Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2016-04-20 17:45:29 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2016-04-20 17:45:29 +0300
commitaae0598aa233d43d0ffc81a070b2ce20d6871c1d (patch)
tree378100f45cf1db972c671a6886496a5604f7ab29
parent95d7d3c2a6aa91f1dcb33ff0cdfc751e2886d8cd (diff)
parentd7e4f920fd93a4ae5679e0eb6b228a349ab3b082 (diff)
Merge branch 'master' into temp_depsgraph_split_ubereval
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt517
-rw-r--r--GNUmakefile10
-rw-r--r--SConstruct1417
-rwxr-xr-xbuild_files/build_environment/install_deps.sh1629
-rw-r--r--build_files/build_environment/install_deps_patches/llvm.patch12
-rw-r--r--build_files/build_environment/install_deps_patches/osl.patch12
-rwxr-xr-xbuild_files/build_environment/prepare_release_env.sh1555
-rw-r--r--build_files/buildbot/config/blender_linux.cmake143
-rw-r--r--build_files/buildbot/config/blender_linux_player.cmake12
-rw-r--r--build_files/buildbot/config/user-config-cuda-glibc211-i686.py5
-rw-r--r--build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py5
-rw-r--r--build_files/buildbot/config/user-config-glibc211-i686.py185
-rw-r--r--build_files/buildbot/config/user-config-glibc211-x86_64.py185
-rw-r--r--build_files/buildbot/config/user-config-mac-i386.py9
-rw-r--r--build_files/buildbot/config/user-config-mac-x86_64.py6
-rw-r--r--build_files/buildbot/config/user-config-player-glibc211-i686.py126
-rw-r--r--build_files/buildbot/config/user-config-player-glibc211-x86_64.py126
-rw-r--r--build_files/buildbot/master.cfg35
-rw-r--r--build_files/buildbot/slave_compile.py319
-rw-r--r--build_files/buildbot/slave_pack.py260
-rw-r--r--build_files/buildbot/slave_test.py25
-rw-r--r--build_files/cmake/Modules/FindLLVM.cmake4
-rw-r--r--build_files/cmake/Modules/FindOpenSubdiv.cmake1
-rw-r--r--build_files/cmake/Modules/FindOpenVDB.cmake74
-rw-r--r--build_files/cmake/Modules/FindPythonLibsUnix.cmake4
-rw-r--r--build_files/cmake/Modules/FindTBB.cmake73
-rw-r--r--build_files/cmake/Modules/GTestTesting.cmake8
-rw-r--r--build_files/cmake/buildinfo.cmake170
-rwxr-xr-xbuild_files/cmake/cmake_consistency_check.py19
-rw-r--r--build_files/cmake/cmake_consistency_check_config.py46
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py16
-rwxr-xr-xbuild_files/cmake/cmake_qtcreator_project.py100
-rw-r--r--build_files/cmake/cmake_static_check_clang_array.py1
-rw-r--r--build_files/cmake/cmake_static_check_cppcheck.py1
-rw-r--r--build_files/cmake/cmake_static_check_smatch.py1
-rw-r--r--build_files/cmake/cmake_static_check_sparse.py1
-rw-r--r--build_files/cmake/cmake_static_check_splint.py1
-rw-r--r--build_files/cmake/config/blender_full.cmake15
-rw-r--r--build_files/cmake/config/blender_lite.cmake5
-rw-r--r--build_files/cmake/config/bpy_module.cmake1
-rw-r--r--build_files/cmake/macros.cmake147
-rw-r--r--build_files/cmake/packaging.cmake10
-rwxr-xr-xbuild_files/cmake/project_info.py34
-rw-r--r--build_files/scons/Modules/FindPython.py50
-rw-r--r--build_files/scons/Modules/FindSharedPtr.py42
-rw-r--r--build_files/scons/Modules/FindUnorderedMap.py38
-rw-r--r--build_files/scons/Modules/__init__.py0
-rw-r--r--build_files/scons/config/darwin-config.py271
-rw-r--r--build_files/scons/config/linux-config.py278
-rw-r--r--build_files/scons/config/win32-mingw-config.py229
-rw-r--r--build_files/scons/config/win32-vc-config.py264
-rw-r--r--build_files/scons/config/win64-mingw-config.py224
-rw-r--r--build_files/scons/config/win64-vc-config.py264
-rw-r--r--build_files/scons/tools/Blender.py1144
-rw-r--r--build_files/scons/tools/__init__.py0
-rw-r--r--build_files/scons/tools/bcolors.py16
-rw-r--r--build_files/scons/tools/btools.py918
-rw-r--r--build_files/scons/tools/crossmingw.py184
-rw-r--r--build_files/scons/tools/mstoolkit.py353
-rw-r--r--doc/build_systems/scons-dev.txt193
-rw-r--r--doc/build_systems/scons.txt227
-rw-r--r--doc/doxygen/Doxyfile82
-rw-r--r--doc/doxygen/doxygen.extern.h4
-rw-r--r--doc/doxygen/doxygen.intern.h2
-rw-r--r--doc/python_api/examples/bpy.app.translations.py9
-rw-r--r--doc/python_api/examples/bpy.ops.1.py8
-rw-r--r--doc/python_api/examples/bpy.types.BlendDataLibraries.write.py18
-rw-r--r--doc/python_api/examples/bpy.types.Menu.3.py80
-rw-r--r--doc/python_api/examples/bpy.types.Menu.py2
-rw-r--r--doc/python_api/examples/bpy.types.RenderEngine.py50
-rw-r--r--doc/python_api/examples/gpu.offscreen.1.py191
-rw-r--r--doc/python_api/rst/bge.app.rst21
-rw-r--r--doc/python_api/rst/bge.logic.rst73
-rw-r--r--doc/python_api/rst/bge.render.rst29
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst9
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst2
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst4
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_IpoActuator.rst65
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst6
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst74
-rw-r--r--doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst6
-rw-r--r--doc/python_api/rst/bgl.rst1
-rw-r--r--doc/python_api/rst/gpu.rst7
-rw-r--r--doc/python_api/rst/include__bmesh.rst8
-rw-r--r--doc/python_api/rst/info_best_practice.rst36
-rw-r--r--doc/python_api/rst/info_quickstart.rst8
-rw-r--r--doc/python_api/rst/info_tips_and_tricks.rst23
-rw-r--r--doc/python_api/rst_from_bmesh_opdefines.py7
-rw-r--r--doc/python_api/sphinx_doc_gen.py23
-rwxr-xr-xdoc/python_api/sphinx_doc_gen.sh19
-rw-r--r--extern/CMakeLists.txt26
-rw-r--r--extern/Eigen3/CMakeLists.txt41
-rw-r--r--extern/Eigen3/Eigen/Core6
-rw-r--r--extern/Eigen3/Eigen/SparseCore2
-rw-r--r--extern/Eigen3/Eigen/src/Cholesky/LDLT.h61
-rw-r--r--extern/Eigen3/Eigen/src/Cholesky/LLT.h10
-rw-r--r--extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h2
-rw-r--r--extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h10
-rw-r--r--extern/Eigen3/Eigen/src/Core/Array.h15
-rw-r--r--extern/Eigen3/Eigen/src/Core/ArrayBase.h4
-rw-r--r--extern/Eigen3/Eigen/src/Core/ArrayWrapper.h10
-rw-r--r--extern/Eigen3/Eigen/src/Core/Assign.h15
-rw-r--r--extern/Eigen3/Eigen/src/Core/Block.h7
-rw-r--r--extern/Eigen3/Eigen/src/Core/CommaInitializer.h11
-rw-r--r--extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h3
-rw-r--r--extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h2
-rw-r--r--extern/Eigen3/Eigen/src/Core/DenseBase.h28
-rw-r--r--extern/Eigen3/Eigen/src/Core/DenseStorage.h271
-rw-r--r--extern/Eigen3/Eigen/src/Core/Diagonal.h8
-rw-r--r--extern/Eigen3/Eigen/src/Core/DiagonalProduct.h5
-rw-r--r--extern/Eigen3/Eigen/src/Core/Functors.h45
-rw-r--r--extern/Eigen3/Eigen/src/Core/GeneralProduct.h14
-rw-r--r--extern/Eigen3/Eigen/src/Core/MapBase.h13
-rw-r--r--extern/Eigen3/Eigen/src/Core/MathFunctions.h2
-rw-r--r--extern/Eigen3/Eigen/src/Core/Matrix.h15
-rw-r--r--extern/Eigen3/Eigen/src/Core/MatrixBase.h27
-rw-r--r--extern/Eigen3/Eigen/src/Core/PermutationMatrix.h34
-rw-r--r--extern/Eigen3/Eigen/src/Core/PlainObjectBase.h32
-rw-r--r--extern/Eigen3/Eigen/src/Core/ProductBase.h14
-rw-r--r--extern/Eigen3/Eigen/src/Core/Redux.h5
-rw-r--r--extern/Eigen3/Eigen/src/Core/Ref.h38
-rw-r--r--extern/Eigen3/Eigen/src/Core/Replicate.h4
-rw-r--r--extern/Eigen3/Eigen/src/Core/ReturnByValue.h11
-rw-r--r--extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h10
-rw-r--r--extern/Eigen3/Eigen/src/Core/TriangularMatrix.h29
-rw-r--r--extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h2
-rw-r--r--extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h20
-rw-r--r--extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h14
-rw-r--r--extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h79
-rw-r--r--extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h6
-rw-r--r--extern/Eigen3/Eigen/src/Core/products/Parallelizer.h17
-rw-r--r--extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h4
-rw-r--r--extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h9
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/Constants.h13
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h3
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/MKL_support.h51
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/Macros.h40
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/Memory.h27
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/StaticAssert.h4
-rw-r--r--extern/Eigen3/Eigen/src/Core/util/XprHelper.h10
-rw-r--r--extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h1
-rw-r--r--extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h8
-rw-r--r--extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h9
-rw-r--r--extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h9
-rw-r--r--extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h14
-rw-r--r--extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h12
-rw-r--r--extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h227
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/AlignedBox.h85
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/AngleAxis.h6
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/Homogeneous.h2
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/Hyperplane.h12
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/Quaternion.h34
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/Rotation2D.h7
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/Transform.h33
-rw-r--r--extern/Eigen3/Eigen/src/Geometry/Umeyama.h10
-rw-r--r--extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h2
-rw-r--r--extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h4
-rw-r--r--extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h24
-rw-r--r--extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h33
-rw-r--r--extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h25
-rw-r--r--extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h48
-rw-r--r--extern/Eigen3/Eigen/src/LU/FullPivLU.h21
-rw-r--r--extern/Eigen3/Eigen/src/LU/PartialPivLU.h8
-rw-r--r--extern/Eigen3/Eigen/src/OrderingMethods/Amd.h19
-rw-r--r--extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h12
-rw-r--r--extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h2
-rw-r--r--extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h35
-rw-r--r--extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h8
-rw-r--r--extern/Eigen3/Eigen/src/QR/HouseholderQR.h98
-rw-r--r--extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h30
-rw-r--r--extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h64
-rw-r--r--extern/Eigen3/Eigen/src/SVD/JacobiSVD.h130
-rw-r--r--extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h42
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h4
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h8
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h136
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h7
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h44
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h17
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h44
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h2
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h10
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h7
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/SparseVector.h1
-rw-r--r--extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h2
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU.h90
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h2
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h4
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h12
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h4
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h4
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h8
-rw-r--r--extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h13
-rw-r--r--extern/Eigen3/Eigen/src/SparseQR/SparseQR.h191
-rw-r--r--extern/Eigen3/Eigen/src/StlSupport/StdDeque.h2
-rw-r--r--extern/Eigen3/Eigen/src/StlSupport/StdList.h2
-rw-r--r--extern/Eigen3/Eigen/src/StlSupport/StdVector.h2
-rw-r--r--extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h112
-rw-r--r--extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h54
-rw-r--r--extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h16
-rw-r--r--extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h17
-rw-r--r--extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h15
-rw-r--r--extern/Eigen3/SConscript35
-rwxr-xr-xextern/Eigen3/eigen-update.sh2
-rw-r--r--extern/Eigen3/eigen3_capi.h32
-rw-r--r--extern/Eigen3/intern/eigenvalues.cc70
-rw-r--r--extern/Eigen3/intern/eigenvalues.h40
-rw-r--r--extern/SConscript56
-rw-r--r--extern/binreloc/SConscript13
-rw-r--r--extern/bullet2/CMakeLists.txt122
-rw-r--r--extern/bullet2/patches/blender.patch324
-rw-r--r--extern/bullet2/patches/convex_hull.patch127
-rw-r--r--extern/bullet2/readme.txt4
-rw-r--r--extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp8
-rw-r--r--extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h23
-rw-r--r--extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp1
-rw-r--r--extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h1
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp2
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp7
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h44
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp168
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h2
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp1143
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h190
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp12
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp5
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp8
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h3
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp7
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp6
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp4
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h4
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp6
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h4
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h10
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h13
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp11
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h4
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp3
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp8
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h3
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp25
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h1
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp2
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp7
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h5
-rw-r--r--extern/bullet2/src/BulletCollision/Doxyfile746
-rw-r--r--extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h14
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h369
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h41
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h1035
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp119
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h908
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h4
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp4
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h6
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp10
-rw-r--r--extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp3
-rw-r--r--extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp18
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp16
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h66
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp3
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h4
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp165
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h23
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h27
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp1121
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h674
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h20
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp4
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h4
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp100
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h87
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp463
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h64
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h5
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp530
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h37
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp8
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h5
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp4
-rw-r--r--extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h2
-rw-r--r--extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp196
-rw-r--r--extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h2
-rw-r--r--extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp118
-rw-r--r--extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h26
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp1841
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h536
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp466
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h106
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp509
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h8
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp534
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h51
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h27
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp126
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h14
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp98
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h20
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h213
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h4
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp118
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h13
-rw-r--r--extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h16
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp17
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp371
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h108
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h350
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp160
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h4
-rw-r--r--extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h2
-rw-r--r--extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp5
-rw-r--r--extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h2
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSoftBody.cpp4
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSoftBody.h2
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp162
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h7
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h2
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp2
-rw-r--r--extern/bullet2/src/BulletSoftBody/btSparseSDF.h1
-rw-r--r--extern/bullet2/src/LinearMath/btAlignedObjectArray.h28
-rw-r--r--extern/bullet2/src/LinearMath/btCpuFeatureUtility.h92
-rw-r--r--extern/bullet2/src/LinearMath/btDefaultMotionState.h4
-rw-r--r--extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h19
-rw-r--r--extern/bullet2/src/LinearMath/btHashMap.h4
-rw-r--r--extern/bullet2/src/LinearMath/btIDebugDraw.h38
-rw-r--r--extern/bullet2/src/LinearMath/btMatrix3x3.h21
-rw-r--r--extern/bullet2/src/LinearMath/btMatrixX.h9
-rw-r--r--extern/bullet2/src/LinearMath/btQuadWord.h2
-rw-r--r--extern/bullet2/src/LinearMath/btQuaternion.h76
-rw-r--r--extern/bullet2/src/LinearMath/btQuickprof.cpp90
-rw-r--r--extern/bullet2/src/LinearMath/btQuickprof.h5
-rw-r--r--extern/bullet2/src/LinearMath/btScalar.h80
-rw-r--r--extern/bullet2/src/LinearMath/btSerializer.cpp1394
-rw-r--r--extern/bullet2/src/LinearMath/btSerializer.h339
-rw-r--r--extern/bullet2/src/LinearMath/btSpatialAlgebra.h331
-rw-r--r--extern/bullet2/src/LinearMath/btTransform.h4
-rw-r--r--extern/bullet2/src/LinearMath/btVector3.cpp4
-rw-r--r--extern/bullet2/src/LinearMath/btVector3.h8
-rw-r--r--extern/bullet2/src/SConscript40
-rw-r--r--extern/carve/CMakeLists.txt2
-rw-r--r--extern/carve/SConscript25
-rwxr-xr-xextern/carve/bundle.sh26
-rw-r--r--extern/carve/files.txt169
-rw-r--r--extern/carve/include/carve/mesh_simplify.hpp8
-rw-r--r--extern/carve/lib/aabb.cpp29
-rw-r--r--extern/carve/lib/edge.cpp23
-rw-r--r--extern/ceres/CMakeLists.txt329
-rw-r--r--extern/ceres/ChangeLog659
-rw-r--r--extern/ceres/LICENSE (renamed from extern/libmv/third_party/ceres/LICENSE)0
-rw-r--r--extern/ceres/README (renamed from extern/libmv/third_party/ceres/README)0
-rwxr-xr-xextern/ceres/bundle.sh198
-rw-r--r--extern/ceres/config/ceres/internal/config.h48
-rw-r--r--extern/ceres/files.txt252
-rw-r--r--extern/ceres/include/ceres/autodiff_cost_function.h227
-rw-r--r--extern/ceres/include/ceres/autodiff_local_parameterization.h154
-rw-r--r--extern/ceres/include/ceres/c_api.h146
-rw-r--r--extern/ceres/include/ceres/ceres.h59
-rw-r--r--extern/ceres/include/ceres/conditioned_cost_function.h99
-rw-r--r--extern/ceres/include/ceres/cost_function.h147
-rw-r--r--extern/ceres/include/ceres/cost_function_to_functor.h682
-rw-r--r--extern/ceres/include/ceres/covariance.h405
-rw-r--r--extern/ceres/include/ceres/crs_matrix.h86
-rw-r--r--extern/ceres/include/ceres/dynamic_autodiff_cost_function.h260
-rw-r--r--extern/ceres/include/ceres/dynamic_cost_function_to_functor.h190
-rw-r--r--extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h205
-rw-r--r--extern/ceres/include/ceres/fpclassify.h70
-rw-r--r--extern/ceres/include/ceres/gradient_checker.h222
-rw-r--r--extern/ceres/include/ceres/gradient_problem.h127
-rw-r--r--extern/ceres/include/ceres/gradient_problem_solver.h357
-rw-r--r--extern/ceres/include/ceres/internal/autodiff.h317
-rw-r--r--extern/ceres/include/ceres/internal/disable_warnings.h44
-rw-r--r--extern/ceres/include/ceres/internal/eigen.h93
-rw-r--r--extern/ceres/include/ceres/internal/fixed_array.h191
-rw-r--r--extern/ceres/include/ceres/internal/macros.h170
-rw-r--r--extern/ceres/include/ceres/internal/manual_constructor.h208
-rw-r--r--extern/ceres/include/ceres/internal/numeric_diff.h446
-rw-r--r--extern/ceres/include/ceres/internal/port.h76
-rw-r--r--extern/ceres/include/ceres/internal/reenable_warnings.h38
-rw-r--r--extern/ceres/include/ceres/internal/scoped_ptr.h310
-rw-r--r--extern/ceres/include/ceres/internal/variadic_evaluate.h194
-rw-r--r--extern/ceres/include/ceres/iteration_callback.h225
-rw-r--r--extern/ceres/include/ceres/jet.h784
-rw-r--r--extern/ceres/include/ceres/local_parameterization.h301
-rw-r--r--extern/ceres/include/ceres/loss_function.h428
-rw-r--r--extern/ceres/include/ceres/normal_prior.h78
-rw-r--r--extern/ceres/include/ceres/numeric_diff_cost_function.h342
-rw-r--r--extern/ceres/include/ceres/numeric_diff_options.h79
-rw-r--r--extern/ceres/include/ceres/ordered_groups.h208
-rw-r--r--extern/ceres/include/ceres/problem.h481
-rw-r--r--extern/ceres/include/ceres/rotation.h629
-rw-r--r--extern/ceres/include/ceres/sized_cost_function.h96
-rw-r--r--extern/ceres/include/ceres/solver.h1028
-rw-r--r--extern/ceres/include/ceres/types.h508
-rw-r--r--extern/ceres/include/ceres/version.h48
-rw-r--r--extern/ceres/internal/ceres/array_utils.cc115
-rw-r--r--extern/ceres/internal/ceres/array_utils.h89
-rw-r--r--extern/ceres/internal/ceres/blas.cc81
-rw-r--r--extern/ceres/internal/ceres/blas.h57
-rw-r--r--extern/ceres/internal/ceres/block_evaluate_preparer.cc83
-rw-r--r--extern/ceres/internal/ceres/block_evaluate_preparer.h77
-rw-r--r--extern/ceres/internal/ceres/block_jacobi_preconditioner.cc106
-rw-r--r--extern/ceres/internal/ceres/block_jacobi_preconditioner.h76
-rw-r--r--extern/ceres/internal/ceres/block_jacobian_writer.cc214
-rw-r--r--extern/ceres/internal/ceres/block_jacobian_writer.h127
-rw-r--r--extern/ceres/internal/ceres/block_random_access_dense_matrix.cc88
-rw-r--r--extern/ceres/internal/ceres/block_random_access_dense_matrix.h98
-rw-r--r--extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc154
-rw-r--r--extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h101
-rw-r--r--extern/ceres/internal/ceres/block_random_access_matrix.cc40
-rw-r--r--extern/ceres/internal/ceres/block_random_access_matrix.h132
-rw-r--r--extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc196
-rw-r--r--extern/ceres/internal/ceres/block_random_access_sparse_matrix.h129
-rw-r--r--extern/ceres/internal/ceres/block_sparse_matrix.cc246
-rw-r--r--extern/ceres/internal/ceres/block_sparse_matrix.h100
-rw-r--r--extern/ceres/internal/ceres/block_structure.cc44
-rw-r--r--extern/ceres/internal/ceres/block_structure.h93
-rw-r--r--extern/ceres/internal/ceres/c_api.cc188
-rw-r--r--extern/ceres/internal/ceres/callbacks.cc111
-rw-r--r--extern/ceres/internal/ceres/callbacks.h71
-rw-r--r--extern/ceres/internal/ceres/casts.h108
-rw-r--r--extern/ceres/internal/ceres/cgnr_linear_operator.h120
-rw-r--r--extern/ceres/internal/ceres/cgnr_solver.cc88
-rw-r--r--extern/ceres/internal/ceres/cgnr_solver.h69
-rw-r--r--extern/ceres/internal/ceres/collections_port.h196
-rw-r--r--extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc122
-rw-r--r--extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h144
-rw-r--r--extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc233
-rw-r--r--extern/ceres/internal/ceres/compressed_row_jacobian_writer.h112
-rw-r--r--extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc562
-rw-r--r--extern/ceres/internal/ceres/compressed_row_sparse_matrix.h181
-rw-r--r--extern/ceres/internal/ceres/conditioned_cost_function.cc130
-rw-r--r--extern/ceres/internal/ceres/conjugate_gradients_solver.cc248
-rw-r--r--extern/ceres/internal/ceres/conjugate_gradients_solver.h74
-rw-r--r--extern/ceres/internal/ceres/coordinate_descent_minimizer.cc278
-rw-r--r--extern/ceres/internal/ceres/coordinate_descent_minimizer.h102
-rw-r--r--extern/ceres/internal/ceres/corrector.cc158
-rw-r--r--extern/ceres/internal/ceres/corrector.h90
-rw-r--r--extern/ceres/internal/ceres/covariance.cc76
-rw-r--r--extern/ceres/internal/ceres/covariance_impl.cc757
-rw-r--r--extern/ceres/internal/ceres/covariance_impl.h92
-rw-r--r--extern/ceres/internal/ceres/cxsparse.h140
-rw-r--r--extern/ceres/internal/ceres/dense_jacobian_writer.h108
-rw-r--r--extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc166
-rw-r--r--extern/ceres/internal/ceres/dense_normal_cholesky_solver.h107
-rw-r--r--extern/ceres/internal/ceres/dense_qr_solver.cc170
-rw-r--r--extern/ceres/internal/ceres/dense_qr_solver.h115
-rw-r--r--extern/ceres/internal/ceres/dense_sparse_matrix.cc183
-rw-r--r--extern/ceres/internal/ceres/dense_sparse_matrix.h109
-rw-r--r--extern/ceres/internal/ceres/detect_structure.cc120
-rw-r--r--extern/ceres/internal/ceres/detect_structure.h67
-rw-r--r--extern/ceres/internal/ceres/dogleg_strategy.cc718
-rw-r--r--extern/ceres/internal/ceres/dogleg_strategy.h165
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_finalizer.h51
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc117
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h83
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc107
-rw-r--r--extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h101
-rw-r--r--extern/ceres/internal/ceres/evaluator.cc86
-rw-r--r--extern/ceres/internal/ceres/evaluator.h205
-rw-r--r--extern/ceres/internal/ceres/execution_summary.h90
-rw-r--r--extern/ceres/internal/ceres/file.cc95
-rw-r--r--extern/ceres/internal/ceres/file.h53
-rw-r--r--extern/ceres/internal/ceres/generate_eliminator_specialization.py231
-rw-r--r--extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py232
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc53
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc59
-rw-r--r--extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc53
-rw-r--r--extern/ceres/internal/ceres/gradient_checking_cost_function.cc337
-rw-r--r--extern/ceres/internal/ceres/gradient_checking_cost_function.h85
-rw-r--r--extern/ceres/internal/ceres/gradient_problem.cc81
-rw-r--r--extern/ceres/internal/ceres/gradient_problem_evaluator.h98
-rw-r--r--extern/ceres/internal/ceres/gradient_problem_solver.cc277
-rw-r--r--extern/ceres/internal/ceres/graph.h225
-rw-r--r--extern/ceres/internal/ceres/graph_algorithms.h364
-rw-r--r--extern/ceres/internal/ceres/householder_vector.h85
-rw-r--r--extern/ceres/internal/ceres/implicit_schur_complement.cc225
-rw-r--r--extern/ceres/internal/ceres/implicit_schur_complement.h167
-rw-r--r--extern/ceres/internal/ceres/integral_types.h91
-rw-r--r--extern/ceres/internal/ceres/iterative_schur_complement_solver.cc182
-rw-r--r--extern/ceres/internal/ceres/iterative_schur_complement_solver.h92
-rw-r--r--extern/ceres/internal/ceres/lapack.cc193
-rw-r--r--extern/ceres/internal/ceres/lapack.h100
-rw-r--r--extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc167
-rw-r--r--extern/ceres/internal/ceres/levenberg_marquardt_strategy.h87
-rw-r--r--extern/ceres/internal/ceres/line_search.cc881
-rw-r--r--extern/ceres/internal/ceres/line_search.h327
-rw-r--r--extern/ceres/internal/ceres/line_search_direction.cc372
-rw-r--r--extern/ceres/internal/ceres/line_search_direction.h72
-rw-r--r--extern/ceres/internal/ceres/line_search_minimizer.cc432
-rw-r--r--extern/ceres/internal/ceres/line_search_minimizer.h77
-rw-r--r--extern/ceres/internal/ceres/line_search_preprocessor.cc106
-rw-r--r--extern/ceres/internal/ceres/line_search_preprocessor.h50
-rw-r--r--extern/ceres/internal/ceres/linear_least_squares_problems.cc732
-rw-r--r--extern/ceres/internal/ceres/linear_least_squares_problems.h85
-rw-r--r--extern/ceres/internal/ceres/linear_operator.cc40
-rw-r--r--extern/ceres/internal/ceres/linear_operator.h59
-rw-r--r--extern/ceres/internal/ceres/linear_solver.cc119
-rw-r--r--extern/ceres/internal/ceres/linear_solver.h362
-rw-r--r--extern/ceres/internal/ceres/local_parameterization.cc345
-rw-r--r--extern/ceres/internal/ceres/loss_function.cc174
-rw-r--r--extern/ceres/internal/ceres/low_rank_inverse_hessian.cc188
-rw-r--r--extern/ceres/internal/ceres/low_rank_inverse_hessian.h108
-rw-r--r--extern/ceres/internal/ceres/map_util.h130
-rw-r--r--extern/ceres/internal/ceres/minimizer.cc87
-rw-r--r--extern/ceres/internal/ceres/minimizer.h202
-rw-r--r--extern/ceres/internal/ceres/mutex.h329
-rw-r--r--extern/ceres/internal/ceres/normal_prior.cc66
-rw-r--r--extern/ceres/internal/ceres/parameter_block.h398
-rw-r--r--extern/ceres/internal/ceres/parameter_block_ordering.cc173
-rw-r--r--extern/ceres/internal/ceres/parameter_block_ordering.h89
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view.cc185
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view.h152
-rw-r--r--extern/ceres/internal/ceres/partitioned_matrix_view_impl.h380
-rw-r--r--extern/ceres/internal/ceres/polynomial.cc398
-rw-r--r--extern/ceres/internal/ceres/polynomial.h136
-rw-r--r--extern/ceres/internal/ceres/preconditioner.cc73
-rw-r--r--extern/ceres/internal/ceres/preconditioner.h177
-rw-r--r--extern/ceres/internal/ceres/preprocessor.cc113
-rw-r--r--extern/ceres/internal/ceres/preprocessor.h122
-rw-r--r--extern/ceres/internal/ceres/problem.cc273
-rw-r--r--extern/ceres/internal/ceres/problem_impl.cc945
-rw-r--r--extern/ceres/internal/ceres/problem_impl.h226
-rw-r--r--extern/ceres/internal/ceres/program.cc524
-rw-r--r--extern/ceres/internal/ceres/program.h192
-rw-r--r--extern/ceres/internal/ceres/program_evaluator.h384
-rw-r--r--extern/ceres/internal/ceres/random.h70
-rw-r--r--extern/ceres/internal/ceres/reorder_program.cc596
-rw-r--r--extern/ceres/internal/ceres/reorder_program.h101
-rw-r--r--extern/ceres/internal/ceres/residual_block.cc219
-rw-r--r--extern/ceres/internal/ceres/residual_block.h148
-rw-r--r--extern/ceres/internal/ceres/residual_block_utils.cc142
-rw-r--r--extern/ceres/internal/ceres/residual_block_utils.h80
-rw-r--r--extern/ceres/internal/ceres/schur_complement_solver.cc670
-rw-r--r--extern/ceres/internal/ceres/schur_complement_solver.h226
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator.cc163
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator.h355
-rw-r--r--extern/ceres/internal/ceres/schur_eliminator_impl.h698
-rw-r--r--extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc115
-rw-r--r--extern/ceres/internal/ceres/schur_jacobi_preconditioner.h106
-rw-r--r--extern/ceres/internal/ceres/scratch_evaluate_preparer.cc78
-rw-r--r--extern/ceres/internal/ceres/scratch_evaluate_preparer.h69
-rw-r--r--extern/ceres/internal/ceres/small_blas.h381
-rw-r--r--extern/ceres/internal/ceres/solver.cc841
-rw-r--r--extern/ceres/internal/ceres/solver_utils.cc86
-rw-r--r--extern/ceres/internal/ceres/solver_utils.h61
-rw-r--r--extern/ceres/internal/ceres/sparse_matrix.cc40
-rw-r--r--extern/ceres/internal/ceres/sparse_matrix.h107
-rw-r--r--extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc486
-rw-r--r--extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h127
-rw-r--r--extern/ceres/internal/ceres/split.cc123
-rw-r--r--extern/ceres/internal/ceres/split.h50
-rw-r--r--extern/ceres/internal/ceres/stl_util.h91
-rw-r--r--extern/ceres/internal/ceres/stringprintf.cc132
-rw-r--r--extern/ceres/internal/ceres/stringprintf.h89
-rw-r--r--extern/ceres/internal/ceres/suitesparse.h306
-rw-r--r--extern/ceres/internal/ceres/triplet_sparse_matrix.cc264
-rw-r--r--extern/ceres/internal/ceres/triplet_sparse_matrix.h129
-rw-r--r--extern/ceres/internal/ceres/trust_region_minimizer.cc716
-rw-r--r--extern/ceres/internal/ceres/trust_region_minimizer.h65
-rw-r--r--extern/ceres/internal/ceres/trust_region_preprocessor.cc362
-rw-r--r--extern/ceres/internal/ceres/trust_region_preprocessor.h50
-rw-r--r--extern/ceres/internal/ceres/trust_region_strategy.cc59
-rw-r--r--extern/ceres/internal/ceres/trust_region_strategy.h164
-rw-r--r--extern/ceres/internal/ceres/types.cc395
-rw-r--r--extern/ceres/internal/ceres/visibility_based_preconditioner.h233
-rw-r--r--extern/ceres/internal/ceres/wall_time.cc96
-rw-r--r--extern/ceres/internal/ceres/wall_time.h88
-rwxr-xr-xextern/ceres/mkfiles.sh (renamed from extern/libmv/third_party/ceres/mkfiles.sh)0
-rw-r--r--extern/ceres/patches/series (renamed from extern/libmv/third_party/ceres/patches/series)0
-rw-r--r--extern/clew/SConscript35
-rw-r--r--extern/clew/include/clew.h18
-rw-r--r--extern/clew/src/clew.c10
-rw-r--r--extern/colamd/CMakeLists.txt41
-rw-r--r--extern/colamd/Doc/ChangeLog129
-rw-r--r--extern/colamd/Doc/lesser.txt504
-rw-r--r--extern/colamd/Include/UFconfig.h118
-rw-r--r--extern/colamd/Include/colamd.h255
-rw-r--r--extern/colamd/README.txt127
-rw-r--r--extern/colamd/SConscript14
-rw-r--r--extern/colamd/Source/colamd.c3611
-rw-r--r--extern/colamd/Source/colamd_global.c24
-rw-r--r--extern/cuew/CMakeLists.txt3
-rw-r--r--extern/cuew/SConscript35
-rw-r--r--extern/cuew/auto/cuda_errors.py35
-rw-r--r--extern/cuew/auto/cuda_extra.py125
-rw-r--r--extern/cuew/auto/cuew_gen.py591
-rwxr-xr-xextern/cuew/auto/cuew_gen.sh10
-rw-r--r--extern/cuew/auto/stdlib.h3
-rw-r--r--extern/cuew/include/cuew.h100
-rw-r--r--extern/cuew/src/cuew.c179
-rw-r--r--extern/curve_fit_nd/CMakeLists.txt35
-rw-r--r--extern/curve_fit_nd/curve_fit_nd.h125
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_corners_detect.c468
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic.c1034
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_inline.h262
-rw-r--r--extern/gflags/AUTHORS.txt (renamed from extern/libmv/third_party/gflags/AUTHORS.txt)0
-rw-r--r--extern/gflags/CMakeLists.txt56
-rw-r--r--extern/gflags/COPYING.txt (renamed from extern/libmv/third_party/gflags/COPYING.txt)0
-rw-r--r--extern/gflags/ChangeLog.txt218
-rw-r--r--extern/gflags/NEWS.txt (renamed from extern/libmv/third_party/gflags/NEWS.txt)0
-rw-r--r--extern/gflags/README.libmv19
-rw-r--r--extern/gflags/README.md270
-rw-r--r--extern/gflags/src/config.h114
-rw-r--r--extern/gflags/src/gflags.cc1966
-rw-r--r--extern/gflags/src/gflags/gflags.h573
-rw-r--r--extern/gflags/src/gflags/gflags_completions.h121
-rw-r--r--extern/gflags/src/gflags/gflags_declare.h141
-rw-r--r--extern/gflags/src/gflags/gflags_gflags.h101
-rw-r--r--extern/gflags/src/gflags_completions.cc771
-rw-r--r--extern/gflags/src/gflags_reporting.cc (renamed from extern/libmv/third_party/gflags/gflags_reporting.cc)0
-rw-r--r--extern/gflags/src/mutex.h348
-rw-r--r--extern/gflags/src/util.h374
-rw-r--r--extern/gflags/src/windows_port.cc73
-rw-r--r--extern/gflags/src/windows_port.h133
-rw-r--r--extern/glew-es/SConscript16
-rw-r--r--extern/glew/SConscript17
-rw-r--r--extern/glew/include/GL/glew.h2375
-rw-r--r--extern/glew/include/GL/glxew.h135
-rw-r--r--extern/glew/include/GL/wglew.h36
-rw-r--r--extern/glew/src/glew.c4862
-rw-r--r--extern/glog/AUTHORS18
-rw-r--r--extern/glog/CMakeLists.txt92
-rw-r--r--extern/glog/COPYING (renamed from extern/libmv/third_party/glog/COPYING)0
-rw-r--r--extern/glog/ChangeLog (renamed from extern/libmv/third_party/glog/ChangeLog)0
-rw-r--r--extern/glog/NEWS (renamed from extern/libmv/third_party/glog/NEWS)0
-rw-r--r--extern/glog/README (renamed from extern/libmv/third_party/glog/README)0
-rw-r--r--extern/glog/README.libmv9
-rw-r--r--extern/glog/src/base/commandlineflags.h133
-rw-r--r--extern/glog/src/base/googleinit.h (renamed from extern/libmv/third_party/glog/src/base/googleinit.h)0
-rw-r--r--extern/glog/src/base/mutex.h333
-rw-r--r--extern/glog/src/config.h (renamed from extern/libmv/third_party/glog/src/config.h)0
-rw-r--r--extern/glog/src/config_freebsd.h192
-rw-r--r--extern/glog/src/config_hurd.h192
-rw-r--r--extern/glog/src/config_linux.h192
-rw-r--r--extern/glog/src/config_mac.h186
-rw-r--r--extern/glog/src/demangle.cc (renamed from extern/libmv/third_party/glog/src/demangle.cc)0
-rw-r--r--extern/glog/src/demangle.h84
-rw-r--r--extern/glog/src/glog/log_severity.h (renamed from extern/libmv/third_party/glog/src/glog/log_severity.h)0
-rw-r--r--extern/glog/src/glog/logging.h1631
-rw-r--r--extern/glog/src/glog/raw_logging.h190
-rw-r--r--extern/glog/src/glog/vlog_is_on.h (renamed from extern/libmv/third_party/glog/src/glog/vlog_is_on.h)0
-rw-r--r--extern/glog/src/logging.cc2089
-rw-r--r--extern/glog/src/raw_logging.cc (renamed from extern/libmv/third_party/glog/src/raw_logging.cc)0
-rw-r--r--extern/glog/src/signalhandler.cc375
-rw-r--r--extern/glog/src/stacktrace.h (renamed from extern/libmv/third_party/glog/src/stacktrace.h)0
-rw-r--r--extern/glog/src/stacktrace_generic-inl.h (renamed from extern/libmv/third_party/glog/src/stacktrace_generic-inl.h)0
-rw-r--r--extern/glog/src/stacktrace_libunwind-inl.h (renamed from extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h)0
-rw-r--r--extern/glog/src/stacktrace_powerpc-inl.h (renamed from extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h)0
-rw-r--r--extern/glog/src/stacktrace_x86-inl.h (renamed from extern/libmv/third_party/glog/src/stacktrace_x86-inl.h)0
-rw-r--r--extern/glog/src/stacktrace_x86_64-inl.h (renamed from extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h)0
-rw-r--r--extern/glog/src/symbolize.cc848
-rw-r--r--extern/glog/src/symbolize.h (renamed from extern/libmv/third_party/glog/src/symbolize.h)0
-rw-r--r--extern/glog/src/utilities.cc352
-rw-r--r--extern/glog/src/utilities.h (renamed from extern/libmv/third_party/glog/src/utilities.h)0
-rw-r--r--extern/glog/src/vlog_is_on.cc257
-rw-r--r--extern/glog/src/windows/config.h28
-rw-r--r--extern/glog/src/windows/glog/log_severity.h (renamed from extern/libmv/third_party/glog/src/windows/glog/log_severity.h)0
-rw-r--r--extern/glog/src/windows/glog/logging.h1616
-rw-r--r--extern/glog/src/windows/glog/raw_logging.h (renamed from extern/libmv/third_party/glog/src/windows/glog/raw_logging.h)0
-rw-r--r--extern/glog/src/windows/glog/vlog_is_on.h (renamed from extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h)0
-rw-r--r--extern/glog/src/windows/port.cc66
-rw-r--r--extern/glog/src/windows/port.h168
-rwxr-xr-xextern/glog/src/windows/preprocess.sh119
-rw-r--r--extern/gtest/include/gtest/gtest.h18
-rw-r--r--extern/gtest/include/gtest/internal/gtest-port.h28
-rw-r--r--extern/libmv/CMakeLists.txt349
-rw-r--r--extern/libmv/ChangeLog707
-rw-r--r--extern/libmv/SConscript70
-rwxr-xr-xextern/libmv/bundle.sh344
-rw-r--r--extern/libmv/files.txt196
-rw-r--r--extern/libmv/intern/camera_intrinsics.cc355
-rw-r--r--extern/libmv/intern/camera_intrinsics.h138
-rw-r--r--extern/libmv/intern/frame_accessor.cc164
-rw-r--r--extern/libmv/intern/stub.cc403
-rw-r--r--extern/libmv/intern/track_region.cc177
-rw-r--r--extern/libmv/intern/utildefines.h62
-rw-r--r--extern/libmv/libmv/autotrack/predict_tracks_test.cc201
-rw-r--r--extern/libmv/libmv/base/aligned_malloc.cc74
-rw-r--r--extern/libmv/libmv/image/array_nd.h496
-rw-r--r--extern/libmv/libmv/multiview/euclidean_resection_test.cc237
-rw-r--r--extern/libmv/libmv/multiview/fundamental.h187
-rw-r--r--extern/libmv/libmv/multiview/homography.cc470
-rw-r--r--extern/libmv/libmv/multiview/projection_test.cc115
-rw-r--r--extern/libmv/libmv/numeric/numeric.h502
-rw-r--r--extern/libmv/libmv/numeric/poly_test.cc98
-rw-r--r--extern/libmv/libmv/simple_pipeline/detect_test.cc230
-rw-r--r--extern/libmv/libmv/simple_pipeline/modal_solver.cc251
-rwxr-xr-xextern/libmv/mkfiles.sh4
-rw-r--r--extern/libmv/third_party/CMakeLists.txt2
-rw-r--r--extern/libmv/third_party/SConscript3
-rw-r--r--extern/libmv/third_party/ceres/CMakeLists.txt359
-rw-r--r--extern/libmv/third_party/ceres/ChangeLog673
-rw-r--r--extern/libmv/third_party/ceres/SConscript63
-rwxr-xr-xextern/libmv/third_party/ceres/bundle.sh267
-rw-r--r--extern/libmv/third_party/ceres/config/ceres/internal/config.h45
-rw-r--r--extern/libmv/third_party/ceres/files.txt258
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h227
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/autodiff_local_parameterization.h154
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/c_api.h146
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/ceres.h59
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/conditioned_cost_function.h99
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/cost_function.h147
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h750
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/covariance.h384
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/crs_matrix.h86
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h260
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h265
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/fpclassify.h87
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/gradient_checker.h222
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/gradient_problem.h127
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h353
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h317
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h44
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/eigen.h93
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h191
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/macros.h170
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h208
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h208
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/port.h88
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h38
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h310
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h182
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/iteration_callback.h225
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/jet.h670
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/local_parameterization.h217
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/loss_function.h401
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/normal_prior.h78
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h315
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/ordered_groups.h201
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/problem.h481
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/rotation.h645
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h96
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/solver.h1004
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/types.h487
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/version.h49
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/array_utils.cc113
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/array_utils.h88
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/blas.cc79
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/blas.h57
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc83
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h77
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc106
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h76
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc212
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.h127
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc88
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h98
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc152
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h101
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.cc40
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h132
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc191
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h128
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc244
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h100
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_structure.cc44
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_structure.h93
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/c_api.cc188
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/callbacks.cc109
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/callbacks.h71
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc245
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h136
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/casts.h108
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_linear_operator.h120
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc88
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h69
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/collections_port.h197
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc118
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h142
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc226
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h109
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc544
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h181
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc130
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc239
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h74
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc272
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h102
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/corrector.cc158
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/corrector.h90
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/covariance.cc62
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/covariance_impl.cc760
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/covariance_impl.h89
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc217
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cxsparse.h141
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h111
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc166
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h107
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc170
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h115
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc183
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h109
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc114
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/detect_structure.h63
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc717
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h165
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h51
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc114
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h83
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc107
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h99
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/evaluator.cc86
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/evaluator.h205
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/execution_summary.h90
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/file.cc95
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/file.h52
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py230
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py231
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc53
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc53
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc329
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.h85
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc81
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h98
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc270
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/graph.h223
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h363
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc225
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h167
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.cc239
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.h90
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/integral_types.h91
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc182
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h92
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/lapack.cc193
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/lapack.h100
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc163
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h87
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search.cc821
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search.h299
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc372
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h72
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc409
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h77
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc106
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h50
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc628
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h84
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_operator.cc40
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_operator.h59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc119
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_solver.h362
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc183
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/loss_function.cc158
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc186
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h108
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/map_util.h130
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/minimizer.cc86
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/minimizer.h202
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/mutex.h329
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc66
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block.h397
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc169
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h89
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc179
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.h152
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h380
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/polynomial.cc394
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/polynomial.h135
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc73
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preconditioner.h177
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc113
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preprocessor.h119
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem.cc271
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc872
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem_impl.h225
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/program.cc517
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/program.h191
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h379
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/random.h70
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc578
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/reorder_program.h101
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block.cc218
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block.h148
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc140
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h80
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc664
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h226
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.cc158
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.h355
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h699
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc115
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h106
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc78
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h69
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.cc110
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.h74
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/small_blas.h381
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver.cc808
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver_utils.cc78
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver_utils.h58
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.cc40
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h107
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc439
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h131
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/split.cc117
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/split.h48
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stl_util.h91
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc130
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stringprintf.h89
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc347
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/suitesparse.h306
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc264
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h129
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc690
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h65
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.cc358
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.h50
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc59
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h164
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/types.cc362
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility.cc160
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility.h84
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc625
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h232
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/wall_time.cc96
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/wall_time.h88
-rw-r--r--extern/libmv/third_party/gflags/ChangeLog.txt208
-rw-r--r--extern/libmv/third_party/gflags/README.libmv18
-rw-r--r--extern/libmv/third_party/gflags/config.h117
-rw-r--r--extern/libmv/third_party/gflags/gflags.cc1957
-rw-r--r--extern/libmv/third_party/gflags/gflags/gflags.h568
-rw-r--r--extern/libmv/third_party/gflags/gflags/gflags_completions.h121
-rw-r--r--extern/libmv/third_party/gflags/gflags/gflags_declare.h136
-rw-r--r--extern/libmv/third_party/gflags/gflags_completions.cc769
-rw-r--r--extern/libmv/third_party/gflags/mutex.h351
-rw-r--r--extern/libmv/third_party/gflags/util.h373
-rw-r--r--extern/libmv/third_party/gflags/windows_port.cc71
-rw-r--r--extern/libmv/third_party/gflags/windows_port.h127
-rw-r--r--extern/libmv/third_party/glog/AUTHORS2
-rw-r--r--extern/libmv/third_party/glog/README.libmv9
-rw-r--r--extern/libmv/third_party/glog/src/base/commandlineflags.h133
-rw-r--r--extern/libmv/third_party/glog/src/base/mutex.h331
-rw-r--r--extern/libmv/third_party/glog/src/config_freebsd.h172
-rw-r--r--extern/libmv/third_party/glog/src/config_hurd.h172
-rw-r--r--extern/libmv/third_party/glog/src/config_linux.h185
-rw-r--r--extern/libmv/third_party/glog/src/config_mac.h171
-rw-r--r--extern/libmv/third_party/glog/src/demangle.h84
-rw-r--r--extern/libmv/third_party/glog/src/glog/logging.h1609
-rw-r--r--extern/libmv/third_party/glog/src/glog/raw_logging.h191
-rw-r--r--extern/libmv/third_party/glog/src/logging.cc2083
-rw-r--r--extern/libmv/third_party/glog/src/signalhandler.cc359
-rw-r--r--extern/libmv/third_party/glog/src/symbolize.cc848
-rw-r--r--extern/libmv/third_party/glog/src/utilities.cc350
-rw-r--r--extern/libmv/third_party/glog/src/vlog_is_on.cc253
-rw-r--r--extern/libmv/third_party/glog/src/windows/config.h24
-rw-r--r--extern/libmv/third_party/glog/src/windows/glog/logging.h1616
-rw-r--r--extern/libmv/third_party/glog/src/windows/port.cc66
-rw-r--r--extern/libmv/third_party/glog/src/windows/port.h179
-rwxr-xr-xextern/libmv/third_party/glog/src/windows/preprocess.sh118
-rw-r--r--extern/libopenjpeg/SConscript30
-rw-r--r--extern/libopenjpeg/bio.c8
-rw-r--r--extern/libopenjpeg/cidx_manager.c2
-rw-r--r--extern/libopenjpeg/cio.c12
-rw-r--r--extern/libopenjpeg/cio.h9
-rw-r--r--extern/libopenjpeg/event.c9
-rw-r--r--extern/libopenjpeg/image.c3
-rw-r--r--extern/libopenjpeg/j2k.c207
-rw-r--r--extern/libopenjpeg/jp2.c265
-rw-r--r--extern/libopenjpeg/openjpeg.h4
-rw-r--r--extern/libopenjpeg/opj_config.h3
-rw-r--r--extern/libopenjpeg/opj_includes.h11
-rw-r--r--extern/libopenjpeg/opj_malloc.h4
-rw-r--r--extern/libopenjpeg/patches/fbsd.patch13
-rw-r--r--extern/libopenjpeg/patches/osx.patch17
-rw-r--r--extern/libopenjpeg/t1.c1
-rw-r--r--extern/libopenjpeg/t2.c52
-rw-r--r--extern/libopenjpeg/tcd.c119
-rw-r--r--extern/libredcode/AUTHOR1
-rw-r--r--extern/libredcode/CMakeLists.txt46
-rw-r--r--extern/libredcode/LICENSE340
-rw-r--r--extern/libredcode/NOTES23
-rw-r--r--extern/libredcode/SConscript16
-rw-r--r--extern/libredcode/codec.c166
-rw-r--r--extern/libredcode/codec.h56
-rw-r--r--extern/libredcode/debayer.c145
-rw-r--r--extern/libredcode/debayer.h33
-rw-r--r--extern/libredcode/format.c248
-rw-r--r--extern/libredcode/format.h46
-rw-r--r--extern/lzma/SConscript9
-rw-r--r--extern/lzo/SConscript9
-rw-r--r--extern/rangetree/SConscript9
-rw-r--r--extern/recastnavigation/Recast/Include/Recast.h822
-rw-r--r--extern/recastnavigation/Recast/Include/RecastAlloc.h81
-rw-r--r--extern/recastnavigation/Recast/Include/RecastAssert.h2
-rw-r--r--extern/recastnavigation/Recast/Include/RecastLog.h80
-rw-r--r--extern/recastnavigation/Recast/Include/RecastTimer.h31
-rw-r--r--extern/recastnavigation/Recast/Source/Recast.cpp40
-rw-r--r--extern/recastnavigation/Recast/Source/RecastAlloc.cpp22
-rw-r--r--extern/recastnavigation/Recast/Source/RecastArea.cpp101
-rw-r--r--extern/recastnavigation/Recast/Source/RecastContour.cpp592
-rw-r--r--extern/recastnavigation/Recast/Source/RecastFilter.cpp23
-rw-r--r--extern/recastnavigation/Recast/Source/RecastLayers.cpp45
-rw-r--r--extern/recastnavigation/Recast/Source/RecastLog.cpp77
-rw-r--r--extern/recastnavigation/Recast/Source/RecastMesh.cpp291
-rw-r--r--extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp681
-rw-r--r--extern/recastnavigation/Recast/Source/RecastRasterization.cpp199
-rw-r--r--extern/recastnavigation/Recast/Source/RecastRegion.cpp693
-rw-r--r--extern/recastnavigation/Recast/Source/RecastTimer.cpp58
-rw-r--r--extern/recastnavigation/SConscript12
-rw-r--r--extern/recastnavigation/readme-blender.txt22
-rw-r--r--extern/recastnavigation/recast-capi.cpp133
-rw-r--r--extern/recastnavigation/recast-capi.h67
-rw-r--r--extern/sdlew/SConscript35
-rwxr-xr-xextern/sdlew/auto/sdlew_gen.sh250
-rwxr-xr-xextern/sdlew/auto/strip_comments.sh15
-rw-r--r--extern/wcwidth/SConscript9
-rw-r--r--extern/wcwidth/wcwidth.c2
-rw-r--r--extern/xdnd/SConscript10
-rw-r--r--intern/CMakeLists.txt11
-rw-r--r--intern/SConscript69
-rw-r--r--intern/atomic/atomic_ops.h26
-rw-r--r--intern/audaspace/CMakeLists.txt4
-rw-r--r--intern/audaspace/Python/AUD_PyAPI.cpp6
-rw-r--r--intern/audaspace/SConscript76
-rw-r--r--intern/audaspace/SDL/AUD_SDLDevice.cpp2
-rw-r--r--intern/audaspace/SDL/AUD_SDLDevice.h11
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp8
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp6
-rw-r--r--intern/audaspace/intern/AUD_C-API.cpp9
-rw-r--r--intern/audaspace/intern/AUD_SilenceReader.cpp2
-rw-r--r--intern/audaspace/intern/AUD_SinusFactory.h2
-rw-r--r--intern/audaspace/intern/AUD_Space.h4
-rw-r--r--intern/container/SConscript33
-rw-r--r--intern/cycles/CMakeLists.txt49
-rw-r--r--intern/cycles/SConscript173
-rw-r--r--intern/cycles/app/CMakeLists.txt23
-rw-r--r--intern/cycles/app/cycles_standalone.cpp8
-rw-r--r--intern/cycles/app/cycles_xml.cpp11
-rw-r--r--intern/cycles/blender/CMakeLists.txt4
-rw-r--r--intern/cycles/blender/addon/__init__.py19
-rw-r--r--intern/cycles/blender/addon/engine.py42
-rw-r--r--intern/cycles/blender/addon/properties.py164
-rw-r--r--intern/cycles/blender/addon/ui.py205
-rw-r--r--intern/cycles/blender/addon/version_update.py139
-rw-r--r--intern/cycles/blender/blender_camera.cpp230
-rw-r--r--intern/cycles/blender/blender_curves.cpp18
-rw-r--r--intern/cycles/blender/blender_mesh.cpp272
-rw-r--r--intern/cycles/blender/blender_object.cpp80
-rw-r--r--intern/cycles/blender/blender_particles.cpp4
-rw-r--r--intern/cycles/blender/blender_python.cpp226
-rw-r--r--intern/cycles/blender/blender_session.cpp292
-rw-r--r--intern/cycles/blender/blender_session.h66
-rw-r--r--intern/cycles/blender/blender_shader.cpp439
-rw-r--r--intern/cycles/blender/blender_sync.cpp166
-rw-r--r--intern/cycles/blender/blender_sync.h102
-rw-r--r--intern/cycles/blender/blender_texture.cpp87
-rw-r--r--intern/cycles/blender/blender_texture.h4
-rw-r--r--intern/cycles/blender/blender_util.h186
-rw-r--r--intern/cycles/bvh/bvh.cpp187
-rw-r--r--intern/cycles/bvh/bvh.h19
-rw-r--r--intern/cycles/bvh/bvh_binning.cpp2
-rw-r--r--intern/cycles/bvh/bvh_build.cpp386
-rw-r--r--intern/cycles/bvh/bvh_build.h38
-rw-r--r--intern/cycles/bvh/bvh_params.h24
-rw-r--r--intern/cycles/bvh/bvh_sort.cpp156
-rw-r--r--intern/cycles/bvh/bvh_split.cpp95
-rw-r--r--intern/cycles/bvh/bvh_split.h61
-rw-r--r--intern/cycles/cmake/external_libs.cmake10
-rw-r--r--intern/cycles/device/CMakeLists.txt25
-rw-r--r--intern/cycles/device/device.cpp45
-rw-r--r--intern/cycles/device/device.h56
-rw-r--r--intern/cycles/device/device_cpu.cpp127
-rw-r--r--intern/cycles/device/device_cuda.cpp265
-rw-r--r--intern/cycles/device/device_memory.h9
-rw-r--r--intern/cycles/device/device_multi.cpp1
-rw-r--r--intern/cycles/device/device_network.cpp3
-rw-r--r--intern/cycles/device/device_network.h4
-rw-r--r--intern/cycles/device/device_opencl.cpp524
-rw-r--r--intern/cycles/device/device_task.cpp4
-rw-r--r--intern/cycles/device/device_task.h3
-rw-r--r--intern/cycles/kernel/CMakeLists.txt28
-rw-r--r--intern/cycles/kernel/SConscript121
-rw-r--r--intern/cycles/kernel/closure/bsdf.h4
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h180
-rw-r--r--intern/cycles/kernel/geom/geom.h4
-rw-r--r--intern/cycles/kernel/geom/geom_bvh.h324
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_shadow.h50
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_subsurface.h184
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_traversal.h72
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_volume.h61
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_volume_all.h126
-rw-r--r--intern/cycles/kernel/geom/geom_curve.h14
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h64
-rw-r--r--intern/cycles/kernel/geom/geom_object.h68
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h6
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh.h2
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_shadow.h38
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_subsurface.h174
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_traversal.h50
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_volume.h56
-rw-r--r--intern/cycles/kernel/geom/geom_qbvh_volume_all.h119
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h110
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h19
-rw-r--r--intern/cycles/kernel/kernel.h74
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h22
-rw-r--r--intern/cycles/kernel/kernel_bake.h364
-rw-r--r--intern/cycles/kernel/kernel_camera.h115
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h38
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h8
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h46
-rw-r--r--intern/cycles/kernel/kernel_emission.h128
-rw-r--r--intern/cycles/kernel/kernel_globals.h47
-rw-r--r--intern/cycles/kernel/kernel_jitter.h5
-rw-r--r--intern/cycles/kernel/kernel_light.h83
-rw-r--r--intern/cycles/kernel/kernel_math.h1
-rw-r--r--intern/cycles/kernel/kernel_path.h468
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h118
-rw-r--r--intern/cycles/kernel/kernel_path_state.h10
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h22
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h16
-rw-r--r--intern/cycles/kernel/kernel_projection.h62
-rw-r--r--intern/cycles/kernel/kernel_shader.h140
-rw-r--r--intern/cycles/kernel/kernel_shaderdata_vars.h99
-rw-r--r--intern/cycles/kernel/kernel_shadow.h27
-rw-r--r--intern/cycles/kernel/kernel_subsurface.h165
-rw-r--r--intern/cycles/kernel/kernel_textures.h12
-rw-r--r--intern/cycles/kernel/kernel_types.h447
-rw-r--r--intern/cycles/kernel/kernel_volume.h75
-rw-r--r--intern/cycles/kernel/kernel_work_stealing.h2
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel.cpp93
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_avx.cpp73
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp77
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu.h52
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h131
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp62
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp65
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp67
-rw-r--r--intern/cycles/kernel/kernels/cuda/kernel.cu106
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel.cl41
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl7
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_data_init.cl161
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl11
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl9
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl10
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl9
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl8
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl9
-rw-r--r--intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl24
-rw-r--r--intern/cycles/kernel/osl/SConscript80
-rw-r--r--intern/cycles/kernel/osl/background.cpp10
-rw-r--r--intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp4
-rw-r--r--intern/cycles/kernel/osl/bsdf_phong_ramp.cpp4
-rw-r--r--intern/cycles/kernel/osl/emissive.cpp4
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.cpp37
-rw-r--r--intern/cycles/kernel/osl/osl_bssrdf.h1
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp2
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h14
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h8
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp149
-rw-r--r--intern/cycles/kernel/osl/osl_services.h81
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp470
-rw-r--r--intern/cycles/kernel/osl/osl_shader.h6
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt6
-rw-r--r--intern/cycles/kernel/shaders/SConscript68
-rw-r--r--intern/cycles/kernel/shaders/node_environment_texture.osl3
-rw-r--r--intern/cycles/kernel/shaders/node_light_path.osl7
-rw-r--r--intern/cycles/kernel/shaders/node_magic_texture.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_rgb_curves.osl25
-rw-r--r--intern/cycles/kernel/shaders/node_subsurface_scattering.osl6
-rw-r--r--intern/cycles/kernel/shaders/node_vector_curves.osl29
-rw-r--r--intern/cycles/kernel/shaders/node_voxel_texture.osl4
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl16
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h33
-rw-r--r--intern/cycles/kernel/split/kernel_background_buffer_update.h15
-rw-r--r--intern/cycles/kernel/split/kernel_data_init.h193
-rw-r--r--intern/cycles/kernel/split/kernel_direct_lighting.h20
-rw-r--r--intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h13
-rw-r--r--intern/cycles/kernel/split/kernel_lamp_emission.h114
-rw-r--r--intern/cycles/kernel/split/kernel_next_iteration_setup.h19
-rw-r--r--intern/cycles/kernel/split/kernel_scene_intersect.h10
-rw-r--r--intern/cycles/kernel/split/kernel_shader_eval.h17
-rw-r--r--intern/cycles/kernel/split/kernel_shadow_blocked.h27
-rw-r--r--intern/cycles/kernel/svm/svm.h8
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h11
-rw-r--r--intern/cycles/kernel/svm/svm_checker.h6
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h44
-rw-r--r--intern/cycles/kernel/svm/svm_gamma.h7
-rw-r--r--intern/cycles/kernel/svm/svm_image.h27
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h12
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h12
-rw-r--r--intern/cycles/kernel/svm/svm_mix.h2
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h8
-rw-r--r--intern/cycles/kernel/svm/svm_ramp.h65
-rw-r--r--intern/cycles/kernel/svm/svm_sky.h6
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h24
-rw-r--r--intern/cycles/kernel/svm/svm_types.h15
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h25
-rw-r--r--intern/cycles/kernel/svm/svm_wave.h15
-rw-r--r--intern/cycles/render/CMakeLists.txt4
-rw-r--r--intern/cycles/render/attribute.cpp3
-rw-r--r--intern/cycles/render/background.cpp18
-rw-r--r--intern/cycles/render/background.h3
-rw-r--r--intern/cycles/render/bake.cpp32
-rw-r--r--intern/cycles/render/bake.h4
-rw-r--r--intern/cycles/render/camera.cpp157
-rw-r--r--intern/cycles/render/camera.h59
-rw-r--r--intern/cycles/render/curves.h44
-rw-r--r--intern/cycles/render/film.cpp67
-rw-r--r--intern/cycles/render/film.h5
-rw-r--r--intern/cycles/render/graph.cpp281
-rw-r--r--intern/cycles/render/graph.h55
-rw-r--r--intern/cycles/render/image.cpp70
-rw-r--r--intern/cycles/render/image.h25
-rw-r--r--intern/cycles/render/integrator.cpp18
-rw-r--r--intern/cycles/render/integrator.h4
-rw-r--r--intern/cycles/render/light.cpp71
-rw-r--r--intern/cycles/render/light.h26
-rw-r--r--intern/cycles/render/mesh.cpp132
-rw-r--r--intern/cycles/render/mesh.h30
-rw-r--r--intern/cycles/render/mesh_displace.cpp16
-rw-r--r--intern/cycles/render/nodes.cpp405
-rw-r--r--intern/cycles/render/nodes.h291
-rw-r--r--intern/cycles/render/object.cpp7
-rw-r--r--intern/cycles/render/osl.cpp115
-rw-r--r--intern/cycles/render/osl.h9
-rw-r--r--intern/cycles/render/scene.cpp32
-rw-r--r--intern/cycles/render/scene.h19
-rw-r--r--intern/cycles/render/session.cpp13
-rw-r--r--intern/cycles/render/session.h2
-rw-r--r--intern/cycles/render/shader.cpp41
-rw-r--r--intern/cycles/render/shader.h36
-rw-r--r--intern/cycles/render/sky_model.cpp370
-rw-r--r--intern/cycles/render/svm.cpp268
-rw-r--r--intern/cycles/render/svm.h95
-rw-r--r--intern/cycles/render/tile.cpp347
-rw-r--r--intern/cycles/render/tile.h36
-rw-r--r--intern/cycles/subd/CMakeLists.txt4
-rw-r--r--intern/cycles/subd/subd_dice.cpp53
-rw-r--r--intern/cycles/subd/subd_dice.h3
-rw-r--r--intern/cycles/subd/subd_mesh.cpp13
-rw-r--r--intern/cycles/subd/subd_patch.cpp29
-rw-r--r--intern/cycles/subd/subd_patch.h10
-rw-r--r--intern/cycles/subd/subd_split.cpp247
-rw-r--r--intern/cycles/subd/subd_split.h2
-rw-r--r--intern/cycles/test/CMakeLists.txt31
-rw-r--r--intern/cycles/test/util_aligned_malloc_test.cpp42
-rw-r--r--intern/cycles/test/util_path_test.cpp401
-rw-r--r--intern/cycles/test/util_string_test.cpp248
-rw-r--r--intern/cycles/test/util_task_test.cpp56
-rw-r--r--intern/cycles/util/CMakeLists.txt24
-rw-r--r--intern/cycles/util/util_aligned_malloc.cpp3
-rw-r--r--intern/cycles/util/util_cache.cpp114
-rw-r--r--intern/cycles/util/util_cache.h182
-rw-r--r--intern/cycles/util/util_debug.cpp167
-rw-r--r--intern/cycles/util/util_debug.h120
-rw-r--r--intern/cycles/util/util_guarded_allocator.h124
-rw-r--r--intern/cycles/util/util_logging.h2
-rw-r--r--intern/cycles/util/util_math.h46
-rw-r--r--intern/cycles/util/util_math_cdf.cpp67
-rw-r--r--intern/cycles/util/util_math_cdf.h78
-rw-r--r--intern/cycles/util/util_math_fast.h11
-rw-r--r--intern/cycles/util/util_md5.cpp9
-rw-r--r--intern/cycles/util/util_md5.h2
-rw-r--r--intern/cycles/util/util_optimization.h85
-rw-r--r--intern/cycles/util/util_path.cpp631
-rw-r--r--intern/cycles/util/util_path.h5
-rw-r--r--intern/cycles/util/util_queue.h29
-rw-r--r--intern/cycles/util/util_set.h28
-rw-r--r--intern/cycles/util/util_simd.cpp3
-rw-r--r--intern/cycles/util/util_simd.h17
-rw-r--r--intern/cycles/util/util_sky_model.cpp370
-rw-r--r--intern/cycles/util/util_sky_model.h (renamed from intern/cycles/render/sky_model.h)0
-rw-r--r--intern/cycles/util/util_sky_model_data.h (renamed from intern/cycles/render/sky_model_data.h)0
-rw-r--r--intern/cycles/util/util_ssef.h4
-rw-r--r--intern/cycles/util/util_stack_allocator.h159
-rw-r--r--intern/cycles/util/util_string.cpp147
-rw-r--r--intern/cycles/util/util_string.h17
-rw-r--r--intern/cycles/util/util_system.cpp55
-rw-r--r--intern/cycles/util/util_task.cpp39
-rw-r--r--intern/cycles/util/util_task.h41
-rw-r--r--intern/cycles/util/util_texture.h53
-rw-r--r--intern/cycles/util/util_thread.h45
-rw-r--r--intern/cycles/util/util_time.cpp3
-rw-r--r--intern/cycles/util/util_time.h18
-rw-r--r--intern/cycles/util/util_transform.cpp2
-rw-r--r--intern/cycles/util/util_transform.h7
-rw-r--r--intern/cycles/util/util_types.h4
-rw-r--r--intern/cycles/util/util_vector.h149
-rw-r--r--intern/cycles/util/util_version.h37
-rw-r--r--intern/cycles/util/util_view.cpp9
-rw-r--r--intern/cycles/util/util_windows.h37
-rw-r--r--intern/dualcon/SConscript35
-rw-r--r--intern/dualcon/intern/Projections.h2
-rw-r--r--intern/eigen/CMakeLists.txt46
-rw-r--r--intern/eigen/eigen_capi.h34
-rw-r--r--intern/eigen/intern/eigenvalues.cc70
-rw-r--r--intern/eigen/intern/eigenvalues.h40
-rw-r--r--intern/eigen/intern/linear_solver.cc366
-rw-r--r--intern/eigen/intern/linear_solver.h72
-rw-r--r--intern/eigen/intern/svd.cc75
-rw-r--r--intern/eigen/intern/svd.h40
-rw-r--r--intern/elbeem/SConscript48
-rw-r--r--intern/elbeem/intern/simulation_object.cpp2
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h226
-rw-r--r--intern/ghost/CMakeLists.txt18
-rw-r--r--intern/ghost/GHOST_C-api.h3
-rw-r--r--intern/ghost/GHOST_ISystem.h3
-rw-r--r--intern/ghost/GHOST_Types.h3
-rw-r--r--intern/ghost/SConscript199
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp23
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h9
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm11
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp120
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp43
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.h3
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerWin32.cpp1
-rw-r--r--intern/ghost/intern/GHOST_EventManager.cpp75
-rw-r--r--intern/ghost/intern/GHOST_EventManager.h23
-rw-r--r--intern/ghost/intern/GHOST_ISystemPaths.cpp4
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h7
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager3Dconnexion.c94
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager3Dconnexion.h50
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.h22
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.mm240
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.cpp146
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.h47
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerX11.cpp145
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerX11.h48
-rw-r--r--intern/ghost/intern/GHOST_System.cpp9
-rw-r--r--intern/ghost/intern/GHOST_System.h3
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h7
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm76
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.cpp127
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.h79
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsWin32.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsX11.cpp128
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsX11.h80
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp1
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h3
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp63
-rw-r--r--intern/ghost/intern/GHOST_TaskbarWin32.h3
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm115
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp27
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h1
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp78
-rw-r--r--intern/ghost/test/CMakeLists.txt2
-rw-r--r--intern/glew-mx/SConscript15
-rw-r--r--intern/glew-mx/glew-mx.h2
-rw-r--r--intern/glew-mx/intern/glew-mx.c9
-rw-r--r--intern/guardedalloc/SConscript45
-rw-r--r--intern/iksolver/CMakeLists.txt29
-rw-r--r--intern/iksolver/SConscript35
-rw-r--r--intern/iksolver/intern/IK_Math.h261
-rw-r--r--intern/iksolver/intern/IK_QJacobian.cpp208
-rw-r--r--intern/iksolver/intern/IK_QJacobian.h62
-rw-r--r--intern/iksolver/intern/IK_QJacobianSolver.cpp102
-rw-r--r--intern/iksolver/intern/IK_QJacobianSolver.h28
-rw-r--r--intern/iksolver/intern/IK_QSegment.cpp398
-rw-r--r--intern/iksolver/intern/IK_QSegment.h171
-rw-r--r--intern/iksolver/intern/IK_QTask.cpp71
-rw-r--r--intern/iksolver/intern/IK_QTask.h56
-rw-r--r--intern/iksolver/intern/IK_Solver.cpp70
-rw-r--r--intern/iksolver/intern/MT_ExpMap.cpp250
-rw-r--r--intern/iksolver/intern/MT_ExpMap.h213
-rw-r--r--intern/iksolver/intern/TNT/cholesky.h98
-rw-r--r--intern/iksolver/intern/TNT/cmat.h614
-rw-r--r--intern/iksolver/intern/TNT/fcscmat.h167
-rw-r--r--intern/iksolver/intern/TNT/fmat.h569
-rw-r--r--intern/iksolver/intern/TNT/fortran.h69
-rw-r--r--intern/iksolver/intern/TNT/fspvec.h171
-rw-r--r--intern/iksolver/intern/TNT/index.h87
-rw-r--r--intern/iksolver/intern/TNT/lapack.h189
-rw-r--r--intern/iksolver/intern/TNT/lu.h208
-rw-r--r--intern/iksolver/intern/TNT/qr.h233
-rw-r--r--intern/iksolver/intern/TNT/region1d.h375
-rw-r--r--intern/iksolver/intern/TNT/region2d.h471
-rw-r--r--intern/iksolver/intern/TNT/stopwatch.h83
-rw-r--r--intern/iksolver/intern/TNT/subscript.h63
-rw-r--r--intern/iksolver/intern/TNT/svd.h435
-rw-r--r--intern/iksolver/intern/TNT/tnt.h93
-rw-r--r--intern/iksolver/intern/TNT/tntmath.h154
-rw-r--r--intern/iksolver/intern/TNT/tntreqs.h73
-rw-r--r--intern/iksolver/intern/TNT/transv.h164
-rw-r--r--intern/iksolver/intern/TNT/triang.h637
-rw-r--r--intern/iksolver/intern/TNT/trisolve.h188
-rw-r--r--intern/iksolver/intern/TNT/vec.h491
-rw-r--r--intern/iksolver/intern/TNT/vecadaptor.h284
-rw-r--r--intern/iksolver/intern/TNT/version.h25
-rw-r--r--intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp91
-rw-r--r--intern/iksolver/test/ik_glut_test/common/GlutDrawer.h95
-rw-r--r--intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp84
-rw-r--r--intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h101
-rw-r--r--intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp99
-rw-r--r--intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h111
-rw-r--r--intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h375
-rw-r--r--intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h80
-rw-r--r--intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h206
-rw-r--r--intern/iksolver/test/ik_glut_test/intern/main.cpp321
-rw-r--r--intern/itasc/SConscript38
-rw-r--r--intern/itasc/kdl/chain.hpp9
-rw-r--r--intern/itasc/kdl/tree.hpp14
-rw-r--r--intern/libmv/CMakeLists.txt238
-rw-r--r--intern/libmv/ChangeLog603
-rwxr-xr-xintern/libmv/bundle.sh187
-rw-r--r--intern/libmv/files.txt138
-rw-r--r--intern/libmv/intern/autotrack.cc (renamed from extern/libmv/intern/autotrack.cc)0
-rw-r--r--intern/libmv/intern/autotrack.h (renamed from extern/libmv/intern/autotrack.h)0
-rw-r--r--intern/libmv/intern/camera_intrinsics.cc345
-rw-r--r--intern/libmv/intern/camera_intrinsics.h138
-rw-r--r--intern/libmv/intern/detector.cc (renamed from extern/libmv/intern/detector.cc)0
-rw-r--r--intern/libmv/intern/detector.h (renamed from extern/libmv/intern/detector.h)0
-rw-r--r--intern/libmv/intern/frame_accessor.cc164
-rw-r--r--intern/libmv/intern/frame_accessor.h (renamed from extern/libmv/intern/frame_accessor.h)0
-rw-r--r--intern/libmv/intern/homography.cc (renamed from extern/libmv/intern/homography.cc)0
-rw-r--r--intern/libmv/intern/homography.h (renamed from extern/libmv/intern/homography.h)0
-rw-r--r--intern/libmv/intern/image.cc (renamed from extern/libmv/intern/image.cc)0
-rw-r--r--intern/libmv/intern/image.h (renamed from extern/libmv/intern/image.h)0
-rw-r--r--intern/libmv/intern/logging.cc (renamed from extern/libmv/intern/logging.cc)0
-rw-r--r--intern/libmv/intern/logging.h (renamed from extern/libmv/intern/logging.h)0
-rw-r--r--intern/libmv/intern/reconstruction.cc (renamed from extern/libmv/intern/reconstruction.cc)0
-rw-r--r--intern/libmv/intern/reconstruction.h (renamed from extern/libmv/intern/reconstruction.h)0
-rw-r--r--intern/libmv/intern/region.h (renamed from extern/libmv/intern/region.h)0
-rw-r--r--intern/libmv/intern/stub.cc398
-rw-r--r--intern/libmv/intern/track_region.cc177
-rw-r--r--intern/libmv/intern/track_region.h (renamed from extern/libmv/intern/track_region.h)0
-rw-r--r--intern/libmv/intern/tracks.cc (renamed from extern/libmv/intern/tracks.cc)0
-rw-r--r--intern/libmv/intern/tracks.h (renamed from extern/libmv/intern/tracks.h)0
-rw-r--r--intern/libmv/intern/tracksN.cc (renamed from extern/libmv/intern/tracksN.cc)0
-rw-r--r--intern/libmv/intern/tracksN.h (renamed from extern/libmv/intern/tracksN.h)0
-rw-r--r--intern/libmv/intern/utildefines.h62
-rw-r--r--intern/libmv/libmv-capi.h (renamed from extern/libmv/libmv-capi.h)0
-rw-r--r--intern/libmv/libmv/autotrack/autotrack.cc (renamed from extern/libmv/libmv/autotrack/autotrack.cc)0
-rw-r--r--intern/libmv/libmv/autotrack/autotrack.h (renamed from extern/libmv/libmv/autotrack/autotrack.h)0
-rw-r--r--intern/libmv/libmv/autotrack/callbacks.h (renamed from extern/libmv/libmv/autotrack/callbacks.h)0
-rw-r--r--intern/libmv/libmv/autotrack/frame_accessor.h (renamed from extern/libmv/libmv/autotrack/frame_accessor.h)0
-rw-r--r--intern/libmv/libmv/autotrack/marker.h (renamed from extern/libmv/libmv/autotrack/marker.h)0
-rw-r--r--intern/libmv/libmv/autotrack/model.h (renamed from extern/libmv/libmv/autotrack/model.h)0
-rw-r--r--intern/libmv/libmv/autotrack/predict_tracks.cc (renamed from extern/libmv/libmv/autotrack/predict_tracks.cc)0
-rw-r--r--intern/libmv/libmv/autotrack/predict_tracks.h (renamed from extern/libmv/libmv/autotrack/predict_tracks.h)0
-rw-r--r--intern/libmv/libmv/autotrack/predict_tracks_test.cc201
-rw-r--r--intern/libmv/libmv/autotrack/quad.h (renamed from extern/libmv/libmv/autotrack/quad.h)0
-rw-r--r--intern/libmv/libmv/autotrack/reconstruction.h (renamed from extern/libmv/libmv/autotrack/reconstruction.h)0
-rw-r--r--intern/libmv/libmv/autotrack/region.h (renamed from extern/libmv/libmv/autotrack/region.h)0
-rw-r--r--intern/libmv/libmv/autotrack/tracks.cc (renamed from extern/libmv/libmv/autotrack/tracks.cc)0
-rw-r--r--intern/libmv/libmv/autotrack/tracks.h (renamed from extern/libmv/libmv/autotrack/tracks.h)0
-rw-r--r--intern/libmv/libmv/autotrack/tracks_test.cc (renamed from extern/libmv/libmv/autotrack/tracks_test.cc)0
-rw-r--r--intern/libmv/libmv/base/aligned_malloc.cc74
-rw-r--r--intern/libmv/libmv/base/aligned_malloc.h (renamed from extern/libmv/libmv/base/aligned_malloc.h)0
-rw-r--r--intern/libmv/libmv/base/id_generator.h (renamed from extern/libmv/libmv/base/id_generator.h)0
-rw-r--r--intern/libmv/libmv/base/scoped_ptr.h (renamed from extern/libmv/libmv/base/scoped_ptr.h)0
-rw-r--r--intern/libmv/libmv/base/scoped_ptr_test.cc (renamed from extern/libmv/libmv/base/scoped_ptr_test.cc)0
-rw-r--r--intern/libmv/libmv/base/vector.h (renamed from extern/libmv/libmv/base/vector.h)0
-rw-r--r--intern/libmv/libmv/base/vector_test.cc (renamed from extern/libmv/libmv/base/vector_test.cc)0
-rw-r--r--intern/libmv/libmv/base/vector_utils.h (renamed from extern/libmv/libmv/base/vector_utils.h)0
-rw-r--r--intern/libmv/libmv/image/array_nd.cc (renamed from extern/libmv/libmv/image/array_nd.cc)0
-rw-r--r--intern/libmv/libmv/image/array_nd.h497
-rw-r--r--intern/libmv/libmv/image/array_nd_test.cc (renamed from extern/libmv/libmv/image/array_nd_test.cc)0
-rw-r--r--intern/libmv/libmv/image/convolve.cc (renamed from extern/libmv/libmv/image/convolve.cc)0
-rw-r--r--intern/libmv/libmv/image/convolve.h (renamed from extern/libmv/libmv/image/convolve.h)0
-rw-r--r--intern/libmv/libmv/image/convolve_test.cc (renamed from extern/libmv/libmv/image/convolve_test.cc)0
-rw-r--r--intern/libmv/libmv/image/correlation.h (renamed from extern/libmv/libmv/image/correlation.h)0
-rw-r--r--intern/libmv/libmv/image/image.h (renamed from extern/libmv/libmv/image/image.h)0
-rw-r--r--intern/libmv/libmv/image/image_converter.h (renamed from extern/libmv/libmv/image/image_converter.h)0
-rw-r--r--intern/libmv/libmv/image/image_drawing.h (renamed from extern/libmv/libmv/image/image_drawing.h)0
-rw-r--r--intern/libmv/libmv/image/image_test.cc (renamed from extern/libmv/libmv/image/image_test.cc)0
-rw-r--r--intern/libmv/libmv/image/sample.h (renamed from extern/libmv/libmv/image/sample.h)0
-rw-r--r--intern/libmv/libmv/image/sample_test.cc (renamed from extern/libmv/libmv/image/sample_test.cc)0
-rw-r--r--intern/libmv/libmv/image/tuple.h (renamed from extern/libmv/libmv/image/tuple.h)0
-rw-r--r--intern/libmv/libmv/image/tuple_test.cc (renamed from extern/libmv/libmv/image/tuple_test.cc)0
-rw-r--r--intern/libmv/libmv/logging/logging.h (renamed from extern/libmv/libmv/logging/logging.h)0
-rw-r--r--intern/libmv/libmv/multiview/conditioning.cc (renamed from extern/libmv/libmv/multiview/conditioning.cc)0
-rw-r--r--intern/libmv/libmv/multiview/conditioning.h (renamed from extern/libmv/libmv/multiview/conditioning.h)0
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection.cc (renamed from extern/libmv/libmv/multiview/euclidean_resection.cc)0
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection.h (renamed from extern/libmv/libmv/multiview/euclidean_resection.h)0
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection_test.cc237
-rw-r--r--intern/libmv/libmv/multiview/fundamental.cc (renamed from extern/libmv/libmv/multiview/fundamental.cc)0
-rw-r--r--intern/libmv/libmv/multiview/fundamental.h180
-rw-r--r--intern/libmv/libmv/multiview/fundamental_test.cc (renamed from extern/libmv/libmv/multiview/fundamental_test.cc)0
-rw-r--r--intern/libmv/libmv/multiview/homography.cc465
-rw-r--r--intern/libmv/libmv/multiview/homography.h (renamed from extern/libmv/libmv/multiview/homography.h)0
-rw-r--r--intern/libmv/libmv/multiview/homography_error.h (renamed from extern/libmv/libmv/multiview/homography_error.h)0
-rw-r--r--intern/libmv/libmv/multiview/homography_parameterization.h (renamed from extern/libmv/libmv/multiview/homography_parameterization.h)0
-rw-r--r--intern/libmv/libmv/multiview/homography_test.cc (renamed from extern/libmv/libmv/multiview/homography_test.cc)0
-rw-r--r--intern/libmv/libmv/multiview/nviewtriangulation.h (renamed from extern/libmv/libmv/multiview/nviewtriangulation.h)0
-rw-r--r--intern/libmv/libmv/multiview/nviewtriangulation_test.cc (renamed from extern/libmv/libmv/multiview/nviewtriangulation_test.cc)0
-rw-r--r--intern/libmv/libmv/multiview/panography.cc (renamed from extern/libmv/libmv/multiview/panography.cc)0
-rw-r--r--intern/libmv/libmv/multiview/panography.h (renamed from extern/libmv/libmv/multiview/panography.h)0
-rw-r--r--intern/libmv/libmv/multiview/panography_kernel.cc (renamed from extern/libmv/libmv/multiview/panography_kernel.cc)0
-rw-r--r--intern/libmv/libmv/multiview/panography_kernel.h (renamed from extern/libmv/libmv/multiview/panography_kernel.h)0
-rw-r--r--intern/libmv/libmv/multiview/panography_test.cc (renamed from extern/libmv/libmv/multiview/panography_test.cc)0
-rw-r--r--intern/libmv/libmv/multiview/projection.cc (renamed from extern/libmv/libmv/multiview/projection.cc)0
-rw-r--r--intern/libmv/libmv/multiview/projection.h (renamed from extern/libmv/libmv/multiview/projection.h)0
-rw-r--r--intern/libmv/libmv/multiview/projection_test.cc115
-rw-r--r--intern/libmv/libmv/multiview/resection.h (renamed from extern/libmv/libmv/multiview/resection.h)0
-rw-r--r--intern/libmv/libmv/multiview/resection_test.cc (renamed from extern/libmv/libmv/multiview/resection_test.cc)0
-rw-r--r--intern/libmv/libmv/multiview/test_data_sets.cc (renamed from extern/libmv/libmv/multiview/test_data_sets.cc)0
-rw-r--r--intern/libmv/libmv/multiview/test_data_sets.h (renamed from extern/libmv/libmv/multiview/test_data_sets.h)0
-rw-r--r--intern/libmv/libmv/multiview/triangulation.cc (renamed from extern/libmv/libmv/multiview/triangulation.cc)0
-rw-r--r--intern/libmv/libmv/multiview/triangulation.h (renamed from extern/libmv/libmv/multiview/triangulation.h)0
-rw-r--r--intern/libmv/libmv/multiview/triangulation_test.cc (renamed from extern/libmv/libmv/multiview/triangulation_test.cc)0
-rw-r--r--intern/libmv/libmv/multiview/two_view_kernel.h (renamed from extern/libmv/libmv/multiview/two_view_kernel.h)0
-rw-r--r--intern/libmv/libmv/numeric/dogleg.h (renamed from extern/libmv/libmv/numeric/dogleg.h)0
-rw-r--r--intern/libmv/libmv/numeric/dogleg_test.cc (renamed from extern/libmv/libmv/numeric/dogleg_test.cc)0
-rw-r--r--intern/libmv/libmv/numeric/function_derivative.h (renamed from extern/libmv/libmv/numeric/function_derivative.h)0
-rw-r--r--intern/libmv/libmv/numeric/function_derivative_test.cc (renamed from extern/libmv/libmv/numeric/function_derivative_test.cc)0
-rw-r--r--intern/libmv/libmv/numeric/levenberg_marquardt.h (renamed from extern/libmv/libmv/numeric/levenberg_marquardt.h)0
-rw-r--r--intern/libmv/libmv/numeric/levenberg_marquardt_test.cc (renamed from extern/libmv/libmv/numeric/levenberg_marquardt_test.cc)0
-rw-r--r--intern/libmv/libmv/numeric/numeric.cc (renamed from extern/libmv/libmv/numeric/numeric.cc)0
-rw-r--r--intern/libmv/libmv/numeric/numeric.h502
-rw-r--r--intern/libmv/libmv/numeric/numeric_test.cc (renamed from extern/libmv/libmv/numeric/numeric_test.cc)0
-rw-r--r--intern/libmv/libmv/numeric/poly.cc (renamed from extern/libmv/libmv/numeric/poly.cc)0
-rw-r--r--intern/libmv/libmv/numeric/poly.h (renamed from extern/libmv/libmv/numeric/poly.h)0
-rw-r--r--intern/libmv/libmv/numeric/poly_test.cc83
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.cc (renamed from extern/libmv/libmv/simple_pipeline/bundle.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.h (renamed from extern/libmv/libmv/simple_pipeline/bundle.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/callbacks.h (renamed from extern/libmv/libmv/simple_pipeline/callbacks.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc (renamed from extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics.h (renamed from extern/libmv/libmv/simple_pipeline/camera_intrinsics.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h (renamed from extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc (renamed from extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/detect.cc (renamed from extern/libmv/libmv/simple_pipeline/detect.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/detect.h (renamed from extern/libmv/libmv/simple_pipeline/detect.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/detect_test.cc232
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.cc (renamed from extern/libmv/libmv/simple_pipeline/distortion_models.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/distortion_models.h (renamed from extern/libmv/libmv/simple_pipeline/distortion_models.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc (renamed from extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h (renamed from extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/intersect.cc (renamed from extern/libmv/libmv/simple_pipeline/intersect.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/intersect.h (renamed from extern/libmv/libmv/simple_pipeline/intersect.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/intersect_test.cc (renamed from extern/libmv/libmv/simple_pipeline/intersect_test.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/keyframe_selection.cc (renamed from extern/libmv/libmv/simple_pipeline/keyframe_selection.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/keyframe_selection.h (renamed from extern/libmv/libmv/simple_pipeline/keyframe_selection.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc (renamed from extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver.cc251
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver.h (renamed from extern/libmv/libmv/simple_pipeline/modal_solver.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver_test.cc (renamed from extern/libmv/libmv/simple_pipeline/modal_solver_test.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/pipeline.cc (renamed from extern/libmv/libmv/simple_pipeline/pipeline.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/pipeline.h (renamed from extern/libmv/libmv/simple_pipeline/pipeline.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction.cc (renamed from extern/libmv/libmv/simple_pipeline/reconstruction.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction.h (renamed from extern/libmv/libmv/simple_pipeline/reconstruction.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc (renamed from extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/reconstruction_scale.h (renamed from extern/libmv/libmv/simple_pipeline/reconstruction_scale.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/resect.cc (renamed from extern/libmv/libmv/simple_pipeline/resect.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/resect.h (renamed from extern/libmv/libmv/simple_pipeline/resect.h)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/resect_test.cc (renamed from extern/libmv/libmv/simple_pipeline/resect_test.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/tracks.cc (renamed from extern/libmv/libmv/simple_pipeline/tracks.cc)0
-rw-r--r--intern/libmv/libmv/simple_pipeline/tracks.h (renamed from extern/libmv/libmv/simple_pipeline/tracks.h)0
-rw-r--r--intern/libmv/libmv/tracking/brute_region_tracker.cc (renamed from extern/libmv/libmv/tracking/brute_region_tracker.cc)0
-rw-r--r--intern/libmv/libmv/tracking/brute_region_tracker.h (renamed from extern/libmv/libmv/tracking/brute_region_tracker.h)0
-rw-r--r--intern/libmv/libmv/tracking/brute_region_tracker_test.cc (renamed from extern/libmv/libmv/tracking/brute_region_tracker_test.cc)0
-rw-r--r--intern/libmv/libmv/tracking/hybrid_region_tracker.cc (renamed from extern/libmv/libmv/tracking/hybrid_region_tracker.cc)0
-rw-r--r--intern/libmv/libmv/tracking/hybrid_region_tracker.h (renamed from extern/libmv/libmv/tracking/hybrid_region_tracker.h)0
-rw-r--r--intern/libmv/libmv/tracking/kalman_filter.h (renamed from extern/libmv/libmv/tracking/kalman_filter.h)0
-rw-r--r--intern/libmv/libmv/tracking/klt_region_tracker.cc (renamed from extern/libmv/libmv/tracking/klt_region_tracker.cc)0
-rw-r--r--intern/libmv/libmv/tracking/klt_region_tracker.h (renamed from extern/libmv/libmv/tracking/klt_region_tracker.h)0
-rw-r--r--intern/libmv/libmv/tracking/klt_region_tracker_test.cc (renamed from extern/libmv/libmv/tracking/klt_region_tracker_test.cc)0
-rw-r--r--intern/libmv/libmv/tracking/pyramid_region_tracker.cc (renamed from extern/libmv/libmv/tracking/pyramid_region_tracker.cc)0
-rw-r--r--intern/libmv/libmv/tracking/pyramid_region_tracker.h (renamed from extern/libmv/libmv/tracking/pyramid_region_tracker.h)0
-rw-r--r--intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc (renamed from extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc)0
-rw-r--r--intern/libmv/libmv/tracking/region_tracker.h (renamed from extern/libmv/libmv/tracking/region_tracker.h)0
-rw-r--r--intern/libmv/libmv/tracking/retrack_region_tracker.cc (renamed from extern/libmv/libmv/tracking/retrack_region_tracker.cc)0
-rw-r--r--intern/libmv/libmv/tracking/retrack_region_tracker.h (renamed from extern/libmv/libmv/tracking/retrack_region_tracker.h)0
-rw-r--r--intern/libmv/libmv/tracking/track_region.cc (renamed from extern/libmv/libmv/tracking/track_region.cc)0
-rw-r--r--intern/libmv/libmv/tracking/track_region.h (renamed from extern/libmv/libmv/tracking/track_region.h)0
-rw-r--r--intern/libmv/libmv/tracking/trklt_region_tracker.cc (renamed from extern/libmv/libmv/tracking/trklt_region_tracker.cc)0
-rw-r--r--intern/libmv/libmv/tracking/trklt_region_tracker.h (renamed from extern/libmv/libmv/tracking/trklt_region_tracker.h)0
-rwxr-xr-xintern/libmv/mkfiles.sh6
-rw-r--r--intern/libmv/third_party/msinttypes/README.libmv (renamed from extern/libmv/third_party/msinttypes/README.libmv)0
-rw-r--r--intern/libmv/third_party/msinttypes/inttypes.h (renamed from extern/libmv/third_party/msinttypes/inttypes.h)0
-rw-r--r--intern/libmv/third_party/msinttypes/stdint.h (renamed from extern/libmv/third_party/msinttypes/stdint.h)0
-rw-r--r--intern/locale/SConscript92
-rw-r--r--intern/locale/boost_locale_wrapper.cpp2
-rw-r--r--intern/memutil/CMakeLists.txt3
-rw-r--r--intern/memutil/MEM_NonCopyable.h62
-rw-r--r--intern/memutil/MEM_RefCountPtr.h297
-rw-r--r--intern/memutil/MEM_SmartPtr.h245
-rw-r--r--intern/memutil/SConscript34
-rw-r--r--intern/mikktspace/CMakeLists.txt7
-rw-r--r--intern/mikktspace/SConscript35
-rw-r--r--intern/mikktspace/mikktspace.c9
-rw-r--r--intern/moto/CMakeLists.txt6
-rw-r--r--intern/moto/SConscript34
-rw-r--r--intern/moto/include/GEN_List.h87
-rw-r--r--intern/moto/include/GEN_Map.h181
-rw-r--r--intern/moto/include/MT_CmMatrix4x4.h16
-rw-r--r--intern/moto/include/MT_Matrix3x3.h50
-rw-r--r--intern/moto/include/MT_Matrix3x3.inl16
-rw-r--r--intern/moto/include/MT_Matrix4x4.h10
-rw-r--r--intern/moto/include/MT_Matrix4x4.inl16
-rw-r--r--intern/moto/include/MT_Plane3.h137
-rw-r--r--intern/moto/include/MT_Plane3.inl128
-rw-r--r--intern/moto/include/MT_Quaternion.h16
-rw-r--r--intern/moto/include/MT_Quaternion.inl32
-rw-r--r--intern/moto/include/MT_Scalar.h15
-rw-r--r--intern/moto/include/MT_Vector2.inl10
-rw-r--r--intern/moto/include/MT_Vector3.h1
-rw-r--r--intern/moto/include/MT_Vector3.inl22
-rw-r--r--intern/moto/include/MT_Vector4.h1
-rw-r--r--intern/moto/include/MT_Vector4.inl6
-rw-r--r--intern/moto/include/NM_Scalar.h159
-rw-r--r--intern/moto/intern/MT_CmMatrix4x4.cpp36
-rw-r--r--intern/moto/intern/MT_Plane3.cpp37
-rw-r--r--intern/moto/intern/MT_Transform.cpp4
-rw-r--r--intern/opencolorio/SConscript56
-rw-r--r--intern/opencolorio/ocio_impl.cc7
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc12
-rw-r--r--intern/opennl/CMakeLists.txt93
-rw-r--r--intern/opennl/SConscript35
-rw-r--r--intern/opennl/doc/OpenNL_License.txt341
-rw-r--r--intern/opennl/doc/OpenNL_Readme.txt13
-rw-r--r--intern/opennl/doc/SuperLU_License.txt31
-rw-r--r--intern/opennl/doc/SuperLU_Readme.txt52
-rw-r--r--intern/opennl/extern/ONL_opennl.h144
-rw-r--r--intern/opennl/intern/opennl.c1270
-rw-r--r--intern/opennl/superlu/Cnames.h284
-rw-r--r--intern/opennl/superlu/get_perm_c.c466
-rw-r--r--intern/opennl/superlu/heap_relax_snode.c119
-rw-r--r--intern/opennl/superlu/lsame.c76
-rw-r--r--intern/opennl/superlu/memory.c214
-rw-r--r--intern/opennl/superlu/mmd.c1028
-rw-r--r--intern/opennl/superlu/relax_snode.c74
-rw-r--r--intern/opennl/superlu/scolumn_bmod.c355
-rw-r--r--intern/opennl/superlu/scolumn_dfs.c273
-rw-r--r--intern/opennl/superlu/scopy_to_ucol.c108
-rw-r--r--intern/opennl/superlu/sgssv.c224
-rw-r--r--intern/opennl/superlu/sgstrf.c457
-rw-r--r--intern/opennl/superlu/sgstrs.c334
-rw-r--r--intern/opennl/superlu/smemory.c683
-rw-r--r--intern/opennl/superlu/smyblas2.c235
-rw-r--r--intern/opennl/superlu/sp_coletree.c335
-rw-r--r--intern/opennl/superlu/sp_ienv.c68
-rw-r--r--intern/opennl/superlu/sp_preorder.c209
-rw-r--r--intern/opennl/superlu/spanel_bmod.c452
-rw-r--r--intern/opennl/superlu/spanel_dfs.c252
-rw-r--r--intern/opennl/superlu/spivotL.c176
-rw-r--r--intern/opennl/superlu/spruneL.c152
-rw-r--r--intern/opennl/superlu/ssnode_bmod.c120
-rw-r--r--intern/opennl/superlu/ssnode_dfs.c109
-rw-r--r--intern/opennl/superlu/ssp_blas2.c475
-rw-r--r--intern/opennl/superlu/ssp_blas3.c124
-rw-r--r--intern/opennl/superlu/ssp_defs.h240
-rw-r--r--intern/opennl/superlu/strsv.c323
-rw-r--r--intern/opennl/superlu/superlu_timer.c61
-rw-r--r--intern/opennl/superlu/supermatrix.h143
-rw-r--r--intern/opennl/superlu/sutil.c485
-rw-r--r--intern/opennl/superlu/util.c400
-rw-r--r--intern/opennl/superlu/util.h271
-rw-r--r--intern/opennl/superlu/xerbla.c47
-rw-r--r--intern/opensubdiv/CMakeLists.txt5
-rw-r--r--intern/opensubdiv/SConscript69
-rw-r--r--intern/opensubdiv/gpu_shader_opensubd_display.glsl45
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc31
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h3
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc8
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h2
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc90
-rw-r--r--intern/opensubdiv/opensubdiv_utils_capi.cc32
-rw-r--r--intern/openvdb/CMakeLists.txt70
-rw-r--r--intern/openvdb/intern/openvdb_dense_convert.cc167
-rw-r--r--intern/openvdb/intern/openvdb_dense_convert.h130
-rw-r--r--intern/openvdb/intern/openvdb_reader.cc136
-rw-r--r--intern/openvdb/intern/openvdb_reader.h55
-rw-r--r--intern/openvdb/intern/openvdb_writer.cc118
-rw-r--r--intern/openvdb/intern/openvdb_writer.h57
-rw-r--r--intern/openvdb/openvdb_capi.cc240
-rw-r--r--intern/openvdb/openvdb_capi.h108
-rw-r--r--intern/openvdb/openvdb_util.cc38
-rw-r--r--intern/openvdb/openvdb_util.h57
-rw-r--r--intern/raskter/CMakeLists.txt40
-rw-r--r--intern/raskter/SConscript35
-rw-r--r--intern/raskter/raskter.c458
-rw-r--r--intern/raskter/raskter.h40
-rw-r--r--intern/rigidbody/SConscript42
-rw-r--r--intern/smoke/CMakeLists.txt2
-rw-r--r--intern/smoke/SConscript48
-rw-r--r--intern/smoke/extern/smoke_API.h3
-rw-r--r--intern/smoke/intern/MERSENNETWISTER.h44
-rw-r--r--intern/smoke/intern/smoke_API.cpp6
-rw-r--r--intern/smoke/intern/spectrum.cpp428
-rw-r--r--intern/smoke/intern/spectrum.h6
-rw-r--r--intern/string/SConscript39
-rw-r--r--intern/utfconv/SConscript41
-rw-r--r--make.bat171
-rw-r--r--release/datafiles/blender_icons.svg50
-rw-r--r--release/datafiles/blender_icons16/icon16_mesh_capsule.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_mesh_capsule.datbin0 -> 4120 bytes
-rw-r--r--release/datafiles/colormanagement/config.ocio2
-rwxr-xr-xrelease/datafiles/datatoc.py79
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/splash.pngbin140110 -> 230768 bytes
-rw-r--r--release/datafiles/splash_2x.pngbin444285 -> 812837 bytes
-rw-r--r--release/environment-macosx18
-rw-r--r--release/environment-mswindows18
-rw-r--r--release/environment-unix18
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py29
-rw-r--r--release/scripts/modules/addon_utils.py42
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py23
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py3
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py7
-rw-r--r--release/scripts/modules/bl_previews_utils/bl_previews_render.py52
-rw-r--r--release/scripts/modules/bpy/__init__.py26
-rw-r--r--release/scripts/modules/bpy/path.py55
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py2
-rw-r--r--release/scripts/modules/bpy/utils/previews.py4
-rw-r--r--release/scripts/modules/bpy_extras/image_utils.py29
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py6
-rw-r--r--release/scripts/modules/bpy_extras/keyconfig_utils.py31
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py31
-rw-r--r--release/scripts/modules/bpy_types.py46
-rw-r--r--release/scripts/modules/console_python.py52
-rw-r--r--release/scripts/modules/progress_report.py2
-rw-r--r--release/scripts/modules/rna_keymap_ui.py20
-rw-r--r--release/scripts/modules/rna_prop_ui.py3
-rw-r--r--release/scripts/modules/sys_info.py119
-rw-r--r--release/scripts/presets/interface_theme/back_to_black.xml9
-rw-r--r--release/scripts/presets/interface_theme/blender_24x.xml11
-rw-r--r--release/scripts/presets/interface_theme/elsyiun.xml43
-rw-r--r--release/scripts/presets/interface_theme/flatty_light.xml11
-rw-r--r--release/scripts/presets/interface_theme/graph.xml11
-rw-r--r--release/scripts/presets/interface_theme/hexagon.xml11
-rw-r--r--release/scripts/presets/interface_theme/rtheme.xml13
-rw-r--r--release/scripts/presets/interface_theme/science_lab.xml13
-rw-r--r--release/scripts/presets/interface_theme/softimage.xml13
-rw-r--r--release/scripts/presets/interface_theme/ubuntu_ambiance.xml11
-rw-r--r--release/scripts/presets/units_length/centimeters.py5
-rw-r--r--release/scripts/presets/units_length/feet.py5
-rw-r--r--release/scripts/presets/units_length/inches.py5
-rw-r--r--release/scripts/presets/units_length/kilometers.py5
-rw-r--r--release/scripts/presets/units_length/meters.py5
-rw-r--r--release/scripts/presets/units_length/miles.py5
-rw-r--r--release/scripts/presets/units_length/millimeters.py5
-rw-r--r--release/scripts/startup/bl_operators/__init__.py9
-rw-r--r--release/scripts/startup/bl_operators/anim.py36
-rw-r--r--release/scripts/startup/bl_operators/bmesh/find_adjacent.py350
-rw-r--r--release/scripts/startup/bl_operators/file.py14
-rw-r--r--release/scripts/startup/bl_operators/mesh.py50
-rw-r--r--release/scripts/startup/bl_operators/node.py32
-rw-r--r--release/scripts/startup/bl_operators/object_align.py7
-rw-r--r--release/scripts/startup/bl_operators/presets.py34
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_smart_project.py28
-rw-r--r--release/scripts/startup/bl_operators/wm.py178
-rw-r--r--release/scripts/startup/bl_ui/__init__.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py14
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py5
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lamp.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py47
-rw-r--r--release/scripts/startup/bl_ui/properties_game.py7
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py306
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py10
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_smoke.py22
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py43
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py27
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py7
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py23
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py7
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py4
-rw-r--r--release/scripts/startup/bl_ui/space_image.py21
-rw-r--r--release/scripts/startup/bl_ui/space_info.py5
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py1
-rw-r--r--release/scripts/startup/bl_ui/space_node.py8
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py93
-rw-r--r--release/scripts/startup/bl_ui/space_time.py8
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py118
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py264
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py103
-rw-r--r--release/scripts/startup/nodeitems_builtins.py3
-rw-r--r--release/scripts/templates_py/background_job.py22
-rw-r--r--release/scripts/templates_py/operator_file_export.py1
-rw-r--r--release/scripts/templates_py/operator_file_import.py1
-rw-r--r--release/scripts/templates_py/operator_mesh_add.py13
-rw-r--r--release/scripts/templates_py/operator_modal_view3d_raycast.py15
-rw-r--r--release/text/ocio-license.txt27
-rw-r--r--release/windows/icons/blender.exe.manifest (renamed from source/icons/blender.exe.manifest)0
-rw-r--r--release/windows/icons/winblender.ico (renamed from source/icons/winblender.ico)bin295606 -> 295606 bytes
-rw-r--r--release/windows/icons/winblender.rc (renamed from source/icons/winblender.rc)0
-rw-r--r--release/windows/icons/winblenderfile.ico (renamed from source/icons/winblenderfile.ico)bin25214 -> 25214 bytes
m---------scons0
-rw-r--r--source/SConscript39
-rw-r--r--source/blender/SConscript77
-rw-r--r--source/blender/avi/SConscript41
-rw-r--r--source/blender/avi/intern/avi.c5
-rw-r--r--source/blender/blenfont/BLF_api.h2
-rw-r--r--source/blender/blenfont/SConscript67
-rw-r--r--source/blender/blenfont/intern/blf.c68
-rw-r--r--source/blender/blenfont/intern/blf_font.c53
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c10
-rw-r--r--source/blender/blenfont/intern/blf_internal.h3
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h2
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c5
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h12
-rw-r--r--source/blender/blenkernel/BKE_armature.h5
-rw-r--r--source/blender/blenkernel/BKE_blender.h24
-rw-r--r--source/blender/blenkernel/BKE_brush.h24
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h13
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h12
-rw-r--r--source/blender/blenkernel/BKE_colortools.h8
-rw-r--r--source/blender/blenkernel/BKE_context.h3
-rw-r--r--source/blender/blenkernel/BKE_curve.h1
-rw-r--r--source/blender/blenkernel/BKE_customdata.h6
-rw-r--r--source/blender/blenkernel/BKE_deform.h41
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h1
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h23
-rw-r--r--source/blender/blenkernel/BKE_font.h14
-rw-r--r--source/blender/blenkernel/BKE_global.h4
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h25
-rw-r--r--source/blender/blenkernel/BKE_group.h2
-rw-r--r--source/blender/blenkernel/BKE_idcode.h18
-rw-r--r--source/blender/blenkernel/BKE_image.h22
-rw-r--r--source/blender/blenkernel/BKE_key.h4
-rw-r--r--source/blender/blenkernel/BKE_lamp.h1
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_library.h56
-rw-r--r--source/blender/blenkernel/BKE_library_query.h27
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h1
-rw-r--r--source/blender/blenkernel/BKE_main.h1
-rw-r--r--source/blender/blenkernel/BKE_material.h5
-rw-r--r--source/blender/blenkernel/BKE_mball.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h12
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h9
-rw-r--r--source/blender/blenkernel/BKE_modifier.h5
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h62
-rw-r--r--source/blender/blenkernel/BKE_object.h9
-rw-r--r--source/blender/blenkernel/BKE_object_deform.h4
-rw-r--r--source/blender/blenkernel/BKE_ocean.h5
-rw-r--r--source/blender/blenkernel/BKE_particle.h16
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h6
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h25
-rw-r--r--source/blender/blenkernel/BKE_report.h2
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h5
-rw-r--r--source/blender/blenkernel/BKE_sca.h10
-rw-r--r--source/blender/blenkernel/BKE_scene.h10
-rw-r--r--source/blender/blenkernel/BKE_screen.h1
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h22
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h1
-rw-r--r--source/blender/blenkernel/BKE_smoke.h2
-rw-r--r--source/blender/blenkernel/BKE_sound.h4
-rw-r--r--source/blender/blenkernel/BKE_speaker.h2
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h6
-rw-r--r--source/blender/blenkernel/BKE_suggestions.h2
-rw-r--r--source/blender/blenkernel/BKE_text.h5
-rw-r--r--source/blender/blenkernel/BKE_tracking.h6
-rw-r--r--source/blender/blenkernel/BKE_world.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt45
-rw-r--r--source/blender/blenkernel/SConscript197
-rw-r--r--source/blender/blenkernel/depsgraph_private.h1
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c5
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h10
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_legacy.c59
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c103
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c448
-rw-r--r--source/blender/blenkernel/intern/action.c5
-rw-r--r--source/blender/blenkernel/intern/addon.c2
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c12
-rw-r--r--source/blender/blenkernel/intern/appdir.c22
-rw-r--r--source/blender/blenkernel/intern/armature.c80
-rw-r--r--source/blender/blenkernel/intern/blender.c217
-rw-r--r--source/blender/blenkernel/intern/boids.c14
-rw-r--r--source/blender/blenkernel/intern/brush.c71
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c117
-rw-r--r--source/blender/blenkernel/intern/camera.c42
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c206
-rw-r--r--source/blender/blenkernel/intern/colortools.c61
-rw-r--r--source/blender/blenkernel/intern/constraint.c34
-rw-r--r--source/blender/blenkernel/intern/context.c10
-rw-r--r--source/blender/blenkernel/intern/curve.c60
-rw-r--r--source/blender/blenkernel/intern/customdata.c108
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c95
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h8
-rw-r--r--source/blender/blenkernel/intern/deform.c188
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c142
-rw-r--r--source/blender/blenkernel/intern/displist.c4
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c135
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c296
-rw-r--r--source/blender/blenkernel/intern/editmesh.c2
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c54
-rw-r--r--source/blender/blenkernel/intern/effect.c21
-rw-r--r--source/blender/blenkernel/intern/fcurve.c219
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c6
-rw-r--r--source/blender/blenkernel/intern/font.c139
-rw-r--r--source/blender/blenkernel/intern/freestyle.c13
-rw-r--r--source/blender/blenkernel/intern/gpencil.c104
-rw-r--r--source/blender/blenkernel/intern/group.c12
-rw-r--r--source/blender/blenkernel/intern/icons.c7
-rw-r--r--source/blender/blenkernel/intern/idcode.c32
-rw-r--r--source/blender/blenkernel/intern/idprop.c5
-rw-r--r--source/blender/blenkernel/intern/image.c438
-rw-r--r--source/blender/blenkernel/intern/ipo.c60
-rw-r--r--source/blender/blenkernel/intern/key.c114
-rw-r--r--source/blender/blenkernel/intern/lamp.c39
-rw-r--r--source/blender/blenkernel/intern/lattice.c30
-rw-r--r--source/blender/blenkernel/intern/library.c471
-rw-r--r--source/blender/blenkernel/intern/library_query.c890
-rw-r--r--source/blender/blenkernel/intern/linestyle.c18
-rw-r--r--source/blender/blenkernel/intern/mask.c16
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c2
-rw-r--r--source/blender/blenkernel/intern/material.c123
-rw-r--r--source/blender/blenkernel/intern/mball.c28
-rw-r--r--source/blender/blenkernel/intern/mesh.c57
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c210
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c45
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c59
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c172
-rw-r--r--source/blender/blenkernel/intern/modifier.c3
-rw-r--r--source/blender/blenkernel/intern/movieclip.c196
-rw-r--r--source/blender/blenkernel/intern/multires.c29
-rw-r--r--source/blender/blenkernel/intern/nla.c83
-rw-r--r--source/blender/blenkernel/intern/node.c46
-rw-r--r--source/blender/blenkernel/intern/object.c291
-rw-r--r--source/blender/blenkernel/intern/object_deform.c25
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c13
-rw-r--r--source/blender/blenkernel/intern/ocean.c470
-rw-r--r--source/blender/blenkernel/intern/packedFile.c8
-rw-r--r--source/blender/blenkernel/intern/paint.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c343
-rw-r--r--source/blender/blenkernel/intern/particle_child.c19
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c89
-rw-r--r--source/blender/blenkernel/intern/particle_system.c300
-rw-r--r--source/blender/blenkernel/intern/pbvh.c611
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c380
-rw-r--r--source/blender/blenkernel/intern/pointcache.c672
-rw-r--r--source/blender/blenkernel/intern/property.c2
-rw-r--r--source/blender/blenkernel/intern/report.c10
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c16
-rw-r--r--source/blender/blenkernel/intern/sca.c176
-rw-r--r--source/blender/blenkernel/intern/scene.c218
-rw-r--r--source/blender/blenkernel/intern/screen.c1
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c486
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c325
-rw-r--r--source/blender/blenkernel/intern/sequencer.c332
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c21
-rw-r--r--source/blender/blenkernel/intern/smoke.c766
-rw-r--r--source/blender/blenkernel/intern/softbody.c232
-rw-r--r--source/blender/blenkernel/intern/sound.c51
-rw-r--r--source/blender/blenkernel/intern/speaker.c30
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c487
-rw-r--r--source/blender/blenkernel/intern/suggestions.c20
-rw-r--r--source/blender/blenkernel/intern/text.c217
-rw-r--r--source/blender/blenkernel/intern/texture.c30
-rw-r--r--source/blender/blenkernel/intern/tracking.c128
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c4
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c13
-rw-r--r--source/blender/blenkernel/intern/unit.c44
-rw-r--r--source/blender/blenkernel/intern/world.c26
-rw-r--r--source/blender/blenkernel/intern/writeavi.c12
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c104
-rw-r--r--source/blender/blenlib/BLI_alloca.h5
-rw-r--r--source/blender/blenlib/BLI_array_utils.h18
-rw-r--r--source/blender/blenlib/BLI_bitmap.h6
-rw-r--r--source/blender/blenlib/BLI_buffer.h55
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h12
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h4
-rw-r--r--source/blender/blenlib/BLI_fileops.h4
-rw-r--r--source/blender/blenlib/BLI_ghash.h45
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h51
-rw-r--r--source/blender/blenlib/BLI_kdtree.h14
-rw-r--r--source/blender/blenlib/BLI_linklist.h6
-rw-r--r--source/blender/blenlib/BLI_linklist_stack.h2
-rw-r--r--source/blender/blenlib/BLI_math_color.h2
-rw-r--r--source/blender/blenlib/BLI_math_geom.h124
-rw-r--r--source/blender/blenlib/BLI_math_inline.h4
-rw-r--r--source/blender/blenlib/BLI_math_interp.h6
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h21
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h27
-rw-r--r--source/blender/blenlib/BLI_math_solvers.h1
-rw-r--r--source/blender/blenlib/BLI_math_vector.h10
-rw-r--r--source/blender/blenlib/BLI_memory_utils.h34
-rw-r--r--source/blender/blenlib/BLI_path_util.h29
-rw-r--r--source/blender/blenlib/BLI_rect.h2
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h9
-rw-r--r--source/blender/blenlib/BLI_string.h6
-rw-r--r--source/blender/blenlib/BLI_sys_types.h20
-rw-r--r--source/blender/blenlib/BLI_task.h16
-rw-r--r--source/blender/blenlib/BLI_threads.h21
-rw-r--r--source/blender/blenlib/BLI_timecode.h2
-rw-r--r--source/blender/blenlib/BLI_utildefines.h29
-rw-r--r--source/blender/blenlib/BLI_voxel.h6
-rw-r--r--source/blender/blenlib/BLI_winstuff.h4
-rw-r--r--source/blender/blenlib/CMakeLists.txt4
-rw-r--r--source/blender/blenlib/PIL_time_utildefines.h35
-rw-r--r--source/blender/blenlib/SConscript56
-rw-r--r--source/blender/blenlib/intern/BLI_args.c2
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c3
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c209
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c498
-rw-r--r--source/blender/blenlib/intern/BLI_kdtree.c319
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c4
-rw-r--r--source/blender/blenlib/intern/array_utils.c28
-rw-r--r--source/blender/blenlib/intern/buffer.c69
-rw-r--r--source/blender/blenlib/intern/dynlib.c3
-rw-r--r--source/blender/blenlib/intern/easing.c2
-rw-r--r--source/blender/blenlib/intern/edgehash.c180
-rw-r--r--source/blender/blenlib/intern/fileops.c15
-rw-r--r--source/blender/blenlib/intern/lasso.c11
-rw-r--r--source/blender/blenlib/intern/math_color.c149
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c50
-rw-r--r--source/blender/blenlib/intern/math_geom.c800
-rw-r--r--source/blender/blenlib/intern/math_geom_inline.c11
-rw-r--r--source/blender/blenlib/intern/math_interp.c37
-rw-r--r--source/blender/blenlib/intern/math_matrix.c190
-rw-r--r--source/blender/blenlib/intern/math_rotation.c235
-rw-r--r--source/blender/blenlib/intern/math_solvers.c17
-rw-r--r--source/blender/blenlib/intern/math_statistics.c87
-rw-r--r--source/blender/blenlib/intern/math_vector.c15
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c31
-rw-r--r--source/blender/blenlib/intern/memory_utils.c50
-rw-r--r--source/blender/blenlib/intern/noise.c6
-rw-r--r--source/blender/blenlib/intern/path_util.c144
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c28
-rw-r--r--source/blender/blenlib/intern/rct.c99
-rw-r--r--source/blender/blenlib/intern/scanfill.c13
-rw-r--r--source/blender/blenlib/intern/smallhash.c17
-rw-r--r--source/blender/blenlib/intern/sort.c17
-rw-r--r--source/blender/blenlib/intern/storage.c86
-rw-r--r--source/blender/blenlib/intern/string.c81
-rw-r--r--source/blender/blenlib/intern/task.c245
-rw-r--r--source/blender/blenlib/intern/time.c3
-rw-r--r--source/blender/blenlib/intern/timecode.c20
-rw-r--r--source/blender/blenlib/intern/voxel.c82
-rw-r--r--source/blender/blenlib/intern/winstuff.c8
-rw-r--r--source/blender/blenloader/BLO_readfile.h201
-rw-r--r--source/blender/blenloader/BLO_writefile.h6
-rw-r--r--source/blender/blenloader/SConscript64
-rw-r--r--source/blender/blenloader/intern/readblenentry.c129
-rw-r--r--source/blender/blenloader/intern/readfile.c1120
-rw-r--r--source/blender/blenloader/intern/readfile.h23
-rw-r--r--source/blender/blenloader/intern/versioning_260.c29
-rw-r--r--source/blender/blenloader/intern/versioning_270.c288
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c145
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c17
-rw-r--r--source/blender/blenloader/intern/writefile.c72
-rw-r--r--source/blender/blentranslation/BLT_translation.h7
-rw-r--r--source/blender/blentranslation/SConscript46
-rw-r--r--source/blender/bmesh/CMakeLists.txt14
-rw-r--r--source/blender/bmesh/SConscript59
-rw-r--r--source/blender/bmesh/bmesh.h1
-rw-r--r--source/blender/bmesh/bmesh_class.h16
-rw-r--r--source/blender/bmesh/bmesh_tools.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c25
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c548
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c57
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c213
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c1
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c54
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c38
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h22
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c1
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c644
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h13
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c62
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api_inline.h20
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c15
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c460
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h34
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.c1543
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon_edgenet.h41
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c109
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h16
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c5
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c22
-rw-r--r--source/blender/bmesh/operators/bmo_connect_concave.c3
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c2
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c157
-rw-r--r--source/blender/bmesh/operators/bmo_create.c1
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c2
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c3
-rw-r--r--source/blender/bmesh/operators/bmo_edgenet.c4
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c8
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c4
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c123
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c19
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c163
-rw-r--r--source/blender/bmesh/operators/bmo_offset_edgeloops.c2
-rw-r--r--source/blender/bmesh/operators/bmo_poke.c26
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c493
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c182
-rw-r--r--source/blender/bmesh/operators/bmo_smooth_laplacian.c97
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c153
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c7
-rw-r--r--source/blender/bmesh/operators/bmo_symmetrize.c3
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c6
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c12
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate.h3
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c354
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c168
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c434
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h11
-rw-r--r--source/blender/bmesh/tools/bmesh_path.c336
-rw-r--r--source/blender/bmesh/tools/bmesh_path.h13
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region.c477
-rw-r--r--source/blender/bmesh/tools/bmesh_path_region.h43
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.c31
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.h2
-rw-r--r--source/blender/collada/AnimationExporter.cpp2
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp10
-rw-r--r--source/blender/collada/DocumentExporter.cpp70
-rw-r--r--source/blender/collada/DocumentExporter.h2
-rw-r--r--source/blender/collada/DocumentImporter.cpp6
-rw-r--r--source/blender/collada/MeshImporter.cpp2
-rw-r--r--source/blender/collada/SConscript63
-rw-r--r--source/blender/collada/SceneExporter.cpp2
-rw-r--r--source/blender/collada/collada.cpp4
-rw-r--r--source/blender/collada/collada_utils.cpp10
-rw-r--r--source/blender/compositor/CMakeLists.txt11
-rw-r--r--source/blender/compositor/SConscript74
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.cpp6
-rw-r--r--source/blender/compositor/intern/COM_CPUDevice.h7
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h1
-rw-r--r--source/blender/compositor/intern/COM_ExecutionGroup.cpp4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cpp10
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cpp3
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h10
-rw-r--r--source/blender/compositor/intern/COM_Node.h1
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp22
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.h4
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp22
-rw-r--r--source/blender/compositor/nodes/COM_BlurNode.cpp18
-rw-r--r--source/blender/compositor/nodes/COM_BokehBlurNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_Stabilize2dNode.cpp22
-rw-r--r--source/blender/compositor/nodes/COM_TrackPositionNode.cpp49
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cpp136
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h7
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_BoxMaskOperation.cpp3
-rw-r--r--source/blender/compositor/operations/COM_ChannelMatteOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ChromaMatteOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ColorMatteOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ColorRampOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ConvolutionFilterOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.cpp15
-rw-r--r--source/blender/compositor/operations/COM_CurveBaseOperation.h1
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.h6
-rw-r--r--source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_EllipseMaskOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp31
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cpp20
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_GlareThresholdOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.cpp27
-rw-r--r--source/blender/compositor/operations/COM_IDMaskOperation.h25
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_MovieClipAttributeOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cpp114
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.h158
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp27
-rw-r--r--source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp7
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp43
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.cpp21
-rw-r--r--source/blender/compositor/operations/COM_TrackPositionOperation.h2
-rw-r--r--source/blender/datatoc/CMakeLists.txt3
-rw-r--r--source/blender/depsgraph/CMakeLists.txt1
-rw-r--r--source/blender/depsgraph/SConscript77
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc8
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_nodes.cc44
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_relations.cc94
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc7
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc35
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.cc3
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.h8
-rw-r--r--source/blender/editors/SConscript68
-rw-r--r--source/blender/editors/animation/CMakeLists.txt4
-rw-r--r--source/blender/editors/animation/SConscript52
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c38
-rw-r--r--source/blender/editors/animation/anim_deps.c55
-rw-r--r--source/blender/editors/animation/anim_draw.c54
-rw-r--r--source/blender/editors/animation/anim_filter.c191
-rw-r--r--source/blender/editors/animation/drivers.c469
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/animation/keyframes_edit.c79
-rw-r--r--source/blender/editors/animation/keyframes_general.c39
-rw-r--r--source/blender/editors/animation/keyframing.c101
-rw-r--r--source/blender/editors/animation/keyingsets.c9
-rw-r--r--source/blender/editors/armature/CMakeLists.txt8
-rw-r--r--source/blender/editors/armature/SConscript57
-rw-r--r--source/blender/editors/armature/armature_add.c67
-rw-r--r--source/blender/editors/armature/armature_edit.c54
-rw-r--r--source/blender/editors/armature/armature_intern.h2
-rw-r--r--source/blender/editors/armature/armature_ops.c2
-rw-r--r--source/blender/editors/armature/armature_select.c74
-rw-r--r--source/blender/editors/armature/armature_skinning.c14
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c4
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c17
-rw-r--r--source/blender/editors/armature/meshlaplacian.c477
-rw-r--r--source/blender/editors/armature/meshlaplacian.h2
-rw-r--r--source/blender/editors/armature/pose_edit.c59
-rw-r--r--source/blender/editors/armature/pose_slide.c31
-rw-r--r--source/blender/editors/armature/reeb.c54
-rw-r--r--source/blender/editors/curve/CMakeLists.txt8
-rw-r--r--source/blender/editors/curve/SConscript49
-rw-r--r--source/blender/editors/curve/curve_intern.h6
-rw-r--r--source/blender/editors/curve/curve_ops.c6
-rw-r--r--source/blender/editors/curve/editcurve.c219
-rw-r--r--source/blender/editors/curve/editcurve_add.c15
-rw-r--r--source/blender/editors/curve/editcurve_paint.c1180
-rw-r--r--source/blender/editors/curve/editcurve_select.c44
-rw-r--r--source/blender/editors/curve/editfont.c226
-rw-r--r--source/blender/editors/datafiles/SConscript113
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt1
-rw-r--r--source/blender/editors/gpencil/SConscript57
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c44
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c259
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c1688
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c17
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c220
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c550
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h71
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c98
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c533
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c115
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c272
-rw-r--r--source/blender/editors/include/BIF_gl.h9
-rw-r--r--source/blender/editors/include/BIF_glutil.h15
-rw-r--r--source/blender/editors/include/ED_anim_api.h4
-rw-r--r--source/blender/editors/include/ED_armature.h4
-rw-r--r--source/blender/editors/include/ED_curve.h19
-rw-r--r--source/blender/editors/include/ED_gpencil.h16
-rw-r--r--source/blender/editors/include/ED_image.h1
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h59
-rw-r--r--source/blender/editors/include/ED_keyframing.h65
-rw-r--r--source/blender/editors/include/ED_lattice.h6
-rw-r--r--source/blender/editors/include/ED_mball.h10
-rw-r--r--source/blender/editors/include/ED_mesh.h20
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/include/ED_object.h7
-rw-r--r--source/blender/editors/include/ED_screen.h7
-rw-r--r--source/blender/editors/include/ED_transform.h64
-rw-r--r--source/blender/editors/include/ED_util.h3
-rw-r--r--source/blender/editors/include/ED_view3d.h39
-rw-r--r--source/blender/editors/include/UI_icons.h7
-rw-r--r--source/blender/editors/include/UI_interface.h47
-rw-r--r--source/blender/editors/include/UI_resources.h6
-rw-r--r--source/blender/editors/include/UI_view2d.h2
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/SConscript63
-rw-r--r--source/blender/editors/interface/interface.c421
-rw-r--r--source/blender/editors/interface/interface_align.c651
-rw-r--r--source/blender/editors/interface/interface_anim.c33
-rw-r--r--source/blender/editors/interface/interface_draw.c546
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c442
-rw-r--r--source/blender/editors/interface/interface_handlers.c876
-rw-r--r--source/blender/editors/interface/interface_icons.c85
-rw-r--r--source/blender/editors/interface/interface_intern.h47
-rw-r--r--source/blender/editors/interface/interface_layout.c217
-rw-r--r--source/blender/editors/interface/interface_ops.c71
-rw-r--r--source/blender/editors/interface/interface_panel.c8
-rw-r--r--source/blender/editors/interface/interface_regions.c364
-rw-r--r--source/blender/editors/interface/interface_style.c17
-rw-r--r--source/blender/editors/interface/interface_templates.c284
-rw-r--r--source/blender/editors/interface/interface_widgets.c121
-rw-r--r--source/blender/editors/interface/resources.c80
-rw-r--r--source/blender/editors/interface/view2d.c89
-rw-r--r--source/blender/editors/interface/view2d_ops.c13
-rw-r--r--source/blender/editors/io/SConscript51
-rw-r--r--source/blender/editors/io/io_collada.c14
-rw-r--r--source/blender/editors/mask/SConscript51
-rw-r--r--source/blender/editors/mask/mask_draw.c6
-rw-r--r--source/blender/editors/mask/mask_edit.c4
-rw-r--r--source/blender/editors/mask/mask_ops.c8
-rw-r--r--source/blender/editors/mesh/SConscript72
-rw-r--r--source/blender/editors/mesh/editface.c56
-rw-r--r--source/blender/editors/mesh/editmesh_add.c108
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c17
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c4
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c2
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c6
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c594
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c976
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c6
-rw-r--r--source/blender/editors/mesh/editmesh_path.c632
-rw-r--r--source/blender/editors/mesh/editmesh_select.c270
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c69
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c83
-rw-r--r--source/blender/editors/mesh/mesh_intern.h8
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c48
-rw-r--r--source/blender/editors/mesh/mesh_ops.c13
-rw-r--r--source/blender/editors/mesh/meshtools.c100
-rw-r--r--source/blender/editors/metaball/SConscript45
-rw-r--r--source/blender/editors/metaball/mball_edit.c93
-rw-r--r--source/blender/editors/object/SConscript66
-rw-r--r--source/blender/editors/object/object_add.c169
-rw-r--r--source/blender/editors/object/object_bake.c10
-rw-r--r--source/blender/editors/object/object_bake_api.c182
-rw-r--r--source/blender/editors/object/object_constraint.c8
-rw-r--r--source/blender/editors/object/object_data_transfer.c66
-rw-r--r--source/blender/editors/object/object_edit.c171
-rw-r--r--source/blender/editors/object/object_group.c3
-rw-r--r--source/blender/editors/object/object_hook.c6
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_lattice.c62
-rw-r--r--source/blender/editors/object/object_modifier.c39
-rw-r--r--source/blender/editors/object/object_ops.c14
-rw-r--r--source/blender/editors/object/object_relations.c92
-rw-r--r--source/blender/editors/object/object_select.c161
-rw-r--r--source/blender/editors/object/object_shapekey.c6
-rw-r--r--source/blender/editors/object/object_transform.c81
-rw-r--r--source/blender/editors/object/object_vgroup.c158
-rw-r--r--source/blender/editors/physics/SConscript58
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c184
-rw-r--r--source/blender/editors/physics/particle_boids.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c152
-rw-r--r--source/blender/editors/physics/particle_object.c37
-rw-r--r--source/blender/editors/physics/physics_pointcache.c270
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c2
-rw-r--r--source/blender/editors/physics/rigidbody_object.c6
-rw-r--r--source/blender/editors/physics/rigidbody_world.c4
-rw-r--r--source/blender/editors/render/SConscript70
-rw-r--r--source/blender/editors/render/render_intern.h3
-rw-r--r--source/blender/editors/render/render_internal.c66
-rw-r--r--source/blender/editors/render/render_opengl.c254
-rw-r--r--source/blender/editors/render/render_ops.c1
-rw-r--r--source/blender/editors/render/render_preview.c8
-rw-r--r--source/blender/editors/render/render_shading.c23
-rw-r--r--source/blender/editors/render/render_view.c28
-rw-r--r--source/blender/editors/screen/SConscript59
-rw-r--r--source/blender/editors/screen/area.c142
-rw-r--r--source/blender/editors/screen/glutil.c326
-rw-r--r--source/blender/editors/screen/screen_context.c23
-rw-r--r--source/blender/editors/screen/screen_edit.c173
-rw-r--r--source/blender/editors/screen/screen_ops.c53
-rw-r--r--source/blender/editors/screen/screendump.c28
-rw-r--r--source/blender/editors/sculpt_paint/SConscript64
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c344
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c65
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h5
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c196
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c53
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c41
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c1087
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2534
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c164
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c21
-rw-r--r--source/blender/editors/sound/SConscript56
-rw-r--r--source/blender/editors/sound/sound_ops.c25
-rw-r--r--source/blender/editors/space_action/SConscript50
-rw-r--r--source/blender/editors/space_action/action_data.c7
-rw-r--r--source/blender/editors/space_action/action_edit.c141
-rw-r--r--source/blender/editors/space_action/action_select.c3
-rw-r--r--source/blender/editors/space_action/space_action.c51
-rw-r--r--source/blender/editors/space_api/SConscript47
-rw-r--r--source/blender/editors/space_api/spacetypes.c7
-rw-r--r--source/blender/editors/space_buttons/SConscript59
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c31
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c27
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c24
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt8
-rw-r--r--source/blender/editors/space_clip/SConscript58
-rw-r--r--source/blender/editors/space_clip/clip_draw.c114
-rw-r--r--source/blender/editors/space_clip/clip_editor.c2
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c3
-rw-r--r--source/blender/editors/space_clip/clip_ops.c16
-rw-r--r--source/blender/editors/space_clip/clip_utils.c17
-rw-r--r--source/blender/editors/space_clip/space_clip.c94
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c3306
-rw-r--r--source/blender/editors/space_clip/tracking_ops_detect.c164
-rw-r--r--source/blender/editors/space_clip/tracking_ops_intern.h53
-rw-r--r--source/blender/editors/space_clip/tracking_ops_orient.c860
-rw-r--r--source/blender/editors/space_clip/tracking_ops_plane.c431
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c351
-rw-r--r--source/blender/editors/space_clip/tracking_ops_stabilize.c242
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c492
-rw-r--r--source/blender/editors/space_clip/tracking_ops_utils.c79
-rw-r--r--source/blender/editors/space_clip/tracking_select.c15
-rw-r--r--source/blender/editors/space_console/SConscript52
-rw-r--r--source/blender/editors/space_console/console_draw.c15
-rw-r--r--source/blender/editors/space_console/console_intern.h2
-rw-r--r--source/blender/editors/space_console/console_ops.c2
-rw-r--r--source/blender/editors/space_console/space_console.c40
-rw-r--r--source/blender/editors/space_file/SConscript75
-rw-r--r--source/blender/editors/space_file/file_draw.c12
-rw-r--r--source/blender/editors/space_file/file_intern.h5
-rw-r--r--source/blender/editors/space_file/file_ops.c146
-rw-r--r--source/blender/editors/space_file/filelist.c158
-rw-r--r--source/blender/editors/space_file/filesel.c9
-rw-r--r--source/blender/editors/space_file/fsmenu.c53
-rw-r--r--source/blender/editors/space_file/space_file.c118
-rw-r--r--source/blender/editors/space_graph/SConscript57
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c171
-rw-r--r--source/blender/editors/space_graph/graph_draw.c45
-rw-r--r--source/blender/editors/space_graph/graph_edit.c450
-rw-r--r--source/blender/editors/space_graph/graph_intern.h5
-rw-r--r--source/blender/editors/space_graph/graph_ops.c69
-rw-r--r--source/blender/editors/space_graph/space_graph.c90
-rw-r--r--source/blender/editors/space_image/SConscript71
-rw-r--r--source/blender/editors/space_image/image_buttons.c278
-rw-r--r--source/blender/editors/space_image/image_draw.c59
-rw-r--r--source/blender/editors/space_image/image_edit.c42
-rw-r--r--source/blender/editors/space_image/image_intern.h2
-rw-r--r--source/blender/editors/space_image/image_ops.c104
-rw-r--r--source/blender/editors/space_image/space_image.c54
-rw-r--r--source/blender/editors/space_info/SConscript57
-rw-r--r--source/blender/editors/space_info/info_ops.c7
-rw-r--r--source/blender/editors/space_info/space_info.c24
-rw-r--r--source/blender/editors/space_info/textview.c27
-rw-r--r--source/blender/editors/space_logic/SConscript58
-rw-r--r--source/blender/editors/space_logic/logic_buttons.c2
-rw-r--r--source/blender/editors/space_logic/logic_ops.c2
-rw-r--r--source/blender/editors/space_logic/logic_window.c12
-rw-r--r--source/blender/editors/space_logic/space_logic.c28
-rw-r--r--source/blender/editors/space_nla/SConscript53
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c6
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_nla/nla_edit.c92
-rw-r--r--source/blender/editors/space_nla/nla_intern.h1
-rw-r--r--source/blender/editors/space_nla/nla_ops.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c46
-rw-r--r--source/blender/editors/space_node/SConscript73
-rw-r--r--source/blender/editors/space_node/drawnode.c79
-rw-r--r--source/blender/editors/space_node/node_add.c11
-rw-r--r--source/blender/editors/space_node/node_draw.c35
-rw-r--r--source/blender/editors/space_node/node_edit.c60
-rw-r--r--source/blender/editors/space_node/node_group.c3
-rw-r--r--source/blender/editors/space_node/node_intern.h4
-rw-r--r--source/blender/editors/space_node/node_ops.c2
-rw-r--r--source/blender/editors/space_node/node_relationships.c267
-rw-r--r--source/blender/editors/space_node/node_select.c12
-rw-r--r--source/blender/editors/space_node/node_templates.c10
-rw-r--r--source/blender/editors/space_node/space_node.c40
-rw-r--r--source/blender/editors/space_outliner/SConscript53
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c30
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c117
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h34
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c9
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c248
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c60
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c36
-rw-r--r--source/blender/editors/space_script/SConscript53
-rw-r--r--source/blender/editors/space_script/script_edit.c4
-rw-r--r--source/blender/editors/space_script/space_script.c24
-rw-r--r--source/blender/editors/space_sequencer/SConscript60
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c49
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c143
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c147
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c42
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c5
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c56
-rw-r--r--source/blender/editors/space_text/SConscript58
-rw-r--r--source/blender/editors/space_text/space_text.c38
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c78
-rw-r--r--source/blender/editors/space_text/text_draw.c179
-rw-r--r--source/blender/editors/space_text/text_format.c2
-rw-r--r--source/blender/editors/space_text/text_format.h2
-rw-r--r--source/blender/editors/space_text/text_intern.h12
-rw-r--r--source/blender/editors/space_text/text_ops.c294
-rw-r--r--source/blender/editors/space_time/SConscript48
-rw-r--r--source/blender/editors/space_time/space_time.c43
-rw-r--r--source/blender/editors/space_time/time_ops.c28
-rw-r--r--source/blender/editors/space_userpref/SConscript47
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c24
-rw-r--r--source/blender/editors/space_view3d/SConscript74
-rw-r--r--source/blender/editors/space_view3d/drawanimviz.c3
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c103
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c318
-rw-r--r--source/blender/editors/space_view3d/drawobject.c1546
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c2
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c597
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c82
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c435
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c348
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c9
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h32
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c36
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c108
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c63
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c125
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c38
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/SConscript58
-rw-r--r--source/blender/editors/transform/transform.c699
-rw-r--r--source/blender/editors/transform/transform.h70
-rw-r--r--source/blender/editors/transform/transform_constraints.c80
-rw-r--r--source/blender/editors/transform/transform_conversions.c410
-rw-r--r--source/blender/editors/transform/transform_generics.c96
-rw-r--r--source/blender/editors/transform/transform_input.c225
-rw-r--r--source/blender/editors/transform/transform_manipulator.c94
-rw-r--r--source/blender/editors/transform/transform_ops.c29
-rw-r--r--source/blender/editors/transform/transform_orientations.c14
-rw-r--r--source/blender/editors/transform/transform_snap.c619
-rw-r--r--source/blender/editors/util/SConscript57
-rw-r--r--source/blender/editors/util/ed_util.c26
-rw-r--r--source/blender/editors/util/numinput.c8
-rw-r--r--source/blender/editors/util/undo.c9
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt8
-rw-r--r--source/blender/editors/uvedit/SConscript54
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c72
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c16
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c205
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c114
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c80
-rw-r--r--source/blender/freestyle/CMakeLists.txt5
-rw-r--r--source/blender/freestyle/FRS_freestyle.h16
-rw-r--r--source/blender/freestyle/SConscript91
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp6
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp18
-rw-r--r--source/blender/freestyle/intern/application/Controller.h2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp9
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h4
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp52
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp50
-rw-r--r--source/blender/freestyle/intern/geometry/GridHelpers.cpp8
-rw-r--r--source/blender/freestyle/intern/geometry/Noise.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp5
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp39
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.cpp6
-rw-r--r--source/blender/freestyle/intern/stroke/ChainingIterators.cpp2
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp2
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp7
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h14
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.cpp15
-rw-r--r--source/blender/gpu/CMakeLists.txt37
-rw-r--r--source/blender/gpu/GPU_basic_shader.h118
-rw-r--r--source/blender/gpu/GPU_buffers.h6
-rw-r--r--source/blender/gpu/GPU_compositing.h9
-rw-r--r--source/blender/gpu/GPU_draw.h18
-rw-r--r--source/blender/gpu/GPU_extensions.h214
-rw-r--r--source/blender/gpu/GPU_framebuffer.h86
-rw-r--r--source/blender/gpu/GPU_material.h41
-rw-r--r--source/blender/gpu/GPU_select.h13
-rw-r--r--source/blender/gpu/GPU_shader.h119
-rw-r--r--source/blender/gpu/GPU_simple_shader.h89
-rw-r--r--source/blender/gpu/GPU_texture.h105
-rw-r--r--source/blender/gpu/SConscript93
-rw-r--r--source/blender/gpu/intern/gpu_basic_shader.c645
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c533
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c154
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h7
-rw-r--r--source/blender/gpu/intern/gpu_compositing.c503
-rw-r--r--source/blender/gpu/intern/gpu_debug.c54
-rw-r--r--source/blender/gpu/intern/gpu_draw.c831
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c2215
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.c639
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c2
-rw-r--r--source/blender/gpu/intern/gpu_material.c1061
-rw-r--r--source/blender/gpu/intern/gpu_select.c48
-rw-r--r--source/blender/gpu/intern/gpu_shader.c737
-rw-r--r--source/blender/gpu/intern/gpu_simple_shader.c281
-rw-r--r--source/blender/gpu/intern/gpu_texture.c769
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl32
-rw-r--r--source/blender/gpu/shaders/gpu_program_smoke_frag.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_frag.glsl273
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_geom.glsl100
-rw-r--r--source/blender/gpu/shaders/gpu_shader_basic_vert.glsl62
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl38
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl138
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_frag.glsl169
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_vert.glsl54
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl48
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl12
-rw-r--r--source/blender/ikplugin/SConscript49
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c7
-rw-r--r--source/blender/imbuf/CMakeLists.txt15
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h8
-rw-r--r--source/blender/imbuf/IMB_imbuf.h1
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h57
-rw-r--r--source/blender/imbuf/IMB_thumbs.h2
-rw-r--r--source/blender/imbuf/SConscript100
-rw-r--r--source/blender/imbuf/intern/IMB_allocimbuf.h12
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h21
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h4
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c36
-rw-r--r--source/blender/imbuf/intern/anim_movie.c206
-rw-r--r--source/blender/imbuf/intern/cineon/SConscript46
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.h6
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.h6
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c32
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c65
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp18
-rw-r--r--source/blender/imbuf/intern/dds/Common.h12
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp40
-rw-r--r--source/blender/imbuf/intern/dds/FlipDXT.cpp4
-rw-r--r--source/blender/imbuf/intern/dds/Image.cpp8
-rw-r--r--source/blender/imbuf/intern/dds/SConscript47
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp4
-rw-r--r--source/blender/imbuf/intern/filter.c137
-rw-r--r--source/blender/imbuf/intern/imageprocess.c2
-rw-r--r--source/blender/imbuf/intern/indexer.c15
-rw-r--r--source/blender/imbuf/intern/indexer_dv.c405
-rw-r--r--source/blender/imbuf/intern/jp2.c6
-rw-r--r--source/blender/imbuf/intern/jpeg.c184
-rw-r--r--source/blender/imbuf/intern/module.c2
-rw-r--r--source/blender/imbuf/intern/oiio/SConscript49
-rw-r--r--source/blender/imbuf/intern/oiio/openimageio_api.cpp12
-rw-r--r--source/blender/imbuf/intern/openexr/SConscript49
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp80
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h6
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp6
-rw-r--r--source/blender/imbuf/intern/png.c1
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c39
-rw-r--r--source/blender/imbuf/intern/readimage.c11
-rw-r--r--source/blender/imbuf/intern/scaling.c92
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c20
-rw-r--r--source/blender/imbuf/intern/targa.c28
-rw-r--r--source/blender/imbuf/intern/thumbs.c17
-rw-r--r--source/blender/imbuf/intern/tiff.c10
-rw-r--r--source/blender/imbuf/intern/util.c16
-rw-r--r--source/blender/imbuf/intern/writeimage.c3
-rw-r--r--source/blender/imbuf/readme.txt4
-rw-r--r--source/blender/makesdna/DNA_ID.h90
-rw-r--r--source/blender/makesdna/DNA_action_types.h21
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h14
-rw-r--r--source/blender/makesdna/DNA_anim_types.h66
-rw-r--r--source/blender/makesdna/DNA_brush_types.h6
-rw-r--r--source/blender/makesdna/DNA_camera_types.h8
-rw-r--r--source/blender/makesdna/DNA_curve_types.h3
-rw-r--r--source/blender/makesdna/DNA_genfile.h26
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h16
-rw-r--r--source/blender/makesdna/DNA_image_types.h17
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h3
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h12
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h31
-rw-r--r--source/blender/makesdna/DNA_node_types.h27
-rw-r--r--source/blender/makesdna/DNA_object_fluidsim.h5
-rw-r--r--source/blender/makesdna/DNA_object_force.h4
-rw-r--r--source/blender/makesdna/DNA_object_types.h5
-rw-r--r--source/blender/makesdna/DNA_particle_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h205
-rw-r--r--source/blender/makesdna/DNA_screen_types.h7
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h2
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h37
-rw-r--r--source/blender/makesdna/DNA_smoke_types.h14
-rw-r--r--source/blender/makesdna/DNA_space_types.h28
-rw-r--r--source/blender/makesdna/DNA_texture_types.h31
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h28
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h19
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h4
-rw-r--r--source/blender/makesdna/DNA_world_types.h2
-rw-r--r--source/blender/makesdna/SConscript45
-rw-r--r--source/blender/makesdna/intern/SConscript94
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c68
-rw-r--r--source/blender/makesdna/intern/makesdna.c130
-rw-r--r--source/blender/makesrna/RNA_access.h16
-rw-r--r--source/blender/makesrna/RNA_define.h2
-rw-r--r--source/blender/makesrna/RNA_enum_types.h236
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/SConscript162
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt8
-rw-r--r--source/blender/makesrna/intern/SConscript244
-rw-r--r--source/blender/makesrna/intern/makesrna.c26
-rw-r--r--source/blender/makesrna/intern/rna_ID.c52
-rw-r--r--source/blender/makesrna/intern/rna_access.c130
-rw-r--r--source/blender/makesrna/intern/rna_action.c23
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c5
-rw-r--r--source/blender/makesrna/intern/rna_animation.c52
-rw-r--r--source/blender/makesrna/intern/rna_animviz.c6
-rw-r--r--source/blender/makesrna/intern/rna_armature.c6
-rw-r--r--source/blender/makesrna/intern/rna_boid.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c45
-rw-r--r--source/blender/makesrna/intern/rna_camera.c13
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c2
-rw-r--r--source/blender/makesrna/intern/rna_color.c9
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c47
-rw-r--r--source/blender/makesrna/intern/rna_controller.c6
-rw-r--r--source/blender/makesrna/intern/rna_curve.c16
-rw-r--r--source/blender/makesrna/intern/rna_define.c16
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c2
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c65
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c8
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c115
-rw-r--r--source/blender/makesrna/intern/rna_group.c2
-rw-r--r--source/blender/makesrna/intern/rna_image.c40
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c44
-rw-r--r--source/blender/makesrna/intern/rna_internal.h2
-rw-r--r--source/blender/makesrna/intern/rna_key.c147
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c32
-rw-r--r--source/blender/makesrna/intern/rna_lattice.c10
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c40
-rw-r--r--source/blender/makesrna/intern/rna_main.c7
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c302
-rw-r--r--source/blender/makesrna/intern/rna_mask.c4
-rw-r--r--source/blender/makesrna/intern/rna_material.c28
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c37
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c21
-rw-r--r--source/blender/makesrna/intern/rna_meta.c8
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c283
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c4
-rw-r--r--source/blender/makesrna/intern/rna_nla.c12
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c371
-rw-r--r--source/blender/makesrna/intern/rna_object.c84
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c84
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c24
-rw-r--r--source/blender/makesrna/intern/rna_packedfile.c2
-rw-r--r--source/blender/makesrna/intern/rna_particle.c54
-rw-r--r--source/blender/makesrna/intern/rna_pose.c23
-rw-r--r--source/blender/makesrna/intern/rna_property.c4
-rw-r--r--source/blender/makesrna/intern/rna_render.c50
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c14
-rw-r--r--source/blender/makesrna/intern/rna_rna.c43
-rw-r--r--source/blender/makesrna/intern/rna_scene.c480
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c47
-rw-r--r--source/blender/makesrna/intern/rna_screen.c12
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c116
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c20
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c159
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c102
-rw-r--r--source/blender/makesrna/intern/rna_sound.c4
-rw-r--r--source/blender/makesrna/intern/rna_sound_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c213
-rw-r--r--source/blender/makesrna/intern/rna_speaker.c4
-rw-r--r--source/blender/makesrna/intern/rna_text.c4
-rw-r--r--source/blender/makesrna/intern/rna_text_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_texture.c62
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c145
-rw-r--r--source/blender/makesrna/intern/rna_ui.c14
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c10
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c191
-rw-r--r--source/blender/makesrna/intern/rna_vfont.c4
-rw-r--r--source/blender/makesrna/intern/rna_vfont_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_wm.c52
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c46
-rw-r--r--source/blender/makesrna/intern/rna_world.c6
-rw-r--r--source/blender/modifiers/CMakeLists.txt8
-rw-r--r--source/blender/modifiers/SConscript88
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c6
-rw-r--r--source/blender/modifiers/intern/MOD_array.c93
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c282
-rw-r--r--source/blender/modifiers/intern/MOD_build.c12
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c6
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c5
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c10
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c16
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c7
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c5
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c11
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c8
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c13
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c159
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c85
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c6
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c6
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c12
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c9
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c59
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c305
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c5
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c72
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c6
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c5
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c13
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c12
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c38
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c33
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c5
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c4
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_util.c21
-rw-r--r--source/blender/modifiers/intern/MOD_util.h17
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c8
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c87
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c13
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c7
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c9
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c9
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c133
-rw-r--r--source/blender/nodes/SConscript85
-rw-r--r--source/blender/nodes/composite/node_composite_util.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.c1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.c11
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.c1
-rw-r--r--source/blender/nodes/intern/node_util.c98
-rw-r--r--source/blender/nodes/intern/node_util.h3
-rw-r--r--source/blender/nodes/shader/node_shader_util.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.c5
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.c8
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c13
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectTransform.c152
-rw-r--r--source/blender/nodes/texture/node_texture_util.c1
-rw-r--r--source/blender/nodes/texture/node_texture_util.h1
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c1
-rw-r--r--source/blender/physics/CMakeLists.txt3
-rw-r--r--source/blender/physics/SConscript44
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp2234
-rw-r--r--source/blender/physics/intern/ConstrainedConjugateGradient.h6
-rw-r--r--source/blender/physics/intern/implicit_blender.c91
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp3
-rw-r--r--source/blender/python/BPY_extern.h14
-rw-r--r--source/blender/python/SConscript210
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c11
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c28
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c7
-rw-r--r--source/blender/python/generic/bgl.c2
-rw-r--r--source/blender/python/generic/bpy_threads.c5
-rw-r--r--source/blender/python/generic/py_capi_utils.c74
-rw-r--r--source/blender/python/generic/py_capi_utils.h2
-rw-r--r--source/blender/python/intern/CMakeLists.txt21
-rw-r--r--source/blender/python/intern/bpy.c9
-rw-r--r--source/blender/python/intern/bpy_app.c13
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c14
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.c117
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.h38
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c11
-rw-r--r--source/blender/python/intern/bpy_app_translations.c19
-rw-r--r--source/blender/python/intern/bpy_driver.c31
-rw-r--r--source/blender/python/intern/bpy_interface.c73
-rw-r--r--source/blender/python/intern/bpy_library.c482
-rw-r--r--source/blender/python/intern/bpy_library.h3
-rw-r--r--source/blender/python/intern/bpy_library_load.c481
-rw-r--r--source/blender/python/intern/bpy_library_write.c215
-rw-r--r--source/blender/python/intern/bpy_operator.c10
-rw-r--r--source/blender/python/intern/bpy_props.c12
-rw-r--r--source/blender/python/intern/bpy_rna.c373
-rw-r--r--source/blender/python/intern/bpy_rna.h5
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c20
-rw-r--r--source/blender/python/intern/bpy_rna_array.c170
-rw-r--r--source/blender/python/intern/bpy_rna_callback.c10
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c79
-rw-r--r--source/blender/python/intern/bpy_rna_driver.h33
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c272
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.h32
-rw-r--r--source/blender/python/intern/bpy_util.h4
-rw-r--r--source/blender/python/intern/bpy_utils_units.c2
-rw-r--r--source/blender/python/intern/gpu.c28
-rw-r--r--source/blender/python/intern/gpu.h2
-rw-r--r--source/blender/python/intern/gpu_offscreen.c432
-rw-r--r--source/blender/python/intern/stubs.c13
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c20
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c8
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c86
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c106
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c6
-rw-r--r--source/blender/python/mathutils/mathutils_interpolate.c11
-rw-r--r--source/blender/python/mathutils/mathutils_kdtree.c82
-rw-r--r--source/blender/python/mathutils/mathutils_noise.c19
-rw-r--r--source/blender/quicktime/SConscript63
-rw-r--r--source/blender/quicktime/apple/qtkit_export.m4
-rw-r--r--source/blender/quicktime/quicktime_export.h5
-rw-r--r--source/blender/render/SConscript125
-rw-r--r--source/blender/render/extern/include/RE_bake.h2
-rw-r--r--source/blender/render/extern/include/RE_engine.h9
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h26
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h49
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h26
-rw-r--r--source/blender/render/intern/include/render_result.h2
-rw-r--r--source/blender/render/intern/include/render_types.h7
-rw-r--r--source/blender/render/intern/include/renderdatabase.h5
-rw-r--r--source/blender/render/intern/include/renderpipeline.h1
-rw-r--r--source/blender/render/intern/include/shading.h4
-rw-r--r--source/blender/render/intern/include/texture.h4
-rw-r--r--source/blender/render/intern/include/zbuf.h4
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp3
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h4
-rw-r--r--source/blender/render/intern/source/bake.c22
-rw-r--r--source/blender/render/intern/source/bake_api.c268
-rw-r--r--source/blender/render/intern/source/convertblender.c104
-rw-r--r--source/blender/render/intern/source/envmap.c19
-rw-r--r--source/blender/render/intern/source/external_engine.c72
-rw-r--r--source/blender/render/intern/source/imagetexture.c22
-rw-r--r--source/blender/render/intern/source/multires_bake.c12
-rw-r--r--source/blender/render/intern/source/pipeline.c422
-rw-r--r--source/blender/render/intern/source/pixelshading.c11
-rw-r--r--source/blender/render/intern/source/pointdensity.c706
-rw-r--r--source/blender/render/intern/source/rayshade.c10
-rw-r--r--source/blender/render/intern/source/render_result.c105
-rw-r--r--source/blender/render/intern/source/render_texture.c222
-rw-r--r--source/blender/render/intern/source/rendercore.c6
-rw-r--r--source/blender/render/intern/source/renderdatabase.c97
-rw-r--r--source/blender/render/intern/source/shadbuf.c4
-rw-r--r--source/blender/render/intern/source/shadeinput.c81
-rw-r--r--source/blender/render/intern/source/shadeoutput.c67
-rw-r--r--source/blender/render/intern/source/volume_precache.c67
-rw-r--r--source/blender/render/intern/source/volumetric.c4
-rw-r--r--source/blender/render/intern/source/voxeldata.c10
-rw-r--r--source/blender/render/intern/source/zbuf.c14
-rw-r--r--source/blender/windowmanager/CMakeLists.txt5
-rw-r--r--source/blender/windowmanager/SConscript98
-rw-r--r--source/blender/windowmanager/WM_api.h65
-rw-r--r--source/blender/windowmanager/WM_keymap.h4
-rw-r--r--source/blender/windowmanager/intern/wm.c2
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c20
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c223
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c108
-rw-r--r--source/blender/windowmanager/intern/wm_files.c1058
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c497
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c53
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c49
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c54
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c36
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c298
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c1307
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c93
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c225
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c45
-rw-r--r--source/blender/windowmanager/intern/wm_window.c206
-rw-r--r--source/blender/windowmanager/wm_cursors.h8
-rw-r--r--source/blender/windowmanager/wm_draw.h8
-rw-r--r--source/blender/windowmanager/wm_event_types.h4
-rw-r--r--source/blender/windowmanager/wm_files.h29
-rw-r--r--source/blender/windowmanager/wm_subwindow.h4
-rw-r--r--source/blender/windowmanager/wm_window.h8
-rw-r--r--source/blenderplayer/CMakeLists.txt30
-rw-r--r--source/blenderplayer/bad_level_call_stubs/SConscript48
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c62
-rw-r--r--source/creator/CMakeLists.txt114
-rw-r--r--source/creator/blender.map1
-rw-r--r--source/creator/creator.c1568
-rw-r--r--source/creator/creator_args.c1870
-rw-r--r--source/creator/creator_intern.h95
-rw-r--r--source/creator/creator_launch_win.c90
-rw-r--r--source/creator/creator_signals.c328
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp36
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp54
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.h1
-rw-r--r--source/gameengine/BlenderRoutines/SConscript91
-rw-r--r--source/gameengine/Converter/BL_ActionActuator.cpp14
-rw-r--r--source/gameengine/Converter/BL_ActionActuator.h2
-rw-r--r--source/gameengine/Converter/BL_ArmatureActuator.cpp2
-rw-r--r--source/gameengine/Converter/BL_ArmatureChannel.h5
-rw-r--r--source/gameengine/Converter/BL_ArmatureConstraint.cpp6
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp55
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp215
-rw-r--r--source/gameengine/Converter/BL_ModifierDeformer.cpp1
-rw-r--r--source/gameengine/Converter/BL_ShapeActionActuator.cpp2
-rw-r--r--source/gameengine/Converter/BL_SkinDeformer.cpp7
-rw-r--r--source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp1
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.cpp101
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.h1
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp43
-rw-r--r--source/gameengine/Converter/KX_ConvertControllers.cpp1
-rw-r--r--source/gameengine/Converter/KX_ConvertSensors.cpp1
-rw-r--r--source/gameengine/Converter/KX_LibLoadStatus.cpp5
-rw-r--r--source/gameengine/Converter/KX_LibLoadStatus.h8
-rw-r--r--source/gameengine/Converter/SConscript94
-rw-r--r--source/gameengine/Expressions/CMakeLists.txt3
-rw-r--r--source/gameengine/Expressions/EXP_ListWrapper.h109
-rw-r--r--source/gameengine/Expressions/SConscript50
-rw-r--r--source/gameengine/Expressions/intern/ListWrapper.cpp424
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp4
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_Joystick.h11
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp4
-rw-r--r--source/gameengine/GameLogic/SCA_DelaySensor.h2
-rw-r--r--source/gameengine/GameLogic/SCA_IActuator.h2
-rw-r--r--source/gameengine/GameLogic/SCA_IController.cpp48
-rw-r--r--source/gameengine/GameLogic/SCA_ILogicBrick.cpp13
-rw-r--r--source/gameengine/GameLogic/SCA_ILogicBrick.h7
-rw-r--r--source/gameengine/GameLogic/SCA_PythonController.cpp7
-rw-r--r--source/gameengine/GameLogic/SConscript63
-rw-r--r--source/gameengine/GamePlayer/SConscript29
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.cpp50
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/common/SConscript81
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp16
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_System.cpp2
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp3
-rw-r--r--source/gameengine/GamePlayer/ghost/SConscript99
-rw-r--r--source/gameengine/Ketsji/BL_Action.cpp74
-rw-r--r--source/gameengine/Ketsji/BL_Action.h19
-rw-r--r--source/gameengine/Ketsji/BL_ActionManager.cpp40
-rw-r--r--source/gameengine/Ketsji/BL_ActionManager.h10
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp15
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp1078
-rw-r--r--source/gameengine/Ketsji/BL_Shader.h180
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp7
-rw-r--r--source/gameengine/Ketsji/CMakeLists.txt4
-rw-r--r--source/gameengine/Ketsji/KXNetwork/SConscript52
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp22
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.h1
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp42
-rw-r--r--source/gameengine/Ketsji/KX_CameraActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_CharacterWrapper.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.cpp62
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintActuator.h10
-rw-r--r--source/gameengine/Ketsji/KX_Dome.cpp799
-rw-r--r--source/gameengine/Ketsji/KX_FontObject.cpp5
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.cpp12
-rw-r--r--source/gameengine/Ketsji/KX_GameActuator.h1
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp328
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h28
-rw-r--r--source/gameengine/Ketsji/KX_IPOTransform.h18
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.cpp113
-rw-r--r--source/gameengine/Ketsji/KX_IPO_SGController.h51
-rw-r--r--source/gameengine/Ketsji/KX_ISceneConverter.h1
-rw-r--r--source/gameengine/Ketsji/KX_IpoActuator.cpp500
-rw-r--r--source/gameengine/Ketsji/KX_IpoActuator.h153
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp203
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h52
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp88
-rw-r--r--source/gameengine/Ketsji/KX_Light.h10
-rw-r--r--source/gameengine/Ketsji/KX_MeshProxy.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_MeshProxy.h3
-rw-r--r--source/gameengine/Ketsji/KX_MouseActuator.cpp78
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.cpp22
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.h8
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.cpp34
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.h4
-rw-r--r--source/gameengine/Ketsji/KX_ObstacleSimulation.cpp8
-rw-r--r--source/gameengine/Ketsji/KX_OrientationInterpolator.cpp12
-rw-r--r--source/gameengine/Ketsji/KX_ParentActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp3
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp214
-rw-r--r--source/gameengine/Ketsji/KX_PythonInitTypes.cpp9
-rw-r--r--source/gameengine/Ketsji/KX_PythonSeq.cpp526
-rw-r--r--source/gameengine/Ketsji/KX_PythonSeq.h68
-rw-r--r--source/gameengine/Ketsji/KX_RadarSensor.cpp14
-rw-r--r--source/gameengine/Ketsji/KX_RayCast.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_RayCast.h27
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.h8
-rw-r--r--source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp46
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h3
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp14
-rw-r--r--source/gameengine/Ketsji/KX_SteeringActuator.cpp24
-rw-r--r--source/gameengine/Ketsji/KX_TimeLogger.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.cpp9
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.cpp22
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp3
-rw-r--r--source/gameengine/Ketsji/KX_VertexProxy.cpp10
-rw-r--r--source/gameengine/Ketsji/KX_WorldInfo.cpp70
-rw-r--r--source/gameengine/Ketsji/SConscript110
-rw-r--r--source/gameengine/Network/LoopBackNetwork/SConscript41
-rw-r--r--source/gameengine/Network/SConscript46
-rw-r--r--source/gameengine/Physics/Bullet/CcdGraphicController.cpp18
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.cpp60
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h23
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp704
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/Bullet/SConscript68
-rw-r--r--source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/Dummy/SConscript45
-rw-r--r--source/gameengine/Physics/common/PHY_ICharacter.h6
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/common/PHY_Pro.h1
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt2
-rw-r--r--source/gameengine/Rasterizer/RAS_2DFilterManager.cpp8
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.cpp14
-rw-r--r--source/gameengine/Rasterizer/RAS_CameraData.h8
-rw-r--r--source/gameengine/Rasterizer/RAS_FramingManager.cpp8
-rw-r--r--source/gameengine/Rasterizer/RAS_FramingManager.h4
-rw-r--r--source/gameengine/Rasterizer/RAS_ICanvas.cpp128
-rw-r--r--source/gameengine/Rasterizer/RAS_ICanvas.h25
-rw-r--r--source/gameengine/Rasterizer/RAS_ILightObject.h11
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp24
-rw-r--r--source/gameengine/Rasterizer/RAS_IRasterizer.h10
-rw-r--r--source/gameengine/Rasterizer/RAS_MaterialBucket.cpp14
-rw-r--r--source/gameengine/Rasterizer/RAS_MaterialBucket.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt4
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp73
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h43
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h1
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp28
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp46
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp318
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h22
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp310
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h69
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp63
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h1
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp76
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h9
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript40
-rw-r--r--source/gameengine/Rasterizer/RAS_TexVert.cpp16
-rw-r--r--source/gameengine/Rasterizer/SConscript62
-rw-r--r--source/gameengine/SConscript51
-rw-r--r--source/gameengine/SceneGraph/SConscript47
-rw-r--r--source/gameengine/SceneGraph/SG_BBox.cpp20
-rw-r--r--source/gameengine/SceneGraph/SG_BBox.h2
-rw-r--r--source/gameengine/SceneGraph/SG_Spatial.cpp16
-rw-r--r--source/gameengine/SceneGraph/SG_Tree.cpp12
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp38
-rw-r--r--source/gameengine/VideoTexture/PyTypeList.h4
-rw-r--r--source/gameengine/VideoTexture/SConscript76
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp6
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp37
-rw-r--r--source/gameengine/VideoTexture/blendVideoTex.cpp2
-rw-r--r--source/icons/SConscript38
-rw-r--r--tests/check_deprecated.py1
-rw-r--r--tests/gtests/blenlib/BLI_array_utils_test.cc120
-rw-r--r--tests/gtests/blenlib/BLI_ghash_performance_test.cc18
-rw-r--r--tests/gtests/blenlib/BLI_ghash_test.cc42
-rw-r--r--tests/gtests/blenlib/BLI_path_util_test.cc11
-rw-r--r--tests/gtests/blenlib/BLI_polyfill2d_test.cc1
-rw-r--r--tests/gtests/blenlib/BLI_ressource_strings.h5
-rw-r--r--tests/gtests/blenlib/BLI_stack_test.cc2
-rw-r--r--tests/gtests/blenlib/BLI_string_test.cc103
-rw-r--r--tests/gtests/blenlib/CMakeLists.txt11
-rw-r--r--tests/gtests/bmesh/bmesh_core_test.cc1
-rw-r--r--tests/gtests/guardedalloc/CMakeLists.txt1
-rw-r--r--tests/gtests/guardedalloc/guardedalloc_alignment_test.cc6
-rw-r--r--tests/gtests/testing/CMakeLists.txt9
-rw-r--r--tests/gtests/testing/testing.h16
-rw-r--r--tests/python/CMakeLists.txt12
-rw-r--r--tests/python/bl_bpy_path.py41
-rw-r--r--tests/python/bl_load_py_modules.py11
-rw-r--r--tests/python/bl_mesh_modifiers.py7
-rw-r--r--tests/python/bl_pyapi_bpy_path.py41
-rw-r--r--tests/python/bl_pyapi_bpy_utils_units.py75
-rw-r--r--tests/python/bl_pyapi_mathutils.py72
-rw-r--r--tests/python/bl_pyapi_units.py75
-rw-r--r--tests/python/bl_rna_defaults.py45
-rw-r--r--tests/python/bl_run_operators.py6
-rw-r--r--tests/python/pep8.py2
-rw-r--r--tests/python/rst_to_doctree_mini.py2
3234 files changed, 188312 insertions, 176650 deletions
diff --git a/.gitignore b/.gitignore
index b172c446553..7acac981ed7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@ Desktop.ini
# commonly used paths in blender
/blender.bin
/user-config.py
+/BUILD_NOTES.txt
# local patches
/*.patch
diff --git a/.gitmodules b/.gitmodules
index 4ce5a2466e6..132f6cffada 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,7 +10,3 @@
path = release/datafiles/locale
url = ../blender-translations.git
ignore = all
-[submodule "scons"]
- path = scons
- url = ../scons.git
- ignore = all
diff --git a/CMakeLists.txt b/CMakeLists.txt
index deafa90dbb5..f05e9680c0a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,11 +47,6 @@ endif()
cmake_minimum_required(VERSION 2.8)
-if(NOT (${CMAKE_VERSION} VERSION_LESS 3.0))
- # keep until CMake-3.0 is min requirement
- cmake_policy(SET CMP0043 OLD)
-endif()
-
if(NOT EXECUTABLE_OUTPUT_PATH)
set(FIRST_RUN TRUE)
else()
@@ -68,10 +63,21 @@ set(CMAKE_BUILD_TYPE_INIT "Release")
# set_property(GLOBAL PROPERTY RULE_MESSAGES OFF)
# global compile definitions since add_definitions() adds for all.
-set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG _DEBUG)
-set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE NDEBUG)
-set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL NDEBUG)
-set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO NDEBUG)
+
+if(NOT (${CMAKE_VERSION} VERSION_LESS 3.0))
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
+ $<$<CONFIG:Debug>:DEBUG;_DEBUG>
+ $<$<CONFIG:Release>:NDEBUG>
+ $<$<CONFIG:MinSizeRel>:NDEBUG>
+ $<$<CONFIG:RelWithDebInfo>:NDEBUG>
+ )
+else()
+ # keep until CMake-3.0 is min requirement
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUG _DEBUG)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE NDEBUG)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL NDEBUG)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO NDEBUG)
+endif()
#-----------------------------------------------------------------------------
# Set policy
@@ -149,10 +155,8 @@ option_defaults_init(
_init_CODEC_FFMPEG
_init_CYCLES_OSL
_init_IMAGE_OPENEXR
- _init_IMAGE_REDCODE
_init_INPUT_NDOF
_init_JACK
- _init_LIBMV_SCHUR_SPECIALIZATION
_init_OPENCOLLADA
_init_OPENCOLORIO
_init_SDL
@@ -168,7 +172,6 @@ if (UNIX AND NOT APPLE)
set(_init_CODEC_FFMPEG OFF)
set(_init_CYCLES_OSL OFF)
set(_init_IMAGE_OPENEXR OFF)
- set(_init_IMAGE_REDCODE OFF)
set(_init_INPUT_NDOF OFF)
set(_init_JACK OFF)
set(_init_OPENCOLLADA OFF)
@@ -179,7 +182,6 @@ if (UNIX AND NOT APPLE)
elseif(WIN32)
set(_init_JACK OFF)
elseif(APPLE)
- set(_init_INPUT_NDOF OFF)
set(_init_JACK OFF)
set(_init_OPENSUBDIV OFF)
endif()
@@ -229,18 +231,17 @@ option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLO
# Compositor
option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
-option(WITH_COMPOSITOR_WERROR "Treat warnings as errors in compositor code" OFF)
-mark_as_advanced(WITH_COMPOSITOR_WERROR)
option(WITH_OPENSUBDIV "Enable OpenSubdiv for surface subdivision" _init_OPENSUBDIV)
-option(WITH_SUBSURF_WERROR "Treat warnings as errors in subsurf code" OFF)
-mark_as_advanced(WITH_COMPOSITOR_WERROR)
+
+option(WITH_OPENVDB "Enable features relying on OpenVDB" OFF)
+option(WITH_OPENVDB_BLOSC "Enable blosc compression for OpenVDB, only enable if OpenVDB was built with blosc support" OFF)
# GHOST Windowing Library Options
option(WITH_GHOST_DEBUG "Enable debugging output for the GHOST library" OFF)
mark_as_advanced(WITH_GHOST_DEBUG)
-option(WITH_GHOST_SDL "Enable building blender against SDL for windowing rather then the native APIs" OFF)
+option(WITH_GHOST_SDL "Enable building Blender against SDL for windowing rather than the native APIs" OFF)
mark_as_advanced(WITH_GHOST_SDL)
if(WITH_X11)
@@ -261,6 +262,10 @@ if(NOT WITH_AUDASPACE)
endif()
option(WITH_OPENMP "Enable OpenMP (has to be supported by the compiler)" ON)
+if(UNIX AND NOT APPLE)
+ option(WITH_OPENMP_STATIC "Link OpenMP statically (only used by the release environment)" OFF)
+ mark_as_advanced(WITH_OPENMP_STATIC)
+endif()
if(WITH_X11)
option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON)
@@ -302,7 +307,6 @@ option(WITH_IMAGE_TIFF "Enable LibTIFF Support" ON)
option(WITH_IMAGE_DDS "Enable DDS Image Support" ON)
option(WITH_IMAGE_CINEON "Enable CINEON and DPX Image Support" ON)
option(WITH_IMAGE_HDR "Enable HDR Image Support" ON)
-option(WITH_IMAGE_REDCODE "Enable RedCode Image Support" ${_init_IMAGE_REDCODE})
option(WITH_IMAGE_FRAMESERVER "Enable image FrameServer Support for rendering" ON)
# Audio/Video format support
@@ -338,10 +342,8 @@ endif()
# Camera/motion tracking
option(WITH_LIBMV "Enable Libmv structure from motion library" ON)
-option(WITH_LIBMV_SCHUR_SPECIALIZATIONS "Enable fixed-size schur specializations." ${_init_LIBMV_SCHUR_SPECIALIZATION})
-option(WITH_LIBMV_WERROR "Treat warnings as errors in Libmv (and Blender's motion tracking) code")
+option(WITH_LIBMV_SCHUR_SPECIALIZATIONS "Enable fixed-size schur specializations." OFF)
mark_as_advanced(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
-mark_as_advanced(WITH_LIBMV_WERROR)
# Freestyle
option(WITH_FREESTYLE "Enable Freestyle (advanced edges rendering)" ON)
@@ -352,7 +354,6 @@ if(WIN32)
endif()
option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ${_init_INPUT_NDOF})
option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
-option(WITH_OPENNL "Enable use of Open Numerical Library" ON)
if(UNIX AND NOT APPLE)
option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON)
option(WITH_STATIC_LIBS "Try to link with static libraries, as much as possible, to make blender more portable across distributions" OFF)
@@ -361,34 +362,41 @@ if(UNIX AND NOT APPLE)
mark_as_advanced(WITH_BOOST_ICU)
endif()
endif()
+
option(WITH_PYTHON_INSTALL "Copy system python into the blender install folder" ON)
-option(WITH_PYTHON_INSTALL_NUMPY "Copy system numpy into the blender install folder" ON)
-set(PYTHON_NUMPY_PATH "" CACHE PATH "Path to python site-packages or dist-packages containing 'numpy' module")
-mark_as_advanced(PYTHON_NUMPY_PATH)
-option(WITH_CPU_SSE "Enable SIMD instruction if they're detected on the host machine" ON)
-mark_as_advanced(WITH_CPU_SSE)
+if(WITH_PYTHON_INSTALL)
+ option(WITH_PYTHON_INSTALL_NUMPY "Copy system numpy into the blender install folder" ON)
+ set(PYTHON_NUMPY_PATH "" CACHE PATH "Path to python site-packages or dist-packages containing 'numpy' module")
+ mark_as_advanced(PYTHON_NUMPY_PATH)
-if(UNIX AND NOT APPLE)
- option(WITH_PYTHON_INSTALL_REQUESTS "Copy system requests into the blender install folder" ON)
- set(PYTHON_REQUESTS_PATH "" CACHE PATH "Path to python site-packages or dist-packages containing 'requests' module")
- mark_as_advanced(PYTHON_REQUESTS_PATH)
+ if(UNIX AND NOT APPLE)
+ option(WITH_PYTHON_INSTALL_REQUESTS "Copy system requests into the blender install folder" ON)
+ set(PYTHON_REQUESTS_PATH "" CACHE PATH "Path to python site-packages or dist-packages containing 'requests' module")
+ mark_as_advanced(PYTHON_REQUESTS_PATH)
+ endif()
endif()
+option(WITH_CPU_SSE "Enable SIMD instruction if they're detected on the host machine" ON)
+mark_as_advanced(WITH_CPU_SSE)
+
# Cycles
option(WITH_CYCLES "Enable Cycles Render Engine" ON)
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
-set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_50 sm_52 CACHE STRING "CUDA architectures to build binaries for")
+set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_37 sm_50 sm_52 CACHE STRING "CUDA architectures to build binaries for")
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
unset(PLATFORM_DEFAULT)
option(WITH_CYCLES_LOGGING "Build Cycles with logging support" ON)
option(WITH_CYCLES_DEBUG "Build Cycles with extra debug capabilities" OFF)
-option(WITH_CYCLES_WERROR "Treat warnings as errors in Cycles code" OFF)
+option(WITH_CYCLES_NATIVE_ONLY "Build Cycles with native kernel only (which fits current CPU, use for development only)" OFF)
mark_as_advanced(WITH_CYCLES_LOGGING)
mark_as_advanced(WITH_CYCLES_DEBUG)
-mark_as_advanced(WITH_CYCLES_WERROR)
+mark_as_advanced(WITH_CYCLES_NATIVE_ONLY)
+
+option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime" ON)
+mark_as_advanced(WITH_CUDA_DYNLOAD)
# LLVM
option(WITH_LLVM "Use LLVM" OFF)
@@ -460,14 +468,16 @@ if(WITH_GLEW_ES AND WITH_SYSTEM_GLEW)
set(WITH_SYSTEM_GLEW OFF)
endif()
-if(MSVC)
+if(WIN32)
getDefaultWindowsPrefixBase(CMAKE_GENERIC_PROGRAM_FILES)
set(CPACK_INSTALL_PREFIX ${CMAKE_GENERIC_PROGRAM_FILES}/${})
endif()
-# Experimental support of C++11
-option(WITH_CPP11 "Build with C++11 standard enabled, for development use only!" OFF)
-mark_as_advanced(WITH_CPP11)
+# Experimental support of C11 and C++11
+option(WITH_C11 "Build with C11 standard enabled, for development use only!" OFF)
+mark_as_advanced(WITH_C11)
+option(WITH_CXX11 "Build with C++11 standard enabled, for development use only!" OFF)
+mark_as_advanced(WITH_CXX11)
# Dependency graph
option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
@@ -483,7 +493,7 @@ option_defaults_clear()
# By default we want to install to the directory we are compiling our executables
# unless specified otherwise, which we currently do not allow
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
- if(MSVC)
+ if(WIN32)
set(CMAKE_INSTALL_PREFIX ${EXECUTABLE_OUTPUT_PATH}/\${BUILD_TYPE} CACHE PATH "default install path" FORCE)
elseif(APPLE)
set(CMAKE_INSTALL_PREFIX ${EXECUTABLE_OUTPUT_PATH}/\${BUILD_TYPE} CACHE PATH "default install path" FORCE)
@@ -499,42 +509,27 @@ endif()
# Apple
if(APPLE)
- if(${CMAKE_VERSION} VERSION_LESS 3.0) # else breaks setting CMP0043 policy
- cmake_minimum_required(VERSION 2.8.8)
- cmake_policy(VERSION 2.8.8)
- endif()
+ # require newer cmake on osx because of version handling,
+ # older cmake cannot handle 2 digit subversion!
+ cmake_minimum_required(VERSION 3.0.0)
if(NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING
"Choose the architecture you want to build Blender for: i386, x86_64 or ppc"
FORCE)
endif()
-
- execute_process(COMMAND uname -r OUTPUT_VARIABLE MAC_SYS) # check for actual system-version
- if(${MAC_SYS} MATCHES 14)
- set(OSX_SYSTEM 10.10)
- # throw an error here, older cmake cannot handle 2 digit subversion!
- cmake_minimum_required(VERSION 3.0.0)
- elseif(${MAC_SYS} MATCHES 13)
- set(OSX_SYSTEM 10.9)
- elseif(${MAC_SYS} MATCHES 12)
- set(OSX_SYSTEM 10.8)
- elseif(${MAC_SYS} MATCHES 11)
- set(OSX_SYSTEM 10.7)
- elseif(${MAC_SYS} MATCHES 10)
- set(OSX_SYSTEM 10.6)
- elseif(${MAC_SYS} MATCHES 9)
- set(OSX_SYSTEM 10.5)
- else()
- set(OSX_SYSTEM unsupported)
+
+ if(NOT DEFINED OSX_SYSTEM)
+ execute_process(
+ COMMAND xcodebuild -version -sdk macosx SDKVersion
+ OUTPUT_VARIABLE OSX_SYSTEM
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
- message(STATUS "Detected system-version: " ${OSX_SYSTEM})
-
+
# workaround for incorrect cmake xcode lookup for developer previews - XCODE_VERSION does not take xcode-select path into accout
# but would always look into /Applications/Xcode.app while dev versions are named Xcode<version>-DP<preview_number>
execute_process(COMMAND xcode-select --print-path OUTPUT_VARIABLE XCODE_CHECK OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE "/Contents/Developer" "" XCODE_BUNDLE ${XCODE_CHECK}) # truncate to bundlepath in any case
- message(STATUS "Xcode-bundle : " ${XCODE_BUNDLE})
if(${CMAKE_GENERATOR} MATCHES "Xcode")
@@ -562,8 +557,8 @@ if(APPLE)
string(SUBSTRING "${XCODE_VERS_BUILD_NR}" 6 3 XCODE_VERSION) # truncate away build-nr
unset(XCODE_VERS_BUILD_NR)
endif()
-
- message(STATUS "Detected Xcode-version: " ${XCODE_VERSION})
+
+ message(STATUS "Detected OS X ${OSX_SYSTEM} and Xcode ${XCODE_VERSION} at ${XCODE_BUNDLE}")
if(${XCODE_VERSION} VERSION_LESS 4.3)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk CACHE PATH "" FORCE) # use guaranteed existing sdk
@@ -625,10 +620,6 @@ if(NOT WITH_SDL AND WITH_GHOST_SDL)
message(FATAL_ERROR "WITH_GHOST_SDL requires WITH_SDL")
endif()
-if(WITH_IMAGE_REDCODE AND ((NOT WITH_IMAGE_OPENJPEG) OR (NOT WITH_CODEC_FFMPEG)))
- message(FATAL_ERROR "WITH_IMAGE_REDCODE requires WITH_IMAGE_OPENJPEG and WITH_CODEC_FFMPEG")
-endif()
-
# python module, needs some different options
if(WITH_PYTHON_MODULE AND WITH_PLAYER)
message(FATAL_ERROR "WITH_PYTHON_MODULE requires WITH_PLAYER to be OFF")
@@ -663,14 +654,21 @@ if(NOT WITH_BOOST)
set_and_warn(WITH_CYCLES OFF)
set_and_warn(WITH_AUDASPACE OFF)
set_and_warn(WITH_INTERNATIONAL OFF)
+ set_and_warn(WITH_OPENVDB OFF)
+ set_and_warn(WITH_OPENCOLORIO OFF)
+ set_and_warn(WITH_MOD_BOOLEAN OFF)
set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE
set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE
-elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL)
+ set_and_warn(WITH_PLAYER OFF) # depends on GAMEENGINE
+elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL OR WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_MOD_BOOLEAN)
# Keep enabled
else()
- # Enabled but we don't need it
- set(WITH_BOOST OFF)
+ # New dependency graph needs either Boost or C++11 for function bindings.
+ if(NOT USE_CXX11)
+ # Enabled but we don't need it
+ set(WITH_BOOST OFF)
+ endif()
endif()
# auto enable openimageio for cycles
@@ -712,11 +710,17 @@ else()
set(COMPILER_SSE2_FLAG)
endif()
-TEST_STDBOOL_SUPPORT()
-if(HAVE_STDBOOL_H)
- add_definitions(-DHAVE_STDBOOL_H)
+if(WITH_BUILDINFO)
+ find_package(Git)
+ if(NOT GIT_FOUND)
+ message(WARNING "Git was not found, disabling WITH_BUILDINFO")
+ set(WITH_BUILDINFO OFF)
+ endif()
endif()
+TEST_SHARED_PTR_SUPPORT()
+TEST_UNORDERED_MAP_SUPPORT()
+
if(WITH_AUDASPACE)
if(WITH_SYSTEM_AUDASPACE)
set(AUDASPACE_DEFINITIONS
@@ -802,14 +806,14 @@ set(PLATFORM_LINKFLAGS_DEBUG "")
# For alternate Python locations the commandline can be used to override detected/default cache settings, e.g:
# On Unix:
# cmake ../blender \
-# -D PYTHON_VERSION=3.4 \
-# -D PYTHON_INCLUDE_DIR=/opt/py34/include/python3.4d \
-# -D PYTHON_LIBRARY=/opt/py34/lib/libpython3.4d.so
+# -D PYTHON_VERSION=3.5 \
+# -D PYTHON_INCLUDE_DIR=/opt/py35/include/python3.5d \
+# -D PYTHON_LIBRARY=/opt/py35/lib/libpython3.5d.so
#
# On Macs:
# cmake ../blender \
-# -D PYTHON_INCLUDE_DIR=/System/Library/Frameworks/Python.framework/Versions/3.4/include/python3.4 \
-# -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/config \
+# -D PYTHON_INCLUDE_DIR=/System/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5 \
+# -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/config \
# -G Xcode
#
# When changing any of this remember to update the notes in doc/build_systems/cmake.txt
@@ -857,13 +861,9 @@ endif()
if(UNIX AND NOT APPLE)
macro(find_package_wrapper)
if(WITH_STATIC_LIBS)
- set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
- set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
- endif()
- find_package(${ARGV})
- if(WITH_STATIC_LIBS)
- set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
- unset(_cmake_find_library_suffixes_back)
+ find_package_static(${ARGV})
+ else()
+ find_package(${ARGV})
endif()
endmacro()
@@ -888,10 +888,10 @@ if(UNIX AND NOT APPLE)
# else values are set below for all platforms
if(WITH_PYTHON)
- # No way to set py34. remove for now.
+ # No way to set py35, remove for now.
# find_package(PythonLibs)
- # Use our own instead, since wothout py is such a rare case,
+ # Use our own instead, since without py is such a rare case,
# require this package
# XXX Linking errors with debian static python :/
# find_package_wrapper(PythonLibsUnix REQUIRED)
@@ -1048,6 +1048,16 @@ if(UNIX AND NOT APPLE)
endif()
endif()
+ if(WITH_OPENVDB)
+ find_package_wrapper(OpenVDB)
+ find_package_wrapper(TBB)
+ if(NOT OPENVDB_FOUND OR NOT TBB_FOUND)
+ set(WITH_OPENVDB OFF)
+ set(WITH_OPENVDB_BLOSC OFF)
+ message(STATUS "OpenVDB not found, disabling it")
+ endif()
+ endif()
+
if(WITH_BOOST)
# uses in build instructions to override include and library variables
if(NOT BOOST_CUSTOM)
@@ -1068,6 +1078,9 @@ if(UNIX AND NOT APPLE)
if(WITH_CYCLES_NETWORK)
list(APPEND __boost_packages serialization)
endif()
+ if(WITH_OPENVDB)
+ list(APPEND __boost_packages iostreams)
+ endif()
find_package(Boost 1.48 COMPONENTS ${__boost_packages})
if(NOT Boost_FOUND)
# try to find non-multithreaded if -mt not found, this flag
@@ -1181,12 +1194,6 @@ if(UNIX AND NOT APPLE)
if(CMAKE_COMPILER_IS_GNUCC)
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
- if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "5.0")
- # GCC5 uses gnu11, until we update, force c89
- # though some c11 features can still be used.
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89")
- endif()
-
# use ld.gold linker if available, could make optional
execute_process(
COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version
@@ -1234,6 +1241,14 @@ elseif(WIN32)
add_definitions(-DWIN32)
if(MSVC)
+ # Minimum MSVC Version
+ set(_min_ver "18.0.31101")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
+ message(FATAL_ERROR
+ "Visual Studio 2013 (Update 4, ${_min_ver}) required, "
+ "found (${CMAKE_CXX_COMPILER_VERSION})")
+ endif()
+ unset(_min_ver)
# needed for some MSVC installations
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
@@ -1266,29 +1281,24 @@ elseif(WIN32)
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
include(InstallRequiredSystemLibraries)
- set(CMAKE_CXX_FLAGS "/nologo /J /Gd /EHsc /MP" CACHE STRING "MSVC MT C++ flags " FORCE)
- set(CMAKE_C_FLAGS "/nologo /J /Gd /MP" CACHE STRING "MSVC MT C++ flags " FORCE)
-
- if(CMAKE_CL_64)
- set(CMAKE_CXX_FLAGS_DEBUG "/Od /RTC1 /MTd /Zi /MP" CACHE STRING "MSVC MT flags " FORCE)
- else()
- set(CMAKE_CXX_FLAGS_DEBUG "/Od /RTC1 /MTd /ZI /MP" CACHE STRING "MSVC MT flags " FORCE)
- endif()
- set(CMAKE_CXX_FLAGS_RELEASE "/O2 /Ob2 /MT /MP" CACHE STRING "MSVC MT flags " FORCE)
- set(CMAKE_CXX_FLAGS_MINSIZEREL "/O1 /Ob1 /MT /MP" CACHE STRING "MSVC MT flags " FORCE)
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/O2 /Ob1 /MT /Zi /MP" CACHE STRING "MSVC MT flags " FORCE)
- if(CMAKE_CL_64)
- set(CMAKE_C_FLAGS_DEBUG "/Od /RTC1 /MTd /Zi /MP" CACHE STRING "MSVC MT flags " FORCE)
- else()
- set(CMAKE_C_FLAGS_DEBUG "/Od /RTC1 /MTd /ZI /MP" CACHE STRING "MSVC MT flags " FORCE)
- endif()
- set(CMAKE_C_FLAGS_RELEASE "/O2 /Ob2 /MT /MP" CACHE STRING "MSVC MT flags " FORCE)
- set(CMAKE_C_FLAGS_MINSIZEREL "/O1 /Ob1 /MT /MP" CACHE STRING "MSVC MT flags " FORCE)
- set(CMAKE_C_FLAGS_RELWITHDEBINFO "/O2 /Ob1 /MT /Zi /MP" CACHE STRING "MSVC MT flags " FORCE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /nologo /J /Gd /MP /EHsc")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP")
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
+ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
+ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
+ set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT")
+ set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} /MT")
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /MT")
set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
+ # Ignore meaningless for us linker warnings.
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /ignore:4049 /ignore:4217 /ignore:4221")
+ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221")
+
# MSVC only, Mingw doesnt need
if(CMAKE_CL_64)
set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:NOREF ${PLATFORM_LINKFLAGS}")
@@ -1298,17 +1308,40 @@ elseif(WIN32)
set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib")
+ # Use dynamic loading for OpenMP
+ if(WITH_OPENMP)
+ if(MSVC_VERSION EQUAL 1800)
+ set(OPENMP_DLL_NAME "vcomp120")
+ else()
+ set(OPENMP_DLL_NAME "vcomp140")
+ endif()
+ set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
+ endif()
+
if(NOT DEFINED LIBDIR)
+
# Setup 64bit and 64bit windows systems
if(CMAKE_CL_64)
message(STATUS "64 bit compiler detected.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/win64_vc12)
+ set(LIBDIR_BASE "win64")
else()
message(STATUS "32 bit compiler detected.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/windows_vc12)
+ set(LIBDIR_BASE "windows")
+ endif()
+
+ if(MSVC_VERSION EQUAL 1900)
+ message(STATUS "Visual Studio 2015 detected.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14)
+ else()
+ message(STATUS "Visual Studio 2013 detected.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc12)
endif()
else()
- message(STATUS using LIBDIR ${LIBDIR})
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+ endif()
+ if(NOT EXISTS "${LIBDIR}/")
+ message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
endif()
# Add each of our libraries to our cmake_prefix_path so find_package() could work
@@ -1337,9 +1370,7 @@ elseif(WIN32)
set(PNG_LIBPATH ${PNG}/lib) # not cmake defined
endif()
- if(MSVC)
- set(JPEG_NAMES ${JPEG_NAMES} libjpeg)
- endif()
+ set(JPEG_NAMES ${JPEG_NAMES} libjpeg)
find_package(jpeg REQUIRED)
set(PTHREADS_INCLUDE_DIRS ${LIBDIR}/pthreads/include)
@@ -1420,14 +1451,14 @@ elseif(WIN32)
message(WARNING "Using HARDCODED OpenEXR locations")
set(OPENEXR ${LIBDIR}/openexr)
set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
- set(OPENEXR_INCLUDE_DIRS ${OPENEXR}/include/OpenEXR)
+ set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
set(OPENEXR_LIBPATH ${OPENEXR}/lib)
set(OPENEXR_LIBRARIES
- ${OPENEXR_LIBPATH}/Iex-2_2.lib
- ${OPENEXR_LIBPATH}/Half.lib
- ${OPENEXR_LIBPATH}/IlmImf-2_2.lib
- ${OPENEXR_LIBPATH}/Imath-2_2.lib
- ${OPENEXR_LIBPATH}/IlmThread-2_2.lib
+ optimized ${OPENEXR_LIBPATH}/Iex-2_2.lib debug ${OPENEXR_LIBPATH}/Iex-2_2_d.lib
+ optimized ${OPENEXR_LIBPATH}/Half.lib debug ${OPENEXR_LIBPATH}/Half_d.lib
+ optimized ${OPENEXR_LIBPATH}/IlmImf-2_2.lib debug ${OPENEXR_LIBPATH}/IlmImf-2_2_d.lib
+ optimized ${OPENEXR_LIBPATH}/Imath-2_2.lib debug ${OPENEXR_LIBPATH}/Imath-2_2_d.lib
+ optimized ${OPENEXR_LIBPATH}/IlmThread-2_2.lib debug ${OPENEXR_LIBPATH}/IlmThread-2_2_d.lib
)
endif()
endif()
@@ -1451,7 +1482,7 @@ elseif(WIN32)
endif()
if(WITH_PYTHON)
- set(PYTHON_VERSION 3.4) # CACHE STRING)
+ set(PYTHON_VERSION 3.5) # CACHE STRING)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
# Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs
@@ -1473,6 +1504,9 @@ elseif(WIN32)
if(WITH_INTERNATIONAL)
list(APPEND boost_extra_libs locale)
endif()
+ if(WITH_OPENVDB)
+ list(APPEND boost_extra_libs iostreams)
+ endif()
set(Boost_USE_STATIC_RUNTIME ON) # prefix lib
set(Boost_USE_MULTITHREADED ON) # suffix -mt
set(Boost_USE_STATIC_LIBS ON) # suffix -s
@@ -1483,12 +1517,12 @@ elseif(WIN32)
set(BOOST_INCLUDE_DIR ${BOOST}/include)
if(MSVC12)
set(BOOST_LIBPATH ${BOOST}/lib)
- set(BOOST_POSTFIX "vc120-mt-s-1_55.lib")
- set(BOOST_DEBUG_POSTFIX "vc120-mt-sgd-1_55.lib")
+ set(BOOST_POSTFIX "vc120-mt-s-1_60.lib")
+ set(BOOST_DEBUG_POSTFIX "vc120-mt-sgd-1_60.lib")
else()
set(BOOST_LIBPATH ${BOOST}/lib)
- set(BOOST_POSTFIX "vc90-mt-s-1_49.lib")
- set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_49.lib")
+ set(BOOST_POSTFIX "vc140-mt-s-1_60.lib")
+ set(BOOST_DEBUG_POSTFIX "vc140-mt-sgd-1_60.lib")
endif()
set(BOOST_LIBRARIES
optimized libboost_date_time-${BOOST_POSTFIX} optimized libboost_filesystem-${BOOST_POSTFIX}
@@ -1561,7 +1595,16 @@ elseif(WIN32)
set(OPENCOLORIO_LIBPATH ${LIBDIR}/opencolorio/lib)
set(OPENCOLORIO_DEFINITIONS)
endif()
-
+
+ if(WITH_OPENVDB)
+ set(BLOSC_LIBRARIES optimized ${LIBDIR}/blosc/lib/libblosc.lib debug ${LIBDIR}/blosc/lib/libblosc_d.lib)
+ set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
+ set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
+ set(OPENVDB ${LIBDIR}/openvdb)
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include ${TBB_INCLUDE_DIR})
+ set(OPENVDB_LIBRARIES optimized openvdb debug openvdb_d ${TBB_LIBRARIES} ${BLOSC_LIBRARIES})
+ set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
+ endif()
if(WITH_MOD_CLOTH_ELTOPO)
set(LAPACK ${LIBDIR}/lapack)
@@ -1584,8 +1627,13 @@ elseif(WIN32)
if(WITH_SDL)
set(SDL ${LIBDIR}/sdl)
set(SDL_INCLUDE_DIR ${SDL}/include)
- set(SDL_LIBRARY SDL2)
set(SDL_LIBPATH ${SDL}/lib)
+ # MinGW TODO: Update MinGW to SDL2
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ set(SDL_LIBRARY SDL2)
+ else()
+ set(SDL_LIBRARY SDL)
+ endif()
endif()
# Audio IO
@@ -1613,23 +1661,25 @@ elseif(WIN32)
"
WITH_MINGW64)
- if(WITH_MINGW64)
- message(STATUS "Compiling for 64 bit with MinGW-w64.")
- execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
- if(GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw64_gcc49)
- else()
+ if(NOT DEFINED LIBDIR)
+ if(WITH_MINGW64)
+ message(STATUS "Compiling for 64 bit with MinGW-w64.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw64)
+ else()
+ message(STATUS "Compiling for 32 bit with MinGW-w32.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw32)
+
+ if(WITH_RAYOPTIMIZATION)
+ message(WARNING "MinGW-w32 is known to be unstable with 'WITH_RAYOPTIMIZATION' option enabled.")
+ endif()
endif()
else()
- message(STATUS "Compiling for 32 bit with MinGW-w32.")
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/mingw32)
-
- if(WITH_RAYOPTIMIZATION)
- message(WARNING "MinGW-w32 is known to be unstable with 'WITH_RAYOPTIMIZATION' option enabled.")
- endif()
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
endif()
-
+ if(NOT EXISTS "${LIBDIR}/")
+ message(FATAL_ERROR "Windows requires pre-compiled libs at: '${LIBDIR}'")
+ endif()
+
list(APPEND PLATFORM_LINKLIBS -lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32 -lpsapi -ldbghelp)
if(WITH_INPUT_IME)
@@ -1741,7 +1791,7 @@ elseif(WIN32)
if(WITH_PYTHON)
# normally cached but not since we include them with blender
- set(PYTHON_VERSION 3.4) # CACHE STRING)
+ set(PYTHON_VERSION 3.5) # CACHE STRING)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") # CACHE PATH)
set(PYTHON_LIBRARY "${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}mw.lib") # CACHE FILEPATH)
@@ -1834,6 +1884,14 @@ elseif(WIN32)
set(SDL_LIBPATH ${SDL}/lib)
endif()
+ if(WITH_OPENVDB)
+ set(OPENVDB ${LIBDIR}/openvdb)
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
+ set(OPENVDB_LIBRARIES openvdb ${TBB_LIBRARIES})
+ set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
+ set(OPENVDB_DEFINITIONS)
+ endif()
+
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
## DISABLE - causes linking errors
@@ -1896,16 +1954,22 @@ elseif(APPLE)
set(WITH_LIBS10.5 ON CACHE BOOL "Use 10.5 libs" FORCE) # valid also for 10.6/7/8/9
endif()
- if(WITH_LIBS10.5)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-9.x.universal)
- else()
- if(CMAKE_OSX_ARCHITECTURES MATCHES i386)
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.x.i386)
+ if(NOT DEFINED LIBDIR)
+ if(WITH_LIBS10.5)
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-9.x.universal)
else()
- set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.0.0-powerpc)
+ if(CMAKE_OSX_ARCHITECTURES MATCHES i386)
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.x.i386)
+ else()
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-8.0.0-powerpc)
+ endif()
endif()
+ else()
+ message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
+ endif()
+ if(NOT EXISTS "${LIBDIR}/")
+ message(FATAL_ERROR "Mac OSX requires pre-compiled libs at: '${LIBDIR}'")
endif()
-
if(WITH_OPENAL)
find_package(OpenAL)
@@ -1946,19 +2010,19 @@ elseif(APPLE)
endif()
if(WITH_PYTHON)
- # we use precompiled libraries for py 3.4 and up by default
- set(PYTHON_VERSION 3.4)
+ # we use precompiled libraries for py 3.5 and up by default
+ set(PYTHON_VERSION 3.5)
if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
# normally cached but not since we include them with blender
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}m")
- # set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
+ set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}m")
set(PYTHON_LIBRARY python${PYTHON_VERSION}m)
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
else()
# module must be compiled against Python framework
set(PYTHON_INCLUDE_DIR "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/include/python${PYTHON_VERSION}m")
- set(PYTHON_EXECUTABLE "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}")
+ set(PYTHON_EXECUTABLE "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}m")
#set(PYTHON_LIBRARY python${PYTHON_VERSION})
set(PYTHON_LIBPATH "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config-${PYTHON_VERSION}m")
#set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
@@ -1967,6 +2031,10 @@ elseif(APPLE)
# uncached vars
set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
+
+ if(NOT EXISTS "${PYTHON_EXECUTABLE}")
+ message(FATAL_ERROR "Python executable missing: ${PYTHON_EXECUTABLE}")
+ endif()
endif()
if(WITH_FFTW3)
@@ -1991,7 +2059,7 @@ elseif(APPLE)
if(WITH_IMAGE_OPENEXR)
set(OPENEXR ${LIBDIR}/openexr)
set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
- set(OPENEXR_INCLUDE_DIRS ${OPENEXR}/include/OpenEXR)
+ set(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR}/include/OpenEXR)
set(OPENEXR_LIBRARIES Iex Half IlmImf Imath IlmThread)
set(OPENEXR_LIBPATH ${OPENEXR}/lib)
endif()
@@ -2115,6 +2183,9 @@ elseif(APPLE)
if(WITH_CYCLES_NETWORK)
list(APPEND BOOST_LIBRARIES boost_serialization-mt)
endif()
+ if(WITH_OPENVDB)
+ list(APPEND BOOST_LIBRARIES boost_iostreams-mt)
+ endif()
set(BOOST_LIBPATH ${BOOST}/lib)
set(BOOST_DEFINITIONS)
endif()
@@ -2139,6 +2210,16 @@ elseif(APPLE)
set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
endif()
+ if(WITH_OPENVDB)
+ set(OPENVDB ${LIBDIR}/openvdb)
+ set(OPENVDB_INCLUDE_DIRS ${OPENVDB}/include)
+ set(TBB_INCLUDE_DIRS ${LIBDIR}/tbb/include)
+ set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a)
+ set(OPENVDB_LIBRARIES openvdb blosc ${TBB_LIBRARIES})
+ set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
+ set(OPENVDB_DEFINITIONS)
+ endif()
+
if(WITH_LLVM)
set(LLVM_ROOT_DIR ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation")
set(LLVM_VERSION "3.4" CACHE STRING "Version of LLVM to use")
@@ -2243,12 +2324,6 @@ endif()
#-----------------------------------------------------------------------------
# Common.
-if(APPLE OR WIN32)
- if(NOT EXISTS "${LIBDIR}/")
- message(FATAL_ERROR "Apple and Windows require pre-compiled libs at: '${LIBDIR}'")
- endif()
-endif()
-
if(NOT WITH_FFTW3 AND WITH_MOD_OCEANSIM)
message(FATAL_ERROR "WITH_MOD_OCEANSIM requires WITH_FFTW3 to be ON")
endif()
@@ -2331,11 +2406,6 @@ if(WITH_IMAGE_OPENJPEG)
endif()
endif()
-if(WITH_IMAGE_REDCODE)
- set(REDCODE ${CMAKE_SOURCE_DIR}/extern)
- set(REDCODE_INC ${REDCODE})
-endif()
-
if(NOT WITH_SYSTEM_EIGEN3)
set(EIGEN3_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/Eigen3)
endif()
@@ -2465,8 +2535,18 @@ endif()
if(WITH_OPENMP)
find_package(OpenMP)
if(OPENMP_FOUND)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+ if(NOT WITH_OPENMP_STATIC)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+ else()
+ # Typically avoid adding flags as defines but we can't
+ # pass OpenMP flags to the linker for static builds, meaning
+ # we can't add any OpenMP related flags to CFLAGS variables
+ # since they're passed to the linker as well.
+ add_definitions("${OpenMP_C_FLAGS}")
+
+ find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES})
+ endif()
else()
set(WITH_OPENMP OFF)
endif()
@@ -2572,15 +2652,68 @@ if(WITH_PYTHON_MODULE)
endif()
#-----------------------------------------------------------------------------
+# Configure GLog/GFlags
+
+if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
+ set(GLOG_DEFINES
+ -DGOOGLE_GLOG_DLL_DECL=
+ )
+
+ set(GFLAGS_DEFINES
+ -DGFLAGS_DLL_DEFINE_FLAG=
+ -DGFLAGS_DLL_DECLARE_FLAG=
+ -DGFLAGS_DLL_DECL=
+ )
+endif()
+
+#-----------------------------------------------------------------------------
+# Configure Ceres
+
+if(WITH_LIBMV)
+ set(CERES_DEFINES)
+
+ if(SHARED_PTR_FOUND)
+ if(SHARED_PTR_TR1_MEMORY_HEADER)
+ list(APPEND CERES_DEFINES -DCERES_TR1_MEMORY_HEADER)
+ endif()
+ if(SHARED_PTR_TR1_NAMESPACE)
+ list(APPEND CERES_DEFINES -DCERES_TR1_SHARED_PTR)
+ endif()
+ else()
+ message(FATAL_ERROR "Ceres: Unable to find shared_ptr.")
+ endif()
+
+ if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
+ list(APPEND CERES_DEFINES -DCERES_STD_UNORDERED_MAP)
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ list(APPEND CERES_DEFINES -DCERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ else()
+ list(APPEND CERES_DEFINES -DCERES_NO_UNORDERED_MAP)
+ message(STATUS "Ceres: Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ list(APPEND CERES_DEFINES -DCERES_TR1_UNORDERED_MAP)
+ else()
+ list(APPEND CERES_DEFINES -DCERES_NO_UNORDERED_MAP)
+ message(STATUS "Ceres: Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+endif()
+
+#-----------------------------------------------------------------------------
# Extra compile flags
if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ALL -Wall)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_CAST_ALIGN -Wcast-align)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_RETURN_TYPE -Werror=return-type)
+ ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_VLA -Werror=vla)
# system headers sometimes do this, disable for now, was: -Werror=strict-prototypes
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_STRICT_PROTOTYPES -Wstrict-prototypes)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_MISSING_PROTOTYPES -Wmissing-prototypes)
@@ -2609,6 +2742,11 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_REDUNDANT_DECLS -Wredundant-decls)
endif()
+ # versions before gcc4.8 include global name-space.
+ if(NOT "${CMAKE_C_COMPILER_VERSION}" VERSION_LESS "4.8")
+ ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_SHADOW -Wshadow)
+ endif()
+
# disable because it gives warnings for printf() & friends.
# ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_DOUBLE_PROMOTION -Wdouble-promotion -Wno-error=double-promotion)
@@ -2625,7 +2763,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_DIV_BY_ZERO -Wno-div-by-zero)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_TYPE_LIMITS -Wtype-limits)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_RETURN_TYPE -Werror=return-type)
- ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_CHAR_SUBSCRIPTS -Wno-char-subscripts)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_UNKNOWN_PRAGMAS -Wno-unknown-pragmas)
@@ -2662,7 +2799,6 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
# strange, clang complains these are not supported, but then yses them.
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ALL -Wall)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_DECLARATION_AFTER_STATEMENT -Werror=declaration-after-statement)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_IMPLICIT_FUNCTION_DECLARATION -Werror=implicit-function-declaration)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_ERROR_RETURN_TYPE -Werror=return-type)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_AUTOLOGICAL_COMPARE -Wno-tautological-compare)
@@ -2724,6 +2860,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC")
"/w34062" # switch statement contains 'default' but no 'case' labels
# disable:
"/wd4018" # signed/unsigned mismatch
+ "/wd4146" # unary minus operator applied to unsigned type, result still unsigned
"/wd4065" # switch statement contains 'default' but no 'case' labels
"/wd4127" # conditional expression is constant
"/wd4181" # qualifier applied to reference type; ignored
@@ -2754,7 +2891,7 @@ if(WITH_PYTHON)
"Python.h for python version \"${PYTHON_VERSION}\"")
endif()
- if(WIN32)
+ if(WIN32 OR APPLE)
# pass, we have this in an archive to extract
elseif(WITH_PYTHON_INSTALL AND WITH_PYTHON_INSTALL_NUMPY)
find_python_package(numpy)
@@ -2767,7 +2904,7 @@ if(WITH_PYTHON)
endif()
endif()
-if(WITH_CPP11)
+if(WITH_CXX11)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(MSVC12)
@@ -2777,6 +2914,16 @@ if(WITH_CPP11)
endif()
endif()
+# Visual Studio has all standards it supports available by default
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID MATCHES "Intel")
+ # Use C99 + GNU extensions, works with GCC, Clang, ICC
+ if(WITH_C11)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
+ else()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
+ endif()
+endif()
+
# Include warnings first, so its possible to disable them with user defined flags
# eg: -Wno-uninitialized
set(CMAKE_C_FLAGS "${C_WARNINGS} ${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS}")
@@ -2832,7 +2979,9 @@ if(WITH_BLENDER OR WITH_PLAYER)
elseif(WITH_CYCLES_STANDALONE)
add_subdirectory(intern/cycles)
add_subdirectory(extern/clew)
- add_subdirectory(extern/cuew)
+ if(WITH_CUDA_DYNLOAD)
+ add_subdirectory(extern/cuew)
+ endif()
if(NOT WITH_SYSTEM_GLEW)
add_subdirectory(extern/glew)
endif()
@@ -2906,6 +3055,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_CYCLES)
info_cfg_option(WITH_FREESTYLE)
info_cfg_option(WITH_OPENCOLORIO)
+ info_cfg_option(WITH_OPENVDB)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)
@@ -2928,7 +3078,6 @@ if(FIRST_RUN)
info_cfg_option(WITH_IMAGE_HDR)
info_cfg_option(WITH_IMAGE_OPENEXR)
info_cfg_option(WITH_IMAGE_OPENJPEG)
- info_cfg_option(WITH_IMAGE_REDCODE)
info_cfg_option(WITH_IMAGE_TIFF)
info_cfg_text("Audio:")
@@ -2971,12 +3120,6 @@ if(FIRST_RUN)
info_cfg_option(WITH_GL_ANGLE)
endif()
- info_cfg_text("Other:")
- info_cfg_option(WITH_OPENNL)
-
- # debug
- message(STATUS "HAVE_STDBOOL_H = ${HAVE_STDBOOL_H}")
-
info_cfg_text("")
message("${_config_msg}")
diff --git a/GNUmakefile b/GNUmakefile
index 3c2ab9d51b9..df2d7051326 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -87,13 +87,13 @@ ifndef NPROCS
NPROCS:=$(shell nproc)
endif
ifeq ($(OS), Darwin)
- NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f3)
+ NPROCS:=$(shell sysctl -n hw.ncpu)
endif
ifeq ($(OS), FreeBSD)
- NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f2 )
+ NPROCS:=$(shell sysctl -n hw.ncpu)
endif
ifeq ($(OS), NetBSD)
- NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f2 )
+ NPROCS:=$(shell sysctl -n hw.ncpu)
endif
endif
@@ -122,7 +122,7 @@ endif
# Build Blender
all: FORCE
@echo
- @echo Configuring Blender ...
+ @echo Configuring Blender in \"$(BUILD_DIR)\" ...
# # if test ! -f $(BUILD_DIR)/CMakeCache.txt ; then \
# # $(CMAKE_CONFIG); \
@@ -136,7 +136,7 @@ all: FORCE
$(MAKE) -C "$(BUILD_DIR)" -s -j $(NPROCS) install
@echo
@echo edit build configuration with: "$(BUILD_DIR)/CMakeCache.txt" run make again to rebuild.
- @echo blender installed, run from: "$(BUILD_DIR)/bin/blender"
+ @echo Blender successfully built, run from: "$(BUILD_DIR)/bin/blender"
@echo
debug: all
diff --git a/SConstruct b/SConstruct
deleted file mode 100644
index b55cca403e9..00000000000
--- a/SConstruct
+++ /dev/null
@@ -1,1417 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-#
-# Main entry-point for the SCons building system
-# Set up some custom actions and target/argument handling
-# Then read all SConscripts and build
-#
-# TODO: fix /FORCE:MULTIPLE on windows to get proper debug builds.
-# TODO: directory copy functions are far too complicated, see:
-# http://wiki.blender.org/index.php/User:Ideasman42/SConsNotSimpleInstallingFiles
-
-import sys
-import os
-import os.path
-import string
-import shutil
-import re
-
-# store path to tools and modules
-toolpath=os.path.join(".", "build_files", "scons", "tools")
-modulespath=os.path.join(".", "build_files", "scons", "Modules")
-
-# needed for importing tools and modules
-sys.path.append(toolpath)
-sys.path.append(modulespath)
-
-import Blender
-import btools
-
-EnsureSConsVersion(1,0,0)
-
-# Before we do anything, let's check if we have a sane os.environ
-if not btools.check_environ():
- Exit()
-
-BlenderEnvironment = Blender.BlenderEnvironment
-B = Blender
-
-VERSION = btools.VERSION # This is used in creating the local config directories
-VERSION_RELEASE_CYCLE = btools.VERSION_RELEASE_CYCLE
-
-### globals ###
-platform = sys.platform
-quickie = None
-quickdebug = None
-
-##### BEGIN SETUP #####
-
-B.possible_types = ['core', 'player', 'player2', 'intern', 'extern', 'system']
-
-B.binarykind = ['blender' , 'blenderplayer']
-##################################
-# target and argument validation #
-##################################
-# XX cheating for BF_FANCY, we check for BF_FANCY before args are validated
-use_color = ARGUMENTS.get('BF_FANCY', '1')
-if platform=='win32':
- use_color = None
-
-if not use_color=='1':
- B.bc.disable()
-
- #on defaut white Os X terminal, some colors are totally unlegible
-if platform=='darwin':
- B.bc.OKGREEN = '\033[34m'
- B.bc.WARNING = '\033[36m'
-
-# arguments
-print B.bc.HEADER+'Command-line arguments'+B.bc.ENDC
-B.arguments = btools.validate_arguments(ARGUMENTS, B.bc)
-btools.print_arguments(B.arguments, B.bc)
-
-# targets
-print B.bc.HEADER+'Command-line targets'+B.bc.ENDC
-B.targets = btools.validate_targets(COMMAND_LINE_TARGETS, B.bc)
-btools.print_targets(B.targets, B.bc)
-
-##########################
-# setting up environment #
-##########################
-
-# handling cmd line arguments & config file
-
-# bitness stuff
-tempbitness = int(B.arguments.get('BF_BITNESS', B.bitness)) # default to bitness found as per starting python
-if tempbitness in B.allowed_bitnesses.values() :
- B.bitness = tempbitness
-
-# first check cmdline for toolset and we create env to work on
-quickie = B.arguments.get('BF_QUICK', None)
-quickdebug = B.arguments.get('BF_QUICKDEBUG', None)
-
-if quickdebug:
- B.quickdebug=string.split(quickdebug, ',')
-else:
- B.quickdebug=[]
-
-if quickie:
- B.quickie=string.split(quickie,',')
-else:
- B.quickie=[]
-
-toolset = B.arguments.get('BF_TOOLSET', None)
-vcver = B.arguments.get('MSVS_VERSION', '12.0')
-
-if toolset:
- print "Using " + toolset
- if toolset=='mstoolkit':
- env = BlenderEnvironment(ENV = os.environ)
- env.Tool('mstoolkit', [toolpath])
- else:
- env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
- if env:
- btools.SetupSpawn(env)
-else:
- if B.bitness==64 and platform=='win32':
- env = BlenderEnvironment(ENV = os.environ, MSVS_ARCH='amd64', TARGET_ARCH='x86_64', MSVC_VERSION=vcver)
- else:
- env = BlenderEnvironment(ENV = os.environ, TARGET_ARCH='x86', MSVC_VERSION=vcver)
-
-if not env:
- print "Could not create a build environment"
- Exit()
-
-cc = B.arguments.get('CC', None)
-cxx = B.arguments.get('CXX', None)
-if cc:
- env['CC'] = cc
-if cxx:
- env['CXX'] = cxx
-
-if sys.platform=='win32':
- if env['CC'] in ['cl', 'cl.exe']:
- platform = 'win64-vc' if B.bitness == 64 else 'win32-vc'
- elif env['CC'] in ['gcc']:
- platform = 'win64-mingw' if B.bitness == 64 else 'win32-mingw'
-
-if 'mingw' in platform:
- print "Setting custom spawn function"
- btools.SetupSpawn(env)
-
-env.SConscriptChdir(0)
-
-# Remove major kernel version from linux platform.
-# After Linus switched kernel to new version model this major version
-# shouldn't take much sense for building rules.
-
-if re.match('linux[0-9]+', platform):
- platform = 'linux'
-
-crossbuild = B.arguments.get('BF_CROSS', None)
-if crossbuild and platform not in ('win32-vc', 'win64-vc'):
- platform = 'linuxcross'
-
-env['OURPLATFORM'] = platform
-
-configfile = os.path.join("build_files", "scons", "config", platform + "-config.py")
-
-if os.path.exists(configfile):
- print B.bc.OKGREEN + "Using config file: " + B.bc.ENDC + configfile
-else:
- print B.bc.FAIL + configfile + " doesn't exist" + B.bc.ENDC
-
-if crossbuild and env['PLATFORM'] != 'win32':
- print B.bc.HEADER+"Preparing for crossbuild"+B.bc.ENDC
- env.Tool('crossmingw', [toolpath])
- # todo: determine proper libs/includes etc.
- # Needed for gui programs, console programs should do without it
-
- # Now we don't need this option to have console window
- # env.Append(LINKFLAGS=['-mwindows'])
-
-userconfig = B.arguments.get('BF_CONFIG', 'user-config.py')
-# first read platform config. B.arguments will override
-optfiles = [configfile]
-if os.path.exists(userconfig):
- print B.bc.OKGREEN + "Using user-config file: " + B.bc.ENDC + userconfig
- optfiles += [userconfig]
-else:
- print B.bc.WARNING + userconfig + " not found, no user overrides" + B.bc.ENDC
-
-opts = btools.read_opts(env, optfiles, B.arguments)
-opts.Update(env)
-
-if sys.platform=='win32':
- if B.bitness==64:
- env.Append(CPPFLAGS=['-DWIN64']) # -DWIN32 needed too, as it's used all over to target Windows generally
-
-if env['BF_DEBUG']:
- env.Append(CPPDEFINES=['_DEBUG', 'DEBUG'])
-else:
- env.Append(CPPDEFINES=['NDEBUG'])
-
-if not env['BF_FANCY']:
- B.bc.disable()
-
-if env['WITH_BF_SDL_DYNLOAD']:
- env['BF_SDL_INC'] = '#extern/sdlew/include/SDL2'
-
-# remove install dir so old and new files are not mixed.
-# NOTE: only do the scripts directory for now, otherwise is too disruptive for developers
-# TODO: perhaps we need an option (off by default) to not do this altogether...
-if not env['WITHOUT_BF_INSTALL'] and not env['WITHOUT_BF_OVERWRITE_INSTALL']:
- scriptsDir = os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts')
- if os.path.isdir(scriptsDir):
- print B.bc.OKGREEN + "Clearing installation directory%s: %s" % (B.bc.ENDC, os.path.abspath(scriptsDir))
- shutil.rmtree(scriptsDir)
-
-
-SetOption('num_jobs', int(env['BF_NUMJOBS']))
-print B.bc.OKGREEN + "Build with parallel jobs%s: %s" % (B.bc.ENDC, GetOption('num_jobs'))
-print B.bc.OKGREEN + "Build with debug symbols%s: %s" % (B.bc.ENDC, env['BF_DEBUG'])
-
-if 'blenderlite' in B.targets:
- target_env_defs = {}
- target_env_defs['WITH_BF_GAMEENGINE'] = False
- target_env_defs['WITH_BF_CYCLES'] = False
- target_env_defs['WITH_BF_OPENAL'] = False
- target_env_defs['WITH_BF_OPENEXR'] = False
- target_env_defs['WITH_BF_PSD'] = False
- target_env_defs['WITH_BF_OPENMP'] = False
- target_env_defs['WITH_BF_ICONV'] = False
- target_env_defs['WITH_BF_INTERNATIONAL'] = False
- target_env_defs['WITH_BF_OPENJPEG'] = False
- target_env_defs['WITH_BF_FFMPEG'] = False
- target_env_defs['WITH_BF_QUICKTIME'] = False
- target_env_defs['WITH_BF_REDCODE'] = False
- target_env_defs['WITH_BF_DDS'] = False
- target_env_defs['WITH_BF_CINEON'] = False
- target_env_defs['WITH_BF_FRAMESERVER'] = False
- target_env_defs['WITH_BF_HDR'] = False
- target_env_defs['WITH_BF_ZLIB'] = False
- target_env_defs['WITH_BF_SDL'] = False
- target_env_defs['WITH_BF_JPEG'] = False
- target_env_defs['WITH_BF_PNG'] = False
- target_env_defs['WITH_BF_BULLET'] = False
- target_env_defs['WITH_BF_BINRELOC'] = False
- target_env_defs['BF_BUILDINFO'] = False
- target_env_defs['WITH_BF_FLUID'] = False
- target_env_defs['WITH_BF_OCEANSIM'] = False
- target_env_defs['WITH_BF_SMOKE'] = False
- target_env_defs['WITH_BF_BOOLEAN'] = False
- target_env_defs['WITH_BF_REMESH'] = False
- target_env_defs['WITH_BF_PYTHON'] = False
- target_env_defs['WITH_BF_IME'] = False
- target_env_defs['WITH_BF_3DMOUSE'] = False
- target_env_defs['WITH_BF_LIBMV'] = False
- target_env_defs['WITH_BF_FREESTYLE'] = False
-
- # Merge blenderlite, let command line to override
- for k,v in target_env_defs.iteritems():
- if k not in B.arguments:
- env[k] = v
-
-if 'cudakernels' in B.targets:
- env['WITH_BF_CYCLES'] = True
- env['WITH_BF_CYCLES_CUDA_BINARIES'] = True
- env['WITH_BF_PYTHON'] = False
- env['WITH_BF_LIBMV'] = False
-
-# Configure paths for automated configuration test programs
-env['CONFIGUREDIR'] = os.path.abspath(os.path.normpath(os.path.join(env['BF_BUILDDIR'], "sconf_temp")))
-env['CONFIGURELOG'] = os.path.abspath(os.path.normpath(os.path.join(env['BF_BUILDDIR'], "config.log")))
-
-#############################################################################
-################### Automatic configuration for OSX ##################
-#############################################################################
-
-if env['OURPLATFORM']=='darwin':
-
- import commands
- import subprocess
-
- command = ["%s"%env['CC'], "--version"]
- line = btools.get_command_output(command)
- ver = re.search(r'[0-9]+(\.[0-9]+[svn]+)+', line) or re.search(r'[0-9]+(\.[0-9]+)+', line) # read the "based on LLVM x.xsvn" version here, not the Apple version
- if ver:
- env['CCVERSION'] = ver.group(0).strip('svn')
- frontend = re.search(r'gcc', line) or re.search(r'clang', line) or re.search(r'llvm-gcc', line) or re.search(r'icc', line)
- if frontend:
- env['C_COMPILER_ID'] = frontend.group(0)
-
- vendor = re.search(r'Apple', line)
- if vendor:
- C_VENDOR = vendor.group(0)
- else:
- C_VENDOR = 'Open Source'
-
- print B.bc.OKGREEN + "Using Compiler: " + B.bc.ENDC + env['C_COMPILER_ID'] + '-' + env['CCVERSION'] + ' ( ' + C_VENDOR + ' )'
-
- cmd = 'sw_vers -productVersion'
- MAC_CUR_VER=cmd_res=commands.getoutput(cmd)
- cmd = 'xcodebuild -version'
- cmd_xcode=commands.getoutput(cmd)
- env['XCODE_CUR_VER']=cmd_xcode[6:][:3] # truncate output to major.minor version
- cmd = 'xcodebuild -showsdks'
- cmd_sdk=commands.getoutput(cmd)
- MACOSX_SDK_CHECK=cmd_sdk
- cmd = 'xcode-select --print-path'
- XCODE_SELECT_PATH=commands.getoutput(cmd)
- if XCODE_SELECT_PATH.endswith("/Contents/Developer"):
- XCODE_BUNDLE=XCODE_SELECT_PATH[:-19]
- else:
- XCODE_BUNDLE=XCODE_SELECT_PATH
-
- print B.bc.OKGREEN + "Detected Xcode version: -- " + B.bc.ENDC + env['XCODE_CUR_VER'] + " --"
- print B.bc.OKGREEN + "Available SDK's: \n" + B.bc.ENDC + MACOSX_SDK_CHECK.replace('\t', '')
-
- if env['MACOSX_SDK'] == '': # no set sdk, choosing best one found
- if 'OS X 10.10' in MACOSX_SDK_CHECK:
- env['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX10.10.sdk'
- elif 'OS X 10.9' in MACOSX_SDK_CHECK:
- env['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX10.9.sdk'
- elif 'OS X 10.8' in MACOSX_SDK_CHECK:
- env['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX10.8.sdk'
- elif 'OS X 10.7' in MACOSX_SDK_CHECK:
- env['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX10.7.sdk'
- elif 'OS X 10.6' in MACOSX_SDK_CHECK:
- env['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX10.6.sdk'
- elif 'OS X 10.5' in MACOSX_SDK_CHECK:
- env['MACOSX_DEPLOYMENT_TARGET'] = '10.5'
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX10.5.sdk'
- else:
- env['MACOSX_SDK']='/Developer/SDKs/MacOSX' + env['MACOSX_SDK'] + '.sdk'
-
- if env['XCODE_CUR_VER'] >= '4.3': ## since version 4.3, XCode and developer dir are bundled ##
- env['MACOSX_SDK'] = XCODE_BUNDLE + '/Contents/Developer/Platforms/MacOSX.platform' + env['MACOSX_SDK']
-
- print B.bc.OKGREEN + "Using OSX SDK :" + B.bc.ENDC + env['MACOSX_SDK']
-
- if not env['WITH_OSX_STATICPYTHON'] == 1:
- # python 3.3 uses Python-framework additionally installed in /Library/Frameworks
- env['BF_PYTHON'] = '/Library/Frameworks/Python.framework/Versions/'
- env['BF_PYTHON_INC'] = env['BF_PYTHON'] + env['BF_PYTHON_VERSION'] + '/include/python' + env['BF_PYTHON_VERSION'] + 'm'
- env['BF_PYTHON_BINARY'] = env['BF_PYTHON'] + env['BF_PYTHON_VERSION'] + '/bin/python' + env['BF_PYTHON_VERSION']
- env['BF_PYTHON_LIB'] = ''
- env['BF_PYTHON_LIBPATH'] = env['BF_PYTHON'] + env['BF_PYTHON_VERSION'] + '/lib/python' + env['BF_PYTHON_VERSION'] + '/config-' + env['BF_PYTHON_VERSION'] +'m'
- env['PLATFORM_LINKFLAGS'] = env['PLATFORM_LINKFLAGS']+['-framework','Python'] # link to python framework
-
- #Ray trace optimization
- if env['WITH_BF_RAYOPTIMIZATION'] == 1:
- if env['MACOSX_ARCHITECTURE'] == 'x86_64' or env['MACOSX_ARCHITECTURE'] == 'i386':
- env['WITH_BF_RAYOPTIMIZATION'] = 1
- else:
- env['WITH_BF_RAYOPTIMIZATION'] = 0
- if env['MACOSX_ARCHITECTURE'] == 'i386':
- env['BF_RAYOPTIMIZATION_SSE_FLAGS'] = env['BF_RAYOPTIMIZATION_SSE_FLAGS']+['-msse']
- elif env['MACOSX_ARCHITECTURE'] == 'x86_64':
- env['BF_RAYOPTIMIZATION_SSE_FLAGS'] = env['BF_RAYOPTIMIZATION_SSE_FLAGS']+['-msse','-msse2']
-
- if env['MACOSX_ARCHITECTURE'] == 'x86_64' or env['MACOSX_ARCHITECTURE'] == 'ppc64':
- ARCH_FLAGS = ['-m64']
- else:
- ARCH_FLAGS = ['-m32']
-
- env.Append(CPPFLAGS=ARCH_FLAGS)
-
- SDK_FLAGS=['-isysroot', env['MACOSX_SDK'],'-mmacosx-version-min='+ env['MACOSX_DEPLOYMENT_TARGET'],'-arch',env['MACOSX_ARCHITECTURE']] # always used
- env['PLATFORM_LINKFLAGS'] = ['-mmacosx-version-min='+ env['MACOSX_DEPLOYMENT_TARGET'],'-isysroot', env['MACOSX_SDK'],'-arch',env['MACOSX_ARCHITECTURE']]+ARCH_FLAGS+env['PLATFORM_LINKFLAGS']
- env['CCFLAGS']=SDK_FLAGS+env['CCFLAGS']
- env['CXXFLAGS']=SDK_FLAGS+env['CXXFLAGS']
-
- #Intel Macs are CoreDuo and Up
- if env['MACOSX_ARCHITECTURE'] == 'i386' or env['MACOSX_ARCHITECTURE'] == 'x86_64':
- env['REL_CCFLAGS'] = env['REL_CCFLAGS']+['-msse','-msse2','-msse3']
- if env['C_COMPILER_ID'] != 'clang' or (env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.3'):
- env['REL_CCFLAGS'] = env['REL_CCFLAGS']+['-ftree-vectorize'] # clang xcode 4 does not accept flag
- else:
- env['CCFLAGS'] = env['CCFLAGS']+['-fno-strict-aliasing']
-
- # Intel 64bit Macs are Core2Duo and up
- if env['MACOSX_ARCHITECTURE'] == 'x86_64':
- env['REL_CCFLAGS'] = env['REL_CCFLAGS']+['-mssse3']
-
- if env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.3':
- env['CCFLAGS'].append('-ftemplate-depth=1024') # only valid for clang bundled with xcode 5
-
- # 3DconnexionClient.framework, optionally install
- if env['WITH_BF_3DMOUSE'] == 1:
- if not os.path.exists('/Library/Frameworks/3DconnexionClient.framework'):
- env['WITH_BF_3DMOUSE'] = 0
- print B.bc.OKGREEN + "3DconnexionClient install not found, disabling WITH_BF_3DMOUSE" # avoid build errors !
- else:
- env.Append(LINKFLAGS=['-F/Library/Frameworks','-Xlinker','-weak_framework','-Xlinker','3DconnexionClient'])
- env['BF_3DMOUSE_INC'] = '/Library/Frameworks/3DconnexionClient.framework/Headers'
- print B.bc.OKGREEN + "Using 3Dconnexion"
-
- # Jackmp.framework, optionally install
- if env['WITH_BF_JACK'] == 1:
- if not os.path.exists('/Library/Frameworks/Jackmp.framework'):
- env['WITH_BF_JACK'] = 0
- print B.bc.OKGREEN + "JackOSX install not found, disabling WITH_BF_JACK" # avoid build errors !
- else:
- env.Append(LINKFLAGS=['-F/Library/Frameworks','-Xlinker','-weak_framework','-Xlinker','Jackmp'])
- print B.bc.OKGREEN + "Using Jack"
-
- if env['WITH_BF_SDL']:
- env.Append(LINKFLAGS=['-lazy_framework','ForceFeedback'])
-
- if env['WITH_BF_QUICKTIME'] == 1:
- env['PLATFORM_LINKFLAGS'] = env['PLATFORM_LINKFLAGS']+['-framework','QTKit']
-
- #Defaults openMP to true if compiler handles it ( only gcc 4.6.1 and newer )
- # if your compiler does not have accurate suffix you may have to enable it by hand !
- if env['WITH_BF_OPENMP'] == 1:
- if env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6.1' or env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.4' and C_VENDOR != 'Apple':
- env['WITH_BF_OPENMP'] = 1 # multithreading for fluids, cloth, sculpt and smoke
- print B.bc.OKGREEN + "Using OpenMP"
- if env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.4':
- OSX_OMP_LIBPATH = Dir(env.subst(env['LCGDIR'])).abspath
- env.Append(BF_PROGRAM_LINKFLAGS=['-L'+OSX_OMP_LIBPATH+'/openmp/lib','-liomp5'])
- env['CCFLAGS'].append('-I'+OSX_OMP_LIBPATH+'/openmp/include') # include for omp.h
- else:
- env['WITH_BF_OPENMP'] = 0
- print B.bc.OKGREEN + "Disabled OpenMP, not supported by compiler"
-
- if env['WITH_BF_CYCLES_OSL'] == 1:
- env['WITH_BF_LLVM'] = 1
- OSX_OSL_LIBPATH = Dir(env.subst(env['BF_OSL_LIBPATH'])).abspath
- # we need 2 variants of passing the oslexec with the force_load option, string and list type atm
- if env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.8' or env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.4':
- env.Append(LINKFLAGS=['-L'+OSX_OSL_LIBPATH,'-loslcomp','-loslexec','-loslquery'])
- else:
- env.Append(LINKFLAGS=['-L'+OSX_OSL_LIBPATH,'-loslcomp','-force_load '+ OSX_OSL_LIBPATH +'/liboslexec.a','-loslquery'])
- env.Append(BF_PROGRAM_LINKFLAGS=['-Xlinker','-force_load','-Xlinker',OSX_OSL_LIBPATH +'/liboslexec.a'])
- else:
- env['WITH_BF_LLVM'] = 0
-
- if env['WITH_BF_LLVM'] == 0:
- # Due duplicated generic UTF functions, we pull them either from LLVMSupport or COLLADA
- env.Append(BF_OPENCOLLADA_LIB=' UTF')
-
- # Trying to get rid of eventually clashes, we export some symbols explicite as local
- env.Append(LINKFLAGS=['-Xlinker','-unexported_symbols_list','-Xlinker','./source/creator/osx_locals.map'])
-
- #for < 10.7.sdk, SystemStubs needs to be linked
- if env['MACOSX_SDK'].endswith("10.6.sdk") or env['MACOSX_SDK'].endswith("10.5.sdk"):
- env['LLIBS'].append('SystemStubs')
-
-#############################################################################
-################### End Automatic configuration for OSX ##################
-#############################################################################
-
-if env['OURPLATFORM'] == 'linux' and not env['C_COMPILER_ID']:
- command = ["%s"%env['CC'], "--version"]
- line = btools.get_command_output(command)
- if line.startswith('gcc'):
- env['C_COMPILER_ID'] = 'gcc'
- elif 'clang' in line[0]:
- env['C_COMPILER_ID'] = 'clang'
-
-if env['WITH_BF_OPENMP'] == 1:
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- env['CCFLAGS'].append('/openmp')
- else:
- if env['CC'].endswith('icc'): # to be able to handle CC=/opt/bla/icc case
- env.Append(LINKFLAGS=['-openmp', '-static-intel'])
- env['CCFLAGS'].append('-openmp')
- else:
- env.Append(CCFLAGS=['-fopenmp'])
-
-if env['WITH_BF_CPP11']:
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- # Nothing special is needed, C++11 features are available by default.
- pass
- else:
- env['CXXFLAGS'].append('-std=c++11')
-
-#check for additional debug libnames
-
-if env.has_key('BF_DEBUG_LIBS'):
- B.quickdebug += env['BF_DEBUG_LIBS']
-
-printdebug = B.arguments.get('BF_LISTDEBUG', 0)
-
-if len(B.quickdebug) > 0 and printdebug != 0:
- print B.bc.OKGREEN + "Buildings these libs with debug symbols:" + B.bc.ENDC
- for l in B.quickdebug:
- print "\t" + l
-
-# remove stdc++ from LLIBS if we are building a statc linked CXXFLAGS
-if env['WITH_BF_STATICCXX']:
- if 'stdc++' in env['LLIBS']:
- env['LLIBS'].remove('stdc++')
- else:
- print '\tcould not remove stdc++ library from LLIBS, WITH_BF_STATICCXX may not work for your platform'
-
-# audaspace is needed for the game engine
-if not env['WITH_BF_AUDASPACE']:
- env['WITH_BF_GAMEENGINE'] = False
-
-# check target for blenderplayer. Set WITH_BF_PLAYER if found on cmdline
-if 'blenderplayer' in B.targets:
- env['WITH_BF_PLAYER'] = True
-
-if 'blendernogame' in B.targets:
- env['WITH_BF_GAMEENGINE'] = False
-
-if not env['WITH_BF_GAMEENGINE']:
- env['WITH_BF_PLAYER'] = False
-
-# build without elbeem (fluidsim)?
-if env['WITH_BF_FLUID'] == 1:
- env['CPPFLAGS'].append('-DWITH_MOD_FLUID')
-
-# build with ocean sim?
-if env['WITH_BF_OCEANSIM'] == 1:
- env['WITH_BF_FFTW3'] = 1 # ocean needs fftw3 so enable it
- env['CPPFLAGS'].append('-DWITH_MOD_OCEANSIM')
-
-
-if btools.ENDIAN == "big":
- env['CPPFLAGS'].append('-D__BIG_ENDIAN__')
-else:
- env['CPPFLAGS'].append('-D__LITTLE_ENDIAN__')
-
-# TODO, make optional (as with CMake)
-env['CPPFLAGS'].append('-DWITH_AVI')
-env['CPPFLAGS'].append('-DWITH_OPENNL')
-
-if env['OURPLATFORM'] not in ('win32-vc', 'win64-vc'):
- env['CPPFLAGS'].append('-DHAVE_STDBOOL_H')
-
-# Audaspace
-
-if env['WITH_BF_AUDASPACE']:
- env['BF_AUDASPACE_C_INC'] = '#intern/audaspace/intern'
- env['BF_AUDASPACE_PY_INC'] = '#intern/audaspace/intern'
- env['BF_AUDASPACE_DEF'] = ['WITH_AUDASPACE']
- env['BF_AUDASPACE_DEF'].append('AUD_DEVICE_H="<AUD_C-API.h>"')
- env['BF_AUDASPACE_DEF'].append('AUD_SPECIAL_H="<AUD_C-API.h>"')
- env['BF_AUDASPACE_DEF'].append('AUD_SOUND_H="<AUD_C-API.h>"')
- env['BF_AUDASPACE_DEF'].append('AUD_HANDLE_H="<AUD_C-API.h>"')
- env['BF_AUDASPACE_DEF'].append('AUD_SEQUENCE_H="<AUD_C-API.h>"')
- env['BF_AUDASPACE_DEF'].append('AUD_TYPES_H="<AUD_Space.h>"')
-
-# OpenGL
-
-if env['WITH_BF_GL_PROFILE_COMPAT']:
- env['BF_GL_DEFINITIONS'].append('WITH_GL_PROFILE_COMPAT')
-
-if env['WITH_BF_GL_PROFILE_CORE']:
- env['BF_GL_DEFINITIONS'].append('WITH_GL_PROFILE_CORE')
-
-if env['WITH_BF_GL_PROFILE_ES20']:
- env['BF_GL_DEFINITIONS'].append('WITH_GL_PROFILE_ES20')
-
-if env['WITH_BF_GL_EGL']:
- env['BF_GL_DEFINITIONS'].append('WITH_EGL')
-
-# GLEW
-
-if env['WITH_BF_GLEW_MX']:
- env['BF_GL_DEFINITIONS'].append('WITH_GLEW_MX')
-
-if env['WITH_BF_GLEW_ES']:
- env['BF_GLEW_INC'] = '#extern/glew-es/include'
-
- env['BF_GL_DEFINITIONS'] += ['GLEW_STATIC', 'WITH_GLEW_ES']
-
- if not env['WITH_BF_GL_PROFILE_ES20']:
- # No ES functions are needed
- env['BF_GL_DEFINITIONS'].append('GLEW_NO_ES')
- elif not (env['WITH_BF_GL_PROFILE_CORE'] or env['WITH_BF_GL_PROFILE_COMPAT']):
- # ES is enabled, but the other functions are all disabled
- env['BF_GL_DEFINITIONS'].append('GLEW_ES_ONLY')
-
- if env['WITH_BF_GL_PROFILE_ES20']:
- if env['WITH_BF_GL_EGL']:
- env['BF_GL_DEFINITIONS'].append('GLEW_USE_LIB_ES20')
-
- if env['WITH_BF_GL_EGL']:
- env['BF_GL_DEFINITIONS'].append('GLEW_INC_EGL')
-
-else:
- env['BF_GLEW_INC'] = '#extern/glew/include'
-
- env['BF_GL_DEFINITIONS'].append('GLEW_STATIC')
-
-# lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir
-B.root_build_dir = env['BF_BUILDDIR']
-B.doc_build_dir = os.path.join(env['BF_INSTALLDIR'], 'doc')
-if not B.root_build_dir[-1]==os.sep:
- B.root_build_dir += os.sep
-if not B.doc_build_dir[-1]==os.sep:
- B.doc_build_dir += os.sep
-
-# We do a shortcut for clean when no quicklist is given: just delete
-# builddir without reading in SConscripts
-do_clean = None
-if 'clean' in B.targets:
- do_clean = True
-
-if not quickie and do_clean:
- if os.path.exists(B.doc_build_dir):
- print B.bc.HEADER+'Cleaning doc dir...'+B.bc.ENDC
- dirs = os.listdir(B.doc_build_dir)
- for entry in dirs:
- if os.path.isdir(B.doc_build_dir + entry) == 1:
- print "clean dir %s"%(B.doc_build_dir+entry)
- shutil.rmtree(B.doc_build_dir+entry)
- else: # remove file
- print "remove file %s"%(B.doc_build_dir+entry)
- os.remove(B.root_build_dir+entry)
- if os.path.exists(B.root_build_dir):
- print B.bc.HEADER+'Cleaning build dir...'+B.bc.ENDC
- dirs = os.listdir(B.root_build_dir)
- for entry in dirs:
- if os.path.isdir(B.root_build_dir + entry) == 1:
- print "clean dir %s"%(B.root_build_dir+entry)
- shutil.rmtree(B.root_build_dir+entry)
- else: # remove file
- print "remove file %s"%(B.root_build_dir+entry)
- os.remove(B.root_build_dir+entry)
- for confile in ['extern/ffmpeg/config.mak', 'extern/x264/config.mak',
- 'extern/xvidcore/build/generic/platform.inc', 'extern/ffmpeg/include']:
- if os.path.exists(confile):
- print "clean file %s"%confile
- if os.path.isdir(confile):
- for root, dirs, files in os.walk(confile):
- for name in files:
- os.remove(os.path.join(root, name))
- else:
- os.remove(confile)
- print B.bc.OKGREEN+'...done'+B.bc.ENDC
- else:
- print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC
- Exit()
-
-
-# ensure python header is found since detection can fail, this could happen
-# with _any_ library but since we used a fixed python version this tends to
-# be most problematic.
-if env['WITH_BF_PYTHON']:
- found_python_h = found_pyconfig_h = False
- for bf_python_inc in env.subst('${BF_PYTHON_INC}').split():
- py_h = os.path.join(Dir(bf_python_inc).abspath, "Python.h")
- if os.path.exists(py_h):
- found_python_h = True
- py_h = os.path.join(Dir(bf_python_inc).abspath, "pyconfig.h")
- if os.path.exists(py_h):
- found_pyconfig_h = True
-
- if not (found_python_h and found_pyconfig_h):
- print("""\nMissing: Python.h and/or pyconfig.h in "%s"
- Set 'BF_PYTHON_INC' to point to valid include path(s),
- containing Python.h and pyconfig.h for Python version "%s".
-
- Example: python scons/scons.py BF_PYTHON_INC=../Python/include
- """ % (env.subst('${BF_PYTHON_INC}'), env.subst('${BF_PYTHON_VERSION}')))
- Exit()
-
-
-if not os.path.isdir ( B.root_build_dir):
- os.makedirs ( B.root_build_dir )
- os.makedirs ( B.root_build_dir + 'source' )
- os.makedirs ( B.root_build_dir + 'intern' )
- os.makedirs ( B.root_build_dir + 'extern' )
- os.makedirs ( B.root_build_dir + 'lib' )
- os.makedirs ( B.root_build_dir + 'bin' )
-# # Docs not working with epy anymore
-# if not os.path.isdir(B.doc_build_dir) and env['WITH_BF_DOCS']:
-# os.makedirs ( B.doc_build_dir )
-
-
-###################################
-# Ensure all data files are valid #
-###################################
-if not os.path.isdir ( B.root_build_dir + 'data_headers'):
- os.makedirs ( B.root_build_dir + 'data_headers' )
-if not os.path.isdir ( B.root_build_dir + 'data_sources'):
- os.makedirs ( B.root_build_dir + 'data_sources' )
-# use for includes
-env['DATA_HEADERS'] = os.path.join(os.path.abspath(env['BF_BUILDDIR']), "data_headers")
-env['DATA_SOURCES'] = os.path.join(os.path.abspath(env['BF_BUILDDIR']), "data_sources")
-def data_to_c(FILE_FROM, FILE_TO, VAR_NAME):
- if os.sep == "\\":
- FILE_FROM = FILE_FROM.replace("/", "\\")
- FILE_TO = FILE_TO.replace("/", "\\")
-
- try:
- # first check if we need to bother.
- if os.path.exists(FILE_TO):
- if os.path.getmtime(FILE_FROM) < os.path.getmtime(FILE_TO):
- return
-
- print(B.bc.HEADER + "Generating: " + B.bc.ENDC + "%r" % os.path.basename(FILE_TO))
- fpin = open(FILE_FROM, "rb")
- fpin.seek(0, os.SEEK_END)
- size = fpin.tell()
- fpin.seek(0)
-
- fpout = open(FILE_TO, "w")
- fpout.write("int %s_size = %d;\n" % (VAR_NAME, size))
- fpout.write("char %s[] = {\n" % VAR_NAME)
-
- while size > 0:
- size -= 1
- if size % 32 == 31:
- fpout.write("\n")
-
- fpout.write("%3d," % ord(fpin.read(1)))
- fpout.write("\n 0};\n\n")
-
- fpin.close()
- fpout.close()
- except KeyboardInterrupt:
- if os.path.exists(FILE_TO):
- os.remove(FILE_TO)
- raise KeyboardInterrupt
-
-def data_to_c_simple(FILE_FROM):
- filename_only = os.path.basename(FILE_FROM)
- FILE_TO = os.path.join(env['DATA_SOURCES'], filename_only + ".c")
- VAR_NAME = "datatoc_" + filename_only.replace(".", "_")
-
- data_to_c(FILE_FROM, FILE_TO, VAR_NAME)
-
-
-def data_to_c_simple_icon(PATH_FROM):
-
- # first handle import
- import sys
- path = "source/blender/datatoc"
- if path not in sys.path:
- sys.path.append(path)
-
- # convert the pixmaps to a png
- import datatoc_icon
-
- filename_only = os.path.basename(PATH_FROM)
- FILE_TO_PNG = os.path.join(env['DATA_SOURCES'], filename_only + ".png")
- FILE_TO = FILE_TO_PNG + ".c"
- argv = [PATH_FROM, FILE_TO_PNG]
- try:
- datatoc_icon.main_ex(argv)
- except KeyboardInterrupt:
- if os.path.exists(FILE_TO_PNG):
- os.remove(FILE_TO_PNG)
- raise KeyboardInterrupt
-
- # then the png to a c file
- data_to_c_simple(FILE_TO_PNG)
-
-
-if B.targets != ['cudakernels']:
- data_to_c("source/blender/compositor/operations/COM_OpenCLKernels.cl",
- B.root_build_dir + "data_headers/COM_OpenCLKernels.cl.h",
- "datatoc_COM_OpenCLKernels_cl")
-
- data_to_c_simple("release/datafiles/startup.blend")
- data_to_c_simple("release/datafiles/preview.blend")
- data_to_c_simple("release/datafiles/preview_cycles.blend")
-
- # --- glsl ---
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_geometry.glsl")
-
- data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl")
-
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_vert.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_material.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_material.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vertex.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vertex_world.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vsm_store_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_vert.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_hq_frag.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_hq_vert.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_lib.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_depth_resolve.glsl")
- data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fx_vert.glsl")
- data_to_c_simple("intern/opencolorio/gpu_shader_display_transform.glsl")
- data_to_c_simple("intern/opensubdiv/gpu_shader_opensubd_display.glsl")
-
- # --- blender ---
- data_to_c_simple("release/datafiles/bfont.pfb")
- data_to_c_simple("release/datafiles/bfont.ttf")
- data_to_c_simple("release/datafiles/bmonofont.ttf")
-
- data_to_c_simple("release/datafiles/splash.png")
- data_to_c_simple("release/datafiles/splash_2x.png")
-
- # data_to_c_simple("release/datafiles/blender_icons16.png")
- # data_to_c_simple("release/datafiles/blender_icons32.png")
- data_to_c_simple_icon("release/datafiles/blender_icons16")
- data_to_c_simple_icon("release/datafiles/blender_icons32")
-
- data_to_c_simple("release/datafiles/prvicons.png")
-
- data_to_c_simple("release/datafiles/brushicons/add.png")
- data_to_c_simple("release/datafiles/brushicons/blob.png")
- data_to_c_simple("release/datafiles/brushicons/blur.png")
- data_to_c_simple("release/datafiles/brushicons/clay.png")
- data_to_c_simple("release/datafiles/brushicons/claystrips.png")
- data_to_c_simple("release/datafiles/brushicons/clone.png")
- data_to_c_simple("release/datafiles/brushicons/crease.png")
- data_to_c_simple("release/datafiles/brushicons/darken.png")
- data_to_c_simple("release/datafiles/brushicons/draw.png")
- data_to_c_simple("release/datafiles/brushicons/fill.png")
- data_to_c_simple("release/datafiles/brushicons/flatten.png")
- data_to_c_simple("release/datafiles/brushicons/grab.png")
- data_to_c_simple("release/datafiles/brushicons/inflate.png")
- data_to_c_simple("release/datafiles/brushicons/layer.png")
- data_to_c_simple("release/datafiles/brushicons/lighten.png")
- data_to_c_simple("release/datafiles/brushicons/mask.png")
- data_to_c_simple("release/datafiles/brushicons/mix.png")
- data_to_c_simple("release/datafiles/brushicons/multiply.png")
- data_to_c_simple("release/datafiles/brushicons/nudge.png")
- data_to_c_simple("release/datafiles/brushicons/pinch.png")
- data_to_c_simple("release/datafiles/brushicons/scrape.png")
- data_to_c_simple("release/datafiles/brushicons/smear.png")
- data_to_c_simple("release/datafiles/brushicons/smooth.png")
- data_to_c_simple("release/datafiles/brushicons/snake_hook.png")
- data_to_c_simple("release/datafiles/brushicons/soften.png")
- data_to_c_simple("release/datafiles/brushicons/subtract.png")
- data_to_c_simple("release/datafiles/brushicons/texdraw.png")
- data_to_c_simple("release/datafiles/brushicons/texfill.png")
- data_to_c_simple("release/datafiles/brushicons/texmask.png")
- data_to_c_simple("release/datafiles/brushicons/thumb.png")
- data_to_c_simple("release/datafiles/brushicons/twist.png")
- data_to_c_simple("release/datafiles/brushicons/vertexdraw.png")
-
- data_to_c_simple("release/datafiles/matcaps/mc01.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc02.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc03.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc04.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc05.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc06.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc07.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc08.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc09.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc10.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc11.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc12.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc13.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc14.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc15.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc16.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc17.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc18.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc19.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc20.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc21.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc22.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc23.jpg")
- data_to_c_simple("release/datafiles/matcaps/mc24.jpg")
-
-##### END DATAFILES ##########
-
-Help(opts.GenerateHelpText(env))
-
-# default is new quieter output, but if you need to see the
-# commands, do 'scons BF_QUIET=0'
-bf_quietoutput = B.arguments.get('BF_QUIET', '1')
-if env['BF_QUIET']:
- B.set_quiet_output(env)
-else:
- if toolset=='msvc':
- B.msvc_hack(env)
-
-print B.bc.HEADER+'Building in: ' + B.bc.ENDC + os.path.abspath(B.root_build_dir)
-env.SConsignFile(B.root_build_dir+'scons-signatures')
-B.init_lib_dict()
-
-##### END SETUP ##########
-
-## Auto-configuration run-time tests
-
-from FindSharedPtr import FindSharedPtr
-from FindUnorderedMap import FindUnorderedMap
-
-conf = Configure(env)
-old_linkflags = conf.env['LINKFLAGS']
-conf.env.Append(LINKFLAGS=env['PLATFORM_LINKFLAGS'])
-
-# Put all tests here
-FindSharedPtr(conf)
-FindUnorderedMap(conf)
-
-conf.env['LINKFLAGS'] = old_linkflags
-env = conf.Finish()
-
-# End of auto configuration
-
-Export('env')
-
-VariantDir(B.root_build_dir+'/source', 'source', duplicate=0)
-SConscript(B.root_build_dir+'/source/SConscript')
-VariantDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
-SConscript(B.root_build_dir+'/intern/SConscript')
-VariantDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
-SConscript(B.root_build_dir+'/extern/SConscript')
-
-# now that we have read all SConscripts, we know what
-# libraries will be built. Create list of
-# libraries to give as objects to linking phase
-mainlist = []
-for tp in B.possible_types:
- if (not tp == 'player') and (not tp == 'player2') and (not tp == 'system'):
- mainlist += B.create_blender_liblist(env, tp)
-
-if B.arguments.get('BF_PRIORITYLIST', '0')=='1':
- B.propose_priorities()
-
-dobj = B.buildinfo(env, "dynamic") + B.resources
-creob = B.creator(env)
-thestatlibs, thelibincs = B.setup_staticlibs(env)
-thesyslibs = B.setup_syslibs(env)
-
-if 'blender' in B.targets or not env['WITH_BF_NOBLENDER']:
- blender_progname = "blender"
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
- blender_progname = "blender-app"
-
- lenv = env.Clone()
- lenv.Append(LINKFLAGS = env['PLATFORM_LINKFLAGS'])
- targetpath = B.root_build_dir + '/blender'
- launcher_obj = [env.Object(B.root_build_dir + 'source/creator/creator/creator_launch_win', ['#source/creator/creator_launch_win.c'])]
- env.BlenderProg(B.root_build_dir, 'blender', [launcher_obj] + B.resources, ['bf_utfconv'] + thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
-
- env.BlenderProg(B.root_build_dir, blender_progname, creob + mainlist + thestatlibs + dobj, thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blender')
-if env['WITH_BF_PLAYER']:
- playerlist = B.create_blender_liblist(env, 'player')
- playerlist += B.create_blender_liblist(env, 'player2')
- playerlist += B.create_blender_liblist(env, 'intern')
- playerlist += B.create_blender_liblist(env, 'extern')
- env.BlenderProg(B.root_build_dir, "blenderplayer", dobj + playerlist + thestatlibs, thesyslibs, [B.root_build_dir+'/lib'] + thelibincs, 'blenderplayer')
-
-##### Now define some targets
-
-
-#------------ INSTALL
-
-#-- binaries
-blenderinstall = []
-if env['OURPLATFORM']=='darwin':
- for prg in B.program_list:
- bundle = '%s.app' % prg[0]
- bundledir = os.path.dirname(bundle)
- for dp, dn, df in os.walk(bundle):
- if '.svn' in dn:
- dn.remove('.svn')
- if '_svn' in dn:
- dn.remove('_svn')
- if '.git' in df:
- df.remove('.git')
- dir=env['BF_INSTALLDIR']+dp[len(bundledir):]
- source=[dp+os.sep+f for f in df]
- blenderinstall.append(env.Install(dir=dir,source=source))
-else:
- blenderinstall = env.Install(dir=env['BF_INSTALLDIR'], source=B.program_list)
-
-#-- local path = config files in install dir: installdir\VERSION
-#- dont do config and scripts for darwin, it is already in the bundle
-dotblendlist = []
-datafileslist = []
-datafilestargetlist = []
-dottargetlist = []
-scriptinstall = []
-cubininstall = []
-
-if env['OURPLATFORM']!='darwin':
- dotblenderinstall = []
- for targetdir,srcfile in zip(dottargetlist, dotblendlist):
- td, tf = os.path.split(targetdir)
- dotblenderinstall.append(env.Install(dir=td, source=srcfile))
- for targetdir,srcfile in zip(datafilestargetlist, datafileslist):
- td, tf = os.path.split(targetdir)
- dotblenderinstall.append(env.Install(dir=td, source=srcfile))
-
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
- scriptinstall.append(env.InstallAs(env['BF_INSTALLDIR'] + '/blender-app.exe.manifest',
- 'source/icons/blender.exe.manifest'))
-
- if env['WITH_BF_PYTHON']:
- #-- local/VERSION/scripts
- scriptpaths=['release/scripts']
- for scriptpath in scriptpaths:
- for dp, dn, df in os.walk(scriptpath):
- if '.git' in df:
- df.remove('.git')
- if '__pycache__' in dn: # py3.2 cache dir
- dn.remove('__pycache__')
-
- # only for testing builds
- if VERSION_RELEASE_CYCLE == "release" and "addons_contrib" in dn:
- dn.remove('addons_contrib')
-
- # do not install freestyle if disabled
- if not env['WITH_BF_FREESTYLE'] and "freestyle" in dn:
- dn.remove("freestyle")
-
- dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
- dir += os.sep + os.path.basename(scriptpath) + dp[len(scriptpath):]
-
- source=[os.path.join(dp, f) for f in df if not f.endswith(".pyc")]
- # To ensure empty dirs are created too
- if len(source)==0 and not os.path.exists(dir):
- env.Execute(Mkdir(dir))
- scriptinstall.append(env.Install(dir=dir,source=source))
- if env['WITH_BF_CYCLES']:
- # cycles python code
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles')
- source=os.listdir('intern/cycles/blender/addon')
- if '__pycache__' in source: source.remove('__pycache__')
- source=['intern/cycles/blender/addon/'+s for s in source]
- scriptinstall.append(env.Install(dir=dir,source=source))
-
- # cycles kernel code
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel')
- source=os.listdir('intern/cycles/kernel')
- if '__pycache__' in source: source.remove('__pycache__')
- source.remove('CMakeLists.txt')
- source.remove('SConscript')
- source.remove('svm')
- source.remove('closure')
- source.remove('geom')
- source.remove('shaders')
- source.remove('osl')
- source.remove('split')
- source=['intern/cycles/kernel/'+s for s in source]
- source.append('intern/cycles/util/util_atomic.h')
- source.append('intern/cycles/util/util_color.h')
- source.append('intern/cycles/util/util_half.h')
- source.append('intern/cycles/util/util_math.h')
- source.append('intern/cycles/util/util_math_fast.h')
- source.append('intern/cycles/util/util_transform.h')
- source.append('intern/cycles/util/util_types.h')
- scriptinstall.append(env.Install(dir=dir,source=source))
- # svm
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'svm')
- source=os.listdir('intern/cycles/kernel/svm')
- if '__pycache__' in source: source.remove('__pycache__')
- source=['intern/cycles/kernel/svm/'+s for s in source]
- scriptinstall.append(env.Install(dir=dir,source=source))
- # closure
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'closure')
- source=os.listdir('intern/cycles/kernel/closure')
- if '__pycache__' in source: source.remove('__pycache__')
- source=['intern/cycles/kernel/closure/'+s for s in source]
- scriptinstall.append(env.Install(dir=dir,source=source))
- # geom
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'geom')
- source=os.listdir('intern/cycles/kernel/geom')
- if '__pycache__' in source: source.remove('__pycache__')
- source=['intern/cycles/kernel/geom/'+s for s in source]
- scriptinstall.append(env.Install(dir=dir,source=source))
- # split
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'split')
- source=os.listdir('intern/cycles/kernel/split')
- if '__pycache__' in source: source.remove('__pycache__')
- source=['intern/cycles/kernel/split/'+s for s in source]
- scriptinstall.append(env.Install(dir=dir,source=source))
-
- # licenses
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'license')
- source=os.listdir('intern/cycles/doc/license')
- if '__pycache__' in source: source.remove('__pycache__')
- source.remove('CMakeLists.txt')
- source=['intern/cycles/doc/license/'+s for s in source]
- scriptinstall.append(env.Install(dir=dir,source=source))
-
- if env['WITH_BF_CYCLES']:
- # cuda binaries
- if env['WITH_BF_CYCLES_CUDA_BINARIES']:
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'lib')
- for arch in env['BF_CYCLES_CUDA_BINARIES_ARCH']:
- kernel_build_dir = os.path.join(B.root_build_dir, 'intern/cycles/kernel')
- for suffix in ('', '_experimental'):
- cubin_file = os.path.join(kernel_build_dir, "kernel%s_%s.cubin" % (suffix, arch))
- cubininstall.append(env.Install(dir=dir,source=cubin_file))
-
- # osl shaders
- if env['WITH_BF_CYCLES_OSL']:
- dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'shader')
-
- osl_source_dir = Dir('./intern/cycles/kernel/shaders').srcnode().path
- oso_build_dir = os.path.join(B.root_build_dir, 'intern/cycles/kernel/shaders')
-
- headers='node_color.h node_fresnel.h node_texture.h oslutil.h stdosl.h'.split()
- source=['intern/cycles/kernel/shaders/'+s for s in headers]
- scriptinstall.append(env.Install(dir=dir,source=source))
-
- for f in os.listdir(osl_source_dir):
- if f.endswith('.osl'):
- oso_file = os.path.join(oso_build_dir, f.replace('.osl', '.oso'))
- scriptinstall.append(env.Install(dir=dir,source=oso_file))
-
- if env['WITH_BF_OCIO']:
- colormanagement = os.path.join('release', 'datafiles', 'colormanagement')
-
- for dp, dn, df in os.walk(colormanagement):
- dir = os.path.join(env['BF_INSTALLDIR'], VERSION, 'datafiles')
- dir += os.sep + os.path.basename(colormanagement) + dp[len(colormanagement):]
-
- source = [os.path.join(dp, f) for f in df if not f.endswith(".pyc")]
-
- # To ensure empty dirs are created too
- if len(source) == 0:
- env.Execute(Mkdir(dir))
-
- scriptinstall.append(env.Install(dir=dir,source=source))
-
- if env['WITH_BF_INTERNATIONAL']:
- internationalpaths=['release' + os.sep + 'datafiles']
-
- def check_path(path, member):
- return (member in path.split(os.sep))
-
- po_dir = os.path.join("release", "datafiles", "locale", "po")
-
- # font files
- for intpath in internationalpaths:
- for dp, dn, df in os.walk(intpath):
- if '.git' in df:
- df.remove('.git')
-
- # we only care about release/datafiles/fonts, release/datafiles/locales
- if check_path(dp, "fonts"):
- pass
- else:
- continue
-
- dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
- dir += os.sep + os.path.basename(intpath) + dp[len(intpath):]
-
- source=[os.path.join(dp, f) for f in df if not f.endswith(".pyc")]
- # To ensure empty dirs are created too
- if len(source)==0:
- env.Execute(Mkdir(dir))
- scriptinstall.append(env.Install(dir=dir,source=source))
-
- # .mo files
- for f in os.listdir(po_dir):
- if not f.endswith(".po"):
- continue
-
- locale_name = os.path.splitext(f)[0]
-
- mo_file = os.path.join(B.root_build_dir, "locale", locale_name + ".mo")
-
- dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
- dir = os.path.join(dir, "datafiles", "locale", locale_name, "LC_MESSAGES")
- scriptinstall.append(env.InstallAs(os.path.join(dir, "blender.mo"), mo_file))
-
- # languages file
- dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
- dir = os.path.join(dir, "datafiles", "locale")
- languages_file = os.path.join("release", "datafiles", "locale", "languages")
- scriptinstall.append(env.InstallAs(os.path.join(dir, "languages"), languages_file))
-
-#-- icons
-if env['OURPLATFORM']=='linux':
- iconlist = []
- icontargetlist = []
-
- for tp, tn, tf in os.walk('release/freedesktop/icons'):
- for f in tf:
- iconlist.append(os.path.join(tp, f))
- icontargetlist.append( os.path.join(*([env['BF_INSTALLDIR']] + tp.split(os.sep)[2:] + [f])) )
-
- iconinstall = []
- for targetdir,srcfile in zip(icontargetlist, iconlist):
- td, tf = os.path.split(targetdir)
- iconinstall.append(env.Install(dir=td, source=srcfile))
-
- scriptinstall.append(env.Install(dir=env['BF_INSTALLDIR'], source='release/bin/blender-thumbnailer.py'))
-
-# dlls for linuxcross
-# TODO - add more libs, for now this lets blenderlite run
-if env['OURPLATFORM']=='linuxcross':
- dir=env['BF_INSTALLDIR']
- source = []
-
- if env['WITH_BF_OPENMP']:
- source += ['../lib/windows/pthreads/lib/pthreadGC2.dll']
-
- scriptinstall.append(env.Install(dir=dir, source=source))
-
-textlist = []
-texttargetlist = []
-for tp, tn, tf in os.walk('release/text'):
- tf.remove("readme.html")
- for f in tf:
- textlist.append(tp+os.sep+f)
-
-def readme_version_patch():
- readme_src = "release/text/readme.html"
- readme_dst = os.path.abspath(os.path.normpath(os.path.join(env['BF_BUILDDIR'], "readme.html")))
-
- if not os.path.exists(readme_dst) or (os.path.getmtime(readme_dst) < os.path.getmtime(readme_src)):
- f = open(readme_src, "r")
- data = f.read()
- f.close()
-
- data = data.replace("BLENDER_VERSION", VERSION)
- f = open(readme_dst, "w")
- f.write(data)
- f.close()
-
- textlist.append(readme_dst)
-
-readme_version_patch()
-del readme_version_patch
-
-
-'''Command(
- "release/text/readme.html"
-
- )
-Command("file.out", "file.in", Copy(env['BF_INSTALLDIR'], "release/text/readme.html"))
-'''
-
-# Font licenses
-textlist.append('release/datafiles/LICENSE-bfont.ttf.txt')
-if env['WITH_BF_INTERNATIONAL']:
- textlist += ['release/datafiles/LICENSE-droidsans.ttf.txt', 'release/datafiles/LICENSE-bmonofont-i18n.ttf.txt']
-
-textinstall = env.Install(dir=env['BF_INSTALLDIR'], source=textlist)
-
-if env['OURPLATFORM']=='darwin':
- allinstall = [blenderinstall, textinstall]
-elif env['OURPLATFORM']=='linux':
- allinstall = [blenderinstall, dotblenderinstall, scriptinstall, textinstall, iconinstall, cubininstall]
-else:
- allinstall = [blenderinstall, dotblenderinstall, scriptinstall, textinstall, cubininstall]
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
- dllsources = []
-
- # Used when linking to libtiff was dynamic
- # keep it here until compilation on all platform would be ok
- # dllsources += ['${BF_TIFF_LIBPATH}/${BF_TIFF_LIB}.dll']
-
- if env['OURPLATFORM'] != 'linuxcross':
- # pthreads library is already added
- dllsources += ['${BF_PTHREADS_LIBPATH}/${BF_PTHREADS_LIB}.dll']
-
- if env['WITH_BF_SDL']:
- dllsources.append('${BF_SDL_LIBPATH}/SDL2.dll')
-
- if env['WITH_BF_PYTHON']:
- if env['BF_DEBUG']:
- dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}_d.dll')
- dllsources.append('${BF_PYTHON_LIBPATH}/sqlite3_d.dll')
- else:
- dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}.dll')
- dllsources.append('${BF_PYTHON_LIBPATH}/sqlite3.dll')
-
- if env['WITH_BF_ICONV']:
- if env['OURPLATFORM'] == 'win64-vc':
- pass # we link statically to iconv on win64
- elif not env['OURPLATFORM'] in ('win32-mingw', 'linuxcross'):
- #gettext for MinGW and cross-compilation is compiled staticly
- dllsources += ['${BF_ICONV_LIBPATH}/iconv.dll']
-
- if env['WITH_BF_OPENAL']:
- dllsources.append('${LCGDIR}/openal/lib/OpenAL32.dll')
-
- if env['WITH_BF_SNDFILE']:
- dllsources.append('${LCGDIR}/sndfile/lib/libsndfile-1.dll')
-
- if env['WITH_BF_FFMPEG']:
- dllsources += env['BF_FFMPEG_DLL'].split()
-
- # Since the thumb handler is loaded by Explorer, architecture is
- # strict: the x86 build fails on x64 Windows. We need to ship
- # both builds in x86 packages.
- if B.bitness == 32:
- dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb.dll')
- dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb64.dll')
-
- if env['WITH_BF_OCIO']:
- if not env['OURPLATFORM'] in ('win32-mingw', 'linuxcross'):
- dllsources.append('${LCGDIR}/opencolorio/bin/OpenColorIO.dll')
-
- else:
- dllsources.append('${LCGDIR}/opencolorio/bin/libOpenColorIO.dll')
-
- dllsources.append('#source/icons/blender.exe.manifest')
-
- windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
- allinstall += windlls
-
- # TODO(sergey): For unti we've got better way to deal with python binary
- if env['WITH_BF_PYTHON']:
- py_target = os.path.join(env['BF_INSTALLDIR'], VERSION, 'python', 'bin')
- if env['BF_DEBUG']:
- allinstall += env.Install(dir=py_target, source = ['${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}_d.dll'])
- else:
- allinstall += env.Install(dir=py_target, source = ['${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}.dll'])
-
-
-if env['OURPLATFORM'] == 'win64-mingw':
- dllsources = []
-
- if env['WITH_BF_PYTHON']:
- if env['BF_DEBUG']:
- dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}_d.dll')
- else:
- dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}.dll')
-
- if env['WITH_BF_FFMPEG']:
- dllsources += env['BF_FFMPEG_DLL'].split()
-
- if env['WITH_BF_OPENAL']:
- dllsources.append('${LCGDIR}/openal/lib/OpenAL32.dll')
- dllsources.append('${LCGDIR}/openal/lib/wrap_oal.dll')
-
- if env['WITH_BF_SNDFILE']:
- dllsources.append('${LCGDIR}/sndfile/lib/libsndfile-1.dll')
-
- if env['WITH_BF_SDL']:
- dllsources.append('${LCGDIR}/sdl/lib/SDL.dll')
-
- if(env['WITH_BF_OPENMP']):
- dllsources.append('${LCGDIR}/binaries/libgomp-1.dll')
-
- if env['WITH_BF_OCIO']:
- dllsources.append('${LCGDIR}/opencolorio/bin/libOpenColorIO.dll')
-
- dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb64.dll')
- dllsources.append('${LCGDIR}/binaries/libgcc_s_sjlj-1.dll')
- dllsources.append('${LCGDIR}/binaries/libwinpthread-1.dll')
- dllsources.append('${LCGDIR}/binaries/libstdc++-6.dll')
- dllsources.append('#source/icons/blender.exe.manifest')
-
- windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
- allinstall += windlls
-
-installtarget = env.Alias('install', allinstall)
-bininstalltarget = env.Alias('install-bin', blenderinstall)
-
-nsisaction = env.Action(btools.NSIS_Installer, btools.NSIS_print)
-nsiscmd = env.Command('nsisinstaller', None, nsisaction)
-nsisalias = env.Alias('nsis', nsiscmd)
-
-if 'blender' in B.targets:
- blenderexe= env.Alias('blender', B.program_list)
- Depends(blenderexe,installtarget)
-
-if env['WITH_BF_PLAYER']:
- blenderplayer = env.Alias('blenderplayer', B.program_list)
- Depends(blenderplayer,installtarget)
-
-if not env['WITH_BF_GAMEENGINE']:
- blendernogame = env.Alias('blendernogame', B.program_list)
- Depends(blendernogame,installtarget)
-
-if 'blenderlite' in B.targets:
- blenderlite = env.Alias('blenderlite', B.program_list)
- Depends(blenderlite,installtarget)
-
-Depends(nsiscmd, allinstall)
-
-buildslave_action = env.Action(btools.buildslave, btools.buildslave_print)
-buildslave_cmd = env.Command('buildslave_exec', None, buildslave_action)
-buildslave_alias = env.Alias('buildslave', buildslave_cmd)
-
-Depends(buildslave_cmd, allinstall)
-
-cudakernels_action = env.Action(btools.cudakernels, btools.cudakernels_print)
-cudakernels_cmd = env.Command('cudakernels_exec', None, cudakernels_action)
-cudakernels_alias = env.Alias('cudakernels', cudakernels_cmd)
-
-cudakernel_dir = os.path.join(os.path.abspath(os.path.normpath(B.root_build_dir)), 'intern/cycles/kernel')
-cuda_kernels = []
-
-for x in env['BF_CYCLES_CUDA_BINARIES_ARCH']:
- cubin = os.path.join(cudakernel_dir, 'kernel_' + x + '.cubin')
- cuda_kernels.append(cubin)
-
-Depends(cudakernels_cmd, cuda_kernels)
-Depends(cudakernels_cmd, cubininstall)
-
-Default(B.program_list)
-
-if not env['WITHOUT_BF_INSTALL']:
- Default(installtarget)
-
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 5a6aa5ca63e..de54ecbd946 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -25,16 +25,22 @@
ARGS=$( \
getopt \
-o s:i:t:h \
---long source:,install:,tmp:,info:,threads:,help,no-sudo,with-all,with-opencollada,\
-ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,\
-force-all,force-python,force-numpy,force-boost,force-ocio,force-oiio,force-llvm,force-osl,force-osd,\
+--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-confirm,with-all,with-opencollada,\
+ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
+force-all,force-python,force-numpy,force-boost,\
+force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
force-ffmpeg,force-opencollada,\
-skip-python,skip-numpy,skip-boost,skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,\
-skip-ffmpeg,skip-opencollada,\
-required-numpy: \
+build-all,build-python,build-numpy,build-boost,\
+build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
+build-ffmpeg,build-opencollada,\
+skip-python,skip-numpy,skip-boost,\
+skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
+skip-ffmpeg,skip-opencollada \
-- "$@" \
)
+COMMANDLINE=$@
+
DISTRO=""
RPM=""
SRC="$HOME/src/blender-deps"
@@ -42,6 +48,7 @@ INST="/opt/lib"
TMP="/tmp"
CWD=$PWD
INFO_PATH=$CWD
+SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# Do not install some optional, potentially conflicting libs by default...
WITH_ALL=false
@@ -69,6 +76,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
-h, --help
Show this message and exit.
+ --show-deps
+ Show main dependencies of Blender (including officially supported versions) and exit.
+
-s <path>, --source=<path>
Use a specific path where to store downloaded libraries sources (defaults to '\$SRC').
@@ -87,6 +97,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--no-sudo
Disable use of sudo (this script won't be able to do much though, will just print needed packages...).
+ --no-confirm
+ Disable any interaction with user (suitable for automated run).
+
--with-all
By default, a number of optional and not-so-often needed libraries are not installed.
This option will try to install them, at the cost of potential conflicts (depending on
@@ -108,10 +121,65 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--ver-osl=<ver>
Force version of OSL library.
+ --ver-osd=<ver>
+ Force version of OSD library.
+
+ --ver-openvdb=<ver>
+ Force version of OpenVDB library.
+
Note about the --ver-foo options:
It may not always work as expected (some libs are actually checked out from a git rev...), yet it might help
to fix some build issues (like LLVM mismatch with the version used by your graphic system).
+ --build-all
+ Force the build of all possible libraries.
+
+ --build-python
+ Force the build of Python.
+
+ --build-numpy
+ Force the build of NumPy.
+
+ --build-boost
+ Force the build of Boost.
+
+ --build-ocio
+ Force the build of OpenColorIO.
+
+ --build-openexr
+ Force the build of OpenEXR.
+
+ --build-oiio
+ Force the build of OpenImageIO.
+
+ --build-llvm
+ Force the build of LLVM.
+
+ --build-osl
+ Force the build of OpenShadingLanguage.
+
+ --build-osd
+ Force the build of OpenSubdiv.
+
+ --build-openvdb
+ Force the build of OpenVDB.
+
+ --build-opencollada
+ Force the build of OpenCOLLADA.
+
+ --build-ffmpeg
+ Force the build of FFMpeg.
+
+ Note about the --build-foo options:
+ * They force the script to prefer building dependencies rather than using available packages.
+ This may make things simpler and allow working around some distribution bugs, but on the other hand it will
+ use much more space on your hard drive.
+ * Please be careful with the Blender building options if you have both 'official' dev packages and
+ install_deps' built ones on your system, by default CMake will prefer official packages, which may lead to
+ linking issues. Please ensure your CMake configuration always uses all correct library paths.
+ * If the “force-built” library is a dependency of others, it will force the build
+ of those libraries as well (e.g. --build-boost also implies --build-oiio and --build-osl...).
+
--force-all
Force the rebuild of all built libraries.
@@ -142,6 +210,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-osd
Force the rebuild of OpenSubdiv.
+ --force-openvdb
+ Force the rebuild of OpenVDB.
+
--force-opencollada
Force the rebuild of OpenCOLLADA.
@@ -181,78 +252,102 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--skip-osd
Unconditionally skip OpenSubdiv installation/building.
+ --skip-openvdb
+ Unconditionally skip OpenVDB installation/building.
+
--skip-opencollada
Unconditionally skip OpenCOLLADA installation/building.
--skip-ffmpeg
- Unconditionally skip FFMpeg installation/building.
-
- --required-numpy
- Use this in case your distro features a valid python package, but no matching Numpy one.
- It will force compilation of both python and numpy\""
+ Unconditionally skip FFMpeg installation/building.\""
##### Main Vars #####
+DO_SHOW_DEPS=false
+
SUDO="sudo"
-PYTHON_VERSION="3.4.0"
-PYTHON_VERSION_MIN="3.4"
+NO_CONFIRM=false
+
+PYTHON_VERSION="3.5.1"
+PYTHON_VERSION_MIN="3.5"
+PYTHON_FORCE_BUILD=false
PYTHON_FORCE_REBUILD=false
PYTHON_SKIP=false
-NUMPY_VERSION="1.8.1"
+NUMPY_VERSION="1.10.1"
NUMPY_VERSION_MIN="1.8"
+NUMPY_FORCE_BUILD=false
NUMPY_FORCE_REBUILD=false
NUMPY_SKIP=false
-NUMPY_REQUIRED=false
-BOOST_VERSION="1.51.0"
+BOOST_VERSION="1.60.0"
BOOST_VERSION_MIN="1.49"
+BOOST_FORCE_BUILD=false
BOOST_FORCE_REBUILD=false
BOOST_SKIP=false
OCIO_VERSION="1.0.9"
OCIO_VERSION_MIN="1.0"
+OCIO_FORCE_BUILD=false
OCIO_FORCE_REBUILD=false
OCIO_SKIP=false
OPENEXR_VERSION="2.2.0"
OPENEXR_VERSION_MIN="2.0.1"
ILMBASE_VERSION="2.2.0"
+ILMBASE_VERSION_MIN="2.2"
+OPENEXR_FORCE_BUILD=false
OPENEXR_FORCE_REBUILD=false
OPENEXR_SKIP=false
_with_built_openexr=false
-OIIO_VERSION="1.4.16"
-OIIO_VERSION_MIN="1.4.0"
+OIIO_VERSION="1.6.9"
+OIIO_VERSION_MIN="1.6.0"
+OIIO_VERSION_MAX="1.9.0" # UNKNOWN currently # Not supported by current OSL...
+OIIO_FORCE_BUILD=false
OIIO_FORCE_REBUILD=false
OIIO_SKIP=false
LLVM_VERSION="3.4"
LLVM_VERSION_MIN="3.4"
LLVM_VERSION_FOUND=""
+LLVM_FORCE_BUILD=false
LLVM_FORCE_REBUILD=false
LLVM_SKIP=false
# OSL needs to be compiled for now!
-OSL_VERSION="1.5.11"
+OSL_VERSION="1.7.1"
OSL_VERSION_MIN=$OSL_VERSION
+OSL_FORCE_BUILD=false
OSL_FORCE_REBUILD=false
OSL_SKIP=false
# OpenSubdiv needs to be compiled for now
OSD_VERSION="3.0.2"
OSD_VERSION_MIN=$OSD_VERSION
+OSD_FORCE_BUILD=false
OSD_FORCE_REBUILD=false
OSD_SKIP=false
+# OpenVDB needs to be compiled for now
+OPENVDB_BLOSC_VERSION="1.7.0"
+
+OPENVDB_VERSION="3.1.0"
+OPENVDB_VERSION_MIN=$OPENVDB_VERSION
+OPENVDB_FORCE_BUILD=false
+OPENVDB_FORCE_REBUILD=false
+OPENVDB_SKIP=false
+
# Version??
OPENCOLLADA_VERSION="1.3"
+OPENCOLLADA_FORCE_BUILD=true # no package!
OPENCOLLADA_FORCE_REBUILD=false
OPENCOLLADA_SKIP=false
-FFMPEG_VERSION="2.1.5"
-FFMPEG_VERSION_MIN="2.1.5"
+FFMPEG_VERSION="2.8.4"
+FFMPEG_VERSION_MIN="2.8.4"
+FFMPEG_FORCE_BUILD=false
FFMPEG_FORCE_REBUILD=false
FFMPEG_SKIP=false
_ffmpeg_list_sep=";"
@@ -355,12 +450,19 @@ while true; do
PRINT ""
exit 0
;;
+ --show-deps)
+ # We have to defer...
+ DO_SHOW_DEPS=true; shift; continue
+ ;;
--no-sudo)
PRINT ""
WARNING "--no-sudo enabled, this script might not be able to do much..."
PRINT ""
SUDO=""; shift; continue
;;
+ --no-confirm)
+ NO_CONFIRM=true; shift; continue
+ ;;
--with-all)
WITH_ALL=true; shift; continue
;;
@@ -370,7 +472,6 @@ while true; do
--ver-ocio)
OCIO_VERSION="$2"
OCIO_VERSION_MIN=$OCIO_VERSION
- echo $OCIO_VERSION
shift; shift; continue
;;
--ver-oiio)
@@ -388,11 +489,71 @@ while true; do
OSL_VERSION_MIN=$OSL_VERSION
shift; shift; continue
;;
- --ver-osd)
+ --ver-osd)
OSD_VERSION="$2"
OSD_VERSION_MIN=$OSD_VERSION
shift; shift; continue
;;
+ --ver-openvdb)
+ OPENVDB_VERSION="$2"
+ OPENVDB_VERSION_MIN=$OPENVDB_VERSION
+ shift; shift; continue
+ ;;
+ --build-all)
+ PYTHON_FORCE_BUILD=true
+ NUMPY_FORCE_BUILD=true
+ BOOST_FORCE_BUILD=true
+ OCIO_FORCE_BUILD=true
+ OPENEXR_FORCE_BUILD=true
+ OIIO_FORCE_BUILD=true
+ LLVM_FORCE_BUILD=true
+ OSL_FORCE_BUILD=true
+ OSD_FORCE_BUILD=true
+ OPENVDB_FORCE_BUILD=true
+ OPENCOLLADA_FORCE_BUILD=true
+ FFMPEG_FORCE_BUILD=true
+ shift; continue
+ ;;
+ --build-python)
+ PYTHON_FORCE_BUILD=true
+ NUMPY_FORCE_BUILD=true
+ shift; continue
+ ;;
+ --build-numpy)
+ PYTHON_FORCE_BUILD=true
+ NUMPY_FORCE_BUILD=true
+ shift; continue
+ ;;
+ --build-boost)
+ BOOST_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-ocio)
+ OCIO_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-openexr)
+ OPENEXR_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-oiio)
+ OIIO_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-llvm)
+ LLVM_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-osl)
+ OSL_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-osd)
+ OSD_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-openvdb)
+ OPENVDB_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-opencollada)
+ OPENCOLLADA_FORCE_BUILD=true; shift; continue
+ ;;
+ --build-ffmpeg)
+ FFMPEG_FORCE_BUILD=true; shift; continue
+ ;;
--force-all)
PYTHON_FORCE_REBUILD=true
NUMPY_FORCE_REBUILD=true
@@ -403,6 +564,7 @@ while true; do
LLVM_FORCE_REBUILD=true
OSL_FORCE_REBUILD=true
OSD_FORCE_REBUILD=true
+ OPENVDB_FORCE_REBUILD=true
OPENCOLLADA_FORCE_REBUILD=true
FFMPEG_FORCE_REBUILD=true
shift; continue
@@ -425,13 +587,10 @@ while true; do
OPENEXR_FORCE_REBUILD=true; shift; continue
;;
--force-oiio)
- OIIO_FORCE_REBUILD=true
- shift; continue
+ OIIO_FORCE_REBUILD=true; shift; continue
;;
--force-llvm)
- LLVM_FORCE_REBUILD=true
- OSL_FORCE_REBUILD=true
- shift; continue
+ LLVM_FORCE_REBUILD=true; shift; continue
;;
--force-osl)
OSL_FORCE_REBUILD=true; shift; continue
@@ -439,6 +598,9 @@ while true; do
--force-osd)
OSD_FORCE_REBUILD=true; shift; continue
;;
+ --force-openvdb)
+ OPENVDB_FORCE_REBUILD=true; shift; continue
+ ;;
--force-opencollada)
OPENCOLLADA_FORCE_REBUILD=true; shift; continue
;;
@@ -471,16 +633,16 @@ while true; do
;;
--skip-osd)
OSD_SKIP=true; shift; continue
- ;;
+ ;;
+ --skip-openvdb)
+ OPENVDB_SKIP=true; shift; continue
+ ;;
--skip-opencollada)
OPENCOLLADA_SKIP=true; shift; continue
;;
--skip-ffmpeg)
FFMPEG_SKIP=true; shift; continue
;;
- --required-numpy)
- NUMPY_REQUIRED=true; shift; continue
- ;;
--)
# no more arguments to parse
break
@@ -496,17 +658,19 @@ while true; do
esac
done
-if [ $WITH_ALL == true -a $OPENCOLLADA_SKIP == false ]; then
+if [ "$WITH_ALL" = true -a "$OPENCOLLADA_SKIP" = false ]; then
WITH_OPENCOLLADA=true
fi
# This has to be done here, because user might force some versions...
-PYTHON_SOURCE=( "http://python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" )
+PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" )
NUMPY_SOURCE=( "http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION/numpy-$NUMPY_VERSION.tar.gz" )
+
_boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'`
BOOST_SOURCE=( "http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" )
+BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams"
OCIO_SOURCE=( "https://github.com/imageworks/OpenColorIO/tarball/v$OCIO_VERSION" )
@@ -523,30 +687,88 @@ OIIO_SOURCE_REPO_UID="c9e67275a0b248ead96152f6d2221cc0c0f278a4"
LLVM_SOURCE=( "http://llvm.org/releases/$LLVM_VERSION/llvm-$LLVM_VERSION.src.tar.gz" )
LLVM_CLANG_SOURCE=( "http://llvm.org/releases/$LLVM_VERSION/clang-$LLVM_VERSION.src.tar.gz" "http://llvm.org/releases/$LLVM_VERSION/cfe-$LLVM_VERSION.src.tar.gz" )
-OSL_USE_REPO=true
-#~ OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/Release-$OSL_VERSION.tar.gz" )
-OSL_SOURCE=( "https://github.com/Nazg-Gul/OpenShadingLanguage/archive/Release-1.5.11.tar.gz" )
+
+OSL_USE_REPO=false
+OSL_SOURCE=( "https://github.com/imageworks/OpenShadingLanguage/archive/Release-$OSL_VERSION.tar.gz" )
+#~ OSL_SOURCE=( "https://github.com/Nazg-Gul/OpenShadingLanguage/archive/Release-1.5.11.tar.gz" )
#~ OSL_SOURCE_REPO=( "https://github.com/imageworks/OpenShadingLanguage.git" )
#~ OSL_SOURCE_REPO=( "https://github.com/mont29/OpenShadingLanguage.git" )
#~ OSL_SOURCE_REPO_UID="85179714e1bc69cd25ecb6bb711c1a156685d395"
#~ OSL_SOURCE_REPO_BRANCH="master"
OSL_SOURCE_REPO=( "https://github.com/Nazg-Gul/OpenShadingLanguage.git" )
-OSL_SOURCE_REPO_UID="22ee5ea298fd215430dfbd160b5aefd507f06db0"
+OSL_SOURCE_REPO_UID="7d40ff5fe8e47b030042afb92d0e955f5aa96f48"
OSL_SOURCE_REPO_BRANCH="blender-fixes"
OSD_USE_REPO=true
-# Script foo to make the version string compliant with the archive name:
+# Script foo to make the version string compliant with the archive name:
# ${Varname//SearchForThisChar/ReplaceWithThisChar}
OSD_SOURCE=( "https://github.com/PixarAnimationStudios/OpenSubdiv/archive/v${OSD_VERSION//./_}.tar.gz" )
OSD_SOURCE_REPO=( "https://github.com/PixarAnimationStudios/OpenSubdiv.git" )
OSD_SOURCE_REPO_UID="404659fffa659da075d1c9416e4fc939139a84ee"
OSD_SOURCE_REPO_BRANCH="dev"
+OPENVDB_USE_REPO=false
+OPENVDB_BLOSC_SOURCE=( "https://github.com/Blosc/c-blosc/archive/v${OPENVDB_BLOSC_VERSION}.tar.gz" )
+OPENVDB_SOURCE=( "https://github.com/dreamworksanimation/openvdb/archive/v${OPENVDB_VERSION}.tar.gz" )
+#~ OPENVDB_SOURCE_REPO=( "https:///dreamworksanimation/openvdb.git" )
+#~ OPENVDB_SOURCE_REPO_UID="404659fffa659da075d1c9416e4fc939139a84ee"
+#~ OPENVDB_SOURCE_REPO_BRANCH="dev"
+
OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
+OPENCOLLADA_REPO_BRANCH="master"
+
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
+
+#### Show Dependencies ####
+
+# Need those to be after we defined versions...
+DEPS_COMMON_INFO="\"COMMON DEPENDENCIES:
+
+Those libraries should be available as packages in all recent distributions (optional ones are [between brackets]):
+
+ * Basics of dev environment (cmake, gcc, svn , git, ...).
+ * libjpeg, libpng, libtiff, [libopenjpeg], [libopenal].
+ * libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed).
+ * libsqlite3, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp.
+ * libsdl1.2, libglew, libglewmx.\""
+
+DEPS_SPECIFIC_INFO="\"BUILDABLE DEPENDENCIES:
+
+The following libraries will probably not all be available as packages in your distribution
+(install_deps will by default try to install packages, and fall back to building missing ones).
+You can force install_deps to build those with '--build-all' or relevant 'build-foo' options, see '--help' message.
+You may also want to build them yourself (optional ones are [between brackets]):
+
+ * Python $PYTHON_VERSION_MIN (from $PYTHON_SOURCE).
+ * [NumPy $NUMPY_VERSION_MIN] (from $NUMPY_SOURCE).
+ * Boost $BOOST_VERSION_MIN (from $BOOST_SOURCE, modules: $BOOST_BUILD_MODULES).
+ * [FFMpeg $FFMPEG_VERSION_MIN (needs libvorbis, libogg, libtheora, libx264, libmp3lame, libxvidcore, libvpx, ...)] (from $FFMPEG_SOURCE).
+ * [OpenColorIO $OCIO_VERSION_MIN] (from $OCIO_SOURCE).
+ * ILMBase $ILMBASE_VERSION_MIN (from $ILMBASE_SOURCE).
+ * OpenEXR $OPENEXR_VERSION_MIN (from $OPENEXR_SOURCE).
+ * OpenImageIO $OIIO_VERSION_MIN (from $OIIO_SOURCE).
+ * [LLVM $LLVM_VERSION_MIN (with clang)] (from $LLVM_SOURCE, and $LLVM_CLANG_SOURCE).
+ * [OpenShadingLanguage $OSL_VERSION_MIN] (from $OSL_SOURCE_REPO, branch $OSL_SOURCE_REPO_BRANCH, commit $OSL_SOURCE_REPO_UID).
+ * [OpenSubDiv $OSD_VERSION_MIN] (from $OSD_SOURCE_REPO, branch $OSD_SOURCE_REPO_BRANCH, commit $OSD_SOURCE_REPO_UID).
+ * [OpenVDB $OPENVDB_VERSION_MIN] (from $OPENVDB_SOURCE), [Blosc $OPENVDB_BLOSC_VERSION] (from $OPENVDB_BLOSC_SOURCE).
+ * [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).\""
+
+if [ "$DO_SHOW_DEPS" = true ]; then
+ PRINT ""
+ PRINT "Blender dependencies (libraries needed to build it):"
+ PRINT ""
+ PRINT "`eval _echo "$DEPS_COMMON_INFO"`"
+ PRINT ""
+ PRINT "`eval _echo "$DEPS_SPECIFIC_INFO"`"
+ PRINT ""
+ exit 0
+fi
+
+
+
##### Generic Helpers #####
# Check return code of wget for success...
@@ -565,7 +787,7 @@ download() {
done
if [ $error -eq 1 ]; then
- ERROR "wget could not find $1, or could not write it to $2, exiting"
+ ERROR "wget could not find ${sources[@]}, or could not write it to $2, exiting"
exit 1
fi
}
@@ -624,6 +846,18 @@ version_ge() {
fi
}
+# Return 0 if $3 > $1 >= $2, else 1.
+# $1 and $2 should be version numbers made of numbers only.
+version_ge_lt() {
+ version_ge $1 $3
+ if [ $? -eq 0 ]; then
+ return 1
+ else
+ version_ge $1 $2
+ return $?
+ fi
+}
+
# Return 0 if $1 is into $2 (e.g. 3.3.2 is into 3.3, but not 3.3.0 or 3.3.5), else 1.
# $1 and $2 should be version numbers made of numbers only.
# $1 should be at least as long as $2!
@@ -736,7 +970,7 @@ compile_Python() {
# Clean install if needed!
magic_compile_check python-$PYTHON_VERSION $py_magic
- if [ $? -eq 1 -o $PYTHON_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$PYTHON_FORCE_REBUILD" = true ]; then
clean_Python
fi
@@ -801,7 +1035,7 @@ compile_Numpy() {
# Clean install if needed!
magic_compile_check numpy-$NUMPY_VERSION $numpy_magic
- if [ $? -eq 1 -o $NUMPY_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$NUMPY_FORCE_REBUILD" = true ]; then
clean_Numpy
fi
@@ -856,13 +1090,13 @@ clean_Boost() {
compile_Boost() {
# To be changed each time we make edits that would modify the compiled result!
- boost_magic=7
+ boost_magic=10
_init_boost
# Clean install if needed!
magic_compile_check boost-$BOOST_VERSION $boost_magic
- if [ $? -eq 1 -o $BOOST_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$BOOST_FORCE_REBUILD" = true ]; then
clean_Boost
fi
@@ -870,7 +1104,9 @@ compile_Boost() {
INFO "Building Boost-$BOOST_VERSION"
# Rebuild dependecies as well!
+ OIIO_FORCE_BUILD=true
OIIO_FORCE_REBUILD=true
+ OSL_FORCE_BUILD=true
OSL_FORCE_REBUILD=true
prepare_opt
@@ -886,7 +1122,7 @@ compile_Boost() {
if [ ! -f $_src/b2 ]; then
./bootstrap.sh
fi
- ./b2 -j$THREADS -a --with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time \
+ ./b2 -j$THREADS -a $BOOST_BUILD_MODULES \
--prefix=$_inst --disable-icu boost.locale.icu=off install
./b2 --clean
@@ -930,7 +1166,7 @@ compile_OCIO() {
# Clean install if needed!
magic_compile_check ocio-$OCIO_VERSION $ocio_magic
- if [ $? -eq 1 -o $OCIO_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OCIO_FORCE_REBUILD" = true ]; then
clean_OCIO
fi
@@ -953,7 +1189,7 @@ compile_OCIO() {
# Always refresh the whole build!
if [ -d build ]; then
rm -rf build
- fi
+ fi
mkdir build
cd build
@@ -1021,7 +1257,7 @@ compile_ILMBASE() {
# Clean install if needed!
magic_compile_check ilmbase-$ILMBASE_VERSION $ilmbase_magic
- if [ $? -eq 1 -o $OPENEXR_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OPENEXR_FORCE_REBUILD" = true ]; then
clean_ILMBASE
rm -rf $_openexr_inst
fi
@@ -1030,6 +1266,7 @@ compile_ILMBASE() {
INFO "Building ILMBase-$ILMBASE_VERSION"
# Rebuild dependecies as well!
+ OPENEXR_FORCE_BUILD=true
OPENEXR_FORCE_REBUILD=true
prepare_opt
@@ -1048,7 +1285,7 @@ compile_ILMBASE() {
# Always refresh the whole build!
if [ -d build ]; then
rm -rf build
- fi
+ fi
mkdir build
cd build
@@ -1106,7 +1343,7 @@ compile_OPENEXR() {
# Clean install if needed!
magic_compile_check openexr-$OPENEXR_VERSION $openexr_magic
- if [ $? -eq 1 -o $OPENEXR_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OPENEXR_FORCE_REBUILD" = true ]; then
clean_OPENEXR
fi
@@ -1120,8 +1357,8 @@ compile_OPENEXR() {
INFO "Building OpenEXR-$OPENEXR_VERSION"
# Rebuild dependecies as well!
+ OIIO_FORCE_BUILD=true
OIIO_FORCE_REBUILD=true
- OSL_FORCE_REBUILD=true
prepare_opt
@@ -1129,7 +1366,7 @@ compile_OPENEXR() {
INFO "Downloading OpenEXR-$OPENEXR_VERSION"
mkdir -p $SRC
- if [ $OPENEXR_USE_REPO == true ]; then
+ if [ "$OPENEXR_USE_REPO" = true ]; then
git clone ${OPENEXR_SOURCE_REPO[0]} $_src
else
download OPENEXR_SOURCE[@] $_src.tar.gz
@@ -1141,7 +1378,7 @@ compile_OPENEXR() {
cd $_src
- if [ $OPENEXR_USE_REPO == true ]; then
+ if [ "$OPENEXR_USE_REPO" = true ]; then
# XXX For now, always update from latest repo...
git pull origin master
# Stick to same rev as windows' libs...
@@ -1155,7 +1392,7 @@ compile_OPENEXR() {
# Always refresh the whole build!
if [ -d build ]; then
rm -rf build
- fi
+ fi
mkdir build
cd build
@@ -1217,12 +1454,12 @@ clean_OIIO() {
compile_OIIO() {
# To be changed each time we make edits that would modify the compiled result!
- oiio_magic=14
+ oiio_magic=16
_init_oiio
# Clean install if needed!
magic_compile_check oiio-$OIIO_VERSION $oiio_magic
- if [ $? -eq 1 -o $OIIO_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OIIO_FORCE_REBUILD" = true ]; then
clean_OIIO
fi
@@ -1230,6 +1467,7 @@ compile_OIIO() {
INFO "Building OpenImageIO-$OIIO_VERSION"
# Rebuild dependecies as well!
+ OSL_FORCE_BUILD=true
OSL_FORCE_REBUILD=true
prepare_opt
@@ -1237,7 +1475,7 @@ compile_OIIO() {
if [ ! -d $_src ]; then
mkdir -p $SRC
- if [ $OIIO_USE_REPO == true ]; then
+ if [ "$OIIO_USE_REPO" = true ]; then
git clone ${OIIO_SOURCE_REPO[0]} $_src
else
download OIIO_SOURCE[@] "$_src.tar.gz"
@@ -1248,7 +1486,7 @@ compile_OIIO() {
cd $_src
- if [ $OIIO_USE_REPO == true ]; then
+ if [ "$OIIO_USE_REPO" = true ]; then
# XXX For now, always update from latest repo...
git pull origin master
# Stick to same rev as windows' libs...
@@ -1259,7 +1497,7 @@ compile_OIIO() {
# Always refresh the whole build!
if [ -d build ]; then
rm -rf build
- fi
+ fi
mkdir build
cd build
@@ -1269,11 +1507,12 @@ compile_OIIO() {
cmake_d="$cmake_d -D STOP_ON_WARNING=OFF"
cmake_d="$cmake_d -D BUILDSTATIC=OFF"
cmake_d="$cmake_d -D LINKSTATIC=OFF"
+ cmake_d="$cmake_d -D USE_SIMD=sse2"
cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION"
- if [ $_with_built_openexr == true ]; then
+ if [ "$_with_built_openexr" = true ]; then
cmake_d="$cmake_d -D ILMBASE_HOME=$INST/openexr"
cmake_d="$cmake_d -D OPENEXR_HOME=$INST/openexr"
INFO "ILMBASE_HOME=$INST/openexr"
@@ -1282,6 +1521,7 @@ compile_OIIO() {
# Optional tests and cmd tools
cmake_d="$cmake_d -D USE_QT=OFF"
cmake_d="$cmake_d -D USE_PYTHON=OFF"
+ cmake_d="$cmake_d -D USE_FFMPEG=OFF"
cmake_d="$cmake_d -D BUILD_TESTING=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TESTS=OFF"
cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=OFF"
@@ -1345,18 +1585,22 @@ clean_LLVM() {
compile_LLVM() {
# To be changed each time we make edits that would modify the compiled result!
- llvm_magic=2
+ llvm_magic=3
_init_llvm
# Clean install if needed!
magic_compile_check llvm-$LLVM_VERSION $llvm_magic
- if [ $? -eq 1 -o $LLVM_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$LLVM_FORCE_REBUILD" = true ]; then
clean_LLVM
fi
if [ ! -d $_inst ]; then
INFO "Building LLVM-$LLVM_VERSION (CLANG included!)"
+ # Rebuild dependecies as well!
+ OSL_FORCE_BUILD=true
+ OSL_FORCE_REBUILD=true
+
prepare_opt
if [ ! -d $_src -o true ]; then
@@ -1376,19 +1620,7 @@ compile_LLVM() {
cd $_src
# XXX Ugly patching hack!
- cat << EOF | patch -p1
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -13,7 +13,7 @@
- set(LLVM_VERSION_MAJOR 3)
- set(LLVM_VERSION_MINOR 1)
-
--set(PACKAGE_VERSION "\${LLVM_VERSION_MAJOR}.\${LLVM_VERSION_MINOR}svn")
-+set(PACKAGE_VERSION "\${LLVM_VERSION_MAJOR}.\${LLVM_VERSION_MINOR}")
-
- set_property(GLOBAL PROPERTY USE_FOLDERS ON)
-
-EOF
+ patch -p1 -i "$SCRIPT_DIR/install_deps_patches/llvm.patch"
cd $CWD
@@ -1427,9 +1659,6 @@ EOF
magic_compile_set llvm-$LLVM_VERSION $llvm_magic
- # Rebuild dependecies as well!
- OSL_FORCE_REBUILD=true
-
cd $CWD
INFO "Done compiling LLVM-$LLVM_VERSION (CLANG included)!"
else
@@ -1453,15 +1682,15 @@ clean_OSL() {
compile_OSL() {
# To be changed each time we make edits that would modify the compiled result!
- osl_magic=17
+ osl_magic=20
_init_osl
# Clean install if needed!
magic_compile_check osl-$OSL_VERSION $osl_magic
- #~ if [ $? -eq 1 -o $OSL_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OSL_FORCE_REBUILD" = true ]; then
#~ rm -Rf $_src # XXX Radical, but not easy to change remote repo fully automatically
- #~ clean_OSL
- #~ fi
+ clean_OSL
+ fi
if [ ! -d $_inst ]; then
INFO "Building OpenShadingLanguage-$OSL_VERSION"
@@ -1471,7 +1700,7 @@ compile_OSL() {
if [ ! -d $_src ]; then
mkdir -p $SRC
- if [ $OSL_USE_REPO == true ]; then
+ if [ "$OSL_USE_REPO" = true ]; then
git clone ${OSL_SOURCE_REPO[0]} $_src
else
download OSL_SOURCE[@] "$_src.tar.gz"
@@ -1483,19 +1712,22 @@ compile_OSL() {
cd $_src
- if [ $OSL_USE_REPO == true ]; then
+ if [ "$OSL_USE_REPO" = true ]; then
git remote set-url origin ${OSL_SOURCE_REPO[0]}
# XXX For now, always update from latest repo...
git pull --no-edit -X theirs origin $OSL_SOURCE_REPO_BRANCH
# Stick to same rev as windows' libs...
git checkout $OSL_SOURCE_REPO_UID
git reset --hard
+
+ # XXX Ugly patching hack!
+ patch -p1 -i "$SCRIPT_DIR/install_deps_patches/osl.patch"
fi
# Always refresh the whole build!
if [ -d build ]; then
rm -rf build
- fi
+ fi
mkdir build
cd build
@@ -1504,10 +1736,13 @@ compile_OSL() {
cmake_d="$cmake_d -D BUILD_TESTING=OFF"
cmake_d="$cmake_d -D STOP_ON_WARNING=OFF"
cmake_d="$cmake_d -D BUILDSTATIC=OFF"
+ cmake_d="$cmake_d -D OSL_BUILD_PLUGINS=OFF"
+ cmake_d="$cmake_d -D OSL_BUILD_TESTS=OFF"
+ cmake_d="$cmake_d -D USE_SIMD=sse2"
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
- if [ $_with_built_openexr == true ]; then
+ if [ "$_with_built_openexr" = true ]; then
INFO "ILMBASE_HOME=$INST/openexr"
cmake_d="$cmake_d -D ILMBASE_HOME=$INST/openexr"
# XXX Temp workaround... sigh, ILMBase really messed the things up by defining their custom names ON by default :(
@@ -1526,11 +1761,14 @@ compile_OSL() {
if [ ! -z $LLVM_VERSION_FOUND ]; then
cmake_d="$cmake_d -D LLVM_VERSION=$LLVM_VERSION_FOUND"
if [ -d $INST/llvm ]; then
- cmake_d="$cmake_d -D LLVM_ROOT_DIR=$INST/llvm"
+ cmake_d="$cmake_d -D LLVM_DIRECTORY=$INST/llvm"
cmake_d="$cmake_d -D LLVM_STATIC=ON"
fi
fi
+ #~ cmake_d="$cmake_d -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
+ #~ cmake_d="$cmake_d -D CMAKE_VERBOSE_MAKEFILE=ON"
+
cmake $cmake_d ..
make -j$THREADS && make install
@@ -1570,12 +1808,12 @@ clean_OSD() {
compile_OSD() {
# To be changed each time we make edits that would modify the compiled result!
- osd_magic=0
+ osd_magic=1
_init_osd
# Clean install if needed!
magic_compile_check osd-$OSD_VERSION $osd_magic
- if [ $? -eq 1 -o $OSD_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OSD_FORCE_REBUILD" = true ]; then
clean_OSD
fi
@@ -1587,7 +1825,7 @@ compile_OSD() {
if [ ! -d $_src ]; then
mkdir -p $SRC
- if [ $OSD_USE_REPO == true ]; then
+ if [ "$OSD_USE_REPO" = true ]; then
git clone ${OSD_SOURCE_REPO[0]} $_src
else
download OSD_SOURCE[@] "$_src.tar.gz"
@@ -1599,7 +1837,7 @@ compile_OSD() {
cd $_src
- if [ $OSD_USE_REPO == true ]; then
+ if [ "$OSD_USE_REPO" = true ]; then
git remote set-url origin ${OSD_SOURCE_REPO[0]}
# XXX For now, always update from latest repo...
git pull --no-edit -X theirs origin $OSD_SOURCE_REPO_BRANCH
@@ -1611,7 +1849,7 @@ compile_OSD() {
# Always refresh the whole build!
if [ -d build ]; then
rm -rf build
- fi
+ fi
mkdir build
cd build
@@ -1619,7 +1857,7 @@ compile_OSD() {
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
# ptex is only needed when nicholas bishop is ready
cmake_d="$cmake_d -D NO_PTEX=1"
- cmake_d="$cmake_d -D NO_CLEW=1"
+ cmake_d="$cmake_d -D NO_CLEW=1 -D NO_CUDA=1 -D NO_OPENCL=1"
# maya plugin, docs, tutorials, regression tests and examples are not needed
cmake_d="$cmake_d -D NO_MAYA=1 -D NO_DOC=1 -D NO_TUTORIALS=1 -D NO_REGRESSION=1 -DNO_EXAMPLES=1"
@@ -1647,6 +1885,193 @@ compile_OSD() {
run_ldconfig "osd"
}
+#### Build Blosc ####
+_init_blosc() {
+ _src=$SRC/c-blosc-$OPENVDB_BLOSC_VERSION
+ _git=false
+ _inst=$INST/blosc-$OPENVDB_BLOSC_VERSION
+ _inst_shortcut=$INST/blosc
+}
+
+clean_BLOSC() {
+ _init_blosc
+ _clean
+}
+
+compile_BLOSC() {
+ # To be changed each time we make edits that would modify the compiled result!
+ blosc_magic=0
+ _init_blosc
+
+ # Clean install if needed!
+ magic_compile_check blosc-$OPENVDB_BLOSC_VERSION $blosc_magic
+ if [ $? -eq 1 -o "$OPENVDB_FORCE_REBUILD" = true ]; then
+ clean_BLOSC
+ rm -rf $_inst
+ fi
+
+ if [ ! -d $_inst ]; then
+ INFO "Building Blosc-$OPENVDB_BLOSC_VERSION"
+
+ # Rebuild dependecies as well!
+ OPENVDB_FORCE_BUILD=true
+ OPENVDB_FORCE_REBUILD=true
+
+ prepare_opt
+
+ if [ ! -d $_src ]; then
+ INFO "Downloading Blosc-$OPENVDB_BLOSC_VERSION"
+ mkdir -p $SRC
+ download OPENVDB_BLOSC_SOURCE[@] $_src.tar.gz
+
+ INFO "Unpacking Blosc-$OPENVDB_BLOSC_VERSION"
+ tar -C $SRC -xf $_src.tar.gz
+ fi
+
+ cd $_src
+ # Always refresh the whole build!
+ if [ -d build ]; then
+ rm -rf build
+ fi
+ mkdir build
+ cd build
+
+ cmake_d="-D CMAKE_BUILD_TYPE=Release"
+ cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
+ cmake_d="$cmake_d -D BUILD_STATIC=OFF"
+ cmake_d="$cmake_d -D BUILD_TESTS=OFF"
+ cmake_d="$cmake_d -D BUILD_BENCHMARKS=OFF"
+ INFO "$cmake_d"
+
+ cmake $cmake_d ..
+
+ make -j$THREADS && make install
+
+ make clean
+
+ if [ -d $_inst ]; then
+ _create_inst_shortcut
+ else
+ ERROR "Blosc-$OPENVDB_BLOSC_VERSION failed to compile, exiting"
+ exit 1
+ fi
+ cd $CWD
+ INFO "Done compiling Blosc-$OPENVDB_BLOSC_VERSION!"
+ else
+ INFO "Own Blosc-$OPENVDB_BLOSC_VERSION is up to date, nothing to do!"
+ INFO "If you want to force rebuild of this lib (and openexr), use the --force-openvdb option."
+ fi
+
+ magic_compile_set blosc-$OPENVDB_BLOSC_VERSION $blosc_magic
+
+ run_ldconfig "blosc"
+}
+
+#### Build OpenVDB ####
+_init_openvdb() {
+ _src=$SRC/openvdb-$OPENVDB_VERSION
+ _git=false
+ _inst=$INST/openvdb-$OPENVDB_VERSION
+ _inst_shortcut=$INST/openvdb
+}
+
+clean_OPENVDB() {
+ _init_openvdb
+ _clean
+}
+
+compile_OPENVDB() {
+ compile_BLOSC
+ PRINT ""
+
+ # To be changed each time we make edits that would modify the compiled result!
+ openvdb_magic=0
+ _init_openvdb
+
+ # Clean install if needed!
+ magic_compile_check openvdb-$OPENVDB_VERSION $openvdb_magic
+ if [ $? -eq 1 -o "$OPENVDB_FORCE_REBUILD" = true ]; then
+ clean_OPENVDB
+ fi
+
+ if [ ! -d $_inst ]; then
+ INFO "Building OpenVDB-$OPENVDB_VERSION"
+
+ prepare_opt
+
+ if [ ! -d $_src -o true ]; then
+ mkdir -p $SRC
+ download OPENVDB_SOURCE[@] "$_src.tar.gz"
+
+ INFO "Unpacking OpenVDB-$OPENVDB_VERSION"
+ #~ tar -C $SRC --transform "s,(.*/?)OpenShadingLanguage-[^/]*(.*),\1OpenShadingLanguage-$OPENVDB_VERSION\2,x" \
+ #~ -xf $_src.tar.gz
+ tar -C $SRC -xf $_src.tar.gz
+ fi
+
+ cd $_src
+
+ #~ if [ "$OPENVDB_USE_REPO" = true ]; then
+ #~ git remote set-url origin ${OPENVDB_SOURCE_REPO[0]}
+ #~ # XXX For now, always update from latest repo...
+ #~ git pull --no-edit -X theirs origin $OPENVDB_SOURCE_REPO_BRANCH
+ #~ # Stick to same rev as windows' libs...
+ #~ git checkout $OPENVDB_SOURCE_REPO_UID
+ #~ git reset --hard
+ #~ fi
+
+ cd openvdb # Grrrrrr...
+
+ # Always refresh the whole build!
+ if [ -d build ]; then
+ rm -rf build
+ fi
+ mkdir build
+ cd build
+
+ make_d="DESTDIR=$_inst"
+
+ if [ -d $INST/boost ]; then
+ make_d="$make_d -D BOOST_ROOT=$INST/boost -D Boost_NO_SYSTEM_PATHS=ON"
+ fi
+
+ #~ if [ "$_with_built_openexr" = true ]; then
+ #~ cmake_d="$cmake_d -D ILMBASE_HOME=$INST/openexr"
+ #~ cmake_d="$cmake_d -D OPENEXR_HOME=$INST/openexr"
+ #~ INFO "ILMBASE_HOME=$INST/openexr"
+ #~ fi
+
+ #~ cmake_d="-D CMAKE_BUILD_TYPE=Release"
+ #~ cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
+ #~ # ptex is only needed when nicholas bishop is ready
+ #~ cmake_d="$cmake_d -D NO_PTEX=1"
+ #~ cmake_d="$cmake_d -D NO_CLEW=1"
+ #~ # maya plugin, docs, tutorials, regression tests and examples are not needed
+ #~ cmake_d="$cmake_d -D NO_MAYA=1 -D NO_DOC=1 -D NO_TUTORIALS=1 -D NO_REGRESSION=1 -DNO_EXAMPLES=1"
+
+ #~ cmake $cmake_d ..
+
+ #~ make -j$THREADS && make install
+ #~ make clean
+
+ #~ if [ -d $_inst ]; then
+ #~ _create_inst_shortcut
+ #~ else
+ #~ ERROR "OpenSubdiv-$OSD_VERSION failed to compile, exiting"
+ #~ exit 1
+ #~ fi
+
+ #~ magic_compile_set osd-$OSD_VERSION $osd_magic
+
+ cd $CWD
+ INFO "Done compiling OpenVDB-$OPENVDB_VERSION!"
+ else
+ INFO "Own OpenVDB-$OPENVDB_VERSION is up to date, nothing to do!"
+ INFO "If you want to force rebuild of this lib, use the --force-openvdb option."
+ fi
+
+ run_ldconfig "openvdb"
+}
#### Build OpenCOLLADA ####
_init_opencollada() {
@@ -1668,7 +2093,7 @@ compile_OpenCOLLADA() {
# Clean install if needed!
magic_compile_check opencollada-$OPENCOLLADA_VERSION $opencollada_magic
- if [ $? -eq 1 -o $OPENCOLLADA_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$OPENCOLLADA_FORCE_REBUILD" = true ]; then
clean_OpenCOLLADA
fi
@@ -1685,7 +2110,7 @@ compile_OpenCOLLADA() {
cd $_src
# XXX For now, always update from latest repo...
- git pull origin master
+ git pull origin $OPENCOLLADA_REPO_BRANCH
# Stick to same rev as windows' libs...
git checkout $OPENCOLLADA_REPO_UID
@@ -1742,12 +2167,12 @@ clean_FFmpeg() {
compile_FFmpeg() {
# To be changed each time we make edits that would modify the compiled result!
- ffmpeg_magic=3
+ ffmpeg_magic=4
_init_ffmpeg
# Clean install if needed!
magic_compile_check ffmpeg-$FFMPEG_VERSION $ffmpeg_magic
- if [ $? -eq 1 -o $FFMPEG_FORCE_REBUILD == true ]; then
+ if [ $? -eq 1 -o "$FFMPEG_FORCE_REBUILD" = true ]; then
clean_FFmpeg
fi
@@ -1769,31 +2194,31 @@ compile_FFmpeg() {
extra=""
- if $VORBIS_USE; then
+ if [ "$VORBIS_USE" = true ]; then
extra="$extra --enable-libvorbis"
fi
- if $THEORA_USE; then
+ if [ "$THEORA_USE" = true ]; then
extra="$extra --enable-libtheora"
fi
- if $XVID_USE; then
+ if [ "$XVID_USE" = true ]; then
extra="$extra --enable-libxvid"
fi
- if $X264_USE; then
+ if [ "$X264_USE" = true ]; then
extra="$extra --enable-libx264"
fi
- if $VPX_USE; then
+ if [ "$VPX_USE" = true ]; then
extra="$extra --enable-libvpx"
fi
- if $MP3LAME_USE; then
+ if [ "$MP3LAME_USE" = true ]; then
extra="$extra --enable-libmp3lame"
fi
- if $OPENJPEG_USE; then
+ if [ "$OPENJPEG_USE" = true ]; then
extra="$extra --enable-libopenjpeg"
fi
@@ -1808,6 +2233,7 @@ compile_FFmpeg() {
--disable-vaapi --disable-libfaac --disable-nonfree --enable-gpl \
--disable-postproc --disable-librtmp --disable-libopencore-amrnb \
--disable-libopencore-amrwb --disable-libdc1394 --disable-version3 --disable-outdev=sdl \
+ --disable-libxcb \
--disable-outdev=xv \
--disable-outdev=alsa --disable-indev=sdl --disable-indev=alsa --disable-indev=jack \
--disable-indev=lavfi $extra
@@ -1880,6 +2306,17 @@ check_package_version_ge_DEB() {
return $?
}
+check_package_version_ge_lt_DEB() {
+ v=`apt-cache policy $1 | grep 'Candidate:' | sed -r 's/.*:\s*([0-9]+:)?(([0-9]+\.?)+).*/\2/'`
+
+ if [ -z "$v" ]; then
+ return 1
+ fi
+
+ version_ge_lt $v $2 $3
+ return $?
+}
+
install_packages_DEB() {
if [ ! $SUDO ]; then
WARNING "--no-sudo enabled, impossible to run apt-get install for $@, you'll have to do it yourself..."
@@ -1899,8 +2336,10 @@ install_DEB() {
PRINT "`eval _echo "$COMMON_INFO"`"
PRINT ""
- read -p "Do you want to continue (Y/n)?"
- [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ if [ "$NO_CONFIRM" = false ]; then
+ read -p "Do you want to continue (Y/n)?"
+ [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ fi
if [ ! -z "`cat /etc/debian_version | grep ^6`" ]; then
if [ -z "`cat /etc/apt/sources.list | grep backports.debian.org`" ]; then
@@ -1938,7 +2377,7 @@ install_DEB() {
OGG_DEV="libogg-dev"
THEORA_DEV="libtheora-dev"
- _packages="gawk cmake cmake-curses-gui scons build-essential libjpeg-dev libpng-dev \
+ _packages="gawk cmake cmake-curses-gui build-essential libjpeg-dev libpng-dev \
libfreetype6-dev libx11-dev \
libxcursor-dev libxi-dev wget libsqlite3-dev libxrandr-dev libxinerama-dev \
libbz2-dev libncurses5-dev libssl-dev liblzma-dev libreadline-dev $OPENJPEG_DEV \
@@ -2005,7 +2444,7 @@ install_DEB() {
fi
fi
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
_packages="$_packages libspnav-dev"
# Only install jack if jack2 is not already installed!
JACK="libjack-dev"
@@ -2021,6 +2460,13 @@ install_DEB() {
PRINT ""
install_packages_DEB $_packages
+ PRINT""
+ SNDFILE_DEV="libsndfile1-dev"
+ check_package_DEB $SNDFILE_DEV
+ if [ $? -eq 0 ]; then
+ install_packages_DEB $SNDFILE_DEV
+ fi
+
PRINT ""
X264_DEV="libx264-dev"
check_package_version_ge_DEB $X264_DEV $X264_VERSION_MIN
@@ -2029,7 +2475,7 @@ install_DEB() {
X264_USE=true
fi
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
PRINT ""
# Grmpf, debian is libxvidcore-dev and ubuntu libxvidcore4-dev!
# Note: not since ubuntu 10.04
@@ -2064,50 +2510,53 @@ install_DEB() {
fi
fi
+
PRINT ""
- if $PYTHON_SKIP; then
- WARNING "Skipping Python installation, as requested..."
+ _do_compile_python=false
+ if [ "$PYTHON_SKIP" = true ]; then
+ WARNING "Skipping Python/NumPy installation, as requested..."
+ elif [ "$PYTHON_FORCE_BUILD" = true ]; then
+ INFO "Forced Python/NumPy building, as requested..."
+ _do_compile_python=true
else
- _do_compile=false
check_package_DEB python$PYTHON_VERSION_MIN-dev
if [ $? -eq 0 ]; then
install_packages_DEB python$PYTHON_VERSION_MIN-dev
+ clean_Python
PRINT ""
- if $NUMPY_SKIP; then
+ if [ "$NUMPY_SKIP" = true ]; then
WARNING "Skipping NumPy installation, as requested..."
else
check_package_DEB python3-numpy
if [ $? -eq 0 ]; then
install_packages_DEB python3-numpy
- elif $NUMPY_REQUIRED; then
- WARNING "Valid python package but no valid numpy package!" \
- " Building both Python and Numpy from sources!"
- _do_compile=true
else
WARNING "Sorry, using python package but no valid numpy package available!" \
- " Use --required-numpy to force building of both Python and numpy."
+ " Use --build-numpy to force building of both Python and NumPy."
fi
fi
else
- _do_compile=true
+ _do_compile_python=true
fi
+ fi
- if $_do_compile; then
- compile_Python
- PRINT ""
- if $NUMPY_SKIP; then
- WARNING "Skipping NumPy installation, as requested..."
- else
- compile_Numpy
- fi
+ if $_do_compile_python; then
+ compile_Python
+ PRINT ""
+ if [ "$NUMPY_SKIP" = true ]; then
+ WARNING "Skipping NumPy installation, as requested..."
else
- clean_Python
+ compile_Numpy
fi
fi
+
PRINT ""
- if $BOOST_SKIP; then
+ if [ "$BOOST_SKIP" = true ]; then
WARNING "Skipping Boost installation, as requested..."
+ elif [ "$BOOST_FORCE_BUILD" = true ]; then
+ INFO "Forced Boost building, as requested..."
+ compile_Boost
else
check_package_version_ge_DEB libboost-dev $BOOST_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -2129,9 +2578,13 @@ install_DEB() {
fi
fi
+
PRINT ""
- if $OCIO_SKIP; then
+ if [ "$OCIO_SKIP" = true ]; then
WARNING "Skipping OpenColorIO installation, as requested..."
+ elif [ "$OCIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenColorIO building, as requested..."
+ compile_OCIO
else
# XXX Always force build of own OCIO, until linux distro guys update their package to default libyaml-cpp ver (0.5)!
#check_package_version_ge_DEB libopencolorio-dev $OCIO_VERSION_MIN
@@ -2143,9 +2596,13 @@ install_DEB() {
#fi
fi
+
PRINT ""
- if $OPENEXR_SKIP; then
- WARNING "Skipping OpenEXR installation, as requested..."
+ if [ "$OPENEXR_SKIP" = true ]; then
+ WARNING "Skipping ILMBase/OpenEXR installation, as requested..."
+ elif [ "$OPENEXR_FORCE_BUILD" = true ]; then
+ INFO "Forced ILMBase/OpenEXR building, as requested..."
+ compile_OPENEXR
else
check_package_version_ge_DEB libopenexr-dev $OPENEXR_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -2158,12 +2615,16 @@ install_DEB() {
fi
fi
+
PRINT ""
- if $OIIO_SKIP; then
+ if [ "$OIIO_SKIP" = true ]; then
WARNING "Skipping OpenImageIO installation, as requested..."
+ elif [ "$OIIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenImageIO building, as requested..."
+ compile_OIIO
else
- check_package_version_ge_DEB libopenimageio-dev $OIIO_VERSION_MIN
- if [ $? -eq 0 -a $_with_built_openexr == false ]; then
+ check_package_version_ge_lt_DEB libopenimageio-dev $OIIO_VERSION_MIN $OIIO_VERSION_MAX
+ if [ $? -eq 0 -a "$_with_built_openexr" = false ]; then
install_packages_DEB libopenimageio-dev
clean_OIIO
else
@@ -2171,44 +2632,61 @@ install_DEB() {
fi
fi
- have_llvm=false
PRINT ""
- if $LLVM_SKIP; then
+ have_llvm=false
+ _do_compile_llvm=false
+ if [ "$LLVM_SKIP" = true ]; then
WARNING "Skipping LLVM installation, as requested (this also implies skipping OSL!)..."
+ elif [ "$LLVM_FORCE_BUILD" = true ]; then
+ INFO "Forced LLVM building, as requested..."
+ _do_compile_llvm=true
else
- check_package_DEB llvm-$LLVM_VERSION-dev
+ check_package_DEB clang-$LLVM_VERSION
if [ $? -eq 0 ]; then
install_packages_DEB llvm-$LLVM_VERSION-dev clang-$LLVM_VERSION
have_llvm=true
LLVM_VERSION_FOUND=$LLVM_VERSION
clean_LLVM
else
- check_package_version_ge_DEB llvm-dev $LLVM_VERSION_MIN
- if [ $? -eq 0 ]; then
- install_packages_DEB llvm-dev clang
- have_llvm=true
- LLVM_VERSION_FOUND="" # Using default one, no need to specify it!
- clean_LLVM
- else
- install_packages_DEB libffi-dev
- # LLVM can't find the debian ffi header dir
- _FFI_INCLUDE_DIR=`dpkg -L libffi-dev | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'`
- PRINT ""
- compile_LLVM
- have_llvm=true
- LLVM_VERSION_FOUND=$LLVM_VERSION
- fi
- fi
+ #~ check_package_version_ge_DEB llvm-dev $LLVM_VERSION_MIN
+ #~ if [ $? -eq 0 ]; then
+ #~ install_packages_DEB llvm-dev clang
+ #~ have_llvm=true
+ #~ LLVM_VERSION_FOUND="" # Using default one, no need to specify it!
+ #~ clean_LLVM
+ #~ else
+ _do_compile_llvm=true
+ #~ fi
+ fi
+ fi
+
+ if [ "$_do_compile_llvm" = true ]; then
+ install_packages_DEB libffi-dev
+ # LLVM can't find the debian ffi header dir
+ _FFI_INCLUDE_DIR=`dpkg -L libffi-dev | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'`
+ PRINT ""
+ compile_LLVM
+ have_llvm=true
+ LLVM_VERSION_FOUND=$LLVM_VERSION
fi
+
PRINT ""
- if $OSL_SKIP; then
+ _do_compile_osl=false
+ if [ "$OSL_SKIP" = true ]; then
WARNING "Skipping OpenShadingLanguage installation, as requested..."
+ elif [ "$OSL_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenShadingLanguage building, as requested..."
+ _do_compile_osl=true
else
- if $have_llvm; then
- install_packages_DEB flex bison libtbb-dev
# No package currently!
+ _do_compile_osl=true
+ fi
+
+ if [ "$_do_compile_osl" = true ]; then
+ if [ "$have_llvm" = true ]; then
+ install_packages_DEB flex bison libtbb-dev
PRINT ""
compile_OSL
else
@@ -2216,25 +2694,40 @@ install_DEB() {
fi
fi
+
PRINT ""
- if $OSD_SKIP; then
+ _do_compile_osd=false
+ if [ "$OSD_SKIP" = true ]; then
WARNING "Skipping OpenSubdiv installation, as requested..."
+ elif [ "$OSD_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenSubdiv building, as requested..."
+ _do_compile_osd=true
else
- if $have_llvm; then
- install_packages_DEB flex bison libtbb-dev
# No package currently!
- PRINT ""
- compile_OSD
- else
- WARNING "No LLVM available, cannot build OSD!"
- fi
+ _do_compile_osd=true
+ fi
+
+ if [ "$_do_compile_osd" = true ]; then
+ install_packages_DEB flex bison libtbb-dev
+ PRINT ""
+ compile_OSD
fi
- if $WITH_OPENCOLLADA; then
+
+ if [ "$WITH_OPENCOLLADA" = true ]; then
+ _do_compile_collada=false
PRINT ""
- if $OPENCOLLADA_SKIP; then
+ if [ "$OPENCOLLADA_SKIP" = true ]; then
WARNING "Skipping OpenCOLLADA installation, as requested..."
+ elif [ "$OPENCOLLADA_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenCollada building, as requested..."
+ _do_compile_collada=true
else
+ # No package currently!
+ _do_compile_collada=true
+ fi
+
+ if [ "$_do_compile_collada" = true ]; then
install_packages_DEB libpcre3-dev
# Find path to libxml shared lib...
_XML2_LIB=`dpkg -L libxml2-dev | grep -e ".*/libxml2.so"`
@@ -2244,9 +2737,13 @@ install_DEB() {
fi
fi
+
PRINT ""
- if $FFMPEG_SKIP; then
+ if [ "$FFMPEG_SKIP" = true ]; then
WARNING "Skipping FFMpeg installation, as requested..."
+ elif [ "$FFMPEG_FORCE_BUILD" = true ]; then
+ INFO "Forced FFMpeg building, as requested..."
+ compile_FFmpeg
else
# XXX Debian features libav packages as ffmpeg, those are not really compatible with blender code currently :/
# So for now, always build our own ffmpeg.
@@ -2284,18 +2781,18 @@ rpm_flavour() {
get_package_version_RPM() {
rpm_flavour
- if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
+ if [ "$RPM" = "FEDORA" -o "$RPM" = "RHEL" ]; then
yum info $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+(([0-9]+\.?)+).*/\1/'
- elif [ $RPM = "SUSE" ]; then
+ elif [ "$RPM" = "SUSE" ]; then
zypper info $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+(([0-9]+\.?)+).*/\1/'
- fi
+ fi
}
check_package_RPM() {
rpm_flavour
- if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
+ if [ "$RPM" = "FEDORA" -o "$RPM" = "RHEL" ]; then
r=`yum info $1 | grep -c 'Summary'`
- elif [ $RPM = "SUSE" ]; then
+ elif [ "$RPM" = "SUSE" ]; then
r=`zypper info $1 | grep -c 'Summary'`
fi
@@ -2328,9 +2825,20 @@ check_package_version_ge_RPM() {
return $?
}
+check_package_version_ge_lt_RPM() {
+ v=`get_package_version_RPM $1`
+
+ if [ -z "$v" ]; then
+ return 1
+ fi
+
+ version_ge_lt $v $2 $3
+ return $?
+}
+
install_packages_RPM() {
rpm_flavour
- if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
+ if [ "$RPM" = "FEDORA" -o "$RPM" = "RHEL" ]; then
if [ ! $SUDO ]; then
WARNING "--no-sudo enabled, impossible to run yum install for $@, you'll have to do it yourself..."
else
@@ -2341,7 +2849,7 @@ install_packages_RPM() {
fi
fi
- elif [ $RPM = "SUSE" ]; then
+ elif [ "$RPM" = "SUSE" ]; then
if [ ! $SUDO ]; then
WARNING "--no-sudo enabled, impossible to run zypper install for $@, you'll have to do it yourself..."
else
@@ -2361,15 +2869,17 @@ install_RPM() {
PRINT "`eval _echo "$COMMON_INFO"`"
PRINT ""
- read -p "Do you want to continue (Y/n)?"
- [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ if [ "$NO_CONFIRM" = false ]; then
+ read -p "Do you want to continue (Y/n)?"
+ [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ fi
# Enable non-free repositories for all flavours
if [ ! $SUDO ]; then
WARNING "--no-sudo enabled, impossible to install third party repositories, you'll have to do it yourself..."
else
rpm_flavour
- if [ $RPM = "FEDORA" ]; then
+ if [ "$RPM" = "FEDORA" ]; then
_fedora_rel="`egrep "[0-9]{1,}" /etc/fedora-release -o`"
$SUDO yum -y localinstall --nogpgcheck \
http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$_fedora_rel.noarch.rpm \
@@ -2380,7 +2890,7 @@ install_RPM() {
# Install cmake now because of difference with RHEL
$SUDO yum -y install cmake
- elif [ $RPM = "RHEL" ]; then
+ elif [ "$RPM" = "RHEL" ]; then
$SUDO yum -y localinstall --nogpgcheck \
http://download.fedoraproject.org/pub/epel/6/$(uname -i)/epel-release-6-8.noarch.rpm \
http://download1.rpmfusion.org/free/el/updates/6/$(uname -i)/rpmfusion-free-release-6-1.noarch.rpm \
@@ -2399,9 +2909,9 @@ install_RPM() {
$SUDO rpm -ihv $SRC/cmake-2.8.8-4.el6.$(uname -m).rpm
fi
- elif [ $RPM = "SUSE" ]; then
+ elif [ "$RPM" = "SUSE" ]; then
# Install this now to avoid using the version from packman repository...
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
install_packages_RPM libjack-devel
fi
@@ -2428,7 +2938,7 @@ install_RPM() {
OGG_DEV="libogg-devel"
THEORA_DEV="libtheora-devel"
- _packages="gcc gcc-c++ git make cmake scons libtiff-devel libjpeg-devel\
+ _packages="gcc gcc-c++ git make cmake libtiff-devel libjpeg-devel\
libpng-devel libX11-devel libXi-devel libXcursor-devel libXrandr-devel libXinerama-devel \
wget ncurses-devel readline-devel $OPENJPEG_DEV openal-soft-devel \
glew-devel yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV patch \
@@ -2439,12 +2949,12 @@ install_RPM() {
OGG_USE=true
THEORA_USE=true
- if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
+ if [ "$RPM" = "FEDORA" -o "$RPM" = "RHEL" ]; then
OPENEXR_DEV="openexr-devel"
_packages="$_packages freetype-devel libsqlite3x-devel fftw-devel SDL-devel"
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
_packages="$_packages jack-audio-connection-kit-devel"
fi
@@ -2459,7 +2969,7 @@ install_RPM() {
X264_USE=true
fi
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
PRINT ""
XVID_DEV="xvidcore-devel"
check_package_RPM $XVID_DEV
@@ -2477,7 +2987,7 @@ install_RPM() {
fi
fi
- elif [ $RPM = "SUSE" ]; then
+ elif [ "$RPM" = "SUSE" ]; then
OPENEXR_DEV="libopenexr-devel"
_packages="$_packages cmake freetype2-devel sqlite3-devel fftw3-devel libSDL-devel"
@@ -2493,7 +3003,7 @@ install_RPM() {
X264_USE=true
fi
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
PRINT ""
XVID_DEV="libxvidcore-devel"
check_package_RPM $XVID_DEV
@@ -2512,7 +3022,14 @@ install_RPM() {
fi
fi
- if $WITH_ALL; then
+ PRINT""
+ SNDFILE_DEV="libsndfile-devel"
+ check_package_RPM $SNDFILE_DEV
+ if [ $? -eq 0 ]; then
+ install_packages_RPM $SNDFILE_DEV
+ fi
+
+ if [ "$WITH_ALL" = true ]; then
PRINT ""
VPX_DEV="libvpx-devel"
check_package_version_ge_RPM $VPX_DEV $VPX_VERSION_MIN
@@ -2524,52 +3041,55 @@ install_RPM() {
install_packages_RPM libspnav-devel
fi
+
PRINT ""
- if $PYTHON_SKIP; then
+ _do_compile_python=false
+ if [ "$PYTHON_SKIP" = true ]; then
WARNING "Skipping Python installation, as requested..."
+ elif [ "$PYTHON_FORCE_BUILD" = true ]; then
+ INFO "Forced Python/NumPy building, as requested..."
+ _do_compile_python=true
else
- _do_compile=false
check_package_version_match_RPM python3-devel $PYTHON_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_RPM python3-devel
+ clean_Python
PRINT ""
- if $NUMPY_SKIP; then
+ if [ "$NUMPY_SKIP" = true ]; then
WARNING "Skipping NumPy installation, as requested..."
else
- check_package_version_match_RPM python3-numpy $NUMPY_VERSION_MIN
+ check_package_version_ge_RPM python3-numpy $NUMPY_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_RPM python3-numpy
- elif $NUMPY_REQUIRED; then
- WARNING "Valid python package but no valid numpy package!" \
- " Building both Python and Numpy from sources!"
- _do_compile=true
else
WARNING "Sorry, using python package but no valid numpy package available!" \
- " Use --required-numpy to force building of both Python and numpy."
+ " Use --build-numpy to force building of both Python and NumPy."
fi
fi
else
- _do_compile=true
+ _do_compile_python=true
fi
+ fi
- if $_do_compile; then
- compile_Python
- PRINT ""
- if $NUMPY_SKIP; then
- WARNING "Skipping NumPy installation, as requested..."
- else
- compile_Numpy
- fi
+ if [ "$_do_compile_python" = true ]; then
+ compile_Python
+ PRINT ""
+ if [ "$NUMPY_SKIP" = true ]; then
+ WARNING "Skipping NumPy installation, as requested..."
else
- clean_Python
+ compile_Numpy
fi
fi
+
PRINT ""
- if $BOOST_SKIP; then
+ if [ "$BOOST_SKIP" = true ]; then
WARNING "Skipping Boost installation, as requested..."
+ elif [ "$BOOST_FORCE_BUILD" = true ]; then
+ INFO "Forced Boost building, as requested..."
+ compile_Boost
else
- check_package_version_ge_RPM boost-devel $BOOST_VERSION
+ check_package_version_ge_RPM boost-devel $BOOST_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_RPM boost-devel
clean_Boost
@@ -2578,9 +3098,13 @@ install_RPM() {
fi
fi
+
PRINT ""
- if $OCIO_SKIP; then
+ if [ "$OCIO_SKIP" = true ]; then
WARNING "Skipping OpenColorIO installation, as requested..."
+ elif [ "$OCIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenColorIO building, as requested..."
+ compile_OCIO
else
# XXX Always force build of own OCIO, until linux distro guys update their package to default libyaml-cpp ver (0.5)!
#check_package_version_ge_RPM OpenColorIO-devel $OCIO_VERSION_MIN
@@ -2593,8 +3117,11 @@ install_RPM() {
fi
PRINT ""
- if $OPENEXR_SKIP; then
- WARNING "Skipping OpenEXR installation, as requested..."
+ if [ "$OPENEXR_SKIP" = true ]; then
+ WARNING "Skipping ILMBase/OpenEXR installation, as requested..."
+ elif [ "$OPENEXR_FORCE_BUILD" = true ]; then
+ INFO "Forced ILMBase/OpenEXR building, as requested..."
+ compile_OPENEXR
else
check_package_version_ge_RPM $OPENEXR_DEV $OPENEXR_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -2608,10 +3135,13 @@ install_RPM() {
fi
PRINT ""
- if $OIIO_SKIP; then
+ if [ "$OIIO_SKIP" = true ]; then
WARNING "Skipping OpenImageIO installation, as requested..."
+ elif [ "$OIIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenImageIO building, as requested..."
+ compile_OIIO
else
- check_package_version_ge_RPM OpenImageIO-devel $OIIO_VERSION_MIN
+ check_package_version_ge_lt_RPM OpenImageIO-devel $OIIO_VERSION_MIN $OIIO_VERSION_MAX
if [ $? -eq 0 -a $_with_built_openexr == false ]; then
install_packages_RPM OpenImageIO-devel
clean_OIIO
@@ -2620,45 +3150,69 @@ install_RPM() {
fi
fi
- have_llvm=false
PRINT ""
- if $LLVM_SKIP; then
+ have_llvm=false
+ _do_compile_llvm=false
+ if [ "$LLVM_SKIP" = true ]; then
WARNING "Skipping LLVM installation, as requested (this also implies skipping OSL!)..."
+ elif [ "$LLVM_FORCE_BUILD" = true ]; then
+ INFO "Forced LLVM building, as requested..."
+ _do_compile_llvm=true
else
# Problem compiling with LLVM 3.2 so match version 3.1 ...
- check_package_version_match_RPM llvm $LLVM_VERSION
- if [ $? -eq 0 ]; then
- if [ $RPM = "SUSE" ]; then
+ if [ "$RPM" = "SUSE" ]; then
+ check_package_version_match_RPM llvm-clang-devel $LLVM_VERSION
+ if [ $? -eq 0 ]; then
install_packages_RPM llvm-devel llvm-clang-devel
+ have_llvm=true
+ LLVM_VERSION_FOUND=$LLVM_VERSION
+ clean_LLVM
else
- install_packages_RPM llvm-devel clang-devel
+ # Better to compile it than use minimum version from repo...
+ _do_compile_llvm=true
fi
- have_llvm=true
- LLVM_VERSION_FOUND=$LLVM_VERSION
- clean_LLVM
else
- #
- # Better to compile it than use minimum version from repo...
- #
- install_packages_RPM libffi-devel
- # LLVM can't find the fedora ffi header dir...
- _FFI_INCLUDE_DIR=`rpm -ql libffi-devel | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'`
- PRINT ""
- compile_LLVM
- have_llvm=true
- LLVM_VERSION_FOUND=$LLVM_VERSION
+ check_package_version_match_RPM clang-devel $LLVM_VERSION
+ if [ $? -eq 0 ]; then
+ install_packages_RPM llvm-devel clang-devel
+ have_llvm=true
+ LLVM_VERSION_FOUND=$LLVM_VERSION
+ clean_LLVM
+ else
+ # Better to compile it than use minimum version from repo...
+ _do_compile_llvm=true
+ fi
fi
fi
+ if [ "$_do_compile_llvm" = true ]; then
+ install_packages_RPM libffi-devel
+ # LLVM can't find the fedora ffi header dir...
+ _FFI_INCLUDE_DIR=`rpm -ql libffi-devel | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'`
+ PRINT ""
+ compile_LLVM
+ have_llvm=true
+ LLVM_VERSION_FOUND=$LLVM_VERSION
+ fi
+
+
PRINT ""
- if $OSL_SKIP; then
+ _do_compile_osl=false
+ if [ "$OSL_SKIP" = true ]; then
WARNING "Skipping OpenShadingLanguage installation, as requested..."
+ elif [ "$OSL_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenShadingLanguage building, as requested..."
+ _do_compile_osl=true
else
- if $have_llvm; then
- # No package currently!
+ # No package currently!
+ _do_compile_osl=true
+ fi
+
+ if [ "$_do_compile_osl" = true ]; then
+ if [ "$have_llvm" = true ]; then
install_packages_RPM flex bison
- if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
+ if [ "$RPM" = "FEDORA" -o "$RPM" = "RHEL" ]; then
install_packages_RPM tbb-devel
fi
PRINT ""
@@ -2668,40 +3222,58 @@ install_RPM() {
fi
fi
+
PRINT ""
- if $OSD_SKIP; then
+ _do_compile_osd=false
+ if [ "$OSD_SKIP" = true ]; then
WARNING "Skipping OpenSubdiv installation, as requested..."
+ elif [ "$OSD_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenSubdiv building, as requested..."
+ _do_compile_osd=true
else
- if $have_llvm; then
- # No package currently!
- install_packages_RPM flex bison
- if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then
- install_packages_RPM tbb-devel
- fi
- PRINT ""
- compile_OSD
- else
- WARNING "No LLVM available, cannot build OSD!"
+ # No package currently!
+ _do_compile_osd=true
+ fi
+
+ if [ "$_do_compile_osd" = true ]; then
+ install_packages_RPM flex bison
+ if [ "$RPM" = "FEDORA" -o "$RPM" = "RHEL" ]; then
+ install_packages_RPM tbb-devel
fi
+ PRINT ""
+ compile_OSD
fi
- if $WITH_OPENCOLLADA; then
+
+ if [ "$WITH_OPENCOLLADA" = true ]; then
PRINT ""
- if $OPENCOLLADA_SKIP; then
+ _do_compile_collada=false
+ if [ "$OPENCOLLADA_SKIP" = true ]; then
WARNING "Skipping OpenCOLLADA installation, as requested..."
+ elif [ "$OPENCOLLADA_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenCollada building, as requested..."
+ _do_compile_collada=true
else
+ # No package...
+ _do_compile_collada=true
+ fi
+
+ if [ "$_do_compile_collada" = true ]; then
install_packages_RPM pcre-devel
# Find path to libxml shared lib...
_XML2_LIB=`rpm -ql libxml2-devel | grep -e ".*/libxml2.so"`
- # No package...
PRINT ""
compile_OpenCOLLADA
fi
fi
+
PRINT ""
- if $FFMPEG_SKIP; then
+ if [ "$FFMPEG_SKIP" = true ]; then
WARNING "Skipping FFMpeg installation, as requested..."
+ elif [ "$FFMPEG_FORCE_BUILD" = true ]; then
+ INFO "Forced FFMpeg building, as requested..."
+ compile_FFmpeg
else
check_package_version_ge_RPM ffmpeg $FFMPEG_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -2751,6 +3323,17 @@ check_package_version_ge_ARCH() {
return $?
}
+check_package_version_ge_lt_ARCH() {
+ v=`get_package_version_ARCH $1`
+
+ if [ -z "$v" ]; then
+ return 1
+ fi
+
+ version_ge_lt $v $2 $3
+ return $?
+}
+
install_packages_ARCH() {
if [ ! $SUDO ]; then
WARNING "--no-sudo enabled, impossible to run pacman for $@, you'll have to do it yourself..."
@@ -2770,8 +3353,10 @@ install_ARCH() {
PRINT "`eval _echo "$COMMON_INFO"`"
PRINT ""
- read -p "Do you want to continue (Y/n)?"
- [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ if [ "$NO_CONFIRM" = false ]; then
+ read -p "Do you want to continue (Y/n)?"
+ [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ fi
# Check for sudo...
if [ $SUDO ]; then
@@ -2798,7 +3383,7 @@ install_ARCH() {
OGG_DEV="libogg"
THEORA_DEV="libtheora"
- _packages="base-devel git scons cmake \
+ _packages="base-devel git cmake \
libxi libxcursor libxrandr libxinerama glew libpng libtiff wget openal \
$OPENJPEG_DEV $VORBIS_DEV $OGG_DEV $THEORA_DEV yasm sdl fftw \
libxml2 yaml-cpp tinyxml"
@@ -2808,7 +3393,7 @@ install_ARCH() {
OGG_USE=true
THEORA_USE=true
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
# No libspacenav in official arch repos...
_packages="$_packages jack"
fi
@@ -2816,6 +3401,13 @@ install_ARCH() {
PRINT ""
install_packages_ARCH $_packages
+ PRINT""
+ SNDFILE_DEV="libsndfile"
+ check_package_ARCH $SNDFILE_DEV
+ if [ $? -eq 0 ]; then
+ install_packages_ARCH $SNDFILE_DEV
+ fi
+
PRINT ""
X264_DEV="x264"
check_package_version_ge_ARCH $X264_DEV $X264_VERSION_MIN
@@ -2824,7 +3416,7 @@ install_ARCH() {
X264_USE=true
fi
- if $WITH_ALL; then
+ if [ "$WITH_ALL" = true ]; then
PRINT ""
XVID_DEV="xvidcore"
check_package_ARCH $XVID_DEV
@@ -2850,52 +3442,55 @@ install_ARCH() {
fi
fi
+
PRINT ""
- if $PYTHON_SKIP; then
+ _do_compile_python=false
+ if [ "$PYTHON_SKIP" = true ]; then
WARNING "Skipping Python installation, as requested..."
+ elif [ "$PYTHON_FORCE_BUILD" = true ]; then
+ INFO "Forced Python/NumPy building, as requested..."
+ _do_compile_python=true
else
- _do_compile=false
check_package_version_ge_ARCH python $PYTHON_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_ARCH python
+ clean_Python
PRINT ""
- if $WITH_NUMPY; then
- if $NUMPY_SKIP; then
+ if [ "$WITH_NUMPY" = true ]; then
+ if [ "$NUMPY_SKIP" = true ]; then
WARNING "Skipping NumPy installation, as requested..."
else
check_package_version_ge_ARCH python-numpy $NUMPY_VERSION_MIN
if [ $? -eq 0 ]; then
install_packages_ARCH python-numpy
- elif $NUMPY_REQUIRED; then
- WARNING "Valid python package but no valid numpy package!" \
- " Building both Python and Numpy from sources!"
- _do_compile=true
else
WARNING "Sorry, using python package but no valid numpy package available!" \
- " Use --required-numpy to force building of both Python and numpy."
+ " Use --build-numpy to force building of both Python and NumPy."
fi
fi
fi
else
- _do_compile=true
+ _do_compile_python=true
fi
+ fi
- if $_do_compile; then
- compile_Python
- PRINT ""
- if $NUMPY_SKIP; then
- WARNING "Skipping NumPy installation, as requested..."
- else
- compile_Numpy
- fi
+ if [ "$_do_compile_python" = true ]; then
+ compile_Python
+ PRINT ""
+ if [ "$NUMPY_SKIP" = true ]; then
+ WARNING "Skipping NumPy installation, as requested..."
else
- clean_Python
+ compile_Numpy
fi
fi
+
PRINT ""
- if $BOOST_SKIP; then
+ if [ "$BOOST_SKIP" = true ]; then
WARNING "Skipping Boost installation, as requested..."
+ elif [ "$BOOST_FORCE_BUILD" = true ]; then
+ INFO "Forced Boost building, as requested..."
+ compile_Boost
else
check_package_version_ge_ARCH boost $BOOST_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -2907,8 +3502,12 @@ install_ARCH() {
fi
PRINT ""
- if $OCIO_SKIP; then
+ _do_compile_ocio=false
+ if [ "$OCIO_SKIP" = true ]; then
WARNING "Skipping OpenColorIO installation, as requested..."
+ elif [ "$OCIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenColorIO building, as requested..."
+ _do_compile_ocio=true
else
# XXX Always force build of own OCIO, until linux distro guys update their package to default libyaml-cpp ver (0.5)!
#check_package_version_ge_ARCH opencolorio $OCIO_VERSION_MIN
@@ -2916,14 +3515,22 @@ install_ARCH() {
#install_packages_ARCH opencolorio yaml-cpp tinyxml
#clean_OCIO
#else
- install_packages_ARCH yaml-cpp tinyxml
- compile_OCIO
+ _do_compile_ocio=true
#fi
fi
+ if [ "$_do_compile_ocio" = true ]; then
+ install_packages_ARCH yaml-cpp tinyxml
+ compile_OCIO
+ fi
+
+
PRINT ""
- if $OPENEXR_SKIP; then
- WARNING "Skipping OpenEXR installation, as requested..."
+ if [ "$OPENEXR_SKIP" = true ]; then
+ WARNING "Skipping ILMBase/OpenEXR installation, as requested..."
+ elif [ "$OPENEXR_FORCE_BUILD" = true ]; then
+ INFO "Forced ILMBase/OpenEXR building, as requested..."
+ compile_OPENEXR
else
check_package_version_ge_ARCH openexr $OPENEXR_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -2936,11 +3543,15 @@ install_ARCH() {
fi
fi
+
PRINT ""
- if $OIIO_SKIP; then
+ if [ "$OIIO_SKIP" = true ]; then
WARNING "Skipping OpenImageIO installation, as requested..."
+ elif [ "$OIIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenImageIO building, as requested..."
+ compile_OIIO
else
- check_package_version_ge_ARCH openimageio $OIIO_VERSION_MIN
+ check_package_version_ge_lt_ARCH openimageio $OIIO_VERSION_MIN $OIIO_VERSION_MAX
if [ $? -eq 0 ]; then
install_packages_ARCH openimageio
clean_OIIO
@@ -2949,88 +3560,123 @@ install_ARCH() {
fi
fi
- have_llvm=false
PRINT ""
- if $LLVM_SKIP; then
+ have_llvm=false
+ _do_compile_llvm=false
+ if [ "$LLVM_SKIP" = true ]; then
WARNING "Skipping LLVM installation, as requested (this also implies skipping OSL!)..."
+ elif [ "$LLVM_FORCE_BUILD" = true ]; then
+ INFO "Forced LLVM building, as requested..."
+ _do_compile_llvm=true
else
- check_package_version_ge_ARCH llvm $LLVM_VERSION_MIN
+ check_package_version_match_ARCH clang $LLVM_VERSION
if [ $? -eq 0 ]; then
install_packages_ARCH llvm clang
have_llvm=true
- LLVM_VERSION=`check_package_version_ge_ARCH llvm $LLVM_VERSION_MIN`
+ LLVM_VERSION=`check_package_version_ge_ARCH clang $LLVM_VERSION_MIN`
LLVM_VERSION_FOUND=$LLVM_VERSION
clean_LLVM
else
- install_packages_ARCH libffi
- # LLVM can't find the arch ffi header dir...
- _FFI_INCLUDE_DIR=`pacman -Ql libffi | grep -e ".*/ffi.h" | awk '{print $2}' | sed -r 's/(.*)\/ffi.h/\1/'`
- # LLVM 3.1 needs python2 to build and arch defaults to python3
- _PYTHON2_BIN="/usr/bin/python2"
- PRINT ""
- compile_LLVM
- have_llvm=true
- LLVM_VERSION_FOUND=$LLVM_VERSION
+ _do_compile_llvm=true
fi
fi
+ if [ "$_do_compile_llvm" = true ]; then
+ install_packages_ARCH libffi
+ # LLVM can't find the arch ffi header dir...
+ _FFI_INCLUDE_DIR=`pacman -Ql libffi | grep -e ".*/ffi.h" | awk '{print $2}' | sed -r 's/(.*)\/ffi.h/\1/'`
+ # LLVM 3.1 needs python2 to build and arch defaults to python3
+ _PYTHON2_BIN="/usr/bin/python2"
+ PRINT ""
+ compile_LLVM
+ have_llvm=true
+ LLVM_VERSION_FOUND=$LLVM_VERSION
+ fi
+
+
PRINT ""
- if $OSL_SKIP; then
+ _do_compile_osl=false
+ if [ "$OSL_SKIP" = true ]; then
WARNING "Skipping OpenShadingLanguage installation, as requested..."
+ elif [ "$OSL_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenShadingLanguage building, as requested..."
+ _do_compile_osl=true
else
- if $have_llvm; then
- check_package_version_ge_ARCH openshadinglanguage $OSL_VERSION_MIN
- if [ $? -eq 0 ]; then
- install_packages_ARCH openshadinglanguage
- clean_OSL
- else
- #XXX Note: will fail to build with LLVM 3.2!
- install_packages_ARCH intel-tbb
- PRINT ""
- compile_OSL
- fi
+ check_package_version_ge_ARCH openshadinglanguage $OSL_VERSION_MIN
+ if [ $? -eq 0 ]; then
+ install_packages_ARCH openshadinglanguage
+ clean_OSL
else
- WARNING "No LLVM available, cannot build OSL!"
+ _do_compile_osl=true
fi
fi
- PRINT ""
- if $OSD_SKIP; then
- WARNING "Skipping OpenSubdiv installation, as requested..."
- else
- if $have_llvm; then
- # No package currently? Just build for now!
+ if [ "$_do_compile_osl" = true ]; then
+ if [ "$have_llvm" = true ]; then
+ #XXX Note: will fail to build with LLVM 3.2!
install_packages_ARCH intel-tbb
PRINT ""
- compile_OSD
+ compile_OSL
else
- WARNING "No LLVM available, cannot build OSD!"
+ WARNING "No LLVM available, cannot build OSL!"
fi
fi
- if $WITH_OPENCOLLADA; then
+
+ PRINT ""
+ _do_compile_osd=false
+ if [ "$OSD_SKIP" = true ]; then
+ WARNING "Skipping OpenSubdiv installation, as requested..."
+ elif [ "$OSD_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenSubdiv building, as requested..."
+ _do_compile_osd=true
+ else
+ # No package currently? Just build for now!
+ _do_compile_osd=true
+ fi
+
+ if [ "$_do_compile_osd" = true ]; then
+ install_packages_ARCH intel-tbb
+ PRINT ""
+ compile_OSD
+ fi
+
+
+ if [ "$WITH_OPENCOLLADA" = true ]; then
PRINT ""
- if $OPENCOLLADA_SKIP; then
+ _do_compile_collada=false
+ if [ "$OPENCOLLADA_SKIP" = true ]; then
WARNING "Skipping OpenCOLLADA installation, as requested..."
+ elif [ "$OPENCOLLADA_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenCollada building, as requested..."
+ _do_compile_collada=true
else
check_package_ARCH opencollada
if [ $? -eq 0 ]; then
install_packages_ARCH opencollada
clean_OpenCOLLADA
else
- install_packages_ARCH pcre
- PRINT ""
- compile_OpenCOLLADA
+ _do_compile_collada=true
fi
- # Find path to libxml shared lib...
- _XML2_LIB=`pacman -Ql libxml2 | grep -e ".*/libxml2.so$" | gawk '{print $2}'`
+ fi
+
+ if [ "$_do_compile_collada" = true ]; then
+ install_packages_ARCH pcre
+ # Find path to libxml shared lib...
+ _XML2_LIB=`pacman -Ql libxml2 | grep -e ".*/libxml2.so$" | gawk '{print $2}'`
+ PRINT ""
+ compile_OpenCOLLADA
fi
fi
+
PRINT ""
- if $FFMPEG_SKIP; then
+ if [ "$FFMPEG_SKIP" = true ]; then
WARNING "Skipping FFMpeg installation, as requested..."
+ elif [ "$FFMPEG_FORCE_BUILD" = true ]; then
+ INFO "Forced FFMpeg building, as requested..."
+ compile_FFmpeg
else
check_package_version_ge_ARCH ffmpeg $FFMPEG_VERSION_MIN
if [ $? -eq 0 ]; then
@@ -3043,6 +3689,177 @@ install_ARCH() {
}
+#### Install on other distro (very limited!) ####
+
+install_OTHER() {
+ PRINT ""
+ WARNING "Attempt to build main dependencies for other linux distributions."
+ PRINT ""
+ PRINT "`eval _echo "$COMMON_INFO"`"
+ PRINT ""
+
+ ERROR "Failed to detect distribution type."
+ PRINT ""
+ PRINT "Your distribution is not supported by this script, you'll have to install dependencies and"
+ PRINT "dev packages yourself. However, this script can still attempt to build main (complex) libraries for you,"
+ PRINT "if you use '--build-foo' options (you can try '--build-all' one first)."
+ PRINT ""
+ PRINT "Quite obviously, it assumes dependencies from those libraries are already available, otherwise please"
+ PRINT "install them (you can also use error messages printed out by build process to find missing libraries...)."
+ PRINT ""
+ PRINT "`eval _echo "$DEPS_COMMON_INFO"`"
+ PRINT ""
+ PRINT "`eval _echo "$DEPS_SPECIFIC_INFO"`"
+ PRINT ""
+
+ if [ "$NO_CONFIRM" = false ]; then
+ read -p "Do you want to continue (Y/n)?"
+ [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit
+ fi
+
+ PRINT ""
+ _do_compile_python=false
+ if [ "$PYTHON_SKIP" = true ]; then
+ WARNING "Skipping Python/NumPy installation, as requested..."
+ elif [ "$PYTHON_FORCE_BUILD" = true ]; then
+ INFO "Forced Python/NumPy building, as requested..."
+ _do_compile_python=true
+ fi
+
+ if [ "$_do_compile_python" = true ]; then
+ compile_Python
+ PRINT ""
+ if [ "$NUMPY_SKIP" = true ]; then
+ WARNING "Skipping NumPy installation, as requested..."
+ else
+ compile_Numpy
+ fi
+ fi
+
+
+ PRINT ""
+ if [ "$BOOST_SKIP" = true ]; then
+ WARNING "Skipping Boost installation, as requested..."
+ elif [ "$BOOST_FORCE_BUILD" = true ]; then
+ INFO "Forced Boost building, as requested..."
+ compile_Boost
+ fi
+
+
+ PRINT ""
+ if [ "$OCIO_SKIP" = true ]; then
+ WARNING "Skipping OpenColorIO installation, as requested..."
+ elif [ "$OCIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenColorIO building, as requested..."
+ compile_OCIO
+ fi
+
+
+ PRINT ""
+ if [ "$OPENEXR_SKIP" = true ]; then
+ WARNING "Skipping ILMBase/OpenEXR installation, as requested..."
+ elif [ "$OPENEXR_FORCE_BUILD" = true ]; then
+ INFO "Forced ILMBase/OpenEXR building, as requested..."
+ compile_OPENEXR
+ fi
+
+
+ PRINT ""
+ if [ "$OIIO_SKIP" = true ]; then
+ WARNING "Skipping OpenImageIO installation, as requested..."
+ elif [ "$OIIO_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenImageIO building, as requested..."
+ compile_OIIO
+ fi
+
+
+ PRINT ""
+ have_llvm=false
+ _do_compile_llvm=false
+ if [ "$LLVM_SKIP" = true ]; then
+ WARNING "Skipping LLVM installation, as requested (this also implies skipping OSL!)..."
+ elif [ "$LLVM_FORCE_BUILD" = true ]; then
+ INFO "Forced LLVM building, as requested..."
+ _do_compile_llvm=true
+ fi
+
+ if [ "$_do_compile_llvm" = true ]; then
+ install_packages_DEB libffi-dev
+ # LLVM can't find the debian ffi header dir
+ _FFI_INCLUDE_DIR=`dpkg -L libffi-dev | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'`
+ PRINT ""
+ compile_LLVM
+ have_llvm=true
+ LLVM_VERSION_FOUND=$LLVM_VERSION
+ fi
+
+
+ PRINT ""
+ _do_compile_osl=false
+ if [ "$OSL_SKIP" = true ]; then
+ WARNING "Skipping OpenShadingLanguage installation, as requested..."
+ elif [ "$OSL_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenShadingLanguage building, as requested..."
+ _do_compile_osl=true
+ fi
+
+ if [ "$_do_compile_osl" = true ]; then
+ if [ "$have_llvm" = true ]; then
+ install_packages_DEB flex bison libtbb-dev
+ PRINT ""
+ compile_OSL
+ else
+ WARNING "No LLVM available, cannot build OSL!"
+ fi
+ fi
+
+
+ PRINT ""
+ _do_compile_osd=false
+ if [ "$OSD_SKIP" = true ]; then
+ WARNING "Skipping OpenSubdiv installation, as requested..."
+ elif [ "$OSD_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenSubdiv building, as requested..."
+ _do_compile_osd=true
+ fi
+
+ if [ "$_do_compile_osd" = true ]; then
+ install_packages_DEB flex bison libtbb-dev
+ PRINT ""
+ compile_OSD
+ fi
+
+
+ if [ "$WITH_OPENCOLLADA" = true ]; then
+ _do_compile_collada=false
+ PRINT ""
+ if [ "$OPENCOLLADA_SKIP" = true ]; then
+ WARNING "Skipping OpenCOLLADA installation, as requested..."
+ elif [ "$OPENCOLLADA_FORCE_BUILD" = true ]; then
+ INFO "Forced OpenCollada building, as requested..."
+ _do_compile_collada=true
+ fi
+
+ if [ "$_do_compile_collada" = true ]; then
+ install_packages_DEB libpcre3-dev
+ # Find path to libxml shared lib...
+ _XML2_LIB=`dpkg -L libxml2-dev | grep -e ".*/libxml2.so"`
+ # No package
+ PRINT ""
+ compile_OpenCOLLADA
+ fi
+ fi
+
+
+ PRINT ""
+ if [ "$FFMPEG_SKIP" = true ]; then
+ WARNING "Skipping FFMpeg installation, as requested..."
+ elif [ "$FFMPEG_FORCE_BUILD" = true ]; then
+ INFO "Forced FFMpeg building, as requested..."
+ compile_FFmpeg
+ fi
+}
+
#### Printing User Info ####
print_info_ffmpeglink_DEB() {
@@ -3067,35 +3884,35 @@ print_info_ffmpeglink() {
# Create list of packages from which to get libs names...
_packages=""
- if $THEORA_USE; then
+ if [ "$THEORA_USE" = true ]; then
_packages="$_packages $THEORA_DEV"
fi
- if $VORBIS_USE; then
+ if [ "$VORBIS_USE" = true ]; then
_packages="$_packages $VORBIS_DEV"
fi
- if $OGG_USE; then
+ if [ "$OGG_USE" = true ]; then
_packages="$_packages $OGG_DEV"
fi
- if $XVID_USE; then
+ if [ "$XVID_USE" = true ]; then
_packages="$_packages $XVID_DEV"
fi
- if $VPX_USE; then
+ if [ "$VPX_USE" = true ]; then
_packages="$_packages $VPX_DEV"
fi
- if $MP3LAME_USE; then
+ if [ "$MP3LAME_USE" = true ]; then
_packages="$_packages $MP3LAME_DEV"
fi
- if $X264_USE; then
+ if [ "$X264_USE" = true ]; then
_packages="$_packages $X264_DEV"
fi
- if $OPENJPEG_USE; then
+ if [ "$OPENJPEG_USE" = true ]; then
_packages="$_packages $OPENJPEG_DEV"
fi
@@ -3106,7 +3923,8 @@ print_info_ffmpeglink() {
elif [ "$DISTRO" = "ARCH" ]; then
print_info_ffmpeglink_ARCH
# XXX TODO!
- else PRINT "<Could not determine additional link libraries needed for ffmpeg, replace this by valid list of libs...>"
+ else
+ PRINT "<Could not determine additional link libraries needed for ffmpeg, replace this by valid list of libs...>"
fi
}
@@ -3119,11 +3937,27 @@ print_info() {
PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!"
PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..."
PRINT ""
+ PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages"
+ PRINT "for some troublesome/buggy libraries..."
+ PRINT ""
+ PRINT ""
+ PRINT "Ran with:"
+ PRINT " install_deps.sh $COMMANDLINE"
+ PRINT ""
PRINT ""
PRINT "If you're using CMake add this to your configuration flags:"
- _buildargs=""
+ _buildargs="-U *SNDFILE* -U *PYTHON* -U *BOOST* -U *Boost*"
+ _buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
+ _buildargs="$_buildargs -U *OPENSUBDIV* -U *COLLADA* -U *FFMPEG*"
+
+ _1="-D WITH_CODEC_SNDFILE=ON"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
+ _1="-D PYTHON_VERSION=$PYTHON_VERSION_MIN"
+ PRINT " $_1"
+ _buildargs="$_buildargs $_1"
if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then
_1="-D PYTHON_ROOT_DIR=$INST/python-$PYTHON_VERSION_MIN"
PRINT " $_1"
@@ -3139,9 +3973,11 @@ print_info() {
fi
if [ -d $INST/ocio ]; then
- _1="-D OPENCOLORIO_ROOT_DIR=$INST/ocio"
+ _1="-D WITH_OPENCOLORIO=ON"
+ _2="-D OPENCOLORIO_ROOT_DIR=$INST/ocio"
PRINT " $_1"
- _buildargs="$_buildargs $_1"
+ PRINT " $_2"
+ _buildargs="$_buildargs $_1 $_2"
fi
if [ -d $INST/openexr ]; then
@@ -3151,9 +3987,11 @@ print_info() {
fi
if [ -d $INST/oiio ]; then
- _1="-D OPENIMAGEIO_ROOT_DIR=$INST/oiio"
+ _1="-D WITH_OPENIMAGEIO=ON"
+ _2="-D OPENIMAGEIO_ROOT_DIR=$INST/oiio"
PRINT " $_1"
- _buildargs="$_buildargs $_1"
+ PRINT " $_2"
+ _buildargs="$_buildargs $_1 $_2"
fi
if [ "$OSL_SKIP" = false ]; then
@@ -3192,7 +4030,7 @@ print_info() {
_buildargs="$_buildargs $_1 $_2"
fi
- if $WITH_OPENCOLLADA; then
+ if [ "$WITH_OPENCOLLADA" = true ]; then
_1="-D WITH_OPENCOLLADA=ON"
PRINT " $_1"
_buildargs="$_buildargs $_1"
@@ -3200,7 +4038,7 @@ print_info() {
if [ "$FFMPEG_SKIP" = false ]; then
_1="-D WITH_CODEC_FFMPEG=ON"
- _2="-D FFMPEG_LIBRARIES='avformat;avcodec;avutil;avdevice;swscale;rt;`print_info_ffmpeglink`'"
+ _2="-D FFMPEG_LIBRARIES='avformat;avcodec;avutil;avdevice;swscale;swresample;lzma;rt;`print_info_ffmpeglink`'"
PRINT " $_1"
PRINT " $_2"
_buildargs="$_buildargs $_1 $_2"
@@ -3214,89 +4052,6 @@ print_info() {
PRINT ""
PRINT "Or even simpler, just run (in your blender-source dir):"
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
-
- PRINT ""
- PRINT "If you're using SCons add this to your user-config:"
-
- if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then
- PRINT "BF_PYTHON = '$INST/python-$PYTHON_VERSION_MIN'"
- PRINT "BF_PYTHON_ABI_FLAGS = 'm'"
- fi
-
- if [ "$OCIO_SKIP" = false ]; then
- PRINT "WITH_BF_OCIO = True"
- if [ -d $INST/ocio ]; then
- PRINT "BF_OCIO = '$INST/ocio'"
- fi
- fi
-
- if [ -d $INST/openexr ]; then
- PRINT "BF_OPENEXR = '$INST/openexr'"
-
- _ilm_libs_ext=""
- #~ version_ge $OPENEXR_VERSION "2.1.0"
- #~ if [ $? -eq 0 ]; then
- #~ _ilm_libs_ext=`echo $OPENEXR_VERSION | sed -r 's/([0-9]+)\.([0-9]+).*/-\1_\2/'`
- #~ fi
- PRINT "BF_OPENEXR_LIB = 'Half IlmImf$_ilm_libs_ext Iex$_ilm_libs_ext Imath$_ilm_libs_ext '"
- # BF_OPENEXR_LIB does not work, things like '-lIlmImf-2_1' do not suit ld.
- # For now, hack around!!!
- PRINT "BF_OPENEXR_LIB_STATIC = '\${BF_OPENEXR}/lib/libHalf.so \${BF_OPENEXR}/lib/libIlmImf$_ilm_libs_ext.so \${BF_OPENEXR}/lib/libIex$_ilm_libs_ext.so \${BF_OPENEXR}/lib/libImath$_ilm_libs_ext.so \${BF_OPENEXR}/lib/libIlmThread$_ilm_libs_ext.so'"
- PRINT "WITH_BF_STATICOPENEXR = True"
- fi
-
- if [ "$OIIO_SKIP" = false ]; then
- PRINT "WITH_BF_OIIO = True"
- if [ -d $INST/oiio ]; then
- PRINT "BF_OIIO = '$INST/oiio'"
- fi
- fi
-
- PRINT "WITH_BF_CYCLES = True"
-
- if [ -d $INST/osl ]; then
- PRINT "BF_OSL = '$INST/osl'"
- fi
-
- if [ "$OSD_SKIP" = false ]; then
- PRINT "WITH_BF_OPENSUBDIV = True"
- if [ -d $INST/osd ]; then
- PRINT "BF_OPENSUBDIV = '$INST/osd'"
- fi
- fi
-
- if [ "$BOOST_SKIP" = false ]; then
- PRINT "WITH_BF_BOOST = True"
- if [ -d $INST/boost ]; then
- PRINT "BF_BOOST = '$INST/boost'"
- fi
- fi
-
- if $WITH_OPENCOLLADA; then
- PRINT "WITH_BF_COLLADA = True"
- if [ -d $INST/opencollada ]; then
- PRINT "BF_OPENCOLLADA = '$INST/opencollada'"
- fi
- fi
-
- if [ "$FFMPEG_SKIP" = false ]; then
- _ffmpeg_list_sep=" "
- if [ -d $INST/ffmpeg ]; then
- PRINT "BF_FFMPEG = '$INST/ffmpeg'"
- fi
- PRINT "BF_FFMPEG_LIB = 'avformat avcodec swscale avutil avdevice `print_info_ffmpeglink`'"
- fi
-
- if [ "$WITH_ALL" = false ]; then
- PRINT "WITH_BF_3DMOUSE = False"
- # No libspacenav in official arch repos...
- elif [ "$DISTRO" = "ARCH" ]; then
- PRINT "WITH_BF_3DMOUSE = False"
- fi
-
- if $WITH_OPENCOLLADA; then
- PRINT "LLIBS = [\""xml2"\", \""expat"\"] + LLIBS"
- fi
}
#### "Main" ####
@@ -3311,28 +4066,8 @@ elif [ -f /etc/redhat-release -o /etc/SuSE-release ]; then
DISTRO="RPM"
install_RPM
else
- ERROR "Failed to detect distribution type."
- PRINT ""
- PRINT "Your distribution is not supported by this script, you'll have to install dependencies and"
- PRINT "dev packages yourself (list non-exhaustive, but should cover most needs):"
- PRINT " * Basics of dev environment (cmake or scons, gcc, svn , git, ...)."
- PRINT " * Python$PYTHON_VERSION_MIN, numpy."
- PRINT " * libboost$BOOST_VERSION_MIN (locale, filesystem, regex, system, thread, wave)."
- PRINT " * libjpeg, libpng, libtiff, libopenjpeg, libopenal."
- PRINT " * ffmpeg (with libvorbis, libogg, libtheora, libx264, libmp3lame, libxvidcore, libvpx, ...)."
- PRINT " * libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed)."
- PRINT " * libsqlite3, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp."
- PRINT " * libsdl1.2, libglew, libglewmx."
- PRINT " * libopencolorio$OCIO_VERSION_MIN, libopenexr$OPENEXR_VERSION_MIN, libopenimageio$OIIO_VERSION_MIN."
- PRINT " * llvm-$LLVM_VERSION (with clang)."
- PRINT ""
- PRINT "Most of up-listed packages are available in recent distributions. The following are likely not,"
- PRINT "you'll have to build them (they are all optional, though):"
- PRINT " * OpenShadingLanguage (from https://github.com/Nazg-Gul/OpenShadingLanguage.git, branch blender-fixes, commit 22ee5ea298fd215430dfbd160b5aefd507f06db0)."
- PRINT " * OpenSubDiv (from https://github.com/PixarAnimationStudios/OpenSubdiv.git, branch dev, commit 404659fffa659da075d1c9416e4fc939139a84ee)."
- PRINT " * OpenCollada (from https://github.com/KhronosGroup/OpenCOLLADA.git, branch master, commit 3335ac164e68b2512a40914b14c74db260e6ff7d)."
- PRINT ""
- exit 1
+ DISTRO="OTHER"
+ install_OTHER
fi
print_info | tee $INFO_PATH/BUILD_NOTES.txt
diff --git a/build_files/build_environment/install_deps_patches/llvm.patch b/build_files/build_environment/install_deps_patches/llvm.patch
new file mode 100644
index 00000000000..2e05c334569
--- /dev/null
+++ b/build_files/build_environment/install_deps_patches/llvm.patch
@@ -0,0 +1,12 @@
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -13,7 +13,7 @@
+ set(LLVM_VERSION_MAJOR 3)
+ set(LLVM_VERSION_MINOR 1)
+
+-set(PACKAGE_VERSION "\${LLVM_VERSION_MAJOR}.\${LLVM_VERSION_MINOR}svn")
++set(PACKAGE_VERSION "\${LLVM_VERSION_MAJOR}.\${LLVM_VERSION_MINOR}")
+
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+
diff --git a/build_files/build_environment/install_deps_patches/osl.patch b/build_files/build_environment/install_deps_patches/osl.patch
new file mode 100644
index 00000000000..3b52403f740
--- /dev/null
+++ b/build_files/build_environment/install_deps_patches/osl.patch
@@ -0,0 +1,12 @@
+--- a/src/shaders/CMakeLists.txt
++++ b/src/shaders/CMakeLists.txt
+@@ -27,7 +27,7 @@ macro (osl_compile oslsrc objlist headers)
+ message (STATUS "cmd: ${CMAKE_CURRENT_BINARY_DIR}/../oslc/oslc ${oslsrc}")
+ endif ()
+ add_custom_command (OUTPUT ${osofile}
+- COMMAND "${CMAKE_CURRENT_BINARY_DIR}/../oslc/oslc" ${oslsrc}
++ COMMAND "${CMAKE_CURRENT_BINARY_DIR}/../oslc/oslc" "-o" ${osofile} ${oslsrc}
+ MAIN_DEPENDENCY ${oslsrc}
+ DEPENDS ${${headers}} ${oslsrc} "${CMAKE_CURRENT_BINARY_DIR}/stdosl.h" "${CMAKE_CURRENT_BINARY_DIR}/../oslc/oslc"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
diff --git a/build_files/build_environment/prepare_release_env.sh b/build_files/build_environment/prepare_release_env.sh
deleted file mode 100755
index f003507b25f..00000000000
--- a/build_files/build_environment/prepare_release_env.sh
+++ /dev/null
@@ -1,1555 +0,0 @@
-#!/bin/sh
-
-#
-# This script will prepare build environment with the same settings as release environment
-#
-# It will install two chroot environments:
-# - /home/buildbot_squeeze_i686
-# - /home/buildbot_squeeze_x86_64
-# which are used for 32bit and 64bit
-#
-# This sctipt will also create folder /home/sources where all dependent libraries sources are
-# downloading and compiling.
-#
-# Release builder scripts are stored in /home/sources/release-builder
-# See build_all.sh script for usage details
-#
-# This script was tested on debian squeeze and wheezy, should work on ubuntu as well
-# It wouldn't work on other distros
-#
-# TODO:
-# - It's still required manual copying of build configuration files to /home/sources/release-builder/config
-# - OSL is not set up yet
-#
-
-set -e
-
-NO_COLOR='\033[0m'
-EWHITE='\033[1;37m'
-ERED='\033[1;31m'
-
-CONFIRM="--i-really-do-know-what-im-doing"
-
-ERROR() {
- echo ${ERED}${@}${NO_COLOR}
-}
-
-INFO() {
- echo ${EWHITE}${@}${NO_COLOR}
-}
-
-if [ $# != 1 ]; then
- ERROR "Usage: $0 $CONFIRM"
- exit 1
-fi
-
-if [ "$1" != "$CONFIRM" ]; then
- ERROR "Usage: $0 $CONFIRM"
- exit 1
-fi
-
-DEBIAN_BRANCH="squeeze"
-DEBIAN_MIRROR="http://ftp.de.debian.org/debian"
-USER_ID=1000
-
-# For now it's always /home, so we can setup schroot to map /sources to the same
-# path at both host and chroot systems (which is currently needed for release building script)
-ENV_PATH="/home"
-
-AMD64_PATH="$ENV_PATH/buildbot_${DEBIAN_BRANCH}_x86_64"
-I686_PATH="$ENV_PATH/buildbot_${DEBIAN_BRANCH}_i686"
-SOURCES_PATH="$ENV_PATH/sources"
-
-THREADS=$(nproc)
-
-# Force vpx be installed from the backports
-VPX_V="1.0.0-2~bpo60+1"
-
-BINUTILS_V="2.22"
-BINUTILS_FV="2.22-7.1"
-
-GCC_V="4.7_4.7.1"
-GCC_FV="4.7_4.7.1-7"
-
-OPENAL_V="1.14"
-
-DPKG_V="1.16.8"
-
-DEBHELPER_V="9"
-DEBHELPER_FV="9.20120909"
-
-JEMALLOC_V="3.1.0"
-SPNAV_V="0.2.2"
-FFMPEG_V="1.0"
-BOOST_V="1_51_0"
-PYTHON_V="3.3.0"
-PYTHIN_V_SHORT="3.3"
-OIIO_V="1.0.9"
-OCIO_V="1.0.7"
-MESA_V="8.0.5"
-
-OPENSSL_V="0.9.8o"
-OPENSSL_FV="0.9.8o-4squeeze13"
-
-CUDA_V="4.2.9"
-CUDA_DISTR="ubuntu10.04"
-CUDA_32="cudatoolkit_${CUDA_V}_linux_32_${CUDA_DISTR}.run"
-CUDA_64="cudatoolkit_${CUDA_V}_linux_64_${CUDA_DISTR}.run"
-
-INSTALL_RELEASE_BUILDER() {
- SOURCES_PATH=$1
-
- RB=$SOURCES_PATH/release-builder
- if [ ! -d $RB ]; then
- INFO "Installing release building scripts"
-
- mkdir -p $RB
-
- cat << EOF > $RB/Readme.txt
-This directory contains scrips needed for automated release archive preparation
-
-config/: storage of scons configs for different platforms
-
-build_all.sh: script asks version to add to archive name and revision to compile,
- when script finished, there'll be 32 and 64 bit archives in current directory
- better to run this script from this directory
-
-do_build_all.sh: uses environment variables set by build_all.sh script (or other scripts)
- and launches compilation inside chroot environments
-
-chroot_compile.py: runs compilation process with giver parameters in chroots
-compile.py: script runs inside chroot environment and prepares archive
-
-blender-buildenv.tar.bz2: archive, received from Ken Hughes when i've been preparing
- new environment to make it as close to old one as it's possible
-
-Hope all this would help you.
-
--Sergey-
-EOF
-
- cat << EOF > $RB/build_all.sh
-#!/bin/sh
-
-echo -n "version: "
-read version
-echo -n "svn revision (blank to latest, 0 to keep unchanged): "
-read revision
-
-export version
-export revision
-
-d=\`dirname \${0}\`
-\${d}/do_build_all.sh
-EOF
- chmod +x $RB/build_all.sh
-
- cat << EOF > $RB/build_all-test.sh
-#!/bin/sh
-
-d=\`dirname \${0}\`
-\${d}/do_build_all.sh
-EOF
- chmod +x $RB/build_all-test.sh
-
- cat << EOF > $RB/chroot-compile.py
-#!/usr/bin/env python
-
-import sys
-import os
-import platform
-
-from optparse import OptionParser
-
-# This could be passed through options, but does we actually need this?
-bl_source = '/home/sources/blender'
-build_dir = '/home/sources/blender-build/'
-install_dir = '/home/sources/blender-install/'
-with_player = True
-
-# Default config
-curr_arch = platform.architecture()[0]
-def_arch = 'x86_64' if curr_arch == '64bit' else 'i686'
-builder_dir = os.path.dirname(os.path.realpath(__file__))
-
-# XXX: bad thing!
-# builder_dir = builder_dir.replace("sources-new", "sources")
-
-def_cores = 1
-if hasattr(os, 'sysconf'):
- if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
- def_cores = os.sysconf('SC_NPROCESSORS_ONLN')
-
-# Per-architecture chroot name
-chroots = { 'i686': 'buildbot_squeeze_i686',
- 'x86_64': 'buildbot_squeeze_x86_64'}
-
-# Parse command line
-op = OptionParser()
-op.add_option('--tag', default = None)
-op.add_option('--branch', default = None)
-op.add_option('--arch', default = def_arch)
-op.add_option('--cores', default = def_cores)
-op.add_option('--bl-version', default = 'UNDEFINED')
-op.add_option('--no-clean', default = False)
-(opts, args) = op.parse_args()
-
-if opts.arch not in chroots:
- print('Error: No configured machine gound to build ' +
- '{0} version' . format(opts.arch))
- sys.exit(1)
-
-chroot = chroots[opts.arch]
-
-if opts.tag:
- bl_source = '/home/sources/blender-tags/' + opts.tag
-elif opts.branch:
- bl_source = '/home/sources/blender-branches/' + opts.branch
-
-if not os.path.isdir(bl_source):
- print('Uname to find directory with sources: ' + bl_source)
- sys.exit(1)
-
-print('Building {0} version, machine is {1}' . format(opts.bl_version, opts.arch))
-
-# Assume builder directory is binded to the same location in
-# chroot environments
-compiler = os.path.join(builder_dir, 'compile.py')
-
-cmd = 'schroot -c %s -d /home/sources/release-builder --' % (chroot)
-cmd += ' python %s' % (compiler)
-cmd += ' --bl-version=%s' % (opts.bl_version)
-cmd += ' --bl-source=%s' % (bl_source)
-cmd += ' --arch=%s' % (opts.arch)
-cmd += ' --build-dir=%s' % (build_dir)
-cmd += ' --install-dir=%s' % (install_dir)
-
-if opts.no_clean:
- cmd += ' --no-clean=1'
-
-if with_player:
- cmd += ' --with-player=1'
-
-#if opts.branch:
-# cmd += ' --use-new-ffmpeg=1'
-
-result = os.system(cmd)
-if result != 0:
- print('compiler script exited with errcode: %s' % (result))
- sys.exit(1)
-EOF
- chmod +x $RB/chroot-compile.py
-
- cat << EOF > $RB/compile.py
-#!/usr/bin/env python
-
-import platform
-import sys
-import os
-import shutil
-
-from optparse import OptionParser
-
-# Default config
-curr_arch = platform.architecture()[0]
-def_arch = 'x86_64' if curr_arch == '64bit' else 'i686'
-builder_dir = os.path.dirname(os.path.realpath(__file__))
-
-def_cores = 1
-if hasattr(os, 'sysconf'):
- if 'SC_NPROCESSORS_ONLN' in os.sysconf_names:
- def_cores = os.sysconf('SC_NPROCESSORS_ONLN')
-
-# Parse command line
-op = OptionParser()
-op.add_option('--arch', default = def_arch)
-op.add_option('--cores', default = def_cores)
-op.add_option('--no-clean', default = False)
-op.add_option('--bl-version', default = 'UNKNOWN')
-op.add_option('--bl-source', default = '')
-op.add_option('--config-dir', default = '')
-op.add_option('--build-dir', default = '')
-op.add_option('--install-dir', default = '')
-op.add_option('--with-player', default = False)
-#op.add_option('--use-new-ffmpeg', default = False)
-(opts, args) = op.parse_args()
-
-if opts.config_dir == '':
- opts.config_dir = os.path.join(builder_dir, 'config')
-
-# Initial directory checking (could be problems with permissions)
-if not os.path.isdir(opts.bl_source):
- print('Blender\'s source tree not found: %s' % (opts.bl_source))
- sys.exit(1)
-
-if not os.path.isdir(opts.config_dir):
- print('Directory with configuration files not found: %s' % (opts.config_dir))
- sys.exit(1)
-
-if not os.path.isdir(os.path.dirname(opts.build_dir)):
- print('Build directory can\'t be reached: %s' % (opts.build_dir))
- sys.exit(1)
-
-if not os.path.isdir(os.path.dirname(opts.install_dir)):
- print('Install directory can\'t be reached: %s' % (opts.install_dir))
- sys.exit(1)
-
-# Detect glibc version
-libc = [name for name in os.listdir('/lib') if 'libc.so.' in name]
-if len(libc) == 0:
- print('Could not find "/lib/libc.so.*": cannot determine glibc version')
- sys.exit(-1)
-
-if len(libc) > 1:
- print('warning: found more than one "/lib/libc.so.*": '+
- 'using %s' % (libc[0]))
-
-glibc = 'glibc' + os.readlink('/lib/' + libc[0])[5:][:-3].replace('.', '')
-glibc = glibc[:8]
-
-# Full name for archive
-full_name = 'blender-%s-linux-%s-%s' % (opts.bl_version, glibc, opts.arch)
-build_dir = os.path.join(opts.build_dir, full_name)
-install_dir = os.path.join(opts.install_dir, full_name)
-scons = os.path.join(opts.bl_source, 'scons', 'scons.py')
-scons_cmd = 'python %s -C %s' % (scons, opts.bl_source)
-config = os.path.join(opts.config_dir, 'user-config-' + glibc + '-' + opts.arch + '.py')
-
-if not os.path.isfile(config):
- print('Configuration file not found: %s' % (config))
- sys.exit(1)
-
-# Clean build directory
-if not opts.no_clean:
- print('Cleaning up build directory...')
- os.system('%s BF_BUILDDIR=%s clean ' % (scons_cmd, build_dir))
-
-# Clean install directory
-if os.path.isdir(install_dir):
- shutil.rmtree(install_dir)
-
-flags = ""
-
-# Switch to newer libraries if needed
-#if opts.use_new_ffmpeg:
-# print("Using new ffmpeg-0.8.1")
-# flags += " BF_FFMPEG='/home/sources/staticlibs/ffmpeg-0.8'"
-
-# Build blenderplayer first
-# (to be sure all stuff needed for blender would copied automatically)
-if opts.with_player:
- player_config = os.path.join(opts.config_dir,
- 'user-config-player-' + glibc + '-' + opts.arch + '.py')
-
- if not os.path.isfile(player_config):
- print('Player configuration file not found: %s' % (player_config))
- sys.exit(1)
-
- cmd = '%s -j %d blenderplayer ' % (scons_cmd, opts.cores + 1)
- cmd += ' BF_BUILDDIR=%s' % (build_dir + '-player')
- cmd += ' BF_INSTALLDIR=%s' % (install_dir)
- cmd += ' BF_CONFIG=%s' % (player_config)
- cmd += flags
-
- result = os.system(cmd)
- if result != 0:
- print('Compilation failed, exit code is %d' % (result))
- sys.exit(-1)
-
-# Build blender itself
-cmd = '%s -j %d blender ' % (scons_cmd, opts.cores + 1)
-cmd += ' BF_BUILDDIR=%s' % (build_dir)
-cmd += ' BF_INSTALLDIR=%s' % (install_dir)
-cmd += ' BF_CONFIG=%s' % (config)
-cmd += flags
-
-result = os.system(cmd)
-if result != 0:
- print('Compilation failed, exit code is %d' % (result))
- sys.exit(-1)
-
-blender = os.path.join(install_dir, 'blender')
-blenderplayer = blender + 'player'
-
-if not os.path.exists(blender):
- print('scons completed successfully but blender executable missing')
- sys.exit(1)
-
-if opts.with_player and not os.path.exists(blenderplayer):
- print('scons completed successfully but blenderplayer executable missing')
- sys.exit(1)
-
-# compile python modules
-#result = os.system('%s --background --python %s/source/tools/compile_scripts.py' % (blender, opts.bl_source))
-#if result != 0:
-# print('Python modules compilation failed, exit code is %d' % (result))
-# sys.exit(-1)
-
-print('build successful')
-
-os.system('strip -s %s %s' % (blender, blenderplayer))
-
-# Copy all texts needed for release
-release_texts = os.path.join(opts.bl_source, 'release', 'text', '*')
-release_txt = os.path.join(install_dir, 'release_%s.txt' % (opts.bl_version))
-
-os.system('cp -r %s %s' % (release_texts, install_dir))
-
-if os.path.exists(release_txt):
- print 'RELEASE TEXT FOUND'
-else:
- print 'WARNING! RELEASE TEXT NOT FOUND!'
-
-# TODO: copy plugins data when ready
-
-# Add software gl libraries and scripts
-mesa_arch = None
-
-if opts.arch == 'x86_64':
- mesa_arch = 'mesalibs64.tar.bz2'
-elif opts.arch == 'i686':
- mesa_arch = 'mesalibs32.tar.bz2'
-
-if mesa_arch is not None:
- mesalibs = os.path.join(builder_dir, 'extra', mesa_arch)
- software_gl = os.path.join(builder_dir, 'extra', 'blender-softwaregl')
-
- os.system('tar -xpf %s -C %s' % (mesalibs, install_dir))
- os.system('cp %s %s' % (software_gl, install_dir))
- os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl')))
-
-# Pack release archive
-print("Building Dynamic Tarball")
-os.system('tar -C %s -cjf %s.tar.bz2 %s ' % (opts.install_dir,
- full_name, full_name))
-
-print('Done.')
-EOF
- chmod +x $RB/compile.py
-
- cat << EOF > $RB/do_build_al.sh
-#!/bin/sh
-
-SOURCES="/home/sources"
-
-#opts="--cores=1 "
-opts=""
-
-if [ "x\${tag}" != "x" ]; then
- echo "Getting tagged source tree..."
- d="\${SOURCES}/blender-tags/\${tag}"
- opts="\${opts} --tag=\${tag}"
- if [ ! -d \${d} ]; then
- svn co https://svn.blender.org/svnroot/bf-blender/tags/\${tag}/blender/@\${revision} \${d}
- else
- svn up -r \${revision} \${d}
- fi
-elif [ "x\${branch}" != "x" ]; then
- echo "Getting branched source tree..."
- d="\${SOURCES}/blender-branches/\${branch}"
- opts="\${opts} --branch=\${branch}"
- if [ ! -d \${d} ]; then
- if [ "x\${revision}" != "x" ]; then
- svn co https://svn.blender.org/svnroot/bf-blender/branches/\${branch}/@\${revision} \${d}
- else
- svn co https://svn.blender.org/svnroot/bf-blender/branches/\${branch}/ \${d}
- fi
- else
- if [ "x\${revision}" != "x" ]; then
- svn up -r \${revision} \${d}
- else
- svn up \${d}
- fi
- fi
-else
- if [ "x\${revision}" != "x" ]; then
- if [ "x\${revision}" != "x0" ]; then
- svn up -r \${revision} \${SOURCES}/blender
- else
- svn up \${SOURCES}/blender
- fi
- fi
-fi
-
-if [ "x\${tag}" != "x" ]; then
- b="\${SOURCES}/blender-tags/\${tag}"
-elif [ "x\${branch}" != "x" ]; then
- b="\${SOURCES}/blender-branches/\${branch}"
-else
- b="\${SOURCES}/blender"
-fi
-
-if [ "x\${addons_revision}" != "x" ]; then
- d="\${b}/release/scripts/addons"
-
- if [ "x\${addons_revision}" != "x0" ]; then
- svn up -r \${addons_revision} \${d}
- else
- svn up \${d}
- fi
-fi
-
-if [ "x\${locale_revision}" != "x" ]; then
- d="\${b}/release/datafiles/locale"
-
- if [ "x\${locale_revision}" != "x0" ]; then
- svn up -r \${locale_revision} \${d}
- else
- svn up \${d}
- fi
-fi
-
-if [ -z "\$version" ]; then
- version=r\`/usr/bin/svnversion \$SOURCES/blender\`
-fi
-
-cd extra
-./update-libs.sh
-cd ..
-
-python chroot-compile.py \${opts} --arch=x86_64 --bl-version \${version} # --no-clean=1
-python chroot-compile.py \${opts} --arch=i686 --bl-version \${version} # --no-clean=1
-EOF
- chmod +x $RB/do_build_al.sh
-
- mkdir -p $RB/extra
-
- cat << EOF > $RB/extra/blender-softwaregl
-#!/bin/sh
-
-BF_DIST_BIN=\`dirname "\$0"\`
-BF_PROGRAM="blender" # BF_PROGRAM=\`basename "\$0"\`-bin
-exitcode=0
-
-LD_LIBRARY_PATH=\${BF_DIST_BIN}/lib:\${LD_LIBRARY_PATH}
-
-if [ -n "\$LD_LIBRARYN32_PATH" ]; then
- LD_LIBRARYN32_PATH=\${BF_DIST_BIN}/lib:\${LD_LIBRARYN32_PATH}
-fi
-if [ -n "\$LD_LIBRARYN64_PATH" ]; then
- LD_LIBRARYN64_PATH=\${BF_DIST_BIN}/lib:\${LD_LIBRARYN64_PATH}
-fi
-if [ -n "\$LD_LIBRARY_PATH_64" ]; then
- LD_LIBRARY_PATH_64=\${BF_DIST_BIN}/lib:\${LD_LIBRARY_PATH_64}
-fi
-
-# Workaround for half-transparent windows when compiz is enabled
-XLIB_SKIP_ARGB_VISUALS=1
-
-export LD_LIBRARY_PATH LD_LIBRARYN32_PATH LD_LIBRARYN64_PATH LD_LIBRARY_PATH_64 LD_PRELOAD XLIB_SKIP_ARGB_VISUALS
-
-"\$BF_DIST_BIN/\$BF_PROGRAM" \${1+"\$@"}
-exitcode=\$?
-exit \$exitcode
-EOF
- chmod +x $RB/extra/blender-softwaregl
-
- cat << EOF > $RB/extra/do_update-libs.sh
-#!/bin/sh
-
-BITS=\$1
-V="\`readlink /opt/lib/mesa | sed -r 's/mesa-//'\`"
-TMP=\`mktemp -d\`
-N="mesalibs\$1-\$V"
-
-if [ ! -f \$N.tar.bz2 ]; then
- mkdir -p \$TMP/lib
- cp -P /opt/lib/mesa/lib/libGL* \$TMP/lib
- strip -s \$TMP/lib/*
- tar -C \$TMP -cf \$N.tar lib
- bzip2 \$N.tar
-
- rm -f mesalibs\$BITS.tar,bz2
- ln -s \$N.tar.bz2 mesalibs\$BITS.tar.bz2
-fi
-
-rm -rf \$TMP
-EOF
- chmod +x $RB/extra/do_update-libs.sh
-
- cat << EOF > $RB/extra/update-libs.sh
-#!/bin/sh
-
-P="/home/sources/release-builder/extra"
-CHROOT_PREFIX="buildbot_squeeze_"
-CHROOT32="\${CHROOT_PREFIX}i686"
-CHROOT64="\${CHROOT_PREFIX}x86_64"
-RUN32="schroot -c \$CHROOT32 -d \$P"
-RUN64="schroot -c \$CHROOT64 -d \$P"
-
-\$RUN64 ./do_update-libs.sh 64
-\$RUN32 ./do_update-libs.sh 32
-EOF
- chmod +x $RB/extra/update-libs.sh
-
- mkdir -p $RB/config
- cp $SOURCES_PATH/blender/build_files/buildbot/config/* $RB/config
-
- fi
-}
-
-INSTALL_SOURCES() {
- SOURCES_PATH=$1
-
- if [ ! -d "$SOURCES_PATH" ]; then
- INFO "Creating sources directory"
- mkdir -p "$SOURCES_PATH"
- fi
-
- if [ ! -d "$SOURCES_PATH/backport/binutils" ]; then
- INFO "Downloading binutils"
- mkdir -p "$SOURCES_PATH/backport/binutils"
- wget -c $DEBIAN_MIRROR/pool/main/b/binutils/binutils_$BINUTILS_FV.diff.gz \
- $DEBIAN_MIRROR/pool/main/b/binutils/binutils_$BINUTILS_FV.dsc \
- $DEBIAN_MIRROR/pool/main/b/binutils/binutils_$BINUTILS_V.orig.tar.gz \
- -P "$SOURCES_PATH/backport/binutils"
- fi
-
- if [ ! -d "$SOURCES_PATH/backport/gcc-4.7" ]; then
- INFO "Downloading gcc-4.7"
- mkdir -p "$SOURCES_PATH/backport/gcc-4.7"
- wget -c $DEBIAN_MIRROR/pool/main/g/gcc-4.7/gcc-$GCC_FV.diff.gz \
- $DEBIAN_MIRROR/pool/main/g/gcc-4.7/gcc-$GCC_FV.dsc \
- $DEBIAN_MIRROR/pool/main/g/gcc-4.7/gcc-$GCC_V.orig.tar.gz \
- -P "$SOURCES_PATH/backport/gcc-4.7"
- fi
-
- if [ ! -d "$SOURCES_PATH/backport/openssl" ]; then
- INFO "Downloading openssl"
- mkdir -p "$SOURCES_PATH/backport/openssl"
- wget -c $DEBIAN_MIRROR/pool/main/o/openssl/openssl_$OPENSSL_FV.debian.tar.gz \
- $DEBIAN_MIRROR/pool/main/o/openssl/openssl_$OPENSSL_FV.dsc \
- $DEBIAN_MIRROR/pool/main/o/openssl/openssl_$OPENSSL_V.orig.tar.gz \
- -P "$SOURCES_PATH/backport/openssl"
- fi
-
- # JeMalloc
- J="$SOURCES_PATH/packages/jemalloc-$JEMALLOC_V"
- if [ ! -d "$J" ]; then
- INFO "Downloading jemalloc-$JEMALLOC_V"
- wget -c http://www.canonware.com/download/jemalloc/jemalloc-$JEMALLOC_V.tar.bz2 -P "$SOURCES_PATH/packages"
- tar -C "$SOURCES_PATH/packages" -xf "$J.tar.bz2"
- cat << EOF > "$J/0config.sh"
-#!/bin/sh
-
-./configure CC="gcc-4.7 -Wl,--as-needed" CXX="g++-4.7 -Wl,--as-needed" LDFLAGS="-pthread -static-libgcc" --prefix=/opt/lib/jemalloc-$JEMALLOC_V
-EOF
- chmod +x "$J/0config.sh"
- fi
-
- # Spnav
- S="$SOURCES_PATH/packages/libspnav-$SPNAV_V"
- if [ ! -d "$S" ]; then
- wget -c http://downloads.sourceforge.net/project/spacenav/spacenav%20library%20%28SDK%29/libspnav%200.2.2/libspnav-$SPNAV_V.tar.gz \
- -P "$SOURCES_PATH/packages"
- tar -C "$SOURCES_PATH/packages" -xf "$S.tar.gz"
- cat << EOF > "$S/0config.sh"
-#!/bin/sh
-
-./configure --prefix=/opt/lib/libspnav-$SPNAV_V
-EOF
- chmod +x "$S/0config.sh"
- fi
-
- # FFmpeg
- F="$SOURCES_PATH/packages/ffmpeg-$FFMPEG_V"
- if [ ! -d "$F" ]; then
- INFO "Downloading FFmpeg-$FFMPEG_V"
- wget -c http://ffmpeg.org/releases/ffmpeg-$FFMPEG_V.tar.bz2 -P "$SOURCES_PATH/packages"
- tar -C "$SOURCES_PATH/packages" -xf "$F.tar.bz2"
- cat << EOF > "$F/0config.sh"
-#!/bin/sh
-
-./configure \\
- --cc="/usr/bin/gcc-4.7 -Wl,--as-needed" \\
- --extra-ldflags="-pthread -static-libgcc" \\
- --prefix=/opt/lib/ffmpeg-$FFMPEG_V \\
- --enable-static \\
- --enable-avfilter \\
- --disable-vdpau \\
- --disable-bzlib \\
- --disable-libgsm \\
- --enable-libschroedinger \\
- --disable-libspeex \\
- --enable-libtheora \\
- --enable-libvorbis \\
- --enable-pthreads \\
- --enable-zlib \\
- --enable-libvpx \\
- --enable-stripping \\
- --enable-runtime-cpudetect \\
- --disable-vaapi \\
- --enable-libopenjpeg \\
- --disable-libfaac \\
- --disable-nonfree \\
- --enable-gpl \\
- --disable-postproc \\
- --disable-x11grab \\
- --enable-libmp3lame \\
- --disable-librtmp \\
- --enable-libx264 \\
- --enable-libxvid \\
- --disable-libopencore-amrnb \\
- --disable-libopencore-amrwb \\
- --disable-libdc1394 \\
- --disable-version3 \\
- --disable-outdev=sdl \\
- --disable-outdev=alsa \\
- --disable-indev=sdl \\
- --disable-indev=alsa \\
- --disable-indev=jack \\
- --disable-indev=lavfi
-
-# --enable-debug
-# --disable-optimizations
-# --disable-ffplay
-EOF
- chmod +x "$F/0config.sh"
- fi
-
- # Boost
- B="$SOURCES_PATH/packages/boost_$BOOST_V"
- if [ ! -d "$B" ]; then
- INFO "Downloading Boost-$BOOST_V"
- b_d=`echo "$BOOST_V" | sed -r 's/_/./g'`
- wget -c http://sourceforge.net/projects/boost/files/boost/$b_d/boost_$BOOST_V.tar.bz2/download -O "$B.tar.bz2"
- tar -C "$SOURCES_PATH/packages" -xf "$B.tar.bz2"
- fi
-
- # Python
- P="$SOURCES_PATH/packages/Python-$PYTHON_V"
- if [ ! -d "$P" ]; then
- INFO "Downloading Python-$PYTHON_V"
- wget -c http://python.org/ftp/python/$PYTHON_V/Python-$PYTHON_V.tar.bz2 -P "$SOURCES_PATH/packages"
- tar -C "$SOURCES_PATH/packages" -xf "$P.tar.bz2"
- cat << EOF > "$P/0config.sh"
-#!/bin/sh
-
-# NOTE: this sounds strange, but make sure /dev/shm/ is writable by your user,
-# otherwise syncronization primitives wouldn't be included into python
-if [[ "\`stat -c '%a' /dev/shm/\`" != "777" ]]; then
- echo "Error checking syncronization primitives"
- exit 1
-fi
-
-./configure --prefix=/opt/lib/python-$PYTHON_V \\
- --enable-ipv6 \\
- --enable-loadable-sqlite-extensions \\
- --with-dbmliborder=bdb \\
- --with-wide-unicode \\
- --with-computed-gotos \\
- --with-pymalloc
-EOF
- chmod +x "$P/0config.sh"
- fi
-
- # OpenImageIO
- O="$SOURCES_PATH/packages/OpenImageIO-$OIIO_V"
- if [ ! -d "$O" ]; then
- INFO "Downloading OpenImageIO-$OIIO_V"
- wget -c https://github.com/OpenImageIO/oiio/tarball/Release-$OIIO_V -O "$O.tar.gz"
- tar -C "$SOURCES_PATH/packages" -xf "$O.tar.gz"
- mv $SOURCES_PATH/packages/OpenImageIO-oiio* $O
- mkdir $O/build
- cat << EOF > "$O/build/prepare.sh"
-#!/bin/sh
-
-if file /bin/cp | grep -q '32-bit'; then
- cflags="-fPIC -m32 -march=i686"
-else
- cflags="-fPIC"
-fi
-
-cmake \\
- -D CMAKE_BUILD_TYPE=Release \\
- -D CMAKE_PREFIX_PATH=/opt/lib/oiio-$OIIO_V \\
- -D CMAKE_INSTALL_PREFIX=/opt/lib/oiio-$OIIO_V \\
- -D BUILDSTATIC=ON \\
- -D USE_JASPER=OFF \\
- -D CMAKE_CXX_FLAGS:STRING="\${cflags}" \\
- -D CMAKE_C_FLAGS:STRING="\${cflags}" \\
- -D CMAKE_EXE_LINKER_FLAGS='-lgcc_s -lgcc' \\
- -D BOOST_ROOT=/opt/lib/boost \\
- ../src
-EOF
- chmod +x "$O/build/prepare.sh"
- fi
-
- # OpenColorIO
- O="$SOURCES_PATH/packages/OpenColorIO-$OCIO_V"
- if [ ! -d "$O" ]; then
- INFO "Downloading OpenColorIO-$OCIO_V"
- wget -c http://github.com/imageworks/OpenColorIO/tarball/v$OCIO_V -O "$O.tar.gz"
- tar -C "$SOURCES_PATH/packages" -xf "$O.tar.gz"
- mv $SOURCES_PATH/packages/imageworks-OpenColorIO* $O
- mkdir $O/build
- cat << EOF > "$O/build/prepare.sh"
-#!/bin/sh
-
-if file /bin/cp | grep -q '32-bit'; then
- cflags="-fPIC -m32 -march=i686"
-else
- cflags="-fPIC"
-fi
-
-cmake \\
- -D CMAKE_BUILD_TYPE=Release \\
- -D CMAKE_PREFIX_PATH=/opt/lib/ocio-1.0.7 \\
- -D CMAKE_INSTALL_PREFIX=/opt/lib/ocio-1.0.7 \\
- -D BUILDSTATIC=ON \\
- -D CMAKE_CXX_FLAGS:STRING="\${cflags}" \\
- -D CMAKE_C_FLAGS:STRING="\${cflags}" \\
- -D CMAKE_EXE_LINKER_FLAGS='-lgcc_s -lgcc' \\
- ..
-EOF
-
- chmod +x "$O/build/prepare.sh"
- fi
-
- # Mesa
- M="$SOURCES_PATH/packages/Mesa-$MESA_V"
- if [ ! -d "$M" ]; then
- INFO "Downloading Mesa-$MESA_V"
- wget -c ftp://ftp.freedesktop.org/pub/mesa/$MESA_V/MesaLib-$MESA_V.tar.bz2 -P "$SOURCES_PATH/packages"
- tar -C "$SOURCES_PATH/packages" -xf "$SOURCES_PATH/packages/MesaLib-$MESA_V.tar.bz2"
- cat << EOF > "$M/0config.sh"
-#!/bin/sh
-
-OPTS="--with-driver=xlib \\
- --disable-driglx-direct \\
- --disable-egl \\
- --enable-gallium-gbm=no \\
- --enable-gallium-egl=no \\
- --enable-gallium-llvm=no \\
- --with-gallium-drivers=swrast \\
- --with-dri-drivers=swrast \\
- --prefix=/opt/lib/mesa-$MESA_V"
-
-if file /bin/cp | grep -q '32-bit'; then
- ./configure CC="gcc-4.7 -Wl,--as-needed" CXX="g++-4.7 -Wl,--as-needed" LDFLAGS="-pthread -static-libgcc" \${OPTS} --enable-32-bit #--build=i486-linux-gnu
-else
- ./configure CC="gcc-4.7 -Wl,--as-needed" CXX="g++-4.7 -Wl,--as-needed" LDFLAGS="-pthread -static-libgcc" \${OPTS}
-fi
-
-EOF
- chmod +x "$M/0config.sh"
- fi
-
- # OpenAL
- O="$SOURCES_PATH/packages/openal-soft-$OPENAL_V"
- if [ ! -d "$O" ]; then
- INFO "Downloading OpenAL-$OPENAL_V"
- wget -c http://kcat.strangesoft.net/openal-releases/openal-soft-$OPENAL_V.tar.bz2 -P "$SOURCES_PATH/packages"
- tar -C "$SOURCES_PATH/packages" -xf "$SOURCES_PATH/packages/openal-soft-$OPENAL_V.tar.bz2"
- cat << EOF > "$O/build-openal.sh"
-#!/bin/sh
-
-DEB_CMAKE_OPTIONS="-DCMAKE_VERBOSE_MAKEFILE=ON \\
- -DCMAKE_INSTALL_PREFIX=/opt/lib/openal-$OPENAL_V \\
- -DCMAKE_BUILD_TYPE:String=Release \\
- -DALSOFT_CONFIG=ON \\
- -DLIBTYPE=STATIC .. "
-
-BUILD_TREE=./build-tree
-
-rm -rf "\${BUILD_TREE}"
-mkdir -p "\${BUILD_TREE}"
-cd "\${BUILD_TREE}"
-
-sh -c "cmake \`echo \$DEB_CMAKE_OPTIONS\`"
-make -j$THREADS
-make install
-EOF
- chmod +x "$O/build-openal.sh"
- fi
-
- # OpenCollada
- O="$SOURCES_PATH/packages/opencollada"
- if [ ! -d "$O" ]; then
- INFO "Checking out OpenCollada sources"
- svn co http://opencollada.googlecode.com/svn/trunk $O
-
- cat << EOF > "$O/build_all.sh"
-#!/bin/sh
-
-scons RELEASE=0 NOVALIDATION=1 XMLPARSER=libxmlnative PCRENATIVE=1 SHAREDLIB=0 -j ${THREADS} --clean
-scons RELEASE=1 NOVALIDATION=1 XMLPARSER=libxmlnative PCRENATIVE=1 SHAREDLIB=0 -j ${THREADS} --clean
-
-scons RELEASE=0 NOVALIDATION=1 XMLPARSER=libxmlnative PCRENATIVE=1 SHAREDLIB=0 -j ${THREADS}
-scons RELEASE=1 NOVALIDATION=1 XMLPARSER=libxmlnative PCRENATIVE=1 SHAREDLIB=0 -j ${THREADS}
-EOF
-
- cat << EOF > "$O/prepare_lib-libxml.sh"
-#!/bin/bash
-
-src="./COLLADAStreamWriter/include
-./COLLADABaseUtils/include
-./COLLADABaseUtils/include/Math
-./COLLADAFramework/include
-./GeneratedSaxParser/include
-./COLLADASaxFrameworkLoader/include
-./COLLADASaxFrameworkLoader/include/generated14
-./COLLADASaxFrameworkLoader/include/generated15"
-
-if [ -z \$1 ]; then
- arch="x86_64"
-else
- arch=\$1
-fi
-
-libs="./GeneratedSaxParser/lib/posix/\${arch}/releaselibxml/libGeneratedSaxParser.a
-./Externals/MathMLSolver/lib/posix/\${arch}/release/libMathMLSolver.a
-./COLLADABaseUtils/lib/posix/\${arch}/release/libOpenCOLLADABaseUtils.a
-./COLLADAFramework/lib/posix/\${arch}/release/libOpenCOLLADAFramework.a
-./COLLADASaxFrameworkLoader/lib/posix/\${arch}/releaselibxmlNovalidation/libOpenCOLLADASaxFrameworkLoader.a
-./COLLADAStreamWriter/lib/posix/\${arch}/release/libOpenCOLLADAStreamWriter.a
-./Externals/UTF/lib/posix/\${arch}/release/libUTF.a
-./common/libBuffer/lib/posix/\${arch}/release/libbuffer.a
-./common/libftoa/lib/posix/\${arch}/release/libftoa.a"
-
-#./Externals/pcre/lib/posix/\${arch}/release/libpcre.a
-#./Externals/LibXML/lib/posix/\${arch}/release/libxml.a
-
-debug_libs="./GeneratedSaxParser/lib/posix/\${arch}/debuglibxml/libGeneratedSaxParser.a
-./Externals/MathMLSolver/lib/posix/\${arch}/debug/libMathMLSolver.a
-./COLLADABaseUtils/lib/posix/\${arch}/debug/libOpenCOLLADABaseUtils.a
-./COLLADAFramework/lib/posix/\${arch}/debug/libOpenCOLLADAFramework.a
-./COLLADASaxFrameworkLoader/lib/posix/\${arch}/debuglibxmlNovalidation/libOpenCOLLADASaxFrameworkLoader.a
-./COLLADAStreamWriter/lib/posix/\${arch}/debug/libOpenCOLLADAStreamWriter.a
-./Externals/UTF/lib/posix/\${arch}/debug/libUTF.a
-./common/libBuffer/lib/posix/\${arch}/debug/libbuffer.a
-./common/libftoa/lib/posix/\${arch}/debug/libftoa.a"
-
-#./Externals/pcre/lib/posix/\${arch}/debug/libpcre.a
-#./Externals/LibXML/lib/posix/\${arch}/debug/libxml.a
-
-d="opencollada-libxml"
-rm -rf \${d}
-mkdir -p \${d}/include
-
-for i in \${src}; do
- mkdir -p \${d}/include/\${i}
- cp \${i}/*.h \${d}/include/\${i}
-done
-
-mkdir \${d}/lib
-for i in \${libs}; do
- echo "" > /dev/null
- cp \${i} \${d}/lib
-done
-
-for i in \${debug_libs}; do
- f=\`basename \${i}\`
- o=\${f/\\.a/_d.a}
- cp \${i} \${d}/lib/\${o}
-done
-
-rm -rf /opt/lib/opencollada
-mv \${d} /opt/lib/opencollada
-chown -R root:staff /opt/lib/opencollada
-EOF
-
- chmod +x "$O/build_all.sh"
- chmod +x "$O/prepare_lib-libxml.sh"
- fi
-
- # Blender
- B="$SOURCES_PATH/blender"
- if [ ! -d "$B" ]; then
- INFO "Checking out Blender sources"
- svn co https://svn.blender.org/svnroot/bf-blender/trunk/blender $B
- fi
-
- # CUDA Toolkit
- C=$SOURCES_PATH/cudatoolkit
- if [ ! -f "$C/$CUDA_32" ]; then
- INFO "Downloading CUDA 32bit toolkit"
- mkdir -p $C
- wget -c http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/$CUDA_32 -P $C
- fi
-
- if [ ! -f "$C/$CUDA_64" ]; then
- INFO "Downloading CUDA 64bit toolkit"
- mkdir -p $C
- wget -c http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/$CUDA_64 -P $C
- fi
-
- if [ ! -f $SOURCES_PATH/Readme.txt ]; then
-
- cat << EOF > $SOURCES_PATH/Readme.txt
-This directory contains different things needed for Blender builds
-
-blender/: directory with blender's svnsnapshot
-
-blender-build/, blender-install/: build and install directories for
- automated release creation
-
-buildbot-i686-slave/,
-buildbot-x86_64-slave/: buildbot slave environments for automated builds
- (maybe it'll be better to move them to /home?)
-
-staticlibs/: set of static libs. Mostly needed to make static linking prioretized
- under dynamic linking
-
-release-builder/: all stuff needed for release archives preparation
-
-Hope all this would help you.
-
--Sergey-
-EOF
- fi
-
- INSTALL_RELEASE_BUILDER $SOURCES_PATH
-}
-
-DO_BACKPORT() {
- CHROOT_ARCH=$1
- CHROOT_PATH=$2
-
- RUN="chroot $CHROOT_PATH"
- P="/home/sources/backport"
-
- # Backport fresh binutils
- if [ `$RUN dpkg-query -W -f='${Version}\n' binutils | grep -c $BINUTILS_V` -eq "0" ]; then
- INFO "Backporting binutils"
- B="$P/binutils/binutils-$BINUTILS_V"
- pkg="$P/binutils/binutils_${BINUTILS_FV}_amd64.deb"
-
- if [ ! -d "$CHROOT_PATH/$B" ]; then
- INFO "Unpacking binutils"
- $RUN dpkg-source -x "$P/binutils/binutils_$BINUTILS_FV.dsc" "$B"
- fi
-
- if [ "$CHROOT_ARCH" = "i386" ]; then
- pkg=`echo "$pkg" | sed -r 's/amd64/i386/g'`
- fi
-
- if [ ! -f "$CHROOT_PATH/$pkg" ]; then
- INFO "Compiling binutils"
- sed -ie 's/with_check := yes/with_check := no/' "$CHROOT_PATH/$B/debian/rules"
- $RUN sh -c "cd '$B' && dpkg-buildpackage -rfakeroot -j$THREADS"
- fi
-
- INFO "Installing binutils"
- $RUN dpkg -i "$pkg"
-
- INFO "Cleaning binutils"
- $RUN sh -c "cd '$B' && fakeroot debian/rules clean"
- fi
-
- # Install fresh gcc
- if [ `$RUN dpkg-query -W -f='${Status}\n' gcc-4.7 2> /dev/null | grep -c installed` -eq "0" ]; then
- INFO "Backporting gcc-4.7"
- G="$P/gcc-4.7/gcc-$GCC_V"
-
- pkg="cpp-4.7_4.7.1-7_amd64.deb gcc-4.7-base_4.7.1-7_amd64.deb \
- libstdc++6-4.7-dev_4.7.1-7_amd64.deb libstdc++6_4.7.1-7_amd64.deb libgcc1_4.7.1-7_amd64.deb \
- libgomp1_4.7.1-7_amd64.deb libitm1_4.7.1-7_amd64.deb libquadmath0_4.7.1-7_amd64.deb \
- gcc-4.7_4.7.1-7_amd64.deb g++-4.7_4.7.1-7_amd64.deb"
-
- if [ ! -d "$CHROOT_PATH/$G" ]; then
- INFO "Unpacking gcc-4.7"
- $RUN dpkg-source -x "$P/gcc-4.7/gcc-$GCC_FV.dsc" "$G"
- fi
-
- if [ "$CHROOT_ARCH" = "i386" ]; then
- pkg=`echo "$pkg" | sed -r 's/amd64/i386/g'`
- fi
-
- ok=true
- for x in `echo "$pkg"`; do
- if [ ! -f "$CHROOT_PATH/$P/gcc-4.7/$x" ]; then
- ok=false
- break;
- fi
- done
-
- if ! $ok; then
- INFO "Compiling gcc-4.7"
- sed -ie 's/#with_check := disabled by hand/with_check := disabled by hand/' "$CHROOT_PATH/$G/debian/rules.defs"
- sed -ie 's/dpkg-dev (>= 1.16.0~ubuntu4)/dpkg-dev (>= 1.15.8)/' "$CHROOT_PATH/$G/debian/control"
- sed -ie 's/doxygen (>= 1.7.2)/doxygen (>= 1.7.1)/' "$CHROOT_PATH/$G/debian/control"
- sed -ie 's/libmpfr-dev (>= 3.0.0-9~)/libmpfr-dev (>= 3.0.0)/' "$CHROOT_PATH/$G/debian/control"
- sed -ie 's/libc6-dev (>= 2.13-5)/libc6-dev (>= 2.11.3)/' "$CHROOT_PATH/$G/debian/control"
- sed -ie 's/libgmp-dev (>= 2:5.0.1~)/libgmp3-dev (>= 2:4.3.2)/' "$CHROOT_PATH/$G/debian/control"
- $RUN sh -c "cd '$G' && dpkg-buildpackage -rfakeroot"
- fi
-
- inst=""
- for x in `echo "$pkg"`; do
- inst="$inst $P/gcc-4.7/$x"
- done
-
- INFO "Installing gcc-4.7"
- $RUN dpkg -i $inst
-
- INFO "Cleaning gcc-4.7"
- $RUN sh -c "cd '$G' && fakeroot debian/rules clean"
- fi
-
- # Backport OpenSSL
- if [ ! -f $CHROOT_PATH/usr/lib/libssl_pic.a ]; then
- INFO "Backporting OpenSSL"
- O="$P/openssl/openssl-$OPENSSL_V"
-
- pkg="libssl-dev_0.9.8o-4squeeze13_amd64.deb libssl0.9.8_0.9.8o-4squeeze13_amd64.deb openssl_0.9.8o-4squeeze13_amd64.deb"
-
- if [ ! -d "$CHROOT_PATH/$O" ]; then
- INFO "Unpacking OpenSSL"
- $RUN dpkg-source -x "$P/openssl/openssl_$OPENSSL_FV.dsc" "$O"
- fi
-
- if [ "$CHROOT_ARCH" = "i386" ]; then
- pkg=`echo "$pkg" | sed -r 's/amd64/i386/g'`
- fi
-
- ok=true
- for x in `echo "$pkg"`; do
- if [ ! -f "$CHROOT_PATH/$P/openssl/$x" ]; then
- ok=false
- break;
- fi
- done
-
- if ! $ok; then
- INFO "Compiling OpenSSL"
- sed -ie 's/#\s*mv debian\/tmp\/usr\/lib\/libcrypto.a debian\/tmp\/usr\/lib\/libcrypto_pic.a/ mv debian\/tmp\/usr\/lib\/libcrypto.a debian\/tmp\/usr\/lib\/libcrypto_pic.a/' "$CHROOT_PATH/$O/debian/rules"
- sed -ie 's/#\s*mv debian\/tmp\/usr\/lib\/libssl.a debian\/tmp\/usr\/lib\/libssl_pic.a/ mv debian\/tmp\/usr\/lib\/libssl.a debian\/tmp\/usr\/lib\/libssl_pic.a/' "$CHROOT_PATH/$O/debian/rules"
- cat << EOF > $CHROOT_PATH/$O/debian/libssl-dev.files
-usr/lib/libssl.so
-usr/lib/libcrypto.so
-usr/lib/libssl.a
-usr/lib/libcrypto.a
-usr/lib/libssl_pic.a
-usr/lib/libcrypto_pic.a
-usr/lib/pkgconfig
-usr/include
-usr/share/man/man3
-EOF
- $RUN sh -c "cd '$O' && dpkg-buildpackage -rfakeroot -j$THREADS"
- fi
-
- inst=""
- for x in `echo "$pkg"`; do
- inst="$inst $P/openssl/$x"
- done
-
- INFO "Installing OpenSSL"
- $RUN dpkg -i $inst
-
- echo "openssl hold" | $RUN dpkg --set-selections
- echo "libssl-dev hold" | $RUN dpkg --set-selections
- echo "libssl0.9.8 hold" | $RUN dpkg --set-selections
-
- INFO "Cleaning OpenSSL"
- $RUN sh -c "cd '$O' && fakeroot debian/rules clean"
- fi
-}
-
-DO_COMPILE() {
- CHROOT_ARCH=$1
- CHROOT_PATH=$2
-
- RUN="chroot $CHROOT_PATH"
- P="/home/sources/packages"
- L="$CHROOT_PATH/opt/lib"
-
- # JeMalloc
- if [ ! -d "$L/jemalloc-$JEMALLOC_V" ]; then
- INFO "Copmiling jemalloc-$JEMALLOC_V"
- $RUN sh -c "cd '$P/jemalloc-$JEMALLOC_V' && ./0config.sh && make clean && make -j$THREADS && make install && make clean"
-
- rm -f "$L/jemalloc"
- ln -s "jemalloc-$JEMALLOC_V" "$L/jemalloc"
- fi
-
- # libspnav
- if [ ! -d "$L/libspnav-$SPNAV_V" ]; then
- INFO "Copmiling libspnav-$SPNAV_V"
- mkdir -p "$L/libspnav-$SPNAV_V/lib"
- mkdir -p "$L/libspnav-$SPNAV_V/include"
- $RUN sh -c "cd '$P/libspnav-$SPNAV_V' && ./0config.sh && make clean && make -j$THREADS && make install && make clean"
-
- rm -f "$L/libspnav"
- ln -s "libspnav-$SPNAV_V" "$L/libspnav"
- fi
-
- # FFmpeg
- if [ ! -d "$L/ffmpeg-$FFMPEG_V" ]; then
- INFO "Copmiling ffmpeg-$FFMPEG_V"
- $RUN sh -c "cd '$P/ffmpeg-$FFMPEG_V' && ./0config.sh && make clean && make -j$THREADS && make install && make clean"
-
- rm -f "$L/ffmpeg"
- ln -s "ffmpeg-$FFMPEG_V" "$L/ffmpeg"
- fi
-
- # Boost
- V=`echo $BOOST_V | sed -r 's/_/./g'`
- if [ ! -d "$L/boost-$V" ]; then
- INFO "Copmiling boost-$V"
- $RUN sh -c "cd '$P/boost_$BOOST_V' && ./bootstrap.sh && ./b2 --clean && ./b2 install --prefix='/opt/lib/boost-$V' && ./b2 --clean"
-
- rm -f "$L/boost"
- ln -s "boost-$V" "$L/boost"
- fi
-
- # OCIO
- if [ ! -d "$L/ocio-$OCIO_V" ]; then
- INFO "Copmiling ocio-$OCIO_V"
- $RUN sh -c "cd '$P/OpenColorIO-$OCIO_V/build' && ./prepare.sh && make clean && make -j$THREADS && make install && make clean"
-
- # Force linking against sttaic libs
- rm -f $L/ocio-$OCIO_V/lib/*.so*
-
- # Additional depencencies
- cp $CHROOT_PATH/$P/OpenColorIO-$OCIO_V/build/ext/dist/lib/libtinyxml.a $L/ocio-$OCIO_V/lib
- cp $CHROOT_PATH/$P/OpenColorIO-$OCIO_V/build/ext/dist/lib/libyaml-cpp.a $L/ocio-$OCIO_V/lib
-
- rm -f "$L/ocio"
- ln -s "ocio-$OCIO_V" "$L/ocio"
- fi
-
- # OIIO
- if [ ! -d "$L/oiio-$OIIO_V" ]; then
- INFO "Copmiling oiio-$OIIO_V"
- $RUN sh -c "cd '$P/OpenImageIO-$OIIO_V/build' && ./prepare.sh && make clean && make -j$THREADS && make install && make clean"
-
- rm -f "$L/oiio"
- ln -s "oiio-$OIIO_V" "$L/oiio"
- fi
-
- # Python
- if [ ! -d "$L/python-$PYTHON_V" ]; then
- INFO "Copmiling Python-$PYTHON_V"
-
- cat << EOF > $CHROOT_PATH/$P/Python-$PYTHON_V/Modules/Setup.local
-_md5 md5module.c
-
-_sha1 sha1module.c
-_sha256 sha256module.c
-_sha512 sha512module.c
-EOF
-
- sed -ie "s/libraries = \['ssl', 'crypto'\]/libraries = ['ssl_pic', 'crypto_pic', 'z']/" "$P/Python-$PYTHON_V/setup.py"
-
- $RUN sh -c "cd '$P/Python-$PYTHON_V' && ./0config.sh && make clean && make -j$THREADS && make install && make clean"
-
- rm -f "$L/python-$PYTHIN_V_SHORT"
- ln -s "python-$PYTHON_V" "$L/python-$PYTHIN_V_SHORT"
- fi
-
- # Mesa
- if [ ! -d "$L/mesa-$MESA_V" ]; then
- INFO "Copmiling Mesa-$MESA_V"
-
- $RUN sh -c "cd '$P/Mesa-$MESA_V' && ./0config.sh && make clean && make -j$THREADS && make install && make clean"
-
- rm -f "$L/mesa"
- ln -s "mesa-$MESA_V" "$L/mesa"
- fi
-
- # OpenAL
- if [ ! -d "$L/openal-$OPENAL_V" ]; then
- INFO "Copmiling openal-$OPENAL_V"
-
- $RUN sh -c "cd '$P/openal-soft-$OPENAL_V' && ./build-openal.sh"
-
- rm -f "$L/openal"
- ln -s "openal-$OPENAL_V" "$L/openal"
- fi
-
- # OpenCollada
- if [ ! -d "$L/opencollada" ]; then
- INFO "Copmiling opencollada"
-
- cat << EOF > "$CHROOT_PATH/$P/opencollada/collada.patch"
-Index: common/libBuffer/include/CommonBuffer.h
-===================================================================
---- common/libBuffer/include/CommonBuffer.h (revision 876)
-+++ common/libBuffer/include/CommonBuffer.h (working copy)
-@@ -12,6 +12,7 @@
- #define __COMMON_BUFFER_H__
-
- #include "CommonIBufferFlusher.h"
-+#include "COLLADABUPlatform.h"
-
- namespace Common
- {
-Index: common/libBuffer/src/CommonLogFileBufferFlusher.cpp
-===================================================================
---- common/libBuffer/src/CommonLogFileBufferFlusher.cpp (revision 876)
-+++ common/libBuffer/src/CommonLogFileBufferFlusher.cpp (working copy)
-@@ -10,6 +10,34 @@
-
- #include "CommonLogFileBufferFlusher.h"
-
-+#include <stdio.h>
-+#include <errno.h>
-+
-+#ifndef _WIN32
-+FILE *_wfopen(const wchar_t *path, const char *mode)
-+{
-+ const wchar_t *src = path;
-+ char *path_mbs;
-+ int n;
-+ FILE *file;
-+
-+ n = (int)wcsrtombs(NULL, &src, 0, NULL);
-+
-+ if (n < 0)
-+ return NULL;
-+
-+ path_mbs = (char *)malloc(n + 1);
-+ wcsrtombs(path_mbs, &path, n, NULL);
-+ path_mbs[n] = 0;
-+
-+ file = fopen(path_mbs, mode);
-+
-+ free(path_mbs);
-+
-+ return file;
-+}
-+#endif
-+
- namespace Common
- {
- //--------------------------------------------------------------------
-@@ -35,7 +63,7 @@
- #ifdef _WIN32
- mError = (int)_wfopen_s( &stream, fileName, L"wb" );
- #else
-- stream = _wfopen( fileName, L"wb" );
-+ stream = _wfopen( fileName, "wb" );
- mError = stream ? 0 : errno;
- #endif
- if ( !mError )
-@@ -65,7 +93,7 @@
- #else
- if ( mUseWideFileName )
- {
-- stream = _wfopen( mWideFileName.c_str(), L"a" );
-+ stream = _wfopen( mWideFileName.c_str(), "a" );
- }
- else
- {
-Index: common/libBuffer/SConscript
-===================================================================
---- common/libBuffer/SConscript (revision 876)
-+++ common/libBuffer/SConscript (working copy)
-@@ -11,7 +11,7 @@
- targetPath = outputDir + libName
-
-
--incDirs = ['include/', '../libftoa/include']
-+incDirs = ['include/', '../libftoa/include', '../../COLLADABaseUtils/include/', '../../Externals/UTF/include']
-
-
- src = []
-EOF
-
- # We're building in a chroot, architecture of host system would be used by scons
- collada_arch="x86_64"
-
- $RUN sh -c "cd '$P/opencollada' && svn revert . -R && cat collada.patch | patch -p0 && ./build_all.sh && ./prepare_lib-libxml.sh $collada_arch"
- fi
-}
-
-ADD_REPO() {
- CHROOT_PATH=$1
- DESC=$2
- REPO=$3
- C="$CHROOT_PATH/etc/apt/sources.list"
- RUN="chroot $CHROOT_PATH"
-
- if [ `cat "$C" | grep -c "$REPO"` -eq "0" ]; then
- INFO "Adding repo $DESC"
- echo "" >> $C
- echo "deb $REPO" >> $C
- echo "deb-src $REPO" >> $C
-
- INFO "Updating packages list"
- $RUN apt-get update
- fi
-}
-
-INSTALL_CHROOT() {
- CHROOT_ARCH=$1
- CHROOT_PATH=$2
-
- RUN="chroot $CHROOT_PATH"
-
- # Install fresh debian to a chroot
- if [ ! -d "$CHROOT_PATH" ]; then
-
- INFO "Installing Debian ${DEBIAN_BRANCH} to ${CHROOT_PATH}"
- debootstrap --arch "${CHROOT_ARCH}" "${DEBIAN_BRANCH}" "${CHROOT_PATH}" "${DEBIAN_MIRROR}"
- fi
-
- # Configure users and groups
-
- if [ `cat ${CHROOT_PATH}/etc/group | grep -c developers` -eq "0" ]; then
- INFO "Creating gorup 'developers'"
- $RUN groupadd -g 7001 developers
- fi
-
- if [ `mount | grep -c "$CHROOT_PATH/dev"` -eq "0" ]; then
- INFO "Mounting devices from host system to chroot"
-
- mount -t proc none $CHROOT_PATH/proc
- mount -t auto -o bind /dev $CHROOT_PATH/dev
- mount -t devpts -o mode=0620 none $CHROOT_PATH/dev/pts
- fi
-
- # Configure apt and install packages
-
- if [ ! -f ${CHROOT_PATH}/etc/apt/apt.conf ]; then
- INFO "Setting up apt to not use recommended packages (saves disk space)"
-
- cat << EOF > "${CHROOT_PATH}/etc/apt/apt.conf"
-APT {
- Default-Release "${DEBIAN_BRANCH}";
- Install-Recommends "0";
-};
-EOF
- fi
-
- ADD_REPO $CHROOT_PATH "mirror.yandex.ru" "http://mirror.yandex.ru/debian-multimedia/ squeeze main non-free"
- ADD_REPO $CHROOT_PATH "backports.debian.org" "http://backports.debian.org/debian-backports squeeze-backports main non-free"
-
- $RUN apt-get upgrade
-
- $RUN apt-get install -y --force-yes deb-multimedia-keyring libx264-dev libxvidcore4-dev libmp3lame-dev
-
- if [ `$RUN dpkg-query -W -f='${Status}\n' locales | grep -c not-installed` -eq "1" ]; then
- INFO "Configuring locales"
- $RUN apt-get install -y locales
- $RUN localedef -i en_US -f UTF-8 en_US.UTF-8
- fi
-
- INFO "Installing packages from repository"
-
- $RUN apt-get install -y mc gcc g++ cmake python dpkg-dev build-essential autoconf bison \
- flex gettext texinfo dejagnu quilt file lsb-release zlib1g-dev fakeroot debhelper \
- g++-multilib libtool autoconf2.64 automake gawk lzma patchutils gperf sharutils \
- libcloog-ppl-dev libmpc-dev libmpfr-dev libgmp3-dev autogen realpath chrpath doxygen \
- graphviz gsfonts-x11 texlive-latex-base libelfg0-dev libx11-dev yasm libopenjpeg-dev \
- libschroedinger-dev libtheora-dev libvorbis-dev libvpx-dev=$VPX_V \
- libopenexr-dev libpng-dev libjpeg-dev libtiff-dev python-dev libbz2-dev libreadline-dev \
- libsqlite3-dev liblzma-dev libncurses5-dev xutils-dev libxext-dev python-libxml2 \
- libglu1-mesa-dev libfftw3-dev libfreetype6-dev libsdl1.2-dev libopenal-dev libjack-dev \
- libxi-dev portaudio19-dev po4a subversion scons libpcre3-dev libexpat1-dev sudo \
- expect bc
-
- if [ $CHROOT_ARCH = "amd64" ]; then
- $RUN apt-get install -y libc6-dev-i386 lib32gcc1
- fi
-
- # Configure sources directory
- if [ ! -d "$CHROOT_PATH/home/sources" ]; then
- INFO "Creating sources directory"
- $RUN mkdir "/home/sources"
- $RUN chmod 775 /home/sources
- $RUN chown root:developers /home/sources
- fi
-
- # Bind directory from host system
- if [ ! -d "$CHROOT_PATH/home/sources/backport" ]; then
- INFO "Binding sources directory from host system to chroot"
- mount -o bind "$SOURCES_PATH" "$CHROOT_PATH/home/sources"
- fi
-
- if [ "`$RUN getent passwd $USER_ID`" = "" ]; then
- INFO "Adding default user to chroot"
- login=`getent passwd $USER_ID | cut -d : -f 1`
- $RUN useradd -d "/home/$login" -G developers,sudo -m -u $USER_ID "$login"
- fi
-
- # Backport packages
- DO_BACKPORT "$CHROOT_ARCH" "$CHROOT_PATH"
-
- # Set default compiler to gcc-4.7
- if [ `readlink "$CHROOT_PATH/usr/bin/gcc"` != "gcc-4.7" ]; then
- INFO "Setting gcc-4.7 as default compiler"
- rm -f $CHROOT_PATH/usr/bin/gcc
- rm -f $CHROOT_PATH/usr/bin/g++
- ln -s gcc-4.7 $CHROOT_PATH/usr/bin/gcc
- ln -s g++-4.7 $CHROOT_PATH/usr/bin/g++
- fi
-
- # Compile packages
- DO_COMPILE "$CHROOT_ARCH" "$CHROOT_PATH"
-
- # Install CUDA toolkit
- if [ ! -d "$CHROOT_PATH/usr/local/cuda-$CUDA_V" ]; then
- INFO "Installing CUDA toolkit"
-
- if [ "$CHROOT_ARCH" = "amd64" ]; then
- C="cudatoolkit_${CUDA_V}_linux_64_${CUDA_DISTR}.run"
- else
- C="cudatoolkit_${CUDA_V}_linux_32_${CUDA_DISTR}.run"
- fi
-
- rm -f $CHROOT_PATH/usr/local/cuda
-
- chmod +x $CHROOT_PATH//home/sources/cudatoolkit/$C
-
- $RUN /usr/bin/expect <<EOF
- spawn /home/sources/cudatoolkit/$C
- expect "Enter install path"
- send "\n"
- expect "Installation Complete"
-EOF
-
- mv $CHROOT_PATH/usr/local/cuda $CHROOT_PATH/usr/local/cuda-$CUDA_V
- ln -s cuda-$CUDA_V $CHROOT_PATH/usr/local/cuda
- sudo ln -s /usr/bin/gcc-4.4 $CHROOT_PATH/usr/local/cuda/bin/gcc
- fi
-
- # Change permissions
- INFO "Changing permissions on sources"
- login=`$RUN getent passwd $USER_ID | cut -d : -f 1`
- for x in /home/sources /opt/lib; do
- $RUN chmod g+w -R $x
- $RUN chown "$login:developers" -R $x
- done
-}
-
-if ! which debootstrap > /dev/null 2>&1; then
- ERROR "debootstrap command not found, can not create chroot environment"
- ERROR "Use apt-get install debootstrap to install debootstrap"
- exit 1
-fi
-
-if [ -z "$ENV_PATH" ]; then
- ERROR "Incorrect environment directory is set"
- exit 1
-fi
-
-INSTALL_SOURCES "$SOURCES_PATH"
-INSTALL_CHROOT amd64 "$AMD64_PATH"
-INSTALL_CHROOT i386 "$I686_PATH"
-
-INFO "Configurtion of build environment is completed!"
-echo "Add this lines to your /etc/fstab:"
-echo
-
-for x in $I686_PATH $AMD64_PATH; do
- echo "none $x/proc proc auto 0 0"
- echo "/dev $x/dev auto bind,auto 0 0"
- echo "none $x/dev/pts devpts mode=0620,auto 0 0"
- echo "/home/sources $x/home/sources auto bind,auto 0 0"
- echo
-done
-
-echo "Add this lines to your /etc/schroot/schroot.conf:"
-echo
-login=`getent passwd $USER_ID | cut -d : -f 1`
-
-for x in $I686_PATH $AMD64_PATH; do
- echo [`basename $x`]
- echo "description=Linux buildbot environment"
- echo "directory=$x"
- echo "users=$login"
- echo "root-groups=root"
- echo
-done
diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake
new file mode 100644
index 00000000000..ed5417c1c6e
--- /dev/null
+++ b/build_files/buildbot/config/blender_linux.cmake
@@ -0,0 +1,143 @@
+# ######## Global feature set settings ########
+
+include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/config/blender_full.cmake")
+
+# Detect which libc we'll be linking against.
+# Some of the paths will depend on this
+
+if (EXISTS "/lib/x86_64-linux-gnu/libc-2.19.so")
+ message(STATUS "Building in GLibc-2.19 environment")
+ set(GLIBC "2.19")
+ set(MULTILIB "/x86_64-linux-gnu")
+elseif (EXISTS "/lib/i386-linux-gnu//libc-2.19.so")
+ message(STATUS "Building in GLibc-2.19 environment")
+ set(GLIBC "2.19")
+ set(MULTILIB "/i386-linux-gnu")
+elseif (EXISTS "/lib/libc-2.11.3.so")
+ message(STATUS "Building in GLibc-2.11 environment")
+ set(GLIBC "2.11")
+ set(MULTILIB "")
+else()
+ message(FATAL_ERROR "Unknown build environment")
+endif()
+
+# Default to only build Blender, not the player
+set(WITH_BLENDER ON CACHE BOOL "" FORCE)
+set(WITH_PLAYER OFF CACHE BOOL "" FORCE)
+
+# ######## Linux-specific build options ########
+# Options which are specific to Linux-only platforms
+set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE)
+
+# ######## Official release-specific build options ########
+# Options which are specific to Linux release builds only
+set(WITH_JACK_DYNLOAD ON CACHE BOOL "" FORCE)
+set(WITH_SDL_DYNLOAD ON CACHE BOOL "" FORCE)
+set(WITH_SYSTEM_GLEW OFF CACHE BOOL "" FORCE)
+
+set(WITH_OPENMP_STATIC ON CACHE BOOL "" FORCE)
+
+set(WITH_PYTHON_INSTALL_NUMPY ON CACHE BOOL "" FORCE)
+set(WITH_PYTHON_INSTALL_REQUESTS ON CACHE BOOL "" FORCE)
+
+# ######## Release environment specific settings ########
+# All the hardcoded libraru paths and such
+
+# LLVM libraries
+set(LLVM_VERSION "3.4" CACHE STRING "" FORCE)
+set(LLVM_ROOT_DIR "/opt/lib/llvm-${LLVM_VERSION}" CACHE STRING "" FORCE)
+set(LLVM_STATIC ON CACHE BOOL "" FORCE)
+
+# BOOST libraries
+set(BOOST_ROOT "/opt/lib/boost" CACHE STRING "" FORCE)
+set(Boost_USE_STATIC_LIBS ON CACHE BOOL "" FORCE)
+
+# FFmpeg libraries
+set(FFMPEG "/opt/lib/ffmpeg" CACHE STRING "" FORCE)
+set(FFMPEG_LIBRARIES
+ avdevice avformat avcodec avutil avfilter swscale swresample
+ /usr/lib${MULTILIB}/libxvidcore.a
+ /usr/lib${MULTILIB}/libx264.a
+ /usr/lib${MULTILIB}/libmp3lame.a
+ /usr/lib${MULTILIB}/libvpx.a
+ /usr/lib${MULTILIB}/libvorbis.a
+ /usr/lib${MULTILIB}/libogg.a
+ /usr/lib${MULTILIB}/libvorbisenc.a
+ /usr/lib${MULTILIB}/libtheora.a
+ /usr/lib${MULTILIB}/libschroedinger-1.0.a
+ /usr/lib${MULTILIB}/liborc-0.4.a
+ CACHE STRING "" FORCE
+)
+
+# SndFile libraries
+set(SNDFILE_LIBRARY "/usr/lib/libsndfile.a;/usr/lib/libFLAC.a" CACHE STRING "" FORCE)
+
+# OpenAL libraries
+set(OPENAL_ROOT_DIR "/opt/lib/openal" CACHE STRING "" FORCE)
+set(OPENAL_INCLUDE_DIR "${OPENAL_ROOT_DIR}/include" CACHE STRING "" FORCE)
+set(OPENAL_LIBRARY
+ ${OPENAL_ROOT_DIR}/lib/libopenal.a
+ ${OPENAL_ROOT_DIR}/lib/libcommon.a
+ CACHE STRING "" FORCE
+)
+
+# OpenCollada libraries
+set(OPENCOLLADA_UTF_LIBRARY "" CACHE STRING "" FORCE)
+set(PCRE_INCLUDE_DIR "/usr/include" CACHE STRING "" FORCE)
+set(PCRE_LIBRARY "/usr/lib${MULTILIB}/libpcre.a" CACHE STRING "" FORCE)
+set(XML2_INCLUDE_DIR "/usr/include" CACHE STRING "" FORCE)
+set(XML2_LIBRARY "/usr/lib${MULTILIB}/libxml2.a" CACHE STRING "" FORCE)
+
+# OpenColorIO libraries
+set(OPENCOLORIO_ROOT_DIR "/opt/lib/ocio" CACHE STRING "" FORCE)
+set(OPENCOLORIO_OPENCOLORIO_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libOpenColorIO.a" CACHE STRING "" FORCE)
+set(OPENCOLORIO_TINYXML_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libtinyxml.a" CACHE STRING "" FORCE)
+set(OPENCOLORIO_YAML-CPP_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libyaml-cpp.a" CACHE STRING "" FORCE)
+
+# OpenImageIO
+if(GLIBC EQUAL "2.19")
+ set(OPENIMAGEIO_LIBRARY
+ /opt/lib/oiio/lib/libOpenImageIO.a
+ /opt/lib/oiio/lib/libOpenImageIO_Util.a
+ /usr/lib${MULTILIB}/libwebp.a
+ /usr/lib${MULTILIB}/liblzma.a
+ /usr/lib${MULTILIB}/libjbig.a
+ CACHE STRING "" FORCE
+ )
+endif()
+
+# OpenSubdiv libraries
+set(OPENSUBDIV_ROOT_DIR "/opt/lib/opensubdiv" CACHE STRING "" FORCE)
+set(OPENSUBDIV_OSDCPU_LIBRARY "${OPENSUBDIV_ROOT_DIR}/lib/libosdCPU.a" CACHE STRING "" FORCE)
+set(OPENSUBDIV_OSDGPU_LIBRARY "${OPENSUBDIV_ROOT_DIR}/lib/libosdGPU.a" CACHE STRING "" FORCE)
+
+# OpenEXR libraries
+set(OPENEXR_ROOT_DIR "/opt/lib/openexr" CACHE STRING "" FORCE)
+set(OPENEXR_HALF_LIBRARY "/opt/lib/openexr/lib/libHalf.a" CACHE STRING "" FORCE)
+set(OPENEXR_IEX_LIBRARY "/opt/lib/openexr/lib/libIex.a" CACHE STRING "" FORCE)
+set(OPENEXR_ILMIMF_LIBRARY "/opt/lib/openexr/lib/libIlmImf.a" CACHE STRING "" FORCE)
+set(OPENEXR_ILMTHREAD_LIBRARY "/opt/lib/openexr/lib/libIlmThread.a" CACHE STRING "" FORCE)
+set(OPENEXR_IMATH_LIBRARY "/opt/lib/openexr/lib/libImath.a" CACHE STRING "" FORCE)
+
+# JeMalloc library
+set(JEMALLOC_LIBRARY "/opt/lib/jemalloc/lib/libjemalloc.a" CACHE STRING "" FORCE)
+
+# Space navigation
+set(SPACENAV_ROOT_DIR "/opt/lib/libspnav" CACHE STRING "" FORCE)
+
+# Force some system libraries to be static
+set(FFTW3_LIBRARY "/usr/lib${MULTILIB}/libfftw3.a" CACHE STRING "" FORCE)
+set(JPEG_LIBRARY "/usr/lib${MULTILIB}/libjpeg.a" CACHE STRING "" FORCE)
+set(PNG_LIBRARY "/usr/lib${MULTILIB}/libpng.a" CACHE STRING "" FORCE)
+set(TIFF_LIBRARY "/usr/lib${MULTILIB}/libtiff.a" CACHE STRING "" FORCE)
+set(ZLIB_LIBRARY "/usr/lib${MULTILIB}/libz.a" CACHE STRING "" FORCE)
+
+# OpenVDB
+set(OPENVDB_LIBRARY
+ /opt/lib/openvdb/lib/libopenvdb.a
+ /opt/lib/blosc/lib/libblosc.a
+ CACHE BOOL "" FORCE
+)
+
+# Additional linking libraries
+set(CMAKE_EXE_LINKER_FLAGS "-lrt -static-libstdc++" CACHE STRING "" FORCE)
diff --git a/build_files/buildbot/config/blender_linux_player.cmake b/build_files/buildbot/config/blender_linux_player.cmake
new file mode 100644
index 00000000000..2fb31192002
--- /dev/null
+++ b/build_files/buildbot/config/blender_linux_player.cmake
@@ -0,0 +1,12 @@
+# This is applied as an ovveride on top of blender_linux.config
+# Disables all the areas which are not needed for the player.
+set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE)
+set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
+set(WITH_FREESTYLE OFF CACHE BOOL "" FORCE)
+set(WITH_GHOST_XDND OFF CACHE BOOL "" FORCE)
+set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
+set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
+set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
+
+set(WITH_BLENDER OFF CACHE BOOL "" FORCE)
+set(WITH_PLAYER ON CACHE BOOL "" FORCE)
diff --git a/build_files/buildbot/config/user-config-cuda-glibc211-i686.py b/build_files/buildbot/config/user-config-cuda-glibc211-i686.py
deleted file mode 100644
index ae5cbac8cc7..00000000000
--- a/build_files/buildbot/config/user-config-cuda-glibc211-i686.py
+++ /dev/null
@@ -1,5 +0,0 @@
-BF_BUILDDIR = '../blender-build/linux-glibc211-i686'
-BF_INSTALLDIR = '../blender-install/linux-glibc211-i686'
-BF_NUMJOBS = 1
-
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
diff --git a/build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py b/build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py
deleted file mode 100644
index 29b1b9f1ad7..00000000000
--- a/build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py
+++ /dev/null
@@ -1,5 +0,0 @@
-BF_BUILDDIR = '../blender-build/linux-glibc211-x86_64'
-BF_INSTALLDIR = '../blender-install/linux-glibc211-x86_64'
-BF_NUMJOBS = 1
-
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
diff --git a/build_files/buildbot/config/user-config-glibc211-i686.py b/build_files/buildbot/config/user-config-glibc211-i686.py
deleted file mode 100644
index 239625c1bef..00000000000
--- a/build_files/buildbot/config/user-config-glibc211-i686.py
+++ /dev/null
@@ -1,185 +0,0 @@
-BF_BUILDDIR = '../blender-build/linux-glibc211-i686'
-BF_INSTALLDIR = '../blender-install/linux-glibc211-i686'
-BF_NUMJOBS = 4
-WITHOUT_BF_OVERWRITE_INSTALL = True
-
-# Python configuration
-BF_PYTHON_VERSION = '3.4'
-BF_PYTHON_ABI_FLAGS = 'm'
-BF_PYTHON = '/opt/lib/python-3.4'
-WITH_BF_PYTHON_INSTALL_NUMPY = True
-WITH_BF_PYTHON_INSTALL_REQUESTS = True
-
-WITH_BF_STATICPYTHON = True
-
-# OpenCollada configuration
-WITH_BF_COLLADA = True
-WITH_BF_STATICOPENCOLLADA=True
-BF_OPENCOLLADA = '/opt/lib/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
-BF_OPENCOLLADA_LIB_STATIC = '${BF_OPENCOLLADA}/lib/libOpenCOLLADAStreamWriter.a ' + \
- '${BF_OPENCOLLADA}/lib/libOpenCOLLADASaxFrameworkLoader.a ' + \
- '${BF_OPENCOLLADA}/lib/libOpenCOLLADAFramework.a ' + \
- '${BF_OPENCOLLADA}/lib/libOpenCOLLADABaseUtils.a ' + \
- '${BF_OPENCOLLADA}/lib/libGeneratedSaxParser.a ' + \
- '${BF_OPENCOLLADA}/lib/libMathMLSolver.a ' + \
- '${BF_OPENCOLLADA}/lib/libbuffer.a ${BF_OPENCOLLADA}/lib/libftoa.a ' + \
- '/usr/lib/libxml2.a /usr/lib/libexpat.a /usr/lib/libpcre.a'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib /home/sources/staticlibs/lib64'
-BF_PCRE_LIB = ''
-BF_EXPAT_LIB = ''
-
-# FFMPEG configuration
-WITH_BF_FFMPEG = True
-WITH_BF_STATICFFMPEG = True
-
-BF_FFMPEG = '/opt/lib/ffmpeg'
-BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \
- '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \
- '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \
- '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \
- '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \
- '/usr/lib/liborc-0.4.a'
-
-# Don't depend on system's libstdc++
-WITH_BF_STATICCXX = True
-BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7.1/libstdc++.a'
-
-WITH_BF_OPENAL = True
-WITH_BF_STATICOPENAL = True
-BF_OPENAL = '/opt/lib/openal'
-BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a'
-
-WITH_BF_GETTEXT_STATIC = True
-
-WITH_BF_FREETYPE_STATIC = False
-
-WITH_BF_OPENEXR = True
-BF_OPENEXR = '/opt/lib/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
-WITH_BF_STATICOPENEXR = True
-
-WITH_BF_TIFF = True
-WITH_BF_STATICTIFF = True
-BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a'
-
-WITH_BF_JPEG = True
-WITH_BF_STATICJPEG = True
-BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a'
-
-WITH_BF_PNG = True
-WITH_BF_STATICPNG = True
-BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a'
-
-WITH_BF_STATICLIBSAMPLERATE = True
-
-WITH_BF_ZLIB = True
-WITH_BF_STATICZLIB = True
-BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a'
-
-WITH_BF_SDL = True
-WITH_BF_SDL_DYNLOAD = True
-
-WITH_BF_OGG = True
-
-WITH_BF_OPENMP = True
-WITH_BF_STATICOPENMP = True
-BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7/libgomp.a'
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_BULLET = True
-
-# Blender player (would be enabled in it's own config)
-WITH_BF_PLAYER = False
-
-# Use jemalloc memory manager
-WITH_BF_JEMALLOC = True
-WITH_BF_STATICJEMALLOC = True
-BF_JEMALLOC = '/opt/lib/jemalloc'
-BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
-
-# Use 3d mouse library
-WITH_BF_3DMOUSE = True
-WITH_BF_STATIC3DMOUSE = True
-BF_3DMOUSE = '/opt/lib/libspnav'
-BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
-
-# FFT
-WITH_BF_FFTW3 = True
-WITH_BF_STATICFFTW3 = True
-
-# JACK
-WITH_BF_JACK = True
-WITH_BF_JACK_DYNLOAD = True
-
-# Cycles
-WITH_BF_CYCLES = True
-WITH_BF_CYCLES_CUDA_BINARIES = False
-
-WITH_BF_OIIO = True
-WITH_BF_STATICOIIO = True
-BF_OIIO = '/opt/lib/oiio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_JPEG}/lib/libjpeg.a'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-
-BF_IS_NEW_OSL = False
-WITH_BF_CYCLES_OSL = True
-WITH_BF_STATICOSL = BF_IS_NEW_OSL
-BF_OSL = '/opt/lib/osl'
-BF_OSL_INC = '${BF_OSL}/include'
-# note oslexec would passed via program linkflags, which is needed to
-# make llvm happy with osl_allocate_closure_component
-BF_OSL_LIB = 'oslcomp oslexec oslquery'
-BF_OSL_LIB_STATIC = '${BF_OSL}/lib/liboslcomp.a ${BF_OSL}/lib/liboslexec.a ${BF_OSL}/lib/liboslquery.a'
-BF_OSL_LIBPATH = '${BF_OSL}/lib'
-BF_OSL_COMPILER = '${BF_OSL}/bin/oslc'
-
-WITH_BF_LLVM = True
-WITH_BF_STATICLLVM = False
-BF_LLVM = '/opt/lib/llvm-3.4.2'
-BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMObject LLVMX86Info LLVMX86AsmPrinter ' + \
- 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \
- 'LLVMTarget LLVMMC LLVMCore LLVMSupport'
-BF_LLVM_LIBPATH = '${BF_LLVM}/lib'
-
-# Color management
-WITH_BF_OCIO = True
-WITH_BF_STATICOCIO = True
-BF_OCIO = '/opt/lib/ocio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-WITH_BF_STATICBOOST = True
-BF_BOOST = '/opt/lib/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \
- '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \
- ${BF_BOOST_LIBPATH}/libboost_thread.a'
-if BF_IS_NEW_OSL:
- BF_BOOST_LIB_STATIC += ' ${BF_BOOST_LIBPATH}/libboost_wave.a'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-# Ocean Simulation
-WITH_BF_OCEANSIM = True
-
-# OpenSubdiv
-WITH_BF_OPENSUBDIV = True
-WITH_BF_STATICOPENSUBDIV = True
-BF_OPENSUBDIV = '/opt/lib/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-BF_OPENSUBDIV_LIB_STATIC = '${BF_OPENSUBDIV}/lib/libosdCPU.a ${BF_OPENSUBDIV}/lib/libosdGPU.a'
-
-# Compilation and optimization
-BF_DEBUG = False
-REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
-PLATFORM_LINKFLAGS = ['-lrt']
-if BF_IS_NEW_OSL:
- BF_PROGRAM_LINKFLAGS = ['-Wl,--version-script=source/creator/blender.map']
-else:
- BF_PROGRAM_LINKFLAGS = ['-Wl,--whole-archive', '-loslexec', '-Wl,--no-whole-archive', '-Wl,--version-script=source/creator/blender.map']
diff --git a/build_files/buildbot/config/user-config-glibc211-x86_64.py b/build_files/buildbot/config/user-config-glibc211-x86_64.py
deleted file mode 100644
index a3195cd9f06..00000000000
--- a/build_files/buildbot/config/user-config-glibc211-x86_64.py
+++ /dev/null
@@ -1,185 +0,0 @@
-BF_BUILDDIR = '../blender-build/linux-glibc211-x86_64'
-BF_INSTALLDIR = '../blender-install/linux-glibc211-x86_64'
-BF_NUMJOBS = 4
-WITHOUT_BF_OVERWRITE_INSTALL = True
-
-# Python configuration
-BF_PYTHON_VERSION = '3.4'
-BF_PYTHON_ABI_FLAGS = 'm'
-BF_PYTHON = '/opt/lib/python-3.4'
-WITH_BF_PYTHON_INSTALL_NUMPY = True
-WITH_BF_PYTHON_INSTALL_REQUESTS = True
-
-WITH_BF_STATICPYTHON = True
-
-# OpenCollada configuration
-WITH_BF_COLLADA = True
-WITH_BF_STATICOPENCOLLADA=True
-BF_OPENCOLLADA = '/opt/lib/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
-BF_OPENCOLLADA_LIB_STATIC = '${BF_OPENCOLLADA}/lib/libOpenCOLLADAStreamWriter.a ' + \
- '${BF_OPENCOLLADA}/lib/libOpenCOLLADASaxFrameworkLoader.a ' + \
- '${BF_OPENCOLLADA}/lib/libOpenCOLLADAFramework.a ' + \
- '${BF_OPENCOLLADA}/lib/libOpenCOLLADABaseUtils.a ' + \
- '${BF_OPENCOLLADA}/lib/libGeneratedSaxParser.a ' + \
- '${BF_OPENCOLLADA}/lib/libMathMLSolver.a ' + \
- '${BF_OPENCOLLADA}/lib/libbuffer.a ${BF_OPENCOLLADA}/lib/libftoa.a ' + \
- '/usr/lib/libxml2.a /usr/lib/libexpat.a /usr/lib/libpcre.a'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib /home/sources/staticlibs/lib64'
-BF_PCRE_LIB = ''
-BF_EXPAT_LIB = ''
-
-# FFMPEG configuration
-WITH_BF_FFMPEG = True
-WITH_BF_STATICFFMPEG = True
-
-BF_FFMPEG = '/opt/lib/ffmpeg'
-BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \
- '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \
- '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \
- '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \
- '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \
- '/usr/lib/liborc-0.4.a'
-
-# Don't depend on system's libstdc++
-WITH_BF_STATICCXX = True
-BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7.1/libstdc++.a'
-
-WITH_BF_OPENAL = True
-WITH_BF_STATICOPENAL = True
-BF_OPENAL = '/opt/lib/openal'
-BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a'
-
-WITH_BF_GETTEXT_STATIC = True
-
-WITH_BF_FREETYPE_STATIC = False
-
-WITH_BF_OPENEXR = True
-BF_OPENEXR = '/opt/lib/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
-WITH_BF_STATICOPENEXR = True
-
-WITH_BF_TIFF = True
-WITH_BF_STATICTIFF = True
-BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a'
-
-WITH_BF_JPEG = True
-WITH_BF_STATICJPEG = True
-BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a'
-
-WITH_BF_PNG = True
-WITH_BF_STATICPNG = True
-BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a'
-
-WITH_BF_STATICLIBSAMPLERATE = True
-
-WITH_BF_ZLIB = True
-WITH_BF_STATICZLIB = True
-BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a'
-
-WITH_BF_SDL = True
-WITH_BF_SDL_DYNLOAD = True
-
-WITH_BF_OGG = True
-
-WITH_BF_OPENMP = True
-WITH_BF_STATICOPENMP = True
-BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7/libgomp.a'
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_BULLET = True
-
-# Blender player (would be enabled in it's own config)
-WITH_BF_PLAYER = False
-
-# Use jemalloc memory manager
-WITH_BF_JEMALLOC = True
-WITH_BF_STATICJEMALLOC = True
-BF_JEMALLOC = '/opt/lib/jemalloc'
-BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
-
-# Use 3d mouse library
-WITH_BF_3DMOUSE = True
-WITH_BF_STATIC3DMOUSE = True
-BF_3DMOUSE = '/opt/lib/libspnav'
-BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
-
-# FFT
-WITH_BF_FFTW3 = True
-WITH_BF_STATICFFTW3 = True
-
-# JACK
-WITH_BF_JACK = True
-WITH_BF_JACK_DYNLOAD = True
-
-# Cycles
-WITH_BF_CYCLES = True
-WITH_BF_CYCLES_CUDA_BINARIES = False
-
-WITH_BF_OIIO = True
-WITH_BF_STATICOIIO = True
-BF_OIIO = '/opt/lib/oiio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_JPEG}/lib/libjpeg.a'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-
-BF_IS_NEW_OSL = False
-WITH_BF_CYCLES_OSL = True
-WITH_BF_STATICOSL = BF_IS_NEW_OSL
-BF_OSL = '/opt/lib/osl'
-BF_OSL_INC = '${BF_OSL}/include'
-# note oslexec would passed via program linkflags, which is needed to
-# make llvm happy with osl_allocate_closure_component
-BF_OSL_LIB = 'oslcomp oslexec oslquery'
-BF_OSL_LIB_STATIC = '${BF_OSL}/lib/liboslcomp.a ${BF_OSL}/lib/liboslexec.a ${BF_OSL}/lib/liboslquery.a'
-BF_OSL_LIBPATH = '${BF_OSL}/lib'
-BF_OSL_COMPILER = '${BF_OSL}/bin/oslc'
-
-WITH_BF_LLVM = True
-WITH_BF_STATICLLVM = False
-BF_LLVM = '/opt/lib/llvm-3.4.2'
-BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMObject LLVMX86Info LLVMX86AsmPrinter ' + \
- 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \
- 'LLVMTarget LLVMMC LLVMCore LLVMSupport'
-BF_LLVM_LIBPATH = '${BF_LLVM}/lib'
-
-# Color management
-WITH_BF_OCIO = True
-WITH_BF_STATICOCIO = True
-BF_OCIO = '/opt/lib/ocio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-WITH_BF_STATICBOOST = True
-BF_BOOST = '/opt/lib/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \
- '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \
- ${BF_BOOST_LIBPATH}/libboost_thread.a'
-if BF_IS_NEW_OSL:
- BF_BOOST_LIB_STATIC += ' ${BF_BOOST_LIBPATH}/libboost_wave.a'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-# Ocean Simulation
-WITH_BF_OCEANSIM = True
-
-# OpenSubdiv
-WITH_BF_OPENSUBDIV = True
-WITH_BF_STATICOPENSUBDIV = True
-BF_OPENSUBDIV = '/opt/lib/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-BF_OPENSUBDIV_LIB_STATIC = '${BF_OPENSUBDIV}/lib/libosdCPU.a ${BF_OPENSUBDIV}/lib/libosdGPU.a'
-
-# Compilation and optimization
-BF_DEBUG = False
-REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
-PLATFORM_LINKFLAGS = ['-lrt']
-if BF_IS_NEW_OSL:
- BF_PROGRAM_LINKFLAGS = ['-Wl,--version-script=source/creator/blender.map']
-else:
- BF_PROGRAM_LINKFLAGS = ['-Wl,--whole-archive', '-loslexec', '-Wl,--no-whole-archive', '-Wl,--version-script=source/creator/blender.map']
diff --git a/build_files/buildbot/config/user-config-mac-i386.py b/build_files/buildbot/config/user-config-mac-i386.py
deleted file mode 100644
index c1beefcf83d..00000000000
--- a/build_files/buildbot/config/user-config-mac-i386.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-MACOSX_ARCHITECTURE = 'i386' # valid archs: ppc, i386, ppc64, x86_64
-
-WITH_BF_CYCLES_CUDA_BINARIES = True
-
-WITH_BF_CYCLES_OSL = False # OSL never worked on OSX 32bit !
-
-WITH_BF_COLLADA = False # we drop 32bit, newest collada is only x86_64 !
-
diff --git a/build_files/buildbot/config/user-config-mac-x86_64.py b/build_files/buildbot/config/user-config-mac-x86_64.py
deleted file mode 100644
index 6a13c80f6ce..00000000000
--- a/build_files/buildbot/config/user-config-mac-x86_64.py
+++ /dev/null
@@ -1,6 +0,0 @@
-CC = "../lib/darwin-9.x.universal/clang-omp-3.5/bin/clang"
-CXX = "../lib/darwin-9.x.universal/clang-omp-3.5/bin/clang++"
-
-MACOSX_ARCHITECTURE = 'x86_64' # valid archs: ppc, i386, ppc64, x86_64
-
-WITH_BF_CYCLES_CUDA_BINARIES = True
diff --git a/build_files/buildbot/config/user-config-player-glibc211-i686.py b/build_files/buildbot/config/user-config-player-glibc211-i686.py
deleted file mode 100644
index b3c26ebb310..00000000000
--- a/build_files/buildbot/config/user-config-player-glibc211-i686.py
+++ /dev/null
@@ -1,126 +0,0 @@
-BF_BUILDDIR = '../blender-build/linux-glibc211-i686'
-BF_INSTALLDIR = '../blender-install/linux-glibc211-i686'
-BF_NUMJOBS = 4
-
-# Python configuration
-BF_PYTHON_VERSION = '3.4'
-BF_PYTHON_ABI_FLAGS = 'm'
-BF_PYTHON = '/opt/lib/python-3.4'
-WITH_BF_PYTHON_INSTALL_NUMPY = True
-WITH_BF_PYTHON_INSTALL_REQUESTS = True
-
-WITH_BF_STATICPYTHON = True
-
-# OpenCollada configuration
-WITH_BF_COLLADA = False
-
-# FFMPEG configuration
-WITH_BF_FFMPEG = True
-WITH_BF_STATICFFMPEG = True
-
-BF_FFMPEG = '/opt/lib/ffmpeg'
-BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \
- '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \
- '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \
- '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \
- '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \
- '/usr/lib/liborc-0.4.a'
-
-# Don't depend on system's libstdc++
-WITH_BF_STATICCXX = True
-BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7.1/libstdc++.a'
-
-WITH_BF_OPENAL = True
-WITH_BF_STATICOPENAL = True
-BF_OPENAL = '/opt/lib/openal'
-BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a'
-
-WITH_BF_GETTEXT_STATIC = True
-
-WITH_BF_FREETYPE_STATIC = False
-
-WITH_BF_OPENEXR = True
-BF_OPENEXR = '/opt/lib/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
-WITH_BF_STATICOPENEXR = True
-
-WITH_BF_TIFF = True
-WITH_BF_STATICTIFF = True
-BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a'
-
-WITH_BF_JPEG = True
-WITH_BF_STATICJPEG = True
-BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a'
-
-WITH_BF_STATICLIBSAMPLERATE = True
-
-WITH_BF_PNG = True
-WITH_BF_STATICPNG = True
-BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a'
-
-WITH_BF_ZLIB = True
-WITH_BF_STATICZLIB = True
-BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a'
-
-WITH_BF_SDL = True
-WITH_BF_SDL_DYNLOAD = True
-
-WITH_BF_OGG = False
-
-WITH_BF_OPENMP = True
-WITH_BF_STATICOPENMP = True
-BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7/libgomp.a'
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_BULLET = True
-
-# Do not build blender when building blenderplayer
-WITH_BF_NOBLENDER = True
-WITH_BF_PLAYER = True
-
-# Use jemalloc memory manager
-WITH_BF_JEMALLOC = True
-WITH_BF_STATICJEMALLOC = True
-BF_JEMALLOC = '/opt/lib/jemalloc'
-BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
-
-# Use 3d mouse library
-WITH_BF_3DMOUSE = True
-WITH_BF_STATIC3DMOUSE = True
-BF_3DMOUSE = '/opt/lib/libspnav'
-BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
-
-# Color management
-WITH_BF_OCIO = True
-WITH_BF_STATICOCIO = True
-BF_OCIO = '/opt/lib/ocio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-WITH_BF_STATICBOOST = True
-BF_BOOST = '/opt/lib/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \
- '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \
- ${BF_BOOST_LIBPATH}/libboost_thread.a'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-# JACK
-WITH_BF_JACK = True
-WITH_BF_JACK_DYNLOAD = True
-
-# Motion Tracking
-WITH_BF_LIBMV = False
-
-# Ocean Simulation
-WITH_BF_FFTW3 = True
-WITH_BF_STATICFFTW3 = True
-WITH_BF_OCEANSIM = True
-
-# Compilation and optimization
-BF_DEBUG = False
-REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
-PLATFORM_LINKFLAGS = ['-lrt']
diff --git a/build_files/buildbot/config/user-config-player-glibc211-x86_64.py b/build_files/buildbot/config/user-config-player-glibc211-x86_64.py
deleted file mode 100644
index 173e15b08ca..00000000000
--- a/build_files/buildbot/config/user-config-player-glibc211-x86_64.py
+++ /dev/null
@@ -1,126 +0,0 @@
-BF_BUILDDIR = '../blender-build/linux-glibc211-x86_64'
-BF_INSTALLDIR = '../blender-install/linux-glibc211-x86_64'
-BF_NUMJOBS = 4
-
-# Python configuration
-BF_PYTHON_VERSION = '3.4'
-BF_PYTHON_ABI_FLAGS = 'm'
-BF_PYTHON = '/opt/lib/python-3.4'
-WITH_BF_PYTHON_INSTALL_NUMPY = True
-WITH_BF_PYTHON_INSTALL_REQUESTS = True
-
-WITH_BF_STATICPYTHON = True
-
-# OpenCollada configuration
-WITH_BF_COLLADA = False
-
-# FFMPEG configuration
-WITH_BF_FFMPEG = True
-WITH_BF_STATICFFMPEG = True
-
-BF_FFMPEG = '/opt/lib/ffmpeg'
-BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \
- '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \
- '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \
- '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \
- '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \
- '/usr/lib/liborc-0.4.a'
-
-# Don't depend on system's libstdc++
-WITH_BF_STATICCXX = True
-BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7.1/libstdc++.a'
-
-WITH_BF_OPENAL = True
-WITH_BF_STATICOPENAL = True
-BF_OPENAL = '/opt/lib/openal'
-BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a'
-
-WITH_BF_GETTEXT_STATIC = True
-
-WITH_BF_FREETYPE_STATIC = False
-
-WITH_BF_OPENEXR = True
-BF_OPENEXR = '/opt/lib/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
-WITH_BF_STATICOPENEXR = True
-
-WITH_BF_TIFF = True
-WITH_BF_STATICTIFF = True
-BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a'
-
-WITH_BF_JPEG = True
-WITH_BF_STATICJPEG = True
-BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a'
-
-WITH_BF_STATICLIBSAMPLERATE = True
-
-WITH_BF_PNG = True
-WITH_BF_STATICPNG = True
-BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a'
-
-WITH_BF_ZLIB = True
-WITH_BF_STATICZLIB = True
-BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a'
-
-WITH_BF_SDL = True
-WITH_BF_SDL_DYNLOAD = True
-
-WITH_BF_OGG = False
-
-WITH_BF_OPENMP = True
-WITH_BF_STATICOPENMP = True
-BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7/libgomp.a'
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_BULLET = True
-
-# Do not build blender when building blenderplayer
-WITH_BF_NOBLENDER = True
-WITH_BF_PLAYER = True
-
-# Use jemalloc memory manager
-WITH_BF_JEMALLOC = True
-WITH_BF_STATICJEMALLOC = True
-BF_JEMALLOC = '/opt/lib/jemalloc'
-BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
-
-# Use 3d mouse library
-WITH_BF_3DMOUSE = True
-WITH_BF_STATIC3DMOUSE = True
-BF_3DMOUSE = '/opt/lib/libspnav'
-BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
-
-# Color management
-WITH_BF_OCIO = True
-WITH_BF_STATICOCIO = True
-BF_OCIO = '/opt/lib/ocio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-WITH_BF_STATICBOOST = True
-BF_BOOST = '/opt/lib/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \
- '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \
- ${BF_BOOST_LIBPATH}/libboost_thread.a'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-# JACK
-WITH_BF_JACK = True
-WITH_BF_JACK_DYNLOAD = True
-
-# Motion Tracking
-WITH_BF_LIBMV = False
-
-# Ocean Simulation
-WITH_BF_FFTW3 = True
-WITH_BF_STATICFFTW3 = True
-WITH_BF_OCEANSIM = True
-
-# Compilation and optimization
-BF_DEBUG = False
-REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
-PLATFORM_LINKFLAGS = ['-lrt']
diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg
index 7b8dd175453..70dcbfbc1df 100644
--- a/build_files/buildbot/master.cfg
+++ b/build_files/buildbot/master.cfg
@@ -87,14 +87,13 @@ c['change_source'] = GitPoller(
# CODEBASES
#
-# Allow to controll separately things like branches for each repo and submodules.
+# Allow to control separately things like branches for each repo and submodules.
all_repositories = {
r'git://git.blender.org/blender.git': 'blender',
r'git://git.blender.org/blender-translations.git': 'blender-translations',
r'git://git.blender.org/blender-addons.git': 'blender-addons',
r'git://git.blender.org/blender-addons-contrib.git': 'blender-addons-contrib',
- r'git://git.blender.org/scons.git': 'scons',
r'https://svn.blender.org/svnroot/bf-blender/': 'lib svn',
}
@@ -129,7 +128,6 @@ def schedule_force_build(name):
forcesched.CodebaseParameter(hide=True, codebase="blender-translations"),
forcesched.CodebaseParameter(hide=True, codebase="blender-addons"),
forcesched.CodebaseParameter(hide=True, codebase="blender-addons-contrib"),
- forcesched.CodebaseParameter(hide=True, codebase="scons"),
forcesched.CodebaseParameter(hide=True, codebase="lib svn")],
properties=[]))
@@ -145,7 +143,6 @@ def schedule_build(name, hour, minute=0):
"blender-translations": {"repository": "", "branch": "master"},
"blender-addons": {"repository": "", "branch": "master"},
"blender-addons-contrib": {"repository": "", "branch": "master"},
- "scons": {"repository": "", "branch": "master"},
"lib svn": {"repository": "", "branch": "trunk"}},
branch=current_branch,
builderNames=[name],
@@ -267,8 +264,7 @@ def generic_builder(id, libdir='', branch='', rsync=False):
for submodule in ('blender-translations',
'blender-addons',
- 'blender-addons-contrib',
- 'scons'):
+ 'blender-addons-contrib'):
f.addStep(git_submodule_step(submodule))
f.addStep(git_step(branch))
@@ -282,11 +278,6 @@ def generic_builder(id, libdir='', branch='', rsync=False):
descriptionDone='packaged'))
if rsync:
f.addStep(rsync_step(id, branch, rsync_script))
- elif id.find('cmake') != -1:
- f.addStep(FileUpload(name='upload',
- slavesrc='buildbot_upload.zip',
- masterdest=filename,
- maxsize=150 * 1024 * 1024))
else:
f.addStep(FileUpload(name='upload',
slavesrc='buildbot_upload.zip',
@@ -299,24 +290,16 @@ def generic_builder(id, libdir='', branch='', rsync=False):
descriptionDone='unpacked'))
return f
-# builders
+# Builders
-add_builder(c, 'mac_x86_64_10_6_scons', 'darwin-9.x.universal', generic_builder, hour=5)
-add_builder(c, 'mac_i386_10_6_scons', 'darwin-9.x.universal', generic_builder, hour=11)
-add_builder(c, 'linux_glibc211_i386_scons', '', generic_builder, hour=1)
-add_builder(c, 'linux_glibc211_x86_64_scons', '', generic_builder, hour=2)
-#add_builder(c, 'win32_scons_vc2013', 'windows_vc12', generic_builder, hour=1)
-#add_builder(c, 'win64_scons_vc2013', 'win64_vc12', generic_builder, hour=2)
+add_builder(c, 'mac_x86_64_10_6_cmake', 'darwin-9.x.universal', generic_builder, hour=5)
+add_builder(c, 'linux_glibc211_i686_cmake', '', generic_builder, hour=1)
+add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2)
+add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=3)
+add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=4)
add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=3)
add_builder(c, 'win64_cmake_vc2013', 'win64_vc12', generic_builder, hour=4)
-#add_builder(c, 'mingw_win32_scons', 'mingw32', generic_builder, hour=4)
-#add_builder(c, 'mingw_win64_scons', 'mingw64', generic_builder, hour=3)
-#add_builder(c, 'freebsd_i386_cmake', '', generic_builder, hour=1)
-#add_builder(c, 'freebsd_x86_64_cmake', '', generic_builder, hour=2)
-
-# Multiview branch
-add_builder(c, 'multiview_win64_scons', 'win64', generic_builder, 'multiview', hour=4)
-add_builder(c, 'multiview_win32_scons', 'windows', generic_builder, 'multiview', hour=5)
+add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=5)
# STATUS TARGETS
#
diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py
index d30241a9e5c..0f34551cfc8 100644
--- a/build_files/buildbot/slave_compile.py
+++ b/build_files/buildbot/slave_compile.py
@@ -31,165 +31,172 @@ if len(sys.argv) < 2:
builder = sys.argv[1]
# we run from build/ directory
-blender_dir = '../blender.git'
+blender_dir = os.path.join('..', 'blender.git')
+
+
+def parse_header_file(filename, define):
+ import re
+ regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
+ with open(filename, "r") as file:
+ for l in file:
+ match = regex.match(l)
+ if match:
+ return match.group(1)
+ return None
if 'cmake' in builder:
# cmake
- # set build options
- cmake_options = ['-DCMAKE_BUILD_TYPE:STRING=Release']
-
- if builder.endswith('mac_x86_64_cmake'):
- cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
- elif builder.endswith('mac_i386_cmake'):
- cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=i386')
- elif builder.endswith('mac_ppc_cmake'):
- cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=ppc')
-
- if 'win64' in builder:
- cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"'])
- elif 'win32' in builder:
- cmake_options.append(['-G', '"Visual Studio 12 2013"'])
-
- cmake_options.append("-C../blender.git/build_files/cmake/config/blender_full.cmake")
- cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=1")
- # configure and make
- retcode = subprocess.call(['cmake', blender_dir] + cmake_options)
- if retcode != 0:
- sys.exit(retcode)
-
- if 'win32' in builder:
- retcode = subprocess.call(['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release'])
- elif 'win64' in builder:
- retcode = subprocess.call(['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release'])
+ # Some fine-tuning configuration
+ blender_dir = os.path.join('..', blender_dir)
+ build_dir = os.path.abspath(os.path.join('..', 'build', builder))
+ install_dir = os.path.abspath(os.path.join('..', 'install', builder))
+ targets = ['blender']
+
+ chroot_name = None # If not None command will be delegated to that chroot
+ cuda_chroot_name = None # If not None cuda compilationcommand will be delegated to that chroot
+ build_cubins = True # Whether to build Cycles CUDA kernels
+ remove_install_dir = False # Remove installation folder before building
+ bits = 64
+
+ # Config file to be used (relative to blender's sources root)
+ cmake_config_file = "build_files/cmake/config/blender_full.cmake"
+ cmake_player_config_file = None
+ cmake_cuda_config_file = None
+
+ # Set build options.
+ cmake_options = []
+ cmake_extra_options = ['-DCMAKE_BUILD_TYPE:STRING=Release']
+ cuda_cmake_options = []
+
+ if builder.startswith('mac'):
+ install_dir = None
+ # Set up OSX architecture
+ if builder.endswith('x86_64_10_6_cmake'):
+ cmake_extra_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64')
+ cmake_extra_options.append('-DCUDA_NVCC_EXECUTABLE=/usr/local/cuda-hack/bin/nvcc')
+
+ elif builder.startswith('win'):
+ install_dir = None
+ if builder.startswith('win64'):
+ cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"'])
+ elif builder.startswith('win32'):
+ bits = 32
+ cmake_options.append(['-G', '"Visual Studio 12 2013"'])
+
+ elif builder.startswith('linux'):
+ tokens = builder.split("_")
+ glibc = tokens[1]
+ if glibc == 'glibc219':
+ deb_name = "jessie"
+ elif glibc == 'glibc211':
+ deb_name = "squeeze"
+ remove_install_dir = True
+ cmake_config_file = "build_files/buildbot/config/blender_linux.cmake"
+ cmake_player_config_file = "build_files/buildbot/config/blender_linux_player.cmake"
+ if builder.endswith('x86_64_cmake'):
+ chroot_name = 'buildbot_' + deb_name + '_x86_64'
+ targets = ['player', 'blender']
+ elif builder.endswith('i686_cmake'):
+ bits = 32
+ chroot_name = 'buildbot_' + deb_name + '_i686'
+ cuda_chroot_name = 'buildbot_' + deb_name + '_x86_64'
+ targets = ['player', 'blender', 'cuda']
+
+ cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file))
+
+ # Prepare CMake options needed to configure cuda binaries compilation.
+ cuda_cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=%s" % ('ON' if build_cubins else 'OFF'))
+ if build_cubins or 'cuda' in targets:
+ if bits == 32:
+ cuda_cmake_options.append("-DCUDA_64_BIT_DEVICE_CODE=OFF")
+ else:
+ cuda_cmake_options.append("-DCUDA_64_BIT_DEVICE_CODE=ON")
+
+ # Only modify common cmake options if cuda doesn't require separate target.
+ if 'cuda' not in targets:
+ cmake_options += cuda_cmake_options
+
+ if install_dir:
+ cmake_options.append("-DCMAKE_INSTALL_PREFIX=%s" % (install_dir))
+
+ cmake_options += cmake_extra_options
+
+ # Prepare chroot command prefix if needed
+ if chroot_name:
+ chroot_prefix = ['schroot', '-c', chroot_name, '--']
else:
- retcode = subprocess.call(['make', '-s', '-j4', 'install'])
- sys.exit(retcode)
-else:
- python_bin = 'python'
- if builder.find('linux') != -1:
- python_bin = '/opt/lib/python-2.7/bin/python2.7'
-
- # scons
- os.chdir(blender_dir)
- scons_cmd = [python_bin, 'scons/scons.py']
- scons_options = ['BF_FANCY=False']
-
- # We're using the same rules as release builder, so tweak
- # build and install dirs
- build_dir = os.path.join('..', 'build', builder)
- install_dir = os.path.join('..', 'install', builder)
-
- # Clean install directory so we'll be sure there's no
- # residual libs and files remained from the previous install.
- if os.path.isdir(install_dir):
- shutil.rmtree(install_dir)
-
- buildbot_dir = os.path.dirname(os.path.realpath(__file__))
- config_dir = os.path.join(buildbot_dir, 'config')
-
- if builder.find('linux') != -1:
- configs = []
- if builder.endswith('linux_glibc211_x86_64_scons'):
- configs = ['user-config-player-glibc211-x86_64.py',
- 'user-config-cuda-glibc211-x86_64.py',
- 'user-config-glibc211-x86_64.py'
- ]
- chroot_name = 'buildbot_squeeze_x86_64'
- cuda_chroot = 'buildbot_squeeze_x86_64'
- elif builder.endswith('linux_glibc211_i386_scons'):
- configs = ['user-config-player-glibc211-i686.py',
- 'user-config-cuda-glibc211-i686.py',
- 'user-config-glibc211-i686.py']
- chroot_name = 'buildbot_squeeze_i686'
-
- # use 64bit cuda toolkit, so there'll be no memory limit issues
- cuda_chroot = 'buildbot_squeeze_x86_64'
-
- # Compilation will happen inside of chroot environment
- prog_scons_cmd = ['schroot', '-c', chroot_name, '--'] + scons_cmd
- cuda_scons_cmd = ['schroot', '-c', cuda_chroot, '--'] + scons_cmd
-
- common_options = ['BF_INSTALLDIR=' + install_dir] + scons_options
-
- for config in configs:
- config_fpath = os.path.join(config_dir, config)
-
- scons_options = []
-
- if config.find('player') != -1:
- scons_options.append('BF_BUILDDIR=%s_player' % (build_dir))
- elif config.find('cuda') != -1:
- scons_options.append('BF_BUILDDIR=%s_cuda' % (build_dir))
- else:
- scons_options.append('BF_BUILDDIR=%s' % (build_dir))
-
- scons_options += common_options
-
- if config.find('player') != -1:
- scons_options.append('blenderplayer')
- cur_scons_cmd = prog_scons_cmd
- elif config.find('cuda') != -1:
- scons_options.append('cudakernels')
- cur_scons_cmd = cuda_scons_cmd
-
- if config.find('i686') != -1:
- scons_options.append('BF_BITNESS=32')
- elif config.find('x86_64') != -1:
- scons_options.append('BF_BITNESS=64')
- else:
- scons_options.append('blender')
- cur_scons_cmd = prog_scons_cmd
-
- scons_options.append('BF_CONFIG=' + config_fpath)
-
- retcode = subprocess.call(cur_scons_cmd + scons_options)
- if retcode != 0:
- print('Error building rules with config ' + config)
- sys.exit(retcode)
-
- sys.exit(0)
+ chroot_prefix = []
+ if cuda_chroot_name:
+ cuda_chroot_prefix = ['schroot', '-c', cuda_chroot_name, '--']
else:
- if builder.find('win') != -1:
- bitness = '32'
-
- if builder.find('win64') != -1:
- bitness = '64'
-
- scons_options.append('BF_INSTALLDIR=' + install_dir)
- scons_options.append('BF_BUILDDIR=' + build_dir)
- scons_options.append('BF_BITNESS=' + bitness)
- scons_options.append('WITH_BF_CYCLES_CUDA_BINARIES=True')
- scons_options.append('BF_CYCLES_CUDA_NVCC=nvcc.exe')
- if builder.find('mingw') != -1:
- scons_options.append('BF_TOOLSET=mingw')
- if builder.endswith('vc2013'):
- scons_options.append('MSVS_VERSION=12.0')
- scons_options.append('MSVC_VERSION=12.0')
- scons_options.append('WITH_BF_CYCLES_CUDA_BINARIES=1')
- scons_options.append('BF_CYCLES_CUDA_NVCC=nvcc.exe')
- scons_options.append('BF_NUMJOBS=1')
-
- elif builder.find('mac') != -1:
- if builder.find('x86_64') != -1:
- config = 'user-config-mac-x86_64.py'
- else:
- config = 'user-config-mac-i386.py'
-
- scons_options.append('BF_CONFIG=' + os.path.join(config_dir, config))
-
- if builder.find('win') != -1:
- if not os.path.exists(install_dir):
- os.makedirs(install_dir)
- if builder.endswith('vc2013'):
- dlls = ('msvcp120.dll', 'msvcr120.dll', 'vcomp120.dll')
- if builder.find('win64') == -1:
- dlls_path = '..\\..\\..\\redist\\x86'
- else:
- dlls_path = '..\\..\\..\\redist\\amd64'
- for dll in dlls:
- shutil.copyfile(os.path.join(dlls_path, dll), os.path.join(install_dir, dll))
-
- retcode = subprocess.call([python_bin, 'scons/scons.py'] + scons_options)
-
- sys.exit(retcode)
+ cuda_chroot_prefix = chroot_prefix[:]
+
+ # Make sure no garbage remained from the previous run
+ # (only do it if builder requested this)
+ if remove_install_dir:
+ if os.path.isdir(install_dir):
+ shutil.rmtree(install_dir)
+
+ for target in targets:
+ print("Building target %s" % (target))
+ # Construct build directory name based on the target
+ target_build_dir = build_dir
+ target_chroot_prefix = chroot_prefix[:]
+ if target != 'blender':
+ target_build_dir += '_' + target
+ target_name = 'install'
+ # Make sure build directory exists and enter it
+ if not os.path.isdir(target_build_dir):
+ os.mkdir(target_build_dir)
+ os.chdir(target_build_dir)
+ # Tweaking CMake options to respect the target
+ target_cmake_options = cmake_options[:]
+ if target == 'player':
+ target_cmake_options.append("-C" + os.path.join(blender_dir, cmake_player_config_file))
+ elif target == 'cuda':
+ target_cmake_options += cuda_cmake_options
+ target_chroot_prefix = cuda_chroot_prefix[:]
+ target_name = 'cycles_kernel_cuda'
+ # If cuda binaries are compiled as a separate target, make sure
+ # other targets don't compile cuda binaries.
+ if 'cuda' in targets and target != 'cuda':
+ target_cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=OFF")
+ # Configure the build
+ print("CMake options:")
+ print(target_cmake_options)
+ if os.path.exists('CMakeCache.txt'):
+ print("Removing CMake cache")
+ os.remove('CMakeCache.txt')
+ retcode = subprocess.call(target_chroot_prefix + ['cmake', blender_dir] + target_cmake_options)
+ if retcode != 0:
+ print('Condifuration FAILED!')
+ sys.exit(retcode)
+
+ if 'win32' in builder:
+ command = ['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release']
+ elif 'win64' in builder:
+ command = ['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release']
+ else:
+ command = target_chroot_prefix + ['make', '-s', '-j2', target_name]
+
+ print("Executing command:")
+ print(command)
+ retcode = subprocess.call(command)
+
+ if retcode != 0:
+ sys.exit(retcode)
+
+ if builder.startswith('linux') and target == 'cuda':
+ blender_h = os.path.join(blender_dir, "source", "blender", "blenkernel", "BKE_blender.h")
+ blender_version = int(parse_header_file(blender_h, 'BLENDER_VERSION'))
+ blender_version = "%d.%d" % (blender_version // 100, blender_version % 100)
+ kernels = os.path.join(target_build_dir, 'intern', 'cycles', 'kernel')
+ install_kernels = os.path.join(install_dir, blender_version, 'scripts', 'addons', 'cycles', 'lib')
+ os.mkdir(install_kernels)
+ print("Copying cuda binaries from %s to %s" % (kernels, install_kernels))
+ os.system('cp %s/*.cubin %s' % (kernels, install_kernels))
+
+else:
+ print("Unknown building system")
+ sys.exit(1)
diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py
index aec7cdca80a..4deb0b1a081 100644
--- a/build_files/buildbot/slave_pack.py
+++ b/build_files/buildbot/slave_pack.py
@@ -36,101 +36,78 @@ builder = sys.argv[1]
# Never write branch if it is master.
branch = sys.argv[2] if (len(sys.argv) >= 3 and sys.argv[2] != 'master') else ''
-# scons does own packaging
-if builder.find('scons') != -1:
- python_bin = 'python'
- if builder.find('linux') != -1:
- python_bin = '/opt/lib/python-2.7/bin/python2.7'
-
- os.chdir('../blender.git')
- scons_options = ['BF_QUICK=slnt', 'BUILDBOT_BRANCH=' + branch, 'buildslave', 'BF_FANCY=False']
-
- buildbot_dir = os.path.dirname(os.path.realpath(__file__))
- config_dir = os.path.join(buildbot_dir, 'config')
- build_dir = os.path.join('..', 'build', builder)
- install_dir = os.path.join('..', 'install', builder)
-
- if builder.find('linux') != -1:
- scons_options += ['WITH_BF_NOBLENDER=True', 'WITH_BF_PLAYER=False',
- 'BF_BUILDDIR=' + build_dir,
- 'BF_INSTALLDIR=' + install_dir,
- 'WITHOUT_BF_INSTALL=True']
-
- config = None
- bits = None
-
- if builder.endswith('linux_glibc211_x86_64_scons'):
- config = 'user-config-glibc211-x86_64.py'
- chroot_name = 'buildbot_squeeze_x86_64'
- bits = 64
- elif builder.endswith('linux_glibc211_i386_scons'):
- config = 'user-config-glibc211-i686.py'
- chroot_name = 'buildbot_squeeze_i686'
- bits = 32
+blender_dir = os.path.join('..', 'blender.git')
+build_dir = os.path.join('..', 'build', builder)
+install_dir = os.path.join('..', 'install', builder)
+buildbot_upload_zip = os.path.abspath(os.path.join(os.path.dirname(install_dir), "buildbot_upload.zip"))
- if config is not None:
- config_fpath = os.path.join(config_dir, config)
- scons_options.append('BF_CONFIG=' + config_fpath)
+upload_filename = None # Name of the archive to be uploaded
+ # (this is the name of archive which will appear on the
+ # download page)
+upload_filepath = None # Filepath to be uploaded to the server
+ # (this folder will be packed)
- blender = os.path.join(install_dir, 'blender')
- blenderplayer = os.path.join(install_dir, 'blenderplayer')
- subprocess.call(['schroot', '-c', chroot_name, '--', 'strip', '--strip-all', blender, blenderplayer])
- extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
- mesalibs = os.path.join(extra, 'mesalibs' + str(bits) + '.tar.bz2')
- software_gl = os.path.join(extra, 'blender-softwaregl')
+def parse_header_file(filename, define):
+ import re
+ regex = re.compile("^#\s*define\s+%s\s+(.*)" % define)
+ with open(filename, "r") as file:
+ for l in file:
+ match = regex.match(l)
+ if match:
+ return match.group(1)
+ return None
- os.system('tar -xpf %s -C %s' % (mesalibs, install_dir))
- os.system('cp %s %s' % (software_gl, install_dir))
- os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl')))
- retcode = subprocess.call(['schroot', '-c', chroot_name, '--', python_bin, 'scons/scons.py'] + scons_options)
-
- sys.exit(retcode)
- else:
- if builder.find('win') != -1:
- bitness = '32'
-
- if builder.find('win64') != -1:
- bitness = '64'
-
- scons_options.append('BF_INSTALLDIR=' + install_dir)
- scons_options.append('BF_BUILDDIR=' + build_dir)
- scons_options.append('BF_BITNESS=' + bitness)
- scons_options.append('WITH_BF_CYCLES_CUDA_BINARIES=True')
- scons_options.append('BF_CYCLES_CUDA_NVCC=nvcc.exe')
- if builder.find('mingw') != -1:
- scons_options.append('BF_TOOLSET=mingw')
- if builder.endswith('vc2013'):
- scons_options.append('MSVS_VERSION=12.0')
- scons_options.append('MSVC_VERSION=12.0')
-
- elif builder.find('mac') != -1:
- if builder.find('x86_64') != -1:
- config = 'user-config-mac-x86_64.py'
- else:
- config = 'user-config-mac-i386.py'
-
- scons_options.append('BF_CONFIG=' + os.path.join(config_dir, config))
-
- retcode = subprocess.call([python_bin, 'scons/scons.py'] + scons_options)
- sys.exit(retcode)
-else:
+# Make sure install directory always exists
+if not os.path.exists(install_dir):
+ os.makedirs(install_dir)
+
+
+def create_tar_bz2(src, dest, package_name):
+ # One extra to remove leading os.sep when cleaning root for package_root
+ ln = len(src) + 1
+ flist = list()
+
+ # Create list of tuples containing file and archive name
+ for root, dirs, files in os.walk(src):
+ package_root = os.path.join(package_name, root[ln:])
+ flist.extend([(os.path.join(root, file), os.path.join(package_root, file)) for file in files])
+
+ import tarfile
+ package = tarfile.open(dest, 'w:bz2')
+ for entry in flist:
+ package.add(entry[0], entry[1], recursive=False)
+ package.close()
+
+
+if builder.find('cmake') != -1:
# CMake
- if 'win' in builder:
+ if 'win' in builder or 'mac' in builder:
+ os.chdir(build_dir)
+
files = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')]
for f in files:
os.remove(f)
retcode = subprocess.call(['cpack', '-G', 'ZIP'])
result_file = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')][0]
- # TODO(sergey): Such magic usually happens in SCon's packaging bu we don't have it
+ # TODO(sergey): Such magic usually happens in SCon's packaging but we don't have it
# in the CMake yet. For until then we do some magic here.
tokens = result_file.split('-')
blender_version = tokens[1].split('.')
blender_full_version = '.'.join(blender_version[0:2])
git_hash = tokens[2].split('.')[1]
platform = builder.split('_')[0]
+ if platform == 'mac':
+ # Special exception for OSX
+ platform = 'OSX-10.6-'
+ if builder.endswith('x86_64_10_6_cmake'):
+ platform += 'x86_64'
+ elif builder.endswith('i386_10_6_cmake'):
+ platform += 'i386'
+ elif builder.endswith('ppc_10_6_cmake'):
+ platform += 'ppc'
builderified_name = 'blender-{}-{}-{}'.format(blender_full_version, git_hash, platform)
if branch != '':
builderified_name = branch + "-" + builderified_name
@@ -138,10 +115,9 @@ else:
os.rename(result_file, "{}.zip".format(builderified_name))
# create zip file
try:
- upload_zip = "buildbot_upload.zip"
- if os.path.exists(upload_zip):
- os.remove(upload_zip)
- z = zipfile.ZipFile(upload_zip, "w", compression=zipfile.ZIP_STORED)
+ if os.path.exists(buildbot_upload_zip):
+ os.remove(buildbot_upload_zip)
+ z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED)
z.write("{}.zip".format(builderified_name))
z.close()
sys.exit(retcode)
@@ -149,48 +125,114 @@ else:
sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n')
sys.exit(1)
+ elif builder.startswith('linux_'):
+ blender = os.path.join(install_dir, 'blender')
+ blenderplayer = os.path.join(install_dir, 'blenderplayer')
-# clean release directory if it already exists
-release_dir = 'release'
+ buildinfo_h = os.path.join(build_dir, "source", "creator", "buildinfo.h")
+ blender_h = os.path.join(blender_dir, "source", "blender", "blenkernel", "BKE_blender.h")
-if os.path.exists(release_dir):
- for f in os.listdir(release_dir):
- if os.path.isfile(os.path.join(release_dir, f)):
- os.remove(os.path.join(release_dir, f))
+ # Get version information
+ blender_version = int(parse_header_file(blender_h, 'BLENDER_VERSION'))
+ blender_version = "%d.%d" % (blender_version // 100, blender_version % 100)
+ blender_hash = parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1]
+ blender_glibc = builder.split('_')[1]
-# create release package
-try:
- subprocess.call(['make', 'package_archive'])
-except Exception as ex:
- sys.stderr.write('Make package release failed' + str(ex) + '\n')
- sys.exit(1)
+ if builder.endswith('x86_64_cmake'):
+ chroot_name = 'buildbot_squeeze_x86_64'
+ bits = 64
+ blender_arch = 'x86_64'
+ elif builder.endswith('i686_cmake'):
+ chroot_name = 'buildbot_squeeze_i686'
+ bits = 32
+ blender_arch = 'i686'
-# find release directory, must exist this time
-if not os.path.exists(release_dir):
- sys.stderr.write("Failed to find release directory %r.\n" % release_dir)
- sys.exit(1)
+ # Strip all unused symbols from the binaries
+ print("Stripping binaries...")
+ chroot_prefix = ['schroot', '-c', chroot_name, '--']
+ subprocess.call(chroot_prefix + ['strip', '--strip-all', blender, blenderplayer])
-# find release package
-file = None
-filepath = None
+ print("Stripping python...")
+ py_target = os.path.join(install_dir, blender_version)
+ subprocess.call(chroot_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';'])
-for f in os.listdir(release_dir):
- rf = os.path.join(release_dir, f)
- if os.path.isfile(rf) and f.startswith('blender'):
- file = f
- filepath = rf
+ # Copy all specific files which are too specific to be copied by
+ # the CMake rules themselves
+ print("Copying extra scripts and libs...")
+
+ extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra')
+ mesalibs = os.path.join(extra, 'mesalibs' + str(bits) + '.tar.bz2')
+ software_gl = os.path.join(blender_dir, 'release', 'bin', 'blender-softwaregl')
+ icons = os.path.join(blender_dir, 'release', 'freedesktop', 'icons')
+
+ os.system('tar -xpf %s -C %s' % (mesalibs, install_dir))
+ os.system('cp %s %s' % (software_gl, install_dir))
+ os.system('cp -r %s %s' % (icons, install_dir))
+ os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl')))
+
+ # Construct archive name
+ package_name = 'blender-%s-%s-linux-%s-%s' % (blender_version,
+ blender_hash,
+ blender_glibc,
+ blender_arch)
+ if branch != '':
+ package_name = branch + "-" + package_name
-if not file:
- sys.stderr.write("Failed to find release package.\n")
+ upload_filename = package_name + ".tar.bz2"
+
+ print("Creating .tar.bz2 archive")
+ upload_filepath = install_dir + '.tar.bz2'
+ create_tar_bz2(install_dir, upload_filepath, package_name)
+else:
+ print("Unknown building system")
sys.exit(1)
+
+if upload_filepath is None:
+ # clean release directory if it already exists
+ release_dir = 'release'
+
+ if os.path.exists(release_dir):
+ for f in os.listdir(release_dir):
+ if os.path.isfile(os.path.join(release_dir, f)):
+ os.remove(os.path.join(release_dir, f))
+
+ # create release package
+ try:
+ subprocess.call(['make', 'package_archive'])
+ except Exception as ex:
+ sys.stderr.write('Make package release failed' + str(ex) + '\n')
+ sys.exit(1)
+
+ # find release directory, must exist this time
+ if not os.path.exists(release_dir):
+ sys.stderr.write("Failed to find release directory %r.\n" % release_dir)
+ sys.exit(1)
+
+ # find release package
+ file = None
+ filepath = None
+
+ for f in os.listdir(release_dir):
+ rf = os.path.join(release_dir, f)
+ if os.path.isfile(rf) and f.startswith('blender'):
+ file = f
+ filepath = rf
+
+ if not file:
+ sys.stderr.write("Failed to find release package.\n")
+ sys.exit(1)
+
+ upload_filename = file
+ upload_filepath = filepath
+
# create zip file
try:
- upload_zip = "buildbot_upload.zip"
+ upload_zip = os.path.join(buildbot_upload_zip)
if os.path.exists(upload_zip):
os.remove(upload_zip)
z = zipfile.ZipFile(upload_zip, "w", compression=zipfile.ZIP_STORED)
- z.write(filepath, arcname=file)
+ z.write(upload_filepath, arcname=upload_filename)
z.close()
except Exception as ex:
sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n')
diff --git a/build_files/buildbot/slave_test.py b/build_files/buildbot/slave_test.py
index ef7a4b23d04..6f313ede2ee 100644
--- a/build_files/buildbot/slave_test.py
+++ b/build_files/buildbot/slave_test.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import subprocess
+import os
import sys
# get builder name
@@ -33,8 +34,26 @@ blender_dir = '../blender.git'
if "cmake" in builder:
# cmake
- retcode = subprocess.call(['ctest', '.' '--output-on-failure'])
+
+ print("Automated tests are still DISABLED!")
+ sys.exit(0)
+
+ build_dir = os.path.abspath(os.path.join('..', 'build', builder))
+ chroot_name = None
+ chroot_prefix = []
+
+ """
+ if builder.endswith('x86_64_cmake'):
+ chroot_name = 'buildbot_squeeze_x86_64'
+ elif builder.endswith('i686_cmake'):
+ chroot_name = 'buildbot_squeeze_i686'
+ if chroot_name:
+ chroot_prefix = ['schroot', '-c', chroot_name, '--']
+ """
+
+ os.chdir(build_dir)
+ retcode = subprocess.call(chroot_prefix + ['ctest', '--output-on-failure'])
sys.exit(retcode)
else:
- # scons
- pass
+ print("Unknown building system")
+ sys.exit(1)
diff --git a/build_files/cmake/Modules/FindLLVM.cmake b/build_files/cmake/Modules/FindLLVM.cmake
index 43791c8df8c..f5f3db3fc71 100644
--- a/build_files/cmake/Modules/FindLLVM.cmake
+++ b/build_files/cmake/Modules/FindLLVM.cmake
@@ -64,7 +64,9 @@ if(LLVM_STATIC)
PATHS ${LLVM_LIBPATH})
else()
find_library(LLVM_LIBRARY
- NAMES LLVM-${LLVM_VERSION}
+ NAMES
+ LLVM-${LLVM_VERSION}
+ LLVMAnalysis # check for the static library as a fall-back
PATHS ${LLVM_LIBPATH})
endif()
diff --git a/build_files/cmake/Modules/FindOpenSubdiv.cmake b/build_files/cmake/Modules/FindOpenSubdiv.cmake
index efbe8a967e1..72025506c97 100644
--- a/build_files/cmake/Modules/FindOpenSubdiv.cmake
+++ b/build_files/cmake/Modules/FindOpenSubdiv.cmake
@@ -39,6 +39,7 @@ SET(_opensubdiv_SEARCH_DIRS
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt/lib/opensubdiv
+ /opt/lib/osd # install_deps.sh
)
FIND_PATH(OPENSUBDIV_INCLUDE_DIR
diff --git a/build_files/cmake/Modules/FindOpenVDB.cmake b/build_files/cmake/Modules/FindOpenVDB.cmake
new file mode 100644
index 00000000000..a13feab8e0e
--- /dev/null
+++ b/build_files/cmake/Modules/FindOpenVDB.cmake
@@ -0,0 +1,74 @@
+# - Find OPENVDB library
+# Find the native OPENVDB includes and library
+# This module defines
+# OPENVDB_INCLUDE_DIRS, where to find openvdb.h, Set when
+# OPENVDB_INCLUDE_DIR is found.
+# OPENVDB_LIBRARIES, libraries to link against to use OPENVDB.
+# OPENVDB_ROOT_DIR, The base directory to search for OPENVDB.
+# This can also be an environment variable.
+# OPENVDB_FOUND, If false, do not try to use OPENVDB.
+#
+# also defined, but not for general use are
+# OPENVDB_LIBRARY, where to find the OPENVDB library.
+
+#=============================================================================
+# Copyright 2015 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If OPENVDB_ROOT_DIR was defined in the environment, use it.
+IF(NOT OPENVDB_ROOT_DIR AND NOT $ENV{OPENVDB_ROOT_DIR} STREQUAL "")
+ SET(OPENVDB_ROOT_DIR $ENV{OPENVDB_ROOT_DIR})
+ENDIF()
+
+SET(_openvdb_SEARCH_DIRS
+ ${OPENVDB_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt/openvdb
+ /opt/lib/openvdb
+)
+
+FIND_PATH(OPENVDB_INCLUDE_DIR
+ NAMES
+ openvdb/openvdb.h
+ HINTS
+ ${_openvdb_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+FIND_LIBRARY(OPENVDB_LIBRARY
+ NAMES
+ openvdb
+ HINTS
+ ${_openvdb_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+)
+
+# handle the QUIETLY and REQUIRED arguments and set OPENVDB_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENVDB DEFAULT_MSG
+ OPENVDB_LIBRARY OPENVDB_INCLUDE_DIR)
+
+IF(OPENVDB_FOUND)
+ SET(OPENVDB_LIBRARIES ${OPENVDB_LIBRARY})
+ SET(OPENVDB_INCLUDE_DIRS ${OPENVDB_INCLUDE_DIR})
+ENDIF(OPENVDB_FOUND)
+
+MARK_AS_ADVANCED(
+ OPENVDB_INCLUDE_DIR
+ OPENVDB_LIBRARY
+)
+
+UNSET(_openvdb_SEARCH_DIRS)
diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
index e4236fb4c24..9d79bdd778d 100644
--- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake
+++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
@@ -38,7 +38,7 @@ IF(NOT PYTHON_ROOT_DIR AND NOT $ENV{PYTHON_ROOT_DIR} STREQUAL "")
SET(PYTHON_ROOT_DIR $ENV{PYTHON_ROOT_DIR})
ENDIF()
-SET(PYTHON_VERSION 3.4 CACHE STRING "Python Version (major and minor only)")
+SET(PYTHON_VERSION 3.5 CACHE STRING "Python Version (major and minor only)")
MARK_AS_ADVANCED(PYTHON_VERSION)
@@ -199,7 +199,7 @@ IF(PYTHONLIBSUNIX_FOUND)
)
# we need this for installation
- # XXX No more valid with debian-like py3.4 packages...
+ # XXX No more valid with debian-like py3.5 packages...
# GET_FILENAME_COMPONENT(PYTHON_LIBPATH ${PYTHON_LIBRARY} PATH)
# not required for build, just used when bundling Python.
diff --git a/build_files/cmake/Modules/FindTBB.cmake b/build_files/cmake/Modules/FindTBB.cmake
new file mode 100644
index 00000000000..8a821f8092e
--- /dev/null
+++ b/build_files/cmake/Modules/FindTBB.cmake
@@ -0,0 +1,73 @@
+# - Find TBB library
+# Find the native TBB includes and library
+# This module defines
+# TBB_INCLUDE_DIRS, where to find tbb.h, Set when
+# TBB is found.
+# TBB_LIBRARIES, libraries to link against to use TBB.
+# TBB_ROOT_DIR, The base directory to search for TBB.
+# This can also be an environment variable.
+# TBB_FOUND, If false, do not try to use TBB.
+#
+# also defined, but not for general use are
+# TBB_LIBRARY, where to find the TBB library.
+
+#=============================================================================
+# Copyright 2016 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If TBB_ROOT_DIR was defined in the environment, use it.
+IF(NOT TBB_ROOT_DIR AND NOT $ENV{TBB_ROOT_DIR} STREQUAL "")
+ SET(TBB_ROOT_DIR $ENV{TBB_ROOT_DIR})
+ENDIF()
+
+SET(_tbb_SEARCH_DIRS
+ ${TBB_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt/lib/tbb
+)
+
+FIND_PATH(TBB_INCLUDE_DIR
+ NAMES
+ tbb/tbb.h
+ HINTS
+ ${_tbb_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+FIND_LIBRARY(TBB_LIBRARY
+ NAMES
+ tbb
+ HINTS
+ ${_tbb_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+ )
+
+# handle the QUIETLY and REQUIRED arguments and set TBB_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(TBB DEFAULT_MSG
+ TBB_LIBRARY TBB_INCLUDE_DIR)
+
+IF(TBB_FOUND)
+ SET(TBB_LIBRARIES ${TBB_LIBRARY})
+ SET(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
+ELSE()
+ SET(TBB_TBB_FOUND FALSE)
+ENDIF()
+
+MARK_AS_ADVANCED(
+ TBB_INCLUDE_DIR
+ TBB_LIBRARY
+)
diff --git a/build_files/cmake/Modules/GTestTesting.cmake b/build_files/cmake/Modules/GTestTesting.cmake
index b98d15ecd41..3ccca1f199c 100644
--- a/build_files/cmake/Modules/GTestTesting.cmake
+++ b/build_files/cmake/Modules/GTestTesting.cmake
@@ -20,8 +20,8 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
set(TEST_INC
${_current_include_directories}
${CMAKE_SOURCE_DIR}/tests/gtests
- ${CMAKE_SOURCE_DIR}/extern/libmv/third_party/glog/src
- ${CMAKE_SOURCE_DIR}/extern/libmv/third_party/gflags
+ ${CMAKE_SOURCE_DIR}/extern/glog/src
+ ${CMAKE_SOURCE_DIR}/extern/gflags/src
${CMAKE_SOURCE_DIR}/extern/gtest/include
)
unset(_current_include_directories)
@@ -29,12 +29,14 @@ macro(BLENDER_SRC_GTEST_EX NAME SRC EXTRA_LIBS DO_ADD_TEST)
add_executable(${NAME}_test ${SRC})
target_link_libraries(${NAME}_test
${EXTRA_LIBS}
+ ${PLATFORM_LINKLIBS}
bf_testing_main
bf_intern_guardedalloc
extern_gtest
# needed for glog
${PTHREADS_LIBRARIES}
- extern_glog)
+ extern_glog
+ extern_gflags)
set_target_properties(${NAME}_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}"
diff --git a/build_files/cmake/buildinfo.cmake b/build_files/cmake/buildinfo.cmake
index 81b0c1b1e23..4caa4a954ea 100644
--- a/build_files/cmake/buildinfo.cmake
+++ b/build_files/cmake/buildinfo.cmake
@@ -9,126 +9,120 @@ set(MY_WC_COMMIT_TIMESTAMP 0)
# Guess if this is a git working copy and then look up the revision
if(EXISTS ${SOURCE_DIR}/.git)
- # The FindGit.cmake module is part of the standard distribution
- find_package(Git)
- if(GIT_FOUND)
- message(STATUS "-- Found Git: ${GIT_EXECUTABLE}")
+ execute_process(COMMAND git rev-parse --abbrev-ref HEAD
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE MY_WC_BRANCH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(MY_WC_BRANCH STREQUAL "HEAD")
+ # Detached HEAD, check whether commit hash is reachable
+ # in the master branch
+ execute_process(COMMAND git rev-parse --short HEAD
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE MY_WC_HASH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
- execute_process(COMMAND git rev-parse --abbrev-ref HEAD
+ execute_process(COMMAND git branch --list master --contains ${MY_WC_HASH}
WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE MY_WC_BRANCH
+ OUTPUT_VARIABLE _git_contains_check
OUTPUT_STRIP_TRAILING_WHITESPACE)
- if(MY_WC_BRANCH STREQUAL "HEAD")
- # Detached HEAD, check whether commit hash is reachable
- # in the master branch
- execute_process(COMMAND git rev-parse --short HEAD
+ STRING(REGEX REPLACE "^[ \t]+" "" _git_contains_check "${_git_contains_check}")
+ if(_git_contains_check STREQUAL "master")
+ set(MY_WC_BRANCH "master")
+ else()
+ execute_process(COMMAND git show-ref --tags -d
WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE MY_WC_HASH
+ OUTPUT_VARIABLE _git_tag_hashes
OUTPUT_STRIP_TRAILING_WHITESPACE)
- execute_process(COMMAND git branch --list master --contains ${MY_WC_HASH}
+ execute_process(COMMAND git rev-parse HEAD
WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE _git_contains_check
+ OUTPUT_VARIABLE _git_head_hash
OUTPUT_STRIP_TRAILING_WHITESPACE)
- STRING(REGEX REPLACE "^[ \t]+" "" _git_contains_check "${_git_contains_check}")
- if(_git_contains_check STREQUAL "master")
+ if(_git_tag_hashes MATCHES "${_git_head_hash}")
set(MY_WC_BRANCH "master")
- else()
- execute_process(COMMAND git show-ref --tags -d
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE _git_tag_hashes
- OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- execute_process(COMMAND git rev-parse HEAD
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE _git_head_hash
- OUTPUT_STRIP_TRAILING_WHITESPACE)
-
- if(_git_tag_hashes MATCHES "${_git_head_hash}")
- set(MY_WC_BRANCH "master")
- endif()
-
- unset(_git_tag_hashes)
- unset(_git_head_hashs)
endif()
+ unset(_git_tag_hashes)
+ unset(_git_head_hashs)
+ endif()
+
- unset(_git_contains_check)
+ unset(_git_contains_check)
+ else()
+ execute_process(COMMAND git log HEAD..@{u}
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE _git_below_check
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
+ if(NOT _git_below_check STREQUAL "")
+ # If there're commits between HEAD and upstream this means
+ # that we're reset-ed to older revision. Use it's hash then.
+ execute_process(COMMAND git rev-parse --short HEAD
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE MY_WC_HASH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
- execute_process(COMMAND git log HEAD..@{u}
+ execute_process(COMMAND git rev-parse --short @{u}
WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE _git_below_check
+ OUTPUT_VARIABLE MY_WC_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
- if(NOT _git_below_check STREQUAL "")
- # If there're commits between HEAD and upstream this means
- # that we're reset-ed to older revision. Use it's hash then.
+
+ if(MY_WC_HASH STREQUAL "")
+ # Local branch, not set to upstream.
+ # Well, let's use HEAD for now
execute_process(COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${SOURCE_DIR}
OUTPUT_VARIABLE MY_WC_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
- else()
- execute_process(COMMAND git rev-parse --short @{u}
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE MY_WC_HASH
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET)
-
- if(MY_WC_HASH STREQUAL "")
- # Local branch, not set to upstream.
- # Well, let's use HEAD for now
- execute_process(COMMAND git rev-parse --short HEAD
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE MY_WC_HASH
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- endif()
- endif()
-
- if(MY_WC_BRANCH MATCHES "^blender-v")
- set(MY_WC_BRANCH "master")
endif()
-
- unset(_git_below_check)
endif()
- execute_process(COMMAND git log -1 --format=%ct
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE MY_WC_COMMIT_TIMESTAMP
- OUTPUT_STRIP_TRAILING_WHITESPACE)
- # May fail in rare cases
- if(MY_WC_COMMIT_TIMESTAMP STREQUAL "")
- set(MY_WC_COMMIT_TIMESTAMP 0)
+ if(MY_WC_BRANCH MATCHES "^blender-v")
+ set(MY_WC_BRANCH "master")
endif()
- # Update GIT index before getting dirty files
- execute_process(COMMAND git update-index -q --refresh
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+ unset(_git_below_check)
+ endif()
- execute_process(COMMAND git diff-index --name-only HEAD --
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE _git_changed_files
- OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND git log -1 --format=%ct
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE MY_WC_COMMIT_TIMESTAMP
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ # May fail in rare cases
+ if(MY_WC_COMMIT_TIMESTAMP STREQUAL "")
+ set(MY_WC_COMMIT_TIMESTAMP 0)
+ endif()
- if(NOT _git_changed_files STREQUAL "")
+ # Update GIT index before getting dirty files
+ execute_process(COMMAND git update-index -q --refresh
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ execute_process(COMMAND git diff-index --name-only HEAD --
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE _git_changed_files
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if(NOT _git_changed_files STREQUAL "")
+ set(MY_WC_BRANCH "${MY_WC_BRANCH} (modified)")
+ else()
+ # Unpushed commits are also considered local modifications
+ execute_process(COMMAND git log @{u}..
+ WORKING_DIRECTORY ${SOURCE_DIR}
+ OUTPUT_VARIABLE _git_unpushed_log
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
+ if(NOT _git_unpushed_log STREQUAL "")
set(MY_WC_BRANCH "${MY_WC_BRANCH} (modified)")
- else()
- # Unpushed commits are also considered local modifications
- execute_process(COMMAND git log @{u}..
- WORKING_DIRECTORY ${SOURCE_DIR}
- OUTPUT_VARIABLE _git_unpushed_log
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET)
- if(NOT _git_unpushed_log STREQUAL "")
- set(MY_WC_BRANCH "${MY_WC_BRANCH} (modified)")
- endif()
- unset(_git_unpushed_log)
endif()
-
- unset(_git_changed_files)
+ unset(_git_unpushed_log)
endif()
+
+ unset(_git_changed_files)
endif()
# BUILD_PLATFORM and BUILD_PLATFORM are taken from CMake
diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py
index d0bbdda1870..6cd66b7640c 100755
--- a/build_files/cmake/cmake_consistency_check.py
+++ b/build_files/cmake/cmake_consistency_check.py
@@ -240,9 +240,10 @@ def cmake_get_src(f):
filen.close()
-def is_ignore(f):
- for ig in IGNORE:
+def is_ignore(f, ignore_used):
+ for index, ig in enumerate(IGNORE):
if ig in f:
+ ignore_used[index] = True
return True
return False
@@ -278,16 +279,17 @@ def main():
# Write a 'sed' script, useful if we get a lot of these
# print("sed '%dd' '%s' > '%s.tmp' ; mv '%s.tmp' '%s'" % (i, cf, cf, cf, cf))
-
if is_err:
raise Exception("CMake referenecs missing files, aborting!")
del is_err
del errs
+ ignore_used = [False] * len(IGNORE)
+
# now check on files not accounted for.
print("\nC/C++ Files CMake doesnt know about...")
for cf in sorted(source_list(SOURCE_DIR, is_c)):
- if not is_ignore(cf):
+ if not is_ignore(cf, ignore_used):
if cf not in global_c:
print("missing_c: ", cf)
@@ -304,7 +306,7 @@ def main():
print("\nC/C++ Headers CMake doesnt know about...")
for hf in sorted(source_list(SOURCE_DIR, is_c_header)):
- if not is_ignore(hf):
+ if not is_ignore(hf, ignore_used):
if hf not in global_h:
print("missing_h: ", hf)
@@ -325,5 +327,12 @@ def main():
if i > 1:
traceback.print_exc()
+ # Check ignores aren't stale
+ print("\nCheck for unused 'IGNORE' paths...")
+ for index, ig in enumerate(IGNORE):
+ if not ignore_used[index]:
+ print("unused ignore: %r" % ig)
+
+
if __name__ == "__main__":
main()
diff --git a/build_files/cmake/cmake_consistency_check_config.py b/build_files/cmake/cmake_consistency_check_config.py
index 1f75b9884bc..7e7cd40dbea 100644
--- a/build_files/cmake/cmake_consistency_check_config.py
+++ b/build_files/cmake/cmake_consistency_check_config.py
@@ -3,16 +3,9 @@ import os
IGNORE = (
"/test/",
"/tests/gtests/",
- "/BSP_GhostTest/",
"/release/",
- "/xembed/",
- "/TerraplayNetwork/",
- "/ik_glut_test/",
# specific source files
- "extern/Eigen2/Eigen/src/Cholesky/CholeskyInstantiations.cpp",
- "extern/Eigen2/Eigen/src/Core/CoreInstantiations.cpp",
- "extern/Eigen2/Eigen/src/QR/QrInstantiations.cpp",
"extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp",
"extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp",
"extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp",
@@ -21,31 +14,8 @@ IGNORE = (
"extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp",
"extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp",
"extern/bullet2/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp",
- "extern/eltopo/common/meshes/ObjLoader.cpp",
- "extern/eltopo/common/meshes/meshloader.cpp",
- "extern/eltopo/common/openglutils.cpp",
- "extern/eltopo/eltopo3d/broadphase_blenderbvh.cpp",
- "source/blender/imbuf/intern/imbuf_cocoa.m",
- "extern/recastnavigation/Recast/Source/RecastLog.cpp",
- "extern/recastnavigation/Recast/Source/RecastTimer.cpp",
"intern/audaspace/SRC/AUD_SRCResampleFactory.cpp",
"intern/audaspace/SRC/AUD_SRCResampleReader.cpp",
- "intern/cycles/render/film_response.cpp",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc",
- "extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc",
"extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h",
"extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h",
@@ -55,20 +25,12 @@ IGNORE = (
"extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.h",
"extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h",
"extern/bullet2/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h",
- "extern/eltopo/common/meshes/Edge.hpp",
- "extern/eltopo/common/meshes/ObjLoader.hpp",
- "extern/eltopo/common/meshes/TriangleIndex.hpp",
- "extern/eltopo/common/meshes/meshloader.h",
- "extern/eltopo/eltopo3d/broadphase_blenderbvh.h",
- "extern/recastnavigation/Recast/Include/RecastLog.h",
- "extern/recastnavigation/Recast/Include/RecastTimer.h",
- "intern/audaspace/SRC/AUD_SRCResampleFactory.h",
- "intern/audaspace/SRC/AUD_SRCResampleReader.h",
- "intern/cycles/render/film_response.h",
"extern/carve/include/carve/config.h",
- "extern/carve/include/carve/external/boost/random.hpp",
+ "extern/carve/include/carve/random/random.h",
"extern/carve/patches/files/config.h",
- "extern/carve/patches/files/random.hpp",
+ "extern/carve/patches/files/random.h",
+ "intern/audaspace/SRC/AUD_SRCResampleFactory.h",
+ "intern/audaspace/SRC/AUD_SRCResampleReader.h",
)
UTF8_CHECK = True
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index d4cce46434d..8d66c101c6a 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -29,6 +29,13 @@ Example linux usage
Windows not supported so far
"""
+import sys
+
+# until we have arg parsing
+import project_info
+if not project_info.init(sys.argv[-1]):
+ sys.exit(1)
+
from project_info import (
SIMPLE_PROJECTFILE,
SOURCE_DIR,
@@ -50,6 +57,8 @@ from os.path import join, dirname, normpath, relpath, exists
def create_nb_project_main():
+ from xml.sax.saxutils import escape
+
files = list(source_list(SOURCE_DIR, filename_check=is_project_file))
files_rel = [relpath(f, start=PROJECT_DIR) for f in files]
files_rel.sort()
@@ -72,7 +81,6 @@ def create_nb_project_main():
# be tricky, get the project name from git if we can!
PROJECT_NAME = project_name_get()
-
make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
make_exe_basename = os.path.basename(make_exe)
@@ -207,8 +215,8 @@ def create_nb_project_main():
build_cmd = "${MAKE} -f Makefile"
clean_cmd = "${MAKE} -f Makefile clean"
- f.write(' <buildCommand>%s</buildCommand>\n' % build_cmd)
- f.write(' <cleanCommand>%s</cleanCommand>\n' % clean_cmd)
+ f.write(' <buildCommand>%s</buildCommand>\n' % escape(build_cmd))
+ f.write(' <cleanCommand>%s</cleanCommand>\n' % escape(clean_cmd))
f.write(' <executablePath>./bin/blender</executablePath>\n')
del build_cmd, clean_cmd
@@ -219,7 +227,7 @@ def create_nb_project_main():
f.write(' </incDir>\n')
f.write(' <preprocessorList>\n')
for cdef in defines:
- f.write(' <Elem>%s</Elem>\n' % cdef)
+ f.write(' <Elem>%s</Elem>\n' % escape(cdef))
f.write(' </preprocessorList>\n')
f.write(' <cTool>\n')
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index 67302c89a68..9c0a02a7a0c 100755
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -24,28 +24,14 @@
r"""
Example Linux usage:
- python ~/blender-git/blender/build_files/cmake/cmake_qtcreator_project.py ~/blender-git/cmake
+ python ~/blender-git/blender/build_files/cmake/cmake_qtcreator_project.py --build-dir ~/blender-git/cmake
Example Win32 usage:
- c:\Python32\python.exe c:\blender_dev\blender\build_files\cmake\cmake_qtcreator_project.py c:\blender_dev\cmake_build
+ c:\Python32\python.exe c:\blender_dev\blender\build_files\cmake\cmake_qtcreator_project.py --build-dir c:\blender_dev\cmake_build
"""
-from project_info import (
- SIMPLE_PROJECTFILE,
- SOURCE_DIR,
- # CMAKE_DIR,
- PROJECT_DIR,
- source_list,
- is_project_file,
- is_c_header,
- is_py,
- cmake_advanced_info,
- cmake_compiler_defines,
- project_name_get,
- )
import os
-import sys
def quote_define(define):
@@ -55,7 +41,20 @@ def quote_define(define):
return define
-def create_qtc_project_main():
+def create_qtc_project_main(name):
+ from project_info import (
+ SIMPLE_PROJECTFILE,
+ SOURCE_DIR,
+ # CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_project_file,
+ is_c_header,
+ cmake_advanced_info,
+ cmake_compiler_defines,
+ project_name_get,
+ )
+
files = list(source_list(SOURCE_DIR, filename_check=is_project_file))
files_rel = [os.path.relpath(f, start=PROJECT_DIR) for f in files]
files_rel.sort()
@@ -63,7 +62,7 @@ def create_qtc_project_main():
# --- qtcreator specific, simple format
if SIMPLE_PROJECTFILE:
# --- qtcreator specific, simple format
- PROJECT_NAME = "Blender"
+ PROJECT_NAME = name or "Blender"
FILE_NAME = PROJECT_NAME.lower()
with open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w') as f:
f.write("\n".join(files_rel))
@@ -91,11 +90,8 @@ def create_qtc_project_main():
for f in files_rel if is_c_header(f)))
includes.sort()
- if 0:
- PROJECT_NAME = "Blender"
- else:
- # be tricky, get the project name from CMake if we can!
- PROJECT_NAME = project_name_get()
+ # be tricky, get the project name from CMake if we can!
+ PROJECT_NAME = name or project_name_get()
FILE_NAME = PROJECT_NAME.lower()
with open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w') as f:
@@ -119,7 +115,7 @@ def create_qtc_project_main():
f.write("\n")
defines_final = [("#define %s %s" % (item[0], quote_define(item[1]))) for item in defines]
- if sys.platform != "win32":
+ if os.name != "nt":
defines_final += cmake_compiler_defines()
f.write("\n".join(defines_final))
@@ -127,17 +123,23 @@ def create_qtc_project_main():
# --- end
-def create_qtc_project_python():
+def create_qtc_project_python(name):
+ from project_info import (
+ SOURCE_DIR,
+ # CMAKE_DIR,
+ PROJECT_DIR,
+ source_list,
+ is_py,
+ project_name_get,
+ )
+
files = list(source_list(SOURCE_DIR, filename_check=is_py))
files_rel = [os.path.relpath(f, start=PROJECT_DIR) for f in files]
files_rel.sort()
# --- qtcreator specific, simple format
- if 0:
- PROJECT_NAME = "Blender_Python"
- else:
- # be tricky, get the project name from git if we can!
- PROJECT_NAME = project_name_get() + "_Python"
+ # be tricky, get the project name from git if we can!
+ PROJECT_NAME = (name or project_name_get()) + "_Python"
FILE_NAME = PROJECT_NAME.lower()
with open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w') as f:
@@ -155,9 +157,43 @@ def create_qtc_project_python():
print("Python project file written to: %r" % qtc_prj)
+def argparse_create():
+ import argparse
+
+ parser = argparse.ArgumentParser(
+ description="This script generates Qt Creator project files for Blender",
+ )
+
+ parser.add_argument(
+ "-n", "--name",
+ dest="name",
+ metavar='NAME', type=str,
+ help="Override default project name (\"Blender\")",
+ required=False,
+ )
+
+ parser.add_argument(
+ "-b", "--build-dir",
+ dest="build_dir",
+ metavar='BUILD_DIR', type=str,
+ help="Specify the build path (or fallback to the $PWD)",
+ required=False,
+ )
+
+ return parser
+
+
def main():
- create_qtc_project_main()
- create_qtc_project_python()
+ parser = argparse_create()
+ args = parser.parse_args()
+ name = args.name
+
+ import project_info
+ if not project_info.init(args.build_dir):
+ return
+
+ create_qtc_project_main(name)
+ create_qtc_project_python(name)
if __name__ == "__main__":
diff --git a/build_files/cmake/cmake_static_check_clang_array.py b/build_files/cmake/cmake_static_check_clang_array.py
index 45b262a13ce..597d1d2b980 100644
--- a/build_files/cmake/cmake_static_check_clang_array.py
+++ b/build_files/cmake/cmake_static_check_clang_array.py
@@ -32,7 +32,6 @@ USE_QUIET = (os.environ.get("QUIET", None) is not None)
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- "blender/intern/opennl",
]
CHECKER_BIN = "python2"
diff --git a/build_files/cmake/cmake_static_check_cppcheck.py b/build_files/cmake/cmake_static_check_cppcheck.py
index 9f012cb7f6d..3504b005adc 100644
--- a/build_files/cmake/cmake_static_check_cppcheck.py
+++ b/build_files/cmake/cmake_static_check_cppcheck.py
@@ -32,7 +32,6 @@ USE_QUIET = (os.environ.get("QUIET", None) is not None)
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- "blender/intern/opennl",
]
CHECKER_BIN = "cppcheck"
diff --git a/build_files/cmake/cmake_static_check_smatch.py b/build_files/cmake/cmake_static_check_smatch.py
index de13d141276..f525187e22c 100644
--- a/build_files/cmake/cmake_static_check_smatch.py
+++ b/build_files/cmake/cmake_static_check_smatch.py
@@ -25,7 +25,6 @@
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- "blender/intern/opennl",
]
CHECKER_BIN = "smatch"
diff --git a/build_files/cmake/cmake_static_check_sparse.py b/build_files/cmake/cmake_static_check_sparse.py
index 2ee99925adb..6d1c4e3d6a2 100644
--- a/build_files/cmake/cmake_static_check_sparse.py
+++ b/build_files/cmake/cmake_static_check_sparse.py
@@ -25,7 +25,6 @@
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- "blender/intern/opennl",
]
CHECKER_BIN = "sparse"
diff --git a/build_files/cmake/cmake_static_check_splint.py b/build_files/cmake/cmake_static_check_splint.py
index 5a967ecc7a3..46d8808e89d 100644
--- a/build_files/cmake/cmake_static_check_splint.py
+++ b/build_files/cmake/cmake_static_check_splint.py
@@ -25,7 +25,6 @@
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
- "blender/intern/opennl",
]
CHECKER_BIN = "splint"
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 881dc515499..d708f1ccecf 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -10,6 +10,7 @@ set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG ON CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE ON CACHE BOOL "" FORCE)
set(WITH_CYCLES ON CACHE BOOL "" FORCE)
+set(WITH_CYCLES_OSL ON CACHE BOOL "" FORCE)
set(WITH_FFTW3 ON CACHE BOOL "" FORCE)
set(WITH_LIBMV ON CACHE BOOL "" FORCE)
set(WITH_LIBMV_SCHUR_SPECIALIZATIONS ON CACHE BOOL "" FORCE)
@@ -25,7 +26,6 @@ set(WITH_IMAGE_FRAMESERVER ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_HDR ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENEXR ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENJPEG ON CACHE BOOL "" FORCE)
-set(WITH_IMAGE_REDCODE ON CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF ON CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF ON CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL ON CACHE BOOL "" FORCE)
@@ -42,7 +42,8 @@ set(WITH_OPENAL ON CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE)
set(WITH_OPENMP ON CACHE BOOL "" FORCE)
-set(WITH_OPENNL ON CACHE BOOL "" FORCE)
+set(WITH_OPENVDB ON CACHE BOOL "" FORCE)
+set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE)
set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE)
set(WITH_SDL ON CACHE BOOL "" FORCE)
@@ -60,10 +61,16 @@ if(UNIX AND NOT APPLE)
set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
elseif(WIN32)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
- set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE)
+ else()
+ # MinGW exceptions
+ set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
+ set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
+ set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
+ endif()
elseif (APPLE)
set(WITH_JACK ON CACHE BOOL "" FORCE)
set(WITH_CODEC_QUICKTIME ON CACHE BOOL "" FORCE)
set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE)
endif()
-
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 2a57e4c33d8..3c53ee7ae23 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -14,6 +14,7 @@ set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
+set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
set(WITH_LLVM OFF CACHE BOOL "" FORCE)
@@ -29,7 +30,6 @@ set(WITH_IMAGE_FRAMESERVER OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_HDR OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENEXR OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_OPENJPEG OFF CACHE BOOL "" FORCE)
-set(WITH_IMAGE_REDCODE OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_TIFF OFF CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
@@ -47,8 +47,7 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENMP OFF CACHE BOOL "" FORCE)
-set(WITH_OPENNL OFF CACHE BOOL "" FORCE)
-set(WITH_PYTHON_INSTALL OFF CACHE BOOL "" FORCE)
+set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/bpy_module.cmake b/build_files/cmake/config/bpy_module.cmake
index b5b13b40987..41140151f04 100644
--- a/build_files/cmake/config/bpy_module.cmake
+++ b/build_files/cmake/config/bpy_module.cmake
@@ -31,3 +31,4 @@ set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
+set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 90c4fbd5674..85bc4008346 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -103,6 +103,23 @@ macro(file_list_suffix
endmacro()
+if(UNIX AND NOT APPLE)
+ macro(find_package_static)
+ set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ find_package(${ARGV})
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
+ unset(_cmake_find_library_suffixes_back)
+ endmacro()
+
+ macro(find_library_static)
+ set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ find_library(${ARGV})
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
+ unset(_cmake_find_library_suffixes_back)
+ endmacro()
+endif()
function(target_link_libraries_optimized
TARGET
@@ -124,22 +141,6 @@ function(target_link_libraries_debug
endforeach()
endfunction()
-function(target_link_libraries_decoupled
- target
- libraries_var
- )
-
- if(NOT MSVC)
- target_link_libraries(${target} ${${libraries_var}})
- else()
- # For MSVC we link to different libraries depending whether
- # release or debug target is being built.
- file_list_suffix(_libraries_debug "${${libraries_var}}" "_d")
- target_link_libraries_debug(${target} "${_libraries_debug}")
- target_link_libraries_optimized(${target} "${${libraries_var}}")
- endif()
-endfunction()
-
# Nicer makefiles with -I/1/foo/ instead of -I/1/2/3/../../foo/
# use it instead of include_directories()
function(blender_include_dirs
@@ -239,6 +240,9 @@ endfunction()
function(SETUP_LIBDIRS)
+ # NOTE: For all new libraries, use absolute library paths.
+ # This should eventually be phased out.
+
link_directories(${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${FREETYPE_LIBPATH})
if(WITH_PYTHON) # AND NOT WITH_PYTHON_MODULE # WIN32 needs
@@ -265,11 +269,8 @@ function(SETUP_LIBDIRS)
if(WITH_OPENCOLORIO)
link_directories(${OPENCOLORIO_LIBPATH})
endif()
- if(WITH_IMAGE_OPENJPEG AND WITH_SYSTEM_OPENJPEG)
- link_directories(${OPENJPEG_LIBPATH})
- endif()
- if(WITH_CODEC_QUICKTIME)
- link_directories(${QUICKTIME_LIBPATH})
+ if(WITH_OPENVDB)
+ link_directories(${OPENVDB_LIBPATH})
endif()
if(WITH_OPENAL)
link_directories(${OPENAL_LIBPATH})
@@ -285,15 +286,13 @@ function(SETUP_LIBDIRS)
endif()
if(WITH_OPENCOLLADA)
link_directories(${OPENCOLLADA_LIBPATH})
- link_directories(${PCRE_LIBPATH})
- link_directories(${EXPAT_LIBPATH})
+ ## Never set
+ # link_directories(${PCRE_LIBPATH})
+ # link_directories(${EXPAT_LIBPATH})
endif()
if(WITH_LLVM)
link_directories(${LLVM_LIBPATH})
endif()
- if(WITH_MEM_JEMALLOC)
- link_directories(${JEMALLOC_LIBPATH})
- endif()
if(WIN32 AND NOT UNIX)
link_directories(${PTHREADS_LIBPATH})
@@ -383,6 +382,9 @@ function(setup_liblinks
target_link_libraries(${target} ${OPENSUBDIV_LIBRARIES})
endif()
endif()
+ if(WITH_OPENVDB)
+ target_link_libraries(${target} ${OPENVDB_LIBRARIES} ${TBB_LIBRARIES})
+ endif()
if(WITH_CYCLES_OSL)
target_link_libraries(${target} ${OSL_LIBRARIES})
endif()
@@ -394,14 +396,7 @@ function(setup_liblinks
endif()
target_link_libraries(${target} ${JPEG_LIBRARIES})
if(WITH_IMAGE_OPENEXR)
- if(WIN32 AND NOT UNIX AND NOT CMAKE_COMPILER_IS_GNUCC)
- file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
- target_link_libraries_debug(${target} "${OPENEXR_LIBRARIES_DEBUG}")
- target_link_libraries_optimized(${target} "${OPENEXR_LIBRARIES}")
- unset(OPENEXR_LIBRARIES_DEBUG)
- else()
- target_link_libraries(${target} ${OPENEXR_LIBRARIES})
- endif()
+ target_link_libraries(${target} ${OPENEXR_LIBRARIES})
endif()
if(WITH_IMAGE_OPENJPEG AND WITH_SYSTEM_OPENJPEG)
target_link_libraries(${target} ${OPENJPEG_LIBRARIES})
@@ -452,11 +447,20 @@ function(setup_liblinks
if(WIN32 AND NOT UNIX)
target_link_libraries(${target} ${PTHREADS_LIBRARIES})
endif()
+ if(UNIX AND NOT APPLE)
+ if(WITH_OPENMP_STATIC)
+ target_link_libraries(${target} ${OpenMP_LIBRARIES})
+ endif()
+ endif()
# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them..
if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
target_link_libraries(${target} "extern_clew")
- target_link_libraries(${target} "extern_cuew")
+ if(WITH_CUDA_DYNLOAD)
+ target_link_libraries(${target} "extern_cuew")
+ else()
+ target_link_libraries(${target} ${CUDA_CUDA_LIBRARY})
+ endif()
endif()
#system libraries with no dependencies such as platform link libs or opengl should go last
@@ -574,7 +578,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
ge_phys_bullet
bf_intern_smoke
extern_lzma
- extern_colamd
+ extern_curve_fit_nd
ge_logic_ketsji
extern_recastnavigation
ge_logic
@@ -587,7 +591,6 @@ function(SETUP_BLENDER_SORTED_LIBS)
ge_logic_loopbacknetwork
bf_intern_moto
extern_openjpeg
- extern_redcode
ge_videotex
bf_dna
bf_blenfont
@@ -602,14 +605,14 @@ function(SETUP_BLENDER_SORTED_LIBS)
cycles_kernel
cycles_util
cycles_subd
- bf_intern_raskter
bf_intern_opencolorio
+ bf_intern_eigen
extern_rangetree
extern_wcwidth
- extern_libmv
+ bf_intern_libmv
extern_glog
+ extern_gflags
extern_sdlew
- extern_eigen3
bf_intern_glew_mx
)
@@ -676,10 +679,6 @@ function(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
endif()
- if(WITH_OPENNL)
- list_insert_after(BLENDER_SORTED_LIBS "bf_render" "bf_intern_opennl")
- endif()
-
if(WITH_BULLET)
list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody")
endif()
@@ -692,6 +691,10 @@ function(SETUP_BLENDER_SORTED_LIBS)
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
+ if(WITH_OPENVDB)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb)
+ endif()
+
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
@@ -778,15 +781,11 @@ macro(TEST_SSE_SUPPORT
unset(CMAKE_REQUIRED_FLAGS)
endmacro()
-macro(TEST_STDBOOL_SUPPORT)
- include(CheckCSourceRuns)
-
- # This program will compile correctly if and only if
- # this C compiler supports C99 stdbool.
- check_c_source_runs("
- #include <stdbool.h>
- int main(void) { return (int)false; }"
- HAVE_STDBOOL_H)
+# Only print message if running CMake first time
+macro(message_first_run)
+ if(FIRST_RUN)
+ message(${ARGV})
+ endif()
endmacro()
macro(TEST_UNORDERED_MAP_SUPPORT)
@@ -795,11 +794,11 @@ macro(TEST_UNORDERED_MAP_SUPPORT)
# and define the include path
# This module defines
# HAVE_UNORDERED_MAP, whether unordered_map implementation was found
- #
+ #
# HAVE_STD_UNORDERED_MAP_HEADER, <unordered_map.h> was found
# HAVE_UNORDERED_MAP_IN_STD_NAMESPACE, unordered_map is in namespace std
# HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE, unordered_map is in namespace std::tr1
- #
+ #
# UNORDERED_MAP_INCLUDE_PREFIX, include path prefix for unordered_map, if found
# UNORDERED_MAP_NAMESPACE, namespace for unordered_map, if found
@@ -823,7 +822,7 @@ macro(TEST_UNORDERED_MAP_SUPPORT)
}"
HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
- message(STATUS "Found unordered_map/set in std namespace.")
+ message_first_run(STATUS "Found unordered_map/set in std namespace.")
set(HAVE_UNORDERED_MAP "TRUE")
set(UNORDERED_MAP_INCLUDE_PREFIX "")
@@ -836,26 +835,26 @@ macro(TEST_UNORDERED_MAP_SUPPORT)
}"
HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
- message(STATUS "Found unordered_map/set in std::tr1 namespace.")
+ message_first_run(STATUS "Found unordered_map/set in std::tr1 namespace.")
set(HAVE_UNORDERED_MAP "TRUE")
set(UNORDERED_MAP_INCLUDE_PREFIX "")
set(UNORDERED_MAP_NAMESPACE "std::tr1")
else()
- message(STATUS "Found <unordered_map> but cannot find either std::unordered_map "
- "or std::tr1::unordered_map.")
+ message_first_run(STATUS "Found <unordered_map> but cannot find either std::unordered_map "
+ "or std::tr1::unordered_map.")
endif()
endif()
else()
CHECK_INCLUDE_FILE_CXX("tr1/unordered_map" HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
- message(STATUS "Found unordered_map/set in std::tr1 namespace.")
+ message_first_run(STATUS "Found unordered_map/set in std::tr1 namespace.")
set(HAVE_UNORDERED_MAP "TRUE")
set(UNORDERED_MAP_INCLUDE_PREFIX "tr1")
set(UNORDERED_MAP_NAMESPACE "std::tr1")
else()
- message(STATUS "Unable to find <unordered_map> or <tr1/unordered_map>. ")
+ message_first_run(STATUS "Unable to find <unordered_map> or <tr1/unordered_map>. ")
endif()
endif()
endmacro()
@@ -892,7 +891,7 @@ macro(TEST_SHARED_PTR_SUPPORT)
HAVE_SHARED_PTR_IN_STD_NAMESPACE)
if(HAVE_SHARED_PTR_IN_STD_NAMESPACE)
- message("-- Found shared_ptr in std namespace using <memory> header.")
+ message_first_run("-- Found shared_ptr in std namespace using <memory> header.")
set(SHARED_PTR_FOUND TRUE)
else()
CHECK_CXX_SOURCE_COMPILES("#include <memory>
@@ -902,7 +901,7 @@ macro(TEST_SHARED_PTR_SUPPORT)
}"
HAVE_SHARED_PTR_IN_TR1_NAMESPACE)
if(HAVE_SHARED_PTR_IN_TR1_NAMESPACE)
- message("-- Found shared_ptr in std::tr1 namespace using <memory> header.")
+ message_first_run("-- Found shared_ptr in std::tr1 namespace using <memory> header.")
set(SHARED_PTR_TR1_NAMESPACE TRUE)
set(SHARED_PTR_FOUND TRUE)
endif()
@@ -923,7 +922,7 @@ macro(TEST_SHARED_PTR_SUPPORT)
}"
HAVE_SHARED_PTR_IN_TR1_NAMESPACE_FROM_TR1_MEMORY_HEADER)
if(HAVE_SHARED_PTR_IN_TR1_NAMESPACE_FROM_TR1_MEMORY_HEADER)
- message("-- Found shared_ptr in std::tr1 namespace using <tr1/memory> header.")
+ message_first_run("-- Found shared_ptr in std::tr1 namespace using <tr1/memory> header.")
set(SHARED_PTR_TR1_MEMORY_HEADER TRUE)
set(SHARED_PTR_TR1_NAMESPACE TRUE)
set(SHARED_PTR_FOUND TRUE)
@@ -1192,7 +1191,7 @@ macro(blender_project_hack_post)
# MINGW workaround for -ladvapi32 being included which surprisingly causes
# string formatting of floats, eg: printf("%.*f", 3, value). to crash blender
# with a meaningless stack trace. by overriding this flag we ensure we only
- # have libs we define and that cmake & scons builds match.
+ # have libs we define.
set(CMAKE_C_STANDARD_LIBRARIES "" CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD_LIBRARIES "" CACHE STRING "" FORCE)
mark_as_advanced(
@@ -1450,17 +1449,21 @@ function(find_python_package
)
if(NOT EXISTS "${PYTHON_${_upper_package}_PATH}")
- message(WARNING "'${package}' path could not be found in:\n"
- "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${package}', "
- "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${package}', "
- "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${package}', "
- "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${package}', "
- "WITH_PYTHON_INSTALL_${_upper_package} option will be ignored when installing python")
+ message(WARNING
+ "Python package '${package}' path could not be found in:\n"
+ "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${package}', "
+ "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${package}', "
+ "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${package}', "
+ "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${package}', "
+ "\n"
+ "The 'WITH_PYTHON_INSTALL_${_upper_package}' option will be ignored when installing Python.\n"
+ "The build will be usable, only add-ons that depend on this package won't be functional."
+ )
set(WITH_PYTHON_INSTALL_${_upper_package} OFF PARENT_SCOPE)
else()
message(STATUS "${package} found at '${PYTHON_${_upper_package}_PATH}'")
endif()
- endif()
+ endif()
endfunction()
# like Python's 'print(dir())'
diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake
index f1939cfd474..afdbc644b4e 100644
--- a/build_files/cmake/packaging.cmake
+++ b/build_files/cmake/packaging.cmake
@@ -23,7 +23,7 @@ set(MY_WC_HASH "unknown")
if(EXISTS ${CMAKE_SOURCE_DIR}/.git/)
find_package(Git)
if(GIT_FOUND)
- message(STATUS "-- Found Git: ${GIT_EXECUTABLE}")
+ message(STATUS "Found Git: ${GIT_EXECUTABLE}")
execute_process(COMMAND git rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE MY_WC_HASH
@@ -37,7 +37,8 @@ unset(MY_WC_HASH)
# Force Package Name
execute_process(COMMAND date "+%Y%m%d" OUTPUT_VARIABLE CPACK_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
-set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-git${CPACK_DATE}.${BUILD_REV}-${CMAKE_SYSTEM_PROCESSOR})
+string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER)
+set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME_LOWER}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-git${CPACK_DATE}.${BUILD_REV}-${CMAKE_SYSTEM_PROCESSOR})
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
# RPM packages
@@ -66,13 +67,14 @@ if(WIN32)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Blender Foundation/Blender")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "Blender Foundation/Blender")
- set(CPACK_NSIS_MUI_ICON ${CMAKE_SOURCE_DIR}/source/icons/winblender.ico)
+ set(CPACK_NSIS_MUI_ICON ${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.ico)
set(CPACK_NSIS_COMPRESSOR "/SOLID lzma")
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/release/text/GPL-license.txt)
- set(CPACK_WIX_PRODUCT_ICON ${CMAKE_SOURCE_DIR}/source/icons/winblender.ico)
+ set(CPACK_WIX_PRODUCT_ICON ${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.ico)
set(CPACK_WIX_UPGRADE_GUID "B767E4FD-7DE7-4094-B051-3AE62E13A17A")
+ set(CPACK_WIX_TEMPLATE ${LIBDIR}/package/installer_wix/WIX.template)
set(CPACK_WIX_UI_BANNER ${LIBDIR}/package/installer_wix/WIX_UI_BANNER.bmp)
set(CPACK_WIX_UI_DIALOG ${LIBDIR}/package/installer_wix/WIX_UI_DIALOG.bmp)
diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py
index c9ea2497987..cfcd9df65c8 100755
--- a/build_files/cmake/project_info.py
+++ b/build_files/cmake/project_info.py
@@ -23,11 +23,9 @@
# <pep8 compliant>
"""
-Example Win32 usage:
- c:\Python32\python.exe c:\blender_dev\blender\build_files\cmake\cmake_qtcreator_project.py c:\blender_dev\cmake_build
+Module for accessing project file data for Blender.
-Example Linux usage:
- python ~/blenderSVN/blender/build_files/cmake/cmake_qtcreator_project.py ~/blenderSVN/cmake
+Before use, call init(cmake_build_dir).
"""
__all__ = (
@@ -42,6 +40,7 @@ __all__ = (
"cmake_advanced_info",
"cmake_compiler_defines",
"project_name_get"
+ "init",
)
@@ -61,19 +60,26 @@ SOURCE_DIR = abspath(SOURCE_DIR)
SIMPLE_PROJECTFILE = False
-# get cmake path
-CMAKE_DIR = sys.argv[-1]
+# must initialize from 'init'
+CMAKE_DIR = None
-if not exists(join(CMAKE_DIR, "CMakeCache.txt")):
- CMAKE_DIR = os.getcwd()
-if not exists(join(CMAKE_DIR, "CMakeCache.txt")):
- print("CMakeCache.txt not found in %r or %r\n Pass CMake build dir as an argument, or run from that dir, aborting" % (CMAKE_DIR, os.getcwd()))
- sys.exit(1)
+def init(cmake_path):
+ global CMAKE_DIR, PROJECT_DIR
+
+ # get cmake path
+ cmake_path = cmake_path or ""
+
+ if (not cmake_path) or (not exists(join(cmake_path, "CMakeCache.txt"))):
+ cmake_path = os.getcwd()
+ if not exists(join(cmake_path, "CMakeCache.txt")):
+ print("CMakeCache.txt not found in %r or %r\n"
+ " Pass CMake build dir as an argument, or run from that dir, aborting" %
+ (cmake_path, os.getcwd()))
+ return False
-# could be either.
-# PROJECT_DIR = SOURCE_DIR
-PROJECT_DIR = CMAKE_DIR
+ PROJECT_DIR = CMAKE_DIR = cmake_path
+ return True
def source_list(path, filename_check=None):
diff --git a/build_files/scons/Modules/FindPython.py b/build_files/scons/Modules/FindPython.py
deleted file mode 100644
index a0ead88ebb4..00000000000
--- a/build_files/scons/Modules/FindPython.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import os
-import platform
-
-def FindPython():
- all_abi_flags = ['m', 'mu', '']
-
- python = "/usr"
- abi_flags = "m" # Most common for linux distros
- version = "3.4"
-
- _arch = platform.uname()[4] + "-linux-gnu"
-
- # Determine ABI flags used on this system
- include = os.path.join(python, "include")
- for cur_flags in all_abi_flags:
- inc = os.path.join(include, "python" + version + cur_flags, "Python.h")
- if os.path.exists(inc):
- abi_flags = cur_flags
- break
-
- # Find config.h. In some distros, such as ubuntu 12.10 they are not in standard include dir.
- incconf = os.path.join(include, _arch, "python" + version + cur_flags)
- if not os.path.exists(os.path.join(incconf, "pyconfig.h")):
- incconf = ''
-
- # Determine whether python is in /usr/lib or /usr/lib64
- lib32 = os.path.join(python, "lib", "python" + version, "sysconfig.py")
- lib64 = os.path.join(python, "lib64", "python" + version, "sysconfig.py")
- if os.path.exists(lib32):
- libpath = "${BF_PYTHON}/lib"
- elif os.path.exists(lib64):
- libpath = "${BF_PYTHON}/lib64"
- else:
- # roll back to default value
- libpath = "${BF_PYTHON}/lib"
-
- libpath_arch = libpath
- _libpath_arch = os.path.join(python, "lib", _arch) # No lib64 stuff with recent deb-like distro afaik...
- _libs = ["libpython" + version + abi_flags + ext for ext in (".so", ".a")]
- for l in _libs:
- if not os.path.exists(os.path.join(libpath, l)) and os.path.exists(os.path.join(_libpath_arch, l)):
- libpath_arch = os.path.join(libpath, _arch)
- break
-
- return {"PYTHON": python,
- "VERSION": version,
- "LIBPATH": libpath,
- "LIBPATH_ARCH": libpath_arch,
- "ABI_FLAGS": abi_flags,
- "CONFIG": incconf}
diff --git a/build_files/scons/Modules/FindSharedPtr.py b/build_files/scons/Modules/FindSharedPtr.py
deleted file mode 100644
index ba53f55d563..00000000000
--- a/build_files/scons/Modules/FindSharedPtr.py
+++ /dev/null
@@ -1,42 +0,0 @@
-def FindSharedPtr(conf):
- """
- Detect shared_ptr availability
- """
-
- found = False
- namespace = None
- header = None
-
- if conf.CheckCXXHeader("memory"):
- # Finding the memory header doesn't mean that shared_ptr is in std
- # namespace.
- #
- # In particular, MSVC 2008 has shared_ptr declared in std::tr1. In
- # order to support this, we do an extra check to see which namespace
- # should be used.
-
- if conf.CheckType('std::shared_ptr<int>', language = 'C++', includes="#include <memory>"):
- print("-- Found shared_ptr in std namespace using <memory> header.")
- namespace = 'std'
- header = 'memory'
- elif conf.CheckType('std::tr1::shared_ptr<int>', language = 'C++', includes="#include <memory>"):
- print("-- Found shared_ptr in std::tr1 namespace using <memory> header..")
- namespace = 'std::tr1'
- header = 'memory'
-
- if not namespace and conf.CheckCXXHeader("tr1/memory"):
- # Further, gcc defines shared_ptr in std::tr1 namespace and
- # <tr1/memory> is to be included for this. And what makes things
- # even more tricky is that gcc does have <memory> header, so
- # all the checks above wouldn't find shared_ptr.
- if conf.CheckType('std::tr1::shared_ptr<int>', language = 'C++', includes="#include <tr1/memory>"):
- print("-- Found shared_ptr in std::tr1 namespace using <tr1/memory> header..")
- namespace = 'std::tr1'
- header = 'tr1/memory'
-
- if not namespace:
- print("-- Unable to find shared_ptrred_map>.")
-
- conf.env['WITH_SHARED_PTR_SUPPORT'] = namespace and header
- conf.env['SHARED_PTR_NAMESPACE'] = namespace
- conf.env['SHARED_PTR_HEADER'] = header
diff --git a/build_files/scons/Modules/FindUnorderedMap.py b/build_files/scons/Modules/FindUnorderedMap.py
deleted file mode 100644
index 34073c1b0b9..00000000000
--- a/build_files/scons/Modules/FindUnorderedMap.py
+++ /dev/null
@@ -1,38 +0,0 @@
-def FindUnorderedMap(conf):
- """
- Detect unordered_map availability
- """
-
- namespace = None
- header = None
-
- if conf.CheckCXXHeader("unordered_map"):
- # Even so we've found unordered_map header file it doesn't
- # mean unordered_map and unordered_set will be declared in
- # std namespace.
- #
- # Namely, MSVC 2008 have unordered_map header which declares
- # unordered_map class in std::tr1 namespace. In order to support
- # this, we do extra check to see which exactly namespace is
- # to be used.
-
- if conf.CheckType('std::unordered_map<int, int>', language = 'CXX', includes="#include <unordered_map>"):
- print("-- Found unordered_map/set in std namespace.")
- namespace = 'std'
- header = 'unordered_map'
- elif conf.CheckType('std::tr1::unordered_map<int, int>', language = 'CXX', includes="#include <unordered_map>"):
- print("-- Found unordered_map/set in std::tr1 namespace.")
- namespace = 'std::tr1'
- header = 'unordered_map'
- else:
- print("-- Found <unordered_map> but can not find neither std::unordered_map nor std::tr1::unordered_map.")
- elif conf.CheckCXXHeader("tr1/unordered_map"):
- print("-- Found unordered_map/set in std::tr1 namespace.")
- namespace = 'std::tr1'
- header = 'tr1/unordered_map'
- else:
- print("-- Unable to find <unordered_map> or <tr1/unordered_map>. ")
-
- conf.env['WITH_UNORDERED_MAP_SUPPORT'] = namespace and header
- conf.env['UNORDERED_MAP_NAMESPACE'] = namespace
- conf.env['UNORDERED_MAP_HEADER'] = header
diff --git a/build_files/scons/Modules/__init__.py b/build_files/scons/Modules/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/build_files/scons/Modules/__init__.py
+++ /dev/null
diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py
deleted file mode 100644
index 0bf03a46bd2..00000000000
--- a/build_files/scons/config/darwin-config.py
+++ /dev/null
@@ -1,271 +0,0 @@
-import commands
-
-#############################################################################
-################### Compiler & architecture settings ##################
-#############################################################################
-
-MACOSX_ARCHITECTURE = 'x86_64' # valid archs: ppc, i386, ppc64, x86_64
-MACOSX_SDK='' # set an sdk name like '10.7' or leave empty for automatic choosing highest available
-MACOSX_DEPLOYMENT_TARGET = '10.6'
-
-# gcc always defaults to the system standard compiler linked by a shim or symlink
-CC = 'gcc'
-CXX = 'g++'
-LCGDIR = '#../lib/darwin-9.x.universal'
-LIBDIR = '${LCGDIR}'
-
-#############################################################################
-################### Dependency settings ##################
-#############################################################################
-
-# enable ffmpeg support
-WITH_BF_FFMPEG = True
-BF_FFMPEG = LIBDIR + '/ffmpeg'
-BF_FFMPEG_INC = "${BF_FFMPEG}/include"
-BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB = 'avcodec avdevice avformat avutil mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg bz2'
-#bz2 is a standard osx dynlib
-
-BF_PYTHON_VERSION = '3.4'
-WITH_OSX_STATICPYTHON = True
-
-# python 3.4 uses precompiled libraries in bf svn /lib by default
-BF_PYTHON = LIBDIR + '/python'
-BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}m'
-# BF_PYTHON_BINARY = '${BF_PYTHON}/bin/python${BF_PYTHON_VERSION}'
-BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION}m'
-BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib/python${BF_PYTHON_VERSION}'
-# BF_PYTHON_LINKFLAGS = ['-u', '_PyMac_Error', '-framework', 'System']
-
-WITH_BF_OPENAL = True
-BF_OPENAL = LIBDIR + '/openal'
-
-WITH_BF_STATICOPENAL = False
-BF_OPENAL_INC = '${BF_OPENAL}/include' # only headers from libdir needed for proper use of framework !!!!
-#BF_OPENAL_LIB = 'openal'
-#BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
-# Warning, this static lib configuration is untested! users of this OS please confirm.
-#BF_OPENAL_LIB_STATIC = '${BF_OPENAL}/lib/libopenal.a'
-
-# Warning, this static lib configuration is untested! users of this OS please confirm.
-BF_CXX = '/usr'
-WITH_BF_STATICCXX = False
-BF_CXX_LIB_STATIC = '${BF_CXX}/lib/libstdc++.a'
-
-WITH_BF_AUDASPACE = True
-
-# we use simply jack framework
-WITH_BF_JACK = True
-BF_JACK = '/Library/Frameworks/Jackmp.framework'
-BF_JACK_INC = '${BF_JACK}/headers'
-#BF_JACK_LIB = 'jack' # not used due framework
-BF_JACK_LIBPATH = '${BF_JACK}'
-
-WITH_BF_SNDFILE = True
-BF_SNDFILE = LIBDIR + '/sndfile'
-BF_SNDFILE_INC = '${BF_SNDFILE}/include'
-BF_SNDFILE_LIB = 'sndfile FLAC ogg vorbis vorbisenc'
-BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib ${BF_FFMPEG}/lib' #ogg libs are stored in ffmpeg dir
-
-WITH_BF_SDL = True
-BF_SDL = LIBDIR + '/sdl' #$(shell sdl-config --prefix)
-BF_SDL_INC = '${BF_SDL}/include' #$(shell $(BF_SDL)/bin/sdl-config --cflags)
-BF_SDL_LIB = 'SDL2' #BF_SDL #$(shell $(BF_SDL)/bin/sdl-config --libs) -lSDL_mixer
-BF_SDL_LIBPATH = '${BF_SDL}/lib'
-
-WITH_BF_OPENEXR = True
-WITH_BF_STATICOPENEXR = False
-BF_OPENEXR = '${LCGDIR}/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR'
-BF_OPENEXR_LIB = ' Iex Half IlmImf Imath IlmThread'
-BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
-# Warning, this static lib configuration is untested! users of this OS please confirm.
-BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
-
-WITH_BF_DDS = True
-
-WITH_BF_JPEG = True
-BF_JPEG = LIBDIR + '/jpeg'
-BF_JPEG_INC = '${BF_JPEG}/include'
-BF_JPEG_LIB = 'jpeg'
-BF_JPEG_LIBPATH = '${BF_JPEG}/lib'
-
-WITH_BF_OPENJPEG = True
-BF_OPENJPEG = '#extern/libopenjpeg'
-BF_OPENJPEG_LIB = ''
-BF_OPENJPEG_INC = '${BF_OPENJPEG}'
-BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
-
-WITH_BF_PNG = True
-BF_PNG = LIBDIR + '/png'
-BF_PNG_INC = '${BF_PNG}/include'
-BF_PNG_LIB = 'png'
-BF_PNG_LIBPATH = '${BF_PNG}/lib'
-
-WITH_BF_TIFF = True
-BF_TIFF = LIBDIR + '/tiff'
-BF_TIFF_INC = '${BF_TIFF}/include'
-BF_TIFF_LIB = 'tiff'
-BF_TIFF_LIBPATH = '${BF_TIFF}/lib'
-
-WITH_BF_ZLIB = True
-BF_ZLIB = '/usr'
-#BF_ZLIB_INC = '${BF_ZLIB}/include' # don't use this, it breaks -isysroot ${MACOSX_SDK}
-BF_ZLIB_LIB = 'z'
-
-WITH_BF_INTERNATIONAL = True
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_PLAYER = True
-WITH_BF_OCEANSIM = True
-
-WITH_BF_BULLET = True
-BF_BULLET = '#extern/bullet2/src'
-BF_BULLET_INC = '${BF_BULLET}'
-BF_BULLET_LIB = 'extern_bullet'
-
-WITH_BF_FFTW3 = True
-BF_FFTW3 = LIBDIR + '/fftw3'
-BF_FFTW3_INC = '${BF_FFTW3}/include'
-BF_FFTW3_LIB = 'libfftw3'
-BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
-
-BF_FREETYPE = LIBDIR + '/freetype'
-BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2'
-BF_FREETYPE_LIB = 'freetype'
-BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib'
-
-WITH_BF_QUICKTIME = True
-
-WITH_BF_ICONV = True
-BF_ICONV = '/usr'
-BF_ICONV_INC = '${BF_ICONV}/include'
-BF_ICONV_LIB = 'iconv'
-#BF_ICONV_LIBPATH = '${BF_ICONV}/lib'
-
-# Mesa Libs should go here if your using them as well....
-WITH_BF_STATICOPENGL = True
-BF_OPENGL_LIB = 'GL GLU'
-BF_OPENGL_LIBPATH = '/System/Library/Frameworks/OpenGL.framework/Libraries'
-BF_OPENGL_LINKFLAGS = ['-framework', 'OpenGL']
-
-#OpenCollada flags
-WITH_BF_COLLADA = True
-BF_COLLADA = '#source/blender/collada'
-BF_COLLADA_INC = '${BF_COLLADA}'
-BF_COLLADA_LIB = 'bf_collada'
-BF_OPENCOLLADA = LIBDIR + '/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
-BF_OPENCOLLADA_LIB = 'OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils OpenCOLLADAStreamWriter MathMLSolver GeneratedSaxParser xml2 buffer ftoa'
-BF_OPENCOLLADA_LIBPATH = LIBDIR + '/opencollada'
-BF_PCRE = LIBDIR + '/opencollada'
-BF_PCRE_LIB = 'pcre'
-BF_PCRE_LIBPATH = '${BF_PCRE}/lib'
-#BF_EXPAT = '/usr'
-#BF_EXPAT_LIB = 'expat'
-#BF_EXPAT_LIBPATH = '/usr/lib'
-
-# Cycles
-WITH_BF_CYCLES = True
-
-#OSL
-
-WITH_BF_CYCLES_OSL = True
-BF_OSL = LIBDIR + '/osl'
-BF_OSL_INC = '${BF_OSL}/include'
-# note oslexec would passed via program linkflags, which is needed to
-# make llvm happy with osl_allocate_closure_component
-#BF_OSL_LIB = 'oslcomp oslquery'
-BF_OSL_LIBPATH = '${BF_OSL}/lib'
-BF_OSL_COMPILER = '${BF_OSL}/bin/oslc'
-
-WITH_BF_LLVM = True
-BF_LLVM = LIBDIR + '/llvm'
-BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMX86Info LLVMX86AsmPrinter ' + \
- 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \
- 'LLVMTarget LLVMMC LLVMCore LLVMSupport LLVMObject'
-BF_LLVM_LIBPATH = '${BF_LLVM}/lib'
-
-WITH_BF_OIIO = True
-BF_OIIO = LIBDIR + '/openimageio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIB = 'OpenImageIO'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-
-WITH_BF_OCIO = True
-BF_OCIO = LIBDIR + '/opencolorio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB = 'OpenColorIO tinyxml yaml-cpp'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-BF_BOOST = LIBDIR + '/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB = 'boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt boost_wave-mt'
-BF_BOOST_LIB_INTERNATIONAL = 'boost_locale-mt'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-WITH_BF_CYCLES_CUDA_BINARIES = False
-BF_CYCLES_CUDA_NVCC = '/usr/local/cuda/bin/nvcc'
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
-
-#Freestyle
-WITH_BF_FREESTYLE = True
-
-#OpenMP ( will be checked for compiler support and turned off eventually )
-WITH_BF_OPENMP = True
-
-WITH_BF_OPENSUBDIV = False
-BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-
-#Ray trace optimization
-WITH_BF_RAYOPTIMIZATION = True
-BF_RAYOPTIMIZATION_SSE_FLAGS = []
-
-# SpaceNavigator and related 3D mice, driver must be 3DxWare 10 Beta 4 (Mac OS X) or later !
-WITH_BF_3DMOUSE = True
-
-#############################################################################
-################### various compile settings and flags ##################
-#############################################################################
-
-BF_QUIET = '1' # suppress verbose output
-
-CFLAGS = []
-CXXFLAGS = []
-CCFLAGS = ['-pipe','-funsigned-char']
-CPPFLAGS = []
-
-PLATFORM_LINKFLAGS = ['-fexceptions','-framework','CoreServices','-framework','Foundation','-framework','IOKit','-framework','AppKit','-framework','Cocoa','-framework','Carbon','-framework','AudioUnit','-framework','AudioToolbox','-framework','CoreAudio','-framework','OpenAL']
-
-LLIBS = ['stdc++']
-
-REL_CFLAGS = []
-REL_CXXFLAGS = []
-REL_CCFLAGS = ['-O2']
-
-CC_WARN = ['-Wall']
-C_WARN = ['-Wno-char-subscripts', '-Wpointer-arith', '-Wcast-align', '-Wdeclaration-after-statement', '-Wno-unknown-pragmas', '-Wstrict-prototypes']
-CXX_WARN = ['-Wno-invalid-offsetof', '-Wno-sign-compare']
-
-##FIX_STUBS_WARNINGS = -Wno-unused
-
-##LOPTS = --dynamic
-##DYNLDFLAGS = -shared $(LDFLAGS)
-
-BF_PROFILE_CCFLAGS = ['-pg', '-g ']
-BF_PROFILE_LINKFLAGS = ['-pg']
-BF_PROFILE = False
-
-BF_DEBUG = False
-BF_DEBUG_CCFLAGS = ['-g']
-
-#############################################################################
-################### Output directories ##################
-#############################################################################
-
-BF_BUILDDIR='../build/darwin'
-BF_INSTALLDIR='../install/darwin'
diff --git a/build_files/scons/config/linux-config.py b/build_files/scons/config/linux-config.py
deleted file mode 100644
index ff8ecf0aa72..00000000000
--- a/build_files/scons/config/linux-config.py
+++ /dev/null
@@ -1,278 +0,0 @@
-from FindPython import FindPython
-
-py = FindPython()
-
-BF_PYTHON_ABI_FLAGS = py['ABI_FLAGS']
-BF_PYTHON = py['PYTHON']
-BF_PYTHON_LIBPATH = py['LIBPATH']
-BF_PYTHON_LIBPATH_ARCH = py['LIBPATH_ARCH']
-BF_PYTHON_CONFIG = py['CONFIG']
-BF_PYTHON_VERSION = py['VERSION']
-WITH_BF_STATICPYTHON = False
-BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}${BF_PYTHON_ABI_FLAGS} ' + BF_PYTHON_CONFIG
-BF_PYTHON_BINARY = '${BF_PYTHON}/bin/python${BF_PYTHON_VERSION}'
-BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION}${BF_PYTHON_ABI_FLAGS}' # BF_PYTHON+'/lib/python'+BF_PYTHON_VERSION+'/config/libpython'+BF_PYTHON_VERSION+'.a'
-BF_PYTHON_LINKFLAGS = ['-Xlinker', '-export-dynamic']
-BF_PYTHON_LIB_STATIC = '${BF_PYTHON_LIBPATH_ARCH}/libpython${BF_PYTHON_VERSION}${BF_PYTHON_ABI_FLAGS}.a'
-
-WITH_BF_OPENAL = True
-WITH_BF_STATICOPENAL = False
-BF_OPENAL = '/usr'
-BF_OPENAL_INC = '${BF_OPENAL}/include'
-BF_OPENAL_LIB = 'openal'
-BF_OPENAL_LIB_STATIC = '${BF_OPENAL}/lib/libopenal.a'
-
-BF_CXX = '/usr'
-WITH_BF_STATICCXX = False
-BF_CXX_LIB_STATIC = '${BF_CXX}/lib/libstdc++.a'
-
-WITH_BF_AUDASPACE = True
-
-WITH_BF_JACK = False
-BF_JACK = '/usr'
-BF_JACK_INC = '${BF_JACK}/include/jack'
-BF_JACK_LIB = 'jack'
-BF_JACK_LIBPATH = '${BF_JACK}/lib'
-
-WITH_BF_SNDFILE = False
-WITH_BF_STATICSNDFILE = False
-BF_SNDFILE = '/usr'
-BF_SNDFILE_INC = '${BF_SNDFILE}/include/sndfile'
-BF_SNDFILE_LIB = 'sndfile'
-BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib'
-BF_SNDFILE_LIB_STATIC = '${BF_SNDFILE}/lib/libsndfile.a ${BF_OGG}/lib/libvorbis.a ${BF_OGG}/lib/libFLAC.a ${BF_OGG}/lib/libvorbisenc.a ${BF_OGG}/lib/libogg.a'
-
-WITH_BF_SDL = True
-BF_SDL = '/usr' #$(shell sdl-config --prefix)
-BF_SDL_INC = '${BF_SDL}/include/SDL' #$(shell $(BF_SDL)/bin/sdl-config --cflags)
-BF_SDL_LIB = 'SDL' #BF_SDL #$(shell $(BF_SDL)/bin/sdl-config --libs) -lSDL_mixer
-
-WITH_BF_OPENEXR = True
-WITH_BF_STATICOPENEXR = False
-BF_OPENEXR = '/usr'
-# when compiling with your own openexr lib you might need to set...
-# BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
-
-BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR'
-BF_OPENEXR_LIB = 'Half IlmImf Iex Imath '
-BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
-# BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
-
-
-WITH_BF_DDS = True
-
-WITH_BF_JPEG = True
-BF_JPEG = '/usr'
-BF_JPEG_INC = '${BF_JPEG}/include'
-BF_JPEG_LIB = 'jpeg'
-
-WITH_BF_PNG = True
-BF_PNG = '/usr'
-BF_PNG_INC = '${BF_PNG}/include'
-BF_PNG_LIB = 'png'
-
-WITH_BF_TIFF = True
-BF_TIFF = '/usr'
-BF_TIFF_INC = '${BF_TIFF}/include'
-BF_TIFF_LIB = 'tiff'
-
-WITH_BF_ZLIB = True
-BF_ZLIB = '/usr'
-BF_ZLIB_INC = '${BF_ZLIB}/include'
-BF_ZLIB_LIB = 'z'
-
-WITH_BF_INTERNATIONAL = True
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_PLAYER = True
-WITH_BF_OCEANSIM = True
-
-WITH_BF_BULLET = True
-BF_BULLET = '#extern/bullet2/src'
-BF_BULLET_INC = '${BF_BULLET}'
-BF_BULLET_LIB = 'extern_bullet'
-
-WITH_BF_ELTOPO = False
-BF_LAPACK = '/usr'
-BF_LAPACK_LIB = 'lapack3gf blas clapack'
-BF_LAPACK_LIBPATH = '${BF_LAPACK}/lib'
-
-BF_FREETYPE = '/usr'
-BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2'
-BF_FREETYPE_LIB = 'freetype'
-#BF_FREETYPE_LIB_STATIC = '${BF_FREETYPE}/lib/libfreetype.a'
-
-WITH_BF_ICONV = False
-BF_ICONV = "/usr"
-BF_ICONV_INC = '${BF_ICONV}/include'
-BF_ICONV_LIB = 'iconv'
-BF_ICONV_LIBPATH = '${BF_ICONV}/lib'
-
-WITH_BF_BINRELOC = True
-
-# enable ffmpeg support
-WITH_BF_FFMPEG = True
-BF_FFMPEG = '/usr'
-BF_FFMPEG_LIB = 'avformat avcodec swscale avutil avdevice'
-BF_FFMPEG_INC = '${BF_FFMPEG}/include'
-BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
-#WITH_BF_STATICFFMPEG = True
-#BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH/libavcodec.a ${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libavutil.a ${BF_FFMPEG_LIBPATH}/libavdevice.a'
-
-# enable ogg, vorbis and theora in ffmpeg
-WITH_BF_OGG = False
-BF_OGG = '/usr'
-BF_OGG_INC = '${BF_OGG}/include'
-BF_OGG_LIB = 'ogg vorbis vorbisenc theoraenc theoradec'
-
-WITH_BF_OPENJPEG = True
-BF_OPENJPEG = '#extern/libopenjpeg'
-BF_OPENJPEG_LIB = ''
-BF_OPENJPEG_INC = '${BF_OPENJPEG}'
-BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
-
-WITH_BF_FFTW3 = False
-WITH_BF_STATICFFTW3 = False
-BF_FFTW3 = '/usr'
-BF_FFTW3_INC = '${BF_FFTW3}/include'
-BF_FFTW3_LIB = 'fftw3'
-BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
-BF_FFTW3_LIB_STATIC = '${BF_FFTW3_LIBPATH}/libfftw3.a'
-
-WITH_BF_REDCODE = False
-BF_REDCODE = '#extern/libredcode'
-BF_REDCODE_LIB = ''
-# BF_REDCODE_INC = '${BF_REDCODE}/include'
-BF_REDCODE_INC = '${BF_REDCODE}/../' #C files request "libredcode/format.h" which is in "#extern/libredcode/format.h", stupid but compiles for now.
-BF_REDCODE_LIBPATH='${BF_REDCODE}/lib'
-
-# Mesa Libs should go here if you're using them as well....
-WITH_BF_STATICOPENGL = False
-BF_OPENGL = '/usr'
-BF_OPENGL_INC = '${BF_OPENGL}/include'
-BF_OPENGL_LIB = 'GL GLU X11 Xi Xxf86vm'
-BF_OPENGL_LIBPATH = '/usr/X11R6/lib'
-BF_OPENGL_LIB_STATIC = '${BF_OPENGL_LIBPATH}/libGL.a ${BF_OPENGL_LIBPATH}/libGLU.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a ${BF_OPENGL_LIBPATH}/libX11.a ${BF_OPENGL_LIBPATH}/libXi.a ${BF_OPENGL_LIBPATH}/libXext.a ${BF_OPENGL_LIBPATH}/libXxf86vm.a'
-
-WITH_BF_COLLADA = False
-BF_COLLADA = '#source/blender/collada'
-BF_COLLADA_INC = '${BF_COLLADA}'
-BF_COLLADA_LIB = 'bf_collada'
-BF_OPENCOLLADA = '/usr'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
-BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver pcre buffer ftoa'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
-BF_PCRE = ''
-BF_PCRE_LIB = 'pcre'
-BF_PCRE_LIBPATH = '/usr/lib'
-BF_EXPAT = '/usr'
-BF_EXPAT_LIB = 'expat'
-BF_EXPAT_LIBPATH = '/usr/lib'
-
-WITH_BF_JEMALLOC = False
-WITH_BF_STATICJEMALLOC = False
-BF_JEMALLOC = '/usr'
-BF_JEMALLOC_INC = '${BF_JEMALLOC}/include'
-BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
-BF_JEMALLOC_LIB = 'jemalloc'
-BF_JEMALLOC_LIB_STATIC = '${BF_JEMALLOC_LIBPATH}/libjemalloc.a'
-
-WITH_BF_OIIO = False
-WITH_BF_STATICOIIO = False
-BF_OIIO = '/usr'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIB = 'OpenImageIO'
-BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_JPEG}/lib/libjpeg.a'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-
-WITH_BF_OCIO = False
-WITH_BF_STATICOCIO = False
-BF_OCIO = '/usr'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB = 'OpenColorIO yaml-cpp tinyxml'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-WITH_BF_STATICBOOST = False
-BF_BOOST = '/usr'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB = 'boost_filesystem boost_regex boost_system boost_thread boost_date_time'
-BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \
- '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a ' + \
- '${BF_BOOST_LIBPATH}/libboost_thread.a'
-BF_BOOST_LIB_INTERNATIONAL = 'boost_locale'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-WITH_BF_CYCLES = WITH_BF_OIIO and WITH_BF_BOOST
-
-WITH_BF_CYCLES_CUDA_BINARIES = False
-BF_CYCLES_CUDA_NVCC = '/usr/local/cuda/bin/nvcc'
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
-
-WITH_BF_OPENMP = True
-
-#Ray trace optimization
-WITH_BF_RAYOPTIMIZATION = True
-BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
-
-#SpaceNavigator and friends
-WITH_BF_3DMOUSE = True
-WITH_BF_STATIC3DMOUSE = False
-BF_3DMOUSE = '/usr'
-BF_3DMOUSE_INC = '${BF_3DMOUSE}/include'
-BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
-BF_3DMOUSE_LIB = 'spnav'
-BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
-
-#Freestyle
-WITH_BF_FREESTYLE = True
-
-WITH_BF_OPENSUBDIV = False
-WITH_BF_STATICOPENSUBDIV = False
-BF_OPENSUBDIV = '/usr'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIB_STATIC = '${BF_OPENSUBDIV_LIBPATH}/libosdGPU.a ${BF_OPENSUBDIV_LIBPATH}/libosdCPU.a'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-
-##
-CC = 'gcc'
-CXX = 'g++'
-
-CCFLAGS = ['-pipe','-fPIC','-funsigned-char','-fno-strict-aliasing', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64','-D_LARGEFILE64_SOURCE']
-CFLAGS = ['-std=gnu89']
-CXXFLAGS = []
-
-CPPFLAGS = []
-# g++ 4.6, only needed for bullet
-CXXFLAGS += ['-fpermissive']
-if WITH_BF_FFMPEG:
- # libavutil needs UINT64_C()
- CXXFLAGS += ['-D__STDC_CONSTANT_MACROS', ]
-REL_CFLAGS = []
-REL_CXXFLAGS = []
-REL_CCFLAGS = ['-O2']
-
-C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement', '-Wunused-parameter', '-Wstrict-prototypes', '-Werror=declaration-after-statement', '-Werror=implicit-function-declaration', '-Werror=return-type']
-CC_WARN = ['-Wall']
-CXX_WARN = ['-Wno-invalid-offsetof', '-Wno-sign-compare']
-
-LLIBS = ['util', 'c', 'm', 'dl', 'pthread']
-
-BF_PROFILE = False
-BF_PROFILE_CCFLAGS = ['-pg','-g']
-BF_PROFILE_LINKFLAGS = ['-pg']
-
-BF_DEBUG = False
-BF_DEBUG_CCFLAGS = ['-g']
-
-BF_BUILDDIR = '../build/linux'
-BF_INSTALLDIR='../install/linux'
-
-#Link against pthread
-PLATFORM_LINKFLAGS = ['-pthread']
-
-#Fix for LLVM conflict with Mesa llvmpipe, SDL dynload also requires symbols to be hidden.
-# TODO(sergey): Move this to SConstruct, so we can have this line depended on user config.
-PLATFORM_LINKFLAGS += ['-Wl,--version-script=source/creator/blender.map']
diff --git a/build_files/scons/config/win32-mingw-config.py b/build_files/scons/config/win32-mingw-config.py
deleted file mode 100644
index 552a1a5cec3..00000000000
--- a/build_files/scons/config/win32-mingw-config.py
+++ /dev/null
@@ -1,229 +0,0 @@
-LCGDIR = '#../lib/mingw32'
-LIBDIR = "${LCGDIR}"
-
-BF_PYTHON = LIBDIR + '/python'
-BF_PYTHON_VERSION = '3.4'
-WITH_BF_STATICPYTHON = False
-BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}'
-BF_PYTHON_BINARY = 'python'
-BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}mw'
-BF_PYTHON_DLL = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}'
-BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib'
-BF_PYTHON_LIB_STATIC = '${BF_PYTHON}/lib/libpython${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}.a'
-
-WITH_BF_OPENAL = True
-BF_OPENAL = LIBDIR + '/openal'
-BF_OPENAL_INC = '${BF_OPENAL}/include'
-BF_OPENAL_LIB = 'wrap_oal'
-BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
-
-WITH_BF_FFMPEG = True
-BF_FFMPEG_LIB = 'avformat-55 avcodec-55 avdevice-55 avutil-52 swscale-2'
-BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
-BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
-BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-55.dll ${BF_FFMPEG_LIBPATH}/avcodec-55.dll ${BF_FFMPEG_LIBPATH}/avdevice-55.dll ${BF_FFMPEG_LIBPATH}/avutil-52.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
-
-WITH_BF_AUDASPACE = True
-
-WITH_BF_JACK = False
-BF_JACK = LIBDIR + '/jack'
-BF_JACK_INC = '${BF_JACK}/include'
-BF_JACK_LIB = 'libjack'
-BF_JACK_LIBPATH = '${BF_JACK}/lib'
-
-WITH_BF_SNDFILE = False
-BF_SNDFILE = LIBDIR + '/sndfile'
-BF_SNDFILE_INC = '${BF_SNDFILE}/include'
-BF_SNDFILE_LIB = 'libsndfile-1'
-BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib'
-
-WITH_BF_SDL = True
-BF_SDL = LIBDIR + '/sdl'
-BF_SDL_INC = '${BF_SDL}/include'
-BF_SDL_LIB = 'SDL'
-BF_SDL_LIBPATH = '${BF_SDL}/lib'
-
-BF_PTHREADS = LIBDIR + '/pthreads'
-BF_PTHREADS_INC = '${BF_PTHREADS}/include'
-BF_PTHREADS_LIB = 'pthreadGC2'
-BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
-
-WITH_BF_OPENEXR = True
-WITH_BF_STATICOPENEXR = False
-BF_OPENEXR = LIBDIR + '/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR'
-BF_OPENEXR_LIB = 'Half IlmImf Imath IlmThread Iex'
-BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
-# Warning, this static lib configuration is untested! users of this OS please confirm.
-BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
-
-WITH_BF_DDS = True
-
-WITH_BF_JPEG = True
-BF_JPEG = LIBDIR + '/jpeg'
-BF_JPEG_INC = '${BF_JPEG}/include'
-BF_JPEG_LIB = 'liblibjpeg'
-BF_JPEG_LIBPATH = '${BF_JPEG}/lib'
-
-WITH_BF_PNG = True
-BF_PNG = LIBDIR + '/png'
-BF_PNG_INC = '${BF_PNG}/include'
-BF_PNG_LIB = 'png'
-BF_PNG_LIBPATH = '${BF_PNG}/lib'
-
-WITH_BF_TIFF = True
-BF_TIFF = LIBDIR + '/tiff'
-BF_TIFF_INC = '${BF_TIFF}/include'
-BF_TIFF_LIB = 'tiff'
-BF_TIFF_LIBPATH = '${BF_TIFF}/lib'
-
-WITH_BF_ZLIB = True
-BF_ZLIB = LIBDIR + '/zlib'
-BF_ZLIB_INC = '${BF_ZLIB}/include'
-BF_ZLIB_LIB = 'z'
-BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib'
-
-WITH_BF_INTERNATIONAL = True
-
-WITH_BF_OPENJPEG = True
-BF_OPENJPEG = '#extern/libopenjpeg'
-BF_OPENJPEG_LIB = ''
-BF_OPENJPEG_INC = '${BF_OPENJPEG}'
-BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
-
-WITH_BF_FFTW3 = True
-BF_FFTW3 = LIBDIR + '/fftw3'
-BF_FFTW3_INC = '${BF_FFTW3}/include'
-BF_FFTW3_LIB = 'fftw3'
-BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_PLAYER = True
-WITH_BF_OCEANSIM = True
-
-WITH_BF_BULLET = True
-BF_BULLET = '#extern/bullet2/src'
-BF_BULLET_INC = '${BF_BULLET}'
-BF_BULLET_LIB = 'extern_bullet'
-
-BF_WINTAB = LIBDIR + '/wintab'
-BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE'
-
-BF_FREETYPE = LIBDIR + '/freetype'
-BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2'
-BF_FREETYPE_LIB = 'freetype'
-BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib'
-
-WITH_BF_ICONV = False
-BF_ICONV = LIBDIR + "/iconv"
-BF_ICONV_INC = '${BF_ICONV}/include'
-BF_ICONV_LIB = 'iconv'
-BF_ICONV_LIBPATH = '${BF_ICONV}/lib'
-
-WITH_BF_REDCODE = False
-BF_REDCODE_INC = '#extern'
-
-# Mesa Libs should go here if your using them as well....
-WITH_BF_STATICOPENGL = False
-BF_OPENGL = 'C:\\MingW'
-BF_OPENGL_INC = '${BF_OPENGL}/include'
-BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
-BF_OPENGL_LIB = 'opengl32 glu32'
-BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a',
- '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
- '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
-
-WITH_BF_COLLADA = True
-BF_COLLADA = '#source/blender/collada'
-BF_COLLADA_INC = '${BF_COLLADA}'
-BF_COLLADA_LIB = 'bf_collada'
-
-BF_OPENCOLLADA = LIBDIR + '/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
-BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver pcre buffer ftoa xml'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
-
-#Cycles
-WITH_BF_CYCLES = True
-WITH_BF_CYCLES_CUDA_BINARIES = False
-BF_CYCLES_CUDA_NVCC = "" # Path to the NVIDIA CUDA compiler
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
-
-WITH_BF_OIIO = True
-BF_OIIO = LIBDIR + '/openimageio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIB = 'OpenImageIO'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-
-WITH_BF_OCIO = True
-BF_OCIO = LIBDIR + '/opencolorio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB = 'OpenColorIO'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-BF_BOOST = LIBDIR + '/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB = 'boost_date_time-mgw46-mt-s-1_49 boost_filesystem-mgw46-mt-s-1_49 boost_regex-mgw46-mt-s-1_49 boost_system-mgw46-mt-s-1_49 boost_thread-mgw46-mt-s-1_49'
-BF_BOOST_LIB_INTERNATIONAL = 'boost_locale-mgw46-mt-s-1_49'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-WITH_BF_OPENSUBDIV = False
-BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-
-#Ray trace optimization
-WITH_BF_RAYOPTIMIZATION = True
-BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
-
-WITH_BF_IME = True
-
-WITH_BF_OPENMP = True
-
-#CUDA
-WITH_BF_CYCLES_CUDA_BINARIES = False
-#BF_CYCLES_CUDA_NVCC = "" # Path to the nvidia compiler
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50']
-
-#Freestyle
-WITH_BF_FREESTYLE = True
-
-##
-CC = 'gcc'
-CXX = 'g++'
-
-CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
-CXXFLAGS = []
-
-CPPFLAGS = ['-DWIN32', '-DFREE_WINDOWS', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE', '-DBOOST_ALL_NO_LIB', '-DBOOST_THREAD_USE_LIB', '-DGLEW_STATIC', '-DOPJ_STATIC']
-REL_CFLAGS = []
-REL_CXXFLAGS = []
-REL_CCFLAGS = ['-O2']
-
-C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement', '-Wstrict-prototypes']
-
-CC_WARN = [ '-Wall' ]
-
-LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32', '-lpsapi', '-ldbghelp']
-
-if WITH_BF_IME:
- LLIBS.append('-limm32')
-
-PLATFORM_LINKFLAGS = ['-Xlinker', '--stack=2097152']
-
-## DISABLED, causes linking errors!
-## for re-distribution, so users dont need mingw installed
-# PLATFORM_LINKFLAGS += ["-static-libgcc", "-static-libstdc++"]
-
-BF_DEBUG = False
-BF_DEBUG_CCFLAGS= ['-g']
-
-BF_PROFILE_CCFLAGS = ['-pg', '-g']
-BF_PROFILE_LINKFLAGS = ['-pg']
-BF_PROFILE_FLAGS = BF_PROFILE_CCFLAGS
-BF_PROFILE = False
-
-BF_BUILDDIR = '..\\build\\win32-mingw'
-BF_INSTALLDIR='..\\install\\win32-mingw'
diff --git a/build_files/scons/config/win32-vc-config.py b/build_files/scons/config/win32-vc-config.py
deleted file mode 100644
index 9bd23a46d66..00000000000
--- a/build_files/scons/config/win32-vc-config.py
+++ /dev/null
@@ -1,264 +0,0 @@
-import subprocess
-
-CL_OUT = subprocess.Popen(["cl.exe"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
-CL_STDOUT, CL_STDERR = CL_OUT.communicate()
-
-if "18.00." in CL_STDERR:
- VC_VERSION = '12.0'
- LCGDIR = '#../lib/windows_vc12'
-else:
- import sys
- print("Visual C version not supported {}\n".format(CL_STDERR))
- sys.exit(1)
-
-LIBDIR = '${LCGDIR}'
-
-WITH_BF_FFMPEG = True
-BF_FFMPEG = LIBDIR +'/ffmpeg'
-BF_FFMPEG_INC = '${BF_FFMPEG}/include ${BF_FFMPEG}/include/msvc'
-BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB = 'avformat-55.lib avcodec-55.lib avdevice-55.lib avutil-52.lib swscale-2.lib'
-BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-55.dll ${BF_FFMPEG_LIBPATH}/avcodec-55.dll ${BF_FFMPEG_LIBPATH}/avdevice-55.dll ${BF_FFMPEG_LIBPATH}/avutil-52.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
-
-BF_PYTHON = LIBDIR + '/python'
-BF_PYTHON_VERSION = '3.4'
-BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}'
-BF_PYTHON_BINARY = 'python'
-BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}'
-BF_PYTHON_DLL = '${BF_PYTHON_LIB}'
-BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib'
-
-WITH_BF_PYTHON_INSTALL_NUMPY = True
-
-WITH_BF_OPENAL = True
-BF_OPENAL = LIBDIR + '/openal'
-BF_OPENAL_INC = '${BF_OPENAL}/include '
-BF_OPENAL_LIB = 'OpenAL32'
-BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
-
-WITH_BF_ICONV = True
-BF_ICONV = LIBDIR + '/iconv'
-BF_ICONV_INC = '${BF_ICONV}/include'
-BF_ICONV_LIB = 'iconv'
-BF_ICONV_LIBPATH = '${BF_ICONV}/lib'
-
-WITH_BF_AUDASPACE = True
-
-WITH_BF_JACK = False
-BF_JACK = LIBDIR + '/jack'
-BF_JACK_INC = '${BF_JACK}/include ${BF_FFMPEG}/include/msvc'
-BF_JACK_LIB = 'libjack'
-BF_JACK_LIBPATH = '${BF_JACK}/lib'
-
-WITH_BF_SNDFILE = True
-BF_SNDFILE = LIBDIR + '/sndfile'
-BF_SNDFILE_INC = '${BF_SNDFILE}/include'
-BF_SNDFILE_LIB = 'libsndfile-1'
-BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib'
-
-WITH_BF_SDL = True
-BF_SDL = LIBDIR + '/sdl'
-BF_SDL_INC = '${BF_SDL}/include'
-BF_SDL_LIB = 'SDL2.lib'
-BF_SDL_LIBPATH = '${BF_SDL}/lib'
-
-BF_PTHREADS = LIBDIR + '/pthreads'
-BF_PTHREADS_INC = '${BF_PTHREADS}/include'
-BF_PTHREADS_LIB = 'pthreadVC2'
-BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
-
-WITH_BF_OPENEXR = True
-WITH_BF_STATICOPENEXR = False
-BF_OPENEXR = LIBDIR + '/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR '
-BF_OPENEXR_LIB = ' Iex-2_2 Half IlmImf-2_2 Imath-2_2 IlmThread-2_2 '
-BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
-BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
-
-WITH_BF_DDS = True
-
-WITH_BF_JPEG = True
-BF_JPEG = LIBDIR + '/jpeg'
-BF_JPEG_INC = '${BF_JPEG}/include'
-BF_JPEG_LIB = 'libjpeg'
-BF_JPEG_LIBPATH = '${BF_JPEG}/lib'
-
-WITH_BF_PNG = True
-BF_PNG = LIBDIR + '/png'
-BF_PNG_INC = '${BF_PNG}/include'
-BF_PNG_LIB = 'libpng'
-BF_PNG_LIBPATH = '${BF_PNG}/lib'
-
-WITH_BF_TIFF = True
-BF_TIFF = LIBDIR + '/tiff'
-BF_TIFF_INC = '${BF_TIFF}/include'
-BF_TIFF_LIB = 'libtiff'
-BF_TIFF_LIBPATH = '${BF_TIFF}/lib'
-
-WITH_BF_ZLIB = True
-BF_ZLIB = LIBDIR + '/zlib'
-BF_ZLIB_INC = '${BF_ZLIB}/include'
-BF_ZLIB_LIB = 'libz_st'
-BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib'
-
-WITH_BF_INTERNATIONAL = True
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_PLAYER = True
-WITH_BF_OCEANSIM = True
-
-WITH_BF_BULLET = True
-BF_BULLET = '#extern/bullet2/src'
-BF_BULLET_INC = '${BF_BULLET}'
-BF_BULLET_LIB = 'extern_bullet'
-
-WITH_BF_ELTOPO = False
-BF_LAPACK = LIBDIR + '/lapack'
-BF_LAPACK_LIB = 'libf2c clapack_nowrap BLAS_nowrap'
-BF_LAPACK_LIBPATH = '${BF_LAPACK}/lib'
-
-BF_WINTAB = LIBDIR + '/wintab'
-BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE'
-
-WITH_BF_BINRELOC = False
-
-BF_WITH_FREETYPE = True
-BF_FREETYPE = LIBDIR + '/freetype'
-BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2'
-BF_FREETYPE_LIB = 'freetype2ST'
-BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib'
-
-WITH_BF_OPENJPEG = True
-BF_OPENJPEG = '#extern/libopenjpeg'
-BF_OPENJPEG_LIB = ''
-BF_OPENJPEG_INC = '${BF_OPENJPEG}'
-BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
-
-WITH_BF_FFTW3 = True
-BF_FFTW3 = LIBDIR + '/fftw3'
-BF_FFTW3_INC = '${BF_FFTW3}/include'
-BF_FFTW3_LIB = 'libfftw'
-BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
-
-WITH_BF_REDCODE = False
-BF_REDCODE_INC = '#extern'
-
-WITH_BF_COLLADA = True
-BF_COLLADA = '#source/blender/collada'
-BF_COLLADA_INC = '${BF_COLLADA}'
-BF_COLLADA_LIB = 'bf_collada'
-
-BF_OPENCOLLADA = LIBDIR + '/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
-BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml pcre buffer ftoa'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
-
-WITH_BF_IME = True
-
-WITH_BF_3DMOUSE = True
-
-WITH_BF_OPENMP = True
-
-#Cycles
-WITH_BF_CYCLES = True
-
-WITH_BF_CYCLES_OSL = True
-WITH_BF_STATICOSL = True
-BF_OSL = '${LIBDIR}/osl'
-BF_OSL_INC = '${BF_OSL}/include'
-BF_OSL_LIBPATH = '${BF_OSL}/lib'
-BF_OSL_LIB_STATIC = '${BF_OSL_LIBPATH}/oslcomp.lib ${BF_OSL_LIBPATH}/oslexec.lib ${BF_OSL_LIBPATH}/oslquery.lib '
-BF_OSL_COMPILER = '${BF_OSL}/bin/oslc'
-
-WITH_BF_LLVM = True
-BF_LLVM = LIBDIR + '/llvm'
-BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMX86Info LLVMX86AsmPrinter ' + \
- 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \
- 'LLVMTarget LLVMMC LLVMCore LLVMObject LLVMRuntimeDyld LLVMSupport'
-BF_LLVM_LIBPATH = '${BF_LLVM}/lib'
-
-WITH_BF_OIIO = True
-BF_OIIO = '${LIBDIR}/openimageio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/OpenImageIO.lib'
-WITH_BF_STATICOIIO = True
-
-WITH_BF_OCIO = True
-BF_OCIO = '${LIBDIR}/opencolorio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/OpenColorIO.lib'
-WITH_BF_STATICOCIO = True
-
-WITH_BF_BOOST = True
-BF_BOOST = '${LIBDIR}/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB = 'libboost_date_time-vc120-mt-s-1_55 libboost_filesystem-vc120-mt-s-1_55 libboost_regex-vc120-mt-s-1_55 libboost_system-vc120-mt-s-1_55 libboost_thread-vc120-mt-s-1_55 libboost_wave-vc120-mt-s-1_55'
-BF_BOOST_LIB_INTERNATIONAL = ' libboost_locale-vc120-mt-s-1_55'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-#CUDA
-WITH_BF_CYCLES_CUDA_BINARIES = False
-#BF_CYCLES_CUDA_NVCC = "" # Path to the nvidia compiler
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
-
-#Ray trace optimization
-WITH_BF_RAYOPTIMIZATION = True
-BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
-
-#Freestyle
-WITH_BF_FREESTYLE = True
-
-WITH_BF_OPENSUBDIV = True
-BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-
-WITH_BF_STATICOPENGL = False
-BF_OPENGL_INC = '${BF_OPENGL}/include'
-BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
-BF_OPENGL_LIB = 'opengl32 glu32'
-BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a',
- '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
- '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
-
-CC = 'cl.exe'
-CXX = 'cl.exe'
-
-CCFLAGS = ['/nologo', '/J', '/W3', '/Gd', '/w34062', '/wd4018', '/wd4065', '/wd4127', '/wd4181', '/wd4200', '/wd4244', '/wd4267', '/wd4305', '/wd4800', '/we4013', '/we4431']
-CXXFLAGS = ['/EHsc']
-BGE_CXXFLAGS = ['/O2', '/Ob2', '/EHsc', '/GR', '/fp:fast', '/arch:SSE']
-
-if VC_VERSION == '12.0':
- CCFLAGS.append('/DOIIO_STATIC_BUILD') # OIIO api changed with 1.4 making this needed
-
-BF_DEBUG_CCFLAGS = ['/Zi', '/Ob0', '/Od', '/FR${TARGET}.sbr']
-
-CPPFLAGS = ['-DWIN32','-D_CONSOLE', '-D_LIB', '-D_CRT_SECURE_NO_DEPRECATE', '-DOPJ_STATIC']
-REL_CFLAGS = []
-REL_CXXFLAGS = []
-REL_CCFLAGS = ['-O2', '/Ob2']
-
-C_WARN = []
-CC_WARN = []
-CXX_WARN = []
-
-LLIBS = ['ws2_32', 'vfw32', 'winmm', 'kernel32', 'user32', 'gdi32', 'comdlg32', 'advapi32', 'shfolder', 'shell32', 'ole32', 'oleaut32', 'uuid', 'psapi', 'Dbghelp']
-
-if WITH_BF_IME:
- LLIBS.append('imm32')
-
-PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:IX86','/STACK:2097152','/INCREMENTAL:NO', '/LARGEADDRESSAWARE', '/NODEFAULTLIB:msvcrt.lib', '/NODEFAULTLIB:msvcmrt.lib', '/NODEFAULTLIB:msvcurt.lib', '/NODEFAULTLIB:msvcrtd.lib']
-
-# # Todo
-# BF_PROFILE_CCFLAGS = ['-pg', '-g ']
-# BF_PROFILE_LINKFLAGS = ['-pg']
-# BF_PROFILE = False
-
-BF_BSC=False
-
-BF_CYCLES_CUDA_ENV="C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd"
-BF_BUILDDIR = '..\\build\\win32-vc'
-BF_INSTALLDIR='..\\install\\win32-vc'
diff --git a/build_files/scons/config/win64-mingw-config.py b/build_files/scons/config/win64-mingw-config.py
deleted file mode 100644
index 87a9b5e4eac..00000000000
--- a/build_files/scons/config/win64-mingw-config.py
+++ /dev/null
@@ -1,224 +0,0 @@
-LCGDIR = '#../lib/mingw64'
-LIBDIR = "${LCGDIR}"
-
-BF_PYTHON = LIBDIR + '/python'
-BF_PYTHON_VERSION = '3.4'
-WITH_BF_STATICPYTHON = False
-BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}'
-BF_PYTHON_BINARY = 'python'
-BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}mw'
-BF_PYTHON_DLL = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}'
-BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib'
-
-WITH_BF_OPENAL = True
-BF_OPENAL = LIBDIR + '/openal'
-BF_OPENAL_INC = '${BF_OPENAL}/include'
-BF_OPENAL_LIB = 'wrap_oal'
-BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
-
-WITH_BF_FFMPEG = True
-BF_FFMPEG_LIB = 'avformat.dll avcodec.dll avdevice.dll avutil.dll swscale.dll swresample.dll'
-BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
-BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
-BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-53.dll ${BF_FFMPEG_LIBPATH}/avcodec-53.dll ${BF_FFMPEG_LIBPATH}/avdevice-53.dll ${BF_FFMPEG_LIBPATH}/avutil-51.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll ${BF_FFMPEG_LIBPATH}/swresample-0.dll ${BF_FFMPEG_LIBPATH}/xvidcore.dll'
-
-WITH_BF_AUDASPACE = True
-
-WITH_BF_JACK = False
-BF_JACK = LIBDIR + '/jack'
-BF_JACK_INC = '${BF_JACK}/include'
-BF_JACK_LIB = 'libjack'
-BF_JACK_LIBPATH = '${BF_JACK}/lib'
-
-WITH_BF_SNDFILE = False
-BF_SNDFILE = LIBDIR + '/sndfile'
-BF_SNDFILE_INC = '${BF_SNDFILE}/include'
-BF_SNDFILE_LIB = 'libsndfile-1'
-BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib'
-
-WITH_BF_SDL = True
-BF_SDL = LIBDIR + '/sdl'
-BF_SDL_INC = '${BF_SDL}/include'
-BF_SDL_LIB = 'SDL'
-BF_SDL_LIBPATH = '${BF_SDL}/lib'
-
-BF_PTHREADS = '' # Part of MinGW-w64
-BF_PTHREADS_INC = ''
-BF_PTHREADS_LIB = ''
-BF_PTHREADS_LIBPATH = ''
-
-WITH_BF_OPENEXR = True
-WITH_BF_STATICOPENEXR = False
-BF_OPENEXR = LIBDIR + '/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR'
-BF_OPENEXR_LIB = 'Half IlmImf Imath IlmThread Iex'
-BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
-
-WITH_BF_DDS = True
-
-WITH_BF_JPEG = True
-BF_JPEG = LIBDIR + '/jpeg'
-BF_JPEG_INC = '${BF_JPEG}/include'
-BF_JPEG_LIB = 'jpeg'
-BF_JPEG_LIBPATH = '${BF_JPEG}/lib'
-
-WITH_BF_PNG = True
-BF_PNG = LIBDIR + '/png'
-BF_PNG_INC = '${BF_PNG}/include'
-BF_PNG_LIB = 'png'
-BF_PNG_LIBPATH = '${BF_PNG}/lib'
-
-WITH_BF_TIFF = True
-BF_TIFF = LIBDIR + '/tiff'
-BF_TIFF_INC = '${BF_TIFF}/include'
-BF_TIFF_LIB = 'tiff'
-BF_TIFF_LIBPATH = '${BF_TIFF}/lib'
-
-WITH_BF_ZLIB = True
-BF_ZLIB = LIBDIR + '/zlib'
-BF_ZLIB_INC = '${BF_ZLIB}/include'
-BF_ZLIB_LIB = 'z'
-BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib'
-
-WITH_BF_INTERNATIONAL = True
-
-WITH_BF_OPENJPEG = True
-BF_OPENJPEG = '#extern/libopenjpeg'
-BF_OPENJPEG_LIB = ''
-BF_OPENJPEG_INC = '${BF_OPENJPEG}'
-BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
-
-WITH_BF_FFTW3 = True
-BF_FFTW3 = LIBDIR + '/fftw3'
-BF_FFTW3_INC = '${BF_FFTW3}/include'
-BF_FFTW3_LIB = 'fftw3'
-BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_OCEANSIM = True
-WITH_BF_PLAYER = True
-WITH_BF_LIBMV = True
-
-WITH_BF_BULLET = True
-BF_BULLET = '#extern/bullet2/src'
-BF_BULLET_INC = '${BF_BULLET}'
-BF_BULLET_LIB = 'extern_bullet'
-
-BF_WINTAB = LIBDIR + '/wintab'
-BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE'
-
-# enable freetype2 support for text objects
-BF_FREETYPE = LIBDIR + '/freetype'
-BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2/'
-BF_FREETYPE_LIB = 'freetype'
-BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib'
-
-WITH_BF_ICONV = False
-BF_ICONV = LIBDIR + "/iconv"
-BF_ICONV_INC = '${BF_ICONV}/include'
-BF_ICONV_LIB = 'iconv'
-BF_ICONV_LIBPATH = '${BF_ICONV}/lib'
-
-WITH_BF_REDCODE = False
-BF_REDCODE_INC = '#extern'
-
-# Mesa Libs should go here if your using them as well....
-WITH_BF_STATICOPENGL = False
-BF_OPENGL = 'C:\\MingW'
-BF_OPENGL_INC = '${BF_OPENGL}/include'
-BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
-BF_OPENGL_LIB = 'opengl32 glu32'
-BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a',
- '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
- '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
-
-WITH_BF_COLLADA = True
-BF_COLLADA = '#source/blender/collada'
-BF_COLLADA_INC = '${BF_COLLADA}'
-BF_COLLADA_LIB = 'bf_collada'
-
-BF_OPENCOLLADA = LIBDIR + '/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
-BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver pcre buffer ftoa xml'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
-
-#Cycles
-WITH_BF_CYCLES = True
-WITH_BF_CYCLES_CUDA_BINARIES = False
-BF_CYCLES_CUDA_NVCC = "" # Path to the NVIDIA CUDA compiler
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
-
-WITH_BF_OIIO = True
-BF_OIIO = LIBDIR + '/openimageio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIB = 'OpenImageIO'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-
-WITH_BF_OCIO = True
-BF_OCIO = LIBDIR + '/opencolorio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIB = 'OpenColorIO'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-
-WITH_BF_BOOST = True
-BF_BOOST = LIBDIR + '/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB = 'boost_date_time-mgw47-mt-s-1_49 boost_date_time-mgw47-mt-sd-1_49 boost_filesystem-mgw47-mt-s-1_49 boost_filesystem-mgw47-mt-sd-1_49 boost_regex-mgw47-mt-s-1_49 boost_regex-mgw47-mt-sd-1_49 boost_system-mgw47-mt-s-1_49 boost_system-mgw47-mt-sd-1_49 boost_thread-mgw47-mt-s-1_49 boost_thread-mgw47-mt-sd-1_49'
-BF_BOOST_LIB_INTERNATIONAL = ' boost_locale-mgw47-mt-s-1_49 boost_locale-mgw47-mt-sd-1_49'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-WITH_BF_OPENSUBDIV = False
-BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-
-#Ray trace optimization
-WITH_BF_RAYOPTIMIZATION = True
-BF_RAYOPTIMIZATION_SSE_FLAGS = ['-mmmx', '-msse', '-msse2']
-
-WITH_BF_IME = True
-
-WITH_BF_OPENMP = True
-
-#Freestyle
-WITH_BF_FREESTYLE = True
-
-##
-CC = 'gcc'
-CXX = 'g++'
-
-CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
-CXXFLAGS = [ '-fpermissive' ]
-
-CPPFLAGS = ['-DWIN32', '-DMS_WIN64', '-DFREE_WINDOWS', '-DFREE_WINDOWS64', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE', '-DBOOST_ALL_NO_LIB', '-DBOOST_THREAD_USE_LIB', '-DGLEW_STATIC', '-DOPJ_STATIC']
-REL_CFLAGS = []
-REL_CXXFLAGS = []
-REL_CCFLAGS = ['-O2', '-ftree-vectorize']
-
-# NOTE: C_WARN seems to get ignored - at least -Wno-char-subscripts doesn't work!
-C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement', '-Wstrict-prototypes']
-
-CC_WARN = [ '-Wall', '-Wno-char-subscripts' ]
-
-LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32', '-lpsapi', '-lpthread', '-ldbghelp']
-
-if WITH_BF_IME:
- LLIBS.append('-limm32')
-
-PLATFORM_LINKFLAGS = ['-Xlinker', '--stack=2097152']
-
-## DISABLED, causes linking errors!
-## for re-distribution, so users dont need mingw installed
-# PLATFORM_LINKFLAGS += ["-static-libgcc", "-static-libstdc++"]
-
-BF_DEBUG = False
-BF_DEBUG_CCFLAGS= ['-g']
-
-BF_PROFILE_CCFLAGS = ['-pg', '-g']
-BF_PROFILE_LINKFLAGS = ['-pg']
-BF_PROFILE_FLAGS = BF_PROFILE_CCFLAGS
-BF_PROFILE = False
-
-BF_BUILDDIR = '..\\build\\win64-mingw'
-BF_INSTALLDIR='..\\install\\win64-mingw'
diff --git a/build_files/scons/config/win64-vc-config.py b/build_files/scons/config/win64-vc-config.py
deleted file mode 100644
index adacc2946c5..00000000000
--- a/build_files/scons/config/win64-vc-config.py
+++ /dev/null
@@ -1,264 +0,0 @@
-import subprocess
-
-CL_OUT = subprocess.Popen(["cl.exe"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
-CL_STDOUT, CL_STDERR = CL_OUT.communicate()
-
-if "18.00." in CL_STDERR:
- VC_VERSION = '12.0'
- LCGDIR = '#../lib/win64_vc12'
-else:
- import sys
- print("Visual C version not supported {}\n".format(CL_STDERR))
- sys.exit(1)
-
-LIBDIR = '${LCGDIR}'
-
-WITH_BF_FFMPEG = True
-BF_FFMPEG = LIBDIR +'/ffmpeg'
-BF_FFMPEG_INC = '${BF_FFMPEG}/include ${BF_FFMPEG}/include/msvc '
-BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
-BF_FFMPEG_LIB = 'avformat-55.lib avcodec-55.lib avdevice-55.lib avutil-52.lib swscale-2.lib'
-BF_FFMPEG_DLL = '${BF_FFMPEG_LIBPATH}/avformat-55.dll ${BF_FFMPEG_LIBPATH}/avcodec-55.dll ${BF_FFMPEG_LIBPATH}/avdevice-55.dll ${BF_FFMPEG_LIBPATH}/avutil-52.dll ${BF_FFMPEG_LIBPATH}/swscale-2.dll'
-
-
-BF_PYTHON = LIBDIR + '/python'
-BF_PYTHON_VERSION = '3.4'
-BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}'
-BF_PYTHON_BINARY = 'python'
-BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION[0]}${BF_PYTHON_VERSION[2]}'
-BF_PYTHON_DLL = '${BF_PYTHON_LIB}'
-BF_PYTHON_LIBPATH = '${BF_PYTHON}/lib'
-
-WITH_BF_PYTHON_INSTALL_NUMPY = True
-
-WITH_BF_OPENAL = True
-BF_OPENAL = LIBDIR + '/openal'
-BF_OPENAL_INC = '${BF_OPENAL}/include '
-BF_OPENAL_LIB = 'OpenAL32'
-BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
-
-WITH_BF_SNDFILE = True
-BF_SNDFILE = LIBDIR + '/sndfile'
-BF_SNDFILE_INC = '${BF_SNDFILE}/include'
-BF_SNDFILE_LIB = 'libsndfile-1'
-BF_SNDFILE_LIBPATH = '${BF_SNDFILE}/lib'
-
-WITH_BF_ICONV = True
-BF_ICONV = LIBDIR + '/iconv'
-BF_ICONV_INC = '${BF_ICONV}/include'
-BF_ICONV_LIB = 'iconv'
-BF_ICONV_LIBPATH = '${BF_ICONV}/lib'
-
-WITH_BF_SDL = True
-BF_SDL = LIBDIR + '/sdl'
-BF_SDL_INC = '${BF_SDL}/include'
-BF_SDL_LIB = 'SDL2.lib'
-BF_SDL_LIBPATH = '${BF_SDL}/lib'
-
-WITH_BF_AUDASPACE = True
-
-WITH_BF_JACK = False
-
-BF_PTHREADS = LIBDIR + '/pthreads'
-BF_PTHREADS_INC = '${BF_PTHREADS}/include'
-BF_PTHREADS_LIB = 'pthreadVC2'
-BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
-
-WITH_BF_OPENEXR = True
-WITH_BF_STATICOPENEXR = False
-BF_OPENEXR = LIBDIR + '/openexr'
-BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR '
-BF_OPENEXR_LIB = ' Iex-2_2 Half IlmImf-2_2 Imath-2_2 IlmThread-2_2 '
-BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
-BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
-
-WITH_BF_DDS = True
-
-WITH_BF_JPEG = True
-BF_JPEG = LIBDIR + '/jpeg'
-BF_JPEG_INC = '${BF_JPEG}/include'
-BF_JPEG_LIB = 'libjpeg'
-BF_JPEG_LIBPATH = '${BF_JPEG}/lib'
-
-WITH_BF_PNG = True
-BF_PNG = LIBDIR + '/png'
-BF_PNG_INC = '${BF_PNG}/include'
-BF_PNG_LIB = 'libpng'
-BF_PNG_LIBPATH = '${BF_PNG}/lib'
-
-WITH_BF_TIFF = True
-BF_TIFF = LIBDIR + '/tiff'
-BF_TIFF_INC = '${BF_TIFF}/include'
-BF_TIFF_LIB = 'libtiff'
-BF_TIFF_LIBPATH = '${BF_TIFF}/lib'
-
-WITH_BF_ZLIB = True
-BF_ZLIB = LIBDIR + '/zlib'
-BF_ZLIB_INC = '${BF_ZLIB}/include'
-BF_ZLIB_LIB = 'libz_st'
-BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib'
-
-WITH_BF_INTERNATIONAL = True
-
-WITH_BF_GAMEENGINE = True
-WITH_BF_PLAYER = True
-WITH_BF_OCEANSIM = True
-
-WITH_BF_BULLET = True
-BF_BULLET = '#extern/bullet2/src'
-BF_BULLET_INC = '${BF_BULLET}'
-BF_BULLET_LIB = 'extern_bullet'
-
-WITH_BF_ELTOPO = False
-BF_LAPACK = LIBDIR + '/lapack'
-BF_LAPACK_LIB = 'libf2c clapack_nowrap BLAS_nowrap'
-BF_LAPACK_LIBPATH = '${BF_LAPACK}/lib'
-
-BF_WINTAB = LIBDIR + '/wintab'
-BF_WINTAB_INC = '${BF_WINTAB}/INCLUDE'
-
-WITH_BF_BINRELOC = False
-
-BF_WITH_FREETYPE = True
-BF_FREETYPE = LIBDIR + '/freetype'
-BF_FREETYPE_INC = '${BF_FREETYPE}/include ${BF_FREETYPE}/include/freetype2'
-BF_FREETYPE_LIB = 'freetype2ST'
-BF_FREETYPE_LIBPATH = '${BF_FREETYPE}/lib'
-
-WITH_BF_QUICKTIME = False
-BF_QUICKTIME = LIBDIR + '/QTDevWin'
-BF_QUICKTIME_INC = '${BF_QUICKTIME}/CIncludes'
-BF_QUICKTIME_LIB = 'qtmlClient'
-BF_QUICKTIME_LIBPATH = '${BF_QUICKTIME}/Libraries'
-
-WITH_BF_OPENJPEG = True
-BF_OPENJPEG = '#extern/libopenjpeg'
-BF_OPENJPEG_LIB = ''
-BF_OPENJPEG_INC = '${BF_OPENJPEG}'
-BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
-
-WITH_BF_FFTW3 = True
-BF_FFTW3 = LIBDIR + '/fftw3'
-BF_FFTW3_INC = '${BF_FFTW3}/include'
-BF_FFTW3_LIB = 'libfftw'
-BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
-
-WITH_BF_REDCODE = False
-BF_REDCODE_INC = '#extern'
-
-WITH_BF_COLLADA = True
-BF_COLLADA = '#source/blender/collada'
-BF_COLLADA_INC = '${BF_COLLADA}'
-BF_COLLADA_LIB = 'bf_collada'
-
-BF_OPENCOLLADA = LIBDIR + '/opencollada'
-BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include/opencollada'
-BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser MathMLSolver xml pcre buffer ftoa'
-BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
-
-WITH_BF_IME = True
-
-WITH_BF_3DMOUSE = True
-
-WITH_BF_OPENMP = True
-
-#Cycles
-WITH_BF_CYCLES = True
-
-WITH_BF_CYCLES_OSL = True
-WITH_BF_STATICOSL = True
-BF_OSL = '${LIBDIR}/osl'
-BF_OSL_INC = '${BF_OSL}/include'
-BF_OSL_LIBPATH = '${BF_OSL}/lib'
-BF_OSL_LIB_STATIC = '${BF_OSL_LIBPATH}/oslcomp.lib ${BF_OSL_LIBPATH}/oslexec.lib ${BF_OSL_LIBPATH}/oslquery.lib '
-BF_OSL_COMPILER = '${BF_OSL}/bin/oslc'
-
-WITH_BF_LLVM = True
-BF_LLVM = LIBDIR + '/llvm'
-BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMX86Info LLVMX86AsmPrinter ' + \
- 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \
- 'LLVMTarget LLVMMC LLVMCore LLVMObject LLVMRuntimeDyld LLVMSupport'
-BF_LLVM_LIBPATH = '${BF_LLVM}/lib'
-
-WITH_BF_OIIO = True
-BF_OIIO = '${LIBDIR}/openimageio'
-BF_OIIO_INC = '${BF_OIIO}/include'
-BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
-BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/OpenImageIO.lib ${BF_OIIO_LIBPATH}/OpenImageIO_Util.lib'
-WITH_BF_STATICOIIO = True
-
-WITH_BF_OCIO = True
-BF_OCIO = '${LIBDIR}/opencolorio'
-BF_OCIO_INC = '${BF_OCIO}/include'
-BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
-BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/OpenColorIO.lib'
-WITH_BF_STATICOCIO = True
-
-WITH_BF_BOOST = True
-BF_BOOST = '${LIBDIR}/boost'
-BF_BOOST_INC = '${BF_BOOST}/include'
-BF_BOOST_LIB = 'libboost_date_time-vc120-mt-s-1_55 libboost_filesystem-vc120-mt-s-1_55 libboost_regex-vc120-mt-s-1_55 libboost_system-vc120-mt-s-1_55 libboost_thread-vc120-mt-s-1_55 libboost_wave-vc120-mt-s-1_55'
-BF_BOOST_LIB_INTERNATIONAL = ' libboost_locale-vc120-mt-s-1_55'
-BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
-
-#CUDA
-WITH_BF_CYCLES_CUDA_BINARIES = False
-#BF_CYCLES_CUDA_NVCC = "" # Path to the nvidia compiler
-BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
-
-#Ray trace optimization
-WITH_BF_RAYOPTIMIZATION = True
-# No need to manually specify SSE/SSE2 on x64 systems.
-BF_RAYOPTIMIZATION_SSE_FLAGS = ['']
-
-#Freestyle
-WITH_BF_FREESTYLE = True
-
-WITH_BF_OPENSUBDIV = True
-BF_OPENSUBDIV = LIBDIR + '/opensubdiv'
-BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include'
-BF_OPENSUBDIV_LIB = 'osdCPU osdGPU'
-BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib'
-
-WITH_BF_STATICOPENGL = False
-BF_OPENGL_INC = '${BF_OPENGL}/include'
-BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
-BF_OPENGL_LIB = 'opengl32 glu32'
-BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a',
- '${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
- '${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
-CC = 'cl.exe'
-CXX = 'cl.exe'
-
-CFLAGS = []
-CCFLAGS = ['/nologo', '/J', '/W3', '/Gd', '/w34062', '/wd4018', '/wd4065', '/wd4127', '/wd4181', '/wd4200', '/wd4244', '/wd4267', '/wd4305', '/wd4800', '/we4013', '/we4431']
-
-# We want to support Vista level ABI for x64
-if VC_VERSION == '12.0':
- CCFLAGS.append('/D_WIN32_WINNT=0x600')
- CCFLAGS.append('/DOIIO_STATIC_BUILD') # OIIO api changed with 1.4 making this needed
-
-CXXFLAGS = ['/EHsc']
-BGE_CXXFLAGS = ['/O2', '/Ob2', '/EHsc', '/GR', '/fp:fast']
-
-BF_DEBUG_CCFLAGS = ['/Zi', '/FR${TARGET}.sbr', '/Od', '/Ob0']
-
-CPPFLAGS = ['-DWIN32', '-D_CONSOLE', '-D_LIB', '-D_CRT_SECURE_NO_DEPRECATE', '-DOPJ_STATIC']
-REL_CFLAGS = []
-REL_CXXFLAGS = []
-REL_CCFLAGS = ['-O2', '/Ob2']
-
-C_WARN = []
-CC_WARN = []
-CXX_WARN = []
-
-LLIBS = ['ws2_32', 'vfw32', 'winmm', 'kernel32', 'user32', 'gdi32', 'comdlg32', 'advapi32', 'shfolder', 'shell32', 'ole32', 'oleaut32', 'uuid', 'psapi', 'Dbghelp']
-
-if WITH_BF_IME:
- LLIBS.append('imm32')
-
-PLATFORM_LINKFLAGS = ['/SUBSYSTEM:CONSOLE','/MACHINE:X64','/STACK:2097152','/OPT:NOREF','/INCREMENTAL:NO', '/NODEFAULTLIB:msvcrt.lib', '/NODEFAULTLIB:msvcmrt.lib', '/NODEFAULTLIB:msvcurt.lib', '/NODEFAULTLIB:msvcrtd.lib']
-
-BF_CYCLES_CUDA_ENV="C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd"
-BF_BUILDDIR = '..\\build\\win64-vc'
-BF_INSTALLDIR='..\\install\\win64-vc'
diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py
deleted file mode 100644
index 8419f9703e0..00000000000
--- a/build_files/scons/tools/Blender.py
+++ /dev/null
@@ -1,1144 +0,0 @@
-#!/usr/bin/env python
-
-"""
-tools.BlenderEnvironment
-
-This environment builds on SCons.Script.SConscript.SConsEnvironment
-
-* library repository
-* custom printout
-* wrapper functions
-
-TODO: clean up and sanitise code - crosscheck with btools and SConstruct
-to kill any code duplication
-
-"""
-
-import os
-import string
-import ctypes as ct
-import glob
-import time
-import sys
-import tarfile
-import shutil
-import cStringIO
-import platform
-
-from SCons.Script.SConscript import SConsEnvironment
-import SCons.Action
-import SCons.Util
-import SCons.Builder
-import SCons.Subst
-import SCons.Tool
-import bcolors
-bc = bcolors.bcolors()
-import btools
-VERSION = btools.VERSION
-VERSION_RELEASE_CYCLE = btools.VERSION_RELEASE_CYCLE
-
-Split = SCons.Util.Split
-Action = SCons.Action.Action
-Builder = SCons.Builder.Builder
-GetBuildPath = SConsEnvironment.GetBuildPath
-
-# a few globals
-root_build_dir = ''
-doc_build_dir = ''
-quickie = None # Anything else than None if BF_QUICK has been passed
-quicklist = [] # The list of libraries/programs to compile during a quickie
-program_list = [] # A list holding Nodes to final binaries, used to create installs
-arguments = None
-targets = None
-resources = []
-allowed_bitnesses = {4 : 32, 8 : 64} # only expecting 32-bit or 64-bit
-bitness = allowed_bitnesses[ct.sizeof(ct.c_void_p)]
-
-##### LIB STUFF ##########
-
-possible_types = ['core'] # can be set in ie. SConstruct
-libs = {}
-vcp = []
-
-def getresources():
- return resources
-
-def init_lib_dict():
- for pt in possible_types:
- libs[pt] = {}
-
-# helper func for add_lib_to_dict
-def internal_lib_to_dict(dict = None, libtype = None, libname = None, priority = 100):
- if not libname in dict[libtype]:
- done = None
- while not done:
- if dict[libtype].has_key(priority):
- priority = priority + 1
- else:
- done = True
- dict[libtype][priority] = libname
-
-# libtype and priority can both be lists, for defining lib in multiple places
-def add_lib_to_dict(env, dict = None, libtype = None, libname = None, priority = 100):
- if not dict or not libtype or not libname:
- print "Passed wrong arg"
- env.Exit()
-
- if type(libtype) is str and type(priority) is int:
- internal_lib_to_dict(dict, libtype, libname, priority)
- elif type(libtype) is list and type(priority) is list:
- if len(libtype)==len(priority):
- for lt, p in zip(libtype, priority):
- internal_lib_to_dict(dict, lt, libname, p)
- else:
- print "libtype and priority lists are unequal in length"
- env.Exit()
- else:
- print "Wrong type combinations for libtype and priority. Only str and int or list and list"
- env.Exit()
-
-def create_blender_liblist(lenv = None, libtype = None):
- if not lenv or not libtype:
- print "missing arg"
-
- lst = []
- if libtype in possible_types:
- curlib = libs[libtype]
- sortlist = curlib.keys()
- sortlist.sort()
- for sk in sortlist:
- v = curlib[sk]
- if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- target = os.path.abspath(os.getcwd() + os.sep + root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
- else:
- target = os.path.abspath(root_build_dir + 'lib' + os.sep +lenv['LIBPREFIX'] + v + lenv['LIBSUFFIX'])
- lst.append(target)
-
- return lst
-
-## TODO: static linking
-def setup_staticlibs(lenv):
- statlibs = [
- #here libs for static linking
- ]
-
- libincs = []
-
- if lenv['WITH_BF_FFMPEG']:
- libincs += Split(lenv['BF_FFMPEG_LIBPATH'])
-
- libincs.extend([
- lenv['BF_OPENGL_LIBPATH'],
- lenv['BF_JPEG_LIBPATH'],
- lenv['BF_ZLIB_LIBPATH'],
- lenv['BF_PNG_LIBPATH'],
- lenv['BF_ICONV_LIBPATH']
- ])
-
- if lenv['WITH_BF_STATICJPEG']:
- statlibs += Split(lenv['BF_JPEG_LIB_STATIC'])
- if lenv['WITH_BF_STATICPNG']:
- statlibs += Split(lenv['BF_PNG_LIB_STATIC'])
-
- libincs += Split(lenv['BF_FREETYPE_LIBPATH'])
- if lenv['WITH_BF_PYTHON']:
- libincs += Split(lenv['BF_PYTHON_LIBPATH'])
- if lenv['WITH_BF_SDL'] and not lenv['WITH_BF_SDL_DYNLOAD']:
- libincs += Split(lenv['BF_SDL_LIBPATH'])
- if lenv['WITH_BF_JACK'] and not lenv['WITH_BF_JACK_DYNLOAD']:
- libincs += Split(lenv['BF_JACK_LIBPATH'])
- if lenv['WITH_BF_SNDFILE']:
- libincs += Split(lenv['BF_SNDFILE_LIBPATH'])
- if lenv['WITH_BF_TIFF']:
- libincs += Split(lenv['BF_TIFF_LIBPATH'])
- if lenv['WITH_BF_STATICTIFF']:
- statlibs += Split(lenv['BF_TIFF_LIB_STATIC'])
- if lenv['WITH_BF_FFTW3']:
- libincs += Split(lenv['BF_FFTW3_LIBPATH'])
- if lenv['WITH_BF_STATICFFTW3']:
- statlibs += Split(lenv['BF_FFTW3_LIB_STATIC'])
- '''
- if lenv['WITH_BF_ELTOPO']:
- libincs += Split(lenv['BF_LAPACK_LIBPATH'])
- if lenv['WITH_BF_STATICLAPACK']:
- statlibs += Split(lenv['BF_LAPACK_LIB_STATIC'])
- '''
- if lenv['WITH_BF_FFMPEG'] and lenv['WITH_BF_STATICFFMPEG']:
- statlibs += Split(lenv['BF_FFMPEG_LIB_STATIC'])
- if lenv['WITH_BF_INTERNATIONAL']:
- if lenv['WITH_BF_FREETYPE_STATIC']:
- statlibs += Split(lenv['BF_FREETYPE_LIB_STATIC'])
- if lenv['WITH_BF_OPENAL']:
- libincs += Split(lenv['BF_OPENAL_LIBPATH'])
- if lenv['WITH_BF_STATICOPENAL']:
- statlibs += Split(lenv['BF_OPENAL_LIB_STATIC'])
- if lenv['WITH_BF_STATICOPENGL']:
- statlibs += Split(lenv['BF_OPENGL_LIB_STATIC'])
- if lenv['WITH_BF_STATICCXX']:
- statlibs += Split(lenv['BF_CXX_LIB_STATIC'])
-
- if lenv['WITH_BF_PYTHON'] and lenv['WITH_BF_STATICPYTHON']:
- statlibs += Split(lenv['BF_PYTHON_LIB_STATIC'])
-
- if lenv['WITH_BF_SNDFILE'] and lenv['WITH_BF_STATICSNDFILE']:
- statlibs += Split(lenv['BF_SNDFILE_LIB_STATIC'])
-
- if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- libincs += Split(lenv['BF_PTHREADS_LIBPATH'])
-
- if lenv['WITH_BF_COLLADA']:
- libincs += Split(lenv['BF_OPENCOLLADA_LIBPATH'])
- if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- libincs += Split(lenv['BF_PCRE_LIBPATH'])
- libincs += Split(lenv['BF_EXPAT_LIBPATH'])
- if lenv['WITH_BF_STATICOPENCOLLADA']:
- statlibs += Split(lenv['BF_OPENCOLLADA_LIB_STATIC'])
-
- if lenv['WITH_BF_OPENMP']:
- if lenv['OURPLATFORM'] == 'linuxcross':
- libincs += Split(lenv['BF_OPENMP_LIBPATH'])
- if lenv['WITH_BF_STATICOPENMP']:
- statlibs += Split(lenv['BF_OPENMP_LIB_STATIC'])
-
- if lenv['WITH_BF_OIIO']:
- libincs += Split(lenv['BF_OIIO_LIBPATH'])
- if lenv['WITH_BF_STATICOIIO']:
- statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
- if lenv['WITH_BF_OPENEXR']:
- libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
- if lenv['WITH_BF_STATICOPENEXR']:
- statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
- if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
- statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
-
- if lenv['WITH_BF_OCIO']:
- libincs += Split(lenv['BF_OCIO_LIBPATH'])
- if lenv['WITH_BF_STATICOCIO']:
- statlibs += Split(lenv['BF_OCIO_LIB_STATIC'])
-
- if lenv['WITH_BF_CYCLES_OSL']:
- libincs += Split(lenv['BF_OSL_LIBPATH'])
- if lenv['WITH_BF_STATICOSL']:
- statlibs += Split(lenv['BF_OSL_LIB_STATIC'])
-
- if lenv['WITH_BF_BOOST']:
- libincs += Split(lenv['BF_BOOST_LIBPATH'])
- if lenv['WITH_BF_STATICBOOST']:
- statlibs += Split(lenv['BF_BOOST_LIB_STATIC'])
-
- if lenv['WITH_BF_LLVM']:
- libincs += Split(lenv['BF_LLVM_LIBPATH'])
- if lenv['WITH_BF_STATICLLVM']:
- statlibs += Split(lenv['BF_LLVM_LIB_STATIC'])
-
- if lenv['WITH_BF_JEMALLOC']:
- libincs += Split(lenv['BF_JEMALLOC_LIBPATH'])
- if lenv['WITH_BF_STATICJEMALLOC']:
- statlibs += Split(lenv['BF_JEMALLOC_LIB_STATIC'])
-
- if lenv['OURPLATFORM']=='linux':
- if lenv['WITH_BF_3DMOUSE']:
- libincs += Split(lenv['BF_3DMOUSE_LIBPATH'])
- if lenv['WITH_BF_STATIC3DMOUSE']:
- statlibs += Split(lenv['BF_3DMOUSE_LIB_STATIC'])
-
- if lenv['WITH_BF_OPENSUBDIV']:
- libincs += Split(lenv['BF_OPENSUBDIV_LIBPATH'])
- if lenv['WITH_BF_STATICOPENSUBDIV']:
- statlibs += Split(lenv['BF_OPENSUBDIV_LIB_STATIC'])
-
- # setting this last so any overriding of manually libs could be handled
- if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross', 'win64-mingw'):
- # We must remove any previous items defining this path, for same reason stated above!
- libincs = [e for e in libincs if SCons.Subst.scons_subst(e, lenv, gvars=lenv.Dictionary()) != "/usr/lib"]
- libincs.append('/usr/lib')
-
- # Hack to pass OSD libraries to linker before extern_{clew,cuew}
- # Here we only store library path, actual library name will be added in setup_syslibs()
- for syslib in create_blender_liblist(lenv, 'system'):
- libincs.append(os.path.dirname(syslib))
-
- return statlibs, libincs
-
-def setup_syslibs(lenv):
- syslibs = []
-
- if not lenv['WITH_BF_FREETYPE_STATIC']:
- syslibs += Split(lenv['BF_FREETYPE_LIB'])
- if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
- if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
- syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
- else:
- syslibs.append(lenv['BF_PYTHON_LIB'])
- if lenv['WITH_BF_OPENAL']:
- if not lenv['WITH_BF_STATICOPENAL']:
- syslibs += Split(lenv['BF_OPENAL_LIB'])
- if lenv['WITH_BF_OPENMP'] and lenv['CC'] != 'icc' and lenv['C_COMPILER_ID'] != 'clang' and not lenv['WITH_BF_STATICOPENMP']:
- if lenv['CC'] == 'cl.exe':
- syslibs += ['vcomp']
- else:
- syslibs += ['gomp']
- if lenv['WITH_BF_ICONV']:
- syslibs += Split(lenv['BF_ICONV_LIB'])
- if lenv['WITH_BF_OIIO']:
- if not lenv['WITH_BF_STATICOIIO']:
- syslibs += Split(lenv['BF_OIIO_LIB'])
-
- if lenv['WITH_BF_OCIO']:
- if not lenv['WITH_BF_STATICOCIO']:
- syslibs += Split(lenv['BF_OCIO_LIB'])
-
- if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
- syslibs += Split(lenv['BF_OPENEXR_LIB'])
- if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
- syslibs += Split(lenv['BF_ZLIB_LIB'])
- if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
- syslibs += Split(lenv['BF_TIFF_LIB'])
- if lenv['WITH_BF_FFMPEG'] and not lenv['WITH_BF_STATICFFMPEG']:
- syslibs += Split(lenv['BF_FFMPEG_LIB'])
- if lenv['WITH_BF_OGG']:
- syslibs += Split(lenv['BF_OGG_LIB'])
- if lenv['WITH_BF_JACK'] and not lenv['WITH_BF_JACK_DYNLOAD']:
- syslibs += Split(lenv['BF_JACK_LIB'])
- if lenv['WITH_BF_SNDFILE'] and not lenv['WITH_BF_STATICSNDFILE']:
- syslibs += Split(lenv['BF_SNDFILE_LIB'])
- if lenv['WITH_BF_FFTW3'] and not lenv['WITH_BF_STATICFFTW3']:
- syslibs += Split(lenv['BF_FFTW3_LIB'])
- '''
- if lenv['WITH_BF_ELTOPO']:
- syslibs += Split(lenv['BF_LAPACK_LIB'])
- '''
- if lenv['WITH_BF_SDL'] and not lenv['WITH_BF_SDL_DYNLOAD']:
- syslibs += Split(lenv['BF_SDL_LIB'])
- if not lenv['WITH_BF_STATICOPENGL']:
- syslibs += Split(lenv['BF_OPENGL_LIB'])
- if lenv['OURPLATFORM'] in ('win32-vc', 'win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
- syslibs += Split(lenv['BF_PTHREADS_LIB'])
- if lenv['WITH_BF_COLLADA'] and not lenv['WITH_BF_STATICOPENCOLLADA']:
- syslibs.append(lenv['BF_PCRE_LIB'])
- if lenv['BF_DEBUG'] and (lenv['OURPLATFORM'] != 'linux'):
- syslibs += [colladalib+'_d' for colladalib in Split(lenv['BF_OPENCOLLADA_LIB'])]
- else:
- syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
- syslibs.append(lenv['BF_EXPAT_LIB'])
-
- if lenv['WITH_BF_JEMALLOC']:
- if not lenv['WITH_BF_STATICJEMALLOC']:
- syslibs += Split(lenv['BF_JEMALLOC_LIB'])
-
- if lenv['OURPLATFORM']=='linux':
- if lenv['WITH_BF_3DMOUSE']:
- if not lenv['WITH_BF_STATIC3DMOUSE']:
- syslibs += Split(lenv['BF_3DMOUSE_LIB'])
-
- if lenv['WITH_BF_CYCLES_OSL'] and not lenv['WITH_BF_STATICOSL']:
- syslibs += Split(lenv['BF_OSL_LIB'])
-
- if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
- syslibs += Split(lenv['BF_BOOST_LIB'])
-
- if lenv['WITH_BF_INTERNATIONAL']:
- syslibs += Split(lenv['BF_BOOST_LIB_INTERNATIONAL'])
-
- if lenv['WITH_BF_LLVM'] and not lenv['WITH_BF_STATICLLVM']:
- syslibs += Split(lenv['BF_LLVM_LIB'])
-
- if not lenv['WITH_BF_STATICJPEG']:
- syslibs += Split(lenv['BF_JPEG_LIB'])
-
- if not lenv['WITH_BF_STATICPNG']:
- syslibs += Split(lenv['BF_PNG_LIB'])
-
- if lenv['WITH_BF_OPENSUBDIV']:
- if not lenv['WITH_BF_STATICOPENSUBDIV']:
- if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
- syslibs += [osdlib+'_d' for osdlib in Split(lenv['BF_OPENSUBDIV_LIB'])]
- else:
- syslibs += Split(lenv['BF_OPENSUBDIV_LIB'])
-
- # Hack to pass OSD libraries to linker before extern_{clew,cuew}
- for syslib in create_blender_liblist(lenv, 'system'):
- syslibs.append(os.path.basename(syslib))
-
- syslibs += lenv['LLIBS']
-
- return syslibs
-
-def propose_priorities():
- print bc.OKBLUE+"Priorities:"+bc.ENDC
- for t in possible_types:
- print bc.OKGREEN+"\t"+t+bc.ENDC
- new_priority = 0
- curlib = libs[t]
- sortlist = curlib.keys()
- sortlist.sort()
-
- for sk in sortlist:
- v = curlib[sk]
- #for p,v in sorted(libs[t].iteritems()):
- print "\t\t",new_priority, v
- new_priority += 5
-
-# emits the necessary file objects for creator.c, to be used in creating
-# the final blender executable
-def creator(env):
- sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
-
- incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/depsgraph', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
-
- defs = []
-
- if env['WITH_BF_BINRELOC']:
- incs.append('#/extern/binreloc/include')
- defs.append('WITH_BINRELOC')
-
- if env['WITH_BF_SDL']:
- if env['WITH_BF_SDL_DYNLOAD']:
- defs.append('WITH_SDL_DYNLOAD')
- incs.append('#/extern/sdlew/include')
- defs.append('WITH_SDL')
-
- if env['WITH_BF_LIBMV']:
- incs.append('#/extern/libmv')
- defs.append('WITH_LIBMV')
-
- if env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_LOGGING']:
- incs.append('#/intern/cycles/blender')
- defs.append('WITH_CYCLES_LOGGING')
-
- if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
-
- if env['WITH_BF_PYTHON']:
- incs.append('#/source/blender/python')
- defs.append('WITH_PYTHON')
- if env['BF_DEBUG']:
- defs.append('_DEBUG')
-
- if env['WITH_BF_FREESTYLE']:
- incs.append('#/source/blender/freestyle')
- defs.append('WITH_FREESTYLE')
-
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
- incs.append('#/intern/utfconv')
-
- env.Append(CPPDEFINES=defs)
- env.Append(CPPPATH=incs)
- obj = [env.Object(root_build_dir+'source/creator/creator/creator', ['#source/creator/creator.c'])]
-
- return obj
-
-## TODO: see if this can be made in an emitter
-def buildinfo(lenv, build_type):
- """
- Generate a buildinfo object
- """
- import subprocess
-
- build_date = time.strftime ("%Y-%m-%d")
- build_time = time.strftime ("%H:%M:%S")
-
- if os.path.isdir(os.path.abspath('.git')):
- try:
- build_commit_timestamp = btools.get_command_output(args=['git', 'log', '-1', '--format=%ct']).strip()
- except OSError:
- build_commit_timestamp = None
- if not build_commit_timestamp:
- # Git command not found
- build_hash = 'unknown'
- build_commit_timestamp = '0'
- build_branch = 'unknown'
- else:
- no_upstream = False
-
- try :
- build_hash = btools.get_command_output(['git', 'rev-parse', '--short', '@{u}'], stderr=subprocess.STDOUT).strip()
- except subprocess.CalledProcessError:
- # assume branch has no upstream configured
- build_hash = btools.get_command_output(['git', 'rev-parse', '--short', 'HEAD']).strip()
- no_upstream = True
-
- build_branch = btools.get_command_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
-
- if build_branch == 'HEAD':
- master_check = btools.get_command_output(['git', 'branch', '--list', 'master', '--contains', build_hash]).strip()
- if master_check == 'master':
- build_branch = 'master'
- else:
- head_hash = btools.get_command_output(['git', 'rev-parse', 'HEAD']).strip()
- tag_hashes = btools.get_command_output(['git', 'show-ref', '--tags', '-d'])
- if tag_hashes.find(head_hash) != -1:
- build_branch = 'master'
-
- if not no_upstream:
- older_commits = btools.get_command_output(['git', 'log', '--oneline', 'HEAD..@{u}']).strip()
- if older_commits:
- build_hash = btools.get_command_output(['git', 'rev-parse', '--short', 'HEAD']).strip()
-
- # ## Check for local modifications
- has_local_changes = False
-
- # Update GIT index before getting dirty files
- os.system('git update-index -q --refresh')
- changed_files = btools.get_command_output(['git', 'diff-index', '--name-only', 'HEAD', '--']).strip()
-
- if changed_files:
- has_local_changes = True
- elif no_upstream == False:
- unpushed_log = btools.get_command_output(['git', 'log', '--oneline', '@{u}..']).strip()
- has_local_changes = unpushed_log != ''
-
- if build_branch.startswith('blender-v'):
- build_branch = 'master'
-
- if has_local_changes:
- build_branch += ' (modified)'
- else:
- build_hash = 'unknown'
- build_commit_timestamp = '0'
- build_branch = 'unknown'
-
- if lenv['BF_DEBUG']:
- build_type = "Debug"
- build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['BF_DEBUG_CCFLAGS'] + lenv['CPPFLAGS'])
- build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['CPPFLAGS'])
- else:
- build_type = "Release"
- build_cflags = ' '.join(lenv['CFLAGS'] + lenv['CCFLAGS'] + lenv['REL_CFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
- build_cxxflags = ' '.join(lenv['CCFLAGS'] + lenv['CXXFLAGS'] + lenv['REL_CXXFLAGS'] + lenv['REL_CCFLAGS'] + lenv['CPPFLAGS'])
-
- build_linkflags = ' '.join(lenv['PLATFORM_LINKFLAGS'])
-
- obj = []
- if lenv['BF_BUILDINFO']:
- lenv.Append (CPPDEFINES = ['BUILD_TIME=\\"%s\\"'%(build_time),
- 'BUILD_DATE=\\"%s\\"'%(build_date),
- 'BUILD_TYPE=\\"%s\\"'%(build_type),
- 'BUILD_HASH=\\"%s\\"'%(build_hash),
- 'BUILD_COMMIT_TIMESTAMP=%s'%(build_commit_timestamp),
- 'BUILD_BRANCH=\\"%s\\"'%(build_branch),
- 'WITH_BUILDINFO',
- 'BUILD_PLATFORM=\\"%s:%s\\"'%(platform.system(), platform.architecture()[0]),
- 'BUILD_CFLAGS=\\"%s\\"'%(build_cflags),
- 'BUILD_CXXFLAGS=\\"%s\\"'%(build_cxxflags),
- 'BUILD_LINKFLAGS=\\"%s\\"'%(build_linkflags),
- 'BUILD_SYSTEM=\\"SCons\\"'
- ])
-
- lenv.Append (CPPPATH = [root_build_dir+'source/blender/blenkernel'])
-
- obj = [lenv.Object (root_build_dir+'source/creator/%s_buildinfo'%build_type, ['#source/creator/buildinfo.c'])]
-
- return obj
-
-##### END LIB STUFF ############
-
-##### ACTION STUFF #############
-
-def my_print_cmd_line(self, s, target, source, env):
- sys.stdout.write(' ' * 70 + '\r')
- sys.stdout.flush()
- sys.stdout.write(s + "\r")
- sys.stdout.flush()
-
-def my_compile_print(target, source, env):
- a = '%s' % (source[0])
- d, f = os.path.split(a)
- return bc.OKBLUE + "Compiling" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
-
-def my_moc_print(target, source, env):
- a = '%s' % (source[0])
- d, f = os.path.split(a)
- return bc.OKBLUE + "Creating MOC" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
-
-def my_linking_print(target, source, env):
- t = '%s' % (target[0])
- d, f = os.path.split(t)
- return bc.OKBLUE + "Linking library" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
-
-def my_program_print(target, source, env):
- t = '%s' % (target[0])
- d, f = os.path.split(t)
- return bc.OKBLUE + "Linking program" + bc.ENDC + " ==> '" + bc.OKGREEN + ("%s" % f) + bc.ENDC + "'"
-
-def msvc_hack(env):
- static_lib = SCons.Tool.createStaticLibBuilder(env)
- program = SCons.Tool.createProgBuilder(env)
-
- env['BUILDERS']['Library'] = static_lib
- env['BUILDERS']['StaticLibrary'] = static_lib
- env['BUILDERS']['Program'] = program
-
-def set_quiet_output(env):
- mycaction = Action("$CCCOM", strfunction=my_compile_print)
- myshcaction = Action("$SHCCCOM", strfunction=my_compile_print)
- mycppaction = Action("$CXXCOM", strfunction=my_compile_print)
- myshcppaction = Action("$SHCXXCOM", strfunction=my_compile_print)
- mylibaction = Action("$ARCOM", strfunction=my_linking_print)
- mylinkaction = Action("$LINKCOM", strfunction=my_program_print)
-
- static_ob, shared_ob = SCons.Tool.createObjBuilders(env)
- static_ob.add_action('.c', mycaction)
- static_ob.add_action('.cpp', mycppaction)
- static_ob.add_action('.cc', mycppaction)
- shared_ob.add_action('.c', myshcaction)
- shared_ob.add_action('.cc', myshcppaction)
-
- static_lib = SCons.Builder.Builder(action = mylibaction,
- emitter = '$LIBEMITTER',
- prefix = '$LIBPREFIX',
- suffix = '$LIBSUFFIX',
- src_suffix = '$OBJSUFFIX',
- src_builder = 'StaticObject')
-
- program = SCons.Builder.Builder(action = mylinkaction,
- emitter = '$PROGEMITTER',
- prefix = '$PROGPREFIX',
- suffix = '$PROGSUFFIX',
- src_suffix = '$OBJSUFFIX',
- src_builder = 'Object',
- target_scanner = SCons.Defaults.ProgScan)
-
- env['BUILDERS']['Object'] = static_ob
- env['BUILDERS']['StaticObject'] = static_ob
- env['BUILDERS']['StaticLibrary'] = static_lib
- env['BUILDERS']['Library'] = static_lib
- env['BUILDERS']['Program'] = program
- if env['BF_LINE_OVERWRITE']:
- SCons.Action._ActionAction.print_cmd_line = my_print_cmd_line
-
-def untar_pybundle(from_tar,to_dir,exclude_re):
- tar= tarfile.open(from_tar, mode='r')
- exclude_re= list(exclude_re) #single re object or list of re objects
- debug= 0 #list files instead of unpacking
- good= []
- if debug: print '\nFiles not being unpacked:\n'
- for name in tar.getnames():
- is_bad= 0
- for r in exclude_re:
- if r.match(name):
- is_bad=1
- if debug: print name
- break
- if not is_bad:
- good.append(tar.getmember(name))
- if debug:
- print '\nFiles being unpacked:\n'
- for g in good:
- print g
- else:
- tar.extractall(to_dir, good)
-
-def my_winpybundle_print(target, source, env):
- pass
-
-def WinPyBundle(target=None, source=None, env=None):
- import re
- py_tar = env.subst(env['LCGDIR']).lstrip("#")
- if env['BF_DEBUG']:
- py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_d.tar.gz'
- else:
- py_tar+= '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '.tar.gz'
-
- py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
- py_target = os.path.join(py_target, VERSION, 'python')
- def printexception(func,path,ex):
- if os.path.exists(path): #do not report if path does not exist. eg on a fresh build.
- print str(func) + ' failed on ' + str(path)
- print "Trying to remove existing py bundle."
- shutil.rmtree(py_target, False, printexception)
- exclude_re=[re.compile('.*/test'),
- re.compile('^test'),
- re.compile('^distutils'),
- re.compile('^idlelib'),
- re.compile('^lib2to3'),
- re.compile('^tkinter'),
- re.compile('^_tkinter_d.pyd'),
- re.compile('^turtledemo'),
- re.compile('^turtle.py'),
- ]
-
- print "Unpacking '" + py_tar + "' to '" + py_target + "'"
- untar_pybundle(py_tar,py_target,exclude_re)
-
- # -------------
- # Extract Numpy
- if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
- py_tar = env.subst(env['LCGDIR']).lstrip("#")
- py_tar += '/release/python' + env['BF_PYTHON_VERSION'].replace('.','') + '_numpy_1.9.tar.gz'
-
- py_target = env.subst(env['BF_INSTALLDIR']).lstrip("#")
- py_target = os.path.join(py_target, VERSION, 'python', 'lib', 'site-packages')
- # rmtree handled above
- # files are cleaned up in their archive
- exclude_re = []
- print("Unpacking '" + py_tar + "' to '" + py_target + "'")
- untar_pybundle(py_tar, py_target, exclude_re)
-
- # --------------------
- # Copy 'site-packages'
- py_dir = env.subst(env['LCGDIR']).lstrip("#")
- py_dir += '/release/site-packages'
- # grr, we have to do one by one because the dir exists
- for f in os.listdir(py_dir):
- if f == '.svn':
- continue
- fn_src = os.path.join(py_dir, f)
- fn_dst = os.path.join(py_target, f)
-
- shutil.rmtree(fn_dst, False, printexception)
- shutil.copytree(fn_src, fn_dst)
-
-
-
-def my_appit_print(target, source, env):
- a = '%s' % (target[0])
- d, f = os.path.split(a)
- return "making bundle for " + f
-
-def AppIt(target=None, source=None, env=None):
- import shutil
- import commands
- import os.path
-
-
- a = '%s' % (target[0])
- builddir, b = os.path.split(a)
- libdir = env['LCGDIR'][1:]
- osxarch = env['MACOSX_ARCHITECTURE']
- installdir = env['BF_INSTALLDIR']
- print("compiled architecture: %s"%(osxarch))
- print("Installing to %s"%(installdir))
- # TODO, use tar.
- python_zip = 'python_' + osxarch + '.zip' # set specific python_arch.zip
- if env['WITH_OSX_STATICPYTHON']:
- print("unzipping to app-bundle: %s"%(python_zip))
- else:
- print("dynamic build - make sure to have python3.x-framework installed")
- bldroot = env.Dir('.').abspath
- binary = env['BINARYKIND']
-
- sourcedir = bldroot + '/release/darwin/%s.app' % binary
- sourceinfo = bldroot + "/release/darwin/%s.app/Contents/Info.plist"%binary
- targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
- cmd = installdir + '/' +'%s.app'%binary
-
- if os.path.isdir(cmd):
- shutil.rmtree(cmd)
- shutil.copytree(sourcedir, cmd)
- cmd = "cat %s | sed s/\$\{MACOSX_BUNDLE_SHORT_VERSION_STRING\}/%s/ | "%(sourceinfo,VERSION)
- cmd += "sed s/\$\{MACOSX_BUNDLE_LONG_VERSION_STRING\}/%s,\ %s/g > %s"%(VERSION,time.strftime("%Y-%b-%d"),targetinfo)
- commands.getoutput(cmd)
- cmd = 'cp %s/%s %s/%s.app/Contents/MacOS/%s'%(builddir, binary,installdir, binary, binary)
- commands.getoutput(cmd)
- cmd = 'mkdir %s/%s.app/Contents/Resources/%s/'%(installdir, binary, VERSION)
- commands.getoutput(cmd)
- cmd = installdir + '/%s.app/Contents/MacOS/%s'%(binary,VERSION)
-
- # blenderplayer doesn't need all the files
- if binary == 'blender':
- cmd = 'mkdir %s/%s.app/Contents/Resources/%s/datafiles'%(installdir, binary, VERSION)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/Resources/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
- commands.getoutput(cmd)
- mo_dir = os.path.join(builddir[:-4], "locale")
- for f in os.listdir(mo_dir):
- cmd = 'ditto %s/%s %s/%s.app/Contents/Resources/%s/datafiles/locale/%s/LC_MESSAGES/blender.mo'%(mo_dir, f, installdir, binary, VERSION, f[:-3])
- commands.getoutput(cmd)
- cmd = 'cp %s/release/datafiles/locale/languages %s/%s.app/Contents/Resources/%s/datafiles/locale/'%(bldroot, installdir, binary, VERSION)
- commands.getoutput(cmd)
-
- if env['WITH_BF_OCIO']:
- cmd = 'cp -R %s/release/datafiles/colormanagement %s/%s.app/Contents/Resources/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
- commands.getoutput(cmd)
-
- cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/Resources/%s/'%(bldroot,installdir,binary,VERSION)
- commands.getoutput(cmd)
-
- if VERSION_RELEASE_CYCLE == "release":
- cmd = 'rm -rf %s/%s.app/Contents/Resources/%s/scripts/addons_contrib'%(installdir,binary,VERSION)
- commands.getoutput(cmd)
-
- if env['WITH_BF_CYCLES']:
- croot = '%s/intern/cycles' % (bldroot)
- cinstalldir = '%s/%s.app/Contents/Resources/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
-
- cmd = 'mkdir %s' % (cinstalldir)
- commands.getoutput(cmd)
- cmd = 'mkdir %s/kernel' % (cinstalldir)
- commands.getoutput(cmd)
- cmd = 'mkdir %s/lib' % (cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/kernel/svm %s/kernel/closure %s/kernel/geom %s/kernel/split %s/kernel/kernels %s/util/util_color.h %s/util/util_half.h %s/util/util_math.h %s/util/util_math_fast.h %s/util/util_transform.h %s/util/util_types.h %s/util/util_atomic.h %s/kernel/' % (croot, croot, croot, croot, croot, croot, croot, croot, croot, croot, croot, croot, cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
- commands.getoutput(cmd)
-
- if env['WITH_BF_CYCLES_OSL']:
- cmd = 'mkdir %s/shader' % (cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/kernel/shaders/*.h %s/shader' % (croot, cinstalldir)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/../intern/cycles/kernel/shaders/*.oso %s/shader' % (builddir, cinstalldir)
- commands.getoutput(cmd)
-
- if env['WITH_OSX_STATICPYTHON']:
- cmd = 'mkdir %s/%s.app/Contents/Resources/%s/python/'%(installdir,binary, VERSION)
- commands.getoutput(cmd)
- cmd = 'unzip -q %s/release/%s -d %s/%s.app/Contents/Resources/%s/python/'%(libdir,python_zip,installdir,binary,VERSION)
- commands.getoutput(cmd)
- cmd = 'cp -R %s/release/site-packages/ %s/%s.app/Contents/Resources/%s/python/lib/python%s/site-packages/'%(libdir,installdir,binary,VERSION,env['BF_PYTHON_VERSION'])
- commands.getoutput(cmd)
-
- cmd = 'chmod +x %s/%s.app/Contents/MacOS/%s'%(installdir,binary, binary)
- commands.getoutput(cmd)
- cmd = 'find %s/%s.app -name .svn -prune -exec rm -rf {} \;'%(installdir, binary)
- commands.getoutput(cmd)
- cmd = 'find %s/%s.app -name .DS_Store -exec rm -rf {} \;'%(installdir, binary)
- commands.getoutput(cmd)
- cmd = 'find %s/%s.app -name __MACOSX -exec rm -rf {} \;'%(installdir, binary)
- commands.getoutput(cmd)
- cmd = 'SetFile -d "%s)" -m "%s)" %s/%s.app'%(time.strftime("%m/%d/%Y %H:%M"),time.strftime("%m/%d/%Y %H:%M"),installdir,binary) # give the bundles actual creation/modification date
- commands.getoutput(cmd)
- if env['WITH_BF_OPENMP']:
- if env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6.1': # for correct errorhandling with gcc >= 4.6.1 we need the gcc.dylib and gomp.dylib to link, thus distribute in app-bundle
- print "Bundling libgcc and libgomp"
- instname = env['BF_CXX']
- cmd = 'ditto --arch %s %s/lib/libgcc_s.1.dylib %s/%s.app/Contents/Resources/lib/'%(osxarch, instname, installdir, binary) # copy libgcc
- commands.getoutput(cmd)
- cmd = 'install_name_tool -id @executable_path/../Resources/lib/libgcc_s.1.dylib %s/%s.app/Contents/Resources/lib/libgcc_s.1.dylib'%(installdir, binary) # change id of libgcc
- commands.getoutput(cmd)
- cmd = 'ditto --arch %s %s/lib/libgomp.1.dylib %s/%s.app/Contents/Resources/lib/'%(osxarch, instname, installdir, binary) # copy libgomp
- commands.getoutput(cmd)
- cmd = 'install_name_tool -id @executable_path/../Resources/lib/libgomp.1.dylib %s/%s.app/Contents/Resources/lib/libgomp.1.dylib'%(installdir, binary) # change id of libgomp
- commands.getoutput(cmd)
- cmd = 'install_name_tool -change %s/lib/libgcc_s.1.dylib @executable_path/../Resources/lib/libgcc_s.1.dylib %s/%s.app/Contents/Resources/lib/libgomp.1.dylib'%(instname, installdir, binary) # change ref to libgcc
- commands.getoutput(cmd)
- cmd = 'install_name_tool -change %s/lib/libgcc_s.1.dylib @executable_path/../Resources/lib/libgcc_s.1.dylib %s/%s.app/Contents/MacOS/%s'%(instname, installdir, binary, binary) # change ref to libgcc ( blender )
- commands.getoutput(cmd)
- cmd = 'install_name_tool -change %s/lib/libgomp.1.dylib @executable_path/../Resources/lib/libgomp.1.dylib %s/%s.app/Contents/MacOS/%s'%(instname, installdir, binary, binary) # change ref to libgomp ( blender )
- commands.getoutput(cmd)
- if env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.4':
- print "Bundling libiomp5"
- instname = env['LCGDIR'][1:] # made libiomp5 part of blender libs
- cmd = 'ditto --arch %s %s/openmp/lib/libiomp5.dylib %s/%s.app/Contents/Resources/lib/'%(osxarch, instname, installdir, binary) # copy libiomp5
- commands.getoutput(cmd)
- cmd = 'cp %s/openmp/LICENSE.txt %s/LICENSE-libiomp5.txt'%(instname, installdir) # copy libiomp5 license
- commands.getoutput(cmd)
-
-# extract copy system python, be sure to update other build systems
-# when making changes to the files that are copied.
-def my_unixpybundle_print(target, source, env):
- pass
-
-def UnixPyBundle(target=None, source=None, env=None):
- # Any Unix except osx
- #-- VERSION/python/lib/python3.1
-
- import commands
-
- def run(cmd):
- print 'Install command:', cmd
- commands.getoutput(cmd)
-
- dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
-
- lib = env['BF_PYTHON_LIBPATH'].split(os.sep)[-1]
- target_lib = "lib64" if lib == "lib64" else "lib"
-
- py_src = env.subst( env['BF_PYTHON_LIBPATH'] + '/python'+env['BF_PYTHON_VERSION'] )
- py_target = env.subst( dir + '/python/' + target_lib + '/python'+env['BF_PYTHON_VERSION'] )
- py_target_bin = env.subst(dir + '/python/bin')
-
- # This is a bit weak, but dont install if its been installed before, makes rebuilds quite slow.
- if os.path.exists(py_target):
- print 'Using existing python from:'
- print '\t"%s"' % py_target
- print '\t(skipping copy)\n'
- return
-
- # Copied from source/creator/CMakeLists.txt, keep in sync.
- print 'Install python from:'
- print '\t"%s" into...' % py_src
- print '\t"%s"\n' % py_target
-
- run("rm -rf '%s'" % py_target)
- try:
- os.makedirs(os.path.dirname(py_target)) # the final part is copied
- except:
- pass
-
- # install the executable
- run("rm -rf '%s'" % py_target_bin)
- os.makedirs(py_target_bin)
- run("cp '%s' '%s'" % (env.subst(env['BF_PYTHON_BINARY']), py_target_bin))
-
- run("cp -R '%s' '%s'" % (py_src, os.path.dirname(py_target)))
- run("rm -rf '%s/distutils'" % py_target)
- run("rm -rf '%s/lib2to3'" % py_target)
- run("rm -rf '%s/config'" % py_target)
-
- for f in os.listdir(py_target):
- if f.startswith("config-"):
- run("rm -rf '%s/%s'" % (py_target, f))
-
- run("rm -rf '%s/site-packages'" % py_target)
- run("mkdir '%s/site-packages'" % py_target) # python needs it.'
- run("rm -rf '%s/idlelib'" % py_target)
- run("rm -rf '%s/tkinter'" % py_target)
- run("rm -rf '%s/turtledemo'" % py_target)
- run("rm -r '%s/turtle.py'" % py_target)
- run("rm -f '%s/lib-dynload/_tkinter.so'" % py_target)
-
- if env['WITH_BF_PYTHON_INSTALL_NUMPY']:
- numpy_src = py_src + "/site-packages/numpy"
- numpy_target = py_target + "/site-packages/numpy"
-
- if os.path.exists(numpy_src):
- print 'Install numpy from:'
- print '\t"%s" into...' % numpy_src
- print '\t"%s"\n' % numpy_target
-
- run("cp -R '%s' '%s'" % (numpy_src, os.path.dirname(numpy_target)))
- run("rm -rf '%s/distutils'" % numpy_target)
- run("rm -rf '%s/oldnumeric'" % numpy_target)
- run("rm -rf '%s/doc'" % numpy_target)
- run("rm -rf '%s/tests'" % numpy_target)
- run("rm -rf '%s/f2py'" % numpy_target)
- run("find '%s' -type d -name 'include' -prune -exec rm -rf {} ';'" % numpy_target)
- run("find '%s' -type d -name '*.h' -prune -exec rm -rf {} ';'" % numpy_target)
- run("find '%s' -type d -name '*.a' -prune -exec rm -rf {} ';'" % numpy_target)
- else:
- print 'Failed to find numpy at %s, skipping copying' % numpy_src
- del numpy_src, numpy_target
-
- if env['WITH_BF_PYTHON_INSTALL_REQUESTS']:
- requests_src = py_src + "/site-packages/requests"
- requests_target = py_target + "/site-packages/requests"
- if os.path.exists(requests_src):
- run("cp -R '%s' '%s'" % (requests_src, os.path.dirname(requests_target)))
- run("find '%s' -type d -name '*.pem -prune -exec rm -rf {} ';'" % requests_target)
- else:
- print('Failed to find requests at %s, skipping copying' % requests_src)
- del requests_src, requests_target
-
- run("find '%s' -type d -name 'test' -prune -exec rm -rf {} ';'" % py_target)
- run("find '%s' -type d -name '__pycache__' -exec rm -rf {} ';'" % py_target)
- run("find '%s' -name '*.py[co]' -exec rm -rf {} ';'" % py_target)
- run("find '%s' -name '*.so' -exec strip -s {} ';'" % py_target)
-
-#### END ACTION STUFF #########
-
-def bsc(env, target, source):
-
- bd = os.path.dirname(target[0].abspath)
- bscfile = '\"'+target[0].abspath+'\"'
- bscpathcollect = '\"'+bd + os.sep + '*.sbr\"'
- bscpathtmp = '\"'+bd + os.sep + 'bscmake.tmp\"'
-
- os.system('dir /b/s '+bscpathcollect+' >'+bscpathtmp)
-
- myfile = open(bscpathtmp[1:-1], 'r')
- lines = myfile.readlines()
- myfile.close()
-
- newfile = open(bscpathtmp[1:-1], 'w')
- for l in lines:
- newfile.write('\"'+l[:-1]+'\"\n')
- newfile.close()
-
- os.system('bscmake /nologo /n /o'+bscfile+' @'+bscpathtmp)
- os.system('del '+bscpathtmp)
-
-class BlenderEnvironment(SConsEnvironment):
-
- PyBundleActionAdded = False
-
- def BlenderRes(self=None, libname=None, source=None, libtype=['core'], priority=[100]):
- global libs
- if not self or not libname or not source:
- print bc.FAIL+'Cannot continue. Missing argument for BlenderRes '+libname+bc.ENDC
- self.Exit()
- if self['OURPLATFORM'] not in ('win32-vc','win32-mingw','linuxcross', 'win64-vc', 'win64-mingw'):
- print bc.FAIL+'BlenderRes is for windows only!'+bc.END
- self.Exit()
-
- print bc.HEADER+'Configuring resource '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC
- lenv = self.Clone()
- if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- res = lenv.RES('#'+root_build_dir+'lib/'+libname, source)
- else:
- res = lenv.RES(root_build_dir+'lib/'+libname, source)
-
-
- SConsEnvironment.Default(self, res)
- resources.append(res)
-
- def BlenderLib(self=None, libname=None, sources=None, includes=[], defines=[], libtype='common', priority = 100, compileflags=None, cc_compileflags=None, cxx_compileflags=None, cc_compilerchange=None, cxx_compilerchange=None):
- global vcp
-
- # sanity check
- # run once in a while to check we dont have duplicates
- if 0:
- for name, dirs in (("source", sources), ("include", includes)):
- files_clean = [os.path.normpath(f) for f in dirs]
- files_clean_set = set(files_clean)
- if len(files_clean) != len(files_clean_set):
- for f in sorted(files_clean_set):
- if f != '.' and files_clean.count(f) > 1:
- raise Exception("Found duplicate %s %r" % (name, f))
- del name, dirs, files_clean, files_clean_set, f
- # end sanity check
-
- if not self or not libname or not sources:
- print bc.FAIL+'Cannot continue. Missing argument for BuildBlenderLib '+libname+bc.ENDC
- self.Exit()
-
- def list_substring(quickie, libname):
- for q in quickie:
- if q in libname:
- return True
- return False
-
- if list_substring(quickie, libname) or len(quickie)==0:
- if list_substring(quickdebug, libname):
- print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname +bc.ENDC+bc.OKBLUE+ " (debug mode)" + bc.ENDC
- else:
- print bc.HEADER+'Configuring library '+bc.ENDC+bc.OKGREEN+libname + bc.ENDC
- lenv = self.Clone()
- lenv.Append(CPPPATH=includes)
- lenv.Append(CPPDEFINES=defines)
- if lenv['BF_DEBUG'] or (libname in quickdebug):
- lenv.Append(CFLAGS = lenv['BF_DEBUG_CFLAGS'])
- lenv.Append(CCFLAGS = lenv['BF_DEBUG_CCFLAGS'])
- lenv.Append(CXXFLAGS = lenv['BF_DEBUG_CXXFLAGS'])
- else:
- lenv.Append(CFLAGS = lenv['REL_CFLAGS'])
- lenv.Append(CCFLAGS = lenv['REL_CCFLAGS'])
- lenv.Append(CXXFLAGS = lenv['REL_CXXFLAGS'])
- if lenv['BF_PROFILE']:
- lenv.Append(CFLAGS = lenv['BF_PROFILE_CFLAGS'])
- lenv.Append(CCFLAGS = lenv['BF_PROFILE_CCFLAGS'])
- lenv.Append(CXXFLAGS = lenv['BF_PROFILE_CXXFLAGS'])
- if compileflags:
- lenv.Replace(CFLAGS = compileflags)
- if cc_compileflags:
- lenv.Replace(CCFLAGS = cc_compileflags)
- if cxx_compileflags:
- lenv.Replace(CXXFLAGS = cxx_compileflags)
- if cc_compilerchange:
- lenv.Replace(CC = cc_compilerchange)
- if cxx_compilerchange:
- lenv.Replace(CXX = cxx_compilerchange)
- lenv.Append(CFLAGS = lenv['C_WARN'])
- lenv.Append(CCFLAGS = lenv['CC_WARN'])
- lenv.Append(CXXFLAGS = lenv['CXX_WARN'])
-
- if lenv['OURPLATFORM'] == 'win64-vc':
- lenv.Append(LINKFLAGS = ['/MACHINE:X64'])
-
- if lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- if lenv['BF_DEBUG']:
- lenv.Append(CCFLAGS = ['/MTd'])
- else:
- lenv.Append(CCFLAGS = ['/MT'])
-
- targetdir = root_build_dir+'lib/' + libname
- if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- targetdir = '#'+targetdir
- lib = lenv.Library(target= targetdir, source=sources)
- SConsEnvironment.Default(self, lib) # we add to default target, because this way we get some kind of progress info during build
- if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- #if targetdir[0] == '#':
- # targetdir = targetdir[1:-1]
- print "! ",targetdir+ '.vcproj' # + self['MSVSPROJECTSUFFIX']
- vcproject = self.MSVSProject(target = targetdir + '.vcproj', # + self['MSVSPROJECTSUFFIX'],
- srcs = sources,
- buildtarget = lib,
- variant = 'Release',
- auto_build_solution=0)
- vcp.append(vcproject)
- SConsEnvironment.Default(self, vcproject)
- else:
- print bc.WARNING+'Not building '+bc.ENDC+bc.OKGREEN+libname+bc.ENDC+' for '+bc.OKBLUE+'BF_QUICK'+bc.ENDC
- # note: libs is a global
- add_lib_to_dict(self, libs, libtype, libname, priority)
-
- def BlenderProg(self=None, builddir=None, progname=None, sources=None, libs=None, libpath=None, binarykind=''):
- global vcp
- print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
- lenv = self.Clone()
- lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
- lenv.Append(LINKFLAGS = lenv['BF_PROGRAM_LINKFLAGS'])
- if lenv['OURPLATFORM'] in ('win32-mingw', 'win64-mingw', 'linuxcross', 'cygwin', 'linux'):
- lenv.Replace(LINK = '$CXX')
- if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
- if lenv['BF_DEBUG']:
- lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb','/NODEFAULTLIB:libcmt'])
- if lenv['OURPLATFORM']=='linux':
- if lenv['WITH_BF_PYTHON']:
- lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
- if lenv['OURPLATFORM']=='sunos5':
- if lenv['WITH_BF_PYTHON']:
- lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
- if lenv['CXX'].endswith('CC'):
- lenv.Replace(LINK = '$CXX')
- if lenv['OURPLATFORM']=='darwin':
- if lenv['WITH_BF_PYTHON']:
- lenv.Append(LINKFLAGS = lenv['BF_PYTHON_LINKFLAGS'])
- lenv.Append(LINKFLAGS = lenv['BF_OPENGL_LINKFLAGS'])
- if lenv['BF_PROFILE']:
- lenv.Append(LINKFLAGS = lenv['BF_PROFILE_LINKFLAGS'])
- if root_build_dir[0]==os.sep or root_build_dir[1]==':':
- lenv.Append(LIBPATH=root_build_dir + '/lib')
- lenv.Append(LIBPATH=libpath)
- lenv.Append(LIBS=libs)
- if lenv['WITH_BF_QUICKTIME']:
- lenv.Append(LIBS = lenv['BF_QUICKTIME_LIB'])
- lenv.Append(LIBPATH = lenv['BF_QUICKTIME_LIBPATH'])
- prog = lenv.Program(target=builddir+'bin/'+progname, source=sources)
- if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc') and lenv['BF_BSC']:
- f = lenv.File(progname + '.bsc', builddir)
- brs = lenv.Command(f, prog, [bsc])
- SConsEnvironment.Default(self, brs)
- SConsEnvironment.Default(self, prog)
- if self['BF_MSVS'] and self['OURPLATFORM'] in ('win32-vc', 'win64-vc') and progname == 'blender':
- print "! ",builddir + "/" + progname + '.sln'
- sln = self.MSVSProject(target = builddir + "/" + progname + '.sln',
- projects= vcp,
- variant = 'Release')
- SConsEnvironment.Default(self, sln)
- program_list.append(prog)
- if lenv['OURPLATFORM']=='darwin':
- lenv['BINARYKIND'] = binarykind
- lenv.AddPostAction(prog,Action(AppIt,strfunction=my_appit_print))
- elif os.sep == '/' and lenv['OURPLATFORM'] != 'linuxcross': # any unix (except cross-compilation)
- if lenv['WITH_BF_PYTHON']:
- if (not lenv['WITHOUT_BF_INSTALL'] and
- not lenv['WITHOUT_BF_PYTHON_INSTALL'] and
- not lenv['WITHOUT_BF_PYTHON_UNPACK'] and
- not BlenderEnvironment.PyBundleActionAdded):
- lenv.AddPostAction(prog,Action(UnixPyBundle,strfunction=my_unixpybundle_print))
- BlenderEnvironment.PyBundleActionAdded = True
- elif lenv['OURPLATFORM'].startswith('win') or lenv['OURPLATFORM'] == 'linuxcross': # windows or cross-compilation
- if lenv['WITH_BF_PYTHON']:
- if (not lenv['WITHOUT_BF_PYTHON_INSTALL'] and
- not lenv['WITHOUT_BF_PYTHON_UNPACK'] and
- not BlenderEnvironment.PyBundleActionAdded):
- lenv.AddPostAction(prog,Action(WinPyBundle,strfunction=my_winpybundle_print))
- BlenderEnvironment.PyBundleActionAdded = True
- return prog
-
- def Glob(lenv, pattern):
- path = string.replace(GetBuildPath(lenv,'SConscript'),'SConscript', '')
- files = []
- for i in glob.glob(path + pattern):
- files.append(string.replace(i, path, ''))
- return files
diff --git a/build_files/scons/tools/__init__.py b/build_files/scons/tools/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/build_files/scons/tools/__init__.py
+++ /dev/null
diff --git a/build_files/scons/tools/bcolors.py b/build_files/scons/tools/bcolors.py
deleted file mode 100644
index b01bb781524..00000000000
--- a/build_files/scons/tools/bcolors.py
+++ /dev/null
@@ -1,16 +0,0 @@
-class bcolors:
- HEADER = '\033[95m'
- OKBLUE = '\033[94m'
- OKGREEN = '\033[92m'
- WARNING = '\033[93m'
- FAIL = '\033[91m'
- ENDC = '\033[0m'
-
- def disable(self):
- self.HEADER = ''
- self.OKBLUE = ''
- self.OKGREEN = ''
- self.WARNING = ''
- self.FAIL = ''
- self.ENDC = ''
-
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
deleted file mode 100644
index 0b85940d024..00000000000
--- a/build_files/scons/tools/btools.py
+++ /dev/null
@@ -1,918 +0,0 @@
-import os
-import os.path
-import SCons.Options
-
-import SCons.Variables
-try:
- import subprocess
-except ImportError:
- pass
-import string
-import shutil
-import sys
-
-Variables = SCons.Variables
-BoolVariable = SCons.Variables.BoolVariable
-
-def get_command_output(*popenargs, **kwargs):
- if hasattr(subprocess, "check_output"):
- return subprocess.check_output(*popenargs, **kwargs)
- if 'stdout' in kwargs:
- raise ValueError('stdout argument not allowed, it will be overridden.')
- process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
- output, unused_err = process.communicate()
- retcode = process.poll()
- if retcode:
- cmd = kwargs.get("args")
- if cmd is None:
- cmd = popenargs[0]
- raise subprocess.CalledProcessError(retcode, cmd)
- return output
-
-def get_version():
- import re
-
- fname = os.path.join(os.path.dirname(__file__), "..", "..", "..", "source", "blender", "blenkernel", "BKE_blender.h")
- ver_base = None
- ver_char = None
- ver_cycle = None
-
- re_ver = re.compile("^#\s*define\s+BLENDER_VERSION\s+([0-9]+)")
- re_ver_char = re.compile("^#\s*define\s+BLENDER_VERSION_CHAR\s*(\S*)") # optional arg
- re_ver_cycle = re.compile("^#\s*define\s+BLENDER_VERSION_CYCLE\s*(\S*)") # optional arg
-
- for l in open(fname, "r"):
- match = re_ver.match(l)
- if match:
- ver = int(match.group(1))
- ver_base = "%d.%d" % (ver / 100, ver % 100)
-
- match = re_ver_char.match(l)
- if match:
- ver_char = match.group(1)
- if ver_char == "BLENDER_CHAR_VERSION":
- ver_char = ""
-
- match = re_ver_cycle.match(l)
- if match:
- ver_cycle = match.group(1)
- if ver_cycle == "BLENDER_CYCLE_VERSION":
- ver_cycle = ""
-
- if (ver_base is not None) and (ver_char is not None) and (ver_cycle is not None):
- # eg '2.56a-beta'
- if ver_cycle != "release":
- ver_display = "%s%s-%s" % (ver_base, ver_char, ver_cycle)
- else:
- ver_display = "%s%s" % (ver_base, ver_char)
-
- return ver_base, ver_display, ver_cycle
-
- raise Exception("%s: missing version string" % fname)
-
-def get_hash():
- try:
- build_hash = get_command_output(['git', 'rev-parse', '--short', 'HEAD']).strip()
- except OSError:
- build_hash = None
- print("WARNING: could not use git to retrieve current Blender repository hash...")
- except subprocess.CalledProcessError as e:
- build_hash = None
- print("WARNING: git errored while retrieving current Blender repository hash (%d)..." % e.returncode)
- if build_hash == '' or build_hash == None:
- build_hash = 'UNKNOWN'
-
- return build_hash
-
-
-def checkEndian():
- return sys.byteorder
-
-
-# This is used in creating the local config directories
-VERSION, VERSION_DISPLAY, VERSION_RELEASE_CYCLE = get_version()
-HASH = get_hash()
-ENDIAN = checkEndian()
-
-
-def print_arguments(args, bc):
- if len(args):
- for k,v in args.iteritems():
- if type(v)==list:
- v = ' '.join(v)
- print '\t'+bc.OKBLUE+k+bc.ENDC+' = '+bc.OKGREEN + v + bc.ENDC
- else:
- print '\t'+bc.WARNING+'No command-line arguments given'+bc.ENDC
-
-def validate_arguments(args, bc):
- opts_list = [
- 'WITH_BF_FREESTYLE', 'WITH_BF_PYTHON', 'WITH_BF_PYTHON_SAFETY', 'WITH_BF_PYTHON_SECURITY', 'BF_PYTHON', 'BF_PYTHON_VERSION', 'BF_PYTHON_INC', 'BF_PYTHON_BINARY', 'BF_PYTHON_LIB', 'BF_PYTHON_LIBPATH', 'BF_PYTHON_LIBPATH_ARCH', 'WITH_BF_STATICPYTHON', 'WITH_OSX_STATICPYTHON', 'BF_PYTHON_LIB_STATIC', 'BF_PYTHON_DLL', 'BF_PYTHON_ABI_FLAGS',
- 'WITH_BF_AUDASPACE', 'BF_AUDASPACE_C_INC', 'BF_AUDASPACE_PY_INC', 'BF_AUDASPACE_DEF',
- 'WITH_BF_OPENAL', 'BF_OPENAL', 'BF_OPENAL_INC', 'BF_OPENAL_LIB', 'BF_OPENAL_LIBPATH', 'WITH_BF_STATICOPENAL', 'BF_OPENAL_LIB_STATIC',
- 'WITH_BF_SDL', 'BF_SDL', 'BF_SDL_INC', 'BF_SDL_LIB', 'BF_SDL_LIBPATH', 'WITH_BF_SDL_DYNLOAD',
- 'WITH_BF_JACK', 'BF_JACK', 'BF_JACK_INC', 'BF_JACK_LIB', 'BF_JACK_LIBPATH', 'WITH_BF_JACK_DYNLOAD',
- 'WITH_BF_SNDFILE', 'BF_SNDFILE', 'BF_SNDFILE_INC', 'BF_SNDFILE_LIB', 'BF_SNDFILE_LIBPATH', 'WITH_BF_STATICSNDFILE', 'BF_SNDFILE_LIB_STATIC',
- 'BF_PTHREADS', 'BF_PTHREADS_INC', 'BF_PTHREADS_LIB', 'BF_PTHREADS_LIBPATH',
- 'WITH_BF_OPENEXR', 'BF_OPENEXR', 'BF_OPENEXR_INC', 'BF_OPENEXR_LIB', 'BF_OPENEXR_LIBPATH', 'WITH_BF_STATICOPENEXR', 'BF_OPENEXR_LIB_STATIC',
- 'WITH_BF_DDS', 'WITH_BF_CINEON', 'WITH_BF_HDR',
- 'WITH_BF_FFMPEG', 'BF_FFMPEG_LIB','BF_FFMPEG_EXTRA', 'BF_FFMPEG', 'BF_FFMPEG_INC', 'BF_FFMPEG_DLL',
- 'WITH_BF_STATICFFMPEG', 'BF_FFMPEG_LIB_STATIC',
- 'WITH_BF_OGG', 'BF_OGG', 'BF_OGG_LIB',
- 'WITH_BF_FRAMESERVER',
- 'WITH_BF_COMPOSITOR',
- 'WITH_BF_JPEG', 'BF_JPEG', 'BF_JPEG_INC', 'BF_JPEG_LIB', 'BF_JPEG_LIBPATH', 'WITH_BF_STATICJPEG', 'BF_JPEG_LIB_STATIC',
- 'WITH_BF_OPENJPEG', 'BF_OPENJPEG', 'BF_OPENJPEG_INC', 'BF_OPENJPEG_LIB', 'BF_OPENJPEG_LIBPATH',
- 'WITH_BF_REDCODE', 'BF_REDCODE', 'BF_REDCODE_INC', 'BF_REDCODE_LIB', 'BF_REDCODE_LIBPATH',
- 'WITH_BF_PNG', 'BF_PNG', 'BF_PNG_INC', 'BF_PNG_LIB', 'BF_PNG_LIBPATH', 'WITH_BF_STATICPNG', 'BF_PNG_LIB_STATIC',
- 'WITH_BF_TIFF', 'BF_TIFF', 'BF_TIFF_INC', 'BF_TIFF_LIB', 'BF_TIFF_LIBPATH', 'WITH_BF_STATICTIFF', 'BF_TIFF_LIB_STATIC',
- 'WITH_BF_ZLIB', 'BF_ZLIB', 'BF_ZLIB_INC', 'BF_ZLIB_LIB', 'BF_ZLIB_LIBPATH', 'WITH_BF_STATICZLIB', 'BF_ZLIB_LIB_STATIC',
- 'WITH_BF_INTERNATIONAL',
- 'WITH_BF_ICONV', 'BF_ICONV', 'BF_ICONV_INC', 'BF_ICONV_LIB', 'BF_ICONV_LIBPATH',
- 'WITH_BF_GAMEENGINE',
- 'WITH_BF_BULLET', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB',
- # 'WITH_BF_ELTOPO', # now only available in a branch
- 'BF_LAPACK', 'BF_LAPACK_LIB', 'BF_LAPACK_LIBPATH', 'BF_LAPACK_LIB_STATIC',
- 'BF_WINTAB', 'BF_WINTAB_INC',
- 'BF_FREETYPE', 'BF_FREETYPE_INC', 'BF_FREETYPE_LIB', 'BF_FREETYPE_LIBPATH', 'BF_FREETYPE_LIB_STATIC', 'WITH_BF_FREETYPE_STATIC',
- 'WITH_BF_QUICKTIME', 'BF_QUICKTIME', 'BF_QUICKTIME_INC', 'BF_QUICKTIME_LIB', 'BF_QUICKTIME_LIBPATH',
- 'WITH_BF_FFTW3', 'BF_FFTW3', 'BF_FFTW3_INC', 'BF_FFTW3_LIB', 'BF_FFTW3_LIBPATH', 'WITH_BF_STATICFFTW3', 'BF_FFTW3_LIB_STATIC',
- 'WITH_BF_STATICOPENGL', 'BF_OPENGL', 'BF_OPENGL_INC', 'BF_OPENGL_LIB', 'BF_OPENGL_LIBPATH', 'BF_OPENGL_LIB_STATIC',
- 'WITH_BF_EGL', 'WITH_BF_GLEW_ES', 'BF_GLEW_INC', 'WITH_BF_GL_PROFILE_CORE', 'WITH_BF_GL_PROFILE_COMPAT', 'WITH_BF_GL_PROFILE_ES20',
- 'WITH_BF_GLEW_MX', 'WITH_BF_GL_EGL', 'WITH_BF_GL_ANGLE',
-
- 'WITH_BF_COLLADA', 'BF_COLLADA', 'BF_COLLADA_INC', 'BF_COLLADA_LIB', 'BF_OPENCOLLADA', 'BF_OPENCOLLADA_INC', 'BF_OPENCOLLADA_LIB', 'BF_OPENCOLLADA_LIBPATH', 'BF_PCRE', 'BF_PCRE_LIB', 'BF_PCRE_LIBPATH', 'BF_EXPAT', 'BF_EXPAT_LIB', 'BF_EXPAT_LIBPATH',
- 'WITH_BF_STATICOPENCOLLADA', 'BF_OPENCOLLADA_LIB_STATIC',
- 'WITH_BF_PLAYER',
- 'WITH_BF_NOBLENDER',
- 'WITH_BF_BINRELOC',
- 'WITH_BF_LZO', 'WITH_BF_LZMA',
- 'LCGDIR',
- 'BF_CXX', 'WITH_BF_STATICCXX', 'BF_CXX_LIB_STATIC',
- 'BF_TWEAK_MODE', 'BF_SPLIT_SRC',
- 'WITHOUT_BF_INSTALL',
- 'WITHOUT_BF_PYTHON_INSTALL', 'WITHOUT_BF_PYTHON_UNPACK',
- 'WITH_BF_PYTHON_INSTALL_NUMPY', 'WITH_BF_PYTHON_INSTALL_REQUESTS',
- 'WITHOUT_BF_OVERWRITE_INSTALL',
- 'WITH_BF_OPENMP', 'BF_OPENMP', 'BF_OPENMP_LIBPATH', 'WITH_BF_STATICOPENMP', 'BF_OPENMP_STATIC_STATIC',
- 'WITH_GHOST_SDL',
- 'WITH_GHOST_XDND',
- 'WITH_X11_XINPUT',
- 'WITH_X11_XF86VMODE',
- 'BF_GHOST_DEBUG',
- 'BF_FANCY', 'BF_QUIET', 'BF_LINE_OVERWRITE',
- 'BF_X264_CONFIG',
- 'BF_XVIDCORE_CONFIG',
- 'WITH_BF_DOCS',
- 'BF_NUMJOBS',
- 'BF_MSVS',
- 'WITH_BF_RAYOPTIMIZATION',
- 'BF_RAYOPTIMIZATION_SSE_FLAGS',
- 'WITH_BF_FLUID',
- 'WITH_BF_BOOLEAN',
- 'WITH_BF_REMESH',
- 'WITH_BF_OCEANSIM',
- 'WITH_BF_SMOKE',
- 'WITH_BF_CXX_GUARDEDALLOC',
- 'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
- 'BUILDBOT_BRANCH',
- 'WITH_BF_IME',
- 'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
- 'WITH_BF_CYCLES', 'WITH_BF_CYCLES_CUDA_BINARIES', 'BF_CYCLES_CUDA_NVCC', 'BF_CYCLES_CUDA_NVCC', 'WITH_BF_CYCLES_CUDA_THREADED_COMPILE', 'BF_CYCLES_CUDA_ENV',
- 'WITH_BF_OIIO', 'WITH_BF_STATICOIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIB_STATIC', 'BF_OIIO_LIBPATH',
- 'WITH_BF_OCIO', 'WITH_BF_STATICOCIO', 'BF_OCIO', 'BF_OCIO_INC', 'BF_OCIO_LIB', 'BF_OCIO_LIB_STATIC', 'BF_OCIO_LIBPATH',
- 'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_INTERNATIONAL', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
- 'WITH_BF_LIBMV', 'WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS',
- 'WITH_BF_CYCLES_OSL', 'WITH_BF_STATICOSL', 'BF_OSL', 'BF_OSL_INC', 'BF_OSL_LIB', 'BF_OSL_LIBPATH', 'BF_OSL_LIB_STATIC', 'BF_OSL_COMPILER',
- 'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS',
- 'WITH_BF_OPENSUBDIV', 'WITH_BF_STATICOPENSUBDIV', 'BF_OPENSUBDIV', 'BF_OPENSUBDIV_INC', 'BF_OPENSUBDIV_LIB', 'BF_OPENSUBDIV_LIBPATH', 'BF_OPENSUBDIV_LIB_STATIC'
- ]
-
- # Have options here that scons expects to be lists
- opts_list_split = [
- 'BF_PYTHON_LINKFLAGS',
- 'BF_OPENGL_LINKFLAGS',
- 'BF_GL_DEFINITIONS',
- 'CFLAGS', 'CCFLAGS', 'CXXFLAGS', 'CPPFLAGS',
- 'REL_CFLAGS', 'REL_CCFLAGS', 'REL_CXXFLAGS',
- 'BGE_CXXFLAGS',
- 'BF_PROFILE_CFLAGS', 'BF_PROFILE_CCFLAGS', 'BF_PROFILE_CXXFLAGS', 'BF_PROFILE_LINKFLAGS',
- 'BF_DEBUG_CFLAGS', 'BF_DEBUG_CCFLAGS', 'BF_DEBUG_CXXFLAGS',
- 'C_WARN', 'CC_WARN', 'CXX_WARN',
- 'LLIBS', 'PLATFORM_LINKFLAGS', 'MACOSX_ARCHITECTURE', 'MACOSX_SDK', 'XCODE_CUR_VER', 'C_COMPILER_ID',
- 'BF_CYCLES_CUDA_BINARIES_ARCH', 'BF_PROGRAM_LINKFLAGS', 'MACOSX_DEPLOYMENT_TARGET',
- 'WITH_BF_CYCLES_DEBUG', 'WITH_BF_CYCLES_LOGGING',
- 'WITH_BF_CPP11', 'WITH_BF_LEGACY_DEPSGRAPH',
- ]
-
-
- arg_list = ['BF_DEBUG', 'BF_QUIET', 'BF_CROSS', 'BF_UPDATE',
- 'BF_INSTALLDIR', 'BF_TOOLSET', 'BF_BINNAME',
- 'BF_BUILDDIR', 'BF_FANCY', 'BF_QUICK', 'BF_PROFILE', 'BF_LINE_OVERWRITE',
- 'BF_BSC', 'BF_CONFIG',
- 'BF_PRIORITYLIST', 'BF_BUILDINFO','CC', 'CXX', 'BF_QUICKDEBUG',
- 'BF_LISTDEBUG', 'LCGDIR', 'BF_X264_CONFIG', 'BF_XVIDCORE_CONFIG',
- 'BF_UNIT_TEST', 'BF_BITNESS', 'MSVS_VERSION']
-
- okdict = {}
-
- for k,v in args.iteritems():
- if (k in opts_list) or (k in arg_list):
- okdict[k] = v
- elif k in opts_list_split:
- okdict[k] = v.split() # "" have already been stripped
- else:
- print '\t'+bc.WARNING+'Invalid argument: '+bc.ENDC+k+'='+v
-
- return okdict
-
-def print_targets(targs, bc):
- if len(targs)>0:
- for t in targs:
- print '\t'+bc.OKBLUE+t+bc.ENDC
- else:
- print '\t'+bc.WARNING+'No targets given, using '+bc.ENDC+bc.OKGREEN+'default'+bc.ENDC
-
-def validate_targets(targs, bc):
- valid_list = ['.', 'blender', 'blenderstatic', 'blenderplayer', 'webplugin',
- 'blendernogame', 'blenderstaticnogame', 'blenderlite', 'release',
- 'everything', 'clean', 'install-bin', 'install', 'nsis','buildslave',
- 'cudakernels']
- oklist = []
- for t in targs:
- if t in valid_list:
- oklist.append(t)
- else:
- print '\t'+bc.WARNING+'Invalid target: '+bc.ENDC+t
- return oklist
-
-class OurSpawn:
- def ourspawn(self, sh, escape, cmd, args, env):
- newargs = " ".join(args[1:])
- cmdline = cmd + " " + newargs
- startupinfo = subprocess.STARTUPINFO()
- proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env=env)
- data, err = proc.communicate()
- rv = proc.wait()
- if err:
- print(err)
- return rv
-
-def SetupSpawn( env ):
- buf = OurSpawn()
- env['SPAWN'] = buf.ourspawn
-
-
-def read_opts(env, cfg, args):
- localopts = Variables.Variables(cfg, args)
- localopts.AddVariables(
- ('LCGDIR', 'Location of SVN lib dir'),
- ('LIBDIR', 'Root dir of libs'),
- (BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
- (BoolVariable('WITH_BF_PYTHON_SAFETY', 'Internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency)', False)),
- (BoolVariable('WITH_BF_PYTHON_SECURITY', 'Disables execution of scripts within blend files by default', True)),
- ('BF_PYTHON', 'Base path for python', ''),
- ('BF_PYTHON_VERSION', 'Python version to use', ''),
- ('BF_PYTHON_INC', 'Include path for Python headers', ''),
- ('BF_PYTHON_BINARY', 'Path to the Python interpreter', ''),
- ('BF_PYTHON_LIB', 'Python library', ''),
- ('BF_PYTHON_LIBPATH_ARCH', 'Additional Python library under some linux flavors (arch-dependent)', ''),
- ('BF_PYTHON_DLL', 'Python dll - used on Windows only', ''),
- ('BF_PYTHON_LIB_STATIC', 'Python static libraries', ''),
- ('BF_PYTHON_LIBPATH', 'Library path', ''),
- ('BF_PYTHON_LINKFLAGS', 'Python link flags', ''),
- (BoolVariable('WITH_BF_STATICPYTHON', 'Staticly link to python', False)),
- (BoolVariable('WITH_OSX_STATICPYTHON', 'Staticly link to python', True)),
- ('BF_PYTHON_ABI_FLAGS', 'Python ABI flags (suffix in library version: m, mu, etc)', ''),
-
- (BoolVariable('WITH_BF_FLUID', 'Build with Fluid simulation (Elbeem)', True)),
- (BoolVariable('WITH_BF_BOOLEAN', 'Build with boolean modifier', True)),
- (BoolVariable('WITH_BF_REMESH', 'Build with remesh modifier', True)),
- (BoolVariable('WITH_BF_OCEANSIM', 'Build with ocean simulation', False)),
- (BoolVariable('WITH_BF_SMOKE', 'Build with smoke simulation', True)),
- ('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
- (BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
- ('BF_OPENAL', 'Base path for OpenAL', ''),
- ('BF_OPENAL_INC', 'Include path for python headers', ''),
- ('BF_OPENAL_LIB', 'Path to OpenAL library', ''),
- ('BF_OPENAL_LIB_STATIC', 'Path to OpenAL static library', ''),
- ('BF_OPENAL_LIBPATH', 'Path to OpenAL library', ''),
- (BoolVariable('WITH_BF_STATICOPENAL', 'Staticly link to openal', False)),
-
- (BoolVariable('WITH_BF_AUDASPACE', 'Build with audaspace if true', True)),
- ('BF_AUDASPACE_C_INC', 'audaspace-c include path', ''),
- ('BF_AUDASPACE_PY_INC', 'audaspace-py include path', ''),
- ('BF_AUDASPACE_DEF', 'audaspace defines', ''),
-
- (BoolVariable('WITH_BF_SDL', 'Use SDL if true', False)),
- ('BF_SDL', 'SDL base path', ''),
- ('BF_SDL_INC', 'SDL include path', ''),
- ('BF_SDL_LIB', 'SDL library', ''),
- ('BF_SDL_LIBPATH', 'SDL library path', ''),
- (BoolVariable('WITH_BF_SDL_DYNLOAD', 'Enable runtime dynamic SDL libraries loading (works only on Linux)', False)),
-
- (BoolVariable('WITH_BF_JACK', 'Enable jack support if true', True)),
- ('BF_JACK', 'jack base path', ''),
- ('BF_JACK_INC', 'jack include path', ''),
- ('BF_JACK_LIB', 'jack library', ''),
- ('BF_JACK_LIBPATH', 'jack library path', ''),
- (BoolVariable('WITH_BF_JACK_DYNLOAD', 'Enable runtime dynamic Jack libraries loading (works only on Linux)', False)),
-
- (BoolVariable('WITH_BF_SNDFILE', 'Enable sndfile support if true', True)),
- ('BF_SNDFILE', 'sndfile base path', ''),
- ('BF_SNDFILE_INC', 'sndfile include path', ''),
- ('BF_SNDFILE_LIB', 'sndfile library', ''),
- ('BF_SNDFILE_LIB_STATIC', 'Path to sndfile static library', ''),
- ('BF_SNDFILE_LIBPATH', 'sndfile library path', ''),
- (BoolVariable('WITH_BF_STATICSNDFILE', 'Staticly link to sndfile', False)),
-
- ('BF_PTHREADS', 'Pthreads base path', ''),
- ('BF_PTHREADS_INC', 'Pthreads include path', ''),
- ('BF_PTHREADS_LIB', 'Pthreads library', ''),
- ('BF_PTHREADS_LIBPATH', 'Pthreads library path', ''),
-
- (BoolVariable('WITH_BF_OPENEXR', 'Use OPENEXR if true', True)),
- (BoolVariable('WITH_BF_STATICOPENEXR', 'Staticly link to OpenEXR', False)),
- ('BF_OPENEXR', 'OPENEXR base path', ''),
- ('BF_OPENEXR_INC', 'OPENEXR include path', ''),
- ('BF_OPENEXR_LIB', 'OPENEXR library', ''),
- ('BF_OPENEXR_LIBPATH', 'OPENEXR library path', ''),
- ('BF_OPENEXR_LIB_STATIC', 'OPENEXR static library', ''),
-
- (BoolVariable('WITH_BF_DDS', 'Support DDS image format if true', True)),
-
- (BoolVariable('WITH_BF_CINEON', 'Support CINEON and DPX image formats if true', True)),
-
- (BoolVariable('WITH_BF_HDR', 'Support HDR image formats if true', True)),
-
- (BoolVariable('WITH_BF_FRAMESERVER', 'Support export to a frameserver', True)),
-
- (BoolVariable('WITH_BF_FFMPEG', 'Use FFMPEG if true', False)),
- ('BF_FFMPEG', 'FFMPEG base path', ''),
- ('BF_FFMPEG_LIB', 'FFMPEG library', ''),
- ('BF_FFMPEG_DLL', 'FFMPEG dll libraries to be installed', ''),
- ('BF_FFMPEG_EXTRA', 'FFMPEG flags that must be preserved', ''),
-
- ('BF_FFMPEG_INC', 'FFMPEG includes', ''),
- ('BF_FFMPEG_LIBPATH', 'FFMPEG library path', ''),
- (BoolVariable('WITH_BF_STATICFFMPEG', 'Use static FFMPEG if true', False)),
- ('BF_FFMPEG_LIB_STATIC', 'Static FFMPEG libraries', ''),
-
- (BoolVariable('WITH_BF_OGG', 'Link OGG, THEORA, VORBIS with FFMPEG if true',
- False)),
- ('BF_OGG', 'OGG base path', ''),
- ('BF_OGG_LIB', 'OGG library', ''),
-
- (BoolVariable('WITH_BF_JPEG', 'Use JPEG if true', True)),
- (BoolVariable('WITH_BF_STATICJPEG', 'Staticly link to JPEG', False)),
- ('BF_JPEG', 'JPEG base path', ''),
- ('BF_JPEG_INC', 'JPEG include path', ''),
- ('BF_JPEG_LIB', 'JPEG library', ''),
- ('BF_JPEG_LIBPATH', 'JPEG library path', ''),
- ('BF_JPEG_LIB_STATIC', 'JPEG static library', ''),
-
- (BoolVariable('WITH_BF_OPENJPEG', 'Use OPENJPEG if true', False)),
- ('BF_OPENJPEG', 'OPENJPEG base path', ''),
- ('BF_OPENJPEG_INC', 'OPENJPEG include path', ''),
- ('BF_OPENJPEG_LIB', 'OPENJPEG library', ''),
- ('BF_OPENJPEG_LIBPATH', 'OPENJPEG library path', ''),
-
- (BoolVariable('WITH_BF_REDCODE', 'Use REDCODE if true', False)),
- ('BF_REDCODE', 'REDCODE base path', ''),
- ('BF_REDCODE_INC', 'REDCODE include path', ''),
- ('BF_REDCODE_LIB', 'REDCODE library', ''),
- ('BF_REDCODE_LIBPATH', 'REDCODE library path', ''),
-
- (BoolVariable('WITH_BF_PNG', 'Use PNG if true', True)),
- (BoolVariable('WITH_BF_STATICPNG', 'Staticly link to PNG', False)),
- ('BF_PNG', 'PNG base path', ''),
- ('BF_PNG_INC', 'PNG include path', ''),
- ('BF_PNG_LIB', 'PNG library', ''),
- ('BF_PNG_LIBPATH', 'PNG library path', ''),
- ('BF_PNG_LIB_STATIC', 'PNG static library', ''),
-
- (BoolVariable('WITH_BF_TIFF', 'Use TIFF if true', True)),
- (BoolVariable('WITH_BF_STATICTIFF', 'Staticly link to TIFF', False)),
- ('BF_TIFF', 'TIFF base path', ''),
- ('BF_TIFF_INC', 'TIFF include path', ''),
- ('BF_TIFF_LIB', 'TIFF library', ''),
- ('BF_TIFF_LIBPATH', 'TIFF library path', ''),
- ('BF_TIFF_LIB_STATIC', 'TIFF static library', ''),
-
- (BoolVariable('WITH_BF_ZLIB', 'Use ZLib if true', True)),
- (BoolVariable('WITH_BF_STATICZLIB', 'Staticly link to ZLib', False)),
- ('BF_ZLIB', 'ZLib base path', ''),
- ('BF_ZLIB_INC', 'ZLib include path', ''),
- ('BF_ZLIB_LIB', 'ZLib library', ''),
- ('BF_ZLIB_LIBPATH', 'ZLib library path', ''),
- ('BF_ZLIB_LIB_STATIC', 'ZLib static library', ''),
-
- (BoolVariable('WITH_BF_INTERNATIONAL', 'Use Boost::locale if true', True)),
-
- (BoolVariable('WITH_BF_ICONV', 'Use iconv if true', True)),
- ('BF_ICONV', 'iconv base path', ''),
- ('BF_ICONV_INC', 'iconv include path', ''),
- ('BF_ICONV_LIB', 'iconv library', ''),
- ('BF_ICONV_LIBPATH', 'iconv library path', ''),
-
- (BoolVariable('WITH_BF_FREESTYLE', 'Compile with freestyle', True)),
-
- (BoolVariable('WITH_BF_GAMEENGINE', 'Build with gameengine' , False)),
-
- (BoolVariable('WITH_BF_BULLET', 'Use Bullet if true', True)),
- # (BoolVariable('WITH_BF_ELTOPO', 'Use Eltopo collision library if true', False)), # this is now only available in a branch
- ('BF_LAPACK', 'LAPACK base path', ''),
- ('BF_LAPACK_LIB', 'LAPACK library', ''),
- ('BF_LAPACK_LIB_STATIC', 'LAPACK library', ''),
- ('BF_LAPACK_LIBPATH', 'LAPACK library path', ''),
- (BoolVariable('WITH_BF_STATICLAPACK', 'Staticly link to LAPACK', False)),
-
- ('BF_BULLET', 'Bullet base dir', ''),
- ('BF_BULLET_INC', 'Bullet include path', ''),
- ('BF_BULLET_LIB', 'Bullet library', ''),
-
- ('BF_WINTAB', 'WinTab base dir', ''),
- ('BF_WINTAB_INC', 'WinTab include dir', ''),
- ('BF_CXX', 'c++ base path for libstdc++, only used when static linking', ''),
- (BoolVariable('WITH_BF_STATICCXX', 'static link to stdc++', False)),
- ('BF_CXX_LIB_STATIC', 'static library path for stdc++', ''),
-
- ('BF_FREETYPE', 'Freetype base path', ''),
- ('BF_FREETYPE_INC', 'Freetype include path', ''),
- ('BF_FREETYPE_LIB', 'Freetype library', ''),
- ('BF_FREETYPE_LIBPATH', 'Freetype library path', ''),
- (BoolVariable('WITH_BF_FREETYPE_STATIC', 'Use Static Freetype if true', False)),
- ('BF_FREETYPE_LIB_STATIC', 'Static Freetype library', ''),
-
- (BoolVariable('WITH_BF_OPENMP', 'Use OpenMP if true', False)),
- (BoolVariable('WITH_BF_STATICOPENMP', 'Staticly link to OpenMP', False)),
- ('BF_OPENMP', 'Base path to OpenMP (used when cross-compiling with older versions of WinGW)', ''),
- ('BF_OPENMP_INC', 'Path to OpenMP includes (used when cross-compiling with older versions of WinGW)', ''),
- ('BF_OPENMP_LIBPATH', 'Path to OpenMP libraries (used when cross-compiling with older versions of WinGW)', ''),
- (BoolVariable('WITH_GHOST_SDL', 'Enable building blender against SDL for windowing rather then the native APIs', False)),
- (BoolVariable('WITH_X11_XINPUT', 'Enable X11 Xinput (tablet support and unicode input)', True)),
- (BoolVariable('WITH_X11_XF86VMODE', 'Enable X11 video mode switching', True)),
- ('BF_OPENMP_LIB_STATIC', 'OpenMP static library', ''),
-
- (BoolVariable('WITH_BF_QUICKTIME', 'Use QuickTime if true', False)),
- ('BF_QUICKTIME', 'QuickTime base path', ''),
- ('BF_QUICKTIME_INC', 'QuickTime include path', ''),
- ('BF_QUICKTIME_LIB', 'QuickTime library', ''),
- ('BF_QUICKTIME_LIBPATH', 'QuickTime library path', ''),
-
- (BoolVariable('WITH_BF_FFTW3', 'Use FFTW3 if true', False)),
- ('BF_FFTW3', 'FFTW3 base path', ''),
- ('BF_FFTW3_INC', 'FFTW3 include path', ''),
- ('BF_FFTW3_LIB', 'FFTW3 library', ''),
- ('BF_FFTW3_LIB_STATIC', 'FFTW3 static libraries', ''),
- ('BF_FFTW3_LIBPATH', 'FFTW3 library path', ''),
- (BoolVariable('WITH_BF_STATICFFTW3', 'Staticly link to FFTW3', False)),
-
- (BoolVariable('WITH_BF_STATICOPENGL', 'Use MESA if true', True)),
- ('BF_OPENGL', 'OpenGL base path', ''),
- ('BF_OPENGL_INC', 'OpenGL include path', ''),
- ('BF_OPENGL_LIB', 'OpenGL libraries', ''),
- ('BF_OPENGL_LIBPATH', 'OpenGL library path', ''),
- ('BF_OPENGL_LIB_STATIC', 'OpenGL static libraries', ''),
- ('BF_OPENGL_LINKFLAGS', 'OpenGL link flags', ''),
-
- (BoolVariable('WITH_BF_GLEW_MX', '', False)),
- (BoolVariable('WITH_BF_GLEW_ES', '', False)),
- (BoolVariable('WITH_BF_GL_EGL', '', False)),
- (BoolVariable('WITH_BF_GL_PROFILE_COMPAT', '', True)),
- (BoolVariable('WITH_BF_GL_PROFILE_CORE', '', False)),
- (BoolVariable('WITH_BF_GL_PROFILE_ES20', '', False)),
- (BoolVariable('WITH_BF_GL_ANGLE', '', False)),
- ('BF_GL_DEFINITIONS', '', []),
- ('BF_GLEW_INC', '', ''),
- ) # end of opts.AddVariables()
-
- localopts.AddVariables(
- (BoolVariable('WITH_BF_COLLADA', 'Build COLLADA import/export module if true', False)),
- (BoolVariable('WITH_BF_STATICOPENCOLLADA', 'Staticly link to OpenCollada', False)),
- ('BF_COLLADA', 'COLLADA base path', ''),
- ('BF_COLLADA_INC', 'COLLADA include path', ''),
- ('BF_COLLADA_LIB', 'COLLADA library', ''),
- ('BF_OPENCOLLADA', 'OpenCollada base path', ''),
- ('BF_OPENCOLLADA_INC', 'OpenCollada base include path', ''),
- ('BF_OPENCOLLADA_LIB', 'OpenCollada library', ''),
- ('BF_OPENCOLLADA_LIBPATH', 'OpenCollada library path', ''),
- ('BF_PCRE', 'PCRE base path', ''),
- ('BF_PCRE_LIB', 'PCRE library', ''),
- ('BF_PCRE_LIBPATH', 'PCRE library path', ''),
- ('BF_EXPAT', 'Expat base path', ''),
- ('BF_EXPAT_LIB', 'Expat library', ''),
- ('BF_EXPAT_LIBPATH', 'Expat library path', ''),
- ('BF_OPENCOLLADA_LIB_STATIC', 'OpenCollada static library', ''),
-
- (BoolVariable('WITH_BF_JEMALLOC', 'Use jemalloc if true', False)),
- (BoolVariable('WITH_BF_STATICJEMALLOC', 'Staticly link to jemalloc', False)),
- ('BF_JEMALLOC', 'jemalloc base path', ''),
- ('BF_JEMALLOC_INC', 'jemalloc include path', ''),
- ('BF_JEMALLOC_LIB', 'jemalloc library', ''),
- ('BF_JEMALLOC_LIBPATH', 'jemalloc library path', ''),
- ('BF_JEMALLOC_LIB_STATIC', 'jemalloc static library', ''),
-
- (BoolVariable('WITH_BF_PLAYER', 'Build blenderplayer if true', False)),
- (BoolVariable('WITH_BF_NOBLENDER', 'Do not build blender if true', False)),
-
- (BoolVariable('WITH_BF_IME', 'Enable Input Method Editor (IME) for complex Asian character input', False)),
-
- (BoolVariable('WITH_BF_3DMOUSE', 'Build blender with support of 3D mouses', False)),
- (BoolVariable('WITH_BF_STATIC3DMOUSE', 'Staticly link to 3d mouse library', False)),
- ('BF_3DMOUSE', '3d mouse library base path', ''),
- ('BF_3DMOUSE_INC', '3d mouse library include path', ''),
- ('BF_3DMOUSE_LIB', '3d mouse library', ''),
- ('BF_3DMOUSE_LIBPATH', '3d mouse library path', ''),
- ('BF_3DMOUSE_LIB_STATIC', '3d mouse static library', ''),
-
- ('CFLAGS', 'C only flags', []),
- ('CCFLAGS', 'Generic C and C++ flags', []),
- ('CXXFLAGS', 'C++ only flags', []),
- ('BGE_CXXFLAGS', 'C++ only flags for BGE', []),
- ('CPPFLAGS', 'Defines', []),
- ('REL_CFLAGS', 'C only release flags', []),
- ('REL_CCFLAGS', 'Generic C and C++ release flags', []),
- ('REL_CXXFLAGS', 'C++ only release flags', []),
-
- ('C_WARN', 'C warning flags', []),
- ('CC_WARN', 'Generic C and C++ warning flags', []),
- ('CXX_WARN', 'C++ only warning flags', []),
-
- ('LLIBS', 'Platform libs', []),
- ('PLATFORM_LINKFLAGS', 'Platform linkflags', []),
- ('MACOSX_ARCHITECTURE', 'python_arch.zip select', ''),
- ('MACOSX_SDK', 'Set OS X SDK', ''),
- ('XCODE_CUR_VER', 'Detect XCode version', ''),
- ('MACOSX_DEPLOYMENT_TARGET', 'Detect OS X target version', ''),
- ('C_COMPILER_ID', 'Detect the resolved compiler', ''),
-
- (BoolVariable('BF_PROFILE', 'Add profiling information if true', False)),
- ('BF_PROFILE_CFLAGS', 'C only profiling flags', []),
- ('BF_PROFILE_CCFLAGS', 'C and C++ profiling flags', []),
- ('BF_PROFILE_CXXFLAGS', 'C++ only profiling flags', []),
- ('BF_PROFILE_LINKFLAGS', 'Profile linkflags', []),
-
- (BoolVariable('BF_DEBUG', 'Add debug flags if true', False)),
- ('BF_DEBUG_CFLAGS', 'C only debug flags', []),
- ('BF_DEBUG_CCFLAGS', 'C and C++ debug flags', []),
- ('BF_DEBUG_CXXFLAGS', 'C++ only debug flags', []),
-
- (BoolVariable('BF_BSC', 'Create .bsc files (msvc only)', False)),
-
- ('BF_BUILDDIR', 'Build dir', ''),
- ('BF_INSTALLDIR', 'Installation dir', ''),
-
- ('CC', 'C compiler to use', env['CC']),
- ('CXX', 'C++ compiler to use', env['CXX']),
-
- (BoolVariable('BF_BUILDINFO', 'Buildtime in splash if true', True)),
-
- (BoolVariable('BF_TWEAK_MODE', 'Enable tweak mode if true', False)),
- (BoolVariable('BF_SPLIT_SRC', 'Split src lib into several chunks if true', False)),
- (BoolVariable('WITHOUT_BF_INSTALL', 'dont install if true', False)),
- (BoolVariable('WITHOUT_BF_PYTHON_INSTALL', 'dont install Python modules if true', False)),
- (BoolVariable('WITH_BF_PYTHON_INSTALL_NUMPY', 'install Python numpy module', False)),
- (BoolVariable('WITH_BF_PYTHON_INSTALL_REQUESTS', 'install Python requests module', False)),
- (BoolVariable('WITHOUT_BF_PYTHON_UNPACK', 'dont remove and unpack Python modules everytime if true', False)),
- (BoolVariable('WITHOUT_BF_OVERWRITE_INSTALL', 'dont remove existing files before breating the new install directory (set to False when making packages for others)', False)),
- (BoolVariable('BF_FANCY', 'Enable fancy output if true', True)),
- (BoolVariable('BF_QUIET', 'Enable silent output if true', True)),
- (BoolVariable('BF_LINE_OVERWRITE', 'Enable overwriting of compile line in BF_QUIET mode if true', False)),
- (BoolVariable('WITH_BF_BINRELOC', 'Enable relocatable binary (linux only)', False)),
-
- (BoolVariable('WITH_BF_LZO', 'Enable fast LZO pointcache compression', True)),
- (BoolVariable('WITH_BF_LZMA', 'Enable best LZMA pointcache compression', True)),
-
- (BoolVariable('WITH_BF_LIBMV', 'Enable libmv structure from motion library', True)),
- (BoolVariable('WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS', 'Enable fixed-size schur specializations', True)),
-
- (BoolVariable('WITH_BF_COMPOSITOR', 'Enable the tile based nodal compositor', True)),
- ) # end of opts.AddOptions()
-
- localopts.AddVariables(
- ('BF_X264_CONFIG', 'configuration flags for x264', ''),
- ('BF_XVIDCORE_CONFIG', 'configuration flags for xvidcore', ''),
-# (BoolVariable('WITH_BF_DOCS', 'Generate API documentation', False)),
-
- ('BF_CONFIG', 'SCons python config file used to set default options', 'user_config.py'),
- ('BF_NUMJOBS', 'Number of build processes to spawn', '1'),
- ('BF_MSVS', 'Generate MSVS project files and solution', False),
-
- (BoolVariable('BF_UNIT_TEST', 'Build with unit test support.', False)),
-
- (BoolVariable('BF_GHOST_DEBUG', 'Make GHOST print events and info to stdout. (very verbose)', False)),
-
- (BoolVariable('WITH_BF_RAYOPTIMIZATION', 'Enable raytracer SSE/SIMD optimization.', False)),
- ('BF_RAYOPTIMIZATION_SSE_FLAGS', 'SSE flags', ''),
- (BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
-
- ('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
-
- (BoolVariable('WITH_BF_CYCLES', 'Build with the Cycles engine', True)),
- (BoolVariable('WITH_BF_CYCLES_CUDA_BINARIES', 'Build with precompiled CUDA binaries', False)),
- (BoolVariable('WITH_BF_CYCLES_CUDA_THREADED_COMPILE', 'Build several render kernels at once (using BF_NUMJOBS)', False)),
- ('BF_CYCLES_CUDA_NVCC', 'CUDA nvcc compiler path', ''),
- ('BF_CYCLES_CUDA_ENV', 'preset environement nvcc will execute in', ''),
- ('BF_CYCLES_CUDA_BINARIES_ARCH', 'CUDA architectures to compile binaries for', []),
- (BoolVariable('WITH_BF_CYCLES_DEBUG', 'Build Cycles engine with extra debugging capabilities', False)),
- (BoolVariable('WITH_BF_CYCLES_LOGGING', 'Build Cycles engine with logging support', True)),
-
- (BoolVariable('WITH_BF_OIIO', 'Build with OpenImageIO', False)),
- (BoolVariable('WITH_BF_STATICOIIO', 'Statically link to OpenImageIO', False)),
- ('BF_OIIO', 'OIIO root path', ''),
- ('BF_OIIO_INC', 'OIIO include path', ''),
- ('BF_OIIO_LIB', 'OIIO library', ''),
- ('BF_OIIO_LIBPATH', 'OIIO library path', ''),
- ('BF_OIIO_LIB_STATIC', 'OIIO static library', ''),
-
- (BoolVariable('WITH_BF_OCIO', 'Build with OpenColorIO', False)),
- (BoolVariable('WITH_BF_STATICOCIO', 'Staticly link to OpenColorIO', False)),
- ('BF_OCIO', 'OCIO root path', ''),
- ('BF_OCIO_INC', 'OCIO include path', ''),
- ('BF_OCIO_LIB', 'OCIO library', ''),
- ('BF_OCIO_LIBPATH', 'OCIO library path', ''),
- ('BF_OCIO_LIB_STATIC', 'OCIO static library', ''),
-
- (BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
- (BoolVariable('WITH_BF_STATICBOOST', 'Staticly link to boost', False)),
- ('BF_BOOST', 'Boost root path', ''),
- ('BF_BOOST_INC', 'Boost include path', ''),
- ('BF_BOOST_LIB', 'Boost library', ''),
- ('BF_BOOST_LIB_INTERNATIONAL', 'Boost library', ''),
- ('BF_BOOST_LIBPATH', 'Boost library path', ''),
- ('BF_BOOST_LIB_STATIC', 'Boost static library', ''),
-
- (BoolVariable('WITH_GHOST_XDND', 'Build with drag-n-drop support on Linux platforms using XDND protocol', True)),
-
- (BoolVariable('WITH_BF_CYCLES_OSL', 'Build with OSL sypport in Cycles', False)),
- (BoolVariable('WITH_BF_STATICOSL', 'Staticly link to OSL', False)),
- ('BF_OSL', 'OSL root path', ''),
- ('BF_OSL_INC', 'OSL include path', ''),
- ('BF_OSL_LIB', 'OSL library', ''),
- ('BF_OSL_LIBPATH', 'OSL library path', ''),
- ('BF_OSL_LIB_STATIC', 'OSL static library', ''),
- ('BF_OSL_COMPILER', 'OSL compiler', ''),
-
- (BoolVariable('WITH_BF_LLVM', 'Build with LLVM sypport (required for OSL)', False)),
- (BoolVariable('WITH_BF_STATICLLVM', 'Staticly link to LLVM', False)),
- ('BF_LLVM', 'LLVM root path', ''),
- ('BF_LLVM_LIB', 'LLVM library', ''),
- ('BF_LLVM_LIBPATH', 'LLVM library path', ''),
- ('BF_LLVM_LIB_STATIC', 'LLVM static library', ''),
-
- ('BF_PROGRAM_LINKFLAGS', 'Link flags applied only to final binaries (blender and blenderplayer, not makesrna/makesdna)', ''),
-
- (BoolVariable('WITH_BF_OPENSUBDIV', 'Build with OpenSubdiv library', False)),
- (BoolVariable('WITH_BF_STATICOPENSUBDIV', 'Staticly link to OpenColorIO', False)),
- ('BF_OPENSUBDIV', 'OpenSubdiv root path', ''),
- ('BF_OPENSUBDIV_INC', 'OpenSubdiv include path', ''),
- ('BF_OPENSUBDIV_LIB', 'OpenSubdiv library', ''),
- ('BF_OPENSUBDIV_LIBPATH', 'OpenSubdiv library path', ''),
- ('BF_OPENSUBDIV_LIB_STATIC', 'OpenSubdiv static library', ''),
-
- (BoolVariable('WITH_BF_CPP11', '"Build with C++11 standard enabled, for development use only!', False)),
-
- (BoolVariable('WITH_BF_LEGACY_DEPSGRAPH', 'Build Blender with legacy dependency graph', True)),
- ) # end of opts.AddOptions()
-
- return localopts
-
-def buildbot_zip(src, dest, package_name, extension):
- import zipfile
- ln = len(src)+1 # one extra to remove leading os.sep when cleaning root for package_root
- flist = list()
-
- # create list of tuples containing file and archive name
- for root, dirs, files in os.walk(src):
- package_root = os.path.join(package_name, root[ln:])
- flist.extend([(os.path.join(root, file), os.path.join(package_root, file)) for file in files])
-
- if extension == '.zip':
- package = zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED)
- package.comment = package_name + ' is a zip-file containing the Blender software. Visit http://www.blender.org for more information.'
- for entry in flist:
- package.write(entry[0], entry[1])
- package.close()
- else:
- import tarfile
- package = tarfile.open(dest, 'w:bz2')
- for entry in flist:
- package.add(entry[0], entry[1], recursive=False)
- package.close()
- bb_zip_name = os.path.normpath(src + os.sep + '..' + os.sep + 'buildbot_upload.zip')
- print("creating %s" % (bb_zip_name))
- bb_zip = zipfile.ZipFile(bb_zip_name, 'w', zipfile.ZIP_DEFLATED)
- print("writing %s to %s" % (dest, bb_zip_name))
- bb_zip.write(dest, os.path.split(dest)[1])
- bb_zip.close()
- print("removing unneeded packed file %s (to keep install directory clean)" % (dest))
- os.remove(dest)
- print("done.")
-
-def buildslave_print(target, source, env):
- return "Running buildslave target"
-
-def buildslave(target=None, source=None, env=None):
- """
- Builder for buildbot integration. Used by buildslaves of http://builder.blender.org only.
- """
-
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'darwin', 'win64-mingw'):
- extension = '.zip'
- else:
- extension = '.tar.bz2'
-
- if env['OURPLATFORM'] == 'win32-mingw':
- platform = 'mingw32'
- elif env['OURPLATFORM'] == 'win64-mingw':
- platform = 'mingw64'
- else:
- platform = env['OURPLATFORM'].split('-')[0]
-
- if platform == 'linux':
- import platform
-
- if "glibc27" in env['BF_INSTALLDIR']:
- glibc = "glibc27"
- elif "glibc211" in env['BF_INSTALLDIR']:
- glibc = "glibc211"
-
- bitness = platform.architecture()[0]
- if bitness == '64bit':
- platform = 'linux-' + glibc + '-x86_64'
- elif bitness == '32bit':
- platform = 'linux-' + glibc + '-i686'
- if platform == 'darwin':
- platform = 'OSX-' + env['MACOSX_DEPLOYMENT_TARGET'] + '-' + env['MACOSX_ARCHITECTURE']
-
-
- branch = env['BUILDBOT_BRANCH']
-
- outdir = os.path.abspath(env['BF_INSTALLDIR'])
- package_name = 'blender-' + VERSION+'-'+HASH + '-' + platform
- if branch != '':
- package_name = branch + '-' + package_name
- package_dir = os.path.normpath(outdir + os.sep + '..' + os.sep + package_name)
- package_archive = os.path.normpath(outdir + os.sep + '..' + os.sep + package_name + extension)
-
- try:
- if os.path.exists(package_archive):
- os.remove(package_archive)
- if os.path.exists(package_dir):
- shutil.rmtree(package_dir)
- except Exception, ex:
- sys.stderr.write('Failed to clean up old package files: ' + str(ex) + '\n')
- return 1
-
- buildbot_zip(outdir, package_archive, package_name, extension)
-
- return 0
-
-def NSIS_print(target, source, env):
- return "Creating NSIS installer for Blender"
-
-def NSIS_Installer(target=None, source=None, env=None):
- print "="*35
-
- if env['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
- print "NSIS installer is only available on Windows."
- exit()
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
- bitness = '32'
- elif env['OURPLATFORM'] in ('win64-vc', 'win64-mingw'):
- bitness = '64'
-
- start_dir = os.getcwd()
- rel_dir = os.path.join(start_dir,'release','windows','installer')
- install_base_dir = start_dir + os.sep
-
- bf_installdir = os.path.join(os.getcwd(),env['BF_INSTALLDIR'])
- bf_installdir = os.path.normpath(bf_installdir)
-
- doneroot = False
- rootdirconts = []
- datafiles = ''
- deldatafiles = ''
- deldatadirs = ''
- l = len(bf_installdir)
-
- for dp,dn,df in os.walk(bf_installdir):
- # install
- if not doneroot:
- for f in df:
- rootdirconts.append(os.path.join(dp,f))
- doneroot = True
- else:
- if len(df)>0:
- datafiles += "\n" +r'SetOutPath $INSTDIR'+dp[l:]+"\n\n"
-
- for f in df:
- outfile = os.path.join(dp,f)
- datafiles += ' File '+outfile + "\n"
-
- # uninstall
- deldir = dp[l+1:]
-
- if len(deldir)>0:
- deldatadirs = "RMDir $INSTDIR\\" + deldir + "\n" + deldatadirs
- deldatadirs = "RMDir /r $INSTDIR\\" + deldir + "\\__pycache__\n" + deldatadirs
-
- for f in df:
- deldatafiles += 'Delete \"$INSTDIR\\' + os.path.join(deldir, f) + "\"\n"
-
- #### change to suit install dir ####
- inst_dir = install_base_dir + env['BF_INSTALLDIR']
-
- os.chdir(rel_dir)
-
- ns = open("00.sconsblender.nsi","r")
-
- ns_cnt = str(ns.read())
- ns.close()
-
- # var replacements
- ns_cnt = string.replace(ns_cnt, "[DISTDIR]", os.path.normpath(inst_dir+os.sep))
- ns_cnt = string.replace(ns_cnt, "[VERSION]", VERSION_DISPLAY)
- ns_cnt = string.replace(ns_cnt, "[SHORTVERSION]", VERSION)
- ns_cnt = string.replace(ns_cnt, "[RELDIR]", os.path.normpath(rel_dir))
- ns_cnt = string.replace(ns_cnt, "[BITNESS]", bitness)
-
- # do root
- rootlist = []
- for rootitem in rootdirconts:
- rootlist.append("File \"" + rootitem + "\"")
- rootstring = string.join(rootlist, "\n ")
- rootstring = rootstring
- rootstring += "\n\n"
- ns_cnt = string.replace(ns_cnt, "[ROOTDIRCONTS]", rootstring)
-
-
- # do delete items
- delrootlist = []
- for rootitem in rootdirconts:
- delrootlist.append("Delete $INSTDIR\\" + rootitem[l+1:])
- delrootstring = string.join(delrootlist, "\n ")
- delrootstring += "\n"
- ns_cnt = string.replace(ns_cnt, "[DELROOTDIRCONTS]", delrootstring)
-
- ns_cnt = string.replace(ns_cnt, "[DODATAFILES]", datafiles)
- ns_cnt = string.replace(ns_cnt, "[DELDATAFILES]", deldatafiles)
- ns_cnt = string.replace(ns_cnt, "[DELDATADIRS]", deldatadirs)
-
- tmpnsi = os.path.normpath(install_base_dir+os.sep+env['BF_BUILDDIR']+os.sep+"00.blender_tmp.nsi")
- new_nsis = open(tmpnsi, 'w')
- new_nsis.write(ns_cnt)
- new_nsis.close()
- print "NSIS Installer script created"
-
- os.chdir(start_dir)
- print "Launching 'makensis'"
-
- cmdline = "makensis " + "\""+tmpnsi+"\""
-
- startupinfo = subprocess.STARTUPINFO()
- #startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, startupinfo=startupinfo, shell = True)
- data, err = proc.communicate()
- rv = proc.wait()
-
- if rv != 0:
- print
- print data.strip().split("\n")[-1]
- return rv
-
-def cudakernels_print(target, source, env):
- return "Running cudakernels target"
-
-def cudakernels(target=None, source=None, env=None):
- """
- Builder for cuda kernels compilation. Used by release build environment only
- """
-
- # Currently nothing to do, everything is handled by a dependency resolver
-
- pass
-
-def check_environ():
- problematic_envvars = ""
- for i in os.environ:
- try:
- os.environ[i].decode('ascii')
- except UnicodeDecodeError:
- problematic_envvars = problematic_envvars + "%s = %s\n" % (i, os.environ[i])
- if len(problematic_envvars)>0:
- print("================\n\n")
- print("@@ ABORTING BUILD @@\n")
- print("PROBLEM DETECTED WITH ENVIRONMENT")
- print("---------------------------------\n\n")
- print("A problem with one or more environment variable was found")
- print("Their value contain non-ascii characters. Check the below")
- print("list and override them locally to be ASCII-clean by doing")
- print("'set VARNAME=cleanvalue' on the command-line prior to")
- print("starting the build process:\n")
- print(problematic_envvars)
- return False
- else:
- return True
diff --git a/build_files/scons/tools/crossmingw.py b/build_files/scons/tools/crossmingw.py
deleted file mode 100644
index f97fdf3c15e..00000000000
--- a/build_files/scons/tools/crossmingw.py
+++ /dev/null
@@ -1,184 +0,0 @@
-"""SCons.Tool.gcc
-
-Tool-specific initialization for MinGW (http://www.mingw.org/)
-
-There normally shouldn't be any need to import this module directly.
-It will usually be imported through the generic SCons.Tool.Tool()
-selection method.
-
-"""
-
-#
-# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation
-#
-# 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.
-#
-
-__revision__ = "src/engine/SCons/Tool/mingw.py 4043 2009/02/23 09:06:45 scons"
-
-import os
-import os.path
-import string
-
-import SCons.Action
-import SCons.Builder
-import SCons.Defaults
-import SCons.Tool
-import SCons.Util
-
-# This is what we search for to find mingw:
-prefixes = SCons.Util.Split("""
- mingw32-
- i386-mingw32msvc-
- i486-mingw32msvc-
- i586-mingw32msvc-
- i686-mingw32msvc-
- i686-pc-mingw32-
-""")
-
-def find(env):
- for prefix in prefixes:
- # First search in the SCons path and then the OS path:
- if env.WhereIs(prefix + 'gcc') or SCons.Util.WhereIs(prefix + 'gcc'):
- return prefix
-
- return ''
-
-def shlib_generator(target, source, env, for_signature):
- cmd = SCons.Util.CLVar(['$SHLINK'])
-
- dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
- if dll: cmd.extend(['-o', dll])
-
- cmd.extend(['$SOURCES', '$SHLINKFLAGS', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
-
- implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
- if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature))
-
- def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
- insert_def = env.subst("$WINDOWS_INSERT_DEF")
- if not insert_def in ['', '0', 0] and def_target: \
- cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature))
-
- return [cmd]
-
-def shlib_emitter(target, source, env):
- dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
- no_import_lib = env.get('no_import_lib', 0)
-
- if not dll:
- raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
-
- if not no_import_lib and \
- not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'):
-
- # Append an import library to the list of targets.
- target.append(env.ReplaceIxes(dll,
- 'SHLIBPREFIX', 'SHLIBSUFFIX',
- 'LIBPREFIX', 'LIBSUFFIX'))
-
- # Append a def file target if there isn't already a def file target
- # or a def file source. There is no option to disable def file
- # target emitting, because I can't figure out why someone would ever
- # want to turn it off.
- def_source = env.FindIxes(source, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
- def_target = env.FindIxes(target, 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX')
- if not def_source and not def_target:
- target.append(env.ReplaceIxes(dll,
- 'SHLIBPREFIX', 'SHLIBSUFFIX',
- 'WINDOWSDEFPREFIX', 'WINDOWSDEFSUFFIX'))
-
- return (target, source)
-
-
-shlib_action = SCons.Action.Action(shlib_generator, generator=1)
-
-res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
-
-res_builder = SCons.Builder.Builder(action=res_action, suffix='.o',
- source_scanner=SCons.Tool.SourceFileScanner)
-SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan)
-
-def generate(env):
- mingw = find(env)
- if mingw:
- dir = os.path.dirname(mingw)
- env.PrependENVPath('PATH', dir )
-
-
- # Most of mingw is the same as gcc and friends...
- gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas', 'm4']
- for tool in gnu_tools:
- SCons.Tool.Tool(tool)(env)
-
- #... but a few things differ:
- env['CC'] = mingw + 'gcc'
- env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
- env['CXX'] = mingw + 'g++'
- env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
- env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
- env['SHLINKCOM'] = shlib_action
- env['LDMODULECOM'] = shlib_action
- env.Append(SHLIBEMITTER = [shlib_emitter])
- env['RANLIB'] = mingw + 'ranlib'
- env['LINK'] = mingw + 'gcc'
- env['AS'] = mingw + 'as'
- env['AR'] = mingw + 'ar'
-
- env['WIN32DEFPREFIX'] = ''
- env['WIN32DEFSUFFIX'] = '.def'
- env['WINDOWSDEFPREFIX'] = '${WIN32DEFPREFIX}'
- env['WINDOWSDEFSUFFIX'] = '${WIN32DEFSUFFIX}'
-
- env['SHOBJSUFFIX'] = '.o'
- env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
-
- env['RC'] = mingw + 'windres'
- env['RCFLAGS'] = SCons.Util.CLVar('')
- env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
- env['RCINCPREFIX'] = '--include-dir '
- env['RCINCSUFFIX'] = ''
- env['RCCOM'] = '$RC $_CPPDEFFLAGS $RCINCFLAGS ${RCINCPREFIX} ${SOURCE.dir} $RCFLAGS -i $SOURCE -o $TARGET'
- env['BUILDERS']['RES'] = res_builder
-
- # Some setting from the platform also have to be overridden:
- env['OBJPREFIX'] = ''
- env['OBJSUFFIX'] = '.o'
- env['LIBPREFIX'] = 'lib'
- env['LIBSUFFIX'] = '.a'
- env['SHOBJPREFIX'] = '$OBJPREFIX'
- env['SHOBJSUFFIX'] = '$OBJSUFFIX'
- env['PROGPREFIX'] = ''
- env['PROGSUFFIX'] = '.exe'
- env['LIBPREFIX'] = ''
- env['LIBSUFFIX'] = '.lib'
- env['SHLIBPREFIX'] = ''
- env['SHLIBSUFFIX'] = '.dll'
- env['LIBPREFIXES'] = [ '$LIBPREFIX' ]
- env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ]
-
-def exists(env):
- return find(env)
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/build_files/scons/tools/mstoolkit.py b/build_files/scons/tools/mstoolkit.py
deleted file mode 100644
index 68e8c4b6475..00000000000
--- a/build_files/scons/tools/mstoolkit.py
+++ /dev/null
@@ -1,353 +0,0 @@
-"""tools.mstoolkit
-
-Tool-specific initialization for Microsoft Visual C/C++ Toolkit Commandline
-
-There normally shouldn't be any need to import this module directly.
-It will usually be imported through the generic SCons.Tool.Tool()
-selection method.
-
-"""
-
-#
-# Copyright (c) 2004 John Connors
-#
-# 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.
-#
-
-
-import os.path
-import re
-import string
-import types
-
-import SCons.Action
-import SCons.Builder
-import SCons.Errors
-import SCons.Platform.win32
-import SCons.Tool
-import SCons.Util
-import SCons.Warnings
-
-CSuffixes = ['.c', '.C']
-CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
-
-def get_msvctoolkit_paths():
- """Return a 4-tuple of (INCLUDE, LIB, PATH, TOOLKIT) as the values of those
- three environment variables that should be set in order to execute
- the MSVC .NET tools properly, if the information wasn't available
- from the registry."""
-
- MSToolkitDir = None
- paths = {}
- exe_path = ''
- lib_path = ''
- include_path = ''
-
- # First, we get the shell folder for this user:
- if not SCons.Util.can_read_reg:
- raise SCons.Errors.InternalError, "No Windows registry module was found"
-
- # look for toolkit
- if os.environ.has_key('VCToolkitInstallDir'):
- MSToolkitDir = os.path.normpath(os.environ['VCToolkitInstallDir'])
- else:
- # last resort -- default install location
- MSToolkitDir = r'C:\Program Files\Microsoft Visual C++ Toolkit 2003'
-
- # look for platform sdk
- if os.environ.has_key('MSSdk'):
- PlatformSDKDir = os.path.normpath(os.environ['MSSdk'])
- else:
- try:
- PlatformSDKDir = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\MicrosoftSDK\Directories\Install Dir')[0]
- PlatformSDKDir = str(PlatformSDKDir)
- except SCons.Util.RegError:
- raise SCons.Errors.InternalError, "The Platform SDK directory was not found in the registry or in the `MSSdk` environment variable."
-
- # look for DX Sdk (expecting DX9)
- # dxsdk docs have a directory key, look for it, extract path
- #dxsdkdocs = ""
- DXsdkDir = ""
- #try:
- # dxsdkdocs = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\DirectX SDK\DX9SDK Doc Path')
- #except SCons.Util.RegError:
- # raise SCons.Errors.InternalError, "The DXSDK directory was not found in the registry."
- if os.environ.has_key('DXSDK_DIR'):
- DXsdkDir = os.path.normpath(os.environ['DXSDK_DIR'])
-
- #DXsdkDir = os.path.split(dxsdkdocs[0])[0]
- DXsdkDir = os.path.split(DXsdkDir)[0]
-
- include_path = r'%s\include;%s\include;%s\include' % (MSToolkitDir, PlatformSDKDir, DXsdkDir)
- lib_path = r'%s\lib;%s\lib;%s\lib' % (MSToolkitDir, PlatformSDKDir, DXsdkDir)
- exe_path = r'%s\bin;%s\bin\win95;%s\bin' % (MSToolkitDir, PlatformSDKDir, PlatformSDKDir)
- return (include_path, lib_path, exe_path, PlatformSDKDir)
-
-def validate_vars(env):
- """Validate the PDB, PCH, and PCHSTOP construction variables."""
- if env.has_key('PCH') and env['PCH']:
- if not env.has_key('PCHSTOP'):
- raise SCons.Errors.UserError, "The PCHSTOP construction must be defined if PCH is defined."
- if not SCons.Util.is_String(env['PCHSTOP']):
- raise SCons.Errors.UserError, "The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']
-
-def pch_emitter(target, source, env):
- """Sets up the PDB dependencies for a pch file, and adds the object
- file target."""
-
- validate_vars(env)
-
- pch = None
- obj = None
-
- for t in target:
- if SCons.Util.splitext(str(t))[1] == '.pch':
- pch = t
- if SCons.Util.splitext(str(t))[1] == '.obj':
- obj = t
-
- if not obj:
- obj = SCons.Util.splitext(str(pch))[0]+'.obj'
-
- target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
-
- if env.has_key('PDB') and env['PDB']:
- env.SideEffect(env['PDB'], target)
- env.Precious(env['PDB'])
-
- return (target, source)
-
-def object_emitter(target, source, env, parent_emitter):
- """Sets up the PDB and PCH dependencies for an object file."""
-
- validate_vars(env)
-
- parent_emitter(target, source, env)
-
- if env.has_key('PDB') and env['PDB']:
- env.SideEffect(env['PDB'], target)
- env.Precious(env['PDB'])
-
- if env.has_key('PCH') and env['PCH']:
- env.Depends(target, env['PCH'])
-
- return (target, source)
-
-def static_object_emitter(target, source, env):
- return object_emitter(target, source, env,
- SCons.Defaults.StaticObjectEmitter)
-
-def shared_object_emitter(target, source, env):
- return object_emitter(target, source, env,
- SCons.Defaults.SharedObjectEmitter)
-
-pch_builder = SCons.Builder.Builder(action='$PCHCOM', suffix='.pch', emitter=pch_emitter)
-res_builder = SCons.Builder.Builder(action='$RCCOM', suffix='.res')
-
-def pdbGenerator(env, target, source, for_signature):
- if target and env.has_key('PDB') and env['PDB']:
- return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature),
- '/DEBUG']
-
-def win32ShlinkTargets(target, source, env, for_signature):
- listCmd = []
- dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
- if dll: listCmd.append("/out:%s"%dll.get_string(for_signature))
-
- implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
- if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature))
-
- return listCmd
-
-def win32ShlinkSources(target, source, env, for_signature):
- listCmd = []
-
- deffile = env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX")
- for src in source:
- if src == deffile:
- # Treat this source as a .def file.
- listCmd.append("/def:%s" % src.get_string(for_signature))
- else:
- # Just treat it as a generic source file.
- listCmd.append(src)
- return listCmd
-
-def win32LibEmitter(target, source, env):
- # SCons.Tool.msvc.validate_vars(env)
-
- dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
- no_import_lib = env.get('no_import_lib', 0)
-
- if not dll:
- raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
-
- if env.get("WIN32_INSERT_DEF", 0) and \
- not env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX"):
-
- # append a def file to the list of sources
- source.append(env.ReplaceIxes(dll,
- "SHLIBPREFIX", "SHLIBSUFFIX",
- "WIN32DEFPREFIX", "WIN32DEFSUFFIX"))
-
- if env.has_key('PDB') and env['PDB']:
- env.SideEffect(env['PDB'], target)
- env.Precious(env['PDB'])
-
- if not no_import_lib and \
- not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
- # Append an import library to the list of targets.
- target.append(env.ReplaceIxes(dll,
- "SHLIBPREFIX", "SHLIBSUFFIX",
- "LIBPREFIX", "LIBSUFFIX"))
- # and .exp file is created if there are exports from a DLL
- target.append(env.ReplaceIxes(dll,
- "SHLIBPREFIX", "SHLIBSUFFIX",
- "WIN32EXPPREFIX", "WIN32EXPSUFFIX"))
-
- return (target, source)
-
-def prog_emitter(target, source, env):
- #SCons.Tool.msvc.validate_vars(env)
-
- if env.has_key('PDB') and env['PDB']:
- env.SideEffect(env['PDB'], target)
- env.Precious(env['PDB'])
-
- return (target,source)
-
-def RegServerFunc(target, source, env):
- if env.has_key('register') and env['register']:
- ret = regServerAction([target[0]], [source[0]], env)
- if ret:
- raise SCons.Errors.UserError, "Unable to register %s" % target[0]
- else:
- print "Registered %s sucessfully" % target[0]
- return ret
- return 0
-
-regServerAction = SCons.Action.Action("$REGSVRCOM")
-regServerCheck = SCons.Action.Action(RegServerFunc, None)
-shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK_TARGETS $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $_SHLINK_SOURCES")}')
-compositeLinkAction = shlibLinkAction + regServerCheck
-
-def generate(env):
- """Add Builders and construction variables for MSVC++ to an Environment."""
- static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
-
- for suffix in CSuffixes:
- static_obj.add_action(suffix, SCons.Defaults.CAction)
- shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
-
- for suffix in CXXSuffixes:
- static_obj.add_action(suffix, SCons.Defaults.CXXAction)
- shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction)
-
- SCons.Tool.createStaticLibBuilder(env)
- SCons.Tool.createSharedLibBuilder(env)
- SCons.Tool.createProgBuilder(env)
-
- env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Zi /Fd%s"%File(PDB)) or ""}'])
- env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
- env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
- env['CC'] = 'cl'
- env['CCFLAGS'] = SCons.Util.CLVar('/nologo')
- env['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS'
- env['SHCC'] = '$CC'
- env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
- env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS'
- env['CXX'] = '$CC'
- env['CXXFLAGS'] = SCons.Util.CLVar('$CCFLAGS $( /TP $)')
- env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
- env['SHCXX'] = '$CXX'
- env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
- env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS'
- env['CPPDEFPREFIX'] = '/D'
- env['CPPDEFSUFFIX'] = ''
- env['INCPREFIX'] = '/I'
- env['INCSUFFIX'] = ''
- env['OBJEMITTER'] = static_object_emitter
- env['SHOBJEMITTER'] = shared_object_emitter
- env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
-
- env['RC'] = 'rc'
- env['RCFLAGS'] = SCons.Util.CLVar('')
- env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
- CScan = env.get_scanner('.c')
- if CScan:
- CScan.add_skey('.rc')
- env['BUILDERS']['RES'] = res_builder
-
- include_path, lib_path, exe_path, sdk_path = get_msvctoolkit_paths()
- env.PrependENVPath('INCLUDE', include_path)
- env.PrependENVPath('LIB', lib_path)
- env.PrependENVPath('PATH', exe_path)
-
- env['ENV']['CPU'] = 'i386'
- env['ENV']['MSSDK'] = sdk_path
- env['ENV']['BkOffice'] = sdk_path
- env['ENV']['Basemake'] = sdk_path + "\\Include\\BKOffice.Mak"
- env['ENV']['INETSDK'] = sdk_path
- env['ENV']['MSSDK'] = sdk_path
- env['ENV']['MSTOOLS'] = sdk_path
- env['ENV']['TARGETOS'] = 'WINNT'
- env['ENV']['APPVER'] = '5.0'
-
- env['CFILESUFFIX'] = '.c'
- env['CXXFILESUFFIX'] = '.cc'
-
- env['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS'
- env['BUILDERS']['PCH'] = pch_builder
-
- env['AR'] = 'lib.exe' #'"' +sdk_path + '\\bin\\Win64\\lib.exe"'
- env['ARFLAGS'] = SCons.Util.CLVar('/nologo')
- env['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
-
- env['SHLINK'] = '$LINK'
- env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll')
- env['_SHLINK_TARGETS'] = win32ShlinkTargets
- env['_SHLINK_SOURCES'] = win32ShlinkSources
- env['SHLINKCOM'] = compositeLinkAction
- env['SHLIBEMITTER']= win32LibEmitter
- env['LINK'] = 'link.exe' #'"' +sdk_path + '\\bin\\Win64\\' + 'link.exe"'
- env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
- env['_PDB'] = pdbGenerator
- env["TEMPFILE"] = SCons.Platform.win32.TempFileMunge
- env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $SOURCES")}'
- env['PROGEMITTER'] = prog_emitter
- env['LIBDIRPREFIX']='/LIBPATH:'
- env['LIBDIRSUFFIX']=''
- env['LIBLINKPREFIX']=''
- env['LIBLINKSUFFIX']='$LIBSUFFIX'
-
- env['WIN32DEFPREFIX'] = ''
- env['WIN32DEFSUFFIX'] = '.def'
- env['WIN32_INSERT_DEF'] = 0
-
- env['WIN32EXPPREFIX'] = ''
- env['WIN32EXPSUFFIX'] = '.exp'
-
- env['REGSVRACTION'] = regServerCheck
- env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
- env['REGSVRFLAGS'] = '/s '
- env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET'
-
-
-def exists(env):
- return env.Detect('cl')
diff --git a/doc/build_systems/scons-dev.txt b/doc/build_systems/scons-dev.txt
deleted file mode 100644
index 9ca072c38c5..00000000000
--- a/doc/build_systems/scons-dev.txt
+++ /dev/null
@@ -1,193 +0,0 @@
-
- Internals of Blenders SCons scripts
- ===================================
-
- Scope
- ------
- This document describes the architecture of the SCons scripts for
- Blender. An overview of available functionality and how to modify,
- extend and maintain the system.
-
- Audience
- --------
- This document is for developers who need to modify the system,
- ie. add or remove new libraries, add new arguments for SCons, etc.
-
- Files and their meaning
- -----------------------
-
- The main entry point for the build system is the SConstruct-file in
- $BLENDERHOME. This file creates the first BlenderEnvironment to work
- with, reads in options, and sets up some directory structures. Further
- it defines some targets.
-
- Platform-specific configurations are in $BLENDERHOME/config. The
- filenames have the form (platform)-config.py, where platform one of:
-
- * darwin
- * linux
- * win32-mingw
- * win32-vc
-
- The user can override options by creating a file
- $BLENDERHOME/user-config.py. It can have any option from
- (platform)-config.py. Options in this file will override the platform
- defaults.
-
- Much of the actual functionality can be found in the python scripts
- in the directory $BLENDERHOME/build_files/scons/tools, with
- Blender.py defining the bulk of the functionality. btools.py has some
- helper functions, and bcolors.py is for the terminal
- colors. mstoolkit.py and crossmingw.py are modules which set up SCons
- for the MS VC++ 2003 toolkit and the cross-compile toolset for
- compiling Windows binaries on Linux respectively. Note: the
- cross-compile doesn't work yet for Blender, but is added in
- preparation for having it work in the distant future.
-
- BlenderEnvironment
- ------------------
-
- The module Blender.py implements a BlenderEnvironment class, derived
- from the SConsEnvironment of SCons. This is done to wrap some often
- used functionality. The BlenderEnvironment offers two important
- wrappers: BlenderProg() and BlenderLib(). The first one is used to
- specify a binary to be built, the second one is used to specify what
- static library is built from given sources.
-
- Build a static library called "somelib". The system handles library
- pre- and suffixes automatically, you don't need to bother yourself
- with these details:
-
- env = BlenderEnvironment(ENV = os.environ) # create an environment
- env.BlenderLib(libname="somelib", sources=['list.c','with.c','sources.c'],
- includes=['/list/with/include/paths', '.', '..'],
- defines=['LIST_WITH', 'CPP_DEFINES', 'TO_USE'],
- libtype=['blender', 'common'] # this is a list with libtypes. Normally you don't
- # need to specify this, but if you encounter linking
- # problems you may need this
- priority=[10, 20] # Priorities, list as long as libtype, priority per type
- compileflags=['/O2'] # List of compile flags needed for this particular library.
- # used only in rare cases, like SOLID, qhull and Bullet
- )
-
- There should be no need to ever add an extra BlenderProg to the
- existing ones in SConstruct, see that file for its use, and Blender.py
- for its implementation.
-
- The new system works so that using these wrappers, has all libraries
- (and programs) register with a central repository. This means that
- adding a new library is as easy as just creating the new SConscript
- and making sure that it gets called properly. Linking and such will
- then be handled automatically.
-
- If you want that adding new source files for a certain library
- is handled automatically, you can use the Glob() function from
- the BlenderEnvironment to create lists of needed files. See
- $BLENDERHOME/source/blender/src/SConscript for an example. Keep in
- mind that this will add any new file that complies to the rule given
- to the Glob() function. There are a few (external) libraries with
- which this can't be used, because it'd take files that shouldn't be
- compiled, and create subsequentially problems during the linking stage
- (like SOLID, qhull, Bullet).
-
- Linking order and priorities
- ----------------------------
-
- As shown above, you can give a library a priority in a certain
- group. If you need to make sure that a Blender library is linked
- before or after another one, you can give it a priority. To debug
- the priorities us BF_PRIORITYLIST=1 on the command-line while running
- a build.
-
- % scons BF_PRIORITYLIST=1
-
- This will give a list with values suggested by the system. Make
- changes to all SConscripts in question to reflect or change the
- values given by this command. ALWAYS check this after adding a new
- internal, external library or core library, and make sure there are
- sane values. You can use large and negative numbers to test with,
- but after you've got a working linking order, do change the system
- to reflect BF_PRIORITYLIST values.
-
- Also, if you find that a library needs to be given multiple times to
- the linker, you can do that by giving a python list with the names
- of the available library types. They are currently:
-
- B.possible_types = ['core', 'common', 'blender', 'intern',
- 'international', 'game', 'game2',
- 'player', 'player2', 'system']
-
- More groups can be added, but that should be carefully considered,
- as it may lead to large-scale changes. The current amount of libraries
- should suffice.
-
- The central repository is utilised in the SConstruct in two
- ways. Firstly, it is used to determine the order of all static
- libraries to link into the main Blender executable. Secondly, it
- is used to keep track of all built binaries and their location,
- so that they can be properly copied to BF_INSTALLDIR.
-
- The libraries can be fetched in their priority order with
- create_blender_liblist from Blender.py, see the SConstruct on how
- it is used.
-
- The program repository is the global list program_list from
- Blender.py. See SConstruct for its usage.
-
-
- Adding a new option and libraries
- ---------------------------------
-
- Lets say we want to add WITH_BF_NEWLIB, which will
- enable or disable a new feature library with sources in
- $BLENDERHOME/source/blender/newlib. This 'newlib' needs external
- headers from a 3rd party library '3rdparty'. For this we want to
- add a set of options BF_3RDPARTY, BF_3RDPARTY_INC, BF_3RDPARTY_LIB,
- BF_3RDPARTY_LIBPATH:
-
- 1) Add all mentiond options to all (platform)-config.py
- files. WITH_BF_NEWLIB is a boolean option ('true', 'false'),
- the rest are strings with paths and library names. See the
- OpenEXR options for example.
-
- 2) Add all options to the argument checking function
- validate_arguments() in btools.py. See again OpenEXR options
- for example.
-
- 3) Add all options to the option reading function read_opts()
- in btools.py. See again OpenEXR options for example. All default
- values can be empty, as the actual default values are in the
- (platform)-config.py files.
-
- 4) Add BF_3RDPARTY_LIB to the function setup_syslibs()
- and BF_3RDPARTY_LIBPATH to the function setup_staticlibs()
- in Blender.py
-
- At this stage we have prepared all option setting and linking needs,
- but we still need to add in the compiling of the 'newlib'.
-
- 5) Create a SConscript in $BLENDERHOME/source/blender/newlib. Look
- at ie. $BLENDERHOME/source/blender/src/SConscript for
- template. The new SConscript will register the new library
- like so:
-
- env.BlenderLib(libname='newlib', sources=sourcefiles, includes=incs) # the rest of the arguments get defaults = empty lists and values
-
- 6) Edit $BLENDERHOME/source/blender/SConscript with the following
- addition:
-
- if env['WITH_BF_NEWLIB'] == 1:
- SConscript(['newlib/SConscript'])
-
- After this you can see if this works by trying to build:
-
- % scons WITH_BF_NEWLIB=1 # build with newlib
- % scons WITH_BF_NEWLIB=0 # disable newlib
-
- This is all what should be needed. Changing the library name doesn't
- need changes elsewhere in the system, as it is handled automatically
- with the central library repository.
-
- Enjoy the new system!!
-
- /Nathan Letwory (jesterKing)
diff --git a/doc/build_systems/scons.txt b/doc/build_systems/scons.txt
deleted file mode 100644
index e3438f1fe04..00000000000
--- a/doc/build_systems/scons.txt
+++ /dev/null
@@ -1,227 +0,0 @@
-
- Blenders SCons build scripts
- ============================
-
- Introduction
- ------------
-
- Since the beginning of 2004 Blender has had the SCons system as a
- build option. SCons is a Python-based, accurate build system. The
- scripts that were implemented in the first iteration worked, but
- the system grew quickly into such a state that maintaining it became
- a nightmare, and adding new features was just horrible, leading to
- many hacks without much sense in the overall structure.
-
- The rewrite has been waiting for a long time. Jonathan Jacobs provided
- a first overhaul of the scripts, which I used in the first phase of
- the rewrite. To make the system as maintainable as possible I made
- some radical changes, but thanks go to Jonathan for providing me
- with the patch to get started.
-
- This document describes the usage of the new SCons scripts. The
- inner workings are described in scons-dev.txt.
-
- Building Blender
- ----------------
-
- To build Blender with the SCons scripts you need a full Python
- install, version 2.4 or later (http://www.python.org). We already provide
- a scons-local installation, which can be found in the scons/ subdirectory.
- This document uses the scons-local installation for its examples.
-
- For build instructions, including dependencies, consult the appropriate
- section for your platform at
- http://wiki.blender.org/index.php/Dev:Doc/Building_Blender. Note that for
- windows many of these dependencies already come in the lib/windows module
- from CVS.
-
- In the base directory of the sources (from now on called $BLENDERHOME)
- you'll see a file named SConstruct. This is the entry point for the
- SCons build system. In a terminal, change to this directory. To just
- build, start the SCons entry script on Windows (will be used for the remainder
- of this document):
-
- % python scons\scons.py
-
- On a Unix-compatible system it would be
-
- % python ./scons/scons.py
-
- This will start the build process with default values. Depending
- on your platform you may see color in your output (non-Windows
- machines). In the the beginning an overview of targets and arguments
- from the command-line is given, then all libraries and binaries to
- build are configured.
-
- The build uses BF_BUILDDIR to build into and BF_INSTALLDIR to finally copy
- all needed files to get a proper setup. The BF_DOCDIR is used to generate
- Blender Python documentation files to. These variables have default values
- for every platform in
- $BLENDERHOME/build_files/scons/config/(platform)-config.py. See the next
- section of this document for how to customize these paths. After the build
- successfully completes, you can find everything you need in BF_INSTALLDIR.
-
- If you want to create the installer package of Blender on Windows you'll
- need to install nullsoft scriptable install system from http://nsis.sf.net.
- As an extra dependency, you need the MoreInfo plugin too. The creation of
- the installer is tied into the build process and can be triggered with:
-
- % python scons\scons.py nsis
-
-
- Configuring the build
- ---------------------
-
- The default values for your platform can be found in the directory
- $BLENDERHOME/build_files/scons/config. Your platform specific defaults are
- in (platform)-config.py, where platform is one of:
-
- - linux, for machines running Linux
- - win32-vc, for Windows machines, compiling with a Microsoft compiler
- - win32-mingw, for Windows machines, compiling with the MingW compiler
- - darwin, for OS X machines
- (TBD: add cygwin, solaris and freebsd support)
-
- These files you will normally not change. If you need to override a
- default value, make a file called $BLENDERHOME/user-config.py, and copy
- settings from the build_files/scons/config/(platform)-config.py that you
- want to change. Don't copy the entire file (unless explicitly stated in
- the configuration file), because you may not get updated options you don't
- change yourself, which may result in build errors. You should NEVER have
- to modify $BLENDERHOME/build_files/scons/config/(platform)-config.py.
-
- You can use BF_CONFIG argument to override the default user-config.py
- check. This is just like the user-config.py, but just with another name:
-
- % python scons\scons.py BF_CONFIG=myownsettings
-
- If you want to quickly test a new setting, you can give the option
- also on the command-line:
-
- % python scons\scons.py BF_BUILDDIR=../mybuilddir WITH_BF_OPENEXR=0
-
- This command sets the build directory to BF_BUILDDIR and disables
- OpenEXR support.
-
- If you need to know what can be set through the command-line, run
- scons with -h:
-
- % python scons\scons.py -h
-
- This command will print a long list with settable options and what
- every option means. Many of the default values will be empty, and
- from a fresh checkout without a user-config.py the actual values
- are the defaults as per $BLENDERHOME/config/(platform)-config.py
- (unless you have overridden any of them in your
- $BLENDERHOME/user-config.py).
-
- Configuring the output
- ----------------------
-
- This rewrite features a cleaner output during the build process. If
- you need to see the full command-line for compiles, then you can
- change that behaviour. Also the use of colors can be changed:
-
- % python scons\scons.py BF_FANCY=0
-
- This will disable the use of colors.
-
- % python scons\scons.py BF_QUIET=0
-
- This will give the old, noisy output. Every command-line per
- compile is printed out in its full glory. This is very useful when
- debugging problems with compiling, because you can see what the
- included paths are, what defines are given on the command-line,
- what compiler switches are used, etc.
-
- Compiling Only Some Libraries
- -----------------------------
-
- Our implementation now has support for specifying a list of libraries that are
- exclusively compiled, ignoring all other libraries. This is invoked
- with the BF_QUICK arguments; for example:
-
- % python scons\scons.py BF_QUICK=src,bf_blenkernel
-
- Note that this not the same as passing a list of folders as in the
- makefile's "quicky" command. In Scons, all of Blender's code modules
- are in their own static library; this corresponds to one-lib-per-folder
- in some cases (especially in blender/source/blender).
-
- To obtain a list of the libraries, simple fire up scons and CTRL-C out once
- it finishes configuring (and printing to the console) the library list.
-
- Compiling Libraries With Debug Profiling
- ----------------------------------------
-
- Scons has support for specifying a list of libraries that are compiled
- with debug profiling enabled. This is implemented in two commands:
- BF_QUICKDEBUG which is a command-line argument and BF_DEBUG_LIBS, which goes
- in your user-config.py
-
- BF_QUICKDEBUG is similar to BF_QUICK:
-
- % python scons\scons.py BF_QUICKDEBUG=src,bf_blenkernel,some-other-lib
-
- To use BF_DEBUG_LIBS, put something like the following in you user-config.py:
-
- BF_DEBUG_LIBS = ['bf_blenlib', 'src', 'some_lib']
-
- For instructions on how to find the names of the libraries (folders) you
- wish to use, see the above section. Note that the command BF_DEBUG
- (see below) will override these settings and compile ALL of Blender with
- debug symbols. Also note that BF_QUICKDEBUG and BF_DEBUG_LIBS are combined;
- for example, setting BF_QUICKDEBUG won't overwrite the contents of BF_DEBUG_LIBS.
-
- Supported toolset
- -----------------
-
- WINDOWS
-
- * msvc, this is a full install of Microsoft Visual C++. You'll
- likely have the .NET Framework SDK, Platform SDK and DX9 SDK
- installed * mstoolkit, this is the free MS VC++ 2003 Toolkit. You
- need to verify you have also the SDKs installed as mentioned
- for msvc. * mingw, this is a minimal MingW install. TBD: write
- proper instructions on getting needed packages.
-
- On Windows with all of the three toolset installed you need to
- specify what toolset to use
-
- % python scons\scons.py BF_TOOLSET=msvc
- % python scons\scons.py BF_TOOLSET=mingw
-
- LINUX and OS X
-
- Currently only the default toolsets are supported for these platforms,
- so nothing special needs to be told to SCons when building. The
- defaults should work fine in most cases.
-
- Examples
- --------
-
- Build Blender with the defaults:
-
- % python scons\scons.py
-
- Build Blender, but disable OpenEXR support:
-
- % python scons\scons.py WITH_BF_OPENEXR=0
-
- Build Blender, enable debug symbols:
-
- % python scons\scons.py BF_DEBUG=1
-
- Build Blender, install to different directory:
-
- % python scons\scons.py BF_INSTALLDIR=../myown/installdir
-
- Build Blender in ../myown/builddir and install to ../myown/installdir:
-
- % python scons\scons.py BF_BUILDDIR=../myown/builddir BF_INSTALLDIR=../myown/installdir
-
- Clean BF_BUILDDIR:
-
- % python scons\scons.py clean
-
- /Nathan Letwory (jesterKing)
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index 153c7983ee5..b34d4dfe6f1 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.9.1
+# Doxyfile 1.8.11
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -351,7 +351,14 @@ IDL_PROPERTY_SUPPORT = YES
# all members of a group must be documented explicitly.
# The default value is: NO.
-DISTRIBUTE_GROUP_DOC = YES
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
@@ -742,6 +749,12 @@ WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated
@@ -765,7 +778,7 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = doxygen.main.h \
@@ -787,12 +800,17 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
FILE_PATTERNS =
@@ -881,6 +899,10 @@ IMAGE_PATH =
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
INPUT_FILTER =
@@ -890,6 +912,10 @@ INPUT_FILTER =
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
FILTER_PATTERNS =
@@ -913,7 +939,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
-# USE_MDFILE_AS_MAINPAGE =
+USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@@ -1148,8 +1174,9 @@ HTML_COLORSTYLE_GAMMA = 79
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
@@ -1623,9 +1650,12 @@ COMPACT_LATEX = NO
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1728,6 +1758,14 @@ LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -2227,7 +2265,8 @@ INCLUDED_BY_GRAPH = NO
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2238,7 +2277,8 @@ CALL_GRAPH = NO
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2261,11 +2301,15 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
-# Possible values are: png, jpg, gif and svg.
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
diff --git a/doc/doxygen/doxygen.extern.h b/doc/doxygen/doxygen.extern.h
index 6c6872ff53f..27b53ad24ab 100644
--- a/doc/doxygen/doxygen.extern.h
+++ b/doc/doxygen/doxygen.extern.h
@@ -11,6 +11,10 @@
*
*/
+/** \defgroup curve_fit Curve Fitting Library
+ * \ingroup extern
+ */
+
/** \defgroup bullet Bullet Physics Library
* \ingroup extern
* \see \ref bulletdoc
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index 2c8ecae0ead..e3cc11b3404 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -38,7 +38,7 @@
* \ingroup intern
*/
-/** \defgroup opennl opennl
+/** \defgroup eigen eigen
* \ingroup intern
*/
diff --git a/doc/python_api/examples/bpy.app.translations.py b/doc/python_api/examples/bpy.app.translations.py
index 01d5a987215..6ea749c7e1e 100644
--- a/doc/python_api/examples/bpy.app.translations.py
+++ b/doc/python_api/examples/bpy.app.translations.py
@@ -3,6 +3,7 @@ Intro
-----
.. warning::
+
Most of this object should only be useful if you actually manipulate i18n stuff from Python.
If you are a regular addon, you should only bother about :const:`contexts` member,
and the :func:`register`/:func:`unregister` functions! The :func:`pgettext` family of functions
@@ -12,12 +13,12 @@ Intro
| ``{locale: {msg_key: msg_translation, ...}, ...}``
| where:
-* locale is either a lang iso code (e.g. ``fr``), a lang+country code (e.g. ``pt_BR``),
+- locale is either a lang iso code (e.g. ``fr``), a lang+country code (e.g. ``pt_BR``),
a lang+variant code (e.g. ``sr@latin``), or a full code (e.g. ``uz_UZ@cyrilic``).
-* msg_key is a tuple (context, org message) - use, as much as possible, the predefined :const:`contexts`.
-* msg_translation is the translated message in given language!
+- msg_key is a tuple (context, org message) - use, as much as possible, the predefined :const:`contexts`.
+- msg_translation is the translated message in given language!
-Then, call ``bpy.app.translations.register(__name__, your_dict)`` in your ``register()`` function, and \n"
+Then, call ``bpy.app.translations.register(__name__, your_dict)`` in your ``register()`` function, and
``bpy.app.translations.unregister(__name__)`` in your ``unregister()`` one.
The ``Manage UI translations`` addon has several functions to help you collect strings to translate, and
diff --git a/doc/python_api/examples/bpy.ops.1.py b/doc/python_api/examples/bpy.ops.1.py
index b4137e5c740..7fdde453abe 100644
--- a/doc/python_api/examples/bpy.ops.1.py
+++ b/doc/python_api/examples/bpy.ops.1.py
@@ -10,9 +10,15 @@ The context overrides are passed as a dictionary, with keys matching the context
member names in bpy.context.
For example to override ``bpy.context.active_object``,
you would pass ``{'active_object': object}``.
+
+.. note::
+
+ You will nearly always want to use a copy of the actual current context as basis
+ (otherwise, you'll have to find and gather all needed data yourself).
"""
# remove all objects in scene rather than the selected ones
import bpy
-override = {'selected_bases': list(bpy.context.scene.object_bases)}
+override = bpy.context.copy()
+override['selected_bases'] = list(bpy.context.scene.object_bases)
bpy.ops.object.delete(override)
diff --git a/doc/python_api/examples/bpy.types.BlendDataLibraries.write.py b/doc/python_api/examples/bpy.types.BlendDataLibraries.write.py
new file mode 100644
index 00000000000..3b5f8bd642b
--- /dev/null
+++ b/doc/python_api/examples/bpy.types.BlendDataLibraries.write.py
@@ -0,0 +1,18 @@
+import bpy
+
+filepath = "//new_library.blend"
+
+# write selected objects and their data to a blend file
+data_blocks = set(bpy.context.selected_objects)
+bpy.data.libraries.write(filepath, data_blocks)
+
+
+# write all meshes starting with a capital letter and
+# set them with fake-user enabled so they aren't lost on re-saving
+data_blocks = {mesh for mesh in bpy.data.meshes if mesh.name[:1].isupper()}
+bpy.data.libraries.write(filepath, data_blocks, fake_user=True)
+
+
+# write all materials, textures and node groups to a library
+data_blocks = {*bpy.data.materials, *bpy.data.textures, *bpy.data.node_groups}
+bpy.data.libraries.write(filepath, data_blocks)
diff --git a/doc/python_api/examples/bpy.types.Menu.3.py b/doc/python_api/examples/bpy.types.Menu.3.py
new file mode 100644
index 00000000000..47c81366db4
--- /dev/null
+++ b/doc/python_api/examples/bpy.types.Menu.3.py
@@ -0,0 +1,80 @@
+"""
+Preset Menus
+++++++++++++
+
+Preset menus are simply a convention that uses a menu sub-class
+to perform the common task of managing presets.
+
+This example shows how you can add a preset menu.
+
+This example uses the object draw options,
+however you can use properties defined by your own scripts too.
+"""
+
+import bpy
+from bpy.types import Operator, Menu
+from bl_operators.presets import AddPresetBase
+
+
+class OBJECT_MT_draw_presets(Menu):
+ bl_label = "Object Draw Presets"
+ preset_subdir = "object/draw"
+ preset_operator = "script.execute_preset"
+ draw = Menu.draw_preset
+
+
+class AddPresetObjectDraw(AddPresetBase, Operator):
+ '''Add a Object Draw Preset'''
+ bl_idname = "camera.object_draw_preset_add"
+ bl_label = "Add Object Draw Preset"
+ preset_menu = "OBJECT_MT_draw_presets"
+
+ # variable used for all preset values
+ preset_defines = [
+ "obj = bpy.context.object"
+ ]
+
+ # properties to store in the preset
+ preset_values = [
+ "obj.draw_type",
+ "obj.show_bounds",
+ "obj.draw_bounds_type",
+ "obj.show_name",
+ "obj.show_axis",
+ "obj.show_wire",
+ ]
+
+ # where to store the preset
+ preset_subdir = "object/draw"
+
+
+# Draw into an existing panel
+def panel_func(self, context):
+ layout = self.layout
+
+ row = layout.row(align=True)
+ row.menu(OBJECT_MT_draw_presets.__name__, text=OBJECT_MT_draw_presets.bl_label)
+ row.operator(AddPresetObjectDraw.bl_idname, text="", icon='ZOOMIN')
+ row.operator(AddPresetObjectDraw.bl_idname, text="", icon='ZOOMOUT').remove_active = True
+
+
+classes = (
+ OBJECT_MT_draw_presets,
+ AddPresetObjectDraw,
+ )
+
+
+def register():
+ for cls in classes:
+ bpy.utils.register_class(cls)
+ bpy.types.OBJECT_PT_display.prepend(panel_func)
+
+
+def unregister():
+ for cls in classes:
+ bpy.utils.unregister_class(cls)
+ bpy.types.OBJECT_PT_display.remove(panel_func)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/doc/python_api/examples/bpy.types.Menu.py b/doc/python_api/examples/bpy.types.Menu.py
index c2162444055..295c108abe3 100644
--- a/doc/python_api/examples/bpy.types.Menu.py
+++ b/doc/python_api/examples/bpy.types.Menu.py
@@ -9,9 +9,11 @@ Notice the 'CATEGORY_MT_name' in :class:`Menu.bl_idname`, this is a naming
convention for menus.
.. note::
+
Menu subclasses must be registered before referencing them from blender.
.. note::
+
Menus have their :class:`Layout.operator_context` initialized as
'EXEC_REGION_WIN' rather than 'INVOKE_DEFAULT' (see :ref:`Execution Context <operator-execution_context>`).
If the operator context needs to initialize inputs from the
diff --git a/doc/python_api/examples/bpy.types.RenderEngine.py b/doc/python_api/examples/bpy.types.RenderEngine.py
index 7af7de1068c..efb7640bcc7 100644
--- a/doc/python_api/examples/bpy.types.RenderEngine.py
+++ b/doc/python_api/examples/bpy.types.RenderEngine.py
@@ -9,8 +9,8 @@ import bpy
class CustomRenderEngine(bpy.types.RenderEngine):
# These three members are used by blender to set up the
# RenderEngine; define its internal name, visible name and capabilities.
- bl_idname = 'custom_renderer'
- bl_label = 'Flat Color Renderer'
+ bl_idname = "custom_renderer"
+ bl_label = "Flat Color Renderer"
bl_use_preview = True
# This is the only method called by blender, in this example
@@ -21,7 +21,7 @@ class CustomRenderEngine(bpy.types.RenderEngine):
self.size_x = int(scene.render.resolution_x * scale)
self.size_y = int(scene.render.resolution_y * scale)
- if scene.name == 'preview':
+ if self.is_preview:
self.render_preview(scene)
else:
self.render_scene(scene)
@@ -36,7 +36,7 @@ class CustomRenderEngine(bpy.types.RenderEngine):
# Here we write the pixel values to the RenderResult
result = self.begin_result(0, 0, self.size_x, self.size_y)
- layer = result.layers[0]
+ layer = result.layers[0].passes["Combined"]
layer.rect = green_rect
self.end_result(result)
@@ -50,21 +50,37 @@ class CustomRenderEngine(bpy.types.RenderEngine):
# Here we write the pixel values to the RenderResult
result = self.begin_result(0, 0, self.size_x, self.size_y)
- layer = result.layers[0]
+ layer = result.layers[0].passes["Combined"]
layer.rect = blue_rect
self.end_result(result)
-# Register the RenderEngine
-bpy.utils.register_class(CustomRenderEngine)
-# RenderEngines also need to tell UI Panels that they are compatible
-# Otherwise most of the UI will be empty when the engine is selected.
-# In this example, we need to see the main render image button and
-# the material preview panel.
-from bl_ui import properties_render
-properties_render.RENDER_PT_render.COMPAT_ENGINES.add('custom_renderer')
-del properties_render
+def register():
+ # Register the RenderEngine
+ bpy.utils.register_class(CustomRenderEngine)
-from bl_ui import properties_material
-properties_material.MATERIAL_PT_preview.COMPAT_ENGINES.add('custom_renderer')
-del properties_material
+ # RenderEngines also need to tell UI Panels that they are compatible
+ # Otherwise most of the UI will be empty when the engine is selected.
+ # In this example, we need to see the main render image button and
+ # the material preview panel.
+ from bl_ui import (
+ properties_render,
+ properties_material,
+ )
+ properties_render.RENDER_PT_render.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
+ properties_material.MATERIAL_PT_preview.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname)
+
+
+def unregister():
+ bpy.utils.unregister_class(CustomRenderEngine)
+
+ from bl_ui import (
+ properties_render,
+ properties_material,
+ )
+ properties_render.RENDER_PT_render.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
+ properties_material.MATERIAL_PT_preview.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/doc/python_api/examples/gpu.offscreen.1.py b/doc/python_api/examples/gpu.offscreen.1.py
new file mode 100644
index 00000000000..75ddf804e70
--- /dev/null
+++ b/doc/python_api/examples/gpu.offscreen.1.py
@@ -0,0 +1,191 @@
+# Draws an off-screen buffer and display it in the corner of the view.
+import bpy
+from bgl import *
+
+
+class OffScreenDraw(bpy.types.Operator):
+ bl_idname = "view3d.offscreen_draw"
+ bl_label = "View3D Offscreen Draw"
+
+ _handle_calc = None
+ _handle_draw = None
+ is_enabled = False
+
+ # manage draw handler
+ @staticmethod
+ def draw_callback_px(self, context):
+ scene = context.scene
+ aspect_ratio = scene.render.resolution_x / scene.render.resolution_y
+
+ self._update_offscreen(context, self._offscreen)
+ self._opengl_draw(context, self._texture, aspect_ratio, 0.2)
+
+ @staticmethod
+ def handle_add(self, context):
+ OffScreenDraw._handle_draw = bpy.types.SpaceView3D.draw_handler_add(
+ self.draw_callback_px, (self, context),
+ 'WINDOW', 'POST_PIXEL',
+ )
+
+ @staticmethod
+ def handle_remove():
+ if OffScreenDraw._handle_draw is not None:
+ bpy.types.SpaceView3D.draw_handler_remove(OffScreenDraw._handle_draw, 'WINDOW')
+
+ OffScreenDraw._handle_draw = None
+
+ # off-screen buffer
+ @staticmethod
+ def _setup_offscreen(context):
+ import gpu
+ scene = context.scene
+ aspect_ratio = scene.render.resolution_x / scene.render.resolution_y
+
+ try:
+ offscreen = gpu.offscreen.new(512, int(512 / aspect_ratio))
+ except Exception as e:
+ print(e)
+ offscreen = None
+
+ return offscreen
+
+ @staticmethod
+ def _update_offscreen(context, offscreen):
+ scene = context.scene
+ render = scene.render
+ camera = scene.camera
+
+ modelview_matrix = camera.matrix_world.inverted()
+ projection_matrix = camera.calc_matrix_camera(
+ render.resolution_x,
+ render.resolution_y,
+ render.pixel_aspect_x,
+ render.pixel_aspect_y,
+ )
+
+ offscreen.draw_view3d(
+ scene,
+ context.space_data,
+ context.region,
+ projection_matrix,
+ modelview_matrix,
+ )
+
+ @staticmethod
+ def _opengl_draw(context, texture, aspect_ratio, scale):
+ """
+ OpenGL code to draw a rectangle in the viewport
+ """
+
+ glDisable(GL_DEPTH_TEST)
+
+ # view setup
+ glMatrixMode(GL_PROJECTION)
+ glPushMatrix()
+ glLoadIdentity()
+
+ glMatrixMode(GL_MODELVIEW)
+ glPushMatrix()
+ glLoadIdentity()
+
+ glOrtho(-1, 1, -1, 1, -15, 15)
+ gluLookAt(0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
+
+ act_tex = Buffer(GL_INT, 1)
+ glGetIntegerv(GL_TEXTURE_2D, act_tex)
+
+ viewport = Buffer(GL_INT, 4)
+ glGetIntegerv(GL_VIEWPORT, viewport)
+
+ width = int(scale * viewport[2])
+ height = int(width / aspect_ratio)
+
+ glViewport(viewport[0], viewport[1], width, height)
+ glScissor(viewport[0], viewport[1], width, height)
+
+ # draw routine
+ glEnable(GL_TEXTURE_2D)
+ glActiveTexture(GL_TEXTURE0)
+
+ glBindTexture(GL_TEXTURE_2D, texture)
+
+ texco = [(1, 1), (0, 1), (0, 0), (1, 0)]
+ verco = [(1.0, 1.0), (-1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)]
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
+
+ glColor4f(1.0, 1.0, 1.0, 1.0)
+
+ glBegin(GL_QUADS)
+ for i in range(4):
+ glTexCoord3f(texco[i][0], texco[i][1], 0.0)
+ glVertex2f(verco[i][0], verco[i][1])
+ glEnd()
+
+ # restoring settings
+ glBindTexture(GL_TEXTURE_2D, act_tex[0])
+
+ glDisable(GL_TEXTURE_2D)
+
+ # reset view
+ glMatrixMode(GL_PROJECTION)
+ glPopMatrix()
+
+ glMatrixMode(GL_MODELVIEW)
+ glPopMatrix()
+
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3])
+ glScissor(viewport[0], viewport[1], viewport[2], viewport[3])
+
+ # operator functions
+ @classmethod
+ def poll(cls, context):
+ return context.area.type == 'VIEW_3D'
+
+ def modal(self, context, event):
+ if context.area:
+ context.area.tag_redraw()
+
+ return {'PASS_THROUGH'}
+
+ def invoke(self, context, event):
+ if OffScreenDraw.is_enabled:
+ self.cancel(context)
+
+ return {'FINISHED'}
+
+ else:
+ self._offscreen = OffScreenDraw._setup_offscreen(context)
+ if self._offscreen:
+ self._texture = self._offscreen.color_texture
+ else:
+ self.report({'ERROR'}, "Error initializing offscreen buffer. More details in the console")
+ return {'CANCELLED'}
+
+ OffScreenDraw.handle_add(self, context)
+ OffScreenDraw.is_enabled = True
+
+ if context.area:
+ context.area.tag_redraw()
+
+ context.window_manager.modal_handler_add(self)
+ return {'RUNNING_MODAL'}
+
+ def cancel(self, context):
+ OffScreenDraw.handle_remove()
+ OffScreenDraw.is_enabled = False
+
+ if context.area:
+ context.area.tag_redraw()
+
+
+def register():
+ bpy.utils.register_class(OffScreenDraw)
+
+
+def unregister():
+ bpy.utils.unregister_class(OffScreenDraw)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/doc/python_api/rst/bge.app.rst b/doc/python_api/rst/bge.app.rst
index a0c2cf36314..34b9263db0c 100644
--- a/doc/python_api/rst/bge.app.rst
+++ b/doc/python_api/rst/bge.app.rst
@@ -10,38 +10,41 @@ Module to access application values that remain unchanged during runtime.
The Blender/BGE version as a tuple of 3 ints, eg. (2, 75, 1).
- .. note:: Version tuples can be compared simply with (in)equality symbols;
- for example, ``(2, 74, 5) <= (2, 75, 0)`` returns True (lexical order).
-
+ .. note::
+
+ Version tuples can be compared simply with (in)equality symbols;
+ for example, ``(2, 74, 5) <= (2, 75, 0)`` returns True (lexical order).
+
:type: tuple of three ints
.. data:: version_string
The Blender/BGE version formatted as a string, eg. "2.75 (sub 1)".
-
+
:type: str
.. data:: version_char
The Blender/BGE version character (for minor releases).
-
+
:type: str
.. data:: has_texture_ffmpeg
- True if the BGE has been built with FFmpeg support, enabling use of :class:`~bge.texture.ImageFFmpeg` and :class:`~bge.texture.VideoFFmpeg`.
-
+ True if the BGE has been built with FFmpeg support,
+ enabling use of :class:`~bge.texture.ImageFFmpeg` and :class:`~bge.texture.VideoFFmpeg`.
+
:type: bool
.. data:: has_joystick
True if the BGE has been built with joystick support.
-
+
:type: bool
.. data:: has_physics
True if the BGE has been built with physics support.
-
+
:type: bool
diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst
index 57d9f1ab5e5..3f35901234a 100644
--- a/doc/python_api/rst/bge.logic.rst
+++ b/doc/python_api/rst/bge.logic.rst
@@ -258,7 +258,8 @@ General functions
Sets the world gravity.
- :type gravity: list [fx, fy, fz]
+ :arg gravity: gravity vector
+ :type gravity: Vector((fx, fy, fz))
.. function:: getSpectrum()
@@ -377,6 +378,76 @@ General functions
Render next frame (if Python has control)
+**********************
+Time related functions
+**********************
+
+.. function:: getClockTime()
+
+ Get the current BGE render time, in seconds. The BGE render time is the
+ simulation time corresponding to the next scene that will be rendered.
+
+ :rtype: double
+
+.. function:: getFrameTime()
+
+ Get the current BGE frame time, in seconds. The BGE frame time is the
+ simulation time corresponding to the current call of the logic system.
+ Generally speaking, it is what the user is interested in.
+
+ :rtype: double
+
+.. function:: getRealTime()
+
+ Get the number of real (system-clock) seconds elapsed since the beginning
+ of the simulation.
+
+ :rtype: double
+
+.. function:: getTimeScale()
+
+ Get the time multiplier between real-time and simulation time. The default
+ value is 1.0. A value greater than 1.0 means that the simulation is going
+ faster than real-time, a value lower than 1.0 means that the simulation is
+ going slower than real-time.
+
+ :rtype: double
+
+.. function:: setTimeScale(time_scale)
+
+ Set the time multiplier between real-time and simulation time. A value
+ greater than 1.0 means that the simulation is going faster than real-time,
+ a value lower than 1.0 means that the simulation is going slower than
+ real-time. Note that a too large value may lead to some physics
+ instabilities.
+
+ :arg time_scale: The new time multiplier.
+
+.. function:: getUseExternalClock()
+
+ Get if the BGE use the inner BGE clock, or rely or on an external
+ clock. The default is to use the inner BGE clock.
+
+ :rtype: bool
+
+.. function:: setUseExternalClock(use_external_clock)
+
+ Set if the BGE use the inner BGE clock, or rely or on an external
+ clock. If the user selects the use of an external clock, he should call
+ regularly the setClockTime method.
+
+ :arg use_external_clock: the new setting
+
+.. function:: setClockTime(new_time)
+
+ Set the next value of the simulation clock. It is preferable to use this
+ method from a custom main function in python, as calling it in the logic
+ block can easily lead to a blocked system (if the time does not advance
+ enough to run at least the next logic step).
+
+ :arg new_time: the next value of the BGE clock (in second).
+
+
*****************
Utility functions
*****************
diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst
index 2afb2796249..3b565e294dd 100644
--- a/doc/python_api/rst/bge.render.rst
+++ b/doc/python_api/rst/bge.render.rst
@@ -113,7 +113,9 @@ Functions
.. note:: Only works in the standalone player, not the Blender-embedded player.
+ :arg width: width in pixels
:type width: integer
+ :arg height: height in pixels
:type height: integer
.. function:: setFullScreen(enable)
@@ -122,6 +124,7 @@ Functions
.. note:: Only works in the standalone player, not the Blender-embedded player.
+ :arg enable: ``True`` to set full screen, ``False`` to set windowed.
:type enable: bool
.. function:: getFullScreen()
@@ -134,9 +137,12 @@ Functions
.. function:: getDisplayDimensions()
- Get the actual display dimensions, in pixels, of the physical display (e.g., the monitor).
+ Get the display dimensions, in pixels, of the display (e.g., the
+ monitor). Can return the size of the entire view, so the
+ combination of all monitors; for example, ``(3840, 1080)`` for two
+ side-by-side 1080p monitors.
- :type dimension: list [width,heigh]
+ :rtype: tuple (width, height)
.. function:: makeScreenshot(filename)
@@ -161,13 +167,14 @@ Functions
.. function:: enableVisibility(visible)
- Doesn't really do anything...
+ Deprecated; doesn't do anything.
.. function:: showMouse(visible)
Enables or disables the operating system mouse cursor.
+ :arg visible:
:type visible: boolean
@@ -175,15 +182,15 @@ Functions
Sets the mouse cursor position.
+ :arg x: X-coordinate in screen pixel coordinates.
:type x: integer
+ :arg y: Y-coordinate in screen pixel coordinates.
:type y: integer
.. function:: setBackgroundColor(rgba)
- Sets the window background color. (Deprecated: use KX_WorldInfo.background_color)
-
- :type rgba: list [r, g, b, a]
+ Deprecated and no longer functional. Use :py:meth:`bge.types.KX_WorldInfo.backgroundColor` instead.
.. function:: setEyeSeparation(eyesep)
@@ -227,6 +234,7 @@ Functions
Set the material mode to use for OpenGL rendering.
+ :arg mode: material mode
:type mode: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL
.. note:: Changes will only affect newly created scenes.
@@ -243,14 +251,17 @@ Functions
Enables or disables a GLSL material setting.
+ :arg setting:
:type setting: string (lights, shaders, shadows, ramps, nodes, extra_textures)
+ :arg enable:
:type enable: boolean
-.. function:: getGLSLMaterialSetting(setting, enable)
+.. function:: getGLSLMaterialSetting(setting)
Get the state of a GLSL material setting.
+ :arg setting:
:type setting: string (lights, shaders, shadows, ramps, nodes, extra_textures)
:rtype: boolean
@@ -311,24 +322,28 @@ Functions
Show or hide the framerate.
+ :arg enable:
:type enable: boolean
.. function:: showProfile(enable)
Show or hide the profile.
+ :arg enable:
:type enable: boolean
.. function:: showProperties(enable)
Show or hide the debug properties.
+ :arg enable:
:type enable: boolean
.. function:: autoDebugList(enable)
Enable or disable auto adding debug properties to the debug list.
+ :arg enable:
:type enable: boolean
.. function:: clearDebugList()
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst b/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst
index 17f54031ec3..ece2a65af71 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst
@@ -89,6 +89,15 @@ base class --- :class:`PyObjectPlus`
:return: the material's shader
:rtype: :class:`BL_Shader`
+ .. method:: getTextureBindcode(textureslot)
+
+ Returns the material's texture OpenGL bind code/id/number/name.
+
+ :arg textureslot: Specifies the texture slot number
+ :type textureslot: integer
+ :return: the material's texture OpenGL bind code/id/number/name
+ :rtype: integer
+
.. attribute:: alpha
The material's alpha transparency.
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst b/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst
index e326892a824..adff6e0a2ad 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst
@@ -25,7 +25,7 @@ base class --- :class:`PyObjectPlus`
The maximum number of jumps a character can perform before having to touch the ground. By default this is set to 1. 2 allows for a double jump, etc.
- :type: int
+ :type: int in [0, 255], default 1
.. attribute:: jumpCount
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
index 74df50ddb58..d8cc5e45e83 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
@@ -799,7 +799,7 @@ base class --- :class:`SCA_IObject`
:return: the first object hit or None if no object or object does not match prop
:rtype: :class:`KX_GameObject`
- .. method:: rayCast(objto, objfrom, dist, prop, face, xray, poly)
+ .. method:: rayCast(objto, objfrom, dist, prop, face, xray, poly, mask)
Look from a point/object to another point/object and find first object hit within dist that matches prop.
if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None, None, None) if no hit.
@@ -851,6 +851,8 @@ base class --- :class:`SCA_IObject`
* 2: return value is a 5-tuple and the 5th element is a 2-tuple (u, v) with the UV mapping of the hit point or None if no hit, or the object doesn't use a mesh collision shape, or doesn't have a UV mapping.
:type poly: integer
+ :arg mask: collision mask: The collision mask (16 layers mapped to a 16-bit integer) is combined with each object's collision group, to hit only a subset of the objects in the scene. Only those objects for which ``collisionGroup & mask`` is true can be hit.
+ :type mask: bitfield
:return: (object, hitpoint, hitnormal) or (object, hitpoint, hitnormal, polygon) or (object, hitpoint, hitnormal, polygon, hituv).
* object, hitpoint and hitnormal are None if no hit.
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_IpoActuator.rst b/doc/python_api/rst/bge_types/bge.types.KX_IpoActuator.rst
deleted file mode 100644
index 2cae4fb3b1a..00000000000
--- a/doc/python_api/rst/bge_types/bge.types.KX_IpoActuator.rst
+++ /dev/null
@@ -1,65 +0,0 @@
-KX_IpoActuator(SCA_IActuator)
-=============================
-
-.. module:: bge.types
-
-base class --- :class:`SCA_IActuator`
-
-.. class:: KX_IpoActuator(SCA_IActuator)
-
- IPO actuator activates an animation.
-
- .. attribute:: frameStart
-
- Start frame.
-
- :type: float
-
- .. attribute:: frameEnd
-
- End frame.
-
- :type: float
-
- .. attribute:: propName
-
- Use this property to define the Ipo position.
-
- :type: string
-
- .. attribute:: framePropName
-
- Assign this property this action current frame number.
-
- :type: string
-
- .. attribute:: mode
-
- Play mode for the ipo. Can be on of :ref:`these constants <ipo-actuator>`
-
- :type: integer
-
- .. attribute:: useIpoAsForce
-
- Apply Ipo as a global or local force depending on the local option (dynamic objects only).
-
- :type: boolean
-
- .. attribute:: useIpoAdd
-
- Ipo is added to the current loc/rot/scale in global or local coordinate according to Local flag.
-
- :type: boolean
-
- .. attribute:: useIpoLocal
-
- Let the ipo acts in local coordinates, used in Force and Add mode.
-
- :type: boolean
-
- .. attribute:: useChildren
-
- Update IPO on all children Objects as well.
-
- :type: boolean
-
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst b/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst
index a5b7aaf5dee..a37b4dad585 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst
@@ -25,6 +25,12 @@ base class --- :class:`PyObjectPlus`
:type: callable
+ .. attribute:: finished
+
+ The current status of the lib load.
+
+ :type: boolean
+
.. attribute:: progress
The current progress of the lib load as a normalized value from 0.0 to 1.0.
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
index 2b2bdf76b4f..5ba7f3b8e34 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst
@@ -48,6 +48,80 @@ base class --- :class:`KX_GameObject`
:type: float
+ .. attribute:: shadowClipStart
+
+ The shadowmap clip start, below which objects will not generate shadows.
+
+ :type: float (read only)
+
+ .. attribute:: shadowClipEnd
+
+ The shadowmap clip end, beyond which objects will not generate shadows.
+
+ :type: float (read only)
+
+ ..attribute:: shadowFrustumSize
+
+ Size of the frustum used for creating the shadowmap.
+
+ :type: float (read only)
+
+ ..attribute:: shadowBindId
+
+ The OpenGL shadow texture bind number/id.
+
+ :type: int (read only)
+
+ ..attribute:: shadowMapType
+
+ The shadow shadow map type (0 -> Simple; 1 -> Variance)
+
+ :type: int (read only)
+
+ ..attribute:: shadowBias
+
+ The shadow buffer sampling bias.
+
+ :type: float (read only)
+
+ ..attribute:: shadowBleedBias
+
+ The bias for reducing light-bleed on variance shadow maps.
+
+ :type: float (read only)
+
+ ..attribute:: useShadow
+
+ Returns True if the light has Shadow option activated, else returns False.
+
+ :type: boolean (read only)
+
+ .. attribute:: shadowColor
+
+ The color of this light shadows. Black = (0.0, 0.0, 0.0), White = (1.0, 1.0, 1.0).
+
+ :type: :class:`mathutils.Color` (read only)
+
+ .. attribute:: shadowMatrix
+
+ Matrix that converts a vector in camera space to shadow buffer depth space.
+
+ Computed as:
+ mat4_perspective_to_depth * mat4_lamp_to_perspective * mat4_world_to_lamp * mat4_cam_to_world.
+
+ mat4_perspective_to_depth is a fixed matrix defined as follow:
+
+ 0.5 0.0 0.0 0.5
+ 0.0 0.5 0.0 0.5
+ 0.0 0.0 0.5 0.5
+ 0.0 0.0 0.0 1.0
+
+ .. note:
+
+ There is one matrix of that type per lamp casting shadow in the scene.
+
+ :type: Matrix4x4 (read only)
+
.. attribute:: distance
The maximum distance this light can illuminate. (SPOT and NORMAL lights only).
diff --git a/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst b/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst
index a636af4f083..1501d85b86c 100644
--- a/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst
+++ b/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst
@@ -63,17 +63,17 @@ base class --- :class:`PyObjectPlus`
The color of the mist. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0].
Mist and background color sould always set to the same color.
- :type: :class:`mathutils.Vector`
+ :type: :class:`mathutils.Color`
.. attribute:: backgroundColor
The color of the background. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0].
Mist and background color sould always set to the same color.
- :type: :class:`mathutils.Vector`
+ :type: :class:`mathutils.Color`
.. attribute:: ambientColor
The color of the ambient light. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0].
- :type: :class:`mathutils.Vector`
+ :type: :class:`mathutils.Color`
diff --git a/doc/python_api/rst/bgl.rst b/doc/python_api/rst/bgl.rst
index 8b0ad63abb4..36e07a17cdc 100644
--- a/doc/python_api/rst/bgl.rst
+++ b/doc/python_api/rst/bgl.rst
@@ -20,6 +20,7 @@ offers a set of extensive examples, including advanced features.
.. note::
+
You can use the :class:`Image` type to load and set textures.
See :class:`Image.gl_load` and :class:`Image.gl_load`,
for example.
diff --git a/doc/python_api/rst/gpu.rst b/doc/python_api/rst/gpu.rst
index b56523c2206..6c38122a573 100644
--- a/doc/python_api/rst/gpu.rst
+++ b/doc/python_api/rst/gpu.rst
@@ -186,6 +186,7 @@ GLSL Lamp Uniforms
mat4_world_to_cam_ * (-vec3_lamp_Z_axis)
.. note::
+
- The lamp Z axis points to the opposite direction of light.
- The norm of the vector should be unit length.
@@ -277,6 +278,12 @@ GLSL Lamp Uniforms
:type: float
+.. data:: GPU_DYNAMIC_LAMP_SPOTSCALE
+
+ Represents the SpotLamp local scale.
+
+ :type: float2
+
GLSL Sampler Uniforms
^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/python_api/rst/include__bmesh.rst b/doc/python_api/rst/include__bmesh.rst
index 9dccd4e72ae..070dc34c964 100644
--- a/doc/python_api/rst/include__bmesh.rst
+++ b/doc/python_api/rst/include__bmesh.rst
@@ -32,14 +32,6 @@ For an overview of BMesh data types and how they reference each other see:
.. warning::
- This API is still in development and experimental, while we don't expect to see large changes,
- many areas are not well tested yet and so its possible changes will be made that break scripts.
-
- *Campbell Barton, 13, March 2012*
-
-
-.. warning::
-
TODO items are...
* add access to BMesh **walkers**
diff --git a/doc/python_api/rst/info_best_practice.rst b/doc/python_api/rst/info_best_practice.rst
index 8c5ae3398bc..9b95ada2b2c 100644
--- a/doc/python_api/rst/info_best_practice.rst
+++ b/doc/python_api/rst/info_best_practice.rst
@@ -34,7 +34,7 @@ As well as pep8 we have other conventions used for blender python scripts.
- Use single quotes for enums, and double quotes for strings.
- Both are of course strings but in our internal API enums are unique items from a limited set. eg.
+ Both are of course strings, but in our internal API enums are unique items from a limited set. eg.
.. code-block:: python
@@ -137,7 +137,7 @@ Searching for list items
In Python there are some handy list functions that save you having to search through the list.
-Even though you're not looping on the list data **python is**,
+Even though you are not looping on the list data **python is**,
so you need to be aware of functions that will slow down your script by searching the whole list.
.. code-block:: python
@@ -283,7 +283,7 @@ This is generally faster since there is no re-assignment and no list duplication
>>> some_list_func(vec)
-Also note that passing a sliced list makes a copy of the list in python memory
+Also note that passing a sliced list makes a copy of the list in python memory.
>>> foobar(my_list[:])
@@ -293,27 +293,29 @@ If my_list was a large array containing 10000's of items, a copy could use a lot
Writing Strings to a File (Python General)
------------------------------------------
-Here are 3 ways of joining multiple strings into 1 string for writing
+Here are 3 ways of joining multiple strings into one string for writing.
+This also applies to any area of your code that involves a lot of string joining.
-This really applies to any area of your code that involves a lot of string joining.
-
-Python’s string addition, *don't use if you can help it, especially when writing data in a loop.*
+``String addition`` -
+this is the slowest option, *don't use if you can help it, especially when writing data in a loop*.
>>> file.write(str1 + " " + str2 + " " + str3 + "\n")
-String formatting. Use this when you're writing string data from floats and ints
+``String formatting`` -
+use this when you are writing string data from floats and ints.
>>> file.write("%s %s %s\n" % (str1, str2, str3))
-Python’s string joining function. To join a list of strings
+``String join() function``
+use to join a list of strings (the list may be temporary). In the following example, the strings are joined with a space " " in between, other examples are "" or ", ".
>>> file.write(" ".join([str1, str2, str3, "\n"]))
-join is fastest on many strings,
+Join is fastest on many strings,
`string formatting <http://docs.python.org/py3k/library/string.html#string-formatting>`__
is quite fast too (better for converting data types). String arithmetic is slowest.
@@ -331,17 +333,17 @@ Parsing Numbers
^^^^^^^^^^^^^^^
Use ``float(string)`` rather than ``eval(string)``, if you know the value will be an int then ``int(string)``,
-float() will work for an int too but it's faster to read ints with int().
+float() will work for an int too but it is faster to read ints with int().
Checking String Start/End
^^^^^^^^^^^^^^^^^^^^^^^^^
-If you're checking the start of a string for a keyword, rather than...
+If you are checking the start of a string for a keyword, rather than...
>>> if line[0:5] == "vert ": ...
-Use...
+use...
>>> if line.startswith("vert "):
@@ -350,7 +352,7 @@ error with the slice length not matching the string length.
my_string.endswith("foo_bar") can be used for line endings too.
-If you are unsure whether the text is upper or lower case use ``lower()`` or ``upper()`` string function.
+If you are unsure whether the text is upper or lower case, use the ``lower()`` or ``upper()`` string function.
>>> if line.lower().startswith("vert ")
@@ -372,7 +374,7 @@ Value Comparison
Python has two ways to compare values ``a == b`` and ``a is b``,
the difference is that ``==`` may run the objects comparison function ``__cmp__()`` whereas ``is`` compares identity,
-that both variables reference the same item in memory.
+this is, that both variables reference the same item in memory.
In cases where you know you are checking for the same value which is referenced from multiple places, ``is`` is faster.
@@ -380,7 +382,7 @@ In cases where you know you are checking for the same value which is referenced
Time Your Code
--------------
-While developing a script it's good to time it to be aware of any changes in performance, this can be done simply.
+While developing a script it is good to time it to be aware of any changes in performance, this can be done simply.
.. code-block:: python
@@ -389,5 +391,5 @@ While developing a script it's good to time it to be aware of any changes in per
# do something...
- print("My Script Finished: %.4f sec" % time.time() - time_start)
+ print("My Script Finished: %.4f sec" % (time.time() - time_start))
diff --git a/doc/python_api/rst/info_quickstart.rst b/doc/python_api/rst/info_quickstart.rst
index ab106dd3bb7..164196c0ac2 100644
--- a/doc/python_api/rst/info_quickstart.rst
+++ b/doc/python_api/rst/info_quickstart.rst
@@ -47,8 +47,12 @@ A quick list of helpful things to know before starting:
- For more examples, the text menu has a templates section where some example operators can be found.
- To examine further scripts distributed with Blender, see:
- | ``~/.blender/scripts/startup/bl_ui`` for the user interface,
- | ``~/.blender/scripts/startup/bl_op`` for operators.
+ | ``scripts/startup/bl_ui`` for the user interface,
+ | ``scripts/startup/bl_operators`` for operators.
+
+ Exact location depends on platform, see:
+ `Configuration and Data Paths
+ <https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`__.
Running Scripts
diff --git a/doc/python_api/rst/info_tips_and_tricks.rst b/doc/python_api/rst/info_tips_and_tricks.rst
index 28d129b5b13..e8928e07671 100644
--- a/doc/python_api/rst/info_tips_and_tricks.rst
+++ b/doc/python_api/rst/info_tips_and_tricks.rst
@@ -114,9 +114,9 @@ This example shows loading a script in as a module and executing a module functi
.. code-block:: python
import myscript
- import imp
+ import importlib
- imp.reload(myscript)
+ importlib.reload(myscript)
myscript.main()
@@ -143,8 +143,8 @@ this example adds the current blend files directory to the search path, then loa
sys.path.append(blend_dir)
import myscript
- import imp
- imp.reload(myscript)
+ import importlib
+ importlib.reload(myscript)
myscript.main()
@@ -213,12 +213,21 @@ this has the disadvantage that any extensions you have installed in your systems
There are 2 ways around this:
-- remove Blender Python sub-directory, Blender will then fallback on the systems Python and use that instead
+- Remove Blender Python sub-directory, Blender will then fallback on the systems Python and use that instead.
+
+ Depending on your platform,
+ you may need to explicitly reference the location of your Python installation using the
+ ``PYTHONPATH`` environment variable, eg:
+
+ .. code-block:: sh
+
+ PYTHONPATH=/usr/lib/python3.5 ./blender
+
.. warning::
The Python version must match the one that Blender comes with.
-- copy the extensions into Blender's Python sub-directory so Blender can access them,
+- Copy or link the extensions into Blender's Python sub-directory so Blender can access them,
you could also copy the entire Python installation into Blenders sub-directory,
replacing the one Blender comes with.
This works as long as the Python versions match and the paths are created in the same relative locations.
@@ -307,7 +316,7 @@ Since it's possible to access data which has been removed (see Gotcha's),
this can be hard to track down the cause of crashes.
To raise Python exceptions on accessing freed data (rather than crashing),
-enable the CMake build option WITH_PYTHON_SAFETY.
+enable the CMake build option ``WITH_PYTHON_SAFETY``.
This enables data tracking which makes data access about 2x slower
which is why the option isn't enabled in release builds.
diff --git a/doc/python_api/rst_from_bmesh_opdefines.py b/doc/python_api/rst_from_bmesh_opdefines.py
index fcfe0c25c80..ebcedbf71f1 100644
--- a/doc/python_api/rst_from_bmesh_opdefines.py
+++ b/doc/python_api/rst_from_bmesh_opdefines.py
@@ -163,6 +163,9 @@ def main():
for i, l in enumerate(b):
l = l.strip()
+ # casts
+ l = l.replace("(int)", "")
+
l = l.replace("{", "(")
l = l.replace("}", ")")
@@ -177,8 +180,8 @@ def main():
l = "None,"
b[i] = l
- #for l in b:
- # print(l)
+ # for l in b:
+ # print(l)
text = "\n".join(b)
global_namespace = {
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index f68d6bf617a..9d0d358305b 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -261,9 +261,11 @@ else:
"bpy.utils.previews",
"bpy_extras",
"gpu",
+ "gpu.offscreen",
"mathutils",
- "mathutils.geometry",
"mathutils.bvhtree",
+ "mathutils.geometry",
+ "mathutils.interpolate",
"mathutils.kdtree",
"mathutils.noise",
"freestyle",
@@ -1000,9 +1002,11 @@ context_type_map = {
"edit_movieclip": ("MovieClip", False),
"edit_object": ("Object", False),
"edit_text": ("Text", False),
+ "editable_bases": ("ObjectBase", True),
"editable_bones": ("EditBone", True),
"editable_gpencil_layers": ("GPencilLayer", True),
"editable_gpencil_strokes": ("GPencilStroke", True),
+ "editable_objects": ("Object", True),
"fluid": ("FluidSimulationModifier", False),
"gpencil_data": ("GreasePencel", False),
"gpencil_data_owner": ("ID", False),
@@ -1344,7 +1348,10 @@ def pyrna2sphinx(basepath):
descr = prop.description
if not descr:
descr = prop.name
- fw(" `%s`, %s, %s\n\n" % (prop.identifier, descr, type_descr))
+ # In rare cases descr may be empty
+ fw(" `%s`, %s\n\n" %
+ (prop.identifier,
+ ", ".join((val for val in (descr, type_descr) if val))))
write_example_ref(" ", fw, "bpy.types." + struct_id + "." + func.identifier)
@@ -1657,9 +1664,15 @@ def write_rst_contents(basepath):
standalone_modules = (
# mathutils
- "mathutils", "mathutils.geometry", "mathutils.bvhtree", "mathutils.kdtree", "mathutils.noise",
+ "mathutils",
+ "mathutils.geometry",
+ "mathutils.bvhtree", "mathutils.kdtree",
+ "mathutils.interpolate",
+ "mathutils.noise",
# misc
- "freestyle", "bgl", "blf", "gpu", "aud", "bpy_extras",
+ "freestyle", "bgl", "blf",
+ "gpu", "gpu.offscreen",
+ "aud", "bpy_extras",
# bmesh, submodules are in own page
"bmesh",
)
@@ -1799,6 +1812,7 @@ def write_rst_importable_modules(basepath):
# C_modules
"aud" : "Audio System",
"blf" : "Font Drawing",
+ "gpu.offscreen" : "GPU Off-Screen Buffer",
"bmesh" : "BMesh Module",
"bmesh.types" : "BMesh Types",
"bmesh.utils" : "BMesh Utilities",
@@ -1811,6 +1825,7 @@ def write_rst_importable_modules(basepath):
"mathutils.geometry" : "Geometry Utilities",
"mathutils.bvhtree" : "BVHTree Utilities",
"mathutils.kdtree" : "KDTree Utilities",
+ "mathutils.interpolate": "Interpolation Utilities",
"mathutils.noise" : "Noise Utilities",
"freestyle" : "Freestyle Module",
"freestyle.types" : "Freestyle Types",
diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh
index 01de3e2c2ea..697cd5a9b3f 100755
--- a/doc/python_api/sphinx_doc_gen.sh
+++ b/doc/python_api/sphinx_doc_gen.sh
@@ -18,8 +18,10 @@ DO_OUT_HTML=true
DO_OUT_HTML_ZIP=true
DO_OUT_PDF=false
+if [ -z $BLENDER_BIN ] ; then
+ BLENDER_BIN="./blender.bin"
+fi
-BLENDER="./blender.bin"
SSH_USER=$1
SSH_HOST=$SSH_USER"@blender.org"
SSH_UPLOAD="/data/www/vhosts/www.blender.org/api" # blender_python_api_VERSION, added after
@@ -52,7 +54,17 @@ SPHINXBASE=doc/python_api
if $DO_EXE_BLENDER ; then
# dont delete existing docs, now partial updates are used for quick builds.
- $BLENDER --background -noaudio --factory-startup --python $SPHINXBASE/sphinx_doc_gen.py
+ $BLENDER_BIN \
+ --background \
+ -noaudio \
+ --factory-startup \
+ --python-exit-code 1 \
+ --python $SPHINXBASE/sphinx_doc_gen.py
+
+ if (($? == 1)) ; then
+ echo "Generating documentation failed, aborting"
+ exit 1
+ fi
fi
@@ -108,6 +120,9 @@ if $DO_UPLOAD ; then
## symlink the dir to a static URL
#ssh $SSH_USER@blender.org 'rm '$SSH_UPLOAD'/250PythonDoc && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/250PythonDoc'
+ if [ "$blender_version_cycle" = "release" ] ; then
+ ssh $SSH_USER@blender.org 'rm '$SSH_UPLOAD'/blender_python_api_current && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/blender_python_api_current'
+ fi
# better redirect
ssh $SSH_USER@blender.org 'echo "<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\" content=\"0;url=../blender_python_api_'$BLENDER_VERSION'/\"></head><body>Redirecting...</body></html>" > '$SSH_UPLOAD'/250PythonDoc/index.html'
diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 93f57b04d4e..58e0c68148b 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -23,17 +23,14 @@
#
# ***** END GPL LICENSE BLOCK *****
+# Libs that adhere to strict flags
+add_subdirectory(curve_fit_nd)
+
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()
add_subdirectory(rangetree)
add_subdirectory(wcwidth)
-add_subdirectory(libmv)
-add_subdirectory(Eigen3)
-
-if(WITH_OPENNL)
- add_subdirectory(colamd)
-endif()
if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
@@ -66,10 +63,6 @@ if(WITH_IMAGE_OPENJPEG AND (NOT WITH_SYSTEM_OPENJPEG))
add_subdirectory(libopenjpeg)
endif()
-if(WITH_IMAGE_REDCODE)
- add_subdirectory(libredcode)
-endif()
-
if(WITH_LZO AND NOT WITH_SYSTEM_LZO)
add_subdirectory(lzo)
endif()
@@ -80,7 +73,9 @@ endif()
if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
add_subdirectory(clew)
- add_subdirectory(cuew)
+ if(WITH_CUDA_DYNLOAD)
+ add_subdirectory(cuew)
+ endif()
endif()
if(WITH_MOD_BOOLEAN)
@@ -91,6 +86,15 @@ if(WITH_X11 AND WITH_GHOST_XDND)
add_subdirectory(xdnd)
endif()
+if(WITH_LIBMV)
+ add_subdirectory(ceres)
+endif()
+
+if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
+ add_subdirectory(gflags)
+ add_subdirectory(glog)
+endif()
+
if(WITH_GTESTS)
add_subdirectory(gtest)
endif()
diff --git a/extern/Eigen3/CMakeLists.txt b/extern/Eigen3/CMakeLists.txt
deleted file mode 100644
index 9bbfc9a3670..00000000000
--- a/extern/Eigen3/CMakeLists.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2015, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Bastien Montagne.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- .
-)
-
-set(INC_SYS
-)
-
-set(SRC
- eigen3_capi.h
-
- intern/eigenvalues.cc
-
- intern/eigenvalues.h
-)
-
-blender_add_lib(extern_eigen3 "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/Eigen3/Eigen/Core b/extern/Eigen3/Eigen/Core
index 9131cc3fc9d..509c529e13d 100644
--- a/extern/Eigen3/Eigen/Core
+++ b/extern/Eigen3/Eigen/Core
@@ -95,7 +95,7 @@
extern "C" {
// In theory we should only include immintrin.h and not the other *mmintrin.h header files directly.
// Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus:
- #ifdef __INTEL_COMPILER
+ #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110
#include <immintrin.h>
#else
#include <emmintrin.h>
@@ -123,7 +123,7 @@
#undef bool
#undef vector
#undef pixel
- #elif defined __ARM_NEON__
+ #elif defined __ARM_NEON
#define EIGEN_VECTORIZE
#define EIGEN_VECTORIZE_NEON
#include <arm_neon.h>
@@ -165,7 +165,7 @@
#endif
// required for __cpuid, needs to be included after cmath
-#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64))
+#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) && (!defined(_WIN32_WCE))
#include <intrin.h>
#endif
diff --git a/extern/Eigen3/Eigen/SparseCore b/extern/Eigen3/Eigen/SparseCore
index 9b5be5e15a9..24bcf0156b3 100644
--- a/extern/Eigen3/Eigen/SparseCore
+++ b/extern/Eigen3/Eigen/SparseCore
@@ -14,7 +14,7 @@
/**
* \defgroup SparseCore_Module SparseCore module
*
- * This module provides a sparse matrix representation, and basic associatd matrix manipulations
+ * This module provides a sparse matrix representation, and basic associated matrix manipulations
* and operations.
*
* See the \ref TutorialSparse "Sparse tutorial"
diff --git a/extern/Eigen3/Eigen/src/Cholesky/LDLT.h b/extern/Eigen3/Eigen/src/Cholesky/LDLT.h
index d026418f8a9..abd30bd916d 100644
--- a/extern/Eigen3/Eigen/src/Cholesky/LDLT.h
+++ b/extern/Eigen3/Eigen/src/Cholesky/LDLT.h
@@ -235,6 +235,11 @@ template<typename _MatrixType, int _UpLo> class LDLT
}
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
/** \internal
* Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U.
@@ -274,30 +279,13 @@ template<> struct ldlt_inplace<Lower>
return true;
}
- RealScalar cutoff(0), biggest_in_corner;
-
for (Index k = 0; k < size; ++k)
{
// Find largest diagonal element
Index index_of_biggest_in_corner;
- biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner);
+ mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner);
index_of_biggest_in_corner += k;
- if(k == 0)
- {
- // The biggest overall is the point of reference to which further diagonals
- // are compared; if any diagonal is negligible compared
- // to the largest overall, the algorithm bails.
- cutoff = abs(NumTraits<Scalar>::epsilon() * biggest_in_corner);
- }
-
- // Finish early if the matrix is not full rank.
- if(biggest_in_corner < cutoff)
- {
- for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i;
- break;
- }
-
transpositions.coeffRef(k) = index_of_biggest_in_corner;
if(k != index_of_biggest_in_corner)
{
@@ -328,15 +316,20 @@ template<> struct ldlt_inplace<Lower>
if(k>0)
{
- temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint();
+ temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint();
mat.coeffRef(k,k) -= (A10 * temp.head(k)).value();
if(rs>0)
A21.noalias() -= A20 * temp.head(k);
}
- if((rs>0) && (abs(mat.coeffRef(k,k)) > cutoff))
- A21 /= mat.coeffRef(k,k);
-
+
+ // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot
+ // was smaller than the cutoff value. However, soince LDLT is not rank-revealing
+ // we should only make sure we do not introduce INF or NaN values.
+ // LAPACK also uses 0 as the cutoff value.
RealScalar realAkk = numext::real(mat.coeffRef(k,k));
+ if((rs>0) && (abs(realAkk) > RealScalar(0)))
+ A21 /= realAkk;
+
if (sign == PositiveSemiDef) {
if (realAkk < 0) sign = Indefinite;
} else if (sign == NegativeSemiDef) {
@@ -446,6 +439,8 @@ template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper>
template<typename MatrixType, int _UpLo>
LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a)
{
+ check_template_parameters();
+
eigen_assert(a.rows()==a.cols());
const Index size = a.rows();
@@ -454,6 +449,7 @@ LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a)
m_transpositions.resize(size);
m_isInitialized = false;
m_temporary.resize(size);
+ m_sign = internal::ZeroSign;
internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign);
@@ -468,7 +464,7 @@ LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a)
*/
template<typename MatrixType, int _UpLo>
template<typename Derived>
-LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w, const typename NumTraits<typename MatrixType::Scalar>::Real& sigma)
+LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w, const typename LDLT<MatrixType,_UpLo>::RealScalar& sigma)
{
const Index size = w.rows();
if (m_isInitialized)
@@ -514,16 +510,21 @@ struct solve_retval<LDLT<_MatrixType,_UpLo>, Rhs>
using std::abs;
using std::max;
typedef typename LDLTType::MatrixType MatrixType;
- typedef typename LDLTType::Scalar Scalar;
typedef typename LDLTType::RealScalar RealScalar;
- const Diagonal<const MatrixType> vectorD = dec().vectorD();
- RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() * NumTraits<Scalar>::epsilon(),
- RealScalar(1) / NumTraits<RealScalar>::highest()); // motivated by LAPACK's xGELSS
+ const typename Diagonal<const MatrixType>::RealReturnType vectorD(dec().vectorD());
+ // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon
+ // as motivated by LAPACK's xGELSS:
+ // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits<RealScalar>::epsilon(),RealScalar(1) / NumTraits<RealScalar>::highest());
+ // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest
+ // diagonal element is not well justified and to numerical issues in some cases.
+ // Moreover, Lapack's xSYTRS routines use 0 for the tolerance.
+ RealScalar tolerance = RealScalar(1) / NumTraits<RealScalar>::highest();
+
for (Index i = 0; i < vectorD.size(); ++i) {
if(abs(vectorD(i)) > tolerance)
- dst.row(i) /= vectorD(i);
+ dst.row(i) /= vectorD(i);
else
- dst.row(i).setZero();
+ dst.row(i).setZero();
}
// dst = L^-T (D^-1 L^-1 P b)
@@ -576,7 +577,7 @@ MatrixType LDLT<MatrixType,_UpLo>::reconstructedMatrix() const
// L^* P
res = matrixU() * res;
// D(L^*P)
- res = vectorD().asDiagonal() * res;
+ res = vectorD().real().asDiagonal() * res;
// L(DL^*P)
res = matrixL() * res;
// P^T (LDL^*P)
diff --git a/extern/Eigen3/Eigen/src/Cholesky/LLT.h b/extern/Eigen3/Eigen/src/Cholesky/LLT.h
index 2e6189f7dab..7c11a2dc29a 100644
--- a/extern/Eigen3/Eigen/src/Cholesky/LLT.h
+++ b/extern/Eigen3/Eigen/src/Cholesky/LLT.h
@@ -174,6 +174,12 @@ template<typename _MatrixType, int _UpLo> class LLT
LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1);
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
/** \internal
* Used to compute and store L
* The strict upper part is not used and even not initialized.
@@ -283,7 +289,7 @@ template<typename Scalar> struct llt_inplace<Scalar, Lower>
return k;
mat.coeffRef(k,k) = x = sqrt(x);
if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint();
- if (rs>0) A21 *= RealScalar(1)/x;
+ if (rs>0) A21 /= x;
}
return -1;
}
@@ -384,6 +390,8 @@ template<typename MatrixType> struct LLT_Traits<MatrixType,Upper>
template<typename MatrixType, int _UpLo>
LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const MatrixType& a)
{
+ check_template_parameters();
+
eigen_assert(a.rows()==a.cols());
const Index size = a.rows();
m_matrix.resize(size, size);
diff --git a/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h b/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h
index 64daa445cf7..66675d7476d 100644
--- a/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h
+++ b/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h
@@ -60,7 +60,7 @@ template<> struct mkl_llt<EIGTYPE> \
lda = m.outerStride(); \
\
info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \
- info = (info==0) ? Success : NumericalIssue; \
+ info = (info==0) ? -1 : info>0 ? info-1 : size; \
return info; \
} \
}; \
diff --git a/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h b/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h
index c449960de4a..99dbe171c36 100644
--- a/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h
+++ b/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h
@@ -78,7 +78,7 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat)
{
res.itype = CHOLMOD_INT;
}
- else if (internal::is_same<_Index,UF_long>::value)
+ else if (internal::is_same<_Index,SuiteSparse_long>::value)
{
res.itype = CHOLMOD_LONG;
}
@@ -395,7 +395,7 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl
CholmodSimplicialLLT(const MatrixType& matrix) : Base()
{
init();
- compute(matrix);
+ Base::compute(matrix);
}
~CholmodSimplicialLLT() {}
@@ -442,7 +442,7 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp
CholmodSimplicialLDLT(const MatrixType& matrix) : Base()
{
init();
- compute(matrix);
+ Base::compute(matrix);
}
~CholmodSimplicialLDLT() {}
@@ -487,7 +487,7 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper
CholmodSupernodalLLT(const MatrixType& matrix) : Base()
{
init();
- compute(matrix);
+ Base::compute(matrix);
}
~CholmodSupernodalLLT() {}
@@ -534,7 +534,7 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom
CholmodDecomposition(const MatrixType& matrix) : Base()
{
init();
- compute(matrix);
+ Base::compute(matrix);
}
~CholmodDecomposition() {}
diff --git a/extern/Eigen3/Eigen/src/Core/Array.h b/extern/Eigen3/Eigen/src/Core/Array.h
index 0ab03eff0f0..0b9c38c8219 100644
--- a/extern/Eigen3/Eigen/src/Core/Array.h
+++ b/extern/Eigen3/Eigen/src/Core/Array.h
@@ -124,6 +124,21 @@ class Array
}
#endif
+#ifdef EIGEN_HAVE_RVALUE_REFERENCES
+ Array(Array&& other)
+ : Base(std::move(other))
+ {
+ Base::_check_template_params();
+ if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic)
+ Base::_set_noalias(other);
+ }
+ Array& operator=(Array&& other)
+ {
+ other.swap(*this);
+ return *this;
+ }
+#endif
+
/** Constructs a vector or row-vector with given dimension. \only_for_vectors
*
* Note that this is only useful for dynamic-size vectors. For fixed-size vectors,
diff --git a/extern/Eigen3/Eigen/src/Core/ArrayBase.h b/extern/Eigen3/Eigen/src/Core/ArrayBase.h
index 38852600dc2..33ff553712e 100644
--- a/extern/Eigen3/Eigen/src/Core/ArrayBase.h
+++ b/extern/Eigen3/Eigen/src/Core/ArrayBase.h
@@ -46,9 +46,6 @@ template<typename Derived> class ArrayBase
typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl;
- using internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
- typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>::operator*;
-
typedef typename internal::traits<Derived>::StorageKind StorageKind;
typedef typename internal::traits<Derived>::Index Index;
typedef typename internal::traits<Derived>::Scalar Scalar;
@@ -56,6 +53,7 @@ template<typename Derived> class ArrayBase
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef DenseBase<Derived> Base;
+ using Base::operator*;
using Base::RowsAtCompileTime;
using Base::ColsAtCompileTime;
using Base::SizeAtCompileTime;
diff --git a/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h b/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h
index a791bc3581a..b4641e2a01f 100644
--- a/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h
+++ b/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h
@@ -29,6 +29,11 @@ struct traits<ArrayWrapper<ExpressionType> >
: public traits<typename remove_all<typename ExpressionType::Nested>::type >
{
typedef ArrayXpr XprKind;
+ // Let's remove NestByRefBit
+ enum {
+ Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags,
+ Flags = Flags0 & ~NestByRefBit
+ };
};
}
@@ -149,6 +154,11 @@ struct traits<MatrixWrapper<ExpressionType> >
: public traits<typename remove_all<typename ExpressionType::Nested>::type >
{
typedef MatrixXpr XprKind;
+ // Let's remove NestByRefBit
+ enum {
+ Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags,
+ Flags = Flags0 & ~NestByRefBit
+ };
};
}
diff --git a/extern/Eigen3/Eigen/src/Core/Assign.h b/extern/Eigen3/Eigen/src/Core/Assign.h
index 1dccc2f4212..f4817317279 100644
--- a/extern/Eigen3/Eigen/src/Core/Assign.h
+++ b/extern/Eigen3/Eigen/src/Core/Assign.h
@@ -439,19 +439,26 @@ struct assign_impl<Derived1, Derived2, SliceVectorizedTraversal, NoUnrolling, Ve
typedef typename Derived1::Index Index;
static inline void run(Derived1 &dst, const Derived2 &src)
{
- typedef packet_traits<typename Derived1::Scalar> PacketTraits;
+ typedef typename Derived1::Scalar Scalar;
+ typedef packet_traits<Scalar> PacketTraits;
enum {
packetSize = PacketTraits::size,
alignable = PacketTraits::AlignedOnScalar,
- dstAlignment = alignable ? Aligned : int(assign_traits<Derived1,Derived2>::DstIsAligned) ,
+ dstIsAligned = assign_traits<Derived1,Derived2>::DstIsAligned,
+ dstAlignment = alignable ? Aligned : int(dstIsAligned),
srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment
};
+ const Scalar *dst_ptr = &dst.coeffRef(0,0);
+ if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0)
+ {
+ // the pointer is not aligend-on scalar, so alignment is not possible
+ return assign_impl<Derived1,Derived2,DefaultTraversal,NoUnrolling>::run(dst, src);
+ }
const Index packetAlignedMask = packetSize - 1;
const Index innerSize = dst.innerSize();
const Index outerSize = dst.outerSize();
const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0;
- Index alignedStart = ((!alignable) || assign_traits<Derived1,Derived2>::DstIsAligned) ? 0
- : internal::first_aligned(&dst.coeffRef(0,0), innerSize);
+ Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize);
for(Index outer = 0; outer < outerSize; ++outer)
{
diff --git a/extern/Eigen3/Eigen/src/Core/Block.h b/extern/Eigen3/Eigen/src/Core/Block.h
index 358b3188b38..82789444327 100644
--- a/extern/Eigen3/Eigen/src/Core/Block.h
+++ b/extern/Eigen3/Eigen/src/Core/Block.h
@@ -66,8 +66,9 @@ struct traits<Block<XprType, BlockRows, BlockCols, InnerPanel> > : traits<XprTyp
: ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime)
: int(traits<XprType>::MaxColsAtCompileTime),
XprTypeIsRowMajor = (int(traits<XprType>::Flags)&RowMajorBit) != 0,
- IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1
- : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0
+ IsDense = is_same<StorageKind,Dense>::value,
+ IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1
+ : (IsDense&&MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0
: XprTypeIsRowMajor,
HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor),
InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime),
@@ -81,7 +82,7 @@ struct traits<Block<XprType, BlockRows, BlockCols, InnerPanel> > : traits<XprTyp
&& (InnerStrideAtCompileTime == 1)
? PacketAccessBit : 0,
MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0,
- FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0,
+ FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits<XprType>::Flags&LinearAccessBit))) ? LinearAccessBit : 0,
FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0,
FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0,
Flags0 = traits<XprType>::Flags & ( (HereditaryBits & ~RowMajorBit) |
diff --git a/extern/Eigen3/Eigen/src/Core/CommaInitializer.h b/extern/Eigen3/Eigen/src/Core/CommaInitializer.h
index a96867af4d5..a036d8c3bc9 100644
--- a/extern/Eigen3/Eigen/src/Core/CommaInitializer.h
+++ b/extern/Eigen3/Eigen/src/Core/CommaInitializer.h
@@ -43,6 +43,17 @@ struct CommaInitializer
m_xpr.block(0, 0, other.rows(), other.cols()) = other;
}
+ /* Copy/Move constructor which transfers ownership. This is crucial in
+ * absence of return value optimization to avoid assertions during destruction. */
+ // FIXME in C++11 mode this could be replaced by a proper RValue constructor
+ inline CommaInitializer(const CommaInitializer& o)
+ : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) {
+ // Mark original object as finished. In absence of R-value references we need to const_cast:
+ const_cast<CommaInitializer&>(o).m_row = m_xpr.rows();
+ const_cast<CommaInitializer&>(o).m_col = m_xpr.cols();
+ const_cast<CommaInitializer&>(o).m_currentBlockRows = 0;
+ }
+
/* inserts a scalar value in the target matrix */
CommaInitializer& operator,(const Scalar& s)
{
diff --git a/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h
index 586f77aaf32..519a866e605 100644
--- a/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h
+++ b/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h
@@ -81,7 +81,8 @@ struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> >
)
),
Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit),
- CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits<BinaryOp>::Cost
+ Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost),
+ CoeffReadCost = EIGEN_ADD_COST(Cost0,functor_traits<BinaryOp>::Cost)
};
};
} // end namespace internal
diff --git a/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h
index f2de749f92b..f7ee60e9879 100644
--- a/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h
+++ b/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h
@@ -47,7 +47,7 @@ struct traits<CwiseUnaryOp<UnaryOp, XprType> >
Flags = _XprTypeNested::Flags & (
HereditaryBits | LinearAccessBit | AlignedBit
| (functor_traits<UnaryOp>::PacketAccess ? PacketAccessBit : 0)),
- CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits<UnaryOp>::Cost
+ CoeffReadCost = EIGEN_ADD_COST(_XprTypeNested::CoeffReadCost, functor_traits<UnaryOp>::Cost)
};
};
}
diff --git a/extern/Eigen3/Eigen/src/Core/DenseBase.h b/extern/Eigen3/Eigen/src/Core/DenseBase.h
index c5800f6c8c8..4b371b075b8 100644
--- a/extern/Eigen3/Eigen/src/Core/DenseBase.h
+++ b/extern/Eigen3/Eigen/src/Core/DenseBase.h
@@ -40,15 +40,14 @@ static inline void check_DenseIndex_is_signed() {
*/
template<typename Derived> class DenseBase
#ifndef EIGEN_PARSED_BY_DOXYGEN
- : public internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
- typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>
+ : public internal::special_scalar_op_base<Derived, typename internal::traits<Derived>::Scalar,
+ typename NumTraits<typename internal::traits<Derived>::Scalar>::Real,
+ DenseCoeffsBase<Derived> >
#else
: public DenseCoeffsBase<Derived>
#endif // not EIGEN_PARSED_BY_DOXYGEN
{
public:
- using internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
- typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>::operator*;
class InnerIterator;
@@ -63,8 +62,9 @@ template<typename Derived> class DenseBase
typedef typename internal::traits<Derived>::Scalar Scalar;
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
+ typedef internal::special_scalar_op_base<Derived,Scalar,RealScalar, DenseCoeffsBase<Derived> > Base;
- typedef DenseCoeffsBase<Derived> Base;
+ using Base::operator*;
using Base::derived;
using Base::const_cast_derived;
using Base::rows;
@@ -183,10 +183,6 @@ template<typename Derived> class DenseBase
/** \returns the number of nonzero coefficients which is in practice the number
* of stored coefficients. */
inline Index nonZeros() const { return size(); }
- /** \returns true if either the number of rows or the number of columns is equal to 1.
- * In other words, this function returns
- * \code rows()==1 || cols()==1 \endcode
- * \sa rows(), cols(), IsVectorAtCompileTime. */
/** \returns the outer size.
*
@@ -266,11 +262,13 @@ template<typename Derived> class DenseBase
template<typename OtherDerived>
Derived& operator=(const ReturnByValue<OtherDerived>& func);
-#ifndef EIGEN_PARSED_BY_DOXYGEN
- /** Copies \a other into *this without evaluating other. \returns a reference to *this. */
+ /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */
template<typename OtherDerived>
Derived& lazyAssign(const DenseBase<OtherDerived>& other);
-#endif // not EIGEN_PARSED_BY_DOXYGEN
+
+ /** \internal Evaluates \a other into *this. \returns a reference to *this. */
+ template<typename OtherDerived>
+ Derived& lazyAssign(const ReturnByValue<OtherDerived>& other);
CommaInitializer<Derived> operator<< (const Scalar& s);
@@ -462,8 +460,10 @@ template<typename Derived> class DenseBase
template<int p> RealScalar lpNorm() const;
template<int RowFactor, int ColFactor>
- const Replicate<Derived,RowFactor,ColFactor> replicate() const;
- const Replicate<Derived,Dynamic,Dynamic> replicate(Index rowFacor,Index colFactor) const;
+ inline const Replicate<Derived,RowFactor,ColFactor> replicate() const;
+
+ typedef Replicate<Derived,Dynamic,Dynamic> ReplicateReturnType;
+ inline const ReplicateReturnType replicate(Index rowFacor,Index colFactor) const;
typedef Reverse<Derived, BothDirections> ReverseReturnType;
typedef const Reverse<const Derived, BothDirections> ConstReverseReturnType;
diff --git a/extern/Eigen3/Eigen/src/Core/DenseStorage.h b/extern/Eigen3/Eigen/src/Core/DenseStorage.h
index 3e7f9c1b7a7..568493cbae0 100644
--- a/extern/Eigen3/Eigen/src/Core/DenseStorage.h
+++ b/extern/Eigen3/Eigen/src/Core/DenseStorage.h
@@ -24,6 +24,14 @@ namespace internal {
struct constructor_without_unaligned_array_assert {};
+template<typename T, int Size> void check_static_allocation_size()
+{
+ // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit
+ #if EIGEN_STACK_ALLOCATION_LIMIT
+ EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);
+ #endif
+}
+
/** \internal
* Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned:
* to 16 bytes boundary if the total size is a multiple of 16 bytes.
@@ -38,12 +46,12 @@ struct plain_array
plain_array()
{
- EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);
+ check_static_allocation_size<T,Size>();
}
plain_array(constructor_without_unaligned_array_assert)
{
- EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);
+ check_static_allocation_size<T,Size>();
}
};
@@ -76,12 +84,12 @@ struct plain_array<T, Size, MatrixOrArrayOptions, 16>
plain_array()
{
EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf);
- EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);
+ check_static_allocation_size<T,Size>();
}
plain_array(constructor_without_unaligned_array_assert)
{
- EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG);
+ check_static_allocation_size<T,Size>();
}
};
@@ -114,33 +122,41 @@ template<typename T, int Size, int _Rows, int _Cols, int _Options> class DenseSt
{
internal::plain_array<T,Size,_Options> m_data;
public:
- inline DenseStorage() {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ DenseStorage() {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert)
: m_data(internal::constructor_without_unaligned_array_assert()) {}
- inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
- inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); }
- static inline DenseIndex rows(void) {return _Rows;}
- static inline DenseIndex cols(void) {return _Cols;}
- inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
- inline void resize(DenseIndex,DenseIndex,DenseIndex) {}
- inline const T *data() const { return m_data.array; }
- inline T *data() { return m_data.array; }
+ DenseStorage(const DenseStorage& other) : m_data(other.m_data) {}
+ DenseStorage& operator=(const DenseStorage& other)
+ {
+ if (this != &other) m_data = other.m_data;
+ return *this;
+ }
+ DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
+ void swap(DenseStorage& other) { std::swap(m_data,other.m_data); }
+ static DenseIndex rows(void) {return _Rows;}
+ static DenseIndex cols(void) {return _Cols;}
+ void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
+ void resize(DenseIndex,DenseIndex,DenseIndex) {}
+ const T *data() const { return m_data.array; }
+ T *data() { return m_data.array; }
};
// null matrix
template<typename T, int _Rows, int _Cols, int _Options> class DenseStorage<T, 0, _Rows, _Cols, _Options>
{
public:
- inline DenseStorage() {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert) {}
- inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
- inline void swap(DenseStorage& ) {}
- static inline DenseIndex rows(void) {return _Rows;}
- static inline DenseIndex cols(void) {return _Cols;}
- inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
- inline void resize(DenseIndex,DenseIndex,DenseIndex) {}
- inline const T *data() const { return 0; }
- inline T *data() { return 0; }
+ DenseStorage() {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert) {}
+ DenseStorage(const DenseStorage&) {}
+ DenseStorage& operator=(const DenseStorage&) { return *this; }
+ DenseStorage(DenseIndex,DenseIndex,DenseIndex) {}
+ void swap(DenseStorage& ) {}
+ static DenseIndex rows(void) {return _Rows;}
+ static DenseIndex cols(void) {return _Cols;}
+ void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {}
+ void resize(DenseIndex,DenseIndex,DenseIndex) {}
+ const T *data() const { return 0; }
+ T *data() { return 0; }
};
// more specializations for null matrices; these are necessary to resolve ambiguities
@@ -160,18 +176,29 @@ template<typename T, int Size, int _Options> class DenseStorage<T, Size, Dynamic
DenseIndex m_rows;
DenseIndex m_cols;
public:
- inline DenseStorage() : m_rows(0), m_cols(0) {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ DenseStorage() : m_rows(0), m_cols(0) {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert)
: m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {}
- inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {}
- inline void swap(DenseStorage& other)
+ DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {}
+ DenseStorage& operator=(const DenseStorage& other)
+ {
+ if (this != &other)
+ {
+ m_data = other.m_data;
+ m_rows = other.m_rows;
+ m_cols = other.m_cols;
+ }
+ return *this;
+ }
+ DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {}
+ void swap(DenseStorage& other)
{ std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); }
- inline DenseIndex rows() const {return m_rows;}
- inline DenseIndex cols() const {return m_cols;}
- inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; }
- inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; }
- inline const T *data() const { return m_data.array; }
- inline T *data() { return m_data.array; }
+ DenseIndex rows() const {return m_rows;}
+ DenseIndex cols() const {return m_cols;}
+ void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; }
+ void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; }
+ const T *data() const { return m_data.array; }
+ T *data() { return m_data.array; }
};
// dynamic-size matrix with fixed-size storage and fixed width
@@ -180,17 +207,27 @@ template<typename T, int Size, int _Cols, int _Options> class DenseStorage<T, Si
internal::plain_array<T,Size,_Options> m_data;
DenseIndex m_rows;
public:
- inline DenseStorage() : m_rows(0) {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ DenseStorage() : m_rows(0) {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert)
: m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {}
- inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {}
- inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
- inline DenseIndex rows(void) const {return m_rows;}
- inline DenseIndex cols(void) const {return _Cols;}
- inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; }
- inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; }
- inline const T *data() const { return m_data.array; }
- inline T *data() { return m_data.array; }
+ DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {}
+ DenseStorage& operator=(const DenseStorage& other)
+ {
+ if (this != &other)
+ {
+ m_data = other.m_data;
+ m_rows = other.m_rows;
+ }
+ return *this;
+ }
+ DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {}
+ void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
+ DenseIndex rows(void) const {return m_rows;}
+ DenseIndex cols(void) const {return _Cols;}
+ void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; }
+ void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; }
+ const T *data() const { return m_data.array; }
+ T *data() { return m_data.array; }
};
// dynamic-size matrix with fixed-size storage and fixed height
@@ -199,17 +236,27 @@ template<typename T, int Size, int _Rows, int _Options> class DenseStorage<T, Si
internal::plain_array<T,Size,_Options> m_data;
DenseIndex m_cols;
public:
- inline DenseStorage() : m_cols(0) {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ DenseStorage() : m_cols(0) {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert)
: m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {}
- inline DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {}
- inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
- inline DenseIndex rows(void) const {return _Rows;}
- inline DenseIndex cols(void) const {return m_cols;}
- inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; }
- inline void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; }
- inline const T *data() const { return m_data.array; }
- inline T *data() { return m_data.array; }
+ DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {}
+ DenseStorage& operator=(const DenseStorage& other)
+ {
+ if (this != &other)
+ {
+ m_data = other.m_data;
+ m_cols = other.m_cols;
+ }
+ return *this;
+ }
+ DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {}
+ void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
+ DenseIndex rows(void) const {return _Rows;}
+ DenseIndex cols(void) const {return m_cols;}
+ void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; }
+ void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; }
+ const T *data() const { return m_data.array; }
+ T *data() { return m_data.array; }
};
// purely dynamic matrix.
@@ -219,18 +266,35 @@ template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynam
DenseIndex m_rows;
DenseIndex m_cols;
public:
- inline DenseStorage() : m_data(0), m_rows(0), m_cols(0) {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert)
+ DenseStorage() : m_data(0), m_rows(0), m_cols(0) {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert)
: m_data(0), m_rows(0), m_cols(0) {}
- inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
+ DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
: m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows), m_cols(nbCols)
{ EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
- inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); }
- inline void swap(DenseStorage& other)
+#ifdef EIGEN_HAVE_RVALUE_REFERENCES
+ DenseStorage(DenseStorage&& other)
+ : m_data(std::move(other.m_data))
+ , m_rows(std::move(other.m_rows))
+ , m_cols(std::move(other.m_cols))
+ {
+ other.m_data = nullptr;
+ }
+ DenseStorage& operator=(DenseStorage&& other)
+ {
+ using std::swap;
+ swap(m_data, other.m_data);
+ swap(m_rows, other.m_rows);
+ swap(m_cols, other.m_cols);
+ return *this;
+ }
+#endif
+ ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); }
+ void swap(DenseStorage& other)
{ std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); }
- inline DenseIndex rows(void) const {return m_rows;}
- inline DenseIndex cols(void) const {return m_cols;}
- inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
+ DenseIndex rows(void) const {return m_rows;}
+ DenseIndex cols(void) const {return m_cols;}
+ void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols)
{
m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*m_cols);
m_rows = nbRows;
@@ -250,8 +314,11 @@ template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynam
m_rows = nbRows;
m_cols = nbCols;
}
- inline const T *data() const { return m_data; }
- inline T *data() { return m_data; }
+ const T *data() const { return m_data; }
+ T *data() { return m_data; }
+ private:
+ DenseStorage(const DenseStorage&);
+ DenseStorage& operator=(const DenseStorage&);
};
// matrix with dynamic width and fixed height (so that matrix has dynamic size).
@@ -260,15 +327,30 @@ template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Ro
T *m_data;
DenseIndex m_cols;
public:
- inline DenseStorage() : m_data(0), m_cols(0) {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {}
- inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(nbCols)
+ DenseStorage() : m_data(0), m_cols(0) {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {}
+ DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(nbCols)
{ EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
- inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); }
- inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
- static inline DenseIndex rows(void) {return _Rows;}
- inline DenseIndex cols(void) const {return m_cols;}
- inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols)
+#ifdef EIGEN_HAVE_RVALUE_REFERENCES
+ DenseStorage(DenseStorage&& other)
+ : m_data(std::move(other.m_data))
+ , m_cols(std::move(other.m_cols))
+ {
+ other.m_data = nullptr;
+ }
+ DenseStorage& operator=(DenseStorage&& other)
+ {
+ using std::swap;
+ swap(m_data, other.m_data);
+ swap(m_cols, other.m_cols);
+ return *this;
+ }
+#endif
+ ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); }
+ void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); }
+ static DenseIndex rows(void) {return _Rows;}
+ DenseIndex cols(void) const {return m_cols;}
+ void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols)
{
m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, _Rows*m_cols);
m_cols = nbCols;
@@ -286,8 +368,11 @@ template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Ro
}
m_cols = nbCols;
}
- inline const T *data() const { return m_data; }
- inline T *data() { return m_data; }
+ const T *data() const { return m_data; }
+ T *data() { return m_data; }
+ private:
+ DenseStorage(const DenseStorage&);
+ DenseStorage& operator=(const DenseStorage&);
};
// matrix with dynamic height and fixed width (so that matrix has dynamic size).
@@ -296,15 +381,30 @@ template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dyn
T *m_data;
DenseIndex m_rows;
public:
- inline DenseStorage() : m_data(0), m_rows(0) {}
- inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {}
- inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows)
+ DenseStorage() : m_data(0), m_rows(0) {}
+ DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {}
+ DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows)
{ EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN }
- inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); }
- inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
- inline DenseIndex rows(void) const {return m_rows;}
- static inline DenseIndex cols(void) {return _Cols;}
- inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex)
+#ifdef EIGEN_HAVE_RVALUE_REFERENCES
+ DenseStorage(DenseStorage&& other)
+ : m_data(std::move(other.m_data))
+ , m_rows(std::move(other.m_rows))
+ {
+ other.m_data = nullptr;
+ }
+ DenseStorage& operator=(DenseStorage&& other)
+ {
+ using std::swap;
+ swap(m_data, other.m_data);
+ swap(m_rows, other.m_rows);
+ return *this;
+ }
+#endif
+ ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); }
+ void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); }
+ DenseIndex rows(void) const {return m_rows;}
+ static DenseIndex cols(void) {return _Cols;}
+ void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex)
{
m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*_Cols);
m_rows = nbRows;
@@ -322,8 +422,11 @@ template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dyn
}
m_rows = nbRows;
}
- inline const T *data() const { return m_data; }
- inline T *data() { return m_data; }
+ const T *data() const { return m_data; }
+ T *data() { return m_data; }
+ private:
+ DenseStorage(const DenseStorage&);
+ DenseStorage& operator=(const DenseStorage&);
};
} // end namespace Eigen
diff --git a/extern/Eigen3/Eigen/src/Core/Diagonal.h b/extern/Eigen3/Eigen/src/Core/Diagonal.h
index aab8007b3fc..68cf6d4b044 100644
--- a/extern/Eigen3/Eigen/src/Core/Diagonal.h
+++ b/extern/Eigen3/Eigen/src/Core/Diagonal.h
@@ -190,18 +190,18 @@ MatrixBase<Derived>::diagonal() const
*
* \sa MatrixBase::diagonal(), class Diagonal */
template<typename Derived>
-inline typename MatrixBase<Derived>::template DiagonalIndexReturnType<DynamicIndex>::Type
+inline typename MatrixBase<Derived>::DiagonalDynamicIndexReturnType
MatrixBase<Derived>::diagonal(Index index)
{
- return typename DiagonalIndexReturnType<DynamicIndex>::Type(derived(), index);
+ return DiagonalDynamicIndexReturnType(derived(), index);
}
/** This is the const version of diagonal(Index). */
template<typename Derived>
-inline typename MatrixBase<Derived>::template ConstDiagonalIndexReturnType<DynamicIndex>::Type
+inline typename MatrixBase<Derived>::ConstDiagonalDynamicIndexReturnType
MatrixBase<Derived>::diagonal(Index index) const
{
- return typename ConstDiagonalIndexReturnType<DynamicIndex>::Type(derived(), index);
+ return ConstDiagonalDynamicIndexReturnType(derived(), index);
}
/** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this
diff --git a/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h b/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h
index c03a0c2e12b..cc6b536e199 100644
--- a/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h
+++ b/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h
@@ -34,8 +34,9 @@ struct traits<DiagonalProduct<MatrixType, DiagonalType, ProductOrder> >
_Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))),
_LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0,
- Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit,//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit),
- CoeffReadCost = NumTraits<Scalar>::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost
+ Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit),
+ Cost0 = EIGEN_ADD_COST(NumTraits<Scalar>::MulCost, MatrixType::CoeffReadCost),
+ CoeffReadCost = EIGEN_ADD_COST(Cost0,DiagonalType::DiagonalVectorType::CoeffReadCost)
};
};
}
diff --git a/extern/Eigen3/Eigen/src/Core/Functors.h b/extern/Eigen3/Eigen/src/Core/Functors.h
index 04fb217323d..5f14c6587e0 100644
--- a/extern/Eigen3/Eigen/src/Core/Functors.h
+++ b/extern/Eigen3/Eigen/src/Core/Functors.h
@@ -259,6 +259,47 @@ template<> struct functor_traits<scalar_boolean_or_op> {
};
};
+/** \internal
+ * \brief Template functors for comparison of two scalars
+ * \todo Implement packet-comparisons
+ */
+template<typename Scalar, ComparisonName cmp> struct scalar_cmp_op;
+
+template<typename Scalar, ComparisonName cmp>
+struct functor_traits<scalar_cmp_op<Scalar, cmp> > {
+ enum {
+ Cost = NumTraits<Scalar>::AddCost,
+ PacketAccess = false
+ };
+};
+
+template<ComparisonName Cmp, typename Scalar>
+struct result_of<scalar_cmp_op<Scalar, Cmp>(Scalar,Scalar)> {
+ typedef bool type;
+};
+
+
+template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_EQ> {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
+ EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;}
+};
+template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_LT> {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
+ EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<b;}
+};
+template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_LE> {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
+ EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;}
+};
+template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_UNORD> {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
+ EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);}
+};
+template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_NEQ> {
+ EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op)
+ EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;}
+};
+
// unary functors:
/** \internal
@@ -589,7 +630,7 @@ struct linspaced_op_impl<Scalar,true>
template<typename Index>
EIGEN_STRONG_INLINE const Packet packetOp(Index i) const
- { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1<Packet>(i),m_interPacket))); }
+ { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1<Packet>(Scalar(i)),m_interPacket))); }
const Scalar m_low;
const Scalar m_step;
@@ -609,7 +650,7 @@ template <typename Scalar, bool RandomAccess> struct functor_traits< linspaced_o
template <typename Scalar, bool RandomAccess> struct linspaced_op
{
typedef typename packet_traits<Scalar>::type Packet;
- linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/(num_steps-1))) {}
+ linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {}
template<typename Index>
EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); }
diff --git a/extern/Eigen3/Eigen/src/Core/GeneralProduct.h b/extern/Eigen3/Eigen/src/Core/GeneralProduct.h
index 2a59d94645e..0eae529909f 100644
--- a/extern/Eigen3/Eigen/src/Core/GeneralProduct.h
+++ b/extern/Eigen3/Eigen/src/Core/GeneralProduct.h
@@ -232,7 +232,7 @@ EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest&
// FIXME not very good if rhs is real and lhs complex while alpha is real too
const Index cols = dest.cols();
for (Index j=0; j<cols; ++j)
- func(dest.col(j), prod.rhs().coeff(j) * prod.lhs());
+ func(dest.col(j), prod.rhs().coeff(0,j) * prod.lhs());
}
// Row major
@@ -243,7 +243,7 @@ EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest&
// FIXME not very good if lhs is real and rhs complex while alpha is real too
const Index rows = dest.rows();
for (Index i=0; i<rows; ++i)
- func(dest.row(i), prod.lhs().coeff(i) * prod.rhs());
+ func(dest.row(i), prod.lhs().coeff(i,0) * prod.rhs());
}
template<typename Lhs, typename Rhs>
@@ -257,7 +257,7 @@ template<typename Lhs, typename Rhs>
class GeneralProduct<Lhs, Rhs, OuterProduct>
: public ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs>
{
- template<typename T> struct IsRowMajor : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {};
+ template<typename T> struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {};
public:
EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct)
@@ -281,22 +281,22 @@ class GeneralProduct<Lhs, Rhs, OuterProduct>
template<typename Dest>
inline void evalTo(Dest& dest) const {
- internal::outer_product_selector_run(*this, dest, set(), IsRowMajor<Dest>());
+ internal::outer_product_selector_run(*this, dest, set(), is_row_major<Dest>());
}
template<typename Dest>
inline void addTo(Dest& dest) const {
- internal::outer_product_selector_run(*this, dest, add(), IsRowMajor<Dest>());
+ internal::outer_product_selector_run(*this, dest, add(), is_row_major<Dest>());
}
template<typename Dest>
inline void subTo(Dest& dest) const {
- internal::outer_product_selector_run(*this, dest, sub(), IsRowMajor<Dest>());
+ internal::outer_product_selector_run(*this, dest, sub(), is_row_major<Dest>());
}
template<typename Dest> void scaleAndAddTo(Dest& dest, const Scalar& alpha) const
{
- internal::outer_product_selector_run(*this, dest, adds(alpha), IsRowMajor<Dest>());
+ internal::outer_product_selector_run(*this, dest, adds(alpha), is_row_major<Dest>());
}
};
diff --git a/extern/Eigen3/Eigen/src/Core/MapBase.h b/extern/Eigen3/Eigen/src/Core/MapBase.h
index 6876de588c0..a9828f7f4b2 100644
--- a/extern/Eigen3/Eigen/src/Core/MapBase.h
+++ b/extern/Eigen3/Eigen/src/Core/MapBase.h
@@ -123,7 +123,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
return internal::ploadt<PacketScalar, LoadMode>(m_data + index * innerStride());
}
- inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime)
+ explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime)
{
EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived)
checkSanity();
@@ -157,7 +157,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
internal::inner_stride_at_compile_time<Derived>::ret==1),
PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1);
eigen_assert(EIGEN_IMPLIES(internal::traits<Derived>::Flags&AlignedBit, (size_t(m_data) % 16) == 0)
- && "data is not aligned");
+ && "input pointer is not aligned on a 16 byte boundary");
}
PointerType m_data;
@@ -168,6 +168,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors>
template<typename Derived> class MapBase<Derived, WriteAccessors>
: public MapBase<Derived, ReadOnlyAccessors>
{
+ typedef MapBase<Derived, ReadOnlyAccessors> ReadOnlyMapBase;
public:
typedef MapBase<Derived, ReadOnlyAccessors> Base;
@@ -230,13 +231,17 @@ template<typename Derived> class MapBase<Derived, WriteAccessors>
Derived& operator=(const MapBase& other)
{
- Base::Base::operator=(other);
+ ReadOnlyMapBase::Base::operator=(other);
return derived();
}
- using Base::Base::operator=;
+ // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base,
+ // see bugs 821 and 920.
+ using ReadOnlyMapBase::Base::operator=;
};
+#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS
+
} // end namespace Eigen
#endif // EIGEN_MAPBASE_H
diff --git a/extern/Eigen3/Eigen/src/Core/MathFunctions.h b/extern/Eigen3/Eigen/src/Core/MathFunctions.h
index 2bfc5ebd98a..adf2f9c511b 100644
--- a/extern/Eigen3/Eigen/src/Core/MathFunctions.h
+++ b/extern/Eigen3/Eigen/src/Core/MathFunctions.h
@@ -294,7 +294,7 @@ struct hypot_impl
RealScalar _x = abs(x);
RealScalar _y = abs(y);
RealScalar p = (max)(_x, _y);
- if(p==RealScalar(0)) return 0;
+ if(p==RealScalar(0)) return RealScalar(0);
RealScalar q = (min)(_x, _y);
RealScalar qp = q/p;
return p * sqrt(RealScalar(1) + qp*qp);
diff --git a/extern/Eigen3/Eigen/src/Core/Matrix.h b/extern/Eigen3/Eigen/src/Core/Matrix.h
index d7d0b5b9a4f..02be142d8cc 100644
--- a/extern/Eigen3/Eigen/src/Core/Matrix.h
+++ b/extern/Eigen3/Eigen/src/Core/Matrix.h
@@ -211,6 +211,21 @@ class Matrix
: Base(internal::constructor_without_unaligned_array_assert())
{ Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED }
+#ifdef EIGEN_HAVE_RVALUE_REFERENCES
+ Matrix(Matrix&& other)
+ : Base(std::move(other))
+ {
+ Base::_check_template_params();
+ if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic)
+ Base::_set_noalias(other);
+ }
+ Matrix& operator=(Matrix&& other)
+ {
+ other.swap(*this);
+ return *this;
+ }
+#endif
+
/** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors
*
* Note that this is only useful for dynamic-size vectors. For fixed-size vectors,
diff --git a/extern/Eigen3/Eigen/src/Core/MatrixBase.h b/extern/Eigen3/Eigen/src/Core/MatrixBase.h
index 344b38f2fc7..e83ef4dc056 100644
--- a/extern/Eigen3/Eigen/src/Core/MatrixBase.h
+++ b/extern/Eigen3/Eigen/src/Core/MatrixBase.h
@@ -159,13 +159,11 @@ template<typename Derived> class MatrixBase
template<typename OtherDerived>
Derived& operator=(const ReturnByValue<OtherDerived>& other);
-#ifndef EIGEN_PARSED_BY_DOXYGEN
template<typename ProductDerived, typename Lhs, typename Rhs>
Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other);
template<typename MatrixPower, typename Lhs, typename Rhs>
Derived& lazyAssign(const MatrixPowerProduct<MatrixPower, Lhs,Rhs>& other);
-#endif // not EIGEN_PARSED_BY_DOXYGEN
template<typename OtherDerived>
Derived& operator+=(const MatrixBase<OtherDerived>& other);
@@ -215,7 +213,7 @@ template<typename Derived> class MatrixBase
typedef Diagonal<Derived> DiagonalReturnType;
DiagonalReturnType diagonal();
- typedef typename internal::add_const<Diagonal<const Derived> >::type ConstDiagonalReturnType;
+ typedef typename internal::add_const<Diagonal<const Derived> >::type ConstDiagonalReturnType;
ConstDiagonalReturnType diagonal() const;
template<int Index> struct DiagonalIndexReturnType { typedef Diagonal<Derived,Index> Type; };
@@ -223,16 +221,12 @@ template<typename Derived> class MatrixBase
template<int Index> typename DiagonalIndexReturnType<Index>::Type diagonal();
template<int Index> typename ConstDiagonalIndexReturnType<Index>::Type diagonal() const;
+
+ typedef Diagonal<Derived,DynamicIndex> DiagonalDynamicIndexReturnType;
+ typedef typename internal::add_const<Diagonal<const Derived,DynamicIndex> >::type ConstDiagonalDynamicIndexReturnType;
- // Note: The "MatrixBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations.
- // On the other hand they confuse MSVC8...
- #if (defined _MSC_VER) && (_MSC_VER >= 1500) // 2008 or later
- typename MatrixBase::template DiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index);
- typename MatrixBase::template ConstDiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index) const;
- #else
- typename DiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index);
- typename ConstDiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index) const;
- #endif
+ DiagonalDynamicIndexReturnType diagonal(Index index);
+ ConstDiagonalDynamicIndexReturnType diagonal(Index index) const;
#ifdef EIGEN2_SUPPORT
template<unsigned int Mode> typename internal::eigen2_part_return_type<Derived, Mode>::type part();
@@ -446,6 +440,15 @@ template<typename Derived> class MatrixBase
template<typename OtherScalar>
void applyOnTheRight(Index p, Index q, const JacobiRotation<OtherScalar>& j);
+///////// SparseCore module /////////
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE const typename SparseMatrixBase<OtherDerived>::template CwiseProductDenseReturnType<Derived>::Type
+ cwiseProduct(const SparseMatrixBase<OtherDerived> &other) const
+ {
+ return other.cwiseProduct(derived());
+ }
+
///////// MatrixFunctions module /////////
typedef typename internal::stem_function<Scalar>::type StemFunction;
diff --git a/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h b/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h
index 1297b8413fb..85ffae2653b 100644
--- a/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h
+++ b/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h
@@ -250,6 +250,35 @@ class PermutationBase : public EigenBase<Derived>
template<typename Other> friend
inline PlainPermutationType operator*(const Transpose<PermutationBase<Other> >& other, const PermutationBase& perm)
{ return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); }
+
+ /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation.
+ *
+ * This function is O(\c n) procedure allocating a buffer of \c n booleans.
+ */
+ Index determinant() const
+ {
+ Index res = 1;
+ Index n = size();
+ Matrix<bool,RowsAtCompileTime,1,0,MaxRowsAtCompileTime> mask(n);
+ mask.fill(false);
+ Index r = 0;
+ while(r < n)
+ {
+ // search for the next seed
+ while(r<n && mask[r]) r++;
+ if(r>=n)
+ break;
+ // we got one, let's follow it until we are back to the seed
+ Index k0 = r++;
+ mask.coeffRef(k0) = true;
+ for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k))
+ {
+ mask.coeffRef(k) = true;
+ res = -res;
+ }
+ }
+ return res;
+ }
protected:
@@ -555,7 +584,10 @@ struct permut_matrix_product_retval
const Index n = Side==OnTheLeft ? rows() : cols();
// FIXME we need an is_same for expression that is not sensitive to constness. For instance
// is_same_xpr<Block<const Matrix>, Block<Matrix> >::value should be true.
- if(is_same<MatrixTypeNestedCleaned,Dest>::value && extract_data(dst) == extract_data(m_matrix))
+ if( is_same<MatrixTypeNestedCleaned,Dest>::value
+ && blas_traits<MatrixTypeNestedCleaned>::HasUsableDirectAccess
+ && blas_traits<Dest>::HasUsableDirectAccess
+ && extract_data(dst) == extract_data(m_matrix))
{
// apply the permutation inplace
Matrix<bool,PermutationType::RowsAtCompileTime,1,0,PermutationType::MaxRowsAtCompileTime> mask(m_permutation.size());
diff --git a/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h b/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h
index dd34b59e541..a4e4af4a7b2 100644
--- a/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h
+++ b/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h
@@ -437,6 +437,36 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
}
#endif
+#ifdef EIGEN_HAVE_RVALUE_REFERENCES
+ PlainObjectBase(PlainObjectBase&& other)
+ : m_storage( std::move(other.m_storage) )
+ {
+ }
+
+ PlainObjectBase& operator=(PlainObjectBase&& other)
+ {
+ using std::swap;
+ swap(m_storage, other.m_storage);
+ return *this;
+ }
+#endif
+
+ /** Copy constructor */
+ EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other)
+ : m_storage()
+ {
+ _check_template_params();
+ lazyAssign(other);
+ }
+
+ template<typename OtherDerived>
+ EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase<OtherDerived> &other)
+ : m_storage()
+ {
+ _check_template_params();
+ lazyAssign(other);
+ }
+
EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols)
: m_storage(a_size, nbRows, nbCols)
{
@@ -573,6 +603,8 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type
: (rows() == other.rows() && cols() == other.cols())))
&& "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined");
EIGEN_ONLY_USED_FOR_DEBUG(other);
+ if(this->size()==0)
+ resizeLike(other);
#else
resizeLike(other);
#endif
diff --git a/extern/Eigen3/Eigen/src/Core/ProductBase.h b/extern/Eigen3/Eigen/src/Core/ProductBase.h
index a494b5f8703..cf74470a9a1 100644
--- a/extern/Eigen3/Eigen/src/Core/ProductBase.h
+++ b/extern/Eigen3/Eigen/src/Core/ProductBase.h
@@ -85,7 +85,14 @@ class ProductBase : public MatrixBase<Derived>
public:
+#ifndef EIGEN_NO_MALLOC
+ typedef typename Base::PlainObject BasePlainObject;
+ typedef Matrix<Scalar,RowsAtCompileTime==1?1:Dynamic,ColsAtCompileTime==1?1:Dynamic,BasePlainObject::Options> DynPlainObject;
+ typedef typename internal::conditional<(BasePlainObject::SizeAtCompileTime==Dynamic) || (BasePlainObject::SizeAtCompileTime*int(sizeof(Scalar)) < int(EIGEN_STACK_ALLOCATION_LIMIT)),
+ BasePlainObject, DynPlainObject>::type PlainObject;
+#else
typedef typename Base::PlainObject PlainObject;
+#endif
ProductBase(const Lhs& a_lhs, const Rhs& a_rhs)
: m_lhs(a_lhs), m_rhs(a_rhs)
@@ -180,7 +187,12 @@ namespace internal {
template<typename Lhs, typename Rhs, int Mode, int N, typename PlainObject>
struct nested<GeneralProduct<Lhs,Rhs,Mode>, N, PlainObject>
{
- typedef PlainObject const& type;
+ typedef typename GeneralProduct<Lhs,Rhs,Mode>::PlainObject const& type;
+};
+template<typename Lhs, typename Rhs, int Mode, int N, typename PlainObject>
+struct nested<const GeneralProduct<Lhs,Rhs,Mode>, N, PlainObject>
+{
+ typedef typename GeneralProduct<Lhs,Rhs,Mode>::PlainObject const& type;
};
}
diff --git a/extern/Eigen3/Eigen/src/Core/Redux.h b/extern/Eigen3/Eigen/src/Core/Redux.h
index 50548fa9a0e..9b8662a6f9a 100644
--- a/extern/Eigen3/Eigen/src/Core/Redux.h
+++ b/extern/Eigen3/Eigen/src/Core/Redux.h
@@ -247,8 +247,9 @@ struct redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling>
}
};
-template<typename Func, typename Derived>
-struct redux_impl<Func, Derived, SliceVectorizedTraversal, NoUnrolling>
+// NOTE: for SliceVectorizedTraversal we simply bypass unrolling
+template<typename Func, typename Derived, int Unrolling>
+struct redux_impl<Func, Derived, SliceVectorizedTraversal, Unrolling>
{
typedef typename Derived::Scalar Scalar;
typedef typename packet_traits<Scalar>::type PacketScalar;
diff --git a/extern/Eigen3/Eigen/src/Core/Ref.h b/extern/Eigen3/Eigen/src/Core/Ref.h
index 00d9e6d2b41..7a3becaf882 100644
--- a/extern/Eigen3/Eigen/src/Core/Ref.h
+++ b/extern/Eigen3/Eigen/src/Core/Ref.h
@@ -101,14 +101,15 @@ struct traits<Ref<_PlainObjectType, _Options, _StrideType> >
template<typename Derived> struct match {
enum {
HasDirectAccess = internal::has_direct_access<Derived>::ret,
- StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)),
+ StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)),
InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic)
|| int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime)
|| (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1),
OuterStrideMatch = Derived::IsVectorAtCompileTime
|| int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime),
AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits<Derived>::Flags&AlignedBit)==AlignedBit),
- MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch
+ ScalarTypeMatch = internal::is_same<typename PlainObjectType::Scalar, typename Derived::Scalar>::value,
+ MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch
};
typedef typename internal::conditional<MatchAtCompileTime,internal::true_type,internal::false_type>::type type;
};
@@ -172,8 +173,12 @@ protected:
}
else
::new (static_cast<Base*>(this)) Base(expr.data(), expr.rows(), expr.cols());
- ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(),
- StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride());
+
+ if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit)))
+ ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1);
+ else
+ ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(),
+ StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride());
}
StrideBase m_stride;
@@ -183,7 +188,11 @@ protected:
template<typename PlainObjectType, int Options, typename StrideType> class Ref
: public RefBase<Ref<PlainObjectType, Options, StrideType> >
{
+ private:
typedef internal::traits<Ref> Traits;
+ template<typename Derived>
+ inline Ref(const PlainObjectBase<Derived>& expr,
+ typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0);
public:
typedef RefBase<Ref> Base;
@@ -195,17 +204,20 @@ template<typename PlainObjectType, int Options, typename StrideType> class Ref
inline Ref(PlainObjectBase<Derived>& expr,
typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0)
{
- Base::construct(expr);
+ EIGEN_STATIC_ASSERT(static_cast<bool>(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH);
+ Base::construct(expr.derived());
}
template<typename Derived>
inline Ref(const DenseBase<Derived>& expr,
- typename internal::enable_if<bool(internal::is_lvalue<Derived>::value&&bool(Traits::template match<Derived>::MatchAtCompileTime)),Derived>::type* = 0,
- int = Derived::ThisConstantIsPrivateInPlainObjectBase)
+ typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0)
#else
template<typename Derived>
inline Ref(DenseBase<Derived>& expr)
#endif
{
+ EIGEN_STATIC_ASSERT(static_cast<bool>(internal::is_lvalue<Derived>::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY);
+ EIGEN_STATIC_ASSERT(static_cast<bool>(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH);
+ enum { THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY = Derived::ThisConstantIsPrivateInPlainObjectBase};
Base::construct(expr.const_cast_derived());
}
@@ -224,13 +236,23 @@ template<typename TPlainObjectType, int Options, typename StrideType> class Ref<
EIGEN_DENSE_PUBLIC_INTERFACE(Ref)
template<typename Derived>
- inline Ref(const DenseBase<Derived>& expr)
+ inline Ref(const DenseBase<Derived>& expr,
+ typename internal::enable_if<bool(Traits::template match<Derived>::ScalarTypeMatch),Derived>::type* = 0)
{
// std::cout << match_helper<Derived>::HasDirectAccess << "," << match_helper<Derived>::OuterStrideMatch << "," << match_helper<Derived>::InnerStrideMatch << "\n";
// std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n";
// std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n";
construct(expr.derived(), typename Traits::template match<Derived>::type());
}
+
+ inline Ref(const Ref& other) : Base(other) {
+ // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy
+ }
+
+ template<typename OtherRef>
+ inline Ref(const RefBase<OtherRef>& other) {
+ construct(other.derived(), typename Traits::template match<OtherRef>::type());
+ }
protected:
diff --git a/extern/Eigen3/Eigen/src/Core/Replicate.h b/extern/Eigen3/Eigen/src/Core/Replicate.h
index dde86a8349b..ac4537c1422 100644
--- a/extern/Eigen3/Eigen/src/Core/Replicate.h
+++ b/extern/Eigen3/Eigen/src/Core/Replicate.h
@@ -135,7 +135,7 @@ template<typename MatrixType,int RowFactor,int ColFactor> class Replicate
*/
template<typename Derived>
template<int RowFactor, int ColFactor>
-inline const Replicate<Derived,RowFactor,ColFactor>
+const Replicate<Derived,RowFactor,ColFactor>
DenseBase<Derived>::replicate() const
{
return Replicate<Derived,RowFactor,ColFactor>(derived());
@@ -150,7 +150,7 @@ DenseBase<Derived>::replicate() const
* \sa VectorwiseOp::replicate(), DenseBase::replicate<int,int>(), class Replicate
*/
template<typename Derived>
-inline const Replicate<Derived,Dynamic,Dynamic>
+const typename DenseBase<Derived>::ReplicateReturnType
DenseBase<Derived>::replicate(Index rowFactor,Index colFactor) const
{
return Replicate<Derived,Dynamic,Dynamic>(derived(),rowFactor,colFactor);
diff --git a/extern/Eigen3/Eigen/src/Core/ReturnByValue.h b/extern/Eigen3/Eigen/src/Core/ReturnByValue.h
index d66c24ba0f8..f635598dccf 100644
--- a/extern/Eigen3/Eigen/src/Core/ReturnByValue.h
+++ b/extern/Eigen3/Eigen/src/Core/ReturnByValue.h
@@ -72,6 +72,8 @@ template<typename Derived> class ReturnByValue
const Unusable& coeff(Index,Index) const { return *reinterpret_cast<const Unusable*>(this); }
Unusable& coeffRef(Index) { return *reinterpret_cast<Unusable*>(this); }
Unusable& coeffRef(Index,Index) { return *reinterpret_cast<Unusable*>(this); }
+ template<int LoadMode> Unusable& packet(Index) const;
+ template<int LoadMode> Unusable& packet(Index, Index) const;
#endif
};
@@ -83,6 +85,15 @@ Derived& DenseBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
return derived();
}
+template<typename Derived>
+template<typename OtherDerived>
+Derived& DenseBase<Derived>::lazyAssign(const ReturnByValue<OtherDerived>& other)
+{
+ other.evalTo(derived());
+ return derived();
+}
+
+
} // end namespace Eigen
#endif // EIGEN_RETURNBYVALUE_H
diff --git a/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h
index 22f3047b43f..0956475af51 100644
--- a/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h
+++ b/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h
@@ -180,15 +180,9 @@ inline Derived& DenseBase<Derived>::operator*=(const Scalar& other)
template<typename Derived>
inline Derived& DenseBase<Derived>::operator/=(const Scalar& other)
{
- typedef typename internal::conditional<NumTraits<Scalar>::IsInteger,
- internal::scalar_quotient_op<Scalar>,
- internal::scalar_product_op<Scalar> >::type BinOp;
typedef typename Derived::PlainObject PlainObject;
- SelfCwiseBinaryOp<BinOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived());
- Scalar actual_other;
- if(NumTraits<Scalar>::IsInteger) actual_other = other;
- else actual_other = Scalar(1)/other;
- tmp = PlainObject::Constant(rows(),cols(), actual_other);
+ SelfCwiseBinaryOp<internal::scalar_quotient_op<Scalar>, Derived, typename PlainObject::ConstantReturnType> tmp(derived());
+ tmp = PlainObject::Constant(rows(),cols(), other);
return derived();
}
diff --git a/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h b/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h
index fba07365f6f..4d65392c685 100644
--- a/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h
+++ b/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h
@@ -278,21 +278,21 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView
/** Efficient triangular matrix times vector/matrix product */
template<typename OtherDerived>
- TriangularProduct<Mode,true,MatrixType,false,OtherDerived, OtherDerived::IsVectorAtCompileTime>
+ TriangularProduct<Mode, true, MatrixType, false, OtherDerived, OtherDerived::ColsAtCompileTime==1>
operator*(const MatrixBase<OtherDerived>& rhs) const
{
return TriangularProduct
- <Mode,true,MatrixType,false,OtherDerived,OtherDerived::IsVectorAtCompileTime>
+ <Mode, true, MatrixType, false, OtherDerived, OtherDerived::ColsAtCompileTime==1>
(m_matrix, rhs.derived());
}
/** Efficient vector/matrix times triangular matrix product */
template<typename OtherDerived> friend
- TriangularProduct<Mode,false,OtherDerived,OtherDerived::IsVectorAtCompileTime,MatrixType,false>
+ TriangularProduct<Mode, false, OtherDerived, OtherDerived::RowsAtCompileTime==1, MatrixType, false>
operator*(const MatrixBase<OtherDerived>& lhs, const TriangularView& rhs)
{
return TriangularProduct
- <Mode,false,OtherDerived,OtherDerived::IsVectorAtCompileTime,MatrixType,false>
+ <Mode, false, OtherDerived, OtherDerived::RowsAtCompileTime==1, MatrixType, false>
(lhs.derived(),rhs.m_matrix);
}
@@ -380,19 +380,19 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView
EIGEN_STRONG_INLINE TriangularView& operator=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
{
setZero();
- return assignProduct(other,1);
+ return assignProduct(other.derived(),1);
}
template<typename ProductDerived, typename Lhs, typename Rhs>
EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
{
- return assignProduct(other,1);
+ return assignProduct(other.derived(),1);
}
template<typename ProductDerived, typename Lhs, typename Rhs>
EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase<ProductDerived, Lhs,Rhs>& other)
{
- return assignProduct(other,-1);
+ return assignProduct(other.derived(),-1);
}
@@ -400,25 +400,34 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView
EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct<ProductDerived>& other)
{
setZero();
- return assignProduct(other,other.alpha());
+ return assignProduct(other.derived(),other.alpha());
}
template<typename ProductDerived>
EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct<ProductDerived>& other)
{
- return assignProduct(other,other.alpha());
+ return assignProduct(other.derived(),other.alpha());
}
template<typename ProductDerived>
EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct<ProductDerived>& other)
{
- return assignProduct(other,-other.alpha());
+ return assignProduct(other.derived(),-other.alpha());
}
protected:
template<typename ProductDerived, typename Lhs, typename Rhs>
EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase<ProductDerived, Lhs,Rhs>& prod, const Scalar& alpha);
+
+ template<int Mode, bool LhsIsTriangular,
+ typename Lhs, bool LhsIsVector,
+ typename Rhs, bool RhsIsVector>
+ EIGEN_STRONG_INLINE TriangularView& assignProduct(const TriangularProduct<Mode, LhsIsTriangular, Lhs, LhsIsVector, Rhs, RhsIsVector>& prod, const Scalar& alpha)
+ {
+ lazyAssign(alpha*prod.eval());
+ return *this;
+ }
MatrixTypeNested m_matrix;
};
diff --git a/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h b/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h
index f183d31de2a..8d9255eef6a 100644
--- a/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h
+++ b/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h
@@ -110,7 +110,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex<
template<> EIGEN_STRONG_INLINE void pstore <std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); }
template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); }
-template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { __pld((float *)addr); }
+template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { EIGEN_ARM_PREFETCH((float *)addr); }
template<> EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet2cf>(const Packet2cf& a)
{
diff --git a/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h b/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h
index 163bac215e6..d49670e0410 100644
--- a/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h
+++ b/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h
@@ -48,9 +48,18 @@ typedef uint32x4_t Packet4ui;
#define EIGEN_INIT_NEON_PACKET2(X, Y) {X, Y}
#define EIGEN_INIT_NEON_PACKET4(X, Y, Z, W) {X, Y, Z, W}
#endif
-
-#ifndef __pld
-#define __pld(x) asm volatile ( " pld [%[addr]]\n" :: [addr] "r" (x) : "cc" );
+
+// arm64 does have the pld instruction. If available, let's trust the __builtin_prefetch built-in function
+// which available on LLVM and GCC (at least)
+#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
+ #define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR);
+#elif defined __pld
+ #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR)
+#elif !defined(__aarch64__)
+ #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ( " pld [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" );
+#else
+ // by default no explicit prefetching
+ #define EIGEN_ARM_PREFETCH(ADDR)
#endif
template<> struct packet_traits<float> : default_packet_traits
@@ -209,8 +218,8 @@ template<> EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet4i& f
template<> EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); }
template<> EIGEN_STRONG_INLINE void pstoreu<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); }
-template<> EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { __pld(addr); }
-template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { __pld(addr); }
+template<> EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { EIGEN_ARM_PREFETCH(addr); }
+template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { EIGEN_ARM_PREFETCH(addr); }
// FIXME only store the 2 first elements ?
template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; }
@@ -375,6 +384,7 @@ template<> EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a)
a_lo = vget_low_s32(a);
a_hi = vget_high_s32(a);
max = vpmax_s32(a_lo, a_hi);
+ max = vpmax_s32(max, max);
return vget_lane_s32(max, 0);
}
diff --git a/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h b/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h
index 99cbd0d95be..2b07168ae4f 100644
--- a/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h
+++ b/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h
@@ -52,7 +52,7 @@ Packet4f plog<Packet4f>(const Packet4f& _x)
Packet4i emm0;
- Packet4f invalid_mask = _mm_cmplt_ps(x, _mm_setzero_ps());
+ Packet4f invalid_mask = _mm_cmpnge_ps(x, _mm_setzero_ps()); // not greater equal is true if x is NaN
Packet4f iszero_mask = _mm_cmpeq_ps(x, _mm_setzero_ps());
x = pmax(x, p4f_min_norm_pos); /* cut off denormalized stuff */
@@ -126,7 +126,7 @@ Packet4f pexp<Packet4f>(const Packet4f& _x)
_EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p4, 1.6666665459E-1f);
_EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p5, 5.0000001201E-1f);
- Packet4f tmp = _mm_setzero_ps(), fx;
+ Packet4f tmp, fx;
Packet4i emm0;
// clamp x
@@ -166,7 +166,7 @@ Packet4f pexp<Packet4f>(const Packet4f& _x)
emm0 = _mm_cvttps_epi32(fx);
emm0 = _mm_add_epi32(emm0, p4i_0x7f);
emm0 = _mm_slli_epi32(emm0, 23);
- return pmul(y, _mm_castsi128_ps(emm0));
+ return pmax(pmul(y, Packet4f(_mm_castsi128_ps(emm0))), _x);
}
template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED
Packet2d pexp<Packet2d>(const Packet2d& _x)
@@ -195,7 +195,7 @@ Packet2d pexp<Packet2d>(const Packet2d& _x)
_EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C2, 1.42860682030941723212e-6);
static const __m128i p4i_1023_0 = _mm_setr_epi32(1023, 1023, 0, 0);
- Packet2d tmp = _mm_setzero_pd(), fx;
+ Packet2d tmp, fx;
Packet4i emm0;
// clamp x
@@ -239,7 +239,7 @@ Packet2d pexp<Packet2d>(const Packet2d& _x)
emm0 = _mm_add_epi32(emm0, p4i_1023_0);
emm0 = _mm_slli_epi32(emm0, 20);
emm0 = _mm_shuffle_epi32(emm0, _MM_SHUFFLE(1,2,0,3));
- return pmul(x, _mm_castsi128_pd(emm0));
+ return pmax(pmul(x, Packet2d(_mm_castsi128_pd(emm0))), _x);
}
/* evaluation of 4 sines at onces, using SSE2 intrinsics.
@@ -279,7 +279,7 @@ Packet4f psin<Packet4f>(const Packet4f& _x)
_EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f);
_EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI
- Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y;
+ Packet4f xmm1, xmm2, xmm3, sign_bit, y;
Packet4i emm0, emm2;
sign_bit = x;
@@ -378,7 +378,7 @@ Packet4f pcos<Packet4f>(const Packet4f& _x)
_EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f);
_EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI
- Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, y;
+ Packet4f xmm1, xmm2, xmm3, y;
Packet4i emm0, emm2;
x = pabs(x);
diff --git a/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h b/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h
index c06a0df1c21..2a9d65b9473 100644
--- a/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h
+++ b/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h
@@ -90,6 +90,7 @@ struct traits<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> >
| (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0),
CoeffReadCost = InnerSize == Dynamic ? Dynamic
+ : InnerSize == 0 ? 0
: InnerSize * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost)
+ (InnerSize - 1) * NumTraits<Scalar>::AddCost,
@@ -133,7 +134,7 @@ class CoeffBasedProduct
};
typedef internal::product_coeff_impl<CanVectorizeInner ? InnerVectorizedTraversal : DefaultTraversal,
- Unroll ? InnerSize-1 : Dynamic,
+ Unroll ? InnerSize : Dynamic,
_LhsNested, _RhsNested, Scalar> ScalarCoeffImpl;
typedef CoeffBasedProduct<LhsNested,RhsNested,NestByRefBit> LazyCoeffBasedProductType;
@@ -184,7 +185,7 @@ class CoeffBasedProduct
{
PacketScalar res;
internal::product_packet_impl<Flags&RowMajorBit ? RowMajor : ColMajor,
- Unroll ? InnerSize-1 : Dynamic,
+ Unroll ? InnerSize : Dynamic,
_LhsNested, _RhsNested, PacketScalar, LoadMode>
::run(row, col, m_lhs, m_rhs, res);
return res;
@@ -242,12 +243,12 @@ struct product_coeff_impl<DefaultTraversal, UnrollingIndex, Lhs, Rhs, RetScalar>
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
{
product_coeff_impl<DefaultTraversal, UnrollingIndex-1, Lhs, Rhs, RetScalar>::run(row, col, lhs, rhs, res);
- res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col);
+ res += lhs.coeff(row, UnrollingIndex-1) * rhs.coeff(UnrollingIndex-1, col);
}
};
template<typename Lhs, typename Rhs, typename RetScalar>
-struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar>
+struct product_coeff_impl<DefaultTraversal, 1, Lhs, Rhs, RetScalar>
{
typedef typename Lhs::Index Index;
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
@@ -257,15 +258,22 @@ struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar>
};
template<typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res)
+ {
+ res = RetScalar(0);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename RetScalar>
struct product_coeff_impl<DefaultTraversal, Dynamic, Lhs, Rhs, RetScalar>
{
typedef typename Lhs::Index Index;
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res)
{
- eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix");
- res = lhs.coeff(row, 0) * rhs.coeff(0, col);
- for(Index i = 1; i < lhs.cols(); ++i)
- res += lhs.coeff(row, i) * rhs.coeff(i, col);
+ res = (lhs.row(row).transpose().cwiseProduct( rhs.col(col) )).sum();
}
};
@@ -295,6 +303,16 @@ struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet>
}
};
+template<typename Lhs, typename Rhs, typename RetScalar>
+struct product_coeff_impl<InnerVectorizedTraversal, 0, Lhs, Rhs, RetScalar>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res)
+ {
+ res = 0;
+ }
+};
+
template<int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar>
struct product_coeff_impl<InnerVectorizedTraversal, UnrollingIndex, Lhs, Rhs, RetScalar>
{
@@ -304,8 +322,7 @@ struct product_coeff_impl<InnerVectorizedTraversal, UnrollingIndex, Lhs, Rhs, Re
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res)
{
Packet pres;
- product_coeff_vectorized_unroller<UnrollingIndex+1-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres);
- product_coeff_impl<DefaultTraversal,UnrollingIndex,Lhs,Rhs,RetScalar>::run(row, col, lhs, rhs, res);
+ product_coeff_vectorized_unroller<UnrollingIndex-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres);
res = predux(pres);
}
};
@@ -373,7 +390,7 @@ struct product_packet_impl<RowMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
{
product_packet_impl<RowMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res);
- res = pmadd(pset1<Packet>(lhs.coeff(row, UnrollingIndex)), rhs.template packet<LoadMode>(UnrollingIndex, col), res);
+ res = pmadd(pset1<Packet>(lhs.coeff(row, UnrollingIndex-1)), rhs.template packet<LoadMode>(UnrollingIndex-1, col), res);
}
};
@@ -384,12 +401,12 @@ struct product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode>
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
{
product_packet_impl<ColMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res);
- res = pmadd(lhs.template packet<LoadMode>(row, UnrollingIndex), pset1<Packet>(rhs.coeff(UnrollingIndex, col)), res);
+ res = pmadd(lhs.template packet<LoadMode>(row, UnrollingIndex-1), pset1<Packet>(rhs.coeff(UnrollingIndex-1, col)), res);
}
};
template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
-struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>
+struct product_packet_impl<RowMajor, 1, Lhs, Rhs, Packet, LoadMode>
{
typedef typename Lhs::Index Index;
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
@@ -399,7 +416,7 @@ struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>
};
template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
-struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>
+struct product_packet_impl<ColMajor, 1, Lhs, Rhs, Packet, LoadMode>
{
typedef typename Lhs::Index Index;
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res)
@@ -409,15 +426,34 @@ struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>
};
template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res)
+ {
+ res = pset1<Packet>(0);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
+struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode>
+{
+ typedef typename Lhs::Index Index;
+ static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res)
+ {
+ res = pset1<Packet>(0);
+ }
+};
+
+template<typename Lhs, typename Rhs, typename Packet, int LoadMode>
struct product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
{
typedef typename Lhs::Index Index;
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res)
{
- eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix");
- res = pmul(pset1<Packet>(lhs.coeff(row, 0)),rhs.template packet<LoadMode>(0, col));
- for(Index i = 1; i < lhs.cols(); ++i)
- res = pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res);
+ res = pset1<Packet>(0);
+ for(Index i = 0; i < lhs.cols(); ++i)
+ res = pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res);
}
};
@@ -427,10 +463,9 @@ struct product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, Packet, LoadMode>
typedef typename Lhs::Index Index;
static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res)
{
- eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix");
- res = pmul(lhs.template packet<LoadMode>(row, 0), pset1<Packet>(rhs.coeff(0, col)));
- for(Index i = 1; i < lhs.cols(); ++i)
- res = pmadd(lhs.template packet<LoadMode>(row, i), pset1<Packet>(rhs.coeff(i, col)), res);
+ res = pset1<Packet>(0);
+ for(Index i = 0; i < lhs.cols(); ++i)
+ res = pmadd(lhs.template packet<LoadMode>(row, i), pset1<Packet>(rhs.coeff(i, col)), res);
}
};
diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h
index 3f5ffcf51c7..a36c7c7a61c 100644
--- a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h
+++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h
@@ -140,8 +140,14 @@ static void run(Index rows, Index cols, Index depth,
// Release all the sub blocks B'_j of B' for the current thread,
// i.e., we simply decrement the number of users by 1
for(Index j=0; j<threads; ++j)
+ {
#pragma omp atomic
+#if defined(_MSC_VER) && _MSC_VER >= 1900
+ (info[j].users) -= 1;
+#else
--(info[j].users);
+#endif
+ }
}
}
else
diff --git a/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h b/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h
index 5c3e9b7ac15..6937ee33284 100644
--- a/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h
+++ b/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h
@@ -125,19 +125,22 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos
if(transpose)
std::swap(rows,cols);
- Index blockCols = (cols / threads) & ~Index(0x3);
- Index blockRows = (rows / threads) & ~Index(0x7);
-
GemmParallelInfo<Index>* info = new GemmParallelInfo<Index>[threads];
- #pragma omp parallel for schedule(static,1) num_threads(threads)
- for(Index i=0; i<threads; ++i)
+ #pragma omp parallel num_threads(threads)
{
+ Index i = omp_get_thread_num();
+ // Note that the actual number of threads might be lower than the number of request ones.
+ Index actual_threads = omp_get_num_threads();
+
+ Index blockCols = (cols / actual_threads) & ~Index(0x3);
+ Index blockRows = (rows / actual_threads) & ~Index(0x7);
+
Index r0 = i*blockRows;
- Index actualBlockRows = (i+1==threads) ? rows-r0 : blockRows;
+ Index actualBlockRows = (i+1==actual_threads) ? rows-r0 : blockRows;
Index c0 = i*blockCols;
- Index actualBlockCols = (i+1==threads) ? cols-c0 : blockCols;
+ Index actualBlockCols = (i+1==actual_threads) ? cols-c0 : blockCols;
info[i].rhs_start = c0;
info[i].rhs_length = actualBlockCols;
diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
index ba41a1c99f6..4cc56a42fd5 100644
--- a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
+++ b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h
@@ -109,7 +109,7 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,true, \
/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \
if (rows != depth) { \
\
- int nthr = mkl_domain_get_max_threads(MKL_BLAS); \
+ int nthr = mkl_domain_get_max_threads(EIGEN_MKL_DOMAIN_BLAS); \
\
if (((nthr==1) && (((std::max)(rows,depth)-diagSize)/(double)diagSize < 0.5))) { \
/* Most likely no benefit to call TRMM or GEMM from MKL*/ \
@@ -223,7 +223,7 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,false, \
/* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \
if (cols != depth) { \
\
- int nthr = mkl_domain_get_max_threads(MKL_BLAS); \
+ int nthr = mkl_domain_get_max_threads(EIGEN_MKL_DOMAIN_BLAS); \
\
if ((nthr==1) && (((std::max)(cols,depth)-diagSize)/(double)diagSize < 0.5)) { \
/* Most likely no benefit to call TRMM or GEMM from MKL*/ \
diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h b/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h
index f103eae72c0..04240ab5032 100644
--- a/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h
+++ b/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h
@@ -302,9 +302,12 @@ EIGEN_DONT_INLINE void triangular_solve_matrix<Scalar,Index,OnTheRight,Mode,Conj
for (Index i=0; i<actual_mc; ++i)
r[i] -= a[i] * b;
}
- Scalar b = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(rhs(j,j));
- for (Index i=0; i<actual_mc; ++i)
- r[i] *= b;
+ if((Mode & UnitDiag)==0)
+ {
+ Scalar b = conj(rhs(j,j));
+ for (Index i=0; i<actual_mc; ++i)
+ r[i] /= b;
+ }
}
// pack the just computed part of lhs to A
diff --git a/extern/Eigen3/Eigen/src/Core/util/Constants.h b/extern/Eigen3/Eigen/src/Core/util/Constants.h
index 14b9624e1d9..1e6277c4f96 100644
--- a/extern/Eigen3/Eigen/src/Core/util/Constants.h
+++ b/extern/Eigen3/Eigen/src/Core/util/Constants.h
@@ -433,6 +433,19 @@ struct MatrixXpr {};
/** The type used to identify an array expression */
struct ArrayXpr {};
+namespace internal {
+ /** \internal
+ * Constants for comparison functors
+ */
+ enum ComparisonName {
+ cmp_EQ = 0,
+ cmp_LT = 1,
+ cmp_LE = 2,
+ cmp_UNORD = 3,
+ cmp_NEQ = 4
+ };
+}
+
} // end namespace Eigen
#endif // EIGEN_CONSTANTS_H
diff --git a/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h b/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h
index d6a814586d3..f277720077b 100644
--- a/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h
+++ b/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h
@@ -235,6 +235,9 @@ template<typename Scalar> class Rotation2D;
template<typename Scalar> class AngleAxis;
template<typename Scalar,int Dim> class Translation;
+// Sparse module:
+template<typename Derived> class SparseMatrixBase;
+
#ifdef EIGEN2_SUPPORT
template<typename Derived, int _Dim> class eigen2_RotationBase;
template<typename Lhs, typename Rhs> class eigen2_Cross;
diff --git a/extern/Eigen3/Eigen/src/Core/util/MKL_support.h b/extern/Eigen3/Eigen/src/Core/util/MKL_support.h
index 1e6e355d626..1ef3b61db14 100644
--- a/extern/Eigen3/Eigen/src/Core/util/MKL_support.h
+++ b/extern/Eigen3/Eigen/src/Core/util/MKL_support.h
@@ -54,11 +54,60 @@
#endif
#if defined EIGEN_USE_MKL
+# include <mkl.h>
+/*Check IMKL version for compatibility: < 10.3 is not usable with Eigen*/
+# ifndef INTEL_MKL_VERSION
+# undef EIGEN_USE_MKL /* INTEL_MKL_VERSION is not even defined on older versions */
+# elif INTEL_MKL_VERSION < 100305 /* the intel-mkl-103-release-notes say this was when the lapacke.h interface was added*/
+# undef EIGEN_USE_MKL
+# endif
+# ifndef EIGEN_USE_MKL
+ /*If the MKL version is too old, undef everything*/
+# undef EIGEN_USE_MKL_ALL
+# undef EIGEN_USE_BLAS
+# undef EIGEN_USE_LAPACKE
+# undef EIGEN_USE_MKL_VML
+# undef EIGEN_USE_LAPACKE_STRICT
+# undef EIGEN_USE_LAPACKE
+# endif
+#endif
-#include <mkl.h>
+#if defined EIGEN_USE_MKL
#include <mkl_lapacke.h>
#define EIGEN_MKL_VML_THRESHOLD 128
+/* MKL_DOMAIN_BLAS, etc are defined only in 10.3 update 7 */
+/* MKL_BLAS, etc are not defined in 11.2 */
+#ifdef MKL_DOMAIN_ALL
+#define EIGEN_MKL_DOMAIN_ALL MKL_DOMAIN_ALL
+#else
+#define EIGEN_MKL_DOMAIN_ALL MKL_ALL
+#endif
+
+#ifdef MKL_DOMAIN_BLAS
+#define EIGEN_MKL_DOMAIN_BLAS MKL_DOMAIN_BLAS
+#else
+#define EIGEN_MKL_DOMAIN_BLAS MKL_BLAS
+#endif
+
+#ifdef MKL_DOMAIN_FFT
+#define EIGEN_MKL_DOMAIN_FFT MKL_DOMAIN_FFT
+#else
+#define EIGEN_MKL_DOMAIN_FFT MKL_FFT
+#endif
+
+#ifdef MKL_DOMAIN_VML
+#define EIGEN_MKL_DOMAIN_VML MKL_DOMAIN_VML
+#else
+#define EIGEN_MKL_DOMAIN_VML MKL_VML
+#endif
+
+#ifdef MKL_DOMAIN_PARDISO
+#define EIGEN_MKL_DOMAIN_PARDISO MKL_DOMAIN_PARDISO
+#else
+#define EIGEN_MKL_DOMAIN_PARDISO MKL_PARDISO
+#endif
+
namespace Eigen {
typedef std::complex<double> dcomplex;
diff --git a/extern/Eigen3/Eigen/src/Core/util/Macros.h b/extern/Eigen3/Eigen/src/Core/util/Macros.h
index 0088621acf7..53fb5fae420 100644
--- a/extern/Eigen3/Eigen/src/Core/util/Macros.h
+++ b/extern/Eigen3/Eigen/src/Core/util/Macros.h
@@ -13,7 +13,7 @@
#define EIGEN_WORLD_VERSION 3
#define EIGEN_MAJOR_VERSION 2
-#define EIGEN_MINOR_VERSION 1
+#define EIGEN_MINOR_VERSION 7
#define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \
(EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \
@@ -96,6 +96,27 @@
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t
#endif
+// A Clang feature extension to determine compiler features.
+// We use it to determine 'cxx_rvalue_references'
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+// Do we support r-value references?
+#if (__has_feature(cxx_rvalue_references) || \
+ defined(__GXX_EXPERIMENTAL_CXX0X__) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1600))
+ #define EIGEN_HAVE_RVALUE_REFERENCES
+#endif
+
+
+// Cross compiler wrapper around LLVM's __has_builtin
+#ifdef __has_builtin
+# define EIGEN_HAS_BUILTIN(x) __has_builtin(x)
+#else
+# define EIGEN_HAS_BUILTIN(x) 0
+#endif
+
/** Allows to disable some optimizations which might affect the accuracy of the result.
* Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them.
* They currently include:
@@ -247,7 +268,7 @@ namespace Eigen {
#if !defined(EIGEN_ASM_COMMENT)
#if (defined __GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
- #define EIGEN_ASM_COMMENT(X) asm("#" X)
+ #define EIGEN_ASM_COMMENT(X) __asm__("#" X)
#else
#define EIGEN_ASM_COMMENT(X)
#endif
@@ -271,6 +292,7 @@ namespace Eigen {
#error Please tell me what is the equivalent of __attribute__((aligned(n))) for your compiler
#endif
+#define EIGEN_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8)
#define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16)
#if EIGEN_ALIGN_STATICALLY
@@ -289,7 +311,8 @@ namespace Eigen {
#endif
#ifndef EIGEN_STACK_ALLOCATION_LIMIT
-#define EIGEN_STACK_ALLOCATION_LIMIT 20000
+// 131072 == 128 KB
+#define EIGEN_STACK_ALLOCATION_LIMIT 131072
#endif
#ifndef EIGEN_DEFAULT_IO_FORMAT
@@ -305,7 +328,7 @@ namespace Eigen {
// just an empty macro !
#define EIGEN_EMPTY
-#if defined(_MSC_VER) && (!defined(__INTEL_COMPILER))
+#if defined(_MSC_VER) && (_MSC_VER < 1900) && (!defined(__INTEL_COMPILER))
#define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \
using Base::operator =;
#elif defined(__clang__) // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653)
@@ -324,8 +347,11 @@ namespace Eigen {
}
#endif
-#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \
- EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived)
+/** \internal
+ * \brief Macro to manually inherit assignment operators.
+ * This is necessary, because the implicitly defined assignment operator gets deleted when a custom operator= is defined.
+ */
+#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived)
/**
* Just a side note. Commenting within defines works only by documenting
@@ -397,6 +423,8 @@ namespace Eigen {
#define EIGEN_SIZE_MAX(a,b) (((int)a == Dynamic || (int)b == Dynamic) ? Dynamic \
: ((int)a >= (int)b) ? (int)a : (int)b)
+#define EIGEN_ADD_COST(a,b) int(a)==Dynamic || int(b)==Dynamic ? Dynamic : int(a)+int(b)
+
#define EIGEN_LOGICAL_XOR(a,b) (((a) || (b)) && !((a) && (b)))
#define EIGEN_IMPLIES(a,b) (!(a) || (b))
diff --git a/extern/Eigen3/Eigen/src/Core/util/Memory.h b/extern/Eigen3/Eigen/src/Core/util/Memory.h
index cacbd02fd12..b9af5cf8c7b 100644
--- a/extern/Eigen3/Eigen/src/Core/util/Memory.h
+++ b/extern/Eigen3/Eigen/src/Core/util/Memory.h
@@ -63,7 +63,7 @@
// Currently, let's include it only on unix systems:
#if defined(__unix__) || defined(__unix)
#include <unistd.h>
- #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0)
+ #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || (defined __PGI) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0)
#define EIGEN_HAS_POSIX_MEMALIGN 1
#endif
#endif
@@ -272,12 +272,12 @@ inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size)
// The defined(_mm_free) is just here to verify that this MSVC version
// implements _mm_malloc/_mm_free based on the corresponding _aligned_
// functions. This may not always be the case and we just try to be safe.
- #if defined(_MSC_VER) && defined(_mm_free)
+ #if defined(_MSC_VER) && (!defined(_WIN32_WCE)) && defined(_mm_free)
result = _aligned_realloc(ptr,new_size,16);
#else
result = generic_aligned_realloc(ptr,new_size,old_size);
#endif
-#elif defined(_MSC_VER)
+#elif defined(_MSC_VER) && (!defined(_WIN32_WCE))
result = _aligned_realloc(ptr,new_size,16);
#else
result = handmade_aligned_realloc(ptr,new_size,old_size);
@@ -417,6 +417,8 @@ template<typename T, bool Align> inline T* conditional_aligned_realloc_new(T* pt
template<typename T, bool Align> inline T* conditional_aligned_new_auto(size_t size)
{
+ if(size==0)
+ return 0; // short-cut. Also fixes Bug 884
check_size_for_overflow<T>(size);
T *result = reinterpret_cast<T*>(conditional_aligned_malloc<Align>(sizeof(T)*size));
if(NumTraits<T>::RequireInitialization)
@@ -464,9 +466,8 @@ template<typename T, bool Align> inline void conditional_aligned_delete_auto(T *
template<typename Scalar, typename Index>
static inline Index first_aligned(const Scalar* array, Index size)
{
- enum { PacketSize = packet_traits<Scalar>::size,
- PacketAlignedMask = PacketSize-1
- };
+ static const Index PacketSize = packet_traits<Scalar>::size;
+ static const Index PacketAlignedMask = PacketSize-1;
if(PacketSize==1)
{
@@ -522,7 +523,7 @@ template<typename T> struct smart_copy_helper<T,false> {
// you can overwrite Eigen's default behavior regarding alloca by defining EIGEN_ALLOCA
// to the appropriate stack allocation function
#ifndef EIGEN_ALLOCA
- #if (defined __linux__)
+ #if (defined __linux__) || (defined __APPLE__) || (defined alloca)
#define EIGEN_ALLOCA alloca
#elif defined(_MSC_VER)
#define EIGEN_ALLOCA _alloca
@@ -612,7 +613,6 @@ template<typename T> class aligned_stack_memory_handler
void* operator new(size_t size, const std::nothrow_t&) throw() { \
try { return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); } \
catch (...) { return 0; } \
- return 0; \
}
#else
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \
@@ -777,9 +777,9 @@ namespace internal {
#ifdef EIGEN_CPUID
-inline bool cpuid_is_vendor(int abcd[4], const char* vendor)
+inline bool cpuid_is_vendor(int abcd[4], const int vendor[3])
{
- return abcd[1]==(reinterpret_cast<const int*>(vendor))[0] && abcd[3]==(reinterpret_cast<const int*>(vendor))[1] && abcd[2]==(reinterpret_cast<const int*>(vendor))[2];
+ return abcd[1]==vendor[0] && abcd[3]==vendor[1] && abcd[2]==vendor[2];
}
inline void queryCacheSizes_intel_direct(int& l1, int& l2, int& l3)
@@ -921,13 +921,16 @@ inline void queryCacheSizes(int& l1, int& l2, int& l3)
{
#ifdef EIGEN_CPUID
int abcd[4];
+ const int GenuineIntel[] = {0x756e6547, 0x49656e69, 0x6c65746e};
+ const int AuthenticAMD[] = {0x68747541, 0x69746e65, 0x444d4163};
+ const int AMDisbetter_[] = {0x69444d41, 0x74656273, 0x21726574}; // "AMDisbetter!"
// identify the CPU vendor
EIGEN_CPUID(abcd,0x0,0);
int max_std_funcs = abcd[1];
- if(cpuid_is_vendor(abcd,"GenuineIntel"))
+ if(cpuid_is_vendor(abcd,GenuineIntel))
queryCacheSizes_intel(l1,l2,l3,max_std_funcs);
- else if(cpuid_is_vendor(abcd,"AuthenticAMD") || cpuid_is_vendor(abcd,"AMDisbetter!"))
+ else if(cpuid_is_vendor(abcd,AuthenticAMD) || cpuid_is_vendor(abcd,AMDisbetter_))
queryCacheSizes_amd(l1,l2,l3);
else
// by default let's use Intel's API
diff --git a/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h b/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h
index 8872c5b648e..bac5d9fe92b 100644
--- a/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h
+++ b/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h
@@ -90,7 +90,9 @@
YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED,
THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE,
THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH,
- OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG
+ OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG,
+ IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY,
+ STORAGE_LAYOUT_DOES_NOT_MATCH
};
};
diff --git a/extern/Eigen3/Eigen/src/Core/util/XprHelper.h b/extern/Eigen3/Eigen/src/Core/util/XprHelper.h
index 3c4773054b4..d05f8e5f6f4 100644
--- a/extern/Eigen3/Eigen/src/Core/util/XprHelper.h
+++ b/extern/Eigen3/Eigen/src/Core/util/XprHelper.h
@@ -341,7 +341,7 @@ template<typename T, int n=1, typename PlainObject = typename eval<T>::type> str
};
template<typename T>
-T* const_cast_ptr(const T* ptr)
+inline T* const_cast_ptr(const T* ptr)
{
return const_cast<T*>(ptr);
}
@@ -366,17 +366,17 @@ struct dense_xpr_base<Derived, ArrayXpr>
/** \internal Helper base class to add a scalar multiple operator
* overloads for complex types */
-template<typename Derived,typename Scalar,typename OtherScalar,
+template<typename Derived, typename Scalar, typename OtherScalar, typename BaseType,
bool EnableIt = !is_same<Scalar,OtherScalar>::value >
-struct special_scalar_op_base : public DenseCoeffsBase<Derived>
+struct special_scalar_op_base : public BaseType
{
// dummy operator* so that the
// "using special_scalar_op_base::operator*" compiles
void operator*() const;
};
-template<typename Derived,typename Scalar,typename OtherScalar>
-struct special_scalar_op_base<Derived,Scalar,OtherScalar,true> : public DenseCoeffsBase<Derived>
+template<typename Derived,typename Scalar,typename OtherScalar, typename BaseType>
+struct special_scalar_op_base<Derived,Scalar,OtherScalar,BaseType,true> : public BaseType
{
const CwiseUnaryOp<scalar_multiple2_op<Scalar,OtherScalar>, Derived>
operator*(const OtherScalar& scalar) const
diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h b/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h
index 0e6fdb4889d..7992d494425 100644
--- a/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h
+++ b/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h
@@ -147,7 +147,6 @@ void fitHyperplane(int numPoints,
// compute the covariance matrix
CovMatrixType covMat = CovMatrixType::Zero(size, size);
- VectorType remean = VectorType::Zero(size);
for(int i = 0; i < numPoints; ++i)
{
VectorType diff = (*(points[i]) - mean).conjugate();
diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h
index af434bc9bd6..417c72944e1 100644
--- a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h
+++ b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h
@@ -234,6 +234,12 @@ template<typename _MatrixType> class ComplexEigenSolver
}
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
EigenvectorType m_eivec;
EigenvalueType m_eivalues;
ComplexSchur<MatrixType> m_schur;
@@ -251,6 +257,8 @@ template<typename MatrixType>
ComplexEigenSolver<MatrixType>&
ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
{
+ check_template_parameters();
+
// this code is inspired from Jampack
eigen_assert(matrix.cols() == matrix.rows());
diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h
index 6e7150685a2..20c59a7a2e6 100644
--- a/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h
+++ b/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h
@@ -298,6 +298,13 @@ template<typename _MatrixType> class EigenSolver
void doComputeEigenvectors();
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
+ }
+
MatrixType m_eivec;
EigenvalueType m_eivalues;
bool m_isInitialized;
@@ -364,6 +371,8 @@ template<typename MatrixType>
EigenSolver<MatrixType>&
EigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors)
{
+ check_template_parameters();
+
using std::sqrt;
using std::abs;
eigen_assert(matrix.cols() == matrix.rows());
diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
index dc240e13e13..956e80d9edc 100644
--- a/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
+++ b/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h
@@ -263,6 +263,13 @@ template<typename _MatrixType> class GeneralizedEigenSolver
}
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL);
+ }
+
MatrixType m_eivec;
ComplexVectorType m_alphas;
VectorType m_betas;
@@ -290,6 +297,8 @@ template<typename MatrixType>
GeneralizedEigenSolver<MatrixType>&
GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors)
{
+ check_template_parameters();
+
using std::sqrt;
using std::abs;
eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows());
diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h b/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h
index 5706eeebe91..aa3833ebad1 100644
--- a/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h
+++ b/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h
@@ -240,10 +240,10 @@ namespace Eigen {
m_S.coeffRef(i,j) = Scalar(0.0);
m_S.rightCols(dim-j-1).applyOnTheLeft(i-1,i,G.adjoint());
m_T.rightCols(dim-i+1).applyOnTheLeft(i-1,i,G.adjoint());
+ // update Q
+ if (m_computeQZ)
+ m_Q.applyOnTheRight(i-1,i,G);
}
- // update Q
- if (m_computeQZ)
- m_Q.applyOnTheRight(i-1,i,G);
// kill T(i,i-1)
if(m_T.coeff(i,i-1)!=Scalar(0))
{
@@ -251,10 +251,10 @@ namespace Eigen {
m_T.coeffRef(i,i-1) = Scalar(0.0);
m_S.applyOnTheRight(i,i-1,G);
m_T.topRows(i).applyOnTheRight(i,i-1,G);
+ // update Z
+ if (m_computeQZ)
+ m_Z.applyOnTheLeft(i,i-1,G.adjoint());
}
- // update Z
- if (m_computeQZ)
- m_Z.applyOnTheLeft(i,i-1,G.adjoint());
}
}
}
@@ -313,7 +313,7 @@ namespace Eigen {
using std::abs;
using std::sqrt;
const Index dim=m_S.cols();
- if (abs(m_S.coeff(i+1,i)==Scalar(0)))
+ if (abs(m_S.coeff(i+1,i))==Scalar(0))
return;
Index z = findSmallDiagEntry(i,i+1);
if (z==i-1)
diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h
index 64d13634141..16d3875372e 100644
--- a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h
+++ b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h
@@ -234,7 +234,7 @@ template<typename _MatrixType> class RealSchur
typedef Matrix<Scalar,3,1> Vector3s;
Scalar computeNormOfT();
- Index findSmallSubdiagEntry(Index iu, const Scalar& norm);
+ Index findSmallSubdiagEntry(Index iu);
void splitOffTwoRows(Index iu, bool computeU, const Scalar& exshift);
void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo);
void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector);
@@ -286,7 +286,7 @@ RealSchur<MatrixType>& RealSchur<MatrixType>::computeFromHessenberg(const HessMa
{
while (iu >= 0)
{
- Index il = findSmallSubdiagEntry(iu, norm);
+ Index il = findSmallSubdiagEntry(iu);
// Check for convergence
if (il == iu) // One root found
@@ -343,16 +343,14 @@ inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT()
/** \internal Look for single small sub-diagonal element and returns its index */
template<typename MatrixType>
-inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu, const Scalar& norm)
+inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu)
{
using std::abs;
Index res = iu;
while (res > 0)
{
Scalar s = abs(m_matT.coeff(res-1,res-1)) + abs(m_matT.coeff(res,res));
- if (s == 0.0)
- s = norm;
- if (abs(m_matT.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s)
+ if (abs(m_matT.coeff(res,res-1)) <= NumTraits<Scalar>::epsilon() * s)
break;
res--;
}
@@ -457,9 +455,7 @@ inline void RealSchur<MatrixType>::initFrancisQRStep(Index il, Index iu, const V
const Scalar lhs = m_matT.coeff(im,im-1) * (abs(v.coeff(1)) + abs(v.coeff(2)));
const Scalar rhs = v.coeff(0) * (abs(m_matT.coeff(im-1,im-1)) + abs(Tmm) + abs(m_matT.coeff(im+1,im+1)));
if (abs(lhs) < NumTraits<Scalar>::epsilon() * rhs)
- {
break;
- }
}
}
diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
index 3993046a88e..1131c8af8ad 100644
--- a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
+++ b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h
@@ -80,6 +80,8 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
/** \brief Scalar type for matrices of type \p _MatrixType. */
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::Index Index;
+
+ typedef Matrix<Scalar,Size,Size,ColMajor,MaxColsAtCompileTime,MaxColsAtCompileTime> EigenvectorsType;
/** \brief Real scalar type for \p _MatrixType.
*
@@ -225,7 +227,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
*
* \sa eigenvalues()
*/
- const MatrixType& eigenvectors() const
+ const EigenvectorsType& eigenvectors() const
{
eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
@@ -351,7 +353,12 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
#endif // EIGEN2_SUPPORT
protected:
- MatrixType m_eivec;
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
+ EigenvectorsType m_eivec;
RealVectorType m_eivalues;
typename TridiagonalizationType::SubDiagonalType m_subdiag;
ComputationInfo m_info;
@@ -376,7 +383,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver
* "implicit symmetric QR step with Wilkinson shift"
*/
namespace internal {
-template<int StorageOrder,typename RealScalar, typename Scalar, typename Index>
+template<typename RealScalar, typename Scalar, typename Index>
static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n);
}
@@ -384,6 +391,8 @@ template<typename MatrixType>
SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
::compute(const MatrixType& matrix, int options)
{
+ check_template_parameters();
+
using std::abs;
eigen_assert(matrix.cols() == matrix.rows());
eigen_assert((options&~(EigVecMask|GenEigMask))==0
@@ -406,7 +415,7 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
// declare some aliases
RealVectorType& diag = m_eivalues;
- MatrixType& mat = m_eivec;
+ EigenvectorsType& mat = m_eivec;
// map the matrix coefficients to [-1:1] to avoid over- and underflow.
mat = matrix.template triangularView<Lower>();
@@ -442,7 +451,7 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
while (start>0 && m_subdiag[start-1]!=0)
start--;
- internal::tridiagonal_qr_step<MatrixType::Flags&RowMajorBit ? RowMajor : ColMajor>(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n);
+ internal::tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n);
}
if (iter <= m_maxIterations * n)
@@ -490,7 +499,13 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,3
typedef typename SolverType::MatrixType MatrixType;
typedef typename SolverType::RealVectorType VectorType;
typedef typename SolverType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename SolverType::EigenvectorsType EigenvectorsType;
+ /** \internal
+ * Computes the roots of the characteristic polynomial of \a m.
+ * For numerical stability m.trace() should be near zero and to avoid over- or underflow m should be normalized.
+ */
static inline void computeRoots(const MatrixType& m, VectorType& roots)
{
using std::sqrt;
@@ -510,148 +525,123 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,3
// Construct the parameters used in classifying the roots of the equation
// and in solving the equation for the roots in closed form.
Scalar c2_over_3 = c2*s_inv3;
- Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3;
- if (a_over_3 > Scalar(0))
+ Scalar a_over_3 = (c2*c2_over_3 - c1)*s_inv3;
+ if(a_over_3<Scalar(0))
a_over_3 = Scalar(0);
Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1));
- Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3;
- if (q > Scalar(0))
+ Scalar q = a_over_3*a_over_3*a_over_3 - half_b*half_b;
+ if(q<Scalar(0))
q = Scalar(0);
// Compute the eigenvalues by solving for the roots of the polynomial.
- Scalar rho = sqrt(-a_over_3);
- Scalar theta = atan2(sqrt(-q),half_b)*s_inv3;
+ Scalar rho = sqrt(a_over_3);
+ Scalar theta = atan2(sqrt(q),half_b)*s_inv3; // since sqrt(q) > 0, atan2 is in [0, pi] and theta is in [0, pi/3]
Scalar cos_theta = cos(theta);
Scalar sin_theta = sin(theta);
- roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta;
- roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta);
- roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta);
-
- // Sort in increasing order.
- if (roots(0) >= roots(1))
- std::swap(roots(0),roots(1));
- if (roots(1) >= roots(2))
- {
- std::swap(roots(1),roots(2));
- if (roots(0) >= roots(1))
- std::swap(roots(0),roots(1));
- }
+ // roots are already sorted, since cos is monotonically decreasing on [0, pi]
+ roots(0) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); // == 2*rho*cos(theta+2pi/3)
+ roots(1) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); // == 2*rho*cos(theta+ pi/3)
+ roots(2) = c2_over_3 + Scalar(2)*rho*cos_theta;
}
-
+
+ static inline bool extract_kernel(MatrixType& mat, Ref<VectorType> res, Ref<VectorType> representative)
+ {
+ using std::abs;
+ Index i0;
+ // Find non-zero column i0 (by construction, there must exist a non zero coefficient on the diagonal):
+ mat.diagonal().cwiseAbs().maxCoeff(&i0);
+ // mat.col(i0) is a good candidate for an orthogonal vector to the current eigenvector,
+ // so let's save it:
+ representative = mat.col(i0);
+ Scalar n0, n1;
+ VectorType c0, c1;
+ n0 = (c0 = representative.cross(mat.col((i0+1)%3))).squaredNorm();
+ n1 = (c1 = representative.cross(mat.col((i0+2)%3))).squaredNorm();
+ if(n0>n1) res = c0/std::sqrt(n0);
+ else res = c1/std::sqrt(n1);
+
+ return true;
+ }
+
static inline void run(SolverType& solver, const MatrixType& mat, int options)
{
- using std::sqrt;
eigen_assert(mat.cols() == 3 && mat.cols() == mat.rows());
eigen_assert((options&~(EigVecMask|GenEigMask))==0
&& (options&EigVecMask)!=EigVecMask
&& "invalid option parameter");
bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors;
- MatrixType& eivecs = solver.m_eivec;
+ EigenvectorsType& eivecs = solver.m_eivec;
VectorType& eivals = solver.m_eivalues;
- // map the matrix coefficients to [-1:1] to avoid over- and underflow.
- Scalar scale = mat.cwiseAbs().maxCoeff();
- MatrixType scaledMat = mat / scale;
+ // Shift the matrix to the mean eigenvalue and map the matrix coefficients to [-1:1] to avoid over- and underflow.
+ Scalar shift = mat.trace() / Scalar(3);
+ // TODO Avoid this copy. Currently it is necessary to suppress bogus values when determining maxCoeff and for computing the eigenvectors later
+ MatrixType scaledMat = mat.template selfadjointView<Lower>();
+ scaledMat.diagonal().array() -= shift;
+ Scalar scale = scaledMat.cwiseAbs().maxCoeff();
+ if(scale > 0) scaledMat /= scale; // TODO for scale==0 we could save the remaining operations
// compute the eigenvalues
computeRoots(scaledMat,eivals);
- // compute the eigen vectors
+ // compute the eigenvectors
if(computeEigenvectors)
{
- Scalar safeNorm2 = Eigen::NumTraits<Scalar>::epsilon();
- safeNorm2 *= safeNorm2;
if((eivals(2)-eivals(0))<=Eigen::NumTraits<Scalar>::epsilon())
{
+ // All three eigenvalues are numerically the same
eivecs.setIdentity();
}
else
{
- scaledMat = scaledMat.template selfadjointView<Lower>();
MatrixType tmp;
tmp = scaledMat;
+ // Compute the eigenvector of the most distinct eigenvalue
Scalar d0 = eivals(2) - eivals(1);
Scalar d1 = eivals(1) - eivals(0);
- int k = d0 > d1 ? 2 : 0;
- d0 = d0 > d1 ? d1 : d0;
-
- tmp.diagonal().array () -= eivals(k);
- VectorType cross;
- Scalar n;
- n = (cross = tmp.row(0).cross(tmp.row(1))).squaredNorm();
-
- if(n>safeNorm2)
- eivecs.col(k) = cross / sqrt(n);
- else
+ Index k(0), l(2);
+ if(d0 > d1)
{
- n = (cross = tmp.row(0).cross(tmp.row(2))).squaredNorm();
-
- if(n>safeNorm2)
- eivecs.col(k) = cross / sqrt(n);
- else
- {
- n = (cross = tmp.row(1).cross(tmp.row(2))).squaredNorm();
-
- if(n>safeNorm2)
- eivecs.col(k) = cross / sqrt(n);
- else
- {
- // the input matrix and/or the eigenvaues probably contains some inf/NaN,
- // => exit
- // scale back to the original size.
- eivals *= scale;
-
- solver.m_info = NumericalIssue;
- solver.m_isInitialized = true;
- solver.m_eigenvectorsOk = computeEigenvectors;
- return;
- }
- }
+ std::swap(k,l);
+ d0 = d1;
}
- tmp = scaledMat;
- tmp.diagonal().array() -= eivals(1);
+ // Compute the eigenvector of index k
+ {
+ tmp.diagonal().array () -= eivals(k);
+ // By construction, 'tmp' is of rank 2, and its kernel corresponds to the respective eigenvector.
+ extract_kernel(tmp, eivecs.col(k), eivecs.col(l));
+ }
- if(d0<=Eigen::NumTraits<Scalar>::epsilon())
- eivecs.col(1) = eivecs.col(k).unitOrthogonal();
+ // Compute eigenvector of index l
+ if(d0<=2*Eigen::NumTraits<Scalar>::epsilon()*d1)
+ {
+ // If d0 is too small, then the two other eigenvalues are numerically the same,
+ // and thus we only have to ortho-normalize the near orthogonal vector we saved above.
+ eivecs.col(l) -= eivecs.col(k).dot(eivecs.col(l))*eivecs.col(l);
+ eivecs.col(l).normalize();
+ }
else
{
- n = (cross = eivecs.col(k).cross(tmp.row(0).normalized())).squaredNorm();
- if(n>safeNorm2)
- eivecs.col(1) = cross / sqrt(n);
- else
- {
- n = (cross = eivecs.col(k).cross(tmp.row(1))).squaredNorm();
- if(n>safeNorm2)
- eivecs.col(1) = cross / sqrt(n);
- else
- {
- n = (cross = eivecs.col(k).cross(tmp.row(2))).squaredNorm();
- if(n>safeNorm2)
- eivecs.col(1) = cross / sqrt(n);
- else
- {
- // we should never reach this point,
- // if so the last two eigenvalues are likely to ve very closed to each other
- eivecs.col(1) = eivecs.col(k).unitOrthogonal();
- }
- }
- }
-
- // make sure that eivecs[1] is orthogonal to eivecs[2]
- Scalar d = eivecs.col(1).dot(eivecs.col(k));
- eivecs.col(1) = (eivecs.col(1) - d * eivecs.col(k)).normalized();
+ tmp = scaledMat;
+ tmp.diagonal().array () -= eivals(l);
+
+ VectorType dummy;
+ extract_kernel(tmp, eivecs.col(l), dummy);
}
- eivecs.col(k==2 ? 0 : 2) = eivecs.col(k).cross(eivecs.col(1)).normalized();
+ // Compute last eigenvector from the other two
+ eivecs.col(1) = eivecs.col(2).cross(eivecs.col(0)).normalized();
}
}
+
// Rescale back to the original size.
eivals *= scale;
+ eivals.array() += shift;
solver.m_info = Success;
solver.m_isInitialized = true;
@@ -665,11 +655,12 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2
typedef typename SolverType::MatrixType MatrixType;
typedef typename SolverType::RealVectorType VectorType;
typedef typename SolverType::Scalar Scalar;
+ typedef typename SolverType::EigenvectorsType EigenvectorsType;
static inline void computeRoots(const MatrixType& m, VectorType& roots)
{
using std::sqrt;
- const Scalar t0 = Scalar(0.5) * sqrt( numext::abs2(m(0,0)-m(1,1)) + Scalar(4)*m(1,0)*m(1,0));
+ const Scalar t0 = Scalar(0.5) * sqrt( numext::abs2(m(0,0)-m(1,1)) + Scalar(4)*numext::abs2(m(1,0)));
const Scalar t1 = Scalar(0.5) * (m(0,0) + m(1,1));
roots(0) = t1 - t0;
roots(1) = t1 + t0;
@@ -678,13 +669,15 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2
static inline void run(SolverType& solver, const MatrixType& mat, int options)
{
using std::sqrt;
+ using std::abs;
+
eigen_assert(mat.cols() == 2 && mat.cols() == mat.rows());
eigen_assert((options&~(EigVecMask|GenEigMask))==0
&& (options&EigVecMask)!=EigVecMask
&& "invalid option parameter");
bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors;
- MatrixType& eivecs = solver.m_eivec;
+ EigenvectorsType& eivecs = solver.m_eivec;
VectorType& eivals = solver.m_eivalues;
// map the matrix coefficients to [-1:1] to avoid over- and underflow.
@@ -698,22 +691,29 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2
// compute the eigen vectors
if(computeEigenvectors)
{
- scaledMat.diagonal().array () -= eivals(1);
- Scalar a2 = numext::abs2(scaledMat(0,0));
- Scalar c2 = numext::abs2(scaledMat(1,1));
- Scalar b2 = numext::abs2(scaledMat(1,0));
- if(a2>c2)
+ if((eivals(1)-eivals(0))<=abs(eivals(1))*Eigen::NumTraits<Scalar>::epsilon())
{
- eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0);
- eivecs.col(1) /= sqrt(a2+b2);
+ eivecs.setIdentity();
}
else
{
- eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0);
- eivecs.col(1) /= sqrt(c2+b2);
- }
+ scaledMat.diagonal().array () -= eivals(1);
+ Scalar a2 = numext::abs2(scaledMat(0,0));
+ Scalar c2 = numext::abs2(scaledMat(1,1));
+ Scalar b2 = numext::abs2(scaledMat(1,0));
+ if(a2>c2)
+ {
+ eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0);
+ eivecs.col(1) /= sqrt(a2+b2);
+ }
+ else
+ {
+ eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0);
+ eivecs.col(1) /= sqrt(c2+b2);
+ }
- eivecs.col(0) << eivecs.col(1).unitOrthogonal();
+ eivecs.col(0) << eivecs.col(1).unitOrthogonal();
+ }
}
// Rescale back to the original size.
@@ -736,7 +736,7 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>
}
namespace internal {
-template<int StorageOrder,typename RealScalar, typename Scalar, typename Index>
+template<typename RealScalar, typename Scalar, typename Index>
static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n)
{
using std::abs;
@@ -788,8 +788,7 @@ static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index sta
// apply the givens rotation to the unit matrix Q = Q * G
if (matrixQ)
{
- // FIXME if StorageOrder == RowMajor this operation is not very efficient
- Map<Matrix<Scalar,Dynamic,Dynamic,StorageOrder> > q(matrixQ,n,n);
+ Map<Matrix<Scalar,Dynamic,Dynamic,ColMajor> > q(matrixQ,n,n);
q.applyOnTheRight(k,k+1,rot);
}
}
diff --git a/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h b/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h
index 8e186d57a34..7e1cd9eb79c 100644
--- a/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h
+++ b/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h
@@ -19,10 +19,12 @@ namespace Eigen {
*
* \brief An axis aligned box
*
- * \param _Scalar the type of the scalar coefficients
- * \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic.
+ * \tparam _Scalar the type of the scalar coefficients
+ * \tparam _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic.
*
* This class represents an axis aligned box as a pair of the minimal and maximal corners.
+ * \warning The result of most methods is undefined when applied to an empty box. You can check for empty boxes using isEmpty().
+ * \sa alignedboxtypedefs
*/
template <typename _Scalar, int _AmbientDim>
class AlignedBox
@@ -40,18 +42,21 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
/** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */
enum CornerType
{
- /** 1D names */
+ /** 1D names @{ */
Min=0, Max=1,
+ /** @} */
- /** Added names for 2D */
+ /** Identifier for 2D corner @{ */
BottomLeft=0, BottomRight=1,
TopLeft=2, TopRight=3,
+ /** @} */
- /** Added names for 3D */
+ /** Identifier for 3D corner @{ */
BottomLeftFloor=0, BottomRightFloor=1,
TopLeftFloor=2, TopRightFloor=3,
BottomLeftCeil=4, BottomRightCeil=5,
TopLeftCeil=6, TopRightCeil=7
+ /** @} */
};
@@ -63,34 +68,33 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
inline explicit AlignedBox(Index _dim) : m_min(_dim), m_max(_dim)
{ setEmpty(); }
- /** Constructs a box with extremities \a _min and \a _max. */
+ /** Constructs a box with extremities \a _min and \a _max.
+ * \warning If either component of \a _min is larger than the same component of \a _max, the constructed box is empty. */
template<typename OtherVectorType1, typename OtherVectorType2>
inline AlignedBox(const OtherVectorType1& _min, const OtherVectorType2& _max) : m_min(_min), m_max(_max) {}
/** Constructs a box containing a single point \a p. */
template<typename Derived>
- inline explicit AlignedBox(const MatrixBase<Derived>& a_p)
- {
- typename internal::nested<Derived,2>::type p(a_p.derived());
- m_min = p;
- m_max = p;
- }
+ inline explicit AlignedBox(const MatrixBase<Derived>& p) : m_min(p), m_max(m_min)
+ { }
~AlignedBox() {}
/** \returns the dimension in which the box holds */
inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size() : Index(AmbientDimAtCompileTime); }
- /** \deprecated use isEmpty */
+ /** \deprecated use isEmpty() */
inline bool isNull() const { return isEmpty(); }
- /** \deprecated use setEmpty */
+ /** \deprecated use setEmpty() */
inline void setNull() { setEmpty(); }
- /** \returns true if the box is empty. */
+ /** \returns true if the box is empty.
+ * \sa setEmpty */
inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); }
- /** Makes \c *this an empty box. */
+ /** Makes \c *this an empty box.
+ * \sa isEmpty */
inline void setEmpty()
{
m_min.setConstant( ScalarTraits::highest() );
@@ -159,7 +163,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
* a uniform distribution */
inline VectorType sample() const
{
- VectorType r;
+ VectorType r(dim());
for(Index d=0; d<dim(); ++d)
{
if(!ScalarTraits::IsInteger)
@@ -175,27 +179,34 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
/** \returns true if the point \a p is inside the box \c *this. */
template<typename Derived>
- inline bool contains(const MatrixBase<Derived>& a_p) const
+ inline bool contains(const MatrixBase<Derived>& p) const
{
- typename internal::nested<Derived,2>::type p(a_p.derived());
- return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).all();
+ typename internal::nested<Derived,2>::type p_n(p.derived());
+ return (m_min.array()<=p_n.array()).all() && (p_n.array()<=m_max.array()).all();
}
/** \returns true if the box \a b is entirely inside the box \c *this. */
inline bool contains(const AlignedBox& b) const
{ return (m_min.array()<=(b.min)().array()).all() && ((b.max)().array()<=m_max.array()).all(); }
- /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */
+ /** \returns true if the box \a b is intersecting the box \c *this.
+ * \sa intersection, clamp */
+ inline bool intersects(const AlignedBox& b) const
+ { return (m_min.array()<=(b.max)().array()).all() && ((b.min)().array()<=m_max.array()).all(); }
+
+ /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this.
+ * \sa extend(const AlignedBox&) */
template<typename Derived>
- inline AlignedBox& extend(const MatrixBase<Derived>& a_p)
+ inline AlignedBox& extend(const MatrixBase<Derived>& p)
{
- typename internal::nested<Derived,2>::type p(a_p.derived());
- m_min = m_min.cwiseMin(p);
- m_max = m_max.cwiseMax(p);
+ typename internal::nested<Derived,2>::type p_n(p.derived());
+ m_min = m_min.cwiseMin(p_n);
+ m_max = m_max.cwiseMax(p_n);
return *this;
}
- /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. */
+ /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this.
+ * \sa merged, extend(const MatrixBase&) */
inline AlignedBox& extend(const AlignedBox& b)
{
m_min = m_min.cwiseMin(b.m_min);
@@ -203,7 +214,9 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
return *this;
}
- /** Clamps \c *this by the box \a b and returns a reference to \c *this. */
+ /** Clamps \c *this by the box \a b and returns a reference to \c *this.
+ * \note If the boxes don't intersect, the resulting box is empty.
+ * \sa intersection(), intersects() */
inline AlignedBox& clamp(const AlignedBox& b)
{
m_min = m_min.cwiseMax(b.m_min);
@@ -211,11 +224,15 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
return *this;
}
- /** Returns an AlignedBox that is the intersection of \a b and \c *this */
+ /** Returns an AlignedBox that is the intersection of \a b and \c *this
+ * \note If the boxes don't intersect, the resulting box is empty.
+ * \sa intersects(), clamp, contains() */
inline AlignedBox intersection(const AlignedBox& b) const
{return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); }
- /** Returns an AlignedBox that is the union of \a b and \c *this */
+ /** Returns an AlignedBox that is the union of \a b and \c *this.
+ * \note Merging with an empty box may result in a box bigger than \c *this.
+ * \sa extend(const AlignedBox&) */
inline AlignedBox merged(const AlignedBox& b) const
{ return AlignedBox(m_min.cwiseMin(b.m_min), m_max.cwiseMax(b.m_max)); }
@@ -231,20 +248,20 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
/** \returns the squared distance between the point \a p and the box \c *this,
* and zero if \a p is inside the box.
- * \sa exteriorDistance()
+ * \sa exteriorDistance(const MatrixBase&), squaredExteriorDistance(const AlignedBox&)
*/
template<typename Derived>
- inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& a_p) const;
+ inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& p) const;
/** \returns the squared distance between the boxes \a b and \c *this,
* and zero if the boxes intersect.
- * \sa exteriorDistance()
+ * \sa exteriorDistance(const AlignedBox&), squaredExteriorDistance(const MatrixBase&)
*/
inline Scalar squaredExteriorDistance(const AlignedBox& b) const;
/** \returns the distance between the point \a p and the box \c *this,
* and zero if \a p is inside the box.
- * \sa squaredExteriorDistance()
+ * \sa squaredExteriorDistance(const MatrixBase&), exteriorDistance(const AlignedBox&)
*/
template<typename Derived>
inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const
@@ -252,7 +269,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim)
/** \returns the distance between the boxes \a b and \c *this,
* and zero if the boxes intersect.
- * \sa squaredExteriorDistance()
+ * \sa squaredExteriorDistance(const AlignedBox&), exteriorDistance(const MatrixBase&)
*/
inline NonInteger exteriorDistance(const AlignedBox& b) const
{ using std::sqrt; return sqrt(NonInteger(squaredExteriorDistance(b))); }
diff --git a/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h b/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h
index 553d38c7449..bbf6a7ed8ed 100644
--- a/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h
+++ b/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h
@@ -131,7 +131,7 @@ public:
m_angle = Scalar(other.angle());
}
- static inline const AngleAxis Identity() { return AngleAxis(0, Vector3::UnitX()); }
+ static inline const AngleAxis Identity() { return AngleAxis(Scalar(0), Vector3::UnitX()); }
/** \returns \c true if \c *this is approximately equal to \a other, within the precision
* determined by \a prec.
@@ -165,8 +165,8 @@ AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const QuaternionBase<QuatDerived
Scalar n2 = q.vec().squaredNorm();
if (n2 < NumTraits<Scalar>::dummy_precision()*NumTraits<Scalar>::dummy_precision())
{
- m_angle = 0;
- m_axis << 1, 0, 0;
+ m_angle = Scalar(0);
+ m_axis << Scalar(1), Scalar(0), Scalar(0);
}
else
{
diff --git a/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h b/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h
index 00e71d190c3..372e422b92c 100644
--- a/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h
+++ b/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h
@@ -79,7 +79,7 @@ template<typename MatrixType,int _Direction> class Homogeneous
{
if( (int(Direction)==Vertical && row==m_matrix.rows())
|| (int(Direction)==Horizontal && col==m_matrix.cols()))
- return 1;
+ return Scalar(1);
return m_matrix.coeff(row, col);
}
diff --git a/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h b/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h
index aeff43fefa6..00b7c4300fd 100644
--- a/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h
+++ b/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h
@@ -100,7 +100,17 @@ public:
{
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 3)
Hyperplane result(p0.size());
- result.normal() = (p2 - p0).cross(p1 - p0).normalized();
+ VectorType v0(p2 - p0), v1(p1 - p0);
+ result.normal() = v0.cross(v1);
+ RealScalar norm = result.normal().norm();
+ if(norm <= v0.norm() * v1.norm() * NumTraits<RealScalar>::epsilon())
+ {
+ Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose();
+ JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV);
+ result.normal() = svd.matrixV().col(2);
+ }
+ else
+ result.normal() /= norm;
result.offset() = -p0.dot(result.normal());
return result;
}
diff --git a/extern/Eigen3/Eigen/src/Geometry/Quaternion.h b/extern/Eigen3/Eigen/src/Geometry/Quaternion.h
index 9fee0c91980..25ed17bb690 100644
--- a/extern/Eigen3/Eigen/src/Geometry/Quaternion.h
+++ b/extern/Eigen3/Eigen/src/Geometry/Quaternion.h
@@ -102,11 +102,11 @@ public:
/** \returns a quaternion representing an identity rotation
* \sa MatrixBase::Identity()
*/
- static inline Quaternion<Scalar> Identity() { return Quaternion<Scalar>(1, 0, 0, 0); }
+ static inline Quaternion<Scalar> Identity() { return Quaternion<Scalar>(Scalar(1), Scalar(0), Scalar(0), Scalar(0)); }
/** \sa QuaternionBase::Identity(), MatrixBase::setIdentity()
*/
- inline QuaternionBase& setIdentity() { coeffs() << 0, 0, 0, 1; return *this; }
+ inline QuaternionBase& setIdentity() { coeffs() << Scalar(0), Scalar(0), Scalar(0), Scalar(1); return *this; }
/** \returns the squared norm of the quaternion's coefficients
* \sa QuaternionBase::norm(), MatrixBase::squaredNorm()
@@ -161,7 +161,7 @@ public:
{ return coeffs().isApprox(other.coeffs(), prec); }
/** return the result vector of \a v through the rotation*/
- EIGEN_STRONG_INLINE Vector3 _transformVector(Vector3 v) const;
+ EIGEN_STRONG_INLINE Vector3 _transformVector(const Vector3& v) const;
/** \returns \c *this with scalar type casted to \a NewScalarType
*
@@ -203,6 +203,8 @@ public:
* \li \c Quaternionf for \c float
* \li \c Quaterniond for \c double
*
+ * \warning Operations interpreting the quaternion as rotation have undefined behavior if the quaternion is not normalized.
+ *
* \sa class AngleAxis, class Transform
*/
@@ -229,7 +231,7 @@ class Quaternion : public QuaternionBase<Quaternion<_Scalar,_Options> >
public:
typedef _Scalar Scalar;
- EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Quaternion)
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Quaternion)
using Base::operator*=;
typedef typename internal::traits<Quaternion>::Coefficients Coefficients;
@@ -339,12 +341,12 @@ class Map<const Quaternion<_Scalar>, _Options >
public:
typedef _Scalar Scalar;
typedef typename internal::traits<Map>::Coefficients Coefficients;
- EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map)
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map)
using Base::operator*=;
/** Constructs a Mapped Quaternion object from the pointer \a coeffs
*
- * The pointer \a coeffs must reference the four coeffecients of Quaternion in the following order:
+ * The pointer \a coeffs must reference the four coefficients of Quaternion in the following order:
* \code *coeffs == {x, y, z, w} \endcode
*
* If the template parameter _Options is set to #Aligned, then the pointer coeffs must be aligned. */
@@ -376,7 +378,7 @@ class Map<Quaternion<_Scalar>, _Options >
public:
typedef _Scalar Scalar;
typedef typename internal::traits<Map>::Coefficients Coefficients;
- EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map)
+ EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map)
using Base::operator*=;
/** Constructs a Mapped Quaternion object from the pointer \a coeffs
@@ -459,12 +461,12 @@ EIGEN_STRONG_INLINE Derived& QuaternionBase<Derived>::operator*= (const Quaterni
*/
template <class Derived>
EIGEN_STRONG_INLINE typename QuaternionBase<Derived>::Vector3
-QuaternionBase<Derived>::_transformVector(Vector3 v) const
+QuaternionBase<Derived>::_transformVector(const Vector3& v) const
{
// Note that this algorithm comes from the optimization by hand
// of the conversion to a Matrix followed by a Matrix/Vector product.
// It appears to be much faster than the common algorithm found
- // in the litterature (30 versus 39 flops). It also requires two
+ // in the literature (30 versus 39 flops). It also requires two
// Vector3 as temporaries.
Vector3 uv = this->vec().cross(v);
uv += uv;
@@ -584,7 +586,7 @@ inline Derived& QuaternionBase<Derived>::setFromTwoVectors(const MatrixBase<Deri
// which yields a singular value problem
if (c < Scalar(-1)+NumTraits<Scalar>::dummy_precision())
{
- c = max<Scalar>(c,-1);
+ c = (max)(c,Scalar(-1));
Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose();
JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV);
Vector3 axis = svd.matrixV().col(2);
@@ -635,7 +637,7 @@ inline Quaternion<typename internal::traits<Derived>::Scalar> QuaternionBase<Der
{
// FIXME should this function be called multiplicativeInverse and conjugate() be called inverse() or opposite() ??
Scalar n2 = this->squaredNorm();
- if (n2 > 0)
+ if (n2 > Scalar(0))
return Quaternion<Scalar>(conjugate().coeffs() / n2);
else
{
@@ -665,12 +667,10 @@ template <class OtherDerived>
inline typename internal::traits<Derived>::Scalar
QuaternionBase<Derived>::angularDistance(const QuaternionBase<OtherDerived>& other) const
{
- using std::acos;
+ using std::atan2;
using std::abs;
- double d = abs(this->dot(other));
- if (d>=1.0)
- return Scalar(0);
- return static_cast<Scalar>(2 * acos(d));
+ Quaternion<Scalar> d = (*this) * other.conjugate();
+ return Scalar(2) * atan2( d.vec().norm(), abs(d.w()) );
}
@@ -710,7 +710,7 @@ QuaternionBase<Derived>::slerp(const Scalar& t, const QuaternionBase<OtherDerive
scale0 = sin( ( Scalar(1) - t ) * theta) / sinTheta;
scale1 = sin( ( t * theta) ) / sinTheta;
}
- if(d<0) scale1 = -scale1;
+ if(d<Scalar(0)) scale1 = -scale1;
return Quaternion<Scalar>(scale0 * coeffs() + scale1 * other.coeffs());
}
diff --git a/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h b/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h
index 1cac343a5ee..a2d59fce10f 100644
--- a/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h
+++ b/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h
@@ -60,6 +60,9 @@ public:
/** Construct a 2D counter clock wise rotation from the angle \a a in radian. */
inline Rotation2D(const Scalar& a) : m_angle(a) {}
+
+ /** Default constructor wihtout initialization. The represented rotation is undefined. */
+ Rotation2D() {}
/** \returns the rotation angle */
inline Scalar angle() const { return m_angle; }
@@ -81,10 +84,10 @@ public:
/** Applies the rotation to a 2D vector */
Vector2 operator* (const Vector2& vec) const
{ return toRotationMatrix() * vec; }
-
+
template<typename Derived>
Rotation2D& fromRotationMatrix(const MatrixBase<Derived>& m);
- Matrix2 toRotationMatrix(void) const;
+ Matrix2 toRotationMatrix() const;
/** \returns the spherical interpolation between \c *this and \a other using
* parameter \a t. It is in fact equivalent to a linear interpolation.
diff --git a/extern/Eigen3/Eigen/src/Geometry/Transform.h b/extern/Eigen3/Eigen/src/Geometry/Transform.h
index 498fea41a90..e786e535695 100644
--- a/extern/Eigen3/Eigen/src/Geometry/Transform.h
+++ b/extern/Eigen3/Eigen/src/Geometry/Transform.h
@@ -62,6 +62,8 @@ struct transform_construct_from_matrix;
template<typename TransformType> struct transform_take_affine_part;
+template<int Mode> struct transform_make_affine;
+
} // end namespace internal
/** \geometry_module \ingroup Geometry_Module
@@ -194,9 +196,9 @@ public:
/** type of the matrix used to represent the linear part of the transformation */
typedef Matrix<Scalar,Dim,Dim,Options> LinearMatrixType;
/** type of read/write reference to the linear part of the transformation */
- typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact)> LinearPart;
+ typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> LinearPart;
/** type of read reference to the linear part of the transformation */
- typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact)> ConstLinearPart;
+ typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> ConstLinearPart;
/** type of read/write reference to the affine part of the transformation */
typedef typename internal::conditional<int(Mode)==int(AffineCompact),
MatrixType&,
@@ -230,8 +232,7 @@ public:
inline Transform()
{
check_template_params();
- if (int(Mode)==Affine)
- makeAffine();
+ internal::transform_make_affine<(int(Mode)==Affine) ? Affine : AffineCompact>::run(m_matrix);
}
inline Transform(const Transform& other)
@@ -591,11 +592,7 @@ public:
*/
void makeAffine()
{
- if(int(Mode)!=int(AffineCompact))
- {
- matrix().template block<1,Dim>(Dim,0).setZero();
- matrix().coeffRef(Dim,Dim) = Scalar(1);
- }
+ internal::transform_make_affine<int(Mode)>::run(m_matrix);
}
/** \internal
@@ -1079,6 +1076,24 @@ Transform<Scalar,Dim,Mode,Options>::fromPositionOrientationScale(const MatrixBas
namespace internal {
+template<int Mode>
+struct transform_make_affine
+{
+ template<typename MatrixType>
+ static void run(MatrixType &mat)
+ {
+ static const int Dim = MatrixType::ColsAtCompileTime-1;
+ mat.template block<1,Dim>(Dim,0).setZero();
+ mat.coeffRef(Dim,Dim) = typename MatrixType::Scalar(1);
+ }
+};
+
+template<>
+struct transform_make_affine<AffineCompact>
+{
+ template<typename MatrixType> static void run(MatrixType &) { }
+};
+
// selector needed to avoid taking the inverse of a 3x4 matrix
template<typename TransformType, int Mode=TransformType::Mode>
struct projective_transform_inverse
diff --git a/extern/Eigen3/Eigen/src/Geometry/Umeyama.h b/extern/Eigen3/Eigen/src/Geometry/Umeyama.h
index 345b47e0c37..5e20662f803 100644
--- a/extern/Eigen3/Eigen/src/Geometry/Umeyama.h
+++ b/extern/Eigen3/Eigen/src/Geometry/Umeyama.h
@@ -113,7 +113,7 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo
const Index n = src.cols(); // number of measurements
// required for demeaning ...
- const RealScalar one_over_n = 1 / static_cast<RealScalar>(n);
+ const RealScalar one_over_n = RealScalar(1) / static_cast<RealScalar>(n);
// computation of mean
const VectorType src_mean = src.rowwise().sum() * one_over_n;
@@ -136,16 +136,16 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo
// Eq. (39)
VectorType S = VectorType::Ones(m);
- if (sigma.determinant()<0) S(m-1) = -1;
+ if (sigma.determinant()<Scalar(0)) S(m-1) = Scalar(-1);
// Eq. (40) and (43)
const VectorType& d = svd.singularValues();
Index rank = 0; for (Index i=0; i<m; ++i) if (!internal::isMuchSmallerThan(d.coeff(i),d.coeff(0))) ++rank;
if (rank == m-1) {
- if ( svd.matrixU().determinant() * svd.matrixV().determinant() > 0 ) {
+ if ( svd.matrixU().determinant() * svd.matrixV().determinant() > Scalar(0) ) {
Rt.block(0,0,m,m).noalias() = svd.matrixU()*svd.matrixV().transpose();
} else {
- const Scalar s = S(m-1); S(m-1) = -1;
+ const Scalar s = S(m-1); S(m-1) = Scalar(-1);
Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose();
S(m-1) = s;
}
@@ -156,7 +156,7 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo
if (with_scaling)
{
// Eq. (42)
- const Scalar c = 1/src_var * svd.singularValues().dot(S);
+ const Scalar c = Scalar(1)/src_var * svd.singularValues().dot(S);
// Eq. (41)
Rt.col(m).head(m) = dst_mean;
diff --git a/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h b/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h
index 1991c652738..60dbea5f56a 100644
--- a/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h
+++ b/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h
@@ -48,7 +48,7 @@ void apply_block_householder_on_the_left(MatrixType& mat, const VectorsType& vec
typedef typename MatrixType::Index Index;
enum { TFactorSize = MatrixType::ColsAtCompileTime };
Index nbVecs = vectors.cols();
- Matrix<typename MatrixType::Scalar, TFactorSize, TFactorSize> T(nbVecs,nbVecs);
+ Matrix<typename MatrixType::Scalar, TFactorSize, TFactorSize, ColMajor> T(nbVecs,nbVecs);
make_block_householder_triangular_factor(T, vectors, hCoeffs);
const TriangularView<const VectorsType, UnitLower>& V(vectors);
diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
index 73ca9bfde6a..1f3c060d028 100644
--- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
+++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h
@@ -65,10 +65,10 @@ class DiagonalPreconditioner
{
typename MatType::InnerIterator it(mat,j);
while(it && it.index()!=j) ++it;
- if(it && it.index()==j)
+ if(it && it.index()==j && it.value()!=Scalar(0))
m_invdiag(j) = Scalar(1)/it.value();
else
- m_invdiag(j) = 0;
+ m_invdiag(j) = Scalar(1);
}
m_isInitialized = true;
return *this;
diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
index 6fc6ab85225..5512219076b 100644
--- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
+++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h
@@ -39,7 +39,6 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x,
int maxIters = iters;
int n = mat.cols();
- x = precond.solve(x);
VectorType r = rhs - mat * x;
VectorType r0 = r;
@@ -61,6 +60,7 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x,
VectorType s(n), t(n);
RealScalar tol2 = tol*tol;
+ RealScalar eps2 = NumTraits<Scalar>::epsilon()*NumTraits<Scalar>::epsilon();
int i = 0;
int restarts = 0;
@@ -69,7 +69,7 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x,
Scalar rho_old = rho;
rho = r0.dot(r);
- if (internal::isMuchSmallerThan(rho,r0_sqnorm))
+ if (abs(rho) < eps2*r0_sqnorm)
{
// The new residual vector became too orthogonal to the arbitrarily choosen direction r0
// Let's restart with a new r0:
@@ -142,7 +142,7 @@ struct traits<BiCGSTAB<_MatrixType,_Preconditioner> >
* SparseMatrix<double> A(n,n);
* // fill A and b
* BiCGSTAB<SparseMatrix<double> > solver;
- * solver(A);
+ * solver.compute(A);
* x = solver.solve(b);
* std::cout << "#iterations: " << solver.iterations() << std::endl;
* std::cout << "estimated error: " << solver.error() << std::endl;
@@ -151,20 +151,7 @@ struct traits<BiCGSTAB<_MatrixType,_Preconditioner> >
* \endcode
*
* By default the iterations start with x=0 as an initial guess of the solution.
- * One can control the start using the solveWithGuess() method. Here is a step by
- * step execution example starting with a random guess and printing the evolution
- * of the estimated error:
- * * \code
- * x = VectorXd::Random(n);
- * solver.setMaxIterations(1);
- * int i = 0;
- * do {
- * x = solver.solveWithGuess(b,x);
- * std::cout << i << " : " << solver.error() << std::endl;
- * ++i;
- * } while (solver.info()!=Success && i<100);
- * \endcode
- * Note that such a step by step excution is slightly slower.
+ * One can control the start using the solveWithGuess() method.
*
* \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
*/
@@ -199,7 +186,8 @@ public:
* this class becomes invalid. Call compute() to update it with the new
* matrix A, or modify a copy of A.
*/
- BiCGSTAB(const MatrixType& A) : Base(A) {}
+ template<typename MatrixDerived>
+ explicit BiCGSTAB(const EigenBase<MatrixDerived>& A) : Base(A.derived()) {}
~BiCGSTAB() {}
diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
index a74a8155e68..1a7e569c806 100644
--- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
+++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h
@@ -112,9 +112,9 @@ struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
* This class allows to solve for A.x = b sparse linear problems using a conjugate gradient algorithm.
* The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or sparse.
*
- * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
- * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
- * or Upper. Default is Lower.
+ * \tparam _MatrixType the type of the matrix A, can be a dense or a sparse matrix.
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower,
+ * Upper, or Lower|Upper in which the full matrix entries will be considered. Default is Lower.
* \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
*
* The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
@@ -137,20 +137,7 @@ struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
* \endcode
*
* By default the iterations start with x=0 as an initial guess of the solution.
- * One can control the start using the solveWithGuess() method. Here is a step by
- * step execution example starting with a random guess and printing the evolution
- * of the estimated error:
- * * \code
- * x = VectorXd::Random(n);
- * cg.setMaxIterations(1);
- * int i = 0;
- * do {
- * x = cg.solveWithGuess(b,x);
- * std::cout << i << " : " << cg.error() << std::endl;
- * ++i;
- * } while (cg.info()!=Success && i<100);
- * \endcode
- * Note that such a step by step excution is slightly slower.
+ * One can control the start using the solveWithGuess() method.
*
* \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
*/
@@ -189,7 +176,8 @@ public:
* this class becomes invalid. Call compute() to update it with the new
* matrix A, or modify a copy of A.
*/
- ConjugateGradient(const MatrixType& A) : Base(A) {}
+ template<typename MatrixDerived>
+ explicit ConjugateGradient(const EigenBase<MatrixDerived>& A) : Base(A.derived()) {}
~ConjugateGradient() {}
@@ -213,6 +201,10 @@ public:
template<typename Rhs,typename Dest>
void _solveWithGuess(const Rhs& b, Dest& x) const
{
+ typedef typename internal::conditional<UpLo==(Lower|Upper),
+ const MatrixType&,
+ SparseSelfAdjointView<const MatrixType, UpLo>
+ >::type MatrixWrapperType;
m_iterations = Base::maxIterations();
m_error = Base::m_tolerance;
@@ -222,8 +214,7 @@ public:
m_error = Base::m_tolerance;
typename Dest::ColXpr xj(x,j);
- internal::conjugate_gradient(mp_matrix->template selfadjointView<UpLo>(), b.col(j), xj,
- Base::m_preconditioner, m_iterations, m_error);
+ internal::conjugate_gradient(MatrixWrapperType(*mp_matrix), b.col(j), xj, Base::m_preconditioner, m_iterations, m_error);
}
m_isInitialized = true;
@@ -234,7 +225,7 @@ public:
template<typename Rhs,typename Dest>
void _solve(const Rhs& b, Dest& x) const
{
- x.setOnes();
+ x.setZero();
_solveWithGuess(b,x);
}
diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
index b55afc13636..d3f37fea2a1 100644
--- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
+++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h
@@ -150,7 +150,6 @@ class IncompleteLUT : internal::noncopyable
{
analyzePattern(amat);
factorize(amat);
- m_isInitialized = m_factorizationIsOk;
return *this;
}
@@ -160,7 +159,7 @@ class IncompleteLUT : internal::noncopyable
template<typename Rhs, typename Dest>
void _solve(const Rhs& b, Dest& x) const
{
- x = m_Pinv * b;
+ x = m_Pinv * b;
x = m_lu.template triangularView<UnitLower>().solve(x);
x = m_lu.template triangularView<Upper>().solve(x);
x = m_P * x;
@@ -223,18 +222,29 @@ template<typename _MatrixType>
void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat)
{
// Compute the Fill-reducing permutation
+ // Since ILUT does not perform any numerical pivoting,
+ // it is highly preferable to keep the diagonal through symmetric permutations.
+#ifndef EIGEN_MPL2_ONLY
+ // To this end, let's symmetrize the pattern and perform AMD on it.
SparseMatrix<Scalar,ColMajor, Index> mat1 = amat;
SparseMatrix<Scalar,ColMajor, Index> mat2 = amat.transpose();
- // Symmetrize the pattern
// FIXME for a matrix with nearly symmetric pattern, mat2+mat1 is the appropriate choice.
// on the other hand for a really non-symmetric pattern, mat2*mat1 should be prefered...
SparseMatrix<Scalar,ColMajor, Index> AtA = mat2 + mat1;
- AtA.prune(keep_diag());
- internal::minimum_degree_ordering<Scalar, Index>(AtA, m_P); // Then compute the AMD ordering...
-
- m_Pinv = m_P.inverse(); // ... and the inverse permutation
+ AMDOrdering<Index> ordering;
+ ordering(AtA,m_P);
+ m_Pinv = m_P.inverse(); // cache the inverse permutation
+#else
+ // If AMD is not available, (MPL2-only), then let's use the slower COLAMD routine.
+ SparseMatrix<Scalar,ColMajor, Index> mat1 = amat;
+ COLAMDOrdering<Index> ordering;
+ ordering(mat1,m_Pinv);
+ m_P = m_Pinv.inverse();
+#endif
m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+ m_isInitialized = false;
}
template <typename Scalar>
@@ -442,6 +452,7 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat)
m_lu.makeCompressed();
m_factorizationIsOk = true;
+ m_isInitialized = m_factorizationIsOk;
m_info = Success;
}
diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
index 2036922d69c..501ef2f8d87 100644
--- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
+++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h
@@ -49,10 +49,11 @@ public:
* this class becomes invalid. Call compute() to update it with the new
* matrix A, or modify a copy of A.
*/
- IterativeSolverBase(const MatrixType& A)
+ template<typename InputDerived>
+ IterativeSolverBase(const EigenBase<InputDerived>& A)
{
init();
- compute(A);
+ compute(A.derived());
}
~IterativeSolverBase() {}
@@ -62,9 +63,11 @@ public:
* Currently, this function mostly call analyzePattern on the preconditioner. In the future
* we might, for instance, implement column reodering for faster matrix vector products.
*/
- Derived& analyzePattern(const MatrixType& A)
+ template<typename InputDerived>
+ Derived& analyzePattern(const EigenBase<InputDerived>& A)
{
- m_preconditioner.analyzePattern(A);
+ grabInput(A.derived());
+ m_preconditioner.analyzePattern(*mp_matrix);
m_isInitialized = true;
m_analysisIsOk = true;
m_info = Success;
@@ -80,11 +83,12 @@ public:
* this class becomes invalid. Call compute() to update it with the new
* matrix A, or modify a copy of A.
*/
- Derived& factorize(const MatrixType& A)
+ template<typename InputDerived>
+ Derived& factorize(const EigenBase<InputDerived>& A)
{
+ grabInput(A.derived());
eigen_assert(m_analysisIsOk && "You must first call analyzePattern()");
- mp_matrix = &A;
- m_preconditioner.factorize(A);
+ m_preconditioner.factorize(*mp_matrix);
m_factorizationIsOk = true;
m_info = Success;
return derived();
@@ -100,10 +104,11 @@ public:
* this class becomes invalid. Call compute() to update it with the new
* matrix A, or modify a copy of A.
*/
- Derived& compute(const MatrixType& A)
+ template<typename InputDerived>
+ Derived& compute(const EigenBase<InputDerived>& A)
{
- mp_matrix = &A;
- m_preconditioner.compute(A);
+ grabInput(A.derived());
+ m_preconditioner.compute(*mp_matrix);
m_isInitialized = true;
m_analysisIsOk = true;
m_factorizationIsOk = true;
@@ -212,6 +217,28 @@ public:
}
protected:
+
+ template<typename InputDerived>
+ void grabInput(const EigenBase<InputDerived>& A)
+ {
+ // we const cast to prevent the creation of a MatrixType temporary by the compiler.
+ grabInput_impl(A.const_cast_derived());
+ }
+
+ template<typename InputDerived>
+ void grabInput_impl(const EigenBase<InputDerived>& A)
+ {
+ m_copyMatrix = A;
+ mp_matrix = &m_copyMatrix;
+ }
+
+ void grabInput_impl(MatrixType& A)
+ {
+ if(MatrixType::RowsAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==Dynamic)
+ m_copyMatrix.resize(0,0);
+ mp_matrix = &A;
+ }
+
void init()
{
m_isInitialized = false;
@@ -220,6 +247,7 @@ protected:
m_maxIterations = -1;
m_tolerance = NumTraits<Scalar>::epsilon();
}
+ MatrixType m_copyMatrix;
const MatrixType* mp_matrix;
Preconditioner m_preconditioner;
diff --git a/extern/Eigen3/Eigen/src/LU/FullPivLU.h b/extern/Eigen3/Eigen/src/LU/FullPivLU.h
index dfe25f424d7..26bc714475c 100644
--- a/extern/Eigen3/Eigen/src/LU/FullPivLU.h
+++ b/extern/Eigen3/Eigen/src/LU/FullPivLU.h
@@ -20,10 +20,11 @@ namespace Eigen {
*
* \param MatrixType the type of the matrix of which we are computing the LU decomposition
*
- * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A
- * is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q
- * are permutation matrices. This is a rank-revealing LU decomposition. The eigenvalues (diagonal
- * coefficients) of U are sorted in such a way that any zeros are at the end.
+ * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A is
+ * decomposed as \f$ A = P^{-1} L U Q^{-1} \f$ where L is unit-lower-triangular, U is
+ * upper-triangular, and P and Q are permutation matrices. This is a rank-revealing LU
+ * decomposition. The eigenvalues (diagonal coefficients) of U are sorted in such a way that any
+ * zeros are at the end.
*
* This decomposition provides the generic approach to solving systems of linear equations, computing
* the rank, invertibility, inverse, kernel, and determinant.
@@ -373,6 +374,12 @@ template<typename _MatrixType> class FullPivLU
inline Index cols() const { return m_lu.cols(); }
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
MatrixType m_lu;
PermutationPType m_p;
PermutationQType m_q;
@@ -417,6 +424,8 @@ FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix)
template<typename MatrixType>
FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
{
+ check_template_parameters();
+
// the permutations are stored as int indices, so just to be sure:
eigen_assert(matrix.rows()<=NumTraits<int>::highest() && matrix.cols()<=NumTraits<int>::highest());
@@ -511,8 +520,8 @@ typename internal::traits<MatrixType>::Scalar FullPivLU<MatrixType>::determinant
}
/** \returns the matrix represented by the decomposition,
- * i.e., it returns the product: P^{-1} L U Q^{-1}.
- * This function is provided for debug purpose. */
+ * i.e., it returns the product: \f$ P^{-1} L U Q^{-1} \f$.
+ * This function is provided for debug purposes. */
template<typename MatrixType>
MatrixType FullPivLU<MatrixType>::reconstructedMatrix() const
{
diff --git a/extern/Eigen3/Eigen/src/LU/PartialPivLU.h b/extern/Eigen3/Eigen/src/LU/PartialPivLU.h
index 740ee694c45..7d1db948c0a 100644
--- a/extern/Eigen3/Eigen/src/LU/PartialPivLU.h
+++ b/extern/Eigen3/Eigen/src/LU/PartialPivLU.h
@@ -171,6 +171,12 @@ template<typename _MatrixType> class PartialPivLU
inline Index cols() const { return m_lu.cols(); }
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
MatrixType m_lu;
PermutationType m_p;
TranspositionType m_rowsTranspositions;
@@ -386,6 +392,8 @@ void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, t
template<typename MatrixType>
PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& matrix)
{
+ check_template_parameters();
+
// the row permutation is stored as int indices, so just to be sure:
eigen_assert(matrix.rows()<NumTraits<int>::highest());
diff --git a/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h b/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h
index 41b4fd7e392..70550b8a90a 100644
--- a/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h
+++ b/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h
@@ -137,22 +137,27 @@ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, Permutation
degree[i] = len[i]; // degree of node i
}
mark = internal::cs_wclear<Index>(0, 0, w, n); /* clear w */
- elen[n] = -2; /* n is a dead element */
- Cp[n] = -1; /* n is a root of assembly tree */
- w[n] = 0; /* n is a dead element */
/* --- Initialize degree lists ------------------------------------------ */
for(i = 0; i < n; i++)
{
+ bool has_diag = false;
+ for(p = Cp[i]; p<Cp[i+1]; ++p)
+ if(Ci[p]==i)
+ {
+ has_diag = true;
+ break;
+ }
+
d = degree[i];
- if(d == 0) /* node i is empty */
+ if(d == 1 && has_diag) /* node i is empty */
{
elen[i] = -2; /* element i is dead */
nel++;
Cp[i] = -1; /* i is a root of assembly tree */
w[i] = 0;
}
- else if(d > dense) /* node i is dense */
+ else if(d > dense || !has_diag) /* node i is dense or has no structural diagonal element */
{
nv[i] = 0; /* absorb i into element n */
elen[i] = -1; /* node i is dead */
@@ -168,6 +173,10 @@ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, Permutation
}
}
+ elen[n] = -2; /* n is a dead element */
+ Cp[n] = -1; /* n is a root of assembly tree */
+ w[n] = 0; /* n is a dead element */
+
while (nel < n) /* while (selecting pivots) do */
{
/* --- Select node of minimum approximate degree -------------------- */
diff --git a/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h b/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h
index b4da6531a1d..f3c31f9cbfc 100644
--- a/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h
+++ b/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h
@@ -109,7 +109,7 @@ class NaturalOrdering
* \class COLAMDOrdering
*
* Functor computing the \em column \em approximate \em minimum \em degree ordering
- * The matrix should be in column-major format
+ * The matrix should be in column-major and \b compressed format (see SparseMatrix::makeCompressed()).
*/
template<typename Index>
class COLAMDOrdering
@@ -118,10 +118,14 @@ class COLAMDOrdering
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
typedef Matrix<Index, Dynamic, 1> IndexVector;
- /** Compute the permutation vector form a sparse matrix */
+ /** Compute the permutation vector \a perm form the sparse matrix \a mat
+ * \warning The input sparse matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
+ */
template <typename MatrixType>
void operator() (const MatrixType& mat, PermutationType& perm)
{
+ eigen_assert(mat.isCompressed() && "COLAMDOrdering requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to COLAMDOrdering");
+
Index m = mat.rows();
Index n = mat.cols();
Index nnz = mat.nonZeros();
@@ -132,12 +136,12 @@ class COLAMDOrdering
Index stats [COLAMD_STATS];
internal::colamd_set_defaults(knobs);
- Index info;
IndexVector p(n+1), A(Alen);
for(Index i=0; i <= n; i++) p(i) = mat.outerIndexPtr()[i];
for(Index i=0; i < nnz; i++) A(i) = mat.innerIndexPtr()[i];
// Call Colamd routine to compute the ordering
- info = internal::colamd(m, n, Alen, A.data(), p.data(), knobs, stats);
+ Index info = internal::colamd(m, n, Alen, A.data(), p.data(), knobs, stats);
+ EIGEN_UNUSED_VARIABLE(info);
eigen_assert( info && "COLAMD failed " );
perm.resize(n);
diff --git a/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h b/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h
index 1c48f0df7b5..18cd7d88aea 100644
--- a/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h
+++ b/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h
@@ -219,7 +219,7 @@ class PardisoImpl
void pardisoInit(int type)
{
m_type = type;
- bool symmetric = abs(m_type) < 10;
+ bool symmetric = std::abs(m_type) < 10;
m_iparm[0] = 1; // No solver default
m_iparm[1] = 3; // use Metis for the ordering
m_iparm[2] = 1; // Numbers of processors, value of OMP_NUM_THREADS
diff --git a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h
index bec85810ccc..567eab7cda5 100644
--- a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h
+++ b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h
@@ -76,7 +76,8 @@ template<typename _MatrixType> class ColPivHouseholderQR
m_colsTranspositions(),
m_temp(),
m_colSqNorms(),
- m_isInitialized(false) {}
+ m_isInitialized(false),
+ m_usePrescribedThreshold(false) {}
/** \brief Default Constructor with memory preallocation
*
@@ -383,6 +384,12 @@ template<typename _MatrixType> class ColPivHouseholderQR
}
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
MatrixType m_qr;
HCoeffsType m_hCoeffs;
PermutationType m_colsPermutation;
@@ -421,6 +428,8 @@ typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDetermina
template<typename MatrixType>
ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
{
+ check_template_parameters();
+
using std::abs;
Index rows = matrix.rows();
Index cols = matrix.cols();
@@ -462,20 +471,10 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const
// we store that back into our table: it can't hurt to correct our table.
m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm;
- // if the current biggest column is smaller than epsilon times the initial biggest column,
- // terminate to avoid generating nan/inf values.
- // Note that here, if we test instead for "biggest == 0", we get a failure every 1000 (or so)
- // repetitions of the unit test, with the result of solve() filled with large values of the order
- // of 1/(size*epsilon).
- if(biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
- {
+ // Track the number of meaningful pivots but do not stop the decomposition to make
+ // sure that the initial matrix is properly reproduced. See bug 941.
+ if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k))
m_nonzero_pivots = k;
- m_hCoeffs.tail(size-k).setZero();
- m_qr.bottomRightCorner(rows-k,cols-k)
- .template triangularView<StrictlyLower>()
- .setZero();
- break;
- }
// apply the transposition to the columns
m_colsTranspositions.coeffRef(k) = biggest_col_index;
@@ -504,7 +503,7 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const
}
m_colsPermutation.setIdentity(PermIndexType(cols));
- for(PermIndexType k = 0; k < m_nonzero_pivots; ++k)
+ for(PermIndexType k = 0; k < size/*m_nonzero_pivots*/; ++k)
m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k)));
m_det_pq = (number_of_transpositions%2) ? -1 : 1;
@@ -554,13 +553,15 @@ struct solve_retval<ColPivHouseholderQR<_MatrixType>, Rhs>
} // end namespace internal
-/** \returns the matrix Q as a sequence of householder transformations */
+/** \returns the matrix Q as a sequence of householder transformations.
+ * You can extract the meaningful part only by using:
+ * \code qr.householderQ().setLength(qr.nonzeroPivots()) \endcode*/
template<typename MatrixType>
typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType>
::householderQ() const
{
eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
- return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()).setLength(m_nonzero_pivots);
+ return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate());
}
/** \return the column-pivoting Householder QR decomposition of \c *this.
diff --git a/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h b/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h
index 6168e7abfb4..0b39966e145 100644
--- a/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h
+++ b/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h
@@ -368,6 +368,12 @@ template<typename _MatrixType> class FullPivHouseholderQR
RealScalar maxPivot() const { return m_maxpivot; }
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
MatrixType m_qr;
HCoeffsType m_hCoeffs;
IntDiagSizeVectorType m_rows_transpositions;
@@ -407,6 +413,8 @@ typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDetermin
template<typename MatrixType>
FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix)
{
+ check_template_parameters();
+
using std::abs;
Index rows = matrix.rows();
Index cols = matrix.cols();
diff --git a/extern/Eigen3/Eigen/src/QR/HouseholderQR.h b/extern/Eigen3/Eigen/src/QR/HouseholderQR.h
index abc61bcbbe1..343a6649934 100644
--- a/extern/Eigen3/Eigen/src/QR/HouseholderQR.h
+++ b/extern/Eigen3/Eigen/src/QR/HouseholderQR.h
@@ -189,6 +189,12 @@ template<typename _MatrixType> class HouseholderQR
const HCoeffsType& hCoeffs() const { return m_hCoeffs; }
protected:
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
+
MatrixType m_qr;
HCoeffsType m_hCoeffs;
RowVectorType m_temp;
@@ -251,56 +257,62 @@ void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename
}
/** \internal */
-template<typename MatrixQR, typename HCoeffs>
-void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs,
- typename MatrixQR::Index maxBlockSize=32,
- typename MatrixQR::Scalar* tempData = 0)
+template<typename MatrixQR, typename HCoeffs,
+ typename MatrixQRScalar = typename MatrixQR::Scalar,
+ bool InnerStrideIsOne = (MatrixQR::InnerStrideAtCompileTime == 1 && HCoeffs::InnerStrideAtCompileTime == 1)>
+struct householder_qr_inplace_blocked
{
- typedef typename MatrixQR::Index Index;
- typedef typename MatrixQR::Scalar Scalar;
- typedef Block<MatrixQR,Dynamic,Dynamic> BlockType;
-
- Index rows = mat.rows();
- Index cols = mat.cols();
- Index size = (std::min)(rows, cols);
-
- typedef Matrix<Scalar,Dynamic,1,ColMajor,MatrixQR::MaxColsAtCompileTime,1> TempType;
- TempType tempVector;
- if(tempData==0)
+ // This is specialized for MKL-supported Scalar types in HouseholderQR_MKL.h
+ static void run(MatrixQR& mat, HCoeffs& hCoeffs,
+ typename MatrixQR::Index maxBlockSize=32,
+ typename MatrixQR::Scalar* tempData = 0)
{
- tempVector.resize(cols);
- tempData = tempVector.data();
- }
-
- Index blockSize = (std::min)(maxBlockSize,size);
+ typedef typename MatrixQR::Index Index;
+ typedef typename MatrixQR::Scalar Scalar;
+ typedef Block<MatrixQR,Dynamic,Dynamic> BlockType;
- Index k = 0;
- for (k = 0; k < size; k += blockSize)
- {
- Index bs = (std::min)(size-k,blockSize); // actual size of the block
- Index tcols = cols - k - bs; // trailing columns
- Index brows = rows-k; // rows of the block
+ Index rows = mat.rows();
+ Index cols = mat.cols();
+ Index size = (std::min)(rows, cols);
- // partition the matrix:
- // A00 | A01 | A02
- // mat = A10 | A11 | A12
- // A20 | A21 | A22
- // and performs the qr dec of [A11^T A12^T]^T
- // and update [A21^T A22^T]^T using level 3 operations.
- // Finally, the algorithm continue on A22
-
- BlockType A11_21 = mat.block(k,k,brows,bs);
- Block<HCoeffs,Dynamic,1> hCoeffsSegment = hCoeffs.segment(k,bs);
+ typedef Matrix<Scalar,Dynamic,1,ColMajor,MatrixQR::MaxColsAtCompileTime,1> TempType;
+ TempType tempVector;
+ if(tempData==0)
+ {
+ tempVector.resize(cols);
+ tempData = tempVector.data();
+ }
- householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData);
+ Index blockSize = (std::min)(maxBlockSize,size);
- if(tcols)
+ Index k = 0;
+ for (k = 0; k < size; k += blockSize)
{
- BlockType A21_22 = mat.block(k,k+bs,brows,tcols);
- apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint());
+ Index bs = (std::min)(size-k,blockSize); // actual size of the block
+ Index tcols = cols - k - bs; // trailing columns
+ Index brows = rows-k; // rows of the block
+
+ // partition the matrix:
+ // A00 | A01 | A02
+ // mat = A10 | A11 | A12
+ // A20 | A21 | A22
+ // and performs the qr dec of [A11^T A12^T]^T
+ // and update [A21^T A22^T]^T using level 3 operations.
+ // Finally, the algorithm continue on A22
+
+ BlockType A11_21 = mat.block(k,k,brows,bs);
+ Block<HCoeffs,Dynamic,1> hCoeffsSegment = hCoeffs.segment(k,bs);
+
+ householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData);
+
+ if(tcols)
+ {
+ BlockType A21_22 = mat.block(k,k+bs,brows,tcols);
+ apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint());
+ }
}
}
-}
+};
template<typename _MatrixType, typename Rhs>
struct solve_retval<HouseholderQR<_MatrixType>, Rhs>
@@ -343,6 +355,8 @@ struct solve_retval<HouseholderQR<_MatrixType>, Rhs>
template<typename MatrixType>
HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& matrix)
{
+ check_template_parameters();
+
Index rows = matrix.rows();
Index cols = matrix.cols();
Index size = (std::min)(rows,cols);
@@ -352,7 +366,7 @@ HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType&
m_temp.resize(cols);
- internal::householder_qr_inplace_blocked(m_qr, m_hCoeffs, 48, m_temp.data());
+ internal::householder_qr_inplace_blocked<MatrixType, HCoeffsType>::run(m_qr, m_hCoeffs, 48, m_temp.data());
m_isInitialized = true;
return *this;
diff --git a/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h b/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h
index 5313de604d2..b80f1b48dac 100644
--- a/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h
+++ b/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h
@@ -34,28 +34,30 @@
#ifndef EIGEN_QR_MKL_H
#define EIGEN_QR_MKL_H
-#include "Eigen/src/Core/util/MKL_support.h"
+#include "../Core/util/MKL_support.h"
namespace Eigen {
-namespace internal {
+ namespace internal {
-/** \internal Specialization for the data types supported by MKL */
+ /** \internal Specialization for the data types supported by MKL */
#define EIGEN_MKL_QR_NOPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \
template<typename MatrixQR, typename HCoeffs> \
-void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, \
- typename MatrixQR::Index maxBlockSize=32, \
- EIGTYPE* tempData = 0) \
+struct householder_qr_inplace_blocked<MatrixQR, HCoeffs, EIGTYPE, true> \
{ \
- lapack_int m = mat.rows(); \
- lapack_int n = mat.cols(); \
- lapack_int lda = mat.outerStride(); \
- lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \
- LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \
- hCoeffs.adjointInPlace(); \
-\
-}
+ static void run(MatrixQR& mat, HCoeffs& hCoeffs, \
+ typename MatrixQR::Index = 32, \
+ typename MatrixQR::Scalar* = 0) \
+ { \
+ lapack_int m = (lapack_int) mat.rows(); \
+ lapack_int n = (lapack_int) mat.cols(); \
+ lapack_int lda = (lapack_int) mat.outerStride(); \
+ lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \
+ LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \
+ hCoeffs.adjointInPlace(); \
+ } \
+};
EIGEN_MKL_QR_NOPIV(double, double, d)
EIGEN_MKL_QR_NOPIV(float, float, s)
diff --git a/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h b/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h
index a2cc2a9e261..36138101d74 100644
--- a/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h
+++ b/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h
@@ -47,7 +47,7 @@ namespace Eigen {
* You can then apply it to a vector.
*
* R is the sparse triangular factor. Use matrixQR() to get it as SparseMatrix.
- * NOTE : The Index type of R is always UF_long. You can get it with SPQR::Index
+ * NOTE : The Index type of R is always SuiteSparse_long. You can get it with SPQR::Index
*
* \tparam _MatrixType The type of the sparse matrix A, must be a column-major SparseMatrix<>
* NOTE
@@ -59,24 +59,18 @@ class SPQR
public:
typedef typename _MatrixType::Scalar Scalar;
typedef typename _MatrixType::RealScalar RealScalar;
- typedef UF_long Index ;
+ typedef SuiteSparse_long Index ;
typedef SparseMatrix<Scalar, ColMajor, Index> MatrixType;
typedef PermutationMatrix<Dynamic, Dynamic> PermutationType;
public:
SPQR()
- : m_isInitialized(false),
- m_ordering(SPQR_ORDERING_DEFAULT),
- m_allow_tol(SPQR_DEFAULT_TOL),
- m_tolerance (NumTraits<Scalar>::epsilon())
+ : m_isInitialized(false), m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits<Scalar>::epsilon()), m_useDefaultThreshold(true)
{
cholmod_l_start(&m_cc);
}
- SPQR(const _MatrixType& matrix)
- : m_isInitialized(false),
- m_ordering(SPQR_ORDERING_DEFAULT),
- m_allow_tol(SPQR_DEFAULT_TOL),
- m_tolerance (NumTraits<Scalar>::epsilon())
+ SPQR(const _MatrixType& matrix)
+ : m_isInitialized(false), m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits<Scalar>::epsilon()), m_useDefaultThreshold(true)
{
cholmod_l_start(&m_cc);
compute(matrix);
@@ -101,10 +95,26 @@ class SPQR
if(m_isInitialized) SPQR_free();
MatrixType mat(matrix);
+
+ /* Compute the default threshold as in MatLab, see:
+ * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
+ * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
+ */
+ RealScalar pivotThreshold = m_tolerance;
+ if(m_useDefaultThreshold)
+ {
+ using std::max;
+ RealScalar max2Norm = 0.0;
+ for (int j = 0; j < mat.cols(); j++) max2Norm = (max)(max2Norm, mat.col(j).norm());
+ if(max2Norm==RealScalar(0))
+ max2Norm = RealScalar(1);
+ pivotThreshold = 20 * (mat.rows() + mat.cols()) * max2Norm * NumTraits<RealScalar>::epsilon();
+ }
+
cholmod_sparse A;
A = viewAsCholmod(mat);
Index col = matrix.cols();
- m_rank = SuiteSparseQR<Scalar>(m_ordering, m_tolerance, col, &A,
+ m_rank = SuiteSparseQR<Scalar>(m_ordering, pivotThreshold, col, &A,
&m_cR, &m_E, &m_H, &m_HPinv, &m_HTau, &m_cc);
if (!m_cR)
@@ -120,7 +130,7 @@ class SPQR
/**
* Get the number of rows of the input matrix and the Q matrix
*/
- inline Index rows() const {return m_H->nrow; }
+ inline Index rows() const {return m_cR->nrow; }
/**
* Get the number of columns of the input matrix.
@@ -145,16 +155,25 @@ class SPQR
{
eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()");
eigen_assert(b.cols()==1 && "This method is for vectors only");
-
+
//Compute Q^T * b
- typename Dest::PlainObject y;
+ typename Dest::PlainObject y, y2;
y = matrixQ().transpose() * b;
- // Solves with the triangular matrix R
+
+ // Solves with the triangular matrix R
Index rk = this->rank();
- y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView<Upper>().solve(y.topRows(rk));
- y.bottomRows(cols()-rk).setZero();
+ y2 = y;
+ y.resize((std::max)(cols(),Index(y.rows())),y.cols());
+ y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView<Upper>().solve(y2.topRows(rk));
+
// Apply the column permutation
- dest.topRows(cols()) = colsPermutation() * y.topRows(cols());
+ // colsPermutation() performs a copy of the permutation,
+ // so let's apply it manually:
+ for(Index i = 0; i < rk; ++i) dest.row(m_E[i]) = y.row(i);
+ for(Index i = rk; i < cols(); ++i) dest.row(m_E[i]).setZero();
+
+// y.bottomRows(y.rows()-rk).setZero();
+// dest = colsPermutation() * y.topRows(cols());
m_info = Success;
}
@@ -197,7 +216,11 @@ class SPQR
/// Set the fill-reducing ordering method to be used
void setSPQROrdering(int ord) { m_ordering = ord;}
/// Set the tolerance tol to treat columns with 2-norm < =tol as zero
- void setPivotThreshold(const RealScalar& tol) { m_tolerance = tol; }
+ void setPivotThreshold(const RealScalar& tol)
+ {
+ m_useDefaultThreshold = false;
+ m_tolerance = tol;
+ }
/** \returns a pointer to the SPQR workspace */
cholmod_common *cholmodCommon() const { return &m_cc; }
@@ -230,6 +253,7 @@ class SPQR
mutable cholmod_dense *m_HTau; // The Householder coefficients
mutable Index m_rank; // The rank of the matrix
mutable cholmod_common m_cc; // Workspace and parameters
+ bool m_useDefaultThreshold; // Use default threshold
template<typename ,typename > friend struct SPQR_QProduct;
};
diff --git a/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h b/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h
index f44995cd39c..1b29774190a 100644
--- a/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h
+++ b/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h
@@ -375,17 +375,19 @@ struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
Scalar z;
JacobiRotation<Scalar> rot;
RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p)));
+
if(n==0)
{
z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q);
work_matrix.row(p) *= z;
if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z);
if(work_matrix.coeff(q,q)!=Scalar(0))
+ {
z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
- else
- z = Scalar(0);
- work_matrix.row(q) *= z;
- if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z);
+ work_matrix.row(q) *= z;
+ if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z);
+ }
+ // otherwise the second row is already zero, so we have nothing to do.
}
else
{
@@ -415,6 +417,7 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
JacobiRotation<RealScalar> *j_right)
{
using std::sqrt;
+ using std::abs;
Matrix<RealScalar,2,2> m;
m << numext::real(matrix.coeff(p,p)), numext::real(matrix.coeff(p,q)),
numext::real(matrix.coeff(q,p)), numext::real(matrix.coeff(q,q));
@@ -428,9 +431,11 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
}
else
{
- RealScalar u = d / t;
- rot1.c() = RealScalar(1) / sqrt(RealScalar(1) + numext::abs2(u));
- rot1.s() = rot1.c() * u;
+ RealScalar t2d2 = numext::hypot(t,d);
+ rot1.c() = abs(t)/t2d2;
+ rot1.s() = d/t2d2;
+ if(t<RealScalar(0))
+ rot1.s() = -rot1.s();
}
m.applyOnTheLeft(0,1,rot1);
j_right->makeJacobi(m,0,1);
@@ -531,8 +536,9 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
JacobiSVD()
: m_isInitialized(false),
m_isAllocated(false),
+ m_usePrescribedThreshold(false),
m_computationOptions(0),
- m_rows(-1), m_cols(-1)
+ m_rows(-1), m_cols(-1), m_diagSize(0)
{}
@@ -545,6 +551,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0)
: m_isInitialized(false),
m_isAllocated(false),
+ m_usePrescribedThreshold(false),
m_computationOptions(0),
m_rows(-1), m_cols(-1)
{
@@ -564,6 +571,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0)
: m_isInitialized(false),
m_isAllocated(false),
+ m_usePrescribedThreshold(false),
m_computationOptions(0),
m_rows(-1), m_cols(-1)
{
@@ -665,23 +673,92 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
return m_nonzeroSingularValues;
}
+
+ /** \returns the rank of the matrix of which \c *this is the SVD.
+ *
+ * \note This method has to determine which singular values should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index rank() const
+ {
+ using std::abs;
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ if(m_singularValues.size()==0) return 0;
+ RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold();
+ Index i = m_nonzeroSingularValues-1;
+ while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i;
+ return i+1;
+ }
+
+ /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(),
+ * which need to determine when singular values are to be considered nonzero.
+ * This is not used for the SVD decomposition itself.
+ *
+ * When it needs to get the threshold value, Eigen calls threshold().
+ * The default is \c NumTraits<Scalar>::epsilon()
+ *
+ * \param threshold The new value to use as the threshold.
+ *
+ * A singular value will be considered nonzero if its value is strictly greater than
+ * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$.
+ *
+ * If you want to come back to the default behavior, call setThreshold(Default_t)
+ */
+ JacobiSVD& setThreshold(const RealScalar& threshold)
+ {
+ m_usePrescribedThreshold = true;
+ m_prescribedThreshold = threshold;
+ return *this;
+ }
+
+ /** Allows to come back to the default behavior, letting Eigen use its default formula for
+ * determining the threshold.
+ *
+ * You should pass the special object Eigen::Default as parameter here.
+ * \code svd.setThreshold(Eigen::Default); \endcode
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ JacobiSVD& setThreshold(Default_t)
+ {
+ m_usePrescribedThreshold = false;
+ return *this;
+ }
+
+ /** Returns the threshold that will be used by certain methods such as rank().
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ RealScalar threshold() const
+ {
+ eigen_assert(m_isInitialized || m_usePrescribedThreshold);
+ return m_usePrescribedThreshold ? m_prescribedThreshold
+ : (std::max<Index>)(1,m_diagSize)*NumTraits<Scalar>::epsilon();
+ }
inline Index rows() const { return m_rows; }
inline Index cols() const { return m_cols; }
private:
void allocate(Index rows, Index cols, unsigned int computationOptions);
+
+ static void check_template_parameters()
+ {
+ EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
+ }
protected:
MatrixUType m_matrixU;
MatrixVType m_matrixV;
SingularValuesType m_singularValues;
WorkMatrixType m_workMatrix;
- bool m_isInitialized, m_isAllocated;
+ bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold;
bool m_computeFullU, m_computeThinU;
bool m_computeFullV, m_computeThinV;
unsigned int m_computationOptions;
Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize;
+ RealScalar m_prescribedThreshold;
template<typename __MatrixType, int _QRPreconditioner, bool _IsComplex>
friend struct internal::svd_precondition_2x2_block_to_be_real;
@@ -690,6 +767,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows> m_qr_precond_morecols;
internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols> m_qr_precond_morerows;
+ MatrixType m_scaledMatrix;
};
template<typename MatrixType, int QRPreconditioner>
@@ -736,14 +814,17 @@ void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Index rows, Index cols, u
: 0);
m_workMatrix.resize(m_diagSize, m_diagSize);
- if(m_cols>m_rows) m_qr_precond_morecols.allocate(*this);
- if(m_rows>m_cols) m_qr_precond_morerows.allocate(*this);
+ if(m_cols>m_rows) m_qr_precond_morecols.allocate(*this);
+ if(m_rows>m_cols) m_qr_precond_morerows.allocate(*this);
+ if(m_cols!=m_cols) m_scaledMatrix.resize(rows,cols);
}
template<typename MatrixType, int QRPreconditioner>
JacobiSVD<MatrixType, QRPreconditioner>&
JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsigned int computationOptions)
{
+ check_template_parameters();
+
using std::abs;
allocate(matrix.rows(), matrix.cols(), computationOptions);
@@ -754,11 +835,21 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
// limit for very small denormal numbers to be considered zero in order to avoid infinite loops (see bug 286)
const RealScalar considerAsZero = RealScalar(2) * std::numeric_limits<RealScalar>::denorm_min();
+ // Scaling factor to reduce over/under-flows
+ RealScalar scale = matrix.cwiseAbs().maxCoeff();
+ if(scale==RealScalar(0)) scale = RealScalar(1);
+
/*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */
- if(!m_qr_precond_morecols.run(*this, matrix) && !m_qr_precond_morerows.run(*this, matrix))
+ if(m_rows!=m_cols)
{
- m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize);
+ m_scaledMatrix = matrix / scale;
+ m_qr_precond_morecols.run(*this, m_scaledMatrix);
+ m_qr_precond_morerows.run(*this, m_scaledMatrix);
+ }
+ else
+ {
+ m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale;
if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize);
if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols);
@@ -784,7 +875,8 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
using std::max;
RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)),
abs(m_workMatrix.coeff(q,q))));
- if((max)(abs(m_workMatrix.coeff(p,q)),abs(m_workMatrix.coeff(q,p))) > threshold)
+ // We compare both values to threshold instead of calling max to be robust to NaN (See bug 791)
+ if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold)
{
finished = false;
@@ -833,6 +925,8 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
if(computeV()) m_matrixV.col(pos).swap(m_matrixV.col(i));
}
}
+
+ m_singularValues *= scale;
m_isInitialized = true;
return *this;
@@ -854,11 +948,11 @@ struct solve_retval<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
// So A^{-1} = V S^{-1} U^*
Matrix<Scalar, Dynamic, Rhs::ColsAtCompileTime, 0, _MatrixType::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime> tmp;
- Index nonzeroSingVals = dec().nonzeroSingularValues();
+ Index rank = dec().rank();
- tmp.noalias() = dec().matrixU().leftCols(nonzeroSingVals).adjoint() * rhs();
- tmp = dec().singularValues().head(nonzeroSingVals).asDiagonal().inverse() * tmp;
- dst = dec().matrixV().leftCols(nonzeroSingVals) * tmp;
+ tmp.noalias() = dec().matrixU().leftCols(rank).adjoint() * rhs();
+ tmp = dec().singularValues().head(rank).asDiagonal().inverse() * tmp;
+ dst = dec().matrixV().leftCols(rank) * tmp;
}
};
} // end namespace internal
diff --git a/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h b/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h
index f41d7e010f7..e1f96ba5a14 100644
--- a/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h
+++ b/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h
@@ -37,6 +37,7 @@ class SimplicialCholeskyBase : internal::noncopyable
{
public:
typedef typename internal::traits<Derived>::MatrixType MatrixType;
+ typedef typename internal::traits<Derived>::OrderingType OrderingType;
enum { UpLo = internal::traits<Derived>::UpLo };
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
@@ -240,15 +241,16 @@ class SimplicialCholeskyBase : internal::noncopyable
RealScalar m_shiftScale;
};
-template<typename _MatrixType, int _UpLo = Lower> class SimplicialLLT;
-template<typename _MatrixType, int _UpLo = Lower> class SimplicialLDLT;
-template<typename _MatrixType, int _UpLo = Lower> class SimplicialCholesky;
+template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialLLT;
+template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialLDLT;
+template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialCholesky;
namespace internal {
-template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixType,_UpLo> >
+template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialLLT<_MatrixType,_UpLo,_Ordering> >
{
typedef _MatrixType MatrixType;
+ typedef _Ordering OrderingType;
enum { UpLo = _UpLo };
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::Index Index;
@@ -259,9 +261,10 @@ template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixTyp
static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
};
-template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixType,_UpLo> >
+template<typename _MatrixType,int _UpLo, typename _Ordering> struct traits<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> >
{
typedef _MatrixType MatrixType;
+ typedef _Ordering OrderingType;
enum { UpLo = _UpLo };
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::Index Index;
@@ -272,9 +275,10 @@ template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixTyp
static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); }
};
-template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_MatrixType,_UpLo> >
+template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> >
{
typedef _MatrixType MatrixType;
+ typedef _Ordering OrderingType;
enum { UpLo = _UpLo };
};
@@ -294,11 +298,12 @@ template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_Matr
* \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
* \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
* or Upper. Default is Lower.
+ * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<>
*
- * \sa class SimplicialLDLT
+ * \sa class SimplicialLDLT, class AMDOrdering, class NaturalOrdering
*/
-template<typename _MatrixType, int _UpLo>
- class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo> >
+template<typename _MatrixType, int _UpLo, typename _Ordering>
+ class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo,_Ordering> >
{
public:
typedef _MatrixType MatrixType;
@@ -382,11 +387,12 @@ public:
* \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<>
* \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
* or Upper. Default is Lower.
+ * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<>
*
- * \sa class SimplicialLLT
+ * \sa class SimplicialLLT, class AMDOrdering, class NaturalOrdering
*/
-template<typename _MatrixType, int _UpLo>
- class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo> >
+template<typename _MatrixType, int _UpLo, typename _Ordering>
+ class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> >
{
public:
typedef _MatrixType MatrixType;
@@ -467,8 +473,8 @@ public:
*
* \sa class SimplicialLDLT, class SimplicialLLT
*/
-template<typename _MatrixType, int _UpLo>
- class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo> >
+template<typename _MatrixType, int _UpLo, typename _Ordering>
+ class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> >
{
public:
typedef _MatrixType MatrixType;
@@ -612,15 +618,13 @@ void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, CholMatrixTy
{
eigen_assert(a.rows()==a.cols());
const Index size = a.rows();
- // TODO allows to configure the permutation
// Note that amd compute the inverse permutation
{
CholMatrixType C;
C = a.template selfadjointView<UpLo>();
- // remove diagonal entries:
- // seems not to be needed
- // C.prune(keep_diag());
- internal::minimum_degree_ordering(C, m_Pinv);
+
+ OrderingType ordering;
+ ordering(C,m_Pinv);
}
if(m_Pinv.size()>0)
diff --git a/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h b/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h
index 17fff96a78b..220c6451cb9 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h
@@ -69,7 +69,7 @@ class AmbiVector
delete[] m_buffer;
if (size<1000)
{
- Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar);
+ Index allocSize = (size * sizeof(ListEl) + sizeof(Scalar) - 1)/sizeof(Scalar);
m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl);
m_buffer = new Scalar[allocSize];
}
@@ -88,7 +88,7 @@ class AmbiVector
Index copyElements = m_allocatedElements;
m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size);
Index allocSize = m_allocatedElements * sizeof(ListEl);
- allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0);
+ allocSize = (allocSize + sizeof(Scalar) - 1)/sizeof(Scalar);
Scalar* newBuffer = new Scalar[allocSize];
memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl));
delete[] m_buffer;
diff --git a/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h b/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h
index 3321fab4a8a..a667cb56ebe 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h
@@ -51,8 +51,8 @@ class CompressedStorage
CompressedStorage& operator=(const CompressedStorage& other)
{
resize(other.size());
- memcpy(m_values, other.m_values, m_size * sizeof(Scalar));
- memcpy(m_indices, other.m_indices, m_size * sizeof(Index));
+ internal::smart_copy(other.m_values, other.m_values + m_size, m_values);
+ internal::smart_copy(other.m_indices, other.m_indices + m_size, m_indices);
return *this;
}
@@ -83,10 +83,10 @@ class CompressedStorage
reallocate(m_size);
}
- void resize(size_t size, float reserveSizeFactor = 0)
+ void resize(size_t size, double reserveSizeFactor = 0)
{
if (m_allocatedSize<size)
- reallocate(size + size_t(reserveSizeFactor*size));
+ reallocate(size + size_t(reserveSizeFactor*double(size)));
m_size = size;
}
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h b/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h
index 16a20a5744e..0c90bafbeab 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h
@@ -57,6 +57,16 @@ public:
inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols)
: m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols)
{}
+
+ inline const Scalar coeff(int row, int col) const
+ {
+ return m_matrix.coeff(row + IsRowMajor ? m_outerStart : 0, col +IsRowMajor ? 0 : m_outerStart);
+ }
+
+ inline const Scalar coeff(int index) const
+ {
+ return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart);
+ }
EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
@@ -68,6 +78,8 @@ public:
const internal::variable_if_dynamic<Index, OuterSize> m_outerSize;
EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl)
+ private:
+ Index nonZeros() const;
};
@@ -82,6 +94,7 @@ class BlockImpl<SparseMatrix<_Scalar, _Options, _Index>,BlockRows,BlockCols,true
typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType;
typedef typename internal::remove_all<typename SparseMatrixType::Nested>::type _MatrixTypeNested;
typedef Block<SparseMatrixType, BlockRows, BlockCols, true> BlockType;
+ typedef Block<const SparseMatrixType, BlockRows, BlockCols, true> ConstBlockType;
public:
enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
@@ -223,6 +236,118 @@ public:
else
return Map<const Matrix<Index,OuterSize,1> >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum();
}
+
+ inline Scalar& coeffRef(int row, int col)
+ {
+ return m_matrix.const_cast_derived().coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart));
+ }
+
+ inline const Scalar coeff(int row, int col) const
+ {
+ return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart));
+ }
+
+ inline const Scalar coeff(int index) const
+ {
+ return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart);
+ }
+
+ const Scalar& lastCoeff() const
+ {
+ EIGEN_STATIC_ASSERT_VECTOR_ONLY(BlockImpl);
+ eigen_assert(nonZeros()>0);
+ if(m_matrix.isCompressed())
+ return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1];
+ else
+ return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart]+m_matrix.innerNonZeroPtr()[m_outerStart]-1];
+ }
+
+ EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); }
+ EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); }
+
+ protected:
+
+ typename SparseMatrixType::Nested m_matrix;
+ Index m_outerStart;
+ const internal::variable_if_dynamic<Index, OuterSize> m_outerSize;
+
+};
+
+
+template<typename _Scalar, int _Options, typename _Index, int BlockRows, int BlockCols>
+class BlockImpl<const SparseMatrix<_Scalar, _Options, _Index>,BlockRows,BlockCols,true,Sparse>
+ : public SparseMatrixBase<Block<const SparseMatrix<_Scalar, _Options, _Index>,BlockRows,BlockCols,true> >
+{
+ typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType;
+ typedef typename internal::remove_all<typename SparseMatrixType::Nested>::type _MatrixTypeNested;
+ typedef Block<const SparseMatrixType, BlockRows, BlockCols, true> BlockType;
+public:
+ enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor };
+ EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType)
+protected:
+ enum { OuterSize = IsRowMajor ? BlockRows : BlockCols };
+public:
+
+ class InnerIterator: public SparseMatrixType::InnerIterator
+ {
+ public:
+ inline InnerIterator(const BlockType& xpr, Index outer)
+ : SparseMatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+ class ReverseInnerIterator: public SparseMatrixType::ReverseInnerIterator
+ {
+ public:
+ inline ReverseInnerIterator(const BlockType& xpr, Index outer)
+ : SparseMatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer)
+ {}
+ inline Index row() const { return IsRowMajor ? m_outer : this->index(); }
+ inline Index col() const { return IsRowMajor ? this->index() : m_outer; }
+ protected:
+ Index m_outer;
+ };
+
+ inline BlockImpl(const SparseMatrixType& xpr, int i)
+ : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize)
+ {}
+
+ inline BlockImpl(const SparseMatrixType& xpr, int startRow, int startCol, int blockRows, int blockCols)
+ : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols)
+ {}
+
+ inline const Scalar* valuePtr() const
+ { return m_matrix.valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; }
+
+ inline const Index* innerIndexPtr() const
+ { return m_matrix.innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; }
+
+ inline const Index* outerIndexPtr() const
+ { return m_matrix.outerIndexPtr() + m_outerStart; }
+
+ Index nonZeros() const
+ {
+ if(m_matrix.isCompressed())
+ return std::size_t(m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()])
+ - std::size_t(m_matrix.outerIndexPtr()[m_outerStart]);
+ else if(m_outerSize.value()==0)
+ return 0;
+ else
+ return Map<const Matrix<Index,OuterSize,1> >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum();
+ }
+
+ inline const Scalar coeff(int row, int col) const
+ {
+ return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart));
+ }
+
+ inline const Scalar coeff(int index) const
+ {
+ return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart);
+ }
const Scalar& lastCoeff() const
{
@@ -265,7 +390,8 @@ const typename SparseMatrixBase<Derived>::ConstInnerVectorReturnType SparseMatri
* is col-major (resp. row-major).
*/
template<typename Derived>
-Block<Derived,Dynamic,Dynamic,true> SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize)
+typename SparseMatrixBase<Derived>::InnerVectorsReturnType
+SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize)
{
return Block<Derived,Dynamic,Dynamic,true>(derived(),
IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart,
@@ -277,7 +403,8 @@ Block<Derived,Dynamic,Dynamic,true> SparseMatrixBase<Derived>::innerVectors(Inde
* is col-major (resp. row-major). Read-only.
*/
template<typename Derived>
-const Block<const Derived,Dynamic,Dynamic,true> SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) const
+const typename SparseMatrixBase<Derived>::ConstInnerVectorsReturnType
+SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) const
{
return Block<const Derived,Dynamic,Dynamic,true>(derived(),
IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart,
@@ -304,8 +431,8 @@ public:
: m_matrix(xpr),
m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0),
m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0),
- m_blockRows(xpr.rows()),
- m_blockCols(xpr.cols())
+ m_blockRows(BlockRows==1 ? 1 : xpr.rows()),
+ m_blockCols(BlockCols==1 ? 1 : xpr.cols())
{}
/** Dynamic-size constructor
@@ -407,3 +534,4 @@ public:
} // end namespace Eigen
#endif // EIGEN_SPARSE_BLOCK_H
+
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
index ec86ca933c2..4ca9128337f 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h
@@ -73,7 +73,8 @@ class CwiseBinaryOpImpl<BinaryOp,Lhs,Rhs,Sparse>::InnerIterator
typedef internal::sparse_cwise_binary_op_inner_iterator_selector<
BinaryOp,Lhs,Rhs, InnerIterator> Base;
- EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, Index outer)
+ // NOTE: we have to prefix Index by "typename Lhs::" to avoid an ICE with VC11
+ EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename Lhs::Index outer)
: Base(binOp.derived(),outer)
{}
};
@@ -313,10 +314,10 @@ SparseMatrixBase<Derived>::operator+=(const SparseMatrixBase<OtherDerived>& othe
template<typename Derived>
template<typename OtherDerived>
-EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE
+EIGEN_STRONG_INLINE const typename SparseMatrixBase<Derived>::template CwiseProductDenseReturnType<OtherDerived>::Type
SparseMatrixBase<Derived>::cwiseProduct(const MatrixBase<OtherDerived> &other) const
{
- return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived());
+ return typename CwiseProductDenseReturnType<OtherDerived>::Type(derived(), other.derived());
}
} // end namespace Eigen
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h b/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h
index 54fd633a10c..ccb6ae7b788 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h
@@ -19,7 +19,10 @@ template<typename Lhs, typename Rhs, int InnerSize> struct SparseDenseProductRet
template<typename Lhs, typename Rhs> struct SparseDenseProductReturnType<Lhs,Rhs,1>
{
- typedef SparseDenseOuterProduct<Lhs,Rhs,false> Type;
+ typedef typename internal::conditional<
+ Lhs::IsRowMajor,
+ SparseDenseOuterProduct<Rhs,Lhs,true>,
+ SparseDenseOuterProduct<Lhs,Rhs,false> >::type Type;
};
template<typename Lhs, typename Rhs, int InnerSize> struct DenseSparseProductReturnType
@@ -29,7 +32,10 @@ template<typename Lhs, typename Rhs, int InnerSize> struct DenseSparseProductRet
template<typename Lhs, typename Rhs> struct DenseSparseProductReturnType<Lhs,Rhs,1>
{
- typedef SparseDenseOuterProduct<Rhs,Lhs,true> Type;
+ typedef typename internal::conditional<
+ Rhs::IsRowMajor,
+ SparseDenseOuterProduct<Rhs,Lhs,true>,
+ SparseDenseOuterProduct<Lhs,Rhs,false> >::type Type;
};
namespace internal {
@@ -114,17 +120,30 @@ class SparseDenseOuterProduct<Lhs,Rhs,Transpose>::InnerIterator : public _LhsNes
typedef typename SparseDenseOuterProduct::Index Index;
public:
EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer)
- : Base(prod.lhs(), 0), m_outer(outer), m_factor(prod.rhs().coeff(outer))
- {
- }
+ : Base(prod.lhs(), 0), m_outer(outer), m_factor(get(prod.rhs(), outer, typename internal::traits<Rhs>::StorageKind() ))
+ { }
inline Index outer() const { return m_outer; }
- inline Index row() const { return Transpose ? Base::row() : m_outer; }
- inline Index col() const { return Transpose ? m_outer : Base::row(); }
+ inline Index row() const { return Transpose ? m_outer : Base::index(); }
+ inline Index col() const { return Transpose ? Base::index() : m_outer; }
inline Scalar value() const { return Base::value() * m_factor; }
protected:
+ static Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense())
+ {
+ return rhs.coeff(outer);
+ }
+
+ static Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse())
+ {
+ typename Traits::_RhsNested::InnerIterator it(rhs, outer);
+ if (it && it.index()==0)
+ return it.value();
+
+ return Scalar(0);
+ }
+
Index m_outer;
Scalar m_factor;
};
@@ -161,7 +180,7 @@ struct sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType, R
typename Res::Scalar tmp(0);
for(LhsInnerIterator it(lhs,j); it ;++it)
tmp += it.value() * rhs.coeff(it.index(),c);
- res.coeffRef(j,c) = alpha * tmp;
+ res.coeffRef(j,c) += alpha * tmp;
}
}
}
@@ -287,15 +306,6 @@ class DenseTimeSparseProduct
DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&);
};
-// sparse * dense
-template<typename Derived>
-template<typename OtherDerived>
-inline const typename SparseDenseProductReturnType<Derived,OtherDerived>::Type
-SparseMatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const
-{
- return typename SparseDenseProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived());
-}
-
} // end namespace Eigen
#endif // EIGEN_SPARSEDENSEPRODUCT_H
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h
index 01ce0dcfee3..2ff2015512f 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h
@@ -691,7 +691,8 @@ class SparseMatrix
m_data.swap(other.m_data);
}
- /** Sets *this to the identity matrix */
+ /** Sets *this to the identity matrix.
+ * This function also turns the matrix into compressed mode, and drop any reserved memory. */
inline void setIdentity()
{
eigen_assert(rows() == cols() && "ONLY FOR SQUARED MATRICES");
@@ -699,6 +700,8 @@ class SparseMatrix
Eigen::Map<Matrix<Index, Dynamic, 1> >(&this->m_data.index(0), rows()).setLinSpaced(0, rows()-1);
Eigen::Map<Matrix<Scalar, Dynamic, 1> >(&this->m_data.value(0), rows()).setOnes();
Eigen::Map<Matrix<Index, Dynamic, 1> >(this->m_outerIndex, rows()+1).setLinSpaced(0, rows());
+ std::free(m_innerNonZeros);
+ m_innerNonZeros = 0;
}
inline SparseMatrix& operator=(const SparseMatrix& other)
{
@@ -940,7 +943,7 @@ void set_from_triplets(const InputIterator& begin, const InputIterator& end, Spa
enum { IsRowMajor = SparseMatrixType::IsRowMajor };
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::Index Index;
- SparseMatrix<Scalar,IsRowMajor?ColMajor:RowMajor> trMat(mat.rows(),mat.cols());
+ SparseMatrix<Scalar,IsRowMajor?ColMajor:RowMajor,Index> trMat(mat.rows(),mat.cols());
if(begin!=end)
{
@@ -1178,7 +1181,7 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse
size_t p = m_outerIndex[outer+1];
++m_outerIndex[outer+1];
- float reallocRatio = 1;
+ double reallocRatio = 1;
if (m_data.allocatedSize()<=m_data.size())
{
// if there is no preallocated memory, let's reserve a minimum of 32 elements
@@ -1190,13 +1193,13 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse
{
// we need to reallocate the data, to reduce multiple reallocations
// we use a smart resize algorithm based on the current filling ratio
- // in addition, we use float to avoid integers overflows
- float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1);
- reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size());
+ // in addition, we use double to avoid integers overflows
+ double nnzEstimate = double(m_outerIndex[outer])*double(m_outerSize)/double(outer+1);
+ reallocRatio = (nnzEstimate-double(m_data.size()))/double(m_data.size());
// furthermore we bound the realloc ratio to:
// 1) reduce multiple minor realloc when the matrix is almost filled
// 2) avoid to allocate too much memory when the matrix is almost empty
- reallocRatio = (std::min)((std::max)(reallocRatio,1.5f),8.f);
+ reallocRatio = (std::min)((std::max)(reallocRatio,1.5),8.);
}
}
m_data.resize(m_data.size()+1,reallocRatio);
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h
index bbcf7fb1c62..9341d9ad2c0 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h
@@ -23,7 +23,14 @@ namespace Eigen {
* This class can be extended with the help of the plugin mechanism described on the page
* \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN.
*/
-template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
+template<typename Derived> class SparseMatrixBase
+#ifndef EIGEN_PARSED_BY_DOXYGEN
+ : public internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar,
+ typename NumTraits<typename internal::traits<Derived>::Scalar>::Real,
+ EigenBase<Derived> >
+#else
+ : public EigenBase<Derived>
+#endif // not EIGEN_PARSED_BY_DOXYGEN
{
public:
@@ -36,7 +43,6 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
>::type PacketReturnType;
typedef SparseMatrixBase StorageBaseType;
- typedef EigenBase<Derived> Base;
template<typename OtherDerived>
Derived& operator=(const EigenBase<OtherDerived> &other)
@@ -132,6 +138,9 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
inline Derived& derived() { return *static_cast<Derived*>(this); }
inline Derived& const_cast_derived() const
{ return *static_cast<Derived*>(const_cast<SparseMatrixBase*>(this)); }
+
+ typedef internal::special_scalar_op_base<Derived, Scalar, RealScalar, EigenBase<Derived> > Base;
+ using Base::operator*;
#endif // not EIGEN_PARSED_BY_DOXYGEN
#define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase
@@ -317,20 +326,18 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
Derived& operator*=(const Scalar& other);
Derived& operator/=(const Scalar& other);
- #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \
- CwiseBinaryOp< \
- internal::scalar_product_op< \
- typename internal::scalar_product_traits< \
- typename internal::traits<Derived>::Scalar, \
- typename internal::traits<OtherDerived>::Scalar \
- >::ReturnType \
- >, \
- const Derived, \
- const OtherDerived \
- >
+ template<typename OtherDerived> struct CwiseProductDenseReturnType {
+ typedef CwiseBinaryOp<internal::scalar_product_op<typename internal::scalar_product_traits<
+ typename internal::traits<Derived>::Scalar,
+ typename internal::traits<OtherDerived>::Scalar
+ >::ReturnType>,
+ const Derived,
+ const OtherDerived
+ > Type;
+ };
template<typename OtherDerived>
- EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE
+ EIGEN_STRONG_INLINE const typename CwiseProductDenseReturnType<OtherDerived>::Type
cwiseProduct(const MatrixBase<OtherDerived> &other) const;
// sparse * sparse
@@ -358,7 +365,8 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
/** sparse * dense (returns a dense object unless it is an outer product) */
template<typename OtherDerived>
const typename SparseDenseProductReturnType<Derived,OtherDerived>::Type
- operator*(const MatrixBase<OtherDerived> &other) const;
+ operator*(const MatrixBase<OtherDerived> &other) const
+ { return typename SparseDenseProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived()); }
/** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */
SparseSymmetricPermutationProduct<Derived,Upper|Lower> twistedBy(const PermutationMatrix<Dynamic,Dynamic,Index>& perm) const
@@ -403,8 +411,10 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived>
const ConstInnerVectorReturnType innerVector(Index outer) const;
// set of inner-vectors
- Block<Derived,Dynamic,Dynamic,true> innerVectors(Index outerStart, Index outerSize);
- const Block<const Derived,Dynamic,Dynamic,true> innerVectors(Index outerStart, Index outerSize) const;
+ typedef Block<Derived,Dynamic,Dynamic,true> InnerVectorsReturnType;
+ typedef Block<const Derived,Dynamic,Dynamic,true> ConstInnerVectorsReturnType;
+ InnerVectorsReturnType innerVectors(Index outerStart, Index outerSize);
+ const ConstInnerVectorsReturnType innerVectors(Index outerStart, Index outerSize) const;
/** \internal use operator= */
template<typename DenseDerived>
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h b/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h
index b85be93f6f9..75e21000959 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h
@@ -61,7 +61,7 @@ struct permut_sparsematrix_product_retval
for(Index j=0; j<m_matrix.outerSize(); ++j)
{
Index jp = m_permutation.indices().coeff(j);
- sizes[((Side==OnTheLeft) ^ Transposed) ? jp : j] = m_matrix.innerVector(((Side==OnTheRight) ^ Transposed) ? jp : j).size();
+ sizes[((Side==OnTheLeft) ^ Transposed) ? jp : j] = m_matrix.innerVector(((Side==OnTheRight) ^ Transposed) ? jp : j).nonZeros();
}
tmp.reserve(sizes);
for(Index j=0; j<m_matrix.outerSize(); ++j)
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h b/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h
index 7c300ee8dbc..76d031d52c8 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h
@@ -26,7 +26,7 @@ template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>
inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); }
};
-// NOTE: VC10 trigger an ICE if don't put typename TransposeImpl<MatrixType,Sparse>:: in front of Index,
+// NOTE: VC10 and VC11 trigger an ICE if don't put typename TransposeImpl<MatrixType,Sparse>:: in front of Index,
// a typedef typename TransposeImpl<MatrixType,Sparse>::Index Index;
// does not fix the issue.
// An alternative is to define the nested class in the parent class itself.
@@ -40,8 +40,8 @@ template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::InnerItera
EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl<MatrixType,Sparse>::Index outer)
: Base(trans.derived().nestedExpression(), outer)
{}
- Index row() const { return Base::col(); }
- Index col() const { return Base::row(); }
+ typename TransposeImpl<MatrixType,Sparse>::Index row() const { return Base::col(); }
+ typename TransposeImpl<MatrixType,Sparse>::Index col() const { return Base::row(); }
};
template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::ReverseInnerIterator
@@ -54,8 +54,8 @@ template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::ReverseInn
EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl<MatrixType,Sparse>::Index outer)
: Base(xpr.derived().nestedExpression(), outer)
{}
- Index row() const { return Base::col(); }
- Index col() const { return Base::row(); }
+ typename TransposeImpl<MatrixType,Sparse>::Index row() const { return Base::col(); }
+ typename TransposeImpl<MatrixType,Sparse>::Index col() const { return Base::row(); }
};
} // end namespace Eigen
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h b/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h
index 05023858b16..d627546def0 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h
@@ -67,7 +67,6 @@ const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern;
const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern;
const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern;
-template<typename Derived> class SparseMatrixBase;
template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseMatrix;
template<typename _Scalar, int _Flags = 0, typename _Index = int> class DynamicSparseMatrix;
template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseVector;
@@ -84,8 +83,10 @@ template<typename Lhs, typename Rhs> class DenseTimeSparseProduct;
template<typename Lhs, typename Rhs, bool Transpose> class SparseDenseOuterProduct;
template<typename Lhs, typename Rhs> struct SparseSparseProductReturnType;
-template<typename Lhs, typename Rhs, int InnerSize = internal::traits<Lhs>::ColsAtCompileTime> struct DenseSparseProductReturnType;
-template<typename Lhs, typename Rhs, int InnerSize = internal::traits<Lhs>::ColsAtCompileTime> struct SparseDenseProductReturnType;
+template<typename Lhs, typename Rhs,
+ int InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(internal::traits<Lhs>::ColsAtCompileTime,internal::traits<Rhs>::RowsAtCompileTime)> struct DenseSparseProductReturnType;
+template<typename Lhs, typename Rhs,
+ int InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(internal::traits<Lhs>::ColsAtCompileTime,internal::traits<Rhs>::RowsAtCompileTime)> struct SparseDenseProductReturnType;
template<typename MatrixType,int UpLo> class SparseSymmetricPermutationProduct;
namespace internal {
diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h b/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h
index 7e15c814b6f..49865d0e72f 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h
@@ -158,6 +158,7 @@ class SparseVector
Index inner = IsColVector ? row : col;
Index outer = IsColVector ? col : row;
+ EIGEN_ONLY_USED_FOR_DEBUG(outer);
eigen_assert(outer==0);
return insert(inner);
}
diff --git a/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h b/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h
index cb8ad82b4f6..ccc12af7962 100644
--- a/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h
+++ b/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h
@@ -69,7 +69,7 @@ struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Upper,RowMajor>
for(int i=lhs.rows()-1 ; i>=0 ; --i)
{
Scalar tmp = other.coeff(i,col);
- Scalar l_ii = 0;
+ Scalar l_ii(0);
typename Lhs::InnerIterator it(lhs, i);
while(it && it.index()<i)
++it;
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h
index 1d592f2c8c7..bdc4f193ddb 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h
@@ -260,16 +260,16 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ
eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
// Initialize with the determinant of the row matrix
Scalar det = Scalar(1.);
- //Note that the diagonal blocks of U are stored in supernodes,
+ // Note that the diagonal blocks of U are stored in supernodes,
// which are available in the L part :)
for (Index j = 0; j < this->cols(); ++j)
{
for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
{
- if(it.row() < j) continue;
- if(it.row() == j)
+ if(it.index() == j)
{
- det *= (std::abs)(it.value());
+ using std::abs;
+ det *= abs(it.value());
break;
}
}
@@ -296,7 +296,8 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ
if(it.row() < j) continue;
if(it.row() == j)
{
- det += (std::log)((std::abs)(it.value()));
+ using std::log; using std::abs;
+ det += log(abs(it.value()));
break;
}
}
@@ -304,21 +305,64 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ
return det;
}
- /** \returns A number representing the sign of the determinant
- *
- * \sa absDeterminant(), logAbsDeterminant()
- */
- Scalar signDeterminant()
- {
- eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
- return Scalar(m_detPermR);
- }
+ /** \returns A number representing the sign of the determinant
+ *
+ * \sa absDeterminant(), logAbsDeterminant()
+ */
+ Scalar signDeterminant()
+ {
+ eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
+ // Initialize with the determinant of the row matrix
+ Index det = 1;
+ // Note that the diagonal blocks of U are stored in supernodes,
+ // which are available in the L part :)
+ for (Index j = 0; j < this->cols(); ++j)
+ {
+ for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
+ {
+ if(it.index() == j)
+ {
+ if(it.value()<0)
+ det = -det;
+ else if(it.value()==0)
+ return 0;
+ break;
+ }
+ }
+ }
+ return det * m_detPermR * m_detPermC;
+ }
+
+ /** \returns The determinant of the matrix.
+ *
+ * \sa absDeterminant(), logAbsDeterminant()
+ */
+ Scalar determinant()
+ {
+ eigen_assert(m_factorizationIsOk && "The matrix should be factorized first.");
+ // Initialize with the determinant of the row matrix
+ Scalar det = Scalar(1.);
+ // Note that the diagonal blocks of U are stored in supernodes,
+ // which are available in the L part :)
+ for (Index j = 0; j < this->cols(); ++j)
+ {
+ for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it)
+ {
+ if(it.index() == j)
+ {
+ det *= it.value();
+ break;
+ }
+ }
+ }
+ return det * Scalar(m_detPermR * m_detPermC);
+ }
protected:
// Functions
void initperfvalues()
{
- m_perfv.panel_size = 1;
+ m_perfv.panel_size = 16;
m_perfv.relax = 1;
m_perfv.maxsuper = 128;
m_perfv.rowblk = 16;
@@ -346,8 +390,8 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ
// values for performance
internal::perfvalues<Index> m_perfv;
RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot
- Index m_nnzL, m_nnzU; // Nonzeros in L and U factors
- Index m_detPermR; // Determinant of the coefficient matrix
+ Index m_nnzL, m_nnzU; // Nonzeros in L and U factors
+ Index m_detPermR, m_detPermC; // Determinants of the permutation matrices
private:
// Disable copy constructor
SparseLU (const SparseLU& );
@@ -623,7 +667,8 @@ void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix)
}
// Update the determinant of the row permutation matrix
- if (pivrow != jj) m_detPermR *= -1;
+ // FIXME: the following test is not correct, we should probably take iperm_c into account and pivrow is not directly the row pivot.
+ if (pivrow != jj) m_detPermR = -m_detPermR;
// Prune columns (0:jj-1) using column jj
Base::pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu);
@@ -638,10 +683,13 @@ void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix)
jcol += panel_size; // Move to the next panel
} // end for -- end elimination
+ m_detPermR = m_perm_r.determinant();
+ m_detPermC = m_perm_c.determinant();
+
// Count the number of nonzeros in factors
Base::countnz(n, m_nnzL, m_nnzU, m_glu);
// Apply permutation to the L subscripts
- Base::fixupL(n, m_perm_r.indices(), m_glu);
+ Base::fixupL(n, m_perm_r.indices(), m_glu);
// Create supernode matrix L
m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup);
@@ -701,8 +749,8 @@ struct SparseLUMatrixUReturnType : internal::no_assignment_operator
}
else
{
- Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(m_mapL.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(lda) );
- Map< Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
+ Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(m_mapL.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(lda) );
+ Map< Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
U = A.template triangularView<Upper>().solve(U);
}
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h
index 14d70897df7..99d651e40d3 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h
@@ -21,6 +21,8 @@ class SparseLUImpl
{
public:
typedef Matrix<Scalar,Dynamic,1> ScalarVector;
+ typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> ScalarMatrix;
+ typedef Map<ScalarMatrix, 0, OuterStride<> > MappedMatrixBlock;
typedef Matrix<Index,Dynamic,1> IndexVector;
typedef typename ScalarVector::RealScalar RealScalar;
typedef Ref<Matrix<Scalar,Dynamic,1> > BlockScalarVector;
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h
index 1ffa7d54e96..45f96d16a8e 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h
@@ -153,8 +153,8 @@ Index SparseLUImpl<Scalar,Index>::memInit(Index m, Index n, Index annz, Index lw
{
Index& num_expansions = glu.num_expansions; //No memory expansions so far
num_expansions = 0;
- glu.nzumax = glu.nzlumax = (std::min)(fillratio * annz / n, m) * n; // estimated number of nonzeros in U
- glu.nzlmax = (std::max)(Index(4), fillratio) * annz / 4; // estimated nnz in L factor
+ glu.nzumax = glu.nzlumax = (std::min)(fillratio * (annz+1) / n, m) * n; // estimated number of nonzeros in U
+ glu.nzlmax = (std::max)(Index(4), fillratio) * (annz+1) / 4; // estimated nnz in L factor
// Return the estimated size to the user if necessary
Index tempSpace;
tempSpace = (2*panel_size + 4 + LUNoMarker) * m * sizeof(Index) + (panel_size + 1) * m * sizeof(Scalar);
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h
index ad6f2183fed..54a56940861 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h
@@ -189,8 +189,8 @@ class MappedSuperNodalMatrix<Scalar,Index>::InnerIterator
m_idval(mat.colIndexPtr()[outer]),
m_startidval(m_idval),
m_endidval(mat.colIndexPtr()[outer+1]),
- m_idrow(mat.rowIndexPtr()[outer]),
- m_endidrow(mat.rowIndexPtr()[outer+1])
+ m_idrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]]),
+ m_endidrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]+1])
{}
inline InnerIterator& operator++()
{
@@ -236,7 +236,7 @@ void MappedSuperNodalMatrix<Scalar,Index>::solveInPlace( MatrixBase<Dest>&X) con
Index n = X.rows();
Index nrhs = X.cols();
const Scalar * Lval = valuePtr(); // Nonzero values
- Matrix<Scalar,Dynamic,Dynamic> work(n, nrhs); // working vector
+ Matrix<Scalar,Dynamic,Dynamic, ColMajor> work(n, nrhs); // working vector
work.setZero();
for (Index k = 0; k <= nsuper(); k ++)
{
@@ -267,12 +267,12 @@ void MappedSuperNodalMatrix<Scalar,Index>::solveInPlace( MatrixBase<Dest>&X) con
Index lda = colIndexPtr()[fsupc+1] - luptr;
// Triangular solve
- Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(Lval[luptr]), nsupc, nsupc, OuterStride<>(lda) );
- Map< Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
+ Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(Lval[luptr]), nsupc, nsupc, OuterStride<>(lda) );
+ Map< Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) );
U = A.template triangularView<UnitLower>().solve(U);
// Matrix-vector product
- new (&A) Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > ( &(Lval[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) );
+ new (&A) Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > ( &(Lval[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) );
work.block(0, 0, nrow, nrhs) = A * U;
//Begin Scatter
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h
index f24bd87d3e9..cacc7e98712 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h
@@ -162,11 +162,11 @@ Index SparseLUImpl<Scalar,Index>::column_bmod(const Index jcol, const Index nseg
// points to the beginning of jcol in snode L\U(jsupno)
ufirst = glu.xlusup(jcol) + d_fsupc;
Index lda = glu.xlusup(jcol+1) - glu.xlusup(jcol);
- Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(lda) );
+ MappedMatrixBlock A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(lda) );
VectorBlock<ScalarVector> u(glu.lusup, ufirst, nsupc);
u = A.template triangularView<UnitLower>().solve(u);
- new (&A) Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) );
+ new (&A) MappedMatrixBlock ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) );
VectorBlock<ScalarVector> l(glu.lusup, ufirst+nsupc, nrow);
l.noalias() -= A * u;
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h
index 0d0283b132b..6af02675429 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h
@@ -56,7 +56,7 @@ EIGEN_DONT_INLINE void LU_kernel_bmod<SegSizeAtCompileTime>::run(const int segsi
// Dense triangular solve -- start effective triangle
luptr += lda * no_zeros + no_zeros;
// Form Eigen matrix and vector
- Map<Matrix<Scalar,SegSizeAtCompileTime,SegSizeAtCompileTime>, 0, OuterStride<> > A( &(lusup.data()[luptr]), segsize, segsize, OuterStride<>(lda) );
+ Map<Matrix<Scalar,SegSizeAtCompileTime,SegSizeAtCompileTime, ColMajor>, 0, OuterStride<> > A( &(lusup.data()[luptr]), segsize, segsize, OuterStride<>(lda) );
Map<Matrix<Scalar,SegSizeAtCompileTime,1> > u(tempv.data(), segsize);
u = A.template triangularView<UnitLower>().solve(u);
@@ -65,7 +65,7 @@ EIGEN_DONT_INLINE void LU_kernel_bmod<SegSizeAtCompileTime>::run(const int segsi
luptr += segsize;
const Index PacketSize = internal::packet_traits<Scalar>::size;
Index ldl = internal::first_multiple(nrow, PacketSize);
- Map<Matrix<Scalar,Dynamic,SegSizeAtCompileTime>, 0, OuterStride<> > B( &(lusup.data()[luptr]), nrow, segsize, OuterStride<>(lda) );
+ Map<Matrix<Scalar,Dynamic,SegSizeAtCompileTime, ColMajor>, 0, OuterStride<> > B( &(lusup.data()[luptr]), nrow, segsize, OuterStride<>(lda) );
Index aligned_offset = internal::first_aligned(tempv.data()+segsize, PacketSize);
Index aligned_with_B_offset = (PacketSize-internal::first_aligned(B.data(), PacketSize))%PacketSize;
Map<Matrix<Scalar,Dynamic,1>, 0, OuterStride<> > l(tempv.data()+segsize+aligned_offset+aligned_with_B_offset, nrow, OuterStride<>(ldl) );
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h
index da0e0fc3c60..9d2ff290635 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h
@@ -102,7 +102,7 @@ void SparseLUImpl<Scalar,Index>::panel_bmod(const Index m, const Index w, const
if(nsupc >= 2)
{
Index ldu = internal::first_multiple<Index>(u_rows, PacketSize);
- Map<Matrix<Scalar,Dynamic,Dynamic>, Aligned, OuterStride<> > U(tempv.data(), u_rows, u_cols, OuterStride<>(ldu));
+ Map<ScalarMatrix, Aligned, OuterStride<> > U(tempv.data(), u_rows, u_cols, OuterStride<>(ldu));
// gather U
Index u_col = 0;
@@ -136,17 +136,17 @@ void SparseLUImpl<Scalar,Index>::panel_bmod(const Index m, const Index w, const
Index lda = glu.xlusup(fsupc+1) - glu.xlusup(fsupc);
no_zeros = (krep - u_rows + 1) - fsupc;
luptr += lda * no_zeros + no_zeros;
- Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A(glu.lusup.data()+luptr, u_rows, u_rows, OuterStride<>(lda) );
+ MappedMatrixBlock A(glu.lusup.data()+luptr, u_rows, u_rows, OuterStride<>(lda) );
U = A.template triangularView<UnitLower>().solve(U);
// update
luptr += u_rows;
- Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > B(glu.lusup.data()+luptr, nrow, u_rows, OuterStride<>(lda) );
+ MappedMatrixBlock B(glu.lusup.data()+luptr, nrow, u_rows, OuterStride<>(lda) );
eigen_assert(tempv.size()>w*ldu + nrow*w + 1);
Index ldl = internal::first_multiple<Index>(nrow, PacketSize);
Index offset = (PacketSize-internal::first_aligned(B.data(), PacketSize)) % PacketSize;
- Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl));
+ MappedMatrixBlock L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl));
L.setZero();
internal::sparselu_gemm<Scalar>(L.rows(), L.cols(), B.cols(), B.data(), B.outerStride(), U.data(), U.outerStride(), L.data(), L.outerStride());
diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h
index ddcd4ec98f8..2e49ef667f4 100644
--- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h
+++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h
@@ -71,13 +71,14 @@ Index SparseLUImpl<Scalar,Index>::pivotL(const Index jcol, const RealScalar& dia
// Determine the largest abs numerical value for partial pivoting
Index diagind = iperm_c(jcol); // diagonal index
- RealScalar pivmax = 0.0;
+ RealScalar pivmax(-1.0);
Index pivptr = nsupc;
Index diag = emptyIdxLU;
RealScalar rtemp;
Index isub, icol, itemp, k;
for (isub = nsupc; isub < nsupr; ++isub) {
- rtemp = std::abs(lu_col_ptr[isub]);
+ using std::abs;
+ rtemp = abs(lu_col_ptr[isub]);
if (rtemp > pivmax) {
pivmax = rtemp;
pivptr = isub;
@@ -86,8 +87,9 @@ Index SparseLUImpl<Scalar,Index>::pivotL(const Index jcol, const RealScalar& dia
}
// Test for singularity
- if ( pivmax == 0.0 ) {
- pivrow = lsub_ptr[pivptr];
+ if ( pivmax <= RealScalar(0.0) ) {
+ // if pivmax == -1, the column is structurally empty, otherwise it is only numerically zero
+ pivrow = pivmax < RealScalar(0.0) ? diagind : lsub_ptr[pivptr];
perm_r(pivrow) = jcol;
return (jcol+1);
}
@@ -101,7 +103,8 @@ Index SparseLUImpl<Scalar,Index>::pivotL(const Index jcol, const RealScalar& dia
if (diag >= 0 )
{
// Diagonal element exists
- rtemp = std::abs(lu_col_ptr[diag]);
+ using std::abs;
+ rtemp = abs(lu_col_ptr[diag]);
if (rtemp != 0.0 && rtemp >= thresh) pivptr = diag;
}
pivrow = lsub_ptr[pivptr];
diff --git a/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h b/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h
index afda43bfc67..a00bd5db124 100644
--- a/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h
+++ b/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h
@@ -2,7 +2,7 @@
// for linear algebra.
//
// Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
-// Copyright (C) 2012-2013 Gael Guennebaud <gael.guennebaud@inria.fr>
+// Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
@@ -58,6 +58,7 @@ namespace internal {
* \tparam _OrderingType The fill-reducing ordering method. See the \link OrderingMethods_Module
* OrderingMethods \endlink module for the list of built-in and external ordering methods.
*
+ * \warning The input sparse matrix A must be in compressed mode (see SparseMatrix::makeCompressed()).
*
*/
template<typename _MatrixType, typename _OrderingType>
@@ -74,13 +75,26 @@ class SparseQR
typedef Matrix<Scalar, Dynamic, 1> ScalarVector;
typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType;
public:
- SparseQR () : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false)
+ SparseQR () : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
{ }
- SparseQR(const MatrixType& mat) : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false)
+ /** Construct a QR factorization of the matrix \a mat.
+ *
+ * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
+ *
+ * \sa compute()
+ */
+ SparseQR(const MatrixType& mat) : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false)
{
compute(mat);
}
+
+ /** Computes the QR factorization of the sparse matrix \a mat.
+ *
+ * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
+ *
+ * \sa analyzePattern(), factorize()
+ */
void compute(const MatrixType& mat)
{
analyzePattern(mat);
@@ -166,7 +180,7 @@ class SparseQR
y.bottomRows(y.rows()-rank).setZero();
// Apply the column permutation
- if (m_perm_c.size()) dest.topRows(cols()) = colsPermutation() * y.topRows(cols());
+ if (m_perm_c.size()) dest = colsPermutation() * y.topRows(cols());
else dest = y.topRows(cols());
m_info = Success;
@@ -206,7 +220,7 @@ class SparseQR
/** \brief Reports whether previous computation was successful.
*
- * \returns \c Success if computation was succesful,
+ * \returns \c Success if computation was successful,
* \c NumericalIssue if the QR factorization reports a numerical problem
* \c InvalidInput if the input matrix is invalid
*
@@ -248,6 +262,7 @@ class SparseQR
IndexVector m_etree; // Column elimination tree
IndexVector m_firstRowElt; // First element in each row
bool m_isQSorted; // whether Q is sorted or not
+ bool m_isEtreeOk; // whether the elimination tree match the initial input matrix
template <typename, typename > friend struct SparseQR_QProduct;
template <typename > friend struct SparseQRMatrixQReturnType;
@@ -256,19 +271,25 @@ class SparseQR
/** \brief Preprocessing step of a QR factorization
*
+ * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()).
+ *
* In this step, the fill-reducing permutation is computed and applied to the columns of A
- * and the column elimination tree is computed as well. Only the sparcity pattern of \a mat is exploited.
+ * and the column elimination tree is computed as well. Only the sparsity pattern of \a mat is exploited.
*
* \note In this step it is assumed that there is no empty row in the matrix \a mat.
*/
template <typename MatrixType, typename OrderingType>
void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
{
+ eigen_assert(mat.isCompressed() && "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR");
+ // Copy to a column major matrix if the input is rowmajor
+ typename internal::conditional<MatrixType::IsRowMajor,QRMatrixType,const MatrixType&>::type matCpy(mat);
// Compute the column fill reducing ordering
OrderingType ord;
- ord(mat, m_perm_c);
+ ord(matCpy, m_perm_c);
Index n = mat.cols();
Index m = mat.rows();
+ Index diagSize = (std::min)(m,n);
if (!m_perm_c.size())
{
@@ -278,22 +299,23 @@ void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
// Compute the column elimination tree of the permuted matrix
m_outputPerm_c = m_perm_c.inverse();
- internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
+ internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
+ m_isEtreeOk = true;
- m_R.resize(n, n);
- m_Q.resize(m, n);
+ m_R.resize(m, n);
+ m_Q.resize(m, diagSize);
// Allocate space for nonzero elements : rough estimation
m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
m_Q.reserve(2*mat.nonZeros());
- m_hcoeffs.resize(n);
+ m_hcoeffs.resize(diagSize);
m_analysisIsok = true;
}
/** \brief Performs the numerical QR factorization of the input matrix
*
* The function SparseQR::analyzePattern(const MatrixType&) must have been called beforehand with
- * a matrix having the same sparcity pattern than \a mat.
+ * a matrix having the same sparsity pattern than \a mat.
*
* \param mat The sparse column-major matrix
*/
@@ -306,23 +328,47 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
Index m = mat.rows();
Index n = mat.cols();
- IndexVector mark(m); mark.setConstant(-1); // Record the visited nodes
- IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q
- Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q
- ScalarVector tval(m); // The dense vector used to compute the current column
- bool found_diag;
-
+ Index diagSize = (std::min)(m,n);
+ IndexVector mark((std::max)(m,n)); mark.setConstant(-1); // Record the visited nodes
+ IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q
+ Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q
+ ScalarVector tval(m); // The dense vector used to compute the current column
+ RealScalar pivotThreshold = m_threshold;
+
+ m_R.setZero();
+ m_Q.setZero();
m_pmat = mat;
+ if(!m_isEtreeOk)
+ {
+ m_outputPerm_c = m_perm_c.inverse();
+ internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
+ m_isEtreeOk = true;
+ }
+
m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
+
// Apply the fill-in reducing permutation lazily:
- for (int i = 0; i < n; i++)
{
- Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
- m_pmat.outerIndexPtr()[p] = mat.outerIndexPtr()[i];
- m_pmat.innerNonZeroPtr()[p] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i];
+ // If the input is row major, copy the original column indices,
+ // otherwise directly use the input matrix
+ //
+ IndexVector originalOuterIndicesCpy;
+ const Index *originalOuterIndices = mat.outerIndexPtr();
+ if(MatrixType::IsRowMajor)
+ {
+ originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1);
+ originalOuterIndices = originalOuterIndicesCpy.data();
+ }
+
+ for (int i = 0; i < n; i++)
+ {
+ Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i;
+ m_pmat.outerIndexPtr()[p] = originalOuterIndices[i];
+ m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i+1] - originalOuterIndices[i];
+ }
}
- /* Compute the default threshold, see :
+ /* Compute the default threshold as in MatLab, see:
* Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
* Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
*/
@@ -330,33 +376,35 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
{
RealScalar max2Norm = 0.0;
for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm());
- m_threshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
+ if(max2Norm==RealScalar(0))
+ max2Norm = RealScalar(1);
+ pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
}
// Initialize the numerical permutation
m_pivotperm.setIdentity(n);
Index nonzeroCol = 0; // Record the number of valid pivots
-
+ m_Q.startVec(0);
+
// Left looking rank-revealing QR factorization: compute a column of R and Q at a time
- for (Index col = 0; col < (std::min)(n,m); ++col)
+ for (Index col = 0; col < n; ++col)
{
mark.setConstant(-1);
m_R.startVec(col);
- m_Q.startVec(col);
mark(nonzeroCol) = col;
Qidx(0) = nonzeroCol;
nzcolR = 0; nzcolQ = 1;
- found_diag = col>=m;
+ bool found_diag = nonzeroCol>=m;
tval.setZero();
// Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
// all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k.
// Note: if the diagonal entry does not exist, then its contribution must be explicitly added,
// thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
- for (typename MatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
+ for (typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
{
- Index curIdx = nonzeroCol ;
+ Index curIdx = nonzeroCol;
if(itp) curIdx = itp.row();
if(curIdx == nonzeroCol) found_diag = true;
@@ -398,7 +446,7 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
// Browse all the indexes of R(:,col) in reverse order
for (Index i = nzcolR-1; i >= 0; i--)
{
- Index curIdx = m_pivotperm.indices()(Ridx(i));
+ Index curIdx = Ridx(i);
// Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
Scalar tdot(0);
@@ -427,33 +475,36 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
}
}
} // End update current column
-
- // Compute the Householder reflection that eliminate the current column
- // FIXME this step should call the Householder module.
- Scalar tau;
- RealScalar beta;
- Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
- // First, the squared norm of Q((col+1):m, col)
- RealScalar sqrNorm = 0.;
- for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
+ Scalar tau = 0;
+ RealScalar beta = 0;
- if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
- {
- tau = RealScalar(0);
- beta = numext::real(c0);
- tval(Qidx(0)) = 1;
- }
- else
+ if(nonzeroCol < diagSize)
{
- beta = std::sqrt(numext::abs2(c0) + sqrNorm);
- if(numext::real(c0) >= RealScalar(0))
- beta = -beta;
- tval(Qidx(0)) = 1;
- for (Index itq = 1; itq < nzcolQ; ++itq)
- tval(Qidx(itq)) /= (c0 - beta);
- tau = numext::conj((beta-c0) / beta);
-
+ // Compute the Householder reflection that eliminate the current column
+ // FIXME this step should call the Householder module.
+ Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
+
+ // First, the squared norm of Q((col+1):m, col)
+ RealScalar sqrNorm = 0.;
+ for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
+ if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
+ {
+ beta = numext::real(c0);
+ tval(Qidx(0)) = 1;
+ }
+ else
+ {
+ using std::sqrt;
+ beta = sqrt(numext::abs2(c0) + sqrNorm);
+ if(numext::real(c0) >= RealScalar(0))
+ beta = -beta;
+ tval(Qidx(0)) = 1;
+ for (Index itq = 1; itq < nzcolQ; ++itq)
+ tval(Qidx(itq)) /= (c0 - beta);
+ tau = numext::conj((beta-c0) / beta);
+
+ }
}
// Insert values in R
@@ -467,45 +518,49 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
}
}
- if(abs(beta) >= m_threshold)
+ if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold)
{
m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
- nonzeroCol++;
// The householder coefficient
- m_hcoeffs(col) = tau;
+ m_hcoeffs(nonzeroCol) = tau;
// Record the householder reflections
for (Index itq = 0; itq < nzcolQ; ++itq)
{
Index iQ = Qidx(itq);
- m_Q.insertBackByOuterInnerUnordered(col,iQ) = tval(iQ);
+ m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ);
tval(iQ) = Scalar(0.);
- }
+ }
+ nonzeroCol++;
+ if(nonzeroCol<diagSize)
+ m_Q.startVec(nonzeroCol);
}
else
{
// Zero pivot found: move implicitly this column to the end
- m_hcoeffs(col) = Scalar(0);
for (Index j = nonzeroCol; j < n-1; j++)
std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
// Recompute the column elimination tree
internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data());
+ m_isEtreeOk = false;
}
}
+ m_hcoeffs.tail(diagSize-nonzeroCol).setZero();
+
// Finalize the column pointers of the sparse matrices R and Q
m_Q.finalize();
m_Q.makeCompressed();
m_R.finalize();
m_R.makeCompressed();
m_isQSorted = false;
-
+
m_nonzeropivots = nonzeroCol;
if(nonzeroCol<n)
{
// Permute the triangular factor to put the 'dead' columns to the end
- MatrixType tempR(m_R);
+ QRMatrixType tempR(m_R);
m_R = tempR * m_pivotperm;
// Update the column permutation
@@ -561,14 +616,16 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
template<typename DesType>
void evalTo(DesType& res) const
{
+ Index m = m_qr.rows();
Index n = m_qr.cols();
+ Index diagSize = (std::min)(m,n);
res = m_other;
if (m_transpose)
{
eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
//Compute res = Q' * other column by column
for(Index j = 0; j < res.cols(); j++){
- for (Index k = 0; k < n; k++)
+ for (Index k = 0; k < diagSize; k++)
{
Scalar tau = Scalar(0);
tau = m_qr.m_Q.col(k).dot(res.col(j));
@@ -581,10 +638,10 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
else
{
eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
- // Compute res = Q' * other column by column
+ // Compute res = Q * other column by column
for(Index j = 0; j < res.cols(); j++)
{
- for (Index k = n-1; k >=0; k--)
+ for (Index k = diagSize-1; k >=0; k--)
{
Scalar tau = Scalar(0);
tau = m_qr.m_Q.col(k).dot(res.col(j));
@@ -618,7 +675,7 @@ struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<Sp
return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
}
inline Index rows() const { return m_qr.rows(); }
- inline Index cols() const { return m_qr.cols(); }
+ inline Index cols() const { return (std::min)(m_qr.rows(),m_qr.cols()); }
// To use for operations with the transpose of Q
SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
{
diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h b/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h
index 4ee8e5c10a5..aaf66330b17 100644
--- a/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h
+++ b/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h
@@ -11,7 +11,7 @@
#ifndef EIGEN_STDDEQUE_H
#define EIGEN_STDDEQUE_H
-#include "Eigen/src/StlSupport/details.h"
+#include "details.h"
// Define the explicit instantiation (e.g. necessary for the Intel compiler)
#if defined(__INTEL_COMPILER) || defined(__GNUC__)
diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdList.h b/extern/Eigen3/Eigen/src/StlSupport/StdList.h
index 627381ecec0..3c742430c12 100644
--- a/extern/Eigen3/Eigen/src/StlSupport/StdList.h
+++ b/extern/Eigen3/Eigen/src/StlSupport/StdList.h
@@ -10,7 +10,7 @@
#ifndef EIGEN_STDLIST_H
#define EIGEN_STDLIST_H
-#include "Eigen/src/StlSupport/details.h"
+#include "details.h"
// Define the explicit instantiation (e.g. necessary for the Intel compiler)
#if defined(__INTEL_COMPILER) || defined(__GNUC__)
diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h
index 40a9abefa82..611664a2e8a 100644
--- a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h
+++ b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h
@@ -11,7 +11,7 @@
#ifndef EIGEN_STDVECTOR_H
#define EIGEN_STDVECTOR_H
-#include "Eigen/src/StlSupport/details.h"
+#include "details.h"
/**
* This section contains a convenience MACRO which allows an easy specialization of
diff --git a/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h b/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h
index 3a48cecf769..29c60c37875 100644
--- a/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h
+++ b/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h
@@ -107,6 +107,16 @@ inline int umfpack_get_determinant(std::complex<double> *Mx, double *Ex, void *N
return umfpack_zi_get_determinant(&mx_real,0,Ex,NumericHandle,User_Info);
}
+namespace internal {
+ template<typename T> struct umfpack_helper_is_sparse_plain : false_type {};
+ template<typename Scalar, int Options, typename StorageIndex>
+ struct umfpack_helper_is_sparse_plain<SparseMatrix<Scalar,Options,StorageIndex> >
+ : true_type {};
+ template<typename Scalar, int Options, typename StorageIndex>
+ struct umfpack_helper_is_sparse_plain<MappedSparseMatrix<Scalar,Options,StorageIndex> >
+ : true_type {};
+}
+
/** \ingroup UmfPackSupport_Module
* \brief A sparse LU factorization and solver based on UmfPack
*
@@ -192,10 +202,14 @@ class UmfPackLU : internal::noncopyable
* Note that the matrix should be column-major, and in compressed format for best performance.
* \sa SparseMatrix::makeCompressed().
*/
- void compute(const MatrixType& matrix)
+ template<typename InputMatrixType>
+ void compute(const InputMatrixType& matrix)
{
- analyzePattern(matrix);
- factorize(matrix);
+ if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar());
+ if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar());
+ grapInput(matrix.derived());
+ analyzePattern_impl();
+ factorize_impl();
}
/** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
@@ -230,23 +244,15 @@ class UmfPackLU : internal::noncopyable
*
* \sa factorize(), compute()
*/
- void analyzePattern(const MatrixType& matrix)
+ template<typename InputMatrixType>
+ void analyzePattern(const InputMatrixType& matrix)
{
- if(m_symbolic)
- umfpack_free_symbolic(&m_symbolic,Scalar());
- if(m_numeric)
- umfpack_free_numeric(&m_numeric,Scalar());
+ if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar());
+ if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar());
- grapInput(matrix);
-
- int errorCode = 0;
- errorCode = umfpack_symbolic(matrix.rows(), matrix.cols(), m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
- &m_symbolic, 0, 0);
+ grapInput(matrix.derived());
- m_isInitialized = true;
- m_info = errorCode ? InvalidInput : Success;
- m_analysisIsOk = true;
- m_factorizationIsOk = false;
+ analyzePattern_impl();
}
/** Performs a numeric decomposition of \a matrix
@@ -255,20 +261,16 @@ class UmfPackLU : internal::noncopyable
*
* \sa analyzePattern(), compute()
*/
- void factorize(const MatrixType& matrix)
+ template<typename InputMatrixType>
+ void factorize(const InputMatrixType& matrix)
{
eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()");
if(m_numeric)
umfpack_free_numeric(&m_numeric,Scalar());
- grapInput(matrix);
-
- int errorCode;
- errorCode = umfpack_numeric(m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
- m_symbolic, &m_numeric, 0, 0);
-
- m_info = errorCode ? NumericalIssue : Success;
- m_factorizationIsOk = true;
+ grapInput(matrix.derived());
+
+ factorize_impl();
}
#ifndef EIGEN_PARSED_BY_DOXYGEN
@@ -283,19 +285,20 @@ class UmfPackLU : internal::noncopyable
protected:
-
void init()
{
- m_info = InvalidInput;
- m_isInitialized = false;
- m_numeric = 0;
- m_symbolic = 0;
- m_outerIndexPtr = 0;
- m_innerIndexPtr = 0;
- m_valuePtr = 0;
+ m_info = InvalidInput;
+ m_isInitialized = false;
+ m_numeric = 0;
+ m_symbolic = 0;
+ m_outerIndexPtr = 0;
+ m_innerIndexPtr = 0;
+ m_valuePtr = 0;
+ m_extractedDataAreDirty = true;
}
- void grapInput(const MatrixType& mat)
+ template<typename InputMatrixType>
+ void grapInput_impl(const InputMatrixType& mat, internal::true_type)
{
m_copyMatrix.resize(mat.rows(), mat.cols());
if( ((MatrixType::Flags&RowMajorBit)==RowMajorBit) || sizeof(typename MatrixType::Index)!=sizeof(int) || !mat.isCompressed() )
@@ -313,6 +316,45 @@ class UmfPackLU : internal::noncopyable
m_valuePtr = mat.valuePtr();
}
}
+
+ template<typename InputMatrixType>
+ void grapInput_impl(const InputMatrixType& mat, internal::false_type)
+ {
+ m_copyMatrix = mat;
+ m_outerIndexPtr = m_copyMatrix.outerIndexPtr();
+ m_innerIndexPtr = m_copyMatrix.innerIndexPtr();
+ m_valuePtr = m_copyMatrix.valuePtr();
+ }
+
+ template<typename InputMatrixType>
+ void grapInput(const InputMatrixType& mat)
+ {
+ grapInput_impl(mat, internal::umfpack_helper_is_sparse_plain<InputMatrixType>());
+ }
+
+ void analyzePattern_impl()
+ {
+ int errorCode = 0;
+ errorCode = umfpack_symbolic(m_copyMatrix.rows(), m_copyMatrix.cols(), m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
+ &m_symbolic, 0, 0);
+
+ m_isInitialized = true;
+ m_info = errorCode ? InvalidInput : Success;
+ m_analysisIsOk = true;
+ m_factorizationIsOk = false;
+ m_extractedDataAreDirty = true;
+ }
+
+ void factorize_impl()
+ {
+ int errorCode;
+ errorCode = umfpack_numeric(m_outerIndexPtr, m_innerIndexPtr, m_valuePtr,
+ m_symbolic, &m_numeric, 0, 0);
+
+ m_info = errorCode ? NumericalIssue : Success;
+ m_factorizationIsOk = true;
+ m_extractedDataAreDirty = true;
+ }
// cached data to reduce reallocation, etc.
mutable LUMatrixType m_l;
diff --git a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h
index 5c8c476eecf..1951286f3ae 100644
--- a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h
+++ b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h
@@ -70,6 +70,43 @@ max
return (max)(Derived::PlainObject::Constant(rows(), cols(), other));
}
+
+#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \
+template<typename OtherDerived> \
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const OtherDerived> \
+OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \
+{ \
+ return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const OtherDerived>(derived(), other.derived()); \
+}\
+typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> > Cmp ## COMPARATOR ## ReturnType; \
+typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject>, const Derived > RCmp ## COMPARATOR ## ReturnType; \
+EIGEN_STRONG_INLINE const Cmp ## COMPARATOR ## ReturnType \
+OP(const Scalar& s) const { \
+ return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \
+} \
+friend EIGEN_STRONG_INLINE const RCmp ## COMPARATOR ## ReturnType \
+OP(const Scalar& s, const Derived& d) { \
+ return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \
+}
+
+#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \
+template<typename OtherDerived> \
+EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_##RCOMPARATOR>, const OtherDerived, const Derived> \
+OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \
+{ \
+ return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_##RCOMPARATOR>, const OtherDerived, const Derived>(other.derived(), derived()); \
+} \
+\
+inline const RCmp ## RCOMPARATOR ## ReturnType \
+OP(const Scalar& s) const { \
+ return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \
+} \
+friend inline const Cmp ## RCOMPARATOR ## ReturnType \
+OP(const Scalar& s, const Derived& d) { \
+ return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \
+}
+
+
/** \returns an expression of the coefficient-wise \< operator of *this and \a other
*
* Example: \include Cwise_less.cpp
@@ -77,7 +114,7 @@ max
*
* \sa all(), any(), operator>(), operator<=()
*/
-EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less)
+EIGEN_MAKE_CWISE_COMP_OP(operator<, LT)
/** \returns an expression of the coefficient-wise \<= operator of *this and \a other
*
@@ -86,7 +123,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less)
*
* \sa all(), any(), operator>=(), operator<()
*/
-EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal)
+EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE)
/** \returns an expression of the coefficient-wise \> operator of *this and \a other
*
@@ -95,7 +132,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal)
*
* \sa all(), any(), operator>=(), operator<()
*/
-EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater)
+EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT)
/** \returns an expression of the coefficient-wise \>= operator of *this and \a other
*
@@ -104,7 +141,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater)
*
* \sa all(), any(), operator>(), operator<=()
*/
-EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal)
+EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE)
/** \returns an expression of the coefficient-wise == operator of *this and \a other
*
@@ -118,7 +155,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal)
*
* \sa all(), any(), isApprox(), isMuchSmallerThan()
*/
-EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to)
+EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ)
/** \returns an expression of the coefficient-wise != operator of *this and \a other
*
@@ -132,7 +169,10 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to)
*
* \sa all(), any(), isApprox(), isMuchSmallerThan()
*/
-EIGEN_MAKE_CWISE_BINARY_OP(operator!=,std::not_equal_to)
+EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ)
+
+#undef EIGEN_MAKE_CWISE_COMP_OP
+#undef EIGEN_MAKE_CWISE_COMP_R_OP
// scalar addition
@@ -209,3 +249,5 @@ operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL);
return CwiseBinaryOp<internal::scalar_boolean_or_op, const Derived, const OtherDerived>(derived(),other.derived());
}
+
+
diff --git a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h
index a596367906f..1c3ed3fcd70 100644
--- a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h
+++ b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h
@@ -185,19 +185,3 @@ cube() const
{
return derived();
}
-
-#define EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(METHOD_NAME,FUNCTOR) \
- inline const CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \
- METHOD_NAME(const Scalar& s) const { \
- return CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \
- (derived(), std::bind2nd(FUNCTOR<Scalar>(), s)); \
- }
-
-EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator==, std::equal_to)
-EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator!=, std::not_equal_to)
-EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<, std::less)
-EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<=, std::less_equal)
-EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>, std::greater)
-EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>=, std::greater_equal)
-
-
diff --git a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h
index 7f62149e04b..c4a042b7027 100644
--- a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h
+++ b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h
@@ -124,3 +124,20 @@ cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const
{
return CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>(derived(), other.derived());
}
+
+typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar,internal::cmp_EQ>, const Derived, const ConstantReturnType> CwiseScalarEqualReturnType;
+
+/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s
+ *
+ * \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
+ * In order to check for equality between two vectors or matrices with floating-point coefficients, it is
+ * generally a far better idea to use a fuzzy comparison as provided by isApprox() and
+ * isMuchSmallerThan().
+ *
+ * \sa cwiseEqual(const MatrixBase<OtherDerived> &) const
+ */
+inline const CwiseScalarEqualReturnType
+cwiseEqual(const Scalar& s) const
+{
+ return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op<Scalar,internal::cmp_EQ>());
+}
diff --git a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h
index 0cf0640bae6..8de10935d55 100644
--- a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h
+++ b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h
@@ -50,18 +50,3 @@ cwiseSqrt() const { return derived(); }
inline const CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const Derived>
cwiseInverse() const { return derived(); }
-/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s
- *
- * \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
- * In order to check for equality between two vectors or matrices with floating-point coefficients, it is
- * generally a far better idea to use a fuzzy comparison as provided by isApprox() and
- * isMuchSmallerThan().
- *
- * \sa cwiseEqual(const MatrixBase<OtherDerived> &) const
- */
-inline const CwiseUnaryOp<std::binder1st<std::equal_to<Scalar> >, const Derived>
-cwiseEqual(const Scalar& s) const
-{
- return CwiseUnaryOp<std::binder1st<std::equal_to<Scalar> >,const Derived>
- (derived(), std::bind1st(std::equal_to<Scalar>(), s));
-}
diff --git a/extern/Eigen3/SConscript b/extern/Eigen3/SConscript
deleted file mode 100644
index 2dc2d623768..00000000000
--- a/extern/Eigen3/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2015, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Bastien Montagne.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-sources = env.Glob('intern/*.cc')
-
-incs = '.'
-defs = []
-
-env.BlenderLib('extern_eigen3', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185])
diff --git a/extern/Eigen3/eigen-update.sh b/extern/Eigen3/eigen-update.sh
index 1cf0337adf6..9d22098c4fd 100755
--- a/extern/Eigen3/eigen-update.sh
+++ b/extern/Eigen3/eigen-update.sh
@@ -17,7 +17,7 @@ if [ -d eigen ]
then
cd eigen
# put here the version you want to use
- hg up 3.2.1
+ hg up 3.2.7
rm -f `find Eigen/ -type f -name "CMakeLists.txt"`
cp -r Eigen ..
cd ..
diff --git a/extern/Eigen3/eigen3_capi.h b/extern/Eigen3/eigen3_capi.h
deleted file mode 100644
index 16f223793a9..00000000000
--- a/extern/Eigen3/eigen3_capi.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Bastien Montagne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __EIGEN3_C_API_H__
-#define __EIGEN3_C_API_H__
-
-#include "intern/eigenvalues.h"
-
-#endif /* __EIGEN3_C_API_H__ */
diff --git a/extern/Eigen3/intern/eigenvalues.cc b/extern/Eigen3/intern/eigenvalues.cc
deleted file mode 100644
index dcaaee8e9c2..00000000000
--- a/extern/Eigen3/intern/eigenvalues.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Bastien Montagne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __EIGEN3_EIGENVALUES_C_API_CC__
-#define __EIGEN3_EIGENVALUES_C_API_CC__
-
-/* Eigen gives annoying huge amount of warnings here, silence them! */
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
-
-#include <Eigen/Core>
-#include <Eigen/Eigenvalues>
-
-#include "eigenvalues.h"
-
-using Eigen::SelfAdjointEigenSolver;
-
-using Eigen::MatrixXf;
-using Eigen::VectorXf;
-using Eigen::Map;
-
-using Eigen::Success;
-
-bool EG3_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors)
-{
- SelfAdjointEigenSolver<MatrixXf> eigen_solver;
-
- /* Blender and Eigen matrices are both column-major. */
- eigen_solver.compute(Map<MatrixXf>((float *)matrix, size, size));
-
- if (eigen_solver.info() != Success) {
- return false;
- }
-
- if (r_eigen_values) {
- Map<VectorXf>(r_eigen_values, size) = eigen_solver.eigenvalues().transpose();
- }
-
- if (r_eigen_vectors) {
- Map<MatrixXf>(r_eigen_vectors, size, size) = eigen_solver.eigenvectors();
- }
-
- return true;
-}
-
-#endif /* __EIGEN3_EIGENVALUES_C_API_CC__ */
diff --git a/extern/Eigen3/intern/eigenvalues.h b/extern/Eigen3/intern/eigenvalues.h
deleted file mode 100644
index 93fc06c2339..00000000000
--- a/extern/Eigen3/intern/eigenvalues.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2015 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Bastien Montagne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __EIGEN3_EIGENVALUES_C_API_H__
-#define __EIGEN3_EIGENVALUES_C_API_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-bool EG3_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __EIGEN3_EIGENVALUES_C_API_H__ */
diff --git a/extern/SConscript b/extern/SConscript
deleted file mode 100644
index 484c0e959c2..00000000000
--- a/extern/SConscript
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/python
-
-Import('env')
-
-if env['WITH_BF_GLEW_ES']:
- SConscript(['glew-es/SConscript'])
-else:
- SConscript(['glew/SConscript'])
-
-SConscript(['colamd/SConscript'])
-SConscript(['rangetree/SConscript'])
-SConscript(['wcwidth/SConscript'])
-SConscript(['libmv/SConscript'])
-SConscript(['Eigen3/SConscript'])
-
-if env['WITH_BF_GAMEENGINE']:
- SConscript(['recastnavigation/SConscript'])
-
-# now only available in a branch
-'''
-if env['WITH_BF_ELTOPO']:
- SConscript(['eltopo/SConscript'])
-'''
-
-if env['WITH_BF_BULLET']:
- SConscript(['bullet2/src/SConscript'])
-
-if env['WITH_BF_COMPOSITOR'] or env['WITH_BF_CYCLES'] or env['WITH_BF_OPENSUBDIV']:
- SConscript (['clew/SConscript'])
- SConscript (['cuew/SConscript'])
-
-if env['WITH_BF_OPENJPEG'] and env['BF_OPENJPEG_LIB'] == '':
- SConscript(['libopenjpeg/SConscript'])
-
-if env['WITH_BF_REDCODE'] and env['BF_REDCODE_LIB'] == '':
- SConscript(['libredcode/SConscript'])
-
-if env['WITH_BF_BINRELOC']:
- SConscript(['binreloc/SConscript']);
-
-if env['WITH_BF_LZO']:
- SConscript(['lzo/SConscript'])
-
-if env['WITH_BF_LZMA']:
- SConscript(['lzma/SConscript'])
-
-if env['WITH_BF_BOOLEAN']:
- SConscript(['carve/SConscript'])
-
-if env['WITH_GHOST_XDND']:
- # FreeBSD doesn't seems to support XDND protocol
- if env['OURPLATFORM'] in ('linux', 'openbsd3', 'sunos5', 'aix4', 'aix5'):
- SConscript(['xdnd/SConscript'])
-
-if env['WITH_BF_SDL'] and env['WITH_BF_SDL_DYNLOAD']:
- SConscript(['sdlew/SConscript'])
diff --git a/extern/binreloc/SConscript b/extern/binreloc/SConscript
deleted file mode 100644
index 331b70a4ebc..00000000000
--- a/extern/binreloc/SConscript
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/python
-import sys
-import os
-
-Import('env')
-defs = 'ENABLE_BINRELOC'
-cflags = []
-
-sources = ['binreloc.c']
-incs = 'include'
-
-env.BlenderLib ( 'extern_binreloc', sources, Split(incs), Split(defs), libtype=['extern','player'], priority=[36,225], compileflags = cflags)
-
diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet2/CMakeLists.txt
index 2b2c18c0685..949a8b01bd2 100644
--- a/extern/bullet2/CMakeLists.txt
+++ b/extern/bullet2/CMakeLists.txt
@@ -43,53 +43,53 @@ set(SRC
src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp
src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp
+ src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp
src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp
- src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
+ src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp
src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
src/BulletCollision/CollisionDispatch/btCollisionObject.cpp
src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
+ src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp
src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
+ src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
+ src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp
- src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp
src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btGhostObject.cpp
+ src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
- src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h
src/BulletCollision/CollisionDispatch/btManifoldResult.cpp
src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp
src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp
src/BulletCollision/CollisionDispatch/btUnionFind.cpp
- src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp
- src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
- src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
- src/BulletCollision/CollisionShapes/btBoxShape.cpp
src/BulletCollision/CollisionShapes/btBox2dShape.cpp
+ src/BulletCollision/CollisionShapes/btBoxShape.cpp
src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp
src/BulletCollision/CollisionShapes/btCapsuleShape.cpp
src/BulletCollision/CollisionShapes/btCollisionShape.cpp
src/BulletCollision/CollisionShapes/btCompoundShape.cpp
src/BulletCollision/CollisionShapes/btConcaveShape.cpp
src/BulletCollision/CollisionShapes/btConeShape.cpp
+ src/BulletCollision/CollisionShapes/btConvex2dShape.cpp
src/BulletCollision/CollisionShapes/btConvexHullShape.cpp
src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp
src/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp
src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
src/BulletCollision/CollisionShapes/btConvexShape.cpp
- src/BulletCollision/CollisionShapes/btConvex2dShape.cpp
src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp
src/BulletCollision/CollisionShapes/btCylinderShape.cpp
src/BulletCollision/CollisionShapes/btEmptyShape.cpp
src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp
- src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp
src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp
+ src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp
src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp
src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp
@@ -106,11 +106,11 @@ set(SRC
src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp
src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp
src/BulletCollision/Gimpact/btContactProcessing.cpp
- src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp
src/BulletCollision/Gimpact/btGImpactBvh.cpp
src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp
src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp
src/BulletCollision/Gimpact/btGImpactShape.cpp
+ src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp
src/BulletCollision/Gimpact/btTriangleShapeEx.cpp
src/BulletCollision/Gimpact/gim_box_set.cpp
src/BulletCollision/Gimpact/gim_contact.cpp
@@ -124,32 +124,32 @@ set(SRC
src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp
src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp
+ src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp
src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp
- src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
-
+
+ src/BulletDynamics/Character/btKinematicCharacterController.cpp
src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp
src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp
+ src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp
+ src/BulletDynamics/ConstraintSolver/btGearConstraint.cpp
src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp
+ src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp
src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp
src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp
+ src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp
src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp
src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp
src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp
src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp
- src/BulletDynamics/ConstraintSolver/btGearConstraint.cpp
- src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp
+ src/BulletDynamics/Dynamics/Bullet-C-API.cpp
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
src/BulletDynamics/Dynamics/btRigidBody.cpp
src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp
- src/BulletDynamics/Dynamics/Bullet-C-API.cpp
- src/BulletDynamics/Vehicle/btRaycastVehicle.cpp
- src/BulletDynamics/Vehicle/btWheelInfo.cpp
- src/BulletDynamics/Character/btKinematicCharacterController.cpp
src/BulletDynamics/Featherstone/btMultiBody.cpp
src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
@@ -158,8 +158,12 @@ set(SRC
src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp
+ src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp
src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp
-
+ src/BulletDynamics/Vehicle/btRaycastVehicle.cpp
+ src/BulletDynamics/Vehicle/btWheelInfo.cpp
+
+ src/BulletSoftBody/btDefaultSoftBodySolver.cpp
src/BulletSoftBody/btSoftBody.cpp
src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp
src/BulletSoftBody/btSoftBodyHelpers.cpp
@@ -167,18 +171,16 @@ set(SRC
src/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp
src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp
src/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp
- src/BulletSoftBody/btDefaultSoftBodySolver.cpp
-
+
src/LinearMath/btAlignedAllocator.cpp
src/LinearMath/btConvexHull.cpp
src/LinearMath/btConvexHullComputer.cpp
src/LinearMath/btGeometryUtil.cpp
+ src/LinearMath/btPolarDecomposition.cpp
src/LinearMath/btQuickprof.cpp
src/LinearMath/btSerializer.cpp
src/LinearMath/btVector3.cpp
- src/LinearMath/btPolarDecomposition.cpp
-
-
+
src/BulletCollision/BroadphaseCollision/btAxisSweep3.h
src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h
src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h
@@ -191,35 +193,37 @@ set(SRC
src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h
src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h
src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h
+ src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h
src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h
- src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h
+ src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btBoxBoxDetector.h
src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h
src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h
src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h
- src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h
src/BulletCollision/CollisionDispatch/btCollisionObject.h
+ src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h
src/BulletCollision/CollisionDispatch/btCollisionWorld.h
+ src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h
src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h
+ src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h
+ src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h
src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h
- src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h
src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h
src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btGhostObject.h
+ src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
+ src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h
src/BulletCollision/CollisionDispatch/btManifoldResult.h
src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h
src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h
src/BulletCollision/CollisionDispatch/btUnionFind.h
- src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h
- src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h
- src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
- src/BulletCollision/CollisionShapes/btBoxShape.h
src/BulletCollision/CollisionShapes/btBox2dShape.h
+ src/BulletCollision/CollisionShapes/btBoxShape.h
src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h
src/BulletCollision/CollisionShapes/btCapsuleShape.h
src/BulletCollision/CollisionShapes/btCollisionMargin.h
@@ -227,20 +231,20 @@ set(SRC
src/BulletCollision/CollisionShapes/btCompoundShape.h
src/BulletCollision/CollisionShapes/btConcaveShape.h
src/BulletCollision/CollisionShapes/btConeShape.h
+ src/BulletCollision/CollisionShapes/btConvex2dShape.h
src/BulletCollision/CollisionShapes/btConvexHullShape.h
src/BulletCollision/CollisionShapes/btConvexInternalShape.h
src/BulletCollision/CollisionShapes/btConvexPointCloudShape.h
src/BulletCollision/CollisionShapes/btConvexPolyhedron.h
src/BulletCollision/CollisionShapes/btConvexShape.h
- src/BulletCollision/CollisionShapes/btConvex2dShape.h
src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h
src/BulletCollision/CollisionShapes/btCylinderShape.h
src/BulletCollision/CollisionShapes/btEmptyShape.h
src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h
src/BulletCollision/CollisionShapes/btMaterial.h
src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h
- src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h
src/BulletCollision/CollisionShapes/btMultiSphereShape.h
+ src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h
src/BulletCollision/CollisionShapes/btOptimizedBvh.h
src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h
src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h
@@ -286,33 +290,43 @@ set(SRC
src/BulletCollision/Gimpact/gim_memory.h
src/BulletCollision/Gimpact/gim_radixsort.h
src/BulletCollision/Gimpact/gim_tri_collision.h
+ src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h
src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h
src/BulletCollision/NarrowPhaseCollision/btConvexCast.h
src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h
src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h
+ src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h
src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h
src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h
+ src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h
src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h
src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h
src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h
src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h
+ src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h
src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
src/BulletCollision/NarrowPhaseCollision/btPointCollector.h
+ src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h
src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h
src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h
src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h
- src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h
-
+
+ src/BulletDynamics/Character/btCharacterControllerInterface.h
+ src/BulletDynamics/Character/btKinematicCharacterController.h
src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h
src/BulletDynamics/ConstraintSolver/btConstraintSolver.h
src/BulletDynamics/ConstraintSolver/btContactConstraint.h
src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
+ src/BulletDynamics/ConstraintSolver/btFixedConstraint.h
+ src/BulletDynamics/ConstraintSolver/btGearConstraint.h
src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
+ src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h
src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h
src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h
src/BulletDynamics/ConstraintSolver/btHingeConstraint.h
src/BulletDynamics/ConstraintSolver/btJacobianEntry.h
+ src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h
src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h
src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
src/BulletDynamics/ConstraintSolver/btSliderConstraint.h
@@ -321,22 +335,16 @@ set(SRC
src/BulletDynamics/ConstraintSolver/btSolverConstraint.h
src/BulletDynamics/ConstraintSolver/btTypedConstraint.h
src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h
- src/BulletDynamics/ConstraintSolver/btGearConstraint.h
- src/BulletDynamics/ConstraintSolver/btFixedConstraint.h
src/BulletDynamics/Dynamics/btActionInterface.h
src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h
src/BulletDynamics/Dynamics/btDynamicsWorld.h
- src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h
src/BulletDynamics/Dynamics/btRigidBody.h
- src/BulletDynamics/Vehicle/btRaycastVehicle.h
- src/BulletDynamics/Vehicle/btVehicleRaycaster.h
- src/BulletDynamics/Vehicle/btWheelInfo.h
- src/BulletDynamics/Character/btCharacterControllerInterface.h
- src/BulletDynamics/Character/btKinematicCharacterController.h
+ src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h
src/BulletDynamics/Featherstone/btMultiBody.h
src/BulletDynamics/Featherstone/btMultiBodyConstraint.h
src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
+ src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h
src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h
src/BulletDynamics/Featherstone/btMultiBodyLink.h
@@ -345,30 +353,36 @@ set(SRC
src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h
src/BulletDynamics/MLCPSolvers/btDantzigLCP.h
src/BulletDynamics/MLCPSolvers/btDantzigSolver.h
+ src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h
+ src/BulletDynamics/MLCPSolvers/btLemkeSolver.h
src/BulletDynamics/MLCPSolvers/btMLCPSolver.h
src/BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h
src/BulletDynamics/MLCPSolvers/btPATHSolver.h
src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h
-
+ src/BulletDynamics/Vehicle/btRaycastVehicle.h
+ src/BulletDynamics/Vehicle/btVehicleRaycaster.h
+ src/BulletDynamics/Vehicle/btWheelInfo.h
+
+ src/BulletSoftBody/btDefaultSoftBodySolver.h
src/BulletSoftBody/btSoftBody.h
- src/BulletSoftBody/btSoftBodyInternals.h
- src/BulletSoftBody/btSoftBodyData.h
src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h
+ src/BulletSoftBody/btSoftBodyData.h
src/BulletSoftBody/btSoftBodyHelpers.h
+ src/BulletSoftBody/btSoftBodyInternals.h
src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h
+ src/BulletSoftBody/btSoftBodySolverVertexBuffer.h
+ src/BulletSoftBody/btSoftBodySolvers.h
src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h
src/BulletSoftBody/btSoftRigidDynamicsWorld.h
src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h
src/BulletSoftBody/btSparseSDF.h
- src/BulletSoftBody/btSoftBodySolvers.h
- src/BulletSoftBody/btDefaultSoftBodySolver.h
- src/BulletSoftBody/btSoftBodySolverVertexBuffer.h
-
+
src/LinearMath/btAabbUtil2.h
src/LinearMath/btAlignedAllocator.h
src/LinearMath/btAlignedObjectArray.h
src/LinearMath/btConvexHull.h
src/LinearMath/btConvexHullComputer.h
+ src/LinearMath/btCpuFeatureUtility.h
src/LinearMath/btDefaultMotionState.h
src/LinearMath/btGeometryUtil.h
src/LinearMath/btGrahamScan2dConvexHull.h
@@ -376,8 +390,10 @@ set(SRC
src/LinearMath/btIDebugDraw.h
src/LinearMath/btList.h
src/LinearMath/btMatrix3x3.h
+ src/LinearMath/btMatrixX.h
src/LinearMath/btMinMax.h
src/LinearMath/btMotionState.h
+ src/LinearMath/btPolarDecomposition.h
src/LinearMath/btPoolAllocator.h
src/LinearMath/btQuadWord.h
src/LinearMath/btQuaternion.h
@@ -385,14 +401,12 @@ set(SRC
src/LinearMath/btRandom.h
src/LinearMath/btScalar.h
src/LinearMath/btSerializer.h
+ src/LinearMath/btSpatialAlgebra.h
src/LinearMath/btStackAlloc.h
src/LinearMath/btTransform.h
src/LinearMath/btTransformUtil.h
src/LinearMath/btVector3.h
- src/LinearMath/btPolarDecomposition.h
- src/LinearMath/btMatrixX.h
-
-
+
src/btBulletCollisionCommon.h
src/btBulletDynamicsCommon.h
src/Bullet-C-Api.h
diff --git a/extern/bullet2/patches/blender.patch b/extern/bullet2/patches/blender.patch
new file mode 100644
index 00000000000..96357ddd315
--- /dev/null
+++ b/extern/bullet2/patches/blender.patch
@@ -0,0 +1,324 @@
+diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
+index be9eca6..ec40c96 100644
+--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
++++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
+@@ -15,7 +15,7 @@ subject to the following restrictions:
+
+
+ /**
+- * @mainpage Bullet Documentation
++ * @page Bullet Documentation
+ *
+ * @section intro_sec Introduction
+ * Bullet is a Collision Detection and Rigid Body Dynamics Library. The Library is Open Source and free for commercial use, under the ZLib license ( http://opensource.org/licenses/zlib-license.php ).
+diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp
+index 36dd043..57eb817 100644
+--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp
++++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp
+@@ -579,14 +579,10 @@ btCollisionShape* btCollisionWorldImporter::convertCollisionShape( btCollisionS
+ btCompoundShapeData* compoundData = (btCompoundShapeData*)shapeData;
+ btCompoundShape* compoundShape = createCompoundShape();
+
+- btCompoundShapeChildData* childShapeDataArray = &compoundData->m_childShapePtr[0];
+-
+
+ btAlignedObjectArray<btCollisionShape*> childShapes;
+ for (int i=0;i<compoundData->m_numChildShapes;i++)
+ {
+- btCompoundShapeChildData* ptr = &compoundData->m_childShapePtr[i];
+-
+ btCollisionShapeData* cd = compoundData->m_childShapePtr[i].m_childShape;
+
+ btCollisionShape* childShape = convertCollisionShape(cd);
+diff --git a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp b/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp
+index 57fc119..31faf1d 100644
+--- a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp
++++ b/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp
+@@ -29,14 +29,11 @@ subject to the following restrictions:
+ static btVector3
+ getNormalizedVector(const btVector3& v)
+ {
+- btScalar l = v.length();
+- btVector3 n = v;
+- if (l < SIMD_EPSILON) {
+- n.setValue(0,0,0);
+- } else {
+- n /= l;
+- }
++ btVector3 n(0, 0, 0);
+
++ if (v.length() > SIMD_EPSILON) {
++ n = v.normalized();
++ }
+ return n;
+ }
+
+diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h
+index 27ccefe..8e4456e 100644
+--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h
++++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h
+@@ -37,8 +37,13 @@ struct btSimdScalar
+ {
+
+ }
+-
++/* workaround for clang 3.4 ( == apple clang 5.1 ) issue, friction would fail with forced inlining */
++#if (defined(__clang__) && defined(__apple_build_version__) && (__clang_major__ == 5) && (__clang_minor__ == 1)) \
++|| (defined(__clang__) && !defined(__apple_build_version__) && (__clang_major__ == 3) && (__clang_minor__ == 4))
++ inline __attribute__ ((noinline)) btSimdScalar(float fl)
++#else
+ SIMD_FORCE_INLINE btSimdScalar(float fl)
++#endif
+ :m_vec128 (_mm_set1_ps(fl))
+ {
+ }
+diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp
+index 5d62da7..fcd312e 100644
+--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp
++++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp
+@@ -28,7 +28,6 @@
+ #include "btMultiBodyJointFeedback.h"
+ #include "LinearMath/btTransformUtil.h"
+ #include "LinearMath/btSerializer.h"
+-#include "Bullet3Common/b3Logging.h"
+ // #define INCLUDE_GYRO_TERM
+
+ ///todo: determine if we need these options. If so, make a proper API, otherwise delete those globals
+@@ -1732,7 +1731,6 @@ void btMultiBody::goToSleep()
+
+ void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep)
+ {
+- int num_links = getNumLinks();
+ extern bool gDisableDeactivation;
+ if (!m_canSleep || gDisableDeactivation)
+ {
+diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
+index 8a034b3..4f66b20 100644
+--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
++++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
+@@ -809,7 +809,6 @@ static void applyJointFeedback(btMultiBodyJacobianData& data, const btMultiBodyS
+ }
+ #endif
+
+-#include "Bullet3Common/b3Logging.h"
+ void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& c, btScalar deltaTime)
+ {
+ #if 1
+diff --git a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h b/extern/bullet2/src/BulletSoftBody/btSparseSDF.h
+index bcf0c79..8992ddb 100644
+--- a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h
++++ b/extern/bullet2/src/BulletSoftBody/btSparseSDF.h
+@@ -185,7 +185,6 @@ struct btSparseSdf
+ {
+ ++nprobes;
+ ++ncells;
+- int sz = sizeof(Cell);
+ if (ncells>m_clampCells)
+ {
+ static int numResets=0;
+diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp b/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp
+index d58ac95..3fd77df 100644
+--- a/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp
++++ b/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp
+@@ -2665,6 +2665,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in
+ }
+
+ vertices.resize(0);
++ original_vertex_index.resize(0);
+ edges.resize(0);
+ faces.resize(0);
+
+@@ -2675,6 +2676,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in
+ {
+ btConvexHullInternal::Vertex* v = oldVertices[copied];
+ vertices.push_back(hull.getCoordinates(v));
++ original_vertex_index.push_back(v->point.index);
+ btConvexHullInternal::Edge* firstEdge = v->edges;
+ if (firstEdge)
+ {
+diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.h b/extern/bullet2/src/LinearMath/btConvexHullComputer.h
+index 7240ac4..6871ce8 100644
+--- a/extern/bullet2/src/LinearMath/btConvexHullComputer.h
++++ b/extern/bullet2/src/LinearMath/btConvexHullComputer.h
+@@ -67,6 +67,7 @@ class btConvexHullComputer
+
+ // Vertices of the output hull
+ btAlignedObjectArray<btVector3> vertices;
++ btAlignedObjectArray<int> original_vertex_index;
+
+ // Edges of the output hull
+ btAlignedObjectArray<Edge> edges;
+diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp
+index 0623e35..02ea503 100644
+--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp
++++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp
+@@ -13,9 +13,9 @@ subject to the following restrictions:
+ 3. This notice may not be removed or altered from any source distribution.
+ */
+
+-#if defined (_WIN32) || defined (__i386__)
+-#define BT_USE_SSE_IN_API
+-#endif
++//#if defined (_WIN32) || defined (__i386__)
++//#define BT_USE_SSE_IN_API
++//#endif
+
+ #include "btConvexHullShape.h"
+ #include "BulletCollision/CollisionShapes/btCollisionMargin.h"
+diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp
+index b56d729..88018b4 100644
+--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp
++++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp
+@@ -13,9 +13,9 @@ subject to the following restrictions:
+ 3. This notice may not be removed or altered from any source distribution.
+ */
+
+-#if defined (_WIN32) || defined (__i386__)
+-#define BT_USE_SSE_IN_API
+-#endif
++//#if defined (_WIN32) || defined (__i386__)
++//#define BT_USE_SSE_IN_API
++//#endif
+
+ #include "btConvexShape.h"
+ #include "btTriangleShape.h"
+diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp
+index a7362ea..6abfdff 100644
+--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp
++++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp
+@@ -13,9 +13,9 @@ subject to the following restrictions:
+ 3. This notice may not be removed or altered from any source distribution.
+ */
+
+-#if defined (_WIN32) || defined (__i386__)
+-#define BT_USE_SSE_IN_API
+-#endif
++//#if defined (_WIN32) || defined (__i386__)
++//#define BT_USE_SSE_IN_API
++//#endif
+
+ #include "btMultiSphereShape.h"
+ #include "BulletCollision/CollisionShapes/btCollisionMargin.h"
+diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
+index 4854f37..9095c59 100644
+--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
++++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
+@@ -12,9 +12,9 @@ subject to the following restrictions:
+ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ */
+-#if defined (_WIN32) || defined (__i386__)
+-#define BT_USE_SSE_IN_API
+-#endif
++//#if defined (_WIN32) || defined (__i386__)
++//#define BT_USE_SSE_IN_API
++//#endif
+
+ #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
+ #include "btConvexPolyhedron.h"
+diff --git a/extern/bullet2/src/LinearMath/btVector3.cpp b/extern/bullet2/src/LinearMath/btVector3.cpp
+index e05bdcc..dbcf2b6 100644
+--- a/extern/bullet2/src/LinearMath/btVector3.cpp
++++ b/extern/bullet2/src/LinearMath/btVector3.cpp
+@@ -15,9 +15,9 @@
+ This source version has been altered.
+ */
+
+-#if defined (_WIN32) || defined (__i386__)
+-#define BT_USE_SSE_IN_API
+-#endif
++//#if defined (_WIN32) || defined (__i386__)
++//#define BT_USE_SSE_IN_API
++//#endif
+
+
+ #include "btVector3.h"
+diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
+index e0e8bc7..a788268 100644
+--- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
++++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
+@@ -425,50 +425,38 @@ void btRigidBody::setCenterOfMassTransform(const btTransform& xform)
+ }
+
+
++bool btRigidBody::checkCollideWithOverride(const btCollisionObject* co) const
++{
++ const btRigidBody* otherRb = btRigidBody::upcast(co);
++ if (!otherRb)
++ return true;
++
++ for (int i = 0; i < m_constraintRefs.size(); ++i)
++ {
++ const btTypedConstraint* c = m_constraintRefs[i];
++ if (c->isEnabled())
++ if (&c->getRigidBodyA() == otherRb || &c->getRigidBodyB() == otherRb)
++ return false;
++ }
++
++ return true;
++}
+
+
+
+ void btRigidBody::addConstraintRef(btTypedConstraint* c)
+ {
+- ///disable collision with the 'other' body
+-
+ int index = m_constraintRefs.findLinearSearch(c);
+- //don't add constraints that are already referenced
+- //btAssert(index == m_constraintRefs.size());
+ if (index == m_constraintRefs.size())
+- {
+- m_constraintRefs.push_back(c);
+- btCollisionObject* colObjA = &c->getRigidBodyA();
+- btCollisionObject* colObjB = &c->getRigidBodyB();
+- if (colObjA == this)
+- {
+- colObjA->setIgnoreCollisionCheck(colObjB, true);
+- }
+- else
+- {
+- colObjB->setIgnoreCollisionCheck(colObjA, true);
+- }
+- }
++ m_constraintRefs.push_back(c);
++
++ m_checkCollideWith = true;
+ }
+
+ void btRigidBody::removeConstraintRef(btTypedConstraint* c)
+ {
+- int index = m_constraintRefs.findLinearSearch(c);
+- //don't remove constraints that are not referenced
+- if(index < m_constraintRefs.size())
+- {
+- m_constraintRefs.remove(c);
+- btCollisionObject* colObjA = &c->getRigidBodyA();
+- btCollisionObject* colObjB = &c->getRigidBodyB();
+- if (colObjA == this)
+- {
+- colObjA->setIgnoreCollisionCheck(colObjB, false);
+- }
+- else
+- {
+- colObjB->setIgnoreCollisionCheck(colObjA, false);
+- }
+- }
++ m_constraintRefs.remove(c);
++ m_checkCollideWith = m_constraintRefs.size() > 0;
+ }
+
+ int btRigidBody::calculateSerializeBufferSize() const
+diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h
+index 1d177db..c2f8c5d 100644
+--- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h
++++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h
+@@ -509,6 +509,8 @@ public:
+ return (getBroadphaseProxy() != 0);
+ }
+
++ virtual bool checkCollideWithOverride(const btCollisionObject* co) const;
++
+ void addConstraintRef(btTypedConstraint* c);
+ void removeConstraintRef(btTypedConstraint* c);
+
diff --git a/extern/bullet2/patches/convex_hull.patch b/extern/bullet2/patches/convex_hull.patch
deleted file mode 100644
index 1b2978221fb..00000000000
--- a/extern/bullet2/patches/convex_hull.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-Index: extern/bullet2/src/Bullet-C-Api.h
-===================================================================
---- extern/bullet2/src/Bullet-C-Api.h (revision 51556)
-+++ extern/bullet2/src/Bullet-C-Api.h (working copy)
-@@ -167,6 +167,16 @@ extern "C" {
- // needed for source/blender/blenkernel/intern/collision.c
- double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]);
-
-+
-+ /* Convex Hull */
-+ PL_DECLARE_HANDLE(plConvexHull);
-+ plConvexHull plConvexHullCompute(float (*coords)[3], int count);
-+ int plConvexHullNumVertices(plConvexHull hull);
-+ int plConvexHullNumFaces(plConvexHull hull);
-+ void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index);
-+ int plConvexHullGetFaceSize(plConvexHull hull, int n);
-+ void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices);
-+
- #ifdef __cplusplus
- }
- #endif
-Index: extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp
-===================================================================
---- extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp (revision 51556)
-+++ extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp (working copy)
-@@ -23,7 +23,7 @@ subject to the following restrictions:
- #include "Bullet-C-Api.h"
- #include "btBulletDynamicsCommon.h"
- #include "LinearMath/btAlignedAllocator.h"
--
-+#include "LinearMath/btConvexHullComputer.h"
-
-
- #include "LinearMath/btVector3.h"
-@@ -403,3 +403,60 @@ double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float
- return -1.0f;
- }
-
-+// Convex hull
-+plConvexHull plConvexHullCompute(float (*coords)[3], int count)
-+{
-+ btConvexHullComputer *computer = new btConvexHullComputer;
-+ computer->compute(reinterpret_cast< float* >(coords),
-+ sizeof(*coords), count, 0, 0);
-+ return reinterpret_cast<plConvexHull>(computer);
-+}
-+
-+int plConvexHullNumVertices(plConvexHull hull)
-+{
-+ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
-+ return computer->vertices.size();
-+}
-+
-+int plConvexHullNumFaces(plConvexHull hull)
-+{
-+ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
-+ return computer->faces.size();
-+}
-+
-+void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3],
-+ int *original_index)
-+{
-+ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
-+ const btVector3 &v(computer->vertices[n]);
-+ coords[0] = v[0];
-+ coords[1] = v[1];
-+ coords[2] = v[2];
-+ (*original_index) = computer->original_vertex_index[n];
-+}
-+
-+int plConvexHullGetFaceSize(plConvexHull hull, int n)
-+{
-+ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
-+ const btConvexHullComputer::Edge *e_orig, *e;
-+ int count;
-+
-+ for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0;
-+ count == 0 || e != e_orig;
-+ e = e->getNextEdgeOfFace(), count++);
-+ return count;
-+}
-+
-+void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices)
-+{
-+ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull));
-+ const btConvexHullComputer::Edge *e_orig, *e;
-+ int count;
-+
-+ for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0;
-+ count == 0 || e != e_orig;
-+ e = e->getNextEdgeOfFace(), count++)
-+ {
-+ vertices[count] = e->getTargetVertex();
-+ }
-+}
-Index: extern/bullet2/src/LinearMath/btConvexHullComputer.cpp
-===================================================================
---- extern/bullet2/src/LinearMath/btConvexHullComputer.cpp (revision 51556)
-+++ extern/bullet2/src/LinearMath/btConvexHullComputer.cpp (working copy)
-@@ -2661,6 +2661,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in
- }
-
- vertices.resize(0);
-+ original_vertex_index.resize(0);
- edges.resize(0);
- faces.resize(0);
-
-@@ -2671,6 +2672,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in
- {
- btConvexHullInternal::Vertex* v = oldVertices[copied];
- vertices.push_back(hull.getCoordinates(v));
-+ original_vertex_index.push_back(v->point.index);
- btConvexHullInternal::Edge* firstEdge = v->edges;
- if (firstEdge)
- {
-Index: extern/bullet2/src/LinearMath/btConvexHullComputer.h
-===================================================================
---- extern/bullet2/src/LinearMath/btConvexHullComputer.h (revision 51556)
-+++ extern/bullet2/src/LinearMath/btConvexHullComputer.h (working copy)
-@@ -67,6 +67,7 @@ class btConvexHullComputer
-
- // Vertices of the output hull
- btAlignedObjectArray<btVector3> vertices;
-+ btAlignedObjectArray<int> original_vertex_index;
-
- // Edges of the output hull
- btAlignedObjectArray<Edge> edges;
diff --git a/extern/bullet2/readme.txt b/extern/bullet2/readme.txt
index 3b286afa579..ec99abf71cf 100644
--- a/extern/bullet2/readme.txt
+++ b/extern/bullet2/readme.txt
@@ -4,8 +4,8 @@ Questions? mail blender at erwincoumans.com, or check the bf-blender mailing lis
Thanks,
Erwin
-Apply patches/convex_hull.patch to add access to the convex hull
-operation, used in the BMesh convex hull operator.
+Apply patches/blender.patch to fix a few build errors and warnings and dd original
+vertex access for BMesh convex hull operator.
Documentation is available at:
http://code.google.com/p/bullet/source/browse/trunk/Bullet_User_Manual.pdf
diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp
index 95443af5070..2ca20cdd8b8 100644
--- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp
+++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp
@@ -38,8 +38,9 @@ static DBVT_INLINE btDbvtVolume merge( const btDbvtVolume& a,
const btDbvtVolume& b)
{
#if (DBVT_MERGE_IMPL==DBVT_IMPL_SSE)
- ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtAabbMm)]);
- btDbvtVolume& res=*(btDbvtVolume*)locals;
+ ATTRIBUTE_ALIGNED16( char locals[sizeof(btDbvtAabbMm)]);
+ btDbvtVolume* ptr = (btDbvtVolume*) locals;
+ btDbvtVolume& res=*ptr;
#else
btDbvtVolume res;
#endif
@@ -250,7 +251,8 @@ static btDbvtVolume bounds( const tNodeArray& leaves)
{
#if DBVT_MERGE_IMPL==DBVT_IMPL_SSE
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]);
- btDbvtVolume& volume=*(btDbvtVolume*)locals;
+ btDbvtVolume* ptr = (btDbvtVolume*) locals;
+ btDbvtVolume& volume=*ptr;
volume=leaves[0]->volume;
#else
btDbvtVolume volume=leaves[0]->volume;
diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h
index b64936844d5..db4e482f292 100644
--- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h
+++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h
@@ -1193,19 +1193,34 @@ inline void btDbvt::collideOCL( const btDbvtNode* root,
/* Insert 0 */
j=nearest(&stack[0],&stock[0],nes[q].value,0,stack.size());
stack.push_back(0);
+
+ //void * memmove ( void * destination, const void * source, size_t num );
+
#if DBVT_USE_MEMMOVE
- memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1));
+ {
+ int num_items_to_move = stack.size()-1-j;
+ if(num_items_to_move > 0)
+ memmove(&stack[j+1],&stack[j],sizeof(int)*num_items_to_move);
+ }
#else
- for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1];
+ for(int k=stack.size()-1;k>j;--k) {
+ stack[k]=stack[k-1];
+ }
#endif
stack[j]=allocate(ifree,stock,nes[q]);
/* Insert 1 */
j=nearest(&stack[0],&stock[0],nes[1-q].value,j,stack.size());
stack.push_back(0);
#if DBVT_USE_MEMMOVE
- memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1));
+ {
+ int num_items_to_move = stack.size()-1-j;
+ if(num_items_to_move > 0)
+ memmove(&stack[j+1],&stack[j],sizeof(int)*num_items_to_move);
+ }
#else
- for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1];
+ for(int k=stack.size()-1;k>j;--k) {
+ stack[k]=stack[k-1];
+ }
#endif
stack[j]=allocate(ifree,stock,nes[1-q]);
}
diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
index ae22dadc73a..ad69fcbd712 100644
--- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
+++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp
@@ -34,7 +34,6 @@ int gFindPairs =0;
btHashedOverlappingPairCache::btHashedOverlappingPairCache():
m_overlapFilterCallback(0),
- m_blockedForChanges(false),
m_ghostPairCallback(0)
{
int initialAllocatedSize= 2;
diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
index eee90e473a9..14614270476 100644
--- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
+++ b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h
@@ -94,7 +94,6 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache
{
btBroadphasePairArray m_overlappingPairArray;
btOverlapFilterCallback* m_overlapFilterCallback;
- bool m_blockedForChanges;
protected:
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
index 669d0b6b55e..3b6913c0e1e 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp
@@ -189,7 +189,7 @@ bool btCollisionDispatcher::needsCollision(const btCollisionObject* body0,const
if ((!body0->isActive()) && (!body1->isActive()))
needsCollision = false;
- else if (!body0->checkCollideWith(body1))
+ else if ((!body0->checkCollideWith(body1)) || (!body1->checkCollideWith(body0)))
needsCollision = false;
return needsCollision ;
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp
index d0924100058..395df3a550f 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp
@@ -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.
@@ -31,10 +31,11 @@ btCollisionObject::btCollisionObject()
m_activationState1(1),
m_deactivationTime(btScalar(0.)),
m_friction(btScalar(0.5)),
- m_rollingFriction(0.0f),
m_restitution(btScalar(0.)),
+ m_rollingFriction(0.0f),
m_internalType(CO_COLLISION_OBJECT),
m_userObjectPointer(0),
+ m_userIndex(-1),
m_hitFraction(btScalar(1.)),
m_ccdSweptSphereRadius(btScalar(0.)),
m_ccdMotionThreshold(btScalar(0.)),
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h
index 89cad168210..c68402418f7 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h
@@ -92,11 +92,10 @@ protected:
int m_internalType;
///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer
- union
- {
- void* m_userObjectPointer;
- int m_userIndex;
- };
+
+ void* m_userObjectPointer;
+
+ int m_userIndex;
///time of impact calculation
btScalar m_hitFraction;
@@ -110,13 +109,11 @@ protected:
/// If some object should have elaborate collision filtering by sub-classes
int m_checkCollideWith;
+ btAlignedObjectArray<const btCollisionObject*> m_objectsWithoutCollisionCheck;
+
///internal update revision number. It will be increased when the object changes. This allows some subsystems to perform lazy evaluation.
int m_updateRevision;
- virtual bool checkCollideWithOverride(const btCollisionObject* /* co */) const
- {
- return true;
- }
public:
@@ -225,7 +222,34 @@ public:
return m_collisionShape;
}
-
+ void setIgnoreCollisionCheck(const btCollisionObject* co, bool ignoreCollisionCheck)
+ {
+ if (ignoreCollisionCheck)
+ {
+ //We don't check for duplicates. Is it ok to leave that up to the user of this API?
+ //int index = m_objectsWithoutCollisionCheck.findLinearSearch(co);
+ //if (index == m_objectsWithoutCollisionCheck.size())
+ //{
+ m_objectsWithoutCollisionCheck.push_back(co);
+ //}
+ }
+ else
+ {
+ m_objectsWithoutCollisionCheck.remove(co);
+ }
+ m_checkCollideWith = m_objectsWithoutCollisionCheck.size() > 0;
+ }
+
+ virtual bool checkCollideWithOverride(const btCollisionObject* co) const
+ {
+ int index = m_objectsWithoutCollisionCheck.findLinearSearch(co);
+ if (index < m_objectsWithoutCollisionCheck.size())
+ {
+ return false;
+ }
+ return true;
+ }
+
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
index d739a2a08d7..c505ed5d508 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp
@@ -34,7 +34,7 @@ subject to the following restrictions:
#include "LinearMath/btSerializer.h"
#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
-#include "BulletCollision/Gimpact/btGImpactShape.h"
+
//#define DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
@@ -292,12 +292,13 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con
btGjkConvexCast gjkConvexCaster(castShape,convexShape,&simplexSolver);
//btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0);
- bool condition = true;
+
btConvexCast* convexCasterPtr = 0;
- if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest)
- convexCasterPtr = &subSimplexConvexCaster;
- else
+ //use kF_UseSubSimplexConvexCastRaytest by default
+ if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest)
convexCasterPtr = &gjkConvexCaster;
+ else
+ convexCasterPtr = &subSimplexConvexCaster;
btConvexCast& convexCaster = *convexCasterPtr;
@@ -308,6 +309,7 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con
{
if (castResult.m_fraction < resultCallback.m_closestHitFraction)
{
+ //todo: figure out what this is about. When is rayFromTest.getBasis() not identity?
#ifdef USE_SUBSIMPLEX_CONVEX_CAST
//rotate normal into worldspace
castResult.m_normal = rayFromTrans.getBasis() * castResult.m_normal;
@@ -387,14 +389,7 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
triangleMesh->performRaycast(&rcb,rayFromLocal,rayToLocal);
}
- else if(collisionShape->getShapeType()==GIMPACT_SHAPE_PROXYTYPE)
- {
- btGImpactMeshShape* concaveShape = (btGImpactMeshShape*)collisionShape;
-
- BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),concaveShape, colObjWorldTransform);
- rcb.m_hitFraction = resultCallback.m_closestHitFraction;
- concaveShape->processAllTrianglesRay(&rcb,rayFromLocal,rayToLocal);
- }else
+ else
{
//generic (slower) case
btConcaveShape* concaveShape = (btConcaveShape*)collisionShape;
@@ -1251,7 +1246,10 @@ public:
void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color)
{
// Draw a small simplex at the center of the object
- getDebugDrawer()->drawTransform(worldTransform,1);
+ if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawFrames)
+ {
+ getDebugDrawer()->drawTransform(worldTransform,1);
+ }
if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
{
@@ -1429,81 +1427,91 @@ void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const
void btCollisionWorld::debugDrawWorld()
{
- if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)
+ if (getDebugDrawer())
{
- int numManifolds = getDispatcher()->getNumManifolds();
- btVector3 color(1,1,0);
- for (int i=0;i<numManifolds;i++)
+ btIDebugDraw::DefaultColors defaultColors = getDebugDrawer()->getDefaultColors();
+
+ if ( getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)
{
- btPersistentManifold* contactManifold = getDispatcher()->getManifoldByIndexInternal(i);
- //btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
- //btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
+
- int numContacts = contactManifold->getNumContacts();
- for (int j=0;j<numContacts;j++)
+ if (getDispatcher())
{
- btManifoldPoint& cp = contactManifold->getContactPoint(j);
- getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color);
+ int numManifolds = getDispatcher()->getNumManifolds();
+
+ for (int i=0;i<numManifolds;i++)
+ {
+ btPersistentManifold* contactManifold = getDispatcher()->getManifoldByIndexInternal(i);
+ //btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
+ //btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
+
+ int numContacts = contactManifold->getNumContacts();
+ for (int j=0;j<numContacts;j++)
+ {
+ btManifoldPoint& cp = contactManifold->getContactPoint(j);
+ getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),defaultColors.m_contactPoint);
+ }
+ }
}
}
- }
- if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)))
- {
- int i;
-
- for ( i=0;i<m_collisionObjects.size();i++)
+ if ((getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)))
{
- btCollisionObject* colObj = m_collisionObjects[i];
- if ((colObj->getCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0)
+ int i;
+
+ for ( i=0;i<m_collisionObjects.size();i++)
{
- if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe))
+ btCollisionObject* colObj = m_collisionObjects[i];
+ if ((colObj->getCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0)
{
- btVector3 color(btScalar(1.),btScalar(1.),btScalar(1.));
- switch(colObj->getActivationState())
+ if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe))
{
- case ACTIVE_TAG:
- color = btVector3(btScalar(1.),btScalar(1.),btScalar(1.)); break;
- case ISLAND_SLEEPING:
- color = btVector3(btScalar(0.),btScalar(1.),btScalar(0.));break;
- case WANTS_DEACTIVATION:
- color = btVector3(btScalar(0.),btScalar(1.),btScalar(1.));break;
- case DISABLE_DEACTIVATION:
- color = btVector3(btScalar(1.),btScalar(0.),btScalar(0.));break;
- case DISABLE_SIMULATION:
- color = btVector3(btScalar(1.),btScalar(1.),btScalar(0.));break;
- default:
+ btVector3 color(btScalar(0.4),btScalar(0.4),btScalar(0.4));
+
+ switch(colObj->getActivationState())
{
- color = btVector3(btScalar(1),btScalar(0.),btScalar(0.));
- }
- };
+ case ACTIVE_TAG:
+ color = defaultColors.m_activeObject; break;
+ case ISLAND_SLEEPING:
+ color = defaultColors.m_deactivatedObject;break;
+ case WANTS_DEACTIVATION:
+ color = defaultColors.m_wantsDeactivationObject;break;
+ case DISABLE_DEACTIVATION:
+ color = defaultColors.m_disabledDeactivationObject;break;
+ case DISABLE_SIMULATION:
+ color = defaultColors.m_disabledSimulationObject;break;
+ default:
+ {
+ color = btVector3(btScalar(.3),btScalar(0.3),btScalar(0.3));
+ }
+ };
- debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color);
- }
- if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
- {
- btVector3 minAabb,maxAabb;
- btVector3 colorvec(1,0,0);
- colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
- btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold);
- minAabb -= contactThreshold;
- maxAabb += contactThreshold;
+ debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color);
+ }
+ if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
+ {
+ btVector3 minAabb,maxAabb;
+ btVector3 colorvec = defaultColors.m_aabb;
+ colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
+ btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold);
+ minAabb -= contactThreshold;
+ maxAabb += contactThreshold;
- btVector3 minAabb2,maxAabb2;
+ btVector3 minAabb2,maxAabb2;
- if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject())
- {
- colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2);
- minAabb2 -= contactThreshold;
- maxAabb2 += contactThreshold;
- minAabb.setMin(minAabb2);
- maxAabb.setMax(maxAabb2);
- }
+ if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject())
+ {
+ colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2);
+ minAabb2 -= contactThreshold;
+ maxAabb2 += contactThreshold;
+ minAabb.setMin(minAabb2);
+ maxAabb.setMax(maxAabb2);
+ }
- m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec);
+ m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec);
+ }
}
}
-
}
}
}
@@ -1512,15 +1520,6 @@ void btCollisionWorld::debugDrawWorld()
void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
{
int i;
- //serialize all collision objects
- for (i=0;i<m_collisionObjects.size();i++)
- {
- btCollisionObject* colObj = m_collisionObjects[i];
- if (colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT)
- {
- colObj->serializeSingleObject(serializer);
- }
- }
///keep track of shapes already serialized
btHashMap<btHashPtr,btCollisionShape*> serializedShapes;
@@ -1537,6 +1536,15 @@ void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
}
}
+ //serialize all collision objects
+ 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))
+ {
+ colObj->serializeSingleObject(serializer);
+ }
+ }
}
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
index 0ac5563d06e..ec40c969f51 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h
@@ -27,7 +27,7 @@ subject to the following restrictions:
* @section install_sec Installation
*
* @subsection step1 Step 1: Download
- * You can download the Bullet Physics Library from the Google Code repository: http://code.google.com/p/bullet/downloads/list
+ * You can download the Bullet Physics Library from the github repository: https://github.com/bulletphysics/bullet3/releases
*
* @subsection step2 Step 2: Building
* Bullet has multiple build systems, including premake, cmake and autotools. Premake and cmake support all platforms.
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp
new file mode 100644
index 00000000000..57eb81703e7
--- /dev/null
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp
@@ -0,0 +1,1143 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "btCollisionWorldImporter.h"
+#include "btBulletCollisionCommon.h"
+#include "LinearMath/btSerializer.h" //for btBulletSerializedArrays definition
+
+#ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
+#include "BulletCollision/Gimpact/btGImpactShape.h"
+#endif //SUPPORT_GIMPACT_SHAPE_IMPORT
+
+btCollisionWorldImporter::btCollisionWorldImporter(btCollisionWorld* world)
+:m_collisionWorld(world),
+m_verboseMode(0)
+{
+
+}
+
+btCollisionWorldImporter::~btCollisionWorldImporter()
+{
+}
+
+
+
+
+
+bool btCollisionWorldImporter::convertAllObjects( btBulletSerializedArrays* arrays)
+{
+
+ m_shapeMap.clear();
+ m_bodyMap.clear();
+
+ int i;
+
+ for (i=0;i<arrays->m_bvhsDouble.size();i++)
+ {
+ btOptimizedBvh* bvh = createOptimizedBvh();
+ btQuantizedBvhDoubleData* bvhData = arrays->m_bvhsDouble[i];
+ bvh->deSerializeDouble(*bvhData);
+ m_bvhMap.insert(arrays->m_bvhsDouble[i],bvh);
+ }
+ for (i=0;i<arrays->m_bvhsFloat.size();i++)
+ {
+ btOptimizedBvh* bvh = createOptimizedBvh();
+ btQuantizedBvhFloatData* bvhData = arrays->m_bvhsFloat[i];
+ bvh->deSerializeFloat(*bvhData);
+ m_bvhMap.insert(arrays->m_bvhsFloat[i],bvh);
+ }
+
+
+
+
+
+ for (i=0;i<arrays->m_colShapeData.size();i++)
+ {
+ btCollisionShapeData* shapeData = arrays->m_colShapeData[i];
+ btCollisionShape* shape = convertCollisionShape(shapeData);
+ if (shape)
+ {
+ // printf("shapeMap.insert(%x,%x)\n",shapeData,shape);
+ m_shapeMap.insert(shapeData,shape);
+ }
+
+ if (shape&& shapeData->m_name)
+ {
+ char* newname = duplicateName(shapeData->m_name);
+ m_objectNameMap.insert(shape,newname);
+ m_nameShapeMap.insert(newname,shape);
+ }
+ }
+
+
+ for (i=0;i<arrays->m_collisionObjectDataDouble.size();i++)
+ {
+ btCollisionObjectDoubleData* colObjData = arrays->m_collisionObjectDataDouble[i];
+ btCollisionShape** shapePtr = m_shapeMap.find(colObjData->m_collisionShape);
+ if (shapePtr && *shapePtr)
+ {
+ btTransform startTransform;
+ colObjData->m_worldTransform.m_origin.m_floats[3] = 0.f;
+ startTransform.deSerializeDouble(colObjData->m_worldTransform);
+
+ btCollisionShape* shape = (btCollisionShape*)*shapePtr;
+ btCollisionObject* body = createCollisionObject(startTransform,shape,colObjData->m_name);
+ body->setFriction(btScalar(colObjData->m_friction));
+ body->setRestitution(btScalar(colObjData->m_restitution));
+
+#ifdef USE_INTERNAL_EDGE_UTILITY
+ if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ {
+ btBvhTriangleMeshShape* trimesh = (btBvhTriangleMeshShape*)shape;
+ if (trimesh->getTriangleInfoMap())
+ {
+ body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
+ }
+ }
+#endif //USE_INTERNAL_EDGE_UTILITY
+ m_bodyMap.insert(colObjData,body);
+ } else
+ {
+ printf("error: no shape found\n");
+ }
+ }
+ for (i=0;i<arrays->m_collisionObjectDataFloat.size();i++)
+ {
+ btCollisionObjectFloatData* colObjData = arrays->m_collisionObjectDataFloat[i];
+ btCollisionShape** shapePtr = m_shapeMap.find(colObjData->m_collisionShape);
+ if (shapePtr && *shapePtr)
+ {
+ btTransform startTransform;
+ colObjData->m_worldTransform.m_origin.m_floats[3] = 0.f;
+ startTransform.deSerializeFloat(colObjData->m_worldTransform);
+
+ btCollisionShape* shape = (btCollisionShape*)*shapePtr;
+ btCollisionObject* body = createCollisionObject(startTransform,shape,colObjData->m_name);
+
+#ifdef USE_INTERNAL_EDGE_UTILITY
+ if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
+ {
+ btBvhTriangleMeshShape* trimesh = (btBvhTriangleMeshShape*)shape;
+ if (trimesh->getTriangleInfoMap())
+ {
+ body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
+ }
+ }
+#endif //USE_INTERNAL_EDGE_UTILITY
+ m_bodyMap.insert(colObjData,body);
+ } else
+ {
+ printf("error: no shape found\n");
+ }
+ }
+
+ return true;
+}
+
+
+
+void btCollisionWorldImporter::deleteAllData()
+{
+ int i;
+
+ for (i=0;i<m_allocatedCollisionObjects.size();i++)
+ {
+ if(m_collisionWorld)
+ m_collisionWorld->removeCollisionObject(m_allocatedCollisionObjects[i]);
+ delete m_allocatedCollisionObjects[i];
+ }
+
+ m_allocatedCollisionObjects.clear();
+
+
+ for (i=0;i<m_allocatedCollisionShapes.size();i++)
+ {
+ delete m_allocatedCollisionShapes[i];
+ }
+ m_allocatedCollisionShapes.clear();
+
+
+ for (i=0;i<m_allocatedBvhs.size();i++)
+ {
+ delete m_allocatedBvhs[i];
+ }
+ m_allocatedBvhs.clear();
+
+ for (i=0;i<m_allocatedTriangleInfoMaps.size();i++)
+ {
+ delete m_allocatedTriangleInfoMaps[i];
+ }
+ m_allocatedTriangleInfoMaps.clear();
+ for (i=0;i<m_allocatedTriangleIndexArrays.size();i++)
+ {
+ delete m_allocatedTriangleIndexArrays[i];
+ }
+ m_allocatedTriangleIndexArrays.clear();
+ for (i=0;i<m_allocatedNames.size();i++)
+ {
+ delete[] m_allocatedNames[i];
+ }
+ m_allocatedNames.clear();
+
+ for (i=0;i<m_allocatedbtStridingMeshInterfaceDatas.size();i++)
+ {
+ btStridingMeshInterfaceData* curData = m_allocatedbtStridingMeshInterfaceDatas[i];
+
+ for(int a = 0;a < curData->m_numMeshParts;a++)
+ {
+ btMeshPartData* curPart = &curData->m_meshPartsPtr[a];
+ if(curPart->m_vertices3f)
+ delete [] curPart->m_vertices3f;
+
+ if(curPart->m_vertices3d)
+ delete [] curPart->m_vertices3d;
+
+ if(curPart->m_indices32)
+ delete [] curPart->m_indices32;
+
+ if(curPart->m_3indices16)
+ delete [] curPart->m_3indices16;
+
+ if(curPart->m_indices16)
+ delete [] curPart->m_indices16;
+
+ if (curPart->m_3indices8)
+ delete [] curPart->m_3indices8;
+
+ }
+ delete [] curData->m_meshPartsPtr;
+ delete curData;
+ }
+ m_allocatedbtStridingMeshInterfaceDatas.clear();
+
+ for (i=0;i<m_indexArrays.size();i++)
+ {
+ btAlignedFree(m_indexArrays[i]);
+ }
+ m_indexArrays.clear();
+
+ for (i=0;i<m_shortIndexArrays.size();i++)
+ {
+ btAlignedFree(m_shortIndexArrays[i]);
+ }
+ m_shortIndexArrays.clear();
+
+ for (i=0;i<m_charIndexArrays.size();i++)
+ {
+ btAlignedFree(m_charIndexArrays[i]);
+ }
+ m_charIndexArrays.clear();
+
+ for (i=0;i<m_floatVertexArrays.size();i++)
+ {
+ btAlignedFree(m_floatVertexArrays[i]);
+ }
+ m_floatVertexArrays.clear();
+
+ for (i=0;i<m_doubleVertexArrays.size();i++)
+ {
+ btAlignedFree(m_doubleVertexArrays[i]);
+ }
+ m_doubleVertexArrays.clear();
+
+
+}
+
+
+
+btCollisionShape* btCollisionWorldImporter::convertCollisionShape( btCollisionShapeData* shapeData )
+{
+ btCollisionShape* shape = 0;
+
+ switch (shapeData->m_shapeType)
+ {
+ case STATIC_PLANE_PROXYTYPE:
+ {
+ btStaticPlaneShapeData* planeData = (btStaticPlaneShapeData*)shapeData;
+ btVector3 planeNormal,localScaling;
+ planeNormal.deSerializeFloat(planeData->m_planeNormal);
+ localScaling.deSerializeFloat(planeData->m_localScaling);
+ shape = createPlaneShape(planeNormal,planeData->m_planeConstant);
+ shape->setLocalScaling(localScaling);
+
+ break;
+ }
+ case SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
+ {
+ btScaledTriangleMeshShapeData* scaledMesh = (btScaledTriangleMeshShapeData*) shapeData;
+ btCollisionShapeData* colShapeData = (btCollisionShapeData*) &scaledMesh->m_trimeshShapeData;
+ colShapeData->m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE;
+ btCollisionShape* childShape = convertCollisionShape(colShapeData);
+ btBvhTriangleMeshShape* meshShape = (btBvhTriangleMeshShape*)childShape;
+ btVector3 localScaling;
+ localScaling.deSerializeFloat(scaledMesh->m_localScaling);
+
+ shape = createScaledTrangleMeshShape(meshShape, localScaling);
+ break;
+ }
+#ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
+ case GIMPACT_SHAPE_PROXYTYPE:
+ {
+ btGImpactMeshShapeData* gimpactData = (btGImpactMeshShapeData*) shapeData;
+ if (gimpactData->m_gimpactSubType == CONST_GIMPACT_TRIMESH_SHAPE)
+ {
+ btStridingMeshInterfaceData* interfaceData = createStridingMeshInterfaceData(&gimpactData->m_meshInterface);
+ btTriangleIndexVertexArray* meshInterface = createMeshInterface(*interfaceData);
+
+
+ btGImpactMeshShape* gimpactShape = createGimpactShape(meshInterface);
+ btVector3 localScaling;
+ localScaling.deSerializeFloat(gimpactData->m_localScaling);
+ gimpactShape->setLocalScaling(localScaling);
+ gimpactShape->setMargin(btScalar(gimpactData->m_collisionMargin));
+ gimpactShape->updateBound();
+ shape = gimpactShape;
+ } else
+ {
+ printf("unsupported gimpact sub type\n");
+ }
+ break;
+ }
+#endif //SUPPORT_GIMPACT_SHAPE_IMPORT
+ //The btCapsuleShape* API has issue passing the margin/scaling/halfextents unmodified through the API
+ //so deal with this
+ case CAPSULE_SHAPE_PROXYTYPE:
+ {
+ btCapsuleShapeData* capData = (btCapsuleShapeData*)shapeData;
+
+
+ switch (capData->m_upAxis)
+ {
+ case 0:
+ {
+ shape = createCapsuleShapeX(1,1);
+ break;
+ }
+ case 1:
+ {
+ shape = createCapsuleShapeY(1,1);
+ break;
+ }
+ case 2:
+ {
+ shape = createCapsuleShapeZ(1,1);
+ break;
+ }
+ default:
+ {
+ printf("error: wrong up axis for btCapsuleShape\n");
+ }
+
+
+ };
+ if (shape)
+ {
+ btCapsuleShape* cap = (btCapsuleShape*) shape;
+ cap->deSerializeFloat(capData);
+ }
+ break;
+ }
+ case CYLINDER_SHAPE_PROXYTYPE:
+ case CONE_SHAPE_PROXYTYPE:
+ case BOX_SHAPE_PROXYTYPE:
+ case SPHERE_SHAPE_PROXYTYPE:
+ case MULTI_SPHERE_SHAPE_PROXYTYPE:
+ case CONVEX_HULL_SHAPE_PROXYTYPE:
+ {
+ btConvexInternalShapeData* bsd = (btConvexInternalShapeData*)shapeData;
+ btVector3 implicitShapeDimensions;
+ implicitShapeDimensions.deSerializeFloat(bsd->m_implicitShapeDimensions);
+ btVector3 localScaling;
+ localScaling.deSerializeFloat(bsd->m_localScaling);
+ btVector3 margin(bsd->m_collisionMargin,bsd->m_collisionMargin,bsd->m_collisionMargin);
+ switch (shapeData->m_shapeType)
+ {
+ case BOX_SHAPE_PROXYTYPE:
+ {
+ btBoxShape* box= (btBoxShape*)createBoxShape(implicitShapeDimensions/localScaling+margin);
+ //box->initializePolyhedralFeatures();
+ shape = box;
+
+ break;
+ }
+ case SPHERE_SHAPE_PROXYTYPE:
+ {
+ shape = createSphereShape(implicitShapeDimensions.getX());
+ break;
+ }
+
+ case CYLINDER_SHAPE_PROXYTYPE:
+ {
+ btCylinderShapeData* cylData = (btCylinderShapeData*) shapeData;
+ btVector3 halfExtents = implicitShapeDimensions+margin;
+ switch (cylData->m_upAxis)
+ {
+ case 0:
+ {
+ shape = createCylinderShapeX(halfExtents.getY(),halfExtents.getX());
+ break;
+ }
+ case 1:
+ {
+ shape = createCylinderShapeY(halfExtents.getX(),halfExtents.getY());
+ break;
+ }
+ case 2:
+ {
+ shape = createCylinderShapeZ(halfExtents.getX(),halfExtents.getZ());
+ break;
+ }
+ default:
+ {
+ printf("unknown Cylinder up axis\n");
+ }
+
+ };
+
+
+
+ break;
+ }
+ case CONE_SHAPE_PROXYTYPE:
+ {
+ btConeShapeData* conData = (btConeShapeData*) shapeData;
+ btVector3 halfExtents = implicitShapeDimensions;//+margin;
+ switch (conData->m_upIndex)
+ {
+ case 0:
+ {
+ shape = createConeShapeX(halfExtents.getY(),halfExtents.getX());
+ break;
+ }
+ case 1:
+ {
+ shape = createConeShapeY(halfExtents.getX(),halfExtents.getY());
+ break;
+ }
+ case 2:
+ {
+ shape = createConeShapeZ(halfExtents.getX(),halfExtents.getZ());
+ break;
+ }
+ default:
+ {
+ printf("unknown Cone up axis\n");
+ }
+
+ };
+
+
+
+ break;
+ }
+ case MULTI_SPHERE_SHAPE_PROXYTYPE:
+ {
+ btMultiSphereShapeData* mss = (btMultiSphereShapeData*)bsd;
+ int numSpheres = mss->m_localPositionArraySize;
+
+ btAlignedObjectArray<btVector3> tmpPos;
+ btAlignedObjectArray<btScalar> radii;
+ radii.resize(numSpheres);
+ tmpPos.resize(numSpheres);
+ int i;
+ for ( i=0;i<numSpheres;i++)
+ {
+ tmpPos[i].deSerializeFloat(mss->m_localPositionArrayPtr[i].m_pos);
+ radii[i] = mss->m_localPositionArrayPtr[i].m_radius;
+ }
+ shape = createMultiSphereShape(&tmpPos[0],&radii[0],numSpheres);
+ break;
+ }
+ case CONVEX_HULL_SHAPE_PROXYTYPE:
+ {
+ // int sz = sizeof(btConvexHullShapeData);
+ // int sz2 = sizeof(btConvexInternalShapeData);
+ // int sz3 = sizeof(btCollisionShapeData);
+ btConvexHullShapeData* convexData = (btConvexHullShapeData*)bsd;
+ int numPoints = convexData->m_numUnscaledPoints;
+
+ btAlignedObjectArray<btVector3> tmpPoints;
+ tmpPoints.resize(numPoints);
+ int i;
+ for ( i=0;i<numPoints;i++)
+ {
+#ifdef BT_USE_DOUBLE_PRECISION
+ if (convexData->m_unscaledPointsDoublePtr)
+ tmpPoints[i].deSerialize(convexData->m_unscaledPointsDoublePtr[i]);
+ if (convexData->m_unscaledPointsFloatPtr)
+ tmpPoints[i].deSerializeFloat(convexData->m_unscaledPointsFloatPtr[i]);
+#else
+ if (convexData->m_unscaledPointsFloatPtr)
+ tmpPoints[i].deSerialize(convexData->m_unscaledPointsFloatPtr[i]);
+ if (convexData->m_unscaledPointsDoublePtr)
+ tmpPoints[i].deSerializeDouble(convexData->m_unscaledPointsDoublePtr[i]);
+#endif //BT_USE_DOUBLE_PRECISION
+ }
+ btConvexHullShape* hullShape = createConvexHullShape();
+ for (i=0;i<numPoints;i++)
+ {
+ hullShape->addPoint(tmpPoints[i]);
+ }
+ hullShape->setMargin(bsd->m_collisionMargin);
+ //hullShape->initializePolyhedralFeatures();
+ shape = hullShape;
+ break;
+ }
+ default:
+ {
+ printf("error: cannot create shape type (%d)\n",shapeData->m_shapeType);
+ }
+ }
+
+ if (shape)
+ {
+ shape->setMargin(bsd->m_collisionMargin);
+
+ btVector3 localScaling;
+ localScaling.deSerializeFloat(bsd->m_localScaling);
+ shape->setLocalScaling(localScaling);
+
+ }
+ break;
+ }
+ case TRIANGLE_MESH_SHAPE_PROXYTYPE:
+ {
+ btTriangleMeshShapeData* trimesh = (btTriangleMeshShapeData*)shapeData;
+ btStridingMeshInterfaceData* interfaceData = createStridingMeshInterfaceData(&trimesh->m_meshInterface);
+ btTriangleIndexVertexArray* meshInterface = createMeshInterface(*interfaceData);
+ if (!meshInterface->getNumSubParts())
+ {
+ return 0;
+ }
+
+ btVector3 scaling; scaling.deSerializeFloat(trimesh->m_meshInterface.m_scaling);
+ meshInterface->setScaling(scaling);
+
+
+ btOptimizedBvh* bvh = 0;
+#if 1
+ if (trimesh->m_quantizedFloatBvh)
+ {
+ btOptimizedBvh** bvhPtr = m_bvhMap.find(trimesh->m_quantizedFloatBvh);
+ if (bvhPtr && *bvhPtr)
+ {
+ bvh = *bvhPtr;
+ } else
+ {
+ bvh = createOptimizedBvh();
+ bvh->deSerializeFloat(*trimesh->m_quantizedFloatBvh);
+ }
+ }
+ if (trimesh->m_quantizedDoubleBvh)
+ {
+ btOptimizedBvh** bvhPtr = m_bvhMap.find(trimesh->m_quantizedDoubleBvh);
+ if (bvhPtr && *bvhPtr)
+ {
+ bvh = *bvhPtr;
+ } else
+ {
+ bvh = createOptimizedBvh();
+ bvh->deSerializeDouble(*trimesh->m_quantizedDoubleBvh);
+ }
+ }
+#endif
+
+
+ btBvhTriangleMeshShape* trimeshShape = createBvhTriangleMeshShape(meshInterface,bvh);
+ trimeshShape->setMargin(trimesh->m_collisionMargin);
+ shape = trimeshShape;
+
+ if (trimesh->m_triangleInfoMap)
+ {
+ btTriangleInfoMap* map = createTriangleInfoMap();
+ map->deSerialize(*trimesh->m_triangleInfoMap);
+ trimeshShape->setTriangleInfoMap(map);
+
+#ifdef USE_INTERNAL_EDGE_UTILITY
+ gContactAddedCallback = btAdjustInternalEdgeContactsCallback;
+#endif //USE_INTERNAL_EDGE_UTILITY
+
+ }
+
+ //printf("trimesh->m_collisionMargin=%f\n",trimesh->m_collisionMargin);
+ break;
+ }
+ case COMPOUND_SHAPE_PROXYTYPE:
+ {
+ btCompoundShapeData* compoundData = (btCompoundShapeData*)shapeData;
+ btCompoundShape* compoundShape = createCompoundShape();
+
+
+ btAlignedObjectArray<btCollisionShape*> childShapes;
+ for (int i=0;i<compoundData->m_numChildShapes;i++)
+ {
+ btCollisionShapeData* cd = compoundData->m_childShapePtr[i].m_childShape;
+
+ btCollisionShape* childShape = convertCollisionShape(cd);
+ if (childShape)
+ {
+ btTransform localTransform;
+ localTransform.deSerializeFloat(compoundData->m_childShapePtr[i].m_transform);
+ compoundShape->addChildShape(localTransform,childShape);
+ } else
+ {
+#ifdef _DEBUG
+ printf("error: couldn't create childShape for compoundShape\n");
+#endif
+ }
+
+ }
+ shape = compoundShape;
+
+ break;
+ }
+ case SOFTBODY_SHAPE_PROXYTYPE:
+ {
+ return 0;
+ }
+ default:
+ {
+#ifdef _DEBUG
+ printf("unsupported shape type (%d)\n",shapeData->m_shapeType);
+#endif
+ }
+ }
+
+ return shape;
+
+}
+
+
+
+char* btCollisionWorldImporter::duplicateName(const char* name)
+{
+ if (name)
+ {
+ int l = (int)strlen(name);
+ char* newName = new char[l+1];
+ memcpy(newName,name,l);
+ newName[l] = 0;
+ m_allocatedNames.push_back(newName);
+ return newName;
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+btTriangleIndexVertexArray* btCollisionWorldImporter::createMeshInterface(btStridingMeshInterfaceData& meshData)
+{
+ btTriangleIndexVertexArray* meshInterface = createTriangleMeshContainer();
+
+ for (int i=0;i<meshData.m_numMeshParts;i++)
+ {
+ btIndexedMesh meshPart;
+ meshPart.m_numTriangles = meshData.m_meshPartsPtr[i].m_numTriangles;
+ meshPart.m_numVertices = meshData.m_meshPartsPtr[i].m_numVertices;
+
+
+ if (meshData.m_meshPartsPtr[i].m_indices32)
+ {
+ meshPart.m_indexType = PHY_INTEGER;
+ meshPart.m_triangleIndexStride = 3*sizeof(int);
+ int* indexArray = (int*)btAlignedAlloc(sizeof(int)*3*meshPart.m_numTriangles,16);
+ m_indexArrays.push_back(indexArray);
+ for (int j=0;j<3*meshPart.m_numTriangles;j++)
+ {
+ indexArray[j] = meshData.m_meshPartsPtr[i].m_indices32[j].m_value;
+ }
+ meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
+ } else
+ {
+ if (meshData.m_meshPartsPtr[i].m_3indices16)
+ {
+ meshPart.m_indexType = PHY_SHORT;
+ meshPart.m_triangleIndexStride = sizeof(short int)*3;//sizeof(btShortIntIndexTripletData);
+
+ short int* indexArray = (short int*)btAlignedAlloc(sizeof(short int)*3*meshPart.m_numTriangles,16);
+ m_shortIndexArrays.push_back(indexArray);
+
+ for (int j=0;j<meshPart.m_numTriangles;j++)
+ {
+ indexArray[3*j] = meshData.m_meshPartsPtr[i].m_3indices16[j].m_values[0];
+ indexArray[3*j+1] = meshData.m_meshPartsPtr[i].m_3indices16[j].m_values[1];
+ indexArray[3*j+2] = meshData.m_meshPartsPtr[i].m_3indices16[j].m_values[2];
+ }
+
+ meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
+ }
+ if (meshData.m_meshPartsPtr[i].m_indices16)
+ {
+ meshPart.m_indexType = PHY_SHORT;
+ meshPart.m_triangleIndexStride = 3*sizeof(short int);
+ short int* indexArray = (short int*)btAlignedAlloc(sizeof(short int)*3*meshPart.m_numTriangles,16);
+ m_shortIndexArrays.push_back(indexArray);
+ for (int j=0;j<3*meshPart.m_numTriangles;j++)
+ {
+ indexArray[j] = meshData.m_meshPartsPtr[i].m_indices16[j].m_value;
+ }
+
+ meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
+ }
+
+ if (meshData.m_meshPartsPtr[i].m_3indices8)
+ {
+ meshPart.m_indexType = PHY_UCHAR;
+ meshPart.m_triangleIndexStride = sizeof(unsigned char)*3;
+
+ unsigned char* indexArray = (unsigned char*)btAlignedAlloc(sizeof(unsigned char)*3*meshPart.m_numTriangles,16);
+ m_charIndexArrays.push_back(indexArray);
+
+ for (int j=0;j<meshPart.m_numTriangles;j++)
+ {
+ indexArray[3*j] = meshData.m_meshPartsPtr[i].m_3indices8[j].m_values[0];
+ indexArray[3*j+1] = meshData.m_meshPartsPtr[i].m_3indices8[j].m_values[1];
+ indexArray[3*j+2] = meshData.m_meshPartsPtr[i].m_3indices8[j].m_values[2];
+ }
+
+ meshPart.m_triangleIndexBase = (const unsigned char*)indexArray;
+ }
+ }
+
+ if (meshData.m_meshPartsPtr[i].m_vertices3f)
+ {
+ meshPart.m_vertexType = PHY_FLOAT;
+ meshPart.m_vertexStride = sizeof(btVector3FloatData);
+ btVector3FloatData* vertices = (btVector3FloatData*) btAlignedAlloc(sizeof(btVector3FloatData)*meshPart.m_numVertices,16);
+ m_floatVertexArrays.push_back(vertices);
+
+ for (int j=0;j<meshPart.m_numVertices;j++)
+ {
+ vertices[j].m_floats[0] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[0];
+ vertices[j].m_floats[1] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[1];
+ vertices[j].m_floats[2] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[2];
+ vertices[j].m_floats[3] = meshData.m_meshPartsPtr[i].m_vertices3f[j].m_floats[3];
+ }
+ meshPart.m_vertexBase = (const unsigned char*)vertices;
+ } else
+ {
+ meshPart.m_vertexType = PHY_DOUBLE;
+ meshPart.m_vertexStride = sizeof(btVector3DoubleData);
+
+
+ btVector3DoubleData* vertices = (btVector3DoubleData*) btAlignedAlloc(sizeof(btVector3DoubleData)*meshPart.m_numVertices,16);
+ m_doubleVertexArrays.push_back(vertices);
+
+ for (int j=0;j<meshPart.m_numVertices;j++)
+ {
+ vertices[j].m_floats[0] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[0];
+ vertices[j].m_floats[1] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[1];
+ vertices[j].m_floats[2] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[2];
+ vertices[j].m_floats[3] = meshData.m_meshPartsPtr[i].m_vertices3d[j].m_floats[3];
+ }
+ meshPart.m_vertexBase = (const unsigned char*)vertices;
+ }
+
+ if (meshPart.m_triangleIndexBase && meshPart.m_vertexBase)
+ {
+ meshInterface->addIndexedMesh(meshPart,meshPart.m_indexType);
+ }
+ }
+
+ return meshInterface;
+}
+
+
+btStridingMeshInterfaceData* btCollisionWorldImporter::createStridingMeshInterfaceData(btStridingMeshInterfaceData* interfaceData)
+{
+ //create a new btStridingMeshInterfaceData that is an exact copy of shapedata and store it in the WorldImporter
+ btStridingMeshInterfaceData* newData = new btStridingMeshInterfaceData;
+
+ newData->m_scaling = interfaceData->m_scaling;
+ newData->m_numMeshParts = interfaceData->m_numMeshParts;
+ newData->m_meshPartsPtr = new btMeshPartData[newData->m_numMeshParts];
+
+ for(int i = 0;i < newData->m_numMeshParts;i++)
+ {
+ btMeshPartData* curPart = &interfaceData->m_meshPartsPtr[i];
+ btMeshPartData* curNewPart = &newData->m_meshPartsPtr[i];
+
+ curNewPart->m_numTriangles = curPart->m_numTriangles;
+ curNewPart->m_numVertices = curPart->m_numVertices;
+
+ if(curPart->m_vertices3f)
+ {
+ curNewPart->m_vertices3f = new btVector3FloatData[curNewPart->m_numVertices];
+ memcpy(curNewPart->m_vertices3f,curPart->m_vertices3f,sizeof(btVector3FloatData) * curNewPart->m_numVertices);
+ }
+ else
+ curNewPart->m_vertices3f = NULL;
+
+ if(curPart->m_vertices3d)
+ {
+ curNewPart->m_vertices3d = new btVector3DoubleData[curNewPart->m_numVertices];
+ memcpy(curNewPart->m_vertices3d,curPart->m_vertices3d,sizeof(btVector3DoubleData) * curNewPart->m_numVertices);
+ }
+ else
+ curNewPart->m_vertices3d = NULL;
+
+ int numIndices = curNewPart->m_numTriangles * 3;
+ ///the m_3indices8 was not initialized in some Bullet versions, this can cause crashes at loading time
+ ///we catch it by only dealing with m_3indices8 if none of the other indices are initialized
+ bool uninitialized3indices8Workaround =false;
+
+ if(curPart->m_indices32)
+ {
+ uninitialized3indices8Workaround=true;
+ curNewPart->m_indices32 = new btIntIndexData[numIndices];
+ memcpy(curNewPart->m_indices32,curPart->m_indices32,sizeof(btIntIndexData) * numIndices);
+ }
+ else
+ curNewPart->m_indices32 = NULL;
+
+ if(curPart->m_3indices16)
+ {
+ uninitialized3indices8Workaround=true;
+ curNewPart->m_3indices16 = new btShortIntIndexTripletData[curNewPart->m_numTriangles];
+ memcpy(curNewPart->m_3indices16,curPart->m_3indices16,sizeof(btShortIntIndexTripletData) * curNewPart->m_numTriangles);
+ }
+ else
+ curNewPart->m_3indices16 = NULL;
+
+ if(curPart->m_indices16)
+ {
+ uninitialized3indices8Workaround=true;
+ curNewPart->m_indices16 = new btShortIntIndexData[numIndices];
+ memcpy(curNewPart->m_indices16,curPart->m_indices16,sizeof(btShortIntIndexData) * numIndices);
+ }
+ else
+ curNewPart->m_indices16 = NULL;
+
+ if(!uninitialized3indices8Workaround && curPart->m_3indices8)
+ {
+ curNewPart->m_3indices8 = new btCharIndexTripletData[curNewPart->m_numTriangles];
+ memcpy(curNewPart->m_3indices8,curPart->m_3indices8,sizeof(btCharIndexTripletData) * curNewPart->m_numTriangles);
+ }
+ else
+ curNewPart->m_3indices8 = NULL;
+
+ }
+
+ m_allocatedbtStridingMeshInterfaceDatas.push_back(newData);
+
+ return(newData);
+}
+
+#ifdef USE_INTERNAL_EDGE_UTILITY
+extern ContactAddedCallback gContactAddedCallback;
+
+static bool btAdjustInternalEdgeContactsCallback(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1)
+{
+
+ btAdjustInternalEdgeContacts(cp,colObj1,colObj0, partId1,index1);
+ //btAdjustInternalEdgeContacts(cp,colObj1,colObj0, partId1,index1, BT_TRIANGLE_CONVEX_BACKFACE_MODE);
+ //btAdjustInternalEdgeContacts(cp,colObj1,colObj0, partId1,index1, BT_TRIANGLE_CONVEX_DOUBLE_SIDED+BT_TRIANGLE_CONCAVE_DOUBLE_SIDED);
+ return true;
+}
+#endif //USE_INTERNAL_EDGE_UTILITY
+
+
+/*
+btRigidBody* btWorldImporter::createRigidBody(bool isDynamic, btScalar mass, const btTransform& startTransform,btCollisionShape* shape,const char* bodyName)
+{
+ btVector3 localInertia;
+ localInertia.setZero();
+
+ if (mass)
+ shape->calculateLocalInertia(mass,localInertia);
+
+ btRigidBody* body = new btRigidBody(mass,0,shape,localInertia);
+ body->setWorldTransform(startTransform);
+
+ if (m_dynamicsWorld)
+ m_dynamicsWorld->addRigidBody(body);
+
+ if (bodyName)
+ {
+ char* newname = duplicateName(bodyName);
+ m_objectNameMap.insert(body,newname);
+ m_nameBodyMap.insert(newname,body);
+ }
+ m_allocatedRigidBodies.push_back(body);
+ return body;
+
+}
+*/
+
+btCollisionObject* btCollisionWorldImporter::getCollisionObjectByName(const char* name)
+{
+ btCollisionObject** bodyPtr = m_nameColObjMap.find(name);
+ if (bodyPtr && *bodyPtr)
+ {
+ return *bodyPtr;
+ }
+ return 0;
+}
+
+btCollisionObject* btCollisionWorldImporter::createCollisionObject(const btTransform& startTransform,btCollisionShape* shape, const char* bodyName)
+{
+ btCollisionObject* colObj = new btCollisionObject();
+ colObj->setWorldTransform(startTransform);
+ colObj->setCollisionShape(shape);
+ m_collisionWorld->addCollisionObject(colObj);//todo: flags etc
+
+ if (bodyName)
+ {
+ char* newname = duplicateName(bodyName);
+ m_objectNameMap.insert(colObj,newname);
+ m_nameColObjMap.insert(newname,colObj);
+ }
+ m_allocatedCollisionObjects.push_back(colObj);
+
+ return colObj;
+}
+
+
+
+btCollisionShape* btCollisionWorldImporter::createPlaneShape(const btVector3& planeNormal,btScalar planeConstant)
+{
+ btStaticPlaneShape* shape = new btStaticPlaneShape(planeNormal,planeConstant);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+btCollisionShape* btCollisionWorldImporter::createBoxShape(const btVector3& halfExtents)
+{
+ btBoxShape* shape = new btBoxShape(halfExtents);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+btCollisionShape* btCollisionWorldImporter::createSphereShape(btScalar radius)
+{
+ btSphereShape* shape = new btSphereShape(radius);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+
+btCollisionShape* btCollisionWorldImporter::createCapsuleShapeX(btScalar radius, btScalar height)
+{
+ btCapsuleShapeX* shape = new btCapsuleShapeX(radius,height);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createCapsuleShapeY(btScalar radius, btScalar height)
+{
+ btCapsuleShape* shape = new btCapsuleShape(radius,height);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createCapsuleShapeZ(btScalar radius, btScalar height)
+{
+ btCapsuleShapeZ* shape = new btCapsuleShapeZ(radius,height);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createCylinderShapeX(btScalar radius,btScalar height)
+{
+ btCylinderShapeX* shape = new btCylinderShapeX(btVector3(height,radius,radius));
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createCylinderShapeY(btScalar radius,btScalar height)
+{
+ btCylinderShape* shape = new btCylinderShape(btVector3(radius,height,radius));
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createCylinderShapeZ(btScalar radius,btScalar height)
+{
+ btCylinderShapeZ* shape = new btCylinderShapeZ(btVector3(radius,radius,height));
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createConeShapeX(btScalar radius,btScalar height)
+{
+ btConeShapeX* shape = new btConeShapeX(radius,height);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createConeShapeY(btScalar radius,btScalar height)
+{
+ btConeShape* shape = new btConeShape(radius,height);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCollisionShape* btCollisionWorldImporter::createConeShapeZ(btScalar radius,btScalar height)
+{
+ btConeShapeZ* shape = new btConeShapeZ(radius,height);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btTriangleIndexVertexArray* btCollisionWorldImporter::createTriangleMeshContainer()
+{
+ btTriangleIndexVertexArray* in = new btTriangleIndexVertexArray();
+ m_allocatedTriangleIndexArrays.push_back(in);
+ return in;
+}
+
+btOptimizedBvh* btCollisionWorldImporter::createOptimizedBvh()
+{
+ btOptimizedBvh* bvh = new btOptimizedBvh();
+ m_allocatedBvhs.push_back(bvh);
+ return bvh;
+}
+
+
+btTriangleInfoMap* btCollisionWorldImporter::createTriangleInfoMap()
+{
+ btTriangleInfoMap* tim = new btTriangleInfoMap();
+ m_allocatedTriangleInfoMaps.push_back(tim);
+ return tim;
+}
+
+btBvhTriangleMeshShape* btCollisionWorldImporter::createBvhTriangleMeshShape(btStridingMeshInterface* trimesh, btOptimizedBvh* bvh)
+{
+ if (bvh)
+ {
+ btBvhTriangleMeshShape* bvhTriMesh = new btBvhTriangleMeshShape(trimesh,bvh->isQuantized(), false);
+ bvhTriMesh->setOptimizedBvh(bvh);
+ m_allocatedCollisionShapes.push_back(bvhTriMesh);
+ return bvhTriMesh;
+ }
+
+ btBvhTriangleMeshShape* ts = new btBvhTriangleMeshShape(trimesh,true);
+ m_allocatedCollisionShapes.push_back(ts);
+ return ts;
+
+}
+btCollisionShape* btCollisionWorldImporter::createConvexTriangleMeshShape(btStridingMeshInterface* trimesh)
+{
+ return 0;
+}
+#ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
+btGImpactMeshShape* btCollisionWorldImporter::createGimpactShape(btStridingMeshInterface* trimesh)
+{
+ btGImpactMeshShape* shape = new btGImpactMeshShape(trimesh);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+
+}
+#endif //SUPPORT_GIMPACT_SHAPE_IMPORT
+
+btConvexHullShape* btCollisionWorldImporter::createConvexHullShape()
+{
+ btConvexHullShape* shape = new btConvexHullShape();
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btCompoundShape* btCollisionWorldImporter::createCompoundShape()
+{
+ btCompoundShape* shape = new btCompoundShape();
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+
+btScaledBvhTriangleMeshShape* btCollisionWorldImporter::createScaledTrangleMeshShape(btBvhTriangleMeshShape* meshShape,const btVector3& localScaling)
+{
+ btScaledBvhTriangleMeshShape* shape = new btScaledBvhTriangleMeshShape(meshShape,localScaling);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+btMultiSphereShape* btCollisionWorldImporter::createMultiSphereShape(const btVector3* positions,const btScalar* radi,int numSpheres)
+{
+ btMultiSphereShape* shape = new btMultiSphereShape(positions, radi, numSpheres);
+ m_allocatedCollisionShapes.push_back(shape);
+ return shape;
+}
+
+
+
+ // query for data
+int btCollisionWorldImporter::getNumCollisionShapes() const
+{
+ return m_allocatedCollisionShapes.size();
+}
+
+btCollisionShape* btCollisionWorldImporter::getCollisionShapeByIndex(int index)
+{
+ return m_allocatedCollisionShapes[index];
+}
+
+btCollisionShape* btCollisionWorldImporter::getCollisionShapeByName(const char* name)
+{
+ btCollisionShape** shapePtr = m_nameShapeMap.find(name);
+ if (shapePtr&& *shapePtr)
+ {
+ return *shapePtr;
+ }
+ return 0;
+}
+
+
+const char* btCollisionWorldImporter::getNameForPointer(const void* ptr) const
+{
+ const char*const * namePtr = m_objectNameMap.find(ptr);
+ if (namePtr && *namePtr)
+ return *namePtr;
+ return 0;
+}
+
+
+int btCollisionWorldImporter::getNumRigidBodies() const
+{
+ return m_allocatedRigidBodies.size();
+}
+
+btCollisionObject* btCollisionWorldImporter::getRigidBodyByIndex(int index) const
+{
+ return m_allocatedRigidBodies[index];
+}
+
+
+int btCollisionWorldImporter::getNumBvhs() const
+{
+ return m_allocatedBvhs.size();
+}
+ btOptimizedBvh* btCollisionWorldImporter::getBvhByIndex(int index) const
+{
+ return m_allocatedBvhs[index];
+}
+
+int btCollisionWorldImporter::getNumTriangleInfoMaps() const
+{
+ return m_allocatedTriangleInfoMaps.size();
+}
+
+btTriangleInfoMap* btCollisionWorldImporter::getTriangleInfoMapByIndex(int index) const
+{
+ return m_allocatedTriangleInfoMaps[index];
+}
+
+
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h
new file mode 100644
index 00000000000..9a6d16fbea7
--- /dev/null
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h
@@ -0,0 +1,190 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+#ifndef BT_COLLISION_WORLD_IMPORTER_H
+#define BT_COLLISION_WORLD_IMPORTER_H
+
+#include "LinearMath/btTransform.h"
+#include "LinearMath/btVector3.h"
+#include "LinearMath/btAlignedObjectArray.h"
+#include "LinearMath/btHashMap.h"
+
+class btCollisionShape;
+class btCollisionObject;
+struct btBulletSerializedArrays;
+
+
+struct ConstraintInput;
+class btCollisionWorld;
+struct btCollisionShapeData;
+class btTriangleIndexVertexArray;
+class btStridingMeshInterface;
+struct btStridingMeshInterfaceData;
+class btGImpactMeshShape;
+class btOptimizedBvh;
+struct btTriangleInfoMap;
+class btBvhTriangleMeshShape;
+class btPoint2PointConstraint;
+class btHingeConstraint;
+class btConeTwistConstraint;
+class btGeneric6DofConstraint;
+class btGeneric6DofSpringConstraint;
+class btSliderConstraint;
+class btGearConstraint;
+struct btContactSolverInfo;
+
+
+
+
+class btCollisionWorldImporter
+{
+protected:
+ btCollisionWorld* m_collisionWorld;
+
+ int m_verboseMode;
+
+ btAlignedObjectArray<btCollisionShape*> m_allocatedCollisionShapes;
+ btAlignedObjectArray<btCollisionObject*> m_allocatedRigidBodies;
+
+ btAlignedObjectArray<btOptimizedBvh*> m_allocatedBvhs;
+ btAlignedObjectArray<btTriangleInfoMap*> m_allocatedTriangleInfoMaps;
+ btAlignedObjectArray<btTriangleIndexVertexArray*> m_allocatedTriangleIndexArrays;
+ btAlignedObjectArray<btStridingMeshInterfaceData*> m_allocatedbtStridingMeshInterfaceDatas;
+ btAlignedObjectArray<btCollisionObject*> m_allocatedCollisionObjects;
+
+
+ btAlignedObjectArray<char*> m_allocatedNames;
+
+ btAlignedObjectArray<int*> m_indexArrays;
+ btAlignedObjectArray<short int*> m_shortIndexArrays;
+ btAlignedObjectArray<unsigned char*> m_charIndexArrays;
+
+ btAlignedObjectArray<btVector3FloatData*> m_floatVertexArrays;
+ btAlignedObjectArray<btVector3DoubleData*> m_doubleVertexArrays;
+
+
+ btHashMap<btHashPtr,btOptimizedBvh*> m_bvhMap;
+ btHashMap<btHashPtr,btTriangleInfoMap*> m_timMap;
+
+ btHashMap<btHashString,btCollisionShape*> m_nameShapeMap;
+ btHashMap<btHashString,btCollisionObject*> m_nameColObjMap;
+
+ btHashMap<btHashPtr,const char*> m_objectNameMap;
+
+ btHashMap<btHashPtr,btCollisionShape*> m_shapeMap;
+ btHashMap<btHashPtr,btCollisionObject*> m_bodyMap;
+
+
+ //methods
+
+
+
+ char* duplicateName(const char* name);
+
+ btCollisionShape* convertCollisionShape( btCollisionShapeData* shapeData );
+
+
+public:
+
+ btCollisionWorldImporter(btCollisionWorld* world);
+
+ virtual ~btCollisionWorldImporter();
+
+ bool convertAllObjects( btBulletSerializedArrays* arrays);
+
+ ///delete all memory collision shapes, rigid bodies, constraints etc. allocated during the load.
+ ///make sure you don't use the dynamics world containing objects after you call this method
+ virtual void deleteAllData();
+
+ void setVerboseMode(int verboseMode)
+ {
+ m_verboseMode = verboseMode;
+ }
+
+ int getVerboseMode() const
+ {
+ return m_verboseMode;
+ }
+
+ // query for data
+ int getNumCollisionShapes() const;
+ btCollisionShape* getCollisionShapeByIndex(int index);
+ int getNumRigidBodies() const;
+ btCollisionObject* getRigidBodyByIndex(int index) const;
+ int getNumConstraints() const;
+
+ int getNumBvhs() const;
+ btOptimizedBvh* getBvhByIndex(int index) const;
+ int getNumTriangleInfoMaps() const;
+ btTriangleInfoMap* getTriangleInfoMapByIndex(int index) const;
+
+ // queris involving named objects
+ btCollisionShape* getCollisionShapeByName(const char* name);
+ btCollisionObject* getCollisionObjectByName(const char* name);
+
+
+ const char* getNameForPointer(const void* ptr) const;
+
+ ///those virtuals are called by load and can be overridden by the user
+
+
+
+ //bodies
+
+ virtual btCollisionObject* createCollisionObject( const btTransform& startTransform, btCollisionShape* shape,const char* bodyName);
+
+ ///shapes
+
+ virtual btCollisionShape* createPlaneShape(const btVector3& planeNormal,btScalar planeConstant);
+ virtual btCollisionShape* createBoxShape(const btVector3& halfExtents);
+ virtual btCollisionShape* createSphereShape(btScalar radius);
+ virtual btCollisionShape* createCapsuleShapeX(btScalar radius, btScalar height);
+ virtual btCollisionShape* createCapsuleShapeY(btScalar radius, btScalar height);
+ virtual btCollisionShape* createCapsuleShapeZ(btScalar radius, btScalar height);
+
+ virtual btCollisionShape* createCylinderShapeX(btScalar radius,btScalar height);
+ virtual btCollisionShape* createCylinderShapeY(btScalar radius,btScalar height);
+ virtual btCollisionShape* createCylinderShapeZ(btScalar radius,btScalar height);
+ virtual btCollisionShape* createConeShapeX(btScalar radius,btScalar height);
+ virtual btCollisionShape* createConeShapeY(btScalar radius,btScalar height);
+ virtual btCollisionShape* createConeShapeZ(btScalar radius,btScalar height);
+ virtual class btTriangleIndexVertexArray* createTriangleMeshContainer();
+ virtual btBvhTriangleMeshShape* createBvhTriangleMeshShape(btStridingMeshInterface* trimesh, btOptimizedBvh* bvh);
+ virtual btCollisionShape* createConvexTriangleMeshShape(btStridingMeshInterface* trimesh);
+#ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
+ virtual btGImpactMeshShape* createGimpactShape(btStridingMeshInterface* trimesh);
+#endif //SUPPORT_GIMPACT_SHAPE_IMPORT
+ virtual btStridingMeshInterfaceData* createStridingMeshInterfaceData(btStridingMeshInterfaceData* interfaceData);
+
+ virtual class btConvexHullShape* createConvexHullShape();
+ virtual class btCompoundShape* createCompoundShape();
+ virtual class btScaledBvhTriangleMeshShape* createScaledTrangleMeshShape(btBvhTriangleMeshShape* meshShape,const btVector3& localScalingbtBvhTriangleMeshShape);
+
+ virtual class btMultiSphereShape* createMultiSphereShape(const btVector3* positions,const btScalar* radi,int numSpheres);
+
+ virtual btTriangleIndexVertexArray* createMeshInterface(btStridingMeshInterfaceData& meshData);
+
+ ///acceleration and connectivity structures
+ virtual btOptimizedBvh* createOptimizedBvh();
+ virtual btTriangleInfoMap* createTriangleInfoMap();
+
+
+
+
+};
+
+
+#endif //BT_WORLD_IMPORTER_H
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
index 286e6c31f2f..a80c438d12a 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
@@ -123,7 +123,7 @@ public:
//backup
btTransform orgTrans = m_compoundColObjWrap->getWorldTransform();
- btTransform orgInterpolationTrans = m_compoundColObjWrap->getWorldTransform();
+
const btTransform& childTrans = compoundShape->getChildTransform(index);
btTransform newChildWorldTrans = orgTrans*childTrans ;
@@ -232,7 +232,9 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
m_compoundShapeRevision = compoundShape->getUpdateRevision();
}
-
+ 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);
@@ -292,7 +294,7 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
btManifoldArray manifoldArray;
const btCollisionShape* childShape = 0;
btTransform orgTrans;
- btTransform orgInterpolationTrans;
+
btTransform newChildWorldTrans;
btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1;
@@ -302,8 +304,8 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
{
childShape = compoundShape->getChildShape(i);
//if not longer overlapping, remove the algorithm
- orgTrans = colObjWrap->getWorldTransform();
- orgInterpolationTrans = colObjWrap->getWorldTransform();
+ orgTrans = colObjWrap->getWorldTransform();
+
const btTransform& childTrans = compoundShape->getChildTransform(i);
newChildWorldTrans = orgTrans*childTrans ;
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
index 95780fb2d27..1d64d84b87b 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
@@ -112,10 +112,9 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
btManifoldResult* resultOut,
btHashedSimplePairCache* childAlgorithmsCache,
btPersistentManifold* sharedManifold)
- :m_compound0ColObjWrap(compound1ObjWrap),m_compound1ColObjWrap(compound0ObjWrap),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut),
+ :m_numOverlapPairs(0),m_compound0ColObjWrap(compound1ObjWrap),m_compound1ColObjWrap(compound0ObjWrap),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut),
m_childCollisionAlgorithmCache(childAlgorithmsCache),
- m_sharedManifold(sharedManifold),
- m_numOverlapPairs(0)
+ m_sharedManifold(sharedManifold)
{
}
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp
index 4ec9ae71386..1cb3d2e7a14 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp
@@ -47,8 +47,6 @@ subject to the following restrictions:
btConvex2dConvex2dAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
{
- m_numPerturbationIterations = 0;
- m_minimumPointsPerturbationThreshold = 3;
m_simplexSolver = simplexSolver;
m_pdSolver = pdSolver;
}
@@ -57,15 +55,13 @@ btConvex2dConvex2dAlgorithm::CreateFunc::~CreateFunc()
{
}
-btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
+btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int /* numPerturbationIterations */, int /* minimumPointsPerturbationThreshold */)
: btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap),
m_simplexSolver(simplexSolver),
m_pdSolver(pdSolver),
m_ownManifold (false),
m_manifoldPtr(mf),
-m_lowLevelOfDetail(false),
- m_numPerturbationIterations(numPerturbationIterations),
-m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold)
+m_lowLevelOfDetail(false)
{
(void)body0Wrap;
(void)body1Wrap;
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h
index 18d9385a180..24d13367786 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h
@@ -40,9 +40,6 @@ class btConvex2dConvex2dAlgorithm : public btActivatingCollisionAlgorithm
btPersistentManifold* m_manifoldPtr;
bool m_lowLevelOfDetail;
- int m_numPerturbationIterations;
- int m_minimumPointsPerturbationThreshold;
-
public:
btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold);
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
index e23f5f7a88d..912a5285568 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
@@ -88,20 +88,19 @@ partId, int triangleIndex)
//just for debugging purposes
//printf("triangle %d",m_triangleCount++);
- const btCollisionObject* ob = const_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
+
btCollisionAlgorithmConstructionInfo ci;
ci.m_dispatcher1 = m_dispatcher;
- //const btCollisionObject* ob = static_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
-
-
#if 0
+
///debug drawing of the overlapping triangles
if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe ))
{
+ const btCollisionObject* ob = const_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
btVector3 color(1,1,0);
btTransform& tr = ob->getWorldTransform();
m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color);
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp
index c3cacec4a4f..d42f00a637f 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp
@@ -105,12 +105,12 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
int maxSize = sizeof(btConvexConvexAlgorithm);
int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm);
int maxSize3 = sizeof(btCompoundCollisionAlgorithm);
- int sl = sizeof(btConvexSeparatingDistanceUtil);
- sl = sizeof(btGjkPairDetector);
+ int maxSize4 = sizeof(btCompoundCompoundCollisionAlgorithm);
+
int collisionAlgorithmMaxElementSize = btMax(maxSize,constructionInfo.m_customCollisionAlgorithmMaxElementSize);
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2);
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3);
-
+ collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize4);
if (constructionInfo.m_persistentManifoldPool)
{
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
index cfcca5654de..8c8a7c3c1e3 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp
@@ -28,9 +28,7 @@ int gFindSimplePairs =0;
-btHashedSimplePairCache::btHashedSimplePairCache():
- m_blockedForChanges(false)
-{
+btHashedSimplePairCache::btHashedSimplePairCache() {
int initialAllocatedSize= 2;
m_overlappingPairArray.reserve(initialAllocatedSize);
growTables();
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
index e88ef97e968..186964d723e 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h
@@ -55,9 +55,7 @@ extern int gFindSimplePairs;
class btHashedSimplePairCache
{
btSimplePairArray m_overlappingPairArray;
-
- bool m_blockedForChanges;
-
+
protected:
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
index 73fa4e87ea4..6cba442ca5d 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp
@@ -193,7 +193,7 @@ struct btConnectivityProcessor : public btTriangleCallback
btScalar len2 = calculatedEdge.length2();
btScalar correctedAngle(0);
- btVector3 calculatedNormalB = normalA;
+ //btVector3 calculatedNormalB = normalA;
bool isConvex = false;
if (len2<m_triangleInfoMap->m_planarEpsilon)
@@ -213,10 +213,6 @@ struct btConnectivityProcessor : public btTriangleCallback
isConvex = (dotA<0.);
correctedAngle = isConvex ? ang4 : -ang4;
- btQuaternion orn2(calculatedEdge,-correctedAngle);
- calculatedNormalB = btMatrix3x3(orn2)*normalA;
-
-
}
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h
index 493d635539e..1fa4995d160 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h
@@ -39,7 +39,11 @@ ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape
bool m_useQuantizedAabbCompression;
bool m_ownsBvh;
+#ifdef __clang__
+ bool m_pad[11] __attribute__((unused));////need padding due to alignment
+#else
bool m_pad[11];////need padding due to alignment
+#endif
public:
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h
index 7578bb258df..f8c55ace4eb 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h
@@ -117,6 +117,7 @@ public:
///fills the dataBuffer and returns the struct name (and 0 on failure)
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const;
+ SIMD_FORCE_INLINE void deSerializeFloat(struct btCapsuleShapeData* dataBuffer);
};
@@ -181,4 +182,13 @@ SIMD_FORCE_INLINE const char* btCapsuleShape::serialize(void* dataBuffer, btSeri
return "btCapsuleShapeData";
}
+SIMD_FORCE_INLINE void btCapsuleShape::deSerializeFloat(btCapsuleShapeData* dataBuffer)
+{
+ m_implicitShapeDimensions.deSerializeFloat(dataBuffer->m_convexInternalShapeData.m_implicitShapeDimensions);
+ m_collisionMargin = dataBuffer->m_convexInternalShapeData.m_collisionMargin;
+ m_localScaling.deSerializeFloat(dataBuffer->m_convexInternalShapeData.m_localScaling);
+ //it is best to already pre-allocate the matching btCapsuleShape*(X/Z) version to match m_upAxis
+ m_upAxis = dataBuffer->m_upAxis;
+}
+
#endif //BT_CAPSULE_SHAPE_H
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h
index ff017a20671..5e86568005e 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h
@@ -29,12 +29,13 @@ ATTRIBUTE_ALIGNED16(class) btCollisionShape
protected:
int m_shapeType;
void* m_userPointer;
+ int m_userIndex;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
- btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0)
+ btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1)
{
}
@@ -130,6 +131,16 @@ public:
{
return m_userPointer;
}
+ void setUserIndex(int index)
+ {
+ m_userIndex = index;
+ }
+
+ int getUserIndex() const
+ {
+ return m_userIndex;
+ }
+
virtual int calculateSerializeBufferSize() const;
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp
index 0aa75f2bff3..e8c8c336cd2 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp
@@ -18,7 +18,7 @@ subject to the following restrictions:
#include "BulletCollision/BroadphaseCollision/btDbvt.h"
#include "LinearMath/btSerializer.h"
-btCompoundShape::btCompoundShape(bool enableDynamicAabbTree)
+btCompoundShape::btCompoundShape(bool enableDynamicAabbTree, const int initialChildCapacity)
: m_localAabbMin(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)),
m_localAabbMax(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)),
m_dynamicAabbTree(0),
@@ -34,6 +34,8 @@ m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.))
m_dynamicAabbTree = new(mem) btDbvt();
btAssert(mem==m_dynamicAabbTree);
}
+
+ m_children.reserve(initialChildCapacity);
}
@@ -77,8 +79,8 @@ void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisio
if (m_dynamicAabbTree)
{
const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax);
- int index = m_children.size();
- child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index);
+ size_t index = m_children.size();
+ child.m_node = m_dynamicAabbTree->insert(bounds,reinterpret_cast<void*>(index) );
}
m_children.push_back(child);
@@ -312,7 +314,8 @@ void btCompoundShape::createAabbTreeFromChildren()
child.m_childShape->getAabb(child.m_transform,localAabbMin,localAabbMax);
const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax);
- child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index);
+ size_t index2 = index;
+ child.m_node = m_dynamicAabbTree->insert(bounds, reinterpret_cast<void*>(index2) );
}
}
}
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h
index 141034a8e8c..4eef8dba306 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h
@@ -53,6 +53,7 @@ SIMD_FORCE_INLINE bool operator==(const btCompoundShapeChild& c1, const btCompou
/// Currently, removal of child shapes is only supported when disabling the aabb tree (pass 'false' in the constructor of btCompoundShape)
ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape
{
+protected:
btAlignedObjectArray<btCompoundShapeChild> m_children;
btVector3 m_localAabbMin;
btVector3 m_localAabbMax;
@@ -64,13 +65,12 @@ ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape
btScalar m_collisionMargin;
-protected:
btVector3 m_localScaling;
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
- btCompoundShape(bool enableDynamicAabbTree = true);
+ explicit btCompoundShape(bool enableDynamicAabbTree = true, const int initialChildCapacity = 0);
virtual ~btCompoundShape();
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
index f4324c1f401..4f45319a83a 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp
@@ -21,6 +21,7 @@ subject to the following restrictions:
#include "btConvexPolyhedron.h"
#include "LinearMath/btHashMap.h"
+
btConvexPolyhedron::btConvexPolyhedron()
{
@@ -33,7 +34,7 @@ btConvexPolyhedron::~btConvexPolyhedron()
inline bool IsAlmostZero(const btVector3& v)
{
- if(fabsf(v.x())>1e-6 || fabsf(v.y())>1e-6 || fabsf(v.z())>1e-6) return false;
+ if(btFabs(v.x())>1e-6 || btFabs(v.y())>1e-6 || btFabs(v.z())>1e-6) return false;
return true;
}
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp
index fb0d9fdb75a..88018b4c624 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp
@@ -48,7 +48,7 @@ btConvexShape::~btConvexShape()
}
-void btConvexShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const
+void btConvexShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max, btVector3& witnesPtMin,btVector3& witnesPtMax) const
{
btVector3 localAxis = dir*trans.getBasis();
btVector3 vtx1 = trans(localGetSupportingVertex(localAxis));
@@ -56,12 +56,16 @@ void btConvexShape::project(const btTransform& trans, const btVector3& dir, btSc
min = vtx1.dot(dir);
max = vtx2.dot(dir);
-
+ witnesPtMax = vtx2;
+ witnesPtMin = vtx1;
+
if(min>max)
{
btScalar tmp = min;
min = max;
max = tmp;
+ witnesPtMax = vtx1;
+ witnesPtMin = vtx2;
}
}
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h
index 290cd9fd13c..875f2ac195a 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h
@@ -52,7 +52,8 @@ public:
btScalar getMarginNonVirtual () const;
void getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const;
- virtual void project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const;
+
+ virtual void project(const btTransform& trans, const btVector3& dir, btScalar& minProj, btScalar& maxProj, btVector3& witnesPtMin,btVector3& witnesPtMax) const;
//notice that the vectors should be unit length
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
index 26322791d04..441a89c6bb6 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp
@@ -59,15 +59,13 @@ PHY_ScalarType hdt, bool flipQuadEdges
)
{
// validation
- btAssert(heightStickWidth > 1 && "bad width");
- btAssert(heightStickLength > 1 && "bad length");
- btAssert(heightfieldData && "null heightfield data");
+ btAssert(heightStickWidth > 1);// && "bad width");
+ btAssert(heightStickLength > 1);// && "bad length");
+ btAssert(heightfieldData);// && "null heightfield data");
// btAssert(heightScale) -- do we care? Trust caller here
- btAssert(minHeight <= maxHeight && "bad min/max height");
- btAssert(upAxis >= 0 && upAxis < 3 &&
- "bad upAxis--should be in range [0,2]");
- btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT &&
- "Bad height data type enum");
+ btAssert(minHeight <= maxHeight);// && "bad min/max height");
+ btAssert(upAxis >= 0 && upAxis < 3);// && "bad upAxis--should be in range [0,2]");
+ btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT);// && "Bad height data type enum");
// initialize member variables
m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
@@ -110,7 +108,7 @@ PHY_ScalarType hdt, bool flipQuadEdges
default:
{
//need to get valid m_upAxis
- btAssert(0 && "Bad m_upAxis");
+ btAssert(0);// && "Bad m_upAxis");
}
}
@@ -365,14 +363,15 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
{
//first triangle
getVertex(x,j,vertices[0]);
- getVertex(x+1,j,vertices[1]);
- getVertex(x+1,j+1,vertices[2]);
+ getVertex(x, j + 1, vertices[1]);
+ getVertex(x + 1, j + 1, vertices[2]);
callback->processTriangle(vertices,x,j);
//second triangle
// getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman
getVertex(x+1,j+1,vertices[1]);
- getVertex(x,j+1,vertices[2]);
- callback->processTriangle(vertices,x,j);
+ getVertex(x + 1, j, vertices[2]);
+ callback->processTriangle(vertices, x, j);
+
} else
{
//first triangle
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h
index 2b92ab7d1b7..5ebaede4a88 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h
@@ -25,7 +25,6 @@ subject to the following restrictions:
ATTRIBUTE_ALIGNED16(class) btMultimaterialTriangleMeshShape : public btBvhTriangleMeshShape
{
btAlignedObjectArray <btMaterial*> m_materialList;
- int ** m_triangleMaterials;
public:
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
index 38ef8f03706..d17141e3f20 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp
@@ -21,7 +21,7 @@ subject to the following restrictions:
btStaticPlaneShape::btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant)
: btConcaveShape (), m_planeNormal(planeNormal.normalized()),
m_planeConstant(planeConstant),
-m_localScaling(btScalar(0.),btScalar(0.),btScalar(0.))
+m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.))
{
m_shapeType = STATIC_PLANE_PROXYTYPE;
// btAssert( btFuzzyZero(m_planeNormal.length() - btScalar(1.)) );
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp
index 5fbed334ec1..e4de7320930 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp
@@ -75,6 +75,13 @@ void btTriangleMesh::addIndex(int index)
}
}
+void btTriangleMesh::addTriangleIndices(int index1, int index2, int index3 )
+{
+ m_indexedMeshes[0].m_numTriangles++;
+ addIndex( index1 );
+ addIndex( index2 );
+ addIndex( index3 );
+}
int btTriangleMesh::findOrAddVertex(const btVector3& vertex, bool removeDuplicateVertices)
{
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h
index 0afc2321ff0..ac4afa7f6b2 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h
@@ -52,7 +52,10 @@ class btTriangleMesh : public btTriangleIndexVertexArray
///By default addTriangle won't search for duplicate vertices, because the search is very slow for large triangle meshes.
///In general it is better to directly use btTriangleIndexVertexArray instead.
void addTriangle(const btVector3& vertex0,const btVector3& vertex1,const btVector3& vertex2, bool removeDuplicateVertices=false);
-
+
+ ///Add a triangle using its indices. Make sure the indices are pointing within the vertices array, so add the vertices first (and to be sure, avoid removal of duplicate vertices)
+ void addTriangleIndices(int index1, int index2, int index3 );
+
int getNumTriangles() const;
virtual void preallocateVertices(int numverts);
diff --git a/extern/bullet2/src/BulletCollision/Doxyfile b/extern/bullet2/src/BulletCollision/Doxyfile
deleted file mode 100644
index 4ecb6acb62f..00000000000
--- a/extern/bullet2/src/BulletCollision/Doxyfile
+++ /dev/null
@@ -1,746 +0,0 @@
-# Doxyfile 1.2.4
-
-# This file describes the settings to be used by doxygen for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# General configuration options
-#---------------------------------------------------------------------------
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-PROJECT_NAME = "Bullet Continuous Collision Detection Library"
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER =
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY =
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
-# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian,
-# Polish, Portuguese and Slovene.
-
-OUTPUT_LANGUAGE = English
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = YES
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = YES
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these class will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. It is allowed to use relative paths in the argument list.
-
-STRIP_FROM_PATH =
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a class diagram (in Html and LaTeX) for classes with base or
-# super classes. Setting the tag to NO turns the diagrams off.
-
-CLASS_DIAGRAMS = YES
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower case letters. If set to YES upper case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# users are adviced to set this option to NO.
-
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = YES
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explict @brief command for a brief description.
-
-JAVADOC_AUTOBRIEF = YES
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# reimplements.
-
-INHERIT_DOCS = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 8
-
-# The ENABLE_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = .
-
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-FILE_PATTERNS = *.h *.cpp *.c
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE =
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-
-EXCLUDE_PATTERNS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS =
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-
-INPUT_FILTER =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse.
-
-FILTER_SOURCE_FILES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = NO
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet
-
-HTML_STYLESHEET =
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX = NO
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript and frames is required (for instance Netscape 4.0+
-# or Internet explorer 4.0+).
-
-GENERATE_TREEVIEW = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 250
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT = latex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = NO
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimised for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using a WORD or other.
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assigments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION = .3
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation. Warning: This feature
-# is still experimental and very incomplete.
-
-GENERATE_XML = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH = ../../generic/extern
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED =
-
-#---------------------------------------------------------------------------
-# Configuration::addtions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tagfiles.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = NO
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = YES
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other
-# documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented header file showing
-# the documented files that directly or indirectly include this file
-
-INCLUDED_BY_GRAPH = YES
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found on the path.
-
-DOT_PATH =
-
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_WIDTH = 1024
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_HEIGHT = 1024
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-#---------------------------------------------------------------------------
-# Configuration::addtions related to the search engine
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-
-SEARCHENGINE = NO
-
-# The CGI_NAME tag should be the name of the CGI script that
-# starts the search engine (doxysearch) with the correct parameters.
-# A script with this name will be generated by doxygen.
-
-CGI_NAME = search.cgi
-
-# The CGI_URL tag should be the absolute URL to the directory where the
-# cgi binaries are located. See the documentation of your http daemon for
-# details.
-
-CGI_URL =
-
-# The DOC_URL tag should be the absolute URL to the directory where the
-# documentation is located. If left blank the absolute path to the
-# documentation, with file:// prepended to it, will be used.
-
-DOC_URL =
-
-# The DOC_ABSPATH tag should be the absolute path to the directory where the
-# documentation is located. If left blank the directory on the local machine
-# will be used.
-
-DOC_ABSPATH =
-
-# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
-# is installed.
-
-BIN_ABSPATH = c:\program files\doxygen\bin
-
-# The EXT_DOC_PATHS tag can be used to specify one or more paths to
-# documentation generated for other projects. This allows doxysearch to search
-# the documentation for these projects as well.
-
-EXT_DOC_PATHS =
diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h b/extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h
index 915277404d6..d98051da3d6 100644
--- a/extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h
+++ b/extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h
@@ -404,12 +404,12 @@ SIMD_FORCE_INLINE void SEGMENT_COLLISION(
CLASS_POINT & vPointA,
CLASS_POINT & vPointB)
{
- CLASS_POINT _AD,_BD,_N;
+ CLASS_POINT _AD,_BD,n;
vec4f _M;//plane
VEC_DIFF(_AD,vA2,vA1);
VEC_DIFF(_BD,vB2,vB1);
- VEC_CROSS(_N,_AD,_BD);
- GREAL _tp = VEC_DOT(_N,_N);
+ VEC_CROSS(n,_AD,_BD);
+ GREAL _tp = VEC_DOT(n,n);
if(_tp<G_EPSILON)//ARE PARALELE
{
//project B over A
@@ -424,10 +424,10 @@ SIMD_FORCE_INLINE void SEGMENT_COLLISION(
_M[2] = VEC_DOT(vA1,_AD);
_M[3] = VEC_DOT(vA2,_AD);
//mid points
- _N[0] = (_M[0]+_M[1])*0.5f;
- _N[1] = (_M[2]+_M[3])*0.5f;
+ n[0] = (_M[0]+_M[1])*0.5f;
+ n[1] = (_M[2]+_M[3])*0.5f;
- if(_N[0]<_N[1])
+ if(n[0]<n[1])
{
if(_M[1]<_M[2])
{
@@ -467,7 +467,7 @@ SIMD_FORCE_INLINE void SEGMENT_COLLISION(
}
- VEC_CROSS(_M,_N,_BD);
+ VEC_CROSS(_M,n,_BD);
_M[3] = VEC_DOT(_M,vB1);
LINE_PLANE_COLLISION(_M,_AD,vA1,vPointA,_tp,btScalar(0), btScalar(1));
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h
new file mode 100644
index 00000000000..9eb880b8dfc
--- /dev/null
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h
@@ -0,0 +1,369 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H
+#define BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H
+
+#include "LinearMath/btTransform.h" // Note that btVector3 might be double precision...
+#include "btGjkEpa3.h"
+#include "btGjkCollisionDescription.h"
+#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
+
+
+
+
+
+
+template <typename btConvexTemplate>
+bool btGjkEpaCalcPenDepth(const btConvexTemplate& a, const btConvexTemplate& b,
+ const btGjkCollisionDescription& colDesc,
+ btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB)
+{
+ (void)v;
+
+ // const btScalar radialmargin(btScalar(0.));
+
+ btVector3 guessVector(b.getWorldTransform().getOrigin()-a.getWorldTransform().getOrigin());//?? why not use the GJK input?
+
+ btGjkEpaSolver3::sResults results;
+
+
+ if(btGjkEpaSolver3_Penetration(a,b,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
+ {
+ if(btGjkEpaSolver3_Distance(a,b,guessVector,results))
+ {
+ wWitnessOnA = results.witnesses[0];
+ wWitnessOnB = results.witnesses[1];
+ v = results.normal;
+ return false;
+ }
+ }
+ return false;
+}
+
+template <typename btConvexTemplate, typename btGjkDistanceTemplate>
+int btComputeGjkEpaPenetration(const btConvexTemplate& a, const btConvexTemplate& b, const btGjkCollisionDescription& colDesc, btVoronoiSimplexSolver& simplexSolver, btGjkDistanceTemplate* distInfo)
+{
+
+ bool m_catchDegeneracies = true;
+ btScalar m_cachedSeparatingDistance = 0.f;
+
+ btScalar distance=btScalar(0.);
+ btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
+
+ btVector3 pointOnA,pointOnB;
+ btTransform localTransA = a.getWorldTransform();
+ btTransform localTransB = b.getWorldTransform();
+
+ btScalar marginA = a.getMargin();
+ btScalar marginB = b.getMargin();
+
+ int m_curIter = 0;
+ int gGjkMaxIter = colDesc.m_maxGjkIterations;//this is to catch invalid input, perhaps check for #NaN?
+ btVector3 m_cachedSeparatingAxis = colDesc.m_firstDir;
+
+ bool isValid = false;
+ bool checkSimplex = false;
+ bool checkPenetration = true;
+ int m_degenerateSimplex = 0;
+
+ int m_lastUsedMethod = -1;
+
+ {
+ btScalar squaredDistance = BT_LARGE_FLOAT;
+ btScalar delta = btScalar(0.);
+
+ btScalar margin = marginA + marginB;
+
+
+
+ simplexSolver.reset();
+
+ for ( ; ; )
+ //while (true)
+ {
+
+ btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* localTransA.getBasis();
+ btVector3 seperatingAxisInB = m_cachedSeparatingAxis* localTransB.getBasis();
+
+ btVector3 pInA = a.getLocalSupportWithoutMargin(seperatingAxisInA);
+ btVector3 qInB = b.getLocalSupportWithoutMargin(seperatingAxisInB);
+
+ btVector3 pWorld = localTransA(pInA);
+ btVector3 qWorld = localTransB(qInB);
+
+
+
+ btVector3 w = pWorld - qWorld;
+ delta = m_cachedSeparatingAxis.dot(w);
+
+ // potential exit, they don't overlap
+ if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * colDesc.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 (simplexSolver.inSimplex(w))
+ {
+ m_degenerateSimplex = 1;
+ checkSimplex = true;
+ break;
+ }
+ // are we getting any closer ?
+ btScalar f0 = squaredDistance - delta;
+ btScalar f1 = squaredDistance * colDesc.m_gjkRelError2;
+
+ if (f0 <= f1)
+ {
+ if (f0 <= btScalar(0.))
+ {
+ m_degenerateSimplex = 2;
+ } else
+ {
+ m_degenerateSimplex = 11;
+ }
+ checkSimplex = true;
+ break;
+ }
+
+ //add current vertex to simplex
+ simplexSolver.addVertex(w, pWorld, qWorld);
+ btVector3 newCachedSeparatingAxis;
+
+ //calculate the closest point to the origin (update vector v)
+ if (!simplexSolver.closest(newCachedSeparatingAxis))
+ {
+ m_degenerateSimplex = 3;
+ checkSimplex = true;
+ break;
+ }
+
+ if(newCachedSeparatingAxis.length2()<colDesc.m_gjkRelError2)
+ {
+ 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;
+ }
+#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;
+ }
+
+ m_cachedSeparatingAxis = newCachedSeparatingAxis;
+
+ //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
+ if (m_curIter++ > gGjkMaxIter)
+ {
+#if defined(DEBUG) || defined (_DEBUG)
+
+ printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
+ printf("sepAxis=(%f,%f,%f), squaredDistance = %f\n",
+ m_cachedSeparatingAxis.getX(),
+ m_cachedSeparatingAxis.getY(),
+ m_cachedSeparatingAxis.getZ(),
+ squaredDistance);
+#endif
+
+ break;
+
+ }
+
+
+ bool check = (!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)
+ {
+ simplexSolver.compute_points(pointOnA, pointOnB);
+ normalInB = m_cachedSeparatingAxis;
+
+ btScalar lenSqr =m_cachedSeparatingAxis.length2();
+
+ //valid normal
+ if (lenSqr < 0.0001)
+ {
+ 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;
+ }
+ }
+
+ bool catchDegeneratePenetrationCase =
+ (m_catchDegeneracies && m_degenerateSimplex && ((distance+margin) < 0.01));
+
+ //if (checkPenetration && !isValid)
+ if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
+ {
+ //penetration case
+
+ //if there is no way to handle penetrations, bail out
+
+ // Penetration depth case.
+ btVector3 tmpPointOnA,tmpPointOnB;
+
+ m_cachedSeparatingAxis.setZero();
+
+ bool isValid2 = btGjkEpaCalcPenDepth(a,b,
+ colDesc,
+ m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB);
+
+ if (isValid2)
+ {
+ 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();
+ //only replace valid penetrations when the result is deeper (check)
+ if (!isValid || (distance2 < distance))
+ {
+ distance = distance2;
+ pointOnA = tmpPointOnA;
+ pointOnB = tmpPointOnB;
+ normalInB = tmpNormalInB;
+
+ isValid = true;
+ m_lastUsedMethod = 3;
+ } else
+ {
+ m_lastUsedMethod = 8;
+ }
+ } 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
+
+
+ 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
+ {
+ m_lastUsedMethod = 5;
+ }
+ }
+ }
+ }
+ }
+
+
+
+ if (isValid && ((distance < 0) || (distance*distance < colDesc.m_maximumDistanceSquared)))
+ {
+
+ m_cachedSeparatingAxis = normalInB;
+ m_cachedSeparatingDistance = distance;
+ distInfo->m_distance = distance;
+ distInfo->m_normalBtoA = normalInB;
+ distInfo->m_pointOnB = pointOnB;
+ distInfo->m_pointOnA = pointOnB+normalInB*distance;
+ return 0;
+ }
+ return -m_lastUsedMethod;
+}
+
+
+
+
+#endif //BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h
new file mode 100644
index 00000000000..0b49b0ecc65
--- /dev/null
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h
@@ -0,0 +1,41 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+#ifndef GJK_COLLISION_DESCRIPTION_H
+#define GJK_COLLISION_DESCRIPTION_H
+
+#include "LinearMath/btVector3.h"
+
+struct btGjkCollisionDescription
+{
+ btVector3 m_firstDir;
+ int m_maxGjkIterations;
+ btScalar m_maximumDistanceSquared;
+ btScalar m_gjkRelError2;
+ btGjkCollisionDescription()
+ :m_firstDir(0,1,0),
+ m_maxGjkIterations(1000),
+ m_maximumDistanceSquared(1e30f),
+ m_gjkRelError2(1.0e-6)
+ {
+ }
+ virtual ~btGjkCollisionDescription()
+ {
+ }
+};
+
+#endif //GJK_COLLISION_DESCRIPTION_H
+
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h
new file mode 100644
index 00000000000..ce1f24bc50d
--- /dev/null
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h
@@ -0,0 +1,1035 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2014 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.
+*/
+
+/*
+Initial GJK-EPA collision solver by Nathanael Presson, 2008
+Improvements and refactoring by Erwin Coumans, 2008-2014
+*/
+#ifndef BT_GJK_EPA3_H
+#define BT_GJK_EPA3_H
+
+#include "LinearMath/btTransform.h"
+#include "btGjkCollisionDescription.h"
+
+
+
+struct btGjkEpaSolver3
+{
+struct sResults
+ {
+ enum eStatus
+ {
+ Separated, /* Shapes doesnt penetrate */
+ Penetrating, /* Shapes are penetrating */
+ GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */
+ EPA_Failed /* EPA phase fail, bigger problem, need to save parameters, and debug */
+ } status;
+ btVector3 witnesses[2];
+ btVector3 normal;
+ btScalar distance;
+ };
+
+
+};
+
+
+
+#if defined(DEBUG) || defined (_DEBUG)
+#include <stdio.h> //for debug printf
+#ifdef __SPU__
+#include <spu_printf.h>
+#define printf spu_printf
+#endif //__SPU__
+#endif
+
+
+
+ // Config
+
+ /* GJK */
+#define GJK_MAX_ITERATIONS 128
+#define GJK_ACCURARY ((btScalar)0.0001)
+#define GJK_MIN_DISTANCE ((btScalar)0.0001)
+#define GJK_DUPLICATED_EPS ((btScalar)0.0001)
+#define GJK_SIMPLEX2_EPS ((btScalar)0.0)
+#define GJK_SIMPLEX3_EPS ((btScalar)0.0)
+#define GJK_SIMPLEX4_EPS ((btScalar)0.0)
+
+ /* EPA */
+#define EPA_MAX_VERTICES 64
+#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
+#define EPA_MAX_ITERATIONS 255
+#define EPA_ACCURACY ((btScalar)0.0001)
+#define EPA_FALLBACK (10*EPA_ACCURACY)
+#define EPA_PLANE_EPS ((btScalar)0.00001)
+#define EPA_INSIDE_EPS ((btScalar)0.01)
+
+
+ // Shorthands
+ typedef unsigned int U;
+ typedef unsigned char U1;
+
+ // MinkowskiDiff
+ template <typename btConvexTemplate>
+ struct MinkowskiDiff
+ {
+ const btConvexTemplate* m_convexAPtr;
+ const btConvexTemplate* m_convexBPtr;
+
+ btMatrix3x3 m_toshape1;
+ btTransform m_toshape0;
+
+ bool m_enableMargin;
+
+
+ MinkowskiDiff(const btConvexTemplate& a, const btConvexTemplate& b)
+ :m_convexAPtr(&a),
+ m_convexBPtr(&b)
+ {
+ }
+
+ void EnableMargin(bool enable)
+ {
+ m_enableMargin = enable;
+ }
+ inline btVector3 Support0(const btVector3& d) const
+ {
+ return m_convexAPtr->getLocalSupportWithMargin(d);
+ }
+ inline btVector3 Support1(const btVector3& d) const
+ {
+ return m_toshape0*m_convexBPtr->getLocalSupportWithMargin(m_toshape1*d);
+ }
+
+
+ inline btVector3 Support(const btVector3& d) const
+ {
+ return(Support0(d)-Support1(-d));
+ }
+ btVector3 Support(const btVector3& d,U index) const
+ {
+ if(index)
+ return(Support1(d));
+ else
+ return(Support0(d));
+ }
+ };
+
+enum eGjkStatus
+{
+ eGjkValid,
+ eGjkInside,
+ eGjkFailed
+};
+
+ // GJK
+ template <typename btConvexTemplate>
+ struct GJK
+ {
+ /* Types */
+ struct sSV
+ {
+ btVector3 d,w;
+ };
+ struct sSimplex
+ {
+ sSV* c[4];
+ btScalar p[4];
+ U rank;
+ };
+
+ /* Fields */
+
+ MinkowskiDiff<btConvexTemplate> m_shape;
+ btVector3 m_ray;
+ btScalar m_distance;
+ sSimplex m_simplices[2];
+ sSV m_store[4];
+ sSV* m_free[4];
+ U m_nfree;
+ U m_current;
+ sSimplex* m_simplex;
+ eGjkStatus m_status;
+ /* Methods */
+
+ GJK(const btConvexTemplate& a, const btConvexTemplate& b)
+ :m_shape(a,b)
+ {
+ Initialize();
+ }
+ void Initialize()
+ {
+ m_ray = btVector3(0,0,0);
+ m_nfree = 0;
+ m_status = eGjkFailed;
+ m_current = 0;
+ m_distance = 0;
+ }
+ eGjkStatus Evaluate(const MinkowskiDiff<btConvexTemplate>& shapearg,const btVector3& guess)
+ {
+ U iterations=0;
+ btScalar sqdist=0;
+ btScalar alpha=0;
+ btVector3 lastw[4];
+ U clastw=0;
+ /* Initialize solver */
+ m_free[0] = &m_store[0];
+ m_free[1] = &m_store[1];
+ m_free[2] = &m_store[2];
+ m_free[3] = &m_store[3];
+ m_nfree = 4;
+ m_current = 0;
+ m_status = eGjkValid;
+ m_shape = shapearg;
+ m_distance = 0;
+ /* Initialize simplex */
+ m_simplices[0].rank = 0;
+ m_ray = guess;
+ const btScalar sqrl= m_ray.length2();
+ appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0));
+ m_simplices[0].p[0] = 1;
+ m_ray = m_simplices[0].c[0]->w;
+ sqdist = sqrl;
+ lastw[0] =
+ lastw[1] =
+ lastw[2] =
+ lastw[3] = m_ray;
+ /* Loop */
+ do {
+ const U next=1-m_current;
+ sSimplex& cs=m_simplices[m_current];
+ sSimplex& ns=m_simplices[next];
+ /* Check zero */
+ const btScalar rl=m_ray.length();
+ if(rl<GJK_MIN_DISTANCE)
+ {/* Touching or inside */
+ m_status=eGjkInside;
+ break;
+ }
+ /* Append new vertice in -'v' direction */
+ appendvertice(cs,-m_ray);
+ const btVector3& w=cs.c[cs.rank-1]->w;
+ bool found=false;
+ for(U i=0;i<4;++i)
+ {
+ if((w-lastw[i]).length2()<GJK_DUPLICATED_EPS)
+ { found=true;break; }
+ }
+ if(found)
+ {/* Return old simplex */
+ removevertice(m_simplices[m_current]);
+ break;
+ }
+ else
+ {/* Update lastw */
+ lastw[clastw=(clastw+1)&3]=w;
+ }
+ /* Check for termination */
+ const btScalar omega=btDot(m_ray,w)/rl;
+ alpha=btMax(omega,alpha);
+ if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
+ {/* Return old simplex */
+ removevertice(m_simplices[m_current]);
+ break;
+ }
+ /* Reduce simplex */
+ btScalar weights[4];
+ U mask=0;
+ switch(cs.rank)
+ {
+ case 2: sqdist=projectorigin( cs.c[0]->w,
+ cs.c[1]->w,
+ weights,mask);break;
+ case 3: sqdist=projectorigin( cs.c[0]->w,
+ cs.c[1]->w,
+ cs.c[2]->w,
+ weights,mask);break;
+ case 4: sqdist=projectorigin( cs.c[0]->w,
+ cs.c[1]->w,
+ cs.c[2]->w,
+ cs.c[3]->w,
+ weights,mask);break;
+ }
+ if(sqdist>=0)
+ {/* Valid */
+ ns.rank = 0;
+ m_ray = btVector3(0,0,0);
+ m_current = next;
+ for(U i=0,ni=cs.rank;i<ni;++i)
+ {
+ if(mask&(1<<i))
+ {
+ ns.c[ns.rank] = cs.c[i];
+ ns.p[ns.rank++] = weights[i];
+ m_ray += cs.c[i]->w*weights[i];
+ }
+ else
+ {
+ m_free[m_nfree++] = cs.c[i];
+ }
+ }
+ if(mask==15) m_status=eGjkInside;
+ }
+ else
+ {/* Return old simplex */
+ removevertice(m_simplices[m_current]);
+ break;
+ }
+ m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eGjkFailed;
+ } while(m_status==eGjkValid);
+ m_simplex=&m_simplices[m_current];
+ switch(m_status)
+ {
+ case eGjkValid: m_distance=m_ray.length();break;
+ case eGjkInside: m_distance=0;break;
+ default:
+ {
+ }
+ }
+ return(m_status);
+ }
+ bool EncloseOrigin()
+ {
+ switch(m_simplex->rank)
+ {
+ case 1:
+ {
+ for(U i=0;i<3;++i)
+ {
+ btVector3 axis=btVector3(0,0,0);
+ axis[i]=1;
+ appendvertice(*m_simplex, axis);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ appendvertice(*m_simplex,-axis);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ }
+ }
+ break;
+ case 2:
+ {
+ const btVector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w;
+ for(U i=0;i<3;++i)
+ {
+ btVector3 axis=btVector3(0,0,0);
+ axis[i]=1;
+ const btVector3 p=btCross(d,axis);
+ if(p.length2()>0)
+ {
+ appendvertice(*m_simplex, p);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ appendvertice(*m_simplex,-p);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ }
+ }
+ }
+ break;
+ case 3:
+ {
+ const btVector3 n=btCross(m_simplex->c[1]->w-m_simplex->c[0]->w,
+ m_simplex->c[2]->w-m_simplex->c[0]->w);
+ if(n.length2()>0)
+ {
+ appendvertice(*m_simplex,n);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ appendvertice(*m_simplex,-n);
+ if(EncloseOrigin()) return(true);
+ removevertice(*m_simplex);
+ }
+ }
+ break;
+ case 4:
+ {
+ if(btFabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w,
+ m_simplex->c[1]->w-m_simplex->c[3]->w,
+ m_simplex->c[2]->w-m_simplex->c[3]->w))>0)
+ return(true);
+ }
+ break;
+ }
+ return(false);
+ }
+ /* Internals */
+ void getsupport(const btVector3& d,sSV& sv) const
+ {
+ sv.d = d/d.length();
+ sv.w = m_shape.Support(sv.d);
+ }
+ void removevertice(sSimplex& simplex)
+ {
+ m_free[m_nfree++]=simplex.c[--simplex.rank];
+ }
+ void appendvertice(sSimplex& simplex,const btVector3& v)
+ {
+ simplex.p[simplex.rank]=0;
+ simplex.c[simplex.rank]=m_free[--m_nfree];
+ getsupport(v,*simplex.c[simplex.rank++]);
+ }
+ static btScalar det(const btVector3& a,const btVector3& b,const btVector3& c)
+ {
+ return( a.y()*b.z()*c.x()+a.z()*b.x()*c.y()-
+ a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+
+ a.x()*b.y()*c.z()-a.z()*b.y()*c.x());
+ }
+ static btScalar projectorigin( const btVector3& a,
+ const btVector3& b,
+ btScalar* w,U& m)
+ {
+ const btVector3 d=b-a;
+ const btScalar l=d.length2();
+ if(l>GJK_SIMPLEX2_EPS)
+ {
+ const btScalar t(l>0?-btDot(a,d)/l:0);
+ if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); }
+ else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); }
+ else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); }
+ }
+ return(-1);
+ }
+ static btScalar projectorigin( const btVector3& a,
+ const btVector3& b,
+ const btVector3& c,
+ btScalar* w,U& m)
+ {
+ static const U imd3[]={1,2,0};
+ const btVector3* vt[]={&a,&b,&c};
+ const btVector3 dl[]={a-b,b-c,c-a};
+ const btVector3 n=btCross(dl[0],dl[1]);
+ const btScalar l=n.length2();
+ if(l>GJK_SIMPLEX3_EPS)
+ {
+ btScalar mindist=-1;
+ btScalar subw[2]={0.f,0.f};
+ U subm(0);
+ for(U i=0;i<3;++i)
+ {
+ if(btDot(*vt[i],btCross(dl[i],n))>0)
+ {
+ const U j=imd3[i];
+ const btScalar subd(projectorigin(*vt[i],*vt[j],subw,subm));
+ if((mindist<0)||(subd<mindist))
+ {
+ mindist = subd;
+ m = static_cast<U>(((subm&1)?1<<i:0)+((subm&2)?1<<j:0));
+ w[i] = subw[0];
+ w[j] = subw[1];
+ w[imd3[j]] = 0;
+ }
+ }
+ }
+ if(mindist<0)
+ {
+ const btScalar d=btDot(a,n);
+ const btScalar s=btSqrt(l);
+ const btVector3 p=n*(d/l);
+ mindist = p.length2();
+ m = 7;
+ w[0] = (btCross(dl[1],b-p)).length()/s;
+ w[1] = (btCross(dl[2],c-p)).length()/s;
+ w[2] = 1-(w[0]+w[1]);
+ }
+ return(mindist);
+ }
+ return(-1);
+ }
+ static btScalar projectorigin( const btVector3& a,
+ const btVector3& b,
+ const btVector3& c,
+ const btVector3& d,
+ btScalar* w,U& m)
+ {
+ static const U imd3[]={1,2,0};
+ const btVector3* vt[]={&a,&b,&c,&d};
+ const btVector3 dl[]={a-d,b-d,c-d};
+ const btScalar vl=det(dl[0],dl[1],dl[2]);
+ const bool ng=(vl*btDot(a,btCross(b-c,a-b)))<=0;
+ if(ng&&(btFabs(vl)>GJK_SIMPLEX4_EPS))
+ {
+ btScalar mindist=-1;
+ btScalar subw[3]={0.f,0.f,0.f};
+ U subm(0);
+ for(U i=0;i<3;++i)
+ {
+ const U j=imd3[i];
+ const btScalar s=vl*btDot(d,btCross(dl[i],dl[j]));
+ if(s>0)
+ {
+ const btScalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm);
+ if((mindist<0)||(subd<mindist))
+ {
+ mindist = subd;
+ m = static_cast<U>((subm&1?1<<i:0)+
+ (subm&2?1<<j:0)+
+ (subm&4?8:0));
+ w[i] = subw[0];
+ w[j] = subw[1];
+ w[imd3[j]] = 0;
+ w[3] = subw[2];
+ }
+ }
+ }
+ if(mindist<0)
+ {
+ mindist = 0;
+ m = 15;
+ w[0] = det(c,b,d)/vl;
+ w[1] = det(a,c,d)/vl;
+ w[2] = det(b,a,d)/vl;
+ w[3] = 1-(w[0]+w[1]+w[2]);
+ }
+ return(mindist);
+ }
+ return(-1);
+ }
+ };
+
+
+enum eEpaStatus
+{
+ eEpaValid,
+ eEpaTouching,
+ eEpaDegenerated,
+ eEpaNonConvex,
+ eEpaInvalidHull,
+ eEpaOutOfFaces,
+ eEpaOutOfVertices,
+ eEpaAccuraryReached,
+ eEpaFallBack,
+ eEpaFailed
+};
+
+
+ // EPA
+template <typename btConvexTemplate>
+ struct EPA
+ {
+ /* Types */
+
+ struct sFace
+ {
+ btVector3 n;
+ btScalar d;
+ typename GJK<btConvexTemplate>::sSV* c[3];
+ sFace* f[3];
+ sFace* l[2];
+ U1 e[3];
+ U1 pass;
+ };
+ struct sList
+ {
+ sFace* root;
+ U count;
+ sList() : root(0),count(0) {}
+ };
+ struct sHorizon
+ {
+ sFace* cf;
+ sFace* ff;
+ U nf;
+ sHorizon() : cf(0),ff(0),nf(0) {}
+ };
+
+ /* Fields */
+ eEpaStatus m_status;
+ typename GJK<btConvexTemplate>::sSimplex m_result;
+ btVector3 m_normal;
+ btScalar m_depth;
+ typename GJK<btConvexTemplate>::sSV m_sv_store[EPA_MAX_VERTICES];
+ sFace m_fc_store[EPA_MAX_FACES];
+ U m_nextsv;
+ sList m_hull;
+ sList m_stock;
+ /* Methods */
+ EPA()
+ {
+ Initialize();
+ }
+
+
+ static inline void bind(sFace* fa,U ea,sFace* fb,U eb)
+ {
+ fa->e[ea]=(U1)eb;fa->f[ea]=fb;
+ fb->e[eb]=(U1)ea;fb->f[eb]=fa;
+ }
+ static inline void append(sList& list,sFace* face)
+ {
+ face->l[0] = 0;
+ face->l[1] = list.root;
+ if(list.root) list.root->l[0]=face;
+ list.root = face;
+ ++list.count;
+ }
+ static inline void remove(sList& list,sFace* face)
+ {
+ if(face->l[1]) face->l[1]->l[0]=face->l[0];
+ if(face->l[0]) face->l[0]->l[1]=face->l[1];
+ if(face==list.root) list.root=face->l[1];
+ --list.count;
+ }
+
+
+ void Initialize()
+ {
+ m_status = eEpaFailed;
+ m_normal = btVector3(0,0,0);
+ m_depth = 0;
+ m_nextsv = 0;
+ for(U i=0;i<EPA_MAX_FACES;++i)
+ {
+ append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);
+ }
+ }
+ eEpaStatus Evaluate(GJK<btConvexTemplate>& gjk,const btVector3& guess)
+ {
+ typename GJK<btConvexTemplate>::sSimplex& simplex=*gjk.m_simplex;
+ if((simplex.rank>1)&&gjk.EncloseOrigin())
+ {
+
+ /* Clean up */
+ while(m_hull.root)
+ {
+ sFace* f = m_hull.root;
+ remove(m_hull,f);
+ append(m_stock,f);
+ }
+ m_status = eEpaValid;
+ m_nextsv = 0;
+ /* Orient simplex */
+ if(gjk.det( simplex.c[0]->w-simplex.c[3]->w,
+ simplex.c[1]->w-simplex.c[3]->w,
+ simplex.c[2]->w-simplex.c[3]->w)<0)
+ {
+ btSwap(simplex.c[0],simplex.c[1]);
+ btSwap(simplex.p[0],simplex.p[1]);
+ }
+ /* Build initial hull */
+ sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),
+ newface(simplex.c[1],simplex.c[0],simplex.c[3],true),
+ newface(simplex.c[2],simplex.c[1],simplex.c[3],true),
+ newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};
+ if(m_hull.count==4)
+ {
+ sFace* best=findbest();
+ sFace outer=*best;
+ U pass=0;
+ U iterations=0;
+ bind(tetra[0],0,tetra[1],0);
+ bind(tetra[0],1,tetra[2],0);
+ bind(tetra[0],2,tetra[3],0);
+ bind(tetra[1],1,tetra[3],2);
+ bind(tetra[1],2,tetra[2],1);
+ bind(tetra[2],2,tetra[3],1);
+ m_status=eEpaValid;
+ for(;iterations<EPA_MAX_ITERATIONS;++iterations)
+ {
+ if(m_nextsv<EPA_MAX_VERTICES)
+ {
+ sHorizon horizon;
+ typename GJK<btConvexTemplate>::sSV* w=&m_sv_store[m_nextsv++];
+ bool valid=true;
+ best->pass = (U1)(++pass);
+ gjk.getsupport(best->n,*w);
+ const btScalar wdist=btDot(best->n,w->w)-best->d;
+ if(wdist>EPA_ACCURACY)
+ {
+ for(U j=0;(j<3)&&valid;++j)
+ {
+ valid&=expand( pass,w,
+ best->f[j],best->e[j],
+ horizon);
+ }
+ if(valid&&(horizon.nf>=3))
+ {
+ bind(horizon.cf,1,horizon.ff,2);
+ remove(m_hull,best);
+ append(m_stock,best);
+ best=findbest();
+ outer=*best;
+ } else { m_status=eEpaInvalidHull;break; }
+ } else { m_status=eEpaAccuraryReached;break; }
+ } else { m_status=eEpaOutOfVertices;break; }
+ }
+ const btVector3 projection=outer.n*outer.d;
+ m_normal = outer.n;
+ m_depth = outer.d;
+ m_result.rank = 3;
+ m_result.c[0] = outer.c[0];
+ m_result.c[1] = outer.c[1];
+ m_result.c[2] = outer.c[2];
+ m_result.p[0] = btCross( outer.c[1]->w-projection,
+ outer.c[2]->w-projection).length();
+ m_result.p[1] = btCross( outer.c[2]->w-projection,
+ outer.c[0]->w-projection).length();
+ m_result.p[2] = btCross( outer.c[0]->w-projection,
+ outer.c[1]->w-projection).length();
+ const btScalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2];
+ m_result.p[0] /= sum;
+ m_result.p[1] /= sum;
+ m_result.p[2] /= sum;
+ return(m_status);
+ }
+ }
+ /* Fallback */
+ m_status = eEpaFallBack;
+ m_normal = -guess;
+ const btScalar nl=m_normal.length();
+ if(nl>0)
+ m_normal = m_normal/nl;
+ else
+ m_normal = btVector3(1,0,0);
+ m_depth = 0;
+ m_result.rank=1;
+ m_result.c[0]=simplex.c[0];
+ m_result.p[0]=1;
+ return(m_status);
+ }
+ bool getedgedist(sFace* face, typename GJK<btConvexTemplate>::sSV* a, typename GJK<btConvexTemplate>::sSV* b, btScalar& dist)
+ {
+ const btVector3 ba = b->w - a->w;
+ const btVector3 n_ab = btCross(ba, face->n); // Outward facing edge normal direction, on triangle plane
+ const btScalar a_dot_nab = btDot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required
+
+ if(a_dot_nab < 0)
+ {
+ // Outside of edge a->b
+
+ const btScalar ba_l2 = ba.length2();
+ const btScalar a_dot_ba = btDot(a->w, ba);
+ const btScalar b_dot_ba = btDot(b->w, ba);
+
+ if(a_dot_ba > 0)
+ {
+ // Pick distance vertex a
+ dist = a->w.length();
+ }
+ else if(b_dot_ba < 0)
+ {
+ // Pick distance vertex b
+ dist = b->w.length();
+ }
+ else
+ {
+ // Pick distance to edge a->b
+ const btScalar a_dot_b = btDot(a->w, b->w);
+ dist = btSqrt(btMax((a->w.length2() * b->w.length2() - a_dot_b * a_dot_b) / ba_l2, (btScalar)0));
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ sFace* newface(typename GJK<btConvexTemplate>::sSV* a,typename GJK<btConvexTemplate>::sSV* b,typename GJK<btConvexTemplate>::sSV* c,bool forced)
+ {
+ if(m_stock.root)
+ {
+ sFace* face=m_stock.root;
+ remove(m_stock,face);
+ append(m_hull,face);
+ face->pass = 0;
+ face->c[0] = a;
+ face->c[1] = b;
+ face->c[2] = c;
+ face->n = btCross(b->w-a->w,c->w-a->w);
+ const btScalar l=face->n.length();
+ const bool v=l>EPA_ACCURACY;
+
+ if(v)
+ {
+ if(!(getedgedist(face, a, b, face->d) ||
+ getedgedist(face, b, c, face->d) ||
+ getedgedist(face, c, a, face->d)))
+ {
+ // Origin projects to the interior of the triangle
+ // Use distance to triangle plane
+ face->d = btDot(a->w, face->n) / l;
+ }
+
+ face->n /= l;
+ if(forced || (face->d >= -EPA_PLANE_EPS))
+ {
+ return face;
+ }
+ else
+ m_status=eEpaNonConvex;
+ }
+ else
+ m_status=eEpaDegenerated;
+
+ remove(m_hull, face);
+ append(m_stock, face);
+ return 0;
+
+ }
+ m_status = m_stock.root ? eEpaOutOfVertices : eEpaOutOfFaces;
+ return 0;
+ }
+ sFace* findbest()
+ {
+ sFace* minf=m_hull.root;
+ btScalar mind=minf->d*minf->d;
+ for(sFace* f=minf->l[1];f;f=f->l[1])
+ {
+ const btScalar sqd=f->d*f->d;
+ if(sqd<mind)
+ {
+ minf=f;
+ mind=sqd;
+ }
+ }
+ return(minf);
+ }
+ bool expand(U pass,typename GJK<btConvexTemplate>::sSV* w,sFace* f,U e,sHorizon& horizon)
+ {
+ static const U i1m3[]={1,2,0};
+ static const U i2m3[]={2,0,1};
+ if(f->pass!=pass)
+ {
+ const U e1=i1m3[e];
+ if((btDot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)
+ {
+ sFace* nf=newface(f->c[e1],f->c[e],w,false);
+ if(nf)
+ {
+ bind(nf,0,f,e);
+ if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf;
+ horizon.cf=nf;
+ ++horizon.nf;
+ return(true);
+ }
+ }
+ else
+ {
+ const U e2=i2m3[e];
+ f->pass = (U1)pass;
+ if( expand(pass,w,f->f[e1],f->e[e1],horizon)&&
+ expand(pass,w,f->f[e2],f->e[e2],horizon))
+ {
+ remove(m_hull,f);
+ append(m_stock,f);
+ return(true);
+ }
+ }
+ }
+ return(false);
+ }
+
+ };
+
+ template <typename btConvexTemplate>
+ static void Initialize( const btConvexTemplate& a, const btConvexTemplate& b,
+ btGjkEpaSolver3::sResults& results,
+ MinkowskiDiff<btConvexTemplate>& shape)
+ {
+ /* Results */
+ results.witnesses[0] =
+ results.witnesses[1] = btVector3(0,0,0);
+ results.status = btGjkEpaSolver3::sResults::Separated;
+ /* Shape */
+
+ shape.m_toshape1 = b.getWorldTransform().getBasis().transposeTimes(a.getWorldTransform().getBasis());
+ shape.m_toshape0 = a.getWorldTransform().inverseTimes(b.getWorldTransform());
+
+ }
+
+
+//
+// Api
+//
+
+
+
+//
+template <typename btConvexTemplate>
+bool btGjkEpaSolver3_Distance(const btConvexTemplate& a, const btConvexTemplate& b,
+ const btVector3& guess,
+ btGjkEpaSolver3::sResults& results)
+{
+ MinkowskiDiff<btConvexTemplate> shape(a,b);
+ Initialize(a,b,results,shape);
+ GJK<btConvexTemplate> gjk(a,b);
+ eGjkStatus gjk_status=gjk.Evaluate(shape,guess);
+ if(gjk_status==eGjkValid)
+ {
+ btVector3 w0=btVector3(0,0,0);
+ btVector3 w1=btVector3(0,0,0);
+ for(U i=0;i<gjk.m_simplex->rank;++i)
+ {
+ const btScalar p=gjk.m_simplex->p[i];
+ w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
+ w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
+ }
+ results.witnesses[0] = a.getWorldTransform()*w0;
+ results.witnesses[1] = a.getWorldTransform()*w1;
+ results.normal = w0-w1;
+ results.distance = results.normal.length();
+ results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1;
+ return(true);
+ }
+ else
+ {
+ results.status = gjk_status==eGjkInside?
+ btGjkEpaSolver3::sResults::Penetrating :
+ btGjkEpaSolver3::sResults::GJK_Failed ;
+ return(false);
+ }
+}
+
+
+template <typename btConvexTemplate>
+bool btGjkEpaSolver3_Penetration(const btConvexTemplate& a,
+ const btConvexTemplate& b,
+ const btVector3& guess,
+ btGjkEpaSolver3::sResults& results)
+{
+ MinkowskiDiff<btConvexTemplate> shape(a,b);
+ Initialize(a,b,results,shape);
+ GJK<btConvexTemplate> gjk(a,b);
+ eGjkStatus gjk_status=gjk.Evaluate(shape,-guess);
+ switch(gjk_status)
+ {
+ case eGjkInside:
+ {
+ EPA<btConvexTemplate> epa;
+ eEpaStatus epa_status=epa.Evaluate(gjk,-guess);
+ if(epa_status!=eEpaFailed)
+ {
+ btVector3 w0=btVector3(0,0,0);
+ for(U i=0;i<epa.m_result.rank;++i)
+ {
+ w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];
+ }
+ results.status = btGjkEpaSolver3::sResults::Penetrating;
+ results.witnesses[0] = a.getWorldTransform()*w0;
+ results.witnesses[1] = a.getWorldTransform()*(w0-epa.m_normal*epa.m_depth);
+ results.normal = -epa.m_normal;
+ results.distance = -epa.m_depth;
+ return(true);
+ } else results.status=btGjkEpaSolver3::sResults::EPA_Failed;
+ }
+ break;
+ case eGjkFailed:
+ results.status=btGjkEpaSolver3::sResults::GJK_Failed;
+ break;
+ default:
+ {
+ }
+ }
+ return(false);
+}
+
+#if 0
+int btComputeGjkEpaPenetration2(const btCollisionDescription& colDesc, btDistanceInfo* distInfo)
+{
+ btGjkEpaSolver3::sResults results;
+ btVector3 guess = colDesc.m_firstDir;
+
+ bool res = btGjkEpaSolver3::Penetration(colDesc.m_objA,colDesc.m_objB,
+ colDesc.m_transformA,colDesc.m_transformB,
+ colDesc.m_localSupportFuncA,colDesc.m_localSupportFuncB,
+ guess,
+ results);
+ if (res)
+ {
+ if ((results.status==btGjkEpaSolver3::sResults::Penetrating) || results.status==GJK::eStatus::Inside)
+ {
+ //normal could be 'swapped'
+
+ distInfo->m_distance = results.distance;
+ distInfo->m_normalBtoA = results.normal;
+ btVector3 tmpNormalInB = results.witnesses[1]-results.witnesses[0];
+ btScalar lenSqr = tmpNormalInB.length2();
+ if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ tmpNormalInB = results.normal;
+ lenSqr = results.normal.length2();
+ }
+
+ if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
+ {
+ tmpNormalInB /= btSqrt(lenSqr);
+ btScalar distance2 = -(results.witnesses[0]-results.witnesses[1]).length();
+ //only replace valid penetrations when the result is deeper (check)
+ //if ((distance2 < results.distance))
+ {
+ distInfo->m_distance = distance2;
+ distInfo->m_pointOnA= results.witnesses[0];
+ distInfo->m_pointOnB= results.witnesses[1];
+ distInfo->m_normalBtoA= tmpNormalInB;
+ return 0;
+ }
+ }
+ }
+
+ }
+
+ return -1;
+}
+#endif
+
+template <typename btConvexTemplate, typename btDistanceInfoTemplate>
+int btComputeGjkDistance(const btConvexTemplate& a, const btConvexTemplate& b,
+ const btGjkCollisionDescription& colDesc, btDistanceInfoTemplate* distInfo)
+{
+ btGjkEpaSolver3::sResults results;
+ btVector3 guess = colDesc.m_firstDir;
+
+ bool isSeparated = btGjkEpaSolver3_Distance( a,b,
+ guess,
+ results);
+ if (isSeparated)
+ {
+ distInfo->m_distance = results.distance;
+ distInfo->m_pointOnA= results.witnesses[0];
+ distInfo->m_pointOnB= results.witnesses[1];
+ distInfo->m_normalBtoA= results.normal;
+ return 0;
+ }
+
+ return -1;
+}
+
+/* Symbols cleanup */
+
+#undef GJK_MAX_ITERATIONS
+#undef GJK_ACCURARY
+#undef GJK_MIN_DISTANCE
+#undef GJK_DUPLICATED_EPS
+#undef GJK_SIMPLEX2_EPS
+#undef GJK_SIMPLEX3_EPS
+#undef GJK_SIMPLEX4_EPS
+
+#undef EPA_MAX_VERTICES
+#undef EPA_MAX_FACES
+#undef EPA_MAX_ITERATIONS
+#undef EPA_ACCURACY
+#undef EPA_FALLBACK
+#undef EPA_PLANE_EPS
+#undef EPA_INSIDE_EPS
+
+
+
+#endif //BT_GJK_EPA3_H
+
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
index 8877579496b..759443a9613 100644
--- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp
@@ -26,7 +26,6 @@ subject to the following restrictions:
#ifdef __SPU__
#include <spu_printf.h>
#define printf spu_printf
-//#define DEBUG_SPU_COLLISION_DETECTION 1
#endif //__SPU__
#endif
@@ -81,17 +80,18 @@ void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result&
#ifdef __SPU__
void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
#else
-void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
+void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input, Result& output, class btIDebugDraw* debugDraw)
#endif
{
m_cachedSeparatingDistance = 0.f;
btScalar distance=btScalar(0.);
btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
+
btVector3 pointOnA,pointOnB;
btTransform localTransA = input.m_transformA;
btTransform localTransB = input.m_transformB;
- btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
+ btVector3 positionOffset=(localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
localTransA.getOrigin() -= positionOffset;
localTransB.getOrigin() -= positionOffset;
@@ -102,17 +102,11 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
gNumGjkChecks++;
-#ifdef DEBUG_SPU_COLLISION_DETECTION
- spu_printf("inside gjk\n");
-#endif
//for CCD we don't use margins
if (m_ignoreMargin)
{
marginA = btScalar(0.);
marginB = btScalar(0.);
-#ifdef DEBUG_SPU_COLLISION_DETECTION
- spu_printf("ignoring margin\n");
-#endif
}
m_curIter = 0;
@@ -143,37 +137,13 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
-#if 1
-
- btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
- btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
-
-// btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
-// btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
-#else
-#ifdef __SPU__
btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
-#else
- btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
- btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
-#ifdef TEST_NON_VIRTUAL
- btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
- btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
- btAssert((pInAv-pInA).length() < 0.0001);
- btAssert((qInBv-qInB).length() < 0.0001);
-#endif //
-#endif //__SPU__
-#endif
-
btVector3 pWorld = localTransA(pInA);
btVector3 qWorld = localTransB(qInB);
-#ifdef DEBUG_SPU_COLLISION_DETECTION
- spu_printf("got local supporting vertices\n");
-#endif
if (check2d)
{
@@ -217,14 +187,8 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
break;
}
-#ifdef DEBUG_SPU_COLLISION_DETECTION
- spu_printf("addVertex 1\n");
-#endif
//add current vertex to simplex
m_simplexSolver->addVertex(w, pWorld, qWorld);
-#ifdef DEBUG_SPU_COLLISION_DETECTION
- spu_printf("addVertex 2\n");
-#endif
btVector3 newCachedSeparatingAxis;
//calculate the closest point to the origin (update vector v)
@@ -274,7 +238,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
//degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
if (m_curIter++ > gGjkMaxIter)
{
- #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
+ #if defined(DEBUG) || defined (_DEBUG)
printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
@@ -307,6 +271,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
{
m_simplexSolver->compute_points(pointOnA, pointOnB);
normalInB = m_cachedSeparatingAxis;
+
btScalar lenSqr =m_cachedSeparatingAxis.length2();
//valid normal
@@ -318,6 +283,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
{
btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
normalInB *= rlen; //normalize
+
btScalar s = btSqrt(squaredDistance);
btAssert(s > btScalar(0.0));
@@ -373,6 +339,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
{
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))
{
@@ -380,8 +347,48 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
pointOnA = tmpPointOnA;
pointOnB = tmpPointOnB;
normalInB = tmpNormalInB;
+ ///todo: need to track down this EPA penetration solver degeneracy
+ ///the penetration solver reports penetration but the contact normal
+ ///connecting the contact points is pointing in the opposite direction
+ ///until then, detect the issue and revert the normal
+ {
+ btScalar d1=0;
+ {
+ btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis();
+ btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis();
+
+
+ btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
+ btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
+
+ btVector3 pWorld = localTransA(pInA);
+ btVector3 qWorld = localTransB(qInB);
+ btVector3 w = pWorld - qWorld;
+ d1 = (-normalInB).dot(w);
+ }
+ btScalar d0 = 0.f;
+ {
+ btVector3 seperatingAxisInA = (-normalInB)* input.m_transformA.getBasis();
+ btVector3 seperatingAxisInB = normalInB* input.m_transformB.getBasis();
+
+
+ btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
+ btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
+
+ btVector3 pWorld = localTransA(pInA);
+ btVector3 qWorld = localTransB(qInB);
+ btVector3 w = pWorld - qWorld;
+ d0 = normalInB.dot(w);
+ }
+ if (d1>d0)
+ {
+ m_lastUsedMethod = 10;
+ normalInB*=-1;
+ }
+
+ }
isValid = true;
- m_lastUsedMethod = 3;
+
} else
{
m_lastUsedMethod = 8;
@@ -413,6 +420,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
pointOnB += m_cachedSeparatingAxis * marginB ;
normalInB = m_cachedSeparatingAxis;
normalInB.normalize();
+
isValid = true;
m_lastUsedMethod = 6;
} else
@@ -431,36 +439,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
{
-#if 0
-///some debugging
-// if (check2d)
- {
- printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
- printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
- }
-#endif
- if (m_fixContactNormalDirection)
- {
- ///@workaround for sticky convex collisions
- //in some degenerate cases (usually when the use uses very small margins)
- //the contact normal is pointing the wrong direction
- //so fix it now (until we can deal with all degenerate cases in GJK and EPA)
- //contact normals need to point from B to A in all cases, so we can simply check if the contact normal really points from B to A
- //We like to use a dot product of the normal against the difference of the centroids,
- //once the centroid is available in the API
- //until then we use the center of the aabb to approximate the centroid
- btVector3 aabbMin,aabbMax;
- m_minkowskiA->getAabb(localTransA,aabbMin,aabbMax);
- btVector3 posA = (aabbMax+aabbMin)*btScalar(0.5);
-
- m_minkowskiB->getAabb(localTransB,aabbMin,aabbMax);
- btVector3 posB = (aabbMin+aabbMax)*btScalar(0.5);
-
- btVector3 diff = posA-posB;
- if (diff.dot(normalInB) < 0.f)
- normalInB *= -1.f;
- }
m_cachedSeparatingAxis = normalInB;
m_cachedSeparatingDistance = distance;
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h
new file mode 100644
index 00000000000..a22a0bae66b
--- /dev/null
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h
@@ -0,0 +1,908 @@
+
+/***
+ * ---------------------------------
+ * Copyright (c)2012 Daniel Fiser <danfis@danfis.cz>
+ *
+ * This file was ported from mpr.c file, part of libccd.
+ * The Minkoski Portal Refinement implementation was ported
+ * to OpenCL by Erwin Coumans for the Bullet 3 Physics library.
+ * The original MPR idea and implementation is by Gary Snethen
+ * in XenoCollide, see http://github.com/erwincoumans/xenocollide
+ *
+ * Distributed under the OSI-approved BSD License (the "License");
+ * see <http://www.opensource.org/licenses/bsd-license.php>.
+ * This software is distributed WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the License for more information.
+ */
+
+///2014 Oct, Erwin Coumans, Use templates to avoid void* casts
+
+#ifndef BT_MPR_PENETRATION_H
+#define BT_MPR_PENETRATION_H
+
+#define BT_DEBUG_MPR1
+
+#include "LinearMath/btTransform.h"
+#include "LinearMath/btAlignedObjectArray.h"
+
+//#define MPR_AVERAGE_CONTACT_POSITIONS
+
+
+struct btMprCollisionDescription
+{
+ btVector3 m_firstDir;
+ int m_maxGjkIterations;
+ btScalar m_maximumDistanceSquared;
+ btScalar m_gjkRelError2;
+
+ btMprCollisionDescription()
+ : m_firstDir(0,1,0),
+ m_maxGjkIterations(1000),
+ m_maximumDistanceSquared(1e30f),
+ m_gjkRelError2(1.0e-6)
+ {
+ }
+ virtual ~btMprCollisionDescription()
+ {
+ }
+};
+
+struct btMprDistanceInfo
+{
+ btVector3 m_pointOnA;
+ btVector3 m_pointOnB;
+ btVector3 m_normalBtoA;
+ btScalar m_distance;
+};
+
+#ifdef __cplusplus
+#define BT_MPR_SQRT sqrtf
+#else
+#define BT_MPR_SQRT sqrt
+#endif
+#define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y))
+#define BT_MPR_FABS fabs
+
+#define BT_MPR_TOLERANCE 1E-6f
+#define BT_MPR_MAX_ITERATIONS 1000
+
+struct _btMprSupport_t
+{
+ btVector3 v; //!< Support point in minkowski sum
+ btVector3 v1; //!< Support point in obj1
+ btVector3 v2; //!< Support point in obj2
+};
+typedef struct _btMprSupport_t btMprSupport_t;
+
+struct _btMprSimplex_t
+{
+ btMprSupport_t ps[4];
+ int last; //!< index of last added point
+};
+typedef struct _btMprSimplex_t btMprSimplex_t;
+
+inline btMprSupport_t* btMprSimplexPointW(btMprSimplex_t *s, int idx)
+{
+ return &s->ps[idx];
+}
+
+inline void btMprSimplexSetSize(btMprSimplex_t *s, int size)
+{
+ s->last = size - 1;
+}
+
+#ifdef DEBUG_MPR
+inline void btPrintPortalVertex(_btMprSimplex_t* portal, int index)
+{
+ printf("portal[%d].v = %f,%f,%f, v1=%f,%f,%f, v2=%f,%f,%f\n", index, portal->ps[index].v.x(),portal->ps[index].v.y(),portal->ps[index].v.z(),
+ portal->ps[index].v1.x(),portal->ps[index].v1.y(),portal->ps[index].v1.z(),
+ portal->ps[index].v2.x(),portal->ps[index].v2.y(),portal->ps[index].v2.z());
+}
+#endif //DEBUG_MPR
+
+
+
+
+inline int btMprSimplexSize(const btMprSimplex_t *s)
+{
+ return s->last + 1;
+}
+
+
+inline const btMprSupport_t* btMprSimplexPoint(const btMprSimplex_t* s, int idx)
+{
+ // here is no check on boundaries
+ return &s->ps[idx];
+}
+
+inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s)
+{
+ *d = *s;
+}
+
+inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a)
+{
+ btMprSupportCopy(s->ps + pos, a);
+}
+
+
+inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2)
+{
+ btMprSupport_t supp;
+
+ btMprSupportCopy(&supp, &s->ps[pos1]);
+ btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]);
+ btMprSupportCopy(&s->ps[pos2], &supp);
+}
+
+
+inline int btMprIsZero(float val)
+{
+ return BT_MPR_FABS(val) < FLT_EPSILON;
+}
+
+
+
+inline int btMprEq(float _a, float _b)
+{
+ float ab;
+ float a, b;
+
+ ab = BT_MPR_FABS(_a - _b);
+ if (BT_MPR_FABS(ab) < FLT_EPSILON)
+ return 1;
+
+ a = BT_MPR_FABS(_a);
+ b = BT_MPR_FABS(_b);
+ if (b > a){
+ return ab < FLT_EPSILON * b;
+ }else{
+ return ab < FLT_EPSILON * a;
+ }
+}
+
+
+inline int btMprVec3Eq(const btVector3* a, const btVector3 *b)
+{
+ return btMprEq((*a).x(), (*b).x())
+ && btMprEq((*a).y(), (*b).y())
+ && btMprEq((*a).z(), (*b).z());
+}
+
+
+
+
+
+
+
+
+
+
+
+template <typename btConvexTemplate>
+inline void btFindOrigin(const btConvexTemplate& a, const btConvexTemplate& b, const btMprCollisionDescription& colDesc,btMprSupport_t *center)
+{
+
+ center->v1 = a.getObjectCenterInWorld();
+ center->v2 = b.getObjectCenterInWorld();
+ center->v = center->v1 - center->v2;
+}
+
+inline void btMprVec3Set(btVector3 *v, float x, float y, float z)
+{
+ v->setValue(x,y,z);
+}
+
+inline void btMprVec3Add(btVector3 *v, const btVector3 *w)
+{
+ *v += *w;
+}
+
+inline void btMprVec3Copy(btVector3 *v, const btVector3 *w)
+{
+ *v = *w;
+}
+
+inline void btMprVec3Scale(btVector3 *d, float k)
+{
+ *d *= k;
+}
+
+inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b)
+{
+ float dot;
+
+ dot = btDot(*a,*b);
+ return dot;
+}
+
+
+inline float btMprVec3Len2(const btVector3 *v)
+{
+ return btMprVec3Dot(v, v);
+}
+
+inline void btMprVec3Normalize(btVector3 *d)
+{
+ float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d));
+ btMprVec3Scale(d, k);
+}
+
+inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b)
+{
+ *d = btCross(*a,*b);
+
+}
+
+
+inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w)
+{
+ *d = *v - *w;
+}
+
+inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir)
+{
+ btVector3 v2v1, v3v1;
+
+ btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v,
+ &btMprSimplexPoint(portal, 1)->v);
+ btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v,
+ &btMprSimplexPoint(portal, 1)->v);
+ btMprVec3Cross(dir, &v2v1, &v3v1);
+ btMprVec3Normalize(dir);
+}
+
+
+inline int portalEncapsulesOrigin(const btMprSimplex_t *portal,
+ const btVector3 *dir)
+{
+ float dot;
+ dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v);
+ return btMprIsZero(dot) || dot > 0.f;
+}
+
+inline int portalReachTolerance(const btMprSimplex_t *portal,
+ const btMprSupport_t *v4,
+ const btVector3 *dir)
+{
+ float dv1, dv2, dv3, dv4;
+ float dot1, dot2, dot3;
+
+ // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}
+
+ dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir);
+ dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir);
+ dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir);
+ dv4 = btMprVec3Dot(&v4->v, dir);
+
+ dot1 = dv4 - dv1;
+ dot2 = dv4 - dv2;
+ dot3 = dv4 - dv3;
+
+ dot1 = BT_MPR_FMIN(dot1, dot2);
+ dot1 = BT_MPR_FMIN(dot1, dot3);
+
+ return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE;
+}
+
+inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal,
+ const btMprSupport_t *v4,
+ const btVector3 *dir)
+{
+ float dot;
+ dot = btMprVec3Dot(&v4->v, dir);
+ return btMprIsZero(dot) || dot > 0.f;
+}
+
+inline void btExpandPortal(btMprSimplex_t *portal,
+ const btMprSupport_t *v4)
+{
+ float dot;
+ btVector3 v4v0;
+
+ btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v);
+ dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0);
+ if (dot > 0.f){
+ dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0);
+ if (dot > 0.f){
+ btMprSimplexSet(portal, 1, v4);
+ }else{
+ btMprSimplexSet(portal, 3, v4);
+ }
+ }else{
+ dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0);
+ if (dot > 0.f){
+ btMprSimplexSet(portal, 2, v4);
+ }else{
+ btMprSimplexSet(portal, 1, v4);
+ }
+ }
+}
+template <typename btConvexTemplate>
+inline void btMprSupport(const btConvexTemplate& a, const btConvexTemplate& b,
+ const btMprCollisionDescription& colDesc,
+ const btVector3& dir, btMprSupport_t *supp)
+{
+ btVector3 seperatingAxisInA = dir* a.getWorldTransform().getBasis();
+ btVector3 seperatingAxisInB = -dir* b.getWorldTransform().getBasis();
+
+ btVector3 pInA = a.getLocalSupportWithMargin(seperatingAxisInA);
+ btVector3 qInB = b.getLocalSupportWithMargin(seperatingAxisInB);
+
+ supp->v1 = a.getWorldTransform()(pInA);
+ supp->v2 = b.getWorldTransform()(qInB);
+ supp->v = supp->v1 - supp->v2;
+}
+
+
+template <typename btConvexTemplate>
+static int btDiscoverPortal(const btConvexTemplate& a, const btConvexTemplate& b,
+ const btMprCollisionDescription& colDesc,
+ btMprSimplex_t *portal)
+{
+ btVector3 dir, va, vb;
+ float dot;
+ int cont;
+
+
+
+ // vertex 0 is center of portal
+ btFindOrigin(a,b,colDesc, btMprSimplexPointW(portal, 0));
+
+
+ // vertex 0 is center of portal
+ btMprSimplexSetSize(portal, 1);
+
+
+
+ btVector3 zero = btVector3(0,0,0);
+ btVector3* org = &zero;
+
+ if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org)){
+ // Portal's center lies on origin (0,0,0) => we know that objects
+ // intersect but we would need to know penetration info.
+ // So move center little bit...
+ btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f);
+ btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va);
+ }
+
+
+ // vertex 1 = support in direction of origin
+ btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v);
+ btMprVec3Scale(&dir, -1.f);
+ btMprVec3Normalize(&dir);
+
+
+ btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 1));
+
+ btMprSimplexSetSize(portal, 2);
+
+ // test if origin isn't outside of v1
+ dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir);
+
+
+ if (btMprIsZero(dot) || dot < 0.f)
+ return -1;
+
+
+ // vertex 2
+ btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v,
+ &btMprSimplexPoint(portal, 1)->v);
+ if (btMprIsZero(btMprVec3Len2(&dir))){
+ if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org)){
+ // origin lies on v1
+ return 1;
+ }else{
+ // origin lies on v0-v1 segment
+ return 2;
+ }
+ }
+
+ btMprVec3Normalize(&dir);
+ btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 2));
+
+
+
+ dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir);
+ if (btMprIsZero(dot) || dot < 0.f)
+ return -1;
+
+ btMprSimplexSetSize(portal, 3);
+
+ // vertex 3 direction
+ btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
+ &btMprSimplexPoint(portal, 0)->v);
+ btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
+ &btMprSimplexPoint(portal, 0)->v);
+ btMprVec3Cross(&dir, &va, &vb);
+ btMprVec3Normalize(&dir);
+
+ // it is better to form portal faces to be oriented "outside" origin
+ dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v);
+ if (dot > 0.f){
+ btMprSimplexSwap(portal, 1, 2);
+ btMprVec3Scale(&dir, -1.f);
+ }
+
+ while (btMprSimplexSize(portal) < 4){
+ btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 3));
+
+ dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir);
+ if (btMprIsZero(dot) || dot < 0.f)
+ return -1;
+
+ cont = 0;
+
+ // test if origin is outside (v1, v0, v3) - set v2 as v3 and
+ // continue
+ btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v,
+ &btMprSimplexPoint(portal, 3)->v);
+ dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
+ if (dot < 0.f && !btMprIsZero(dot)){
+ btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3));
+ cont = 1;
+ }
+
+ if (!cont){
+ // test if origin is outside (v3, v0, v2) - set v1 as v3 and
+ // continue
+ btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v,
+ &btMprSimplexPoint(portal, 2)->v);
+ dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
+ if (dot < 0.f && !btMprIsZero(dot)){
+ btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3));
+ cont = 1;
+ }
+ }
+
+ if (cont){
+ btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
+ &btMprSimplexPoint(portal, 0)->v);
+ btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
+ &btMprSimplexPoint(portal, 0)->v);
+ btMprVec3Cross(&dir, &va, &vb);
+ btMprVec3Normalize(&dir);
+ }else{
+ btMprSimplexSetSize(portal, 4);
+ }
+ }
+
+ return 0;
+}
+
+template <typename btConvexTemplate>
+static int btRefinePortal(const btConvexTemplate& a, const btConvexTemplate& b,const btMprCollisionDescription& colDesc,
+ btMprSimplex_t *portal)
+{
+ btVector3 dir;
+ btMprSupport_t v4;
+
+ for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
+ //while (1)
+ {
+ // compute direction outside the portal (from v0 throught v1,v2,v3
+ // face)
+ btPortalDir(portal, &dir);
+
+ // test if origin is inside the portal
+ if (portalEncapsulesOrigin(portal, &dir))
+ return 0;
+
+ // get next support point
+
+ btMprSupport(a,b,colDesc, dir, &v4);
+
+
+ // test if v4 can expand portal to contain origin and if portal
+ // expanding doesn't reach given tolerance
+ if (!portalCanEncapsuleOrigin(portal, &v4, &dir)
+ || portalReachTolerance(portal, &v4, &dir))
+ {
+ return -1;
+ }
+
+ // v1-v2-v3 triangle must be rearranged to face outside Minkowski
+ // difference (direction from v0).
+ btExpandPortal(portal, &v4);
+ }
+
+ return -1;
+}
+
+static void btFindPos(const btMprSimplex_t *portal, btVector3 *pos)
+{
+
+ btVector3 zero = btVector3(0,0,0);
+ btVector3* origin = &zero;
+
+ btVector3 dir;
+ size_t i;
+ float b[4], sum, inv;
+ btVector3 vec, p1, p2;
+
+ btPortalDir(portal, &dir);
+
+ // use barycentric coordinates of tetrahedron to find origin
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
+ &btMprSimplexPoint(portal, 2)->v);
+ b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
+
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
+ &btMprSimplexPoint(portal, 2)->v);
+ b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
+
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v,
+ &btMprSimplexPoint(portal, 1)->v);
+ b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
+
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
+ &btMprSimplexPoint(portal, 1)->v);
+ b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
+
+ sum = b[0] + b[1] + b[2] + b[3];
+
+ if (btMprIsZero(sum) || sum < 0.f){
+ b[0] = 0.f;
+
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
+ &btMprSimplexPoint(portal, 3)->v);
+ b[1] = btMprVec3Dot(&vec, &dir);
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
+ &btMprSimplexPoint(portal, 1)->v);
+ b[2] = btMprVec3Dot(&vec, &dir);
+ btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
+ &btMprSimplexPoint(portal, 2)->v);
+ b[3] = btMprVec3Dot(&vec, &dir);
+
+ sum = b[1] + b[2] + b[3];
+ }
+
+ inv = 1.f / sum;
+
+ btMprVec3Copy(&p1, origin);
+ btMprVec3Copy(&p2, origin);
+ for (i = 0; i < 4; i++){
+ btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1);
+ btMprVec3Scale(&vec, b[i]);
+ btMprVec3Add(&p1, &vec);
+
+ btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2);
+ btMprVec3Scale(&vec, b[i]);
+ btMprVec3Add(&p2, &vec);
+ }
+ btMprVec3Scale(&p1, inv);
+ btMprVec3Scale(&p2, inv);
+#ifdef MPR_AVERAGE_CONTACT_POSITIONS
+ btMprVec3Copy(pos, &p1);
+ btMprVec3Add(pos, &p2);
+ btMprVec3Scale(pos, 0.5);
+#else
+ btMprVec3Copy(pos, &p2);
+#endif//MPR_AVERAGE_CONTACT_POSITIONS
+}
+
+inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b)
+{
+ btVector3 ab;
+ btMprVec3Sub2(&ab, a, b);
+ return btMprVec3Len2(&ab);
+}
+
+inline float _btMprVec3PointSegmentDist2(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.
+
+ float dist, t;
+ btVector3 d, a;
+
+ // direction of segment
+ btMprVec3Sub2(&d, b, x0);
+
+ // precompute vector from P to x0
+ btMprVec3Sub2(&a, x0, P);
+
+ t = -1.f * btMprVec3Dot(&a, &d);
+ t /= btMprVec3Len2(&d);
+
+ if (t < 0.f || btMprIsZero(t)){
+ dist = btMprVec3Dist2(x0, P);
+ if (witness)
+ btMprVec3Copy(witness, x0);
+ }else if (t > 1.f || btMprEq(t, 1.f)){
+ dist = btMprVec3Dist2(b, P);
+ if (witness)
+ btMprVec3Copy(witness, b);
+ }else{
+ if (witness){
+ btMprVec3Copy(witness, &d);
+ btMprVec3Scale(witness, t);
+ btMprVec3Add(witness, x0);
+ dist = btMprVec3Dist2(witness, P);
+ }else{
+ // recycling variables
+ btMprVec3Scale(&d, t);
+ btMprVec3Add(&d, &a);
+ dist = btMprVec3Len2(&d);
+ }
+ }
+
+ return dist;
+}
+
+
+
+inline float btMprVec3PointTriDist2(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;
+ float u, v, w, p, q, r;
+ float s, t, dist, dist2;
+ btVector3 witness2;
+
+ btMprVec3Sub2(&d1, B, x0);
+ btMprVec3Sub2(&d2, C, x0);
+ btMprVec3Sub2(&a, x0, P);
+
+ u = btMprVec3Dot(&a, &a);
+ v = btMprVec3Dot(&d1, &d1);
+ w = btMprVec3Dot(&d2, &d2);
+ p = btMprVec3Dot(&a, &d1);
+ q = btMprVec3Dot(&a, &d2);
+ r = btMprVec3Dot(&d1, &d2);
+
+ btScalar div = (w * v - r * r);
+ if (btMprIsZero(div))
+ {
+ s=-1;
+ } else
+ {
+ s = (q * r - w * p) / div;
+ t = (-s * r - q) / w;
+ }
+
+ if ((btMprIsZero(s) || s > 0.f)
+ && (btMprEq(s, 1.f) || s < 1.f)
+ && (btMprIsZero(t) || t > 0.f)
+ && (btMprEq(t, 1.f) || t < 1.f)
+ && (btMprEq(t + s, 1.f) || t + s < 1.f)){
+
+ if (witness){
+ btMprVec3Scale(&d1, s);
+ btMprVec3Scale(&d2, t);
+ btMprVec3Copy(witness, x0);
+ btMprVec3Add(witness, &d1);
+ btMprVec3Add(witness, &d2);
+
+ dist = btMprVec3Dist2(witness, P);
+ }else{
+ dist = s * s * v;
+ dist += t * t * w;
+ dist += 2.f * s * t * r;
+ dist += 2.f * s * p;
+ dist += 2.f * t * q;
+ dist += u;
+ }
+ }else{
+ dist = _btMprVec3PointSegmentDist2(P, x0, B, witness);
+
+ dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2);
+ if (dist2 < dist){
+ dist = dist2;
+ if (witness)
+ btMprVec3Copy(witness, &witness2);
+ }
+
+ dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2);
+ if (dist2 < dist){
+ dist = dist2;
+ if (witness)
+ btMprVec3Copy(witness, &witness2);
+ }
+ }
+
+ return dist;
+}
+
+template <typename btConvexTemplate>
+static void btFindPenetr(const btConvexTemplate& a, const btConvexTemplate& b,
+ const btMprCollisionDescription& colDesc,
+ btMprSimplex_t *portal,
+ float *depth, btVector3 *pdir, btVector3 *pos)
+{
+ btVector3 dir;
+ btMprSupport_t v4;
+ unsigned long iterations;
+
+ btVector3 zero = btVector3(0,0,0);
+ btVector3* origin = &zero;
+
+
+ iterations = 1UL;
+ for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
+ //while (1)
+ {
+ // compute portal direction and obtain next support point
+ btPortalDir(portal, &dir);
+
+ btMprSupport(a,b,colDesc, dir, &v4);
+
+
+ // reached tolerance -> find penetration info
+ if (portalReachTolerance(portal, &v4, &dir)
+ || iterations ==BT_MPR_MAX_ITERATIONS)
+ {
+ *depth = btMprVec3PointTriDist2(origin,&btMprSimplexPoint(portal, 1)->v,&btMprSimplexPoint(portal, 2)->v,&btMprSimplexPoint(portal, 3)->v,pdir);
+ *depth = BT_MPR_SQRT(*depth);
+
+ if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z()))
+ {
+
+ *pdir = dir;
+ }
+ btMprVec3Normalize(pdir);
+
+ // barycentric coordinates:
+ btFindPos(portal, pos);
+
+
+ return;
+ }
+
+ btExpandPortal(portal, &v4);
+
+ iterations++;
+ }
+}
+
+static void btFindPenetrTouch(btMprSimplex_t *portal,float *depth, btVector3 *dir, btVector3 *pos)
+{
+ // Touching contact on portal's v1 - so depth is zero and direction
+ // is unimportant and pos can be guessed
+ *depth = 0.f;
+ btVector3 zero = btVector3(0,0,0);
+ btVector3* origin = &zero;
+
+
+ btMprVec3Copy(dir, origin);
+#ifdef MPR_AVERAGE_CONTACT_POSITIONS
+ btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
+ btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
+ btMprVec3Scale(pos, 0.5);
+#else
+ btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
+#endif
+}
+
+static void btFindPenetrSegment(btMprSimplex_t *portal,
+ float *depth, btVector3 *dir, btVector3 *pos)
+{
+
+ // Origin lies on v0-v1 segment.
+ // Depth is distance to v1, direction also and position must be
+ // computed
+#ifdef MPR_AVERAGE_CONTACT_POSITIONS
+ btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
+ btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
+ btMprVec3Scale(pos, 0.5f);
+#else
+ btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
+#endif//MPR_AVERAGE_CONTACT_POSITIONS
+
+ btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v);
+ *depth = BT_MPR_SQRT(btMprVec3Len2(dir));
+ btMprVec3Normalize(dir);
+
+
+}
+
+
+template <typename btConvexTemplate>
+inline int btMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b,
+ const btMprCollisionDescription& colDesc,
+ float *depthOut, btVector3* dirOut, btVector3* posOut)
+{
+
+ btMprSimplex_t portal;
+
+
+ // Phase 1: Portal discovery
+ int result = btDiscoverPortal(a,b,colDesc, &portal);
+
+
+ //sepAxis[pairIndex] = *pdir;//or -dir?
+
+ switch (result)
+ {
+ case 0:
+ {
+ // Phase 2: Portal refinement
+
+ result = btRefinePortal(a,b,colDesc, &portal);
+ if (result < 0)
+ return -1;
+
+ // Phase 3. Penetration info
+ btFindPenetr(a,b,colDesc, &portal, depthOut, dirOut, posOut);
+
+
+ break;
+ }
+ case 1:
+ {
+ // Touching contact on portal's v1.
+ btFindPenetrTouch(&portal, depthOut, dirOut, posOut);
+ result=0;
+ break;
+ }
+ case 2:
+ {
+
+ btFindPenetrSegment( &portal, depthOut, dirOut, posOut);
+ result=0;
+ break;
+ }
+ default:
+ {
+ //if (res < 0)
+ //{
+ // Origin isn't inside portal - no collision.
+ result = -1;
+ //}
+ }
+ };
+
+ return result;
+};
+
+
+template<typename btConvexTemplate, typename btMprDistanceTemplate>
+inline int btComputeMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, const
+ btMprCollisionDescription& colDesc, btMprDistanceTemplate* distInfo)
+{
+ btVector3 dir,pos;
+ float depth;
+
+ int res = btMprPenetration(a,b,colDesc,&depth, &dir, &pos);
+ if (res==0)
+ {
+ distInfo->m_distance = -depth;
+ distInfo->m_pointOnB = pos;
+ distInfo->m_normalBtoA = -dir;
+ distInfo->m_pointOnA = pos-distInfo->m_distance*dir;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+
+#endif //BT_MPR_PENETRATION_H
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
index 2ceaab750fa..5026397f67f 100644
--- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h
@@ -196,10 +196,6 @@ public:
m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
- m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse;
- m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
- m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
-
m_pointCache[insertIndex].m_lifeTime = lifeTime;
#else
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
index b08205e84aa..d5f4a964bf3 100644
--- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp
@@ -116,7 +116,7 @@ static int gActualSATPairTests=0;
inline bool IsAlmostZero(const btVector3& v)
{
- if(fabsf(v.x())>1e-6 || fabsf(v.y())>1e-6 || fabsf(v.z())>1e-6) return false;
+ if(btFabs(v.x())>1e-6 || btFabs(v.y())>1e-6 || btFabs(v.z())>1e-6) return false;
return true;
}
@@ -313,7 +313,7 @@ bool btPolyhedralContactClipping::findSeparatingAxis( const btConvexPolyhedron&
int edgeB=-1;
btVector3 worldEdgeA;
btVector3 worldEdgeB;
- btVector3 witnessPointA,witnessPointB;
+ btVector3 witnessPointA(0,0,0),witnessPointB(0,0,0);
int curEdgeEdge = 0;
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
index 3999d400503..f2ed0cd39c4 100644
--- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h
@@ -32,10 +32,12 @@ public:
//@BP Mod - allow backface filtering and unflipped normals
enum EFlags
{
- kF_None = 0,
+ kF_None = 0,
kF_FilterBackfaces = 1 << 0,
kF_KeepUnflippedNormal = 1 << 1, // Prevents returned face normal getting flipped when a ray hits a back-facing triangle
- kF_UseSubSimplexConvexCastRaytest = 1 << 2, // Uses an approximate but faster ray versus convex intersection algorithm
+ ///SubSimplexConvexCastRaytest is the default, even if kF_None is set.
+ kF_UseSubSimplexConvexCastRaytest = 1 << 2, // Uses an approximate but faster ray versus convex intersection algorithm
+ kF_UseGjkConvexCastRaytest = 1 << 3,
kF_Terminator = 0xFFFFFFFF
};
unsigned int m_flags;
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
index 18eb662de2f..ec638f60ba5 100644
--- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp
@@ -65,10 +65,10 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
btVector3 n;
n.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
- bool hasResult = false;
+
btVector3 c;
- btScalar lastLambda = lambda;
+
btScalar dist2 = v.length2();
@@ -109,9 +109,9 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
//m_simplexSolver->reset();
//check next line
w = supVertexA-supVertexB;
- lastLambda = lambda;
+
n = v;
- hasResult = true;
+
}
}
///Just like regular GJK only add the vertex if it isn't already (close) to current vertex, it would lead to divisions by zero and NaN etc.
@@ -121,7 +121,7 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
if (m_simplexSolver->closest(v))
{
dist2 = v.length2();
- hasResult = true;
+
//todo: check this normal for validity
//n=v;
//printf("V=%f , %f, %f\n",v[0],v[1],v[2]);
diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp
index a775198ab29..23b4f79cfc2 100644
--- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp
+++ b/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp
@@ -294,7 +294,10 @@ bool btVoronoiSimplexSolver::inSimplex(const btVector3& w)
#else
if (m_simplexVectorW[i] == w)
#endif
+ {
found = true;
+ break;
+ }
}
//check in case lastW is already removed
diff --git a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp b/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp
index 8d940e63cd3..31faf1df5e3 100644
--- a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp
+++ b/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp
@@ -29,13 +29,11 @@ subject to the following restrictions:
static btVector3
getNormalizedVector(const btVector3& v)
{
- btScalar l = v.length();
- btVector3 n = v;
- if (l < SIMD_EPSILON) {
- n.setValue(0,0,0);
- } else {
- n /= l;
- }
+ btVector3 n(0, 0, 0);
+
+ if (v.length() > SIMD_EPSILON) {
+ n = v.normalized();
+ }
return n;
}
@@ -383,8 +381,8 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co
if (callback.hasHit())
{
// we moved only a fraction
- btScalar hitDistance;
- hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
+ //btScalar hitDistance;
+ //hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
// m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
@@ -638,7 +636,7 @@ void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWo
// printf(" dt = %f", dt);
// quick check...
- if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) {
+ if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0 || m_walkDirection.fuzzyZero())) {
// printf("\n");
return; // no motion
}
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp
index 15a4c92de20..09b7388b63e 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp
@@ -214,7 +214,7 @@ void btConeTwistConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const bt
}
// m_swingCorrection is always positive or 0
info->m_lowerLimit[srow] = 0;
- info->m_upperLimit[srow] = SIMD_INFINITY;
+ info->m_upperLimit[srow] = (m_bMotorEnabled && m_maxMotorImpulse >= 0.0f) ? m_maxMotorImpulse : SIMD_INFINITY;
srow += info->rowskip;
}
}
@@ -540,8 +540,8 @@ void btConeTwistConstraint::calcAngleInfo()
m_solveTwistLimit = false;
m_solveSwingLimit = false;
- btVector3 b1Axis1,b1Axis2,b1Axis3;
- btVector3 b2Axis1,b2Axis2;
+ btVector3 b1Axis1(0,0,0),b1Axis2(0,0,0),b1Axis3(0,0,0);
+ btVector3 b2Axis1(0,0,0),b2Axis2(0,0,0);
b1Axis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(0);
b2Axis1 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(0);
@@ -778,8 +778,10 @@ void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTr
target[2] = x * ivA[2] + y * jvA[2] + z * kvA[2];
target.normalize();
m_swingAxis = -ivB.cross(target);
- m_swingCorrection = m_swingAxis.length();
- m_swingAxis.normalize();
+ m_swingCorrection = m_swingAxis.length();
+
+ if (!btFuzzyZero(m_swingCorrection))
+ m_swingAxis.normalize();
}
}
@@ -983,8 +985,8 @@ void btConeTwistConstraint::adjustSwingAxisToUseEllipseNormal(btVector3& vSwingA
void btConeTwistConstraint::setMotorTarget(const btQuaternion &q)
{
- btTransform trACur = m_rbA.getCenterOfMassTransform();
- btTransform trBCur = m_rbB.getCenterOfMassTransform();
+ //btTransform trACur = m_rbA.getCenterOfMassTransform();
+ //btTransform trBCur = m_rbB.getCenterOfMassTransform();
// btTransform trABCur = trBCur.inverse() * trACur;
// btQuaternion qABCur = trABCur.getRotation();
// btTransform trConstraintCur = (trBCur * m_rbBFrame).inverse() * (trACur * m_rbAFrame);
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h
index 1735b524dba..b7636180c34 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h
@@ -170,6 +170,11 @@ public:
{
m_angularOnly = angularOnly;
}
+
+ bool getAngularOnly() const
+ {
+ return m_angularOnly;
+ }
void setLimit(int limitIndex,btScalar limitValue)
{
@@ -196,6 +201,33 @@ public:
};
}
+ btScalar getLimit(int limitIndex) const
+ {
+ switch (limitIndex)
+ {
+ case 3:
+ {
+ return m_twistSpan;
+ break;
+ }
+ case 4:
+ {
+ return m_swingSpan2;
+ break;
+ }
+ case 5:
+ {
+ return m_swingSpan1;
+ break;
+ }
+ default:
+ {
+ btAssert(0 && "Invalid limitIndex specified for btConeTwistConstraint");
+ return 0.0;
+ }
+ };
+ }
+
// setLimit(), a few notes:
// _softness:
// 0->1, recommend ~0.8->1.
@@ -218,8 +250,8 @@ public:
m_relaxationFactor = _relaxationFactor;
}
- const btTransform& getAFrame() { return m_rbAFrame; };
- const btTransform& getBFrame() { return m_rbBFrame; };
+ const btTransform& getAFrame() const { return m_rbAFrame; };
+ const btTransform& getBFrame() const { return m_rbBFrame; };
inline int getSolveTwistLimit()
{
@@ -239,27 +271,43 @@ public:
void calcAngleInfo();
void calcAngleInfo2(const btTransform& transA, const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB);
- inline btScalar getSwingSpan1()
+ inline btScalar getSwingSpan1() const
{
return m_swingSpan1;
}
- inline btScalar getSwingSpan2()
+ inline btScalar getSwingSpan2() const
{
return m_swingSpan2;
}
- inline btScalar getTwistSpan()
+ inline btScalar getTwistSpan() const
{
return m_twistSpan;
}
- inline btScalar getTwistAngle()
+ inline btScalar getLimitSoftness() const
+ {
+ return m_limitSoftness;
+ }
+ inline btScalar getBiasFactor() const
+ {
+ return m_biasFactor;
+ }
+ inline btScalar getRelaxationFactor() const
+ {
+ return m_relaxationFactor;
+ }
+ inline btScalar getTwistAngle() const
{
return m_twistAngle;
}
bool isPastSwingLimit() { return m_solveSwingLimit; }
+ btScalar getDamping() const { return m_damping; }
void setDamping(btScalar damping) { m_damping = damping; }
void enableMotor(bool b) { m_bMotorEnabled = b; }
+ bool isMotorEnabled() const { return m_bMotorEnabled; }
+ btScalar getMaxMotorImpulse() const { return m_maxMotorImpulse; }
+ bool isMaxMotorImpulseNormalized() const { return m_bNormalizedMotorStrength; }
void setMaxMotorImpulse(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; m_bNormalizedMotorStrength = false; }
void setMaxMotorImpulseNormalized(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; m_bNormalizedMotorStrength = true; }
@@ -271,6 +319,7 @@ public:
// note: if q violates the joint limits, the internal target is clamped to avoid conflicting impulses (very bad for stability)
// note: don't forget to enableMotor()
void setMotorTarget(const btQuaternion &q);
+ const btQuaternion& getMotorTarget() const { return m_qTarget; }
// same as above, but q is the desired rotation of frameA wrt frameB in constraint space
void setMotorTargetInConstraintSpace(const btQuaternion &q);
@@ -297,6 +346,11 @@ public:
///return the local value of parameter
virtual btScalar getParam(int num, int axis = -1) const;
+ int getFlags() const
+ {
+ return m_flags;
+ }
+
virtual int calculateSerializeBufferSize() const;
///fills the dataBuffer and returns the struct name (and 0 on failure)
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp
index 9d60d9957a5..1098d0c96b6 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp
@@ -155,8 +155,7 @@ void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1,
body1.getCenterOfMassTransform().getBasis().transpose() * body1.getAngularVelocity(),
body2.getLinearVelocity(),
body2.getCenterOfMassTransform().getBasis().transpose() * body2.getAngularVelocity());
- btScalar a;
- a=jacDiagABInv;
+
rel_vel = normal.dot(vel);
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
index c07e9bbd806..a3a0fa6729f 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h
@@ -89,7 +89,7 @@ struct btContactSolverInfo : public btContactSolverInfoData
m_solverMode = SOLVER_USE_WARMSTARTING | SOLVER_SIMD;// | SOLVER_RANDMIZE_ORDER;
m_restingContactRestitutionThreshold = 2;//unused as of 2.81
m_minimumSolverBatchSize = 128; //try to combine islands until the amount of constraints reaches this limit
- m_maxGyroscopicForce = 100.f; ///only used to clamp forces for bodies that have their BT_ENABLE_GYROPSCOPIC_FORCE flag set (using btRigidBody::setFlag)
+ m_maxGyroscopicForce = 100.f; ///it is only used for 'explicit' version of gyroscopic force
m_singleAxisRollingFrictionThreshold = 1e30f;///if the velocity is above this threshold, it will use a single constraint row (axis), otherwise 3 rows.
}
};
@@ -111,7 +111,7 @@ struct btContactSolverInfoDoubleData
double m_splitImpulseTurnErp;
double m_linearSlop;
double m_warmstartingFactor;
- double m_maxGyroscopicForce;
+ double m_maxGyroscopicForce;///it is only used for 'explicit' version of gyroscopic force
double m_singleAxisRollingFrictionThreshold;
int m_numIterations;
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp
index 3428e0b069d..75d81cc08c2 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp
@@ -21,166 +21,17 @@ subject to the following restrictions:
btFixedConstraint::btFixedConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& frameInA,const btTransform& frameInB)
-:btTypedConstraint(FIXED_CONSTRAINT_TYPE,rbA,rbB)
-{
- m_frameInA = frameInA;
- m_frameInB = frameInB;
-
-}
-
-btFixedConstraint::~btFixedConstraint ()
+:btGeneric6DofSpring2Constraint(rbA,rbB,frameInA,frameInB)
{
+ setAngularLowerLimit(btVector3(0,0,0));
+ setAngularUpperLimit(btVector3(0,0,0));
+ setLinearLowerLimit(btVector3(0,0,0));
+ setLinearUpperLimit(btVector3(0,0,0));
}
-
-void btFixedConstraint::getInfo1 (btConstraintInfo1* info)
-{
- info->m_numConstraintRows = 6;
- info->nub = 0;
-}
-
-void btFixedConstraint::getInfo2 (btConstraintInfo2* info)
-{
- //fix the 3 linear degrees of freedom
-
- const btTransform& transA = m_rbA.getCenterOfMassTransform();
- const btTransform& transB = m_rbB.getCenterOfMassTransform();
-
- const btVector3& worldPosA = m_rbA.getCenterOfMassTransform().getOrigin();
- const btMatrix3x3& worldOrnA = m_rbA.getCenterOfMassTransform().getBasis();
- const btVector3& worldPosB= m_rbB.getCenterOfMassTransform().getOrigin();
- const btMatrix3x3& worldOrnB = m_rbB.getCenterOfMassTransform().getBasis();
-
- info->m_J1linearAxis[0] = 1;
- info->m_J1linearAxis[info->rowskip+1] = 1;
- info->m_J1linearAxis[2*info->rowskip+2] = 1;
- btVector3 a1 = worldOrnA * m_frameInA.getOrigin();
- {
- btVector3* angular0 = (btVector3*)(info->m_J1angularAxis);
- btVector3* angular1 = (btVector3*)(info->m_J1angularAxis+info->rowskip);
- btVector3* angular2 = (btVector3*)(info->m_J1angularAxis+2*info->rowskip);
- btVector3 a1neg = -a1;
- a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2);
- }
- if (info->m_J2linearAxis)
- {
- info->m_J2linearAxis[0] = -1;
- info->m_J2linearAxis[info->rowskip+1] = -1;
- info->m_J2linearAxis[2*info->rowskip+2] = -1;
- }
-
- btVector3 a2 = worldOrnB*m_frameInB.getOrigin();
- {
- btVector3* angular0 = (btVector3*)(info->m_J2angularAxis);
- btVector3* angular1 = (btVector3*)(info->m_J2angularAxis+info->rowskip);
- btVector3* angular2 = (btVector3*)(info->m_J2angularAxis+2*info->rowskip);
- a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
- }
-
- // set right hand side for the linear dofs
- btScalar k = info->fps * info->erp;
-
- btVector3 linearError = k*(a2+worldPosB-a1-worldPosA);
- int j;
- for (j=0; j<3; j++)
- {
- info->m_constraintError[j*info->rowskip] = linearError[j];
- //printf("info->m_constraintError[%d]=%f\n",j,info->m_constraintError[j]);
- }
-
- btVector3 ivA = transA.getBasis() * m_frameInA.getBasis().getColumn(0);
- btVector3 jvA = transA.getBasis() * m_frameInA.getBasis().getColumn(1);
- btVector3 kvA = transA.getBasis() * m_frameInA.getBasis().getColumn(2);
- btVector3 ivB = transB.getBasis() * m_frameInB.getBasis().getColumn(0);
- btVector3 target;
- btScalar x = ivB.dot(ivA);
- btScalar y = ivB.dot(jvA);
- btScalar z = ivB.dot(kvA);
- btVector3 swingAxis(0,0,0);
- {
- if((!btFuzzyZero(y)) || (!(btFuzzyZero(z))))
- {
- swingAxis = -ivB.cross(ivA);
- }
- }
- btVector3 vTwist(1,0,0);
-
- // compute rotation of A wrt B (in constraint space)
- btQuaternion qA = transA.getRotation() * m_frameInA.getRotation();
- btQuaternion qB = transB.getRotation() * m_frameInB.getRotation();
- btQuaternion qAB = qB.inverse() * qA;
- // split rotation into cone and twist
- // (all this is done from B's perspective. Maybe I should be averaging axes...)
- btVector3 vConeNoTwist = quatRotate(qAB, vTwist); vConeNoTwist.normalize();
- btQuaternion qABCone = shortestArcQuat(vTwist, vConeNoTwist); qABCone.normalize();
- btQuaternion qABTwist = qABCone.inverse() * qAB; qABTwist.normalize();
-
- int row = 3;
- int srow = row * info->rowskip;
- btVector3 ax1;
- // angular limits
- {
- btScalar *J1 = info->m_J1angularAxis;
- btScalar *J2 = info->m_J2angularAxis;
- btTransform trA = transA*m_frameInA;
- btVector3 twistAxis = trA.getBasis().getColumn(0);
-
- btVector3 p = trA.getBasis().getColumn(1);
- btVector3 q = trA.getBasis().getColumn(2);
- int srow1 = srow + info->rowskip;
- J1[srow+0] = p[0];
- J1[srow+1] = p[1];
- J1[srow+2] = p[2];
- J1[srow1+0] = q[0];
- J1[srow1+1] = q[1];
- J1[srow1+2] = q[2];
- J2[srow+0] = -p[0];
- J2[srow+1] = -p[1];
- J2[srow+2] = -p[2];
- J2[srow1+0] = -q[0];
- J2[srow1+1] = -q[1];
- J2[srow1+2] = -q[2];
- btScalar fact = info->fps;
- info->m_constraintError[srow] = fact * swingAxis.dot(p);
- info->m_constraintError[srow1] = fact * swingAxis.dot(q);
- info->m_lowerLimit[srow] = -SIMD_INFINITY;
- info->m_upperLimit[srow] = SIMD_INFINITY;
- info->m_lowerLimit[srow1] = -SIMD_INFINITY;
- info->m_upperLimit[srow1] = SIMD_INFINITY;
- srow = srow1 + info->rowskip;
-
- {
- btQuaternion qMinTwist = qABTwist;
- btScalar twistAngle = qABTwist.getAngle();
-
- if (twistAngle > SIMD_PI) // long way around. flip quat and recalculate.
- {
- qMinTwist = -(qABTwist);
- twistAngle = qMinTwist.getAngle();
- }
-
- if (twistAngle > SIMD_EPSILON)
- {
- twistAxis = btVector3(qMinTwist.x(), qMinTwist.y(), qMinTwist.z());
- twistAxis.normalize();
- twistAxis = quatRotate(qB, -twistAxis);
- }
- ax1 = twistAxis;
- btScalar *J1 = info->m_J1angularAxis;
- btScalar *J2 = info->m_J2angularAxis;
- J1[srow+0] = ax1[0];
- J1[srow+1] = ax1[1];
- J1[srow+2] = ax1[2];
- J2[srow+0] = -ax1[0];
- J2[srow+1] = -ax1[1];
- J2[srow+2] = -ax1[2];
- btScalar k = info->fps;
- info->m_constraintError[srow] = k * twistAngle;
- info->m_lowerLimit[srow] = -SIMD_INFINITY;
- info->m_upperLimit[srow] = SIMD_INFINITY;
- }
- }
-} \ No newline at end of file
+btFixedConstraint::~btFixedConstraint ()
+{
+}
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h
index e1c9430fd3c..bff2008b283 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h
@@ -16,32 +16,17 @@ subject to the following restrictions:
#ifndef BT_FIXED_CONSTRAINT_H
#define BT_FIXED_CONSTRAINT_H
-#include "btTypedConstraint.h"
+#include "btGeneric6DofSpring2Constraint.h"
-ATTRIBUTE_ALIGNED16(class) btFixedConstraint : public btTypedConstraint
+
+ATTRIBUTE_ALIGNED16(class) btFixedConstraint : public btGeneric6DofSpring2Constraint
{
- btTransform m_frameInA;
- btTransform m_frameInB;
public:
btFixedConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& frameInA,const btTransform& frameInB);
-
- virtual ~btFixedConstraint();
- virtual void getInfo1 (btConstraintInfo1* info);
-
- virtual void getInfo2 (btConstraintInfo2* info);
-
- virtual void setParam(int num, btScalar value, int axis = -1)
- {
- btAssert(0);
- }
- virtual btScalar getParam(int num, int axis = -1) const
- {
- btAssert(0);
- return 0.f;
- }
+ virtual ~btFixedConstraint();
};
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
index 431a524169e..bea8629c325 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h
@@ -111,14 +111,14 @@ public:
//! Is limited
- bool isLimited()
+ bool isLimited() const
{
if(m_loLimit > m_hiLimit) return false;
return true;
}
//! Need apply correction
- bool needApplyTorques()
+ bool needApplyTorques() const
{
if(m_currentLimit == 0 && m_enableMotor == false) return false;
return true;
@@ -207,11 +207,11 @@ public:
- limited means upper > lower
- limitIndex: first 3 are linear, next 3 are angular
*/
- inline bool isLimited(int limitIndex)
+ inline bool isLimited(int limitIndex) const
{
return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
}
- inline bool needApplyForce(int limitIndex)
+ inline bool needApplyForce(int limitIndex) const
{
if(m_currentLimit[limitIndex] == 0 && m_enableMotor[limitIndex] == false) return false;
return true;
@@ -457,7 +457,7 @@ public:
m_linearLimits.m_lowerLimit = linearLower;
}
- void getLinearLowerLimit(btVector3& linearLower)
+ void getLinearLowerLimit(btVector3& linearLower) const
{
linearLower = m_linearLimits.m_lowerLimit;
}
@@ -467,7 +467,7 @@ public:
m_linearLimits.m_upperLimit = linearUpper;
}
- void getLinearUpperLimit(btVector3& linearUpper)
+ void getLinearUpperLimit(btVector3& linearUpper) const
{
linearUpper = m_linearLimits.m_upperLimit;
}
@@ -478,7 +478,7 @@ public:
m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]);
}
- void getAngularLowerLimit(btVector3& angularLower)
+ void getAngularLowerLimit(btVector3& angularLower) const
{
for(int i = 0; i < 3; i++)
angularLower[i] = m_angularLimits[i].m_loLimit;
@@ -490,7 +490,7 @@ public:
m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]);
}
- void getAngularUpperLimit(btVector3& angularUpper)
+ void getAngularUpperLimit(btVector3& angularUpper) const
{
for(int i = 0; i < 3; i++)
angularUpper[i] = m_angularLimits[i].m_hiLimit;
@@ -532,7 +532,7 @@ public:
- limited means upper > lower
- limitIndex: first 3 are linear, next 3 are angular
*/
- bool isLimited(int limitIndex)
+ bool isLimited(int limitIndex) const
{
if(limitIndex<3)
{
@@ -549,8 +549,11 @@ public:
btConstraintInfo2 *info, int row, btVector3& ax1, int rotational, int rotAllowed = false);
// access for UseFrameOffset
- bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; }
+ bool getUseFrameOffset() const { return m_useOffsetForConstraintFrame; }
void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; }
+
+ bool getUseLinearReferenceFrameA() const { return m_useLinearReferenceFrameA; }
+ void setUseLinearReferenceFrameA(bool linearReferenceFrameA) { m_useLinearReferenceFrameA = linearReferenceFrameA; }
///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
///If no axis is provided, it uses the default axis for this constraint.
@@ -560,6 +563,10 @@ public:
void setAxis( const btVector3& axis1, const btVector3& axis2);
+ virtual int getFlags() const
+ {
+ return m_flags;
+ }
virtual int calculateSerializeBufferSize() const;
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
new file mode 100644
index 00000000000..49ff78c2621
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
@@ -0,0 +1,1121 @@
+/*
+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.
+*/
+
+/*
+2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer
+Pros:
+- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled)
+- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring)
+- Servo motor functionality
+- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision)
+- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2)
+
+Cons:
+- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation. (with PGS)
+- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.)
+*/
+
+/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev
+/// Added support for generic constraint solver through getInfo1/getInfo2 methods
+
+/*
+2007-09-09
+btGeneric6DofConstraint Refactored by Francisco Le?n
+email: projectileman@yahoo.com
+http://gimpact.sf.net
+*/
+
+
+
+#include "btGeneric6DofSpring2Constraint.h"
+#include "BulletDynamics/Dynamics/btRigidBody.h"
+#include "LinearMath/btTransformUtil.h"
+#include <new>
+
+
+
+btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder)
+ : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, rbA, rbB)
+ , m_frameInA(frameInA)
+ , m_frameInB(frameInB)
+ , m_rotateOrder(rotOrder)
+ , m_flags(0)
+{
+ calculateTransforms();
+}
+
+
+btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder)
+ : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, getFixedBody(), rbB)
+ , m_frameInB(frameInB)
+ , m_rotateOrder(rotOrder)
+ , m_flags(0)
+{
+ ///not providing rigidbody A means implicitly using worldspace for body A
+ m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
+ calculateTransforms();
+}
+
+
+btScalar btGeneric6DofSpring2Constraint::btGetMatrixElem(const btMatrix3x3& mat, int index)
+{
+ int i = index%3;
+ int j = index/3;
+ return mat[i][j];
+}
+
+// MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
+
+bool btGeneric6DofSpring2Constraint::matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
+{
+ // rot = cy*cz -cy*sz sy
+ // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
+ // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
+
+ btScalar fi = btGetMatrixElem(mat,2);
+ if (fi < btScalar(1.0f))
+ {
+ if (fi > btScalar(-1.0f))
+ {
+ xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
+ xyz[1] = btAsin(btGetMatrixElem(mat,2));
+ xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
+ return true;
+ }
+ else
+ {
+ // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
+ xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
+ xyz[1] = -SIMD_HALF_PI;
+ xyz[2] = btScalar(0.0);
+ return false;
+ }
+ }
+ else
+ {
+ // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
+ xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
+ xyz[1] = SIMD_HALF_PI;
+ xyz[2] = 0.0;
+ }
+ return false;
+}
+
+bool btGeneric6DofSpring2Constraint::matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz)
+{
+ // rot = cy*cz -sz sy*cz
+ // cy*cx*sz+sx*sy cx*cz sy*cx*sz-cy*sx
+ // cy*sx*sz-cx*sy sx*cz sy*sx*sz+cx*cy
+
+ btScalar fi = btGetMatrixElem(mat,1);
+ if (fi < btScalar(1.0f))
+ {
+ if (fi > btScalar(-1.0f))
+ {
+ xyz[0] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,4));
+ xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0));
+ xyz[2] = btAsin(-btGetMatrixElem(mat,1));
+ return true;
+ }
+ else
+ {
+ xyz[0] = -btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8));
+ xyz[1] = btScalar(0.0);
+ xyz[2] = SIMD_HALF_PI;
+ return false;
+ }
+ }
+ else
+ {
+ xyz[0] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8));
+ xyz[1] = 0.0;
+ xyz[2] = -SIMD_HALF_PI;
+ }
+ return false;
+}
+
+bool btGeneric6DofSpring2Constraint::matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz)
+{
+ // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy
+ // cx*sz cx*cz -sx
+ // cy*sx*sz-cz*sy sy*sz+cy*cz*sx cy*cx
+
+ btScalar fi = btGetMatrixElem(mat,5);
+ if (fi < btScalar(1.0f))
+ {
+ if (fi > btScalar(-1.0f))
+ {
+ xyz[0] = btAsin(-btGetMatrixElem(mat,5));
+ xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,8));
+ xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
+ return true;
+ }
+ else
+ {
+ xyz[0] = SIMD_HALF_PI;
+ xyz[1] = -btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
+ xyz[2] = btScalar(0.0);
+ return false;
+ }
+ }
+ else
+ {
+ xyz[0] = -SIMD_HALF_PI;
+ xyz[1] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
+ xyz[2] = 0.0;
+ }
+ return false;
+}
+
+bool btGeneric6DofSpring2Constraint::matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz)
+{
+ // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx
+ // sz cz*cx -cz*sx
+ // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx
+
+ btScalar fi = btGetMatrixElem(mat,3);
+ if (fi < btScalar(1.0f))
+ {
+ if (fi > btScalar(-1.0f))
+ {
+ xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,4));
+ xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,0));
+ xyz[2] = btAsin(btGetMatrixElem(mat,3));
+ return true;
+ }
+ else
+ {
+ xyz[0] = btScalar(0.0);
+ xyz[1] = -btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8));
+ xyz[2] = -SIMD_HALF_PI;
+ return false;
+ }
+ }
+ else
+ {
+ xyz[0] = btScalar(0.0);
+ xyz[1] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8));
+ xyz[2] = SIMD_HALF_PI;
+ }
+ return false;
+}
+
+bool btGeneric6DofSpring2Constraint::matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz)
+{
+ // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx
+ // cy*sz+cz*sx*sy cz*cx sz*sy-cz*xy*sx
+ // -cx*sy sx cx*cy
+
+ btScalar fi = btGetMatrixElem(mat,7);
+ if (fi < btScalar(1.0f))
+ {
+ if (fi > btScalar(-1.0f))
+ {
+ xyz[0] = btAsin(btGetMatrixElem(mat,7));
+ xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8));
+ xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,4));
+ return true;
+ }
+ else
+ {
+ xyz[0] = -SIMD_HALF_PI;
+ xyz[1] = btScalar(0.0);
+ xyz[2] = -btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0));
+ return false;
+ }
+ }
+ else
+ {
+ xyz[0] = SIMD_HALF_PI;
+ xyz[1] = btScalar(0.0);
+ xyz[2] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0));
+ }
+ return false;
+}
+
+bool btGeneric6DofSpring2Constraint::matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz)
+{
+ // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*sy
+ // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx
+ // -sy cy*sx cy*cx
+
+ btScalar fi = btGetMatrixElem(mat,6);
+ if (fi < btScalar(1.0f))
+ {
+ if (fi > btScalar(-1.0f))
+ {
+ xyz[0] = btAtan2(btGetMatrixElem(mat,7), btGetMatrixElem(mat,8));
+ xyz[1] = btAsin(-btGetMatrixElem(mat,6));
+ xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,0));
+ return true;
+ }
+ else
+ {
+ xyz[0] = btScalar(0.0);
+ xyz[1] = SIMD_HALF_PI;
+ xyz[2] = -btAtan2(btGetMatrixElem(mat,1),btGetMatrixElem(mat,2));
+ return false;
+ }
+ }
+ else
+ {
+ xyz[0] = btScalar(0.0);
+ xyz[1] = -SIMD_HALF_PI;
+ xyz[2] = btAtan2(-btGetMatrixElem(mat,1),-btGetMatrixElem(mat,2));
+ }
+ return false;
+}
+
+void btGeneric6DofSpring2Constraint::calculateAngleInfo()
+{
+ btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
+ switch (m_rotateOrder)
+ {
+ case RO_XYZ : matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); break;
+ case RO_XZY : matrixToEulerXZY(relative_frame,m_calculatedAxisAngleDiff); break;
+ case RO_YXZ : matrixToEulerYXZ(relative_frame,m_calculatedAxisAngleDiff); break;
+ case RO_YZX : matrixToEulerYZX(relative_frame,m_calculatedAxisAngleDiff); break;
+ case RO_ZXY : matrixToEulerZXY(relative_frame,m_calculatedAxisAngleDiff); break;
+ case RO_ZYX : matrixToEulerZYX(relative_frame,m_calculatedAxisAngleDiff); break;
+ default : btAssert(false);
+ }
+ // in euler angle mode we do not actually constrain the angular velocity
+ // along the axes axis[0] and axis[2] (although we do use axis[1]) :
+ //
+ // to get constrain w2-w1 along ...not
+ // ------ --------------------- ------
+ // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
+ // d(angle[1])/dt = 0 ax[1]
+ // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
+ //
+ // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
+ // to prove the result for angle[0], write the expression for angle[0] from
+ // GetInfo1 then take the derivative. to prove this for angle[2] it is
+ // easier to take the euler rate expression for d(angle[2])/dt with respect
+ // to the components of w and set that to 0.
+ switch (m_rotateOrder)
+ {
+ case RO_XYZ :
+ {
+ //Is this the "line of nodes" calculation choosing planes YZ (B coordinate system) and xy (A coordinate system)? (http://en.wikipedia.org/wiki/Euler_angles)
+ //The two planes are non-homologous, so this is a TaitBryan angle formalism and not a proper Euler
+ //Extrinsic rotations are equal to the reversed order intrinsic rotations so the above xyz extrinsic rotations (axes are fixed) are the same as the zy'x" intrinsic rotations (axes are refreshed after each rotation)
+ //that is why xy and YZ planes are chosen (this will describe a zy'x" intrinsic rotation) (see the figure on the left at http://en.wikipedia.org/wiki/Euler_angles under TaitBryan angles)
+ // x' = Nperp = N.cross(axis2)
+ // y' = N = axis2.cross(axis0)
+ // z' = z
+ //
+ // x" = X
+ // y" = y'
+ // z" = ??
+ //in other words:
+ //first rotate around z
+ //second rotate around y'= z.cross(X)
+ //third rotate around x" = X
+ //Original XYZ extrinsic rotation order.
+ //Planes: xy and YZ normals: z, X. Plane intersection (N) is z.cross(X)
+ btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
+ btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
+ m_calculatedAxis[1] = axis2.cross(axis0);
+ m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
+ m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
+ break;
+ }
+ case RO_XZY :
+ {
+ //planes: xz,ZY normals: y, X
+ //first rotate around y
+ //second rotate around z'= y.cross(X)
+ //third rotate around x" = X
+ btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
+ btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1);
+ m_calculatedAxis[2] = axis0.cross(axis1);
+ m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]);
+ m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0);
+ break;
+ }
+ case RO_YXZ :
+ {
+ //planes: yx,XZ normals: z, Y
+ //first rotate around z
+ //second rotate around x'= z.cross(Y)
+ //third rotate around y" = Y
+ btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1);
+ btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
+ m_calculatedAxis[0] = axis1.cross(axis2);
+ m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]);
+ m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1);
+ break;
+ }
+ case RO_YZX :
+ {
+ //planes: yz,ZX normals: x, Y
+ //first rotate around x
+ //second rotate around z'= x.cross(Y)
+ //third rotate around y" = Y
+ btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0);
+ btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1);
+ m_calculatedAxis[2] = axis0.cross(axis1);
+ m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]);
+ m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0);
+ break;
+ }
+ case RO_ZXY :
+ {
+ //planes: zx,XY normals: y, Z
+ //first rotate around y
+ //second rotate around x'= y.cross(Z)
+ //third rotate around z" = Z
+ btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1);
+ btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2);
+ m_calculatedAxis[0] = axis1.cross(axis2);
+ m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]);
+ m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1);
+ break;
+ }
+ case RO_ZYX :
+ {
+ //planes: zy,YX normals: x, Z
+ //first rotate around x
+ //second rotate around y' = x.cross(Z)
+ //third rotate around z" = Z
+ btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0);
+ btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2);
+ m_calculatedAxis[1] = axis2.cross(axis0);
+ m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
+ m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
+ break;
+ }
+ default:
+ btAssert(false);
+ }
+
+ m_calculatedAxis[0].normalize();
+ m_calculatedAxis[1].normalize();
+ m_calculatedAxis[2].normalize();
+
+}
+
+void btGeneric6DofSpring2Constraint::calculateTransforms()
+{
+ calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
+}
+
+void btGeneric6DofSpring2Constraint::calculateTransforms(const btTransform& transA,const btTransform& transB)
+{
+ m_calculatedTransformA = transA * m_frameInA;
+ m_calculatedTransformB = transB * m_frameInB;
+ calculateLinearInfo();
+ calculateAngleInfo();
+
+ btScalar miA = getRigidBodyA().getInvMass();
+ btScalar miB = getRigidBodyB().getInvMass();
+ m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
+ btScalar miS = miA + miB;
+ if(miS > btScalar(0.f))
+ {
+ m_factA = miB / miS;
+ }
+ else
+ {
+ m_factA = btScalar(0.5f);
+ }
+ m_factB = btScalar(1.0f) - m_factA;
+}
+
+
+void btGeneric6DofSpring2Constraint::testAngularLimitMotor(int axis_index)
+{
+ btScalar angle = m_calculatedAxisAngleDiff[axis_index];
+ angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
+ m_angularLimits[axis_index].m_currentPosition = angle;
+ m_angularLimits[axis_index].testLimitValue(angle);
+}
+
+
+void btGeneric6DofSpring2Constraint::getInfo1 (btConstraintInfo1* info)
+{
+ //prepare constraint
+ calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
+ info->m_numConstraintRows = 0;
+ info->nub = 0;
+ int i;
+ //test linear limits
+ for(i = 0; i < 3; i++)
+ {
+ if (m_linearLimits.m_currentLimit[i]==4) info->m_numConstraintRows += 2;
+ else if (m_linearLimits.m_currentLimit[i]!=0) info->m_numConstraintRows += 1;
+ if (m_linearLimits.m_enableMotor[i] ) info->m_numConstraintRows += 1;
+ if (m_linearLimits.m_enableSpring[i]) info->m_numConstraintRows += 1;
+ }
+ //test angular limits
+ for (i=0;i<3 ;i++ )
+ {
+ testAngularLimitMotor(i);
+ if (m_angularLimits[i].m_currentLimit==4) info->m_numConstraintRows += 2;
+ else if (m_angularLimits[i].m_currentLimit!=0) info->m_numConstraintRows += 1;
+ if (m_angularLimits[i].m_enableMotor ) info->m_numConstraintRows += 1;
+ if (m_angularLimits[i].m_enableSpring) info->m_numConstraintRows += 1;
+ }
+}
+
+
+void btGeneric6DofSpring2Constraint::getInfo2 (btConstraintInfo2* info)
+{
+ const btTransform& transA = m_rbA.getCenterOfMassTransform();
+ const btTransform& transB = m_rbB.getCenterOfMassTransform();
+ const btVector3& linVelA = m_rbA.getLinearVelocity();
+ const btVector3& linVelB = m_rbB.getLinearVelocity();
+ const btVector3& angVelA = m_rbA.getAngularVelocity();
+ const btVector3& angVelB = m_rbB.getAngularVelocity();
+
+ // for stability better to solve angular limits first
+ int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
+ setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
+}
+
+
+int btGeneric6DofSpring2Constraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
+{
+ //solve linear limits
+ btRotationalLimitMotor2 limot;
+ for (int i=0;i<3 ;i++ )
+ {
+ if(m_linearLimits.m_currentLimit[i] || m_linearLimits.m_enableMotor[i] || m_linearLimits.m_enableSpring[i])
+ { // re-use rotational motor code
+ limot.m_bounce = m_linearLimits.m_bounce[i];
+ limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
+ limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
+ limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
+ limot.m_currentLimitErrorHi = m_linearLimits.m_currentLimitErrorHi[i];
+ limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
+ limot.m_servoMotor = m_linearLimits.m_servoMotor[i];
+ limot.m_servoTarget = m_linearLimits.m_servoTarget[i];
+ limot.m_enableSpring = m_linearLimits.m_enableSpring[i];
+ limot.m_springStiffness = m_linearLimits.m_springStiffness[i];
+ limot.m_springStiffnessLimited = m_linearLimits.m_springStiffnessLimited[i];
+ limot.m_springDamping = m_linearLimits.m_springDamping[i];
+ limot.m_springDampingLimited = m_linearLimits.m_springDampingLimited[i];
+ limot.m_equilibriumPoint = m_linearLimits.m_equilibriumPoint[i];
+ limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
+ limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
+ limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
+ limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
+ btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
+ int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP2) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
+ limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP2) ? m_linearLimits.m_stopERP[i] : info->erp;
+ limot.m_motorCFM = (flags & BT_6DOF_FLAGS_CFM_MOTO2) ? m_linearLimits.m_motorCFM[i] : info->cfm[0];
+ limot.m_motorERP = (flags & BT_6DOF_FLAGS_ERP_MOTO2) ? m_linearLimits.m_motorERP[i] : info->erp;
+
+ //rotAllowed is a bit of a magic from the original 6dof. The calculation of it here is something that imitates the original behavior as much as possible.
+ int indx1 = (i + 1) % 3;
+ int indx2 = (i + 2) % 3;
+ int rotAllowed = 1; // rotations around orthos to current axis (it is used only when one of the body is static)
+ #define D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION 1.0e-3
+ bool indx1Violated = m_angularLimits[indx1].m_currentLimit == 1 ||
+ m_angularLimits[indx1].m_currentLimit == 2 ||
+ ( m_angularLimits[indx1].m_currentLimit == 3 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) ||
+ ( m_angularLimits[indx1].m_currentLimit == 4 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) );
+ bool indx2Violated = m_angularLimits[indx2].m_currentLimit == 1 ||
+ m_angularLimits[indx2].m_currentLimit == 2 ||
+ ( m_angularLimits[indx2].m_currentLimit == 3 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) ||
+ ( m_angularLimits[indx2].m_currentLimit == 4 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) );
+ if( indx1Violated && indx2Violated )
+ {
+ rotAllowed = 0;
+ }
+ row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed);
+
+ }
+ }
+ return row;
+}
+
+
+
+int btGeneric6DofSpring2Constraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
+{
+ int row = row_offset;
+
+ //order of rotational constraint rows
+ int cIdx[] = {0, 1, 2};
+ switch(m_rotateOrder)
+ {
+ case RO_XYZ : cIdx[0] = 0; cIdx[1] = 1; cIdx[2] = 2; break;
+ case RO_XZY : cIdx[0] = 0; cIdx[1] = 2; cIdx[2] = 1; break;
+ case RO_YXZ : cIdx[0] = 1; cIdx[1] = 0; cIdx[2] = 2; break;
+ case RO_YZX : cIdx[0] = 1; cIdx[1] = 2; cIdx[2] = 0; break;
+ case RO_ZXY : cIdx[0] = 2; cIdx[1] = 0; cIdx[2] = 1; break;
+ case RO_ZYX : cIdx[0] = 2; cIdx[1] = 1; cIdx[2] = 0; break;
+ default : btAssert(false);
+ }
+
+ for (int ii = 0; ii < 3 ; ii++ )
+ {
+ int i = cIdx[ii];
+ if(m_angularLimits[i].m_currentLimit || m_angularLimits[i].m_enableMotor || m_angularLimits[i].m_enableSpring)
+ {
+ btVector3 axis = getAxis(i);
+ int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ if(!(flags & BT_6DOF_FLAGS_CFM_STOP2))
+ {
+ m_angularLimits[i].m_stopCFM = info->cfm[0];
+ }
+ if(!(flags & BT_6DOF_FLAGS_ERP_STOP2))
+ {
+ m_angularLimits[i].m_stopERP = info->erp;
+ }
+ if(!(flags & BT_6DOF_FLAGS_CFM_MOTO2))
+ {
+ m_angularLimits[i].m_motorCFM = info->cfm[0];
+ }
+ if(!(flags & BT_6DOF_FLAGS_ERP_MOTO2))
+ {
+ m_angularLimits[i].m_motorERP = info->erp;
+ }
+ row += get_limit_motor_info2(&m_angularLimits[i],transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1);
+ }
+ }
+
+ return row;
+}
+
+
+void btGeneric6DofSpring2Constraint::setFrames(const btTransform& frameA, const btTransform& frameB)
+{
+ m_frameInA = frameA;
+ m_frameInB = frameB;
+ buildJacobian();
+ calculateTransforms();
+}
+
+
+void btGeneric6DofSpring2Constraint::calculateLinearInfo()
+{
+ m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
+ m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
+ for(int i = 0; i < 3; i++)
+ {
+ m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
+ m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
+ }
+}
+
+void btGeneric6DofSpring2Constraint::calculateJacobi(btRotationalLimitMotor2 * limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2 *info, int srow, btVector3& ax1, int rotational, int rotAllowed)
+{
+ btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
+ btScalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis;
+
+ J1[srow+0] = ax1[0];
+ J1[srow+1] = ax1[1];
+ J1[srow+2] = ax1[2];
+
+ J2[srow+0] = -ax1[0];
+ J2[srow+1] = -ax1[1];
+ J2[srow+2] = -ax1[2];
+
+ if(!rotational)
+ {
+ btVector3 tmpA, tmpB, relA, relB;
+ // get vector from bodyB to frameB in WCS
+ relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
+ // same for bodyA
+ relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
+ tmpA = relA.cross(ax1);
+ tmpB = relB.cross(ax1);
+ if(m_hasStaticBody && (!rotAllowed))
+ {
+ tmpA *= m_factA;
+ tmpB *= m_factB;
+ }
+ int i;
+ for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i];
+ for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i];
+ }
+}
+
+
+int btGeneric6DofSpring2Constraint::get_limit_motor_info2(
+ btRotationalLimitMotor2 * limot,
+ const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
+ btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed)
+{
+ int count = 0;
+ int srow = row * info->rowskip;
+
+ if (limot->m_currentLimit==4)
+ {
+ btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1);
+
+ calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
+ info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1);
+ if (rotational) {
+ if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) {
+ btScalar bounceerror = -limot->m_bounce* vel;
+ if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
+ }
+ } else {
+ if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) {
+ btScalar bounceerror = -limot->m_bounce* vel;
+ if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
+ }
+ }
+ info->m_lowerLimit[srow] = rotational ? 0 : -SIMD_INFINITY;
+ info->m_upperLimit[srow] = rotational ? SIMD_INFINITY : 0;
+ info->cfm[srow] = limot->m_stopCFM;
+ srow += info->rowskip;
+ ++count;
+
+ calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
+ info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitErrorHi * (rotational ? -1 : 1);
+ if (rotational) {
+ if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) {
+ btScalar bounceerror = -limot->m_bounce* vel;
+ if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
+ }
+ } else {
+ if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) {
+ btScalar bounceerror = -limot->m_bounce* vel;
+ if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror;
+ }
+ }
+ info->m_lowerLimit[srow] = rotational ? -SIMD_INFINITY : 0;
+ info->m_upperLimit[srow] = rotational ? 0 : SIMD_INFINITY;
+ info->cfm[srow] = limot->m_stopCFM;
+ srow += info->rowskip;
+ ++count;
+ } else
+ if (limot->m_currentLimit==3)
+ {
+ calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
+ info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1);
+ info->m_lowerLimit[srow] = -SIMD_INFINITY;
+ info->m_upperLimit[srow] = SIMD_INFINITY;
+ info->cfm[srow] = limot->m_stopCFM;
+ srow += info->rowskip;
+ ++count;
+ }
+
+ if (limot->m_enableMotor && !limot->m_servoMotor)
+ {
+ calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
+ btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
+ btScalar mot_fact = getMotorFactor(limot->m_currentPosition,
+ limot->m_loLimit,
+ limot->m_hiLimit,
+ 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->cfm[srow] = limot->m_motorCFM;
+ srow += info->rowskip;
+ ++count;
+ }
+
+ if (limot->m_enableMotor && limot->m_servoMotor)
+ {
+ btScalar error = limot->m_currentPosition - limot->m_servoTarget;
+ calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
+ btScalar targetvelocity = error<0 ? -limot->m_targetVelocity : limot->m_targetVelocity;
+ btScalar tag_vel = -targetvelocity;
+ btScalar mot_fact;
+ if(error != 0)
+ {
+ btScalar lowLimit;
+ btScalar hiLimit;
+ if(limot->m_loLimit > limot->m_hiLimit)
+ {
+ lowLimit = error > 0 ? limot->m_servoTarget : -SIMD_INFINITY;
+ hiLimit = error < 0 ? limot->m_servoTarget : SIMD_INFINITY;
+ }
+ else
+ {
+ lowLimit = error > 0 && limot->m_servoTarget>limot->m_loLimit ? limot->m_servoTarget : limot->m_loLimit;
+ hiLimit = error < 0 && limot->m_servoTarget<limot->m_hiLimit ? limot->m_servoTarget : limot->m_hiLimit;
+ }
+ mot_fact = getMotorFactor(limot->m_currentPosition, lowLimit, hiLimit, tag_vel, info->fps * limot->m_motorERP);
+ }
+ else
+ {
+ 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->cfm[srow] = limot->m_motorCFM;
+ srow += info->rowskip;
+ ++count;
+ }
+
+ if (limot->m_enableSpring)
+ {
+ btScalar error = limot->m_currentPosition - limot->m_equilibriumPoint;
+ calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed);
+
+ //btScalar cfm = 1.0 / ((1.0/info->fps)*limot->m_springStiffness+ limot->m_springDamping);
+ //if(cfm > 0.99999)
+ // cfm = 0.99999;
+ //btScalar erp = (1.0/info->fps)*limot->m_springStiffness / ((1.0/info->fps)*limot->m_springStiffness + limot->m_springDamping);
+ //info->m_constraintError[srow] = info->fps * erp * error * (rotational ? -1.0 : 1.0);
+ //info->m_lowerLimit[srow] = -SIMD_INFINITY;
+ //info->m_upperLimit[srow] = SIMD_INFINITY;
+
+ btScalar dt = BT_ONE / info->fps;
+ btScalar kd = limot->m_springDamping;
+ btScalar ks = limot->m_springStiffness;
+ btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1);
+// btScalar erp = 0.1;
+ btScalar cfm = BT_ZERO;
+ btScalar mA = BT_ONE / m_rbA.getInvMass();
+ btScalar mB = BT_ONE / m_rbB.getInvMass();
+ btScalar m = mA > mB ? mB : mA;
+ btScalar angularfreq = sqrt(ks / m);
+
+
+ //limit stiffness (the spring should not be sampled faster that the quarter of its angular frequency)
+ if(limot->m_springStiffnessLimited && 0.25 < angularfreq * dt)
+ {
+ ks = BT_ONE / dt / dt / btScalar(16.0) * m;
+ }
+ //avoid damping that would blow up the spring
+ if(limot->m_springDampingLimited && kd * dt > m)
+ {
+ kd = m / dt;
+ }
+ btScalar fs = ks * error * dt;
+ btScalar fd = -kd * (vel) * (rotational ? -1 : 1) * dt;
+ btScalar f = (fs+fd);
+
+ info->m_constraintError[srow] = (vel + f * (rotational ? -1 : 1)) ;
+
+ btScalar minf = f < fd ? f : fd;
+ btScalar maxf = f < fd ? fd : f;
+ if(!rotational)
+ {
+ info->m_lowerLimit[srow] = minf > 0 ? 0 : minf;
+ info->m_upperLimit[srow] = maxf < 0 ? 0 : maxf;
+ }
+ else
+ {
+ info->m_lowerLimit[srow] = -maxf > 0 ? 0 : -maxf;
+ info->m_upperLimit[srow] = -minf < 0 ? 0 : -minf;
+ }
+
+ info->cfm[srow] = cfm;
+ srow += info->rowskip;
+ ++count;
+ }
+
+ return count;
+}
+
+
+//override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
+//If no axis is provided, it uses the default axis for this constraint.
+void btGeneric6DofSpring2Constraint::setParam(int num, btScalar value, int axis)
+{
+ if((axis >= 0) && (axis < 3))
+ {
+ switch(num)
+ {
+ case BT_CONSTRAINT_STOP_ERP :
+ m_linearLimits.m_stopERP[axis] = value;
+ m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ case BT_CONSTRAINT_STOP_CFM :
+ m_linearLimits.m_stopCFM[axis] = value;
+ m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ case BT_CONSTRAINT_ERP :
+ m_linearLimits.m_motorERP[axis] = value;
+ m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ case BT_CONSTRAINT_CFM :
+ m_linearLimits.m_motorCFM[axis] = value;
+ m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ default :
+ btAssertConstrParams(0);
+ }
+ }
+ else if((axis >=3) && (axis < 6))
+ {
+ switch(num)
+ {
+ case BT_CONSTRAINT_STOP_ERP :
+ m_angularLimits[axis - 3].m_stopERP = value;
+ m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ case BT_CONSTRAINT_STOP_CFM :
+ m_angularLimits[axis - 3].m_stopCFM = value;
+ m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ case BT_CONSTRAINT_ERP :
+ m_angularLimits[axis - 3].m_motorERP = value;
+ m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ case BT_CONSTRAINT_CFM :
+ m_angularLimits[axis - 3].m_motorCFM = value;
+ m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2);
+ break;
+ default :
+ btAssertConstrParams(0);
+ }
+ }
+ else
+ {
+ btAssertConstrParams(0);
+ }
+}
+
+//return the local value of parameter
+btScalar btGeneric6DofSpring2Constraint::getParam(int num, int axis) const
+{
+ btScalar retVal = 0;
+ if((axis >= 0) && (axis < 3))
+ {
+ switch(num)
+ {
+ case BT_CONSTRAINT_STOP_ERP :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_linearLimits.m_stopERP[axis];
+ break;
+ case BT_CONSTRAINT_STOP_CFM :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_linearLimits.m_stopCFM[axis];
+ break;
+ case BT_CONSTRAINT_ERP :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_linearLimits.m_motorERP[axis];
+ break;
+ case BT_CONSTRAINT_CFM :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_linearLimits.m_motorCFM[axis];
+ break;
+ default :
+ btAssertConstrParams(0);
+ }
+ }
+ else if((axis >=3) && (axis < 6))
+ {
+ switch(num)
+ {
+ case BT_CONSTRAINT_STOP_ERP :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_angularLimits[axis - 3].m_stopERP;
+ break;
+ case BT_CONSTRAINT_STOP_CFM :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_angularLimits[axis - 3].m_stopCFM;
+ break;
+ case BT_CONSTRAINT_ERP :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_angularLimits[axis - 3].m_motorERP;
+ break;
+ case BT_CONSTRAINT_CFM :
+ btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2)));
+ retVal = m_angularLimits[axis - 3].m_motorCFM;
+ break;
+ default :
+ btAssertConstrParams(0);
+ }
+ }
+ else
+ {
+ btAssertConstrParams(0);
+ }
+ return retVal;
+}
+
+
+
+void btGeneric6DofSpring2Constraint::setAxis(const btVector3& axis1,const btVector3& axis2)
+{
+ btVector3 zAxis = axis1.normalized();
+ btVector3 yAxis = axis2.normalized();
+ btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
+
+ btTransform frameInW;
+ frameInW.setIdentity();
+ frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0],
+ xAxis[1], yAxis[1], zAxis[1],
+ xAxis[2], yAxis[2], zAxis[2]);
+
+ // now get constraint frame in local coordinate systems
+ m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW;
+ m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW;
+
+ calculateTransforms();
+}
+
+void btGeneric6DofSpring2Constraint::setBounce(int index, btScalar bounce)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_bounce[index] = bounce;
+ else
+ m_angularLimits[index - 3].m_bounce = bounce;
+}
+
+void btGeneric6DofSpring2Constraint::enableMotor(int index, bool onOff)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_enableMotor[index] = onOff;
+ else
+ m_angularLimits[index - 3].m_enableMotor = onOff;
+}
+
+void btGeneric6DofSpring2Constraint::setServo(int index, bool onOff)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_servoMotor[index] = onOff;
+ else
+ m_angularLimits[index - 3].m_servoMotor = onOff;
+}
+
+void btGeneric6DofSpring2Constraint::setTargetVelocity(int index, btScalar velocity)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_targetVelocity[index] = velocity;
+ else
+ m_angularLimits[index - 3].m_targetVelocity = velocity;
+}
+
+void btGeneric6DofSpring2Constraint::setServoTarget(int index, btScalar target)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_servoTarget[index] = target;
+ else
+ m_angularLimits[index - 3].m_servoTarget = target;
+}
+
+void btGeneric6DofSpring2Constraint::setMaxMotorForce(int index, btScalar force)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_maxMotorForce[index] = force;
+ else
+ m_angularLimits[index - 3].m_maxMotorForce = force;
+}
+
+void btGeneric6DofSpring2Constraint::enableSpring(int index, bool onOff)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_enableSpring[index] = onOff;
+ else
+ m_angularLimits[index - 3] .m_enableSpring = onOff;
+}
+
+void btGeneric6DofSpring2Constraint::setStiffness(int index, btScalar stiffness, bool limitIfNeeded)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3) {
+ m_linearLimits.m_springStiffness[index] = stiffness;
+ m_linearLimits.m_springStiffnessLimited[index] = limitIfNeeded;
+ } else {
+ m_angularLimits[index - 3].m_springStiffness = stiffness;
+ m_angularLimits[index - 3].m_springStiffnessLimited = limitIfNeeded;
+ }
+}
+
+void btGeneric6DofSpring2Constraint::setDamping(int index, btScalar damping, bool limitIfNeeded)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3) {
+ m_linearLimits.m_springDamping[index] = damping;
+ m_linearLimits.m_springDampingLimited[index] = limitIfNeeded;
+ } else {
+ m_angularLimits[index - 3].m_springDamping = damping;
+ m_angularLimits[index - 3].m_springDampingLimited = limitIfNeeded;
+ }
+}
+
+void btGeneric6DofSpring2Constraint::setEquilibriumPoint()
+{
+ calculateTransforms();
+ int i;
+ for( i = 0; i < 3; i++)
+ m_linearLimits.m_equilibriumPoint[i] = m_calculatedLinearDiff[i];
+ for(i = 0; i < 3; i++)
+ m_angularLimits[i].m_equilibriumPoint = m_calculatedAxisAngleDiff[i];
+}
+
+void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index)
+{
+ btAssert((index >= 0) && (index < 6));
+ calculateTransforms();
+ if (index<3)
+ m_linearLimits.m_equilibriumPoint[index] = m_calculatedLinearDiff[index];
+ else
+ m_angularLimits[index - 3] .m_equilibriumPoint = m_calculatedAxisAngleDiff[index - 3];
+}
+
+void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index, btScalar val)
+{
+ btAssert((index >= 0) && (index < 6));
+ if (index<3)
+ m_linearLimits.m_equilibriumPoint[index] = val;
+ else
+ m_angularLimits[index - 3] .m_equilibriumPoint = val;
+}
+
+
+//////////////////////////// btRotationalLimitMotor2 ////////////////////////////////////
+
+void btRotationalLimitMotor2::testLimitValue(btScalar test_value)
+{
+ //we can't normalize the angles here because we would lost the sign that we use later, but it doesn't seem to be a problem
+ if(m_loLimit > m_hiLimit) {
+ m_currentLimit = 0;
+ m_currentLimitError = btScalar(0.f);
+ }
+ else if(m_loLimit == m_hiLimit) {
+ m_currentLimitError = test_value - m_loLimit;
+ m_currentLimit = 3;
+ } else {
+ m_currentLimitError = test_value - m_loLimit;
+ m_currentLimitErrorHi = test_value - m_hiLimit;
+ m_currentLimit = 4;
+ }
+}
+
+//////////////////////////// btTranslationalLimitMotor2 ////////////////////////////////////
+
+void btTranslationalLimitMotor2::testLimitValue(int limitIndex, btScalar test_value)
+{
+ btScalar loLimit = m_lowerLimit[limitIndex];
+ btScalar hiLimit = m_upperLimit[limitIndex];
+ if(loLimit > hiLimit) {
+ m_currentLimitError[limitIndex] = 0;
+ m_currentLimit[limitIndex] = 0;
+ }
+ else if(loLimit == hiLimit) {
+ m_currentLimitError[limitIndex] = test_value - loLimit;
+ m_currentLimit[limitIndex] = 3;
+ } else {
+ m_currentLimitError[limitIndex] = test_value - loLimit;
+ m_currentLimitErrorHi[limitIndex] = test_value - hiLimit;
+ m_currentLimit[limitIndex] = 4;
+ }
+}
+
+
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h
new file mode 100644
index 00000000000..ace4b3c29bf
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h
@@ -0,0 +1,674 @@
+/*
+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.
+*/
+
+/*
+2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer
+Pros:
+- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled)
+- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring)
+- Servo motor functionality
+- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision)
+- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2)
+
+Cons:
+- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation.
+- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.)
+*/
+
+/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev
+/// Added support for generic constraint solver through getInfo1/getInfo2 methods
+
+/*
+2007-09-09
+btGeneric6DofConstraint Refactored by Francisco Le?n
+email: projectileman@yahoo.com
+http://gimpact.sf.net
+*/
+
+
+#ifndef BT_GENERIC_6DOF_CONSTRAINT2_H
+#define BT_GENERIC_6DOF_CONSTRAINT2_H
+
+#include "LinearMath/btVector3.h"
+#include "btJacobianEntry.h"
+#include "btTypedConstraint.h"
+
+class btRigidBody;
+
+
+#ifdef BT_USE_DOUBLE_PRECISION
+#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintDoubleData2
+#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintDoubleData2"
+#else
+#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintData
+#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintData"
+#endif //BT_USE_DOUBLE_PRECISION
+
+enum RotateOrder
+{
+ RO_XYZ=0,
+ RO_XZY,
+ RO_YXZ,
+ RO_YZX,
+ RO_ZXY,
+ RO_ZYX
+};
+
+class btRotationalLimitMotor2
+{
+public:
+// upper < lower means free
+// upper == lower means locked
+// upper > lower means limited
+ btScalar m_loLimit;
+ btScalar m_hiLimit;
+ btScalar m_bounce;
+ btScalar m_stopERP;
+ btScalar m_stopCFM;
+ btScalar m_motorERP;
+ btScalar m_motorCFM;
+ bool m_enableMotor;
+ btScalar m_targetVelocity;
+ btScalar m_maxMotorForce;
+ bool m_servoMotor;
+ btScalar m_servoTarget;
+ bool m_enableSpring;
+ btScalar m_springStiffness;
+ bool m_springStiffnessLimited;
+ btScalar m_springDamping;
+ bool m_springDampingLimited;
+ btScalar m_equilibriumPoint;
+
+ btScalar m_currentLimitError;
+ btScalar m_currentLimitErrorHi;
+ btScalar m_currentPosition;
+ int m_currentLimit;
+
+ btRotationalLimitMotor2()
+ {
+ m_loLimit = 1.0f;
+ m_hiLimit = -1.0f;
+ m_bounce = 0.0f;
+ m_stopERP = 0.2f;
+ m_stopCFM = 0.f;
+ m_motorERP = 0.9f;
+ m_motorCFM = 0.f;
+ m_enableMotor = false;
+ m_targetVelocity = 0;
+ m_maxMotorForce = 0.1f;
+ m_servoMotor = false;
+ m_servoTarget = 0;
+ m_enableSpring = false;
+ m_springStiffness = 0;
+ m_springStiffnessLimited = false;
+ m_springDamping = 0;
+ m_springDampingLimited = false;
+ m_equilibriumPoint = 0;
+
+ m_currentLimitError = 0;
+ m_currentLimitErrorHi = 0;
+ m_currentPosition = 0;
+ m_currentLimit = 0;
+ }
+
+ btRotationalLimitMotor2(const btRotationalLimitMotor2 & limot)
+ {
+ m_loLimit = limot.m_loLimit;
+ m_hiLimit = limot.m_hiLimit;
+ m_bounce = limot.m_bounce;
+ m_stopERP = limot.m_stopERP;
+ m_stopCFM = limot.m_stopCFM;
+ m_motorERP = limot.m_motorERP;
+ m_motorCFM = limot.m_motorCFM;
+ m_enableMotor = limot.m_enableMotor;
+ m_targetVelocity = limot.m_targetVelocity;
+ m_maxMotorForce = limot.m_maxMotorForce;
+ m_servoMotor = limot.m_servoMotor;
+ m_servoTarget = limot.m_servoTarget;
+ m_enableSpring = limot.m_enableSpring;
+ m_springStiffness = limot.m_springStiffness;
+ m_springStiffnessLimited = limot.m_springStiffnessLimited;
+ m_springDamping = limot.m_springDamping;
+ m_springDampingLimited = limot.m_springDampingLimited;
+ m_equilibriumPoint = limot.m_equilibriumPoint;
+
+ m_currentLimitError = limot.m_currentLimitError;
+ m_currentLimitErrorHi = limot.m_currentLimitErrorHi;
+ m_currentPosition = limot.m_currentPosition;
+ m_currentLimit = limot.m_currentLimit;
+ }
+
+
+ bool isLimited()
+ {
+ if(m_loLimit > m_hiLimit) return false;
+ return true;
+ }
+
+ void testLimitValue(btScalar test_value);
+};
+
+
+
+class btTranslationalLimitMotor2
+{
+public:
+// upper < lower means free
+// upper == lower means locked
+// upper > lower means limited
+ btVector3 m_lowerLimit;
+ btVector3 m_upperLimit;
+ btVector3 m_bounce;
+ btVector3 m_stopERP;
+ btVector3 m_stopCFM;
+ btVector3 m_motorERP;
+ btVector3 m_motorCFM;
+ bool m_enableMotor[3];
+ bool m_servoMotor[3];
+ bool m_enableSpring[3];
+ btVector3 m_servoTarget;
+ btVector3 m_springStiffness;
+ bool m_springStiffnessLimited[3];
+ btVector3 m_springDamping;
+ bool m_springDampingLimited[3];
+ btVector3 m_equilibriumPoint;
+ btVector3 m_targetVelocity;
+ btVector3 m_maxMotorForce;
+
+ btVector3 m_currentLimitError;
+ btVector3 m_currentLimitErrorHi;
+ btVector3 m_currentLinearDiff;
+ int m_currentLimit[3];
+
+ btTranslationalLimitMotor2()
+ {
+ m_lowerLimit .setValue(0.f , 0.f , 0.f );
+ m_upperLimit .setValue(0.f , 0.f , 0.f );
+ m_bounce .setValue(0.f , 0.f , 0.f );
+ m_stopERP .setValue(0.2f, 0.2f, 0.2f);
+ m_stopCFM .setValue(0.f , 0.f , 0.f );
+ m_motorERP .setValue(0.9f, 0.9f, 0.9f);
+ m_motorCFM .setValue(0.f , 0.f , 0.f );
+
+ m_currentLimitError .setValue(0.f , 0.f , 0.f );
+ m_currentLimitErrorHi.setValue(0.f , 0.f , 0.f );
+ m_currentLinearDiff .setValue(0.f , 0.f , 0.f );
+
+ for(int i=0; i < 3; i++)
+ {
+ m_enableMotor[i] = false;
+ m_servoMotor[i] = false;
+ m_enableSpring[i] = false;
+ m_servoTarget[i] = btScalar(0.f);
+ m_springStiffness[i] = btScalar(0.f);
+ m_springStiffnessLimited[i] = false;
+ m_springDamping[i] = btScalar(0.f);
+ m_springDampingLimited[i] = false;
+ m_equilibriumPoint[i] = btScalar(0.f);
+ m_targetVelocity[i] = btScalar(0.f);
+ m_maxMotorForce[i] = btScalar(0.f);
+
+ m_currentLimit[i] = 0;
+ }
+ }
+
+ btTranslationalLimitMotor2(const btTranslationalLimitMotor2 & other )
+ {
+ m_lowerLimit = other.m_lowerLimit;
+ m_upperLimit = other.m_upperLimit;
+ m_bounce = other.m_bounce;
+ m_stopERP = other.m_stopERP;
+ m_stopCFM = other.m_stopCFM;
+ m_motorERP = other.m_motorERP;
+ m_motorCFM = other.m_motorCFM;
+
+ m_currentLimitError = other.m_currentLimitError;
+ m_currentLimitErrorHi = other.m_currentLimitErrorHi;
+ m_currentLinearDiff = other.m_currentLinearDiff;
+
+ for(int i=0; i < 3; i++)
+ {
+ m_enableMotor[i] = other.m_enableMotor[i];
+ m_servoMotor[i] = other.m_servoMotor[i];
+ m_enableSpring[i] = other.m_enableSpring[i];
+ m_servoTarget[i] = other.m_servoTarget[i];
+ m_springStiffness[i] = other.m_springStiffness[i];
+ m_springStiffnessLimited[i] = other.m_springStiffnessLimited[i];
+ m_springDamping[i] = other.m_springDamping[i];
+ m_springDampingLimited[i] = other.m_springDampingLimited[i];
+ m_equilibriumPoint[i] = other.m_equilibriumPoint[i];
+ m_targetVelocity[i] = other.m_targetVelocity[i];
+ m_maxMotorForce[i] = other.m_maxMotorForce[i];
+
+ m_currentLimit[i] = other.m_currentLimit[i];
+ }
+ }
+
+ inline bool isLimited(int limitIndex)
+ {
+ return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
+ }
+
+ void testLimitValue(int limitIndex, btScalar test_value);
+};
+
+enum bt6DofFlags2
+{
+ BT_6DOF_FLAGS_CFM_STOP2 = 1,
+ BT_6DOF_FLAGS_ERP_STOP2 = 2,
+ BT_6DOF_FLAGS_CFM_MOTO2 = 4,
+ BT_6DOF_FLAGS_ERP_MOTO2 = 8
+};
+#define BT_6DOF_FLAGS_AXIS_SHIFT2 4 // bits per axis
+
+
+ATTRIBUTE_ALIGNED16(class) btGeneric6DofSpring2Constraint : public btTypedConstraint
+{
+protected:
+
+ btTransform m_frameInA;
+ btTransform m_frameInB;
+
+ btJacobianEntry m_jacLinear[3];
+ btJacobianEntry m_jacAng[3];
+
+ btTranslationalLimitMotor2 m_linearLimits;
+ btRotationalLimitMotor2 m_angularLimits[3];
+
+ RotateOrder m_rotateOrder;
+
+protected:
+
+ btTransform m_calculatedTransformA;
+ btTransform m_calculatedTransformB;
+ btVector3 m_calculatedAxisAngleDiff;
+ btVector3 m_calculatedAxis[3];
+ btVector3 m_calculatedLinearDiff;
+ btScalar m_factA;
+ btScalar m_factB;
+ bool m_hasStaticBody;
+ int m_flags;
+
+ btGeneric6DofSpring2Constraint& operator=(btGeneric6DofSpring2Constraint&)
+ {
+ btAssert(0);
+ return *this;
+ }
+
+ int setAngularLimits(btConstraintInfo2 *info, int row_offset,const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB);
+ int setLinearLimits(btConstraintInfo2 *info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB);
+
+ void calculateLinearInfo();
+ void calculateAngleInfo();
+ void testAngularLimitMotor(int axis_index);
+
+ void calculateJacobi(btRotationalLimitMotor2* limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2* info, int srow, btVector3& ax1, int rotational, int rotAllowed);
+ int get_limit_motor_info2(btRotationalLimitMotor2* limot,
+ const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
+ btConstraintInfo2* info, int row, btVector3& ax1, int rotational, int rotAllowed = false);
+
+ static btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
+ static bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
+ static bool matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz);
+ static bool matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz);
+ static bool matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz);
+ static bool matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz);
+ static bool matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz);
+
+public:
+
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
+ btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ);
+ btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ);
+
+ virtual void buildJacobian() {}
+ virtual void getInfo1 (btConstraintInfo1* info);
+ virtual void getInfo2 (btConstraintInfo2* info);
+ virtual int calculateSerializeBufferSize() const;
+ virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const;
+
+ btRotationalLimitMotor2* getRotationalLimitMotor(int index) { return &m_angularLimits[index]; }
+ btTranslationalLimitMotor2* getTranslationalLimitMotor() { return &m_linearLimits; }
+
+ // Calculates the global transform for the joint offset for body A an B, and also calculates the angle differences between the bodies.
+ void calculateTransforms(const btTransform& transA,const btTransform& transB);
+ void calculateTransforms();
+
+ // Gets the global transform of the offset for body A
+ const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; }
+ // Gets the global transform of the offset for body B
+ const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; }
+
+ const btTransform & getFrameOffsetA() const { return m_frameInA; }
+ const btTransform & getFrameOffsetB() const { return m_frameInB; }
+
+ btTransform & getFrameOffsetA() { return m_frameInA; }
+ btTransform & getFrameOffsetB() { return m_frameInB; }
+
+ // Get the rotation axis in global coordinates ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously )
+ btVector3 getAxis(int axis_index) const { return m_calculatedAxis[axis_index]; }
+
+ // Get the relative Euler angle ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously )
+ btScalar getAngle(int axis_index) const { return m_calculatedAxisAngleDiff[axis_index]; }
+
+ // Get the relative position of the constraint pivot ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously )
+ btScalar getRelativePivotPosition(int axis_index) const { return m_calculatedLinearDiff[axis_index]; }
+
+ void setFrames(const btTransform & frameA, const btTransform & frameB);
+
+ void setLinearLowerLimit(const btVector3& linearLower) { m_linearLimits.m_lowerLimit = linearLower; }
+ void getLinearLowerLimit(btVector3& linearLower) { linearLower = m_linearLimits.m_lowerLimit; }
+ void setLinearUpperLimit(const btVector3& linearUpper) { m_linearLimits.m_upperLimit = linearUpper; }
+ void getLinearUpperLimit(btVector3& linearUpper) { linearUpper = m_linearLimits.m_upperLimit; }
+
+ void setAngularLowerLimit(const btVector3& angularLower)
+ {
+ for(int i = 0; i < 3; i++)
+ m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]);
+ }
+
+ void setAngularLowerLimitReversed(const btVector3& angularLower)
+ {
+ for(int i = 0; i < 3; i++)
+ m_angularLimits[i].m_hiLimit = btNormalizeAngle(-angularLower[i]);
+ }
+
+ void getAngularLowerLimit(btVector3& angularLower)
+ {
+ for(int i = 0; i < 3; i++)
+ angularLower[i] = m_angularLimits[i].m_loLimit;
+ }
+
+ void getAngularLowerLimitReversed(btVector3& angularLower)
+ {
+ for(int i = 0; i < 3; i++)
+ angularLower[i] = -m_angularLimits[i].m_hiLimit;
+ }
+
+ void setAngularUpperLimit(const btVector3& angularUpper)
+ {
+ for(int i = 0; i < 3; i++)
+ m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]);
+ }
+
+ void setAngularUpperLimitReversed(const btVector3& angularUpper)
+ {
+ for(int i = 0; i < 3; i++)
+ m_angularLimits[i].m_loLimit = btNormalizeAngle(-angularUpper[i]);
+ }
+
+ void getAngularUpperLimit(btVector3& angularUpper)
+ {
+ for(int i = 0; i < 3; i++)
+ angularUpper[i] = m_angularLimits[i].m_hiLimit;
+ }
+
+ void getAngularUpperLimitReversed(btVector3& angularUpper)
+ {
+ for(int i = 0; i < 3; i++)
+ angularUpper[i] = -m_angularLimits[i].m_loLimit;
+ }
+
+ //first 3 are linear, next 3 are angular
+
+ void setLimit(int axis, btScalar lo, btScalar hi)
+ {
+ if(axis<3)
+ {
+ m_linearLimits.m_lowerLimit[axis] = lo;
+ m_linearLimits.m_upperLimit[axis] = hi;
+ }
+ else
+ {
+ lo = btNormalizeAngle(lo);
+ hi = btNormalizeAngle(hi);
+ m_angularLimits[axis-3].m_loLimit = lo;
+ m_angularLimits[axis-3].m_hiLimit = hi;
+ }
+ }
+
+ void setLimitReversed(int axis, btScalar lo, btScalar hi)
+ {
+ if(axis<3)
+ {
+ m_linearLimits.m_lowerLimit[axis] = lo;
+ m_linearLimits.m_upperLimit[axis] = hi;
+ }
+ else
+ {
+ lo = btNormalizeAngle(lo);
+ hi = btNormalizeAngle(hi);
+ m_angularLimits[axis-3].m_hiLimit = -lo;
+ m_angularLimits[axis-3].m_loLimit = -hi;
+ }
+ }
+
+ bool isLimited(int limitIndex)
+ {
+ if(limitIndex<3)
+ {
+ return m_linearLimits.isLimited(limitIndex);
+ }
+ return m_angularLimits[limitIndex-3].isLimited();
+ }
+
+ void setRotationOrder(RotateOrder order) { m_rotateOrder = order; }
+ RotateOrder getRotationOrder() { return m_rotateOrder; }
+
+ void setAxis( const btVector3& axis1, const btVector3& axis2);
+
+ void setBounce(int index, btScalar bounce);
+
+ void enableMotor(int index, bool onOff);
+ void setServo(int index, bool onOff); // set the type of the motor (servo or not) (the motor has to be turned on for servo also)
+ void setTargetVelocity(int index, btScalar velocity);
+ void setServoTarget(int index, btScalar target);
+ void setMaxMotorForce(int index, btScalar force);
+
+ void enableSpring(int index, bool onOff);
+ void setStiffness(int index, btScalar stiffness, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the stiffness in necessary situations where otherwise the spring would move unrealistically too widely
+ void setDamping(int index, btScalar damping, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the damping in necessary situations where otherwise the spring would blow up
+ void setEquilibriumPoint(); // set the current constraint position/orientation as an equilibrium point for all DOF
+ void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF
+ void setEquilibriumPoint(int index, btScalar val);
+
+ //override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
+ //If no axis is provided, it uses the default axis for this constraint.
+ virtual void setParam(int num, btScalar value, int axis = -1);
+ virtual btScalar getParam(int num, int axis = -1) const;
+};
+
+
+struct btGeneric6DofSpring2ConstraintData
+{
+ btTypedConstraintData m_typeConstraintData;
+ btTransformFloatData m_rbAFrame;
+ btTransformFloatData m_rbBFrame;
+
+ btVector3FloatData m_linearUpperLimit;
+ btVector3FloatData m_linearLowerLimit;
+ btVector3FloatData m_linearBounce;
+ btVector3FloatData m_linearStopERP;
+ btVector3FloatData m_linearStopCFM;
+ btVector3FloatData m_linearMotorERP;
+ btVector3FloatData m_linearMotorCFM;
+ btVector3FloatData m_linearTargetVelocity;
+ btVector3FloatData m_linearMaxMotorForce;
+ btVector3FloatData m_linearServoTarget;
+ btVector3FloatData m_linearSpringStiffness;
+ btVector3FloatData m_linearSpringDamping;
+ btVector3FloatData m_linearEquilibriumPoint;
+ char m_linearEnableMotor[4];
+ char m_linearServoMotor[4];
+ char m_linearEnableSpring[4];
+ char m_linearSpringStiffnessLimited[4];
+ char m_linearSpringDampingLimited[4];
+ char m_padding1[4];
+
+ btVector3FloatData m_angularUpperLimit;
+ btVector3FloatData m_angularLowerLimit;
+ btVector3FloatData m_angularBounce;
+ btVector3FloatData m_angularStopERP;
+ btVector3FloatData m_angularStopCFM;
+ btVector3FloatData m_angularMotorERP;
+ btVector3FloatData m_angularMotorCFM;
+ btVector3FloatData m_angularTargetVelocity;
+ btVector3FloatData m_angularMaxMotorForce;
+ btVector3FloatData m_angularServoTarget;
+ btVector3FloatData m_angularSpringStiffness;
+ btVector3FloatData m_angularSpringDamping;
+ btVector3FloatData m_angularEquilibriumPoint;
+ char m_angularEnableMotor[4];
+ char m_angularServoMotor[4];
+ char m_angularEnableSpring[4];
+ char m_angularSpringStiffnessLimited[4];
+ char m_angularSpringDampingLimited[4];
+
+ int m_rotateOrder;
+};
+
+struct btGeneric6DofSpring2ConstraintDoubleData2
+{
+ btTypedConstraintDoubleData m_typeConstraintData;
+ btTransformDoubleData m_rbAFrame;
+ btTransformDoubleData m_rbBFrame;
+
+ btVector3DoubleData m_linearUpperLimit;
+ btVector3DoubleData m_linearLowerLimit;
+ btVector3DoubleData m_linearBounce;
+ btVector3DoubleData m_linearStopERP;
+ btVector3DoubleData m_linearStopCFM;
+ btVector3DoubleData m_linearMotorERP;
+ btVector3DoubleData m_linearMotorCFM;
+ btVector3DoubleData m_linearTargetVelocity;
+ btVector3DoubleData m_linearMaxMotorForce;
+ btVector3DoubleData m_linearServoTarget;
+ btVector3DoubleData m_linearSpringStiffness;
+ btVector3DoubleData m_linearSpringDamping;
+ btVector3DoubleData m_linearEquilibriumPoint;
+ char m_linearEnableMotor[4];
+ char m_linearServoMotor[4];
+ char m_linearEnableSpring[4];
+ char m_linearSpringStiffnessLimited[4];
+ char m_linearSpringDampingLimited[4];
+ char m_padding1[4];
+
+ btVector3DoubleData m_angularUpperLimit;
+ btVector3DoubleData m_angularLowerLimit;
+ btVector3DoubleData m_angularBounce;
+ btVector3DoubleData m_angularStopERP;
+ btVector3DoubleData m_angularStopCFM;
+ btVector3DoubleData m_angularMotorERP;
+ btVector3DoubleData m_angularMotorCFM;
+ btVector3DoubleData m_angularTargetVelocity;
+ btVector3DoubleData m_angularMaxMotorForce;
+ btVector3DoubleData m_angularServoTarget;
+ btVector3DoubleData m_angularSpringStiffness;
+ btVector3DoubleData m_angularSpringDamping;
+ btVector3DoubleData m_angularEquilibriumPoint;
+ char m_angularEnableMotor[4];
+ char m_angularServoMotor[4];
+ char m_angularEnableSpring[4];
+ char m_angularSpringStiffnessLimited[4];
+ char m_angularSpringDampingLimited[4];
+
+ int m_rotateOrder;
+};
+
+SIMD_FORCE_INLINE int btGeneric6DofSpring2Constraint::calculateSerializeBufferSize() const
+{
+ return sizeof(btGeneric6DofSpring2ConstraintData2);
+}
+
+SIMD_FORCE_INLINE const char* btGeneric6DofSpring2Constraint::serialize(void* dataBuffer, btSerializer* serializer) const
+{
+ btGeneric6DofSpring2ConstraintData2* dof = (btGeneric6DofSpring2ConstraintData2*)dataBuffer;
+ btTypedConstraint::serialize(&dof->m_typeConstraintData,serializer);
+
+ m_frameInA.serialize(dof->m_rbAFrame);
+ m_frameInB.serialize(dof->m_rbBFrame);
+
+ int i;
+ for (i=0;i<3;i++)
+ {
+ dof->m_angularLowerLimit.m_floats[i] = m_angularLimits[i].m_loLimit;
+ dof->m_angularUpperLimit.m_floats[i] = m_angularLimits[i].m_hiLimit;
+ dof->m_angularBounce.m_floats[i] = m_angularLimits[i].m_bounce;
+ dof->m_angularStopERP.m_floats[i] = m_angularLimits[i].m_stopERP;
+ dof->m_angularStopCFM.m_floats[i] = m_angularLimits[i].m_stopCFM;
+ dof->m_angularMotorERP.m_floats[i] = m_angularLimits[i].m_motorERP;
+ dof->m_angularMotorCFM.m_floats[i] = m_angularLimits[i].m_motorCFM;
+ dof->m_angularTargetVelocity.m_floats[i] = m_angularLimits[i].m_targetVelocity;
+ dof->m_angularMaxMotorForce.m_floats[i] = m_angularLimits[i].m_maxMotorForce;
+ dof->m_angularServoTarget.m_floats[i] = m_angularLimits[i].m_servoTarget;
+ dof->m_angularSpringStiffness.m_floats[i] = m_angularLimits[i].m_springStiffness;
+ dof->m_angularSpringDamping.m_floats[i] = m_angularLimits[i].m_springDamping;
+ dof->m_angularEquilibriumPoint.m_floats[i] = m_angularLimits[i].m_equilibriumPoint;
+ }
+ dof->m_angularLowerLimit.m_floats[3] = 0;
+ dof->m_angularUpperLimit.m_floats[3] = 0;
+ dof->m_angularBounce.m_floats[3] = 0;
+ dof->m_angularStopERP.m_floats[3] = 0;
+ dof->m_angularStopCFM.m_floats[3] = 0;
+ dof->m_angularMotorERP.m_floats[3] = 0;
+ dof->m_angularMotorCFM.m_floats[3] = 0;
+ dof->m_angularTargetVelocity.m_floats[3] = 0;
+ dof->m_angularMaxMotorForce.m_floats[3] = 0;
+ dof->m_angularServoTarget.m_floats[3] = 0;
+ dof->m_angularSpringStiffness.m_floats[3] = 0;
+ dof->m_angularSpringDamping.m_floats[3] = 0;
+ dof->m_angularEquilibriumPoint.m_floats[3] = 0;
+ for (i=0;i<4;i++)
+ {
+ dof->m_angularEnableMotor[i] = i < 3 ? ( m_angularLimits[i].m_enableMotor ? 1 : 0 ) : 0;
+ dof->m_angularServoMotor[i] = i < 3 ? ( m_angularLimits[i].m_servoMotor ? 1 : 0 ) : 0;
+ dof->m_angularEnableSpring[i] = i < 3 ? ( m_angularLimits[i].m_enableSpring ? 1 : 0 ) : 0;
+ dof->m_angularSpringStiffnessLimited[i] = i < 3 ? ( m_angularLimits[i].m_springStiffnessLimited ? 1 : 0 ) : 0;
+ dof->m_angularSpringDampingLimited[i] = i < 3 ? ( m_angularLimits[i].m_springDampingLimited ? 1 : 0 ) : 0;
+ }
+
+ m_linearLimits.m_lowerLimit.serialize( dof->m_linearLowerLimit );
+ m_linearLimits.m_upperLimit.serialize( dof->m_linearUpperLimit );
+ m_linearLimits.m_bounce.serialize( dof->m_linearBounce );
+ m_linearLimits.m_stopERP.serialize( dof->m_linearStopERP );
+ m_linearLimits.m_stopCFM.serialize( dof->m_linearStopCFM );
+ m_linearLimits.m_motorERP.serialize( dof->m_linearMotorERP );
+ m_linearLimits.m_motorCFM.serialize( dof->m_linearMotorCFM );
+ m_linearLimits.m_targetVelocity.serialize( dof->m_linearTargetVelocity );
+ m_linearLimits.m_maxMotorForce.serialize( dof->m_linearMaxMotorForce );
+ m_linearLimits.m_servoTarget.serialize( dof->m_linearServoTarget );
+ m_linearLimits.m_springStiffness.serialize( dof->m_linearSpringStiffness );
+ m_linearLimits.m_springDamping.serialize( dof->m_linearSpringDamping );
+ m_linearLimits.m_equilibriumPoint.serialize( dof->m_linearEquilibriumPoint );
+ for (i=0;i<4;i++)
+ {
+ dof->m_linearEnableMotor[i] = i < 3 ? ( m_linearLimits.m_enableMotor[i] ? 1 : 0 ) : 0;
+ dof->m_linearServoMotor[i] = i < 3 ? ( m_linearLimits.m_servoMotor[i] ? 1 : 0 ) : 0;
+ dof->m_linearEnableSpring[i] = i < 3 ? ( m_linearLimits.m_enableSpring[i] ? 1 : 0 ) : 0;
+ dof->m_linearSpringStiffnessLimited[i] = i < 3 ? ( m_linearLimits.m_springStiffnessLimited[i] ? 1 : 0 ) : 0;
+ dof->m_linearSpringDampingLimited[i] = i < 3 ? ( m_linearLimits.m_springDampingLimited[i] ? 1 : 0 ) : 0;
+ }
+
+ dof->m_rotateOrder = m_rotateOrder;
+
+ return btGeneric6DofSpring2ConstraintDataName;
+}
+
+
+
+
+
+#endif //BT_GENERIC_6DOF_CONSTRAINT_H
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h
index 1b2e0f62ca8..dac59c6889d 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h
@@ -63,6 +63,26 @@ public:
void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF
void setEquilibriumPoint(int index, btScalar val);
+ bool isSpringEnabled(int index) const
+ {
+ return m_springEnabled[index];
+ }
+
+ btScalar getStiffness(int index) const
+ {
+ return m_springStiffness[index];
+ }
+
+ btScalar getDamping(int index) const
+ {
+ return m_springDamping[index];
+ }
+
+ btScalar getEquilibriumPoint(int index) const
+ {
+ return m_equilibriumPoint[index];
+ }
+
virtual void setAxis( const btVector3& axis1, const btVector3& axis2);
virtual void getInfo2 (btConstraintInfo2* info);
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp
index 29123d526b4..4be2aabe4d3 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp
@@ -25,7 +25,7 @@ subject to the following restrictions:
// anchor, axis1 and axis2 are in world coordinate system
// axis1 must be orthogonal to axis2
btHinge2Constraint::btHinge2Constraint(btRigidBody& rbA, btRigidBody& rbB, btVector3& anchor, btVector3& axis1, btVector3& axis2)
-: btGeneric6DofSpringConstraint(rbA, rbB, btTransform::getIdentity(), btTransform::getIdentity(), true),
+: btGeneric6DofSpring2Constraint(rbA, rbB, btTransform::getIdentity(), btTransform::getIdentity(),RO_XYZ),
m_anchor(anchor),
m_axis1(axis1),
m_axis2(axis2)
@@ -59,7 +59,7 @@ btHinge2Constraint::btHinge2Constraint(btRigidBody& rbA, btRigidBody& rbB, btVec
setAngularUpperLimit(btVector3(-1.f, 0.f, SIMD_HALF_PI * 0.5f));
// enable suspension
enableSpring(2, true);
- setStiffness(2, SIMD_PI * SIMD_PI * 4.f); // period 1 sec for 1 kilogramm weel :-)
+ setStiffness(2, SIMD_PI * SIMD_PI * 4.f);
setDamping(2, 0.01f);
setEquilibriumPoint();
}
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h
index 9a004986911..06a8e3ecd14 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h
@@ -20,7 +20,7 @@ subject to the following restrictions:
#include "LinearMath/btVector3.h"
#include "btTypedConstraint.h"
-#include "btGeneric6DofSpringConstraint.h"
+#include "btGeneric6DofSpring2Constraint.h"
@@ -29,7 +29,7 @@ subject to the following restrictions:
// 2 rotational degrees of freedom, similar to Euler rotations around Z (axis 1) and X (axis 2)
// 1 translational (along axis Z) with suspension spring
-ATTRIBUTE_ALIGNED16(class) btHinge2Constraint : public btGeneric6DofSpringConstraint
+ATTRIBUTE_ALIGNED16(class) btHinge2Constraint : public btGeneric6DofSpring2Constraint
{
protected:
btVector3 m_anchor;
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp
index c1897413078..76a1509471e 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp
@@ -45,7 +45,11 @@ btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const bt
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
m_useReferenceFrameA(useReferenceFrameA),
- m_flags(0)
+ m_flags(0),
+ m_normalCFM(0),
+ m_normalERP(0),
+ m_stopCFM(0),
+ m_stopERP(0)
{
m_rbAFrame.getOrigin() = pivotInA;
@@ -101,7 +105,11 @@ m_angularOnly(false), m_enableAngularMotor(false),
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
m_useReferenceFrameA(useReferenceFrameA),
-m_flags(0)
+m_flags(0),
+m_normalCFM(0),
+m_normalERP(0),
+m_stopCFM(0),
+m_stopERP(0)
{
// since no frame is given, assume this to be zero angle and just pick rb transform axis
@@ -151,7 +159,11 @@ m_enableAngularMotor(false),
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
m_useReferenceFrameA(useReferenceFrameA),
-m_flags(0)
+m_flags(0),
+m_normalCFM(0),
+m_normalERP(0),
+m_stopCFM(0),
+m_stopERP(0)
{
#ifndef _BT_USE_CENTER_LIMIT_
//start with free
@@ -177,7 +189,11 @@ m_enableAngularMotor(false),
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
m_useReferenceFrameA(useReferenceFrameA),
-m_flags(0)
+m_flags(0),
+m_normalCFM(0),
+m_normalERP(0),
+m_stopCFM(0),
+m_stopERP(0)
{
///not providing rigidbody B means implicitly using worldspace for body B
@@ -285,8 +301,60 @@ void btHingeConstraint::buildJacobian()
#endif //__SPU__
+static inline btScalar btNormalizeAnglePositive(btScalar angle)
+{
+ return btFmod(btFmod(angle, btScalar(2.0*SIMD_PI)) + btScalar(2.0*SIMD_PI), btScalar(2.0*SIMD_PI));
+}
+
+
+
+static btScalar btShortestAngularDistance(btScalar accAngle, btScalar curAngle)
+{
+ btScalar result = btNormalizeAngle(btNormalizeAnglePositive(btNormalizeAnglePositive(curAngle) -
+ btNormalizeAnglePositive(accAngle)));
+ return result;
+}
+
+static btScalar btShortestAngleUpdate(btScalar accAngle, btScalar curAngle)
+{
+ btScalar tol(0.3);
+ btScalar result = btShortestAngularDistance(accAngle, curAngle);
+
+ if (btFabs(result) > tol)
+ return curAngle;
+ else
+ return accAngle + result;
+
+ return curAngle;
+}
+
+
+btScalar btHingeAccumulatedAngleConstraint::getAccumulatedHingeAngle()
+{
+ btScalar hingeAngle = getHingeAngle();
+ m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,hingeAngle);
+ return m_accumulatedAngle;
+}
+void btHingeAccumulatedAngleConstraint::setAccumulatedHingeAngle(btScalar accAngle)
+{
+ m_accumulatedAngle = accAngle;
+}
+
+void btHingeAccumulatedAngleConstraint::getInfo1(btConstraintInfo1* info)
+{
+ //update m_accumulatedAngle
+ btScalar curHingeAngle = getHingeAngle();
+ m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,curHingeAngle);
+
+ btHingeConstraint::getInfo1(info);
+
+}
+
+
void btHingeConstraint::getInfo1(btConstraintInfo1* info)
{
+
+
if (m_useSolveConstraintObsolete)
{
info->m_numConstraintRows = 0;
@@ -413,7 +481,9 @@ void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransf
a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
}
// linear RHS
- btScalar k = info->fps * info->erp;
+ btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM) ? m_normalERP : info->erp;
+
+ btScalar k = info->fps * normalErp;
if (!m_angularOnly)
{
for(i = 0; i < 3; i++)
@@ -510,7 +580,7 @@ void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransf
powered = 0;
}
info->m_constraintError[srow] = btScalar(0.0f);
- btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp;
+ btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp;
if(powered)
{
if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
@@ -606,6 +676,8 @@ void btHingeConstraint::updateRHS(btScalar timeStep)
}
+
+
btScalar btHingeConstraint::getHingeAngle()
{
return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
@@ -798,7 +870,8 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info
for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i];
for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i];
- btScalar k = info->fps * info->erp;
+ btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM)? m_normalERP : info->erp;
+ btScalar k = info->fps * normalErp;
if (!m_angularOnly)
{
@@ -856,7 +929,8 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info
// angular_velocity = (erp*fps) * (ax1 x ax2)
// ax1 x ax2 is in the plane space of ax1, so we project the angular
// velocity to p and q to find the right hand side.
- k = info->fps * info->erp;
+ k = info->fps * normalErp;//??
+
btVector3 u = ax1A.cross(ax1B);
info->m_constraintError[s3] = k * u.dot(p);
info->m_constraintError[s4] = k * u.dot(q);
@@ -901,7 +975,7 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info
powered = 0;
}
info->m_constraintError[srow] = btScalar(0.0f);
- btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp;
+ btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp;
if(powered)
{
if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
@@ -1002,6 +1076,10 @@ void btHingeConstraint::setParam(int num, btScalar value, int axis)
m_normalCFM = value;
m_flags |= BT_HINGE_FLAGS_CFM_NORM;
break;
+ case BT_CONSTRAINT_ERP:
+ m_normalERP = value;
+ m_flags |= BT_HINGE_FLAGS_ERP_NORM;
+ break;
default :
btAssertConstrParams(0);
}
@@ -1032,6 +1110,10 @@ btScalar btHingeConstraint::getParam(int num, int axis) const
btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_NORM);
retVal = m_normalCFM;
break;
+ case BT_CONSTRAINT_ERP:
+ btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_NORM);
+ retVal = m_normalERP;
+ break;
default :
btAssertConstrParams(0);
}
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h
index 7c33ac24e05..f26e72105ba 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h
@@ -41,7 +41,8 @@ enum btHingeFlags
{
BT_HINGE_FLAGS_CFM_STOP = 1,
BT_HINGE_FLAGS_ERP_STOP = 2,
- BT_HINGE_FLAGS_CFM_NORM = 4
+ BT_HINGE_FLAGS_CFM_NORM = 4,
+ BT_HINGE_FLAGS_ERP_NORM = 8
};
@@ -94,6 +95,7 @@ public:
int m_flags;
btScalar m_normalCFM;
+ btScalar m_normalERP;
btScalar m_stopCFM;
btScalar m_stopERP;
@@ -175,6 +177,7 @@ public:
// maintain a given angular target.
void enableMotor(bool enableMotor) { m_enableAngularMotor = enableMotor; }
void setMaxMotorImpulse(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; }
+ void setMotorTargetVelocity(btScalar motorTargetVelocity) { m_motorTargetVelocity = motorTargetVelocity; }
void setMotorTarget(const btQuaternion& qAinB, btScalar dt); // qAinB is rotation of body A wrt body B.
void setMotorTarget(btScalar targetAngle, btScalar dt);
@@ -191,6 +194,33 @@ public:
m_relaxationFactor = _relaxationFactor;
#endif
}
+
+ btScalar getLimitSoftness() const
+ {
+#ifdef _BT_USE_CENTER_LIMIT_
+ return m_limit.getSoftness();
+#else
+ return m_limitSoftness;
+#endif
+ }
+
+ btScalar getLimitBiasFactor() const
+ {
+#ifdef _BT_USE_CENTER_LIMIT_
+ return m_limit.getBiasFactor();
+#else
+ return m_biasFactor;
+#endif
+ }
+
+ btScalar getLimitRelaxationFactor() const
+ {
+#ifdef _BT_USE_CENTER_LIMIT_
+ return m_limit.getRelaxationFactor();
+#else
+ return m_relaxationFactor;
+#endif
+ }
void setAxis(btVector3& axisInA)
{
@@ -217,6 +247,14 @@ public:
}
+ bool hasLimit() const {
+#ifdef _BT_USE_CENTER_LIMIT_
+ return m_limit.getHalfRange() > 0;
+#else
+ return m_lowerLimit <= m_upperLimit;
+#endif
+ }
+
btScalar getLowerLimit() const
{
#ifdef _BT_USE_CENTER_LIMIT_
@@ -236,6 +274,7 @@ public:
}
+ ///The getHingeAngle gives the hinge angle in range [-PI,PI]
btScalar getHingeAngle();
btScalar getHingeAngle(const btTransform& transA,const btTransform& transB);
@@ -286,13 +325,20 @@ public:
// access for UseFrameOffset
bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; }
void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; }
-
+ // access for UseReferenceFrameA
+ bool getUseReferenceFrameA() const { return m_useReferenceFrameA; }
+ void setUseReferenceFrameA(bool useReferenceFrameA) { m_useReferenceFrameA = useReferenceFrameA; }
///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
///If no axis is provided, it uses the default axis for this constraint.
virtual void setParam(int num, btScalar value, int axis = -1);
///return the local value of parameter
virtual btScalar getParam(int num, int axis = -1) const;
+
+ virtual int getFlags() const
+ {
+ return m_flags;
+ }
virtual int calculateSerializeBufferSize() const;
@@ -326,6 +372,43 @@ struct btHingeConstraintDoubleData
};
#endif //BT_BACKWARDS_COMPATIBLE_SERIALIZATION
+///The getAccumulatedHingeAngle returns the accumulated hinge angle, taking rotation across the -PI/PI boundary into account
+ATTRIBUTE_ALIGNED16(class) btHingeAccumulatedAngleConstraint : public btHingeConstraint
+{
+protected:
+ btScalar m_accumulatedAngle;
+public:
+
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
+ btHingeAccumulatedAngleConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, const btVector3& axisInA,const btVector3& axisInB, bool useReferenceFrameA = false)
+ :btHingeConstraint(rbA,rbB,pivotInA,pivotInB, axisInA,axisInB, useReferenceFrameA )
+ {
+ m_accumulatedAngle=getHingeAngle();
+ }
+
+ btHingeAccumulatedAngleConstraint(btRigidBody& rbA,const btVector3& pivotInA,const btVector3& axisInA, bool useReferenceFrameA = false)
+ :btHingeConstraint(rbA,pivotInA,axisInA, useReferenceFrameA)
+ {
+ m_accumulatedAngle=getHingeAngle();
+ }
+
+ btHingeAccumulatedAngleConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA = false)
+ :btHingeConstraint(rbA,rbB, rbAFrame, rbBFrame, useReferenceFrameA )
+ {
+ m_accumulatedAngle=getHingeAngle();
+ }
+
+ btHingeAccumulatedAngleConstraint(btRigidBody& rbA,const btTransform& rbAFrame, bool useReferenceFrameA = false)
+ :btHingeConstraint(rbA,rbAFrame, useReferenceFrameA )
+ {
+ m_accumulatedAngle=getHingeAngle();
+ }
+ btScalar getAccumulatedHingeAngle();
+ void setAccumulatedHingeAngle(btScalar accAngle);
+ virtual void getInfo1 (btConstraintInfo1* info);
+
+};
struct btHingeConstraintFloatData
{
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp
new file mode 100644
index 00000000000..f110cd48081
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp
@@ -0,0 +1,463 @@
+/*
+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 "btNNCGConstraintSolver.h"
+
+
+
+
+
+
+btScalar btNNCGConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
+{
+ btScalar val = btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup( bodies,numBodies,manifoldPtr, numManifolds, constraints,numConstraints,infoGlobal,debugDrawer);
+
+ m_pNC.resizeNoInitialize(m_tmpSolverNonContactConstraintPool.size());
+ m_pC.resizeNoInitialize(m_tmpSolverContactConstraintPool.size());
+ m_pCF.resizeNoInitialize(m_tmpSolverContactFrictionConstraintPool.size());
+ m_pCRF.resizeNoInitialize(m_tmpSolverContactRollingFrictionConstraintPool.size());
+
+ m_deltafNC.resizeNoInitialize(m_tmpSolverNonContactConstraintPool.size());
+ m_deltafC.resizeNoInitialize(m_tmpSolverContactConstraintPool.size());
+ m_deltafCF.resizeNoInitialize(m_tmpSolverContactFrictionConstraintPool.size());
+ m_deltafCRF.resizeNoInitialize(m_tmpSolverContactRollingFrictionConstraintPool.size());
+
+ return val;
+}
+
+btScalar btNNCGConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** /*bodies */,int /*numBodies*/,btPersistentManifold** /*manifoldPtr*/, int /*numManifolds*/,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* /*debugDrawer*/)
+{
+
+ int numNonContactPool = m_tmpSolverNonContactConstraintPool.size();
+ int numConstraintPool = m_tmpSolverContactConstraintPool.size();
+ int numFrictionPool = m_tmpSolverContactFrictionConstraintPool.size();
+
+ if (infoGlobal.m_solverMode & SOLVER_RANDMIZE_ORDER)
+ {
+ if (1) // uncomment this for a bit less random ((iteration & 7) == 0)
+ {
+
+ for (int j=0; j<numNonContactPool; ++j) {
+ int tmp = m_orderNonContactConstraintPool[j];
+ int swapi = btRandInt2(j+1);
+ m_orderNonContactConstraintPool[j] = m_orderNonContactConstraintPool[swapi];
+ m_orderNonContactConstraintPool[swapi] = tmp;
+ }
+
+ //contact/friction constraints are not solved more than
+ if (iteration< infoGlobal.m_numIterations)
+ {
+ for (int j=0; j<numConstraintPool; ++j) {
+ int tmp = m_orderTmpConstraintPool[j];
+ int swapi = btRandInt2(j+1);
+ m_orderTmpConstraintPool[j] = m_orderTmpConstraintPool[swapi];
+ m_orderTmpConstraintPool[swapi] = tmp;
+ }
+
+ for (int j=0; j<numFrictionPool; ++j) {
+ int tmp = m_orderFrictionConstraintPool[j];
+ int swapi = btRandInt2(j+1);
+ m_orderFrictionConstraintPool[j] = m_orderFrictionConstraintPool[swapi];
+ m_orderFrictionConstraintPool[swapi] = tmp;
+ }
+ }
+ }
+ }
+
+
+ btScalar deltaflengthsqr = 0;
+
+ if (infoGlobal.m_solverMode & SOLVER_SIMD)
+ {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
+ if (iteration < constraint.m_overrideNumSolverIterations)
+ {
+ btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint);
+ m_deltafNC[j] = deltaf;
+ deltaflengthsqr += deltaf * deltaf;
+ }
+ }
+ } else
+ {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
+ if (iteration < constraint.m_overrideNumSolverIterations)
+ {
+ btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint);
+ m_deltafNC[j] = deltaf;
+ deltaflengthsqr += deltaf * deltaf;
+ }
+ }
+ }
+
+
+ if (m_onlyForNoneContact)
+ {
+ if (iteration==0)
+ {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = m_deltafNC[j];
+ } else {
+ // deltaflengthsqrprev can be 0 only if the solver solved the problem exactly in the previous iteration. In this case we should have quit, but mainly for debug reason with this 'hack' it is now allowed to continue the calculation
+ btScalar beta = m_deltafLengthSqrPrev>0 ? deltaflengthsqr / m_deltafLengthSqrPrev : 2;
+ if (beta>1)
+ {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = 0;
+ } else
+ {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
+ if (iteration < constraint.m_overrideNumSolverIterations)
+ {
+ btScalar additionaldeltaimpulse = beta * m_pNC[j];
+ constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
+ m_pNC[j] = beta * m_pNC[j] + m_deltafNC[j];
+ btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
+ btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
+ const btSolverConstraint& c = constraint;
+ body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
+ body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
+ }
+ }
+ }
+ }
+ m_deltafLengthSqrPrev = deltaflengthsqr;
+ }
+
+
+
+ if (infoGlobal.m_solverMode & SOLVER_SIMD)
+ {
+
+ if (iteration< infoGlobal.m_numIterations)
+ {
+ 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);
+ }
+ }
+
+ ///solve all contact constraints using SIMD, if available
+ if (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS)
+ {
+ int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
+ int multiplier = (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)? 2 : 1;
+
+ for (int c=0;c<numPoolConstraints;c++)
+ {
+ btScalar totalImpulse =0;
+
+ {
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[c]];
+ btScalar deltaf = resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafC[c] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ totalImpulse = solveManifold.m_appliedImpulse;
+ }
+ bool applyFriction = true;
+ if (applyFriction)
+ {
+ {
+
+ btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[c*multiplier]];
+
+ if (totalImpulse>btScalar(0))
+ {
+ solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
+ solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
+ btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafCF[c*multiplier] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ } else {
+ m_deltafCF[c*multiplier] = 0;
+ }
+ }
+
+ if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)
+ {
+
+ btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[c*multiplier+1]];
+
+ if (totalImpulse>btScalar(0))
+ {
+ solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
+ solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
+ btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafCF[c*multiplier+1] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ } else {
+ m_deltafCF[c*multiplier+1] = 0;
+ }
+ }
+ }
+ }
+
+ }
+ else//SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS
+ {
+ //solve the friction constraints after all contact constraints, don't interleave them
+ int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
+ int j;
+
+ for (j=0;j<numPoolConstraints;j++)
+ {
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
+ //resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ btScalar deltaf = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafC[j] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ }
+
+
+
+ ///solve all friction constraints, using SIMD, if available
+
+ int numFrictionPoolConstraints = m_tmpSolverContactFrictionConstraintPool.size();
+ for (j=0;j<numFrictionPoolConstraints;j++)
+ {
+ btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[j]];
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse;
+
+ if (totalImpulse>btScalar(0))
+ {
+ solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
+ solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
+
+ //resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafCF[j] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ } else {
+ m_deltafCF[j] = 0;
+ }
+ }
+
+
+ int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size();
+ for (j=0;j<numRollingFrictionPoolConstraints;j++)
+ {
+
+ btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[j];
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[rollingFrictionConstraint.m_frictionIndex].m_appliedImpulse;
+ if (totalImpulse>btScalar(0))
+ {
+ btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
+ if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction)
+ rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
+
+ rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
+ rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
+
+ btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint);
+ m_deltafCRF[j] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ } else {
+ m_deltafCRF[j] = 0;
+ }
+ }
+
+
+ }
+ }
+
+
+
+ } else
+ {
+
+ if (iteration< infoGlobal.m_numIterations)
+ {
+ 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);
+ }
+ }
+ ///solve all contact constraints
+ int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
+ for (int j=0;j<numPoolConstraints;j++)
+ {
+ const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
+ btScalar deltaf = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafC[j] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ }
+ ///solve all friction constraints
+ int numFrictionPoolConstraints = m_tmpSolverContactFrictionConstraintPool.size();
+ for (int j=0;j<numFrictionPoolConstraints;j++)
+ {
+ btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[j]];
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse;
+
+ if (totalImpulse>btScalar(0))
+ {
+ solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
+ solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
+
+ btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
+ m_deltafCF[j] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ } else {
+ m_deltafCF[j] = 0;
+ }
+ }
+
+ int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size();
+ for (int j=0;j<numRollingFrictionPoolConstraints;j++)
+ {
+ btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[j];
+ btScalar totalImpulse = m_tmpSolverContactConstraintPool[rollingFrictionConstraint.m_frictionIndex].m_appliedImpulse;
+ if (totalImpulse>btScalar(0))
+ {
+ btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
+ if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction)
+ rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
+
+ rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
+ rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
+
+ btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint);
+ m_deltafCRF[j] = deltaf;
+ deltaflengthsqr += deltaf*deltaf;
+ } else {
+ m_deltafCRF[j] = 0;
+ }
+ }
+ }
+ }
+
+
+
+
+ if (!m_onlyForNoneContact)
+ {
+ if (iteration==0)
+ {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = m_deltafNC[j];
+ for (int j=0;j<m_tmpSolverContactConstraintPool.size();j++) m_pC[j] = m_deltafC[j];
+ for (int j=0;j<m_tmpSolverContactFrictionConstraintPool.size();j++) m_pCF[j] = m_deltafCF[j];
+ if ( (infoGlobal.m_solverMode & SOLVER_SIMD) ==0 || (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) == 0 )
+ {
+ for (int j=0;j<m_tmpSolverContactRollingFrictionConstraintPool.size();j++) m_pCRF[j] = m_deltafCRF[j];
+ }
+ } else
+ {
+ // deltaflengthsqrprev can be 0 only if the solver solved the problem exactly in the previous iteration. In this case we should have quit, but mainly for debug reason with this 'hack' it is now allowed to continue the calculation
+ btScalar beta = m_deltafLengthSqrPrev>0 ? deltaflengthsqr / m_deltafLengthSqrPrev : 2;
+ if (beta>1) {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = 0;
+ for (int j=0;j<m_tmpSolverContactConstraintPool.size();j++) m_pC[j] = 0;
+ for (int j=0;j<m_tmpSolverContactFrictionConstraintPool.size();j++) m_pCF[j] = 0;
+ if ( (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) == 0 ) {
+ for (int j=0;j<m_tmpSolverContactRollingFrictionConstraintPool.size();j++) m_pCRF[j] = 0;
+ }
+ } else {
+ for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
+ if (iteration < constraint.m_overrideNumSolverIterations) {
+ btScalar additionaldeltaimpulse = beta * m_pNC[j];
+ constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
+ m_pNC[j] = beta * m_pNC[j] + m_deltafNC[j];
+ btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
+ btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
+ const btSolverConstraint& c = constraint;
+ body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
+ body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
+ }
+ }
+ for (int j=0;j<m_tmpSolverContactConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
+ if (iteration< infoGlobal.m_numIterations) {
+ btScalar additionaldeltaimpulse = beta * m_pC[j];
+ constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
+ m_pC[j] = beta * m_pC[j] + m_deltafC[j];
+ btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
+ btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
+ const btSolverConstraint& c = constraint;
+ body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
+ body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
+ }
+ }
+ for (int j=0;j<m_tmpSolverContactFrictionConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[j]];
+ if (iteration< infoGlobal.m_numIterations) {
+ btScalar additionaldeltaimpulse = beta * m_pCF[j];
+ constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
+ m_pCF[j] = beta * m_pCF[j] + m_deltafCF[j];
+ btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
+ btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
+ const btSolverConstraint& c = constraint;
+ body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
+ body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
+ }
+ }
+ if ( (infoGlobal.m_solverMode & SOLVER_SIMD) ==0 || (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) == 0 ) {
+ for (int j=0;j<m_tmpSolverContactRollingFrictionConstraintPool.size();j++)
+ {
+ btSolverConstraint& constraint = m_tmpSolverContactRollingFrictionConstraintPool[j];
+ if (iteration< infoGlobal.m_numIterations) {
+ btScalar additionaldeltaimpulse = beta * m_pCRF[j];
+ constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
+ m_pCRF[j] = beta * m_pCRF[j] + m_deltafCRF[j];
+ btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
+ btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
+ const btSolverConstraint& c = constraint;
+ body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
+ body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
+ }
+ }
+ }
+ }
+ }
+ m_deltafLengthSqrPrev = deltaflengthsqr;
+ }
+
+ return deltaflengthsqr;
+}
+
+btScalar btNNCGConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal)
+{
+ m_pNC.resizeNoInitialize(0);
+ m_pC.resizeNoInitialize(0);
+ m_pCF.resizeNoInitialize(0);
+ m_pCRF.resizeNoInitialize(0);
+
+ m_deltafNC.resizeNoInitialize(0);
+ m_deltafC.resizeNoInitialize(0);
+ m_deltafCF.resizeNoInitialize(0);
+ m_deltafCRF.resizeNoInitialize(0);
+
+ return btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(bodies, numBodies, infoGlobal);
+}
+
+
+
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h
new file mode 100644
index 00000000000..a300929cd5c
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h
@@ -0,0 +1,64 @@
+/*
+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_NNCG_CONSTRAINT_SOLVER_H
+#define BT_NNCG_CONSTRAINT_SOLVER_H
+
+#include "btSequentialImpulseConstraintSolver.h"
+
+ATTRIBUTE_ALIGNED16(class) btNNCGConstraintSolver : public btSequentialImpulseConstraintSolver
+{
+protected:
+
+ btScalar m_deltafLengthSqrPrev;
+
+ btAlignedObjectArray<btScalar> m_pNC; // p for None Contact constraints
+ btAlignedObjectArray<btScalar> m_pC; // p for Contact constraints
+ btAlignedObjectArray<btScalar> m_pCF; // p for ContactFriction constraints
+ btAlignedObjectArray<btScalar> m_pCRF; // p for ContactRollingFriction constraints
+
+ //These are recalculated in every iterations. We just keep these to prevent reallocation in each iteration.
+ btAlignedObjectArray<btScalar> m_deltafNC; // deltaf for NoneContact constraints
+ btAlignedObjectArray<btScalar> m_deltafC; // deltaf for Contact constraints
+ btAlignedObjectArray<btScalar> m_deltafCF; // deltaf for ContactFriction constraints
+ btAlignedObjectArray<btScalar> m_deltafCRF; // deltaf for ContactRollingFriction constraints
+
+
+protected:
+
+ 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);
+
+ virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
+
+public:
+
+ BT_DECLARE_ALIGNED_ALLOCATOR();
+
+ btNNCGConstraintSolver() : btSequentialImpulseConstraintSolver(), m_onlyForNoneContact(false) {}
+
+ virtual btConstraintSolverType getSolverType() const
+ {
+ return BT_NNCG_SOLVER;
+ }
+
+ bool m_onlyForNoneContact;
+};
+
+
+
+
+#endif //BT_NNCG_CONSTRAINT_SOLVER_H
+
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h
index 91218949498..8fa03d719d7 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h
@@ -116,6 +116,11 @@ public:
virtual void setParam(int num, btScalar value, int axis = -1);
///return the local value of parameter
virtual btScalar getParam(int num, int axis = -1) const;
+
+ virtual int getFlags() const
+ {
+ return m_flags;
+ }
virtual int calculateSerializeBufferSize() const;
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
index f855581c712..8da572bf7d8 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
@@ -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.
@@ -22,6 +22,8 @@ subject to the following restrictions:
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
#include "LinearMath/btIDebugDraw.h"
+#include "LinearMath/btCpuFeatureUtility.h"
+
//#include "btJacobianEntry.h"
#include "LinearMath/btMinMax.h"
#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
@@ -37,121 +39,253 @@ int gNumSplitImpulseRecoveries = 0;
#include "BulletDynamics/Dynamics/btRigidBody.h"
-btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver()
-:m_btSeed2(0)
+
+///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)
{
+ 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 delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn;
+ deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
+ deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv;
+
+ const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
+ if (sum < c.m_lowerLimit)
+ {
+ deltaImpulse = c.m_lowerLimit - c.m_appliedImpulse;
+ c.m_appliedImpulse = c.m_lowerLimit;
+ }
+ else if (sum > c.m_upperLimit)
+ {
+ deltaImpulse = c.m_upperLimit - c.m_appliedImpulse;
+ c.m_appliedImpulse = c.m_upperLimit;
+ }
+ else
+ {
+ 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);
+
+ return deltaImpulse;
}
-btSequentialImpulseConstraintSolver::~btSequentialImpulseConstraintSolver()
+
+static btSimdScalar gResolveSingleConstraintRowLowerLimit_scalar_reference(btSolverBody& body1, btSolverBody& body2, 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());
+
+ deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
+ deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv;
+ const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
+ if (sum < c.m_lowerLimit)
+ {
+ deltaImpulse = c.m_lowerLimit - c.m_appliedImpulse;
+ c.m_appliedImpulse = c.m_lowerLimit;
+ }
+ else
+ {
+ 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);
+
+ return deltaImpulse;
}
+
+
#ifdef USE_SIMD
#include <emmintrin.h>
+
+
#define btVecSplat(x, e) _mm_shuffle_ps(x, x, _MM_SHUFFLE(e,e,e,e))
static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 )
{
__m128 result = _mm_mul_ps( vec0, vec1);
return _mm_add_ps( btVecSplat( result, 0 ), _mm_add_ps( btVecSplat( result, 1 ), btVecSplat( result, 2 ) ) );
}
-#endif//USE_SIMD
+
+#if defined (BT_ALLOW_SSE4)
+#include <intrin.h>
+
+#define USE_FMA 1
+#define USE_FMA3_INSTEAD_FMA4 1
+#define USE_SSE4_DOT 1
+
+#define SSE4_DP(a, b) _mm_dp_ps(a, b, 0x7f)
+#define SSE4_DP_FP(a, b) _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7f))
+
+#if USE_SSE4_DOT
+#define DOT_PRODUCT(a, b) SSE4_DP(a, b)
+#else
+#define DOT_PRODUCT(a, b) btSimdDot3(a, b)
+#endif
+
+#if USE_FMA
+#if USE_FMA3_INSTEAD_FMA4
+// a*b + c
+#define FMADD(a, b, c) _mm_fmadd_ps(a, b, c)
+// -(a*b) + c
+#define FMNADD(a, b, c) _mm_fnmadd_ps(a, b, c)
+#else // USE_FMA3
+// a*b + c
+#define FMADD(a, b, c) _mm_macc_ps(a, b, c)
+// -(a*b) + c
+#define FMNADD(a, b, c) _mm_nmacc_ps(a, b, c)
+#endif
+#else // USE_FMA
+// c + a*b
+#define FMADD(a, b, c) _mm_add_ps(c, _mm_mul_ps(a, b))
+// c - a*b
+#define FMNADD(a, b, c) _mm_sub_ps(c, _mm_mul_ps(a, b))
+#endif
+#endif
// Project Gauss Seidel or the equivalent Sequential Impulse
-btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+static btSimdScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c)
{
-#ifdef USE_SIMD
__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));
- 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);
- btSimdScalar resultLowerLess,resultUpperLess;
- resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1);
- resultUpperLess = _mm_cmplt_ps(sum,upperLimit1);
- __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 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);
+ 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));
+ 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);
+ btSimdScalar resultLowerLess, resultUpperLess;
+ resultLowerLess = _mm_cmplt_ps(sum, lowerLimit1);
+ resultUpperLess = _mm_cmplt_ps(sum, upperLimit1);
+ __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 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 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));
+ 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;
+}
+
+// Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3
+static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, 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));
+ deltaImpulse = FMNADD(deltaVel1Dotn, tmp, deltaImpulse);
+ deltaImpulse = FMNADD(deltaVel2Dotn, tmp, deltaImpulse);
+ tmp = _mm_add_ps(c.m_appliedImpulse, deltaImpulse); // sum
+ const __m128 maskLower = _mm_cmpgt_ps(tmp, lowerLimit);
+ 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;
#else
- return resolveSingleConstraintRowGeneric(body1,body2,c);
+ return gResolveSingleConstraintRowGeneric_sse2(body1,body2,c);
#endif
}
-// Project Gauss Seidel or the equivalent Sequential Impulse
-btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGeneric(btSolverBody& body1,btSolverBody& body2,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 delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn;
- deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
- deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv;
- const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
- if (sum < c.m_lowerLimit)
- {
- deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse;
- c.m_appliedImpulse = c.m_lowerLimit;
- }
- else if (sum > c.m_upperLimit)
- {
- deltaImpulse = c.m_upperLimit-c.m_appliedImpulse;
- c.m_appliedImpulse = c.m_upperLimit;
- }
- else
- {
- c.m_appliedImpulse = sum;
- }
+static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& body1, btSolverBody& body2, 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));
+ 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);
+ btSimdScalar resultLowerLess, resultUpperLess;
+ resultLowerLess = _mm_cmplt_ps(sum, lowerLimit1);
+ resultUpperLess = _mm_cmplt_ps(sum, upperLimit1);
+ __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 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;
+}
- body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
- body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
+// Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3
+static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, 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));
+ 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;
+#else
+ return gResolveSingleConstraintRowLowerLimit_sse2(body1,body2,c);
+#endif //BT_ALLOW_SSE4
+}
+
+
+#endif //USE_SIMD
+
+
+
+btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+{
+#ifdef USE_SIMD
+ return m_resolveSingleConstraintRowGeneric(body1, body2, c);
+#else
+ return resolveSingleConstraintRowGeneric(body1,body2,c);
+#endif
+}
+
+// Project Gauss Seidel or the equivalent Sequential Impulse
+btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGeneric(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
+{
+ return gResolveSingleConstraintRowGeneric_scalar_reference(body1, body2, c);
}
btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c)
{
#ifdef USE_SIMD
- __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));
- 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);
- btSimdScalar resultLowerLess,resultUpperLess;
- resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1);
- resultUpperLess = _mm_cmplt_ps(sum,upperLimit1);
- __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 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;
+ return m_resolveSingleConstraintRowLowerLimit(body1, body2, c);
#else
return resolveSingleConstraintRowLowerLimit(body1,body2,c);
#endif
@@ -160,26 +294,7 @@ btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowe
btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimit(btSolverBody& body1,btSolverBody& body2,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());
-
- deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv;
- deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv;
- const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
- if (sum < c.m_lowerLimit)
- {
- deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse;
- c.m_appliedImpulse = c.m_lowerLimit;
- }
- else
- {
- 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);
-
- return deltaImpulse;
+ return gResolveSingleConstraintRowLowerLimit_scalar_reference(body1,body2,c);
}
@@ -248,6 +363,63 @@ void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFri
}
+ btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver()
+ : m_resolveSingleConstraintRowGeneric(gResolveSingleConstraintRowGeneric_scalar_reference),
+ m_resolveSingleConstraintRowLowerLimit(gResolveSingleConstraintRowLowerLimit_scalar_reference),
+ m_btSeed2(0)
+ {
+
+#ifdef USE_SIMD
+ m_resolveSingleConstraintRowGeneric = gResolveSingleConstraintRowGeneric_sse2;
+ m_resolveSingleConstraintRowLowerLimit=gResolveSingleConstraintRowLowerLimit_sse2;
+#endif //USE_SIMD
+
+#ifdef BT_ALLOW_SSE4
+ int cpuFeatures = btCpuFeatureUtility::getCpuFeatures();
+ if ((cpuFeatures & btCpuFeatureUtility::CPU_FEATURE_FMA3) && (cpuFeatures & btCpuFeatureUtility::CPU_FEATURE_SSE4_1))
+ {
+ m_resolveSingleConstraintRowGeneric = gResolveSingleConstraintRowGeneric_sse4_1_fma3;
+ m_resolveSingleConstraintRowLowerLimit = gResolveSingleConstraintRowLowerLimit_sse4_1_fma3;
+ }
+#endif//BT_ALLOW_SSE4
+
+ }
+
+ btSequentialImpulseConstraintSolver::~btSequentialImpulseConstraintSolver()
+ {
+ }
+
+ btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getScalarConstraintRowSolverGeneric()
+ {
+ return gResolveSingleConstraintRowGeneric_scalar_reference;
+ }
+
+ btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getScalarConstraintRowSolverLowerLimit()
+ {
+ return gResolveSingleConstraintRowLowerLimit_scalar_reference;
+ }
+
+
+#ifdef USE_SIMD
+ btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE2ConstraintRowSolverGeneric()
+ {
+ return gResolveSingleConstraintRowGeneric_sse2;
+ }
+ btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE2ConstraintRowSolverLowerLimit()
+ {
+ return gResolveSingleConstraintRowLowerLimit_sse2;
+ }
+#ifdef BT_ALLOW_SSE4
+ btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverGeneric()
+ {
+ return gResolveSingleConstraintRowGeneric_sse4_1_fma3;
+ }
+ btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverLowerLimit()
+ {
+ return gResolveSingleConstraintRowLowerLimit_sse4_1_fma3;
+ }
+#endif //BT_ALLOW_SSE4
+#endif //USE_SIMD
unsigned long btSequentialImpulseConstraintSolver::btRand2()
{
@@ -308,7 +480,7 @@ void btSequentialImpulseConstraintSolver::initSolverBody(btSolverBody* solverBod
solverBody->m_angularVelocity = rb->getAngularVelocity();
solverBody->m_externalForceImpulse = rb->getTotalForce()*rb->getInvMass()*timeStep;
solverBody->m_externalTorqueImpulse = rb->getTotalTorque()*rb->getInvInertiaTensorWorld()*timeStep ;
-
+
} else
{
solverBody->m_worldTransform.setIdentity();
@@ -340,7 +512,7 @@ btScalar btSequentialImpulseConstraintSolver::restitutionCurve(btScalar rel_vel,
void btSequentialImpulseConstraintSolver::applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection, int frictionMode)
{
-
+
if (colObj && colObj->hasAnisotropicFriction(frictionMode))
{
@@ -361,7 +533,7 @@ void btSequentialImpulseConstraintSolver::applyAnisotropicFriction(btCollisionOb
void btSequentialImpulseConstraintSolver::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, btScalar desiredVelocity, btScalar cfmSlip)
{
-
+
btSolverBody& solverBodyA = m_tmpSolverBodyPool[solverBodyIdA];
btSolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB];
@@ -422,26 +594,26 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr
}
{
-
+
btScalar rel_vel;
- btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0))
+ 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))
+ 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));
rel_vel = vel1Dotn+vel2Dotn;
// btScalar positionalError = 0.f;
- btSimdScalar velocityError = desiredVelocity - rel_vel;
- btSimdScalar velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv);
+ btScalar velocityError = desiredVelocity - rel_vel;
+ btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv;
solverConstraint.m_rhs = velocityImpulse;
solverConstraint.m_rhsPenetration = 0.f;
solverConstraint.m_cfm = cfmSlip;
solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
solverConstraint.m_upperLimit = solverConstraint.m_friction;
-
+
}
}
@@ -449,7 +621,7 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addFrictionConstraint(c
{
btSolverConstraint& solverConstraint = m_tmpSolverContactFrictionConstraintPool.expandNonInitializing();
solverConstraint.m_frictionIndex = frictionIndex;
- setupFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2,
+ setupFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2,
colObj0, colObj1, relaxation, desiredVelocity, cfmSlip);
return solverConstraint;
}
@@ -457,7 +629,7 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addFrictionConstraint(c
void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis1,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,
btScalar desiredVelocity, btScalar cfmSlip)
{
@@ -503,12 +675,12 @@ void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint( btSolv
}
{
-
+
btScalar rel_vel;
- btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0))
+ 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))
+ 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));
rel_vel = vel1Dotn+vel2Dotn;
@@ -521,7 +693,7 @@ void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint( btSolv
solverConstraint.m_cfm = cfmSlip;
solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
solverConstraint.m_upperLimit = solverConstraint.m_friction;
-
+
}
}
@@ -536,7 +708,7 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addRollingFrictionConst
{
btSolverConstraint& solverConstraint = m_tmpSolverContactRollingFrictionConstraintPool.expandNonInitializing();
solverConstraint.m_frictionIndex = frictionIndex;
- setupRollingFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2,
+ setupRollingFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2,
colObj0, colObj1, relaxation, desiredVelocity, cfmSlip);
return solverConstraint;
}
@@ -564,7 +736,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
body.setCompanionId(solverBodyIdA);
} else
{
-
+
if (m_fixedBodyId<0)
{
m_fixedBodyId = m_tmpSolverBodyPool.size();
@@ -582,15 +754,15 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject&
#include <stdio.h>
-void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstraint& solverConstraint,
+void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstraint& solverConstraint,
int solverBodyIdA, int solverBodyIdB,
btManifoldPoint& cp, const btContactSolverInfo& infoGlobal,
btScalar& relaxation,
const btVector3& rel_pos1, const btVector3& rel_pos2)
{
-
- const btVector3& pos1 = cp.getPositionWorldOnA();
- const btVector3& pos2 = cp.getPositionWorldOnB();
+
+ // const btVector3& pos1 = cp.getPositionWorldOnA();
+ // const btVector3& pos2 = cp.getPositionWorldOnB();
btSolverBody* bodyA = &m_tmpSolverBodyPool[solverBodyIdA];
btSolverBody* bodyB = &m_tmpSolverBodyPool[solverBodyIdB];
@@ -598,23 +770,23 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra
btRigidBody* rb0 = bodyA->m_originalBody;
btRigidBody* rb1 = bodyB->m_originalBody;
-// btVector3 rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin();
+// btVector3 rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin();
// btVector3 rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin();
- //rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin();
+ //rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin();
//rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin();
relaxation = 1.f;
btVector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB);
solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0);
- btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB);
+ btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB);
solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0);
{
#ifdef COMPUTE_IMPULSE_DENOM
btScalar denom0 = rb0->computeImpulseDenominator(pos1,cp.m_normalWorldOnB);
btScalar denom1 = rb1->computeImpulseDenominator(pos2,cp.m_normalWorldOnB);
-#else
+#else
btVector3 vec;
btScalar denom0 = 0.f;
btScalar denom1 = 0.f;
@@ -628,7 +800,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra
vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2);
denom1 = rb1->getInvMass() + cp.m_normalWorldOnB.dot(vec);
}
-#endif //COMPUTE_IMPULSE_DENOM
+#endif //COMPUTE_IMPULSE_DENOM
btScalar denom = relaxation/(denom0+denom1);
solverConstraint.m_jacDiagABInv = denom;
@@ -666,11 +838,11 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra
btVector3 vel = vel1 - vel2;
btScalar rel_vel = cp.m_normalWorldOnB.dot(vel);
-
+
solverConstraint.m_friction = cp.m_combinedFriction;
-
+
restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution);
if (restitution <= btScalar(0.))
{
@@ -700,17 +872,17 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra
btVector3 externalTorqueImpulseA = bodyA->m_originalBody ? bodyA->m_externalTorqueImpulse: btVector3(0,0,0);
btVector3 externalForceImpulseB = bodyB->m_originalBody ? bodyB->m_externalForceImpulse: btVector3(0,0,0);
btVector3 externalTorqueImpulseB = bodyB->m_originalBody ?bodyB->m_externalTorqueImpulse : btVector3(0,0,0);
-
- btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(bodyA->m_linearVelocity+externalForceImpulseA)
+
+ btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(bodyA->m_linearVelocity+externalForceImpulseA)
+ solverConstraint.m_relpos1CrossNormal.dot(bodyA->m_angularVelocity+externalTorqueImpulseA);
- btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(bodyB->m_linearVelocity+externalForceImpulseB)
+ btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(bodyB->m_linearVelocity+externalForceImpulseB)
+ solverConstraint.m_relpos2CrossNormal.dot(bodyB->m_angularVelocity+externalTorqueImpulseB);
btScalar rel_vel = vel1Dotn+vel2Dotn;
btScalar positionalError = 0.f;
btScalar velocityError = restitution - rel_vel;// * damping;
-
+
btScalar erp = infoGlobal.m_erp2;
if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
@@ -755,7 +927,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra
-void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse( btSolverConstraint& solverConstraint,
+void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse( btSolverConstraint& solverConstraint,
int solverBodyIdA, int solverBodyIdB,
btManifoldPoint& cp, const btContactSolverInfo& infoGlobal)
{
@@ -834,7 +1006,7 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
btVector3 rel_pos1;
btVector3 rel_pos2;
btScalar relaxation;
-
+
int frictionIndex = m_tmpSolverContactConstraintPool.size();
btSolverConstraint& solverConstraint = m_tmpSolverContactConstraintPool.expandNonInitializing();
@@ -848,7 +1020,7 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
const btVector3& pos1 = cp.getPositionWorldOnA();
const btVector3& pos2 = cp.getPositionWorldOnB();
- rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin();
+ rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin();
rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin();
btVector3 vel1;// = rb0 ? rb0->getVelocityInLocalPoint(rel_pos1) : btVector3(0,0,0);
@@ -856,13 +1028,13 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
solverBodyA->getVelocityInLocalPointNoDelta(rel_pos1,vel1);
solverBodyB->getVelocityInLocalPointNoDelta(rel_pos2,vel2 );
-
+
btVector3 vel = vel1 - vel2;
btScalar rel_vel = cp.m_normalWorldOnB.dot(vel);
setupContactConstraint(solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal, relaxation, rel_pos1, rel_pos2);
-
+
// const btVector3& pos1 = cp.getPositionWorldOnA();
// const btVector3& pos2 = cp.getPositionWorldOnB();
@@ -903,21 +1075,21 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
if (axis1.length()>0.001)
addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
-
+
}
}
///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
+ ///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,
+ ///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
@@ -973,9 +1145,9 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
}
setFrictionConstraintImpulse( solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal);
-
-
+
+
}
}
@@ -1015,7 +1187,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
bool found=false;
for (int b=0;b<numBodies;b++)
{
-
+
if (&constraint->getRigidBodyA()==bodies[b])
{
found = true;
@@ -1047,7 +1219,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
bool found=false;
for (int b=0;b<numBodies;b++)
{
-
+
if (manifoldPtr[i]->getBody0()==bodies[b])
{
found = true;
@@ -1071,8 +1243,8 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
}
}
#endif //BT_ADDITIONAL_DEBUG
-
-
+
+
for (int i = 0; i < numBodies; i++)
{
bodies[i]->setCompanionId(-1);
@@ -1087,6 +1259,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
//convert all bodies
+
for (int i=0;i<numBodies;i++)
{
int bodyId = getOrInitSolverBody(*bodies[i],infoGlobal.m_timeStep);
@@ -1096,14 +1269,27 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
{
btSolverBody& solverBody = m_tmpSolverBodyPool[bodyId];
btVector3 gyroForce (0,0,0);
- if (body->getFlags()&BT_ENABLE_GYROPSCOPIC_FORCE)
+ if (body->getFlags()&BT_ENABLE_GYROSCOPIC_FORCE_EXPLICIT)
{
- gyroForce = body->computeGyroscopicForce(infoGlobal.m_maxGyroscopicForce);
+ 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;
@@ -1123,7 +1309,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
int totalNumRows = 0;
int i;
-
+
m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints);
//calculate the total number of contraint rows
for (i=0;i<numConstraints;i++)
@@ -1153,14 +1339,14 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
}
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);
@@ -1268,7 +1454,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
}
-
+
{
btScalar rel_vel;
btVector3 externalForceImpulseA = bodyAPtr->m_originalBody ? bodyAPtr->m_externalForceImpulse : btVector3(0,0,0);
@@ -1276,11 +1462,11 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
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)
+
+ 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)
+
+ btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(rbB.getLinearVelocity()+externalForceImpulseB)
+ solverConstraint.m_relpos2CrossNormal.dot(rbB.getAngularVelocity()+externalTorqueImpulseB);
rel_vel = vel1Dotn+vel2Dotn;
@@ -1346,7 +1532,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
int numNonContactPool = m_tmpSolverNonContactConstraintPool.size();
int numConstraintPool = m_tmpSolverContactConstraintPool.size();
int numFrictionPool = m_tmpSolverContactFrictionConstraintPool.size();
-
+
if (infoGlobal.m_solverMode & SOLVER_RANDMIZE_ORDER)
{
if (1) // uncomment this for a bit less random ((iteration & 7) == 0)
@@ -1359,7 +1545,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
m_orderNonContactConstraintPool[swapi] = tmp;
}
- //contact/friction constraints are not solved more than
+ //contact/friction constraints are not solved more than
if (iteration< infoGlobal.m_numIterations)
{
for (int j=0; j<numConstraintPool; ++j) {
@@ -1438,7 +1624,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
{
btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[c*multiplier+1]];
-
+
if (totalImpulse>btScalar(0))
{
solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
@@ -1463,8 +1649,8 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
}
-
-
+
+
///solve all friction constraints, using SIMD, if available
@@ -1483,7 +1669,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
}
}
-
+
int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size();
for (j=0;j<numRollingFrictionPoolConstraints;j++)
{
@@ -1502,9 +1688,9 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration
resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint);
}
}
-
- }
+
+ }
}
} else
{
@@ -1628,10 +1814,10 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations(
for ( int iteration = 0 ; iteration< maxIterations ; iteration++)
//for ( int iteration = maxIterations-1 ; iteration >= 0;iteration--)
- {
+ {
solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer);
}
-
+
}
return 0.f;
}
@@ -1673,7 +1859,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo
fb->m_appliedForceBodyB += solverConstr.m_contactNormal2*solverConstr.m_appliedImpulse*constr->getRigidBodyB().getLinearFactor()/infoGlobal.m_timeStep;
fb->m_appliedTorqueBodyA += solverConstr.m_relpos1CrossNormal* constr->getRigidBodyA().getAngularFactor()*solverConstr.m_appliedImpulse/infoGlobal.m_timeStep;
fb->m_appliedTorqueBodyB += solverConstr.m_relpos2CrossNormal* constr->getRigidBodyB().getAngularFactor()*solverConstr.m_appliedImpulse/infoGlobal.m_timeStep; /*RGM ???? */
-
+
}
constr->internalSetAppliedImpulse(solverConstr.m_appliedImpulse);
@@ -1694,7 +1880,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo
m_tmpSolverBodyPool[i].writebackVelocityAndTransform(infoGlobal.m_timeStep, infoGlobal.m_splitImpulseTurnErp);
else
m_tmpSolverBodyPool[i].writebackVelocity();
-
+
m_tmpSolverBodyPool[i].m_originalBody->setLinearVelocity(
m_tmpSolverBodyPool[i].m_linearVelocity+
m_tmpSolverBodyPool[i].m_externalForceImpulse);
@@ -1727,13 +1913,13 @@ btScalar btSequentialImpulseConstraintSolver::solveGroup(btCollisionObject** bod
BT_PROFILE("solveGroup");
//you need to provide at least some bodies
-
+
solveGroupCacheFriendlySetup( bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer);
solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer);
solveGroupCacheFriendlyFinish(bodies, numBodies, infoGlobal);
-
+
return 0.f;
}
@@ -1741,5 +1927,3 @@ void btSequentialImpulseConstraintSolver::reset()
{
m_btSeed2 = 0;
}
-
-
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
index 47dbbe3393d..a6029180983 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h
@@ -27,6 +27,8 @@ class btCollisionObject;
#include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h"
#include "BulletDynamics/ConstraintSolver/btConstraintSolver.h"
+typedef btSimdScalar(*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
{
@@ -43,6 +45,10 @@ protected:
btAlignedObjectArray<btTypedConstraint::btConstraintInfo1> m_tmpConstraintSizesPool;
int m_maxOverrideNumSolverIterations;
int m_fixedBodyId;
+
+ btSingleConstraintRowSolver m_resolveSingleConstraintRowGeneric;
+ btSingleConstraintRowSolver m_resolveSingleConstraintRowLowerLimit;
+
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,
@@ -112,9 +118,7 @@ public:
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();
@@ -136,6 +140,33 @@ public:
{
return BT_SEQUENTIAL_IMPULSE_SOLVER;
}
+
+ btSingleConstraintRowSolver getActiveConstraintRowSolverGeneric()
+ {
+ return m_resolveSingleConstraintRowGeneric;
+ }
+ void setConstraintRowSolverGeneric(btSingleConstraintRowSolver rowSolver)
+ {
+ m_resolveSingleConstraintRowGeneric = rowSolver;
+ }
+ btSingleConstraintRowSolver getActiveConstraintRowSolverLowerLimit()
+ {
+ return m_resolveSingleConstraintRowLowerLimit;
+ }
+ void setConstraintRowSolverLowerLimit(btSingleConstraintRowSolver rowSolver)
+ {
+ m_resolveSingleConstraintRowLowerLimit = rowSolver;
+ }
+
+ ///Various implementations of solving a single constraint row using a generic equality constraint, using scalar reference, SSE2 or SSE4
+ btSingleConstraintRowSolver getScalarConstraintRowSolverGeneric();
+ btSingleConstraintRowSolver getSSE2ConstraintRowSolverGeneric();
+ btSingleConstraintRowSolver getSSE4_1ConstraintRowSolverGeneric();
+
+ ///Various implementations of solving a single constraint row using an inequality (lower limit) constraint, using scalar reference, SSE2 or SSE4
+ btSingleConstraintRowSolver getScalarConstraintRowSolverLowerLimit();
+ btSingleConstraintRowSolver getSSE2ConstraintRowSolverLowerLimit();
+ btSingleConstraintRowSolver getSSE4_1ConstraintRowSolverLowerLimit();
};
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
index aff9f27f594..f8f81bfe6fa 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp
@@ -539,8 +539,8 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra
btScalar tag_vel = getTargetLinMotorVelocity();
btScalar mot_fact = getMotorFactor(m_linPos, m_lowerLinLimit, m_upperLinLimit, tag_vel, info->fps * currERP);
info->m_constraintError[srow] -= signFact * mot_fact * getTargetLinMotorVelocity();
- info->m_lowerLimit[srow] += -getMaxLinMotorForce() * info->fps;
- info->m_upperLimit[srow] += getMaxLinMotorForce() * info->fps;
+ info->m_lowerLimit[srow] += -getMaxLinMotorForce() / info->fps;
+ info->m_upperLimit[srow] += getMaxLinMotorForce() / info->fps;
}
if(limit)
{
@@ -641,8 +641,8 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra
}
btScalar mot_fact = getMotorFactor(m_angPos, m_lowerAngLimit, m_upperAngLimit, getTargetAngMotorVelocity(), info->fps * currERP);
info->m_constraintError[srow] = mot_fact * getTargetAngMotorVelocity();
- info->m_lowerLimit[srow] = -getMaxAngMotorForce() * info->fps;
- info->m_upperLimit[srow] = getMaxAngMotorForce() * info->fps;
+ info->m_lowerLimit[srow] = -getMaxAngMotorForce() / info->fps;
+ info->m_upperLimit[srow] = getMaxAngMotorForce() / info->fps;
}
if(limit)
{
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h
index 57ebb47d8e7..628ada4cfb1 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h
@@ -280,6 +280,11 @@ public:
virtual void setParam(int num, btScalar value, int axis = -1);
///return the local value of parameter
virtual btScalar getParam(int num, int axis = -1) const;
+
+ virtual int getFlags() const
+ {
+ return m_flags;
+ }
virtual int calculateSerializeBufferSize() const;
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp
index 27fdd9d3df8..736a64a1c94 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp
@@ -24,7 +24,7 @@ subject to the following restrictions:
btTypedConstraint::btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA)
:btTypedObject(type),
m_userConstraintType(-1),
-m_userConstraintId(-1),
+m_userConstraintPtr((void*)-1),
m_breakingImpulseThreshold(SIMD_INFINITY),
m_isEnabled(true),
m_needsFeedback(false),
@@ -41,7 +41,7 @@ m_jointFeedback(0)
btTypedConstraint::btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA,btRigidBody& rbB)
:btTypedObject(type),
m_userConstraintType(-1),
-m_userConstraintId(-1),
+m_userConstraintPtr((void*)-1),
m_breakingImpulseThreshold(SIMD_INFINITY),
m_isEnabled(true),
m_needsFeedback(false),
diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h
index b58f984d0fb..b55db0c1bfb 100644
--- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h
@@ -44,6 +44,7 @@ enum btTypedConstraintType
D6_SPRING_CONSTRAINT_TYPE,
GEAR_CONSTRAINT_TYPE,
FIXED_CONSTRAINT_TYPE,
+ D6_SPRING_2_CONSTRAINT_TYPE,
MAX_CONSTRAINT_TYPE
};
@@ -65,6 +66,7 @@ enum btConstraintParams
ATTRIBUTE_ALIGNED16(struct) btJointFeedback
{
+ BT_DECLARE_ALIGNED_ALLOCATOR();
btVector3 m_appliedForceBodyA;
btVector3 m_appliedTorqueBodyA;
btVector3 m_appliedForceBodyB;
diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
index fb8a4068e23..361a054ec69 100644
--- a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
+++ b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp
@@ -4,8 +4,8 @@ Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -34,6 +34,7 @@ subject to the following restrictions:
#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h"
#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h"
#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h"
+#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h"
#include "BulletDynamics/ConstraintSolver/btContactConstraint.h"
@@ -58,7 +59,7 @@ int firstHit=startHit;
SIMD_FORCE_INLINE int btGetConstraintIslandId(const btTypedConstraint* lhs)
{
int islandId;
-
+
const btCollisionObject& rcolObj0 = lhs->getRigidBodyA();
const btCollisionObject& rcolObj1 = lhs->getRigidBodyB();
islandId= rcolObj0.getIslandTag()>=0?rcolObj0.getIslandTag():rcolObj1.getIslandTag();
@@ -88,7 +89,7 @@ struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCal
int m_numConstraints;
btIDebugDraw* m_debugDrawer;
btDispatcher* m_dispatcher;
-
+
btAlignedObjectArray<btCollisionObject*> m_bodies;
btAlignedObjectArray<btPersistentManifold*> m_manifolds;
btAlignedObjectArray<btTypedConstraint*> m_constraints;
@@ -127,7 +128,7 @@ struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCal
m_constraints.resize (0);
}
-
+
virtual void processIsland(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifolds,int numManifolds, int islandId)
{
if (islandId<0)
@@ -140,7 +141,7 @@ struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCal
btTypedConstraint** startConstraint = 0;
int numCurConstraints = 0;
int i;
-
+
//find the first constraint for this island
for (i=0;i<m_numConstraints;i++)
{
@@ -164,7 +165,7 @@ struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCal
m_solver->solveGroup( bodies,numBodies,manifolds, numManifolds,startConstraint,numCurConstraints,*m_solverInfo,m_debugDrawer,m_dispatcher);
} else
{
-
+
for (i=0;i<numBodies;i++)
m_bodies.push_back(bodies[i]);
for (i=0;i<numManifolds;i++)
@@ -187,7 +188,7 @@ struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCal
btCollisionObject** bodies = m_bodies.size()? &m_bodies[0]:0;
btPersistentManifold** manifold = m_manifolds.size()?&m_manifolds[0]:0;
btTypedConstraint** constraints = m_constraints.size()?&m_constraints[0]:0;
-
+
m_solver->solveGroup( bodies,m_bodies.size(),manifold, m_manifolds.size(),constraints, m_constraints.size() ,*m_solverInfo,m_debugDrawer,m_dispatcher);
m_bodies.resize(0);
m_manifolds.resize(0);
@@ -206,10 +207,10 @@ m_solverIslandCallback ( NULL ),
m_constraintSolver(constraintSolver),
m_gravity(0,-10,0),
m_localTime(0),
+m_fixedTimeStep(0),
m_synchronizeAllMotionStates(false),
m_applySpeculativeContactRestitution(false),
m_profileTimings(0),
-m_fixedTimeStep(0),
m_latencyMotionStateInterpolation(true)
{
@@ -317,6 +318,9 @@ void btDiscreteDynamicsWorld::debugDrawWorld()
}
}
}
+ if (getDebugDrawer())
+ getDebugDrawer()->flushLines();
+
}
void btDiscreteDynamicsWorld::clearForces()
@@ -329,7 +333,7 @@ void btDiscreteDynamicsWorld::clearForces()
//it might break backward compatibility (people applying forces on sleeping objects get never cleared and accumulate on wake-up
body->clearForces();
}
-}
+}
///apply gravity, call this once per timestep
void btDiscreteDynamicsWorld::applyGravity()
@@ -445,7 +449,7 @@ int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps,
applyGravity();
-
+
for (int i=0;i<clampedSimulationSteps;i++)
{
@@ -463,18 +467,18 @@ int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps,
#ifndef BT_NO_PROFILE
CProfileManager::Increment_Frame_Counter();
#endif //BT_NO_PROFILE
-
+
return numSimulationSubSteps;
}
void btDiscreteDynamicsWorld::internalSingleStepSimulation(btScalar timeStep)
{
-
+
BT_PROFILE("internalSingleStepSimulation");
if(0 != m_internalPreTickCallback) {
(*m_internalPreTickCallback)(this, timeStep);
- }
+ }
///apply gravity, predict motion
predictUnconstraintMotion(timeStep);
@@ -487,20 +491,20 @@ void btDiscreteDynamicsWorld::internalSingleStepSimulation(btScalar timeStep)
createPredictiveContacts(timeStep);
-
+
///perform collision detection
performDiscreteCollisionDetection();
calculateSimulationIslands();
-
+
getSolverInfo().m_timeStep = timeStep;
-
+
///solve contact and other joint constraints
solveConstraints(getSolverInfo());
-
+
///CallbackTriggers();
///integrate transforms
@@ -509,12 +513,12 @@ void btDiscreteDynamicsWorld::internalSingleStepSimulation(btScalar timeStep)
///update vehicle simulation
updateActions(timeStep);
-
+
updateActivationState( timeStep );
if(0 != m_internalTickCallback) {
(*m_internalTickCallback)(this, timeStep);
- }
+ }
}
void btDiscreteDynamicsWorld::setGravity(const btVector3& gravity)
@@ -606,14 +610,14 @@ void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body, short group, short
void btDiscreteDynamicsWorld::updateActions(btScalar timeStep)
{
BT_PROFILE("updateActions");
-
+
for ( int i=0;i<m_actions.size();i++)
{
m_actions[i]->updateAction( this, timeStep);
}
}
-
-
+
+
void btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep)
{
BT_PROFILE("updateActivationState");
@@ -634,7 +638,7 @@ void btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep)
{
if (body->getActivationState() == ACTIVE_TAG)
body->setActivationState( WANTS_DEACTIVATION );
- if (body->getActivationState() == ISLAND_SLEEPING)
+ if (body->getActivationState() == ISLAND_SLEEPING)
{
body->setAngularVelocity(btVector3(0,0,0));
body->setLinearVelocity(btVector3(0,0,0));
@@ -653,6 +657,9 @@ void btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep)
void btDiscreteDynamicsWorld::addConstraint(btTypedConstraint* constraint,bool disableCollisionsBetweenLinkedBodies)
{
m_constraints.push_back(constraint);
+ //Make sure the two bodies of a type constraint are different (possibly add this to the btTypedConstraint constructor?)
+ btAssert(&constraint->getRigidBodyA()!=&constraint->getRigidBodyB());
+
if (disableCollisionsBetweenLinkedBodies)
{
constraint->getRigidBodyA().addConstraintRef(constraint);
@@ -704,25 +711,25 @@ void btDiscreteDynamicsWorld::removeCharacter(btActionInterface* character)
void btDiscreteDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
{
BT_PROFILE("solveConstraints");
-
+
m_sortedConstraints.resize( m_constraints.size());
- int i;
+ int i;
for (i=0;i<getNumConstraints();i++)
{
m_sortedConstraints[i] = m_constraints[i];
}
// btAssert(0);
-
-
+
+
m_sortedConstraints.quickSort(btSortConstraintOnIslandPredicate());
-
+
btTypedConstraint** constraintsPtr = getNumConstraints() ? &m_sortedConstraints[0] : 0;
-
+
m_solverIslandCallback->setup(&solverInfo,constraintsPtr,m_sortedConstraints.size(),getDebugDrawer());
m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds());
-
+
/// solve all the constraints for this island
m_islandManager->buildAndProcessIslands(getCollisionWorld()->getDispatcher(),getCollisionWorld(),m_solverIslandCallback);
@@ -743,10 +750,10 @@ void btDiscreteDynamicsWorld::calculateSimulationIslands()
for (int i=0;i<this->m_predictiveManifolds.size();i++)
{
btPersistentManifold* manifold = m_predictiveManifolds[i];
-
+
const btCollisionObject* colObj0 = manifold->getBody0();
const btCollisionObject* colObj1 = manifold->getBody1();
-
+
if (((colObj0) && (!(colObj0)->isStaticOrKinematicObject())) &&
((colObj1) && (!(colObj1)->isStaticOrKinematicObject())))
{
@@ -754,7 +761,7 @@ void btDiscreteDynamicsWorld::calculateSimulationIslands()
}
}
}
-
+
{
int i;
int numConstraints = int(m_constraints.size());
@@ -778,7 +785,7 @@ void btDiscreteDynamicsWorld::calculateSimulationIslands()
//Store the island id in each body
getSimulationIslandManager()->storeIslandActivationState(getCollisionWorld());
-
+
}
@@ -794,7 +801,7 @@ public:
btDispatcher* m_dispatcher;
public:
- btClosestNotMeConvexResultCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :
+ btClosestNotMeConvexResultCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :
btCollisionWorld::ClosestConvexResultCallback(fromA,toA),
m_me(me),
m_allowedPenetration(0.0f),
@@ -874,7 +881,7 @@ int gNumClampedCcdMotions=0;
void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
{
BT_PROFILE("createPredictiveContacts");
-
+
{
BT_PROFILE("release predictive contact manifolds");
@@ -896,7 +903,7 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
{
body->predictIntegratedTransform(timeStep, predictedTrans);
-
+
btScalar squareMotion = (predictedTrans.getOrigin()-body->getWorldTransform().getOrigin()).length2();
if (getDispatchInfo().m_useContinuous && body->getCcdSquareMotionThreshold() && body->getCcdSquareMotionThreshold() < squareMotion)
@@ -910,7 +917,7 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
{
public:
- StaticOnlyCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :
+ StaticOnlyCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :
btClosestNotMeConvexResultCallback(me,fromA,toA,pairCache,dispatcher)
{
}
@@ -940,14 +947,14 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep)
convexSweepTest(&tmpSphere,body->getWorldTransform(),modifiedPredictedTrans,sweepResults);
if (sweepResults.hasHit() && (sweepResults.m_closestHitFraction < 1.f))
{
-
+
btVector3 distVec = (predictedTrans.getOrigin()-body->getWorldTransform().getOrigin())*sweepResults.m_closestHitFraction;
btScalar distance = distVec.dot(-sweepResults.m_hitNormalWorld);
-
+
btPersistentManifold* manifold = m_dispatcher1->getNewManifold(body,sweepResults.m_hitCollisionObject);
m_predictiveManifolds.push_back(manifold);
-
+
btVector3 worldPointB = body->getWorldTransform().getOrigin()+distVec;
btVector3 localPointB = sweepResults.m_hitCollisionObject->getWorldTransform().inverse()*worldPointB;
@@ -980,10 +987,10 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
{
body->predictIntegratedTransform(timeStep, predictedTrans);
-
+
btScalar squareMotion = (predictedTrans.getOrigin()-body->getWorldTransform().getOrigin()).length2();
-
+
if (getDispatchInfo().m_useContinuous && body->getCcdSquareMotionThreshold() && body->getCcdSquareMotionThreshold() < squareMotion)
{
@@ -996,7 +1003,7 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
{
public:
- StaticOnlyCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :
+ StaticOnlyCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :
btClosestNotMeConvexResultCallback(me,fromA,toA,pairCache,dispatcher)
{
}
@@ -1026,7 +1033,7 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
convexSweepTest(&tmpSphere,body->getWorldTransform(),modifiedPredictedTrans,sweepResults);
if (sweepResults.hasHit() && (sweepResults.m_closestHitFraction < 1.f))
{
-
+
//printf("clamped integration to hit fraction = %f\n",fraction);
body->setHitFraction(sweepResults.m_closestHitFraction);
body->predictIntegratedTransform(timeStep*body->getHitFraction(), predictedTrans);
@@ -1051,13 +1058,13 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
printf("sm2=%f\n",sm2);
}
#else
-
+
//don't apply the collision response right now, it will happen next frame
//if you really need to, you can uncomment next 3 lines. Note that is uses zero restitution.
//btScalar appliedImpulse = 0.f;
//btScalar depth = 0.f;
//appliedImpulse = resolveSingleCollision(body,(btCollisionObject*)sweepResults.m_hitCollisionObject,sweepResults.m_hitPointWorld,sweepResults.m_hitNormalWorld,getSolverInfo(), depth);
-
+
#endif
@@ -1065,10 +1072,10 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
}
}
}
-
+
body->proceedToTransform( predictedTrans);
-
+
}
}
@@ -1082,7 +1089,7 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
btPersistentManifold* manifold = m_predictiveManifolds[i];
btRigidBody* body0 = btRigidBody::upcast((btCollisionObject*)manifold->getBody0());
btRigidBody* body1 = btRigidBody::upcast((btCollisionObject*)manifold->getBody1());
-
+
for (int p=0;p<manifold->getNumContacts();p++)
{
const btManifoldPoint& pt = manifold->getContactPoint(p);
@@ -1092,11 +1099,11 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
//if (pt.getDistance()>0 && combinedRestitution>0 && pt.m_appliedImpulse != 0.f)
{
btVector3 imp = -pt.m_normalWorldOnB * pt.m_appliedImpulse* combinedRestitution;
-
+
const btVector3& pos1 = pt.getPositionWorldOnA();
const btVector3& pos2 = pt.getPositionWorldOnB();
- btVector3 rel_pos0 = pos1 - body0->getWorldTransform().getOrigin();
+ btVector3 rel_pos0 = pos1 - body0->getWorldTransform().getOrigin();
btVector3 rel_pos1 = pos2 - body1->getWorldTransform().getOrigin();
if (body0)
@@ -1107,7 +1114,7 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep)
}
}
}
-
+
}
@@ -1146,7 +1153,7 @@ void btDiscreteDynamicsWorld::startProfiling(btScalar timeStep)
-
+
void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
{
@@ -1166,12 +1173,12 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
btTransform tr;
tr.setIdentity();
btVector3 pivot = p2pC->getPivotInA();
- pivot = p2pC->getRigidBodyA().getCenterOfMassTransform() * pivot;
+ pivot = p2pC->getRigidBodyA().getCenterOfMassTransform() * pivot;
tr.setOrigin(pivot);
getDebugDrawer()->drawTransform(tr, dbgDrawSize);
- // that ideally should draw the same frame
+ // that ideally should draw the same frame
pivot = p2pC->getPivotInB();
- pivot = p2pC->getRigidBodyB().getCenterOfMassTransform() * pivot;
+ pivot = p2pC->getRigidBodyB().getCenterOfMassTransform() * pivot;
tr.setOrigin(pivot);
if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
}
@@ -1190,13 +1197,13 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
break;
}
bool drawSect = true;
- if(minAng > maxAng)
+ if(!pHinge->hasLimit())
{
minAng = btScalar(0.f);
maxAng = SIMD_2_PI;
drawSect = false;
}
- if(drawLimits)
+ if(drawLimits)
{
btVector3& center = tr.getOrigin();
btVector3 normal = tr.getBasis().getColumn(2);
@@ -1231,7 +1238,7 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
getDebugDrawer()->drawLine(tr.getOrigin(), pCur, btVector3(0,0,0));
pPrev = pCur;
- }
+ }
btScalar tws = pCT->getTwistSpan();
btScalar twa = pCT->getTwistAngle();
bool useFrameB = (pCT->getRigidBodyB().getInvMass() > btScalar(0.f));
@@ -1259,7 +1266,7 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
tr = p6DOF->getCalculatedTransformB();
if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
- if(drawLimits)
+ if(drawLimits)
{
tr = p6DOF->getCalculatedTransformA();
const btVector3& center = p6DOF->getCalculatedTransformB().getOrigin();
@@ -1300,6 +1307,57 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
}
}
break;
+ ///note: the code for D6_SPRING_2_CONSTRAINT_TYPE is identical to D6_CONSTRAINT_TYPE, the D6_CONSTRAINT_TYPE+D6_SPRING_CONSTRAINT_TYPE will likely become obsolete/deprecated at some stage
+ case D6_SPRING_2_CONSTRAINT_TYPE:
+ {
+ {
+ btGeneric6DofSpring2Constraint* p6DOF = (btGeneric6DofSpring2Constraint*)constraint;
+ btTransform tr = p6DOF->getCalculatedTransformA();
+ if (drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
+ tr = p6DOF->getCalculatedTransformB();
+ if (drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize);
+ if (drawLimits)
+ {
+ tr = p6DOF->getCalculatedTransformA();
+ const btVector3& center = p6DOF->getCalculatedTransformB().getOrigin();
+ btVector3 up = tr.getBasis().getColumn(2);
+ 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));
+ axis = tr.getBasis().getColumn(1);
+ btScalar ay = p6DOF->getAngle(1);
+ btScalar az = p6DOF->getAngle(2);
+ btScalar cy = btCos(ay);
+ btScalar sy = btSin(ay);
+ btScalar cz = btCos(az);
+ btScalar sz = btSin(az);
+ btVector3 ref;
+ ref[0] = cy*cz*axis[0] + cy*sz*axis[1] - sy*axis[2];
+ ref[1] = -sz*axis[0] + cz*axis[1];
+ ref[2] = cz*sy*axis[0] + sz*sy*axis[1] + cy*axis[2];
+ tr = p6DOF->getCalculatedTransformB();
+ btVector3 normal = -tr.getBasis().getColumn(0);
+ btScalar minFi = p6DOF->getRotationalLimitMotor(0)->m_loLimit;
+ btScalar maxFi = p6DOF->getRotationalLimitMotor(0)->m_hiLimit;
+ if (minFi > maxFi)
+ {
+ getDebugDrawer()->drawArc(center, normal, ref, dbgDrawSize, dbgDrawSize, -SIMD_PI, SIMD_PI, btVector3(0, 0, 0), false);
+ }
+ else if (minFi < maxFi)
+ {
+ getDebugDrawer()->drawArc(center, normal, ref, dbgDrawSize, dbgDrawSize, minFi, maxFi, btVector3(0, 0, 0), true);
+ }
+ tr = p6DOF->getCalculatedTransformA();
+ btVector3 bbMin = p6DOF->getTranslationalLimitMotor()->m_lowerLimit;
+ btVector3 bbMax = p6DOF->getTranslationalLimitMotor()->m_upperLimit;
+ getDebugDrawer()->drawBox(bbMin, bbMax, tr, btVector3(0, 0, 0));
+ }
+ }
+ break;
+ }
case SLIDER_CONSTRAINT_TYPE:
{
btSliderConstraint* pSlider = (btSliderConstraint*)constraint;
@@ -1322,7 +1380,7 @@ void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint)
}
}
break;
- default :
+ default :
break;
}
return;
@@ -1422,19 +1480,19 @@ void btDiscreteDynamicsWorld::serializeDynamicsWorldInfo(btSerializer* serialize
worldInfo->m_solverInfo.m_globalCfm = getSolverInfo().m_globalCfm;
worldInfo->m_solverInfo.m_splitImpulsePenetrationThreshold = getSolverInfo().m_splitImpulsePenetrationThreshold;
worldInfo->m_solverInfo.m_splitImpulseTurnErp = getSolverInfo().m_splitImpulseTurnErp;
-
+
worldInfo->m_solverInfo.m_linearSlop = getSolverInfo().m_linearSlop;
worldInfo->m_solverInfo.m_warmstartingFactor = getSolverInfo().m_warmstartingFactor;
worldInfo->m_solverInfo.m_maxGyroscopicForce = getSolverInfo().m_maxGyroscopicForce;
worldInfo->m_solverInfo.m_singleAxisRollingFrictionThreshold = getSolverInfo().m_singleAxisRollingFrictionThreshold;
-
+
worldInfo->m_solverInfo.m_numIterations = getSolverInfo().m_numIterations;
worldInfo->m_solverInfo.m_solverMode = getSolverInfo().m_solverMode;
worldInfo->m_solverInfo.m_restingContactRestitutionThreshold = getSolverInfo().m_restingContactRestitutionThreshold;
worldInfo->m_solverInfo.m_minimumSolverBatchSize = getSolverInfo().m_minimumSolverBatchSize;
-
+
worldInfo->m_solverInfo.m_splitImpulse = getSolverInfo().m_splitImpulse;
-
+
#ifdef BT_USE_DOUBLE_PRECISION
const char* structType = "btDynamicsWorldDoubleData";
#else//BT_USE_DOUBLE_PRECISION
@@ -1450,10 +1508,10 @@ void btDiscreteDynamicsWorld::serialize(btSerializer* serializer)
serializeDynamicsWorldInfo(serializer);
- serializeRigidBodies(serializer);
-
serializeCollisionObjects(serializer);
+ serializeRigidBodies(serializer);
+
serializer->finishSerialization();
}
diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h
index d8a34b7da3d..dd3d1c3660c 100644
--- a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h
+++ b/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h
@@ -151,7 +151,7 @@ public:
virtual void removeCollisionObject(btCollisionObject* collisionObject);
- void debugDrawConstraint(btTypedConstraint* constraint);
+ virtual void debugDrawConstraint(btTypedConstraint* constraint);
virtual void debugDrawWorld();
diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
index 222f9006687..a7882684bf1 100644
--- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
+++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
@@ -87,7 +87,7 @@ void btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo&
setMassProps(constructionInfo.m_mass, constructionInfo.m_localInertia);
updateInertiaTensor();
- m_rigidbodyFlags = 0;
+ m_rigidbodyFlags = BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY;
m_deltaLinearVelocity.setZero();
@@ -257,12 +257,41 @@ void btRigidBody::updateInertiaTensor()
}
-btVector3 btRigidBody::computeGyroscopicForce(btScalar maxGyroscopicForce) const
+
+btVector3 btRigidBody::getLocalInertia() const
{
+
btVector3 inertiaLocal;
- inertiaLocal[0] = 1.f/getInvInertiaDiagLocal()[0];
- inertiaLocal[1] = 1.f/getInvInertiaDiagLocal()[1];
- inertiaLocal[2] = 1.f/getInvInertiaDiagLocal()[2];
+ const btVector3 inertia = m_invInertiaLocal;
+ inertiaLocal.setValue(inertia.x() != btScalar(0.0) ? btScalar(1.0) / inertia.x() : btScalar(0.0),
+ inertia.y() != btScalar(0.0) ? btScalar(1.0) / inertia.y() : btScalar(0.0),
+ inertia.z() != btScalar(0.0) ? btScalar(1.0) / inertia.z() : btScalar(0.0));
+ return inertiaLocal;
+}
+
+inline btVector3 evalEulerEqn(const btVector3& w1, const btVector3& w0, const btVector3& T, const btScalar dt,
+ const btMatrix3x3 &I)
+{
+ const btVector3 w2 = I*w1 + w1.cross(I*w1)*dt - (T*dt + I*w0);
+ return w2;
+}
+
+inline btMatrix3x3 evalEulerEqnDeriv(const btVector3& w1, const btVector3& w0, const btScalar dt,
+ const btMatrix3x3 &I)
+{
+
+ btMatrix3x3 w1x, Iw1x;
+ const btVector3 Iwi = (I*w1);
+ w1.getSkewSymmetricMatrix(&w1x[0], &w1x[1], &w1x[2]);
+ Iwi.getSkewSymmetricMatrix(&Iw1x[0], &Iw1x[1], &Iw1x[2]);
+
+ const btMatrix3x3 dfw1 = I + (w1x*I - Iw1x)*dt;
+ return dfw1;
+}
+
+btVector3 btRigidBody::computeGyroscopicForceExplicit(btScalar maxGyroscopicForce) const
+{
+ btVector3 inertiaLocal = getLocalInertia();
btMatrix3x3 inertiaTensorWorld = getWorldTransform().getBasis().scaled(inertiaLocal) * getWorldTransform().getBasis().transpose();
btVector3 tmp = inertiaTensorWorld*getAngularVelocity();
btVector3 gf = getAngularVelocity().cross(tmp);
@@ -274,6 +303,85 @@ btVector3 btRigidBody::computeGyroscopicForce(btScalar maxGyroscopicForce) const
return gf;
}
+
+btVector3 btRigidBody::computeGyroscopicImpulseImplicit_Body(btScalar step) const
+{
+ btVector3 idl = getLocalInertia();
+ btVector3 omega1 = getAngularVelocity();
+ btQuaternion q = getWorldTransform().getRotation();
+
+ // Convert to body coordinates
+ btVector3 omegab = quatRotate(q.inverse(), omega1);
+ btMatrix3x3 Ib;
+ Ib.setValue(idl.x(),0,0,
+ 0,idl.y(),0,
+ 0,0,idl.z());
+
+ btVector3 ibo = Ib*omegab;
+
+ // Residual vector
+ btVector3 f = step * omegab.cross(ibo);
+
+ btMatrix3x3 skew0;
+ omegab.getSkewSymmetricMatrix(&skew0[0], &skew0[1], &skew0[2]);
+ btVector3 om = Ib*omegab;
+ btMatrix3x3 skew1;
+ om.getSkewSymmetricMatrix(&skew1[0],&skew1[1],&skew1[2]);
+
+ // Jacobian
+ btMatrix3x3 J = Ib + (skew0*Ib - skew1)*step;
+
+// btMatrix3x3 Jinv = J.inverse();
+// btVector3 omega_div = Jinv*f;
+ btVector3 omega_div = J.solve33(f);
+
+ // Single Newton-Raphson update
+ omegab = omegab - omega_div;//Solve33(J, f);
+ // Back to world coordinates
+ btVector3 omega2 = quatRotate(q,omegab);
+ btVector3 gf = omega2-omega1;
+ return gf;
+}
+
+
+
+btVector3 btRigidBody::computeGyroscopicImpulseImplicit_World(btScalar step) const
+{
+ // use full newton-euler equations. common practice to drop the wxIw term. want it for better tumbling behavior.
+ // calculate using implicit euler step so it's stable.
+
+ const btVector3 inertiaLocal = getLocalInertia();
+ const btVector3 w0 = getAngularVelocity();
+
+ btMatrix3x3 I;
+
+ I = m_worldTransform.getBasis().scaled(inertiaLocal) *
+ m_worldTransform.getBasis().transpose();
+
+ // use newtons method to find implicit solution for new angular velocity (w')
+ // f(w') = -(T*step + Iw) + Iw' + w' + w'xIw'*step = 0
+ // df/dw' = I + 1xIw'*step + w'xI*step
+
+ btVector3 w1 = w0;
+
+ // one step of newton's method
+ {
+ const btVector3 fw = evalEulerEqn(w1, w0, btVector3(0, 0, 0), step, I);
+ const btMatrix3x3 dfw = evalEulerEqnDeriv(w1, w0, step, I);
+
+ btVector3 dw;
+ dw = dfw.solve33(fw);
+ //const btMatrix3x3 dfw_inv = dfw.inverse();
+ //dw = dfw_inv*fw;
+
+ w1 -= dw;
+ }
+
+ btVector3 gf = (w1 - w0);
+ return gf;
+}
+
+
void btRigidBody::integrateVelocities(btScalar step)
{
if (isStaticOrKinematicObject())
diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h
index ed90fb44115..c2f8c5d64ae 100644
--- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h
+++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h
@@ -41,10 +41,13 @@ extern bool gDisableDeactivation;
enum btRigidBodyFlags
{
BT_DISABLE_WORLD_GRAVITY = 1,
- ///The BT_ENABLE_GYROPSCOPIC_FORCE can easily introduce instability
- ///So generally it is best to not enable it.
- ///If really needed, run at a high frequency like 1000 Hertz: ///See Demos/GyroscopicDemo for an example use
- BT_ENABLE_GYROPSCOPIC_FORCE = 2
+ ///BT_ENABLE_GYROPSCOPIC_FORCE flags is enabled by default in Bullet 2.83 and onwards.
+ ///and it BT_ENABLE_GYROPSCOPIC_FORCE becomes equivalent to BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY
+ ///See Demos/GyroscopicDemo and computeGyroscopicImpulseImplicit
+ BT_ENABLE_GYROSCOPIC_FORCE_EXPLICIT = 2,
+ BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_WORLD=4,
+ BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY=8,
+ BT_ENABLE_GYROPSCOPIC_FORCE = BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_BODY,
};
@@ -87,7 +90,7 @@ class btRigidBody : public btCollisionObject
//m_optionalMotionState allows to automatic synchronize the world transform for active objects
btMotionState* m_optionalMotionState;
- //keep track of typed constraints referencing this rigid body
+ //keep track of typed constraints referencing this rigid body, to disable collision between linked bodies
btAlignedObjectArray<btTypedConstraint*> m_constraintRefs;
int m_rigidbodyFlags;
@@ -531,7 +534,18 @@ public:
return m_rigidbodyFlags;
}
- btVector3 computeGyroscopicForce(btScalar maxGyroscopicForce) const;
+
+
+
+ ///perform implicit force computation in world space
+ btVector3 computeGyroscopicImpulseImplicit_World(btScalar dt) const;
+
+ ///perform implicit force computation in body space (inertial frame)
+ btVector3 computeGyroscopicImpulseImplicit_Body(btScalar step) const;
+
+ ///explicit version is best avoided, it gains energy
+ btVector3 computeGyroscopicForceExplicit(btScalar maxGyroscopicForce) const;
+ btVector3 getLocalInertia() const;
///////////////////////////////////////////////
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp
index 56a1c55d9ae..e49cf30d044 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp
@@ -6,7 +6,8 @@
*
* COPYRIGHT:
* Copyright (C) Stephen Thompson, <stephen@solarflare.org.uk>, 2011-2013
- * Portions written By Erwin Coumans: replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
+ * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
+ * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements
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.
@@ -24,21 +25,20 @@
#include "btMultiBody.h"
#include "btMultiBodyLink.h"
#include "btMultiBodyLinkCollider.h"
-
+#include "btMultiBodyJointFeedback.h"
+#include "LinearMath/btTransformUtil.h"
+#include "LinearMath/btSerializer.h"
// #define INCLUDE_GYRO_TERM
+///todo: determine if we need these options. If so, make a proper API, otherwise delete those globals
+bool gJointFeedbackInWorldSpace = false;
+bool gJointFeedbackInJointFrame = false;
+
namespace {
const btScalar SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m^2 s^-2)
const btScalar SLEEP_TIMEOUT = btScalar(2); // in seconds
}
-
-
-
-//
-// Various spatial helper functions
-//
-
namespace {
void SpatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates
@@ -59,7 +59,7 @@ namespace {
btVector3 &bottom_out)
{
top_out = rotation_matrix.transpose() * top_in;
- bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in));
+ bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in));
}
btScalar SpatialDotProduct(const btVector3 &a_top,
@@ -69,6 +69,17 @@ namespace {
{
return a_bottom.dot(b_top) + a_top.dot(b_bottom);
}
+
+ void SpatialCrossProduct(const btVector3 &a_top,
+ const btVector3 &a_bottom,
+ const btVector3 &b_top,
+ const btVector3 &b_bottom,
+ btVector3 &top_out,
+ btVector3 &bottom_out)
+ {
+ top_out = a_top.cross(b_top);
+ bottom_out = a_bottom.cross(b_top) + a_top.cross(b_bottom);
+ }
}
@@ -79,133 +90,331 @@ namespace {
btMultiBody::btMultiBody(int n_links,
btScalar mass,
const btVector3 &inertia,
- bool fixed_base_,
- bool can_sleep_)
- : base_quat(0, 0, 0, 1),
- base_mass(mass),
- base_inertia(inertia),
+ bool fixedBase,
+ bool canSleep,
+ bool /*deprecatedUseMultiDof*/)
+ :
+ m_baseCollider(0),
+ m_baseName(0),
+ m_basePos(0,0,0),
+ m_baseQuat(0, 0, 0, 1),
+ m_baseMass(mass),
+ m_baseInertia(inertia),
- fixed_base(fixed_base_),
- awake(true),
- can_sleep(can_sleep_),
- sleep_timer(0),
- m_baseCollider(0),
+ m_fixedBase(fixedBase),
+ m_awake(true),
+ m_canSleep(canSleep),
+ m_sleepTimer(0),
+
m_linearDamping(0.04f),
m_angularDamping(0.04f),
m_useGyroTerm(true),
- m_maxAppliedImpulse(1000.f),
- m_hasSelfCollision(true)
+ m_maxAppliedImpulse(1000.f),
+ m_maxCoordinateVelocity(100.f),
+ m_hasSelfCollision(true),
+ __posUpdated(false),
+ m_dofCount(0),
+ m_posVarCnt(0),
+ m_useRK4(false),
+ m_useGlobalVelocities(false),
+ m_internalNeedsJointFeedback(false)
{
- links.resize(n_links);
+ m_links.resize(n_links);
+ m_matrixBuf.resize(n_links + 1);
+
- vector_buf.resize(2*n_links);
- matrix_buf.resize(n_links + 1);
- m_real_buf.resize(6 + 2*n_links);
- base_pos.setValue(0, 0, 0);
- base_force.setValue(0, 0, 0);
- base_torque.setValue(0, 0, 0);
+ m_baseForce.setValue(0, 0, 0);
+ m_baseTorque.setValue(0, 0, 0);
}
btMultiBody::~btMultiBody()
{
}
+void btMultiBody::setupFixed(int i,
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &parentComToThisPivotOffset,
+ const btVector3 &thisPivotToThisComOffset, bool /*deprecatedDisableParentCollision*/)
+{
+
+ m_links[i].m_mass = mass;
+ m_links[i].m_inertiaLocal = inertia;
+ m_links[i].m_parent = parent;
+ m_links[i].m_zeroRotParentToThis = rotParentToThis;
+ m_links[i].m_dVector = thisPivotToThisComOffset;
+ m_links[i].m_eVector = parentComToThisPivotOffset;
+
+ m_links[i].m_jointType = btMultibodyLink::eFixed;
+ m_links[i].m_dofCount = 0;
+ m_links[i].m_posVarCount = 0;
+
+ m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
+
+ m_links[i].updateCacheMultiDof();
+
+ updateLinksDofOffsets();
+
+}
+
+
void btMultiBody::setupPrismatic(int i,
btScalar mass,
const btVector3 &inertia,
int parent,
- const btQuaternion &rot_parent_to_this,
- const btVector3 &joint_axis,
- const btVector3 &r_vector_when_q_zero,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &jointAxis,
+ const btVector3 &parentComToThisPivotOffset,
+ const btVector3 &thisPivotToThisComOffset,
bool disableParentCollision)
{
- links[i].mass = mass;
- links[i].inertia = inertia;
- links[i].parent = parent;
- links[i].zero_rot_parent_to_this = rot_parent_to_this;
- links[i].axis_top.setValue(0,0,0);
- links[i].axis_bottom = joint_axis;
- links[i].e_vector = r_vector_when_q_zero;
- links[i].is_revolute = false;
- links[i].cached_rot_parent_to_this = rot_parent_to_this;
- if (disableParentCollision)
- links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
+ m_dofCount += 1;
+ m_posVarCnt += 1;
+
+ m_links[i].m_mass = mass;
+ m_links[i].m_inertiaLocal = inertia;
+ m_links[i].m_parent = parent;
+ m_links[i].m_zeroRotParentToThis = rotParentToThis;
+ m_links[i].setAxisTop(0, 0., 0., 0.);
+ m_links[i].setAxisBottom(0, jointAxis);
+ m_links[i].m_eVector = parentComToThisPivotOffset;
+ m_links[i].m_dVector = thisPivotToThisComOffset;
+ m_links[i].m_cachedRotParentToThis = rotParentToThis;
+
+ m_links[i].m_jointType = btMultibodyLink::ePrismatic;
+ m_links[i].m_dofCount = 1;
+ m_links[i].m_posVarCount = 1;
+ m_links[i].m_jointPos[0] = 0.f;
+ m_links[i].m_jointTorque[0] = 0.f;
- links[i].updateCache();
+ if (disableParentCollision)
+ m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
+ //
+
+ m_links[i].updateCacheMultiDof();
+
+ updateLinksDofOffsets();
}
void btMultiBody::setupRevolute(int i,
btScalar mass,
const btVector3 &inertia,
int parent,
- const btQuaternion &zero_rot_parent_to_this,
- const btVector3 &joint_axis,
- const btVector3 &parent_axis_position,
- const btVector3 &my_axis_position,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &jointAxis,
+ const btVector3 &parentComToThisPivotOffset,
+ const btVector3 &thisPivotToThisComOffset,
bool disableParentCollision)
{
- links[i].mass = mass;
- links[i].inertia = inertia;
- links[i].parent = parent;
- links[i].zero_rot_parent_to_this = zero_rot_parent_to_this;
- links[i].axis_top = joint_axis;
- links[i].axis_bottom = joint_axis.cross(my_axis_position);
- links[i].d_vector = my_axis_position;
- links[i].e_vector = parent_axis_position;
- links[i].is_revolute = true;
+ m_dofCount += 1;
+ m_posVarCnt += 1;
+
+ m_links[i].m_mass = mass;
+ m_links[i].m_inertiaLocal = inertia;
+ m_links[i].m_parent = parent;
+ m_links[i].m_zeroRotParentToThis = rotParentToThis;
+ m_links[i].setAxisTop(0, jointAxis);
+ m_links[i].setAxisBottom(0, jointAxis.cross(thisPivotToThisComOffset));
+ m_links[i].m_dVector = thisPivotToThisComOffset;
+ m_links[i].m_eVector = parentComToThisPivotOffset;
+
+ m_links[i].m_jointType = btMultibodyLink::eRevolute;
+ m_links[i].m_dofCount = 1;
+ m_links[i].m_posVarCount = 1;
+ m_links[i].m_jointPos[0] = 0.f;
+ m_links[i].m_jointTorque[0] = 0.f;
+
+ if (disableParentCollision)
+ m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
+ //
+ m_links[i].updateCacheMultiDof();
+ //
+ updateLinksDofOffsets();
+}
+
+
+
+void btMultiBody::setupSpherical(int i,
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &parentComToThisPivotOffset,
+ const btVector3 &thisPivotToThisComOffset,
+ bool disableParentCollision)
+{
+
+ m_dofCount += 3;
+ m_posVarCnt += 4;
+
+ m_links[i].m_mass = mass;
+ m_links[i].m_inertiaLocal = inertia;
+ m_links[i].m_parent = parent;
+ m_links[i].m_zeroRotParentToThis = rotParentToThis;
+ m_links[i].m_dVector = thisPivotToThisComOffset;
+ m_links[i].m_eVector = parentComToThisPivotOffset;
+
+ m_links[i].m_jointType = btMultibodyLink::eSpherical;
+ m_links[i].m_dofCount = 3;
+ m_links[i].m_posVarCount = 4;
+ m_links[i].setAxisTop(0, 1.f, 0.f, 0.f);
+ m_links[i].setAxisTop(1, 0.f, 1.f, 0.f);
+ m_links[i].setAxisTop(2, 0.f, 0.f, 1.f);
+ m_links[i].setAxisBottom(0, m_links[i].getAxisTop(0).cross(thisPivotToThisComOffset));
+ m_links[i].setAxisBottom(1, m_links[i].getAxisTop(1).cross(thisPivotToThisComOffset));
+ m_links[i].setAxisBottom(2, m_links[i].getAxisTop(2).cross(thisPivotToThisComOffset));
+ m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f; m_links[i].m_jointPos[3] = 1.f;
+ m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f;
+
+
if (disableParentCollision)
- links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
- links[i].updateCache();
+ m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
+ //
+ m_links[i].updateCacheMultiDof();
+ //
+ updateLinksDofOffsets();
}
+void btMultiBody::setupPlanar(int i,
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &rotationAxis,
+ const btVector3 &parentComToThisComOffset,
+ bool disableParentCollision)
+{
+
+ m_dofCount += 3;
+ m_posVarCnt += 3;
+
+ m_links[i].m_mass = mass;
+ m_links[i].m_inertiaLocal = inertia;
+ m_links[i].m_parent = parent;
+ m_links[i].m_zeroRotParentToThis = rotParentToThis;
+ m_links[i].m_dVector.setZero();
+ m_links[i].m_eVector = parentComToThisComOffset;
+
+ //
+ static btVector3 vecNonParallelToRotAxis(1, 0, 0);
+ if(rotationAxis.normalized().dot(vecNonParallelToRotAxis) > 0.999)
+ vecNonParallelToRotAxis.setValue(0, 1, 0);
+ //
+
+ m_links[i].m_jointType = btMultibodyLink::ePlanar;
+ m_links[i].m_dofCount = 3;
+ m_links[i].m_posVarCount = 3;
+ btVector3 n=rotationAxis.normalized();
+ m_links[i].setAxisTop(0, n[0],n[1],n[2]);
+ m_links[i].setAxisTop(1,0,0,0);
+ m_links[i].setAxisTop(2,0,0,0);
+ m_links[i].setAxisBottom(0,0,0,0);
+ btVector3 cr = m_links[i].getAxisTop(0).cross(vecNonParallelToRotAxis);
+ m_links[i].setAxisBottom(1,cr[0],cr[1],cr[2]);
+ cr = m_links[i].getAxisBottom(1).cross(m_links[i].getAxisTop(0));
+ m_links[i].setAxisBottom(2,cr[0],cr[1],cr[2]);
+ m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f;
+ m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f;
+ if (disableParentCollision)
+ m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
+ //
+ m_links[i].updateCacheMultiDof();
+ //
+ updateLinksDofOffsets();
+}
+void btMultiBody::finalizeMultiDof()
+{
+ m_deltaV.resize(0);
+ m_deltaV.resize(6 + m_dofCount);
+ m_realBuf.resize(6 + m_dofCount + m_dofCount*m_dofCount + 6 + m_dofCount); //m_dofCount for joint-space vels + m_dofCount^2 for "D" matrices + delta-pos vector (6 base "vels" + joint "vels")
+ m_vectorBuf.resize(2 * m_dofCount); //two 3-vectors (i.e. one six-vector) for each system dof ("h" matrices)
+ updateLinksDofOffsets();
+}
int btMultiBody::getParent(int i) const
{
- return links[i].parent;
+ return m_links[i].m_parent;
}
btScalar btMultiBody::getLinkMass(int i) const
{
- return links[i].mass;
+ return m_links[i].m_mass;
}
const btVector3 & btMultiBody::getLinkInertia(int i) const
{
- return links[i].inertia;
+ return m_links[i].m_inertiaLocal;
}
btScalar btMultiBody::getJointPos(int i) const
{
- return links[i].joint_pos;
+ return m_links[i].m_jointPos[0];
}
btScalar btMultiBody::getJointVel(int i) const
{
- return m_real_buf[6 + i];
+ return m_realBuf[6 + m_links[i].m_dofOffset];
}
+btScalar * btMultiBody::getJointPosMultiDof(int i)
+{
+ return &m_links[i].m_jointPos[0];
+}
+
+btScalar * btMultiBody::getJointVelMultiDof(int i)
+{
+ return &m_realBuf[6 + m_links[i].m_dofOffset];
+}
+
+const btScalar * btMultiBody::getJointPosMultiDof(int i) const
+{
+ return &m_links[i].m_jointPos[0];
+}
+
+const btScalar * btMultiBody::getJointVelMultiDof(int i) const
+{
+ return &m_realBuf[6 + m_links[i].m_dofOffset];
+}
+
+
void btMultiBody::setJointPos(int i, btScalar q)
{
- links[i].joint_pos = q;
- links[i].updateCache();
+ m_links[i].m_jointPos[0] = q;
+ m_links[i].updateCacheMultiDof();
+}
+
+void btMultiBody::setJointPosMultiDof(int i, btScalar *q)
+{
+ for(int pos = 0; pos < m_links[i].m_posVarCount; ++pos)
+ m_links[i].m_jointPos[pos] = q[pos];
+
+ m_links[i].updateCacheMultiDof();
}
void btMultiBody::setJointVel(int i, btScalar qdot)
{
- m_real_buf[6 + i] = qdot;
+ m_realBuf[6 + m_links[i].m_dofOffset] = qdot;
+}
+
+void btMultiBody::setJointVelMultiDof(int i, btScalar *qdot)
+{
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ m_realBuf[6 + m_links[i].m_dofOffset + dof] = qdot[dof];
}
const btVector3 & btMultiBody::getRVector(int i) const
{
- return links[i].cached_r_vector;
+ return m_links[i].m_cachedRVector;
}
const btQuaternion & btMultiBody::getParentToLocalRot(int i) const
{
- return links[i].cached_rot_parent_to_this;
+ return m_links[i].m_cachedRotParentToThis;
}
btVector3 btMultiBody::localPosToWorld(int i, const btVector3 &local_pos) const
@@ -260,20 +469,20 @@ void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const
{
int num_links = getNumLinks();
// Calculates the velocities of each link (and the base) in its local frame
- omega[0] = quatRotate(base_quat ,getBaseOmega());
- vel[0] = quatRotate(base_quat ,getBaseVel());
+ omega[0] = quatRotate(m_baseQuat ,getBaseOmega());
+ vel[0] = quatRotate(m_baseQuat ,getBaseVel());
for (int i = 0; i < num_links; ++i) {
- const int parent = links[i].parent;
+ const int parent = m_links[i].m_parent;
// transform parent vel into this frame, store in omega[i+1], vel[i+1]
- SpatialTransform(btMatrix3x3(links[i].cached_rot_parent_to_this), links[i].cached_r_vector,
+ SpatialTransform(btMatrix3x3(m_links[i].m_cachedRotParentToThis), m_links[i].m_cachedRVector,
omega[parent+1], vel[parent+1],
omega[i+1], vel[i+1]);
// now add qidot * shat_i
- omega[i+1] += getJointVel(i) * links[i].axis_top;
- vel[i+1] += getJointVel(i) * links[i].axis_bottom;
+ omega[i+1] += getJointVel(i) * m_links[i].getAxisTop(0);
+ vel[i+1] += getJointVel(i) * m_links[i].getAxisBottom(0);
}
}
@@ -286,12 +495,12 @@ btScalar btMultiBody::getKineticEnergy() const
compTreeLinkVelocities(&omega[0], &vel[0]);
// we will do the factor of 0.5 at the end
- btScalar result = base_mass * vel[0].dot(vel[0]);
- result += omega[0].dot(base_inertia * omega[0]);
+ btScalar result = m_baseMass * vel[0].dot(vel[0]);
+ result += omega[0].dot(m_baseInertia * omega[0]);
for (int i = 0; i < num_links; ++i) {
- result += links[i].mass * vel[i+1].dot(vel[i+1]);
- result += omega[i+1].dot(links[i].inertia * omega[i+1]);
+ result += m_links[i].m_mass * vel[i+1].dot(vel[i+1]);
+ result += omega[i+1].dot(m_links[i].m_inertiaLocal * omega[i+1]);
}
return 0.5f * result;
@@ -306,27 +515,38 @@ btVector3 btMultiBody::getAngularMomentum() const
btAlignedObjectArray<btQuaternion> rot_from_world;rot_from_world.resize(num_links+1);
compTreeLinkVelocities(&omega[0], &vel[0]);
- rot_from_world[0] = base_quat;
- btVector3 result = quatRotate(rot_from_world[0].inverse() , (base_inertia * omega[0]));
+ rot_from_world[0] = m_baseQuat;
+ btVector3 result = quatRotate(rot_from_world[0].inverse() , (m_baseInertia * omega[0]));
for (int i = 0; i < num_links; ++i) {
- rot_from_world[i+1] = links[i].cached_rot_parent_to_this * rot_from_world[links[i].parent+1];
- result += (quatRotate(rot_from_world[i+1].inverse() , (links[i].inertia * omega[i+1])));
+ rot_from_world[i+1] = m_links[i].m_cachedRotParentToThis * rot_from_world[m_links[i].m_parent+1];
+ result += (quatRotate(rot_from_world[i+1].inverse() , (m_links[i].m_inertiaLocal * omega[i+1])));
}
return result;
}
+void btMultiBody::clearConstraintForces()
+{
+ m_baseConstraintForce.setValue(0, 0, 0);
+ m_baseConstraintTorque.setValue(0, 0, 0);
+
+ for (int i = 0; i < getNumLinks(); ++i) {
+ m_links[i].m_appliedConstraintForce.setValue(0, 0, 0);
+ m_links[i].m_appliedConstraintTorque.setValue(0, 0, 0);
+ }
+}
void btMultiBody::clearForcesAndTorques()
{
- base_force.setValue(0, 0, 0);
- base_torque.setValue(0, 0, 0);
+ m_baseForce.setValue(0, 0, 0);
+ m_baseTorque.setValue(0, 0, 0);
+
for (int i = 0; i < getNumLinks(); ++i) {
- links[i].applied_force.setValue(0, 0, 0);
- links[i].applied_torque.setValue(0, 0, 0);
- links[i].joint_torque = 0;
+ m_links[i].m_appliedForce.setValue(0, 0, 0);
+ m_links[i].m_appliedTorque.setValue(0, 0, 0);
+ m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = m_links[i].m_jointTorque[3] = m_links[i].m_jointTorque[4] = m_links[i].m_jointTorque[5] = 0.f;
}
}
@@ -334,54 +554,81 @@ void btMultiBody::clearVelocities()
{
for (int i = 0; i < 6 + getNumLinks(); ++i)
{
- m_real_buf[i] = 0.f;
+ m_realBuf[i] = 0.f;
}
}
void btMultiBody::addLinkForce(int i, const btVector3 &f)
{
- links[i].applied_force += f;
+ m_links[i].m_appliedForce += f;
}
void btMultiBody::addLinkTorque(int i, const btVector3 &t)
{
- links[i].applied_torque += t;
+ m_links[i].m_appliedTorque += t;
}
+void btMultiBody::addLinkConstraintForce(int i, const btVector3 &f)
+{
+ m_links[i].m_appliedConstraintForce += f;
+}
+
+void btMultiBody::addLinkConstraintTorque(int i, const btVector3 &t)
+{
+ m_links[i].m_appliedConstraintTorque += t;
+}
+
+
+
void btMultiBody::addJointTorque(int i, btScalar Q)
{
- links[i].joint_torque += Q;
+ m_links[i].m_jointTorque[0] += Q;
+}
+
+void btMultiBody::addJointTorqueMultiDof(int i, int dof, btScalar Q)
+{
+ m_links[i].m_jointTorque[dof] += Q;
+}
+
+void btMultiBody::addJointTorqueMultiDof(int i, const btScalar *Q)
+{
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ m_links[i].m_jointTorque[dof] = Q[dof];
}
const btVector3 & btMultiBody::getLinkForce(int i) const
{
- return links[i].applied_force;
+ return m_links[i].m_appliedForce;
}
const btVector3 & btMultiBody::getLinkTorque(int i) const
{
- return links[i].applied_torque;
+ return m_links[i].m_appliedTorque;
}
btScalar btMultiBody::getJointTorque(int i) const
{
- return links[i].joint_torque;
+ return m_links[i].m_jointTorque[0];
}
+btScalar * btMultiBody::getJointTorqueMultiDof(int i)
+{
+ return &m_links[i].m_jointTorque[0];
+}
-inline btMatrix3x3 vecMulVecTranspose(const btVector3& v0, const btVector3& v1Transposed)
+inline btMatrix3x3 outerProduct(const btVector3& v0, const btVector3& v1) //renamed it from vecMulVecTranspose (http://en.wikipedia.org/wiki/Outer_product); maybe it should be moved to btVector3 like dot and cross?
{
btVector3 row0 = btVector3(
- v0.x() * v1Transposed.x(),
- v0.x() * v1Transposed.y(),
- v0.x() * v1Transposed.z());
+ v0.x() * v1.x(),
+ v0.x() * v1.y(),
+ v0.x() * v1.z());
btVector3 row1 = btVector3(
- v0.y() * v1Transposed.x(),
- v0.y() * v1Transposed.y(),
- v0.y() * v1Transposed.z());
+ v0.y() * v1.x(),
+ v0.y() * v1.y(),
+ v0.y() * v1.z());
btVector3 row2 = btVector3(
- v0.z() * v1Transposed.x(),
- v0.z() * v1Transposed.y(),
- v0.z() * v1Transposed.z());
+ v0.z() * v1.x(),
+ v0.z() * v1.y(),
+ v0.z() * v1.z());
btMatrix3x3 m(row0[0],row0[1],row0[2],
row1[0],row1[1],row1[2],
@@ -389,11 +636,14 @@ inline btMatrix3x3 vecMulVecTranspose(const btVector3& v0, const btVector3& v1Tr
return m;
}
+#define vecMulVecTranspose(v0, v1Transposed) outerProduct(v0, v1Transposed)
+//
-void btMultiBody::stepVelocities(btScalar dt,
+void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt,
btAlignedObjectArray<btScalar> &scratch_r,
btAlignedObjectArray<btVector3> &scratch_v,
- btAlignedObjectArray<btMatrix3x3> &scratch_m)
+ btAlignedObjectArray<btMatrix3x3> &scratch_m,
+ bool isConstraintPass)
{
// Implement Featherstone's algorithm to calculate joint accelerations (q_double_dot)
// and the base linear & angular accelerations.
@@ -405,6 +655,12 @@ void btMultiBody::stepVelocities(btScalar dt,
// Format is: 3 angular accelerations (in world frame), 3 linear accelerations (in world frame),
// num_links joint acceleration values.
+ // We added support for multi degree of freedom (multi dof) joints.
+ // In addition we also can compute the joint reaction forces. This is performed in a second pass,
+ // so that we can include the effect of the constraint solver forces (computed in the PGS LCP solver)
+
+ m_internalNeedsJointFeedback = false;
+
int num_links = getNumLinks();
const btScalar DAMPING_K1_LINEAR = m_linearDamping;
@@ -419,261 +675,513 @@ void btMultiBody::stepVelocities(btScalar dt,
// Temporary matrices/vectors -- use scratch space from caller
// so that we don't have to keep reallocating every frame
- scratch_r.resize(2*num_links + 6);
+ scratch_r.resize(2*m_dofCount + 6); //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);
- btScalar * r_ptr = &scratch_r[0];
- btScalar * output = &scratch_r[num_links]; // "output" holds the q_double_dot results
+ //btScalar * r_ptr = &scratch_r[0];
+ btScalar * output = &scratch_r[m_dofCount]; // "output" holds the q_double_dot results
btVector3 * v_ptr = &scratch_v[0];
- // vhat_i (top = angular, bottom = linear part)
- btVector3 * vel_top_angular = v_ptr; v_ptr += num_links + 1;
- btVector3 * vel_bottom_linear = v_ptr; v_ptr += num_links + 1;
-
- // zhat_i^A
- btVector3 * zero_acc_top_angular = v_ptr; v_ptr += num_links + 1;
- btVector3 * zero_acc_bottom_linear = v_ptr; v_ptr += num_links + 1;
-
- // chat_i (note NOT defined for the base)
- btVector3 * coriolis_top_angular = v_ptr; v_ptr += num_links;
- btVector3 * coriolis_bottom_linear = v_ptr; v_ptr += num_links;
-
- // top left, top right and bottom left blocks of Ihat_i^A.
- // bottom right block = transpose of top left block and is not stored.
- // Note: the top right and bottom left blocks are always symmetric matrices, but we don't make use of this fact currently.
- btMatrix3x3 * inertia_top_left = &scratch_m[num_links + 1];
- btMatrix3x3 * inertia_top_right = &scratch_m[2*num_links + 2];
- btMatrix3x3 * inertia_bottom_left = &scratch_m[3*num_links + 3];
+ // vhat_i (top = angular, bottom = linear part)
+ btSpatialMotionVector *spatVel = (btSpatialMotionVector *)v_ptr;
+ v_ptr += num_links * 2 + 2;
+ //
+ // zhat_i^A
+ btSpatialForceVector * zeroAccSpatFrc = (btSpatialForceVector *)v_ptr;
+ v_ptr += num_links * 2 + 2;
+ //
+ // chat_i (note NOT defined for the base)
+ btSpatialMotionVector * spatCoriolisAcc = (btSpatialMotionVector *)v_ptr;
+ v_ptr += num_links * 2;
+ //
+ // Ihat_i^A.
+ btSymmetricSpatialDyad * spatInertia = (btSymmetricSpatialDyad *)&scratch_m[num_links + 1];
// Cached 3x3 rotation matrices from parent frame to this frame.
- btMatrix3x3 * rot_from_parent = &matrix_buf[0];
+ btMatrix3x3 * rot_from_parent = &m_matrixBuf[0];
btMatrix3x3 * rot_from_world = &scratch_m[0];
// hhat_i, ahat_i
- // hhat is NOT stored for the base (but ahat is)
- btVector3 * h_top = num_links > 0 ? &vector_buf[0] : 0;
- btVector3 * h_bottom = num_links > 0 ? &vector_buf[num_links] : 0;
- btVector3 * accel_top = v_ptr; v_ptr += num_links + 1;
- btVector3 * accel_bottom = v_ptr; v_ptr += num_links + 1;
-
- // Y_i, D_i
- btScalar * Y = r_ptr; r_ptr += num_links;
- btScalar * D = num_links > 0 ? &m_real_buf[6 + num_links] : 0;
+ // 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;
+ //
+ // Y_i, invD_i
+ btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
+ btScalar * Y = &scratch_r[0];
+ //
+ //aux variables
+ static btSpatialMotionVector spatJointVel; //spatial velocity due to the joint motion (i.e. without predecessors' influence)
+ static btScalar D[36]; //"D" matrix; it's dofxdof for each body so asingle 6x6 D matrix will do
+ static btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies
+ static btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel)
+ static btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough
+ static btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors
+ static btSpatialTransformationMatrix fromParent; //spatial transform from parent to child
+ static btSymmetricSpatialDyad dyadTemp; //inertia matrix temp
+ static btSpatialTransformationMatrix fromWorld;
+ fromWorld.m_trnVec.setZero();
+ /////////////////
// ptr to the joint accel part of the output
btScalar * joint_accel = output + 6;
-
// Start of the algorithm proper.
// First 'upward' loop.
// Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
- rot_from_parent[0] = btMatrix3x3(base_quat);
+ rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!?
- vel_top_angular[0] = rot_from_parent[0] * base_omega;
- vel_bottom_linear[0] = rot_from_parent[0] * base_vel;
-
- if (fixed_base) {
- zero_acc_top_angular[0] = zero_acc_bottom_linear[0] = btVector3(0,0,0);
- } else {
- zero_acc_top_angular[0] = - (rot_from_parent[0] * (base_force
- - base_mass*(DAMPING_K1_LINEAR+DAMPING_K2_LINEAR*base_vel.norm())*base_vel));
-
- zero_acc_bottom_linear[0] =
- - (rot_from_parent[0] * base_torque);
+ //create the vector of spatial velocity of the base by transforming global-coor linear and angular velocities into base-local coordinates
+ spatVel[0].setVector(rot_from_parent[0] * base_omega, rot_from_parent[0] * base_vel);
+ if (m_fixedBase)
+ {
+ zeroAccSpatFrc[0].setZero();
+ }
+ else
+ {
+ btVector3 baseForce = isConstraintPass? m_baseConstraintForce : m_baseForce;
+ 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.;
+ zeroAccSpatFrc[0].addVector(angDampMult * m_baseInertia * spatVel[0].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[0].getAngular().norm()),
+ linDampMult * m_baseMass * spatVel[0].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[0].getLinear().norm()));
+
+ //
+ //p += vhat x Ihat vhat - done in a simpler way
if (m_useGyroTerm)
- zero_acc_bottom_linear[0]+=vel_top_angular[0].cross( base_inertia * vel_top_angular[0] );
+ zeroAccSpatFrc[0].addAngular(spatVel[0].getAngular().cross(m_baseInertia * spatVel[0].getAngular()));
+ //
+ zeroAccSpatFrc[0].addLinear(m_baseMass * spatVel[0].getAngular().cross(spatVel[0].getLinear()));
+ }
- zero_acc_bottom_linear[0] += base_inertia * vel_top_angular[0] * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR*vel_top_angular[0].norm());
- }
+ //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
+ spatInertia[0].setMatrix( btMatrix3x3(0,0,0,0,0,0,0,0,0),
+ //
+ btMatrix3x3(m_baseMass, 0, 0,
+ 0, m_baseMass, 0,
+ 0, 0, m_baseMass),
+ //
+ btMatrix3x3(m_baseInertia[0], 0, 0,
+ 0, m_baseInertia[1], 0,
+ 0, 0, m_baseInertia[2])
+ );
+ rot_from_world[0] = rot_from_parent[0];
+ //
+ for (int i = 0; i < num_links; ++i) {
+ const int parent = m_links[i].m_parent;
+ rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis);
+ rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1];
- inertia_top_left[0] = btMatrix3x3(0,0,0,0,0,0,0,0,0);//::Zero();
-
-
- inertia_top_right[0].setValue(base_mass, 0, 0,
- 0, base_mass, 0,
- 0, 0, base_mass);
- inertia_bottom_left[0].setValue(base_inertia[0], 0, 0,
- 0, base_inertia[1], 0,
- 0, 0, base_inertia[2]);
+ fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector;
+ fromWorld.m_rotMat = rot_from_world[i+1];
+ fromParent.transform(spatVel[parent+1], spatVel[i+1]);
- rot_from_world[0] = rot_from_parent[0];
+ // now set vhat_i to its true value by doing
+ // vhat_i += qidot * shat_i
+ if(!m_useGlobalVelocities)
+ {
+ spatJointVel.setZero();
- for (int i = 0; i < num_links; ++i) {
- const int parent = links[i].parent;
- rot_from_parent[i+1] = btMatrix3x3(links[i].cached_rot_parent_to_this);
-
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof];
- rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1];
-
- // vhat_i = i_xhat_p(i) * vhat_p(i)
- SpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
- vel_top_angular[parent+1], vel_bottom_linear[parent+1],
- vel_top_angular[i+1], vel_bottom_linear[i+1]);
-
- // we can now calculate chat_i
- // remember vhat_i is really vhat_p(i) (but in current frame) at this point
- coriolis_bottom_linear[i] = vel_top_angular[i+1].cross(vel_top_angular[i+1].cross(links[i].cached_r_vector))
- + 2 * vel_top_angular[i+1].cross(links[i].axis_bottom) * getJointVel(i);
- if (links[i].is_revolute) {
- coriolis_top_angular[i] = vel_top_angular[i+1].cross(links[i].axis_top) * getJointVel(i);
- coriolis_bottom_linear[i] += (getJointVel(i) * getJointVel(i)) * links[i].axis_top.cross(links[i].axis_bottom);
- } else {
- coriolis_top_angular[i] = btVector3(0,0,0);
- }
-
- // now set vhat_i to its true value by doing
- // vhat_i += qidot * shat_i
- vel_top_angular[i+1] += getJointVel(i) * links[i].axis_top;
- vel_bottom_linear[i+1] += getJointVel(i) * links[i].axis_bottom;
+ // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint
+ spatVel[i+1] += spatJointVel;
- // calculate zhat_i^A
- zero_acc_top_angular[i+1] = - (rot_from_world[i+1] * (links[i].applied_force));
- zero_acc_top_angular[i+1] += links[i].mass * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR*vel_bottom_linear[i+1].norm()) * vel_bottom_linear[i+1];
+ //
+ // vhat_i is vhat_p(i) transformed to local coors + the velocity across the i-th inboard joint
+ //spatVel[i+1] = fromParent * spatVel[parent+1] + spatJointVel;
- zero_acc_bottom_linear[i+1] =
- - (rot_from_world[i+1] * links[i].applied_torque);
- if (m_useGyroTerm)
+ }
+ else
{
- zero_acc_bottom_linear[i+1] += vel_top_angular[i+1].cross( links[i].inertia * vel_top_angular[i+1] );
+ fromWorld.transformRotationOnly(m_links[i].m_absFrameTotVelocity, spatVel[i+1]);
+ fromWorld.transformRotationOnly(m_links[i].m_absFrameLocVelocity, spatJointVel);
}
- zero_acc_bottom_linear[i+1] += links[i].inertia * vel_top_angular[i+1] * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR*vel_top_angular[i+1].norm());
+ // we can now calculate chat_i
+ spatVel[i+1].cross(spatJointVel, spatCoriolisAcc[i]);
- // calculate Ihat_i^A
- inertia_top_left[i+1] = btMatrix3x3(0,0,0,0,0,0,0,0,0);//::Zero();
- inertia_top_right[i+1].setValue(links[i].mass, 0, 0,
- 0, links[i].mass, 0,
- 0, 0, links[i].mass);
- inertia_bottom_left[i+1].setValue(links[i].inertia[0], 0, 0,
- 0, links[i].inertia[1], 0,
- 0, 0, links[i].inertia[2]);
- }
+ // calculate zhat_i^A
+ //
+ //external forces
+ btVector3 linkAppliedForce = isConstraintPass? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce;
+ btVector3 linkAppliedTorque =isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque;
+
+ zeroAccSpatFrc[i+1].setVector(-(rot_from_world[i+1] * linkAppliedTorque), -(rot_from_world[i+1] * linkAppliedForce ));
+
+#if 0
+ {
+ b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f",
+ i+1,
+ zeroAccSpatFrc[i+1].m_topVec[0],
+ zeroAccSpatFrc[i+1].m_topVec[1],
+ zeroAccSpatFrc[i+1].m_topVec[2],
+ zeroAccSpatFrc[i+1].m_bottomVec[0],
+ zeroAccSpatFrc[i+1].m_bottomVec[1],
+ zeroAccSpatFrc[i+1].m_bottomVec[2]);
+ }
+#endif
+ //
+ //adding damping terms (only)
+ btScalar linDampMult = 1., angDampMult = 1.;
+ zeroAccSpatFrc[i+1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i+1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i+1].getAngular().norm()),
+ linDampMult * m_links[i].m_mass * spatVel[i+1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i+1].getLinear().norm()));
+
+ // calculate Ihat_i^A
+ //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
+ spatInertia[i+1].setMatrix( btMatrix3x3(0,0,0,0,0,0,0,0,0),
+ //
+ btMatrix3x3(m_links[i].m_mass, 0, 0,
+ 0, m_links[i].m_mass, 0,
+ 0, 0, m_links[i].m_mass),
+ //
+ btMatrix3x3(m_links[i].m_inertiaLocal[0], 0, 0,
+ 0, m_links[i].m_inertiaLocal[1], 0,
+ 0, 0, m_links[i].m_inertiaLocal[2])
+ );
+ //
+ //p += vhat x Ihat vhat - done in a simpler way
+ if(m_useGyroTerm)
+ zeroAccSpatFrc[i+1].addAngular(spatVel[i+1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i+1].getAngular()));
+ //
+ zeroAccSpatFrc[i+1].addLinear(m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear()));
+ //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear());
+ ////clamp parent's omega
+ //btScalar parOmegaMod = temp.length();
+ //btScalar parOmegaModMax = 1000;
+ //if(parOmegaMod > parOmegaModMax)
+ // temp *= parOmegaModMax / parOmegaMod;
+ //zeroAccSpatFrc[i+1].addLinear(temp);
+ //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length());
+ //temp = spatCoriolisAcc[i].getLinear();
+ //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length());
+
+
+
+ //printf("w[%d] = [%.4f %.4f %.4f]\n", i, vel_top_angular[i+1].x(), vel_top_angular[i+1].y(), vel_top_angular[i+1].z());
+ //printf("v[%d] = [%.4f %.4f %.4f]\n", i, vel_bottom_linear[i+1].x(), vel_bottom_linear[i+1].y(), vel_bottom_linear[i+1].z());
+ //printf("c[%d] = [%.4f %.4f %.4f]\n", i, coriolis_bottom_linear[i].x(), coriolis_bottom_linear[i].y(), coriolis_bottom_linear[i].z());
+ }
+
// 'Downward' loop.
// (part of TreeForwardDynamics in Mirtich.)
- for (int i = num_links - 1; i >= 0; --i) {
-
- h_top[i] = inertia_top_left[i+1] * links[i].axis_top + inertia_top_right[i+1] * links[i].axis_bottom;
- h_bottom[i] = inertia_bottom_left[i+1] * links[i].axis_top + inertia_top_left[i+1].transpose() * links[i].axis_bottom;
- btScalar val = SpatialDotProduct(links[i].axis_top, links[i].axis_bottom, h_top[i], h_bottom[i]);
- D[i] = val;
- Y[i] = links[i].joint_torque
- - SpatialDotProduct(links[i].axis_top, links[i].axis_bottom, zero_acc_top_angular[i+1], zero_acc_bottom_linear[i+1])
- - SpatialDotProduct(h_top[i], h_bottom[i], coriolis_top_angular[i], coriolis_bottom_linear[i]);
+ for (int i = num_links - 1; i >= 0; --i)
+ {
+ const int parent = m_links[i].m_parent;
+ fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector;
- const int parent = links[i].parent;
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ //
+ hDof = spatInertia[i+1] * m_links[i].m_axes[dof];
+ //
+ 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)
+ ;
+ }
-
- // Ip += pXi * (Ii - hi hi' / Di) * iXp
- const btScalar one_over_di = 1.0f / D[i];
+ 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];
+ D_row[dof2] = m_links[i].m_axes[dof].dot(hDof2);
+ }
+ }
-
+ btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset];
+ switch(m_links[i].m_jointType)
+ {
+ case btMultibodyLink::ePrismatic:
+ case btMultibodyLink::eRevolute:
+ {
+ invDi[0] = 1.0f / D[0];
+ break;
+ }
+ case btMultibodyLink::eSpherical:
+ case btMultibodyLink::ePlanar:
+ {
+ static btMatrix3x3 D3x3; D3x3.setValue(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]);
+ static btMatrix3x3 invD3x3; invD3x3 = D3x3.inverse();
+
+ //unroll the loop?
+ for(int row = 0; row < 3; ++row)
+ {
+ for(int col = 0; col < 3; ++col)
+ {
+ invDi[row * 3 + col] = invD3x3[row][col];
+ }
+ }
+
+ break;
+ }
+ default:
+ {
+
+ }
+ }
+ //determine h*D^{-1}
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ spatForceVecTemps[dof].setZero();
+
+ for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
+ {
+ btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
+ //
+ spatForceVecTemps[dof] += hDof2 * invDi[dof2 * m_links[i].m_dofCount + dof];
+ }
+ }
- const btMatrix3x3 TL = inertia_top_left[i+1] - vecMulVecTranspose(one_over_di * h_top[i] , h_bottom[i]);
- const btMatrix3x3 TR = inertia_top_right[i+1] - vecMulVecTranspose(one_over_di * h_top[i] , h_top[i]);
- const btMatrix3x3 BL = inertia_bottom_left[i+1]- vecMulVecTranspose(one_over_di * h_bottom[i] , h_bottom[i]);
+ dyadTemp = spatInertia[i+1];
+ //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];
+ //
+ dyadTemp -= symmetricSpatialOuterProduct(hDof, spatForceVecTemps[dof]);
+ }
- btMatrix3x3 r_cross;
- r_cross.setValue(
- 0, -links[i].cached_r_vector[2], links[i].cached_r_vector[1],
- links[i].cached_r_vector[2], 0, -links[i].cached_r_vector[0],
- -links[i].cached_r_vector[1], links[i].cached_r_vector[0], 0);
+ fromParent.transformInverse(dyadTemp, spatInertia[parent+1], btSpatialTransformationMatrix::Add);
- inertia_top_left[parent+1] += rot_from_parent[i+1].transpose() * ( TL - TR * r_cross ) * rot_from_parent[i+1];
- inertia_top_right[parent+1] += rot_from_parent[i+1].transpose() * TR * rot_from_parent[i+1];
- inertia_bottom_left[parent+1] += rot_from_parent[i+1].transpose() *
- (r_cross * (TL - TR * r_cross) + BL - TL.transpose() * r_cross) * rot_from_parent[i+1];
-
-
- // Zp += pXi * (Zi + Ii*ci + hi*Yi/Di)
- btVector3 in_top, in_bottom, out_top, out_bottom;
- const btScalar Y_over_D = Y[i] * one_over_di;
- in_top = zero_acc_top_angular[i+1]
- + inertia_top_left[i+1] * coriolis_top_angular[i]
- + inertia_top_right[i+1] * coriolis_bottom_linear[i]
- + Y_over_D * h_top[i];
- in_bottom = zero_acc_bottom_linear[i+1]
- + inertia_bottom_left[i+1] * coriolis_top_angular[i]
- + inertia_top_left[i+1].transpose() * coriolis_bottom_linear[i]
- + Y_over_D * h_bottom[i];
- InverseSpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
- in_top, in_bottom, out_top, out_bottom);
- zero_acc_top_angular[parent+1] += out_top;
- zero_acc_bottom_linear[parent+1] += out_bottom;
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ invD_times_Y[dof] = 0.f;
+
+ for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
+ {
+ invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2];
+ }
+ }
+
+ spatForceVecTemps[0] = zeroAccSpatFrc[i+1] + spatInertia[i+1] * spatCoriolisAcc[i];
+
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ //
+ spatForceVecTemps[0] += hDof * invD_times_Y[dof];
+ }
+
+ fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]);
+
+ zeroAccSpatFrc[parent+1] += spatForceVecTemps[1];
}
// Second 'upward' loop
// (part of TreeForwardDynamics in Mirtich)
- if (fixed_base)
+ if (m_fixedBase)
{
- accel_top[0] = accel_bottom[0] = btVector3(0,0,0);
+ spatAcc[0].setZero();
}
else
{
if (num_links > 0)
{
- //Matrix<btScalar, 6, 6> Imatrix;
- //Imatrix.block<3,3>(0,0) = inertia_top_left[0];
- //Imatrix.block<3,3>(3,0) = inertia_bottom_left[0];
- //Imatrix.block<3,3>(0,3) = inertia_top_right[0];
- //Imatrix.block<3,3>(3,3) = inertia_top_left[0].transpose();
- //cached_imatrix_lu.reset(new Eigen::LU<Matrix<btScalar, 6, 6> >(Imatrix)); // TODO: Avoid memory allocation here?
-
- cached_inertia_top_left = inertia_top_left[0];
- cached_inertia_top_right = inertia_top_right[0];
- cached_inertia_lower_left = inertia_bottom_left[0];
- cached_inertia_lower_right= inertia_top_left[0].transpose();
-
- }
- btVector3 rhs_top (zero_acc_top_angular[0][0], zero_acc_top_angular[0][1], zero_acc_top_angular[0][2]);
- btVector3 rhs_bot (zero_acc_bottom_linear[0][0], zero_acc_bottom_linear[0][1], zero_acc_bottom_linear[0][2]);
- float result[6];
-
- solveImatrix(rhs_top, rhs_bot, result);
-// printf("result=%f,%f,%f,%f,%f,%f\n",result[0],result[0],result[0],result[0],result[0],result[0]);
- for (int i = 0; i < 3; ++i) {
- accel_top[0][i] = -result[i];
- accel_bottom[0][i] = -result[i+3];
- }
+ m_cachedInertiaTopLeft = spatInertia[0].m_topLeftMat;
+ m_cachedInertiaTopRight = spatInertia[0].m_topRightMat;
+ m_cachedInertiaLowerLeft = spatInertia[0].m_bottomLeftMat;
+ m_cachedInertiaLowerRight= spatInertia[0].m_topLeftMat.transpose();
+ }
+
+ solveImatrix(zeroAccSpatFrc[0], result);
+ spatAcc[0] = -result;
}
+
+
+ // now do the loop over the m_links
+ for (int i = 0; i < num_links; ++i)
+ {
+ // qdd = D^{-1} * (Y - h^{T}*apar) = (S^{T}*I*S)^{-1} * (tau - S^{T}*I*cor - S^{T}*zeroAccFrc - S^{T}*I*apar)
+ // a = apar + cor + Sqdd
+ //or
+ // qdd = D^{-1} * (Y - h^{T}*(apar+cor))
+ // a = apar + Sqdd
+
+ const int parent = m_links[i].m_parent;
+ fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector;
+
+ fromParent.transform(spatAcc[parent+1], spatAcc[i+1]);
+
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ 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);
+ }
+
+ btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset];
+ //D^{-1} * (Y - h^{T}*apar)
+ mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
+
+ spatAcc[i+1] += spatCoriolisAcc[i];
+
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ spatAcc[i+1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
+
+ if (m_links[i].m_jointFeedback)
+ {
+ m_internalNeedsJointFeedback = true;
+
+ btVector3 angularBotVec = (spatInertia[i+1]*spatAcc[i+1]+zeroAccSpatFrc[i+1]).m_bottomVec;
+ btVector3 linearTopVec = (spatInertia[i+1]*spatAcc[i+1]+zeroAccSpatFrc[i+1]).m_topVec;
+
+ if (gJointFeedbackInJointFrame)
+ {
+ //shift the reaction forces to the joint frame
+ //linear (force) component is the same
+ //shift the angular (torque, moment) component using the relative position, m_links[i].m_dVector
+ angularBotVec = angularBotVec - linearTopVec.cross(m_links[i].m_dVector);
+ }
+
+
+ if (gJointFeedbackInWorldSpace)
+ {
+ if (isConstraintPass)
+ {
+ m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += m_links[i].m_cachedWorldTransform.getBasis()*angularBotVec;
+ m_links[i].m_jointFeedback->m_reactionForces.m_topVec += m_links[i].m_cachedWorldTransform.getBasis()*linearTopVec;
+ } else
+ {
+ m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = m_links[i].m_cachedWorldTransform.getBasis()*angularBotVec;
+ m_links[i].m_jointFeedback->m_reactionForces.m_topVec = m_links[i].m_cachedWorldTransform.getBasis()*linearTopVec;
+ }
+ } else
+ {
+ if (isConstraintPass)
+ {
+ m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += angularBotVec;
+ m_links[i].m_jointFeedback->m_reactionForces.m_topVec += linearTopVec;
+
+ }
+ else
+ {
+ m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = angularBotVec;
+ m_links[i].m_jointFeedback->m_reactionForces.m_topVec = linearTopVec;
+ }
+ }
+ }
- // now do the loop over the links
- for (int i = 0; i < num_links; ++i) {
- const int parent = links[i].parent;
- SpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
- accel_top[parent+1], accel_bottom[parent+1],
- accel_top[i+1], accel_bottom[i+1]);
- joint_accel[i] = (Y[i] - SpatialDotProduct(h_top[i], h_bottom[i], accel_top[i+1], accel_bottom[i+1])) / D[i];
- accel_top[i+1] += coriolis_top_angular[i] + joint_accel[i] * links[i].axis_top;
- accel_bottom[i+1] += coriolis_bottom_linear[i] + joint_accel[i] * links[i].axis_bottom;
}
// transform base accelerations back to the world frame.
- btVector3 omegadot_out = rot_from_parent[0].transpose() * accel_top[0];
+ 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() * accel_bottom[0];
+ 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];
+
+ /////////////////
+ //printf("q = [");
+ //printf("%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f ", m_baseQuat.x(), m_baseQuat.y(), m_baseQuat.z(), m_baseQuat.w(), m_basePos.x(), m_basePos.y(), m_basePos.z());
+ //for(int link = 0; link < getNumLinks(); ++link)
+ // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
+ // printf("%.6f ", m_links[link].m_jointPos[dof]);
+ //printf("]\n");
+ ////
+ //printf("qd = [");
+ //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
+ // printf("%.6f ", m_realBuf[dof]);
+ //printf("]\n");
+ //printf("qdd = [");
+ //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
+ // printf("%.6f ", output[dof]);
+ //printf("]\n");
+ /////////////////
+
// Final step: add the accelerations (times dt) to the velocities.
- applyDeltaVee(output, dt);
+ if (!isConstraintPass)
+ {
+ if(dt > 0.)
+ applyDeltaVeeMultiDof(output, dt);
+
+ }
+ /////
+ //btScalar angularThres = 1;
+ //btScalar maxAngVel = 0.;
+ //bool scaleDown = 1.;
+ //for(int link = 0; link < m_links.size(); ++link)
+ //{
+ // if(spatVel[link+1].getAngular().length() > maxAngVel)
+ // {
+ // maxAngVel = spatVel[link+1].getAngular().length();
+ // scaleDown = angularThres / spatVel[link+1].getAngular().length();
+ // break;
+ // }
+ //}
+
+ //if(scaleDown != 1.)
+ //{
+ // for(int link = 0; link < m_links.size(); ++link)
+ // {
+ // if(m_links[link].m_jointType == btMultibodyLink::eRevolute || m_links[link].m_jointType == btMultibodyLink::eSpherical)
+ // {
+ // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
+ // getJointVelMultiDof(link)[dof] *= scaleDown;
+ // }
+ // }
+ //}
+ /////
+
+ /////////////////////
+ if(m_useGlobalVelocities)
+ {
+ for (int i = 0; i < num_links; ++i)
+ {
+ const int parent = m_links[i].m_parent;
+ //rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); /// <- done
+ //rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; /// <- done
+
+ fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector;
+ fromWorld.m_rotMat = rot_from_world[i+1];
+
+ // vhat_i = i_xhat_p(i) * vhat_p(i)
+ fromParent.transform(spatVel[parent+1], spatVel[i+1]);
+ //nice alternative below (using operator *) but it generates temps
+ /////////////////////////////////////////////////////////////
+
+ // now set vhat_i to its true value by doing
+ // vhat_i += qidot * shat_i
+ spatJointVel.setZero();
+
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof];
+
+ // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint
+ spatVel[i+1] += spatJointVel;
+
+
+ fromWorld.transformInverseRotationOnly(spatVel[i+1], m_links[i].m_absFrameTotVelocity);
+ fromWorld.transformInverseRotationOnly(spatJointVel, m_links[i].m_absFrameLocVelocity);
+ }
+ }
}
@@ -685,24 +1193,24 @@ void btMultiBody::solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bo
///solve I * x = rhs, so the result = invI * rhs
if (num_links == 0)
{
- // in the case of 0 links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
- result[0] = rhs_bot[0] / base_inertia[0];
- result[1] = rhs_bot[1] / base_inertia[1];
- result[2] = rhs_bot[2] / base_inertia[2];
- result[3] = rhs_top[0] / base_mass;
- result[4] = rhs_top[1] / base_mass;
- result[5] = rhs_top[2] / base_mass;
+ // 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];
+ 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
{
/// Special routine for calculating the inverse of a spatial inertia matrix
///the 6x6 matrix is stored as 4 blocks of 3x3 matrices
- btMatrix3x3 Binv = cached_inertia_top_right.inverse()*-1.f;
- btMatrix3x3 tmp = cached_inertia_lower_right * Binv;
- btMatrix3x3 invIupper_right = (tmp * cached_inertia_top_left + cached_inertia_lower_left).inverse();
- tmp = invIupper_right * cached_inertia_lower_right;
+ btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse()*-1.f;
+ btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv;
+ btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse();
+ tmp = invIupper_right * m_cachedInertiaLowerRight;
btMatrix3x3 invI_upper_left = (tmp * Binv);
btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
- tmp = cached_inertia_top_left * invI_upper_left;
+ tmp = m_cachedInertiaTopLeft * invI_upper_left;
tmp[0][0]-= 1.0;
tmp[1][1]-= 1.0;
tmp[2][2]-= 1.0;
@@ -727,171 +1235,363 @@ void btMultiBody::solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bo
}
}
+void btMultiBody::solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const
+{
+ int num_links = getNumLinks();
+ ///solve I * x = rhs, so the result = invI * rhs
+ 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
+ {
+ /// Special routine for calculating the inverse of a spatial inertia matrix
+ ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices
+ btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse()*-1.f;
+ btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv;
+ btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse();
+ tmp = invIupper_right * m_cachedInertiaLowerRight;
+ btMatrix3x3 invI_upper_left = (tmp * Binv);
+ btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
+ tmp = m_cachedInertiaTopLeft * invI_upper_left;
+ tmp[0][0]-= 1.0;
+ tmp[1][1]-= 1.0;
+ tmp[2][2]-= 1.0;
+ btMatrix3x3 invI_lower_left = (Binv * tmp);
+
+ //multiply result = invI * rhs
+ {
+ btVector3 vtop = invI_upper_left*rhs.getLinear();
+ btVector3 tmp;
+ tmp = invIupper_right * rhs.getAngular();
+ vtop += tmp;
+ btVector3 vbot = invI_lower_left*rhs.getLinear();
+ tmp = invI_lower_right * rhs.getAngular();
+ vbot += tmp;
+ result.setVector(vtop, vbot);
+ }
+
+ }
+}
+void btMultiBody::mulMatrix(btScalar *pA, btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const
+{
+ for (int row = 0; row < rowsA; row++)
+ {
+ for (int col = 0; col < colsB; col++)
+ {
+ pC[row * colsB + col] = 0.f;
+ for (int inner = 0; inner < rowsB; inner++)
+ {
+ pC[row * colsB + col] += pA[row * colsA + inner] * pB[col + inner * colsB];
+ }
+ }
+ }
+}
-void btMultiBody::calcAccelerationDeltas(const btScalar *force, btScalar *output,
+void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output,
btAlignedObjectArray<btScalar> &scratch_r, btAlignedObjectArray<btVector3> &scratch_v) const
{
// Temporary matrices/vectors -- use scratch space from caller
// so that we don't have to keep reallocating every frame
- int num_links = getNumLinks();
- scratch_r.resize(num_links);
- scratch_v.resize(4*num_links + 4);
- btScalar * r_ptr = num_links == 0 ? 0 : &scratch_r[0];
+
+ int num_links = getNumLinks();
+ scratch_r.resize(m_dofCount);
+ scratch_v.resize(4*num_links + 4);
+
+ btScalar * r_ptr = m_dofCount ? &scratch_r[0] : 0;
btVector3 * v_ptr = &scratch_v[0];
-
+
// zhat_i^A (scratch space)
- btVector3 * zero_acc_top_angular = v_ptr; v_ptr += num_links + 1;
- btVector3 * zero_acc_bottom_linear = v_ptr; v_ptr += num_links + 1;
+ btSpatialForceVector * zeroAccSpatFrc = (btSpatialForceVector *)v_ptr;
+ v_ptr += num_links * 2 + 2;
// rot_from_parent (cached from calcAccelerations)
- const btMatrix3x3 * rot_from_parent = &matrix_buf[0];
+ const btMatrix3x3 * rot_from_parent = &m_matrixBuf[0];
// hhat (cached), accel (scratch)
- const btVector3 * h_top = num_links > 0 ? &vector_buf[0] : 0;
- const btVector3 * h_bottom = num_links > 0 ? &vector_buf[num_links] : 0;
- btVector3 * accel_top = v_ptr; v_ptr += num_links + 1;
- btVector3 * accel_bottom = v_ptr; v_ptr += num_links + 1;
-
- // Y_i (scratch), D_i (cached)
- btScalar * Y = r_ptr; r_ptr += num_links;
- const btScalar * D = num_links > 0 ? &m_real_buf[6 + num_links] : 0;
+ // hhat is NOT stored for the base (but ahat is)
+ const btSpatialForceVector * h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0);
+ btSpatialMotionVector * spatAcc = (btSpatialMotionVector *)v_ptr;
+ v_ptr += num_links * 2 + 2;
+
+ // Y_i (scratch), invD_i (cached)
+ const btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
+ btScalar * Y = r_ptr;
+ ////////////////
+ //aux variables
+ static btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies
+ static btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel)
+ static btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough
+ static btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors
+ static btSpatialTransformationMatrix fromParent;
+ /////////////////
- btAssert(num_links == 0 || r_ptr - &scratch_r[0] == scratch_r.size());
- btAssert(v_ptr - &scratch_v[0] == scratch_v.size());
-
-
-
// First 'upward' loop.
// Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
-
- btVector3 input_force(force[3],force[4],force[5]);
- btVector3 input_torque(force[0],force[1],force[2]);
-
- // Fill in zero_acc
+
+ // Fill in zero_acc
// -- set to force/torque on the base, zero otherwise
- if (fixed_base)
+ if (m_fixedBase)
{
- zero_acc_top_angular[0] = zero_acc_bottom_linear[0] = btVector3(0,0,0);
+ zeroAccSpatFrc[0].setZero();
} else
- {
- zero_acc_top_angular[0] = - (rot_from_parent[0] * input_force);
- zero_acc_bottom_linear[0] = - (rot_from_parent[0] * input_torque);
+ {
+ //test forces
+ fromParent.m_rotMat = rot_from_parent[0];
+ fromParent.transformRotationOnly(btSpatialForceVector(-force[0],-force[1],-force[2], -force[3],-force[4],-force[5]), zeroAccSpatFrc[0]);
}
for (int i = 0; i < num_links; ++i)
{
- zero_acc_top_angular[i+1] = zero_acc_bottom_linear[i+1] = btVector3(0,0,0);
- }
+ zeroAccSpatFrc[i+1].setZero();
+ }
- // 'Downward' loop.
- for (int i = num_links - 1; i >= 0; --i)
+ // 'Downward' loop.
+ // (part of TreeForwardDynamics in Mirtich.)
+ for (int i = num_links - 1; i >= 0; --i)
{
+ const int parent = m_links[i].m_parent;
+ fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector;
- Y[i] = - SpatialDotProduct(links[i].axis_top, links[i].axis_bottom, zero_acc_top_angular[i+1], zero_acc_bottom_linear[i+1]);
- Y[i] += force[6 + i]; // add joint torque
-
- const int parent = links[i].parent;
-
- // Zp += pXi * (Zi + hi*Yi/Di)
- btVector3 in_top, in_bottom, out_top, out_bottom;
- const btScalar Y_over_D = Y[i] / D[i];
- in_top = zero_acc_top_angular[i+1] + Y_over_D * h_top[i];
- in_bottom = zero_acc_bottom_linear[i+1] + Y_over_D * h_bottom[i];
- InverseSpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
- in_top, in_bottom, out_top, out_bottom);
- zero_acc_top_angular[parent+1] += out_top;
- zero_acc_bottom_linear[parent+1] += out_bottom;
- }
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ Y[m_links[i].m_dofOffset + dof] = force[6 + m_links[i].m_dofOffset + dof]
+ - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i+1])
+ ;
+ }
- // ptr to the joint accel part of the output
+ btVector3 in_top, in_bottom, out_top, out_bottom;
+ const btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset];
+
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ invD_times_Y[dof] = 0.f;
+
+ for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
+ {
+ invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2];
+ }
+ }
+
+ // Zp += pXi * (Zi + hi*Yi/Di)
+ spatForceVecTemps[0] = zeroAccSpatFrc[i+1];
+
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ {
+ const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
+ //
+ spatForceVecTemps[0] += hDof * invD_times_Y[dof];
+ }
+
+
+ fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]);
+
+ zeroAccSpatFrc[parent+1] += spatForceVecTemps[1];
+ }
+
+ // ptr to the joint accel part of the output
btScalar * joint_accel = output + 6;
+
// Second 'upward' loop
- if (fixed_base)
+ // (part of TreeForwardDynamics in Mirtich)
+
+ if (m_fixedBase)
{
- accel_top[0] = accel_bottom[0] = btVector3(0,0,0);
- } else
+ spatAcc[0].setZero();
+ }
+ else
+ {
+ solveImatrix(zeroAccSpatFrc[0], result);
+ spatAcc[0] = -result;
+
+ }
+
+ // now do the loop over the m_links
+ for (int i = 0; i < num_links; ++i)
{
- btVector3 rhs_top (zero_acc_top_angular[0][0], zero_acc_top_angular[0][1], zero_acc_top_angular[0][2]);
- btVector3 rhs_bot (zero_acc_bottom_linear[0][0], zero_acc_bottom_linear[0][1], zero_acc_bottom_linear[0][2]);
+ const int parent = m_links[i].m_parent;
+ fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector;
+
+ fromParent.transform(spatAcc[parent+1], spatAcc[i+1]);
- float result[6];
- solveImatrix(rhs_top,rhs_bot, result);
- // printf("result=%f,%f,%f,%f,%f,%f\n",result[0],result[0],result[0],result[0],result[0],result[0]);
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++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);
+ }
- for (int i = 0; i < 3; ++i) {
- accel_top[0][i] = -result[i];
- accel_bottom[0][i] = -result[i+3];
- }
+ const btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset];
+ mulMatrix(const_cast<btScalar*>(invDi), Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
- }
-
- // now do the loop over the links
- for (int i = 0; i < num_links; ++i) {
- const int parent = links[i].parent;
- SpatialTransform(rot_from_parent[i+1], links[i].cached_r_vector,
- accel_top[parent+1], accel_bottom[parent+1],
- accel_top[i+1], accel_bottom[i+1]);
- joint_accel[i] = (Y[i] - SpatialDotProduct(h_top[i], h_bottom[i], accel_top[i+1], accel_bottom[i+1])) / D[i];
- accel_top[i+1] += joint_accel[i] * links[i].axis_top;
- accel_bottom[i+1] += joint_accel[i] * links[i].axis_bottom;
+ for(int dof = 0; dof < m_links[i].m_dofCount; ++dof)
+ spatAcc[i+1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
}
// transform base accelerations back to the world frame.
btVector3 omegadot_out;
- omegadot_out = rot_from_parent[0].transpose() * accel_top[0];
+ 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;
- vdot_out = rot_from_parent[0].transpose() * accel_bottom[0];
-
+ vdot_out = rot_from_parent[0].transpose() * spatAcc[0].getLinear();
output[3] = vdot_out[0];
output[4] = vdot_out[1];
output[5] = vdot_out[2];
+
+ /////////////////
+ //printf("delta = [");
+ //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
+ // printf("%.2f ", output[dof]);
+ //printf("]\n");
+ /////////////////
}
-void btMultiBody::stepPositions(btScalar dt)
-{
+
+
+
+void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd)
+{
int num_links = getNumLinks();
// step position by adding dt * velocity
- btVector3 v = getBaseVel();
- base_pos += dt * v;
-
- // "exponential map" method for the rotation
- btVector3 base_omega = getBaseOmega();
- const btScalar omega_norm = base_omega.norm();
- const btScalar omega_times_dt = omega_norm * dt;
- const btScalar SMALL_ROTATION_ANGLE = 0.02f; // Theoretically this should be ~ pow(FLT_EPSILON,0.25) which is ~ 0.0156
- if (fabs(omega_times_dt) < SMALL_ROTATION_ANGLE)
+ //btVector3 v = getBaseVel();
+ //m_basePos += dt * v;
+ //
+ btScalar *pBasePos = (pq ? &pq[4] : m_basePos);
+ btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
+ //
+ pBasePos[0] += dt * pBaseVel[0];
+ pBasePos[1] += dt * pBaseVel[1];
+ pBasePos[2] += dt * pBaseVel[2];
+
+ ///////////////////////////////
+ //local functor for quaternion integration (to avoid error prone redundancy)
+ struct
{
- const btScalar xsq = omega_times_dt * omega_times_dt; // |omega|^2 * dt^2
- const btScalar sin_term = dt * (xsq / 48.0f - 0.5f); // -sin(0.5*dt*|omega|) / |omega|
- const btScalar cos_term = 1.0f - xsq / 8.0f; // cos(0.5*dt*|omega|)
- base_quat = base_quat * btQuaternion(sin_term * base_omega[0],sin_term * base_omega[1],sin_term * base_omega[2],cos_term);
- } else
+ //"exponential map" based on btTransformUtil::integrateTransform(..)
+ void operator() (const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt)
+ {
+ //baseBody => quat is alias and omega is global coor
+ //!baseBody => quat is alibi and omega is local coor
+
+ btVector3 axis;
+ btVector3 angvel;
+
+ if(!baseBody)
+ angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok
+ else
+ angvel = omega;
+
+ btScalar fAngle = angvel.length();
+ //limit the angular motion
+ if (fAngle * dt > ANGULAR_MOTION_THRESHOLD)
+ {
+ fAngle = btScalar(0.5)*SIMD_HALF_PI / dt;
+ }
+
+ if ( fAngle < btScalar(0.001) )
+ {
+ // use Taylor's expansions of sync function
+ axis = angvel*( btScalar(0.5)*dt-(dt*dt*dt)*(btScalar(0.020833333333))*fAngle*fAngle );
+ }
+ else
+ {
+ // sync(fAngle) = sin(c*fAngle)/t
+ axis = angvel*( btSin(btScalar(0.5)*fAngle*dt)/fAngle );
+ }
+
+ if(!baseBody)
+ quat = btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat;
+ else
+ quat = quat * btQuaternion(-axis.x(),-axis.y(),-axis.z(),btCos( fAngle*dt*btScalar(0.5) ));
+ //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse();
+
+ quat.normalize();
+ }
+ } pQuatUpdateFun;
+ ///////////////////////////////
+
+ //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
+ //
+ btScalar *pBaseQuat = pq ? pq : m_baseQuat;
+ btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
+ //
+ static btQuaternion baseQuat; baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
+ static btVector3 baseOmega; baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
+ pQuatUpdateFun(baseOmega, baseQuat, true, dt);
+ pBaseQuat[0] = baseQuat.x();
+ pBaseQuat[1] = baseQuat.y();
+ pBaseQuat[2] = baseQuat.z();
+ pBaseQuat[3] = baseQuat.w();
+
+
+ //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z());
+ //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z());
+ //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w());
+
+ if(pq)
+ pq += 7;
+ if(pqd)
+ pqd += 6;
+
+ // Finally we can update m_jointPos for each of the m_links
+ for (int i = 0; i < num_links; ++i)
{
- base_quat = base_quat * btQuaternion(base_omega / omega_norm,-omega_times_dt);
- }
+ btScalar *pJointPos = (pq ? pq : &m_links[i].m_jointPos[0]);
+ btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i));
- // Make sure the quaternion represents a valid rotation.
- // (Not strictly necessary, but helps prevent any round-off errors from building up.)
- base_quat.normalize();
+ switch(m_links[i].m_jointType)
+ {
+ case btMultibodyLink::ePrismatic:
+ case btMultibodyLink::eRevolute:
+ {
+ btScalar jointVel = pJointVel[0];
+ pJointPos[0] += dt * jointVel;
+ break;
+ }
+ case btMultibodyLink::eSpherical:
+ {
+ static btVector3 jointVel; jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
+ static btQuaternion jointOri; jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
+ pQuatUpdateFun(jointVel, jointOri, false, dt);
+ pJointPos[0] = jointOri.x(); pJointPos[1] = jointOri.y(); pJointPos[2] = jointOri.z(); pJointPos[3] = jointOri.w();
+ break;
+ }
+ case btMultibodyLink::ePlanar:
+ {
+ pJointPos[0] += dt * getJointVelMultiDof(i)[0];
+
+ btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
+ btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
+ pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
+ pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
+
+ break;
+ }
+ default:
+ {
+ }
- // Finally we can update joint_pos for each of the links
- for (int i = 0; i < num_links; ++i)
- {
- float jointVel = getJointVel(i);
- links[i].joint_pos += dt * jointVel;
- links[i].updateCache();
+ }
+
+ m_links[i].updateCacheMultiDof(pq);
+
+ if(pq)
+ pq += m_links[i].m_posVarCount;
+ if(pqd)
+ pqd += m_links[i].m_dofCount;
}
}
-void btMultiBody::fillContactJacobian(int link,
+void btMultiBody::fillConstraintJacobianMultiDof(int link,
const btVector3 &contact_point,
- const btVector3 &normal,
+ const btVector3 &normal_ang,
+ const btVector3 &normal_lin,
btScalar *jac,
btAlignedObjectArray<btScalar> &scratch_r,
btAlignedObjectArray<btVector3> &scratch_v,
@@ -899,46 +1599,53 @@ void btMultiBody::fillContactJacobian(int link,
{
// temporary space
int num_links = getNumLinks();
- scratch_v.resize(2*num_links + 2);
+ int m_dofCount = getNumDofs();
+ scratch_v.resize(3*num_links + 3); //(num_links + base) offsets + (num_links + base) normals_lin + (num_links + base) normals_ang
scratch_m.resize(num_links + 1);
btVector3 * v_ptr = &scratch_v[0];
- btVector3 * p_minus_com = v_ptr; v_ptr += num_links + 1;
- btVector3 * n_local = v_ptr; v_ptr += num_links + 1;
+ btVector3 * p_minus_com_local = v_ptr; v_ptr += num_links + 1;
+ btVector3 * n_local_lin = v_ptr; v_ptr += num_links + 1;
+ btVector3 * n_local_ang = v_ptr; v_ptr += num_links + 1;
btAssert(v_ptr - &scratch_v[0] == scratch_v.size());
- scratch_r.resize(num_links);
- btScalar * results = num_links > 0 ? &scratch_r[0] : 0;
+ scratch_r.resize(m_dofCount);
+ btScalar * results = m_dofCount > 0 ? &scratch_r[0] : 0;
btMatrix3x3 * rot_from_world = &scratch_m[0];
- const btVector3 p_minus_com_world = contact_point - base_pos;
+ const btVector3 p_minus_com_world = contact_point - m_basePos;
+ const btVector3 &normal_lin_world = normal_lin; //convenience
+ const btVector3 &normal_ang_world = normal_ang;
- rot_from_world[0] = btMatrix3x3(base_quat);
-
- p_minus_com[0] = rot_from_world[0] * p_minus_com_world;
- n_local[0] = rot_from_world[0] * normal;
+ rot_from_world[0] = btMatrix3x3(m_baseQuat);
// omega coeffients first.
- btVector3 omega_coeffs;
- omega_coeffs = p_minus_com_world.cross(normal);
- jac[0] = omega_coeffs[0];
- jac[1] = omega_coeffs[1];
- jac[2] = omega_coeffs[2];
+ btVector3 omega_coeffs_world;
+ omega_coeffs_world = p_minus_com_world.cross(normal_lin_world);
+ jac[0] = omega_coeffs_world[0] + normal_ang_world[0];
+ jac[1] = omega_coeffs_world[1] + normal_ang_world[1];
+ jac[2] = omega_coeffs_world[2] + normal_ang_world[2];
// then v coefficients
- jac[3] = normal[0];
- jac[4] = normal[1];
- jac[5] = normal[2];
+ jac[3] = normal_lin_world[0];
+ jac[4] = normal_lin_world[1];
+ jac[5] = normal_lin_world[2];
+
+ //create link-local versions of p_minus_com and normal
+ p_minus_com_local[0] = rot_from_world[0] * p_minus_com_world;
+ n_local_lin[0] = rot_from_world[0] * normal_lin_world;
+ n_local_ang[0] = rot_from_world[0] * normal_ang_world;
// Set remaining jac values to zero for now.
- for (int i = 6; i < 6 + num_links; ++i) {
+ for (int i = 6; i < 6 + m_dofCount; ++i)
+ {
jac[i] = 0;
}
// Qdot coefficients, if necessary.
if (num_links > 0 && link > -1) {
- // TODO: speed this up -- don't calculate for links we don't need.
+ // TODO: speed this up -- don't calculate for m_links we don't need.
// (Also, we are making 3 separate calls to this function, for the normal & the 2 friction directions,
// which is resulting in repeated work being done...)
@@ -946,64 +1653,292 @@ void btMultiBody::fillContactJacobian(int link,
for (int i = 0; i < num_links; ++i) {
// transform to local frame
- const int parent = links[i].parent;
- const btMatrix3x3 mtx(links[i].cached_rot_parent_to_this);
+ const int parent = m_links[i].m_parent;
+ const btMatrix3x3 mtx(m_links[i].m_cachedRotParentToThis);
rot_from_world[i+1] = mtx * rot_from_world[parent+1];
- n_local[i+1] = mtx * n_local[parent+1];
- p_minus_com[i+1] = mtx * p_minus_com[parent+1] - links[i].cached_r_vector;
-
- // calculate the jacobian entry
- if (links[i].is_revolute) {
- results[i] = n_local[i+1].dot( links[i].axis_top.cross(p_minus_com[i+1]) + links[i].axis_bottom );
- } else {
- results[i] = n_local[i+1].dot( links[i].axis_bottom );
- }
+ n_local_lin[i+1] = mtx * n_local_lin[parent+1];
+ n_local_ang[i+1] = mtx * n_local_ang[parent+1];
+ p_minus_com_local[i+1] = mtx * p_minus_com_local[parent+1] - m_links[i].m_cachedRVector;
+
+ // calculate the jacobian entry
+ switch(m_links[i].m_jointType)
+ {
+ case btMultibodyLink::eRevolute:
+ {
+ results[m_links[i].m_dofOffset] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(0));
+ results[m_links[i].m_dofOffset] += n_local_ang[i+1].dot(m_links[i].getAxisTop(0));
+ break;
+ }
+ case btMultibodyLink::ePrismatic:
+ {
+ results[m_links[i].m_dofOffset] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(0));
+ break;
+ }
+ case btMultibodyLink::eSpherical:
+ {
+ results[m_links[i].m_dofOffset + 0] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(0));
+ results[m_links[i].m_dofOffset + 1] = n_local_lin[i+1].dot(m_links[i].getAxisTop(1).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(1));
+ results[m_links[i].m_dofOffset + 2] = n_local_lin[i+1].dot(m_links[i].getAxisTop(2).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(2));
+
+ results[m_links[i].m_dofOffset + 0] += n_local_ang[i+1].dot(m_links[i].getAxisTop(0));
+ results[m_links[i].m_dofOffset + 1] += n_local_ang[i+1].dot(m_links[i].getAxisTop(1));
+ results[m_links[i].m_dofOffset + 2] += n_local_ang[i+1].dot(m_links[i].getAxisTop(2));
+
+ break;
+ }
+ case btMultibodyLink::ePlanar:
+ {
+ results[m_links[i].m_dofOffset + 0] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]));// + m_links[i].getAxisBottom(0));
+ results[m_links[i].m_dofOffset + 1] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(1));
+ results[m_links[i].m_dofOffset + 2] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(2));
+
+ break;
+ }
+ default:
+ {
+ }
+ }
+
}
// Now copy through to output.
- while (link != -1) {
- jac[6 + link] = results[link];
- link = links[link].parent;
+ //printf("jac[%d] = ", link);
+ while (link != -1)
+ {
+ for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
+ {
+ jac[6 + m_links[link].m_dofOffset + dof] = results[m_links[link].m_dofOffset + dof];
+ //printf("%.2f\t", jac[6 + m_links[link].m_dofOffset + dof]);
+ }
+
+ link = m_links[link].m_parent;
}
+ //printf("]\n");
}
}
+
void btMultiBody::wakeUp()
{
- awake = true;
+ m_awake = true;
}
void btMultiBody::goToSleep()
{
- awake = false;
+ m_awake = false;
}
void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep)
{
- int num_links = getNumLinks();
extern bool gDisableDeactivation;
- if (!can_sleep || gDisableDeactivation)
+ if (!m_canSleep || gDisableDeactivation)
{
- awake = true;
- sleep_timer = 0;
+ m_awake = true;
+ m_sleepTimer = 0;
return;
}
// motion is computed as omega^2 + v^2 + (sum of squares of joint velocities)
btScalar motion = 0;
- for (int i = 0; i < 6 + num_links; ++i) {
- motion += m_real_buf[i] * m_real_buf[i];
- }
+ {
+ for (int i = 0; i < 6 + m_dofCount; ++i)
+ motion += m_realBuf[i] * m_realBuf[i];
+ }
+
if (motion < SLEEP_EPSILON) {
- sleep_timer += timestep;
- if (sleep_timer > SLEEP_TIMEOUT) {
+ m_sleepTimer += timestep;
+ if (m_sleepTimer > SLEEP_TIMEOUT) {
goToSleep();
}
} else {
- sleep_timer = 0;
- if (!awake)
+ m_sleepTimer = 0;
+ if (!m_awake)
wakeUp();
}
}
+
+
+void btMultiBody::forwardKinematics(btAlignedObjectArray<btQuaternion>& world_to_local,btAlignedObjectArray<btVector3>& local_origin)
+{
+
+ int num_links = getNumLinks();
+
+ // Cached 3x3 rotation matrices from parent frame to this frame.
+ btMatrix3x3* rot_from_parent =(btMatrix3x3 *) &m_matrixBuf[0];
+
+ rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!?
+
+ for (int i = 0; i < num_links; ++i)
+ {
+ rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis);
+ }
+
+ int nLinks = getNumLinks();
+ ///base + num m_links
+ world_to_local.resize(nLinks+1);
+ local_origin.resize(nLinks+1);
+
+ world_to_local[0] = getWorldToBaseRot();
+ local_origin[0] = getBasePos();
+
+ for (int k=0;k<getNumLinks();k++)
+ {
+ const int parent = getParent(k);
+ world_to_local[k+1] = getParentToLocalRot(k) * world_to_local[parent+1];
+ local_origin[k+1] = local_origin[parent+1] + (quatRotate(world_to_local[k+1].inverse() , getRVector(k)));
+ }
+
+ for (int link=0;link<getNumLinks();link++)
+ {
+ int index = link+1;
+
+ btVector3 posr = local_origin[index];
+ btScalar quat[4]={-world_to_local[index].x(),-world_to_local[index].y(),-world_to_local[index].z(),world_to_local[index].w()};
+ btTransform tr;
+ tr.setIdentity();
+ tr.setOrigin(posr);
+ tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3]));
+ getLink(link).m_cachedWorldTransform = tr;
+
+ }
+
+}
+
+void btMultiBody::updateCollisionObjectWorldTransforms(btAlignedObjectArray<btQuaternion>& world_to_local,btAlignedObjectArray<btVector3>& local_origin)
+{
+ world_to_local.resize(getNumLinks()+1);
+ local_origin.resize(getNumLinks()+1);
+
+ world_to_local[0] = getWorldToBaseRot();
+ local_origin[0] = getBasePos();
+
+ if (getBaseCollider())
+ {
+ btVector3 posr = local_origin[0];
+ // float pos[4]={posr.x(),posr.y(),posr.z(),1};
+ btScalar quat[4]={-world_to_local[0].x(),-world_to_local[0].y(),-world_to_local[0].z(),world_to_local[0].w()};
+ btTransform tr;
+ tr.setIdentity();
+ tr.setOrigin(posr);
+ tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3]));
+
+ getBaseCollider()->setWorldTransform(tr);
+
+ }
+
+ for (int k=0;k<getNumLinks();k++)
+ {
+ const int parent = getParent(k);
+ world_to_local[k+1] = getParentToLocalRot(k) * world_to_local[parent+1];
+ local_origin[k+1] = local_origin[parent+1] + (quatRotate(world_to_local[k+1].inverse() , getRVector(k)));
+ }
+
+
+ for (int m=0;m<getNumLinks();m++)
+ {
+ btMultiBodyLinkCollider* col = getLink(m).m_collider;
+ if (col)
+ {
+ int link = col->m_link;
+ btAssert(link == m);
+
+ int index = link+1;
+
+ btVector3 posr = local_origin[index];
+ // float pos[4]={posr.x(),posr.y(),posr.z(),1};
+ btScalar quat[4]={-world_to_local[index].x(),-world_to_local[index].y(),-world_to_local[index].z(),world_to_local[index].w()};
+ btTransform tr;
+ tr.setIdentity();
+ tr.setOrigin(posr);
+ tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3]));
+
+ col->setWorldTransform(tr);
+ }
+ }
+}
+
+int btMultiBody::calculateSerializeBufferSize() const
+{
+ int sz = sizeof(btMultiBodyData);
+ return sz;
+}
+
+ ///fills the dataBuffer and returns the struct name (and 0 on failure)
+const char* btMultiBody::serialize(void* dataBuffer, class btSerializer* serializer) const
+{
+ btMultiBodyData* mbd = (btMultiBodyData*) dataBuffer;
+ getBaseWorldTransform().serialize(mbd->m_baseWorldTransform);
+ mbd->m_baseMass = this->getBaseMass();
+ getBaseInertia().serialize(mbd->m_baseInertia);
+ {
+ char* name = (char*) serializer->findNameForPointer(m_baseName);
+ mbd->m_baseName = (char*)serializer->getUniquePointer(name);
+ if (mbd->m_baseName)
+ {
+ serializer->serializeName(name);
+ }
+ }
+ mbd->m_numLinks = this->getNumLinks();
+ if (mbd->m_numLinks)
+ {
+ int sz = sizeof(btMultiBodyLinkData);
+ int numElem = mbd->m_numLinks;
+ btChunk* chunk = serializer->allocate(sz,numElem);
+ btMultiBodyLinkData* memPtr = (btMultiBodyLinkData*)chunk->m_oldPtr;
+ for (int i=0;i<numElem;i++,memPtr++)
+ {
+
+ memPtr->m_jointType = getLink(i).m_jointType;
+ memPtr->m_dofCount = getLink(i).m_dofCount;
+ memPtr->m_posVarCount = getLink(i).m_posVarCount;
+
+ getLink(i).m_inertiaLocal.serialize(memPtr->m_linkInertia);
+ memPtr->m_linkMass = getLink(i).m_mass;
+ memPtr->m_parentIndex = getLink(i).m_parent;
+ getLink(i).m_eVector.serialize(memPtr->m_parentComToThisComOffset);
+ getLink(i).m_dVector.serialize(memPtr->m_thisPivotToThisComOffset);
+ getLink(i).m_zeroRotParentToThis.serialize(memPtr->m_zeroRotParentToThis);
+ btAssert(memPtr->m_dofCount<=3);
+ for (int dof = 0;dof<getLink(i).m_dofCount;dof++)
+ {
+ getLink(i).getAxisBottom(dof).serialize(memPtr->m_jointAxisBottom[dof]);
+ getLink(i).getAxisTop(dof).serialize(memPtr->m_jointAxisTop[dof]);
+
+ memPtr->m_jointTorque[dof] = getLink(i).m_jointTorque[dof];
+ memPtr->m_jointVel[dof] = getJointVelMultiDof(i)[dof];
+
+ }
+ int numPosVar = getLink(i).m_posVarCount;
+ for (int posvar = 0; posvar < numPosVar;posvar++)
+ {
+ memPtr->m_jointPos[posvar] = getLink(i).m_jointPos[posvar];
+ }
+
+
+ {
+ char* name = (char*) serializer->findNameForPointer(m_links[i].m_linkName);
+ memPtr->m_linkName = (char*)serializer->getUniquePointer(name);
+ if (memPtr->m_linkName)
+ {
+ serializer->serializeName(name);
+ }
+ }
+ {
+ char* name = (char*) serializer->findNameForPointer(m_links[i].m_jointName);
+ memPtr->m_jointName = (char*)serializer->getUniquePointer(name);
+ if (memPtr->m_jointName)
+ {
+ serializer->serializeName(name);
+ }
+ }
+ memPtr->m_linkCollider = (btCollisionObjectData*)serializer->getUniquePointer(getLink(i).m_collider);
+
+ }
+ serializer->finalizeChunk(chunk,btMultiBodyLinkDataName,BT_ARRAY_CODE,(void*) &m_links[0]);
+ }
+ mbd->m_links = mbd->m_numLinks? (btMultiBodyLinkData*) serializer->getUniquePointer((void*)&m_links[0]):0;
+
+ return btMultiBodyDataName;
+}
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h
index 7177bebbff5..8fbe6cda827 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h
@@ -6,7 +6,8 @@
*
* COPYRIGHT:
* Copyright (C) Stephen Thompson, <stephen@solarflare.org.uk>, 2011-2013
- * Portions written By Erwin Coumans: replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
+ * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
+ * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements
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.
@@ -31,10 +32,23 @@
#include "LinearMath/btAlignedObjectArray.h"
+///serialization data, don't change them if you are not familiar with the details of the serialization mechanisms
+#ifdef BT_USE_DOUBLE_PRECISION
+ #define btMultiBodyData btMultiBodyDoubleData
+ #define btMultiBodyDataName "btMultiBodyDoubleData"
+ #define btMultiBodyLinkData btMultiBodyLinkDoubleData
+ #define btMultiBodyLinkDataName "btMultiBodyLinkDoubleData"
+#else
+ #define btMultiBodyData btMultiBodyFloatData
+ #define btMultiBodyDataName "btMultiBodyFloatData"
+ #define btMultiBodyLinkData btMultiBodyLinkFloatData
+ #define btMultiBodyLinkDataName "btMultiBodyLinkFloatData"
+#endif //BT_USE_DOUBLE_PRECISION
+
#include "btMultiBodyLink.h"
class btMultiBodyLinkCollider;
-class btMultiBody
+ATTRIBUTE_ALIGNED16(class) btMultiBody
{
public:
@@ -45,42 +59,71 @@ public:
// initialization
//
- btMultiBody(int n_links, // NOT including the base
- btScalar mass, // mass of base
- const btVector3 &inertia, // inertia of base, in base frame; assumed diagonal
- bool fixed_base_, // whether the base is fixed (true) or can move (false)
- bool can_sleep_);
+ btMultiBody(int n_links, // NOT including the base
+ btScalar mass, // mass of base
+ const btVector3 &inertia, // inertia of base, in base frame; assumed diagonal
+ bool fixedBase, // whether the base is fixed (true) or can move (false)
+ bool canSleep, bool deprecatedMultiDof=true);
+
- ~btMultiBody();
+ virtual ~btMultiBody();
- void setupPrismatic(int i, // 0 to num_links-1
- btScalar mass,
- const btVector3 &inertia, // in my frame; assumed diagonal
- int parent,
- const btQuaternion &rot_parent_to_this, // rotate points in parent frame to my frame.
- const btVector3 &joint_axis, // in my frame
- const btVector3 &r_vector_when_q_zero, // vector from parent COM to my COM, in my frame, when q = 0.
- bool disableParentCollision=false
- );
-
- void setupRevolute(int i, // 0 to num_links-1
+ //note: fixed link collision with parent is always disabled
+ void setupFixed(int linkIndex,
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &parentComToThisPivotOffset,
+ const btVector3 &thisPivotToThisComOffset, bool deprecatedDisableParentCollision=true);
+
+
+ void setupPrismatic(int i,
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis,
+ const btVector3 &jointAxis,
+ const btVector3 &parentComToThisPivotOffset,
+ const btVector3 &thisPivotToThisComOffset,
+ bool disableParentCollision);
+
+ void setupRevolute(int linkIndex, // 0 to num_links-1
btScalar mass,
const btVector3 &inertia,
- int parent,
- const btQuaternion &zero_rot_parent_to_this, // rotate points in parent frame to this frame, when q = 0
- const btVector3 &joint_axis, // in my frame
- const btVector3 &parent_axis_position, // vector from parent COM to joint axis, in PARENT frame
- const btVector3 &my_axis_position, // vector from joint axis to my COM, in MY frame
+ int parentIndex,
+ const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0
+ const btVector3 &jointAxis, // in my frame
+ const btVector3 &parentComToThisPivotOffset, // vector from parent COM to joint axis, in PARENT frame
+ const btVector3 &thisPivotToThisComOffset, // vector from joint axis to my COM, in MY frame
bool disableParentCollision=false);
+
+ void setupSpherical(int linkIndex, // 0 to num_links-1
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0
+ const btVector3 &parentComToThisPivotOffset, // vector from parent COM to joint axis, in PARENT frame
+ const btVector3 &thisPivotToThisComOffset, // vector from joint axis to my COM, in MY frame
+ bool disableParentCollision=false);
+
+ void setupPlanar(int i, // 0 to num_links-1
+ btScalar mass,
+ const btVector3 &inertia,
+ int parent,
+ const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0
+ const btVector3 &rotationAxis,
+ const btVector3 &parentComToThisComOffset, // vector from parent COM to this COM, in PARENT frame
+ bool disableParentCollision=false);
const btMultibodyLink& getLink(int index) const
{
- return links[index];
+ return m_links[index];
}
btMultibodyLink& getLink(int index)
{
- return links[index];
+ return m_links[index];
}
@@ -106,69 +149,98 @@ public:
//
- // get number of links, masses, moments of inertia
+ // get number of m_links, masses, moments of inertia
//
- int getNumLinks() const { return links.size(); }
- btScalar getBaseMass() const { return base_mass; }
- const btVector3 & getBaseInertia() const { return base_inertia; }
+ int getNumLinks() const { return m_links.size(); }
+ int getNumDofs() const { return m_dofCount; }
+ int getNumPosVars() const { return m_posVarCnt; }
+ btScalar getBaseMass() const { return m_baseMass; }
+ const btVector3 & getBaseInertia() const { return m_baseInertia; }
btScalar getLinkMass(int i) const;
const btVector3 & getLinkInertia(int i) const;
+
//
// change mass (incomplete: can only change base mass and inertia at present)
//
- void setBaseMass(btScalar mass) { base_mass = mass; }
- void setBaseInertia(const btVector3 &inertia) { base_inertia = inertia; }
+ void setBaseMass(btScalar mass) { m_baseMass = mass; }
+ void setBaseInertia(const btVector3 &inertia) { m_baseInertia = inertia; }
//
// get/set pos/vel/rot/omega for the base link
//
- const btVector3 & getBasePos() const { return base_pos; } // in world frame
+ const btVector3 & getBasePos() const { return m_basePos; } // in world frame
const btVector3 getBaseVel() const
{
- return btVector3(m_real_buf[3],m_real_buf[4],m_real_buf[5]);
+ return btVector3(m_realBuf[3],m_realBuf[4],m_realBuf[5]);
} // in world frame
const btQuaternion & getWorldToBaseRot() const
{
- return base_quat;
+ return m_baseQuat;
} // rotates world vectors into base frame
- btVector3 getBaseOmega() const { return btVector3(m_real_buf[0],m_real_buf[1],m_real_buf[2]); } // in world frame
+ btVector3 getBaseOmega() const { return btVector3(m_realBuf[0],m_realBuf[1],m_realBuf[2]); } // in world frame
void setBasePos(const btVector3 &pos)
{
- base_pos = pos;
+ m_basePos = pos;
+ }
+
+ void setBaseWorldTransform(const btTransform& tr)
+ {
+ setBasePos(tr.getOrigin());
+ setWorldToBaseRot(tr.getRotation().inverse());
+
+ }
+
+ btTransform getBaseWorldTransform() const
+ {
+ btTransform tr;
+ tr.setOrigin(getBasePos());
+ tr.setRotation(getWorldToBaseRot().inverse());
+ return tr;
}
+
void setBaseVel(const btVector3 &vel)
{
- m_real_buf[3]=vel[0]; m_real_buf[4]=vel[1]; m_real_buf[5]=vel[2];
+ m_realBuf[3]=vel[0]; m_realBuf[4]=vel[1]; m_realBuf[5]=vel[2];
}
void setWorldToBaseRot(const btQuaternion &rot)
{
- base_quat = rot;
+ m_baseQuat = rot; //m_baseQuat asumed to ba alias!?
}
void setBaseOmega(const btVector3 &omega)
{
- m_real_buf[0]=omega[0];
- m_real_buf[1]=omega[1];
- m_real_buf[2]=omega[2];
+ m_realBuf[0]=omega[0];
+ m_realBuf[1]=omega[1];
+ m_realBuf[2]=omega[2];
}
//
- // get/set pos/vel for child links (i = 0 to num_links-1)
+ // get/set pos/vel for child m_links (i = 0 to num_links-1)
//
btScalar getJointPos(int i) const;
btScalar getJointVel(int i) const;
+ btScalar * getJointVelMultiDof(int i);
+ btScalar * getJointPosMultiDof(int i);
+
+ const btScalar * getJointVelMultiDof(int i) const ;
+ const btScalar * getJointPosMultiDof(int i) const ;
+
void setJointPos(int i, btScalar q);
void setJointVel(int i, btScalar qdot);
+ void setJointPosMultiDof(int i, btScalar *q);
+ void setJointVelMultiDof(int i, btScalar *qdot);
+
+
//
// direct access to velocities as a vector of 6 + num_links elements.
@@ -176,7 +248,7 @@ public:
//
const btScalar * getVelocityVector() const
{
- return &m_real_buf[0];
+ return &m_realBuf[0];
}
/* btScalar * getVelocityVector()
{
@@ -185,7 +257,7 @@ public:
*/
//
- // get the frames of reference (positions and orientations) of the child links
+ // get the frames of reference (positions and orientations) of the child m_links
// (i = 0 to num_links-1)
//
@@ -216,22 +288,37 @@ public:
//
void clearForcesAndTorques();
+ void clearConstraintForces();
+
void clearVelocities();
void addBaseForce(const btVector3 &f)
{
- base_force += f;
+ m_baseForce += f;
}
- void addBaseTorque(const btVector3 &t) { base_torque += t; }
+ void addBaseTorque(const btVector3 &t) { m_baseTorque += t; }
void addLinkForce(int i, const btVector3 &f);
void addLinkTorque(int i, const btVector3 &t);
- void addJointTorque(int i, btScalar Q);
- const btVector3 & getBaseForce() const { return base_force; }
- const btVector3 & getBaseTorque() const { return base_torque; }
+ void addBaseConstraintForce(const btVector3 &f)
+ {
+ m_baseConstraintForce += f;
+ }
+ void addBaseConstraintTorque(const btVector3 &t) { m_baseConstraintTorque += t; }
+ void addLinkConstraintForce(int i, const btVector3 &f);
+ void addLinkConstraintTorque(int i, const btVector3 &t);
+
+
+void addJointTorque(int i, btScalar Q);
+ void addJointTorqueMultiDof(int i, int dof, btScalar Q);
+ void addJointTorqueMultiDof(int i, const btScalar *Q);
+
+ const btVector3 & getBaseForce() const { return m_baseForce; }
+ const btVector3 & getBaseTorque() const { return m_baseTorque; }
const btVector3 & getLinkForce(int i) const;
const btVector3 & getLinkTorque(int i) const;
btScalar getJointTorque(int i) const;
+ btScalar * getJointTorqueMultiDof(int i);
//
@@ -250,62 +337,82 @@ public:
// improvement, at least on Windows (where dynamic memory
// allocation appears to be fairly slow).
//
- void stepVelocities(btScalar dt,
+
+
+ void computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt,
btAlignedObjectArray<btScalar> &scratch_r,
btAlignedObjectArray<btVector3> &scratch_v,
- btAlignedObjectArray<btMatrix3x3> &scratch_m);
+ btAlignedObjectArray<btMatrix3x3> &scratch_m,
+ bool isConstraintPass=false
+ );
- // calcAccelerationDeltas
+///stepVelocitiesMultiDof is deprecated, use computeAccelerationsArticulatedBodyAlgorithmMultiDof instead
+ void stepVelocitiesMultiDof(btScalar dt,
+ btAlignedObjectArray<btScalar> &scratch_r,
+ btAlignedObjectArray<btVector3> &scratch_v,
+ btAlignedObjectArray<btMatrix3x3> &scratch_m,
+ bool isConstraintPass=false)
+ {
+ computeAccelerationsArticulatedBodyAlgorithmMultiDof(dt,scratch_r,scratch_v,scratch_m,isConstraintPass);
+ }
+
+ // calcAccelerationDeltasMultiDof
// input: force vector (in same format as jacobian, i.e.:
// 3 torque values, 3 force values, num_links joint torque values)
// output: 3 omegadot values, 3 vdot values, num_links q_double_dot values
// (existing contents of output array are replaced)
- // stepVelocities must have been called first.
- void calcAccelerationDeltas(const btScalar *force, btScalar *output,
+ // calcAccelerationDeltasMultiDof must have been called first.
+ void calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output,
btAlignedObjectArray<btScalar> &scratch_r,
btAlignedObjectArray<btVector3> &scratch_v) const;
-
- // apply a delta-vee directly. used in sequential impulses code.
- void applyDeltaVee(const btScalar * delta_vee)
+
+
+ void applyDeltaVeeMultiDof2(const btScalar * delta_vee, btScalar multiplier)
{
-
- for (int i = 0; i < 6 + getNumLinks(); ++i)
- {
- m_real_buf[i] += delta_vee[i];
- }
-
- }
- void applyDeltaVee(const btScalar * delta_vee, btScalar multiplier)
+ for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
+ {
+ m_deltaV[dof] += delta_vee[dof] * multiplier;
+ }
+ }
+ void processDeltaVeeMultiDof2()
{
- btScalar sum = 0;
- for (int i = 0; i < 6 + getNumLinks(); ++i)
- {
- sum += delta_vee[i]*multiplier*delta_vee[i]*multiplier;
- }
- btScalar l = btSqrt(sum);
- /*
- static btScalar maxl = -1e30f;
- if (l>maxl)
- {
- maxl=l;
- // printf("maxl=%f\n",maxl);
- }
- */
- if (l>m_maxAppliedImpulse)
- {
-// printf("exceeds 100: l=%f\n",maxl);
- multiplier *= m_maxAppliedImpulse/l;
+ applyDeltaVeeMultiDof(&m_deltaV[0],1);
+
+ for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
+ {
+ m_deltaV[dof] = 0.f;
}
+ }
- for (int i = 0; i < 6 + getNumLinks(); ++i)
+ void applyDeltaVeeMultiDof(const btScalar * delta_vee, btScalar multiplier)
+ {
+ //for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
+ // printf("%.4f ", delta_vee[dof]*multiplier);
+ //printf("\n");
+
+ //btScalar sum = 0;
+ //for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
+ //{
+ // sum += delta_vee[dof]*multiplier*delta_vee[dof]*multiplier;
+ //}
+ //btScalar l = btSqrt(sum);
+
+ //if (l>m_maxAppliedImpulse)
+ //{
+ // multiplier *= m_maxAppliedImpulse/l;
+ //}
+
+ for (int dof = 0; dof < 6 + getNumDofs(); ++dof)
{
- sum += delta_vee[i]*multiplier*delta_vee[i]*multiplier;
- m_real_buf[i] += delta_vee[i] * multiplier;
+ m_realBuf[dof] += delta_vee[dof] * multiplier;
+ btClamp(m_realBuf[dof],-m_maxCoordinateVelocity,m_maxCoordinateVelocity);
}
}
+
+
// timestep the positions (given current velocities).
- void stepPositions(btScalar dt);
+ void stepPositionsMultiDof(btScalar dt, btScalar *pq = 0, btScalar *pqd = 0);
//
@@ -315,12 +422,24 @@ public:
// This routine fills out a contact constraint jacobian for this body.
// the 'normal' supplied must be -n for body1 or +n for body2 of the contact.
// 'normal' & 'contact_point' are both given in world coordinates.
- void fillContactJacobian(int link,
+
+ void fillContactJacobianMultiDof(int link,
const btVector3 &contact_point,
const btVector3 &normal,
btScalar *jac,
btAlignedObjectArray<btScalar> &scratch_r,
btAlignedObjectArray<btVector3> &scratch_v,
+ btAlignedObjectArray<btMatrix3x3> &scratch_m) const { fillConstraintJacobianMultiDof(link, contact_point, btVector3(0, 0, 0), normal, jac, scratch_r, scratch_v, scratch_m); }
+
+ //a more general version of fillContactJacobianMultiDof which does not assume..
+ //.. that the constraint in question is contact or, to be more precise, constrains linear velocity only
+ void fillConstraintJacobianMultiDof(int link,
+ const btVector3 &contact_point,
+ const btVector3 &normal_ang,
+ const btVector3 &normal_lin,
+ btScalar *jac,
+ btAlignedObjectArray<btScalar> &scratch_r,
+ btAlignedObjectArray<btVector3> &scratch_v,
btAlignedObjectArray<btMatrix3x3> &scratch_m) const;
@@ -329,17 +448,22 @@ public:
//
void setCanSleep(bool canSleep)
{
- can_sleep = canSleep;
+ m_canSleep = canSleep;
}
- bool isAwake() const { return awake; }
+ bool getCanSleep()const
+ {
+ return m_canSleep;
+ }
+
+ bool isAwake() const { return m_awake; }
void wakeUp();
void goToSleep();
void checkMotionAndSleepIfRequired(btScalar timestep);
bool hasFixedBase() const
{
- return fixed_base;
+ return m_fixedBase;
}
int getCompanionId() const
@@ -352,9 +476,9 @@ public:
m_companionId = id;
}
- void setNumLinks(int numLinks)//careful: when changing the number of links, make sure to re-initialize or update existing links
+ void setNumLinks(int numLinks)//careful: when changing the number of m_links, make sure to re-initialize or update existing m_links
{
- links.resize(numLinks);
+ m_links.resize(numLinks);
}
btScalar getLinearDamping() const
@@ -369,6 +493,10 @@ public:
{
return m_angularDamping;
}
+ void setAngularDamping( btScalar damp)
+ {
+ m_angularDamping = damp;
+ }
bool getUseGyroTerm() const
{
@@ -378,6 +506,15 @@ public:
{
m_useGyroTerm = useGyro;
}
+ btScalar getMaxCoordinateVelocity() const
+ {
+ return m_maxCoordinateVelocity ;
+ }
+ void setMaxCoordinateVelocity(btScalar maxVel)
+ {
+ m_maxCoordinateVelocity = maxVel;
+ }
+
btScalar getMaxAppliedImpulse() const
{
return m_maxAppliedImpulse;
@@ -386,7 +523,6 @@ public:
{
m_maxAppliedImpulse = maxImp;
}
-
void setHasSelfCollision(bool hasSelfCollision)
{
m_hasSelfCollision = hasSelfCollision;
@@ -396,6 +532,47 @@ public:
return m_hasSelfCollision;
}
+
+ void finalizeMultiDof();
+
+ void useRK4Integration(bool use) { m_useRK4 = use; }
+ bool isUsingRK4Integration() const { return m_useRK4; }
+ void useGlobalVelocities(bool use) { m_useGlobalVelocities = use; }
+ bool isUsingGlobalVelocities() const { return m_useGlobalVelocities; }
+
+ bool isPosUpdated() const
+ {
+ return __posUpdated;
+ }
+ void setPosUpdated(bool updated)
+ {
+ __posUpdated = updated;
+ }
+
+ //internalNeedsJointFeedback is for internal use only
+ bool internalNeedsJointFeedback() const
+ {
+ return m_internalNeedsJointFeedback;
+ }
+ void forwardKinematics(btAlignedObjectArray<btQuaternion>& scratch_q,btAlignedObjectArray<btVector3>& scratch_m);
+
+ void updateCollisionObjectWorldTransforms(btAlignedObjectArray<btQuaternion>& scratch_q,btAlignedObjectArray<btVector3>& scratch_m);
+
+ 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;
+
+ const char* getBaseName() const
+ {
+ return m_baseName;
+ }
+ ///memory of setBaseName needs to be manager by user
+ void setBaseName(const char* name)
+ {
+ m_baseName = name;
+ }
+
private:
btMultiBody(const btMultiBody &); // not implemented
void operator=(const btMultiBody &); // not implemented
@@ -403,64 +580,181 @@ private:
void compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const;
void solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bot, float result[6]) const;
-
+ void solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const;
+
+ void updateLinksDofOffsets()
+ {
+ int dofOffset = 0, cfgOffset = 0;
+ for(int bidx = 0; bidx < m_links.size(); ++bidx)
+ {
+ m_links[bidx].m_dofOffset = dofOffset; m_links[bidx].m_cfgOffset = cfgOffset;
+ dofOffset += m_links[bidx].m_dofCount; cfgOffset += m_links[bidx].m_posVarCount;
+ }
+ }
+
+ void mulMatrix(btScalar *pA, btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const;
+
private:
btMultiBodyLinkCollider* m_baseCollider;//can be NULL
+ const char* m_baseName;//memory needs to be manager by user!
- btVector3 base_pos; // position of COM of base (world frame)
- btQuaternion base_quat; // rotates world points into base frame
+ btVector3 m_basePos; // position of COM of base (world frame)
+ btQuaternion m_baseQuat; // rotates world points into base frame
- btScalar base_mass; // mass of the base
- btVector3 base_inertia; // inertia of the base (in local frame; diagonal)
+ btScalar m_baseMass; // mass of the base
+ btVector3 m_baseInertia; // inertia of the base (in local frame; diagonal)
- btVector3 base_force; // external force applied to base. World frame.
- btVector3 base_torque; // external torque applied to base. World frame.
-
- btAlignedObjectArray<btMultibodyLink> links; // array of links, excluding the base. index from 0 to num_links-1.
+ btVector3 m_baseForce; // external force applied to base. World frame.
+ btVector3 m_baseTorque; // external torque applied to base. World frame.
+
+ btVector3 m_baseConstraintForce; // external force applied to base. World frame.
+ btVector3 m_baseConstraintTorque; // external torque applied to base. World frame.
+
+ btAlignedObjectArray<btMultibodyLink> m_links; // array of m_links, excluding the base. index from 0 to num_links-1.
btAlignedObjectArray<btMultiBodyLinkCollider*> m_colliders;
+
//
- // real_buf:
+ // realBuf:
// offset size array
- // 0 6 + num_links v (base_omega; base_vel; joint_vels)
+ // 0 6 + num_links v (base_omega; base_vel; joint_vels) MULTIDOF [sysdof x sysdof for D matrices (TOO MUCH!) + pos_delta which is sys-cfg sized]
// 6+num_links num_links D
//
- // vector_buf:
+ // vectorBuf:
// offset size array
// 0 num_links h_top
// num_links num_links h_bottom
//
- // matrix_buf:
+ // matrixBuf:
// offset size array
// 0 num_links+1 rot_from_parent
//
-
- btAlignedObjectArray<btScalar> m_real_buf;
- btAlignedObjectArray<btVector3> vector_buf;
- btAlignedObjectArray<btMatrix3x3> matrix_buf;
+ btAlignedObjectArray<btScalar> m_deltaV;
+ btAlignedObjectArray<btScalar> m_realBuf;
+ btAlignedObjectArray<btVector3> m_vectorBuf;
+ btAlignedObjectArray<btMatrix3x3> m_matrixBuf;
- //std::auto_ptr<Eigen::LU<Eigen::Matrix<btScalar, 6, 6> > > cached_imatrix_lu;
- btMatrix3x3 cached_inertia_top_left;
- btMatrix3x3 cached_inertia_top_right;
- btMatrix3x3 cached_inertia_lower_left;
- btMatrix3x3 cached_inertia_lower_right;
+ btMatrix3x3 m_cachedInertiaTopLeft;
+ btMatrix3x3 m_cachedInertiaTopRight;
+ btMatrix3x3 m_cachedInertiaLowerLeft;
+ btMatrix3x3 m_cachedInertiaLowerRight;
- bool fixed_base;
+ bool m_fixedBase;
// Sleep parameters.
- bool awake;
- bool can_sleep;
- btScalar sleep_timer;
+ bool m_awake;
+ bool m_canSleep;
+ btScalar m_sleepTimer;
int m_companionId;
btScalar m_linearDamping;
btScalar m_angularDamping;
bool m_useGyroTerm;
btScalar m_maxAppliedImpulse;
+ btScalar m_maxCoordinateVelocity;
bool m_hasSelfCollision;
+
+ bool __posUpdated;
+ int m_dofCount, m_posVarCnt;
+ bool m_useRK4, m_useGlobalVelocities;
+
+ ///the m_needsJointFeedback gets updated/computed during the stepVelocitiesMultiDof and it for internal usage only
+ bool m_internalNeedsJointFeedback;
};
+struct btMultiBodyLinkDoubleData
+{
+ btQuaternionDoubleData m_zeroRotParentToThis;
+ btVector3DoubleData m_parentComToThisComOffset;
+ btVector3DoubleData m_thisPivotToThisComOffset;
+ btVector3DoubleData m_jointAxisTop[6];
+ btVector3DoubleData m_jointAxisBottom[6];
+
+
+ char *m_linkName;
+ char *m_jointName;
+ btCollisionObjectDoubleData *m_linkCollider;
+
+ btVector3DoubleData m_linkInertia; // inertia of the base (in local frame; diagonal)
+ double m_linkMass;
+ int m_parentIndex;
+ int m_jointType;
+
+
+
+
+ int m_dofCount;
+ int m_posVarCount;
+ double m_jointPos[7];
+ double m_jointVel[6];
+ double m_jointTorque[6];
+
+
+
+};
+
+struct btMultiBodyLinkFloatData
+{
+ btQuaternionFloatData m_zeroRotParentToThis;
+ btVector3FloatData m_parentComToThisComOffset;
+ btVector3FloatData m_thisPivotToThisComOffset;
+ btVector3FloatData m_jointAxisTop[6];
+ btVector3FloatData m_jointAxisBottom[6];
+
+
+ char *m_linkName;
+ char *m_jointName;
+ btCollisionObjectFloatData *m_linkCollider;
+
+ btVector3FloatData m_linkInertia; // inertia of the base (in local frame; diagonal)
+ int m_dofCount;
+ float m_linkMass;
+ int m_parentIndex;
+ int m_jointType;
+
+
+
+ float m_jointPos[7];
+ float m_jointVel[6];
+ float m_jointTorque[6];
+ int m_posVarCount;
+
+
+};
+
+///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64
+struct btMultiBodyDoubleData
+{
+ char *m_baseName;
+ btMultiBodyLinkDoubleData *m_links;
+ btCollisionObjectDoubleData *m_baseCollider;
+
+ btTransformDoubleData m_baseWorldTransform;
+ btVector3DoubleData m_baseInertia; // inertia of the base (in local frame; diagonal)
+
+ int m_numLinks;
+ double m_baseMass;
+
+ 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_baseInertia; // inertia of the base (in local frame; diagonal)
+
+ float m_baseMass;
+ int m_numLinks;
+};
+
+
+
#endif
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
index 44e04c3a132..12997d2e374 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp
@@ -1,263 +1,101 @@
#include "btMultiBodyConstraint.h"
#include "BulletDynamics/Dynamics/btRigidBody.h"
+#include "btMultiBodyPoint2Point.h" //for testing (BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST macro)
+
+
btMultiBodyConstraint::btMultiBodyConstraint(btMultiBody* bodyA,btMultiBody* bodyB,int linkA, int linkB, int numRows, bool isUnilateral)
:m_bodyA(bodyA),
m_bodyB(bodyB),
m_linkA(linkA),
m_linkB(linkB),
- m_num_rows(numRows),
+ m_numRows(numRows),
+ m_jacSizeA(0),
+ m_jacSizeBoth(0),
m_isUnilateral(isUnilateral),
+ m_numDofsFinalized(-1),
m_maxAppliedImpulse(100)
{
- m_jac_size_A = (6 + bodyA->getNumLinks());
- m_jac_size_both = (m_jac_size_A + (bodyB ? 6 + bodyB->getNumLinks() : 0));
- m_pos_offset = ((1 + m_jac_size_both)*m_num_rows);
- m_data.resize((2 + m_jac_size_both) * m_num_rows);
-}
-btMultiBodyConstraint::~btMultiBodyConstraint()
-{
}
-
-
-btScalar btMultiBodyConstraint::fillConstraintRowMultiBodyMultiBody(btMultiBodySolverConstraint& constraintRow,
- btMultiBodyJacobianData& data,
- btScalar* jacOrgA,btScalar* jacOrgB,
- const btContactSolverInfo& infoGlobal,
- btScalar desiredVelocity,
- btScalar lowerLimit,
- btScalar upperLimit)
+void btMultiBodyConstraint::updateJacobianSizes()
{
-
-
-
- constraintRow.m_multiBodyA = m_bodyA;
- constraintRow.m_multiBodyB = m_bodyB;
-
- btMultiBody* multiBodyA = constraintRow.m_multiBodyA;
- btMultiBody* multiBodyB = constraintRow.m_multiBodyB;
-
- if (multiBodyA)
+ if(m_bodyA)
{
-
- const int ndofA = multiBodyA->getNumLinks() + 6;
-
- constraintRow.m_deltaVelAindex = multiBodyA->getCompanionId();
-
- if (constraintRow.m_deltaVelAindex <0)
- {
- constraintRow.m_deltaVelAindex = data.m_deltaVelocities.size();
- multiBodyA->setCompanionId(constraintRow.m_deltaVelAindex);
- data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofA);
- } else
- {
- btAssert(data.m_deltaVelocities.size() >= constraintRow.m_deltaVelAindex+ndofA);
- }
-
- constraintRow.m_jacAindex = data.m_jacobians.size();
- data.m_jacobians.resize(data.m_jacobians.size()+ndofA);
- data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofA);
- btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size());
- for (int i=0;i<ndofA;i++)
- data.m_jacobians[constraintRow.m_jacAindex+i] = jacOrgA[i];
-
- btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[constraintRow.m_jacAindex];
- multiBodyA->calcAccelerationDeltas(&data.m_jacobians[constraintRow.m_jacAindex],delta,data.scratch_r, data.scratch_v);
- }
-
- if (multiBodyB)
- {
- const int ndofB = multiBodyB->getNumLinks() + 6;
-
- constraintRow.m_deltaVelBindex = multiBodyB->getCompanionId();
- if (constraintRow.m_deltaVelBindex <0)
- {
- constraintRow.m_deltaVelBindex = data.m_deltaVelocities.size();
- multiBodyB->setCompanionId(constraintRow.m_deltaVelBindex);
- data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofB);
- }
-
- constraintRow.m_jacBindex = data.m_jacobians.size();
- data.m_jacobians.resize(data.m_jacobians.size()+ndofB);
-
- for (int i=0;i<ndofB;i++)
- data.m_jacobians[constraintRow.m_jacBindex+i] = jacOrgB[i];
-
- data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofB);
- btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size());
- multiBodyB->calcAccelerationDeltas(&data.m_jacobians[constraintRow.m_jacBindex],&data.m_deltaVelocitiesUnitImpulse[constraintRow.m_jacBindex],data.scratch_r, data.scratch_v);
- }
- {
-
- btVector3 vec;
- btScalar denom0 = 0.f;
- btScalar denom1 = 0.f;
- btScalar* jacB = 0;
- btScalar* jacA = 0;
- btScalar* lambdaA =0;
- btScalar* lambdaB =0;
- int ndofA = 0;
- if (multiBodyA)
- {
- ndofA = multiBodyA->getNumLinks() + 6;
- jacA = &data.m_jacobians[constraintRow.m_jacAindex];
- lambdaA = &data.m_deltaVelocitiesUnitImpulse[constraintRow.m_jacAindex];
- for (int i = 0; i < ndofA; ++i)
- {
- btScalar j = jacA[i] ;
- btScalar l =lambdaA[i];
- denom0 += j*l;
- }
- }
- if (multiBodyB)
- {
- const int ndofB = multiBodyB->getNumLinks() + 6;
- jacB = &data.m_jacobians[constraintRow.m_jacBindex];
- lambdaB = &data.m_deltaVelocitiesUnitImpulse[constraintRow.m_jacBindex];
- for (int i = 0; i < ndofB; ++i)
- {
- btScalar j = jacB[i] ;
- btScalar l =lambdaB[i];
- denom1 += j*l;
- }
-
- }
-
- if (multiBodyA && (multiBodyA==multiBodyB))
- {
- // ndof1 == ndof2 in this case
- for (int i = 0; i < ndofA; ++i)
- {
- denom1 += jacB[i] * lambdaA[i];
- denom1 += jacA[i] * lambdaB[i];
- }
- }
-
- btScalar d = denom0+denom1;
- if (btFabs(d)>SIMD_EPSILON)
- {
-
- constraintRow.m_jacDiagABInv = 1.f/(d);
- } else
- {
- constraintRow.m_jacDiagABInv = 1.f;
- }
-
+ m_jacSizeA = (6 + m_bodyA->getNumDofs());
}
-
- //compute rhs and remaining constraintRow fields
-
-
-
-
- btScalar rel_vel = 0.f;
- int ndofA = 0;
- int ndofB = 0;
+ if(m_bodyB)
{
+ m_jacSizeBoth = m_jacSizeA + 6 + m_bodyB->getNumDofs();
+ }
+ else
+ m_jacSizeBoth = m_jacSizeA;
+}
- btVector3 vel1,vel2;
- if (multiBodyA)
- {
- ndofA = multiBodyA->getNumLinks() + 6;
- btScalar* jacA = &data.m_jacobians[constraintRow.m_jacAindex];
- for (int i = 0; i < ndofA ; ++i)
- rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i];
- }
- if (multiBodyB)
- {
- ndofB = multiBodyB->getNumLinks() + 6;
- btScalar* jacB = &data.m_jacobians[constraintRow.m_jacBindex];
- for (int i = 0; i < ndofB ; ++i)
- rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i];
-
- }
-
- constraintRow.m_friction = 0.f;
-
- constraintRow.m_appliedImpulse = 0.f;
- constraintRow.m_appliedPushImpulse = 0.f;
-
- btScalar velocityError = desiredVelocity - rel_vel;// * damping;
-
- btScalar erp = infoGlobal.m_erp2;
-
- btScalar velocityImpulse = velocityError *constraintRow.m_jacDiagABInv;
-
- if (!infoGlobal.m_splitImpulse)
- {
- //combine position and velocity into rhs
- constraintRow.m_rhs = velocityImpulse;
- constraintRow.m_rhsPenetration = 0.f;
-
- } else
- {
- //split position and velocity into rhs and m_rhsPenetration
- constraintRow.m_rhs = velocityImpulse;
- constraintRow.m_rhsPenetration = 0.f;
- }
-
-
- constraintRow.m_cfm = 0.f;
- constraintRow.m_lowerLimit = lowerLimit;
- constraintRow.m_upperLimit = upperLimit;
+void btMultiBodyConstraint::allocateJacobiansMultiDof()
+{
+ updateJacobianSizes();
- }
- return rel_vel;
+ m_posOffset = ((1 + m_jacSizeBoth)*m_numRows);
+ m_data.resize((2 + m_jacSizeBoth) * m_numRows);
}
+btMultiBodyConstraint::~btMultiBodyConstraint()
+{
+}
void btMultiBodyConstraint::applyDeltaVee(btMultiBodyJacobianData& data, btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof)
{
- for (int i = 0; i < ndof; ++i)
+ for (int i = 0; i < ndof; ++i)
data.m_deltaVelocities[velocityIndex+i] += delta_vee[i] * impulse;
}
-
-void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstraint& solverConstraint,
- btMultiBodyJacobianData& data,
- const btVector3& contactNormalOnB,
- const btVector3& posAworld, const btVector3& posBworld,
- btScalar position,
- const btContactSolverInfo& infoGlobal,
- btScalar& relaxation,
- bool isFriction, btScalar desiredVelocity, btScalar cfmSlip)
+btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstraint& solverConstraint,
+ btMultiBodyJacobianData& data,
+ btScalar* jacOrgA, btScalar* jacOrgB,
+ const btVector3& contactNormalOnB,
+ const btVector3& posAworld, const btVector3& posBworld,
+ btScalar posError,
+ const btContactSolverInfo& infoGlobal,
+ btScalar lowerLimit, btScalar upperLimit,
+ btScalar relaxation,
+ bool isFriction, btScalar desiredVelocity, btScalar cfmSlip)
{
-
-
- btVector3 rel_pos1 = posAworld;
- btVector3 rel_pos2 = posBworld;
+
solverConstraint.m_multiBodyA = m_bodyA;
solverConstraint.m_multiBodyB = m_bodyB;
solverConstraint.m_linkA = m_linkA;
solverConstraint.m_linkB = m_linkB;
-
btMultiBody* multiBodyA = solverConstraint.m_multiBodyA;
btMultiBody* multiBodyB = solverConstraint.m_multiBodyB;
- const btVector3& pos1 = posAworld;
- const btVector3& pos2 = posBworld;
-
btSolverBody* bodyA = multiBodyA ? 0 : &data.m_solverBodyPool->at(solverConstraint.m_solverBodyIdA);
btSolverBody* bodyB = multiBodyB ? 0 : &data.m_solverBodyPool->at(solverConstraint.m_solverBodyIdB);
btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody;
btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody;
+ btVector3 rel_pos1, rel_pos2; //these two used to be inited to posAworld and posBworld (respectively) but it does not seem necessary
if (bodyA)
- rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin();
+ rel_pos1 = posAworld - bodyA->getWorldTransform().getOrigin();
if (bodyB)
- rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin();
-
- relaxation = 1.f;
+ rel_pos2 = posBworld - bodyB->getWorldTransform().getOrigin();
if (multiBodyA)
{
- const int ndofA = multiBodyA->getNumLinks() + 6;
+ if (solverConstraint.m_linkA<0)
+ {
+ rel_pos1 = posAworld - multiBodyA->getBasePos();
+ } else
+ {
+ rel_pos1 = posAworld - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin();
+ }
+
+ const int ndofA = multiBodyA->getNumDofs() + 6;
solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId();
@@ -271,16 +109,35 @@ void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstr
btAssert(data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex+ndofA);
}
+ //determine jacobian of this 1D constraint in terms of multibodyA's degrees of freedom
+ //resize..
solverConstraint.m_jacAindex = data.m_jacobians.size();
data.m_jacobians.resize(data.m_jacobians.size()+ndofA);
- data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofA);
- btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size());
+ //copy/determine
+ if(jacOrgA)
+ {
+ for (int i=0;i<ndofA;i++)
+ data.m_jacobians[solverConstraint.m_jacAindex+i] = jacOrgA[i];
+ }
+ else
+ {
+ btScalar* jac1=&data.m_jacobians[solverConstraint.m_jacAindex];
+ multiBodyA->fillContactJacobianMultiDof(solverConstraint.m_linkA, posAworld, contactNormalOnB, jac1, data.scratch_r, data.scratch_v, data.scratch_m);
+ }
- btScalar* jac1=&data.m_jacobians[solverConstraint.m_jacAindex];
- multiBodyA->fillContactJacobian(solverConstraint.m_linkA, posAworld, contactNormalOnB, jac1, data.scratch_r, data.scratch_v, data.scratch_m);
+ //determine the velocity response of multibodyA to reaction impulses of this constraint (i.e. A[i,i] for i=1,...n_con: multibody's inverse inertia with respect to this 1D constraint)
+ //resize..
+ data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofA); //=> each constraint row has the constrained tree dofs allocated in m_deltaVelocitiesUnitImpulse
+ btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size());
btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
- multiBodyA->calcAccelerationDeltas(&data.m_jacobians[solverConstraint.m_jacAindex],delta,data.scratch_r, data.scratch_v);
- } else
+ //determine..
+ multiBodyA->calcAccelerationDeltasMultiDof(&data.m_jacobians[solverConstraint.m_jacAindex],delta,data.scratch_r, data.scratch_v);
+
+ btVector3 torqueAxis0 = rel_pos1.cross(contactNormalOnB);
+ solverConstraint.m_relpos1CrossNormal = torqueAxis0;
+ solverConstraint.m_contactNormal1 = contactNormalOnB;
+ }
+ else //if(rb0)
{
btVector3 torqueAxis0 = rel_pos1.cross(contactNormalOnB);
solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0);
@@ -290,7 +147,15 @@ void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstr
if (multiBodyB)
{
- const int ndofB = multiBodyB->getNumLinks() + 6;
+ if (solverConstraint.m_linkB<0)
+ {
+ rel_pos2 = posBworld - multiBodyB->getBasePos();
+ } else
+ {
+ rel_pos2 = posBworld - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin();
+ }
+
+ const int ndofB = multiBodyB->getNumDofs() + 6;
solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId();
if (solverConstraint.m_deltaVelBindex <0)
@@ -300,144 +165,136 @@ void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstr
data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofB);
}
+ //determine jacobian of this 1D constraint in terms of multibodyB's degrees of freedom
+ //resize..
solverConstraint.m_jacBindex = data.m_jacobians.size();
-
data.m_jacobians.resize(data.m_jacobians.size()+ndofB);
+ //copy/determine..
+ if(jacOrgB)
+ {
+ for (int i=0;i<ndofB;i++)
+ data.m_jacobians[solverConstraint.m_jacBindex+i] = jacOrgB[i];
+ }
+ else
+ {
+ multiBodyB->fillContactJacobianMultiDof(solverConstraint.m_linkB, posBworld, -contactNormalOnB, &data.m_jacobians[solverConstraint.m_jacBindex], data.scratch_r, data.scratch_v, data.scratch_m);
+ }
+
+ //determine velocity response of multibodyB to reaction impulses of this constraint (i.e. A[i,i] for i=1,...n_con: multibody's inverse inertia with respect to this 1D constraint)
+ //resize..
data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofB);
btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size());
+ btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
+ //determine..
+ multiBodyB->calcAccelerationDeltasMultiDof(&data.m_jacobians[solverConstraint.m_jacBindex],delta,data.scratch_r, data.scratch_v);
- multiBodyB->fillContactJacobian(solverConstraint.m_linkB, posBworld, -contactNormalOnB, &data.m_jacobians[solverConstraint.m_jacBindex], data.scratch_r, data.scratch_v, data.scratch_m);
- multiBodyB->calcAccelerationDeltas(&data.m_jacobians[solverConstraint.m_jacBindex],&data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],data.scratch_r, data.scratch_v);
- } else
+ btVector3 torqueAxis1 = rel_pos2.cross(contactNormalOnB);
+ solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
+ solverConstraint.m_contactNormal2 = -contactNormalOnB;
+
+ }
+ else //if(rb1)
{
- btVector3 torqueAxis1 = rel_pos2.cross(contactNormalOnB);
+ btVector3 torqueAxis1 = rel_pos2.cross(contactNormalOnB);
solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0);
solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
solverConstraint.m_contactNormal2 = -contactNormalOnB;
}
-
{
-
+
btVector3 vec;
btScalar denom0 = 0.f;
btScalar denom1 = 0.f;
btScalar* jacB = 0;
btScalar* jacA = 0;
- btScalar* lambdaA =0;
- btScalar* lambdaB =0;
+ btScalar* deltaVelA = 0;
+ btScalar* deltaVelB = 0;
int ndofA = 0;
+ //determine the "effective mass" of the constrained multibodyA with respect to this 1D constraint (i.e. 1/A[i,i])
if (multiBodyA)
{
- ndofA = multiBodyA->getNumLinks() + 6;
+ ndofA = multiBodyA->getNumDofs() + 6;
jacA = &data.m_jacobians[solverConstraint.m_jacAindex];
- lambdaA = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
+ deltaVelA = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
for (int i = 0; i < ndofA; ++i)
{
btScalar j = jacA[i] ;
- btScalar l =lambdaA[i];
+ btScalar l = deltaVelA[i];
denom0 += j*l;
}
- } else
+ }
+ else if(rb0)
{
- if (rb0)
- {
- vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1);
- denom0 = rb0->getInvMass() + contactNormalOnB.dot(vec);
- }
+ vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1);
+ denom0 = rb0->getInvMass() + contactNormalOnB.dot(vec);
}
+ //
if (multiBodyB)
{
- const int ndofB = multiBodyB->getNumLinks() + 6;
+ const int ndofB = multiBodyB->getNumDofs() + 6;
jacB = &data.m_jacobians[solverConstraint.m_jacBindex];
- lambdaB = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
+ deltaVelB = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
for (int i = 0; i < ndofB; ++i)
{
btScalar j = jacB[i] ;
- btScalar l =lambdaB[i];
+ btScalar l = deltaVelB[i];
denom1 += j*l;
}
- } else
+ }
+ else if(rb1)
{
- if (rb1)
- {
- vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2);
- denom1 = rb1->getInvMass() + contactNormalOnB.dot(vec);
- }
+ vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2);
+ denom1 = rb1->getInvMass() + contactNormalOnB.dot(vec);
}
- if (multiBodyA && (multiBodyA==multiBodyB))
- {
- // ndof1 == ndof2 in this case
- for (int i = 0; i < ndofA; ++i)
- {
- denom1 += jacB[i] * lambdaA[i];
- denom1 += jacA[i] * lambdaB[i];
- }
- }
-
- btScalar d = denom0+denom1;
- if (btFabs(d)>SIMD_EPSILON)
- {
-
- solverConstraint.m_jacDiagABInv = relaxation/(d);
- } else
- {
- solverConstraint.m_jacDiagABInv = 1.f;
- }
-
+ //
+ btScalar d = denom0+denom1;
+ if (d>SIMD_EPSILON)
+ {
+ solverConstraint.m_jacDiagABInv = relaxation/(d);
+ }
+ else
+ {
+ //disable the constraint row to handle singularity/redundant constraint
+ solverConstraint.m_jacDiagABInv = 0.f;
+ }
}
-
- //compute rhs and remaining solverConstraint fields
-
-
- btScalar restitution = 0.f;
- btScalar penetration = isFriction? 0 : position+infoGlobal.m_linearSlop;
+ //compute rhs and remaining solverConstraint fields
+ btScalar penetration = isFriction? 0 : posError+infoGlobal.m_linearSlop;
btScalar rel_vel = 0.f;
int ndofA = 0;
int ndofB = 0;
{
-
btVector3 vel1,vel2;
if (multiBodyA)
{
- ndofA = multiBodyA->getNumLinks() + 6;
+ ndofA = multiBodyA->getNumDofs() + 6;
btScalar* jacA = &data.m_jacobians[solverConstraint.m_jacAindex];
- for (int i = 0; i < ndofA ; ++i)
+ for (int i = 0; i < ndofA ; ++i)
rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i];
- } else
+ }
+ else if(rb0)
{
- if (rb0)
- {
- rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1);
- }
+ rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1);
}
if (multiBodyB)
{
- ndofB = multiBodyB->getNumLinks() + 6;
+ ndofB = multiBodyB->getNumDofs() + 6;
btScalar* jacB = &data.m_jacobians[solverConstraint.m_jacBindex];
- for (int i = 0; i < ndofB ; ++i)
+ for (int i = 0; i < ndofB ; ++i)
rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i];
- } else
+ }
+ else if(rb1)
{
- if (rb1)
- {
- rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2);
- }
+ rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2);
}
solverConstraint.m_friction = 0.f;//cp.m_combinedFriction;
-
-
- restitution = restitution * -rel_vel;//restitutionCurve(rel_vel, cp.m_combinedRestitution);
- if (restitution <= btScalar(0.))
- {
- restitution = 0.f;
- };
}
@@ -474,18 +331,15 @@ void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstr
}
} else
*/
- {
- solverConstraint.m_appliedImpulse = 0.f;
- }
+ solverConstraint.m_appliedImpulse = 0.f;
solverConstraint.m_appliedPushImpulse = 0.f;
{
-
btScalar positionalError = 0.f;
- btScalar velocityError = restitution - rel_vel;// * damping;
-
+ btScalar velocityError = desiredVelocity - rel_vel;// * damping;
+
btScalar erp = infoGlobal.m_erp2;
if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
@@ -493,15 +347,7 @@ void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstr
erp = infoGlobal.m_erp;
}
- if (penetration>0)
- {
- positionalError = 0;
- velocityError = -penetration / infoGlobal.m_timeStep;
-
- } else
- {
- positionalError = -penetration * erp/infoGlobal.m_timeStep;
- }
+ positionalError = -penetration * erp/infoGlobal.m_timeStep;
btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv;
btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv;
@@ -520,8 +366,10 @@ void btMultiBodyConstraint::fillMultiBodyConstraintMixed(btMultiBodySolverConstr
}
solverConstraint.m_cfm = 0.f;
- solverConstraint.m_lowerLimit = -m_maxAppliedImpulse;
- solverConstraint.m_upperLimit = m_maxAppliedImpulse;
+ solverConstraint.m_lowerLimit = lowerLimit;
+ solverConstraint.m_upperLimit = upperLimit;
}
+ return rel_vel;
+
}
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h
index 9fa317330b3..3b32b46e911 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -28,8 +28,8 @@ struct btSolverInfo;
struct btMultiBodyJacobianData
{
btAlignedObjectArray<btScalar> m_jacobians;
- btAlignedObjectArray<btScalar> m_deltaVelocitiesUnitImpulse;
- btAlignedObjectArray<btScalar> m_deltaVelocities;
+ btAlignedObjectArray<btScalar> m_deltaVelocitiesUnitImpulse; //holds the joint-space response of the corresp. tree to the test impulse in each constraint space dimension
+ btAlignedObjectArray<btScalar> m_deltaVelocities; //holds joint-space vectors of all the constrained trees accumulating the effect of corrective impulses applied in SI
btAlignedObjectArray<btScalar> scratch_r;
btAlignedObjectArray<btVector3> scratch_v;
btAlignedObjectArray<btMatrix3x3> scratch_m;
@@ -48,16 +48,17 @@ protected:
int m_linkA;
int m_linkB;
- int m_num_rows;
- int m_jac_size_A;
- int m_jac_size_both;
- int m_pos_offset;
+ int m_numRows;
+ int m_jacSizeA;
+ int m_jacSizeBoth;
+ int m_posOffset;
bool m_isUnilateral;
-
+ int m_numDofsFinalized;
btScalar m_maxAppliedImpulse;
+ // warning: the data block lay out is not consistent for all constraints
// data block laid out as follows:
// cached impulses. (one per row.)
// jacobians. (interleaved, row1 body1 then row1 body2 then row2 body 1 etc)
@@ -66,40 +67,37 @@ protected:
void applyDeltaVee(btMultiBodyJacobianData& data, btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof);
- void fillMultiBodyConstraintMixed(btMultiBodySolverConstraint& solverConstraint,
- btMultiBodyJacobianData& data,
- const btVector3& contactNormalOnB,
- const btVector3& posAworld, const btVector3& posBworld,
- btScalar position,
- const btContactSolverInfo& infoGlobal,
- btScalar& relaxation,
- bool isFriction, btScalar desiredVelocity=0, btScalar cfmSlip=0);
-
- btScalar fillConstraintRowMultiBodyMultiBody(btMultiBodySolverConstraint& constraintRow,
- btMultiBodyJacobianData& data,
- btScalar* jacOrgA,btScalar* jacOrgB,
- const btContactSolverInfo& infoGlobal,
- btScalar desiredVelocity,
- btScalar lowerLimit,
- btScalar upperLimit);
+ btScalar fillMultiBodyConstraint(btMultiBodySolverConstraint& solverConstraint,
+ btMultiBodyJacobianData& data,
+ btScalar* jacOrgA, btScalar* jacOrgB,
+ const btVector3& contactNormalOnB,
+ const btVector3& posAworld, const btVector3& posBworld,
+ btScalar posError,
+ const btContactSolverInfo& infoGlobal,
+ btScalar lowerLimit, btScalar upperLimit,
+ btScalar relaxation = 1.f,
+ bool isFriction = false, btScalar desiredVelocity=0, btScalar cfmSlip=0);
public:
btMultiBodyConstraint(btMultiBody* bodyA,btMultiBody* bodyB,int linkA, int linkB, int numRows, bool isUnilateral);
virtual ~btMultiBodyConstraint();
+ void updateJacobianSizes();
+ void allocateJacobiansMultiDof();
+ virtual void finalizeMultiDof()=0;
virtual int getIslandIdA() const =0;
virtual int getIslandIdB() const =0;
-
+
virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal)=0;
int getNumRows() const
{
- return m_num_rows;
+ return m_numRows;
}
btMultiBody* getMultiBodyA()
@@ -111,20 +109,33 @@ public:
return m_bodyB;
}
+ void internalSetAppliedImpulse(int dof, btScalar appliedImpulse)
+ {
+ btAssert(dof>=0);
+ btAssert(dof < getNumRows());
+ m_data[dof] = appliedImpulse;
+ }
+
+ btScalar getAppliedImpulse(int dof)
+ {
+ btAssert(dof>=0);
+ btAssert(dof < getNumRows());
+ return m_data[dof];
+ }
// current constraint position
// constraint is pos >= 0 for unilateral, or pos = 0 for bilateral
// NOTE: ignored position for friction rows.
- btScalar getPosition(int row) const
- {
- return m_data[m_pos_offset + row];
+ btScalar getPosition(int row) const
+ {
+ return m_data[m_posOffset + row];
}
- void setPosition(int row, btScalar pos)
- {
- m_data[m_pos_offset + row] = pos;
+ void setPosition(int row, btScalar pos)
+ {
+ m_data[m_posOffset + row] = pos;
}
-
+
bool isUnilateral() const
{
return m_isUnilateral;
@@ -133,21 +144,21 @@ public:
// jacobian blocks.
// each of size 6 + num_links. (jacobian2 is null if no body2.)
// format: 3 'omega' coefficients, 3 'v' coefficients, then the 'qdot' coefficients.
- btScalar* jacobianA(int row)
- {
- return &m_data[m_num_rows + row * m_jac_size_both];
+ btScalar* jacobianA(int row)
+ {
+ return &m_data[m_numRows + row * m_jacSizeBoth];
}
- const btScalar* jacobianA(int row) const
- {
- return &m_data[m_num_rows + (row * m_jac_size_both)];
+ const btScalar* jacobianA(int row) const
+ {
+ return &m_data[m_numRows + (row * m_jacSizeBoth)];
}
- btScalar* jacobianB(int row)
- {
- return &m_data[m_num_rows + (row * m_jac_size_both) + m_jac_size_A];
+ btScalar* jacobianB(int row)
+ {
+ return &m_data[m_numRows + (row * m_jacSizeBoth) + m_jacSizeA];
}
- const btScalar* jacobianB(int row) const
- {
- return &m_data[m_num_rows + (row * m_jac_size_both) + m_jac_size_A];
+ const btScalar* jacobianB(int row) const
+ {
+ return &m_data[m_numRows + (row * m_jacSizeBoth) + m_jacSizeA];
}
btScalar getMaxAppliedImpulse() const
@@ -158,7 +169,8 @@ public:
{
m_maxAppliedImpulse = maxImp;
}
-
+
+ virtual void debugDraw(class btIDebugDraw* drawer)=0;
};
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
index 577f846225b..4f66b20b2c1 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp
@@ -13,6 +13,7 @@ subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
+
#include "btMultiBodyConstraintSolver.h"
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
#include "btMultiBodyLinkCollider.h"
@@ -33,9 +34,12 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl
for (int j=0;j<m_multiBodyNonContactConstraints.size();j++)
{
btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[j];
- //if (iteration < constraint.m_overrideNumSolverIterations)
- //resolveSingleConstraintRowGenericMultiBody(constraint);
+
resolveSingleConstraintRowGeneric(constraint);
+ if(constraint.m_multiBodyA)
+ constraint.m_multiBodyA->setPosUpdated(false);
+ if(constraint.m_multiBodyB)
+ constraint.m_multiBodyB->setPosUpdated(false);
}
//solve featherstone normal contact
@@ -44,6 +48,11 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl
btMultiBodySolverConstraint& constraint = m_multiBodyNormalContactConstraints[j];
if (iteration < infoGlobal.m_numIterations)
resolveSingleConstraintRowGeneric(constraint);
+
+ if(constraint.m_multiBodyA)
+ constraint.m_multiBodyA->setPosUpdated(false);
+ if(constraint.m_multiBodyB)
+ constraint.m_multiBodyB->setPosUpdated(false);
}
//solve featherstone frictional contact
@@ -60,6 +69,11 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl
frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse);
frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse;
resolveSingleConstraintRowGeneric(frictionConstraint);
+
+ if(frictionConstraint.m_multiBodyA)
+ frictionConstraint.m_multiBodyA->setPosUpdated(false);
+ if(frictionConstraint.m_multiBodyB)
+ frictionConstraint.m_multiBodyB->setPosUpdated(false);
}
}
}
@@ -108,10 +122,10 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult
if (c.m_multiBodyA)
{
- ndofA = c.m_multiBodyA->getNumLinks() + 6;
+ 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
+ } 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());
@@ -119,10 +133,10 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult
if (c.m_multiBodyB)
{
- ndofB = c.m_multiBodyB->getNumLinks() + 6;
+ 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
+ } 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());
@@ -151,8 +165,12 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult
if (c.m_multiBodyA)
{
applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse,c.m_deltaVelAindex,ndofA);
- c.m_multiBodyA->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse);
- } else
+#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);
+#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ } else if(c.m_solverBodyIdA >= 0)
{
bodyA->internalApplyImpulse(c.m_contactNormal1*bodyA->internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
@@ -160,8 +178,12 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult
if (c.m_multiBodyB)
{
applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse,c.m_deltaVelBindex,ndofB);
- c.m_multiBodyB->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse);
- } else
+#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);
+#endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+ } else if(c.m_solverBodyIdB >= 0)
{
bodyB->internalApplyImpulse(c.m_contactNormal2*bodyB->internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
}
@@ -169,60 +191,6 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult
}
-void btMultiBodyConstraintSolver::resolveSingleConstraintRowGenericMultiBody(const btMultiBodySolverConstraint& c)
-{
-
- btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm;
- btScalar deltaVelADotn=0;
- btScalar deltaVelBDotn=0;
- int ndofA=0;
- int ndofB=0;
-
- if (c.m_multiBodyA)
- {
- ndofA = c.m_multiBodyA->getNumLinks() + 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];
- }
-
- if (c.m_multiBodyB)
- {
- ndofB = c.m_multiBodyB->getNumLinks() + 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];
- }
-
-
- 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;
- c.m_appliedImpulse = c.m_lowerLimit;
- }
- else if (sum > c.m_upperLimit)
- {
- 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);
- c.m_multiBodyA->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse);
- }
- if (c.m_multiBodyB)
- {
- applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse,c.m_deltaVelBindex,ndofB);
- c.m_multiBodyB->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse);
- }
-}
void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySolverConstraint& solverConstraint,
@@ -255,9 +223,19 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
relaxation = 1.f;
+
+
+
if (multiBodyA)
{
- const int ndofA = multiBodyA->getNumLinks() + 6;
+ if (solverConstraint.m_linkA<0)
+ {
+ rel_pos1 = pos1 - multiBodyA->getBasePos();
+ } else
+ {
+ rel_pos1 = pos1 - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin();
+ }
+ const int ndofA = multiBodyA->getNumDofs() + 6;
solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId();
@@ -277,20 +255,34 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
btScalar* jac1=&m_data.m_jacobians[solverConstraint.m_jacAindex];
- multiBodyA->fillContactJacobian(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
+ multiBodyA->fillContactJacobianMultiDof(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
btScalar* delta = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
- multiBodyA->calcAccelerationDeltas(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v);
+ multiBodyA->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v);
+
+ btVector3 torqueAxis0 = rel_pos1.cross(contactNormal);
+ solverConstraint.m_relpos1CrossNormal = torqueAxis0;
+ solverConstraint.m_contactNormal1 = contactNormal;
} else
{
btVector3 torqueAxis0 = rel_pos1.cross(contactNormal);
- solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0);
solverConstraint.m_relpos1CrossNormal = torqueAxis0;
solverConstraint.m_contactNormal1 = contactNormal;
+ solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0);
}
+
+
if (multiBodyB)
{
- const int ndofB = multiBodyB->getNumLinks() + 6;
+ if (solverConstraint.m_linkB<0)
+ {
+ rel_pos2 = pos2 - multiBodyB->getBasePos();
+ } else
+ {
+ rel_pos2 = pos2 - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin();
+ }
+
+ const int ndofB = multiBodyB->getNumDofs() + 6;
solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId();
if (solverConstraint.m_deltaVelBindex <0)
@@ -306,14 +298,20 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofB);
btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
- multiBodyB->fillContactJacobian(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -contactNormal, &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
- multiBodyB->calcAccelerationDeltas(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v);
+ multiBodyB->fillContactJacobianMultiDof(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -contactNormal, &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
+ multiBodyB->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v);
+
+ btVector3 torqueAxis1 = rel_pos2.cross(contactNormal);
+ solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
+ solverConstraint.m_contactNormal2 = -contactNormal;
+
} else
{
btVector3 torqueAxis1 = rel_pos2.cross(contactNormal);
- solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0);
solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
solverConstraint.m_contactNormal2 = -contactNormal;
+
+ solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0);
}
{
@@ -328,7 +326,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
int ndofA = 0;
if (multiBodyA)
{
- ndofA = multiBodyA->getNumLinks() + 6;
+ ndofA = multiBodyA->getNumDofs() + 6;
jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
lambdaA = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
for (int i = 0; i < ndofA; ++i)
@@ -347,7 +345,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
}
if (multiBodyB)
{
- const int ndofB = multiBodyB->getNumLinks() + 6;
+ const int ndofB = multiBodyB->getNumDofs() + 6;
jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
lambdaB = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
for (int i = 0; i < ndofB; ++i)
@@ -366,24 +364,16 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
}
}
- if (multiBodyA && (multiBodyA==multiBodyB))
- {
- // ndof1 == ndof2 in this case
- for (int i = 0; i < ndofA; ++i)
- {
- denom1 += jacB[i] * lambdaA[i];
- denom1 += jacA[i] * lambdaB[i];
- }
- }
+
btScalar d = denom0+denom1;
- if (btFabs(d)>SIMD_EPSILON)
+ if (d>SIMD_EPSILON)
{
-
- solverConstraint.m_jacDiagABInv = relaxation/(d);
+ solverConstraint.m_jacDiagABInv = relaxation/(d);
} else
{
- solverConstraint.m_jacDiagABInv = 1.f;
+ //disable the constraint row to handle singularity/redundant constraint
+ solverConstraint.m_jacDiagABInv = 0.f;
}
}
@@ -404,7 +394,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
btVector3 vel1,vel2;
if (multiBodyA)
{
- ndofA = multiBodyA->getNumLinks() + 6;
+ ndofA = multiBodyA->getNumDofs() + 6;
btScalar* jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
for (int i = 0; i < ndofA ; ++i)
rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i];
@@ -417,7 +407,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
}
if (multiBodyB)
{
- ndofB = multiBodyB->getNumLinks() + 6;
+ ndofB = multiBodyB->getNumDofs() + 6;
btScalar* jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
for (int i = 0; i < ndofB ; ++i)
rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i];
@@ -432,17 +422,20 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
solverConstraint.m_friction = cp.m_combinedFriction;
-
- restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution);
- if (restitution <= btScalar(0.))
+ if(!isFriction)
{
- restitution = 0.f;
- };
+ restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution);
+ if (restitution <= btScalar(0.))
+ {
+ restitution = 0.f;
+ }
+ }
}
///warm starting (or zero if disabled)
- if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
+ //disable warmstarting for btMultiBody, it has issues gaining energy (==explosion)
+ if (0)//infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
{
solverConstraint.m_appliedImpulse = isFriction ? 0 : cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor;
@@ -452,7 +445,8 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
{
btScalar impulse = solverConstraint.m_appliedImpulse;
btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
- multiBodyA->applyDeltaVee(deltaV,impulse);
+ multiBodyA->applyDeltaVeeMultiDof(deltaV,impulse);
+
applyDeltaVee(deltaV,impulse,solverConstraint.m_deltaVelAindex,ndofA);
} else
{
@@ -463,7 +457,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
{
btScalar impulse = solverConstraint.m_appliedImpulse;
btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
- multiBodyB->applyDeltaVee(deltaV,impulse);
+ multiBodyB->applyDeltaVeeMultiDof(deltaV,impulse);
applyDeltaVee(deltaV,impulse,solverConstraint.m_deltaVelBindex,ndofB);
} else
{
@@ -479,11 +473,9 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
solverConstraint.m_appliedPushImpulse = 0.f;
{
-
btScalar positionalError = 0.f;
- btScalar velocityError = restitution - rel_vel;// * damping;
-
+ btScalar velocityError = restitution - rel_vel;// * damping; //note for friction restitution is always set to 0 (check above) so it is acutally velocityError = -rel_vel for friction
btScalar erp = infoGlobal.m_erp2;
if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
@@ -494,7 +486,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
if (penetration>0)
{
positionalError = 0;
- velocityError = -penetration / infoGlobal.m_timeStep;
+ velocityError -= penetration / infoGlobal.m_timeStep;
} else
{
@@ -504,22 +496,33 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol
btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv;
btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv;
- if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
+ if(!isFriction)
{
- //combine position and velocity into rhs
- solverConstraint.m_rhs = penetrationImpulse+velocityImpulse;
- solverConstraint.m_rhsPenetration = 0.f;
+ if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
+ {
+ //combine position and velocity into rhs
+ solverConstraint.m_rhs = penetrationImpulse+velocityImpulse;
+ solverConstraint.m_rhsPenetration = 0.f;
- } else
+ } else
+ {
+ //split position and velocity into rhs and m_rhsPenetration
+ solverConstraint.m_rhs = velocityImpulse;
+ solverConstraint.m_rhsPenetration = penetrationImpulse;
+ }
+
+ solverConstraint.m_lowerLimit = 0;
+ solverConstraint.m_upperLimit = 1e10f;
+ }
+ else
{
- //split position and velocity into rhs and m_rhsPenetration
solverConstraint.m_rhs = velocityImpulse;
- solverConstraint.m_rhsPenetration = penetrationImpulse;
+ solverConstraint.m_rhsPenetration = 0.f;
+ solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
+ solverConstraint.m_upperLimit = solverConstraint.m_friction;
}
- solverConstraint.m_cfm = 0.f;
- solverConstraint.m_lowerLimit = 0;
- solverConstraint.m_upperLimit = 1e10f;
+ solverConstraint.m_cfm = 0.f; //why not use cfmSlip?
}
}
@@ -531,6 +534,9 @@ btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyFrictionCo
{
BT_PROFILE("addMultiBodyFrictionConstraint");
btMultiBodySolverConstraint& solverConstraint = m_multiBodyFrictionContactConstraints.expandNonInitializing();
+ solverConstraint.m_orgConstraint = 0;
+ solverConstraint.m_orgDofIndex = -1;
+
solverConstraint.m_frictionIndex = frictionIndex;
bool isFriction = true;
@@ -575,15 +581,15 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold*
int solverBodyIdA = mbA? -1 : getOrInitSolverBody(*colObj0,infoGlobal.m_timeStep);
int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1,infoGlobal.m_timeStep);
- btSolverBody* solverBodyA = mbA ? 0 : &m_tmpSolverBodyPool[solverBodyIdA];
- btSolverBody* solverBodyB = mbB ? 0 : &m_tmpSolverBodyPool[solverBodyIdB];
+// btSolverBody* solverBodyA = mbA ? 0 : &m_tmpSolverBodyPool[solverBodyIdA];
+// btSolverBody* solverBodyB = mbB ? 0 : &m_tmpSolverBodyPool[solverBodyIdB];
///avoid collision response between two static objects
// if (!solverBodyA || (solverBodyA->m_invMass.isZero() && (!solverBodyB || solverBodyB->m_invMass.isZero())))
// return;
- int rollingFriction=1;
+
for (int j=0;j<manifold->getNumContacts();j++)
{
@@ -599,8 +605,10 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold*
btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints.expandNonInitializing();
- btRigidBody* rb0 = btRigidBody::upcast(colObj0);
- btRigidBody* rb1 = btRigidBody::upcast(colObj1);
+ // btRigidBody* rb0 = btRigidBody::upcast(colObj0);
+ // btRigidBody* rb1 = btRigidBody::upcast(colObj1);
+ solverConstraint.m_orgConstraint = 0;
+ solverConstraint.m_orgDofIndex = -1;
solverConstraint.m_solverBodyIdA = solverBodyIdA;
solverConstraint.m_solverBodyIdB = solverBodyIdB;
solverConstraint.m_multiBodyA = mbA;
@@ -624,6 +632,7 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold*
#ifdef ENABLE_FRICTION
solverConstraint.m_frictionIndex = frictionIndex;
#if ROLLING_FRICTION
+ int rollingFriction=1;
btVector3 angVelA(0,0,0),angVelB(0,0,0);
if (rb0)
angVelA = rb0->getAngularVelocity();
@@ -702,6 +711,10 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold*
{
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);
+ addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal);
+
if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
{
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
@@ -709,10 +722,6 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold*
addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal);
}
- applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
- applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
- addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal);
-
if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION))
{
cp.m_lateralFrictionInitialized = true;
@@ -741,7 +750,7 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold*
void btMultiBodyConstraintSolver::convertContacts(btPersistentManifold** manifoldPtr,int numManifolds, const btContactSolverInfo& infoGlobal)
{
- btPersistentManifold* manifold = 0;
+ //btPersistentManifold* manifold = 0;
for (int i=0;i<numManifolds;i++)
{
@@ -779,6 +788,264 @@ btScalar btMultiBodyConstraintSolver::solveGroup(btCollisionObject** bodies,int
return btSequentialImpulseConstraintSolver::solveGroup(bodies,numBodies,manifold,numManifolds,constraints,numConstraints,info,debugDrawer,dispatcher);
}
+#if 0
+static void applyJointFeedback(btMultiBodyJacobianData& data, const btMultiBodySolverConstraint& solverConstraint, int jacIndex, btMultiBody* mb, btScalar appliedImpulse)
+{
+ if (appliedImpulse!=0 && mb->internalNeedsJointFeedback())
+ {
+ //todo: get rid of those temporary memory allocations for the joint feedback
+ btAlignedObjectArray<btScalar> forceVector;
+ int numDofsPlusBase = 6+mb->getNumDofs();
+ forceVector.resize(numDofsPlusBase);
+ for (int i=0;i<numDofsPlusBase;i++)
+ {
+ forceVector[i] = data.m_jacobians[jacIndex+i]*appliedImpulse;
+ }
+ btAlignedObjectArray<btScalar> output;
+ output.resize(numDofsPlusBase);
+ bool applyJointFeedback = true;
+ mb->calcAccelerationDeltasMultiDof(&forceVector[0],&output[0],data.scratch_r,data.scratch_v,applyJointFeedback);
+ }
+}
+#endif
+
+void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& c, btScalar deltaTime)
+{
+#if 1
+
+ //bod->addBaseForce(m_gravity * bod->getBaseMass());
+ //bod->addLinkForce(j, m_gravity * bod->getLinkMass(j));
+
+ if (c.m_orgConstraint)
+ {
+ c.m_orgConstraint->internalSetAppliedImpulse(c.m_orgDofIndex,c.m_appliedImpulse);
+ }
+
+
+ if (c.m_multiBodyA)
+ {
+
+ c.m_multiBodyA->setCompanionId(-1);
+ btVector3 force = c.m_contactNormal1*(c.m_appliedImpulse/deltaTime);
+ btVector3 torque = c.m_relpos1CrossNormal*(c.m_appliedImpulse/deltaTime);
+ if (c.m_linkA<0)
+ {
+ c.m_multiBodyA->addBaseConstraintForce(force);
+ c.m_multiBodyA->addBaseConstraintTorque(torque);
+ } else
+ {
+ c.m_multiBodyA->addLinkConstraintForce(c.m_linkA,force);
+ //b3Printf("force = %f,%f,%f\n",force[0],force[1],force[2]);//[0],torque[1],torque[2]);
+ c.m_multiBodyA->addLinkConstraintTorque(c.m_linkA,torque);
+ }
+ }
+
+ if (c.m_multiBodyB)
+ {
+ {
+ c.m_multiBodyB->setCompanionId(-1);
+ btVector3 force = c.m_contactNormal2*(c.m_appliedImpulse/deltaTime);
+ btVector3 torque = c.m_relpos2CrossNormal*(c.m_appliedImpulse/deltaTime);
+ if (c.m_linkB<0)
+ {
+ c.m_multiBodyB->addBaseConstraintForce(force);
+ c.m_multiBodyB->addBaseConstraintTorque(torque);
+ } else
+ {
+ {
+ c.m_multiBodyB->addLinkConstraintForce(c.m_linkB,force);
+ //b3Printf("t = %f,%f,%f\n",force[0],force[1],force[2]);//[0],torque[1],torque[2]);
+ c.m_multiBodyB->addLinkConstraintTorque(c.m_linkB,torque);
+ }
+
+ }
+ }
+ }
+#endif
+
+#ifndef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
+
+ 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);
+ }
+ }
+
+ 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);
+ }
+ }
+#endif
+
+
+
+}
+
+btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal)
+{
+ BT_PROFILE("btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish");
+ int numPoolConstraints = m_multiBodyNormalContactConstraints.size();
+
+
+ //write back the delta v to the multi bodies, either as applied impulse (direct velocity change)
+ //or as applied force, so we can measure the joint reaction forces easier
+ for (int i=0;i<numPoolConstraints;i++)
+ {
+ btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[i];
+ writeBackSolverBodyToMultiBody(solverConstraint,infoGlobal.m_timeStep);
+
+ writeBackSolverBodyToMultiBody(m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],infoGlobal.m_timeStep);
+
+ if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
+ {
+ writeBackSolverBodyToMultiBody(m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],infoGlobal.m_timeStep);
+ }
+ }
+
+
+ for (int i=0;i<m_multiBodyNonContactConstraints.size();i++)
+ {
+ btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
+ writeBackSolverBodyToMultiBody(solverConstraint,infoGlobal.m_timeStep);
+ }
+
+
+ if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
+ {
+ BT_PROFILE("warm starting write back");
+ for (int j=0;j<numPoolConstraints;j++)
+ {
+ const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[j];
+ btManifoldPoint* pt = (btManifoldPoint*) solverConstraint.m_originalContactPoint;
+ btAssert(pt);
+ pt->m_appliedImpulse = solverConstraint.m_appliedImpulse;
+ pt->m_appliedImpulseLateral1 = m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse;
+
+ //printf("pt->m_appliedImpulseLateral1 = %f\n", pt->m_appliedImpulseLateral1);
+ if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
+ {
+ pt->m_appliedImpulseLateral2 = m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse;
+ }
+ //do a callback here?
+ }
+ }
+#if 0
+ //multibody joint feedback
+ {
+ BT_PROFILE("multi body joint feedback");
+ for (int j=0;j<numPoolConstraints;j++)
+ {
+ const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[j];
+
+ //apply the joint feedback into all links of the btMultiBody
+ //todo: double-check the signs of the applied impulse
+
+ if(solverConstraint.m_multiBodyA && solverConstraint.m_multiBodyA->isMultiDof())
+ {
+ applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacAindex,solverConstraint.m_multiBodyA, solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
+ }
+ if(solverConstraint.m_multiBodyB && solverConstraint.m_multiBodyB->isMultiDof())
+ {
+ applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacBindex,solverConstraint.m_multiBodyB,solverConstraint.m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
+ }
+#if 0
+ if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA->isMultiDof())
+ {
+ applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_jacAindex,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
+
+ }
+ if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB->isMultiDof())
+ {
+ applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_jacBindex,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
+ }
+
+ if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
+ {
+ if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA->isMultiDof())
+ {
+ applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_jacAindex,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
+ }
+
+ if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB->isMultiDof())
+ {
+ applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_jacBindex,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB,
+ m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
+ }
+ }
+#endif
+ }
+
+ for (int i=0;i<m_multiBodyNonContactConstraints.size();i++)
+ {
+ const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
+ if(solverConstraint.m_multiBodyA && solverConstraint.m_multiBodyA->isMultiDof())
+ {
+ applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacAindex,solverConstraint.m_multiBodyA, solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
+ }
+ if(solverConstraint.m_multiBodyB && solverConstraint.m_multiBodyB->isMultiDof())
+ {
+ applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacBindex,solverConstraint.m_multiBodyB,solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
+ }
+ }
+ }
+
+ numPoolConstraints = m_multiBodyNonContactConstraints.size();
+
+#if 0
+ //@todo: m_originalContactPoint is not initialized for btMultiBodySolverConstraint
+ for (int i=0;i<numPoolConstraints;i++)
+ {
+ const btMultiBodySolverConstraint& c = m_multiBodyNonContactConstraints[i];
+
+ btTypedConstraint* constr = (btTypedConstraint*)c.m_originalContactPoint;
+ btJointFeedback* fb = constr->getJointFeedback();
+ if (fb)
+ {
+ fb->m_appliedForceBodyA += c.m_contactNormal1*c.m_appliedImpulse*constr->getRigidBodyA().getLinearFactor()/infoGlobal.m_timeStep;
+ fb->m_appliedForceBodyB += c.m_contactNormal2*c.m_appliedImpulse*constr->getRigidBodyB().getLinearFactor()/infoGlobal.m_timeStep;
+ fb->m_appliedTorqueBodyA += c.m_relpos1CrossNormal* constr->getRigidBodyA().getAngularFactor()*c.m_appliedImpulse/infoGlobal.m_timeStep;
+ fb->m_appliedTorqueBodyB += c.m_relpos2CrossNormal* constr->getRigidBodyB().getAngularFactor()*c.m_appliedImpulse/infoGlobal.m_timeStep; /*RGM ???? */
+
+ }
+
+ constr->internalSetAppliedImpulse(c.m_appliedImpulse);
+ if (btFabs(c.m_appliedImpulse)>=constr->getBreakingImpulseThreshold())
+ {
+ constr->setEnabled(false);
+ }
+
+ }
+#endif
+#endif
+
+ return btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(bodies,numBodies,infoGlobal);
+}
+
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)
{
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
index 0f4cd69c029..321ee4231a3 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h
@@ -19,6 +19,7 @@ subject to the following restrictions:
#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
#include "btMultiBodySolverConstraint.h"
+#define DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
class btMultiBody;
@@ -43,7 +44,7 @@ protected:
int m_tmpNumMultiBodyConstraints;
void resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c);
- void resolveSingleConstraintRowGenericMultiBody(const btMultiBodySolverConstraint& c);
+
void convertContacts(btPersistentManifold** manifoldPtr,int numManifolds, const btContactSolverInfo& infoGlobal);
btMultiBodySolverConstraint& addMultiBodyFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0, btScalar cfmSlip=0);
@@ -66,14 +67,15 @@ protected:
virtual btScalar solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
void applyDeltaVee(btScalar* deltaV, btScalar impulse, int velocityIndex, int ndof);
-
+ void writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& constraint, btScalar deltaTime);
public:
BT_DECLARE_ALIGNED_ALLOCATOR();
///this method should not be called, it was just used during porting/integration of Featherstone btMultiBody, providing backwards compatibility but no support for btMultiBodyConstraint (only contact constraints)
virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher);
-
+ virtual btScalar solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal);
+
virtual void solveMultiBodyGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher);
};
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
index 0910f8f6abb..a9c0b33b3a3 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp
@@ -20,8 +20,8 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
#include "LinearMath/btQuickprof.h"
#include "btMultiBodyConstraint.h"
-
-
+#include "LinearMath/btIDebugDraw.h"
+#include "LinearMath/btSerializer.h"
void btMultiBodyDynamicsWorld::addMultiBody(btMultiBody* body, short group, short mask)
@@ -364,7 +364,9 @@ struct MultiBodyInplaceSolverIslandCallback : public btSimulationIslandManager::
btCollisionObject** bodies = m_bodies.size()? &m_bodies[0]:0;
btPersistentManifold** manifold = m_manifolds.size()?&m_manifolds[0]:0;
btTypedConstraint** constraints = m_constraints.size()?&m_constraints[0]:0;
- btMultiBodyConstraint** multiBodyConstraints = m_multiBodyConstraints.size() ? &m_multiBodyConstraints[0] : 0;
+ btMultiBodyConstraint** multiBodyConstraints = m_multiBodyConstraints.size() ? &m_multiBodyConstraints[0] : 0;
+
+ //printf("mb contacts = %d, mb constraints = %d\n", mbContacts, m_multiBodyConstraints.size());
m_solver->solveMultiBodyGroup( bodies,m_bodies.size(),manifold, m_manifolds.size(),constraints, m_constraints.size() ,multiBodyConstraints, m_multiBodyConstraints.size(), *m_solverInfo,m_debugDrawer,m_dispatcher);
m_bodies.resize(0);
@@ -392,11 +394,20 @@ btMultiBodyDynamicsWorld::~btMultiBodyDynamicsWorld ()
delete m_solverMultiBodyIslandCallback;
}
+void btMultiBodyDynamicsWorld::forwardKinematics()
+{
+ btAlignedObjectArray<btQuaternion> world_to_local;
+ btAlignedObjectArray<btVector3> local_origin;
-
-
+ for (int b=0;b<m_multiBodies.size();b++)
+ {
+ btMultiBody* bod = m_multiBodies[b];
+ bod->forwardKinematics(world_to_local,local_origin);
+ }
+}
void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
{
+ forwardKinematics();
btAlignedObjectArray<btScalar> scratch_r;
btAlignedObjectArray<btVector3> scratch_v;
@@ -430,9 +441,9 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
/// solve all the constraints for this island
m_islandManager->buildAndProcessIslands(getCollisionWorld()->getDispatcher(),getCollisionWorld(),m_solverMultiBodyIslandCallback);
-
+#ifndef BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
{
- BT_PROFILE("btMultiBody addForce and stepVelocities");
+ BT_PROFILE("btMultiBody addForce");
for (int i=0;i<this->m_multiBodies.size();i++)
{
btMultiBody* bod = m_multiBodies[i];
@@ -451,27 +462,267 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
if (!isSleeping)
{
- scratch_r.resize(bod->getNumLinks()+1);
+ //useless? they get resized in stepVelocities once again (AND DIFFERENTLY)
+ scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd)
scratch_v.resize(bod->getNumLinks()+1);
scratch_m.resize(bod->getNumLinks()+1);
- bod->clearForcesAndTorques();
bod->addBaseForce(m_gravity * bod->getBaseMass());
for (int j = 0; j < bod->getNumLinks(); ++j)
{
bod->addLinkForce(j, m_gravity * bod->getLinkMass(j));
}
+ }//if (!isSleeping)
+ }
+ }
+#endif //BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
+
- bod->stepVelocities(solverInfo.m_timeStep, scratch_r, scratch_v, scratch_m);
- }
+ {
+ BT_PROFILE("btMultiBody stepVelocities");
+ for (int i=0;i<this->m_multiBodies.size();i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b=0;b<bod->getNumLinks();b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState()==ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ //useless? they get resized in stepVelocities once again (AND DIFFERENTLY)
+ scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd)
+ scratch_v.resize(bod->getNumLinks()+1);
+ scratch_m.resize(bod->getNumLinks()+1);
+ bool doNotUpdatePos = false;
+
+ {
+ if(!bod->isUsingRK4Integration())
+ {
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(solverInfo.m_timeStep, scratch_r, scratch_v, scratch_m);
+ }
+ else
+ {
+ //
+ int numDofs = bod->getNumDofs() + 6;
+ int numPosVars = bod->getNumPosVars() + 7;
+ btAlignedObjectArray<btScalar> scratch_r2; scratch_r2.resize(2*numPosVars + 8*numDofs);
+ //convenience
+ btScalar *pMem = &scratch_r2[0];
+ btScalar *scratch_q0 = pMem; pMem += numPosVars;
+ btScalar *scratch_qx = pMem; pMem += numPosVars;
+ btScalar *scratch_qd0 = pMem; pMem += numDofs;
+ btScalar *scratch_qd1 = pMem; pMem += numDofs;
+ btScalar *scratch_qd2 = pMem; pMem += numDofs;
+ btScalar *scratch_qd3 = pMem; pMem += numDofs;
+ btScalar *scratch_qdd0 = pMem; pMem += numDofs;
+ btScalar *scratch_qdd1 = pMem; pMem += numDofs;
+ btScalar *scratch_qdd2 = pMem; pMem += numDofs;
+ btScalar *scratch_qdd3 = pMem; pMem += numDofs;
+ btAssert((pMem - (2*numPosVars + 8*numDofs)) == &scratch_r2[0]);
+
+ /////
+ //copy q0 to scratch_q0 and qd0 to scratch_qd0
+ scratch_q0[0] = bod->getWorldToBaseRot().x();
+ scratch_q0[1] = bod->getWorldToBaseRot().y();
+ scratch_q0[2] = bod->getWorldToBaseRot().z();
+ scratch_q0[3] = bod->getWorldToBaseRot().w();
+ scratch_q0[4] = bod->getBasePos().x();
+ scratch_q0[5] = bod->getBasePos().y();
+ scratch_q0[6] = bod->getBasePos().z();
+ //
+ for(int link = 0; link < bod->getNumLinks(); ++link)
+ {
+ for(int dof = 0; dof < bod->getLink(link).m_posVarCount; ++dof)
+ scratch_q0[7 + bod->getLink(link).m_cfgOffset + dof] = bod->getLink(link).m_jointPos[dof];
+ }
+ //
+ for(int dof = 0; dof < numDofs; ++dof)
+ scratch_qd0[dof] = bod->getVelocityVector()[dof];
+ ////
+ struct
+ {
+ btMultiBody *bod;
+ btScalar *scratch_qx, *scratch_q0;
+
+ void operator()()
+ {
+ for(int dof = 0; dof < bod->getNumPosVars() + 7; ++dof)
+ scratch_qx[dof] = scratch_q0[dof];
+ }
+ } pResetQx = {bod, scratch_qx, scratch_q0};
+ //
+ struct
+ {
+ void operator()(btScalar dt, const btScalar *pDer, const btScalar *pCurVal, btScalar *pVal, int size)
+ {
+ for(int i = 0; i < size; ++i)
+ pVal[i] = pCurVal[i] + dt * pDer[i];
+ }
+
+ } pEulerIntegrate;
+ //
+ struct
+ {
+ void operator()(btMultiBody *pBody, const btScalar *pData)
+ {
+ btScalar *pVel = const_cast<btScalar*>(pBody->getVelocityVector());
+
+ for(int i = 0; i < pBody->getNumDofs() + 6; ++i)
+ pVel[i] = pData[i];
+
+ }
+ } pCopyToVelocityVector;
+ //
+ struct
+ {
+ void operator()(const btScalar *pSrc, btScalar *pDst, int start, int size)
+ {
+ for(int i = 0; i < size; ++i)
+ pDst[i] = pSrc[start + i];
+ }
+ } pCopy;
+ //
+
+ btScalar h = solverInfo.m_timeStep;
+ #define output &scratch_r[bod->getNumDofs()]
+ //calc qdd0 from: q0 & qd0
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m);
+ pCopy(output, scratch_qdd0, 0, numDofs);
+ //calc q1 = q0 + h/2 * qd0
+ pResetQx();
+ bod->stepPositionsMultiDof(btScalar(.5)*h, scratch_qx, scratch_qd0);
+ //calc qd1 = qd0 + h/2 * qdd0
+ pEulerIntegrate(btScalar(.5)*h, scratch_qdd0, scratch_qd0, scratch_qd1, numDofs);
+ //
+ //calc qdd1 from: q1 & qd1
+ pCopyToVelocityVector(bod, scratch_qd1);
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m);
+ pCopy(output, scratch_qdd1, 0, numDofs);
+ //calc q2 = q0 + h/2 * qd1
+ pResetQx();
+ bod->stepPositionsMultiDof(btScalar(.5)*h, scratch_qx, scratch_qd1);
+ //calc qd2 = qd0 + h/2 * qdd1
+ pEulerIntegrate(btScalar(.5)*h, scratch_qdd1, scratch_qd0, scratch_qd2, numDofs);
+ //
+ //calc qdd2 from: q2 & qd2
+ pCopyToVelocityVector(bod, scratch_qd2);
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m);
+ pCopy(output, scratch_qdd2, 0, numDofs);
+ //calc q3 = q0 + h * qd2
+ pResetQx();
+ bod->stepPositionsMultiDof(h, scratch_qx, scratch_qd2);
+ //calc qd3 = qd0 + h * qdd2
+ pEulerIntegrate(h, scratch_qdd2, scratch_qd0, scratch_qd3, numDofs);
+ //
+ //calc qdd3 from: q3 & qd3
+ pCopyToVelocityVector(bod, scratch_qd3);
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m);
+ pCopy(output, scratch_qdd3, 0, numDofs);
+
+ //
+ //calc q = q0 + h/6(qd0 + 2*(qd1 + qd2) + qd3)
+ //calc qd = qd0 + h/6(qdd0 + 2*(qdd1 + qdd2) + qdd3)
+ btAlignedObjectArray<btScalar> delta_q; delta_q.resize(numDofs);
+ btAlignedObjectArray<btScalar> delta_qd; delta_qd.resize(numDofs);
+ for(int i = 0; i < numDofs; ++i)
+ {
+ delta_q[i] = h/btScalar(6.)*(scratch_qd0[i] + 2*scratch_qd1[i] + 2*scratch_qd2[i] + scratch_qd3[i]);
+ delta_qd[i] = h/btScalar(6.)*(scratch_qdd0[i] + 2*scratch_qdd1[i] + 2*scratch_qdd2[i] + scratch_qdd3[i]);
+ //delta_q[i] = h*scratch_qd0[i];
+ //delta_qd[i] = h*scratch_qdd0[i];
+ }
+ //
+ pCopyToVelocityVector(bod, scratch_qd0);
+ bod->applyDeltaVeeMultiDof(&delta_qd[0], 1);
+ //
+ if(!doNotUpdatePos)
+ {
+ btScalar *pRealBuf = const_cast<btScalar *>(bod->getVelocityVector());
+ pRealBuf += 6 + bod->getNumDofs() + bod->getNumDofs()*bod->getNumDofs();
+
+ for(int i = 0; i < numDofs; ++i)
+ pRealBuf[i] = delta_q[i];
+
+ //bod->stepPositionsMultiDof(1, 0, &delta_q[0]);
+ bod->setPosUpdated(true);
+ }
+
+ //ugly hack which resets the cached data to t0 (needed for constraint solver)
+ {
+ for(int link = 0; link < bod->getNumLinks(); ++link)
+ bod->getLink(link).updateCacheMultiDof();
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0, scratch_r, scratch_v, scratch_m);
+ }
+
+ }
+ }
+
+#ifndef BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
+ bod->clearForcesAndTorques();
+#endif //BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
+ }//if (!isSleeping)
}
}
+ clearMultiBodyConstraintForces();
+
m_solverMultiBodyIslandCallback->processConstraints();
m_constraintSolver->allSolved(solverInfo, m_debugDrawer);
+ {
+ BT_PROFILE("btMultiBody stepVelocities");
+ for (int i=0;i<this->m_multiBodies.size();i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b=0;b<bod->getNumLinks();b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState()==ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ //useless? they get resized in stepVelocities once again (AND DIFFERENTLY)
+ scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd)
+ scratch_v.resize(bod->getNumLinks()+1);
+ scratch_m.resize(bod->getNumLinks()+1);
+
+
+ {
+ if(!bod->isUsingRK4Integration())
+ {
+ bool isConstraintPass = true;
+ bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(solverInfo.m_timeStep, scratch_r, scratch_v, scratch_m, isConstraintPass);
+ }
+ }
+ }
+ }
+ }
+
+ for (int i=0;i<this->m_multiBodies.size();i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+ bod->processDeltaVeeMultiDof2();
+ }
+
}
void btMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep)
@@ -503,76 +754,245 @@ void btMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep)
{
int nLinks = bod->getNumLinks();
- ///base + num links
+ ///base + num m_links
+
+
+ {
+ if(!bod->isPosUpdated())
+ bod->stepPositionsMultiDof(timeStep);
+ else
+ {
+ btScalar *pRealBuf = const_cast<btScalar *>(bod->getVelocityVector());
+ pRealBuf += 6 + bod->getNumDofs() + bod->getNumDofs()*bod->getNumDofs();
+
+ bod->stepPositionsMultiDof(1, 0, pRealBuf);
+ bod->setPosUpdated(false);
+ }
+ }
+
world_to_local.resize(nLinks+1);
local_origin.resize(nLinks+1);
- bod->stepPositions(timeStep);
+ bod->updateCollisionObjectWorldTransforms(world_to_local,local_origin);
+
+ } else
+ {
+ bod->clearVelocities();
+ }
+ }
+ }
+}
-
- world_to_local[0] = bod->getWorldToBaseRot();
- local_origin[0] = bod->getBasePos();
- if (bod->getBaseCollider())
- {
- btVector3 posr = local_origin[0];
- float pos[4]={posr.x(),posr.y(),posr.z(),1};
- float quat[4]={-world_to_local[0].x(),-world_to_local[0].y(),-world_to_local[0].z(),world_to_local[0].w()};
- btTransform tr;
- tr.setIdentity();
- tr.setOrigin(posr);
- tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3]));
+void btMultiBodyDynamicsWorld::addMultiBodyConstraint( btMultiBodyConstraint* constraint)
+{
+ m_multiBodyConstraints.push_back(constraint);
+}
- bod->getBaseCollider()->setWorldTransform(tr);
+void btMultiBodyDynamicsWorld::removeMultiBodyConstraint( btMultiBodyConstraint* constraint)
+{
+ m_multiBodyConstraints.remove(constraint);
+}
- }
-
- for (int k=0;k<bod->getNumLinks();k++)
- {
- const int parent = bod->getParent(k);
- world_to_local[k+1] = bod->getParentToLocalRot(k) * world_to_local[parent+1];
- local_origin[k+1] = local_origin[parent+1] + (quatRotate(world_to_local[k+1].inverse() , bod->getRVector(k)));
- }
+void btMultiBodyDynamicsWorld::debugDrawMultiBodyConstraint(btMultiBodyConstraint* constraint)
+{
+ constraint->debugDraw(getDebugDrawer());
+}
- for (int m=0;m<bod->getNumLinks();m++)
- {
- btMultiBodyLinkCollider* col = bod->getLink(m).m_collider;
- if (col)
- {
- int link = col->m_link;
- btAssert(link == m);
+void btMultiBodyDynamicsWorld::debugDrawWorld()
+{
+ BT_PROFILE("btMultiBodyDynamicsWorld debugDrawWorld");
- int index = link+1;
+ bool drawConstraints = false;
+ if (getDebugDrawer())
+ {
+ int mode = getDebugDrawer()->getDebugMode();
+ if (mode & (btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits))
+ {
+ drawConstraints = true;
+ }
- btVector3 posr = local_origin[index];
- float pos[4]={posr.x(),posr.y(),posr.z(),1};
- float quat[4]={-world_to_local[index].x(),-world_to_local[index].y(),-world_to_local[index].z(),world_to_local[index].w()};
- btTransform tr;
- tr.setIdentity();
- tr.setOrigin(posr);
- tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3]));
+ if (drawConstraints)
+ {
+ BT_PROFILE("btMultiBody debugDrawWorld");
+
+ btAlignedObjectArray<btQuaternion> world_to_local1;
+ btAlignedObjectArray<btVector3> local_origin1;
- col->setWorldTransform(tr);
+ for (int c=0;c<m_multiBodyConstraints.size();c++)
+ {
+ btMultiBodyConstraint* constraint = m_multiBodyConstraints[c];
+ debugDrawMultiBodyConstraint(constraint);
+ }
+
+ for (int b = 0; b<m_multiBodies.size(); b++)
+ {
+ btMultiBody* bod = m_multiBodies[b];
+ bod->forwardKinematics(world_to_local1,local_origin1);
+
+ 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);
+
+ //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);
+
+ btVector4 color(0,0,0,1);//1,1,1);
+ btVector3 from = vec+tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
+ btVector3 to = tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
+ getDebugDrawer()->drawLine(from,to,color);
+ }
+ if (bod->getLink(m).m_jointType==btMultibodyLink::eFixed)
+ {
+ btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_bottomVec);
+
+ btVector4 color(0,0,0,1);//1,1,1);
+ btVector3 from = vec+tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
+ btVector3 to = tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
+ getDebugDrawer()->drawLine(from,to,color);
+ }
+ if (bod->getLink(m).m_jointType==btMultibodyLink::ePrismatic)
+ {
+ btVector3 vec = quatRotate(tr.getRotation(),bod->getLink(m).m_axes[0].m_bottomVec);
+
+ btVector4 color(0,0,0,1);//1,1,1);
+ btVector3 from = vec+tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
+ btVector3 to = tr.getOrigin()-quatRotate(tr.getRotation(),bod->getLink(m).m_dVector);
+ getDebugDrawer()->drawLine(from,to,color);
}
+
}
- } else
- {
- bod->clearVelocities();
}
}
}
+
+ btDiscreteDynamicsWorld::debugDrawWorld();
}
-void btMultiBodyDynamicsWorld::addMultiBodyConstraint( btMultiBodyConstraint* constraint)
+void btMultiBodyDynamicsWorld::applyGravity()
{
- m_multiBodyConstraints.push_back(constraint);
+ btDiscreteDynamicsWorld::applyGravity();
+#ifdef BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
+ BT_PROFILE("btMultiBody addGravity");
+ for (int i=0;i<this->m_multiBodies.size();i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b=0;b<bod->getNumLinks();b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState()==ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ bod->addBaseForce(m_gravity * bod->getBaseMass());
+
+ for (int j = 0; j < bod->getNumLinks(); ++j)
+ {
+ bod->addLinkForce(j, m_gravity * bod->getLinkMass(j));
+ }
+ }//if (!isSleeping)
+ }
+#endif //BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
}
-void btMultiBodyDynamicsWorld::removeMultiBodyConstraint( btMultiBodyConstraint* constraint)
+void btMultiBodyDynamicsWorld::clearMultiBodyConstraintForces()
+{
+ for (int i=0;i<this->m_multiBodies.size();i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+ bod->clearConstraintForces();
+ }
+}
+void btMultiBodyDynamicsWorld::clearMultiBodyForces()
{
- m_multiBodyConstraints.remove(constraint);
+ {
+ BT_PROFILE("clearMultiBodyForces");
+ for (int i=0;i<this->m_multiBodies.size();i++)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+
+ bool isSleeping = false;
+
+ if (bod->getBaseCollider() && bod->getBaseCollider()->getActivationState() == ISLAND_SLEEPING)
+ {
+ isSleeping = true;
+ }
+ for (int b=0;b<bod->getNumLinks();b++)
+ {
+ if (bod->getLink(b).m_collider && bod->getLink(b).m_collider->getActivationState()==ISLAND_SLEEPING)
+ isSleeping = true;
+ }
+
+ if (!isSleeping)
+ {
+ btMultiBody* bod = m_multiBodies[i];
+ bod->clearForcesAndTorques();
+ }
+ }
+ }
+
}
+void btMultiBodyDynamicsWorld::clearForces()
+{
+ btDiscreteDynamicsWorld::clearForces();
+
+#ifdef BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
+ clearMultiBodyForces();
+#endif
+}
+
+
+
+
+void btMultiBodyDynamicsWorld::serialize(btSerializer* serializer)
+{
+
+ serializer->startSerialization();
+
+ serializeDynamicsWorldInfo( serializer);
+
+ serializeMultiBodies(serializer);
+
+ serializeRigidBodies(serializer);
+
+ serializeCollisionObjects(serializer);
+
+ serializer->finishSerialization();
+}
+
+void btMultiBodyDynamicsWorld::serializeMultiBodies(btSerializer* serializer)
+{
+ int i;
+ //serialize all collision objects
+ for (i=0;i<m_multiBodies.size();i++)
+ {
+ btMultiBody* mb = m_multiBodies[i];
+ {
+ int len = mb->calculateSerializeBufferSize();
+ btChunk* chunk = serializer->allocate(len,1);
+ const char* structType = mb->serialize(chunk->m_oldPtr, serializer);
+ serializer->finalizeChunk(chunk,structType,BT_MULTIBODY_CODE,mb);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
index ad57a346dcc..03ef3335c22 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -18,6 +18,7 @@ subject to the following restrictions:
#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
+#define BT_USE_VIRTUAL_CLEARFORCES_AND_GRAVITY
class btMultiBody;
class btMultiBodyConstraint;
@@ -38,19 +39,61 @@ protected:
virtual void calculateSimulationIslands();
virtual void updateActivationState(btScalar timeStep);
virtual void solveConstraints(btContactSolverInfo& solverInfo);
- virtual void integrateTransforms(btScalar timeStep);
+
+ virtual void serializeMultiBodies(btSerializer* serializer);
+
public:
btMultiBodyDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btMultiBodyConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration);
-
+
virtual ~btMultiBodyDynamicsWorld ();
virtual void addMultiBody(btMultiBody* body, short group= btBroadphaseProxy::DefaultFilter, short mask=btBroadphaseProxy::AllFilter);
virtual void removeMultiBody(btMultiBody* body);
+ virtual int getNumMultibodies() const
+ {
+ return m_multiBodies.size();
+ }
+
+ btMultiBody* getMultiBody(int mbIndex)
+ {
+ return m_multiBodies[mbIndex];
+ }
+
virtual void addMultiBodyConstraint( btMultiBodyConstraint* constraint);
+ virtual int getNumMultiBodyConstraints() const
+ {
+ return m_multiBodyConstraints.size();
+ }
+
+ virtual btMultiBodyConstraint* getMultiBodyConstraint( int constraintIndex)
+ {
+ return m_multiBodyConstraints[constraintIndex];
+ }
+
+ virtual const btMultiBodyConstraint* getMultiBodyConstraint( int constraintIndex) const
+ {
+ return m_multiBodyConstraints[constraintIndex];
+ }
+
virtual void removeMultiBodyConstraint( btMultiBodyConstraint* constraint);
+
+ virtual void integrateTransforms(btScalar timeStep);
+
+ virtual void debugDrawWorld();
+
+ virtual void debugDrawMultiBodyConstraint(btMultiBodyConstraint* constraint);
+
+ void forwardKinematics();
+ virtual void clearForces();
+ virtual void clearMultiBodyConstraintForces();
+ virtual void clearMultiBodyForces();
+ virtual void applyGravity();
+
+ virtual void serialize(btSerializer* serializer);
+
};
#endif //BT_MULTIBODY_DYNAMICS_WORLD_H
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h
new file mode 100644
index 00000000000..5c2fa8ed5b9
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h
@@ -0,0 +1,27 @@
+/*
+Copyright (c) 2015 Google Inc.
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+
+#ifndef BT_MULTIBODY_JOINT_FEEDBACK_H
+#define BT_MULTIBODY_JOINT_FEEDBACK_H
+
+#include "LinearMath/btSpatialAlgebra.h"
+
+struct btMultiBodyJointFeedback
+{
+ btSpatialForceVector m_reactionForces;
+};
+
+#endif //BT_MULTIBODY_JOINT_FEEDBACK_H
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
index ea309e8857d..3f05aa4d5fa 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -21,51 +21,68 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
+
btMultiBodyJointLimitConstraint::btMultiBodyJointLimitConstraint(btMultiBody* body, int link, btScalar lower, btScalar upper)
- :btMultiBodyConstraint(body,body,link,link,2,true),
+ //:btMultiBodyConstraint(body,0,link,-1,2,true),
+ :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,2,true),
m_lowerBound(lower),
m_upperBound(upper)
{
+
+}
+
+void btMultiBodyJointLimitConstraint::finalizeMultiDof()
+{
// the data.m_jacobians never change, so may as well
// initialize them here
-
- // note: we rely on the fact that data.m_jacobians are
- // always initialized to zero by the Constraint ctor
- // row 0: the lower bound
- jacobianA(0)[6 + link] = 1;
+ allocateJacobiansMultiDof();
- // row 1: the upper bound
- jacobianB(1)[6 + link] = -1;
+ unsigned int offset = 6 + m_bodyA->getLink(m_linkA).m_dofOffset;
+
+ // row 0: the lower bound
+ jacobianA(0)[offset] = 1;
+ // row 1: the upper bound
+ //jacobianA(1)[offset] = -1;
+ jacobianB(1)[offset] = -1;
+
+ m_numDofsFinalized = m_jacSizeBoth;
}
+
btMultiBodyJointLimitConstraint::~btMultiBodyJointLimitConstraint()
{
}
int btMultiBodyJointLimitConstraint::getIslandIdA() const
{
- btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider();
- if (col)
- return col->getIslandTag();
- for (int i=0;i<m_bodyA->getNumLinks();i++)
+ if(m_bodyA)
{
- 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();
+ for (int i=0;i<m_bodyA->getNumLinks();i++)
+ {
+ if (m_bodyA->getLink(i).m_collider)
+ return m_bodyA->getLink(i).m_collider->getIslandTag();
+ }
}
return -1;
}
int btMultiBodyJointLimitConstraint::getIslandIdB() const
{
- btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
- if (col)
- return col->getIslandTag();
-
- for (int i=0;i<m_bodyB->getNumLinks();i++)
+ if(m_bodyB)
{
- col = m_bodyB->getLink(i).m_collider;
+ btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider();
if (col)
return col->getIslandTag();
+
+ for (int i=0;i<m_bodyB->getNumLinks();i++)
+ {
+ col = m_bodyB->getLink(i).m_collider;
+ if (col)
+ return col->getIslandTag();
+ }
}
return -1;
}
@@ -75,22 +92,71 @@ void btMultiBodyJointLimitConstraint::createConstraintRows(btMultiBodyConstraint
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal)
{
+
// only positions need to be updated -- data.m_jacobians and force
// directions were set in the ctor and never change.
-
+
+ if (m_numDofsFinalized != m_jacSizeBoth)
+ {
+ finalizeMultiDof();
+ }
+
+
// row 0: the lower bound
- setPosition(0, m_bodyA->getJointPos(m_linkA) - m_lowerBound);
+ setPosition(0, m_bodyA->getJointPos(m_linkA) - m_lowerBound); //multidof: this is joint-type dependent
// row 1: the upper bound
setPosition(1, m_upperBound - m_bodyA->getJointPos(m_linkA));
-
+
for (int row=0;row<getNumRows();row++)
{
+
+ btScalar direction = row? -1 : 1;
+
btMultiBodySolverConstraint& constraintRow = constraintRows.expandNonInitializing();
+ constraintRow.m_orgConstraint = this;
+ constraintRow.m_orgDofIndex = row;
+
constraintRow.m_multiBodyA = m_bodyA;
constraintRow.m_multiBodyB = m_bodyB;
-
- btScalar rel_vel = fillConstraintRowMultiBodyMultiBody(constraintRow,data,jacobianA(row),jacobianB(row),infoGlobal,0,-m_maxAppliedImpulse,m_maxAppliedImpulse);
+ const btScalar posError = 0; //why assume it's zero?
+ const btVector3 dummy(0, 0, 0);
+
+ btScalar rel_vel = fillMultiBodyConstraint(constraintRow,data,jacobianA(row),jacobianB(row),dummy,dummy,dummy,posError,infoGlobal,0,m_maxAppliedImpulse);
+
+ {
+ //expect either prismatic or revolute joint type for now
+ btAssert((m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::eRevolute)||(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::ePrismatic));
+ switch (m_bodyA->getLink(m_linkA).m_jointType)
+ {
+ case btMultibodyLink::eRevolute:
+ {
+ constraintRow.m_contactNormal1.setZero();
+ constraintRow.m_contactNormal2.setZero();
+ btVector3 revoluteAxisInWorld = direction*quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_topVec);
+ constraintRow.m_relpos1CrossNormal=revoluteAxisInWorld;
+ constraintRow.m_relpos2CrossNormal=-revoluteAxisInWorld;
+
+ break;
+ }
+ case btMultibodyLink::ePrismatic:
+ {
+ btVector3 prismaticAxisInWorld = direction* quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_bottomVec);
+ constraintRow.m_contactNormal1=prismaticAxisInWorld;
+ constraintRow.m_contactNormal2=-prismaticAxisInWorld;
+ constraintRow.m_relpos1CrossNormal.setZero();
+ constraintRow.m_relpos2CrossNormal.setZero();
+
+ break;
+ }
+ default:
+ {
+ btAssert(0);
+ }
+ };
+
+ }
+
{
btScalar penetration = getPosition(row);
btScalar positionalError = 0.f;
@@ -127,7 +193,7 @@ void btMultiBodyJointLimitConstraint::createConstraintRows(btMultiBodyConstraint
}
}
-
-
-
+
+
+
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
index 0c7fc170822..55b8d122b97 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -30,14 +30,20 @@ public:
btMultiBodyJointLimitConstraint(btMultiBody* body, int link, btScalar lower, btScalar upper);
virtual ~btMultiBodyJointLimitConstraint();
+ virtual void finalizeMultiDof();
+
virtual int getIslandIdA() const;
virtual int getIslandIdB() const;
virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal);
-
-
+
+ virtual void debugDraw(class btIDebugDraw* drawer)
+ {
+ //todo(erwincoumans)
+ }
+
};
#endif //BT_MULTIBODY_JOINT_LIMIT_CONSTRAINT_H
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
index ab5a430231b..062d19accaa 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -22,18 +22,41 @@ subject to the following restrictions:
btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse)
- :btMultiBodyConstraint(body,body,link,link,1,true),
- m_desiredVelocity(desiredVelocity)
+ :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,1,true),
+ m_desiredVelocity(desiredVelocity)
{
+
m_maxAppliedImpulse = maxMotorImpulse;
// the data.m_jacobians never change, so may as well
// initialize them here
-
- // note: we rely on the fact that data.m_jacobians are
- // always initialized to zero by the Constraint ctor
- // row 0: the lower bound
- jacobianA(0)[6 + link] = 1;
+
+}
+
+void btMultiBodyJointMotor::finalizeMultiDof()
+{
+ allocateJacobiansMultiDof();
+ // note: we rely on the fact that data.m_jacobians are
+ // always initialized to zero by the Constraint ctor
+ int linkDoF = 0;
+ unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF);
+
+ // row 0: the lower bound
+ // row 0: the lower bound
+ jacobianA(0)[offset] = 1;
+
+ m_numDofsFinalized = m_jacSizeBoth;
+}
+
+btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse)
+ //:btMultiBodyConstraint(body,0,link,-1,1,true),
+ :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,1,true),
+ m_desiredVelocity(desiredVelocity)
+{
+ btAssert(linkDoF < body->getLink(link).m_dofCount);
+
+ m_maxAppliedImpulse = maxMotorImpulse;
+
}
btMultiBodyJointMotor::~btMultiBodyJointMotor()
{
@@ -74,16 +97,61 @@ void btMultiBodyJointMotor::createConstraintRows(btMultiBodyConstraintArray& con
{
// only positions need to be updated -- data.m_jacobians and force
// directions were set in the ctor and never change.
-
-
+
+ if (m_numDofsFinalized != m_jacSizeBoth)
+ {
+ finalizeMultiDof();
+ }
+
+ //don't crash
+ if (m_numDofsFinalized != m_jacSizeBoth)
+ return;
+
+ const btScalar posError = 0;
+ const btVector3 dummy(0, 0, 0);
for (int row=0;row<getNumRows();row++)
{
btMultiBodySolverConstraint& constraintRow = constraintRows.expandNonInitializing();
-
- btScalar penetration = 0;
- fillConstraintRowMultiBodyMultiBody(constraintRow,data,jacobianA(row),jacobianB(row),infoGlobal,m_desiredVelocity,-m_maxAppliedImpulse,m_maxAppliedImpulse);
+
+
+ fillMultiBodyConstraint(constraintRow,data,jacobianA(row),jacobianB(row),dummy,dummy,dummy,posError,infoGlobal,-m_maxAppliedImpulse,m_maxAppliedImpulse,1,false,m_desiredVelocity);
+ constraintRow.m_orgConstraint = this;
+ constraintRow.m_orgDofIndex = row;
+ {
+ //expect either prismatic or revolute joint type for now
+ btAssert((m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::eRevolute)||(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::ePrismatic));
+ switch (m_bodyA->getLink(m_linkA).m_jointType)
+ {
+ case btMultibodyLink::eRevolute:
+ {
+ constraintRow.m_contactNormal1.setZero();
+ constraintRow.m_contactNormal2.setZero();
+ btVector3 revoluteAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_topVec);
+ constraintRow.m_relpos1CrossNormal=revoluteAxisInWorld;
+ constraintRow.m_relpos2CrossNormal=-revoluteAxisInWorld;
+
+ break;
+ }
+ case btMultibodyLink::ePrismatic:
+ {
+ btVector3 prismaticAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_bottomVec);
+ constraintRow.m_contactNormal1=prismaticAxisInWorld;
+ constraintRow.m_contactNormal2=-prismaticAxisInWorld;
+ constraintRow.m_relpos1CrossNormal.setZero();
+ constraintRow.m_relpos2CrossNormal.setZero();
+
+ break;
+ }
+ default:
+ {
+ btAssert(0);
+ }
+ };
+
+ }
+
}
}
-
+
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h
index 43869348141..011aadcfa4b 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -25,13 +25,15 @@ class btMultiBodyJointMotor : public btMultiBodyConstraint
{
protected:
-
+
btScalar m_desiredVelocity;
public:
btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse);
+ btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse);
virtual ~btMultiBodyJointMotor();
+ virtual void finalizeMultiDof();
virtual int getIslandIdA() const;
virtual int getIslandIdB() const;
@@ -39,8 +41,16 @@ public:
virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows,
btMultiBodyJacobianData& data,
const btContactSolverInfo& infoGlobal);
-
-
+
+ virtual void setVelocityTarget(btScalar velTarget)
+ {
+ m_desiredVelocity = velTarget;
+ }
+
+ virtual void debugDraw(class btIDebugDraw* drawer)
+ {
+ //todo(erwincoumans)
+ }
};
#endif //BT_MULTIBODY_JOINT_MOTOR_H
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h
index fbd54c45db3..668e4443904 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h
@@ -24,84 +24,193 @@ enum btMultiBodyLinkFlags
{
BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION = 1
};
+
+//both defines are now permanently enabled
+#define BT_MULTIBODYLINK_INCLUDE_PLANAR_JOINTS
+#define TEST_SPATIAL_ALGEBRA_LAYER
+
//
-// Link struct
+// Various spatial helper functions
//
-struct btMultibodyLink
-{
+//namespace {
- BT_DECLARE_ALIGNED_ALLOCATOR();
- btScalar joint_pos; // qi
+#include "LinearMath/btSpatialAlgebra.h"
- btScalar mass; // mass of link
- btVector3 inertia; // inertia of link (local frame; diagonal)
+//}
- int parent; // index of the parent link (assumed to be < index of this link), or -1 if parent is the base link.
+//
+// Link struct
+//
- btQuaternion zero_rot_parent_to_this; // rotates vectors in parent-frame to vectors in local-frame (when q=0). constant.
+struct btMultibodyLink
+{
- // "axis" = spatial joint axis (Mirtich Defn 9 p104). (expressed in local frame.) constant.
- // for prismatic: axis_top = zero;
- // axis_bottom = unit vector along the joint axis.
- // for revolute: axis_top = unit vector along the rotation axis (u);
- // axis_bottom = u cross d_vector.
- btVector3 axis_top;
- btVector3 axis_bottom;
+ BT_DECLARE_ALIGNED_ALLOCATOR();
- btVector3 d_vector; // vector from the inboard joint pos to this link's COM. (local frame.) constant. set for revolute joints only.
+ btScalar m_mass; // mass of link
+ btVector3 m_inertiaLocal; // inertia of link (local frame; diagonal)
- // e_vector is constant, but depends on the joint type
- // prismatic: vector from COM of parent to COM of this link, WHEN Q = 0. (local frame.)
- // revolute: vector from parent's COM to the pivot point, in PARENT's frame.
- btVector3 e_vector;
+ int m_parent; // index of the parent link (assumed to be < index of this link), or -1 if parent is the base link.
- bool is_revolute; // true = revolute, false = prismatic
+ btQuaternion m_zeroRotParentToThis; // rotates vectors in parent-frame to vectors in local-frame (when q=0). constant.
- btQuaternion cached_rot_parent_to_this; // rotates vectors in parent frame to vectors in local frame
- btVector3 cached_r_vector; // vector from COM of parent to COM of this link, in local frame.
+ btVector3 m_dVector; // vector from the inboard joint pos to this link's COM. (local frame.) constant.
+ //this is set to zero for planar joint (see also m_eVector comment)
+
+ // m_eVector is constant, but depends on the joint type:
+ // revolute, fixed, prismatic, spherical: vector from parent's COM to the pivot point, in PARENT's frame.
+ // planar: vector from COM of parent to COM of this link, WHEN Q = 0. (local frame.)
+ // todo: fix the planar so it is consistent with the other joints
+
+ btVector3 m_eVector;
- btVector3 applied_force; // In WORLD frame
- btVector3 applied_torque; // In WORLD frame
- btScalar joint_torque;
+ btSpatialMotionVector m_absFrameTotVelocity, m_absFrameLocVelocity;
+ enum eFeatherstoneJointType
+ {
+ eRevolute = 0,
+ ePrismatic = 1,
+ eSpherical = 2,
+ ePlanar = 3,
+ eFixed = 4,
+ eInvalid
+ };
+
+
+
+ // "axis" = spatial joint axis (Mirtich Defn 9 p104). (expressed in local frame.) constant.
+ // for prismatic: m_axesTop[0] = zero;
+ // m_axesBottom[0] = unit vector along the joint axis.
+ // for revolute: m_axesTop[0] = unit vector along the rotation axis (u);
+ // m_axesBottom[0] = u cross m_dVector (i.e. COM linear motion due to the rotation at the joint)
+ //
+ // for spherical: m_axesTop[0][1][2] (u1,u2,u3) form a 3x3 identity matrix (3 rotation axes)
+ // m_axesBottom[0][1][2] cross u1,u2,u3 (i.e. COM linear motion due to the rotation at the joint)
+ //
+ // for planar: m_axesTop[0] = unit vector along the rotation axis (u); defines the plane of motion
+ // m_axesTop[1][2] = zero
+ // m_axesBottom[0] = zero
+ // m_axesBottom[1][2] = unit vectors along the translational axes on that plane
+ btSpatialMotionVector m_axes[6];
+ void setAxisTop(int dof, const btVector3 &axis) { m_axes[dof].m_topVec = axis; }
+ void setAxisBottom(int dof, const btVector3 &axis) { m_axes[dof].m_bottomVec = axis; }
+ void setAxisTop(int dof, const btScalar &x, const btScalar &y, const btScalar &z) { m_axes[dof].m_topVec.setValue(x, y, z); }
+ void setAxisBottom(int dof, const btScalar &x, const btScalar &y, const btScalar &z) { m_axes[dof].m_bottomVec.setValue(x, y, z); }
+ const btVector3 & getAxisTop(int dof) const { return m_axes[dof].m_topVec; }
+ const btVector3 & getAxisBottom(int dof) const { return m_axes[dof].m_bottomVec; }
+
+ int m_dofOffset, m_cfgOffset;
+
+ btQuaternion m_cachedRotParentToThis; // rotates vectors in parent frame to vectors in local frame
+ btVector3 m_cachedRVector; // vector from COM of parent to COM of this link, in local frame.
+
+ btVector3 m_appliedForce; // In WORLD frame
+ btVector3 m_appliedTorque; // In WORLD frame
+
+btVector3 m_appliedConstraintForce; // In WORLD frame
+ btVector3 m_appliedConstraintTorque; // In WORLD frame
+
+ btScalar m_jointPos[7];
+
+ //m_jointTorque is the joint torque applied by the user using 'addJointTorque'.
+ //It gets set to zero after each internal stepSimulation call
+ btScalar m_jointTorque[6];
+
class btMultiBodyLinkCollider* m_collider;
int m_flags;
+
+
+ int m_dofCount, m_posVarCount; //redundant but handy
+
+ eFeatherstoneJointType m_jointType;
+
+ struct btMultiBodyJointFeedback* m_jointFeedback;
+
+ btTransform m_cachedWorldTransform;//this cache is updated when calling btMultiBody::forwardKinematics
+
+ const char* m_linkName;//m_linkName memory needs to be managed by the developer/user!
+ const char* m_jointName;//m_jointName memory needs to be managed by the developer/user!
// ctor: set some sensible defaults
btMultibodyLink()
- : joint_pos(0),
- mass(1),
- parent(-1),
- zero_rot_parent_to_this(1, 0, 0, 0),
- is_revolute(false),
- cached_rot_parent_to_this(1, 0, 0, 0),
- joint_torque(0),
+ : m_mass(1),
+ m_parent(-1),
+ m_zeroRotParentToThis(0, 0, 0, 1),
+ m_cachedRotParentToThis(0, 0, 0, 1),
m_collider(0),
- m_flags(0)
+ m_flags(0),
+ m_dofCount(0),
+ m_posVarCount(0),
+ m_jointType(btMultibodyLink::eInvalid),
+ m_jointFeedback(0),
+ m_linkName(0),
+ m_jointName(0)
{
- inertia.setValue(1, 1, 1);
- axis_top.setValue(0, 0, 0);
- axis_bottom.setValue(1, 0, 0);
- d_vector.setValue(0, 0, 0);
- e_vector.setValue(0, 0, 0);
- cached_r_vector.setValue(0, 0, 0);
- applied_force.setValue( 0, 0, 0);
- applied_torque.setValue(0, 0, 0);
+
+ m_inertiaLocal.setValue(1, 1, 1);
+ setAxisTop(0, 0., 0., 0.);
+ setAxisBottom(0, 1., 0., 0.);
+ m_dVector.setValue(0, 0, 0);
+ m_eVector.setValue(0, 0, 0);
+ m_cachedRVector.setValue(0, 0, 0);
+ m_appliedForce.setValue( 0, 0, 0);
+ m_appliedTorque.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"
+ m_jointTorque[0] = m_jointTorque[1] = m_jointTorque[2] = m_jointTorque[3] = m_jointTorque[4] = m_jointTorque[5] = 0.f;
+ m_cachedWorldTransform.setIdentity();
}
- // routine to update cached_rot_parent_to_this and cached_r_vector
- void updateCache()
+ // routine to update m_cachedRotParentToThis and m_cachedRVector
+ void updateCacheMultiDof(btScalar *pq = 0)
{
- if (is_revolute)
- {
- cached_rot_parent_to_this = btQuaternion(axis_top,-joint_pos) * zero_rot_parent_to_this;
- cached_r_vector = d_vector + quatRotate(cached_rot_parent_to_this,e_vector);
- } else
+ btScalar *pJointPos = (pq ? pq : &m_jointPos[0]);
+
+ switch(m_jointType)
{
- // cached_rot_parent_to_this never changes, so no need to update
- cached_r_vector = e_vector + joint_pos * axis_bottom;
+ case eRevolute:
+ {
+ m_cachedRotParentToThis = btQuaternion(getAxisTop(0),-pJointPos[0]) * m_zeroRotParentToThis;
+ m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector);
+
+ break;
+ }
+ case ePrismatic:
+ {
+ // m_cachedRotParentToThis never changes, so no need to update
+ m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector) + pJointPos[0] * getAxisBottom(0);
+
+ break;
+ }
+ case eSpherical:
+ {
+ m_cachedRotParentToThis = btQuaternion(pJointPos[0], pJointPos[1], pJointPos[2], -pJointPos[3]) * m_zeroRotParentToThis;
+ m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector);
+
+ break;
+ }
+ case ePlanar:
+ {
+ m_cachedRotParentToThis = btQuaternion(getAxisTop(0),-pJointPos[0]) * m_zeroRotParentToThis;
+ m_cachedRVector = quatRotate(btQuaternion(getAxisTop(0),-pJointPos[0]), pJointPos[1] * getAxisBottom(1) + pJointPos[2] * getAxisBottom(2)) + quatRotate(m_cachedRotParentToThis,m_eVector);
+
+ break;
+ }
+ case eFixed:
+ {
+ m_cachedRotParentToThis = m_zeroRotParentToThis;
+ m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector);
+
+ break;
+ }
+ default:
+ {
+ //invalid type
+ btAssert(0);
+ }
}
}
};
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
index 27f12514a6d..5080ea87454 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h
@@ -74,14 +74,14 @@ public:
if (m_link>=0)
{
const btMultibodyLink& link = m_multiBody->getLink(this->m_link);
- if ((link.m_flags&BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) && link.parent == other->m_link)
+ if ((link.m_flags&BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) && link.m_parent == other->m_link)
return false;
}
if (other->m_link>=0)
{
const btMultibodyLink& otherLink = other->m_multiBody->getLink(other->m_link);
- if ((otherLink.m_flags& BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) && otherLink.parent == this->m_link)
+ if ((otherLink.m_flags& BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) && otherLink.m_parent == this->m_link)
return false;
}
return true;
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
index f6690049156..12b21f74603 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -18,25 +18,39 @@ subject to the following restrictions:
#include "btMultiBodyPoint2Point.h"
#include "btMultiBodyLinkCollider.h"
#include "BulletDynamics/Dynamics/btRigidBody.h"
+#include "LinearMath/btIDebugDraw.h"
+
+#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST
+ #define BTMBP2PCONSTRAINT_DIM 3
+#else
+ #define BTMBP2PCONSTRAINT_DIM 6
+#endif
btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB)
- :btMultiBodyConstraint(body,0,link,-1,3,false),
+ :btMultiBodyConstraint(body,0,link,-1,BTMBP2PCONSTRAINT_DIM,false),
m_rigidBodyA(0),
m_rigidBodyB(bodyB),
m_pivotInA(pivotInA),
m_pivotInB(pivotInB)
{
+ m_data.resize(BTMBP2PCONSTRAINT_DIM);//at least store the applied impulses
}
btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB)
- :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,3,false),
+ :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,BTMBP2PCONSTRAINT_DIM,false),
m_rigidBodyA(0),
m_rigidBodyB(0),
m_pivotInA(pivotInA),
m_pivotInB(pivotInB)
{
+ m_data.resize(BTMBP2PCONSTRAINT_DIM);//at least store the applied impulses
}
+void btMultiBodyPoint2Point::finalizeMultiDof()
+{
+ //not implemented yet
+ btAssert(0);
+}
btMultiBodyPoint2Point::~btMultiBodyPoint2Point()
{
@@ -90,25 +104,37 @@ void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& co
{
// int i=1;
- for (int i=0;i<3;i++)
+int numDim = BTMBP2PCONSTRAINT_DIM;
+ for (int i=0;i<numDim;i++)
{
btMultiBodySolverConstraint& constraintRow = constraintRows.expandNonInitializing();
+ //memset(&constraintRow,0xffffffff,sizeof(btMultiBodySolverConstraint));
+ constraintRow.m_orgConstraint = this;
+ constraintRow.m_orgDofIndex = i;
+ constraintRow.m_relpos1CrossNormal.setValue(0,0,0);
+ constraintRow.m_contactNormal1.setValue(0,0,0);
+ constraintRow.m_relpos2CrossNormal.setValue(0,0,0);
+ constraintRow.m_contactNormal2.setValue(0,0,0);
+ constraintRow.m_angularComponentA.setValue(0,0,0);
+ constraintRow.m_angularComponentB.setValue(0,0,0);
constraintRow.m_solverBodyIdA = data.m_fixedBodyId;
constraintRow.m_solverBodyIdB = data.m_fixedBodyId;
-
btVector3 contactNormalOnB(0,0,0);
+#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST
contactNormalOnB[i] = -1;
+#else
+ contactNormalOnB[i%3] = -1;
+#endif
- btScalar penetration = 0;
// Convert local points back to world
btVector3 pivotAworld = m_pivotInA;
if (m_rigidBodyA)
{
-
+
constraintRow.m_solverBodyIdA = m_rigidBodyA->getCompanionId();
pivotAworld = m_rigidBodyA->getCenterOfMassTransform()*m_pivotInA;
} else
@@ -125,19 +151,71 @@ void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& co
{
if (m_bodyB)
pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB);
-
+
}
- btScalar position = (pivotAworld-pivotBworld).dot(contactNormalOnB);
- btScalar relaxation = 1.f;
- fillMultiBodyConstraintMixed(constraintRow, data,
- contactNormalOnB,
- pivotAworld, pivotBworld,
- position,
- infoGlobal,
- relaxation,
- false);
- constraintRow.m_lowerLimit = -m_maxAppliedImpulse;
- constraintRow.m_upperLimit = m_maxAppliedImpulse;
+ btScalar posError = i < 3 ? (pivotAworld-pivotBworld).dot(contactNormalOnB) : 0;
+
+#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST
+
+
+ fillMultiBodyConstraint(constraintRow, data, 0, 0,
+ contactNormalOnB, pivotAworld, pivotBworld, //sucks but let it be this way "for the time being"
+ posError,
+ infoGlobal,
+ -m_maxAppliedImpulse, m_maxAppliedImpulse
+ );
+ //@todo: support the case of btMultiBody versus btRigidBody,
+ //see btPoint2PointConstraint::getInfo2NonVirtual
+#else
+ const btVector3 dummy(0, 0, 0);
+
+ btAssert(m_bodyA->isMultiDof());
+
+ btScalar* jac1 = jacobianA(i);
+ const btVector3 &normalAng = i >= 3 ? contactNormalOnB : dummy;
+ const btVector3 &normalLin = i < 3 ? contactNormalOnB : dummy;
+
+ m_bodyA->filConstraintJacobianMultiDof(m_linkA, pivotAworld, normalAng, normalLin, jac1, data.scratch_r, data.scratch_v, data.scratch_m);
+
+ fillMultiBodyConstraint(constraintRow, data, jac1, 0,
+ dummy, dummy, dummy, //sucks but let it be this way "for the time being"
+ posError,
+ infoGlobal,
+ -m_maxAppliedImpulse, m_maxAppliedImpulse
+ );
+#endif
+ }
+}
+
+void btMultiBodyPoint2Point::debugDraw(class btIDebugDraw* drawer)
+{
+ btTransform tr;
+ tr.setIdentity();
+
+ if (m_rigidBodyA)
+ {
+ btVector3 pivot = m_rigidBodyA->getCenterOfMassTransform() * m_pivotInA;
+ tr.setOrigin(pivot);
+ drawer->drawTransform(tr, 0.1);
+ }
+ if (m_bodyA)
+ {
+ btVector3 pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA);
+ tr.setOrigin(pivotAworld);
+ drawer->drawTransform(tr, 0.1);
+ }
+ if (m_rigidBodyB)
+ {
+ // that ideally should draw the same frame
+ btVector3 pivot = m_rigidBodyB->getCenterOfMassTransform() * m_pivotInB;
+ tr.setOrigin(pivot);
+ drawer->drawTransform(tr, 0.1);
+ }
+ if (m_bodyB)
+ {
+ btVector3 pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB);
+ tr.setOrigin(pivotBworld);
+ drawer->drawTransform(tr, 0.1);
}
}
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h
index 26ca12b406d..b2e219ac159 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h
@@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -20,6 +20,8 @@ subject to the following restrictions:
#include "btMultiBodyConstraint.h"
+//#define BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST
+
class btMultiBodyPoint2Point : public btMultiBodyConstraint
{
protected:
@@ -28,7 +30,7 @@ protected:
btRigidBody* m_rigidBodyB;
btVector3 m_pivotInA;
btVector3 m_pivotInB;
-
+
public:
@@ -37,6 +39,8 @@ public:
virtual ~btMultiBodyPoint2Point();
+ virtual void finalizeMultiDof();
+
virtual int getIslandIdA() const;
virtual int getIslandIdB() const;
@@ -54,7 +58,8 @@ public:
m_pivotInB = pivotInB;
}
-
+ virtual void debugDraw(class btIDebugDraw* drawer);
+
};
#endif //BT_MULTIBODY_POINT2POINT_H
diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h
index cf06dfb9ebf..6fa1550e9e6 100644
--- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h
+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h
@@ -20,6 +20,7 @@ subject to the following restrictions:
#include "LinearMath/btAlignedObjectArray.h"
class btMultiBody;
+class btMultiBodyConstraint;
#include "BulletDynamics/ConstraintSolver/btSolverBody.h"
#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
@@ -28,16 +29,19 @@ ATTRIBUTE_ALIGNED16 (struct) btMultiBodySolverConstraint
{
BT_DECLARE_ALIGNED_ALLOCATOR();
+ btMultiBodySolverConstraint() : m_solverBodyIdA(-1), m_multiBodyA(0), m_linkA(-1), m_solverBodyIdB(-1), m_multiBodyB(0), m_linkB(-1),m_orgConstraint(0), m_orgDofIndex(-1)
+ {}
int m_deltaVelAindex;//more generic version of m_relpos1CrossNormal/m_contactNormal1
- btVector3 m_relpos1CrossNormal;
- btVector3 m_contactNormal1;
int m_jacAindex;
-
int m_deltaVelBindex;
+ int m_jacBindex;
+
+ btVector3 m_relpos1CrossNormal;
+ btVector3 m_contactNormal1;
btVector3 m_relpos2CrossNormal;
btVector3 m_contactNormal2; //usually m_contactNormal2 == -m_contactNormal1, but not always
- int m_jacBindex;
+
btVector3 m_angularComponentA;
btVector3 m_angularComponentB;
@@ -70,6 +74,10 @@ ATTRIBUTE_ALIGNED16 (struct) btMultiBodySolverConstraint
btMultiBody* m_multiBodyB;
int m_linkB;
+ //for writing back applied impulses
+ btMultiBodyConstraint* m_orgConstraint;
+ int m_orgDofIndex;
+
enum btSolverConstraintType
{
BT_SOLVER_CONTACT_1D = 0,
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp
index 3bf7b5c1311..986f2148701 100644
--- a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp
@@ -821,14 +821,15 @@ void btSolveL1T (const btScalar *L, btScalar *B, int n, int lskip1)
/* declare variables - Z matrix, p and q vectors, etc */
btScalar Z11,m11,Z21,m21,Z31,m31,Z41,m41,p1,q1,p2,p3,p4,*ex;
const btScalar *ell;
- int lskip2,lskip3,i,j;
+ int lskip2,i,j;
+// int lskip3;
/* special handling for L and B because we're solving L1 *transpose* */
L = L + (n-1)*(lskip1+1);
B = B + n-1;
lskip1 = -lskip1;
/* compute lskip values */
lskip2 = 2*lskip1;
- lskip3 = 3*lskip1;
+ //lskip3 = 3*lskip1;
/* compute all 4 x 1 blocks of X */
for (i=0; i <= n-4; i+=4) {
/* compute all 4 x 1 block of X, from rows i..i+4-1 */
@@ -1199,9 +1200,9 @@ struct btLCP
int *const m_findex, *const m_p, *const m_C;
btLCP (int _n, int _nskip, int _nub, btScalar *_Adata, btScalar *_x, btScalar *_b, btScalar *_w,
- btScalar *_lo, btScalar *_hi, btScalar *_L, btScalar *_d,
+ btScalar *_lo, btScalar *_hi, btScalar *l, btScalar *_d,
btScalar *_Dell, btScalar *_ell, btScalar *_tmp,
- bool *_state, int *_findex, int *_p, int *_C, btScalar **Arows);
+ bool *_state, int *_findex, int *p, int *c, btScalar **Arows);
int getNub() const { return m_nub; }
void transfer_i_to_C (int i);
void transfer_i_to_N (int i) { m_nN++; } // because we can assume C and N span 1:i-1
@@ -1224,9 +1225,9 @@ struct btLCP
btLCP::btLCP (int _n, int _nskip, int _nub, btScalar *_Adata, btScalar *_x, btScalar *_b, btScalar *_w,
- btScalar *_lo, btScalar *_hi, btScalar *_L, btScalar *_d,
+ btScalar *_lo, btScalar *_hi, btScalar *l, btScalar *_d,
btScalar *_Dell, btScalar *_ell, btScalar *_tmp,
- bool *_state, int *_findex, int *_p, int *_C, btScalar **Arows):
+ bool *_state, int *_findex, int *p, int *c, btScalar **Arows):
m_n(_n), m_nskip(_nskip), m_nub(_nub), m_nC(0), m_nN(0),
# ifdef BTROWPTRS
m_A(Arows),
@@ -1234,8 +1235,8 @@ btLCP::btLCP (int _n, int _nskip, int _nub, btScalar *_Adata, btScalar *_x, btSc
m_A(_Adata),
#endif
m_x(_x), m_b(_b), m_w(_w), m_lo(_lo), m_hi(_hi),
- m_L(_L), m_d(_d), m_Dell(_Dell), m_ell(_ell), m_tmp(_tmp),
- m_state(_state), m_findex(_findex), m_p(_p), m_C(_C)
+ m_L(l), m_d(_d), m_Dell(_Dell), m_ell(_ell), m_tmp(_tmp),
+ m_state(_state), m_findex(_findex), m_p(p), m_C(c)
{
{
btSetZero (m_x,m_n);
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp
new file mode 100644
index 00000000000..1f4015c7c72
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp
@@ -0,0 +1,371 @@
+/* Copyright (C) 2004-2013 MBSim Development Team
+
+Code was converted for the Bullet Continuous Collision Detection and Physics Library
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+//The original version is here
+//https://code.google.com/p/mbsim-env/source/browse/trunk/kernel/mbsim/numerics/linear_complementarity_problem/lemke_algorithm.cc
+//This file is re-distributed under the ZLib license, with permission of the original author
+//Math library was replaced from fmatvec to a the file src/LinearMath/btMatrixX.h
+//STL/std::vector replaced by btAlignedObjectArray
+
+
+
+#include "btLemkeAlgorithm.h"
+
+#undef BT_DEBUG_OSTREAM
+#ifdef BT_DEBUG_OSTREAM
+using namespace std;
+#endif //BT_DEBUG_OSTREAM
+
+btScalar btMachEps()
+{
+ static bool calculated=false;
+ static btScalar machEps = btScalar(1.);
+ if (!calculated)
+ {
+ do {
+ machEps /= btScalar(2.0);
+ // If next epsilon yields 1, then break, because current
+ // epsilon is the machine epsilon.
+ }
+ while ((btScalar)(1.0 + (machEps/btScalar(2.0))) != btScalar(1.0));
+// printf( "\nCalculated Machine epsilon: %G\n", machEps );
+ calculated=true;
+ }
+ return machEps;
+}
+
+btScalar btEpsRoot() {
+
+ static btScalar epsroot = 0.;
+ static bool alreadyCalculated = false;
+
+ if (!alreadyCalculated) {
+ epsroot = btSqrt(btMachEps());
+ alreadyCalculated = true;
+ }
+ return epsroot;
+}
+
+
+
+ btVectorXu btLemkeAlgorithm::solve(unsigned int maxloops /* = 0*/)
+{
+
+
+ steps = 0;
+
+ int dim = m_q.size();
+#ifdef BT_DEBUG_OSTREAM
+ if(DEBUGLEVEL >= 1) {
+ cout << "Dimension = " << dim << endl;
+ }
+#endif //BT_DEBUG_OSTREAM
+
+ btVectorXu solutionVector(2 * dim);
+ solutionVector.setZero();
+
+ //, INIT, 0.);
+
+ btMatrixXu ident(dim, dim);
+ ident.setIdentity();
+#ifdef BT_DEBUG_OSTREAM
+ cout << m_M << std::endl;
+#endif
+
+ btMatrixXu mNeg = m_M.negative();
+
+ btMatrixXu A(dim, 2 * dim + 2);
+ //
+ A.setSubMatrix(0, 0, dim - 1, dim - 1,ident);
+ A.setSubMatrix(0, dim, dim - 1, 2 * dim - 1,mNeg);
+ A.setSubMatrix(0, 2 * dim, dim - 1, 2 * dim, -1.f);
+ A.setSubMatrix(0, 2 * dim + 1, dim - 1, 2 * dim + 1,m_q);
+
+#ifdef BT_DEBUG_OSTREAM
+ cout << A << std::endl;
+#endif //BT_DEBUG_OSTREAM
+
+
+ // btVectorXu q_;
+ // q_ >> A(0, 2 * dim + 1, dim - 1, 2 * dim + 1);
+
+ btAlignedObjectArray<int> basis;
+ //At first, all w-values are in the basis
+ for (int i = 0; i < dim; i++)
+ basis.push_back(i);
+
+ int pivotRowIndex = -1;
+ btScalar minValue = 1e30f;
+ bool greaterZero = true;
+ for (int i=0;i<dim;i++)
+ {
+ btScalar v =A(i,2*dim+1);
+ if (v<minValue)
+ {
+ minValue=v;
+ pivotRowIndex = i;
+ }
+ if (v<0)
+ greaterZero = false;
+ }
+
+
+
+ // int pivotRowIndex = q_.minIndex();//minIndex(q_); // first row is that with lowest q-value
+ int z0Row = pivotRowIndex; // remember the col of z0 for ending algorithm afterwards
+ int pivotColIndex = 2 * dim; // first col is that of z0
+
+#ifdef BT_DEBUG_OSTREAM
+ if (DEBUGLEVEL >= 3)
+ {
+ // cout << "A: " << A << endl;
+ cout << "pivotRowIndex " << pivotRowIndex << endl;
+ cout << "pivotColIndex " << pivotColIndex << endl;
+ cout << "Basis: ";
+ for (int i = 0; i < basis.size(); i++)
+ cout << basis[i] << " ";
+ cout << endl;
+ }
+#endif //BT_DEBUG_OSTREAM
+
+ if (!greaterZero)
+ {
+
+ if (maxloops == 0) {
+ maxloops = 100;
+// maxloops = UINT_MAX; //TODO: not a really nice way, problem is: maxloops should be 2^dim (=1<<dim), but this could exceed UINT_MAX and thus the result would be 0 and therefore the lemke algorithm wouldn't start but probably would find a solution within less then UINT_MAX steps. Therefore this constant is used as a upper border right now...
+ }
+
+ /*start looping*/
+ for(steps = 0; steps < maxloops; steps++) {
+
+ GaussJordanEliminationStep(A, pivotRowIndex, pivotColIndex, basis);
+#ifdef BT_DEBUG_OSTREAM
+ if (DEBUGLEVEL >= 3) {
+ // cout << "A: " << A << endl;
+ cout << "pivotRowIndex " << pivotRowIndex << endl;
+ cout << "pivotColIndex " << pivotColIndex << endl;
+ cout << "Basis: ";
+ for (int i = 0; i < basis.size(); i++)
+ cout << basis[i] << " ";
+ cout << endl;
+ }
+#endif //BT_DEBUG_OSTREAM
+
+ int pivotColIndexOld = pivotColIndex;
+
+ /*find new column index */
+ if (basis[pivotRowIndex] < dim) //if a w-value left the basis get in the correspondent z-value
+ pivotColIndex = basis[pivotRowIndex] + dim;
+ else
+ //else do it the other way round and get in the corresponding w-value
+ pivotColIndex = basis[pivotRowIndex] - dim;
+
+ /*the column becomes part of the basis*/
+ basis[pivotRowIndex] = pivotColIndexOld;
+
+ pivotRowIndex = findLexicographicMinimum(A, pivotColIndex);
+
+ if(z0Row == pivotRowIndex) { //if z0 leaves the basis the solution is found --> one last elimination step is necessary
+ GaussJordanEliminationStep(A, pivotRowIndex, pivotColIndex, basis);
+ basis[pivotRowIndex] = pivotColIndex; //update basis
+ break;
+ }
+
+ }
+#ifdef BT_DEBUG_OSTREAM
+ if(DEBUGLEVEL >= 1) {
+ cout << "Number of loops: " << steps << endl;
+ cout << "Number of maximal loops: " << maxloops << endl;
+ }
+#endif //BT_DEBUG_OSTREAM
+
+ if(!validBasis(basis)) {
+ info = -1;
+#ifdef BT_DEBUG_OSTREAM
+ if(DEBUGLEVEL >= 1)
+ cerr << "Lemke-Algorithm ended with Ray-Termination (no valid solution)." << endl;
+#endif //BT_DEBUG_OSTREAM
+
+ return solutionVector;
+ }
+
+ }
+#ifdef BT_DEBUG_OSTREAM
+ if (DEBUGLEVEL >= 2) {
+ // cout << "A: " << A << endl;
+ cout << "pivotRowIndex " << pivotRowIndex << endl;
+ cout << "pivotColIndex " << pivotColIndex << endl;
+ }
+#endif //BT_DEBUG_OSTREAM
+
+ for (int i = 0; i < basis.size(); i++)
+ {
+ solutionVector[basis[i]] = A(i,2*dim+1);//q_[i];
+ }
+
+ info = 0;
+
+ return solutionVector;
+ }
+
+ int btLemkeAlgorithm::findLexicographicMinimum(const btMatrixXu& A, const int & pivotColIndex) {
+ int RowIndex = 0;
+ int dim = A.rows();
+ btAlignedObjectArray<btVectorXu> Rows;
+ for (int row = 0; row < dim; row++)
+ {
+
+ btVectorXu vec(dim + 1);
+ vec.setZero();//, INIT, 0.)
+ Rows.push_back(vec);
+ btScalar a = A(row, pivotColIndex);
+ if (a > 0) {
+ Rows[row][0] = A(row, 2 * dim + 1) / a;
+ Rows[row][1] = A(row, 2 * dim) / a;
+ for (int j = 2; j < dim + 1; j++)
+ Rows[row][j] = A(row, j - 1) / a;
+
+#ifdef BT_DEBUG_OSTREAM
+ // if (DEBUGLEVEL) {
+ // cout << "Rows(" << row << ") = " << Rows[row] << endl;
+ // }
+#endif
+ }
+ }
+
+ for (int i = 0; i < Rows.size(); i++)
+ {
+ if (Rows[i].nrm2() > 0.) {
+
+ int j = 0;
+ for (; j < Rows.size(); j++)
+ {
+ if(i != j)
+ {
+ if(Rows[j].nrm2() > 0.)
+ {
+ btVectorXu test(dim + 1);
+ for (int ii=0;ii<dim+1;ii++)
+ {
+ test[ii] = Rows[j][ii] - Rows[i][ii];
+ }
+
+ //=Rows[j] - Rows[i]
+ if (! LexicographicPositive(test))
+ break;
+ }
+ }
+ }
+
+ if (j == Rows.size())
+ {
+ RowIndex += i;
+ break;
+ }
+ }
+ }
+
+ return RowIndex;
+ }
+
+ bool btLemkeAlgorithm::LexicographicPositive(const btVectorXu & v)
+{
+ int i = 0;
+ // if (DEBUGLEVEL)
+ // cout << "v " << v << endl;
+
+ while(i < v.size()-1 && fabs(v[i]) < btMachEps())
+ i++;
+ if (v[i] > 0)
+ return true;
+
+ return false;
+ }
+
+void btLemkeAlgorithm::GaussJordanEliminationStep(btMatrixXu& A, int pivotRowIndex, int pivotColumnIndex, const btAlignedObjectArray<int>& basis)
+{
+
+ btScalar a = -1 / A(pivotRowIndex, pivotColumnIndex);
+#ifdef BT_DEBUG_OSTREAM
+ cout << A << std::endl;
+#endif
+
+ for (int i = 0; i < A.rows(); i++)
+ {
+ if (i != pivotRowIndex)
+ {
+ for (int j = 0; j < A.cols(); j++)
+ {
+ if (j != pivotColumnIndex)
+ {
+ btScalar v = A(i, j);
+ v += A(pivotRowIndex, j) * A(i, pivotColumnIndex) * a;
+ A.setElem(i, j, v);
+ }
+ }
+ }
+ }
+
+#ifdef BT_DEBUG_OSTREAM
+ cout << A << std::endl;
+#endif //BT_DEBUG_OSTREAM
+ for (int i = 0; i < A.cols(); i++)
+ {
+ A.mulElem(pivotRowIndex, i,-a);
+ }
+#ifdef BT_DEBUG_OSTREAM
+ cout << A << std::endl;
+#endif //#ifdef BT_DEBUG_OSTREAM
+
+ for (int i = 0; i < A.rows(); i++)
+ {
+ if (i != pivotRowIndex)
+ {
+ A.setElem(i, pivotColumnIndex,0);
+ }
+ }
+#ifdef BT_DEBUG_OSTREAM
+ cout << A << std::endl;
+#endif //#ifdef BT_DEBUG_OSTREAM
+ }
+
+ bool btLemkeAlgorithm::greaterZero(const btVectorXu & vector)
+{
+ bool isGreater = true;
+ for (int i = 0; i < vector.size(); i++) {
+ if (vector[i] < 0) {
+ isGreater = false;
+ break;
+ }
+ }
+
+ return isGreater;
+ }
+
+ bool btLemkeAlgorithm::validBasis(const btAlignedObjectArray<int>& basis)
+ {
+ bool isValid = true;
+ for (int i = 0; i < basis.size(); i++) {
+ if (basis[i] >= basis.size() * 2) { //then z0 is in the base
+ isValid = false;
+ break;
+ }
+ }
+
+ return isValid;
+ }
+
+
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h
new file mode 100644
index 00000000000..7555cd9d207
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h
@@ -0,0 +1,108 @@
+/* Copyright (C) 2004-2013 MBSim Development Team
+
+Code was converted for the Bullet Continuous Collision Detection and Physics Library
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+//The original version is here
+//https://code.google.com/p/mbsim-env/source/browse/trunk/kernel/mbsim/numerics/linear_complementarity_problem/lemke_algorithm.cc
+//This file is re-distributed under the ZLib license, with permission of the original author (Kilian Grundl)
+//Math library was replaced from fmatvec to a the file src/LinearMath/btMatrixX.h
+//STL/std::vector replaced by btAlignedObjectArray
+
+
+
+#ifndef BT_NUMERICS_LEMKE_ALGORITHM_H_
+#define BT_NUMERICS_LEMKE_ALGORITHM_H_
+
+#include "LinearMath/btMatrixX.h"
+
+
+#include <vector> //todo: replace by btAlignedObjectArray
+
+class btLemkeAlgorithm
+{
+public:
+
+
+ btLemkeAlgorithm(const btMatrixXu& M_, const btVectorXu& q_, const int & DEBUGLEVEL_ = 0) :
+ DEBUGLEVEL(DEBUGLEVEL_)
+ {
+ setSystem(M_, q_);
+ }
+
+ /* GETTER / SETTER */
+ /**
+ * \brief return info of solution process
+ */
+ int getInfo() {
+ return info;
+ }
+
+ /**
+ * \brief get the number of steps until the solution was found
+ */
+ int getSteps(void) {
+ return steps;
+ }
+
+
+
+ /**
+ * \brief set system with Matrix M and vector q
+ */
+ void setSystem(const btMatrixXu & M_, const btVectorXu & q_)
+ {
+ m_M = M_;
+ m_q = q_;
+ }
+ /***************************************************/
+
+ /**
+ * \brief solve algorithm adapted from : Fast Implementation of Lemke’s Algorithm for Rigid Body Contact Simulation (John E. Lloyd)
+ */
+ btVectorXu solve(unsigned int maxloops = 0);
+
+ virtual ~btLemkeAlgorithm() {
+ }
+
+protected:
+ int findLexicographicMinimum(const btMatrixXu &A, const int & pivotColIndex);
+ bool LexicographicPositive(const btVectorXu & v);
+ void GaussJordanEliminationStep(btMatrixXu &A, int pivotRowIndex, int pivotColumnIndex, const btAlignedObjectArray<int>& basis);
+ bool greaterZero(const btVectorXu & vector);
+ bool validBasis(const btAlignedObjectArray<int>& basis);
+
+ btMatrixXu m_M;
+ btVectorXu m_q;
+
+ /**
+ * \brief number of steps until the Lemke algorithm found a solution
+ */
+ unsigned int steps;
+
+ /**
+ * \brief define level of debug output
+ */
+ int DEBUGLEVEL;
+
+ /**
+ * \brief did the algorithm find a solution
+ *
+ * -1 : not successful
+ * 0 : successful
+ */
+ int info;
+};
+
+
+#endif /* BT_NUMERICS_LEMKE_ALGORITHM_H_ */
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h
new file mode 100644
index 00000000000..98484c37964
--- /dev/null
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h
@@ -0,0 +1,350 @@
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+///original version written by Erwin Coumans, October 2013
+
+#ifndef BT_LEMKE_SOLVER_H
+#define BT_LEMKE_SOLVER_H
+
+
+#include "btMLCPSolverInterface.h"
+#include "btLemkeAlgorithm.h"
+
+
+
+
+///The btLemkeSolver is based on "Fast Implementation of Lemkes Algorithm for Rigid Body Contact Simulation (John E. Lloyd) "
+///It is a slower but more accurate solver. Increase the m_maxLoops for better convergence, at the cost of more CPU time.
+///The original implementation of the btLemkeAlgorithm was done by Kilian Grundl from the MBSim team
+class btLemkeSolver : public btMLCPSolverInterface
+{
+protected:
+
+public:
+
+ btScalar m_maxValue;
+ int m_debugLevel;
+ int m_maxLoops;
+ bool m_useLoHighBounds;
+
+
+
+ btLemkeSolver()
+ :m_maxValue(100000),
+ m_debugLevel(0),
+ m_maxLoops(1000),
+ m_useLoHighBounds(true)
+ {
+ }
+ virtual bool solveMLCP(const btMatrixXu & A, const btVectorXu & b, btVectorXu& x, const btVectorXu & lo,const btVectorXu & hi,const btAlignedObjectArray<int>& limitDependency, int numIterations, bool useSparsity = true)
+ {
+
+ if (m_useLoHighBounds)
+ {
+
+ BT_PROFILE("btLemkeSolver::solveMLCP");
+ int n = A.rows();
+ if (0==n)
+ return true;
+
+ bool fail = false;
+
+ btVectorXu solution(n);
+ btVectorXu q1;
+ q1.resize(n);
+ for (int row=0;row<n;row++)
+ {
+ q1[row] = -b[row];
+ }
+
+ // cout << "A" << endl;
+ // cout << A << endl;
+
+ /////////////////////////////////////
+
+ //slow matrix inversion, replace with LU decomposition
+ btMatrixXu A1;
+ btMatrixXu B(n,n);
+ {
+ BT_PROFILE("inverse(slow)");
+ A1.resize(A.rows(),A.cols());
+ for (int row=0;row<A.rows();row++)
+ {
+ for (int col=0;col<A.cols();col++)
+ {
+ A1.setElem(row,col,A(row,col));
+ }
+ }
+
+ btMatrixXu matrix;
+ matrix.resize(n,2*n);
+ for (int row=0;row<n;row++)
+ {
+ for (int col=0;col<n;col++)
+ {
+ matrix.setElem(row,col,A1(row,col));
+ }
+ }
+
+
+ btScalar ratio,a;
+ int i,j,k;
+ for(i = 0; i < n; i++){
+ for(j = n; j < 2*n; j++){
+ if(i==(j-n))
+ matrix.setElem(i,j,1.0);
+ else
+ matrix.setElem(i,j,0.0);
+ }
+ }
+ for(i = 0; i < n; i++){
+ for(j = 0; j < n; j++){
+ if(i!=j)
+ {
+ btScalar v = matrix(i,i);
+ if (btFuzzyZero(v))
+ {
+ a = 0.000001f;
+ }
+ ratio = matrix(j,i)/matrix(i,i);
+ for(k = 0; k < 2*n; k++){
+ matrix.addElem(j,k,- ratio * matrix(i,k));
+ }
+ }
+ }
+ }
+ for(i = 0; i < n; i++){
+ a = matrix(i,i);
+ if (btFuzzyZero(a))
+ {
+ a = 0.000001f;
+ }
+ btScalar invA = 1.f/a;
+ for(j = 0; j < 2*n; j++){
+ matrix.mulElem(i,j,invA);
+ }
+ }
+
+
+
+
+
+ for (int row=0;row<n;row++)
+ {
+ for (int col=0;col<n;col++)
+ {
+ B.setElem(row,col,matrix(row,n+col));
+ }
+ }
+ }
+
+ btMatrixXu b1(n,1);
+
+ btMatrixXu M(n*2,n*2);
+ for (int row=0;row<n;row++)
+ {
+ b1.setElem(row,0,-b[row]);
+ for (int col=0;col<n;col++)
+ {
+ btScalar v =B(row,col);
+ M.setElem(row,col,v);
+ M.setElem(n+row,n+col,v);
+ M.setElem(n+row,col,-v);
+ M.setElem(row,n+col,-v);
+
+ }
+ }
+
+ btMatrixXu Bb1 = B*b1;
+// q = [ (-B*b1 - lo)' (hi + B*b1)' ]'
+
+ btVectorXu qq;
+ qq.resize(n*2);
+ for (int row=0;row<n;row++)
+ {
+ qq[row] = -Bb1(row,0)-lo[row];
+ qq[n+row] = Bb1(row,0)+hi[row];
+ }
+
+ btVectorXu z1;
+
+ btMatrixXu y1;
+ y1.resize(n,1);
+ btLemkeAlgorithm lemke(M,qq,m_debugLevel);
+ {
+ BT_PROFILE("lemke.solve");
+ lemke.setSystem(M,qq);
+ z1 = lemke.solve(m_maxLoops);
+ }
+ for (int row=0;row<n;row++)
+ {
+ y1.setElem(row,0,z1[2*n+row]-z1[3*n+row]);
+ }
+ btMatrixXu y1_b1(n,1);
+ for (int i=0;i<n;i++)
+ {
+ y1_b1.setElem(i,0,y1(i,0)-b1(i,0));
+ }
+
+ btMatrixXu x1;
+
+ x1 = B*(y1_b1);
+
+ for (int row=0;row<n;row++)
+ {
+ solution[row] = x1(row,0);//n];
+ }
+
+ int errorIndexMax = -1;
+ int errorIndexMin = -1;
+ float errorValueMax = -1e30;
+ float errorValueMin = 1e30;
+
+ for (int i=0;i<n;i++)
+ {
+ x[i] = solution[i];
+ volatile btScalar check = x[i];
+ if (x[i] != check)
+ {
+ //printf("Lemke result is #NAN\n");
+ x.setZero();
+ return false;
+ }
+
+ //this is some hack/safety mechanism, to discard invalid solutions from the Lemke solver
+ //we need to figure out why it happens, and fix it, or detect it properly)
+ if (x[i]>m_maxValue)
+ {
+ if (x[i]> errorValueMax)
+ {
+ fail = true;
+ errorIndexMax = i;
+ errorValueMax = x[i];
+ }
+ ////printf("x[i] = %f,",x[i]);
+ }
+ if (x[i]<-m_maxValue)
+ {
+ if (x[i]<errorValueMin)
+ {
+ errorIndexMin = i;
+ errorValueMin = x[i];
+ fail = true;
+ //printf("x[i] = %f,",x[i]);
+ }
+ }
+ }
+ if (fail)
+ {
+ int m_errorCountTimes = 0;
+ if (errorIndexMin<0)
+ errorValueMin = 0.f;
+ if (errorIndexMax<0)
+ errorValueMax = 0.f;
+ m_errorCountTimes++;
+ // printf("Error (x[%d] = %f, x[%d] = %f), resetting %d times\n", errorIndexMin,errorValueMin, errorIndexMax, errorValueMax, errorCountTimes++);
+ for (int i=0;i<n;i++)
+ {
+ x[i]=0.f;
+ }
+ }
+ return !fail;
+ } else
+
+ {
+ int dimension = A.rows();
+ if (0==dimension)
+ return true;
+
+// printf("================ solving using Lemke/Newton/Fixpoint\n");
+
+ btVectorXu q;
+ q.resize(dimension);
+ for (int row=0;row<dimension;row++)
+ {
+ q[row] = -b[row];
+ }
+
+ btLemkeAlgorithm lemke(A,q,m_debugLevel);
+
+
+ lemke.setSystem(A,q);
+
+ btVectorXu solution = lemke.solve(m_maxLoops);
+
+ //check solution
+
+ bool fail = false;
+ int errorIndexMax = -1;
+ int errorIndexMin = -1;
+ float errorValueMax = -1e30;
+ float errorValueMin = 1e30;
+
+ for (int i=0;i<dimension;i++)
+ {
+ x[i] = solution[i+dimension];
+ volatile btScalar check = x[i];
+ if (x[i] != check)
+ {
+ x.setZero();
+ return false;
+ }
+
+ //this is some hack/safety mechanism, to discard invalid solutions from the Lemke solver
+ //we need to figure out why it happens, and fix it, or detect it properly)
+ if (x[i]>m_maxValue)
+ {
+ if (x[i]> errorValueMax)
+ {
+ fail = true;
+ errorIndexMax = i;
+ errorValueMax = x[i];
+ }
+ ////printf("x[i] = %f,",x[i]);
+ }
+ if (x[i]<-m_maxValue)
+ {
+ if (x[i]<errorValueMin)
+ {
+ errorIndexMin = i;
+ errorValueMin = x[i];
+ fail = true;
+ //printf("x[i] = %f,",x[i]);
+ }
+ }
+ }
+ if (fail)
+ {
+ static int errorCountTimes = 0;
+ if (errorIndexMin<0)
+ errorValueMin = 0.f;
+ if (errorIndexMax<0)
+ errorValueMax = 0.f;
+ printf("Error (x[%d] = %f, x[%d] = %f), resetting %d times\n", errorIndexMin,errorValueMin, errorIndexMax, errorValueMax, errorCountTimes++);
+ for (int i=0;i<dimension;i++)
+ {
+ x[i]=0.f;
+ }
+ }
+
+
+ return !fail;
+ }
+ return true;
+
+ }
+
+};
+
+#endif //BT_LEMKE_SOLVER_H
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp
index 0635b958bed..6688694a928 100644
--- a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp
@@ -44,8 +44,8 @@ btScalar btMLCPSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,
int numFrictionPerContact = m_tmpSolverContactConstraintPool.size()==m_tmpSolverContactFrictionConstraintPool.size()? 1 : 2;
- int numBodies = m_tmpSolverBodyPool.size();
- m_allConstraintArray.resize(0);
+ // int numBodies = m_tmpSolverBodyPool.size();
+ m_allConstraintPtrArray.resize(0);
m_limitDependencies.resize(m_tmpSolverNonContactConstraintPool.size()+m_tmpSolverContactConstraintPool.size()+m_tmpSolverContactFrictionConstraintPool.size());
btAssert(m_limitDependencies.size() == m_tmpSolverNonContactConstraintPool.size()+m_tmpSolverContactConstraintPool.size()+m_tmpSolverContactFrictionConstraintPool.size());
// printf("m_limitDependencies.size() = %d\n",m_limitDependencies.size());
@@ -53,7 +53,7 @@ btScalar btMLCPSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,
int dindex = 0;
for (int i=0;i<m_tmpSolverNonContactConstraintPool.size();i++)
{
- m_allConstraintArray.push_back(m_tmpSolverNonContactConstraintPool[i]);
+ m_allConstraintPtrArray.push_back(&m_tmpSolverNonContactConstraintPool[i]);
m_limitDependencies[dindex++] = -1;
}
@@ -65,14 +65,14 @@ btScalar btMLCPSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,
{
for (int i=0;i<m_tmpSolverContactConstraintPool.size();i++)
{
- m_allConstraintArray.push_back(m_tmpSolverContactConstraintPool[i]);
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
m_limitDependencies[dindex++] = -1;
- m_allConstraintArray.push_back(m_tmpSolverContactFrictionConstraintPool[i*numFrictionPerContact]);
+ 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_allConstraintArray.push_back(m_tmpSolverContactFrictionConstraintPool[i*numFrictionPerContact+1]);
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i*numFrictionPerContact+1]);
m_limitDependencies[dindex++] = findex+firstContactConstraintOffset;
}
}
@@ -80,19 +80,19 @@ btScalar btMLCPSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,
{
for (int i=0;i<m_tmpSolverContactConstraintPool.size();i++)
{
- m_allConstraintArray.push_back(m_tmpSolverContactConstraintPool[i]);
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
m_limitDependencies[dindex++] = -1;
}
for (int i=0;i<m_tmpSolverContactFrictionConstraintPool.size();i++)
{
- m_allConstraintArray.push_back(m_tmpSolverContactFrictionConstraintPool[i]);
+ m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i]);
m_limitDependencies[dindex++] = m_tmpSolverContactFrictionConstraintPool[i].m_frictionIndex+firstContactConstraintOffset;
}
}
- if (!m_allConstraintArray.size())
+ if (!m_allConstraintPtrArray.size())
{
m_A.resize(0,0);
m_b.resize(0);
@@ -156,7 +156,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
{
int numContactRows = interleaveContactAndFriction ? 3 : 1;
- int numConstraintRows = m_allConstraintArray.size();
+ int numConstraintRows = m_allConstraintPtrArray.size();
int n = numConstraintRows;
{
BT_PROFILE("init b (rhs)");
@@ -166,11 +166,11 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
m_bSplit.setZero();
for (int i=0;i<numConstraintRows ;i++)
{
- btScalar jacDiag = m_allConstraintArray[i].m_jacDiagABInv;
+ btScalar jacDiag = m_allConstraintPtrArray[i]->m_jacDiagABInv;
if (!btFuzzyZero(jacDiag))
{
- btScalar rhs = m_allConstraintArray[i].m_rhs;
- btScalar rhsPenetration = m_allConstraintArray[i].m_rhsPenetration;
+ btScalar rhs = m_allConstraintPtrArray[i]->m_rhs;
+ btScalar rhsPenetration = m_allConstraintPtrArray[i]->m_rhsPenetration;
m_b[i]=rhs/jacDiag;
m_bSplit[i] = rhsPenetration/jacDiag;
}
@@ -178,8 +178,8 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
}
}
- btScalar* w = 0;
- int nub = 0;
+// btScalar* w = 0;
+// int nub = 0;
m_lo.resize(numConstraintRows);
m_hi.resize(numConstraintRows);
@@ -195,14 +195,14 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
m_hi[i] = BT_INFINITY;
} else
{
- m_lo[i] = m_allConstraintArray[i].m_lowerLimit;
- m_hi[i] = m_allConstraintArray[i].m_upperLimit;
+ m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
+ m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
}
}
}
//
- int m=m_allConstraintArray.size();
+ int m=m_allConstraintPtrArray.size();
int numBodies = m_tmpSolverBodyPool.size();
btAlignedObjectArray<int> bodyJointNodeArray;
@@ -213,7 +213,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
btAlignedObjectArray<btJointNode> jointNodeArray;
{
BT_PROFILE("jointNodeArray.reserve");
- jointNodeArray.reserve(2*m_allConstraintArray.size());
+ jointNodeArray.reserve(2*m_allConstraintPtrArray.size());
}
static btMatrixXu J3;
@@ -235,7 +235,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
{
BT_PROFILE("ofs resize");
ofs.resize(0);
- ofs.resizeNoInitialize(m_allConstraintArray.size());
+ ofs.resizeNoInitialize(m_allConstraintPtrArray.size());
}
{
BT_PROFILE("Compute J and JinvM");
@@ -243,11 +243,11 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
int numRows = 0;
- for (int i=0;i<m_allConstraintArray.size();i+=numRows,c++)
+ for (int i=0;i<m_allConstraintPtrArray.size();i+=numRows,c++)
{
ofs[c] = rowOffset;
- int sbA = m_allConstraintArray[i].m_solverBodyIdA;
- int sbB = m_allConstraintArray[i].m_solverBodyIdB;
+ 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;
@@ -268,13 +268,13 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
}
for (int row=0;row<numRows;row++,cur++)
{
- btVector3 normalInvMass = m_allConstraintArray[i+row].m_contactNormal1 * orgBodyA->getInvMass();
- btVector3 relPosCrossNormalInvInertia = m_allConstraintArray[i+row].m_relpos1CrossNormal * orgBodyA->getInvInertiaTensorWorld();
+ 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_allConstraintArray[i+row].m_contactNormal1[r]);
- J3.setElem(cur,r+4,m_allConstraintArray[i+row].m_relpos1CrossNormal[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]);
}
@@ -305,13 +305,13 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
for (int row=0;row<numRows;row++,cur++)
{
- btVector3 normalInvMassB = m_allConstraintArray[i+row].m_contactNormal2*orgBodyB->getInvMass();
- btVector3 relPosInvInertiaB = m_allConstraintArray[i+row].m_relpos2CrossNormal * orgBodyB->getInvInertiaTensorWorld();
+ 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_allConstraintArray[i+row].m_contactNormal2[r]);
- J3.setElem(cur,r+4,m_allConstraintArray[i+row].m_relpos2CrossNormal[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]);
}
@@ -349,13 +349,13 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
{
int numRows = 0;
BT_PROFILE("Compute A");
- for (int i=0;i<m_allConstraintArray.size();i+= numRows,c++)
+ for (int i=0;i<m_allConstraintPtrArray.size();i+= numRows,c++)
{
int row__ = ofs[c];
- int sbA = m_allConstraintArray[i].m_solverBodyIdA;
- int sbB = m_allConstraintArray[i].m_solverBodyIdB;
- btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
- btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
+ 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 ;
@@ -371,7 +371,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
{
int numRowsOther = cr0 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j0].m_numConstraintRows : numContactRows;
- size_t ofsother = (m_allConstraintArray[cr0].m_solverBodyIdB == sbA) ? 8*numRowsOther : 0;
+ 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]);
@@ -390,7 +390,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
if (j1<c)
{
int numRowsOther = cj1 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j1].m_numConstraintRows : numContactRows;
- size_t ofsother = (m_allConstraintArray[cj1].m_solverBodyIdB == sbB) ? 8*numRowsOther : 0;
+ 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]);
}
@@ -404,15 +404,15 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
// compute diagonal blocks of m_A
int row__ = 0;
- int numJointRows = m_allConstraintArray.size();
+ int numJointRows = m_allConstraintPtrArray.size();
int jj=0;
for (;row__<numJointRows;)
{
- int sbA = m_allConstraintArray[row__].m_solverBodyIdA;
- int sbB = m_allConstraintArray[row__].m_solverBodyIdB;
- btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
+ //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;
@@ -453,9 +453,9 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
if (infoGlobal.m_solverMode&SOLVER_USE_WARMSTARTING)
{
- for (int i=0;i<m_allConstraintArray.size();i++)
+ for (int i=0;i<m_allConstraintPtrArray.size();i++)
{
- const btSolverConstraint& c = m_allConstraintArray[i];
+ const btSolverConstraint& c = *m_allConstraintPtrArray[i];
m_x[i]=c.m_appliedImpulse;
m_xSplit[i] = c.m_appliedPushImpulse;
}
@@ -471,7 +471,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
{
int numBodies = this->m_tmpSolverBodyPool.size();
- int numConstraintRows = m_allConstraintArray.size();
+ int numConstraintRows = m_allConstraintPtrArray.size();
m_b.resize(numConstraintRows);
if (infoGlobal.m_splitImpulse)
@@ -482,11 +482,11 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
for (int i=0;i<numConstraintRows ;i++)
{
- if (m_allConstraintArray[i].m_jacDiagABInv)
+ if (m_allConstraintPtrArray[i]->m_jacDiagABInv)
{
- m_b[i]=m_allConstraintArray[i].m_rhs/m_allConstraintArray[i].m_jacDiagABInv;
+ m_b[i]=m_allConstraintPtrArray[i]->m_rhs/m_allConstraintPtrArray[i]->m_jacDiagABInv;
if (infoGlobal.m_splitImpulse)
- m_bSplit[i] = m_allConstraintArray[i].m_rhsPenetration/m_allConstraintArray[i].m_jacDiagABInv;
+ m_bSplit[i] = m_allConstraintPtrArray[i]->m_rhsPenetration/m_allConstraintPtrArray[i]->m_jacDiagABInv;
}
}
@@ -517,28 +517,28 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
for (int i=0;i<numConstraintRows;i++)
{
- m_lo[i] = m_allConstraintArray[i].m_lowerLimit;
- m_hi[i] = m_allConstraintArray[i].m_upperLimit;
+ m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
+ m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
- int bodyIndex0 = m_allConstraintArray[i].m_solverBodyIdA;
- int bodyIndex1 = m_allConstraintArray[i].m_solverBodyIdB;
+ int bodyIndex0 = m_allConstraintPtrArray[i]->m_solverBodyIdA;
+ int bodyIndex1 = m_allConstraintPtrArray[i]->m_solverBodyIdB;
if (m_tmpSolverBodyPool[bodyIndex0].m_originalBody)
{
- setElem(J,i,6*bodyIndex0+0,m_allConstraintArray[i].m_contactNormal1[0]);
- setElem(J,i,6*bodyIndex0+1,m_allConstraintArray[i].m_contactNormal1[1]);
- setElem(J,i,6*bodyIndex0+2,m_allConstraintArray[i].m_contactNormal1[2]);
- setElem(J,i,6*bodyIndex0+3,m_allConstraintArray[i].m_relpos1CrossNormal[0]);
- setElem(J,i,6*bodyIndex0+4,m_allConstraintArray[i].m_relpos1CrossNormal[1]);
- setElem(J,i,6*bodyIndex0+5,m_allConstraintArray[i].m_relpos1CrossNormal[2]);
+ setElem(J,i,6*bodyIndex0+0,m_allConstraintPtrArray[i]->m_contactNormal1[0]);
+ setElem(J,i,6*bodyIndex0+1,m_allConstraintPtrArray[i]->m_contactNormal1[1]);
+ setElem(J,i,6*bodyIndex0+2,m_allConstraintPtrArray[i]->m_contactNormal1[2]);
+ setElem(J,i,6*bodyIndex0+3,m_allConstraintPtrArray[i]->m_relpos1CrossNormal[0]);
+ setElem(J,i,6*bodyIndex0+4,m_allConstraintPtrArray[i]->m_relpos1CrossNormal[1]);
+ setElem(J,i,6*bodyIndex0+5,m_allConstraintPtrArray[i]->m_relpos1CrossNormal[2]);
}
if (m_tmpSolverBodyPool[bodyIndex1].m_originalBody)
{
- setElem(J,i,6*bodyIndex1+0,m_allConstraintArray[i].m_contactNormal2[0]);
- setElem(J,i,6*bodyIndex1+1,m_allConstraintArray[i].m_contactNormal2[1]);
- setElem(J,i,6*bodyIndex1+2,m_allConstraintArray[i].m_contactNormal2[2]);
- setElem(J,i,6*bodyIndex1+3,m_allConstraintArray[i].m_relpos2CrossNormal[0]);
- setElem(J,i,6*bodyIndex1+4,m_allConstraintArray[i].m_relpos2CrossNormal[1]);
- setElem(J,i,6*bodyIndex1+5,m_allConstraintArray[i].m_relpos2CrossNormal[2]);
+ setElem(J,i,6*bodyIndex1+0,m_allConstraintPtrArray[i]->m_contactNormal2[0]);
+ setElem(J,i,6*bodyIndex1+1,m_allConstraintPtrArray[i]->m_contactNormal2[1]);
+ setElem(J,i,6*bodyIndex1+2,m_allConstraintPtrArray[i]->m_contactNormal2[2]);
+ setElem(J,i,6*bodyIndex1+3,m_allConstraintPtrArray[i]->m_relpos2CrossNormal[0]);
+ setElem(J,i,6*bodyIndex1+4,m_allConstraintPtrArray[i]->m_relpos2CrossNormal[1]);
+ setElem(J,i,6*bodyIndex1+5,m_allConstraintPtrArray[i]->m_relpos2CrossNormal[2]);
}
}
@@ -573,9 +573,9 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
m_xSplit.resize(numConstraintRows);
// m_x.setZero();
- for (int i=0;i<m_allConstraintArray.size();i++)
+ for (int i=0;i<m_allConstraintPtrArray.size();i++)
{
- const btSolverConstraint& c = m_allConstraintArray[i];
+ const btSolverConstraint& c = *m_allConstraintPtrArray[i];
m_x[i]=c.m_appliedImpulse;
if (infoGlobal.m_splitImpulse)
m_xSplit[i] = c.m_appliedPushImpulse;
@@ -597,27 +597,33 @@ btScalar btMLCPSolver::solveGroupCacheFriendlyIterations(btCollisionObject** bod
if (result)
{
BT_PROFILE("process MLCP results");
- for (int i=0;i<m_allConstraintArray.size();i++)
+ for (int i=0;i<m_allConstraintPtrArray.size();i++)
{
{
- btSolverConstraint& c = m_allConstraintArray[i];
+ btSolverConstraint& c = *m_allConstraintPtrArray[i];
int sbA = c.m_solverBodyIdA;
int sbB = c.m_solverBodyIdB;
- btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
- btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
+ //btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
+ // btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
- solverBodyA.internalApplyImpulse(c.m_contactNormal1*solverBodyA.internalGetInvMass(),c.m_angularComponentA,m_x[i]);
- solverBodyB.internalApplyImpulse(c.m_contactNormal2*solverBodyB.internalGetInvMass(),c.m_angularComponentB,m_x[i]);
+ {
+ btScalar deltaImpulse = m_x[i]-c.m_appliedImpulse;
+ c.m_appliedImpulse = m_x[i];
+ 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)
{
- solverBodyA.internalApplyPushImpulse(c.m_contactNormal1*solverBodyA.internalGetInvMass(),c.m_angularComponentA,m_xSplit[i]);
- solverBodyB.internalApplyPushImpulse(c.m_contactNormal2*solverBodyB.internalGetInvMass(),c.m_angularComponentB,m_xSplit[i]);
+ btScalar deltaImpulse = m_xSplit[i] - c.m_appliedPushImpulse;
+ solverBodyA.internalApplyPushImpulse(c.m_contactNormal1*solverBodyA.internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
+ solverBodyB.internalApplyPushImpulse(c.m_contactNormal2*solverBodyB.internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
c.m_appliedPushImpulse = m_xSplit[i];
}
- c.m_appliedImpulse = m_x[i];
+
}
}
}
@@ -629,4 +635,6 @@ btScalar btMLCPSolver::solveGroupCacheFriendlyIterations(btCollisionObject** bod
}
return 0.f;
-} \ No newline at end of file
+}
+
+
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h
index 31e8eb88ba5..43e85445bad 100644
--- a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.h
@@ -39,13 +39,15 @@ protected:
btVectorXu m_xSplit2;
btAlignedObjectArray<int> m_limitDependencies;
- btConstraintArray m_allConstraintArray;
+ btAlignedObjectArray<btSolverConstraint*> m_allConstraintPtrArray;
btMLCPSolverInterface* m_solver;
int m_fallback;
btScalar m_cfm;
virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
+
+
virtual void createMLCP(const btContactSolverInfo& infoGlobal);
virtual void createMLCPFast(const btContactSolverInfo& infoGlobal);
diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h
index d2ad54d21a8..77cc57c6e0e 100644
--- a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h
+++ b/extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h
@@ -62,7 +62,7 @@ public:
}
float aDiag = A(i,i);
- x [i] = (b [i] - delta) / A(i,i);
+ x [i] = (b [i] - delta) / aDiag;
float s = 1.f;
if (limitDependency[i]>=0)
diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp
index 77b475b9682..a7b1688469f 100644
--- a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp
+++ b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp
@@ -296,8 +296,9 @@ void btRaycastVehicle::updateVehicle( btScalar step )
int i=0;
for (i=0;i<m_wheelInfo.size();i++)
{
- btScalar depth;
- depth = rayCast( m_wheelInfo[i]);
+ //btScalar depth;
+ //depth =
+ rayCast( m_wheelInfo[i]);
}
updateSuspension(step);
diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h
index f59555f94d2..82d44c73e05 100644
--- a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h
+++ b/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h
@@ -58,8 +58,6 @@ public:
};
private:
- btScalar m_tau;
- btScalar m_damping;
btVehicleRaycaster* m_vehicleRaycaster;
btScalar m_pitchControl;
btScalar m_steeringValue;
diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBody.cpp b/extern/bullet2/src/BulletSoftBody/btSoftBody.cpp
index 2bfd62f2a2f..51f4b33d034 100644
--- a/extern/bullet2/src/BulletSoftBody/btSoftBody.cpp
+++ b/extern/bullet2/src/BulletSoftBody/btSoftBody.cpp
@@ -3605,8 +3605,8 @@ const char* btSoftBody::serialize(void* dataBuffer, class btSerializer* serializ
m_joints[i]->m_refs[0].serializeFloat(memPtr->m_refs[0]);
m_joints[i]->m_refs[1].serializeFloat(memPtr->m_refs[1]);
memPtr->m_cfm = m_joints[i]->m_cfm;
- memPtr->m_erp = m_joints[i]->m_erp;
- memPtr->m_split = m_joints[i]->m_split;
+ memPtr->m_erp = float(m_joints[i]->m_erp);
+ memPtr->m_split = float(m_joints[i]->m_split);
memPtr->m_delete = m_joints[i]->m_delete;
for (int j=0;j<4;j++)
diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBody.h b/extern/bullet2/src/BulletSoftBody/btSoftBody.h
index ee1a3d95228..bd5846bfb67 100644
--- a/extern/bullet2/src/BulletSoftBody/btSoftBody.h
+++ b/extern/bullet2/src/BulletSoftBody/btSoftBody.h
@@ -171,6 +171,7 @@ public:
/* ImplicitFn */
struct ImplicitFn
{
+ virtual ~ImplicitFn() {}
virtual btScalar Eval(const btVector3& x)=0;
};
@@ -528,6 +529,7 @@ public:
{
struct IControl
{
+ virtual ~IControl() {}
virtual void Prepare(AJoint*) {}
virtual btScalar Speed(AJoint*,btScalar current) { return(current); }
static IControl* Default() { static IControl def;return(&def); }
diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp b/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp
index 36f675a6c0c..293a393e55e 100644
--- a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp
+++ b/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp
@@ -480,6 +480,168 @@ void btSoftBodyHelpers::DrawClusterTree( btSoftBody* psb,
drawTree(idraw,psb->m_cdbvt.m_root,0,btVector3(0,1,1),btVector3(1,0,0),mindepth,maxdepth);
}
+
+//The btSoftBody object from the BulletSDK includes an array of Nodes and Links. These links appear
+// to be first set up to connect a node to between 5 and 6 of its neighbors [480 links],
+//and then to the rest of the nodes after the execution of the Floyd-Warshall graph algorithm
+//[another 930 links].
+//The way the links are stored by default, we have a number of cases where adjacent links share a node in common
+// - this leads to the creation of a data dependency through memory.
+//The PSolve_Links() function reads and writes nodes as it iterates over each link.
+//So, we now have the possibility of a data dependency between iteration X
+//that processes link L with iteration X+1 that processes link L+1
+//because L and L+1 have one node in common, and iteration X updates the positions of that node,
+//and iteration X+1 reads in the position of that shared node.
+//
+//Such a memory dependency limits the ability of a modern CPU to speculate beyond
+//a certain point because it has to respect a possible dependency
+//- this prevents the CPU from making full use of its out-of-order resources.
+//If we re-order the links such that we minimize the cases where a link L and L+1 share a common node,
+//we create a temporal gap between when the node position is written,
+//and when it is subsequently read. This in turn allows the CPU to continue execution without
+//risking a dependency violation. Such a reordering would result in significant speedups on
+//modern CPUs with lots of execution resources.
+//In our testing, we see it have a tremendous impact not only on the A7,
+//but also on all x86 cores that ship with modern Macs.
+//The attached source file includes a single function (ReoptimizeLinkOrder) which can be called on a
+//btSoftBody object in the solveConstraints() function before the actual solver is invoked,
+//or right after generateBendingConstraints() once we have all 1410 links.
+
+
+//===================================================================
+//
+//
+// This function takes in a list of interdependent Links and tries
+// to maximize the distance between calculation
+// of dependent links. This increases the amount of parallelism that can
+// be exploited by out-of-order instruction processors with large but
+// (inevitably) finite instruction windows.
+//
+//===================================================================
+
+// A small structure to track lists of dependent link calculations
+class LinkDeps_t {
+ public:
+ int value; // A link calculation that is dependent on this one
+ // Positive values = "input A" while negative values = "input B"
+ LinkDeps_t *next; // Next dependence in the list
+};
+typedef LinkDeps_t *LinkDepsPtr_t;
+
+// Dependency list constants
+#define REOP_NOT_DEPENDENT -1
+#define REOP_NODE_COMPLETE -2 // Must be less than REOP_NOT_DEPENDENT
+
+
+void btSoftBodyHelpers::ReoptimizeLinkOrder(btSoftBody *psb /* This can be replaced by a btSoftBody pointer */)
+{
+ int i, nLinks=psb->m_links.size(), nNodes=psb->m_nodes.size();
+ btSoftBody::Link *lr;
+ int ar, br;
+ btSoftBody::Node *node0 = &(psb->m_nodes[0]);
+ btSoftBody::Node *node1 = &(psb->m_nodes[1]);
+ LinkDepsPtr_t linkDep;
+ int readyListHead, readyListTail, linkNum, linkDepFrees, depLink;
+
+ // Allocate temporary buffers
+ int *nodeWrittenAt = new int[nNodes+1]; // What link calculation produced this node's current values?
+ int *linkDepA = new int[nLinks]; // Link calculation input is dependent upon prior calculation #N
+ int *linkDepB = new int[nLinks];
+ int *readyList = new int[nLinks]; // List of ready-to-process link calculations (# of links, maximum)
+ LinkDeps_t *linkDepFreeList = new LinkDeps_t[2*nLinks]; // Dependent-on-me list elements (2x# of links, maximum)
+ LinkDepsPtr_t *linkDepListStarts = new LinkDepsPtr_t[nLinks]; // Start nodes of dependent-on-me lists, one for each link
+
+ // Copy the original, unsorted links to a side buffer
+ btSoftBody::Link *linkBuffer = new btSoftBody::Link[nLinks];
+ memcpy(linkBuffer, &(psb->m_links[0]), sizeof(btSoftBody::Link)*nLinks);
+
+ // Clear out the node setup and ready list
+ for (i=0; i < nNodes+1; i++) {
+ nodeWrittenAt[i] = REOP_NOT_DEPENDENT;
+ }
+ for (i=0; i < nLinks; i++) {
+ linkDepListStarts[i] = NULL;
+ }
+ readyListHead = readyListTail = linkDepFrees = 0;
+
+ // Initial link analysis to set up data structures
+ for (i=0; i < nLinks; i++) {
+
+ // Note which prior link calculations we are dependent upon & build up dependence lists
+ lr = &(psb->m_links[i]);
+ ar = (lr->m_n[0] - node0)/(node1 - node0);
+ br = (lr->m_n[1] - node0)/(node1 - node0);
+ if (nodeWrittenAt[ar] > REOP_NOT_DEPENDENT) {
+ linkDepA[i] = nodeWrittenAt[ar];
+ linkDep = &linkDepFreeList[linkDepFrees++];
+ linkDep->value = i;
+ linkDep->next = linkDepListStarts[nodeWrittenAt[ar]];
+ linkDepListStarts[nodeWrittenAt[ar]] = linkDep;
+ } else {
+ linkDepA[i] = REOP_NOT_DEPENDENT;
+ }
+ if (nodeWrittenAt[br] > REOP_NOT_DEPENDENT) {
+ linkDepB[i] = nodeWrittenAt[br];
+ linkDep = &linkDepFreeList[linkDepFrees++];
+ linkDep->value = -(i+1);
+ linkDep->next = linkDepListStarts[nodeWrittenAt[br]];
+ linkDepListStarts[nodeWrittenAt[br]] = linkDep;
+ } else {
+ linkDepB[i] = REOP_NOT_DEPENDENT;
+ }
+
+ // Add this link to the initial ready list, if it is not dependent on any other links
+ if ((linkDepA[i] == REOP_NOT_DEPENDENT) && (linkDepB[i] == REOP_NOT_DEPENDENT)) {
+ readyList[readyListTail++] = i;
+ linkDepA[i] = linkDepB[i] = REOP_NODE_COMPLETE; // Probably not needed now
+ }
+
+ // Update the nodes to mark which ones are calculated by this link
+ nodeWrittenAt[ar] = nodeWrittenAt[br] = i;
+ }
+
+ // Process the ready list and create the sorted list of links
+ // -- By treating the ready list as a queue, we maximize the distance between any
+ // inter-dependent node calculations
+ // -- All other (non-related) nodes in the ready list will automatically be inserted
+ // in between each set of inter-dependent link calculations by this loop
+ i = 0;
+ while (readyListHead != readyListTail) {
+ // Use ready list to select the next link to process
+ linkNum = readyList[readyListHead++];
+ // Copy the next-to-calculate link back into the original link array
+ psb->m_links[i++] = linkBuffer[linkNum];
+
+ // Free up any link inputs that are dependent on this one
+ linkDep = linkDepListStarts[linkNum];
+ while (linkDep) {
+ depLink = linkDep->value;
+ if (depLink >= 0) {
+ linkDepA[depLink] = REOP_NOT_DEPENDENT;
+ } else {
+ depLink = -depLink - 1;
+ linkDepB[depLink] = REOP_NOT_DEPENDENT;
+ }
+ // Add this dependent link calculation to the ready list if *both* inputs are clear
+ if ((linkDepA[depLink] == REOP_NOT_DEPENDENT) && (linkDepB[depLink] == REOP_NOT_DEPENDENT)) {
+ readyList[readyListTail++] = depLink;
+ linkDepA[depLink] = linkDepB[depLink] = REOP_NODE_COMPLETE; // Probably not needed now
+ }
+ linkDep = linkDep->next;
+ }
+ }
+
+ // Delete the temporary buffers
+ delete [] nodeWrittenAt;
+ delete [] linkDepA;
+ delete [] linkDepB;
+ delete [] readyList;
+ delete [] linkDepFreeList;
+ delete [] linkDepListStarts;
+ delete [] linkBuffer;
+}
+
+
//
void btSoftBodyHelpers::DrawFrame( btSoftBody* psb,
btIDebugDraw* idraw)
diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h b/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h
index 620a52fe394..7271530109a 100644
--- a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h
+++ b/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h
@@ -137,7 +137,12 @@ struct btSoftBodyHelpers
bool bfacelinks,
bool btetralinks,
bool bfacesfromtetras);
-
+
+ /// Sort the list of links to move link calculations that are dependent upon earlier
+ /// ones as far as possible away from the calculation of those values
+ /// This tends to make adjacent loop iterations not dependent upon one another,
+ /// so out-of-order processors can execute instructions from multiple iterations at once
+ static void ReoptimizeLinkOrder(btSoftBody *psb );
};
#endif //BT_SOFT_BODY_HELPERS_H
diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h b/extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h
index 19d0543ef9e..759509a1d86 100644
--- a/extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h
+++ b/extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h
@@ -161,7 +161,7 @@ public:
}
virtual btScalar getMargin() const
{
- return getMargin();
+ return btConvexInternalShape::getMargin();
}
};
diff --git a/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp b/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp
index 5f35935450c..653d5a06b49 100644
--- a/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp
+++ b/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp
@@ -76,7 +76,7 @@ void btSoftRigidDynamicsWorld::predictUnconstraintMotion(btScalar timeStep)
btDiscreteDynamicsWorld::predictUnconstraintMotion( timeStep );
{
BT_PROFILE("predictUnconstraintMotionSoftBody");
- m_softBodySolver->predictMotion( timeStep );
+ m_softBodySolver->predictMotion( float(timeStep) );
}
}
diff --git a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h b/extern/bullet2/src/BulletSoftBody/btSparseSDF.h
index bcf0c798253..8992ddbb68d 100644
--- a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h
+++ b/extern/bullet2/src/BulletSoftBody/btSparseSDF.h
@@ -185,7 +185,6 @@ struct btSparseSdf
{
++nprobes;
++ncells;
- int sz = sizeof(Cell);
if (ncells>m_clampCells)
{
static int numResets=0;
diff --git a/extern/bullet2/src/LinearMath/btAlignedObjectArray.h b/extern/bullet2/src/LinearMath/btAlignedObjectArray.h
index 24e59ab65d7..6193ef7f427 100644
--- a/extern/bullet2/src/LinearMath/btAlignedObjectArray.h
+++ b/extern/bullet2/src/LinearMath/btAlignedObjectArray.h
@@ -39,6 +39,12 @@ subject to the following restrictions:
#include <new> //for placement new
#endif //BT_USE_PLACEMENT_NEW
+// The register keyword is deprecated in C++11 so don't use it.
+#if __cplusplus > 199711L
+#define BT_REGISTER
+#else
+#define BT_REGISTER register
+#endif
///The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods
///It is developed to replace stl::vector to avoid portability issues, including STL alignment issues to add SIMD/SSE data
@@ -202,24 +208,16 @@ protected:
///when the new number of elements is smaller, the destructor will be called, but memory will not be freed, to reduce performance overhead of run-time memory (de)allocations.
SIMD_FORCE_INLINE void resizeNoInitialize(int newsize)
{
- int curSize = size();
-
- if (newsize < curSize)
+ if (newsize > size())
{
- } else
- {
- if (newsize > size())
- {
- reserve(newsize);
- }
- //leave this uninitialized
+ reserve(newsize);
}
m_size = newsize;
}
SIMD_FORCE_INLINE void resize(int newsize, const T& fillData=T())
{
- int curSize = size();
+ const BT_REGISTER int curSize = size();
if (newsize < curSize)
{
@@ -229,7 +227,7 @@ protected:
}
} else
{
- if (newsize > size())
+ if (newsize > curSize)
{
reserve(newsize);
}
@@ -246,7 +244,7 @@ protected:
}
SIMD_FORCE_INLINE T& expandNonInitializing( )
{
- int sz = size();
+ const BT_REGISTER int sz = size();
if( sz == capacity() )
{
reserve( allocSize(size()) );
@@ -259,7 +257,7 @@ protected:
SIMD_FORCE_INLINE T& expand( const T& fillValue=T())
{
- int sz = size();
+ const BT_REGISTER int sz = size();
if( sz == capacity() )
{
reserve( allocSize(size()) );
@@ -275,7 +273,7 @@ protected:
SIMD_FORCE_INLINE void push_back(const T& _Val)
{
- int sz = size();
+ const BT_REGISTER int sz = size();
if( sz == capacity() )
{
reserve( allocSize(size()) );
diff --git a/extern/bullet2/src/LinearMath/btCpuFeatureUtility.h b/extern/bullet2/src/LinearMath/btCpuFeatureUtility.h
new file mode 100644
index 00000000000..d2cab52d488
--- /dev/null
+++ b/extern/bullet2/src/LinearMath/btCpuFeatureUtility.h
@@ -0,0 +1,92 @@
+
+#ifndef BT_CPU_UTILITY_H
+#define BT_CPU_UTILITY_H
+
+#include "LinearMath/btScalar.h"
+
+#include <string.h>//memset
+#ifdef USE_SIMD
+#include <emmintrin.h>
+#ifdef BT_ALLOW_SSE4
+#include <intrin.h>
+#endif //BT_ALLOW_SSE4
+#endif //USE_SIMD
+
+#if defined BT_USE_NEON
+#define ARM_NEON_GCC_COMPATIBILITY 1
+#include <arm_neon.h>
+#include <sys/types.h>
+#include <sys/sysctl.h> //for sysctlbyname
+#endif //BT_USE_NEON
+
+///Rudimentary btCpuFeatureUtility for CPU features: only report the features that Bullet actually uses (SSE4/FMA3, NEON_HPFP)
+///We assume SSE2 in case BT_USE_SSE2 is defined in LinearMath/btScalar.h
+class btCpuFeatureUtility
+{
+public:
+ enum btCpuFeature
+ {
+ CPU_FEATURE_FMA3=1,
+ CPU_FEATURE_SSE4_1=2,
+ CPU_FEATURE_NEON_HPFP=4
+ };
+
+ static int getCpuFeatures()
+ {
+
+ static int capabilities = 0;
+ static bool testedCapabilities = false;
+ if (0 != testedCapabilities)
+ {
+ return capabilities;
+ }
+
+#ifdef BT_USE_NEON
+ {
+ uint32_t hasFeature = 0;
+ size_t featureSize = sizeof(hasFeature);
+ int err = sysctlbyname("hw.optional.neon_hpfp", &hasFeature, &featureSize, NULL, 0);
+ if (0 == err && hasFeature)
+ capabilities |= CPU_FEATURE_NEON_HPFP;
+ }
+#endif //BT_USE_NEON
+
+#ifdef BT_ALLOW_SSE4
+ {
+ int cpuInfo[4];
+ memset(cpuInfo, 0, sizeof(cpuInfo));
+ unsigned long long sseExt = 0;
+ __cpuid(cpuInfo, 1);
+
+ bool osUsesXSAVE_XRSTORE = cpuInfo[2] & (1 << 27) || false;
+ bool cpuAVXSuport = cpuInfo[2] & (1 << 28) || false;
+
+ if (osUsesXSAVE_XRSTORE && cpuAVXSuport)
+ {
+ sseExt = _xgetbv(0);
+ }
+ const int OSXSAVEFlag = (1UL << 27);
+ const int AVXFlag = ((1UL << 28) | OSXSAVEFlag);
+ const int FMAFlag = ((1UL << 12) | AVXFlag | OSXSAVEFlag);
+ if ((cpuInfo[2] & FMAFlag) == FMAFlag && (sseExt & 6) == 6)
+ {
+ capabilities |= btCpuFeatureUtility::CPU_FEATURE_FMA3;
+ }
+
+ const int SSE41Flag = (1 << 19);
+ if (cpuInfo[2] & SSE41Flag)
+ {
+ capabilities |= btCpuFeatureUtility::CPU_FEATURE_SSE4_1;
+ }
+ }
+#endif//BT_ALLOW_SSE4
+
+ testedCapabilities = true;
+ return capabilities;
+ }
+
+
+};
+
+
+#endif //BT_CPU_UTILITY_H
diff --git a/extern/bullet2/src/LinearMath/btDefaultMotionState.h b/extern/bullet2/src/LinearMath/btDefaultMotionState.h
index c90b749230c..01c5f8d932d 100644
--- a/extern/bullet2/src/LinearMath/btDefaultMotionState.h
+++ b/extern/bullet2/src/LinearMath/btDefaultMotionState.h
@@ -25,14 +25,14 @@ ATTRIBUTE_ALIGNED16(struct) btDefaultMotionState : public btMotionState
///synchronizes world transform from user to physics
virtual void getWorldTransform(btTransform& centerOfMassWorldTrans ) const
{
- centerOfMassWorldTrans = m_centerOfMassOffset.inverse() * m_graphicsWorldTrans ;
+ centerOfMassWorldTrans = m_graphicsWorldTrans * m_centerOfMassOffset.inverse() ;
}
///synchronizes world transform from physics to user
///Bullet only calls the update of worldtransform for active objects
virtual void setWorldTransform(const btTransform& centerOfMassWorldTrans)
{
- m_graphicsWorldTrans = centerOfMassWorldTrans * m_centerOfMassOffset ;
+ m_graphicsWorldTrans = centerOfMassWorldTrans * m_centerOfMassOffset;
}
diff --git a/extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h b/extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h
index e658c5cf062..13a79aa5856 100644
--- a/extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h
+++ b/extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h
@@ -85,9 +85,17 @@ inline void GrahamScanConvexHull2D(btAlignedObjectArray<GrahamVector3>& original
originalPoints[0].m_angle = -1e30f;
for (int i=1;i<originalPoints.size();i++)
{
- btVector3 xvec = axis0;
- btVector3 ar = originalPoints[i]-originalPoints[0];
- originalPoints[i].m_angle = btCross(xvec, ar).dot(normalAxis) / ar.length();
+ btVector3 ar = originalPoints[i]-originalPoints[0];
+ btScalar ar1 = axis1.dot(ar);
+ btScalar ar0 = axis0.dot(ar);
+ if( ar1*ar1+ar0*ar0 < FLT_EPSILON )
+ {
+ originalPoints[i].m_angle = 0.0f;
+ }
+ else
+ {
+ originalPoints[i].m_angle = btAtan2Fast(ar1, ar0);
+ }
}
//step 2: sort all points, based on 'angle' with this anchor
@@ -111,6 +119,11 @@ inline void GrahamScanConvexHull2D(btAlignedObjectArray<GrahamVector3>& original
else
hull.push_back(originalPoints[i]);
}
+
+ if( hull.size() == 1 )
+ {
+ hull.push_back( originalPoints[i] );
+ }
}
}
diff --git a/extern/bullet2/src/LinearMath/btHashMap.h b/extern/bullet2/src/LinearMath/btHashMap.h
index ce07db3ac6b..af9727b7ada 100644
--- a/extern/bullet2/src/LinearMath/btHashMap.h
+++ b/extern/bullet2/src/LinearMath/btHashMap.h
@@ -399,6 +399,10 @@ protected:
return find(key);
}
+ const Value* operator[](const Key& key) const {
+ return find(key);
+ }
+
const Value* find(const Key& key) const
{
int index = findIndex(key);
diff --git a/extern/bullet2/src/LinearMath/btIDebugDraw.h b/extern/bullet2/src/LinearMath/btIDebugDraw.h
index de97c3f87fd..58c9838c490 100644
--- a/extern/bullet2/src/LinearMath/btIDebugDraw.h
+++ b/extern/bullet2/src/LinearMath/btIDebugDraw.h
@@ -21,6 +21,7 @@ subject to the following restrictions:
#include "btTransform.h"
+
///The btIDebugDraw interface class allows hooking up a debug renderer to visually debug simulations.
///Typical use case: create a debug drawer object, and assign it to a btCollisionWorld or btDynamicsWorld using setDebugDrawer and call debugDrawWorld.
///A class that implements the btIDebugDraw interface has to implement the drawLine method at a minimum.
@@ -29,6 +30,29 @@ class btIDebugDraw
{
public:
+ ATTRIBUTE_ALIGNED16(struct) DefaultColors
+ {
+ btVector3 m_activeObject;
+ btVector3 m_deactivatedObject;
+ btVector3 m_wantsDeactivationObject;
+ btVector3 m_disabledDeactivationObject;
+ btVector3 m_disabledSimulationObject;
+ btVector3 m_aabb;
+ btVector3 m_contactPoint;
+
+ DefaultColors()
+ : m_activeObject(1,1,1),
+ m_deactivatedObject(0,1,0),
+ m_wantsDeactivationObject(0,1,1),
+ m_disabledDeactivationObject(1,0,0),
+ m_disabledSimulationObject(1,1,0),
+ m_aabb(1,0,0),
+ m_contactPoint(1,1,0)
+ {
+ }
+ };
+
+
enum DebugDrawModes
{
DBG_NoDebug=0,
@@ -46,12 +70,18 @@ class btIDebugDraw
DBG_DrawConstraints = (1 << 11),
DBG_DrawConstraintLimits = (1 << 12),
DBG_FastWireframe = (1<<13),
- DBG_DrawNormals = (1<<14),
+ DBG_DrawNormals = (1<<14),
+ DBG_DrawFrames = (1<<15),
DBG_MAX_DEBUG_DRAW_MODE
};
virtual ~btIDebugDraw() {};
+
+ virtual DefaultColors getDefaultColors() const { DefaultColors colors; return colors; }
+ ///the default implementation for setDefaultColors has no effect. A derived class can implement it and store the colors.
+ virtual void setDefaultColors(const DefaultColors& /*colors*/) {}
+
virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)=0;
virtual void drawLine(const btVector3& from,const btVector3& to, const btVector3& fromColor, const btVector3& toColor)
@@ -147,7 +177,7 @@ class btIDebugDraw
const btVector3& vx = axis;
btVector3 vy = normal.cross(axis);
btScalar step = stepDegrees * SIMD_RADS_PER_DEG;
- int nSteps = (int)((maxAngle - minAngle) / step);
+ int nSteps = (int)btFabs((maxAngle - minAngle) / step);
if(!nSteps) nSteps = 1;
btVector3 prev = center + radiusA * vx * btCos(minAngle) + radiusB * vy * btSin(minAngle);
if(drawSect)
@@ -438,6 +468,10 @@ class btIDebugDraw
drawLine(transform*pt0,transform*pt1,color);
drawLine(transform*pt2,transform*pt3,color);
}
+
+ virtual void flushLines()
+ {
+ }
};
diff --git a/extern/bullet2/src/LinearMath/btMatrix3x3.h b/extern/bullet2/src/LinearMath/btMatrix3x3.h
index 14fe704f81a..41dea694835 100644
--- a/extern/bullet2/src/LinearMath/btMatrix3x3.h
+++ b/extern/bullet2/src/LinearMath/btMatrix3x3.h
@@ -610,6 +610,27 @@ public:
/**@brief Return the inverse of the matrix */
btMatrix3x3 inverse() const;
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases.
+ ///Solve33 is from Box2d, thanks to Erin Catto,
+ btVector3 solve33(const btVector3& b) const
+ {
+ btVector3 col1 = getColumn(0);
+ btVector3 col2 = getColumn(1);
+ btVector3 col3 = getColumn(2);
+
+ btScalar det = btDot(col1, btCross(col2, col3));
+ if (btFabs(det)>SIMD_EPSILON)
+ {
+ det = 1.0f / det;
+ }
+ btVector3 x;
+ x[0] = det * btDot(b, btCross(col2, col3));
+ x[1] = det * btDot(col1, btCross(b, col3));
+ x[2] = det * btDot(col1, btCross(col2, b));
+ return x;
+ }
+
btMatrix3x3 transposeTimes(const btMatrix3x3& m) const;
btMatrix3x3 timesTranspose(const btMatrix3x3& m) const;
diff --git a/extern/bullet2/src/LinearMath/btMatrixX.h b/extern/bullet2/src/LinearMath/btMatrixX.h
index 865d77967a9..42caed42eff 100644
--- a/extern/bullet2/src/LinearMath/btMatrixX.h
+++ b/extern/bullet2/src/LinearMath/btMatrixX.h
@@ -19,6 +19,7 @@ subject to the following restrictions:
#include "LinearMath/btQuickprof.h"
#include "LinearMath/btAlignedObjectArray.h"
+#include <stdio.h>
//#define BT_DEBUG_OSTREAM
#ifdef BT_DEBUG_OSTREAM
@@ -94,7 +95,7 @@ struct btVectorX
{
T temp;
temp = scale / absxi;
- ssq = ssq * (temp * temp) + 1.0;
+ ssq = ssq * (temp * temp) + BT_ONE;
scale = absxi;
}
else
@@ -354,11 +355,11 @@ struct btMatrixX
for (int i=0; i < res.rows(); ++i)
{
T dotProd=0;
- T dotProd2=0;
- int waste=0,waste2=0;
+// T dotProd2=0;
+ //int waste=0,waste2=0;
{
- bool useOtherCol = true;
+// bool useOtherCol = true;
{
for (int v=0;v<rows();v++)
{
diff --git a/extern/bullet2/src/LinearMath/btQuadWord.h b/extern/bullet2/src/LinearMath/btQuadWord.h
index 11067ef47d9..fcfb3be4447 100644
--- a/extern/bullet2/src/LinearMath/btQuadWord.h
+++ b/extern/bullet2/src/LinearMath/btQuadWord.h
@@ -73,7 +73,7 @@ public:
public:
-#if defined(BT_USE_SSE) || defined(BT_USE_NEON)
+#if (defined(BT_USE_SSE_IN_API) && defined(BT_USE_SSE)) || defined(BT_USE_NEON)
// Set Vector
SIMD_FORCE_INLINE btQuadWord(const btSimdFloat4 vec)
diff --git a/extern/bullet2/src/LinearMath/btQuaternion.h b/extern/bullet2/src/LinearMath/btQuaternion.h
index 665421de1e4..ede76938404 100644
--- a/extern/bullet2/src/LinearMath/btQuaternion.h
+++ b/extern/bullet2/src/LinearMath/btQuaternion.h
@@ -22,6 +22,13 @@ subject to the following restrictions:
#include "btQuadWord.h"
+#ifdef BT_USE_DOUBLE_PRECISION
+#define btQuaternionData btQuaternionDoubleData
+#define btQuaternionDataName "btQuaternionDoubleData"
+#else
+#define btQuaternionData btQuaternionFloatData
+#define btQuaternionDataName "btQuaternionFloatData"
+#endif //BT_USE_DOUBLE_PRECISION
@@ -560,7 +567,18 @@ public:
SIMD_FORCE_INLINE const btScalar& getW() const { return m_floats[3]; }
-
+ SIMD_FORCE_INLINE void serialize(struct btQuaternionData& dataOut) const;
+
+ SIMD_FORCE_INLINE void deSerialize(const struct btQuaternionData& dataIn);
+
+ SIMD_FORCE_INLINE void serializeFloat(struct btQuaternionFloatData& dataOut) const;
+
+ SIMD_FORCE_INLINE void deSerializeFloat(const struct btQuaternionFloatData& dataIn);
+
+ SIMD_FORCE_INLINE void serializeDouble(struct btQuaternionDoubleData& dataOut) const;
+
+ SIMD_FORCE_INLINE void deSerializeDouble(const struct btQuaternionDoubleData& dataIn);
+
};
@@ -903,6 +921,62 @@ shortestArcQuatNormalize2(btVector3& v0,btVector3& v1)
return shortestArcQuat(v0,v1);
}
+
+
+
+struct btQuaternionFloatData
+{
+ float m_floats[4];
+};
+
+struct btQuaternionDoubleData
+{
+ double m_floats[4];
+
+};
+
+SIMD_FORCE_INLINE void btQuaternion::serializeFloat(struct btQuaternionFloatData& dataOut) const
+{
+ ///could also do a memcpy, check if it is worth it
+ for (int i=0;i<4;i++)
+ dataOut.m_floats[i] = float(m_floats[i]);
+}
+
+SIMD_FORCE_INLINE void btQuaternion::deSerializeFloat(const struct btQuaternionFloatData& dataIn)
+{
+ for (int i=0;i<4;i++)
+ m_floats[i] = btScalar(dataIn.m_floats[i]);
+}
+
+
+SIMD_FORCE_INLINE void btQuaternion::serializeDouble(struct btQuaternionDoubleData& dataOut) const
+{
+ ///could also do a memcpy, check if it is worth it
+ for (int i=0;i<4;i++)
+ dataOut.m_floats[i] = double(m_floats[i]);
+}
+
+SIMD_FORCE_INLINE void btQuaternion::deSerializeDouble(const struct btQuaternionDoubleData& dataIn)
+{
+ for (int i=0;i<4;i++)
+ m_floats[i] = btScalar(dataIn.m_floats[i]);
+}
+
+
+SIMD_FORCE_INLINE void btQuaternion::serialize(struct btQuaternionData& dataOut) const
+{
+ ///could also do a memcpy, check if it is worth it
+ for (int i=0;i<4;i++)
+ dataOut.m_floats[i] = m_floats[i];
+}
+
+SIMD_FORCE_INLINE void btQuaternion::deSerialize(const struct btQuaternionData& dataIn)
+{
+ for (int i=0;i<4;i++)
+ m_floats[i] = dataIn.m_floats[i];
+}
+
+
#endif //BT_SIMD__QUATERNION_H_
diff --git a/extern/bullet2/src/LinearMath/btQuickprof.cpp b/extern/bullet2/src/LinearMath/btQuickprof.cpp
index 544aee89d02..d88d965a4cc 100644
--- a/extern/bullet2/src/LinearMath/btQuickprof.cpp
+++ b/extern/bullet2/src/LinearMath/btQuickprof.cpp
@@ -10,7 +10,7 @@
**
***************************************************************************************************/
-// Credits: The Clock class was inspired by the Timer classes in
+// Credits: The Clock class was inspired by the Timer classes in
// Ogre (www.ogre3d.org).
#include "btQuickprof.h"
@@ -27,8 +27,8 @@ static btClock gProfileClock;
#include <stdio.h>
#endif
-#if defined (SUNOS) || defined (__SUNOS__)
-#include <stdio.h>
+#if defined (SUNOS) || defined (__SUNOS__)
+#include <stdio.h>
#endif
#if defined(WIN32) || defined(_WIN32)
@@ -37,12 +37,17 @@ static btClock gProfileClock;
#define WIN32_LEAN_AND_MEAN
#define NOWINRES
#define NOMCX
-#define NOIME
+#define NOIME
#ifdef _XBOX
#include <Xtl.h>
#else //_XBOX
#include <windows.h>
+
+#if WINVER <0x0602
+#define GetTickCount64 GetTickCount
+#endif
+
#endif //_XBOX
#include <time.h>
@@ -59,7 +64,7 @@ struct btClockData
#ifdef BT_USE_WINDOWS_TIMERS
LARGE_INTEGER mClockFrequency;
- DWORD mStartTick;
+ LONGLONG mStartTick;
LONGLONG mPrevElapsedTime;
LARGE_INTEGER mStartTime;
#else
@@ -105,7 +110,7 @@ void btClock::reset()
{
#ifdef BT_USE_WINDOWS_TIMERS
QueryPerformanceCounter(&m_data->mStartTime);
- m_data->mStartTick = GetTickCount();
+ m_data->mStartTick = GetTickCount64();
m_data->mPrevElapsedTime = 0;
#else
#ifdef __CELLOS_LV2__
@@ -121,34 +126,34 @@ void btClock::reset()
#endif
}
-/// Returns the time in ms since the last call to reset or since
+/// Returns the time in ms since the last call to reset or since
/// the btClock was created.
unsigned long int btClock::getTimeMilliseconds()
{
#ifdef BT_USE_WINDOWS_TIMERS
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
- LONGLONG elapsedTime = currentTime.QuadPart -
+ LONGLONG elapsedTime = currentTime.QuadPart -
m_data->mStartTime.QuadPart;
// Compute the number of millisecond ticks elapsed.
- unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
+ unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
m_data->mClockFrequency.QuadPart);
- // Check for unexpected leaps in the Win32 performance counter.
- // (This is caused by unexpected data across the PCI to ISA
+ // Check for unexpected leaps in the Win32 performance counter.
+ // (This is caused by unexpected data across the PCI to ISA
// bridge, aka south bridge. See Microsoft KB274323.)
- unsigned long elapsedTicks = GetTickCount() - m_data->mStartTick;
+ unsigned long elapsedTicks = (unsigned long)(GetTickCount64() - m_data->mStartTick);
signed long msecOff = (signed long)(msecTicks - elapsedTicks);
if (msecOff < -100 || msecOff > 100)
{
// Adjust the starting time forwards.
- LONGLONG msecAdjustment = mymin(msecOff *
- m_data->mClockFrequency.QuadPart / 1000, elapsedTime -
+ LONGLONG msecAdjustment = mymin(msecOff *
+ m_data->mClockFrequency.QuadPart / 1000, elapsedTime -
m_data->mPrevElapsedTime);
m_data->mStartTime.QuadPart += msecAdjustment;
elapsedTime -= msecAdjustment;
// Recompute the number of millisecond ticks elapsed.
- msecTicks = (unsigned long)(1000 * elapsedTime /
+ msecTicks = (unsigned long)(1000 * elapsedTime /
m_data->mClockFrequency.QuadPart);
}
@@ -171,36 +176,36 @@ unsigned long int btClock::getTimeMilliseconds()
struct timeval currentTime;
gettimeofday(&currentTime, 0);
- return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 +
+ return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 +
(currentTime.tv_usec - m_data->mStartTime.tv_usec) / 1000;
#endif //__CELLOS_LV2__
#endif
}
- /// Returns the time in us since the last call to reset or since
+ /// Returns the time in us since the last call to reset or since
/// the Clock was created.
unsigned long int btClock::getTimeMicroseconds()
{
#ifdef BT_USE_WINDOWS_TIMERS
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
- LONGLONG elapsedTime = currentTime.QuadPart -
+ LONGLONG elapsedTime = currentTime.QuadPart -
m_data->mStartTime.QuadPart;
// Compute the number of millisecond ticks elapsed.
- unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
+ unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
m_data->mClockFrequency.QuadPart);
- // Check for unexpected leaps in the Win32 performance counter.
- // (This is caused by unexpected data across the PCI to ISA
+ // Check for unexpected leaps in the Win32 performance counter.
+ // (This is caused by unexpected data across the PCI to ISA
// bridge, aka south bridge. See Microsoft KB274323.)
- unsigned long elapsedTicks = GetTickCount() - m_data->mStartTick;
+ unsigned long elapsedTicks = (unsigned long)(GetTickCount64() - m_data->mStartTick);
signed long msecOff = (signed long)(msecTicks - elapsedTicks);
if (msecOff < -100 || msecOff > 100)
{
// Adjust the starting time forwards.
- LONGLONG msecAdjustment = mymin(msecOff *
- m_data->mClockFrequency.QuadPart / 1000, elapsedTime -
+ LONGLONG msecAdjustment = mymin(msecOff *
+ m_data->mClockFrequency.QuadPart / 1000, elapsedTime -
m_data->mPrevElapsedTime);
m_data->mStartTime.QuadPart += msecAdjustment;
elapsedTime -= msecAdjustment;
@@ -210,7 +215,7 @@ unsigned long int btClock::getTimeMicroseconds()
m_data->mPrevElapsedTime = elapsedTime;
// Convert to microseconds.
- unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime /
+ unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime /
m_data->mClockFrequency.QuadPart);
return usecTicks;
@@ -229,14 +234,22 @@ unsigned long int btClock::getTimeMicroseconds()
struct timeval currentTime;
gettimeofday(&currentTime, 0);
- return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 +
+ return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 +
(currentTime.tv_usec - m_data->mStartTime.tv_usec);
#endif//__CELLOS_LV2__
-#endif
+#endif
}
+/// Returns the time in s since the last call to reset or since
+/// the Clock was created.
+btScalar btClock::getTimeSeconds()
+{
+ static const btScalar microseconds_to_seconds = btScalar(0.000001);
+ return btScalar(getTimeMicroseconds()) * microseconds_to_seconds;
+}
+
inline void Profile_Get_Ticks(unsigned long int * ticks)
@@ -293,8 +306,7 @@ void CProfileNode::CleanupMemory()
CProfileNode::~CProfileNode( void )
{
- delete ( Child);
- delete ( Sibling);
+ CleanupMemory();
}
@@ -318,7 +330,7 @@ CProfileNode * CProfileNode::Get_Sub_Node( const char * name )
}
// We didn't find it, so add it
-
+
CProfileNode * node = new CProfileNode( name, this );
node->Sibling = Child;
Child = node;
@@ -330,7 +342,7 @@ void CProfileNode::Reset( void )
{
TotalCalls = 0;
TotalTime = 0.0f;
-
+
if ( Child ) {
Child->Reset();
@@ -352,7 +364,7 @@ void CProfileNode::Call( void )
bool CProfileNode::Return( void )
{
- if ( --RecursionCounter == 0 && TotalCalls != 0 ) {
+ if ( --RecursionCounter == 0 && TotalCalls != 0 ) {
unsigned long int time;
Profile_Get_Ticks(&time);
time-=StartTime;
@@ -445,8 +457,8 @@ void CProfileManager::Start_Profile( const char * name )
{
if (name != CurrentNode->Get_Name()) {
CurrentNode = CurrentNode->Get_Sub_Node( name );
- }
-
+ }
+
CurrentNode->Call();
}
@@ -470,7 +482,7 @@ void CProfileManager::Stop_Profile( void )
* This resets everything except for the tree structure. All of the timing data is reset. *
*=============================================================================================*/
void CProfileManager::Reset( void )
-{
+{
gProfileClock.reset();
Root.Reset();
Root.Call();
@@ -516,9 +528,9 @@ void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spaci
printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time );
float totalTime = 0.f;
-
+
int numChildren = 0;
-
+
for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next())
{
numChildren++;
@@ -535,11 +547,11 @@ void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spaci
if (parent_time < accumulated_time)
{
- printf("what's wrong\n");
+ //printf("what's wrong\n");
}
for (i=0;i<spacing;i++) printf(".");
printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:",parent_time > SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
-
+
for (i=0;i<numChildren;i++)
{
profileIterator->Enter_Child(i);
diff --git a/extern/bullet2/src/LinearMath/btQuickprof.h b/extern/bullet2/src/LinearMath/btQuickprof.h
index 93f3f4a60fa..362f62d6d40 100644
--- a/extern/bullet2/src/LinearMath/btQuickprof.h
+++ b/extern/bullet2/src/LinearMath/btQuickprof.h
@@ -52,6 +52,11 @@ public:
/// Returns the time in us since the last call to reset or since
/// the Clock was created.
unsigned long int getTimeMicroseconds();
+
+ /// Returns the time in s since the last call to reset or since
+ /// the Clock was created.
+ btScalar getTimeSeconds();
+
private:
struct btClockData* m_data;
};
diff --git a/extern/bullet2/src/LinearMath/btScalar.h b/extern/bullet2/src/LinearMath/btScalar.h
index 401e11eaaa8..0bfd255bdb4 100644
--- a/extern/bullet2/src/LinearMath/btScalar.h
+++ b/extern/bullet2/src/LinearMath/btScalar.h
@@ -28,7 +28,7 @@ subject to the following restrictions:
#include <float.h>
/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
-#define BT_BULLET_VERSION 282
+#define BT_BULLET_VERSION 284
inline int btGetVersion()
{
@@ -48,6 +48,11 @@ inline int btGetVersion()
#define ATTRIBUTE_ALIGNED16(a) a
#define ATTRIBUTE_ALIGNED64(a) a
#define ATTRIBUTE_ALIGNED128(a) a
+ #elif (_M_ARM)
+ #define SIMD_FORCE_INLINE __forceinline
+ #define ATTRIBUTE_ALIGNED16(a) __declspec() a
+ #define ATTRIBUTE_ALIGNED64(a) __declspec() a
+ #define ATTRIBUTE_ALIGNED128(a) __declspec () a
#else
//#define BT_HAS_ALIGNED_ALLOCATOR
#pragma warning(disable : 4324) // disable padding warning
@@ -67,13 +72,20 @@ inline int btGetVersion()
#define btFsel(a,b,c) __fsel((a),(b),(c))
#else
-#if (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION))
+#if defined (_M_ARM)
+ //Do not turn SSE on for ARM (may want to turn on BT_USE_NEON however)
+#elif (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION))
#if _MSC_VER>1400
#define BT_USE_SIMD_VECTOR3
#endif
#define BT_USE_SSE
#ifdef BT_USE_SSE
+
+#if (_MSC_FULL_VER >= 170050727)//Visual Studio 2012 can compile SSE4/FMA3 (but SSE4/FMA3 is not enabled by default)
+ #define BT_ALLOW_SSE4
+#endif //(_MSC_FULL_VER >= 160040219)
+
//BT_USE_SSE_IN_API is disabled under Windows by default, because
//it makes it harder to integrate Bullet into your application under Windows
//(structured embedding Bullet structs/classes need to be 16-byte aligned)
@@ -338,12 +350,23 @@ inline __m128 operator * (const __m128 A, const __m128 B)
#else//BT_USE_NEON
#ifndef BT_INFINITY
- static int btInfinityMask = 0x7F800000;
- #define BT_INFINITY (*(float*)&btInfinityMask)
- inline int btGetInfinityMask()//suppress stupid compiler warning
- {
- return btInfinityMask;
- }
+ struct btInfMaskConverter
+ {
+ union {
+ float mask;
+ int intmask;
+ };
+ btInfMaskConverter(int mask=0x7F800000)
+ :intmask(mask)
+ {
+ }
+ };
+ static btInfMaskConverter btInfinityMask = 0x7F800000;
+ #define BT_INFINITY (btInfinityMask.mask)
+ inline int btGetInfinityMask()//suppress stupid compiler warning
+ {
+ return btInfinityMask.intmask;
+ }
#endif
#endif//BT_USE_NEON
@@ -395,19 +418,30 @@ SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmod(x,y); }
SIMD_FORCE_INLINE btScalar btSqrt(btScalar y)
{
#ifdef USE_APPROXIMATION
+#ifdef __LP64__
+ float xhalf = 0.5f*y;
+ int i = *(int*)&y;
+ i = 0x5f375a86 - (i>>1);
+ y = *(float*)&i;
+ y = y*(1.5f - xhalf*y*y);
+ y = y*(1.5f - xhalf*y*y);
+ y = y*(1.5f - xhalf*y*y);
+ y=1/y;
+ return y;
+#else
double x, z, tempf;
unsigned long *tfptr = ((unsigned long *)&tempf) + 1;
-
- tempf = y;
- *tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */
- x = tempf;
- z = y*btScalar(0.5);
- x = (btScalar(1.5)*x)-(x*x)*(x*z); /* iteration formula */
- x = (btScalar(1.5)*x)-(x*x)*(x*z);
- x = (btScalar(1.5)*x)-(x*x)*(x*z);
- x = (btScalar(1.5)*x)-(x*x)*(x*z);
- x = (btScalar(1.5)*x)-(x*x)*(x*z);
- return x*y;
+ tempf = y;
+ *tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */
+ x = tempf;
+ z = y*btScalar(0.5);
+ x = (btScalar(1.5)*x)-(x*x)*(x*z); /* iteration formula */
+ x = (btScalar(1.5)*x)-(x*x)*(x*z);
+ x = (btScalar(1.5)*x)-(x*x)*(x*z);
+ x = (btScalar(1.5)*x)-(x*x)*(x*z);
+ x = (btScalar(1.5)*x)-(x*x)*(x*z);
+ return x*y;
+#endif
#else
return sqrtf(y);
#endif
@@ -452,9 +486,17 @@ SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmodf(x,y); }
#ifdef BT_USE_DOUBLE_PRECISION
#define SIMD_EPSILON DBL_EPSILON
#define SIMD_INFINITY DBL_MAX
+#define BT_ONE 1.0
+#define BT_ZERO 0.0
+#define BT_TWO 2.0
+#define BT_HALF 0.5
#else
#define SIMD_EPSILON FLT_EPSILON
#define SIMD_INFINITY FLT_MAX
+#define BT_ONE 1.0f
+#define BT_ZERO 0.0f
+#define BT_TWO 2.0f
+#define BT_HALF 0.5f
#endif
SIMD_FORCE_INLINE btScalar btAtan2Fast(btScalar y, btScalar x)
diff --git a/extern/bullet2/src/LinearMath/btSerializer.cpp b/extern/bullet2/src/LinearMath/btSerializer.cpp
index ba344939530..8fdcfb14211 100644
--- a/extern/bullet2/src/LinearMath/btSerializer.cpp
+++ b/extern/bullet2/src/LinearMath/btSerializer.cpp
@@ -1,5 +1,5 @@
char sBulletDNAstr[]= {
-char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(69),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(123),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),
@@ -162,340 +162,433 @@ char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char
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(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(116),char(97),char(117),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(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(0),char(84),char(89),char(80),char(69),
-char(87),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(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),
-char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),
-char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),
-char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),
-char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),
-char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),
-char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),
-char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),
-char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),
-char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),
-char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),
-char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),
-char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),
-char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),
-char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),
-char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),
-char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),
-char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),
-char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),
-char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),
-char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),
-char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),
-char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),
-char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
-char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),
-char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(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(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(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(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(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(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(116),char(97),char(117),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(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(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(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(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(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(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),
+char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),
+char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),
+char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),
+char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),
+char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),
+char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),
+char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),
+char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),
+char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),
+char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),
+char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),
+char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),
+char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),
+char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),
+char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),
+char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),
+char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),
+char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),
+char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),
+char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),
+char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),
+char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),
+char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),
+char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),
+char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),
+char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),
+char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),
+char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),
+char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(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(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(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(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(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(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(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(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(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(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(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(84),char(0),
-char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0),char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),
-char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0),char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),char(60),char(0),char(60),char(0),
-char(16),char(0),char(64),char(0),char(68),char(0),char(-48),char(1),char(0),char(1),char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-24),char(1),
-char(-96),char(3),char(8),char(0),char(52),char(0),char(52),char(0),char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),char(116),char(0),char(92),char(1),
-char(-36),char(0),char(-116),char(1),char(124),char(1),char(-44),char(0),char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2),char(-52),char(0),char(108),char(1),
-char(92),char(0),char(-116),char(0),char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0),char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),
-char(92),char(1),char(104),char(0),char(-84),char(1),char(0),char(0),char(83),char(84),char(82),char(67),char(76),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(13),char(0),char(9),char(0),char(16),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(17),char(0),char(2),char(0),char(15),char(0),char(10),char(0),
-char(13),char(0),char(11),char(0),char(18),char(0),char(2),char(0),char(16),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(19),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(20),char(0),char(6),char(0),
+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(-48),char(1),
+char(0),char(1),char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-24),char(1),char(-96),char(3),char(8),char(0),char(52),char(0),char(52),char(0),
+char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),char(116),char(0),char(92),char(1),char(-36),char(0),char(-116),char(1),char(124),char(1),char(-44),char(0),
+char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2),char(-124),char(2),char(-76),char(4),char(-52),char(0),char(108),char(1),char(92),char(0),char(-116),char(0),
+char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0),char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0),
+char(-84),char(1),char(-68),char(2),char(108),char(1),char(-68),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(21),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(22),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(23),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),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(20),char(0),char(30),char(0),char(22),char(0),char(31),char(0),char(19),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),
-char(24),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(21),char(0),char(30),char(0),char(22),char(0),char(31),char(0),
-char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(19),char(0),char(32),char(0),char(25),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(26),char(0),char(5),char(0),char(25),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(27),char(0),char(5),char(0),char(25),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(28),char(0),char(2),char(0),
-char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(29),char(0),char(4),char(0),char(27),char(0),char(47),char(0),char(28),char(0),char(48),char(0),
-char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(30),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(31),char(0),char(2),char(0),
-char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(32),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),
-char(33),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(34),char(0),char(8),char(0),char(13),char(0),char(54),char(0),
-char(14),char(0),char(55),char(0),char(30),char(0),char(56),char(0),char(32),char(0),char(57),char(0),char(33),char(0),char(58),char(0),char(31),char(0),char(59),char(0),
-char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(35),char(0),char(4),char(0),char(34),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(36),char(0),char(7),char(0),char(25),char(0),char(38),char(0),char(35),char(0),char(65),char(0),
-char(23),char(0),char(66),char(0),char(24),char(0),char(67),char(0),char(37),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),
-char(38),char(0),char(2),char(0),char(36),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(39),char(0),char(4),char(0),char(17),char(0),char(71),char(0),
-char(25),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(40),char(0),char(4),char(0),char(25),char(0),char(38),char(0),
-char(39),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(41),char(0),char(3),char(0),char(27),char(0),char(47),char(0),
-char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(42),char(0),char(3),char(0),char(27),char(0),char(47),char(0),char(4),char(0),char(78),char(0),
-char(0),char(0),char(37),char(0),char(43),char(0),char(3),char(0),char(27),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(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(37),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(44),char(0),char(85),char(0),char(4),char(0),char(86),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(45),char(0),char(5),char(0),char(25),char(0),char(38),char(0),char(35),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(46),char(0),char(5),char(0),char(27),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(47),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),
-char(25),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(18),char(0),char(104),char(0),char(18),char(0),char(105),char(0),char(14),char(0),char(106),char(0),
+char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),
+char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),
+char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),
+char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),
char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),
char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),
char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),
-char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(48),char(0),char(25),char(0),char(9),char(0),char(101),char(0),
-char(9),char(0),char(102),char(0),char(25),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(17),char(0),char(104),char(0),char(17),char(0),char(105),char(0),
+char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(25),char(0),char(9),char(0),char(101),char(0),
+char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),
char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),
char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),
char(7),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),
-char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(49),char(0),char(2),char(0),
-char(50),char(0),char(124),char(0),char(14),char(0),char(125),char(0),char(51),char(0),char(2),char(0),char(52),char(0),char(124),char(0),char(13),char(0),char(125),char(0),
-char(53),char(0),char(21),char(0),char(48),char(0),char(126),char(0),char(15),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0),
+char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(2),char(0),
+char(52),char(0),char(124),char(0),char(14),char(0),char(125),char(0),char(53),char(0),char(2),char(0),char(54),char(0),char(124),char(0),char(13),char(0),char(125),char(0),
+char(55),char(0),char(21),char(0),char(50),char(0),char(126),char(0),char(17),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0),
char(13),char(0),char(-126),char(0),char(13),char(0),char(-125),char(0),char(13),char(0),char(125),char(0),char(13),char(0),char(-124),char(0),char(13),char(0),char(-123),char(0),
char(13),char(0),char(-122),char(0),char(13),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(7),char(0),char(-116),char(0),char(7),char(0),char(-115),char(0),char(7),char(0),char(-114),char(0),char(7),char(0),char(-113),char(0),
-char(7),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(54),char(0),char(22),char(0),char(47),char(0),char(126),char(0),char(16),char(0),char(127),char(0),
+char(7),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(56),char(0),char(22),char(0),char(49),char(0),char(126),char(0),char(18),char(0),char(127),char(0),
char(14),char(0),char(-128),char(0),char(14),char(0),char(-127),char(0),char(14),char(0),char(-126),char(0),char(14),char(0),char(-125),char(0),char(14),char(0),char(125),char(0),
char(14),char(0),char(-124),char(0),char(14),char(0),char(-123),char(0),char(14),char(0),char(-122),char(0),char(14),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(8),char(0),char(-116),char(0),char(8),char(0),char(-115),char(0),
char(8),char(0),char(-114),char(0),char(8),char(0),char(-113),char(0),char(8),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(0),char(0),char(37),char(0),
-char(55),char(0),char(2),char(0),char(4),char(0),char(-110),char(0),char(4),char(0),char(-109),char(0),char(56),char(0),char(13),char(0),char(53),char(0),char(-108),char(0),
-char(53),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),
+char(57),char(0),char(2),char(0),char(4),char(0),char(-110),char(0),char(4),char(0),char(-109),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-108),char(0),
+char(55),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),
char(4),char(0),char(-103),char(0),char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),
-char(7),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(57),char(0),char(13),char(0),char(58),char(0),char(-108),char(0),char(58),char(0),char(-107),char(0),
+char(7),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(59),char(0),char(13),char(0),char(60),char(0),char(-108),char(0),char(60),char(0),char(-107),char(0),
char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0),
char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),
-char(4),char(0),char(-97),char(0),char(59),char(0),char(14),char(0),char(54),char(0),char(-108),char(0),char(54),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),
+char(4),char(0),char(-97),char(0),char(61),char(0),char(14),char(0),char(56),char(0),char(-108),char(0),char(56),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),
char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0),char(8),char(0),char(-102),char(0),
char(8),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),
-char(0),char(0),char(-96),char(0),char(60),char(0),char(3),char(0),char(57),char(0),char(-95),char(0),char(13),char(0),char(-94),char(0),char(13),char(0),char(-93),char(0),
-char(61),char(0),char(3),char(0),char(59),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(62),char(0),char(3),char(0),
-char(57),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(63),char(0),char(13),char(0),char(57),char(0),char(-95),char(0),
-char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),
+char(0),char(0),char(-96),char(0),char(62),char(0),char(3),char(0),char(59),char(0),char(-95),char(0),char(13),char(0),char(-94),char(0),char(13),char(0),char(-93),char(0),
+char(63),char(0),char(3),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(64),char(0),char(3),char(0),
+char(59),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-95),char(0),
+char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),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(64),char(0),char(13),char(0),char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),
-char(17),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),
+char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(66),char(0),char(13),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),
+char(19),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),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(65),char(0),char(14),char(0),char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),
+char(7),char(0),char(-81),char(0),char(67),char(0),char(14),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),
char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),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(0),char(0),char(-80),char(0),char(66),char(0),char(10),char(0),char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),
+char(0),char(0),char(-80),char(0),char(68),char(0),char(10),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),
char(8),char(0),char(-79),char(0),char(8),char(0),char(-78),char(0),char(8),char(0),char(-77),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(-76),char(0),char(67),char(0),char(11),char(0),char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),
-char(17),char(0),char(-91),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),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(-76),char(0),char(0),char(0),char(21),char(0),char(68),char(0),char(9),char(0),
-char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),char(17),char(0),char(-91),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),
-char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(69),char(0),char(9),char(0),
-char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),
-char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(70),char(0),char(5),char(0),
-char(68),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),
-char(71),char(0),char(5),char(0),char(69),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),
-char(8),char(0),char(-65),char(0),char(72),char(0),char(9),char(0),char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),char(17),char(0),char(-91),char(0),
-char(7),char(0),char(-75),char(0),char(7),char(0),char(-74),char(0),char(7),char(0),char(-73),char(0),char(7),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),
-char(4),char(0),char(-70),char(0),char(73),char(0),char(9),char(0),char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),
-char(8),char(0),char(-75),char(0),char(8),char(0),char(-74),char(0),char(8),char(0),char(-73),char(0),char(8),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),
-char(4),char(0),char(-70),char(0),char(74),char(0),char(5),char(0),char(56),char(0),char(-95),char(0),char(13),char(0),char(-64),char(0),char(13),char(0),char(-63),char(0),
-char(7),char(0),char(-62),char(0),char(0),char(0),char(37),char(0),char(75),char(0),char(4),char(0),char(59),char(0),char(-95),char(0),char(14),char(0),char(-64),char(0),
-char(14),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(50),char(0),char(22),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-76),char(0),
-char(8),char(0),char(111),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(113),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(8),char(0),char(-51),char(0),char(8),char(0),char(-50),char(0),char(8),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),
-char(4),char(0),char(-47),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(0),char(0),char(37),char(0),
-char(52),char(0),char(22),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-76),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-60),char(0),
-char(7),char(0),char(113),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(7),char(0),char(-51),char(0),
-char(7),char(0),char(-50),char(0),char(7),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),char(4),char(0),char(-47),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(0),char(0),char(37),char(0),char(76),char(0),char(4),char(0),char(7),char(0),char(-43),char(0),
-char(7),char(0),char(-42),char(0),char(7),char(0),char(-41),char(0),char(4),char(0),char(79),char(0),char(77),char(0),char(10),char(0),char(76),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(7),char(0),char(-120),char(0),char(7),char(0),char(-34),char(0),char(4),char(0),char(-33),char(0),char(4),char(0),char(53),char(0),char(78),char(0),char(4),char(0),
-char(76),char(0),char(-40),char(0),char(4),char(0),char(-32),char(0),char(7),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),char(79),char(0),char(4),char(0),
-char(13),char(0),char(-35),char(0),char(76),char(0),char(-40),char(0),char(4),char(0),char(-29),char(0),char(7),char(0),char(-28),char(0),char(80),char(0),char(7),char(0),
-char(13),char(0),char(-27),char(0),char(76),char(0),char(-40),char(0),char(4),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(4),char(0),char(53),char(0),char(81),char(0),char(6),char(0),char(15),char(0),char(-22),char(0),char(13),char(0),char(-24),char(0),
-char(13),char(0),char(-21),char(0),char(58),char(0),char(-20),char(0),char(4),char(0),char(-19),char(0),char(7),char(0),char(-23),char(0),char(82),char(0),char(26),char(0),
-char(4),char(0),char(-18),char(0),char(7),char(0),char(-17),char(0),char(7),char(0),char(-76),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(7),char(0),char(-13),char(0),char(7),char(0),char(-12),char(0),char(7),char(0),char(-11),char(0),char(7),char(0),char(-10),char(0),
-char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(7),char(0),char(-5),char(0),
-char(7),char(0),char(-4),char(0),char(7),char(0),char(-3),char(0),char(7),char(0),char(-2),char(0),char(7),char(0),char(-1),char(0),char(7),char(0),char(0),char(1),
-char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(3),char(1),char(4),char(0),char(4),char(1),char(4),char(0),char(5),char(1),
-char(4),char(0),char(118),char(0),char(83),char(0),char(12),char(0),char(15),char(0),char(6),char(1),char(15),char(0),char(7),char(1),char(15),char(0),char(8),char(1),
-char(13),char(0),char(9),char(1),char(13),char(0),char(10),char(1),char(7),char(0),char(11),char(1),char(4),char(0),char(12),char(1),char(4),char(0),char(13),char(1),
-char(4),char(0),char(14),char(1),char(4),char(0),char(15),char(1),char(7),char(0),char(-25),char(0),char(4),char(0),char(53),char(0),char(84),char(0),char(27),char(0),
-char(17),char(0),char(16),char(1),char(15),char(0),char(17),char(1),char(15),char(0),char(18),char(1),char(13),char(0),char(9),char(1),char(13),char(0),char(19),char(1),
-char(13),char(0),char(20),char(1),char(13),char(0),char(21),char(1),char(13),char(0),char(22),char(1),char(13),char(0),char(23),char(1),char(4),char(0),char(24),char(1),
-char(7),char(0),char(25),char(1),char(4),char(0),char(26),char(1),char(4),char(0),char(27),char(1),char(4),char(0),char(28),char(1),char(7),char(0),char(29),char(1),
-char(7),char(0),char(30),char(1),char(4),char(0),char(31),char(1),char(4),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(7),char(0),char(37),char(1),char(7),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(41),char(1),char(85),char(0),char(12),char(0),char(9),char(0),char(42),char(1),char(9),char(0),char(43),char(1),
-char(13),char(0),char(44),char(1),char(7),char(0),char(45),char(1),char(7),char(0),char(-57),char(0),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1),
-char(13),char(0),char(48),char(1),char(4),char(0),char(49),char(1),char(4),char(0),char(50),char(1),char(4),char(0),char(51),char(1),char(4),char(0),char(53),char(0),
-char(86),char(0),char(19),char(0),char(48),char(0),char(126),char(0),char(83),char(0),char(52),char(1),char(76),char(0),char(53),char(1),char(77),char(0),char(54),char(1),
-char(78),char(0),char(55),char(1),char(79),char(0),char(56),char(1),char(80),char(0),char(57),char(1),char(81),char(0),char(58),char(1),char(84),char(0),char(59),char(1),
-char(85),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(4),char(0),char(27),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1),
-char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(82),char(0),char(68),char(1),
-};
+char(8),char(0),char(-81),char(0),char(8),char(0),char(-76),char(0),char(69),char(0),char(11),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),
+char(19),char(0),char(-91),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),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(-76),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),
+char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),
+char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(71),char(0),char(9),char(0),
+char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),
+char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(72),char(0),char(5),char(0),
+char(70),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),
+char(73),char(0),char(5),char(0),char(71),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),
+char(8),char(0),char(-65),char(0),char(74),char(0),char(41),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),
+char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),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(13),char(0),char(-60),char(0),char(13),char(0),char(-59),char(0),char(13),char(0),char(-58),char(0),char(13),char(0),char(-57),char(0),
+char(13),char(0),char(-56),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0),
+char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0),char(0),char(0),char(-80),char(0),char(13),char(0),char(-73),char(0),
+char(13),char(0),char(-72),char(0),char(13),char(0),char(-48),char(0),char(13),char(0),char(-47),char(0),char(13),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0),
+char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),
+char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),
+char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-95),char(0),
+char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),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(14),char(0),char(-60),char(0),char(14),char(0),char(-59),char(0),
+char(14),char(0),char(-58),char(0),char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),
+char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0),char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0),
+char(0),char(0),char(-80),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(14),char(0),char(-48),char(0),char(14),char(0),char(-47),char(0),
+char(14),char(0),char(-46),char(0),char(14),char(0),char(-45),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),
+char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),
+char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0),
+char(76),char(0),char(9),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(7),char(0),char(-75),char(0),
+char(7),char(0),char(-74),char(0),char(7),char(0),char(-73),char(0),char(7),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),
+char(77),char(0),char(9),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(8),char(0),char(-75),char(0),
+char(8),char(0),char(-74),char(0),char(8),char(0),char(-73),char(0),char(8),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),
+char(78),char(0),char(5),char(0),char(58),char(0),char(-95),char(0),char(13),char(0),char(-31),char(0),char(13),char(0),char(-30),char(0),char(7),char(0),char(-29),char(0),
+char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-31),char(0),char(14),char(0),char(-30),char(0),
+char(8),char(0),char(-29),char(0),char(52),char(0),char(22),char(0),char(8),char(0),char(-28),char(0),char(8),char(0),char(-76),char(0),char(8),char(0),char(111),char(0),
+char(8),char(0),char(-27),char(0),char(8),char(0),char(113),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(8),char(0),char(-21),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(-17),char(0),char(8),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),
+char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(22),char(0),
+char(7),char(0),char(-28),char(0),char(7),char(0),char(-76),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(113),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(7),char(0),char(-21),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(-17),char(0),
+char(7),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),
+char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(80),char(0),char(4),char(0),char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),
+char(7),char(0),char(-8),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),char(80),char(0),char(-7),char(0),char(13),char(0),char(-6),char(0),
+char(13),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(7),char(0),char(-120),char(0),
+char(7),char(0),char(-1),char(0),char(4),char(0),char(0),char(1),char(4),char(0),char(53),char(0),char(82),char(0),char(4),char(0),char(80),char(0),char(-7),char(0),
+char(4),char(0),char(1),char(1),char(7),char(0),char(2),char(1),char(4),char(0),char(3),char(1),char(83),char(0),char(4),char(0),char(13),char(0),char(-2),char(0),
+char(80),char(0),char(-7),char(0),char(4),char(0),char(4),char(1),char(7),char(0),char(5),char(1),char(84),char(0),char(7),char(0),char(13),char(0),char(6),char(1),
+char(80),char(0),char(-7),char(0),char(4),char(0),char(7),char(1),char(7),char(0),char(8),char(1),char(7),char(0),char(9),char(1),char(7),char(0),char(10),char(1),
+char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(11),char(1),char(13),char(0),char(9),char(1),char(13),char(0),char(12),char(1),
+char(60),char(0),char(13),char(1),char(4),char(0),char(14),char(1),char(7),char(0),char(10),char(1),char(86),char(0),char(26),char(0),char(4),char(0),char(15),char(1),
+char(7),char(0),char(16),char(1),char(7),char(0),char(-76),char(0),char(7),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(19),char(1),
+char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),
+char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),
+char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),
+char(4),char(0),char(35),char(1),char(4),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(118),char(0),
+char(87),char(0),char(12),char(0),char(17),char(0),char(39),char(1),char(17),char(0),char(40),char(1),char(17),char(0),char(41),char(1),char(13),char(0),char(42),char(1),
+char(13),char(0),char(43),char(1),char(7),char(0),char(44),char(1),char(4),char(0),char(45),char(1),char(4),char(0),char(46),char(1),char(4),char(0),char(47),char(1),
+char(4),char(0),char(48),char(1),char(7),char(0),char(8),char(1),char(4),char(0),char(53),char(0),char(88),char(0),char(27),char(0),char(19),char(0),char(49),char(1),
+char(17),char(0),char(50),char(1),char(17),char(0),char(51),char(1),char(13),char(0),char(42),char(1),char(13),char(0),char(52),char(1),char(13),char(0),char(53),char(1),
+char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(4),char(0),char(57),char(1),char(7),char(0),char(58),char(1),
+char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1),
+char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(7),char(0),char(66),char(1),char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1),
+char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(4),char(0),char(72),char(1),char(4),char(0),char(73),char(1),
+char(4),char(0),char(74),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(75),char(1),char(9),char(0),char(76),char(1),char(13),char(0),char(77),char(1),
+char(7),char(0),char(78),char(1),char(7),char(0),char(-24),char(0),char(7),char(0),char(79),char(1),char(4),char(0),char(80),char(1),char(13),char(0),char(81),char(1),
+char(4),char(0),char(82),char(1),char(4),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),
+char(50),char(0),char(126),char(0),char(87),char(0),char(85),char(1),char(80),char(0),char(86),char(1),char(81),char(0),char(87),char(1),char(82),char(0),char(88),char(1),
+char(83),char(0),char(89),char(1),char(84),char(0),char(90),char(1),char(85),char(0),char(91),char(1),char(88),char(0),char(92),char(1),char(89),char(0),char(93),char(1),
+char(4),char(0),char(94),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(97),char(1),
+char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(86),char(0),char(101),char(1),char(91),char(0),char(17),char(0),
+char(16),char(0),char(102),char(1),char(14),char(0),char(103),char(1),char(14),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),
+char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1),char(49),char(0),char(109),char(1),char(14),char(0),char(110),char(1),char(8),char(0),char(111),char(1),
+char(4),char(0),char(112),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(113),char(1),char(4),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(92),char(0),char(17),char(0),char(15),char(0),char(102),char(1),char(13),char(0),char(103),char(1),
+char(13),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1),
+char(50),char(0),char(109),char(1),char(13),char(0),char(110),char(1),char(4),char(0),char(113),char(1),char(7),char(0),char(111),char(1),char(4),char(0),char(112),char(1),
+char(4),char(0),char(84),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(7),char(0),char(117),char(1),char(4),char(0),char(114),char(1),
+char(93),char(0),char(8),char(0),char(0),char(0),char(118),char(1),char(91),char(0),char(88),char(1),char(49),char(0),char(119),char(1),char(20),char(0),char(120),char(1),
+char(14),char(0),char(121),char(1),char(4),char(0),char(95),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),
+char(0),char(0),char(118),char(1),char(92),char(0),char(88),char(1),char(50),char(0),char(119),char(1),char(19),char(0),char(120),char(1),char(13),char(0),char(121),char(1),
+char(7),char(0),char(122),char(1),char(4),char(0),char(95),char(1),};
int sBulletDNAlen= sizeof(sBulletDNAstr);
char sBulletDNAstr64[]= {
-char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(69),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(123),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),
@@ -658,334 +751,427 @@ char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char
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(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(116),char(97),char(117),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(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(0),char(84),char(89),char(80),char(69),
-char(87),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(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),
-char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),
-char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),
-char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),
-char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),
-char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),
-char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),
-char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
-char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),
-char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),
-char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),
-char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),
-char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),
-char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),
-char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),
-char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),
-char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),
-char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
-char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),
-char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),
-char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),
-char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),
-char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),
-char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),
-char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),
-char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),
-char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),
-char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),
-char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),
-char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),
-char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),
-char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(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(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(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(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(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(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(116),char(97),char(117),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(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(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(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(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(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(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),
+char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),
+char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),
+char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),
+char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),
+char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),
+char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),
+char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),
+char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),
+char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),
+char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),
+char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),
+char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),
+char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),
+char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),
+char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),
+char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),
+char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),
+char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),
+char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),
+char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),
+char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),
+char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),
+char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),
+char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),
+char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),
+char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),
+char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),
+char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),
+char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),
+char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),
+char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),
+char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),
+char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),
+char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),
+char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),
+char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),
+char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),
+char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(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(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(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(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(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(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(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(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(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(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(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(96),char(0),
-char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0),char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),
-char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0),char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),char(64),char(0),char(64),char(0),
-char(16),char(0),char(72),char(0),char(80),char(0),char(-32),char(1),char(16),char(1),char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-8),char(1),
-char(-80),char(3),char(8),char(0),char(64),char(0),char(64),char(0),char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),char(-128),char(0),char(104),char(1),
-char(-24),char(0),char(-104),char(1),char(-120),char(1),char(-32),char(0),char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2),char(-40),char(0),char(120),char(1),
-char(104),char(0),char(-104),char(0),char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0),char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),
-char(104),char(1),char(112),char(0),char(-32),char(1),char(0),char(0),char(83),char(84),char(82),char(67),char(76),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(13),char(0),char(9),char(0),char(16),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(17),char(0),char(2),char(0),char(15),char(0),char(10),char(0),
-char(13),char(0),char(11),char(0),char(18),char(0),char(2),char(0),char(16),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(19),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(20),char(0),char(6),char(0),
+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(-32),char(1),
+char(16),char(1),char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-8),char(1),char(-80),char(3),char(8),char(0),char(64),char(0),char(64),char(0),
+char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),char(-128),char(0),char(104),char(1),char(-24),char(0),char(-104),char(1),char(-120),char(1),char(-32),char(0),
+char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2),char(-112),char(2),char(-64),char(4),char(-40),char(0),char(120),char(1),char(104),char(0),char(-104),char(0),
+char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0),char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0),
+char(-32),char(1),char(-56),char(2),char(120),char(1),char(-56),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(21),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(22),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(23),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),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(20),char(0),char(30),char(0),char(22),char(0),char(31),char(0),char(19),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),
-char(24),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(21),char(0),char(30),char(0),char(22),char(0),char(31),char(0),
-char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(19),char(0),char(32),char(0),char(25),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(26),char(0),char(5),char(0),char(25),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(27),char(0),char(5),char(0),char(25),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(28),char(0),char(2),char(0),
-char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(29),char(0),char(4),char(0),char(27),char(0),char(47),char(0),char(28),char(0),char(48),char(0),
-char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(30),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(31),char(0),char(2),char(0),
-char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(32),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),
-char(33),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(34),char(0),char(8),char(0),char(13),char(0),char(54),char(0),
-char(14),char(0),char(55),char(0),char(30),char(0),char(56),char(0),char(32),char(0),char(57),char(0),char(33),char(0),char(58),char(0),char(31),char(0),char(59),char(0),
-char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(35),char(0),char(4),char(0),char(34),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(36),char(0),char(7),char(0),char(25),char(0),char(38),char(0),char(35),char(0),char(65),char(0),
-char(23),char(0),char(66),char(0),char(24),char(0),char(67),char(0),char(37),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),
-char(38),char(0),char(2),char(0),char(36),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(39),char(0),char(4),char(0),char(17),char(0),char(71),char(0),
-char(25),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(40),char(0),char(4),char(0),char(25),char(0),char(38),char(0),
-char(39),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(41),char(0),char(3),char(0),char(27),char(0),char(47),char(0),
-char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(42),char(0),char(3),char(0),char(27),char(0),char(47),char(0),char(4),char(0),char(78),char(0),
-char(0),char(0),char(37),char(0),char(43),char(0),char(3),char(0),char(27),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(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(37),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(44),char(0),char(85),char(0),char(4),char(0),char(86),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(45),char(0),char(5),char(0),char(25),char(0),char(38),char(0),char(35),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(46),char(0),char(5),char(0),char(27),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(47),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),
-char(25),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(18),char(0),char(104),char(0),char(18),char(0),char(105),char(0),char(14),char(0),char(106),char(0),
+char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),
+char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),
+char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),
+char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),
char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),
char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),
char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),
-char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(48),char(0),char(25),char(0),char(9),char(0),char(101),char(0),
-char(9),char(0),char(102),char(0),char(25),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(17),char(0),char(104),char(0),char(17),char(0),char(105),char(0),
+char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(25),char(0),char(9),char(0),char(101),char(0),
+char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0),
char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),
char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),
char(7),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),
-char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(49),char(0),char(2),char(0),
-char(50),char(0),char(124),char(0),char(14),char(0),char(125),char(0),char(51),char(0),char(2),char(0),char(52),char(0),char(124),char(0),char(13),char(0),char(125),char(0),
-char(53),char(0),char(21),char(0),char(48),char(0),char(126),char(0),char(15),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0),
+char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(2),char(0),
+char(52),char(0),char(124),char(0),char(14),char(0),char(125),char(0),char(53),char(0),char(2),char(0),char(54),char(0),char(124),char(0),char(13),char(0),char(125),char(0),
+char(55),char(0),char(21),char(0),char(50),char(0),char(126),char(0),char(17),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0),
char(13),char(0),char(-126),char(0),char(13),char(0),char(-125),char(0),char(13),char(0),char(125),char(0),char(13),char(0),char(-124),char(0),char(13),char(0),char(-123),char(0),
char(13),char(0),char(-122),char(0),char(13),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(7),char(0),char(-116),char(0),char(7),char(0),char(-115),char(0),char(7),char(0),char(-114),char(0),char(7),char(0),char(-113),char(0),
-char(7),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(54),char(0),char(22),char(0),char(47),char(0),char(126),char(0),char(16),char(0),char(127),char(0),
+char(7),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(56),char(0),char(22),char(0),char(49),char(0),char(126),char(0),char(18),char(0),char(127),char(0),
char(14),char(0),char(-128),char(0),char(14),char(0),char(-127),char(0),char(14),char(0),char(-126),char(0),char(14),char(0),char(-125),char(0),char(14),char(0),char(125),char(0),
char(14),char(0),char(-124),char(0),char(14),char(0),char(-123),char(0),char(14),char(0),char(-122),char(0),char(14),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(8),char(0),char(-116),char(0),char(8),char(0),char(-115),char(0),
char(8),char(0),char(-114),char(0),char(8),char(0),char(-113),char(0),char(8),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(0),char(0),char(37),char(0),
-char(55),char(0),char(2),char(0),char(4),char(0),char(-110),char(0),char(4),char(0),char(-109),char(0),char(56),char(0),char(13),char(0),char(53),char(0),char(-108),char(0),
-char(53),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),
+char(57),char(0),char(2),char(0),char(4),char(0),char(-110),char(0),char(4),char(0),char(-109),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-108),char(0),
+char(55),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),
char(4),char(0),char(-103),char(0),char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),
-char(7),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(57),char(0),char(13),char(0),char(58),char(0),char(-108),char(0),char(58),char(0),char(-107),char(0),
+char(7),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(59),char(0),char(13),char(0),char(60),char(0),char(-108),char(0),char(60),char(0),char(-107),char(0),
char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0),
char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),
-char(4),char(0),char(-97),char(0),char(59),char(0),char(14),char(0),char(54),char(0),char(-108),char(0),char(54),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),
+char(4),char(0),char(-97),char(0),char(61),char(0),char(14),char(0),char(56),char(0),char(-108),char(0),char(56),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),
char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0),char(8),char(0),char(-102),char(0),
char(8),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),
-char(0),char(0),char(-96),char(0),char(60),char(0),char(3),char(0),char(57),char(0),char(-95),char(0),char(13),char(0),char(-94),char(0),char(13),char(0),char(-93),char(0),
-char(61),char(0),char(3),char(0),char(59),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(62),char(0),char(3),char(0),
-char(57),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(63),char(0),char(13),char(0),char(57),char(0),char(-95),char(0),
-char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),
+char(0),char(0),char(-96),char(0),char(62),char(0),char(3),char(0),char(59),char(0),char(-95),char(0),char(13),char(0),char(-94),char(0),char(13),char(0),char(-93),char(0),
+char(63),char(0),char(3),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(64),char(0),char(3),char(0),
+char(59),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-95),char(0),
+char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),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(64),char(0),char(13),char(0),char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),
-char(17),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),
+char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(66),char(0),char(13),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),
+char(19),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),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(65),char(0),char(14),char(0),char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),
+char(7),char(0),char(-81),char(0),char(67),char(0),char(14),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),
char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),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(0),char(0),char(-80),char(0),char(66),char(0),char(10),char(0),char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),
+char(0),char(0),char(-80),char(0),char(68),char(0),char(10),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),
char(8),char(0),char(-79),char(0),char(8),char(0),char(-78),char(0),char(8),char(0),char(-77),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(-76),char(0),char(67),char(0),char(11),char(0),char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),
-char(17),char(0),char(-91),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),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(-76),char(0),char(0),char(0),char(21),char(0),char(68),char(0),char(9),char(0),
-char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),char(17),char(0),char(-91),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),
-char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(69),char(0),char(9),char(0),
-char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),
-char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(70),char(0),char(5),char(0),
-char(68),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),
-char(71),char(0),char(5),char(0),char(69),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),
-char(8),char(0),char(-65),char(0),char(72),char(0),char(9),char(0),char(57),char(0),char(-95),char(0),char(17),char(0),char(-92),char(0),char(17),char(0),char(-91),char(0),
-char(7),char(0),char(-75),char(0),char(7),char(0),char(-74),char(0),char(7),char(0),char(-73),char(0),char(7),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),
-char(4),char(0),char(-70),char(0),char(73),char(0),char(9),char(0),char(59),char(0),char(-95),char(0),char(18),char(0),char(-92),char(0),char(18),char(0),char(-91),char(0),
-char(8),char(0),char(-75),char(0),char(8),char(0),char(-74),char(0),char(8),char(0),char(-73),char(0),char(8),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),
-char(4),char(0),char(-70),char(0),char(74),char(0),char(5),char(0),char(56),char(0),char(-95),char(0),char(13),char(0),char(-64),char(0),char(13),char(0),char(-63),char(0),
-char(7),char(0),char(-62),char(0),char(0),char(0),char(37),char(0),char(75),char(0),char(4),char(0),char(59),char(0),char(-95),char(0),char(14),char(0),char(-64),char(0),
-char(14),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(50),char(0),char(22),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-76),char(0),
-char(8),char(0),char(111),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(113),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(8),char(0),char(-51),char(0),char(8),char(0),char(-50),char(0),char(8),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),
-char(4),char(0),char(-47),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(0),char(0),char(37),char(0),
-char(52),char(0),char(22),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-76),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-60),char(0),
-char(7),char(0),char(113),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(7),char(0),char(-51),char(0),
-char(7),char(0),char(-50),char(0),char(7),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0),char(4),char(0),char(-47),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(0),char(0),char(37),char(0),char(76),char(0),char(4),char(0),char(7),char(0),char(-43),char(0),
-char(7),char(0),char(-42),char(0),char(7),char(0),char(-41),char(0),char(4),char(0),char(79),char(0),char(77),char(0),char(10),char(0),char(76),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(7),char(0),char(-120),char(0),char(7),char(0),char(-34),char(0),char(4),char(0),char(-33),char(0),char(4),char(0),char(53),char(0),char(78),char(0),char(4),char(0),
-char(76),char(0),char(-40),char(0),char(4),char(0),char(-32),char(0),char(7),char(0),char(-31),char(0),char(4),char(0),char(-30),char(0),char(79),char(0),char(4),char(0),
-char(13),char(0),char(-35),char(0),char(76),char(0),char(-40),char(0),char(4),char(0),char(-29),char(0),char(7),char(0),char(-28),char(0),char(80),char(0),char(7),char(0),
-char(13),char(0),char(-27),char(0),char(76),char(0),char(-40),char(0),char(4),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(4),char(0),char(53),char(0),char(81),char(0),char(6),char(0),char(15),char(0),char(-22),char(0),char(13),char(0),char(-24),char(0),
-char(13),char(0),char(-21),char(0),char(58),char(0),char(-20),char(0),char(4),char(0),char(-19),char(0),char(7),char(0),char(-23),char(0),char(82),char(0),char(26),char(0),
-char(4),char(0),char(-18),char(0),char(7),char(0),char(-17),char(0),char(7),char(0),char(-76),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(7),char(0),char(-13),char(0),char(7),char(0),char(-12),char(0),char(7),char(0),char(-11),char(0),char(7),char(0),char(-10),char(0),
-char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(7),char(0),char(-5),char(0),
-char(7),char(0),char(-4),char(0),char(7),char(0),char(-3),char(0),char(7),char(0),char(-2),char(0),char(7),char(0),char(-1),char(0),char(7),char(0),char(0),char(1),
-char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(3),char(1),char(4),char(0),char(4),char(1),char(4),char(0),char(5),char(1),
-char(4),char(0),char(118),char(0),char(83),char(0),char(12),char(0),char(15),char(0),char(6),char(1),char(15),char(0),char(7),char(1),char(15),char(0),char(8),char(1),
-char(13),char(0),char(9),char(1),char(13),char(0),char(10),char(1),char(7),char(0),char(11),char(1),char(4),char(0),char(12),char(1),char(4),char(0),char(13),char(1),
-char(4),char(0),char(14),char(1),char(4),char(0),char(15),char(1),char(7),char(0),char(-25),char(0),char(4),char(0),char(53),char(0),char(84),char(0),char(27),char(0),
-char(17),char(0),char(16),char(1),char(15),char(0),char(17),char(1),char(15),char(0),char(18),char(1),char(13),char(0),char(9),char(1),char(13),char(0),char(19),char(1),
-char(13),char(0),char(20),char(1),char(13),char(0),char(21),char(1),char(13),char(0),char(22),char(1),char(13),char(0),char(23),char(1),char(4),char(0),char(24),char(1),
-char(7),char(0),char(25),char(1),char(4),char(0),char(26),char(1),char(4),char(0),char(27),char(1),char(4),char(0),char(28),char(1),char(7),char(0),char(29),char(1),
-char(7),char(0),char(30),char(1),char(4),char(0),char(31),char(1),char(4),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(7),char(0),char(37),char(1),char(7),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(41),char(1),char(85),char(0),char(12),char(0),char(9),char(0),char(42),char(1),char(9),char(0),char(43),char(1),
-char(13),char(0),char(44),char(1),char(7),char(0),char(45),char(1),char(7),char(0),char(-57),char(0),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1),
-char(13),char(0),char(48),char(1),char(4),char(0),char(49),char(1),char(4),char(0),char(50),char(1),char(4),char(0),char(51),char(1),char(4),char(0),char(53),char(0),
-char(86),char(0),char(19),char(0),char(48),char(0),char(126),char(0),char(83),char(0),char(52),char(1),char(76),char(0),char(53),char(1),char(77),char(0),char(54),char(1),
-char(78),char(0),char(55),char(1),char(79),char(0),char(56),char(1),char(80),char(0),char(57),char(1),char(81),char(0),char(58),char(1),char(84),char(0),char(59),char(1),
-char(85),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(4),char(0),char(27),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1),
-char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(82),char(0),char(68),char(1),
-};
+char(8),char(0),char(-81),char(0),char(8),char(0),char(-76),char(0),char(69),char(0),char(11),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),
+char(19),char(0),char(-91),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),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(-76),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),
+char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),
+char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(71),char(0),char(9),char(0),
+char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),
+char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(72),char(0),char(5),char(0),
+char(70),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),
+char(73),char(0),char(5),char(0),char(71),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),
+char(8),char(0),char(-65),char(0),char(74),char(0),char(41),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),
+char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),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(13),char(0),char(-60),char(0),char(13),char(0),char(-59),char(0),char(13),char(0),char(-58),char(0),char(13),char(0),char(-57),char(0),
+char(13),char(0),char(-56),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0),
+char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0),char(0),char(0),char(-80),char(0),char(13),char(0),char(-73),char(0),
+char(13),char(0),char(-72),char(0),char(13),char(0),char(-48),char(0),char(13),char(0),char(-47),char(0),char(13),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0),
+char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0),
+char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),
+char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-95),char(0),
+char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),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(14),char(0),char(-60),char(0),char(14),char(0),char(-59),char(0),
+char(14),char(0),char(-58),char(0),char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),
+char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0),char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0),
+char(0),char(0),char(-80),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(14),char(0),char(-48),char(0),char(14),char(0),char(-47),char(0),
+char(14),char(0),char(-46),char(0),char(14),char(0),char(-45),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0),
+char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),
+char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0),
+char(76),char(0),char(9),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(7),char(0),char(-75),char(0),
+char(7),char(0),char(-74),char(0),char(7),char(0),char(-73),char(0),char(7),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),
+char(77),char(0),char(9),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(8),char(0),char(-75),char(0),
+char(8),char(0),char(-74),char(0),char(8),char(0),char(-73),char(0),char(8),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),
+char(78),char(0),char(5),char(0),char(58),char(0),char(-95),char(0),char(13),char(0),char(-31),char(0),char(13),char(0),char(-30),char(0),char(7),char(0),char(-29),char(0),
+char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-31),char(0),char(14),char(0),char(-30),char(0),
+char(8),char(0),char(-29),char(0),char(52),char(0),char(22),char(0),char(8),char(0),char(-28),char(0),char(8),char(0),char(-76),char(0),char(8),char(0),char(111),char(0),
+char(8),char(0),char(-27),char(0),char(8),char(0),char(113),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(8),char(0),char(-21),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(-17),char(0),char(8),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),
+char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(22),char(0),
+char(7),char(0),char(-28),char(0),char(7),char(0),char(-76),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(113),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(7),char(0),char(-21),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(-17),char(0),
+char(7),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),
+char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(80),char(0),char(4),char(0),char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),
+char(7),char(0),char(-8),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),char(80),char(0),char(-7),char(0),char(13),char(0),char(-6),char(0),
+char(13),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(7),char(0),char(-120),char(0),
+char(7),char(0),char(-1),char(0),char(4),char(0),char(0),char(1),char(4),char(0),char(53),char(0),char(82),char(0),char(4),char(0),char(80),char(0),char(-7),char(0),
+char(4),char(0),char(1),char(1),char(7),char(0),char(2),char(1),char(4),char(0),char(3),char(1),char(83),char(0),char(4),char(0),char(13),char(0),char(-2),char(0),
+char(80),char(0),char(-7),char(0),char(4),char(0),char(4),char(1),char(7),char(0),char(5),char(1),char(84),char(0),char(7),char(0),char(13),char(0),char(6),char(1),
+char(80),char(0),char(-7),char(0),char(4),char(0),char(7),char(1),char(7),char(0),char(8),char(1),char(7),char(0),char(9),char(1),char(7),char(0),char(10),char(1),
+char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(11),char(1),char(13),char(0),char(9),char(1),char(13),char(0),char(12),char(1),
+char(60),char(0),char(13),char(1),char(4),char(0),char(14),char(1),char(7),char(0),char(10),char(1),char(86),char(0),char(26),char(0),char(4),char(0),char(15),char(1),
+char(7),char(0),char(16),char(1),char(7),char(0),char(-76),char(0),char(7),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(19),char(1),
+char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),
+char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),
+char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1),
+char(4),char(0),char(35),char(1),char(4),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(118),char(0),
+char(87),char(0),char(12),char(0),char(17),char(0),char(39),char(1),char(17),char(0),char(40),char(1),char(17),char(0),char(41),char(1),char(13),char(0),char(42),char(1),
+char(13),char(0),char(43),char(1),char(7),char(0),char(44),char(1),char(4),char(0),char(45),char(1),char(4),char(0),char(46),char(1),char(4),char(0),char(47),char(1),
+char(4),char(0),char(48),char(1),char(7),char(0),char(8),char(1),char(4),char(0),char(53),char(0),char(88),char(0),char(27),char(0),char(19),char(0),char(49),char(1),
+char(17),char(0),char(50),char(1),char(17),char(0),char(51),char(1),char(13),char(0),char(42),char(1),char(13),char(0),char(52),char(1),char(13),char(0),char(53),char(1),
+char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(4),char(0),char(57),char(1),char(7),char(0),char(58),char(1),
+char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1),
+char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(7),char(0),char(66),char(1),char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1),
+char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(4),char(0),char(72),char(1),char(4),char(0),char(73),char(1),
+char(4),char(0),char(74),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(75),char(1),char(9),char(0),char(76),char(1),char(13),char(0),char(77),char(1),
+char(7),char(0),char(78),char(1),char(7),char(0),char(-24),char(0),char(7),char(0),char(79),char(1),char(4),char(0),char(80),char(1),char(13),char(0),char(81),char(1),
+char(4),char(0),char(82),char(1),char(4),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),
+char(50),char(0),char(126),char(0),char(87),char(0),char(85),char(1),char(80),char(0),char(86),char(1),char(81),char(0),char(87),char(1),char(82),char(0),char(88),char(1),
+char(83),char(0),char(89),char(1),char(84),char(0),char(90),char(1),char(85),char(0),char(91),char(1),char(88),char(0),char(92),char(1),char(89),char(0),char(93),char(1),
+char(4),char(0),char(94),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(97),char(1),
+char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(86),char(0),char(101),char(1),char(91),char(0),char(17),char(0),
+char(16),char(0),char(102),char(1),char(14),char(0),char(103),char(1),char(14),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1),
+char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1),char(49),char(0),char(109),char(1),char(14),char(0),char(110),char(1),char(8),char(0),char(111),char(1),
+char(4),char(0),char(112),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(113),char(1),char(4),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(92),char(0),char(17),char(0),char(15),char(0),char(102),char(1),char(13),char(0),char(103),char(1),
+char(13),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1),
+char(50),char(0),char(109),char(1),char(13),char(0),char(110),char(1),char(4),char(0),char(113),char(1),char(7),char(0),char(111),char(1),char(4),char(0),char(112),char(1),
+char(4),char(0),char(84),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(7),char(0),char(117),char(1),char(4),char(0),char(114),char(1),
+char(93),char(0),char(8),char(0),char(0),char(0),char(118),char(1),char(91),char(0),char(88),char(1),char(49),char(0),char(119),char(1),char(20),char(0),char(120),char(1),
+char(14),char(0),char(121),char(1),char(4),char(0),char(95),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),
+char(0),char(0),char(118),char(1),char(92),char(0),char(88),char(1),char(50),char(0),char(119),char(1),char(19),char(0),char(120),char(1),char(13),char(0),char(121),char(1),
+char(7),char(0),char(122),char(1),char(4),char(0),char(95),char(1),};
int sBulletDNAlen64= sizeof(sBulletDNAstr64);
diff --git a/extern/bullet2/src/LinearMath/btSerializer.h b/extern/bullet2/src/LinearMath/btSerializer.h
index ff1dc574c5d..033895b1e5e 100644
--- a/extern/bullet2/src/LinearMath/btSerializer.h
+++ b/extern/bullet2/src/LinearMath/btSerializer.h
@@ -4,8 +4,8 @@ Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
+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.
@@ -32,12 +32,12 @@ extern int sBulletDNAlen;
extern char sBulletDNAstr64[];
extern int sBulletDNAlen64;
-SIMD_FORCE_INLINE int btStrLen(const char* str)
+SIMD_FORCE_INLINE int btStrLen(const char* str)
{
- if (!str)
+ if (!str)
return(0);
int len = 0;
-
+
while (*str != 0)
{
str++;
@@ -85,7 +85,7 @@ public:
virtual void* getUniquePointer(void*oldPtr) = 0;
virtual void startSerialization() = 0;
-
+
virtual void finishSerialization() = 0;
virtual const char* findNameForPointer(const void* ptr) const = 0;
@@ -98,6 +98,9 @@ public:
virtual void setSerializationFlags(int flags) = 0;
+ virtual int getNumChunks() const = 0;
+
+ virtual const btChunk* getChunk(int chunkIndex) const = 0;
};
@@ -110,6 +113,8 @@ public:
# define BT_MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
#endif
+
+#define BT_MULTIBODY_CODE BT_MAKE_ID('M','B','D','Y')
#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')
@@ -134,21 +139,46 @@ struct btPointerUid
};
};
+struct btBulletSerializedArrays
+{
+ btBulletSerializedArrays()
+ {
+ }
+ btAlignedObjectArray<struct btQuantizedBvhDoubleData*> m_bvhsDouble;
+ btAlignedObjectArray<struct btQuantizedBvhFloatData*> m_bvhsFloat;
+ btAlignedObjectArray<struct btCollisionShapeData*> m_colShapeData;
+ btAlignedObjectArray<struct btDynamicsWorldDoubleData*> m_dynamicWorldInfoDataDouble;
+ btAlignedObjectArray<struct btDynamicsWorldFloatData*> m_dynamicWorldInfoDataFloat;
+ btAlignedObjectArray<struct btRigidBodyDoubleData*> m_rigidBodyDataDouble;
+ btAlignedObjectArray<struct btRigidBodyFloatData*> m_rigidBodyDataFloat;
+ btAlignedObjectArray<struct btCollisionObjectDoubleData*> m_collisionObjectDataDouble;
+ btAlignedObjectArray<struct btCollisionObjectFloatData*> m_collisionObjectDataFloat;
+ btAlignedObjectArray<struct btTypedConstraintFloatData*> m_constraintDataFloat;
+ btAlignedObjectArray<struct btTypedConstraintDoubleData*> m_constraintDataDouble;
+ btAlignedObjectArray<struct btTypedConstraintData*> m_constraintData;//for backwards compatibility
+ btAlignedObjectArray<struct btSoftBodyFloatData*> m_softBodyFloatData;
+ btAlignedObjectArray<struct btSoftBodyDoubleData*> m_softBodyDoubleData;
+
+};
+
+
///The btDefaultSerializer is the main Bullet serialization class.
///The constructor takes an optional argument for backwards compatibility, it is recommended to leave this empty/zero.
class btDefaultSerializer : public btSerializer
{
+protected:
btAlignedObjectArray<char*> mTypes;
btAlignedObjectArray<short*> mStructs;
btAlignedObjectArray<short> mTlens;
btHashMap<btHashInt, int> mStructReverse;
btHashMap<btHashString,int> mTypeLookup;
-
+
+
btHashMap<btHashPtr,void*> m_chunkP;
-
+
btHashMap<btHashPtr,const char*> m_nameMap;
btHashMap<btHashPtr,btPointerUid> m_uniquePointers;
@@ -156,6 +186,7 @@ class btDefaultSerializer : public btSerializer
int m_totalSize;
unsigned char* m_buffer;
+ bool m_ownsBuffer;
int m_currentSize;
void* m_dna;
int m_dnaLength;
@@ -164,10 +195,11 @@ class btDefaultSerializer : public btSerializer
btAlignedObjectArray<btChunk*> m_chunkPtrs;
-
+
protected:
- virtual void* findPointer(void* oldPtr)
+
+ virtual void* findPointer(void* oldPtr)
{
void** ptr = m_chunkP.find(oldPtr);
if (ptr && *ptr)
@@ -175,11 +207,11 @@ protected:
return 0;
}
-
- void writeDNA()
+
+ virtual void writeDNA()
{
btChunk* dnaChunk = allocate(m_dnaLength,1);
memcpy(dnaChunk->m_oldPtr,m_dna,m_dnaLength);
@@ -193,7 +225,7 @@ protected:
const int* valuePtr = mTypeLookup.find(key);
if (valuePtr)
return *valuePtr;
-
+
return -1;
}
@@ -205,7 +237,7 @@ protected:
int littleEndian= 1;
littleEndian= ((char*)&littleEndian)[0];
-
+
m_dna = btAlignedAlloc(dnalen,16);
memcpy(m_dna,bdnaOrg,dnalen);
@@ -233,16 +265,16 @@ protected:
// Parse names
if (!littleEndian)
*intPtr = btSwapEndian(*intPtr);
-
+
dataLen = *intPtr;
-
+
intPtr++;
cp = (char*)intPtr;
int i;
for ( i=0; i<dataLen; i++)
{
-
+
while (*cp)cp++;
cp++;
}
@@ -260,11 +292,11 @@ protected:
if (!littleEndian)
*intPtr = btSwapEndian(*intPtr);
-
+
dataLen = *intPtr;
intPtr++;
-
+
cp = (char*)intPtr;
for (i=0; i<dataLen; i++)
{
@@ -315,7 +347,7 @@ protected:
if (!littleEndian)
*intPtr = btSwapEndian(*intPtr);
- dataLen = *intPtr ;
+ dataLen = *intPtr ;
intPtr++;
@@ -323,7 +355,7 @@ protected:
for (i=0; i<dataLen; i++)
{
mStructs.push_back (shtPtr);
-
+
if (!littleEndian)
{
shtPtr[0]= btSwapEndian(shtPtr[0]);
@@ -353,20 +385,28 @@ protected:
}
}
-public:
-
+public:
+
+ btHashMap<btHashPtr,void*> m_skipPointers;
-
- btDefaultSerializer(int totalSize=0)
+ btDefaultSerializer(int totalSize=0, unsigned char* buffer=0)
:m_totalSize(totalSize),
m_currentSize(0),
m_dna(0),
m_dnaLength(0),
m_serializationFlags(0)
{
- m_buffer = m_totalSize?(unsigned char*)btAlignedAlloc(totalSize,16):0;
-
+ if (buffer==0)
+ {
+ m_buffer = m_totalSize?(unsigned char*)btAlignedAlloc(totalSize,16):0;
+ m_ownsBuffer = true;
+ } else
+ {
+ m_buffer = buffer;
+ m_ownsBuffer = false;
+ }
+
const bool VOID_IS_8 = ((sizeof(void*)==8));
#ifdef BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
@@ -385,7 +425,7 @@ public:
btAssert(0);
#endif
}
-
+
#else //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
if (VOID_IS_8)
{
@@ -395,27 +435,33 @@ public:
initDNA((const char*)sBulletDNAstr,sBulletDNAlen);
}
#endif //BT_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES
-
+
}
- virtual ~btDefaultSerializer()
+ virtual ~btDefaultSerializer()
{
- if (m_buffer)
+ if (m_buffer && m_ownsBuffer)
btAlignedFree(m_buffer);
if (m_dna)
btAlignedFree(m_dna);
}
+ void insertHeader()
+ {
+ writeHeader(m_buffer);
+ m_currentSize += BT_HEADER_LENGTH;
+ }
+
void writeHeader(unsigned char* buffer) const
{
-
+
#ifdef BT_USE_DOUBLE_PRECISION
memcpy(buffer, "BULLETd", 7);
#else
memcpy(buffer, "BULLETf", 7);
#endif //BT_USE_DOUBLE_PRECISION
-
+
int littleEndian= 1;
littleEndian= ((char*)&littleEndian)[0];
@@ -429,7 +475,7 @@ public:
if (littleEndian)
{
- buffer[8]='v';
+ buffer[8]='v';
} else
{
buffer[8]='V';
@@ -438,7 +484,7 @@ public:
buffer[9] = '2';
buffer[10] = '8';
- buffer[11] = '2';
+ buffer[11] = '4';
}
@@ -450,7 +496,7 @@ public:
unsigned char* buffer = internalAlloc(BT_HEADER_LENGTH);
writeHeader(buffer);
}
-
+
}
virtual void finishSerialization()
@@ -486,6 +532,7 @@ public:
mTlens.clear();
mStructReverse.clear();
mTypeLookup.clear();
+ m_skipPointers.clear();
m_chunkP.clear();
m_nameMap.clear();
m_uniquePointers.clear();
@@ -502,8 +549,15 @@ public:
{
return uptr->m_ptr;
}
+
+ void** ptr2 = m_skipPointers[oldPtr];
+ if (ptr2)
+ {
+ return 0;
+ }
+
m_uniqueIdGenerator++;
-
+
btPointerUid uid;
uid.m_uniqueIds[0] = m_uniqueIdGenerator;
uid.m_uniqueIds[1] = m_uniqueIdGenerator;
@@ -530,17 +584,17 @@ public:
}
chunk->m_dna_nr = getReverseType(structType);
-
+
chunk->m_chunkCode = chunkCode;
-
+
void* uniquePtr = getUniquePointer(oldPtr);
-
+
m_chunkP.insert(oldPtr,uniquePtr);//chunk->m_oldPtr);
chunk->m_oldPtr = uniquePtr;//oldPtr;
-
+
}
-
+
virtual unsigned char* internalAlloc(size_t size)
{
unsigned char* ptr = 0;
@@ -558,7 +612,7 @@ public:
return ptr;
}
-
+
virtual btChunk* allocate(size_t size, int numElements)
{
@@ -566,15 +620,15 @@ public:
unsigned char* ptr = internalAlloc(int(size)*numElements+sizeof(btChunk));
unsigned char* data = ptr + sizeof(btChunk);
-
+
btChunk* chunk = (btChunk*)ptr;
chunk->m_chunkCode = 0;
chunk->m_oldPtr = data;
chunk->m_length = int(size)*numElements;
chunk->m_number = numElements;
-
+
m_chunkPtrs.push_back(chunk);
-
+
return chunk;
}
@@ -631,9 +685,202 @@ public:
{
m_serializationFlags = flags;
}
+ int getNumChunks() const
+ {
+ return m_chunkPtrs.size();
+ }
+ const btChunk* getChunk(int chunkIndex) const
+ {
+ return m_chunkPtrs[chunkIndex];
+ }
};
+///In general it is best to use btDefaultSerializer,
+///in particular when writing the data to disk or sending it over the network.
+///The btInMemorySerializer is experimental and only suitable in a few cases.
+///The btInMemorySerializer takes a shortcut and can be useful to create a deep-copy
+///of objects. There will be a demo on how to use the btInMemorySerializer.
+#ifdef ENABLE_INMEMORY_SERIALIZER
+
+struct btInMemorySerializer : public btDefaultSerializer
+{
+ btHashMap<btHashPtr,btChunk*> m_uid2ChunkPtr;
+ btHashMap<btHashPtr,void*> m_orgPtr2UniqueDataPtr;
+ btHashMap<btHashString,const void*> m_names2Ptr;
+
+
+ btBulletSerializedArrays m_arrays;
+
+ btInMemorySerializer(int totalSize=0, unsigned char* buffer=0)
+ :btDefaultSerializer(totalSize,buffer)
+ {
+
+ }
+
+ virtual void startSerialization()
+ {
+ m_uid2ChunkPtr.clear();
+ //todo: m_arrays.clear();
+ btDefaultSerializer::startSerialization();
+ }
+
+
+
+ btChunk* findChunkFromUniquePointer(void* uniquePointer)
+ {
+ btChunk** chkPtr = m_uid2ChunkPtr[uniquePointer];
+ if (chkPtr)
+ {
+ return *chkPtr;
+ }
+ return 0;
+ }
+
+ virtual void registerNameForPointer(const void* ptr, const char* name)
+ {
+ btDefaultSerializer::registerNameForPointer(ptr,name);
+ m_names2Ptr.insert(name,ptr);
+ }
+
+ virtual void finishSerialization()
+ {
+ }
+
+ virtual void* getUniquePointer(void*oldPtr)
+ {
+ if (oldPtr==0)
+ return 0;
+
+ // void* uniquePtr = getUniquePointer(oldPtr);
+ btChunk* chunk = findChunkFromUniquePointer(oldPtr);
+ if (chunk)
+ {
+ return chunk->m_oldPtr;
+ } else
+ {
+ const char* n = (const char*) oldPtr;
+ const void** ptr = m_names2Ptr[n];
+ if (ptr)
+ {
+ return oldPtr;
+ } else
+ {
+ void** ptr2 = m_skipPointers[oldPtr];
+ if (ptr2)
+ {
+ return 0;
+ } else
+ {
+ //If this assert hit, serialization happened in the wrong order
+ // 'getUniquePointer'
+ btAssert(0);
+ }
+
+ }
+ return 0;
+ }
+ return oldPtr;
+ }
+
+ virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)
+ {
+ if (!(m_serializationFlags&BT_SERIALIZE_NO_DUPLICATE_ASSERT))
+ {
+ btAssert(!findPointer(oldPtr));
+ }
+
+ chunk->m_dna_nr = getReverseType(structType);
+ chunk->m_chunkCode = chunkCode;
+ //void* uniquePtr = getUniquePointer(oldPtr);
+ m_chunkP.insert(oldPtr,oldPtr);//chunk->m_oldPtr);
+ // chunk->m_oldPtr = uniquePtr;//oldPtr;
+
+ void* uid = findPointer(oldPtr);
+ m_uid2ChunkPtr.insert(uid,chunk);
+
+ switch (chunk->m_chunkCode)
+ {
+ case BT_SOFTBODY_CODE:
+ {
+ #ifdef BT_USE_DOUBLE_PRECISION
+ m_arrays.m_softBodyDoubleData.push_back((btSoftBodyDoubleData*) chunk->m_oldPtr);
+ #else
+ m_arrays.m_softBodyFloatData.push_back((btSoftBodyFloatData*) chunk->m_oldPtr);
+ #endif
+ break;
+ }
+ case BT_COLLISIONOBJECT_CODE:
+ {
+ #ifdef BT_USE_DOUBLE_PRECISION
+ m_arrays.m_collisionObjectDataDouble.push_back((btCollisionObjectDoubleData*)chunk->m_oldPtr);
+ #else//BT_USE_DOUBLE_PRECISION
+ m_arrays.m_collisionObjectDataFloat.push_back((btCollisionObjectFloatData*)chunk->m_oldPtr);
+ #endif //BT_USE_DOUBLE_PRECISION
+ break;
+ }
+ case BT_RIGIDBODY_CODE:
+ {
+ #ifdef BT_USE_DOUBLE_PRECISION
+ m_arrays.m_rigidBodyDataDouble.push_back((btRigidBodyDoubleData*)chunk->m_oldPtr);
+ #else
+ m_arrays.m_rigidBodyDataFloat.push_back((btRigidBodyFloatData*)chunk->m_oldPtr);
+ #endif//BT_USE_DOUBLE_PRECISION
+ break;
+ };
+ case BT_CONSTRAINT_CODE:
+ {
+ #ifdef BT_USE_DOUBLE_PRECISION
+ m_arrays.m_constraintDataDouble.push_back((btTypedConstraintDoubleData*)chunk->m_oldPtr);
+ #else
+ m_arrays.m_constraintDataFloat.push_back((btTypedConstraintFloatData*)chunk->m_oldPtr);
+ #endif
+ break;
+ }
+ case BT_QUANTIZED_BVH_CODE:
+ {
+ #ifdef BT_USE_DOUBLE_PRECISION
+ m_arrays.m_bvhsDouble.push_back((btQuantizedBvhDoubleData*) chunk->m_oldPtr);
+ #else
+ m_arrays.m_bvhsFloat.push_back((btQuantizedBvhFloatData*) chunk->m_oldPtr);
+ #endif
+ break;
+ }
+
+ case BT_SHAPE_CODE:
+ {
+ btCollisionShapeData* shapeData = (btCollisionShapeData*) chunk->m_oldPtr;
+ m_arrays.m_colShapeData.push_back(shapeData);
+ break;
+ }
+ case BT_TRIANLGE_INFO_MAP:
+ case BT_ARRAY_CODE:
+ case BT_SBMATERIAL_CODE:
+ case BT_SBNODE_CODE:
+ case BT_DYNAMICSWORLD_CODE:
+ case BT_DNA_CODE:
+ {
+ break;
+ }
+ default:
+ {
+ }
+ };
+ }
+
+ int getNumChunks() const
+ {
+ return m_uid2ChunkPtr.size();
+ }
+
+ const btChunk* getChunk(int chunkIndex) const
+ {
+ return *m_uid2ChunkPtr.getAtIndex(chunkIndex);
+ }
+
+};
+#endif //ENABLE_INMEMORY_SERIALIZER
+
#endif //BT_SERIALIZER_H
diff --git a/extern/bullet2/src/LinearMath/btSpatialAlgebra.h b/extern/bullet2/src/LinearMath/btSpatialAlgebra.h
new file mode 100644
index 00000000000..8e59658bca7
--- /dev/null
+++ b/extern/bullet2/src/LinearMath/btSpatialAlgebra.h
@@ -0,0 +1,331 @@
+/*
+Copyright (c) 2003-2015 Erwin Coumans, Jakub Stepien
+
+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.
+*/
+
+///These spatial algebra classes are used for btMultiBody,
+///see BulletDynamics/Featherstone
+
+#ifndef BT_SPATIAL_ALGEBRA_H
+#define BT_SPATIAL_ALGEBRA_H
+
+
+#include "btMatrix3x3.h"
+
+struct btSpatialForceVector
+{
+ btVector3 m_topVec, m_bottomVec;
+ //
+ btSpatialForceVector() { setZero(); }
+ btSpatialForceVector(const btVector3 &angular, const btVector3 &linear) : m_topVec(linear), m_bottomVec(angular) {}
+ btSpatialForceVector(const btScalar &ax, const btScalar &ay, const btScalar &az, const btScalar &lx, const btScalar &ly, const btScalar &lz)
+ {
+ setValue(ax, ay, az, lx, ly, lz);
+ }
+ //
+ void setVector(const btVector3 &angular, const btVector3 &linear) { m_topVec = linear; m_bottomVec = angular; }
+ void setValue(const btScalar &ax, const btScalar &ay, const btScalar &az, const btScalar &lx, const btScalar &ly, const btScalar &lz)
+ {
+ m_bottomVec.setValue(ax, ay, az); m_topVec.setValue(lx, ly, lz);
+ }
+ //
+ void addVector(const btVector3 &angular, const btVector3 &linear) { m_topVec += linear; m_bottomVec += angular; }
+ void addValue(const btScalar &ax, const btScalar &ay, const btScalar &az, const btScalar &lx, const btScalar &ly, const btScalar &lz)
+ {
+ m_bottomVec[0] += ax; m_bottomVec[1] += ay; m_bottomVec[2] += az;
+ m_topVec[0] += lx; m_topVec[1] += ly; m_topVec[2] += lz;
+ }
+ //
+ const btVector3 & getLinear() const { return m_topVec; }
+ const btVector3 & getAngular() const { return m_bottomVec; }
+ //
+ void setLinear(const btVector3 &linear) { m_topVec = linear; }
+ void setAngular(const btVector3 &angular) { m_bottomVec = angular; }
+ //
+ void addAngular(const btVector3 &angular) { m_bottomVec += angular; }
+ void addLinear(const btVector3 &linear) { m_topVec += linear; }
+ //
+ void setZero() { m_topVec.setZero(); m_bottomVec.setZero(); }
+ //
+ btSpatialForceVector & operator += (const btSpatialForceVector &vec) { m_topVec += vec.m_topVec; m_bottomVec += vec.m_bottomVec; return *this; }
+ btSpatialForceVector & operator -= (const btSpatialForceVector &vec) { m_topVec -= vec.m_topVec; m_bottomVec -= vec.m_bottomVec; return *this; }
+ btSpatialForceVector operator - (const btSpatialForceVector &vec) const { return btSpatialForceVector(m_bottomVec - vec.m_bottomVec, m_topVec - vec.m_topVec); }
+ btSpatialForceVector operator + (const btSpatialForceVector &vec) const { return btSpatialForceVector(m_bottomVec + vec.m_bottomVec, m_topVec + vec.m_topVec); }
+ btSpatialForceVector operator - () const { return btSpatialForceVector(-m_bottomVec, -m_topVec); }
+ btSpatialForceVector operator * (const btScalar &s) const { return btSpatialForceVector(s * m_bottomVec, s * m_topVec); }
+ //btSpatialForceVector & operator = (const btSpatialForceVector &vec) { m_topVec = vec.m_topVec; m_bottomVec = vec.m_bottomVec; return *this; }
+};
+
+struct btSpatialMotionVector
+{
+ btVector3 m_topVec, m_bottomVec;
+ //
+ btSpatialMotionVector() { setZero(); }
+ btSpatialMotionVector(const btVector3 &angular, const btVector3 &linear) : m_topVec(angular), m_bottomVec(linear) {}
+ //
+ void setVector(const btVector3 &angular, const btVector3 &linear) { m_topVec = angular; m_bottomVec = linear; }
+ void setValue(const btScalar &ax, const btScalar &ay, const btScalar &az, const btScalar &lx, const btScalar &ly, const btScalar &lz)
+ {
+ m_topVec.setValue(ax, ay, az); m_bottomVec.setValue(lx, ly, lz);
+ }
+ //
+ void addVector(const btVector3 &angular, const btVector3 &linear) { m_topVec += linear; m_bottomVec += angular; }
+ void addValue(const btScalar &ax, const btScalar &ay, const btScalar &az, const btScalar &lx, const btScalar &ly, const btScalar &lz)
+ {
+ m_topVec[0] += ax; m_topVec[1] += ay; m_topVec[2] += az;
+ m_bottomVec[0] += lx; m_bottomVec[1] += ly; m_bottomVec[2] += lz;
+ }
+ //
+ const btVector3 & getAngular() const { return m_topVec; }
+ const btVector3 & getLinear() const { return m_bottomVec; }
+ //
+ void setAngular(const btVector3 &angular) { m_topVec = angular; }
+ void setLinear(const btVector3 &linear) { m_bottomVec = linear; }
+ //
+ void addAngular(const btVector3 &angular) { m_topVec += angular; }
+ void addLinear(const btVector3 &linear) { m_bottomVec += linear; }
+ //
+ void setZero() { m_topVec.setZero(); m_bottomVec.setZero(); }
+ //
+ btScalar dot(const btSpatialForceVector &b) const
+ {
+ return m_bottomVec.dot(b.m_topVec) + m_topVec.dot(b.m_bottomVec);
+ }
+ //
+ template<typename SpatialVectorType>
+ void cross(const SpatialVectorType &b, SpatialVectorType &out) const
+ {
+ out.m_topVec = m_topVec.cross(b.m_topVec);
+ out.m_bottomVec = m_bottomVec.cross(b.m_topVec) + m_topVec.cross(b.m_bottomVec);
+ }
+ template<typename SpatialVectorType>
+ SpatialVectorType cross(const SpatialVectorType &b) const
+ {
+ SpatialVectorType out;
+ out.m_topVec = m_topVec.cross(b.m_topVec);
+ out.m_bottomVec = m_bottomVec.cross(b.m_topVec) + m_topVec.cross(b.m_bottomVec);
+ return out;
+ }
+ //
+ btSpatialMotionVector & operator += (const btSpatialMotionVector &vec) { m_topVec += vec.m_topVec; m_bottomVec += vec.m_bottomVec; return *this; }
+ btSpatialMotionVector & operator -= (const btSpatialMotionVector &vec) { m_topVec -= vec.m_topVec; m_bottomVec -= vec.m_bottomVec; return *this; }
+ btSpatialMotionVector & operator *= (const btScalar &s) { m_topVec *= s; m_bottomVec *= s; return *this; }
+ btSpatialMotionVector operator - (const btSpatialMotionVector &vec) const { return btSpatialMotionVector(m_topVec - vec.m_topVec, m_bottomVec - vec.m_bottomVec); }
+ btSpatialMotionVector operator + (const btSpatialMotionVector &vec) const { return btSpatialMotionVector(m_topVec + vec.m_topVec, m_bottomVec + vec.m_bottomVec); }
+ btSpatialMotionVector operator - () const { return btSpatialMotionVector(-m_topVec, -m_bottomVec); }
+ btSpatialMotionVector operator * (const btScalar &s) const { return btSpatialMotionVector(s * m_topVec, s * m_bottomVec); }
+};
+
+struct btSymmetricSpatialDyad
+{
+ btMatrix3x3 m_topLeftMat, m_topRightMat, m_bottomLeftMat;
+ //
+ btSymmetricSpatialDyad() { setIdentity(); }
+ btSymmetricSpatialDyad(const btMatrix3x3 &topLeftMat, const btMatrix3x3 &topRightMat, const btMatrix3x3 &bottomLeftMat) { setMatrix(topLeftMat, topRightMat, bottomLeftMat); }
+ //
+ void setMatrix(const btMatrix3x3 &topLeftMat, const btMatrix3x3 &topRightMat, const btMatrix3x3 &bottomLeftMat)
+ {
+ m_topLeftMat = topLeftMat;
+ m_topRightMat = topRightMat;
+ m_bottomLeftMat = bottomLeftMat;
+ }
+ //
+ void addMatrix(const btMatrix3x3 &topLeftMat, const btMatrix3x3 &topRightMat, const btMatrix3x3 &bottomLeftMat)
+ {
+ m_topLeftMat += topLeftMat;
+ m_topRightMat += topRightMat;
+ m_bottomLeftMat += bottomLeftMat;
+ }
+ //
+ void setIdentity() { m_topLeftMat.setIdentity(); m_topRightMat.setIdentity(); m_bottomLeftMat.setIdentity(); }
+ //
+ btSymmetricSpatialDyad & operator -= (const btSymmetricSpatialDyad &mat)
+ {
+ m_topLeftMat -= mat.m_topLeftMat;
+ m_topRightMat -= mat.m_topRightMat;
+ m_bottomLeftMat -= mat.m_bottomLeftMat;
+ return *this;
+ }
+ //
+ btSpatialForceVector operator * (const btSpatialMotionVector &vec)
+ {
+ return btSpatialForceVector(m_bottomLeftMat * vec.m_topVec + m_topLeftMat.transpose() * vec.m_bottomVec, m_topLeftMat * vec.m_topVec + m_topRightMat * vec.m_bottomVec);
+ }
+};
+
+struct btSpatialTransformationMatrix
+{
+ btMatrix3x3 m_rotMat; //btMatrix3x3 m_trnCrossMat;
+ btVector3 m_trnVec;
+ //
+ enum eOutputOperation
+ {
+ None = 0,
+ Add = 1,
+ Subtract = 2
+ };
+ //
+ template<typename SpatialVectorType>
+ void transform( const SpatialVectorType &inVec,
+ SpatialVectorType &outVec,
+ eOutputOperation outOp = None)
+ {
+ if(outOp == None)
+ {
+ outVec.m_topVec = m_rotMat * inVec.m_topVec;
+ outVec.m_bottomVec = -m_trnVec.cross(outVec.m_topVec) + m_rotMat * inVec.m_bottomVec;
+ }
+ else if(outOp == Add)
+ {
+ outVec.m_topVec += m_rotMat * inVec.m_topVec;
+ outVec.m_bottomVec += -m_trnVec.cross(outVec.m_topVec) + m_rotMat * inVec.m_bottomVec;
+ }
+ else if(outOp == Subtract)
+ {
+ outVec.m_topVec -= m_rotMat * inVec.m_topVec;
+ outVec.m_bottomVec -= -m_trnVec.cross(outVec.m_topVec) + m_rotMat * inVec.m_bottomVec;
+ }
+
+ }
+
+ template<typename SpatialVectorType>
+ void transformRotationOnly( const SpatialVectorType &inVec,
+ SpatialVectorType &outVec,
+ eOutputOperation outOp = None)
+ {
+ if(outOp == None)
+ {
+ outVec.m_topVec = m_rotMat * inVec.m_topVec;
+ outVec.m_bottomVec = m_rotMat * inVec.m_bottomVec;
+ }
+ else if(outOp == Add)
+ {
+ outVec.m_topVec += m_rotMat * inVec.m_topVec;
+ outVec.m_bottomVec += m_rotMat * inVec.m_bottomVec;
+ }
+ else if(outOp == Subtract)
+ {
+ outVec.m_topVec -= m_rotMat * inVec.m_topVec;
+ outVec.m_bottomVec -= m_rotMat * inVec.m_bottomVec;
+ }
+
+ }
+
+ template<typename SpatialVectorType>
+ void transformInverse( const SpatialVectorType &inVec,
+ SpatialVectorType &outVec,
+ eOutputOperation outOp = None)
+ {
+ if(outOp == None)
+ {
+ outVec.m_topVec = m_rotMat.transpose() * inVec.m_topVec;
+ outVec.m_bottomVec = m_rotMat.transpose() * (inVec.m_bottomVec + m_trnVec.cross(inVec.m_topVec));
+ }
+ else if(outOp == Add)
+ {
+ outVec.m_topVec += m_rotMat.transpose() * inVec.m_topVec;
+ outVec.m_bottomVec += m_rotMat.transpose() * (inVec.m_bottomVec + m_trnVec.cross(inVec.m_topVec));
+ }
+ else if(outOp == Subtract)
+ {
+ outVec.m_topVec -= m_rotMat.transpose() * inVec.m_topVec;
+ outVec.m_bottomVec -= m_rotMat.transpose() * (inVec.m_bottomVec + m_trnVec.cross(inVec.m_topVec));
+ }
+ }
+
+ template<typename SpatialVectorType>
+ void transformInverseRotationOnly( const SpatialVectorType &inVec,
+ SpatialVectorType &outVec,
+ eOutputOperation outOp = None)
+ {
+ if(outOp == None)
+ {
+ outVec.m_topVec = m_rotMat.transpose() * inVec.m_topVec;
+ outVec.m_bottomVec = m_rotMat.transpose() * inVec.m_bottomVec;
+ }
+ else if(outOp == Add)
+ {
+ outVec.m_topVec += m_rotMat.transpose() * inVec.m_topVec;
+ outVec.m_bottomVec += m_rotMat.transpose() * inVec.m_bottomVec;
+ }
+ else if(outOp == Subtract)
+ {
+ outVec.m_topVec -= m_rotMat.transpose() * inVec.m_topVec;
+ outVec.m_bottomVec -= m_rotMat.transpose() * inVec.m_bottomVec;
+ }
+
+ }
+
+ void transformInverse( const btSymmetricSpatialDyad &inMat,
+ btSymmetricSpatialDyad &outMat,
+ eOutputOperation outOp = None)
+ {
+ const btMatrix3x3 r_cross( 0, -m_trnVec[2], m_trnVec[1],
+ m_trnVec[2], 0, -m_trnVec[0],
+ -m_trnVec[1], m_trnVec[0], 0);
+
+
+ if(outOp == None)
+ {
+ outMat.m_topLeftMat = m_rotMat.transpose() * ( inMat.m_topLeftMat - inMat.m_topRightMat * r_cross ) * m_rotMat;
+ outMat.m_topRightMat = m_rotMat.transpose() * inMat.m_topRightMat * m_rotMat;
+ outMat.m_bottomLeftMat = m_rotMat.transpose() * (r_cross * (inMat.m_topLeftMat - inMat.m_topRightMat * r_cross) + inMat.m_bottomLeftMat - inMat.m_topLeftMat.transpose() * r_cross) * m_rotMat;
+ }
+ else if(outOp == Add)
+ {
+ outMat.m_topLeftMat += m_rotMat.transpose() * ( inMat.m_topLeftMat - inMat.m_topRightMat * r_cross ) * m_rotMat;
+ outMat.m_topRightMat += m_rotMat.transpose() * inMat.m_topRightMat * m_rotMat;
+ outMat.m_bottomLeftMat += m_rotMat.transpose() * (r_cross * (inMat.m_topLeftMat - inMat.m_topRightMat * r_cross) + inMat.m_bottomLeftMat - inMat.m_topLeftMat.transpose() * r_cross) * m_rotMat;
+ }
+ else if(outOp == Subtract)
+ {
+ outMat.m_topLeftMat -= m_rotMat.transpose() * ( inMat.m_topLeftMat - inMat.m_topRightMat * r_cross ) * m_rotMat;
+ outMat.m_topRightMat -= m_rotMat.transpose() * inMat.m_topRightMat * m_rotMat;
+ outMat.m_bottomLeftMat -= m_rotMat.transpose() * (r_cross * (inMat.m_topLeftMat - inMat.m_topRightMat * r_cross) + inMat.m_bottomLeftMat - inMat.m_topLeftMat.transpose() * r_cross) * m_rotMat;
+ }
+ }
+
+ template<typename SpatialVectorType>
+ SpatialVectorType operator * (const SpatialVectorType &vec)
+ {
+ SpatialVectorType out;
+ transform(vec, out);
+ return out;
+ }
+};
+
+template<typename SpatialVectorType>
+void symmetricSpatialOuterProduct(const SpatialVectorType &a, const SpatialVectorType &b, btSymmetricSpatialDyad &out)
+{
+ //output op maybe?
+
+ out.m_topLeftMat = outerProduct(a.m_topVec, b.m_bottomVec);
+ out.m_topRightMat = outerProduct(a.m_topVec, b.m_topVec);
+ out.m_topLeftMat = outerProduct(a.m_bottomVec, b.m_bottomVec);
+ //maybe simple a*spatTranspose(a) would be nicer?
+}
+
+template<typename SpatialVectorType>
+btSymmetricSpatialDyad symmetricSpatialOuterProduct(const SpatialVectorType &a, const SpatialVectorType &b)
+{
+ btSymmetricSpatialDyad out;
+
+ out.m_topLeftMat = outerProduct(a.m_topVec, b.m_bottomVec);
+ out.m_topRightMat = outerProduct(a.m_topVec, b.m_topVec);
+ out.m_bottomLeftMat = outerProduct(a.m_bottomVec, b.m_bottomVec);
+
+ return out;
+ //maybe simple a*spatTranspose(a) would be nicer?
+}
+
+#endif //BT_SPATIAL_ALGEBRA_H
+
diff --git a/extern/bullet2/src/LinearMath/btTransform.h b/extern/bullet2/src/LinearMath/btTransform.h
index 907627379bf..d4f939a5d99 100644
--- a/extern/bullet2/src/LinearMath/btTransform.h
+++ b/extern/bullet2/src/LinearMath/btTransform.h
@@ -127,7 +127,7 @@ public:
/**@brief Set from an array
- * @param m A pointer to a 15 element array (12 rotation(row major padded on the right by 1), and 3 translation */
+ * @param m A pointer to a 16 element array (12 rotation(row major padded on the right by 1), and 3 translation */
void setFromOpenGLMatrix(const btScalar *m)
{
m_basis.setFromOpenGLSubMatrix(m);
@@ -135,7 +135,7 @@ public:
}
/**@brief Fill an array representation
- * @param m A pointer to a 15 element array (12 rotation(row major padded on the right by 1), and 3 translation */
+ * @param m A pointer to a 16 element array (12 rotation(row major padded on the right by 1), and 3 translation */
void getOpenGLMatrix(btScalar *m) const
{
m_basis.getOpenGLSubMatrix(m);
diff --git a/extern/bullet2/src/LinearMath/btVector3.cpp b/extern/bullet2/src/LinearMath/btVector3.cpp
index 2ba7029c9be..dbcf2b6ab57 100644
--- a/extern/bullet2/src/LinearMath/btVector3.cpp
+++ b/extern/bullet2/src/LinearMath/btVector3.cpp
@@ -63,7 +63,7 @@ long _maxdot_large( const float *vv, const float *vec, unsigned long count, floa
float4 stack_array[ STACK_ARRAY_COUNT ];
#if DEBUG
- memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) );
+ //memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) );
#endif
size_t index;
@@ -448,7 +448,7 @@ long _mindot_large( const float *vv, const float *vec, unsigned long count, floa
float4 stack_array[ STACK_ARRAY_COUNT ];
#if DEBUG
- memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) );
+ //memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) );
#endif
size_t index;
diff --git a/extern/bullet2/src/LinearMath/btVector3.h b/extern/bullet2/src/LinearMath/btVector3.h
index 112b70dd66b..839b19c1449 100644
--- a/extern/bullet2/src/LinearMath/btVector3.h
+++ b/extern/bullet2/src/LinearMath/btVector3.h
@@ -501,10 +501,10 @@ public:
__m128 tmp3 = _mm_add_ps(r0,r1);
mVec128 = tmp3;
#elif defined(BT_USE_NEON)
- mVec128 = vsubq_f32(v1.mVec128, v0.mVec128);
- mVec128 = vmulq_n_f32(mVec128, rt);
- mVec128 = vaddq_f32(mVec128, v0.mVec128);
-#else
+ float32x4_t vl = vsubq_f32(v1.mVec128, v0.mVec128);
+ vl = vmulq_n_f32(vl, rt);
+ mVec128 = vaddq_f32(vl, v0.mVec128);
+#else
btScalar s = btScalar(1.0) - rt;
m_floats[0] = s * v0.m_floats[0] + rt * v1.m_floats[0];
m_floats[1] = s * v0.m_floats[1] + rt * v1.m_floats[1];
diff --git a/extern/bullet2/src/SConscript b/extern/bullet2/src/SConscript
deleted file mode 100644
index 20a87d5d12c..00000000000
--- a/extern/bullet2/src/SConscript
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/python
-import sys
-import os
-
-Import('env')
-
-defs = ''
-cflags = []
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- defs += ' WIN32 NDEBUG _WINDOWS'
- #cflags += ['/MT', '/W3', '/GX', '/O2', '/Op']
- cflags += ['/MT', '/W3', '/GX', '/Og', '/Ot', '/Ob1', '/Op', '/G6', '/O3', '/EHcs']
-elif env['OURPLATFORM'] in ('win32-mingw', 'linuxcross', 'win64-mingw'):
- defs += ' NDEBUG'
- cflags += ['-O2']
-elif env['OURPLATFORM'] in ('linux', 'freebsd4', 'freebsd5'):
- defs += ' NDEBUG'
- cflags += ['-O2']
-elif sys.platform=='darwin':
- defs += ' NDEBUG'
- cflags += ['-O3','-fPIC']
-
-bullet2_src = env.Glob("LinearMath/*.cpp")
-bullet2_src += env.Glob("BulletCollision/BroadphaseCollision/*.cpp")
-bullet2_src += env.Glob("BulletCollision/CollisionDispatch/*.cpp")
-bullet2_src += env.Glob("BulletCollision/Gimpact/*.cpp")
-bullet2_src += env.Glob("BulletCollision/CollisionShapes/*.cpp")
-bullet2_src += env.Glob("BulletCollision/NarrowPhaseCollision/*.cpp")
-bullet2_src += env.Glob("BulletDynamics/Vehicle/*.cpp")
-bullet2_src += env.Glob("BulletDynamics/ConstraintSolver/*.cpp")
-bullet2_src += env.Glob("BulletDynamics/Dynamics/*.cpp")
-bullet2_src += env.Glob("BulletDynamics/Character/*.cpp")
-bullet2_src += env.Glob("BulletDynamics/Featherstone/*.cpp")
-bullet2_src += env.Glob("BulletDynamics/MLCPSolvers/*.cpp")
-bullet2_src += env.Glob("BulletSoftBody/*.cpp")
-
-incs = '. BulletCollision BulletDynamics LinearMath BulletSoftBody'
-
-env.BlenderLib ( libname = 'extern_bullet2', sources=bullet2_src, includes=Split(incs), defines=Split(defs), libtype=['extern','player'], priority=[20,137], compileflags=cflags )
diff --git a/extern/carve/CMakeLists.txt b/extern/carve/CMakeLists.txt
index 643bd423546..bb81332917e 100644
--- a/extern/carve/CMakeLists.txt
+++ b/extern/carve/CMakeLists.txt
@@ -37,12 +37,10 @@ set(INC_SYS
set(SRC
carve-capi.cc
carve-util.cc
- lib/aabb.cpp
lib/carve.cpp
lib/convex_hull.cpp
lib/csg_collector.cpp
lib/csg.cpp
- lib/edge.cpp
lib/face.cpp
lib/geom2d.cpp
lib/geom3d.cpp
diff --git a/extern/carve/SConscript b/extern/carve/SConscript
deleted file mode 100644
index e08e75e6640..00000000000
--- a/extern/carve/SConscript
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/python
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-Import ('env')
-
-sources = env.Glob('lib/*.cpp')
-sources += env.Glob('*.cc')
-
-defs = []
-incs = ['include']
-
-if env['WITH_BF_BOOST']:
- if env['OURPLATFORM'] not in ('win32-vc', 'win64-vc'):
- # Boost is setting as preferred collections library in the Carve code when using MSVC compiler
- if env['OURPLATFORM'] not in ('win32-mingw', 'win64-mingw'):
- defs.append('HAVE_BOOST_UNORDERED_COLLECTIONS')
-
- defs.append('CARVE_SYSTEM_BOOST')
- defs.append('HAVE_BOOST_LIBRARY')
- incs.append(env['BF_BOOST_INC'])
-
-env.BlenderLib ('extern_carve', Split(sources), incs, defs, libtype=['extern'], priority=[40] )
diff --git a/extern/carve/bundle.sh b/extern/carve/bundle.sh
index dec902e30c0..00de08ea93c 100755
--- a/extern/carve/bundle.sh
+++ b/extern/carve/bundle.sh
@@ -103,29 +103,3 @@ endif()
blender_add_lib(extern_carve "\${SRC}" "\${INC}" "\${INC_SYS}")
EOF
-
-cat > SConscript << EOF
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-Import ('env')
-
-sources = env.Glob('lib/*.cpp')
-sources += env.Glob('*.cc')
-
-defs = []
-incs = ['include']
-
-if env['WITH_BF_BOOST']:
- if env['OURPLATFORM'] not in ('win32-vc', 'win64-vc'):
- # Boost is setting as preferred collections library in the Carve code when using MSVC compiler
- if env['OURPLATFORM'] not in ('win32-mingw', 'win64-mingw'):
- defs.append('HAVE_BOOST_UNORDERED_COLLECTIONS')
-
- defs.append('CARVE_SYSTEM_BOOST')
- defs.append('HAVE_BOOST_LIBRARY')
- incs.append(env['BF_BOOST_INC'])
-
-env.BlenderLib ('extern_carve', Split(sources), incs, defs, libtype=['extern'], priority=[40] )
-EOF
diff --git a/extern/carve/files.txt b/extern/carve/files.txt
index 5c02a04dfe2..9598d07f7e8 100644
--- a/extern/carve/files.txt
+++ b/extern/carve/files.txt
@@ -1,108 +1,107 @@
-include/carve/vertex_impl.hpp
-include/carve/aabb_impl.hpp
+include/carve/edge_impl.hpp
+include/carve/tag.hpp
+include/carve/colour.hpp
+include/carve/math_constants.hpp
include/carve/csg.hpp
-include/carve/triangle_intersection.hpp
-include/carve/pointset_iter.hpp
-include/carve/debug_hooks.hpp
-include/carve/mesh.hpp
-include/carve/triangulator_impl.hpp
-include/carve/edge_decl.hpp
-include/carve/collection/unordered.hpp
-include/carve/collection/unordered/tr1_impl.hpp
-include/carve/collection/unordered/fallback_impl.hpp
-include/carve/collection/unordered/std_impl.hpp
-include/carve/collection/unordered/vcpp_impl.hpp
-include/carve/collection/unordered/libstdcpp_impl.hpp
-include/carve/collection/unordered/boost_impl.hpp
-include/carve/convex_hull.hpp
+include/carve/heap.hpp
+include/carve/vector.hpp
+include/carve/djset.hpp
+include/carve/mesh_impl.hpp
+include/carve/polyline_iter.hpp
+include/carve/input.hpp
+include/carve/geom2d.hpp
+include/carve/aabb_impl.hpp
include/carve/geom.hpp
+include/carve/triangulator.hpp
+include/carve/pointset_iter.hpp
+include/carve/spacetree.hpp
+include/carve/vertex_impl.hpp
+include/carve/vcpp_config.h
+include/carve/octree_decl.hpp
+include/carve/rescale.hpp
include/carve/collection_types.hpp
+include/carve/faceloop.hpp
+include/carve/polyhedron_base.hpp
+include/carve/vertex_decl.hpp
include/carve/cbrt.h
-include/carve/util.hpp
-include/carve/iobj.hpp
-include/carve/polyline_decl.hpp
-include/carve/polyline_impl.hpp
-include/carve/win32.h
-include/carve/edge_impl.hpp
-include/carve/carve.hpp
-include/carve/polyline.hpp
-include/carve/face_decl.hpp
include/carve/matrix.hpp
-include/carve/classification.hpp
-include/carve/geom_impl.hpp
-include/carve/faceloop.hpp
-include/carve/mesh_ops.hpp
include/carve/tree.hpp
-include/carve/geom2d.hpp
-include/carve/face_impl.hpp
-include/carve/polyhedron_decl.hpp
-include/carve/interpolator.hpp
-include/carve/poly_decl.hpp
-include/carve/mesh_impl.hpp
-include/carve/gnu_cxx.h
-include/carve/mesh_simplify.hpp
-include/carve/triangulator.hpp
-include/carve/pointset_impl.hpp
+include/carve/debug_hooks.hpp
include/carve/rtree.hpp
-include/carve/math_constants.hpp
-include/carve/vector.hpp
-include/carve/octree_impl.hpp
-include/carve/pointset.hpp
include/carve/math.hpp
-include/carve/intersection.hpp
-include/carve/colour.hpp
-include/carve/kd_node.hpp
-include/carve/input.hpp
+include/carve/convex_hull.hpp
+include/carve/polyline.hpp
include/carve/geom3d.hpp
-include/carve/exact.hpp
-include/carve/rescale.hpp
-include/carve/polyhedron_base.hpp
-include/carve/heap.hpp
-include/carve/spacetree.hpp
-include/carve/polyhedron_impl.hpp
-include/carve/vcpp_config.h
include/carve/aabb.hpp
-include/carve/polyline_iter.hpp
-include/carve/djset.hpp
-include/carve/vertex_decl.hpp
-include/carve/csg_triangulator.hpp
-include/carve/poly.hpp
-include/carve/timing.hpp
-include/carve/octree_decl.hpp
include/carve/pointset_decl.hpp
-include/carve/tag.hpp
+include/carve/intersection.hpp
+include/carve/face_impl.hpp
include/carve/collection.hpp
include/carve/poly_impl.hpp
-lib/intersection.cpp
+include/carve/exact.hpp
+include/carve/timing.hpp
+include/carve/poly.hpp
+include/carve/mesh.hpp
+include/carve/win32.h
+include/carve/mesh_simplify.hpp
+include/carve/classification.hpp
+include/carve/collection/unordered/fallback_impl.hpp
+include/carve/collection/unordered/std_impl.hpp
+include/carve/collection/unordered/vcpp_impl.hpp
+include/carve/collection/unordered/boost_impl.hpp
+include/carve/collection/unordered/libstdcpp_impl.hpp
+include/carve/collection/unordered/tr1_impl.hpp
+include/carve/collection/unordered.hpp
+include/carve/pointset.hpp
+include/carve/mesh_ops.hpp
+include/carve/triangle_intersection.hpp
+include/carve/octree_impl.hpp
+include/carve/pointset_impl.hpp
+include/carve/carve.hpp
+include/carve/kd_node.hpp
+include/carve/polyhedron_impl.hpp
+include/carve/interpolator.hpp
+include/carve/edge_decl.hpp
+include/carve/face_decl.hpp
+include/carve/geom_impl.hpp
+include/carve/util.hpp
+include/carve/random/random.h
+include/carve/gnu_cxx.h
+include/carve/polyline_decl.hpp
+include/carve/triangulator_impl.hpp
+include/carve/iobj.hpp
+include/carve/csg_triangulator.hpp
+include/carve/polyline_impl.hpp
+include/carve/poly_decl.hpp
+include/carve/polyhedron_decl.hpp
+lib/math.cpp
+lib/intersect_classify_edge.cpp
+lib/csg_detail.hpp
+lib/polyhedron.cpp
+lib/csg.cpp
lib/intersect.cpp
-lib/triangulator.cpp
-lib/intersect_debug.hpp
-lib/csg_collector.hpp
lib/csg_data.hpp
-lib/convex_hull.cpp
-lib/intersect_classify_common.hpp
-lib/intersect_common.hpp
-lib/polyhedron.cpp
-lib/polyline.cpp
-lib/pointset.cpp
+lib/intersection.cpp
+lib/timing.cpp
+lib/intersect_classify_common_impl.hpp
lib/geom2d.cpp
-lib/math.cpp
+lib/csg_collector.hpp
+lib/mesh.cpp
lib/intersect_half_classify_group.cpp
+lib/octree.cpp
+lib/csg_collector.cpp
+lib/intersect_debug.hpp
+lib/intersect_classify_common.hpp
+lib/geom3d.cpp
lib/intersect_face_division.cpp
+lib/face.cpp
+lib/triangulator.cpp
lib/tag.cpp
-lib/aabb.cpp
lib/intersect_classify_group.cpp
-lib/csg_detail.hpp
-lib/mesh.cpp
-lib/timing.cpp
-lib/geom3d.cpp
+lib/polyline.cpp
+lib/intersect_common.hpp
+lib/convex_hull.cpp
lib/intersect_group.cpp
lib/carve.cpp
-lib/intersect_classify_edge.cpp
-lib/csg.cpp
-lib/face.cpp
-lib/csg_collector.cpp
+lib/pointset.cpp
lib/intersect_debug.cpp
-lib/edge.cpp
-lib/intersect_classify_common_impl.hpp
-lib/octree.cpp
diff --git a/extern/carve/include/carve/mesh_simplify.hpp b/extern/carve/include/carve/mesh_simplify.hpp
index 40c90eb763d..9c7371b3df5 100644
--- a/extern/carve/include/carve/mesh_simplify.hpp
+++ b/extern/carve/include/carve/mesh_simplify.hpp
@@ -1341,9 +1341,9 @@ namespace carve {
carve::geom::vector<3> v_best = vert->v;
double d_best = 0.0;
- for (size_t axes = 0; axes < 8; ++axes) {
+ for (int axes = 0; axes < 8; ++axes) {
carve::geom::vector<3> v = vert->v;
- for (size_t N = 0; N < 3; ++N) {
+ for (int N = 0; N < 3; ++N) {
if (constraint & (1 << N)) continue;
if (axes & (1<<N)) {
v.v[N] = ceil(v.v[N] / grid) * grid;
@@ -1471,9 +1471,9 @@ namespace carve {
std::vector<heapval_t> heap;
point_enumerator_t(vector_t _origin, int _base, int _n_dp) : origin(_origin), rounding_fac(pow((double)_base, _n_dp)), last(-1.0, _origin), heap() {
- for (size_t i = 0; i < (1 << 3); ++i) {
+ for (int i = 0; i < (1 << 3); ++i) {
vector_t t = origin;
- for (size_t j = 0; j < 3; ++j) {
+ for (int j = 0; j < 3; ++j) {
if (i & (1U << j)) {
t[j] = ceil(t[j] * rounding_fac) / rounding_fac;
} else {
diff --git a/extern/carve/lib/aabb.cpp b/extern/carve/lib/aabb.cpp
deleted file mode 100644
index 41d4e0e32e0..00000000000
--- a/extern/carve/lib/aabb.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/aabb.hpp>
-#include <carve/geom3d.hpp>
-
-namespace carve {
- namespace geom3d {
- }
-}
-
diff --git a/extern/carve/lib/edge.cpp b/extern/carve/lib/edge.cpp
deleted file mode 100644
index 68f01b5599b..00000000000
--- a/extern/carve/lib/edge.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/poly.hpp>
-
diff --git a/extern/ceres/CMakeLists.txt b/extern/ceres/CMakeLists.txt
new file mode 100644
index 00000000000..2ad8c543088
--- /dev/null
+++ b/extern/ceres/CMakeLists.txt
@@ -0,0 +1,329 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2012, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# NOTE: This file is automatically generated by bundle.sh script
+# If you're doing changes in this file, please update template
+# in that script too
+
+set(INC
+ .
+ include
+ internal
+ config
+ ../gflags/src
+)
+
+set(INC_SYS
+ ${EIGEN3_INCLUDE_DIRS}
+)
+
+set(SRC
+ internal/ceres/array_utils.cc
+ internal/ceres/blas.cc
+ internal/ceres/block_evaluate_preparer.cc
+ internal/ceres/block_jacobian_writer.cc
+ internal/ceres/block_jacobi_preconditioner.cc
+ internal/ceres/block_random_access_dense_matrix.cc
+ internal/ceres/block_random_access_diagonal_matrix.cc
+ internal/ceres/block_random_access_matrix.cc
+ internal/ceres/block_random_access_sparse_matrix.cc
+ internal/ceres/block_sparse_matrix.cc
+ internal/ceres/block_structure.cc
+ internal/ceres/callbacks.cc
+ internal/ceres/c_api.cc
+ internal/ceres/cgnr_solver.cc
+ internal/ceres/compressed_col_sparse_matrix_utils.cc
+ internal/ceres/compressed_row_jacobian_writer.cc
+ internal/ceres/compressed_row_sparse_matrix.cc
+ internal/ceres/conditioned_cost_function.cc
+ internal/ceres/conjugate_gradients_solver.cc
+ internal/ceres/coordinate_descent_minimizer.cc
+ internal/ceres/corrector.cc
+ internal/ceres/covariance.cc
+ internal/ceres/covariance_impl.cc
+ internal/ceres/dense_normal_cholesky_solver.cc
+ internal/ceres/dense_qr_solver.cc
+ internal/ceres/dense_sparse_matrix.cc
+ internal/ceres/detect_structure.cc
+ internal/ceres/dogleg_strategy.cc
+ internal/ceres/dynamic_compressed_row_jacobian_writer.cc
+ internal/ceres/dynamic_compressed_row_sparse_matrix.cc
+ internal/ceres/evaluator.cc
+ internal/ceres/file.cc
+ internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
+ internal/ceres/generated/schur_eliminator_d_d_d.cc
+ internal/ceres/gradient_checking_cost_function.cc
+ internal/ceres/gradient_problem.cc
+ internal/ceres/gradient_problem_solver.cc
+ internal/ceres/implicit_schur_complement.cc
+ internal/ceres/iterative_schur_complement_solver.cc
+ internal/ceres/lapack.cc
+ internal/ceres/levenberg_marquardt_strategy.cc
+ internal/ceres/linear_least_squares_problems.cc
+ internal/ceres/linear_operator.cc
+ internal/ceres/linear_solver.cc
+ internal/ceres/line_search.cc
+ internal/ceres/line_search_direction.cc
+ internal/ceres/line_search_minimizer.cc
+ internal/ceres/line_search_preprocessor.cc
+ internal/ceres/local_parameterization.cc
+ internal/ceres/loss_function.cc
+ internal/ceres/low_rank_inverse_hessian.cc
+ internal/ceres/minimizer.cc
+ internal/ceres/normal_prior.cc
+ internal/ceres/parameter_block_ordering.cc
+ internal/ceres/partitioned_matrix_view.cc
+ internal/ceres/polynomial.cc
+ internal/ceres/preconditioner.cc
+ internal/ceres/preprocessor.cc
+ internal/ceres/problem.cc
+ internal/ceres/problem_impl.cc
+ internal/ceres/program.cc
+ internal/ceres/reorder_program.cc
+ internal/ceres/residual_block.cc
+ internal/ceres/residual_block_utils.cc
+ internal/ceres/schur_complement_solver.cc
+ internal/ceres/schur_eliminator.cc
+ internal/ceres/schur_jacobi_preconditioner.cc
+ internal/ceres/scratch_evaluate_preparer.cc
+ internal/ceres/solver.cc
+ internal/ceres/solver_utils.cc
+ internal/ceres/sparse_matrix.cc
+ internal/ceres/sparse_normal_cholesky_solver.cc
+ internal/ceres/split.cc
+ internal/ceres/stringprintf.cc
+ internal/ceres/triplet_sparse_matrix.cc
+ internal/ceres/trust_region_minimizer.cc
+ internal/ceres/trust_region_preprocessor.cc
+ internal/ceres/trust_region_strategy.cc
+ internal/ceres/types.cc
+ internal/ceres/wall_time.cc
+
+ include/ceres/autodiff_cost_function.h
+ include/ceres/autodiff_local_parameterization.h
+ include/ceres/c_api.h
+ include/ceres/ceres.h
+ include/ceres/conditioned_cost_function.h
+ include/ceres/cost_function.h
+ include/ceres/cost_function_to_functor.h
+ include/ceres/covariance.h
+ include/ceres/crs_matrix.h
+ include/ceres/dynamic_autodiff_cost_function.h
+ include/ceres/dynamic_cost_function_to_functor.h
+ include/ceres/dynamic_numeric_diff_cost_function.h
+ include/ceres/fpclassify.h
+ include/ceres/gradient_checker.h
+ include/ceres/gradient_problem.h
+ include/ceres/gradient_problem_solver.h
+ include/ceres/internal/autodiff.h
+ include/ceres/internal/disable_warnings.h
+ include/ceres/internal/eigen.h
+ include/ceres/internal/fixed_array.h
+ include/ceres/internal/macros.h
+ include/ceres/internal/manual_constructor.h
+ include/ceres/internal/numeric_diff.h
+ include/ceres/internal/port.h
+ include/ceres/internal/reenable_warnings.h
+ include/ceres/internal/scoped_ptr.h
+ include/ceres/internal/variadic_evaluate.h
+ include/ceres/iteration_callback.h
+ include/ceres/jet.h
+ include/ceres/local_parameterization.h
+ include/ceres/loss_function.h
+ include/ceres/normal_prior.h
+ include/ceres/numeric_diff_cost_function.h
+ include/ceres/numeric_diff_options.h
+ include/ceres/ordered_groups.h
+ include/ceres/problem.h
+ include/ceres/rotation.h
+ include/ceres/sized_cost_function.h
+ include/ceres/solver.h
+ include/ceres/types.h
+ include/ceres/version.h
+ internal/ceres/array_utils.h
+ internal/ceres/blas.h
+ internal/ceres/block_evaluate_preparer.h
+ internal/ceres/block_jacobian_writer.h
+ internal/ceres/block_jacobi_preconditioner.h
+ internal/ceres/block_random_access_dense_matrix.h
+ internal/ceres/block_random_access_diagonal_matrix.h
+ internal/ceres/block_random_access_matrix.h
+ internal/ceres/block_random_access_sparse_matrix.h
+ internal/ceres/block_sparse_matrix.h
+ internal/ceres/block_structure.h
+ internal/ceres/callbacks.h
+ internal/ceres/casts.h
+ internal/ceres/cgnr_linear_operator.h
+ internal/ceres/cgnr_solver.h
+ internal/ceres/collections_port.h
+ internal/ceres/compressed_col_sparse_matrix_utils.h
+ internal/ceres/compressed_row_jacobian_writer.h
+ internal/ceres/compressed_row_sparse_matrix.h
+ internal/ceres/conjugate_gradients_solver.h
+ internal/ceres/coordinate_descent_minimizer.h
+ internal/ceres/corrector.h
+ internal/ceres/covariance_impl.h
+ internal/ceres/cxsparse.h
+ internal/ceres/dense_jacobian_writer.h
+ internal/ceres/dense_normal_cholesky_solver.h
+ internal/ceres/dense_qr_solver.h
+ internal/ceres/dense_sparse_matrix.h
+ internal/ceres/detect_structure.h
+ internal/ceres/dogleg_strategy.h
+ internal/ceres/dynamic_compressed_row_finalizer.h
+ internal/ceres/dynamic_compressed_row_jacobian_writer.h
+ internal/ceres/dynamic_compressed_row_sparse_matrix.h
+ internal/ceres/evaluator.h
+ internal/ceres/execution_summary.h
+ internal/ceres/file.h
+ internal/ceres/gradient_checking_cost_function.h
+ internal/ceres/gradient_problem_evaluator.h
+ internal/ceres/graph_algorithms.h
+ internal/ceres/graph.h
+ internal/ceres/householder_vector.h
+ internal/ceres/implicit_schur_complement.h
+ internal/ceres/integral_types.h
+ internal/ceres/iterative_schur_complement_solver.h
+ internal/ceres/lapack.h
+ internal/ceres/levenberg_marquardt_strategy.h
+ internal/ceres/linear_least_squares_problems.h
+ internal/ceres/linear_operator.h
+ internal/ceres/linear_solver.h
+ internal/ceres/line_search_direction.h
+ internal/ceres/line_search.h
+ internal/ceres/line_search_minimizer.h
+ internal/ceres/line_search_preprocessor.h
+ internal/ceres/low_rank_inverse_hessian.h
+ internal/ceres/map_util.h
+ internal/ceres/minimizer.h
+ internal/ceres/mutex.h
+ internal/ceres/parameter_block.h
+ internal/ceres/parameter_block_ordering.h
+ internal/ceres/partitioned_matrix_view.h
+ internal/ceres/partitioned_matrix_view_impl.h
+ internal/ceres/polynomial.h
+ internal/ceres/preconditioner.h
+ internal/ceres/preprocessor.h
+ internal/ceres/problem_impl.h
+ internal/ceres/program_evaluator.h
+ internal/ceres/program.h
+ internal/ceres/random.h
+ internal/ceres/reorder_program.h
+ internal/ceres/residual_block.h
+ internal/ceres/residual_block_utils.h
+ internal/ceres/schur_complement_solver.h
+ internal/ceres/schur_eliminator.h
+ internal/ceres/schur_eliminator_impl.h
+ internal/ceres/schur_jacobi_preconditioner.h
+ internal/ceres/scratch_evaluate_preparer.h
+ internal/ceres/small_blas.h
+ internal/ceres/solver_utils.h
+ internal/ceres/sparse_matrix.h
+ internal/ceres/sparse_normal_cholesky_solver.h
+ internal/ceres/split.h
+ internal/ceres/stl_util.h
+ internal/ceres/stringprintf.h
+ internal/ceres/suitesparse.h
+ internal/ceres/triplet_sparse_matrix.h
+ internal/ceres/trust_region_minimizer.h
+ internal/ceres/trust_region_preprocessor.h
+ internal/ceres/trust_region_strategy.h
+ internal/ceres/visibility_based_preconditioner.h
+ internal/ceres/wall_time.h
+)
+
+if(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
+ list(APPEND SRC
+ internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
+ internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
+ internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
+ internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
+ internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
+ internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
+ internal/ceres/generated/schur_eliminator_2_2_2.cc
+ internal/ceres/generated/schur_eliminator_2_2_3.cc
+ internal/ceres/generated/schur_eliminator_2_2_4.cc
+ internal/ceres/generated/schur_eliminator_2_2_d.cc
+ internal/ceres/generated/schur_eliminator_2_3_3.cc
+ internal/ceres/generated/schur_eliminator_2_3_4.cc
+ internal/ceres/generated/schur_eliminator_2_3_6.cc
+ internal/ceres/generated/schur_eliminator_2_3_9.cc
+ internal/ceres/generated/schur_eliminator_2_3_d.cc
+ internal/ceres/generated/schur_eliminator_2_4_3.cc
+ internal/ceres/generated/schur_eliminator_2_4_4.cc
+ internal/ceres/generated/schur_eliminator_2_4_8.cc
+ internal/ceres/generated/schur_eliminator_2_4_9.cc
+ internal/ceres/generated/schur_eliminator_2_4_d.cc
+ internal/ceres/generated/schur_eliminator_2_d_d.cc
+ internal/ceres/generated/schur_eliminator_4_4_2.cc
+ internal/ceres/generated/schur_eliminator_4_4_3.cc
+ internal/ceres/generated/schur_eliminator_4_4_4.cc
+ internal/ceres/generated/schur_eliminator_4_4_d.cc
+ )
+else()
+ add_definitions(-DCERES_RESTRICT_SCHUR_SPECIALIZATION)
+endif()
+
+if(WIN32)
+ list(APPEND INC
+ ../glog/src/windows
+ )
+else()
+ list(APPEND INC
+ ../glog/src
+ )
+endif()
+
+add_definitions(${GFLAGS_DEFINES})
+add_definitions(${GLOG_DEFINES})
+add_definitions(${CERES_DEFINES})
+
+add_definitions(
+ -DCERES_HAVE_PTHREAD
+ -DCERES_NO_SUITESPARSE
+ -DCERES_NO_CXSPARSE
+ -DCERES_NO_LAPACK
+ -DCERES_HAVE_RWLOCK
+)
+
+if(WITH_OPENMP)
+ add_definitions(
+ -DCERES_USE_OPENMP
+ )
+endif()
+
+blender_add_lib(extern_ceres "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/ceres/ChangeLog b/extern/ceres/ChangeLog
new file mode 100644
index 00000000000..0e6c195174c
--- /dev/null
+++ b/extern/ceres/ChangeLog
@@ -0,0 +1,659 @@
+commit aef9c9563b08d5f39eee1576af133a84749d1b48
+Author: Alessandro Gentilini <agentilini@gmail.com>
+Date: Tue Oct 6 20:43:45 2015 +0200
+
+ Add test for Bessel functions.
+
+ Change-Id: Ief5881e8027643d7ef627e60a88fdbad17f3d884
+
+commit 49c86018e00f196c4aa9bd25daccb9919917efee
+Author: Alessandro Gentilini <agentilini@gmail.com>
+Date: Wed Sep 23 21:59:44 2015 +0200
+
+ Add Bessel functions in order to use them in residual code.
+
+ See "How can I use the Bessel function in the residual function?" at
+ https://groups.google.com/d/msg/ceres-solver/Vh1gpqac8v0/NIK1EiWJCAAJ
+
+ Change-Id: I3e80d9f9d1cadaf7177076e493ff46ace5233b76
+
+commit dfb201220c034fde00a242d0533bef3f73b2907d
+Author: Simon Rutishauser <simon.rutishauser@pix4d.com>
+Date: Tue Oct 13 07:33:58 2015 +0200
+
+ Make miniglog threadsafe on non-windows system by using
+ localtime_r() instead of localtime() for time formatting
+
+ Change-Id: Ib8006c685cd8ed4f374893bef56c4061ca2c9747
+
+commit 41455566ac633e55f222bce7c4d2cb4cc33d5c72
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Mon Sep 28 22:43:42 2015 +0100
+
+ Remove link-time optimisation (LTO).
+
+ - On GCC 4.9+ although GCC supports LTO, it requires use of the
+ non-default gcc-ar & gcc-ranlib. Whilst we can ensure Ceres is
+ compiled with these, doing so with GCC 4.9 causes multiple definition
+ linker errors of static ints inside Eigen when compiling the tests
+ and examples when they are not also built with LTO.
+ - On OS X (Xcode 6 & 7) after the latest update to gtest, if LTO
+ is used when compiling the tests (& examples), two tests fail
+ due to typeinfo::operator== (things are fine if only Ceres itself is
+ compiled with LTO).
+ - This patch disables LTO for all compilers. It should be revisited when
+ the performance is more stable across our supported compilers.
+
+ Change-Id: I17b52957faefbdeff0aa40846dc9b342db1b02e3
+
+commit 89c40005bfceadb4163bd16b7464b3c2ce740daf
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Sep 27 13:37:26 2015 +0100
+
+ Only use LTO when compiling Ceres itself, not tests or examples.
+
+ - If Ceres is built as a shared library, and LTO is enabled for Ceres
+ and the tests, then type_info::operator==() incorrectly returns false
+ in gtests' CheckedDowncastToActualType() in the following tests:
+ -- levenberg_marquardt_strategy_test.
+ -- gradient_checking_cost_function_test.
+ on at least Xcode 6 & 7 as reported here:
+ https://github.com/google/googletest/issues/595.
+ - This does not appear to be a gtest issue, but is perhaps an LLVM bug
+ or an RTTI shared library issue. Either way, disabling the use of
+ LTO when compiling the test application resolves the issue.
+ - Allow LTO to be enabled for GCC, if it is supported.
+ - Add CMake function to allow easy appending to target properties s/t
+ Ceres library-specific compile flags can be iteratively constructed.
+
+ Change-Id: I923e6aae4f7cefa098cf32b2f8fc19389e7918c9
+
+commit 0794f41cca440f7f65d9a44e671f66f6e498ef7c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sat Sep 26 14:10:15 2015 -0700
+
+ Documentation updates.
+
+ 1. Fix a typo in the Trust Region algorithm.
+ 2. Add ARL in the list of users.
+ 3. Update the version history.
+
+ Change-Id: Ic286e8ef1a71af07f3890b7592dd3aed9c5f87ce
+
+commit 90e32a8dc437dfb0e6747ce15a1f3193c13b7d5b
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Mon Sep 21 21:08:25 2015 +0100
+
+ Use old minimum iOS version flags on Xcode < 7.0.
+
+ - The newer style, which are more specific and match the SDK names
+ are not available on Xcode < 7.0.
+
+ Change-Id: I2f07a0365183d2781157cdb05fd49b30ae001ac5
+
+commit 26cd5326a1fb99ae02c667eab9942e1308046984
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Mon Sep 21 10:16:01 2015 +0100
+
+ Add gtest-specific flags when building/using as a shared library.
+
+ - Currently these flags are only used to define the relevant DLL export
+ prefix for Windows.
+
+ Change-Id: I0c05207b512cb4a985390aefc779b91febdabb38
+
+commit c4c79472112a49bc1340da0074af2d15b1c89749
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Sep 20 18:26:59 2015 +0100
+
+ Clean up iOS.cmake to use xcrun/xcodebuild & libtool.
+
+ - Substantial cleanup of iOS.cmake to use xcrun & xcodebuild to
+ determine the SDK & tool paths.
+ - Use libtool -static to link libraries instead of ar + ranlib, which
+ is not compatible with Xcode 7+, this change should be backwards
+ compatible to at least Xcode 6.
+ - Force locations of unordered_map & shared_ptr on iOS to work around
+ check_cxx_source_compiles() running in a forked CMake instance without
+ access to the variables (IOS_PLATFORM) defined by the user.
+ - Minor CMake style updates.
+
+ Change-Id: I5f83a60607db34d461ebe85f9dce861f53d98277
+
+commit 155765bbb358f1d19f072a4b54825faf1c059910
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Sep 16 06:56:08 2015 -0700
+
+ Import the latest version of gtest and gmock.
+
+ Change-Id: I4b686c44bba823cab1dae40efa99e31340d2b52a
+
+commit 0c4647b8f1496c97c6b9376d9c49ddc204aa08dd
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Wed Sep 16 20:01:11 2015 +0100
+
+ Remove FAQ about increasing inlining threshold for Clang.
+
+ - Changing the inlining threshold for Clang as described has a minimal
+ effect on user performance.
+ - The problem that originally prompted the belief that it did was
+ due to an erroneous CXX flag configuration (in user code).
+
+ Change-Id: I03017241c0f87b8dcefb8c984ec3b192afd97fc2
+
+commit f4b768b69afcf282568f9ab3a3f0eb8078607468
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Sep 14 13:53:24 2015 -0700
+
+ Lint changes from William Rucklidge
+
+ Change-Id: I0dac2549a8fa2bfd12f745a8d8a0db623b7ec1ac
+
+commit 5f2f05c726443e35767d677daba6d25dbc2d7ff8
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Sep 11 22:19:38 2015 -0700
+
+ Refactor system_test
+
+ 1. Move common test infrastructure into test_util.
+ 2. system_test now only contains powells function.
+ 3. Add bundle_adjustment_test.
+
+ Instead of a single function which computes everything,
+ there is now a test for each solver configuration which
+ uses the reference solution computed by the fixture.
+
+ Change-Id: I16a9a9a83a845a7aaf28762bcecf1a8ff5aee805
+
+commit 1936d47e213142b8bf29d3f548905116092b093d
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Tue Sep 8 23:27:42 2015 +0100
+
+ Revert increased inline threshold (iff Clang) to exported Ceres target.
+
+ - Increasing the inline threshold results in very variable performance
+ improvements, and could potentially confuse users if they are trying
+ to set the inline threshold themselves.
+ - As such, we no longer export our inline threshold configuration for
+ Clang, but instead document how to change it in the FAQs.
+
+ Change-Id: I88e2e0001e4586ba2718535845ed1e4b1a5b72bc
+
+commit a66d89dcda47cefda83758bfb9e7374bec4ce866
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sat Sep 5 16:50:20 2015 -0700
+
+ Get ready for 1.11.0RC1
+
+ Update version numbers.
+ Drop CERES_VERSION_ABI macro.
+
+ Change-Id: Ib3eadabb318afe206bb196a5221b195d26cbeaa0
+
+commit 1ac3dd223c179fbadaed568ac532af4139c75d84
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sat Sep 5 15:30:01 2015 -0700
+
+ Fix a bug in CompressedRowSparseMatrix::AppendRows
+
+ The test for CompressedRowSparseMatrix::AppendRows tries to add
+ a matrix of size zero, which results in an invalid pointer deferencing
+ even though that pointer is never written to.
+
+ Change-Id: I97dba37082bd5dad242ae1af0447a9178cd92027
+
+commit 67622b080c8d37b5e932120a53d4ce76b80543e5
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sat Sep 5 13:18:38 2015 -0700
+
+ Fix a pointer access bug in Ridders' algorithm.
+
+ A pointer to an Eigen matrix was being used as an array.
+
+ Change-Id: Ifaea14fa3416eda5953de49afb78dc5a6ea816eb
+
+commit 5742b7d0f14d2d170054623ccfee09ea214b8ed9
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Aug 26 09:24:33 2015 -0700
+
+ Improve performance of SPARSE_NORMAL_CHOLESKY + dynamic_sparsity
+
+ The outer product computation logic in SparseNormalCholeskySolver
+ does not work well with dynamic sparsity. The overhead of computing
+ the sparsity pattern of the normal equations is only amortized if
+ the sparsity is constant. If the sparsity can change from call to call
+ SparseNormalCholeskySolver will actually be more expensive.
+
+ For Eigen and for CXSparse we now explicitly compute the normal
+ equations using their respective matrix-matrix product routines and solve.
+ Change-Id: Ifbd8ed78987cdf71640e66ed69500442526a23d4
+
+commit d0b6cf657d6ef0dd739e958af9a5768f2eecfd35
+Author: Keir Mierle <mierle@gmail.com>
+Date: Fri Sep 4 18:43:41 2015 -0700
+
+ Fix incorrect detect structure test
+
+ Change-Id: I7062f3639147c40b57947790d3b18331a39a366b
+
+commit 0e8264cc47661651a11e2dd8570c210082963545
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sat Aug 22 16:23:05 2015 +0100
+
+ Add increased inline threshold (iff Clang) to exported Ceres target.
+
+ - When compiled with Clang, Ceres and all of the examples are compiled
+ with an increased inlining-threshold, as the default value can result
+ in poor Eigen performance.
+ - Previously, client code using Ceres would typically not use an
+ increased inlining-threshold (unless the user has specifically added
+ it themselves). However, increasing the inlining threshold can result
+ in significant performance improvements in auto-diffed CostFunctions.
+ - This patch adds the inlining-threshold flags to the interface flags
+ for the Ceres CMake target s/t any client code using Ceres (via
+ CMake), and compiled with Clang, will now be compiled with the same
+ increased inlining threshold as used by Ceres itself.
+
+ Change-Id: I31e8f1abfda140d22e85bb48aa57f028a68a415e
+
+commit a1b3fce9e0a4141b973f6b4dd9b08c4c13052d52
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Mon Aug 31 14:14:56 2015 +0100
+
+ Add optional export of Ceres build directory to new features list.
+
+ Change-Id: I6f1e42b41957ae9cc98fd9dcd1969ef64c4cd96f
+
+commit e46777d8df068866ef80902401a03e29348d11ae
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Mon Aug 31 12:41:54 2015 +0100
+
+ Credit reporters of buildsystem bugs in version history.
+
+ Change-Id: I16fe7973534cd556d97215e84268ae0b8ec4e11a
+
+commit 01548282cb620e5e3ac79a63a391cd0afd5433e4
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Aug 30 22:29:27 2015 -0700
+
+ Update the version history.
+
+ Change-Id: I29873bed31675e0108f1a44f53f7bc68976b7f98
+
+commit 2701429f770fce69ed0c77523fa43d7bc20ac6dc
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Aug 30 21:33:57 2015 -0700
+
+ Use Eigen::Dynamic instead of ceres::DYNAMIC in numeric_diff.h
+
+ Change-Id: Iccb0284a8fb4c2160748dfae24bcd595f1d4cb5c
+
+commit 4f049db7c2a3ee8cf9910c6eac96be6a28a5999c
+Author: Tal Ben-Nun <tbennun@gmail.com>
+Date: Wed May 13 15:43:51 2015 +0300
+
+ Adaptive numeric differentiation using Ridders' method.
+
+ This method numerically computes function derivatives in different
+ scales, extrapolating between intermediate results to conserve function
+ evaluations. Adaptive differentiation is essential to produce accurate
+ results for functions with noisy derivatives.
+
+ Full changelist:
+ -Created a new type of NumericDiffMethod (RIDDERS).
+ -Implemented EvaluateRiddersJacobianColumn in NumericDiff.
+ -Created unit tests with f(x) = x^2 + [random noise] and
+ f(x) = exp(x).
+
+ Change-Id: I2d6e924d7ff686650272f29a8c981351e6f72091
+
+commit 070bba4b43b4b7449628bf456a10452fd2b34d28
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Aug 25 13:37:33 2015 -0700
+
+ Lint fixes from William Rucklidge
+
+ Change-Id: I719e8852859c970091df842e59c44e02e2c65827
+
+commit 887a20ca7f02a1504e35f7cabbdfb2e0842a0b0b
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Wed Aug 12 21:41:43 2015 +0100
+
+ Build position independent code when compiling Ceres statically.
+
+ - Previously, when Ceres was built as a static library we did not
+ compile position independent code. This means that the resulting
+ static library could not be linked against shared libraries, but
+ could be used by executables.
+ - To enable the use of a static Ceres library by other shared libraries
+ as reported in [1], the static library must be generated from
+ position independent code (except on Windows, where PIC does not
+ apply).
+
+ [1] https://github.com/Itseez/opencv_contrib/pull/290#issuecomment-130389471
+
+ Change-Id: I99388f1784ece688f91b162d009578c5c97ddaf6
+
+commit 860bba588b981a5718f6b73e7e840e5b8757fe65
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Aug 25 09:43:21 2015 -0700
+
+ Fix a bug in DetectStructure
+
+ The logic for determing static/dynamic f-block size in
+ DetectStructure was broken in a corner case, where the very first
+ row block which was used to initialize the f_block_size contained
+ more than one f blocks of varying sizes. The way the if block
+ was structured, no iteration was performed on the remaining
+ f-blocks and the loop failed to detect that the f-block size
+ was actually changing.
+
+ If in the remaining row blocks, there were no row blocks
+ with varying f-block sizes, the function will erroneously
+ return a static f-block size.
+
+ Thanks to Johannes Schonberger for providing a reproduction for this
+ rather tricky corner case.
+
+ Change-Id: Ib442a041d8b7efd29f9653be6a11a69d0eccd1ec
+
+commit b0cbc0f0b0a22f01724b7b647a4a94db959cc4e4
+Author: Johannes Schönberger <hannesschoenberger@gmail.com>
+Date: Thu Aug 20 14:21:30 2015 -0400
+
+ Reduce memory footprint of SubsetParameterization
+
+ Change-Id: If113cb4696d5aef3e50eed01fba7a3d4143b7ec8
+
+commit ad2a99777786101411a971e59576ca533a297013
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sat Aug 22 11:18:45 2015 +0200
+
+ Fix for reoder program unit test when built without suitesparse
+
+ This commit fixes failure of reorder_program_test when Ceres is built without
+ any suitesparse.
+
+ Change-Id: Ia23ae8dfd20c482cb9cd1301f17edf9a34df3235
+
+commit 4bf3868beca9c17615f72ec03730cddb3676acaa
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Aug 9 15:24:45 2015 -0700
+
+ Fix a bug in the Schur eliminator
+
+ The schur eliminator treats rows with e blocks and row with
+ no e blocks separately. The template specialization logic only
+ applies to the rows with e blocks.
+
+ So, in cases where the rows with e-blocks have a fixed size f-block
+ but the rows without e-blocks have f-blocks of varying sizes,
+ DetectStructure will return a static f-block size, but we need to be
+ careful that we do not blindly use that static f-block size everywhere.
+
+ This patch fixes a bug where such care was not being taken, where
+ it was assumed that the static f-block size could be assumed for all
+ f-block sizes.
+
+ A new test is added, which triggers an exception in debug mode. In
+ release mode this error does not present itself, due to a peculiarity
+ of the way Eigen works.
+
+ Thanks to Werner Trobin for reporting this bug.
+
+ Change-Id: I8ae7aabf8eed8c3f9cf74b6c74d632ba44f82581
+
+commit 1635ce726078f00264b89d7fb6e76fd1c2796e59
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Aug 19 00:26:02 2015 -0700
+
+ Fix a bug in the reordering code.
+
+ When the user provides an ordering which starts at a non-zero group id,
+ or has gaps in the groups, then CAMD, the algorithm used to reorder
+ the program can crash or return garbage results.
+
+ The solution is to map the ordering into grouping constraints, and then
+ to re-number the groups to be contiguous using a call to
+ MapValuesToContiguousRange. This was already done for CAMD based
+ ordering for Schur type solvers, but was not done for SPARSE_NORMAL_CHOLESKY.
+
+ Thanks to Bernhard Zeisl for not only reporting the bug but also
+ providing a reproduction.
+
+ Change-Id: I5cfae222d701dfdb8e1bda7f0b4670a30417aa89
+
+commit 4c3f8987e7f0c51fd367cf6d43d7eb879e79589f
+Author: Simon Rutishauser <simon.rutishauser@pix4d.com>
+Date: Thu Aug 13 11:10:44 2015 +0200
+
+ Add missing CERES_EXPORT to ComposedLoss
+
+ Change-Id: Id7db388d41bf53e6e5704039040c9d2c6bf4c29c
+
+commit 1a740cc787b85b883a0703403a99fe49662acb79
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Aug 11 18:08:05 2015 -0700
+
+ Add the option to use numeric differentiation to nist and more_garbow_hillstrom
+
+ Change-Id: If0a5caef90b524dcf5e2567c5b681987f5459401
+
+commit ea667ede5c038d6bf3d1c9ec3dbdc5072d1beec6
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Aug 9 16:56:13 2015 +0100
+
+ Fix EIGENSPARSE option help s/t it displays in CMake ncurses GUI.
+
+ - Shorten description for EIGENSPARSE to a single line, as otherwise
+ it is not correctly displayed in the ncurses CMake GUI.
+ - Made explicit in description that this results in an LGPL licensed
+ version of Ceres (this is also made clear in the CMake log output if
+ EIGENSPARSE is enabled).
+
+ Change-Id: I11678a9cbc7a817133c22128da01055a3cb8a26d
+
+commit a14ec27fb28ab2e8d7f1c9d88e41101dc6c0aab5
+Author: Richard Stebbing <richie.stebbing@gmail.com>
+Date: Fri Aug 7 08:42:03 2015 -0700
+
+ Fix SparseNormalCholeskySolver with dynamic sparsity.
+
+ The previous implementation incorrectly cached the outer product matrix
+ pattern even when `dynamic_sparsity = true`.
+
+ Change-Id: I1e58315a9b44f2f457d07c56b203ab2668bfb8a2
+
+commit 3dd7fced44ff00197fa9fcb1f2081d12be728062
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Aug 9 16:38:50 2015 +0100
+
+ Remove legacy dependency detection macros.
+
+ - Before the new CMake buildsystem in 1.8, Ceres used non-standard
+ HINTS variables for dependencies. For backwards compatibility CMake
+ macros were added to translate these legacy variables into the new
+ (standard) variables.
+ - As it has now been multiple releases since the legacy variables
+ were used and they no longer appear in any of the documentation
+ support for them has now expired.
+
+ Change-Id: I2cc72927ed711142ba7943df334ee008181f86a2
+
+commit 8b32e258ccce1eed2a50bb002add16cad13aff1e
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Aug 9 15:42:39 2015 +0100
+
+ Fix failed if() condition expansion if gflags is not found.
+
+ - If a CMake-ified version of gflags is not detected, then
+ gflags_LIBRARIES is not set and the TARGET condition within a
+ multiconditional if() statement prevents configuration.
+
+ Change-Id: Ia92e97523d7a1478ab36539726b9540d7cfee5d0
+
+commit cc8d47aabb9d63ba4588ba7295058a6191c2df83
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Aug 9 15:18:42 2015 +0100
+
+ Update all CMake to lowercase function name style.
+
+ - Updated to new CMake style where function names are all lowercase,
+ this will be backwards compatible as CMake function names are
+ case insensitive.
+ - Updated using Emacs' M-x unscreamify-cmake-buffer.
+
+ Change-Id: If7219816f560270e59212813aeb021353a64a0e2
+
+commit 1f106904c1f47460c35ac03258d6506bb2d60838
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Aug 9 14:55:02 2015 +0100
+
+ Update minimum iOS version to 7.0 for shared_ptr/unordered_map.
+
+ - In order to correctly detect shared_ptr (& unordered_map)
+ the iOS version must be >= 7.0 (Xcode 5.0+). This only affects the
+ SIMULATOR(64) platform builds, as the OS (device) build uses the
+ latest SDK which is now likely 8.0+.
+
+ Change-Id: Iefec8f03408b8cdc7a495f442ebba081f800adb0
+
+commit 16ecd40523a408e7705c9fdb0e159cef2007b8ab
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sat Aug 8 17:32:31 2015 +0100
+
+ Fix bug in gflags' <= 2.1.2 exported CMake configuration.
+
+ - gflags <= 2.1.2 has a bug in its exported gflags-config.cmake:
+ https://github.com/gflags/gflags/issues/110 whereby it sets
+ gflags_LIBRARIES to a non-existent 'gflags' target.
+ - This causes linker errors if gflags is installed in a non-standard
+ location (as otherwise CMake resolves gflags to -lgflags which
+ links if gflags is installed somewhere on the current path).
+ - We now check for this case, and search for the correct gflags imported
+ target and update gflags_LIBRARIES to reference it if found, otherwise
+ proceed on to the original manual search to try to find gflags.
+
+ Change-Id: Iceccc3ee53c7c2010e41cc45255f966e7b13d526
+
+commit 56be8de007dfd65ed5a31c795eb4a08ad765f411
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Thu Jun 25 21:31:00 2015 +0100
+
+ Add docs for new CXX11 option & mask option for Windows.
+
+ - The CXX11 option has no effect on Windows, as there, any new C++11
+ features are enabled by default, as such to avoid confusion we only
+ present the option for non-Windows.
+
+ Change-Id: I38925ae3bb8c16682d404468ba95c611a519b9b9
+
+commit cf863b6415ac4dbf3626e70adeac1ac0f3d87ee5
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Aug 6 14:52:18 2015 -0700
+
+ Remove the spec file needed for generating RPMs.
+
+ Now that ceres is part of RawHide, there is no need to carry
+ this spec file with the ceres distribution.
+
+ Change-Id: Icc400b9874ba05ba05b353e2658f1de94c72299e
+
+commit 560940fa277a469c1ab34f1aa303ff1af9c3cacf
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sat Jul 11 22:21:31 2015 -0700
+
+ A refactor of the cubic interpolation code
+
+ 1. Push the boundary handling logic into the underlying array
+ object. This has two very significant impacts:
+
+ a. The interpolation code becomes extremely simple to write
+ and to test.
+
+ b. The user has more flexibility in implementing how out of bounds
+ values are handled. We provide one default implementation.
+
+ Change-Id: Ic2f6cf9257ce7110c62e492688e5a6c8be1e7df2
+
+commit dfdf19e111c2b0e6daeb6007728ec2f784106d49
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Aug 5 15:20:57 2015 -0700
+
+ Lint cleanup from Jim Roseborough
+
+ Change-Id: Id6845c85644d40e635ed196ca74fc51a387aade4
+
+commit 7444f23ae245476a7ac8421cc2f88d6947fd3e5f
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Aug 3 12:22:44 2015 -0700
+
+ Fix a typo in small_blas.h
+
+ The reason this rather serious looking typo has not
+ caused any problems uptil now is because NUM_ROW_B is
+ computed but never actually used.
+
+ Thanks to Werner Trobin for pointing this out.
+
+ Change-Id: Id2b4d9326ec21baec8a85423e3270aefbafb611e
+
+commit 5a48b92123b30a437f031eb24b0deaadc8f60d26
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sat Jul 4 17:59:52 2015 +0100
+
+ Export Ceres build directory into local CMake package registry.
+
+ - Optionally use CMake's export() functionality to export the Ceres
+ build directory as a package into the local CMake package registry.
+ - This enables the detection & use of Ceres from CMake *without*
+ requiring that Ceres be installed.
+
+ Change-Id: Ib5a7588446f490e1b405878475b6b1dd13accd1f
+
+commit d9790e77894ea99d38137d359d6118315b2d1601
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Jul 12 19:39:47 2015 -0700
+
+ Add ProductParameterization
+
+ Often a parameter block is the Cartesian product of a number of
+ manifolds. For example, a rigid transformation SE(3) = SO(3) x R^3
+ In such cases, where you have the local parameterization
+ of the individual manifolds available,
+ ProductParameterization can be used to construct a local
+ parameterization of the cartesian product.
+
+ Change-Id: I4b5bcbd2407a38739c7725b129789db5c3d65a20
+
+commit 7b4fb69dad49eaefb5d2d47ef0d76f48ad7fef73
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Sun Jun 28 21:43:46 2015 +0100
+
+ Cleanup FindGflags & use installed gflags CMake config if present.
+
+ - Split out gflags namespace detection methods:
+ check_cxx_source_compiles() & regex, into separate functions.
+ - Use installed/exported gflags CMake configuration (present for
+ versions >= 2.1) if available, unless user expresses a preference not
+ to, or specifies search directories, in which case fall back to manual
+ search for components.
+ -- Prefer installed gflags CMake configurations over exported gflags
+ build directories on all OSs.
+ - Remove custom version of check_cxx_source_compiles() that attempted
+ to force the build type of the test project. This only worked for
+ NMake on Windows, not MSVC as msbuild ignored our attempts to force
+ the build type. Now we always use the regex method on Windows if
+ we cannot find an installed gflags CMake configuration which works
+ even on MSVC by bypassing msbuild.
+ - Add default search paths for gflags on Windows.
+
+ Change-Id: I083b267d97a7a5838a1314f3d41a61ae48d5a2d7
+
+commit b3063c047906d4a44503dc0187fdcbbfcdda5f38
+Author: Alex Stewart <alexs.mac@gmail.com>
+Date: Wed Jul 15 20:56:56 2015 +0100
+
+ Add default glog install location on Windows to search paths.
+
+ Change-Id: I083d368be48986e6780c11460f5a07b2f3b6c900
diff --git a/extern/libmv/third_party/ceres/LICENSE b/extern/ceres/LICENSE
index 2e3ead5ed45..2e3ead5ed45 100644
--- a/extern/libmv/third_party/ceres/LICENSE
+++ b/extern/ceres/LICENSE
diff --git a/extern/libmv/third_party/ceres/README b/extern/ceres/README
index 8dd8ccf91a1..8dd8ccf91a1 100644
--- a/extern/libmv/third_party/ceres/README
+++ b/extern/ceres/README
diff --git a/extern/ceres/bundle.sh b/extern/ceres/bundle.sh
new file mode 100755
index 00000000000..0eaf00f3989
--- /dev/null
+++ b/extern/ceres/bundle.sh
@@ -0,0 +1,198 @@
+#!/bin/sh
+
+if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then
+ echo Proceeding as requested by command line ...
+else
+ echo "*** Please run again with --i-really-know-what-im-doing ..."
+ exit 1
+fi
+
+repo="https://ceres-solver.googlesource.com/ceres-solver"
+branch="master"
+#tag="1.4.0"
+tag=""
+tmp=`mktemp -d`
+checkout="$tmp/ceres"
+
+GIT="git --git-dir $tmp/ceres/.git --work-tree $checkout"
+
+git clone $repo $checkout
+
+if [ $branch != "master" ]; then
+ $GIT checkout -t remotes/origin/$branch
+else
+ if [ "x$tag" != "x" ]; then
+ $GIT checkout $tag
+ fi
+fi
+
+$GIT log -n 50 > ChangeLog
+
+for p in `cat ./patches/series`; do
+ echo "Applying patch $p..."
+ cat ./patches/$p | patch -d $tmp/ceres -p1
+done
+
+find include -type f -not -iwholename '*.svn*' -exec rm -rf {} \;
+find internal -type f -not -iwholename '*.svn*' -exec rm -rf {} \;
+
+cat "files.txt" | while read f; do
+ mkdir -p `dirname $f`
+ cp $tmp/ceres/$f $f
+done
+
+rm -rf $tmp
+
+sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/' | \
+ grep -v -E 'schur_eliminator_[0-9]_[0-9d]_[0-9d].cc' | \
+ grep -v -E 'partitioned_matrix_view_[0-9]_[0-9d]_[0-9d].cc' | sort -d`
+generated_sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t\t/' | \
+ grep -E 'schur_eliminator_[0-9]_[0-9d]_[0-9d].cc|partitioned_matrix_view_[0-9]_[0-9d]_[0-9d].cc' | sort -d`
+headers=`find ./include ./internal -type f -iname '*.h' | sed -r 's/^\.\//\t/' | sort -d`
+
+src_dir=`find ./internal -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/' | sort -d | uniq`
+src=""
+for x in $src_dir $src_third_dir; do
+ t=""
+
+ if test `echo "$x" | grep -c glog ` -eq 1; then
+ continue;
+ fi
+
+ if test `echo "$x" | grep -c generated` -eq 1; then
+ continue;
+ fi
+
+ if stat $x/*.cpp > /dev/null 2>&1; then
+ t="src += env.Glob('`echo $x'/*.cpp'`')"
+ fi
+
+ if stat $x/*.c > /dev/null 2>&1; then
+ if [ -z "$t" ]; then
+ t="src += env.Glob('`echo $x'/*.c'`')"
+ else
+ t="$t + env.Glob('`echo $x'/*.c'`')"
+ fi
+ fi
+
+ if stat $x/*.cc > /dev/null 2>&1; then
+ if [ -z "$t" ]; then
+ t="src += env.Glob('`echo $x'/*.cc'`')"
+ else
+ t="$t + env.Glob('`echo $x'/*.cc'`')"
+ fi
+ fi
+
+ if [ -z "$src" ]; then
+ src=$t
+ else
+ src=`echo "$src\n$t"`
+ fi
+done
+
+cat > CMakeLists.txt << EOF
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2012, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# NOTE: This file is automatically generated by bundle.sh script
+# If you're doing changes in this file, please update template
+# in that script too
+
+set(INC
+ .
+ include
+ internal
+ config
+ ../gflags/src
+)
+
+set(INC_SYS
+ \${EIGEN3_INCLUDE_DIRS}
+)
+
+set(SRC
+${sources}
+
+${headers}
+)
+
+if(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
+ list(APPEND SRC
+${generated_sources}
+ )
+else()
+ add_definitions(-DCERES_RESTRICT_SCHUR_SPECIALIZATION)
+endif()
+
+if(WIN32)
+ list(APPEND INC
+ ../glog/src/windows
+ )
+else()
+ list(APPEND INC
+ ../glog/src
+ )
+endif()
+
+add_definitions(\${GFLAGS_DEFINES})
+add_definitions(\${GLOG_DEFINES})
+add_definitions(\${CERES_DEFINES})
+
+add_definitions(
+ -DCERES_HAVE_PTHREAD
+ -DCERES_NO_SUITESPARSE
+ -DCERES_NO_CXSPARSE
+ -DCERES_NO_LAPACK
+ -DCERES_HAVE_RWLOCK
+)
+
+if(WITH_OPENMP)
+ add_definitions(
+ -DCERES_USE_OPENMP
+ )
+endif()
+
+TEST_UNORDERED_MAP_SUPPORT()
+if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
+ add_definitions(-DCERES_STD_UNORDERED_MAP)
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DCERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ else()
+ add_definitions(-DCERES_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DCERES_TR1_UNORDERED_MAP)
+ else()
+ add_definitions(-DCERES_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+endif()
+
+blender_add_lib(extern_ceres "\${SRC}" "\${INC}" "\${INC_SYS}")
+EOF
diff --git a/extern/ceres/config/ceres/internal/config.h b/extern/ceres/config/ceres/internal/config.h
new file mode 100644
index 00000000000..1cf034ded5f
--- /dev/null
+++ b/extern/ceres/config/ceres/internal/config.h
@@ -0,0 +1,48 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: alexs.mac@gmail.com (Alex Stewart)
+
+// Default (empty) configuration options for Ceres.
+//
+// IMPORTANT: Most users of Ceres will not use this file, when
+// compiling Ceres with CMake, CMake will configure a new
+// config.h with the currently selected Ceres compile
+// options in <BUILD_DIR>/config, which will be added to
+// the include path for compilation, and installed with the
+// public Ceres headers. However, for some users of Ceres
+// who compile without CMake (Android), this file ensures
+// that Ceres will compile, with the user either specifying
+// manually the Ceres compile options, or passing them
+// directly through the compiler.
+
+#ifndef CERES_PUBLIC_INTERNAL_CONFIG_H_
+#define CERES_PUBLIC_INTERNAL_CONFIG_H_
+
+
+#endif // CERES_PUBLIC_INTERNAL_CONFIG_H_
diff --git a/extern/ceres/files.txt b/extern/ceres/files.txt
new file mode 100644
index 00000000000..f49f1fb0ded
--- /dev/null
+++ b/extern/ceres/files.txt
@@ -0,0 +1,252 @@
+include/ceres/autodiff_cost_function.h
+include/ceres/autodiff_local_parameterization.h
+include/ceres/c_api.h
+include/ceres/ceres.h
+include/ceres/conditioned_cost_function.h
+include/ceres/cost_function.h
+include/ceres/cost_function_to_functor.h
+include/ceres/covariance.h
+include/ceres/crs_matrix.h
+include/ceres/dynamic_autodiff_cost_function.h
+include/ceres/dynamic_cost_function_to_functor.h
+include/ceres/dynamic_numeric_diff_cost_function.h
+include/ceres/fpclassify.h
+include/ceres/gradient_checker.h
+include/ceres/gradient_problem.h
+include/ceres/gradient_problem_solver.h
+include/ceres/internal/autodiff.h
+include/ceres/internal/disable_warnings.h
+include/ceres/internal/eigen.h
+include/ceres/internal/fixed_array.h
+include/ceres/internal/macros.h
+include/ceres/internal/manual_constructor.h
+include/ceres/internal/numeric_diff.h
+include/ceres/internal/port.h
+include/ceres/internal/reenable_warnings.h
+include/ceres/internal/scoped_ptr.h
+include/ceres/internal/variadic_evaluate.h
+include/ceres/iteration_callback.h
+include/ceres/jet.h
+include/ceres/local_parameterization.h
+include/ceres/loss_function.h
+include/ceres/normal_prior.h
+include/ceres/numeric_diff_cost_function.h
+include/ceres/numeric_diff_options.h
+include/ceres/ordered_groups.h
+include/ceres/problem.h
+include/ceres/rotation.h
+include/ceres/sized_cost_function.h
+include/ceres/solver.h
+include/ceres/types.h
+include/ceres/version.h
+internal/ceres/array_utils.cc
+internal/ceres/array_utils.h
+internal/ceres/blas.cc
+internal/ceres/blas.h
+internal/ceres/block_evaluate_preparer.cc
+internal/ceres/block_evaluate_preparer.h
+internal/ceres/block_jacobian_writer.cc
+internal/ceres/block_jacobian_writer.h
+internal/ceres/block_jacobi_preconditioner.cc
+internal/ceres/block_jacobi_preconditioner.h
+internal/ceres/block_random_access_dense_matrix.cc
+internal/ceres/block_random_access_dense_matrix.h
+internal/ceres/block_random_access_diagonal_matrix.cc
+internal/ceres/block_random_access_diagonal_matrix.h
+internal/ceres/block_random_access_matrix.cc
+internal/ceres/block_random_access_matrix.h
+internal/ceres/block_random_access_sparse_matrix.cc
+internal/ceres/block_random_access_sparse_matrix.h
+internal/ceres/block_sparse_matrix.cc
+internal/ceres/block_sparse_matrix.h
+internal/ceres/block_structure.cc
+internal/ceres/block_structure.h
+internal/ceres/callbacks.cc
+internal/ceres/callbacks.h
+internal/ceres/c_api.cc
+internal/ceres/casts.h
+internal/ceres/cgnr_linear_operator.h
+internal/ceres/cgnr_solver.cc
+internal/ceres/cgnr_solver.h
+internal/ceres/collections_port.h
+internal/ceres/compressed_col_sparse_matrix_utils.cc
+internal/ceres/compressed_col_sparse_matrix_utils.h
+internal/ceres/compressed_row_jacobian_writer.cc
+internal/ceres/compressed_row_jacobian_writer.h
+internal/ceres/compressed_row_sparse_matrix.cc
+internal/ceres/compressed_row_sparse_matrix.h
+internal/ceres/conditioned_cost_function.cc
+internal/ceres/conjugate_gradients_solver.cc
+internal/ceres/conjugate_gradients_solver.h
+internal/ceres/coordinate_descent_minimizer.cc
+internal/ceres/coordinate_descent_minimizer.h
+internal/ceres/corrector.cc
+internal/ceres/corrector.h
+internal/ceres/covariance.cc
+internal/ceres/covariance_impl.cc
+internal/ceres/covariance_impl.h
+internal/ceres/cxsparse.h
+internal/ceres/dense_jacobian_writer.h
+internal/ceres/dense_normal_cholesky_solver.cc
+internal/ceres/dense_normal_cholesky_solver.h
+internal/ceres/dense_qr_solver.cc
+internal/ceres/dense_qr_solver.h
+internal/ceres/dense_sparse_matrix.cc
+internal/ceres/dense_sparse_matrix.h
+internal/ceres/detect_structure.cc
+internal/ceres/detect_structure.h
+internal/ceres/dogleg_strategy.cc
+internal/ceres/dogleg_strategy.h
+internal/ceres/dynamic_compressed_row_finalizer.h
+internal/ceres/dynamic_compressed_row_jacobian_writer.cc
+internal/ceres/dynamic_compressed_row_jacobian_writer.h
+internal/ceres/dynamic_compressed_row_sparse_matrix.cc
+internal/ceres/dynamic_compressed_row_sparse_matrix.h
+internal/ceres/evaluator.cc
+internal/ceres/evaluator.h
+internal/ceres/execution_summary.h
+internal/ceres/file.cc
+internal/ceres/file.h
+internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
+internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
+internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
+internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
+internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
+internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
+internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
+internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
+internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
+internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
+internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
+internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
+internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
+internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
+internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
+internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
+internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
+internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
+internal/ceres/generated/schur_eliminator_2_2_2.cc
+internal/ceres/generated/schur_eliminator_2_2_3.cc
+internal/ceres/generated/schur_eliminator_2_2_4.cc
+internal/ceres/generated/schur_eliminator_2_2_d.cc
+internal/ceres/generated/schur_eliminator_2_3_3.cc
+internal/ceres/generated/schur_eliminator_2_3_4.cc
+internal/ceres/generated/schur_eliminator_2_3_6.cc
+internal/ceres/generated/schur_eliminator_2_3_9.cc
+internal/ceres/generated/schur_eliminator_2_3_d.cc
+internal/ceres/generated/schur_eliminator_2_4_3.cc
+internal/ceres/generated/schur_eliminator_2_4_4.cc
+internal/ceres/generated/schur_eliminator_2_4_8.cc
+internal/ceres/generated/schur_eliminator_2_4_9.cc
+internal/ceres/generated/schur_eliminator_2_4_d.cc
+internal/ceres/generated/schur_eliminator_2_d_d.cc
+internal/ceres/generated/schur_eliminator_4_4_2.cc
+internal/ceres/generated/schur_eliminator_4_4_3.cc
+internal/ceres/generated/schur_eliminator_4_4_4.cc
+internal/ceres/generated/schur_eliminator_4_4_d.cc
+internal/ceres/generated/schur_eliminator_d_d_d.cc
+internal/ceres/generate_eliminator_specialization.py
+internal/ceres/generate_partitioned_matrix_view_specializations.py
+internal/ceres/gradient_checking_cost_function.cc
+internal/ceres/gradient_checking_cost_function.h
+internal/ceres/gradient_problem.cc
+internal/ceres/gradient_problem_evaluator.h
+internal/ceres/gradient_problem_solver.cc
+internal/ceres/graph_algorithms.h
+internal/ceres/graph.h
+internal/ceres/householder_vector.h
+internal/ceres/implicit_schur_complement.cc
+internal/ceres/implicit_schur_complement.h
+internal/ceres/integral_types.h
+internal/ceres/iterative_schur_complement_solver.cc
+internal/ceres/iterative_schur_complement_solver.h
+internal/ceres/lapack.cc
+internal/ceres/lapack.h
+internal/ceres/levenberg_marquardt_strategy.cc
+internal/ceres/levenberg_marquardt_strategy.h
+internal/ceres/linear_least_squares_problems.cc
+internal/ceres/linear_least_squares_problems.h
+internal/ceres/linear_operator.cc
+internal/ceres/linear_operator.h
+internal/ceres/linear_solver.cc
+internal/ceres/linear_solver.h
+internal/ceres/line_search.cc
+internal/ceres/line_search_direction.cc
+internal/ceres/line_search_direction.h
+internal/ceres/line_search.h
+internal/ceres/line_search_minimizer.cc
+internal/ceres/line_search_minimizer.h
+internal/ceres/line_search_preprocessor.cc
+internal/ceres/line_search_preprocessor.h
+internal/ceres/local_parameterization.cc
+internal/ceres/loss_function.cc
+internal/ceres/low_rank_inverse_hessian.cc
+internal/ceres/low_rank_inverse_hessian.h
+internal/ceres/map_util.h
+internal/ceres/minimizer.cc
+internal/ceres/minimizer.h
+internal/ceres/mutex.h
+internal/ceres/normal_prior.cc
+internal/ceres/parameter_block.h
+internal/ceres/parameter_block_ordering.cc
+internal/ceres/parameter_block_ordering.h
+internal/ceres/partitioned_matrix_view.cc
+internal/ceres/partitioned_matrix_view.h
+internal/ceres/partitioned_matrix_view_impl.h
+internal/ceres/polynomial.cc
+internal/ceres/polynomial.h
+internal/ceres/preconditioner.cc
+internal/ceres/preconditioner.h
+internal/ceres/preprocessor.cc
+internal/ceres/preprocessor.h
+internal/ceres/problem.cc
+internal/ceres/problem_impl.cc
+internal/ceres/problem_impl.h
+internal/ceres/program.cc
+internal/ceres/program_evaluator.h
+internal/ceres/program.h
+internal/ceres/random.h
+internal/ceres/reorder_program.cc
+internal/ceres/reorder_program.h
+internal/ceres/residual_block.cc
+internal/ceres/residual_block.h
+internal/ceres/residual_block_utils.cc
+internal/ceres/residual_block_utils.h
+internal/ceres/schur_complement_solver.cc
+internal/ceres/schur_complement_solver.h
+internal/ceres/schur_eliminator.cc
+internal/ceres/schur_eliminator.h
+internal/ceres/schur_eliminator_impl.h
+internal/ceres/schur_jacobi_preconditioner.cc
+internal/ceres/schur_jacobi_preconditioner.h
+internal/ceres/scratch_evaluate_preparer.cc
+internal/ceres/scratch_evaluate_preparer.h
+internal/ceres/small_blas.h
+internal/ceres/solver.cc
+internal/ceres/solver_utils.cc
+internal/ceres/solver_utils.h
+internal/ceres/sparse_matrix.cc
+internal/ceres/sparse_matrix.h
+internal/ceres/sparse_normal_cholesky_solver.cc
+internal/ceres/sparse_normal_cholesky_solver.h
+internal/ceres/split.cc
+internal/ceres/split.h
+internal/ceres/stl_util.h
+internal/ceres/stringprintf.cc
+internal/ceres/stringprintf.h
+internal/ceres/suitesparse.h
+internal/ceres/triplet_sparse_matrix.cc
+internal/ceres/triplet_sparse_matrix.h
+internal/ceres/trust_region_minimizer.cc
+internal/ceres/trust_region_minimizer.h
+internal/ceres/trust_region_preprocessor.cc
+internal/ceres/trust_region_preprocessor.h
+internal/ceres/trust_region_strategy.cc
+internal/ceres/trust_region_strategy.h
+internal/ceres/types.cc
+internal/ceres/visibility_based_preconditioner.h
+internal/ceres/wall_time.cc
+internal/ceres/wall_time.h
+config/ceres/internal/config.h
diff --git a/extern/ceres/include/ceres/autodiff_cost_function.h b/extern/ceres/include/ceres/autodiff_cost_function.h
new file mode 100644
index 00000000000..e7893e4828e
--- /dev/null
+++ b/extern/ceres/include/ceres/autodiff_cost_function.h
@@ -0,0 +1,227 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Create CostFunctions as needed by the least squares framework, with
+// Jacobians computed via automatic differentiation. For more
+// information on automatic differentation, see the wikipedia article
+// at http://en.wikipedia.org/wiki/Automatic_differentiation
+//
+// To get an auto differentiated cost function, you must define a class with a
+// templated operator() (a functor) that computes the cost function in terms of
+// the template parameter T. The autodiff framework substitutes appropriate
+// "jet" objects for T in order to compute the derivative when necessary, but
+// this is hidden, and you should write the function as if T were a scalar type
+// (e.g. a double-precision floating point number).
+//
+// The function must write the computed value in the last argument
+// (the only non-const one) and return true to indicate
+// success. Please see cost_function.h for details on how the return
+// value maybe used to impose simple constraints on the parameter
+// block.
+//
+// For example, consider a scalar error e = k - x'y, where both x and y are
+// two-dimensional column vector parameters, the prime sign indicates
+// transposition, and k is a constant. The form of this error, which is the
+// difference between a constant and an expression, is a common pattern in least
+// squares problems. For example, the value x'y might be the model expectation
+// for a series of measurements, where there is an instance of the cost function
+// for each measurement k.
+//
+// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
+// the squaring is implicitly done by the optimization framework.
+//
+// To write an auto-differentiable cost function for the above model, first
+// define the object
+//
+// class MyScalarCostFunctor {
+// MyScalarCostFunctor(double k): k_(k) {}
+//
+// template <typename T>
+// bool operator()(const T* const x , const T* const y, T* e) const {
+// e[0] = T(k_) - x[0] * y[0] + x[1] * y[1];
+// return true;
+// }
+//
+// private:
+// double k_;
+// };
+//
+// Note that in the declaration of operator() the input parameters x and y come
+// first, and are passed as const pointers to arrays of T. If there were three
+// input parameters, then the third input parameter would come after y. The
+// output is always the last parameter, and is also a pointer to an array. In
+// the example above, e is a scalar, so only e[0] is set.
+//
+// Then given this class definition, the auto differentiated cost function for
+// it can be constructed as follows.
+//
+// CostFunction* cost_function
+// = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
+// new MyScalarCostFunctor(1.0)); ^ ^ ^
+// | | |
+// Dimension of residual -----+ | |
+// Dimension of x ---------------+ |
+// Dimension of y ------------------+
+//
+// In this example, there is usually an instance for each measumerent of k.
+//
+// In the instantiation above, the template parameters following
+// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
+// 1-dimensional output from two arguments, both 2-dimensional.
+//
+// AutoDiffCostFunction also supports cost functions with a
+// runtime-determined number of residuals. For example:
+//
+// CostFunction* cost_function
+// = new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
+// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
+// runtime_number_of_residuals); <----+ | | |
+// | | | |
+// | | | |
+// Actual number of residuals ------+ | | |
+// Indicate dynamic number of residuals --------+ | |
+// Dimension of x ------------------------------------+ |
+// Dimension of y ---------------------------------------+
+//
+// The framework can currently accommodate cost functions of up to 10
+// independent variables, and there is no limit on the dimensionality
+// of each of them.
+//
+// WARNING #1: Since the functor will get instantiated with different types for
+// T, you must to convert from other numeric types to T before mixing
+// computations with other variables of type T. In the example above, this is
+// seen where instead of using k_ directly, k_ is wrapped with T(k_).
+//
+// WARNING #2: A common beginner's error when first using autodiff cost
+// functions is to get the sizing wrong. In particular, there is a tendency to
+// set the template parameters to (dimension of residual, number of parameters)
+// instead of passing a dimension parameter for *every parameter*. In the
+// example above, that would be <MyScalarCostFunctor, 1, 2>, which is missing
+// the last '2' argument. Please be careful when setting the size parameters.
+
+#ifndef CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
+
+#include "ceres/internal/autodiff.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/sized_cost_function.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// A cost function which computes the derivative of the cost with respect to
+// the parameters (a.k.a. the jacobian) using an autodifferentiation framework.
+// The first template argument is the functor object, described in the header
+// comment. The second argument is the dimension of the residual (or
+// ceres::DYNAMIC to indicate it will be set at runtime), and subsequent
+// arguments describe the size of the Nth parameter, one per parameter.
+//
+// The constructors take ownership of the cost functor.
+//
+// If the number of residuals (argument kNumResiduals below) is
+// ceres::DYNAMIC, then the two-argument constructor must be used. The
+// second constructor takes a number of residuals (in addition to the
+// templated number of residuals). This allows for varying the number
+// of residuals for a single autodiff cost function at runtime.
+template <typename CostFunctor,
+ int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
+ int N0, // Number of parameters in block 0.
+ int N1 = 0, // Number of parameters in block 1.
+ int N2 = 0, // Number of parameters in block 2.
+ int N3 = 0, // Number of parameters in block 3.
+ int N4 = 0, // Number of parameters in block 4.
+ int N5 = 0, // Number of parameters in block 5.
+ int N6 = 0, // Number of parameters in block 6.
+ int N7 = 0, // Number of parameters in block 7.
+ int N8 = 0, // Number of parameters in block 8.
+ int N9 = 0> // Number of parameters in block 9.
+class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9> {
+ public:
+ // Takes ownership of functor. Uses the template-provided value for the
+ // number of residuals ("kNumResiduals").
+ explicit AutoDiffCostFunction(CostFunctor* functor)
+ : functor_(functor) {
+ CHECK_NE(kNumResiduals, DYNAMIC)
+ << "Can't run the fixed-size constructor if the "
+ << "number of residuals is set to ceres::DYNAMIC.";
+ }
+
+ // Takes ownership of functor. Ignores the template-provided
+ // kNumResiduals in favor of the "num_residuals" argument provided.
+ //
+ // This allows for having autodiff cost functions which return varying
+ // numbers of residuals at runtime.
+ AutoDiffCostFunction(CostFunctor* functor, int num_residuals)
+ : functor_(functor) {
+ CHECK_EQ(kNumResiduals, DYNAMIC)
+ << "Can't run the dynamic-size constructor if the "
+ << "number of residuals is not ceres::DYNAMIC.";
+ SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9>
+ ::set_num_residuals(num_residuals);
+ }
+
+ virtual ~AutoDiffCostFunction() {}
+
+ // Implementation details follow; clients of the autodiff cost function should
+ // not have to examine below here.
+ //
+ // To handle varardic cost functions, some template magic is needed. It's
+ // mostly hidden inside autodiff.h.
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ if (!jacobians) {
+ return internal::VariadicEvaluate<
+ CostFunctor, double, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
+ ::Call(*functor_, parameters, residuals);
+ }
+ return internal::AutoDiff<CostFunctor, double,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate(
+ *functor_,
+ parameters,
+ SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9>::num_residuals(),
+ residuals,
+ jacobians);
+ }
+
+ private:
+ internal::scoped_ptr<CostFunctor> functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/autodiff_local_parameterization.h b/extern/ceres/include/ceres/autodiff_local_parameterization.h
new file mode 100644
index 00000000000..27397e20d3b
--- /dev/null
+++ b/extern/ceres/include/ceres/autodiff_local_parameterization.h
@@ -0,0 +1,154 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sergey.vfx@gmail.com (Sergey Sharybin)
+// mierle@gmail.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
+#define CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
+
+#include "ceres/local_parameterization.h"
+#include "ceres/internal/autodiff.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+
+// Create local parameterization with Jacobians computed via automatic
+// differentiation. For more information on local parameterizations,
+// see include/ceres/local_parameterization.h
+//
+// To get an auto differentiated local parameterization, you must define
+// a class with a templated operator() (a functor) that computes
+//
+// x_plus_delta = Plus(x, delta);
+//
+// the template parameter T. The autodiff framework substitutes appropriate
+// "Jet" objects for T in order to compute the derivative when necessary, but
+// this is hidden, and you should write the function as if T were a scalar type
+// (e.g. a double-precision floating point number).
+//
+// The function must write the computed value in the last argument (the only
+// non-const one) and return true to indicate success.
+//
+// For example, Quaternions have a three dimensional local
+// parameterization. It's plus operation can be implemented as (taken
+// from internal/ceres/auto_diff_local_parameterization_test.cc)
+//
+// struct QuaternionPlus {
+// template<typename T>
+// bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
+// const T squared_norm_delta =
+// delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
+//
+// T q_delta[4];
+// if (squared_norm_delta > T(0.0)) {
+// T norm_delta = sqrt(squared_norm_delta);
+// const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
+// q_delta[0] = cos(norm_delta);
+// q_delta[1] = sin_delta_by_delta * delta[0];
+// q_delta[2] = sin_delta_by_delta * delta[1];
+// q_delta[3] = sin_delta_by_delta * delta[2];
+// } else {
+// // We do not just use q_delta = [1,0,0,0] here because that is a
+// // constant and when used for automatic differentiation will
+// // lead to a zero derivative. Instead we take a first order
+// // approximation and evaluate it at zero.
+// q_delta[0] = T(1.0);
+// q_delta[1] = delta[0];
+// q_delta[2] = delta[1];
+// q_delta[3] = delta[2];
+// }
+//
+// QuaternionProduct(q_delta, x, x_plus_delta);
+// return true;
+// }
+// };
+//
+// Then given this struct, the auto differentiated local
+// parameterization can now be constructed as
+//
+// LocalParameterization* local_parameterization =
+// new AutoDiffLocalParameterization<QuaternionPlus, 4, 3>;
+// | |
+// Global Size ---------------+ |
+// Local Size -------------------+
+//
+// WARNING: Since the functor will get instantiated with different types for
+// T, you must to convert from other numeric types to T before mixing
+// computations with other variables of type T. In the example above, this is
+// seen where instead of using k_ directly, k_ is wrapped with T(k_).
+
+template <typename Functor, int kGlobalSize, int kLocalSize>
+class AutoDiffLocalParameterization : public LocalParameterization {
+ public:
+ AutoDiffLocalParameterization() :
+ functor_(new Functor()) {}
+
+ // Takes ownership of functor.
+ explicit AutoDiffLocalParameterization(Functor* functor) :
+ functor_(functor) {}
+
+ virtual ~AutoDiffLocalParameterization() {}
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ return (*functor_)(x, delta, x_plus_delta);
+ }
+
+ virtual bool ComputeJacobian(const double* x, double* jacobian) const {
+ double zero_delta[kLocalSize];
+ for (int i = 0; i < kLocalSize; ++i) {
+ zero_delta[i] = 0.0;
+ }
+
+ double x_plus_delta[kGlobalSize];
+ for (int i = 0; i < kGlobalSize; ++i) {
+ x_plus_delta[i] = 0.0;
+ }
+
+ const double* parameter_ptrs[2] = {x, zero_delta};
+ double* jacobian_ptrs[2] = { NULL, jacobian };
+ return internal::AutoDiff<Functor, double, kGlobalSize, kLocalSize>
+ ::Differentiate(*functor_,
+ parameter_ptrs,
+ kGlobalSize,
+ x_plus_delta,
+ jacobian_ptrs);
+ }
+
+ virtual int GlobalSize() const { return kGlobalSize; }
+ virtual int LocalSize() const { return kLocalSize; }
+
+ private:
+ internal::scoped_ptr<Functor> functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
diff --git a/extern/ceres/include/ceres/c_api.h b/extern/ceres/include/ceres/c_api.h
new file mode 100644
index 00000000000..df7c9b6d671
--- /dev/null
+++ b/extern/ceres/include/ceres/c_api.h
@@ -0,0 +1,146 @@
+/* Ceres Solver - A fast non-linear least squares minimizer
+ * Copyright 2015 Google Inc. All rights reserved.
+ * http://ceres-solver.org/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Google Inc. nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: mierle@gmail.com (Keir Mierle)
+ *
+ * A minimal C API for Ceres. Not all functionality is included. This API is
+ * not intended for clients of Ceres, but is instead intended for easing the
+ * process of binding Ceres to other languages.
+ *
+ * Currently this is a work in progress.
+ */
+
+#ifndef CERES_PUBLIC_C_API_H_
+#define CERES_PUBLIC_C_API_H_
+
+#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Init the Ceres private data. Must be called before anything else. */
+CERES_EXPORT void ceres_init();
+
+/* Equivalent to CostFunction::Evaluate() in the C++ API.
+ *
+ * The user may keep private information inside the opaque user_data object.
+ * The pointer here is the same one passed in the ceres_add_residual_block().
+ */
+typedef int (*ceres_cost_function_t)(void* user_data,
+ double** parameters,
+ double* residuals,
+ double** jacobians);
+
+/* Equivalent to LossFunction::Evaluate() from the C++ API. */
+typedef void (*ceres_loss_function_t)(void* user_data,
+ double squared_norm,
+ double out[3]);
+
+/* Create callback data for Ceres' stock loss functions.
+ *
+ * Ceres has several loss functions available by default, and these functions
+ * expose those to the C API. To use the stock loss functions, call
+ * ceres_create_*_loss_data(), which internally creates an instance of one of
+ * the stock loss functions (for example ceres::CauchyLoss), and pass the
+ * returned "loss_function_data" along with the ceres_stock_loss_function to
+ * ceres_add_residual_block().
+ *
+ * For example:
+ *
+ * void* cauchy_loss_function_data =
+ * ceres_create_cauchy_loss_function_data(1.2, 0.0);
+ * ceres_problem_add_residual_block(
+ * problem,
+ * my_cost_function,
+ * my_cost_function_data,
+ * ceres_stock_loss_function,
+ * cauchy_loss_function_data,
+ * 1,
+ * 2,
+ * parameter_sizes,
+ * parameter_pointers);
+ * ...
+ * ceres_free_stock_loss_function_data(cauchy_loss_function_data);
+ *
+ * See loss_function.h for the details of each loss function.
+ */
+CERES_EXPORT void* ceres_create_huber_loss_function_data(double a);
+CERES_EXPORT void* ceres_create_softl1_loss_function_data(double a);
+CERES_EXPORT void* ceres_create_cauchy_loss_function_data(double a);
+CERES_EXPORT void* ceres_create_arctan_loss_function_data(double a);
+CERES_EXPORT void* ceres_create_tolerant_loss_function_data(double a, double b);
+
+/* Free the given stock loss function data. */
+CERES_EXPORT void ceres_free_stock_loss_function_data(void* loss_function_data);
+
+/* This is an implementation of ceres_loss_function_t contained within Ceres
+ * itself, intended as a way to access the various stock Ceres loss functions
+ * from the C API. This should be passed to ceres_add_residual() below, in
+ * combination with a user_data pointer generated by
+ * ceres_create_stock_loss_function() above. */
+CERES_EXPORT void ceres_stock_loss_function(void* user_data,
+ double squared_norm,
+ double out[3]);
+
+/* Equivalent to Problem from the C++ API. */
+struct ceres_problem_s;
+typedef struct ceres_problem_s ceres_problem_t;
+
+struct ceres_residual_block_id_s;
+typedef struct ceres_residual_block_id_s ceres_residual_block_id_t;
+
+/* Create and destroy a problem */
+/* TODO(keir): Add options for the problem. */
+CERES_EXPORT ceres_problem_t* ceres_create_problem();
+CERES_EXPORT void ceres_free_problem(ceres_problem_t* problem);
+
+/* Add a residual block. */
+CERES_EXPORT ceres_residual_block_id_t* ceres_problem_add_residual_block(
+ ceres_problem_t* problem,
+ ceres_cost_function_t cost_function,
+ void* cost_function_data,
+ ceres_loss_function_t loss_function,
+ void* loss_function_data,
+ int num_residuals,
+ int num_parameter_blocks,
+ int* parameter_block_sizes,
+ double** parameters);
+
+CERES_EXPORT void ceres_solve(ceres_problem_t* problem);
+
+/* TODO(keir): Figure out a way to pass a config in. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif /* CERES_PUBLIC_C_API_H_ */
diff --git a/extern/ceres/include/ceres/ceres.h b/extern/ceres/include/ceres/ceres.h
new file mode 100644
index 00000000000..64ffb99798a
--- /dev/null
+++ b/extern/ceres/include/ceres/ceres.h
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// This is a forwarding header containing the public symbols exported from
+// Ceres. Anything in the "ceres" namespace is available for use.
+
+#ifndef CERES_PUBLIC_CERES_H_
+#define CERES_PUBLIC_CERES_H_
+
+#include "ceres/autodiff_cost_function.h"
+#include "ceres/autodiff_local_parameterization.h"
+#include "ceres/cost_function.h"
+#include "ceres/cost_function_to_functor.h"
+#include "ceres/covariance.h"
+#include "ceres/crs_matrix.h"
+#include "ceres/dynamic_autodiff_cost_function.h"
+#include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/gradient_problem.h"
+#include "ceres/gradient_problem_solver.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/jet.h"
+#include "ceres/local_parameterization.h"
+#include "ceres/loss_function.h"
+#include "ceres/numeric_diff_cost_function.h"
+#include "ceres/ordered_groups.h"
+#include "ceres/problem.h"
+#include "ceres/sized_cost_function.h"
+#include "ceres/solver.h"
+#include "ceres/types.h"
+#include "ceres/version.h"
+
+#endif // CERES_PUBLIC_CERES_H_
diff --git a/extern/ceres/include/ceres/conditioned_cost_function.h b/extern/ceres/include/ceres/conditioned_cost_function.h
new file mode 100644
index 00000000000..29597d935cb
--- /dev/null
+++ b/extern/ceres/include/ceres/conditioned_cost_function.h
@@ -0,0 +1,99 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wjr@google.com (William Rucklidge)
+//
+// This file contains a cost function that can apply a transformation to
+// each residual value before they are square-summed.
+
+#ifndef CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
+#define CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
+
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// This class allows you to apply different conditioning to the residual
+// values of a wrapped cost function. An example where this is useful is
+// where you have an existing cost function that produces N values, but you
+// want the total cost to be something other than just the sum of these
+// squared values - maybe you want to apply a different scaling to some
+// values, to change their contribution to the cost.
+//
+// Usage:
+//
+// // my_cost_function produces N residuals
+// CostFunction* my_cost_function = ...
+// CHECK_EQ(N, my_cost_function->num_residuals());
+// vector<CostFunction*> conditioners;
+//
+// // Make N 1x1 cost functions (1 parameter, 1 residual)
+// CostFunction* f_1 = ...
+// conditioners.push_back(f_1);
+// ...
+// CostFunction* f_N = ...
+// conditioners.push_back(f_N);
+// ConditionedCostFunction* ccf =
+// new ConditionedCostFunction(my_cost_function, conditioners);
+//
+// Now ccf's residual i (i=0..N-1) will be passed though the i'th conditioner.
+//
+// ccf_residual[i] = f_i(my_cost_function_residual[i])
+//
+// and the Jacobian will be affected appropriately.
+class CERES_EXPORT ConditionedCostFunction : public CostFunction {
+ public:
+ // Builds a cost function based on a wrapped cost function, and a
+ // per-residual conditioner. Takes ownership of all of the wrapped cost
+ // functions, or not, depending on the ownership parameter. Conditioners
+ // may be NULL, in which case the corresponding residual is not modified.
+ ConditionedCostFunction(CostFunction* wrapped_cost_function,
+ const std::vector<CostFunction*>& conditioners,
+ Ownership ownership);
+ virtual ~ConditionedCostFunction();
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const;
+
+ private:
+ internal::scoped_ptr<CostFunction> wrapped_cost_function_;
+ std::vector<CostFunction*> conditioners_;
+ Ownership ownership_;
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/cost_function.h b/extern/ceres/include/ceres/cost_function.h
new file mode 100644
index 00000000000..f051a897c0d
--- /dev/null
+++ b/extern/ceres/include/ceres/cost_function.h
@@ -0,0 +1,147 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// keir@google.m (Keir Mierle)
+//
+// This is the interface through which the least squares solver accesses the
+// residual and Jacobian of the least squares problem. Users are expected to
+// subclass CostFunction to define their own terms in the least squares problem.
+//
+// It is recommended that users define templated residual functors for use as
+// arguments for AutoDiffCostFunction (see autodiff_cost_function.h), instead of
+// directly implementing the CostFunction interface. This often results in both
+// shorter code and faster execution than hand-coded derivatives. However,
+// specialized cases may demand direct implementation of the lower-level
+// CostFunction interface; for example, this is true when calling legacy code
+// which is not templated on numeric types.
+
+#ifndef CERES_PUBLIC_COST_FUNCTION_H_
+#define CERES_PUBLIC_COST_FUNCTION_H_
+
+#include <vector>
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// This class implements the computation of the cost (a.k.a. residual) terms as
+// a function of the input (control) variables, and is the interface for users
+// to describe their least squares problem to Ceres. In other words, this is the
+// modelling layer between users and the Ceres optimizer. The signature of the
+// function (number and sizes of input parameter blocks and number of outputs)
+// is stored in parameter_block_sizes_ and num_residuals_ respectively. User
+// code inheriting from this class is expected to set these two members with the
+// corresponding accessors. This information will be verified by the Problem
+// when added with AddResidualBlock().
+class CERES_EXPORT CostFunction {
+ public:
+ CostFunction() : num_residuals_(0) {}
+
+ virtual ~CostFunction() {}
+
+ // Inputs:
+ //
+ // parameters is an array of pointers to arrays containing the
+ // various parameter blocks. parameters has the same number of
+ // elements as parameter_block_sizes_. Parameter blocks are in the
+ // same order as parameter_block_sizes_.i.e.,
+ //
+ // parameters_[i] = double[parameter_block_sizes_[i]]
+ //
+ // Outputs:
+ //
+ // residuals is an array of size num_residuals_.
+ //
+ // jacobians is an array of size parameter_block_sizes_ containing
+ // pointers to storage for jacobian blocks corresponding to each
+ // parameter block. Jacobian blocks are in the same order as
+ // parameter_block_sizes, i.e. jacobians[i], is an
+ // array that contains num_residuals_* parameter_block_sizes_[i]
+ // elements. Each jacobian block is stored in row-major order, i.e.,
+ //
+ // jacobians[i][r*parameter_block_size_[i] + c] =
+ // d residual[r] / d parameters[i][c]
+ //
+ // If jacobians is NULL, then no derivatives are returned; this is
+ // the case when computing cost only. If jacobians[i] is NULL, then
+ // the jacobian block corresponding to the i'th parameter block must
+ // not to be returned.
+ //
+ // The return value indicates whether the computation of the
+ // residuals and/or jacobians was successful or not.
+ //
+ // This can be used to communicate numerical failures in jacobian
+ // computations for instance.
+ //
+ // A more interesting and common use is to impose constraints on the
+ // parameters. If the initial values of the parameter blocks satisfy
+ // the constraints, then returning false whenever the constraints
+ // are not satisfied will prevent the solver from moving into the
+ // infeasible region. This is not a very sophisticated mechanism for
+ // enforcing constraints, but is often good enough.
+ //
+ // Note that it is important that the initial values of the
+ // parameter block must be feasible, otherwise the solver will
+ // declare a numerical problem at iteration 0.
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const = 0;
+
+ const std::vector<int32>& parameter_block_sizes() const {
+ return parameter_block_sizes_;
+ }
+
+ int num_residuals() const {
+ return num_residuals_;
+ }
+
+ protected:
+ std::vector<int32>* mutable_parameter_block_sizes() {
+ return &parameter_block_sizes_;
+ }
+
+ void set_num_residuals(int num_residuals) {
+ num_residuals_ = num_residuals;
+ }
+
+ private:
+ // Cost function signature metadata: number of inputs & their sizes,
+ // number of outputs (residuals).
+ std::vector<int32> parameter_block_sizes_;
+ int num_residuals_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(CostFunction);
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/cost_function_to_functor.h b/extern/ceres/include/ceres/cost_function_to_functor.h
new file mode 100644
index 00000000000..6c67ac0f937
--- /dev/null
+++ b/extern/ceres/include/ceres/cost_function_to_functor.h
@@ -0,0 +1,682 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// CostFunctionToFunctor is an adapter class that allows users to use
+// SizedCostFunction objects in templated functors which are to be used for
+// automatic differentiation. This allows the user to seamlessly mix
+// analytic, numeric and automatic differentiation.
+//
+// For example, let us assume that
+//
+// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
+// public:
+// IntrinsicProjection(const double* observation);
+// virtual bool Evaluate(double const* const* parameters,
+// double* residuals,
+// double** jacobians) const;
+// };
+//
+// is a cost function that implements the projection of a point in its
+// local coordinate system onto its image plane and subtracts it from
+// the observed point projection. It can compute its residual and
+// either via analytic or numerical differentiation can compute its
+// jacobians.
+//
+// Now we would like to compose the action of this CostFunction with
+// the action of camera extrinsics, i.e., rotation and
+// translation. Say we have a templated function
+//
+// template<typename T>
+// void RotateAndTranslatePoint(const T* rotation,
+// const T* translation,
+// const T* point,
+// T* result);
+//
+// Then we can now do the following,
+//
+// struct CameraProjection {
+// CameraProjection(const double* observation)
+// : intrinsic_projection_(new IntrinsicProjection(observation)) {
+// }
+// template <typename T>
+// bool operator()(const T* rotation,
+// const T* translation,
+// const T* intrinsics,
+// const T* point,
+// T* residual) const {
+// T transformed_point[3];
+// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
+//
+// // Note that we call intrinsic_projection_, just like it was
+// // any other templated functor.
+//
+// return intrinsic_projection_(intrinsics, transformed_point, residual);
+// }
+//
+// private:
+// CostFunctionToFunctor<2,5,3> intrinsic_projection_;
+// };
+
+#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
+#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
+
+#include <numeric>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/dynamic_cost_function_to_functor.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+
+template <int kNumResiduals,
+ int N0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
+ int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
+class CostFunctionToFunctor {
+ public:
+ // Takes ownership of cost_function.
+ explicit CostFunctionToFunctor(CostFunction* cost_function)
+ : cost_functor_(cost_function) {
+ CHECK_NOTNULL(cost_function);
+ CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
+
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) // NOLINT
+ << "Zero block cannot precede a non-zero block. Block sizes are "
+ << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
+
+ const std::vector<int32>& parameter_block_sizes =
+ cost_function->parameter_block_sizes();
+ const int num_parameter_blocks =
+ (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
+ (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
+ CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks);
+
+ CHECK_EQ(N0, parameter_block_sizes[0]);
+ if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT
+ if (parameter_block_sizes.size() > 2) CHECK_EQ(N2, parameter_block_sizes[2]); // NOLINT
+ if (parameter_block_sizes.size() > 3) CHECK_EQ(N3, parameter_block_sizes[3]); // NOLINT
+ if (parameter_block_sizes.size() > 4) CHECK_EQ(N4, parameter_block_sizes[4]); // NOLINT
+ if (parameter_block_sizes.size() > 5) CHECK_EQ(N5, parameter_block_sizes[5]); // NOLINT
+ if (parameter_block_sizes.size() > 6) CHECK_EQ(N6, parameter_block_sizes[6]); // NOLINT
+ if (parameter_block_sizes.size() > 7) CHECK_EQ(N7, parameter_block_sizes[7]); // NOLINT
+ if (parameter_block_sizes.size() > 8) CHECK_EQ(N8, parameter_block_sizes[8]); // NOLINT
+ if (parameter_block_sizes.size() > 9) CHECK_EQ(N9, parameter_block_sizes[9]); // NOLINT
+
+ CHECK_EQ(accumulate(parameter_block_sizes.begin(),
+ parameter_block_sizes.end(), 0),
+ N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9);
+ }
+
+ bool operator()(const double* x0, double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_EQ(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+
+ return cost_functor_(&x0, residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(2);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(3);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(4);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(5);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(6);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ const double* x6,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(7);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ const double* x6,
+ const double* x7,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(8);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ parameter_blocks[7] = x7;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ const double* x6,
+ const double* x7,
+ const double* x8,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(9);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ parameter_blocks[7] = x7;
+ parameter_blocks[8] = x8;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ const double* x6,
+ const double* x7,
+ const double* x8,
+ const double* x9,
+ double* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_NE(N9, 0);
+ internal::FixedArray<const double*> parameter_blocks(10);
+ parameter_blocks[0] = x0;
+ parameter_blocks[1] = x1;
+ parameter_blocks[2] = x2;
+ parameter_blocks[3] = x3;
+ parameter_blocks[4] = x4;
+ parameter_blocks[5] = x5;
+ parameter_blocks[6] = x6;
+ parameter_blocks[7] = x7;
+ parameter_blocks[8] = x8;
+ parameter_blocks[9] = x9;
+ return cost_functor_(parameter_blocks.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0, JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_EQ(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ return cost_functor_(&x0, residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_EQ(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(2);
+ jets[0] = x0;
+ jets[1] = x1;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_EQ(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(3);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_EQ(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(4);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_EQ(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(5);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_EQ(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(6);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_EQ(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(7);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ const JetT* x7,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_EQ(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(8);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ jets[7] = x7;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ const JetT* x7,
+ const JetT* x8,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_EQ(N9, 0);
+ internal::FixedArray<const JetT*> jets(9);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ jets[7] = x7;
+ jets[8] = x8;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ template <typename JetT>
+ bool operator()(const JetT* x0,
+ const JetT* x1,
+ const JetT* x2,
+ const JetT* x3,
+ const JetT* x4,
+ const JetT* x5,
+ const JetT* x6,
+ const JetT* x7,
+ const JetT* x8,
+ const JetT* x9,
+ JetT* residuals) const {
+ CHECK_NE(N0, 0);
+ CHECK_NE(N1, 0);
+ CHECK_NE(N2, 0);
+ CHECK_NE(N3, 0);
+ CHECK_NE(N4, 0);
+ CHECK_NE(N5, 0);
+ CHECK_NE(N6, 0);
+ CHECK_NE(N7, 0);
+ CHECK_NE(N8, 0);
+ CHECK_NE(N9, 0);
+ internal::FixedArray<const JetT*> jets(10);
+ jets[0] = x0;
+ jets[1] = x1;
+ jets[2] = x2;
+ jets[3] = x3;
+ jets[4] = x4;
+ jets[5] = x5;
+ jets[6] = x6;
+ jets[7] = x7;
+ jets[8] = x8;
+ jets[9] = x9;
+ return cost_functor_(jets.get(), residuals);
+ }
+
+ private:
+ DynamicCostFunctionToFunctor cost_functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
diff --git a/extern/ceres/include/ceres/covariance.h b/extern/ceres/include/ceres/covariance.h
new file mode 100644
index 00000000000..dd20dc36ba1
--- /dev/null
+++ b/extern/ceres/include/ceres/covariance.h
@@ -0,0 +1,405 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_COVARIANCE_H_
+#define CERES_PUBLIC_COVARIANCE_H_
+
+#include <utility>
+#include <vector>
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+class Problem;
+
+namespace internal {
+class CovarianceImpl;
+} // namespace internal
+
+// WARNING
+// =======
+// It is very easy to use this class incorrectly without understanding
+// the underlying mathematics. Please read and understand the
+// documentation completely before attempting to use this class.
+//
+//
+// This class allows the user to evaluate the covariance for a
+// non-linear least squares problem and provides random access to its
+// blocks
+//
+// Background
+// ==========
+// One way to assess the quality of the solution returned by a
+// non-linear least squares solve is to analyze the covariance of the
+// solution.
+//
+// Let us consider the non-linear regression problem
+//
+// y = f(x) + N(0, I)
+//
+// i.e., the observation y is a random non-linear function of the
+// independent variable x with mean f(x) and identity covariance. Then
+// the maximum likelihood estimate of x given observations y is the
+// solution to the non-linear least squares problem:
+//
+// x* = arg min_x |f(x)|^2
+//
+// And the covariance of x* is given by
+//
+// C(x*) = inverse[J'(x*)J(x*)]
+//
+// Here J(x*) is the Jacobian of f at x*. The above formula assumes
+// that J(x*) has full column rank.
+//
+// If J(x*) is rank deficient, then the covariance matrix C(x*) is
+// also rank deficient and is given by
+//
+// C(x*) = pseudoinverse[J'(x*)J(x*)]
+//
+// Note that in the above, we assumed that the covariance
+// matrix for y was identity. This is an important assumption. If this
+// is not the case and we have
+//
+// y = f(x) + N(0, S)
+//
+// Where S is a positive semi-definite matrix denoting the covariance
+// of y, then the maximum likelihood problem to be solved is
+//
+// x* = arg min_x f'(x) inverse[S] f(x)
+//
+// and the corresponding covariance estimate of x* is given by
+//
+// C(x*) = inverse[J'(x*) inverse[S] J(x*)]
+//
+// So, if it is the case that the observations being fitted to have a
+// covariance matrix not equal to identity, then it is the user's
+// responsibility that the corresponding cost functions are correctly
+// scaled, e.g. in the above case the cost function for this problem
+// should evaluate S^{-1/2} f(x) instead of just f(x), where S^{-1/2}
+// is the inverse square root of the covariance matrix S.
+//
+// This class allows the user to evaluate the covariance for a
+// non-linear least squares problem and provides random access to its
+// blocks. The computation assumes that the CostFunctions compute
+// residuals such that their covariance is identity.
+//
+// Since the computation of the covariance matrix requires computing
+// the inverse of a potentially large matrix, this can involve a
+// rather large amount of time and memory. However, it is usually the
+// case that the user is only interested in a small part of the
+// covariance matrix. Quite often just the block diagonal. This class
+// allows the user to specify the parts of the covariance matrix that
+// she is interested in and then uses this information to only compute
+// and store those parts of the covariance matrix.
+//
+// Rank of the Jacobian
+// --------------------
+// As we noted above, if the jacobian is rank deficient, then the
+// inverse of J'J is not defined and instead a pseudo inverse needs to
+// be computed.
+//
+// The rank deficiency in J can be structural -- columns which are
+// always known to be zero or numerical -- depending on the exact
+// values in the Jacobian.
+//
+// Structural rank deficiency occurs when the problem contains
+// parameter blocks that are constant. This class correctly handles
+// structural rank deficiency like that.
+//
+// Numerical rank deficiency, where the rank of the matrix cannot be
+// predicted by its sparsity structure and requires looking at its
+// numerical values is more complicated. Here again there are two
+// cases.
+//
+// a. The rank deficiency arises from overparameterization. e.g., a
+// four dimensional quaternion used to parameterize SO(3), which is
+// a three dimensional manifold. In cases like this, the user should
+// use an appropriate LocalParameterization. Not only will this lead
+// to better numerical behaviour of the Solver, it will also expose
+// the rank deficiency to the Covariance object so that it can
+// handle it correctly.
+//
+// b. More general numerical rank deficiency in the Jacobian
+// requires the computation of the so called Singular Value
+// Decomposition (SVD) of J'J. We do not know how to do this for
+// large sparse matrices efficiently. For small and moderate sized
+// problems this is done using dense linear algebra.
+//
+// Gauge Invariance
+// ----------------
+// In structure from motion (3D reconstruction) problems, the
+// reconstruction is ambiguous upto a similarity transform. This is
+// known as a Gauge Ambiguity. Handling Gauges correctly requires the
+// use of SVD or custom inversion algorithms. For small problems the
+// user can use the dense algorithm. For more details see
+//
+// Ken-ichi Kanatani, Daniel D. Morris: Gauges and gauge
+// transformations for uncertainty description of geometric structure
+// with indeterminacy. IEEE Transactions on Information Theory 47(5):
+// 2017-2028 (2001)
+//
+// Example Usage
+// =============
+//
+// double x[3];
+// double y[2];
+//
+// Problem problem;
+// problem.AddParameterBlock(x, 3);
+// problem.AddParameterBlock(y, 2);
+// <Build Problem>
+// <Solve Problem>
+//
+// Covariance::Options options;
+// Covariance covariance(options);
+//
+// std::vector<std::pair<const double*, const double*> > covariance_blocks;
+// covariance_blocks.push_back(make_pair(x, x));
+// covariance_blocks.push_back(make_pair(y, y));
+// covariance_blocks.push_back(make_pair(x, y));
+//
+// CHECK(covariance.Compute(covariance_blocks, &problem));
+//
+// double covariance_xx[3 * 3];
+// double covariance_yy[2 * 2];
+// double covariance_xy[3 * 2];
+// covariance.GetCovarianceBlock(x, x, covariance_xx)
+// covariance.GetCovarianceBlock(y, y, covariance_yy)
+// covariance.GetCovarianceBlock(x, y, covariance_xy)
+//
+class CERES_EXPORT Covariance {
+ public:
+ struct CERES_EXPORT Options {
+ Options()
+#ifndef CERES_NO_SUITESPARSE
+ : algorithm_type(SUITE_SPARSE_QR),
+#else
+ : algorithm_type(EIGEN_SPARSE_QR),
+#endif
+ min_reciprocal_condition_number(1e-14),
+ null_space_rank(0),
+ num_threads(1),
+ apply_loss_function(true) {
+ }
+
+ // Ceres supports three different algorithms for covariance
+ // estimation, which represent different tradeoffs in speed,
+ // accuracy and reliability.
+ //
+ // 1. DENSE_SVD uses Eigen's JacobiSVD to perform the
+ // computations. It computes the singular value decomposition
+ //
+ // U * S * V' = J
+ //
+ // and then uses it to compute the pseudo inverse of J'J as
+ //
+ // pseudoinverse[J'J]^ = V * pseudoinverse[S] * V'
+ //
+ // It is an accurate but slow method and should only be used
+ // for small to moderate sized problems. It can handle
+ // full-rank as well as rank deficient Jacobians.
+ //
+ // 2. EIGEN_SPARSE_QR uses the sparse QR factorization algorithm
+ // in Eigen to compute the decomposition
+ //
+ // Q * R = J
+ //
+ // [J'J]^-1 = [R*R']^-1
+ //
+ // It is a moderately fast algorithm for sparse matrices.
+ //
+ // 3. SUITE_SPARSE_QR uses the SuiteSparseQR sparse QR
+ // factorization algorithm. It uses dense linear algebra and is
+ // multi threaded, so for large sparse sparse matrices it is
+ // significantly faster than EIGEN_SPARSE_QR.
+ //
+ // Neither EIGEN_SPARSE_QR not SUITE_SPARSE_QR are capable of
+ // computing the covariance if the Jacobian is rank deficient.
+ CovarianceAlgorithmType algorithm_type;
+
+ // If the Jacobian matrix is near singular, then inverting J'J
+ // will result in unreliable results, e.g, if
+ //
+ // J = [1.0 1.0 ]
+ // [1.0 1.0000001 ]
+ //
+ // which is essentially a rank deficient matrix, we have
+ //
+ // inv(J'J) = [ 2.0471e+14 -2.0471e+14]
+ // [-2.0471e+14 2.0471e+14]
+ //
+ // This is not a useful result. Therefore, by default
+ // Covariance::Compute will return false if a rank deficient
+ // Jacobian is encountered. How rank deficiency is detected
+ // depends on the algorithm being used.
+ //
+ // 1. DENSE_SVD
+ //
+ // min_sigma / max_sigma < sqrt(min_reciprocal_condition_number)
+ //
+ // where min_sigma and max_sigma are the minimum and maxiumum
+ // singular values of J respectively.
+ //
+ // 2. SUITE_SPARSE_QR and EIGEN_SPARSE_QR
+ //
+ // rank(J) < num_col(J)
+ //
+ // Here rank(J) is the estimate of the rank of J returned by the
+ // sparse QR factorization algorithm. It is a fairly reliable
+ // indication of rank deficiency.
+ //
+ double min_reciprocal_condition_number;
+
+ // When using DENSE_SVD, the user has more control in dealing with
+ // singular and near singular covariance matrices.
+ //
+ // As mentioned above, when the covariance matrix is near
+ // singular, instead of computing the inverse of J'J, the
+ // Moore-Penrose pseudoinverse of J'J should be computed.
+ //
+ // If J'J has the eigen decomposition (lambda_i, e_i), where
+ // lambda_i is the i^th eigenvalue and e_i is the corresponding
+ // eigenvector, then the inverse of J'J is
+ //
+ // inverse[J'J] = sum_i e_i e_i' / lambda_i
+ //
+ // and computing the pseudo inverse involves dropping terms from
+ // this sum that correspond to small eigenvalues.
+ //
+ // How terms are dropped is controlled by
+ // min_reciprocal_condition_number and null_space_rank.
+ //
+ // If null_space_rank is non-negative, then the smallest
+ // null_space_rank eigenvalue/eigenvectors are dropped
+ // irrespective of the magnitude of lambda_i. If the ratio of the
+ // smallest non-zero eigenvalue to the largest eigenvalue in the
+ // truncated matrix is still below
+ // min_reciprocal_condition_number, then the Covariance::Compute()
+ // will fail and return false.
+ //
+ // Setting null_space_rank = -1 drops all terms for which
+ //
+ // lambda_i / lambda_max < min_reciprocal_condition_number.
+ //
+ // This option has no effect on the SUITE_SPARSE_QR and
+ // EIGEN_SPARSE_QR algorithms.
+ int null_space_rank;
+
+ int num_threads;
+
+ // Even though the residual blocks in the problem may contain loss
+ // functions, setting apply_loss_function to false will turn off
+ // the application of the loss function to the output of the cost
+ // function and in turn its effect on the covariance.
+ //
+ // TODO(sameergaarwal): Expand this based on Jim's experiments.
+ bool apply_loss_function;
+ };
+
+ explicit Covariance(const Options& options);
+ ~Covariance();
+
+ // Compute a part of the covariance matrix.
+ //
+ // The vector covariance_blocks, indexes into the covariance matrix
+ // block-wise using pairs of parameter blocks. This allows the
+ // covariance estimation algorithm to only compute and store these
+ // blocks.
+ //
+ // Since the covariance matrix is symmetric, if the user passes
+ // (block1, block2), then GetCovarianceBlock can be called with
+ // block1, block2 as well as block2, block1.
+ //
+ // covariance_blocks cannot contain duplicates. Bad things will
+ // happen if they do.
+ //
+ // Note that the list of covariance_blocks is only used to determine
+ // what parts of the covariance matrix are computed. The full
+ // Jacobian is used to do the computation, i.e. they do not have an
+ // impact on what part of the Jacobian is used for computation.
+ //
+ // The return value indicates the success or failure of the
+ // covariance computation. Please see the documentation for
+ // Covariance::Options for more on the conditions under which this
+ // function returns false.
+ bool Compute(
+ const std::vector<std::pair<const double*,
+ const double*> >& covariance_blocks,
+ Problem* problem);
+
+ // Return the block of the cross-covariance matrix corresponding to
+ // parameter_block1 and parameter_block2.
+ //
+ // Compute must be called before the first call to
+ // GetCovarianceBlock and the pair <parameter_block1,
+ // parameter_block2> OR the pair <parameter_block2,
+ // parameter_block1> must have been present in the vector
+ // covariance_blocks when Compute was called. Otherwise
+ // GetCovarianceBlock will return false.
+ //
+ // covariance_block must point to a memory location that can store a
+ // parameter_block1_size x parameter_block2_size matrix. The
+ // returned covariance will be a row-major matrix.
+ bool GetCovarianceBlock(const double* parameter_block1,
+ const double* parameter_block2,
+ double* covariance_block) const;
+
+ // Return the block of the cross-covariance matrix corresponding to
+ // parameter_block1 and parameter_block2.
+ // Returns cross-covariance in the tangent space if a local
+ // parameterization is associated with either parameter block;
+ // else returns cross-covariance in the ambient space.
+ //
+ // Compute must be called before the first call to
+ // GetCovarianceBlock and the pair <parameter_block1,
+ // parameter_block2> OR the pair <parameter_block2,
+ // parameter_block1> must have been present in the vector
+ // covariance_blocks when Compute was called. Otherwise
+ // GetCovarianceBlock will return false.
+ //
+ // covariance_block must point to a memory location that can store a
+ // parameter_block1_local_size x parameter_block2_local_size matrix. The
+ // returned covariance will be a row-major matrix.
+ bool GetCovarianceBlockInTangentSpace(const double* parameter_block1,
+ const double* parameter_block2,
+ double* covariance_block) const;
+
+ private:
+ internal::scoped_ptr<internal::CovarianceImpl> impl_;
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_COVARIANCE_H_
diff --git a/extern/ceres/include/ceres/crs_matrix.h b/extern/ceres/include/ceres/crs_matrix.h
new file mode 100644
index 00000000000..23687c4670e
--- /dev/null
+++ b/extern/ceres/include/ceres/crs_matrix.h
@@ -0,0 +1,86 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_CRS_MATRIX_H_
+#define CERES_PUBLIC_CRS_MATRIX_H_
+
+#include <vector>
+#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// A compressed row sparse matrix used primarily for communicating the
+// Jacobian matrix to the user.
+struct CERES_EXPORT CRSMatrix {
+ CRSMatrix() : num_rows(0), num_cols(0) {}
+
+ int num_rows;
+ int num_cols;
+
+ // A compressed row matrix stores its contents in three arrays,
+ // rows, cols and values.
+ //
+ // rows is a num_rows + 1 sized array that points into the cols and
+ // values array. For each row i:
+ //
+ // cols[rows[i]] ... cols[rows[i + 1] - 1] are the indices of the
+ // non-zero columns of row i.
+ //
+ // values[rows[i]] .. values[rows[i + 1] - 1] are the values of the
+ // corresponding entries.
+ //
+ // cols and values contain as many entries as there are non-zeros in
+ // the matrix.
+ //
+ // e.g, consider the 3x4 sparse matrix
+ //
+ // [ 0 10 0 4 ]
+ // [ 0 2 -3 2 ]
+ // [ 1 2 0 0 ]
+ //
+ // The three arrays will be:
+ //
+ //
+ // -row0- ---row1--- -row2-
+ // rows = [ 0, 2, 5, 7]
+ // cols = [ 1, 3, 1, 2, 3, 0, 1]
+ // values = [10, 4, 2, -3, 2, 1, 2]
+
+ std::vector<int> cols;
+ std::vector<int> rows;
+ std::vector<double> values;
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_CRS_MATRIX_H_
diff --git a/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h b/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h
new file mode 100644
index 00000000000..e6d26111f18
--- /dev/null
+++ b/extern/ceres/include/ceres/dynamic_autodiff_cost_function.h
@@ -0,0 +1,260 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// mierle@gmail.com (Keir Mierle)
+//
+// This autodiff implementation differs from the one found in
+// autodiff_cost_function.h by supporting autodiff on cost functions
+// with variable numbers of parameters with variable sizes. With the
+// other implementation, all the sizes (both the number of parameter
+// blocks and the size of each block) must be fixed at compile time.
+//
+// The functor API differs slightly from the API for fixed size
+// autodiff; the expected interface for the cost functors is:
+//
+// struct MyCostFunctor {
+// template<typename T>
+// bool operator()(T const* const* parameters, T* residuals) const {
+// // Use parameters[i] to access the i'th parameter block.
+// }
+// }
+//
+// Since the sizing of the parameters is done at runtime, you must
+// also specify the sizes after creating the dynamic autodiff cost
+// function. For example:
+//
+// DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
+// new MyCostFunctor());
+// cost_function.AddParameterBlock(5);
+// cost_function.AddParameterBlock(10);
+// cost_function.SetNumResiduals(21);
+//
+// Under the hood, the implementation evaluates the cost function
+// multiple times, computing a small set of the derivatives (four by
+// default, controlled by the Stride template parameter) with each
+// pass. There is a tradeoff with the size of the passes; you may want
+// to experiment with the stride.
+
+#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
+
+#include <cmath>
+#include <numeric>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/jet.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+template <typename CostFunctor, int Stride = 4>
+class DynamicAutoDiffCostFunction : public CostFunction {
+ public:
+ explicit DynamicAutoDiffCostFunction(CostFunctor* functor)
+ : functor_(functor) {}
+
+ virtual ~DynamicAutoDiffCostFunction() {}
+
+ void AddParameterBlock(int size) {
+ mutable_parameter_block_sizes()->push_back(size);
+ }
+
+ void SetNumResiduals(int num_residuals) {
+ set_num_residuals(num_residuals);
+ }
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ CHECK_GT(num_residuals(), 0)
+ << "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
+ << "before DynamicAutoDiffCostFunction::Evaluate().";
+
+ if (jacobians == NULL) {
+ return (*functor_)(parameters, residuals);
+ }
+
+ // The difficulty with Jets, as implemented in Ceres, is that they were
+ // originally designed for strictly compile-sized use. At this point, there
+ // is a large body of code that assumes inside a cost functor it is
+ // acceptable to do e.g. T(1.5) and get an appropriately sized jet back.
+ //
+ // Unfortunately, it is impossible to communicate the expected size of a
+ // dynamically sized jet to the static instantiations that existing code
+ // depends on.
+ //
+ // To work around this issue, the solution here is to evaluate the
+ // jacobians in a series of passes, each one computing Stripe *
+ // num_residuals() derivatives. This is done with small, fixed-size jets.
+ const int num_parameter_blocks = parameter_block_sizes().size();
+ const int num_parameters = std::accumulate(parameter_block_sizes().begin(),
+ parameter_block_sizes().end(),
+ 0);
+
+ // Allocate scratch space for the strided evaluation.
+ std::vector<Jet<double, Stride> > input_jets(num_parameters);
+ std::vector<Jet<double, Stride> > output_jets(num_residuals());
+
+ // Make the parameter pack that is sent to the functor (reused).
+ std::vector<Jet<double, Stride>* > jet_parameters(num_parameter_blocks,
+ static_cast<Jet<double, Stride>* >(NULL));
+ int num_active_parameters = 0;
+
+ // To handle constant parameters between non-constant parameter blocks, the
+ // start position --- a raw parameter index --- of each contiguous block of
+ // non-constant parameters is recorded in start_derivative_section.
+ std::vector<int> start_derivative_section;
+ bool in_derivative_section = false;
+ int parameter_cursor = 0;
+
+ // Discover the derivative sections and set the parameter values.
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ jet_parameters[i] = &input_jets[parameter_cursor];
+
+ const int parameter_block_size = parameter_block_sizes()[i];
+ if (jacobians[i] != NULL) {
+ if (!in_derivative_section) {
+ start_derivative_section.push_back(parameter_cursor);
+ in_derivative_section = true;
+ }
+
+ num_active_parameters += parameter_block_size;
+ } else {
+ in_derivative_section = false;
+ }
+
+ for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) {
+ input_jets[parameter_cursor].a = parameters[i][j];
+ }
+ }
+
+ // When `num_active_parameters % Stride != 0` then it can be the case
+ // that `active_parameter_count < Stride` while parameter_cursor is less
+ // than the total number of parameters and with no remaining non-constant
+ // parameter blocks. Pushing parameter_cursor (the total number of
+ // parameters) as a final entry to start_derivative_section is required
+ // because if a constant parameter block is encountered after the
+ // last non-constant block then current_derivative_section is incremented
+ // and would otherwise index an invalid position in
+ // start_derivative_section. Setting the final element to the total number
+ // of parameters means that this can only happen at most once in the loop
+ // below.
+ start_derivative_section.push_back(parameter_cursor);
+
+ // Evaluate all of the strides. Each stride is a chunk of the derivative to
+ // evaluate, typically some size proportional to the size of the SIMD
+ // registers of the CPU.
+ int num_strides = static_cast<int>(ceil(num_active_parameters /
+ static_cast<float>(Stride)));
+
+ int current_derivative_section = 0;
+ int current_derivative_section_cursor = 0;
+
+ for (int pass = 0; pass < num_strides; ++pass) {
+ // Set most of the jet components to zero, except for
+ // non-constant #Stride parameters.
+ const int initial_derivative_section = current_derivative_section;
+ const int initial_derivative_section_cursor =
+ current_derivative_section_cursor;
+
+ int active_parameter_count = 0;
+ parameter_cursor = 0;
+
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ for (int j = 0; j < parameter_block_sizes()[i];
+ ++j, parameter_cursor++) {
+ input_jets[parameter_cursor].v.setZero();
+ if (active_parameter_count < Stride &&
+ parameter_cursor >= (
+ start_derivative_section[current_derivative_section] +
+ current_derivative_section_cursor)) {
+ if (jacobians[i] != NULL) {
+ input_jets[parameter_cursor].v[active_parameter_count] = 1.0;
+ ++active_parameter_count;
+ ++current_derivative_section_cursor;
+ } else {
+ ++current_derivative_section;
+ current_derivative_section_cursor = 0;
+ }
+ }
+ }
+ }
+
+ if (!(*functor_)(&jet_parameters[0], &output_jets[0])) {
+ return false;
+ }
+
+ // Copy the pieces of the jacobians into their final place.
+ active_parameter_count = 0;
+
+ current_derivative_section = initial_derivative_section;
+ current_derivative_section_cursor = initial_derivative_section_cursor;
+
+ for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
+ for (int j = 0; j < parameter_block_sizes()[i];
+ ++j, parameter_cursor++) {
+ if (active_parameter_count < Stride &&
+ parameter_cursor >= (
+ start_derivative_section[current_derivative_section] +
+ current_derivative_section_cursor)) {
+ if (jacobians[i] != NULL) {
+ for (int k = 0; k < num_residuals(); ++k) {
+ jacobians[i][k * parameter_block_sizes()[i] + j] =
+ output_jets[k].v[active_parameter_count];
+ }
+ ++active_parameter_count;
+ ++current_derivative_section_cursor;
+ } else {
+ ++current_derivative_section;
+ current_derivative_section_cursor = 0;
+ }
+ }
+ }
+ }
+
+ // Only copy the residuals over once (even though we compute them on
+ // every loop).
+ if (pass == num_strides - 1) {
+ for (int k = 0; k < num_residuals(); ++k) {
+ residuals[k] = output_jets[k].a;
+ }
+ }
+ }
+ return true;
+ }
+
+ private:
+ internal::scoped_ptr<CostFunctor> functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h b/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h
new file mode 100644
index 00000000000..9339a503ea0
--- /dev/null
+++ b/extern/ceres/include/ceres/dynamic_cost_function_to_functor.h
@@ -0,0 +1,190 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// dgossow@google.com (David Gossow)
+//
+// DynamicCostFunctionToFunctor allows users to use CostFunction
+// objects in templated functors which are to be used for automatic
+// differentiation. It works similar to CostFunctionToFunctor, with the
+// difference that it allows you to wrap a cost function with dynamic numbers
+// of parameters and residuals.
+//
+// For example, let us assume that
+//
+// class IntrinsicProjection : public CostFunction {
+// public:
+// IntrinsicProjection(const double* observation);
+// virtual bool Evaluate(double const* const* parameters,
+// double* residuals,
+// double** jacobians) const;
+// };
+//
+// is a cost function that implements the projection of a point in its
+// local coordinate system onto its image plane and subtracts it from
+// the observed point projection. It can compute its residual and
+// either via analytic or numerical differentiation can compute its
+// jacobians. The intrinsics are passed in as parameters[0] and the point as
+// parameters[1].
+//
+// Now we would like to compose the action of this CostFunction with
+// the action of camera extrinsics, i.e., rotation and
+// translation. Say we have a templated function
+//
+// template<typename T>
+// void RotateAndTranslatePoint(double const* const* parameters,
+// double* residuals);
+//
+// Then we can now do the following,
+//
+// struct CameraProjection {
+// CameraProjection(const double* observation)
+// : intrinsic_projection_.(new IntrinsicProjection(observation)) {
+// }
+// template <typename T>
+// bool operator()(T const* const* parameters,
+// T* residual) const {
+// const T* rotation = parameters[0];
+// const T* translation = parameters[1];
+// const T* intrinsics = parameters[2];
+// const T* point = parameters[3];
+// T transformed_point[3];
+// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
+//
+// // Note that we call intrinsic_projection_, just like it was
+// // any other templated functor.
+// const T* projection_parameters[2];
+// projection_parameters[0] = intrinsics;
+// projection_parameters[1] = transformed_point;
+// return intrinsic_projection_(projection_parameters, residual);
+// }
+//
+// private:
+// DynamicCostFunctionToFunctor intrinsic_projection_;
+// };
+
+#ifndef CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
+#define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
+
+#include <numeric>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+
+class DynamicCostFunctionToFunctor {
+ public:
+ // Takes ownership of cost_function.
+ explicit DynamicCostFunctionToFunctor(CostFunction* cost_function)
+ : cost_function_(cost_function) {
+ CHECK_NOTNULL(cost_function);
+ }
+
+ bool operator()(double const* const* parameters, double* residuals) const {
+ return cost_function_->Evaluate(parameters, residuals, NULL);
+ }
+
+ template <typename JetT>
+ bool operator()(JetT const* const* inputs, JetT* output) const {
+ const std::vector<int32>& parameter_block_sizes =
+ cost_function_->parameter_block_sizes();
+ const int num_parameter_blocks = parameter_block_sizes.size();
+ const int num_residuals = cost_function_->num_residuals();
+ const int num_parameters = std::accumulate(parameter_block_sizes.begin(),
+ parameter_block_sizes.end(), 0);
+
+ internal::FixedArray<double> parameters(num_parameters);
+ internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
+ internal::FixedArray<double> jacobians(num_residuals * num_parameters);
+ internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
+ internal::FixedArray<double> residuals(num_residuals);
+
+ // Build a set of arrays to get the residuals and jacobians from
+ // the CostFunction wrapped by this functor.
+ double* parameter_ptr = parameters.get();
+ double* jacobian_ptr = jacobians.get();
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ parameter_blocks[i] = parameter_ptr;
+ jacobian_blocks[i] = jacobian_ptr;
+ for (int j = 0; j < parameter_block_sizes[i]; ++j) {
+ *parameter_ptr++ = inputs[i][j].a;
+ }
+ jacobian_ptr += num_residuals * parameter_block_sizes[i];
+ }
+
+ if (!cost_function_->Evaluate(parameter_blocks.get(),
+ residuals.get(),
+ jacobian_blocks.get())) {
+ return false;
+ }
+
+ // Now that we have the incoming Jets, which are carrying the
+ // partial derivatives of each of the inputs w.r.t to some other
+ // underlying parameters. The derivative of the outputs of the
+ // cost function w.r.t to the same underlying parameters can now
+ // be computed by applying the chain rule.
+ //
+ // d output[i] d output[i] d input[j]
+ // -------------- = sum_j ----------- * ------------
+ // d parameter[k] d input[j] d parameter[k]
+ //
+ // d input[j]
+ // -------------- = inputs[j], so
+ // d parameter[k]
+ //
+ // outputJet[i] = sum_k jacobian[i][k] * inputJet[k]
+ //
+ // The following loop, iterates over the residuals, computing one
+ // output jet at a time.
+ for (int i = 0; i < num_residuals; ++i) {
+ output[i].a = residuals[i];
+ output[i].v.setZero();
+
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ const int32 block_size = parameter_block_sizes[j];
+ for (int k = 0; k < parameter_block_sizes[j]; ++k) {
+ output[i].v +=
+ jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ internal::scoped_ptr<CostFunction> cost_function_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
diff --git a/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h b/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
new file mode 100644
index 00000000000..c852d57a3fc
--- /dev/null
+++ b/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
@@ -0,0 +1,205 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+// thadh@gmail.com (Thad Hughes)
+// tbennun@gmail.com (Tal Ben-Nun)
+//
+// This numeric diff implementation differs from the one found in
+// numeric_diff_cost_function.h by supporting numericdiff on cost
+// functions with variable numbers of parameters with variable
+// sizes. With the other implementation, all the sizes (both the
+// number of parameter blocks and the size of each block) must be
+// fixed at compile time.
+//
+// The functor API differs slightly from the API for fixed size
+// numeric diff; the expected interface for the cost functors is:
+//
+// struct MyCostFunctor {
+// bool operator()(double const* const* parameters, double* residuals) const {
+// // Use parameters[i] to access the i'th parameter block.
+// }
+// }
+//
+// Since the sizing of the parameters is done at runtime, you must
+// also specify the sizes after creating the
+// DynamicNumericDiffCostFunction. For example:
+//
+// DynamicAutoDiffCostFunction<MyCostFunctor, CENTRAL> cost_function(
+// new MyCostFunctor());
+// cost_function.AddParameterBlock(5);
+// cost_function.AddParameterBlock(10);
+// cost_function.SetNumResiduals(21);
+
+#ifndef CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
+
+#include <cmath>
+#include <numeric>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/numeric_diff.h"
+#include "ceres/numeric_diff_options.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+template <typename CostFunctor, NumericDiffMethodType method = CENTRAL>
+class DynamicNumericDiffCostFunction : public CostFunction {
+ public:
+ explicit DynamicNumericDiffCostFunction(
+ const CostFunctor* functor,
+ Ownership ownership = TAKE_OWNERSHIP,
+ const NumericDiffOptions& options = NumericDiffOptions())
+ : functor_(functor),
+ ownership_(ownership),
+ options_(options) {
+ }
+
+ // Deprecated. New users should avoid using this constructor. Instead, use the
+ // constructor with NumericDiffOptions.
+ DynamicNumericDiffCostFunction(
+ const CostFunctor* functor,
+ Ownership ownership,
+ double relative_step_size)
+ : functor_(functor),
+ ownership_(ownership),
+ options_() {
+ LOG(WARNING) << "This constructor is deprecated and will be removed in "
+ "a future version. Please use the NumericDiffOptions "
+ "constructor instead.";
+
+ options_.relative_step_size = relative_step_size;
+ }
+
+ virtual ~DynamicNumericDiffCostFunction() {
+ if (ownership_ != TAKE_OWNERSHIP) {
+ functor_.release();
+ }
+ }
+
+ void AddParameterBlock(int size) {
+ mutable_parameter_block_sizes()->push_back(size);
+ }
+
+ void SetNumResiduals(int num_residuals) {
+ set_num_residuals(num_residuals);
+ }
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ using internal::NumericDiff;
+ CHECK_GT(num_residuals(), 0)
+ << "You must call DynamicNumericDiffCostFunction::SetNumResiduals() "
+ << "before DynamicNumericDiffCostFunction::Evaluate().";
+
+ const std::vector<int32>& block_sizes = parameter_block_sizes();
+ CHECK(!block_sizes.empty())
+ << "You must call DynamicNumericDiffCostFunction::AddParameterBlock() "
+ << "before DynamicNumericDiffCostFunction::Evaluate().";
+
+ const bool status = EvaluateCostFunctor(parameters, residuals);
+ if (jacobians == NULL || !status) {
+ return status;
+ }
+
+ // Create local space for a copy of the parameters which will get mutated.
+ int parameters_size = accumulate(block_sizes.begin(), block_sizes.end(), 0);
+ std::vector<double> parameters_copy(parameters_size);
+ std::vector<double*> parameters_references_copy(block_sizes.size());
+ parameters_references_copy[0] = &parameters_copy[0];
+ for (int block = 1; block < block_sizes.size(); ++block) {
+ parameters_references_copy[block] = parameters_references_copy[block - 1]
+ + block_sizes[block - 1];
+ }
+
+ // Copy the parameters into the local temp space.
+ for (int block = 0; block < block_sizes.size(); ++block) {
+ memcpy(parameters_references_copy[block],
+ parameters[block],
+ block_sizes[block] * sizeof(*parameters[block]));
+ }
+
+ for (int block = 0; block < block_sizes.size(); ++block) {
+ if (jacobians[block] != NULL &&
+ !NumericDiff<CostFunctor, method, DYNAMIC,
+ DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC,
+ DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC, DYNAMIC,
+ DYNAMIC, DYNAMIC>::EvaluateJacobianForParameterBlock(
+ functor_.get(),
+ residuals,
+ options_,
+ this->num_residuals(),
+ block,
+ block_sizes[block],
+ &parameters_references_copy[0],
+ jacobians[block])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ bool EvaluateCostFunctor(double const* const* parameters,
+ double* residuals) const {
+ return EvaluateCostFunctorImpl(functor_.get(),
+ parameters,
+ residuals,
+ functor_.get());
+ }
+
+ // Helper templates to allow evaluation of a functor or a
+ // CostFunction.
+ bool EvaluateCostFunctorImpl(const CostFunctor* functor,
+ double const* const* parameters,
+ double* residuals,
+ const void* /* NOT USED */) const {
+ return (*functor)(parameters, residuals);
+ }
+
+ bool EvaluateCostFunctorImpl(const CostFunctor* functor,
+ double const* const* parameters,
+ double* residuals,
+ const CostFunction* /* NOT USED */) const {
+ return functor->Evaluate(parameters, residuals, NULL);
+ }
+
+ internal::scoped_ptr<const CostFunctor> functor_;
+ Ownership ownership_;
+ NumericDiffOptions options_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/fpclassify.h b/extern/ceres/include/ceres/fpclassify.h
new file mode 100644
index 00000000000..bc2dc90026c
--- /dev/null
+++ b/extern/ceres/include/ceres/fpclassify.h
@@ -0,0 +1,70 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Portable floating point classification. The names are picked such that they
+// do not collide with macros. For example, "isnan" in C99 is a macro and hence
+// does not respect namespaces.
+//
+// TODO(keir): Finish porting!
+
+#ifndef CERES_PUBLIC_FPCLASSIFY_H_
+#define CERES_PUBLIC_FPCLASSIFY_H_
+
+#if defined(_MSC_VER)
+#include <float.h>
+#endif
+
+#include <limits>
+
+namespace ceres {
+
+#if defined(_MSC_VER)
+
+inline bool IsFinite (double x) { return _finite(x) != 0; }
+inline bool IsInfinite(double x) { return _finite(x) == 0 && _isnan(x) == 0; }
+inline bool IsNaN (double x) { return _isnan(x) != 0; }
+inline bool IsNormal (double x) { // NOLINT
+ const int classification = _fpclass(x);
+ return (classification == _FPCLASS_NN || classification == _FPCLASS_PN);
+}
+
+# else
+
+// These definitions are for the normal Unix suspects.
+inline bool IsFinite (double x) { return std::isfinite(x); }
+inline bool IsInfinite(double x) { return std::isinf(x); }
+inline bool IsNaN (double x) { return std::isnan(x); }
+inline bool IsNormal (double x) { return std::isnormal(x); }
+
+#endif
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_FPCLASSIFY_H_
diff --git a/extern/ceres/include/ceres/gradient_checker.h b/extern/ceres/include/ceres/gradient_checker.h
new file mode 100644
index 00000000000..28304159b44
--- /dev/null
+++ b/extern/ceres/include/ceres/gradient_checker.h
@@ -0,0 +1,222 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+// Copyright 2007 Google Inc. All Rights Reserved.
+//
+// Author: wjr@google.com (William Rucklidge)
+//
+// This file contains a class that exercises a cost function, to make sure
+// that it is computing reasonable derivatives. It compares the Jacobians
+// computed by the cost function with those obtained by finite
+// differences.
+
+#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
+#define CERES_PUBLIC_GRADIENT_CHECKER_H_
+
+#include <cstddef>
+#include <algorithm>
+#include <vector>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/numeric_diff_cost_function.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// An object that exercises a cost function, to compare the answers that it
+// gives with derivatives estimated using finite differencing.
+//
+// The only likely usage of this is for testing.
+//
+// How to use: Fill in an array of pointers to parameter blocks for your
+// CostFunction, and then call Probe(). Check that the return value is
+// 'true'. See prober_test.cc for an example.
+//
+// This is templated similarly to NumericDiffCostFunction, as it internally
+// uses that.
+template <typename CostFunctionToProbe,
+ int M = 0, int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0>
+class GradientChecker {
+ public:
+ // Here we stash some results from the probe, for later
+ // inspection.
+ struct GradientCheckResults {
+ // Computed cost.
+ Vector cost;
+
+ // The sizes of these matrices are dictated by the cost function's
+ // parameter and residual block sizes. Each vector's length will
+ // term->parameter_block_sizes().size(), and each matrix is the
+ // Jacobian of the residual with respect to the corresponding parameter
+ // block.
+
+ // Derivatives as computed by the cost function.
+ std::vector<Matrix> term_jacobians;
+
+ // Derivatives as computed by finite differencing.
+ std::vector<Matrix> finite_difference_jacobians;
+
+ // Infinity-norm of term_jacobians - finite_difference_jacobians.
+ double error_jacobians;
+ };
+
+ // Checks the Jacobian computed by a cost function.
+ //
+ // probe_point: The parameter values at which to probe.
+ // error_tolerance: A threshold for the infinity-norm difference
+ // between the Jacobians. If the Jacobians differ by more than
+ // this amount, then the probe fails.
+ //
+ // term: The cost function to test. Not retained after this call returns.
+ //
+ // results: On return, the two Jacobians (and other information)
+ // will be stored here. May be NULL.
+ //
+ // Returns true if no problems are detected and the difference between the
+ // Jacobians is less than error_tolerance.
+ static bool Probe(double const* const* probe_point,
+ double error_tolerance,
+ CostFunctionToProbe *term,
+ GradientCheckResults* results) {
+ CHECK_NOTNULL(probe_point);
+ CHECK_NOTNULL(term);
+ LOG(INFO) << "-------------------- Starting Probe() --------------------";
+
+ // We need a GradientCheckeresults, whether or not they supplied one.
+ internal::scoped_ptr<GradientCheckResults> owned_results;
+ if (results == NULL) {
+ owned_results.reset(new GradientCheckResults);
+ results = owned_results.get();
+ }
+
+ // Do a consistency check between the term and the template parameters.
+ CHECK_EQ(M, term->num_residuals());
+ const int num_residuals = M;
+ const std::vector<int32>& block_sizes = term->parameter_block_sizes();
+ const int num_blocks = block_sizes.size();
+
+ CHECK_LE(num_blocks, 5) << "Unable to test functions that take more "
+ << "than 5 parameter blocks";
+ if (N0) {
+ CHECK_EQ(N0, block_sizes[0]);
+ CHECK_GE(num_blocks, 1);
+ } else {
+ CHECK_LT(num_blocks, 1);
+ }
+ if (N1) {
+ CHECK_EQ(N1, block_sizes[1]);
+ CHECK_GE(num_blocks, 2);
+ } else {
+ CHECK_LT(num_blocks, 2);
+ }
+ if (N2) {
+ CHECK_EQ(N2, block_sizes[2]);
+ CHECK_GE(num_blocks, 3);
+ } else {
+ CHECK_LT(num_blocks, 3);
+ }
+ if (N3) {
+ CHECK_EQ(N3, block_sizes[3]);
+ CHECK_GE(num_blocks, 4);
+ } else {
+ CHECK_LT(num_blocks, 4);
+ }
+ if (N4) {
+ CHECK_EQ(N4, block_sizes[4]);
+ CHECK_GE(num_blocks, 5);
+ } else {
+ CHECK_LT(num_blocks, 5);
+ }
+
+ results->term_jacobians.clear();
+ results->term_jacobians.resize(num_blocks);
+ results->finite_difference_jacobians.clear();
+ results->finite_difference_jacobians.resize(num_blocks);
+
+ internal::FixedArray<double*> term_jacobian_pointers(num_blocks);
+ internal::FixedArray<double*>
+ finite_difference_jacobian_pointers(num_blocks);
+ for (int i = 0; i < num_blocks; i++) {
+ results->term_jacobians[i].resize(num_residuals, block_sizes[i]);
+ term_jacobian_pointers[i] = results->term_jacobians[i].data();
+ results->finite_difference_jacobians[i].resize(
+ num_residuals, block_sizes[i]);
+ finite_difference_jacobian_pointers[i] =
+ results->finite_difference_jacobians[i].data();
+ }
+ results->cost.resize(num_residuals, 1);
+
+ CHECK(term->Evaluate(probe_point, results->cost.data(),
+ term_jacobian_pointers.get()));
+ NumericDiffCostFunction<CostFunctionToProbe, CENTRAL, M, N0, N1, N2, N3, N4>
+ numeric_term(term, DO_NOT_TAKE_OWNERSHIP);
+ CHECK(numeric_term.Evaluate(probe_point, results->cost.data(),
+ finite_difference_jacobian_pointers.get()));
+
+ results->error_jacobians = 0;
+ for (int i = 0; i < num_blocks; i++) {
+ Matrix jacobian_difference = results->term_jacobians[i] -
+ results->finite_difference_jacobians[i];
+ results->error_jacobians =
+ std::max(results->error_jacobians,
+ jacobian_difference.lpNorm<Eigen::Infinity>());
+ }
+
+ LOG(INFO) << "========== term-computed derivatives ==========";
+ for (int i = 0; i < num_blocks; i++) {
+ LOG(INFO) << "term_computed block " << i;
+ LOG(INFO) << "\n" << results->term_jacobians[i];
+ }
+
+ LOG(INFO) << "========== finite-difference derivatives ==========";
+ for (int i = 0; i < num_blocks; i++) {
+ LOG(INFO) << "finite_difference block " << i;
+ LOG(INFO) << "\n" << results->finite_difference_jacobians[i];
+ }
+
+ LOG(INFO) << "========== difference ==========";
+ for (int i = 0; i < num_blocks; i++) {
+ LOG(INFO) << "difference block " << i;
+ LOG(INFO) << (results->term_jacobians[i] -
+ results->finite_difference_jacobians[i]);
+ }
+
+ LOG(INFO) << "||difference|| = " << results->error_jacobians;
+
+ return results->error_jacobians < error_tolerance;
+ }
+
+ private:
+ CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_GRADIENT_CHECKER_H_
diff --git a/extern/ceres/include/ceres/gradient_problem.h b/extern/ceres/include/ceres/gradient_problem.h
new file mode 100644
index 00000000000..1226a4cd895
--- /dev/null
+++ b/extern/ceres/include/ceres/gradient_problem.h
@@ -0,0 +1,127 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_H_
+#define CERES_PUBLIC_GRADIENT_PROBLEM_H_
+
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/local_parameterization.h"
+
+namespace ceres {
+
+class FirstOrderFunction;
+
+// Instances of GradientProblem represent general non-linear
+// optimization problems that must be solved using just the value of
+// the objective function and its gradient. Unlike the Problem class,
+// which can only be used to model non-linear least squares problems,
+// instances of GradientProblem not restricted in the form of the
+// objective function.
+//
+// Structurally GradientProblem is a composition of a
+// FirstOrderFunction and optionally a LocalParameterization.
+//
+// The FirstOrderFunction is responsible for evaluating the cost and
+// gradient of the objective function.
+//
+// The LocalParameterization is responsible for going back and forth
+// between the ambient space and the local tangent space. (See
+// local_parameterization.h for more details). When a
+// LocalParameterization is not provided, then the tangent space is
+// assumed to coincide with the ambient Euclidean space that the
+// gradient vector lives in.
+//
+// Example usage:
+//
+// The following demonstrate the problem construction for Rosenbrock's function
+//
+// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+//
+// class Rosenbrock : public ceres::FirstOrderFunction {
+// public:
+// virtual ~Rosenbrock() {}
+//
+// virtual bool Evaluate(const double* parameters,
+// double* cost,
+// double* gradient) const {
+// const double x = parameters[0];
+// const double y = parameters[1];
+//
+// cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
+// if (gradient != NULL) {
+// gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
+// gradient[1] = 200.0 * (y - x * x);
+// }
+// return true;
+// };
+//
+// virtual int NumParameters() const { return 2; };
+// };
+//
+// ceres::GradientProblem problem(new Rosenbrock());
+class CERES_EXPORT GradientProblem {
+ public:
+ // Takes ownership of the function.
+ explicit GradientProblem(FirstOrderFunction* function);
+
+ // Takes ownership of the function and the parameterization.
+ GradientProblem(FirstOrderFunction* function,
+ LocalParameterization* parameterization);
+
+ int NumParameters() const;
+ int NumLocalParameters() const;
+
+ // This call is not thread safe.
+ bool Evaluate(const double* parameters, double* cost, double* gradient) const;
+ bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
+
+ private:
+ internal::scoped_ptr<FirstOrderFunction> function_;
+ internal::scoped_ptr<LocalParameterization> parameterization_;
+ internal::scoped_array<double> scratch_;
+};
+
+// A FirstOrderFunction object implements the evaluation of a function
+// and its gradient.
+class CERES_EXPORT FirstOrderFunction {
+ public:
+ virtual ~FirstOrderFunction() {}
+ // cost is never NULL. gradient may be null.
+ virtual bool Evaluate(const double* const parameters,
+ double* cost,
+ double* gradient) const = 0;
+ virtual int NumParameters() const = 0;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_GRADIENT_PROBLEM_H_
diff --git a/extern/ceres/include/ceres/gradient_problem_solver.h b/extern/ceres/include/ceres/gradient_problem_solver.h
new file mode 100644
index 00000000000..a7d0121ea0c
--- /dev/null
+++ b/extern/ceres/include/ceres/gradient_problem_solver.h
@@ -0,0 +1,357 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
+#define CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
+
+#include <cmath>
+#include <string>
+#include <vector>
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+class GradientProblem;
+
+class CERES_EXPORT GradientProblemSolver {
+ public:
+ virtual ~GradientProblemSolver();
+
+ // The options structure contains, not surprisingly, options that control how
+ // the solver operates. The defaults should be suitable for a wide range of
+ // problems; however, better performance is often obtainable with tweaking.
+ //
+ // The constants are defined inside types.h
+ struct CERES_EXPORT Options {
+ // Default constructor that sets up a generic sparse problem.
+ Options() {
+ line_search_direction_type = LBFGS;
+ line_search_type = WOLFE;
+ nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
+ max_lbfgs_rank = 20;
+ use_approximate_eigenvalue_bfgs_scaling = false;
+ line_search_interpolation_type = CUBIC;
+ min_line_search_step_size = 1e-9;
+ line_search_sufficient_function_decrease = 1e-4;
+ max_line_search_step_contraction = 1e-3;
+ min_line_search_step_contraction = 0.6;
+ max_num_line_search_step_size_iterations = 20;
+ max_num_line_search_direction_restarts = 5;
+ line_search_sufficient_curvature_decrease = 0.9;
+ max_line_search_step_expansion = 10.0;
+ max_num_iterations = 50;
+ max_solver_time_in_seconds = 1e9;
+ function_tolerance = 1e-6;
+ gradient_tolerance = 1e-10;
+ logging_type = PER_MINIMIZER_ITERATION;
+ minimizer_progress_to_stdout = false;
+ }
+
+ // Returns true if the options struct has a valid
+ // configuration. Returns false otherwise, and fills in *error
+ // with a message describing the problem.
+ bool IsValid(std::string* error) const;
+
+ // Minimizer options ----------------------------------------
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+
+ // The LBFGS hessian approximation is a low rank approximation to
+ // the inverse of the Hessian matrix. The rank of the
+ // approximation determines (linearly) the space and time
+ // complexity of using the approximation. Higher the rank, the
+ // better is the quality of the approximation. The increase in
+ // quality is however is bounded for a number of reasons.
+ //
+ // 1. The method only uses secant information and not actual
+ // derivatives.
+ //
+ // 2. The Hessian approximation is constrained to be positive
+ // definite.
+ //
+ // So increasing this rank to a large number will cost time and
+ // space complexity without the corresponding increase in solution
+ // quality. There are no hard and fast rules for choosing the
+ // maximum rank. The best choice usually requires some problem
+ // specific experimentation.
+ //
+ // For more theoretical and implementation details of the LBFGS
+ // method, please see:
+ //
+ // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
+ // Limited Storage". Mathematics of Computation 35 (151): 773–782.
+ int max_lbfgs_rank;
+
+ // As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
+ // the initial inverse Hessian approximation is taken to be the Identity.
+ // However, Oren showed that using instead I * \gamma, where \gamma is
+ // chosen to approximate an eigenvalue of the true inverse Hessian can
+ // result in improved convergence in a wide variety of cases. Setting
+ // use_approximate_eigenvalue_bfgs_scaling to true enables this scaling.
+ //
+ // It is important to note that approximate eigenvalue scaling does not
+ // always improve convergence, and that it can in fact significantly degrade
+ // performance for certain classes of problem, which is why it is disabled
+ // by default. In particular it can degrade performance when the
+ // sensitivity of the problem to different parameters varies significantly,
+ // as in this case a single scalar factor fails to capture this variation
+ // and detrimentally downscales parts of the jacobian approximation which
+ // correspond to low-sensitivity parameters. It can also reduce the
+ // robustness of the solution to errors in the jacobians.
+ //
+ // Oren S.S., Self-scaling variable metric (SSVM) algorithms
+ // Part II: Implementation and experiments, Management Science,
+ // 20(5), 863-874, 1974.
+ bool use_approximate_eigenvalue_bfgs_scaling;
+
+ // Degree of the polynomial used to approximate the objective
+ // function. Valid values are BISECTION, QUADRATIC and CUBIC.
+ //
+ // BISECTION corresponds to pure backtracking search with no
+ // interpolation.
+ LineSearchInterpolationType line_search_interpolation_type;
+
+ // If during the line search, the step_size falls below this
+ // value, it is truncated to zero.
+ double min_line_search_step_size;
+
+ // Line search parameters.
+
+ // Solving the line search problem exactly is computationally
+ // prohibitive. Fortunately, line search based optimization
+ // algorithms can still guarantee convergence if instead of an
+ // exact solution, the line search algorithm returns a solution
+ // which decreases the value of the objective function
+ // sufficiently. More precisely, we are looking for a step_size
+ // s.t.
+ //
+ // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
+ //
+ double line_search_sufficient_function_decrease;
+
+ // In each iteration of the line search,
+ //
+ // new_step_size >= max_line_search_step_contraction * step_size
+ //
+ // Note that by definition, for contraction:
+ //
+ // 0 < max_step_contraction < min_step_contraction < 1
+ //
+ double max_line_search_step_contraction;
+
+ // In each iteration of the line search,
+ //
+ // new_step_size <= min_line_search_step_contraction * step_size
+ //
+ // Note that by definition, for contraction:
+ //
+ // 0 < max_step_contraction < min_step_contraction < 1
+ //
+ double min_line_search_step_contraction;
+
+ // Maximum number of trial step size iterations during each line search,
+ // if a step size satisfying the search conditions cannot be found within
+ // this number of trials, the line search will terminate.
+ int max_num_line_search_step_size_iterations;
+
+ // Maximum number of restarts of the line search direction algorithm before
+ // terminating the optimization. Restarts of the line search direction
+ // algorithm occur when the current algorithm fails to produce a new descent
+ // direction. This typically indicates a numerical failure, or a breakdown
+ // in the validity of the approximations used.
+ int max_num_line_search_direction_restarts;
+
+ // The strong Wolfe conditions consist of the Armijo sufficient
+ // decrease condition, and an additional requirement that the
+ // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
+ // conditions) of the gradient along the search direction
+ // decreases sufficiently. Precisely, this second condition
+ // is that we seek a step_size s.t.
+ //
+ // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
+ //
+ // Where f() is the line search objective and f'() is the derivative
+ // of f w.r.t step_size (d f / d step_size).
+ double line_search_sufficient_curvature_decrease;
+
+ // During the bracketing phase of the Wolfe search, the step size is
+ // increased until either a point satisfying the Wolfe conditions is
+ // found, or an upper bound for a bracket containing a point satisfying
+ // the conditions is found. Precisely, at each iteration of the
+ // expansion:
+ //
+ // new_step_size <= max_step_expansion * step_size.
+ //
+ // By definition for expansion, max_step_expansion > 1.0.
+ double max_line_search_step_expansion;
+
+ // Maximum number of iterations for the minimizer to run for.
+ int max_num_iterations;
+
+ // Maximum time for which the minimizer should run for.
+ double max_solver_time_in_seconds;
+
+ // Minimizer terminates when
+ //
+ // (new_cost - old_cost) < function_tolerance * old_cost;
+ //
+ double function_tolerance;
+
+ // Minimizer terminates when
+ //
+ // max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
+ //
+ // This value should typically be 1e-4 * function_tolerance.
+ double gradient_tolerance;
+
+ // Logging options ---------------------------------------------------------
+
+ LoggingType logging_type;
+
+ // By default the Minimizer progress is logged to VLOG(1), which
+ // is sent to STDERR depending on the vlog level. If this flag is
+ // set to true, and logging_type is not SILENT, the logging output
+ // is sent to STDOUT.
+ bool minimizer_progress_to_stdout;
+
+ // Callbacks that are executed at the end of each iteration of the
+ // Minimizer. An iteration may terminate midway, either due to
+ // numerical failures or because one of the convergence tests has
+ // been satisfied. In this case none of the callbacks are
+ // executed.
+
+ // Callbacks are executed in the order that they are specified in
+ // this vector. By default, parameter blocks are updated only at
+ // the end of the optimization, i.e when the Minimizer
+ // terminates. This behaviour is controlled by
+ // update_state_every_variable. If the user wishes to have access
+ // to the update parameter blocks when his/her callbacks are
+ // executed, then set update_state_every_iteration to true.
+ //
+ // The solver does NOT take ownership of these pointers.
+ std::vector<IterationCallback*> callbacks;
+ };
+
+ struct CERES_EXPORT Summary {
+ Summary();
+
+ // A brief one line description of the state of the solver after
+ // termination.
+ std::string BriefReport() const;
+
+ // A full multiline description of the state of the solver after
+ // termination.
+ std::string FullReport() const;
+
+ bool IsSolutionUsable() const;
+
+ // Minimizer summary -------------------------------------------------
+ TerminationType termination_type;
+
+ // Reason why the solver terminated.
+ std::string message;
+
+ // Cost of the problem (value of the objective function) before
+ // the optimization.
+ double initial_cost;
+
+ // Cost of the problem (value of the objective function) after the
+ // optimization.
+ double final_cost;
+
+ // IterationSummary for each minimizer iteration in order.
+ std::vector<IterationSummary> iterations;
+
+ // Sum total of all time spent inside Ceres when Solve is called.
+ double total_time_in_seconds;
+
+ // Time (in seconds) spent evaluating the cost.
+ double cost_evaluation_time_in_seconds;
+
+ // Time (in seconds) spent evaluating the gradient.
+ double gradient_evaluation_time_in_seconds;
+
+ // Time (in seconds) spent minimizing the interpolating polynomial
+ // to compute the next candidate step size as part of a line search.
+ double line_search_polynomial_minimization_time_in_seconds;
+
+ // Number of parameters in the probem.
+ int num_parameters;
+
+ // Dimension of the tangent space of the problem.
+ int num_local_parameters;
+
+ // Type of line search direction used.
+ LineSearchDirectionType line_search_direction_type;
+
+ // Type of the line search algorithm used.
+ LineSearchType line_search_type;
+
+ // When performing line search, the degree of the polynomial used
+ // to approximate the objective function.
+ LineSearchInterpolationType line_search_interpolation_type;
+
+ // If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
+ // then this indicates the particular variant of non-linear
+ // conjugate gradient used.
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+
+ // If the type of the line search direction is LBFGS, then this
+ // indicates the rank of the Hessian approximation.
+ int max_lbfgs_rank;
+ };
+
+ // Once a least squares problem has been built, this function takes
+ // the problem and optimizes it based on the values of the options
+ // parameters. Upon return, a detailed summary of the work performed
+ // by the preprocessor, the non-linear minmizer and the linear
+ // solver are reported in the summary object.
+ virtual void Solve(const GradientProblemSolver::Options& options,
+ const GradientProblem& problem,
+ double* parameters,
+ GradientProblemSolver::Summary* summary);
+};
+
+// Helper function which avoids going through the interface.
+CERES_EXPORT void Solve(const GradientProblemSolver::Options& options,
+ const GradientProblem& problem,
+ double* parameters,
+ GradientProblemSolver::Summary* summary);
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
diff --git a/extern/ceres/include/ceres/internal/autodiff.h b/extern/ceres/include/ceres/internal/autodiff.h
new file mode 100644
index 00000000000..136152a36cd
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/autodiff.h
@@ -0,0 +1,317 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Computation of the Jacobian matrix for vector-valued functions of multiple
+// variables, using automatic differentiation based on the implementation of
+// dual numbers in jet.h. Before reading the rest of this file, it is adivsable
+// to read jet.h's header comment in detail.
+//
+// The helper wrapper AutoDiff::Differentiate() computes the jacobian of
+// functors with templated operator() taking this form:
+//
+// struct F {
+// template<typename T>
+// bool operator()(const T *x, const T *y, ..., T *z) {
+// // Compute z[] based on x[], y[], ...
+// // return true if computation succeeded, false otherwise.
+// }
+// };
+//
+// All inputs and outputs may be vector-valued.
+//
+// To understand how jets are used to compute the jacobian, a
+// picture may help. Consider a vector-valued function, F, returning 3
+// dimensions and taking a vector-valued parameter of 4 dimensions:
+//
+// y x
+// [ * ] F [ * ]
+// [ * ] <--- [ * ]
+// [ * ] [ * ]
+// [ * ]
+//
+// Similar to the 2-parameter example for f described in jet.h, computing the
+// jacobian dy/dx is done by substutiting a suitable jet object for x and all
+// intermediate steps of the computation of F. Since x is has 4 dimensions, use
+// a Jet<double, 4>.
+//
+// Before substituting a jet object for x, the dual components are set
+// appropriately for each dimension of x:
+//
+// y x
+// [ * | * * * * ] f [ * | 1 0 0 0 ] x0
+// [ * | * * * * ] <--- [ * | 0 1 0 0 ] x1
+// [ * | * * * * ] [ * | 0 0 1 0 ] x2
+// ---+--- [ * | 0 0 0 1 ] x3
+// | ^ ^ ^ ^
+// dy/dx | | | +----- infinitesimal for x3
+// | | +------- infinitesimal for x2
+// | +--------- infinitesimal for x1
+// +----------- infinitesimal for x0
+//
+// The reason to set the internal 4x4 submatrix to the identity is that we wish
+// to take the derivative of y separately with respect to each dimension of x.
+// Each column of the 4x4 identity is therefore for a single component of the
+// independent variable x.
+//
+// Then the jacobian of the mapping, dy/dx, is the 3x4 sub-matrix of the
+// extended y vector, indicated in the above diagram.
+//
+// Functors with multiple parameters
+// ---------------------------------
+// In practice, it is often convenient to use a function f of two or more
+// vector-valued parameters, for example, x[3] and z[6]. Unfortunately, the jet
+// framework is designed for a single-parameter vector-valued input. The wrapper
+// in this file addresses this issue adding support for functions with one or
+// more parameter vectors.
+//
+// To support multiple parameters, all the parameter vectors are concatenated
+// into one and treated as a single parameter vector, except that since the
+// functor expects different inputs, we need to construct the jets as if they
+// were part of a single parameter vector. The extended jets are passed
+// separately for each parameter.
+//
+// For example, consider a functor F taking two vector parameters, p[2] and
+// q[3], and producing an output y[4]:
+//
+// struct F {
+// template<typename T>
+// bool operator()(const T *p, const T *q, T *z) {
+// // ...
+// }
+// };
+//
+// In this case, the necessary jet type is Jet<double, 5>. Here is a
+// visualization of the jet objects in this case:
+//
+// Dual components for p ----+
+// |
+// -+-
+// y [ * | 1 0 | 0 0 0 ] --- p[0]
+// [ * | 0 1 | 0 0 0 ] --- p[1]
+// [ * | . . | + + + ] |
+// [ * | . . | + + + ] v
+// [ * | . . | + + + ] <--- F(p, q)
+// [ * | . . | + + + ] ^
+// ^^^ ^^^^^ |
+// dy/dp dy/dq [ * | 0 0 | 1 0 0 ] --- q[0]
+// [ * | 0 0 | 0 1 0 ] --- q[1]
+// [ * | 0 0 | 0 0 1 ] --- q[2]
+// --+--
+// |
+// Dual components for q --------------+
+//
+// where the 4x2 submatrix (marked with ".") and 4x3 submatrix (marked with "+"
+// of y in the above diagram are the derivatives of y with respect to p and q
+// respectively. This is how autodiff works for functors taking multiple vector
+// valued arguments (up to 6).
+//
+// Jacobian NULL pointers
+// ----------------------
+// In general, the functions below will accept NULL pointers for all or some of
+// the Jacobian parameters, meaning that those Jacobians will not be computed.
+
+#ifndef CERES_PUBLIC_INTERNAL_AUTODIFF_H_
+#define CERES_PUBLIC_INTERNAL_AUTODIFF_H_
+
+#include <stddef.h>
+
+#include "ceres/jet.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/variadic_evaluate.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Extends src by a 1st order pertubation for every dimension and puts it in
+// dst. The size of src is N. Since this is also used for perturbations in
+// blocked arrays, offset is used to shift which part of the jet the
+// perturbation occurs. This is used to set up the extended x augmented by an
+// identity matrix. The JetT type should be a Jet type, and T should be a
+// numeric type (e.g. double). For example,
+//
+// 0 1 2 3 4 5 6 7 8
+// dst[0] [ * | . . | 1 0 0 | . . . ]
+// dst[1] [ * | . . | 0 1 0 | . . . ]
+// dst[2] [ * | . . | 0 0 1 | . . . ]
+//
+// is what would get put in dst if N was 3, offset was 3, and the jet type JetT
+// was 8-dimensional.
+template <typename JetT, typename T, int N>
+inline void Make1stOrderPerturbation(int offset, const T* src, JetT* dst) {
+ DCHECK(src);
+ DCHECK(dst);
+ for (int j = 0; j < N; ++j) {
+ dst[j].a = src[j];
+ dst[j].v.setZero();
+ dst[j].v[offset + j] = T(1.0);
+ }
+}
+
+// Takes the 0th order part of src, assumed to be a Jet type, and puts it in
+// dst. This is used to pick out the "vector" part of the extended y.
+template <typename JetT, typename T>
+inline void Take0thOrderPart(int M, const JetT *src, T dst) {
+ DCHECK(src);
+ for (int i = 0; i < M; ++i) {
+ dst[i] = src[i].a;
+ }
+}
+
+// Takes N 1st order parts, starting at index N0, and puts them in the M x N
+// matrix 'dst'. This is used to pick out the "matrix" parts of the extended y.
+template <typename JetT, typename T, int N0, int N>
+inline void Take1stOrderPart(const int M, const JetT *src, T *dst) {
+ DCHECK(src);
+ DCHECK(dst);
+ for (int i = 0; i < M; ++i) {
+ Eigen::Map<Eigen::Matrix<T, N, 1> >(dst + N * i, N) =
+ src[i].v.template segment<N>(N0);
+ }
+}
+
+// This is in a struct because default template parameters on a
+// function are not supported in C++03 (though it is available in
+// C++0x). N0 through N5 are the dimension of the input arguments to
+// the user supplied functor.
+template <typename Functor, typename T,
+ int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
+ int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
+struct AutoDiff {
+ static bool Differentiate(const Functor& functor,
+ T const *const *parameters,
+ int num_outputs,
+ T *function_value,
+ T **jacobians) {
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ DCHECK_GT(num_outputs, 0);
+ DCHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) // NOLINT
+ << "Zero block cannot precede a non-zero block. Block sizes are "
+ << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
+
+ typedef Jet<T, N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9> JetT;
+ FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(
+ N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9 + num_outputs);
+
+ // These are the positions of the respective jets in the fixed array x.
+ const int jet0 = 0;
+ const int jet1 = N0;
+ const int jet2 = N0 + N1;
+ const int jet3 = N0 + N1 + N2;
+ const int jet4 = N0 + N1 + N2 + N3;
+ const int jet5 = N0 + N1 + N2 + N3 + N4;
+ const int jet6 = N0 + N1 + N2 + N3 + N4 + N5;
+ const int jet7 = N0 + N1 + N2 + N3 + N4 + N5 + N6;
+ const int jet8 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7;
+ const int jet9 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8;
+
+ const JetT *unpacked_parameters[10] = {
+ x.get() + jet0,
+ x.get() + jet1,
+ x.get() + jet2,
+ x.get() + jet3,
+ x.get() + jet4,
+ x.get() + jet5,
+ x.get() + jet6,
+ x.get() + jet7,
+ x.get() + jet8,
+ x.get() + jet9,
+ };
+
+ JetT* output = x.get() + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
+
+#define CERES_MAKE_1ST_ORDER_PERTURBATION(i) \
+ if (N ## i) { \
+ internal::Make1stOrderPerturbation<JetT, T, N ## i>( \
+ jet ## i, \
+ parameters[i], \
+ x.get() + jet ## i); \
+ }
+ CERES_MAKE_1ST_ORDER_PERTURBATION(0);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(1);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(2);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(3);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(4);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(5);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(6);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(7);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(8);
+ CERES_MAKE_1ST_ORDER_PERTURBATION(9);
+#undef CERES_MAKE_1ST_ORDER_PERTURBATION
+
+ if (!VariadicEvaluate<Functor, JetT,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
+ functor, unpacked_parameters, output)) {
+ return false;
+ }
+
+ internal::Take0thOrderPart(num_outputs, output, function_value);
+
+#define CERES_TAKE_1ST_ORDER_PERTURBATION(i) \
+ if (N ## i) { \
+ if (jacobians[i]) { \
+ internal::Take1stOrderPart<JetT, T, \
+ jet ## i, \
+ N ## i>(num_outputs, \
+ output, \
+ jacobians[i]); \
+ } \
+ }
+ CERES_TAKE_1ST_ORDER_PERTURBATION(0);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(1);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(2);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(3);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(4);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(5);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(6);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(7);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(8);
+ CERES_TAKE_1ST_ORDER_PERTURBATION(9);
+#undef CERES_TAKE_1ST_ORDER_PERTURBATION
+ return true;
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_AUTODIFF_H_
diff --git a/extern/ceres/include/ceres/internal/disable_warnings.h b/extern/ceres/include/ceres/internal/disable_warnings.h
new file mode 100644
index 00000000000..094124f7159
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/disable_warnings.h
@@ -0,0 +1,44 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// This file has the sole purpose to silence warnings when including Ceres.
+
+// This is not your usual header guard. The macro CERES_WARNINGS_DISABLED
+// shows up again in reenable_warnings.h.
+#ifndef CERES_WARNINGS_DISABLED
+#define CERES_WARNINGS_DISABLED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+// Disable the warning C4251 which is trigerred by stl classes in
+// Ceres' public interface. To quote MSDN: "C4251 can be ignored "
+// "if you are deriving from a type in the Standard C++ Library"
+#pragma warning( disable : 4251 )
+#endif
+
+#endif // CERES_WARNINGS_DISABLED
diff --git a/extern/ceres/include/ceres/internal/eigen.h b/extern/ceres/include/ceres/internal/eigen.h
new file mode 100644
index 00000000000..7138804ace4
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/eigen.h
@@ -0,0 +1,93 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_EIGEN_H_
+#define CERES_INTERNAL_EIGEN_H_
+
+#include "Eigen/Core"
+
+namespace ceres {
+
+typedef Eigen::Matrix<double, Eigen::Dynamic, 1> Vector;
+typedef Eigen::Matrix<double,
+ Eigen::Dynamic,
+ Eigen::Dynamic,
+ Eigen::RowMajor> Matrix;
+typedef Eigen::Map<Vector> VectorRef;
+typedef Eigen::Map<Matrix> MatrixRef;
+typedef Eigen::Map<const Vector> ConstVectorRef;
+typedef Eigen::Map<const Matrix> ConstMatrixRef;
+
+// Column major matrices for DenseSparseMatrix/DenseQRSolver
+typedef Eigen::Matrix<double,
+ Eigen::Dynamic,
+ Eigen::Dynamic,
+ Eigen::ColMajor> ColMajorMatrix;
+
+typedef Eigen::Map<ColMajorMatrix, 0,
+ Eigen::Stride<Eigen::Dynamic, 1> > ColMajorMatrixRef;
+
+typedef Eigen::Map<const ColMajorMatrix,
+ 0,
+ Eigen::Stride<Eigen::Dynamic, 1> > ConstColMajorMatrixRef;
+
+
+
+// C++ does not support templated typdefs, thus the need for this
+// struct so that we can support statically sized Matrix and Maps.
+template <int num_rows = Eigen::Dynamic, int num_cols = Eigen::Dynamic>
+struct EigenTypes {
+ typedef Eigen::Matrix <double, num_rows, num_cols, Eigen::RowMajor>
+ Matrix;
+
+ typedef Eigen::Map<
+ Eigen::Matrix<double, num_rows, num_cols, Eigen::RowMajor> >
+ MatrixRef;
+
+ typedef Eigen::Matrix <double, num_rows, 1>
+ Vector;
+
+ typedef Eigen::Map <
+ Eigen::Matrix<double, num_rows, 1> >
+ VectorRef;
+
+
+ typedef Eigen::Map<
+ const Eigen::Matrix<double, num_rows, num_cols, Eigen::RowMajor> >
+ ConstMatrixRef;
+
+ typedef Eigen::Map <
+ const Eigen::Matrix<double, num_rows, 1> >
+ ConstVectorRef;
+};
+
+} // namespace ceres
+
+#endif // CERES_INTERNAL_EIGEN_H_
diff --git a/extern/ceres/include/ceres/internal/fixed_array.h b/extern/ceres/include/ceres/internal/fixed_array.h
new file mode 100644
index 00000000000..387298c58d0
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/fixed_array.h
@@ -0,0 +1,191 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: rennie@google.com (Jeffrey Rennie)
+// Author: sanjay@google.com (Sanjay Ghemawat) -- renamed to FixedArray
+
+#ifndef CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
+#define CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
+
+#include <cstddef>
+#include "Eigen/Core"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/manual_constructor.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// A FixedArray<T> represents a non-resizable array of T where the
+// length of the array does not need to be a compile time constant.
+//
+// FixedArray allocates small arrays inline, and large arrays on
+// the heap. It is a good replacement for non-standard and deprecated
+// uses of alloca() and variable length arrays (a GCC extension).
+//
+// FixedArray keeps performance fast for small arrays, because it
+// avoids heap operations. It also helps reduce the chances of
+// accidentally overflowing your stack if large input is passed to
+// your function.
+//
+// Also, FixedArray is useful for writing portable code. Not all
+// compilers support arrays of dynamic size.
+
+// Most users should not specify an inline_elements argument and let
+// FixedArray<> automatically determine the number of elements
+// to store inline based on sizeof(T).
+//
+// If inline_elements is specified, the FixedArray<> implementation
+// will store arrays of length <= inline_elements inline.
+//
+// Finally note that unlike vector<T> FixedArray<T> will not zero-initialize
+// simple types like int, double, bool, etc.
+//
+// Non-POD types will be default-initialized just like regular vectors or
+// arrays.
+
+#if defined(_WIN64)
+ typedef __int64 ssize_t;
+#elif defined(_WIN32)
+ typedef __int32 ssize_t;
+#endif
+
+template <typename T, ssize_t inline_elements = -1>
+class FixedArray {
+ public:
+ // For playing nicely with stl:
+ typedef T value_type;
+ typedef T* iterator;
+ typedef T const* const_iterator;
+ typedef T& reference;
+ typedef T const& const_reference;
+ typedef T* pointer;
+ typedef std::ptrdiff_t difference_type;
+ typedef size_t size_type;
+
+ // REQUIRES: n >= 0
+ // Creates an array object that can store "n" elements.
+ //
+ // FixedArray<T> will not zero-initialiaze POD (simple) types like int,
+ // double, bool, etc.
+ // Non-POD types will be default-initialized just like regular vectors or
+ // arrays.
+ explicit FixedArray(size_type n);
+
+ // Releases any resources.
+ ~FixedArray();
+
+ // Returns the length of the array.
+ inline size_type size() const { return size_; }
+
+ // Returns the memory size of the array in bytes.
+ inline size_t memsize() const { return size_ * sizeof(T); }
+
+ // Returns a pointer to the underlying element array.
+ inline const T* get() const { return &array_[0].element; }
+ inline T* get() { return &array_[0].element; }
+
+ // REQUIRES: 0 <= i < size()
+ // Returns a reference to the "i"th element.
+ inline T& operator[](size_type i) {
+ DCHECK_LT(i, size_);
+ return array_[i].element;
+ }
+
+ // REQUIRES: 0 <= i < size()
+ // Returns a reference to the "i"th element.
+ inline const T& operator[](size_type i) const {
+ DCHECK_LT(i, size_);
+ return array_[i].element;
+ }
+
+ inline iterator begin() { return &array_[0].element; }
+ inline iterator end() { return &array_[size_].element; }
+
+ inline const_iterator begin() const { return &array_[0].element; }
+ inline const_iterator end() const { return &array_[size_].element; }
+
+ private:
+ // Container to hold elements of type T. This is necessary to handle
+ // the case where T is a a (C-style) array. The size of InnerContainer
+ // and T must be the same, otherwise callers' assumptions about use
+ // of this code will be broken.
+ struct InnerContainer {
+ T element;
+ };
+
+ // How many elements should we store inline?
+ // a. If not specified, use a default of 256 bytes (256 bytes
+ // seems small enough to not cause stack overflow or unnecessary
+ // stack pollution, while still allowing stack allocation for
+ // reasonably long character arrays.
+ // b. Never use 0 length arrays (not ISO C++)
+ static const size_type S1 = ((inline_elements < 0)
+ ? (256/sizeof(T)) : inline_elements);
+ static const size_type S2 = (S1 <= 0) ? 1 : S1;
+ static const size_type kInlineElements = S2;
+
+ size_type const size_;
+ InnerContainer* const array_;
+
+ // Allocate some space, not an array of elements of type T, so that we can
+ // skip calling the T constructors and destructors for space we never use.
+ ManualConstructor<InnerContainer> inline_space_[kInlineElements];
+};
+
+// Implementation details follow
+
+template <class T, ssize_t S>
+inline FixedArray<T, S>::FixedArray(typename FixedArray<T, S>::size_type n)
+ : size_(n),
+ array_((n <= kInlineElements
+ ? reinterpret_cast<InnerContainer*>(inline_space_)
+ : new InnerContainer[n])) {
+ // Construct only the elements actually used.
+ if (array_ == reinterpret_cast<InnerContainer*>(inline_space_)) {
+ for (size_t i = 0; i != size_; ++i) {
+ inline_space_[i].Init();
+ }
+ }
+}
+
+template <class T, ssize_t S>
+inline FixedArray<T, S>::~FixedArray() {
+ if (array_ != reinterpret_cast<InnerContainer*>(inline_space_)) {
+ delete[] array_;
+ } else {
+ for (size_t i = 0; i != size_; ++i) {
+ inline_space_[i].Destroy();
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
diff --git a/extern/ceres/include/ceres/internal/macros.h b/extern/ceres/include/ceres/internal/macros.h
new file mode 100644
index 00000000000..bebb965e25b
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/macros.h
@@ -0,0 +1,170 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//
+// Various Google-specific macros.
+//
+// This code is compiled directly on many platforms, including client
+// platforms like Windows, Mac, and embedded systems. Before making
+// any changes here, make sure that you're not breaking any platforms.
+
+#ifndef CERES_PUBLIC_INTERNAL_MACROS_H_
+#define CERES_PUBLIC_INTERNAL_MACROS_H_
+
+#include <cstddef> // For size_t.
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+//
+// For disallowing only assign or copy, write the code directly, but declare
+// the intend in a comment, for example:
+//
+// void operator=(const TypeName&); // _DISALLOW_ASSIGN
+
+// Note, that most uses of CERES_DISALLOW_ASSIGN and CERES_DISALLOW_COPY
+// are broken semantically, one should either use disallow both or
+// neither. Try to avoid these in new code.
+#define CERES_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ CERES_DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example. If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function. In these rare
+// cases, you have to use the unsafe ARRAYSIZE() macro below. This is
+// due to a limitation in C++'s template system. The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+
+// That gcc wants both of these prototypes seems mysterious. VC, for
+// its part, can't decide which to use (another mystery). Matching of
+// template overloads: the final frontier.
+#ifndef _WIN32
+template <typename T, size_t N>
+char (&ArraySizeHelper(const T (&array)[N]))[N];
+#endif
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// ARRAYSIZE performs essentially the same calculation as arraysize,
+// but can be used on anonymous types or types defined inside
+// functions. It's less safe than arraysize as it accepts some
+// (although not all) pointers. Therefore, you should use arraysize
+// whenever possible.
+//
+// The expression ARRAYSIZE(a) is a compile-time constant of type
+// size_t.
+//
+// ARRAYSIZE catches a few type errors. If you see a compiler error
+//
+// "warning: division by zero in ..."
+//
+// when using ARRAYSIZE, you are (wrongfully) giving it a pointer.
+// You should only use ARRAYSIZE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element). If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array. Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size. Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+//
+// Kudos to Jorg Brown for this simple and elegant implementation.
+//
+// - wan 2005-11-16
+//
+// Starting with Visual C++ 2005, WinNT.h includes ARRAYSIZE. However,
+// the definition comes from the over-broad windows.h header that
+// introduces a macro, ERROR, that conflicts with the logging framework
+// that Ceres uses. Instead, rename ARRAYSIZE to CERES_ARRAYSIZE.
+#define CERES_ARRAYSIZE(a) \
+ ((sizeof(a) / sizeof(*(a))) / \
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+// Tell the compiler to warn about unused return values for functions
+// declared with this macro. The macro should be used on function
+// declarations following the argument list:
+//
+// Sprocket* AllocateSprocket() MUST_USE_RESULT;
+//
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
+ && !defined(COMPILER_ICC)
+#define CERES_MUST_USE_RESULT __attribute__ ((warn_unused_result))
+#else
+#define CERES_MUST_USE_RESULT
+#endif
+
+// Platform independent macros to get aligned memory allocations.
+// For example
+//
+// MyFoo my_foo CERES_ALIGN_ATTRIBUTE(16);
+//
+// Gives us an instance of MyFoo which is aligned at a 16 byte
+// boundary.
+#if defined(_MSC_VER)
+#define CERES_ALIGN_ATTRIBUTE(n) __declspec(align(n))
+#define CERES_ALIGN_OF(T) __alignof(T)
+#elif defined(__GNUC__)
+#define CERES_ALIGN_ATTRIBUTE(n) __attribute__((aligned(n)))
+#define CERES_ALIGN_OF(T) __alignof(T)
+#endif
+
+#endif // CERES_PUBLIC_INTERNAL_MACROS_H_
diff --git a/extern/ceres/include/ceres/internal/manual_constructor.h b/extern/ceres/include/ceres/internal/manual_constructor.h
new file mode 100644
index 00000000000..0d7633cef83
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/manual_constructor.h
@@ -0,0 +1,208 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: kenton@google.com (Kenton Varda)
+//
+// ManualConstructor statically-allocates space in which to store some
+// object, but does not initialize it. You can then call the constructor
+// and destructor for the object yourself as you see fit. This is useful
+// for memory management optimizations, where you want to initialize and
+// destroy an object multiple times but only allocate it once.
+//
+// (When I say ManualConstructor statically allocates space, I mean that
+// the ManualConstructor object itself is forced to be the right size.)
+
+#ifndef CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
+#define CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
+
+#include <new>
+
+namespace ceres {
+namespace internal {
+
+// ------- Define CERES_ALIGNED_CHAR_ARRAY --------------------------------
+
+#ifndef CERES_ALIGNED_CHAR_ARRAY
+
+// Because MSVC and older GCCs require that the argument to their alignment
+// construct to be a literal constant integer, we use a template instantiated
+// at all the possible powers of two.
+template<int alignment, int size> struct AlignType { };
+template<int size> struct AlignType<0, size> { typedef char result[size]; };
+
+#if !defined(CERES_ALIGN_ATTRIBUTE)
+#define CERES_ALIGNED_CHAR_ARRAY you_must_define_CERES_ALIGNED_CHAR_ARRAY_for_your_compiler
+#else // !defined(CERES_ALIGN_ATTRIBUTE)
+
+#define CERES_ALIGN_TYPE_TEMPLATE(X) \
+ template<int size> struct AlignType<X, size> { \
+ typedef CERES_ALIGN_ATTRIBUTE(X) char result[size]; \
+ }
+
+CERES_ALIGN_TYPE_TEMPLATE(1);
+CERES_ALIGN_TYPE_TEMPLATE(2);
+CERES_ALIGN_TYPE_TEMPLATE(4);
+CERES_ALIGN_TYPE_TEMPLATE(8);
+CERES_ALIGN_TYPE_TEMPLATE(16);
+CERES_ALIGN_TYPE_TEMPLATE(32);
+CERES_ALIGN_TYPE_TEMPLATE(64);
+CERES_ALIGN_TYPE_TEMPLATE(128);
+CERES_ALIGN_TYPE_TEMPLATE(256);
+CERES_ALIGN_TYPE_TEMPLATE(512);
+CERES_ALIGN_TYPE_TEMPLATE(1024);
+CERES_ALIGN_TYPE_TEMPLATE(2048);
+CERES_ALIGN_TYPE_TEMPLATE(4096);
+CERES_ALIGN_TYPE_TEMPLATE(8192);
+// Any larger and MSVC++ will complain.
+
+#undef CERES_ALIGN_TYPE_TEMPLATE
+
+#define CERES_ALIGNED_CHAR_ARRAY(T, Size) \
+ typename AlignType<CERES_ALIGN_OF(T), sizeof(T) * Size>::result
+
+#endif // !defined(CERES_ALIGN_ATTRIBUTE)
+
+#endif // CERES_ALIGNED_CHAR_ARRAY
+
+template <typename Type>
+class ManualConstructor {
+ public:
+ // No constructor or destructor because one of the most useful uses of
+ // this class is as part of a union, and members of a union cannot have
+ // constructors or destructors. And, anyway, the whole point of this
+ // class is to bypass these.
+
+ inline Type* get() {
+ return reinterpret_cast<Type*>(space_);
+ }
+ inline const Type* get() const {
+ return reinterpret_cast<const Type*>(space_);
+ }
+
+ inline Type* operator->() { return get(); }
+ inline const Type* operator->() const { return get(); }
+
+ inline Type& operator*() { return *get(); }
+ inline const Type& operator*() const { return *get(); }
+
+ // This is needed to get around the strict aliasing warning GCC generates.
+ inline void* space() {
+ return reinterpret_cast<void*>(space_);
+ }
+
+ // You can pass up to four constructor arguments as arguments of Init().
+ inline void Init() {
+ new(space()) Type;
+ }
+
+ template <typename T1>
+ inline void Init(const T1& p1) {
+ new(space()) Type(p1);
+ }
+
+ template <typename T1, typename T2>
+ inline void Init(const T1& p1, const T2& p2) {
+ new(space()) Type(p1, p2);
+ }
+
+ template <typename T1, typename T2, typename T3>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3) {
+ new(space()) Type(p1, p2, p3);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
+ new(space()) Type(p1, p2, p3, p4);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5) {
+ new(space()) Type(p1, p2, p3, p4, p5);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5, const T6& p6) {
+ new(space()) Type(p1, p2, p3, p4, p5, p6);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5, const T6& p6, const T7& p7) {
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5, const T6& p6, const T7& p7, const T8& p8,
+ const T9& p9) {
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5, const T6& p6, const T7& p7, const T8& p8,
+ const T9& p9, const T10& p10) {
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+ inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
+ const T5& p5, const T6& p6, const T7& p7, const T8& p8,
+ const T9& p9, const T10& p10, const T11& p11) {
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
+ }
+
+ inline void Destroy() {
+ get()->~Type();
+ }
+
+ private:
+ CERES_ALIGNED_CHAR_ARRAY(Type, 1) space_;
+};
+
+#undef CERES_ALIGNED_CHAR_ARRAY
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
diff --git a/extern/ceres/include/ceres/internal/numeric_diff.h b/extern/ceres/include/ceres/internal/numeric_diff.h
new file mode 100644
index 00000000000..11e8275b1d3
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/numeric_diff.h
@@ -0,0 +1,446 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// mierle@gmail.com (Keir Mierle)
+// tbennun@gmail.com (Tal Ben-Nun)
+//
+// Finite differencing routines used by NumericDiffCostFunction.
+
+#ifndef CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
+#define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
+
+#include <cstring>
+
+#include "Eigen/Dense"
+#include "Eigen/StdVector"
+#include "ceres/cost_function.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/variadic_evaluate.h"
+#include "ceres/numeric_diff_options.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+
+namespace ceres {
+namespace internal {
+
+// Helper templates that allow evaluation of a variadic functor or a
+// CostFunction object.
+template <typename CostFunctor,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9 >
+bool EvaluateImpl(const CostFunctor* functor,
+ double const* const* parameters,
+ double* residuals,
+ const void* /* NOT USED */) {
+ return VariadicEvaluate<CostFunctor,
+ double,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
+ *functor,
+ parameters,
+ residuals);
+}
+
+template <typename CostFunctor,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9 >
+bool EvaluateImpl(const CostFunctor* functor,
+ double const* const* parameters,
+ double* residuals,
+ const CostFunction* /* NOT USED */) {
+ return functor->Evaluate(parameters, residuals, NULL);
+}
+
+// This is split from the main class because C++ doesn't allow partial template
+// specializations for member functions. The alternative is to repeat the main
+// class for differing numbers of parameters, which is also unfortunate.
+template <typename CostFunctor,
+ NumericDiffMethodType kMethod,
+ int kNumResiduals,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9,
+ int kParameterBlock,
+ int kParameterBlockSize>
+struct NumericDiff {
+ // Mutates parameters but must restore them before return.
+ static bool EvaluateJacobianForParameterBlock(
+ const CostFunctor* functor,
+ const double* residuals_at_eval_point,
+ const NumericDiffOptions& options,
+ int num_residuals,
+ int parameter_block_index,
+ int parameter_block_size,
+ double **parameters,
+ double *jacobian) {
+ using Eigen::Map;
+ using Eigen::Matrix;
+ using Eigen::RowMajor;
+ using Eigen::ColMajor;
+
+ const int num_residuals_internal =
+ (kNumResiduals != ceres::DYNAMIC ? kNumResiduals : num_residuals);
+ const int parameter_block_index_internal =
+ (kParameterBlock != ceres::DYNAMIC ? kParameterBlock :
+ parameter_block_index);
+ const int parameter_block_size_internal =
+ (kParameterBlockSize != ceres::DYNAMIC ? kParameterBlockSize :
+ parameter_block_size);
+
+ typedef Matrix<double, kNumResiduals, 1> ResidualVector;
+ typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+
+ // The convoluted reasoning for choosing the Row/Column major
+ // ordering of the matrix is an artifact of the restrictions in
+ // Eigen that prevent it from creating RowMajor matrices with a
+ // single column. In these cases, we ask for a ColMajor matrix.
+ typedef Matrix<double,
+ kNumResiduals,
+ kParameterBlockSize,
+ (kParameterBlockSize == 1) ? ColMajor : RowMajor>
+ JacobianMatrix;
+
+ Map<JacobianMatrix> parameter_jacobian(jacobian,
+ num_residuals_internal,
+ parameter_block_size_internal);
+
+ Map<ParameterVector> x_plus_delta(
+ parameters[parameter_block_index_internal],
+ parameter_block_size_internal);
+ ParameterVector x(x_plus_delta);
+ ParameterVector step_size = x.array().abs() *
+ ((kMethod == RIDDERS) ? options.ridders_relative_initial_step_size :
+ options.relative_step_size);
+
+ // It is not a good idea to make the step size arbitrarily
+ // small. This will lead to problems with round off and numerical
+ // instability when dividing by the step size. The general
+ // recommendation is to not go down below sqrt(epsilon).
+ double min_step_size = std::sqrt(std::numeric_limits<double>::epsilon());
+
+ // For Ridders' method, the initial step size is required to be large,
+ // thus ridders_relative_initial_step_size is used.
+ if (kMethod == RIDDERS) {
+ min_step_size = std::max(min_step_size,
+ options.ridders_relative_initial_step_size);
+ }
+
+ // For each parameter in the parameter block, use finite differences to
+ // compute the derivative for that parameter.
+ FixedArray<double> temp_residual_array(num_residuals_internal);
+ FixedArray<double> residual_array(num_residuals_internal);
+ Map<ResidualVector> residuals(residual_array.get(),
+ num_residuals_internal);
+
+ for (int j = 0; j < parameter_block_size_internal; ++j) {
+ const double delta = std::max(min_step_size, step_size(j));
+
+ if (kMethod == RIDDERS) {
+ if (!EvaluateRiddersJacobianColumn(functor, j, delta,
+ options,
+ num_residuals_internal,
+ parameter_block_size_internal,
+ x.data(),
+ residuals_at_eval_point,
+ parameters,
+ x_plus_delta.data(),
+ temp_residual_array.get(),
+ residual_array.get())) {
+ return false;
+ }
+ } else {
+ if (!EvaluateJacobianColumn(functor, j, delta,
+ num_residuals_internal,
+ parameter_block_size_internal,
+ x.data(),
+ residuals_at_eval_point,
+ parameters,
+ x_plus_delta.data(),
+ temp_residual_array.get(),
+ residual_array.get())) {
+ return false;
+ }
+ }
+
+ parameter_jacobian.col(j).matrix() = residuals;
+ }
+ return true;
+ }
+
+ static bool EvaluateJacobianColumn(const CostFunctor* functor,
+ int parameter_index,
+ double delta,
+ int num_residuals,
+ int parameter_block_size,
+ const double* x_ptr,
+ const double* residuals_at_eval_point,
+ double** parameters,
+ double* x_plus_delta_ptr,
+ double* temp_residuals_ptr,
+ double* residuals_ptr) {
+ using Eigen::Map;
+ using Eigen::Matrix;
+
+ typedef Matrix<double, kNumResiduals, 1> ResidualVector;
+ typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+
+ Map<const ParameterVector> x(x_ptr, parameter_block_size);
+ Map<ParameterVector> x_plus_delta(x_plus_delta_ptr,
+ parameter_block_size);
+
+ Map<ResidualVector> residuals(residuals_ptr, num_residuals);
+ Map<ResidualVector> temp_residuals(temp_residuals_ptr, num_residuals);
+
+ // Mutate 1 element at a time and then restore.
+ x_plus_delta(parameter_index) = x(parameter_index) + delta;
+
+ if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor, parameters, residuals.data(), functor)) {
+ return false;
+ }
+
+ // Compute this column of the jacobian in 3 steps:
+ // 1. Store residuals for the forward part.
+ // 2. Subtract residuals for the backward (or 0) part.
+ // 3. Divide out the run.
+ double one_over_delta = 1.0 / delta;
+ if (kMethod == CENTRAL || kMethod == RIDDERS) {
+ // Compute the function on the other side of x(parameter_index).
+ x_plus_delta(parameter_index) = x(parameter_index) - delta;
+
+ if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor, parameters, temp_residuals.data(), functor)) {
+ return false;
+ }
+
+ residuals -= temp_residuals;
+ one_over_delta /= 2;
+ } else {
+ // Forward difference only; reuse existing residuals evaluation.
+ residuals -=
+ Map<const ResidualVector>(residuals_at_eval_point,
+ num_residuals);
+ }
+
+ // Restore x_plus_delta.
+ x_plus_delta(parameter_index) = x(parameter_index);
+
+ // Divide out the run to get slope.
+ residuals *= one_over_delta;
+
+ return true;
+ }
+
+ // This numeric difference implementation uses adaptive differentiation
+ // on the parameters to obtain the Jacobian matrix. The adaptive algorithm
+ // is based on Ridders' method for adaptive differentiation, which creates
+ // a Romberg tableau from varying step sizes and extrapolates the
+ // intermediate results to obtain the current computational error.
+ //
+ // References:
+ // C.J.F. Ridders, Accurate computation of F'(x) and F'(x) F"(x), Advances
+ // in Engineering Software (1978), Volume 4, Issue 2, April 1982,
+ // Pages 75-76, ISSN 0141-1195,
+ // http://dx.doi.org/10.1016/S0141-1195(82)80057-0.
+ static bool EvaluateRiddersJacobianColumn(
+ const CostFunctor* functor,
+ int parameter_index,
+ double delta,
+ const NumericDiffOptions& options,
+ int num_residuals,
+ int parameter_block_size,
+ const double* x_ptr,
+ const double* residuals_at_eval_point,
+ double** parameters,
+ double* x_plus_delta_ptr,
+ double* temp_residuals_ptr,
+ double* residuals_ptr) {
+ using Eigen::Map;
+ using Eigen::Matrix;
+ using Eigen::aligned_allocator;
+
+ typedef Matrix<double, kNumResiduals, 1> ResidualVector;
+ typedef Matrix<double, kNumResiduals, Eigen::Dynamic> ResidualCandidateMatrix;
+ typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+
+ Map<const ParameterVector> x(x_ptr, parameter_block_size);
+ Map<ParameterVector> x_plus_delta(x_plus_delta_ptr,
+ parameter_block_size);
+
+ Map<ResidualVector> residuals(residuals_ptr, num_residuals);
+ Map<ResidualVector> temp_residuals(temp_residuals_ptr, num_residuals);
+
+ // In order for the algorithm to converge, the step size should be
+ // initialized to a value that is large enough to produce a significant
+ // change in the function.
+ // As the derivative is estimated, the step size decreases.
+ // By default, the step sizes are chosen so that the middle column
+ // of the Romberg tableau uses the input delta.
+ double current_step_size = delta *
+ pow(options.ridders_step_shrink_factor,
+ options.max_num_ridders_extrapolations / 2);
+
+ // Double-buffering temporary differential candidate vectors
+ // from previous step size.
+ ResidualCandidateMatrix stepsize_candidates_a(
+ num_residuals,
+ options.max_num_ridders_extrapolations);
+ ResidualCandidateMatrix stepsize_candidates_b(
+ num_residuals,
+ options.max_num_ridders_extrapolations);
+ ResidualCandidateMatrix* current_candidates = &stepsize_candidates_a;
+ ResidualCandidateMatrix* previous_candidates = &stepsize_candidates_b;
+
+ // Represents the computational error of the derivative. This variable is
+ // initially set to a large value, and is set to the difference between
+ // current and previous finite difference extrapolations.
+ // norm_error is supposed to decrease as the finite difference tableau
+ // generation progresses, serving both as an estimate for differentiation
+ // error and as a measure of differentiation numerical stability.
+ double norm_error = std::numeric_limits<double>::max();
+
+ // Loop over decreasing step sizes until:
+ // 1. Error is smaller than a given value (ridders_epsilon),
+ // 2. Maximal order of extrapolation reached, or
+ // 3. Extrapolation becomes numerically unstable.
+ for (int i = 0; i < options.max_num_ridders_extrapolations; ++i) {
+ // Compute the numerical derivative at this step size.
+ if (!EvaluateJacobianColumn(functor, parameter_index, current_step_size,
+ num_residuals,
+ parameter_block_size,
+ x.data(),
+ residuals_at_eval_point,
+ parameters,
+ x_plus_delta.data(),
+ temp_residuals.data(),
+ current_candidates->col(0).data())) {
+ // Something went wrong; bail.
+ return false;
+ }
+
+ // Store initial results.
+ if (i == 0) {
+ residuals = current_candidates->col(0);
+ }
+
+ // Shrink differentiation step size.
+ current_step_size /= options.ridders_step_shrink_factor;
+
+ // Extrapolation factor for Richardson acceleration method (see below).
+ double richardson_factor = options.ridders_step_shrink_factor *
+ options.ridders_step_shrink_factor;
+ for (int k = 1; k <= i; ++k) {
+ // Extrapolate the various orders of finite differences using
+ // the Richardson acceleration method.
+ current_candidates->col(k) =
+ (richardson_factor * current_candidates->col(k - 1) -
+ previous_candidates->col(k - 1)) / (richardson_factor - 1.0);
+
+ richardson_factor *= options.ridders_step_shrink_factor *
+ options.ridders_step_shrink_factor;
+
+ // Compute the difference between the previous value and the current.
+ double candidate_error = std::max(
+ (current_candidates->col(k) -
+ current_candidates->col(k - 1)).norm(),
+ (current_candidates->col(k) -
+ previous_candidates->col(k - 1)).norm());
+
+ // If the error has decreased, update results.
+ if (candidate_error <= norm_error) {
+ norm_error = candidate_error;
+ residuals = current_candidates->col(k);
+
+ // If the error is small enough, stop.
+ if (norm_error < options.ridders_epsilon) {
+ break;
+ }
+ }
+ }
+
+ // After breaking out of the inner loop, declare convergence.
+ if (norm_error < options.ridders_epsilon) {
+ break;
+ }
+
+ // Check to see if the current gradient estimate is numerically unstable.
+ // If so, bail out and return the last stable result.
+ if (i > 0) {
+ double tableau_error = (current_candidates->col(i) -
+ previous_candidates->col(i - 1)).norm();
+
+ // Compare current error to the chosen candidate's error.
+ if (tableau_error >= 2 * norm_error) {
+ break;
+ }
+ }
+
+ std::swap(current_candidates, previous_candidates);
+ }
+ return true;
+ }
+};
+
+template <typename CostFunctor,
+ NumericDiffMethodType kMethod,
+ int kNumResiduals,
+ int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9,
+ int kParameterBlock>
+struct NumericDiff<CostFunctor, kMethod, kNumResiduals,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,
+ kParameterBlock, 0> {
+ // Mutates parameters but must restore them before return.
+ static bool EvaluateJacobianForParameterBlock(
+ const CostFunctor* functor,
+ const double* residuals_at_eval_point,
+ const NumericDiffOptions& options,
+ const int num_residuals,
+ const int parameter_block_index,
+ const int parameter_block_size,
+ double **parameters,
+ double *jacobian) {
+ // Silence unused parameter compiler warnings.
+ (void)functor;
+ (void)residuals_at_eval_point;
+ (void)options;
+ (void)num_residuals;
+ (void)parameter_block_index;
+ (void)parameter_block_size;
+ (void)parameters;
+ (void)jacobian;
+ LOG(FATAL) << "Control should never reach here.";
+ return true;
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
diff --git a/extern/ceres/include/ceres/internal/port.h b/extern/ceres/include/ceres/internal/port.h
new file mode 100644
index 00000000000..e57049dde4b
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/port.h
@@ -0,0 +1,76 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_PUBLIC_INTERNAL_PORT_H_
+#define CERES_PUBLIC_INTERNAL_PORT_H_
+
+// This file needs to compile as c code.
+#ifdef __cplusplus
+
+#include "ceres/internal/config.h"
+
+#if defined(CERES_TR1_MEMORY_HEADER)
+#include <tr1/memory>
+#else
+#include <memory>
+#endif
+
+namespace ceres {
+
+#if defined(CERES_TR1_SHARED_PTR)
+using std::tr1::shared_ptr;
+#else
+using std::shared_ptr;
+#endif
+
+} // namespace ceres
+
+#endif // __cplusplus
+
+// A macro to signal which functions and classes are exported when
+// building a DLL with MSVC.
+//
+// Note that the ordering here is important, CERES_BUILDING_SHARED_LIBRARY
+// is only defined locally when Ceres is compiled, it is never exported to
+// users. However, in order that we do not have to configure config.h
+// separately for building vs installing, if we are using MSVC and building
+// a shared library, then both CERES_BUILDING_SHARED_LIBRARY and
+// CERES_USING_SHARED_LIBRARY will be defined when Ceres is compiled.
+// Hence it is important that the check for CERES_BUILDING_SHARED_LIBRARY
+// happens first.
+#if defined(_MSC_VER) && defined(CERES_BUILDING_SHARED_LIBRARY)
+# define CERES_EXPORT __declspec(dllexport)
+#elif defined(_MSC_VER) && defined(CERES_USING_SHARED_LIBRARY)
+# define CERES_EXPORT __declspec(dllimport)
+#else
+# define CERES_EXPORT
+#endif
+
+#endif // CERES_PUBLIC_INTERNAL_PORT_H_
diff --git a/extern/ceres/include/ceres/internal/reenable_warnings.h b/extern/ceres/include/ceres/internal/reenable_warnings.h
new file mode 100644
index 00000000000..7e410259d64
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/reenable_warnings.h
@@ -0,0 +1,38 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+// This is not your usual header guard. See disable_warnings.h
+#ifdef CERES_WARNINGS_DISABLED
+#undef CERES_WARNINGS_DISABLED
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif // CERES_WARNINGS_DISABLED
diff --git a/extern/ceres/include/ceres/internal/scoped_ptr.h b/extern/ceres/include/ceres/internal/scoped_ptr.h
new file mode 100644
index 00000000000..fa0ac25a031
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/scoped_ptr.h
@@ -0,0 +1,310 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: jorg@google.com (Jorg Brown)
+//
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class, and its closely-related brethren,
+// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
+
+#ifndef CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
+#define CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include <cstddef>
+#include <algorithm>
+
+namespace ceres {
+namespace internal {
+
+template <class C> class scoped_ptr;
+template <class C, class Free> class scoped_ptr_malloc;
+template <class C> class scoped_array;
+
+template <class C>
+scoped_ptr<C> make_scoped_ptr(C *);
+
+// A scoped_ptr<T> is like a T*, except that the destructor of
+// scoped_ptr<T> automatically deletes the pointer it holds (if
+// any). That is, scoped_ptr<T> owns the T object that it points
+// to. Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to
+// a T object. Also like T*, scoped_ptr<T> is thread-compatible, and
+// once you dereference it, you get the threadsafety guarantees of T.
+//
+// The size of a scoped_ptr is small: sizeof(scoped_ptr<C>) == sizeof(C*)
+template <class C>
+class scoped_ptr {
+ public:
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_ptr.
+ // The input parameter must be allocated with new.
+ explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_ptr() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete ptr_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != ptr_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete ptr_;
+ ptr_ = p;
+ }
+ }
+
+ // Accessors to get the owned object.
+ // operator* and operator-> will assert() if there is no current object.
+ C& operator*() const {
+ assert(ptr_ != NULL);
+ return *ptr_;
+ }
+ C* operator->() const {
+ assert(ptr_ != NULL);
+ return ptr_;
+ }
+ C* get() const { return ptr_; }
+
+ // Comparison operators.
+ // These return whether a scoped_ptr and a raw pointer refer to
+ // the same object, not just to two different but equal objects.
+ bool operator==(const C* p) const { return ptr_ == p; }
+ bool operator!=(const C* p) const { return ptr_ != p; }
+
+ // Swap two scoped pointers.
+ void swap(scoped_ptr& p2) {
+ C* tmp = ptr_;
+ ptr_ = p2.ptr_;
+ p2.ptr_ = tmp;
+ }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = ptr_;
+ ptr_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* ptr_;
+
+ // google3 friend class that can access copy ctor (although if it actually
+ // calls a copy ctor, there will be a problem) see below
+ friend scoped_ptr<C> make_scoped_ptr<C>(C *p);
+
+ // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't
+ // make sense, and if C2 == C, it still doesn't make sense because you should
+ // never have the same object owned by two different scoped_ptrs.
+ template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_ptr(const scoped_ptr&);
+ void operator=(const scoped_ptr&);
+};
+
+// Free functions
+template <class C>
+inline void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {
+ p1.swap(p2);
+}
+
+template <class C>
+inline bool operator==(const C* p1, const scoped_ptr<C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+inline bool operator==(const C* p1, const scoped_ptr<const C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+inline bool operator!=(const C* p1, const scoped_ptr<C>& p2) {
+ return p1 != p2.get();
+}
+
+template <class C>
+inline bool operator!=(const C* p1, const scoped_ptr<const C>& p2) {
+ return p1 != p2.get();
+}
+
+template <class C>
+scoped_ptr<C> make_scoped_ptr(C *p) {
+ // This does nothing but to return a scoped_ptr of the type that the passed
+ // pointer is of. (This eliminates the need to specify the name of T when
+ // making a scoped_ptr that is used anonymously/temporarily.) From an
+ // access control point of view, we construct an unnamed scoped_ptr here
+ // which we return and thus copy-construct. Hence, we need to have access
+ // to scoped_ptr::scoped_ptr(scoped_ptr const &). However, it is guaranteed
+ // that we never actually call the copy constructor, which is a good thing
+ // as we would call the temporary's object destructor (and thus delete p)
+ // if we actually did copy some object, here.
+ return scoped_ptr<C>(p);
+}
+
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL. A scoped_array<C> owns the object that it points to.
+// scoped_array<T> is thread-compatible, and once you index into it,
+// the returned objects have only the threadsafety guarantees of T.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_array.
+ // The input parameter must be allocated with new [].
+ explicit scoped_array(C* p = NULL) : array_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_array() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != array_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ array_ = p;
+ }
+ }
+
+ // Get one element of the current object.
+ // Will assert() if there is no current object, or index i is negative.
+ C& operator[](std::ptrdiff_t i) const {
+ assert(i >= 0);
+ assert(array_ != NULL);
+ return array_[i];
+ }
+
+ // Get a pointer to the zeroth element of the current object.
+ // If there is no current object, return NULL.
+ C* get() const {
+ return array_;
+ }
+
+ // Comparison operators.
+ // These return whether a scoped_array and a raw pointer refer to
+ // the same array, not just to two different but equal arrays.
+ bool operator==(const C* p) const { return array_ == p; }
+ bool operator!=(const C* p) const { return array_ != p; }
+
+ // Swap two scoped arrays.
+ void swap(scoped_array& p2) {
+ C* tmp = array_;
+ array_ = p2.array_;
+ p2.array_ = tmp;
+ }
+
+ // Release an array.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = array_;
+ array_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* array_;
+
+ // Forbid comparison of different scoped_array types.
+ template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_array(const scoped_array&);
+ void operator=(const scoped_array&);
+};
+
+// Free functions
+template <class C>
+inline void swap(scoped_array<C>& p1, scoped_array<C>& p2) {
+ p1.swap(p2);
+}
+
+template <class C>
+inline bool operator==(const C* p1, const scoped_array<C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+inline bool operator==(const C* p1, const scoped_array<const C>& p2) {
+ return p1 == p2.get();
+}
+
+template <class C>
+inline bool operator!=(const C* p1, const scoped_array<C>& p2) {
+ return p1 != p2.get();
+}
+
+template <class C>
+inline bool operator!=(const C* p1, const scoped_array<const C>& p2) {
+ return p1 != p2.get();
+}
+
+// This class wraps the c library function free() in a class that can be
+// passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFree {
+ public:
+ inline void operator()(void* x) const {
+ free(x);
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
diff --git a/extern/ceres/include/ceres/internal/variadic_evaluate.h b/extern/ceres/include/ceres/internal/variadic_evaluate.h
new file mode 100644
index 00000000000..b3515b96d18
--- /dev/null
+++ b/extern/ceres/include/ceres/internal/variadic_evaluate.h
@@ -0,0 +1,194 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// mierle@gmail.com (Keir Mierle)
+
+#ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
+#define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
+
+#include <stddef.h>
+
+#include "ceres/jet.h"
+#include "ceres/types.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// This block of quasi-repeated code calls the user-supplied functor, which may
+// take a variable number of arguments. This is accomplished by specializing the
+// struct based on the size of the trailing parameters; parameters with 0 size
+// are assumed missing.
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8, int N9>
+struct VariadicEvaluate {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ input[7],
+ input[8],
+ input[9],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7, int N8>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, N8, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ input[7],
+ input[8],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6, int N7>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ input[7],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5, int N6>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ input[6],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
+ int N5>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ input[5],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ input[4],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2, int N3>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ input[3],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1, int N2>
+struct VariadicEvaluate<Functor, T, N0, N1, N2, 0, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ input[2],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0, int N1>
+struct VariadicEvaluate<Functor, T, N0, N1, 0, 0, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ input[1],
+ output);
+ }
+};
+
+template<typename Functor, typename T, int N0>
+struct VariadicEvaluate<Functor, T, N0, 0, 0, 0, 0, 0, 0, 0, 0, 0> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input[0],
+ output);
+ }
+};
+
+// Template instantiation for dynamically-sized functors.
+template<typename Functor, typename T>
+struct VariadicEvaluate<Functor, T, ceres::DYNAMIC, ceres::DYNAMIC,
+ ceres::DYNAMIC, ceres::DYNAMIC, ceres::DYNAMIC,
+ ceres::DYNAMIC, ceres::DYNAMIC, ceres::DYNAMIC,
+ ceres::DYNAMIC, ceres::DYNAMIC> {
+ static bool Call(const Functor& functor, T const *const *input, T* output) {
+ return functor(input, output);
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
diff --git a/extern/ceres/include/ceres/iteration_callback.h b/extern/ceres/include/ceres/iteration_callback.h
new file mode 100644
index 00000000000..6bab00439c5
--- /dev/null
+++ b/extern/ceres/include/ceres/iteration_callback.h
@@ -0,0 +1,225 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// When an iteration callback is specified, Ceres calls the callback
+// after each minimizer step (if the minimizer has not converged) and
+// passes it an IterationSummary object, defined below.
+
+#ifndef CERES_PUBLIC_ITERATION_CALLBACK_H_
+#define CERES_PUBLIC_ITERATION_CALLBACK_H_
+
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// This struct describes the state of the optimizer after each
+// iteration of the minimization.
+struct CERES_EXPORT IterationSummary {
+ IterationSummary()
+ : iteration(0),
+ step_is_valid(false),
+ step_is_nonmonotonic(false),
+ step_is_successful(false),
+ cost(0.0),
+ cost_change(0.0),
+ gradient_max_norm(0.0),
+ gradient_norm(0.0),
+ step_norm(0.0),
+ eta(0.0),
+ step_size(0.0),
+ line_search_function_evaluations(0),
+ line_search_gradient_evaluations(0),
+ line_search_iterations(0),
+ linear_solver_iterations(0),
+ iteration_time_in_seconds(0.0),
+ step_solver_time_in_seconds(0.0),
+ cumulative_time_in_seconds(0.0) {}
+
+ // Current iteration number.
+ int32 iteration;
+
+ // Step was numerically valid, i.e., all values are finite and the
+ // step reduces the value of the linearized model.
+ //
+ // Note: step_is_valid is false when iteration = 0.
+ bool step_is_valid;
+
+ // Step did not reduce the value of the objective function
+ // sufficiently, but it was accepted because of the relaxed
+ // acceptance criterion used by the non-monotonic trust region
+ // algorithm.
+ //
+ // Note: step_is_nonmonotonic is false when iteration = 0;
+ bool step_is_nonmonotonic;
+
+ // Whether or not the minimizer accepted this step or not. If the
+ // ordinary trust region algorithm is used, this means that the
+ // relative reduction in the objective function value was greater
+ // than Solver::Options::min_relative_decrease. However, if the
+ // non-monotonic trust region algorithm is used
+ // (Solver::Options:use_nonmonotonic_steps = true), then even if the
+ // relative decrease is not sufficient, the algorithm may accept the
+ // step and the step is declared successful.
+ //
+ // Note: step_is_successful is false when iteration = 0.
+ bool step_is_successful;
+
+ // Value of the objective function.
+ double cost;
+
+ // Change in the value of the objective function in this
+ // iteration. This can be positive or negative.
+ double cost_change;
+
+ // Infinity norm of the gradient vector.
+ double gradient_max_norm;
+
+ // 2-norm of the gradient vector.
+ double gradient_norm;
+
+ // 2-norm of the size of the step computed by the optimization
+ // algorithm.
+ double step_norm;
+
+ // For trust region algorithms, the ratio of the actual change in
+ // cost and the change in the cost of the linearized approximation.
+ double relative_decrease;
+
+ // Size of the trust region at the end of the current iteration. For
+ // the Levenberg-Marquardt algorithm, the regularization parameter
+ // mu = 1.0 / trust_region_radius.
+ double trust_region_radius;
+
+ // For the inexact step Levenberg-Marquardt algorithm, this is the
+ // relative accuracy with which the Newton(LM) step is solved. This
+ // number affects only the iterative solvers capable of solving
+ // linear systems inexactly. Factorization-based exact solvers
+ // ignore it.
+ double eta;
+
+ // Step sized computed by the line search algorithm.
+ double step_size;
+
+ // Number of function value evaluations used by the line search algorithm.
+ int line_search_function_evaluations;
+
+ // Number of function gradient evaluations used by the line search algorithm.
+ int line_search_gradient_evaluations;
+
+ // Number of iterations taken by the line search algorithm.
+ int line_search_iterations;
+
+ // Number of iterations taken by the linear solver to solve for the
+ // Newton step.
+ int linear_solver_iterations;
+
+ // All times reported below are wall times.
+
+ // Time (in seconds) spent inside the minimizer loop in the current
+ // iteration.
+ double iteration_time_in_seconds;
+
+ // Time (in seconds) spent inside the trust region step solver.
+ double step_solver_time_in_seconds;
+
+ // Time (in seconds) since the user called Solve().
+ double cumulative_time_in_seconds;
+};
+
+// Interface for specifying callbacks that are executed at the end of
+// each iteration of the Minimizer. The solver uses the return value
+// of operator() to decide whether to continue solving or to
+// terminate. The user can return three values.
+//
+// SOLVER_ABORT indicates that the callback detected an abnormal
+// situation. The solver returns without updating the parameter blocks
+// (unless Solver::Options::update_state_every_iteration is set
+// true). Solver returns with Solver::Summary::termination_type set to
+// USER_ABORT.
+//
+// SOLVER_TERMINATE_SUCCESSFULLY indicates that there is no need to
+// optimize anymore (some user specified termination criterion has
+// been met). Solver returns with Solver::Summary::termination_type
+// set to USER_SUCCESS.
+//
+// SOLVER_CONTINUE indicates that the solver should continue
+// optimizing.
+//
+// For example, the following Callback is used internally by Ceres to
+// log the progress of the optimization.
+//
+// Callback for logging the state of the minimizer to STDERR or STDOUT
+// depending on the user's preferences and logging level.
+//
+// class LoggingCallback : public IterationCallback {
+// public:
+// explicit LoggingCallback(bool log_to_stdout)
+// : log_to_stdout_(log_to_stdout) {}
+//
+// ~LoggingCallback() {}
+//
+// CallbackReturnType operator()(const IterationSummary& summary) {
+// const char* kReportRowFormat =
+// "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
+// "rho:% 3.2e mu:% 3.2e eta:% 3.2e li:% 3d";
+// string output = StringPrintf(kReportRowFormat,
+// summary.iteration,
+// summary.cost,
+// summary.cost_change,
+// summary.gradient_max_norm,
+// summary.step_norm,
+// summary.relative_decrease,
+// summary.trust_region_radius,
+// summary.eta,
+// summary.linear_solver_iterations);
+// if (log_to_stdout_) {
+// cout << output << endl;
+// } else {
+// VLOG(1) << output;
+// }
+// return SOLVER_CONTINUE;
+// }
+//
+// private:
+// const bool log_to_stdout_;
+// };
+//
+class CERES_EXPORT IterationCallback {
+ public:
+ virtual ~IterationCallback() {}
+ virtual CallbackReturnType operator()(const IterationSummary& summary) = 0;
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_ITERATION_CALLBACK_H_
diff --git a/extern/ceres/include/ceres/jet.h b/extern/ceres/include/ceres/jet.h
new file mode 100644
index 00000000000..a21fd7adb90
--- /dev/null
+++ b/extern/ceres/include/ceres/jet.h
@@ -0,0 +1,784 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A simple implementation of N-dimensional dual numbers, for automatically
+// computing exact derivatives of functions.
+//
+// While a complete treatment of the mechanics of automatic differentation is
+// beyond the scope of this header (see
+// http://en.wikipedia.org/wiki/Automatic_differentiation for details), the
+// basic idea is to extend normal arithmetic with an extra element, "e," often
+// denoted with the greek symbol epsilon, such that e != 0 but e^2 = 0. Dual
+// numbers are extensions of the real numbers analogous to complex numbers:
+// whereas complex numbers augment the reals by introducing an imaginary unit i
+// such that i^2 = -1, dual numbers introduce an "infinitesimal" unit e such
+// that e^2 = 0. Dual numbers have two components: the "real" component and the
+// "infinitesimal" component, generally written as x + y*e. Surprisingly, this
+// leads to a convenient method for computing exact derivatives without needing
+// to manipulate complicated symbolic expressions.
+//
+// For example, consider the function
+//
+// f(x) = x^2 ,
+//
+// evaluated at 10. Using normal arithmetic, f(10) = 100, and df/dx(10) = 20.
+// Next, augument 10 with an infinitesimal to get:
+//
+// f(10 + e) = (10 + e)^2
+// = 100 + 2 * 10 * e + e^2
+// = 100 + 20 * e -+-
+// -- |
+// | +--- This is zero, since e^2 = 0
+// |
+// +----------------- This is df/dx!
+//
+// Note that the derivative of f with respect to x is simply the infinitesimal
+// component of the value of f(x + e). So, in order to take the derivative of
+// any function, it is only necessary to replace the numeric "object" used in
+// the function with one extended with infinitesimals. The class Jet, defined in
+// this header, is one such example of this, where substitution is done with
+// templates.
+//
+// To handle derivatives of functions taking multiple arguments, different
+// infinitesimals are used, one for each variable to take the derivative of. For
+// example, consider a scalar function of two scalar parameters x and y:
+//
+// f(x, y) = x^2 + x * y
+//
+// Following the technique above, to compute the derivatives df/dx and df/dy for
+// f(1, 3) involves doing two evaluations of f, the first time replacing x with
+// x + e, the second time replacing y with y + e.
+//
+// For df/dx:
+//
+// f(1 + e, y) = (1 + e)^2 + (1 + e) * 3
+// = 1 + 2 * e + 3 + 3 * e
+// = 4 + 5 * e
+//
+// --> df/dx = 5
+//
+// For df/dy:
+//
+// f(1, 3 + e) = 1^2 + 1 * (3 + e)
+// = 1 + 3 + e
+// = 4 + e
+//
+// --> df/dy = 1
+//
+// To take the gradient of f with the implementation of dual numbers ("jets") in
+// this file, it is necessary to create a single jet type which has components
+// for the derivative in x and y, and passing them to a templated version of f:
+//
+// template<typename T>
+// T f(const T &x, const T &y) {
+// return x * x + x * y;
+// }
+//
+// // The "2" means there should be 2 dual number components.
+// Jet<double, 2> x(0); // Pick the 0th dual number for x.
+// Jet<double, 2> y(1); // Pick the 1st dual number for y.
+// Jet<double, 2> z = f(x, y);
+//
+// LOG(INFO) << "df/dx = " << z.v[0]
+// << "df/dy = " << z.v[1];
+//
+// Most users should not use Jet objects directly; a wrapper around Jet objects,
+// which makes computing the derivative, gradient, or jacobian of templated
+// functors simple, is in autodiff.h. Even autodiff.h should not be used
+// directly; instead autodiff_cost_function.h is typically the file of interest.
+//
+// For the more mathematically inclined, this file implements first-order
+// "jets". A 1st order jet is an element of the ring
+//
+// T[N] = T[t_1, ..., t_N] / (t_1, ..., t_N)^2
+//
+// which essentially means that each jet consists of a "scalar" value 'a' from T
+// and a 1st order perturbation vector 'v' of length N:
+//
+// x = a + \sum_i v[i] t_i
+//
+// A shorthand is to write an element as x = a + u, where u is the pertubation.
+// Then, the main point about the arithmetic of jets is that the product of
+// perturbations is zero:
+//
+// (a + u) * (b + v) = ab + av + bu + uv
+// = ab + (av + bu) + 0
+//
+// which is what operator* implements below. Addition is simpler:
+//
+// (a + u) + (b + v) = (a + b) + (u + v).
+//
+// The only remaining question is how to evaluate the function of a jet, for
+// which we use the chain rule:
+//
+// f(a + u) = f(a) + f'(a) u
+//
+// where f'(a) is the (scalar) derivative of f at a.
+//
+// By pushing these things through sufficiently and suitably templated
+// functions, we can do automatic differentiation. Just be sure to turn on
+// function inlining and common-subexpression elimination, or it will be very
+// slow!
+//
+// WARNING: Most Ceres users should not directly include this file or know the
+// details of how jets work. Instead the suggested method for automatic
+// derivatives is to use autodiff_cost_function.h, which is a wrapper around
+// both jets.h and autodiff.h to make taking derivatives of cost functions for
+// use in Ceres easier.
+
+#ifndef CERES_PUBLIC_JET_H_
+#define CERES_PUBLIC_JET_H_
+
+#include <cmath>
+#include <iosfwd>
+#include <iostream> // NOLINT
+#include <limits>
+#include <string>
+
+#include "Eigen/Core"
+#include "ceres/fpclassify.h"
+
+namespace ceres {
+
+template <typename T, int N>
+struct Jet {
+ enum { DIMENSION = N };
+
+ // Default-construct "a" because otherwise this can lead to false errors about
+ // uninitialized uses when other classes relying on default constructed T
+ // (where T is a Jet<T, N>). This usually only happens in opt mode. Note that
+ // the C++ standard mandates that e.g. default constructed doubles are
+ // initialized to 0.0; see sections 8.5 of the C++03 standard.
+ Jet() : a() {
+ v.setZero();
+ }
+
+ // Constructor from scalar: a + 0.
+ explicit Jet(const T& value) {
+ a = value;
+ v.setZero();
+ }
+
+ // Constructor from scalar plus variable: a + t_i.
+ Jet(const T& value, int k) {
+ a = value;
+ v.setZero();
+ v[k] = T(1.0);
+ }
+
+ // Constructor from scalar and vector part
+ // The use of Eigen::DenseBase allows Eigen expressions
+ // to be passed in without being fully evaluated until
+ // they are assigned to v
+ template<typename Derived>
+ EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived> &v)
+ : a(a), v(v) {
+ }
+
+ // Compound operators
+ Jet<T, N>& operator+=(const Jet<T, N> &y) {
+ *this = *this + y;
+ return *this;
+ }
+
+ Jet<T, N>& operator-=(const Jet<T, N> &y) {
+ *this = *this - y;
+ return *this;
+ }
+
+ Jet<T, N>& operator*=(const Jet<T, N> &y) {
+ *this = *this * y;
+ return *this;
+ }
+
+ Jet<T, N>& operator/=(const Jet<T, N> &y) {
+ *this = *this / y;
+ return *this;
+ }
+
+ // The scalar part.
+ T a;
+
+ // The infinitesimal part.
+ //
+ // Note the Eigen::DontAlign bit is needed here because this object
+ // gets allocated on the stack and as part of other arrays and
+ // structs. Forcing the right alignment there is the source of much
+ // pain and suffering. Even if that works, passing Jets around to
+ // functions by value has problems because the C++ ABI does not
+ // guarantee alignment for function arguments.
+ //
+ // Setting the DontAlign bit prevents Eigen from using SSE for the
+ // various operations on Jets. This is a small performance penalty
+ // since the AutoDiff code will still expose much of the code as
+ // statically sized loops to the compiler. But given the subtle
+ // issues that arise due to alignment, especially when dealing with
+ // multiple platforms, it seems to be a trade off worth making.
+ Eigen::Matrix<T, N, 1, Eigen::DontAlign> v;
+};
+
+// Unary +
+template<typename T, int N> inline
+Jet<T, N> const& operator+(const Jet<T, N>& f) {
+ return f;
+}
+
+// TODO(keir): Try adding __attribute__((always_inline)) to these functions to
+// see if it causes a performance increase.
+
+// Unary -
+template<typename T, int N> inline
+Jet<T, N> operator-(const Jet<T, N>&f) {
+ return Jet<T, N>(-f.a, -f.v);
+}
+
+// Binary +
+template<typename T, int N> inline
+Jet<T, N> operator+(const Jet<T, N>& f,
+ const Jet<T, N>& g) {
+ return Jet<T, N>(f.a + g.a, f.v + g.v);
+}
+
+// Binary + with a scalar: x + s
+template<typename T, int N> inline
+Jet<T, N> operator+(const Jet<T, N>& f, T s) {
+ return Jet<T, N>(f.a + s, f.v);
+}
+
+// Binary + with a scalar: s + x
+template<typename T, int N> inline
+Jet<T, N> operator+(T s, const Jet<T, N>& f) {
+ return Jet<T, N>(f.a + s, f.v);
+}
+
+// Binary -
+template<typename T, int N> inline
+Jet<T, N> operator-(const Jet<T, N>& f,
+ const Jet<T, N>& g) {
+ return Jet<T, N>(f.a - g.a, f.v - g.v);
+}
+
+// Binary - with a scalar: x - s
+template<typename T, int N> inline
+Jet<T, N> operator-(const Jet<T, N>& f, T s) {
+ return Jet<T, N>(f.a - s, f.v);
+}
+
+// Binary - with a scalar: s - x
+template<typename T, int N> inline
+Jet<T, N> operator-(T s, const Jet<T, N>& f) {
+ return Jet<T, N>(s - f.a, -f.v);
+}
+
+// Binary *
+template<typename T, int N> inline
+Jet<T, N> operator*(const Jet<T, N>& f,
+ const Jet<T, N>& g) {
+ return Jet<T, N>(f.a * g.a, f.a * g.v + f.v * g.a);
+}
+
+// Binary * with a scalar: x * s
+template<typename T, int N> inline
+Jet<T, N> operator*(const Jet<T, N>& f, T s) {
+ return Jet<T, N>(f.a * s, f.v * s);
+}
+
+// Binary * with a scalar: s * x
+template<typename T, int N> inline
+Jet<T, N> operator*(T s, const Jet<T, N>& f) {
+ return Jet<T, N>(f.a * s, f.v * s);
+}
+
+// Binary /
+template<typename T, int N> inline
+Jet<T, N> operator/(const Jet<T, N>& f,
+ const Jet<T, N>& g) {
+ // This uses:
+ //
+ // a + u (a + u)(b - v) (a + u)(b - v)
+ // ----- = -------------- = --------------
+ // b + v (b + v)(b - v) b^2
+ //
+ // which holds because v*v = 0.
+ const T g_a_inverse = T(1.0) / g.a;
+ const T f_a_by_g_a = f.a * g_a_inverse;
+ return Jet<T, N>(f.a * g_a_inverse, (f.v - f_a_by_g_a * g.v) * g_a_inverse);
+}
+
+// Binary / with a scalar: s / x
+template<typename T, int N> inline
+Jet<T, N> operator/(T s, const Jet<T, N>& g) {
+ const T minus_s_g_a_inverse2 = -s / (g.a * g.a);
+ return Jet<T, N>(s / g.a, g.v * minus_s_g_a_inverse2);
+}
+
+// Binary / with a scalar: x / s
+template<typename T, int N> inline
+Jet<T, N> operator/(const Jet<T, N>& f, T s) {
+ const T s_inverse = 1.0 / s;
+ return Jet<T, N>(f.a * s_inverse, f.v * s_inverse);
+}
+
+// Binary comparison operators for both scalars and jets.
+#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op) \
+template<typename T, int N> inline \
+bool operator op(const Jet<T, N>& f, const Jet<T, N>& g) { \
+ return f.a op g.a; \
+} \
+template<typename T, int N> inline \
+bool operator op(const T& s, const Jet<T, N>& g) { \
+ return s op g.a; \
+} \
+template<typename T, int N> inline \
+bool operator op(const Jet<T, N>& f, const T& s) { \
+ return f.a op s; \
+}
+CERES_DEFINE_JET_COMPARISON_OPERATOR( < ) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR( <= ) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR( > ) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR( >= ) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR( == ) // NOLINT
+CERES_DEFINE_JET_COMPARISON_OPERATOR( != ) // NOLINT
+#undef CERES_DEFINE_JET_COMPARISON_OPERATOR
+
+// Pull some functions from namespace std.
+//
+// This is necessary because we want to use the same name (e.g. 'sqrt') for
+// double-valued and Jet-valued functions, but we are not allowed to put
+// Jet-valued functions inside namespace std.
+//
+// TODO(keir): Switch to "using".
+inline double abs (double x) { return std::abs(x); }
+inline double log (double x) { return std::log(x); }
+inline double exp (double x) { return std::exp(x); }
+inline double sqrt (double x) { return std::sqrt(x); }
+inline double cos (double x) { return std::cos(x); }
+inline double acos (double x) { return std::acos(x); }
+inline double sin (double x) { return std::sin(x); }
+inline double asin (double x) { return std::asin(x); }
+inline double tan (double x) { return std::tan(x); }
+inline double atan (double x) { return std::atan(x); }
+inline double sinh (double x) { return std::sinh(x); }
+inline double cosh (double x) { return std::cosh(x); }
+inline double tanh (double x) { return std::tanh(x); }
+inline double pow (double x, double y) { return std::pow(x, y); }
+inline double atan2(double y, double x) { return std::atan2(y, x); }
+
+// In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
+
+// abs(x + h) ~= x + h or -(x + h)
+template <typename T, int N> inline
+Jet<T, N> abs(const Jet<T, N>& f) {
+ return f.a < T(0.0) ? -f : f;
+}
+
+// log(a + h) ~= log(a) + h / a
+template <typename T, int N> inline
+Jet<T, N> log(const Jet<T, N>& f) {
+ const T a_inverse = T(1.0) / f.a;
+ return Jet<T, N>(log(f.a), f.v * a_inverse);
+}
+
+// exp(a + h) ~= exp(a) + exp(a) h
+template <typename T, int N> inline
+Jet<T, N> exp(const Jet<T, N>& f) {
+ const T tmp = exp(f.a);
+ return Jet<T, N>(tmp, tmp * f.v);
+}
+
+// sqrt(a + h) ~= sqrt(a) + h / (2 sqrt(a))
+template <typename T, int N> inline
+Jet<T, N> sqrt(const Jet<T, N>& f) {
+ const T tmp = sqrt(f.a);
+ const T two_a_inverse = T(1.0) / (T(2.0) * tmp);
+ return Jet<T, N>(tmp, f.v * two_a_inverse);
+}
+
+// cos(a + h) ~= cos(a) - sin(a) h
+template <typename T, int N> inline
+Jet<T, N> cos(const Jet<T, N>& f) {
+ return Jet<T, N>(cos(f.a), - sin(f.a) * f.v);
+}
+
+// acos(a + h) ~= acos(a) - 1 / sqrt(1 - a^2) h
+template <typename T, int N> inline
+Jet<T, N> acos(const Jet<T, N>& f) {
+ const T tmp = - T(1.0) / sqrt(T(1.0) - f.a * f.a);
+ return Jet<T, N>(acos(f.a), tmp * f.v);
+}
+
+// sin(a + h) ~= sin(a) + cos(a) h
+template <typename T, int N> inline
+Jet<T, N> sin(const Jet<T, N>& f) {
+ return Jet<T, N>(sin(f.a), cos(f.a) * f.v);
+}
+
+// asin(a + h) ~= asin(a) + 1 / sqrt(1 - a^2) h
+template <typename T, int N> inline
+Jet<T, N> asin(const Jet<T, N>& f) {
+ const T tmp = T(1.0) / sqrt(T(1.0) - f.a * f.a);
+ return Jet<T, N>(asin(f.a), tmp * f.v);
+}
+
+// tan(a + h) ~= tan(a) + (1 + tan(a)^2) h
+template <typename T, int N> inline
+Jet<T, N> tan(const Jet<T, N>& f) {
+ const T tan_a = tan(f.a);
+ const T tmp = T(1.0) + tan_a * tan_a;
+ return Jet<T, N>(tan_a, tmp * f.v);
+}
+
+// atan(a + h) ~= atan(a) + 1 / (1 + a^2) h
+template <typename T, int N> inline
+Jet<T, N> atan(const Jet<T, N>& f) {
+ const T tmp = T(1.0) / (T(1.0) + f.a * f.a);
+ return Jet<T, N>(atan(f.a), tmp * f.v);
+}
+
+// sinh(a + h) ~= sinh(a) + cosh(a) h
+template <typename T, int N> inline
+Jet<T, N> sinh(const Jet<T, N>& f) {
+ return Jet<T, N>(sinh(f.a), cosh(f.a) * f.v);
+}
+
+// cosh(a + h) ~= cosh(a) + sinh(a) h
+template <typename T, int N> inline
+Jet<T, N> cosh(const Jet<T, N>& f) {
+ return Jet<T, N>(cosh(f.a), sinh(f.a) * f.v);
+}
+
+// tanh(a + h) ~= tanh(a) + (1 - tanh(a)^2) h
+template <typename T, int N> inline
+Jet<T, N> tanh(const Jet<T, N>& f) {
+ const T tanh_a = tanh(f.a);
+ const T tmp = T(1.0) - tanh_a * tanh_a;
+ return Jet<T, N>(tanh_a, tmp * f.v);
+}
+
+// Bessel functions of the first kind with integer order equal to 0, 1, n.
+inline double BesselJ0(double x) { return j0(x); }
+inline double BesselJ1(double x) { return j1(x); }
+inline double BesselJn(int n, double x) { return jn(n, x); }
+
+// For the formulae of the derivatives of the Bessel functions see the book:
+// Olver, Lozier, Boisvert, Clark, NIST Handbook of Mathematical Functions,
+// Cambridge University Press 2010.
+//
+// Formulae are also available at http://dlmf.nist.gov
+
+// See formula http://dlmf.nist.gov/10.6#E3
+// j0(a + h) ~= j0(a) - j1(a) h
+template <typename T, int N> inline
+Jet<T, N> BesselJ0(const Jet<T, N>& f) {
+ return Jet<T, N>(BesselJ0(f.a),
+ -BesselJ1(f.a) * f.v);
+}
+
+// See formula http://dlmf.nist.gov/10.6#E1
+// j1(a + h) ~= j1(a) + 0.5 ( j0(a) - j2(a) ) h
+template <typename T, int N> inline
+Jet<T, N> BesselJ1(const Jet<T, N>& f) {
+ return Jet<T, N>(BesselJ1(f.a),
+ T(0.5) * (BesselJ0(f.a) - BesselJn(2, f.a)) * f.v);
+}
+
+// See formula http://dlmf.nist.gov/10.6#E1
+// j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
+template <typename T, int N> inline
+Jet<T, N> BesselJn(int n, const Jet<T, N>& f) {
+ return Jet<T, N>(BesselJn(n, f.a),
+ T(0.5) * (BesselJn(n - 1, f.a) - BesselJn(n + 1, f.a)) * f.v);
+}
+
+// Jet Classification. It is not clear what the appropriate semantics are for
+// these classifications. This picks that IsFinite and isnormal are "all"
+// operations, i.e. all elements of the jet must be finite for the jet itself
+// to be finite (or normal). For IsNaN and IsInfinite, the answer is less
+// clear. This takes a "any" approach for IsNaN and IsInfinite such that if any
+// part of a jet is nan or inf, then the entire jet is nan or inf. This leads
+// to strange situations like a jet can be both IsInfinite and IsNaN, but in
+// practice the "any" semantics are the most useful for e.g. checking that
+// derivatives are sane.
+
+// The jet is finite if all parts of the jet are finite.
+template <typename T, int N> inline
+bool IsFinite(const Jet<T, N>& f) {
+ if (!IsFinite(f.a)) {
+ return false;
+ }
+ for (int i = 0; i < N; ++i) {
+ if (!IsFinite(f.v[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// The jet is infinite if any part of the jet is infinite.
+template <typename T, int N> inline
+bool IsInfinite(const Jet<T, N>& f) {
+ if (IsInfinite(f.a)) {
+ return true;
+ }
+ for (int i = 0; i < N; i++) {
+ if (IsInfinite(f.v[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// The jet is NaN if any part of the jet is NaN.
+template <typename T, int N> inline
+bool IsNaN(const Jet<T, N>& f) {
+ if (IsNaN(f.a)) {
+ return true;
+ }
+ for (int i = 0; i < N; ++i) {
+ if (IsNaN(f.v[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// The jet is normal if all parts of the jet are normal.
+template <typename T, int N> inline
+bool IsNormal(const Jet<T, N>& f) {
+ if (!IsNormal(f.a)) {
+ return false;
+ }
+ for (int i = 0; i < N; ++i) {
+ if (!IsNormal(f.v[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// atan2(b + db, a + da) ~= atan2(b, a) + (- b da + a db) / (a^2 + b^2)
+//
+// In words: the rate of change of theta is 1/r times the rate of
+// change of (x, y) in the positive angular direction.
+template <typename T, int N> inline
+Jet<T, N> atan2(const Jet<T, N>& g, const Jet<T, N>& f) {
+ // Note order of arguments:
+ //
+ // f = a + da
+ // g = b + db
+
+ T const tmp = T(1.0) / (f.a * f.a + g.a * g.a);
+ return Jet<T, N>(atan2(g.a, f.a), tmp * (- g.a * f.v + f.a * g.v));
+}
+
+
+// pow -- base is a differentiable function, exponent is a constant.
+// (a+da)^p ~= a^p + p*a^(p-1) da
+template <typename T, int N> inline
+Jet<T, N> pow(const Jet<T, N>& f, double g) {
+ T const tmp = g * pow(f.a, g - T(1.0));
+ return Jet<T, N>(pow(f.a, g), tmp * f.v);
+}
+
+// pow -- base is a constant, exponent is a differentiable function.
+// We have various special cases, see the comment for pow(Jet, Jet) for
+// analysis:
+//
+// 1. For f > 0 we have: (f)^(g + dg) ~= f^g + f^g log(f) dg
+//
+// 2. For f == 0 and g > 0 we have: (f)^(g + dg) ~= f^g
+//
+// 3. For f < 0 and integer g we have: (f)^(g + dg) ~= f^g but if dg
+// != 0, the derivatives are not defined and we return NaN.
+
+template <typename T, int N> inline
+Jet<T, N> pow(double f, const Jet<T, N>& g) {
+ if (f == 0 && g.a > 0) {
+ // Handle case 2.
+ return Jet<T, N>(T(0.0));
+ }
+ if (f < 0 && g.a == floor(g.a)) {
+ // Handle case 3.
+ Jet<T, N> ret(pow(f, g.a));
+ for (int i = 0; i < N; i++) {
+ if (g.v[i] != T(0.0)) {
+ // Return a NaN when g.v != 0.
+ ret.v[i] = std::numeric_limits<T>::quiet_NaN();
+ }
+ }
+ return ret;
+ }
+ // Handle case 1.
+ T const tmp = pow(f, g.a);
+ return Jet<T, N>(tmp, log(f) * tmp * g.v);
+}
+
+// pow -- both base and exponent are differentiable functions. This has a
+// variety of special cases that require careful handling.
+//
+// 1. For f > 0:
+// (f + df)^(g + dg) ~= f^g + f^(g - 1) * (g * df + f * log(f) * dg)
+// The numerical evaluation of f * log(f) for f > 0 is well behaved, even for
+// extremely small values (e.g. 1e-99).
+//
+// 2. For f == 0 and g > 1: (f + df)^(g + dg) ~= 0
+// This cases is needed because log(0) can not be evaluated in the f > 0
+// expression. However the function f*log(f) is well behaved around f == 0
+// and its limit as f-->0 is zero.
+//
+// 3. For f == 0 and g == 1: (f + df)^(g + dg) ~= 0 + df
+//
+// 4. For f == 0 and 0 < g < 1: The value is finite but the derivatives are not.
+//
+// 5. For f == 0 and g < 0: The value and derivatives of f^g are not finite.
+//
+// 6. For f == 0 and g == 0: The C standard incorrectly defines 0^0 to be 1
+// "because there are applications that can exploit this definition". We
+// (arbitrarily) decree that derivatives here will be nonfinite, since that
+// is consistent with the behavior for f == 0, g < 0 and 0 < g < 1.
+// Practically any definition could have been justified because mathematical
+// consistency has been lost at this point.
+//
+// 7. For f < 0, g integer, dg == 0: (f + df)^(g + dg) ~= f^g + g * f^(g - 1) df
+// This is equivalent to the case where f is a differentiable function and g
+// is a constant (to first order).
+//
+// 8. For f < 0, g integer, dg != 0: The value is finite but the derivatives are
+// not, because any change in the value of g moves us away from the point
+// with a real-valued answer into the region with complex-valued answers.
+//
+// 9. For f < 0, g noninteger: The value and derivatives of f^g are not finite.
+
+template <typename T, int N> inline
+Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
+ if (f.a == 0 && g.a >= 1) {
+ // Handle cases 2 and 3.
+ if (g.a > 1) {
+ return Jet<T, N>(T(0.0));
+ }
+ return f;
+ }
+ if (f.a < 0 && g.a == floor(g.a)) {
+ // Handle cases 7 and 8.
+ T const tmp = g.a * pow(f.a, g.a - T(1.0));
+ Jet<T, N> ret(pow(f.a, g.a), tmp * f.v);
+ for (int i = 0; i < N; i++) {
+ if (g.v[i] != T(0.0)) {
+ // Return a NaN when g.v != 0.
+ ret.v[i] = std::numeric_limits<T>::quiet_NaN();
+ }
+ }
+ return ret;
+ }
+ // Handle the remaining cases. For cases 4,5,6,9 we allow the log() function
+ // to generate -HUGE_VAL or NaN, since those cases result in a nonfinite
+ // derivative.
+ T const tmp1 = pow(f.a, g.a);
+ T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
+ T const tmp3 = tmp1 * log(f.a);
+ return Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
+}
+
+// Define the helper functions Eigen needs to embed Jet types.
+//
+// NOTE(keir): machine_epsilon() and precision() are missing, because they don't
+// work with nested template types (e.g. where the scalar is itself templated).
+// Among other things, this means that decompositions of Jet's does not work,
+// for example
+//
+// Matrix<Jet<T, N> ... > A, x, b;
+// ...
+// A.solve(b, &x)
+//
+// does not work and will fail with a strange compiler error.
+//
+// TODO(keir): This is an Eigen 2.0 limitation that is lifted in 3.0. When we
+// switch to 3.0, also add the rest of the specialization functionality.
+template<typename T, int N> inline const Jet<T, N>& ei_conj(const Jet<T, N>& x) { return x; } // NOLINT
+template<typename T, int N> inline const Jet<T, N>& ei_real(const Jet<T, N>& x) { return x; } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_imag(const Jet<T, N>& ) { return Jet<T, N>(0.0); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_abs (const Jet<T, N>& x) { return fabs(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_abs2(const Jet<T, N>& x) { return x * x; } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_sqrt(const Jet<T, N>& x) { return sqrt(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_exp (const Jet<T, N>& x) { return exp(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_log (const Jet<T, N>& x) { return log(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_sin (const Jet<T, N>& x) { return sin(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_cos (const Jet<T, N>& x) { return cos(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_tan (const Jet<T, N>& x) { return tan(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_atan(const Jet<T, N>& x) { return atan(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_sinh(const Jet<T, N>& x) { return sinh(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_cosh(const Jet<T, N>& x) { return cosh(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_tanh(const Jet<T, N>& x) { return tanh(x); } // NOLINT
+template<typename T, int N> inline Jet<T, N> ei_pow (const Jet<T, N>& x, Jet<T, N> y) { return pow(x, y); } // NOLINT
+
+// Note: This has to be in the ceres namespace for argument dependent lookup to
+// function correctly. Otherwise statements like CHECK_LE(x, 2.0) fail with
+// strange compile errors.
+template <typename T, int N>
+inline std::ostream &operator<<(std::ostream &s, const Jet<T, N>& z) {
+ return s << "[" << z.a << " ; " << z.v.transpose() << "]";
+}
+
+} // namespace ceres
+
+namespace Eigen {
+
+// Creating a specialization of NumTraits enables placing Jet objects inside
+// Eigen arrays, getting all the goodness of Eigen combined with autodiff.
+template<typename T, int N>
+struct NumTraits<ceres::Jet<T, N> > {
+ typedef ceres::Jet<T, N> Real;
+ typedef ceres::Jet<T, N> NonInteger;
+ typedef ceres::Jet<T, N> Nested;
+
+ static typename ceres::Jet<T, N> dummy_precision() {
+ return ceres::Jet<T, N>(1e-12);
+ }
+
+ static inline Real epsilon() {
+ return Real(std::numeric_limits<T>::epsilon());
+ }
+
+ enum {
+ IsComplex = 0,
+ IsInteger = 0,
+ IsSigned,
+ ReadCost = 1,
+ AddCost = 1,
+ // For Jet types, multiplication is more expensive than addition.
+ MulCost = 3,
+ HasFloatingPoint = 1,
+ RequireInitialization = 1
+ };
+};
+
+} // namespace Eigen
+
+#endif // CERES_PUBLIC_JET_H_
diff --git a/extern/ceres/include/ceres/local_parameterization.h b/extern/ceres/include/ceres/local_parameterization.h
new file mode 100644
index 00000000000..67633de309f
--- /dev/null
+++ b/extern/ceres/include/ceres/local_parameterization.h
@@ -0,0 +1,301 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
+#define CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
+
+#include <vector>
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// Purpose: Sometimes parameter blocks x can overparameterize a problem
+//
+// min f(x)
+// x
+//
+// In that case it is desirable to choose a parameterization for the
+// block itself to remove the null directions of the cost. More
+// generally, if x lies on a manifold of a smaller dimension than the
+// ambient space that it is embedded in, then it is numerically and
+// computationally more effective to optimize it using a
+// parameterization that lives in the tangent space of that manifold
+// at each point.
+//
+// For example, a sphere in three dimensions is a 2 dimensional
+// manifold, embedded in a three dimensional space. At each point on
+// the sphere, the plane tangent to it defines a two dimensional
+// tangent space. For a cost function defined on this sphere, given a
+// point x, moving in the direction normal to the sphere at that point
+// is not useful. Thus a better way to do a local optimization is to
+// optimize over two dimensional vector delta in the tangent space at
+// that point and then "move" to the point x + delta, where the move
+// operation involves projecting back onto the sphere. Doing so
+// removes a redundent dimension from the optimization, making it
+// numerically more robust and efficient.
+//
+// More generally we can define a function
+//
+// x_plus_delta = Plus(x, delta),
+//
+// where x_plus_delta has the same size as x, and delta is of size
+// less than or equal to x. The function Plus, generalizes the
+// definition of vector addition. Thus it satisfies the identify
+//
+// Plus(x, 0) = x, for all x.
+//
+// A trivial version of Plus is when delta is of the same size as x
+// and
+//
+// Plus(x, delta) = x + delta
+//
+// A more interesting case if x is two dimensional vector, and the
+// user wishes to hold the first coordinate constant. Then, delta is a
+// scalar and Plus is defined as
+//
+// Plus(x, delta) = x + [0] * delta
+// [1]
+//
+// An example that occurs commonly in Structure from Motion problems
+// is when camera rotations are parameterized using Quaternion. There,
+// it is useful only make updates orthogonal to that 4-vector defining
+// the quaternion. One way to do this is to let delta be a 3
+// dimensional vector and define Plus to be
+//
+// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x
+//
+// The multiplication between the two 4-vectors on the RHS is the
+// standard quaternion product.
+//
+// Given g and a point x, optimizing f can now be restated as
+//
+// min f(Plus(x, delta))
+// delta
+//
+// Given a solution delta to this problem, the optimal value is then
+// given by
+//
+// x* = Plus(x, delta)
+//
+// The class LocalParameterization defines the function Plus and its
+// Jacobian which is needed to compute the Jacobian of f w.r.t delta.
+class CERES_EXPORT LocalParameterization {
+ public:
+ virtual ~LocalParameterization();
+
+ // Generalization of the addition operation,
+ //
+ // x_plus_delta = Plus(x, delta)
+ //
+ // with the condition that Plus(x, 0) = x.
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const = 0;
+
+ // The jacobian of Plus(x, delta) w.r.t delta at delta = 0.
+ //
+ // jacobian is a row-major GlobalSize() x LocalSize() matrix.
+ virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0;
+
+ // local_matrix = global_matrix * jacobian
+ //
+ // global_matrix is a num_rows x GlobalSize row major matrix.
+ // local_matrix is a num_rows x LocalSize row major matrix.
+ // jacobian(x) is the matrix returned by ComputeJacobian at x.
+ //
+ // This is only used by GradientProblem. For most normal uses, it is
+ // okay to use the default implementation.
+ virtual bool MultiplyByJacobian(const double* x,
+ const int num_rows,
+ const double* global_matrix,
+ double* local_matrix) const;
+
+ // Size of x.
+ virtual int GlobalSize() const = 0;
+
+ // Size of delta.
+ virtual int LocalSize() const = 0;
+};
+
+// Some basic parameterizations
+
+// Identity Parameterization: Plus(x, delta) = x + delta
+class CERES_EXPORT IdentityParameterization : public LocalParameterization {
+ public:
+ explicit IdentityParameterization(int size);
+ virtual ~IdentityParameterization() {}
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const;
+ virtual bool ComputeJacobian(const double* x,
+ double* jacobian) const;
+ virtual bool MultiplyByJacobian(const double* x,
+ const int num_cols,
+ const double* global_matrix,
+ double* local_matrix) const;
+ virtual int GlobalSize() const { return size_; }
+ virtual int LocalSize() const { return size_; }
+
+ private:
+ const int size_;
+};
+
+// Hold a subset of the parameters inside a parameter block constant.
+class CERES_EXPORT SubsetParameterization : public LocalParameterization {
+ public:
+ explicit SubsetParameterization(int size,
+ const std::vector<int>& constant_parameters);
+ virtual ~SubsetParameterization() {}
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const;
+ virtual bool ComputeJacobian(const double* x,
+ double* jacobian) const;
+ virtual bool MultiplyByJacobian(const double* x,
+ const int num_cols,
+ const double* global_matrix,
+ double* local_matrix) const;
+ virtual int GlobalSize() const {
+ return static_cast<int>(constancy_mask_.size());
+ }
+ virtual int LocalSize() const { return local_size_; }
+
+ private:
+ const int local_size_;
+ std::vector<char> constancy_mask_;
+};
+
+// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x
+// with * being the quaternion multiplication operator. Here we assume
+// that the first element of the quaternion vector is the real (cos
+// theta) part.
+class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
+ public:
+ virtual ~QuaternionParameterization() {}
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const;
+ virtual bool ComputeJacobian(const double* x,
+ double* jacobian) const;
+ virtual int GlobalSize() const { return 4; }
+ virtual int LocalSize() const { return 3; }
+};
+
+
+// This provides a parameterization for homogeneous vectors which are commonly
+// used in Structure for Motion problems. One example where they are used is
+// in representing points whose triangulation is ill-conditioned. Here
+// it is advantageous to use an over-parameterization since homogeneous vectors
+// can represent points at infinity.
+//
+// The plus operator is defined as
+// Plus(x, delta) =
+// [sin(0.5 * |delta|) * delta / |delta|, cos(0.5 * |delta|)] * x
+// with * defined as an operator which applies the update orthogonal to x to
+// remain on the sphere. We assume that the last element of x is the scalar
+// component. The size of the homogeneous vector is required to be greater than
+// 1.
+class CERES_EXPORT HomogeneousVectorParameterization :
+ public LocalParameterization {
+ public:
+ explicit HomogeneousVectorParameterization(int size);
+ virtual ~HomogeneousVectorParameterization() {}
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const;
+ virtual bool ComputeJacobian(const double* x,
+ double* jacobian) const;
+ virtual int GlobalSize() const { return size_; }
+ virtual int LocalSize() const { return size_ - 1; }
+
+ private:
+ const int size_;
+};
+
+// Construct a local parameterization by taking the Cartesian product
+// of a number of other local parameterizations. This is useful, when
+// a parameter block is the cartesian product of two or more
+// manifolds. For example the parameters of a camera consist of a
+// rotation and a translation, i.e., SO(3) x R^3.
+//
+// Currently this class supports taking the cartesian product of up to
+// four local parameterizations.
+//
+// Example usage:
+//
+// ProductParameterization product_param(new QuaterionionParameterization(),
+// new IdentityParameterization(3));
+//
+// is the local parameterization for a rigid transformation, where the
+// rotation is represented using a quaternion.
+class CERES_EXPORT ProductParameterization : public LocalParameterization {
+ public:
+ //
+ // NOTE: All the constructors take ownership of the input local
+ // parameterizations.
+ //
+ ProductParameterization(LocalParameterization* local_param1,
+ LocalParameterization* local_param2);
+
+ ProductParameterization(LocalParameterization* local_param1,
+ LocalParameterization* local_param2,
+ LocalParameterization* local_param3);
+
+ ProductParameterization(LocalParameterization* local_param1,
+ LocalParameterization* local_param2,
+ LocalParameterization* local_param3,
+ LocalParameterization* local_param4);
+
+ virtual ~ProductParameterization();
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const;
+ virtual bool ComputeJacobian(const double* x,
+ double* jacobian) const;
+ virtual int GlobalSize() const { return global_size_; }
+ virtual int LocalSize() const { return local_size_; }
+
+ private:
+ void Init();
+
+ std::vector<LocalParameterization*> local_params_;
+ int local_size_;
+ int global_size_;
+ int buffer_size_;
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
diff --git a/extern/ceres/include/ceres/loss_function.h b/extern/ceres/include/ceres/loss_function.h
new file mode 100644
index 00000000000..0512c135143
--- /dev/null
+++ b/extern/ceres/include/ceres/loss_function.h
@@ -0,0 +1,428 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// The LossFunction interface is the way users describe how residuals
+// are converted to cost terms for the overall problem cost function.
+// For the exact manner in which loss functions are converted to the
+// overall cost for a problem, see problem.h.
+//
+// For least squares problem where there are no outliers and standard
+// squared loss is expected, it is not necessary to create a loss
+// function; instead passing a NULL to the problem when adding
+// residuals implies a standard squared loss.
+//
+// For least squares problems where the minimization may encounter
+// input terms that contain outliers, that is, completely bogus
+// measurements, it is important to use a loss function that reduces
+// their associated penalty.
+//
+// Consider a structure from motion problem. The unknowns are 3D
+// points and camera parameters, and the measurements are image
+// coordinates describing the expected reprojected position for a
+// point in a camera. For example, we want to model the geometry of a
+// street scene with fire hydrants and cars, observed by a moving
+// camera with unknown parameters, and the only 3D points we care
+// about are the pointy tippy-tops of the fire hydrants. Our magic
+// image processing algorithm, which is responsible for producing the
+// measurements that are input to Ceres, has found and matched all
+// such tippy-tops in all image frames, except that in one of the
+// frame it mistook a car's headlight for a hydrant. If we didn't do
+// anything special (i.e. if we used a basic quadratic loss), the
+// residual for the erroneous measurement will result in extreme error
+// due to the quadratic nature of squared loss. This results in the
+// entire solution getting pulled away from the optimimum to reduce
+// the large error that would otherwise be attributed to the wrong
+// measurement.
+//
+// Using a robust loss function, the cost for large residuals is
+// reduced. In the example above, this leads to outlier terms getting
+// downweighted so they do not overly influence the final solution.
+//
+// What cost function is best?
+//
+// In general, there isn't a principled way to select a robust loss
+// function. The authors suggest starting with a non-robust cost, then
+// only experimenting with robust loss functions if standard squared
+// loss doesn't work.
+
+#ifndef CERES_PUBLIC_LOSS_FUNCTION_H_
+#define CERES_PUBLIC_LOSS_FUNCTION_H_
+
+#include "glog/logging.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+class CERES_EXPORT LossFunction {
+ public:
+ virtual ~LossFunction() {}
+
+ // For a residual vector with squared 2-norm 'sq_norm', this method
+ // is required to fill in the value and derivatives of the loss
+ // function (rho in this example):
+ //
+ // out[0] = rho(sq_norm),
+ // out[1] = rho'(sq_norm),
+ // out[2] = rho''(sq_norm),
+ //
+ // Here the convention is that the contribution of a term to the
+ // cost function is given by 1/2 rho(s), where
+ //
+ // s = ||residuals||^2.
+ //
+ // Calling the method with a negative value of 's' is an error and
+ // the implementations are not required to handle that case.
+ //
+ // Most sane choices of rho() satisfy:
+ //
+ // rho(0) = 0,
+ // rho'(0) = 1,
+ // rho'(s) < 1 in outlier region,
+ // rho''(s) < 0 in outlier region,
+ //
+ // so that they mimic the least squares cost for small residuals.
+ virtual void Evaluate(double sq_norm, double out[3]) const = 0;
+};
+
+// Some common implementations follow below.
+//
+// Note: in the region of interest (i.e. s < 3) we have:
+// TrivialLoss >= HuberLoss >= SoftLOneLoss >= CauchyLoss
+
+
+// This corresponds to no robustification.
+//
+// rho(s) = s
+//
+// At s = 0: rho = [0, 1, 0].
+//
+// It is not normally necessary to use this, as passing NULL for the
+// loss function when building the problem accomplishes the same
+// thing.
+class CERES_EXPORT TrivialLoss : public LossFunction {
+ public:
+ virtual void Evaluate(double, double*) const;
+};
+
+// Scaling
+// -------
+// Given one robustifier
+// s -> rho(s)
+// one can change the length scale at which robustification takes
+// place, by adding a scale factor 'a' as follows:
+//
+// s -> a^2 rho(s / a^2).
+//
+// The first and second derivatives are:
+//
+// s -> rho'(s / a^2),
+// s -> (1 / a^2) rho''(s / a^2),
+//
+// but the behaviour near s = 0 is the same as the original function,
+// i.e.
+//
+// rho(s) = s + higher order terms,
+// a^2 rho(s / a^2) = s + higher order terms.
+//
+// The scalar 'a' should be positive.
+//
+// The reason for the appearance of squaring is that 'a' is in the
+// units of the residual vector norm whereas 's' is a squared
+// norm. For applications it is more convenient to specify 'a' than
+// its square. The commonly used robustifiers below are described in
+// un-scaled format (a = 1) but their implementations work for any
+// non-zero value of 'a'.
+
+// Huber.
+//
+// rho(s) = s for s <= 1,
+// rho(s) = 2 sqrt(s) - 1 for s >= 1.
+//
+// At s = 0: rho = [0, 1, 0].
+//
+// The scaling parameter 'a' corresponds to 'delta' on this page:
+// http://en.wikipedia.org/wiki/Huber_Loss_Function
+class CERES_EXPORT HuberLoss : public LossFunction {
+ public:
+ explicit HuberLoss(double a) : a_(a), b_(a * a) { }
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ const double a_;
+ // b = a^2.
+ const double b_;
+};
+
+// Soft L1, similar to Huber but smooth.
+//
+// rho(s) = 2 (sqrt(1 + s) - 1).
+//
+// At s = 0: rho = [0, 1, -1/2].
+class CERES_EXPORT SoftLOneLoss : public LossFunction {
+ public:
+ explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) { }
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ // b = a^2.
+ const double b_;
+ // c = 1 / a^2.
+ const double c_;
+};
+
+// Inspired by the Cauchy distribution
+//
+// rho(s) = log(1 + s).
+//
+// At s = 0: rho = [0, 1, -1].
+class CERES_EXPORT CauchyLoss : public LossFunction {
+ public:
+ explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) { }
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ // b = a^2.
+ const double b_;
+ // c = 1 / a^2.
+ const double c_;
+};
+
+// Loss that is capped beyond a certain level using the arc-tangent function.
+// The scaling parameter 'a' determines the level where falloff occurs.
+// For costs much smaller than 'a', the loss function is linear and behaves like
+// TrivialLoss, and for values much larger than 'a' the value asymptotically
+// approaches the constant value of a * PI / 2.
+//
+// rho(s) = a atan(s / a).
+//
+// At s = 0: rho = [0, 1, 0].
+class CERES_EXPORT ArctanLoss : public LossFunction {
+ public:
+ explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) { }
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ const double a_;
+ // b = 1 / a^2.
+ const double b_;
+};
+
+// Loss function that maps to approximately zero cost in a range around the
+// origin, and reverts to linear in error (quadratic in cost) beyond this range.
+// The tolerance parameter 'a' sets the nominal point at which the
+// transition occurs, and the transition size parameter 'b' sets the nominal
+// distance over which most of the transition occurs. Both a and b must be
+// greater than zero, and typically b will be set to a fraction of a.
+// The slope rho'[s] varies smoothly from about 0 at s <= a - b to
+// about 1 at s >= a + b.
+//
+// The term is computed as:
+//
+// rho(s) = b log(1 + exp((s - a) / b)) - c0.
+//
+// where c0 is chosen so that rho(0) == 0
+//
+// c0 = b log(1 + exp(-a / b)
+//
+// This has the following useful properties:
+//
+// rho(s) == 0 for s = 0
+// rho'(s) ~= 0 for s << a - b
+// rho'(s) ~= 1 for s >> a + b
+// rho''(s) > 0 for all s
+//
+// In addition, all derivatives are continuous, and the curvature is
+// concentrated in the range a - b to a + b.
+//
+// At s = 0: rho = [0, ~0, ~0].
+class CERES_EXPORT TolerantLoss : public LossFunction {
+ public:
+ explicit TolerantLoss(double a, double b);
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ const double a_, b_, c_;
+};
+
+// This is the Tukey biweight loss function which aggressively
+// attempts to suppress large errors.
+//
+// The term is computed as:
+//
+// rho(s) = a^2 / 6 * (1 - (1 - s / a^2)^3 ) for s <= a^2,
+// rho(s) = a^2 / 6 for s > a^2.
+//
+// At s = 0: rho = [0, 0.5, -1 / a^2]
+class CERES_EXPORT TukeyLoss : public ceres::LossFunction {
+ public:
+ explicit TukeyLoss(double a) : a_squared_(a * a) { }
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ const double a_squared_;
+};
+
+// Composition of two loss functions. The error is the result of first
+// evaluating g followed by f to yield the composition f(g(s)).
+// The loss functions must not be NULL.
+class CERES_EXPORT ComposedLoss : public LossFunction {
+ public:
+ explicit ComposedLoss(const LossFunction* f, Ownership ownership_f,
+ const LossFunction* g, Ownership ownership_g);
+ virtual ~ComposedLoss();
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ internal::scoped_ptr<const LossFunction> f_, g_;
+ const Ownership ownership_f_, ownership_g_;
+};
+
+// The discussion above has to do with length scaling: it affects the space
+// in which s is measured. Sometimes you want to simply scale the output
+// value of the robustifier. For example, you might want to weight
+// different error terms differently (e.g., weight pixel reprojection
+// errors differently from terrain errors).
+//
+// If rho is the wrapped robustifier, then this simply outputs
+// s -> a * rho(s)
+//
+// The first and second derivatives are, not surprisingly
+// s -> a * rho'(s)
+// s -> a * rho''(s)
+//
+// Since we treat the a NULL Loss function as the Identity loss
+// function, rho = NULL is a valid input and will result in the input
+// being scaled by a. This provides a simple way of implementing a
+// scaled ResidualBlock.
+class CERES_EXPORT ScaledLoss : public LossFunction {
+ public:
+ // Constructs a ScaledLoss wrapping another loss function. Takes
+ // ownership of the wrapped loss function or not depending on the
+ // ownership parameter.
+ ScaledLoss(const LossFunction* rho, double a, Ownership ownership) :
+ rho_(rho), a_(a), ownership_(ownership) { }
+
+ virtual ~ScaledLoss() {
+ if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
+ rho_.release();
+ }
+ }
+ virtual void Evaluate(double, double*) const;
+
+ private:
+ internal::scoped_ptr<const LossFunction> rho_;
+ const double a_;
+ const Ownership ownership_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(ScaledLoss);
+};
+
+// Sometimes after the optimization problem has been constructed, we
+// wish to mutate the scale of the loss function. For example, when
+// performing estimation from data which has substantial outliers,
+// convergence can be improved by starting out with a large scale,
+// optimizing the problem and then reducing the scale. This can have
+// better convergence behaviour than just using a loss function with a
+// small scale.
+//
+// This templated class allows the user to implement a loss function
+// whose scale can be mutated after an optimization problem has been
+// constructed.
+//
+// Since we treat the a NULL Loss function as the Identity loss
+// function, rho = NULL is a valid input.
+//
+// Example usage
+//
+// Problem problem;
+//
+// // Add parameter blocks
+//
+// CostFunction* cost_function =
+// new AutoDiffCostFunction < UW_Camera_Mapper, 2, 9, 3>(
+// new UW_Camera_Mapper(feature_x, feature_y));
+//
+// LossFunctionWrapper* loss_function(new HuberLoss(1.0), TAKE_OWNERSHIP);
+//
+// problem.AddResidualBlock(cost_function, loss_function, parameters);
+//
+// Solver::Options options;
+// Solger::Summary summary;
+//
+// Solve(options, &problem, &summary)
+//
+// loss_function->Reset(new HuberLoss(1.0), TAKE_OWNERSHIP);
+//
+// Solve(options, &problem, &summary)
+//
+class CERES_EXPORT LossFunctionWrapper : public LossFunction {
+ public:
+ LossFunctionWrapper(LossFunction* rho, Ownership ownership)
+ : rho_(rho), ownership_(ownership) {
+ }
+
+ virtual ~LossFunctionWrapper() {
+ if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
+ rho_.release();
+ }
+ }
+
+ virtual void Evaluate(double sq_norm, double out[3]) const {
+ if (rho_.get() == NULL) {
+ out[0] = sq_norm;
+ out[1] = 1.0;
+ out[2] = 0.0;
+ }
+ else {
+ rho_->Evaluate(sq_norm, out);
+ }
+ }
+
+ void Reset(LossFunction* rho, Ownership ownership) {
+ if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
+ rho_.release();
+ }
+ rho_.reset(rho);
+ ownership_ = ownership;
+ }
+
+ private:
+ internal::scoped_ptr<const LossFunction> rho_;
+ Ownership ownership_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(LossFunctionWrapper);
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_LOSS_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/normal_prior.h b/extern/ceres/include/ceres/normal_prior.h
new file mode 100644
index 00000000000..cd98b4c846b
--- /dev/null
+++ b/extern/ceres/include/ceres/normal_prior.h
@@ -0,0 +1,78 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Cost term that implements a prior on a parameter block using a
+// normal distribution.
+
+#ifndef CERES_PUBLIC_NORMAL_PRIOR_H_
+#define CERES_PUBLIC_NORMAL_PRIOR_H_
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// Implements a cost function of the form
+//
+// cost(x) = ||A(x - b)||^2
+//
+// where, the matrix A and the vector b are fixed and x is the
+// variable. In case the user is interested in implementing a cost
+// function of the form
+//
+// cost(x) = (x - mu)^T S^{-1} (x - mu)
+//
+// where, mu is a vector and S is a covariance matrix, then, A =
+// S^{-1/2}, i.e the matrix A is the square root of the inverse of the
+// covariance, also known as the stiffness matrix. There are however
+// no restrictions on the shape of A. It is free to be rectangular,
+// which would be the case if the covariance matrix S is rank
+// deficient.
+
+class CERES_EXPORT NormalPrior: public CostFunction {
+ public:
+ // Check that the number of rows in the vector b are the same as the
+ // number of columns in the matrix A, crash otherwise.
+ NormalPrior(const Matrix& A, const Vector& b);
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const;
+ private:
+ Matrix A_;
+ Vector b_;
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_NORMAL_PRIOR_H_
diff --git a/extern/ceres/include/ceres/numeric_diff_cost_function.h b/extern/ceres/include/ceres/numeric_diff_cost_function.h
new file mode 100644
index 00000000000..fa96078df02
--- /dev/null
+++ b/extern/ceres/include/ceres/numeric_diff_cost_function.h
@@ -0,0 +1,342 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+//
+// Create CostFunctions as needed by the least squares framework with jacobians
+// computed via numeric (a.k.a. finite) differentiation. For more details see
+// http://en.wikipedia.org/wiki/Numerical_differentiation.
+//
+// To get an numerically differentiated cost function, you must define
+// a class with a operator() (a functor) that computes the residuals.
+//
+// The function must write the computed value in the last argument
+// (the only non-const one) and return true to indicate success.
+// Please see cost_function.h for details on how the return value
+// maybe used to impose simple constraints on the parameter block.
+//
+// For example, consider a scalar error e = k - x'y, where both x and y are
+// two-dimensional column vector parameters, the prime sign indicates
+// transposition, and k is a constant. The form of this error, which is the
+// difference between a constant and an expression, is a common pattern in least
+// squares problems. For example, the value x'y might be the model expectation
+// for a series of measurements, where there is an instance of the cost function
+// for each measurement k.
+//
+// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
+// the squaring is implicitly done by the optimization framework.
+//
+// To write an numerically-differentiable cost function for the above model, first
+// define the object
+//
+// class MyScalarCostFunctor {
+// MyScalarCostFunctor(double k): k_(k) {}
+//
+// bool operator()(const double* const x,
+// const double* const y,
+// double* residuals) const {
+// residuals[0] = k_ - x[0] * y[0] + x[1] * y[1];
+// return true;
+// }
+//
+// private:
+// double k_;
+// };
+//
+// Note that in the declaration of operator() the input parameters x
+// and y come first, and are passed as const pointers to arrays of
+// doubles. If there were three input parameters, then the third input
+// parameter would come after y. The output is always the last
+// parameter, and is also a pointer to an array. In the example above,
+// the residual is a scalar, so only residuals[0] is set.
+//
+// Then given this class definition, the numerically differentiated
+// cost function with central differences used for computing the
+// derivative can be constructed as follows.
+//
+// CostFunction* cost_function
+// = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
+// new MyScalarCostFunctor(1.0)); ^ ^ ^ ^
+// | | | |
+// Finite Differencing Scheme -+ | | |
+// Dimension of residual ------------+ | |
+// Dimension of x ----------------------+ |
+// Dimension of y -------------------------+
+//
+// In this example, there is usually an instance for each measurement of k.
+//
+// In the instantiation above, the template parameters following
+// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing
+// a 1-dimensional output from two arguments, both 2-dimensional.
+//
+// NumericDiffCostFunction also supports cost functions with a
+// runtime-determined number of residuals. For example:
+//
+// CostFunction* cost_function
+// = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
+// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
+// TAKE_OWNERSHIP, | | |
+// runtime_number_of_residuals); <----+ | | |
+// | | | |
+// | | | |
+// Actual number of residuals ------+ | | |
+// Indicate dynamic number of residuals --------------------+ | |
+// Dimension of x ------------------------------------------------+ |
+// Dimension of y ---------------------------------------------------+
+//
+// The framework can currently accommodate cost functions of up to 10
+// independent variables, and there is no limit on the dimensionality
+// of each of them.
+//
+// The central difference method is considerably more accurate at the cost of
+// twice as many function evaluations than forward difference. Consider using
+// central differences begin with, and only after that works, trying forward
+// difference to improve performance.
+//
+// WARNING #1: A common beginner's error when first using
+// NumericDiffCostFunction is to get the sizing wrong. In particular,
+// there is a tendency to set the template parameters to (dimension of
+// residual, number of parameters) instead of passing a dimension
+// parameter for *every parameter*. In the example above, that would
+// be <MyScalarCostFunctor, 1, 2>, which is missing the last '2'
+// argument. Please be careful when setting the size parameters.
+//
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+//
+// ALTERNATE INTERFACE
+//
+// For a variety of reasons, including compatibility with legacy code,
+// NumericDiffCostFunction can also take CostFunction objects as
+// input. The following describes how.
+//
+// To get a numerically differentiated cost function, define a
+// subclass of CostFunction such that the Evaluate() function ignores
+// the jacobian parameter. The numeric differentiation wrapper will
+// fill in the jacobian parameter if necessary by repeatedly calling
+// the Evaluate() function with small changes to the appropriate
+// parameters, and computing the slope. For performance, the numeric
+// differentiation wrapper class is templated on the concrete cost
+// function, even though it could be implemented only in terms of the
+// virtual CostFunction interface.
+//
+// The numerically differentiated version of a cost function for a cost function
+// can be constructed as follows:
+//
+// CostFunction* cost_function
+// = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
+// new MyCostFunction(...), TAKE_OWNERSHIP);
+//
+// where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
+// respectively. Look at the tests for a more detailed example.
+//
+// TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives.
+
+#ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
+#define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
+
+#include "Eigen/Dense"
+#include "ceres/cost_function.h"
+#include "ceres/internal/numeric_diff.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/numeric_diff_options.h"
+#include "ceres/sized_cost_function.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+template <typename CostFunctor,
+ NumericDiffMethodType method = CENTRAL,
+ int kNumResiduals = 0, // Number of residuals, or ceres::DYNAMIC
+ int N0 = 0, // Number of parameters in block 0.
+ int N1 = 0, // Number of parameters in block 1.
+ int N2 = 0, // Number of parameters in block 2.
+ int N3 = 0, // Number of parameters in block 3.
+ int N4 = 0, // Number of parameters in block 4.
+ int N5 = 0, // Number of parameters in block 5.
+ int N6 = 0, // Number of parameters in block 6.
+ int N7 = 0, // Number of parameters in block 7.
+ int N8 = 0, // Number of parameters in block 8.
+ int N9 = 0> // Number of parameters in block 9.
+class NumericDiffCostFunction
+ : public SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9> {
+ public:
+ NumericDiffCostFunction(
+ CostFunctor* functor,
+ Ownership ownership = TAKE_OWNERSHIP,
+ int num_residuals = kNumResiduals,
+ const NumericDiffOptions& options = NumericDiffOptions())
+ : functor_(functor),
+ ownership_(ownership),
+ options_(options) {
+ if (kNumResiduals == DYNAMIC) {
+ SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9>
+ ::set_num_residuals(num_residuals);
+ }
+ }
+
+ // Deprecated. New users should avoid using this constructor. Instead, use the
+ // constructor with NumericDiffOptions.
+ NumericDiffCostFunction(CostFunctor* functor,
+ Ownership ownership,
+ int num_residuals,
+ const double relative_step_size)
+ :functor_(functor),
+ ownership_(ownership),
+ options_() {
+ LOG(WARNING) << "This constructor is deprecated and will be removed in "
+ "a future version. Please use the NumericDiffOptions "
+ "constructor instead.";
+
+ if (kNumResiduals == DYNAMIC) {
+ SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9>
+ ::set_num_residuals(num_residuals);
+ }
+
+ options_.relative_step_size = relative_step_size;
+ }
+
+ ~NumericDiffCostFunction() {
+ if (ownership_ != TAKE_OWNERSHIP) {
+ functor_.release();
+ }
+ }
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ using internal::FixedArray;
+ using internal::NumericDiff;
+
+ const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
+ const int kNumParameterBlocks =
+ (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
+ (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
+
+ // Get the function value (residuals) at the the point to evaluate.
+ if (!internal::EvaluateImpl<CostFunctor,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor_.get(),
+ parameters,
+ residuals,
+ functor_.get())) {
+ return false;
+ }
+
+ if (jacobians == NULL) {
+ return true;
+ }
+
+ // Create a copy of the parameters which will get mutated.
+ FixedArray<double> parameters_copy(kNumParameters);
+ FixedArray<double*> parameters_reference_copy(kNumParameterBlocks);
+
+ parameters_reference_copy[0] = parameters_copy.get();
+ if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0;
+ if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1;
+ if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2;
+ if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3;
+ if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4;
+ if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5;
+ if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6;
+ if (N8) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
+ if (N9) parameters_reference_copy[9] = parameters_reference_copy[8] + N8;
+
+#define CERES_COPY_PARAMETER_BLOCK(block) \
+ if (N ## block) memcpy(parameters_reference_copy[block], \
+ parameters[block], \
+ sizeof(double) * N ## block); // NOLINT
+
+ CERES_COPY_PARAMETER_BLOCK(0);
+ CERES_COPY_PARAMETER_BLOCK(1);
+ CERES_COPY_PARAMETER_BLOCK(2);
+ CERES_COPY_PARAMETER_BLOCK(3);
+ CERES_COPY_PARAMETER_BLOCK(4);
+ CERES_COPY_PARAMETER_BLOCK(5);
+ CERES_COPY_PARAMETER_BLOCK(6);
+ CERES_COPY_PARAMETER_BLOCK(7);
+ CERES_COPY_PARAMETER_BLOCK(8);
+ CERES_COPY_PARAMETER_BLOCK(9);
+
+#undef CERES_COPY_PARAMETER_BLOCK
+
+#define CERES_EVALUATE_JACOBIAN_FOR_BLOCK(block) \
+ if (N ## block && jacobians[block] != NULL) { \
+ if (!NumericDiff<CostFunctor, \
+ method, \
+ kNumResiduals, \
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, \
+ block, \
+ N ## block >::EvaluateJacobianForParameterBlock( \
+ functor_.get(), \
+ residuals, \
+ options_, \
+ SizedCostFunction<kNumResiduals, \
+ N0, N1, N2, N3, N4, \
+ N5, N6, N7, N8, N9>::num_residuals(), \
+ block, \
+ N ## block, \
+ parameters_reference_copy.get(), \
+ jacobians[block])) { \
+ return false; \
+ } \
+ }
+
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(0);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(1);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(2);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(3);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(4);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(5);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(6);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(7);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(8);
+ CERES_EVALUATE_JACOBIAN_FOR_BLOCK(9);
+
+#undef CERES_EVALUATE_JACOBIAN_FOR_BLOCK
+
+ return true;
+ }
+
+ private:
+ internal::scoped_ptr<CostFunctor> functor_;
+ Ownership ownership_;
+ NumericDiffOptions options_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/numeric_diff_options.h b/extern/ceres/include/ceres/numeric_diff_options.h
new file mode 100644
index 00000000000..119c8a86596
--- /dev/null
+++ b/extern/ceres/include/ceres/numeric_diff_options.h
@@ -0,0 +1,79 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: tbennun@gmail.com (Tal Ben-Nun)
+//
+
+#ifndef CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
+#define CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
+
+namespace ceres {
+
+// Options pertaining to numeric differentiation (e.g., convergence criteria,
+// step sizes).
+struct CERES_EXPORT NumericDiffOptions {
+ NumericDiffOptions() {
+ relative_step_size = 1e-6;
+ ridders_relative_initial_step_size = 1e-2;
+ max_num_ridders_extrapolations = 10;
+ ridders_epsilon = 1e-12;
+ ridders_step_shrink_factor = 2.0;
+ }
+
+ // Numeric differentiation step size (multiplied by parameter block's
+ // order of magnitude). If parameters are close to zero, the step size
+ // is set to sqrt(machine_epsilon).
+ double relative_step_size;
+
+ // Initial step size for Ridders adaptive numeric differentiation (multiplied
+ // by parameter block's order of magnitude).
+ // If parameters are close to zero, Ridders' method sets the step size
+ // directly to this value. This parameter is separate from
+ // "relative_step_size" in order to set a different default value.
+ //
+ // Note: For Ridders' method to converge, the step size should be initialized
+ // to a value that is large enough to produce a significant change in the
+ // function. As the derivative is estimated, the step size decreases.
+ double ridders_relative_initial_step_size;
+
+ // Maximal number of adaptive extrapolations (sampling) in Ridders' method.
+ int max_num_ridders_extrapolations;
+
+ // Convergence criterion on extrapolation error for Ridders adaptive
+ // differentiation. The available error estimation methods are defined in
+ // NumericDiffErrorType and set in the "ridders_error_method" field.
+ double ridders_epsilon;
+
+ // The factor in which to shrink the step size with each extrapolation in
+ // Ridders' method.
+ double ridders_step_shrink_factor;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
diff --git a/extern/ceres/include/ceres/ordered_groups.h b/extern/ceres/include/ceres/ordered_groups.h
new file mode 100644
index 00000000000..aa1bd3a7da1
--- /dev/null
+++ b/extern/ceres/include/ceres/ordered_groups.h
@@ -0,0 +1,208 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_ORDERED_GROUPS_H_
+#define CERES_PUBLIC_ORDERED_GROUPS_H_
+
+#include <map>
+#include <set>
+#include <vector>
+#include "ceres/internal/port.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// A class for storing and manipulating an ordered collection of
+// groups/sets with the following semantics:
+//
+// Group ids are non-negative integer values. Elements are any type
+// that can serve as a key in a map or an element of a set.
+//
+// An element can only belong to one group at a time. A group may
+// contain an arbitrary number of elements.
+//
+// Groups are ordered by their group id.
+template <typename T>
+class OrderedGroups {
+ public:
+ // Add an element to a group. If a group with this id does not
+ // exist, one is created. This method can be called any number of
+ // times for the same element. Group ids should be non-negative
+ // numbers.
+ //
+ // Return value indicates if adding the element was a success.
+ bool AddElementToGroup(const T element, const int group) {
+ if (group < 0) {
+ return false;
+ }
+
+ typename std::map<T, int>::const_iterator it =
+ element_to_group_.find(element);
+ if (it != element_to_group_.end()) {
+ if (it->second == group) {
+ // Element is already in the right group, nothing to do.
+ return true;
+ }
+
+ group_to_elements_[it->second].erase(element);
+ if (group_to_elements_[it->second].size() == 0) {
+ group_to_elements_.erase(it->second);
+ }
+ }
+
+ element_to_group_[element] = group;
+ group_to_elements_[group].insert(element);
+ return true;
+ }
+
+ void Clear() {
+ group_to_elements_.clear();
+ element_to_group_.clear();
+ }
+
+ // Remove the element, no matter what group it is in. Return value
+ // indicates if the element was actually removed.
+ bool Remove(const T element) {
+ const int current_group = GroupId(element);
+ if (current_group < 0) {
+ return false;
+ }
+
+ group_to_elements_[current_group].erase(element);
+
+ if (group_to_elements_[current_group].size() == 0) {
+ // If the group is empty, then get rid of it.
+ group_to_elements_.erase(current_group);
+ }
+
+ element_to_group_.erase(element);
+ return true;
+ }
+
+ // Bulk remove elements. The return value indicates the number of
+ // elements successfully removed.
+ int Remove(const std::vector<T>& elements) {
+ if (NumElements() == 0 || elements.size() == 0) {
+ return 0;
+ }
+
+ int num_removed = 0;
+ for (int i = 0; i < elements.size(); ++i) {
+ num_removed += Remove(elements[i]);
+ }
+ return num_removed;
+ }
+
+ // Reverse the order of the groups in place.
+ void Reverse() {
+ if (NumGroups() == 0) {
+ return;
+ }
+
+ typename std::map<int, std::set<T> >::reverse_iterator it =
+ group_to_elements_.rbegin();
+ std::map<int, std::set<T> > new_group_to_elements;
+ new_group_to_elements[it->first] = it->second;
+
+ int new_group_id = it->first + 1;
+ for (++it; it != group_to_elements_.rend(); ++it) {
+ for (typename std::set<T>::const_iterator element_it = it->second.begin();
+ element_it != it->second.end();
+ ++element_it) {
+ element_to_group_[*element_it] = new_group_id;
+ }
+ new_group_to_elements[new_group_id] = it->second;
+ new_group_id++;
+ }
+
+ group_to_elements_.swap(new_group_to_elements);
+ }
+
+ // Return the group id for the element. If the element is not a
+ // member of any group, return -1.
+ int GroupId(const T element) const {
+ typename std::map<T, int>::const_iterator it =
+ element_to_group_.find(element);
+ if (it == element_to_group_.end()) {
+ return -1;
+ }
+ return it->second;
+ }
+
+ bool IsMember(const T element) const {
+ typename std::map<T, int>::const_iterator it =
+ element_to_group_.find(element);
+ return (it != element_to_group_.end());
+ }
+
+ // This function always succeeds, i.e., implicitly there exists a
+ // group for every integer.
+ int GroupSize(const int group) const {
+ typename std::map<int, std::set<T> >::const_iterator it =
+ group_to_elements_.find(group);
+ return (it == group_to_elements_.end()) ? 0 : it->second.size();
+ }
+
+ int NumElements() const {
+ return element_to_group_.size();
+ }
+
+ // Number of groups with one or more elements.
+ int NumGroups() const {
+ return group_to_elements_.size();
+ }
+
+ // The first group with one or more elements. Calling this when
+ // there are no groups with non-zero elements will result in a
+ // crash.
+ int MinNonZeroGroup() const {
+ CHECK_NE(NumGroups(), 0);
+ return group_to_elements_.begin()->first;
+ }
+
+ const std::map<int, std::set<T> >& group_to_elements() const {
+ return group_to_elements_;
+ }
+
+ const std::map<T, int>& element_to_group() const {
+ return element_to_group_;
+ }
+
+ private:
+ std::map<int, std::set<T> > group_to_elements_;
+ std::map<T, int> element_to_group_;
+};
+
+// Typedef for the most commonly used version of OrderedGroups.
+typedef OrderedGroups<double*> ParameterBlockOrdering;
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_ORDERED_GROUP_H_
diff --git a/extern/ceres/include/ceres/problem.h b/extern/ceres/include/ceres/problem.h
new file mode 100644
index 00000000000..409274c62c2
--- /dev/null
+++ b/extern/ceres/include/ceres/problem.h
@@ -0,0 +1,481 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// keir@google.com (Keir Mierle)
+//
+// The Problem object is used to build and hold least squares problems.
+
+#ifndef CERES_PUBLIC_PROBLEM_H_
+#define CERES_PUBLIC_PROBLEM_H_
+
+#include <cstddef>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "glog/logging.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+
+namespace ceres {
+
+class CostFunction;
+class LossFunction;
+class LocalParameterization;
+class Solver;
+struct CRSMatrix;
+
+namespace internal {
+class Preprocessor;
+class ProblemImpl;
+class ParameterBlock;
+class ResidualBlock;
+} // namespace internal
+
+// A ResidualBlockId is an opaque handle clients can use to remove residual
+// blocks from a Problem after adding them.
+typedef internal::ResidualBlock* ResidualBlockId;
+
+// A class to represent non-linear least squares problems. Such
+// problems have a cost function that is a sum of error terms (known
+// as "residuals"), where each residual is a function of some subset
+// of the parameters. The cost function takes the form
+//
+// N 1
+// SUM --- loss( || r_i1, r_i2,..., r_ik ||^2 ),
+// i=1 2
+//
+// where
+//
+// r_ij is residual number i, component j; the residual is a
+// function of some subset of the parameters x1...xk. For
+// example, in a structure from motion problem a residual
+// might be the difference between a measured point in an
+// image and the reprojected position for the matching
+// camera, point pair. The residual would have two
+// components, error in x and error in y.
+//
+// loss(y) is the loss function; for example, squared error or
+// Huber L1 loss. If loss(y) = y, then the cost function is
+// non-robustified least squares.
+//
+// This class is specifically designed to address the important subset
+// of "sparse" least squares problems, where each component of the
+// residual depends only on a small number number of parameters, even
+// though the total number of residuals and parameters may be very
+// large. This property affords tremendous gains in scale, allowing
+// efficient solving of large problems that are otherwise
+// inaccessible.
+//
+// The canonical example of a sparse least squares problem is
+// "structure-from-motion" (SFM), where the parameters are points and
+// cameras, and residuals are reprojection errors. Typically a single
+// residual will depend only on 9 parameters (3 for the point, 6 for
+// the camera).
+//
+// To create a least squares problem, use the AddResidualBlock() and
+// AddParameterBlock() methods, documented below. Here is an example least
+// squares problem containing 3 parameter blocks of sizes 3, 4 and 5
+// respectively and two residual terms of size 2 and 6:
+//
+// double x1[] = { 1.0, 2.0, 3.0 };
+// double x2[] = { 1.0, 2.0, 3.0, 5.0 };
+// double x3[] = { 1.0, 2.0, 3.0, 6.0, 7.0 };
+//
+// Problem problem;
+//
+// problem.AddResidualBlock(new MyUnaryCostFunction(...), x1);
+// problem.AddResidualBlock(new MyBinaryCostFunction(...), x2, x3);
+//
+// Please see cost_function.h for details of the CostFunction object.
+class CERES_EXPORT Problem {
+ public:
+ struct CERES_EXPORT Options {
+ Options()
+ : cost_function_ownership(TAKE_OWNERSHIP),
+ loss_function_ownership(TAKE_OWNERSHIP),
+ local_parameterization_ownership(TAKE_OWNERSHIP),
+ enable_fast_removal(false),
+ disable_all_safety_checks(false) {}
+
+ // These flags control whether the Problem object owns the cost
+ // functions, loss functions, and parameterizations passed into
+ // the Problem. If set to TAKE_OWNERSHIP, then the problem object
+ // will delete the corresponding cost or loss functions on
+ // destruction. The destructor is careful to delete the pointers
+ // only once, since sharing cost/loss/parameterizations is
+ // allowed.
+ Ownership cost_function_ownership;
+ Ownership loss_function_ownership;
+ Ownership local_parameterization_ownership;
+
+ // If true, trades memory for faster RemoveResidualBlock() and
+ // RemoveParameterBlock() operations.
+ //
+ // By default, RemoveParameterBlock() and RemoveResidualBlock() take time
+ // proportional to the size of the entire problem. If you only ever remove
+ // parameters or residuals from the problem occassionally, this might be
+ // acceptable. However, if you have memory to spare, enable this option to
+ // make RemoveParameterBlock() take time proportional to the number of
+ // residual blocks that depend on it, and RemoveResidualBlock() take (on
+ // average) constant time.
+ //
+ // The increase in memory usage is twofold: an additonal hash set per
+ // parameter block containing all the residuals that depend on the parameter
+ // block; and a hash set in the problem containing all residuals.
+ bool enable_fast_removal;
+
+ // By default, Ceres performs a variety of safety checks when constructing
+ // the problem. There is a small but measurable performance penalty to
+ // these checks, typically around 5% of construction time. If you are sure
+ // your problem construction is correct, and 5% of the problem construction
+ // time is truly an overhead you want to avoid, then you can set
+ // disable_all_safety_checks to true.
+ //
+ // WARNING: Do not set this to true, unless you are absolutely sure of what
+ // you are doing.
+ bool disable_all_safety_checks;
+ };
+
+ // The default constructor is equivalent to the
+ // invocation Problem(Problem::Options()).
+ Problem();
+ explicit Problem(const Options& options);
+
+ ~Problem();
+
+ // Add a residual block to the overall cost function. The cost
+ // function carries with it information about the sizes of the
+ // parameter blocks it expects. The function checks that these match
+ // the sizes of the parameter blocks listed in parameter_blocks. The
+ // program aborts if a mismatch is detected. loss_function can be
+ // NULL, in which case the cost of the term is just the squared norm
+ // of the residuals.
+ //
+ // The user has the option of explicitly adding the parameter blocks
+ // using AddParameterBlock. This causes additional correctness
+ // checking; however, AddResidualBlock implicitly adds the parameter
+ // blocks if they are not present, so calling AddParameterBlock
+ // explicitly is not required.
+ //
+ // The Problem object by default takes ownership of the
+ // cost_function and loss_function pointers. These objects remain
+ // live for the life of the Problem object. If the user wishes to
+ // keep control over the destruction of these objects, then they can
+ // do this by setting the corresponding enums in the Options struct.
+ //
+ // Note: Even though the Problem takes ownership of cost_function
+ // and loss_function, it does not preclude the user from re-using
+ // them in another residual block. The destructor takes care to call
+ // delete on each cost_function or loss_function pointer only once,
+ // regardless of how many residual blocks refer to them.
+ //
+ // Example usage:
+ //
+ // double x1[] = {1.0, 2.0, 3.0};
+ // double x2[] = {1.0, 2.0, 5.0, 6.0};
+ // double x3[] = {3.0, 6.0, 2.0, 5.0, 1.0};
+ //
+ // Problem problem;
+ //
+ // problem.AddResidualBlock(new MyUnaryCostFunction(...), NULL, x1);
+ // problem.AddResidualBlock(new MyBinaryCostFunction(...), NULL, x2, x1);
+ //
+ ResidualBlockId AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ const std::vector<double*>& parameter_blocks);
+
+ // Convenience methods for adding residuals with a small number of
+ // parameters. This is the common case. Instead of specifying the
+ // parameter block arguments as a vector, list them as pointers.
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8,
+ double* x9);
+
+ // Add a parameter block with appropriate size to the problem.
+ // Repeated calls with the same arguments are ignored. Repeated
+ // calls with the same double pointer but a different size results
+ // in undefined behaviour.
+ void AddParameterBlock(double* values, int size);
+
+ // Add a parameter block with appropriate size and parameterization
+ // to the problem. Repeated calls with the same arguments are
+ // ignored. Repeated calls with the same double pointer but a
+ // different size results in undefined behaviour.
+ void AddParameterBlock(double* values,
+ int size,
+ LocalParameterization* local_parameterization);
+
+ // Remove a parameter block from the problem. The parameterization of the
+ // parameter block, if it exists, will persist until the deletion of the
+ // problem (similar to cost/loss functions in residual block removal). Any
+ // residual blocks that depend on the parameter are also removed, as
+ // described above in RemoveResidualBlock().
+ //
+ // If Problem::Options::enable_fast_removal is true, then the
+ // removal is fast (almost constant time). Otherwise, removing a parameter
+ // block will incur a scan of the entire Problem object.
+ //
+ // WARNING: Removing a residual or parameter block will destroy the implicit
+ // ordering, rendering the jacobian or residuals returned from the solver
+ // uninterpretable. If you depend on the evaluated jacobian, do not use
+ // remove! This may change in a future release.
+ void RemoveParameterBlock(double* values);
+
+ // Remove a residual block from the problem. Any parameters that the residual
+ // block depends on are not removed. The cost and loss functions for the
+ // residual block will not get deleted immediately; won't happen until the
+ // problem itself is deleted.
+ //
+ // WARNING: Removing a residual or parameter block will destroy the implicit
+ // ordering, rendering the jacobian or residuals returned from the solver
+ // uninterpretable. If you depend on the evaluated jacobian, do not use
+ // remove! This may change in a future release.
+ void RemoveResidualBlock(ResidualBlockId residual_block);
+
+ // Hold the indicated parameter block constant during optimization.
+ void SetParameterBlockConstant(double* values);
+
+ // Allow the indicated parameter block to vary during optimization.
+ void SetParameterBlockVariable(double* values);
+
+ // Set the local parameterization for one of the parameter blocks.
+ // The local_parameterization is owned by the Problem by default. It
+ // is acceptable to set the same parameterization for multiple
+ // parameters; the destructor is careful to delete local
+ // parameterizations only once. The local parameterization can only
+ // be set once per parameter, and cannot be changed once set.
+ void SetParameterization(double* values,
+ LocalParameterization* local_parameterization);
+
+ // Get the local parameterization object associated with this
+ // parameter block. If there is no parameterization object
+ // associated then NULL is returned.
+ const LocalParameterization* GetParameterization(double* values) const;
+
+ // Set the lower/upper bound for the parameter with position "index".
+ void SetParameterLowerBound(double* values, int index, double lower_bound);
+ void SetParameterUpperBound(double* values, int index, double upper_bound);
+
+ // Number of parameter blocks in the problem. Always equals
+ // parameter_blocks().size() and parameter_block_sizes().size().
+ int NumParameterBlocks() const;
+
+ // The size of the parameter vector obtained by summing over the
+ // sizes of all the parameter blocks.
+ int NumParameters() const;
+
+ // Number of residual blocks in the problem. Always equals
+ // residual_blocks().size().
+ int NumResidualBlocks() const;
+
+ // The size of the residual vector obtained by summing over the
+ // sizes of all of the residual blocks.
+ int NumResiduals() const;
+
+ // The size of the parameter block.
+ int ParameterBlockSize(const double* values) const;
+
+ // The size of local parameterization for the parameter block. If
+ // there is no local parameterization associated with this parameter
+ // block, then ParameterBlockLocalSize = ParameterBlockSize.
+ int ParameterBlockLocalSize(const double* values) const;
+
+ // Is the given parameter block present in this problem or not?
+ bool HasParameterBlock(const double* values) const;
+
+ // Fills the passed parameter_blocks vector with pointers to the
+ // parameter blocks currently in the problem. After this call,
+ // parameter_block.size() == NumParameterBlocks.
+ void GetParameterBlocks(std::vector<double*>* parameter_blocks) const;
+
+ // Fills the passed residual_blocks vector with pointers to the
+ // residual blocks currently in the problem. After this call,
+ // residual_blocks.size() == NumResidualBlocks.
+ void GetResidualBlocks(std::vector<ResidualBlockId>* residual_blocks) const;
+
+ // Get all the parameter blocks that depend on the given residual block.
+ void GetParameterBlocksForResidualBlock(
+ const ResidualBlockId residual_block,
+ std::vector<double*>* parameter_blocks) const;
+
+ // Get the CostFunction for the given residual block.
+ const CostFunction* GetCostFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const;
+
+ // Get the LossFunction for the given residual block. Returns NULL
+ // if no loss function is associated with this residual block.
+ const LossFunction* GetLossFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const;
+
+ // Get all the residual blocks that depend on the given parameter block.
+ //
+ // If Problem::Options::enable_fast_removal is true, then
+ // getting the residual blocks is fast and depends only on the number of
+ // residual blocks. Otherwise, getting the residual blocks for a parameter
+ // block will incur a scan of the entire Problem object.
+ void GetResidualBlocksForParameterBlock(
+ const double* values,
+ std::vector<ResidualBlockId>* residual_blocks) const;
+
+ // Options struct to control Problem::Evaluate.
+ struct EvaluateOptions {
+ EvaluateOptions()
+ : apply_loss_function(true),
+ num_threads(1) {
+ }
+
+ // The set of parameter blocks for which evaluation should be
+ // performed. This vector determines the order that parameter
+ // blocks occur in the gradient vector and in the columns of the
+ // jacobian matrix. If parameter_blocks is empty, then it is
+ // assumed to be equal to vector containing ALL the parameter
+ // blocks. Generally speaking the parameter blocks will occur in
+ // the order in which they were added to the problem. But, this
+ // may change if the user removes any parameter blocks from the
+ // problem.
+ //
+ // NOTE: This vector should contain the same pointers as the ones
+ // used to add parameter blocks to the Problem. These parameter
+ // block should NOT point to new memory locations. Bad things will
+ // happen otherwise.
+ std::vector<double*> parameter_blocks;
+
+ // The set of residual blocks to evaluate. This vector determines
+ // the order in which the residuals occur, and how the rows of the
+ // jacobian are ordered. If residual_blocks is empty, then it is
+ // assumed to be equal to the vector containing ALL the residual
+ // blocks. Generally speaking the residual blocks will occur in
+ // the order in which they were added to the problem. But, this
+ // may change if the user removes any residual blocks from the
+ // problem.
+ std::vector<ResidualBlockId> residual_blocks;
+
+ // Even though the residual blocks in the problem may contain loss
+ // functions, setting apply_loss_function to false will turn off
+ // the application of the loss function to the output of the cost
+ // function. This is of use for example if the user wishes to
+ // analyse the solution quality by studying the distribution of
+ // residuals before and after the solve.
+ bool apply_loss_function;
+
+ int num_threads;
+ };
+
+ // Evaluate Problem. Any of the output pointers can be NULL. Which
+ // residual blocks and parameter blocks are used is controlled by
+ // the EvaluateOptions struct above.
+ //
+ // Note 1: The evaluation will use the values stored in the memory
+ // locations pointed to by the parameter block pointers used at the
+ // time of the construction of the problem. i.e.,
+ //
+ // Problem problem;
+ // double x = 1;
+ // problem.AddResidualBlock(new MyCostFunction, NULL, &x);
+ //
+ // double cost = 0.0;
+ // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
+ //
+ // The cost is evaluated at x = 1. If you wish to evaluate the
+ // problem at x = 2, then
+ //
+ // x = 2;
+ // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
+ //
+ // is the way to do so.
+ //
+ // Note 2: If no local parameterizations are used, then the size of
+ // the gradient vector (and the number of columns in the jacobian)
+ // is the sum of the sizes of all the parameter blocks. If a
+ // parameter block has a local parameterization, then it contributes
+ // "LocalSize" entries to the gradient vector (and the number of
+ // columns in the jacobian).
+ bool Evaluate(const EvaluateOptions& options,
+ double* cost,
+ std::vector<double>* residuals,
+ std::vector<double>* gradient,
+ CRSMatrix* jacobian);
+
+ private:
+ friend class Solver;
+ friend class Covariance;
+ internal::scoped_ptr<internal::ProblemImpl> problem_impl_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(Problem);
+};
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_PROBLEM_H_
diff --git a/extern/ceres/include/ceres/rotation.h b/extern/ceres/include/ceres/rotation.h
new file mode 100644
index 00000000000..e9496d772e4
--- /dev/null
+++ b/extern/ceres/include/ceres/rotation.h
@@ -0,0 +1,629 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+//
+// Templated functions for manipulating rotations. The templated
+// functions are useful when implementing functors for automatic
+// differentiation.
+//
+// In the following, the Quaternions are laid out as 4-vectors, thus:
+//
+// q[0] scalar part.
+// q[1] coefficient of i.
+// q[2] coefficient of j.
+// q[3] coefficient of k.
+//
+// where: i*i = j*j = k*k = -1 and i*j = k, j*k = i, k*i = j.
+
+#ifndef CERES_PUBLIC_ROTATION_H_
+#define CERES_PUBLIC_ROTATION_H_
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include "glog/logging.h"
+
+namespace ceres {
+
+// Trivial wrapper to index linear arrays as matrices, given a fixed
+// column and row stride. When an array "T* array" is wrapped by a
+//
+// (const) MatrixAdapter<T, row_stride, col_stride> M"
+//
+// the expression M(i, j) is equivalent to
+//
+// arrary[i * row_stride + j * col_stride]
+//
+// Conversion functions to and from rotation matrices accept
+// MatrixAdapters to permit using row-major and column-major layouts,
+// and rotation matrices embedded in larger matrices (such as a 3x4
+// projection matrix).
+template <typename T, int row_stride, int col_stride>
+struct MatrixAdapter;
+
+// Convenience functions to create a MatrixAdapter that treats the
+// array pointed to by "pointer" as a 3x3 (contiguous) column-major or
+// row-major matrix.
+template <typename T>
+MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer);
+
+template <typename T>
+MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer);
+
+// Convert a value in combined axis-angle representation to a quaternion.
+// The value angle_axis is a triple whose norm is an angle in radians,
+// and whose direction is aligned with the axis of rotation,
+// and quaternion is a 4-tuple that will contain the resulting quaternion.
+// The implementation may be used with auto-differentiation up to the first
+// derivative, higher derivatives may have unexpected results near the origin.
+template<typename T>
+void AngleAxisToQuaternion(const T* angle_axis, T* quaternion);
+
+// Convert a quaternion to the equivalent combined axis-angle representation.
+// The value quaternion must be a unit quaternion - it is not normalized first,
+// and angle_axis will be filled with a value whose norm is the angle of
+// rotation in radians, and whose direction is the axis of rotation.
+// The implemention may be used with auto-differentiation up to the first
+// derivative, higher derivatives may have unexpected results near the origin.
+template<typename T>
+void QuaternionToAngleAxis(const T* quaternion, T* angle_axis);
+
+// Conversions between 3x3 rotation matrix (in column major order) and
+// quaternion rotation representations. Templated for use with
+// autodifferentiation.
+template <typename T>
+void RotationMatrixToQuaternion(const T* R, T* quaternion);
+
+template <typename T, int row_stride, int col_stride>
+void RotationMatrixToQuaternion(
+ const MatrixAdapter<const T, row_stride, col_stride>& R,
+ T* quaternion);
+
+// Conversions between 3x3 rotation matrix (in column major order) and
+// axis-angle rotation representations. Templated for use with
+// autodifferentiation.
+template <typename T>
+void RotationMatrixToAngleAxis(const T* R, T* angle_axis);
+
+template <typename T, int row_stride, int col_stride>
+void RotationMatrixToAngleAxis(
+ const MatrixAdapter<const T, row_stride, col_stride>& R,
+ T* angle_axis);
+
+template <typename T>
+void AngleAxisToRotationMatrix(const T* angle_axis, T* R);
+
+template <typename T, int row_stride, int col_stride>
+void AngleAxisToRotationMatrix(
+ const T* angle_axis,
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
+// Conversions between 3x3 rotation matrix (in row major order) and
+// Euler angle (in degrees) rotation representations.
+//
+// The {pitch,roll,yaw} Euler angles are rotations around the {x,y,z}
+// axes, respectively. They are applied in that same order, so the
+// total rotation R is Rz * Ry * Rx.
+template <typename T>
+void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
+
+template <typename T, int row_stride, int col_stride>
+void EulerAnglesToRotationMatrix(
+ const T* euler,
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
+// Convert a 4-vector to a 3x3 scaled rotation matrix.
+//
+// The choice of rotation is such that the quaternion [1 0 0 0] goes to an
+// identity matrix and for small a, b, c the quaternion [1 a b c] goes to
+// the matrix
+//
+// [ 0 -c b ]
+// I + 2 [ c 0 -a ] + higher order terms
+// [ -b a 0 ]
+//
+// which corresponds to a Rodrigues approximation, the last matrix being
+// the cross-product matrix of [a b c]. Together with the property that
+// R(q1 * q2) = R(q1) * R(q2) this uniquely defines the mapping from q to R.
+//
+// No normalization of the quaternion is performed, i.e.
+// R = ||q||^2 * Q, where Q is an orthonormal matrix
+// such that det(Q) = 1 and Q*Q' = I
+//
+// WARNING: The rotation matrix is ROW MAJOR
+template <typename T> inline
+void QuaternionToScaledRotation(const T q[4], T R[3 * 3]);
+
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToScaledRotation(
+ const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
+// Same as above except that the rotation matrix is normalized by the
+// Frobenius norm, so that R * R' = I (and det(R) = 1).
+//
+// WARNING: The rotation matrix is ROW MAJOR
+template <typename T> inline
+void QuaternionToRotation(const T q[4], T R[3 * 3]);
+
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToRotation(
+ const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R);
+
+// Rotates a point pt by a quaternion q:
+//
+// result = R(q) * pt
+//
+// Assumes the quaternion is unit norm. This assumption allows us to
+// write the transform as (something)*pt + pt, as is clear from the
+// formula below. If you pass in a quaternion with |q|^2 = 2 then you
+// WILL NOT get back 2 times the result you get for a unit quaternion.
+template <typename T> inline
+void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
+
+// With this function you do not need to assume that q has unit norm.
+// It does assume that the norm is non-zero.
+template <typename T> inline
+void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
+
+// zw = z * w, where * is the Quaternion product between 4 vectors.
+template<typename T> inline
+void QuaternionProduct(const T z[4], const T w[4], T zw[4]);
+
+// xy = x cross y;
+template<typename T> inline
+void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]);
+
+template<typename T> inline
+T DotProduct(const T x[3], const T y[3]);
+
+// y = R(angle_axis) * x;
+template<typename T> inline
+void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]);
+
+// --- IMPLEMENTATION
+
+template<typename T, int row_stride, int col_stride>
+struct MatrixAdapter {
+ T* pointer_;
+ explicit MatrixAdapter(T* pointer)
+ : pointer_(pointer)
+ {}
+
+ T& operator()(int r, int c) const {
+ return pointer_[r * row_stride + c * col_stride];
+ }
+};
+
+template <typename T>
+MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer) {
+ return MatrixAdapter<T, 1, 3>(pointer);
+}
+
+template <typename T>
+MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer) {
+ return MatrixAdapter<T, 3, 1>(pointer);
+}
+
+template<typename T>
+inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
+ const T& a0 = angle_axis[0];
+ const T& a1 = angle_axis[1];
+ const T& a2 = angle_axis[2];
+ const T theta_squared = a0 * a0 + a1 * a1 + a2 * a2;
+
+ // For points not at the origin, the full conversion is numerically stable.
+ if (theta_squared > T(0.0)) {
+ const T theta = sqrt(theta_squared);
+ const T half_theta = theta * T(0.5);
+ const T k = sin(half_theta) / theta;
+ quaternion[0] = cos(half_theta);
+ quaternion[1] = a0 * k;
+ quaternion[2] = a1 * k;
+ quaternion[3] = a2 * k;
+ } else {
+ // At the origin, sqrt() will produce NaN in the derivative since
+ // the argument is zero. By approximating with a Taylor series,
+ // and truncating at one term, the value and first derivatives will be
+ // computed correctly when Jets are used.
+ const T k(0.5);
+ quaternion[0] = T(1.0);
+ quaternion[1] = a0 * k;
+ quaternion[2] = a1 * k;
+ quaternion[3] = a2 * k;
+ }
+}
+
+template<typename T>
+inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
+ const T& q1 = quaternion[1];
+ const T& q2 = quaternion[2];
+ const T& q3 = quaternion[3];
+ const T sin_squared_theta = q1 * q1 + q2 * q2 + q3 * q3;
+
+ // For quaternions representing non-zero rotation, the conversion
+ // is numerically stable.
+ if (sin_squared_theta > T(0.0)) {
+ const T sin_theta = sqrt(sin_squared_theta);
+ const T& cos_theta = quaternion[0];
+
+ // If cos_theta is negative, theta is greater than pi/2, which
+ // means that angle for the angle_axis vector which is 2 * theta
+ // would be greater than pi.
+ //
+ // While this will result in the correct rotation, it does not
+ // result in a normalized angle-axis vector.
+ //
+ // In that case we observe that 2 * theta ~ 2 * theta - 2 * pi,
+ // which is equivalent saying
+ //
+ // theta - pi = atan(sin(theta - pi), cos(theta - pi))
+ // = atan(-sin(theta), -cos(theta))
+ //
+ const T two_theta =
+ T(2.0) * ((cos_theta < 0.0)
+ ? atan2(-sin_theta, -cos_theta)
+ : atan2(sin_theta, cos_theta));
+ const T k = two_theta / sin_theta;
+ angle_axis[0] = q1 * k;
+ angle_axis[1] = q2 * k;
+ angle_axis[2] = q3 * k;
+ } else {
+ // For zero rotation, sqrt() will produce NaN in the derivative since
+ // the argument is zero. By approximating with a Taylor series,
+ // and truncating at one term, the value and first derivatives will be
+ // computed correctly when Jets are used.
+ const T k(2.0);
+ angle_axis[0] = q1 * k;
+ angle_axis[1] = q2 * k;
+ angle_axis[2] = q3 * k;
+ }
+}
+
+template <typename T>
+void RotationMatrixToQuaternion(const T* R, T* angle_axis) {
+ RotationMatrixToQuaternion(ColumnMajorAdapter3x3(R), angle_axis);
+}
+
+// This algorithm comes from "Quaternion Calculus and Fast Animation",
+// Ken Shoemake, 1987 SIGGRAPH course notes
+template <typename T, int row_stride, int col_stride>
+void RotationMatrixToQuaternion(
+ const MatrixAdapter<const T, row_stride, col_stride>& R,
+ T* quaternion) {
+ const T trace = R(0, 0) + R(1, 1) + R(2, 2);
+ if (trace >= 0.0) {
+ T t = sqrt(trace + T(1.0));
+ quaternion[0] = T(0.5) * t;
+ t = T(0.5) / t;
+ quaternion[1] = (R(2, 1) - R(1, 2)) * t;
+ quaternion[2] = (R(0, 2) - R(2, 0)) * t;
+ quaternion[3] = (R(1, 0) - R(0, 1)) * t;
+ } else {
+ int i = 0;
+ if (R(1, 1) > R(0, 0)) {
+ i = 1;
+ }
+
+ if (R(2, 2) > R(i, i)) {
+ i = 2;
+ }
+
+ const int j = (i + 1) % 3;
+ const int k = (j + 1) % 3;
+ T t = sqrt(R(i, i) - R(j, j) - R(k, k) + T(1.0));
+ quaternion[i + 1] = T(0.5) * t;
+ t = T(0.5) / t;
+ quaternion[0] = (R(k, j) - R(j, k)) * t;
+ quaternion[j + 1] = (R(j, i) + R(i, j)) * t;
+ quaternion[k + 1] = (R(k, i) + R(i, k)) * t;
+ }
+}
+
+// The conversion of a rotation matrix to the angle-axis form is
+// numerically problematic when then rotation angle is close to zero
+// or to Pi. The following implementation detects when these two cases
+// occurs and deals with them by taking code paths that are guaranteed
+// to not perform division by a small number.
+template <typename T>
+inline void RotationMatrixToAngleAxis(const T* R, T* angle_axis) {
+ RotationMatrixToAngleAxis(ColumnMajorAdapter3x3(R), angle_axis);
+}
+
+template <typename T, int row_stride, int col_stride>
+void RotationMatrixToAngleAxis(
+ const MatrixAdapter<const T, row_stride, col_stride>& R,
+ T* angle_axis) {
+ T quaternion[4];
+ RotationMatrixToQuaternion(R, quaternion);
+ QuaternionToAngleAxis(quaternion, angle_axis);
+ return;
+}
+
+template <typename T>
+inline void AngleAxisToRotationMatrix(const T* angle_axis, T* R) {
+ AngleAxisToRotationMatrix(angle_axis, ColumnMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride>
+void AngleAxisToRotationMatrix(
+ const T* angle_axis,
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
+ static const T kOne = T(1.0);
+ const T theta2 = DotProduct(angle_axis, angle_axis);
+ if (theta2 > T(std::numeric_limits<double>::epsilon())) {
+ // We want to be careful to only evaluate the square root if the
+ // norm of the angle_axis vector is greater than zero. Otherwise
+ // we get a division by zero.
+ const T theta = sqrt(theta2);
+ const T wx = angle_axis[0] / theta;
+ const T wy = angle_axis[1] / theta;
+ const T wz = angle_axis[2] / theta;
+
+ const T costheta = cos(theta);
+ const T sintheta = sin(theta);
+
+ R(0, 0) = costheta + wx*wx*(kOne - costheta);
+ R(1, 0) = wz*sintheta + wx*wy*(kOne - costheta);
+ R(2, 0) = -wy*sintheta + wx*wz*(kOne - costheta);
+ R(0, 1) = wx*wy*(kOne - costheta) - wz*sintheta;
+ R(1, 1) = costheta + wy*wy*(kOne - costheta);
+ R(2, 1) = wx*sintheta + wy*wz*(kOne - costheta);
+ R(0, 2) = wy*sintheta + wx*wz*(kOne - costheta);
+ R(1, 2) = -wx*sintheta + wy*wz*(kOne - costheta);
+ R(2, 2) = costheta + wz*wz*(kOne - costheta);
+ } else {
+ // Near zero, we switch to using the first order Taylor expansion.
+ R(0, 0) = kOne;
+ R(1, 0) = angle_axis[2];
+ R(2, 0) = -angle_axis[1];
+ R(0, 1) = -angle_axis[2];
+ R(1, 1) = kOne;
+ R(2, 1) = angle_axis[0];
+ R(0, 2) = angle_axis[1];
+ R(1, 2) = -angle_axis[0];
+ R(2, 2) = kOne;
+ }
+}
+
+template <typename T>
+inline void EulerAnglesToRotationMatrix(const T* euler,
+ const int row_stride_parameter,
+ T* R) {
+ CHECK_EQ(row_stride_parameter, 3);
+ EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride>
+void EulerAnglesToRotationMatrix(
+ const T* euler,
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
+ const double kPi = 3.14159265358979323846;
+ const T degrees_to_radians(kPi / 180.0);
+
+ const T pitch(euler[0] * degrees_to_radians);
+ const T roll(euler[1] * degrees_to_radians);
+ const T yaw(euler[2] * degrees_to_radians);
+
+ const T c1 = cos(yaw);
+ const T s1 = sin(yaw);
+ const T c2 = cos(roll);
+ const T s2 = sin(roll);
+ const T c3 = cos(pitch);
+ const T s3 = sin(pitch);
+
+ R(0, 0) = c1*c2;
+ R(0, 1) = -s1*c3 + c1*s2*s3;
+ R(0, 2) = s1*s3 + c1*s2*c3;
+
+ R(1, 0) = s1*c2;
+ R(1, 1) = c1*c3 + s1*s2*s3;
+ R(1, 2) = -c1*s3 + s1*s2*c3;
+
+ R(2, 0) = -s2;
+ R(2, 1) = c2*s3;
+ R(2, 2) = c2*c3;
+}
+
+template <typename T> inline
+void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
+ QuaternionToScaledRotation(q, RowMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToScaledRotation(
+ const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
+ // Make convenient names for elements of q.
+ T a = q[0];
+ T b = q[1];
+ T c = q[2];
+ T d = q[3];
+ // This is not to eliminate common sub-expression, but to
+ // make the lines shorter so that they fit in 80 columns!
+ T aa = a * a;
+ T ab = a * b;
+ T ac = a * c;
+ T ad = a * d;
+ T bb = b * b;
+ T bc = b * c;
+ T bd = b * d;
+ T cc = c * c;
+ T cd = c * d;
+ T dd = d * d;
+
+ R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd); // NOLINT
+ R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab); // NOLINT
+ R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd; // NOLINT
+}
+
+template <typename T> inline
+void QuaternionToRotation(const T q[4], T R[3 * 3]) {
+ QuaternionToRotation(q, RowMajorAdapter3x3(R));
+}
+
+template <typename T, int row_stride, int col_stride> inline
+void QuaternionToRotation(const T q[4],
+ const MatrixAdapter<T, row_stride, col_stride>& R) {
+ QuaternionToScaledRotation(q, R);
+
+ T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
+ CHECK_NE(normalizer, T(0));
+ normalizer = T(1) / normalizer;
+
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ R(i, j) *= normalizer;
+ }
+ }
+}
+
+template <typename T> inline
+void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
+ const T t2 = q[0] * q[1];
+ const T t3 = q[0] * q[2];
+ const T t4 = q[0] * q[3];
+ const T t5 = -q[1] * q[1];
+ const T t6 = q[1] * q[2];
+ const T t7 = q[1] * q[3];
+ const T t8 = -q[2] * q[2];
+ const T t9 = q[2] * q[3];
+ const T t1 = -q[3] * q[3];
+ result[0] = T(2) * ((t8 + t1) * pt[0] + (t6 - t4) * pt[1] + (t3 + t7) * pt[2]) + pt[0]; // NOLINT
+ result[1] = T(2) * ((t4 + t6) * pt[0] + (t5 + t1) * pt[1] + (t9 - t2) * pt[2]) + pt[1]; // NOLINT
+ result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2]; // NOLINT
+}
+
+template <typename T> inline
+void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
+ // 'scale' is 1 / norm(q).
+ const T scale = T(1) / sqrt(q[0] * q[0] +
+ q[1] * q[1] +
+ q[2] * q[2] +
+ q[3] * q[3]);
+
+ // Make unit-norm version of q.
+ const T unit[4] = {
+ scale * q[0],
+ scale * q[1],
+ scale * q[2],
+ scale * q[3],
+ };
+
+ UnitQuaternionRotatePoint(unit, pt, result);
+}
+
+template<typename T> inline
+void QuaternionProduct(const T z[4], const T w[4], T zw[4]) {
+ zw[0] = z[0] * w[0] - z[1] * w[1] - z[2] * w[2] - z[3] * w[3];
+ zw[1] = z[0] * w[1] + z[1] * w[0] + z[2] * w[3] - z[3] * w[2];
+ zw[2] = z[0] * w[2] - z[1] * w[3] + z[2] * w[0] + z[3] * w[1];
+ zw[3] = z[0] * w[3] + z[1] * w[2] - z[2] * w[1] + z[3] * w[0];
+}
+
+// xy = x cross y;
+template<typename T> inline
+void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]) {
+ x_cross_y[0] = x[1] * y[2] - x[2] * y[1];
+ x_cross_y[1] = x[2] * y[0] - x[0] * y[2];
+ x_cross_y[2] = x[0] * y[1] - x[1] * y[0];
+}
+
+template<typename T> inline
+T DotProduct(const T x[3], const T y[3]) {
+ return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
+}
+
+template<typename T> inline
+void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) {
+ const T theta2 = DotProduct(angle_axis, angle_axis);
+ if (theta2 > T(std::numeric_limits<double>::epsilon())) {
+ // Away from zero, use the rodriguez formula
+ //
+ // result = pt costheta +
+ // (w x pt) * sintheta +
+ // w (w . pt) (1 - costheta)
+ //
+ // We want to be careful to only evaluate the square root if the
+ // norm of the angle_axis vector is greater than zero. Otherwise
+ // we get a division by zero.
+ //
+ const T theta = sqrt(theta2);
+ const T costheta = cos(theta);
+ const T sintheta = sin(theta);
+ const T theta_inverse = 1.0 / theta;
+
+ const T w[3] = { angle_axis[0] * theta_inverse,
+ angle_axis[1] * theta_inverse,
+ angle_axis[2] * theta_inverse };
+
+ // Explicitly inlined evaluation of the cross product for
+ // performance reasons.
+ const T w_cross_pt[3] = { w[1] * pt[2] - w[2] * pt[1],
+ w[2] * pt[0] - w[0] * pt[2],
+ w[0] * pt[1] - w[1] * pt[0] };
+ const T tmp =
+ (w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) * (T(1.0) - costheta);
+
+ result[0] = pt[0] * costheta + w_cross_pt[0] * sintheta + w[0] * tmp;
+ result[1] = pt[1] * costheta + w_cross_pt[1] * sintheta + w[1] * tmp;
+ result[2] = pt[2] * costheta + w_cross_pt[2] * sintheta + w[2] * tmp;
+ } else {
+ // Near zero, the first order Taylor approximation of the rotation
+ // matrix R corresponding to a vector w and angle w is
+ //
+ // R = I + hat(w) * sin(theta)
+ //
+ // But sintheta ~ theta and theta * w = angle_axis, which gives us
+ //
+ // R = I + hat(w)
+ //
+ // and actually performing multiplication with the point pt, gives us
+ // R * pt = pt + w x pt.
+ //
+ // Switching to the Taylor expansion near zero provides meaningful
+ // derivatives when evaluated using Jets.
+ //
+ // Explicitly inlined evaluation of the cross product for
+ // performance reasons.
+ const T w_cross_pt[3] = { angle_axis[1] * pt[2] - angle_axis[2] * pt[1],
+ angle_axis[2] * pt[0] - angle_axis[0] * pt[2],
+ angle_axis[0] * pt[1] - angle_axis[1] * pt[0] };
+
+ result[0] = pt[0] + w_cross_pt[0];
+ result[1] = pt[1] + w_cross_pt[1];
+ result[2] = pt[2] + w_cross_pt[2];
+ }
+}
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_ROTATION_H_
diff --git a/extern/ceres/include/ceres/sized_cost_function.h b/extern/ceres/include/ceres/sized_cost_function.h
new file mode 100644
index 00000000000..b10421e81be
--- /dev/null
+++ b/extern/ceres/include/ceres/sized_cost_function.h
@@ -0,0 +1,96 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A convenience class for cost functions which are statically sized.
+// Compared to the dynamically-sized base class, this reduces boilerplate.
+//
+// The kNumResiduals template parameter can be a constant such as 2 or 5, or it
+// can be ceres::DYNAMIC. If kNumResiduals is ceres::DYNAMIC, then subclasses
+// are responsible for calling set_num_residuals() at runtime.
+
+#ifndef CERES_PUBLIC_SIZED_COST_FUNCTION_H_
+#define CERES_PUBLIC_SIZED_COST_FUNCTION_H_
+
+#include "ceres/types.h"
+#include "ceres/cost_function.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+template<int kNumResiduals,
+ int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
+ int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
+class SizedCostFunction : public CostFunction {
+ public:
+ SizedCostFunction() {
+ CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC)
+ << "Cost functions must have at least one residual block.";
+
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
+ ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) || // NOLINT
+ ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0))) // NOLINT
+ << "Zero block cannot precede a non-zero block. Block sizes are "
+ << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
+
+ set_num_residuals(kNumResiduals);
+
+#define CERES_ADD_PARAMETER_BLOCK(N) \
+ if (N) mutable_parameter_block_sizes()->push_back(N);
+ CERES_ADD_PARAMETER_BLOCK(N0);
+ CERES_ADD_PARAMETER_BLOCK(N1);
+ CERES_ADD_PARAMETER_BLOCK(N2);
+ CERES_ADD_PARAMETER_BLOCK(N3);
+ CERES_ADD_PARAMETER_BLOCK(N4);
+ CERES_ADD_PARAMETER_BLOCK(N5);
+ CERES_ADD_PARAMETER_BLOCK(N6);
+ CERES_ADD_PARAMETER_BLOCK(N7);
+ CERES_ADD_PARAMETER_BLOCK(N8);
+ CERES_ADD_PARAMETER_BLOCK(N9);
+#undef CERES_ADD_PARAMETER_BLOCK
+ }
+
+ virtual ~SizedCostFunction() { }
+
+ // Subclasses must implement Evaluate().
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_SIZED_COST_FUNCTION_H_
diff --git a/extern/ceres/include/ceres/solver.h b/extern/ceres/include/ceres/solver.h
new file mode 100644
index 00000000000..318cf48cb83
--- /dev/null
+++ b/extern/ceres/include/ceres/solver.h
@@ -0,0 +1,1028 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_SOLVER_H_
+#define CERES_PUBLIC_SOLVER_H_
+
+#include <cmath>
+#include <string>
+#include <vector>
+#include "ceres/crs_matrix.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/ordered_groups.h"
+#include "ceres/types.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+class Problem;
+
+// Interface for non-linear least squares solvers.
+class CERES_EXPORT Solver {
+ public:
+ virtual ~Solver();
+
+ // The options structure contains, not surprisingly, options that control how
+ // the solver operates. The defaults should be suitable for a wide range of
+ // problems; however, better performance is often obtainable with tweaking.
+ //
+ // The constants are defined inside types.h
+ struct CERES_EXPORT Options {
+ // Default constructor that sets up a generic sparse problem.
+ Options() {
+ minimizer_type = TRUST_REGION;
+ line_search_direction_type = LBFGS;
+ line_search_type = WOLFE;
+ nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
+ max_lbfgs_rank = 20;
+ use_approximate_eigenvalue_bfgs_scaling = false;
+ line_search_interpolation_type = CUBIC;
+ min_line_search_step_size = 1e-9;
+ line_search_sufficient_function_decrease = 1e-4;
+ max_line_search_step_contraction = 1e-3;
+ min_line_search_step_contraction = 0.6;
+ max_num_line_search_step_size_iterations = 20;
+ max_num_line_search_direction_restarts = 5;
+ line_search_sufficient_curvature_decrease = 0.9;
+ max_line_search_step_expansion = 10.0;
+ trust_region_strategy_type = LEVENBERG_MARQUARDT;
+ dogleg_type = TRADITIONAL_DOGLEG;
+ use_nonmonotonic_steps = false;
+ max_consecutive_nonmonotonic_steps = 5;
+ max_num_iterations = 50;
+ max_solver_time_in_seconds = 1e9;
+ num_threads = 1;
+ initial_trust_region_radius = 1e4;
+ max_trust_region_radius = 1e16;
+ min_trust_region_radius = 1e-32;
+ min_relative_decrease = 1e-3;
+ min_lm_diagonal = 1e-6;
+ max_lm_diagonal = 1e32;
+ max_num_consecutive_invalid_steps = 5;
+ function_tolerance = 1e-6;
+ gradient_tolerance = 1e-10;
+ parameter_tolerance = 1e-8;
+
+#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) && !defined(CERES_ENABLE_LGPL_CODE) // NOLINT
+ linear_solver_type = DENSE_QR;
+#else
+ linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+#endif
+
+ preconditioner_type = JACOBI;
+ visibility_clustering_type = CANONICAL_VIEWS;
+ dense_linear_algebra_library_type = EIGEN;
+
+ // Choose a default sparse linear algebra library in the order:
+ //
+ // SUITE_SPARSE > CX_SPARSE > EIGEN_SPARSE > NO_SPARSE
+ sparse_linear_algebra_library_type = NO_SPARSE;
+#if !defined(CERES_NO_SUITESPARSE)
+ sparse_linear_algebra_library_type = SUITE_SPARSE;
+#else
+ #if !defined(CERES_NO_CXSPARSE)
+ sparse_linear_algebra_library_type = CX_SPARSE;
+ #else
+ #if defined(CERES_USE_EIGEN_SPARSE)
+ sparse_linear_algebra_library_type = EIGEN_SPARSE;
+ #endif
+ #endif
+#endif
+
+ num_linear_solver_threads = 1;
+ use_explicit_schur_complement = false;
+ use_postordering = false;
+ dynamic_sparsity = false;
+ min_linear_solver_iterations = 0;
+ max_linear_solver_iterations = 500;
+ eta = 1e-1;
+ jacobi_scaling = true;
+ use_inner_iterations = false;
+ inner_iteration_tolerance = 1e-3;
+ logging_type = PER_MINIMIZER_ITERATION;
+ minimizer_progress_to_stdout = false;
+ trust_region_problem_dump_directory = "/tmp";
+ trust_region_problem_dump_format_type = TEXTFILE;
+ check_gradients = false;
+ gradient_check_relative_precision = 1e-8;
+ numeric_derivative_relative_step_size = 1e-6;
+ update_state_every_iteration = false;
+ }
+
+ // Returns true if the options struct has a valid
+ // configuration. Returns false otherwise, and fills in *error
+ // with a message describing the problem.
+ bool IsValid(std::string* error) const;
+
+ // Minimizer options ----------------------------------------
+
+ // Ceres supports the two major families of optimization strategies -
+ // Trust Region and Line Search.
+ //
+ // 1. The line search approach first finds a descent direction
+ // along which the objective function will be reduced and then
+ // computes a step size that decides how far should move along
+ // that direction. The descent direction can be computed by
+ // various methods, such as gradient descent, Newton's method and
+ // Quasi-Newton method. The step size can be determined either
+ // exactly or inexactly.
+ //
+ // 2. The trust region approach approximates the objective
+ // function using using a model function (often a quadratic) over
+ // a subset of the search space known as the trust region. If the
+ // model function succeeds in minimizing the true objective
+ // function the trust region is expanded; conversely, otherwise it
+ // is contracted and the model optimization problem is solved
+ // again.
+ //
+ // Trust region methods are in some sense dual to line search methods:
+ // trust region methods first choose a step size (the size of the
+ // trust region) and then a step direction while line search methods
+ // first choose a step direction and then a step size.
+ MinimizerType minimizer_type;
+
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+
+ // The LBFGS hessian approximation is a low rank approximation to
+ // the inverse of the Hessian matrix. The rank of the
+ // approximation determines (linearly) the space and time
+ // complexity of using the approximation. Higher the rank, the
+ // better is the quality of the approximation. The increase in
+ // quality is however is bounded for a number of reasons.
+ //
+ // 1. The method only uses secant information and not actual
+ // derivatives.
+ //
+ // 2. The Hessian approximation is constrained to be positive
+ // definite.
+ //
+ // So increasing this rank to a large number will cost time and
+ // space complexity without the corresponding increase in solution
+ // quality. There are no hard and fast rules for choosing the
+ // maximum rank. The best choice usually requires some problem
+ // specific experimentation.
+ //
+ // For more theoretical and implementation details of the LBFGS
+ // method, please see:
+ //
+ // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
+ // Limited Storage". Mathematics of Computation 35 (151): 773–782.
+ int max_lbfgs_rank;
+
+ // As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
+ // the initial inverse Hessian approximation is taken to be the Identity.
+ // However, Oren showed that using instead I * \gamma, where \gamma is
+ // chosen to approximate an eigenvalue of the true inverse Hessian can
+ // result in improved convergence in a wide variety of cases. Setting
+ // use_approximate_eigenvalue_bfgs_scaling to true enables this scaling.
+ //
+ // It is important to note that approximate eigenvalue scaling does not
+ // always improve convergence, and that it can in fact significantly degrade
+ // performance for certain classes of problem, which is why it is disabled
+ // by default. In particular it can degrade performance when the
+ // sensitivity of the problem to different parameters varies significantly,
+ // as in this case a single scalar factor fails to capture this variation
+ // and detrimentally downscales parts of the jacobian approximation which
+ // correspond to low-sensitivity parameters. It can also reduce the
+ // robustness of the solution to errors in the jacobians.
+ //
+ // Oren S.S., Self-scaling variable metric (SSVM) algorithms
+ // Part II: Implementation and experiments, Management Science,
+ // 20(5), 863-874, 1974.
+ bool use_approximate_eigenvalue_bfgs_scaling;
+
+ // Degree of the polynomial used to approximate the objective
+ // function. Valid values are BISECTION, QUADRATIC and CUBIC.
+ //
+ // BISECTION corresponds to pure backtracking search with no
+ // interpolation.
+ LineSearchInterpolationType line_search_interpolation_type;
+
+ // If during the line search, the step_size falls below this
+ // value, it is truncated to zero.
+ double min_line_search_step_size;
+
+ // Line search parameters.
+
+ // Solving the line search problem exactly is computationally
+ // prohibitive. Fortunately, line search based optimization
+ // algorithms can still guarantee convergence if instead of an
+ // exact solution, the line search algorithm returns a solution
+ // which decreases the value of the objective function
+ // sufficiently. More precisely, we are looking for a step_size
+ // s.t.
+ //
+ // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
+ //
+ double line_search_sufficient_function_decrease;
+
+ // In each iteration of the line search,
+ //
+ // new_step_size >= max_line_search_step_contraction * step_size
+ //
+ // Note that by definition, for contraction:
+ //
+ // 0 < max_step_contraction < min_step_contraction < 1
+ //
+ double max_line_search_step_contraction;
+
+ // In each iteration of the line search,
+ //
+ // new_step_size <= min_line_search_step_contraction * step_size
+ //
+ // Note that by definition, for contraction:
+ //
+ // 0 < max_step_contraction < min_step_contraction < 1
+ //
+ double min_line_search_step_contraction;
+
+ // Maximum number of trial step size iterations during each line search,
+ // if a step size satisfying the search conditions cannot be found within
+ // this number of trials, the line search will terminate.
+ int max_num_line_search_step_size_iterations;
+
+ // Maximum number of restarts of the line search direction algorithm before
+ // terminating the optimization. Restarts of the line search direction
+ // algorithm occur when the current algorithm fails to produce a new descent
+ // direction. This typically indicates a numerical failure, or a breakdown
+ // in the validity of the approximations used.
+ int max_num_line_search_direction_restarts;
+
+ // The strong Wolfe conditions consist of the Armijo sufficient
+ // decrease condition, and an additional requirement that the
+ // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
+ // conditions) of the gradient along the search direction
+ // decreases sufficiently. Precisely, this second condition
+ // is that we seek a step_size s.t.
+ //
+ // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
+ //
+ // Where f() is the line search objective and f'() is the derivative
+ // of f w.r.t step_size (d f / d step_size).
+ double line_search_sufficient_curvature_decrease;
+
+ // During the bracketing phase of the Wolfe search, the step size is
+ // increased until either a point satisfying the Wolfe conditions is
+ // found, or an upper bound for a bracket containing a point satisfying
+ // the conditions is found. Precisely, at each iteration of the
+ // expansion:
+ //
+ // new_step_size <= max_step_expansion * step_size.
+ //
+ // By definition for expansion, max_step_expansion > 1.0.
+ double max_line_search_step_expansion;
+
+ TrustRegionStrategyType trust_region_strategy_type;
+
+ // Type of dogleg strategy to use.
+ DoglegType dogleg_type;
+
+ // The classical trust region methods are descent methods, in that
+ // they only accept a point if it strictly reduces the value of
+ // the objective function.
+ //
+ // Relaxing this requirement allows the algorithm to be more
+ // efficient in the long term at the cost of some local increase
+ // in the value of the objective function.
+ //
+ // This is because allowing for non-decreasing objective function
+ // values in a princpled manner allows the algorithm to "jump over
+ // boulders" as the method is not restricted to move into narrow
+ // valleys while preserving its convergence properties.
+ //
+ // Setting use_nonmonotonic_steps to true enables the
+ // non-monotonic trust region algorithm as described by Conn,
+ // Gould & Toint in "Trust Region Methods", Section 10.1.
+ //
+ // The parameter max_consecutive_nonmonotonic_steps controls the
+ // window size used by the step selection algorithm to accept
+ // non-monotonic steps.
+ //
+ // Even though the value of the objective function may be larger
+ // than the minimum value encountered over the course of the
+ // optimization, the final parameters returned to the user are the
+ // ones corresponding to the minimum cost over all iterations.
+ bool use_nonmonotonic_steps;
+ int max_consecutive_nonmonotonic_steps;
+
+ // Maximum number of iterations for the minimizer to run for.
+ int max_num_iterations;
+
+ // Maximum time for which the minimizer should run for.
+ double max_solver_time_in_seconds;
+
+ // Number of threads used by Ceres for evaluating the cost and
+ // jacobians.
+ int num_threads;
+
+ // Trust region minimizer settings.
+ double initial_trust_region_radius;
+ double max_trust_region_radius;
+
+ // Minimizer terminates when the trust region radius becomes
+ // smaller than this value.
+ double min_trust_region_radius;
+
+ // Lower bound for the relative decrease before a step is
+ // accepted.
+ double min_relative_decrease;
+
+ // For the Levenberg-Marquadt algorithm, the scaled diagonal of
+ // the normal equations J'J is used to control the size of the
+ // trust region. Extremely small and large values along the
+ // diagonal can make this regularization scheme
+ // fail. max_lm_diagonal and min_lm_diagonal, clamp the values of
+ // diag(J'J) from above and below. In the normal course of
+ // operation, the user should not have to modify these parameters.
+ double min_lm_diagonal;
+ double max_lm_diagonal;
+
+ // Sometimes due to numerical conditioning problems or linear
+ // solver flakiness, the trust region strategy may return a
+ // numerically invalid step that can be fixed by reducing the
+ // trust region size. So the TrustRegionMinimizer allows for a few
+ // successive invalid steps before it declares NUMERICAL_FAILURE.
+ int max_num_consecutive_invalid_steps;
+
+ // Minimizer terminates when
+ //
+ // (new_cost - old_cost) < function_tolerance * old_cost;
+ //
+ double function_tolerance;
+
+ // Minimizer terminates when
+ //
+ // max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
+ //
+ // This value should typically be 1e-4 * function_tolerance.
+ double gradient_tolerance;
+
+ // Minimizer terminates when
+ //
+ // |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
+ //
+ double parameter_tolerance;
+
+ // Linear least squares solver options -------------------------------------
+
+ LinearSolverType linear_solver_type;
+
+ // Type of preconditioner to use with the iterative linear solvers.
+ PreconditionerType preconditioner_type;
+
+ // Type of clustering algorithm to use for visibility based
+ // preconditioning. This option is used only when the
+ // preconditioner_type is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
+ VisibilityClusteringType visibility_clustering_type;
+
+ // Ceres supports using multiple dense linear algebra libraries
+ // for dense matrix factorizations. Currently EIGEN and LAPACK are
+ // the valid choices. EIGEN is always available, LAPACK refers to
+ // the system BLAS + LAPACK library which may or may not be
+ // available.
+ //
+ // This setting affects the DENSE_QR, DENSE_NORMAL_CHOLESKY and
+ // DENSE_SCHUR solvers. For small to moderate sized probem EIGEN
+ // is a fine choice but for large problems, an optimized LAPACK +
+ // BLAS implementation can make a substantial difference in
+ // performance.
+ DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
+
+ // Ceres supports using multiple sparse linear algebra libraries
+ // for sparse matrix ordering and factorizations. Currently,
+ // SUITE_SPARSE and CX_SPARSE are the valid choices, depending on
+ // whether they are linked into Ceres at build time.
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+
+ // Number of threads used by Ceres to solve the Newton
+ // step. Currently only the SPARSE_SCHUR solver is capable of
+ // using this setting.
+ int num_linear_solver_threads;
+
+ // The order in which variables are eliminated in a linear solver
+ // can have a significant of impact on the efficiency and accuracy
+ // of the method. e.g., when doing sparse Cholesky factorization,
+ // there are matrices for which a good ordering will give a
+ // Cholesky factor with O(n) storage, where as a bad ordering will
+ // result in an completely dense factor.
+ //
+ // Ceres allows the user to provide varying amounts of hints to
+ // the solver about the variable elimination ordering to use. This
+ // can range from no hints, where the solver is free to decide the
+ // best possible ordering based on the user's choices like the
+ // linear solver being used, to an exact order in which the
+ // variables should be eliminated, and a variety of possibilities
+ // in between.
+ //
+ // Instances of the ParameterBlockOrdering class are used to
+ // communicate this information to Ceres.
+ //
+ // Formally an ordering is an ordered partitioning of the
+ // parameter blocks, i.e, each parameter block belongs to exactly
+ // one group, and each group has a unique non-negative integer
+ // associated with it, that determines its order in the set of
+ // groups.
+ //
+ // Given such an ordering, Ceres ensures that the parameter blocks in
+ // the lowest numbered group are eliminated first, and then the
+ // parmeter blocks in the next lowest numbered group and so on. Within
+ // each group, Ceres is free to order the parameter blocks as it
+ // chooses.
+ //
+ // If NULL, then all parameter blocks are assumed to be in the
+ // same group and the solver is free to decide the best
+ // ordering.
+ //
+ // e.g. Consider the linear system
+ //
+ // x + y = 3
+ // 2x + 3y = 7
+ //
+ // There are two ways in which it can be solved. First eliminating x
+ // from the two equations, solving for y and then back substituting
+ // for x, or first eliminating y, solving for x and back substituting
+ // for y. The user can construct three orderings here.
+ //
+ // {0: x}, {1: y} - eliminate x first.
+ // {0: y}, {1: x} - eliminate y first.
+ // {0: x, y} - Solver gets to decide the elimination order.
+ //
+ // Thus, to have Ceres determine the ordering automatically using
+ // heuristics, put all the variables in group 0 and to control the
+ // ordering for every variable, create groups 0..N-1, one per
+ // variable, in the desired order.
+ //
+ // Bundle Adjustment
+ // -----------------
+ //
+ // A particular case of interest is bundle adjustment, where the user
+ // has two options. The default is to not specify an ordering at all,
+ // the solver will see that the user wants to use a Schur type solver
+ // and figure out the right elimination ordering.
+ //
+ // But if the user already knows what parameter blocks are points and
+ // what are cameras, they can save preprocessing time by partitioning
+ // the parameter blocks into two groups, one for the points and one
+ // for the cameras, where the group containing the points has an id
+ // smaller than the group containing cameras.
+ shared_ptr<ParameterBlockOrdering> linear_solver_ordering;
+
+ // Use an explicitly computed Schur complement matrix with
+ // ITERATIVE_SCHUR.
+ //
+ // By default this option is disabled and ITERATIVE_SCHUR
+ // evaluates evaluates matrix-vector products between the Schur
+ // complement and a vector implicitly by exploiting the algebraic
+ // expression for the Schur complement.
+ //
+ // The cost of this evaluation scales with the number of non-zeros
+ // in the Jacobian.
+ //
+ // For small to medium sized problems there is a sweet spot where
+ // computing the Schur complement is cheap enough that it is much
+ // more efficient to explicitly compute it and use it for evaluating
+ // the matrix-vector products.
+ //
+ // Enabling this option tells ITERATIVE_SCHUR to use an explicitly
+ // computed Schur complement.
+ //
+ // NOTE: This option can only be used with the SCHUR_JACOBI
+ // preconditioner.
+ bool use_explicit_schur_complement;
+
+ // Sparse Cholesky factorization algorithms use a fill-reducing
+ // ordering to permute the columns of the Jacobian matrix. There
+ // are two ways of doing this.
+
+ // 1. Compute the Jacobian matrix in some order and then have the
+ // factorization algorithm permute the columns of the Jacobian.
+
+ // 2. Compute the Jacobian with its columns already permuted.
+
+ // The first option incurs a significant memory penalty. The
+ // factorization algorithm has to make a copy of the permuted
+ // Jacobian matrix, thus Ceres pre-permutes the columns of the
+ // Jacobian matrix and generally speaking, there is no performance
+ // penalty for doing so.
+
+ // In some rare cases, it is worth using a more complicated
+ // reordering algorithm which has slightly better runtime
+ // performance at the expense of an extra copy of the Jacobian
+ // matrix. Setting use_postordering to true enables this tradeoff.
+ bool use_postordering;
+
+ // Some non-linear least squares problems are symbolically dense but
+ // numerically sparse. i.e. at any given state only a small number
+ // of jacobian entries are non-zero, but the position and number of
+ // non-zeros is different depending on the state. For these problems
+ // it can be useful to factorize the sparse jacobian at each solver
+ // iteration instead of including all of the zero entries in a single
+ // general factorization.
+ //
+ // If your problem does not have this property (or you do not know),
+ // then it is probably best to keep this false, otherwise it will
+ // likely lead to worse performance.
+
+ // This settings affects the SPARSE_NORMAL_CHOLESKY solver.
+ bool dynamic_sparsity;
+
+ // Some non-linear least squares problems have additional
+ // structure in the way the parameter blocks interact that it is
+ // beneficial to modify the way the trust region step is computed.
+ //
+ // e.g., consider the following regression problem
+ //
+ // y = a_1 exp(b_1 x) + a_2 exp(b_3 x^2 + c_1)
+ //
+ // Given a set of pairs{(x_i, y_i)}, the user wishes to estimate
+ // a_1, a_2, b_1, b_2, and c_1.
+ //
+ // Notice here that the expression on the left is linear in a_1
+ // and a_2, and given any value for b_1, b_2 and c_1, it is
+ // possible to use linear regression to estimate the optimal
+ // values of a_1 and a_2. Indeed, its possible to analytically
+ // eliminate the variables a_1 and a_2 from the problem all
+ // together. Problems like these are known as separable least
+ // squares problem and the most famous algorithm for solving them
+ // is the Variable Projection algorithm invented by Golub &
+ // Pereyra.
+ //
+ // Similar structure can be found in the matrix factorization with
+ // missing data problem. There the corresponding algorithm is
+ // known as Wiberg's algorithm.
+ //
+ // Ruhe & Wedin (Algorithms for Separable Nonlinear Least Squares
+ // Problems, SIAM Reviews, 22(3), 1980) present an analyis of
+ // various algorithms for solving separable non-linear least
+ // squares problems and refer to "Variable Projection" as
+ // Algorithm I in their paper.
+ //
+ // Implementing Variable Projection is tedious and expensive, and
+ // they present a simpler algorithm, which they refer to as
+ // Algorithm II, where once the Newton/Trust Region step has been
+ // computed for the whole problem (a_1, a_2, b_1, b_2, c_1) and
+ // additional optimization step is performed to estimate a_1 and
+ // a_2 exactly.
+ //
+ // This idea can be generalized to cases where the residual is not
+ // linear in a_1 and a_2, i.e., Solve for the trust region step
+ // for the full problem, and then use it as the starting point to
+ // further optimize just a_1 and a_2. For the linear case, this
+ // amounts to doing a single linear least squares solve. For
+ // non-linear problems, any method for solving the a_1 and a_2
+ // optimization problems will do. The only constraint on a_1 and
+ // a_2 is that they do not co-occur in any residual block.
+ //
+ // This idea can be further generalized, by not just optimizing
+ // (a_1, a_2), but decomposing the graph corresponding to the
+ // Hessian matrix's sparsity structure in a collection of
+ // non-overlapping independent sets and optimizing each of them.
+ //
+ // Setting "use_inner_iterations" to true enables the use of this
+ // non-linear generalization of Ruhe & Wedin's Algorithm II. This
+ // version of Ceres has a higher iteration complexity, but also
+ // displays better convergence behaviour per iteration. Setting
+ // Solver::Options::num_threads to the maximum number possible is
+ // highly recommended.
+ bool use_inner_iterations;
+
+ // If inner_iterations is true, then the user has two choices.
+ //
+ // 1. Let the solver heuristically decide which parameter blocks
+ // to optimize in each inner iteration. To do this leave
+ // Solver::Options::inner_iteration_ordering untouched.
+ //
+ // 2. Specify a collection of of ordered independent sets. Where
+ // the lower numbered groups are optimized before the higher
+ // number groups. Each group must be an independent set. Not
+ // all parameter blocks need to be present in the ordering.
+ shared_ptr<ParameterBlockOrdering> inner_iteration_ordering;
+
+ // Generally speaking, inner iterations make significant progress
+ // in the early stages of the solve and then their contribution
+ // drops down sharply, at which point the time spent doing inner
+ // iterations is not worth it.
+ //
+ // Once the relative decrease in the objective function due to
+ // inner iterations drops below inner_iteration_tolerance, the use
+ // of inner iterations in subsequent trust region minimizer
+ // iterations is disabled.
+ double inner_iteration_tolerance;
+
+ // Minimum number of iterations for which the linear solver should
+ // run, even if the convergence criterion is satisfied.
+ int min_linear_solver_iterations;
+
+ // Maximum number of iterations for which the linear solver should
+ // run. If the solver does not converge in less than
+ // max_linear_solver_iterations, then it returns MAX_ITERATIONS,
+ // as its termination type.
+ int max_linear_solver_iterations;
+
+ // Forcing sequence parameter. The truncated Newton solver uses
+ // this number to control the relative accuracy with which the
+ // Newton step is computed.
+ //
+ // This constant is passed to ConjugateGradientsSolver which uses
+ // it to terminate the iterations when
+ //
+ // (Q_i - Q_{i-1})/Q_i < eta/i
+ double eta;
+
+ // Normalize the jacobian using Jacobi scaling before calling
+ // the linear least squares solver.
+ bool jacobi_scaling;
+
+ // Logging options ---------------------------------------------------------
+
+ LoggingType logging_type;
+
+ // By default the Minimizer progress is logged to VLOG(1), which
+ // is sent to STDERR depending on the vlog level. If this flag is
+ // set to true, and logging_type is not SILENT, the logging output
+ // is sent to STDOUT.
+ bool minimizer_progress_to_stdout;
+
+ // List of iterations at which the minimizer should dump the trust
+ // region problem. Useful for testing and benchmarking. If empty
+ // (default), no problems are dumped.
+ std::vector<int> trust_region_minimizer_iterations_to_dump;
+
+ // Directory to which the problems should be written to. Should be
+ // non-empty if trust_region_minimizer_iterations_to_dump is
+ // non-empty and trust_region_problem_dump_format_type is not
+ // CONSOLE.
+ std::string trust_region_problem_dump_directory;
+ DumpFormatType trust_region_problem_dump_format_type;
+
+ // Finite differences options ----------------------------------------------
+
+ // Check all jacobians computed by each residual block with finite
+ // differences. This is expensive since it involves computing the
+ // derivative by normal means (e.g. user specified, autodiff,
+ // etc), then also computing it using finite differences. The
+ // results are compared, and if they differ substantially, details
+ // are printed to the log.
+ bool check_gradients;
+
+ // Relative precision to check for in the gradient checker. If the
+ // relative difference between an element in a jacobian exceeds
+ // this number, then the jacobian for that cost term is dumped.
+ double gradient_check_relative_precision;
+
+ // Relative shift used for taking numeric derivatives. For finite
+ // differencing, each dimension is evaluated at slightly shifted
+ // values; for the case of central difference, this is what gets
+ // evaluated:
+ //
+ // delta = numeric_derivative_relative_step_size;
+ // f_initial = f(x)
+ // f_forward = f((1 + delta) * x)
+ // f_backward = f((1 - delta) * x)
+ //
+ // The finite differencing is done along each dimension. The
+ // reason to use a relative (rather than absolute) step size is
+ // that this way, numeric differentation works for functions where
+ // the arguments are typically large (e.g. 1e9) and when the
+ // values are small (e.g. 1e-5). It is possible to construct
+ // "torture cases" which break this finite difference heuristic,
+ // but they do not come up often in practice.
+ //
+ // TODO(keir): Pick a smarter number than the default above! In
+ // theory a good choice is sqrt(eps) * x, which for doubles means
+ // about 1e-8 * x. However, I have found this number too
+ // optimistic. This number should be exposed for users to change.
+ double numeric_derivative_relative_step_size;
+
+ // If true, the user's parameter blocks are updated at the end of
+ // every Minimizer iteration, otherwise they are updated when the
+ // Minimizer terminates. This is useful if, for example, the user
+ // wishes to visualize the state of the optimization every
+ // iteration.
+ bool update_state_every_iteration;
+
+ // Callbacks that are executed at the end of each iteration of the
+ // Minimizer. An iteration may terminate midway, either due to
+ // numerical failures or because one of the convergence tests has
+ // been satisfied. In this case none of the callbacks are
+ // executed.
+
+ // Callbacks are executed in the order that they are specified in
+ // this vector. By default, parameter blocks are updated only at
+ // the end of the optimization, i.e when the Minimizer
+ // terminates. This behaviour is controlled by
+ // update_state_every_variable. If the user wishes to have access
+ // to the update parameter blocks when his/her callbacks are
+ // executed, then set update_state_every_iteration to true.
+ //
+ // The solver does NOT take ownership of these pointers.
+ std::vector<IterationCallback*> callbacks;
+ };
+
+ struct CERES_EXPORT Summary {
+ Summary();
+
+ // A brief one line description of the state of the solver after
+ // termination.
+ std::string BriefReport() const;
+
+ // A full multiline description of the state of the solver after
+ // termination.
+ std::string FullReport() const;
+
+ bool IsSolutionUsable() const;
+
+ // Minimizer summary -------------------------------------------------
+ MinimizerType minimizer_type;
+
+ TerminationType termination_type;
+
+ // Reason why the solver terminated.
+ std::string message;
+
+ // Cost of the problem (value of the objective function) before
+ // the optimization.
+ double initial_cost;
+
+ // Cost of the problem (value of the objective function) after the
+ // optimization.
+ double final_cost;
+
+ // The part of the total cost that comes from residual blocks that
+ // were held fixed by the preprocessor because all the parameter
+ // blocks that they depend on were fixed.
+ double fixed_cost;
+
+ // IterationSummary for each minimizer iteration in order.
+ std::vector<IterationSummary> iterations;
+
+ // Number of minimizer iterations in which the step was
+ // accepted. Unless use_non_monotonic_steps is true this is also
+ // the number of steps in which the objective function value/cost
+ // went down.
+ int num_successful_steps;
+
+ // Number of minimizer iterations in which the step was rejected
+ // either because it did not reduce the cost enough or the step
+ // was not numerically valid.
+ int num_unsuccessful_steps;
+
+ // Number of times inner iterations were performed.
+ int num_inner_iteration_steps;
+
+ // All times reported below are wall times.
+
+ // When the user calls Solve, before the actual optimization
+ // occurs, Ceres performs a number of preprocessing steps. These
+ // include error checks, memory allocations, and reorderings. This
+ // time is accounted for as preprocessing time.
+ double preprocessor_time_in_seconds;
+
+ // Time spent in the TrustRegionMinimizer.
+ double minimizer_time_in_seconds;
+
+ // After the Minimizer is finished, some time is spent in
+ // re-evaluating residuals etc. This time is accounted for in the
+ // postprocessor time.
+ double postprocessor_time_in_seconds;
+
+ // Some total of all time spent inside Ceres when Solve is called.
+ double total_time_in_seconds;
+
+ // Time (in seconds) spent in the linear solver computing the
+ // trust region step.
+ double linear_solver_time_in_seconds;
+
+ // Time (in seconds) spent evaluating the residual vector.
+ double residual_evaluation_time_in_seconds;
+
+ // Time (in seconds) spent evaluating the jacobian matrix.
+ double jacobian_evaluation_time_in_seconds;
+
+ // Time (in seconds) spent doing inner iterations.
+ double inner_iteration_time_in_seconds;
+
+ // Cumulative timing information for line searches performed as part of the
+ // solve. Note that in addition to the case when the Line Search minimizer
+ // is used, the Trust Region minimizer also uses a line search when
+ // solving a constrained problem.
+
+ // Time (in seconds) spent evaluating the univariate cost function as part
+ // of a line search.
+ double line_search_cost_evaluation_time_in_seconds;
+
+ // Time (in seconds) spent evaluating the gradient of the univariate cost
+ // function as part of a line search.
+ double line_search_gradient_evaluation_time_in_seconds;
+
+ // Time (in seconds) spent minimizing the interpolating polynomial
+ // to compute the next candidate step size as part of a line search.
+ double line_search_polynomial_minimization_time_in_seconds;
+
+ // Total time (in seconds) spent performing line searches.
+ double line_search_total_time_in_seconds;
+
+ // Number of parameter blocks in the problem.
+ int num_parameter_blocks;
+
+ // Number of parameters in the probem.
+ int num_parameters;
+
+ // Dimension of the tangent space of the problem (or the number of
+ // columns in the Jacobian for the problem). This is different
+ // from num_parameters if a parameter block is associated with a
+ // LocalParameterization
+ int num_effective_parameters;
+
+ // Number of residual blocks in the problem.
+ int num_residual_blocks;
+
+ // Number of residuals in the problem.
+ int num_residuals;
+
+ // Number of parameter blocks in the problem after the inactive
+ // and constant parameter blocks have been removed. A parameter
+ // block is inactive if no residual block refers to it.
+ int num_parameter_blocks_reduced;
+
+ // Number of parameters in the reduced problem.
+ int num_parameters_reduced;
+
+ // Dimension of the tangent space of the reduced problem (or the
+ // number of columns in the Jacobian for the reduced
+ // problem). This is different from num_parameters_reduced if a
+ // parameter block in the reduced problem is associated with a
+ // LocalParameterization.
+ int num_effective_parameters_reduced;
+
+ // Number of residual blocks in the reduced problem.
+ int num_residual_blocks_reduced;
+
+ // Number of residuals in the reduced problem.
+ int num_residuals_reduced;
+
+ // Is the reduced problem bounds constrained.
+ bool is_constrained;
+
+ // Number of threads specified by the user for Jacobian and
+ // residual evaluation.
+ int num_threads_given;
+
+ // Number of threads actually used by the solver for Jacobian and
+ // residual evaluation. This number is not equal to
+ // num_threads_given if OpenMP is not available.
+ int num_threads_used;
+
+ // Number of threads specified by the user for solving the trust
+ // region problem.
+ int num_linear_solver_threads_given;
+
+ // Number of threads actually used by the solver for solving the
+ // trust region problem. This number is not equal to
+ // num_threads_given if OpenMP is not available.
+ int num_linear_solver_threads_used;
+
+ // Type of the linear solver requested by the user.
+ LinearSolverType linear_solver_type_given;
+
+ // Type of the linear solver actually used. This may be different
+ // from linear_solver_type_given if Ceres determines that the
+ // problem structure is not compatible with the linear solver
+ // requested or if the linear solver requested by the user is not
+ // available, e.g. The user requested SPARSE_NORMAL_CHOLESKY but
+ // no sparse linear algebra library was available.
+ LinearSolverType linear_solver_type_used;
+
+ // Size of the elimination groups given by the user as hints to
+ // the linear solver.
+ std::vector<int> linear_solver_ordering_given;
+
+ // Size of the parameter groups used by the solver when ordering
+ // the columns of the Jacobian. This maybe different from
+ // linear_solver_ordering_given if the user left
+ // linear_solver_ordering_given blank and asked for an automatic
+ // ordering, or if the problem contains some constant or inactive
+ // parameter blocks.
+ std::vector<int> linear_solver_ordering_used;
+
+ // True if the user asked for inner iterations to be used as part
+ // of the optimization.
+ bool inner_iterations_given;
+
+ // True if the user asked for inner iterations to be used as part
+ // of the optimization and the problem structure was such that
+ // they were actually performed. e.g., in a problem with just one
+ // parameter block, inner iterations are not performed.
+ bool inner_iterations_used;
+
+ // Size of the parameter groups given by the user for performing
+ // inner iterations.
+ std::vector<int> inner_iteration_ordering_given;
+
+ // Size of the parameter groups given used by the solver for
+ // performing inner iterations. This maybe different from
+ // inner_iteration_ordering_given if the user left
+ // inner_iteration_ordering_given blank and asked for an automatic
+ // ordering, or if the problem contains some constant or inactive
+ // parameter blocks.
+ std::vector<int> inner_iteration_ordering_used;
+
+ // Type of the preconditioner requested by the user.
+ PreconditionerType preconditioner_type_given;
+
+ // Type of the preconditioner actually used. This may be different
+ // from linear_solver_type_given if Ceres determines that the
+ // problem structure is not compatible with the linear solver
+ // requested or if the linear solver requested by the user is not
+ // available.
+ PreconditionerType preconditioner_type_used;
+
+ // Type of clustering algorithm used for visibility based
+ // preconditioning. Only meaningful when the preconditioner_type
+ // is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
+ VisibilityClusteringType visibility_clustering_type;
+
+ // Type of trust region strategy.
+ TrustRegionStrategyType trust_region_strategy_type;
+
+ // Type of dogleg strategy used for solving the trust region
+ // problem.
+ DoglegType dogleg_type;
+
+ // Type of the dense linear algebra library used.
+ DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
+
+ // Type of the sparse linear algebra library used.
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+
+ // Type of line search direction used.
+ LineSearchDirectionType line_search_direction_type;
+
+ // Type of the line search algorithm used.
+ LineSearchType line_search_type;
+
+ // When performing line search, the degree of the polynomial used
+ // to approximate the objective function.
+ LineSearchInterpolationType line_search_interpolation_type;
+
+ // If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
+ // then this indicates the particular variant of non-linear
+ // conjugate gradient used.
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+
+ // If the type of the line search direction is LBFGS, then this
+ // indicates the rank of the Hessian approximation.
+ int max_lbfgs_rank;
+ };
+
+ // Once a least squares problem has been built, this function takes
+ // the problem and optimizes it based on the values of the options
+ // parameters. Upon return, a detailed summary of the work performed
+ // by the preprocessor, the non-linear minmizer and the linear
+ // solver are reported in the summary object.
+ virtual void Solve(const Options& options,
+ Problem* problem,
+ Solver::Summary* summary);
+};
+
+// Helper function which avoids going through the interface.
+CERES_EXPORT void Solve(const Solver::Options& options,
+ Problem* problem,
+ Solver::Summary* summary);
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_SOLVER_H_
diff --git a/extern/ceres/include/ceres/types.h b/extern/ceres/include/ceres/types.h
new file mode 100644
index 00000000000..2ea41803629
--- /dev/null
+++ b/extern/ceres/include/ceres/types.h
@@ -0,0 +1,508 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Enums and other top level class definitions.
+//
+// Note: internal/types.cc defines stringification routines for some
+// of these enums. Please update those routines if you extend or
+// remove enums from here.
+
+#ifndef CERES_PUBLIC_TYPES_H_
+#define CERES_PUBLIC_TYPES_H_
+
+#include <string>
+
+#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres {
+
+// Basic integer types. These typedefs are in the Ceres namespace to avoid
+// conflicts with other packages having similar typedefs.
+typedef int int32;
+
+// Argument type used in interfaces that can optionally take ownership
+// of a passed in argument. If TAKE_OWNERSHIP is passed, the called
+// object takes ownership of the pointer argument, and will call
+// delete on it upon completion.
+enum Ownership {
+ DO_NOT_TAKE_OWNERSHIP,
+ TAKE_OWNERSHIP
+};
+
+// TODO(keir): Considerably expand the explanations of each solver type.
+enum LinearSolverType {
+ // These solvers are for general rectangular systems formed from the
+ // normal equations A'A x = A'b. They are direct solvers and do not
+ // assume any special problem structure.
+
+ // Solve the normal equations using a dense Cholesky solver; based
+ // on Eigen.
+ DENSE_NORMAL_CHOLESKY,
+
+ // Solve the normal equations using a dense QR solver; based on
+ // Eigen.
+ DENSE_QR,
+
+ // Solve the normal equations using a sparse cholesky solver; requires
+ // SuiteSparse or CXSparse.
+ SPARSE_NORMAL_CHOLESKY,
+
+ // Specialized solvers, specific to problems with a generalized
+ // bi-partitite structure.
+
+ // Solves the reduced linear system using a dense Cholesky solver;
+ // based on Eigen.
+ DENSE_SCHUR,
+
+ // Solves the reduced linear system using a sparse Cholesky solver;
+ // based on CHOLMOD.
+ SPARSE_SCHUR,
+
+ // Solves the reduced linear system using Conjugate Gradients, based
+ // on a new Ceres implementation. Suitable for large scale
+ // problems.
+ ITERATIVE_SCHUR,
+
+ // Conjugate gradients on the normal equations.
+ CGNR
+};
+
+enum PreconditionerType {
+ // Trivial preconditioner - the identity matrix.
+ IDENTITY,
+
+ // Block diagonal of the Gauss-Newton Hessian.
+ JACOBI,
+
+ // Note: The following three preconditioners can only be used with
+ // the ITERATIVE_SCHUR solver. They are well suited for Structure
+ // from Motion problems.
+
+ // Block diagonal of the Schur complement. This preconditioner may
+ // only be used with the ITERATIVE_SCHUR solver.
+ SCHUR_JACOBI,
+
+ // Visibility clustering based preconditioners.
+ //
+ // The following two preconditioners use the visibility structure of
+ // the scene to determine the sparsity structure of the
+ // preconditioner. This is done using a clustering algorithm. The
+ // available visibility clustering algorithms are described below.
+ //
+ // Note: Requires SuiteSparse.
+ CLUSTER_JACOBI,
+ CLUSTER_TRIDIAGONAL
+};
+
+enum VisibilityClusteringType {
+ // Canonical views algorithm as described in
+ //
+ // "Scene Summarization for Online Image Collections", Ian Simon, Noah
+ // Snavely, Steven M. Seitz, ICCV 2007.
+ //
+ // This clustering algorithm can be quite slow, but gives high
+ // quality clusters. The original visibility based clustering paper
+ // used this algorithm.
+ CANONICAL_VIEWS,
+
+ // The classic single linkage algorithm. It is extremely fast as
+ // compared to CANONICAL_VIEWS, but can give slightly poorer
+ // results. For problems with large number of cameras though, this
+ // is generally a pretty good option.
+ //
+ // If you are using SCHUR_JACOBI preconditioner and have SuiteSparse
+ // available, CLUSTER_JACOBI and CLUSTER_TRIDIAGONAL in combination
+ // with the SINGLE_LINKAGE algorithm will generally give better
+ // results.
+ SINGLE_LINKAGE
+};
+
+enum SparseLinearAlgebraLibraryType {
+ // High performance sparse Cholesky factorization and approximate
+ // minimum degree ordering.
+ SUITE_SPARSE,
+
+ // A lightweight replacment for SuiteSparse, which does not require
+ // a LAPACK/BLAS implementation. Consequently, its performance is
+ // also a bit lower than SuiteSparse.
+ CX_SPARSE,
+
+ // Eigen's sparse linear algebra routines. In particular Ceres uses
+ // the Simplicial LDLT routines.
+ EIGEN_SPARSE,
+
+ // No sparse linear solver should be used. This does not necessarily
+ // imply that Ceres was built without any sparse library, although that
+ // is the likely use case, merely that one should not be used.
+ NO_SPARSE
+};
+
+enum DenseLinearAlgebraLibraryType {
+ EIGEN,
+ LAPACK
+};
+
+// Logging options
+// The options get progressively noisier.
+enum LoggingType {
+ SILENT,
+ PER_MINIMIZER_ITERATION
+};
+
+enum MinimizerType {
+ LINE_SEARCH,
+ TRUST_REGION
+};
+
+enum LineSearchDirectionType {
+ // Negative of the gradient.
+ STEEPEST_DESCENT,
+
+ // A generalization of the Conjugate Gradient method to non-linear
+ // functions. The generalization can be performed in a number of
+ // different ways, resulting in a variety of search directions. The
+ // precise choice of the non-linear conjugate gradient algorithm
+ // used is determined by NonlinerConjuateGradientType.
+ NONLINEAR_CONJUGATE_GRADIENT,
+
+ // BFGS, and it's limited memory approximation L-BFGS, are quasi-Newton
+ // algorithms that approximate the Hessian matrix by iteratively refining
+ // an initial estimate with rank-one updates using the gradient at each
+ // iteration. They are a generalisation of the Secant method and satisfy
+ // the Secant equation. The Secant equation has an infinium of solutions
+ // in multiple dimensions, as there are N*(N+1)/2 degrees of freedom in a
+ // symmetric matrix but only N conditions are specified by the Secant
+ // equation. The requirement that the Hessian approximation be positive
+ // definite imposes another N additional constraints, but that still leaves
+ // remaining degrees-of-freedom. (L)BFGS methods uniquely deteremine the
+ // approximate Hessian by imposing the additional constraints that the
+ // approximation at the next iteration must be the 'closest' to the current
+ // approximation (the nature of how this proximity is measured is actually
+ // the defining difference between a family of quasi-Newton methods including
+ // (L)BFGS & DFP). (L)BFGS is currently regarded as being the best known
+ // general quasi-Newton method.
+ //
+ // The principal difference between BFGS and L-BFGS is that whilst BFGS
+ // maintains a full, dense approximation to the (inverse) Hessian, L-BFGS
+ // maintains only a window of the last M observations of the parameters and
+ // gradients. Using this observation history, the calculation of the next
+ // search direction can be computed without requiring the construction of the
+ // full dense inverse Hessian approximation. This is particularly important
+ // for problems with a large number of parameters, where storage of an N-by-N
+ // matrix in memory would be prohibitive.
+ //
+ // For more details on BFGS see:
+ //
+ // Broyden, C.G., "The Convergence of a Class of Double-rank Minimization
+ // Algorithms,"; J. Inst. Maths. Applics., Vol. 6, pp 76–90, 1970.
+ //
+ // Fletcher, R., "A New Approach to Variable Metric Algorithms,"
+ // Computer Journal, Vol. 13, pp 317–322, 1970.
+ //
+ // Goldfarb, D., "A Family of Variable Metric Updates Derived by Variational
+ // Means," Mathematics of Computing, Vol. 24, pp 23–26, 1970.
+ //
+ // Shanno, D.F., "Conditioning of Quasi-Newton Methods for Function
+ // Minimization," Mathematics of Computing, Vol. 24, pp 647–656, 1970.
+ //
+ // For more details on L-BFGS see:
+ //
+ // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
+ // Storage". Mathematics of Computation 35 (151): 773–782.
+ //
+ // Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
+ // "Representations of Quasi-Newton Matrices and their use in
+ // Limited Memory Methods". Mathematical Programming 63 (4):
+ // 129–156.
+ //
+ // A general reference for both methods:
+ //
+ // Nocedal J., Wright S., Numerical Optimization, 2nd Ed. Springer, 1999.
+ LBFGS,
+ BFGS,
+};
+
+// Nonliner conjugate gradient methods are a generalization of the
+// method of Conjugate Gradients for linear systems. The
+// generalization can be carried out in a number of different ways
+// leading to number of different rules for computing the search
+// direction. Ceres provides a number of different variants. For more
+// details see Numerical Optimization by Nocedal & Wright.
+enum NonlinearConjugateGradientType {
+ FLETCHER_REEVES,
+ POLAK_RIBIERE,
+ HESTENES_STIEFEL,
+};
+
+enum LineSearchType {
+ // Backtracking line search with polynomial interpolation or
+ // bisection.
+ ARMIJO,
+ WOLFE,
+};
+
+// Ceres supports different strategies for computing the trust region
+// step.
+enum TrustRegionStrategyType {
+ // The default trust region strategy is to use the step computation
+ // used in the Levenberg-Marquardt algorithm. For more details see
+ // levenberg_marquardt_strategy.h
+ LEVENBERG_MARQUARDT,
+
+ // Powell's dogleg algorithm interpolates between the Cauchy point
+ // and the Gauss-Newton step. It is particularly useful if the
+ // LEVENBERG_MARQUARDT algorithm is making a large number of
+ // unsuccessful steps. For more details see dogleg_strategy.h.
+ //
+ // NOTES:
+ //
+ // 1. This strategy has not been experimented with or tested as
+ // extensively as LEVENBERG_MARQUARDT, and therefore it should be
+ // considered EXPERIMENTAL for now.
+ //
+ // 2. For now this strategy should only be used with exact
+ // factorization based linear solvers, i.e., SPARSE_SCHUR,
+ // DENSE_SCHUR, DENSE_QR and SPARSE_NORMAL_CHOLESKY.
+ DOGLEG
+};
+
+// Ceres supports two different dogleg strategies.
+// The "traditional" dogleg method by Powell and the
+// "subspace" method described in
+// R. H. Byrd, R. B. Schnabel, and G. A. Shultz,
+// "Approximate solution of the trust region problem by minimization
+// over two-dimensional subspaces", Mathematical Programming,
+// 40 (1988), pp. 247--263
+enum DoglegType {
+ // The traditional approach constructs a dogleg path
+ // consisting of two line segments and finds the furthest
+ // point on that path that is still inside the trust region.
+ TRADITIONAL_DOGLEG,
+
+ // The subspace approach finds the exact minimum of the model
+ // constrained to the subspace spanned by the dogleg path.
+ SUBSPACE_DOGLEG
+};
+
+enum TerminationType {
+ // Minimizer terminated because one of the convergence criterion set
+ // by the user was satisfied.
+ //
+ // 1. (new_cost - old_cost) < function_tolerance * old_cost;
+ // 2. max_i |gradient_i| < gradient_tolerance
+ // 3. |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
+ //
+ // The user's parameter blocks will be updated with the solution.
+ CONVERGENCE,
+
+ // The solver ran for maximum number of iterations or maximum amount
+ // of time specified by the user, but none of the convergence
+ // criterion specified by the user were met. The user's parameter
+ // blocks will be updated with the solution found so far.
+ NO_CONVERGENCE,
+
+ // The minimizer terminated because of an error. The user's
+ // parameter blocks will not be updated.
+ FAILURE,
+
+ // Using an IterationCallback object, user code can control the
+ // minimizer. The following enums indicate that the user code was
+ // responsible for termination.
+ //
+ // Minimizer terminated successfully because a user
+ // IterationCallback returned SOLVER_TERMINATE_SUCCESSFULLY.
+ //
+ // The user's parameter blocks will be updated with the solution.
+ USER_SUCCESS,
+
+ // Minimizer terminated because because a user IterationCallback
+ // returned SOLVER_ABORT.
+ //
+ // The user's parameter blocks will not be updated.
+ USER_FAILURE
+};
+
+// Enums used by the IterationCallback instances to indicate to the
+// solver whether it should continue solving, the user detected an
+// error or the solution is good enough and the solver should
+// terminate.
+enum CallbackReturnType {
+ // Continue solving to next iteration.
+ SOLVER_CONTINUE,
+
+ // Terminate solver, and do not update the parameter blocks upon
+ // return. Unless the user has set
+ // Solver:Options:::update_state_every_iteration, in which case the
+ // state would have been updated every iteration
+ // anyways. Solver::Summary::termination_type is set to USER_ABORT.
+ SOLVER_ABORT,
+
+ // Terminate solver, update state and
+ // return. Solver::Summary::termination_type is set to USER_SUCCESS.
+ SOLVER_TERMINATE_SUCCESSFULLY
+};
+
+// The format in which linear least squares problems should be logged
+// when Solver::Options::lsqp_iterations_to_dump is non-empty.
+enum DumpFormatType {
+ // Print the linear least squares problem in a human readable format
+ // to stderr. The Jacobian is printed as a dense matrix. The vectors
+ // D, x and f are printed as dense vectors. This should only be used
+ // for small problems.
+ CONSOLE,
+
+ // Write out the linear least squares problem to the directory
+ // pointed to by Solver::Options::lsqp_dump_directory as text files
+ // which can be read into MATLAB/Octave. The Jacobian is dumped as a
+ // text file containing (i,j,s) triplets, the vectors D, x and f are
+ // dumped as text files containing a list of their values.
+ //
+ // A MATLAB/octave script called lm_iteration_???.m is also output,
+ // which can be used to parse and load the problem into memory.
+ TEXTFILE
+};
+
+// For SizedCostFunction and AutoDiffCostFunction, DYNAMIC can be
+// specified for the number of residuals. If specified, then the
+// number of residuas for that cost function can vary at runtime.
+enum DimensionType {
+ DYNAMIC = -1
+};
+
+// The differentiation method used to compute numerical derivatives in
+// NumericDiffCostFunction and DynamicNumericDiffCostFunction.
+enum NumericDiffMethodType {
+ // Compute central finite difference: f'(x) ~ (f(x+h) - f(x-h)) / 2h.
+ CENTRAL,
+
+ // Compute forward finite difference: f'(x) ~ (f(x+h) - f(x)) / h.
+ FORWARD,
+
+ // Adaptive numerical differentiation using Ridders' method. Provides more
+ // accurate and robust derivatives at the expense of additional cost
+ // function evaluations.
+ RIDDERS
+};
+
+enum LineSearchInterpolationType {
+ BISECTION,
+ QUADRATIC,
+ CUBIC
+};
+
+enum CovarianceAlgorithmType {
+ DENSE_SVD,
+ SUITE_SPARSE_QR,
+ EIGEN_SPARSE_QR
+};
+
+CERES_EXPORT const char* LinearSolverTypeToString(
+ LinearSolverType type);
+CERES_EXPORT bool StringToLinearSolverType(std::string value,
+ LinearSolverType* type);
+
+CERES_EXPORT const char* PreconditionerTypeToString(PreconditionerType type);
+CERES_EXPORT bool StringToPreconditionerType(std::string value,
+ PreconditionerType* type);
+
+CERES_EXPORT const char* VisibilityClusteringTypeToString(
+ VisibilityClusteringType type);
+CERES_EXPORT bool StringToVisibilityClusteringType(std::string value,
+ VisibilityClusteringType* type);
+
+CERES_EXPORT const char* SparseLinearAlgebraLibraryTypeToString(
+ SparseLinearAlgebraLibraryType type);
+CERES_EXPORT bool StringToSparseLinearAlgebraLibraryType(
+ std::string value,
+ SparseLinearAlgebraLibraryType* type);
+
+CERES_EXPORT const char* DenseLinearAlgebraLibraryTypeToString(
+ DenseLinearAlgebraLibraryType type);
+CERES_EXPORT bool StringToDenseLinearAlgebraLibraryType(
+ std::string value,
+ DenseLinearAlgebraLibraryType* type);
+
+CERES_EXPORT const char* TrustRegionStrategyTypeToString(
+ TrustRegionStrategyType type);
+CERES_EXPORT bool StringToTrustRegionStrategyType(std::string value,
+ TrustRegionStrategyType* type);
+
+CERES_EXPORT const char* DoglegTypeToString(DoglegType type);
+CERES_EXPORT bool StringToDoglegType(std::string value, DoglegType* type);
+
+CERES_EXPORT const char* MinimizerTypeToString(MinimizerType type);
+CERES_EXPORT bool StringToMinimizerType(std::string value, MinimizerType* type);
+
+CERES_EXPORT const char* LineSearchDirectionTypeToString(
+ LineSearchDirectionType type);
+CERES_EXPORT bool StringToLineSearchDirectionType(std::string value,
+ LineSearchDirectionType* type);
+
+CERES_EXPORT const char* LineSearchTypeToString(LineSearchType type);
+CERES_EXPORT bool StringToLineSearchType(std::string value, LineSearchType* type);
+
+CERES_EXPORT const char* NonlinearConjugateGradientTypeToString(
+ NonlinearConjugateGradientType type);
+CERES_EXPORT bool StringToNonlinearConjugateGradientType(
+ std::string value,
+ NonlinearConjugateGradientType* type);
+
+CERES_EXPORT const char* LineSearchInterpolationTypeToString(
+ LineSearchInterpolationType type);
+CERES_EXPORT bool StringToLineSearchInterpolationType(
+ std::string value,
+ LineSearchInterpolationType* type);
+
+CERES_EXPORT const char* CovarianceAlgorithmTypeToString(
+ CovarianceAlgorithmType type);
+CERES_EXPORT bool StringToCovarianceAlgorithmType(
+ std::string value,
+ CovarianceAlgorithmType* type);
+
+CERES_EXPORT const char* NumericDiffMethodTypeToString(
+ NumericDiffMethodType type);
+CERES_EXPORT bool StringToNumericDiffMethodType(
+ std::string value,
+ NumericDiffMethodType* type);
+
+CERES_EXPORT const char* TerminationTypeToString(TerminationType type);
+
+CERES_EXPORT bool IsSchurType(LinearSolverType type);
+CERES_EXPORT bool IsSparseLinearAlgebraLibraryTypeAvailable(
+ SparseLinearAlgebraLibraryType type);
+CERES_EXPORT bool IsDenseLinearAlgebraLibraryTypeAvailable(
+ DenseLinearAlgebraLibraryType type);
+
+} // namespace ceres
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif // CERES_PUBLIC_TYPES_H_
diff --git a/extern/ceres/include/ceres/version.h b/extern/ceres/include/ceres/version.h
new file mode 100644
index 00000000000..66505a515c9
--- /dev/null
+++ b/extern/ceres/include/ceres/version.h
@@ -0,0 +1,48 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+
+#ifndef CERES_PUBLIC_VERSION_H_
+#define CERES_PUBLIC_VERSION_H_
+
+#define CERES_VERSION_MAJOR 1
+#define CERES_VERSION_MINOR 11
+#define CERES_VERSION_REVISION 0
+
+// Classic CPP stringifcation; the extra level of indirection allows the
+// preprocessor to expand the macro before being converted to a string.
+#define CERES_TO_STRING_HELPER(x) #x
+#define CERES_TO_STRING(x) CERES_TO_STRING_HELPER(x)
+
+// The Ceres version as a string; for example "1.9.0".
+#define CERES_VERSION_STRING CERES_TO_STRING(CERES_VERSION_MAJOR) "." \
+ CERES_TO_STRING(CERES_VERSION_MINOR) "." \
+ CERES_TO_STRING(CERES_VERSION_REVISION)
+
+#endif // CERES_PUBLIC_VERSION_H_
diff --git a/extern/ceres/internal/ceres/array_utils.cc b/extern/ceres/internal/ceres/array_utils.cc
new file mode 100644
index 00000000000..7be3c78ce24
--- /dev/null
+++ b/extern/ceres/internal/ceres/array_utils.cc
@@ -0,0 +1,115 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/array_utils.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <string>
+#include <vector>
+#include "ceres/fpclassify.h"
+#include "ceres/stringprintf.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+
+// It is a near impossibility that user code generates this exact
+// value in normal operation, thus we will use it to fill arrays
+// before passing them to user code. If on return an element of the
+// array still contains this value, we will assume that the user code
+// did not write to that memory location.
+const double kImpossibleValue = 1e302;
+
+bool IsArrayValid(const int size, const double* x) {
+ if (x != NULL) {
+ for (int i = 0; i < size; ++i) {
+ if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+int FindInvalidValue(const int size, const double* x) {
+ if (x == NULL) {
+ return size;
+ }
+
+ for (int i = 0; i < size; ++i) {
+ if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) {
+ return i;
+ }
+ }
+
+ return size;
+}
+
+void InvalidateArray(const int size, double* x) {
+ if (x != NULL) {
+ for (int i = 0; i < size; ++i) {
+ x[i] = kImpossibleValue;
+ }
+ }
+}
+
+void AppendArrayToString(const int size, const double* x, string* result) {
+ for (int i = 0; i < size; ++i) {
+ if (x == NULL) {
+ StringAppendF(result, "Not Computed ");
+ } else {
+ if (x[i] == kImpossibleValue) {
+ StringAppendF(result, "Uninitialized ");
+ } else {
+ StringAppendF(result, "%12g ", x[i]);
+ }
+ }
+ }
+}
+
+void MapValuesToContiguousRange(const int size, int* array) {
+ std::vector<int> unique_values(array, array + size);
+ std::sort(unique_values.begin(), unique_values.end());
+ unique_values.erase(std::unique(unique_values.begin(),
+ unique_values.end()),
+ unique_values.end());
+
+ for (int i = 0; i < size; ++i) {
+ array[i] = std::lower_bound(unique_values.begin(),
+ unique_values.end(),
+ array[i]) - unique_values.begin();
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/array_utils.h b/extern/ceres/internal/ceres/array_utils.h
new file mode 100644
index 00000000000..2d2ffca8809
--- /dev/null
+++ b/extern/ceres/internal/ceres/array_utils.h
@@ -0,0 +1,89 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Utility routines for validating arrays.
+//
+// These are useful for detecting two common class of errors.
+//
+// 1. Uninitialized memory - where the user for some reason did not
+// compute part of an array, but the code expects it.
+//
+// 2. Numerical failure while computing the cost/residual/jacobian,
+// e.g. NaN, infinities etc. This is particularly useful since the
+// automatic differentiation code does computations that are not
+// evident to the user and can silently generate hard to debug errors.
+
+#ifndef CERES_INTERNAL_ARRAY_UTILS_H_
+#define CERES_INTERNAL_ARRAY_UTILS_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+// Fill the array x with an impossible value that the user code is
+// never expected to compute.
+void InvalidateArray(int size, double* x);
+
+// Check if all the entries of the array x are valid, i.e. all the
+// values in the array should be finite and none of them should be
+// equal to the "impossible" value used by InvalidateArray.
+bool IsArrayValid(int size, const double* x);
+
+// If the array contains an invalid value, return the index for it,
+// otherwise return size.
+int FindInvalidValue(const int size, const double* x);
+
+// Utility routine to print an array of doubles to a string. If the
+// array pointer is NULL, it is treated as an array of zeros.
+void AppendArrayToString(const int size, const double* x, std::string* result);
+
+extern const double kImpossibleValue;
+
+// This routine takes an array of integer values, sorts and uniques
+// them and then maps each value in the array to its position in the
+// sorted+uniqued array. By doing this, if there are are k unique
+// values in the array, each value is replaced by an integer in the
+// range [0, k-1], while preserving their relative order.
+//
+// For example
+//
+// [1 0 3 5 0 1 5]
+//
+// gets mapped to
+//
+// [1 0 2 3 0 1 3]
+void MapValuesToContiguousRange(int size, int* array);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_ARRAY_UTILS_H_
diff --git a/extern/ceres/internal/ceres/blas.cc b/extern/ceres/internal/ceres/blas.cc
new file mode 100644
index 00000000000..3ba63bbed5a
--- /dev/null
+++ b/extern/ceres/internal/ceres/blas.cc
@@ -0,0 +1,81 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/blas.h"
+#include "ceres/internal/port.h"
+#include "glog/logging.h"
+
+#ifndef CERES_NO_LAPACK
+extern "C" void dsyrk_(char* uplo,
+ char* trans,
+ int* n,
+ int* k,
+ double* alpha,
+ double* a,
+ int* lda,
+ double* beta,
+ double* c,
+ int* ldc);
+#endif
+
+namespace ceres {
+namespace internal {
+
+void BLAS::SymmetricRankKUpdate(int num_rows,
+ int num_cols,
+ const double* a,
+ bool transpose,
+ double alpha,
+ double beta,
+ double* c) {
+#ifdef CERES_NO_LAPACK
+ LOG(FATAL) << "Ceres was built without a BLAS library.";
+#else
+ char uplo = 'L';
+ char trans = transpose ? 'T' : 'N';
+ int n = transpose ? num_cols : num_rows;
+ int k = transpose ? num_rows : num_cols;
+ int lda = k;
+ int ldc = n;
+ dsyrk_(&uplo,
+ &trans,
+ &n,
+ &k,
+ &alpha,
+ const_cast<double*>(a),
+ &lda,
+ &beta,
+ c,
+ &ldc);
+#endif
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/blas.h b/extern/ceres/internal/ceres/blas.h
new file mode 100644
index 00000000000..a43301c5d18
--- /dev/null
+++ b/extern/ceres/internal/ceres/blas.h
@@ -0,0 +1,57 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Wrapper functions around BLAS functions.
+
+#ifndef CERES_INTERNAL_BLAS_H_
+#define CERES_INTERNAL_BLAS_H_
+
+namespace ceres {
+namespace internal {
+
+class BLAS {
+ public:
+ // transpose = true : c = alpha * a'a + beta * c;
+ // transpose = false : c = alpha * aa' + beta * c;
+ //
+ // Assumes column major matrices.
+ static void SymmetricRankKUpdate(int num_rows,
+ int num_cols,
+ const double* a,
+ bool transpose,
+ double alpha,
+ double beta,
+ double* c);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLAS_H_
diff --git a/extern/ceres/internal/ceres/block_evaluate_preparer.cc b/extern/ceres/internal/ceres/block_evaluate_preparer.cc
new file mode 100644
index 00000000000..59c0d3ecc10
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_evaluate_preparer.cc
@@ -0,0 +1,83 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/block_evaluate_preparer.h"
+
+#include <vector>
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/casts.h"
+#include "ceres/parameter_block.h"
+#include "ceres/residual_block.h"
+#include "ceres/sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+void BlockEvaluatePreparer::Init(int const* const* jacobian_layout,
+ int max_derivatives_per_residual_block) {
+ jacobian_layout_ = jacobian_layout;
+ scratch_evaluate_preparer_.Init(max_derivatives_per_residual_block);
+}
+
+// Point the jacobian blocks directly into the block sparse matrix.
+void BlockEvaluatePreparer::Prepare(const ResidualBlock* residual_block,
+ int residual_block_index,
+ SparseMatrix* jacobian,
+ double** jacobians) {
+ // If the overall jacobian is not available, use the scratch space.
+ if (jacobian == NULL) {
+ scratch_evaluate_preparer_.Prepare(residual_block,
+ residual_block_index,
+ jacobian,
+ jacobians);
+ return;
+ }
+
+ double* jacobian_values =
+ down_cast<BlockSparseMatrix*>(jacobian)->mutable_values();
+
+ const int* jacobian_block_offset = jacobian_layout_[residual_block_index];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (!residual_block->parameter_blocks()[j]->IsConstant()) {
+ jacobians[j] = jacobian_values + *jacobian_block_offset;
+
+ // The jacobian_block_offset can't be indexed with 'j' since the code
+ // that creates the layout strips out any blocks for inactive
+ // parameters. Instead, bump the pointer for active parameters only.
+ jacobian_block_offset++;
+ } else {
+ jacobians[j] = NULL;
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_evaluate_preparer.h b/extern/ceres/internal/ceres/block_evaluate_preparer.h
new file mode 100644
index 00000000000..4378689729f
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_evaluate_preparer.h
@@ -0,0 +1,77 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A evaluate preparer which puts jacobian the evaluated jacobian blocks
+// directly into their final resting place in an overall block sparse matrix.
+// The evaluator takes care to avoid evaluating the jacobian for fixed
+// parameters.
+
+#ifndef CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
+#define CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
+
+#include "ceres/scratch_evaluate_preparer.h"
+
+namespace ceres {
+namespace internal {
+
+class ResidualBlock;
+class SparseMatrix;
+
+class BlockEvaluatePreparer {
+ public:
+ // Using Init() instead of a constructor allows for allocating this structure
+ // with new[]. This is because C++ doesn't allow passing arguments to objects
+ // constructed with new[] (as opposed to plain 'new').
+ void Init(int const* const* jacobian_layout,
+ int max_derivatives_per_residual_block);
+
+ // EvaluatePreparer interface
+
+ // Point the jacobian blocks directly into the block sparse matrix, if
+ // jacobian is non-null. Otherwise, uses an internal per-thread buffer to
+ // store the jacobians temporarily.
+ void Prepare(const ResidualBlock* residual_block,
+ int residual_block_index,
+ SparseMatrix* jacobian,
+ double** jacobians);
+
+ private:
+ int const* const* jacobian_layout_;
+
+ // For the case that the overall jacobian is not available, but the
+ // individual jacobians are requested, use a pass-through scratch evaluate
+ // preparer.
+ ScratchEvaluatePreparer scratch_evaluate_preparer_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
diff --git a/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc b/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc
new file mode 100644
index 00000000000..22d4b351c51
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_jacobi_preconditioner.cc
@@ -0,0 +1,106 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/block_jacobi_preconditioner.h"
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/block_random_access_diagonal_matrix.h"
+#include "ceres/casts.h"
+#include "ceres/integral_types.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+BlockJacobiPreconditioner::BlockJacobiPreconditioner(
+ const BlockSparseMatrix& A) {
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ std::vector<int> blocks(bs->cols.size());
+ for (int i = 0; i < blocks.size(); ++i) {
+ blocks[i] = bs->cols[i].size;
+ }
+
+ m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
+}
+
+BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {}
+
+bool BlockJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+ const double* D) {
+ const CompressedRowBlockStructure* bs = A.block_structure();
+ const double* values = A.values();
+ m_->SetZero();
+ for (int i = 0; i < bs->rows.size(); ++i) {
+ const int row_block_size = bs->rows[i].block.size;
+ const std::vector<Cell>& cells = bs->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ const int block_id = cells[j].block_id;
+ const int col_block_size = bs->cols[block_id].size;
+
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = m_->GetCell(block_id, block_id,
+ &r, &c,
+ &row_stride, &col_stride);
+ MatrixRef m(cell_info->values, row_stride, col_stride);
+ ConstMatrixRef b(values + cells[j].position,
+ row_block_size,
+ col_block_size);
+ m.block(r, c, col_block_size, col_block_size) += b.transpose() * b;
+ }
+ }
+
+ if (D != NULL) {
+ // Add the diagonal.
+ int position = 0;
+ for (int i = 0; i < bs->cols.size(); ++i) {
+ const int block_size = bs->cols[i].size;
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = m_->GetCell(i, i,
+ &r, &c,
+ &row_stride, &col_stride);
+ MatrixRef m(cell_info->values, row_stride, col_stride);
+ m.block(r, c, block_size, block_size).diagonal() +=
+ ConstVectorRef(D + position, block_size).array().square().matrix();
+ position += block_size;
+ }
+ }
+
+ m_->Invert();
+ return true;
+}
+
+void BlockJacobiPreconditioner::RightMultiply(const double* x,
+ double* y) const {
+ m_->RightMultiply(x, y);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_jacobi_preconditioner.h b/extern/ceres/internal/ceres/block_jacobi_preconditioner.h
new file mode 100644
index 00000000000..14007295823
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_jacobi_preconditioner.h
@@ -0,0 +1,76 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
+#define CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
+
+#include <vector>
+#include "ceres/block_random_access_diagonal_matrix.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/preconditioner.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrix;
+struct CompressedRowBlockStructure;
+
+// A block Jacobi preconditioner. This is intended for use with
+// conjugate gradients, or other iterative symmetric solvers. To use
+// the preconditioner, create one by passing a BlockSparseMatrix "A"
+// to the constructor. This fixes the sparsity pattern to the pattern
+// of the matrix A^TA.
+//
+// Before each use of the preconditioner in a solve with conjugate gradients,
+// update the matrix by running Update(A, D). The values of the matrix A are
+// inspected to construct the preconditioner. The vector D is applied as the
+// D^TD diagonal term.
+class BlockJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
+ public:
+ // A must remain valid while the BlockJacobiPreconditioner is.
+ explicit BlockJacobiPreconditioner(const BlockSparseMatrix& A);
+ virtual ~BlockJacobiPreconditioner();
+
+ // Preconditioner interface
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const { return m_->num_rows(); }
+ virtual int num_cols() const { return m_->num_rows(); }
+
+ const BlockRandomAccessDiagonalMatrix& matrix() const { return *m_; }
+ private:
+ virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+
+ scoped_ptr<BlockRandomAccessDiagonalMatrix> m_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
diff --git a/extern/ceres/internal/ceres/block_jacobian_writer.cc b/extern/ceres/internal/ceres/block_jacobian_writer.cc
new file mode 100644
index 00000000000..7a3fee4fbdf
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_jacobian_writer.cc
@@ -0,0 +1,214 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/block_jacobian_writer.h"
+
+#include "ceres/block_evaluate_preparer.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+namespace {
+
+// Given the residual block ordering, build a lookup table to determine which
+// per-parameter jacobian goes where in the overall program jacobian.
+//
+// Since we expect to use a Schur type linear solver to solve the LM step, take
+// extra care to place the E blocks and the F blocks contiguously. E blocks are
+// the first num_eliminate_blocks parameter blocks as indicated by the parameter
+// block ordering. The remaining parameter blocks are the F blocks.
+//
+// TODO(keir): Consider if we should use a boolean for each parameter block
+// instead of num_eliminate_blocks.
+void BuildJacobianLayout(const Program& program,
+ int num_eliminate_blocks,
+ vector<int*>* jacobian_layout,
+ vector<int>* jacobian_layout_storage) {
+ const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+
+ // Iterate over all the active residual blocks and determine how many E blocks
+ // are there. This will determine where the F blocks start in the jacobian
+ // matrix. Also compute the number of jacobian blocks.
+ int f_block_pos = 0;
+ int num_jacobian_blocks = 0;
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks[i];
+ const int num_residuals = residual_block->NumResiduals();
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+
+ // Advance f_block_pos over each E block for this residual.
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ if (!parameter_block->IsConstant()) {
+ // Only count blocks for active parameters.
+ num_jacobian_blocks++;
+ if (parameter_block->index() < num_eliminate_blocks) {
+ f_block_pos += num_residuals * parameter_block->LocalSize();
+ }
+ }
+ }
+ }
+
+ // We now know that the E blocks are laid out starting at zero, and the F
+ // blocks are laid out starting at f_block_pos. Iterate over the residual
+ // blocks again, and this time fill the jacobian_layout array with the
+ // position information.
+
+ jacobian_layout->resize(program.NumResidualBlocks());
+ jacobian_layout_storage->resize(num_jacobian_blocks);
+
+ int e_block_pos = 0;
+ int* jacobian_pos = &(*jacobian_layout_storage)[0];
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ const ResidualBlock* residual_block = residual_blocks[i];
+ const int num_residuals = residual_block->NumResiduals();
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+
+ (*jacobian_layout)[i] = jacobian_pos;
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ const int parameter_block_index = parameter_block->index();
+ if (parameter_block->IsConstant()) {
+ continue;
+ }
+ const int jacobian_block_size =
+ num_residuals * parameter_block->LocalSize();
+ if (parameter_block_index < num_eliminate_blocks) {
+ *jacobian_pos = e_block_pos;
+ e_block_pos += jacobian_block_size;
+ } else {
+ *jacobian_pos = f_block_pos;
+ f_block_pos += jacobian_block_size;
+ }
+ jacobian_pos++;
+ }
+ }
+}
+
+} // namespace
+
+BlockJacobianWriter::BlockJacobianWriter(const Evaluator::Options& options,
+ Program* program)
+ : program_(program) {
+ CHECK_GE(options.num_eliminate_blocks, 0)
+ << "num_eliminate_blocks must be greater than 0.";
+
+ BuildJacobianLayout(*program,
+ options.num_eliminate_blocks,
+ &jacobian_layout_,
+ &jacobian_layout_storage_);
+}
+
+// Create evaluate prepareres that point directly into the final jacobian. This
+// makes the final Write() a nop.
+BlockEvaluatePreparer* BlockJacobianWriter::CreateEvaluatePreparers(
+ int num_threads) {
+ int max_derivatives_per_residual_block =
+ program_->MaxDerivativesPerResidualBlock();
+
+ BlockEvaluatePreparer* preparers = new BlockEvaluatePreparer[num_threads];
+ for (int i = 0; i < num_threads; i++) {
+ preparers[i].Init(&jacobian_layout_[0], max_derivatives_per_residual_block);
+ }
+ return preparers;
+}
+
+SparseMatrix* BlockJacobianWriter::CreateJacobian() const {
+ CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+
+ const vector<ParameterBlock*>& parameter_blocks =
+ program_->parameter_blocks();
+
+ // Construct the column blocks.
+ bs->cols.resize(parameter_blocks.size());
+ for (int i = 0, cursor = 0; i < parameter_blocks.size(); ++i) {
+ CHECK_NE(parameter_blocks[i]->index(), -1);
+ CHECK(!parameter_blocks[i]->IsConstant());
+ bs->cols[i].size = parameter_blocks[i]->LocalSize();
+ bs->cols[i].position = cursor;
+ cursor += bs->cols[i].size;
+ }
+
+ // Construct the cells in each row.
+ const vector<ResidualBlock*>& residual_blocks = program_->residual_blocks();
+ int row_block_position = 0;
+ bs->rows.resize(residual_blocks.size());
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ const ResidualBlock* residual_block = residual_blocks[i];
+ CompressedRow* row = &bs->rows[i];
+
+ row->block.size = residual_block->NumResiduals();
+ row->block.position = row_block_position;
+ row_block_position += row->block.size;
+
+ // Size the row by the number of active parameters in this residual.
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ int num_active_parameter_blocks = 0;
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (residual_block->parameter_blocks()[j]->index() != -1) {
+ num_active_parameter_blocks++;
+ }
+ }
+ row->cells.resize(num_active_parameter_blocks);
+
+ // Add layout information for the active parameters in this row.
+ for (int j = 0, k = 0; j < num_parameter_blocks; ++j) {
+ const ParameterBlock* parameter_block =
+ residual_block->parameter_blocks()[j];
+ if (!parameter_block->IsConstant()) {
+ Cell& cell = row->cells[k];
+ cell.block_id = parameter_block->index();
+ cell.position = jacobian_layout_[i][k];
+
+ // Only increment k for active parameters, since there is only layout
+ // information for active parameters.
+ k++;
+ }
+ }
+
+ sort(row->cells.begin(), row->cells.end(), CellLessThan);
+ }
+
+ BlockSparseMatrix* jacobian = new BlockSparseMatrix(bs);
+ CHECK_NOTNULL(jacobian);
+ return jacobian;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_jacobian_writer.h b/extern/ceres/internal/ceres/block_jacobian_writer.h
new file mode 100644
index 00000000000..8e6f45130a4
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_jacobian_writer.h
@@ -0,0 +1,127 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A jacobian writer that writes to block sparse matrices. The "writer" name is
+// misleading, since the Write() operation on the block jacobian writer does not
+// write anything. Instead, the Prepare() method on the BlockEvaluatePreparers
+// makes a jacobians array which has direct pointers into the block sparse
+// jacobian. When the cost function is evaluated, the jacobian blocks get placed
+// directly in their final location.
+
+#ifndef CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
+#define CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
+
+#include <vector>
+#include "ceres/evaluator.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockEvaluatePreparer;
+class Program;
+class SparseMatrix;
+
+class BlockJacobianWriter {
+ public:
+ BlockJacobianWriter(const Evaluator::Options& options,
+ Program* program);
+
+ // JacobianWriter interface.
+
+ // Create evaluate prepareres that point directly into the final jacobian.
+ // This makes the final Write() a nop.
+ BlockEvaluatePreparer* CreateEvaluatePreparers(int num_threads);
+
+ SparseMatrix* CreateJacobian() const;
+
+ void Write(int /* residual_id */,
+ int /* residual_offset */,
+ double** /* jacobians */,
+ SparseMatrix* /* jacobian */) {
+ // This is a noop since the blocks were written directly into their final
+ // position by the outside evaluate call, thanks to the jacobians array
+ // prepared by the BlockEvaluatePreparers.
+ }
+
+ private:
+ Program* program_;
+
+ // Stores the position of each residual / parameter jacobian.
+ //
+ // The block sparse matrix that this writer writes to is stored as a set of
+ // contiguos dense blocks, one after each other; see BlockSparseMatrix. The
+ // "double* values_" member of the block sparse matrix contains all of these
+ // blocks. Given a pointer to the first element of a block and the size of
+ // that block, it's possible to write to it.
+ //
+ // In the case of a block sparse jacobian, the jacobian writer needs a way to
+ // find the offset in the values_ array of each residual/parameter jacobian
+ // block.
+ //
+ // That is the purpose of jacobian_layout_.
+ //
+ // In particular, jacobian_layout_[i][j] is the offset in the values_ array of
+ // the derivative of residual block i with respect to the parameter block at
+ // active argument position j.
+ //
+ // The active qualifier means that non-active parameters do not count. Care
+ // must be taken when indexing into jacobian_layout_ to account for this.
+ // Consider a single residual example:
+ //
+ // r(x, y, z)
+ //
+ // with r in R^3, x in R^4, y in R^2, and z in R^5.
+ // Take y as a constant (non-active) parameter.
+ // Take r as residual number 0.
+ //
+ // In this case, the active arguments are only (x, z), so the active argument
+ // position for x is 0, and the active argument position for z is 1. This is
+ // similar to thinking of r as taking only 2 parameters:
+ //
+ // r(x, z)
+ //
+ // There are only 2 jacobian blocks: dr/dx and dr/dz. jacobian_layout_ would
+ // have the following contents:
+ //
+ // jacobian_layout_[0] = { 0, 12 }
+ //
+ // which indicates that dr/dx is located at values_[0], and dr/dz is at
+ // values_[12]. See BlockEvaluatePreparer::Prepare()'s comments about 'j'.
+ std::vector<int*> jacobian_layout_;
+
+ // The pointers in jacobian_layout_ point directly into this vector.
+ std::vector<int> jacobian_layout_storage_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
diff --git a/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc b/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc
new file mode 100644
index 00000000000..61748ef6f7f
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_dense_matrix.cc
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/block_random_access_dense_matrix.h"
+
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+BlockRandomAccessDenseMatrix::BlockRandomAccessDenseMatrix(
+ const std::vector<int>& blocks) {
+ const int num_blocks = blocks.size();
+ block_layout_.resize(num_blocks, 0);
+ num_rows_ = 0;
+ for (int i = 0; i < num_blocks; ++i) {
+ block_layout_[i] = num_rows_;
+ num_rows_ += blocks[i];
+ }
+
+ values_.reset(new double[num_rows_ * num_rows_]);
+
+ cell_infos_.reset(new CellInfo[num_blocks * num_blocks]);
+ for (int i = 0; i < num_blocks * num_blocks; ++i) {
+ cell_infos_[i].values = values_.get();
+ }
+
+ SetZero();
+}
+
+// Assume that the user does not hold any locks on any cell blocks
+// when they are calling SetZero.
+BlockRandomAccessDenseMatrix::~BlockRandomAccessDenseMatrix() {
+}
+
+CellInfo* BlockRandomAccessDenseMatrix::GetCell(const int row_block_id,
+ const int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) {
+ *row = block_layout_[row_block_id];
+ *col = block_layout_[col_block_id];
+ *row_stride = num_rows_;
+ *col_stride = num_rows_;
+ return &cell_infos_[row_block_id * block_layout_.size() + col_block_id];
+}
+
+// Assume that the user does not hold any locks on any cell blocks
+// when they are calling SetZero.
+void BlockRandomAccessDenseMatrix::SetZero() {
+ if (num_rows_) {
+ VectorRef(values_.get(), num_rows_ * num_rows_).setZero();
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_random_access_dense_matrix.h b/extern/ceres/internal/ceres/block_random_access_dense_matrix.h
new file mode 100644
index 00000000000..89689082561
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_dense_matrix.h
@@ -0,0 +1,98 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
+#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
+
+#include "ceres/block_random_access_matrix.h"
+
+#include <vector>
+
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+namespace internal {
+
+// A square block random accessible matrix with the same row and
+// column block structure. All cells are stored in the same single
+// array, so that its also accessible as a dense matrix of size
+// num_rows x num_cols.
+//
+// This class is NOT thread safe. Since all n^2 cells are stored,
+// GetCell never returns NULL for any (row_block_id, col_block_id)
+// pair.
+//
+// ReturnCell is a nop.
+class BlockRandomAccessDenseMatrix : public BlockRandomAccessMatrix {
+ public:
+ // blocks is a vector of block sizes. The resulting matrix has
+ // blocks.size() * blocks.size() cells.
+ explicit BlockRandomAccessDenseMatrix(const std::vector<int>& blocks);
+
+ // The destructor is not thread safe. It assumes that no one is
+ // modifying any cells when the matrix is being destroyed.
+ virtual ~BlockRandomAccessDenseMatrix();
+
+ // BlockRandomAccessMatrix interface.
+ virtual CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride);
+
+ // This is not a thread safe method, it assumes that no cell is
+ // locked.
+ virtual void SetZero();
+
+ // Since the matrix is square with the same row and column block
+ // structure, num_rows() = num_cols().
+ virtual int num_rows() const { return num_rows_; }
+ virtual int num_cols() const { return num_rows_; }
+
+ // The underlying matrix storing the cells.
+ const double* values() const { return values_.get(); }
+ double* mutable_values() { return values_.get(); }
+
+ private:
+ int num_rows_;
+ std::vector<int> block_layout_;
+ scoped_array<double> values_;
+ scoped_array<CellInfo> cell_infos_;
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDenseMatrix);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
new file mode 100644
index 00000000000..052690d18be
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
@@ -0,0 +1,154 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/block_random_access_diagonal_matrix.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+#include "Eigen/Dense"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/stl_util.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+// TODO(sameeragarwal): Drop the dependence on TripletSparseMatrix.
+
+BlockRandomAccessDiagonalMatrix::BlockRandomAccessDiagonalMatrix(
+ const vector<int>& blocks)
+ : blocks_(blocks) {
+ // Build the row/column layout vector and count the number of scalar
+ // rows/columns.
+ int num_cols = 0;
+ int num_nonzeros = 0;
+ vector<int> block_positions;
+ for (int i = 0; i < blocks_.size(); ++i) {
+ block_positions.push_back(num_cols);
+ num_cols += blocks_[i];
+ num_nonzeros += blocks_[i] * blocks_[i];
+ }
+
+ VLOG(1) << "Matrix Size [" << num_cols
+ << "," << num_cols
+ << "] " << num_nonzeros;
+
+ tsm_.reset(new TripletSparseMatrix(num_cols, num_cols, num_nonzeros));
+ tsm_->set_num_nonzeros(num_nonzeros);
+ int* rows = tsm_->mutable_rows();
+ int* cols = tsm_->mutable_cols();
+ double* values = tsm_->mutable_values();
+
+ int pos = 0;
+ for (int i = 0; i < blocks_.size(); ++i) {
+ const int block_size = blocks_[i];
+ layout_.push_back(new CellInfo(values + pos));
+ const int block_begin = block_positions[i];
+ for (int r = 0; r < block_size; ++r) {
+ for (int c = 0; c < block_size; ++c, ++pos) {
+ rows[pos] = block_begin + r;
+ cols[pos] = block_begin + c;
+ }
+ }
+ }
+}
+
+// Assume that the user does not hold any locks on any cell blocks
+// when they are calling SetZero.
+BlockRandomAccessDiagonalMatrix::~BlockRandomAccessDiagonalMatrix() {
+ STLDeleteContainerPointers(layout_.begin(), layout_.end());
+}
+
+CellInfo* BlockRandomAccessDiagonalMatrix::GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) {
+ if (row_block_id != col_block_id) {
+ return NULL;
+ }
+ const int stride = blocks_[row_block_id];
+
+ // Each cell is stored contiguously as its own little dense matrix.
+ *row = 0;
+ *col = 0;
+ *row_stride = stride;
+ *col_stride = stride;
+ return layout_[row_block_id];
+}
+
+// Assume that the user does not hold any locks on any cell blocks
+// when they are calling SetZero.
+void BlockRandomAccessDiagonalMatrix::SetZero() {
+ if (tsm_->num_nonzeros()) {
+ VectorRef(tsm_->mutable_values(),
+ tsm_->num_nonzeros()).setZero();
+ }
+}
+
+void BlockRandomAccessDiagonalMatrix::Invert() {
+ double* values = tsm_->mutable_values();
+ for (int i = 0; i < blocks_.size(); ++i) {
+ const int block_size = blocks_[i];
+ MatrixRef block(values, block_size, block_size);
+ block =
+ block
+ .selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(Matrix::Identity(block_size, block_size));
+ values += block_size * block_size;
+ }
+}
+
+void BlockRandomAccessDiagonalMatrix::RightMultiply(const double* x,
+ double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+ const double* values = tsm_->values();
+ for (int i = 0; i < blocks_.size(); ++i) {
+ const int block_size = blocks_[i];
+ ConstMatrixRef block(values, block_size, block_size);
+ VectorRef(y, block_size).noalias() += block * ConstVectorRef(x, block_size);
+ x += block_size;
+ y += block_size;
+ values += block_size * block_size;
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h
new file mode 100644
index 00000000000..07ffc9d4a0d
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_diagonal_matrix.h
@@ -0,0 +1,101 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
+#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
+
+#include <set>
+#include <vector>
+#include <utility>
+#include "ceres/mutex.h"
+#include "ceres/block_random_access_matrix.h"
+#include "ceres/collections_port.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/integral_types.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+// A thread safe block diagonal matrix implementation of
+// BlockRandomAccessMatrix.
+class BlockRandomAccessDiagonalMatrix : public BlockRandomAccessMatrix {
+ public:
+ // blocks is an array of block sizes.
+ explicit BlockRandomAccessDiagonalMatrix(const std::vector<int>& blocks);
+
+ // The destructor is not thread safe. It assumes that no one is
+ // modifying any cells when the matrix is being destroyed.
+ virtual ~BlockRandomAccessDiagonalMatrix();
+
+ // BlockRandomAccessMatrix Interface.
+ virtual CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride);
+
+ // This is not a thread safe method, it assumes that no cell is
+ // locked.
+ virtual void SetZero();
+
+ // Invert the matrix assuming that each block is positive definite.
+ void Invert();
+
+ // y += S * x
+ void RightMultiply(const double* x, double* y) const;
+
+ // Since the matrix is square, num_rows() == num_cols().
+ virtual int num_rows() const { return tsm_->num_rows(); }
+ virtual int num_cols() const { return tsm_->num_cols(); }
+
+ const TripletSparseMatrix* matrix() const { return tsm_.get(); }
+ TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
+
+ private:
+ // row/column block sizes.
+ const std::vector<int> blocks_;
+ std::vector<CellInfo*> layout_;
+
+ // The underlying matrix object which actually stores the cells.
+ scoped_ptr<TripletSparseMatrix> tsm_;
+
+ friend class BlockRandomAccessDiagonalMatrixTest;
+ CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDiagonalMatrix);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/block_random_access_matrix.cc b/extern/ceres/internal/ceres/block_random_access_matrix.cc
new file mode 100644
index 00000000000..347d765bbca
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_matrix.cc
@@ -0,0 +1,40 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/block_random_access_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+BlockRandomAccessMatrix::~BlockRandomAccessMatrix() {
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_random_access_matrix.h b/extern/ceres/internal/ceres/block_random_access_matrix.h
new file mode 100644
index 00000000000..34c8bf5cd4d
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_matrix.h
@@ -0,0 +1,132 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Interface for matrices that allow block based random access.
+
+#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
+#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
+
+#include "ceres/mutex.h"
+
+namespace ceres {
+namespace internal {
+
+// A matrix implementing the BlockRandomAccessMatrix interface is a
+// matrix whose rows and columns are divided into blocks. For example
+// the matrix A:
+//
+// 3 4 5
+// A = 5 [c_11 c_12 c_13]
+// 4 [c_21 c_22 c_23]
+//
+// has row blocks of size 5 and 4, and column blocks of size 3, 4 and
+// 5. It has six cells corresponding to the six row-column block
+// combinations.
+//
+// BlockRandomAccessMatrix objects provide access to cells c_ij using
+// the GetCell method. when a cell is present, GetCell will return a
+// CellInfo object containing a pointer to an array which contains the
+// cell as a submatrix and a mutex that guards this submatrix. If the
+// user is accessing the matrix concurrently, it is his responsibility
+// to use the mutex to exclude other writers from writing to the cell
+// concurrently.
+//
+// There is no requirement that all cells be present, i.e. the matrix
+// itself can be block sparse. When a cell is not present, the GetCell
+// method will return a NULL pointer.
+//
+// There is no requirement about how the cells are stored beyond that
+// form a dense submatrix of a larger dense matrix. Like everywhere
+// else in Ceres, RowMajor storage assumed.
+//
+// Example usage:
+//
+// BlockRandomAccessMatrix* A = new BlockRandomAccessMatrixSubClass(...)
+//
+// int row, col, row_stride, col_stride;
+// CellInfo* cell = A->GetCell(row_block_id, col_block_id,
+// &row, &col,
+// &row_stride, &col_stride);
+//
+// if (cell != NULL) {
+// MatrixRef m(cell->values, row_stride, col_stride);
+// CeresMutexLock l(&cell->m);
+// m.block(row, col, row_block_size, col_block_size) = ...
+// }
+
+// Structure to carry a pointer to the array containing a cell and the
+// Mutex guarding it.
+struct CellInfo {
+ CellInfo()
+ : values(NULL) {
+ }
+
+ explicit CellInfo(double* ptr)
+ : values(ptr) {
+ }
+
+ double* values;
+ Mutex m;
+};
+
+class BlockRandomAccessMatrix {
+ public:
+ virtual ~BlockRandomAccessMatrix();
+
+ // If the cell (row_block_id, col_block_id) is present, then return
+ // a CellInfo with a pointer to the dense matrix containing it,
+ // otherwise return NULL. The dense matrix containing this cell has
+ // size row_stride, col_stride and the cell is located at position
+ // (row, col) within this matrix.
+ //
+ // The size of the cell is row_block_size x col_block_size is
+ // assumed known to the caller. row_block_size less than or equal to
+ // row_stride and col_block_size is upper bounded by col_stride.
+ virtual CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) = 0;
+
+ // Zero out the values of the array. The structure of the matrix
+ // (size and sparsity) is preserved.
+ virtual void SetZero() = 0;
+
+ // Number of scalar rows and columns in the matrix, i.e the sum of
+ // all row blocks and column block sizes respectively.
+ virtual int num_rows() const = 0;
+ virtual int num_cols() const = 0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc
new file mode 100644
index 00000000000..5432ec1064a
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.cc
@@ -0,0 +1,196 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/block_random_access_sparse_matrix.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/mutex.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::make_pair;
+using std::pair;
+using std::set;
+using std::vector;
+
+BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
+ const vector<int>& blocks,
+ const set<pair<int, int> >& block_pairs)
+ : kMaxRowBlocks(10 * 1000 * 1000),
+ blocks_(blocks) {
+ CHECK_LT(blocks.size(), kMaxRowBlocks);
+
+ // Build the row/column layout vector and count the number of scalar
+ // rows/columns.
+ int num_cols = 0;
+ block_positions_.reserve(blocks_.size());
+ for (int i = 0; i < blocks_.size(); ++i) {
+ block_positions_.push_back(num_cols);
+ num_cols += blocks_[i];
+ }
+
+ // Count the number of scalar non-zero entries and build the layout
+ // object for looking into the values array of the
+ // TripletSparseMatrix.
+ int num_nonzeros = 0;
+ for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
+ it != block_pairs.end();
+ ++it) {
+ const int row_block_size = blocks_[it->first];
+ const int col_block_size = blocks_[it->second];
+ num_nonzeros += row_block_size * col_block_size;
+ }
+
+ VLOG(1) << "Matrix Size [" << num_cols
+ << "," << num_cols
+ << "] " << num_nonzeros;
+
+ tsm_.reset(new TripletSparseMatrix(num_cols, num_cols, num_nonzeros));
+ tsm_->set_num_nonzeros(num_nonzeros);
+ int* rows = tsm_->mutable_rows();
+ int* cols = tsm_->mutable_cols();
+ double* values = tsm_->mutable_values();
+
+ int pos = 0;
+ for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
+ it != block_pairs.end();
+ ++it) {
+ const int row_block_size = blocks_[it->first];
+ const int col_block_size = blocks_[it->second];
+ cell_values_.push_back(make_pair(make_pair(it->first, it->second),
+ values + pos));
+ layout_[IntPairToLong(it->first, it->second)] =
+ new CellInfo(values + pos);
+ pos += row_block_size * col_block_size;
+ }
+
+ // Fill the sparsity pattern of the underlying matrix.
+ for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
+ it != block_pairs.end();
+ ++it) {
+ const int row_block_id = it->first;
+ const int col_block_id = it->second;
+ const int row_block_size = blocks_[row_block_id];
+ const int col_block_size = blocks_[col_block_id];
+ int pos =
+ layout_[IntPairToLong(row_block_id, col_block_id)]->values - values;
+ for (int r = 0; r < row_block_size; ++r) {
+ for (int c = 0; c < col_block_size; ++c, ++pos) {
+ rows[pos] = block_positions_[row_block_id] + r;
+ cols[pos] = block_positions_[col_block_id] + c;
+ values[pos] = 1.0;
+ DCHECK_LT(rows[pos], tsm_->num_rows());
+ DCHECK_LT(cols[pos], tsm_->num_rows());
+ }
+ }
+ }
+}
+
+// Assume that the user does not hold any locks on any cell blocks
+// when they are calling SetZero.
+BlockRandomAccessSparseMatrix::~BlockRandomAccessSparseMatrix() {
+ for (LayoutType::iterator it = layout_.begin();
+ it != layout_.end();
+ ++it) {
+ delete it->second;
+ }
+}
+
+CellInfo* BlockRandomAccessSparseMatrix::GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride) {
+ const LayoutType::iterator it =
+ layout_.find(IntPairToLong(row_block_id, col_block_id));
+ if (it == layout_.end()) {
+ return NULL;
+ }
+
+ // Each cell is stored contiguously as its own little dense matrix.
+ *row = 0;
+ *col = 0;
+ *row_stride = blocks_[row_block_id];
+ *col_stride = blocks_[col_block_id];
+ return it->second;
+}
+
+// Assume that the user does not hold any locks on any cell blocks
+// when they are calling SetZero.
+void BlockRandomAccessSparseMatrix::SetZero() {
+ if (tsm_->num_nonzeros()) {
+ VectorRef(tsm_->mutable_values(),
+ tsm_->num_nonzeros()).setZero();
+ }
+}
+
+void BlockRandomAccessSparseMatrix::SymmetricRightMultiply(const double* x,
+ double* y) const {
+ vector< pair<pair<int, int>, double*> >::const_iterator it =
+ cell_values_.begin();
+ for (; it != cell_values_.end(); ++it) {
+ const int row = it->first.first;
+ const int row_block_size = blocks_[row];
+ const int row_block_pos = block_positions_[row];
+
+ const int col = it->first.second;
+ const int col_block_size = blocks_[col];
+ const int col_block_pos = block_positions_[col];
+
+ MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ it->second, row_block_size, col_block_size,
+ x + col_block_pos,
+ y + row_block_pos);
+
+ // Since the matrix is symmetric, but only the upper triangular
+ // part is stored, if the block being accessed is not a diagonal
+ // block, then use the same block to do the corresponding lower
+ // triangular multiply also.
+ if (row != col) {
+ MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ it->second, row_block_size, col_block_size,
+ x + row_block_pos,
+ y + col_block_pos);
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h
new file mode 100644
index 00000000000..2b3c7fdabae
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_random_access_sparse_matrix.h
@@ -0,0 +1,129 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
+
+#include <set>
+#include <vector>
+#include <utility>
+#include "ceres/mutex.h"
+#include "ceres/block_random_access_matrix.h"
+#include "ceres/collections_port.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/integral_types.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "ceres/small_blas.h"
+
+namespace ceres {
+namespace internal {
+
+// A thread safe square block sparse implementation of
+// BlockRandomAccessMatrix. Internally a TripletSparseMatrix is used
+// for doing the actual storage. This class augments this matrix with
+// an unordered_map that allows random read/write access.
+class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix {
+ public:
+ // blocks is an array of block sizes. block_pairs is a set of
+ // <row_block_id, col_block_id> pairs to identify the non-zero cells
+ // of this matrix.
+ BlockRandomAccessSparseMatrix(
+ const std::vector<int>& blocks,
+ const std::set<std::pair<int, int> >& block_pairs);
+
+ // The destructor is not thread safe. It assumes that no one is
+ // modifying any cells when the matrix is being destroyed.
+ virtual ~BlockRandomAccessSparseMatrix();
+
+ // BlockRandomAccessMatrix Interface.
+ virtual CellInfo* GetCell(int row_block_id,
+ int col_block_id,
+ int* row,
+ int* col,
+ int* row_stride,
+ int* col_stride);
+
+ // This is not a thread safe method, it assumes that no cell is
+ // locked.
+ virtual void SetZero();
+
+ // Assume that the matrix is symmetric and only one half of the
+ // matrix is stored.
+ //
+ // y += S * x
+ void SymmetricRightMultiply(const double* x, double* y) const;
+
+ // Since the matrix is square, num_rows() == num_cols().
+ virtual int num_rows() const { return tsm_->num_rows(); }
+ virtual int num_cols() const { return tsm_->num_cols(); }
+
+ // Access to the underlying matrix object.
+ const TripletSparseMatrix* matrix() const { return tsm_.get(); }
+ TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
+
+ private:
+ int64 IntPairToLong(int row, int col) const {
+ return row * kMaxRowBlocks + col;
+ }
+
+ void LongToIntPair(int64 index, int* row, int* col) const {
+ *row = index / kMaxRowBlocks;
+ *col = index % kMaxRowBlocks;
+ }
+
+ const int64 kMaxRowBlocks;
+
+ // row/column block sizes.
+ const std::vector<int> blocks_;
+ std::vector<int> block_positions_;
+
+ // A mapping from <row_block_id, col_block_id> to the position in
+ // the values array of tsm_ where the block is stored.
+ typedef HashMap<long int, CellInfo* > LayoutType;
+ LayoutType layout_;
+
+ // In order traversal of contents of the matrix. This allows us to
+ // implement a matrix-vector which is 20% faster than using the
+ // iterator in the Layout object instead.
+ std::vector<std::pair<std::pair<int, int>, double*> > cell_values_;
+ // The underlying matrix object which actually stores the cells.
+ scoped_ptr<TripletSparseMatrix> tsm_;
+
+ friend class BlockRandomAccessSparseMatrixTest;
+ CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessSparseMatrix);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/block_sparse_matrix.cc b/extern/ceres/internal/ceres/block_sparse_matrix.cc
new file mode 100644
index 00000000000..68d0780156c
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_sparse_matrix.cc
@@ -0,0 +1,246 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/block_sparse_matrix.h"
+
+#include <cstddef>
+#include <algorithm>
+#include <vector>
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/small_blas.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+BlockSparseMatrix::~BlockSparseMatrix() {}
+
+BlockSparseMatrix::BlockSparseMatrix(
+ CompressedRowBlockStructure* block_structure)
+ : num_rows_(0),
+ num_cols_(0),
+ num_nonzeros_(0),
+ values_(NULL),
+ block_structure_(block_structure) {
+ CHECK_NOTNULL(block_structure_.get());
+
+ // Count the number of columns in the matrix.
+ for (int i = 0; i < block_structure_->cols.size(); ++i) {
+ num_cols_ += block_structure_->cols[i].size;
+ }
+
+ // Count the number of non-zero entries and the number of rows in
+ // the matrix.
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_size = block_structure_->rows[i].block.size;
+ num_rows_ += row_block_size;
+
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ num_nonzeros_ += col_block_size * row_block_size;
+ }
+ }
+
+ CHECK_GE(num_rows_, 0);
+ CHECK_GE(num_cols_, 0);
+ CHECK_GE(num_nonzeros_, 0);
+ VLOG(2) << "Allocating values array with "
+ << num_nonzeros_ * sizeof(double) << " bytes."; // NOLINT
+ values_.reset(new double[num_nonzeros_]);
+ CHECK_NOTNULL(values_.get());
+}
+
+void BlockSparseMatrix::SetZero() {
+ std::fill(values_.get(), values_.get() + num_nonzeros_, 0.0);
+}
+
+void BlockSparseMatrix::RightMultiply(const double* x, double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_pos = block_structure_->rows[i].block.position;
+ int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ int col_block_pos = block_structure_->cols[col_block_id].position;
+ MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values_.get() + cells[j].position, row_block_size, col_block_size,
+ x + col_block_pos,
+ y + row_block_pos);
+ }
+ }
+}
+
+void BlockSparseMatrix::LeftMultiply(const double* x, double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_pos = block_structure_->rows[i].block.position;
+ int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ int col_block_pos = block_structure_->cols[col_block_id].position;
+ MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values_.get() + cells[j].position, row_block_size, col_block_size,
+ x + row_block_pos,
+ y + col_block_pos);
+ }
+ }
+}
+
+void BlockSparseMatrix::SquaredColumnNorm(double* x) const {
+ CHECK_NOTNULL(x);
+ VectorRef(x, num_cols_).setZero();
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ int col_block_pos = block_structure_->cols[col_block_id].position;
+ const MatrixRef m(values_.get() + cells[j].position,
+ row_block_size, col_block_size);
+ VectorRef(x + col_block_pos, col_block_size) += m.colwise().squaredNorm();
+ }
+ }
+}
+
+void BlockSparseMatrix::ScaleColumns(const double* scale) {
+ CHECK_NOTNULL(scale);
+
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ int col_block_pos = block_structure_->cols[col_block_id].position;
+ MatrixRef m(values_.get() + cells[j].position,
+ row_block_size, col_block_size);
+ m *= ConstVectorRef(scale + col_block_pos, col_block_size).asDiagonal();
+ }
+ }
+}
+
+void BlockSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
+ CHECK_NOTNULL(dense_matrix);
+
+ dense_matrix->resize(num_rows_, num_cols_);
+ dense_matrix->setZero();
+ Matrix& m = *dense_matrix;
+
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_pos = block_structure_->rows[i].block.position;
+ int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ int col_block_pos = block_structure_->cols[col_block_id].position;
+ int jac_pos = cells[j].position;
+ m.block(row_block_pos, col_block_pos, row_block_size, col_block_size)
+ += MatrixRef(values_.get() + jac_pos, row_block_size, col_block_size);
+ }
+ }
+}
+
+void BlockSparseMatrix::ToTripletSparseMatrix(
+ TripletSparseMatrix* matrix) const {
+ CHECK_NOTNULL(matrix);
+
+ matrix->Reserve(num_nonzeros_);
+ matrix->Resize(num_rows_, num_cols_);
+ matrix->SetZero();
+
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ int row_block_pos = block_structure_->rows[i].block.position;
+ int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ int col_block_id = cells[j].block_id;
+ int col_block_size = block_structure_->cols[col_block_id].size;
+ int col_block_pos = block_structure_->cols[col_block_id].position;
+ int jac_pos = cells[j].position;
+ for (int r = 0; r < row_block_size; ++r) {
+ for (int c = 0; c < col_block_size; ++c, ++jac_pos) {
+ matrix->mutable_rows()[jac_pos] = row_block_pos + r;
+ matrix->mutable_cols()[jac_pos] = col_block_pos + c;
+ matrix->mutable_values()[jac_pos] = values_[jac_pos];
+ }
+ }
+ }
+ }
+ matrix->set_num_nonzeros(num_nonzeros_);
+}
+
+// Return a pointer to the block structure. We continue to hold
+// ownership of the object though.
+const CompressedRowBlockStructure* BlockSparseMatrix::block_structure()
+ const {
+ return block_structure_.get();
+}
+
+void BlockSparseMatrix::ToTextFile(FILE* file) const {
+ CHECK_NOTNULL(file);
+ for (int i = 0; i < block_structure_->rows.size(); ++i) {
+ const int row_block_pos = block_structure_->rows[i].block.position;
+ const int row_block_size = block_structure_->rows[i].block.size;
+ const vector<Cell>& cells = block_structure_->rows[i].cells;
+ for (int j = 0; j < cells.size(); ++j) {
+ const int col_block_id = cells[j].block_id;
+ const int col_block_size = block_structure_->cols[col_block_id].size;
+ const int col_block_pos = block_structure_->cols[col_block_id].position;
+ int jac_pos = cells[j].position;
+ for (int r = 0; r < row_block_size; ++r) {
+ for (int c = 0; c < col_block_size; ++c) {
+ fprintf(file, "% 10d % 10d %17f\n",
+ row_block_pos + r,
+ col_block_pos + c,
+ values_[jac_pos++]);
+ }
+ }
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_sparse_matrix.h b/extern/ceres/internal/ceres/block_sparse_matrix.h
new file mode 100644
index 00000000000..2f9afb738f8
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_sparse_matrix.h
@@ -0,0 +1,100 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Implementation of the SparseMatrix interface for block sparse
+// matrices.
+
+#ifndef CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
+
+#include "ceres/block_structure.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+namespace internal {
+
+class TripletSparseMatrix;
+
+// This class implements the SparseMatrix interface for storing and
+// manipulating block sparse matrices. The block structure is stored
+// in the CompressedRowBlockStructure object and one is needed to
+// initialize the matrix. For details on how the blocks structure of
+// the matrix is stored please see the documentation
+//
+// internal/ceres/block_structure.h
+//
+class BlockSparseMatrix : public SparseMatrix {
+ public:
+ // Construct a block sparse matrix with a fully initialized
+ // CompressedRowBlockStructure objected. The matrix takes over
+ // ownership of this object and destroys it upon destruction.
+ //
+ // TODO(sameeragarwal): Add a function which will validate legal
+ // CompressedRowBlockStructure objects.
+ explicit BlockSparseMatrix(CompressedRowBlockStructure* block_structure);
+
+ BlockSparseMatrix();
+ virtual ~BlockSparseMatrix();
+
+ // Implementation of SparseMatrix interface.
+ virtual void SetZero();
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual void LeftMultiply(const double* x, double* y) const;
+ virtual void SquaredColumnNorm(double* x) const;
+ virtual void ScaleColumns(const double* scale);
+ virtual void ToDenseMatrix(Matrix* dense_matrix) const;
+ virtual void ToTextFile(FILE* file) const;
+
+ virtual int num_rows() const { return num_rows_; }
+ virtual int num_cols() const { return num_cols_; }
+ virtual int num_nonzeros() const { return num_nonzeros_; }
+ virtual const double* values() const { return values_.get(); }
+ virtual double* mutable_values() { return values_.get(); }
+
+ void ToTripletSparseMatrix(TripletSparseMatrix* matrix) const;
+ const CompressedRowBlockStructure* block_structure() const;
+
+ private:
+ int num_rows_;
+ int num_cols_;
+ int max_num_nonzeros_;
+ int num_nonzeros_;
+ scoped_array<double> values_;
+ scoped_ptr<CompressedRowBlockStructure> block_structure_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrix);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/block_structure.cc b/extern/ceres/internal/ceres/block_structure.cc
new file mode 100644
index 00000000000..6479b60f700
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_structure.cc
@@ -0,0 +1,44 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/block_structure.h"
+
+namespace ceres {
+namespace internal {
+
+bool CellLessThan(const Cell& lhs, const Cell& rhs) {
+ if (lhs.block_id == rhs.block_id) {
+ return (lhs.position < rhs.position);
+ }
+ return (lhs.block_id < rhs.block_id);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/block_structure.h b/extern/ceres/internal/ceres/block_structure.h
new file mode 100644
index 00000000000..6e7003addb6
--- /dev/null
+++ b/extern/ceres/internal/ceres/block_structure.h
@@ -0,0 +1,93 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Block structure objects are used to carry information about the
+// dense block structure of sparse matrices. The BlockSparseMatrix
+// object uses the BlockStructure objects to keep track of the matrix
+// structure and operate upon it. This allows us to use more cache
+// friendly block oriented linear algebra operations on the matrix
+// instead of accessing it one scalar entry at a time.
+
+#ifndef CERES_INTERNAL_BLOCK_STRUCTURE_H_
+#define CERES_INTERNAL_BLOCK_STRUCTURE_H_
+
+#include <vector>
+#include "ceres/internal/port.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+typedef int32 BlockSize;
+
+struct Block {
+ Block() : size(-1), position(-1) {}
+ Block(int size_, int position_) : size(size_), position(position_) {}
+
+ BlockSize size;
+ int position; // Position along the row/column.
+};
+
+struct Cell {
+ Cell() : block_id(-1), position(-1) {}
+ Cell(int block_id_, int position_)
+ : block_id(block_id_), position(position_) {}
+
+ // Column or row block id as the case maybe.
+ int block_id;
+ // Where in the values array of the jacobian is this cell located.
+ int position;
+};
+
+// Order cell by their block_id;
+bool CellLessThan(const Cell& lhs, const Cell& rhs);
+
+struct CompressedList {
+ Block block;
+ std::vector<Cell> cells;
+};
+
+typedef CompressedList CompressedRow;
+typedef CompressedList CompressedColumn;
+
+struct CompressedRowBlockStructure {
+ std::vector<Block> cols;
+ std::vector<CompressedRow> rows;
+};
+
+struct CompressedColumnBlockStructure {
+ std::vector<Block> rows;
+ std::vector<CompressedColumn> cols;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_BLOCK_STRUCTURE_H_
diff --git a/extern/ceres/internal/ceres/c_api.cc b/extern/ceres/internal/ceres/c_api.cc
new file mode 100644
index 00000000000..ada8f3e0013
--- /dev/null
+++ b/extern/ceres/internal/ceres/c_api.cc
@@ -0,0 +1,188 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+//
+// An incomplete C API for Ceres.
+//
+// TODO(keir): Figure out why logging does not seem to work.
+
+#include "ceres/c_api.h"
+
+#include <vector>
+#include <iostream>
+#include <string>
+#include "ceres/cost_function.h"
+#include "ceres/loss_function.h"
+#include "ceres/problem.h"
+#include "ceres/solver.h"
+#include "ceres/types.h" // for std
+#include "glog/logging.h"
+
+using ceres::Problem;
+
+void ceres_init() {
+ // This is not ideal, but it's not clear what to do if there is no gflags and
+ // no access to command line arguments.
+ char message[] = "<unknown>";
+ google::InitGoogleLogging(message);
+}
+
+ceres_problem_t* ceres_create_problem() {
+ return reinterpret_cast<ceres_problem_t*>(new Problem);
+}
+
+void ceres_free_problem(ceres_problem_t* problem) {
+ delete reinterpret_cast<Problem*>(problem);
+}
+
+// This cost function wraps a C-level function pointer from the user, to bridge
+// between C and C++.
+class CallbackCostFunction : public ceres::CostFunction {
+ public:
+ CallbackCostFunction(ceres_cost_function_t cost_function,
+ void* user_data,
+ int num_residuals,
+ int num_parameter_blocks,
+ int* parameter_block_sizes)
+ : cost_function_(cost_function),
+ user_data_(user_data) {
+ set_num_residuals(num_residuals);
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ mutable_parameter_block_sizes()->push_back(parameter_block_sizes[i]);
+ }
+ }
+
+ virtual ~CallbackCostFunction() {}
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ return (*cost_function_)(user_data_,
+ const_cast<double**>(parameters),
+ residuals,
+ jacobians);
+ }
+
+ private:
+ ceres_cost_function_t cost_function_;
+ void* user_data_;
+};
+
+// This loss function wraps a C-level function pointer from the user, to bridge
+// between C and C++.
+class CallbackLossFunction : public ceres::LossFunction {
+ public:
+ explicit CallbackLossFunction(ceres_loss_function_t loss_function,
+ void* user_data)
+ : loss_function_(loss_function), user_data_(user_data) {}
+ virtual void Evaluate(double sq_norm, double* rho) const {
+ (*loss_function_)(user_data_, sq_norm, rho);
+ }
+
+ private:
+ ceres_loss_function_t loss_function_;
+ void* user_data_;
+};
+
+// Wrappers for the stock loss functions.
+void* ceres_create_huber_loss_function_data(double a) {
+ return new ceres::HuberLoss(a);
+}
+void* ceres_create_softl1_loss_function_data(double a) {
+ return new ceres::SoftLOneLoss(a);
+}
+void* ceres_create_cauchy_loss_function_data(double a) {
+ return new ceres::CauchyLoss(a);
+}
+void* ceres_create_arctan_loss_function_data(double a) {
+ return new ceres::ArctanLoss(a);
+}
+void* ceres_create_tolerant_loss_function_data(double a, double b) {
+ return new ceres::TolerantLoss(a, b);
+}
+
+void ceres_free_stock_loss_function_data(void* loss_function_data) {
+ delete reinterpret_cast<ceres::LossFunction*>(loss_function_data);
+}
+
+void ceres_stock_loss_function(void* user_data,
+ double squared_norm,
+ double out[3]) {
+ reinterpret_cast<ceres::LossFunction*>(user_data)
+ ->Evaluate(squared_norm, out);
+}
+
+ceres_residual_block_id_t* ceres_problem_add_residual_block(
+ ceres_problem_t* problem,
+ ceres_cost_function_t cost_function,
+ void* cost_function_data,
+ ceres_loss_function_t loss_function,
+ void* loss_function_data,
+ int num_residuals,
+ int num_parameter_blocks,
+ int* parameter_block_sizes,
+ double** parameters) {
+ Problem* ceres_problem = reinterpret_cast<Problem*>(problem);
+
+ ceres::CostFunction* callback_cost_function =
+ new CallbackCostFunction(cost_function,
+ cost_function_data,
+ num_residuals,
+ num_parameter_blocks,
+ parameter_block_sizes);
+
+ ceres::LossFunction* callback_loss_function = NULL;
+ if (loss_function != NULL) {
+ callback_loss_function = new CallbackLossFunction(loss_function,
+ loss_function_data);
+ }
+
+ std::vector<double*> parameter_blocks(parameters,
+ parameters + num_parameter_blocks);
+ return reinterpret_cast<ceres_residual_block_id_t*>(
+ ceres_problem->AddResidualBlock(callback_cost_function,
+ callback_loss_function,
+ parameter_blocks));
+}
+
+void ceres_solve(ceres_problem_t* c_problem) {
+ Problem* problem = reinterpret_cast<Problem*>(c_problem);
+
+ // TODO(keir): Obviously, this way of setting options won't scale or last.
+ // Instead, figure out a way to specify some of the options without
+ // duplicating everything.
+ ceres::Solver::Options options;
+ options.max_num_iterations = 100;
+ options.linear_solver_type = ceres::DENSE_QR;
+ options.minimizer_progress_to_stdout = true;
+
+ ceres::Solver::Summary summary;
+ ceres::Solve(options, problem, &summary);
+ std::cout << summary.FullReport() << "\n";
+}
diff --git a/extern/ceres/internal/ceres/callbacks.cc b/extern/ceres/internal/ceres/callbacks.cc
new file mode 100644
index 00000000000..50a0ec19924
--- /dev/null
+++ b/extern/ceres/internal/ceres/callbacks.cc
@@ -0,0 +1,111 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <iostream> // NO LINT
+#include "ceres/callbacks.h"
+#include "ceres/program.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+
+StateUpdatingCallback::StateUpdatingCallback(Program* program,
+ double* parameters)
+ : program_(program), parameters_(parameters) {}
+
+StateUpdatingCallback::~StateUpdatingCallback() {}
+
+CallbackReturnType StateUpdatingCallback::operator()(
+ const IterationSummary& summary) {
+ if (summary.step_is_successful) {
+ program_->StateVectorToParameterBlocks(parameters_);
+ program_->CopyParameterBlockStateToUserState();
+ }
+ return SOLVER_CONTINUE;
+}
+
+LoggingCallback::LoggingCallback(const MinimizerType minimizer_type,
+ const bool log_to_stdout)
+ : minimizer_type(minimizer_type),
+ log_to_stdout_(log_to_stdout) {}
+
+LoggingCallback::~LoggingCallback() {}
+
+CallbackReturnType LoggingCallback::operator()(
+ const IterationSummary& summary) {
+ string output;
+ if (minimizer_type == LINE_SEARCH) {
+ const char* kReportRowFormat =
+ "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
+ "s:% 3.2e e:% 3d it:% 3.2e tt:% 3.2e";
+ output = StringPrintf(kReportRowFormat,
+ summary.iteration,
+ summary.cost,
+ summary.cost_change,
+ summary.gradient_max_norm,
+ summary.step_norm,
+ summary.step_size,
+ summary.line_search_function_evaluations,
+ summary.iteration_time_in_seconds,
+ summary.cumulative_time_in_seconds);
+ } else if (minimizer_type == TRUST_REGION) {
+ if (summary.iteration == 0) {
+ output = "iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time\n"; // NOLINT
+ }
+ const char* kReportRowFormat =
+ "% 4d % 8e % 3.2e % 3.2e % 3.2e % 3.2e % 3.2e % 4d % 3.2e % 3.2e"; // NOLINT
+ output += StringPrintf(kReportRowFormat,
+ summary.iteration,
+ summary.cost,
+ summary.cost_change,
+ summary.gradient_max_norm,
+ summary.step_norm,
+ summary.relative_decrease,
+ summary.trust_region_radius,
+ summary.linear_solver_iterations,
+ summary.iteration_time_in_seconds,
+ summary.cumulative_time_in_seconds);
+ } else {
+ LOG(FATAL) << "Unknown minimizer type.";
+ }
+
+ if (log_to_stdout_) {
+ std::cout << output << std::endl;
+ } else {
+ VLOG(1) << output;
+ }
+ return SOLVER_CONTINUE;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/callbacks.h b/extern/ceres/internal/ceres/callbacks.h
new file mode 100644
index 00000000000..33c66df5c11
--- /dev/null
+++ b/extern/ceres/internal/ceres/callbacks.h
@@ -0,0 +1,71 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_CALLBACKS_H_
+#define CERES_INTERNAL_CALLBACKS_H_
+
+#include <string>
+#include "ceres/iteration_callback.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+
+// Callback for updating the externally visible state of parameter
+// blocks.
+class StateUpdatingCallback : public IterationCallback {
+ public:
+ StateUpdatingCallback(Program* program, double* parameters);
+ virtual ~StateUpdatingCallback();
+ virtual CallbackReturnType operator()(const IterationSummary& summary);
+ private:
+ Program* program_;
+ double* parameters_;
+};
+
+// Callback for logging the state of the minimizer to STDERR or
+// STDOUT depending on the user's preferences and logging level.
+class LoggingCallback : public IterationCallback {
+ public:
+ LoggingCallback(MinimizerType minimizer_type, bool log_to_stdout);
+ virtual ~LoggingCallback();
+ virtual CallbackReturnType operator()(const IterationSummary& summary);
+
+ private:
+ const MinimizerType minimizer_type;
+ const bool log_to_stdout_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CALLBACKS_H_
diff --git a/extern/ceres/internal/ceres/casts.h b/extern/ceres/internal/ceres/casts.h
new file mode 100644
index 00000000000..f18fdea2d86
--- /dev/null
+++ b/extern/ceres/internal/ceres/casts.h
@@ -0,0 +1,108 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_CASTS_H_
+#define CERES_INTERNAL_CASTS_H_
+
+#include <cassert>
+#include <cstddef> // For NULL.
+
+namespace ceres {
+
+// Identity metafunction.
+template <class T>
+struct identity_ {
+ typedef T type;
+};
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for implicit conversions. For example:
+// - Upcasting in a type hierarchy.
+// - Performing arithmetic conversions (int32 to int64, int to double, etc.).
+// - Adding const or volatile qualifiers.
+//
+// In general, implicit_cast can be used to convert this code
+// To to = from;
+// DoSomething(to);
+// to this
+// DoSomething(implicit_cast<To>(from));
+//
+// base::identity_ is used to make a non-deduced context, which
+// forces all callers to explicitly specify the template argument.
+template<typename To>
+inline To implicit_cast(typename identity_<To>::type to) {
+ return to;
+}
+
+// This version of implicit_cast is used when two template arguments
+// are specified. It's obsolete and should not be used.
+template<typename To, typename From>
+inline To implicit_cast(typename identity_<From>::type const &f) {
+ return f;
+}
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed. When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo? It
+// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
+// when you downcast, you should use this macro. In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not). In normal mode, we do the efficient static_cast<>
+// instead. Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+// This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From> // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) { // so we only accept pointers
+ // Ensures that To is a sub-type of From *. This test is here only
+ // for compile-time type checking, and has no overhead in an
+ // optimized build at run-time, as it will be optimized away
+ // completely.
+
+ // TODO(csilvers): This should use COMPILE_ASSERT.
+ if (false) {
+ implicit_cast<From*, To>(NULL);
+ }
+
+ // uses RTTI in dbg and fastbuild. asserts are disabled in opt builds.
+ assert(f == NULL || dynamic_cast<To>(f) != NULL); // NOLINT
+ return static_cast<To>(f);
+}
+
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CASTS_H_
diff --git a/extern/ceres/internal/ceres/cgnr_linear_operator.h b/extern/ceres/internal/ceres/cgnr_linear_operator.h
new file mode 100644
index 00000000000..44c07cabd01
--- /dev/null
+++ b/extern/ceres/internal/ceres/cgnr_linear_operator.h
@@ -0,0 +1,120 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
+#define CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
+
+#include <algorithm>
+#include "ceres/linear_operator.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+class SparseMatrix;
+
+// A linear operator which takes a matrix A and a diagonal vector D and
+// performs products of the form
+//
+// (A^T A + D^T D)x
+//
+// This is used to implement iterative general sparse linear solving with
+// conjugate gradients, where A is the Jacobian and D is a regularizing
+// parameter. A brief proof that D^T D is the correct regularizer:
+//
+// Given a regularized least squares problem:
+//
+// min ||Ax - b||^2 + ||Dx||^2
+// x
+//
+// First expand into matrix notation:
+//
+// (Ax - b)^T (Ax - b) + xD^TDx
+//
+// Then multiply out to get:
+//
+// = xA^TAx - 2b^T Ax + b^Tb + xD^TDx
+//
+// Take the derivative:
+//
+// 0 = 2A^TAx - 2A^T b + 2 D^TDx
+// 0 = A^TAx - A^T b + D^TDx
+// 0 = (A^TA + D^TD)x - A^T b
+//
+// Thus, the symmetric system we need to solve for CGNR is
+//
+// Sx = z
+//
+// with S = A^TA + D^TD
+// and z = A^T b
+//
+// Note: This class is not thread safe, since it uses some temporary storage.
+class CgnrLinearOperator : public LinearOperator {
+ public:
+ CgnrLinearOperator(const LinearOperator& A, const double *D)
+ : A_(A), D_(D), z_(new double[A.num_rows()]) {
+ }
+ virtual ~CgnrLinearOperator() {}
+
+ virtual void RightMultiply(const double* x, double* y) const {
+ std::fill(z_.get(), z_.get() + A_.num_rows(), 0.0);
+
+ // z = Ax
+ A_.RightMultiply(x, z_.get());
+
+ // y = y + Atz
+ A_.LeftMultiply(z_.get(), y);
+
+ // y = y + DtDx
+ if (D_ != NULL) {
+ int n = A_.num_cols();
+ VectorRef(y, n).array() += ConstVectorRef(D_, n).array().square() *
+ ConstVectorRef(x, n).array();
+ }
+ }
+
+ virtual void LeftMultiply(const double* x, double* y) const {
+ RightMultiply(x, y);
+ }
+
+ virtual int num_rows() const { return A_.num_cols(); }
+ virtual int num_cols() const { return A_.num_cols(); }
+
+ private:
+ const LinearOperator& A_;
+ const double* D_;
+ scoped_array<double> z_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
diff --git a/extern/ceres/internal/ceres/cgnr_solver.cc b/extern/ceres/internal/ceres/cgnr_solver.cc
new file mode 100644
index 00000000000..61fae758d5b
--- /dev/null
+++ b/extern/ceres/internal/ceres/cgnr_solver.cc
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/cgnr_solver.h"
+
+#include "ceres/block_jacobi_preconditioner.h"
+#include "ceres/cgnr_linear_operator.h"
+#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+CgnrSolver::CgnrSolver(const LinearSolver::Options& options)
+ : options_(options),
+ preconditioner_(NULL) {
+ if (options_.preconditioner_type != JACOBI &&
+ options_.preconditioner_type != IDENTITY) {
+ LOG(FATAL) << "CGNR only supports IDENTITY and JACOBI preconditioners.";
+ }
+}
+
+LinearSolver::Summary CgnrSolver::SolveImpl(
+ BlockSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("CgnrSolver::Solve");
+
+ // Form z = Atb.
+ Vector z(A->num_cols());
+ z.setZero();
+ A->LeftMultiply(b, z.data());
+
+ // Precondition if necessary.
+ LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
+ if (options_.preconditioner_type == JACOBI) {
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(new BlockJacobiPreconditioner(*A));
+ }
+ preconditioner_->Update(*A, per_solve_options.D);
+ cg_per_solve_options.preconditioner = preconditioner_.get();
+ }
+
+ // Solve (AtA + DtD)x = z (= Atb).
+ VectorRef(x, A->num_cols()).setZero();
+ CgnrLinearOperator lhs(*A, per_solve_options.D);
+ event_logger.AddEvent("Setup");
+
+ ConjugateGradientsSolver conjugate_gradient_solver(options_);
+ LinearSolver::Summary summary =
+ conjugate_gradient_solver.Solve(&lhs, z.data(), cg_per_solve_options, x);
+ event_logger.AddEvent("Solve");
+ return summary;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/cgnr_solver.h b/extern/ceres/internal/ceres/cgnr_solver.h
new file mode 100644
index 00000000000..f7a15736925
--- /dev/null
+++ b/extern/ceres/internal/ceres/cgnr_solver.h
@@ -0,0 +1,69 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_CGNR_SOLVER_H_
+#define CERES_INTERNAL_CGNR_SOLVER_H_
+
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+class Preconditioner;
+
+class BlockJacobiPreconditioner;
+
+// A conjugate gradients on the normal equations solver. This directly solves
+// for the solution to
+//
+// (A^T A + D^T D)x = A^T b
+//
+// as required for solving for x in the least squares sense. Currently only
+// block diagonal preconditioning is supported.
+class CgnrSolver : public BlockSparseMatrixSolver {
+ public:
+ explicit CgnrSolver(const LinearSolver::Options& options);
+ virtual Summary SolveImpl(
+ BlockSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ private:
+ const LinearSolver::Options options_;
+ scoped_ptr<Preconditioner> preconditioner_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CGNR_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/collections_port.h b/extern/ceres/internal/ceres/collections_port.h
new file mode 100644
index 00000000000..e699a661b8b
--- /dev/null
+++ b/extern/ceres/internal/ceres/collections_port.h
@@ -0,0 +1,196 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Portable HashMap and HashSet, and a specialized overload for hashing pairs.
+
+#ifndef CERES_INTERNAL_COLLECTIONS_PORT_H_
+#define CERES_INTERNAL_COLLECTIONS_PORT_H_
+
+#include "ceres/internal/port.h"
+
+#if defined(CERES_NO_UNORDERED_MAP)
+# include <map>
+# include <set>
+#endif
+
+#if defined(CERES_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+# include <tr1/unordered_set>
+# define CERES_HASH_NAMESPACE_START namespace std { namespace tr1 {
+# define CERES_HASH_NAMESPACE_END } }
+#endif
+
+#if defined(CERES_STD_UNORDERED_MAP)
+# include <unordered_map>
+# include <unordered_set>
+# define CERES_HASH_NAMESPACE_START namespace std {
+# define CERES_HASH_NAMESPACE_END }
+#endif
+
+#if defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+# include <unordered_set>
+# define CERES_HASH_NAMESPACE_START namespace std { namespace tr1 {
+# define CERES_HASH_NAMESPACE_END } }
+#endif
+
+#if !defined(CERES_NO_UNORDERED_MAP) && !defined(CERES_TR1_UNORDERED_MAP) && \
+ !defined(CERES_STD_UNORDERED_MAP) && !defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: CERES_NO_UNORDERED_MAP, CERES_TR1_UNORDERED_MAP,\
+ CERES_STD_UNORDERED_MAP, CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#include <utility>
+#include "ceres/integral_types.h"
+
+// Some systems don't have access to unordered_map/unordered_set. In
+// that case, substitute the hash map/set with normal map/set. The
+// price to pay is slower speed for some operations.
+#if defined(CERES_NO_UNORDERED_MAP)
+
+namespace ceres {
+namespace internal {
+
+template<typename K, typename V>
+struct HashMap : map<K, V> {};
+
+template<typename K>
+struct HashSet : set<K> {};
+
+} // namespace internal
+} // namespace ceres
+
+#else
+
+namespace ceres {
+namespace internal {
+
+#if defined(CERES_TR1_UNORDERED_MAP) || \
+ defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+template<typename K, typename V>
+struct HashMap : std::tr1::unordered_map<K, V> {};
+template<typename K>
+struct HashSet : std::tr1::unordered_set<K> {};
+#endif
+
+#if defined(CERES_STD_UNORDERED_MAP)
+template<typename K, typename V>
+struct HashMap : std::unordered_map<K, V> {};
+template<typename K>
+struct HashSet : std::unordered_set<K> {};
+#endif
+
+#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
+#define GG_LONGLONG(x) x##I64
+#define GG_ULONGLONG(x) x##UI64
+#else
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#endif
+
+// The hash function is due to Bob Jenkins (see
+// http://burtleburtle.net/bob/hash/index.html). Each mix takes 36 instructions,
+// in 18 cycles if you're lucky. On x86 architectures, this requires 45
+// instructions in 27 cycles, if you're lucky.
+//
+// 32bit version
+inline void hash_mix(uint32& a, uint32& b, uint32& c) {
+ a -= b; a -= c; a ^= (c>>13);
+ b -= c; b -= a; b ^= (a<<8);
+ c -= a; c -= b; c ^= (b>>13);
+ a -= b; a -= c; a ^= (c>>12);
+ b -= c; b -= a; b ^= (a<<16);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>3);
+ b -= c; b -= a; b ^= (a<<10);
+ c -= a; c -= b; c ^= (b>>15);
+}
+
+// 64bit version
+inline void hash_mix(uint64& a, uint64& b, uint64& c) {
+ a -= b; a -= c; a ^= (c>>43);
+ b -= c; b -= a; b ^= (a<<9);
+ c -= a; c -= b; c ^= (b>>8);
+ a -= b; a -= c; a ^= (c>>38);
+ b -= c; b -= a; b ^= (a<<23);
+ c -= a; c -= b; c ^= (b>>5);
+ a -= b; a -= c; a ^= (c>>35);
+ b -= c; b -= a; b ^= (a<<49);
+ c -= a; c -= b; c ^= (b>>11);
+}
+
+inline uint32 Hash32NumWithSeed(uint32 num, uint32 c) {
+ // The golden ratio; an arbitrary value.
+ uint32 b = 0x9e3779b9UL;
+ hash_mix(num, b, c);
+ return c;
+}
+
+inline uint64 Hash64NumWithSeed(uint64 num, uint64 c) {
+ // More of the golden ratio.
+ uint64 b = GG_ULONGLONG(0xe08c1d668b756f82);
+ hash_mix(num, b, c);
+ return c;
+}
+
+} // namespace internal
+} // namespace ceres
+
+// Since on some platforms this is a doubly-nested namespace (std::tr1) and
+// others it is not, the entire namespace line must be in a macro.
+CERES_HASH_NAMESPACE_START
+
+// The outrageously annoying specializations below are for portability reasons.
+// In short, it's not possible to have two overloads of hash<pair<T1, T2>
+
+// Hasher for STL pairs. Requires hashers for both members to be defined.
+template<typename T>
+struct hash<pair<T, T> > {
+ size_t operator()(const pair<T, T>& p) const {
+ size_t h1 = hash<T>()(p.first);
+ size_t h2 = hash<T>()(p.second);
+ // The decision below is at compile time
+ return (sizeof(h1) <= sizeof(ceres::internal::uint32)) ?
+ ceres::internal::Hash32NumWithSeed(h1, h2) :
+ ceres::internal::Hash64NumWithSeed(h1, h2);
+ }
+ // Less than operator for MSVC.
+ bool operator()(const pair<T, T>& a,
+ const pair<T, T>& b) const {
+ return a < b;
+ }
+ static const size_t bucket_size = 4; // These are required by MSVC
+ static const size_t min_buckets = 8; // 4 and 8 are defaults.
+};
+
+CERES_HASH_NAMESPACE_END
+
+#endif // CERES_NO_UNORDERED_MAP
+#endif // CERES_INTERNAL_COLLECTIONS_PORT_H_
diff --git a/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc b/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
new file mode 100644
index 00000000000..ebb2a62c544
--- /dev/null
+++ b/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
@@ -0,0 +1,122 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/compressed_col_sparse_matrix_utils.h"
+
+#include <vector>
+#include <algorithm>
+#include "ceres/internal/port.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+void CompressedColumnScalarMatrixToBlockMatrix(
+ const int* scalar_rows,
+ const int* scalar_cols,
+ const vector<int>& row_blocks,
+ const vector<int>& col_blocks,
+ vector<int>* block_rows,
+ vector<int>* block_cols) {
+ CHECK_NOTNULL(block_rows)->clear();
+ CHECK_NOTNULL(block_cols)->clear();
+ const int num_row_blocks = row_blocks.size();
+ const int num_col_blocks = col_blocks.size();
+
+ vector<int> row_block_starts(num_row_blocks);
+ for (int i = 0, cursor = 0; i < num_row_blocks; ++i) {
+ row_block_starts[i] = cursor;
+ cursor += row_blocks[i];
+ }
+
+ // This loop extracts the block sparsity of the scalar sparse matrix
+ // It does so by iterating over the columns, but only considering
+ // the columns corresponding to the first element of each column
+ // block. Within each column, the inner loop iterates over the rows,
+ // and detects the presence of a row block by checking for the
+ // presence of a non-zero entry corresponding to its first element.
+ block_cols->push_back(0);
+ int c = 0;
+ for (int col_block = 0; col_block < num_col_blocks; ++col_block) {
+ int column_size = 0;
+ for (int idx = scalar_cols[c]; idx < scalar_cols[c + 1]; ++idx) {
+ vector<int>::const_iterator it =
+ std::lower_bound(row_block_starts.begin(),
+ row_block_starts.end(),
+ scalar_rows[idx]);
+ // Since we are using lower_bound, it will return the row id
+ // where the row block starts. For everything but the first row
+ // of the block, where these values will be the same, we can
+ // skip, as we only need the first row to detect the presence of
+ // the block.
+ //
+ // For rows all but the first row in the last row block,
+ // lower_bound will return row_block_starts.end(), but those can
+ // be skipped like the rows in other row blocks too.
+ if (it == row_block_starts.end() || *it != scalar_rows[idx]) {
+ continue;
+ }
+
+ block_rows->push_back(it - row_block_starts.begin());
+ ++column_size;
+ }
+ block_cols->push_back(block_cols->back() + column_size);
+ c += col_blocks[col_block];
+ }
+}
+
+void BlockOrderingToScalarOrdering(const vector<int>& blocks,
+ const vector<int>& block_ordering,
+ vector<int>* scalar_ordering) {
+ CHECK_EQ(blocks.size(), block_ordering.size());
+ const int num_blocks = blocks.size();
+
+ // block_starts = [0, block1, block1 + block2 ..]
+ vector<int> block_starts(num_blocks);
+ for (int i = 0, cursor = 0; i < num_blocks ; ++i) {
+ block_starts[i] = cursor;
+ cursor += blocks[i];
+ }
+
+ scalar_ordering->resize(block_starts.back() + blocks.back());
+ int cursor = 0;
+ for (int i = 0; i < num_blocks; ++i) {
+ const int block_id = block_ordering[i];
+ const int block_size = blocks[block_id];
+ int block_position = block_starts[block_id];
+ for (int j = 0; j < block_size; ++j) {
+ (*scalar_ordering)[cursor++] = block_position++;
+ }
+ }
+}
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h b/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
new file mode 100644
index 00000000000..da2109fba3e
--- /dev/null
+++ b/extern/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
@@ -0,0 +1,144 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
+#define CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
+
+#include <vector>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+// Extract the block sparsity pattern of the scalar compressed columns
+// matrix and return it in compressed column form. The compressed
+// column form is stored in two vectors block_rows, and block_cols,
+// which correspond to the row and column arrays in a compressed
+// column sparse matrix.
+//
+// If c_ij is the block in the matrix A corresponding to row block i
+// and column block j, then it is expected that A contains at least
+// one non-zero entry corresponding to the top left entry of c_ij,
+// as that entry is used to detect the presence of a non-zero c_ij.
+void CompressedColumnScalarMatrixToBlockMatrix(
+ const int* scalar_rows,
+ const int* scalar_cols,
+ const std::vector<int>& row_blocks,
+ const std::vector<int>& col_blocks,
+ std::vector<int>* block_rows,
+ std::vector<int>* block_cols);
+
+// Given a set of blocks and a permutation of these blocks, compute
+// the corresponding "scalar" ordering, where the scalar ordering of
+// size sum(blocks).
+void BlockOrderingToScalarOrdering(
+ const std::vector<int>& blocks,
+ const std::vector<int>& block_ordering,
+ std::vector<int>* scalar_ordering);
+
+// Solve the linear system
+//
+// R * solution = rhs
+//
+// Where R is an upper triangular compressed column sparse matrix.
+template <typename IntegerType>
+void SolveUpperTriangularInPlace(IntegerType num_cols,
+ const IntegerType* rows,
+ const IntegerType* cols,
+ const double* values,
+ double* rhs_and_solution) {
+ for (IntegerType c = num_cols - 1; c >= 0; --c) {
+ rhs_and_solution[c] /= values[cols[c + 1] - 1];
+ for (IntegerType idx = cols[c]; idx < cols[c + 1] - 1; ++idx) {
+ const IntegerType r = rows[idx];
+ const double v = values[idx];
+ rhs_and_solution[r] -= v * rhs_and_solution[c];
+ }
+ }
+}
+
+// Solve the linear system
+//
+// R' * solution = rhs
+//
+// Where R is an upper triangular compressed column sparse matrix.
+template <typename IntegerType>
+void SolveUpperTriangularTransposeInPlace(IntegerType num_cols,
+ const IntegerType* rows,
+ const IntegerType* cols,
+ const double* values,
+ double* rhs_and_solution) {
+ for (IntegerType c = 0; c < num_cols; ++c) {
+ for (IntegerType idx = cols[c]; idx < cols[c + 1] - 1; ++idx) {
+ const IntegerType r = rows[idx];
+ const double v = values[idx];
+ rhs_and_solution[c] -= v * rhs_and_solution[r];
+ }
+ rhs_and_solution[c] = rhs_and_solution[c] / values[cols[c + 1] - 1];
+ }
+}
+
+// Given a upper triangular matrix R in compressed column form, solve
+// the linear system,
+//
+// R'R x = b
+//
+// Where b is all zeros except for rhs_nonzero_index, where it is
+// equal to one.
+//
+// The function exploits this knowledge to reduce the number of
+// floating point operations.
+template <typename IntegerType>
+void SolveRTRWithSparseRHS(IntegerType num_cols,
+ const IntegerType* rows,
+ const IntegerType* cols,
+ const double* values,
+ const int rhs_nonzero_index,
+ double* solution) {
+ std::fill(solution, solution + num_cols, 0.0);
+ solution[rhs_nonzero_index] = 1.0 / values[cols[rhs_nonzero_index + 1] - 1];
+
+ for (IntegerType c = rhs_nonzero_index + 1; c < num_cols; ++c) {
+ for (IntegerType idx = cols[c]; idx < cols[c + 1] - 1; ++idx) {
+ const IntegerType r = rows[idx];
+ if (r < rhs_nonzero_index) continue;
+ const double v = values[idx];
+ solution[c] -= v * solution[r];
+ }
+ solution[c] = solution[c] / values[cols[c + 1] - 1];
+ }
+
+ SolveUpperTriangularInPlace(num_cols, rows, cols, values, solution);
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
diff --git a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc
new file mode 100644
index 00000000000..64b6ac00447
--- /dev/null
+++ b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc
@@ -0,0 +1,233 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/compressed_row_jacobian_writer.h"
+
+#include <utility>
+#include <vector>
+
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/scratch_evaluate_preparer.h"
+
+namespace ceres {
+namespace internal {
+
+using std::make_pair;
+using std::pair;
+using std::vector;
+
+void CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors(
+ const Program* program, CompressedRowSparseMatrix* jacobian) {
+ const vector<ParameterBlock*>& parameter_blocks =
+ program->parameter_blocks();
+ vector<int>& col_blocks = *(jacobian->mutable_col_blocks());
+ col_blocks.resize(parameter_blocks.size());
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ col_blocks[i] = parameter_blocks[i]->LocalSize();
+ }
+
+ const vector<ResidualBlock*>& residual_blocks =
+ program->residual_blocks();
+ vector<int>& row_blocks = *(jacobian->mutable_row_blocks());
+ row_blocks.resize(residual_blocks.size());
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ row_blocks[i] = residual_blocks[i]->NumResiduals();
+ }
+}
+
+void CompressedRowJacobianWriter::GetOrderedParameterBlocks(
+ const Program* program,
+ int residual_id,
+ vector<pair<int, int> >* evaluated_jacobian_blocks) {
+ const ResidualBlock* residual_block =
+ program->residual_blocks()[residual_id];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ const ParameterBlock* parameter_block =
+ residual_block->parameter_blocks()[j];
+ if (!parameter_block->IsConstant()) {
+ evaluated_jacobian_blocks->push_back(
+ make_pair(parameter_block->index(), j));
+ }
+ }
+ sort(evaluated_jacobian_blocks->begin(), evaluated_jacobian_blocks->end());
+}
+
+SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
+ const vector<ResidualBlock*>& residual_blocks =
+ program_->residual_blocks();
+
+ int total_num_residuals = program_->NumResiduals();
+ int total_num_effective_parameters = program_->NumEffectiveParameters();
+
+ // Count the number of jacobian nonzeros.
+ int num_jacobian_nonzeros = 0;
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks[i];
+ const int num_residuals = residual_block->NumResiduals();
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ if (!parameter_block->IsConstant()) {
+ num_jacobian_nonzeros += num_residuals * parameter_block->LocalSize();
+ }
+ }
+ }
+
+ // Allocate storage for the jacobian with some extra space at the end.
+ // Allocate more space than needed to store the jacobian so that when the LM
+ // algorithm adds the diagonal, no reallocation is necessary. This reduces
+ // peak memory usage significantly.
+ CompressedRowSparseMatrix* jacobian =
+ new CompressedRowSparseMatrix(
+ total_num_residuals,
+ total_num_effective_parameters,
+ num_jacobian_nonzeros + total_num_effective_parameters);
+
+ // At this stage, the CompressedRowSparseMatrix is an invalid state. But this
+ // seems to be the only way to construct it without doing a memory copy.
+ int* rows = jacobian->mutable_rows();
+ int* cols = jacobian->mutable_cols();
+ int row_pos = 0;
+ rows[0] = 0;
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ const ResidualBlock* residual_block = residual_blocks[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+
+ // Count the number of derivatives for a row of this residual block and
+ // build a list of active parameter block indices.
+ int num_derivatives = 0;
+ vector<int> parameter_indices;
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ if (!parameter_block->IsConstant()) {
+ parameter_indices.push_back(parameter_block->index());
+ num_derivatives += parameter_block->LocalSize();
+ }
+ }
+
+ // Sort the parameters by their position in the state vector.
+ sort(parameter_indices.begin(), parameter_indices.end());
+ CHECK(unique(parameter_indices.begin(), parameter_indices.end()) ==
+ parameter_indices.end())
+ << "Ceres internal error: "
+ << "Duplicate parameter blocks detected in a cost function. "
+ << "This should never happen. Please report this to "
+ << "the Ceres developers.";
+
+ // Update the row indices.
+ const int num_residuals = residual_block->NumResiduals();
+ for (int j = 0; j < num_residuals; ++j) {
+ rows[row_pos + j + 1] = rows[row_pos + j] + num_derivatives;
+ }
+
+ // Iterate over parameter blocks in the order which they occur in the
+ // parameter vector. This code mirrors that in Write(), where jacobian
+ // values are updated.
+ int col_pos = 0;
+ for (int j = 0; j < parameter_indices.size(); ++j) {
+ ParameterBlock* parameter_block =
+ program_->parameter_blocks()[parameter_indices[j]];
+ const int parameter_block_size = parameter_block->LocalSize();
+
+ for (int r = 0; r < num_residuals; ++r) {
+ // This is the position in the values array of the jacobian where this
+ // row of the jacobian block should go.
+ const int column_block_begin = rows[row_pos + r] + col_pos;
+
+ for (int c = 0; c < parameter_block_size; ++c) {
+ cols[column_block_begin + c] = parameter_block->delta_offset() + c;
+ }
+ }
+ col_pos += parameter_block_size;
+ }
+ row_pos += num_residuals;
+ }
+ CHECK_EQ(num_jacobian_nonzeros, rows[total_num_residuals]);
+
+ PopulateJacobianRowAndColumnBlockVectors(program_, jacobian);
+
+ return jacobian;
+}
+
+void CompressedRowJacobianWriter::Write(int residual_id,
+ int residual_offset,
+ double **jacobians,
+ SparseMatrix* base_jacobian) {
+ CompressedRowSparseMatrix* jacobian =
+ down_cast<CompressedRowSparseMatrix*>(base_jacobian);
+
+ double* jacobian_values = jacobian->mutable_values();
+ const int* jacobian_rows = jacobian->rows();
+
+ const ResidualBlock* residual_block =
+ program_->residual_blocks()[residual_id];
+ const int num_residuals = residual_block->NumResiduals();
+
+ vector<pair<int, int> > evaluated_jacobian_blocks;
+ GetOrderedParameterBlocks(program_, residual_id, &evaluated_jacobian_blocks);
+
+ // Where in the current row does the jacobian for a parameter block begin.
+ int col_pos = 0;
+
+ // Iterate over the jacobian blocks in increasing order of their
+ // positions in the reduced parameter vector.
+ for (int i = 0; i < evaluated_jacobian_blocks.size(); ++i) {
+ const ParameterBlock* parameter_block =
+ program_->parameter_blocks()[evaluated_jacobian_blocks[i].first];
+ const int argument = evaluated_jacobian_blocks[i].second;
+ const int parameter_block_size = parameter_block->LocalSize();
+
+ // Copy one row of the jacobian block at a time.
+ for (int r = 0; r < num_residuals; ++r) {
+ // Position of the r^th row of the current jacobian block.
+ const double* block_row_begin =
+ jacobians[argument] + r * parameter_block_size;
+
+ // Position in the values array of the jacobian where this
+ // row of the jacobian block should go.
+ double* column_block_begin =
+ jacobian_values + jacobian_rows[residual_offset + r] + col_pos;
+
+ std::copy(block_row_begin,
+ block_row_begin + parameter_block_size,
+ column_block_begin);
+ }
+ col_pos += parameter_block_size;
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h
new file mode 100644
index 00000000000..1cd01235ccf
--- /dev/null
+++ b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.h
@@ -0,0 +1,112 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A jacobian writer that directly writes to compressed row sparse matrices.
+
+#ifndef CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
+#define CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
+
+#include <utility>
+#include <vector>
+
+#include "ceres/evaluator.h"
+#include "ceres/scratch_evaluate_preparer.h"
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+class Program;
+class SparseMatrix;
+
+class CompressedRowJacobianWriter {
+ public:
+ CompressedRowJacobianWriter(Evaluator::Options /* ignored */,
+ Program* program)
+ : program_(program) {
+ }
+
+ // PopulateJacobianRowAndColumnBlockVectors sets col_blocks and
+ // row_blocks for a CompressedRowSparseMatrix, based on the
+ // parameter block sizes and residual sizes respectively from the
+ // program. This is useful when Solver::Options::use_block_amd =
+ // true;
+ //
+ // This function is static so that it is available to other jacobian
+ // writers which use CompressedRowSparseMatrix (or derived types).
+ // (Jacobian writers do not fall under any type hierarchy; they only
+ // have to provide an interface as specified in program_evaluator.h).
+ static void PopulateJacobianRowAndColumnBlockVectors(
+ const Program* program,
+ CompressedRowSparseMatrix* jacobian);
+
+ // It is necessary to determine the order of the jacobian blocks
+ // before copying them into a CompressedRowSparseMatrix (or derived
+ // type). Just because a cost function uses parameter blocks 1
+ // after 2 in its arguments does not mean that the block 1 occurs
+ // before block 2 in the column layout of the jacobian. Thus,
+ // GetOrderedParameterBlocks determines the order by sorting the
+ // jacobian blocks by their position in the state vector.
+ //
+ // This function is static so that it is available to other jacobian
+ // writers which use CompressedRowSparseMatrix (or derived types).
+ // (Jacobian writers do not fall under any type hierarchy; they only
+ // have to provide an interface as specified in
+ // program_evaluator.h).
+ static void GetOrderedParameterBlocks(
+ const Program* program,
+ int residual_id,
+ std::vector<std::pair<int, int> >* evaluated_jacobian_blocks);
+
+ // JacobianWriter interface.
+
+ // Since the compressed row matrix has different layout than that
+ // assumed by the cost functions, use scratch space to store the
+ // jacobians temporarily then copy them over to the larger jacobian
+ // in the Write() function.
+ ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads) {
+ return ScratchEvaluatePreparer::Create(*program_, num_threads);
+ }
+
+ SparseMatrix* CreateJacobian() const;
+
+ void Write(int residual_id,
+ int residual_offset,
+ double **jacobians,
+ SparseMatrix* base_jacobian);
+
+ private:
+ Program* program_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
diff --git a/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc
new file mode 100644
index 00000000000..91d18bbd604
--- /dev/null
+++ b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.cc
@@ -0,0 +1,562 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/compressed_row_sparse_matrix.h"
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+#include "ceres/crs_matrix.h"
+#include "ceres/internal/port.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+namespace {
+
+// Helper functor used by the constructor for reordering the contents
+// of a TripletSparseMatrix. This comparator assumes thay there are no
+// duplicates in the pair of arrays rows and cols, i.e., there is no
+// indices i and j (not equal to each other) s.t.
+//
+// rows[i] == rows[j] && cols[i] == cols[j]
+//
+// If this is the case, this functor will not be a StrictWeakOrdering.
+struct RowColLessThan {
+ RowColLessThan(const int* rows, const int* cols)
+ : rows(rows), cols(cols) {
+ }
+
+ bool operator()(const int x, const int y) const {
+ if (rows[x] == rows[y]) {
+ return (cols[x] < cols[y]);
+ }
+ return (rows[x] < rows[y]);
+ }
+
+ const int* rows;
+ const int* cols;
+};
+
+} // namespace
+
+// This constructor gives you a semi-initialized CompressedRowSparseMatrix.
+CompressedRowSparseMatrix::CompressedRowSparseMatrix(int num_rows,
+ int num_cols,
+ int max_num_nonzeros) {
+ num_rows_ = num_rows;
+ num_cols_ = num_cols;
+ rows_.resize(num_rows + 1, 0);
+ cols_.resize(max_num_nonzeros, 0);
+ values_.resize(max_num_nonzeros, 0.0);
+
+
+ VLOG(1) << "# of rows: " << num_rows_
+ << " # of columns: " << num_cols_
+ << " max_num_nonzeros: " << cols_.size()
+ << ". Allocating " << (num_rows_ + 1) * sizeof(int) + // NOLINT
+ cols_.size() * sizeof(int) + // NOLINT
+ cols_.size() * sizeof(double); // NOLINT
+}
+
+CompressedRowSparseMatrix::CompressedRowSparseMatrix(
+ const TripletSparseMatrix& m) {
+ num_rows_ = m.num_rows();
+ num_cols_ = m.num_cols();
+
+ rows_.resize(num_rows_ + 1, 0);
+ cols_.resize(m.num_nonzeros(), 0);
+ values_.resize(m.max_num_nonzeros(), 0.0);
+
+ // index is the list of indices into the TripletSparseMatrix m.
+ vector<int> index(m.num_nonzeros(), 0);
+ for (int i = 0; i < m.num_nonzeros(); ++i) {
+ index[i] = i;
+ }
+
+ // Sort index such that the entries of m are ordered by row and ties
+ // are broken by column.
+ sort(index.begin(), index.end(), RowColLessThan(m.rows(), m.cols()));
+
+ VLOG(1) << "# of rows: " << num_rows_
+ << " # of columns: " << num_cols_
+ << " max_num_nonzeros: " << cols_.size()
+ << ". Allocating "
+ << ((num_rows_ + 1) * sizeof(int) + // NOLINT
+ cols_.size() * sizeof(int) + // NOLINT
+ cols_.size() * sizeof(double)); // NOLINT
+
+ // Copy the contents of the cols and values array in the order given
+ // by index and count the number of entries in each row.
+ for (int i = 0; i < m.num_nonzeros(); ++i) {
+ const int idx = index[i];
+ ++rows_[m.rows()[idx] + 1];
+ cols_[i] = m.cols()[idx];
+ values_[i] = m.values()[idx];
+ }
+
+ // Find the cumulative sum of the row counts.
+ for (int i = 1; i < num_rows_ + 1; ++i) {
+ rows_[i] += rows_[i - 1];
+ }
+
+ CHECK_EQ(num_nonzeros(), m.num_nonzeros());
+}
+
+CompressedRowSparseMatrix::CompressedRowSparseMatrix(const double* diagonal,
+ int num_rows) {
+ CHECK_NOTNULL(diagonal);
+
+ num_rows_ = num_rows;
+ num_cols_ = num_rows;
+ rows_.resize(num_rows + 1);
+ cols_.resize(num_rows);
+ values_.resize(num_rows);
+
+ rows_[0] = 0;
+ for (int i = 0; i < num_rows_; ++i) {
+ cols_[i] = i;
+ values_[i] = diagonal[i];
+ rows_[i + 1] = i + 1;
+ }
+
+ CHECK_EQ(num_nonzeros(), num_rows);
+}
+
+CompressedRowSparseMatrix::~CompressedRowSparseMatrix() {
+}
+
+void CompressedRowSparseMatrix::SetZero() {
+ std::fill(values_.begin(), values_.end(), 0);
+}
+
+void CompressedRowSparseMatrix::RightMultiply(const double* x,
+ double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ y[r] += values_[idx] * x[cols_[idx]];
+ }
+ }
+}
+
+void CompressedRowSparseMatrix::LeftMultiply(const double* x, double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ y[cols_[idx]] += values_[idx] * x[r];
+ }
+ }
+}
+
+void CompressedRowSparseMatrix::SquaredColumnNorm(double* x) const {
+ CHECK_NOTNULL(x);
+
+ std::fill(x, x + num_cols_, 0.0);
+ for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
+ x[cols_[idx]] += values_[idx] * values_[idx];
+ }
+}
+
+void CompressedRowSparseMatrix::ScaleColumns(const double* scale) {
+ CHECK_NOTNULL(scale);
+
+ for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
+ values_[idx] *= scale[cols_[idx]];
+ }
+}
+
+void CompressedRowSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
+ CHECK_NOTNULL(dense_matrix);
+ dense_matrix->resize(num_rows_, num_cols_);
+ dense_matrix->setZero();
+
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ (*dense_matrix)(r, cols_[idx]) = values_[idx];
+ }
+ }
+}
+
+void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
+ CHECK_GE(delta_rows, 0);
+ CHECK_LE(delta_rows, num_rows_);
+
+ num_rows_ -= delta_rows;
+ rows_.resize(num_rows_ + 1);
+
+ // Walk the list of row blocks until we reach the new number of rows
+ // and the drop the rest of the row blocks.
+ int num_row_blocks = 0;
+ int num_rows = 0;
+ while (num_row_blocks < row_blocks_.size() && num_rows < num_rows_) {
+ num_rows += row_blocks_[num_row_blocks];
+ ++num_row_blocks;
+ }
+
+ row_blocks_.resize(num_row_blocks);
+}
+
+void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
+ CHECK_EQ(m.num_cols(), num_cols_);
+
+ CHECK(row_blocks_.size() == 0 || m.row_blocks().size() !=0)
+ << "Cannot append a matrix with row blocks to one without and vice versa."
+ << "This matrix has : " << row_blocks_.size() << " row blocks."
+ << "The matrix being appended has: " << m.row_blocks().size()
+ << " row blocks.";
+
+ if (m.num_rows() == 0) {
+ return;
+ }
+
+ if (cols_.size() < num_nonzeros() + m.num_nonzeros()) {
+ cols_.resize(num_nonzeros() + m.num_nonzeros());
+ values_.resize(num_nonzeros() + m.num_nonzeros());
+ }
+
+ // Copy the contents of m into this matrix.
+ DCHECK_LT(num_nonzeros(), cols_.size());
+ if (m.num_nonzeros() > 0) {
+ std::copy(m.cols(), m.cols() + m.num_nonzeros(), &cols_[num_nonzeros()]);
+ std::copy(m.values(),
+ m.values() + m.num_nonzeros(),
+ &values_[num_nonzeros()]);
+ }
+
+ rows_.resize(num_rows_ + m.num_rows() + 1);
+ // new_rows = [rows_, m.row() + rows_[num_rows_]]
+ std::fill(rows_.begin() + num_rows_,
+ rows_.begin() + num_rows_ + m.num_rows() + 1,
+ rows_[num_rows_]);
+
+ for (int r = 0; r < m.num_rows() + 1; ++r) {
+ rows_[num_rows_ + r] += m.rows()[r];
+ }
+
+ num_rows_ += m.num_rows();
+ row_blocks_.insert(row_blocks_.end(),
+ m.row_blocks().begin(),
+ m.row_blocks().end());
+}
+
+void CompressedRowSparseMatrix::ToTextFile(FILE* file) const {
+ CHECK_NOTNULL(file);
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ fprintf(file,
+ "% 10d % 10d %17f\n",
+ r,
+ cols_[idx],
+ values_[idx]);
+ }
+ }
+}
+
+void CompressedRowSparseMatrix::ToCRSMatrix(CRSMatrix* matrix) const {
+ matrix->num_rows = num_rows_;
+ matrix->num_cols = num_cols_;
+ matrix->rows = rows_;
+ matrix->cols = cols_;
+ matrix->values = values_;
+
+ // Trim.
+ matrix->rows.resize(matrix->num_rows + 1);
+ matrix->cols.resize(matrix->rows[matrix->num_rows]);
+ matrix->values.resize(matrix->rows[matrix->num_rows]);
+}
+
+void CompressedRowSparseMatrix::SetMaxNumNonZeros(int num_nonzeros) {
+ CHECK_GE(num_nonzeros, 0);
+
+ cols_.resize(num_nonzeros);
+ values_.resize(num_nonzeros);
+}
+
+void CompressedRowSparseMatrix::SolveLowerTriangularInPlace(
+ double* solution) const {
+ for (int r = 0; r < num_rows_; ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1] - 1; ++idx) {
+ solution[r] -= values_[idx] * solution[cols_[idx]];
+ }
+ solution[r] /= values_[rows_[r + 1] - 1];
+ }
+}
+
+void CompressedRowSparseMatrix::SolveLowerTriangularTransposeInPlace(
+ double* solution) const {
+ for (int r = num_rows_ - 1; r >= 0; --r) {
+ solution[r] /= values_[rows_[r + 1] - 1];
+ for (int idx = rows_[r + 1] - 2; idx >= rows_[r]; --idx) {
+ solution[cols_[idx]] -= values_[idx] * solution[r];
+ }
+ }
+}
+
+CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+ const double* diagonal,
+ const vector<int>& blocks) {
+ int num_rows = 0;
+ int num_nonzeros = 0;
+ for (int i = 0; i < blocks.size(); ++i) {
+ num_rows += blocks[i];
+ num_nonzeros += blocks[i] * blocks[i];
+ }
+
+ CompressedRowSparseMatrix* matrix =
+ new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros);
+
+ int* rows = matrix->mutable_rows();
+ int* cols = matrix->mutable_cols();
+ double* values = matrix->mutable_values();
+ std::fill(values, values + num_nonzeros, 0.0);
+
+ int idx_cursor = 0;
+ int col_cursor = 0;
+ for (int i = 0; i < blocks.size(); ++i) {
+ const int block_size = blocks[i];
+ for (int r = 0; r < block_size; ++r) {
+ *(rows++) = idx_cursor;
+ values[idx_cursor + r] = diagonal[col_cursor + r];
+ for (int c = 0; c < block_size; ++c, ++idx_cursor) {
+ *(cols++) = col_cursor + c;
+ }
+ }
+ col_cursor += block_size;
+ }
+ *rows = idx_cursor;
+
+ *matrix->mutable_row_blocks() = blocks;
+ *matrix->mutable_col_blocks() = blocks;
+
+ CHECK_EQ(idx_cursor, num_nonzeros);
+ CHECK_EQ(col_cursor, num_rows);
+ return matrix;
+}
+
+CompressedRowSparseMatrix* CompressedRowSparseMatrix::Transpose() const {
+ CompressedRowSparseMatrix* transpose =
+ new CompressedRowSparseMatrix(num_cols_, num_rows_, num_nonzeros());
+
+ int* transpose_rows = transpose->mutable_rows();
+ int* transpose_cols = transpose->mutable_cols();
+ double* transpose_values = transpose->mutable_values();
+
+ for (int idx = 0; idx < num_nonzeros(); ++idx) {
+ ++transpose_rows[cols_[idx] + 1];
+ }
+
+ for (int i = 1; i < transpose->num_rows() + 1; ++i) {
+ transpose_rows[i] += transpose_rows[i - 1];
+ }
+
+ for (int r = 0; r < num_rows(); ++r) {
+ for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
+ const int c = cols_[idx];
+ const int transpose_idx = transpose_rows[c]++;
+ transpose_cols[transpose_idx] = r;
+ transpose_values[transpose_idx] = values_[idx];
+ }
+ }
+
+ for (int i = transpose->num_rows() - 1; i > 0 ; --i) {
+ transpose_rows[i] = transpose_rows[i - 1];
+ }
+ transpose_rows[0] = 0;
+
+ *(transpose->mutable_row_blocks()) = col_blocks_;
+ *(transpose->mutable_col_blocks()) = row_blocks_;
+
+ return transpose;
+}
+
+namespace {
+// A ProductTerm is a term in the outer product of a matrix with
+// itself.
+struct ProductTerm {
+ ProductTerm(const int row, const int col, const int index)
+ : row(row), col(col), index(index) {
+ }
+
+ bool operator<(const ProductTerm& right) const {
+ if (row == right.row) {
+ if (col == right.col) {
+ return index < right.index;
+ }
+ return col < right.col;
+ }
+ return row < right.row;
+ }
+
+ int row;
+ int col;
+ int index;
+};
+
+CompressedRowSparseMatrix*
+CompressAndFillProgram(const int num_rows,
+ const int num_cols,
+ const vector<ProductTerm>& product,
+ vector<int>* program) {
+ CHECK_GT(product.size(), 0);
+
+ // Count the number of unique product term, which in turn is the
+ // number of non-zeros in the outer product.
+ int num_nonzeros = 1;
+ for (int i = 1; i < product.size(); ++i) {
+ if (product[i].row != product[i - 1].row ||
+ product[i].col != product[i - 1].col) {
+ ++num_nonzeros;
+ }
+ }
+
+ CompressedRowSparseMatrix* matrix =
+ new CompressedRowSparseMatrix(num_rows, num_cols, num_nonzeros);
+
+ int* crsm_rows = matrix->mutable_rows();
+ std::fill(crsm_rows, crsm_rows + num_rows + 1, 0);
+ int* crsm_cols = matrix->mutable_cols();
+ std::fill(crsm_cols, crsm_cols + num_nonzeros, 0);
+
+ CHECK_NOTNULL(program)->clear();
+ program->resize(product.size());
+
+ // Iterate over the sorted product terms. This means each row is
+ // filled one at a time, and we are able to assign a position in the
+ // values array to each term.
+ //
+ // If terms repeat, i.e., they contribute to the same entry in the
+ // result matrix), then they do not affect the sparsity structure of
+ // the result matrix.
+ int nnz = 0;
+ crsm_cols[0] = product[0].col;
+ crsm_rows[product[0].row + 1]++;
+ (*program)[product[0].index] = nnz;
+ for (int i = 1; i < product.size(); ++i) {
+ const ProductTerm& previous = product[i - 1];
+ const ProductTerm& current = product[i];
+
+ // Sparsity structure is updated only if the term is not a repeat.
+ if (previous.row != current.row || previous.col != current.col) {
+ crsm_cols[++nnz] = current.col;
+ crsm_rows[current.row + 1]++;
+ }
+
+ // All terms get assigned the position in the values array where
+ // their value is accumulated.
+ (*program)[current.index] = nnz;
+ }
+
+ for (int i = 1; i < num_rows + 1; ++i) {
+ crsm_rows[i] += crsm_rows[i - 1];
+ }
+
+ return matrix;
+}
+
+} // namespace
+
+CompressedRowSparseMatrix*
+CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
+ const CompressedRowSparseMatrix& m,
+ vector<int>* program) {
+ CHECK_NOTNULL(program)->clear();
+ CHECK_GT(m.num_nonzeros(), 0)
+ << "Congratulations, "
+ << "you found a bug in Ceres. Please report it.";
+
+ vector<ProductTerm> product;
+ const vector<int>& row_blocks = m.row_blocks();
+ int row_block_begin = 0;
+ // Iterate over row blocks
+ for (int row_block = 0; row_block < row_blocks.size(); ++row_block) {
+ const int row_block_end = row_block_begin + row_blocks[row_block];
+ // Compute the outer product terms for just one row per row block.
+ const int r = row_block_begin;
+ // Compute the lower triangular part of the product.
+ for (int idx1 = m.rows()[r]; idx1 < m.rows()[r + 1]; ++idx1) {
+ for (int idx2 = m.rows()[r]; idx2 <= idx1; ++idx2) {
+ product.push_back(ProductTerm(m.cols()[idx1],
+ m.cols()[idx2],
+ product.size()));
+ }
+ }
+ row_block_begin = row_block_end;
+ }
+ CHECK_EQ(row_block_begin, m.num_rows());
+ sort(product.begin(), product.end());
+ return CompressAndFillProgram(m.num_cols(), m.num_cols(), product, program);
+}
+
+void CompressedRowSparseMatrix::ComputeOuterProduct(
+ const CompressedRowSparseMatrix& m,
+ const vector<int>& program,
+ CompressedRowSparseMatrix* result) {
+ result->SetZero();
+ double* values = result->mutable_values();
+ const vector<int>& row_blocks = m.row_blocks();
+
+ int cursor = 0;
+ int row_block_begin = 0;
+ const double* m_values = m.values();
+ const int* m_rows = m.rows();
+ // Iterate over row blocks.
+ for (int row_block = 0; row_block < row_blocks.size(); ++row_block) {
+ const int row_block_end = row_block_begin + row_blocks[row_block];
+ const int saved_cursor = cursor;
+ for (int r = row_block_begin; r < row_block_end; ++r) {
+ // Reuse the program segment for each row in this row block.
+ cursor = saved_cursor;
+ const int row_begin = m_rows[r];
+ const int row_end = m_rows[r + 1];
+ for (int idx1 = row_begin; idx1 < row_end; ++idx1) {
+ const double v1 = m_values[idx1];
+ for (int idx2 = row_begin; idx2 <= idx1; ++idx2, ++cursor) {
+ values[program[cursor]] += v1 * m_values[idx2];
+ }
+ }
+ }
+ row_block_begin = row_block_end;
+ }
+
+ CHECK_EQ(row_block_begin, m.num_rows());
+ CHECK_EQ(cursor, program.size());
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h
new file mode 100644
index 00000000000..987339d09a1
--- /dev/null
+++ b/extern/ceres/internal/ceres/compressed_row_sparse_matrix.h
@@ -0,0 +1,181 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
+
+#include <vector>
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+struct CRSMatrix;
+
+namespace internal {
+
+class TripletSparseMatrix;
+
+class CompressedRowSparseMatrix : public SparseMatrix {
+ public:
+ // Build a matrix with the same content as the TripletSparseMatrix
+ // m. TripletSparseMatrix objects are easier to construct
+ // incrementally, so we use them to initialize SparseMatrix
+ // objects.
+ //
+ // We assume that m does not have any repeated entries.
+ explicit CompressedRowSparseMatrix(const TripletSparseMatrix& m);
+
+ // Use this constructor only if you know what you are doing. This
+ // creates a "blank" matrix with the appropriate amount of memory
+ // allocated. However, the object itself is in an inconsistent state
+ // as the rows and cols matrices do not match the values of
+ // num_rows, num_cols and max_num_nonzeros.
+ //
+ // The use case for this constructor is that when the user knows the
+ // size of the matrix to begin with and wants to update the layout
+ // manually, instead of going via the indirect route of first
+ // constructing a TripletSparseMatrix, which leads to more than
+ // double the peak memory usage.
+ CompressedRowSparseMatrix(int num_rows,
+ int num_cols,
+ int max_num_nonzeros);
+
+ // Build a square sparse diagonal matrix with num_rows rows and
+ // columns. The diagonal m(i,i) = diagonal(i);
+ CompressedRowSparseMatrix(const double* diagonal, int num_rows);
+
+ virtual ~CompressedRowSparseMatrix();
+
+ // SparseMatrix interface.
+ virtual void SetZero();
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual void LeftMultiply(const double* x, double* y) const;
+ virtual void SquaredColumnNorm(double* x) const;
+ virtual void ScaleColumns(const double* scale);
+
+ virtual void ToDenseMatrix(Matrix* dense_matrix) const;
+ virtual void ToTextFile(FILE* file) const;
+ virtual int num_rows() const { return num_rows_; }
+ virtual int num_cols() const { return num_cols_; }
+ virtual int num_nonzeros() const { return rows_[num_rows_]; }
+ virtual const double* values() const { return &values_[0]; }
+ virtual double* mutable_values() { return &values_[0]; }
+
+ // Delete the bottom delta_rows.
+ // num_rows -= delta_rows
+ void DeleteRows(int delta_rows);
+
+ // Append the contents of m to the bottom of this matrix. m must
+ // have the same number of columns as this matrix.
+ void AppendRows(const CompressedRowSparseMatrix& m);
+
+ void ToCRSMatrix(CRSMatrix* matrix) const;
+
+ // Low level access methods that expose the structure of the matrix.
+ const int* cols() const { return &cols_[0]; }
+ int* mutable_cols() { return &cols_[0]; }
+
+ const int* rows() const { return &rows_[0]; }
+ int* mutable_rows() { return &rows_[0]; }
+
+ const std::vector<int>& row_blocks() const { return row_blocks_; }
+ std::vector<int>* mutable_row_blocks() { return &row_blocks_; }
+
+ const std::vector<int>& col_blocks() const { return col_blocks_; }
+ std::vector<int>* mutable_col_blocks() { return &col_blocks_; }
+
+ // Destructive array resizing method.
+ void SetMaxNumNonZeros(int num_nonzeros);
+
+ // Non-destructive array resizing method.
+ void set_num_rows(const int num_rows) { num_rows_ = num_rows; }
+ void set_num_cols(const int num_cols) { num_cols_ = num_cols; }
+
+ void SolveLowerTriangularInPlace(double* solution) const;
+ void SolveLowerTriangularTransposeInPlace(double* solution) const;
+
+ CompressedRowSparseMatrix* Transpose() const;
+
+ static CompressedRowSparseMatrix* CreateBlockDiagonalMatrix(
+ const double* diagonal,
+ const std::vector<int>& blocks);
+
+ // Compute the sparsity structure of the product m.transpose() * m
+ // and create a CompressedRowSparseMatrix corresponding to it.
+ //
+ // Also compute a "program" vector, which for every term in the
+ // outer product points to the entry in the values array of the
+ // result matrix where it should be accumulated.
+ //
+ // This program is used by the ComputeOuterProduct function below to
+ // compute the outer product.
+ //
+ // Since the entries of the program are the same for rows with the
+ // same sparsity structure, the program only stores the result for
+ // one row per row block. The ComputeOuterProduct function reuses
+ // this information for each row in the row block.
+ static CompressedRowSparseMatrix* CreateOuterProductMatrixAndProgram(
+ const CompressedRowSparseMatrix& m,
+ std::vector<int>* program);
+
+ // Compute the values array for the expression m.transpose() * m,
+ // where the matrix used to store the result and a program have been
+ // created using the CreateOuterProductMatrixAndProgram function
+ // above.
+ static void ComputeOuterProduct(const CompressedRowSparseMatrix& m,
+ const std::vector<int>& program,
+ CompressedRowSparseMatrix* result);
+
+ private:
+ int num_rows_;
+ int num_cols_;
+ std::vector<int> rows_;
+ std::vector<int> cols_;
+ std::vector<double> values_;
+
+ // If the matrix has an underlying block structure, then it can also
+ // carry with it row and column block sizes. This is auxilliary and
+ // optional information for use by algorithms operating on the
+ // matrix. The class itself does not make use of this information in
+ // any way.
+ std::vector<int> row_blocks_;
+ std::vector<int> col_blocks_;
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(CompressedRowSparseMatrix);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/conditioned_cost_function.cc b/extern/ceres/internal/ceres/conditioned_cost_function.cc
new file mode 100644
index 00000000000..08899e3d246
--- /dev/null
+++ b/extern/ceres/internal/ceres/conditioned_cost_function.cc
@@ -0,0 +1,130 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wjr@google.com (William Rucklidge)
+//
+// This file contains the implementation of the conditioned cost function.
+
+#include "ceres/conditioned_cost_function.h"
+
+#include <cstddef>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/stl_util.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// This cost function has the same dimensions (parameters, residuals) as
+// the one it's wrapping.
+ConditionedCostFunction::ConditionedCostFunction(
+ CostFunction* wrapped_cost_function,
+ const std::vector<CostFunction*>& conditioners,
+ Ownership ownership)
+ : wrapped_cost_function_(wrapped_cost_function),
+ conditioners_(conditioners),
+ ownership_(ownership) {
+ // Set up our dimensions.
+ set_num_residuals(wrapped_cost_function_->num_residuals());
+ *mutable_parameter_block_sizes() =
+ wrapped_cost_function_->parameter_block_sizes();
+
+ // Sanity-check the conditioners' dimensions.
+ CHECK_EQ(wrapped_cost_function_->num_residuals(), conditioners_.size());
+ for (int i = 0; i < wrapped_cost_function_->num_residuals(); i++) {
+ if (conditioners[i]) {
+ CHECK_EQ(1, conditioners[i]->num_residuals());
+ CHECK_EQ(1, conditioners[i]->parameter_block_sizes().size());
+ CHECK_EQ(1, conditioners[i]->parameter_block_sizes()[0]);
+ }
+ }
+}
+
+ConditionedCostFunction::~ConditionedCostFunction() {
+ if (ownership_ == TAKE_OWNERSHIP) {
+ STLDeleteElements(&conditioners_);
+ } else {
+ wrapped_cost_function_.release();
+ }
+}
+
+bool ConditionedCostFunction::Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ bool success = wrapped_cost_function_->Evaluate(parameters, residuals,
+ jacobians);
+ if (!success) {
+ return false;
+ }
+
+ for (int r = 0; r < wrapped_cost_function_->num_residuals(); r++) {
+ // On output, we want to have
+ // residuals[r] = conditioners[r](wrapped_residuals[r])
+ // For parameter block i, column c,
+ // jacobians[i][r*parameter_block_size_[i] + c] =
+ // = d residual[r] / d parameters[i][c]
+ // = conditioners[r]'(wrapped_residuals[r]) *
+ // d wrapped_residuals[r] / d parameters[i][c]
+ if (conditioners_[r]) {
+ double conditioner_derivative;
+ double* conditioner_derivative_pointer = &conditioner_derivative;
+ double** conditioner_derivative_pointer2 =
+ &conditioner_derivative_pointer;
+ if (!jacobians) {
+ conditioner_derivative_pointer2 = NULL;
+ }
+
+ double unconditioned_residual = residuals[r];
+ double* parameter_pointer = &unconditioned_residual;
+ success = conditioners_[r]->Evaluate(&parameter_pointer,
+ &residuals[r],
+ conditioner_derivative_pointer2);
+ if (!success) {
+ return false;
+ }
+
+ if (jacobians) {
+ for (int i = 0;
+ i < wrapped_cost_function_->parameter_block_sizes().size();
+ i++) {
+ if (jacobians[i]) {
+ int parameter_block_size =
+ wrapped_cost_function_->parameter_block_sizes()[i];
+ VectorRef jacobian_row(jacobians[i] + r * parameter_block_size,
+ parameter_block_size, 1);
+ jacobian_row *= conditioner_derivative;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/conjugate_gradients_solver.cc b/extern/ceres/internal/ceres/conjugate_gradients_solver.cc
new file mode 100644
index 00000000000..3702276a2fb
--- /dev/null
+++ b/extern/ceres/internal/ceres/conjugate_gradients_solver.cc
@@ -0,0 +1,248 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// A preconditioned conjugate gradients solver
+// (ConjugateGradientsSolver) for positive semidefinite linear
+// systems.
+//
+// We have also augmented the termination criterion used by this
+// solver to support not just residual based termination but also
+// termination based on decrease in the value of the quadratic model
+// that CG optimizes.
+
+#include "ceres/conjugate_gradients_solver.h"
+
+#include <cmath>
+#include <cstddef>
+#include "ceres/fpclassify.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_operator.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+
+bool IsZeroOrInfinity(double x) {
+ return ((x == 0.0) || (IsInfinite(x)));
+}
+
+} // namespace
+
+ConjugateGradientsSolver::ConjugateGradientsSolver(
+ const LinearSolver::Options& options)
+ : options_(options) {
+}
+
+LinearSolver::Summary ConjugateGradientsSolver::Solve(
+ LinearOperator* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ CHECK_NOTNULL(A);
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(b);
+ CHECK_EQ(A->num_rows(), A->num_cols());
+
+ LinearSolver::Summary summary;
+ summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
+ summary.message = "Maximum number of iterations reached.";
+ summary.num_iterations = 0;
+
+ const int num_cols = A->num_cols();
+ VectorRef xref(x, num_cols);
+ ConstVectorRef bref(b, num_cols);
+
+ const double norm_b = bref.norm();
+ if (norm_b == 0.0) {
+ xref.setZero();
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Convergence. |b| = 0.";
+ return summary;
+ }
+
+ Vector r(num_cols);
+ Vector p(num_cols);
+ Vector z(num_cols);
+ Vector tmp(num_cols);
+
+ const double tol_r = per_solve_options.r_tolerance * norm_b;
+
+ tmp.setZero();
+ A->RightMultiply(x, tmp.data());
+ r = bref - tmp;
+ double norm_r = r.norm();
+ if (options_.min_num_iterations == 0 && norm_r <= tol_r) {
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message =
+ StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
+ return summary;
+ }
+
+ double rho = 1.0;
+
+ // Initial value of the quadratic model Q = x'Ax - 2 * b'x.
+ double Q0 = -1.0 * xref.dot(bref + r);
+
+ for (summary.num_iterations = 1;; ++summary.num_iterations) {
+ // Apply preconditioner
+ if (per_solve_options.preconditioner != NULL) {
+ z.setZero();
+ per_solve_options.preconditioner->RightMultiply(r.data(), z.data());
+ } else {
+ z = r;
+ }
+
+ double last_rho = rho;
+ rho = r.dot(z);
+ if (IsZeroOrInfinity(rho)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = StringPrintf("Numerical failure. rho = r'z = %e.", rho);
+ break;
+ }
+
+ if (summary.num_iterations == 1) {
+ p = z;
+ } else {
+ double beta = rho / last_rho;
+ if (IsZeroOrInfinity(beta)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = StringPrintf(
+ "Numerical failure. beta = rho_n / rho_{n-1} = %e, "
+ "rho_n = %e, rho_{n-1} = %e", beta, rho, last_rho);
+ break;
+ }
+ p = z + beta * p;
+ }
+
+ Vector& q = z;
+ q.setZero();
+ A->RightMultiply(p.data(), q.data());
+ const double pq = p.dot(q);
+ if ((pq <= 0) || IsInfinite(pq)) {
+ summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
+ summary.message = StringPrintf(
+ "Matrix is indefinite, no more progress can be made. "
+ "p'q = %e. |p| = %e, |q| = %e",
+ pq, p.norm(), q.norm());
+ break;
+ }
+
+ const double alpha = rho / pq;
+ if (IsInfinite(alpha)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message =
+ StringPrintf("Numerical failure. alpha = rho / pq = %e, "
+ "rho = %e, pq = %e.", alpha, rho, pq);
+ break;
+ }
+
+ xref = xref + alpha * p;
+
+ // Ideally we would just use the update r = r - alpha*q to keep
+ // track of the residual vector. However this estimate tends to
+ // drift over time due to round off errors. Thus every
+ // residual_reset_period iterations, we calculate the residual as
+ // r = b - Ax. We do not do this every iteration because this
+ // requires an additional matrix vector multiply which would
+ // double the complexity of the CG algorithm.
+ if (summary.num_iterations % options_.residual_reset_period == 0) {
+ tmp.setZero();
+ A->RightMultiply(x, tmp.data());
+ r = bref - tmp;
+ } else {
+ r = r - alpha * q;
+ }
+
+ // Quadratic model based termination.
+ // Q1 = x'Ax - 2 * b' x.
+ const double Q1 = -1.0 * xref.dot(bref + r);
+
+ // For PSD matrices A, let
+ //
+ // Q(x) = x'Ax - 2b'x
+ //
+ // be the cost of the quadratic function defined by A and b. Then,
+ // the solver terminates at iteration i if
+ //
+ // i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
+ //
+ // This termination criterion is more useful when using CG to
+ // solve the Newton step. This particular convergence test comes
+ // from Stephen Nash's work on truncated Newton
+ // methods. References:
+ //
+ // 1. Stephen G. Nash & Ariela Sofer, Assessing A Search
+ // Direction Within A Truncated Newton Method, Operation
+ // Research Letters 9(1990) 219-221.
+ //
+ // 2. Stephen G. Nash, A Survey of Truncated Newton Methods,
+ // Journal of Computational and Applied Mathematics,
+ // 124(1-2), 45-59, 2000.
+ //
+ const double zeta = summary.num_iterations * (Q1 - Q0) / Q1;
+ if (zeta < per_solve_options.q_tolerance &&
+ summary.num_iterations >= options_.min_num_iterations) {
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message =
+ StringPrintf("Iteration: %d Convergence: zeta = %e < %e. |r| = %e",
+ summary.num_iterations,
+ zeta,
+ per_solve_options.q_tolerance,
+ r.norm());
+ break;
+ }
+ Q0 = Q1;
+
+ // Residual based termination.
+ norm_r = r. norm();
+ if (norm_r <= tol_r &&
+ summary.num_iterations >= options_.min_num_iterations) {
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message =
+ StringPrintf("Iteration: %d Convergence. |r| = %e <= %e.",
+ summary.num_iterations,
+ norm_r,
+ tol_r);
+ break;
+ }
+
+ if (summary.num_iterations >= options_.max_num_iterations) {
+ break;
+ }
+ }
+
+ return summary;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/conjugate_gradients_solver.h b/extern/ceres/internal/ceres/conjugate_gradients_solver.h
new file mode 100644
index 00000000000..a1e18334414
--- /dev/null
+++ b/extern/ceres/internal/ceres/conjugate_gradients_solver.h
@@ -0,0 +1,74 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Preconditioned Conjugate Gradients based solver for positive
+// semidefinite linear systems.
+
+#ifndef CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
+#define CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
+
+#include "ceres/linear_solver.h"
+#include "ceres/internal/macros.h"
+
+namespace ceres {
+namespace internal {
+
+class LinearOperator;
+
+// This class implements the now classical Conjugate Gradients
+// algorithm of Hestenes & Stiefel for solving postive semidefinite
+// linear sytems. Optionally it can use a preconditioner also to
+// reduce the condition number of the linear system and improve the
+// convergence rate. Modern references for Conjugate Gradients are the
+// books by Yousef Saad and Trefethen & Bau. This implementation of CG
+// has been augmented with additional termination tests that are
+// needed for forcing early termination when used as part of an
+// inexact Newton solver.
+//
+// For more details see the documentation for
+// LinearSolver::PerSolveOptions::r_tolerance and
+// LinearSolver::PerSolveOptions::q_tolerance in linear_solver.h.
+class ConjugateGradientsSolver : public LinearSolver {
+ public:
+ explicit ConjugateGradientsSolver(const LinearSolver::Options& options);
+ virtual Summary Solve(LinearOperator* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ private:
+ const LinearSolver::Options options_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(ConjugateGradientsSolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc b/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc
new file mode 100644
index 00000000000..c6b42cf1516
--- /dev/null
+++ b/extern/ceres/internal/ceres/coordinate_descent_minimizer.cc
@@ -0,0 +1,278 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/coordinate_descent_minimizer.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#endif
+
+#include <iterator>
+#include <numeric>
+#include <vector>
+#include "ceres/evaluator.h"
+#include "ceres/linear_solver.h"
+#include "ceres/minimizer.h"
+#include "ceres/parameter_block.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/solver.h"
+#include "ceres/trust_region_minimizer.h"
+#include "ceres/trust_region_strategy.h"
+
+namespace ceres {
+namespace internal {
+
+using std::map;
+using std::max;
+using std::min;
+using std::set;
+using std::string;
+using std::vector;
+
+CoordinateDescentMinimizer::~CoordinateDescentMinimizer() {
+}
+
+bool CoordinateDescentMinimizer::Init(
+ const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering& ordering,
+ string* error) {
+ parameter_blocks_.clear();
+ independent_set_offsets_.clear();
+ independent_set_offsets_.push_back(0);
+
+ // Serialize the OrderedGroups into a vector of parameter block
+ // offsets for parallel access.
+ map<ParameterBlock*, int> parameter_block_index;
+ map<int, set<double*> > group_to_elements = ordering.group_to_elements();
+ for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+ it != group_to_elements.end();
+ ++it) {
+ for (set<double*>::const_iterator ptr_it = it->second.begin();
+ ptr_it != it->second.end();
+ ++ptr_it) {
+ parameter_blocks_.push_back(parameter_map.find(*ptr_it)->second);
+ parameter_block_index[parameter_blocks_.back()] =
+ parameter_blocks_.size() - 1;
+ }
+ independent_set_offsets_.push_back(
+ independent_set_offsets_.back() + it->second.size());
+ }
+
+ // The ordering does not have to contain all parameter blocks, so
+ // assign zero offsets/empty independent sets to these parameter
+ // blocks.
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ if (!ordering.IsMember(parameter_blocks[i]->mutable_user_state())) {
+ parameter_blocks_.push_back(parameter_blocks[i]);
+ independent_set_offsets_.push_back(independent_set_offsets_.back());
+ }
+ }
+
+ // Compute the set of residual blocks that depend on each parameter
+ // block.
+ residual_blocks_.resize(parameter_block_index.size());
+ const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ const map<ParameterBlock*, int>::const_iterator it =
+ parameter_block_index.find(parameter_block);
+ if (it != parameter_block_index.end()) {
+ residual_blocks_[it->second].push_back(residual_block);
+ }
+ }
+ }
+
+ evaluator_options_.linear_solver_type = DENSE_QR;
+ evaluator_options_.num_eliminate_blocks = 0;
+ evaluator_options_.num_threads = 1;
+
+ return true;
+}
+
+void CoordinateDescentMinimizer::Minimize(
+ const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) {
+ // Set the state and mark all parameter blocks constant.
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks_[i];
+ parameter_block->SetState(parameters + parameter_block->state_offset());
+ parameter_block->SetConstant();
+ }
+
+ scoped_array<LinearSolver*> linear_solvers(
+ new LinearSolver*[options.num_threads]);
+
+ LinearSolver::Options linear_solver_options;
+ linear_solver_options.type = DENSE_QR;
+
+ for (int i = 0; i < options.num_threads; ++i) {
+ linear_solvers[i] = LinearSolver::Create(linear_solver_options);
+ }
+
+ for (int i = 0; i < independent_set_offsets_.size() - 1; ++i) {
+ const int num_problems =
+ independent_set_offsets_[i + 1] - independent_set_offsets_[i];
+ // No point paying the price for an OpemMP call if the set is of
+ // size zero.
+ if (num_problems == 0) {
+ continue;
+ }
+
+#ifdef CERES_USE_OPENMP
+ const int num_inner_iteration_threads =
+ min(options.num_threads, num_problems);
+ evaluator_options_.num_threads =
+ max(1, options.num_threads / num_inner_iteration_threads);
+
+ // The parameter blocks in each independent set can be optimized
+ // in parallel, since they do not co-occur in any residual block.
+#pragma omp parallel for num_threads(num_inner_iteration_threads)
+#endif
+ for (int j = independent_set_offsets_[i];
+ j < independent_set_offsets_[i + 1];
+ ++j) {
+#ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+#else
+ int thread_id = 0;
+#endif
+
+ ParameterBlock* parameter_block = parameter_blocks_[j];
+ const int old_index = parameter_block->index();
+ const int old_delta_offset = parameter_block->delta_offset();
+ parameter_block->SetVarying();
+ parameter_block->set_index(0);
+ parameter_block->set_delta_offset(0);
+
+ Program inner_program;
+ inner_program.mutable_parameter_blocks()->push_back(parameter_block);
+ *inner_program.mutable_residual_blocks() = residual_blocks_[j];
+
+ // TODO(sameeragarwal): Better error handling. Right now we
+ // assume that this is not going to lead to problems of any
+ // sort. Basically we should be checking for numerical failure
+ // of some sort.
+ //
+ // On the other hand, if the optimization is a failure, that in
+ // some ways is fine, since it won't change the parameters and
+ // we are fine.
+ Solver::Summary inner_summary;
+ Solve(&inner_program,
+ linear_solvers[thread_id],
+ parameters + parameter_block->state_offset(),
+ &inner_summary);
+
+ parameter_block->set_index(old_index);
+ parameter_block->set_delta_offset(old_delta_offset);
+ parameter_block->SetState(parameters + parameter_block->state_offset());
+ parameter_block->SetConstant();
+ }
+ }
+
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ parameter_blocks_[i]->SetVarying();
+ }
+
+ for (int i = 0; i < options.num_threads; ++i) {
+ delete linear_solvers[i];
+ }
+}
+
+// Solve the optimization problem for one parameter block.
+void CoordinateDescentMinimizer::Solve(Program* program,
+ LinearSolver* linear_solver,
+ double* parameter,
+ Solver::Summary* summary) {
+ *summary = Solver::Summary();
+ summary->initial_cost = 0.0;
+ summary->fixed_cost = 0.0;
+ summary->final_cost = 0.0;
+ string error;
+
+ Minimizer::Options minimizer_options;
+ minimizer_options.evaluator.reset(
+ CHECK_NOTNULL(Evaluator::Create(evaluator_options_, program, &error)));
+ minimizer_options.jacobian.reset(
+ CHECK_NOTNULL(minimizer_options.evaluator->CreateJacobian()));
+
+ TrustRegionStrategy::Options trs_options;
+ trs_options.linear_solver = linear_solver;
+ minimizer_options.trust_region_strategy.reset(
+ CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options)));
+ minimizer_options.is_silent = true;
+
+ TrustRegionMinimizer minimizer;
+ minimizer.Minimize(minimizer_options, parameter, summary);
+}
+
+bool CoordinateDescentMinimizer::IsOrderingValid(
+ const Program& program,
+ const ParameterBlockOrdering& ordering,
+ string* message) {
+ const map<int, set<double*> >& group_to_elements =
+ ordering.group_to_elements();
+
+ // Verify that each group is an independent set
+ map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+ for (; it != group_to_elements.end(); ++it) {
+ if (!program.IsParameterBlockSetIndependent(it->second)) {
+ *message =
+ StringPrintf("The user-provided "
+ "parameter_blocks_for_inner_iterations does not "
+ "form an independent set. Group Id: %d", it->first);
+ return false;
+ }
+ }
+ return true;
+}
+
+// Find a recursive decomposition of the Hessian matrix as a set
+// of independent sets of decreasing size and invert it. This
+// seems to work better in practice, i.e., Cameras before
+// points.
+ParameterBlockOrdering* CoordinateDescentMinimizer::CreateOrdering(
+ const Program& program) {
+ scoped_ptr<ParameterBlockOrdering> ordering(new ParameterBlockOrdering);
+ ComputeRecursiveIndependentSetOrdering(program, ordering.get());
+ ordering->Reverse();
+ return ordering.release();
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/coordinate_descent_minimizer.h b/extern/ceres/internal/ceres/coordinate_descent_minimizer.h
new file mode 100644
index 00000000000..25ea04ce622
--- /dev/null
+++ b/extern/ceres/internal/ceres/coordinate_descent_minimizer.h
@@ -0,0 +1,102 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
+#define CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
+
+#include <string>
+#include <vector>
+
+#include "ceres/evaluator.h"
+#include "ceres/minimizer.h"
+#include "ceres/problem_impl.h"
+#include "ceres/solver.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+class LinearSolver;
+
+// Given a Program, and a ParameterBlockOrdering which partitions
+// (non-exhaustively) the Hessian matrix into independent sets,
+// perform coordinate descent on the parameter blocks in the
+// ordering. The independent set structure allows for all parameter
+// blocks in the same independent set to be optimized in parallel, and
+// the order of the independent set determines the order in which the
+// parameter block groups are optimized.
+//
+// The minimizer assumes that none of the parameter blocks in the
+// program are constant.
+class CoordinateDescentMinimizer : public Minimizer {
+ public:
+ bool Init(const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering& ordering,
+ std::string* error);
+
+ // Minimizer interface.
+ virtual ~CoordinateDescentMinimizer();
+ virtual void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary);
+
+ // Verify that each group in the ordering forms an independent set.
+ static bool IsOrderingValid(const Program& program,
+ const ParameterBlockOrdering& ordering,
+ std::string* message);
+
+ // Find a recursive decomposition of the Hessian matrix as a set
+ // of independent sets of decreasing size and invert it. This
+ // seems to work better in practice, i.e., Cameras before
+ // points.
+ static ParameterBlockOrdering* CreateOrdering(const Program& program);
+
+ private:
+ void Solve(Program* program,
+ LinearSolver* linear_solver,
+ double* parameters,
+ Solver::Summary* summary);
+
+ std::vector<ParameterBlock*> parameter_blocks_;
+ std::vector<std::vector<ResidualBlock*> > residual_blocks_;
+ // The optimization is performed in rounds. In each round all the
+ // parameter blocks that form one independent set are optimized in
+ // parallel. This array, marks the boundaries of the independent
+ // sets in parameter_blocks_.
+ std::vector<int> independent_set_offsets_;
+
+ Evaluator::Options evaluator_options_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
diff --git a/extern/ceres/internal/ceres/corrector.cc b/extern/ceres/internal/ceres/corrector.cc
new file mode 100644
index 00000000000..720182868c1
--- /dev/null
+++ b/extern/ceres/internal/ceres/corrector.cc
@@ -0,0 +1,158 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/corrector.h"
+
+#include <cstddef>
+#include <cmath>
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Corrector::Corrector(const double sq_norm, const double rho[3]) {
+ CHECK_GE(sq_norm, 0.0);
+ sqrt_rho1_ = sqrt(rho[1]);
+
+ // If sq_norm = 0.0, the correction becomes trivial, the residual
+ // and the jacobian are scaled by the squareroot of the derivative
+ // of rho. Handling this case explicitly avoids the divide by zero
+ // error that would occur below.
+ //
+ // The case where rho'' < 0 also gets special handling. Technically
+ // it shouldn't, and the computation of the scaling should proceed
+ // as below, however we found in experiments that applying the
+ // curvature correction when rho'' < 0, which is the case when we
+ // are in the outlier region slows down the convergence of the
+ // algorithm significantly.
+ //
+ // Thus, we have divided the action of the robustifier into two
+ // parts. In the inliner region, we do the full second order
+ // correction which re-wights the gradient of the function by the
+ // square root of the derivative of rho, and the Gauss-Newton
+ // Hessian gets both the scaling and the rank-1 curvature
+ // correction. Normaly, alpha is upper bounded by one, but with this
+ // change, alpha is bounded above by zero.
+ //
+ // Empirically we have observed that the full Triggs correction and
+ // the clamped correction both start out as very good approximations
+ // to the loss function when we are in the convex part of the
+ // function, but as the function starts transitioning from convex to
+ // concave, the Triggs approximation diverges more and more and
+ // ultimately becomes linear. The clamped Triggs model however
+ // remains quadratic.
+ //
+ // The reason why the Triggs approximation becomes so poor is
+ // because the curvature correction that it applies to the gauss
+ // newton hessian goes from being a full rank correction to a rank
+ // deficient correction making the inversion of the Hessian fraught
+ // with all sorts of misery and suffering.
+ //
+ // The clamped correction retains its quadratic nature and inverting it
+ // is always well formed.
+ if ((sq_norm == 0.0) || (rho[2] <= 0.0)) {
+ residual_scaling_ = sqrt_rho1_;
+ alpha_sq_norm_ = 0.0;
+ return;
+ }
+
+ // We now require that the first derivative of the loss function be
+ // positive only if the second derivative is positive. This is
+ // because when the second derivative is non-positive, we do not use
+ // the second order correction suggested by BANS and instead use a
+ // simpler first order strategy which does not use a division by the
+ // gradient of the loss function.
+ CHECK_GT(rho[1], 0.0);
+
+ // Calculate the smaller of the two solutions to the equation
+ //
+ // 0.5 * alpha^2 - alpha - rho'' / rho' * z'z = 0.
+ //
+ // Start by calculating the discriminant D.
+ const double D = 1.0 + 2.0 * sq_norm * rho[2] / rho[1];
+
+ // Since both rho[1] and rho[2] are guaranteed to be positive at
+ // this point, we know that D > 1.0.
+
+ const double alpha = 1.0 - sqrt(D);
+
+ // Calculate the constants needed by the correction routines.
+ residual_scaling_ = sqrt_rho1_ / (1 - alpha);
+ alpha_sq_norm_ = alpha / sq_norm;
+}
+
+void Corrector::CorrectResiduals(const int num_rows, double* residuals) {
+ DCHECK(residuals != NULL);
+ // Equation 11 in BANS.
+ VectorRef(residuals, num_rows) *= residual_scaling_;
+}
+
+void Corrector::CorrectJacobian(const int num_rows,
+ const int num_cols,
+ double* residuals,
+ double* jacobian) {
+ DCHECK(residuals != NULL);
+ DCHECK(jacobian != NULL);
+
+ // The common case (rho[2] <= 0).
+ if (alpha_sq_norm_ == 0.0) {
+ VectorRef(jacobian, num_rows * num_cols) *= sqrt_rho1_;
+ return;
+ }
+
+ // Equation 11 in BANS.
+ //
+ // J = sqrt(rho) * (J - alpha^2 r * r' J)
+ //
+ // In days gone by this loop used to be a single Eigen expression of
+ // the form
+ //
+ // J = sqrt_rho1_ * (J - alpha_sq_norm_ * r* (r.transpose() * J));
+ //
+ // Which turns out to about 17x slower on bal problems. The reason
+ // is that Eigen is unable to figure out that this expression can be
+ // evaluated columnwise and ends up creating a temporary.
+ for (int c = 0; c < num_cols; ++c) {
+ double r_transpose_j = 0.0;
+ for (int r = 0; r < num_rows; ++r) {
+ r_transpose_j += jacobian[r * num_cols + c] * residuals[r];
+ }
+
+ for (int r = 0; r < num_rows; ++r) {
+ jacobian[r * num_cols + c] = sqrt_rho1_ *
+ (jacobian[r * num_cols + c] -
+ alpha_sq_norm_ * residuals[r] * r_transpose_j);
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/corrector.h b/extern/ceres/internal/ceres/corrector.h
new file mode 100644
index 00000000000..315f012ab1d
--- /dev/null
+++ b/extern/ceres/internal/ceres/corrector.h
@@ -0,0 +1,90 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Class definition for the object that is responsible for applying a
+// second order correction to the Gauss-Newton based on the ideas in
+// BANS by Triggs et al.
+
+#ifndef CERES_INTERNAL_CORRECTOR_H_
+#define CERES_INTERNAL_CORRECTOR_H_
+
+namespace ceres {
+namespace internal {
+
+// Corrector is responsible for applying the second order correction
+// to the residual and jacobian of a least squares problem based on a
+// radial robust loss.
+//
+// The key idea here is to look at the expressions for the robustified
+// gauss newton approximation and then take its squareroot to get the
+// corresponding corrections to the residual and jacobian. For the
+// full expressions see Eq. 10 and 11 in BANS by Triggs et al.
+class Corrector {
+ public:
+ // The constructor takes the squared norm, the value, the first and
+ // second derivatives of the LossFunction. It precalculates some of
+ // the constants that are needed to apply the correction. The
+ // correction constant alpha is constrained to be smaller than 1, if
+ // it becomes larger than 1, then it will reverse the sign of the
+ // residual and the correction. If alpha is equal to 1 will result
+ // in a divide by zero error. Thus we constrain alpha to be upper
+ // bounded by 1 - epsilon_.
+ //
+ // rho[1] needs to be positive. The constructor will crash if this
+ // condition is not met.
+ //
+ // In practical use CorrectJacobian should always be called before
+ // CorrectResidual, because the jacobian correction depends on the
+ // value of the uncorrected residual values.
+ explicit Corrector(double sq_norm, const double rho[3]);
+
+ // residuals *= sqrt(rho[1]) / (1 - alpha)
+ void CorrectResiduals(int num_rows, double* residuals);
+
+ // jacobian = sqrt(rho[1]) * jacobian -
+ // sqrt(rho[1]) * alpha / sq_norm * residuals residuals' * jacobian.
+ //
+ // The method assumes that the jacobian has row-major storage. It is
+ // the caller's responsibility to ensure that the pointer to
+ // jacobian is not null.
+ void CorrectJacobian(int num_rows,
+ int num_cols,
+ double* residuals,
+ double* jacobian);
+
+ private:
+ double sqrt_rho1_;
+ double residual_scaling_;
+ double alpha_sq_norm_;
+};
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_CORRECTOR_H_
diff --git a/extern/ceres/internal/ceres/covariance.cc b/extern/ceres/internal/ceres/covariance.cc
new file mode 100644
index 00000000000..690847945a9
--- /dev/null
+++ b/extern/ceres/internal/ceres/covariance.cc
@@ -0,0 +1,76 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/covariance.h"
+
+#include <utility>
+#include <vector>
+#include "ceres/covariance_impl.h"
+#include "ceres/problem.h"
+#include "ceres/problem_impl.h"
+
+namespace ceres {
+
+using std::pair;
+using std::vector;
+
+Covariance::Covariance(const Covariance::Options& options) {
+ impl_.reset(new internal::CovarianceImpl(options));
+}
+
+Covariance::~Covariance() {
+}
+
+bool Covariance::Compute(
+ const vector<pair<const double*, const double*> >& covariance_blocks,
+ Problem* problem) {
+ return impl_->Compute(covariance_blocks, problem->problem_impl_.get());
+}
+
+bool Covariance::GetCovarianceBlock(const double* parameter_block1,
+ const double* parameter_block2,
+ double* covariance_block) const {
+ return impl_->GetCovarianceBlockInTangentOrAmbientSpace(parameter_block1,
+ parameter_block2,
+ true, // ambient
+ covariance_block);
+}
+
+bool Covariance::GetCovarianceBlockInTangentSpace(
+ const double* parameter_block1,
+ const double* parameter_block2,
+ double* covariance_block) const {
+ return impl_->GetCovarianceBlockInTangentOrAmbientSpace(parameter_block1,
+ parameter_block2,
+ false, // tangent
+ covariance_block);
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/covariance_impl.cc b/extern/ceres/internal/ceres/covariance_impl.cc
new file mode 100644
index 00000000000..3e8302bed55
--- /dev/null
+++ b/extern/ceres/internal/ceres/covariance_impl.cc
@@ -0,0 +1,757 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/covariance_impl.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#endif
+
+#include <algorithm>
+#include <cstdlib>
+#include <utility>
+#include <vector>
+
+#include "Eigen/SparseCore"
+#include "Eigen/SparseQR"
+#include "Eigen/SVD"
+
+#include "ceres/compressed_col_sparse_matrix_utils.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/covariance.h"
+#include "ceres/crs_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/map_util.h"
+#include "ceres/parameter_block.h"
+#include "ceres/problem_impl.h"
+#include "ceres/suitesparse.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::make_pair;
+using std::map;
+using std::pair;
+using std::swap;
+using std::vector;
+
+typedef vector<pair<const double*, const double*> > CovarianceBlocks;
+
+CovarianceImpl::CovarianceImpl(const Covariance::Options& options)
+ : options_(options),
+ is_computed_(false),
+ is_valid_(false) {
+#ifndef CERES_USE_OPENMP
+ if (options_.num_threads > 1) {
+ LOG(WARNING)
+ << "OpenMP support is not compiled into this binary; "
+ << "only options.num_threads = 1 is supported. Switching "
+ << "to single threaded mode.";
+ options_.num_threads = 1;
+ }
+#endif
+ evaluate_options_.num_threads = options_.num_threads;
+ evaluate_options_.apply_loss_function = options_.apply_loss_function;
+}
+
+CovarianceImpl::~CovarianceImpl() {
+}
+
+bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks,
+ ProblemImpl* problem) {
+ problem_ = problem;
+ parameter_block_to_row_index_.clear();
+ covariance_matrix_.reset(NULL);
+ is_valid_ = (ComputeCovarianceSparsity(covariance_blocks, problem) &&
+ ComputeCovarianceValues());
+ is_computed_ = true;
+ return is_valid_;
+}
+
+bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace(
+ const double* original_parameter_block1,
+ const double* original_parameter_block2,
+ bool lift_covariance_to_ambient_space,
+ double* covariance_block) const {
+ CHECK(is_computed_)
+ << "Covariance::GetCovarianceBlock called before Covariance::Compute";
+ CHECK(is_valid_)
+ << "Covariance::GetCovarianceBlock called when Covariance::Compute "
+ << "returned false.";
+
+ // If either of the two parameter blocks is constant, then the
+ // covariance block is also zero.
+ if (constant_parameter_blocks_.count(original_parameter_block1) > 0 ||
+ constant_parameter_blocks_.count(original_parameter_block2) > 0) {
+ const ProblemImpl::ParameterMap& parameter_map = problem_->parameter_map();
+ ParameterBlock* block1 =
+ FindOrDie(parameter_map,
+ const_cast<double*>(original_parameter_block1));
+
+ ParameterBlock* block2 =
+ FindOrDie(parameter_map,
+ const_cast<double*>(original_parameter_block2));
+ const int block1_size = block1->Size();
+ const int block2_size = block2->Size();
+ MatrixRef(covariance_block, block1_size, block2_size).setZero();
+ return true;
+ }
+
+ const double* parameter_block1 = original_parameter_block1;
+ const double* parameter_block2 = original_parameter_block2;
+ const bool transpose = parameter_block1 > parameter_block2;
+ if (transpose) {
+ swap(parameter_block1, parameter_block2);
+ }
+
+ // Find where in the covariance matrix the block is located.
+ const int row_begin =
+ FindOrDie(parameter_block_to_row_index_, parameter_block1);
+ const int col_begin =
+ FindOrDie(parameter_block_to_row_index_, parameter_block2);
+ const int* rows = covariance_matrix_->rows();
+ const int* cols = covariance_matrix_->cols();
+ const int row_size = rows[row_begin + 1] - rows[row_begin];
+ const int* cols_begin = cols + rows[row_begin];
+
+ // The only part that requires work is walking the compressed column
+ // vector to determine where the set of columns correspnding to the
+ // covariance block begin.
+ int offset = 0;
+ while (cols_begin[offset] != col_begin && offset < row_size) {
+ ++offset;
+ }
+
+ if (offset == row_size) {
+ LOG(ERROR) << "Unable to find covariance block for "
+ << original_parameter_block1 << " "
+ << original_parameter_block2;
+ return false;
+ }
+
+ const ProblemImpl::ParameterMap& parameter_map = problem_->parameter_map();
+ ParameterBlock* block1 =
+ FindOrDie(parameter_map, const_cast<double*>(parameter_block1));
+ ParameterBlock* block2 =
+ FindOrDie(parameter_map, const_cast<double*>(parameter_block2));
+ const LocalParameterization* local_param1 = block1->local_parameterization();
+ const LocalParameterization* local_param2 = block2->local_parameterization();
+ const int block1_size = block1->Size();
+ const int block1_local_size = block1->LocalSize();
+ const int block2_size = block2->Size();
+ const int block2_local_size = block2->LocalSize();
+
+ ConstMatrixRef cov(covariance_matrix_->values() + rows[row_begin],
+ block1_size,
+ row_size);
+
+ // Fast path when there are no local parameterizations or if the
+ // user does not want it lifted to the ambient space.
+ if ((local_param1 == NULL && local_param2 == NULL) ||
+ !lift_covariance_to_ambient_space) {
+ if (transpose) {
+ MatrixRef(covariance_block, block2_local_size, block1_local_size) =
+ cov.block(0, offset, block1_local_size,
+ block2_local_size).transpose();
+ } else {
+ MatrixRef(covariance_block, block1_local_size, block2_local_size) =
+ cov.block(0, offset, block1_local_size, block2_local_size);
+ }
+ return true;
+ }
+
+ // If local parameterizations are used then the covariance that has
+ // been computed is in the tangent space and it needs to be lifted
+ // back to the ambient space.
+ //
+ // This is given by the formula
+ //
+ // C'_12 = J_1 C_12 J_2'
+ //
+ // Where C_12 is the local tangent space covariance for parameter
+ // blocks 1 and 2. J_1 and J_2 are respectively the local to global
+ // jacobians for parameter blocks 1 and 2.
+ //
+ // See Result 5.11 on page 142 of Hartley & Zisserman (2nd Edition)
+ // for a proof.
+ //
+ // TODO(sameeragarwal): Add caching of local parameterization, so
+ // that they are computed just once per parameter block.
+ Matrix block1_jacobian(block1_size, block1_local_size);
+ if (local_param1 == NULL) {
+ block1_jacobian.setIdentity();
+ } else {
+ local_param1->ComputeJacobian(parameter_block1, block1_jacobian.data());
+ }
+
+ Matrix block2_jacobian(block2_size, block2_local_size);
+ // Fast path if the user is requesting a diagonal block.
+ if (parameter_block1 == parameter_block2) {
+ block2_jacobian = block1_jacobian;
+ } else {
+ if (local_param2 == NULL) {
+ block2_jacobian.setIdentity();
+ } else {
+ local_param2->ComputeJacobian(parameter_block2, block2_jacobian.data());
+ }
+ }
+
+ if (transpose) {
+ MatrixRef(covariance_block, block2_size, block1_size) =
+ block2_jacobian *
+ cov.block(0, offset, block1_local_size, block2_local_size).transpose() *
+ block1_jacobian.transpose();
+ } else {
+ MatrixRef(covariance_block, block1_size, block2_size) =
+ block1_jacobian *
+ cov.block(0, offset, block1_local_size, block2_local_size) *
+ block2_jacobian.transpose();
+ }
+
+ return true;
+}
+
+// Determine the sparsity pattern of the covariance matrix based on
+// the block pairs requested by the user.
+bool CovarianceImpl::ComputeCovarianceSparsity(
+ const CovarianceBlocks& original_covariance_blocks,
+ ProblemImpl* problem) {
+ EventLogger event_logger("CovarianceImpl::ComputeCovarianceSparsity");
+
+ // Determine an ordering for the parameter block, by sorting the
+ // parameter blocks by their pointers.
+ vector<double*> all_parameter_blocks;
+ problem->GetParameterBlocks(&all_parameter_blocks);
+ const ProblemImpl::ParameterMap& parameter_map = problem->parameter_map();
+ constant_parameter_blocks_.clear();
+ vector<double*>& active_parameter_blocks =
+ evaluate_options_.parameter_blocks;
+ active_parameter_blocks.clear();
+ for (int i = 0; i < all_parameter_blocks.size(); ++i) {
+ double* parameter_block = all_parameter_blocks[i];
+
+ ParameterBlock* block = FindOrDie(parameter_map, parameter_block);
+ if (block->IsConstant()) {
+ constant_parameter_blocks_.insert(parameter_block);
+ } else {
+ active_parameter_blocks.push_back(parameter_block);
+ }
+ }
+
+ std::sort(active_parameter_blocks.begin(), active_parameter_blocks.end());
+
+ // Compute the number of rows. Map each parameter block to the
+ // first row corresponding to it in the covariance matrix using the
+ // ordering of parameter blocks just constructed.
+ int num_rows = 0;
+ parameter_block_to_row_index_.clear();
+ for (int i = 0; i < active_parameter_blocks.size(); ++i) {
+ double* parameter_block = active_parameter_blocks[i];
+ const int parameter_block_size =
+ problem->ParameterBlockLocalSize(parameter_block);
+ parameter_block_to_row_index_[parameter_block] = num_rows;
+ num_rows += parameter_block_size;
+ }
+
+ // Compute the number of non-zeros in the covariance matrix. Along
+ // the way flip any covariance blocks which are in the lower
+ // triangular part of the matrix.
+ int num_nonzeros = 0;
+ CovarianceBlocks covariance_blocks;
+ for (int i = 0; i < original_covariance_blocks.size(); ++i) {
+ const pair<const double*, const double*>& block_pair =
+ original_covariance_blocks[i];
+ if (constant_parameter_blocks_.count(block_pair.first) > 0 ||
+ constant_parameter_blocks_.count(block_pair.second) > 0) {
+ continue;
+ }
+
+ int index1 = FindOrDie(parameter_block_to_row_index_, block_pair.first);
+ int index2 = FindOrDie(parameter_block_to_row_index_, block_pair.second);
+ const int size1 = problem->ParameterBlockLocalSize(block_pair.first);
+ const int size2 = problem->ParameterBlockLocalSize(block_pair.second);
+ num_nonzeros += size1 * size2;
+
+ // Make sure we are constructing a block upper triangular matrix.
+ if (index1 > index2) {
+ covariance_blocks.push_back(make_pair(block_pair.second,
+ block_pair.first));
+ } else {
+ covariance_blocks.push_back(block_pair);
+ }
+ }
+
+ if (covariance_blocks.size() == 0) {
+ VLOG(2) << "No non-zero covariance blocks found";
+ covariance_matrix_.reset(NULL);
+ return true;
+ }
+
+ // Sort the block pairs. As a consequence we get the covariance
+ // blocks as they will occur in the CompressedRowSparseMatrix that
+ // will store the covariance.
+ sort(covariance_blocks.begin(), covariance_blocks.end());
+
+ // Fill the sparsity pattern of the covariance matrix.
+ covariance_matrix_.reset(
+ new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros));
+
+ int* rows = covariance_matrix_->mutable_rows();
+ int* cols = covariance_matrix_->mutable_cols();
+
+ // Iterate over parameter blocks and in turn over the rows of the
+ // covariance matrix. For each parameter block, look in the upper
+ // triangular part of the covariance matrix to see if there are any
+ // blocks requested by the user. If this is the case then fill out a
+ // set of compressed rows corresponding to this parameter block.
+ //
+ // The key thing that makes this loop work is the fact that the
+ // row/columns of the covariance matrix are ordered by the pointer
+ // values of the parameter blocks. Thus iterating over the keys of
+ // parameter_block_to_row_index_ corresponds to iterating over the
+ // rows of the covariance matrix in order.
+ int i = 0; // index into covariance_blocks.
+ int cursor = 0; // index into the covariance matrix.
+ for (map<const double*, int>::const_iterator it =
+ parameter_block_to_row_index_.begin();
+ it != parameter_block_to_row_index_.end();
+ ++it) {
+ const double* row_block = it->first;
+ const int row_block_size = problem->ParameterBlockLocalSize(row_block);
+ int row_begin = it->second;
+
+ // Iterate over the covariance blocks contained in this row block
+ // and count the number of columns in this row block.
+ int num_col_blocks = 0;
+ int num_columns = 0;
+ for (int j = i; j < covariance_blocks.size(); ++j, ++num_col_blocks) {
+ const pair<const double*, const double*>& block_pair =
+ covariance_blocks[j];
+ if (block_pair.first != row_block) {
+ break;
+ }
+ num_columns += problem->ParameterBlockLocalSize(block_pair.second);
+ }
+
+ // Fill out all the compressed rows for this parameter block.
+ for (int r = 0; r < row_block_size; ++r) {
+ rows[row_begin + r] = cursor;
+ for (int c = 0; c < num_col_blocks; ++c) {
+ const double* col_block = covariance_blocks[i + c].second;
+ const int col_block_size = problem->ParameterBlockLocalSize(col_block);
+ int col_begin = FindOrDie(parameter_block_to_row_index_, col_block);
+ for (int k = 0; k < col_block_size; ++k) {
+ cols[cursor++] = col_begin++;
+ }
+ }
+ }
+
+ i+= num_col_blocks;
+ }
+
+ rows[num_rows] = cursor;
+ return true;
+}
+
+bool CovarianceImpl::ComputeCovarianceValues() {
+ switch (options_.algorithm_type) {
+ case DENSE_SVD:
+ return ComputeCovarianceValuesUsingDenseSVD();
+#ifndef CERES_NO_SUITESPARSE
+ case SUITE_SPARSE_QR:
+ return ComputeCovarianceValuesUsingSuiteSparseQR();
+#else
+ LOG(ERROR) << "SuiteSparse is required to use the "
+ << "SUITE_SPARSE_QR algorithm.";
+ return false;
+#endif
+ case EIGEN_SPARSE_QR:
+ return ComputeCovarianceValuesUsingEigenSparseQR();
+ default:
+ LOG(ERROR) << "Unsupported covariance estimation algorithm type: "
+ << CovarianceAlgorithmTypeToString(options_.algorithm_type);
+ return false;
+ }
+ return false;
+}
+
+bool CovarianceImpl::ComputeCovarianceValuesUsingSuiteSparseQR() {
+ EventLogger event_logger(
+ "CovarianceImpl::ComputeCovarianceValuesUsingSparseQR");
+
+#ifndef CERES_NO_SUITESPARSE
+ if (covariance_matrix_.get() == NULL) {
+ // Nothing to do, all zeros covariance matrix.
+ return true;
+ }
+
+ CRSMatrix jacobian;
+ problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+ event_logger.AddEvent("Evaluate");
+
+ // Construct a compressed column form of the Jacobian.
+ const int num_rows = jacobian.num_rows;
+ const int num_cols = jacobian.num_cols;
+ const int num_nonzeros = jacobian.values.size();
+
+ vector<SuiteSparse_long> transpose_rows(num_cols + 1, 0);
+ vector<SuiteSparse_long> transpose_cols(num_nonzeros, 0);
+ vector<double> transpose_values(num_nonzeros, 0);
+
+ for (int idx = 0; idx < num_nonzeros; ++idx) {
+ transpose_rows[jacobian.cols[idx] + 1] += 1;
+ }
+
+ for (int i = 1; i < transpose_rows.size(); ++i) {
+ transpose_rows[i] += transpose_rows[i - 1];
+ }
+
+ for (int r = 0; r < num_rows; ++r) {
+ for (int idx = jacobian.rows[r]; idx < jacobian.rows[r + 1]; ++idx) {
+ const int c = jacobian.cols[idx];
+ const int transpose_idx = transpose_rows[c];
+ transpose_cols[transpose_idx] = r;
+ transpose_values[transpose_idx] = jacobian.values[idx];
+ ++transpose_rows[c];
+ }
+ }
+
+ for (int i = transpose_rows.size() - 1; i > 0 ; --i) {
+ transpose_rows[i] = transpose_rows[i - 1];
+ }
+ transpose_rows[0] = 0;
+
+ cholmod_sparse cholmod_jacobian;
+ cholmod_jacobian.nrow = num_rows;
+ cholmod_jacobian.ncol = num_cols;
+ cholmod_jacobian.nzmax = num_nonzeros;
+ cholmod_jacobian.nz = NULL;
+ cholmod_jacobian.p = reinterpret_cast<void*>(&transpose_rows[0]);
+ cholmod_jacobian.i = reinterpret_cast<void*>(&transpose_cols[0]);
+ cholmod_jacobian.x = reinterpret_cast<void*>(&transpose_values[0]);
+ cholmod_jacobian.z = NULL;
+ cholmod_jacobian.stype = 0; // Matrix is not symmetric.
+ cholmod_jacobian.itype = CHOLMOD_LONG;
+ cholmod_jacobian.xtype = CHOLMOD_REAL;
+ cholmod_jacobian.dtype = CHOLMOD_DOUBLE;
+ cholmod_jacobian.sorted = 1;
+ cholmod_jacobian.packed = 1;
+
+ cholmod_common cc;
+ cholmod_l_start(&cc);
+
+ cholmod_sparse* R = NULL;
+ SuiteSparse_long* permutation = NULL;
+
+ // Compute a Q-less QR factorization of the Jacobian. Since we are
+ // only interested in inverting J'J = R'R, we do not need Q. This
+ // saves memory and gives us R as a permuted compressed column
+ // sparse matrix.
+ //
+ // TODO(sameeragarwal): Currently the symbolic factorization and the
+ // numeric factorization is done at the same time, and this does not
+ // explicitly account for the block column and row structure in the
+ // matrix. When using AMD, we have observed in the past that
+ // computing the ordering with the block matrix is significantly
+ // more efficient, both in runtime as well as the quality of
+ // ordering computed. So, it maybe worth doing that analysis
+ // separately.
+ const SuiteSparse_long rank =
+ SuiteSparseQR<double>(SPQR_ORDERING_BESTAMD,
+ SPQR_DEFAULT_TOL,
+ cholmod_jacobian.ncol,
+ &cholmod_jacobian,
+ &R,
+ &permutation,
+ &cc);
+ event_logger.AddEvent("Numeric Factorization");
+ CHECK_NOTNULL(permutation);
+ CHECK_NOTNULL(R);
+
+ if (rank < cholmod_jacobian.ncol) {
+ LOG(ERROR) << "Jacobian matrix is rank deficient. "
+ << "Number of columns: " << cholmod_jacobian.ncol
+ << " rank: " << rank;
+ free(permutation);
+ cholmod_l_free_sparse(&R, &cc);
+ cholmod_l_finish(&cc);
+ return false;
+ }
+
+ vector<int> inverse_permutation(num_cols);
+ for (SuiteSparse_long i = 0; i < num_cols; ++i) {
+ inverse_permutation[permutation[i]] = i;
+ }
+
+ const int* rows = covariance_matrix_->rows();
+ const int* cols = covariance_matrix_->cols();
+ double* values = covariance_matrix_->mutable_values();
+
+ // The following loop exploits the fact that the i^th column of A^{-1}
+ // is given by the solution to the linear system
+ //
+ // A x = e_i
+ //
+ // where e_i is a vector with e(i) = 1 and all other entries zero.
+ //
+ // Since the covariance matrix is symmetric, the i^th row and column
+ // are equal.
+ const int num_threads = options_.num_threads;
+ scoped_array<double> workspace(new double[num_threads * num_cols]);
+
+#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
+ for (int r = 0; r < num_cols; ++r) {
+ const int row_begin = rows[r];
+ const int row_end = rows[r + 1];
+ if (row_end == row_begin) {
+ continue;
+ }
+
+# ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+# else
+ int thread_id = 0;
+# endif
+
+ double* solution = workspace.get() + thread_id * num_cols;
+ SolveRTRWithSparseRHS<SuiteSparse_long>(
+ num_cols,
+ static_cast<SuiteSparse_long*>(R->i),
+ static_cast<SuiteSparse_long*>(R->p),
+ static_cast<double*>(R->x),
+ inverse_permutation[r],
+ solution);
+ for (int idx = row_begin; idx < row_end; ++idx) {
+ const int c = cols[idx];
+ values[idx] = solution[inverse_permutation[c]];
+ }
+ }
+
+ free(permutation);
+ cholmod_l_free_sparse(&R, &cc);
+ cholmod_l_finish(&cc);
+ event_logger.AddEvent("Inversion");
+ return true;
+
+#else // CERES_NO_SUITESPARSE
+
+ return false;
+
+#endif // CERES_NO_SUITESPARSE
+}
+
+bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
+ EventLogger event_logger(
+ "CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD");
+ if (covariance_matrix_.get() == NULL) {
+ // Nothing to do, all zeros covariance matrix.
+ return true;
+ }
+
+ CRSMatrix jacobian;
+ problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+ event_logger.AddEvent("Evaluate");
+
+ Matrix dense_jacobian(jacobian.num_rows, jacobian.num_cols);
+ dense_jacobian.setZero();
+ for (int r = 0; r < jacobian.num_rows; ++r) {
+ for (int idx = jacobian.rows[r]; idx < jacobian.rows[r + 1]; ++idx) {
+ const int c = jacobian.cols[idx];
+ dense_jacobian(r, c) = jacobian.values[idx];
+ }
+ }
+ event_logger.AddEvent("ConvertToDenseMatrix");
+
+ Eigen::JacobiSVD<Matrix> svd(dense_jacobian,
+ Eigen::ComputeThinU | Eigen::ComputeThinV);
+
+ event_logger.AddEvent("SingularValueDecomposition");
+
+ const Vector singular_values = svd.singularValues();
+ const int num_singular_values = singular_values.rows();
+ Vector inverse_squared_singular_values(num_singular_values);
+ inverse_squared_singular_values.setZero();
+
+ const double max_singular_value = singular_values[0];
+ const double min_singular_value_ratio =
+ sqrt(options_.min_reciprocal_condition_number);
+
+ const bool automatic_truncation = (options_.null_space_rank < 0);
+ const int max_rank = std::min(num_singular_values,
+ num_singular_values - options_.null_space_rank);
+
+ // Compute the squared inverse of the singular values. Truncate the
+ // computation based on min_singular_value_ratio and
+ // null_space_rank. When either of these two quantities are active,
+ // the resulting covariance matrix is a Moore-Penrose inverse
+ // instead of a regular inverse.
+ for (int i = 0; i < max_rank; ++i) {
+ const double singular_value_ratio = singular_values[i] / max_singular_value;
+ if (singular_value_ratio < min_singular_value_ratio) {
+ // Since the singular values are in decreasing order, if
+ // automatic truncation is enabled, then from this point on
+ // all values will fail the ratio test and there is nothing to
+ // do in this loop.
+ if (automatic_truncation) {
+ break;
+ } else {
+ LOG(ERROR) << "Cholesky factorization of J'J is not reliable. "
+ << "Reciprocal condition number: "
+ << singular_value_ratio * singular_value_ratio << " "
+ << "min_reciprocal_condition_number: "
+ << options_.min_reciprocal_condition_number;
+ return false;
+ }
+ }
+
+ inverse_squared_singular_values[i] =
+ 1.0 / (singular_values[i] * singular_values[i]);
+ }
+
+ Matrix dense_covariance =
+ svd.matrixV() *
+ inverse_squared_singular_values.asDiagonal() *
+ svd.matrixV().transpose();
+ event_logger.AddEvent("PseudoInverse");
+
+ const int num_rows = covariance_matrix_->num_rows();
+ const int* rows = covariance_matrix_->rows();
+ const int* cols = covariance_matrix_->cols();
+ double* values = covariance_matrix_->mutable_values();
+
+ for (int r = 0; r < num_rows; ++r) {
+ for (int idx = rows[r]; idx < rows[r + 1]; ++idx) {
+ const int c = cols[idx];
+ values[idx] = dense_covariance(r, c);
+ }
+ }
+ event_logger.AddEvent("CopyToCovarianceMatrix");
+ return true;
+}
+
+bool CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR() {
+ EventLogger event_logger(
+ "CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR");
+ if (covariance_matrix_.get() == NULL) {
+ // Nothing to do, all zeros covariance matrix.
+ return true;
+ }
+
+ CRSMatrix jacobian;
+ problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+ event_logger.AddEvent("Evaluate");
+
+ typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix;
+
+ // Convert the matrix to column major order as required by SparseQR.
+ EigenSparseMatrix sparse_jacobian =
+ Eigen::MappedSparseMatrix<double, Eigen::RowMajor>(
+ jacobian.num_rows, jacobian.num_cols,
+ static_cast<int>(jacobian.values.size()),
+ jacobian.rows.data(), jacobian.cols.data(), jacobian.values.data());
+ event_logger.AddEvent("ConvertToSparseMatrix");
+
+ Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int> >
+ qr_solver(sparse_jacobian);
+ event_logger.AddEvent("QRDecomposition");
+
+ if (qr_solver.info() != Eigen::Success) {
+ LOG(ERROR) << "Eigen::SparseQR decomposition failed.";
+ return false;
+ }
+
+ if (qr_solver.rank() < jacobian.num_cols) {
+ LOG(ERROR) << "Jacobian matrix is rank deficient. "
+ << "Number of columns: " << jacobian.num_cols
+ << " rank: " << qr_solver.rank();
+ return false;
+ }
+
+ const int* rows = covariance_matrix_->rows();
+ const int* cols = covariance_matrix_->cols();
+ double* values = covariance_matrix_->mutable_values();
+
+ // Compute the inverse column permutation used by QR factorization.
+ Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> inverse_permutation =
+ qr_solver.colsPermutation().inverse();
+
+ // The following loop exploits the fact that the i^th column of A^{-1}
+ // is given by the solution to the linear system
+ //
+ // A x = e_i
+ //
+ // where e_i is a vector with e(i) = 1 and all other entries zero.
+ //
+ // Since the covariance matrix is symmetric, the i^th row and column
+ // are equal.
+ const int num_cols = jacobian.num_cols;
+ const int num_threads = options_.num_threads;
+ scoped_array<double> workspace(new double[num_threads * num_cols]);
+
+#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
+ for (int r = 0; r < num_cols; ++r) {
+ const int row_begin = rows[r];
+ const int row_end = rows[r + 1];
+ if (row_end == row_begin) {
+ continue;
+ }
+
+# ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+# else
+ int thread_id = 0;
+# endif
+
+ double* solution = workspace.get() + thread_id * num_cols;
+ SolveRTRWithSparseRHS<int>(
+ num_cols,
+ qr_solver.matrixR().innerIndexPtr(),
+ qr_solver.matrixR().outerIndexPtr(),
+ &qr_solver.matrixR().data().value(0),
+ inverse_permutation.indices().coeff(r),
+ solution);
+
+ // Assign the values of the computed covariance using the
+ // inverse permutation used in the QR factorization.
+ for (int idx = row_begin; idx < row_end; ++idx) {
+ const int c = cols[idx];
+ values[idx] = solution[inverse_permutation.indices().coeff(c)];
+ }
+ }
+
+ event_logger.AddEvent("Inverse");
+
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/covariance_impl.h b/extern/ceres/internal/ceres/covariance_impl.h
new file mode 100644
index 00000000000..eb0cd040666
--- /dev/null
+++ b/extern/ceres/internal/ceres/covariance_impl.h
@@ -0,0 +1,92 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_COVARIANCE_IMPL_H_
+#define CERES_INTERNAL_COVARIANCE_IMPL_H_
+
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+#include "ceres/covariance.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/problem_impl.h"
+#include "ceres/suitesparse.h"
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+
+class CovarianceImpl {
+ public:
+ explicit CovarianceImpl(const Covariance::Options& options);
+ ~CovarianceImpl();
+
+ bool Compute(
+ const std::vector<std::pair<const double*,
+ const double*> >& covariance_blocks,
+ ProblemImpl* problem);
+
+ bool GetCovarianceBlockInTangentOrAmbientSpace(
+ const double* parameter_block1,
+ const double* parameter_block2,
+ bool lift_covariance_to_ambient_space,
+ double* covariance_block) const;
+
+ bool ComputeCovarianceSparsity(
+ const std::vector<std::pair<const double*,
+ const double*> >& covariance_blocks,
+ ProblemImpl* problem);
+
+ bool ComputeCovarianceValues();
+ bool ComputeCovarianceValuesUsingDenseSVD();
+ bool ComputeCovarianceValuesUsingSuiteSparseQR();
+ bool ComputeCovarianceValuesUsingEigenSparseQR();
+
+ const CompressedRowSparseMatrix* covariance_matrix() const {
+ return covariance_matrix_.get();
+ }
+
+ private:
+ ProblemImpl* problem_;
+ Covariance::Options options_;
+ Problem::EvaluateOptions evaluate_options_;
+ bool is_computed_;
+ bool is_valid_;
+ std::map<const double*, int> parameter_block_to_row_index_;
+ std::set<const double*> constant_parameter_blocks_;
+ scoped_ptr<CompressedRowSparseMatrix> covariance_matrix_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_COVARIANCE_IMPL_H_
diff --git a/extern/ceres/internal/ceres/cxsparse.h b/extern/ceres/internal/ceres/cxsparse.h
new file mode 100644
index 00000000000..26dd1927a78
--- /dev/null
+++ b/extern/ceres/internal/ceres/cxsparse.h
@@ -0,0 +1,140 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: strandmark@google.com (Petter Strandmark)
+
+#ifndef CERES_INTERNAL_CXSPARSE_H_
+#define CERES_INTERNAL_CXSPARSE_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_NO_CXSPARSE
+
+#include <vector>
+#include "cs.h"
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+class TripletSparseMatrix;
+
+// This object provides access to solving linear systems using Cholesky
+// factorization with a known symbolic factorization. This features does not
+// explicity exist in CXSparse. The methods in the class are nonstatic because
+// the class manages internal scratch space.
+class CXSparse {
+ public:
+ CXSparse();
+ ~CXSparse();
+
+ // Solves a symmetric linear system A * x = b using Cholesky factorization.
+ // A - The system matrix.
+ // symbolic_factorization - The symbolic factorization of A. This is obtained
+ // from AnalyzeCholesky.
+ // b - The right hand size of the linear equation. This
+ // array will also recieve the solution.
+ // Returns false if Cholesky factorization of A fails.
+ bool SolveCholesky(cs_di* A, cs_dis* symbolic_factorization, double* b);
+
+ // Creates a sparse matrix from a compressed-column form. No memory is
+ // allocated or copied; the structure A is filled out with info from the
+ // argument.
+ cs_di CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
+
+ // Creates a new matrix from a triplet form. Deallocate the returned matrix
+ // with Free. May return NULL if the compression or allocation fails.
+ cs_di* CreateSparseMatrix(TripletSparseMatrix* A);
+
+ // B = A'
+ //
+ // The returned matrix should be deallocated with Free when not used
+ // anymore.
+ cs_di* TransposeMatrix(cs_di* A);
+
+ // C = A * B
+ //
+ // The returned matrix should be deallocated with Free when not used
+ // anymore.
+ cs_di* MatrixMatrixMultiply(cs_di* A, cs_di* B);
+
+ // Computes a symbolic factorization of A that can be used in SolveCholesky.
+ //
+ // The returned matrix should be deallocated with Free when not used anymore.
+ cs_dis* AnalyzeCholesky(cs_di* A);
+
+ // Computes a symbolic factorization of A that can be used in
+ // SolveCholesky, but does not compute a fill-reducing ordering.
+ //
+ // The returned matrix should be deallocated with Free when not used anymore.
+ cs_dis* AnalyzeCholeskyWithNaturalOrdering(cs_di* A);
+
+ // Computes a symbolic factorization of A that can be used in
+ // SolveCholesky. The difference from AnalyzeCholesky is that this
+ // function first detects the block sparsity of the matrix using
+ // information about the row and column blocks and uses this block
+ // sparse matrix to find a fill-reducing ordering. This ordering is
+ // then used to find a symbolic factorization. This can result in a
+ // significant performance improvement AnalyzeCholesky on block
+ // sparse matrices.
+ //
+ // The returned matrix should be deallocated with Free when not used
+ // anymore.
+ cs_dis* BlockAnalyzeCholesky(cs_di* A,
+ const std::vector<int>& row_blocks,
+ const std::vector<int>& col_blocks);
+
+ // Compute an fill-reducing approximate minimum degree ordering of
+ // the matrix A. ordering should be non-NULL and should point to
+ // enough memory to hold the ordering for the rows of A.
+ void ApproximateMinimumDegreeOrdering(cs_di* A, int* ordering);
+
+ void Free(cs_di* sparse_matrix);
+ void Free(cs_dis* symbolic_factorization);
+
+ private:
+ // Cached scratch space
+ CS_ENTRY* scratch_;
+ int scratch_size_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#else // CERES_NO_CXSPARSE
+
+typedef void cs_dis;
+
+class CXSparse {
+ public:
+ void Free(void* arg) {}
+};
+#endif // CERES_NO_CXSPARSE
+
+#endif // CERES_INTERNAL_CXSPARSE_H_
diff --git a/extern/ceres/internal/ceres/dense_jacobian_writer.h b/extern/ceres/internal/ceres/dense_jacobian_writer.h
new file mode 100644
index 00000000000..1b04f383f09
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_jacobian_writer.h
@@ -0,0 +1,108 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A jacobian writer that writes to dense Eigen matrices.
+
+#ifndef CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
+#define CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
+
+#include "ceres/casts.h"
+#include "ceres/dense_sparse_matrix.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/scratch_evaluate_preparer.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+class DenseJacobianWriter {
+ public:
+ DenseJacobianWriter(Evaluator::Options /* ignored */,
+ Program* program)
+ : program_(program) {
+ }
+
+ // JacobianWriter interface.
+
+ // Since the dense matrix has different layout than that assumed by the cost
+ // functions, use scratch space to store the jacobians temporarily then copy
+ // them over to the larger jacobian later.
+ ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads) {
+ return ScratchEvaluatePreparer::Create(*program_, num_threads);
+ }
+
+ SparseMatrix* CreateJacobian() const {
+ return new DenseSparseMatrix(program_->NumResiduals(),
+ program_->NumEffectiveParameters(),
+ true);
+ }
+
+ void Write(int residual_id,
+ int residual_offset,
+ double **jacobians,
+ SparseMatrix* jacobian) {
+ DenseSparseMatrix* dense_jacobian = down_cast<DenseSparseMatrix*>(jacobian);
+ const ResidualBlock* residual_block =
+ program_->residual_blocks()[residual_id];
+ int num_parameter_blocks = residual_block->NumParameterBlocks();
+ int num_residuals = residual_block->NumResiduals();
+
+ // Now copy the jacobians for each parameter into the dense jacobian matrix.
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+
+ // If the parameter block is fixed, then there is nothing to do.
+ if (parameter_block->IsConstant()) {
+ continue;
+ }
+
+ const int parameter_block_size = parameter_block->LocalSize();
+ ConstMatrixRef parameter_jacobian(jacobians[j],
+ num_residuals,
+ parameter_block_size);
+
+ dense_jacobian->mutable_matrix().block(
+ residual_offset,
+ parameter_block->delta_offset(),
+ num_residuals,
+ parameter_block_size) = parameter_jacobian;
+ }
+ }
+
+ private:
+ Program* program_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
diff --git a/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc
new file mode 100644
index 00000000000..b13cf3fc9f6
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.cc
@@ -0,0 +1,166 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dense_normal_cholesky_solver.h"
+
+#include <cstddef>
+
+#include "Eigen/Dense"
+#include "ceres/blas.h"
+#include "ceres/dense_sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/lapack.h"
+#include "ceres/linear_solver.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+
+DenseNormalCholeskySolver::DenseNormalCholeskySolver(
+ const LinearSolver::Options& options)
+ : options_(options) {}
+
+LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ if (options_.dense_linear_algebra_library_type == EIGEN) {
+ return SolveUsingEigen(A, b, per_solve_options, x);
+ } else {
+ return SolveUsingLAPACK(A, b, per_solve_options, x);
+ }
+}
+
+LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingEigen(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("DenseNormalCholeskySolver::Solve");
+
+ const int num_rows = A->num_rows();
+ const int num_cols = A->num_cols();
+
+ ConstColMajorMatrixRef Aref = A->matrix();
+ Matrix lhs(num_cols, num_cols);
+ lhs.setZero();
+
+ event_logger.AddEvent("Setup");
+
+ // lhs += A'A
+ //
+ // Using rankUpdate instead of GEMM, exposes the fact that its the
+ // same matrix being multiplied with itself and that the product is
+ // symmetric.
+ lhs.selfadjointView<Eigen::Upper>().rankUpdate(Aref.transpose());
+
+ // rhs = A'b
+ Vector rhs = Aref.transpose() * ConstVectorRef(b, num_rows);
+
+ if (per_solve_options.D != NULL) {
+ ConstVectorRef D(per_solve_options.D, num_cols);
+ lhs += D.array().square().matrix().asDiagonal();
+ }
+ event_logger.AddEvent("Product");
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ Eigen::LLT<Matrix, Eigen::Upper> llt =
+ lhs.selfadjointView<Eigen::Upper>().llt();
+
+ if (llt.info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen LLT decomposition failed.";
+ } else {
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+ }
+
+ VectorRef(x, num_cols) = llt.solve(rhs);
+ event_logger.AddEvent("Solve");
+ return summary;
+}
+
+LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingLAPACK(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("DenseNormalCholeskySolver::Solve");
+
+ if (per_solve_options.D != NULL) {
+ // Temporarily append a diagonal block to the A matrix, but undo
+ // it before returning the matrix to the user.
+ A->AppendDiagonal(per_solve_options.D);
+ }
+
+ const int num_cols = A->num_cols();
+ Matrix lhs(num_cols, num_cols);
+ event_logger.AddEvent("Setup");
+
+ // lhs = A'A
+ //
+ // Note: This is a bit delicate, it assumes that the stride on this
+ // matrix is the same as the number of rows.
+ BLAS::SymmetricRankKUpdate(A->num_rows(),
+ num_cols,
+ A->values(),
+ true,
+ 1.0,
+ 0.0,
+ lhs.data());
+
+ if (per_solve_options.D != NULL) {
+ // Undo the modifications to the matrix A.
+ A->RemoveDiagonal();
+ }
+
+ // TODO(sameeragarwal): Replace this with a gemv call for true blasness.
+ // rhs = A'b
+ VectorRef(x, num_cols) =
+ A->matrix().transpose() * ConstVectorRef(b, A->num_rows());
+ event_logger.AddEvent("Product");
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type =
+ LAPACK::SolveInPlaceUsingCholesky(num_cols,
+ lhs.data(),
+ x,
+ &summary.message);
+ event_logger.AddEvent("Solve");
+ return summary;
+}
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h
new file mode 100644
index 00000000000..11287ebf675
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_normal_cholesky_solver.h
@@ -0,0 +1,107 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Solve dense rectangular systems Ax = b by forming the normal
+// equations and solving them using the Cholesky factorization.
+
+#ifndef CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
+#define CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
+
+#include "ceres/linear_solver.h"
+#include "ceres/internal/macros.h"
+
+namespace ceres {
+namespace internal {
+
+class DenseSparseMatrix;
+
+// This class implements the LinearSolver interface for solving
+// rectangular/unsymmetric (well constrained) linear systems of the
+// form
+//
+// Ax = b
+//
+// Since there does not usually exist a solution that satisfies these
+// equations, the solver instead solves the linear least squares
+// problem
+//
+// min_x |Ax - b|^2
+//
+// Setting the gradient of the above optimization problem to zero
+// gives us the normal equations
+//
+// A'Ax = A'b
+//
+// A'A is a positive definite matrix (hopefully), and the resulting
+// linear system can be solved using Cholesky factorization.
+//
+// If the PerSolveOptions struct has a non-null array D, then the
+// augmented/regularized linear system
+//
+// [ A ]x = [b]
+// [ diag(D) ] [0]
+//
+// is solved.
+//
+// This class uses the LDLT factorization routines from the Eigen
+// library. This solver always returns a solution, it is the user's
+// responsibility to judge if the solution is good enough for their
+// purposes.
+class DenseNormalCholeskySolver: public DenseSparseMatrixSolver {
+ public:
+ explicit DenseNormalCholeskySolver(const LinearSolver::Options& options);
+
+ private:
+ virtual LinearSolver::Summary SolveImpl(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ LinearSolver::Summary SolveUsingLAPACK(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ LinearSolver::Summary SolveUsingEigen(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ const LinearSolver::Options options_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(DenseNormalCholeskySolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/dense_qr_solver.cc b/extern/ceres/internal/ceres/dense_qr_solver.cc
new file mode 100644
index 00000000000..e85fdfc0c68
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_qr_solver.cc
@@ -0,0 +1,170 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dense_qr_solver.h"
+
+
+#include <cstddef>
+#include "Eigen/Dense"
+#include "ceres/dense_sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/lapack.h"
+#include "ceres/linear_solver.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+
+DenseQRSolver::DenseQRSolver(const LinearSolver::Options& options)
+ : options_(options) {
+ work_.resize(1);
+}
+
+LinearSolver::Summary DenseQRSolver::SolveImpl(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ if (options_.dense_linear_algebra_library_type == EIGEN) {
+ return SolveUsingEigen(A, b, per_solve_options, x);
+ } else {
+ return SolveUsingLAPACK(A, b, per_solve_options, x);
+ }
+}
+
+LinearSolver::Summary DenseQRSolver::SolveUsingLAPACK(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("DenseQRSolver::Solve");
+
+ const int num_rows = A->num_rows();
+ const int num_cols = A->num_cols();
+
+ if (per_solve_options.D != NULL) {
+ // Temporarily append a diagonal block to the A matrix, but undo
+ // it before returning the matrix to the user.
+ A->AppendDiagonal(per_solve_options.D);
+ }
+
+ // TODO(sameeragarwal): Since we are copying anyways, the diagonal
+ // can be appended to the matrix instead of doing it on A.
+ lhs_ = A->matrix();
+
+ if (per_solve_options.D != NULL) {
+ // Undo the modifications to the matrix A.
+ A->RemoveDiagonal();
+ }
+
+ // rhs = [b;0] to account for the additional rows in the lhs.
+ if (rhs_.rows() != lhs_.rows()) {
+ rhs_.resize(lhs_.rows());
+ }
+ rhs_.setZero();
+ rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
+
+ if (work_.rows() == 1) {
+ const int work_size =
+ LAPACK::EstimateWorkSizeForQR(lhs_.rows(), lhs_.cols());
+ VLOG(3) << "Working memory for Dense QR factorization: "
+ << work_size * sizeof(double);
+ work_.resize(work_size);
+ }
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LAPACK::SolveInPlaceUsingQR(lhs_.rows(),
+ lhs_.cols(),
+ lhs_.data(),
+ work_.rows(),
+ work_.data(),
+ rhs_.data(),
+ &summary.message);
+ event_logger.AddEvent("Solve");
+ if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
+ VectorRef(x, num_cols) = rhs_.head(num_cols);
+ }
+
+ event_logger.AddEvent("TearDown");
+ return summary;
+}
+
+LinearSolver::Summary DenseQRSolver::SolveUsingEigen(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("DenseQRSolver::Solve");
+
+ const int num_rows = A->num_rows();
+ const int num_cols = A->num_cols();
+
+ if (per_solve_options.D != NULL) {
+ // Temporarily append a diagonal block to the A matrix, but undo
+ // it before returning the matrix to the user.
+ A->AppendDiagonal(per_solve_options.D);
+ }
+
+ // rhs = [b;0] to account for the additional rows in the lhs.
+ const int augmented_num_rows =
+ num_rows + ((per_solve_options.D != NULL) ? num_cols : 0);
+ if (rhs_.rows() != augmented_num_rows) {
+ rhs_.resize(augmented_num_rows);
+ rhs_.setZero();
+ }
+ rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
+ event_logger.AddEvent("Setup");
+
+ // Solve the system.
+ VectorRef(x, num_cols) = A->matrix().householderQr().solve(rhs_);
+ event_logger.AddEvent("Solve");
+
+ if (per_solve_options.D != NULL) {
+ // Undo the modifications to the matrix A.
+ A->RemoveDiagonal();
+ }
+
+ // We always succeed, since the QR solver returns the best solution
+ // it can. It is the job of the caller to determine if the solution
+ // is good enough or not.
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ event_logger.AddEvent("TearDown");
+ return summary;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dense_qr_solver.h b/extern/ceres/internal/ceres/dense_qr_solver.h
new file mode 100644
index 00000000000..1a6e0898c56
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_qr_solver.h
@@ -0,0 +1,115 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Solve dense rectangular systems Ax = b using the QR factorization.
+#ifndef CERES_INTERNAL_DENSE_QR_SOLVER_H_
+#define CERES_INTERNAL_DENSE_QR_SOLVER_H_
+
+#include "ceres/linear_solver.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/macros.h"
+
+namespace ceres {
+namespace internal {
+
+class DenseSparseMatrix;
+
+// This class implements the LinearSolver interface for solving
+// rectangular/unsymmetric (well constrained) linear systems of the
+// form
+//
+// Ax = b
+//
+// Since there does not usually exist a solution that satisfies these
+// equations, the solver instead solves the linear least squares
+// problem
+//
+// min_x |Ax - b|^2
+//
+// The solution strategy is based on computing the QR decomposition of
+// A, i.e.
+//
+// A = QR
+//
+// Where Q is an orthonormal matrix and R is an upper triangular
+// matrix. Then
+//
+// Ax = b
+// QRx = b
+// Q'QRx = Q'b
+// Rx = Q'b
+// x = R^{-1} Q'b
+//
+// If the PerSolveOptions struct has a non-null array D, then the
+// augmented/regularized linear system
+//
+// [ A ]x = [b]
+// [ diag(D) ] [0]
+//
+// is solved.
+//
+// This class uses the dense QR factorization routines from the Eigen
+// library. This solver always returns a solution, it is the user's
+// responsibility to judge if the solution is good enough for their
+// purposes.
+class DenseQRSolver: public DenseSparseMatrixSolver {
+ public:
+ explicit DenseQRSolver(const LinearSolver::Options& options);
+
+ private:
+ virtual LinearSolver::Summary SolveImpl(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ LinearSolver::Summary SolveUsingEigen(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ LinearSolver::Summary SolveUsingLAPACK(
+ DenseSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ const LinearSolver::Options options_;
+ ColMajorMatrix lhs_;
+ Vector rhs_;
+ Vector work_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DENSE_QR_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/dense_sparse_matrix.cc b/extern/ceres/internal/ceres/dense_sparse_matrix.cc
new file mode 100644
index 00000000000..19db867d4aa
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_sparse_matrix.cc
@@ -0,0 +1,183 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/dense_sparse_matrix.h"
+
+#include <algorithm>
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols)
+ : has_diagonal_appended_(false),
+ has_diagonal_reserved_(false) {
+ m_.resize(num_rows, num_cols);
+ m_.setZero();
+}
+
+DenseSparseMatrix::DenseSparseMatrix(int num_rows,
+ int num_cols,
+ bool reserve_diagonal)
+ : has_diagonal_appended_(false),
+ has_diagonal_reserved_(reserve_diagonal) {
+ if (reserve_diagonal) {
+ // Allocate enough space for the diagonal.
+ m_.resize(num_rows + num_cols, num_cols);
+ } else {
+ m_.resize(num_rows, num_cols);
+ }
+ m_.setZero();
+}
+
+DenseSparseMatrix::DenseSparseMatrix(const TripletSparseMatrix& m)
+ : m_(Eigen::MatrixXd::Zero(m.num_rows(), m.num_cols())),
+ has_diagonal_appended_(false),
+ has_diagonal_reserved_(false) {
+ const double *values = m.values();
+ const int *rows = m.rows();
+ const int *cols = m.cols();
+ int num_nonzeros = m.num_nonzeros();
+
+ for (int i = 0; i < num_nonzeros; ++i) {
+ m_(rows[i], cols[i]) += values[i];
+ }
+}
+
+DenseSparseMatrix::DenseSparseMatrix(const ColMajorMatrix& m)
+ : m_(m),
+ has_diagonal_appended_(false),
+ has_diagonal_reserved_(false) {
+}
+
+void DenseSparseMatrix::SetZero() {
+ m_.setZero();
+}
+
+void DenseSparseMatrix::RightMultiply(const double* x, double* y) const {
+ VectorRef(y, num_rows()) += matrix() * ConstVectorRef(x, num_cols());
+}
+
+void DenseSparseMatrix::LeftMultiply(const double* x, double* y) const {
+ VectorRef(y, num_cols()) +=
+ matrix().transpose() * ConstVectorRef(x, num_rows());
+}
+
+void DenseSparseMatrix::SquaredColumnNorm(double* x) const {
+ VectorRef(x, num_cols()) = m_.colwise().squaredNorm();
+}
+
+void DenseSparseMatrix::ScaleColumns(const double* scale) {
+ m_ *= ConstVectorRef(scale, num_cols()).asDiagonal();
+}
+
+void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
+ *dense_matrix = m_.block(0, 0, num_rows(), num_cols());
+}
+
+void DenseSparseMatrix::AppendDiagonal(double *d) {
+ CHECK(!has_diagonal_appended_);
+ if (!has_diagonal_reserved_) {
+ ColMajorMatrix tmp = m_;
+ m_.resize(m_.rows() + m_.cols(), m_.cols());
+ m_.setZero();
+ m_.block(0, 0, tmp.rows(), tmp.cols()) = tmp;
+ has_diagonal_reserved_ = true;
+ }
+
+ m_.bottomLeftCorner(m_.cols(), m_.cols()) =
+ ConstVectorRef(d, m_.cols()).asDiagonal();
+ has_diagonal_appended_ = true;
+}
+
+void DenseSparseMatrix::RemoveDiagonal() {
+ CHECK(has_diagonal_appended_);
+ has_diagonal_appended_ = false;
+ // Leave the diagonal reserved.
+}
+
+int DenseSparseMatrix::num_rows() const {
+ if (has_diagonal_reserved_ && !has_diagonal_appended_) {
+ return m_.rows() - m_.cols();
+ }
+ return m_.rows();
+}
+
+int DenseSparseMatrix::num_cols() const {
+ return m_.cols();
+}
+
+int DenseSparseMatrix::num_nonzeros() const {
+ if (has_diagonal_reserved_ && !has_diagonal_appended_) {
+ return (m_.rows() - m_.cols()) * m_.cols();
+ }
+ return m_.rows() * m_.cols();
+}
+
+ConstColMajorMatrixRef DenseSparseMatrix::matrix() const {
+ return ConstColMajorMatrixRef(
+ m_.data(),
+ ((has_diagonal_reserved_ && !has_diagonal_appended_)
+ ? m_.rows() - m_.cols()
+ : m_.rows()),
+ m_.cols(),
+ Eigen::Stride<Eigen::Dynamic, 1>(m_.rows(), 1));
+}
+
+ColMajorMatrixRef DenseSparseMatrix::mutable_matrix() {
+ return ColMajorMatrixRef(
+ m_.data(),
+ ((has_diagonal_reserved_ && !has_diagonal_appended_)
+ ? m_.rows() - m_.cols()
+ : m_.rows()),
+ m_.cols(),
+ Eigen::Stride<Eigen::Dynamic, 1>(m_.rows(), 1));
+}
+
+
+void DenseSparseMatrix::ToTextFile(FILE* file) const {
+ CHECK_NOTNULL(file);
+ const int active_rows =
+ (has_diagonal_reserved_ && !has_diagonal_appended_)
+ ? (m_.rows() - m_.cols())
+ : m_.rows();
+
+ for (int r = 0; r < active_rows; ++r) {
+ for (int c = 0; c < m_.cols(); ++c) {
+ fprintf(file, "% 10d % 10d %17f\n", r, c, m_(r, c));
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dense_sparse_matrix.h b/extern/ceres/internal/ceres/dense_sparse_matrix.h
new file mode 100644
index 00000000000..b011bfddee7
--- /dev/null
+++ b/extern/ceres/internal/ceres/dense_sparse_matrix.h
@@ -0,0 +1,109 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A dense matrix implemented under the SparseMatrix interface.
+
+#ifndef CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
+
+#include "ceres/sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class TripletSparseMatrix;
+
+class DenseSparseMatrix : public SparseMatrix {
+ public:
+ // Build a matrix with the same content as the TripletSparseMatrix
+ // m. This assumes that m does not have any repeated entries.
+ explicit DenseSparseMatrix(const TripletSparseMatrix& m);
+ explicit DenseSparseMatrix(const ColMajorMatrix& m);
+
+ DenseSparseMatrix(int num_rows, int num_cols);
+ DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal);
+
+ virtual ~DenseSparseMatrix() {}
+
+ // SparseMatrix interface.
+ virtual void SetZero();
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual void LeftMultiply(const double* x, double* y) const;
+ virtual void SquaredColumnNorm(double* x) const;
+ virtual void ScaleColumns(const double* scale);
+ virtual void ToDenseMatrix(Matrix* dense_matrix) const;
+ virtual void ToTextFile(FILE* file) const;
+ virtual int num_rows() const;
+ virtual int num_cols() const;
+ virtual int num_nonzeros() const;
+ virtual const double* values() const { return m_.data(); }
+ virtual double* mutable_values() { return m_.data(); }
+
+ ConstColMajorMatrixRef matrix() const;
+ ColMajorMatrixRef mutable_matrix();
+
+ // Only one diagonal can be appended at a time. The diagonal is appended to
+ // as a new set of rows, e.g.
+ //
+ // Original matrix:
+ //
+ // x x x
+ // x x x
+ // x x x
+ //
+ // After append diagonal (1, 2, 3):
+ //
+ // x x x
+ // x x x
+ // x x x
+ // 1 0 0
+ // 0 2 0
+ // 0 0 3
+ //
+ // Calling RemoveDiagonal removes the block. It is a fatal error to append a
+ // diagonal to a matrix that already has an appended diagonal, and it is also
+ // a fatal error to remove a diagonal from a matrix that has none.
+ void AppendDiagonal(double *d);
+ void RemoveDiagonal();
+
+ private:
+ ColMajorMatrix m_;
+ bool has_diagonal_appended_;
+ bool has_diagonal_reserved_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/detect_structure.cc b/extern/ceres/internal/ceres/detect_structure.cc
new file mode 100644
index 00000000000..959a0ee3c84
--- /dev/null
+++ b/extern/ceres/internal/ceres/detect_structure.cc
@@ -0,0 +1,120 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/detect_structure.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+void DetectStructure(const CompressedRowBlockStructure& bs,
+ const int num_eliminate_blocks,
+ int* row_block_size,
+ int* e_block_size,
+ int* f_block_size) {
+ const int num_row_blocks = bs.rows.size();
+ *row_block_size = 0;
+ *e_block_size = 0;
+ *f_block_size = 0;
+
+ // Iterate over row blocks of the matrix, checking if row_block,
+ // e_block or f_block sizes remain constant.
+ for (int r = 0; r < num_row_blocks; ++r) {
+ const CompressedRow& row = bs.rows[r];
+ // We do not care about the sizes of the blocks in rows which do
+ // not contain e_blocks.
+ if (row.cells.front().block_id >= num_eliminate_blocks) {
+ break;
+ }
+
+ // Detect fixed or dynamic row block size.
+ if (*row_block_size == 0) {
+ *row_block_size = row.block.size;
+ } else if (*row_block_size != Eigen::Dynamic &&
+ *row_block_size != row.block.size) {
+ VLOG(2) << "Dynamic row block size because the block size changed from "
+ << *row_block_size << " to "
+ << row.block.size;
+ *row_block_size = Eigen::Dynamic;
+ }
+
+ // Detect fixed or dynamic e-block size.
+ const int e_block_id = row.cells.front().block_id;
+ if (*e_block_size == 0) {
+ *e_block_size = bs.cols[e_block_id].size;
+ } else if (*e_block_size != Eigen::Dynamic &&
+ *e_block_size != bs.cols[e_block_id].size) {
+ VLOG(2) << "Dynamic e block size because the block size changed from "
+ << *e_block_size << " to "
+ << bs.cols[e_block_id].size;
+ *e_block_size = Eigen::Dynamic;
+ }
+
+ // Detect fixed or dynamic f-block size. We are only interested in
+ // rows with e-blocks, and the e-block is always the first block,
+ // so only rows of size greater than 1 are of interest.
+ if (row.cells.size() > 1) {
+ if (*f_block_size == 0) {
+ const int f_block_id = row.cells[1].block_id;
+ *f_block_size = bs.cols[f_block_id].size;
+ }
+
+ for (int c = 1;
+ (c < row.cells.size()) && (*f_block_size != Eigen::Dynamic);
+ ++c) {
+ const int f_block_id = row.cells[c].block_id;
+ if (*f_block_size != bs.cols[f_block_id].size) {
+ VLOG(2) << "Dynamic f block size because the block size "
+ << "changed from " << *f_block_size << " to "
+ << bs.cols[f_block_id].size;
+ *f_block_size = Eigen::Dynamic;
+ }
+ }
+ }
+
+ const bool is_everything_dynamic = (*row_block_size == Eigen::Dynamic &&
+ *e_block_size == Eigen::Dynamic &&
+ *f_block_size == Eigen::Dynamic);
+ if (is_everything_dynamic) {
+ break;
+ }
+ }
+
+ CHECK_NE(*row_block_size, 0) << "No rows found";
+ CHECK_NE(*e_block_size, 0) << "No e type blocks found";
+ VLOG(1) << "Schur complement static structure <"
+ << *row_block_size << ","
+ << *e_block_size << ","
+ << *f_block_size << ">.";
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/detect_structure.h b/extern/ceres/internal/ceres/detect_structure.h
new file mode 100644
index 00000000000..602581c846e
--- /dev/null
+++ b/extern/ceres/internal/ceres/detect_structure.h
@@ -0,0 +1,67 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_DETECT_STRUCTURE_H_
+#define CERES_INTERNAL_DETECT_STRUCTURE_H_
+
+#include "ceres/block_structure.h"
+
+namespace ceres {
+namespace internal {
+
+// Detect static blocks in the problem sparsity. For rows containing
+// e_blocks, we are interested in detecting if the size of the row
+// blocks, e_blocks and the f_blocks remain constant. If they do, then
+// we can use template specialization to improve the performance of
+// the block level linear algebra operations used by the
+// SchurEliminator.
+//
+// If a block size is not constant, we return Eigen::Dynamic as the
+// value. This just means that the eliminator uses dynamically sized
+// linear algebra operations rather than static operations whose size
+// is known as compile time.
+//
+// For more details about e_blocks and f_blocks, see
+// schur_eliminator.h. This information is used to initialized an
+// appropriate template specialization of SchurEliminator.
+//
+// Note: The structure of rows without any e-blocks has no effect on
+// the values returned by this function. It is entirely possible that
+// the f_block_size and row_blocks_size is not constant in such rows.
+void DetectStructure(const CompressedRowBlockStructure& bs,
+ const int num_eliminate_blocks,
+ int* row_block_size,
+ int* e_block_size,
+ int* f_block_size);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DETECT_STRUCTURE_H_
diff --git a/extern/ceres/internal/ceres/dogleg_strategy.cc b/extern/ceres/internal/ceres/dogleg_strategy.cc
new file mode 100644
index 00000000000..839e1816338
--- /dev/null
+++ b/extern/ceres/internal/ceres/dogleg_strategy.cc
@@ -0,0 +1,718 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dogleg_strategy.h"
+
+#include <cmath>
+#include "Eigen/Dense"
+#include "ceres/array_utils.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_least_squares_problems.h"
+#include "ceres/linear_solver.h"
+#include "ceres/polynomial.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/trust_region_strategy.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+const double kMaxMu = 1.0;
+const double kMinMu = 1e-8;
+}
+
+DoglegStrategy::DoglegStrategy(const TrustRegionStrategy::Options& options)
+ : linear_solver_(options.linear_solver),
+ radius_(options.initial_radius),
+ max_radius_(options.max_radius),
+ min_diagonal_(options.min_lm_diagonal),
+ max_diagonal_(options.max_lm_diagonal),
+ mu_(kMinMu),
+ min_mu_(kMinMu),
+ max_mu_(kMaxMu),
+ mu_increase_factor_(10.0),
+ increase_threshold_(0.75),
+ decrease_threshold_(0.25),
+ dogleg_step_norm_(0.0),
+ reuse_(false),
+ dogleg_type_(options.dogleg_type) {
+ CHECK_NOTNULL(linear_solver_);
+ CHECK_GT(min_diagonal_, 0.0);
+ CHECK_LE(min_diagonal_, max_diagonal_);
+ CHECK_GT(max_radius_, 0.0);
+}
+
+// If the reuse_ flag is not set, then the Cauchy point (scaled
+// gradient) and the new Gauss-Newton step are computed from
+// scratch. The Dogleg step is then computed as interpolation of these
+// two vectors.
+TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
+ const TrustRegionStrategy::PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals,
+ double* step) {
+ CHECK_NOTNULL(jacobian);
+ CHECK_NOTNULL(residuals);
+ CHECK_NOTNULL(step);
+
+ const int n = jacobian->num_cols();
+ if (reuse_) {
+ // Gauss-Newton and gradient vectors are always available, only a
+ // new interpolant need to be computed. For the subspace case,
+ // the subspace and the two-dimensional model are also still valid.
+ switch (dogleg_type_) {
+ case TRADITIONAL_DOGLEG:
+ ComputeTraditionalDoglegStep(step);
+ break;
+
+ case SUBSPACE_DOGLEG:
+ ComputeSubspaceDoglegStep(step);
+ break;
+ }
+ TrustRegionStrategy::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ return summary;
+ }
+
+ reuse_ = true;
+ // Check that we have the storage needed to hold the various
+ // temporary vectors.
+ if (diagonal_.rows() != n) {
+ diagonal_.resize(n, 1);
+ gradient_.resize(n, 1);
+ gauss_newton_step_.resize(n, 1);
+ }
+
+ // Vector used to form the diagonal matrix that is used to
+ // regularize the Gauss-Newton solve and that defines the
+ // elliptical trust region
+ //
+ // || D * step || <= radius_ .
+ //
+ jacobian->SquaredColumnNorm(diagonal_.data());
+ for (int i = 0; i < n; ++i) {
+ diagonal_[i] = std::min(std::max(diagonal_[i], min_diagonal_),
+ max_diagonal_);
+ }
+ diagonal_ = diagonal_.array().sqrt();
+
+ ComputeGradient(jacobian, residuals);
+ ComputeCauchyPoint(jacobian);
+
+ LinearSolver::Summary linear_solver_summary =
+ ComputeGaussNewtonStep(per_solve_options, jacobian, residuals);
+
+ TrustRegionStrategy::Summary summary;
+ summary.residual_norm = linear_solver_summary.residual_norm;
+ summary.num_iterations = linear_solver_summary.num_iterations;
+ summary.termination_type = linear_solver_summary.termination_type;
+
+ if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+ return summary;
+ }
+
+ if (linear_solver_summary.termination_type != LINEAR_SOLVER_FAILURE) {
+ switch (dogleg_type_) {
+ // Interpolate the Cauchy point and the Gauss-Newton step.
+ case TRADITIONAL_DOGLEG:
+ ComputeTraditionalDoglegStep(step);
+ break;
+
+ // Find the minimum in the subspace defined by the
+ // Cauchy point and the (Gauss-)Newton step.
+ case SUBSPACE_DOGLEG:
+ if (!ComputeSubspaceModel(jacobian)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ break;
+ }
+ ComputeSubspaceDoglegStep(step);
+ break;
+ }
+ }
+
+ return summary;
+}
+
+// The trust region is assumed to be elliptical with the
+// diagonal scaling matrix D defined by sqrt(diagonal_).
+// It is implemented by substituting step' = D * step.
+// The trust region for step' is spherical.
+// The gradient, the Gauss-Newton step, the Cauchy point,
+// and all calculations involving the Jacobian have to
+// be adjusted accordingly.
+void DoglegStrategy::ComputeGradient(
+ SparseMatrix* jacobian,
+ const double* residuals) {
+ gradient_.setZero();
+ jacobian->LeftMultiply(residuals, gradient_.data());
+ gradient_.array() /= diagonal_.array();
+}
+
+// The Cauchy point is the global minimizer of the quadratic model
+// along the one-dimensional subspace spanned by the gradient.
+void DoglegStrategy::ComputeCauchyPoint(SparseMatrix* jacobian) {
+ // alpha * -gradient is the Cauchy point.
+ Vector Jg(jacobian->num_rows());
+ Jg.setZero();
+ // The Jacobian is scaled implicitly by computing J * (D^-1 * (D^-1 * g))
+ // instead of (J * D^-1) * (D^-1 * g).
+ Vector scaled_gradient =
+ (gradient_.array() / diagonal_.array()).matrix();
+ jacobian->RightMultiply(scaled_gradient.data(), Jg.data());
+ alpha_ = gradient_.squaredNorm() / Jg.squaredNorm();
+}
+
+// The dogleg step is defined as the intersection of the trust region
+// boundary with the piecewise linear path from the origin to the Cauchy
+// point and then from there to the Gauss-Newton point (global minimizer
+// of the model function). The Gauss-Newton point is taken if it lies
+// within the trust region.
+void DoglegStrategy::ComputeTraditionalDoglegStep(double* dogleg) {
+ VectorRef dogleg_step(dogleg, gradient_.rows());
+
+ // Case 1. The Gauss-Newton step lies inside the trust region, and
+ // is therefore the optimal solution to the trust-region problem.
+ const double gradient_norm = gradient_.norm();
+ const double gauss_newton_norm = gauss_newton_step_.norm();
+ if (gauss_newton_norm <= radius_) {
+ dogleg_step = gauss_newton_step_;
+ dogleg_step_norm_ = gauss_newton_norm;
+ dogleg_step.array() /= diagonal_.array();
+ VLOG(3) << "GaussNewton step size: " << dogleg_step_norm_
+ << " radius: " << radius_;
+ return;
+ }
+
+ // Case 2. The Cauchy point and the Gauss-Newton steps lie outside
+ // the trust region. Rescale the Cauchy point to the trust region
+ // and return.
+ if (gradient_norm * alpha_ >= radius_) {
+ dogleg_step = -(radius_ / gradient_norm) * gradient_;
+ dogleg_step_norm_ = radius_;
+ dogleg_step.array() /= diagonal_.array();
+ VLOG(3) << "Cauchy step size: " << dogleg_step_norm_
+ << " radius: " << radius_;
+ return;
+ }
+
+ // Case 3. The Cauchy point is inside the trust region and the
+ // Gauss-Newton step is outside. Compute the line joining the two
+ // points and the point on it which intersects the trust region
+ // boundary.
+
+ // a = alpha * -gradient
+ // b = gauss_newton_step
+ const double b_dot_a = -alpha_ * gradient_.dot(gauss_newton_step_);
+ const double a_squared_norm = pow(alpha_ * gradient_norm, 2.0);
+ const double b_minus_a_squared_norm =
+ a_squared_norm - 2 * b_dot_a + pow(gauss_newton_norm, 2);
+
+ // c = a' (b - a)
+ // = alpha * -gradient' gauss_newton_step - alpha^2 |gradient|^2
+ const double c = b_dot_a - a_squared_norm;
+ const double d = sqrt(c * c + b_minus_a_squared_norm *
+ (pow(radius_, 2.0) - a_squared_norm));
+
+ double beta =
+ (c <= 0)
+ ? (d - c) / b_minus_a_squared_norm
+ : (radius_ * radius_ - a_squared_norm) / (d + c);
+ dogleg_step = (-alpha_ * (1.0 - beta)) * gradient_
+ + beta * gauss_newton_step_;
+ dogleg_step_norm_ = dogleg_step.norm();
+ dogleg_step.array() /= diagonal_.array();
+ VLOG(3) << "Dogleg step size: " << dogleg_step_norm_
+ << " radius: " << radius_;
+}
+
+// The subspace method finds the minimum of the two-dimensional problem
+//
+// min. 1/2 x' B' H B x + g' B x
+// s.t. || B x ||^2 <= r^2
+//
+// where r is the trust region radius and B is the matrix with unit columns
+// spanning the subspace defined by the steepest descent and Newton direction.
+// This subspace by definition includes the Gauss-Newton point, which is
+// therefore taken if it lies within the trust region.
+void DoglegStrategy::ComputeSubspaceDoglegStep(double* dogleg) {
+ VectorRef dogleg_step(dogleg, gradient_.rows());
+
+ // The Gauss-Newton point is inside the trust region if |GN| <= radius_.
+ // This test is valid even though radius_ is a length in the two-dimensional
+ // subspace while gauss_newton_step_ is expressed in the (scaled)
+ // higher dimensional original space. This is because
+ //
+ // 1. gauss_newton_step_ by definition lies in the subspace, and
+ // 2. the subspace basis is orthonormal.
+ //
+ // As a consequence, the norm of the gauss_newton_step_ in the subspace is
+ // the same as its norm in the original space.
+ const double gauss_newton_norm = gauss_newton_step_.norm();
+ if (gauss_newton_norm <= radius_) {
+ dogleg_step = gauss_newton_step_;
+ dogleg_step_norm_ = gauss_newton_norm;
+ dogleg_step.array() /= diagonal_.array();
+ VLOG(3) << "GaussNewton step size: " << dogleg_step_norm_
+ << " radius: " << radius_;
+ return;
+ }
+
+ // The optimum lies on the boundary of the trust region. The above problem
+ // therefore becomes
+ //
+ // min. 1/2 x^T B^T H B x + g^T B x
+ // s.t. || B x ||^2 = r^2
+ //
+ // Notice the equality in the constraint.
+ //
+ // This can be solved by forming the Lagrangian, solving for x(y), where
+ // y is the Lagrange multiplier, using the gradient of the objective, and
+ // putting x(y) back into the constraint. This results in a fourth order
+ // polynomial in y, which can be solved using e.g. the companion matrix.
+ // See the description of MakePolynomialForBoundaryConstrainedProblem for
+ // details. The result is up to four real roots y*, not all of which
+ // correspond to feasible points. The feasible points x(y*) have to be
+ // tested for optimality.
+
+ if (subspace_is_one_dimensional_) {
+ // The subspace is one-dimensional, so both the gradient and
+ // the Gauss-Newton step point towards the same direction.
+ // In this case, we move along the gradient until we reach the trust
+ // region boundary.
+ dogleg_step = -(radius_ / gradient_.norm()) * gradient_;
+ dogleg_step_norm_ = radius_;
+ dogleg_step.array() /= diagonal_.array();
+ VLOG(3) << "Dogleg subspace step size (1D): " << dogleg_step_norm_
+ << " radius: " << radius_;
+ return;
+ }
+
+ Vector2d minimum(0.0, 0.0);
+ if (!FindMinimumOnTrustRegionBoundary(&minimum)) {
+ // For the positive semi-definite case, a traditional dogleg step
+ // is taken in this case.
+ LOG(WARNING) << "Failed to compute polynomial roots. "
+ << "Taking traditional dogleg step instead.";
+ ComputeTraditionalDoglegStep(dogleg);
+ return;
+ }
+
+ // Test first order optimality at the minimum.
+ // The first order KKT conditions state that the minimum x*
+ // has to satisfy either || x* ||^2 < r^2 (i.e. has to lie within
+ // the trust region), or
+ //
+ // (B x* + g) + y x* = 0
+ //
+ // for some positive scalar y.
+ // Here, as it is already known that the minimum lies on the boundary, the
+ // latter condition is tested. To allow for small imprecisions, we test if
+ // the angle between (B x* + g) and -x* is smaller than acos(0.99).
+ // The exact value of the cosine is arbitrary but should be close to 1.
+ //
+ // This condition should not be violated. If it is, the minimum was not
+ // correctly determined.
+ const double kCosineThreshold = 0.99;
+ const Vector2d grad_minimum = subspace_B_ * minimum + subspace_g_;
+ const double cosine_angle = -minimum.dot(grad_minimum) /
+ (minimum.norm() * grad_minimum.norm());
+ if (cosine_angle < kCosineThreshold) {
+ LOG(WARNING) << "First order optimality seems to be violated "
+ << "in the subspace method!\n"
+ << "Cosine of angle between x and B x + g is "
+ << cosine_angle << ".\n"
+ << "Taking a regular dogleg step instead.\n"
+ << "Please consider filing a bug report if this "
+ << "happens frequently or consistently.\n";
+ ComputeTraditionalDoglegStep(dogleg);
+ return;
+ }
+
+ // Create the full step from the optimal 2d solution.
+ dogleg_step = subspace_basis_ * minimum;
+ dogleg_step_norm_ = radius_;
+ dogleg_step.array() /= diagonal_.array();
+ VLOG(3) << "Dogleg subspace step size: " << dogleg_step_norm_
+ << " radius: " << radius_;
+}
+
+// Build the polynomial that defines the optimal Lagrange multipliers.
+// Let the Lagrangian be
+//
+// L(x, y) = 0.5 x^T B x + x^T g + y (0.5 x^T x - 0.5 r^2). (1)
+//
+// Stationary points of the Lagrangian are given by
+//
+// 0 = d L(x, y) / dx = Bx + g + y x (2)
+// 0 = d L(x, y) / dy = 0.5 x^T x - 0.5 r^2 (3)
+//
+// For any given y, we can solve (2) for x as
+//
+// x(y) = -(B + y I)^-1 g . (4)
+//
+// As B + y I is 2x2, we form the inverse explicitly:
+//
+// (B + y I)^-1 = (1 / det(B + y I)) adj(B + y I) (5)
+//
+// where adj() denotes adjugation. This should be safe, as B is positive
+// semi-definite and y is necessarily positive, so (B + y I) is indeed
+// invertible.
+// Plugging (5) into (4) and the result into (3), then dividing by 0.5 we
+// obtain
+//
+// 0 = (1 / det(B + y I))^2 g^T adj(B + y I)^T adj(B + y I) g - r^2
+// (6)
+//
+// or
+//
+// det(B + y I)^2 r^2 = g^T adj(B + y I)^T adj(B + y I) g (7a)
+// = g^T adj(B)^T adj(B) g
+// + 2 y g^T adj(B)^T g + y^2 g^T g (7b)
+//
+// as
+//
+// adj(B + y I) = adj(B) + y I = adj(B)^T + y I . (8)
+//
+// The left hand side can be expressed explicitly using
+//
+// det(B + y I) = det(B) + y tr(B) + y^2 . (9)
+//
+// So (7) is a polynomial in y of degree four.
+// Bringing everything back to the left hand side, the coefficients can
+// be read off as
+//
+// y^4 r^2
+// + y^3 2 r^2 tr(B)
+// + y^2 (r^2 tr(B)^2 + 2 r^2 det(B) - g^T g)
+// + y^1 (2 r^2 det(B) tr(B) - 2 g^T adj(B)^T g)
+// + y^0 (r^2 det(B)^2 - g^T adj(B)^T adj(B) g)
+//
+Vector DoglegStrategy::MakePolynomialForBoundaryConstrainedProblem() const {
+ const double detB = subspace_B_.determinant();
+ const double trB = subspace_B_.trace();
+ const double r2 = radius_ * radius_;
+ Matrix2d B_adj;
+ B_adj << subspace_B_(1, 1) , -subspace_B_(0, 1),
+ -subspace_B_(1, 0) , subspace_B_(0, 0);
+
+ Vector polynomial(5);
+ polynomial(0) = r2;
+ polynomial(1) = 2.0 * r2 * trB;
+ polynomial(2) = r2 * (trB * trB + 2.0 * detB) - subspace_g_.squaredNorm();
+ polynomial(3) = -2.0 * (subspace_g_.transpose() * B_adj * subspace_g_
+ - r2 * detB * trB);
+ polynomial(4) = r2 * detB * detB - (B_adj * subspace_g_).squaredNorm();
+
+ return polynomial;
+}
+
+// Given a Lagrange multiplier y that corresponds to a stationary point
+// of the Lagrangian L(x, y), compute the corresponding x from the
+// equation
+//
+// 0 = d L(x, y) / dx
+// = B * x + g + y * x
+// = (B + y * I) * x + g
+//
+DoglegStrategy::Vector2d DoglegStrategy::ComputeSubspaceStepFromRoot(
+ double y) const {
+ const Matrix2d B_i = subspace_B_ + y * Matrix2d::Identity();
+ return -B_i.partialPivLu().solve(subspace_g_);
+}
+
+// This function evaluates the quadratic model at a point x in the
+// subspace spanned by subspace_basis_.
+double DoglegStrategy::EvaluateSubspaceModel(const Vector2d& x) const {
+ return 0.5 * x.dot(subspace_B_ * x) + subspace_g_.dot(x);
+}
+
+// This function attempts to solve the boundary-constrained subspace problem
+//
+// min. 1/2 x^T B^T H B x + g^T B x
+// s.t. || B x ||^2 = r^2
+//
+// where B is an orthonormal subspace basis and r is the trust-region radius.
+//
+// This is done by finding the roots of a fourth degree polynomial. If the
+// root finding fails, the function returns false and minimum will be set
+// to (0, 0). If it succeeds, true is returned.
+//
+// In the failure case, another step should be taken, such as the traditional
+// dogleg step.
+bool DoglegStrategy::FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const {
+ CHECK_NOTNULL(minimum);
+
+ // Return (0, 0) in all error cases.
+ minimum->setZero();
+
+ // Create the fourth-degree polynomial that is a necessary condition for
+ // optimality.
+ const Vector polynomial = MakePolynomialForBoundaryConstrainedProblem();
+
+ // Find the real parts y_i of its roots (not only the real roots).
+ Vector roots_real;
+ if (!FindPolynomialRoots(polynomial, &roots_real, NULL)) {
+ // Failed to find the roots of the polynomial, i.e. the candidate
+ // solutions of the constrained problem. Report this back to the caller.
+ return false;
+ }
+
+ // For each root y, compute B x(y) and check for feasibility.
+ // Notice that there should always be four roots, as the leading term of
+ // the polynomial is r^2 and therefore non-zero. However, as some roots
+ // may be complex, the real parts are not necessarily unique.
+ double minimum_value = std::numeric_limits<double>::max();
+ bool valid_root_found = false;
+ for (int i = 0; i < roots_real.size(); ++i) {
+ const Vector2d x_i = ComputeSubspaceStepFromRoot(roots_real(i));
+
+ // Not all roots correspond to points on the trust region boundary.
+ // There are at most four candidate solutions. As we are interested
+ // in the minimum, it is safe to consider all of them after projecting
+ // them onto the trust region boundary.
+ if (x_i.norm() > 0) {
+ const double f_i = EvaluateSubspaceModel((radius_ / x_i.norm()) * x_i);
+ valid_root_found = true;
+ if (f_i < minimum_value) {
+ minimum_value = f_i;
+ *minimum = x_i;
+ }
+ }
+ }
+
+ return valid_root_found;
+}
+
+LinearSolver::Summary DoglegStrategy::ComputeGaussNewtonStep(
+ const PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals) {
+ const int n = jacobian->num_cols();
+ LinearSolver::Summary linear_solver_summary;
+ linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
+
+ // The Jacobian matrix is often quite poorly conditioned. Thus it is
+ // necessary to add a diagonal matrix at the bottom to prevent the
+ // linear solver from failing.
+ //
+ // We do this by computing the same diagonal matrix as the one used
+ // by Levenberg-Marquardt (other choices are possible), and scaling
+ // it by a small constant (independent of the trust region radius).
+ //
+ // If the solve fails, the multiplier to the diagonal is increased
+ // up to max_mu_ by a factor of mu_increase_factor_ every time. If
+ // the linear solver is still not successful, the strategy returns
+ // with LINEAR_SOLVER_FAILURE.
+ //
+ // Next time when a new Gauss-Newton step is requested, the
+ // multiplier starts out from the last successful solve.
+ //
+ // When a step is declared successful, the multiplier is decreased
+ // by half of mu_increase_factor_.
+
+ while (mu_ < max_mu_) {
+ // Dogleg, as far as I (sameeragarwal) understand it, requires a
+ // reasonably good estimate of the Gauss-Newton step. This means
+ // that we need to solve the normal equations more or less
+ // exactly. This is reflected in the values of the tolerances set
+ // below.
+ //
+ // For now, this strategy should only be used with exact
+ // factorization based solvers, for which these tolerances are
+ // automatically satisfied.
+ //
+ // The right way to combine inexact solves with trust region
+ // methods is to use Stiehaug's method.
+ LinearSolver::PerSolveOptions solve_options;
+ solve_options.q_tolerance = 0.0;
+ solve_options.r_tolerance = 0.0;
+
+ lm_diagonal_ = diagonal_ * std::sqrt(mu_);
+ solve_options.D = lm_diagonal_.data();
+
+ // As in the LevenbergMarquardtStrategy, solve Jy = r instead
+ // of Jx = -r and later set x = -y to avoid having to modify
+ // either jacobian or residuals.
+ InvalidateArray(n, gauss_newton_step_.data());
+ linear_solver_summary = linear_solver_->Solve(jacobian,
+ residuals,
+ solve_options,
+ gauss_newton_step_.data());
+
+ if (per_solve_options.dump_format_type == CONSOLE ||
+ (per_solve_options.dump_format_type != CONSOLE &&
+ !per_solve_options.dump_filename_base.empty())) {
+ if (!DumpLinearLeastSquaresProblem(per_solve_options.dump_filename_base,
+ per_solve_options.dump_format_type,
+ jacobian,
+ solve_options.D,
+ residuals,
+ gauss_newton_step_.data(),
+ 0)) {
+ LOG(ERROR) << "Unable to dump trust region problem."
+ << " Filename base: "
+ << per_solve_options.dump_filename_base;
+ }
+ }
+
+ if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+ return linear_solver_summary;
+ }
+
+ if (linear_solver_summary.termination_type == LINEAR_SOLVER_FAILURE ||
+ !IsArrayValid(n, gauss_newton_step_.data())) {
+ mu_ *= mu_increase_factor_;
+ VLOG(2) << "Increasing mu " << mu_;
+ linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
+ continue;
+ }
+ break;
+ }
+
+ if (linear_solver_summary.termination_type != LINEAR_SOLVER_FAILURE) {
+ // The scaled Gauss-Newton step is D * GN:
+ //
+ // - (D^-1 J^T J D^-1)^-1 (D^-1 g)
+ // = - D (J^T J)^-1 D D^-1 g
+ // = D -(J^T J)^-1 g
+ //
+ gauss_newton_step_.array() *= -diagonal_.array();
+ }
+
+ return linear_solver_summary;
+}
+
+void DoglegStrategy::StepAccepted(double step_quality) {
+ CHECK_GT(step_quality, 0.0);
+
+ if (step_quality < decrease_threshold_) {
+ radius_ *= 0.5;
+ }
+
+ if (step_quality > increase_threshold_) {
+ radius_ = std::max(radius_, 3.0 * dogleg_step_norm_);
+ }
+
+ // Reduce the regularization multiplier, in the hope that whatever
+ // was causing the rank deficiency has gone away and we can return
+ // to doing a pure Gauss-Newton solve.
+ mu_ = std::max(min_mu_, 2.0 * mu_ / mu_increase_factor_);
+ reuse_ = false;
+}
+
+void DoglegStrategy::StepRejected(double step_quality) {
+ radius_ *= 0.5;
+ reuse_ = true;
+}
+
+void DoglegStrategy::StepIsInvalid() {
+ mu_ *= mu_increase_factor_;
+ reuse_ = false;
+}
+
+double DoglegStrategy::Radius() const {
+ return radius_;
+}
+
+bool DoglegStrategy::ComputeSubspaceModel(SparseMatrix* jacobian) {
+ // Compute an orthogonal basis for the subspace using QR decomposition.
+ Matrix basis_vectors(jacobian->num_cols(), 2);
+ basis_vectors.col(0) = gradient_;
+ basis_vectors.col(1) = gauss_newton_step_;
+ Eigen::ColPivHouseholderQR<Matrix> basis_qr(basis_vectors);
+
+ switch (basis_qr.rank()) {
+ case 0:
+ // This should never happen, as it implies that both the gradient
+ // and the Gauss-Newton step are zero. In this case, the minimizer should
+ // have stopped due to the gradient being too small.
+ LOG(ERROR) << "Rank of subspace basis is 0. "
+ << "This means that the gradient at the current iterate is "
+ << "zero but the optimization has not been terminated. "
+ << "You may have found a bug in Ceres.";
+ return false;
+
+ case 1:
+ // Gradient and Gauss-Newton step coincide, so we lie on one of the
+ // major axes of the quadratic problem. In this case, we simply move
+ // along the gradient until we reach the trust region boundary.
+ subspace_is_one_dimensional_ = true;
+ return true;
+
+ case 2:
+ subspace_is_one_dimensional_ = false;
+ break;
+
+ default:
+ LOG(ERROR) << "Rank of the subspace basis matrix is reported to be "
+ << "greater than 2. As the matrix contains only two "
+ << "columns this cannot be true and is indicative of "
+ << "a bug.";
+ return false;
+ }
+
+ // The subspace is two-dimensional, so compute the subspace model.
+ // Given the basis U, this is
+ //
+ // subspace_g_ = g_scaled^T U
+ //
+ // and
+ //
+ // subspace_B_ = U^T (J_scaled^T J_scaled) U
+ //
+ // As J_scaled = J * D^-1, the latter becomes
+ //
+ // subspace_B_ = ((U^T D^-1) J^T) (J (D^-1 U))
+ // = (J (D^-1 U))^T (J (D^-1 U))
+
+ subspace_basis_ =
+ basis_qr.householderQ() * Matrix::Identity(jacobian->num_cols(), 2);
+
+ subspace_g_ = subspace_basis_.transpose() * gradient_;
+
+ Eigen::Matrix<double, 2, Eigen::Dynamic, Eigen::RowMajor>
+ Jb(2, jacobian->num_rows());
+ Jb.setZero();
+
+ Vector tmp;
+ tmp = (subspace_basis_.col(0).array() / diagonal_.array()).matrix();
+ jacobian->RightMultiply(tmp.data(), Jb.row(0).data());
+ tmp = (subspace_basis_.col(1).array() / diagonal_.array()).matrix();
+ jacobian->RightMultiply(tmp.data(), Jb.row(1).data());
+
+ subspace_B_ = Jb * Jb.transpose();
+
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dogleg_strategy.h b/extern/ceres/internal/ceres/dogleg_strategy.h
new file mode 100644
index 00000000000..046b9d824c9
--- /dev/null
+++ b/extern/ceres/internal/ceres/dogleg_strategy.h
@@ -0,0 +1,165 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_DOGLEG_STRATEGY_H_
+#define CERES_INTERNAL_DOGLEG_STRATEGY_H_
+
+#include "ceres/linear_solver.h"
+#include "ceres/trust_region_strategy.h"
+
+namespace ceres {
+namespace internal {
+
+// Dogleg step computation and trust region sizing strategy based on
+// on "Methods for Nonlinear Least Squares" by K. Madsen, H.B. Nielsen
+// and O. Tingleff. Available to download from
+//
+// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
+//
+// One minor modification is that instead of computing the pure
+// Gauss-Newton step, we compute a regularized version of it. This is
+// because the Jacobian is often rank-deficient and in such cases
+// using a direct solver leads to numerical failure.
+//
+// If SUBSPACE is passed as the type argument to the constructor, the
+// DoglegStrategy follows the approach by Shultz, Schnabel, Byrd.
+// This finds the exact optimum over the two-dimensional subspace
+// spanned by the two Dogleg vectors.
+class DoglegStrategy : public TrustRegionStrategy {
+ public:
+ explicit DoglegStrategy(const TrustRegionStrategy::Options& options);
+ virtual ~DoglegStrategy() {}
+
+ // TrustRegionStrategy interface
+ virtual Summary ComputeStep(const PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals,
+ double* step);
+ virtual void StepAccepted(double step_quality);
+ virtual void StepRejected(double step_quality);
+ virtual void StepIsInvalid();
+
+ virtual double Radius() const;
+
+ // These functions are predominantly for testing.
+ Vector gradient() const { return gradient_; }
+ Vector gauss_newton_step() const { return gauss_newton_step_; }
+ Matrix subspace_basis() const { return subspace_basis_; }
+ Vector subspace_g() const { return subspace_g_; }
+ Matrix subspace_B() const { return subspace_B_; }
+
+ private:
+ typedef Eigen::Matrix<double, 2, 1, Eigen::DontAlign> Vector2d;
+ typedef Eigen::Matrix<double, 2, 2, Eigen::DontAlign> Matrix2d;
+
+ LinearSolver::Summary ComputeGaussNewtonStep(
+ const PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals);
+ void ComputeCauchyPoint(SparseMatrix* jacobian);
+ void ComputeGradient(SparseMatrix* jacobian, const double* residuals);
+ void ComputeTraditionalDoglegStep(double* step);
+ bool ComputeSubspaceModel(SparseMatrix* jacobian);
+ void ComputeSubspaceDoglegStep(double* step);
+
+ bool FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const;
+ Vector MakePolynomialForBoundaryConstrainedProblem() const;
+ Vector2d ComputeSubspaceStepFromRoot(double lambda) const;
+ double EvaluateSubspaceModel(const Vector2d& x) const;
+
+ LinearSolver* linear_solver_;
+ double radius_;
+ const double max_radius_;
+
+ const double min_diagonal_;
+ const double max_diagonal_;
+
+ // mu is used to scale the diagonal matrix used to make the
+ // Gauss-Newton solve full rank. In each solve, the strategy starts
+ // out with mu = min_mu, and tries values upto max_mu. If the user
+ // reports an invalid step, the value of mu_ is increased so that
+ // the next solve starts with a stronger regularization.
+ //
+ // If a successful step is reported, then the value of mu_ is
+ // decreased with a lower bound of min_mu_.
+ double mu_;
+ const double min_mu_;
+ const double max_mu_;
+ const double mu_increase_factor_;
+ const double increase_threshold_;
+ const double decrease_threshold_;
+
+ Vector diagonal_; // sqrt(diag(J^T J))
+ Vector lm_diagonal_;
+
+ Vector gradient_;
+ Vector gauss_newton_step_;
+
+ // cauchy_step = alpha * gradient
+ double alpha_;
+ double dogleg_step_norm_;
+
+ // When, ComputeStep is called, reuse_ indicates whether the
+ // Gauss-Newton and Cauchy steps from the last call to ComputeStep
+ // can be reused or not.
+ //
+ // If the user called StepAccepted, then it is expected that the
+ // user has recomputed the Jacobian matrix and new Gauss-Newton
+ // solve is needed and reuse is set to false.
+ //
+ // If the user called StepRejected, then it is expected that the
+ // user wants to solve the trust region problem with the same matrix
+ // but a different trust region radius and the Gauss-Newton and
+ // Cauchy steps can be reused to compute the Dogleg, thus reuse is
+ // set to true.
+ //
+ // If the user called StepIsInvalid, then there was a numerical
+ // problem with the step computed in the last call to ComputeStep,
+ // and the regularization used to do the Gauss-Newton solve is
+ // increased and a new solve should be done when ComputeStep is
+ // called again, thus reuse is set to false.
+ bool reuse_;
+
+ // The dogleg type determines how the minimum of the local
+ // quadratic model is found.
+ DoglegType dogleg_type_;
+
+ // If the type is SUBSPACE_DOGLEG, the two-dimensional
+ // model 1/2 x^T B x + g^T x has to be computed and stored.
+ bool subspace_is_one_dimensional_;
+ Matrix subspace_basis_;
+ Vector2d subspace_g_;
+ Matrix2d subspace_B_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DOGLEG_STRATEGY_H_
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_finalizer.h b/extern/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
new file mode 100644
index 00000000000..a25a3083120
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
@@ -0,0 +1,51 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: richie.stebbing@gmail.com (Richard Stebbing)
+
+#ifndef CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALIZER_H_
+#define CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALIZER_H_
+
+#include "ceres/casts.h"
+#include "ceres/dynamic_compressed_row_sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+struct DynamicCompressedRowJacobianFinalizer {
+ void operator()(SparseMatrix* base_jacobian, int num_parameters) {
+ DynamicCompressedRowSparseMatrix* jacobian =
+ down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
+ jacobian->Finalize(num_parameters);
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALISER_H_
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc b/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
new file mode 100644
index 00000000000..fd5d89e350a
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
@@ -0,0 +1,117 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: richie.stebbing@gmail.com (Richard Stebbing)
+
+#include "ceres/compressed_row_jacobian_writer.h"
+#include "ceres/dynamic_compressed_row_jacobian_writer.h"
+#include "ceres/casts.h"
+#include "ceres/dynamic_compressed_row_sparse_matrix.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+
+namespace ceres {
+namespace internal {
+
+using std::pair;
+using std::vector;
+
+ScratchEvaluatePreparer*
+DynamicCompressedRowJacobianWriter::CreateEvaluatePreparers(int num_threads) {
+ return ScratchEvaluatePreparer::Create(*program_, num_threads);
+}
+
+SparseMatrix* DynamicCompressedRowJacobianWriter::CreateJacobian() const {
+ // Initialize `jacobian` with zero number of `max_num_nonzeros`.
+ const int num_residuals = program_->NumResiduals();
+ const int num_effective_parameters = program_->NumEffectiveParameters();
+
+ DynamicCompressedRowSparseMatrix* jacobian =
+ new DynamicCompressedRowSparseMatrix(num_residuals,
+ num_effective_parameters,
+ 0);
+
+ vector<int>* row_blocks = jacobian->mutable_row_blocks();
+ for (int i = 0; i < jacobian->num_rows(); ++i) {
+ row_blocks->push_back(1);
+ }
+
+ vector<int>* col_blocks = jacobian->mutable_col_blocks();
+ for (int i = 0; i < jacobian->num_cols(); ++i) {
+ col_blocks->push_back(1);
+ }
+
+ return jacobian;
+}
+
+void DynamicCompressedRowJacobianWriter::Write(int residual_id,
+ int residual_offset,
+ double **jacobians,
+ SparseMatrix* base_jacobian) {
+ DynamicCompressedRowSparseMatrix* jacobian =
+ down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
+
+ // Get the `residual_block` of interest.
+ const ResidualBlock* residual_block =
+ program_->residual_blocks()[residual_id];
+ const int num_residuals = residual_block->NumResiduals();
+
+ vector<pair<int, int> > evaluated_jacobian_blocks;
+ CompressedRowJacobianWriter::GetOrderedParameterBlocks(
+ program_, residual_id, &evaluated_jacobian_blocks);
+
+ // `residual_offset` is the residual row in the global jacobian.
+ // Empty the jacobian rows.
+ jacobian->ClearRows(residual_offset, num_residuals);
+
+ // Iterate over each parameter block.
+ for (int i = 0; i < evaluated_jacobian_blocks.size(); ++i) {
+ const ParameterBlock* parameter_block =
+ program_->parameter_blocks()[evaluated_jacobian_blocks[i].first];
+ const int parameter_block_jacobian_index =
+ evaluated_jacobian_blocks[i].second;
+ const int parameter_block_size = parameter_block->LocalSize();
+
+ // For each parameter block only insert its non-zero entries.
+ for (int r = 0; r < num_residuals; ++r) {
+ for (int c = 0; c < parameter_block_size; ++c) {
+ const double& v = jacobians[parameter_block_jacobian_index][
+ r * parameter_block_size + c];
+ // Only insert non-zero entries.
+ if (v != 0.0) {
+ jacobian->InsertEntry(
+ residual_offset + r, parameter_block->delta_offset() + c, v);
+ }
+ }
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h b/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
new file mode 100644
index 00000000000..6e5ac38f07e
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
@@ -0,0 +1,83 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: richie.stebbing@gmail.com (Richard Stebbing)
+//
+// A jacobian writer that directly writes to dynamic compressed row sparse
+// matrices.
+
+#ifndef CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
+#define CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
+
+#include "ceres/evaluator.h"
+#include "ceres/scratch_evaluate_preparer.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+class SparseMatrix;
+
+class DynamicCompressedRowJacobianWriter {
+ public:
+ DynamicCompressedRowJacobianWriter(Evaluator::Options /* ignored */,
+ Program* program)
+ : program_(program) {
+ }
+
+ // JacobianWriter interface.
+
+ // The compressed row matrix has different layout than that assumed by
+ // the cost functions. The scratch space is therefore used to store
+ // the jacobians (including zeros) temporarily before only the non-zero
+ // entries are copied over to the larger jacobian in `Write`.
+ ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads);
+
+ // Return a `DynamicCompressedRowSparseMatrix` which is filled by
+ // `Write`. Note that `Finalize` must be called to make the
+ // `CompressedRowSparseMatrix` interface valid.
+ SparseMatrix* CreateJacobian() const;
+
+ // Write only the non-zero jacobian entries for a residual block
+ // (specified by `residual_id`) into `base_jacobian`, starting at the row
+ // specifed by `residual_offset`.
+ //
+ // This method is thread-safe over residual blocks (each `residual_id`).
+ void Write(int residual_id,
+ int residual_offset,
+ double **jacobians,
+ SparseMatrix* base_jacobian);
+
+ private:
+ Program* program_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc b/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
new file mode 100644
index 00000000000..f020768ce10
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
@@ -0,0 +1,107 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: richie.stebbing@gmail.com (Richard Stebbing)
+
+#include <cstring>
+#include "ceres/dynamic_compressed_row_sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+DynamicCompressedRowSparseMatrix::DynamicCompressedRowSparseMatrix(
+ int num_rows,
+ int num_cols,
+ int initial_max_num_nonzeros)
+ : CompressedRowSparseMatrix(num_rows,
+ num_cols,
+ initial_max_num_nonzeros) {
+ dynamic_cols_.resize(num_rows);
+ dynamic_values_.resize(num_rows);
+ }
+
+void DynamicCompressedRowSparseMatrix::InsertEntry(int row,
+ int col,
+ const double& value) {
+ CHECK_GE(row, 0);
+ CHECK_LT(row, num_rows());
+ CHECK_GE(col, 0);
+ CHECK_LT(col, num_cols());
+ dynamic_cols_[row].push_back(col);
+ dynamic_values_[row].push_back(value);
+}
+
+void DynamicCompressedRowSparseMatrix::ClearRows(int row_start,
+ int num_rows) {
+ for (int r = 0; r < num_rows; ++r) {
+ const int i = row_start + r;
+ CHECK_GE(i, 0);
+ CHECK_LT(i, this->num_rows());
+ dynamic_cols_[i].resize(0);
+ dynamic_values_[i].resize(0);
+ }
+}
+
+void DynamicCompressedRowSparseMatrix::Finalize(int num_additional_elements) {
+ // `num_additional_elements` is provided as an argument so that additional
+ // storage can be reserved when it is known by the finalizer.
+ CHECK_GE(num_additional_elements, 0);
+
+ // Count the number of non-zeros and resize `cols_` and `values_`.
+ int num_jacobian_nonzeros = 0;
+ for (int i = 0; i < dynamic_cols_.size(); ++i) {
+ num_jacobian_nonzeros += dynamic_cols_[i].size();
+ }
+
+ SetMaxNumNonZeros(num_jacobian_nonzeros + num_additional_elements);
+
+ // Flatten `dynamic_cols_` into `cols_` and `dynamic_values_`
+ // into `values_`.
+ int index_into_values_and_cols = 0;
+ for (int i = 0; i < num_rows(); ++i) {
+ mutable_rows()[i] = index_into_values_and_cols;
+ const int num_nonzero_columns = dynamic_cols_[i].size();
+ if (num_nonzero_columns > 0) {
+ memcpy(mutable_cols() + index_into_values_and_cols,
+ &dynamic_cols_[i][0],
+ dynamic_cols_[i].size() * sizeof(dynamic_cols_[0][0]));
+ memcpy(mutable_values() + index_into_values_and_cols,
+ &dynamic_values_[i][0],
+ dynamic_values_[i].size() * sizeof(dynamic_values_[0][0]));
+ index_into_values_and_cols += dynamic_cols_[i].size();
+ }
+ }
+ mutable_rows()[num_rows()] = index_into_values_and_cols;
+
+ CHECK_EQ(index_into_values_and_cols, num_jacobian_nonzeros)
+ << "Ceres bug: final index into values_ and cols_ should be equal to "
+ << "the number of jacobian nonzeros. Please contact the developers!";
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h b/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
new file mode 100644
index 00000000000..cab860bddbd
--- /dev/null
+++ b/extern/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
@@ -0,0 +1,101 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: richie.stebbing@gmail.com (Richard Stebbing)
+//
+// A compressed row sparse matrix that provides an extended interface to
+// allow dynamic insertion of entries. This is provided for the use case
+// where the sparsity structure and number of non-zero entries is dynamic.
+// This flexibility is achieved by using an (internal) scratch space that
+// allows independent insertion of entries into each row (thread-safe).
+// Once insertion is complete, the `Finalize` method must be called to ensure
+// that the underlying `CompressedRowSparseMatrix` is consistent.
+//
+// This should only be used if you really do need a dynamic sparsity pattern.
+
+#ifndef CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
+
+#include <vector>
+
+#include "ceres/compressed_row_sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+class DynamicCompressedRowSparseMatrix : public CompressedRowSparseMatrix {
+ public:
+ // Set the number of rows and columns for the underlyig
+ // `CompressedRowSparseMatrix` and set the initial number of maximum non-zero
+ // entries. Note that following the insertion of entries, when `Finalize`
+ // is called the number of non-zeros is determined and all internal
+ // structures are adjusted as required. If you know the upper limit on the
+ // number of non-zeros, then passing this value here can prevent future
+ // memory reallocations which may improve performance. Otherwise, if no
+ // upper limit is available a value of 0 is sufficient.
+ //
+ // Typical usage of this class is to define a new instance with a given
+ // number of rows, columns and maximum number of non-zero elements
+ // (if available). Next, entries are inserted at row and column positions
+ // using `InsertEntry`. Finally, once all elements have been inserted,
+ // `Finalize` must be called to make the underlying
+ // `CompressedRowSparseMatrix` consistent.
+ DynamicCompressedRowSparseMatrix(int num_rows,
+ int num_cols,
+ int initial_max_num_nonzeros);
+
+ // Insert an entry at a given row and column position. This method is
+ // thread-safe across rows i.e. different threads can insert values
+ // simultaneously into different rows. It should be emphasised that this
+ // method always inserts a new entry and does not check for existing
+ // entries at the specified row and column position. Duplicate entries
+ // for a given row and column position will result in undefined
+ // behavior.
+ void InsertEntry(int row, int col, const double& value);
+
+ // Clear all entries for rows, starting from row index `row_start`
+ // and proceeding for `num_rows`.
+ void ClearRows(int row_start, int num_rows);
+
+ // Make the underlying internal `CompressedRowSparseMatrix` data structures
+ // consistent. Additional space for non-zero entries in the
+ // `CompressedRowSparseMatrix` can be reserved by specifying
+ // `num_additional_elements`. This is useful when it is known that rows will
+ // be appended to the `CompressedRowSparseMatrix` (e.g. appending a diagonal
+ // matrix to the jacobian) as it prevents need for future reallocation.
+ void Finalize(int num_additional_elements);
+
+ private:
+ std::vector<std::vector<int> > dynamic_cols_;
+ std::vector<std::vector<double> > dynamic_values_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/evaluator.cc b/extern/ceres/internal/ceres/evaluator.cc
new file mode 100644
index 00000000000..baba9afa11b
--- /dev/null
+++ b/extern/ceres/internal/ceres/evaluator.cc
@@ -0,0 +1,86 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include <vector>
+#include "ceres/block_evaluate_preparer.h"
+#include "ceres/block_jacobian_writer.h"
+#include "ceres/compressed_row_jacobian_writer.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/crs_matrix.h"
+#include "ceres/dense_jacobian_writer.h"
+#include "ceres/dynamic_compressed_row_finalizer.h"
+#include "ceres/dynamic_compressed_row_jacobian_writer.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/port.h"
+#include "ceres/program_evaluator.h"
+#include "ceres/scratch_evaluate_preparer.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Evaluator::~Evaluator() {}
+
+Evaluator* Evaluator::Create(const Evaluator::Options& options,
+ Program* program,
+ std::string* error) {
+ switch (options.linear_solver_type) {
+ case DENSE_QR:
+ case DENSE_NORMAL_CHOLESKY:
+ return new ProgramEvaluator<ScratchEvaluatePreparer,
+ DenseJacobianWriter>(options,
+ program);
+ case DENSE_SCHUR:
+ case SPARSE_SCHUR:
+ case ITERATIVE_SCHUR:
+ case CGNR:
+ return new ProgramEvaluator<BlockEvaluatePreparer,
+ BlockJacobianWriter>(options,
+ program);
+ case SPARSE_NORMAL_CHOLESKY:
+ if (options.dynamic_sparsity) {
+ return new ProgramEvaluator<ScratchEvaluatePreparer,
+ DynamicCompressedRowJacobianWriter,
+ DynamicCompressedRowJacobianFinalizer>(
+ options, program);
+ } else {
+ return new ProgramEvaluator<ScratchEvaluatePreparer,
+ CompressedRowJacobianWriter>(options,
+ program);
+ }
+
+ default:
+ *error = "Invalid Linear Solver Type. Unable to create evaluator.";
+ return NULL;
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/evaluator.h b/extern/ceres/internal/ceres/evaluator.h
new file mode 100644
index 00000000000..fea307919d0
--- /dev/null
+++ b/extern/ceres/internal/ceres/evaluator.h
@@ -0,0 +1,205 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_EVALUATOR_H_
+#define CERES_INTERNAL_EVALUATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "ceres/execution_summary.h"
+#include "ceres/internal/port.h"
+#include "ceres/types.h"
+
+namespace ceres {
+
+struct CRSMatrix;
+
+namespace internal {
+
+class Program;
+class SparseMatrix;
+
+// The Evaluator interface offers a way to interact with a least squares cost
+// function that is useful for an optimizer that wants to minimize the least
+// squares objective. This insulates the optimizer from issues like Jacobian
+// storage, parameterization, etc.
+class Evaluator {
+ public:
+ virtual ~Evaluator();
+
+ struct Options {
+ Options()
+ : num_threads(1),
+ num_eliminate_blocks(-1),
+ linear_solver_type(DENSE_QR),
+ dynamic_sparsity(false) {}
+
+ int num_threads;
+ int num_eliminate_blocks;
+ LinearSolverType linear_solver_type;
+ bool dynamic_sparsity;
+ };
+
+ static Evaluator* Create(const Options& options,
+ Program* program,
+ std::string* error);
+
+ // This is used for computing the cost, residual and Jacobian for
+ // returning to the user. For actually solving the optimization
+ // problem, the optimization algorithm uses the ProgramEvaluator
+ // objects directly.
+ //
+ // The residual, gradients and jacobian pointers can be NULL, in
+ // which case they will not be evaluated. cost cannot be NULL.
+ //
+ // The parallelism of the evaluator is controlled by num_threads; it
+ // should be at least 1.
+ //
+ // Note: That this function does not take a parameter vector as
+ // input. The parameter blocks are evaluated on the values contained
+ // in the arrays pointed to by their user_state pointers.
+ //
+ // Also worth noting is that this function mutates program by
+ // calling Program::SetParameterOffsetsAndIndex() on it so that an
+ // evaluator object can be constructed.
+ static bool Evaluate(Program* program,
+ int num_threads,
+ double* cost,
+ std::vector<double>* residuals,
+ std::vector<double>* gradient,
+ CRSMatrix* jacobian);
+
+ // Build and return a sparse matrix for storing and working with the Jacobian
+ // of the objective function. The jacobian has dimensions
+ // NumEffectiveParameters() by NumParameters(), and is typically extremely
+ // sparse. Since the sparsity pattern of the Jacobian remains constant over
+ // the lifetime of the optimization problem, this method is used to
+ // instantiate a SparseMatrix object with the appropriate sparsity structure
+ // (which can be an expensive operation) and then reused by the optimization
+ // algorithm and the various linear solvers.
+ //
+ // It is expected that the classes implementing this interface will be aware
+ // of their client's requirements for the kind of sparse matrix storage and
+ // layout that is needed for an efficient implementation. For example
+ // CompressedRowOptimizationProblem creates a compressed row representation of
+ // the jacobian for use with CHOLMOD, where as BlockOptimizationProblem
+ // creates a BlockSparseMatrix representation of the jacobian for use in the
+ // Schur complement based methods.
+ virtual SparseMatrix* CreateJacobian() const = 0;
+
+
+ // Options struct to control Evaluator::Evaluate;
+ struct EvaluateOptions {
+ EvaluateOptions()
+ : apply_loss_function(true) {
+ }
+
+ // If false, the loss function correction is not applied to the
+ // residual blocks.
+ bool apply_loss_function;
+ };
+
+ // Evaluate the cost function for the given state. Returns the cost,
+ // residuals, and jacobian in the corresponding arguments. Both residuals and
+ // jacobian are optional; to avoid computing them, pass NULL.
+ //
+ // If non-NULL, the Jacobian must have a suitable sparsity pattern; only the
+ // values array of the jacobian is modified.
+ //
+ // state is an array of size NumParameters(), cost is a pointer to a single
+ // double, and residuals is an array of doubles of size NumResiduals().
+ virtual bool Evaluate(const EvaluateOptions& evaluate_options,
+ const double* state,
+ double* cost,
+ double* residuals,
+ double* gradient,
+ SparseMatrix* jacobian) = 0;
+
+ // Variant of Evaluator::Evaluate where the user wishes to use the
+ // default EvaluateOptions struct. This is mostly here as a
+ // convenience method.
+ bool Evaluate(const double* state,
+ double* cost,
+ double* residuals,
+ double* gradient,
+ SparseMatrix* jacobian) {
+ return Evaluate(EvaluateOptions(),
+ state,
+ cost,
+ residuals,
+ gradient,
+ jacobian);
+ }
+
+ // Make a change delta (of size NumEffectiveParameters()) to state (of size
+ // NumParameters()) and store the result in state_plus_delta.
+ //
+ // In the case that there are no parameterizations used, this is equivalent to
+ //
+ // state_plus_delta[i] = state[i] + delta[i] ;
+ //
+ // however, the mapping is more complicated in the case of parameterizations
+ // like quaternions. This is the same as the "Plus()" operation in
+ // local_parameterization.h, but operating over the entire state vector for a
+ // problem.
+ virtual bool Plus(const double* state,
+ const double* delta,
+ double* state_plus_delta) const = 0;
+
+ // The number of parameters in the optimization problem.
+ virtual int NumParameters() const = 0;
+
+ // This is the effective number of parameters that the optimizer may adjust.
+ // This applies when there are parameterizations on some of the parameters.
+ virtual int NumEffectiveParameters() const = 0;
+
+ // The number of residuals in the optimization problem.
+ virtual int NumResiduals() const = 0;
+
+ // The following two methods return copies instead of references so
+ // that the base class implementation does not have to worry about
+ // life time issues. Further, these calls are not expected to be
+ // frequent or performance sensitive.
+ virtual std::map<std::string, int> CallStatistics() const {
+ return std::map<std::string, int>();
+ }
+
+ virtual std::map<std::string, double> TimeStatistics() const {
+ return std::map<std::string, double>();
+ }
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_EVALUATOR_H_
diff --git a/extern/ceres/internal/ceres/execution_summary.h b/extern/ceres/internal/ceres/execution_summary.h
new file mode 100644
index 00000000000..aa9929d8974
--- /dev/null
+++ b/extern/ceres/internal/ceres/execution_summary.h
@@ -0,0 +1,90 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_EXECUTION_SUMMARY_H_
+#define CERES_INTERNAL_EXECUTION_SUMMARY_H_
+
+#include <map>
+#include <string>
+
+#include "ceres/internal/port.h"
+#include "ceres/wall_time.h"
+#include "ceres/mutex.h"
+
+namespace ceres {
+namespace internal {
+
+// Struct used by various objects to report statistics and other
+// information about their execution. e.g., ExecutionSummary::times
+// can be used for reporting times associated with various activities.
+class ExecutionSummary {
+ public:
+ void IncrementTimeBy(const std::string& name, const double value) {
+ CeresMutexLock l(&times_mutex_);
+ times_[name] += value;
+ }
+
+ void IncrementCall(const std::string& name) {
+ CeresMutexLock l(&calls_mutex_);
+ calls_[name] += 1;
+ }
+
+ const std::map<std::string, double>& times() const { return times_; }
+ const std::map<std::string, int>& calls() const { return calls_; }
+
+ private:
+ Mutex times_mutex_;
+ std::map<std::string, double> times_;
+
+ Mutex calls_mutex_;
+ std::map<std::string, int> calls_;
+};
+
+class ScopedExecutionTimer {
+ public:
+ ScopedExecutionTimer(const std::string& name, ExecutionSummary* summary)
+ : start_time_(WallTimeInSeconds()),
+ name_(name),
+ summary_(summary) {}
+
+ ~ScopedExecutionTimer() {
+ summary_->IncrementTimeBy(name_, WallTimeInSeconds() - start_time_);
+ }
+
+ private:
+ const double start_time_;
+ const std::string name_;
+ ExecutionSummary* summary_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_EXECUTION_SUMMARY_H_
diff --git a/extern/ceres/internal/ceres/file.cc b/extern/ceres/internal/ceres/file.cc
new file mode 100644
index 00000000000..c95a44d2c38
--- /dev/null
+++ b/extern/ceres/internal/ceres/file.cc
@@ -0,0 +1,95 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Really simple file IO.
+
+#include "ceres/file.h"
+
+#include <cstdio>
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+
+void WriteStringToFileOrDie(const string &data, const string &filename) {
+ FILE* file_descriptor = fopen(filename.c_str(), "wb");
+ if (!file_descriptor) {
+ LOG(FATAL) << "Couldn't write to file: " << filename;
+ }
+ fwrite(data.c_str(), 1, data.size(), file_descriptor);
+ fclose(file_descriptor);
+}
+
+void ReadFileToStringOrDie(const string &filename, string *data) {
+ FILE* file_descriptor = fopen(filename.c_str(), "r");
+
+ if (!file_descriptor) {
+ LOG(FATAL) << "Couldn't read file: " << filename;
+ }
+
+ // Resize the input buffer appropriately.
+ fseek(file_descriptor, 0L, SEEK_END);
+ int num_bytes = ftell(file_descriptor);
+ data->resize(num_bytes);
+
+ // Read the data.
+ fseek(file_descriptor, 0L, SEEK_SET);
+ int num_read = fread(&((*data)[0]),
+ sizeof((*data)[0]),
+ num_bytes,
+ file_descriptor);
+ if (num_read != num_bytes) {
+ LOG(FATAL) << "Couldn't read all of " << filename
+ << "expected bytes: " << num_bytes * sizeof((*data)[0])
+ << "actual bytes: " << num_read;
+ }
+ fclose(file_descriptor);
+}
+
+string JoinPath(const string& dirname, const string& basename) {
+#ifdef _WIN32
+ static const char separator = '\\';
+#else
+ static const char separator = '/';
+#endif // _WIN32
+
+ if ((!basename.empty() && basename[0] == separator) || dirname.empty()) {
+ return basename;
+ } else if (dirname[dirname.size() - 1] == separator) {
+ return dirname + basename;
+ } else {
+ return dirname + string(&separator, 1) + basename;
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/file.h b/extern/ceres/internal/ceres/file.h
new file mode 100644
index 00000000000..219b459b919
--- /dev/null
+++ b/extern/ceres/internal/ceres/file.h
@@ -0,0 +1,53 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Simple file IO support. This is a portability shim.
+
+#ifndef CERES_INTERNAL_FILE_H_
+#define CERES_INTERNAL_FILE_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+void WriteStringToFileOrDie(const std::string &data,
+ const std::string &filename);
+void ReadFileToStringOrDie(const std::string &filename, std::string *data);
+
+// Join two path components, adding a slash if necessary. If basename is an
+// absolute path then JoinPath ignores dirname and simply returns basename.
+std::string JoinPath(const std::string& dirname, const std::string& basename);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_FILE_H_
diff --git a/extern/ceres/internal/ceres/generate_eliminator_specialization.py b/extern/ceres/internal/ceres/generate_eliminator_specialization.py
new file mode 100644
index 00000000000..e89e7a48c98
--- /dev/null
+++ b/extern/ceres/internal/ceres/generate_eliminator_specialization.py
@@ -0,0 +1,231 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2015 Google Inc. All rights reserved.
+# http://ceres-solver.org/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: sameeragarwal@google.com (Sameer Agarwal)
+#
+# Script for explicitly generating template specialization of the
+# SchurEliminator class. It is a rather large class
+# and the number of explicit instantiations is also large. Explicitly
+# generating these instantiations in separate .cc files breaks the
+# compilation into separate compilation unit rather than one large cc
+# file which takes 2+GB of RAM to compile.
+#
+# This script creates two sets of files.
+#
+# 1. schur_eliminator_x_x_x.cc
+# where, the x indicates the template parameters and
+#
+# 2. schur_eliminator.cc
+#
+# that contains a factory function for instantiating these classes
+# based on runtime parameters.
+#
+# The list of tuples, specializations indicates the set of
+# specializations that is generated.
+
+# Set of template specializations to generate
+SPECIALIZATIONS = [(2, 2, 2),
+ (2, 2, 3),
+ (2, 2, 4),
+ (2, 2, "Eigen::Dynamic"),
+ (2, 3, 3),
+ (2, 3, 4),
+ (2, 3, 6),
+ (2, 3, 9),
+ (2, 3, "Eigen::Dynamic"),
+ (2, 4, 3),
+ (2, 4, 4),
+ (2, 4, 8),
+ (2, 4, 9),
+ (2, 4, "Eigen::Dynamic"),
+ (2, "Eigen::Dynamic", "Eigen::Dynamic"),
+ (4, 4, 2),
+ (4, 4, 3),
+ (4, 4, 4),
+ (4, 4, "Eigen::Dynamic"),
+ ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
+HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+"""
+
+DYNAMIC_FILE = """
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<%s, %s, %s>;
+
+} // namespace internal
+} // namespace ceres
+"""
+
+SPECIALIZATION_FILE = """
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<%s, %s, %s>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+FACTORY_FILE_HEADER = """
+#include "ceres/linear_solver.h"
+#include "ceres/schur_eliminator.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+SchurEliminatorBase*
+SchurEliminatorBase::Create(const LinearSolver::Options& options) {
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) &&
+ (options.e_block_size == %s) &&
+ (options.f_block_size == %s)) {
+ return new SchurEliminator<%s, %s, %s>(options);
+ }
+"""
+
+FACTORY_FOOTER = """
+#endif
+ VLOG(1) << "Template specializations not found for <"
+ << options.row_block_size << ","
+ << options.e_block_size << ","
+ << options.f_block_size << ">";
+ return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
+}
+
+} // namespace internal
+} // namespace ceres
+"""
+
+
+def SuffixForSize(size):
+ if size == "Eigen::Dynamic":
+ return "d"
+ return str(size)
+
+
+def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
+ return "_".join([prefix] + map(SuffixForSize, (row_block_size,
+ e_block_size,
+ f_block_size)))
+
+
+def Specialize():
+ """
+ Generate specialization code and the conditionals to instantiate it.
+ """
+ f = open("schur_eliminator.cc", "w")
+ f.write(HEADER)
+ f.write(FACTORY_FILE_HEADER)
+
+ for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
+ output = SpecializationFilename("generated/schur_eliminator",
+ row_block_size,
+ e_block_size,
+ f_block_size) + ".cc"
+ fptr = open(output, "w")
+ fptr.write(HEADER)
+
+ template = SPECIALIZATION_FILE
+ if (row_block_size == "Eigen::Dynamic" and
+ e_block_size == "Eigen::Dynamic" and
+ f_block_size == "Eigen::Dynamic"):
+ template = DYNAMIC_FILE
+
+ fptr.write(template % (row_block_size, e_block_size, f_block_size))
+ fptr.close()
+
+ f.write(FACTORY_CONDITIONAL % (row_block_size,
+ e_block_size,
+ f_block_size,
+ row_block_size,
+ e_block_size,
+ f_block_size))
+ f.write(FACTORY_FOOTER)
+ f.close()
+
+
+if __name__ == "__main__":
+ Specialize()
diff --git a/extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py b/extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py
new file mode 100644
index 00000000000..c4ac3cf2332
--- /dev/null
+++ b/extern/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py
@@ -0,0 +1,232 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2015 Google Inc. All rights reserved.
+# http://ceres-solver.org/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: sameeragarwal@google.com (Sameer Agarwal)
+#
+# Script for explicitly generating template specialization of the
+# PartitionedMatrixView class. Explicitly generating these
+# instantiations in separate .cc files breaks the compilation into
+# separate compilation unit rather than one large cc file.
+#
+# This script creates two sets of files.
+#
+# 1. partitioned_matrix_view_x_x_x.cc
+# where the x indicates the template parameters and
+#
+# 2. partitioned_matrix_view.cc
+#
+# that contains a factory function for instantiating these classes
+# based on runtime parameters.
+#
+# The list of tuples, specializations indicates the set of
+# specializations that is generated.
+
+# Set of template specializations to generate
+SPECIALIZATIONS = [(2, 2, 2),
+ (2, 2, 3),
+ (2, 2, 4),
+ (2, 2, "Eigen::Dynamic"),
+ (2, 3, 3),
+ (2, 3, 4),
+ (2, 3, 6),
+ (2, 3, 9),
+ (2, 3, "Eigen::Dynamic"),
+ (2, 4, 3),
+ (2, 4, 4),
+ (2, 4, 8),
+ (2, 4, 9),
+ (2, 4, "Eigen::Dynamic"),
+ (2, "Eigen::Dynamic", "Eigen::Dynamic"),
+ (4, 4, 2),
+ (4, 4, 3),
+ (4, 4, 4),
+ (4, 4, "Eigen::Dynamic"),
+ ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
+HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+"""
+
+DYNAMIC_FILE = """
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<%s, %s, %s>;
+
+} // namespace internal
+} // namespace ceres
+"""
+
+SPECIALIZATION_FILE = """
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<%s, %s, %s>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+FACTORY_FILE_HEADER = """
+#include "ceres/linear_solver.h"
+#include "ceres/partitioned_matrix_view.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+PartitionedMatrixViewBase*
+PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
+ const BlockSparseMatrix& matrix) {
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+"""
+
+FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) &&
+ (options.e_block_size == %s) &&
+ (options.f_block_size == %s)) {
+ return new PartitionedMatrixView<%s, %s, %s>(
+ matrix, options.elimination_groups[0]);
+ }
+"""
+
+FACTORY_FOOTER = """
+#endif
+ VLOG(1) << "Template specializations not found for <"
+ << options.row_block_size << ","
+ << options.e_block_size << ","
+ << options.f_block_size << ">";
+ return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+};
+
+} // namespace internal
+} // namespace ceres
+"""
+
+
+def SuffixForSize(size):
+ if size == "Eigen::Dynamic":
+ return "d"
+ return str(size)
+
+
+def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
+ return "_".join([prefix] + map(SuffixForSize, (row_block_size,
+ e_block_size,
+ f_block_size)))
+
+
+def Specialize():
+ """
+ Generate specialization code and the conditionals to instantiate it.
+ """
+ f = open("partitioned_matrix_view.cc", "w")
+ f.write(HEADER)
+ f.write(FACTORY_FILE_HEADER)
+
+ for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
+ output = SpecializationFilename("generated/partitioned_matrix_view",
+ row_block_size,
+ e_block_size,
+ f_block_size) + ".cc"
+ fptr = open(output, "w")
+ fptr.write(HEADER)
+
+ template = SPECIALIZATION_FILE
+ if (row_block_size == "Eigen::Dynamic" and
+ e_block_size == "Eigen::Dynamic" and
+ f_block_size == "Eigen::Dynamic"):
+ template = DYNAMIC_FILE
+
+ fptr.write(template % (row_block_size, e_block_size, f_block_size))
+ fptr.close()
+
+ f.write(FACTORY_CONDITIONAL % (row_block_size,
+ e_block_size,
+ f_block_size,
+ row_block_size,
+ e_block_size,
+ f_block_size))
+ f.write(FACTORY_FOOTER)
+ f.close()
+
+
+if __name__ == "__main__":
+ Specialize()
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
new file mode 100644
index 00000000000..500115b9897
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, 2>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
new file mode 100644
index 00000000000..1384cb619e3
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
new file mode 100644
index 00000000000..030035ec97b
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
new file mode 100644
index 00000000000..c9501b50170
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 2, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
new file mode 100644
index 00000000000..c2639bff69e
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
new file mode 100644
index 00000000000..693e43959c1
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
new file mode 100644
index 00000000000..7b9368ffefd
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 6>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
new file mode 100644
index 00000000000..e72c5f6937a
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, 9>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
new file mode 100644
index 00000000000..c1f410eb64c
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 3, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
new file mode 100644
index 00000000000..7292c333d5d
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
new file mode 100644
index 00000000000..891d65a8646
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
new file mode 100644
index 00000000000..395f6bd4c13
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 8>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
new file mode 100644
index 00000000000..88952b10e34
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, 9>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
new file mode 100644
index 00000000000..7733e1993eb
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, 4, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
new file mode 100644
index 00000000000..117a0cdb8c1
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
new file mode 100644
index 00000000000..a620bb70dba
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, 2>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
new file mode 100644
index 00000000000..2978630832c
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
new file mode 100644
index 00000000000..bcd03b02e3a
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
new file mode 100644
index 00000000000..6b541ecf0d9
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<4, 4, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
new file mode 100644
index 00000000000..85111e722c4
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
@@ -0,0 +1,53 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+
+#include "ceres/partitioned_matrix_view_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
new file mode 100644
index 00000000000..ac07a3f229e
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 2, 2>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
new file mode 100644
index 00000000000..0ec09553f9e
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 2, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
new file mode 100644
index 00000000000..74a42cc4a16
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 2, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
new file mode 100644
index 00000000000..5ce757fda5d
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 2, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
new file mode 100644
index 00000000000..2e7ae28b4ea
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 3, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
new file mode 100644
index 00000000000..443207070cf
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 3, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
new file mode 100644
index 00000000000..ac2f358b383
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 3, 6>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
new file mode 100644
index 00000000000..930ab440fa5
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 3, 9>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
new file mode 100644
index 00000000000..486c53d36f4
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 3, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
new file mode 100644
index 00000000000..6f247a7b832
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 4, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
new file mode 100644
index 00000000000..c44cd045263
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 4, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
new file mode 100644
index 00000000000..c9a0d5fc729
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 4, 8>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
new file mode 100644
index 00000000000..b0455b0bca0
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 4, 9>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
new file mode 100644
index 00000000000..3234380f23c
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, 4, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
new file mode 100644
index 00000000000..311f8556932
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
new file mode 100644
index 00000000000..bc40bd55296
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<4, 4, 2>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
new file mode 100644
index 00000000000..cca88c802b0
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<4, 4, 3>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
new file mode 100644
index 00000000000..33c94a907b9
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<4, 4, 4>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
new file mode 100644
index 00000000000..1a1866f93a8
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<4, 4, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc b/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
new file mode 100644
index 00000000000..6b18ef8c863
--- /dev/null
+++ b/extern/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
@@ -0,0 +1,53 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+
+#include "ceres/schur_eliminator_impl.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+template class SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>;
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/ceres/internal/ceres/gradient_checking_cost_function.cc
new file mode 100644
index 00000000000..580fd260e15
--- /dev/null
+++ b/extern/ceres/internal/ceres/gradient_checking_cost_function.cc
@@ -0,0 +1,337 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/gradient_checking_cost_function.h"
+
+#include <algorithm>
+#include <cmath>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/parameter_block.h"
+#include "ceres/problem.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::abs;
+using std::max;
+using std::string;
+using std::vector;
+
+namespace {
+
+// True if x and y have an absolute relative difference less than
+// relative_precision and false otherwise. Stores the relative and absolute
+// difference in relative/absolute_error if non-NULL.
+bool IsClose(double x, double y, double relative_precision,
+ double *relative_error,
+ double *absolute_error) {
+ double local_absolute_error;
+ double local_relative_error;
+ if (!absolute_error) {
+ absolute_error = &local_absolute_error;
+ }
+ if (!relative_error) {
+ relative_error = &local_relative_error;
+ }
+ *absolute_error = abs(x - y);
+ *relative_error = *absolute_error / max(abs(x), abs(y));
+ if (x == 0 || y == 0) {
+ // If x or y is exactly zero, then relative difference doesn't have any
+ // meaning. Take the absolute difference instead.
+ *relative_error = *absolute_error;
+ }
+ return abs(*relative_error) < abs(relative_precision);
+}
+
+class GradientCheckingCostFunction : public CostFunction {
+ public:
+ GradientCheckingCostFunction(const CostFunction* function,
+ const NumericDiffOptions& options,
+ double relative_precision,
+ const string& extra_info)
+ : function_(function),
+ relative_precision_(relative_precision),
+ extra_info_(extra_info) {
+ DynamicNumericDiffCostFunction<CostFunction, CENTRAL>*
+ finite_diff_cost_function =
+ new DynamicNumericDiffCostFunction<CostFunction, CENTRAL>(
+ function,
+ DO_NOT_TAKE_OWNERSHIP,
+ options);
+
+ const vector<int32>& parameter_block_sizes =
+ function->parameter_block_sizes();
+ for (int i = 0; i < parameter_block_sizes.size(); ++i) {
+ finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]);
+ }
+ *mutable_parameter_block_sizes() = parameter_block_sizes;
+ set_num_residuals(function->num_residuals());
+ finite_diff_cost_function->SetNumResiduals(num_residuals());
+ finite_diff_cost_function_.reset(finite_diff_cost_function);
+ }
+
+ virtual ~GradientCheckingCostFunction() { }
+
+ virtual bool Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ if (!jacobians) {
+ // Nothing to check in this case; just forward.
+ return function_->Evaluate(parameters, residuals, NULL);
+ }
+
+ int num_residuals = function_->num_residuals();
+
+ // Make space for the jacobians of the two methods.
+ const vector<int32>& block_sizes = function_->parameter_block_sizes();
+ vector<Matrix> term_jacobians(block_sizes.size());
+ vector<Matrix> finite_difference_jacobians(block_sizes.size());
+ vector<double*> term_jacobian_pointers(block_sizes.size());
+ vector<double*> finite_difference_jacobian_pointers(block_sizes.size());
+ for (int i = 0; i < block_sizes.size(); i++) {
+ term_jacobians[i].resize(num_residuals, block_sizes[i]);
+ term_jacobian_pointers[i] = term_jacobians[i].data();
+ finite_difference_jacobians[i].resize(num_residuals, block_sizes[i]);
+ finite_difference_jacobian_pointers[i] =
+ finite_difference_jacobians[i].data();
+ }
+
+ // Evaluate the derivative using the user supplied code.
+ if (!function_->Evaluate(parameters,
+ residuals,
+ &term_jacobian_pointers[0])) {
+ LOG(WARNING) << "Function evaluation failed.";
+ return false;
+ }
+
+ // Evaluate the derivative using numeric derivatives.
+ finite_diff_cost_function_->Evaluate(
+ parameters,
+ residuals,
+ &finite_difference_jacobian_pointers[0]);
+
+ // See if any elements have relative error larger than the threshold.
+ int num_bad_jacobian_components = 0;
+ double worst_relative_error = 0;
+
+ // Accumulate the error message for all the jacobians, since it won't get
+ // output if there are no bad jacobian components.
+ string m;
+ for (int k = 0; k < block_sizes.size(); k++) {
+ // Copy the original jacobian blocks into the jacobians array.
+ if (jacobians[k] != NULL) {
+ MatrixRef(jacobians[k],
+ term_jacobians[k].rows(),
+ term_jacobians[k].cols()) = term_jacobians[k];
+ }
+
+ StringAppendF(&m,
+ "========== "
+ "Jacobian for " "block %d: (%ld by %ld)) "
+ "==========\n",
+ k,
+ static_cast<long>(term_jacobians[k].rows()),
+ static_cast<long>(term_jacobians[k].cols()));
+ // The funny spacing creates appropriately aligned column headers.
+ m += " block row col user dx/dy num diff dx/dy "
+ "abs error relative error parameter residual\n";
+
+ for (int i = 0; i < term_jacobians[k].rows(); i++) {
+ for (int j = 0; j < term_jacobians[k].cols(); j++) {
+ double term_jacobian = term_jacobians[k](i, j);
+ double finite_jacobian = finite_difference_jacobians[k](i, j);
+ double relative_error, absolute_error;
+ bool bad_jacobian_entry =
+ !IsClose(term_jacobian,
+ finite_jacobian,
+ relative_precision_,
+ &relative_error,
+ &absolute_error);
+ worst_relative_error = max(worst_relative_error, relative_error);
+
+ StringAppendF(&m, "%6d %4d %4d %17g %17g %17g %17g %17g %17g",
+ k, i, j,
+ term_jacobian, finite_jacobian,
+ absolute_error, relative_error,
+ parameters[k][j],
+ residuals[i]);
+
+ if (bad_jacobian_entry) {
+ num_bad_jacobian_components++;
+ StringAppendF(
+ &m, " ------ (%d,%d,%d) Relative error worse than %g",
+ k, i, j, relative_precision_);
+ }
+ m += "\n";
+ }
+ }
+ }
+
+ // Since there were some bad errors, dump comprehensive debug info.
+ if (num_bad_jacobian_components) {
+ string header = StringPrintf("Detected %d bad jacobian component(s). "
+ "Worst relative error was %g.\n",
+ num_bad_jacobian_components,
+ worst_relative_error);
+ if (!extra_info_.empty()) {
+ header += "Extra info for this residual: " + extra_info_ + "\n";
+ }
+ LOG(WARNING) << "\n" << header << m;
+ }
+ return true;
+ }
+
+ private:
+ const CostFunction* function_;
+ internal::scoped_ptr<CostFunction> finite_diff_cost_function_;
+ double relative_precision_;
+ string extra_info_;
+};
+
+} // namespace
+
+CostFunction *CreateGradientCheckingCostFunction(
+ const CostFunction *cost_function,
+ double relative_step_size,
+ double relative_precision,
+ const string& extra_info) {
+ NumericDiffOptions numeric_diff_options;
+ numeric_diff_options.relative_step_size = relative_step_size;
+
+ return new GradientCheckingCostFunction(cost_function,
+ numeric_diff_options,
+ relative_precision,
+ extra_info);
+}
+
+ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
+ double relative_step_size,
+ double relative_precision) {
+ // We create new CostFunctions by wrapping the original CostFunction
+ // in a gradient checking CostFunction. So its okay for the
+ // ProblemImpl to take ownership of it and destroy it. The
+ // LossFunctions and LocalParameterizations are reused and since
+ // they are owned by problem_impl, gradient_checking_problem_impl
+ // should not take ownership of it.
+ Problem::Options gradient_checking_problem_options;
+ gradient_checking_problem_options.cost_function_ownership = TAKE_OWNERSHIP;
+ gradient_checking_problem_options.loss_function_ownership =
+ DO_NOT_TAKE_OWNERSHIP;
+ gradient_checking_problem_options.local_parameterization_ownership =
+ DO_NOT_TAKE_OWNERSHIP;
+
+ ProblemImpl* gradient_checking_problem_impl = new ProblemImpl(
+ gradient_checking_problem_options);
+
+ Program* program = problem_impl->mutable_program();
+
+ // For every ParameterBlock in problem_impl, create a new parameter
+ // block with the same local parameterization and constancy.
+ const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks[i];
+ gradient_checking_problem_impl->AddParameterBlock(
+ parameter_block->mutable_user_state(),
+ parameter_block->Size(),
+ parameter_block->mutable_local_parameterization());
+
+ if (parameter_block->IsConstant()) {
+ gradient_checking_problem_impl->SetParameterBlockConstant(
+ parameter_block->mutable_user_state());
+ }
+ }
+
+ // For every ResidualBlock in problem_impl, create a new
+ // ResidualBlock by wrapping its CostFunction inside a
+ // GradientCheckingCostFunction.
+ const vector<ResidualBlock*>& residual_blocks = program->residual_blocks();
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks[i];
+
+ // Build a human readable string which identifies the
+ // ResidualBlock. This is used by the GradientCheckingCostFunction
+ // when logging debugging information.
+ string extra_info = StringPrintf(
+ "Residual block id %d; depends on parameters [", i);
+ vector<double*> parameter_blocks;
+ for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+ parameter_blocks.push_back(parameter_block->mutable_user_state());
+ StringAppendF(&extra_info, "%p", parameter_block->mutable_user_state());
+ extra_info += (j < residual_block->NumParameterBlocks() - 1) ? ", " : "]";
+ }
+
+ // Wrap the original CostFunction in a GradientCheckingCostFunction.
+ CostFunction* gradient_checking_cost_function =
+ CreateGradientCheckingCostFunction(residual_block->cost_function(),
+ relative_step_size,
+ relative_precision,
+ extra_info);
+
+ // The const_cast is necessary because
+ // ProblemImpl::AddResidualBlock can potentially take ownership of
+ // the LossFunction, but in this case we are guaranteed that this
+ // will not be the case, so this const_cast is harmless.
+ gradient_checking_problem_impl->AddResidualBlock(
+ gradient_checking_cost_function,
+ const_cast<LossFunction*>(residual_block->loss_function()),
+ parameter_blocks);
+ }
+
+ // Normally, when a problem is given to the solver, we guarantee
+ // that the state pointers for each parameter block point to the
+ // user provided data. Since we are creating this new problem from a
+ // problem given to us at an arbitrary stage of the solve, we cannot
+ // depend on this being the case, so we explicitly call
+ // SetParameterBlockStatePtrsToUserStatePtrs to ensure that this is
+ // the case.
+ gradient_checking_problem_impl
+ ->mutable_program()
+ ->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ return gradient_checking_problem_impl;
+}
+
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/gradient_checking_cost_function.h b/extern/ceres/internal/ceres/gradient_checking_cost_function.h
new file mode 100644
index 00000000000..cf92cb72bc5
--- /dev/null
+++ b/extern/ceres/internal/ceres/gradient_checking_cost_function.h
@@ -0,0 +1,85 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
+#define CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
+
+#include <string>
+
+#include "ceres/cost_function.h"
+
+namespace ceres {
+namespace internal {
+
+class ProblemImpl;
+
+// Creates a CostFunction that checks the jacobians that cost_function computes
+// with finite differences. Bad results are logged; required precision is
+// controlled by relative_precision and the numeric differentiation step size is
+// controlled with relative_step_size. See solver.h for a better explanation of
+// relative_step_size. Caller owns result.
+//
+// The condition enforced is that
+//
+// (J_actual(i, j) - J_numeric(i, j))
+// ------------------------------------ < relative_precision
+// max(J_actual(i, j), J_numeric(i, j))
+//
+// where J_actual(i, j) is the jacobian as computed by the supplied cost
+// function (by the user) and J_numeric is the jacobian as computed by finite
+// differences.
+//
+// Note: This is quite inefficient and is intended only for debugging.
+CostFunction* CreateGradientCheckingCostFunction(
+ const CostFunction* cost_function,
+ double relative_step_size,
+ double relative_precision,
+ const std::string& extra_info);
+
+// Create a new ProblemImpl object from the input problem_impl, where
+// each CostFunctions in problem_impl are wrapped inside a
+// GradientCheckingCostFunctions. This gives us a ProblemImpl object
+// which checks its derivatives against estimates from numeric
+// differentiation everytime a ResidualBlock is evaluated.
+//
+// relative_step_size and relative_precision are parameters to control
+// the numeric differentiation and the relative tolerance between the
+// jacobian computed by the CostFunctions in problem_impl and
+// jacobians obtained by numerically differentiating them. For more
+// details see the documentation for
+// CreateGradientCheckingCostFunction above.
+ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
+ double relative_step_size,
+ double relative_precision);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
diff --git a/extern/ceres/internal/ceres/gradient_problem.cc b/extern/ceres/internal/ceres/gradient_problem.cc
new file mode 100644
index 00000000000..4ebd3e60610
--- /dev/null
+++ b/extern/ceres/internal/ceres/gradient_problem.cc
@@ -0,0 +1,81 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/gradient_problem.h"
+#include "ceres/local_parameterization.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+GradientProblem::GradientProblem(FirstOrderFunction* function)
+ : function_(function),
+ parameterization_(
+ new IdentityParameterization(function_->NumParameters())),
+ scratch_(new double[function_->NumParameters()]) {
+}
+
+GradientProblem::GradientProblem(FirstOrderFunction* function,
+ LocalParameterization* parameterization)
+ : function_(function),
+ parameterization_(parameterization),
+ scratch_(new double[function_->NumParameters()]) {
+ CHECK_EQ(function_->NumParameters(), parameterization_->GlobalSize());
+}
+
+int GradientProblem::NumParameters() const {
+ return function_->NumParameters();
+}
+
+int GradientProblem::NumLocalParameters() const {
+ return parameterization_->LocalSize();
+}
+
+
+bool GradientProblem::Evaluate(const double* parameters,
+ double* cost,
+ double* gradient) const {
+ if (gradient == NULL) {
+ return function_->Evaluate(parameters, cost, NULL);
+ }
+
+ return (function_->Evaluate(parameters, cost, scratch_.get()) &&
+ parameterization_->MultiplyByJacobian(parameters,
+ 1,
+ scratch_.get(),
+ gradient));
+}
+
+bool GradientProblem::Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ return parameterization_->Plus(x, delta, x_plus_delta);
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/gradient_problem_evaluator.h b/extern/ceres/internal/ceres/gradient_problem_evaluator.h
new file mode 100644
index 00000000000..2c562544768
--- /dev/null
+++ b/extern/ceres/internal/ceres/gradient_problem_evaluator.h
@@ -0,0 +1,98 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
+#define CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
+
+#include <map>
+#include <string>
+
+#include "ceres/evaluator.h"
+#include "ceres/execution_summary.h"
+#include "ceres/gradient_problem.h"
+#include "ceres/internal/port.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+
+class GradientProblemEvaluator : public Evaluator {
+ public:
+ explicit GradientProblemEvaluator(const GradientProblem& problem)
+ : problem_(problem) {}
+ virtual ~GradientProblemEvaluator() {}
+ virtual SparseMatrix* CreateJacobian() const { return NULL; }
+ virtual bool Evaluate(const EvaluateOptions& evaluate_options,
+ const double* state,
+ double* cost,
+ double* residuals,
+ double* gradient,
+ SparseMatrix* jacobian) {
+ CHECK(jacobian == NULL);
+ ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
+ ScopedExecutionTimer call_type_timer(
+ gradient == NULL ? "Evaluator::Cost" : "Evaluator::Gradient",
+ &execution_summary_);
+ return problem_.Evaluate(state, cost, gradient);
+ }
+
+ virtual bool Plus(const double* state,
+ const double* delta,
+ double* state_plus_delta) const {
+ return problem_.Plus(state, delta, state_plus_delta);
+ }
+
+ virtual int NumParameters() const {
+ return problem_.NumParameters();
+ }
+
+ virtual int NumEffectiveParameters() const {
+ return problem_.NumLocalParameters();
+ }
+
+ virtual int NumResiduals() const { return 1; }
+
+ virtual std::map<std::string, int> CallStatistics() const {
+ return execution_summary_.calls();
+ }
+
+ virtual std::map<std::string, double> TimeStatistics() const {
+ return execution_summary_.times();
+ }
+
+ private:
+ const GradientProblem& problem_;
+ ::ceres::internal::ExecutionSummary execution_summary_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
diff --git a/extern/ceres/internal/ceres/gradient_problem_solver.cc b/extern/ceres/internal/ceres/gradient_problem_solver.cc
new file mode 100644
index 00000000000..9a549c23dac
--- /dev/null
+++ b/extern/ceres/internal/ceres/gradient_problem_solver.cc
@@ -0,0 +1,277 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/gradient_problem_solver.h"
+
+#include "ceres/callbacks.h"
+#include "ceres/gradient_problem.h"
+#include "ceres/gradient_problem_evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/map_util.h"
+#include "ceres/minimizer.h"
+#include "ceres/solver.h"
+#include "ceres/solver_utils.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+using internal::StringPrintf;
+using internal::StringAppendF;
+using std::string;
+
+namespace {
+
+Solver::Options GradientProblemSolverOptionsToSolverOptions(
+ const GradientProblemSolver::Options& options) {
+#define COPY_OPTION(x) solver_options.x = options.x
+
+ Solver::Options solver_options;
+ solver_options.minimizer_type = LINE_SEARCH;
+ COPY_OPTION(line_search_direction_type);
+ COPY_OPTION(line_search_type);
+ COPY_OPTION(nonlinear_conjugate_gradient_type);
+ COPY_OPTION(max_lbfgs_rank);
+ COPY_OPTION(use_approximate_eigenvalue_bfgs_scaling);
+ COPY_OPTION(line_search_interpolation_type);
+ COPY_OPTION(min_line_search_step_size);
+ COPY_OPTION(line_search_sufficient_function_decrease);
+ COPY_OPTION(max_line_search_step_contraction);
+ COPY_OPTION(min_line_search_step_contraction);
+ COPY_OPTION(max_num_line_search_step_size_iterations);
+ COPY_OPTION(max_num_line_search_direction_restarts);
+ COPY_OPTION(line_search_sufficient_curvature_decrease);
+ COPY_OPTION(max_line_search_step_expansion);
+ COPY_OPTION(max_num_iterations);
+ COPY_OPTION(max_solver_time_in_seconds);
+ COPY_OPTION(function_tolerance);
+ COPY_OPTION(gradient_tolerance);
+ COPY_OPTION(logging_type);
+ COPY_OPTION(minimizer_progress_to_stdout);
+ COPY_OPTION(callbacks);
+ return solver_options;
+#undef COPY_OPTION
+}
+
+
+} // namespace
+
+GradientProblemSolver::~GradientProblemSolver() {
+}
+
+void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
+ const GradientProblem& problem,
+ double* parameters_ptr,
+ GradientProblemSolver::Summary* summary) {
+ using internal::scoped_ptr;
+ using internal::WallTimeInSeconds;
+ using internal::Minimizer;
+ using internal::GradientProblemEvaluator;
+ using internal::LoggingCallback;
+ using internal::SetSummaryFinalCost;
+
+ double start_time = WallTimeInSeconds();
+ Solver::Options solver_options =
+ GradientProblemSolverOptionsToSolverOptions(options);
+
+ *CHECK_NOTNULL(summary) = Summary();
+ summary->num_parameters = problem.NumParameters();
+ summary->num_local_parameters = problem.NumLocalParameters();
+ summary->line_search_direction_type = options.line_search_direction_type; // NOLINT
+ summary->line_search_interpolation_type = options.line_search_interpolation_type; // NOLINT
+ summary->line_search_type = options.line_search_type;
+ summary->max_lbfgs_rank = options.max_lbfgs_rank;
+ summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT
+
+ // Check validity
+ if (!solver_options.IsValid(&summary->message)) {
+ LOG(ERROR) << "Terminating: " << summary->message;
+ return;
+ }
+
+ // Assuming that the parameter blocks in the program have been
+ Minimizer::Options minimizer_options;
+ minimizer_options = Minimizer::Options(solver_options);
+ minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem));
+
+ scoped_ptr<IterationCallback> logging_callback;
+ if (options.logging_type != SILENT) {
+ logging_callback.reset(
+ new LoggingCallback(LINE_SEARCH, options.minimizer_progress_to_stdout));
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ logging_callback.get());
+ }
+
+ scoped_ptr<Minimizer> minimizer(Minimizer::Create(LINE_SEARCH));
+ Vector solution(problem.NumParameters());
+ VectorRef parameters(parameters_ptr, problem.NumParameters());
+ solution = parameters;
+
+ Solver::Summary solver_summary;
+ solver_summary.fixed_cost = 0.0;
+ solver_summary.preprocessor_time_in_seconds = 0.0;
+ solver_summary.postprocessor_time_in_seconds = 0.0;
+ solver_summary.line_search_polynomial_minimization_time_in_seconds = 0.0;
+
+ minimizer->Minimize(minimizer_options, solution.data(), &solver_summary);
+
+ summary->termination_type = solver_summary.termination_type;
+ summary->message = solver_summary.message;
+ summary->initial_cost = solver_summary.initial_cost;
+ summary->final_cost = solver_summary.final_cost;
+ summary->iterations = solver_summary.iterations;
+ summary->line_search_polynomial_minimization_time_in_seconds =
+ solver_summary.line_search_polynomial_minimization_time_in_seconds;
+
+ if (summary->IsSolutionUsable()) {
+ parameters = solution;
+ SetSummaryFinalCost(summary);
+ }
+
+ const std::map<string, double>& evaluator_time_statistics =
+ minimizer_options.evaluator->TimeStatistics();
+ summary->cost_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ summary->gradient_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+
+ summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
+}
+
+// Invalid values for most fields, to ensure that we are not
+// accidentally reporting default values.
+GradientProblemSolver::Summary::Summary()
+ : termination_type(FAILURE),
+ message("ceres::GradientProblemSolve was not called."),
+ initial_cost(-1.0),
+ final_cost(-1.0),
+ total_time_in_seconds(-1.0),
+ cost_evaluation_time_in_seconds(-1.0),
+ gradient_evaluation_time_in_seconds(-1.0),
+ line_search_polynomial_minimization_time_in_seconds(-1.0),
+ num_parameters(-1),
+ num_local_parameters(-1),
+ line_search_direction_type(LBFGS),
+ line_search_type(ARMIJO),
+ line_search_interpolation_type(BISECTION),
+ nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
+ max_lbfgs_rank(-1) {
+}
+
+bool GradientProblemSolver::Summary::IsSolutionUsable() const {
+ return internal::IsSolutionUsable(*this);
+}
+
+string GradientProblemSolver::Summary::BriefReport() const {
+ return StringPrintf("Ceres GradientProblemSolver Report: "
+ "Iterations: %d, "
+ "Initial cost: %e, "
+ "Final cost: %e, "
+ "Termination: %s",
+ static_cast<int>(iterations.size()),
+ initial_cost,
+ final_cost,
+ TerminationTypeToString(termination_type));
+}
+
+string GradientProblemSolver::Summary::FullReport() const {
+ using internal::VersionString;
+
+ string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
+
+ StringAppendF(&report, "Parameters % 25d\n", num_parameters);
+ if (num_local_parameters != num_parameters) {
+ StringAppendF(&report, "Local parameters % 25d\n",
+ num_local_parameters);
+ }
+
+ string line_search_direction_string;
+ if (line_search_direction_type == LBFGS) {
+ line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
+ } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
+ line_search_direction_string =
+ NonlinearConjugateGradientTypeToString(
+ nonlinear_conjugate_gradient_type);
+ } else {
+ line_search_direction_string =
+ LineSearchDirectionTypeToString(line_search_direction_type);
+ }
+
+ StringAppendF(&report, "Line search direction %19s\n",
+ line_search_direction_string.c_str());
+
+ const string line_search_type_string =
+ StringPrintf("%s %s",
+ LineSearchInterpolationTypeToString(
+ line_search_interpolation_type),
+ LineSearchTypeToString(line_search_type));
+ StringAppendF(&report, "Line search type %19s\n",
+ line_search_type_string.c_str());
+ StringAppendF(&report, "\n");
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != FAILURE &&
+ termination_type != USER_FAILURE) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nMinimizer iterations % 16d\n",
+ static_cast<int>(iterations.size()));
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+
+ StringAppendF(&report, "\n Cost evaluation %23.4f\n",
+ cost_evaluation_time_in_seconds);
+ StringAppendF(&report, " Gradient evaluation %23.4f\n",
+ gradient_evaluation_time_in_seconds);
+ StringAppendF(&report, " Polynomial minimization %17.4f\n",
+ line_search_polynomial_minimization_time_in_seconds);
+
+ StringAppendF(&report, "Total %25.4f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s (%s)\n",
+ TerminationTypeToString(termination_type), message.c_str());
+ return report;
+}
+
+void Solve(const GradientProblemSolver::Options& options,
+ const GradientProblem& problem,
+ double* parameters,
+ GradientProblemSolver::Summary* summary) {
+ GradientProblemSolver solver;
+ solver.Solve(options, problem, parameters, summary);
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/graph.h b/extern/ceres/internal/ceres/graph.h
new file mode 100644
index 00000000000..b96b67265cb
--- /dev/null
+++ b/extern/ceres/internal/ceres/graph.h
@@ -0,0 +1,225 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_GRAPH_H_
+#define CERES_INTERNAL_GRAPH_H_
+
+#include <limits>
+#include <utility>
+#include "ceres/integral_types.h"
+#include "ceres/map_util.h"
+#include "ceres/collections_port.h"
+#include "ceres/internal/macros.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// A unweighted undirected graph templated over the vertex ids. Vertex
+// should be hashable.
+template <typename Vertex>
+class Graph {
+ public:
+ Graph() {}
+
+ // Add a vertex.
+ void AddVertex(const Vertex& vertex) {
+ if (vertices_.insert(vertex).second) {
+ edges_[vertex] = HashSet<Vertex>();
+ }
+ }
+
+ bool RemoveVertex(const Vertex& vertex) {
+ if (vertices_.find(vertex) == vertices_.end()) {
+ return false;
+ }
+
+ vertices_.erase(vertex);
+ const HashSet<Vertex>& sinks = edges_[vertex];
+ for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
+ it != sinks.end(); ++it) {
+ edges_[*it].erase(vertex);
+ }
+
+ edges_.erase(vertex);
+ return true;
+ }
+
+ // Add an edge between the vertex1 and vertex2. Calling AddEdge on a
+ // pair of vertices which do not exist in the graph yet will result
+ // in undefined behavior.
+ //
+ // It is legal to call this method repeatedly for the same set of
+ // vertices.
+ void AddEdge(const Vertex& vertex1, const Vertex& vertex2) {
+ DCHECK(vertices_.find(vertex1) != vertices_.end());
+ DCHECK(vertices_.find(vertex2) != vertices_.end());
+
+ if (edges_[vertex1].insert(vertex2).second) {
+ edges_[vertex2].insert(vertex1);
+ }
+ }
+
+ // Calling Neighbors on a vertex not in the graph will result in
+ // undefined behaviour.
+ const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
+ return FindOrDie(edges_, vertex);
+ }
+
+ const HashSet<Vertex>& vertices() const {
+ return vertices_;
+ }
+
+ private:
+ HashSet<Vertex> vertices_;
+ HashMap<Vertex, HashSet<Vertex> > edges_;
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
+};
+
+// A weighted undirected graph templated over the vertex ids. Vertex
+// should be hashable and comparable.
+template <typename Vertex>
+class WeightedGraph {
+ public:
+ WeightedGraph() {}
+
+ // Add a weighted vertex. If the vertex already exists in the graph,
+ // its weight is set to the new weight.
+ void AddVertex(const Vertex& vertex, double weight) {
+ if (vertices_.find(vertex) == vertices_.end()) {
+ vertices_.insert(vertex);
+ edges_[vertex] = HashSet<Vertex>();
+ }
+ vertex_weights_[vertex] = weight;
+ }
+
+ // Uses weight = 1.0. If vertex already exists, its weight is set to
+ // 1.0.
+ void AddVertex(const Vertex& vertex) {
+ AddVertex(vertex, 1.0);
+ }
+
+ bool RemoveVertex(const Vertex& vertex) {
+ if (vertices_.find(vertex) == vertices_.end()) {
+ return false;
+ }
+
+ vertices_.erase(vertex);
+ vertex_weights_.erase(vertex);
+ const HashSet<Vertex>& sinks = edges_[vertex];
+ for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
+ it != sinks.end(); ++it) {
+ if (vertex < *it) {
+ edge_weights_.erase(std::make_pair(vertex, *it));
+ } else {
+ edge_weights_.erase(std::make_pair(*it, vertex));
+ }
+ edges_[*it].erase(vertex);
+ }
+
+ edges_.erase(vertex);
+ return true;
+ }
+
+ // Add a weighted edge between the vertex1 and vertex2. Calling
+ // AddEdge on a pair of vertices which do not exist in the graph yet
+ // will result in undefined behavior.
+ //
+ // It is legal to call this method repeatedly for the same set of
+ // vertices.
+ void AddEdge(const Vertex& vertex1, const Vertex& vertex2, double weight) {
+ DCHECK(vertices_.find(vertex1) != vertices_.end());
+ DCHECK(vertices_.find(vertex2) != vertices_.end());
+
+ if (edges_[vertex1].insert(vertex2).second) {
+ edges_[vertex2].insert(vertex1);
+ }
+
+ if (vertex1 < vertex2) {
+ edge_weights_[std::make_pair(vertex1, vertex2)] = weight;
+ } else {
+ edge_weights_[std::make_pair(vertex2, vertex1)] = weight;
+ }
+ }
+
+ // Uses weight = 1.0.
+ void AddEdge(const Vertex& vertex1, const Vertex& vertex2) {
+ AddEdge(vertex1, vertex2, 1.0);
+ }
+
+ // Calling VertexWeight on a vertex not in the graph will result in
+ // undefined behavior.
+ double VertexWeight(const Vertex& vertex) const {
+ return FindOrDie(vertex_weights_, vertex);
+ }
+
+ // Calling EdgeWeight on a pair of vertices where either one of the
+ // vertices is not present in the graph will result in undefined
+ // behaviour. If there is no edge connecting vertex1 and vertex2,
+ // the edge weight is zero.
+ double EdgeWeight(const Vertex& vertex1, const Vertex& vertex2) const {
+ if (vertex1 < vertex2) {
+ return FindWithDefault(edge_weights_,
+ std::make_pair(vertex1, vertex2), 0.0);
+ } else {
+ return FindWithDefault(edge_weights_,
+ std::make_pair(vertex2, vertex1), 0.0);
+ }
+ }
+
+ // Calling Neighbors on a vertex not in the graph will result in
+ // undefined behaviour.
+ const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
+ return FindOrDie(edges_, vertex);
+ }
+
+ const HashSet<Vertex>& vertices() const {
+ return vertices_;
+ }
+
+ static double InvalidWeight() {
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ private:
+ HashSet<Vertex> vertices_;
+ HashMap<Vertex, double> vertex_weights_;
+ HashMap<Vertex, HashSet<Vertex> > edges_;
+ HashMap<std::pair<Vertex, Vertex>, double> edge_weights_;
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(WeightedGraph);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_GRAPH_H_
diff --git a/extern/ceres/internal/ceres/graph_algorithms.h b/extern/ceres/internal/ceres/graph_algorithms.h
new file mode 100644
index 00000000000..d1d3f52cd22
--- /dev/null
+++ b/extern/ceres/internal/ceres/graph_algorithms.h
@@ -0,0 +1,364 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Various algorithms that operate on undirected graphs.
+
+#ifndef CERES_INTERNAL_GRAPH_ALGORITHMS_H_
+#define CERES_INTERNAL_GRAPH_ALGORITHMS_H_
+
+#include <algorithm>
+#include <vector>
+#include <utility>
+#include "ceres/collections_port.h"
+#include "ceres/graph.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Compare two vertices of a graph by their degrees, if the degrees
+// are equal then order them by their ids.
+template <typename Vertex>
+class VertexTotalOrdering {
+ public:
+ explicit VertexTotalOrdering(const Graph<Vertex>& graph)
+ : graph_(graph) {}
+
+ bool operator()(const Vertex& lhs, const Vertex& rhs) const {
+ if (graph_.Neighbors(lhs).size() == graph_.Neighbors(rhs).size()) {
+ return lhs < rhs;
+ }
+ return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size();
+ }
+
+ private:
+ const Graph<Vertex>& graph_;
+};
+
+template <typename Vertex>
+class VertexDegreeLessThan {
+ public:
+ explicit VertexDegreeLessThan(const Graph<Vertex>& graph)
+ : graph_(graph) {}
+
+ bool operator()(const Vertex& lhs, const Vertex& rhs) const {
+ return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size();
+ }
+
+ private:
+ const Graph<Vertex>& graph_;
+};
+
+// Order the vertices of a graph using its (approximately) largest
+// independent set, where an independent set of a graph is a set of
+// vertices that have no edges connecting them. The maximum
+// independent set problem is NP-Hard, but there are effective
+// approximation algorithms available. The implementation here uses a
+// breadth first search that explores the vertices in order of
+// increasing degree. The same idea is used by Saad & Li in "MIQR: A
+// multilevel incomplete QR preconditioner for large sparse
+// least-squares problems", SIMAX, 2007.
+//
+// Given a undirected graph G(V,E), the algorithm is a greedy BFS
+// search where the vertices are explored in increasing order of their
+// degree. The output vector ordering contains elements of S in
+// increasing order of their degree, followed by elements of V - S in
+// increasing order of degree. The return value of the function is the
+// cardinality of S.
+template <typename Vertex>
+int IndependentSetOrdering(const Graph<Vertex>& graph,
+ std::vector<Vertex>* ordering) {
+ const HashSet<Vertex>& vertices = graph.vertices();
+ const int num_vertices = vertices.size();
+
+ CHECK_NOTNULL(ordering);
+ ordering->clear();
+ ordering->reserve(num_vertices);
+
+ // Colors for labeling the graph during the BFS.
+ const char kWhite = 0;
+ const char kGrey = 1;
+ const char kBlack = 2;
+
+ // Mark all vertices white.
+ HashMap<Vertex, char> vertex_color;
+ std::vector<Vertex> vertex_queue;
+ for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
+ it != vertices.end();
+ ++it) {
+ vertex_color[*it] = kWhite;
+ vertex_queue.push_back(*it);
+ }
+
+
+ std::sort(vertex_queue.begin(), vertex_queue.end(),
+ VertexTotalOrdering<Vertex>(graph));
+
+ // Iterate over vertex_queue. Pick the first white vertex, add it
+ // to the independent set. Mark it black and its neighbors grey.
+ for (int i = 0; i < vertex_queue.size(); ++i) {
+ const Vertex& vertex = vertex_queue[i];
+ if (vertex_color[vertex] != kWhite) {
+ continue;
+ }
+
+ ordering->push_back(vertex);
+ vertex_color[vertex] = kBlack;
+ const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
+ for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
+ it != neighbors.end();
+ ++it) {
+ vertex_color[*it] = kGrey;
+ }
+ }
+
+ int independent_set_size = ordering->size();
+
+ // Iterate over the vertices and add all the grey vertices to the
+ // ordering. At this stage there should only be black or grey
+ // vertices in the graph.
+ for (typename std::vector<Vertex>::const_iterator it = vertex_queue.begin();
+ it != vertex_queue.end();
+ ++it) {
+ const Vertex vertex = *it;
+ DCHECK(vertex_color[vertex] != kWhite);
+ if (vertex_color[vertex] != kBlack) {
+ ordering->push_back(vertex);
+ }
+ }
+
+ CHECK_EQ(ordering->size(), num_vertices);
+ return independent_set_size;
+}
+
+// Same as above with one important difference. The ordering parameter
+// is an input/output parameter which carries an initial ordering of
+// the vertices of the graph. The greedy independent set algorithm
+// starts by sorting the vertices in increasing order of their
+// degree. The input ordering is used to stabilize this sort, i.e., if
+// two vertices have the same degree then they are ordered in the same
+// order in which they occur in "ordering".
+//
+// This is useful in eliminating non-determinism from the Schur
+// ordering algorithm over all.
+template <typename Vertex>
+int StableIndependentSetOrdering(const Graph<Vertex>& graph,
+ std::vector<Vertex>* ordering) {
+ CHECK_NOTNULL(ordering);
+ const HashSet<Vertex>& vertices = graph.vertices();
+ const int num_vertices = vertices.size();
+ CHECK_EQ(vertices.size(), ordering->size());
+
+ // Colors for labeling the graph during the BFS.
+ const char kWhite = 0;
+ const char kGrey = 1;
+ const char kBlack = 2;
+
+ std::vector<Vertex> vertex_queue(*ordering);
+
+ std::stable_sort(vertex_queue.begin(), vertex_queue.end(),
+ VertexDegreeLessThan<Vertex>(graph));
+
+ // Mark all vertices white.
+ HashMap<Vertex, char> vertex_color;
+ for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
+ it != vertices.end();
+ ++it) {
+ vertex_color[*it] = kWhite;
+ }
+
+ ordering->clear();
+ ordering->reserve(num_vertices);
+ // Iterate over vertex_queue. Pick the first white vertex, add it
+ // to the independent set. Mark it black and its neighbors grey.
+ for (int i = 0; i < vertex_queue.size(); ++i) {
+ const Vertex& vertex = vertex_queue[i];
+ if (vertex_color[vertex] != kWhite) {
+ continue;
+ }
+
+ ordering->push_back(vertex);
+ vertex_color[vertex] = kBlack;
+ const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
+ for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
+ it != neighbors.end();
+ ++it) {
+ vertex_color[*it] = kGrey;
+ }
+ }
+
+ int independent_set_size = ordering->size();
+
+ // Iterate over the vertices and add all the grey vertices to the
+ // ordering. At this stage there should only be black or grey
+ // vertices in the graph.
+ for (typename std::vector<Vertex>::const_iterator it = vertex_queue.begin();
+ it != vertex_queue.end();
+ ++it) {
+ const Vertex vertex = *it;
+ DCHECK(vertex_color[vertex] != kWhite);
+ if (vertex_color[vertex] != kBlack) {
+ ordering->push_back(vertex);
+ }
+ }
+
+ CHECK_EQ(ordering->size(), num_vertices);
+ return independent_set_size;
+}
+
+// Find the connected component for a vertex implemented using the
+// find and update operation for disjoint-set. Recursively traverse
+// the disjoint set structure till you reach a vertex whose connected
+// component has the same id as the vertex itself. Along the way
+// update the connected components of all the vertices. This updating
+// is what gives this data structure its efficiency.
+template <typename Vertex>
+Vertex FindConnectedComponent(const Vertex& vertex,
+ HashMap<Vertex, Vertex>* union_find) {
+ typename HashMap<Vertex, Vertex>::iterator it = union_find->find(vertex);
+ DCHECK(it != union_find->end());
+ if (it->second != vertex) {
+ it->second = FindConnectedComponent(it->second, union_find);
+ }
+
+ return it->second;
+}
+
+// Compute a degree two constrained Maximum Spanning Tree/forest of
+// the input graph. Caller owns the result.
+//
+// Finding degree 2 spanning tree of a graph is not always
+// possible. For example a star graph, i.e. a graph with n-nodes
+// where one node is connected to the other n-1 nodes does not have
+// a any spanning trees of degree less than n-1.Even if such a tree
+// exists, finding such a tree is NP-Hard.
+
+// We get around both of these problems by using a greedy, degree
+// constrained variant of Kruskal's algorithm. We start with a graph
+// G_T with the same vertex set V as the input graph G(V,E) but an
+// empty edge set. We then iterate over the edges of G in decreasing
+// order of weight, adding them to G_T if doing so does not create a
+// cycle in G_T} and the degree of all the vertices in G_T remains
+// bounded by two. This O(|E|) algorithm results in a degree-2
+// spanning forest, or a collection of linear paths that span the
+// graph G.
+template <typename Vertex>
+WeightedGraph<Vertex>*
+Degree2MaximumSpanningForest(const WeightedGraph<Vertex>& graph) {
+ // Array of edges sorted in decreasing order of their weights.
+ std::vector<std::pair<double, std::pair<Vertex, Vertex> > > weighted_edges;
+ WeightedGraph<Vertex>* forest = new WeightedGraph<Vertex>();
+
+ // Disjoint-set to keep track of the connected components in the
+ // maximum spanning tree.
+ HashMap<Vertex, Vertex> disjoint_set;
+
+ // Sort of the edges in the graph in decreasing order of their
+ // weight. Also add the vertices of the graph to the Maximum
+ // Spanning Tree graph and set each vertex to be its own connected
+ // component in the disjoint_set structure.
+ const HashSet<Vertex>& vertices = graph.vertices();
+ for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
+ it != vertices.end();
+ ++it) {
+ const Vertex vertex1 = *it;
+ forest->AddVertex(vertex1, graph.VertexWeight(vertex1));
+ disjoint_set[vertex1] = vertex1;
+
+ const HashSet<Vertex>& neighbors = graph.Neighbors(vertex1);
+ for (typename HashSet<Vertex>::const_iterator it2 = neighbors.begin();
+ it2 != neighbors.end();
+ ++it2) {
+ const Vertex vertex2 = *it2;
+ if (vertex1 >= vertex2) {
+ continue;
+ }
+ const double weight = graph.EdgeWeight(vertex1, vertex2);
+ weighted_edges.push_back(
+ std::make_pair(weight, std::make_pair(vertex1, vertex2)));
+ }
+ }
+
+ // The elements of this vector, are pairs<edge_weight,
+ // edge>. Sorting it using the reverse iterators gives us the edges
+ // in decreasing order of edges.
+ std::sort(weighted_edges.rbegin(), weighted_edges.rend());
+
+ // Greedily add edges to the spanning tree/forest as long as they do
+ // not violate the degree/cycle constraint.
+ for (int i =0; i < weighted_edges.size(); ++i) {
+ const std::pair<Vertex, Vertex>& edge = weighted_edges[i].second;
+ const Vertex vertex1 = edge.first;
+ const Vertex vertex2 = edge.second;
+
+ // Check if either of the vertices are of degree 2 already, in
+ // which case adding this edge will violate the degree 2
+ // constraint.
+ if ((forest->Neighbors(vertex1).size() == 2) ||
+ (forest->Neighbors(vertex2).size() == 2)) {
+ continue;
+ }
+
+ // Find the id of the connected component to which the two
+ // vertices belong to. If the id is the same, it means that the
+ // two of them are already connected to each other via some other
+ // vertex, and adding this edge will create a cycle.
+ Vertex root1 = FindConnectedComponent(vertex1, &disjoint_set);
+ Vertex root2 = FindConnectedComponent(vertex2, &disjoint_set);
+
+ if (root1 == root2) {
+ continue;
+ }
+
+ // This edge can be added, add an edge in either direction with
+ // the same weight as the original graph.
+ const double edge_weight = graph.EdgeWeight(vertex1, vertex2);
+ forest->AddEdge(vertex1, vertex2, edge_weight);
+ forest->AddEdge(vertex2, vertex1, edge_weight);
+
+ // Connected the two connected components by updating the
+ // disjoint_set structure. Always connect the connected component
+ // with the greater index with the connected component with the
+ // smaller index. This should ensure shallower trees, for quicker
+ // lookup.
+ if (root2 < root1) {
+ std::swap(root1, root2);
+ }
+
+ disjoint_set[root2] = root1;
+ }
+ return forest;
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_GRAPH_ALGORITHMS_H_
diff --git a/extern/ceres/internal/ceres/householder_vector.h b/extern/ceres/internal/ceres/householder_vector.h
new file mode 100644
index 00000000000..f54feea054d
--- /dev/null
+++ b/extern/ceres/internal/ceres/householder_vector.h
@@ -0,0 +1,85 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://code.google.com/p/ceres-solver/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#ifndef CERES_PUBLIC_HOUSEHOLDER_VECTOR_H_
+#define CERES_PUBLIC_HOUSEHOLDER_VECTOR_H_
+
+#include "Eigen/Core"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Algorithm 5.1.1 from 'Matrix Computations' by Golub et al. (Johns Hopkins
+// Studies in Mathematical Sciences) but using the nth element of the input
+// vector as pivot instead of first. This computes the vector v with v(n) = 1
+// and beta such that H = I - beta * v * v^T is orthogonal and
+// H * x = ||x||_2 * e_n.
+template <typename Scalar>
+void ComputeHouseholderVector(const Eigen::Matrix<Scalar, Eigen::Dynamic, 1>& x,
+ Eigen::Matrix<Scalar, Eigen::Dynamic, 1>* v,
+ Scalar* beta) {
+ CHECK_NOTNULL(beta);
+ CHECK_NOTNULL(v);
+ CHECK_GT(x.rows(), 1);
+ CHECK_EQ(x.rows(), v->rows());
+
+ Scalar sigma = x.head(x.rows() - 1).squaredNorm();
+ *v = x;
+ (*v)(v->rows() - 1) = Scalar(1.0);
+
+ *beta = Scalar(0.0);
+ const Scalar& x_pivot = x(x.rows() - 1);
+
+ if (sigma <= Scalar(std::numeric_limits<double>::epsilon())) {
+ if (x_pivot < Scalar(0.0)) {
+ *beta = Scalar(2.0);
+ }
+ return;
+ }
+
+ const Scalar mu = sqrt(x_pivot * x_pivot + sigma);
+ Scalar v_pivot = Scalar(1.0);
+
+ if (x_pivot <= Scalar(0.0)) {
+ v_pivot = x_pivot - mu;
+ } else {
+ v_pivot = -sigma / (x_pivot + mu);
+ }
+
+ *beta = Scalar(2.0) * v_pivot * v_pivot / (sigma + v_pivot * v_pivot);
+
+ v->head(v->rows() - 1) /= v_pivot;
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_HOUSEHOLDER_VECTOR_H_
diff --git a/extern/ceres/internal/ceres/implicit_schur_complement.cc b/extern/ceres/internal/ceres/implicit_schur_complement.cc
new file mode 100644
index 00000000000..d05f03817b7
--- /dev/null
+++ b/extern/ceres/internal/ceres/implicit_schur_complement.cc
@@ -0,0 +1,225 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/implicit_schur_complement.h"
+
+#include "Eigen/Dense"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+ImplicitSchurComplement::ImplicitSchurComplement(
+ const LinearSolver::Options& options)
+ : options_(options),
+ D_(NULL),
+ b_(NULL) {
+}
+
+ImplicitSchurComplement::~ImplicitSchurComplement() {
+}
+
+void ImplicitSchurComplement::Init(const BlockSparseMatrix& A,
+ const double* D,
+ const double* b) {
+ // Since initialization is reasonably heavy, perhaps we can save on
+ // constructing a new object everytime.
+ if (A_ == NULL) {
+ A_.reset(PartitionedMatrixViewBase::Create(options_, A));
+ }
+
+ D_ = D;
+ b_ = b;
+
+ // Initialize temporary storage and compute the block diagonals of
+ // E'E and F'E.
+ if (block_diagonal_EtE_inverse_ == NULL) {
+ block_diagonal_EtE_inverse_.reset(A_->CreateBlockDiagonalEtE());
+ if (options_.preconditioner_type == JACOBI) {
+ block_diagonal_FtF_inverse_.reset(A_->CreateBlockDiagonalFtF());
+ }
+ rhs_.resize(A_->num_cols_f());
+ rhs_.setZero();
+ tmp_rows_.resize(A_->num_rows());
+ tmp_e_cols_.resize(A_->num_cols_e());
+ tmp_e_cols_2_.resize(A_->num_cols_e());
+ tmp_f_cols_.resize(A_->num_cols_f());
+ } else {
+ A_->UpdateBlockDiagonalEtE(block_diagonal_EtE_inverse_.get());
+ if (options_.preconditioner_type == JACOBI) {
+ A_->UpdateBlockDiagonalFtF(block_diagonal_FtF_inverse_.get());
+ }
+ }
+
+ // The block diagonals of the augmented linear system contain
+ // contributions from the diagonal D if it is non-null. Add that to
+ // the block diagonals and invert them.
+ AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get());
+ if (options_.preconditioner_type == JACOBI) {
+ AddDiagonalAndInvert((D_ == NULL) ? NULL : D_ + A_->num_cols_e(),
+ block_diagonal_FtF_inverse_.get());
+ }
+
+ // Compute the RHS of the Schur complement system.
+ UpdateRhs();
+}
+
+// Evaluate the product
+//
+// Sx = [F'F - F'E (E'E)^-1 E'F]x
+//
+// By breaking it down into individual matrix vector products
+// involving the matrices E and F. This is implemented using a
+// PartitionedMatrixView of the input matrix A.
+void ImplicitSchurComplement::RightMultiply(const double* x, double* y) const {
+ // y1 = F x
+ tmp_rows_.setZero();
+ A_->RightMultiplyF(x, tmp_rows_.data());
+
+ // y2 = E' y1
+ tmp_e_cols_.setZero();
+ A_->LeftMultiplyE(tmp_rows_.data(), tmp_e_cols_.data());
+
+ // y3 = -(E'E)^-1 y2
+ tmp_e_cols_2_.setZero();
+ block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(),
+ tmp_e_cols_2_.data());
+ tmp_e_cols_2_ *= -1.0;
+
+ // y1 = y1 + E y3
+ A_->RightMultiplyE(tmp_e_cols_2_.data(), tmp_rows_.data());
+
+ // y5 = D * x
+ if (D_ != NULL) {
+ ConstVectorRef Dref(D_ + A_->num_cols_e(), num_cols());
+ VectorRef(y, num_cols()) =
+ (Dref.array().square() *
+ ConstVectorRef(x, num_cols()).array()).matrix();
+ } else {
+ VectorRef(y, num_cols()).setZero();
+ }
+
+ // y = y5 + F' y1
+ A_->LeftMultiplyF(tmp_rows_.data(), y);
+}
+
+// Given a block diagonal matrix and an optional array of diagonal
+// entries D, add them to the diagonal of the matrix and compute the
+// inverse of each diagonal block.
+void ImplicitSchurComplement::AddDiagonalAndInvert(
+ const double* D,
+ BlockSparseMatrix* block_diagonal) {
+ const CompressedRowBlockStructure* block_diagonal_structure =
+ block_diagonal->block_structure();
+ for (int r = 0; r < block_diagonal_structure->rows.size(); ++r) {
+ const int row_block_pos = block_diagonal_structure->rows[r].block.position;
+ const int row_block_size = block_diagonal_structure->rows[r].block.size;
+ const Cell& cell = block_diagonal_structure->rows[r].cells[0];
+ MatrixRef m(block_diagonal->mutable_values() + cell.position,
+ row_block_size, row_block_size);
+
+ if (D != NULL) {
+ ConstVectorRef d(D + row_block_pos, row_block_size);
+ m += d.array().square().matrix().asDiagonal();
+ }
+
+ m = m
+ .selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(Matrix::Identity(row_block_size, row_block_size));
+ }
+}
+
+// Similar to RightMultiply, use the block structure of the matrix A
+// to compute y = (E'E)^-1 (E'b - E'F x).
+void ImplicitSchurComplement::BackSubstitute(const double* x, double* y) {
+ const int num_cols_e = A_->num_cols_e();
+ const int num_cols_f = A_->num_cols_f();
+ const int num_cols = A_->num_cols();
+ const int num_rows = A_->num_rows();
+
+ // y1 = F x
+ tmp_rows_.setZero();
+ A_->RightMultiplyF(x, tmp_rows_.data());
+
+ // y2 = b - y1
+ tmp_rows_ = ConstVectorRef(b_, num_rows) - tmp_rows_;
+
+ // y3 = E' y2
+ tmp_e_cols_.setZero();
+ A_->LeftMultiplyE(tmp_rows_.data(), tmp_e_cols_.data());
+
+ // y = (E'E)^-1 y3
+ VectorRef(y, num_cols).setZero();
+ block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(), y);
+
+ // The full solution vector y has two blocks. The first block of
+ // variables corresponds to the eliminated variables, which we just
+ // computed via back substitution. The second block of variables
+ // corresponds to the Schur complement system, so we just copy those
+ // values from the solution to the Schur complement.
+ VectorRef(y + num_cols_e, num_cols_f) = ConstVectorRef(x, num_cols_f);
+}
+
+// Compute the RHS of the Schur complement system.
+//
+// rhs = F'b - F'E (E'E)^-1 E'b
+//
+// Like BackSubstitute, we use the block structure of A to implement
+// this using a series of matrix vector products.
+void ImplicitSchurComplement::UpdateRhs() {
+ // y1 = E'b
+ tmp_e_cols_.setZero();
+ A_->LeftMultiplyE(b_, tmp_e_cols_.data());
+
+ // y2 = (E'E)^-1 y1
+ Vector y2 = Vector::Zero(A_->num_cols_e());
+ block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(), y2.data());
+
+ // y3 = E y2
+ tmp_rows_.setZero();
+ A_->RightMultiplyE(y2.data(), tmp_rows_.data());
+
+ // y3 = b - y3
+ tmp_rows_ = ConstVectorRef(b_, A_->num_rows()) - tmp_rows_;
+
+ // rhs = F' y3
+ rhs_.setZero();
+ A_->LeftMultiplyF(tmp_rows_.data(), rhs_.data());
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/implicit_schur_complement.h b/extern/ceres/internal/ceres/implicit_schur_complement.h
new file mode 100644
index 00000000000..5d822ebaeef
--- /dev/null
+++ b/extern/ceres/internal/ceres/implicit_schur_complement.h
@@ -0,0 +1,167 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// An iterative solver for solving the Schur complement/reduced camera
+// linear system that arise in SfM problems.
+
+#ifndef CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
+#define CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
+
+#include "ceres/linear_operator.h"
+#include "ceres/linear_solver.h"
+#include "ceres/partitioned_matrix_view.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrix;
+
+// This class implements various linear algebraic operations related
+// to the Schur complement without explicitly forming it.
+//
+//
+// Given a reactangular linear system Ax = b, where
+//
+// A = [E F]
+//
+// The normal equations are given by
+//
+// A'Ax = A'b
+//
+// |E'E E'F||y| = |E'b|
+// |F'E F'F||z| |F'b|
+//
+// and the Schur complement system is given by
+//
+// [F'F - F'E (E'E)^-1 E'F] z = F'b - F'E (E'E)^-1 E'b
+//
+// Now if we wish to solve Ax = b in the least squares sense, one way
+// is to form this Schur complement system and solve it using
+// Preconditioned Conjugate Gradients.
+//
+// The key operation in a conjugate gradient solver is the evaluation of the
+// matrix vector product with the Schur complement
+//
+// S = F'F - F'E (E'E)^-1 E'F
+//
+// It is straightforward to see that matrix vector products with S can
+// be evaluated without storing S in memory. Instead, given (E'E)^-1
+// (which for our purposes is an easily inverted block diagonal
+// matrix), it can be done in terms of matrix vector products with E,
+// F and (E'E)^-1. This class implements this functionality and other
+// auxilliary bits needed to implement a CG solver on the Schur
+// complement using the PartitionedMatrixView object.
+//
+// THREAD SAFETY: This class is nqot thread safe. In particular, the
+// RightMultiply (and the LeftMultiply) methods are not thread safe as
+// they depend on mutable arrays used for the temporaries needed to
+// compute the product y += Sx;
+class ImplicitSchurComplement : public LinearOperator {
+ public:
+ // num_eliminate_blocks is the number of E blocks in the matrix
+ // A.
+ //
+ // preconditioner indicates whether the inverse of the matrix F'F
+ // should be computed or not as a preconditioner for the Schur
+ // Complement.
+ //
+ // TODO(sameeragarwal): Get rid of the two bools below and replace
+ // them with enums.
+ explicit ImplicitSchurComplement(const LinearSolver::Options& options);
+ virtual ~ImplicitSchurComplement();
+
+ // Initialize the Schur complement for a linear least squares
+ // problem of the form
+ //
+ // |A | x = |b|
+ // |diag(D)| |0|
+ //
+ // If D is null, then it is treated as a zero dimensional matrix. It
+ // is important that the matrix A have a BlockStructure object
+ // associated with it and has a block structure that is compatible
+ // with the SchurComplement solver.
+ void Init(const BlockSparseMatrix& A, const double* D, const double* b);
+
+ // y += Sx, where S is the Schur complement.
+ virtual void RightMultiply(const double* x, double* y) const;
+
+ // The Schur complement is a symmetric positive definite matrix,
+ // thus the left and right multiply operators are the same.
+ virtual void LeftMultiply(const double* x, double* y) const {
+ RightMultiply(x, y);
+ }
+
+ // y = (E'E)^-1 (E'b - E'F x). Given an estimate of the solution to
+ // the Schur complement system, this method computes the value of
+ // the e_block variables that were eliminated to form the Schur
+ // complement.
+ void BackSubstitute(const double* x, double* y);
+
+ virtual int num_rows() const { return A_->num_cols_f(); }
+ virtual int num_cols() const { return A_->num_cols_f(); }
+ const Vector& rhs() const { return rhs_; }
+
+ const BlockSparseMatrix* block_diagonal_EtE_inverse() const {
+ return block_diagonal_EtE_inverse_.get();
+ }
+
+ const BlockSparseMatrix* block_diagonal_FtF_inverse() const {
+ return block_diagonal_FtF_inverse_.get();
+ }
+
+ private:
+ void AddDiagonalAndInvert(const double* D, BlockSparseMatrix* matrix);
+ void UpdateRhs();
+
+ const LinearSolver::Options& options_;
+
+ scoped_ptr<PartitionedMatrixViewBase> A_;
+ const double* D_;
+ const double* b_;
+
+ scoped_ptr<BlockSparseMatrix> block_diagonal_EtE_inverse_;
+ scoped_ptr<BlockSparseMatrix> block_diagonal_FtF_inverse_;
+
+ Vector rhs_;
+
+ // Temporary storage vectors used to implement RightMultiply.
+ mutable Vector tmp_rows_;
+ mutable Vector tmp_e_cols_;
+ mutable Vector tmp_e_cols_2_;
+ mutable Vector tmp_f_cols_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
diff --git a/extern/ceres/internal/ceres/integral_types.h b/extern/ceres/internal/ceres/integral_types.h
new file mode 100644
index 00000000000..98a746f13ff
--- /dev/null
+++ b/extern/ceres/internal/ceres/integral_types.h
@@ -0,0 +1,91 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Portable typedefs for various fixed-size integers. Uses template
+// metaprogramming instead of fragile compiler defines.
+
+#ifndef CERES_INTERNAL_INTEGRAL_TYPES_H_
+#define CERES_INTERNAL_INTEGRAL_TYPES_H_
+
+namespace ceres {
+namespace internal {
+
+// Compile time ternary on types.
+template<bool kCondition, typename kTrueType, typename kFalseType>
+struct Ternary {
+ typedef kTrueType type;
+};
+template<typename kTrueType, typename kFalseType>
+struct Ternary<false, kTrueType, kFalseType> {
+ typedef kFalseType type;
+};
+
+#define CERES_INTSIZE(TYPE) \
+ typename Ternary<sizeof(TYPE) * 8 == kBits, TYPE,
+
+template<int kBits>
+struct Integer {
+ typedef
+ CERES_INTSIZE(char)
+ CERES_INTSIZE(short)
+ CERES_INTSIZE(int)
+ CERES_INTSIZE(long int)
+ CERES_INTSIZE(long long)
+ void>::type >::type >::type >::type >::type
+ type;
+};
+
+template<int kBits>
+struct UnsignedInteger {
+ typedef
+ CERES_INTSIZE(unsigned char)
+ CERES_INTSIZE(unsigned short)
+ CERES_INTSIZE(unsigned int)
+ CERES_INTSIZE(unsigned long int)
+ CERES_INTSIZE(unsigned long long)
+ void>::type >::type >::type >::type >::type
+ type;
+};
+
+#undef CERES_INTSIZE
+
+typedef Integer< 8>::type int8;
+typedef Integer<32>::type int32;
+typedef Integer<64>::type int64;
+
+typedef UnsignedInteger< 8>::type uint8;
+typedef UnsignedInteger<16>::type uint16;
+typedef UnsignedInteger<32>::type uint32;
+typedef UnsignedInteger<64>::type uint64;
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_INTEGRAL_TYPES_H_
diff --git a/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc b/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc
new file mode 100644
index 00000000000..9d4e30d69d2
--- /dev/null
+++ b/extern/ceres/internal/ceres/iterative_schur_complement_solver.cc
@@ -0,0 +1,182 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/iterative_schur_complement_solver.h"
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/detect_structure.h"
+#include "ceres/implicit_schur_complement.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/preconditioner.h"
+#include "ceres/schur_jacobi_preconditioner.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "ceres/visibility_based_preconditioner.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+IterativeSchurComplementSolver::IterativeSchurComplementSolver(
+ const LinearSolver::Options& options)
+ : options_(options) {
+}
+
+IterativeSchurComplementSolver::~IterativeSchurComplementSolver() {
+}
+
+LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
+ BlockSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("IterativeSchurComplementSolver::Solve");
+
+ CHECK_NOTNULL(A->block_structure());
+ const int num_eliminate_blocks = options_.elimination_groups[0];
+ // Initialize a ImplicitSchurComplement object.
+ if (schur_complement_ == NULL) {
+ DetectStructure(*(A->block_structure()),
+ num_eliminate_blocks,
+ &options_.row_block_size,
+ &options_.e_block_size,
+ &options_.f_block_size);
+ schur_complement_.reset(new ImplicitSchurComplement(options_));
+ }
+ schur_complement_->Init(*A, per_solve_options.D, b);
+
+ const int num_schur_complement_blocks =
+ A->block_structure()->cols.size() - num_eliminate_blocks;
+ if (num_schur_complement_blocks == 0) {
+ VLOG(2) << "No parameter blocks left in the schur complement.";
+ LinearSolver::Summary cg_summary;
+ cg_summary.num_iterations = 0;
+ cg_summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ schur_complement_->BackSubstitute(NULL, x);
+ return cg_summary;
+ }
+
+ // Initialize the solution to the Schur complement system to zero.
+ reduced_linear_system_solution_.resize(schur_complement_->num_rows());
+ reduced_linear_system_solution_.setZero();
+
+ // Instantiate a conjugate gradient solver that runs on the Schur
+ // complement matrix with the block diagonal of the matrix F'F as
+ // the preconditioner.
+ LinearSolver::Options cg_options;
+ cg_options.min_num_iterations = options_.min_num_iterations;
+ cg_options.max_num_iterations = options_.max_num_iterations;
+ ConjugateGradientsSolver cg_solver(cg_options);
+ LinearSolver::PerSolveOptions cg_per_solve_options;
+
+ cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
+ cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
+
+ Preconditioner::Options preconditioner_options;
+ preconditioner_options.type = options_.preconditioner_type;
+ preconditioner_options.visibility_clustering_type =
+ options_.visibility_clustering_type;
+ preconditioner_options.sparse_linear_algebra_library_type =
+ options_.sparse_linear_algebra_library_type;
+ preconditioner_options.num_threads = options_.num_threads;
+ preconditioner_options.row_block_size = options_.row_block_size;
+ preconditioner_options.e_block_size = options_.e_block_size;
+ preconditioner_options.f_block_size = options_.f_block_size;
+ preconditioner_options.elimination_groups = options_.elimination_groups;
+
+ switch (options_.preconditioner_type) {
+ case IDENTITY:
+ break;
+ case JACOBI:
+ preconditioner_.reset(
+ new SparseMatrixPreconditionerWrapper(
+ schur_complement_->block_diagonal_FtF_inverse()));
+ break;
+ case SCHUR_JACOBI:
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(
+ new SchurJacobiPreconditioner(*A->block_structure(),
+ preconditioner_options));
+ }
+ break;
+ case CLUSTER_JACOBI:
+ case CLUSTER_TRIDIAGONAL:
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(
+ new VisibilityBasedPreconditioner(*A->block_structure(),
+ preconditioner_options));
+ }
+ break;
+ default:
+ LOG(FATAL) << "Unknown Preconditioner Type";
+ }
+
+ bool preconditioner_update_was_successful = true;
+ if (preconditioner_.get() != NULL) {
+ preconditioner_update_was_successful =
+ preconditioner_->Update(*A, per_solve_options.D);
+ cg_per_solve_options.preconditioner = preconditioner_.get();
+ }
+ event_logger.AddEvent("Setup");
+
+ LinearSolver::Summary cg_summary;
+ cg_summary.num_iterations = 0;
+ cg_summary.termination_type = LINEAR_SOLVER_FAILURE;
+
+ // TODO(sameeragarwal): Refactor preconditioners to return a more
+ // sane message.
+ cg_summary.message = "Preconditioner update failed.";
+ if (preconditioner_update_was_successful) {
+ cg_summary = cg_solver.Solve(schur_complement_.get(),
+ schur_complement_->rhs().data(),
+ cg_per_solve_options,
+ reduced_linear_system_solution_.data());
+ if (cg_summary.termination_type != LINEAR_SOLVER_FAILURE &&
+ cg_summary.termination_type != LINEAR_SOLVER_FATAL_ERROR) {
+ schur_complement_->BackSubstitute(
+ reduced_linear_system_solution_.data(), x);
+ }
+ }
+ event_logger.AddEvent("Solve");
+ return cg_summary;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/iterative_schur_complement_solver.h b/extern/ceres/internal/ceres/iterative_schur_complement_solver.h
new file mode 100644
index 00000000000..e90d310de07
--- /dev/null
+++ b/extern/ceres/internal/ceres/iterative_schur_complement_solver.h
@@ -0,0 +1,92 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
+#define CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
+
+#include "ceres/linear_solver.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrix;
+class ImplicitSchurComplement;
+class Preconditioner;
+
+// This class implements an iterative solver for the linear least
+// squares problems that have a bi-partite sparsity structure common
+// to Structure from Motion problems.
+//
+// The algorithm used by this solver was developed in a series of
+// papers - "Agarwal et al, Bundle Adjustment in the Large, ECCV 2010"
+// and "Wu et al, Multicore Bundle Adjustment, submitted to CVPR
+// 2011" at the Univeristy of Washington.
+//
+// The key idea is that one can run Conjugate Gradients on the Schur
+// Complement system without explicitly forming the Schur Complement
+// in memory. The heavy lifting for this is done by the
+// ImplicitSchurComplement class. Not forming the Schur complement in
+// memory and factoring it results in substantial savings in time and
+// memory. Further, iterative solvers like this open up the
+// possibility of solving the Newton equations in a non-linear solver
+// only approximately and terminating early, thereby saving even more
+// time.
+//
+// For the curious, running CG on the Schur complement is the same as
+// running CG on the Normal Equations with an SSOR preconditioner. For
+// a proof of this fact and others related to this solver please see
+// the section on Domain Decomposition Methods in Saad's book
+// "Iterative Methods for Sparse Linear Systems".
+class IterativeSchurComplementSolver : public BlockSparseMatrixSolver {
+ public:
+ explicit IterativeSchurComplementSolver(const LinearSolver::Options& options);
+ virtual ~IterativeSchurComplementSolver();
+
+ private:
+ virtual LinearSolver::Summary SolveImpl(
+ BlockSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& options,
+ double* x);
+
+ LinearSolver::Options options_;
+ scoped_ptr<internal::ImplicitSchurComplement> schur_complement_;
+ scoped_ptr<Preconditioner> preconditioner_;
+ Vector reduced_linear_system_solution_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(IterativeSchurComplementSolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/lapack.cc b/extern/ceres/internal/ceres/lapack.cc
new file mode 100644
index 00000000000..6fc23f4e658
--- /dev/null
+++ b/extern/ceres/internal/ceres/lapack.cc
@@ -0,0 +1,193 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/lapack.h"
+
+#include "ceres/internal/port.h"
+#include "ceres/linear_solver.h"
+#include "glog/logging.h"
+
+// C interface to the LAPACK Cholesky factorization and triangular solve.
+extern "C" void dpotrf_(char* uplo,
+ int* n,
+ double* a,
+ int* lda,
+ int* info);
+
+extern "C" void dpotrs_(char* uplo,
+ int* n,
+ int* nrhs,
+ double* a,
+ int* lda,
+ double* b,
+ int* ldb,
+ int* info);
+
+extern "C" void dgels_(char* uplo,
+ int* m,
+ int* n,
+ int* nrhs,
+ double* a,
+ int* lda,
+ double* b,
+ int* ldb,
+ double* work,
+ int* lwork,
+ int* info);
+
+
+namespace ceres {
+namespace internal {
+
+LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
+ int num_rows,
+ const double* in_lhs,
+ double* rhs_and_solution,
+ std::string* message) {
+#ifdef CERES_NO_LAPACK
+ LOG(FATAL) << "Ceres was built without a BLAS library.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+#else
+ char uplo = 'L';
+ int n = num_rows;
+ int info = 0;
+ int nrhs = 1;
+ double* lhs = const_cast<double*>(in_lhs);
+
+ dpotrf_(&uplo, &n, lhs, &n, &info);
+ if (info < 0) {
+ LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+ << "Please report it."
+ << "LAPACK::dpotrf fatal error."
+ << "Argument: " << -info << " is invalid.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ if (info > 0) {
+ *message =
+ StringPrintf(
+ "LAPACK::dpotrf numerical failure. "
+ "The leading minor of order %d is not positive definite.", info);
+ return LINEAR_SOLVER_FAILURE;
+ }
+
+ dpotrs_(&uplo, &n, &nrhs, lhs, &n, rhs_and_solution, &n, &info);
+ if (info < 0) {
+ LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+ << "Please report it."
+ << "LAPACK::dpotrs fatal error."
+ << "Argument: " << -info << " is invalid.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+ }
+
+ *message = "Success";
+ return LINEAR_SOLVER_SUCCESS;
+#endif
+}
+
+int LAPACK::EstimateWorkSizeForQR(int num_rows, int num_cols) {
+#ifdef CERES_NO_LAPACK
+ LOG(FATAL) << "Ceres was built without a LAPACK library.";
+ return -1;
+#else
+ char trans = 'N';
+ int nrhs = 1;
+ int lwork = -1;
+ double work;
+ int info = 0;
+ dgels_(&trans,
+ &num_rows,
+ &num_cols,
+ &nrhs,
+ NULL,
+ &num_rows,
+ NULL,
+ &num_rows,
+ &work,
+ &lwork,
+ &info);
+
+ if (info < 0) {
+ LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+ << "Please report it."
+ << "LAPACK::dgels fatal error."
+ << "Argument: " << -info << " is invalid.";
+ }
+ return static_cast<int>(work);
+#endif
+}
+
+LinearSolverTerminationType LAPACK::SolveInPlaceUsingQR(
+ int num_rows,
+ int num_cols,
+ const double* in_lhs,
+ int work_size,
+ double* work,
+ double* rhs_and_solution,
+ std::string* message) {
+#ifdef CERES_NO_LAPACK
+ LOG(FATAL) << "Ceres was built without a LAPACK library.";
+ return LINEAR_SOLVER_FATAL_ERROR;
+#else
+ char trans = 'N';
+ int m = num_rows;
+ int n = num_cols;
+ int nrhs = 1;
+ int lda = num_rows;
+ int ldb = num_rows;
+ int info = 0;
+ double* lhs = const_cast<double*>(in_lhs);
+
+ dgels_(&trans,
+ &m,
+ &n,
+ &nrhs,
+ lhs,
+ &lda,
+ rhs_and_solution,
+ &ldb,
+ work,
+ &work_size,
+ &info);
+
+ if (info < 0) {
+ LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+ << "Please report it."
+ << "LAPACK::dgels fatal error."
+ << "Argument: " << -info << " is invalid.";
+ }
+
+ *message = "Success.";
+ return LINEAR_SOLVER_SUCCESS;
+#endif
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/lapack.h b/extern/ceres/internal/ceres/lapack.h
new file mode 100644
index 00000000000..5bb1a220c26
--- /dev/null
+++ b/extern/ceres/internal/ceres/lapack.h
@@ -0,0 +1,100 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LAPACK_H_
+#define CERES_INTERNAL_LAPACK_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+class LAPACK {
+ public:
+ // Solve
+ //
+ // lhs * solution = rhs
+ //
+ // using a Cholesky factorization. Here
+ // lhs is a symmetric positive definite matrix. It is assumed to be
+ // column major and only the lower triangular part of the matrix is
+ // referenced.
+ //
+ // This function uses the LAPACK dpotrf and dpotrs routines.
+ //
+ // The return value and the message string together describe whether
+ // the solver terminated successfully or not and if so, what was the
+ // reason for failure.
+ static LinearSolverTerminationType SolveInPlaceUsingCholesky(
+ int num_rows,
+ const double* lhs,
+ double* rhs_and_solution,
+ std::string* message);
+
+ // The SolveUsingQR function requires a buffer for its temporary
+ // computation. This function given the size of the lhs matrix will
+ // return the size of the buffer needed.
+ static int EstimateWorkSizeForQR(int num_rows, int num_cols);
+
+ // Solve
+ //
+ // lhs * solution = rhs
+ //
+ // using a dense QR factorization. lhs is an arbitrary (possibly
+ // rectangular) matrix with full column rank.
+ //
+ // work is an array of size work_size that this routine uses for its
+ // temporary storage. The optimal size of this array can be obtained
+ // by calling EstimateWorkSizeForQR.
+ //
+ // When calling, rhs_and_solution contains the rhs, and upon return
+ // the first num_col entries are the solution.
+ //
+ // This function uses the LAPACK dgels routine.
+ //
+ // The return value and the message string together describe whether
+ // the solver terminated successfully or not and if so, what was the
+ // reason for failure.
+ static LinearSolverTerminationType SolveInPlaceUsingQR(
+ int num_rows,
+ int num_cols,
+ const double* lhs,
+ int work_size,
+ double* work,
+ double* rhs_and_solution,
+ std::string* message);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LAPACK_H_
diff --git a/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc
new file mode 100644
index 00000000000..e9833805ef5
--- /dev/null
+++ b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.cc
@@ -0,0 +1,167 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/levenberg_marquardt_strategy.h"
+
+#include <cmath>
+#include "Eigen/Core"
+#include "ceres/array_utils.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_least_squares_problems.h"
+#include "ceres/linear_solver.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/trust_region_strategy.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+LevenbergMarquardtStrategy::LevenbergMarquardtStrategy(
+ const TrustRegionStrategy::Options& options)
+ : linear_solver_(options.linear_solver),
+ radius_(options.initial_radius),
+ max_radius_(options.max_radius),
+ min_diagonal_(options.min_lm_diagonal),
+ max_diagonal_(options.max_lm_diagonal),
+ decrease_factor_(2.0),
+ reuse_diagonal_(false) {
+ CHECK_NOTNULL(linear_solver_);
+ CHECK_GT(min_diagonal_, 0.0);
+ CHECK_LE(min_diagonal_, max_diagonal_);
+ CHECK_GT(max_radius_, 0.0);
+}
+
+LevenbergMarquardtStrategy::~LevenbergMarquardtStrategy() {
+}
+
+TrustRegionStrategy::Summary LevenbergMarquardtStrategy::ComputeStep(
+ const TrustRegionStrategy::PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals,
+ double* step) {
+ CHECK_NOTNULL(jacobian);
+ CHECK_NOTNULL(residuals);
+ CHECK_NOTNULL(step);
+
+ const int num_parameters = jacobian->num_cols();
+ if (!reuse_diagonal_) {
+ if (diagonal_.rows() != num_parameters) {
+ diagonal_.resize(num_parameters, 1);
+ }
+
+ jacobian->SquaredColumnNorm(diagonal_.data());
+ for (int i = 0; i < num_parameters; ++i) {
+ diagonal_[i] = std::min(std::max(diagonal_[i], min_diagonal_),
+ max_diagonal_);
+ }
+ }
+
+ lm_diagonal_ = (diagonal_ / radius_).array().sqrt();
+
+ LinearSolver::PerSolveOptions solve_options;
+ solve_options.D = lm_diagonal_.data();
+ solve_options.q_tolerance = per_solve_options.eta;
+ // Disable r_tolerance checking. Since we only care about
+ // termination via the q_tolerance. As Nash and Sofer show,
+ // r_tolerance based termination is essentially useless in
+ // Truncated Newton methods.
+ solve_options.r_tolerance = -1.0;
+
+ // Invalidate the output array lm_step, so that we can detect if
+ // the linear solver generated numerical garbage. This is known
+ // to happen for the DENSE_QR and then DENSE_SCHUR solver when
+ // the Jacobin is severly rank deficient and mu is too small.
+ InvalidateArray(num_parameters, step);
+
+ // Instead of solving Jx = -r, solve Jy = r.
+ // Then x can be found as x = -y, but the inputs jacobian and residuals
+ // do not need to be modified.
+ LinearSolver::Summary linear_solver_summary =
+ linear_solver_->Solve(jacobian, residuals, solve_options, step);
+
+ if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+ LOG(WARNING) << "Linear solver fatal error: "
+ << linear_solver_summary.message;
+ } else if (linear_solver_summary.termination_type == LINEAR_SOLVER_FAILURE) {
+ LOG(WARNING) << "Linear solver failure. Failed to compute a step: "
+ << linear_solver_summary.message;
+ } else if (!IsArrayValid(num_parameters, step)) {
+ LOG(WARNING) << "Linear solver failure. Failed to compute a finite step.";
+ linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
+ } else {
+ VectorRef(step, num_parameters) *= -1.0;
+ }
+ reuse_diagonal_ = true;
+
+ if (per_solve_options.dump_format_type == CONSOLE ||
+ (per_solve_options.dump_format_type != CONSOLE &&
+ !per_solve_options.dump_filename_base.empty())) {
+ if (!DumpLinearLeastSquaresProblem(per_solve_options.dump_filename_base,
+ per_solve_options.dump_format_type,
+ jacobian,
+ solve_options.D,
+ residuals,
+ step,
+ 0)) {
+ LOG(ERROR) << "Unable to dump trust region problem."
+ << " Filename base: " << per_solve_options.dump_filename_base;
+ }
+ }
+
+
+ TrustRegionStrategy::Summary summary;
+ summary.residual_norm = linear_solver_summary.residual_norm;
+ summary.num_iterations = linear_solver_summary.num_iterations;
+ summary.termination_type = linear_solver_summary.termination_type;
+ return summary;
+}
+
+void LevenbergMarquardtStrategy::StepAccepted(double step_quality) {
+ CHECK_GT(step_quality, 0.0);
+ radius_ = radius_ / std::max(1.0 / 3.0,
+ 1.0 - pow(2.0 * step_quality - 1.0, 3));
+ radius_ = std::min(max_radius_, radius_);
+ decrease_factor_ = 2.0;
+ reuse_diagonal_ = false;
+}
+
+void LevenbergMarquardtStrategy::StepRejected(double step_quality) {
+ radius_ = radius_ / decrease_factor_;
+ decrease_factor_ *= 2.0;
+ reuse_diagonal_ = true;
+}
+
+double LevenbergMarquardtStrategy::Radius() const {
+ return radius_;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h
new file mode 100644
index 00000000000..c87a016c8f4
--- /dev/null
+++ b/extern/ceres/internal/ceres/levenberg_marquardt_strategy.h
@@ -0,0 +1,87 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
+#define CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
+
+#include "ceres/internal/eigen.h"
+#include "ceres/trust_region_strategy.h"
+
+namespace ceres {
+namespace internal {
+
+// Levenberg-Marquardt step computation and trust region sizing
+// strategy based on on "Methods for Nonlinear Least Squares" by
+// K. Madsen, H.B. Nielsen and O. Tingleff. Available to download from
+//
+// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
+class LevenbergMarquardtStrategy : public TrustRegionStrategy {
+ public:
+ explicit LevenbergMarquardtStrategy(
+ const TrustRegionStrategy::Options& options);
+ virtual ~LevenbergMarquardtStrategy();
+
+ // TrustRegionStrategy interface
+ virtual TrustRegionStrategy::Summary ComputeStep(
+ const TrustRegionStrategy::PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals,
+ double* step);
+ virtual void StepAccepted(double step_quality);
+ virtual void StepRejected(double step_quality);
+ virtual void StepIsInvalid() {
+ // Treat the current step as a rejected step with no increase in
+ // solution quality. Since rejected steps lead to decrease in the
+ // size of the trust region, the next time ComputeStep is called,
+ // this will lead to a better conditioned system.
+ StepRejected(0.0);
+ }
+
+ virtual double Radius() const;
+
+ private:
+ LinearSolver* linear_solver_;
+ double radius_;
+ double max_radius_;
+ const double min_diagonal_;
+ const double max_diagonal_;
+ double decrease_factor_;
+ bool reuse_diagonal_;
+ Vector diagonal_; // diagonal_ = diag(J'J)
+ // Scaled copy of diagonal_. Stored here as optimization to prevent
+ // allocations in every iteration and reuse when a step fails and
+ // ComputeStep is called again.
+ Vector lm_diagonal_; // lm_diagonal_ = diagonal_ / radius_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
diff --git a/extern/ceres/internal/ceres/line_search.cc b/extern/ceres/internal/ceres/line_search.cc
new file mode 100644
index 00000000000..9cdcb7b77e5
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search.cc
@@ -0,0 +1,881 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search.h"
+
+#include <iomanip>
+#include <iostream> // NOLINT
+
+#include "glog/logging.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/fpclassify.h"
+#include "ceres/map_util.h"
+#include "ceres/polynomial.h"
+#include "ceres/stringprintf.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+
+using std::map;
+using std::ostream;
+using std::string;
+using std::vector;
+
+namespace {
+// Precision used for floating point values in error message output.
+const int kErrorMessageNumericPrecision = 8;
+
+FunctionSample ValueSample(const double x, const double value) {
+ FunctionSample sample;
+ sample.x = x;
+ sample.value = value;
+ sample.value_is_valid = true;
+ return sample;
+}
+
+FunctionSample ValueAndGradientSample(const double x,
+ const double value,
+ const double gradient) {
+ FunctionSample sample;
+ sample.x = x;
+ sample.value = value;
+ sample.gradient = gradient;
+ sample.value_is_valid = true;
+ sample.gradient_is_valid = true;
+ return sample;
+}
+
+} // namespace
+
+
+ostream& operator<<(ostream &os, const FunctionSample& sample);
+
+// Convenience stream operator for pushing FunctionSamples into log messages.
+ostream& operator<<(ostream &os, const FunctionSample& sample) {
+ os << sample.ToDebugString();
+ return os;
+}
+
+LineSearch::LineSearch(const LineSearch::Options& options)
+ : options_(options) {}
+
+LineSearch* LineSearch::Create(const LineSearchType line_search_type,
+ const LineSearch::Options& options,
+ string* error) {
+ LineSearch* line_search = NULL;
+ switch (line_search_type) {
+ case ceres::ARMIJO:
+ line_search = new ArmijoLineSearch(options);
+ break;
+ case ceres::WOLFE:
+ line_search = new WolfeLineSearch(options);
+ break;
+ default:
+ *error = string("Invalid line search algorithm type: ") +
+ LineSearchTypeToString(line_search_type) +
+ string(", unable to create line search.");
+ return NULL;
+ }
+ return line_search;
+}
+
+LineSearchFunction::LineSearchFunction(Evaluator* evaluator)
+ : evaluator_(evaluator),
+ position_(evaluator->NumParameters()),
+ direction_(evaluator->NumEffectiveParameters()),
+ evaluation_point_(evaluator->NumParameters()),
+ scaled_direction_(evaluator->NumEffectiveParameters()),
+ gradient_(evaluator->NumEffectiveParameters()),
+ initial_evaluator_residual_time_in_seconds(0.0),
+ initial_evaluator_jacobian_time_in_seconds(0.0) {}
+
+void LineSearchFunction::Init(const Vector& position,
+ const Vector& direction) {
+ position_ = position;
+ direction_ = direction;
+}
+
+bool LineSearchFunction::Evaluate(double x, double* f, double* g) {
+ scaled_direction_ = x * direction_;
+ if (!evaluator_->Plus(position_.data(),
+ scaled_direction_.data(),
+ evaluation_point_.data())) {
+ return false;
+ }
+
+ if (g == NULL) {
+ return (evaluator_->Evaluate(evaluation_point_.data(),
+ f, NULL, NULL, NULL) &&
+ IsFinite(*f));
+ }
+
+ if (!evaluator_->Evaluate(evaluation_point_.data(),
+ f, NULL, gradient_.data(), NULL)) {
+ return false;
+ }
+
+ *g = direction_.dot(gradient_);
+ return IsFinite(*f) && IsFinite(*g);
+}
+
+double LineSearchFunction::DirectionInfinityNorm() const {
+ return direction_.lpNorm<Eigen::Infinity>();
+}
+
+void LineSearchFunction::ResetTimeStatistics() {
+ const map<string, double> evaluator_time_statistics =
+ evaluator_->TimeStatistics();
+ initial_evaluator_residual_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ initial_evaluator_jacobian_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+}
+
+void LineSearchFunction::TimeStatistics(
+ double* cost_evaluation_time_in_seconds,
+ double* gradient_evaluation_time_in_seconds) const {
+ const map<string, double> evaluator_time_statistics =
+ evaluator_->TimeStatistics();
+ *cost_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0) -
+ initial_evaluator_residual_time_in_seconds;
+ // Strictly speaking this will slightly underestimate the time spent
+ // evaluating the gradient of the line search univariate cost function as it
+ // does not count the time spent performing the dot product with the direction
+ // vector. However, this will typically be small by comparison, and also
+ // allows direct subtraction of the timing information from the totals for
+ // the evaluator returned in the solver summary.
+ *gradient_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0) -
+ initial_evaluator_jacobian_time_in_seconds;
+}
+
+void LineSearch::Search(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const {
+ const double start_time = WallTimeInSeconds();
+ *CHECK_NOTNULL(summary) = LineSearch::Summary();
+
+ summary->cost_evaluation_time_in_seconds = 0.0;
+ summary->gradient_evaluation_time_in_seconds = 0.0;
+ summary->polynomial_minimization_time_in_seconds = 0.0;
+
+ options().function->ResetTimeStatistics();
+ this->DoSearch(step_size_estimate, initial_cost, initial_gradient, summary);
+ options().function->
+ TimeStatistics(&summary->cost_evaluation_time_in_seconds,
+ &summary->gradient_evaluation_time_in_seconds);
+
+ summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
+}
+
+// Returns step_size \in [min_step_size, max_step_size] which minimizes the
+// polynomial of degree defined by interpolation_type which interpolates all
+// of the provided samples with valid values.
+double LineSearch::InterpolatingPolynomialMinimizingStepSize(
+ const LineSearchInterpolationType& interpolation_type,
+ const FunctionSample& lowerbound,
+ const FunctionSample& previous,
+ const FunctionSample& current,
+ const double min_step_size,
+ const double max_step_size) const {
+ if (!current.value_is_valid ||
+ (interpolation_type == BISECTION &&
+ max_step_size <= current.x)) {
+ // Either: sample is invalid; or we are using BISECTION and contracting
+ // the step size.
+ return std::min(std::max(current.x * 0.5, min_step_size), max_step_size);
+ } else if (interpolation_type == BISECTION) {
+ CHECK_GT(max_step_size, current.x);
+ // We are expanding the search (during a Wolfe bracketing phase) using
+ // BISECTION interpolation. Using BISECTION when trying to expand is
+ // strictly speaking an oxymoron, but we define this to mean always taking
+ // the maximum step size so that the Armijo & Wolfe implementations are
+ // agnostic to the interpolation type.
+ return max_step_size;
+ }
+ // Only check if lower-bound is valid here, where it is required
+ // to avoid replicating current.value_is_valid == false
+ // behaviour in WolfeLineSearch.
+ CHECK(lowerbound.value_is_valid)
+ << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
+ << "Ceres bug: lower-bound sample for interpolation is invalid, "
+ << "please contact the developers!, interpolation_type: "
+ << LineSearchInterpolationTypeToString(interpolation_type)
+ << ", lowerbound: " << lowerbound << ", previous: " << previous
+ << ", current: " << current;
+
+ // Select step size by interpolating the function and gradient values
+ // and minimizing the corresponding polynomial.
+ vector<FunctionSample> samples;
+ samples.push_back(lowerbound);
+
+ if (interpolation_type == QUADRATIC) {
+ // Two point interpolation using function values and the
+ // gradient at the lower bound.
+ samples.push_back(ValueSample(current.x, current.value));
+
+ if (previous.value_is_valid) {
+ // Three point interpolation, using function values and the
+ // gradient at the lower bound.
+ samples.push_back(ValueSample(previous.x, previous.value));
+ }
+ } else if (interpolation_type == CUBIC) {
+ // Two point interpolation using the function values and the gradients.
+ samples.push_back(current);
+
+ if (previous.value_is_valid) {
+ // Three point interpolation using the function values and
+ // the gradients.
+ samples.push_back(previous);
+ }
+ } else {
+ LOG(FATAL) << "Ceres bug: No handler for interpolation_type: "
+ << LineSearchInterpolationTypeToString(interpolation_type)
+ << ", please contact the developers!";
+ }
+
+ double step_size = 0.0, unused_min_value = 0.0;
+ MinimizeInterpolatingPolynomial(samples, min_step_size, max_step_size,
+ &step_size, &unused_min_value);
+ return step_size;
+}
+
+ArmijoLineSearch::ArmijoLineSearch(const LineSearch::Options& options)
+ : LineSearch(options) {}
+
+void ArmijoLineSearch::DoSearch(const double step_size_estimate,
+ const double initial_cost,
+ const double initial_gradient,
+ Summary* summary) const {
+ CHECK_GE(step_size_estimate, 0.0);
+ CHECK_GT(options().sufficient_decrease, 0.0);
+ CHECK_LT(options().sufficient_decrease, 1.0);
+ CHECK_GT(options().max_num_iterations, 0);
+ LineSearchFunction* function = options().function;
+
+ // Note initial_cost & initial_gradient are evaluated at step_size = 0,
+ // not step_size_estimate, which is our starting guess.
+ const FunctionSample initial_position =
+ ValueAndGradientSample(0.0, initial_cost, initial_gradient);
+
+ FunctionSample previous = ValueAndGradientSample(0.0, 0.0, 0.0);
+ previous.value_is_valid = false;
+
+ FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
+ current.value_is_valid = false;
+
+ // As the Armijo line search algorithm always uses the initial point, for
+ // which both the function value and derivative are known, when fitting a
+ // minimizing polynomial, we can fit up to a quadratic without requiring the
+ // gradient at the current query point.
+ const bool interpolation_uses_gradient_at_current_sample =
+ options().interpolation_type == CUBIC;
+ const double descent_direction_max_norm = function->DirectionInfinityNorm();
+
+ ++summary->num_function_evaluations;
+ if (interpolation_uses_gradient_at_current_sample) {
+ ++summary->num_gradient_evaluations;
+ }
+ current.value_is_valid =
+ function->Evaluate(current.x,
+ &current.value,
+ interpolation_uses_gradient_at_current_sample
+ ? &current.gradient : NULL);
+ current.gradient_is_valid =
+ interpolation_uses_gradient_at_current_sample && current.value_is_valid;
+ while (!current.value_is_valid ||
+ current.value > (initial_cost
+ + options().sufficient_decrease
+ * initial_gradient
+ * current.x)) {
+ // If current.value_is_valid is false, we treat it as if the cost at that
+ // point is not large enough to satisfy the sufficient decrease condition.
+ ++summary->num_iterations;
+ if (summary->num_iterations >= options().max_num_iterations) {
+ summary->error =
+ StringPrintf("Line search failed: Armijo failed to find a point "
+ "satisfying the sufficient decrease condition within "
+ "specified max_num_iterations: %d.",
+ options().max_num_iterations);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ return;
+ }
+
+ const double polynomial_minimization_start_time = WallTimeInSeconds();
+ const double step_size =
+ this->InterpolatingPolynomialMinimizingStepSize(
+ options().interpolation_type,
+ initial_position,
+ previous,
+ current,
+ (options().max_step_contraction * current.x),
+ (options().min_step_contraction * current.x));
+ summary->polynomial_minimization_time_in_seconds +=
+ (WallTimeInSeconds() - polynomial_minimization_start_time);
+
+ if (step_size * descent_direction_max_norm < options().min_step_size) {
+ summary->error =
+ StringPrintf("Line search failed: step_size too small: %.5e "
+ "with descent_direction_max_norm: %.5e.", step_size,
+ descent_direction_max_norm);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ return;
+ }
+
+ previous = current;
+ current.x = step_size;
+
+ ++summary->num_function_evaluations;
+ if (interpolation_uses_gradient_at_current_sample) {
+ ++summary->num_gradient_evaluations;
+ }
+ current.value_is_valid =
+ function->Evaluate(current.x,
+ &current.value,
+ interpolation_uses_gradient_at_current_sample
+ ? &current.gradient : NULL);
+ current.gradient_is_valid =
+ interpolation_uses_gradient_at_current_sample && current.value_is_valid;
+ }
+
+ summary->optimal_step_size = current.x;
+ summary->success = true;
+}
+
+WolfeLineSearch::WolfeLineSearch(const LineSearch::Options& options)
+ : LineSearch(options) {}
+
+void WolfeLineSearch::DoSearch(const double step_size_estimate,
+ const double initial_cost,
+ const double initial_gradient,
+ Summary* summary) const {
+ // All parameters should have been validated by the Solver, but as
+ // invalid values would produce crazy nonsense, hard check them here.
+ CHECK_GE(step_size_estimate, 0.0);
+ CHECK_GT(options().sufficient_decrease, 0.0);
+ CHECK_GT(options().sufficient_curvature_decrease,
+ options().sufficient_decrease);
+ CHECK_LT(options().sufficient_curvature_decrease, 1.0);
+ CHECK_GT(options().max_step_expansion, 1.0);
+
+ // Note initial_cost & initial_gradient are evaluated at step_size = 0,
+ // not step_size_estimate, which is our starting guess.
+ const FunctionSample initial_position =
+ ValueAndGradientSample(0.0, initial_cost, initial_gradient);
+
+ bool do_zoom_search = false;
+ // Important: The high/low in bracket_high & bracket_low refer to their
+ // _function_ values, not their step sizes i.e. it is _not_ required that
+ // bracket_low.x < bracket_high.x.
+ FunctionSample solution, bracket_low, bracket_high;
+
+ // Wolfe bracketing phase: Increases step_size until either it finds a point
+ // that satisfies the (strong) Wolfe conditions, or an interval that brackets
+ // step sizes which satisfy the conditions. From Nocedal & Wright [1] p61 the
+ // interval: (step_size_{k-1}, step_size_{k}) contains step lengths satisfying
+ // the strong Wolfe conditions if one of the following conditions are met:
+ //
+ // 1. step_size_{k} violates the sufficient decrease (Armijo) condition.
+ // 2. f(step_size_{k}) >= f(step_size_{k-1}).
+ // 3. f'(step_size_{k}) >= 0.
+ //
+ // Caveat: If f(step_size_{k}) is invalid, then step_size is reduced, ignoring
+ // this special case, step_size monotonically increases during bracketing.
+ if (!this->BracketingPhase(initial_position,
+ step_size_estimate,
+ &bracket_low,
+ &bracket_high,
+ &do_zoom_search,
+ summary)) {
+ // Failed to find either a valid point, a valid bracket satisfying the Wolfe
+ // conditions, or even a step size > minimum tolerance satisfying the Armijo
+ // condition.
+ return;
+ }
+
+ if (!do_zoom_search) {
+ // Either: Bracketing phase already found a point satisfying the strong
+ // Wolfe conditions, thus no Zoom required.
+ //
+ // Or: Bracketing failed to find a valid bracket or a point satisfying the
+ // strong Wolfe conditions within max_num_iterations, or whilst searching
+ // shrank the bracket width until it was below our minimum tolerance.
+ // As these are 'artificial' constraints, and we would otherwise fail to
+ // produce a valid point when ArmijoLineSearch would succeed, we return the
+ // point with the lowest cost found thus far which satsifies the Armijo
+ // condition (but not the Wolfe conditions).
+ summary->optimal_step_size = bracket_low.x;
+ summary->success = true;
+ return;
+ }
+
+ VLOG(3) << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
+ << "Starting line search zoom phase with bracket_low: "
+ << bracket_low << ", bracket_high: " << bracket_high
+ << ", bracket width: " << fabs(bracket_low.x - bracket_high.x)
+ << ", bracket abs delta cost: "
+ << fabs(bracket_low.value - bracket_high.value);
+
+ // Wolfe Zoom phase: Called when the Bracketing phase finds an interval of
+ // non-zero, finite width that should bracket step sizes which satisfy the
+ // (strong) Wolfe conditions (before finding a step size that satisfies the
+ // conditions). Zoom successively decreases the size of the interval until a
+ // step size which satisfies the Wolfe conditions is found. The interval is
+ // defined by bracket_low & bracket_high, which satisfy:
+ //
+ // 1. The interval bounded by step sizes: bracket_low.x & bracket_high.x
+ // contains step sizes that satsify the strong Wolfe conditions.
+ // 2. bracket_low.x is of all the step sizes evaluated *which satisifed the
+ // Armijo sufficient decrease condition*, the one which generated the
+ // smallest function value, i.e. bracket_low.value <
+ // f(all other steps satisfying Armijo).
+ // - Note that this does _not_ (necessarily) mean that initially
+ // bracket_low.value < bracket_high.value (although this is typical)
+ // e.g. when bracket_low = initial_position, and bracket_high is the
+ // first sample, and which does not satisfy the Armijo condition,
+ // but still has bracket_high.value < initial_position.value.
+ // 3. bracket_high is chosen after bracket_low, s.t.
+ // bracket_low.gradient * (bracket_high.x - bracket_low.x) < 0.
+ if (!this->ZoomPhase(initial_position,
+ bracket_low,
+ bracket_high,
+ &solution,
+ summary) && !solution.value_is_valid) {
+ // Failed to find a valid point (given the specified decrease parameters)
+ // within the specified bracket.
+ return;
+ }
+ // Ensure that if we ran out of iterations whilst zooming the bracket, or
+ // shrank the bracket width to < tolerance and failed to find a point which
+ // satisfies the strong Wolfe curvature condition, that we return the point
+ // amongst those found thus far, which minimizes f() and satisfies the Armijo
+ // condition.
+ solution =
+ solution.value_is_valid && solution.value <= bracket_low.value
+ ? solution : bracket_low;
+
+ summary->optimal_step_size = solution.x;
+ summary->success = true;
+}
+
+// Returns true if either:
+//
+// A termination condition satisfying the (strong) Wolfe bracketing conditions
+// is found:
+//
+// - A valid point, defined as a bracket of zero width [zoom not required].
+// - A valid bracket (of width > tolerance), [zoom required].
+//
+// Or, searching was stopped due to an 'artificial' constraint, i.e. not
+// a condition imposed / required by the underlying algorithm, but instead an
+// engineering / implementation consideration. But a step which exceeds the
+// minimum step size, and satsifies the Armijo condition was still found,
+// and should thus be used [zoom not required].
+//
+// Returns false if no step size > minimum step size was found which
+// satisfies at least the Armijo condition.
+bool WolfeLineSearch::BracketingPhase(
+ const FunctionSample& initial_position,
+ const double step_size_estimate,
+ FunctionSample* bracket_low,
+ FunctionSample* bracket_high,
+ bool* do_zoom_search,
+ Summary* summary) const {
+ LineSearchFunction* function = options().function;
+
+ FunctionSample previous = initial_position;
+ FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
+ current.value_is_valid = false;
+
+ const double descent_direction_max_norm =
+ function->DirectionInfinityNorm();
+
+ *do_zoom_search = false;
+ *bracket_low = initial_position;
+
+ // As we require the gradient to evaluate the Wolfe condition, we always
+ // calculate it together with the value, irrespective of the interpolation
+ // type. As opposed to only calculating the gradient after the Armijo
+ // condition is satisifed, as the computational saving from this approach
+ // would be slight (perhaps even negative due to the extra call). Also,
+ // always calculating the value & gradient together protects against us
+ // reporting invalid solutions if the cost function returns slightly different
+ // function values when evaluated with / without gradients (due to numerical
+ // issues).
+ ++summary->num_function_evaluations;
+ ++summary->num_gradient_evaluations;
+ current.value_is_valid =
+ function->Evaluate(current.x,
+ &current.value,
+ &current.gradient);
+ current.gradient_is_valid = current.value_is_valid;
+
+ while (true) {
+ ++summary->num_iterations;
+
+ if (current.value_is_valid &&
+ (current.value > (initial_position.value
+ + options().sufficient_decrease
+ * initial_position.gradient
+ * current.x) ||
+ (previous.value_is_valid && current.value > previous.value))) {
+ // Bracket found: current step size violates Armijo sufficient decrease
+ // condition, or has stepped past an inflection point of f() relative to
+ // previous step size.
+ *do_zoom_search = true;
+ *bracket_low = previous;
+ *bracket_high = current;
+ VLOG(3) << std::scientific
+ << std::setprecision(kErrorMessageNumericPrecision)
+ << "Bracket found: current step (" << current.x
+ << ") violates Armijo sufficient condition, or has passed an "
+ << "inflection point of f() based on value.";
+ break;
+ }
+
+ if (current.value_is_valid &&
+ fabs(current.gradient) <=
+ -options().sufficient_curvature_decrease * initial_position.gradient) {
+ // Current step size satisfies the strong Wolfe conditions, and is thus a
+ // valid termination point, therefore a Zoom not required.
+ *bracket_low = current;
+ *bracket_high = current;
+ VLOG(3) << std::scientific
+ << std::setprecision(kErrorMessageNumericPrecision)
+ << "Bracketing phase found step size: " << current.x
+ << ", satisfying strong Wolfe conditions, initial_position: "
+ << initial_position << ", current: " << current;
+ break;
+
+ } else if (current.value_is_valid && current.gradient >= 0) {
+ // Bracket found: current step size has stepped past an inflection point
+ // of f(), but Armijo sufficient decrease is still satisfied and
+ // f(current) is our best minimum thus far. Remember step size
+ // monotonically increases, thus previous_step_size < current_step_size
+ // even though f(previous) > f(current).
+ *do_zoom_search = true;
+ // Note inverse ordering from first bracket case.
+ *bracket_low = current;
+ *bracket_high = previous;
+ VLOG(3) << "Bracket found: current step (" << current.x
+ << ") satisfies Armijo, but has gradient >= 0, thus have passed "
+ << "an inflection point of f().";
+ break;
+
+ } else if (current.value_is_valid &&
+ fabs(current.x - previous.x) * descent_direction_max_norm
+ < options().min_step_size) {
+ // We have shrunk the search bracket to a width less than our tolerance,
+ // and still not found either a point satisfying the strong Wolfe
+ // conditions, or a valid bracket containing such a point. Stop searching
+ // and set bracket_low to the size size amongst all those tested which
+ // minimizes f() and satisfies the Armijo condition.
+ LOG_IF(WARNING, !options().is_silent)
+ << "Line search failed: Wolfe bracketing phase shrank "
+ << "bracket width: " << fabs(current.x - previous.x)
+ << ", to < tolerance: " << options().min_step_size
+ << ", with descent_direction_max_norm: "
+ << descent_direction_max_norm << ", and failed to find "
+ << "a point satisfying the strong Wolfe conditions or a "
+ << "bracketing containing such a point. Accepting "
+ << "point found satisfying Armijo condition only, to "
+ << "allow continuation.";
+ *bracket_low = current;
+ break;
+
+ } else if (summary->num_iterations >= options().max_num_iterations) {
+ // Check num iterations bound here so that we always evaluate the
+ // max_num_iterations-th iteration against all conditions, and
+ // then perform no additional (unused) evaluations.
+ summary->error =
+ StringPrintf("Line search failed: Wolfe bracketing phase failed to "
+ "find a point satisfying strong Wolfe conditions, or a "
+ "bracket containing such a point within specified "
+ "max_num_iterations: %d", options().max_num_iterations);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ // Ensure that bracket_low is always set to the step size amongst all
+ // those tested which minimizes f() and satisfies the Armijo condition
+ // when we terminate due to the 'artificial' max_num_iterations condition.
+ *bracket_low =
+ current.value_is_valid && current.value < bracket_low->value
+ ? current : *bracket_low;
+ break;
+ }
+ // Either: f(current) is invalid; or, f(current) is valid, but does not
+ // satisfy the strong Wolfe conditions itself, or the conditions for
+ // being a boundary of a bracket.
+
+ // If f(current) is valid, (but meets no criteria) expand the search by
+ // increasing the step size.
+ const double max_step_size =
+ current.value_is_valid
+ ? (current.x * options().max_step_expansion) : current.x;
+
+ // We are performing 2-point interpolation only here, but the API of
+ // InterpolatingPolynomialMinimizingStepSize() allows for up to
+ // 3-point interpolation, so pad call with a sample with an invalid
+ // value that will therefore be ignored.
+ const FunctionSample unused_previous;
+ DCHECK(!unused_previous.value_is_valid);
+ // Contracts step size if f(current) is not valid.
+ const double polynomial_minimization_start_time = WallTimeInSeconds();
+ const double step_size =
+ this->InterpolatingPolynomialMinimizingStepSize(
+ options().interpolation_type,
+ previous,
+ unused_previous,
+ current,
+ previous.x,
+ max_step_size);
+ summary->polynomial_minimization_time_in_seconds +=
+ (WallTimeInSeconds() - polynomial_minimization_start_time);
+ if (step_size * descent_direction_max_norm < options().min_step_size) {
+ summary->error =
+ StringPrintf("Line search failed: step_size too small: %.5e "
+ "with descent_direction_max_norm: %.5e", step_size,
+ descent_direction_max_norm);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ return false;
+ }
+
+ previous = current.value_is_valid ? current : previous;
+ current.x = step_size;
+
+ ++summary->num_function_evaluations;
+ ++summary->num_gradient_evaluations;
+ current.value_is_valid =
+ function->Evaluate(current.x,
+ &current.value,
+ &current.gradient);
+ current.gradient_is_valid = current.value_is_valid;
+ }
+
+ // Ensure that even if a valid bracket was found, we will only mark a zoom
+ // as required if the bracket's width is greater than our minimum tolerance.
+ if (*do_zoom_search &&
+ fabs(bracket_high->x - bracket_low->x) * descent_direction_max_norm
+ < options().min_step_size) {
+ *do_zoom_search = false;
+ }
+
+ return true;
+}
+
+// Returns true iff solution satisfies the strong Wolfe conditions. Otherwise,
+// on return false, if we stopped searching due to the 'artificial' condition of
+// reaching max_num_iterations, solution is the step size amongst all those
+// tested, which satisfied the Armijo decrease condition and minimized f().
+bool WolfeLineSearch::ZoomPhase(const FunctionSample& initial_position,
+ FunctionSample bracket_low,
+ FunctionSample bracket_high,
+ FunctionSample* solution,
+ Summary* summary) const {
+ LineSearchFunction* function = options().function;
+
+ CHECK(bracket_low.value_is_valid && bracket_low.gradient_is_valid)
+ << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
+ << "Ceres bug: f_low input to Wolfe Zoom invalid, please contact "
+ << "the developers!, initial_position: " << initial_position
+ << ", bracket_low: " << bracket_low
+ << ", bracket_high: "<< bracket_high;
+ // We do not require bracket_high.gradient_is_valid as the gradient condition
+ // for a valid bracket is only dependent upon bracket_low.gradient, and
+ // in order to minimize jacobian evaluations, bracket_high.gradient may
+ // not have been calculated (if bracket_high.value does not satisfy the
+ // Armijo sufficient decrease condition and interpolation method does not
+ // require it).
+ //
+ // We also do not require that: bracket_low.value < bracket_high.value,
+ // although this is typical. This is to deal with the case when
+ // bracket_low = initial_position, bracket_high is the first sample,
+ // and bracket_high does not satisfy the Armijo condition, but still has
+ // bracket_high.value < initial_position.value.
+ CHECK(bracket_high.value_is_valid)
+ << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
+ << "Ceres bug: f_high input to Wolfe Zoom invalid, please "
+ << "contact the developers!, initial_position: " << initial_position
+ << ", bracket_low: " << bracket_low
+ << ", bracket_high: "<< bracket_high;
+
+ if (bracket_low.gradient * (bracket_high.x - bracket_low.x) >= 0) {
+ // The third condition for a valid initial bracket:
+ //
+ // 3. bracket_high is chosen after bracket_low, s.t.
+ // bracket_low.gradient * (bracket_high.x - bracket_low.x) < 0.
+ //
+ // is not satisfied. As this can happen when the users' cost function
+ // returns inconsistent gradient values relative to the function values,
+ // we do not CHECK_LT(), but we do stop processing and return an invalid
+ // value.
+ summary->error =
+ StringPrintf("Line search failed: Wolfe zoom phase passed a bracket "
+ "which does not satisfy: bracket_low.gradient * "
+ "(bracket_high.x - bracket_low.x) < 0 [%.8e !< 0] "
+ "with initial_position: %s, bracket_low: %s, bracket_high:"
+ " %s, the most likely cause of which is the cost function "
+ "returning inconsistent gradient & function values.",
+ bracket_low.gradient * (bracket_high.x - bracket_low.x),
+ initial_position.ToDebugString().c_str(),
+ bracket_low.ToDebugString().c_str(),
+ bracket_high.ToDebugString().c_str());
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ solution->value_is_valid = false;
+ return false;
+ }
+
+ const int num_bracketing_iterations = summary->num_iterations;
+ const double descent_direction_max_norm = function->DirectionInfinityNorm();
+
+ while (true) {
+ // Set solution to bracket_low, as it is our best step size (smallest f())
+ // found thus far and satisfies the Armijo condition, even though it does
+ // not satisfy the Wolfe condition.
+ *solution = bracket_low;
+ if (summary->num_iterations >= options().max_num_iterations) {
+ summary->error =
+ StringPrintf("Line search failed: Wolfe zoom phase failed to "
+ "find a point satisfying strong Wolfe conditions "
+ "within specified max_num_iterations: %d, "
+ "(num iterations taken for bracketing: %d).",
+ options().max_num_iterations, num_bracketing_iterations);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ return false;
+ }
+ if (fabs(bracket_high.x - bracket_low.x) * descent_direction_max_norm
+ < options().min_step_size) {
+ // Bracket width has been reduced below tolerance, and no point satisfying
+ // the strong Wolfe conditions has been found.
+ summary->error =
+ StringPrintf("Line search failed: Wolfe zoom bracket width: %.5e "
+ "too small with descent_direction_max_norm: %.5e.",
+ fabs(bracket_high.x - bracket_low.x),
+ descent_direction_max_norm);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ return false;
+ }
+
+ ++summary->num_iterations;
+ // Polynomial interpolation requires inputs ordered according to step size,
+ // not f(step size).
+ const FunctionSample& lower_bound_step =
+ bracket_low.x < bracket_high.x ? bracket_low : bracket_high;
+ const FunctionSample& upper_bound_step =
+ bracket_low.x < bracket_high.x ? bracket_high : bracket_low;
+ // We are performing 2-point interpolation only here, but the API of
+ // InterpolatingPolynomialMinimizingStepSize() allows for up to
+ // 3-point interpolation, so pad call with a sample with an invalid
+ // value that will therefore be ignored.
+ const FunctionSample unused_previous;
+ DCHECK(!unused_previous.value_is_valid);
+ const double polynomial_minimization_start_time = WallTimeInSeconds();
+ solution->x =
+ this->InterpolatingPolynomialMinimizingStepSize(
+ options().interpolation_type,
+ lower_bound_step,
+ unused_previous,
+ upper_bound_step,
+ lower_bound_step.x,
+ upper_bound_step.x);
+ summary->polynomial_minimization_time_in_seconds +=
+ (WallTimeInSeconds() - polynomial_minimization_start_time);
+ // No check on magnitude of step size being too small here as it is
+ // lower-bounded by the initial bracket start point, which was valid.
+ //
+ // As we require the gradient to evaluate the Wolfe condition, we always
+ // calculate it together with the value, irrespective of the interpolation
+ // type. As opposed to only calculating the gradient after the Armijo
+ // condition is satisifed, as the computational saving from this approach
+ // would be slight (perhaps even negative due to the extra call). Also,
+ // always calculating the value & gradient together protects against us
+ // reporting invalid solutions if the cost function returns slightly
+ // different function values when evaluated with / without gradients (due
+ // to numerical issues).
+ ++summary->num_function_evaluations;
+ ++summary->num_gradient_evaluations;
+ solution->value_is_valid =
+ function->Evaluate(solution->x,
+ &solution->value,
+ &solution->gradient);
+ solution->gradient_is_valid = solution->value_is_valid;
+ if (!solution->value_is_valid) {
+ summary->error =
+ StringPrintf("Line search failed: Wolfe Zoom phase found "
+ "step_size: %.5e, for which function is invalid, "
+ "between low_step: %.5e and high_step: %.5e "
+ "at which function is valid.",
+ solution->x, bracket_low.x, bracket_high.x);
+ LOG_IF(WARNING, !options().is_silent) << summary->error;
+ return false;
+ }
+
+ VLOG(3) << "Zoom iteration: "
+ << summary->num_iterations - num_bracketing_iterations
+ << ", bracket_low: " << bracket_low
+ << ", bracket_high: " << bracket_high
+ << ", minimizing solution: " << *solution;
+
+ if ((solution->value > (initial_position.value
+ + options().sufficient_decrease
+ * initial_position.gradient
+ * solution->x)) ||
+ (solution->value >= bracket_low.value)) {
+ // Armijo sufficient decrease not satisfied, or not better
+ // than current lowest sample, use as new upper bound.
+ bracket_high = *solution;
+ continue;
+ }
+
+ // Armijo sufficient decrease satisfied, check strong Wolfe condition.
+ if (fabs(solution->gradient) <=
+ -options().sufficient_curvature_decrease * initial_position.gradient) {
+ // Found a valid termination point satisfying strong Wolfe conditions.
+ VLOG(3) << std::scientific
+ << std::setprecision(kErrorMessageNumericPrecision)
+ << "Zoom phase found step size: " << solution->x
+ << ", satisfying strong Wolfe conditions.";
+ break;
+
+ } else if (solution->gradient * (bracket_high.x - bracket_low.x) >= 0) {
+ bracket_high = bracket_low;
+ }
+
+ bracket_low = *solution;
+ }
+ // Solution contains a valid point which satisfies the strong Wolfe
+ // conditions.
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/line_search.h b/extern/ceres/internal/ceres/line_search.h
new file mode 100644
index 00000000000..6a21cbeac11
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search.h
@@ -0,0 +1,327 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Interface for and implementation of various Line search algorithms.
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_H_
+#define CERES_INTERNAL_LINE_SEARCH_H_
+
+#include <string>
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class Evaluator;
+struct FunctionSample;
+class LineSearchFunction;
+
+// Line search is another name for a one dimensional optimization
+// algorithm. The name "line search" comes from the fact one
+// dimensional optimization problems that arise as subproblems of
+// general multidimensional optimization problems.
+//
+// While finding the exact minimum of a one dimensionl function is
+// hard, instances of LineSearch find a point that satisfies a
+// sufficient decrease condition. Depending on the particular
+// condition used, we get a variety of different line search
+// algorithms, e.g., Armijo, Wolfe etc.
+class LineSearch {
+ public:
+ struct Summary;
+
+ struct Options {
+ Options()
+ : interpolation_type(CUBIC),
+ sufficient_decrease(1e-4),
+ max_step_contraction(1e-3),
+ min_step_contraction(0.9),
+ min_step_size(1e-9),
+ max_num_iterations(20),
+ sufficient_curvature_decrease(0.9),
+ max_step_expansion(10.0),
+ is_silent(false),
+ function(NULL) {}
+
+ // Degree of the polynomial used to approximate the objective
+ // function.
+ LineSearchInterpolationType interpolation_type;
+
+ // Armijo and Wolfe line search parameters.
+
+ // Solving the line search problem exactly is computationally
+ // prohibitive. Fortunately, line search based optimization
+ // algorithms can still guarantee convergence if instead of an
+ // exact solution, the line search algorithm returns a solution
+ // which decreases the value of the objective function
+ // sufficiently. More precisely, we are looking for a step_size
+ // s.t.
+ //
+ // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
+ double sufficient_decrease;
+
+ // In each iteration of the Armijo / Wolfe line search,
+ //
+ // new_step_size >= max_step_contraction * step_size
+ //
+ // Note that by definition, for contraction:
+ //
+ // 0 < max_step_contraction < min_step_contraction < 1
+ //
+ double max_step_contraction;
+
+ // In each iteration of the Armijo / Wolfe line search,
+ //
+ // new_step_size <= min_step_contraction * step_size
+ // Note that by definition, for contraction:
+ //
+ // 0 < max_step_contraction < min_step_contraction < 1
+ //
+ double min_step_contraction;
+
+ // If during the line search, the step_size falls below this
+ // value, it is truncated to zero.
+ double min_step_size;
+
+ // Maximum number of trial step size iterations during each line search,
+ // if a step size satisfying the search conditions cannot be found within
+ // this number of trials, the line search will terminate.
+ int max_num_iterations;
+
+ // Wolfe-specific line search parameters.
+
+ // The strong Wolfe conditions consist of the Armijo sufficient
+ // decrease condition, and an additional requirement that the
+ // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
+ // conditions) of the gradient along the search direction
+ // decreases sufficiently. Precisely, this second condition
+ // is that we seek a step_size s.t.
+ //
+ // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
+ //
+ // Where f() is the line search objective and f'() is the derivative
+ // of f w.r.t step_size (d f / d step_size).
+ double sufficient_curvature_decrease;
+
+ // During the bracketing phase of the Wolfe search, the step size is
+ // increased until either a point satisfying the Wolfe conditions is
+ // found, or an upper bound for a bracket containing a point satisfying
+ // the conditions is found. Precisely, at each iteration of the
+ // expansion:
+ //
+ // new_step_size <= max_step_expansion * step_size.
+ //
+ // By definition for expansion, max_step_expansion > 1.0.
+ double max_step_expansion;
+
+ bool is_silent;
+
+ // The one dimensional function that the line search algorithm
+ // minimizes.
+ LineSearchFunction* function;
+ };
+
+ // Result of the line search.
+ struct Summary {
+ Summary()
+ : success(false),
+ optimal_step_size(0.0),
+ num_function_evaluations(0),
+ num_gradient_evaluations(0),
+ num_iterations(0),
+ cost_evaluation_time_in_seconds(-1.0),
+ gradient_evaluation_time_in_seconds(-1.0),
+ polynomial_minimization_time_in_seconds(-1.0),
+ total_time_in_seconds(-1.0) {}
+
+ bool success;
+ double optimal_step_size;
+ int num_function_evaluations;
+ int num_gradient_evaluations;
+ int num_iterations;
+ // Cumulative time spent evaluating the value of the cost function across
+ // all iterations.
+ double cost_evaluation_time_in_seconds;
+ // Cumulative time spent evaluating the gradient of the cost function across
+ // all iterations.
+ double gradient_evaluation_time_in_seconds;
+ // Cumulative time spent minimizing the interpolating polynomial to compute
+ // the next candidate step size across all iterations.
+ double polynomial_minimization_time_in_seconds;
+ double total_time_in_seconds;
+ std::string error;
+ };
+
+ explicit LineSearch(const LineSearch::Options& options);
+ virtual ~LineSearch() {}
+
+ static LineSearch* Create(const LineSearchType line_search_type,
+ const LineSearch::Options& options,
+ std::string* error);
+
+ // Perform the line search.
+ //
+ // step_size_estimate must be a positive number.
+ //
+ // initial_cost and initial_gradient are the values and gradient of
+ // the function at zero.
+ // summary must not be null and will contain the result of the line
+ // search.
+ //
+ // Summary::success is true if a non-zero step size is found.
+ void Search(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const;
+ double InterpolatingPolynomialMinimizingStepSize(
+ const LineSearchInterpolationType& interpolation_type,
+ const FunctionSample& lowerbound_sample,
+ const FunctionSample& previous_sample,
+ const FunctionSample& current_sample,
+ const double min_step_size,
+ const double max_step_size) const;
+
+ protected:
+ const LineSearch::Options& options() const { return options_; }
+
+ private:
+ virtual void DoSearch(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const = 0;
+
+ private:
+ LineSearch::Options options_;
+};
+
+// An object used by the line search to access the function values
+// and gradient of the one dimensional function being optimized.
+//
+// In practice, this object provides access to the objective
+// function value and the directional derivative of the underlying
+// optimization problem along a specific search direction.
+class LineSearchFunction {
+ public:
+ explicit LineSearchFunction(Evaluator* evaluator);
+ void Init(const Vector& position, const Vector& direction);
+ // Evaluate the line search objective
+ //
+ // f(x) = p(position + x * direction)
+ //
+ // Where, p is the objective function of the general optimization
+ // problem.
+ //
+ // g is the gradient f'(x) at x.
+ //
+ // f must not be null. The gradient is computed only if g is not null.
+ bool Evaluate(double x, double* f, double* g);
+ double DirectionInfinityNorm() const;
+ // Resets to now, the start point for the results from TimeStatistics().
+ void ResetTimeStatistics();
+ void TimeStatistics(double* cost_evaluation_time_in_seconds,
+ double* gradient_evaluation_time_in_seconds) const;
+
+ private:
+ Evaluator* evaluator_;
+ Vector position_;
+ Vector direction_;
+
+ // evaluation_point = Evaluator::Plus(position_, x * direction_);
+ Vector evaluation_point_;
+
+ // scaled_direction = x * direction_;
+ Vector scaled_direction_;
+ Vector gradient_;
+
+ // We may not exclusively own the evaluator (e.g. in the Trust Region
+ // minimizer), hence we need to save the initial evaluation durations for the
+ // value & gradient to accurately determine the duration of the evaluations
+ // we invoked. These are reset by a call to ResetTimeStatistics().
+ double initial_evaluator_residual_time_in_seconds;
+ double initial_evaluator_jacobian_time_in_seconds;
+};
+
+// Backtracking and interpolation based Armijo line search. This
+// implementation is based on the Armijo line search that ships in the
+// minFunc package by Mark Schmidt.
+//
+// For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html
+class ArmijoLineSearch : public LineSearch {
+ public:
+ explicit ArmijoLineSearch(const LineSearch::Options& options);
+ virtual ~ArmijoLineSearch() {}
+
+ private:
+ virtual void DoSearch(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const;
+};
+
+// Bracketing / Zoom Strong Wolfe condition line search. This implementation
+// is based on the pseudo-code algorithm presented in Nocedal & Wright [1]
+// (p60-61) with inspiration from the WolfeLineSearch which ships with the
+// minFunc package by Mark Schmidt [2].
+//
+// [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed., Springer, 1999.
+// [2] http://www.di.ens.fr/~mschmidt/Software/minFunc.html.
+class WolfeLineSearch : public LineSearch {
+ public:
+ explicit WolfeLineSearch(const LineSearch::Options& options);
+ virtual ~WolfeLineSearch() {}
+
+ // Returns true iff either a valid point, or valid bracket are found.
+ bool BracketingPhase(const FunctionSample& initial_position,
+ const double step_size_estimate,
+ FunctionSample* bracket_low,
+ FunctionSample* bracket_high,
+ bool* perform_zoom_search,
+ Summary* summary) const;
+ // Returns true iff final_line_sample satisfies strong Wolfe conditions.
+ bool ZoomPhase(const FunctionSample& initial_position,
+ FunctionSample bracket_low,
+ FunctionSample bracket_high,
+ FunctionSample* solution,
+ Summary* summary) const;
+
+ private:
+ virtual void DoSearch(double step_size_estimate,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) const;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINE_SEARCH_H_
diff --git a/extern/ceres/internal/ceres/line_search_direction.cc b/extern/ceres/internal/ceres/line_search_direction.cc
new file mode 100644
index 00000000000..1f9d205bff5
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search_direction.cc
@@ -0,0 +1,372 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search_direction.h"
+#include "ceres/line_search_minimizer.h"
+#include "ceres/low_rank_inverse_hessian.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+class SteepestDescent : public LineSearchDirection {
+ public:
+ virtual ~SteepestDescent() {}
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ *search_direction = -current.gradient;
+ return true;
+ }
+};
+
+class NonlinearConjugateGradient : public LineSearchDirection {
+ public:
+ NonlinearConjugateGradient(const NonlinearConjugateGradientType type,
+ const double function_tolerance)
+ : type_(type),
+ function_tolerance_(function_tolerance) {
+ }
+
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ double beta = 0.0;
+ Vector gradient_change;
+ switch (type_) {
+ case FLETCHER_REEVES:
+ beta = current.gradient_squared_norm / previous.gradient_squared_norm;
+ break;
+ case POLAK_RIBIERE:
+ gradient_change = current.gradient - previous.gradient;
+ beta = (current.gradient.dot(gradient_change) /
+ previous.gradient_squared_norm);
+ break;
+ case HESTENES_STIEFEL:
+ gradient_change = current.gradient - previous.gradient;
+ beta = (current.gradient.dot(gradient_change) /
+ previous.search_direction.dot(gradient_change));
+ break;
+ default:
+ LOG(FATAL) << "Unknown nonlinear conjugate gradient type: " << type_;
+ }
+
+ *search_direction = -current.gradient + beta * previous.search_direction;
+ const double directional_derivative =
+ current.gradient.dot(*search_direction);
+ if (directional_derivative > -function_tolerance_) {
+ LOG(WARNING) << "Restarting non-linear conjugate gradients: "
+ << directional_derivative;
+ *search_direction = -current.gradient;
+ }
+
+ return true;
+ }
+
+ private:
+ const NonlinearConjugateGradientType type_;
+ const double function_tolerance_;
+};
+
+class LBFGS : public LineSearchDirection {
+ public:
+ LBFGS(const int num_parameters,
+ const int max_lbfgs_rank,
+ const bool use_approximate_eigenvalue_bfgs_scaling)
+ : low_rank_inverse_hessian_(num_parameters,
+ max_lbfgs_rank,
+ use_approximate_eigenvalue_bfgs_scaling),
+ is_positive_definite_(true) {}
+
+ virtual ~LBFGS() {}
+
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ CHECK(is_positive_definite_)
+ << "Ceres bug: NextDirection() called on L-BFGS after inverse Hessian "
+ << "approximation has become indefinite, please contact the "
+ << "developers!";
+
+ low_rank_inverse_hessian_.Update(
+ previous.search_direction * previous.step_size,
+ current.gradient - previous.gradient);
+
+ search_direction->setZero();
+ low_rank_inverse_hessian_.RightMultiply(current.gradient.data(),
+ search_direction->data());
+ *search_direction *= -1.0;
+
+ if (search_direction->dot(current.gradient) >= 0.0) {
+ LOG(WARNING) << "Numerical failure in L-BFGS update: inverse Hessian "
+ << "approximation is not positive definite, and thus "
+ << "initial gradient for search direction is positive: "
+ << search_direction->dot(current.gradient);
+ is_positive_definite_ = false;
+ return false;
+ }
+
+ return true;
+ }
+
+ private:
+ LowRankInverseHessian low_rank_inverse_hessian_;
+ bool is_positive_definite_;
+};
+
+class BFGS : public LineSearchDirection {
+ public:
+ BFGS(const int num_parameters,
+ const bool use_approximate_eigenvalue_scaling)
+ : num_parameters_(num_parameters),
+ use_approximate_eigenvalue_scaling_(use_approximate_eigenvalue_scaling),
+ initialized_(false),
+ is_positive_definite_(true) {
+ LOG_IF(WARNING, num_parameters_ >= 1e3)
+ << "BFGS line search being created with: " << num_parameters_
+ << " parameters, this will allocate a dense approximate inverse Hessian"
+ << " of size: " << num_parameters_ << " x " << num_parameters_
+ << ", consider using the L-BFGS memory-efficient line search direction "
+ << "instead.";
+ // Construct inverse_hessian_ after logging warning about size s.t. if the
+ // allocation crashes us, the log will highlight what the issue likely was.
+ inverse_hessian_ = Matrix::Identity(num_parameters, num_parameters);
+ }
+
+ virtual ~BFGS() {}
+
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ CHECK(is_positive_definite_)
+ << "Ceres bug: NextDirection() called on BFGS after inverse Hessian "
+ << "approximation has become indefinite, please contact the "
+ << "developers!";
+
+ const Vector delta_x = previous.search_direction * previous.step_size;
+ const Vector delta_gradient = current.gradient - previous.gradient;
+ const double delta_x_dot_delta_gradient = delta_x.dot(delta_gradient);
+
+ // The (L)BFGS algorithm explicitly requires that the secant equation:
+ //
+ // B_{k+1} * s_k = y_k
+ //
+ // Is satisfied at each iteration, where B_{k+1} is the approximated
+ // Hessian at the k+1-th iteration, s_k = (x_{k+1} - x_{k}) and
+ // y_k = (grad_{k+1} - grad_{k}). As the approximated Hessian must be
+ // positive definite, this is equivalent to the condition:
+ //
+ // s_k^T * y_k > 0 [s_k^T * B_{k+1} * s_k = s_k^T * y_k > 0]
+ //
+ // This condition would always be satisfied if the function was strictly
+ // convex, alternatively, it is always satisfied provided that a Wolfe line
+ // search is used (even if the function is not strictly convex). See [1]
+ // (p138) for a proof.
+ //
+ // Although Ceres will always use a Wolfe line search when using (L)BFGS,
+ // practical implementation considerations mean that the line search
+ // may return a point that satisfies only the Armijo condition, and thus
+ // could violate the Secant equation. As such, we will only use a step
+ // to update the Hessian approximation if:
+ //
+ // s_k^T * y_k > tolerance
+ //
+ // It is important that tolerance is very small (and >=0), as otherwise we
+ // might skip the update too often and fail to capture important curvature
+ // information in the Hessian. For example going from 1e-10 -> 1e-14
+ // improves the NIST benchmark score from 43/54 to 53/54.
+ //
+ // [1] Nocedal J, Wright S, Numerical Optimization, 2nd Ed. Springer, 1999.
+ //
+ // TODO(alexs.mac): Consider using Damped BFGS update instead of
+ // skipping update.
+ const double kBFGSSecantConditionHessianUpdateTolerance = 1e-14;
+ if (delta_x_dot_delta_gradient <=
+ kBFGSSecantConditionHessianUpdateTolerance) {
+ VLOG(2) << "Skipping BFGS Update, delta_x_dot_delta_gradient too "
+ << "small: " << delta_x_dot_delta_gradient << ", tolerance: "
+ << kBFGSSecantConditionHessianUpdateTolerance
+ << " (Secant condition).";
+ } else {
+ // Update dense inverse Hessian approximation.
+
+ if (!initialized_ && use_approximate_eigenvalue_scaling_) {
+ // Rescale the initial inverse Hessian approximation (H_0) to be
+ // iteratively updated so that it is of similar 'size' to the true
+ // inverse Hessian at the start point. As shown in [1]:
+ //
+ // \gamma = (delta_gradient_{0}' * delta_x_{0}) /
+ // (delta_gradient_{0}' * delta_gradient_{0})
+ //
+ // Satisfies:
+ //
+ // (1 / \lambda_m) <= \gamma <= (1 / \lambda_1)
+ //
+ // Where \lambda_1 & \lambda_m are the smallest and largest eigenvalues
+ // of the true initial Hessian (not the inverse) respectively. Thus,
+ // \gamma is an approximate eigenvalue of the true inverse Hessian, and
+ // choosing: H_0 = I * \gamma will yield a starting point that has a
+ // similar scale to the true inverse Hessian. This technique is widely
+ // reported to often improve convergence, however this is not
+ // universally true, particularly if there are errors in the initial
+ // gradients, or if there are significant differences in the sensitivity
+ // of the problem to the parameters (i.e. the range of the magnitudes of
+ // the components of the gradient is large).
+ //
+ // The original origin of this rescaling trick is somewhat unclear, the
+ // earliest reference appears to be Oren [1], however it is widely
+ // discussed without specific attributation in various texts including
+ // [2] (p143).
+ //
+ // [1] Oren S.S., Self-scaling variable metric (SSVM) algorithms
+ // Part II: Implementation and experiments, Management Science,
+ // 20(5), 863-874, 1974.
+ // [2] Nocedal J., Wright S., Numerical Optimization, Springer, 1999.
+ const double approximate_eigenvalue_scale =
+ delta_x_dot_delta_gradient / delta_gradient.dot(delta_gradient);
+ inverse_hessian_ *= approximate_eigenvalue_scale;
+
+ VLOG(4) << "Applying approximate_eigenvalue_scale: "
+ << approximate_eigenvalue_scale << " to initial inverse "
+ << "Hessian approximation.";
+ }
+ initialized_ = true;
+
+ // Efficient O(num_parameters^2) BFGS update [2].
+ //
+ // Starting from dense BFGS update detailed in Nocedal [2] p140/177 and
+ // using: y_k = delta_gradient, s_k = delta_x:
+ //
+ // \rho_k = 1.0 / (s_k' * y_k)
+ // V_k = I - \rho_k * y_k * s_k'
+ // H_k = (V_k' * H_{k-1} * V_k) + (\rho_k * s_k * s_k')
+ //
+ // This update involves matrix, matrix products which naively O(N^3),
+ // however we can exploit our knowledge that H_k is positive definite
+ // and thus by defn. symmetric to reduce the cost of the update:
+ //
+ // Expanding the update above yields:
+ //
+ // H_k = H_{k-1} +
+ // \rho_k * ( (1.0 + \rho_k * y_k' * H_k * y_k) * s_k * s_k' -
+ // (s_k * y_k' * H_k + H_k * y_k * s_k') )
+ //
+ // Using: A = (s_k * y_k' * H_k), and the knowledge that H_k = H_k', the
+ // last term simplifies to (A + A'). Note that although A is not symmetric
+ // (A + A') is symmetric. For ease of construction we also define
+ // B = (1 + \rho_k * y_k' * H_k * y_k) * s_k * s_k', which is by defn
+ // symmetric due to construction from: s_k * s_k'.
+ //
+ // Now we can write the BFGS update as:
+ //
+ // H_k = H_{k-1} + \rho_k * (B - (A + A'))
+
+ // For efficiency, as H_k is by defn. symmetric, we will only maintain the
+ // *lower* triangle of H_k (and all intermediary terms).
+
+ const double rho_k = 1.0 / delta_x_dot_delta_gradient;
+
+ // Calculate: A = s_k * y_k' * H_k
+ Matrix A = delta_x * (delta_gradient.transpose() *
+ inverse_hessian_.selfadjointView<Eigen::Lower>());
+
+ // Calculate scalar: (1 + \rho_k * y_k' * H_k * y_k)
+ const double delta_x_times_delta_x_transpose_scale_factor =
+ (1.0 + (rho_k * delta_gradient.transpose() *
+ inverse_hessian_.selfadjointView<Eigen::Lower>() *
+ delta_gradient));
+ // Calculate: B = (1 + \rho_k * y_k' * H_k * y_k) * s_k * s_k'
+ Matrix B = Matrix::Zero(num_parameters_, num_parameters_);
+ B.selfadjointView<Eigen::Lower>().
+ rankUpdate(delta_x, delta_x_times_delta_x_transpose_scale_factor);
+
+ // Finally, update inverse Hessian approximation according to:
+ // H_k = H_{k-1} + \rho_k * (B - (A + A')). Note that (A + A') is
+ // symmetric, even though A is not.
+ inverse_hessian_.triangularView<Eigen::Lower>() +=
+ rho_k * (B - A - A.transpose());
+ }
+
+ *search_direction =
+ inverse_hessian_.selfadjointView<Eigen::Lower>() *
+ (-1.0 * current.gradient);
+
+ if (search_direction->dot(current.gradient) >= 0.0) {
+ LOG(WARNING) << "Numerical failure in BFGS update: inverse Hessian "
+ << "approximation is not positive definite, and thus "
+ << "initial gradient for search direction is positive: "
+ << search_direction->dot(current.gradient);
+ is_positive_definite_ = false;
+ return false;
+ }
+
+ return true;
+ }
+
+ private:
+ const int num_parameters_;
+ const bool use_approximate_eigenvalue_scaling_;
+ Matrix inverse_hessian_;
+ bool initialized_;
+ bool is_positive_definite_;
+};
+
+LineSearchDirection*
+LineSearchDirection::Create(const LineSearchDirection::Options& options) {
+ if (options.type == STEEPEST_DESCENT) {
+ return new SteepestDescent;
+ }
+
+ if (options.type == NONLINEAR_CONJUGATE_GRADIENT) {
+ return new NonlinearConjugateGradient(
+ options.nonlinear_conjugate_gradient_type,
+ options.function_tolerance);
+ }
+
+ if (options.type == ceres::LBFGS) {
+ return new ceres::internal::LBFGS(
+ options.num_parameters,
+ options.max_lbfgs_rank,
+ options.use_approximate_eigenvalue_bfgs_scaling);
+ }
+
+ if (options.type == ceres::BFGS) {
+ return new ceres::internal::BFGS(
+ options.num_parameters,
+ options.use_approximate_eigenvalue_bfgs_scaling);
+ }
+
+ LOG(ERROR) << "Unknown line search direction type: " << options.type;
+ return NULL;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/line_search_direction.h b/extern/ceres/internal/ceres/line_search_direction.h
new file mode 100644
index 00000000000..467578d5f7c
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search_direction.h
@@ -0,0 +1,72 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
+#define CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
+
+#include "ceres/internal/eigen.h"
+#include "ceres/line_search_minimizer.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class LineSearchDirection {
+ public:
+ struct Options {
+ Options()
+ : num_parameters(0),
+ type(LBFGS),
+ nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
+ function_tolerance(1e-12),
+ max_lbfgs_rank(20),
+ use_approximate_eigenvalue_bfgs_scaling(true) {
+ }
+
+ int num_parameters;
+ LineSearchDirectionType type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ double function_tolerance;
+ int max_lbfgs_rank;
+ bool use_approximate_eigenvalue_bfgs_scaling;
+ };
+
+ static LineSearchDirection* Create(const Options& options);
+
+ virtual ~LineSearchDirection() {}
+ virtual bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) = 0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
diff --git a/extern/ceres/internal/ceres/line_search_minimizer.cc b/extern/ceres/internal/ceres/line_search_minimizer.cc
new file mode 100644
index 00000000000..62264fb0b64
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search_minimizer.cc
@@ -0,0 +1,432 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Generic loop for line search based optimization algorithms.
+//
+// This is primarily inpsired by the minFunc packaged written by Mark
+// Schmidt.
+//
+// http://www.di.ens.fr/~mschmidt/Software/minFunc.html
+//
+// For details on the theory and implementation see "Numerical
+// Optimization" by Nocedal & Wright.
+
+#include "ceres/line_search_minimizer.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/array_utils.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/line_search.h"
+#include "ceres/line_search_direction.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+
+// TODO(sameeragarwal): I think there is a small bug here, in that if
+// the evaluation fails, then the state can contain garbage. Look at
+// this more carefully.
+bool Evaluate(Evaluator* evaluator,
+ const Vector& x,
+ LineSearchMinimizer::State* state,
+ std::string* message) {
+ if (!evaluator->Evaluate(x.data(),
+ &(state->cost),
+ NULL,
+ state->gradient.data(),
+ NULL)) {
+ *message = "Gradient evaluation failed.";
+ return false;
+ }
+
+ Vector negative_gradient = -state->gradient;
+ Vector projected_gradient_step(x.size());
+ if (!evaluator->Plus(x.data(),
+ negative_gradient.data(),
+ projected_gradient_step.data())) {
+ *message = "projected_gradient_step = Plus(x, -gradient) failed.";
+ return false;
+ }
+
+ state->gradient_squared_norm = (x - projected_gradient_step).squaredNorm();
+ state->gradient_max_norm =
+ (x - projected_gradient_step).lpNorm<Eigen::Infinity>();
+ return true;
+}
+
+} // namespace
+
+void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) {
+ const bool is_not_silent = !options.is_silent;
+ double start_time = WallTimeInSeconds();
+ double iteration_start_time = start_time;
+
+ Evaluator* evaluator = CHECK_NOTNULL(options.evaluator.get());
+ const int num_parameters = evaluator->NumParameters();
+ const int num_effective_parameters = evaluator->NumEffectiveParameters();
+
+ summary->termination_type = NO_CONVERGENCE;
+ summary->num_successful_steps = 0;
+ summary->num_unsuccessful_steps = 0;
+
+ VectorRef x(parameters, num_parameters);
+
+ State current_state(num_parameters, num_effective_parameters);
+ State previous_state(num_parameters, num_effective_parameters);
+
+ Vector delta(num_effective_parameters);
+ Vector x_plus_delta(num_parameters);
+
+ IterationSummary iteration_summary;
+ iteration_summary.iteration = 0;
+ iteration_summary.step_is_valid = false;
+ iteration_summary.step_is_successful = false;
+ iteration_summary.cost_change = 0.0;
+ iteration_summary.gradient_max_norm = 0.0;
+ iteration_summary.gradient_norm = 0.0;
+ iteration_summary.step_norm = 0.0;
+ iteration_summary.linear_solver_iterations = 0;
+ iteration_summary.step_solver_time_in_seconds = 0;
+
+ // Do initial cost and Jacobian evaluation.
+ if (!Evaluate(evaluator, x, &current_state, &summary->message)) {
+ summary->termination_type = FAILURE;
+ summary->message = "Initial cost and jacobian evaluation failed. "
+ "More details: " + summary->message;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ summary->initial_cost = current_state.cost + summary->fixed_cost;
+ iteration_summary.cost = current_state.cost + summary->fixed_cost;
+
+ iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
+ iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
+
+ if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
+ summary->message = StringPrintf("Gradient tolerance reached. "
+ "Gradient max norm: %e <= %e",
+ iteration_summary.gradient_max_norm,
+ options.gradient_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
+ summary->iterations.push_back(iteration_summary);
+
+ LineSearchDirection::Options line_search_direction_options;
+ line_search_direction_options.num_parameters = num_effective_parameters;
+ line_search_direction_options.type = options.line_search_direction_type;
+ line_search_direction_options.nonlinear_conjugate_gradient_type =
+ options.nonlinear_conjugate_gradient_type;
+ line_search_direction_options.max_lbfgs_rank = options.max_lbfgs_rank;
+ line_search_direction_options.use_approximate_eigenvalue_bfgs_scaling =
+ options.use_approximate_eigenvalue_bfgs_scaling;
+ scoped_ptr<LineSearchDirection> line_search_direction(
+ LineSearchDirection::Create(line_search_direction_options));
+
+ LineSearchFunction line_search_function(evaluator);
+
+ LineSearch::Options line_search_options;
+ line_search_options.interpolation_type =
+ options.line_search_interpolation_type;
+ line_search_options.min_step_size = options.min_line_search_step_size;
+ line_search_options.sufficient_decrease =
+ options.line_search_sufficient_function_decrease;
+ line_search_options.max_step_contraction =
+ options.max_line_search_step_contraction;
+ line_search_options.min_step_contraction =
+ options.min_line_search_step_contraction;
+ line_search_options.max_num_iterations =
+ options.max_num_line_search_step_size_iterations;
+ line_search_options.sufficient_curvature_decrease =
+ options.line_search_sufficient_curvature_decrease;
+ line_search_options.max_step_expansion =
+ options.max_line_search_step_expansion;
+ line_search_options.function = &line_search_function;
+
+ scoped_ptr<LineSearch>
+ line_search(LineSearch::Create(options.line_search_type,
+ line_search_options,
+ &summary->message));
+ if (line_search.get() == NULL) {
+ summary->termination_type = FAILURE;
+ LOG_IF(ERROR, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ LineSearch::Summary line_search_summary;
+ int num_line_search_direction_restarts = 0;
+
+ while (true) {
+ if (!RunCallbacks(options, iteration_summary, summary)) {
+ break;
+ }
+
+ iteration_start_time = WallTimeInSeconds();
+ if (iteration_summary.iteration >= options.max_num_iterations) {
+ summary->message = "Maximum number of iterations reached.";
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ }
+
+ const double total_solver_time = iteration_start_time - start_time +
+ summary->preprocessor_time_in_seconds;
+ if (total_solver_time >= options.max_solver_time_in_seconds) {
+ summary->message = "Maximum solver time reached.";
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ }
+
+ iteration_summary = IterationSummary();
+ iteration_summary.iteration = summary->iterations.back().iteration + 1;
+ iteration_summary.step_is_valid = false;
+ iteration_summary.step_is_successful = false;
+
+ bool line_search_status = true;
+ if (iteration_summary.iteration == 1) {
+ current_state.search_direction = -current_state.gradient;
+ } else {
+ line_search_status = line_search_direction->NextDirection(
+ previous_state,
+ current_state,
+ &current_state.search_direction);
+ }
+
+ if (!line_search_status &&
+ num_line_search_direction_restarts >=
+ options.max_num_line_search_direction_restarts) {
+ // Line search direction failed to generate a new direction, and we
+ // have already reached our specified maximum number of restarts,
+ // terminate optimization.
+ summary->message =
+ StringPrintf("Line search direction failure: specified "
+ "max_num_line_search_direction_restarts: %d reached.",
+ options.max_num_line_search_direction_restarts);
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ } else if (!line_search_status) {
+ // Restart line search direction with gradient descent on first iteration
+ // as we have not yet reached our maximum number of restarts.
+ CHECK_LT(num_line_search_direction_restarts,
+ options.max_num_line_search_direction_restarts);
+
+ ++num_line_search_direction_restarts;
+ LOG_IF(WARNING, is_not_silent)
+ << "Line search direction algorithm: "
+ << LineSearchDirectionTypeToString(
+ options.line_search_direction_type)
+ << ", failed to produce a valid new direction at "
+ << "iteration: " << iteration_summary.iteration
+ << ". Restarting, number of restarts: "
+ << num_line_search_direction_restarts << " / "
+ << options.max_num_line_search_direction_restarts
+ << " [max].";
+ line_search_direction.reset(
+ LineSearchDirection::Create(line_search_direction_options));
+ current_state.search_direction = -current_state.gradient;
+ }
+
+ line_search_function.Init(x, current_state.search_direction);
+ current_state.directional_derivative =
+ current_state.gradient.dot(current_state.search_direction);
+
+ // TODO(sameeragarwal): Refactor this into its own object and add
+ // explanations for the various choices.
+ //
+ // Note that we use !line_search_status to ensure that we treat cases when
+ // we restarted the line search direction equivalently to the first
+ // iteration.
+ const double initial_step_size =
+ (iteration_summary.iteration == 1 || !line_search_status)
+ ? std::min(1.0, 1.0 / current_state.gradient_max_norm)
+ : std::min(1.0, 2.0 * (current_state.cost - previous_state.cost) /
+ current_state.directional_derivative);
+ // By definition, we should only ever go forwards along the specified search
+ // direction in a line search, most likely cause for this being violated
+ // would be a numerical failure in the line search direction calculation.
+ if (initial_step_size < 0.0) {
+ summary->message =
+ StringPrintf("Numerical failure in line search, initial_step_size is "
+ "negative: %.5e, directional_derivative: %.5e, "
+ "(current_cost - previous_cost): %.5e",
+ initial_step_size, current_state.directional_derivative,
+ (current_state.cost - previous_state.cost));
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ }
+
+ line_search->Search(initial_step_size,
+ current_state.cost,
+ current_state.directional_derivative,
+ &line_search_summary);
+ if (!line_search_summary.success) {
+ summary->message =
+ StringPrintf("Numerical failure in line search, failed to find "
+ "a valid step size, (did not run out of iterations) "
+ "using initial_step_size: %.5e, initial_cost: %.5e, "
+ "initial_gradient: %.5e.",
+ initial_step_size, current_state.cost,
+ current_state.directional_derivative);
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ summary->termination_type = FAILURE;
+ break;
+ }
+
+ current_state.step_size = line_search_summary.optimal_step_size;
+ delta = current_state.step_size * current_state.search_direction;
+
+ previous_state = current_state;
+ iteration_summary.step_solver_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+
+ const double x_norm = x.norm();
+
+ if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
+ summary->termination_type = FAILURE;
+ summary->message =
+ "x_plus_delta = Plus(x, delta) failed. This should not happen "
+ "as the step was valid when it was selected by the line search.";
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ } else if (!Evaluate(evaluator,
+ x_plus_delta,
+ &current_state,
+ &summary->message)) {
+ summary->termination_type = FAILURE;
+ summary->message =
+ "Step failed to evaluate. This should not happen as the step was "
+ "valid when it was selected by the line search. More details: " +
+ summary->message;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ } else {
+ x = x_plus_delta;
+ }
+
+ iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
+ iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
+ iteration_summary.cost_change = previous_state.cost - current_state.cost;
+ iteration_summary.cost = current_state.cost + summary->fixed_cost;
+ iteration_summary.step_norm = delta.norm();
+ iteration_summary.step_is_valid = true;
+ iteration_summary.step_is_successful = true;
+ iteration_summary.step_size = current_state.step_size;
+ iteration_summary.line_search_function_evaluations =
+ line_search_summary.num_function_evaluations;
+ iteration_summary.line_search_gradient_evaluations =
+ line_search_summary.num_gradient_evaluations;
+ iteration_summary.line_search_iterations =
+ line_search_summary.num_iterations;
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
+
+ summary->line_search_cost_evaluation_time_in_seconds +=
+ line_search_summary.cost_evaluation_time_in_seconds;
+ summary->line_search_gradient_evaluation_time_in_seconds +=
+ line_search_summary.gradient_evaluation_time_in_seconds;
+ summary->line_search_polynomial_minimization_time_in_seconds +=
+ line_search_summary.polynomial_minimization_time_in_seconds;
+ summary->line_search_total_time_in_seconds +=
+ line_search_summary.total_time_in_seconds;
+ ++summary->num_successful_steps;
+
+ const double step_size_tolerance = options.parameter_tolerance *
+ (x_norm + options.parameter_tolerance);
+ if (iteration_summary.step_norm <= step_size_tolerance) {
+ summary->message =
+ StringPrintf("Parameter tolerance reached. "
+ "Relative step_norm: %e <= %e.",
+ (iteration_summary.step_norm /
+ (x_norm + options.parameter_tolerance)),
+ options.parameter_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
+ summary->message = StringPrintf("Gradient tolerance reached. "
+ "Gradient max norm: %e <= %e",
+ iteration_summary.gradient_max_norm,
+ options.gradient_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ }
+
+ const double absolute_function_tolerance =
+ options.function_tolerance * previous_state.cost;
+ if (fabs(iteration_summary.cost_change) <= absolute_function_tolerance) {
+ summary->message =
+ StringPrintf("Function tolerance reached. "
+ "|cost_change|/cost: %e <= %e",
+ fabs(iteration_summary.cost_change) /
+ previous_state.cost,
+ options.function_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ break;
+ }
+
+ summary->iterations.push_back(iteration_summary);
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/line_search_minimizer.h b/extern/ceres/internal/ceres/line_search_minimizer.h
new file mode 100644
index 00000000000..54b7202e0c3
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search_minimizer.h
@@ -0,0 +1,77 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
+#define CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
+
+#include "ceres/minimizer.h"
+#include "ceres/solver.h"
+#include "ceres/types.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Generic line search minimization algorithm.
+//
+// For example usage, see SolverImpl::Minimize.
+class LineSearchMinimizer : public Minimizer {
+ public:
+ struct State {
+ State(int num_parameters,
+ int num_effective_parameters)
+ : cost(0.0),
+ gradient(num_effective_parameters),
+ gradient_squared_norm(0.0),
+ search_direction(num_effective_parameters),
+ directional_derivative(0.0),
+ step_size(0.0) {
+ }
+
+ double cost;
+ Vector gradient;
+ double gradient_squared_norm;
+ double gradient_max_norm;
+ Vector search_direction;
+ double directional_derivative;
+ double step_size;
+ };
+
+ ~LineSearchMinimizer() {}
+ virtual void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
diff --git a/extern/ceres/internal/ceres/line_search_preprocessor.cc b/extern/ceres/internal/ceres/line_search_preprocessor.cc
new file mode 100644
index 00000000000..831f5e8d079
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search_preprocessor.cc
@@ -0,0 +1,106 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search_preprocessor.h"
+
+#include <numeric>
+#include <string>
+#include "ceres/evaluator.h"
+#include "ceres/minimizer.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+
+bool IsProgramValid(const Program& program, std::string* error) {
+ if (program.IsBoundsConstrained()) {
+ *error = "LINE_SEARCH Minimizer does not support bounds.";
+ return false;
+ }
+ return program.ParameterBlocksAreFinite(error);
+}
+
+bool SetupEvaluator(PreprocessedProblem* pp) {
+ pp->evaluator_options = Evaluator::Options();
+ // This ensures that we get a Block Jacobian Evaluator without any
+ // requirement on orderings.
+ pp->evaluator_options.linear_solver_type = CGNR;
+ pp->evaluator_options.num_eliminate_blocks = 0;
+ pp->evaluator_options.num_threads = pp->options.num_threads;
+ pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
+ pp->reduced_program.get(),
+ &pp->error));
+ return (pp->evaluator.get() != NULL);
+}
+
+} // namespace
+
+LineSearchPreprocessor::~LineSearchPreprocessor() {
+}
+
+bool LineSearchPreprocessor::Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* pp) {
+ CHECK_NOTNULL(pp);
+ pp->options = options;
+ ChangeNumThreadsIfNeeded(&pp->options);
+
+ pp->problem = problem;
+ Program* program = problem->mutable_program();
+ if (!IsProgramValid(*program, &pp->error)) {
+ return false;
+ }
+
+ pp->reduced_program.reset(
+ program->CreateReducedProgram(&pp->removed_parameter_blocks,
+ &pp->fixed_cost,
+ &pp->error));
+
+ if (pp->reduced_program.get() == NULL) {
+ return false;
+ }
+
+ if (pp->reduced_program->NumParameterBlocks() == 0) {
+ return true;
+ }
+
+ if (!SetupEvaluator(pp)) {
+ return false;
+ }
+
+ SetupCommonMinimizerOptions(pp);
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/line_search_preprocessor.h b/extern/ceres/internal/ceres/line_search_preprocessor.h
new file mode 100644
index 00000000000..132d83a0a9a
--- /dev/null
+++ b/extern/ceres/internal/ceres/line_search_preprocessor.h
@@ -0,0 +1,50 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
+#define CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
+
+#include "ceres/preprocessor.h"
+
+namespace ceres {
+namespace internal {
+
+class LineSearchPreprocessor : public Preprocessor {
+ public:
+ virtual ~LineSearchPreprocessor();
+ virtual bool Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* preprocessed_problem);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
diff --git a/extern/ceres/internal/ceres/linear_least_squares_problems.cc b/extern/ceres/internal/ceres/linear_least_squares_problems.cc
new file mode 100644
index 00000000000..0a69375f7b5
--- /dev/null
+++ b/extern/ceres/internal/ceres/linear_least_squares_problems.cc
@@ -0,0 +1,732 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/linear_least_squares_problems.h"
+
+#include <cstdio>
+#include <string>
+#include <vector>
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/casts.h"
+#include "ceres/file.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/stringprintf.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+
+LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id) {
+ switch (id) {
+ case 0:
+ return LinearLeastSquaresProblem0();
+ case 1:
+ return LinearLeastSquaresProblem1();
+ case 2:
+ return LinearLeastSquaresProblem2();
+ case 3:
+ return LinearLeastSquaresProblem3();
+ case 4:
+ return LinearLeastSquaresProblem4();
+ default:
+ LOG(FATAL) << "Unknown problem id requested " << id;
+ }
+ return NULL;
+}
+
+/*
+A = [1 2]
+ [3 4]
+ [6 -10]
+
+b = [ 8
+ 18
+ -18]
+
+x = [2
+ 3]
+
+D = [1
+ 2]
+
+x_D = [1.78448275;
+ 2.82327586;]
+ */
+LinearLeastSquaresProblem* LinearLeastSquaresProblem0() {
+ LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+
+ TripletSparseMatrix* A = new TripletSparseMatrix(3, 2, 6);
+ problem->b.reset(new double[3]);
+ problem->D.reset(new double[2]);
+
+ problem->x.reset(new double[2]);
+ problem->x_D.reset(new double[2]);
+
+ int* Ai = A->mutable_rows();
+ int* Aj = A->mutable_cols();
+ double* Ax = A->mutable_values();
+
+ int counter = 0;
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j< 2; ++j) {
+ Ai[counter] = i;
+ Aj[counter] = j;
+ ++counter;
+ }
+ }
+
+ Ax[0] = 1.;
+ Ax[1] = 2.;
+ Ax[2] = 3.;
+ Ax[3] = 4.;
+ Ax[4] = 6;
+ Ax[5] = -10;
+ A->set_num_nonzeros(6);
+ problem->A.reset(A);
+
+ problem->b[0] = 8;
+ problem->b[1] = 18;
+ problem->b[2] = -18;
+
+ problem->x[0] = 2.0;
+ problem->x[1] = 3.0;
+
+ problem->D[0] = 1;
+ problem->D[1] = 2;
+
+ problem->x_D[0] = 1.78448275;
+ problem->x_D[1] = 2.82327586;
+ return problem;
+}
+
+
+/*
+ A = [1 0 | 2 0 0
+ 3 0 | 0 4 0
+ 0 5 | 0 0 6
+ 0 7 | 8 0 0
+ 0 9 | 1 0 0
+ 0 0 | 1 1 1]
+
+ b = [0
+ 1
+ 2
+ 3
+ 4
+ 5]
+
+ c = A'* b = [ 3
+ 67
+ 33
+ 9
+ 17]
+
+ A'A = [10 0 2 12 0
+ 0 155 65 0 30
+ 2 65 70 1 1
+ 12 0 1 17 1
+ 0 30 1 1 37]
+
+ S = [ 42.3419 -1.4000 -11.5806
+ -1.4000 2.6000 1.0000
+ 11.5806 1.0000 31.1935]
+
+ r = [ 4.3032
+ 5.4000
+ 5.0323]
+
+ S\r = [ 0.2102
+ 2.1367
+ 0.1388]
+
+ A\b = [-2.3061
+ 0.3172
+ 0.2102
+ 2.1367
+ 0.1388]
+*/
+// The following two functions create a TripletSparseMatrix and a
+// BlockSparseMatrix version of this problem.
+
+// TripletSparseMatrix version.
+LinearLeastSquaresProblem* LinearLeastSquaresProblem1() {
+ int num_rows = 6;
+ int num_cols = 5;
+
+ LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+ TripletSparseMatrix* A = new TripletSparseMatrix(num_rows,
+ num_cols,
+ num_rows * num_cols);
+ problem->b.reset(new double[num_rows]);
+ problem->D.reset(new double[num_cols]);
+ problem->num_eliminate_blocks = 2;
+
+ int* rows = A->mutable_rows();
+ int* cols = A->mutable_cols();
+ double* values = A->mutable_values();
+
+ int nnz = 0;
+
+ // Row 1
+ {
+ rows[nnz] = 0;
+ cols[nnz] = 0;
+ values[nnz++] = 1;
+
+ rows[nnz] = 0;
+ cols[nnz] = 2;
+ values[nnz++] = 2;
+ }
+
+ // Row 2
+ {
+ rows[nnz] = 1;
+ cols[nnz] = 0;
+ values[nnz++] = 3;
+
+ rows[nnz] = 1;
+ cols[nnz] = 3;
+ values[nnz++] = 4;
+ }
+
+ // Row 3
+ {
+ rows[nnz] = 2;
+ cols[nnz] = 1;
+ values[nnz++] = 5;
+
+ rows[nnz] = 2;
+ cols[nnz] = 4;
+ values[nnz++] = 6;
+ }
+
+ // Row 4
+ {
+ rows[nnz] = 3;
+ cols[nnz] = 1;
+ values[nnz++] = 7;
+
+ rows[nnz] = 3;
+ cols[nnz] = 2;
+ values[nnz++] = 8;
+ }
+
+ // Row 5
+ {
+ rows[nnz] = 4;
+ cols[nnz] = 1;
+ values[nnz++] = 9;
+
+ rows[nnz] = 4;
+ cols[nnz] = 2;
+ values[nnz++] = 1;
+ }
+
+ // Row 6
+ {
+ rows[nnz] = 5;
+ cols[nnz] = 2;
+ values[nnz++] = 1;
+
+ rows[nnz] = 5;
+ cols[nnz] = 3;
+ values[nnz++] = 1;
+
+ rows[nnz] = 5;
+ cols[nnz] = 4;
+ values[nnz++] = 1;
+ }
+
+ A->set_num_nonzeros(nnz);
+ CHECK(A->IsValid());
+
+ problem->A.reset(A);
+
+ for (int i = 0; i < num_cols; ++i) {
+ problem->D.get()[i] = 1;
+ }
+
+ for (int i = 0; i < num_rows; ++i) {
+ problem->b.get()[i] = i;
+ }
+
+ return problem;
+}
+
+// BlockSparseMatrix version
+LinearLeastSquaresProblem* LinearLeastSquaresProblem2() {
+ int num_rows = 6;
+ int num_cols = 5;
+
+ LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+
+ problem->b.reset(new double[num_rows]);
+ problem->D.reset(new double[num_cols]);
+ problem->num_eliminate_blocks = 2;
+
+ CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+ scoped_array<double> values(new double[num_rows * num_cols]);
+
+ for (int c = 0; c < num_cols; ++c) {
+ bs->cols.push_back(Block());
+ bs->cols.back().size = 1;
+ bs->cols.back().position = c;
+ }
+
+ int nnz = 0;
+
+ // Row 1
+ {
+ values[nnz++] = 1;
+ values[nnz++] = 2;
+
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 0;
+ row.cells.push_back(Cell(0, 0));
+ row.cells.push_back(Cell(2, 1));
+ }
+
+ // Row 2
+ {
+ values[nnz++] = 3;
+ values[nnz++] = 4;
+
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 1;
+ row.cells.push_back(Cell(0, 2));
+ row.cells.push_back(Cell(3, 3));
+ }
+
+ // Row 3
+ {
+ values[nnz++] = 5;
+ values[nnz++] = 6;
+
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 2;
+ row.cells.push_back(Cell(1, 4));
+ row.cells.push_back(Cell(4, 5));
+ }
+
+ // Row 4
+ {
+ values[nnz++] = 7;
+ values[nnz++] = 8;
+
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 3;
+ row.cells.push_back(Cell(1, 6));
+ row.cells.push_back(Cell(2, 7));
+ }
+
+ // Row 5
+ {
+ values[nnz++] = 9;
+ values[nnz++] = 1;
+
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 4;
+ row.cells.push_back(Cell(1, 8));
+ row.cells.push_back(Cell(2, 9));
+ }
+
+ // Row 6
+ {
+ values[nnz++] = 1;
+ values[nnz++] = 1;
+ values[nnz++] = 1;
+
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 5;
+ row.cells.push_back(Cell(2, 10));
+ row.cells.push_back(Cell(3, 11));
+ row.cells.push_back(Cell(4, 12));
+ }
+
+ BlockSparseMatrix* A = new BlockSparseMatrix(bs);
+ memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
+
+ for (int i = 0; i < num_cols; ++i) {
+ problem->D.get()[i] = 1;
+ }
+
+ for (int i = 0; i < num_rows; ++i) {
+ problem->b.get()[i] = i;
+ }
+
+ problem->A.reset(A);
+
+ return problem;
+}
+
+
+/*
+ A = [1 0
+ 3 0
+ 0 5
+ 0 7
+ 0 9
+ 0 0]
+
+ b = [0
+ 1
+ 2
+ 3
+ 4
+ 5]
+*/
+// BlockSparseMatrix version
+LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
+ int num_rows = 5;
+ int num_cols = 2;
+
+ LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+
+ problem->b.reset(new double[num_rows]);
+ problem->D.reset(new double[num_cols]);
+ problem->num_eliminate_blocks = 2;
+
+ CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+ scoped_array<double> values(new double[num_rows * num_cols]);
+
+ for (int c = 0; c < num_cols; ++c) {
+ bs->cols.push_back(Block());
+ bs->cols.back().size = 1;
+ bs->cols.back().position = c;
+ }
+
+ int nnz = 0;
+
+ // Row 1
+ {
+ values[nnz++] = 1;
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 0;
+ row.cells.push_back(Cell(0, 0));
+ }
+
+ // Row 2
+ {
+ values[nnz++] = 3;
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 1;
+ row.cells.push_back(Cell(0, 1));
+ }
+
+ // Row 3
+ {
+ values[nnz++] = 5;
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 2;
+ row.cells.push_back(Cell(1, 2));
+ }
+
+ // Row 4
+ {
+ values[nnz++] = 7;
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 3;
+ row.cells.push_back(Cell(1, 3));
+ }
+
+ // Row 5
+ {
+ values[nnz++] = 9;
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 4;
+ row.cells.push_back(Cell(1, 4));
+ }
+
+ BlockSparseMatrix* A = new BlockSparseMatrix(bs);
+ memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
+
+ for (int i = 0; i < num_cols; ++i) {
+ problem->D.get()[i] = 1;
+ }
+
+ for (int i = 0; i < num_rows; ++i) {
+ problem->b.get()[i] = i;
+ }
+
+ problem->A.reset(A);
+
+ return problem;
+}
+
+/*
+ A = [1 2 0 0 0 1 1
+ 1 4 0 0 0 5 6
+ 0 0 9 0 0 3 1]
+
+ b = [0
+ 1
+ 2]
+*/
+// BlockSparseMatrix version
+//
+// This problem has the unique property that it has two different
+// sized f-blocks, but only one of them occurs in the rows involving
+// the one e-block. So performing Schur elimination on this problem
+// tests the Schur Eliminator's ability to handle non-e-block rows
+// correctly when their structure does not conform to the static
+// structure determined by DetectStructure.
+//
+// NOTE: This problem is too small and rank deficient to be solved without
+// the diagonal regularization.
+LinearLeastSquaresProblem* LinearLeastSquaresProblem4() {
+ int num_rows = 3;
+ int num_cols = 7;
+
+ LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+
+ problem->b.reset(new double[num_rows]);
+ problem->D.reset(new double[num_cols]);
+ problem->num_eliminate_blocks = 1;
+
+ CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+ scoped_array<double> values(new double[num_rows * num_cols]);
+
+ // Column block structure
+ bs->cols.push_back(Block());
+ bs->cols.back().size = 2;
+ bs->cols.back().position = 0;
+
+ bs->cols.push_back(Block());
+ bs->cols.back().size = 3;
+ bs->cols.back().position = 2;
+
+ bs->cols.push_back(Block());
+ bs->cols.back().size = 2;
+ bs->cols.back().position = 5;
+
+ int nnz = 0;
+
+ // Row 1 & 2
+ {
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 2;
+ row.block.position = 0;
+
+ row.cells.push_back(Cell(0, nnz));
+ values[nnz++] = 1;
+ values[nnz++] = 2;
+ values[nnz++] = 1;
+ values[nnz++] = 4;
+
+ row.cells.push_back(Cell(2, nnz));
+ values[nnz++] = 1;
+ values[nnz++] = 1;
+ values[nnz++] = 5;
+ values[nnz++] = 6;
+ }
+
+ // Row 3
+ {
+ bs->rows.push_back(CompressedRow());
+ CompressedRow& row = bs->rows.back();
+ row.block.size = 1;
+ row.block.position = 2;
+
+ row.cells.push_back(Cell(1, nnz));
+ values[nnz++] = 9;
+ values[nnz++] = 0;
+ values[nnz++] = 0;
+
+ row.cells.push_back(Cell(2, nnz));
+ values[nnz++] = 3;
+ values[nnz++] = 1;
+ }
+
+ BlockSparseMatrix* A = new BlockSparseMatrix(bs);
+ memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
+
+ for (int i = 0; i < num_cols; ++i) {
+ problem->D.get()[i] = (i + 1) * 100;
+ }
+
+ for (int i = 0; i < num_rows; ++i) {
+ problem->b.get()[i] = i;
+ }
+
+ problem->A.reset(A);
+ return problem;
+}
+
+namespace {
+bool DumpLinearLeastSquaresProblemToConsole(const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
+ CHECK_NOTNULL(A);
+ Matrix AA;
+ A->ToDenseMatrix(&AA);
+ LOG(INFO) << "A^T: \n" << AA.transpose();
+
+ if (D != NULL) {
+ LOG(INFO) << "A's appended diagonal:\n"
+ << ConstVectorRef(D, A->num_cols());
+ }
+
+ if (b != NULL) {
+ LOG(INFO) << "b: \n" << ConstVectorRef(b, A->num_rows());
+ }
+
+ if (x != NULL) {
+ LOG(INFO) << "x: \n" << ConstVectorRef(x, A->num_cols());
+ }
+ return true;
+}
+
+void WriteArrayToFileOrDie(const string& filename,
+ const double* x,
+ const int size) {
+ CHECK_NOTNULL(x);
+ VLOG(2) << "Writing array to: " << filename;
+ FILE* fptr = fopen(filename.c_str(), "w");
+ CHECK_NOTNULL(fptr);
+ for (int i = 0; i < size; ++i) {
+ fprintf(fptr, "%17f\n", x[i]);
+ }
+ fclose(fptr);
+}
+
+bool DumpLinearLeastSquaresProblemToTextFile(const string& filename_base,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
+ CHECK_NOTNULL(A);
+ LOG(INFO) << "writing to: " << filename_base << "*";
+
+ string matlab_script;
+ StringAppendF(&matlab_script,
+ "function lsqp = load_trust_region_problem()\n");
+ StringAppendF(&matlab_script,
+ "lsqp.num_rows = %d;\n", A->num_rows());
+ StringAppendF(&matlab_script,
+ "lsqp.num_cols = %d;\n", A->num_cols());
+
+ {
+ string filename = filename_base + "_A.txt";
+ FILE* fptr = fopen(filename.c_str(), "w");
+ CHECK_NOTNULL(fptr);
+ A->ToTextFile(fptr);
+ fclose(fptr);
+ StringAppendF(&matlab_script,
+ "tmp = load('%s', '-ascii');\n", filename.c_str());
+ StringAppendF(
+ &matlab_script,
+ "lsqp.A = sparse(tmp(:, 1) + 1, tmp(:, 2) + 1, tmp(:, 3), %d, %d);\n",
+ A->num_rows(),
+ A->num_cols());
+ }
+
+
+ if (D != NULL) {
+ string filename = filename_base + "_D.txt";
+ WriteArrayToFileOrDie(filename, D, A->num_cols());
+ StringAppendF(&matlab_script,
+ "lsqp.D = load('%s', '-ascii');\n", filename.c_str());
+ }
+
+ if (b != NULL) {
+ string filename = filename_base + "_b.txt";
+ WriteArrayToFileOrDie(filename, b, A->num_rows());
+ StringAppendF(&matlab_script,
+ "lsqp.b = load('%s', '-ascii');\n", filename.c_str());
+ }
+
+ if (x != NULL) {
+ string filename = filename_base + "_x.txt";
+ WriteArrayToFileOrDie(filename, x, A->num_cols());
+ StringAppendF(&matlab_script,
+ "lsqp.x = load('%s', '-ascii');\n", filename.c_str());
+ }
+
+ string matlab_filename = filename_base + ".m";
+ WriteStringToFileOrDie(matlab_script, matlab_filename);
+ return true;
+}
+} // namespace
+
+bool DumpLinearLeastSquaresProblem(const string& filename_base,
+ DumpFormatType dump_format_type,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
+ switch (dump_format_type) {
+ case CONSOLE:
+ return DumpLinearLeastSquaresProblemToConsole(A, D, b, x,
+ num_eliminate_blocks);
+ case TEXTFILE:
+ return DumpLinearLeastSquaresProblemToTextFile(filename_base,
+ A, D, b, x,
+ num_eliminate_blocks);
+ default:
+ LOG(FATAL) << "Unknown DumpFormatType " << dump_format_type;
+ }
+
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/linear_least_squares_problems.h b/extern/ceres/internal/ceres/linear_least_squares_problems.h
new file mode 100644
index 00000000000..384efb59a2b
--- /dev/null
+++ b/extern/ceres/internal/ceres/linear_least_squares_problems.h
@@ -0,0 +1,85 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
+#define CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
+
+#include <string>
+#include <vector>
+#include "ceres/sparse_matrix.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+namespace internal {
+
+// Structure defining a linear least squares problem and if possible
+// ground truth solutions. To be used by various LinearSolver tests.
+struct LinearLeastSquaresProblem {
+ LinearLeastSquaresProblem()
+ : A(NULL), b(NULL), D(NULL), num_eliminate_blocks(0),
+ x(NULL), x_D(NULL) {
+ }
+
+ scoped_ptr<SparseMatrix> A;
+ scoped_array<double> b;
+ scoped_array<double> D;
+ // If using the schur eliminator then how many of the variable
+ // blocks are e_type blocks.
+ int num_eliminate_blocks;
+
+ // Solution to min_x |Ax - b|^2
+ scoped_array<double> x;
+ // Solution to min_x |Ax - b|^2 + |Dx|^2
+ scoped_array<double> x_D;
+};
+
+// Factories for linear least squares problem.
+LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id);
+
+LinearLeastSquaresProblem* LinearLeastSquaresProblem0();
+LinearLeastSquaresProblem* LinearLeastSquaresProblem1();
+LinearLeastSquaresProblem* LinearLeastSquaresProblem2();
+LinearLeastSquaresProblem* LinearLeastSquaresProblem3();
+LinearLeastSquaresProblem* LinearLeastSquaresProblem4();
+
+// Write the linear least squares problem to disk. The exact format
+// depends on dump_format_type.
+bool DumpLinearLeastSquaresProblem(const std::string& filename_base,
+ DumpFormatType dump_format_type,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks);
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
diff --git a/extern/ceres/internal/ceres/linear_operator.cc b/extern/ceres/internal/ceres/linear_operator.cc
new file mode 100644
index 00000000000..9d291bd3465
--- /dev/null
+++ b/extern/ceres/internal/ceres/linear_operator.cc
@@ -0,0 +1,40 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/linear_operator.h"
+
+namespace ceres {
+namespace internal {
+
+LinearOperator::~LinearOperator() {
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/linear_operator.h b/extern/ceres/internal/ceres/linear_operator.h
new file mode 100644
index 00000000000..6463fb5089a
--- /dev/null
+++ b/extern/ceres/internal/ceres/linear_operator.h
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Base classes for access to an linear operator.
+
+#ifndef CERES_INTERNAL_LINEAR_OPERATOR_H_
+#define CERES_INTERNAL_LINEAR_OPERATOR_H_
+
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+// This is an abstract base class for linear operators. It supports
+// access to size information and left and right multiply operators.
+class LinearOperator {
+ public:
+ virtual ~LinearOperator();
+
+ // y = y + Ax;
+ virtual void RightMultiply(const double* x, double* y) const = 0;
+ // y = y + A'x;
+ virtual void LeftMultiply(const double* x, double* y) const = 0;
+
+ virtual int num_rows() const = 0;
+ virtual int num_cols() const = 0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINEAR_OPERATOR_H_
diff --git a/extern/ceres/internal/ceres/linear_solver.cc b/extern/ceres/internal/ceres/linear_solver.cc
new file mode 100644
index 00000000000..38e4625f747
--- /dev/null
+++ b/extern/ceres/internal/ceres/linear_solver.cc
@@ -0,0 +1,119 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/linear_solver.h"
+
+#include "ceres/cgnr_solver.h"
+#include "ceres/dense_normal_cholesky_solver.h"
+#include "ceres/dense_qr_solver.h"
+#include "ceres/iterative_schur_complement_solver.h"
+#include "ceres/schur_complement_solver.h"
+#include "ceres/sparse_normal_cholesky_solver.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+LinearSolver::~LinearSolver() {
+}
+
+LinearSolverType LinearSolver::LinearSolverForZeroEBlocks(
+ LinearSolverType linear_solver_type) {
+ if (!IsSchurType(linear_solver_type)) {
+ return linear_solver_type;
+ }
+
+ if (linear_solver_type == SPARSE_SCHUR) {
+ return SPARSE_NORMAL_CHOLESKY;
+ }
+
+ if (linear_solver_type == DENSE_SCHUR) {
+ // TODO(sameeragarwal): This is probably not a great choice.
+ // Ideally, we should have a DENSE_NORMAL_CHOLESKY, that can take
+ // a BlockSparseMatrix as input.
+ return DENSE_QR;
+ }
+
+ if (linear_solver_type == ITERATIVE_SCHUR) {
+ return CGNR;
+ }
+
+ return linear_solver_type;
+}
+
+LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) {
+ switch (options.type) {
+ case CGNR:
+ return new CgnrSolver(options);
+
+ case SPARSE_NORMAL_CHOLESKY:
+#if defined(CERES_NO_SUITESPARSE) && \
+ defined(CERES_NO_CXSPARSE) && \
+ !defined(CERES_USE_EIGEN_SPARSE)
+ return NULL;
+#else
+ return new SparseNormalCholeskySolver(options);
+#endif
+
+ case SPARSE_SCHUR:
+#if defined(CERES_NO_SUITESPARSE) && \
+ defined(CERES_NO_CXSPARSE) && \
+ !defined(CERES_USE_EIGEN_SPARSE)
+ return NULL;
+#else
+ return new SparseSchurComplementSolver(options);
+#endif
+
+ case DENSE_SCHUR:
+ return new DenseSchurComplementSolver(options);
+
+ case ITERATIVE_SCHUR:
+ if (options.use_explicit_schur_complement) {
+ return new SparseSchurComplementSolver(options);
+ } else {
+ return new IterativeSchurComplementSolver(options);
+ }
+
+ case DENSE_QR:
+ return new DenseQRSolver(options);
+
+ case DENSE_NORMAL_CHOLESKY:
+ return new DenseNormalCholeskySolver(options);
+
+ default:
+ LOG(FATAL) << "Unknown linear solver type :"
+ << options.type;
+ return NULL; // MSVC doesn't understand that LOG(FATAL) never returns.
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/linear_solver.h b/extern/ceres/internal/ceres/linear_solver.h
new file mode 100644
index 00000000000..fb9332ca6e3
--- /dev/null
+++ b/extern/ceres/internal/ceres/linear_solver.h
@@ -0,0 +1,362 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Abstract interface for objects solving linear systems of various
+// kinds.
+
+#ifndef CERES_INTERNAL_LINEAR_SOLVER_H_
+#define CERES_INTERNAL_LINEAR_SOLVER_H_
+
+#include <cstddef>
+#include <map>
+#include <string>
+#include <vector>
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/dense_sparse_matrix.h"
+#include "ceres/execution_summary.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+enum LinearSolverTerminationType {
+ // Termination criterion was met.
+ LINEAR_SOLVER_SUCCESS,
+
+ // Solver ran for max_num_iterations and terminated before the
+ // termination tolerance could be satisfied.
+ LINEAR_SOLVER_NO_CONVERGENCE,
+
+ // Solver was terminated due to numerical problems, generally due to
+ // the linear system being poorly conditioned.
+ LINEAR_SOLVER_FAILURE,
+
+ // Solver failed with a fatal error that cannot be recovered from,
+ // e.g. CHOLMOD ran out of memory when computing the symbolic or
+ // numeric factorization or an underlying library was called with
+ // the wrong arguments.
+ LINEAR_SOLVER_FATAL_ERROR
+};
+
+
+class LinearOperator;
+
+// Abstract base class for objects that implement algorithms for
+// solving linear systems
+//
+// Ax = b
+//
+// It is expected that a single instance of a LinearSolver object
+// maybe used multiple times for solving multiple linear systems with
+// the same sparsity structure. This allows them to cache and reuse
+// information across solves. This means that calling Solve on the
+// same LinearSolver instance with two different linear systems will
+// result in undefined behaviour.
+//
+// Subclasses of LinearSolver use two structs to configure themselves.
+// The Options struct configures the LinearSolver object for its
+// lifetime. The PerSolveOptions struct is used to specify options for
+// a particular Solve call.
+class LinearSolver {
+ public:
+ struct Options {
+ Options()
+ : type(SPARSE_NORMAL_CHOLESKY),
+ preconditioner_type(JACOBI),
+ visibility_clustering_type(CANONICAL_VIEWS),
+ dense_linear_algebra_library_type(EIGEN),
+ sparse_linear_algebra_library_type(SUITE_SPARSE),
+ use_postordering(false),
+ dynamic_sparsity(false),
+ use_explicit_schur_complement(false),
+ min_num_iterations(1),
+ max_num_iterations(1),
+ num_threads(1),
+ residual_reset_period(10),
+ row_block_size(Eigen::Dynamic),
+ e_block_size(Eigen::Dynamic),
+ f_block_size(Eigen::Dynamic) {
+ }
+
+ LinearSolverType type;
+ PreconditionerType preconditioner_type;
+ VisibilityClusteringType visibility_clustering_type;
+ DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+
+ // See solver.h for information about these flags.
+ bool use_postordering;
+ bool dynamic_sparsity;
+ bool use_explicit_schur_complement;
+
+ // Number of internal iterations that the solver uses. This
+ // parameter only makes sense for iterative solvers like CG.
+ int min_num_iterations;
+ int max_num_iterations;
+
+ // If possible, how many threads can the solver use.
+ int num_threads;
+
+ // Hints about the order in which the parameter blocks should be
+ // eliminated by the linear solver.
+ //
+ // For example if elimination_groups is a vector of size k, then
+ // the linear solver is informed that it should eliminate the
+ // parameter blocks 0 ... elimination_groups[0] - 1 first, and
+ // then elimination_groups[0] ... elimination_groups[1] - 1 and so
+ // on. Within each elimination group, the linear solver is free to
+ // choose how the parameter blocks are ordered. Different linear
+ // solvers have differing requirements on elimination_groups.
+ //
+ // The most common use is for Schur type solvers, where there
+ // should be at least two elimination groups and the first
+ // elimination group must form an independent set in the normal
+ // equations. The first elimination group corresponds to the
+ // num_eliminate_blocks in the Schur type solvers.
+ std::vector<int> elimination_groups;
+
+ // Iterative solvers, e.g. Preconditioned Conjugate Gradients
+ // maintain a cheap estimate of the residual which may become
+ // inaccurate over time. Thus for non-zero values of this
+ // parameter, the solver can be told to recalculate the value of
+ // the residual using a |b - Ax| evaluation.
+ int residual_reset_period;
+
+ // If the block sizes in a BlockSparseMatrix are fixed, then in
+ // some cases the Schur complement based solvers can detect and
+ // specialize on them.
+ //
+ // It is expected that these parameters are set programmatically
+ // rather than manually.
+ //
+ // Please see schur_complement_solver.h and schur_eliminator.h for
+ // more details.
+ int row_block_size;
+ int e_block_size;
+ int f_block_size;
+ };
+
+ // Options for the Solve method.
+ struct PerSolveOptions {
+ PerSolveOptions()
+ : D(NULL),
+ preconditioner(NULL),
+ r_tolerance(0.0),
+ q_tolerance(0.0) {
+ }
+
+ // This option only makes sense for unsymmetric linear solvers
+ // that can solve rectangular linear systems.
+ //
+ // Given a matrix A, an optional diagonal matrix D as a vector,
+ // and a vector b, the linear solver will solve for
+ //
+ // | A | x = | b |
+ // | D | | 0 |
+ //
+ // If D is null, then it is treated as zero, and the solver returns
+ // the solution to
+ //
+ // A x = b
+ //
+ // In either case, x is the vector that solves the following
+ // optimization problem.
+ //
+ // arg min_x ||Ax - b||^2 + ||Dx||^2
+ //
+ // Here A is a matrix of size m x n, with full column rank. If A
+ // does not have full column rank, the results returned by the
+ // solver cannot be relied on. D, if it is not null is an array of
+ // size n. b is an array of size m and x is an array of size n.
+ double * D;
+
+ // This option only makes sense for iterative solvers.
+ //
+ // In general the performance of an iterative linear solver
+ // depends on the condition number of the matrix A. For example
+ // the convergence rate of the conjugate gradients algorithm
+ // is proportional to the square root of the condition number.
+ //
+ // One particularly useful technique for improving the
+ // conditioning of a linear system is to precondition it. In its
+ // simplest form a preconditioner is a matrix M such that instead
+ // of solving Ax = b, we solve the linear system AM^{-1} y = b
+ // instead, where M is such that the condition number k(AM^{-1})
+ // is smaller than the conditioner k(A). Given the solution to
+ // this system, x = M^{-1} y. The iterative solver takes care of
+ // the mechanics of solving the preconditioned system and
+ // returning the corrected solution x. The user only needs to
+ // supply a linear operator.
+ //
+ // A null preconditioner is equivalent to an identity matrix being
+ // used a preconditioner.
+ LinearOperator* preconditioner;
+
+
+ // The following tolerance related options only makes sense for
+ // iterative solvers. Direct solvers ignore them.
+
+ // Solver terminates when
+ //
+ // |Ax - b| <= r_tolerance * |b|.
+ //
+ // This is the most commonly used termination criterion for
+ // iterative solvers.
+ double r_tolerance;
+
+ // For PSD matrices A, let
+ //
+ // Q(x) = x'Ax - 2b'x
+ //
+ // be the cost of the quadratic function defined by A and b. Then,
+ // the solver terminates at iteration i if
+ //
+ // i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
+ //
+ // This termination criterion is more useful when using CG to
+ // solve the Newton step. This particular convergence test comes
+ // from Stephen Nash's work on truncated Newton
+ // methods. References:
+ //
+ // 1. Stephen G. Nash & Ariela Sofer, Assessing A Search
+ // Direction Within A Truncated Newton Method, Operation
+ // Research Letters 9(1990) 219-221.
+ //
+ // 2. Stephen G. Nash, A Survey of Truncated Newton Methods,
+ // Journal of Computational and Applied Mathematics,
+ // 124(1-2), 45-59, 2000.
+ //
+ double q_tolerance;
+ };
+
+ // Summary of a call to the Solve method. We should move away from
+ // the true/false method for determining solver success. We should
+ // let the summary object do the talking.
+ struct Summary {
+ Summary()
+ : residual_norm(0.0),
+ num_iterations(-1),
+ termination_type(LINEAR_SOLVER_FAILURE) {
+ }
+
+ double residual_norm;
+ int num_iterations;
+ LinearSolverTerminationType termination_type;
+ std::string message;
+ };
+
+ // If the optimization problem is such that there are no remaining
+ // e-blocks, a Schur type linear solver cannot be used. If the
+ // linear solver is of Schur type, this function implements a policy
+ // to select an alternate nearest linear solver to the one selected
+ // by the user. The input linear_solver_type is returned otherwise.
+ static LinearSolverType LinearSolverForZeroEBlocks(
+ LinearSolverType linear_solver_type);
+
+ virtual ~LinearSolver();
+
+ // Solve Ax = b.
+ virtual Summary Solve(LinearOperator* A,
+ const double* b,
+ const PerSolveOptions& per_solve_options,
+ double* x) = 0;
+
+ // The following two methods return copies instead of references so
+ // that the base class implementation does not have to worry about
+ // life time issues. Further, these calls are not expected to be
+ // frequent or performance sensitive.
+ virtual std::map<std::string, int> CallStatistics() const {
+ return std::map<std::string, int>();
+ }
+
+ virtual std::map<std::string, double> TimeStatistics() const {
+ return std::map<std::string, double>();
+ }
+
+ // Factory
+ static LinearSolver* Create(const Options& options);
+};
+
+// This templated subclass of LinearSolver serves as a base class for
+// other linear solvers that depend on the particular matrix layout of
+// the underlying linear operator. For example some linear solvers
+// need low level access to the TripletSparseMatrix implementing the
+// LinearOperator interface. This class hides those implementation
+// details behind a private virtual method, and has the Solve method
+// perform the necessary upcasting.
+template <typename MatrixType>
+class TypedLinearSolver : public LinearSolver {
+ public:
+ virtual ~TypedLinearSolver() {}
+ virtual LinearSolver::Summary Solve(
+ LinearOperator* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_);
+ CHECK_NOTNULL(A);
+ CHECK_NOTNULL(b);
+ CHECK_NOTNULL(x);
+ return SolveImpl(down_cast<MatrixType*>(A), b, per_solve_options, x);
+ }
+
+ virtual std::map<std::string, int> CallStatistics() const {
+ return execution_summary_.calls();
+ }
+
+ virtual std::map<std::string, double> TimeStatistics() const {
+ return execution_summary_.times();
+ }
+
+ private:
+ virtual LinearSolver::Summary SolveImpl(
+ MatrixType* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) = 0;
+
+ ExecutionSummary execution_summary_;
+};
+
+// Linear solvers that depend on acccess to the low level structure of
+// a SparseMatrix.
+typedef TypedLinearSolver<BlockSparseMatrix> BlockSparseMatrixSolver; // NOLINT
+typedef TypedLinearSolver<CompressedRowSparseMatrix> CompressedRowSparseMatrixSolver; // NOLINT
+typedef TypedLinearSolver<DenseSparseMatrix> DenseSparseMatrixSolver; // NOLINT
+typedef TypedLinearSolver<TripletSparseMatrix> TripletSparseMatrixSolver; // NOLINT
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LINEAR_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/local_parameterization.cc b/extern/ceres/internal/ceres/local_parameterization.cc
new file mode 100644
index 00000000000..82004761ec0
--- /dev/null
+++ b/extern/ceres/internal/ceres/local_parameterization.cc
@@ -0,0 +1,345 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/local_parameterization.h"
+
+#include "ceres/householder_vector.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/rotation.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+using std::vector;
+
+LocalParameterization::~LocalParameterization() {
+}
+
+bool LocalParameterization::MultiplyByJacobian(const double* x,
+ const int num_rows,
+ const double* global_matrix,
+ double* local_matrix) const {
+ Matrix jacobian(GlobalSize(), LocalSize());
+ if (!ComputeJacobian(x, jacobian.data())) {
+ return false;
+ }
+
+ MatrixRef(local_matrix, num_rows, LocalSize()) =
+ ConstMatrixRef(global_matrix, num_rows, GlobalSize()) * jacobian;
+ return true;
+}
+
+IdentityParameterization::IdentityParameterization(const int size)
+ : size_(size) {
+ CHECK_GT(size, 0);
+}
+
+bool IdentityParameterization::Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ VectorRef(x_plus_delta, size_) =
+ ConstVectorRef(x, size_) + ConstVectorRef(delta, size_);
+ return true;
+}
+
+bool IdentityParameterization::ComputeJacobian(const double* x,
+ double* jacobian) const {
+ MatrixRef(jacobian, size_, size_) = Matrix::Identity(size_, size_);
+ return true;
+}
+
+bool IdentityParameterization::MultiplyByJacobian(const double* x,
+ const int num_cols,
+ const double* global_matrix,
+ double* local_matrix) const {
+ std::copy(global_matrix,
+ global_matrix + num_cols * GlobalSize(),
+ local_matrix);
+ return true;
+}
+
+SubsetParameterization::SubsetParameterization(
+ int size,
+ const vector<int>& constant_parameters)
+ : local_size_(size - constant_parameters.size()),
+ constancy_mask_(size, 0) {
+ CHECK_GT(constant_parameters.size(), 0)
+ << "The set of constant parameters should contain at least "
+ << "one element. If you do not wish to hold any parameters "
+ << "constant, then do not use a SubsetParameterization";
+
+ vector<int> constant = constant_parameters;
+ sort(constant.begin(), constant.end());
+ CHECK(unique(constant.begin(), constant.end()) == constant.end())
+ << "The set of constant parameters cannot contain duplicates";
+ CHECK_LT(constant_parameters.size(), size)
+ << "Number of parameters held constant should be less "
+ << "than the size of the parameter block. If you wish "
+ << "to hold the entire parameter block constant, then a "
+ << "efficient way is to directly mark it as constant "
+ << "instead of using a LocalParameterization to do so.";
+ CHECK_GE(*min_element(constant.begin(), constant.end()), 0);
+ CHECK_LT(*max_element(constant.begin(), constant.end()), size);
+
+ for (int i = 0; i < constant_parameters.size(); ++i) {
+ constancy_mask_[constant_parameters[i]] = 1;
+ }
+}
+
+bool SubsetParameterization::Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
+ if (constancy_mask_[i]) {
+ x_plus_delta[i] = x[i];
+ } else {
+ x_plus_delta[i] = x[i] + delta[j++];
+ }
+ }
+ return true;
+}
+
+bool SubsetParameterization::ComputeJacobian(const double* x,
+ double* jacobian) const {
+ MatrixRef m(jacobian, constancy_mask_.size(), local_size_);
+ m.setZero();
+ for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
+ if (!constancy_mask_[i]) {
+ m(i, j++) = 1.0;
+ }
+ }
+ return true;
+}
+
+bool SubsetParameterization::MultiplyByJacobian(const double* x,
+ const int num_rows,
+ const double* global_matrix,
+ double* local_matrix) const {
+ for (int row = 0; row < num_rows; ++row) {
+ for (int col = 0, j = 0; col < constancy_mask_.size(); ++col) {
+ if (!constancy_mask_[col]) {
+ local_matrix[row * LocalSize() + j++] =
+ global_matrix[row * GlobalSize() + col];
+ }
+ }
+ }
+ return true;
+}
+
+bool QuaternionParameterization::Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ const double norm_delta =
+ sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
+ if (norm_delta > 0.0) {
+ const double sin_delta_by_delta = (sin(norm_delta) / norm_delta);
+ double q_delta[4];
+ q_delta[0] = cos(norm_delta);
+ q_delta[1] = sin_delta_by_delta * delta[0];
+ q_delta[2] = sin_delta_by_delta * delta[1];
+ q_delta[3] = sin_delta_by_delta * delta[2];
+ QuaternionProduct(q_delta, x, x_plus_delta);
+ } else {
+ for (int i = 0; i < 4; ++i) {
+ x_plus_delta[i] = x[i];
+ }
+ }
+ return true;
+}
+
+bool QuaternionParameterization::ComputeJacobian(const double* x,
+ double* jacobian) const {
+ jacobian[0] = -x[1]; jacobian[1] = -x[2]; jacobian[2] = -x[3]; // NOLINT
+ jacobian[3] = x[0]; jacobian[4] = x[3]; jacobian[5] = -x[2]; // NOLINT
+ jacobian[6] = -x[3]; jacobian[7] = x[0]; jacobian[8] = x[1]; // NOLINT
+ jacobian[9] = x[2]; jacobian[10] = -x[1]; jacobian[11] = x[0]; // NOLINT
+ return true;
+}
+
+HomogeneousVectorParameterization::HomogeneousVectorParameterization(int size)
+ : size_(size) {
+ CHECK_GT(size_, 1) << "The size of the homogeneous vector needs to be "
+ << "greater than 1.";
+}
+
+bool HomogeneousVectorParameterization::Plus(const double* x_ptr,
+ const double* delta_ptr,
+ double* x_plus_delta_ptr) const {
+ ConstVectorRef x(x_ptr, size_);
+ ConstVectorRef delta(delta_ptr, size_ - 1);
+ VectorRef x_plus_delta(x_plus_delta_ptr, size_);
+
+ const double norm_delta = delta.norm();
+
+ if (norm_delta == 0.0) {
+ x_plus_delta = x;
+ return true;
+ }
+
+ // Map the delta from the minimum representation to the over parameterized
+ // homogeneous vector. See section A6.9.2 on page 624 of Hartley & Zisserman
+ // (2nd Edition) for a detailed description. Note there is a typo on Page
+ // 625, line 4 so check the book errata.
+ const double norm_delta_div_2 = 0.5 * norm_delta;
+ const double sin_delta_by_delta = sin(norm_delta_div_2) /
+ norm_delta_div_2;
+
+ Vector y(size_);
+ y.head(size_ - 1) = 0.5 * sin_delta_by_delta * delta;
+ y(size_ - 1) = cos(norm_delta_div_2);
+
+ Vector v(size_);
+ double beta;
+ internal::ComputeHouseholderVector<double>(x, &v, &beta);
+
+ // Apply the delta update to remain on the unit sphere. See section A6.9.3
+ // on page 625 of Hartley & Zisserman (2nd Edition) for a detailed
+ // description.
+ x_plus_delta = x.norm() * (y - v * (beta * (v.transpose() * y)));
+
+ return true;
+}
+
+bool HomogeneousVectorParameterization::ComputeJacobian(
+ const double* x_ptr, double* jacobian_ptr) const {
+ ConstVectorRef x(x_ptr, size_);
+ MatrixRef jacobian(jacobian_ptr, size_, size_ - 1);
+
+ Vector v(size_);
+ double beta;
+ internal::ComputeHouseholderVector<double>(x, &v, &beta);
+
+ // The Jacobian is equal to J = 0.5 * H.leftCols(size_ - 1) where H is the
+ // Householder matrix (H = I - beta * v * v').
+ for (int i = 0; i < size_ - 1; ++i) {
+ jacobian.col(i) = -0.5 * beta * v(i) * v;
+ jacobian.col(i)(i) += 0.5;
+ }
+ jacobian *= x.norm();
+
+ return true;
+}
+
+ProductParameterization::ProductParameterization(
+ LocalParameterization* local_param1,
+ LocalParameterization* local_param2) {
+ local_params_.push_back(local_param1);
+ local_params_.push_back(local_param2);
+ Init();
+}
+
+ProductParameterization::ProductParameterization(
+ LocalParameterization* local_param1,
+ LocalParameterization* local_param2,
+ LocalParameterization* local_param3) {
+ local_params_.push_back(local_param1);
+ local_params_.push_back(local_param2);
+ local_params_.push_back(local_param3);
+ Init();
+}
+
+ProductParameterization::ProductParameterization(
+ LocalParameterization* local_param1,
+ LocalParameterization* local_param2,
+ LocalParameterization* local_param3,
+ LocalParameterization* local_param4) {
+ local_params_.push_back(local_param1);
+ local_params_.push_back(local_param2);
+ local_params_.push_back(local_param3);
+ local_params_.push_back(local_param4);
+ Init();
+}
+
+ProductParameterization::~ProductParameterization() {
+ for (int i = 0; i < local_params_.size(); ++i) {
+ delete local_params_[i];
+ }
+}
+
+void ProductParameterization::Init() {
+ global_size_ = 0;
+ local_size_ = 0;
+ buffer_size_ = 0;
+ for (int i = 0; i < local_params_.size(); ++i) {
+ const LocalParameterization* param = local_params_[i];
+ buffer_size_ = std::max(buffer_size_,
+ param->LocalSize() * param->GlobalSize());
+ global_size_ += param->GlobalSize();
+ local_size_ += param->LocalSize();
+ }
+}
+
+bool ProductParameterization::Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ int x_cursor = 0;
+ int delta_cursor = 0;
+ for (int i = 0; i < local_params_.size(); ++i) {
+ const LocalParameterization* param = local_params_[i];
+ if (!param->Plus(x + x_cursor,
+ delta + delta_cursor,
+ x_plus_delta + x_cursor)) {
+ return false;
+ }
+ delta_cursor += param->LocalSize();
+ x_cursor += param->GlobalSize();
+ }
+
+ return true;
+}
+
+bool ProductParameterization::ComputeJacobian(const double* x,
+ double* jacobian_ptr) const {
+ MatrixRef jacobian(jacobian_ptr, GlobalSize(), LocalSize());
+ jacobian.setZero();
+ internal::FixedArray<double> buffer(buffer_size_);
+
+ int x_cursor = 0;
+ int delta_cursor = 0;
+ for (int i = 0; i < local_params_.size(); ++i) {
+ const LocalParameterization* param = local_params_[i];
+ const int local_size = param->LocalSize();
+ const int global_size = param->GlobalSize();
+
+ if (!param->ComputeJacobian(x + x_cursor, buffer.get())) {
+ return false;
+ }
+
+ jacobian.block(x_cursor, delta_cursor, global_size, local_size)
+ = MatrixRef(buffer.get(), global_size, local_size);
+ delta_cursor += local_size;
+ x_cursor += global_size;
+ }
+
+ return true;
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/loss_function.cc b/extern/ceres/internal/ceres/loss_function.cc
new file mode 100644
index 00000000000..eb5026784dd
--- /dev/null
+++ b/extern/ceres/internal/ceres/loss_function.cc
@@ -0,0 +1,174 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Purpose: See .h file.
+
+#include "ceres/loss_function.h"
+
+#include <cmath>
+#include <cstddef>
+#include <limits>
+
+namespace ceres {
+
+void TrivialLoss::Evaluate(double s, double rho[3]) const {
+ rho[0] = s;
+ rho[1] = 1.0;
+ rho[2] = 0.0;
+}
+
+void HuberLoss::Evaluate(double s, double rho[3]) const {
+ if (s > b_) {
+ // Outlier region.
+ // 'r' is always positive.
+ const double r = sqrt(s);
+ rho[0] = 2.0 * a_ * r - b_;
+ rho[1] = std::max(std::numeric_limits<double>::min(), a_ / r);
+ rho[2] = - rho[1] / (2.0 * s);
+ } else {
+ // Inlier region.
+ rho[0] = s;
+ rho[1] = 1.0;
+ rho[2] = 0.0;
+ }
+}
+
+void SoftLOneLoss::Evaluate(double s, double rho[3]) const {
+ const double sum = 1.0 + s * c_;
+ const double tmp = sqrt(sum);
+ // 'sum' and 'tmp' are always positive, assuming that 's' is.
+ rho[0] = 2.0 * b_ * (tmp - 1.0);
+ rho[1] = std::max(std::numeric_limits<double>::min(), 1.0 / tmp);
+ rho[2] = - (c_ * rho[1]) / (2.0 * sum);
+}
+
+void CauchyLoss::Evaluate(double s, double rho[3]) const {
+ const double sum = 1.0 + s * c_;
+ const double inv = 1.0 / sum;
+ // 'sum' and 'inv' are always positive, assuming that 's' is.
+ rho[0] = b_ * log(sum);
+ rho[1] = std::max(std::numeric_limits<double>::min(), inv);
+ rho[2] = - c_ * (inv * inv);
+}
+
+void ArctanLoss::Evaluate(double s, double rho[3]) const {
+ const double sum = 1 + s * s * b_;
+ const double inv = 1 / sum;
+ // 'sum' and 'inv' are always positive.
+ rho[0] = a_ * atan2(s, a_);
+ rho[1] = std::max(std::numeric_limits<double>::min(), inv);
+ rho[2] = -2.0 * s * b_ * (inv * inv);
+}
+
+TolerantLoss::TolerantLoss(double a, double b)
+ : a_(a),
+ b_(b),
+ c_(b * log(1.0 + exp(-a / b))) {
+ CHECK_GE(a, 0.0);
+ CHECK_GT(b, 0.0);
+}
+
+void TolerantLoss::Evaluate(double s, double rho[3]) const {
+ const double x = (s - a_) / b_;
+ // The basic equation is rho[0] = b ln(1 + e^x). However, if e^x is too
+ // large, it will overflow. Since numerically 1 + e^x == e^x when the
+ // x is greater than about ln(2^53) for doubles, beyond this threshold
+ // we substitute x for ln(1 + e^x) as a numerically equivalent approximation.
+ static const double kLog2Pow53 = 36.7; // ln(MathLimits<double>::kEpsilon).
+ if (x > kLog2Pow53) {
+ rho[0] = s - a_ - c_;
+ rho[1] = 1.0;
+ rho[2] = 0.0;
+ } else {
+ const double e_x = exp(x);
+ rho[0] = b_ * log(1.0 + e_x) - c_;
+ rho[1] = std::max(std::numeric_limits<double>::min(), e_x / (1.0 + e_x));
+ rho[2] = 0.5 / (b_ * (1.0 + cosh(x)));
+ }
+}
+
+void TukeyLoss::Evaluate(double s, double* rho) const {
+ if (s <= a_squared_) {
+ // Inlier region.
+ const double value = 1.0 - s / a_squared_;
+ const double value_sq = value * value;
+ rho[0] = a_squared_ / 6.0 * (1.0 - value_sq * value);
+ rho[1] = 0.5 * value_sq;
+ rho[2] = -1.0 / a_squared_ * value;
+ } else {
+ // Outlier region.
+ rho[0] = a_squared_ / 6.0;
+ rho[1] = 0.0;
+ rho[2] = 0.0;
+ }
+}
+
+ComposedLoss::ComposedLoss(const LossFunction* f, Ownership ownership_f,
+ const LossFunction* g, Ownership ownership_g)
+ : f_(CHECK_NOTNULL(f)),
+ g_(CHECK_NOTNULL(g)),
+ ownership_f_(ownership_f),
+ ownership_g_(ownership_g) {
+}
+
+ComposedLoss::~ComposedLoss() {
+ if (ownership_f_ == DO_NOT_TAKE_OWNERSHIP) {
+ f_.release();
+ }
+ if (ownership_g_ == DO_NOT_TAKE_OWNERSHIP) {
+ g_.release();
+ }
+}
+
+void ComposedLoss::Evaluate(double s, double rho[3]) const {
+ double rho_f[3], rho_g[3];
+ g_->Evaluate(s, rho_g);
+ f_->Evaluate(rho_g[0], rho_f);
+ rho[0] = rho_f[0];
+ // f'(g(s)) * g'(s).
+ rho[1] = rho_f[1] * rho_g[1];
+ // f''(g(s)) * g'(s) * g'(s) + f'(g(s)) * g''(s).
+ rho[2] = rho_f[2] * rho_g[1] * rho_g[1] + rho_f[1] * rho_g[2];
+}
+
+void ScaledLoss::Evaluate(double s, double rho[3]) const {
+ if (rho_.get() == NULL) {
+ rho[0] = a_ * s;
+ rho[1] = a_;
+ rho[2] = 0.0;
+ } else {
+ rho_->Evaluate(s, rho);
+ rho[0] *= a_;
+ rho[1] *= a_;
+ rho[2] *= a_;
+ }
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc b/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc
new file mode 100644
index 00000000000..1c6c9925f1c
--- /dev/null
+++ b/extern/ceres/internal/ceres/low_rank_inverse_hessian.cc
@@ -0,0 +1,188 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <list>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/low_rank_inverse_hessian.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::list;
+
+// The (L)BFGS algorithm explicitly requires that the secant equation:
+//
+// B_{k+1} * s_k = y_k
+//
+// Is satisfied at each iteration, where B_{k+1} is the approximated
+// Hessian at the k+1-th iteration, s_k = (x_{k+1} - x_{k}) and
+// y_k = (grad_{k+1} - grad_{k}). As the approximated Hessian must be
+// positive definite, this is equivalent to the condition:
+//
+// s_k^T * y_k > 0 [s_k^T * B_{k+1} * s_k = s_k^T * y_k > 0]
+//
+// This condition would always be satisfied if the function was strictly
+// convex, alternatively, it is always satisfied provided that a Wolfe line
+// search is used (even if the function is not strictly convex). See [1]
+// (p138) for a proof.
+//
+// Although Ceres will always use a Wolfe line search when using (L)BFGS,
+// practical implementation considerations mean that the line search
+// may return a point that satisfies only the Armijo condition, and thus
+// could violate the Secant equation. As such, we will only use a step
+// to update the Hessian approximation if:
+//
+// s_k^T * y_k > tolerance
+//
+// It is important that tolerance is very small (and >=0), as otherwise we
+// might skip the update too often and fail to capture important curvature
+// information in the Hessian. For example going from 1e-10 -> 1e-14 improves
+// the NIST benchmark score from 43/54 to 53/54.
+//
+// [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed. Springer, 1999.
+//
+// TODO(alexs.mac): Consider using Damped BFGS update instead of
+// skipping update.
+const double kLBFGSSecantConditionHessianUpdateTolerance = 1e-14;
+
+LowRankInverseHessian::LowRankInverseHessian(
+ int num_parameters,
+ int max_num_corrections,
+ bool use_approximate_eigenvalue_scaling)
+ : num_parameters_(num_parameters),
+ max_num_corrections_(max_num_corrections),
+ use_approximate_eigenvalue_scaling_(use_approximate_eigenvalue_scaling),
+ approximate_eigenvalue_scale_(1.0),
+ delta_x_history_(num_parameters, max_num_corrections),
+ delta_gradient_history_(num_parameters, max_num_corrections),
+ delta_x_dot_delta_gradient_(max_num_corrections) {
+}
+
+bool LowRankInverseHessian::Update(const Vector& delta_x,
+ const Vector& delta_gradient) {
+ const double delta_x_dot_delta_gradient = delta_x.dot(delta_gradient);
+ if (delta_x_dot_delta_gradient <=
+ kLBFGSSecantConditionHessianUpdateTolerance) {
+ VLOG(2) << "Skipping L-BFGS Update, delta_x_dot_delta_gradient too "
+ << "small: " << delta_x_dot_delta_gradient << ", tolerance: "
+ << kLBFGSSecantConditionHessianUpdateTolerance
+ << " (Secant condition).";
+ return false;
+ }
+
+
+ int next = indices_.size();
+ // Once the size of the list reaches max_num_corrections_, simulate
+ // a circular buffer by removing the first element of the list and
+ // making it the next position where the LBFGS history is stored.
+ if (next == max_num_corrections_) {
+ next = indices_.front();
+ indices_.pop_front();
+ }
+
+ indices_.push_back(next);
+ delta_x_history_.col(next) = delta_x;
+ delta_gradient_history_.col(next) = delta_gradient;
+ delta_x_dot_delta_gradient_(next) = delta_x_dot_delta_gradient;
+ approximate_eigenvalue_scale_ =
+ delta_x_dot_delta_gradient / delta_gradient.squaredNorm();
+ return true;
+}
+
+void LowRankInverseHessian::RightMultiply(const double* x_ptr,
+ double* y_ptr) const {
+ ConstVectorRef gradient(x_ptr, num_parameters_);
+ VectorRef search_direction(y_ptr, num_parameters_);
+
+ search_direction = gradient;
+
+ const int num_corrections = indices_.size();
+ Vector alpha(num_corrections);
+
+ for (list<int>::const_reverse_iterator it = indices_.rbegin();
+ it != indices_.rend();
+ ++it) {
+ const double alpha_i = delta_x_history_.col(*it).dot(search_direction) /
+ delta_x_dot_delta_gradient_(*it);
+ search_direction -= alpha_i * delta_gradient_history_.col(*it);
+ alpha(*it) = alpha_i;
+ }
+
+ if (use_approximate_eigenvalue_scaling_) {
+ // Rescale the initial inverse Hessian approximation (H_0) to be iteratively
+ // updated so that it is of similar 'size' to the true inverse Hessian along
+ // the most recent search direction. As shown in [1]:
+ //
+ // \gamma_k = (delta_gradient_{k-1}' * delta_x_{k-1}) /
+ // (delta_gradient_{k-1}' * delta_gradient_{k-1})
+ //
+ // Satisfies:
+ //
+ // (1 / \lambda_m) <= \gamma_k <= (1 / \lambda_1)
+ //
+ // Where \lambda_1 & \lambda_m are the smallest and largest eigenvalues of
+ // the true Hessian (not the inverse) along the most recent search direction
+ // respectively. Thus \gamma is an approximate eigenvalue of the true
+ // inverse Hessian, and choosing: H_0 = I * \gamma will yield a starting
+ // point that has a similar scale to the true inverse Hessian. This
+ // technique is widely reported to often improve convergence, however this
+ // is not universally true, particularly if there are errors in the initial
+ // jacobians, or if there are significant differences in the sensitivity
+ // of the problem to the parameters (i.e. the range of the magnitudes of
+ // the components of the gradient is large).
+ //
+ // The original origin of this rescaling trick is somewhat unclear, the
+ // earliest reference appears to be Oren [1], however it is widely discussed
+ // without specific attributation in various texts including [2] (p143/178).
+ //
+ // [1] Oren S.S., Self-scaling variable metric (SSVM) algorithms Part II:
+ // Implementation and experiments, Management Science,
+ // 20(5), 863-874, 1974.
+ // [2] Nocedal J., Wright S., Numerical Optimization, Springer, 1999.
+ search_direction *= approximate_eigenvalue_scale_;
+
+ VLOG(4) << "Applying approximate_eigenvalue_scale: "
+ << approximate_eigenvalue_scale_ << " to initial inverse Hessian "
+ << "approximation.";
+ }
+
+ for (list<int>::const_iterator it = indices_.begin();
+ it != indices_.end();
+ ++it) {
+ const double beta = delta_gradient_history_.col(*it).dot(search_direction) /
+ delta_x_dot_delta_gradient_(*it);
+ search_direction += delta_x_history_.col(*it) * (alpha(*it) - beta);
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/low_rank_inverse_hessian.h b/extern/ceres/internal/ceres/low_rank_inverse_hessian.h
new file mode 100644
index 00000000000..2c768c2ca53
--- /dev/null
+++ b/extern/ceres/internal/ceres/low_rank_inverse_hessian.h
@@ -0,0 +1,108 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Limited memory positive definite approximation to the inverse
+// Hessian, using the LBFGS algorithm
+
+#ifndef CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
+#define CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
+
+#include <list>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_operator.h"
+
+namespace ceres {
+namespace internal {
+
+// LowRankInverseHessian is a positive definite approximation to the
+// Hessian using the limited memory variant of the
+// Broyden-Fletcher-Goldfarb-Shanno (BFGS)secant formula for
+// approximating the Hessian.
+//
+// Other update rules like the Davidon-Fletcher-Powell (DFP) are
+// possible, but the BFGS rule is considered the best performing one.
+//
+// The limited memory variant was developed by Nocedal and further
+// enhanced with scaling rule by Byrd, Nocedal and Schanbel.
+//
+// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
+// Storage". Mathematics of Computation 35 (151): 773–782.
+//
+// Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
+// "Representations of Quasi-Newton Matrices and their use in
+// Limited Memory Methods". Mathematical Programming 63 (4):
+class LowRankInverseHessian : public LinearOperator {
+ public:
+ // num_parameters is the row/column size of the Hessian.
+ // max_num_corrections is the rank of the Hessian approximation.
+ // use_approximate_eigenvalue_scaling controls whether the initial
+ // inverse Hessian used during Right/LeftMultiply() is scaled by
+ // the approximate eigenvalue of the true inverse Hessian at the
+ // current operating point.
+ // The approximation uses:
+ // 2 * max_num_corrections * num_parameters + max_num_corrections
+ // doubles.
+ LowRankInverseHessian(int num_parameters,
+ int max_num_corrections,
+ bool use_approximate_eigenvalue_scaling);
+ virtual ~LowRankInverseHessian() {}
+
+ // Update the low rank approximation. delta_x is the change in the
+ // domain of Hessian, and delta_gradient is the change in the
+ // gradient. The update copies the delta_x and delta_gradient
+ // vectors, and gets rid of the oldest delta_x and delta_gradient
+ // vectors if the number of corrections is already equal to
+ // max_num_corrections.
+ bool Update(const Vector& delta_x, const Vector& delta_gradient);
+
+ // LinearOperator interface
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual void LeftMultiply(const double* x, double* y) const {
+ RightMultiply(x, y);
+ }
+ virtual int num_rows() const { return num_parameters_; }
+ virtual int num_cols() const { return num_parameters_; }
+
+ private:
+ const int num_parameters_;
+ const int max_num_corrections_;
+ const bool use_approximate_eigenvalue_scaling_;
+ double approximate_eigenvalue_scale_;
+ ColMajorMatrix delta_x_history_;
+ ColMajorMatrix delta_gradient_history_;
+ Vector delta_x_dot_delta_gradient_;
+ std::list<int> indices_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
diff --git a/extern/ceres/internal/ceres/map_util.h b/extern/ceres/internal/ceres/map_util.h
new file mode 100644
index 00000000000..61c531f297c
--- /dev/null
+++ b/extern/ceres/internal/ceres/map_util.h
@@ -0,0 +1,130 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// Originally by Anton Carver
+
+#ifndef CERES_INTERNAL_MAP_UTIL_H_
+#define CERES_INTERNAL_MAP_UTIL_H_
+
+#include <utility>
+#include "ceres/internal/port.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// Perform a lookup in a map or hash_map, assuming that the key exists.
+// Crash if it does not.
+//
+// This is intended as a replacement for operator[] as an rvalue (for reading)
+// when the key is guaranteed to exist.
+//
+// operator[] is discouraged for several reasons:
+// * It has a side-effect of inserting missing keys
+// * It is not thread-safe (even when it is not inserting, it can still
+// choose to resize the underlying storage)
+// * It invalidates iterators (when it chooses to resize)
+// * It default constructs a value object even if it doesn't need to
+//
+// This version assumes the key is printable, and includes it in the fatal log
+// message.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindOrDie(const Collection& collection,
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ CHECK(it != collection.end()) << "Map key not found: " << key;
+ return it->second;
+}
+
+// Perform a lookup in a map or hash_map.
+// If the key is present in the map then the value associated with that
+// key is returned, otherwise the value passed as a default is returned.
+template <class Collection>
+const typename Collection::value_type::second_type&
+FindWithDefault(const Collection& collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ typename Collection::const_iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return value;
+ }
+ return it->second;
+}
+
+// Insert a new key and value into a map or hash_map.
+// If the key is not present in the map the key and value are
+// inserted, otherwise nothing happens. True indicates that an insert
+// took place, false indicates the key was already present.
+template <class Collection>
+bool InsertIfNotPresent(
+ Collection * const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& value) {
+ std::pair<typename Collection::iterator, bool> ret =
+ collection->insert(typename Collection::value_type(key, value));
+ return ret.second;
+}
+
+// Perform a lookup in a map or hash_map.
+// Same as above but the returned pointer is not const and can be used to change
+// the stored value.
+template <class Collection>
+typename Collection::value_type::second_type*
+FindOrNull(Collection& collection, // NOLINT
+ const typename Collection::value_type::first_type& key) {
+ typename Collection::iterator it = collection.find(key);
+ if (it == collection.end()) {
+ return 0;
+ }
+ return &it->second;
+}
+
+// Test to see if a set, map, hash_set or hash_map contains a particular key.
+// Returns true if the key is in the collection.
+template <class Collection, class Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+ typename Collection::const_iterator it = collection.find(key);
+ return it != collection.end();
+}
+
+// Inserts a new key/value into a map or hash_map.
+// Dies if the key is already present.
+template<class Collection>
+void InsertOrDie(Collection* const collection,
+ const typename Collection::value_type::first_type& key,
+ const typename Collection::value_type::second_type& data) {
+ typedef typename Collection::value_type value_type;
+ CHECK(collection->insert(value_type(key, data)).second)
+ << "duplicate key: " << key;
+}
+
+} // namespace ceres
+
+#endif // CERES_INTERNAL_MAP_UTIL_H_
diff --git a/extern/ceres/internal/ceres/minimizer.cc b/extern/ceres/internal/ceres/minimizer.cc
new file mode 100644
index 00000000000..f5960336f12
--- /dev/null
+++ b/extern/ceres/internal/ceres/minimizer.cc
@@ -0,0 +1,87 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/line_search_minimizer.h"
+#include "ceres/minimizer.h"
+#include "ceres/trust_region_minimizer.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Minimizer* Minimizer::Create(MinimizerType minimizer_type) {
+ if (minimizer_type == TRUST_REGION) {
+ return new TrustRegionMinimizer;
+ }
+
+ if (minimizer_type == LINE_SEARCH) {
+ return new LineSearchMinimizer;
+ }
+
+ LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
+ return NULL;
+}
+
+
+Minimizer::~Minimizer() {}
+
+bool Minimizer::RunCallbacks(const Minimizer::Options& options,
+ const IterationSummary& iteration_summary,
+ Solver::Summary* summary) {
+ const bool is_not_silent = !options.is_silent;
+ CallbackReturnType status = SOLVER_CONTINUE;
+ int i = 0;
+ while (status == SOLVER_CONTINUE && i < options.callbacks.size()) {
+ status = (*options.callbacks[i])(iteration_summary);
+ ++i;
+ }
+ switch (status) {
+ case SOLVER_CONTINUE:
+ return true;
+ case SOLVER_TERMINATE_SUCCESSFULLY:
+ summary->termination_type = USER_SUCCESS;
+ summary->message =
+ "User callback returned SOLVER_TERMINATE_SUCCESSFULLY.";
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return false;
+ case SOLVER_ABORT:
+ summary->termination_type = USER_FAILURE;
+ summary->message = "User callback returned SOLVER_ABORT.";
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return false;
+ default:
+ LOG(FATAL) << "Unknown type of user callback status";
+ }
+ return false;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/minimizer.h b/extern/ceres/internal/ceres/minimizer.h
new file mode 100644
index 00000000000..b59372806e7
--- /dev/null
+++ b/extern/ceres/internal/ceres/minimizer.h
@@ -0,0 +1,202 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_MINIMIZER_H_
+#define CERES_INTERNAL_MINIMIZER_H_
+
+#include <string>
+#include <vector>
+#include "ceres/internal/port.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/solver.h"
+
+namespace ceres {
+namespace internal {
+
+class Evaluator;
+class SparseMatrix;
+class TrustRegionStrategy;
+class CoordinateDescentMinimizer;
+class LinearSolver;
+
+// Interface for non-linear least squares solvers.
+class Minimizer {
+ public:
+ // Options struct to control the behaviour of the Minimizer. Please
+ // see solver.h for detailed information about the meaning and
+ // default values of each of these parameters.
+ struct Options {
+ Options() {
+ Init(Solver::Options());
+ }
+
+ explicit Options(const Solver::Options& options) {
+ Init(options);
+ }
+
+ void Init(const Solver::Options& options) {
+ num_threads = options.num_threads;
+ max_num_iterations = options.max_num_iterations;
+ max_solver_time_in_seconds = options.max_solver_time_in_seconds;
+ max_step_solver_retries = 5;
+ gradient_tolerance = options.gradient_tolerance;
+ parameter_tolerance = options.parameter_tolerance;
+ function_tolerance = options.function_tolerance;
+ min_relative_decrease = options.min_relative_decrease;
+ eta = options.eta;
+ jacobi_scaling = options.jacobi_scaling;
+ use_nonmonotonic_steps = options.use_nonmonotonic_steps;
+ max_consecutive_nonmonotonic_steps =
+ options.max_consecutive_nonmonotonic_steps;
+ trust_region_problem_dump_directory =
+ options.trust_region_problem_dump_directory;
+ trust_region_minimizer_iterations_to_dump =
+ options.trust_region_minimizer_iterations_to_dump;
+ trust_region_problem_dump_format_type =
+ options.trust_region_problem_dump_format_type;
+ max_num_consecutive_invalid_steps =
+ options.max_num_consecutive_invalid_steps;
+ min_trust_region_radius = options.min_trust_region_radius;
+ line_search_direction_type = options.line_search_direction_type;
+ line_search_type = options.line_search_type;
+ nonlinear_conjugate_gradient_type =
+ options.nonlinear_conjugate_gradient_type;
+ max_lbfgs_rank = options.max_lbfgs_rank;
+ use_approximate_eigenvalue_bfgs_scaling =
+ options.use_approximate_eigenvalue_bfgs_scaling;
+ line_search_interpolation_type =
+ options.line_search_interpolation_type;
+ min_line_search_step_size = options.min_line_search_step_size;
+ line_search_sufficient_function_decrease =
+ options.line_search_sufficient_function_decrease;
+ max_line_search_step_contraction =
+ options.max_line_search_step_contraction;
+ min_line_search_step_contraction =
+ options.min_line_search_step_contraction;
+ max_num_line_search_step_size_iterations =
+ options.max_num_line_search_step_size_iterations;
+ max_num_line_search_direction_restarts =
+ options.max_num_line_search_direction_restarts;
+ line_search_sufficient_curvature_decrease =
+ options.line_search_sufficient_curvature_decrease;
+ max_line_search_step_expansion =
+ options.max_line_search_step_expansion;
+ inner_iteration_tolerance = options.inner_iteration_tolerance;
+ is_silent = (options.logging_type == SILENT);
+ is_constrained = false;
+ callbacks = options.callbacks;
+ }
+
+ int max_num_iterations;
+ double max_solver_time_in_seconds;
+ int num_threads;
+
+ // Number of times the linear solver should be retried in case of
+ // numerical failure. The retries are done by exponentially scaling up
+ // mu at each retry. This leads to stronger and stronger
+ // regularization making the linear least squares problem better
+ // conditioned at each retry.
+ int max_step_solver_retries;
+ double gradient_tolerance;
+ double parameter_tolerance;
+ double function_tolerance;
+ double min_relative_decrease;
+ double eta;
+ bool jacobi_scaling;
+ bool use_nonmonotonic_steps;
+ int max_consecutive_nonmonotonic_steps;
+ std::vector<int> trust_region_minimizer_iterations_to_dump;
+ DumpFormatType trust_region_problem_dump_format_type;
+ std::string trust_region_problem_dump_directory;
+ int max_num_consecutive_invalid_steps;
+ double min_trust_region_radius;
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ int max_lbfgs_rank;
+ bool use_approximate_eigenvalue_bfgs_scaling;
+ LineSearchInterpolationType line_search_interpolation_type;
+ double min_line_search_step_size;
+ double line_search_sufficient_function_decrease;
+ double max_line_search_step_contraction;
+ double min_line_search_step_contraction;
+ int max_num_line_search_step_size_iterations;
+ int max_num_line_search_direction_restarts;
+ double line_search_sufficient_curvature_decrease;
+ double max_line_search_step_expansion;
+ double inner_iteration_tolerance;
+
+ // If true, then all logging is disabled.
+ bool is_silent;
+
+ // Use a bounds constrained optimization algorithm.
+ bool is_constrained;
+
+ // List of callbacks that are executed by the Minimizer at the end
+ // of each iteration.
+ //
+ // The Options struct does not own these pointers.
+ std::vector<IterationCallback*> callbacks;
+
+ // Object responsible for evaluating the cost, residuals and
+ // Jacobian matrix.
+ shared_ptr<Evaluator> evaluator;
+
+ // Object responsible for actually computing the trust region
+ // step, and sizing the trust region radius.
+ shared_ptr<TrustRegionStrategy> trust_region_strategy;
+
+ // Object holding the Jacobian matrix. It is assumed that the
+ // sparsity structure of the matrix has already been initialized
+ // and will remain constant for the life time of the
+ // optimization.
+ shared_ptr<SparseMatrix> jacobian;
+
+ shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+ };
+
+ static Minimizer* Create(MinimizerType minimizer_type);
+ static bool RunCallbacks(const Options& options,
+ const IterationSummary& iteration_summary,
+ Solver::Summary* summary);
+
+ virtual ~Minimizer();
+ // Note: The minimizer is expected to update the state of the
+ // parameters array every iteration. This is required for the
+ // StateUpdatingCallback to work.
+ virtual void Minimize(const Options& options,
+ double* parameters,
+ Solver::Summary* summary) = 0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_MINIMIZER_H_
diff --git a/extern/ceres/internal/ceres/mutex.h b/extern/ceres/internal/ceres/mutex.h
new file mode 100644
index 00000000000..2ce97772755
--- /dev/null
+++ b/extern/ceres/internal/ceres/mutex.h
@@ -0,0 +1,329 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Craig Silverstein.
+//
+// A simple mutex wrapper, supporting locks and read-write locks.
+// You should assume the locks are *not* re-entrant.
+//
+// This class is meant to be internal-only and should be wrapped by an
+// internal namespace. Before you use this module, please give the
+// name of your internal namespace for this module. Or, if you want
+// to expose it, you'll want to move it to the Google namespace. We
+// cannot put this class in global namespace because there can be some
+// problems when we have multiple versions of Mutex in each shared object.
+//
+// NOTE: by default, we have #ifdef'ed out the TryLock() method.
+// This is for two reasons:
+// 1) TryLock() under Windows is a bit annoying (it requires a
+// #define to be defined very early).
+// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
+// mode.
+// If you need TryLock(), and either these two caveats are not a
+// problem for you, or you're willing to work around them, then
+// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
+// in the code below.
+//
+// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
+// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
+// Because of that, we might as well use windows locks for
+// cygwin. They seem to be more reliable than the cygwin pthreads layer.
+//
+// TRICKY IMPLEMENTATION NOTE:
+// This class is designed to be safe to use during
+// dynamic-initialization -- that is, by global constructors that are
+// run before main() starts. The issue in this case is that
+// dynamic-initialization happens in an unpredictable order, and it
+// could be that someone else's dynamic initializer could call a
+// function that tries to acquire this mutex -- but that all happens
+// before this mutex's constructor has run. (This can happen even if
+// the mutex and the function that uses the mutex are in the same .cc
+// file.) Basically, because Mutex does non-trivial work in its
+// constructor, it's not, in the naive implementation, safe to use
+// before dynamic initialization has run on it.
+//
+// The solution used here is to pair the actual mutex primitive with a
+// bool that is set to true when the mutex is dynamically initialized.
+// (Before that it's false.) Then we modify all mutex routines to
+// look at the bool, and not try to lock/unlock until the bool makes
+// it to true (which happens after the Mutex constructor has run.)
+//
+// This works because before main() starts -- particularly, during
+// dynamic initialization -- there are no threads, so a) it's ok that
+// the mutex operations are a no-op, since we don't need locking then
+// anyway; and b) we can be quite confident our bool won't change
+// state between a call to Lock() and a call to Unlock() (that would
+// require a global constructor in one translation unit to call Lock()
+// and another global constructor in another translation unit to call
+// Unlock() later, which is pretty perverse).
+//
+// That said, it's tricky, and can conceivably fail; it's safest to
+// avoid trying to acquire a mutex in a global constructor, if you
+// can. One way it can fail is that a really smart compiler might
+// initialize the bool to true at static-initialization time (too
+// early) rather than at dynamic-initialization time. To discourage
+// that, we set is_safe_ to true in code (not the constructor
+// colon-initializer) and set it to true via a function that always
+// evaluates to true, but that the compiler can't know always
+// evaluates to true. This should be good enough.
+
+#ifndef CERES_INTERNAL_MUTEX_H_
+#define CERES_INTERNAL_MUTEX_H_
+
+#include "ceres/internal/port.h"
+
+#if defined(CERES_NO_THREADS)
+ typedef int MutexType; // to keep a lock-count
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+# define CERES_WIN32_LEAN_AND_MEAN // We only need minimal includes
+# ifdef CERES_GMUTEX_TRYLOCK
+ // We need Windows NT or later for TryEnterCriticalSection(). If you
+ // don't need that functionality, you can remove these _WIN32_WINNT
+ // lines, and change TryLock() to assert(0) or something.
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+# endif
+# endif
+// Unfortunately, windows.h defines a bunch of macros with common
+// names. Two in particular need avoiding: ERROR and min/max.
+// To avoid macro definition of ERROR.
+# define NOGDI
+// To avoid macro definition of min/max.
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include <windows.h>
+ typedef CRITICAL_SECTION MutexType;
+#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
+ // Needed for pthread_rwlock_*. If it causes problems, you could take it
+ // out, but then you'd have to unset CERES_HAVE_RWLOCK (at least on linux --
+ // it *does* cause problems for FreeBSD, or MacOSX, but isn't needed for
+ // locking there.)
+# if defined(__linux__) && !defined(_XOPEN_SOURCE)
+# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
+# endif
+# include <pthread.h>
+ typedef pthread_rwlock_t MutexType;
+#elif defined(CERES_HAVE_PTHREAD)
+# include <pthread.h>
+ typedef pthread_mutex_t MutexType;
+#else
+# error Need to implement mutex.h for your architecture, or #define NO_THREADS
+#endif
+
+// We need to include these header files after defining _XOPEN_SOURCE
+// as they may define the _XOPEN_SOURCE macro.
+#include <assert.h>
+#include <stdlib.h> // for abort()
+
+namespace ceres {
+namespace internal {
+
+class Mutex {
+ public:
+ // Create a Mutex that is not held by anybody. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ // See below for a recommendation for constructing global Mutex
+ // objects.
+ inline Mutex();
+
+ // Destructor
+ inline ~Mutex();
+
+ inline void Lock(); // Block if needed until free then acquire exclusively
+ inline void Unlock(); // Release a lock acquired via Lock()
+#ifdef CERES_GMUTEX_TRYLOCK
+ inline bool TryLock(); // If free, Lock() and return true, else return false
+#endif
+ // Note that on systems that don't support read-write locks, these may
+ // be implemented as synonyms to Lock() and Unlock(). So you can use
+ // these for efficiency, but don't use them anyplace where being able
+ // to do shared reads is necessary to avoid deadlock.
+ inline void ReaderLock(); // Block until free or shared then acquire a share
+ inline void ReaderUnlock(); // Release a read share of this Mutex
+ inline void WriterLock() { Lock(); } // Acquire an exclusive lock
+ inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
+
+ // TODO(hamaji): Do nothing, implement correctly.
+ inline void AssertHeld() {}
+
+ private:
+ MutexType mutex_;
+ // We want to make sure that the compiler sets is_safe_ to true only
+ // when we tell it to, and never makes assumptions is_safe_ is
+ // always true. volatile is the most reliable way to do that.
+ volatile bool is_safe_;
+
+ inline void SetIsSafe() { is_safe_ = true; }
+
+ // Catch the error of writing Mutex when intending MutexLock.
+ Mutex(Mutex* /*ignored*/) {}
+ // Disallow "evil" constructors
+ Mutex(const Mutex&);
+ void operator=(const Mutex&);
+};
+
+// Now the implementation of Mutex for various systems
+#if defined(CERES_NO_THREADS)
+
+// When we don't have threads, we can be either reading or writing,
+// but not both. We can have lots of readers at once (in no-threads
+// mode, that's most likely to happen in recursive function calls),
+// but only one writer. We represent this by having mutex_ be -1 when
+// writing and a number > 0 when reading (and 0 when no lock is held).
+//
+// In debug mode, we assert these invariants, while in non-debug mode
+// we do nothing, for efficiency. That's why everything is in an
+// assert.
+
+Mutex::Mutex() : mutex_(0) { }
+Mutex::~Mutex() { assert(mutex_ == 0); }
+void Mutex::Lock() { assert(--mutex_ == -1); }
+void Mutex::Unlock() { assert(mutex_++ == -1); }
+#ifdef CERES_GMUTEX_TRYLOCK
+bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
+#endif
+void Mutex::ReaderLock() { assert(++mutex_ > 0); }
+void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
+
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+
+Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
+Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
+void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
+void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ TryEnterCriticalSection(&mutex_) != 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+void Mutex::ReaderUnlock() { Unlock(); }
+
+#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
+
+#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_rwlock_destroy); }
+void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_rwlock_wrlock); }
+void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); }
+#ifdef CERES_GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_rwlock_trywrlock(&mutex_) == 0 :
+ true; }
+#endif
+void Mutex::ReaderLock() { CERES_SAFE_PTHREAD(pthread_rwlock_rdlock); }
+void Mutex::ReaderUnlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); }
+#undef CERES_SAFE_PTHREAD
+
+#elif defined(CERES_HAVE_PTHREAD)
+
+#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_mutex_destroy); }
+void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_mutex_lock); }
+void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_mutex_unlock); }
+#ifdef CERES_GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_mutex_trylock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); }
+void Mutex::ReaderUnlock() { Unlock(); }
+#undef CERES_SAFE_PTHREAD
+
+#endif
+
+// --------------------------------------------------------------------------
+// Some helper classes
+
+// Note: The weird "Ceres" prefix for the class is a workaround for having two
+// similar mutex.h files included in the same translation unit. This is a
+// problem because macros do not respect C++ namespaces, and as a result, this
+// does not work well (e.g. inside Chrome). The offending macros are
+// "MutexLock(x) COMPILE_ASSERT(false)". To work around this, "Ceres" is
+// prefixed to the class names; this permits defining the classes.
+
+// CeresMutexLock(mu) acquires mu when constructed and releases it
+// when destroyed.
+class CeresMutexLock {
+ public:
+ explicit CeresMutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
+ ~CeresMutexLock() { mu_->Unlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ CeresMutexLock(const CeresMutexLock&);
+ void operator=(const CeresMutexLock&);
+};
+
+// CeresReaderMutexLock and CeresWriterMutexLock do the same, for rwlocks
+class CeresReaderMutexLock {
+ public:
+ explicit CeresReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
+ ~CeresReaderMutexLock() { mu_->ReaderUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ CeresReaderMutexLock(const CeresReaderMutexLock&);
+ void operator=(const CeresReaderMutexLock&);
+};
+
+class CeresWriterMutexLock {
+ public:
+ explicit CeresWriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
+ ~CeresWriterMutexLock() { mu_->WriterUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ CeresWriterMutexLock(const CeresWriterMutexLock&);
+ void operator=(const CeresWriterMutexLock&);
+};
+
+// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
+#define CeresMutexLock(x) \
+ COMPILE_ASSERT(0, ceres_mutex_lock_decl_missing_var_name)
+#define CeresReaderMutexLock(x) \
+ COMPILE_ASSERT(0, ceres_rmutex_lock_decl_missing_var_name)
+#define CeresWriterMutexLock(x) \
+ COMPILE_ASSERT(0, ceres_wmutex_lock_decl_missing_var_name)
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_MUTEX_H_
diff --git a/extern/ceres/internal/ceres/normal_prior.cc b/extern/ceres/internal/ceres/normal_prior.cc
new file mode 100644
index 00000000000..b3666cd702f
--- /dev/null
+++ b/extern/ceres/internal/ceres/normal_prior.cc
@@ -0,0 +1,66 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/normal_prior.h"
+
+#include <cstddef>
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+NormalPrior::NormalPrior(const Matrix& A, const Vector& b)
+ : A_(A), b_(b) {
+ CHECK_GT(b_.rows(), 0);
+ CHECK_GT(A_.rows(), 0);
+ CHECK_EQ(b_.rows(), A.cols());
+ set_num_residuals(A_.rows());
+ mutable_parameter_block_sizes()->push_back(b_.rows());
+}
+
+bool NormalPrior::Evaluate(double const* const* parameters,
+ double* residuals,
+ double** jacobians) const {
+ ConstVectorRef p(parameters[0], parameter_block_sizes()[0]);
+ VectorRef r(residuals, num_residuals());
+ // The following line should read
+ // r = A_ * (p - b_);
+ // The extra eval is to get around a bug in the eigen library.
+ r = A_ * (p - b_).eval();
+ if ((jacobians != NULL) && (jacobians[0] != NULL)) {
+ MatrixRef(jacobians[0], num_residuals(), parameter_block_sizes()[0]) = A_;
+ }
+ return true;
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/parameter_block.h b/extern/ceres/internal/ceres/parameter_block.h
new file mode 100644
index 00000000000..cb7140d9582
--- /dev/null
+++ b/extern/ceres/internal/ceres/parameter_block.h
@@ -0,0 +1,398 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_PARAMETER_BLOCK_H_
+#define CERES_INTERNAL_PARAMETER_BLOCK_H_
+
+#include <algorithm>
+#include <cstdlib>
+#include <limits>
+#include <string>
+#include "ceres/array_utils.h"
+#include "ceres/collections_port.h"
+#include "ceres/integral_types.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/local_parameterization.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+class ProblemImpl;
+class ResidualBlock;
+
+// The parameter block encodes the location of the user's original value, and
+// also the "current state" of the parameter. The evaluator uses whatever is in
+// the current state of the parameter when evaluating. This is inlined since the
+// methods are performance sensitive.
+//
+// The class is not thread-safe, unless only const methods are called. The
+// parameter block may also hold a pointer to a local parameterization; the
+// parameter block does not take ownership of this pointer, so the user is
+// responsible for the proper disposal of the local parameterization.
+class ParameterBlock {
+ public:
+ // TODO(keir): Decide what data structure is best here. Should this be a set?
+ // Probably not, because sets are memory inefficient. However, if it's a
+ // vector, you can get into pathological linear performance when removing a
+ // residual block from a problem where all the residual blocks depend on one
+ // parameter; for example, shared focal length in a bundle adjustment
+ // problem. It might be worth making a custom structure that is just an array
+ // when it is small, but transitions to a hash set when it has more elements.
+ //
+ // For now, use a hash set.
+ typedef HashSet<ResidualBlock*> ResidualBlockSet;
+
+ // Create a parameter block with the user state, size, and index specified.
+ // The size is the size of the parameter block and the index is the position
+ // of the parameter block inside a Program (if any).
+ ParameterBlock(double* user_state, int size, int index) {
+ Init(user_state, size, index, NULL);
+ }
+
+ ParameterBlock(double* user_state,
+ int size,
+ int index,
+ LocalParameterization* local_parameterization) {
+ Init(user_state, size, index, local_parameterization);
+ }
+
+ // The size of the parameter block.
+ int Size() const { return size_; }
+
+ // Manipulate the parameter state.
+ bool SetState(const double* x) {
+ CHECK(x != NULL)
+ << "Tried to set the state of constant parameter "
+ << "with user location " << user_state_;
+ CHECK(!is_constant_)
+ << "Tried to set the state of constant parameter "
+ << "with user location " << user_state_;
+
+ state_ = x;
+ return UpdateLocalParameterizationJacobian();
+ }
+
+ // Copy the current parameter state out to x. This is "GetState()" rather than
+ // simply "state()" since it is actively copying the data into the passed
+ // pointer.
+ void GetState(double *x) const {
+ if (x != state_) {
+ memcpy(x, state_, sizeof(*state_) * size_);
+ }
+ }
+
+ // Direct pointers to the current state.
+ const double* state() const { return state_; }
+ const double* user_state() const { return user_state_; }
+ double* mutable_user_state() { return user_state_; }
+ LocalParameterization* local_parameterization() const {
+ return local_parameterization_;
+ }
+ LocalParameterization* mutable_local_parameterization() {
+ return local_parameterization_;
+ }
+
+ // Set this parameter block to vary or not.
+ void SetConstant() { is_constant_ = true; }
+ void SetVarying() { is_constant_ = false; }
+ bool IsConstant() const { return is_constant_; }
+
+ // This parameter block's index in an array.
+ int index() const { return index_; }
+ void set_index(int index) { index_ = index; }
+
+ // This parameter offset inside a larger state vector.
+ int state_offset() const { return state_offset_; }
+ void set_state_offset(int state_offset) { state_offset_ = state_offset; }
+
+ // This parameter offset inside a larger delta vector.
+ int delta_offset() const { return delta_offset_; }
+ void set_delta_offset(int delta_offset) { delta_offset_ = delta_offset; }
+
+ // Methods relating to the parameter block's parameterization.
+
+ // The local to global jacobian. Returns NULL if there is no local
+ // parameterization for this parameter block. The returned matrix is row-major
+ // and has Size() rows and LocalSize() columns.
+ const double* LocalParameterizationJacobian() const {
+ return local_parameterization_jacobian_.get();
+ }
+
+ int LocalSize() const {
+ return (local_parameterization_ == NULL)
+ ? size_
+ : local_parameterization_->LocalSize();
+ }
+
+ // Set the parameterization. The parameterization can be set exactly once;
+ // multiple calls to set the parameterization to different values will crash.
+ // It is an error to pass NULL for the parameterization. The parameter block
+ // does not take ownership of the parameterization.
+ void SetParameterization(LocalParameterization* new_parameterization) {
+ CHECK(new_parameterization != NULL) << "NULL parameterization invalid.";
+ CHECK(new_parameterization->GlobalSize() == size_)
+ << "Invalid parameterization for parameter block. The parameter block "
+ << "has size " << size_ << " while the parameterization has a global "
+ << "size of " << new_parameterization->GlobalSize() << ". Did you "
+ << "accidentally use the wrong parameter block or parameterization?";
+ if (new_parameterization != local_parameterization_) {
+ CHECK(local_parameterization_ == NULL)
+ << "Can't re-set the local parameterization; it leads to "
+ << "ambiguous ownership.";
+ local_parameterization_ = new_parameterization;
+ local_parameterization_jacobian_.reset(
+ new double[local_parameterization_->GlobalSize() *
+ local_parameterization_->LocalSize()]);
+ CHECK(UpdateLocalParameterizationJacobian())
+ << "Local parameterization Jacobian computation failed for x: "
+ << ConstVectorRef(state_, Size()).transpose();
+ } else {
+ // Ignore the case that the parameterizations match.
+ }
+ }
+
+ void SetUpperBound(int index, double upper_bound) {
+ CHECK_LT(index, size_);
+
+ if (upper_bounds_.get() == NULL) {
+ upper_bounds_.reset(new double[size_]);
+ std::fill(upper_bounds_.get(),
+ upper_bounds_.get() + size_,
+ std::numeric_limits<double>::max());
+ }
+
+ upper_bounds_[index] = upper_bound;
+ }
+
+ void SetLowerBound(int index, double lower_bound) {
+ CHECK_LT(index, size_);
+
+ if (lower_bounds_.get() == NULL) {
+ lower_bounds_.reset(new double[size_]);
+ std::fill(lower_bounds_.get(),
+ lower_bounds_.get() + size_,
+ -std::numeric_limits<double>::max());
+ }
+
+ lower_bounds_[index] = lower_bound;
+ }
+
+ // Generalization of the addition operation. This is the same as
+ // LocalParameterization::Plus() followed by projection onto the
+ // hyper cube implied by the bounds constraints.
+ bool Plus(const double *x, const double* delta, double* x_plus_delta) {
+ if (local_parameterization_ != NULL) {
+ if (!local_parameterization_->Plus(x, delta, x_plus_delta)) {
+ return false;
+ }
+ } else {
+ VectorRef(x_plus_delta, size_) = ConstVectorRef(x, size_) +
+ ConstVectorRef(delta, size_);
+ }
+
+ // Project onto the box constraints.
+ if (lower_bounds_.get() != NULL) {
+ for (int i = 0; i < size_; ++i) {
+ x_plus_delta[i] = std::max(x_plus_delta[i], lower_bounds_[i]);
+ }
+ }
+
+ if (upper_bounds_.get() != NULL) {
+ for (int i = 0; i < size_; ++i) {
+ x_plus_delta[i] = std::min(x_plus_delta[i], upper_bounds_[i]);
+ }
+ }
+
+ return true;
+ }
+
+ std::string ToString() const {
+ return StringPrintf("{ this=%p, user_state=%p, state=%p, size=%d, "
+ "constant=%d, index=%d, state_offset=%d, "
+ "delta_offset=%d }",
+ this,
+ user_state_,
+ state_,
+ size_,
+ is_constant_,
+ index_,
+ state_offset_,
+ delta_offset_);
+ }
+
+ void EnableResidualBlockDependencies() {
+ CHECK(residual_blocks_.get() == NULL)
+ << "Ceres bug: There is already a residual block collection "
+ << "for parameter block: " << ToString();
+ residual_blocks_.reset(new ResidualBlockSet);
+ }
+
+ void AddResidualBlock(ResidualBlock* residual_block) {
+ CHECK(residual_blocks_.get() != NULL)
+ << "Ceres bug: The residual block collection is null for parameter "
+ << "block: " << ToString();
+ residual_blocks_->insert(residual_block);
+ }
+
+ void RemoveResidualBlock(ResidualBlock* residual_block) {
+ CHECK(residual_blocks_.get() != NULL)
+ << "Ceres bug: The residual block collection is null for parameter "
+ << "block: " << ToString();
+ CHECK(residual_blocks_->find(residual_block) != residual_blocks_->end())
+ << "Ceres bug: Missing residual for parameter block: " << ToString();
+ residual_blocks_->erase(residual_block);
+ }
+
+ // This is only intended for iterating; perhaps this should only expose
+ // .begin() and .end().
+ ResidualBlockSet* mutable_residual_blocks() {
+ return residual_blocks_.get();
+ }
+
+ double LowerBoundForParameter(int index) const {
+ if (lower_bounds_.get() == NULL) {
+ return -std::numeric_limits<double>::max();
+ } else {
+ return lower_bounds_[index];
+ }
+ }
+
+ double UpperBoundForParameter(int index) const {
+ if (upper_bounds_.get() == NULL) {
+ return std::numeric_limits<double>::max();
+ } else {
+ return upper_bounds_[index];
+ }
+ }
+
+ private:
+ void Init(double* user_state,
+ int size,
+ int index,
+ LocalParameterization* local_parameterization) {
+ user_state_ = user_state;
+ size_ = size;
+ index_ = index;
+ is_constant_ = false;
+ state_ = user_state_;
+
+ local_parameterization_ = NULL;
+ if (local_parameterization != NULL) {
+ SetParameterization(local_parameterization);
+ }
+
+ state_offset_ = -1;
+ delta_offset_ = -1;
+ }
+
+ bool UpdateLocalParameterizationJacobian() {
+ if (local_parameterization_ == NULL) {
+ return true;
+ }
+
+ // Update the local to global Jacobian. In some cases this is
+ // wasted effort; if this is a bottleneck, we will find a solution
+ // at that time.
+
+ const int jacobian_size = Size() * LocalSize();
+ InvalidateArray(jacobian_size,
+ local_parameterization_jacobian_.get());
+ if (!local_parameterization_->ComputeJacobian(
+ state_,
+ local_parameterization_jacobian_.get())) {
+ LOG(WARNING) << "Local parameterization Jacobian computation failed"
+ "for x: " << ConstVectorRef(state_, Size()).transpose();
+ return false;
+ }
+
+ if (!IsArrayValid(jacobian_size, local_parameterization_jacobian_.get())) {
+ LOG(WARNING) << "Local parameterization Jacobian computation returned"
+ << "an invalid matrix for x: "
+ << ConstVectorRef(state_, Size()).transpose()
+ << "\n Jacobian matrix : "
+ << ConstMatrixRef(local_parameterization_jacobian_.get(),
+ Size(),
+ LocalSize());
+ return false;
+ }
+ return true;
+ }
+
+ double* user_state_;
+ int size_;
+ bool is_constant_;
+ LocalParameterization* local_parameterization_;
+
+ // The "state" of the parameter. These fields are only needed while the
+ // solver is running. While at first glance using mutable is a bad idea, this
+ // ends up simplifying the internals of Ceres enough to justify the potential
+ // pitfalls of using "mutable."
+ mutable const double* state_;
+ mutable scoped_array<double> local_parameterization_jacobian_;
+
+ // The index of the parameter. This is used by various other parts of Ceres to
+ // permit switching from a ParameterBlock* to an index in another array.
+ int32 index_;
+
+ // The offset of this parameter block inside a larger state vector.
+ int32 state_offset_;
+
+ // The offset of this parameter block inside a larger delta vector.
+ int32 delta_offset_;
+
+ // If non-null, contains the residual blocks this parameter block is in.
+ scoped_ptr<ResidualBlockSet> residual_blocks_;
+
+ // Upper and lower bounds for the parameter block. SetUpperBound
+ // and SetLowerBound lazily initialize the upper_bounds_ and
+ // lower_bounds_ arrays. If they are never called, then memory for
+ // these arrays is never allocated. Thus for problems where there
+ // are no bounds, or only one sided bounds we do not pay the cost of
+ // allocating memory for the inactive bounds constraints.
+ //
+ // Upon initialization these arrays are initialized to
+ // std::numeric_limits<double>::max() and
+ // -std::numeric_limits<double>::max() respectively which correspond
+ // to the parameter block being unconstrained.
+ scoped_array<double> upper_bounds_;
+ scoped_array<double> lower_bounds_;
+
+ // Necessary so ProblemImpl can clean up the parameterizations.
+ friend class ProblemImpl;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PARAMETER_BLOCK_H_
diff --git a/extern/ceres/internal/ceres/parameter_block_ordering.cc b/extern/ceres/internal/ceres/parameter_block_ordering.cc
new file mode 100644
index 00000000000..efba339977c
--- /dev/null
+++ b/extern/ceres/internal/ceres/parameter_block_ordering.cc
@@ -0,0 +1,173 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/parameter_block_ordering.h"
+
+#include "ceres/graph.h"
+#include "ceres/graph_algorithms.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/map_util.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::map;
+using std::set;
+using std::vector;
+
+int ComputeStableSchurOrdering(const Program& program,
+ vector<ParameterBlock*>* ordering) {
+ CHECK_NOTNULL(ordering)->clear();
+ EventLogger event_logger("ComputeStableSchurOrdering");
+ scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+ event_logger.AddEvent("CreateHessianGraph");
+
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+ const HashSet<ParameterBlock*>& vertices = graph->vertices();
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ if (vertices.count(parameter_blocks[i]) > 0) {
+ ordering->push_back(parameter_blocks[i]);
+ }
+ }
+ event_logger.AddEvent("Preordering");
+
+ int independent_set_size = StableIndependentSetOrdering(*graph, ordering);
+ event_logger.AddEvent("StableIndependentSet");
+
+ // Add the excluded blocks to back of the ordering vector.
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks[i];
+ if (parameter_block->IsConstant()) {
+ ordering->push_back(parameter_block);
+ }
+ }
+ event_logger.AddEvent("ConstantParameterBlocks");
+
+ return independent_set_size;
+}
+
+int ComputeSchurOrdering(const Program& program,
+ vector<ParameterBlock*>* ordering) {
+ CHECK_NOTNULL(ordering)->clear();
+
+ scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+ int independent_set_size = IndependentSetOrdering(*graph, ordering);
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+
+ // Add the excluded blocks to back of the ordering vector.
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks[i];
+ if (parameter_block->IsConstant()) {
+ ordering->push_back(parameter_block);
+ }
+ }
+
+ return independent_set_size;
+}
+
+void ComputeRecursiveIndependentSetOrdering(const Program& program,
+ ParameterBlockOrdering* ordering) {
+ CHECK_NOTNULL(ordering)->Clear();
+ const vector<ParameterBlock*> parameter_blocks = program.parameter_blocks();
+ scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
+
+ int num_covered = 0;
+ int round = 0;
+ while (num_covered < parameter_blocks.size()) {
+ vector<ParameterBlock*> independent_set_ordering;
+ const int independent_set_size =
+ IndependentSetOrdering(*graph, &independent_set_ordering);
+ for (int i = 0; i < independent_set_size; ++i) {
+ ParameterBlock* parameter_block = independent_set_ordering[i];
+ ordering->AddElementToGroup(parameter_block->mutable_user_state(), round);
+ graph->RemoveVertex(parameter_block);
+ }
+ num_covered += independent_set_size;
+ ++round;
+ }
+}
+
+Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
+ Graph<ParameterBlock*>* graph = CHECK_NOTNULL(new Graph<ParameterBlock*>);
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks[i];
+ if (!parameter_block->IsConstant()) {
+ graph->AddVertex(parameter_block);
+ }
+ }
+
+ const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ const ResidualBlock* residual_block = residual_blocks[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ ParameterBlock* const* parameter_blocks =
+ residual_block->parameter_blocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (parameter_blocks[j]->IsConstant()) {
+ continue;
+ }
+
+ for (int k = j + 1; k < num_parameter_blocks; ++k) {
+ if (parameter_blocks[k]->IsConstant()) {
+ continue;
+ }
+
+ graph->AddEdge(parameter_blocks[j], parameter_blocks[k]);
+ }
+ }
+ }
+
+ return graph;
+}
+
+void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
+ vector<int>* group_sizes) {
+ CHECK_NOTNULL(group_sizes)->clear();
+ if (ordering == NULL) {
+ return;
+ }
+
+ const map<int, set<double*> >& group_to_elements =
+ ordering->group_to_elements();
+ for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+ it != group_to_elements.end();
+ ++it) {
+ group_sizes->push_back(it->second.size());
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/parameter_block_ordering.h b/extern/ceres/internal/ceres/parameter_block_ordering.h
new file mode 100644
index 00000000000..f996929f6b3
--- /dev/null
+++ b/extern/ceres/internal/ceres/parameter_block_ordering.h
@@ -0,0 +1,89 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
+#define CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
+
+#include <vector>
+#include "ceres/ordered_groups.h"
+#include "ceres/graph.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+class ParameterBlock;
+
+// Uses an approximate independent set ordering to order the parameter
+// blocks of a problem so that it is suitable for use with Schur
+// complement based solvers. The output variable ordering contains an
+// ordering of the parameter blocks and the return value is size of
+// the independent set or the number of e_blocks (see
+// schur_complement_solver.h for an explanation). Constant parameters
+// are added to the end.
+//
+// The ordering vector has the structure
+//
+// ordering = [independent set,
+// complement of the independent set,
+// fixed blocks]
+int ComputeSchurOrdering(const Program& program,
+ std::vector<ParameterBlock* >* ordering);
+
+// Same as above, except that ties while computing the independent set
+// ordering are resolved in favour of the order in which the parameter
+// blocks occur in the program.
+int ComputeStableSchurOrdering(const Program& program,
+ std::vector<ParameterBlock* >* ordering);
+
+// Use an approximate independent set ordering to decompose the
+// parameter blocks of a problem in a sequence of independent
+// sets. The ordering covers all the non-constant parameter blocks in
+// the program.
+void ComputeRecursiveIndependentSetOrdering(const Program& program,
+ ParameterBlockOrdering* ordering);
+
+// Builds a graph on the parameter blocks of a Problem, whose
+// structure reflects the sparsity structure of the Hessian. Each
+// vertex corresponds to a parameter block in the Problem except for
+// parameter blocks that are marked constant. An edge connects two
+// parameter blocks, if they co-occur in a residual block.
+Graph<ParameterBlock*>* CreateHessianGraph(const Program& program);
+
+// Iterate over each of the groups in order of their priority and fill
+// summary with their sizes.
+void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
+ std::vector<int>* group_sizes);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
diff --git a/extern/ceres/internal/ceres/partitioned_matrix_view.cc b/extern/ceres/internal/ceres/partitioned_matrix_view.cc
new file mode 100644
index 00000000000..8054964e039
--- /dev/null
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view.cc
@@ -0,0 +1,185 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of PartitionedMatrixView.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_partitioned_matrix_view_specializations.py.
+// Editing it manually is not recommended.
+
+#include "ceres/linear_solver.h"
+#include "ceres/partitioned_matrix_view.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+PartitionedMatrixViewBase*
+PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
+ const BlockSparseMatrix& matrix) {
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 2)) {
+ return new PartitionedMatrixView<2, 2, 2>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<2, 2, 3>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<2, 2, 4>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new PartitionedMatrixView<2, 2, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<2, 3, 3>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<2, 3, 4>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 6)) {
+ return new PartitionedMatrixView<2, 3, 6>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 9)) {
+ return new PartitionedMatrixView<2, 3, 9>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new PartitionedMatrixView<2, 3, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<2, 4, 3>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<2, 4, 4>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 8)) {
+ return new PartitionedMatrixView<2, 4, 8>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 9)) {
+ return new PartitionedMatrixView<2, 4, 9>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new PartitionedMatrixView<2, 4, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == Eigen::Dynamic) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 2)) {
+ return new PartitionedMatrixView<4, 4, 2>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new PartitionedMatrixView<4, 4, 3>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new PartitionedMatrixView<4, 4, 4>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new PartitionedMatrixView<4, 4, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+ }
+ if ((options.row_block_size == Eigen::Dynamic) &&
+ (options.e_block_size == Eigen::Dynamic) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+ }
+
+#endif
+ VLOG(1) << "Template specializations not found for <"
+ << options.row_block_size << ","
+ << options.e_block_size << ","
+ << options.f_block_size << ">";
+ return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
+ matrix, options.elimination_groups[0]);
+};
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/partitioned_matrix_view.h b/extern/ceres/internal/ceres/partitioned_matrix_view.h
new file mode 100644
index 00000000000..6e75060a47e
--- /dev/null
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view.h
@@ -0,0 +1,152 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// For generalized bi-partite Jacobian matrices that arise in
+// Structure from Motion related problems, it is sometimes useful to
+// have access to the two parts of the matrix as linear operators
+// themselves. This class provides that functionality.
+
+#ifndef CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
+#define CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+#include "ceres/small_blas.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Given generalized bi-partite matrix A = [E F], with the same block
+// structure as required by the Schur complement based solver, found
+// in explicit_schur_complement_solver.h, provide access to the
+// matrices E and F and their outer products E'E and F'F with
+// themselves.
+//
+// Lack of BlockStructure object will result in a crash and if the
+// block structure of the matrix does not satisfy the requirements of
+// the Schur complement solver it will result in unpredictable and
+// wrong output.
+class PartitionedMatrixViewBase {
+ public:
+ virtual ~PartitionedMatrixViewBase() {}
+
+ // y += E'x
+ virtual void LeftMultiplyE(const double* x, double* y) const = 0;
+
+ // y += F'x
+ virtual void LeftMultiplyF(const double* x, double* y) const = 0;
+
+ // y += Ex
+ virtual void RightMultiplyE(const double* x, double* y) const = 0;
+
+ // y += Fx
+ virtual void RightMultiplyF(const double* x, double* y) const = 0;
+
+ // Create and return the block diagonal of the matrix E'E.
+ virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const = 0;
+
+ // Create and return the block diagonal of the matrix F'F. Caller
+ // owns the result.
+ virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const = 0;
+
+ // Compute the block diagonal of the matrix E'E and store it in
+ // block_diagonal. The matrix block_diagonal is expected to have a
+ // BlockStructure (preferably created using
+ // CreateBlockDiagonalMatrixEtE) which is has the same structure as
+ // the block diagonal of E'E.
+ virtual void UpdateBlockDiagonalEtE(
+ BlockSparseMatrix* block_diagonal) const = 0;
+
+ // Compute the block diagonal of the matrix F'F and store it in
+ // block_diagonal. The matrix block_diagonal is expected to have a
+ // BlockStructure (preferably created using
+ // CreateBlockDiagonalMatrixFtF) which is has the same structure as
+ // the block diagonal of F'F.
+ virtual void UpdateBlockDiagonalFtF(
+ BlockSparseMatrix* block_diagonal) const = 0;
+
+ virtual int num_col_blocks_e() const = 0;
+ virtual int num_col_blocks_f() const = 0;
+ virtual int num_cols_e() const = 0;
+ virtual int num_cols_f() const = 0;
+ virtual int num_rows() const = 0;
+ virtual int num_cols() const = 0;
+
+ static PartitionedMatrixViewBase* Create(const LinearSolver::Options& options,
+ const BlockSparseMatrix& matrix);
+};
+
+template <int kRowBlockSize = Eigen::Dynamic,
+ int kEBlockSize = Eigen::Dynamic,
+ int kFBlockSize = Eigen::Dynamic >
+class PartitionedMatrixView : public PartitionedMatrixViewBase {
+ public:
+ // matrix = [E F], where the matrix E contains the first
+ // num_col_blocks_a column blocks.
+ PartitionedMatrixView(const BlockSparseMatrix& matrix, int num_col_blocks_e);
+
+ virtual ~PartitionedMatrixView();
+ virtual void LeftMultiplyE(const double* x, double* y) const;
+ virtual void LeftMultiplyF(const double* x, double* y) const;
+ virtual void RightMultiplyE(const double* x, double* y) const;
+ virtual void RightMultiplyF(const double* x, double* y) const;
+ virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const;
+ virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const;
+ virtual void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const;
+ virtual void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const;
+ virtual int num_col_blocks_e() const { return num_col_blocks_e_; }
+ virtual int num_col_blocks_f() const { return num_col_blocks_f_; }
+ virtual int num_cols_e() const { return num_cols_e_; }
+ virtual int num_cols_f() const { return num_cols_f_; }
+ virtual int num_rows() const { return matrix_.num_rows(); }
+ virtual int num_cols() const { return matrix_.num_cols(); }
+
+ private:
+ BlockSparseMatrix* CreateBlockDiagonalMatrixLayout(int start_col_block,
+ int end_col_block) const;
+
+ const BlockSparseMatrix& matrix_;
+ int num_row_blocks_e_;
+ int num_col_blocks_e_;
+ int num_col_blocks_f_;
+ int num_cols_e_;
+ int num_cols_f_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
diff --git a/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h b/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h
new file mode 100644
index 00000000000..86fb278fa27
--- /dev/null
+++ b/extern/ceres/internal/ceres/partitioned_matrix_view_impl.h
@@ -0,0 +1,380 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/partitioned_matrix_view.h"
+
+#include <algorithm>
+#include <cstring>
+#include <vector>
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/small_blas.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+PartitionedMatrixView(
+ const BlockSparseMatrix& matrix,
+ int num_col_blocks_e)
+ : matrix_(matrix),
+ num_col_blocks_e_(num_col_blocks_e) {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+ CHECK_NOTNULL(bs);
+
+ num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
+
+ // Compute the number of row blocks in E. The number of row blocks
+ // in E maybe less than the number of row blocks in the input matrix
+ // as some of the row blocks at the bottom may not have any
+ // e_blocks. For a definition of what an e_block is, please see
+ // explicit_schur_complement_solver.h
+ num_row_blocks_e_ = 0;
+ for (int r = 0; r < bs->rows.size(); ++r) {
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ if (cells[0].block_id < num_col_blocks_e_) {
+ ++num_row_blocks_e_;
+ }
+ }
+
+ // Compute the number of columns in E and F.
+ num_cols_e_ = 0;
+ num_cols_f_ = 0;
+
+ for (int c = 0; c < bs->cols.size(); ++c) {
+ const Block& block = bs->cols[c];
+ if (c < num_col_blocks_e_) {
+ num_cols_e_ += block.size;
+ } else {
+ num_cols_f_ += block.size;
+ }
+ }
+
+ CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+~PartitionedMatrixView() {
+}
+
+// The next four methods don't seem to be particularly cache
+// friendly. This is an artifact of how the BlockStructure of the
+// input matrix is constructed. These methods will benefit from
+// multithreading as well as improved data layout.
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+RightMultiplyE(const double* x, double* y) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+ // Iterate over the first num_row_blocks_e_ row blocks, and multiply
+ // by the first cell in each row block.
+ const double* values = matrix_.values();
+ for (int r = 0; r < num_row_blocks_e_; ++r) {
+ const Cell& cell = bs->rows[r].cells[0];
+ const int row_block_pos = bs->rows[r].block.position;
+ const int row_block_size = bs->rows[r].block.size;
+ const int col_block_id = cell.block_id;
+ const int col_block_pos = bs->cols[col_block_id].position;
+ const int col_block_size = bs->cols[col_block_id].size;
+ MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+ values + cell.position, row_block_size, col_block_size,
+ x + col_block_pos,
+ y + row_block_pos);
+ }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+RightMultiplyF(const double* x, double* y) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+ // Iterate over row blocks, and if the row block is in E, then
+ // multiply by all the cells except the first one which is of type
+ // E. If the row block is not in E (i.e its in the bottom
+ // num_row_blocks - num_row_blocks_e row blocks), then all the cells
+ // are of type F and multiply by them all.
+ const double* values = matrix_.values();
+ for (int r = 0; r < num_row_blocks_e_; ++r) {
+ const int row_block_pos = bs->rows[r].block.position;
+ const int row_block_size = bs->rows[r].block.size;
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ for (int c = 1; c < cells.size(); ++c) {
+ const int col_block_id = cells[c].block_id;
+ const int col_block_pos = bs->cols[col_block_id].position;
+ const int col_block_size = bs->cols[col_block_id].size;
+ MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+ values + cells[c].position, row_block_size, col_block_size,
+ x + col_block_pos - num_cols_e_,
+ y + row_block_pos);
+ }
+ }
+
+ for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
+ const int row_block_pos = bs->rows[r].block.position;
+ const int row_block_size = bs->rows[r].block.size;
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ for (int c = 0; c < cells.size(); ++c) {
+ const int col_block_id = cells[c].block_id;
+ const int col_block_pos = bs->cols[col_block_id].position;
+ const int col_block_size = bs->cols[col_block_id].size;
+ MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values + cells[c].position, row_block_size, col_block_size,
+ x + col_block_pos - num_cols_e_,
+ y + row_block_pos);
+ }
+ }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+LeftMultiplyE(const double* x, double* y) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+ // Iterate over the first num_row_blocks_e_ row blocks, and multiply
+ // by the first cell in each row block.
+ const double* values = matrix_.values();
+ for (int r = 0; r < num_row_blocks_e_; ++r) {
+ const Cell& cell = bs->rows[r].cells[0];
+ const int row_block_pos = bs->rows[r].block.position;
+ const int row_block_size = bs->rows[r].block.size;
+ const int col_block_id = cell.block_id;
+ const int col_block_pos = bs->cols[col_block_id].position;
+ const int col_block_size = bs->cols[col_block_id].size;
+ MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+ values + cell.position, row_block_size, col_block_size,
+ x + row_block_pos,
+ y + col_block_pos);
+ }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+LeftMultiplyF(const double* x, double* y) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+
+ // Iterate over row blocks, and if the row block is in E, then
+ // multiply by all the cells except the first one which is of type
+ // E. If the row block is not in E (i.e its in the bottom
+ // num_row_blocks - num_row_blocks_e row blocks), then all the cells
+ // are of type F and multiply by them all.
+ const double* values = matrix_.values();
+ for (int r = 0; r < num_row_blocks_e_; ++r) {
+ const int row_block_pos = bs->rows[r].block.position;
+ const int row_block_size = bs->rows[r].block.size;
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ for (int c = 1; c < cells.size(); ++c) {
+ const int col_block_id = cells[c].block_id;
+ const int col_block_pos = bs->cols[col_block_id].position;
+ const int col_block_size = bs->cols[col_block_id].size;
+ MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+ values + cells[c].position, row_block_size, col_block_size,
+ x + row_block_pos,
+ y + col_block_pos - num_cols_e_);
+ }
+ }
+
+ for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
+ const int row_block_pos = bs->rows[r].block.position;
+ const int row_block_size = bs->rows[r].block.size;
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ for (int c = 0; c < cells.size(); ++c) {
+ const int col_block_id = cells[c].block_id;
+ const int col_block_pos = bs->cols[col_block_id].position;
+ const int col_block_size = bs->cols[col_block_id].size;
+ MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values + cells[c].position, row_block_size, col_block_size,
+ x + row_block_pos,
+ y + col_block_pos - num_cols_e_);
+ }
+ }
+}
+
+// Given a range of columns blocks of a matrix m, compute the block
+// structure of the block diagonal of the matrix m(:,
+// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
+// and return a BlockSparseMatrix with the this block structure. The
+// caller owns the result.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+BlockSparseMatrix*
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+CreateBlockDiagonalMatrixLayout(int start_col_block, int end_col_block) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+ CompressedRowBlockStructure* block_diagonal_structure =
+ new CompressedRowBlockStructure;
+
+ int block_position = 0;
+ int diagonal_cell_position = 0;
+
+ // Iterate over the column blocks, creating a new diagonal block for
+ // each column block.
+ for (int c = start_col_block; c < end_col_block; ++c) {
+ const Block& block = bs->cols[c];
+ block_diagonal_structure->cols.push_back(Block());
+ Block& diagonal_block = block_diagonal_structure->cols.back();
+ diagonal_block.size = block.size;
+ diagonal_block.position = block_position;
+
+ block_diagonal_structure->rows.push_back(CompressedRow());
+ CompressedRow& row = block_diagonal_structure->rows.back();
+ row.block = diagonal_block;
+
+ row.cells.push_back(Cell());
+ Cell& cell = row.cells.back();
+ cell.block_id = c - start_col_block;
+ cell.position = diagonal_cell_position;
+
+ block_position += block.size;
+ diagonal_cell_position += block.size * block.size;
+ }
+
+ // Build a BlockSparseMatrix with the just computed block
+ // structure.
+ return new BlockSparseMatrix(block_diagonal_structure);
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+BlockSparseMatrix*
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+CreateBlockDiagonalEtE() const {
+ BlockSparseMatrix* block_diagonal =
+ CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
+ UpdateBlockDiagonalEtE(block_diagonal);
+ return block_diagonal;
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+BlockSparseMatrix*
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+CreateBlockDiagonalFtF() const {
+ BlockSparseMatrix* block_diagonal =
+ CreateBlockDiagonalMatrixLayout(
+ num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
+ UpdateBlockDiagonalFtF(block_diagonal);
+ return block_diagonal;
+}
+
+// Similar to the code in RightMultiplyE, except instead of the matrix
+// vector multiply its an outer product.
+//
+// block_diagonal = block_diagonal(E'E)
+//
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+UpdateBlockDiagonalEtE(
+ BlockSparseMatrix* block_diagonal) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+ const CompressedRowBlockStructure* block_diagonal_structure =
+ block_diagonal->block_structure();
+
+ block_diagonal->SetZero();
+ const double* values = matrix_.values();
+ for (int r = 0; r < num_row_blocks_e_ ; ++r) {
+ const Cell& cell = bs->rows[r].cells[0];
+ const int row_block_size = bs->rows[r].block.size;
+ const int block_id = cell.block_id;
+ const int col_block_size = bs->cols[block_id].size;
+ const int cell_position =
+ block_diagonal_structure->rows[block_id].cells[0].position;
+
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
+ values + cell.position, row_block_size, col_block_size,
+ values + cell.position, row_block_size, col_block_size,
+ block_diagonal->mutable_values() + cell_position,
+ 0, 0, col_block_size, col_block_size);
+ }
+}
+
+// Similar to the code in RightMultiplyF, except instead of the matrix
+// vector multiply its an outer product.
+//
+// block_diagonal = block_diagonal(F'F)
+//
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
+ const CompressedRowBlockStructure* bs = matrix_.block_structure();
+ const CompressedRowBlockStructure* block_diagonal_structure =
+ block_diagonal->block_structure();
+
+ block_diagonal->SetZero();
+ const double* values = matrix_.values();
+ for (int r = 0; r < num_row_blocks_e_; ++r) {
+ const int row_block_size = bs->rows[r].block.size;
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ for (int c = 1; c < cells.size(); ++c) {
+ const int col_block_id = cells[c].block_id;
+ const int col_block_size = bs->cols[col_block_id].size;
+ const int diagonal_block_id = col_block_id - num_col_blocks_e_;
+ const int cell_position =
+ block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
+
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
+ values + cells[c].position, row_block_size, col_block_size,
+ values + cells[c].position, row_block_size, col_block_size,
+ block_diagonal->mutable_values() + cell_position,
+ 0, 0, col_block_size, col_block_size);
+ }
+ }
+
+ for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
+ const int row_block_size = bs->rows[r].block.size;
+ const std::vector<Cell>& cells = bs->rows[r].cells;
+ for (int c = 0; c < cells.size(); ++c) {
+ const int col_block_id = cells[c].block_id;
+ const int col_block_size = bs->cols[col_block_id].size;
+ const int diagonal_block_id = col_block_id - num_col_blocks_e_;
+ const int cell_position =
+ block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
+
+ MatrixTransposeMatrixMultiply
+ <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values + cells[c].position, row_block_size, col_block_size,
+ values + cells[c].position, row_block_size, col_block_size,
+ block_diagonal->mutable_values() + cell_position,
+ 0, 0, col_block_size, col_block_size);
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/polynomial.cc b/extern/ceres/internal/ceres/polynomial.cc
new file mode 100644
index 00000000000..13bf8edeee6
--- /dev/null
+++ b/extern/ceres/internal/ceres/polynomial.cc
@@ -0,0 +1,398 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: moll.markus@arcor.de (Markus Moll)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/polynomial.h"
+
+#include <cmath>
+#include <cstddef>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/internal/port.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+using std::vector;
+
+namespace {
+
+// Balancing function as described by B. N. Parlett and C. Reinsch,
+// "Balancing a Matrix for Calculation of Eigenvalues and Eigenvectors".
+// In: Numerische Mathematik, Volume 13, Number 4 (1969), 293-304,
+// Springer Berlin / Heidelberg. DOI: 10.1007/BF02165404
+void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) {
+ CHECK_NOTNULL(companion_matrix_ptr);
+ Matrix& companion_matrix = *companion_matrix_ptr;
+ Matrix companion_matrix_offdiagonal = companion_matrix;
+ companion_matrix_offdiagonal.diagonal().setZero();
+
+ const int degree = companion_matrix.rows();
+
+ // gamma <= 1 controls how much a change in the scaling has to
+ // lower the 1-norm of the companion matrix to be accepted.
+ //
+ // gamma = 1 seems to lead to cycles (numerical issues?), so
+ // we set it slightly lower.
+ const double gamma = 0.9;
+
+ // Greedily scale row/column pairs until there is no change.
+ bool scaling_has_changed;
+ do {
+ scaling_has_changed = false;
+
+ for (int i = 0; i < degree; ++i) {
+ const double row_norm = companion_matrix_offdiagonal.row(i).lpNorm<1>();
+ const double col_norm = companion_matrix_offdiagonal.col(i).lpNorm<1>();
+
+ // Decompose row_norm/col_norm into mantissa * 2^exponent,
+ // where 0.5 <= mantissa < 1. Discard mantissa (return value
+ // of frexp), as only the exponent is needed.
+ int exponent = 0;
+ std::frexp(row_norm / col_norm, &exponent);
+ exponent /= 2;
+
+ if (exponent != 0) {
+ const double scaled_col_norm = std::ldexp(col_norm, exponent);
+ const double scaled_row_norm = std::ldexp(row_norm, -exponent);
+ if (scaled_col_norm + scaled_row_norm < gamma * (col_norm + row_norm)) {
+ // Accept the new scaling. (Multiplication by powers of 2 should not
+ // introduce rounding errors (ignoring non-normalized numbers and
+ // over- or underflow))
+ scaling_has_changed = true;
+ companion_matrix_offdiagonal.row(i) *= std::ldexp(1.0, -exponent);
+ companion_matrix_offdiagonal.col(i) *= std::ldexp(1.0, exponent);
+ }
+ }
+ }
+ } while (scaling_has_changed);
+
+ companion_matrix_offdiagonal.diagonal() = companion_matrix.diagonal();
+ companion_matrix = companion_matrix_offdiagonal;
+ VLOG(3) << "Balanced companion matrix is\n" << companion_matrix;
+}
+
+void BuildCompanionMatrix(const Vector& polynomial,
+ Matrix* companion_matrix_ptr) {
+ CHECK_NOTNULL(companion_matrix_ptr);
+ Matrix& companion_matrix = *companion_matrix_ptr;
+
+ const int degree = polynomial.size() - 1;
+
+ companion_matrix.resize(degree, degree);
+ companion_matrix.setZero();
+ companion_matrix.diagonal(-1).setOnes();
+ companion_matrix.col(degree - 1) = -polynomial.reverse().head(degree);
+}
+
+// Remove leading terms with zero coefficients.
+Vector RemoveLeadingZeros(const Vector& polynomial_in) {
+ int i = 0;
+ while (i < (polynomial_in.size() - 1) && polynomial_in(i) == 0.0) {
+ ++i;
+ }
+ return polynomial_in.tail(polynomial_in.size() - i);
+}
+
+void FindLinearPolynomialRoots(const Vector& polynomial,
+ Vector* real,
+ Vector* imaginary) {
+ CHECK_EQ(polynomial.size(), 2);
+ if (real != NULL) {
+ real->resize(1);
+ (*real)(0) = -polynomial(1) / polynomial(0);
+ }
+
+ if (imaginary != NULL) {
+ imaginary->setZero(1);
+ }
+}
+
+void FindQuadraticPolynomialRoots(const Vector& polynomial,
+ Vector* real,
+ Vector* imaginary) {
+ CHECK_EQ(polynomial.size(), 3);
+ const double a = polynomial(0);
+ const double b = polynomial(1);
+ const double c = polynomial(2);
+ const double D = b * b - 4 * a * c;
+ const double sqrt_D = sqrt(fabs(D));
+ if (real != NULL) {
+ real->setZero(2);
+ }
+ if (imaginary != NULL) {
+ imaginary->setZero(2);
+ }
+
+ // Real roots.
+ if (D >= 0) {
+ if (real != NULL) {
+ // Stable quadratic roots according to BKP Horn.
+ // http://people.csail.mit.edu/bkph/articles/Quadratics.pdf
+ if (b >= 0) {
+ (*real)(0) = (-b - sqrt_D) / (2.0 * a);
+ (*real)(1) = (2.0 * c) / (-b - sqrt_D);
+ } else {
+ (*real)(0) = (2.0 * c) / (-b + sqrt_D);
+ (*real)(1) = (-b + sqrt_D) / (2.0 * a);
+ }
+ }
+ return;
+ }
+
+ // Use the normal quadratic formula for the complex case.
+ if (real != NULL) {
+ (*real)(0) = -b / (2.0 * a);
+ (*real)(1) = -b / (2.0 * a);
+ }
+ if (imaginary != NULL) {
+ (*imaginary)(0) = sqrt_D / (2.0 * a);
+ (*imaginary)(1) = -sqrt_D / (2.0 * a);
+ }
+}
+} // namespace
+
+bool FindPolynomialRoots(const Vector& polynomial_in,
+ Vector* real,
+ Vector* imaginary) {
+ if (polynomial_in.size() == 0) {
+ LOG(ERROR) << "Invalid polynomial of size 0 passed to FindPolynomialRoots";
+ return false;
+ }
+
+ Vector polynomial = RemoveLeadingZeros(polynomial_in);
+ const int degree = polynomial.size() - 1;
+
+ VLOG(3) << "Input polynomial: " << polynomial_in.transpose();
+ if (polynomial.size() != polynomial_in.size()) {
+ VLOG(3) << "Trimmed polynomial: " << polynomial.transpose();
+ }
+
+ // Is the polynomial constant?
+ if (degree == 0) {
+ LOG(WARNING) << "Trying to extract roots from a constant "
+ << "polynomial in FindPolynomialRoots";
+ // We return true with no roots, not false, as if the polynomial is constant
+ // it is correct that there are no roots. It is not the case that they were
+ // there, but that we have failed to extract them.
+ return true;
+ }
+
+ // Linear
+ if (degree == 1) {
+ FindLinearPolynomialRoots(polynomial, real, imaginary);
+ return true;
+ }
+
+ // Quadratic
+ if (degree == 2) {
+ FindQuadraticPolynomialRoots(polynomial, real, imaginary);
+ return true;
+ }
+
+ // The degree is now known to be at least 3. For cubic or higher
+ // roots we use the method of companion matrices.
+
+ // Divide by leading term
+ const double leading_term = polynomial(0);
+ polynomial /= leading_term;
+
+ // Build and balance the companion matrix to the polynomial.
+ Matrix companion_matrix(degree, degree);
+ BuildCompanionMatrix(polynomial, &companion_matrix);
+ BalanceCompanionMatrix(&companion_matrix);
+
+ // Find its (complex) eigenvalues.
+ Eigen::EigenSolver<Matrix> solver(companion_matrix, false);
+ if (solver.info() != Eigen::Success) {
+ LOG(ERROR) << "Failed to extract eigenvalues from companion matrix.";
+ return false;
+ }
+
+ // Output roots
+ if (real != NULL) {
+ *real = solver.eigenvalues().real();
+ } else {
+ LOG(WARNING) << "NULL pointer passed as real argument to "
+ << "FindPolynomialRoots. Real parts of the roots will not "
+ << "be returned.";
+ }
+ if (imaginary != NULL) {
+ *imaginary = solver.eigenvalues().imag();
+ }
+ return true;
+}
+
+Vector DifferentiatePolynomial(const Vector& polynomial) {
+ const int degree = polynomial.rows() - 1;
+ CHECK_GE(degree, 0);
+
+ // Degree zero polynomials are constants, and their derivative does
+ // not result in a smaller degree polynomial, just a degree zero
+ // polynomial with value zero.
+ if (degree == 0) {
+ return Eigen::VectorXd::Zero(1);
+ }
+
+ Vector derivative(degree);
+ for (int i = 0; i < degree; ++i) {
+ derivative(i) = (degree - i) * polynomial(i);
+ }
+
+ return derivative;
+}
+
+void MinimizePolynomial(const Vector& polynomial,
+ const double x_min,
+ const double x_max,
+ double* optimal_x,
+ double* optimal_value) {
+ // Find the minimum of the polynomial at the two ends.
+ //
+ // We start by inspecting the middle of the interval. Technically
+ // this is not needed, but we do this to make this code as close to
+ // the minFunc package as possible.
+ *optimal_x = (x_min + x_max) / 2.0;
+ *optimal_value = EvaluatePolynomial(polynomial, *optimal_x);
+
+ const double x_min_value = EvaluatePolynomial(polynomial, x_min);
+ if (x_min_value < *optimal_value) {
+ *optimal_value = x_min_value;
+ *optimal_x = x_min;
+ }
+
+ const double x_max_value = EvaluatePolynomial(polynomial, x_max);
+ if (x_max_value < *optimal_value) {
+ *optimal_value = x_max_value;
+ *optimal_x = x_max;
+ }
+
+ // If the polynomial is linear or constant, we are done.
+ if (polynomial.rows() <= 2) {
+ return;
+ }
+
+ const Vector derivative = DifferentiatePolynomial(polynomial);
+ Vector roots_real;
+ if (!FindPolynomialRoots(derivative, &roots_real, NULL)) {
+ LOG(WARNING) << "Unable to find the critical points of "
+ << "the interpolating polynomial.";
+ return;
+ }
+
+ // This is a bit of an overkill, as some of the roots may actually
+ // have a complex part, but its simpler to just check these values.
+ for (int i = 0; i < roots_real.rows(); ++i) {
+ const double root = roots_real(i);
+ if ((root < x_min) || (root > x_max)) {
+ continue;
+ }
+
+ const double value = EvaluatePolynomial(polynomial, root);
+ if (value < *optimal_value) {
+ *optimal_value = value;
+ *optimal_x = root;
+ }
+ }
+}
+
+string FunctionSample::ToDebugString() const {
+ return StringPrintf("[x: %.8e, value: %.8e, gradient: %.8e, "
+ "value_is_valid: %d, gradient_is_valid: %d]",
+ x, value, gradient, value_is_valid, gradient_is_valid);
+}
+
+Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples) {
+ const int num_samples = samples.size();
+ int num_constraints = 0;
+ for (int i = 0; i < num_samples; ++i) {
+ if (samples[i].value_is_valid) {
+ ++num_constraints;
+ }
+ if (samples[i].gradient_is_valid) {
+ ++num_constraints;
+ }
+ }
+
+ const int degree = num_constraints - 1;
+
+ Matrix lhs = Matrix::Zero(num_constraints, num_constraints);
+ Vector rhs = Vector::Zero(num_constraints);
+
+ int row = 0;
+ for (int i = 0; i < num_samples; ++i) {
+ const FunctionSample& sample = samples[i];
+ if (sample.value_is_valid) {
+ for (int j = 0; j <= degree; ++j) {
+ lhs(row, j) = pow(sample.x, degree - j);
+ }
+ rhs(row) = sample.value;
+ ++row;
+ }
+
+ if (sample.gradient_is_valid) {
+ for (int j = 0; j < degree; ++j) {
+ lhs(row, j) = (degree - j) * pow(sample.x, degree - j - 1);
+ }
+ rhs(row) = sample.gradient;
+ ++row;
+ }
+ }
+
+ return lhs.fullPivLu().solve(rhs);
+}
+
+void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
+ double x_min,
+ double x_max,
+ double* optimal_x,
+ double* optimal_value) {
+ const Vector polynomial = FindInterpolatingPolynomial(samples);
+ MinimizePolynomial(polynomial, x_min, x_max, optimal_x, optimal_value);
+ for (int i = 0; i < samples.size(); ++i) {
+ const FunctionSample& sample = samples[i];
+ if ((sample.x < x_min) || (sample.x > x_max)) {
+ continue;
+ }
+
+ const double value = EvaluatePolynomial(polynomial, sample.x);
+ if (value < *optimal_value) {
+ *optimal_x = sample.x;
+ *optimal_value = value;
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/polynomial.h b/extern/ceres/internal/ceres/polynomial.h
new file mode 100644
index 00000000000..09a64c577f5
--- /dev/null
+++ b/extern/ceres/internal/ceres/polynomial.h
@@ -0,0 +1,136 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: moll.markus@arcor.de (Markus Moll)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+
+#include <string>
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+// All polynomials are assumed to be the form
+//
+// sum_{i=0}^N polynomial(i) x^{N-i}.
+//
+// and are given by a vector of coefficients of size N + 1.
+
+// Evaluate the polynomial at x using the Horner scheme.
+inline double EvaluatePolynomial(const Vector& polynomial, double x) {
+ double v = 0.0;
+ for (int i = 0; i < polynomial.size(); ++i) {
+ v = v * x + polynomial(i);
+ }
+ return v;
+}
+
+// Use the companion matrix eigenvalues to determine the roots of the
+// polynomial.
+//
+// This function returns true on success, false otherwise.
+// Failure indicates that the polynomial is invalid (of size 0) or
+// that the eigenvalues of the companion matrix could not be computed.
+// On failure, a more detailed message will be written to LOG(ERROR).
+// If real is not NULL, the real parts of the roots will be returned in it.
+// Likewise, if imaginary is not NULL, imaginary parts will be returned in it.
+bool FindPolynomialRoots(const Vector& polynomial,
+ Vector* real,
+ Vector* imaginary);
+
+// Return the derivative of the given polynomial. It is assumed that
+// the input polynomial is at least of degree zero.
+Vector DifferentiatePolynomial(const Vector& polynomial);
+
+// Find the minimum value of the polynomial in the interval [x_min,
+// x_max]. The minimum is obtained by computing all the roots of the
+// derivative of the input polynomial. All real roots within the
+// interval [x_min, x_max] are considered as well as the end points
+// x_min and x_max. Since polynomials are differentiable functions,
+// this ensures that the true minimum is found.
+void MinimizePolynomial(const Vector& polynomial,
+ double x_min,
+ double x_max,
+ double* optimal_x,
+ double* optimal_value);
+
+// Structure for storing sample values of a function.
+//
+// Clients can use this struct to communicate the value of the
+// function and or its gradient at a given point x.
+struct FunctionSample {
+ FunctionSample()
+ : x(0.0),
+ value(0.0),
+ value_is_valid(false),
+ gradient(0.0),
+ gradient_is_valid(false) {
+ }
+ std::string ToDebugString() const;
+
+ double x;
+ double value; // value = f(x)
+ bool value_is_valid;
+ double gradient; // gradient = f'(x)
+ bool gradient_is_valid;
+};
+
+// Given a set of function value and/or gradient samples, find a
+// polynomial whose value and gradients are exactly equal to the ones
+// in samples.
+//
+// Generally speaking,
+//
+// degree = # values + # gradients - 1
+//
+// Of course its possible to sample a polynomial any number of times,
+// in which case, generally speaking the spurious higher order
+// coefficients will be zero.
+Vector FindInterpolatingPolynomial(const std::vector<FunctionSample>& samples);
+
+// Interpolate the function described by samples with a polynomial,
+// and minimize it on the interval [x_min, x_max]. Depending on the
+// input samples, it is possible that the interpolation or the root
+// finding algorithms may fail due to numerical difficulties. But the
+// function is guaranteed to return its best guess of an answer, by
+// considering the samples and the end points as possible solutions.
+void MinimizeInterpolatingPolynomial(const std::vector<FunctionSample>& samples,
+ double x_min,
+ double x_max,
+ double* optimal_x,
+ double* optimal_value);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/preconditioner.cc b/extern/ceres/internal/ceres/preconditioner.cc
new file mode 100644
index 00000000000..82621dae50c
--- /dev/null
+++ b/extern/ceres/internal/ceres/preconditioner.cc
@@ -0,0 +1,73 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/preconditioner.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Preconditioner::~Preconditioner() {
+}
+
+PreconditionerType Preconditioner::PreconditionerForZeroEBlocks(
+ PreconditionerType preconditioner_type) {
+ if (preconditioner_type == SCHUR_JACOBI ||
+ preconditioner_type == CLUSTER_JACOBI ||
+ preconditioner_type == CLUSTER_TRIDIAGONAL) {
+ return JACOBI;
+ }
+ return preconditioner_type;
+}
+
+SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
+ const SparseMatrix* matrix)
+ : matrix_(CHECK_NOTNULL(matrix)) {
+}
+
+SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {
+}
+
+bool SparseMatrixPreconditionerWrapper::UpdateImpl(const SparseMatrix& A,
+ const double* D) {
+ return true;
+}
+
+void SparseMatrixPreconditionerWrapper::RightMultiply(const double* x,
+ double* y) const {
+ matrix_->RightMultiply(x, y);
+}
+
+int SparseMatrixPreconditionerWrapper::num_rows() const {
+ return matrix_->num_rows();
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/preconditioner.h b/extern/ceres/internal/ceres/preconditioner.h
new file mode 100644
index 00000000000..a248eae060d
--- /dev/null
+++ b/extern/ceres/internal/ceres/preconditioner.h
@@ -0,0 +1,177 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_PRECONDITIONER_H_
+#define CERES_INTERNAL_PRECONDITIONER_H_
+
+#include <vector>
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/linear_operator.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrix;
+class SparseMatrix;
+
+class Preconditioner : public LinearOperator {
+ public:
+ struct Options {
+ Options()
+ : type(JACOBI),
+ visibility_clustering_type(CANONICAL_VIEWS),
+ sparse_linear_algebra_library_type(SUITE_SPARSE),
+ num_threads(1),
+ row_block_size(Eigen::Dynamic),
+ e_block_size(Eigen::Dynamic),
+ f_block_size(Eigen::Dynamic) {
+ }
+
+ PreconditionerType type;
+ VisibilityClusteringType visibility_clustering_type;
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
+
+ // If possible, how many threads the preconditioner can use.
+ int num_threads;
+
+ // Hints about the order in which the parameter blocks should be
+ // eliminated by the linear solver.
+ //
+ // For example if elimination_groups is a vector of size k, then
+ // the linear solver is informed that it should eliminate the
+ // parameter blocks 0 ... elimination_groups[0] - 1 first, and
+ // then elimination_groups[0] ... elimination_groups[1] - 1 and so
+ // on. Within each elimination group, the linear solver is free to
+ // choose how the parameter blocks are ordered. Different linear
+ // solvers have differing requirements on elimination_groups.
+ //
+ // The most common use is for Schur type solvers, where there
+ // should be at least two elimination groups and the first
+ // elimination group must form an independent set in the normal
+ // equations. The first elimination group corresponds to the
+ // num_eliminate_blocks in the Schur type solvers.
+ std::vector<int> elimination_groups;
+
+ // If the block sizes in a BlockSparseMatrix are fixed, then in
+ // some cases the Schur complement based solvers can detect and
+ // specialize on them.
+ //
+ // It is expected that these parameters are set programmatically
+ // rather than manually.
+ //
+ // Please see schur_complement_solver.h and schur_eliminator.h for
+ // more details.
+ int row_block_size;
+ int e_block_size;
+ int f_block_size;
+ };
+
+ // If the optimization problem is such that there are no remaining
+ // e-blocks, ITERATIVE_SCHUR with a Schur type preconditioner cannot
+ // be used. This function returns JACOBI if a preconditioner for
+ // ITERATIVE_SCHUR is used. The input preconditioner_type is
+ // returned otherwise.
+ static PreconditionerType PreconditionerForZeroEBlocks(
+ PreconditionerType preconditioner_type);
+
+ virtual ~Preconditioner();
+
+ // Update the numerical value of the preconditioner for the linear
+ // system:
+ //
+ // | A | x = |b|
+ // |diag(D)| |0|
+ //
+ // for some vector b. It is important that the matrix A have the
+ // same block structure as the one used to construct this object.
+ //
+ // D can be NULL, in which case its interpreted as a diagonal matrix
+ // of size zero.
+ virtual bool Update(const LinearOperator& A, const double* D) = 0;
+
+ // LinearOperator interface. Since the operator is symmetric,
+ // LeftMultiply and num_cols are just calls to RightMultiply and
+ // num_rows respectively. Update() must be called before
+ // RightMultiply can be called.
+ virtual void RightMultiply(const double* x, double* y) const = 0;
+ virtual void LeftMultiply(const double* x, double* y) const {
+ return RightMultiply(x, y);
+ }
+
+ virtual int num_rows() const = 0;
+ virtual int num_cols() const {
+ return num_rows();
+ }
+};
+
+// This templated subclass of Preconditioner serves as a base class for
+// other preconditioners that depend on the particular matrix layout of
+// the underlying linear operator.
+template <typename MatrixType>
+class TypedPreconditioner : public Preconditioner {
+ public:
+ virtual ~TypedPreconditioner() {}
+ virtual bool Update(const LinearOperator& A, const double* D) {
+ return UpdateImpl(*down_cast<const MatrixType*>(&A), D);
+ }
+
+ private:
+ virtual bool UpdateImpl(const MatrixType& A, const double* D) = 0;
+};
+
+// Preconditioners that depend on acccess to the low level structure
+// of a SparseMatrix.
+typedef TypedPreconditioner<SparseMatrix> SparseMatrixPreconditioner; // NOLINT
+typedef TypedPreconditioner<BlockSparseMatrix> BlockSparseMatrixPreconditioner; // NOLINT
+typedef TypedPreconditioner<CompressedRowSparseMatrix> CompressedRowSparseMatrixPreconditioner; // NOLINT
+
+// Wrap a SparseMatrix object as a preconditioner.
+class SparseMatrixPreconditionerWrapper : public SparseMatrixPreconditioner {
+ public:
+ // Wrapper does NOT take ownership of the matrix pointer.
+ explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix);
+ virtual ~SparseMatrixPreconditionerWrapper();
+
+ // Preconditioner interface
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ private:
+ virtual bool UpdateImpl(const SparseMatrix& A, const double* D);
+ const SparseMatrix* matrix_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PRECONDITIONER_H_
diff --git a/extern/ceres/internal/ceres/preprocessor.cc b/extern/ceres/internal/ceres/preprocessor.cc
new file mode 100644
index 00000000000..4aba6a39ce8
--- /dev/null
+++ b/extern/ceres/internal/ceres/preprocessor.cc
@@ -0,0 +1,113 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/callbacks.h"
+#include "ceres/gradient_checking_cost_function.h"
+#include "ceres/line_search_preprocessor.h"
+#include "ceres/preprocessor.h"
+#include "ceres/problem_impl.h"
+#include "ceres/solver.h"
+#include "ceres/trust_region_preprocessor.h"
+
+namespace ceres {
+namespace internal {
+
+Preprocessor* Preprocessor::Create(MinimizerType minimizer_type) {
+ if (minimizer_type == TRUST_REGION) {
+ return new TrustRegionPreprocessor;
+ }
+
+ if (minimizer_type == LINE_SEARCH) {
+ return new LineSearchPreprocessor;
+ }
+
+ LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
+ return NULL;
+}
+
+Preprocessor::~Preprocessor() {
+}
+
+void ChangeNumThreadsIfNeeded(Solver::Options* options) {
+#ifndef CERES_USE_OPENMP
+ if (options->num_threads > 1) {
+ LOG(WARNING)
+ << "OpenMP support is not compiled into this binary; "
+ << "only options.num_threads = 1 is supported. Switching "
+ << "to single threaded mode.";
+ options->num_threads = 1;
+ }
+
+ // Only the Trust Region solver currently uses a linear solver.
+ if (options->minimizer_type == TRUST_REGION &&
+ options->num_linear_solver_threads > 1) {
+ LOG(WARNING)
+ << "OpenMP support is not compiled into this binary; "
+ << "only options.num_linear_solver_threads=1 is supported. Switching "
+ << "to single threaded mode.";
+ options->num_linear_solver_threads = 1;
+ }
+#endif // CERES_USE_OPENMP
+}
+
+void SetupCommonMinimizerOptions(PreprocessedProblem* pp) {
+ const Solver::Options& options = pp->options;
+ Program* program = pp->reduced_program.get();
+
+ // Assuming that the parameter blocks in the program have been
+ // reordered as needed, extract them into a contiguous vector.
+ pp->reduced_parameters.resize(program->NumParameters());
+ double* reduced_parameters = pp->reduced_parameters.data();
+ program->ParameterBlocksToStateVector(reduced_parameters);
+
+ Minimizer::Options& minimizer_options = pp->minimizer_options;
+ minimizer_options = Minimizer::Options(options);
+ minimizer_options.evaluator = pp->evaluator;
+
+ if (options.logging_type != SILENT) {
+ pp->logging_callback.reset(
+ new LoggingCallback(options.minimizer_type,
+ options.minimizer_progress_to_stdout));
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ pp->logging_callback.get());
+ }
+
+ if (options.update_state_every_iteration) {
+ pp->state_updating_callback.reset(
+ new StateUpdatingCallback(program, reduced_parameters));
+ // This must get pushed to the front of the callbacks so that it
+ // is run before any of the user callbacks.
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ pp->state_updating_callback.get());
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/preprocessor.h b/extern/ceres/internal/ceres/preprocessor.h
new file mode 100644
index 00000000000..ff53d6f0d3f
--- /dev/null
+++ b/extern/ceres/internal/ceres/preprocessor.h
@@ -0,0 +1,122 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_PREPROCESSOR_H_
+#define CERES_INTERNAL_PREPROCESSOR_H_
+
+#include <string>
+#include <vector>
+
+#include "ceres/coordinate_descent_minimizer.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/iteration_callback.h"
+#include "ceres/linear_solver.h"
+#include "ceres/minimizer.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/solver.h"
+
+namespace ceres {
+namespace internal {
+
+struct PreprocessedProblem;
+
+// Given a Problem object and a Solver::Options object indicating the
+// configuration of the solver, the job of the Preprocessor is to
+// analyze the Problem and perform the setup needed to solve it using
+// the desired Minimization algorithm. The setup involves removing
+// redundancies in the input problem (inactive parameter and residual
+// blocks), finding fill reducing orderings as needed, configuring and
+// creating various objects needed by the Minimizer to solve the
+// problem such as an evaluator, a linear solver etc.
+//
+// Each Minimizer (LineSearchMinimizer and TrustRegionMinimizer) comes
+// with a corresponding Preprocessor (LineSearchPreprocessor and
+// TrustRegionPreprocessor) that knows about its needs and performs
+// the preprocessing needed.
+//
+// The output of the Preprocessor is stored in a PreprocessedProblem
+// object.
+class Preprocessor {
+ public:
+ // Factory.
+ static Preprocessor* Create(MinimizerType minimizer_type);
+ virtual ~Preprocessor();
+ virtual bool Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* pp) = 0;
+};
+
+// A PreprocessedProblem is the result of running the Preprocessor on
+// a Problem and Solver::Options object.
+struct PreprocessedProblem {
+ PreprocessedProblem()
+ : fixed_cost(0.0) {
+ }
+
+ std::string error;
+ Solver::Options options;
+ LinearSolver::Options linear_solver_options;
+ Evaluator::Options evaluator_options;
+ Minimizer::Options minimizer_options;
+
+ ProblemImpl* problem;
+ scoped_ptr<ProblemImpl> gradient_checking_problem;
+ scoped_ptr<Program> reduced_program;
+ scoped_ptr<LinearSolver> linear_solver;
+ scoped_ptr<IterationCallback> logging_callback;
+ scoped_ptr<IterationCallback> state_updating_callback;
+
+ shared_ptr<Evaluator> evaluator;
+ shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+
+ std::vector<double*> removed_parameter_blocks;
+ Vector reduced_parameters;
+ double fixed_cost;
+};
+
+// Common functions used by various preprocessors.
+
+// If OpenMP support is not available and user has requested more than
+// one thread, then set the *_num_threads options as needed to 1.
+void ChangeNumThreadsIfNeeded(Solver::Options* options);
+
+// Extract the effective parameter vector from the preprocessed
+// problem and setup bits of the Minimizer::Options object that are
+// common to all Preprocessors.
+void SetupCommonMinimizerOptions(PreprocessedProblem* pp);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PREPROCESSOR_H_
diff --git a/extern/ceres/internal/ceres/problem.cc b/extern/ceres/internal/ceres/problem.cc
new file mode 100644
index 00000000000..03b7d6afa48
--- /dev/null
+++ b/extern/ceres/internal/ceres/problem.cc
@@ -0,0 +1,273 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// keir@google.com (Keir Mierle)
+
+#include "ceres/problem.h"
+
+#include <vector>
+#include "ceres/crs_matrix.h"
+#include "ceres/problem_impl.h"
+
+namespace ceres {
+
+using std::vector;
+
+Problem::Problem() : problem_impl_(new internal::ProblemImpl) {}
+Problem::Problem(const Problem::Options& options)
+ : problem_impl_(new internal::ProblemImpl(options)) {}
+Problem::~Problem() {}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ const vector<double*>& parameter_blocks) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ parameter_blocks);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6, x7);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8) {
+ return problem_impl_->AddResidualBlock(cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8);
+}
+
+ResidualBlockId Problem::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8, double* x9) {
+ return problem_impl_->AddResidualBlock(
+ cost_function,
+ loss_function,
+ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
+}
+
+void Problem::AddParameterBlock(double* values, int size) {
+ problem_impl_->AddParameterBlock(values, size);
+}
+
+void Problem::AddParameterBlock(double* values,
+ int size,
+ LocalParameterization* local_parameterization) {
+ problem_impl_->AddParameterBlock(values, size, local_parameterization);
+}
+
+void Problem::RemoveResidualBlock(ResidualBlockId residual_block) {
+ problem_impl_->RemoveResidualBlock(residual_block);
+}
+
+void Problem::RemoveParameterBlock(double* values) {
+ problem_impl_->RemoveParameterBlock(values);
+}
+
+void Problem::SetParameterBlockConstant(double* values) {
+ problem_impl_->SetParameterBlockConstant(values);
+}
+
+void Problem::SetParameterBlockVariable(double* values) {
+ problem_impl_->SetParameterBlockVariable(values);
+}
+
+void Problem::SetParameterization(
+ double* values,
+ LocalParameterization* local_parameterization) {
+ problem_impl_->SetParameterization(values, local_parameterization);
+}
+
+const LocalParameterization* Problem::GetParameterization(
+ double* values) const {
+ return problem_impl_->GetParameterization(values);
+}
+
+void Problem::SetParameterLowerBound(double* values,
+ int index,
+ double lower_bound) {
+ problem_impl_->SetParameterLowerBound(values, index, lower_bound);
+}
+
+void Problem::SetParameterUpperBound(double* values,
+ int index,
+ double upper_bound) {
+ problem_impl_->SetParameterUpperBound(values, index, upper_bound);
+}
+
+bool Problem::Evaluate(const EvaluateOptions& evaluate_options,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian) {
+ return problem_impl_->Evaluate(evaluate_options,
+ cost,
+ residuals,
+ gradient,
+ jacobian);
+}
+
+int Problem::NumParameterBlocks() const {
+ return problem_impl_->NumParameterBlocks();
+}
+
+int Problem::NumParameters() const {
+ return problem_impl_->NumParameters();
+}
+
+int Problem::NumResidualBlocks() const {
+ return problem_impl_->NumResidualBlocks();
+}
+
+int Problem::NumResiduals() const {
+ return problem_impl_->NumResiduals();
+}
+
+int Problem::ParameterBlockSize(const double* parameter_block) const {
+ return problem_impl_->ParameterBlockSize(parameter_block);
+}
+
+int Problem::ParameterBlockLocalSize(const double* parameter_block) const {
+ return problem_impl_->ParameterBlockLocalSize(parameter_block);
+}
+
+bool Problem::HasParameterBlock(const double* values) const {
+ return problem_impl_->HasParameterBlock(values);
+}
+
+void Problem::GetParameterBlocks(vector<double*>* parameter_blocks) const {
+ problem_impl_->GetParameterBlocks(parameter_blocks);
+}
+
+void Problem::GetResidualBlocks(
+ vector<ResidualBlockId>* residual_blocks) const {
+ problem_impl_->GetResidualBlocks(residual_blocks);
+}
+
+void Problem::GetParameterBlocksForResidualBlock(
+ const ResidualBlockId residual_block,
+ vector<double*>* parameter_blocks) const {
+ problem_impl_->GetParameterBlocksForResidualBlock(residual_block,
+ parameter_blocks);
+}
+
+const CostFunction* Problem::GetCostFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const {
+ return problem_impl_->GetCostFunctionForResidualBlock(residual_block);
+}
+
+const LossFunction* Problem::GetLossFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const {
+ return problem_impl_->GetLossFunctionForResidualBlock(residual_block);
+}
+
+void Problem::GetResidualBlocksForParameterBlock(
+ const double* values,
+ vector<ResidualBlockId>* residual_blocks) const {
+ problem_impl_->GetResidualBlocksForParameterBlock(values,
+ residual_blocks);
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/problem_impl.cc b/extern/ceres/internal/ceres/problem_impl.cc
new file mode 100644
index 00000000000..8547d5d3f77
--- /dev/null
+++ b/extern/ceres/internal/ceres/problem_impl.cc
@@ -0,0 +1,945 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// mierle@gmail.com (Keir Mierle)
+
+#include "ceres/problem_impl.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/cost_function.h"
+#include "ceres/crs_matrix.h"
+#include "ceres/evaluator.h"
+#include "ceres/loss_function.h"
+#include "ceres/map_util.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/stl_util.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::map;
+using std::string;
+using std::vector;
+typedef std::map<double*, internal::ParameterBlock*> ParameterMap;
+
+namespace {
+// Returns true if two regions of memory, a and b, with sizes size_a and size_b
+// respectively, overlap.
+bool RegionsAlias(const double* a, int size_a,
+ const double* b, int size_b) {
+ return (a < b) ? b < (a + size_a)
+ : a < (b + size_b);
+}
+
+void CheckForNoAliasing(double* existing_block,
+ int existing_block_size,
+ double* new_block,
+ int new_block_size) {
+ CHECK(!RegionsAlias(existing_block, existing_block_size,
+ new_block, new_block_size))
+ << "Aliasing detected between existing parameter block at memory "
+ << "location " << existing_block
+ << " and has size " << existing_block_size << " with new parameter "
+ << "block that has memory address " << new_block << " and would have "
+ << "size " << new_block_size << ".";
+}
+
+} // namespace
+
+ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
+ int size) {
+ CHECK(values != NULL) << "Null pointer passed to AddParameterBlock "
+ << "for a parameter with size " << size;
+
+ // Ignore the request if there is a block for the given pointer already.
+ ParameterMap::iterator it = parameter_block_map_.find(values);
+ if (it != parameter_block_map_.end()) {
+ if (!options_.disable_all_safety_checks) {
+ int existing_size = it->second->Size();
+ CHECK(size == existing_size)
+ << "Tried adding a parameter block with the same double pointer, "
+ << values << ", twice, but with different block sizes. Original "
+ << "size was " << existing_size << " but new size is "
+ << size;
+ }
+ return it->second;
+ }
+
+ if (!options_.disable_all_safety_checks) {
+ // Before adding the parameter block, also check that it doesn't alias any
+ // other parameter blocks.
+ if (!parameter_block_map_.empty()) {
+ ParameterMap::iterator lb = parameter_block_map_.lower_bound(values);
+
+ // If lb is not the first block, check the previous block for aliasing.
+ if (lb != parameter_block_map_.begin()) {
+ ParameterMap::iterator previous = lb;
+ --previous;
+ CheckForNoAliasing(previous->first,
+ previous->second->Size(),
+ values,
+ size);
+ }
+
+ // If lb is not off the end, check lb for aliasing.
+ if (lb != parameter_block_map_.end()) {
+ CheckForNoAliasing(lb->first,
+ lb->second->Size(),
+ values,
+ size);
+ }
+ }
+ }
+
+ // Pass the index of the new parameter block as well to keep the index in
+ // sync with the position of the parameter in the program's parameter vector.
+ ParameterBlock* new_parameter_block =
+ new ParameterBlock(values, size, program_->parameter_blocks_.size());
+
+ // For dynamic problems, add the list of dependent residual blocks, which is
+ // empty to start.
+ if (options_.enable_fast_removal) {
+ new_parameter_block->EnableResidualBlockDependencies();
+ }
+ parameter_block_map_[values] = new_parameter_block;
+ program_->parameter_blocks_.push_back(new_parameter_block);
+ return new_parameter_block;
+}
+
+void ProblemImpl::InternalRemoveResidualBlock(ResidualBlock* residual_block) {
+ CHECK_NOTNULL(residual_block);
+ // Perform no check on the validity of residual_block, that is handled in
+ // the public method: RemoveResidualBlock().
+
+ // If needed, remove the parameter dependencies on this residual block.
+ if (options_.enable_fast_removal) {
+ const int num_parameter_blocks_for_residual =
+ residual_block->NumParameterBlocks();
+ for (int i = 0; i < num_parameter_blocks_for_residual; ++i) {
+ residual_block->parameter_blocks()[i]
+ ->RemoveResidualBlock(residual_block);
+ }
+
+ ResidualBlockSet::iterator it = residual_block_set_.find(residual_block);
+ residual_block_set_.erase(it);
+ }
+ DeleteBlockInVector(program_->mutable_residual_blocks(), residual_block);
+}
+
+// Deletes the residual block in question, assuming there are no other
+// references to it inside the problem (e.g. by another parameter). Referenced
+// cost and loss functions are tucked away for future deletion, since it is not
+// possible to know whether other parts of the problem depend on them without
+// doing a full scan.
+void ProblemImpl::DeleteBlock(ResidualBlock* residual_block) {
+ // The const casts here are legit, since ResidualBlock holds these
+ // pointers as const pointers but we have ownership of them and
+ // have the right to destroy them when the destructor is called.
+ if (options_.cost_function_ownership == TAKE_OWNERSHIP &&
+ residual_block->cost_function() != NULL) {
+ cost_functions_to_delete_.push_back(
+ const_cast<CostFunction*>(residual_block->cost_function()));
+ }
+ if (options_.loss_function_ownership == TAKE_OWNERSHIP &&
+ residual_block->loss_function() != NULL) {
+ loss_functions_to_delete_.push_back(
+ const_cast<LossFunction*>(residual_block->loss_function()));
+ }
+ delete residual_block;
+}
+
+// Deletes the parameter block in question, assuming there are no other
+// references to it inside the problem (e.g. by any residual blocks).
+// Referenced parameterizations are tucked away for future deletion, since it
+// is not possible to know whether other parts of the problem depend on them
+// without doing a full scan.
+void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) {
+ if (options_.local_parameterization_ownership == TAKE_OWNERSHIP &&
+ parameter_block->local_parameterization() != NULL) {
+ local_parameterizations_to_delete_.push_back(
+ parameter_block->mutable_local_parameterization());
+ }
+ parameter_block_map_.erase(parameter_block->mutable_user_state());
+ delete parameter_block;
+}
+
+ProblemImpl::ProblemImpl() : program_(new internal::Program) {}
+ProblemImpl::ProblemImpl(const Problem::Options& options)
+ : options_(options),
+ program_(new internal::Program) {}
+
+ProblemImpl::~ProblemImpl() {
+ // Collect the unique cost/loss functions and delete the residuals.
+ const int num_residual_blocks = program_->residual_blocks_.size();
+ cost_functions_to_delete_.reserve(num_residual_blocks);
+ loss_functions_to_delete_.reserve(num_residual_blocks);
+ for (int i = 0; i < program_->residual_blocks_.size(); ++i) {
+ DeleteBlock(program_->residual_blocks_[i]);
+ }
+
+ // Collect the unique parameterizations and delete the parameters.
+ for (int i = 0; i < program_->parameter_blocks_.size(); ++i) {
+ DeleteBlock(program_->parameter_blocks_[i]);
+ }
+
+ // Delete the owned cost/loss functions and parameterizations.
+ STLDeleteUniqueContainerPointers(local_parameterizations_to_delete_.begin(),
+ local_parameterizations_to_delete_.end());
+ STLDeleteUniqueContainerPointers(cost_functions_to_delete_.begin(),
+ cost_functions_to_delete_.end());
+ STLDeleteUniqueContainerPointers(loss_functions_to_delete_.begin(),
+ loss_functions_to_delete_.end());
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ const vector<double*>& parameter_blocks) {
+ CHECK_NOTNULL(cost_function);
+ CHECK_EQ(parameter_blocks.size(),
+ cost_function->parameter_block_sizes().size());
+
+ // Check the sizes match.
+ const vector<int32>& parameter_block_sizes =
+ cost_function->parameter_block_sizes();
+
+ if (!options_.disable_all_safety_checks) {
+ CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size())
+ << "Number of blocks input is different than the number of blocks "
+ << "that the cost function expects.";
+
+ // Check for duplicate parameter blocks.
+ vector<double*> sorted_parameter_blocks(parameter_blocks);
+ sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
+ vector<double*>::const_iterator duplicate_items =
+ unique(sorted_parameter_blocks.begin(),
+ sorted_parameter_blocks.end());
+ if (duplicate_items != sorted_parameter_blocks.end()) {
+ string blocks;
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ blocks += StringPrintf(" %p ", parameter_blocks[i]);
+ }
+
+ LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
+ << "are not allowed. Parameter block pointers: ["
+ << blocks << "]";
+ }
+ }
+
+ // Add parameter blocks and convert the double*'s to parameter blocks.
+ vector<ParameterBlock*> parameter_block_ptrs(parameter_blocks.size());
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ parameter_block_ptrs[i] =
+ InternalAddParameterBlock(parameter_blocks[i],
+ parameter_block_sizes[i]);
+ }
+
+ if (!options_.disable_all_safety_checks) {
+ // Check that the block sizes match the block sizes expected by the
+ // cost_function.
+ for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
+ CHECK_EQ(cost_function->parameter_block_sizes()[i],
+ parameter_block_ptrs[i]->Size())
+ << "The cost function expects parameter block " << i
+ << " of size " << cost_function->parameter_block_sizes()[i]
+ << " but was given a block of size "
+ << parameter_block_ptrs[i]->Size();
+ }
+ }
+
+ ResidualBlock* new_residual_block =
+ new ResidualBlock(cost_function,
+ loss_function,
+ parameter_block_ptrs,
+ program_->residual_blocks_.size());
+
+ // Add dependencies on the residual to the parameter blocks.
+ if (options_.enable_fast_removal) {
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ parameter_block_ptrs[i]->AddResidualBlock(new_residual_block);
+ }
+ }
+
+ program_->residual_blocks_.push_back(new_residual_block);
+
+ if (options_.enable_fast_removal) {
+ residual_block_set_.insert(new_residual_block);
+ }
+
+ return new_residual_block;
+}
+
+// Unfortunately, macros don't help much to reduce this code, and var args don't
+// work because of the ambiguous case that there is no loss function.
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ residual_parameters.push_back(x7);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ residual_parameters.push_back(x7);
+ residual_parameters.push_back(x8);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+ResidualBlock* ProblemImpl::AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8, double* x9) {
+ vector<double*> residual_parameters;
+ residual_parameters.push_back(x0);
+ residual_parameters.push_back(x1);
+ residual_parameters.push_back(x2);
+ residual_parameters.push_back(x3);
+ residual_parameters.push_back(x4);
+ residual_parameters.push_back(x5);
+ residual_parameters.push_back(x6);
+ residual_parameters.push_back(x7);
+ residual_parameters.push_back(x8);
+ residual_parameters.push_back(x9);
+ return AddResidualBlock(cost_function, loss_function, residual_parameters);
+}
+
+void ProblemImpl::AddParameterBlock(double* values, int size) {
+ InternalAddParameterBlock(values, size);
+}
+
+void ProblemImpl::AddParameterBlock(
+ double* values,
+ int size,
+ LocalParameterization* local_parameterization) {
+ ParameterBlock* parameter_block =
+ InternalAddParameterBlock(values, size);
+ if (local_parameterization != NULL) {
+ parameter_block->SetParameterization(local_parameterization);
+ }
+}
+
+// Delete a block from a vector of blocks, maintaining the indexing invariant.
+// This is done in constant time by moving an element from the end of the
+// vector over the element to remove, then popping the last element. It
+// destroys the ordering in the interest of speed.
+template<typename Block>
+void ProblemImpl::DeleteBlockInVector(vector<Block*>* mutable_blocks,
+ Block* block_to_remove) {
+ CHECK_EQ((*mutable_blocks)[block_to_remove->index()], block_to_remove)
+ << "You found a Ceres bug! \n"
+ << "Block requested: "
+ << block_to_remove->ToString() << "\n"
+ << "Block present: "
+ << (*mutable_blocks)[block_to_remove->index()]->ToString();
+
+ // Prepare the to-be-moved block for the new, lower-in-index position by
+ // setting the index to the blocks final location.
+ Block* tmp = mutable_blocks->back();
+ tmp->set_index(block_to_remove->index());
+
+ // Overwrite the to-be-deleted residual block with the one at the end.
+ (*mutable_blocks)[block_to_remove->index()] = tmp;
+
+ DeleteBlock(block_to_remove);
+
+ // The block is gone so shrink the vector of blocks accordingly.
+ mutable_blocks->pop_back();
+}
+
+void ProblemImpl::RemoveResidualBlock(ResidualBlock* residual_block) {
+ CHECK_NOTNULL(residual_block);
+
+ // Verify that residual_block identifies a residual in the current problem.
+ const string residual_not_found_message =
+ StringPrintf("Residual block to remove: %p not found. This usually means "
+ "one of three things have happened:\n"
+ " 1) residual_block is uninitialised and points to a random "
+ "area in memory.\n"
+ " 2) residual_block represented a residual that was added to"
+ " the problem, but referred to a parameter block which has "
+ "since been removed, which removes all residuals which "
+ "depend on that parameter block, and was thus removed.\n"
+ " 3) residual_block referred to a residual that has already "
+ "been removed from the problem (by the user).",
+ residual_block);
+ if (options_.enable_fast_removal) {
+ CHECK(residual_block_set_.find(residual_block) !=
+ residual_block_set_.end())
+ << residual_not_found_message;
+ } else {
+ // Perform a full search over all current residuals.
+ CHECK(std::find(program_->residual_blocks().begin(),
+ program_->residual_blocks().end(),
+ residual_block) != program_->residual_blocks().end())
+ << residual_not_found_message;
+ }
+
+ InternalRemoveResidualBlock(residual_block);
+}
+
+void ProblemImpl::RemoveParameterBlock(double* values) {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "it can be removed.";
+ }
+
+ if (options_.enable_fast_removal) {
+ // Copy the dependent residuals from the parameter block because the set of
+ // dependents will change after each call to RemoveResidualBlock().
+ vector<ResidualBlock*> residual_blocks_to_remove(
+ parameter_block->mutable_residual_blocks()->begin(),
+ parameter_block->mutable_residual_blocks()->end());
+ for (int i = 0; i < residual_blocks_to_remove.size(); ++i) {
+ InternalRemoveResidualBlock(residual_blocks_to_remove[i]);
+ }
+ } else {
+ // Scan all the residual blocks to remove ones that depend on the parameter
+ // block. Do the scan backwards since the vector changes while iterating.
+ const int num_residual_blocks = NumResidualBlocks();
+ for (int i = num_residual_blocks - 1; i >= 0; --i) {
+ ResidualBlock* residual_block =
+ (*(program_->mutable_residual_blocks()))[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (residual_block->parameter_blocks()[j] == parameter_block) {
+ InternalRemoveResidualBlock(residual_block);
+ // The parameter blocks are guaranteed unique.
+ break;
+ }
+ }
+ }
+ }
+ DeleteBlockInVector(program_->mutable_parameter_blocks(), parameter_block);
+}
+
+void ProblemImpl::SetParameterBlockConstant(double* values) {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "it can be set constant.";
+ }
+
+ parameter_block->SetConstant();
+}
+
+void ProblemImpl::SetParameterBlockVariable(double* values) {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "it can be set varying.";
+ }
+
+ parameter_block->SetVarying();
+}
+
+void ProblemImpl::SetParameterization(
+ double* values,
+ LocalParameterization* local_parameterization) {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can set its local parameterization.";
+ }
+
+ parameter_block->SetParameterization(local_parameterization);
+}
+
+const LocalParameterization* ProblemImpl::GetParameterization(
+ double* values) const {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can get its local parameterization.";
+ }
+
+ return parameter_block->local_parameterization();
+}
+
+void ProblemImpl::SetParameterLowerBound(double* values,
+ int index,
+ double lower_bound) {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can set a lower bound on one of its components.";
+ }
+
+ parameter_block->SetLowerBound(index, lower_bound);
+}
+
+void ProblemImpl::SetParameterUpperBound(double* values,
+ int index,
+ double upper_bound) {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, values, NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can set an upper bound on one of its components.";
+ }
+ parameter_block->SetUpperBound(index, upper_bound);
+}
+
+bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
+ double* cost,
+ vector<double>* residuals,
+ vector<double>* gradient,
+ CRSMatrix* jacobian) {
+ if (cost == NULL &&
+ residuals == NULL &&
+ gradient == NULL &&
+ jacobian == NULL) {
+ LOG(INFO) << "Nothing to do.";
+ return true;
+ }
+
+ // If the user supplied residual blocks, then use them, otherwise
+ // take the residual blocks from the underlying program.
+ Program program;
+ *program.mutable_residual_blocks() =
+ ((evaluate_options.residual_blocks.size() > 0)
+ ? evaluate_options.residual_blocks : program_->residual_blocks());
+
+ const vector<double*>& parameter_block_ptrs =
+ evaluate_options.parameter_blocks;
+
+ vector<ParameterBlock*> variable_parameter_blocks;
+ vector<ParameterBlock*>& parameter_blocks =
+ *program.mutable_parameter_blocks();
+
+ if (parameter_block_ptrs.size() == 0) {
+ // The user did not provide any parameter blocks, so default to
+ // using all the parameter blocks in the order that they are in
+ // the underlying program object.
+ parameter_blocks = program_->parameter_blocks();
+ } else {
+ // The user supplied a vector of parameter blocks. Using this list
+ // requires a number of steps.
+
+ // 1. Convert double* into ParameterBlock*
+ parameter_blocks.resize(parameter_block_ptrs.size());
+ for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
+ parameter_blocks[i] = FindWithDefault(parameter_block_map_,
+ parameter_block_ptrs[i],
+ NULL);
+ if (parameter_blocks[i] == NULL) {
+ LOG(FATAL) << "No known parameter block for "
+ << "Problem::Evaluate::Options.parameter_blocks[" << i << "]"
+ << " = " << parameter_block_ptrs[i];
+ }
+ }
+
+ // 2. The user may have only supplied a subset of parameter
+ // blocks, so identify the ones that are not supplied by the user
+ // and are NOT constant. These parameter blocks are stored in
+ // variable_parameter_blocks.
+ //
+ // To ensure that the parameter blocks are not included in the
+ // columns of the jacobian, we need to make sure that they are
+ // constant during evaluation and then make them variable again
+ // after we are done.
+ vector<ParameterBlock*> all_parameter_blocks(program_->parameter_blocks());
+ vector<ParameterBlock*> included_parameter_blocks(
+ program.parameter_blocks());
+
+ vector<ParameterBlock*> excluded_parameter_blocks;
+ sort(all_parameter_blocks.begin(), all_parameter_blocks.end());
+ sort(included_parameter_blocks.begin(), included_parameter_blocks.end());
+ set_difference(all_parameter_blocks.begin(),
+ all_parameter_blocks.end(),
+ included_parameter_blocks.begin(),
+ included_parameter_blocks.end(),
+ back_inserter(excluded_parameter_blocks));
+
+ variable_parameter_blocks.reserve(excluded_parameter_blocks.size());
+ for (int i = 0; i < excluded_parameter_blocks.size(); ++i) {
+ ParameterBlock* parameter_block = excluded_parameter_blocks[i];
+ if (!parameter_block->IsConstant()) {
+ variable_parameter_blocks.push_back(parameter_block);
+ parameter_block->SetConstant();
+ }
+ }
+ }
+
+ // Setup the Parameter indices and offsets before an evaluator can
+ // be constructed and used.
+ program.SetParameterOffsetsAndIndex();
+
+ Evaluator::Options evaluator_options;
+
+ // Even though using SPARSE_NORMAL_CHOLESKY requires SuiteSparse or
+ // CXSparse, here it just being used for telling the evaluator to
+ // use a SparseRowCompressedMatrix for the jacobian. This is because
+ // the Evaluator decides the storage for the Jacobian based on the
+ // type of linear solver being used.
+ evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+#ifndef CERES_USE_OPENMP
+ LOG_IF(WARNING, evaluate_options.num_threads > 1)
+ << "OpenMP support is not compiled into this binary; "
+ << "only evaluate_options.num_threads = 1 is supported. Switching "
+ << "to single threaded mode.";
+ evaluator_options.num_threads = 1;
+#else
+ evaluator_options.num_threads = evaluate_options.num_threads;
+#endif // CERES_USE_OPENMP
+
+ string error;
+ scoped_ptr<Evaluator> evaluator(
+ Evaluator::Create(evaluator_options, &program, &error));
+ if (evaluator.get() == NULL) {
+ LOG(ERROR) << "Unable to create an Evaluator object. "
+ << "Error: " << error
+ << "This is a Ceres bug; please contact the developers!";
+
+ // Make the parameter blocks that were temporarily marked
+ // constant, variable again.
+ for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
+ variable_parameter_blocks[i]->SetVarying();
+ }
+
+ program_->SetParameterBlockStatePtrsToUserStatePtrs();
+ program_->SetParameterOffsetsAndIndex();
+ return false;
+ }
+
+ if (residuals !=NULL) {
+ residuals->resize(evaluator->NumResiduals());
+ }
+
+ if (gradient != NULL) {
+ gradient->resize(evaluator->NumEffectiveParameters());
+ }
+
+ scoped_ptr<CompressedRowSparseMatrix> tmp_jacobian;
+ if (jacobian != NULL) {
+ tmp_jacobian.reset(
+ down_cast<CompressedRowSparseMatrix*>(evaluator->CreateJacobian()));
+ }
+
+ // Point the state pointers to the user state pointers. This is
+ // needed so that we can extract a parameter vector which is then
+ // passed to Evaluator::Evaluate.
+ program.SetParameterBlockStatePtrsToUserStatePtrs();
+
+ // Copy the value of the parameter blocks into a vector, since the
+ // Evaluate::Evaluate method needs its input as such. The previous
+ // call to SetParameterBlockStatePtrsToUserStatePtrs ensures that
+ // these values are the ones corresponding to the actual state of
+ // the parameter blocks, rather than the temporary state pointer
+ // used for evaluation.
+ Vector parameters(program.NumParameters());
+ program.ParameterBlocksToStateVector(parameters.data());
+
+ double tmp_cost = 0;
+
+ Evaluator::EvaluateOptions evaluator_evaluate_options;
+ evaluator_evaluate_options.apply_loss_function =
+ evaluate_options.apply_loss_function;
+ bool status = evaluator->Evaluate(evaluator_evaluate_options,
+ parameters.data(),
+ &tmp_cost,
+ residuals != NULL ? &(*residuals)[0] : NULL,
+ gradient != NULL ? &(*gradient)[0] : NULL,
+ tmp_jacobian.get());
+
+ // Make the parameter blocks that were temporarily marked constant,
+ // variable again.
+ for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
+ variable_parameter_blocks[i]->SetVarying();
+ }
+
+ if (status) {
+ if (cost != NULL) {
+ *cost = tmp_cost;
+ }
+ if (jacobian != NULL) {
+ tmp_jacobian->ToCRSMatrix(jacobian);
+ }
+ }
+
+ program_->SetParameterBlockStatePtrsToUserStatePtrs();
+ program_->SetParameterOffsetsAndIndex();
+ return status;
+}
+
+int ProblemImpl::NumParameterBlocks() const {
+ return program_->NumParameterBlocks();
+}
+
+int ProblemImpl::NumParameters() const {
+ return program_->NumParameters();
+}
+
+int ProblemImpl::NumResidualBlocks() const {
+ return program_->NumResidualBlocks();
+}
+
+int ProblemImpl::NumResiduals() const {
+ return program_->NumResiduals();
+}
+
+int ProblemImpl::ParameterBlockSize(const double* values) const {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, const_cast<double*>(values), NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can get its size.";
+ }
+
+ return parameter_block->Size();
+}
+
+int ProblemImpl::ParameterBlockLocalSize(const double* values) const {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, const_cast<double*>(values), NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can get its local size.";
+ }
+
+ return parameter_block->LocalSize();
+}
+
+bool ProblemImpl::HasParameterBlock(const double* parameter_block) const {
+ return (parameter_block_map_.find(const_cast<double*>(parameter_block)) !=
+ parameter_block_map_.end());
+}
+
+void ProblemImpl::GetParameterBlocks(vector<double*>* parameter_blocks) const {
+ CHECK_NOTNULL(parameter_blocks);
+ parameter_blocks->resize(0);
+ for (ParameterMap::const_iterator it = parameter_block_map_.begin();
+ it != parameter_block_map_.end();
+ ++it) {
+ parameter_blocks->push_back(it->first);
+ }
+}
+
+void ProblemImpl::GetResidualBlocks(
+ vector<ResidualBlockId>* residual_blocks) const {
+ CHECK_NOTNULL(residual_blocks);
+ *residual_blocks = program().residual_blocks();
+}
+
+void ProblemImpl::GetParameterBlocksForResidualBlock(
+ const ResidualBlockId residual_block,
+ vector<double*>* parameter_blocks) const {
+ int num_parameter_blocks = residual_block->NumParameterBlocks();
+ CHECK_NOTNULL(parameter_blocks)->resize(num_parameter_blocks);
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ (*parameter_blocks)[i] =
+ residual_block->parameter_blocks()[i]->mutable_user_state();
+ }
+}
+
+const CostFunction* ProblemImpl::GetCostFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const {
+ return residual_block->cost_function();
+}
+
+const LossFunction* ProblemImpl::GetLossFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const {
+ return residual_block->loss_function();
+}
+
+void ProblemImpl::GetResidualBlocksForParameterBlock(
+ const double* values,
+ vector<ResidualBlockId>* residual_blocks) const {
+ ParameterBlock* parameter_block =
+ FindWithDefault(parameter_block_map_, const_cast<double*>(values), NULL);
+ if (parameter_block == NULL) {
+ LOG(FATAL) << "Parameter block not found: " << values
+ << ". You must add the parameter block to the problem before "
+ << "you can get the residual blocks that depend on it.";
+ }
+
+ if (options_.enable_fast_removal) {
+ // In this case the residual blocks that depend on the parameter block are
+ // stored in the parameter block already, so just copy them out.
+ CHECK_NOTNULL(residual_blocks)->resize(
+ parameter_block->mutable_residual_blocks()->size());
+ std::copy(parameter_block->mutable_residual_blocks()->begin(),
+ parameter_block->mutable_residual_blocks()->end(),
+ residual_blocks->begin());
+ return;
+ }
+
+ // Find residual blocks that depend on the parameter block.
+ CHECK_NOTNULL(residual_blocks)->clear();
+ const int num_residual_blocks = NumResidualBlocks();
+ for (int i = 0; i < num_residual_blocks; ++i) {
+ ResidualBlock* residual_block =
+ (*(program_->mutable_residual_blocks()))[i];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (residual_block->parameter_blocks()[j] == parameter_block) {
+ residual_blocks->push_back(residual_block);
+ // The parameter blocks are guaranteed unique.
+ break;
+ }
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/problem_impl.h b/extern/ceres/internal/ceres/problem_impl.h
new file mode 100644
index 00000000000..f42bde6c793
--- /dev/null
+++ b/extern/ceres/internal/ceres/problem_impl.h
@@ -0,0 +1,226 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// This is the implementation of the public Problem API. The pointer to
+// implementation (PIMPL) idiom makes it possible for Ceres internal code to
+// refer to the private data members without needing to exposing it to the
+// world. An alternative to PIMPL is to have a factory which returns instances
+// of a virtual base class; while that approach would work, it requires clients
+// to always put a Problem object into a scoped pointer; this needlessly muddies
+// client code for little benefit. Therefore, the PIMPL comprise was chosen.
+
+#ifndef CERES_PUBLIC_PROBLEM_IMPL_H_
+#define CERES_PUBLIC_PROBLEM_IMPL_H_
+
+#include <map>
+#include <vector>
+
+#include "ceres/internal/macros.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/collections_port.h"
+#include "ceres/problem.h"
+#include "ceres/types.h"
+
+namespace ceres {
+
+class CostFunction;
+class LossFunction;
+class LocalParameterization;
+struct CRSMatrix;
+
+namespace internal {
+
+class Program;
+class ResidualBlock;
+
+class ProblemImpl {
+ public:
+ typedef std::map<double*, ParameterBlock*> ParameterMap;
+ typedef HashSet<ResidualBlock*> ResidualBlockSet;
+
+ ProblemImpl();
+ explicit ProblemImpl(const Problem::Options& options);
+
+ ~ProblemImpl();
+
+ // See the public problem.h file for description of these methods.
+ ResidualBlockId AddResidualBlock(
+ CostFunction* cost_function,
+ LossFunction* loss_function,
+ const std::vector<double*>& parameter_blocks);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8);
+ ResidualBlockId AddResidualBlock(CostFunction* cost_function,
+ LossFunction* loss_function,
+ double* x0, double* x1, double* x2,
+ double* x3, double* x4, double* x5,
+ double* x6, double* x7, double* x8,
+ double* x9);
+ void AddParameterBlock(double* values, int size);
+ void AddParameterBlock(double* values,
+ int size,
+ LocalParameterization* local_parameterization);
+
+ void RemoveResidualBlock(ResidualBlock* residual_block);
+ void RemoveParameterBlock(double* values);
+
+ void SetParameterBlockConstant(double* values);
+ void SetParameterBlockVariable(double* values);
+ void SetParameterization(double* values,
+ LocalParameterization* local_parameterization);
+ const LocalParameterization* GetParameterization(double* values) const;
+
+ void SetParameterLowerBound(double* values, int index, double lower_bound);
+ void SetParameterUpperBound(double* values, int index, double upper_bound);
+
+ bool Evaluate(const Problem::EvaluateOptions& options,
+ double* cost,
+ std::vector<double>* residuals,
+ std::vector<double>* gradient,
+ CRSMatrix* jacobian);
+
+ int NumParameterBlocks() const;
+ int NumParameters() const;
+ int NumResidualBlocks() const;
+ int NumResiduals() const;
+
+ int ParameterBlockSize(const double* parameter_block) const;
+ int ParameterBlockLocalSize(const double* parameter_block) const;
+
+ bool HasParameterBlock(const double* parameter_block) const;
+
+ void GetParameterBlocks(std::vector<double*>* parameter_blocks) const;
+ void GetResidualBlocks(std::vector<ResidualBlockId>* residual_blocks) const;
+
+ void GetParameterBlocksForResidualBlock(
+ const ResidualBlockId residual_block,
+ std::vector<double*>* parameter_blocks) const;
+
+ const CostFunction* GetCostFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const;
+ const LossFunction* GetLossFunctionForResidualBlock(
+ const ResidualBlockId residual_block) const;
+
+ void GetResidualBlocksForParameterBlock(
+ const double* values,
+ std::vector<ResidualBlockId>* residual_blocks) const;
+
+ const Program& program() const { return *program_; }
+ Program* mutable_program() { return program_.get(); }
+
+ const ParameterMap& parameter_map() const { return parameter_block_map_; }
+ const ResidualBlockSet& residual_block_set() const {
+ CHECK(options_.enable_fast_removal)
+ << "Fast removal not enabled, residual_block_set is not maintained.";
+ return residual_block_set_;
+ }
+
+ private:
+ ParameterBlock* InternalAddParameterBlock(double* values, int size);
+ void InternalRemoveResidualBlock(ResidualBlock* residual_block);
+
+ bool InternalEvaluate(Program* program,
+ double* cost,
+ std::vector<double>* residuals,
+ std::vector<double>* gradient,
+ CRSMatrix* jacobian);
+
+ // Delete the arguments in question. These differ from the Remove* functions
+ // in that they do not clean up references to the block to delete; they
+ // merely delete them.
+ template<typename Block>
+ void DeleteBlockInVector(std::vector<Block*>* mutable_blocks,
+ Block* block_to_remove);
+ void DeleteBlock(ResidualBlock* residual_block);
+ void DeleteBlock(ParameterBlock* parameter_block);
+
+ const Problem::Options options_;
+
+ // The mapping from user pointers to parameter blocks.
+ std::map<double*, ParameterBlock*> parameter_block_map_;
+
+ // Iff enable_fast_removal is enabled, contains the current residual blocks.
+ ResidualBlockSet residual_block_set_;
+
+ // The actual parameter and residual blocks.
+ internal::scoped_ptr<internal::Program> program_;
+
+ // When removing residual and parameter blocks, cost/loss functions and
+ // parameterizations have ambiguous ownership. Instead of scanning the entire
+ // problem to see if the cost/loss/parameterization is shared with other
+ // residual or parameter blocks, buffer them until destruction.
+ //
+ // TODO(keir): See if it makes sense to use sets instead.
+ std::vector<CostFunction*> cost_functions_to_delete_;
+ std::vector<LossFunction*> loss_functions_to_delete_;
+ std::vector<LocalParameterization*> local_parameterizations_to_delete_;
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(ProblemImpl);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_PUBLIC_PROBLEM_IMPL_H_
diff --git a/extern/ceres/internal/ceres/program.cc b/extern/ceres/internal/ceres/program.cc
new file mode 100644
index 00000000000..8e97f072113
--- /dev/null
+++ b/extern/ceres/internal/ceres/program.cc
@@ -0,0 +1,524 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/program.h"
+
+#include <map>
+#include <vector>
+#include "ceres/array_utils.h"
+#include "ceres/casts.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/cost_function.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/port.h"
+#include "ceres/local_parameterization.h"
+#include "ceres/loss_function.h"
+#include "ceres/map_util.h"
+#include "ceres/parameter_block.h"
+#include "ceres/problem.h"
+#include "ceres/residual_block.h"
+#include "ceres/stl_util.h"
+#include "ceres/triplet_sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+using std::max;
+using std::set;
+using std::string;
+using std::vector;
+
+Program::Program() {}
+
+Program::Program(const Program& program)
+ : parameter_blocks_(program.parameter_blocks_),
+ residual_blocks_(program.residual_blocks_) {
+}
+
+const vector<ParameterBlock*>& Program::parameter_blocks() const {
+ return parameter_blocks_;
+}
+
+const vector<ResidualBlock*>& Program::residual_blocks() const {
+ return residual_blocks_;
+}
+
+vector<ParameterBlock*>* Program::mutable_parameter_blocks() {
+ return &parameter_blocks_;
+}
+
+vector<ResidualBlock*>* Program::mutable_residual_blocks() {
+ return &residual_blocks_;
+}
+
+bool Program::StateVectorToParameterBlocks(const double *state) {
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ if (!parameter_blocks_[i]->IsConstant() &&
+ !parameter_blocks_[i]->SetState(state)) {
+ return false;
+ }
+ state += parameter_blocks_[i]->Size();
+ }
+ return true;
+}
+
+void Program::ParameterBlocksToStateVector(double *state) const {
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ parameter_blocks_[i]->GetState(state);
+ state += parameter_blocks_[i]->Size();
+ }
+}
+
+void Program::CopyParameterBlockStateToUserState() {
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ parameter_blocks_[i]->GetState(parameter_blocks_[i]->mutable_user_state());
+ }
+}
+
+bool Program::SetParameterBlockStatePtrsToUserStatePtrs() {
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ if (!parameter_blocks_[i]->IsConstant() &&
+ !parameter_blocks_[i]->SetState(parameter_blocks_[i]->user_state())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Program::Plus(const double* state,
+ const double* delta,
+ double* state_plus_delta) const {
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ if (!parameter_blocks_[i]->Plus(state, delta, state_plus_delta)) {
+ return false;
+ }
+ state += parameter_blocks_[i]->Size();
+ delta += parameter_blocks_[i]->LocalSize();
+ state_plus_delta += parameter_blocks_[i]->Size();
+ }
+ return true;
+}
+
+void Program::SetParameterOffsetsAndIndex() {
+ // Set positions for all parameters appearing as arguments to residuals to one
+ // past the end of the parameter block array.
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks_[i];
+ for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
+ residual_block->parameter_blocks()[j]->set_index(-1);
+ }
+ }
+ // For parameters that appear in the program, set their position and offset.
+ int state_offset = 0;
+ int delta_offset = 0;
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ parameter_blocks_[i]->set_index(i);
+ parameter_blocks_[i]->set_state_offset(state_offset);
+ parameter_blocks_[i]->set_delta_offset(delta_offset);
+ state_offset += parameter_blocks_[i]->Size();
+ delta_offset += parameter_blocks_[i]->LocalSize();
+ }
+}
+
+bool Program::IsValid() const {
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ const ResidualBlock* residual_block = residual_blocks_[i];
+ if (residual_block->index() != i) {
+ LOG(WARNING) << "Residual block: " << i
+ << " has incorrect index: " << residual_block->index();
+ return false;
+ }
+ }
+
+ int state_offset = 0;
+ int delta_offset = 0;
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+ if (parameter_block->index() != i ||
+ parameter_block->state_offset() != state_offset ||
+ parameter_block->delta_offset() != delta_offset) {
+ LOG(WARNING) << "Parameter block: " << i
+ << "has incorrect indexing information: "
+ << parameter_block->ToString();
+ return false;
+ }
+
+ state_offset += parameter_blocks_[i]->Size();
+ delta_offset += parameter_blocks_[i]->LocalSize();
+ }
+
+ return true;
+}
+
+bool Program::ParameterBlocksAreFinite(string* message) const {
+ CHECK_NOTNULL(message);
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+ const double* array = parameter_block->user_state();
+ const int size = parameter_block->Size();
+ const int invalid_index = FindInvalidValue(size, array);
+ if (invalid_index != size) {
+ *message = StringPrintf(
+ "ParameterBlock: %p with size %d has at least one invalid value.\n"
+ "First invalid value is at index: %d.\n"
+ "Parameter block values: ",
+ array, size, invalid_index);
+ AppendArrayToString(size, array, message);
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Program::IsBoundsConstrained() const {
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+ if (parameter_block->IsConstant()) {
+ continue;
+ }
+ const int size = parameter_block->Size();
+ for (int j = 0; j < size; ++j) {
+ const double lower_bound = parameter_block->LowerBoundForParameter(j);
+ const double upper_bound = parameter_block->UpperBoundForParameter(j);
+ if (lower_bound > -std::numeric_limits<double>::max() ||
+ upper_bound < std::numeric_limits<double>::max()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool Program::IsFeasible(string* message) const {
+ CHECK_NOTNULL(message);
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+ const double* parameters = parameter_block->user_state();
+ const int size = parameter_block->Size();
+ if (parameter_block->IsConstant()) {
+ // Constant parameter blocks must start in the feasible region
+ // to ultimately produce a feasible solution, since Ceres cannot
+ // change them.
+ for (int j = 0; j < size; ++j) {
+ const double lower_bound = parameter_block->LowerBoundForParameter(j);
+ const double upper_bound = parameter_block->UpperBoundForParameter(j);
+ if (parameters[j] < lower_bound || parameters[j] > upper_bound) {
+ *message = StringPrintf(
+ "ParameterBlock: %p with size %d has at least one infeasible "
+ "value."
+ "\nFirst infeasible value is at index: %d."
+ "\nLower bound: %e, value: %e, upper bound: %e"
+ "\nParameter block values: ",
+ parameters, size, j, lower_bound, parameters[j], upper_bound);
+ AppendArrayToString(size, parameters, message);
+ return false;
+ }
+ }
+ } else {
+ // Variable parameter blocks must have non-empty feasible
+ // regions, otherwise there is no way to produce a feasible
+ // solution.
+ for (int j = 0; j < size; ++j) {
+ const double lower_bound = parameter_block->LowerBoundForParameter(j);
+ const double upper_bound = parameter_block->UpperBoundForParameter(j);
+ if (lower_bound >= upper_bound) {
+ *message = StringPrintf(
+ "ParameterBlock: %p with size %d has at least one infeasible "
+ "bound."
+ "\nFirst infeasible bound is at index: %d."
+ "\nLower bound: %e, upper bound: %e"
+ "\nParameter block values: ",
+ parameters, size, j, lower_bound, upper_bound);
+ AppendArrayToString(size, parameters, message);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+Program* Program::CreateReducedProgram(
+ vector<double*>* removed_parameter_blocks,
+ double* fixed_cost,
+ string* error) const {
+ CHECK_NOTNULL(removed_parameter_blocks);
+ CHECK_NOTNULL(fixed_cost);
+ CHECK_NOTNULL(error);
+
+ scoped_ptr<Program> reduced_program(new Program(*this));
+ if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks,
+ fixed_cost,
+ error)) {
+ return NULL;
+ }
+
+ reduced_program->SetParameterOffsetsAndIndex();
+ return reduced_program.release();
+}
+
+bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
+ double* fixed_cost,
+ string* error) {
+ CHECK_NOTNULL(removed_parameter_blocks);
+ CHECK_NOTNULL(fixed_cost);
+ CHECK_NOTNULL(error);
+
+ scoped_array<double> residual_block_evaluate_scratch;
+ residual_block_evaluate_scratch.reset(
+ new double[MaxScratchDoublesNeededForEvaluate()]);
+ *fixed_cost = 0.0;
+
+ // Mark all the parameters as unused. Abuse the index member of the
+ // parameter blocks for the marking.
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ parameter_blocks_[i]->set_index(-1);
+ }
+
+ // Filter out residual that have all-constant parameters, and mark
+ // all the parameter blocks that appear in residuals.
+ int num_active_residual_blocks = 0;
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ ResidualBlock* residual_block = residual_blocks_[i];
+ int num_parameter_blocks = residual_block->NumParameterBlocks();
+
+ // Determine if the residual block is fixed, and also mark varying
+ // parameters that appear in the residual block.
+ bool all_constant = true;
+ for (int k = 0; k < num_parameter_blocks; k++) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[k];
+ if (!parameter_block->IsConstant()) {
+ all_constant = false;
+ parameter_block->set_index(1);
+ }
+ }
+
+ if (!all_constant) {
+ residual_blocks_[num_active_residual_blocks++] = residual_block;
+ continue;
+ }
+
+ // The residual is constant and will be removed, so its cost is
+ // added to the variable fixed_cost.
+ double cost = 0.0;
+ if (!residual_block->Evaluate(true,
+ &cost,
+ NULL,
+ NULL,
+ residual_block_evaluate_scratch.get())) {
+ *error = StringPrintf("Evaluation of the residual %d failed during "
+ "removal of fixed residual blocks.", i);
+ return false;
+ }
+ *fixed_cost += cost;
+ }
+ residual_blocks_.resize(num_active_residual_blocks);
+
+ // Filter out unused or fixed parameter blocks.
+ int num_active_parameter_blocks = 0;
+ removed_parameter_blocks->clear();
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ ParameterBlock* parameter_block = parameter_blocks_[i];
+ if (parameter_block->index() == -1) {
+ removed_parameter_blocks->push_back(
+ parameter_block->mutable_user_state());
+ } else {
+ parameter_blocks_[num_active_parameter_blocks++] = parameter_block;
+ }
+ }
+ parameter_blocks_.resize(num_active_parameter_blocks);
+
+ if (!(((NumResidualBlocks() == 0) &&
+ (NumParameterBlocks() == 0)) ||
+ ((NumResidualBlocks() != 0) &&
+ (NumParameterBlocks() != 0)))) {
+ *error = "Congratulations, you found a bug in Ceres. Please report it.";
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::IsParameterBlockSetIndependent(
+ const set<double*>& independent_set) const {
+ // Loop over each residual block and ensure that no two parameter
+ // blocks in the same residual block are part of
+ // parameter_block_ptrs as that would violate the assumption that it
+ // is an independent set in the Hessian matrix.
+ for (vector<ResidualBlock*>::const_iterator it = residual_blocks_.begin();
+ it != residual_blocks_.end();
+ ++it) {
+ ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks();
+ const int num_parameter_blocks = (*it)->NumParameterBlocks();
+ int count = 0;
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ count += independent_set.count(
+ parameter_blocks[i]->mutable_user_state());
+ }
+ if (count > 1) {
+ return false;
+ }
+ }
+ return true;
+}
+
+TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
+ // Matrix to store the block sparsity structure of the Jacobian.
+ TripletSparseMatrix* tsm =
+ new TripletSparseMatrix(NumParameterBlocks(),
+ NumResidualBlocks(),
+ 10 * NumResidualBlocks());
+ int num_nonzeros = 0;
+ int* rows = tsm->mutable_rows();
+ int* cols = tsm->mutable_cols();
+ double* values = tsm->mutable_values();
+
+ for (int c = 0; c < residual_blocks_.size(); ++c) {
+ const ResidualBlock* residual_block = residual_blocks_[c];
+ const int num_parameter_blocks = residual_block->NumParameterBlocks();
+ ParameterBlock* const* parameter_blocks =
+ residual_block->parameter_blocks();
+
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ if (parameter_blocks[j]->IsConstant()) {
+ continue;
+ }
+
+ // Re-size the matrix if needed.
+ if (num_nonzeros >= tsm->max_num_nonzeros()) {
+ tsm->set_num_nonzeros(num_nonzeros);
+ tsm->Reserve(2 * num_nonzeros);
+ rows = tsm->mutable_rows();
+ cols = tsm->mutable_cols();
+ values = tsm->mutable_values();
+ }
+
+ const int r = parameter_blocks[j]->index();
+ rows[num_nonzeros] = r;
+ cols[num_nonzeros] = c;
+ values[num_nonzeros] = 1.0;
+ ++num_nonzeros;
+ }
+ }
+
+ tsm->set_num_nonzeros(num_nonzeros);
+ return tsm;
+}
+
+int Program::NumResidualBlocks() const {
+ return residual_blocks_.size();
+}
+
+int Program::NumParameterBlocks() const {
+ return parameter_blocks_.size();
+}
+
+int Program::NumResiduals() const {
+ int num_residuals = 0;
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ num_residuals += residual_blocks_[i]->NumResiduals();
+ }
+ return num_residuals;
+}
+
+int Program::NumParameters() const {
+ int num_parameters = 0;
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ num_parameters += parameter_blocks_[i]->Size();
+ }
+ return num_parameters;
+}
+
+int Program::NumEffectiveParameters() const {
+ int num_parameters = 0;
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ num_parameters += parameter_blocks_[i]->LocalSize();
+ }
+ return num_parameters;
+}
+
+int Program::MaxScratchDoublesNeededForEvaluate() const {
+ // Compute the scratch space needed for evaluate.
+ int max_scratch_bytes_for_evaluate = 0;
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ max_scratch_bytes_for_evaluate =
+ max(max_scratch_bytes_for_evaluate,
+ residual_blocks_[i]->NumScratchDoublesForEvaluate());
+ }
+ return max_scratch_bytes_for_evaluate;
+}
+
+int Program::MaxDerivativesPerResidualBlock() const {
+ int max_derivatives = 0;
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ int derivatives = 0;
+ ResidualBlock* residual_block = residual_blocks_[i];
+ int num_parameters = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameters; ++j) {
+ derivatives += residual_block->NumResiduals() *
+ residual_block->parameter_blocks()[j]->LocalSize();
+ }
+ max_derivatives = max(max_derivatives, derivatives);
+ }
+ return max_derivatives;
+}
+
+int Program::MaxParametersPerResidualBlock() const {
+ int max_parameters = 0;
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ max_parameters = max(max_parameters,
+ residual_blocks_[i]->NumParameterBlocks());
+ }
+ return max_parameters;
+}
+
+int Program::MaxResidualsPerResidualBlock() const {
+ int max_residuals = 0;
+ for (int i = 0; i < residual_blocks_.size(); ++i) {
+ max_residuals = max(max_residuals, residual_blocks_[i]->NumResiduals());
+ }
+ return max_residuals;
+}
+
+string Program::ToString() const {
+ string ret = "Program dump\n";
+ ret += StringPrintf("Number of parameter blocks: %d\n", NumParameterBlocks());
+ ret += StringPrintf("Number of parameters: %d\n", NumParameters());
+ ret += "Parameters:\n";
+ for (int i = 0; i < parameter_blocks_.size(); ++i) {
+ ret += StringPrintf("%d: %s\n",
+ i, parameter_blocks_[i]->ToString().c_str());
+ }
+ return ret;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/program.h b/extern/ceres/internal/ceres/program.h
new file mode 100644
index 00000000000..38c958fe34a
--- /dev/null
+++ b/extern/ceres/internal/ceres/program.h
@@ -0,0 +1,192 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_PROGRAM_H_
+#define CERES_INTERNAL_PROGRAM_H_
+
+#include <set>
+#include <string>
+#include <vector>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class ParameterBlock;
+class ProblemImpl;
+class ResidualBlock;
+class TripletSparseMatrix;
+
+// A nonlinear least squares optimization problem. This is different from the
+// similarly-named "Problem" object, which offers a mutation interface for
+// adding and modifying parameters and residuals. The Program contains the core
+// part of the Problem, which is the parameters and the residuals, stored in a
+// particular ordering. The ordering is critical, since it defines the mapping
+// between (residual, parameter) pairs and a position in the jacobian of the
+// objective function. Various parts of Ceres transform one Program into
+// another; for example, the first stage of solving involves stripping all
+// constant parameters and residuals. This is in contrast with Problem, which is
+// not built for transformation.
+class Program {
+ public:
+ Program();
+ explicit Program(const Program& program);
+
+ // The ordered parameter and residual blocks for the program.
+ const std::vector<ParameterBlock*>& parameter_blocks() const;
+ const std::vector<ResidualBlock*>& residual_blocks() const;
+ std::vector<ParameterBlock*>* mutable_parameter_blocks();
+ std::vector<ResidualBlock*>* mutable_residual_blocks();
+
+ // Serialize to/from the program and update states.
+ //
+ // NOTE: Setting the state of a parameter block can trigger the
+ // computation of the Jacobian of its local parameterization. If
+ // this computation fails for some reason, then this method returns
+ // false and the state of the parameter blocks cannot be trusted.
+ bool StateVectorToParameterBlocks(const double *state);
+ void ParameterBlocksToStateVector(double *state) const;
+
+ // Copy internal state to the user's parameters.
+ void CopyParameterBlockStateToUserState();
+
+ // Set the parameter block pointers to the user pointers. Since this
+ // runs parameter block set state internally, which may call local
+ // parameterizations, this can fail. False is returned on failure.
+ bool SetParameterBlockStatePtrsToUserStatePtrs();
+
+ // Update a state vector for the program given a delta.
+ bool Plus(const double* state,
+ const double* delta,
+ double* state_plus_delta) const;
+
+ // Set the parameter indices and offsets. This permits mapping backward
+ // from a ParameterBlock* to an index in the parameter_blocks() vector. For
+ // any parameter block p, after calling SetParameterOffsetsAndIndex(), it
+ // is true that
+ //
+ // parameter_blocks()[p->index()] == p
+ //
+ // If a parameter appears in a residual but not in the parameter block, then
+ // it will have an index of -1.
+ //
+ // This also updates p->state_offset() and p->delta_offset(), which are the
+ // position of the parameter in the state and delta vector respectively.
+ void SetParameterOffsetsAndIndex();
+
+ // Check if the internal state of the program (the indexing and the
+ // offsets) are correct.
+ bool IsValid() const;
+
+ bool ParameterBlocksAreFinite(std::string* message) const;
+
+ // Returns true if the program has any non-constant parameter blocks
+ // which have non-trivial bounds constraints.
+ bool IsBoundsConstrained() const;
+
+ // Returns false, if the program has any constant parameter blocks
+ // which are not feasible, or any variable parameter blocks which
+ // have a lower bound greater than or equal to the upper bound.
+ bool IsFeasible(std::string* message) const;
+
+ // Loop over each residual block and ensure that no two parameter
+ // blocks in the same residual block are part of
+ // parameter_blocks as that would violate the assumption that it
+ // is an independent set in the Hessian matrix.
+ bool IsParameterBlockSetIndependent(
+ const std::set<double*>& independent_set) const;
+
+ // Create a TripletSparseMatrix which contains the zero-one
+ // structure corresponding to the block sparsity of the transpose of
+ // the Jacobian matrix.
+ //
+ // Caller owns the result.
+ TripletSparseMatrix* CreateJacobianBlockSparsityTranspose() const;
+
+ // Create a copy of this program and removes constant parameter
+ // blocks and residual blocks with no varying parameter blocks while
+ // preserving their relative order.
+ //
+ // removed_parameter_blocks on exit will contain the list of
+ // parameter blocks that were removed.
+ //
+ // fixed_cost will be equal to the sum of the costs of the residual
+ // blocks that were removed.
+ //
+ // If there was a problem, then the function will return a NULL
+ // pointer and error will contain a human readable description of
+ // the problem.
+ Program* CreateReducedProgram(std::vector<double*>* removed_parameter_blocks,
+ double* fixed_cost,
+ std::string* error) const;
+
+ // See problem.h for what these do.
+ int NumParameterBlocks() const;
+ int NumParameters() const;
+ int NumEffectiveParameters() const;
+ int NumResidualBlocks() const;
+ int NumResiduals() const;
+
+ int MaxScratchDoublesNeededForEvaluate() const;
+ int MaxDerivativesPerResidualBlock() const;
+ int MaxParametersPerResidualBlock() const;
+ int MaxResidualsPerResidualBlock() const;
+
+ // A human-readable dump of the parameter blocks for debugging.
+ // TODO(keir): If necessary, also dump the residual blocks.
+ std::string ToString() const;
+
+ private:
+ // Remove constant parameter blocks and residual blocks with no
+ // varying parameter blocks while preserving their relative order.
+ //
+ // removed_parameter_blocks on exit will contain the list of
+ // parameter blocks that were removed.
+ //
+ // fixed_cost will be equal to the sum of the costs of the residual
+ // blocks that were removed.
+ //
+ // If there was a problem, then the function will return false and
+ // error will contain a human readable description of the problem.
+ bool RemoveFixedBlocks(std::vector<double*>* removed_parameter_blocks,
+ double* fixed_cost,
+ std::string* message);
+
+ // The Program does not own the ParameterBlock or ResidualBlock objects.
+ std::vector<ParameterBlock*> parameter_blocks_;
+ std::vector<ResidualBlock*> residual_blocks_;
+
+ friend class ProblemImpl;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PROGRAM_H_
diff --git a/extern/ceres/internal/ceres/program_evaluator.h b/extern/ceres/internal/ceres/program_evaluator.h
new file mode 100644
index 00000000000..74a812adeef
--- /dev/null
+++ b/extern/ceres/internal/ceres/program_evaluator.h
@@ -0,0 +1,384 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// The ProgramEvaluator runs the cost functions contained in each residual block
+// and stores the result into a jacobian. The particular type of jacobian is
+// abstracted out using two template parameters:
+//
+// - An "EvaluatePreparer" that is responsible for creating the array with
+// pointers to the jacobian blocks where the cost function evaluates to.
+// - A "JacobianWriter" that is responsible for storing the resulting
+// jacobian blocks in the passed sparse matrix.
+//
+// This abstraction affords an efficient evaluator implementation while still
+// supporting writing to multiple sparse matrix formats. For example, when the
+// ProgramEvaluator is parameterized for writing to block sparse matrices, the
+// residual jacobians are written directly into their final position in the
+// block sparse matrix by the user's CostFunction; there is no copying.
+//
+// The evaluation is threaded with OpenMP.
+//
+// The EvaluatePreparer and JacobianWriter interfaces are as follows:
+//
+// class EvaluatePreparer {
+// // Prepare the jacobians array for use as the destination of a call to
+// // a cost function's evaluate method.
+// void Prepare(const ResidualBlock* residual_block,
+// int residual_block_index,
+// SparseMatrix* jacobian,
+// double** jacobians);
+// }
+//
+// class JacobianWriter {
+// // Create a jacobian that this writer can write. Same as
+// // Evaluator::CreateJacobian.
+// SparseMatrix* CreateJacobian() const;
+//
+// // Create num_threads evaluate preparers. Caller owns result which must
+// // be freed with delete[]. Resulting preparers are valid while *this is.
+// EvaluatePreparer* CreateEvaluatePreparers(int num_threads);
+//
+// // Write the block jacobians from a residual block evaluation to the
+// // larger sparse jacobian.
+// void Write(int residual_id,
+// int residual_offset,
+// double** jacobians,
+// SparseMatrix* jacobian);
+// }
+//
+// Note: The ProgramEvaluator is not thread safe, since internally it maintains
+// some per-thread scratch space.
+
+#ifndef CERES_INTERNAL_PROGRAM_EVALUATOR_H_
+#define CERES_INTERNAL_PROGRAM_EVALUATOR_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#endif
+
+#include <map>
+#include <string>
+#include <vector>
+#include "ceres/execution_summary.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/small_blas.h"
+
+namespace ceres {
+namespace internal {
+
+struct NullJacobianFinalizer {
+ void operator()(SparseMatrix* jacobian, int num_parameters) {}
+};
+
+template<typename EvaluatePreparer,
+ typename JacobianWriter,
+ typename JacobianFinalizer = NullJacobianFinalizer>
+class ProgramEvaluator : public Evaluator {
+ public:
+ ProgramEvaluator(const Evaluator::Options &options, Program* program)
+ : options_(options),
+ program_(program),
+ jacobian_writer_(options, program),
+ evaluate_preparers_(
+ jacobian_writer_.CreateEvaluatePreparers(options.num_threads)) {
+#ifndef CERES_USE_OPENMP
+ if (options_.num_threads > 1) {
+ LOG(WARNING)
+ << "OpenMP support is not compiled into this binary; "
+ << "only options.num_threads = 1 is supported. Switching "
+ << "to single threaded mode.";
+ options_.num_threads = 1;
+ }
+#endif
+
+ BuildResidualLayout(*program, &residual_layout_);
+ evaluate_scratch_.reset(CreateEvaluatorScratch(*program,
+ options.num_threads));
+ }
+
+ // Implementation of Evaluator interface.
+ SparseMatrix* CreateJacobian() const {
+ return jacobian_writer_.CreateJacobian();
+ }
+
+ bool Evaluate(const Evaluator::EvaluateOptions& evaluate_options,
+ const double* state,
+ double* cost,
+ double* residuals,
+ double* gradient,
+ SparseMatrix* jacobian) {
+ ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
+ ScopedExecutionTimer call_type_timer(gradient == NULL && jacobian == NULL
+ ? "Evaluator::Residual"
+ : "Evaluator::Jacobian",
+ &execution_summary_);
+
+ // The parameters are stateful, so set the state before evaluating.
+ if (!program_->StateVectorToParameterBlocks(state)) {
+ return false;
+ }
+
+ if (residuals != NULL) {
+ VectorRef(residuals, program_->NumResiduals()).setZero();
+ }
+
+ if (jacobian != NULL) {
+ jacobian->SetZero();
+ }
+
+ // Each thread gets it's own cost and evaluate scratch space.
+ for (int i = 0; i < options_.num_threads; ++i) {
+ evaluate_scratch_[i].cost = 0.0;
+ if (gradient != NULL) {
+ VectorRef(evaluate_scratch_[i].gradient.get(),
+ program_->NumEffectiveParameters()).setZero();
+ }
+ }
+
+ // This bool is used to disable the loop if an error is encountered
+ // without breaking out of it. The remaining loop iterations are still run,
+ // but with an empty body, and so will finish quickly.
+ bool abort = false;
+ int num_residual_blocks = program_->NumResidualBlocks();
+#pragma omp parallel for num_threads(options_.num_threads)
+ for (int i = 0; i < num_residual_blocks; ++i) {
+// Disable the loop instead of breaking, as required by OpenMP.
+#pragma omp flush(abort)
+ if (abort) {
+ continue;
+ }
+
+#ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+#else
+ int thread_id = 0;
+#endif
+ EvaluatePreparer* preparer = &evaluate_preparers_[thread_id];
+ EvaluateScratch* scratch = &evaluate_scratch_[thread_id];
+
+ // Prepare block residuals if requested.
+ const ResidualBlock* residual_block = program_->residual_blocks()[i];
+ double* block_residuals = NULL;
+ if (residuals != NULL) {
+ block_residuals = residuals + residual_layout_[i];
+ } else if (gradient != NULL) {
+ block_residuals = scratch->residual_block_residuals.get();
+ }
+
+ // Prepare block jacobians if requested.
+ double** block_jacobians = NULL;
+ if (jacobian != NULL || gradient != NULL) {
+ preparer->Prepare(residual_block,
+ i,
+ jacobian,
+ scratch->jacobian_block_ptrs.get());
+ block_jacobians = scratch->jacobian_block_ptrs.get();
+ }
+
+ // Evaluate the cost, residuals, and jacobians.
+ double block_cost;
+ if (!residual_block->Evaluate(
+ evaluate_options.apply_loss_function,
+ &block_cost,
+ block_residuals,
+ block_jacobians,
+ scratch->residual_block_evaluate_scratch.get())) {
+ abort = true;
+// This ensures that the OpenMP threads have a consistent view of 'abort'. Do
+// the flush inside the failure case so that there is usually only one
+// synchronization point per loop iteration instead of two.
+#pragma omp flush(abort)
+ continue;
+ }
+
+ scratch->cost += block_cost;
+
+ // Store the jacobians, if they were requested.
+ if (jacobian != NULL) {
+ jacobian_writer_.Write(i,
+ residual_layout_[i],
+ block_jacobians,
+ jacobian);
+ }
+
+ // Compute and store the gradient, if it was requested.
+ if (gradient != NULL) {
+ int num_residuals = residual_block->NumResiduals();
+ int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ const ParameterBlock* parameter_block =
+ residual_block->parameter_blocks()[j];
+ if (parameter_block->IsConstant()) {
+ continue;
+ }
+
+ MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ block_jacobians[j],
+ num_residuals,
+ parameter_block->LocalSize(),
+ block_residuals,
+ scratch->gradient.get() + parameter_block->delta_offset());
+ }
+ }
+ }
+
+ if (!abort) {
+ const int num_parameters = program_->NumEffectiveParameters();
+
+ // Sum the cost and gradient (if requested) from each thread.
+ (*cost) = 0.0;
+ if (gradient != NULL) {
+ VectorRef(gradient, num_parameters).setZero();
+ }
+ for (int i = 0; i < options_.num_threads; ++i) {
+ (*cost) += evaluate_scratch_[i].cost;
+ if (gradient != NULL) {
+ VectorRef(gradient, num_parameters) +=
+ VectorRef(evaluate_scratch_[i].gradient.get(), num_parameters);
+ }
+ }
+
+ // Finalize the Jacobian if it is available.
+ // `num_parameters` is passed to the finalizer so that additional
+ // storage can be reserved for additional diagonal elements if
+ // necessary.
+ if (jacobian != NULL) {
+ JacobianFinalizer f;
+ f(jacobian, num_parameters);
+ }
+ }
+ return !abort;
+ }
+
+ bool Plus(const double* state,
+ const double* delta,
+ double* state_plus_delta) const {
+ return program_->Plus(state, delta, state_plus_delta);
+ }
+
+ int NumParameters() const {
+ return program_->NumParameters();
+ }
+ int NumEffectiveParameters() const {
+ return program_->NumEffectiveParameters();
+ }
+
+ int NumResiduals() const {
+ return program_->NumResiduals();
+ }
+
+ virtual std::map<std::string, int> CallStatistics() const {
+ return execution_summary_.calls();
+ }
+
+ virtual std::map<std::string, double> TimeStatistics() const {
+ return execution_summary_.times();
+ }
+
+ private:
+ // Per-thread scratch space needed to evaluate and store each residual block.
+ struct EvaluateScratch {
+ void Init(int max_parameters_per_residual_block,
+ int max_scratch_doubles_needed_for_evaluate,
+ int max_residuals_per_residual_block,
+ int num_parameters) {
+ residual_block_evaluate_scratch.reset(
+ new double[max_scratch_doubles_needed_for_evaluate]);
+ gradient.reset(new double[num_parameters]);
+ VectorRef(gradient.get(), num_parameters).setZero();
+ residual_block_residuals.reset(
+ new double[max_residuals_per_residual_block]);
+ jacobian_block_ptrs.reset(
+ new double*[max_parameters_per_residual_block]);
+ }
+
+ double cost;
+ scoped_array<double> residual_block_evaluate_scratch;
+ // The gradient in the local parameterization.
+ scoped_array<double> gradient;
+ // Enough space to store the residual for the largest residual block.
+ scoped_array<double> residual_block_residuals;
+ scoped_array<double*> jacobian_block_ptrs;
+ };
+
+ static void BuildResidualLayout(const Program& program,
+ std::vector<int>* residual_layout) {
+ const std::vector<ResidualBlock*>& residual_blocks =
+ program.residual_blocks();
+ residual_layout->resize(program.NumResidualBlocks());
+ int residual_pos = 0;
+ for (int i = 0; i < residual_blocks.size(); ++i) {
+ const int num_residuals = residual_blocks[i]->NumResiduals();
+ (*residual_layout)[i] = residual_pos;
+ residual_pos += num_residuals;
+ }
+ }
+
+ // Create scratch space for each thread evaluating the program.
+ static EvaluateScratch* CreateEvaluatorScratch(const Program& program,
+ int num_threads) {
+ int max_parameters_per_residual_block =
+ program.MaxParametersPerResidualBlock();
+ int max_scratch_doubles_needed_for_evaluate =
+ program.MaxScratchDoublesNeededForEvaluate();
+ int max_residuals_per_residual_block =
+ program.MaxResidualsPerResidualBlock();
+ int num_parameters = program.NumEffectiveParameters();
+
+ EvaluateScratch* evaluate_scratch = new EvaluateScratch[num_threads];
+ for (int i = 0; i < num_threads; i++) {
+ evaluate_scratch[i].Init(max_parameters_per_residual_block,
+ max_scratch_doubles_needed_for_evaluate,
+ max_residuals_per_residual_block,
+ num_parameters);
+ }
+ return evaluate_scratch;
+ }
+
+ Evaluator::Options options_;
+ Program* program_;
+ JacobianWriter jacobian_writer_;
+ scoped_array<EvaluatePreparer> evaluate_preparers_;
+ scoped_array<EvaluateScratch> evaluate_scratch_;
+ std::vector<int> residual_layout_;
+ ::ceres::internal::ExecutionSummary execution_summary_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PROGRAM_EVALUATOR_H_
diff --git a/extern/ceres/internal/ceres/random.h b/extern/ceres/internal/ceres/random.h
new file mode 100644
index 00000000000..2a025600609
--- /dev/null
+++ b/extern/ceres/internal/ceres/random.h
@@ -0,0 +1,70 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_RANDOM_H_
+#define CERES_INTERNAL_RANDOM_H_
+
+#include <cmath>
+#include <cstdlib>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+
+inline void SetRandomState(int state) {
+ srand(state);
+}
+
+inline int Uniform(int n) {
+ return rand() % n;
+}
+
+inline double RandDouble() {
+ double r = static_cast<double>(rand());
+ return r / RAND_MAX;
+}
+
+// Box-Muller algorithm for normal random number generation.
+// http://en.wikipedia.org/wiki/Box-Muller_transform
+inline double RandNormal() {
+ double x1, x2, w;
+ do {
+ x1 = 2.0 * RandDouble() - 1.0;
+ x2 = 2.0 * RandDouble() - 1.0;
+ w = x1 * x1 + x2 * x2;
+ } while ( w >= 1.0 || w == 0.0 );
+
+ w = sqrt((-2.0 * log(w)) / w);
+ return x1 * w;
+}
+
+} // namespace ceres
+
+#endif // CERES_INTERNAL_RANDOM_H_
diff --git a/extern/ceres/internal/ceres/reorder_program.cc b/extern/ceres/internal/ceres/reorder_program.cc
new file mode 100644
index 00000000000..d0e8f32b3b7
--- /dev/null
+++ b/extern/ceres/internal/ceres/reorder_program.cc
@@ -0,0 +1,596 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/reorder_program.h"
+
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "ceres/cxsparse.h"
+#include "ceres/internal/port.h"
+#include "ceres/ordered_groups.h"
+#include "ceres/parameter_block.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/solver.h"
+#include "ceres/suitesparse.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "Eigen/SparseCore"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/OrderingMethods"
+#endif
+
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::map;
+using std::set;
+using std::string;
+using std::vector;
+
+namespace {
+
+// Find the minimum index of any parameter block to the given
+// residual. Parameter blocks that have indices greater than
+// size_of_first_elimination_group are considered to have an index
+// equal to size_of_first_elimination_group.
+static int MinParameterBlock(const ResidualBlock* residual_block,
+ int size_of_first_elimination_group) {
+ int min_parameter_block_position = size_of_first_elimination_group;
+ for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
+ ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
+ if (!parameter_block->IsConstant()) {
+ CHECK_NE(parameter_block->index(), -1)
+ << "Did you forget to call Program::SetParameterOffsetsAndIndex()? "
+ << "This is a Ceres bug; please contact the developers!";
+ min_parameter_block_position = std::min(parameter_block->index(),
+ min_parameter_block_position);
+ }
+ }
+ return min_parameter_block_position;
+}
+
+#if EIGEN_VERSION_AT_LEAST(3, 2, 2) && defined(CERES_USE_EIGEN_SPARSE)
+Eigen::SparseMatrix<int> CreateBlockJacobian(
+ const TripletSparseMatrix& block_jacobian_transpose) {
+ typedef Eigen::SparseMatrix<int> SparseMatrix;
+ typedef Eigen::Triplet<int> Triplet;
+
+ const int* rows = block_jacobian_transpose.rows();
+ const int* cols = block_jacobian_transpose.cols();
+ int num_nonzeros = block_jacobian_transpose.num_nonzeros();
+ vector<Triplet> triplets;
+ triplets.reserve(num_nonzeros);
+ for (int i = 0; i < num_nonzeros; ++i) {
+ triplets.push_back(Triplet(cols[i], rows[i], 1));
+ }
+
+ SparseMatrix block_jacobian(block_jacobian_transpose.num_cols(),
+ block_jacobian_transpose.num_rows());
+ block_jacobian.setFromTriplets(triplets.begin(), triplets.end());
+ return block_jacobian;
+}
+#endif
+
+void OrderingForSparseNormalCholeskyUsingSuiteSparse(
+ const TripletSparseMatrix& tsm_block_jacobian_transpose,
+ const vector<ParameterBlock*>& parameter_blocks,
+ const ParameterBlockOrdering& parameter_block_ordering,
+ int* ordering) {
+#ifdef CERES_NO_SUITESPARSE
+ LOG(FATAL) << "Congratulations, you found a Ceres bug! "
+ << "Please report this error to the developers.";
+#else
+ SuiteSparse ss;
+ cholmod_sparse* block_jacobian_transpose =
+ ss.CreateSparseMatrix(
+ const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
+
+ // No CAMD or the user did not supply a useful ordering, then just
+ // use regular AMD.
+ if (parameter_block_ordering.NumGroups() <= 1 ||
+ !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
+ ss.ApproximateMinimumDegreeOrdering(block_jacobian_transpose, &ordering[0]);
+ } else {
+ vector<int> constraints;
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ constraints.push_back(
+ parameter_block_ordering.GroupId(
+ parameter_blocks[i]->mutable_user_state()));
+ }
+
+ // Renumber the entries of constraints to be contiguous integers
+ // as CAMD requires that the group ids be in the range [0,
+ // parameter_blocks.size() - 1].
+ MapValuesToContiguousRange(constraints.size(), &constraints[0]);
+ ss.ConstrainedApproximateMinimumDegreeOrdering(block_jacobian_transpose,
+ &constraints[0],
+ ordering);
+ }
+
+ ss.Free(block_jacobian_transpose);
+#endif // CERES_NO_SUITESPARSE
+}
+
+void OrderingForSparseNormalCholeskyUsingCXSparse(
+ const TripletSparseMatrix& tsm_block_jacobian_transpose,
+ int* ordering) {
+#ifdef CERES_NO_CXSPARSE
+ LOG(FATAL) << "Congratulations, you found a Ceres bug! "
+ << "Please report this error to the developers.";
+#else // CERES_NO_CXSPARSE
+ // CXSparse works with J'J instead of J'. So compute the block
+ // sparsity for J'J and compute an approximate minimum degree
+ // ordering.
+ CXSparse cxsparse;
+ cs_di* block_jacobian_transpose;
+ block_jacobian_transpose =
+ cxsparse.CreateSparseMatrix(
+ const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
+ cs_di* block_jacobian = cxsparse.TransposeMatrix(block_jacobian_transpose);
+ cs_di* block_hessian =
+ cxsparse.MatrixMatrixMultiply(block_jacobian_transpose, block_jacobian);
+ cxsparse.Free(block_jacobian);
+ cxsparse.Free(block_jacobian_transpose);
+
+ cxsparse.ApproximateMinimumDegreeOrdering(block_hessian, ordering);
+ cxsparse.Free(block_hessian);
+#endif // CERES_NO_CXSPARSE
+}
+
+
+#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
+void OrderingForSparseNormalCholeskyUsingEigenSparse(
+ const TripletSparseMatrix& tsm_block_jacobian_transpose,
+ int* ordering) {
+#ifndef CERES_USE_EIGEN_SPARSE
+ LOG(FATAL) <<
+ "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
+ "because Ceres was not built with support for "
+ "Eigen's SimplicialLDLT decomposition. "
+ "This requires enabling building with -DEIGENSPARSE=ON.";
+#else
+
+ // This conversion from a TripletSparseMatrix to a Eigen::Triplet
+ // matrix is unfortunate, but unavoidable for now. It is not a
+ // significant performance penalty in the grand scheme of
+ // things. The right thing to do here would be to get a compressed
+ // row sparse matrix representation of the jacobian and go from
+ // there. But that is a project for another day.
+ typedef Eigen::SparseMatrix<int> SparseMatrix;
+
+ const SparseMatrix block_jacobian =
+ CreateBlockJacobian(tsm_block_jacobian_transpose);
+ const SparseMatrix block_hessian =
+ block_jacobian.transpose() * block_jacobian;
+
+ Eigen::AMDOrdering<int> amd_ordering;
+ Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
+ amd_ordering(block_hessian, perm);
+ for (int i = 0; i < block_hessian.rows(); ++i) {
+ ordering[i] = perm.indices()[i];
+ }
+#endif // CERES_USE_EIGEN_SPARSE
+}
+#endif
+
+} // namespace
+
+bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering& ordering,
+ Program* program,
+ string* error) {
+ const int num_parameter_blocks = program->NumParameterBlocks();
+ if (ordering.NumElements() != num_parameter_blocks) {
+ *error = StringPrintf("User specified ordering does not have the same "
+ "number of parameters as the problem. The problem"
+ "has %d blocks while the ordering has %d blocks.",
+ num_parameter_blocks,
+ ordering.NumElements());
+ return false;
+ }
+
+ vector<ParameterBlock*>* parameter_blocks =
+ program->mutable_parameter_blocks();
+ parameter_blocks->clear();
+
+ const map<int, set<double*> >& groups = ordering.group_to_elements();
+ for (map<int, set<double*> >::const_iterator group_it = groups.begin();
+ group_it != groups.end();
+ ++group_it) {
+ const set<double*>& group = group_it->second;
+ for (set<double*>::const_iterator parameter_block_ptr_it = group.begin();
+ parameter_block_ptr_it != group.end();
+ ++parameter_block_ptr_it) {
+ ProblemImpl::ParameterMap::const_iterator parameter_block_it =
+ parameter_map.find(*parameter_block_ptr_it);
+ if (parameter_block_it == parameter_map.end()) {
+ *error = StringPrintf("User specified ordering contains a pointer "
+ "to a double that is not a parameter block in "
+ "the problem. The invalid double is in group: %d",
+ group_it->first);
+ return false;
+ }
+ parameter_blocks->push_back(parameter_block_it->second);
+ }
+ }
+ return true;
+}
+
+bool LexicographicallyOrderResidualBlocks(
+ const int size_of_first_elimination_group,
+ Program* program,
+ string* error) {
+ CHECK_GE(size_of_first_elimination_group, 1)
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+
+ // Create a histogram of the number of residuals for each E block. There is an
+ // extra bucket at the end to catch all non-eliminated F blocks.
+ vector<int> residual_blocks_per_e_block(size_of_first_elimination_group + 1);
+ vector<ResidualBlock*>* residual_blocks = program->mutable_residual_blocks();
+ vector<int> min_position_per_residual(residual_blocks->size());
+ for (int i = 0; i < residual_blocks->size(); ++i) {
+ ResidualBlock* residual_block = (*residual_blocks)[i];
+ int position = MinParameterBlock(residual_block,
+ size_of_first_elimination_group);
+ min_position_per_residual[i] = position;
+ DCHECK_LE(position, size_of_first_elimination_group);
+ residual_blocks_per_e_block[position]++;
+ }
+
+ // Run a cumulative sum on the histogram, to obtain offsets to the start of
+ // each histogram bucket (where each bucket is for the residuals for that
+ // E-block).
+ vector<int> offsets(size_of_first_elimination_group + 1);
+ std::partial_sum(residual_blocks_per_e_block.begin(),
+ residual_blocks_per_e_block.end(),
+ offsets.begin());
+ CHECK_EQ(offsets.back(), residual_blocks->size())
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+
+ CHECK(find(residual_blocks_per_e_block.begin(),
+ residual_blocks_per_e_block.end() - 1, 0) !=
+ residual_blocks_per_e_block.end())
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+
+ // Fill in each bucket with the residual blocks for its corresponding E block.
+ // Each bucket is individually filled from the back of the bucket to the front
+ // of the bucket. The filling order among the buckets is dictated by the
+ // residual blocks. This loop uses the offsets as counters; subtracting one
+ // from each offset as a residual block is placed in the bucket. When the
+ // filling is finished, the offset pointerts should have shifted down one
+ // entry (this is verified below).
+ vector<ResidualBlock*> reordered_residual_blocks(
+ (*residual_blocks).size(), static_cast<ResidualBlock*>(NULL));
+ for (int i = 0; i < residual_blocks->size(); ++i) {
+ int bucket = min_position_per_residual[i];
+
+ // Decrement the cursor, which should now point at the next empty position.
+ offsets[bucket]--;
+
+ // Sanity.
+ CHECK(reordered_residual_blocks[offsets[bucket]] == NULL)
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+
+ reordered_residual_blocks[offsets[bucket]] = (*residual_blocks)[i];
+ }
+
+ // Sanity check #1: The difference in bucket offsets should match the
+ // histogram sizes.
+ for (int i = 0; i < size_of_first_elimination_group; ++i) {
+ CHECK_EQ(residual_blocks_per_e_block[i], offsets[i + 1] - offsets[i])
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+ }
+ // Sanity check #2: No NULL's left behind.
+ for (int i = 0; i < reordered_residual_blocks.size(); ++i) {
+ CHECK(reordered_residual_blocks[i] != NULL)
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+ }
+
+ // Now that the residuals are collected by E block, swap them in place.
+ swap(*program->mutable_residual_blocks(), reordered_residual_blocks);
+ return true;
+}
+
+// Pre-order the columns corresponding to the schur complement if
+// possible.
+void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
+ const ParameterBlockOrdering& parameter_block_ordering,
+ Program* program) {
+#ifndef CERES_NO_SUITESPARSE
+ SuiteSparse ss;
+ if (!SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
+ return;
+ }
+
+ vector<int> constraints;
+ vector<ParameterBlock*>& parameter_blocks =
+ *(program->mutable_parameter_blocks());
+
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ constraints.push_back(
+ parameter_block_ordering.GroupId(
+ parameter_blocks[i]->mutable_user_state()));
+ }
+
+ // Renumber the entries of constraints to be contiguous integers as
+ // CAMD requires that the group ids be in the range [0,
+ // parameter_blocks.size() - 1].
+ MapValuesToContiguousRange(constraints.size(), &constraints[0]);
+
+ // Compute a block sparse presentation of J'.
+ scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+ program->CreateJacobianBlockSparsityTranspose());
+
+ cholmod_sparse* block_jacobian_transpose =
+ ss.CreateSparseMatrix(tsm_block_jacobian_transpose.get());
+
+ vector<int> ordering(parameter_blocks.size(), 0);
+ ss.ConstrainedApproximateMinimumDegreeOrdering(block_jacobian_transpose,
+ &constraints[0],
+ &ordering[0]);
+ ss.Free(block_jacobian_transpose);
+
+ const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
+ for (int i = 0; i < program->NumParameterBlocks(); ++i) {
+ parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
+ }
+
+ program->SetParameterOffsetsAndIndex();
+#endif
+}
+
+void MaybeReorderSchurComplementColumnsUsingEigen(
+ const int size_of_first_elimination_group,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Program* program) {
+#if !EIGEN_VERSION_AT_LEAST(3, 2, 2) || !defined(CERES_USE_EIGEN_SPARSE)
+ return;
+#else
+
+ scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+ program->CreateJacobianBlockSparsityTranspose());
+
+ typedef Eigen::SparseMatrix<int> SparseMatrix;
+ const SparseMatrix block_jacobian =
+ CreateBlockJacobian(*tsm_block_jacobian_transpose);
+ const int num_rows = block_jacobian.rows();
+ const int num_cols = block_jacobian.cols();
+
+ // Vertically partition the jacobian in parameter blocks of type E
+ // and F.
+ const SparseMatrix E =
+ block_jacobian.block(0,
+ 0,
+ num_rows,
+ size_of_first_elimination_group);
+ const SparseMatrix F =
+ block_jacobian.block(0,
+ size_of_first_elimination_group,
+ num_rows,
+ num_cols - size_of_first_elimination_group);
+
+ // Block sparsity pattern of the schur complement.
+ const SparseMatrix block_schur_complement =
+ F.transpose() * F - F.transpose() * E * E.transpose() * F;
+
+ Eigen::AMDOrdering<int> amd_ordering;
+ Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
+ amd_ordering(block_schur_complement, perm);
+
+ const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
+ vector<ParameterBlock*> ordering(num_cols);
+
+ // The ordering of the first size_of_first_elimination_group does
+ // not matter, so we preserve the existing ordering.
+ for (int i = 0; i < size_of_first_elimination_group; ++i) {
+ ordering[i] = parameter_blocks[i];
+ }
+
+ // For the rest of the blocks, use the ordering computed using AMD.
+ for (int i = 0; i < block_schur_complement.cols(); ++i) {
+ ordering[size_of_first_elimination_group + i] =
+ parameter_blocks[size_of_first_elimination_group + perm.indices()[i]];
+ }
+
+ swap(*program->mutable_parameter_blocks(), ordering);
+ program->SetParameterOffsetsAndIndex();
+#endif
+}
+
+bool ReorderProgramForSchurTypeLinearSolver(
+ const LinearSolverType linear_solver_type,
+ const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+ const ProblemImpl::ParameterMap& parameter_map,
+ ParameterBlockOrdering* parameter_block_ordering,
+ Program* program,
+ string* error) {
+ if (parameter_block_ordering->NumElements() !=
+ program->NumParameterBlocks()) {
+ *error = StringPrintf(
+ "The program has %d parameter blocks, but the parameter block "
+ "ordering has %d parameter blocks.",
+ program->NumParameterBlocks(),
+ parameter_block_ordering->NumElements());
+ return false;
+ }
+
+ if (parameter_block_ordering->NumGroups() == 1) {
+ // If the user supplied an parameter_block_ordering with just one
+ // group, it is equivalent to the user supplying NULL as an
+ // parameter_block_ordering. Ceres is completely free to choose the
+ // parameter block ordering as it sees fit. For Schur type solvers,
+ // this means that the user wishes for Ceres to identify the
+ // e_blocks, which we do by computing a maximal independent set.
+ vector<ParameterBlock*> schur_ordering;
+ const int size_of_first_elimination_group =
+ ComputeStableSchurOrdering(*program, &schur_ordering);
+
+ CHECK_EQ(schur_ordering.size(), program->NumParameterBlocks())
+ << "Congratulations, you found a Ceres bug! Please report this error "
+ << "to the developers.";
+
+ // Update the parameter_block_ordering object.
+ for (int i = 0; i < schur_ordering.size(); ++i) {
+ double* parameter_block = schur_ordering[i]->mutable_user_state();
+ const int group_id = (i < size_of_first_elimination_group) ? 0 : 1;
+ parameter_block_ordering->AddElementToGroup(parameter_block, group_id);
+ }
+
+ // We could call ApplyOrdering but this is cheaper and
+ // simpler.
+ swap(*program->mutable_parameter_blocks(), schur_ordering);
+ } else {
+ // The user provided an ordering with more than one elimination
+ // group.
+
+ // Verify that the first elimination group is an independent set.
+ const set<double*>& first_elimination_group =
+ parameter_block_ordering
+ ->group_to_elements()
+ .begin()
+ ->second;
+ if (!program->IsParameterBlockSetIndependent(first_elimination_group)) {
+ *error =
+ StringPrintf("The first elimination group in the parameter block "
+ "ordering of size %zd is not an independent set",
+ first_elimination_group.size());
+ return false;
+ }
+
+ if (!ApplyOrdering(parameter_map,
+ *parameter_block_ordering,
+ program,
+ error)) {
+ return false;
+ }
+ }
+
+ program->SetParameterOffsetsAndIndex();
+
+ const int size_of_first_elimination_group =
+ parameter_block_ordering->group_to_elements().begin()->second.size();
+
+ if (linear_solver_type == SPARSE_SCHUR) {
+ if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
+ MaybeReorderSchurComplementColumnsUsingSuiteSparse(
+ *parameter_block_ordering,
+ program);
+ } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+ MaybeReorderSchurComplementColumnsUsingEigen(
+ size_of_first_elimination_group,
+ parameter_map,
+ program);
+ }
+ }
+
+ // Schur type solvers also require that their residual blocks be
+ // lexicographically ordered.
+ if (!LexicographicallyOrderResidualBlocks(size_of_first_elimination_group,
+ program,
+ error)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool ReorderProgramForSparseNormalCholesky(
+ const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+ const ParameterBlockOrdering& parameter_block_ordering,
+ Program* program,
+ string* error) {
+ if (parameter_block_ordering.NumElements() != program->NumParameterBlocks()) {
+ *error = StringPrintf(
+ "The program has %d parameter blocks, but the parameter block "
+ "ordering has %d parameter blocks.",
+ program->NumParameterBlocks(),
+ parameter_block_ordering.NumElements());
+ return false;
+ }
+
+ // Compute a block sparse presentation of J'.
+ scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
+ program->CreateJacobianBlockSparsityTranspose());
+
+ vector<int> ordering(program->NumParameterBlocks(), 0);
+ vector<ParameterBlock*>& parameter_blocks =
+ *(program->mutable_parameter_blocks());
+
+ if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
+ OrderingForSparseNormalCholeskyUsingSuiteSparse(
+ *tsm_block_jacobian_transpose,
+ parameter_blocks,
+ parameter_block_ordering,
+ &ordering[0]);
+ } else if (sparse_linear_algebra_library_type == CX_SPARSE) {
+ OrderingForSparseNormalCholeskyUsingCXSparse(
+ *tsm_block_jacobian_transpose,
+ &ordering[0]);
+ } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
+ OrderingForSparseNormalCholeskyUsingEigenSparse(
+ *tsm_block_jacobian_transpose,
+ &ordering[0]);
+#else
+ // For Eigen versions less than 3.2.2, there is nothing to do as
+ // older versions of Eigen do not expose a method for doing
+ // symbolic analysis on pre-ordered matrices, so a block
+ // pre-ordering is a bit pointless.
+
+ return true;
+#endif
+ }
+
+ // Apply ordering.
+ const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
+ for (int i = 0; i < program->NumParameterBlocks(); ++i) {
+ parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
+ }
+
+ program->SetParameterOffsetsAndIndex();
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/reorder_program.h b/extern/ceres/internal/ceres/reorder_program.h
new file mode 100644
index 00000000000..36e5d1637a9
--- /dev/null
+++ b/extern/ceres/internal/ceres/reorder_program.h
@@ -0,0 +1,101 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_REORDER_PROGRAM_H_
+#define CERES_INTERNAL_REORDER_PROGRAM_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/problem_impl.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+
+// Reorder the parameter blocks in program using the ordering
+bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering& ordering,
+ Program* program,
+ std::string* error);
+
+// Reorder the residuals for program, if necessary, so that the residuals
+// involving each E block occur together. This is a necessary condition for the
+// Schur eliminator, which works on these "row blocks" in the jacobian.
+bool LexicographicallyOrderResidualBlocks(int size_of_first_elimination_group,
+ Program* program,
+ std::string* error);
+
+// Schur type solvers require that all parameter blocks eliminated
+// by the Schur eliminator occur before others and the residuals be
+// sorted in lexicographic order of their parameter blocks.
+//
+// If the parameter_block_ordering only contains one elimination
+// group then a maximal independent set is computed and used as the
+// first elimination group, otherwise the user's ordering is used.
+//
+// If the linear solver type is SPARSE_SCHUR and support for
+// constrained fill-reducing ordering is available in the sparse
+// linear algebra library (SuiteSparse version >= 4.2.0) then
+// columns of the schur complement matrix are ordered to reduce the
+// fill-in the Cholesky factorization.
+//
+// Upon return, ordering contains the parameter block ordering that
+// was used to order the program.
+bool ReorderProgramForSchurTypeLinearSolver(
+ LinearSolverType linear_solver_type,
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+ const ProblemImpl::ParameterMap& parameter_map,
+ ParameterBlockOrdering* parameter_block_ordering,
+ Program* program,
+ std::string* error);
+
+// Sparse cholesky factorization routines when doing the sparse
+// cholesky factorization of the Jacobian matrix, reorders its
+// columns to reduce the fill-in. Compute this permutation and
+// re-order the parameter blocks.
+//
+// When using SuiteSparse, if the parameter_block_ordering contains
+// more than one elimination group and support for constrained
+// fill-reducing ordering is available in the sparse linear algebra
+// library (SuiteSparse version >= 4.2.0) then the fill reducing
+// ordering will take it into account, otherwise it will be ignored.
+bool ReorderProgramForSparseNormalCholesky(
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+ const ParameterBlockOrdering& parameter_block_ordering,
+ Program* program,
+ std::string* error);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_REORDER_PROGRAM_
diff --git a/extern/ceres/internal/ceres/residual_block.cc b/extern/ceres/internal/ceres/residual_block.cc
new file mode 100644
index 00000000000..9a123cf132e
--- /dev/null
+++ b/extern/ceres/internal/ceres/residual_block.cc
@@ -0,0 +1,219 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/residual_block.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <vector>
+#include "ceres/corrector.h"
+#include "ceres/parameter_block.h"
+#include "ceres/residual_block_utils.h"
+#include "ceres/cost_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/local_parameterization.h"
+#include "ceres/loss_function.h"
+#include "ceres/small_blas.h"
+
+using Eigen::Dynamic;
+
+namespace ceres {
+namespace internal {
+
+ResidualBlock::ResidualBlock(
+ const CostFunction* cost_function,
+ const LossFunction* loss_function,
+ const std::vector<ParameterBlock*>& parameter_blocks,
+ int index)
+ : cost_function_(cost_function),
+ loss_function_(loss_function),
+ parameter_blocks_(
+ new ParameterBlock* [
+ cost_function->parameter_block_sizes().size()]),
+ index_(index) {
+ std::copy(parameter_blocks.begin(),
+ parameter_blocks.end(),
+ parameter_blocks_.get());
+}
+
+bool ResidualBlock::Evaluate(const bool apply_loss_function,
+ double* cost,
+ double* residuals,
+ double** jacobians,
+ double* scratch) const {
+ const int num_parameter_blocks = NumParameterBlocks();
+ const int num_residuals = cost_function_->num_residuals();
+
+ // Collect the parameters from their blocks. This will rarely allocate, since
+ // residuals taking more than 8 parameter block arguments are rare.
+ FixedArray<const double*, 8> parameters(num_parameter_blocks);
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ parameters[i] = parameter_blocks_[i]->state();
+ }
+
+ // Put pointers into the scratch space into global_jacobians as appropriate.
+ FixedArray<double*, 8> global_jacobians(num_parameter_blocks);
+ if (jacobians != NULL) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+ if (jacobians[i] != NULL &&
+ parameter_block->LocalParameterizationJacobian() != NULL) {
+ global_jacobians[i] = scratch;
+ scratch += num_residuals * parameter_block->Size();
+ } else {
+ global_jacobians[i] = jacobians[i];
+ }
+ }
+ }
+
+ // If the caller didn't request residuals, use the scratch space for them.
+ bool outputting_residuals = (residuals != NULL);
+ if (!outputting_residuals) {
+ residuals = scratch;
+ }
+
+ // Invalidate the evaluation buffers so that we can check them after
+ // the CostFunction::Evaluate call, to see if all the return values
+ // that were required were written to and that they are finite.
+ double** eval_jacobians = (jacobians != NULL) ? global_jacobians.get() : NULL;
+
+ InvalidateEvaluation(*this, cost, residuals, eval_jacobians);
+
+ if (!cost_function_->Evaluate(parameters.get(), residuals, eval_jacobians)) {
+ return false;
+ }
+
+ if (!IsEvaluationValid(*this,
+ parameters.get(),
+ cost,
+ residuals,
+ eval_jacobians)) {
+ std::string message =
+ "\n\n"
+ "Error in evaluating the ResidualBlock.\n\n"
+ "There are two possible reasons. Either the CostFunction did not evaluate and fill all \n" // NOLINT
+ "residual and jacobians that were requested or there was a non-finite value (nan/infinite)\n" // NOLINT
+ "generated during the or jacobian computation. \n\n" +
+ EvaluationToString(*this,
+ parameters.get(),
+ cost,
+ residuals,
+ eval_jacobians);
+ LOG(WARNING) << message;
+ return false;
+ }
+
+ double squared_norm = VectorRef(residuals, num_residuals).squaredNorm();
+
+ // Update the jacobians with the local parameterizations.
+ if (jacobians != NULL) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ if (jacobians[i] != NULL) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+
+ // Apply local reparameterization to the jacobians.
+ if (parameter_block->LocalParameterizationJacobian() != NULL) {
+ // jacobians[i] = global_jacobians[i] * global_to_local_jacobian.
+ MatrixMatrixMultiply<Dynamic, Dynamic, Dynamic, Dynamic, 0>(
+ global_jacobians[i],
+ num_residuals,
+ parameter_block->Size(),
+ parameter_block->LocalParameterizationJacobian(),
+ parameter_block->Size(),
+ parameter_block->LocalSize(),
+ jacobians[i], 0, 0, num_residuals, parameter_block->LocalSize());
+ }
+ }
+ }
+ }
+
+ if (loss_function_ == NULL || !apply_loss_function) {
+ *cost = 0.5 * squared_norm;
+ return true;
+ }
+
+ double rho[3];
+ loss_function_->Evaluate(squared_norm, rho);
+ *cost = 0.5 * rho[0];
+
+ // No jacobians and not outputting residuals? All done. Doing an early exit
+ // here avoids constructing the "Corrector" object below in a common case.
+ if (jacobians == NULL && !outputting_residuals) {
+ return true;
+ }
+
+ // Correct for the effects of the loss function. The jacobians need to be
+ // corrected before the residuals, since they use the uncorrected residuals.
+ Corrector correct(squared_norm, rho);
+ if (jacobians != NULL) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ if (jacobians[i] != NULL) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+
+ // Correct the jacobians for the loss function.
+ correct.CorrectJacobian(num_residuals,
+ parameter_block->LocalSize(),
+ residuals,
+ jacobians[i]);
+ }
+ }
+ }
+
+ // Correct the residuals with the loss function.
+ if (outputting_residuals) {
+ correct.CorrectResiduals(num_residuals, residuals);
+ }
+ return true;
+}
+
+int ResidualBlock::NumScratchDoublesForEvaluate() const {
+ // Compute the amount of scratch space needed to store the full-sized
+ // jacobians. For parameters that have no local parameterization no storage
+ // is needed and the passed-in jacobian array is used directly. Also include
+ // space to store the residuals, which is needed for cost-only evaluations.
+ // This is slightly pessimistic, since both won't be needed all the time, but
+ // the amount of excess should not cause problems for the caller.
+ int num_parameters = NumParameterBlocks();
+ int scratch_doubles = 1;
+ for (int i = 0; i < num_parameters; ++i) {
+ const ParameterBlock* parameter_block = parameter_blocks_[i];
+ if (!parameter_block->IsConstant() &&
+ parameter_block->LocalParameterizationJacobian() != NULL) {
+ scratch_doubles += parameter_block->Size();
+ }
+ }
+ scratch_doubles *= NumResiduals();
+ return scratch_doubles;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/residual_block.h b/extern/ceres/internal/ceres/residual_block.h
new file mode 100644
index 00000000000..05e6d1f81e5
--- /dev/null
+++ b/extern/ceres/internal/ceres/residual_block.h
@@ -0,0 +1,148 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// keir@google.com (Keir Mierle)
+//
+// Purpose : Class and struct definitions for parameter and residual blocks.
+
+#ifndef CERES_INTERNAL_RESIDUAL_BLOCK_H_
+#define CERES_INTERNAL_RESIDUAL_BLOCK_H_
+
+#include <string>
+#include <vector>
+
+#include "ceres/cost_function.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+
+namespace ceres {
+
+class LossFunction;
+
+namespace internal {
+
+class ParameterBlock;
+
+// A term in the least squares problem. The mathematical form of each term in
+// the overall least-squares cost function is:
+//
+// 1
+// --- loss_function( || cost_function(block1, block2, ...) ||^2 ),
+// 2
+//
+// Storing the cost function and the loss function separately permits optimizing
+// the problem with standard non-linear least techniques, without requiring a
+// more general non-linear solver.
+//
+// The residual block stores pointers to but does not own the cost functions,
+// loss functions, and parameter blocks.
+class ResidualBlock {
+ public:
+ // Construct the residual block with the given cost/loss functions. Loss may
+ // be null. The index is the index of the residual block in the Program's
+ // residual_blocks array.
+ ResidualBlock(const CostFunction* cost_function,
+ const LossFunction* loss_function,
+ const std::vector<ParameterBlock*>& parameter_blocks,
+ int index);
+
+ // Evaluates the residual term, storing the scalar cost in *cost, the residual
+ // components in *residuals, and the jacobians between the parameters and
+ // residuals in jacobians[i], in row-major order. If residuals is NULL, the
+ // residuals are not computed. If jacobians is NULL, no jacobians are
+ // computed. If jacobians[i] is NULL, then the jacobian for that parameter is
+ // not computed.
+ //
+ // Evaluate needs scratch space which must be supplied by the caller via
+ // scratch. The array should have at least NumScratchDoublesForEvaluate()
+ // space available.
+ //
+ // The return value indicates the success or failure. If the function returns
+ // false, the caller should expect the the output memory locations to have
+ // been modified.
+ //
+ // The returned cost and jacobians have had robustification and local
+ // parameterizations applied already; for example, the jacobian for a
+ // 4-dimensional quaternion parameter using the "QuaternionParameterization"
+ // is num_residuals by 3 instead of num_residuals by 4.
+ //
+ // apply_loss_function as the name implies allows the user to switch
+ // the application of the loss function on and off.
+ bool Evaluate(bool apply_loss_function,
+ double* cost,
+ double* residuals,
+ double** jacobians,
+ double* scratch) const;
+
+
+ const CostFunction* cost_function() const { return cost_function_; }
+ const LossFunction* loss_function() const { return loss_function_; }
+
+ // Access the parameter blocks for this residual. The array has size
+ // NumParameterBlocks().
+ ParameterBlock* const* parameter_blocks() const {
+ return parameter_blocks_.get();
+ }
+
+ // Number of variable blocks that this residual term depends on.
+ int NumParameterBlocks() const {
+ return cost_function_->parameter_block_sizes().size();
+ }
+
+ // The size of the residual vector returned by this residual function.
+ int NumResiduals() const { return cost_function_->num_residuals(); }
+
+ // The minimum amount of scratch space needed to pass to Evaluate().
+ int NumScratchDoublesForEvaluate() const;
+
+ // This residual block's index in an array.
+ int index() const { return index_; }
+ void set_index(int index) { index_ = index; }
+
+ std::string ToString() {
+ return StringPrintf("{residual block; index=%d}", index_);
+ }
+
+ private:
+ const CostFunction* cost_function_;
+ const LossFunction* loss_function_;
+ scoped_array<ParameterBlock*> parameter_blocks_;
+
+ // The index of the residual, typically in a Program. This is only to permit
+ // switching from a ResidualBlock* to an index in the Program's array, needed
+ // to do efficient removals.
+ int32 index_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_RESIDUAL_BLOCK_H_
diff --git a/extern/ceres/internal/ceres/residual_block_utils.cc b/extern/ceres/internal/ceres/residual_block_utils.cc
new file mode 100644
index 00000000000..dd2bd73a6ac
--- /dev/null
+++ b/extern/ceres/internal/ceres/residual_block_utils.cc
@@ -0,0 +1,142 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/residual_block_utils.h"
+
+#include <cmath>
+#include <cstddef>
+#include <limits>
+#include "ceres/array_utils.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/parameter_block.h"
+#include "ceres/residual_block.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+
+void InvalidateEvaluation(const ResidualBlock& block,
+ double* cost,
+ double* residuals,
+ double** jacobians) {
+ const int num_parameter_blocks = block.NumParameterBlocks();
+ const int num_residuals = block.NumResiduals();
+
+ InvalidateArray(1, cost);
+ InvalidateArray(num_residuals, residuals);
+ if (jacobians != NULL) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ const int parameter_block_size = block.parameter_blocks()[i]->Size();
+ InvalidateArray(num_residuals * parameter_block_size, jacobians[i]);
+ }
+ }
+}
+
+string EvaluationToString(const ResidualBlock& block,
+ double const* const* parameters,
+ double* cost,
+ double* residuals,
+ double** jacobians) {
+ CHECK_NOTNULL(cost);
+ CHECK_NOTNULL(residuals);
+
+ const int num_parameter_blocks = block.NumParameterBlocks();
+ const int num_residuals = block.NumResiduals();
+ string result = "";
+
+ StringAppendF(&result,
+ "Residual Block size: %d parameter blocks x %d residuals\n\n",
+ num_parameter_blocks, num_residuals);
+ result +=
+ "For each parameter block, the value of the parameters are printed in the first column \n" // NOLINT
+ "and the value of the jacobian under the corresponding residual. If a ParameterBlock was \n" // NOLINT
+ "held constant then the corresponding jacobian is printed as 'Not Computed'. If an entry \n" // NOLINT
+ "of the Jacobian/residual array was requested but was not written to by user code, it is \n" // NOLINT
+ "indicated by 'Uninitialized'. This is an error. Residuals or Jacobian values evaluating \n" // NOLINT
+ "to Inf or NaN is also an error. \n\n"; // NOLINT
+
+ string space = "Residuals: ";
+ result += space;
+ AppendArrayToString(num_residuals, residuals, &result);
+ StringAppendF(&result, "\n\n");
+
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ const int parameter_block_size = block.parameter_blocks()[i]->Size();
+ StringAppendF(
+ &result, "Parameter Block %d, size: %d\n", i, parameter_block_size);
+ StringAppendF(&result, "\n");
+ for (int j = 0; j < parameter_block_size; ++j) {
+ AppendArrayToString(1, parameters[i] + j, &result);
+ StringAppendF(&result, "| ");
+ for (int k = 0; k < num_residuals; ++k) {
+ AppendArrayToString(1,
+ (jacobians != NULL && jacobians[i] != NULL)
+ ? jacobians[i] + k * parameter_block_size + j
+ : NULL,
+ &result);
+ }
+ StringAppendF(&result, "\n");
+ }
+ StringAppendF(&result, "\n");
+ }
+ StringAppendF(&result, "\n");
+ return result;
+}
+
+bool IsEvaluationValid(const ResidualBlock& block,
+ double const* const* parameters,
+ double* cost,
+ double* residuals,
+ double** jacobians) {
+ const int num_parameter_blocks = block.NumParameterBlocks();
+ const int num_residuals = block.NumResiduals();
+
+ if (!IsArrayValid(num_residuals, residuals)) {
+ return false;
+ }
+
+ if (jacobians != NULL) {
+ for (int i = 0; i < num_parameter_blocks; ++i) {
+ const int parameter_block_size = block.parameter_blocks()[i]->Size();
+ if (!IsArrayValid(num_residuals * parameter_block_size, jacobians[i])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/residual_block_utils.h b/extern/ceres/internal/ceres/residual_block_utils.h
new file mode 100644
index 00000000000..627337f743c
--- /dev/null
+++ b/extern/ceres/internal/ceres/residual_block_utils.h
@@ -0,0 +1,80 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Utility routines for ResidualBlock evaluation.
+//
+// These are useful for detecting two common class of errors.
+//
+// 1. Uninitialized memory - where the user for some reason did not
+// compute part of a cost/residual/jacobian.
+//
+// 2. Numerical failure while computing the cost/residual/jacobian,
+// e.g. NaN, infinities etc. This is particularly useful since the
+// automatic differentiation code does computations that are not
+// evident to the user and can silently generate hard to debug errors.
+
+#ifndef CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
+#define CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class ResidualBlock;
+
+// Invalidate cost, resdual and jacobian arrays (if not NULL).
+void InvalidateEvaluation(const ResidualBlock& block,
+ double* cost,
+ double* residuals,
+ double** jacobians);
+
+// Check if any of the arrays cost, residuals or jacobians contains an
+// NaN, return true if it does.
+bool IsEvaluationValid(const ResidualBlock& block,
+ double const* const* parameters,
+ double* cost,
+ double* residuals,
+ double** jacobians);
+
+// Create a string representation of the Residual block containing the
+// value of the parameters, residuals and jacobians if present.
+// Useful for debugging output.
+std::string EvaluationToString(const ResidualBlock& block,
+ double const* const* parameters,
+ double* cost,
+ double* residuals,
+ double** jacobians);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
diff --git a/extern/ceres/internal/ceres/schur_complement_solver.cc b/extern/ceres/internal/ceres/schur_complement_solver.cc
new file mode 100644
index 00000000000..2491060dcdc
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_complement_solver.cc
@@ -0,0 +1,670 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/internal/port.h"
+
+#include <algorithm>
+#include <ctime>
+#include <set>
+#include <vector>
+
+#include "ceres/block_random_access_dense_matrix.h"
+#include "ceres/block_random_access_matrix.h"
+#include "ceres/block_random_access_sparse_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/cxsparse.h"
+#include "ceres/detect_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/lapack.h"
+#include "ceres/linear_solver.h"
+#include "ceres/schur_complement_solver.h"
+#include "ceres/suitesparse.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+#include "Eigen/Dense"
+#include "Eigen/SparseCore"
+
+namespace ceres {
+namespace internal {
+
+using std::make_pair;
+using std::pair;
+using std::set;
+using std::vector;
+
+namespace {
+
+class BlockRandomAccessSparseMatrixAdapter : public LinearOperator {
+ public:
+ explicit BlockRandomAccessSparseMatrixAdapter(
+ const BlockRandomAccessSparseMatrix& m)
+ : m_(m) {
+ }
+
+ virtual ~BlockRandomAccessSparseMatrixAdapter() {}
+
+ // y = y + Ax;
+ virtual void RightMultiply(const double* x, double* y) const {
+ m_.SymmetricRightMultiply(x, y);
+ }
+
+ // y = y + A'x;
+ virtual void LeftMultiply(const double* x, double* y) const {
+ m_.SymmetricRightMultiply(x, y);
+ }
+
+ virtual int num_rows() const { return m_.num_rows(); }
+ virtual int num_cols() const { return m_.num_rows(); }
+
+ private:
+ const BlockRandomAccessSparseMatrix& m_;
+};
+
+class BlockRandomAccessDiagonalMatrixAdapter : public LinearOperator {
+ public:
+ explicit BlockRandomAccessDiagonalMatrixAdapter(
+ const BlockRandomAccessDiagonalMatrix& m)
+ : m_(m) {
+ }
+
+ virtual ~BlockRandomAccessDiagonalMatrixAdapter() {}
+
+ // y = y + Ax;
+ virtual void RightMultiply(const double* x, double* y) const {
+ m_.RightMultiply(x, y);
+ }
+
+ // y = y + A'x;
+ virtual void LeftMultiply(const double* x, double* y) const {
+ m_.RightMultiply(x, y);
+ }
+
+ virtual int num_rows() const { return m_.num_rows(); }
+ virtual int num_cols() const { return m_.num_rows(); }
+
+ private:
+ const BlockRandomAccessDiagonalMatrix& m_;
+};
+
+} // namespace
+
+LinearSolver::Summary SchurComplementSolver::SolveImpl(
+ BlockSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x) {
+ EventLogger event_logger("SchurComplementSolver::Solve");
+
+ if (eliminator_.get() == NULL) {
+ InitStorage(A->block_structure());
+ DetectStructure(*A->block_structure(),
+ options_.elimination_groups[0],
+ &options_.row_block_size,
+ &options_.e_block_size,
+ &options_.f_block_size);
+ eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_)));
+ eliminator_->Init(options_.elimination_groups[0], A->block_structure());
+ };
+ std::fill(x, x + A->num_cols(), 0.0);
+ event_logger.AddEvent("Setup");
+
+ eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get());
+ event_logger.AddEvent("Eliminate");
+
+ double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
+ const LinearSolver::Summary summary =
+ SolveReducedLinearSystem(per_solve_options, reduced_solution);
+ event_logger.AddEvent("ReducedSolve");
+
+ if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
+ eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x);
+ event_logger.AddEvent("BackSubstitute");
+ }
+
+ return summary;
+}
+
+// Initialize a BlockRandomAccessDenseMatrix to store the Schur
+// complement.
+void DenseSchurComplementSolver::InitStorage(
+ const CompressedRowBlockStructure* bs) {
+ const int num_eliminate_blocks = options().elimination_groups[0];
+ const int num_col_blocks = bs->cols.size();
+
+ vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
+ for (int i = num_eliminate_blocks, j = 0;
+ i < num_col_blocks;
+ ++i, ++j) {
+ blocks[j] = bs->cols[i].size;
+ }
+
+ set_lhs(new BlockRandomAccessDenseMatrix(blocks));
+ set_rhs(new double[lhs()->num_rows()]);
+}
+
+// Solve the system Sx = r, assuming that the matrix S is stored in a
+// BlockRandomAccessDenseMatrix. The linear system is solved using
+// Eigen's Cholesky factorization.
+LinearSolver::Summary
+DenseSchurComplementSolver::SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) {
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ const BlockRandomAccessDenseMatrix* m =
+ down_cast<const BlockRandomAccessDenseMatrix*>(lhs());
+ const int num_rows = m->num_rows();
+
+ // The case where there are no f blocks, and the system is block
+ // diagonal.
+ if (num_rows == 0) {
+ return summary;
+ }
+
+ summary.num_iterations = 1;
+
+ if (options().dense_linear_algebra_library_type == EIGEN) {
+ Eigen::LLT<Matrix, Eigen::Upper> llt =
+ ConstMatrixRef(m->values(), num_rows, num_rows)
+ .selfadjointView<Eigen::Upper>()
+ .llt();
+ if (llt.info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message =
+ "Eigen failure. Unable to perform dense Cholesky factorization.";
+ return summary;
+ }
+
+ VectorRef(solution, num_rows) = llt.solve(ConstVectorRef(rhs(), num_rows));
+ } else {
+ VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
+ summary.termination_type =
+ LAPACK::SolveInPlaceUsingCholesky(num_rows,
+ m->values(),
+ solution,
+ &summary.message);
+ }
+
+ return summary;
+}
+
+SparseSchurComplementSolver::SparseSchurComplementSolver(
+ const LinearSolver::Options& options)
+ : SchurComplementSolver(options),
+ factor_(NULL),
+ cxsparse_factor_(NULL) {
+}
+
+SparseSchurComplementSolver::~SparseSchurComplementSolver() {
+ if (factor_ != NULL) {
+ ss_.Free(factor_);
+ factor_ = NULL;
+ }
+
+ if (cxsparse_factor_ != NULL) {
+ cxsparse_.Free(cxsparse_factor_);
+ cxsparse_factor_ = NULL;
+ }
+}
+
+// Determine the non-zero blocks in the Schur Complement matrix, and
+// initialize a BlockRandomAccessSparseMatrix object.
+void SparseSchurComplementSolver::InitStorage(
+ const CompressedRowBlockStructure* bs) {
+ const int num_eliminate_blocks = options().elimination_groups[0];
+ const int num_col_blocks = bs->cols.size();
+ const int num_row_blocks = bs->rows.size();
+
+ blocks_.resize(num_col_blocks - num_eliminate_blocks, 0);
+ for (int i = num_eliminate_blocks; i < num_col_blocks; ++i) {
+ blocks_[i - num_eliminate_blocks] = bs->cols[i].size;
+ }
+
+ set<pair<int, int> > block_pairs;
+ for (int i = 0; i < blocks_.size(); ++i) {
+ block_pairs.insert(make_pair(i, i));
+ }
+
+ int r = 0;
+ while (r < num_row_blocks) {
+ int e_block_id = bs->rows[r].cells.front().block_id;
+ if (e_block_id >= num_eliminate_blocks) {
+ break;
+ }
+ vector<int> f_blocks;
+
+ // Add to the chunk until the first block in the row is
+ // different than the one in the first row for the chunk.
+ for (; r < num_row_blocks; ++r) {
+ const CompressedRow& row = bs->rows[r];
+ if (row.cells.front().block_id != e_block_id) {
+ break;
+ }
+
+ // Iterate over the blocks in the row, ignoring the first
+ // block since it is the one to be eliminated.
+ for (int c = 1; c < row.cells.size(); ++c) {
+ const Cell& cell = row.cells[c];
+ f_blocks.push_back(cell.block_id - num_eliminate_blocks);
+ }
+ }
+
+ sort(f_blocks.begin(), f_blocks.end());
+ f_blocks.erase(unique(f_blocks.begin(), f_blocks.end()), f_blocks.end());
+ for (int i = 0; i < f_blocks.size(); ++i) {
+ for (int j = i + 1; j < f_blocks.size(); ++j) {
+ block_pairs.insert(make_pair(f_blocks[i], f_blocks[j]));
+ }
+ }
+ }
+
+ // Remaing rows do not contribute to the chunks and directly go
+ // into the schur complement via an outer product.
+ for (; r < num_row_blocks; ++r) {
+ const CompressedRow& row = bs->rows[r];
+ CHECK_GE(row.cells.front().block_id, num_eliminate_blocks);
+ for (int i = 0; i < row.cells.size(); ++i) {
+ int r_block1_id = row.cells[i].block_id - num_eliminate_blocks;
+ for (int j = 0; j < row.cells.size(); ++j) {
+ int r_block2_id = row.cells[j].block_id - num_eliminate_blocks;
+ if (r_block1_id <= r_block2_id) {
+ block_pairs.insert(make_pair(r_block1_id, r_block2_id));
+ }
+ }
+ }
+ }
+
+ set_lhs(new BlockRandomAccessSparseMatrix(blocks_, block_pairs));
+ set_rhs(new double[lhs()->num_rows()]);
+}
+
+LinearSolver::Summary
+SparseSchurComplementSolver::SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) {
+ if (options().type == ITERATIVE_SCHUR) {
+ CHECK(options().use_explicit_schur_complement);
+ return SolveReducedLinearSystemUsingConjugateGradients(per_solve_options,
+ solution);
+ }
+
+ switch (options().sparse_linear_algebra_library_type) {
+ case SUITE_SPARSE:
+ return SolveReducedLinearSystemUsingSuiteSparse(per_solve_options,
+ solution);
+ case CX_SPARSE:
+ return SolveReducedLinearSystemUsingCXSparse(per_solve_options,
+ solution);
+ case EIGEN_SPARSE:
+ return SolveReducedLinearSystemUsingEigen(per_solve_options,
+ solution);
+ default:
+ LOG(FATAL) << "Unknown sparse linear algebra library : "
+ << options().sparse_linear_algebra_library_type;
+ }
+
+ return LinearSolver::Summary();
+}
+
+// Solve the system Sx = r, assuming that the matrix S is stored in a
+// BlockRandomAccessSparseMatrix. The linear system is solved using
+// CHOLMOD's sparse cholesky factorization routines.
+LinearSolver::Summary
+SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) {
+#ifdef CERES_NO_SUITESPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message = "Ceres was not built with SuiteSparse support. "
+ "Therefore, SPARSE_SCHUR cannot be used with SUITE_SPARSE";
+ return summary;
+
+#else
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ TripletSparseMatrix* tsm =
+ const_cast<TripletSparseMatrix*>(
+ down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
+ const int num_rows = tsm->num_rows();
+
+ // The case where there are no f blocks, and the system is block
+ // diagonal.
+ if (num_rows == 0) {
+ return summary;
+ }
+
+ summary.num_iterations = 1;
+ cholmod_sparse* cholmod_lhs = NULL;
+ if (options().use_postordering) {
+ // If we are going to do a full symbolic analysis of the schur
+ // complement matrix from scratch and not rely on the
+ // pre-ordering, then the fastest path in cholmod_factorize is the
+ // one corresponding to upper triangular matrices.
+
+ // Create a upper triangular symmetric matrix.
+ cholmod_lhs = ss_.CreateSparseMatrix(tsm);
+ cholmod_lhs->stype = 1;
+
+ if (factor_ == NULL) {
+ factor_ = ss_.BlockAnalyzeCholesky(cholmod_lhs,
+ blocks_,
+ blocks_,
+ &summary.message);
+ }
+ } else {
+ // If we are going to use the natural ordering (i.e. rely on the
+ // pre-ordering computed by solver_impl.cc), then the fastest
+ // path in cholmod_factorize is the one corresponding to lower
+ // triangular matrices.
+
+ // Create a upper triangular symmetric matrix.
+ cholmod_lhs = ss_.CreateSparseMatrixTranspose(tsm);
+ cholmod_lhs->stype = -1;
+
+ if (factor_ == NULL) {
+ factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(cholmod_lhs,
+ &summary.message);
+ }
+ }
+
+ if (factor_ == NULL) {
+ ss_.Free(cholmod_lhs);
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ // No need to set message as it has already been set by the
+ // symbolic analysis routines above.
+ return summary;
+ }
+
+ summary.termination_type =
+ ss_.Cholesky(cholmod_lhs, factor_, &summary.message);
+
+ ss_.Free(cholmod_lhs);
+
+ if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
+ // No need to set message as it has already been set by the
+ // numeric factorization routine above.
+ return summary;
+ }
+
+ cholmod_dense* cholmod_rhs =
+ ss_.CreateDenseVector(const_cast<double*>(rhs()), num_rows, num_rows);
+ cholmod_dense* cholmod_solution = ss_.Solve(factor_,
+ cholmod_rhs,
+ &summary.message);
+ ss_.Free(cholmod_rhs);
+
+ if (cholmod_solution == NULL) {
+ summary.message =
+ "SuiteSparse failure. Unable to perform triangular solve.";
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ return summary;
+ }
+
+ VectorRef(solution, num_rows)
+ = VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
+ ss_.Free(cholmod_solution);
+ return summary;
+#endif // CERES_NO_SUITESPARSE
+}
+
+// Solve the system Sx = r, assuming that the matrix S is stored in a
+// BlockRandomAccessSparseMatrix. The linear system is solved using
+// CXSparse's sparse cholesky factorization routines.
+LinearSolver::Summary
+SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) {
+#ifdef CERES_NO_CXSPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message = "Ceres was not built with CXSparse support. "
+ "Therefore, SPARSE_SCHUR cannot be used with CX_SPARSE";
+ return summary;
+
+#else
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ // Extract the TripletSparseMatrix that is used for actually storing S.
+ TripletSparseMatrix* tsm =
+ const_cast<TripletSparseMatrix*>(
+ down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
+ const int num_rows = tsm->num_rows();
+
+ // The case where there are no f blocks, and the system is block
+ // diagonal.
+ if (num_rows == 0) {
+ return summary;
+ }
+
+ cs_di* lhs = CHECK_NOTNULL(cxsparse_.CreateSparseMatrix(tsm));
+ VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
+
+ // Compute symbolic factorization if not available.
+ if (cxsparse_factor_ == NULL) {
+ cxsparse_factor_ = cxsparse_.BlockAnalyzeCholesky(lhs, blocks_, blocks_);
+ }
+
+ if (cxsparse_factor_ == NULL) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "CXSparse failure. Unable to find symbolic factorization.";
+ } else if (!cxsparse_.SolveCholesky(lhs, cxsparse_factor_, solution)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "CXSparse::SolveCholesky failed.";
+ }
+
+ cxsparse_.Free(lhs);
+ return summary;
+#endif // CERES_NO_CXPARSE
+}
+
+// Solve the system Sx = r, assuming that the matrix S is stored in a
+// BlockRandomAccessSparseMatrix. The linear system is solved using
+// Eigen's sparse cholesky factorization routines.
+LinearSolver::Summary
+SparseSchurComplementSolver::SolveReducedLinearSystemUsingEigen(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) {
+#ifndef CERES_USE_EIGEN_SPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_SCHUR cannot be used with EIGEN_SPARSE. "
+ "Ceres was not built with support for "
+ "Eigen's SimplicialLDLT decomposition. "
+ "This requires enabling building with -DEIGENSPARSE=ON.";
+ return summary;
+
+#else
+ EventLogger event_logger("SchurComplementSolver::EigenSolve");
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ // Extract the TripletSparseMatrix that is used for actually storing S.
+ TripletSparseMatrix* tsm =
+ const_cast<TripletSparseMatrix*>(
+ down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
+ const int num_rows = tsm->num_rows();
+
+ // The case where there are no f blocks, and the system is block
+ // diagonal.
+ if (num_rows == 0) {
+ return summary;
+ }
+
+ // This is an upper triangular matrix.
+ CompressedRowSparseMatrix crsm(*tsm);
+ // Map this to a column major, lower triangular matrix.
+ Eigen::MappedSparseMatrix<double, Eigen::ColMajor> eigen_lhs(
+ crsm.num_rows(),
+ crsm.num_rows(),
+ crsm.num_nonzeros(),
+ crsm.mutable_rows(),
+ crsm.mutable_cols(),
+ crsm.mutable_values());
+ event_logger.AddEvent("ToCompressedRowSparseMatrix");
+
+ // Compute symbolic factorization if one does not exist.
+ if (simplicial_ldlt_.get() == NULL) {
+ simplicial_ldlt_.reset(new SimplicialLDLT);
+ // This ordering is quite bad. The scalar ordering produced by the
+ // AMD algorithm is quite bad and can be an order of magnitude
+ // worse than the one computed using the block version of the
+ // algorithm.
+ simplicial_ldlt_->analyzePattern(eigen_lhs);
+ event_logger.AddEvent("Analysis");
+ if (simplicial_ldlt_->info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "Eigen failure. Unable to find symbolic factorization.";
+ return summary;
+ }
+ }
+
+ simplicial_ldlt_->factorize(eigen_lhs);
+ event_logger.AddEvent("Factorize");
+ if (simplicial_ldlt_->info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen failure. Unable to find numeric factoriztion.";
+ return summary;
+ }
+
+ VectorRef(solution, num_rows) =
+ simplicial_ldlt_->solve(ConstVectorRef(rhs(), num_rows));
+ event_logger.AddEvent("Solve");
+ if (simplicial_ldlt_->info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen failure. Unable to do triangular solve.";
+ }
+
+ return summary;
+#endif // CERES_USE_EIGEN_SPARSE
+}
+
+LinearSolver::Summary
+SparseSchurComplementSolver::SolveReducedLinearSystemUsingConjugateGradients(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) {
+ const int num_rows = lhs()->num_rows();
+ // The case where there are no f blocks, and the system is block
+ // diagonal.
+ if (num_rows == 0) {
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+ return summary;
+ }
+
+ // Only SCHUR_JACOBI is supported over here right now.
+ CHECK_EQ(options().preconditioner_type, SCHUR_JACOBI);
+
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(new BlockRandomAccessDiagonalMatrix(blocks_));
+ }
+
+ BlockRandomAccessSparseMatrix* sc =
+ down_cast<BlockRandomAccessSparseMatrix*>(
+ const_cast<BlockRandomAccessMatrix*>(lhs()));
+
+ // Extract block diagonal from the Schur complement to construct the
+ // schur_jacobi preconditioner.
+ for (int i = 0; i < blocks_.size(); ++i) {
+ const int block_size = blocks_[i];
+
+ int sc_r, sc_c, sc_row_stride, sc_col_stride;
+ CellInfo* sc_cell_info =
+ CHECK_NOTNULL(sc->GetCell(i, i,
+ &sc_r, &sc_c,
+ &sc_row_stride, &sc_col_stride));
+ MatrixRef sc_m(sc_cell_info->values, sc_row_stride, sc_col_stride);
+
+ int pre_r, pre_c, pre_row_stride, pre_col_stride;
+ CellInfo* pre_cell_info = CHECK_NOTNULL(
+ preconditioner_->GetCell(i, i,
+ &pre_r, &pre_c,
+ &pre_row_stride, &pre_col_stride));
+ MatrixRef pre_m(pre_cell_info->values, pre_row_stride, pre_col_stride);
+
+ pre_m.block(pre_r, pre_c, block_size, block_size) =
+ sc_m.block(sc_r, sc_c, block_size, block_size);
+ }
+ preconditioner_->Invert();
+
+ VectorRef(solution, num_rows).setZero();
+
+ scoped_ptr<LinearOperator> lhs_adapter(
+ new BlockRandomAccessSparseMatrixAdapter(*sc));
+ scoped_ptr<LinearOperator> preconditioner_adapter(
+ new BlockRandomAccessDiagonalMatrixAdapter(*preconditioner_));
+
+
+ LinearSolver::Options cg_options;
+ cg_options.min_num_iterations = options().min_num_iterations;
+ cg_options.max_num_iterations = options().max_num_iterations;
+ ConjugateGradientsSolver cg_solver(cg_options);
+
+ LinearSolver::PerSolveOptions cg_per_solve_options;
+ cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
+ cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
+ cg_per_solve_options.preconditioner = preconditioner_adapter.get();
+
+ return cg_solver.Solve(lhs_adapter.get(),
+ rhs(),
+ cg_per_solve_options,
+ solution);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/schur_complement_solver.h b/extern/ceres/internal/ceres/schur_complement_solver.h
new file mode 100644
index 00000000000..714dafc5b0c
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_complement_solver.h
@@ -0,0 +1,226 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
+#define CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
+
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "ceres/internal/port.h"
+
+#include "ceres/block_random_access_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/cxsparse.h"
+#include "ceres/linear_solver.h"
+#include "ceres/schur_eliminator.h"
+#include "ceres/suitesparse.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "ceres/block_random_access_diagonal_matrix.h"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/SparseCholesky"
+#include "Eigen/OrderingMethods"
+#endif
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrix;
+
+// Base class for Schur complement based linear least squares
+// solvers. It assumes that the input linear system Ax = b can be
+// partitioned into
+//
+// E y + F z = b
+//
+// Where x = [y;z] is a partition of the variables. The paritioning
+// of the variables is such that, E'E is a block diagonal
+// matrix. Further, the rows of A are ordered so that for every
+// variable block in y, all the rows containing that variable block
+// occur as a vertically contiguous block. i.e the matrix A looks like
+//
+// E F
+// A = [ y1 0 0 0 | z1 0 0 0 z5]
+// [ y1 0 0 0 | z1 z2 0 0 0]
+// [ 0 y2 0 0 | 0 0 z3 0 0]
+// [ 0 0 y3 0 | z1 z2 z3 z4 z5]
+// [ 0 0 y3 0 | z1 0 0 0 z5]
+// [ 0 0 0 y4 | 0 0 0 0 z5]
+// [ 0 0 0 y4 | 0 z2 0 0 0]
+// [ 0 0 0 y4 | 0 0 0 0 0]
+// [ 0 0 0 0 | z1 0 0 0 0]
+// [ 0 0 0 0 | 0 0 z3 z4 z5]
+//
+// This structure should be reflected in the corresponding
+// CompressedRowBlockStructure object associated with A. The linear
+// system Ax = b should either be well posed or the array D below
+// should be non-null and the diagonal matrix corresponding to it
+// should be non-singular.
+//
+// SchurComplementSolver has two sub-classes.
+//
+// DenseSchurComplementSolver: For problems where the Schur complement
+// matrix is small and dense, or if CHOLMOD/SuiteSparse is not
+// installed. For structure from motion problems, this is solver can
+// be used for problems with upto a few hundred cameras.
+//
+// SparseSchurComplementSolver: For problems where the Schur
+// complement matrix is large and sparse. It requires that
+// CHOLMOD/SuiteSparse be installed, as it uses CHOLMOD to find a
+// sparse Cholesky factorization of the Schur complement. This solver
+// can be used for solving structure from motion problems with tens of
+// thousands of cameras, though depending on the exact sparsity
+// structure, it maybe better to use an iterative solver.
+//
+// The two solvers can be instantiated by calling
+// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
+// set to DENSE_SCHUR and SPARSE_SCHUR
+// respectively. LinearSolver::Options::elimination_groups[0] should be
+// at least 1.
+class SchurComplementSolver : public BlockSparseMatrixSolver {
+ public:
+ explicit SchurComplementSolver(const LinearSolver::Options& options)
+ : options_(options) {
+ CHECK_GT(options.elimination_groups.size(), 1);
+ CHECK_GT(options.elimination_groups[0], 0);
+ }
+
+ // LinearSolver methods
+ virtual ~SchurComplementSolver() {}
+ virtual LinearSolver::Summary SolveImpl(
+ BlockSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
+
+ protected:
+ const LinearSolver::Options& options() const { return options_; }
+
+ const BlockRandomAccessMatrix* lhs() const { return lhs_.get(); }
+ void set_lhs(BlockRandomAccessMatrix* lhs) { lhs_.reset(lhs); }
+ const double* rhs() const { return rhs_.get(); }
+ void set_rhs(double* rhs) { rhs_.reset(rhs); }
+
+ private:
+ virtual void InitStorage(const CompressedRowBlockStructure* bs) = 0;
+ virtual LinearSolver::Summary SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution) = 0;
+
+ LinearSolver::Options options_;
+
+ scoped_ptr<SchurEliminatorBase> eliminator_;
+ scoped_ptr<BlockRandomAccessMatrix> lhs_;
+ scoped_array<double> rhs_;
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(SchurComplementSolver);
+};
+
+// Dense Cholesky factorization based solver.
+class DenseSchurComplementSolver : public SchurComplementSolver {
+ public:
+ explicit DenseSchurComplementSolver(const LinearSolver::Options& options)
+ : SchurComplementSolver(options) {}
+ virtual ~DenseSchurComplementSolver() {}
+
+ private:
+ virtual void InitStorage(const CompressedRowBlockStructure* bs);
+ virtual LinearSolver::Summary SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution);
+
+ CERES_DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver);
+};
+
+// Sparse Cholesky factorization based solver.
+class SparseSchurComplementSolver : public SchurComplementSolver {
+ public:
+ explicit SparseSchurComplementSolver(const LinearSolver::Options& options);
+ virtual ~SparseSchurComplementSolver();
+
+ private:
+ virtual void InitStorage(const CompressedRowBlockStructure* bs);
+ virtual LinearSolver::Summary SolveReducedLinearSystem(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution);
+ LinearSolver::Summary SolveReducedLinearSystemUsingSuiteSparse(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution);
+ LinearSolver::Summary SolveReducedLinearSystemUsingCXSparse(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution);
+ LinearSolver::Summary SolveReducedLinearSystemUsingEigen(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution);
+ LinearSolver::Summary SolveReducedLinearSystemUsingConjugateGradients(
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* solution);
+
+ // Size of the blocks in the Schur complement.
+ std::vector<int> blocks_;
+
+ SuiteSparse ss_;
+ // Symbolic factorization of the reduced linear system. Precomputed
+ // once and reused in subsequent calls.
+ cholmod_factor* factor_;
+
+ CXSparse cxsparse_;
+ // Cached factorization
+ cs_dis* cxsparse_factor_;
+
+#ifdef CERES_USE_EIGEN_SPARSE
+
+ // The preprocessor gymnastics here are dealing with the fact that
+ // before version 3.2.2, Eigen did not support a third template
+ // parameter to specify the ordering.
+#if EIGEN_VERSION_AT_LEAST(3,2,2)
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower,
+ Eigen::NaturalOrdering<int> >
+ SimplicialLDLT;
+#else
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower>
+ SimplicialLDLT;
+#endif
+
+ scoped_ptr<SimplicialLDLT> simplicial_ldlt_;
+#endif
+
+ scoped_ptr<BlockRandomAccessDiagonalMatrix> preconditioner_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/schur_eliminator.cc b/extern/ceres/internal/ceres/schur_eliminator.cc
new file mode 100644
index 00000000000..ec0e2a020e5
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_eliminator.cc
@@ -0,0 +1,163 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Template specialization of SchurEliminator.
+//
+// ========================================
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+//=========================================
+//
+// This file is generated using generate_eliminator_specialization.py.
+// Editing it manually is not recommended.
+
+#include "ceres/linear_solver.h"
+#include "ceres/schur_eliminator.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres {
+namespace internal {
+
+SchurEliminatorBase*
+SchurEliminatorBase::Create(const LinearSolver::Options& options) {
+#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 2)) {
+ return new SchurEliminator<2, 2, 2>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<2, 2, 3>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<2, 2, 4>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 2) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new SchurEliminator<2, 2, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<2, 3, 3>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<2, 3, 4>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 6)) {
+ return new SchurEliminator<2, 3, 6>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == 9)) {
+ return new SchurEliminator<2, 3, 9>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 3) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new SchurEliminator<2, 3, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<2, 4, 3>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<2, 4, 4>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 8)) {
+ return new SchurEliminator<2, 4, 8>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 9)) {
+ return new SchurEliminator<2, 4, 9>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new SchurEliminator<2, 4, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 2) &&
+ (options.e_block_size == Eigen::Dynamic) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 2)) {
+ return new SchurEliminator<4, 4, 2>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 3)) {
+ return new SchurEliminator<4, 4, 3>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == 4)) {
+ return new SchurEliminator<4, 4, 4>(options);
+ }
+ if ((options.row_block_size == 4) &&
+ (options.e_block_size == 4) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new SchurEliminator<4, 4, Eigen::Dynamic>(options);
+ }
+ if ((options.row_block_size == Eigen::Dynamic) &&
+ (options.e_block_size == Eigen::Dynamic) &&
+ (options.f_block_size == Eigen::Dynamic)) {
+ return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
+ }
+
+#endif
+ VLOG(1) << "Template specializations not found for <"
+ << options.row_block_size << ","
+ << options.e_block_size << ","
+ << options.f_block_size << ">";
+ return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/schur_eliminator.h b/extern/ceres/internal/ceres/schur_eliminator.h
new file mode 100644
index 00000000000..761b58adc7f
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_eliminator.h
@@ -0,0 +1,355 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_SCHUR_ELIMINATOR_H_
+#define CERES_INTERNAL_SCHUR_ELIMINATOR_H_
+
+#include <map>
+#include <vector>
+#include "ceres/mutex.h"
+#include "ceres/block_random_access_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/linear_solver.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+namespace internal {
+
+// Classes implementing the SchurEliminatorBase interface implement
+// variable elimination for linear least squares problems. Assuming
+// that the input linear system Ax = b can be partitioned into
+//
+// E y + F z = b
+//
+// Where x = [y;z] is a partition of the variables. The paritioning
+// of the variables is such that, E'E is a block diagonal matrix. Or
+// in other words, the parameter blocks in E form an independent set
+// of the of the graph implied by the block matrix A'A. Then, this
+// class provides the functionality to compute the Schur complement
+// system
+//
+// S z = r
+//
+// where
+//
+// S = F'F - F'E (E'E)^{-1} E'F and r = F'b - F'E(E'E)^(-1) E'b
+//
+// This is the Eliminate operation, i.e., construct the linear system
+// obtained by eliminating the variables in E.
+//
+// The eliminator also provides the reverse functionality, i.e. given
+// values for z it can back substitute for the values of y, by solving the
+// linear system
+//
+// Ey = b - F z
+//
+// which is done by observing that
+//
+// y = (E'E)^(-1) [E'b - E'F z]
+//
+// The eliminator has a number of requirements.
+//
+// The rows of A are ordered so that for every variable block in y,
+// all the rows containing that variable block occur as a vertically
+// contiguous block. i.e the matrix A looks like
+//
+// E F chunk
+// A = [ y1 0 0 0 | z1 0 0 0 z5] 1
+// [ y1 0 0 0 | z1 z2 0 0 0] 1
+// [ 0 y2 0 0 | 0 0 z3 0 0] 2
+// [ 0 0 y3 0 | z1 z2 z3 z4 z5] 3
+// [ 0 0 y3 0 | z1 0 0 0 z5] 3
+// [ 0 0 0 y4 | 0 0 0 0 z5] 4
+// [ 0 0 0 y4 | 0 z2 0 0 0] 4
+// [ 0 0 0 y4 | 0 0 0 0 0] 4
+// [ 0 0 0 0 | z1 0 0 0 0] non chunk blocks
+// [ 0 0 0 0 | 0 0 z3 z4 z5] non chunk blocks
+//
+// This structure should be reflected in the corresponding
+// CompressedRowBlockStructure object associated with A. The linear
+// system Ax = b should either be well posed or the array D below
+// should be non-null and the diagonal matrix corresponding to it
+// should be non-singular. For simplicity of exposition only the case
+// with a null D is described.
+//
+// The usual way to do the elimination is as follows. Starting with
+//
+// E y + F z = b
+//
+// we can form the normal equations,
+//
+// E'E y + E'F z = E'b
+// F'E y + F'F z = F'b
+//
+// multiplying both sides of the first equation by (E'E)^(-1) and then
+// by F'E we get
+//
+// F'E y + F'E (E'E)^(-1) E'F z = F'E (E'E)^(-1) E'b
+// F'E y + F'F z = F'b
+//
+// now subtracting the two equations we get
+//
+// [FF' - F'E (E'E)^(-1) E'F] z = F'b - F'E(E'E)^(-1) E'b
+//
+// Instead of forming the normal equations and operating on them as
+// general sparse matrices, the algorithm here deals with one
+// parameter block in y at a time. The rows corresponding to a single
+// parameter block yi are known as a chunk, and the algorithm operates
+// on one chunk at a time. The mathematics remains the same since the
+// reduced linear system can be shown to be the sum of the reduced
+// linear systems for each chunk. This can be seen by observing two
+// things.
+//
+// 1. E'E is a block diagonal matrix.
+//
+// 2. When E'F is computed, only the terms within a single chunk
+// interact, i.e for y1 column blocks when transposed and multiplied
+// with F, the only non-zero contribution comes from the blocks in
+// chunk1.
+//
+// Thus, the reduced linear system
+//
+// FF' - F'E (E'E)^(-1) E'F
+//
+// can be re-written as
+//
+// sum_k F_k F_k' - F_k'E_k (E_k'E_k)^(-1) E_k' F_k
+//
+// Where the sum is over chunks and E_k'E_k is dense matrix of size y1
+// x y1.
+//
+// Advanced usage. Uptil now it has been assumed that the user would
+// be interested in all of the Schur Complement S. However, it is also
+// possible to use this eliminator to obtain an arbitrary submatrix of
+// the full Schur complement. When the eliminator is generating the
+// blocks of S, it asks the RandomAccessBlockMatrix instance passed to
+// it if it has storage for that block. If it does, the eliminator
+// computes/updates it, if not it is skipped. This is useful when one
+// is interested in constructing a preconditioner based on the Schur
+// Complement, e.g., computing the block diagonal of S so that it can
+// be used as a preconditioner for an Iterative Substructuring based
+// solver [See Agarwal et al, Bundle Adjustment in the Large, ECCV
+// 2008 for an example of such use].
+//
+// Example usage: Please see schur_complement_solver.cc
+class SchurEliminatorBase {
+ public:
+ virtual ~SchurEliminatorBase() {}
+
+ // Initialize the eliminator. It is the user's responsibilty to call
+ // this function before calling Eliminate or BackSubstitute. It is
+ // also the caller's responsibilty to ensure that the
+ // CompressedRowBlockStructure object passed to this method is the
+ // same one (or is equivalent to) the one associated with the
+ // BlockSparseMatrix objects below.
+ virtual void Init(int num_eliminate_blocks,
+ const CompressedRowBlockStructure* bs) = 0;
+
+ // Compute the Schur complement system from the augmented linear
+ // least squares problem [A;D] x = [b;0]. The left hand side and the
+ // right hand side of the reduced linear system are returned in lhs
+ // and rhs respectively.
+ //
+ // It is the caller's responsibility to construct and initialize
+ // lhs. Depending upon the structure of the lhs object passed here,
+ // the full or a submatrix of the Schur complement will be computed.
+ //
+ // Since the Schur complement is a symmetric matrix, only the upper
+ // triangular part of the Schur complement is computed.
+ virtual void Eliminate(const BlockSparseMatrix* A,
+ const double* b,
+ const double* D,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs) = 0;
+
+ // Given values for the variables z in the F block of A, solve for
+ // the optimal values of the variables y corresponding to the E
+ // block in A.
+ virtual void BackSubstitute(const BlockSparseMatrix* A,
+ const double* b,
+ const double* D,
+ const double* z,
+ double* y) = 0;
+ // Factory
+ static SchurEliminatorBase* Create(const LinearSolver::Options& options);
+};
+
+// Templated implementation of the SchurEliminatorBase interface. The
+// templating is on the sizes of the row, e and f blocks sizes in the
+// input matrix. In many problems, the sizes of one or more of these
+// blocks are constant, in that case, its worth passing these
+// parameters as template arguments so that they are visible to the
+// compiler and can be used for compile time optimization of the low
+// level linear algebra routines.
+//
+// This implementation is mulithreaded using OpenMP. The level of
+// parallelism is controlled by LinearSolver::Options::num_threads.
+template <int kRowBlockSize = Eigen::Dynamic,
+ int kEBlockSize = Eigen::Dynamic,
+ int kFBlockSize = Eigen::Dynamic >
+class SchurEliminator : public SchurEliminatorBase {
+ public:
+ explicit SchurEliminator(const LinearSolver::Options& options)
+ : num_threads_(options.num_threads) {
+ }
+
+ // SchurEliminatorBase Interface
+ virtual ~SchurEliminator();
+ virtual void Init(int num_eliminate_blocks,
+ const CompressedRowBlockStructure* bs);
+ virtual void Eliminate(const BlockSparseMatrix* A,
+ const double* b,
+ const double* D,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs);
+ virtual void BackSubstitute(const BlockSparseMatrix* A,
+ const double* b,
+ const double* D,
+ const double* z,
+ double* y);
+
+ private:
+ // Chunk objects store combinatorial information needed to
+ // efficiently eliminate a whole chunk out of the least squares
+ // problem. Consider the first chunk in the example matrix above.
+ //
+ // [ y1 0 0 0 | z1 0 0 0 z5]
+ // [ y1 0 0 0 | z1 z2 0 0 0]
+ //
+ // One of the intermediate quantities that needs to be calculated is
+ // for each row the product of the y block transposed with the
+ // non-zero z block, and the sum of these blocks across rows. A
+ // temporary array "buffer_" is used for computing and storing them
+ // and the buffer_layout maps the indices of the z-blocks to
+ // position in the buffer_ array. The size of the chunk is the
+ // number of row blocks/residual blocks for the particular y block
+ // being considered.
+ //
+ // For the example chunk shown above,
+ //
+ // size = 2
+ //
+ // The entries of buffer_layout will be filled in the following order.
+ //
+ // buffer_layout[z1] = 0
+ // buffer_layout[z5] = y1 * z1
+ // buffer_layout[z2] = y1 * z1 + y1 * z5
+ typedef std::map<int, int> BufferLayoutType;
+ struct Chunk {
+ Chunk() : size(0) {}
+ int size;
+ int start;
+ BufferLayoutType buffer_layout;
+ };
+
+ void ChunkDiagonalBlockAndGradient(
+ const Chunk& chunk,
+ const BlockSparseMatrix* A,
+ const double* b,
+ int row_block_counter,
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix* eet,
+ double* g,
+ double* buffer,
+ BlockRandomAccessMatrix* lhs);
+
+ void UpdateRhs(const Chunk& chunk,
+ const BlockSparseMatrix* A,
+ const double* b,
+ int row_block_counter,
+ const double* inverse_ete_g,
+ double* rhs);
+
+ void ChunkOuterProduct(const CompressedRowBlockStructure* bs,
+ const Matrix& inverse_eet,
+ const double* buffer,
+ const BufferLayoutType& buffer_layout,
+ BlockRandomAccessMatrix* lhs);
+ void EBlockRowOuterProduct(const BlockSparseMatrix* A,
+ int row_block_index,
+ BlockRandomAccessMatrix* lhs);
+
+
+ void NoEBlockRowsUpdate(const BlockSparseMatrix* A,
+ const double* b,
+ int row_block_counter,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs);
+
+ void NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
+ int row_block_index,
+ BlockRandomAccessMatrix* lhs);
+
+ int num_eliminate_blocks_;
+
+ // Block layout of the columns of the reduced linear system. Since
+ // the f blocks can be of varying size, this vector stores the
+ // position of each f block in the row/col of the reduced linear
+ // system. Thus lhs_row_layout_[i] is the row/col position of the
+ // i^th f block.
+ std::vector<int> lhs_row_layout_;
+
+ // Combinatorial structure of the chunks in A. For more information
+ // see the documentation of the Chunk object above.
+ std::vector<Chunk> chunks_;
+
+ // TODO(sameeragarwal): The following two arrays contain per-thread
+ // storage. They should be refactored into a per thread struct.
+
+ // Buffer to store the products of the y and z blocks generated
+ // during the elimination phase. buffer_ is of size num_threads *
+ // buffer_size_. Each thread accesses the chunk
+ //
+ // [thread_id * buffer_size_ , (thread_id + 1) * buffer_size_]
+ //
+ scoped_array<double> buffer_;
+
+ // Buffer to store per thread matrix matrix products used by
+ // ChunkOuterProduct. Like buffer_ it is of size num_threads *
+ // buffer_size_. Each thread accesses the chunk
+ //
+ // [thread_id * buffer_size_ , (thread_id + 1) * buffer_size_ -1]
+ //
+ scoped_array<double> chunk_outer_product_buffer_;
+
+ int buffer_size_;
+ int num_threads_;
+ int uneliminated_row_begins_;
+
+ // Locks for the blocks in the right hand side of the reduced linear
+ // system.
+ std::vector<Mutex*> rhs_locks_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCHUR_ELIMINATOR_H_
diff --git a/extern/ceres/internal/ceres/schur_eliminator_impl.h b/extern/ceres/internal/ceres/schur_eliminator_impl.h
new file mode 100644
index 00000000000..f2535880f15
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_eliminator_impl.h
@@ -0,0 +1,698 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// TODO(sameeragarwal): row_block_counter can perhaps be replaced by
+// Chunk::start ?
+
+#ifndef CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
+#define CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
+
+// Eigen has an internal threshold switching between different matrix
+// multiplication algorithms. In particular for matrices larger than
+// EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD it uses a cache friendly
+// matrix matrix product algorithm that has a higher setup cost. For
+// matrix sizes close to this threshold, especially when the matrices
+// are thin and long, the default choice may not be optimal. This is
+// the case for us, as the default choice causes a 30% performance
+// regression when we moved from Eigen2 to Eigen3.
+
+#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 10
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#endif
+
+#include <algorithm>
+#include <map>
+#include "ceres/block_random_access_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/map_util.h"
+#include "ceres/schur_eliminator.h"
+#include "ceres/small_blas.h"
+#include "ceres/stl_util.h"
+#include "Eigen/Dense"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::~SchurEliminator() {
+ STLDeleteElements(&rhs_locks_);
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+Init(int num_eliminate_blocks, const CompressedRowBlockStructure* bs) {
+ CHECK_GT(num_eliminate_blocks, 0)
+ << "SchurComplementSolver cannot be initialized with "
+ << "num_eliminate_blocks = 0.";
+
+ num_eliminate_blocks_ = num_eliminate_blocks;
+
+ const int num_col_blocks = bs->cols.size();
+ const int num_row_blocks = bs->rows.size();
+
+ buffer_size_ = 1;
+ chunks_.clear();
+ lhs_row_layout_.clear();
+
+ int lhs_num_rows = 0;
+ // Add a map object for each block in the reduced linear system
+ // and build the row/column block structure of the reduced linear
+ // system.
+ lhs_row_layout_.resize(num_col_blocks - num_eliminate_blocks_);
+ for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {
+ lhs_row_layout_[i - num_eliminate_blocks_] = lhs_num_rows;
+ lhs_num_rows += bs->cols[i].size;
+ }
+
+ int r = 0;
+ // Iterate over the row blocks of A, and detect the chunks. The
+ // matrix should already have been ordered so that all rows
+ // containing the same y block are vertically contiguous. Along
+ // the way also compute the amount of space each chunk will need
+ // to perform the elimination.
+ while (r < num_row_blocks) {
+ const int chunk_block_id = bs->rows[r].cells.front().block_id;
+ if (chunk_block_id >= num_eliminate_blocks_) {
+ break;
+ }
+
+ chunks_.push_back(Chunk());
+ Chunk& chunk = chunks_.back();
+ chunk.size = 0;
+ chunk.start = r;
+ int buffer_size = 0;
+ const int e_block_size = bs->cols[chunk_block_id].size;
+
+ // Add to the chunk until the first block in the row is
+ // different than the one in the first row for the chunk.
+ while (r + chunk.size < num_row_blocks) {
+ const CompressedRow& row = bs->rows[r + chunk.size];
+ if (row.cells.front().block_id != chunk_block_id) {
+ break;
+ }
+
+ // Iterate over the blocks in the row, ignoring the first
+ // block since it is the one to be eliminated.
+ for (int c = 1; c < row.cells.size(); ++c) {
+ const Cell& cell = row.cells[c];
+ if (InsertIfNotPresent(
+ &(chunk.buffer_layout), cell.block_id, buffer_size)) {
+ buffer_size += e_block_size * bs->cols[cell.block_id].size;
+ }
+ }
+
+ buffer_size_ = std::max(buffer_size, buffer_size_);
+ ++chunk.size;
+ }
+
+ CHECK_GT(chunk.size, 0);
+ r += chunk.size;
+ }
+ const Chunk& chunk = chunks_.back();
+
+ uneliminated_row_begins_ = chunk.start + chunk.size;
+ if (num_threads_ > 1) {
+ random_shuffle(chunks_.begin(), chunks_.end());
+ }
+
+ buffer_.reset(new double[buffer_size_ * num_threads_]);
+
+ // chunk_outer_product_buffer_ only needs to store e_block_size *
+ // f_block_size, which is always less than buffer_size_, so we just
+ // allocate buffer_size_ per thread.
+ chunk_outer_product_buffer_.reset(new double[buffer_size_ * num_threads_]);
+
+ STLDeleteElements(&rhs_locks_);
+ rhs_locks_.resize(num_col_blocks - num_eliminate_blocks_);
+ for (int i = 0; i < num_col_blocks - num_eliminate_blocks_; ++i) {
+ rhs_locks_[i] = new Mutex;
+ }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+Eliminate(const BlockSparseMatrix* A,
+ const double* b,
+ const double* D,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs) {
+ if (lhs->num_rows() > 0) {
+ lhs->SetZero();
+ VectorRef(rhs, lhs->num_rows()).setZero();
+ }
+
+ const CompressedRowBlockStructure* bs = A->block_structure();
+ const int num_col_blocks = bs->cols.size();
+
+ // Add the diagonal to the schur complement.
+ if (D != NULL) {
+#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
+ for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {
+ const int block_id = i - num_eliminate_blocks_;
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block_id, block_id,
+ &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ const int block_size = bs->cols[i].size;
+ typename EigenTypes<Eigen::Dynamic>::ConstVectorRef
+ diag(D + bs->cols[i].position, block_size);
+
+ CeresMutexLock l(&cell_info->m);
+ MatrixRef m(cell_info->values, row_stride, col_stride);
+ m.block(r, c, block_size, block_size).diagonal()
+ += diag.array().square().matrix();
+ }
+ }
+ }
+
+ // Eliminate y blocks one chunk at a time. For each chunk, compute
+ // the entries of the normal equations and the gradient vector block
+ // corresponding to the y block and then apply Gaussian elimination
+ // to them. The matrix ete stores the normal matrix corresponding to
+ // the block being eliminated and array buffer_ contains the
+ // non-zero blocks in the row corresponding to this y block in the
+ // normal equations. This computation is done in
+ // ChunkDiagonalBlockAndGradient. UpdateRhs then applies gaussian
+ // elimination to the rhs of the normal equations, updating the rhs
+ // of the reduced linear system by modifying rhs blocks for all the
+ // z blocks that share a row block/residual term with the y
+ // block. EliminateRowOuterProduct does the corresponding operation
+ // for the lhs of the reduced linear system.
+#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
+ for (int i = 0; i < chunks_.size(); ++i) {
+#ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+#else
+ int thread_id = 0;
+#endif
+ double* buffer = buffer_.get() + thread_id * buffer_size_;
+ const Chunk& chunk = chunks_[i];
+ const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
+ const int e_block_size = bs->cols[e_block_id].size;
+
+ VectorRef(buffer, buffer_size_).setZero();
+
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
+ ete(e_block_size, e_block_size);
+
+ if (D != NULL) {
+ const typename EigenTypes<kEBlockSize>::ConstVectorRef
+ diag(D + bs->cols[e_block_id].position, e_block_size);
+ ete = diag.array().square().matrix().asDiagonal();
+ } else {
+ ete.setZero();
+ }
+
+ FixedArray<double, 8> g(e_block_size);
+ typename EigenTypes<kEBlockSize>::VectorRef gref(g.get(), e_block_size);
+ gref.setZero();
+
+ // We are going to be computing
+ //
+ // S += F'F - F'E(E'E)^{-1}E'F
+ //
+ // for each Chunk. The computation is broken down into a number of
+ // function calls as below.
+
+ // Compute the outer product of the e_blocks with themselves (ete
+ // = E'E). Compute the product of the e_blocks with the
+ // corresonding f_blocks (buffer = E'F), the gradient of the terms
+ // in this chunk (g) and add the outer product of the f_blocks to
+ // Schur complement (S += F'F).
+ ChunkDiagonalBlockAndGradient(
+ chunk, A, b, chunk.start, &ete, g.get(), buffer, lhs);
+
+ // Normally one wouldn't compute the inverse explicitly, but
+ // e_block_size will typically be a small number like 3, in
+ // which case its much faster to compute the inverse once and
+ // use it to multiply other matrices/vectors instead of doing a
+ // Solve call over and over again.
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix inverse_ete =
+ ete
+ .template selfadjointView<Eigen::Upper>()
+ .llt()
+ .solve(Matrix::Identity(e_block_size, e_block_size));
+
+ // For the current chunk compute and update the rhs of the reduced
+ // linear system.
+ //
+ // rhs = F'b - F'E(E'E)^(-1) E'b
+
+ FixedArray<double, 8> inverse_ete_g(e_block_size);
+ MatrixVectorMultiply<kEBlockSize, kEBlockSize, 0>(
+ inverse_ete.data(),
+ e_block_size,
+ e_block_size,
+ g.get(),
+ inverse_ete_g.get());
+
+ UpdateRhs(chunk, A, b, chunk.start, inverse_ete_g.get(), rhs);
+
+ // S -= F'E(E'E)^{-1}E'F
+ ChunkOuterProduct(bs, inverse_ete, buffer, chunk.buffer_layout, lhs);
+ }
+
+ // For rows with no e_blocks, the schur complement update reduces to
+ // S += F'F.
+ NoEBlockRowsUpdate(A, b, uneliminated_row_begins_, lhs, rhs);
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+BackSubstitute(const BlockSparseMatrix* A,
+ const double* b,
+ const double* D,
+ const double* z,
+ double* y) {
+ const CompressedRowBlockStructure* bs = A->block_structure();
+#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
+ for (int i = 0; i < chunks_.size(); ++i) {
+ const Chunk& chunk = chunks_[i];
+ const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
+ const int e_block_size = bs->cols[e_block_id].size;
+
+ double* y_ptr = y + bs->cols[e_block_id].position;
+ typename EigenTypes<kEBlockSize>::VectorRef y_block(y_ptr, e_block_size);
+
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
+ ete(e_block_size, e_block_size);
+ if (D != NULL) {
+ const typename EigenTypes<kEBlockSize>::ConstVectorRef
+ diag(D + bs->cols[e_block_id].position, e_block_size);
+ ete = diag.array().square().matrix().asDiagonal();
+ } else {
+ ete.setZero();
+ }
+
+ const double* values = A->values();
+ for (int j = 0; j < chunk.size; ++j) {
+ const CompressedRow& row = bs->rows[chunk.start + j];
+ const Cell& e_cell = row.cells.front();
+ DCHECK_EQ(e_block_id, e_cell.block_id);
+
+ FixedArray<double, 8> sj(row.block.size);
+
+ typename EigenTypes<kRowBlockSize>::VectorRef(sj.get(), row.block.size) =
+ typename EigenTypes<kRowBlockSize>::ConstVectorRef
+ (b + bs->rows[chunk.start + j].block.position, row.block.size);
+
+ for (int c = 1; c < row.cells.size(); ++c) {
+ const int f_block_id = row.cells[c].block_id;
+ const int f_block_size = bs->cols[f_block_id].size;
+ const int r_block = f_block_id - num_eliminate_blocks_;
+
+ MatrixVectorMultiply<kRowBlockSize, kFBlockSize, -1>(
+ values + row.cells[c].position, row.block.size, f_block_size,
+ z + lhs_row_layout_[r_block],
+ sj.get());
+ }
+
+ MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ sj.get(),
+ y_ptr);
+
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ values + e_cell.position, row.block.size, e_block_size,
+ ete.data(), 0, 0, e_block_size, e_block_size);
+ }
+
+ ete.llt().solveInPlace(y_block);
+ }
+}
+
+// Update the rhs of the reduced linear system. Compute
+//
+// F'b - F'E(E'E)^(-1) E'b
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+UpdateRhs(const Chunk& chunk,
+ const BlockSparseMatrix* A,
+ const double* b,
+ int row_block_counter,
+ const double* inverse_ete_g,
+ double* rhs) {
+ const CompressedRowBlockStructure* bs = A->block_structure();
+ const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
+ const int e_block_size = bs->cols[e_block_id].size;
+
+ int b_pos = bs->rows[row_block_counter].block.position;
+ const double* values = A->values();
+ for (int j = 0; j < chunk.size; ++j) {
+ const CompressedRow& row = bs->rows[row_block_counter + j];
+ const Cell& e_cell = row.cells.front();
+
+ typename EigenTypes<kRowBlockSize>::Vector sj =
+ typename EigenTypes<kRowBlockSize>::ConstVectorRef
+ (b + b_pos, row.block.size);
+
+ MatrixVectorMultiply<kRowBlockSize, kEBlockSize, -1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ inverse_ete_g, sj.data());
+
+ for (int c = 1; c < row.cells.size(); ++c) {
+ const int block_id = row.cells[c].block_id;
+ const int block_size = bs->cols[block_id].size;
+ const int block = block_id - num_eliminate_blocks_;
+ CeresMutexLock l(rhs_locks_[block]);
+ MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+ values + row.cells[c].position,
+ row.block.size, block_size,
+ sj.data(), rhs + lhs_row_layout_[block]);
+ }
+ b_pos += row.block.size;
+ }
+}
+
+// Given a Chunk - set of rows with the same e_block, e.g. in the
+// following Chunk with two rows.
+//
+// E F
+// [ y11 0 0 0 | z11 0 0 0 z51]
+// [ y12 0 0 0 | z12 z22 0 0 0]
+//
+// this function computes twp matrices. The diagonal block matrix
+//
+// ete = y11 * y11' + y12 * y12'
+//
+// and the off diagonal blocks in the Guass Newton Hessian.
+//
+// buffer = [y11'(z11 + z12), y12' * z22, y11' * z51]
+//
+// which are zero compressed versions of the block sparse matrices E'E
+// and E'F.
+//
+// and the gradient of the e_block, E'b.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+ChunkDiagonalBlockAndGradient(
+ const Chunk& chunk,
+ const BlockSparseMatrix* A,
+ const double* b,
+ int row_block_counter,
+ typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix* ete,
+ double* g,
+ double* buffer,
+ BlockRandomAccessMatrix* lhs) {
+ const CompressedRowBlockStructure* bs = A->block_structure();
+
+ int b_pos = bs->rows[row_block_counter].block.position;
+ const int e_block_size = ete->rows();
+
+ // Iterate over the rows in this chunk, for each row, compute the
+ // contribution of its F blocks to the Schur complement, the
+ // contribution of its E block to the matrix EE' (ete), and the
+ // corresponding block in the gradient vector.
+ const double* values = A->values();
+ for (int j = 0; j < chunk.size; ++j) {
+ const CompressedRow& row = bs->rows[row_block_counter + j];
+
+ if (row.cells.size() > 1) {
+ EBlockRowOuterProduct(A, row_block_counter + j, lhs);
+ }
+
+ // Extract the e_block, ETE += E_i' E_i
+ const Cell& e_cell = row.cells.front();
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ values + e_cell.position, row.block.size, e_block_size,
+ ete->data(), 0, 0, e_block_size, e_block_size);
+
+ // g += E_i' b_i
+ MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ b + b_pos,
+ g);
+
+
+ // buffer = E'F. This computation is done by iterating over the
+ // f_blocks for each row in the chunk.
+ for (int c = 1; c < row.cells.size(); ++c) {
+ const int f_block_id = row.cells[c].block_id;
+ const int f_block_size = bs->cols[f_block_id].size;
+ double* buffer_ptr =
+ buffer + FindOrDie(chunk.buffer_layout, f_block_id);
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kEBlockSize, kRowBlockSize, kFBlockSize, 1>(
+ values + e_cell.position, row.block.size, e_block_size,
+ values + row.cells[c].position, row.block.size, f_block_size,
+ buffer_ptr, 0, 0, e_block_size, f_block_size);
+ }
+ b_pos += row.block.size;
+ }
+}
+
+// Compute the outer product F'E(E'E)^{-1}E'F and subtract it from the
+// Schur complement matrix, i.e
+//
+// S -= F'E(E'E)^{-1}E'F.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+ChunkOuterProduct(const CompressedRowBlockStructure* bs,
+ const Matrix& inverse_ete,
+ const double* buffer,
+ const BufferLayoutType& buffer_layout,
+ BlockRandomAccessMatrix* lhs) {
+ // This is the most computationally expensive part of this
+ // code. Profiling experiments reveal that the bottleneck is not the
+ // computation of the right-hand matrix product, but memory
+ // references to the left hand side.
+ const int e_block_size = inverse_ete.rows();
+ BufferLayoutType::const_iterator it1 = buffer_layout.begin();
+
+#ifdef CERES_USE_OPENMP
+ int thread_id = omp_get_thread_num();
+#else
+ int thread_id = 0;
+#endif
+ double* b1_transpose_inverse_ete =
+ chunk_outer_product_buffer_.get() + thread_id * buffer_size_;
+
+ // S(i,j) -= bi' * ete^{-1} b_j
+ for (; it1 != buffer_layout.end(); ++it1) {
+ const int block1 = it1->first - num_eliminate_blocks_;
+ const int block1_size = bs->cols[it1->first].size;
+ MatrixTransposeMatrixMultiply
+ <kEBlockSize, kFBlockSize, kEBlockSize, kEBlockSize, 0>(
+ buffer + it1->second, e_block_size, block1_size,
+ inverse_ete.data(), e_block_size, e_block_size,
+ b1_transpose_inverse_ete, 0, 0, block1_size, e_block_size);
+
+ BufferLayoutType::const_iterator it2 = it1;
+ for (; it2 != buffer_layout.end(); ++it2) {
+ const int block2 = it2->first - num_eliminate_blocks_;
+
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block1, block2,
+ &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ const int block2_size = bs->cols[it2->first].size;
+ CeresMutexLock l(&cell_info->m);
+ MatrixMatrixMultiply
+ <kFBlockSize, kEBlockSize, kEBlockSize, kFBlockSize, -1>(
+ b1_transpose_inverse_ete, block1_size, e_block_size,
+ buffer + it2->second, e_block_size, block2_size,
+ cell_info->values, r, c, row_stride, col_stride);
+ }
+ }
+ }
+}
+
+// For rows with no e_blocks, the schur complement update reduces to S
+// += F'F. This function iterates over the rows of A with no e_block,
+// and calls NoEBlockRowOuterProduct on each row.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+NoEBlockRowsUpdate(const BlockSparseMatrix* A,
+ const double* b,
+ int row_block_counter,
+ BlockRandomAccessMatrix* lhs,
+ double* rhs) {
+ const CompressedRowBlockStructure* bs = A->block_structure();
+ const double* values = A->values();
+ for (; row_block_counter < bs->rows.size(); ++row_block_counter) {
+ const CompressedRow& row = bs->rows[row_block_counter];
+ for (int c = 0; c < row.cells.size(); ++c) {
+ const int block_id = row.cells[c].block_id;
+ const int block_size = bs->cols[block_id].size;
+ const int block = block_id - num_eliminate_blocks_;
+ MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values + row.cells[c].position, row.block.size, block_size,
+ b + row.block.position,
+ rhs + lhs_row_layout_[block]);
+ }
+ NoEBlockRowOuterProduct(A, row_block_counter, lhs);
+ }
+}
+
+
+// A row r of A, which has no e_blocks gets added to the Schur
+// Complement as S += r r'. This function is responsible for computing
+// the contribution of a single row r to the Schur complement. It is
+// very similar in structure to EBlockRowOuterProduct except for
+// one difference. It does not use any of the template
+// parameters. This is because the algorithm used for detecting the
+// static structure of the matrix A only pays attention to rows with
+// e_blocks. This is becase rows without e_blocks are rare and
+// typically arise from regularization terms in the original
+// optimization problem, and have a very different structure than the
+// rows with e_blocks. Including them in the static structure
+// detection will lead to most template parameters being set to
+// dynamic. Since the number of rows without e_blocks is small, the
+// lack of templating is not an issue.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
+ int row_block_index,
+ BlockRandomAccessMatrix* lhs) {
+ const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRow& row = bs->rows[row_block_index];
+ const double* values = A->values();
+ for (int i = 0; i < row.cells.size(); ++i) {
+ const int block1 = row.cells[i].block_id - num_eliminate_blocks_;
+ DCHECK_GE(block1, 0);
+
+ const int block1_size = bs->cols[row.cells[i].block_id].size;
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block1, block1,
+ &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ CeresMutexLock l(&cell_info->m);
+ // This multiply currently ignores the fact that this is a
+ // symmetric outer product.
+ MatrixTransposeMatrixMultiply
+ <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values + row.cells[i].position, row.block.size, block1_size,
+ values + row.cells[i].position, row.block.size, block1_size,
+ cell_info->values, r, c, row_stride, col_stride);
+ }
+
+ for (int j = i + 1; j < row.cells.size(); ++j) {
+ const int block2 = row.cells[j].block_id - num_eliminate_blocks_;
+ DCHECK_GE(block2, 0);
+ DCHECK_LT(block1, block2);
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block1, block2,
+ &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ const int block2_size = bs->cols[row.cells[j].block_id].size;
+ CeresMutexLock l(&cell_info->m);
+ MatrixTransposeMatrixMultiply
+ <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
+ values + row.cells[i].position, row.block.size, block1_size,
+ values + row.cells[j].position, row.block.size, block2_size,
+ cell_info->values, r, c, row_stride, col_stride);
+ }
+ }
+ }
+}
+
+// For a row with an e_block, compute the contribition S += F'F. This
+// function has the same structure as NoEBlockRowOuterProduct, except
+// that this function uses the template parameters.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void
+SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
+EBlockRowOuterProduct(const BlockSparseMatrix* A,
+ int row_block_index,
+ BlockRandomAccessMatrix* lhs) {
+ const CompressedRowBlockStructure* bs = A->block_structure();
+ const CompressedRow& row = bs->rows[row_block_index];
+ const double* values = A->values();
+ for (int i = 1; i < row.cells.size(); ++i) {
+ const int block1 = row.cells[i].block_id - num_eliminate_blocks_;
+ DCHECK_GE(block1, 0);
+
+ const int block1_size = bs->cols[row.cells[i].block_id].size;
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block1, block1,
+ &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ CeresMutexLock l(&cell_info->m);
+ // block += b1.transpose() * b1;
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
+ values + row.cells[i].position, row.block.size, block1_size,
+ values + row.cells[i].position, row.block.size, block1_size,
+ cell_info->values, r, c, row_stride, col_stride);
+ }
+
+ for (int j = i + 1; j < row.cells.size(); ++j) {
+ const int block2 = row.cells[j].block_id - num_eliminate_blocks_;
+ DCHECK_GE(block2, 0);
+ DCHECK_LT(block1, block2);
+ const int block2_size = bs->cols[row.cells[j].block_id].size;
+ int r, c, row_stride, col_stride;
+ CellInfo* cell_info = lhs->GetCell(block1, block2,
+ &r, &c,
+ &row_stride, &col_stride);
+ if (cell_info != NULL) {
+ // block += b1.transpose() * b2;
+ CeresMutexLock l(&cell_info->m);
+ MatrixTransposeMatrixMultiply
+ <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
+ values + row.cells[i].position, row.block.size, block1_size,
+ values + row.cells[j].position, row.block.size, block2_size,
+ cell_info->values, r, c, row_stride, col_stride);
+ }
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
diff --git a/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc
new file mode 100644
index 00000000000..3e6cc90f63c
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.cc
@@ -0,0 +1,115 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/schur_jacobi_preconditioner.h"
+
+#include <utility>
+#include <vector>
+#include "ceres/block_random_access_diagonal_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/collections_port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/schur_eliminator.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+SchurJacobiPreconditioner::SchurJacobiPreconditioner(
+ const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options)
+ : options_(options) {
+ CHECK_GT(options_.elimination_groups.size(), 1);
+ CHECK_GT(options_.elimination_groups[0], 0);
+ const int num_blocks = bs.cols.size() - options_.elimination_groups[0];
+ CHECK_GT(num_blocks, 0)
+ << "Jacobian should have atleast 1 f_block for "
+ << "SCHUR_JACOBI preconditioner.";
+
+ std::vector<int> blocks(num_blocks);
+ for (int i = 0; i < num_blocks; ++i) {
+ blocks[i] = bs.cols[i + options_.elimination_groups[0]].size;
+ }
+
+ m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
+ InitEliminator(bs);
+}
+
+SchurJacobiPreconditioner::~SchurJacobiPreconditioner() {
+}
+
+// Initialize the SchurEliminator.
+void SchurJacobiPreconditioner::InitEliminator(
+ const CompressedRowBlockStructure& bs) {
+ LinearSolver::Options eliminator_options;
+ eliminator_options.elimination_groups = options_.elimination_groups;
+ eliminator_options.num_threads = options_.num_threads;
+ eliminator_options.e_block_size = options_.e_block_size;
+ eliminator_options.f_block_size = options_.f_block_size;
+ eliminator_options.row_block_size = options_.row_block_size;
+ eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
+ eliminator_->Init(eliminator_options.elimination_groups[0], &bs);
+}
+
+// Update the values of the preconditioner matrix and factorize it.
+bool SchurJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+ const double* D) {
+ const int num_rows = m_->num_rows();
+ CHECK_GT(num_rows, 0);
+
+ // We need a dummy rhs vector and a dummy b vector since the Schur
+ // eliminator combines the computation of the reduced camera matrix
+ // with the computation of the right hand side of that linear
+ // system.
+ //
+ // TODO(sameeragarwal): Perhaps its worth refactoring the
+ // SchurEliminator::Eliminate function to allow NULL for the rhs. As
+ // of now it does not seem to be worth the effort.
+ Vector rhs = Vector::Zero(m_->num_rows());
+ Vector b = Vector::Zero(A.num_rows());
+
+ // Compute a subset of the entries of the Schur complement.
+ eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data());
+ m_->Invert();
+ return true;
+}
+
+void SchurJacobiPreconditioner::RightMultiply(const double* x,
+ double* y) const {
+ m_->RightMultiply(x, y);
+}
+
+int SchurJacobiPreconditioner::num_rows() const {
+ return m_->num_rows();
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h
new file mode 100644
index 00000000000..5398f3ff35d
--- /dev/null
+++ b/extern/ceres/internal/ceres/schur_jacobi_preconditioner.h
@@ -0,0 +1,106 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Detailed descriptions of these preconditions beyond what is
+// documented here can be found in
+//
+// Bundle Adjustment in the Large
+// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
+// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
+
+#ifndef CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
+#define CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
+
+#include <set>
+#include <vector>
+#include <utility>
+#include "ceres/collections_port.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/preconditioner.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockRandomAccessDiagonalMatrix;
+class BlockSparseMatrix;
+struct CompressedRowBlockStructure;
+class SchurEliminatorBase;
+
+// This class implements the SCHUR_JACOBI preconditioner for Structure
+// from Motion/Bundle Adjustment problems. Full mathematical details
+// can be found in
+//
+// Bundle Adjustment in the Large
+// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
+// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
+//
+// Example usage:
+//
+// Preconditioner::Options options;
+// options.preconditioner_type = SCHUR_JACOBI;
+// options.elimination_groups.push_back(num_points);
+// options.elimination_groups.push_back(num_cameras);
+// SchurJacobiPreconditioner preconditioner(
+// *A.block_structure(), options);
+// preconditioner.Update(A, NULL);
+// preconditioner.RightMultiply(x, y);
+//
+class SchurJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
+ public:
+ // Initialize the symbolic structure of the preconditioner. bs is
+ // the block structure of the linear system to be solved. It is used
+ // to determine the sparsity structure of the preconditioner matrix.
+ //
+ // It has the same structural requirement as other Schur complement
+ // based solvers. Please see schur_eliminator.h for more details.
+ SchurJacobiPreconditioner(const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options);
+ virtual ~SchurJacobiPreconditioner();
+
+ // Preconditioner interface.
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ private:
+ void InitEliminator(const CompressedRowBlockStructure& bs);
+ virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+
+ Preconditioner::Options options_;
+ scoped_ptr<SchurEliminatorBase> eliminator_;
+ // Preconditioner matrix.
+ scoped_ptr<BlockRandomAccessDiagonalMatrix> m_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(SchurJacobiPreconditioner);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
diff --git a/extern/ceres/internal/ceres/scratch_evaluate_preparer.cc b/extern/ceres/internal/ceres/scratch_evaluate_preparer.cc
new file mode 100644
index 00000000000..f01ef11c26f
--- /dev/null
+++ b/extern/ceres/internal/ceres/scratch_evaluate_preparer.cc
@@ -0,0 +1,78 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/scratch_evaluate_preparer.h"
+
+#include "ceres/parameter_block.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+
+namespace ceres {
+namespace internal {
+
+ScratchEvaluatePreparer* ScratchEvaluatePreparer::Create(
+ const Program &program,
+ int num_threads) {
+ ScratchEvaluatePreparer* preparers = new ScratchEvaluatePreparer[num_threads];
+ int max_derivatives_per_residual_block =
+ program.MaxDerivativesPerResidualBlock();
+ for (int i = 0; i < num_threads; i++) {
+ preparers[i].Init(max_derivatives_per_residual_block);
+ }
+ return preparers;
+}
+
+void ScratchEvaluatePreparer::Init(int max_derivatives_per_residual_block) {
+ jacobian_scratch_.reset(
+ new double[max_derivatives_per_residual_block]);
+}
+
+// Point the jacobian blocks into the scratch area of this evaluate preparer.
+void ScratchEvaluatePreparer::Prepare(const ResidualBlock* residual_block,
+ int /* residual_block_index */,
+ SparseMatrix* /* jacobian */,
+ double** jacobians) {
+ double* jacobian_block_cursor = jacobian_scratch_.get();
+ int num_residuals = residual_block->NumResiduals();
+ int num_parameter_blocks = residual_block->NumParameterBlocks();
+ for (int j = 0; j < num_parameter_blocks; ++j) {
+ const ParameterBlock* parameter_block =
+ residual_block->parameter_blocks()[j];
+ if (parameter_block->IsConstant()) {
+ jacobians[j] = NULL;
+ } else {
+ jacobians[j] = jacobian_block_cursor;
+ jacobian_block_cursor += num_residuals * parameter_block->LocalSize();
+ }
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/scratch_evaluate_preparer.h b/extern/ceres/internal/ceres/scratch_evaluate_preparer.h
new file mode 100644
index 00000000000..fa9ebd0e50e
--- /dev/null
+++ b/extern/ceres/internal/ceres/scratch_evaluate_preparer.h
@@ -0,0 +1,69 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+//
+// A scratch evaluate preparer provides temporary storage for the jacobians that
+// are created when running user-provided cost functions. The evaluator takes
+// care to avoid evaluating the jacobian for fixed parameters.
+
+#ifndef CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
+#define CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
+
+#include "ceres/internal/scoped_ptr.h"
+
+namespace ceres {
+namespace internal {
+
+class Program;
+class ResidualBlock;
+class SparseMatrix;
+
+class ScratchEvaluatePreparer {
+ public:
+ // Create num_threads ScratchEvaluatePreparers.
+ static ScratchEvaluatePreparer* Create(const Program &program,
+ int num_threads);
+
+ // EvaluatePreparer interface
+ void Init(int max_derivatives_per_residual_block);
+ void Prepare(const ResidualBlock* residual_block,
+ int residual_block_index,
+ SparseMatrix* jacobian,
+ double** jacobians);
+
+ private:
+ // Scratch space for the jacobians; each jacobian is packed one after another.
+ // There is enough scratch to hold all the jacobians for the largest residual.
+ scoped_array<double> jacobian_scratch_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
diff --git a/extern/ceres/internal/ceres/small_blas.h b/extern/ceres/internal/ceres/small_blas.h
new file mode 100644
index 00000000000..264ac53047d
--- /dev/null
+++ b/extern/ceres/internal/ceres/small_blas.h
@@ -0,0 +1,381 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Simple blas functions for use in the Schur Eliminator. These are
+// fairly basic implementations which already yield a significant
+// speedup in the eliminator performance.
+
+#ifndef CERES_INTERNAL_SMALL_BLAS_H_
+#define CERES_INTERNAL_SMALL_BLAS_H_
+
+#include "ceres/internal/port.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// The following three macros are used to share code and reduce
+// template junk across the various GEMM variants.
+#define CERES_GEMM_BEGIN(name) \
+ template<int kRowA, int kColA, int kRowB, int kColB, int kOperation> \
+ inline void name(const double* A, \
+ const int num_row_a, \
+ const int num_col_a, \
+ const double* B, \
+ const int num_row_b, \
+ const int num_col_b, \
+ double* C, \
+ const int start_row_c, \
+ const int start_col_c, \
+ const int row_stride_c, \
+ const int col_stride_c)
+
+#define CERES_GEMM_NAIVE_HEADER \
+ DCHECK_GT(num_row_a, 0); \
+ DCHECK_GT(num_col_a, 0); \
+ DCHECK_GT(num_row_b, 0); \
+ DCHECK_GT(num_col_b, 0); \
+ DCHECK_GE(start_row_c, 0); \
+ DCHECK_GE(start_col_c, 0); \
+ DCHECK_GT(row_stride_c, 0); \
+ DCHECK_GT(col_stride_c, 0); \
+ DCHECK((kRowA == Eigen::Dynamic) || (kRowA == num_row_a)); \
+ DCHECK((kColA == Eigen::Dynamic) || (kColA == num_col_a)); \
+ DCHECK((kRowB == Eigen::Dynamic) || (kRowB == num_row_b)); \
+ DCHECK((kColB == Eigen::Dynamic) || (kColB == num_col_b)); \
+ const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a); \
+ const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a); \
+ const int NUM_ROW_B = (kRowB != Eigen::Dynamic ? kRowB : num_row_b); \
+ const int NUM_COL_B = (kColB != Eigen::Dynamic ? kColB : num_col_b);
+
+#define CERES_GEMM_EIGEN_HEADER \
+ const typename EigenTypes<kRowA, kColA>::ConstMatrixRef \
+ Aref(A, num_row_a, num_col_a); \
+ const typename EigenTypes<kRowB, kColB>::ConstMatrixRef \
+ Bref(B, num_row_b, num_col_b); \
+ MatrixRef Cref(C, row_stride_c, col_stride_c); \
+
+#define CERES_CALL_GEMM(name) \
+ name<kRowA, kColA, kRowB, kColB, kOperation>( \
+ A, num_row_a, num_col_a, \
+ B, num_row_b, num_col_b, \
+ C, start_row_c, start_col_c, row_stride_c, col_stride_c);
+
+
+// For the matrix-matrix functions below, there are three variants for
+// each functionality. Foo, FooNaive and FooEigen. Foo is the one to
+// be called by the user. FooNaive is a basic loop based
+// implementation and FooEigen uses Eigen's implementation. Foo
+// chooses between FooNaive and FooEigen depending on how many of the
+// template arguments are fixed at compile time. Currently, FooEigen
+// is called if all matrix dimensions are compile time
+// constants. FooNaive is called otherwise. This leads to the best
+// performance currently.
+//
+// The MatrixMatrixMultiply variants compute:
+//
+// C op A * B;
+//
+// The MatrixTransposeMatrixMultiply variants compute:
+//
+// C op A' * B
+//
+// where op can be +=, -=, or =.
+//
+// The template parameters (kRowA, kColA, kRowB, kColB) allow
+// specialization of the loop at compile time. If this information is
+// not available, then Eigen::Dynamic should be used as the template
+// argument.
+//
+// kOperation = 1 -> C += A * B
+// kOperation = -1 -> C -= A * B
+// kOperation = 0 -> C = A * B
+//
+// The functions can write into matrices C which are larger than the
+// matrix A * B. This is done by specifying the true size of C via
+// row_stride_c and col_stride_c, and then indicating where A * B
+// should be written into by start_row_c and start_col_c.
+//
+// Graphically if row_stride_c = 10, col_stride_c = 12, start_row_c =
+// 4 and start_col_c = 5, then if A = 3x2 and B = 2x4, we get
+//
+// ------------
+// ------------
+// ------------
+// ------------
+// -----xxxx---
+// -----xxxx---
+// -----xxxx---
+// ------------
+// ------------
+// ------------
+//
+CERES_GEMM_BEGIN(MatrixMatrixMultiplyEigen) {
+ CERES_GEMM_EIGEN_HEADER
+ Eigen::Block<MatrixRef, kRowA, kColB>
+ block(Cref, start_row_c, start_col_c, num_row_a, num_col_b);
+
+ if (kOperation > 0) {
+ block.noalias() += Aref * Bref;
+ } else if (kOperation < 0) {
+ block.noalias() -= Aref * Bref;
+ } else {
+ block.noalias() = Aref * Bref;
+ }
+}
+
+CERES_GEMM_BEGIN(MatrixMatrixMultiplyNaive) {
+ CERES_GEMM_NAIVE_HEADER
+ DCHECK_EQ(NUM_COL_A, NUM_ROW_B);
+
+ const int NUM_ROW_C = NUM_ROW_A;
+ const int NUM_COL_C = NUM_COL_B;
+ DCHECK_LE(start_row_c + NUM_ROW_C, row_stride_c);
+ DCHECK_LE(start_col_c + NUM_COL_C, col_stride_c);
+
+ for (int row = 0; row < NUM_ROW_C; ++row) {
+ for (int col = 0; col < NUM_COL_C; ++col) {
+ double tmp = 0.0;
+ for (int k = 0; k < NUM_COL_A; ++k) {
+ tmp += A[row * NUM_COL_A + k] * B[k * NUM_COL_B + col];
+ }
+
+ const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
+ if (kOperation > 0) {
+ C[index] += tmp;
+ } else if (kOperation < 0) {
+ C[index] -= tmp;
+ } else {
+ C[index] = tmp;
+ }
+ }
+ }
+}
+
+CERES_GEMM_BEGIN(MatrixMatrixMultiply) {
+#ifdef CERES_NO_CUSTOM_BLAS
+
+ CERES_CALL_GEMM(MatrixMatrixMultiplyEigen)
+ return;
+
+#else
+
+ if (kRowA != Eigen::Dynamic && kColA != Eigen::Dynamic &&
+ kRowB != Eigen::Dynamic && kColB != Eigen::Dynamic) {
+ CERES_CALL_GEMM(MatrixMatrixMultiplyEigen)
+ } else {
+ CERES_CALL_GEMM(MatrixMatrixMultiplyNaive)
+ }
+
+#endif
+}
+
+CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiplyEigen) {
+ CERES_GEMM_EIGEN_HEADER
+ Eigen::Block<MatrixRef, kColA, kColB> block(Cref,
+ start_row_c, start_col_c,
+ num_col_a, num_col_b);
+ if (kOperation > 0) {
+ block.noalias() += Aref.transpose() * Bref;
+ } else if (kOperation < 0) {
+ block.noalias() -= Aref.transpose() * Bref;
+ } else {
+ block.noalias() = Aref.transpose() * Bref;
+ }
+}
+
+CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiplyNaive) {
+ CERES_GEMM_NAIVE_HEADER
+ DCHECK_EQ(NUM_ROW_A, NUM_ROW_B);
+
+ const int NUM_ROW_C = NUM_COL_A;
+ const int NUM_COL_C = NUM_COL_B;
+ DCHECK_LE(start_row_c + NUM_ROW_C, row_stride_c);
+ DCHECK_LE(start_col_c + NUM_COL_C, col_stride_c);
+
+ for (int row = 0; row < NUM_ROW_C; ++row) {
+ for (int col = 0; col < NUM_COL_C; ++col) {
+ double tmp = 0.0;
+ for (int k = 0; k < NUM_ROW_A; ++k) {
+ tmp += A[k * NUM_COL_A + row] * B[k * NUM_COL_B + col];
+ }
+
+ const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
+ if (kOperation > 0) {
+ C[index]+= tmp;
+ } else if (kOperation < 0) {
+ C[index]-= tmp;
+ } else {
+ C[index]= tmp;
+ }
+ }
+ }
+}
+
+CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiply) {
+#ifdef CERES_NO_CUSTOM_BLAS
+
+ CERES_CALL_GEMM(MatrixTransposeMatrixMultiplyEigen)
+ return;
+
+#else
+
+ if (kRowA != Eigen::Dynamic && kColA != Eigen::Dynamic &&
+ kRowB != Eigen::Dynamic && kColB != Eigen::Dynamic) {
+ CERES_CALL_GEMM(MatrixTransposeMatrixMultiplyEigen)
+ } else {
+ CERES_CALL_GEMM(MatrixTransposeMatrixMultiplyNaive)
+ }
+
+#endif
+}
+
+// Matrix-Vector multiplication
+//
+// c op A * b;
+//
+// where op can be +=, -=, or =.
+//
+// The template parameters (kRowA, kColA) allow specialization of the
+// loop at compile time. If this information is not available, then
+// Eigen::Dynamic should be used as the template argument.
+//
+// kOperation = 1 -> c += A' * b
+// kOperation = -1 -> c -= A' * b
+// kOperation = 0 -> c = A' * b
+template<int kRowA, int kColA, int kOperation>
+inline void MatrixVectorMultiply(const double* A,
+ const int num_row_a,
+ const int num_col_a,
+ const double* b,
+ double* c) {
+#ifdef CERES_NO_CUSTOM_BLAS
+ const typename EigenTypes<kRowA, kColA>::ConstMatrixRef
+ Aref(A, num_row_a, num_col_a);
+ const typename EigenTypes<kColA>::ConstVectorRef bref(b, num_col_a);
+ typename EigenTypes<kRowA>::VectorRef cref(c, num_row_a);
+
+ // lazyProduct works better than .noalias() for matrix-vector
+ // products.
+ if (kOperation > 0) {
+ cref += Aref.lazyProduct(bref);
+ } else if (kOperation < 0) {
+ cref -= Aref.lazyProduct(bref);
+ } else {
+ cref = Aref.lazyProduct(bref);
+ }
+#else
+
+ DCHECK_GT(num_row_a, 0);
+ DCHECK_GT(num_col_a, 0);
+ DCHECK((kRowA == Eigen::Dynamic) || (kRowA == num_row_a));
+ DCHECK((kColA == Eigen::Dynamic) || (kColA == num_col_a));
+
+ const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a);
+ const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a);
+
+ for (int row = 0; row < NUM_ROW_A; ++row) {
+ double tmp = 0.0;
+ for (int col = 0; col < NUM_COL_A; ++col) {
+ tmp += A[row * NUM_COL_A + col] * b[col];
+ }
+
+ if (kOperation > 0) {
+ c[row] += tmp;
+ } else if (kOperation < 0) {
+ c[row] -= tmp;
+ } else {
+ c[row] = tmp;
+ }
+ }
+#endif // CERES_NO_CUSTOM_BLAS
+}
+
+// Similar to MatrixVectorMultiply, except that A is transposed, i.e.,
+//
+// c op A' * b;
+template<int kRowA, int kColA, int kOperation>
+inline void MatrixTransposeVectorMultiply(const double* A,
+ const int num_row_a,
+ const int num_col_a,
+ const double* b,
+ double* c) {
+#ifdef CERES_NO_CUSTOM_BLAS
+ const typename EigenTypes<kRowA, kColA>::ConstMatrixRef
+ Aref(A, num_row_a, num_col_a);
+ const typename EigenTypes<kRowA>::ConstVectorRef bref(b, num_row_a);
+ typename EigenTypes<kColA>::VectorRef cref(c, num_col_a);
+
+ // lazyProduct works better than .noalias() for matrix-vector
+ // products.
+ if (kOperation > 0) {
+ cref += Aref.transpose().lazyProduct(bref);
+ } else if (kOperation < 0) {
+ cref -= Aref.transpose().lazyProduct(bref);
+ } else {
+ cref = Aref.transpose().lazyProduct(bref);
+ }
+#else
+
+ DCHECK_GT(num_row_a, 0);
+ DCHECK_GT(num_col_a, 0);
+ DCHECK((kRowA == Eigen::Dynamic) || (kRowA == num_row_a));
+ DCHECK((kColA == Eigen::Dynamic) || (kColA == num_col_a));
+
+ const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a);
+ const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a);
+
+ for (int row = 0; row < NUM_COL_A; ++row) {
+ double tmp = 0.0;
+ for (int col = 0; col < NUM_ROW_A; ++col) {
+ tmp += A[col * NUM_COL_A + row] * b[col];
+ }
+
+ if (kOperation > 0) {
+ c[row] += tmp;
+ } else if (kOperation < 0) {
+ c[row] -= tmp;
+ } else {
+ c[row] = tmp;
+ }
+ }
+#endif // CERES_NO_CUSTOM_BLAS
+}
+
+#undef CERES_GEMM_BEGIN
+#undef CERES_GEMM_EIGEN_HEADER
+#undef CERES_GEMM_NAIVE_HEADER
+#undef CERES_CALL_GEMM
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SMALL_BLAS_H_
diff --git a/extern/ceres/internal/ceres/solver.cc b/extern/ceres/internal/ceres/solver.cc
new file mode 100644
index 00000000000..9f3228bb0be
--- /dev/null
+++ b/extern/ceres/internal/ceres/solver.cc
@@ -0,0 +1,841 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+// sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/solver.h"
+
+#include <algorithm>
+#include <sstream> // NOLINT
+#include <vector>
+#include "ceres/gradient_checking_cost_function.h"
+#include "ceres/internal/port.h"
+#include "ceres/parameter_block_ordering.h"
+#include "ceres/preprocessor.h"
+#include "ceres/problem.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/solver_utils.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace {
+
+using std::map;
+using std::string;
+using std::vector;
+
+#define OPTION_OP(x, y, OP) \
+ if (!(options.x OP y)) { \
+ std::stringstream ss; \
+ ss << "Invalid configuration. "; \
+ ss << string("Solver::Options::" #x " = ") << options.x << ". "; \
+ ss << "Violated constraint: "; \
+ ss << string("Solver::Options::" #x " " #OP " "#y); \
+ *error = ss.str(); \
+ return false; \
+ }
+
+#define OPTION_OP_OPTION(x, y, OP) \
+ if (!(options.x OP options.y)) { \
+ std::stringstream ss; \
+ ss << "Invalid configuration. "; \
+ ss << string("Solver::Options::" #x " = ") << options.x << ". "; \
+ ss << string("Solver::Options::" #y " = ") << options.y << ". "; \
+ ss << "Violated constraint: "; \
+ ss << string("Solver::Options::" #x); \
+ ss << string(#OP " Solver::Options::" #y "."); \
+ *error = ss.str(); \
+ return false; \
+ }
+
+#define OPTION_GE(x, y) OPTION_OP(x, y, >=);
+#define OPTION_GT(x, y) OPTION_OP(x, y, >);
+#define OPTION_LE(x, y) OPTION_OP(x, y, <=);
+#define OPTION_LT(x, y) OPTION_OP(x, y, <);
+#define OPTION_LE_OPTION(x, y) OPTION_OP_OPTION(x, y, <=)
+#define OPTION_LT_OPTION(x, y) OPTION_OP_OPTION(x, y, <)
+
+bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
+ OPTION_GE(max_num_iterations, 0);
+ OPTION_GE(max_solver_time_in_seconds, 0.0);
+ OPTION_GE(function_tolerance, 0.0);
+ OPTION_GE(gradient_tolerance, 0.0);
+ OPTION_GE(parameter_tolerance, 0.0);
+ OPTION_GT(num_threads, 0);
+ OPTION_GT(num_linear_solver_threads, 0);
+ if (options.check_gradients) {
+ OPTION_GT(gradient_check_relative_precision, 0.0);
+ OPTION_GT(numeric_derivative_relative_step_size, 0.0);
+ }
+ return true;
+}
+
+bool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
+ OPTION_GT(initial_trust_region_radius, 0.0);
+ OPTION_GT(min_trust_region_radius, 0.0);
+ OPTION_GT(max_trust_region_radius, 0.0);
+ OPTION_LE_OPTION(min_trust_region_radius, max_trust_region_radius);
+ OPTION_LE_OPTION(min_trust_region_radius, initial_trust_region_radius);
+ OPTION_LE_OPTION(initial_trust_region_radius, max_trust_region_radius);
+ OPTION_GE(min_relative_decrease, 0.0);
+ OPTION_GE(min_lm_diagonal, 0.0);
+ OPTION_GE(max_lm_diagonal, 0.0);
+ OPTION_LE_OPTION(min_lm_diagonal, max_lm_diagonal);
+ OPTION_GE(max_num_consecutive_invalid_steps, 0);
+ OPTION_GT(eta, 0.0);
+ OPTION_GE(min_linear_solver_iterations, 0);
+ OPTION_GE(max_linear_solver_iterations, 1);
+ OPTION_LE_OPTION(min_linear_solver_iterations, max_linear_solver_iterations);
+
+ if (options.use_inner_iterations) {
+ OPTION_GE(inner_iteration_tolerance, 0.0);
+ }
+
+ if (options.use_nonmonotonic_steps) {
+ OPTION_GT(max_consecutive_nonmonotonic_steps, 0);
+ }
+
+ if (options.linear_solver_type == ITERATIVE_SCHUR &&
+ options.use_explicit_schur_complement &&
+ options.preconditioner_type != SCHUR_JACOBI) {
+ *error = "use_explicit_schur_complement only supports "
+ "SCHUR_JACOBI as the preconditioner.";
+ return false;
+ }
+
+ if (options.preconditioner_type == CLUSTER_JACOBI &&
+ options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
+ *error = "CLUSTER_JACOBI requires "
+ "Solver::Options::sparse_linear_algebra_library_type to be "
+ "SUITE_SPARSE";
+ return false;
+ }
+
+ if (options.preconditioner_type == CLUSTER_TRIDIAGONAL &&
+ options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
+ *error = "CLUSTER_TRIDIAGONAL requires "
+ "Solver::Options::sparse_linear_algebra_library_type to be "
+ "SUITE_SPARSE";
+ return false;
+ }
+
+#ifdef CERES_NO_LAPACK
+ if (options.dense_linear_algebra_library_type == LAPACK) {
+ if (options.linear_solver_type == DENSE_NORMAL_CHOLESKY) {
+ *error = "Can't use DENSE_NORMAL_CHOLESKY with LAPACK because "
+ "LAPACK was not enabled when Ceres was built.";
+ return false;
+ } else if (options.linear_solver_type == DENSE_QR) {
+ *error = "Can't use DENSE_QR with LAPACK because "
+ "LAPACK was not enabled when Ceres was built.";
+ return false;
+ } else if (options.linear_solver_type == DENSE_SCHUR) {
+ *error = "Can't use DENSE_SCHUR with LAPACK because "
+ "LAPACK was not enabled when Ceres was built.";
+ return false;
+ }
+ }
+#endif
+
+#ifdef CERES_NO_SUITESPARSE
+ if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) {
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+ *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because "
+ "SuiteSparse was not enabled when Ceres was built.";
+ return false;
+ } else if (options.linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR with SUITESPARSE because "
+ "SuiteSparse was not enabled when Ceres was built.";
+ return false;
+ } else if (options.preconditioner_type == CLUSTER_JACOBI) {
+ *error = "CLUSTER_JACOBI preconditioner not supported. "
+ "SuiteSparse was not enabled when Ceres was built.";
+ return false;
+ } else if (options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
+ *error = "CLUSTER_TRIDIAGONAL preconditioner not supported. "
+ "SuiteSparse was not enabled when Ceres was built.";
+ return false;
+ }
+ }
+#endif
+
+#ifdef CERES_NO_CXSPARSE
+ if (options.sparse_linear_algebra_library_type == CX_SPARSE) {
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+ *error = "Can't use SPARSE_NORMAL_CHOLESKY with CX_SPARSE because "
+ "CXSparse was not enabled when Ceres was built.";
+ return false;
+ } else if (options.linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR with CX_SPARSE because "
+ "CXSparse was not enabled when Ceres was built.";
+ return false;
+ }
+ }
+#endif
+
+#ifndef CERES_USE_EIGEN_SPARSE
+ if (options.sparse_linear_algebra_library_type == EIGEN_SPARSE) {
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+ *error = "Can't use SPARSE_NORMAL_CHOLESKY with EIGEN_SPARSE because "
+ "Eigen's sparse linear algebra was not enabled when Ceres was "
+ "built.";
+ return false;
+ } else if (options.linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR with EIGEN_SPARSE because "
+ "Eigen's sparse linear algebra was not enabled when Ceres was "
+ "built.";
+ return false;
+ }
+ }
+#endif
+
+ if (options.sparse_linear_algebra_library_type == NO_SPARSE) {
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
+ *error = "Can't use SPARSE_NORMAL_CHOLESKY as "
+ "sparse_linear_algebra_library_type is NO_SPARSE.";
+ return false;
+ } else if (options.linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR as "
+ "sparse_linear_algebra_library_type is NO_SPARSE.";
+ return false;
+ }
+ }
+
+ if (options.trust_region_strategy_type == DOGLEG) {
+ if (options.linear_solver_type == ITERATIVE_SCHUR ||
+ options.linear_solver_type == CGNR) {
+ *error = "DOGLEG only supports exact factorization based linear "
+ "solvers. If you want to use an iterative solver please "
+ "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
+ return false;
+ }
+ }
+
+ if (options.trust_region_minimizer_iterations_to_dump.size() > 0 &&
+ options.trust_region_problem_dump_format_type != CONSOLE &&
+ options.trust_region_problem_dump_directory.empty()) {
+ *error = "Solver::Options::trust_region_problem_dump_directory is empty.";
+ return false;
+ }
+
+ if (options.dynamic_sparsity &&
+ options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
+ *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+ return false;
+ }
+
+ return true;
+}
+
+bool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
+ OPTION_GT(max_lbfgs_rank, 0);
+ OPTION_GT(min_line_search_step_size, 0.0);
+ OPTION_GT(max_line_search_step_contraction, 0.0);
+ OPTION_LT(max_line_search_step_contraction, 1.0);
+ OPTION_LT_OPTION(max_line_search_step_contraction,
+ min_line_search_step_contraction);
+ OPTION_LE(min_line_search_step_contraction, 1.0);
+ OPTION_GT(max_num_line_search_step_size_iterations, 0);
+ OPTION_GT(line_search_sufficient_function_decrease, 0.0);
+ OPTION_LT_OPTION(line_search_sufficient_function_decrease,
+ line_search_sufficient_curvature_decrease);
+ OPTION_LT(line_search_sufficient_curvature_decrease, 1.0);
+ OPTION_GT(max_line_search_step_expansion, 1.0);
+
+ if ((options.line_search_direction_type == ceres::BFGS ||
+ options.line_search_direction_type == ceres::LBFGS) &&
+ options.line_search_type != ceres::WOLFE) {
+ *error =
+ string("Invalid configuration: Solver::Options::line_search_type = ")
+ + string(LineSearchTypeToString(options.line_search_type))
+ + string(". When using (L)BFGS, "
+ "Solver::Options::line_search_type must be set to WOLFE.");
+ return false;
+ }
+
+ // Warn user if they have requested BISECTION interpolation, but constraints
+ // on max/min step size change during line search prevent bisection scaling
+ // from occurring. Warn only, as this is likely a user mistake, but one which
+ // does not prevent us from continuing.
+ LOG_IF(WARNING,
+ (options.line_search_interpolation_type == ceres::BISECTION &&
+ (options.max_line_search_step_contraction > 0.5 ||
+ options.min_line_search_step_contraction < 0.5)))
+ << "Line search interpolation type is BISECTION, but specified "
+ << "max_line_search_step_contraction: "
+ << options.max_line_search_step_contraction << ", and "
+ << "min_line_search_step_contraction: "
+ << options.min_line_search_step_contraction
+ << ", prevent bisection (0.5) scaling, continuing with solve regardless.";
+
+ return true;
+}
+
+#undef OPTION_OP
+#undef OPTION_OP_OPTION
+#undef OPTION_GT
+#undef OPTION_GE
+#undef OPTION_LE
+#undef OPTION_LT
+#undef OPTION_LE_OPTION
+#undef OPTION_LT_OPTION
+
+void StringifyOrdering(const vector<int>& ordering, string* report) {
+ if (ordering.size() == 0) {
+ internal::StringAppendF(report, "AUTOMATIC");
+ return;
+ }
+
+ for (int i = 0; i < ordering.size() - 1; ++i) {
+ internal::StringAppendF(report, "%d, ", ordering[i]);
+ }
+ internal::StringAppendF(report, "%d", ordering.back());
+}
+
+void SummarizeGivenProgram(const internal::Program& program,
+ Solver::Summary* summary) {
+ summary->num_parameter_blocks = program.NumParameterBlocks();
+ summary->num_parameters = program.NumParameters();
+ summary->num_effective_parameters = program.NumEffectiveParameters();
+ summary->num_residual_blocks = program.NumResidualBlocks();
+ summary->num_residuals = program.NumResiduals();
+}
+
+void SummarizeReducedProgram(const internal::Program& program,
+ Solver::Summary* summary) {
+ summary->num_parameter_blocks_reduced = program.NumParameterBlocks();
+ summary->num_parameters_reduced = program.NumParameters();
+ summary->num_effective_parameters_reduced = program.NumEffectiveParameters();
+ summary->num_residual_blocks_reduced = program.NumResidualBlocks();
+ summary->num_residuals_reduced = program.NumResiduals();
+}
+
+void PreSolveSummarize(const Solver::Options& options,
+ const internal::ProblemImpl* problem,
+ Solver::Summary* summary) {
+ SummarizeGivenProgram(problem->program(), summary);
+ internal::OrderingToGroupSizes(options.linear_solver_ordering.get(),
+ &(summary->linear_solver_ordering_given));
+ internal::OrderingToGroupSizes(options.inner_iteration_ordering.get(),
+ &(summary->inner_iteration_ordering_given));
+
+ summary->dense_linear_algebra_library_type = options.dense_linear_algebra_library_type; // NOLINT
+ summary->dogleg_type = options.dogleg_type;
+ summary->inner_iteration_time_in_seconds = 0.0;
+ summary->line_search_cost_evaluation_time_in_seconds = 0.0;
+ summary->line_search_gradient_evaluation_time_in_seconds = 0.0;
+ summary->line_search_polynomial_minimization_time_in_seconds = 0.0;
+ summary->line_search_total_time_in_seconds = 0.0;
+ summary->inner_iterations_given = options.use_inner_iterations;
+ summary->line_search_direction_type = options.line_search_direction_type; // NOLINT
+ summary->line_search_interpolation_type = options.line_search_interpolation_type; // NOLINT
+ summary->line_search_type = options.line_search_type;
+ summary->linear_solver_type_given = options.linear_solver_type;
+ summary->max_lbfgs_rank = options.max_lbfgs_rank;
+ summary->minimizer_type = options.minimizer_type;
+ summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT
+ summary->num_linear_solver_threads_given = options.num_linear_solver_threads; // NOLINT
+ summary->num_threads_given = options.num_threads;
+ summary->preconditioner_type_given = options.preconditioner_type;
+ summary->sparse_linear_algebra_library_type = options.sparse_linear_algebra_library_type; // NOLINT
+ summary->trust_region_strategy_type = options.trust_region_strategy_type; // NOLINT
+ summary->visibility_clustering_type = options.visibility_clustering_type; // NOLINT
+}
+
+void PostSolveSummarize(const internal::PreprocessedProblem& pp,
+ Solver::Summary* summary) {
+ internal::OrderingToGroupSizes(pp.options.linear_solver_ordering.get(),
+ &(summary->linear_solver_ordering_used));
+ internal::OrderingToGroupSizes(pp.options.inner_iteration_ordering.get(),
+ &(summary->inner_iteration_ordering_used));
+
+ summary->inner_iterations_used = pp.inner_iteration_minimizer.get() != NULL; // NOLINT
+ summary->linear_solver_type_used = pp.options.linear_solver_type;
+ summary->num_linear_solver_threads_used = pp.options.num_linear_solver_threads; // NOLINT
+ summary->num_threads_used = pp.options.num_threads;
+ summary->preconditioner_type_used = pp.options.preconditioner_type; // NOLINT
+
+ internal::SetSummaryFinalCost(summary);
+
+ if (pp.reduced_program.get() != NULL) {
+ SummarizeReducedProgram(*pp.reduced_program, summary);
+ }
+
+ // It is possible that no evaluator was created. This would be the
+ // case if the preprocessor failed, or if the reduced problem did
+ // not contain any parameter blocks. Thus, only extract the
+ // evaluator statistics if one exists.
+ if (pp.evaluator.get() != NULL) {
+ const map<string, double>& evaluator_time_statistics =
+ pp.evaluator->TimeStatistics();
+ summary->residual_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
+ summary->jacobian_evaluation_time_in_seconds =
+ FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
+ }
+
+ // Again, like the evaluator, there may or may not be a linear
+ // solver from which we can extract run time statistics. In
+ // particular the line search solver does not use a linear solver.
+ if (pp.linear_solver.get() != NULL) {
+ const map<string, double>& linear_solver_time_statistics =
+ pp.linear_solver->TimeStatistics();
+ summary->linear_solver_time_in_seconds =
+ FindWithDefault(linear_solver_time_statistics,
+ "LinearSolver::Solve",
+ 0.0);
+ }
+}
+
+void Minimize(internal::PreprocessedProblem* pp,
+ Solver::Summary* summary) {
+ using internal::Program;
+ using internal::scoped_ptr;
+ using internal::Minimizer;
+
+ Program* program = pp->reduced_program.get();
+ if (pp->reduced_program->NumParameterBlocks() == 0) {
+ summary->message = "Function tolerance reached. "
+ "No non-constant parameter blocks found.";
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, pp->options.logging_type != SILENT) << summary->message;
+ summary->initial_cost = summary->fixed_cost;
+ summary->final_cost = summary->fixed_cost;
+ return;
+ }
+
+ scoped_ptr<Minimizer> minimizer(
+ Minimizer::Create(pp->options.minimizer_type));
+ minimizer->Minimize(pp->minimizer_options,
+ pp->reduced_parameters.data(),
+ summary);
+
+ if (summary->IsSolutionUsable()) {
+ program->StateVectorToParameterBlocks(pp->reduced_parameters.data());
+ program->CopyParameterBlockStateToUserState();
+ }
+}
+
+} // namespace
+
+bool Solver::Options::IsValid(string* error) const {
+ if (!CommonOptionsAreValid(*this, error)) {
+ return false;
+ }
+
+ if (minimizer_type == TRUST_REGION &&
+ !TrustRegionOptionsAreValid(*this, error)) {
+ return false;
+ }
+
+ // We do not know if the problem is bounds constrained or not, if it
+ // is then the trust region solver will also use the line search
+ // solver to do a projection onto the box constraints, so make sure
+ // that the line search options are checked independent of what
+ // minimizer algorithm is being used.
+ return LineSearchOptionsAreValid(*this, error);
+}
+
+Solver::~Solver() {}
+
+void Solver::Solve(const Solver::Options& options,
+ Problem* problem,
+ Solver::Summary* summary) {
+ using internal::PreprocessedProblem;
+ using internal::Preprocessor;
+ using internal::ProblemImpl;
+ using internal::Program;
+ using internal::scoped_ptr;
+ using internal::WallTimeInSeconds;
+
+ CHECK_NOTNULL(problem);
+ CHECK_NOTNULL(summary);
+
+ double start_time = WallTimeInSeconds();
+ *summary = Summary();
+ if (!options.IsValid(&summary->message)) {
+ LOG(ERROR) << "Terminating: " << summary->message;
+ return;
+ }
+
+ ProblemImpl* problem_impl = problem->problem_impl_.get();
+ Program* program = problem_impl->mutable_program();
+ PreSolveSummarize(options, problem_impl, summary);
+
+ // Make sure that all the parameter blocks states are set to the
+ // values provided by the user.
+ program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ scoped_ptr<internal::ProblemImpl> gradient_checking_problem;
+ if (options.check_gradients) {
+ gradient_checking_problem.reset(
+ CreateGradientCheckingProblemImpl(
+ problem_impl,
+ options.numeric_derivative_relative_step_size,
+ options.gradient_check_relative_precision));
+ problem_impl = gradient_checking_problem.get();
+ program = problem_impl->mutable_program();
+ }
+
+ scoped_ptr<Preprocessor> preprocessor(
+ Preprocessor::Create(options.minimizer_type));
+ PreprocessedProblem pp;
+ const bool status = preprocessor->Preprocess(options, problem_impl, &pp);
+ summary->fixed_cost = pp.fixed_cost;
+ summary->preprocessor_time_in_seconds = WallTimeInSeconds() - start_time;
+
+ if (status) {
+ const double minimizer_start_time = WallTimeInSeconds();
+ Minimize(&pp, summary);
+ summary->minimizer_time_in_seconds =
+ WallTimeInSeconds() - minimizer_start_time;
+ } else {
+ summary->message = pp.error;
+ }
+
+ const double postprocessor_start_time = WallTimeInSeconds();
+ problem_impl = problem->problem_impl_.get();
+ program = problem_impl->mutable_program();
+ // On exit, ensure that the parameter blocks again point at the user
+ // provided values and the parameter blocks are numbered according
+ // to their position in the original user provided program.
+ program->SetParameterBlockStatePtrsToUserStatePtrs();
+ program->SetParameterOffsetsAndIndex();
+ PostSolveSummarize(pp, summary);
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - postprocessor_start_time;
+
+ summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
+}
+
+void Solve(const Solver::Options& options,
+ Problem* problem,
+ Solver::Summary* summary) {
+ Solver solver;
+ solver.Solve(options, problem, summary);
+}
+
+Solver::Summary::Summary()
+ // Invalid values for most fields, to ensure that we are not
+ // accidentally reporting default values.
+ : minimizer_type(TRUST_REGION),
+ termination_type(FAILURE),
+ message("ceres::Solve was not called."),
+ initial_cost(-1.0),
+ final_cost(-1.0),
+ fixed_cost(-1.0),
+ num_successful_steps(-1),
+ num_unsuccessful_steps(-1),
+ num_inner_iteration_steps(-1),
+ preprocessor_time_in_seconds(-1.0),
+ minimizer_time_in_seconds(-1.0),
+ postprocessor_time_in_seconds(-1.0),
+ total_time_in_seconds(-1.0),
+ linear_solver_time_in_seconds(-1.0),
+ residual_evaluation_time_in_seconds(-1.0),
+ jacobian_evaluation_time_in_seconds(-1.0),
+ inner_iteration_time_in_seconds(-1.0),
+ line_search_cost_evaluation_time_in_seconds(-1.0),
+ line_search_gradient_evaluation_time_in_seconds(-1.0),
+ line_search_polynomial_minimization_time_in_seconds(-1.0),
+ line_search_total_time_in_seconds(-1.0),
+ num_parameter_blocks(-1),
+ num_parameters(-1),
+ num_effective_parameters(-1),
+ num_residual_blocks(-1),
+ num_residuals(-1),
+ num_parameter_blocks_reduced(-1),
+ num_parameters_reduced(-1),
+ num_effective_parameters_reduced(-1),
+ num_residual_blocks_reduced(-1),
+ num_residuals_reduced(-1),
+ is_constrained(false),
+ num_threads_given(-1),
+ num_threads_used(-1),
+ num_linear_solver_threads_given(-1),
+ num_linear_solver_threads_used(-1),
+ linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
+ linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
+ inner_iterations_given(false),
+ inner_iterations_used(false),
+ preconditioner_type_given(IDENTITY),
+ preconditioner_type_used(IDENTITY),
+ visibility_clustering_type(CANONICAL_VIEWS),
+ trust_region_strategy_type(LEVENBERG_MARQUARDT),
+ dense_linear_algebra_library_type(EIGEN),
+ sparse_linear_algebra_library_type(SUITE_SPARSE),
+ line_search_direction_type(LBFGS),
+ line_search_type(ARMIJO),
+ line_search_interpolation_type(BISECTION),
+ nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
+ max_lbfgs_rank(-1) {
+}
+
+using internal::StringAppendF;
+using internal::StringPrintf;
+
+string Solver::Summary::BriefReport() const {
+ return StringPrintf("Ceres Solver Report: "
+ "Iterations: %d, "
+ "Initial cost: %e, "
+ "Final cost: %e, "
+ "Termination: %s",
+ num_successful_steps + num_unsuccessful_steps,
+ initial_cost,
+ final_cost,
+ TerminationTypeToString(termination_type));
+}
+
+string Solver::Summary::FullReport() const {
+ using internal::VersionString;
+
+ string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
+
+ StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
+ StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
+ num_parameter_blocks, num_parameter_blocks_reduced);
+ StringAppendF(&report, "Parameters % 25d% 25d\n",
+ num_parameters, num_parameters_reduced);
+ if (num_effective_parameters_reduced != num_parameters_reduced) {
+ StringAppendF(&report, "Effective parameters% 25d% 25d\n",
+ num_effective_parameters, num_effective_parameters_reduced);
+ }
+ StringAppendF(&report, "Residual blocks % 25d% 25d\n",
+ num_residual_blocks, num_residual_blocks_reduced);
+ StringAppendF(&report, "Residual % 25d% 25d\n",
+ num_residuals, num_residuals_reduced);
+
+ if (minimizer_type == TRUST_REGION) {
+ // TRUST_SEARCH HEADER
+ StringAppendF(&report, "\nMinimizer %19s\n",
+ "TRUST_REGION");
+
+ if (linear_solver_type_used == DENSE_NORMAL_CHOLESKY ||
+ linear_solver_type_used == DENSE_SCHUR ||
+ linear_solver_type_used == DENSE_QR) {
+ StringAppendF(&report, "\nDense linear algebra library %15s\n",
+ DenseLinearAlgebraLibraryTypeToString(
+ dense_linear_algebra_library_type));
+ }
+
+ if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
+ linear_solver_type_used == SPARSE_SCHUR ||
+ (linear_solver_type_used == ITERATIVE_SCHUR &&
+ (preconditioner_type_used == CLUSTER_JACOBI ||
+ preconditioner_type_used == CLUSTER_TRIDIAGONAL))) {
+ StringAppendF(&report, "\nSparse linear algebra library %15s\n",
+ SparseLinearAlgebraLibraryTypeToString(
+ sparse_linear_algebra_library_type));
+ }
+
+ StringAppendF(&report, "Trust region strategy %19s",
+ TrustRegionStrategyTypeToString(
+ trust_region_strategy_type));
+ if (trust_region_strategy_type == DOGLEG) {
+ if (dogleg_type == TRADITIONAL_DOGLEG) {
+ StringAppendF(&report, " (TRADITIONAL)");
+ } else {
+ StringAppendF(&report, " (SUBSPACE)");
+ }
+ }
+ StringAppendF(&report, "\n");
+ StringAppendF(&report, "\n");
+
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Linear solver %25s%25s\n",
+ LinearSolverTypeToString(linear_solver_type_given),
+ LinearSolverTypeToString(linear_solver_type_used));
+
+ if (linear_solver_type_given == CGNR ||
+ linear_solver_type_given == ITERATIVE_SCHUR) {
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ PreconditionerTypeToString(preconditioner_type_given),
+ PreconditionerTypeToString(preconditioner_type_used));
+ }
+
+ if (preconditioner_type_used == CLUSTER_JACOBI ||
+ preconditioner_type_used == CLUSTER_TRIDIAGONAL) {
+ StringAppendF(&report, "Visibility clustering%24s%25s\n",
+ VisibilityClusteringTypeToString(
+ visibility_clustering_type),
+ VisibilityClusteringTypeToString(
+ visibility_clustering_type));
+ }
+ StringAppendF(&report, "Threads % 25d% 25d\n",
+ num_threads_given, num_threads_used);
+ StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
+ num_linear_solver_threads_given,
+ num_linear_solver_threads_used);
+
+ if (IsSchurType(linear_solver_type_used)) {
+ string given;
+ StringifyOrdering(linear_solver_ordering_given, &given);
+ string used;
+ StringifyOrdering(linear_solver_ordering_used, &used);
+ StringAppendF(&report,
+ "Linear solver ordering %22s %24s\n",
+ given.c_str(),
+ used.c_str());
+ }
+
+ if (inner_iterations_given) {
+ StringAppendF(&report,
+ "Use inner iterations %20s %20s\n",
+ inner_iterations_given ? "True" : "False",
+ inner_iterations_used ? "True" : "False");
+ }
+
+ if (inner_iterations_used) {
+ string given;
+ StringifyOrdering(inner_iteration_ordering_given, &given);
+ string used;
+ StringifyOrdering(inner_iteration_ordering_used, &used);
+ StringAppendF(&report,
+ "Inner iteration ordering %20s %24s\n",
+ given.c_str(),
+ used.c_str());
+ }
+ } else {
+ // LINE_SEARCH HEADER
+ StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
+
+
+ string line_search_direction_string;
+ if (line_search_direction_type == LBFGS) {
+ line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
+ } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
+ line_search_direction_string =
+ NonlinearConjugateGradientTypeToString(
+ nonlinear_conjugate_gradient_type);
+ } else {
+ line_search_direction_string =
+ LineSearchDirectionTypeToString(line_search_direction_type);
+ }
+
+ StringAppendF(&report, "Line search direction %19s\n",
+ line_search_direction_string.c_str());
+
+ const string line_search_type_string =
+ StringPrintf("%s %s",
+ LineSearchInterpolationTypeToString(
+ line_search_interpolation_type),
+ LineSearchTypeToString(line_search_type));
+ StringAppendF(&report, "Line search type %19s\n",
+ line_search_type_string.c_str());
+ StringAppendF(&report, "\n");
+
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Threads % 25d% 25d\n",
+ num_threads_given, num_threads_used);
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != FAILURE &&
+ termination_type != USER_FAILURE) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nMinimizer iterations % 16d\n",
+ num_successful_steps + num_unsuccessful_steps);
+
+ // Successful/Unsuccessful steps only matter in the case of the
+ // trust region solver. Line search terminates when it encounters
+ // the first unsuccessful step.
+ if (minimizer_type == TRUST_REGION) {
+ StringAppendF(&report, "Successful steps % 14d\n",
+ num_successful_steps);
+ StringAppendF(&report, "Unsuccessful steps % 14d\n",
+ num_unsuccessful_steps);
+ }
+ if (inner_iterations_used) {
+ StringAppendF(&report, "Steps with inner iterations % 14d\n",
+ num_inner_iteration_steps);
+ }
+
+ const bool print_line_search_timing_information =
+ minimizer_type == LINE_SEARCH ||
+ (minimizer_type == TRUST_REGION && is_constrained);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.4f\n",
+ preprocessor_time_in_seconds);
+
+ StringAppendF(&report, "\n Residual evaluation %23.4f\n",
+ residual_evaluation_time_in_seconds);
+ if (print_line_search_timing_information) {
+ StringAppendF(&report, " Line search cost evaluation %10.4f\n",
+ line_search_cost_evaluation_time_in_seconds);
+ }
+ StringAppendF(&report, " Jacobian evaluation %23.4f\n",
+ jacobian_evaluation_time_in_seconds);
+ if (print_line_search_timing_information) {
+ StringAppendF(&report, " Line search gradient evaluation %6.4f\n",
+ line_search_gradient_evaluation_time_in_seconds);
+ }
+
+ if (minimizer_type == TRUST_REGION) {
+ StringAppendF(&report, " Linear solver %23.4f\n",
+ linear_solver_time_in_seconds);
+ }
+
+ if (inner_iterations_used) {
+ StringAppendF(&report, " Inner iterations %23.4f\n",
+ inner_iteration_time_in_seconds);
+ }
+
+ if (print_line_search_timing_information) {
+ StringAppendF(&report, " Line search polynomial minimization %.4f\n",
+ line_search_polynomial_minimization_time_in_seconds);
+ }
+
+ StringAppendF(&report, "Minimizer %25.4f\n\n",
+ minimizer_time_in_seconds);
+
+ StringAppendF(&report, "Postprocessor %24.4f\n",
+ postprocessor_time_in_seconds);
+
+ StringAppendF(&report, "Total %25.4f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s (%s)\n",
+ TerminationTypeToString(termination_type), message.c_str());
+ return report;
+}
+
+bool Solver::Summary::IsSolutionUsable() const {
+ return internal::IsSolutionUsable(*this);
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/solver_utils.cc b/extern/ceres/internal/ceres/solver_utils.cc
new file mode 100644
index 00000000000..7f4ff7eb940
--- /dev/null
+++ b/extern/ceres/internal/ceres/solver_utils.cc
@@ -0,0 +1,86 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <string>
+
+#include "Eigen/Core"
+#include "ceres/internal/port.h"
+#include "ceres/solver_utils.h"
+#include "ceres/version.h"
+
+namespace ceres {
+namespace internal {
+
+#define CERES_EIGEN_VERSION \
+ CERES_TO_STRING(EIGEN_WORLD_VERSION) "." \
+ CERES_TO_STRING(EIGEN_MAJOR_VERSION) "." \
+ CERES_TO_STRING(EIGEN_MINOR_VERSION)
+
+std::string VersionString() {
+ std::string value = std::string(CERES_VERSION_STRING);
+ value += "-eigen-(" + std::string(CERES_EIGEN_VERSION) + ")";
+
+#ifdef CERES_NO_LAPACK
+ value += "-no_lapack";
+#else
+ value += "-lapack";
+#endif
+
+#ifndef CERES_NO_SUITESPARSE
+ value += "-suitesparse-(" + std::string(CERES_SUITESPARSE_VERSION) + ")";
+#endif
+
+#ifndef CERES_NO_CXSPARSE
+ value += "-cxsparse-(" + std::string(CERES_CXSPARSE_VERSION) + ")";
+#endif
+
+#ifdef CERES_USE_EIGEN_SPARSE
+ value += "-eigensparse";
+#endif
+
+#ifdef CERES_RESTRUCT_SCHUR_SPECIALIZATIONS
+ value += "-no_schur_specializations";
+#endif
+
+#ifdef CERES_USE_OPENMP
+ value += "-openmp";
+#else
+ value += "-no_openmp";
+#endif
+
+#ifdef CERES_NO_CUSTOM_BLAS
+ value += "-no_custom_blas";
+#endif
+
+ return value;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/solver_utils.h b/extern/ceres/internal/ceres/solver_utils.h
new file mode 100644
index 00000000000..85fbf3776ab
--- /dev/null
+++ b/extern/ceres/internal/ceres/solver_utils.h
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <algorithm>
+#include <string>
+
+#include "ceres/iteration_callback.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+template <typename SummaryType>
+bool IsSolutionUsable(const SummaryType& summary) {
+ return (summary.termination_type == CONVERGENCE ||
+ summary.termination_type == NO_CONVERGENCE ||
+ summary.termination_type == USER_SUCCESS);
+}
+
+template <typename SummaryType>
+void SetSummaryFinalCost(SummaryType* summary) {
+ summary->final_cost = summary->initial_cost;
+ // We need the loop here, instead of just looking at the last
+ // iteration because the minimizer maybe making non-monotonic steps.
+ for (int i = 0; i < summary->iterations.size(); ++i) {
+ const IterationSummary& iteration_summary = summary->iterations[i];
+ summary->final_cost = std::min(iteration_summary.cost, summary->final_cost);
+ }
+}
+
+std::string VersionString();
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/sparse_matrix.cc b/extern/ceres/internal/ceres/sparse_matrix.cc
new file mode 100644
index 00000000000..f95ff3220bd
--- /dev/null
+++ b/extern/ceres/internal/ceres/sparse_matrix.cc
@@ -0,0 +1,40 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+SparseMatrix::~SparseMatrix() {
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/sparse_matrix.h b/extern/ceres/internal/ceres/sparse_matrix.h
new file mode 100644
index 00000000000..b3af1d06440
--- /dev/null
+++ b/extern/ceres/internal/ceres/sparse_matrix.h
@@ -0,0 +1,107 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Interface definition for sparse matrices.
+
+#ifndef CERES_INTERNAL_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_SPARSE_MATRIX_H_
+
+#include <cstdio>
+#include "ceres/linear_operator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+// This class defines the interface for storing and manipulating
+// sparse matrices. The key property that differentiates different
+// sparse matrices is how they are organized in memory and how the
+// information about the sparsity structure of the matrix is
+// stored. This has significant implications for linear solvers
+// operating on these matrices.
+//
+// To deal with the different kinds of layouts, we will assume that a
+// sparse matrix will have a two part representation. A values array
+// that will be used to store the entries of the sparse matrix and
+// some sort of a layout object that tells the user the sparsity
+// structure and layout of the values array. For example in case of
+// the TripletSparseMatrix, this information is carried in the rows
+// and cols arrays and for the BlockSparseMatrix, this information is
+// carried in the CompressedRowBlockStructure object.
+//
+// This interface deliberately does not contain any information about
+// the structure of the sparse matrix as that seems to be highly
+// matrix type dependent and we are at this stage unable to come up
+// with an efficient high level interface that spans multiple sparse
+// matrix types.
+class SparseMatrix : public LinearOperator {
+ public:
+ virtual ~SparseMatrix();
+
+ // y += Ax;
+ virtual void RightMultiply(const double* x, double* y) const = 0;
+ // y += A'x;
+ virtual void LeftMultiply(const double* x, double* y) const = 0;
+
+ // In MATLAB notation sum(A.*A, 1)
+ virtual void SquaredColumnNorm(double* x) const = 0;
+ // A = A * diag(scale)
+ virtual void ScaleColumns(const double* scale) = 0;
+
+ // A = 0. A->num_nonzeros() == 0 is true after this call. The
+ // sparsity pattern is preserved.
+ virtual void SetZero() = 0;
+
+ // Resize and populate dense_matrix with a dense version of the
+ // sparse matrix.
+ virtual void ToDenseMatrix(Matrix* dense_matrix) const = 0;
+
+ // Write out the matrix as a sequence of (i,j,s) triplets. This
+ // format is useful for loading the matrix into MATLAB/octave as a
+ // sparse matrix.
+ virtual void ToTextFile(FILE* file) const = 0;
+
+ // Accessors for the values array that stores the entries of the
+ // sparse matrix. The exact interpreptation of the values of this
+ // array depends on the particular kind of SparseMatrix being
+ // accessed.
+ virtual double* mutable_values() = 0;
+ virtual const double* values() const = 0;
+
+ virtual int num_rows() const = 0;
+ virtual int num_cols() const = 0;
+ virtual int num_nonzeros() const = 0;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SPARSE_MATRIX_H_
diff --git a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
new file mode 100644
index 00000000000..ed00879b47a
--- /dev/null
+++ b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
@@ -0,0 +1,486 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/sparse_normal_cholesky_solver.h"
+
+#include <algorithm>
+#include <cstring>
+#include <ctime>
+
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/cxsparse.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/suitesparse.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+#include "Eigen/SparseCore"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/SparseCholesky"
+#endif
+
+namespace ceres {
+namespace internal {
+namespace {
+
+#ifdef CERES_USE_EIGEN_SPARSE
+// A templated factorized and solve function, which allows us to use
+// the same code independent of whether a AMD or a Natural ordering is
+// used.
+template <typename SimplicialCholeskySolver, typename SparseMatrixType>
+LinearSolver::Summary SimplicialLDLTSolve(
+ const SparseMatrixType& lhs,
+ const bool do_symbolic_analysis,
+ SimplicialCholeskySolver* solver,
+ double* rhs_and_solution,
+ EventLogger* event_logger) {
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ if (do_symbolic_analysis) {
+ solver->analyzePattern(lhs);
+ event_logger->AddEvent("Analyze");
+ if (solver->info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "Eigen failure. Unable to find symbolic factorization.";
+ return summary;
+ }
+ }
+
+ solver->factorize(lhs);
+ event_logger->AddEvent("Factorize");
+ if (solver->info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen failure. Unable to find numeric factorization.";
+ return summary;
+ }
+
+ const Vector rhs = VectorRef(rhs_and_solution, lhs.cols());
+
+ VectorRef(rhs_and_solution, lhs.cols()) = solver->solve(rhs);
+ event_logger->AddEvent("Solve");
+ if (solver->info() != Eigen::Success) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "Eigen failure. Unable to do triangular solve.";
+ return summary;
+ }
+
+ return summary;
+}
+
+#endif // CERES_USE_EIGEN_SPARSE
+
+#ifndef CERES_NO_CXSPARSE
+LinearSolver::Summary ComputeNormalEquationsAndSolveUsingCXSparse(
+ CompressedRowSparseMatrix* A,
+ double * rhs_and_solution,
+ EventLogger* event_logger) {
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ CXSparse cxsparse;
+
+ // Wrap the augmented Jacobian in a compressed sparse column matrix.
+ cs_di a_transpose = cxsparse.CreateSparseMatrixTransposeView(A);
+
+ // Compute the normal equations. J'J delta = J'f and solve them
+ // using a sparse Cholesky factorization. Notice that when compared
+ // to SuiteSparse we have to explicitly compute the transpose of Jt,
+ // and then the normal equations before they can be
+ // factorized. CHOLMOD/SuiteSparse on the other hand can just work
+ // off of Jt to compute the Cholesky factorization of the normal
+ // equations.
+ cs_di* a = cxsparse.TransposeMatrix(&a_transpose);
+ cs_di* lhs = cxsparse.MatrixMatrixMultiply(&a_transpose, a);
+ cxsparse.Free(a);
+ event_logger->AddEvent("NormalEquations");
+
+ cs_dis* factor = cxsparse.AnalyzeCholesky(lhs);
+ event_logger->AddEvent("Analysis");
+
+ if (factor == NULL) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message = "CXSparse::AnalyzeCholesky failed.";
+ } else if (!cxsparse.SolveCholesky(lhs, factor, rhs_and_solution)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "CXSparse::SolveCholesky failed.";
+ }
+ event_logger->AddEvent("Solve");
+
+ cxsparse.Free(lhs);
+ cxsparse.Free(factor);
+ event_logger->AddEvent("TearDown");
+ return summary;
+}
+
+#endif // CERES_NO_CXSPARSE
+
+} // namespace
+
+SparseNormalCholeskySolver::SparseNormalCholeskySolver(
+ const LinearSolver::Options& options)
+ : factor_(NULL),
+ cxsparse_factor_(NULL),
+ options_(options) {
+}
+
+void SparseNormalCholeskySolver::FreeFactorization() {
+ if (factor_ != NULL) {
+ ss_.Free(factor_);
+ factor_ = NULL;
+ }
+
+ if (cxsparse_factor_ != NULL) {
+ cxsparse_.Free(cxsparse_factor_);
+ cxsparse_factor_ = NULL;
+ }
+}
+
+SparseNormalCholeskySolver::~SparseNormalCholeskySolver() {
+ FreeFactorization();
+}
+
+LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl(
+ CompressedRowSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double * x) {
+
+ const int num_cols = A->num_cols();
+ VectorRef(x, num_cols).setZero();
+ A->LeftMultiply(b, x);
+
+ if (per_solve_options.D != NULL) {
+ // Temporarily append a diagonal block to the A matrix, but undo
+ // it before returning the matrix to the user.
+ scoped_ptr<CompressedRowSparseMatrix> regularizer;
+ if (A->col_blocks().size() > 0) {
+ regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+ per_solve_options.D, A->col_blocks()));
+ } else {
+ regularizer.reset(new CompressedRowSparseMatrix(
+ per_solve_options.D, num_cols));
+ }
+ A->AppendRows(*regularizer);
+ }
+
+ LinearSolver::Summary summary;
+ switch (options_.sparse_linear_algebra_library_type) {
+ case SUITE_SPARSE:
+ summary = SolveImplUsingSuiteSparse(A, x);
+ break;
+ case CX_SPARSE:
+ summary = SolveImplUsingCXSparse(A, x);
+ break;
+ case EIGEN_SPARSE:
+ summary = SolveImplUsingEigen(A, x);
+ break;
+ default:
+ LOG(FATAL) << "Unknown sparse linear algebra library : "
+ << options_.sparse_linear_algebra_library_type;
+ }
+
+ if (per_solve_options.D != NULL) {
+ A->DeleteRows(num_cols);
+ }
+
+ return summary;
+}
+
+LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingEigen(
+ CompressedRowSparseMatrix* A,
+ double * rhs_and_solution) {
+#ifndef CERES_USE_EIGEN_SPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
+ "because Ceres was not built with support for "
+ "Eigen's SimplicialLDLT decomposition. "
+ "This requires enabling building with -DEIGENSPARSE=ON.";
+ return summary;
+
+#else
+
+ EventLogger event_logger("SparseNormalCholeskySolver::Eigen::Solve");
+ // Compute the normal equations. J'J delta = J'f and solve them
+ // using a sparse Cholesky factorization. Notice that when compared
+ // to SuiteSparse we have to explicitly compute the normal equations
+ // before they can be factorized. CHOLMOD/SuiteSparse on the other
+ // hand can just work off of Jt to compute the Cholesky
+ // factorization of the normal equations.
+
+ if (options_.dynamic_sparsity) {
+ // In the case where the problem has dynamic sparsity, it is not
+ // worth using the ComputeOuterProduct routine, as the setup cost
+ // is not amortized over multiple calls to Solve.
+ Eigen::MappedSparseMatrix<double, Eigen::RowMajor> a(
+ A->num_rows(),
+ A->num_cols(),
+ A->num_nonzeros(),
+ A->mutable_rows(),
+ A->mutable_cols(),
+ A->mutable_values());
+
+ Eigen::SparseMatrix<double> lhs = a.transpose() * a;
+ Eigen::SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
+ return SimplicialLDLTSolve(lhs,
+ true,
+ &solver,
+ rhs_and_solution,
+ &event_logger);
+ }
+
+ if (outer_product_.get() == NULL) {
+ outer_product_.reset(
+ CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
+ *A, &pattern_));
+ }
+
+ CompressedRowSparseMatrix::ComputeOuterProduct(
+ *A, pattern_, outer_product_.get());
+
+ // Map to an upper triangular column major matrix.
+ //
+ // outer_product_ is a compressed row sparse matrix and in lower
+ // triangular form, when mapped to a compressed column sparse
+ // matrix, it becomes an upper triangular matrix.
+ Eigen::MappedSparseMatrix<double, Eigen::ColMajor> lhs(
+ outer_product_->num_rows(),
+ outer_product_->num_rows(),
+ outer_product_->num_nonzeros(),
+ outer_product_->mutable_rows(),
+ outer_product_->mutable_cols(),
+ outer_product_->mutable_values());
+
+ bool do_symbolic_analysis = false;
+
+ // If using post ordering or an old version of Eigen, we cannot
+ // depend on a preordered jacobian, so we work with a SimplicialLDLT
+ // decomposition with AMD ordering.
+ if (options_.use_postordering ||
+ !EIGEN_VERSION_AT_LEAST(3, 2, 2)) {
+ if (amd_ldlt_.get() == NULL) {
+ amd_ldlt_.reset(new SimplicialLDLTWithAMDOrdering);
+ do_symbolic_analysis = true;
+ }
+
+ return SimplicialLDLTSolve(lhs,
+ do_symbolic_analysis,
+ amd_ldlt_.get(),
+ rhs_and_solution,
+ &event_logger);
+ }
+
+#if EIGEN_VERSION_AT_LEAST(3,2,2)
+ // The common case
+ if (natural_ldlt_.get() == NULL) {
+ natural_ldlt_.reset(new SimplicialLDLTWithNaturalOrdering);
+ do_symbolic_analysis = true;
+ }
+
+ return SimplicialLDLTSolve(lhs,
+ do_symbolic_analysis,
+ natural_ldlt_.get(),
+ rhs_and_solution,
+ &event_logger);
+#endif
+
+#endif // EIGEN_USE_EIGEN_SPARSE
+}
+
+LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
+ CompressedRowSparseMatrix* A,
+ double * rhs_and_solution) {
+#ifdef CERES_NO_CXSPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_NORMAL_CHOLESKY cannot be used with CX_SPARSE "
+ "because Ceres was not built with support for CXSparse. "
+ "This requires enabling building with -DCXSPARSE=ON.";
+
+ return summary;
+
+#else
+
+ EventLogger event_logger("SparseNormalCholeskySolver::CXSparse::Solve");
+ if (options_.dynamic_sparsity) {
+ return ComputeNormalEquationsAndSolveUsingCXSparse(A,
+ rhs_and_solution,
+ &event_logger);
+ }
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 1;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.message = "Success.";
+
+ // Compute the normal equations. J'J delta = J'f and solve them
+ // using a sparse Cholesky factorization. Notice that when compared
+ // to SuiteSparse we have to explicitly compute the normal equations
+ // before they can be factorized. CHOLMOD/SuiteSparse on the other
+ // hand can just work off of Jt to compute the Cholesky
+ // factorization of the normal equations.
+ if (outer_product_.get() == NULL) {
+ outer_product_.reset(
+ CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
+ *A, &pattern_));
+ }
+
+ CompressedRowSparseMatrix::ComputeOuterProduct(
+ *A, pattern_, outer_product_.get());
+ cs_di lhs =
+ cxsparse_.CreateSparseMatrixTransposeView(outer_product_.get());
+
+ event_logger.AddEvent("Setup");
+
+ // Compute symbolic factorization if not available.
+ if (cxsparse_factor_ == NULL) {
+ if (options_.use_postordering) {
+ cxsparse_factor_ = cxsparse_.BlockAnalyzeCholesky(&lhs,
+ A->col_blocks(),
+ A->col_blocks());
+ } else {
+ cxsparse_factor_ = cxsparse_.AnalyzeCholeskyWithNaturalOrdering(&lhs);
+ }
+ }
+ event_logger.AddEvent("Analysis");
+
+ if (cxsparse_factor_ == NULL) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "CXSparse failure. Unable to find symbolic factorization.";
+ } else if (!cxsparse_.SolveCholesky(&lhs,
+ cxsparse_factor_,
+ rhs_and_solution)) {
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ summary.message = "CXSparse::SolveCholesky failed.";
+ }
+ event_logger.AddEvent("Solve");
+
+ return summary;
+#endif
+}
+
+LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
+ CompressedRowSparseMatrix* A,
+ double * rhs_and_solution) {
+#ifdef CERES_NO_SUITESPARSE
+
+ LinearSolver::Summary summary;
+ summary.num_iterations = 0;
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ summary.message =
+ "SPARSE_NORMAL_CHOLESKY cannot be used with SUITE_SPARSE "
+ "because Ceres was not built with support for SuiteSparse. "
+ "This requires enabling building with -DSUITESPARSE=ON.";
+ return summary;
+
+#else
+
+ EventLogger event_logger("SparseNormalCholeskySolver::SuiteSparse::Solve");
+ LinearSolver::Summary summary;
+ summary.termination_type = LINEAR_SOLVER_SUCCESS;
+ summary.num_iterations = 1;
+ summary.message = "Success.";
+
+ const int num_cols = A->num_cols();
+ cholmod_sparse lhs = ss_.CreateSparseMatrixTransposeView(A);
+ event_logger.AddEvent("Setup");
+
+ if (options_.dynamic_sparsity) {
+ FreeFactorization();
+ }
+
+ if (factor_ == NULL) {
+ if (options_.use_postordering) {
+ factor_ = ss_.BlockAnalyzeCholesky(&lhs,
+ A->col_blocks(),
+ A->row_blocks(),
+ &summary.message);
+ } else {
+ if (options_.dynamic_sparsity) {
+ factor_ = ss_.AnalyzeCholesky(&lhs, &summary.message);
+ } else {
+ factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&lhs,
+ &summary.message);
+ }
+ }
+ }
+ event_logger.AddEvent("Analysis");
+
+ if (factor_ == NULL) {
+ summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+ // No need to set message as it has already been set by the
+ // symbolic analysis routines above.
+ return summary;
+ }
+
+ summary.termination_type = ss_.Cholesky(&lhs, factor_, &summary.message);
+ if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
+ return summary;
+ }
+
+ cholmod_dense* rhs = ss_.CreateDenseVector(rhs_and_solution,
+ num_cols,
+ num_cols);
+ cholmod_dense* solution = ss_.Solve(factor_, rhs, &summary.message);
+ event_logger.AddEvent("Solve");
+
+ ss_.Free(rhs);
+ if (solution != NULL) {
+ memcpy(rhs_and_solution, solution->x, num_cols * sizeof(*rhs_and_solution));
+ ss_.Free(solution);
+ } else {
+ // No need to set message as it has already been set by the
+ // numeric factorization routine above.
+ summary.termination_type = LINEAR_SOLVER_FAILURE;
+ }
+
+ event_logger.AddEvent("Teardown");
+ return summary;
+#endif
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h
new file mode 100644
index 00000000000..2a93bc56d29
--- /dev/null
+++ b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.h
@@ -0,0 +1,127 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// A solver for sparse linear least squares problem based on solving
+// the normal equations via a sparse cholesky factorization.
+
+#ifndef CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
+#define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
+
+#include <vector>
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#include "ceres/internal/macros.h"
+#include "ceres/linear_solver.h"
+#include "ceres/suitesparse.h"
+#include "ceres/cxsparse.h"
+
+#ifdef CERES_USE_EIGEN_SPARSE
+#include "Eigen/SparseCholesky"
+#endif
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+
+// Solves the normal equations (A'A + D'D) x = A'b, using the CHOLMOD sparse
+// cholesky solver.
+class SparseNormalCholeskySolver : public CompressedRowSparseMatrixSolver {
+ public:
+ explicit SparseNormalCholeskySolver(const LinearSolver::Options& options);
+ virtual ~SparseNormalCholeskySolver();
+
+ private:
+ virtual LinearSolver::Summary SolveImpl(
+ CompressedRowSparseMatrix* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& options,
+ double* x);
+
+ LinearSolver::Summary SolveImplUsingSuiteSparse(
+ CompressedRowSparseMatrix* A,
+ double* rhs_and_solution);
+
+
+ LinearSolver::Summary SolveImplUsingCXSparse(
+ CompressedRowSparseMatrix* A,
+ double* rhs_and_solution);
+
+ LinearSolver::Summary SolveImplUsingEigen(
+ CompressedRowSparseMatrix* A,
+ double* rhs_and_solution);
+
+ void FreeFactorization();
+
+ SuiteSparse ss_;
+ // Cached factorization
+ cholmod_factor* factor_;
+
+ CXSparse cxsparse_;
+ // Cached factorization
+ cs_dis* cxsparse_factor_;
+
+#ifdef CERES_USE_EIGEN_SPARSE
+
+ // The preprocessor gymnastics here are dealing with the fact that
+ // before version 3.2.2, Eigen did not support a third template
+ // parameter to specify the ordering.
+#if EIGEN_VERSION_AT_LEAST(3,2,2)
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper,
+ Eigen::NaturalOrdering<int> >
+ SimplicialLDLTWithNaturalOrdering;
+ scoped_ptr<SimplicialLDLTWithNaturalOrdering> natural_ldlt_;
+
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper,
+ Eigen::AMDOrdering<int> >
+ SimplicialLDLTWithAMDOrdering;
+ scoped_ptr<SimplicialLDLTWithAMDOrdering> amd_ldlt_;
+
+#else
+ typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper>
+ SimplicialLDLTWithAMDOrdering;
+
+ scoped_ptr<SimplicialLDLTWithAMDOrdering> amd_ldlt_;
+#endif
+
+#endif
+
+ scoped_ptr<CompressedRowSparseMatrix> outer_product_;
+ std::vector<int> pattern_;
+ const LinearSolver::Options options_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(SparseNormalCholeskySolver);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/extern/ceres/internal/ceres/split.cc b/extern/ceres/internal/ceres/split.cc
new file mode 100644
index 00000000000..296c09a6440
--- /dev/null
+++ b/extern/ceres/internal/ceres/split.cc
@@ -0,0 +1,123 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#include "ceres/split.h"
+
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+using std::vector;
+
+// If we know how much to allocate for a vector of strings, we can allocate the
+// vector<string> only once and directly to the right size. This saves in
+// between 33-66 % of memory space needed for the result, and runs faster in the
+// microbenchmarks.
+//
+// The reserve is only implemented for the single character delim.
+//
+// The implementation for counting is cut-and-pasted from
+// SplitStringToIteratorUsing. I could have written my own counting iterator,
+// and use the existing template function, but probably this is more clear and
+// more sure to get optimized to reasonable code.
+static int CalculateReserveForVector(const string& full, const char* delim) {
+ int count = 0;
+ if (delim[0] != '\0' && delim[1] == '\0') {
+ // Optimize the common case where delim is a single character.
+ char c = delim[0];
+ const char* p = full.data();
+ const char* end = p + full.size();
+ while (p != end) {
+ if (*p == c) { // This could be optimized with hasless(v,1) trick.
+ ++p;
+ } else {
+ while (++p != end && *p != c) {
+ // Skip to the next occurence of the delimiter.
+ }
+ ++count;
+ }
+ }
+ }
+ return count;
+}
+
+template <typename StringType, typename ITR>
+static inline
+void SplitStringToIteratorUsing(const StringType& full,
+ const char* delim,
+ ITR& result) {
+ // Optimize the common case where delim is a single character.
+ if (delim[0] != '\0' && delim[1] == '\0') {
+ char c = delim[0];
+ const char* p = full.data();
+ const char* end = p + full.size();
+ while (p != end) {
+ if (*p == c) {
+ ++p;
+ } else {
+ const char* start = p;
+ while (++p != end && *p != c) {
+ // Skip to the next occurence of the delimiter.
+ }
+ *result++ = StringType(start, p - start);
+ }
+ }
+ return;
+ }
+
+ string::size_type begin_index, end_index;
+ begin_index = full.find_first_not_of(delim);
+ while (begin_index != string::npos) {
+ end_index = full.find_first_of(delim, begin_index);
+ if (end_index == string::npos) {
+ *result++ = full.substr(begin_index);
+ return;
+ }
+ *result++ = full.substr(begin_index, (end_index - begin_index));
+ begin_index = full.find_first_not_of(delim, end_index);
+ }
+}
+
+void SplitStringUsing(const string& full,
+ const char* delim,
+ vector<string>* result) {
+ result->reserve(result->size() + CalculateReserveForVector(full, delim));
+ std::back_insert_iterator<vector<string> > it(*result);
+ SplitStringToIteratorUsing(full, delim, it);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/split.h b/extern/ceres/internal/ceres/split.h
new file mode 100644
index 00000000000..94b773dee4d
--- /dev/null
+++ b/extern/ceres/internal/ceres/split.h
@@ -0,0 +1,50 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_SPLIT_H_
+#define CERES_INTERNAL_SPLIT_H_
+
+#include <string>
+#include <vector>
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+// Split a string using one or more character delimiters, presented as a
+// nul-terminated c string. Append the components to 'result'. If there are
+// consecutive delimiters, this function skips over all of them.
+void SplitStringUsing(const std::string& full, const char* delim,
+ std::vector<std::string>* res);
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_SPLIT_H_
diff --git a/extern/ceres/internal/ceres/stl_util.h b/extern/ceres/internal/ceres/stl_util.h
new file mode 100644
index 00000000000..0595a4cf2e9
--- /dev/null
+++ b/extern/ceres/internal/ceres/stl_util.h
@@ -0,0 +1,91 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keir@google.com (Keir Mierle)
+
+#ifndef CERES_INTERNAL_STL_UTIL_H_
+#define CERES_INTERNAL_STL_UTIL_H_
+
+#include <algorithm>
+
+namespace ceres {
+
+// STLDeleteContainerPointers()
+// For a range within a container of pointers, calls delete
+// (non-array version) on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
+// Variant of STLDeleteContainerPointers which allows the container to
+// contain duplicates.
+template <class ForwardIterator>
+void STLDeleteUniqueContainerPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ sort(begin, end);
+ ForwardIterator new_end = unique(begin, end);
+ while (begin != new_end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container. This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// ElementDeleter (defined below), which ensures that your container's elements
+// are deleted when the ElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T *container) {
+ if (!container) return;
+ STLDeleteContainerPointers(container->begin(), container->end());
+ container->clear();
+}
+
+} // namespace ceres
+
+#endif // CERES_INTERNAL_STL_UTIL_H_
diff --git a/extern/ceres/internal/ceres/stringprintf.cc b/extern/ceres/internal/ceres/stringprintf.cc
new file mode 100644
index 00000000000..d1d8b5fe8ab
--- /dev/null
+++ b/extern/ceres/internal/ceres/stringprintf.cc
@@ -0,0 +1,132 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Sanjay Ghemawat
+
+#include "ceres/stringprintf.h"
+
+#include <cerrno>
+#include <cstdarg> // For va_list and related operations
+#include <cstdio> // MSVC requires this for _vsnprintf
+#include <string>
+#include <vector>
+
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+using std::string;
+
+#ifdef _MSC_VER
+enum { IS_COMPILER_MSVC = 1 };
+#if _MSC_VER < 1800
+#define va_copy(d, s) ((d) = (s))
+#endif
+#else
+enum { IS_COMPILER_MSVC = 0 };
+#endif
+
+void StringAppendV(string* dst, const char* format, va_list ap) {
+ // First try with a small fixed size buffer
+ char space[1024];
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int result = vsnprintf(space, sizeof(space), format, backup_ap);
+ va_end(backup_ap);
+
+ if (result < sizeof(space)) {
+ if (result >= 0) {
+ // Normal case -- everything fit.
+ dst->append(space, result);
+ return;
+ }
+
+ if (IS_COMPILER_MSVC) {
+ // Error or MSVC running out of space. MSVC 8.0 and higher
+ // can be asked about space needed with the special idiom below:
+ va_copy(backup_ap, ap);
+ result = vsnprintf(NULL, 0, format, backup_ap);
+ va_end(backup_ap);
+ }
+
+ if (result < 0) {
+ // Just an error.
+ return;
+ }
+ }
+
+ // Increase the buffer size to the size requested by vsnprintf,
+ // plus one for the closing \0.
+ int length = result+1;
+ char* buf = new char[length];
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ result = vsnprintf(buf, length, format, backup_ap);
+ va_end(backup_ap);
+
+ if (result >= 0 && result < length) {
+ // It fit
+ dst->append(buf, result);
+ }
+ delete[] buf;
+}
+
+
+string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+const string& SStringPrintf(string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+void StringAppendF(string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/stringprintf.h b/extern/ceres/internal/ceres/stringprintf.h
new file mode 100644
index 00000000000..feeb9c23430
--- /dev/null
+++ b/extern/ceres/internal/ceres/stringprintf.h
@@ -0,0 +1,89 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Sanjay Ghemawat
+//
+// Printf variants that place their output in a C++ string.
+//
+// Usage:
+// string result = StringPrintf("%d %s\n", 10, "hello");
+// SStringPrintf(&result, "%d %s\n", 10, "hello");
+// StringAppendF(&result, "%d %s\n", 20, "there");
+
+#ifndef CERES_INTERNAL_STRINGPRINTF_H_
+#define CERES_INTERNAL_STRINGPRINTF_H_
+
+#include <cstdarg>
+#include <string>
+
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+#if (defined(__GNUC__) || defined(__clang__))
+// Tell the compiler to do printf format string checking if the compiler
+// supports it; see the 'format' attribute in
+// <http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html>.
+//
+// N.B.: As the GCC manual states, "[s]ince non-static C++ methods
+// have an implicit 'this' argument, the arguments of such methods
+// should be counted from two, not one."
+#define CERES_PRINTF_ATTRIBUTE(string_index, first_to_check) \
+ __attribute__((__format__ (__printf__, string_index, first_to_check)))
+#define CERES_SCANF_ATTRIBUTE(string_index, first_to_check) \
+ __attribute__((__format__ (__scanf__, string_index, first_to_check)))
+#else
+#define CERES_PRINTF_ATTRIBUTE(string_index, first_to_check)
+#endif
+
+// Return a C++ string.
+extern std::string StringPrintf(const char* format, ...)
+ // Tell the compiler to do printf format string checking.
+ CERES_PRINTF_ATTRIBUTE(1, 2);
+
+// Store result into a supplied string and return it.
+extern const std::string& SStringPrintf(std::string* dst, const char* format, ...)
+ // Tell the compiler to do printf format string checking.
+ CERES_PRINTF_ATTRIBUTE(2, 3);
+
+// Append result to a supplied string.
+extern void StringAppendF(std::string* dst, const char* format, ...)
+ // Tell the compiler to do printf format string checking.
+ CERES_PRINTF_ATTRIBUTE(2, 3);
+
+// Lower-level routine that takes a va_list and appends to a specified string.
+// All other routines are just convenience wrappers around it.
+extern void StringAppendV(std::string* dst, const char* format, va_list ap);
+
+#undef CERES_PRINTF_ATTRIBUTE
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_STRINGPRINTF_H_
diff --git a/extern/ceres/internal/ceres/suitesparse.h b/extern/ceres/internal/ceres/suitesparse.h
new file mode 100644
index 00000000000..380d76e003a
--- /dev/null
+++ b/extern/ceres/internal/ceres/suitesparse.h
@@ -0,0 +1,306 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// A simple C++ interface to the SuiteSparse and CHOLMOD libraries.
+
+#ifndef CERES_INTERNAL_SUITESPARSE_H_
+#define CERES_INTERNAL_SUITESPARSE_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+#include "ceres/internal/port.h"
+
+#ifndef CERES_NO_SUITESPARSE
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "ceres/linear_solver.h"
+#include "cholmod.h"
+#include "glog/logging.h"
+#include "SuiteSparseQR.hpp"
+
+// Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
+// if SuiteSparse was compiled with Metis support. This makes
+// calling and linking into cholmod_camd problematic even though it
+// has nothing to do with Metis. This has been fixed reliably in
+// 4.2.0.
+//
+// The fix was actually committed in 4.1.0, but there is
+// some confusion about a silent update to the tar ball, so we are
+// being conservative and choosing the next minor version where
+// things are stable.
+#if (SUITESPARSE_VERSION < 4002)
+#define CERES_NO_CAMD
+#endif
+
+// UF_long is deprecated but SuiteSparse_long is only available in
+// newer versions of SuiteSparse. So for older versions of
+// SuiteSparse, we define SuiteSparse_long to be the same as UF_long,
+// which is what recent versions of SuiteSparse do anyways.
+#ifndef SuiteSparse_long
+#define SuiteSparse_long UF_long
+#endif
+
+namespace ceres {
+namespace internal {
+
+class CompressedRowSparseMatrix;
+class TripletSparseMatrix;
+
+// The raw CHOLMOD and SuiteSparseQR libraries have a slightly
+// cumbersome c like calling format. This object abstracts it away and
+// provides the user with a simpler interface. The methods here cannot
+// be static as a cholmod_common object serves as a global variable
+// for all cholmod function calls.
+class SuiteSparse {
+ public:
+ SuiteSparse();
+ ~SuiteSparse();
+
+ // Functions for building cholmod_sparse objects from sparse
+ // matrices stored in triplet form. The matrix A is not
+ // modifed. Called owns the result.
+ cholmod_sparse* CreateSparseMatrix(TripletSparseMatrix* A);
+
+ // This function works like CreateSparseMatrix, except that the
+ // return value corresponds to A' rather than A.
+ cholmod_sparse* CreateSparseMatrixTranspose(TripletSparseMatrix* A);
+
+ // Create a cholmod_sparse wrapper around the contents of A. This is
+ // a shallow object, which refers to the contents of A and does not
+ // use the SuiteSparse machinery to allocate memory.
+ cholmod_sparse CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
+
+ // Given a vector x, build a cholmod_dense vector of size out_size
+ // with the first in_size entries copied from x. If x is NULL, then
+ // an all zeros vector is returned. Caller owns the result.
+ cholmod_dense* CreateDenseVector(const double* x, int in_size, int out_size);
+
+ // The matrix A is scaled using the matrix whose diagonal is the
+ // vector scale. mode describes how scaling is applied. Possible
+ // values are CHOLMOD_ROW for row scaling - diag(scale) * A,
+ // CHOLMOD_COL for column scaling - A * diag(scale) and CHOLMOD_SYM
+ // for symmetric scaling which scales both the rows and the columns
+ // - diag(scale) * A * diag(scale).
+ void Scale(cholmod_dense* scale, int mode, cholmod_sparse* A) {
+ cholmod_scale(scale, mode, A, &cc_);
+ }
+
+ // Create and return a matrix m = A * A'. Caller owns the
+ // result. The matrix A is not modified.
+ cholmod_sparse* AATranspose(cholmod_sparse* A) {
+ cholmod_sparse*m = cholmod_aat(A, NULL, A->nrow, 1, &cc_);
+ m->stype = 1; // Pay attention to the upper triangular part.
+ return m;
+ }
+
+ // y = alpha * A * x + beta * y. Only y is modified.
+ void SparseDenseMultiply(cholmod_sparse* A, double alpha, double beta,
+ cholmod_dense* x, cholmod_dense* y) {
+ double alpha_[2] = {alpha, 0};
+ double beta_[2] = {beta, 0};
+ cholmod_sdmult(A, 0, alpha_, beta_, x, y, &cc_);
+ }
+
+ // Find an ordering of A or AA' (if A is unsymmetric) that minimizes
+ // the fill-in in the Cholesky factorization of the corresponding
+ // matrix. This is done by using the AMD algorithm.
+ //
+ // Using this ordering, the symbolic Cholesky factorization of A (or
+ // AA') is computed and returned.
+ //
+ // A is not modified, only the pattern of non-zeros of A is used,
+ // the actual numerical values in A are of no consequence.
+ //
+ // message contains an explanation of the failures if any.
+ //
+ // Caller owns the result.
+ cholmod_factor* AnalyzeCholesky(cholmod_sparse* A, std::string* message);
+
+ cholmod_factor* BlockAnalyzeCholesky(cholmod_sparse* A,
+ const std::vector<int>& row_blocks,
+ const std::vector<int>& col_blocks,
+ std::string* message);
+
+ // If A is symmetric, then compute the symbolic Cholesky
+ // factorization of A(ordering, ordering). If A is unsymmetric, then
+ // compute the symbolic factorization of
+ // A(ordering,:) A(ordering,:)'.
+ //
+ // A is not modified, only the pattern of non-zeros of A is used,
+ // the actual numerical values in A are of no consequence.
+ //
+ // message contains an explanation of the failures if any.
+ //
+ // Caller owns the result.
+ cholmod_factor* AnalyzeCholeskyWithUserOrdering(
+ cholmod_sparse* A,
+ const std::vector<int>& ordering,
+ std::string* message);
+
+ // Perform a symbolic factorization of A without re-ordering A. No
+ // postordering of the elimination tree is performed. This ensures
+ // that the symbolic factor does not introduce an extra permutation
+ // on the matrix. See the documentation for CHOLMOD for more details.
+ //
+ // message contains an explanation of the failures if any.
+ cholmod_factor* AnalyzeCholeskyWithNaturalOrdering(cholmod_sparse* A,
+ std::string* message);
+
+ // Use the symbolic factorization in L, to find the numerical
+ // factorization for the matrix A or AA^T. Return true if
+ // successful, false otherwise. L contains the numeric factorization
+ // on return.
+ //
+ // message contains an explanation of the failures if any.
+ LinearSolverTerminationType Cholesky(cholmod_sparse* A,
+ cholmod_factor* L,
+ std::string* message);
+
+ // Given a Cholesky factorization of a matrix A = LL^T, solve the
+ // linear system Ax = b, and return the result. If the Solve fails
+ // NULL is returned. Caller owns the result.
+ //
+ // message contains an explanation of the failures if any.
+ cholmod_dense* Solve(cholmod_factor* L, cholmod_dense* b, std::string* message);
+
+ // By virtue of the modeling layer in Ceres being block oriented,
+ // all the matrices used by Ceres are also block oriented. When
+ // doing sparse direct factorization of these matrices the
+ // fill-reducing ordering algorithms (in particular AMD) can either
+ // be run on the block or the scalar form of these matrices. The two
+ // SuiteSparse::AnalyzeCholesky methods allows the the client to
+ // compute the symbolic factorization of a matrix by either using
+ // AMD on the matrix or a user provided ordering of the rows.
+ //
+ // But since the underlying matrices are block oriented, it is worth
+ // running AMD on just the block structre of these matrices and then
+ // lifting these block orderings to a full scalar ordering. This
+ // preserves the block structure of the permuted matrix, and exposes
+ // more of the super-nodal structure of the matrix to the numerical
+ // factorization routines.
+ //
+ // Find the block oriented AMD ordering of a matrix A, whose row and
+ // column blocks are given by row_blocks, and col_blocks
+ // respectively. The matrix may or may not be symmetric. The entries
+ // of col_blocks do not need to sum to the number of columns in
+ // A. If this is the case, only the first sum(col_blocks) are used
+ // to compute the ordering.
+ bool BlockAMDOrdering(const cholmod_sparse* A,
+ const std::vector<int>& row_blocks,
+ const std::vector<int>& col_blocks,
+ std::vector<int>* ordering);
+
+ // Find a fill reducing approximate minimum degree
+ // ordering. ordering is expected to be large enough to hold the
+ // ordering.
+ bool ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix, int* ordering);
+
+
+ // Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
+ // if SuiteSparse was compiled with Metis support. This makes
+ // calling and linking into cholmod_camd problematic even though it
+ // has nothing to do with Metis. This has been fixed reliably in
+ // 4.2.0.
+ //
+ // The fix was actually committed in 4.1.0, but there is
+ // some confusion about a silent update to the tar ball, so we are
+ // being conservative and choosing the next minor version where
+ // things are stable.
+ static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
+ return (SUITESPARSE_VERSION > 4001);
+ }
+
+ // Find a fill reducing approximate minimum degree
+ // ordering. constraints is an array which associates with each
+ // column of the matrix an elimination group. i.e., all columns in
+ // group 0 are eliminated first, all columns in group 1 are
+ // eliminated next etc. This function finds a fill reducing ordering
+ // that obeys these constraints.
+ //
+ // Calling ApproximateMinimumDegreeOrdering is equivalent to calling
+ // ConstrainedApproximateMinimumDegreeOrdering with a constraint
+ // array that puts all columns in the same elimination group.
+ //
+ // If CERES_NO_CAMD is defined then calling this function will
+ // result in a crash.
+ bool ConstrainedApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
+ int* constraints,
+ int* ordering);
+
+ void Free(cholmod_sparse* m) { cholmod_free_sparse(&m, &cc_); }
+ void Free(cholmod_dense* m) { cholmod_free_dense(&m, &cc_); }
+ void Free(cholmod_factor* m) { cholmod_free_factor(&m, &cc_); }
+
+ void Print(cholmod_sparse* m, const std::string& name) {
+ cholmod_print_sparse(m, const_cast<char*>(name.c_str()), &cc_);
+ }
+
+ void Print(cholmod_dense* m, const std::string& name) {
+ cholmod_print_dense(m, const_cast<char*>(name.c_str()), &cc_);
+ }
+
+ void Print(cholmod_triplet* m, const std::string& name) {
+ cholmod_print_triplet(m, const_cast<char*>(name.c_str()), &cc_);
+ }
+
+ cholmod_common* mutable_cc() { return &cc_; }
+
+ private:
+ cholmod_common cc_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#else // CERES_NO_SUITESPARSE
+
+typedef void cholmod_factor;
+
+class SuiteSparse {
+ public:
+ // Defining this static function even when SuiteSparse is not
+ // available, allows client code to check for the presence of CAMD
+ // without checking for the absence of the CERES_NO_CAMD symbol.
+ //
+ // This is safer because the symbol maybe missing due to a user
+ // accidently not including suitesparse.h in their code when
+ // checking for the symbol.
+ static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
+ return false;
+ }
+
+ void Free(void* arg) {}
+};
+
+#endif // CERES_NO_SUITESPARSE
+
+#endif // CERES_INTERNAL_SUITESPARSE_H_
diff --git a/extern/ceres/internal/ceres/triplet_sparse_matrix.cc b/extern/ceres/internal/ceres/triplet_sparse_matrix.cc
new file mode 100644
index 00000000000..8df405ca115
--- /dev/null
+++ b/extern/ceres/internal/ceres/triplet_sparse_matrix.cc
@@ -0,0 +1,264 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/triplet_sparse_matrix.h"
+
+#include <algorithm>
+#include <cstddef>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+TripletSparseMatrix::TripletSparseMatrix()
+ : num_rows_(0),
+ num_cols_(0),
+ max_num_nonzeros_(0),
+ num_nonzeros_(0),
+ rows_(NULL),
+ cols_(NULL),
+ values_(NULL) {}
+
+TripletSparseMatrix::~TripletSparseMatrix() {}
+
+TripletSparseMatrix::TripletSparseMatrix(int num_rows,
+ int num_cols,
+ int max_num_nonzeros)
+ : num_rows_(num_rows),
+ num_cols_(num_cols),
+ max_num_nonzeros_(max_num_nonzeros),
+ num_nonzeros_(0),
+ rows_(NULL),
+ cols_(NULL),
+ values_(NULL) {
+ // All the sizes should at least be zero
+ CHECK_GE(num_rows, 0);
+ CHECK_GE(num_cols, 0);
+ CHECK_GE(max_num_nonzeros, 0);
+ AllocateMemory();
+}
+
+TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig)
+ : SparseMatrix(),
+ num_rows_(orig.num_rows_),
+ num_cols_(orig.num_cols_),
+ max_num_nonzeros_(orig.max_num_nonzeros_),
+ num_nonzeros_(orig.num_nonzeros_),
+ rows_(NULL),
+ cols_(NULL),
+ values_(NULL) {
+ AllocateMemory();
+ CopyData(orig);
+}
+
+TripletSparseMatrix& TripletSparseMatrix::operator=(
+ const TripletSparseMatrix& rhs) {
+ num_rows_ = rhs.num_rows_;
+ num_cols_ = rhs.num_cols_;
+ num_nonzeros_ = rhs.num_nonzeros_;
+ max_num_nonzeros_ = rhs.max_num_nonzeros_;
+ AllocateMemory();
+ CopyData(rhs);
+ return *this;
+}
+
+bool TripletSparseMatrix::AllTripletsWithinBounds() const {
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ if ((rows_[i] < 0) || (rows_[i] >= num_rows_) ||
+ (cols_[i] < 0) || (cols_[i] >= num_cols_))
+ return false;
+ }
+ return true;
+}
+
+void TripletSparseMatrix::Reserve(int new_max_num_nonzeros) {
+ CHECK_LE(num_nonzeros_, new_max_num_nonzeros)
+ << "Reallocation will cause data loss";
+
+ // Nothing to do if we have enough space already.
+ if (new_max_num_nonzeros <= max_num_nonzeros_)
+ return;
+
+ int* new_rows = new int[new_max_num_nonzeros];
+ int* new_cols = new int[new_max_num_nonzeros];
+ double* new_values = new double[new_max_num_nonzeros];
+
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ new_rows[i] = rows_[i];
+ new_cols[i] = cols_[i];
+ new_values[i] = values_[i];
+ }
+
+ rows_.reset(new_rows);
+ cols_.reset(new_cols);
+ values_.reset(new_values);
+
+ max_num_nonzeros_ = new_max_num_nonzeros;
+}
+
+void TripletSparseMatrix::SetZero() {
+ std::fill(values_.get(), values_.get() + max_num_nonzeros_, 0.0);
+ num_nonzeros_ = 0;
+}
+
+void TripletSparseMatrix::set_num_nonzeros(int num_nonzeros) {
+ CHECK_GE(num_nonzeros, 0);
+ CHECK_LE(num_nonzeros, max_num_nonzeros_);
+ num_nonzeros_ = num_nonzeros;
+}
+
+void TripletSparseMatrix::AllocateMemory() {
+ rows_.reset(new int[max_num_nonzeros_]);
+ cols_.reset(new int[max_num_nonzeros_]);
+ values_.reset(new double[max_num_nonzeros_]);
+}
+
+void TripletSparseMatrix::CopyData(const TripletSparseMatrix& orig) {
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ rows_[i] = orig.rows_[i];
+ cols_[i] = orig.cols_[i];
+ values_[i] = orig.values_[i];
+ }
+}
+
+void TripletSparseMatrix::RightMultiply(const double* x, double* y) const {
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ y[rows_[i]] += values_[i]*x[cols_[i]];
+ }
+}
+
+void TripletSparseMatrix::LeftMultiply(const double* x, double* y) const {
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ y[cols_[i]] += values_[i]*x[rows_[i]];
+ }
+}
+
+void TripletSparseMatrix::SquaredColumnNorm(double* x) const {
+ CHECK_NOTNULL(x);
+ VectorRef(x, num_cols_).setZero();
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ x[cols_[i]] += values_[i] * values_[i];
+ }
+}
+
+void TripletSparseMatrix::ScaleColumns(const double* scale) {
+ CHECK_NOTNULL(scale);
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ values_[i] = values_[i] * scale[cols_[i]];
+ }
+}
+
+void TripletSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
+ dense_matrix->resize(num_rows_, num_cols_);
+ dense_matrix->setZero();
+ Matrix& m = *dense_matrix;
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ m(rows_[i], cols_[i]) += values_[i];
+ }
+}
+
+void TripletSparseMatrix::AppendRows(const TripletSparseMatrix& B) {
+ CHECK_EQ(B.num_cols(), num_cols_);
+ Reserve(num_nonzeros_ + B.num_nonzeros_);
+ for (int i = 0; i < B.num_nonzeros_; ++i) {
+ rows_.get()[num_nonzeros_] = B.rows()[i] + num_rows_;
+ cols_.get()[num_nonzeros_] = B.cols()[i];
+ values_.get()[num_nonzeros_++] = B.values()[i];
+ }
+ num_rows_ = num_rows_ + B.num_rows();
+}
+
+void TripletSparseMatrix::AppendCols(const TripletSparseMatrix& B) {
+ CHECK_EQ(B.num_rows(), num_rows_);
+ Reserve(num_nonzeros_ + B.num_nonzeros_);
+ for (int i = 0; i < B.num_nonzeros_; ++i, ++num_nonzeros_) {
+ rows_.get()[num_nonzeros_] = B.rows()[i];
+ cols_.get()[num_nonzeros_] = B.cols()[i] + num_cols_;
+ values_.get()[num_nonzeros_] = B.values()[i];
+ }
+ num_cols_ = num_cols_ + B.num_cols();
+}
+
+
+void TripletSparseMatrix::Resize(int new_num_rows, int new_num_cols) {
+ if ((new_num_rows >= num_rows_) && (new_num_cols >= num_cols_)) {
+ num_rows_ = new_num_rows;
+ num_cols_ = new_num_cols;
+ return;
+ }
+
+ num_rows_ = new_num_rows;
+ num_cols_ = new_num_cols;
+
+ int* r_ptr = rows_.get();
+ int* c_ptr = cols_.get();
+ double* v_ptr = values_.get();
+
+ int dropped_terms = 0;
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ if ((r_ptr[i] < num_rows_) && (c_ptr[i] < num_cols_)) {
+ if (dropped_terms) {
+ r_ptr[i-dropped_terms] = r_ptr[i];
+ c_ptr[i-dropped_terms] = c_ptr[i];
+ v_ptr[i-dropped_terms] = v_ptr[i];
+ }
+ } else {
+ ++dropped_terms;
+ }
+ }
+ num_nonzeros_ -= dropped_terms;
+}
+
+TripletSparseMatrix* TripletSparseMatrix::CreateSparseDiagonalMatrix(
+ const double* values, int num_rows) {
+ TripletSparseMatrix* m =
+ new TripletSparseMatrix(num_rows, num_rows, num_rows);
+ for (int i = 0; i < num_rows; ++i) {
+ m->mutable_rows()[i] = i;
+ m->mutable_cols()[i] = i;
+ m->mutable_values()[i] = values[i];
+ }
+ m->set_num_nonzeros(num_rows);
+ return m;
+}
+
+void TripletSparseMatrix::ToTextFile(FILE* file) const {
+ CHECK_NOTNULL(file);
+ for (int i = 0; i < num_nonzeros_; ++i) {
+ fprintf(file, "% 10d % 10d %17f\n", rows_[i], cols_[i], values_[i]);
+ }
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/triplet_sparse_matrix.h b/extern/ceres/internal/ceres/triplet_sparse_matrix.h
new file mode 100644
index 00000000000..f3f5370df6f
--- /dev/null
+++ b/extern/ceres/internal/ceres/triplet_sparse_matrix.h
@@ -0,0 +1,129 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
+
+#include "ceres/sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+// An implementation of the SparseMatrix interface to store and
+// manipulate sparse matrices in triplet (i,j,s) form. This object is
+// inspired by the design of the cholmod_triplet struct used in the
+// SuiteSparse package and is memory layout compatible with it.
+class TripletSparseMatrix : public SparseMatrix {
+ public:
+ TripletSparseMatrix();
+ TripletSparseMatrix(int num_rows, int num_cols, int max_num_nonzeros);
+ explicit TripletSparseMatrix(const TripletSparseMatrix& orig);
+
+ TripletSparseMatrix& operator=(const TripletSparseMatrix& rhs);
+
+ ~TripletSparseMatrix();
+
+ // Implementation of the SparseMatrix interface.
+ virtual void SetZero();
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual void LeftMultiply(const double* x, double* y) const;
+ virtual void SquaredColumnNorm(double* x) const;
+ virtual void ScaleColumns(const double* scale);
+ virtual void ToDenseMatrix(Matrix* dense_matrix) const;
+ virtual void ToTextFile(FILE* file) const;
+ virtual int num_rows() const { return num_rows_; }
+ virtual int num_cols() const { return num_cols_; }
+ virtual int num_nonzeros() const { return num_nonzeros_; }
+ virtual const double* values() const { return values_.get(); }
+ virtual double* mutable_values() { return values_.get(); }
+ virtual void set_num_nonzeros(int num_nonzeros);
+
+ // Increase max_num_nonzeros and correspondingly increase the size
+ // of rows_, cols_ and values_. If new_max_num_nonzeros is smaller
+ // than max_num_nonzeros_, then num_non_zeros should be less than or
+ // equal to new_max_num_nonzeros, otherwise data loss is possible
+ // and the method crashes.
+ void Reserve(int new_max_num_nonzeros);
+
+ // Append the matrix B at the bottom of this matrix. B should have
+ // the same number of columns as num_cols_.
+ void AppendRows(const TripletSparseMatrix& B);
+
+ // Append the matrix B at the right of this matrix. B should have
+ // the same number of rows as num_rows_;
+ void AppendCols(const TripletSparseMatrix& B);
+
+ // Resize the matrix. Entries which fall outside the new matrix
+ // bounds are dropped and the num_non_zeros changed accordingly.
+ void Resize(int new_num_rows, int new_num_cols);
+
+ int max_num_nonzeros() const { return max_num_nonzeros_; }
+ const int* rows() const { return rows_.get(); }
+ const int* cols() const { return cols_.get(); }
+ int* mutable_rows() { return rows_.get(); }
+ int* mutable_cols() { return cols_.get(); }
+
+ // Returns true if the entries of the matrix obey the row, column,
+ // and column size bounds and false otherwise.
+ bool AllTripletsWithinBounds() const;
+
+ bool IsValid() const { return AllTripletsWithinBounds(); }
+
+ // Build a sparse diagonal matrix of size num_rows x num_rows from
+ // the array values. Entries of the values array are copied into the
+ // sparse matrix.
+ static TripletSparseMatrix* CreateSparseDiagonalMatrix(const double* values,
+ int num_rows);
+
+ private:
+ void AllocateMemory();
+ void CopyData(const TripletSparseMatrix& orig);
+
+ int num_rows_;
+ int num_cols_;
+ int max_num_nonzeros_;
+ int num_nonzeros_;
+
+ // The data is stored as three arrays. For each i, values_[i] is
+ // stored at the location (rows_[i], cols_[i]). If the there are
+ // multiple entries with the same (rows_[i], cols_[i]), the values_
+ // entries corresponding to them are summed up.
+ scoped_array<int> rows_;
+ scoped_array<int> cols_;
+ scoped_array<double> values_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H__
diff --git a/extern/ceres/internal/ceres/trust_region_minimizer.cc b/extern/ceres/internal/ceres/trust_region_minimizer.cc
new file mode 100644
index 00000000000..d654d0867f1
--- /dev/null
+++ b/extern/ceres/internal/ceres/trust_region_minimizer.cc
@@ -0,0 +1,716 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/trust_region_minimizer.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include "Eigen/Core"
+#include "ceres/array_utils.h"
+#include "ceres/coordinate_descent_minimizer.h"
+#include "ceres/evaluator.h"
+#include "ceres/file.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/line_search.h"
+#include "ceres/linear_least_squares_problems.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/stringprintf.h"
+#include "ceres/trust_region_strategy.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+namespace {
+
+LineSearch::Summary DoLineSearch(const Minimizer::Options& options,
+ const Vector& x,
+ const Vector& gradient,
+ const double cost,
+ const Vector& delta,
+ Evaluator* evaluator) {
+ LineSearchFunction line_search_function(evaluator);
+
+ LineSearch::Options line_search_options;
+ line_search_options.is_silent = true;
+ line_search_options.interpolation_type =
+ options.line_search_interpolation_type;
+ line_search_options.min_step_size = options.min_line_search_step_size;
+ line_search_options.sufficient_decrease =
+ options.line_search_sufficient_function_decrease;
+ line_search_options.max_step_contraction =
+ options.max_line_search_step_contraction;
+ line_search_options.min_step_contraction =
+ options.min_line_search_step_contraction;
+ line_search_options.max_num_iterations =
+ options.max_num_line_search_step_size_iterations;
+ line_search_options.sufficient_curvature_decrease =
+ options.line_search_sufficient_curvature_decrease;
+ line_search_options.max_step_expansion =
+ options.max_line_search_step_expansion;
+ line_search_options.function = &line_search_function;
+
+ std::string message;
+ scoped_ptr<LineSearch> line_search(
+ CHECK_NOTNULL(LineSearch::Create(ceres::ARMIJO,
+ line_search_options,
+ &message)));
+ LineSearch::Summary summary;
+ line_search_function.Init(x, delta);
+ line_search->Search(1.0, cost, gradient.dot(delta), &summary);
+ return summary;
+}
+
+} // namespace
+
+// Compute a scaling vector that is used to improve the conditioning
+// of the Jacobian.
+void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian,
+ double* scale) const {
+ jacobian.SquaredColumnNorm(scale);
+ for (int i = 0; i < jacobian.num_cols(); ++i) {
+ scale[i] = 1.0 / (1.0 + sqrt(scale[i]));
+ }
+}
+
+void TrustRegionMinimizer::Init(const Minimizer::Options& options) {
+ options_ = options;
+ sort(options_.trust_region_minimizer_iterations_to_dump.begin(),
+ options_.trust_region_minimizer_iterations_to_dump.end());
+}
+
+void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) {
+ double start_time = WallTimeInSeconds();
+ double iteration_start_time = start_time;
+ Init(options);
+
+ Evaluator* evaluator = CHECK_NOTNULL(options_.evaluator.get());
+ SparseMatrix* jacobian = CHECK_NOTNULL(options_.jacobian.get());
+ TrustRegionStrategy* strategy =
+ CHECK_NOTNULL(options_.trust_region_strategy.get());
+
+ const bool is_not_silent = !options.is_silent;
+
+ // If the problem is bounds constrained, then enable the use of a
+ // line search after the trust region step has been computed. This
+ // line search will automatically use a projected test point onto
+ // the feasible set, there by guaranteeing the feasibility of the
+ // final output.
+ //
+ // TODO(sameeragarwal): Make line search available more generally.
+ const bool use_line_search = options.is_constrained;
+
+ summary->termination_type = NO_CONVERGENCE;
+ summary->num_successful_steps = 0;
+ summary->num_unsuccessful_steps = 0;
+ summary->is_constrained = options.is_constrained;
+
+ const int num_parameters = evaluator->NumParameters();
+ const int num_effective_parameters = evaluator->NumEffectiveParameters();
+ const int num_residuals = evaluator->NumResiduals();
+
+ Vector residuals(num_residuals);
+ Vector trust_region_step(num_effective_parameters);
+ Vector delta(num_effective_parameters);
+ Vector x_plus_delta(num_parameters);
+ Vector gradient(num_effective_parameters);
+ Vector model_residuals(num_residuals);
+ Vector scale(num_effective_parameters);
+ Vector negative_gradient(num_effective_parameters);
+ Vector projected_gradient_step(num_parameters);
+
+ IterationSummary iteration_summary;
+ iteration_summary.iteration = 0;
+ iteration_summary.step_is_valid = false;
+ iteration_summary.step_is_successful = false;
+ iteration_summary.cost_change = 0.0;
+ iteration_summary.gradient_max_norm = 0.0;
+ iteration_summary.gradient_norm = 0.0;
+ iteration_summary.step_norm = 0.0;
+ iteration_summary.relative_decrease = 0.0;
+ iteration_summary.trust_region_radius = strategy->Radius();
+ iteration_summary.eta = options_.eta;
+ iteration_summary.linear_solver_iterations = 0;
+ iteration_summary.step_solver_time_in_seconds = 0;
+
+ VectorRef x_min(parameters, num_parameters);
+ Vector x = x_min;
+ // Project onto the feasible set.
+ if (options.is_constrained) {
+ delta.setZero();
+ if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
+ summary->message =
+ "Unable to project initial point onto the feasible set.";
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+ x_min = x_plus_delta;
+ x = x_plus_delta;
+ }
+
+ double x_norm = x.norm();
+
+ // Do initial cost and Jacobian evaluation.
+ double cost = 0.0;
+ if (!evaluator->Evaluate(x.data(),
+ &cost,
+ residuals.data(),
+ gradient.data(),
+ jacobian)) {
+ summary->message = "Residual and Jacobian evaluation failed.";
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ negative_gradient = -gradient;
+ if (!evaluator->Plus(x.data(),
+ negative_gradient.data(),
+ projected_gradient_step.data())) {
+ summary->message = "Unable to compute gradient step.";
+ summary->termination_type = FAILURE;
+ LOG(ERROR) << "Terminating: " << summary->message;
+ return;
+ }
+
+ summary->initial_cost = cost + summary->fixed_cost;
+ iteration_summary.cost = cost + summary->fixed_cost;
+ iteration_summary.gradient_max_norm =
+ (x - projected_gradient_step).lpNorm<Eigen::Infinity>();
+ iteration_summary.gradient_norm = (x - projected_gradient_step).norm();
+
+ if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
+ summary->message = StringPrintf("Gradient tolerance reached. "
+ "Gradient max norm: %e <= %e",
+ iteration_summary.gradient_max_norm,
+ options_.gradient_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+
+ // Ensure that there is an iteration summary object for iteration
+ // 0 in Summary::iterations.
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time +
+ summary->preprocessor_time_in_seconds;
+ summary->iterations.push_back(iteration_summary);
+ return;
+ }
+
+ if (options_.jacobi_scaling) {
+ EstimateScale(*jacobian, scale.data());
+ jacobian->ScaleColumns(scale.data());
+ } else {
+ scale.setOnes();
+ }
+
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
+ summary->iterations.push_back(iteration_summary);
+
+ int num_consecutive_nonmonotonic_steps = 0;
+ double minimum_cost = cost;
+ double reference_cost = cost;
+ double accumulated_reference_model_cost_change = 0.0;
+ double candidate_cost = cost;
+ double accumulated_candidate_model_cost_change = 0.0;
+ int num_consecutive_invalid_steps = 0;
+ bool inner_iterations_are_enabled =
+ options.inner_iteration_minimizer.get() != NULL;
+ while (true) {
+ bool inner_iterations_were_useful = false;
+ if (!RunCallbacks(options, iteration_summary, summary)) {
+ return;
+ }
+
+ iteration_start_time = WallTimeInSeconds();
+ if (iteration_summary.iteration >= options_.max_num_iterations) {
+ summary->message = "Maximum number of iterations reached.";
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ const double total_solver_time = iteration_start_time - start_time +
+ summary->preprocessor_time_in_seconds;
+ if (total_solver_time >= options_.max_solver_time_in_seconds) {
+ summary->message = "Maximum solver time reached.";
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ const double strategy_start_time = WallTimeInSeconds();
+ TrustRegionStrategy::PerSolveOptions per_solve_options;
+ per_solve_options.eta = options_.eta;
+ if (find(options_.trust_region_minimizer_iterations_to_dump.begin(),
+ options_.trust_region_minimizer_iterations_to_dump.end(),
+ iteration_summary.iteration) !=
+ options_.trust_region_minimizer_iterations_to_dump.end()) {
+ per_solve_options.dump_format_type =
+ options_.trust_region_problem_dump_format_type;
+ per_solve_options.dump_filename_base =
+ JoinPath(options_.trust_region_problem_dump_directory,
+ StringPrintf("ceres_solver_iteration_%03d",
+ iteration_summary.iteration));
+ } else {
+ per_solve_options.dump_format_type = TEXTFILE;
+ per_solve_options.dump_filename_base.clear();
+ }
+
+ TrustRegionStrategy::Summary strategy_summary =
+ strategy->ComputeStep(per_solve_options,
+ jacobian,
+ residuals.data(),
+ trust_region_step.data());
+
+ if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+ summary->message =
+ "Linear solver failed due to unrecoverable "
+ "non-numeric causes. Please see the error log for clues. ";
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ iteration_summary = IterationSummary();
+ iteration_summary.iteration = summary->iterations.back().iteration + 1;
+ iteration_summary.step_solver_time_in_seconds =
+ WallTimeInSeconds() - strategy_start_time;
+ iteration_summary.linear_solver_iterations =
+ strategy_summary.num_iterations;
+ iteration_summary.step_is_valid = false;
+ iteration_summary.step_is_successful = false;
+
+ double model_cost_change = 0.0;
+ if (strategy_summary.termination_type != LINEAR_SOLVER_FAILURE) {
+ // new_model_cost
+ // = 1/2 [f + J * step]^2
+ // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ]
+ // model_cost_change
+ // = cost - new_model_cost
+ // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step]
+ // = -f'J * step - step' * J' * J * step / 2
+ model_residuals.setZero();
+ jacobian->RightMultiply(trust_region_step.data(), model_residuals.data());
+ model_cost_change =
+ - model_residuals.dot(residuals + model_residuals / 2.0);
+
+ if (model_cost_change < 0.0) {
+ VLOG_IF(1, is_not_silent)
+ << "Invalid step: current_cost: " << cost
+ << " absolute difference " << model_cost_change
+ << " relative difference " << (model_cost_change / cost);
+ } else {
+ iteration_summary.step_is_valid = true;
+ }
+ }
+
+ if (!iteration_summary.step_is_valid) {
+ // Invalid steps can happen due to a number of reasons, and we
+ // allow a limited number of successive failures, and return with
+ // FAILURE if this limit is exceeded.
+ if (++num_consecutive_invalid_steps >=
+ options_.max_num_consecutive_invalid_steps) {
+ summary->message = StringPrintf(
+ "Number of successive invalid steps more "
+ "than Solver::Options::max_num_consecutive_invalid_steps: %d",
+ options_.max_num_consecutive_invalid_steps);
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ // We are going to try and reduce the trust region radius and
+ // solve again. To do this, we are going to treat this iteration
+ // as an unsuccessful iteration. Since the various callbacks are
+ // still executed, we are going to fill the iteration summary
+ // with data that assumes a step of length zero and no progress.
+ iteration_summary.cost = cost + summary->fixed_cost;
+ iteration_summary.cost_change = 0.0;
+ iteration_summary.gradient_max_norm =
+ summary->iterations.back().gradient_max_norm;
+ iteration_summary.gradient_norm =
+ summary->iterations.back().gradient_norm;
+ iteration_summary.step_norm = 0.0;
+ iteration_summary.relative_decrease = 0.0;
+ iteration_summary.eta = options_.eta;
+ } else {
+ // The step is numerically valid, so now we can judge its quality.
+ num_consecutive_invalid_steps = 0;
+
+ // Undo the Jacobian column scaling.
+ delta = (trust_region_step.array() * scale.array()).matrix();
+
+ // Try improving the step further by using an ARMIJO line
+ // search.
+ //
+ // TODO(sameeragarwal): What happens to trust region sizing as
+ // it interacts with the line search ?
+ if (use_line_search) {
+ const LineSearch::Summary line_search_summary =
+ DoLineSearch(options, x, gradient, cost, delta, evaluator);
+
+ summary->line_search_cost_evaluation_time_in_seconds +=
+ line_search_summary.cost_evaluation_time_in_seconds;
+ summary->line_search_gradient_evaluation_time_in_seconds +=
+ line_search_summary.gradient_evaluation_time_in_seconds;
+ summary->line_search_polynomial_minimization_time_in_seconds +=
+ line_search_summary.polynomial_minimization_time_in_seconds;
+ summary->line_search_total_time_in_seconds +=
+ line_search_summary.total_time_in_seconds;
+
+ if (line_search_summary.success) {
+ delta *= line_search_summary.optimal_step_size;
+ }
+ }
+
+ double new_cost = std::numeric_limits<double>::max();
+ if (evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
+ if (!evaluator->Evaluate(x_plus_delta.data(),
+ &new_cost,
+ NULL,
+ NULL,
+ NULL)) {
+ LOG_IF(WARNING, is_not_silent)
+ << "Step failed to evaluate. "
+ << "Treating it as a step with infinite cost";
+ new_cost = std::numeric_limits<double>::max();
+ }
+ } else {
+ LOG_IF(WARNING, is_not_silent)
+ << "x_plus_delta = Plus(x, delta) failed. "
+ << "Treating it as a step with infinite cost";
+ }
+
+ if (new_cost < std::numeric_limits<double>::max()) {
+ // Check if performing an inner iteration will make it better.
+ if (inner_iterations_are_enabled) {
+ ++summary->num_inner_iteration_steps;
+ double inner_iteration_start_time = WallTimeInSeconds();
+ const double x_plus_delta_cost = new_cost;
+ Vector inner_iteration_x = x_plus_delta;
+ Solver::Summary inner_iteration_summary;
+ options.inner_iteration_minimizer->Minimize(options,
+ inner_iteration_x.data(),
+ &inner_iteration_summary);
+ if (!evaluator->Evaluate(inner_iteration_x.data(),
+ &new_cost,
+ NULL, NULL, NULL)) {
+ VLOG_IF(2, is_not_silent) << "Inner iteration failed.";
+ new_cost = x_plus_delta_cost;
+ } else {
+ x_plus_delta = inner_iteration_x;
+ // Boost the model_cost_change, since the inner iteration
+ // improvements are not accounted for by the trust region.
+ model_cost_change += x_plus_delta_cost - new_cost;
+ VLOG_IF(2, is_not_silent)
+ << "Inner iteration succeeded; Current cost: " << cost
+ << " Trust region step cost: " << x_plus_delta_cost
+ << " Inner iteration cost: " << new_cost;
+
+ inner_iterations_were_useful = new_cost < cost;
+
+ const double inner_iteration_relative_progress =
+ 1.0 - new_cost / x_plus_delta_cost;
+ // Disable inner iterations once the relative improvement
+ // drops below tolerance.
+ inner_iterations_are_enabled =
+ (inner_iteration_relative_progress >
+ options.inner_iteration_tolerance);
+ VLOG_IF(2, is_not_silent && !inner_iterations_are_enabled)
+ << "Disabling inner iterations. Progress : "
+ << inner_iteration_relative_progress;
+ }
+ summary->inner_iteration_time_in_seconds +=
+ WallTimeInSeconds() - inner_iteration_start_time;
+ }
+ }
+
+ iteration_summary.step_norm = (x - x_plus_delta).norm();
+
+ // Convergence based on parameter_tolerance.
+ const double step_size_tolerance = options_.parameter_tolerance *
+ (x_norm + options_.parameter_tolerance);
+ if (iteration_summary.step_norm <= step_size_tolerance) {
+ summary->message =
+ StringPrintf("Parameter tolerance reached. "
+ "Relative step_norm: %e <= %e.",
+ (iteration_summary.step_norm /
+ (x_norm + options_.parameter_tolerance)),
+ options_.parameter_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ iteration_summary.cost_change = cost - new_cost;
+ const double absolute_function_tolerance =
+ options_.function_tolerance * cost;
+ if (fabs(iteration_summary.cost_change) <= absolute_function_tolerance) {
+ summary->message =
+ StringPrintf("Function tolerance reached. "
+ "|cost_change|/cost: %e <= %e",
+ fabs(iteration_summary.cost_change) / cost,
+ options_.function_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ const double relative_decrease =
+ iteration_summary.cost_change / model_cost_change;
+
+ const double historical_relative_decrease =
+ (reference_cost - new_cost) /
+ (accumulated_reference_model_cost_change + model_cost_change);
+
+ // If monotonic steps are being used, then the relative_decrease
+ // is the usual ratio of the change in objective function value
+ // divided by the change in model cost.
+ //
+ // If non-monotonic steps are allowed, then we take the maximum
+ // of the relative_decrease and the
+ // historical_relative_decrease, which measures the increase
+ // from a reference iteration. The model cost change is
+ // estimated by accumulating the model cost changes since the
+ // reference iteration. The historical relative_decrease offers
+ // a boost to a step which is not too bad compared to the
+ // reference iteration, allowing for non-monotonic steps.
+ iteration_summary.relative_decrease =
+ options.use_nonmonotonic_steps
+ ? std::max(relative_decrease, historical_relative_decrease)
+ : relative_decrease;
+
+ // Normally, the quality of a trust region step is measured by
+ // the ratio
+ //
+ // cost_change
+ // r = -----------------
+ // model_cost_change
+ //
+ // All the change in the nonlinear objective is due to the trust
+ // region step so this ratio is a good measure of the quality of
+ // the trust region radius. However, when inner iterations are
+ // being used, cost_change includes the contribution of the
+ // inner iterations and its not fair to credit it all to the
+ // trust region algorithm. So we change the ratio to be
+ //
+ // cost_change
+ // r = ------------------------------------------------
+ // (model_cost_change + inner_iteration_cost_change)
+ //
+ // In most cases this is fine, but it can be the case that the
+ // change in solution quality due to inner iterations is so large
+ // and the trust region step is so bad, that this ratio can become
+ // quite small.
+ //
+ // This can cause the trust region loop to reject this step. To
+ // get around this, we expicitly check if the inner iterations
+ // led to a net decrease in the objective function value. If
+ // they did, we accept the step even if the trust region ratio
+ // is small.
+ //
+ // Notice that we do not just check that cost_change is positive
+ // which is a weaker condition and would render the
+ // min_relative_decrease threshold useless. Instead, we keep
+ // track of inner_iterations_were_useful, which is true only
+ // when inner iterations lead to a net decrease in the cost.
+ iteration_summary.step_is_successful =
+ (inner_iterations_were_useful ||
+ iteration_summary.relative_decrease >
+ options_.min_relative_decrease);
+
+ if (iteration_summary.step_is_successful) {
+ accumulated_candidate_model_cost_change += model_cost_change;
+ accumulated_reference_model_cost_change += model_cost_change;
+
+ if (!inner_iterations_were_useful &&
+ relative_decrease <= options_.min_relative_decrease) {
+ iteration_summary.step_is_nonmonotonic = true;
+ VLOG_IF(2, is_not_silent)
+ << "Non-monotonic step! "
+ << " relative_decrease: "
+ << relative_decrease
+ << " historical_relative_decrease: "
+ << historical_relative_decrease;
+ }
+ }
+ }
+
+ if (iteration_summary.step_is_successful) {
+ ++summary->num_successful_steps;
+ strategy->StepAccepted(iteration_summary.relative_decrease);
+
+ x = x_plus_delta;
+ x_norm = x.norm();
+
+ // Step looks good, evaluate the residuals and Jacobian at this
+ // point.
+ if (!evaluator->Evaluate(x.data(),
+ &cost,
+ residuals.data(),
+ gradient.data(),
+ jacobian)) {
+ summary->message = "Residual and Jacobian evaluation failed.";
+ summary->termination_type = FAILURE;
+ LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+
+ negative_gradient = -gradient;
+ if (!evaluator->Plus(x.data(),
+ negative_gradient.data(),
+ projected_gradient_step.data())) {
+ summary->message =
+ "projected_gradient_step = Plus(x, -gradient) failed.";
+ summary->termination_type = FAILURE;
+ LOG(ERROR) << "Terminating: " << summary->message;
+ return;
+ }
+
+ iteration_summary.gradient_max_norm =
+ (x - projected_gradient_step).lpNorm<Eigen::Infinity>();
+ iteration_summary.gradient_norm = (x - projected_gradient_step).norm();
+
+ if (options_.jacobi_scaling) {
+ jacobian->ScaleColumns(scale.data());
+ }
+
+ // Update the best, reference and candidate iterates.
+ //
+ // Based on algorithm 10.1.2 (page 357) of "Trust Region
+ // Methods" by Conn Gould & Toint, or equations 33-40 of
+ // "Non-monotone trust-region algorithms for nonlinear
+ // optimization subject to convex constraints" by Phil Toint,
+ // Mathematical Programming, 77, 1997.
+ if (cost < minimum_cost) {
+ // A step that improves solution quality was found.
+ x_min = x;
+ minimum_cost = cost;
+ // Set the candidate iterate to the current point.
+ candidate_cost = cost;
+ num_consecutive_nonmonotonic_steps = 0;
+ accumulated_candidate_model_cost_change = 0.0;
+ } else {
+ ++num_consecutive_nonmonotonic_steps;
+ if (cost > candidate_cost) {
+ // The current iterate is has a higher cost than the
+ // candidate iterate. Set the candidate to this point.
+ VLOG_IF(2, is_not_silent)
+ << "Updating the candidate iterate to the current point.";
+ candidate_cost = cost;
+ accumulated_candidate_model_cost_change = 0.0;
+ }
+
+ // At this point we have made too many non-monotonic steps and
+ // we are going to reset the value of the reference iterate so
+ // as to force the algorithm to descend.
+ //
+ // This is the case because the candidate iterate has a value
+ // greater than minimum_cost but smaller than the reference
+ // iterate.
+ if (num_consecutive_nonmonotonic_steps ==
+ options.max_consecutive_nonmonotonic_steps) {
+ VLOG_IF(2, is_not_silent)
+ << "Resetting the reference point to the candidate point";
+ reference_cost = candidate_cost;
+ accumulated_reference_model_cost_change =
+ accumulated_candidate_model_cost_change;
+ }
+ }
+ } else {
+ ++summary->num_unsuccessful_steps;
+ if (iteration_summary.step_is_valid) {
+ strategy->StepRejected(iteration_summary.relative_decrease);
+ } else {
+ strategy->StepIsInvalid();
+ }
+ }
+
+ iteration_summary.cost = cost + summary->fixed_cost;
+ iteration_summary.trust_region_radius = strategy->Radius();
+ iteration_summary.iteration_time_in_seconds =
+ WallTimeInSeconds() - iteration_start_time;
+ iteration_summary.cumulative_time_in_seconds =
+ WallTimeInSeconds() - start_time
+ + summary->preprocessor_time_in_seconds;
+ summary->iterations.push_back(iteration_summary);
+
+ // If the step was successful, check for the gradient norm
+ // collapsing to zero, and if the step is unsuccessful then check
+ // if the trust region radius has collapsed to zero.
+ //
+ // For correctness (Number of IterationSummary objects, correct
+ // final cost, and state update) these convergence tests need to
+ // be performed at the end of the iteration.
+ if (iteration_summary.step_is_successful) {
+ // Gradient norm can only go down in successful steps.
+ if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
+ summary->message = StringPrintf("Gradient tolerance reached. "
+ "Gradient max norm: %e <= %e",
+ iteration_summary.gradient_max_norm,
+ options_.gradient_tolerance);
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
+ return;
+ }
+ } else {
+ // Trust region radius can only go down if the step if
+ // unsuccessful.
+ if (iteration_summary.trust_region_radius <
+ options_.min_trust_region_radius) {
+ summary->message = "Termination. Minimum trust region radius reached.";
+ summary->termination_type = CONVERGENCE;
+ VLOG_IF(1, is_not_silent) << summary->message;
+ return;
+ }
+ }
+ }
+}
+
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/trust_region_minimizer.h b/extern/ceres/internal/ceres/trust_region_minimizer.h
new file mode 100644
index 00000000000..ed52c2642d1
--- /dev/null
+++ b/extern/ceres/internal/ceres/trust_region_minimizer.h
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
+#define CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
+
+#include "ceres/minimizer.h"
+#include "ceres/solver.h"
+#include "ceres/types.h"
+
+namespace ceres {
+namespace internal {
+
+// Generic trust region minimization algorithm. The heavy lifting is
+// done by a TrustRegionStrategy object passed in as part of options.
+//
+// For example usage, see SolverImpl::Minimize.
+class TrustRegionMinimizer : public Minimizer {
+ public:
+ ~TrustRegionMinimizer() {}
+ virtual void Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary);
+
+ private:
+ void Init(const Minimizer::Options& options);
+ void EstimateScale(const SparseMatrix& jacobian, double* scale) const;
+ bool MaybeDumpLinearLeastSquaresProblem(const int iteration,
+ const SparseMatrix* jacobian,
+ const double* residuals,
+ const double* step) const;
+
+ Minimizer::Options options_;
+};
+
+} // namespace internal
+} // namespace ceres
+#endif // CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
diff --git a/extern/ceres/internal/ceres/trust_region_preprocessor.cc b/extern/ceres/internal/ceres/trust_region_preprocessor.cc
new file mode 100644
index 00000000000..4020e4ca115
--- /dev/null
+++ b/extern/ceres/internal/ceres/trust_region_preprocessor.cc
@@ -0,0 +1,362 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/trust_region_preprocessor.h"
+
+#include <numeric>
+#include <string>
+#include "ceres/callbacks.h"
+#include "ceres/evaluator.h"
+#include "ceres/linear_solver.h"
+#include "ceres/minimizer.h"
+#include "ceres/parameter_block.h"
+#include "ceres/preconditioner.h"
+#include "ceres/preprocessor.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/reorder_program.h"
+#include "ceres/suitesparse.h"
+#include "ceres/trust_region_strategy.h"
+#include "ceres/wall_time.h"
+
+namespace ceres {
+namespace internal {
+
+using std::vector;
+
+namespace {
+
+ParameterBlockOrdering* CreateDefaultLinearSolverOrdering(
+ const Program& program) {
+ ParameterBlockOrdering* ordering = new ParameterBlockOrdering;
+ const vector<ParameterBlock*>& parameter_blocks =
+ program.parameter_blocks();
+ for (int i = 0; i < parameter_blocks.size(); ++i) {
+ ordering->AddElementToGroup(
+ const_cast<double*>(parameter_blocks[i]->user_state()), 0);
+ }
+ return ordering;
+}
+
+// Check if all the user supplied values in the parameter blocks are
+// sane or not, and if the program is feasible or not.
+bool IsProgramValid(const Program& program, std::string* error) {
+ return (program.ParameterBlocksAreFinite(error) &&
+ program.IsFeasible(error));
+}
+
+void AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
+ Solver::Options* options) {
+ if (!IsSchurType(options->linear_solver_type)) {
+ return;
+ }
+
+ const LinearSolverType linear_solver_type_given = options->linear_solver_type;
+ const PreconditionerType preconditioner_type_given =
+ options->preconditioner_type;
+ options->linear_solver_type = LinearSolver::LinearSolverForZeroEBlocks(
+ linear_solver_type_given);
+
+ std::string message;
+ if (linear_solver_type_given == ITERATIVE_SCHUR) {
+ options->preconditioner_type = Preconditioner::PreconditionerForZeroEBlocks(
+ preconditioner_type_given);
+
+ message =
+ StringPrintf(
+ "No E blocks. Switching from %s(%s) to %s(%s).",
+ LinearSolverTypeToString(linear_solver_type_given),
+ PreconditionerTypeToString(preconditioner_type_given),
+ LinearSolverTypeToString(options->linear_solver_type),
+ PreconditionerTypeToString(options->preconditioner_type));
+ } else {
+ message =
+ StringPrintf(
+ "No E blocks. Switching from %s to %s.",
+ LinearSolverTypeToString(linear_solver_type_given),
+ LinearSolverTypeToString(options->linear_solver_type));
+ }
+
+ VLOG_IF(1, options->logging_type != SILENT) << message;
+}
+
+// For Schur type and SPARSE_NORMAL_CHOLESKY linear solvers, reorder
+// the program to reduce fill-in and increase cache coherency.
+bool ReorderProgram(PreprocessedProblem* pp) {
+ Solver::Options& options = pp->options;
+ if (IsSchurType(options.linear_solver_type)) {
+ return ReorderProgramForSchurTypeLinearSolver(
+ options.linear_solver_type,
+ options.sparse_linear_algebra_library_type,
+ pp->problem->parameter_map(),
+ options.linear_solver_ordering.get(),
+ pp->reduced_program.get(),
+ &pp->error);
+ }
+
+ if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY &&
+ !options.dynamic_sparsity) {
+ return ReorderProgramForSparseNormalCholesky(
+ options.sparse_linear_algebra_library_type,
+ *options.linear_solver_ordering,
+ pp->reduced_program.get(),
+ &pp->error);
+ }
+
+ return true;
+}
+
+// Configure and create a linear solver object. In doing so, if a
+// sparse direct factorization based linear solver is being used, then
+// find a fill reducing ordering and reorder the program as needed
+// too.
+bool SetupLinearSolver(PreprocessedProblem* pp) {
+ Solver::Options& options = pp->options;
+ if (options.linear_solver_ordering.get() == NULL) {
+ // If the user has not supplied a linear solver ordering, then we
+ // assume that they are giving all the freedom to us in choosing
+ // the best possible ordering. This intent can be indicated by
+ // putting all the parameter blocks in the same elimination group.
+ options.linear_solver_ordering.reset(
+ CreateDefaultLinearSolverOrdering(*pp->reduced_program));
+ } else {
+ // If the user supplied an ordering, then check if the first
+ // elimination group is still non-empty after the reduced problem
+ // has been constructed.
+ //
+ // This is important for Schur type linear solvers, where the
+ // first elimination group is special -- it needs to be an
+ // independent set.
+ //
+ // If the first elimination group is empty, then we cannot use the
+ // user's requested linear solver (and a preconditioner as the
+ // case may be) so we must use a different one.
+ ParameterBlockOrdering* ordering = options.linear_solver_ordering.get();
+ const int min_group_id = ordering->MinNonZeroGroup();
+ ordering->Remove(pp->removed_parameter_blocks);
+ if (IsSchurType(options.linear_solver_type) &&
+ min_group_id != ordering->MinNonZeroGroup()) {
+ AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
+ &options);
+ }
+ }
+
+ // Reorder the program to reduce fill in and improve cache coherency
+ // of the Jacobian.
+ if (!ReorderProgram(pp)) {
+ return false;
+ }
+
+ // Configure the linear solver.
+ pp->linear_solver_options = LinearSolver::Options();
+ pp->linear_solver_options.min_num_iterations =
+ options.min_linear_solver_iterations;
+ pp->linear_solver_options.max_num_iterations =
+ options.max_linear_solver_iterations;
+ pp->linear_solver_options.type = options.linear_solver_type;
+ pp->linear_solver_options.preconditioner_type = options.preconditioner_type;
+ pp->linear_solver_options.visibility_clustering_type =
+ options.visibility_clustering_type;
+ pp->linear_solver_options.sparse_linear_algebra_library_type =
+ options.sparse_linear_algebra_library_type;
+ pp->linear_solver_options.dense_linear_algebra_library_type =
+ options.dense_linear_algebra_library_type;
+ pp->linear_solver_options.use_explicit_schur_complement =
+ options.use_explicit_schur_complement;
+ pp->linear_solver_options.dynamic_sparsity = options.dynamic_sparsity;
+ pp->linear_solver_options.num_threads = options.num_linear_solver_threads;
+
+ // Ignore user's postordering preferences and force it to be true if
+ // cholmod_camd is not available. This ensures that the linear
+ // solver does not assume that a fill-reducing pre-ordering has been
+ // done.
+ pp->linear_solver_options.use_postordering = options.use_postordering;
+ if (options.linear_solver_type == SPARSE_SCHUR &&
+ options.sparse_linear_algebra_library_type == SUITE_SPARSE &&
+ !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
+ pp->linear_solver_options.use_postordering = true;
+ }
+
+ OrderingToGroupSizes(options.linear_solver_ordering.get(),
+ &pp->linear_solver_options.elimination_groups);
+
+ // Schur type solvers expect at least two elimination groups. If
+ // there is only one elimination group, then it is guaranteed that
+ // this group only contains e_blocks. Thus we add a dummy
+ // elimination group with zero blocks in it.
+ if (IsSchurType(pp->linear_solver_options.type) &&
+ pp->linear_solver_options.elimination_groups.size() == 1) {
+ pp->linear_solver_options.elimination_groups.push_back(0);
+ }
+
+ pp->linear_solver.reset(LinearSolver::Create(pp->linear_solver_options));
+ return (pp->linear_solver.get() != NULL);
+}
+
+// Configure and create the evaluator.
+bool SetupEvaluator(PreprocessedProblem* pp) {
+ const Solver::Options& options = pp->options;
+ pp->evaluator_options = Evaluator::Options();
+ pp->evaluator_options.linear_solver_type = options.linear_solver_type;
+ pp->evaluator_options.num_eliminate_blocks = 0;
+ if (IsSchurType(options.linear_solver_type)) {
+ pp->evaluator_options.num_eliminate_blocks =
+ options
+ .linear_solver_ordering
+ ->group_to_elements().begin()
+ ->second.size();
+ }
+
+ pp->evaluator_options.num_threads = options.num_threads;
+ pp->evaluator_options.dynamic_sparsity = options.dynamic_sparsity;
+ pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
+ pp->reduced_program.get(),
+ &pp->error));
+
+ return (pp->evaluator.get() != NULL);
+}
+
+// If the user requested inner iterations, then find an inner
+// iteration ordering as needed and configure and create a
+// CoordinateDescentMinimizer object to perform the inner iterations.
+bool SetupInnerIterationMinimizer(PreprocessedProblem* pp) {
+ Solver::Options& options = pp->options;
+ if (!options.use_inner_iterations) {
+ return true;
+ }
+
+ // With just one parameter block, the outer iteration of the trust
+ // region method and inner iterations are doing exactly the same
+ // thing, and thus inner iterations are not needed.
+ if (pp->reduced_program->NumParameterBlocks() == 1) {
+ LOG(WARNING) << "Reduced problem only contains one parameter block."
+ << "Disabling inner iterations.";
+ return true;
+ }
+
+ if (options.inner_iteration_ordering.get() != NULL) {
+ // If the user supplied an ordering, then remove the set of
+ // inactive parameter blocks from it
+ options.inner_iteration_ordering->Remove(pp->removed_parameter_blocks);
+ if (options.inner_iteration_ordering->NumElements() == 0) {
+ LOG(WARNING) << "No remaining elements in the inner iteration ordering.";
+ return true;
+ }
+
+ // Validate the reduced ordering.
+ if (!CoordinateDescentMinimizer::IsOrderingValid(
+ *pp->reduced_program,
+ *options.inner_iteration_ordering,
+ &pp->error)) {
+ return false;
+ }
+ } else {
+ // The user did not supply an ordering, so create one.
+ options.inner_iteration_ordering.reset(
+ CoordinateDescentMinimizer::CreateOrdering(*pp->reduced_program));
+ }
+
+ pp->inner_iteration_minimizer.reset(new CoordinateDescentMinimizer);
+ return pp->inner_iteration_minimizer->Init(*pp->reduced_program,
+ pp->problem->parameter_map(),
+ *options.inner_iteration_ordering,
+ &pp->error);
+}
+
+// Configure and create a TrustRegionMinimizer object.
+void SetupMinimizerOptions(PreprocessedProblem* pp) {
+ const Solver::Options& options = pp->options;
+
+ SetupCommonMinimizerOptions(pp);
+ pp->minimizer_options.is_constrained =
+ pp->reduced_program->IsBoundsConstrained();
+ pp->minimizer_options.jacobian.reset(pp->evaluator->CreateJacobian());
+ pp->minimizer_options.inner_iteration_minimizer =
+ pp->inner_iteration_minimizer;
+
+ TrustRegionStrategy::Options strategy_options;
+ strategy_options.linear_solver = pp->linear_solver.get();
+ strategy_options.initial_radius =
+ options.initial_trust_region_radius;
+ strategy_options.max_radius = options.max_trust_region_radius;
+ strategy_options.min_lm_diagonal = options.min_lm_diagonal;
+ strategy_options.max_lm_diagonal = options.max_lm_diagonal;
+ strategy_options.trust_region_strategy_type =
+ options.trust_region_strategy_type;
+ strategy_options.dogleg_type = options.dogleg_type;
+ pp->minimizer_options.trust_region_strategy.reset(
+ CHECK_NOTNULL(TrustRegionStrategy::Create(strategy_options)));
+}
+
+} // namespace
+
+TrustRegionPreprocessor::~TrustRegionPreprocessor() {
+}
+
+bool TrustRegionPreprocessor::Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* pp) {
+ CHECK_NOTNULL(pp);
+ pp->options = options;
+ ChangeNumThreadsIfNeeded(&pp->options);
+
+ pp->problem = problem;
+ Program* program = problem->mutable_program();
+ if (!IsProgramValid(*program, &pp->error)) {
+ return false;
+ }
+
+ pp->reduced_program.reset(
+ program->CreateReducedProgram(&pp->removed_parameter_blocks,
+ &pp->fixed_cost,
+ &pp->error));
+
+ if (pp->reduced_program.get() == NULL) {
+ return false;
+ }
+
+ if (pp->reduced_program->NumParameterBlocks() == 0) {
+ // The reduced problem has no parameter or residual blocks. There
+ // is nothing more to do.
+ return true;
+ }
+
+ if (!SetupLinearSolver(pp) ||
+ !SetupEvaluator(pp) ||
+ !SetupInnerIterationMinimizer(pp)) {
+ return false;
+ }
+
+ SetupMinimizerOptions(pp);
+ return true;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/trust_region_preprocessor.h b/extern/ceres/internal/ceres/trust_region_preprocessor.h
new file mode 100644
index 00000000000..a6631ab3d40
--- /dev/null
+++ b/extern/ceres/internal/ceres/trust_region_preprocessor.h
@@ -0,0 +1,50 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
+#define CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
+
+#include "ceres/preprocessor.h"
+
+namespace ceres {
+namespace internal {
+
+class TrustRegionPreprocessor : public Preprocessor {
+ public:
+ virtual ~TrustRegionPreprocessor();
+ virtual bool Preprocess(const Solver::Options& options,
+ ProblemImpl* problem,
+ PreprocessedProblem* preprocessed_problem);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
diff --git a/extern/ceres/internal/ceres/trust_region_strategy.cc b/extern/ceres/internal/ceres/trust_region_strategy.cc
new file mode 100644
index 00000000000..2db6a6c899b
--- /dev/null
+++ b/extern/ceres/internal/ceres/trust_region_strategy.cc
@@ -0,0 +1,59 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+// keir@google.com (Keir Mierle)
+
+#include "ceres/trust_region_strategy.h"
+#include "ceres/dogleg_strategy.h"
+#include "ceres/levenberg_marquardt_strategy.h"
+
+namespace ceres {
+namespace internal {
+
+TrustRegionStrategy::~TrustRegionStrategy() {}
+
+TrustRegionStrategy* TrustRegionStrategy::Create(const Options& options) {
+ switch (options.trust_region_strategy_type) {
+ case LEVENBERG_MARQUARDT:
+ return new LevenbergMarquardtStrategy(options);
+ case DOGLEG:
+ return new DoglegStrategy(options);
+ default:
+ LOG(FATAL) << "Unknown trust region strategy: "
+ << options.trust_region_strategy_type;
+ }
+
+ LOG(FATAL) << "Unknown trust region strategy: "
+ << options.trust_region_strategy_type;
+ return NULL;
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/trust_region_strategy.h b/extern/ceres/internal/ceres/trust_region_strategy.h
new file mode 100644
index 00000000000..9560e67459a
--- /dev/null
+++ b/extern/ceres/internal/ceres/trust_region_strategy.h
@@ -0,0 +1,164 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
+#define CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
+
+#include <string>
+#include "ceres/internal/port.h"
+#include "ceres/linear_solver.h"
+
+namespace ceres {
+namespace internal {
+
+class LinearSolver;
+class SparseMatrix;
+
+// Interface for classes implementing various trust region strategies
+// for nonlinear least squares problems.
+//
+// The object is expected to maintain and update a trust region
+// radius, which it then uses to solve for the trust region step using
+// the jacobian matrix and residual vector.
+//
+// Here the term trust region radius is used loosely, as the strategy
+// is free to treat it as guidance and violate it as need be. e.g.,
+// the LevenbergMarquardtStrategy uses the inverse of the trust region
+// radius to scale the damping term, which controls the step size, but
+// does not set a hard limit on its size.
+class TrustRegionStrategy {
+ public:
+ struct Options {
+ Options()
+ : trust_region_strategy_type(LEVENBERG_MARQUARDT),
+ initial_radius(1e4),
+ max_radius(1e32),
+ min_lm_diagonal(1e-6),
+ max_lm_diagonal(1e32),
+ dogleg_type(TRADITIONAL_DOGLEG) {
+ }
+
+ TrustRegionStrategyType trust_region_strategy_type;
+ // Linear solver used for actually solving the trust region step.
+ LinearSolver* linear_solver;
+ double initial_radius;
+ double max_radius;
+
+ // Minimum and maximum values of the diagonal damping matrix used
+ // by LevenbergMarquardtStrategy. The DoglegStrategy also uses
+ // these bounds to construct a regularizing diagonal to ensure
+ // that the Gauss-Newton step computation is of full rank.
+ double min_lm_diagonal;
+ double max_lm_diagonal;
+
+ // Further specify which dogleg method to use
+ DoglegType dogleg_type;
+ };
+
+ // Per solve options.
+ struct PerSolveOptions {
+ PerSolveOptions()
+ : eta(0),
+ dump_filename_base(""),
+ dump_format_type(TEXTFILE) {
+ }
+
+ // Forcing sequence for inexact solves.
+ double eta;
+
+ // If non-empty and dump_format_type is not CONSOLE, the trust
+ // regions strategy will write the linear system to file(s) with
+ // name starting with dump_filename_base. If dump_format_type is
+ // CONSOLE then dump_filename_base will be ignored and the linear
+ // system will be written to the standard error.
+ std::string dump_filename_base;
+ DumpFormatType dump_format_type;
+ };
+
+ struct Summary {
+ Summary()
+ : residual_norm(0.0),
+ num_iterations(-1),
+ termination_type(LINEAR_SOLVER_FAILURE) {
+ }
+
+ // If the trust region problem is,
+ //
+ // 1/2 x'Ax + b'x + c,
+ //
+ // then
+ //
+ // residual_norm = |Ax -b|
+ double residual_norm;
+
+ // Number of iterations used by the linear solver. If a linear
+ // solver was not called (e.g., DogLegStrategy after an
+ // unsuccessful step), then this would be zero.
+ int num_iterations;
+
+ // Status of the linear solver used to solve the Newton system.
+ LinearSolverTerminationType termination_type;
+ };
+
+ virtual ~TrustRegionStrategy();
+
+ // Use the current radius to solve for the trust region step.
+ virtual Summary ComputeStep(const PerSolveOptions& per_solve_options,
+ SparseMatrix* jacobian,
+ const double* residuals,
+ double* step) = 0;
+
+ // Inform the strategy that the current step has been accepted, and
+ // that the ratio of the decrease in the non-linear objective to the
+ // decrease in the trust region model is step_quality.
+ virtual void StepAccepted(double step_quality) = 0;
+
+ // Inform the strategy that the current step has been rejected, and
+ // that the ratio of the decrease in the non-linear objective to the
+ // decrease in the trust region model is step_quality.
+ virtual void StepRejected(double step_quality) = 0;
+
+ // Inform the strategy that the current step has been rejected
+ // because it was found to be numerically invalid.
+ // StepRejected/StepAccepted will not be called for this step, and
+ // the strategy is free to do what it wants with this information.
+ virtual void StepIsInvalid() = 0;
+
+ // Current trust region radius.
+ virtual double Radius() const = 0;
+
+ // Factory.
+ static TrustRegionStrategy* Create(const Options& options);
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
diff --git a/extern/ceres/internal/ceres/types.cc b/extern/ceres/internal/ceres/types.cc
new file mode 100644
index 00000000000..f86fb78eb8c
--- /dev/null
+++ b/extern/ceres/internal/ceres/types.cc
@@ -0,0 +1,395 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <algorithm>
+#include <cctype>
+#include <string>
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+using std::string;
+
+#define CASESTR(x) case x: return #x
+#define STRENUM(x) if (value == #x) { *type = x; return true;}
+
+static void UpperCase(string* input) {
+ std::transform(input->begin(), input->end(), input->begin(), ::toupper);
+}
+
+const char* LinearSolverTypeToString(LinearSolverType type) {
+ switch (type) {
+ CASESTR(DENSE_NORMAL_CHOLESKY);
+ CASESTR(DENSE_QR);
+ CASESTR(SPARSE_NORMAL_CHOLESKY);
+ CASESTR(DENSE_SCHUR);
+ CASESTR(SPARSE_SCHUR);
+ CASESTR(ITERATIVE_SCHUR);
+ CASESTR(CGNR);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLinearSolverType(string value, LinearSolverType* type) {
+ UpperCase(&value);
+ STRENUM(DENSE_NORMAL_CHOLESKY);
+ STRENUM(DENSE_QR);
+ STRENUM(SPARSE_NORMAL_CHOLESKY);
+ STRENUM(DENSE_SCHUR);
+ STRENUM(SPARSE_SCHUR);
+ STRENUM(ITERATIVE_SCHUR);
+ STRENUM(CGNR);
+ return false;
+}
+
+const char* PreconditionerTypeToString(PreconditionerType type) {
+ switch (type) {
+ CASESTR(IDENTITY);
+ CASESTR(JACOBI);
+ CASESTR(SCHUR_JACOBI);
+ CASESTR(CLUSTER_JACOBI);
+ CASESTR(CLUSTER_TRIDIAGONAL);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToPreconditionerType(string value, PreconditionerType* type) {
+ UpperCase(&value);
+ STRENUM(IDENTITY);
+ STRENUM(JACOBI);
+ STRENUM(SCHUR_JACOBI);
+ STRENUM(CLUSTER_JACOBI);
+ STRENUM(CLUSTER_TRIDIAGONAL);
+ return false;
+}
+
+const char* SparseLinearAlgebraLibraryTypeToString(
+ SparseLinearAlgebraLibraryType type) {
+ switch (type) {
+ CASESTR(SUITE_SPARSE);
+ CASESTR(CX_SPARSE);
+ CASESTR(EIGEN_SPARSE);
+ CASESTR(NO_SPARSE);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToSparseLinearAlgebraLibraryType(
+ string value,
+ SparseLinearAlgebraLibraryType* type) {
+ UpperCase(&value);
+ STRENUM(SUITE_SPARSE);
+ STRENUM(CX_SPARSE);
+ STRENUM(EIGEN_SPARSE);
+ STRENUM(NO_SPARSE);
+ return false;
+}
+
+const char* DenseLinearAlgebraLibraryTypeToString(
+ DenseLinearAlgebraLibraryType type) {
+ switch (type) {
+ CASESTR(EIGEN);
+ CASESTR(LAPACK);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToDenseLinearAlgebraLibraryType(
+ string value,
+ DenseLinearAlgebraLibraryType* type) {
+ UpperCase(&value);
+ STRENUM(EIGEN);
+ STRENUM(LAPACK);
+ return false;
+}
+
+const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type) {
+ switch (type) {
+ CASESTR(LEVENBERG_MARQUARDT);
+ CASESTR(DOGLEG);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToTrustRegionStrategyType(string value,
+ TrustRegionStrategyType* type) {
+ UpperCase(&value);
+ STRENUM(LEVENBERG_MARQUARDT);
+ STRENUM(DOGLEG);
+ return false;
+}
+
+const char* DoglegTypeToString(DoglegType type) {
+ switch (type) {
+ CASESTR(TRADITIONAL_DOGLEG);
+ CASESTR(SUBSPACE_DOGLEG);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToDoglegType(string value, DoglegType* type) {
+ UpperCase(&value);
+ STRENUM(TRADITIONAL_DOGLEG);
+ STRENUM(SUBSPACE_DOGLEG);
+ return false;
+}
+
+const char* MinimizerTypeToString(MinimizerType type) {
+ switch (type) {
+ CASESTR(TRUST_REGION);
+ CASESTR(LINE_SEARCH);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToMinimizerType(string value, MinimizerType* type) {
+ UpperCase(&value);
+ STRENUM(TRUST_REGION);
+ STRENUM(LINE_SEARCH);
+ return false;
+}
+
+const char* LineSearchDirectionTypeToString(LineSearchDirectionType type) {
+ switch (type) {
+ CASESTR(STEEPEST_DESCENT);
+ CASESTR(NONLINEAR_CONJUGATE_GRADIENT);
+ CASESTR(LBFGS);
+ CASESTR(BFGS);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLineSearchDirectionType(string value,
+ LineSearchDirectionType* type) {
+ UpperCase(&value);
+ STRENUM(STEEPEST_DESCENT);
+ STRENUM(NONLINEAR_CONJUGATE_GRADIENT);
+ STRENUM(LBFGS);
+ STRENUM(BFGS);
+ return false;
+}
+
+const char* LineSearchTypeToString(LineSearchType type) {
+ switch (type) {
+ CASESTR(ARMIJO);
+ CASESTR(WOLFE);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLineSearchType(string value, LineSearchType* type) {
+ UpperCase(&value);
+ STRENUM(ARMIJO);
+ STRENUM(WOLFE);
+ return false;
+}
+
+const char* LineSearchInterpolationTypeToString(
+ LineSearchInterpolationType type) {
+ switch (type) {
+ CASESTR(BISECTION);
+ CASESTR(QUADRATIC);
+ CASESTR(CUBIC);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLineSearchInterpolationType(
+ string value,
+ LineSearchInterpolationType* type) {
+ UpperCase(&value);
+ STRENUM(BISECTION);
+ STRENUM(QUADRATIC);
+ STRENUM(CUBIC);
+ return false;
+}
+
+const char* NonlinearConjugateGradientTypeToString(
+ NonlinearConjugateGradientType type) {
+ switch (type) {
+ CASESTR(FLETCHER_REEVES);
+ CASESTR(POLAK_RIBIERE);
+ CASESTR(HESTENES_STIEFEL);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToNonlinearConjugateGradientType(
+ string value,
+ NonlinearConjugateGradientType* type) {
+ UpperCase(&value);
+ STRENUM(FLETCHER_REEVES);
+ STRENUM(POLAK_RIBIERE);
+ STRENUM(HESTENES_STIEFEL);
+ return false;
+}
+
+const char* CovarianceAlgorithmTypeToString(
+ CovarianceAlgorithmType type) {
+ switch (type) {
+ CASESTR(DENSE_SVD);
+ CASESTR(EIGEN_SPARSE_QR);
+ CASESTR(SUITE_SPARSE_QR);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToCovarianceAlgorithmType(
+ string value,
+ CovarianceAlgorithmType* type) {
+ UpperCase(&value);
+ STRENUM(DENSE_SVD);
+ STRENUM(EIGEN_SPARSE_QR);
+ STRENUM(SUITE_SPARSE_QR);
+ return false;
+}
+
+const char* NumericDiffMethodTypeToString(
+ NumericDiffMethodType type) {
+ switch (type) {
+ CASESTR(CENTRAL);
+ CASESTR(FORWARD);
+ CASESTR(RIDDERS);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToNumericDiffMethodType(
+ string value,
+ NumericDiffMethodType* type) {
+ UpperCase(&value);
+ STRENUM(CENTRAL);
+ STRENUM(FORWARD);
+ STRENUM(RIDDERS);
+ return false;
+}
+
+const char* VisibilityClusteringTypeToString(
+ VisibilityClusteringType type) {
+ switch (type) {
+ CASESTR(CANONICAL_VIEWS);
+ CASESTR(SINGLE_LINKAGE);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToVisibilityClusteringType(
+ string value,
+ VisibilityClusteringType* type) {
+ UpperCase(&value);
+ STRENUM(CANONICAL_VIEWS);
+ STRENUM(SINGLE_LINKAGE);
+ return false;
+}
+
+const char* TerminationTypeToString(TerminationType type) {
+ switch (type) {
+ CASESTR(CONVERGENCE);
+ CASESTR(NO_CONVERGENCE);
+ CASESTR(FAILURE);
+ CASESTR(USER_SUCCESS);
+ CASESTR(USER_FAILURE);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+#undef CASESTR
+#undef STRENUM
+
+bool IsSchurType(LinearSolverType type) {
+ return ((type == SPARSE_SCHUR) ||
+ (type == DENSE_SCHUR) ||
+ (type == ITERATIVE_SCHUR));
+}
+
+bool IsSparseLinearAlgebraLibraryTypeAvailable(
+ SparseLinearAlgebraLibraryType type) {
+ if (type == SUITE_SPARSE) {
+#ifdef CERES_NO_SUITESPARSE
+ return false;
+#else
+ return true;
+#endif
+ }
+
+ if (type == CX_SPARSE) {
+#ifdef CERES_NO_CXSPARSE
+ return false;
+#else
+ return true;
+#endif
+ }
+
+ if (type == EIGEN_SPARSE) {
+#ifdef CERES_USE_EIGEN_SPARSE
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ LOG(WARNING) << "Unknown sparse linear algebra library " << type;
+ return false;
+}
+
+bool IsDenseLinearAlgebraLibraryTypeAvailable(
+ DenseLinearAlgebraLibraryType type) {
+ if (type == EIGEN) {
+ return true;
+ }
+ if (type == LAPACK) {
+#ifdef CERES_NO_LAPACK
+ return false;
+#else
+ return true;
+#endif
+ }
+
+ LOG(WARNING) << "Unknown dense linear algebra library " << type;
+ return false;
+}
+
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/visibility_based_preconditioner.h b/extern/ceres/internal/ceres/visibility_based_preconditioner.h
new file mode 100644
index 00000000000..a627c13523c
--- /dev/null
+++ b/extern/ceres/internal/ceres/visibility_based_preconditioner.h
@@ -0,0 +1,233 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Preconditioners for linear systems that arise in Structure from
+// Motion problems. VisibilityBasedPreconditioner implements:
+//
+// CLUSTER_JACOBI
+// CLUSTER_TRIDIAGONAL
+//
+// Detailed descriptions of these preconditions beyond what is
+// documented here can be found in
+//
+// Visibility Based Preconditioning for Bundle Adjustment
+// A. Kushal & S. Agarwal, CVPR 2012.
+//
+// http://www.cs.washington.edu/homes/sagarwal/vbp.pdf
+//
+// The two preconditioners share enough code that its most efficient
+// to implement them as part of the same code base.
+
+#ifndef CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
+#define CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
+
+#include <set>
+#include <vector>
+#include <utility>
+#include "ceres/collections_port.h"
+#include "ceres/graph.h"
+#include "ceres/internal/macros.h"
+#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
+#include "ceres/preconditioner.h"
+#include "ceres/suitesparse.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockRandomAccessSparseMatrix;
+class BlockSparseMatrix;
+struct CompressedRowBlockStructure;
+class SchurEliminatorBase;
+
+// This class implements visibility based preconditioners for
+// Structure from Motion/Bundle Adjustment problems. The name
+// VisibilityBasedPreconditioner comes from the fact that the sparsity
+// structure of the preconditioner matrix is determined by analyzing
+// the visibility structure of the scene, i.e. which cameras see which
+// points.
+//
+// The key idea of visibility based preconditioning is to identify
+// cameras that we expect have strong interactions, and then using the
+// entries in the Schur complement matrix corresponding to these
+// camera pairs as an approximation to the full Schur complement.
+//
+// CLUSTER_JACOBI identifies these camera pairs by clustering cameras,
+// and considering all non-zero camera pairs within each cluster. The
+// clustering in the current implementation is done using the
+// Canonical Views algorithm of Simon et al. (see
+// canonical_views_clustering.h). For the purposes of clustering, the
+// similarity or the degree of interaction between a pair of cameras
+// is measured by counting the number of points visible in both the
+// cameras. Thus the name VisibilityBasedPreconditioner. Further, if we
+// were to permute the parameter blocks such that all the cameras in
+// the same cluster occur contiguously, the preconditioner matrix will
+// be a block diagonal matrix with blocks corresponding to the
+// clusters. Thus in analogy with the Jacobi preconditioner we refer
+// to this as the CLUSTER_JACOBI preconditioner.
+//
+// CLUSTER_TRIDIAGONAL adds more mass to the CLUSTER_JACOBI
+// preconditioner by considering the interaction between clusters and
+// identifying strong interactions between cluster pairs. This is done
+// by constructing a weighted graph on the clusters, with the weight
+// on the edges connecting two clusters proportional to the number of
+// 3D points visible to cameras in both the clusters. A degree-2
+// maximum spanning forest is identified in this graph and the camera
+// pairs contained in the edges of this forest are added to the
+// preconditioner. The detailed reasoning for this construction is
+// explained in the paper mentioned above.
+//
+// Degree-2 spanning trees and forests have the property that they
+// correspond to tri-diagonal matrices. Thus there exist a permutation
+// of the camera blocks under which the CLUSTER_TRIDIAGONAL
+// preconditioner matrix is a block tridiagonal matrix, and thus the
+// name for the preconditioner.
+//
+// Thread Safety: This class is NOT thread safe.
+//
+// Example usage:
+//
+// LinearSolver::Options options;
+// options.preconditioner_type = CLUSTER_JACOBI;
+// options.elimination_groups.push_back(num_points);
+// options.elimination_groups.push_back(num_cameras);
+// VisibilityBasedPreconditioner preconditioner(
+// *A.block_structure(), options);
+// preconditioner.Update(A, NULL);
+// preconditioner.RightMultiply(x, y);
+//
+#ifndef CERES_NO_SUITESPARSE
+class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
+ public:
+ // Initialize the symbolic structure of the preconditioner. bs is
+ // the block structure of the linear system to be solved. It is used
+ // to determine the sparsity structure of the preconditioner matrix.
+ //
+ // It has the same structural requirement as other Schur complement
+ // based solvers. Please see schur_eliminator.h for more details.
+ VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options);
+ virtual ~VisibilityBasedPreconditioner();
+
+ // Preconditioner interface
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ friend class VisibilityBasedPreconditionerTest;
+
+ private:
+ virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
+ void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
+ void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
+ void InitStorage(const CompressedRowBlockStructure& bs);
+ void InitEliminator(const CompressedRowBlockStructure& bs);
+ LinearSolverTerminationType Factorize();
+ void ScaleOffDiagonalCells();
+
+ void ClusterCameras(const std::vector<std::set<int> >& visibility);
+ void FlattenMembershipMap(const HashMap<int, int>& membership_map,
+ std::vector<int>* membership_vector) const;
+ void ComputeClusterVisibility(
+ const std::vector<std::set<int> >& visibility,
+ std::vector<std::set<int> >* cluster_visibility) const;
+ WeightedGraph<int>* CreateClusterGraph(
+ const std::vector<std::set<int> >& visibility) const;
+ void ForestToClusterPairs(const WeightedGraph<int>& forest,
+ HashSet<std::pair<int, int> >* cluster_pairs) const;
+ void ComputeBlockPairsInPreconditioner(const CompressedRowBlockStructure& bs);
+ bool IsBlockPairInPreconditioner(int block1, int block2) const;
+ bool IsBlockPairOffDiagonal(int block1, int block2) const;
+
+ Preconditioner::Options options_;
+
+ // Number of parameter blocks in the schur complement.
+ int num_blocks_;
+ int num_clusters_;
+
+ // Sizes of the blocks in the schur complement.
+ std::vector<int> block_size_;
+
+ // Mapping from cameras to clusters.
+ std::vector<int> cluster_membership_;
+
+ // Non-zero camera pairs from the schur complement matrix that are
+ // present in the preconditioner, sorted by row (first element of
+ // each pair), then column (second).
+ std::set<std::pair<int, int> > block_pairs_;
+
+ // Set of cluster pairs (including self pairs (i,i)) in the
+ // preconditioner.
+ HashSet<std::pair<int, int> > cluster_pairs_;
+ scoped_ptr<SchurEliminatorBase> eliminator_;
+
+ // Preconditioner matrix.
+ scoped_ptr<BlockRandomAccessSparseMatrix> m_;
+
+ // RightMultiply is a const method for LinearOperators. It is
+ // implemented using CHOLMOD's sparse triangular matrix solve
+ // function. This however requires non-const access to the
+ // SuiteSparse context object, even though it does not result in any
+ // of the state of the preconditioner being modified.
+ SuiteSparse ss_;
+
+ // Symbolic and numeric factorization of the preconditioner.
+ cholmod_factor* factor_;
+
+ // Temporary vector used by RightMultiply.
+ cholmod_dense* tmp_rhs_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(VisibilityBasedPreconditioner);
+};
+#else // SuiteSparse
+// If SuiteSparse is not compiled in, the preconditioner is not
+// available.
+class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
+ public:
+ VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
+ const Preconditioner::Options& options) {
+ LOG(FATAL) << "Visibility based preconditioning is not available. Please "
+ "build Ceres with SuiteSparse.";
+ }
+ virtual ~VisibilityBasedPreconditioner() {}
+ virtual void RightMultiply(const double* x, double* y) const {}
+ virtual void LeftMultiply(const double* x, double* y) const {}
+ virtual int num_rows() const { return -1; }
+ virtual int num_cols() const { return -1; }
+
+ private:
+ bool UpdateImpl(const BlockSparseMatrix& A, const double* D) {
+ return false;
+ }
+};
+#endif // CERES_NO_SUITESPARSE
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
diff --git a/extern/ceres/internal/ceres/wall_time.cc b/extern/ceres/internal/ceres/wall_time.cc
new file mode 100644
index 00000000000..c353973cc3e
--- /dev/null
+++ b/extern/ceres/internal/ceres/wall_time.cc
@@ -0,0 +1,96 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: strandmark@google.com (Petter Strandmark)
+
+#include "ceres/wall_time.h"
+
+#ifdef CERES_USE_OPENMP
+#include <omp.h>
+#else
+#include <ctime>
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace ceres {
+namespace internal {
+
+double WallTimeInSeconds() {
+#ifdef CERES_USE_OPENMP
+ return omp_get_wtime();
+#else
+#ifdef _WIN32
+ return static_cast<double>(std::time(NULL));
+#else
+ timeval time_val;
+ gettimeofday(&time_val, NULL);
+ return (time_val.tv_sec + time_val.tv_usec * 1e-6);
+#endif
+#endif
+}
+
+EventLogger::EventLogger(const std::string& logger_name)
+ : start_time_(WallTimeInSeconds()),
+ last_event_time_(start_time_),
+ events_("") {
+ StringAppendF(&events_,
+ "\n%s\n Delta Cumulative\n",
+ logger_name.c_str());
+}
+
+EventLogger::~EventLogger() {
+ if (VLOG_IS_ON(3)) {
+ AddEvent("Total");
+ VLOG(2) << "\n" << events_ << "\n";
+ }
+}
+
+void EventLogger::AddEvent(const std::string& event_name) {
+ if (!VLOG_IS_ON(3)) {
+ return;
+ }
+
+ const double current_time = WallTimeInSeconds();
+ const double relative_time_delta = current_time - last_event_time_;
+ const double absolute_time_delta = current_time - start_time_;
+ last_event_time_ = current_time;
+
+ StringAppendF(&events_,
+ " %30s : %10.5f %10.5f\n",
+ event_name.c_str(),
+ relative_time_delta,
+ absolute_time_delta);
+}
+
+} // namespace internal
+} // namespace ceres
diff --git a/extern/ceres/internal/ceres/wall_time.h b/extern/ceres/internal/ceres/wall_time.h
new file mode 100644
index 00000000000..966aa67cab6
--- /dev/null
+++ b/extern/ceres/internal/ceres/wall_time.h
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2015 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: strandmark@google.com (Petter Strandmark)
+
+#ifndef CERES_INTERNAL_WALL_TIME_H_
+#define CERES_INTERNAL_WALL_TIME_H_
+
+#include <map>
+#include <string>
+#include "ceres/internal/port.h"
+#include "ceres/stringprintf.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+// Returns time, in seconds, from some arbitrary starting point. If
+// OpenMP is available then the high precision openmp_get_wtime()
+// function is used. Otherwise on unixes, gettimeofday is used. The
+// granularity is in seconds on windows systems.
+double WallTimeInSeconds();
+
+// Log a series of events, recording for each event the time elapsed
+// since the last event and since the creation of the object.
+//
+// The information is output to VLOG(3) upon destruction. A
+// name::Total event is added as the final event right before
+// destruction.
+//
+// Example usage:
+//
+// void Foo() {
+// EventLogger event_logger("Foo");
+// Bar1();
+// event_logger.AddEvent("Bar1")
+// Bar2();
+// event_logger.AddEvent("Bar2")
+// Bar3();
+// }
+//
+// Will produce output that looks like
+//
+// Foo
+// Bar1: time1 time1
+// Bar2: time2 time1 + time2;
+// Total: time3 time1 + time2 + time3;
+class EventLogger {
+ public:
+ explicit EventLogger(const std::string& logger_name);
+ ~EventLogger();
+ void AddEvent(const std::string& event_name);
+
+ private:
+ const double start_time_;
+ double last_event_time_;
+ std::string events_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_WALL_TIME_H_
diff --git a/extern/libmv/third_party/ceres/mkfiles.sh b/extern/ceres/mkfiles.sh
index cb07663e94a..cb07663e94a 100755
--- a/extern/libmv/third_party/ceres/mkfiles.sh
+++ b/extern/ceres/mkfiles.sh
diff --git a/extern/libmv/third_party/ceres/patches/series b/extern/ceres/patches/series
index e69de29bb2d..e69de29bb2d 100644
--- a/extern/libmv/third_party/ceres/patches/series
+++ b/extern/ceres/patches/series
diff --git a/extern/clew/SConscript b/extern/clew/SConscript
deleted file mode 100644
index 14a03c7298e..00000000000
--- a/extern/clew/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('src/clew.c')
-
-incs = 'include'
-defs = ['CL_USE_DEPRECATED_OPENCL_1_1_APIS']
-
-env.BlenderLib ('extern_clew', sources, Split(incs), defines=defs, libtype=['system'], priority = [999])
diff --git a/extern/clew/include/clew.h b/extern/clew/include/clew.h
index 1b72f813c9f..1f79c12481b 100644
--- a/extern/clew/include/clew.h
+++ b/extern/clew/include/clew.h
@@ -78,13 +78,13 @@ extern "C" {
#define CL_API_SUFFIX__VERSION_1_0 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
#define CL_EXT_SUFFIX__VERSION_1_0 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
#define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
- #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
- #define CL_API_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK
- #define CL_EXT_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK
- #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- #define CL_API_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK
- #define CL_EXT_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK
+ #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+ #define CL_API_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK
+ #define CL_EXT_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK
+ #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+ #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+ #define CL_API_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK
+ #define CL_EXT_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK
#else
#define CL_EXTENSION_WEAK_LINK
#define CL_API_SUFFIX__VERSION_1_0
@@ -2484,7 +2484,7 @@ PFNCLCREATEFROMGLTEXTURE3D)(cl_context /* context */,
#ifdef __APPLE__
# pragma GCC diagnostic pop // ignored "-Wignored-attributes"
#endif
-
+
/* cl_khr_gl_sharing extension */
#define cl_khr_gl_sharing 1
@@ -2781,7 +2781,7 @@ CLEW_FUN_EXPORT PFNCLGETGLCONTEXTINFOKHR __clewGetGLContextInfoKH
#define CLEW_ERROR_ATEXIT_FAILED -2 //!< Error code for failing to queue the closing of the dynamic library to atexit()
//! \brief Load OpenCL dynamic library and set function entry points
-int clewInit ();
+int clewInit (void);
//! \brief Convert an OpenCL error code to its string equivalent
const char* clewErrorString (cl_int error);
diff --git a/extern/clew/src/clew.c b/extern/clew/src/clew.c
index 8c9316d3c9c..e3adabd829c 100644
--- a/extern/clew/src/clew.c
+++ b/extern/clew/src/clew.c
@@ -378,5 +378,15 @@ const char* clewErrorString(cl_int error)
, "CL_INVALID_DEVICE_PARTITION_COUNT" // -68
};
+ static const int num_errors = sizeof(strings) / sizeof(strings[0]);
+
+ if (error == -1001) {
+ return "CL_PLATFORM_NOT_FOUND_KHR";
+ }
+
+ if (error > 0 || -error >= num_errors) {
+ return "Unknown OpenCL error";
+ }
+
return strings[-error];
}
diff --git a/extern/colamd/CMakeLists.txt b/extern/colamd/CMakeLists.txt
deleted file mode 100644
index 3019ee5904e..00000000000
--- a/extern/colamd/CMakeLists.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# Contributor(s): Blender Foundation,
-# Sergey Sharybin
-#
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- Include
-)
-
-set(INC_SYS
-
-)
-
-set(SRC
- Source/colamd.c
- Source/colamd_global.c
-
- Include/colamd.h
- Include/UFconfig.h
-)
-
-blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/colamd/Doc/ChangeLog b/extern/colamd/Doc/ChangeLog
deleted file mode 100644
index 29308e9ad01..00000000000
--- a/extern/colamd/Doc/ChangeLog
+++ /dev/null
@@ -1,129 +0,0 @@
-May 31, 2007: version 2.7.0
-
- * ported to 64-bit MATLAB
-
- * subdirectories added (Source/, Include/, Lib/, Doc/, MATLAB/, Demo/)
-
-Dec 12, 2006, version 2.5.2
-
- * minor MATLAB cleanup. MATLAB functions renamed colamd2 and symamd2,
- so that they do not conflict with the built-in versions. Note that
- the MATLAB built-in functions colamd and symamd are identical to
- the colamd and symamd functions here.
-
-Aug 31, 2006: Version 2.5.1
-
- * minor change to colamd.m and symamd.m, to use etree instead
- of sparsfun.
-
-Apr. 30, 2006: Version 2.5
-
- * colamd_recommended modified, to do more careful integer overflow
- checking. It now returns size_t, not int. colamd_l_recommended
- also returns size_t. A zero is returned if an error occurs. A
- postive return value denotes success. In v2.4 and earlier,
- -1 was returned on error (an int or long).
-
- * long replaced with UF_long integer, which is long except on WIN64.
-
-Nov 15, 2005:
-
- * minor editting of comments; version number (2.4) unchanged.
-
-Changes from Version 2.3 to 2.4 (Aug 30, 2005)
-
- * Makefile now relies on ../UFconfig/UFconfig.mk
-
- * changed the dense row/col detection. The meaning of the knobs
- has thus changed.
-
- * added an option to turn off aggressive absorption. It was
- always on in versions 2.3 and earlier.
-
- * added a #define'd version number
-
- * added a function pointer (colamd_printf) for COLAMD's printing.
-
- * added a -DNPRINT option, to turn off printing at compile-time.
-
- * added a check for integer overflow in colamd_recommended
-
- * minor changes to allow for more simpler 100% test coverage
-
- * bug fix. If symamd v2.3 fails to allocate its copy of the input
- matrix, then it erroneously frees a calloc'd workspace twice.
- This bug has no effect on the MATLAB symamd mexFunction, since
- mxCalloc terminates the mexFunction if it fails to allocate
- memory. Similarly, UMFPACK is not affected because it does not
- use symamd. The bug has no effect on the colamd ordering
- routine in v2.3.
-
-Changes from Version 2.2 to 2.3 (Sept. 8, 2003)
-
- * removed the call to the MATLAB spparms ('spumoni') function.
- This can take a lot of time if you are ordering many small
- matrices. Only affects the MATLAB interface (colamdmex.c,
- symamdmex.c, colamdtestmex.c, and symamdtestmex.c). The
- usage of the optional 2nd argument to the colamd and symamd
- mexFunctions was changed accordingly.
-
-Changes from Version 2.1 to 2.2 (Sept. 23, 2002)
-
- * extensive testing routines added (colamd_test.m, colamdtestmex.c,
- and symamdtestmex.c), and the Makefile modified accordingly.
-
- * a few typos in the comments corrected
-
- * use of the MATLAB "flops" command removed from colamd_demo, and an
- m-file routine luflops.m added.
-
- * an explicit typecast from unsigned to int added, for COLAMD_C and
- COLAMD_R in colamd.h.
-
- * #include <stdio.h> added to colamd_example.c
-
-
-Changes from Version 2.0 to 2.1 (May 4, 2001)
-
- * TRUE and FALSE are predefined on some systems, so they are defined
- here only if not already defined.
-
- * web site changed
-
- * UNIX Makefile modified, to handle the case if "." is not in your path.
-
-
-Changes from Version 1.0 to 2.0 (January 31, 2000)
-
- No bugs were found in version 1.1. These changes merely add new
- functionality.
-
- * added the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro.
-
- * moved the output statistics, from A, to a separate output argument.
- The arguments changed for the C-callable routines.
-
- * added colamd_report and symamd_report.
-
- * added a C-callable symamd routine. Formerly, symamd was only
- available as a mexFunction from MATLAB.
-
- * added error-checking to symamd. Formerly, it assumed its input
- was error-free.
-
- * added the optional stats and knobs arguments to the symamd mexFunction
-
- * deleted colamd_help. A help message is still available from
- "help colamd" and "help symamd" in MATLAB.
-
- * deleted colamdtree.m and symamdtree.m. Now, colamd.m and symamd.m
- also do the elimination tree post-ordering. The Version 1.1
- colamd and symamd mexFunctions, which do not do the post-
- ordering, are now visible as colamdmex and symamdmex from
- MATLAB. Essentialy, the post-ordering is now the default
- behavior of colamd.m and symamd.m, to match the behavior of
- colmmd and symmmd. The post-ordering is only available in the
- MATLAB interface, not the C-callable interface.
-
- * made a slight change to the dense row/column detection in symamd,
- to match the stated specifications.
diff --git a/extern/colamd/Doc/lesser.txt b/extern/colamd/Doc/lesser.txt
deleted file mode 100644
index 8add30ad590..00000000000
--- a/extern/colamd/Doc/lesser.txt
+++ /dev/null
@@ -1,504 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
diff --git a/extern/colamd/Include/UFconfig.h b/extern/colamd/Include/UFconfig.h
deleted file mode 100644
index 7b5e79e544f..00000000000
--- a/extern/colamd/Include/UFconfig.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/* ========================================================================== */
-/* === UFconfig.h =========================================================== */
-/* ========================================================================== */
-
-/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages
- * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others).
- *
- * UFconfig.h provides the definition of the long integer. On most systems,
- * a C program can be compiled in LP64 mode, in which long's and pointers are
- * both 64-bits, and int's are 32-bits. Windows 64, however, uses the LLP64
- * model, in which int's and long's are 32-bits, and long long's and pointers
- * are 64-bits.
- *
- * SuiteSparse packages that include long integer versions are
- * intended for the LP64 mode. However, as a workaround for Windows 64
- * (and perhaps other systems), the long integer can be redefined.
- *
- * If _WIN64 is defined, then the __int64 type is used instead of long.
- *
- * The long integer can also be defined at compile time. For example, this
- * could be added to UFconfig.mk:
- *
- * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \
- * -D'UF_long_id="%lld"'
- *
- * This file defines UF_long as either long (on all but _WIN64) or
- * __int64 on Windows 64. The intent is that a UF_long is always a 64-bit
- * integer in a 64-bit code. ptrdiff_t might be a better choice than long;
- * it is always the same size as a pointer.
- *
- * This file also defines the SUITESPARSE_VERSION and related definitions.
- *
- * Copyright (c) 2007, University of Florida. No licensing restrictions
- * apply to this file or to the UFconfig directory. Author: Timothy A. Davis.
- */
-
-#ifndef _UFCONFIG_H
-#define _UFCONFIG_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <limits.h>
-
-/* ========================================================================== */
-/* === UF_long ============================================================== */
-/* ========================================================================== */
-
-#ifndef UF_long
-
-#ifdef _WIN64
-
-#define UF_long __int64
-#define UF_long_max _I64_MAX
-#define UF_long_id "%I64d"
-
-#else
-
-#define UF_long long
-#define UF_long_max LONG_MAX
-#define UF_long_id "%ld"
-
-#endif
-#endif
-
-/* ========================================================================== */
-/* === SuiteSparse version ================================================== */
-/* ========================================================================== */
-
-/* SuiteSparse is not a package itself, but a collection of packages, some of
- * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD,
- * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the
- * collection itself. The versions of packages within each version of
- * SuiteSparse are meant to work together. Combining one packge from one
- * version of SuiteSparse, with another package from another version of
- * SuiteSparse, may or may not work.
- *
- * SuiteSparse Version 3.4.0 contains the following packages:
- *
- * AMD version 2.2.0
- * CAMD version 2.2.0
- * COLAMD version 2.7.1
- * CCOLAMD version 2.7.1
- * CHOLMOD version 1.7.1
- * CSparse version 2.2.3
- * CXSparse version 2.2.3
- * KLU version 1.1.0
- * BTF version 1.1.0
- * LDL version 2.0.1
- * UFconfig version number is the same as SuiteSparse
- * UMFPACK version 5.4.0
- * RBio version 1.1.2
- * UFcollection version 1.2.0
- * LINFACTOR version 1.1.0
- * MESHND version 1.1.1
- * SSMULT version 2.0.0
- * MATLAB_Tools no specific version number
- * SuiteSparseQR version 1.1.2
- *
- * Other package dependencies:
- * BLAS required by CHOLMOD and UMFPACK
- * LAPACK required by CHOLMOD
- * METIS 4.0.1 required by CHOLMOD (optional) and KLU (optional)
- */
-
-#define SUITESPARSE_DATE "May 20, 2009"
-#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub))
-#define SUITESPARSE_MAIN_VERSION 3
-#define SUITESPARSE_SUB_VERSION 4
-#define SUITESPARSE_SUBSUB_VERSION 0
-#define SUITESPARSE_VERSION \
- SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION)
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/extern/colamd/Include/colamd.h b/extern/colamd/Include/colamd.h
deleted file mode 100644
index 26372d8fa96..00000000000
--- a/extern/colamd/Include/colamd.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/* ========================================================================== */
-/* === colamd/symamd prototypes and definitions ============================= */
-/* ========================================================================== */
-
-/* COLAMD / SYMAMD include file
-
- You must include this file (colamd.h) in any routine that uses colamd,
- symamd, or the related macros and definitions.
-
- Authors:
-
- The authors of the code itself are Stefan I. Larimore and Timothy A.
- Davis (davis at cise.ufl.edu), University of Florida. The algorithm was
- developed in collaboration with John Gilbert, Xerox PARC, and Esmond
- Ng, Oak Ridge National Laboratory.
-
- Acknowledgements:
-
- This work was supported by the National Science Foundation, under
- grants DMS-9504974 and DMS-9803599.
-
- Notice:
-
- Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use, copy, modify, and/or distribute
- this program, provided that the Copyright, this License, and the
- Availability of the original version is retained on all copies and made
- accessible to the end-user of any code or package that includes COLAMD
- or any modified version of COLAMD.
-
- Availability:
-
- The colamd/symamd library is available at
-
- http://www.cise.ufl.edu/research/sparse/colamd/
-
- This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h
- file. It is required by the colamd.c, colamdmex.c, and symamdmex.c
- files, and by any C code that calls the routines whose prototypes are
- listed below, or that uses the colamd/symamd definitions listed below.
-
-*/
-
-#ifndef COLAMD_H
-#define COLAMD_H
-
-/* make it easy for C++ programs to include COLAMD */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* ========================================================================== */
-/* === Include files ======================================================== */
-/* ========================================================================== */
-
-#include <stdlib.h>
-
-/* ========================================================================== */
-/* === COLAMD version ======================================================= */
-/* ========================================================================== */
-
-/* COLAMD Version 2.4 and later will include the following definitions.
- * As an example, to test if the version you are using is 2.4 or later:
- *
- * #ifdef COLAMD_VERSION
- * if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ...
- * #endif
- *
- * This also works during compile-time:
- *
- * #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4))
- * printf ("This is version 2.4 or later\n") ;
- * #else
- * printf ("This is an early version\n") ;
- * #endif
- *
- * Versions 2.3 and earlier of COLAMD do not include a #define'd version number.
- */
-
-#define COLAMD_DATE "Nov 1, 2007"
-#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
-#define COLAMD_MAIN_VERSION 2
-#define COLAMD_SUB_VERSION 7
-#define COLAMD_SUBSUB_VERSION 1
-#define COLAMD_VERSION \
- COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION)
-
-/* ========================================================================== */
-/* === Knob and statistics definitions ====================================== */
-/* ========================================================================== */
-
-/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */
-#define COLAMD_KNOBS 20
-
-/* number of output statistics. Only stats [0..6] are currently used. */
-#define COLAMD_STATS 20
-
-/* knobs [0] and stats [0]: dense row knob and output statistic. */
-#define COLAMD_DENSE_ROW 0
-
-/* knobs [1] and stats [1]: dense column knob and output statistic. */
-#define COLAMD_DENSE_COL 1
-
-/* knobs [2]: aggressive absorption */
-#define COLAMD_AGGRESSIVE 2
-
-/* stats [2]: memory defragmentation count output statistic */
-#define COLAMD_DEFRAG_COUNT 2
-
-/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */
-#define COLAMD_STATUS 3
-
-/* stats [4..6]: error info, or info on jumbled columns */
-#define COLAMD_INFO1 4
-#define COLAMD_INFO2 5
-#define COLAMD_INFO3 6
-
-/* error codes returned in stats [3]: */
-#define COLAMD_OK (0)
-#define COLAMD_OK_BUT_JUMBLED (1)
-#define COLAMD_ERROR_A_not_present (-1)
-#define COLAMD_ERROR_p_not_present (-2)
-#define COLAMD_ERROR_nrow_negative (-3)
-#define COLAMD_ERROR_ncol_negative (-4)
-#define COLAMD_ERROR_nnz_negative (-5)
-#define COLAMD_ERROR_p0_nonzero (-6)
-#define COLAMD_ERROR_A_too_small (-7)
-#define COLAMD_ERROR_col_length_negative (-8)
-#define COLAMD_ERROR_row_index_out_of_bounds (-9)
-#define COLAMD_ERROR_out_of_memory (-10)
-#define COLAMD_ERROR_internal_error (-999)
-
-
-/* ========================================================================== */
-/* === Prototypes of user-callable routines ================================= */
-/* ========================================================================== */
-
-/* define UF_long */
-#include "UFconfig.h"
-
-size_t colamd_recommended /* returns recommended value of Alen, */
- /* or 0 if input arguments are erroneous */
-(
- int nnz, /* nonzeros in A */
- int n_row, /* number of rows in A */
- int n_col /* number of columns in A */
-) ;
-
-size_t colamd_l_recommended /* returns recommended value of Alen, */
- /* or 0 if input arguments are erroneous */
-(
- UF_long nnz, /* nonzeros in A */
- UF_long n_row, /* number of rows in A */
- UF_long n_col /* number of columns in A */
-) ;
-
-void colamd_set_defaults /* sets default parameters */
-( /* knobs argument is modified on output */
- double knobs [COLAMD_KNOBS] /* parameter settings for colamd */
-) ;
-
-void colamd_l_set_defaults /* sets default parameters */
-( /* knobs argument is modified on output */
- double knobs [COLAMD_KNOBS] /* parameter settings for colamd */
-) ;
-
-int colamd /* returns (1) if successful, (0) otherwise*/
-( /* A and p arguments are modified on output */
- int n_row, /* number of rows in A */
- int n_col, /* number of columns in A */
- int Alen, /* size of the array A */
- int A [], /* row indices of A, of size Alen */
- int p [], /* column pointers of A, of size n_col+1 */
- double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
- int stats [COLAMD_STATS] /* colamd output statistics and error codes */
-) ;
-
-UF_long colamd_l /* returns (1) if successful, (0) otherwise*/
-( /* A and p arguments are modified on output */
- UF_long n_row, /* number of rows in A */
- UF_long n_col, /* number of columns in A */
- UF_long Alen, /* size of the array A */
- UF_long A [], /* row indices of A, of size Alen */
- UF_long p [], /* column pointers of A, of size n_col+1 */
- double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
- UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */
-) ;
-
-int symamd /* return (1) if OK, (0) otherwise */
-(
- int n, /* number of rows and columns of A */
- int A [], /* row indices of A */
- int p [], /* column pointers of A */
- int perm [], /* output permutation, size n_col+1 */
- double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
- int stats [COLAMD_STATS], /* output statistics and error codes */
- void * (*allocate) (size_t, size_t),
- /* pointer to calloc (ANSI C) or */
- /* mxCalloc (for MATLAB mexFunction) */
- void (*release) (void *)
- /* pointer to free (ANSI C) or */
- /* mxFree (for MATLAB mexFunction) */
-) ;
-
-UF_long symamd_l /* return (1) if OK, (0) otherwise */
-(
- UF_long n, /* number of rows and columns of A */
- UF_long A [], /* row indices of A */
- UF_long p [], /* column pointers of A */
- UF_long perm [], /* output permutation, size n_col+1 */
- double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
- UF_long stats [COLAMD_STATS], /* output statistics and error codes */
- void * (*allocate) (size_t, size_t),
- /* pointer to calloc (ANSI C) or */
- /* mxCalloc (for MATLAB mexFunction) */
- void (*release) (void *)
- /* pointer to free (ANSI C) or */
- /* mxFree (for MATLAB mexFunction) */
-) ;
-
-void colamd_report
-(
- int stats [COLAMD_STATS]
-) ;
-
-void colamd_l_report
-(
- UF_long stats [COLAMD_STATS]
-) ;
-
-void symamd_report
-(
- int stats [COLAMD_STATS]
-) ;
-
-void symamd_l_report
-(
- UF_long stats [COLAMD_STATS]
-) ;
-
-#ifndef EXTERN
-#define EXTERN extern
-#endif
-
-EXTERN int (*colamd_printf) (const char *, ...) ;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* COLAMD_H */
diff --git a/extern/colamd/README.txt b/extern/colamd/README.txt
deleted file mode 100644
index 5ed81c71d02..00000000000
--- a/extern/colamd/README.txt
+++ /dev/null
@@ -1,127 +0,0 @@
-The COLAMD ordering method - Version 2.7
--------------------------------------------------------------------------------
-
-The COLAMD column approximate minimum degree ordering algorithm computes
-a permutation vector P such that the LU factorization of A (:,P)
-tends to be sparser than that of A. The Cholesky factorization of
-(A (:,P))'*(A (:,P)) will also tend to be sparser than that of A'*A.
-SYMAMD is a symmetric minimum degree ordering method based on COLAMD,
-available as a MATLAB-callable function. It constructs a matrix M such
-that M'*M has the same pattern as A, and then uses COLAMD to compute a column
-ordering of M. Colamd and symamd tend to be faster and generate better
-orderings than their MATLAB counterparts, colmmd and symmmd.
-
-To compile and test the colamd m-files and mexFunctions, just unpack the
-COLAMD/ directory from the COLAMD.tar.gz file, and run MATLAB from
-within that directory. Next, type colamd_test to compile and test colamd
-and symamd. This will work on any computer with MATLAB (Unix, PC, or Mac).
-Alternatively, type "make" (in Unix) to compile and run a simple example C
-code, without using MATLAB.
-
-To compile and install the colamd m-files and mexFunctions, just cd to
-COLAMD/MATLAB and type colamd_install in the MATLAB command window.
-A short demo will run. Optionally, type colamd_test to run an extensive tests.
-Type "make" in Unix in the COLAMD directory to compile the C-callable
-library and to run a short demo.
-
-If you have MATLAB 7.2 or earlier, you must first edit UFconfig/UFconfig.h to
-remove the "-largeArrayDims" option from the MEX command (or just use
-colamd_make.m inside MATLAB).
-
-Colamd is a built-in routine in MATLAB, available from The
-Mathworks, Inc. Under most cases, the compiled COLAMD from Versions 2.0 to the
-current version do not differ. Colamd Versions 2.2 and 2.3 differ only in their
-mexFunction interaces to MATLAB. v2.4 fixes a bug in the symamd routine in
-v2.3. The bug (in v2.3 and earlier) has no effect on the MATLAB symamd
-mexFunction. v2.5 adds additional checks for integer overflow, so that
-the "int" version can be safely used with 64-bit pointers. Refer to the
-ChangeLog for more details.
-
-To use colamd and symamd within an application written in C, all you need are
-colamd.c, colamd_global.c, and colamd.h, which are the C-callable
-colamd/symamd codes. See colamd.c for more information on how to call
-colamd from a C program.
-
-Requires UFconfig, in the ../UFconfig directory relative to this directory.
-
- Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
-
- See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c
- file) for the License.
-
-
-Related papers:
-
- T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
- minimum degree ordering algorithm, ACM Transactions on Mathematical
- Software, vol. 30, no. 3., pp. 353-376, 2004.
-
- T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
- an approximate column minimum degree ordering algorithm, ACM
- Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
- 2004.
-
- "An approximate minimum degree column ordering algorithm",
- S. I. Larimore, MS Thesis, Dept. of Computer and Information
- Science and Engineering, University of Florida, Gainesville, FL,
- 1998. CISE Tech Report TR-98-016. Available at
- ftp://ftp.cise.ufl.edu/cis/tech-reports/tr98/tr98-016.ps
- via anonymous ftp.
-
- Approximate Deficiency for Ordering the Columns of a Matrix,
- J. L. Kern, Senior Thesis, Dept. of Computer and Information
- Science and Engineering, University of Florida, Gainesville, FL,
- 1999. Available at http://www.cise.ufl.edu/~davis/Kern/kern.ps
-
-
-Authors: Stefan I. Larimore and Timothy A. Davis, University of Florida,
-in collaboration with John Gilbert, Xerox PARC (now at UC Santa Barbara),
-and Esmong Ng, Lawrence Berkeley National Laboratory (much of this work
-he did while at Oak Ridge National Laboratory).
-
-COLAMD files:
-
- Demo simple demo
- Doc additional documentation (see colamd.c for more)
- Include include file
- Lib compiled C-callable library
- Makefile primary Unix Makefile
- MATLAB MATLAB functions
- README.txt this file
- Source C source code
-
- ./Demo:
- colamd_example.c simple example
- colamd_example.out output of colamd_example.c
- colamd_l_example.c simple example, long integers
- colamd_l_example.out output of colamd_l_example.c
- Makefile Makefile for C demos
-
- ./Doc:
- ChangeLog change log
- lesser.txt license
-
- ./Include:
- colamd.h include file
-
- ./Lib:
- Makefile Makefile for C-callable library
-
- ./MATLAB:
- colamd2.m MATLAB interface for colamd2
- colamd_demo.m simple demo
- colamd_install.m compile and install colamd2 and symamd2
- colamd_make.m compile colamd2 and symamd2
- colamdmex.ca MATLAB mexFunction for colamd2
- colamd_test.m extensive test
- colamdtestmex.c test function for colamd
- Contents.m contents of the MATLAB directory
- luflops.m test code
- Makefile Makefile for MATLAB functions
- symamd2.m MATLAB interface for symamd2
- symamdmex.c MATLAB mexFunction for symamd2
- symamdtestmex.c test function for symamd
-
- ./Source:
- colamd.c primary source code
- colamd_global.c globally defined function pointers (malloc, free, ...)
diff --git a/extern/colamd/SConscript b/extern/colamd/SConscript
deleted file mode 100644
index 7930e3ace2d..00000000000
--- a/extern/colamd/SConscript
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/python
-import sys
-import os
-
-Import('env')
-
-defs = ''
-cflags = []
-
-src = env.Glob('Source/*.c')
-
-incs = './Include'
-
-env.BlenderLib ( libname = 'extern_colamd', sources=src, includes=Split(incs), defines=Split(defs), libtype=['extern', 'player'], priority=[20,137], compileflags=cflags )
diff --git a/extern/colamd/Source/colamd.c b/extern/colamd/Source/colamd.c
deleted file mode 100644
index 5fe20d62822..00000000000
--- a/extern/colamd/Source/colamd.c
+++ /dev/null
@@ -1,3611 +0,0 @@
-/* ========================================================================== */
-/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
-/* ========================================================================== */
-
-/* COLAMD / SYMAMD
-
- colamd: an approximate minimum degree column ordering algorithm,
- for LU factorization of symmetric or unsymmetric matrices,
- QR factorization, least squares, interior point methods for
- linear programming problems, and other related problems.
-
- symamd: an approximate minimum degree ordering algorithm for Cholesky
- factorization of symmetric matrices.
-
- Purpose:
-
- Colamd computes a permutation Q such that the Cholesky factorization of
- (AQ)'(AQ) has less fill-in and requires fewer floating point operations
- than A'A. This also provides a good ordering for sparse partial
- pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
- factorization, and P is computed during numerical factorization via
- conventional partial pivoting with row interchanges. Colamd is the
- column ordering method used in SuperLU, part of the ScaLAPACK library.
- It is also available as built-in function in MATLAB Version 6,
- available from MathWorks, Inc. (http://www.mathworks.com). This
- routine can be used in place of colmmd in MATLAB.
-
- Symamd computes a permutation P of a symmetric matrix A such that the
- Cholesky factorization of PAP' has less fill-in and requires fewer
- floating point operations than A. Symamd constructs a matrix M such
- that M'M has the same nonzero pattern of A, and then orders the columns
- of M using colmmd. The column ordering of M is then returned as the
- row and column ordering P of A.
-
- Authors:
-
- The authors of the code itself are Stefan I. Larimore and Timothy A.
- Davis (davis at cise.ufl.edu), University of Florida. The algorithm was
- developed in collaboration with John Gilbert, Xerox PARC, and Esmond
- Ng, Oak Ridge National Laboratory.
-
- Acknowledgements:
-
- This work was supported by the National Science Foundation, under
- grants DMS-9504974 and DMS-9803599.
-
- Copyright and License:
-
- Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
- COLAMD is also available under alternate licenses, contact T. Davis
- for details.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
- USA
-
- Permission is hereby granted to use or copy this program under the
- terms of the GNU LGPL, provided that the Copyright, this License,
- and the Availability of the original version is retained on all copies.
- User documentation of any code that uses this code or any modified
- version of this code must cite the Copyright, this License, the
- Availability note, and "Used by permission." Permission to modify
- the code and to distribute modified code is granted, provided the
- Copyright, this License, and the Availability note are retained,
- and a notice that the code was modified is included.
-
- Availability:
-
- The colamd/symamd library is available at
-
- http://www.cise.ufl.edu/research/sparse/colamd/
-
- This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
- file. It requires the colamd.h file. It is required by the colamdmex.c
- and symamdmex.c files, for the MATLAB interface to colamd and symamd.
- Appears as ACM Algorithm 836.
-
- See the ChangeLog file for changes since Version 1.0.
-
- References:
-
- T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
- minimum degree ordering algorithm, ACM Transactions on Mathematical
- Software, vol. 30, no. 3., pp. 353-376, 2004.
-
- T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
- an approximate column minimum degree ordering algorithm, ACM
- Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
- 2004.
-
-*/
-
-/* ========================================================================== */
-/* === Description of user-callable routines ================================ */
-/* ========================================================================== */
-
-/* COLAMD includes both int and UF_long versions of all its routines. The
- * description below is for the int version. For UF_long, all int arguments
- * become UF_long. UF_long is normally defined as long, except for WIN64.
-
- ----------------------------------------------------------------------------
- colamd_recommended:
- ----------------------------------------------------------------------------
-
- C syntax:
-
- #include "colamd.h"
- size_t colamd_recommended (int nnz, int n_row, int n_col) ;
- size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
- UF_long n_col) ;
-
- Purpose:
-
- Returns recommended value of Alen for use by colamd. Returns 0
- if any input argument is negative. The use of this routine
- is optional. Not needed for symamd, which dynamically allocates
- its own memory.
-
- Note that in v2.4 and earlier, these routines returned int or long.
- They now return a value of type size_t.
-
- Arguments (all input arguments):
-
- int nnz ; Number of nonzeros in the matrix A. This must
- be the same value as p [n_col] in the call to
- colamd - otherwise you will get a wrong value
- of the recommended memory to use.
-
- int n_row ; Number of rows in the matrix A.
-
- int n_col ; Number of columns in the matrix A.
-
- ----------------------------------------------------------------------------
- colamd_set_defaults:
- ----------------------------------------------------------------------------
-
- C syntax:
-
- #include "colamd.h"
- colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
- colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
-
- Purpose:
-
- Sets the default parameters. The use of this routine is optional.
-
- Arguments:
-
- double knobs [COLAMD_KNOBS] ; Output only.
-
- NOTE: the meaning of the dense row/col knobs has changed in v2.4
-
- knobs [0] and knobs [1] control dense row and col detection:
-
- Colamd: rows with more than
- max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
- entries are removed prior to ordering. Columns with more than
- max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
- entries are removed prior to
- ordering, and placed last in the output column ordering.
-
- Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
- Rows and columns with more than
- max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
- entries are removed prior to ordering, and placed last in the
- output ordering.
-
- COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
- respectively, in colamd.h. Default values of these two knobs
- are both 10. Currently, only knobs [0] and knobs [1] are
- used, but future versions may use more knobs. If so, they will
- be properly set to their defaults by the future version of
- colamd_set_defaults, so that the code that calls colamd will
- not need to change, assuming that you either use
- colamd_set_defaults, or pass a (double *) NULL pointer as the
- knobs array to colamd or symamd.
-
- knobs [2]: aggressive absorption
-
- knobs [COLAMD_AGGRESSIVE] controls whether or not to do
- aggressive absorption during the ordering. Default is TRUE.
-
-
- ----------------------------------------------------------------------------
- colamd:
- ----------------------------------------------------------------------------
-
- C syntax:
-
- #include "colamd.h"
- int colamd (int n_row, int n_col, int Alen, int *A, int *p,
- double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
- UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
- UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
- UF_long stats [COLAMD_STATS]) ;
-
- Purpose:
-
- Computes a column ordering (Q) of A such that P(AQ)=LU or
- (AQ)'AQ=LL' have less fill-in and require fewer floating point
- operations than factorizing the unpermuted matrix A or A'A,
- respectively.
-
- Returns:
-
- TRUE (1) if successful, FALSE (0) otherwise.
-
- Arguments:
-
- int n_row ; Input argument.
-
- Number of rows in the matrix A.
- Restriction: n_row >= 0.
- Colamd returns FALSE if n_row is negative.
-
- int n_col ; Input argument.
-
- Number of columns in the matrix A.
- Restriction: n_col >= 0.
- Colamd returns FALSE if n_col is negative.
-
- int Alen ; Input argument.
-
- Restriction (see note):
- Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
- Colamd returns FALSE if these conditions are not met.
-
- Note: this restriction makes an modest assumption regarding
- the size of the two typedef's structures in colamd.h.
- We do, however, guarantee that
-
- Alen >= colamd_recommended (nnz, n_row, n_col)
-
- will be sufficient. Note: the macro version does not check
- for integer overflow, and thus is not recommended. Use
- the colamd_recommended routine instead.
-
- int A [Alen] ; Input argument, undefined on output.
-
- A is an integer array of size Alen. Alen must be at least as
- large as the bare minimum value given above, but this is very
- low, and can result in excessive run time. For best
- performance, we recommend that Alen be greater than or equal to
- colamd_recommended (nnz, n_row, n_col), which adds
- nnz/5 to the bare minimum value given above.
-
- On input, the row indices of the entries in column c of the
- matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices
- in a given column c need not be in ascending order, and
- duplicate row indices may be be present. However, colamd will
- work a little faster if both of these conditions are met
- (Colamd puts the matrix into this format, if it finds that the
- the conditions are not met).
-
- The matrix is 0-based. That is, rows are in the range 0 to
- n_row-1, and columns are in the range 0 to n_col-1. Colamd
- returns FALSE if any row index is out of range.
-
- The contents of A are modified during ordering, and are
- undefined on output.
-
- int p [n_col+1] ; Both input and output argument.
-
- p is an integer array of size n_col+1. On input, it holds the
- "pointers" for the column form of the matrix A. Column c of
- the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
- entry, p [0], must be zero, and p [c] <= p [c+1] must hold
- for all c in the range 0 to n_col-1. The value p [n_col] is
- thus the total number of entries in the pattern of the matrix A.
- Colamd returns FALSE if these conditions are not met.
-
- On output, if colamd returns TRUE, the array p holds the column
- permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
- the first column index in the new ordering, and p [n_col-1] is
- the last. That is, p [k] = j means that column j of A is the
- kth pivot column, in AQ, where k is in the range 0 to n_col-1
- (p [0] = j means that column j of A is the first column in AQ).
-
- If colamd returns FALSE, then no permutation is returned, and
- p is undefined on output.
-
- double knobs [COLAMD_KNOBS] ; Input argument.
-
- See colamd_set_defaults for a description.
-
- int stats [COLAMD_STATS] ; Output argument.
-
- Statistics on the ordering, and error status.
- See colamd.h for related definitions.
- Colamd returns FALSE if stats is not present.
-
- stats [0]: number of dense or empty rows ignored.
-
- stats [1]: number of dense or empty columns ignored (and
- ordered last in the output permutation p)
- Note that a row can become "empty" if it
- contains only "dense" and/or "empty" columns,
- and similarly a column can become "empty" if it
- only contains "dense" and/or "empty" rows.
-
- stats [2]: number of garbage collections performed.
- This can be excessively high if Alen is close
- to the minimum required value.
-
- stats [3]: status code. < 0 is an error code.
- > 1 is a warning or notice.
-
- 0 OK. Each column of the input matrix contained
- row indices in increasing order, with no
- duplicates.
-
- 1 OK, but columns of input matrix were jumbled
- (unsorted columns or duplicate entries). Colamd
- had to do some extra work to sort the matrix
- first and remove duplicate entries, but it
- still was able to return a valid permutation
- (return value of colamd was TRUE).
-
- stats [4]: highest numbered column that
- is unsorted or has duplicate
- entries.
- stats [5]: last seen duplicate or
- unsorted row index.
- stats [6]: number of duplicate or
- unsorted row indices.
-
- -1 A is a null pointer
-
- -2 p is a null pointer
-
- -3 n_row is negative
-
- stats [4]: n_row
-
- -4 n_col is negative
-
- stats [4]: n_col
-
- -5 number of nonzeros in matrix is negative
-
- stats [4]: number of nonzeros, p [n_col]
-
- -6 p [0] is nonzero
-
- stats [4]: p [0]
-
- -7 A is too small
-
- stats [4]: required size
- stats [5]: actual size (Alen)
-
- -8 a column has a negative number of entries
-
- stats [4]: column with < 0 entries
- stats [5]: number of entries in col
-
- -9 a row index is out of bounds
-
- stats [4]: column with bad row index
- stats [5]: bad row index
- stats [6]: n_row, # of rows of matrx
-
- -10 (unused; see symamd.c)
-
- -999 (unused; see symamd.c)
-
- Future versions may return more statistics in the stats array.
-
- Example:
-
- See http://www.cise.ufl.edu/research/sparse/colamd/example.c
- for a complete example.
-
- To order the columns of a 5-by-4 matrix with 11 nonzero entries in
- the following nonzero pattern
-
- x 0 x 0
- x 0 x x
- 0 x x 0
- 0 0 x x
- x x 0 0
-
- with default knobs and no output statistics, do the following:
-
- #include "colamd.h"
- #define ALEN 100
- int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
- int p [ ] = {0, 3, 5, 9, 11} ;
- int stats [COLAMD_STATS] ;
- colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
-
- The permutation is returned in the array p, and A is destroyed.
-
- ----------------------------------------------------------------------------
- symamd:
- ----------------------------------------------------------------------------
-
- C syntax:
-
- #include "colamd.h"
- int symamd (int n, int *A, int *p, int *perm,
- double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
- void (*allocate) (size_t, size_t), void (*release) (void *)) ;
- UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
- double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
- void (*allocate) (size_t, size_t), void (*release) (void *)) ;
-
- Purpose:
-
- The symamd routine computes an ordering P of a symmetric sparse
- matrix A such that the Cholesky factorization PAP' = LL' remains
- sparse. It is based on a column ordering of a matrix M constructed
- so that the nonzero pattern of M'M is the same as A. The matrix A
- is assumed to be symmetric; only the strictly lower triangular part
- is accessed. You must pass your selected memory allocator (usually
- calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
- memory for the temporary matrix M.
-
- Returns:
-
- TRUE (1) if successful, FALSE (0) otherwise.
-
- Arguments:
-
- int n ; Input argument.
-
- Number of rows and columns in the symmetrix matrix A.
- Restriction: n >= 0.
- Symamd returns FALSE if n is negative.
-
- int A [nnz] ; Input argument.
-
- A is an integer array of size nnz, where nnz = p [n].
-
- The row indices of the entries in column c of the matrix are
- held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a
- given column c need not be in ascending order, and duplicate
- row indices may be present. However, symamd will run faster
- if the columns are in sorted order with no duplicate entries.
-
- The matrix is 0-based. That is, rows are in the range 0 to
- n-1, and columns are in the range 0 to n-1. Symamd
- returns FALSE if any row index is out of range.
-
- The contents of A are not modified.
-
- int p [n+1] ; Input argument.
-
- p is an integer array of size n+1. On input, it holds the
- "pointers" for the column form of the matrix A. Column c of
- the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
- entry, p [0], must be zero, and p [c] <= p [c+1] must hold
- for all c in the range 0 to n-1. The value p [n] is
- thus the total number of entries in the pattern of the matrix A.
- Symamd returns FALSE if these conditions are not met.
-
- The contents of p are not modified.
-
- int perm [n+1] ; Output argument.
-
- On output, if symamd returns TRUE, the array perm holds the
- permutation P, where perm [0] is the first index in the new
- ordering, and perm [n-1] is the last. That is, perm [k] = j
- means that row and column j of A is the kth column in PAP',
- where k is in the range 0 to n-1 (perm [0] = j means
- that row and column j of A are the first row and column in
- PAP'). The array is used as a workspace during the ordering,
- which is why it must be of length n+1, not just n.
-
- double knobs [COLAMD_KNOBS] ; Input argument.
-
- See colamd_set_defaults for a description.
-
- int stats [COLAMD_STATS] ; Output argument.
-
- Statistics on the ordering, and error status.
- See colamd.h for related definitions.
- Symamd returns FALSE if stats is not present.
-
- stats [0]: number of dense or empty row and columns ignored
- (and ordered last in the output permutation
- perm). Note that a row/column can become
- "empty" if it contains only "dense" and/or
- "empty" columns/rows.
-
- stats [1]: (same as stats [0])
-
- stats [2]: number of garbage collections performed.
-
- stats [3]: status code. < 0 is an error code.
- > 1 is a warning or notice.
-
- 0 OK. Each column of the input matrix contained
- row indices in increasing order, with no
- duplicates.
-
- 1 OK, but columns of input matrix were jumbled
- (unsorted columns or duplicate entries). Symamd
- had to do some extra work to sort the matrix
- first and remove duplicate entries, but it
- still was able to return a valid permutation
- (return value of symamd was TRUE).
-
- stats [4]: highest numbered column that
- is unsorted or has duplicate
- entries.
- stats [5]: last seen duplicate or
- unsorted row index.
- stats [6]: number of duplicate or
- unsorted row indices.
-
- -1 A is a null pointer
-
- -2 p is a null pointer
-
- -3 (unused, see colamd.c)
-
- -4 n is negative
-
- stats [4]: n
-
- -5 number of nonzeros in matrix is negative
-
- stats [4]: # of nonzeros (p [n]).
-
- -6 p [0] is nonzero
-
- stats [4]: p [0]
-
- -7 (unused)
-
- -8 a column has a negative number of entries
-
- stats [4]: column with < 0 entries
- stats [5]: number of entries in col
-
- -9 a row index is out of bounds
-
- stats [4]: column with bad row index
- stats [5]: bad row index
- stats [6]: n_row, # of rows of matrx
-
- -10 out of memory (unable to allocate temporary
- workspace for M or count arrays using the
- "allocate" routine passed into symamd).
-
- Future versions may return more statistics in the stats array.
-
- void * (*allocate) (size_t, size_t)
-
- A pointer to a function providing memory allocation. The
- allocated memory must be returned initialized to zero. For a
- C application, this argument should normally be a pointer to
- calloc. For a MATLAB mexFunction, the routine mxCalloc is
- passed instead.
-
- void (*release) (size_t, size_t)
-
- A pointer to a function that frees memory allocated by the
- memory allocation routine above. For a C application, this
- argument should normally be a pointer to free. For a MATLAB
- mexFunction, the routine mxFree is passed instead.
-
-
- ----------------------------------------------------------------------------
- colamd_report:
- ----------------------------------------------------------------------------
-
- C syntax:
-
- #include "colamd.h"
- colamd_report (int stats [COLAMD_STATS]) ;
- colamd_l_report (UF_long stats [COLAMD_STATS]) ;
-
- Purpose:
-
- Prints the error status and statistics recorded in the stats
- array on the standard error output (for a standard C routine)
- or on the MATLAB output (for a mexFunction).
-
- Arguments:
-
- int stats [COLAMD_STATS] ; Input only. Statistics from colamd.
-
-
- ----------------------------------------------------------------------------
- symamd_report:
- ----------------------------------------------------------------------------
-
- C syntax:
-
- #include "colamd.h"
- symamd_report (int stats [COLAMD_STATS]) ;
- symamd_l_report (UF_long stats [COLAMD_STATS]) ;
-
- Purpose:
-
- Prints the error status and statistics recorded in the stats
- array on the standard error output (for a standard C routine)
- or on the MATLAB output (for a mexFunction).
-
- Arguments:
-
- int stats [COLAMD_STATS] ; Input only. Statistics from symamd.
-
-
-*/
-
-/* ========================================================================== */
-/* === Scaffolding code definitions ======================================== */
-/* ========================================================================== */
-
-/* Ensure that debugging is turned off: */
-#ifndef NDEBUG
-#define NDEBUG
-#endif
-
-/* turn on debugging by uncommenting the following line
- #undef NDEBUG
-*/
-
-/*
- Our "scaffolding code" philosophy: In our opinion, well-written library
- code should keep its "debugging" code, and just normally have it turned off
- by the compiler so as not to interfere with performance. This serves
- several purposes:
-
- (1) assertions act as comments to the reader, telling you what the code
- expects at that point. All assertions will always be true (unless
- there really is a bug, of course).
-
- (2) leaving in the scaffolding code assists anyone who would like to modify
- the code, or understand the algorithm (by reading the debugging output,
- one can get a glimpse into what the code is doing).
-
- (3) (gasp!) for actually finding bugs. This code has been heavily tested
- and "should" be fully functional and bug-free ... but you never know...
-
- The code will become outrageously slow when debugging is
- enabled. To control the level of debugging output, set an environment
- variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging,
- you should see the following message on the standard output:
-
- colamd: debug version, D = 1 (THIS WILL BE SLOW!)
-
- or a similar message for symamd. If you don't, then debugging has not
- been enabled.
-
-*/
-
-/* ========================================================================== */
-/* === Include files ======================================================== */
-/* ========================================================================== */
-
-#include "colamd.h"
-#include <limits.h>
-#include <math.h>
-
-#ifdef MATLAB_MEX_FILE
-#include "mex.h"
-#include "matrix.h"
-#endif /* MATLAB_MEX_FILE */
-
-#if !defined (NPRINT) || !defined (NDEBUG)
-#include <stdio.h>
-#endif
-
-#ifndef NULL
-#define NULL ((void *) 0)
-#endif
-
-/* ========================================================================== */
-/* === int or UF_long ======================================================= */
-/* ========================================================================== */
-
-/* define UF_long */
-#include "UFconfig.h"
-
-#ifdef DLONG
-
-#define Int UF_long
-#define ID UF_long_id
-#define Int_MAX UF_long_max
-
-#define COLAMD_recommended colamd_l_recommended
-#define COLAMD_set_defaults colamd_l_set_defaults
-#define COLAMD_MAIN colamd_l
-#define SYMAMD_MAIN symamd_l
-#define COLAMD_report colamd_l_report
-#define SYMAMD_report symamd_l_report
-
-#else
-
-#define Int int
-#define ID "%d"
-#define Int_MAX INT_MAX
-
-#define COLAMD_recommended colamd_recommended
-#define COLAMD_set_defaults colamd_set_defaults
-#define COLAMD_MAIN colamd
-#define SYMAMD_MAIN symamd
-#define COLAMD_report colamd_report
-#define SYMAMD_report symamd_report
-
-#endif
-
-/* ========================================================================== */
-/* === Row and Column structures ============================================ */
-/* ========================================================================== */
-
-/* User code that makes use of the colamd/symamd routines need not directly */
-/* reference these structures. They are used only for colamd_recommended. */
-
-typedef struct Colamd_Col_struct
-{
- Int start ; /* index for A of first row in this column, or DEAD */
- /* if column is dead */
- Int length ; /* number of rows in this column */
- union
- {
- Int thickness ; /* number of original columns represented by this */
- /* col, if the column is alive */
- Int parent ; /* parent in parent tree super-column structure, if */
- /* the column is dead */
- } shared1 ;
- union
- {
- Int score ; /* the score used to maintain heap, if col is alive */
- Int order ; /* pivot ordering of this column, if col is dead */
- } shared2 ;
- union
- {
- Int headhash ; /* head of a hash bucket, if col is at the head of */
- /* a degree list */
- Int hash ; /* hash value, if col is not in a degree list */
- Int prev ; /* previous column in degree list, if col is in a */
- /* degree list (but not at the head of a degree list) */
- } shared3 ;
- union
- {
- Int degree_next ; /* next column, if col is in a degree list */
- Int hash_next ; /* next column, if col is in a hash list */
- } shared4 ;
-
-} Colamd_Col ;
-
-typedef struct Colamd_Row_struct
-{
- Int start ; /* index for A of first col in this row */
- Int length ; /* number of principal columns in this row */
- union
- {
- Int degree ; /* number of principal & non-principal columns in row */
- Int p ; /* used as a row pointer in init_rows_cols () */
- } shared1 ;
- union
- {
- Int mark ; /* for computing set differences and marking dead rows*/
- Int first_column ;/* first column in row (used in garbage collection) */
- } shared2 ;
-
-} Colamd_Row ;
-
-/* ========================================================================== */
-/* === Definitions ========================================================== */
-/* ========================================================================== */
-
-/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
-#define PUBLIC
-#define PRIVATE static
-
-#define DENSE_DEGREE(alpha,n) \
- ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
-
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-#define ONES_COMPLEMENT(r) (-(r)-1)
-
-/* -------------------------------------------------------------------------- */
-/* Change for version 2.1: define TRUE and FALSE only if not yet defined */
-/* -------------------------------------------------------------------------- */
-
-#ifndef TRUE
-#define TRUE (1)
-#endif
-
-#ifndef FALSE
-#define FALSE (0)
-#endif
-
-/* -------------------------------------------------------------------------- */
-
-#define EMPTY (-1)
-
-/* Row and column status */
-#define ALIVE (0)
-#define DEAD (-1)
-
-/* Column status */
-#define DEAD_PRINCIPAL (-1)
-#define DEAD_NON_PRINCIPAL (-2)
-
-/* Macros for row and column status update and checking. */
-#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
-#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
-#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
-#define COL_IS_DEAD(c) (Col [c].start < ALIVE)
-#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
-#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
-#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
-#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
-#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
-
-/* ========================================================================== */
-/* === Colamd reporting mechanism =========================================== */
-/* ========================================================================== */
-
-#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
-/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
-#define INDEX(i) ((i)+1)
-#else
-/* In C, matrices are 0-based and indices are reported as such in *_report */
-#define INDEX(i) (i)
-#endif
-
-/* All output goes through the PRINTF macro. */
-#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
-
-/* ========================================================================== */
-/* === Prototypes of PRIVATE routines ======================================= */
-/* ========================================================================== */
-
-PRIVATE Int init_rows_cols
-(
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A [],
- Int p [],
- Int stats [COLAMD_STATS]
-) ;
-
-PRIVATE void init_scoring
-(
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A [],
- Int head [],
- double knobs [COLAMD_KNOBS],
- Int *p_n_row2,
- Int *p_n_col2,
- Int *p_max_deg
-) ;
-
-PRIVATE Int find_ordering
-(
- Int n_row,
- Int n_col,
- Int Alen,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A [],
- Int head [],
- Int n_col2,
- Int max_deg,
- Int pfree,
- Int aggressive
-) ;
-
-PRIVATE void order_children
-(
- Int n_col,
- Colamd_Col Col [],
- Int p []
-) ;
-
-PRIVATE void detect_super_cols
-(
-
-#ifndef NDEBUG
- Int n_col,
- Colamd_Row Row [],
-#endif /* NDEBUG */
-
- Colamd_Col Col [],
- Int A [],
- Int head [],
- Int row_start,
- Int row_length
-) ;
-
-PRIVATE Int garbage_collection
-(
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A [],
- Int *pfree
-) ;
-
-PRIVATE Int clear_mark
-(
- Int tag_mark,
- Int max_mark,
- Int n_row,
- Colamd_Row Row []
-) ;
-
-PRIVATE void print_report
-(
- char *method,
- Int stats [COLAMD_STATS]
-) ;
-
-/* ========================================================================== */
-/* === Debugging prototypes and definitions ================================= */
-/* ========================================================================== */
-
-#ifndef NDEBUG
-
-#include <assert.h>
-
-/* colamd_debug is the *ONLY* global variable, and is only */
-/* present when debugging */
-
-PRIVATE Int colamd_debug = 0 ; /* debug print level */
-
-#define DEBUG0(params) { PRINTF (params) ; }
-#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
-#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
-#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
-#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
-
-#ifdef MATLAB_MEX_FILE
-#define ASSERT(expression) (mxAssert ((expression), ""))
-#else
-#define ASSERT(expression) (assert (expression))
-#endif /* MATLAB_MEX_FILE */
-
-PRIVATE void colamd_get_debug /* gets the debug print level from getenv */
-(
- char *method
-) ;
-
-PRIVATE void debug_deg_lists
-(
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int head [],
- Int min_score,
- Int should,
- Int max_deg
-) ;
-
-PRIVATE void debug_mark
-(
- Int n_row,
- Colamd_Row Row [],
- Int tag_mark,
- Int max_mark
-) ;
-
-PRIVATE void debug_matrix
-(
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A []
-) ;
-
-PRIVATE void debug_structures
-(
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A [],
- Int n_col2
-) ;
-
-#else /* NDEBUG */
-
-/* === No debugging ========================================================= */
-
-#define DEBUG0(params) ;
-#define DEBUG1(params) ;
-#define DEBUG2(params) ;
-#define DEBUG3(params) ;
-#define DEBUG4(params) ;
-
-#define ASSERT(expression)
-
-#endif /* NDEBUG */
-
-/* ========================================================================== */
-/* === USER-CALLABLE ROUTINES: ============================================== */
-/* ========================================================================== */
-
-/* ========================================================================== */
-/* === colamd_recommended =================================================== */
-/* ========================================================================== */
-
-/*
- The colamd_recommended routine returns the suggested size for Alen. This
- value has been determined to provide good balance between the number of
- garbage collections and the memory requirements for colamd. If any
- argument is negative, or if integer overflow occurs, a 0 is returned as an
- error condition. 2*nnz space is required for the row and column
- indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
- required for the Col and Row arrays, respectively, which are internal to
- colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the
- minimal amount of "elbow room", and nnz/5 more space is recommended for
- run time efficiency.
-
- Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
-
- This function is not needed when using symamd.
-*/
-
-/* add two values of type size_t, and check for integer overflow */
-static size_t t_add (size_t a, size_t b, int *ok)
-{
- (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
- return ((*ok) ? (a + b) : 0) ;
-}
-
-/* compute a*k where k is a small integer, and check for integer overflow */
-static size_t t_mult (size_t a, size_t k, int *ok)
-{
- size_t i, s = 0 ;
- for (i = 0 ; i < k ; i++)
- {
- s = t_add (s, a, ok) ;
- }
- return (s) ;
-}
-
-/* size of the Col and Row structures */
-#define COLAMD_C(n_col,ok) \
- ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
-
-#define COLAMD_R(n_row,ok) \
- ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
-
-
-PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */
-(
- /* === Parameters ======================================================= */
-
- Int nnz, /* number of nonzeros in A */
- Int n_row, /* number of rows in A */
- Int n_col /* number of columns in A */
-)
-{
- size_t s, c, r ;
- int ok = TRUE ;
- if (nnz < 0 || n_row < 0 || n_col < 0)
- {
- return (0) ;
- }
- s = t_mult (nnz, 2, &ok) ; /* 2*nnz */
- c = COLAMD_C (n_col, &ok) ; /* size of column structures */
- r = COLAMD_R (n_row, &ok) ; /* size of row structures */
- s = t_add (s, c, &ok) ;
- s = t_add (s, r, &ok) ;
- s = t_add (s, n_col, &ok) ; /* elbow room */
- s = t_add (s, nnz/5, &ok) ; /* elbow room */
- ok = ok && (s < Int_MAX) ;
- return (ok ? s : 0) ;
-}
-
-
-/* ========================================================================== */
-/* === colamd_set_defaults ================================================== */
-/* ========================================================================== */
-
-/*
- The colamd_set_defaults routine sets the default values of the user-
- controllable parameters for colamd and symamd:
-
- Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
- entries are removed prior to ordering. Columns with more than
- max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
- prior to ordering, and placed last in the output column ordering.
-
- Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
- entries are removed prior to ordering, and placed last in the
- output ordering.
-
- knobs [0] dense row control
-
- knobs [1] dense column control
-
- knobs [2] if nonzero, do aggresive absorption
-
- knobs [3..19] unused, but future versions might use this
-
-*/
-
-PUBLIC void COLAMD_set_defaults
-(
- /* === Parameters ======================================================= */
-
- double knobs [COLAMD_KNOBS] /* knob array */
-)
-{
- /* === Local variables ================================================== */
-
- Int i ;
-
- if (!knobs)
- {
- return ; /* no knobs to initialize */
- }
- for (i = 0 ; i < COLAMD_KNOBS ; i++)
- {
- knobs [i] = 0 ;
- }
- knobs [COLAMD_DENSE_ROW] = 10 ;
- knobs [COLAMD_DENSE_COL] = 10 ;
- knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/
-}
-
-
-/* ========================================================================== */
-/* === symamd =============================================================== */
-/* ========================================================================== */
-
-PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */
-(
- /* === Parameters ======================================================= */
-
- Int n, /* number of rows and columns of A */
- Int A [], /* row indices of A */
- Int p [], /* column pointers of A */
- Int perm [], /* output permutation, size n+1 */
- double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
- Int stats [COLAMD_STATS], /* output statistics and error codes */
- void * (*allocate) (size_t, size_t),
- /* pointer to calloc (ANSI C) or */
- /* mxCalloc (for MATLAB mexFunction) */
- void (*release) (void *)
- /* pointer to free (ANSI C) or */
- /* mxFree (for MATLAB mexFunction) */
-)
-{
- /* === Local variables ================================================== */
-
- Int *count ; /* length of each column of M, and col pointer*/
- Int *mark ; /* mark array for finding duplicate entries */
- Int *M ; /* row indices of matrix M */
- size_t Mlen ; /* length of M */
- Int n_row ; /* number of rows in M */
- Int nnz ; /* number of entries in A */
- Int i ; /* row index of A */
- Int j ; /* column index of A */
- Int k ; /* row index of M */
- Int mnz ; /* number of nonzeros in M */
- Int pp ; /* index into a column of A */
- Int last_row ; /* last row seen in the current column */
- Int length ; /* number of nonzeros in a column */
-
- double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */
- double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */
-
-#ifndef NDEBUG
- colamd_get_debug ("symamd") ;
-#endif /* NDEBUG */
-
- /* === Check the input arguments ======================================== */
-
- if (!stats)
- {
- DEBUG0 (("symamd: stats not present\n")) ;
- return (FALSE) ;
- }
- for (i = 0 ; i < COLAMD_STATS ; i++)
- {
- stats [i] = 0 ;
- }
- stats [COLAMD_STATUS] = COLAMD_OK ;
- stats [COLAMD_INFO1] = -1 ;
- stats [COLAMD_INFO2] = -1 ;
-
- if (!A)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
- DEBUG0 (("symamd: A not present\n")) ;
- return (FALSE) ;
- }
-
- if (!p) /* p is not present */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
- DEBUG0 (("symamd: p not present\n")) ;
- return (FALSE) ;
- }
-
- if (n < 0) /* n must be >= 0 */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
- stats [COLAMD_INFO1] = n ;
- DEBUG0 (("symamd: n negative %d\n", n)) ;
- return (FALSE) ;
- }
-
- nnz = p [n] ;
- if (nnz < 0) /* nnz must be >= 0 */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
- stats [COLAMD_INFO1] = nnz ;
- DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
- return (FALSE) ;
- }
-
- if (p [0] != 0)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
- stats [COLAMD_INFO1] = p [0] ;
- DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
- return (FALSE) ;
- }
-
- /* === If no knobs, set default knobs =================================== */
-
- if (!knobs)
- {
- COLAMD_set_defaults (default_knobs) ;
- knobs = default_knobs ;
- }
-
- /* === Allocate count and mark ========================================== */
-
- count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
- if (!count)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
- DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
- return (FALSE) ;
- }
-
- mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
- if (!mark)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
- (*release) ((void *) count) ;
- DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
- return (FALSE) ;
- }
-
- /* === Compute column counts of M, check if A is valid ================== */
-
- stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
-
- for (i = 0 ; i < n ; i++)
- {
- mark [i] = -1 ;
- }
-
- for (j = 0 ; j < n ; j++)
- {
- last_row = -1 ;
-
- length = p [j+1] - p [j] ;
- if (length < 0)
- {
- /* column pointers must be non-decreasing */
- stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
- stats [COLAMD_INFO1] = j ;
- stats [COLAMD_INFO2] = length ;
- (*release) ((void *) count) ;
- (*release) ((void *) mark) ;
- DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
- return (FALSE) ;
- }
-
- for (pp = p [j] ; pp < p [j+1] ; pp++)
- {
- i = A [pp] ;
- if (i < 0 || i >= n)
- {
- /* row index i, in column j, is out of bounds */
- stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
- stats [COLAMD_INFO1] = j ;
- stats [COLAMD_INFO2] = i ;
- stats [COLAMD_INFO3] = n ;
- (*release) ((void *) count) ;
- (*release) ((void *) mark) ;
- DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
- return (FALSE) ;
- }
-
- if (i <= last_row || mark [i] == j)
- {
- /* row index is unsorted or repeated (or both), thus col */
- /* is jumbled. This is a notice, not an error condition. */
- stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
- stats [COLAMD_INFO1] = j ;
- stats [COLAMD_INFO2] = i ;
- (stats [COLAMD_INFO3]) ++ ;
- DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
- }
-
- if (i > j && mark [i] != j)
- {
- /* row k of M will contain column indices i and j */
- count [i]++ ;
- count [j]++ ;
- }
-
- /* mark the row as having been seen in this column */
- mark [i] = j ;
-
- last_row = i ;
- }
- }
-
- /* v2.4: removed free(mark) */
-
- /* === Compute column pointers of M ===================================== */
-
- /* use output permutation, perm, for column pointers of M */
- perm [0] = 0 ;
- for (j = 1 ; j <= n ; j++)
- {
- perm [j] = perm [j-1] + count [j-1] ;
- }
- for (j = 0 ; j < n ; j++)
- {
- count [j] = perm [j] ;
- }
-
- /* === Construct M ====================================================== */
-
- mnz = perm [n] ;
- n_row = mnz / 2 ;
- Mlen = COLAMD_recommended (mnz, n_row, n) ;
- M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
- DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
- n_row, n, mnz, (double) Mlen)) ;
-
- if (!M)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
- (*release) ((void *) count) ;
- (*release) ((void *) mark) ;
- DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
- return (FALSE) ;
- }
-
- k = 0 ;
-
- if (stats [COLAMD_STATUS] == COLAMD_OK)
- {
- /* Matrix is OK */
- for (j = 0 ; j < n ; j++)
- {
- ASSERT (p [j+1] - p [j] >= 0) ;
- for (pp = p [j] ; pp < p [j+1] ; pp++)
- {
- i = A [pp] ;
- ASSERT (i >= 0 && i < n) ;
- if (i > j)
- {
- /* row k of M contains column indices i and j */
- M [count [i]++] = k ;
- M [count [j]++] = k ;
- k++ ;
- }
- }
- }
- }
- else
- {
- /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */
- DEBUG0 (("symamd: Duplicates in A.\n")) ;
- for (i = 0 ; i < n ; i++)
- {
- mark [i] = -1 ;
- }
- for (j = 0 ; j < n ; j++)
- {
- ASSERT (p [j+1] - p [j] >= 0) ;
- for (pp = p [j] ; pp < p [j+1] ; pp++)
- {
- i = A [pp] ;
- ASSERT (i >= 0 && i < n) ;
- if (i > j && mark [i] != j)
- {
- /* row k of M contains column indices i and j */
- M [count [i]++] = k ;
- M [count [j]++] = k ;
- k++ ;
- mark [i] = j ;
- }
- }
- }
- /* v2.4: free(mark) moved below */
- }
-
- /* count and mark no longer needed */
- (*release) ((void *) count) ;
- (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */
- ASSERT (k == n_row) ;
-
- /* === Adjust the knobs for M =========================================== */
-
- for (i = 0 ; i < COLAMD_KNOBS ; i++)
- {
- cknobs [i] = knobs [i] ;
- }
-
- /* there are no dense rows in M */
- cknobs [COLAMD_DENSE_ROW] = -1 ;
- cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
-
- /* === Order the columns of M =========================================== */
-
- /* v2.4: colamd cannot fail here, so the error check is removed */
- (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
-
- /* Note that the output permutation is now in perm */
-
- /* === get the statistics for symamd from colamd ======================== */
-
- /* a dense column in colamd means a dense row and col in symamd */
- stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
-
- /* === Free M =========================================================== */
-
- (*release) ((void *) M) ;
- DEBUG0 (("symamd: done.\n")) ;
- return (TRUE) ;
-
-}
-
-/* ========================================================================== */
-/* === colamd =============================================================== */
-/* ========================================================================== */
-
-/*
- The colamd routine computes a column ordering Q of a sparse matrix
- A such that the LU factorization P(AQ) = LU remains sparse, where P is
- selected via partial pivoting. The routine can also be viewed as
- providing a permutation Q such that the Cholesky factorization
- (AQ)'(AQ) = LL' remains sparse.
-*/
-
-PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/
-(
- /* === Parameters ======================================================= */
-
- Int n_row, /* number of rows in A */
- Int n_col, /* number of columns in A */
- Int Alen, /* length of A */
- Int A [], /* row indices of A */
- Int p [], /* pointers to columns in A */
- double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
- Int stats [COLAMD_STATS] /* output statistics and error codes */
-)
-{
- /* === Local variables ================================================== */
-
- Int i ; /* loop index */
- Int nnz ; /* nonzeros in A */
- size_t Row_size ; /* size of Row [], in integers */
- size_t Col_size ; /* size of Col [], in integers */
- size_t need ; /* minimum required length of A */
- Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */
- Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */
- Int n_col2 ; /* number of non-dense, non-empty columns */
- Int n_row2 ; /* number of non-dense, non-empty rows */
- Int ngarbage ; /* number of garbage collections performed */
- Int max_deg ; /* maximum row degree */
- double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
- Int aggressive ; /* do aggressive absorption */
- int ok ;
-
-#ifndef NDEBUG
- colamd_get_debug ("colamd") ;
-#endif /* NDEBUG */
-
- /* === Check the input arguments ======================================== */
-
- if (!stats)
- {
- DEBUG0 (("colamd: stats not present\n")) ;
- return (FALSE) ;
- }
- for (i = 0 ; i < COLAMD_STATS ; i++)
- {
- stats [i] = 0 ;
- }
- stats [COLAMD_STATUS] = COLAMD_OK ;
- stats [COLAMD_INFO1] = -1 ;
- stats [COLAMD_INFO2] = -1 ;
-
- if (!A) /* A is not present */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
- DEBUG0 (("colamd: A not present\n")) ;
- return (FALSE) ;
- }
-
- if (!p) /* p is not present */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
- DEBUG0 (("colamd: p not present\n")) ;
- return (FALSE) ;
- }
-
- if (n_row < 0) /* n_row must be >= 0 */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
- stats [COLAMD_INFO1] = n_row ;
- DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
- return (FALSE) ;
- }
-
- if (n_col < 0) /* n_col must be >= 0 */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
- stats [COLAMD_INFO1] = n_col ;
- DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
- return (FALSE) ;
- }
-
- nnz = p [n_col] ;
- if (nnz < 0) /* nnz must be >= 0 */
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
- stats [COLAMD_INFO1] = nnz ;
- DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
- return (FALSE) ;
- }
-
- if (p [0] != 0)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
- stats [COLAMD_INFO1] = p [0] ;
- DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
- return (FALSE) ;
- }
-
- /* === If no knobs, set default knobs =================================== */
-
- if (!knobs)
- {
- COLAMD_set_defaults (default_knobs) ;
- knobs = default_knobs ;
- }
-
- aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
-
- /* === Allocate the Row and Col arrays from array A ===================== */
-
- ok = TRUE ;
- Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */
- Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */
-
- /* need = 2*nnz + n_col + Col_size + Row_size ; */
- need = t_mult (nnz, 2, &ok) ;
- need = t_add (need, n_col, &ok) ;
- need = t_add (need, Col_size, &ok) ;
- need = t_add (need, Row_size, &ok) ;
-
- if (!ok || need > (size_t) Alen || need > Int_MAX)
- {
- /* not enough space in array A to perform the ordering */
- stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
- stats [COLAMD_INFO1] = need ;
- stats [COLAMD_INFO2] = Alen ;
- DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
- return (FALSE) ;
- }
-
- Alen -= Col_size + Row_size ;
- Col = (Colamd_Col *) &A [Alen] ;
- Row = (Colamd_Row *) &A [Alen + Col_size] ;
-
- /* === Construct the row and column data structures ===================== */
-
- if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
- {
- /* input matrix is invalid */
- DEBUG0 (("colamd: Matrix invalid\n")) ;
- return (FALSE) ;
- }
-
- /* === Initialize scores, kill dense rows/columns ======================= */
-
- init_scoring (n_row, n_col, Row, Col, A, p, knobs,
- &n_row2, &n_col2, &max_deg) ;
-
- /* === Order the supercolumns =========================================== */
-
- ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
- n_col2, max_deg, 2*nnz, aggressive) ;
-
- /* === Order the non-principal columns ================================== */
-
- order_children (n_col, Col, p) ;
-
- /* === Return statistics in stats ======================================= */
-
- stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
- stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
- stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
- DEBUG0 (("colamd: done.\n")) ;
- return (TRUE) ;
-}
-
-
-/* ========================================================================== */
-/* === colamd_report ======================================================== */
-/* ========================================================================== */
-
-PUBLIC void COLAMD_report
-(
- Int stats [COLAMD_STATS]
-)
-{
- print_report ("colamd", stats) ;
-}
-
-
-/* ========================================================================== */
-/* === symamd_report ======================================================== */
-/* ========================================================================== */
-
-PUBLIC void SYMAMD_report
-(
- Int stats [COLAMD_STATS]
-)
-{
- print_report ("symamd", stats) ;
-}
-
-
-
-/* ========================================================================== */
-/* === NON-USER-CALLABLE ROUTINES: ========================================== */
-/* ========================================================================== */
-
-/* There are no user-callable routines beyond this point in the file */
-
-
-/* ========================================================================== */
-/* === init_rows_cols ======================================================= */
-/* ========================================================================== */
-
-/*
- Takes the column form of the matrix in A and creates the row form of the
- matrix. Also, row and column attributes are stored in the Col and Row
- structs. If the columns are un-sorted or contain duplicate row indices,
- this routine will also sort and remove duplicate row indices from the
- column form of the matrix. Returns FALSE if the matrix is invalid,
- TRUE otherwise. Not user-callable.
-*/
-
-PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */
-(
- /* === Parameters ======================================================= */
-
- Int n_row, /* number of rows of A */
- Int n_col, /* number of columns of A */
- Colamd_Row Row [], /* of size n_row+1 */
- Colamd_Col Col [], /* of size n_col+1 */
- Int A [], /* row indices of A, of size Alen */
- Int p [], /* pointers to columns in A, of size n_col+1 */
- Int stats [COLAMD_STATS] /* colamd statistics */
-)
-{
- /* === Local variables ================================================== */
-
- Int col ; /* a column index */
- Int row ; /* a row index */
- Int *cp ; /* a column pointer */
- Int *cp_end ; /* a pointer to the end of a column */
- Int *rp ; /* a row pointer */
- Int *rp_end ; /* a pointer to the end of a row */
- Int last_row ; /* previous row */
-
- /* === Initialize columns, and check column pointers ==================== */
-
- for (col = 0 ; col < n_col ; col++)
- {
- Col [col].start = p [col] ;
- Col [col].length = p [col+1] - p [col] ;
-
- if (Col [col].length < 0)
- {
- /* column pointers must be non-decreasing */
- stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
- stats [COLAMD_INFO1] = col ;
- stats [COLAMD_INFO2] = Col [col].length ;
- DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
- return (FALSE) ;
- }
-
- Col [col].shared1.thickness = 1 ;
- Col [col].shared2.score = 0 ;
- Col [col].shared3.prev = EMPTY ;
- Col [col].shared4.degree_next = EMPTY ;
- }
-
- /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
-
- /* === Scan columns, compute row degrees, and check row indices ========= */
-
- stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
-
- for (row = 0 ; row < n_row ; row++)
- {
- Row [row].length = 0 ;
- Row [row].shared2.mark = -1 ;
- }
-
- for (col = 0 ; col < n_col ; col++)
- {
- last_row = -1 ;
-
- cp = &A [p [col]] ;
- cp_end = &A [p [col+1]] ;
-
- while (cp < cp_end)
- {
- row = *cp++ ;
-
- /* make sure row indices within range */
- if (row < 0 || row >= n_row)
- {
- stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
- stats [COLAMD_INFO1] = col ;
- stats [COLAMD_INFO2] = row ;
- stats [COLAMD_INFO3] = n_row ;
- DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
- return (FALSE) ;
- }
-
- if (row <= last_row || Row [row].shared2.mark == col)
- {
- /* row index are unsorted or repeated (or both), thus col */
- /* is jumbled. This is a notice, not an error condition. */
- stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
- stats [COLAMD_INFO1] = col ;
- stats [COLAMD_INFO2] = row ;
- (stats [COLAMD_INFO3]) ++ ;
- DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
- }
-
- if (Row [row].shared2.mark != col)
- {
- Row [row].length++ ;
- }
- else
- {
- /* this is a repeated entry in the column, */
- /* it will be removed */
- Col [col].length-- ;
- }
-
- /* mark the row as having been seen in this column */
- Row [row].shared2.mark = col ;
-
- last_row = row ;
- }
- }
-
- /* === Compute row pointers ============================================= */
-
- /* row form of the matrix starts directly after the column */
- /* form of matrix in A */
- Row [0].start = p [n_col] ;
- Row [0].shared1.p = Row [0].start ;
- Row [0].shared2.mark = -1 ;
- for (row = 1 ; row < n_row ; row++)
- {
- Row [row].start = Row [row-1].start + Row [row-1].length ;
- Row [row].shared1.p = Row [row].start ;
- Row [row].shared2.mark = -1 ;
- }
-
- /* === Create row form ================================================== */
-
- if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
- {
- /* if cols jumbled, watch for repeated row indices */
- for (col = 0 ; col < n_col ; col++)
- {
- cp = &A [p [col]] ;
- cp_end = &A [p [col+1]] ;
- while (cp < cp_end)
- {
- row = *cp++ ;
- if (Row [row].shared2.mark != col)
- {
- A [(Row [row].shared1.p)++] = col ;
- Row [row].shared2.mark = col ;
- }
- }
- }
- }
- else
- {
- /* if cols not jumbled, we don't need the mark (this is faster) */
- for (col = 0 ; col < n_col ; col++)
- {
- cp = &A [p [col]] ;
- cp_end = &A [p [col+1]] ;
- while (cp < cp_end)
- {
- A [(Row [*cp++].shared1.p)++] = col ;
- }
- }
- }
-
- /* === Clear the row marks and set row degrees ========================== */
-
- for (row = 0 ; row < n_row ; row++)
- {
- Row [row].shared2.mark = 0 ;
- Row [row].shared1.degree = Row [row].length ;
- }
-
- /* === See if we need to re-create columns ============================== */
-
- if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
- {
- DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
-
-#ifndef NDEBUG
- /* make sure column lengths are correct */
- for (col = 0 ; col < n_col ; col++)
- {
- p [col] = Col [col].length ;
- }
- for (row = 0 ; row < n_row ; row++)
- {
- rp = &A [Row [row].start] ;
- rp_end = rp + Row [row].length ;
- while (rp < rp_end)
- {
- p [*rp++]-- ;
- }
- }
- for (col = 0 ; col < n_col ; col++)
- {
- ASSERT (p [col] == 0) ;
- }
- /* now p is all zero (different than when debugging is turned off) */
-#endif /* NDEBUG */
-
- /* === Compute col pointers ========================================= */
-
- /* col form of the matrix starts at A [0]. */
- /* Note, we may have a gap between the col form and the row */
- /* form if there were duplicate entries, if so, it will be */
- /* removed upon the first garbage collection */
- Col [0].start = 0 ;
- p [0] = Col [0].start ;
- for (col = 1 ; col < n_col ; col++)
- {
- /* note that the lengths here are for pruned columns, i.e. */
- /* no duplicate row indices will exist for these columns */
- Col [col].start = Col [col-1].start + Col [col-1].length ;
- p [col] = Col [col].start ;
- }
-
- /* === Re-create col form =========================================== */
-
- for (row = 0 ; row < n_row ; row++)
- {
- rp = &A [Row [row].start] ;
- rp_end = rp + Row [row].length ;
- while (rp < rp_end)
- {
- A [(p [*rp++])++] = row ;
- }
- }
- }
-
- /* === Done. Matrix is not (or no longer) jumbled ====================== */
-
- return (TRUE) ;
-}
-
-
-/* ========================================================================== */
-/* === init_scoring ========================================================= */
-/* ========================================================================== */
-
-/*
- Kills dense or empty columns and rows, calculates an initial score for
- each column, and places all columns in the degree lists. Not user-callable.
-*/
-
-PRIVATE void init_scoring
-(
- /* === Parameters ======================================================= */
-
- Int n_row, /* number of rows of A */
- Int n_col, /* number of columns of A */
- Colamd_Row Row [], /* of size n_row+1 */
- Colamd_Col Col [], /* of size n_col+1 */
- Int A [], /* column form and row form of A */
- Int head [], /* of size n_col+1 */
- double knobs [COLAMD_KNOBS],/* parameters */
- Int *p_n_row2, /* number of non-dense, non-empty rows */
- Int *p_n_col2, /* number of non-dense, non-empty columns */
- Int *p_max_deg /* maximum row degree */
-)
-{
- /* === Local variables ================================================== */
-
- Int c ; /* a column index */
- Int r, row ; /* a row index */
- Int *cp ; /* a column pointer */
- Int deg ; /* degree of a row or column */
- Int *cp_end ; /* a pointer to the end of a column */
- Int *new_cp ; /* new column pointer */
- Int col_length ; /* length of pruned column */
- Int score ; /* current column score */
- Int n_col2 ; /* number of non-dense, non-empty columns */
- Int n_row2 ; /* number of non-dense, non-empty rows */
- Int dense_row_count ; /* remove rows with more entries than this */
- Int dense_col_count ; /* remove cols with more entries than this */
- Int min_score ; /* smallest column score */
- Int max_deg ; /* maximum row degree */
- Int next_col ; /* Used to add to degree list.*/
-
-#ifndef NDEBUG
- Int debug_count ; /* debug only. */
-#endif /* NDEBUG */
-
- /* === Extract knobs ==================================================== */
-
- /* Note: if knobs contains a NaN, this is undefined: */
- if (knobs [COLAMD_DENSE_ROW] < 0)
- {
- /* only remove completely dense rows */
- dense_row_count = n_col-1 ;
- }
- else
- {
- dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
- }
- if (knobs [COLAMD_DENSE_COL] < 0)
- {
- /* only remove completely dense columns */
- dense_col_count = n_row-1 ;
- }
- else
- {
- dense_col_count =
- DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
- }
-
- DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
- max_deg = 0 ;
- n_col2 = n_col ;
- n_row2 = n_row ;
-
- /* === Kill empty columns =============================================== */
-
- /* Put the empty columns at the end in their natural order, so that LU */
- /* factorization can proceed as far as possible. */
- for (c = n_col-1 ; c >= 0 ; c--)
- {
- deg = Col [c].length ;
- if (deg == 0)
- {
- /* this is a empty column, kill and order it last */
- Col [c].shared2.order = --n_col2 ;
- KILL_PRINCIPAL_COL (c) ;
- }
- }
- DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
-
- /* === Kill dense columns =============================================== */
-
- /* Put the dense columns at the end, in their natural order */
- for (c = n_col-1 ; c >= 0 ; c--)
- {
- /* skip any dead columns */
- if (COL_IS_DEAD (c))
- {
- continue ;
- }
- deg = Col [c].length ;
- if (deg > dense_col_count)
- {
- /* this is a dense column, kill and order it last */
- Col [c].shared2.order = --n_col2 ;
- /* decrement the row degrees */
- cp = &A [Col [c].start] ;
- cp_end = cp + Col [c].length ;
- while (cp < cp_end)
- {
- Row [*cp++].shared1.degree-- ;
- }
- KILL_PRINCIPAL_COL (c) ;
- }
- }
- DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
-
- /* === Kill dense and empty rows ======================================== */
-
- for (r = 0 ; r < n_row ; r++)
- {
- deg = Row [r].shared1.degree ;
- ASSERT (deg >= 0 && deg <= n_col) ;
- if (deg > dense_row_count || deg == 0)
- {
- /* kill a dense or empty row */
- KILL_ROW (r) ;
- --n_row2 ;
- }
- else
- {
- /* keep track of max degree of remaining rows */
- max_deg = MAX (max_deg, deg) ;
- }
- }
- DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
-
- /* === Compute initial column scores ==================================== */
-
- /* At this point the row degrees are accurate. They reflect the number */
- /* of "live" (non-dense) columns in each row. No empty rows exist. */
- /* Some "live" columns may contain only dead rows, however. These are */
- /* pruned in the code below. */
-
- /* now find the initial matlab score for each column */
- for (c = n_col-1 ; c >= 0 ; c--)
- {
- /* skip dead column */
- if (COL_IS_DEAD (c))
- {
- continue ;
- }
- score = 0 ;
- cp = &A [Col [c].start] ;
- new_cp = cp ;
- cp_end = cp + Col [c].length ;
- while (cp < cp_end)
- {
- /* get a row */
- row = *cp++ ;
- /* skip if dead */
- if (ROW_IS_DEAD (row))
- {
- continue ;
- }
- /* compact the column */
- *new_cp++ = row ;
- /* add row's external degree */
- score += Row [row].shared1.degree - 1 ;
- /* guard against integer overflow */
- score = MIN (score, n_col) ;
- }
- /* determine pruned column length */
- col_length = (Int) (new_cp - &A [Col [c].start]) ;
- if (col_length == 0)
- {
- /* a newly-made null column (all rows in this col are "dense" */
- /* and have already been killed) */
- DEBUG2 (("Newly null killed: %d\n", c)) ;
- Col [c].shared2.order = --n_col2 ;
- KILL_PRINCIPAL_COL (c) ;
- }
- else
- {
- /* set column length and set score */
- ASSERT (score >= 0) ;
- ASSERT (score <= n_col) ;
- Col [c].length = col_length ;
- Col [c].shared2.score = score ;
- }
- }
- DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
- n_col-n_col2)) ;
-
- /* At this point, all empty rows and columns are dead. All live columns */
- /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
- /* yet). Rows may contain dead columns, but all live rows contain at */
- /* least one live column. */
-
-#ifndef NDEBUG
- debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
-#endif /* NDEBUG */
-
- /* === Initialize degree lists ========================================== */
-
-#ifndef NDEBUG
- debug_count = 0 ;
-#endif /* NDEBUG */
-
- /* clear the hash buckets */
- for (c = 0 ; c <= n_col ; c++)
- {
- head [c] = EMPTY ;
- }
- min_score = n_col ;
- /* place in reverse order, so low column indices are at the front */
- /* of the lists. This is to encourage natural tie-breaking */
- for (c = n_col-1 ; c >= 0 ; c--)
- {
- /* only add principal columns to degree lists */
- if (COL_IS_ALIVE (c))
- {
- DEBUG4 (("place %d score %d minscore %d ncol %d\n",
- c, Col [c].shared2.score, min_score, n_col)) ;
-
- /* === Add columns score to DList =============================== */
-
- score = Col [c].shared2.score ;
-
- ASSERT (min_score >= 0) ;
- ASSERT (min_score <= n_col) ;
- ASSERT (score >= 0) ;
- ASSERT (score <= n_col) ;
- ASSERT (head [score] >= EMPTY) ;
-
- /* now add this column to dList at proper score location */
- next_col = head [score] ;
- Col [c].shared3.prev = EMPTY ;
- Col [c].shared4.degree_next = next_col ;
-
- /* if there already was a column with the same score, set its */
- /* previous pointer to this new column */
- if (next_col != EMPTY)
- {
- Col [next_col].shared3.prev = c ;
- }
- head [score] = c ;
-
- /* see if this score is less than current min */
- min_score = MIN (min_score, score) ;
-
-#ifndef NDEBUG
- debug_count++ ;
-#endif /* NDEBUG */
-
- }
- }
-
-#ifndef NDEBUG
- DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
- debug_count, n_col, n_col-debug_count)) ;
- ASSERT (debug_count == n_col2) ;
- debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
-#endif /* NDEBUG */
-
- /* === Return number of remaining columns, and max row degree =========== */
-
- *p_n_col2 = n_col2 ;
- *p_n_row2 = n_row2 ;
- *p_max_deg = max_deg ;
-}
-
-
-/* ========================================================================== */
-/* === find_ordering ======================================================== */
-/* ========================================================================== */
-
-/*
- Order the principal columns of the supercolumn form of the matrix
- (no supercolumns on input). Uses a minimum approximate column minimum
- degree ordering method. Not user-callable.
-*/
-
-PRIVATE Int find_ordering /* return the number of garbage collections */
-(
- /* === Parameters ======================================================= */
-
- Int n_row, /* number of rows of A */
- Int n_col, /* number of columns of A */
- Int Alen, /* size of A, 2*nnz + n_col or larger */
- Colamd_Row Row [], /* of size n_row+1 */
- Colamd_Col Col [], /* of size n_col+1 */
- Int A [], /* column form and row form of A */
- Int head [], /* of size n_col+1 */
- Int n_col2, /* Remaining columns to order */
- Int max_deg, /* Maximum row degree */
- Int pfree, /* index of first free slot (2*nnz on entry) */
- Int aggressive
-)
-{
- /* === Local variables ================================================== */
-
- Int k ; /* current pivot ordering step */
- Int pivot_col ; /* current pivot column */
- Int *cp ; /* a column pointer */
- Int *rp ; /* a row pointer */
- Int pivot_row ; /* current pivot row */
- Int *new_cp ; /* modified column pointer */
- Int *new_rp ; /* modified row pointer */
- Int pivot_row_start ; /* pointer to start of pivot row */
- Int pivot_row_degree ; /* number of columns in pivot row */
- Int pivot_row_length ; /* number of supercolumns in pivot row */
- Int pivot_col_score ; /* score of pivot column */
- Int needed_memory ; /* free space needed for pivot row */
- Int *cp_end ; /* pointer to the end of a column */
- Int *rp_end ; /* pointer to the end of a row */
- Int row ; /* a row index */
- Int col ; /* a column index */
- Int max_score ; /* maximum possible score */
- Int cur_score ; /* score of current column */
- unsigned Int hash ; /* hash value for supernode detection */
- Int head_column ; /* head of hash bucket */
- Int first_col ; /* first column in hash bucket */
- Int tag_mark ; /* marker value for mark array */
- Int row_mark ; /* Row [row].shared2.mark */
- Int set_difference ; /* set difference size of row with pivot row */
- Int min_score ; /* smallest column score */
- Int col_thickness ; /* "thickness" (no. of columns in a supercol) */
- Int max_mark ; /* maximum value of tag_mark */
- Int pivot_col_thickness ; /* number of columns represented by pivot col */
- Int prev_col ; /* Used by Dlist operations. */
- Int next_col ; /* Used by Dlist operations. */
- Int ngarbage ; /* number of garbage collections performed */
-
-#ifndef NDEBUG
- Int debug_d ; /* debug loop counter */
- Int debug_step = 0 ; /* debug loop counter */
-#endif /* NDEBUG */
-
- /* === Initialization and clear mark ==================================== */
-
- max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */
- tag_mark = clear_mark (0, max_mark, n_row, Row) ;
- min_score = 0 ;
- ngarbage = 0 ;
- DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
-
- /* === Order the columns ================================================ */
-
- for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
- {
-
-#ifndef NDEBUG
- if (debug_step % 100 == 0)
- {
- DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ;
- }
- else
- {
- DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
- }
- debug_step++ ;
- debug_deg_lists (n_row, n_col, Row, Col, head,
- min_score, n_col2-k, max_deg) ;
- debug_matrix (n_row, n_col, Row, Col, A) ;
-#endif /* NDEBUG */
-
- /* === Select pivot column, and order it ============================ */
-
- /* make sure degree list isn't empty */
- ASSERT (min_score >= 0) ;
- ASSERT (min_score <= n_col) ;
- ASSERT (head [min_score] >= EMPTY) ;
-
-#ifndef NDEBUG
- for (debug_d = 0 ; debug_d < min_score ; debug_d++)
- {
- ASSERT (head [debug_d] == EMPTY) ;
- }
-#endif /* NDEBUG */
-
- /* get pivot column from head of minimum degree list */
- while (head [min_score] == EMPTY && min_score < n_col)
- {
- min_score++ ;
- }
- pivot_col = head [min_score] ;
- ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
- next_col = Col [pivot_col].shared4.degree_next ;
- head [min_score] = next_col ;
- if (next_col != EMPTY)
- {
- Col [next_col].shared3.prev = EMPTY ;
- }
-
- ASSERT (COL_IS_ALIVE (pivot_col)) ;
-
- /* remember score for defrag check */
- pivot_col_score = Col [pivot_col].shared2.score ;
-
- /* the pivot column is the kth column in the pivot order */
- Col [pivot_col].shared2.order = k ;
-
- /* increment order count by column thickness */
- pivot_col_thickness = Col [pivot_col].shared1.thickness ;
- k += pivot_col_thickness ;
- ASSERT (pivot_col_thickness > 0) ;
- DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
-
- /* === Garbage_collection, if necessary ============================= */
-
- needed_memory = MIN (pivot_col_score, n_col - k) ;
- if (pfree + needed_memory >= Alen)
- {
- pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
- ngarbage++ ;
- /* after garbage collection we will have enough */
- ASSERT (pfree + needed_memory < Alen) ;
- /* garbage collection has wiped out the Row[].shared2.mark array */
- tag_mark = clear_mark (0, max_mark, n_row, Row) ;
-
-#ifndef NDEBUG
- debug_matrix (n_row, n_col, Row, Col, A) ;
-#endif /* NDEBUG */
- }
-
- /* === Compute pivot row pattern ==================================== */
-
- /* get starting location for this new merged row */
- pivot_row_start = pfree ;
-
- /* initialize new row counts to zero */
- pivot_row_degree = 0 ;
-
- /* tag pivot column as having been visited so it isn't included */
- /* in merged pivot row */
- Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
-
- /* pivot row is the union of all rows in the pivot column pattern */
- cp = &A [Col [pivot_col].start] ;
- cp_end = cp + Col [pivot_col].length ;
- while (cp < cp_end)
- {
- /* get a row */
- row = *cp++ ;
- DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
- /* skip if row is dead */
- if (ROW_IS_ALIVE (row))
- {
- rp = &A [Row [row].start] ;
- rp_end = rp + Row [row].length ;
- while (rp < rp_end)
- {
- /* get a column */
- col = *rp++ ;
- /* add the column, if alive and untagged */
- col_thickness = Col [col].shared1.thickness ;
- if (col_thickness > 0 && COL_IS_ALIVE (col))
- {
- /* tag column in pivot row */
- Col [col].shared1.thickness = -col_thickness ;
- ASSERT (pfree < Alen) ;
- /* place column in pivot row */
- A [pfree++] = col ;
- pivot_row_degree += col_thickness ;
- }
- }
- }
- }
-
- /* clear tag on pivot column */
- Col [pivot_col].shared1.thickness = pivot_col_thickness ;
- max_deg = MAX (max_deg, pivot_row_degree) ;
-
-#ifndef NDEBUG
- DEBUG3 (("check2\n")) ;
- debug_mark (n_row, Row, tag_mark, max_mark) ;
-#endif /* NDEBUG */
-
- /* === Kill all rows used to construct pivot row ==================== */
-
- /* also kill pivot row, temporarily */
- cp = &A [Col [pivot_col].start] ;
- cp_end = cp + Col [pivot_col].length ;
- while (cp < cp_end)
- {
- /* may be killing an already dead row */
- row = *cp++ ;
- DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
- KILL_ROW (row) ;
- }
-
- /* === Select a row index to use as the new pivot row =============== */
-
- pivot_row_length = pfree - pivot_row_start ;
- if (pivot_row_length > 0)
- {
- /* pick the "pivot" row arbitrarily (first row in col) */
- pivot_row = A [Col [pivot_col].start] ;
- DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
- }
- else
- {
- /* there is no pivot row, since it is of zero length */
- pivot_row = EMPTY ;
- ASSERT (pivot_row_length == 0) ;
- }
- ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
-
- /* === Approximate degree computation =============================== */
-
- /* Here begins the computation of the approximate degree. The column */
- /* score is the sum of the pivot row "length", plus the size of the */
- /* set differences of each row in the column minus the pattern of the */
- /* pivot row itself. The column ("thickness") itself is also */
- /* excluded from the column score (we thus use an approximate */
- /* external degree). */
-
- /* The time taken by the following code (compute set differences, and */
- /* add them up) is proportional to the size of the data structure */
- /* being scanned - that is, the sum of the sizes of each column in */
- /* the pivot row. Thus, the amortized time to compute a column score */
- /* is proportional to the size of that column (where size, in this */
- /* context, is the column "length", or the number of row indices */
- /* in that column). The number of row indices in a column is */
- /* monotonically non-decreasing, from the length of the original */
- /* column on input to colamd. */
-
- /* === Compute set differences ====================================== */
-
- DEBUG3 (("** Computing set differences phase. **\n")) ;
-
- /* pivot row is currently dead - it will be revived later. */
-
- DEBUG3 (("Pivot row: ")) ;
- /* for each column in pivot row */
- rp = &A [pivot_row_start] ;
- rp_end = rp + pivot_row_length ;
- while (rp < rp_end)
- {
- col = *rp++ ;
- ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
- DEBUG3 (("Col: %d\n", col)) ;
-
- /* clear tags used to construct pivot row pattern */
- col_thickness = -Col [col].shared1.thickness ;
- ASSERT (col_thickness > 0) ;
- Col [col].shared1.thickness = col_thickness ;
-
- /* === Remove column from degree list =========================== */
-
- cur_score = Col [col].shared2.score ;
- prev_col = Col [col].shared3.prev ;
- next_col = Col [col].shared4.degree_next ;
- ASSERT (cur_score >= 0) ;
- ASSERT (cur_score <= n_col) ;
- ASSERT (cur_score >= EMPTY) ;
- if (prev_col == EMPTY)
- {
- head [cur_score] = next_col ;
- }
- else
- {
- Col [prev_col].shared4.degree_next = next_col ;
- }
- if (next_col != EMPTY)
- {
- Col [next_col].shared3.prev = prev_col ;
- }
-
- /* === Scan the column ========================================== */
-
- cp = &A [Col [col].start] ;
- cp_end = cp + Col [col].length ;
- while (cp < cp_end)
- {
- /* get a row */
- row = *cp++ ;
- row_mark = Row [row].shared2.mark ;
- /* skip if dead */
- if (ROW_IS_MARKED_DEAD (row_mark))
- {
- continue ;
- }
- ASSERT (row != pivot_row) ;
- set_difference = row_mark - tag_mark ;
- /* check if the row has been seen yet */
- if (set_difference < 0)
- {
- ASSERT (Row [row].shared1.degree <= max_deg) ;
- set_difference = Row [row].shared1.degree ;
- }
- /* subtract column thickness from this row's set difference */
- set_difference -= col_thickness ;
- ASSERT (set_difference >= 0) ;
- /* absorb this row if the set difference becomes zero */
- if (set_difference == 0 && aggressive)
- {
- DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
- KILL_ROW (row) ;
- }
- else
- {
- /* save the new mark */
- Row [row].shared2.mark = set_difference + tag_mark ;
- }
- }
- }
-
-#ifndef NDEBUG
- debug_deg_lists (n_row, n_col, Row, Col, head,
- min_score, n_col2-k-pivot_row_degree, max_deg) ;
-#endif /* NDEBUG */
-
- /* === Add up set differences for each column ======================= */
-
- DEBUG3 (("** Adding set differences phase. **\n")) ;
-
- /* for each column in pivot row */
- rp = &A [pivot_row_start] ;
- rp_end = rp + pivot_row_length ;
- while (rp < rp_end)
- {
- /* get a column */
- col = *rp++ ;
- ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
- hash = 0 ;
- cur_score = 0 ;
- cp = &A [Col [col].start] ;
- /* compact the column */
- new_cp = cp ;
- cp_end = cp + Col [col].length ;
-
- DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
-
- while (cp < cp_end)
- {
- /* get a row */
- row = *cp++ ;
- ASSERT(row >= 0 && row < n_row) ;
- row_mark = Row [row].shared2.mark ;
- /* skip if dead */
- if (ROW_IS_MARKED_DEAD (row_mark))
- {
- DEBUG4 ((" Row %d, dead\n", row)) ;
- continue ;
- }
- DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
- ASSERT (row_mark >= tag_mark) ;
- /* compact the column */
- *new_cp++ = row ;
- /* compute hash function */
- hash += row ;
- /* add set difference */
- cur_score += row_mark - tag_mark ;
- /* integer overflow... */
- cur_score = MIN (cur_score, n_col) ;
- }
-
- /* recompute the column's length */
- Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
-
- /* === Further mass elimination ================================= */
-
- if (Col [col].length == 0)
- {
- DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
- /* nothing left but the pivot row in this column */
- KILL_PRINCIPAL_COL (col) ;
- pivot_row_degree -= Col [col].shared1.thickness ;
- ASSERT (pivot_row_degree >= 0) ;
- /* order it */
- Col [col].shared2.order = k ;
- /* increment order count by column thickness */
- k += Col [col].shared1.thickness ;
- }
- else
- {
- /* === Prepare for supercolumn detection ==================== */
-
- DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
-
- /* save score so far */
- Col [col].shared2.score = cur_score ;
-
- /* add column to hash table, for supercolumn detection */
- hash %= n_col + 1 ;
-
- DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
- ASSERT (((Int) hash) <= n_col) ;
-
- head_column = head [hash] ;
- if (head_column > EMPTY)
- {
- /* degree list "hash" is non-empty, use prev (shared3) of */
- /* first column in degree list as head of hash bucket */
- first_col = Col [head_column].shared3.headhash ;
- Col [head_column].shared3.headhash = col ;
- }
- else
- {
- /* degree list "hash" is empty, use head as hash bucket */
- first_col = - (head_column + 2) ;
- head [hash] = - (col + 2) ;
- }
- Col [col].shared4.hash_next = first_col ;
-
- /* save hash function in Col [col].shared3.hash */
- Col [col].shared3.hash = (Int) hash ;
- ASSERT (COL_IS_ALIVE (col)) ;
- }
- }
-
- /* The approximate external column degree is now computed. */
-
- /* === Supercolumn detection ======================================== */
-
- DEBUG3 (("** Supercolumn detection phase. **\n")) ;
-
- detect_super_cols (
-
-#ifndef NDEBUG
- n_col, Row,
-#endif /* NDEBUG */
-
- Col, A, head, pivot_row_start, pivot_row_length) ;
-
- /* === Kill the pivotal column ====================================== */
-
- KILL_PRINCIPAL_COL (pivot_col) ;
-
- /* === Clear mark =================================================== */
-
- tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
-
-#ifndef NDEBUG
- DEBUG3 (("check3\n")) ;
- debug_mark (n_row, Row, tag_mark, max_mark) ;
-#endif /* NDEBUG */
-
- /* === Finalize the new pivot row, and column scores ================ */
-
- DEBUG3 (("** Finalize scores phase. **\n")) ;
-
- /* for each column in pivot row */
- rp = &A [pivot_row_start] ;
- /* compact the pivot row */
- new_rp = rp ;
- rp_end = rp + pivot_row_length ;
- while (rp < rp_end)
- {
- col = *rp++ ;
- /* skip dead columns */
- if (COL_IS_DEAD (col))
- {
- continue ;
- }
- *new_rp++ = col ;
- /* add new pivot row to column */
- A [Col [col].start + (Col [col].length++)] = pivot_row ;
-
- /* retrieve score so far and add on pivot row's degree. */
- /* (we wait until here for this in case the pivot */
- /* row's degree was reduced due to mass elimination). */
- cur_score = Col [col].shared2.score + pivot_row_degree ;
-
- /* calculate the max possible score as the number of */
- /* external columns minus the 'k' value minus the */
- /* columns thickness */
- max_score = n_col - k - Col [col].shared1.thickness ;
-
- /* make the score the external degree of the union-of-rows */
- cur_score -= Col [col].shared1.thickness ;
-
- /* make sure score is less or equal than the max score */
- cur_score = MIN (cur_score, max_score) ;
- ASSERT (cur_score >= 0) ;
-
- /* store updated score */
- Col [col].shared2.score = cur_score ;
-
- /* === Place column back in degree list ========================= */
-
- ASSERT (min_score >= 0) ;
- ASSERT (min_score <= n_col) ;
- ASSERT (cur_score >= 0) ;
- ASSERT (cur_score <= n_col) ;
- ASSERT (head [cur_score] >= EMPTY) ;
- next_col = head [cur_score] ;
- Col [col].shared4.degree_next = next_col ;
- Col [col].shared3.prev = EMPTY ;
- if (next_col != EMPTY)
- {
- Col [next_col].shared3.prev = col ;
- }
- head [cur_score] = col ;
-
- /* see if this score is less than current min */
- min_score = MIN (min_score, cur_score) ;
-
- }
-
-#ifndef NDEBUG
- debug_deg_lists (n_row, n_col, Row, Col, head,
- min_score, n_col2-k, max_deg) ;
-#endif /* NDEBUG */
-
- /* === Resurrect the new pivot row ================================== */
-
- if (pivot_row_degree > 0)
- {
- /* update pivot row length to reflect any cols that were killed */
- /* during super-col detection and mass elimination */
- Row [pivot_row].start = pivot_row_start ;
- Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
- ASSERT (Row [pivot_row].length > 0) ;
- Row [pivot_row].shared1.degree = pivot_row_degree ;
- Row [pivot_row].shared2.mark = 0 ;
- /* pivot row is no longer dead */
-
- DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
- pivot_row, pivot_row_degree)) ;
- }
- }
-
- /* === All principal columns have now been ordered ====================== */
-
- return (ngarbage) ;
-}
-
-
-/* ========================================================================== */
-/* === order_children ======================================================= */
-/* ========================================================================== */
-
-/*
- The find_ordering routine has ordered all of the principal columns (the
- representatives of the supercolumns). The non-principal columns have not
- yet been ordered. This routine orders those columns by walking up the
- parent tree (a column is a child of the column which absorbed it). The
- final permutation vector is then placed in p [0 ... n_col-1], with p [0]
- being the first column, and p [n_col-1] being the last. It doesn't look
- like it at first glance, but be assured that this routine takes time linear
- in the number of columns. Although not immediately obvious, the time
- taken by this routine is O (n_col), that is, linear in the number of
- columns. Not user-callable.
-*/
-
-PRIVATE void order_children
-(
- /* === Parameters ======================================================= */
-
- Int n_col, /* number of columns of A */
- Colamd_Col Col [], /* of size n_col+1 */
- Int p [] /* p [0 ... n_col-1] is the column permutation*/
-)
-{
- /* === Local variables ================================================== */
-
- Int i ; /* loop counter for all columns */
- Int c ; /* column index */
- Int parent ; /* index of column's parent */
- Int order ; /* column's order */
-
- /* === Order each non-principal column ================================== */
-
- for (i = 0 ; i < n_col ; i++)
- {
- /* find an un-ordered non-principal column */
- ASSERT (COL_IS_DEAD (i)) ;
- if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
- {
- parent = i ;
- /* once found, find its principal parent */
- do
- {
- parent = Col [parent].shared1.parent ;
- } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
-
- /* now, order all un-ordered non-principal columns along path */
- /* to this parent. collapse tree at the same time */
- c = i ;
- /* get order of parent */
- order = Col [parent].shared2.order ;
-
- do
- {
- ASSERT (Col [c].shared2.order == EMPTY) ;
-
- /* order this column */
- Col [c].shared2.order = order++ ;
- /* collaps tree */
- Col [c].shared1.parent = parent ;
-
- /* get immediate parent of this column */
- c = Col [c].shared1.parent ;
-
- /* continue until we hit an ordered column. There are */
- /* guarranteed not to be anymore unordered columns */
- /* above an ordered column */
- } while (Col [c].shared2.order == EMPTY) ;
-
- /* re-order the super_col parent to largest order for this group */
- Col [parent].shared2.order = order ;
- }
- }
-
- /* === Generate the permutation ========================================= */
-
- for (c = 0 ; c < n_col ; c++)
- {
- p [Col [c].shared2.order] = c ;
- }
-}
-
-
-/* ========================================================================== */
-/* === detect_super_cols ==================================================== */
-/* ========================================================================== */
-
-/*
- Detects supercolumns by finding matches between columns in the hash buckets.
- Check amongst columns in the set A [row_start ... row_start + row_length-1].
- The columns under consideration are currently *not* in the degree lists,
- and have already been placed in the hash buckets.
-
- The hash bucket for columns whose hash function is equal to h is stored
- as follows:
-
- if head [h] is >= 0, then head [h] contains a degree list, so:
-
- head [h] is the first column in degree bucket h.
- Col [head [h]].headhash gives the first column in hash bucket h.
-
- otherwise, the degree list is empty, and:
-
- -(head [h] + 2) is the first column in hash bucket h.
-
- For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
- column" pointer. Col [c].shared3.hash is used instead as the hash number
- for that column. The value of Col [c].shared4.hash_next is the next column
- in the same hash bucket.
-
- Assuming no, or "few" hash collisions, the time taken by this routine is
- linear in the sum of the sizes (lengths) of each column whose score has
- just been computed in the approximate degree computation.
- Not user-callable.
-*/
-
-PRIVATE void detect_super_cols
-(
- /* === Parameters ======================================================= */
-
-#ifndef NDEBUG
- /* these two parameters are only needed when debugging is enabled: */
- Int n_col, /* number of columns of A */
- Colamd_Row Row [], /* of size n_row+1 */
-#endif /* NDEBUG */
-
- Colamd_Col Col [], /* of size n_col+1 */
- Int A [], /* row indices of A */
- Int head [], /* head of degree lists and hash buckets */
- Int row_start, /* pointer to set of columns to check */
- Int row_length /* number of columns to check */
-)
-{
- /* === Local variables ================================================== */
-
- Int hash ; /* hash value for a column */
- Int *rp ; /* pointer to a row */
- Int c ; /* a column index */
- Int super_c ; /* column index of the column to absorb into */
- Int *cp1 ; /* column pointer for column super_c */
- Int *cp2 ; /* column pointer for column c */
- Int length ; /* length of column super_c */
- Int prev_c ; /* column preceding c in hash bucket */
- Int i ; /* loop counter */
- Int *rp_end ; /* pointer to the end of the row */
- Int col ; /* a column index in the row to check */
- Int head_column ; /* first column in hash bucket or degree list */
- Int first_col ; /* first column in hash bucket */
-
- /* === Consider each column in the row ================================== */
-
- rp = &A [row_start] ;
- rp_end = rp + row_length ;
- while (rp < rp_end)
- {
- col = *rp++ ;
- if (COL_IS_DEAD (col))
- {
- continue ;
- }
-
- /* get hash number for this column */
- hash = Col [col].shared3.hash ;
- ASSERT (hash <= n_col) ;
-
- /* === Get the first column in this hash bucket ===================== */
-
- head_column = head [hash] ;
- if (head_column > EMPTY)
- {
- first_col = Col [head_column].shared3.headhash ;
- }
- else
- {
- first_col = - (head_column + 2) ;
- }
-
- /* === Consider each column in the hash bucket ====================== */
-
- for (super_c = first_col ; super_c != EMPTY ;
- super_c = Col [super_c].shared4.hash_next)
- {
- ASSERT (COL_IS_ALIVE (super_c)) ;
- ASSERT (Col [super_c].shared3.hash == hash) ;
- length = Col [super_c].length ;
-
- /* prev_c is the column preceding column c in the hash bucket */
- prev_c = super_c ;
-
- /* === Compare super_c with all columns after it ================ */
-
- for (c = Col [super_c].shared4.hash_next ;
- c != EMPTY ; c = Col [c].shared4.hash_next)
- {
- ASSERT (c != super_c) ;
- ASSERT (COL_IS_ALIVE (c)) ;
- ASSERT (Col [c].shared3.hash == hash) ;
-
- /* not identical if lengths or scores are different */
- if (Col [c].length != length ||
- Col [c].shared2.score != Col [super_c].shared2.score)
- {
- prev_c = c ;
- continue ;
- }
-
- /* compare the two columns */
- cp1 = &A [Col [super_c].start] ;
- cp2 = &A [Col [c].start] ;
-
- for (i = 0 ; i < length ; i++)
- {
- /* the columns are "clean" (no dead rows) */
- ASSERT (ROW_IS_ALIVE (*cp1)) ;
- ASSERT (ROW_IS_ALIVE (*cp2)) ;
- /* row indices will same order for both supercols, */
- /* no gather scatter nessasary */
- if (*cp1++ != *cp2++)
- {
- break ;
- }
- }
-
- /* the two columns are different if the for-loop "broke" */
- if (i != length)
- {
- prev_c = c ;
- continue ;
- }
-
- /* === Got it! two columns are identical =================== */
-
- ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
-
- Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
- Col [c].shared1.parent = super_c ;
- KILL_NON_PRINCIPAL_COL (c) ;
- /* order c later, in order_children() */
- Col [c].shared2.order = EMPTY ;
- /* remove c from hash bucket */
- Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
- }
- }
-
- /* === Empty this hash bucket ======================================= */
-
- if (head_column > EMPTY)
- {
- /* corresponding degree list "hash" is not empty */
- Col [head_column].shared3.headhash = EMPTY ;
- }
- else
- {
- /* corresponding degree list "hash" is empty */
- head [hash] = EMPTY ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === garbage_collection =================================================== */
-/* ========================================================================== */
-
-/*
- Defragments and compacts columns and rows in the workspace A. Used when
- all avaliable memory has been used while performing row merging. Returns
- the index of the first free position in A, after garbage collection. The
- time taken by this routine is linear is the size of the array A, which is
- itself linear in the number of nonzeros in the input matrix.
- Not user-callable.
-*/
-
-PRIVATE Int garbage_collection /* returns the new value of pfree */
-(
- /* === Parameters ======================================================= */
-
- Int n_row, /* number of rows */
- Int n_col, /* number of columns */
- Colamd_Row Row [], /* row info */
- Colamd_Col Col [], /* column info */
- Int A [], /* A [0 ... Alen-1] holds the matrix */
- Int *pfree /* &A [0] ... pfree is in use */
-)
-{
- /* === Local variables ================================================== */
-
- Int *psrc ; /* source pointer */
- Int *pdest ; /* destination pointer */
- Int j ; /* counter */
- Int r ; /* a row index */
- Int c ; /* a column index */
- Int length ; /* length of a row or column */
-
-#ifndef NDEBUG
- Int debug_rows ;
- DEBUG2 (("Defrag..\n")) ;
- for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
- debug_rows = 0 ;
-#endif /* NDEBUG */
-
- /* === Defragment the columns =========================================== */
-
- pdest = &A[0] ;
- for (c = 0 ; c < n_col ; c++)
- {
- if (COL_IS_ALIVE (c))
- {
- psrc = &A [Col [c].start] ;
-
- /* move and compact the column */
- ASSERT (pdest <= psrc) ;
- Col [c].start = (Int) (pdest - &A [0]) ;
- length = Col [c].length ;
- for (j = 0 ; j < length ; j++)
- {
- r = *psrc++ ;
- if (ROW_IS_ALIVE (r))
- {
- *pdest++ = r ;
- }
- }
- Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
- }
- }
-
- /* === Prepare to defragment the rows =================================== */
-
- for (r = 0 ; r < n_row ; r++)
- {
- if (ROW_IS_DEAD (r) || (Row [r].length == 0))
- {
- /* This row is already dead, or is of zero length. Cannot compact
- * a row of zero length, so kill it. NOTE: in the current version,
- * there are no zero-length live rows. Kill the row (for the first
- * time, or again) just to be safe. */
- KILL_ROW (r) ;
- }
- else
- {
- /* save first column index in Row [r].shared2.first_column */
- psrc = &A [Row [r].start] ;
- Row [r].shared2.first_column = *psrc ;
- ASSERT (ROW_IS_ALIVE (r)) ;
- /* flag the start of the row with the one's complement of row */
- *psrc = ONES_COMPLEMENT (r) ;
-#ifndef NDEBUG
- debug_rows++ ;
-#endif /* NDEBUG */
- }
- }
-
- /* === Defragment the rows ============================================== */
-
- psrc = pdest ;
- while (psrc < pfree)
- {
- /* find a negative number ... the start of a row */
- if (*psrc++ < 0)
- {
- psrc-- ;
- /* get the row index */
- r = ONES_COMPLEMENT (*psrc) ;
- ASSERT (r >= 0 && r < n_row) ;
- /* restore first column index */
- *psrc = Row [r].shared2.first_column ;
- ASSERT (ROW_IS_ALIVE (r)) ;
- ASSERT (Row [r].length > 0) ;
- /* move and compact the row */
- ASSERT (pdest <= psrc) ;
- Row [r].start = (Int) (pdest - &A [0]) ;
- length = Row [r].length ;
- for (j = 0 ; j < length ; j++)
- {
- c = *psrc++ ;
- if (COL_IS_ALIVE (c))
- {
- *pdest++ = c ;
- }
- }
- Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
- ASSERT (Row [r].length > 0) ;
-#ifndef NDEBUG
- debug_rows-- ;
-#endif /* NDEBUG */
- }
- }
- /* ensure we found all the rows */
- ASSERT (debug_rows == 0) ;
-
- /* === Return the new value of pfree ==================================== */
-
- return ((Int) (pdest - &A [0])) ;
-}
-
-
-/* ========================================================================== */
-/* === clear_mark =========================================================== */
-/* ========================================================================== */
-
-/*
- Clears the Row [].shared2.mark array, and returns the new tag_mark.
- Return value is the new tag_mark. Not user-callable.
-*/
-
-PRIVATE Int clear_mark /* return the new value for tag_mark */
-(
- /* === Parameters ======================================================= */
-
- Int tag_mark, /* new value of tag_mark */
- Int max_mark, /* max allowed value of tag_mark */
-
- Int n_row, /* number of rows in A */
- Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */
-)
-{
- /* === Local variables ================================================== */
-
- Int r ;
-
- if (tag_mark <= 0 || tag_mark >= max_mark)
- {
- for (r = 0 ; r < n_row ; r++)
- {
- if (ROW_IS_ALIVE (r))
- {
- Row [r].shared2.mark = 0 ;
- }
- }
- tag_mark = 1 ;
- }
-
- return (tag_mark) ;
-}
-
-
-/* ========================================================================== */
-/* === print_report ========================================================= */
-/* ========================================================================== */
-
-PRIVATE void print_report
-(
- char *method,
- Int stats [COLAMD_STATS]
-)
-{
-
- Int i1, i2, i3 ;
-
- PRINTF (("\n%s version %d.%d, %s: ", method,
- COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
-
- if (!stats)
- {
- PRINTF (("No statistics available.\n")) ;
- return ;
- }
-
- i1 = stats [COLAMD_INFO1] ;
- i2 = stats [COLAMD_INFO2] ;
- i3 = stats [COLAMD_INFO3] ;
-
- if (stats [COLAMD_STATUS] >= 0)
- {
- PRINTF (("OK. ")) ;
- }
- else
- {
- PRINTF (("ERROR. ")) ;
- }
-
- switch (stats [COLAMD_STATUS])
- {
-
- case COLAMD_OK_BUT_JUMBLED:
-
- PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
-
- PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
- method, i3)) ;
-
- PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n",
- method, INDEX (i2))) ;
-
- PRINTF(("%s: last seen in column: %d",
- method, INDEX (i1))) ;
-
- /* no break - fall through to next case instead */
-
- case COLAMD_OK:
-
- PRINTF(("\n")) ;
-
- PRINTF(("%s: number of dense or empty rows ignored: %d\n",
- method, stats [COLAMD_DENSE_ROW])) ;
-
- PRINTF(("%s: number of dense or empty columns ignored: %d\n",
- method, stats [COLAMD_DENSE_COL])) ;
-
- PRINTF(("%s: number of garbage collections performed: %d\n",
- method, stats [COLAMD_DEFRAG_COUNT])) ;
- break ;
-
- case COLAMD_ERROR_A_not_present:
-
- PRINTF(("Array A (row indices of matrix) not present.\n")) ;
- break ;
-
- case COLAMD_ERROR_p_not_present:
-
- PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
- break ;
-
- case COLAMD_ERROR_nrow_negative:
-
- PRINTF(("Invalid number of rows (%d).\n", i1)) ;
- break ;
-
- case COLAMD_ERROR_ncol_negative:
-
- PRINTF(("Invalid number of columns (%d).\n", i1)) ;
- break ;
-
- case COLAMD_ERROR_nnz_negative:
-
- PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
- break ;
-
- case COLAMD_ERROR_p0_nonzero:
-
- PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
- break ;
-
- case COLAMD_ERROR_A_too_small:
-
- PRINTF(("Array A too small.\n")) ;
- PRINTF((" Need Alen >= %d, but given only Alen = %d.\n",
- i1, i2)) ;
- break ;
-
- case COLAMD_ERROR_col_length_negative:
-
- PRINTF
- (("Column %d has a negative number of nonzero entries (%d).\n",
- INDEX (i1), i2)) ;
- break ;
-
- case COLAMD_ERROR_row_index_out_of_bounds:
-
- PRINTF
- (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
- INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
- break ;
-
- case COLAMD_ERROR_out_of_memory:
-
- PRINTF(("Out of memory.\n")) ;
- break ;
-
- /* v2.4: internal-error case deleted */
- }
-}
-
-
-
-
-/* ========================================================================== */
-/* === colamd debugging routines ============================================ */
-/* ========================================================================== */
-
-/* When debugging is disabled, the remainder of this file is ignored. */
-
-#ifndef NDEBUG
-
-
-/* ========================================================================== */
-/* === debug_structures ===================================================== */
-/* ========================================================================== */
-
-/*
- At this point, all empty rows and columns are dead. All live columns
- are "clean" (containing no dead rows) and simplicial (no supercolumns
- yet). Rows may contain dead columns, but all live rows contain at
- least one live column.
-*/
-
-PRIVATE void debug_structures
-(
- /* === Parameters ======================================================= */
-
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A [],
- Int n_col2
-)
-{
- /* === Local variables ================================================== */
-
- Int i ;
- Int c ;
- Int *cp ;
- Int *cp_end ;
- Int len ;
- Int score ;
- Int r ;
- Int *rp ;
- Int *rp_end ;
- Int deg ;
-
- /* === Check A, Row, and Col ============================================ */
-
- for (c = 0 ; c < n_col ; c++)
- {
- if (COL_IS_ALIVE (c))
- {
- len = Col [c].length ;
- score = Col [c].shared2.score ;
- DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
- ASSERT (len > 0) ;
- ASSERT (score >= 0) ;
- ASSERT (Col [c].shared1.thickness == 1) ;
- cp = &A [Col [c].start] ;
- cp_end = cp + len ;
- while (cp < cp_end)
- {
- r = *cp++ ;
- ASSERT (ROW_IS_ALIVE (r)) ;
- }
- }
- else
- {
- i = Col [c].shared2.order ;
- ASSERT (i >= n_col2 && i < n_col) ;
- }
- }
-
- for (r = 0 ; r < n_row ; r++)
- {
- if (ROW_IS_ALIVE (r))
- {
- i = 0 ;
- len = Row [r].length ;
- deg = Row [r].shared1.degree ;
- ASSERT (len > 0) ;
- ASSERT (deg > 0) ;
- rp = &A [Row [r].start] ;
- rp_end = rp + len ;
- while (rp < rp_end)
- {
- c = *rp++ ;
- if (COL_IS_ALIVE (c))
- {
- i++ ;
- }
- }
- ASSERT (i > 0) ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === debug_deg_lists ====================================================== */
-/* ========================================================================== */
-
-/*
- Prints the contents of the degree lists. Counts the number of columns
- in the degree list and compares it to the total it should have. Also
- checks the row degrees.
-*/
-
-PRIVATE void debug_deg_lists
-(
- /* === Parameters ======================================================= */
-
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int head [],
- Int min_score,
- Int should,
- Int max_deg
-)
-{
- /* === Local variables ================================================== */
-
- Int deg ;
- Int col ;
- Int have ;
- Int row ;
-
- /* === Check the degree lists =========================================== */
-
- if (n_col > 10000 && colamd_debug <= 0)
- {
- return ;
- }
- have = 0 ;
- DEBUG4 (("Degree lists: %d\n", min_score)) ;
- for (deg = 0 ; deg <= n_col ; deg++)
- {
- col = head [deg] ;
- if (col == EMPTY)
- {
- continue ;
- }
- DEBUG4 (("%d:", deg)) ;
- while (col != EMPTY)
- {
- DEBUG4 ((" %d", col)) ;
- have += Col [col].shared1.thickness ;
- ASSERT (COL_IS_ALIVE (col)) ;
- col = Col [col].shared4.degree_next ;
- }
- DEBUG4 (("\n")) ;
- }
- DEBUG4 (("should %d have %d\n", should, have)) ;
- ASSERT (should == have) ;
-
- /* === Check the row degrees ============================================ */
-
- if (n_row > 10000 && colamd_debug <= 0)
- {
- return ;
- }
- for (row = 0 ; row < n_row ; row++)
- {
- if (ROW_IS_ALIVE (row))
- {
- ASSERT (Row [row].shared1.degree <= max_deg) ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === debug_mark =========================================================== */
-/* ========================================================================== */
-
-/*
- Ensures that the tag_mark is less that the maximum and also ensures that
- each entry in the mark array is less than the tag mark.
-*/
-
-PRIVATE void debug_mark
-(
- /* === Parameters ======================================================= */
-
- Int n_row,
- Colamd_Row Row [],
- Int tag_mark,
- Int max_mark
-)
-{
- /* === Local variables ================================================== */
-
- Int r ;
-
- /* === Check the Row marks ============================================== */
-
- ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
- if (n_row > 10000 && colamd_debug <= 0)
- {
- return ;
- }
- for (r = 0 ; r < n_row ; r++)
- {
- ASSERT (Row [r].shared2.mark < tag_mark) ;
- }
-}
-
-
-/* ========================================================================== */
-/* === debug_matrix ========================================================= */
-/* ========================================================================== */
-
-/*
- Prints out the contents of the columns and the rows.
-*/
-
-PRIVATE void debug_matrix
-(
- /* === Parameters ======================================================= */
-
- Int n_row,
- Int n_col,
- Colamd_Row Row [],
- Colamd_Col Col [],
- Int A []
-)
-{
- /* === Local variables ================================================== */
-
- Int r ;
- Int c ;
- Int *rp ;
- Int *rp_end ;
- Int *cp ;
- Int *cp_end ;
-
- /* === Dump the rows and columns of the matrix ========================== */
-
- if (colamd_debug < 3)
- {
- return ;
- }
- DEBUG3 (("DUMP MATRIX:\n")) ;
- for (r = 0 ; r < n_row ; r++)
- {
- DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
- if (ROW_IS_DEAD (r))
- {
- continue ;
- }
- DEBUG3 (("start %d length %d degree %d\n",
- Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
- rp = &A [Row [r].start] ;
- rp_end = rp + Row [r].length ;
- while (rp < rp_end)
- {
- c = *rp++ ;
- DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ;
- }
- }
-
- for (c = 0 ; c < n_col ; c++)
- {
- DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
- if (COL_IS_DEAD (c))
- {
- continue ;
- }
- DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
- Col [c].start, Col [c].length,
- Col [c].shared1.thickness, Col [c].shared2.score)) ;
- cp = &A [Col [c].start] ;
- cp_end = cp + Col [c].length ;
- while (cp < cp_end)
- {
- r = *cp++ ;
- DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ;
- }
- }
-}
-
-PRIVATE void colamd_get_debug
-(
- char *method
-)
-{
- FILE *f ;
- colamd_debug = 0 ; /* no debug printing */
- f = fopen ("debug", "r") ;
- if (f == (FILE *) NULL)
- {
- colamd_debug = 0 ;
- }
- else
- {
- fscanf (f, "%d", &colamd_debug) ;
- fclose (f) ;
- }
- DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
- method, colamd_debug)) ;
-}
-
-#endif /* NDEBUG */
diff --git a/extern/colamd/Source/colamd_global.c b/extern/colamd/Source/colamd_global.c
deleted file mode 100644
index 4d1ae22300c..00000000000
--- a/extern/colamd/Source/colamd_global.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* ========================================================================== */
-/* === colamd_global.c ====================================================== */
-/* ========================================================================== */
-
-/* ----------------------------------------------------------------------------
- * COLAMD, Copyright (C) 2007, Timothy A. Davis.
- * See License.txt for the Version 2.1 of the GNU Lesser General Public License
- * http://www.cise.ufl.edu/research/sparse
- * -------------------------------------------------------------------------- */
-
-/* Global variables for COLAMD */
-
-#ifndef NPRINT
-#ifdef MATLAB_MEX_FILE
-#include "mex.h"
-int (*colamd_printf) (const char *, ...) = mexPrintf ;
-#else
-#include <stdio.h>
-int (*colamd_printf) (const char *, ...) = printf ;
-#endif
-#else
-int (*colamd_printf) (const char *, ...) = ((void *) 0) ;
-#endif
-
diff --git a/extern/cuew/CMakeLists.txt b/extern/cuew/CMakeLists.txt
index 284fbbc6aca..9ba390b3225 100644
--- a/extern/cuew/CMakeLists.txt
+++ b/extern/cuew/CMakeLists.txt
@@ -33,8 +33,9 @@ set(INC_SYS
)
set(SRC
- include/cuew.h
src/cuew.c
+
+ include/cuew.h
)
blender_add_lib(extern_cuew "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/cuew/SConscript b/extern/cuew/SConscript
deleted file mode 100644
index 9c12c71133c..00000000000
--- a/extern/cuew/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('src/cuew.c')
-
-incs = 'include'
-defs = []
-
-env.BlenderLib ('extern_cuew', sources, Split(incs), defines=defs, libtype=['system'], priority = [0])
diff --git a/extern/cuew/auto/cuda_errors.py b/extern/cuew/auto/cuda_errors.py
deleted file mode 100644
index 464b7765234..00000000000
--- a/extern/cuew/auto/cuda_errors.py
+++ /dev/null
@@ -1,35 +0,0 @@
-CUDA_ERRORS={
-'CUDA_SUCCESS': "No errors",
-'CUDA_ERROR_INVALID_VALUE': "Invalid value",
-'CUDA_ERROR_OUT_OF_MEMORY': "Out of memory",
-'CUDA_ERROR_NOT_INITIALIZED': "Driver not initialized",
-'CUDA_ERROR_DEINITIALIZED': "Driver deinitialized",
-'CUDA_ERROR_NO_DEVICE': "No CUDA-capable device available",
-'CUDA_ERROR_INVALID_DEVICE': "Invalid device",
-'CUDA_ERROR_INVALID_IMAGE': "Invalid kernel image",
-'CUDA_ERROR_INVALID_CONTEXT': "Invalid context",
-'CUDA_ERROR_CONTEXT_ALREADY_CURRENT': "Context already current",
-'CUDA_ERROR_MAP_FAILED': "Map failed",
-'CUDA_ERROR_UNMAP_FAILED': "Unmap failed",
-'CUDA_ERROR_ARRAY_IS_MAPPED': "Array is mapped",
-'CUDA_ERROR_ALREADY_MAPPED': "Already mapped",
-'CUDA_ERROR_NO_BINARY_FOR_GPU': "No binary for GPU",
-'CUDA_ERROR_ALREADY_ACQUIRED': "Already acquired",
-'CUDA_ERROR_NOT_MAPPED': "Not mapped",
-'CUDA_ERROR_NOT_MAPPED_AS_ARRAY': "Mapped resource not available for access as an array",
-'CUDA_ERROR_NOT_MAPPED_AS_POINTER': "Mapped resource not available for access as a pointer",
-'CUDA_ERROR_ECC_UNCORRECTABLE': "Uncorrectable ECC error detected",
-'CUDA_ERROR_UNSUPPORTED_LIMIT': "CUlimit not supported by device",
-'CUDA_ERROR_INVALID_SOURCE': "Invalid source",
-'CUDA_ERROR_FILE_NOT_FOUND': "File not found",
-'CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND': "Link to a shared object failed to resolve",
-'CUDA_ERROR_SHARED_OBJECT_INIT_FAILED': "Shared object initialization failed",
-'CUDA_ERROR_INVALID_HANDLE': "Invalid handle",
-'CUDA_ERROR_NOT_FOUND': "Not found",
-'CUDA_ERROR_NOT_READY': "CUDA not ready",
-'CUDA_ERROR_LAUNCH_FAILED': "Launch failed",
-'CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES': "Launch exceeded resources",
-'CUDA_ERROR_LAUNCH_TIMEOUT': "Launch exceeded timeout",
-'CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING': "Launch with incompatible texturing",
-'CUDA_ERROR_UNKNOWN': "Unknown error",
-}
diff --git a/extern/cuew/auto/cuda_extra.py b/extern/cuew/auto/cuda_extra.py
deleted file mode 100644
index fd4f466df83..00000000000
--- a/extern/cuew/auto/cuda_extra.py
+++ /dev/null
@@ -1,125 +0,0 @@
-extra_code = """
-static void path_join(const char *path1,
- const char *path2,
- int maxlen,
- char *result) {
-#if defined(WIN32) || defined(_WIN32)
- const char separator = '\\\\';
-#else
- const char separator = '/';
-#endif
- int n = snprintf(result, maxlen, "%s%c%s", path1, separator, path2);
- if (n != -1 && n < maxlen) {
- result[n] = '\\0';
- }
- else {
- result[maxlen - 1] = '\\0';
- }
-}
-
-static int path_exists(const char *path) {
- struct stat st;
- if (stat(path, &st)) {
- return 0;
- }
- return 1;
-}
-
-const char *cuewCompilerPath(void) {
-#ifdef _WIN32
- const char *defaultpaths[] = {"C:/CUDA/bin", NULL};
- const char *executable = "nvcc.exe";
-#else
- const char *defaultpaths[] = {
- "/Developer/NVIDIA/CUDA-5.0/bin",
- "/usr/local/cuda-5.0/bin",
- "/usr/local/cuda/bin",
- "/Developer/NVIDIA/CUDA-6.0/bin",
- "/usr/local/cuda-6.0/bin",
- "/Developer/NVIDIA/CUDA-5.5/bin",
- "/usr/local/cuda-5.5/bin",
- NULL};
- const char *executable = "nvcc";
-#endif
- int i;
-
- const char *binpath = getenv("CUDA_BIN_PATH");
-
- static char nvcc[65536];
-
- if (binpath) {
- path_join(binpath, executable, sizeof(nvcc), nvcc);
- if (path_exists(nvcc))
- return nvcc;
- }
-
- for (i = 0; defaultpaths[i]; ++i) {
- path_join(defaultpaths[i], executable, sizeof(nvcc), nvcc);
- if (path_exists(nvcc))
- return nvcc;
- }
-
-#ifndef _WIN32
- {
- FILE *handle = popen("which nvcc", "r");
- if (handle) {
- char buffer[4096] = {0};
- int len = fread(buffer, 1, sizeof(buffer) - 1, handle);
- buffer[len] = '\\0';
- pclose(handle);
-
- if (buffer[0])
- return "nvcc";
- }
- }
-#endif
-
- return NULL;
-}
-
-int cuewCompilerVersion(void) {
- const char *path = cuewCompilerPath();
- const char *marker = "Cuda compilation tools, release ";
- FILE *pipe;
- int major, minor;
- char *versionstr;
- char buf[128];
- char output[65536] = "\\0";
- char command[65536] = "\\0";
-
- if (path == NULL)
- return 0;
-
- /* get --version output */
- strncpy(command, path, sizeof(command));
- strncat(command, " --version", sizeof(command) - strlen(path));
- pipe = popen(command, "r");
- if (!pipe) {
- fprintf(stderr, "CUDA: failed to run compiler to retrieve version");
- return 0;
- }
-
- while (!feof(pipe)) {
- if (fgets(buf, sizeof(buf), pipe) != NULL) {
- strncat(output, buf, sizeof(output) - strlen(output));
- }
- }
-
- pclose(pipe);
-
- /* parse version number */
- versionstr = strstr(output, marker);
- if (versionstr == NULL) {
- fprintf(stderr, "CUDA: failed to find version number in:\\n\\n%s\\n", output);
- return 0;
- }
- versionstr += strlen(marker);
-
- if (sscanf(versionstr, "%d.%d", &major, &minor) < 2) {
- fprintf(stderr, "CUDA: failed to parse version number from:\\n\\n%s\\n", output);
- return 0;
- }
-
- return 10 * major + minor;
-}
-"""
diff --git a/extern/cuew/auto/cuew_gen.py b/extern/cuew/auto/cuew_gen.py
deleted file mode 100644
index a94525c52b1..00000000000
--- a/extern/cuew/auto/cuew_gen.py
+++ /dev/null
@@ -1,591 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2014 Blender Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-# This script generates either header or implementation file from
-# a CUDA header files.
-#
-# Usage: cuew hdr|impl [/path/to/cuda/includes]
-# - hdr means header file will be generated and printed to stdout.
-# - impl means implementation file will be generated and printed to stdout.
-# - /path/to/cuda/includes is a path to a folder with cuda.h and cudaGL.h
-# for which wrangler will be generated.
-
-import os
-import sys
-from cuda_errors import CUDA_ERRORS
-from pycparser import c_parser, c_ast, parse_file
-from subprocess import Popen, PIPE
-
-INCLUDE_DIR = "/usr/include"
-LIB = "CUEW"
-REAL_LIB = "CUDA"
-VERSION_MAJOR = "1"
-VERSION_MINOR = "2"
-COPYRIGHT = """/*
- * Copyright 2011-2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */"""
-FILES = ["cuda.h", "cudaGL.h"]
-
-TYPEDEFS = []
-FUNC_TYPEDEFS = []
-SYMBOLS = []
-DEFINES = []
-DEFINES_V2 = []
-ERRORS = []
-
-
-class FuncDefVisitor(c_ast.NodeVisitor):
- indent = 0
- prev_complex = False
- dummy_typedefs = ['size_t', 'CUdeviceptr']
-
- def _get_quals_string(self, node):
- if node.quals:
- return ' '.join(node.quals) + ' '
- return ''
-
- def _get_ident_type(self, node):
- if isinstance(node, c_ast.PtrDecl):
- return self._get_ident_type(node.type.type) + '*'
- if isinstance(node, c_ast.ArrayDecl):
- return self._get_ident_type(node.type)
- elif isinstance(node, c_ast.Struct):
- if node.name:
- return 'struct ' + node.name
- else:
- self.indent += 1
- struct = self._stringify_struct(node)
- self.indent -= 1
- return "struct {\n" + \
- struct + (" " * self.indent) + "}"
- elif isinstance(node, c_ast.Union):
- self.indent += 1
- union = self._stringify_struct(node)
- self.indent -= 1
- return "union {\n" + union + (" " * self.indent) + "}"
- elif isinstance(node, c_ast.Enum):
- return 'enum ' + node.name
- elif isinstance(node, c_ast.TypeDecl):
- return self._get_ident_type(node.type)
- else:
- return node.names[0]
-
- def _stringify_param(self, param):
- param_type = param.type
- result = self._get_quals_string(param)
- result += self._get_ident_type(param_type)
- if param.name:
- result += ' ' + param.name
- if isinstance(param_type, c_ast.ArrayDecl):
- # TODO(sergey): Workaround to deal with the
- # preprocessed file where array size got
- # substituded.
- dim = param_type.dim.value
- if param.name == "reserved" and dim == "64":
- dim = "CU_IPC_HANDLE_SIZE"
- result += '[' + dim + ']'
- return result
-
- def _stringify_params(self, params):
- result = []
- for param in params:
- result.append(self._stringify_param(param))
- return ', '.join(result)
-
- def _stringify_struct(self, node):
- result = ""
- children = node.children()
- for child in children:
- member = self._stringify_param(child[1])
- result += (" " * self.indent) + member + ";\n"
- return result
-
- def _stringify_enum(self, node):
- result = ""
- children = node.children()
- for child in children:
- if isinstance(child[1], c_ast.EnumeratorList):
- enumerators = child[1].enumerators
- for enumerator in enumerators:
- result += (" " * self.indent) + enumerator.name
- if enumerator.value:
- result += " = " + enumerator.value.value
- result += ",\n"
- if enumerator.name.startswith("CUDA_ERROR_"):
- ERRORS.append(enumerator.name)
- return result
-
- def visit_Decl(self, node):
- if node.type.__class__.__name__ == 'FuncDecl':
- if isinstance(node.type, c_ast.FuncDecl):
- func_decl = node.type
- func_decl_type = func_decl.type
-
- typedef = 'typedef '
- symbol_name = None
-
- if isinstance(func_decl_type, c_ast.TypeDecl):
- symbol_name = func_decl_type.declname
- typedef += self._get_quals_string(func_decl_type)
- typedef += self._get_ident_type(func_decl_type.type)
- typedef += ' CUDAAPI'
- typedef += ' t' + symbol_name
- elif isinstance(func_decl_type, c_ast.PtrDecl):
- ptr_type = func_decl_type.type
- symbol_name = ptr_type.declname
- typedef += self._get_quals_string(ptr_type)
- typedef += self._get_ident_type(func_decl_type)
- typedef += ' CUDAAPI'
- typedef += ' t' + symbol_name
-
- typedef += '(' + \
- self._stringify_params(func_decl.args.params) + \
- ');'
-
- SYMBOLS.append(symbol_name)
- FUNC_TYPEDEFS.append(typedef)
-
- def visit_Typedef(self, node):
- if node.name in self.dummy_typedefs:
- return
-
- complex = False
- type = self._get_ident_type(node.type)
- quals = self._get_quals_string(node)
-
- if isinstance(node.type.type, c_ast.Struct):
- self.indent += 1
- struct = self._stringify_struct(node.type.type)
- self.indent -= 1
- typedef = quals + type + " {\n" + struct + "} " + node.name
- complex = True
- elif isinstance(node.type.type, c_ast.Enum):
- self.indent += 1
- enum = self._stringify_enum(node.type.type)
- self.indent -= 1
- typedef = quals + type + " {\n" + enum + "} " + node.name
- complex = True
- else:
- typedef = quals + type + " " + node.name
- if complex or self.prev_complex:
- typedef = "\ntypedef " + typedef + ";"
- else:
- typedef = "typedef " + typedef + ";"
-
- TYPEDEFS.append(typedef)
-
- self.prev_complex = complex
-
-
-def get_latest_cpp():
- path_prefix = "/usr/bin"
- for cpp_version in ["9", "8", "7", "6", "5", "4"]:
- test_cpp = os.path.join(path_prefix, "cpp-4." + cpp_version)
- if os.path.exists(test_cpp):
- return test_cpp
- return None
-
-
-def preprocess_file(filename, cpp_path):
- args = [cpp_path, "-I./"]
- if filename.endswith("GL.h"):
- args.append("-DCUDAAPI= ")
- args.append(filename)
-
- try:
- pipe = Popen(args,
- stdout=PIPE,
- universal_newlines=True)
- text = pipe.communicate()[0]
- except OSError as e:
- raise RuntimeError("Unable to invoke 'cpp'. " +
- 'Make sure its path was passed correctly\n' +
- ('Original error: %s' % e))
-
- return text
-
-
-def parse_files():
- parser = c_parser.CParser()
- cpp_path = get_latest_cpp()
-
- for filename in FILES:
- filepath = os.path.join(INCLUDE_DIR, filename)
- dummy_typedefs = {}
- text = preprocess_file(filepath, cpp_path)
-
- if filepath.endswith("GL.h"):
- dummy_typedefs = {
- "CUresult": "int",
- "CUgraphicsResource": "void *",
- "CUdevice": "void *",
- "CUcontext": "void *",
- "CUdeviceptr": "void *",
- "CUstream": "void *"
- }
-
- text = "typedef int GLint;\n" + text
- text = "typedef unsigned int GLuint;\n" + text
- text = "typedef unsigned int GLenum;\n" + text
- text = "typedef long size_t;\n" + text
-
- for typedef in sorted(dummy_typedefs):
- text = "typedef " + dummy_typedefs[typedef] + " " + \
- typedef + ";\n" + text
-
- ast = parser.parse(text, filepath)
-
- with open(filepath) as f:
- lines = f.readlines()
- for line in lines:
- if line.startswith("#define"):
- line = line[8:-1]
- token = line.split()
- if token[0] not in ("__cuda_cuda_h__",
- "CUDA_CB",
- "CUDAAPI"):
- DEFINES.append(token)
-
- for line in lines:
- # TODO(sergey): Use better matching rule for _v2 symbols.
- if line[0].isspace() and line.lstrip().startswith("#define"):
- line = line[12:-1]
- token = line.split()
- if len(token) == 2 and token[1].endswith("_v2"):
- DEFINES_V2.append(token)
-
- v = FuncDefVisitor()
- for typedef in dummy_typedefs:
- v.dummy_typedefs.append(typedef)
- v.visit(ast)
-
- FUNC_TYPEDEFS.append('')
- SYMBOLS.append('')
-
-
-def print_copyright():
- print(COPYRIGHT)
- print("")
-
-
-def open_header_guard():
- print("#ifndef __%s_H__" % (LIB))
- print("#define __%s_H__" % (LIB))
- print("")
- print("#ifdef __cplusplus")
- print("extern \"C\" {")
- print("#endif")
- print("")
-
-
-def close_header_guard():
- print("")
- print("#ifdef __cplusplus")
- print("}")
- print("#endif")
- print("")
- print("#endif /* __%s_H__ */" % (LIB))
-
-
-def print_header():
- print_copyright()
- open_header_guard()
-
- # Fot size_t.
- print("#include <stdlib.h>")
- print("")
-
- print("/* Defines. */")
- print("#define %s_VERSION_MAJOR %s" % (LIB, VERSION_MAJOR))
- print("#define %s_VERSION_MINOR %s" % (LIB, VERSION_MINOR))
- print("")
- for define in DEFINES:
- print('#define %s' % (' '.join(define)))
- print("")
-
- print("""/* Functions which changed 3.1 -> 3.2 for 64 bit stuff,
- * the cuda library has both the old ones for compatibility and new
- * ones with _v2 postfix,
- */""")
- for define in DEFINES_V2:
- print('#define %s' % (' '.join(define)))
- print("")
-
- print("/* Types. */")
-
- # We handle this specially because of the file is
- # getting preprocessed.
- print("""#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64)
-typedef unsigned long long CUdeviceptr;
-#else
-typedef unsigned int CUdeviceptr;
-#endif
-""")
-
- for typedef in TYPEDEFS:
- print('%s' % (typedef))
-
- # TDO(sergey): This is only specific to CUDA wrapper.
- print("""
-#ifdef _WIN32
-# define CUDAAPI __stdcall
-# define CUDA_CB __stdcall
-#else
-# define CUDAAPI
-# define CUDA_CB
-#endif
-""")
-
- print("/* Function types. */")
- for func_typedef in FUNC_TYPEDEFS:
- print('%s' % (func_typedef))
- print("")
-
- print("/* Function declarations. */")
- for symbol in SYMBOLS:
- if symbol:
- print('extern t%s *%s;' % (symbol, symbol))
- else:
- print("")
-
- print("")
- print("enum {")
- print(" CUEW_SUCCESS = 0,")
- print(" CUEW_ERROR_OPEN_FAILED = -1,")
- print(" CUEW_ERROR_ATEXIT_FAILED = -2,")
- print("};")
- print("")
- print("int %sInit(void);" % (LIB.lower()))
- # TODO(sergey): Get rid of hardcoded CUresult.
- print("const char *%sErrorString(CUresult result);" % (LIB.lower()))
- print("const char *cuewCompilerPath(void);")
- print("int cuewCompilerVersion(void);")
-
- close_header_guard()
-
-
-def print_dl_wrapper():
- print("""#ifdef _WIN32
-# define WIN32_LEAN_AND_MEAN
-# define VC_EXTRALEAN
-# include <windows.h>
-
-/* Utility macros. */
-
-typedef HMODULE DynamicLibrary;
-
-# define dynamic_library_open(path) LoadLibrary(path)
-# define dynamic_library_close(lib) FreeLibrary(lib)
-# define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol)
-#else
-# include <dlfcn.h>
-
-typedef void* DynamicLibrary;
-
-# define dynamic_library_open(path) dlopen(path, RTLD_NOW)
-# define dynamic_library_close(lib) dlclose(lib)
-# define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
-#endif
-""")
-
-
-def print_dl_helper_macro():
- print("""#define %s_LIBRARY_FIND_CHECKED(name) \\
- name = (t##name *)dynamic_library_find(lib, #name); \\
- assert(name);
-
-#define %s_LIBRARY_FIND(name) \\
- name = (t##name *)dynamic_library_find(lib, #name);
-
-static DynamicLibrary lib;""" % (REAL_LIB, REAL_LIB))
- print("")
-
-
-def print_dl_close():
- print("""static void %sExit(void) {
- if(lib != NULL) {
- /* Ignore errors. */
- dynamic_library_close(lib);
- lib = NULL;
- }
-}""" % (LIB.lower()))
- print("")
-
-
-def print_lib_path():
- # TODO(sergey): get rid of hardcoded libraries.
- print("""#ifdef _WIN32
- /* Expected in c:/windows/system or similar, no path needed. */
- const char *path = "nvcuda.dll";
-#elif defined(__APPLE__)
- /* Default installation path. */
- const char *path = "/usr/local/cuda/lib/libcuda.dylib";
-#else
- const char *path = "libcuda.so";
-#endif""")
-
-
-def print_init_guard():
- print(""" static int initialized = 0;
- static int result = 0;
- int error, driver_version;
-
- if (initialized) {
- return result;
- }
-
- initialized = 1;
-
- error = atexit(cuewExit);
- if (error) {
- result = CUEW_ERROR_ATEXIT_FAILED;
- return result;
- }
-
- /* Load library. */
- lib = dynamic_library_open(path);
-
- if (lib == NULL) {
- result = CUEW_ERROR_OPEN_FAILED;
- return result;
- }""")
- print("")
-
-
-def print_driver_version_guard():
- # TODO(sergey): Currently it's hardcoded for CUDA only.
- print(""" /* Detect driver version. */
- driver_version = 1000;
-
- %s_LIBRARY_FIND_CHECKED(cuDriverGetVersion);
- if (cuDriverGetVersion) {
- cuDriverGetVersion(&driver_version);
- }
-
- /* We require version 4.0. */
- if (driver_version < 4000) {
- result = CUEW_ERROR_OPEN_FAILED;
- return result;
- }""" % (REAL_LIB))
-
-
-def print_dl_init():
- print("int %sInit(void) {" % (LIB.lower()))
-
- print(" /* Library paths. */")
- print_lib_path()
- print_init_guard()
- print_driver_version_guard()
-
- print(" /* Fetch all function pointers. */")
- for symbol in SYMBOLS:
- if symbol:
- print(" %s_LIBRARY_FIND(%s);" % (REAL_LIB, symbol))
- else:
- print("")
-
- print("")
- print(" result = CUEW_SUCCESS;")
- print(" return result;")
-
- print("}")
-
-
-def print_implementation():
- print_copyright()
-
- # TODO(sergey): Get rid of hardcoded header.
- print("""#ifdef _MSC_VER
-# define snprintf _snprintf
-# define popen _popen
-# define pclose _pclose
-# define _CRT_SECURE_NO_WARNINGS
-#endif
-""")
- print("#include <cuew.h>")
- print("#include <assert.h>")
- print("#include <stdio.h>")
- print("#include <string.h>")
- print("#include <sys/stat.h>")
- print("")
-
- print_dl_wrapper()
- print_dl_helper_macro()
-
- print("/* Function definitions. */")
- for symbol in SYMBOLS:
- if symbol:
- print('t%s *%s;' % (symbol, symbol))
- else:
- print("")
- print("")
-
- print_dl_close()
-
- print("/* Implementation function. */")
- print_dl_init()
-
- print("")
- # TODO(sergey): Get rid of hardcoded CUresult.
- print("const char *%sErrorString(CUresult result) {" % (LIB.lower()))
- print(" switch(result) {")
- print(" case CUDA_SUCCESS: return \"No errors\";")
-
- for error in ERRORS:
- if error in CUDA_ERRORS:
- str = CUDA_ERRORS[error]
- else:
- str = error[11:]
- print(" case %s: return \"%s\";" % (error, str))
-
- print(" default: return \"Unknown CUDA error value\";")
- print(" }")
- print("}")
-
- from cuda_extra import extra_code
- print(extra_code)
-
-if __name__ == "__main__":
-
- if len(sys.argv) != 2 and len(sys.argv) != 3:
- print("Usage: %s hdr|impl [/path/to/cuda/toolkit/include]" %
- (sys.argv[0]))
- exit(1)
-
- if len(sys.argv) == 3:
- INCLUDE_DIR = sys.argv[2]
-
- parse_files()
-
- if sys.argv[1] == "hdr":
- print_header()
- elif sys.argv[1] == "impl":
- print_implementation()
- else:
- print("Unknown command %s" % (sys.argv[1]))
- exit(1)
diff --git a/extern/cuew/auto/cuew_gen.sh b/extern/cuew/auto/cuew_gen.sh
deleted file mode 100755
index b44987b801d..00000000000
--- a/extern/cuew/auto/cuew_gen.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-# This script invokes cuew_gen.py and updates the
-# header and source files in the repository.
-
-SCRIPT=`realpath -s $0`
-DIR=`dirname $SCRIPT`
-
-python ${DIR}/cuew_gen.py hdr $@ > $DIR/../include/cuew.h
-python ${DIR}/cuew_gen.py impl $@ > $DIR/../src/cuew.c
diff --git a/extern/cuew/auto/stdlib.h b/extern/cuew/auto/stdlib.h
deleted file mode 100644
index 75976c8574f..00000000000
--- a/extern/cuew/auto/stdlib.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/* This file is needed to workaround issue with parsing system headers. */
-
-typedef long size_t;
diff --git a/extern/cuew/include/cuew.h b/extern/cuew/include/cuew.h
index fd03311ad41..47b19b4b3a5 100644
--- a/extern/cuew/include/cuew.h
+++ b/extern/cuew/include/cuew.h
@@ -27,13 +27,16 @@ extern "C" {
#define CUEW_VERSION_MAJOR 1
#define CUEW_VERSION_MINOR 2
-#define CUDA_VERSION 6000
+#define CUDA_VERSION 7050
#define CU_IPC_HANDLE_SIZE 64
+#define CU_STREAM_LEGACY ((CUstream)0x1)
+#define CU_STREAM_PER_THREAD ((CUstream)0x2)
#define CU_MEMHOSTALLOC_PORTABLE 0x01
#define CU_MEMHOSTALLOC_DEVICEMAP 0x02
#define CU_MEMHOSTALLOC_WRITECOMBINED 0x04
#define CU_MEMHOSTREGISTER_PORTABLE 0x01
#define CU_MEMHOSTREGISTER_DEVICEMAP 0x02
+#define CU_MEMHOSTREGISTER_IOMEMORY 0x04
#define CUDA_ARRAY3D_LAYERED 0x01
#define CUDA_ARRAY3D_2DARRAY 0x01
#define CUDA_ARRAY3D_SURFACE_LDST 0x02
@@ -48,7 +51,6 @@ extern "C" {
#define CU_LAUNCH_PARAM_BUFFER_POINTER ((void*)0x01)
#define CU_LAUNCH_PARAM_BUFFER_SIZE ((void*)0x02)
#define CU_PARAM_TR_DEFAULT -1
-#define CUDAGL_H
/* Functions which changed 3.1 -> 3.2 for 64 bit stuff,
* the cuda library has both the old ones for compatibility and new
@@ -100,10 +102,16 @@ extern "C" {
#define cuCtxPushCurrent cuCtxPushCurrent_v2
#define cuStreamDestroy cuStreamDestroy_v2
#define cuEventDestroy cuEventDestroy_v2
+#define cuLinkCreate cuLinkCreate_v2
+#define cuLinkAddData cuLinkAddData_v2
+#define cuLinkAddFile cuLinkAddFile_v2
+#define cuMemHostRegister cuMemHostRegister_v2
+#define cuGraphicsResourceSetMapFlags cuGraphicsResourceSetMapFlags_v2
#define cuTexRefSetAddress2D cuTexRefSetAddress2D_v2
#define cuGLCtxCreate cuGLCtxCreate_v2
#define cuGLMapBufferObject cuGLMapBufferObject_v2
#define cuGLMapBufferObjectAsync cuGLMapBufferObjectAsync_v2
+#define cuGLGetDevices cuGLGetDevices_v2
/* Types. */
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64)
@@ -172,6 +180,11 @@ typedef enum CUevent_flags_enum {
CU_EVENT_INTERPROCESS = 0x4,
} CUevent_flags;
+typedef enum CUoccupancy_flags_enum {
+ CU_OCCUPANCY_DEFAULT = 0x0,
+ CU_OCCUPANCY_DISABLE_CACHING_OVERRIDE = 0x1,
+} CUoccupancy_flags;
+
typedef enum CUarray_format_enum {
CU_AD_FORMAT_UNSIGNED_INT8 = 0x01,
CU_AD_FORMAT_UNSIGNED_INT16 = 0x02,
@@ -381,7 +394,9 @@ typedef enum CUjit_target_enum {
CU_TARGET_COMPUTE_30 = 30,
CU_TARGET_COMPUTE_32 = 32,
CU_TARGET_COMPUTE_35 = 35,
+ CU_TARGET_COMPUTE_37 = 37,
CU_TARGET_COMPUTE_50 = 50,
+ CU_TARGET_COMPUTE_52 = 52,
} CUjit_target;
typedef enum CUjit_fallback_enum {
@@ -474,6 +489,7 @@ typedef enum cudaError_enum {
CUDA_ERROR_CONTEXT_ALREADY_IN_USE = 216,
CUDA_ERROR_PEER_ACCESS_UNSUPPORTED = 217,
CUDA_ERROR_INVALID_PTX = 218,
+ CUDA_ERROR_INVALID_GRAPHICS_CONTEXT = 219,
CUDA_ERROR_INVALID_SOURCE = 300,
CUDA_ERROR_FILE_NOT_FOUND = 301,
CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND = 302,
@@ -506,6 +522,7 @@ typedef enum cudaError_enum {
} CUresult;
typedef void* CUstreamCallback;
+typedef size_t* CUoccupancyB2DSize;
typedef struct CUDA_MEMCPY2D_st {
size_t srcXInBytes;
@@ -710,6 +727,19 @@ typedef enum CUGLmap_flags_enum {
CU_GL_MAP_RESOURCE_FLAGS_WRITE_DISCARD = 0x02,
} CUGLmap_flags;
+typedef enum {
+ NVRTC_SUCCESS = 0,
+ NVRTC_ERROR_OUT_OF_MEMORY = 1,
+ NVRTC_ERROR_PROGRAM_CREATION_FAILURE = 2,
+ NVRTC_ERROR_INVALID_INPUT = 3,
+ NVRTC_ERROR_INVALID_PROGRAM = 4,
+ NVRTC_ERROR_INVALID_OPTION = 5,
+ NVRTC_ERROR_COMPILATION = 6,
+ NVRTC_ERROR_BUILTIN_OPERATION_FAILURE = 7,
+} nvrtcResult;
+
+typedef struct _nvrtcProgram* nvrtcProgram;
+
#ifdef _WIN32
# define CUDAAPI __stdcall
# define CUDA_CB __stdcall
@@ -730,6 +760,11 @@ typedef CUresult CUDAAPI tcuDeviceTotalMem_v2(size_t* bytes, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceGetAttribute(int* pi, CUdevice_attribute attrib, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceGetProperties(CUdevprop* prop, CUdevice dev);
typedef CUresult CUDAAPI tcuDeviceComputeCapability(int* major, int* minor, CUdevice dev);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxRetain(CUcontext* pctx, CUdevice dev);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxRelease(CUdevice dev);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxSetFlags(CUdevice dev, unsigned flags);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxGetState(CUdevice dev, unsigned* flags, int* active);
+typedef CUresult CUDAAPI tcuDevicePrimaryCtxReset(CUdevice dev);
typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext* pctx, unsigned flags, CUdevice dev);
typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx);
typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext ctx);
@@ -737,6 +772,7 @@ typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext* pctx);
typedef CUresult CUDAAPI tcuCtxSetCurrent(CUcontext ctx);
typedef CUresult CUDAAPI tcuCtxGetCurrent(CUcontext* pctx);
typedef CUresult CUDAAPI tcuCtxGetDevice(CUdevice* device);
+typedef CUresult CUDAAPI tcuCtxGetFlags(unsigned* flags);
typedef CUresult CUDAAPI tcuCtxSynchronize(void);
typedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value);
typedef CUresult CUDAAPI tcuCtxGetLimit(size_t* pvalue, CUlimit limit);
@@ -757,9 +793,9 @@ typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction* hfunc, CUmodule hmod,
typedef CUresult CUDAAPI tcuModuleGetGlobal_v2(CUdeviceptr* dptr, size_t* bytes, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuModuleGetTexRef(CUtexref* pTexRef, CUmodule hmod, const char* name);
typedef CUresult CUDAAPI tcuModuleGetSurfRef(CUsurfref* pSurfRef, CUmodule hmod, const char* name);
-typedef CUresult CUDAAPI tcuLinkCreate(unsigned numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut);
-typedef CUresult CUDAAPI tcuLinkAddData(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned numOptions, CUjit_option* options, void* optionValues);
-typedef CUresult CUDAAPI tcuLinkAddFile(CUlinkState state, CUjitInputType type, const char* path, unsigned numOptions, CUjit_option* options, void* optionValues);
+typedef CUresult CUDAAPI tcuLinkCreate_v2(unsigned numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut);
+typedef CUresult CUDAAPI tcuLinkAddData_v2(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned numOptions, CUjit_option* options, void* optionValues);
+typedef CUresult CUDAAPI tcuLinkAddFile_v2(CUlinkState state, CUjitInputType type, const char* path, unsigned numOptions, CUjit_option* options, void* optionValues);
typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void* cubinOut, size_t* sizeOut);
typedef CUresult CUDAAPI tcuLinkDestroy(CUlinkState state);
typedef CUresult CUDAAPI tcuMemGetInfo_v2(size_t* free, size_t* total);
@@ -780,7 +816,7 @@ typedef CUresult CUDAAPI tcuIpcOpenEventHandle(CUevent* phEvent, CUipcEventHandl
typedef CUresult CUDAAPI tcuIpcGetMemHandle(CUipcMemHandle* pHandle, CUdeviceptr dptr);
typedef CUresult CUDAAPI tcuIpcOpenMemHandle(CUdeviceptr* pdptr, CUipcMemHandle handle, unsigned Flags);
typedef CUresult CUDAAPI tcuIpcCloseMemHandle(CUdeviceptr dptr);
-typedef CUresult CUDAAPI tcuMemHostRegister(void* p, size_t bytesize, unsigned Flags);
+typedef CUresult CUDAAPI tcuMemHostRegister_v2(void* p, size_t bytesize, unsigned Flags);
typedef CUresult CUDAAPI tcuMemHostUnregister(void* p);
typedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount);
typedef CUresult CUDAAPI tcuMemcpyPeer(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount);
@@ -828,6 +864,7 @@ typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipma
typedef CUresult CUDAAPI tcuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray);
typedef CUresult CUDAAPI tcuPointerGetAttribute(void* data, CUpointer_attribute attribute, CUdeviceptr ptr);
typedef CUresult CUDAAPI tcuPointerSetAttribute(const void* value, CUpointer_attribute attribute, CUdeviceptr ptr);
+typedef CUresult CUDAAPI tcuPointerGetAttributes(unsigned numAttributes, CUpointer_attribute* attributes, void* data, CUdeviceptr ptr);
typedef CUresult CUDAAPI tcuStreamCreate(CUstream* phStream, unsigned Flags);
typedef CUresult CUDAAPI tcuStreamCreateWithPriority(CUstream* phStream, unsigned flags, int priority);
typedef CUresult CUDAAPI tcuStreamGetPriority(CUstream hStream, int* priority);
@@ -858,6 +895,10 @@ typedef CUresult CUDAAPI tcuLaunch(CUfunction f);
typedef CUresult CUDAAPI tcuLaunchGrid(CUfunction f, int grid_width, int grid_height);
typedef CUresult CUDAAPI tcuLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream hStream);
typedef CUresult CUDAAPI tcuParamSetTexRef(CUfunction hfunc, int texunit, CUtexref hTexRef);
+typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessor(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize);
+typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize, unsigned flags);
+typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSize(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit);
+typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSizeWithFlags(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit, unsigned flags);
typedef CUresult CUDAAPI tcuTexRefSetArray(CUtexref hTexRef, CUarray hArray, unsigned Flags);
typedef CUresult CUDAAPI tcuTexRefSetMipmappedArray(CUtexref hTexRef, CUmipmappedArray hMipmappedArray, unsigned Flags);
typedef CUresult CUDAAPI tcuTexRefSetAddress_v2(size_t* ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, size_t bytes);
@@ -900,14 +941,14 @@ typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resour
typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned arrayIndex, unsigned mipLevel);
typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedMipmappedArray(CUmipmappedArray* pMipmappedArray, CUgraphicsResource resource);
typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer_v2(CUdeviceptr* pDevPtr, size_t* pSize, CUgraphicsResource resource);
-typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags(CUgraphicsResource resource, unsigned flags);
+typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags_v2(CUgraphicsResource resource, unsigned flags);
typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned count, CUgraphicsResource* resources, CUstream hStream);
typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned count, CUgraphicsResource* resources, CUstream hStream);
typedef CUresult CUDAAPI tcuGetExportTable(const void* ppExportTable, const CUuuid* pExportTableId);
typedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource* pCudaResource, GLuint buffer, unsigned Flags);
typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned Flags);
-typedef CUresult CUDAAPI tcuGLGetDevices(unsigned* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned cudaDeviceCount, CUGLDeviceList deviceList);
+typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned cudaDeviceCount, CUGLDeviceList deviceList);
typedef CUresult CUDAAPI tcuGLCtxCreate_v2(CUcontext* pCtx, unsigned Flags, CUdevice device);
typedef CUresult CUDAAPI tcuGLInit(void);
typedef CUresult CUDAAPI tcuGLRegisterBufferObject(GLuint buffer);
@@ -918,6 +959,16 @@ typedef CUresult CUDAAPI tcuGLSetBufferObjectMapFlags(GLuint buffer, unsigned Fl
typedef CUresult CUDAAPI tcuGLMapBufferObjectAsync_v2(CUdeviceptr* dptr, size_t* size, GLuint buffer, CUstream hStream);
typedef CUresult CUDAAPI tcuGLUnmapBufferObjectAsync(GLuint buffer, CUstream hStream);
+typedef const char* CUDAAPI tnvrtcGetErrorString(nvrtcResult result);
+typedef nvrtcResult CUDAAPI tnvrtcVersion(int* major, int* minor);
+typedef nvrtcResult CUDAAPI tnvrtcCreateProgram(nvrtcProgram* prog, const char* src, const char* name, int numHeaders, const char* headers, const char* includeNames);
+typedef nvrtcResult CUDAAPI tnvrtcDestroyProgram(nvrtcProgram* prog);
+typedef nvrtcResult CUDAAPI tnvrtcCompileProgram(nvrtcProgram prog, int numOptions, const char* options);
+typedef nvrtcResult CUDAAPI tnvrtcGetPTXSize(nvrtcProgram prog, size_t* ptxSizeRet);
+typedef nvrtcResult CUDAAPI tnvrtcGetPTX(nvrtcProgram prog, char* ptx);
+typedef nvrtcResult CUDAAPI tnvrtcGetProgramLogSize(nvrtcProgram prog, size_t* logSizeRet);
+typedef nvrtcResult CUDAAPI tnvrtcGetProgramLog(nvrtcProgram prog, char* log);
+
/* Function declarations. */
extern tcuGetErrorString *cuGetErrorString;
@@ -931,6 +982,11 @@ extern tcuDeviceTotalMem_v2 *cuDeviceTotalMem_v2;
extern tcuDeviceGetAttribute *cuDeviceGetAttribute;
extern tcuDeviceGetProperties *cuDeviceGetProperties;
extern tcuDeviceComputeCapability *cuDeviceComputeCapability;
+extern tcuDevicePrimaryCtxRetain *cuDevicePrimaryCtxRetain;
+extern tcuDevicePrimaryCtxRelease *cuDevicePrimaryCtxRelease;
+extern tcuDevicePrimaryCtxSetFlags *cuDevicePrimaryCtxSetFlags;
+extern tcuDevicePrimaryCtxGetState *cuDevicePrimaryCtxGetState;
+extern tcuDevicePrimaryCtxReset *cuDevicePrimaryCtxReset;
extern tcuCtxCreate_v2 *cuCtxCreate_v2;
extern tcuCtxDestroy_v2 *cuCtxDestroy_v2;
extern tcuCtxPushCurrent_v2 *cuCtxPushCurrent_v2;
@@ -938,6 +994,7 @@ extern tcuCtxPopCurrent_v2 *cuCtxPopCurrent_v2;
extern tcuCtxSetCurrent *cuCtxSetCurrent;
extern tcuCtxGetCurrent *cuCtxGetCurrent;
extern tcuCtxGetDevice *cuCtxGetDevice;
+extern tcuCtxGetFlags *cuCtxGetFlags;
extern tcuCtxSynchronize *cuCtxSynchronize;
extern tcuCtxSetLimit *cuCtxSetLimit;
extern tcuCtxGetLimit *cuCtxGetLimit;
@@ -958,9 +1015,9 @@ extern tcuModuleGetFunction *cuModuleGetFunction;
extern tcuModuleGetGlobal_v2 *cuModuleGetGlobal_v2;
extern tcuModuleGetTexRef *cuModuleGetTexRef;
extern tcuModuleGetSurfRef *cuModuleGetSurfRef;
-extern tcuLinkCreate *cuLinkCreate;
-extern tcuLinkAddData *cuLinkAddData;
-extern tcuLinkAddFile *cuLinkAddFile;
+extern tcuLinkCreate_v2 *cuLinkCreate_v2;
+extern tcuLinkAddData_v2 *cuLinkAddData_v2;
+extern tcuLinkAddFile_v2 *cuLinkAddFile_v2;
extern tcuLinkComplete *cuLinkComplete;
extern tcuLinkDestroy *cuLinkDestroy;
extern tcuMemGetInfo_v2 *cuMemGetInfo_v2;
@@ -981,7 +1038,7 @@ extern tcuIpcOpenEventHandle *cuIpcOpenEventHandle;
extern tcuIpcGetMemHandle *cuIpcGetMemHandle;
extern tcuIpcOpenMemHandle *cuIpcOpenMemHandle;
extern tcuIpcCloseMemHandle *cuIpcCloseMemHandle;
-extern tcuMemHostRegister *cuMemHostRegister;
+extern tcuMemHostRegister_v2 *cuMemHostRegister_v2;
extern tcuMemHostUnregister *cuMemHostUnregister;
extern tcuMemcpy *cuMemcpy;
extern tcuMemcpyPeer *cuMemcpyPeer;
@@ -1029,6 +1086,7 @@ extern tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel;
extern tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy;
extern tcuPointerGetAttribute *cuPointerGetAttribute;
extern tcuPointerSetAttribute *cuPointerSetAttribute;
+extern tcuPointerGetAttributes *cuPointerGetAttributes;
extern tcuStreamCreate *cuStreamCreate;
extern tcuStreamCreateWithPriority *cuStreamCreateWithPriority;
extern tcuStreamGetPriority *cuStreamGetPriority;
@@ -1059,6 +1117,10 @@ extern tcuLaunch *cuLaunch;
extern tcuLaunchGrid *cuLaunchGrid;
extern tcuLaunchGridAsync *cuLaunchGridAsync;
extern tcuParamSetTexRef *cuParamSetTexRef;
+extern tcuOccupancyMaxActiveBlocksPerMultiprocessor *cuOccupancyMaxActiveBlocksPerMultiprocessor;
+extern tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags *cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags;
+extern tcuOccupancyMaxPotentialBlockSize *cuOccupancyMaxPotentialBlockSize;
+extern tcuOccupancyMaxPotentialBlockSizeWithFlags *cuOccupancyMaxPotentialBlockSizeWithFlags;
extern tcuTexRefSetArray *cuTexRefSetArray;
extern tcuTexRefSetMipmappedArray *cuTexRefSetMipmappedArray;
extern tcuTexRefSetAddress_v2 *cuTexRefSetAddress_v2;
@@ -1101,14 +1163,14 @@ extern tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource;
extern tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray;
extern tcuGraphicsResourceGetMappedMipmappedArray *cuGraphicsResourceGetMappedMipmappedArray;
extern tcuGraphicsResourceGetMappedPointer_v2 *cuGraphicsResourceGetMappedPointer_v2;
-extern tcuGraphicsResourceSetMapFlags *cuGraphicsResourceSetMapFlags;
+extern tcuGraphicsResourceSetMapFlags_v2 *cuGraphicsResourceSetMapFlags_v2;
extern tcuGraphicsMapResources *cuGraphicsMapResources;
extern tcuGraphicsUnmapResources *cuGraphicsUnmapResources;
extern tcuGetExportTable *cuGetExportTable;
extern tcuGraphicsGLRegisterBuffer *cuGraphicsGLRegisterBuffer;
extern tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage;
-extern tcuGLGetDevices *cuGLGetDevices;
+extern tcuGLGetDevices_v2 *cuGLGetDevices_v2;
extern tcuGLCtxCreate_v2 *cuGLCtxCreate_v2;
extern tcuGLInit *cuGLInit;
extern tcuGLRegisterBufferObject *cuGLRegisterBufferObject;
@@ -1119,6 +1181,16 @@ extern tcuGLSetBufferObjectMapFlags *cuGLSetBufferObjectMapFlags;
extern tcuGLMapBufferObjectAsync_v2 *cuGLMapBufferObjectAsync_v2;
extern tcuGLUnmapBufferObjectAsync *cuGLUnmapBufferObjectAsync;
+extern tnvrtcGetErrorString *nvrtcGetErrorString;
+extern tnvrtcVersion *nvrtcVersion;
+extern tnvrtcCreateProgram *nvrtcCreateProgram;
+extern tnvrtcDestroyProgram *nvrtcDestroyProgram;
+extern tnvrtcCompileProgram *nvrtcCompileProgram;
+extern tnvrtcGetPTXSize *nvrtcGetPTXSize;
+extern tnvrtcGetPTX *nvrtcGetPTX;
+extern tnvrtcGetProgramLogSize *nvrtcGetProgramLogSize;
+extern tnvrtcGetProgramLog *nvrtcGetProgramLog;
+
enum {
CUEW_SUCCESS = 0,
diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c
index da892efc0f4..c96ea2c1959 100644
--- a/extern/cuew/src/cuew.c
+++ b/extern/cuew/src/cuew.c
@@ -15,7 +15,9 @@
*/
#ifdef _MSC_VER
-# define snprintf _snprintf
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
# define popen _popen
# define pclose _pclose
# define _CRT_SECURE_NO_WARNINGS
@@ -36,7 +38,7 @@
typedef HMODULE DynamicLibrary;
-# define dynamic_library_open(path) LoadLibrary(path)
+# define dynamic_library_open(path) LoadLibraryA(path)
# define dynamic_library_close(lib) FreeLibrary(lib)
# define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol)
#else
@@ -49,14 +51,23 @@ typedef void* DynamicLibrary;
# define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
#endif
-#define CUDA_LIBRARY_FIND_CHECKED(name) \
+#define _LIBRARY_FIND_CHECKED(lib, name) \
name = (t##name *)dynamic_library_find(lib, #name); \
assert(name);
-#define CUDA_LIBRARY_FIND(name) \
+#define _LIBRARY_FIND(lib, name) \
name = (t##name *)dynamic_library_find(lib, #name);
-static DynamicLibrary lib;
+#define CUDA_LIBRARY_FIND_CHECKED(name) \
+ _LIBRARY_FIND_CHECKED(cuda_lib, name)
+#define CUDA_LIBRARY_FIND(name) _LIBRARY_FIND(cuda_lib, name)
+
+#define NVRTC_LIBRARY_FIND_CHECKED(name) \
+ _LIBRARY_FIND_CHECKED(nvrtc_lib, name)
+#define NVRTC_LIBRARY_FIND(name) _LIBRARY_FIND(nvrtc_lib, name)
+
+static DynamicLibrary cuda_lib;
+static DynamicLibrary nvrtc_lib;
/* Function definitions. */
tcuGetErrorString *cuGetErrorString;
@@ -70,6 +81,11 @@ tcuDeviceTotalMem_v2 *cuDeviceTotalMem_v2;
tcuDeviceGetAttribute *cuDeviceGetAttribute;
tcuDeviceGetProperties *cuDeviceGetProperties;
tcuDeviceComputeCapability *cuDeviceComputeCapability;
+tcuDevicePrimaryCtxRetain *cuDevicePrimaryCtxRetain;
+tcuDevicePrimaryCtxRelease *cuDevicePrimaryCtxRelease;
+tcuDevicePrimaryCtxSetFlags *cuDevicePrimaryCtxSetFlags;
+tcuDevicePrimaryCtxGetState *cuDevicePrimaryCtxGetState;
+tcuDevicePrimaryCtxReset *cuDevicePrimaryCtxReset;
tcuCtxCreate_v2 *cuCtxCreate_v2;
tcuCtxDestroy_v2 *cuCtxDestroy_v2;
tcuCtxPushCurrent_v2 *cuCtxPushCurrent_v2;
@@ -77,6 +93,7 @@ tcuCtxPopCurrent_v2 *cuCtxPopCurrent_v2;
tcuCtxSetCurrent *cuCtxSetCurrent;
tcuCtxGetCurrent *cuCtxGetCurrent;
tcuCtxGetDevice *cuCtxGetDevice;
+tcuCtxGetFlags *cuCtxGetFlags;
tcuCtxSynchronize *cuCtxSynchronize;
tcuCtxSetLimit *cuCtxSetLimit;
tcuCtxGetLimit *cuCtxGetLimit;
@@ -97,9 +114,9 @@ tcuModuleGetFunction *cuModuleGetFunction;
tcuModuleGetGlobal_v2 *cuModuleGetGlobal_v2;
tcuModuleGetTexRef *cuModuleGetTexRef;
tcuModuleGetSurfRef *cuModuleGetSurfRef;
-tcuLinkCreate *cuLinkCreate;
-tcuLinkAddData *cuLinkAddData;
-tcuLinkAddFile *cuLinkAddFile;
+tcuLinkCreate_v2 *cuLinkCreate_v2;
+tcuLinkAddData_v2 *cuLinkAddData_v2;
+tcuLinkAddFile_v2 *cuLinkAddFile_v2;
tcuLinkComplete *cuLinkComplete;
tcuLinkDestroy *cuLinkDestroy;
tcuMemGetInfo_v2 *cuMemGetInfo_v2;
@@ -120,7 +137,7 @@ tcuIpcOpenEventHandle *cuIpcOpenEventHandle;
tcuIpcGetMemHandle *cuIpcGetMemHandle;
tcuIpcOpenMemHandle *cuIpcOpenMemHandle;
tcuIpcCloseMemHandle *cuIpcCloseMemHandle;
-tcuMemHostRegister *cuMemHostRegister;
+tcuMemHostRegister_v2 *cuMemHostRegister_v2;
tcuMemHostUnregister *cuMemHostUnregister;
tcuMemcpy *cuMemcpy;
tcuMemcpyPeer *cuMemcpyPeer;
@@ -168,6 +185,7 @@ tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel;
tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy;
tcuPointerGetAttribute *cuPointerGetAttribute;
tcuPointerSetAttribute *cuPointerSetAttribute;
+tcuPointerGetAttributes *cuPointerGetAttributes;
tcuStreamCreate *cuStreamCreate;
tcuStreamCreateWithPriority *cuStreamCreateWithPriority;
tcuStreamGetPriority *cuStreamGetPriority;
@@ -198,6 +216,10 @@ tcuLaunch *cuLaunch;
tcuLaunchGrid *cuLaunchGrid;
tcuLaunchGridAsync *cuLaunchGridAsync;
tcuParamSetTexRef *cuParamSetTexRef;
+tcuOccupancyMaxActiveBlocksPerMultiprocessor *cuOccupancyMaxActiveBlocksPerMultiprocessor;
+tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags *cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags;
+tcuOccupancyMaxPotentialBlockSize *cuOccupancyMaxPotentialBlockSize;
+tcuOccupancyMaxPotentialBlockSizeWithFlags *cuOccupancyMaxPotentialBlockSizeWithFlags;
tcuTexRefSetArray *cuTexRefSetArray;
tcuTexRefSetMipmappedArray *cuTexRefSetMipmappedArray;
tcuTexRefSetAddress_v2 *cuTexRefSetAddress_v2;
@@ -240,14 +262,14 @@ tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource;
tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray;
tcuGraphicsResourceGetMappedMipmappedArray *cuGraphicsResourceGetMappedMipmappedArray;
tcuGraphicsResourceGetMappedPointer_v2 *cuGraphicsResourceGetMappedPointer_v2;
-tcuGraphicsResourceSetMapFlags *cuGraphicsResourceSetMapFlags;
+tcuGraphicsResourceSetMapFlags_v2 *cuGraphicsResourceSetMapFlags_v2;
tcuGraphicsMapResources *cuGraphicsMapResources;
tcuGraphicsUnmapResources *cuGraphicsUnmapResources;
tcuGetExportTable *cuGetExportTable;
tcuGraphicsGLRegisterBuffer *cuGraphicsGLRegisterBuffer;
tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage;
-tcuGLGetDevices *cuGLGetDevices;
+tcuGLGetDevices_v2 *cuGLGetDevices_v2;
tcuGLCtxCreate_v2 *cuGLCtxCreate_v2;
tcuGLInit *cuGLInit;
tcuGLRegisterBufferObject *cuGLRegisterBufferObject;
@@ -258,12 +280,34 @@ tcuGLSetBufferObjectMapFlags *cuGLSetBufferObjectMapFlags;
tcuGLMapBufferObjectAsync_v2 *cuGLMapBufferObjectAsync_v2;
tcuGLUnmapBufferObjectAsync *cuGLUnmapBufferObjectAsync;
+tnvrtcGetErrorString *nvrtcGetErrorString;
+tnvrtcVersion *nvrtcVersion;
+tnvrtcCreateProgram *nvrtcCreateProgram;
+tnvrtcDestroyProgram *nvrtcDestroyProgram;
+tnvrtcCompileProgram *nvrtcCompileProgram;
+tnvrtcGetPTXSize *nvrtcGetPTXSize;
+tnvrtcGetPTX *nvrtcGetPTX;
+tnvrtcGetProgramLogSize *nvrtcGetProgramLogSize;
+tnvrtcGetProgramLog *nvrtcGetProgramLog;
+
+
+static DynamicLibrary dynamic_library_open_find(const char **paths) {
+ int i = 0;
+ while (paths[i] != NULL) {
+ DynamicLibrary lib = dynamic_library_open(paths[i]);
+ if (lib != NULL) {
+ return lib;
+ }
+ ++i;
+ }
+ return NULL;
+}
static void cuewExit(void) {
- if(lib != NULL) {
+ if(cuda_lib != NULL) {
/* Ignore errors. */
- dynamic_library_close(lib);
- lib = NULL;
+ dynamic_library_close(cuda_lib);
+ cuda_lib = NULL;
}
}
@@ -272,12 +316,21 @@ int cuewInit(void) {
/* Library paths. */
#ifdef _WIN32
/* Expected in c:/windows/system or similar, no path needed. */
- const char *path = "nvcuda.dll";
+ const char *cuda_paths[] = {"nvcuda.dll", NULL};
+ const char *nvrtc_paths[] = {"nvrtc.dll", NULL};
#elif defined(__APPLE__)
/* Default installation path. */
- const char *path = "/usr/local/cuda/lib/libcuda.dylib";
+ const char *cuda_paths[] = {"/usr/local/cuda/lib/libcuda.dylib", NULL};
+ const char *nvrtc_paths[] = {"/usr/local/cuda/lib/libnvrtc.dylib", NULL};
+#else
+ const char *cuda_paths[] = {"libcuda.so", NULL};
+ const char *nvrtc_paths[] = {"libnvrtc.so",
+# if defined(__x86_64__) || defined(_M_X64)
+ "/usr/local/cuda/lib64/libnvrtc.so",
#else
- const char *path = "libcuda.so";
+ "/usr/local/cuda/lib/libnvrtc.so",
+#endif
+ NULL};
#endif
static int initialized = 0;
static int result = 0;
@@ -296,9 +349,11 @@ int cuewInit(void) {
}
/* Load library. */
- lib = dynamic_library_open(path);
+ cuda_lib = dynamic_library_open_find(cuda_paths);
+ nvrtc_lib = dynamic_library_open_find(nvrtc_paths);
- if (lib == NULL) {
+ /* CUDA library is mandatory to have, while nvrtc might be missing. */
+ if (cuda_lib == NULL) {
result = CUEW_ERROR_OPEN_FAILED;
return result;
}
@@ -328,6 +383,11 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuDeviceGetAttribute);
CUDA_LIBRARY_FIND(cuDeviceGetProperties);
CUDA_LIBRARY_FIND(cuDeviceComputeCapability);
+ CUDA_LIBRARY_FIND(cuDevicePrimaryCtxRetain);
+ CUDA_LIBRARY_FIND(cuDevicePrimaryCtxRelease);
+ CUDA_LIBRARY_FIND(cuDevicePrimaryCtxSetFlags);
+ CUDA_LIBRARY_FIND(cuDevicePrimaryCtxGetState);
+ CUDA_LIBRARY_FIND(cuDevicePrimaryCtxReset);
CUDA_LIBRARY_FIND(cuCtxCreate_v2);
CUDA_LIBRARY_FIND(cuCtxDestroy_v2);
CUDA_LIBRARY_FIND(cuCtxPushCurrent_v2);
@@ -335,6 +395,7 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuCtxSetCurrent);
CUDA_LIBRARY_FIND(cuCtxGetCurrent);
CUDA_LIBRARY_FIND(cuCtxGetDevice);
+ CUDA_LIBRARY_FIND(cuCtxGetFlags);
CUDA_LIBRARY_FIND(cuCtxSynchronize);
CUDA_LIBRARY_FIND(cuCtxSetLimit);
CUDA_LIBRARY_FIND(cuCtxGetLimit);
@@ -355,9 +416,9 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuModuleGetGlobal_v2);
CUDA_LIBRARY_FIND(cuModuleGetTexRef);
CUDA_LIBRARY_FIND(cuModuleGetSurfRef);
- CUDA_LIBRARY_FIND(cuLinkCreate);
- CUDA_LIBRARY_FIND(cuLinkAddData);
- CUDA_LIBRARY_FIND(cuLinkAddFile);
+ CUDA_LIBRARY_FIND(cuLinkCreate_v2);
+ CUDA_LIBRARY_FIND(cuLinkAddData_v2);
+ CUDA_LIBRARY_FIND(cuLinkAddFile_v2);
CUDA_LIBRARY_FIND(cuLinkComplete);
CUDA_LIBRARY_FIND(cuLinkDestroy);
CUDA_LIBRARY_FIND(cuMemGetInfo_v2);
@@ -378,7 +439,7 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuIpcGetMemHandle);
CUDA_LIBRARY_FIND(cuIpcOpenMemHandle);
CUDA_LIBRARY_FIND(cuIpcCloseMemHandle);
- CUDA_LIBRARY_FIND(cuMemHostRegister);
+ CUDA_LIBRARY_FIND(cuMemHostRegister_v2);
CUDA_LIBRARY_FIND(cuMemHostUnregister);
CUDA_LIBRARY_FIND(cuMemcpy);
CUDA_LIBRARY_FIND(cuMemcpyPeer);
@@ -426,6 +487,7 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuMipmappedArrayDestroy);
CUDA_LIBRARY_FIND(cuPointerGetAttribute);
CUDA_LIBRARY_FIND(cuPointerSetAttribute);
+ CUDA_LIBRARY_FIND(cuPointerGetAttributes);
CUDA_LIBRARY_FIND(cuStreamCreate);
CUDA_LIBRARY_FIND(cuStreamCreateWithPriority);
CUDA_LIBRARY_FIND(cuStreamGetPriority);
@@ -456,6 +518,10 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuLaunchGrid);
CUDA_LIBRARY_FIND(cuLaunchGridAsync);
CUDA_LIBRARY_FIND(cuParamSetTexRef);
+ CUDA_LIBRARY_FIND(cuOccupancyMaxActiveBlocksPerMultiprocessor);
+ CUDA_LIBRARY_FIND(cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags);
+ CUDA_LIBRARY_FIND(cuOccupancyMaxPotentialBlockSize);
+ CUDA_LIBRARY_FIND(cuOccupancyMaxPotentialBlockSizeWithFlags);
CUDA_LIBRARY_FIND(cuTexRefSetArray);
CUDA_LIBRARY_FIND(cuTexRefSetMipmappedArray);
CUDA_LIBRARY_FIND(cuTexRefSetAddress_v2);
@@ -498,14 +564,14 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuGraphicsSubResourceGetMappedArray);
CUDA_LIBRARY_FIND(cuGraphicsResourceGetMappedMipmappedArray);
CUDA_LIBRARY_FIND(cuGraphicsResourceGetMappedPointer_v2);
- CUDA_LIBRARY_FIND(cuGraphicsResourceSetMapFlags);
+ CUDA_LIBRARY_FIND(cuGraphicsResourceSetMapFlags_v2);
CUDA_LIBRARY_FIND(cuGraphicsMapResources);
CUDA_LIBRARY_FIND(cuGraphicsUnmapResources);
CUDA_LIBRARY_FIND(cuGetExportTable);
CUDA_LIBRARY_FIND(cuGraphicsGLRegisterBuffer);
CUDA_LIBRARY_FIND(cuGraphicsGLRegisterImage);
- CUDA_LIBRARY_FIND(cuGLGetDevices);
+ CUDA_LIBRARY_FIND(cuGLGetDevices_v2);
CUDA_LIBRARY_FIND(cuGLCtxCreate_v2);
CUDA_LIBRARY_FIND(cuGLInit);
CUDA_LIBRARY_FIND(cuGLRegisterBufferObject);
@@ -517,6 +583,18 @@ int cuewInit(void) {
CUDA_LIBRARY_FIND(cuGLUnmapBufferObjectAsync);
+ if (nvrtc_lib != NULL) {
+ NVRTC_LIBRARY_FIND(nvrtcGetErrorString);
+ NVRTC_LIBRARY_FIND(nvrtcVersion);
+ NVRTC_LIBRARY_FIND(nvrtcCreateProgram);
+ NVRTC_LIBRARY_FIND(nvrtcDestroyProgram);
+ NVRTC_LIBRARY_FIND(nvrtcCompileProgram);
+ NVRTC_LIBRARY_FIND(nvrtcGetPTXSize);
+ NVRTC_LIBRARY_FIND(nvrtcGetPTX);
+ NVRTC_LIBRARY_FIND(nvrtcGetProgramLogSize);
+ NVRTC_LIBRARY_FIND(nvrtcGetProgramLog);
+ }
+
result = CUEW_SUCCESS;
return result;
}
@@ -528,10 +606,10 @@ const char *cuewErrorString(CUresult result) {
case CUDA_ERROR_OUT_OF_MEMORY: return "Out of memory";
case CUDA_ERROR_NOT_INITIALIZED: return "Driver not initialized";
case CUDA_ERROR_DEINITIALIZED: return "Driver deinitialized";
- case CUDA_ERROR_PROFILER_DISABLED: return "PROFILER_DISABLED";
- case CUDA_ERROR_PROFILER_NOT_INITIALIZED: return "PROFILER_NOT_INITIALIZED";
- case CUDA_ERROR_PROFILER_ALREADY_STARTED: return "PROFILER_ALREADY_STARTED";
- case CUDA_ERROR_PROFILER_ALREADY_STOPPED: return "PROFILER_ALREADY_STOPPED";
+ case CUDA_ERROR_PROFILER_DISABLED: return "Profiler disabled";
+ case CUDA_ERROR_PROFILER_NOT_INITIALIZED: return "Profiler not initialized";
+ case CUDA_ERROR_PROFILER_ALREADY_STARTED: return "Profiler already started";
+ case CUDA_ERROR_PROFILER_ALREADY_STOPPED: return "Profiler already stopped";
case CUDA_ERROR_NO_DEVICE: return "No CUDA-capable device available";
case CUDA_ERROR_INVALID_DEVICE: return "Invalid device";
case CUDA_ERROR_INVALID_IMAGE: return "Invalid kernel image";
@@ -548,37 +626,38 @@ const char *cuewErrorString(CUresult result) {
case CUDA_ERROR_NOT_MAPPED_AS_POINTER: return "Mapped resource not available for access as a pointer";
case CUDA_ERROR_ECC_UNCORRECTABLE: return "Uncorrectable ECC error detected";
case CUDA_ERROR_UNSUPPORTED_LIMIT: return "CUlimit not supported by device";
- case CUDA_ERROR_CONTEXT_ALREADY_IN_USE: return "CONTEXT_ALREADY_IN_USE";
- case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED: return "PEER_ACCESS_UNSUPPORTED";
- case CUDA_ERROR_INVALID_PTX: return "INVALID_PTX";
+ case CUDA_ERROR_CONTEXT_ALREADY_IN_USE: return "Context already in use";
+ case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED: return "Peer access unsupported";
+ case CUDA_ERROR_INVALID_PTX: return "Invalid ptx";
+ case CUDA_ERROR_INVALID_GRAPHICS_CONTEXT: return "Invalid graphics context";
case CUDA_ERROR_INVALID_SOURCE: return "Invalid source";
case CUDA_ERROR_FILE_NOT_FOUND: return "File not found";
case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "Link to a shared object failed to resolve";
case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED: return "Shared object initialization failed";
- case CUDA_ERROR_OPERATING_SYSTEM: return "OPERATING_SYSTEM";
+ case CUDA_ERROR_OPERATING_SYSTEM: return "Operating system";
case CUDA_ERROR_INVALID_HANDLE: return "Invalid handle";
case CUDA_ERROR_NOT_FOUND: return "Not found";
case CUDA_ERROR_NOT_READY: return "CUDA not ready";
- case CUDA_ERROR_ILLEGAL_ADDRESS: return "ILLEGAL_ADDRESS";
+ case CUDA_ERROR_ILLEGAL_ADDRESS: return "Illegal address";
case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES: return "Launch exceeded resources";
case CUDA_ERROR_LAUNCH_TIMEOUT: return "Launch exceeded timeout";
case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING: return "Launch with incompatible texturing";
- case CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED: return "PEER_ACCESS_ALREADY_ENABLED";
- case CUDA_ERROR_PEER_ACCESS_NOT_ENABLED: return "PEER_ACCESS_NOT_ENABLED";
- case CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE: return "PRIMARY_CONTEXT_ACTIVE";
- case CUDA_ERROR_CONTEXT_IS_DESTROYED: return "CONTEXT_IS_DESTROYED";
- case CUDA_ERROR_ASSERT: return "ASSERT";
- case CUDA_ERROR_TOO_MANY_PEERS: return "TOO_MANY_PEERS";
- case CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED: return "HOST_MEMORY_ALREADY_REGISTERED";
- case CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED: return "HOST_MEMORY_NOT_REGISTERED";
- case CUDA_ERROR_HARDWARE_STACK_ERROR: return "HARDWARE_STACK_ERROR";
- case CUDA_ERROR_ILLEGAL_INSTRUCTION: return "ILLEGAL_INSTRUCTION";
- case CUDA_ERROR_MISALIGNED_ADDRESS: return "MISALIGNED_ADDRESS";
- case CUDA_ERROR_INVALID_ADDRESS_SPACE: return "INVALID_ADDRESS_SPACE";
- case CUDA_ERROR_INVALID_PC: return "INVALID_PC";
+ case CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED: return "Peer access already enabled";
+ case CUDA_ERROR_PEER_ACCESS_NOT_ENABLED: return "Peer access not enabled";
+ case CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE: return "Primary context active";
+ case CUDA_ERROR_CONTEXT_IS_DESTROYED: return "Context is destroyed";
+ case CUDA_ERROR_ASSERT: return "Assert";
+ case CUDA_ERROR_TOO_MANY_PEERS: return "Too many peers";
+ case CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED: return "Host memory already registered";
+ case CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED: return "Host memory not registered";
+ case CUDA_ERROR_HARDWARE_STACK_ERROR: return "Hardware stack error";
+ case CUDA_ERROR_ILLEGAL_INSTRUCTION: return "Illegal instruction";
+ case CUDA_ERROR_MISALIGNED_ADDRESS: return "Misaligned address";
+ case CUDA_ERROR_INVALID_ADDRESS_SPACE: return "Invalid address space";
+ case CUDA_ERROR_INVALID_PC: return "Invalid pc";
case CUDA_ERROR_LAUNCH_FAILED: return "Launch failed";
- case CUDA_ERROR_NOT_PERMITTED: return "NOT_PERMITTED";
- case CUDA_ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
+ case CUDA_ERROR_NOT_PERMITTED: return "Not permitted";
+ case CUDA_ERROR_NOT_SUPPORTED: return "Not supported";
case CUDA_ERROR_UNKNOWN: return "Unknown error";
default: return "Unknown CUDA error value";
}
@@ -686,7 +765,7 @@ int cuewCompilerVersion(void) {
while (!feof(pipe)) {
if (fgets(buf, sizeof(buf), pipe) != NULL) {
- strncat(output, buf, sizeof(output) - strlen(output) - 1 );
+ strncat(output, buf, sizeof(output) - strlen(output) - 1);
}
}
diff --git a/extern/curve_fit_nd/CMakeLists.txt b/extern/curve_fit_nd/CMakeLists.txt
new file mode 100644
index 00000000000..6669971aa2d
--- /dev/null
+++ b/extern/curve_fit_nd/CMakeLists.txt
@@ -0,0 +1,35 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ intern/curve_fit_cubic.c
+ intern/curve_fit_corners_detect.c
+
+ intern/curve_fit_inline.h
+ curve_fit_nd.h
+)
+
+blender_add_lib(extern_curve_fit_nd "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h
new file mode 100644
index 00000000000..d20921c186a
--- /dev/null
+++ b/extern/curve_fit_nd/curve_fit_nd.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2016, DWANGO Co., Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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.
+ */
+
+#ifndef __SPLINE_FIT__
+#define __SPLINE_FIT__
+
+/** \file curve_fit_nd.h
+ * \ingroup curve_fit
+ */
+
+
+/* curve_fit_cubic.c */
+
+/**
+ * Takes a flat array of points and evalues that to calculate a bezier spline.
+ *
+ * \param points, points_len: The array of points to calculate a cubics from.
+ * \param dims: The number of dimensions for for each element in \a points.
+ * \param error_threshold: the error threshold to allow for,
+ * the curve will be within this distance from \a points.
+ * \param corners, corners_len: indices for points which will not have aligned tangents (optional).
+ * This can use the output of #curve_fit_corners_detect_db which has been included
+ * to evaluate a line to detect corner indices.
+ *
+ * \param r_cubic_array, r_cubic_array_len: Resulting array of tangents and knots, formatted as follows:
+ * ``r_cubic_array[r_cubic_array_len][3][dims]``,
+ * where each point has 0 and 2 for the tangents and the middle index 1 for the knot.
+ * The size of the *flat* array will be ``r_cubic_array_len * 3 * dims``.
+ * \param r_corner_index_array, r_corner_index_len: Corner indices in in \a r_cubic_array (optional).
+ * This allows you to access corners on the resulting curve.
+ *
+ * \returns zero on success, nonzero is reserved for error values.
+ */
+int curve_fit_cubic_to_points_db(
+ const double *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const double error_threshold,
+ const unsigned int *corners,
+ unsigned int corners_len,
+
+ double **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len);
+
+int curve_fit_cubic_to_points_fl(
+ const float *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const float error_threshold,
+ const unsigned int *corners,
+ const unsigned int corners_len,
+
+ float **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corners_index_array, unsigned int *r_corners_index_len);
+
+
+/* curve_fit_corners_detect.c */
+
+/**
+ * A helper function that takes a line and outputs its corner indices.
+ *
+ * \param points, points_len: Curve to evaluate.
+ * \param dims: The number of dimensions for for each element in \a points.
+ * \param radius_min: Corners on the curve between points below this radius are ignored.
+ * \param radius_max: Corners on the curve above this radius are ignored.
+ * \param samples_max: Prevent testing corners beyond this many points
+ * (prevents a large radius taking excessive time to compute).
+ * \param angle_threshold: Angles above this value are considered corners
+ * (higher value for fewer corners).
+ *
+ * \param r_corners, r_corners_len: Resulting array of corners.
+ *
+ * \returns zero on success, nonzero is reserved for error values.
+ */
+int curve_fit_corners_detect_db(
+ const double *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const double radius_min,
+ const double radius_max,
+ const unsigned int samples_max,
+ const double angle_threshold,
+
+ unsigned int **r_corners,
+ unsigned int *r_corners_len);
+
+int curve_fit_corners_detect_fl(
+ const float *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const float radius_min,
+ const float radius_max,
+ const unsigned int samples_max,
+ const float angle_threshold,
+
+ unsigned int **r_corners,
+ unsigned int *r_corners_len);
+
+#endif /* __SPLINE_FIT__ */
diff --git a/extern/curve_fit_nd/intern/curve_fit_corners_detect.c b/extern/curve_fit_nd/intern/curve_fit_corners_detect.c
new file mode 100644
index 00000000000..67ed3561a65
--- /dev/null
+++ b/extern/curve_fit_nd/intern/curve_fit_corners_detect.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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.
+ */
+
+/** \file curve_fit_corners_detect.c
+ * \ingroup curve_fit
+ */
+
+#include <math.h>
+#include <float.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "../curve_fit_nd.h"
+
+typedef unsigned int uint;
+
+#include "curve_fit_inline.h"
+
+#ifdef _MSC_VER
+# define alloca(size) _alloca(size)
+#endif
+
+#if !defined(_MSC_VER)
+# define USE_VLA
+#endif
+
+#ifdef USE_VLA
+# ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wvla"
+# endif
+#else
+# ifdef __GNUC__
+# pragma GCC diagnostic error "-Wvla"
+# endif
+#endif
+
+/* -------------------------------------------------------------------- */
+
+/** \name Simple Vector Math Lib
+ * \{ */
+
+static double cos_vnvnvn(
+ const double v0[], const double v1[], const double v2[],
+ const uint dims)
+{
+#ifdef USE_VLA
+ double dvec0[dims];
+ double dvec1[dims];
+#else
+ double *dvec0 = alloca(sizeof(double) * dims);
+ double *dvec1 = alloca(sizeof(double) * dims);
+#endif
+ normalize_vn_vnvn(dvec0, v0, v1, dims);
+ normalize_vn_vnvn(dvec1, v1, v2, dims);
+ double d = dot_vnvn(dvec0, dvec1, dims);
+ /* sanity check */
+ d = max(-1.0, min(1.0, d));
+ return d;
+}
+
+static double angle_vnvnvn(
+ const double v0[], const double v1[], const double v2[],
+ const uint dims)
+{
+ return acos(cos_vnvnvn(v0, v1, v2, dims));
+}
+
+
+static bool isect_line_sphere_vn(
+ const double l1[],
+ const double l2[],
+ const double sp[],
+ const double r,
+ uint dims,
+
+ double r_p1[]
+#if 0 /* UNUSED */
+ double r_p2[]
+#endif
+ )
+{
+#ifdef USE_VLA
+ double ldir[dims];
+ double tvec[dims];
+#else
+ double *ldir = alloca(sizeof(double) * dims);
+ double *tvec = alloca(sizeof(double) * dims);
+#endif
+
+ sub_vn_vnvn(ldir, l2, l1, dims);
+
+ sub_vn_vnvn(tvec, l1, sp, dims);
+ const double a = len_squared_vn(ldir, dims);
+ const double b = 2.0 * dot_vnvn(ldir, tvec, dims);
+ const double c = len_squared_vn(sp, dims) + len_squared_vn(l1, dims) - (2.0 * dot_vnvn(sp, l1, dims)) - sq(r);
+
+ const double i = b * b - 4.0 * a * c;
+
+ if ((i < 0.0) || (a == 0.0)) {
+ return false;
+ }
+ else if (i == 0.0) {
+ /* one intersection */
+ const double mu = -b / (2.0 * a);
+ mul_vnvn_fl(r_p1, ldir, mu, dims);
+ iadd_vnvn(r_p1, l1, dims);
+ return true;
+ }
+ else if (i > 0.0) {
+ /* # avoid calc twice */
+ const double i_sqrt = sqrt(i);
+ double mu;
+
+ /* Note: when l1 is inside the sphere and l2 is outside.
+ * the first intersection point will always be between the pair. */
+
+ /* first intersection */
+ mu = (-b + i_sqrt) / (2.0 * a);
+ mul_vnvn_fl(r_p1, ldir, mu, dims);
+ iadd_vnvn(r_p1, l1, dims);
+#if 0
+ /* second intersection */
+ mu = (-b - i_sqrt) / (2.0 * a);
+ mul_vnvn_fl(r_p2, ldir, mu, dims);
+ iadd_vnvn(r_p2, l1, dims);
+#endif
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+
+static bool point_corner_measure(
+ const double *points,
+ const uint points_len,
+ const uint i,
+ const uint i_prev_init,
+ const uint i_next_init,
+ const double radius,
+ const uint samples_max,
+ const uint dims,
+
+ double r_p_prev[], uint *r_i_prev_next,
+ double r_p_next[], uint *r_i_next_prev)
+{
+ const double *p = &points[i * dims];
+ uint sample;
+
+
+ uint i_prev = i_prev_init;
+ uint i_prev_next = i_prev + 1;
+ sample = 0;
+ while (true) {
+ if ((i_prev == -1) || (sample++ > samples_max)) {
+ return false;
+ }
+ else if (len_squared_vnvn(p, &points[i_prev * dims], dims) < radius) {
+ i_prev -= 1;
+ }
+ else {
+ break;
+ }
+ }
+
+ uint i_next = i_next_init;
+ uint i_next_prev = i_next - 1;
+ sample = 0;
+ while (true) {
+ if ((i_next == points_len) || (sample++ > samples_max)) {
+ return false;
+ }
+ else if (len_squared_vnvn(p, &points[i_next * dims], dims) < radius) {
+ i_next += 1;
+ }
+ else {
+ break;
+ }
+ }
+
+ /* find points on the sphere */
+ if (!isect_line_sphere_vn(
+ &points[i_prev * dims], &points[i_prev_next * dims], p, radius, dims,
+ r_p_prev))
+ {
+ return false;
+ }
+
+ if (!isect_line_sphere_vn(
+ &points[i_next * dims], &points[i_next_prev * dims], p, radius, dims,
+ r_p_next))
+ {
+ return false;
+ }
+
+ *r_i_prev_next = i_prev_next;
+ *r_i_next_prev = i_next_prev;
+
+ return true;
+}
+
+
+static double point_corner_angle(
+ const double *points,
+ const uint points_len,
+ const uint i,
+ const double radius_mid,
+ const double radius_max,
+ const double angle_threshold,
+ const double angle_threshold_cos,
+ /* prevent locking up when for example `radius_min` is very large
+ * (possibly larger then the curve).
+ * In this case we would end up checking every point from every other point,
+ * never reaching one that was outside the `radius_min`. */
+
+ /* prevent locking up when for e */
+ const uint samples_max,
+
+ const uint dims)
+{
+ assert(angle_threshold_cos == cos(angle_threshold));
+
+ if (i == 0 || i == points_len - 1) {
+ return 0.0;
+ }
+
+ const double *p = &points[i * dims];
+
+ /* initial test */
+ if (cos_vnvnvn(&points[(i - 1) * dims], p, &points[(i + 1) * dims], dims) > angle_threshold_cos) {
+ return 0.0;
+ }
+
+#ifdef USE_VLA
+ double p_mid_prev[dims];
+ double p_mid_next[dims];
+#else
+ double *p_mid_prev = alloca(sizeof(double) * dims);
+ double *p_mid_next = alloca(sizeof(double) * dims);
+#endif
+
+ uint i_mid_prev_next, i_mid_next_prev;
+ if (point_corner_measure(
+ points, points_len,
+ i, i - 1, i + 1,
+ radius_mid,
+ samples_max,
+ dims,
+
+ p_mid_prev, &i_mid_prev_next,
+ p_mid_next, &i_mid_next_prev))
+ {
+ const double angle_mid_cos = cos_vnvnvn(p_mid_prev, p, p_mid_next, dims);
+
+ /* compare as cos and flip direction */
+
+ /* if (angle_mid > angle_threshold) { */
+ if (angle_mid_cos < angle_threshold_cos) {
+#ifdef USE_VLA
+ double p_max_prev[dims];
+ double p_max_next[dims];
+#else
+ double *p_max_prev = alloca(sizeof(double) * dims);
+ double *p_max_next = alloca(sizeof(double) * dims);
+#endif
+
+ uint i_max_prev_next, i_max_next_prev;
+ if (point_corner_measure(
+ points, points_len,
+ i, i - 1, i + 1,
+ radius_max,
+ samples_max,
+ dims,
+
+ p_max_prev, &i_max_prev_next,
+ p_max_next, &i_max_next_prev))
+ {
+ const double angle_mid = acos(angle_mid_cos);
+ const double angle_max = angle_vnvnvn(p_max_prev, p, p_max_next, dims) / 2.0;
+ const double angle_diff = angle_mid - angle_max;
+ if (angle_diff > angle_threshold) {
+ return angle_diff;
+ }
+ }
+ }
+ }
+
+ return 0.0;
+}
+
+
+int curve_fit_corners_detect_db(
+ const double *points,
+ const uint points_len,
+ const uint dims,
+ const double radius_min, /* ignore values below this */
+ const double radius_max, /* ignore values above this */
+ const uint samples_max,
+ const double angle_threshold,
+
+ uint **r_corners,
+ uint *r_corners_len)
+{
+ const double angle_threshold_cos = cos(angle_threshold);
+ uint corners_len = 0;
+
+ /* Use the difference in angle between the mid-max radii
+ * to detect the difference between a corner and a sharp turn. */
+ const double radius_mid = (radius_min + radius_max) / 2.0;
+
+ /* we could ignore first/last- but simple to keep aligned with the point array */
+ double *points_angle = malloc(sizeof(double) * points_len);
+ points_angle[0] = 0.0;
+
+ *r_corners = NULL;
+ *r_corners_len = 0;
+
+ for (uint i = 0; i < points_len; i++) {
+ points_angle[i] = point_corner_angle(
+ points, points_len, i,
+ radius_mid, radius_max,
+ angle_threshold, angle_threshold_cos,
+ samples_max,
+ dims);
+
+ if (points_angle[i] != 0.0) {
+ corners_len++;
+ }
+ }
+
+ if (corners_len == 0) {
+ free(points_angle);
+ return 0;
+ }
+
+ /* Clean angle limits!
+ *
+ * How this works:
+ * - Find contiguous 'corners' (where the distance is less or equal to the error threshold).
+ * - Keep track of the corner with the highest angle
+ * - Clear every other angle (so they're ignored when setting corners). */
+ {
+ const double radius_min_sq = sq(radius_min);
+ uint i_span_start = 0;
+ while (i_span_start < points_len) {
+ uint i_span_end = i_span_start;
+ if (points_angle[i_span_start] != 0.0) {
+ uint i_next = i_span_start + 1;
+ uint i_best = i_span_start;
+ while (i_next < points_len) {
+ if ((points_angle[i_next] == 0.0) ||
+ (len_squared_vnvn(
+ &points[(i_next - 1) * dims],
+ &points[i_next * dims], dims) > radius_min_sq))
+ {
+ break;
+ }
+ else {
+ if (points_angle[i_best] < points_angle[i_next]) {
+ i_best = i_next;
+ }
+ i_span_end = i_next;
+ i_next += 1;
+ }
+ }
+
+ if (i_span_start != i_span_end) {
+ uint i = i_span_start;
+ while (i <= i_span_end) {
+ if (i != i_best) {
+ /* we could use some other error code */
+ assert(points_angle[i] != 0.0);
+ points_angle[i] = 0.0;
+ corners_len--;
+ }
+ i += 1;
+ }
+ }
+ }
+ i_span_start = i_span_end + 1;
+ }
+ }
+ /* End angle limit cleaning! */
+
+ corners_len += 2; /* first and last */
+ uint *corners = malloc(sizeof(uint) * corners_len);
+ uint i_corner = 0;
+ corners[i_corner++] = 0;
+ for (uint i = 0; i < points_len; i++) {
+ if (points_angle[i] != 0.0) {
+ corners[i_corner++] = i;
+ }
+ }
+ corners[i_corner++] = points_len - 1;
+ assert(i_corner == corners_len);
+
+ free(points_angle);
+
+ *r_corners = corners;
+ *r_corners_len = corners_len;
+
+ return 0;
+}
+
+int curve_fit_corners_detect_fl(
+ const float *points,
+ const uint points_len,
+ const uint dims,
+ const float radius_min, /* ignore values below this */
+ const float radius_max, /* ignore values above this */
+ const uint samples_max,
+ const float angle_threshold,
+
+ uint **r_corners,
+ uint *r_corners_len)
+{
+ const uint points_flat_len = points_len * dims;
+ double *points_db = malloc(sizeof(double) * points_flat_len);
+
+ for (uint i = 0; i < points_flat_len; i++) {
+ points_db[i] = (double)points[i];
+ }
+
+ int result = curve_fit_corners_detect_db(
+ points_db, points_len,
+ dims,
+ radius_min, radius_max,
+ samples_max,
+ angle_threshold,
+ r_corners, r_corners_len);
+
+ free(points_db);
+
+ return result;
+}
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c
new file mode 100644
index 00000000000..810cf92760d
--- /dev/null
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (c) 2016, DWANGO Co., Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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.
+ */
+
+/** \file curve_fit_cubic.c
+ * \ingroup curve_fit
+ */
+
+#include <math.h>
+#include <float.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "../curve_fit_nd.h"
+
+/* avoid re-calculating lengths multiple times */
+#define USE_LENGTH_CACHE
+
+/* store the indices in the cubic data so we can return the original indices,
+ * useful when the caller has data assosiated with the curve. */
+#define USE_ORIG_INDEX_DATA
+
+typedef unsigned int uint;
+
+#include "curve_fit_inline.h"
+
+#ifdef _MSC_VER
+# define alloca(size) _alloca(size)
+#endif
+
+#if !defined(_MSC_VER)
+# define USE_VLA
+#endif
+
+#ifdef USE_VLA
+# ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wvla"
+# endif
+#else
+# ifdef __GNUC__
+# pragma GCC diagnostic error "-Wvla"
+# endif
+#endif
+
+#define SWAP(type, a, b) { \
+ type sw_ap; \
+ sw_ap = (a); \
+ (a) = (b); \
+ (b) = sw_ap; \
+} (void)0
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Cubic Type & Functions
+ * \{ */
+
+typedef struct Cubic {
+ /* single linked lists */
+ struct Cubic *next;
+#ifdef USE_ORIG_INDEX_DATA
+ uint orig_span;
+#endif
+ /* 0: point_0, 1: handle_0, 2: handle_1, 3: point_1,
+ * each one is offset by 'dims' */
+ double pt_data[0];
+} Cubic;
+
+#define CUBIC_PT(cubic, index, dims) \
+ (&(cubic)->pt_data[(index) * (dims)])
+
+#define CUBIC_VARS(c, dims, _p0, _p1, _p2, _p3) \
+ double \
+ *_p0 = (c)->pt_data, \
+ *_p1 = _p0 + (dims), \
+ *_p2 = _p1 + (dims), \
+ *_p3 = _p2 + (dims); ((void)0)
+#define CUBIC_VARS_CONST(c, dims, _p0, _p1, _p2, _p3) \
+ const double \
+ *_p0 = (c)->pt_data, \
+ *_p1 = _p0 + (dims), \
+ *_p2 = _p1 + (dims), \
+ *_p3 = _p2 + (dims); ((void)0)
+
+
+static Cubic *cubic_alloc(const uint dims)
+{
+ return malloc(sizeof(Cubic) + (sizeof(double) * 4 * dims));
+}
+
+static void cubic_init(
+ Cubic *cubic,
+ const double p0[], const double p1[], const double p2[], const double p3[],
+ const uint dims)
+{
+ copy_vnvn(CUBIC_PT(cubic, 0, dims), p0, dims);
+ copy_vnvn(CUBIC_PT(cubic, 1, dims), p1, dims);
+ copy_vnvn(CUBIC_PT(cubic, 2, dims), p2, dims);
+ copy_vnvn(CUBIC_PT(cubic, 3, dims), p3, dims);
+}
+
+static void cubic_free(Cubic *cubic)
+{
+ free(cubic);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name CubicList Type & Functions
+ * \{ */
+
+typedef struct CubicList {
+ struct Cubic *items;
+ uint len;
+ uint dims;
+} CubicList;
+
+static void cubic_list_prepend(CubicList *clist, Cubic *cubic)
+{
+ cubic->next = clist->items;
+ clist->items = cubic;
+ clist->len++;
+}
+
+static double *cubic_list_as_array(
+ const CubicList *clist
+#ifdef USE_ORIG_INDEX_DATA
+ ,
+ const uint index_last,
+ uint *r_orig_index
+#endif
+ )
+{
+ const uint dims = clist->dims;
+ const uint array_flat_len = (clist->len + 1) * 3 * dims;
+
+ double *array = malloc(sizeof(double) * array_flat_len);
+ const double *handle_prev = &((Cubic *)clist->items)->pt_data[dims];
+
+#ifdef USE_ORIG_INDEX_DATA
+ uint orig_index_value = index_last;
+ uint orig_index_index = clist->len;
+ bool use_orig_index = (r_orig_index != NULL);
+#endif
+
+ /* fill the array backwards */
+ const size_t array_chunk = 3 * dims;
+ double *array_iter = array + array_flat_len;
+ for (Cubic *citer = clist->items; citer; citer = citer->next) {
+ array_iter -= array_chunk;
+ memcpy(array_iter, &citer->pt_data[2 * dims], sizeof(double) * 2 * dims);
+ memcpy(&array_iter[2 * dims], &handle_prev[dims], sizeof(double) * dims);
+ handle_prev = citer->pt_data;
+
+#ifdef USE_ORIG_INDEX_DATA
+ if (use_orig_index) {
+ r_orig_index[orig_index_index--] = orig_index_value;
+ orig_index_value -= citer->orig_span;
+ }
+#endif
+ }
+
+#ifdef USE_ORIG_INDEX_DATA
+ if (use_orig_index) {
+ assert(orig_index_index == 0);
+ assert(orig_index_value == 0 || index_last == 0);
+ r_orig_index[orig_index_index] = index_last ? orig_index_value : 0;
+
+ }
+#endif
+
+ /* flip tangent for first and last (we could leave at zero, but set to something useful) */
+
+ /* first */
+ array_iter -= array_chunk;
+ memcpy(&array_iter[dims], handle_prev, sizeof(double) * 2 * dims);
+ flip_vn_vnvn(&array_iter[0 * dims], &array_iter[1 * dims], &array_iter[2 * dims], dims);
+ assert(array == array_iter);
+
+ /* last */
+ array_iter += array_flat_len - (3 * dims);
+ flip_vn_vnvn(&array_iter[2 * dims], &array_iter[1 * dims], &array_iter[0 * dims], dims);
+
+ return array;
+}
+
+static void cubic_list_clear(CubicList *clist)
+{
+ Cubic *cubic_next;
+ for (Cubic *citer = clist->items; citer; citer = cubic_next) {
+ cubic_next = citer->next;
+ cubic_free(citer);
+ }
+ clist->items = NULL;
+ clist->len = 0;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Cubic Evaluation
+ * \{ */
+
+static void cubic_evaluate(
+ const Cubic *cubic, const double t, const uint dims,
+ double r_v[])
+{
+ CUBIC_VARS_CONST(cubic, dims, p0, p1, p2, p3);
+ const double s = 1.0 - t;
+
+ for (uint j = 0; j < dims; j++) {
+ const double p01 = (p0[j] * s) + (p1[j] * t);
+ const double p12 = (p1[j] * s) + (p2[j] * t);
+ const double p23 = (p2[j] * s) + (p3[j] * t);
+ r_v[j] = ((((p01 * s) + (p12 * t))) * s) +
+ ((((p12 * s) + (p23 * t))) * t);
+ }
+}
+
+static void cubic_calc_point(
+ const Cubic *cubic, const double t, const uint dims,
+ double r_v[])
+{
+ CUBIC_VARS_CONST(cubic, dims, p0, p1, p2, p3);
+ const double s = 1.0 - t;
+ for (uint j = 0; j < dims; j++) {
+ r_v[j] = p0[j] * s * s * s +
+ 3.0 * t * s * (s * p1[j] + t * p2[j]) + t * t * t * p3[j];
+ }
+}
+
+static void cubic_calc_speed(
+ const Cubic *cubic, const double t, const uint dims,
+ double r_v[])
+{
+ CUBIC_VARS_CONST(cubic, dims, p0, p1, p2, p3);
+ const double s = 1.0 - t;
+ for (uint j = 0; j < dims; j++) {
+ r_v[j] = 3.0 * ((p1[j] - p0[j]) * s * s + 2.0 *
+ (p2[j] - p0[j]) * s * t +
+ (p3[j] - p2[j]) * t * t);
+ }
+}
+
+static void cubic_calc_acceleration(
+ const Cubic *cubic, const double t, const uint dims,
+ double r_v[])
+{
+ CUBIC_VARS_CONST(cubic, dims, p0, p1, p2, p3);
+ const double s = 1.0 - t;
+ for (uint j = 0; j < dims; j++) {
+ r_v[j] = 6.0 * ((p2[j] - 2.0 * p1[j] + p0[j]) * s +
+ (p3[j] - 2.0 * p2[j] + p1[j]) * t);
+ }
+}
+
+/**
+ * Returns a 'measure' of the maximal discrepancy of the points specified
+ * by points_offset from the corresponding cubic(u[]) points.
+ */
+static void cubic_calc_error(
+ const Cubic *cubic,
+ const double *points_offset,
+ const uint points_offset_len,
+ const double *u,
+ const uint dims,
+
+ double *r_error_sq_max,
+ uint *r_error_index)
+{
+ double error_sq_max = 0.0;
+ uint error_index = 0;
+
+ const double *pt_real = points_offset + dims;
+#ifdef USE_VLA
+ double pt_eval[dims];
+#else
+ double *pt_eval = alloca(sizeof(double) * dims);
+#endif
+
+ for (uint i = 1; i < points_offset_len - 1; i++, pt_real += dims) {
+ cubic_evaluate(cubic, u[i], dims, pt_eval);
+
+ const double err_sq = len_squared_vnvn(pt_real, pt_eval, dims);
+ if (err_sq >= error_sq_max) {
+ error_sq_max = err_sq;
+ error_index = i;
+ }
+ }
+
+ *r_error_sq_max = error_sq_max;
+ *r_error_index = error_index;
+}
+
+/**
+ * Bezier multipliers
+ */
+
+static double B1(double u)
+{
+ double tmp = 1.0 - u;
+ return 3.0 * u * tmp * tmp;
+}
+
+static double B2(double u)
+{
+ return 3.0 * u * u * (1.0 - u);
+}
+
+static double B0plusB1(double u)
+{
+ double tmp = 1.0 - u;
+ return tmp * tmp * (1.0 + 2.0 * u);
+}
+
+static double B2plusB3(double u)
+{
+ return u * u * (3.0 - 2.0 * u);
+}
+
+static void points_calc_center_weighted(
+ const double *points_offset,
+ const uint points_offset_len,
+ const uint dims,
+
+ double r_center[])
+{
+ /*
+ * Calculate a center that compensates for point spacing.
+ */
+
+ const double *pt_prev = &points_offset[(points_offset_len - 2) * dims];
+ const double *pt_curr = pt_prev + dims;
+ const double *pt_next = points_offset;
+
+ double w_prev = len_vnvn(pt_prev, pt_curr, dims);
+
+ zero_vn(r_center, dims);
+ double w_tot = 0.0;
+
+ for (uint i_next = 0; i_next < points_offset_len; i_next++) {
+ const double w_next = len_vnvn(pt_curr, pt_next, dims);
+ const double w = w_prev + w_next;
+ w_tot += w;
+
+ miadd_vn_vn_fl(r_center, pt_curr, w, dims);
+
+ w_prev = w_next;
+
+ pt_prev = pt_curr;
+ pt_curr = pt_next;
+ pt_next += dims;
+ }
+
+ if (w_tot != 0.0) {
+ imul_vn_fl(r_center, 1.0 / w_tot, dims);
+ }
+}
+
+/**
+ * Use least-squares method to find Bezier control points for region.
+ */
+static void cubic_from_points(
+ const double *points_offset,
+ const uint points_offset_len,
+ const double *u_prime,
+ const double tan_l[],
+ const double tan_r[],
+ const uint dims,
+
+ Cubic *r_cubic)
+{
+
+ const double *p0 = &points_offset[0];
+ const double *p3 = &points_offset[(points_offset_len - 1) * dims];
+
+ /* Point Pairs */
+ double alpha_l, alpha_r;
+#ifdef USE_VLA
+ double a[2][dims];
+ double tmp[dims];
+#else
+ double *a[2] = {
+ alloca(sizeof(double) * dims),
+ alloca(sizeof(double) * dims),
+ };
+ double *tmp = alloca(sizeof(double) * dims);
+#endif
+
+ {
+ double x[2] = {0.0}, c[2][2] = {{0.0}};
+ const double *pt = points_offset;
+
+ for (uint i = 0; i < points_offset_len; i++, pt += dims) {
+ mul_vnvn_fl(a[0], tan_l, B1(u_prime[i]), dims);
+ mul_vnvn_fl(a[1], tan_r, B2(u_prime[i]), dims);
+
+ c[0][0] += dot_vnvn(a[0], a[0], dims);
+ c[0][1] += dot_vnvn(a[0], a[1], dims);
+ c[1][1] += dot_vnvn(a[1], a[1], dims);
+
+ c[1][0] = c[0][1];
+
+ {
+ const double b0_plus_b1 = B0plusB1(u_prime[i]);
+ const double b2_plus_b3 = B2plusB3(u_prime[i]);
+ for (uint j = 0; j < dims; j++) {
+ tmp[j] = (pt[j] - (p0[j] * b0_plus_b1)) + (p3[j] * b2_plus_b3);
+ }
+
+ x[0] += dot_vnvn(a[0], tmp, dims);
+ x[1] += dot_vnvn(a[1], tmp, dims);
+ }
+ }
+
+ double det_C0_C1 = c[0][0] * c[1][1] - c[0][1] * c[1][0];
+ double det_C_0X = x[1] * c[0][0] - x[0] * c[0][1];
+ double det_X_C1 = x[0] * c[1][1] - x[1] * c[0][1];
+
+ if (is_almost_zero(det_C0_C1)) {
+ det_C0_C1 = c[0][0] * c[1][1] * 10e-12;
+ }
+
+ /* may still divide-by-zero, check below will catch nan values */
+ alpha_l = det_X_C1 / det_C0_C1;
+ alpha_r = det_C_0X / det_C0_C1;
+ }
+
+ /*
+ * The problem that the stupid values for alpha dare not put
+ * only when we realize that the sign and wrong,
+ * but even if the values are too high.
+ * But how do you evaluate it?
+ *
+ * Meanwhile, we should ensure that these values are sometimes
+ * so only problems absurd of approximation and not for bugs in the code.
+ */
+
+ /* flip check to catch nan values */
+ if (!(alpha_l >= 0.0) ||
+ !(alpha_r >= 0.0))
+ {
+ alpha_l = alpha_r = len_vnvn(p0, p3, dims) / 3.0;
+ }
+
+ double *p1 = CUBIC_PT(r_cubic, 1, dims);
+ double *p2 = CUBIC_PT(r_cubic, 2, dims);
+
+ copy_vnvn(CUBIC_PT(r_cubic, 0, dims), p0, dims);
+ copy_vnvn(CUBIC_PT(r_cubic, 3, dims), p3, dims);
+
+#ifdef USE_ORIG_INDEX_DATA
+ r_cubic->orig_span = (points_offset_len - 1);
+#endif
+
+ /* p1 = p0 - (tan_l * alpha_l);
+ * p2 = p3 + (tan_r * alpha_r);
+ */
+ msub_vn_vnvn_fl(p1, p0, tan_l, alpha_l, dims);
+ madd_vn_vnvn_fl(p2, p3, tan_r, alpha_r, dims);
+
+ /* ------------------------------------
+ * Clamping (we could make it optional)
+ */
+#ifdef USE_VLA
+ double center[dims];
+#else
+ double *center = alloca(sizeof(double) * dims);
+#endif
+ points_calc_center_weighted(points_offset, points_offset_len, dims, center);
+
+ const double clamp_scale = 3.0; /* clamp to 3x */
+ double dist_sq_max = 0.0;
+
+ {
+ const double *pt = points_offset;
+ for (uint i = 0; i < points_offset_len; i++, pt += dims) {
+#if 0
+ double dist_sq_test = sq(len_vnvn(center, pt, dims) * clamp_scale);
+#else
+ /* do inline */
+ double dist_sq_test = 0.0;
+ for (uint j = 0; j < dims; j++) {
+ dist_sq_test += sq((pt[j] - center[j]) * clamp_scale);
+ }
+#endif
+ dist_sq_max = max(dist_sq_max, dist_sq_test);
+ }
+ }
+
+ double p1_dist_sq = len_squared_vnvn(center, p1, dims);
+ double p2_dist_sq = len_squared_vnvn(center, p2, dims);
+
+ if (p1_dist_sq > dist_sq_max ||
+ p2_dist_sq > dist_sq_max)
+ {
+
+ alpha_l = alpha_r = len_vnvn(p0, p3, dims) / 3.0;
+
+ /*
+ * p1 = p0 - (tan_l * alpha_l);
+ * p2 = p3 + (tan_r * alpha_r);
+ */
+ for (uint j = 0; j < dims; j++) {
+ p1[j] = p0[j] - (tan_l[j] * alpha_l);
+ p2[j] = p3[j] + (tan_r[j] * alpha_r);
+ }
+
+ p1_dist_sq = len_squared_vnvn(center, p1, dims);
+ p2_dist_sq = len_squared_vnvn(center, p2, dims);
+ }
+
+ /* clamp within the 3x radius */
+ if (p1_dist_sq > dist_sq_max) {
+ isub_vnvn(p1, center, dims);
+ imul_vn_fl(p1, sqrt(dist_sq_max) / sqrt(p1_dist_sq), dims);
+ iadd_vnvn(p1, center, dims);
+ }
+ if (p2_dist_sq > dist_sq_max) {
+ isub_vnvn(p2, center, dims);
+ imul_vn_fl(p2, sqrt(dist_sq_max) / sqrt(p2_dist_sq), dims);
+ iadd_vnvn(p2, center, dims);
+ }
+ /* end clamping */
+}
+
+#ifdef USE_LENGTH_CACHE
+static void points_calc_coord_length_cache(
+ const double *points_offset,
+ const uint points_offset_len,
+ const uint dims,
+
+ double *r_points_length_cache)
+{
+ const double *pt_prev = points_offset;
+ const double *pt = pt_prev + dims;
+ r_points_length_cache[0] = 0.0;
+ for (uint i = 1; i < points_offset_len; i++) {
+ r_points_length_cache[i] = len_vnvn(pt, pt_prev, dims);
+ pt_prev = pt;
+ pt += dims;
+ }
+}
+#endif /* USE_LENGTH_CACHE */
+
+
+static void points_calc_coord_length(
+ const double *points_offset,
+ const uint points_offset_len,
+ const uint dims,
+#ifdef USE_LENGTH_CACHE
+ const double *points_length_cache,
+#endif
+ double *r_u)
+{
+ const double *pt_prev = points_offset;
+ const double *pt = pt_prev + dims;
+ r_u[0] = 0.0;
+ for (uint i = 1, i_prev = 0; i < points_offset_len; i++) {
+ double length;
+
+#ifdef USE_LENGTH_CACHE
+ length = points_length_cache[i];
+
+ assert(len_vnvn(pt, pt_prev, dims) == points_length_cache[i]);
+#else
+ length = len_vnvn(pt, pt_prev, dims);
+#endif
+
+ r_u[i] = r_u[i_prev] + length;
+ i_prev = i;
+ pt_prev = pt;
+ pt += dims;
+ }
+ assert(!is_almost_zero(r_u[points_offset_len - 1]));
+ const double w = r_u[points_offset_len - 1];
+ for (uint i = 0; i < points_offset_len; i++) {
+ r_u[i] /= w;
+ }
+}
+
+/**
+ * Use Newton-Raphson iteration to find better root.
+ *
+ * \param cubic: Current fitted curve.
+ * \param p: Point to test against.
+ * \param u: Parameter value for \a p.
+ *
+ * \note Return value may be `nan` caller must check for this.
+ */
+static double cubic_find_root(
+ const Cubic *cubic,
+ const double p[],
+ const double u,
+ const uint dims)
+{
+ /* Newton-Raphson Method. */
+ /* all vectors */
+#ifdef USE_VLA
+ double q0_u[dims];
+ double q1_u[dims];
+ double q2_u[dims];
+#else
+ double *q0_u = alloca(sizeof(double) * dims);
+ double *q1_u = alloca(sizeof(double) * dims);
+ double *q2_u = alloca(sizeof(double) * dims);
+#endif
+
+ cubic_calc_point(cubic, u, dims, q0_u);
+ cubic_calc_speed(cubic, u, dims, q1_u);
+ cubic_calc_acceleration(cubic, u, dims, q2_u);
+
+ /* may divide-by-zero, caller must check for that case */
+ /* u - ((q0_u - p) * q1_u) / (q1_u.length_squared() + (q0_u - p) * q2_u) */
+ isub_vnvn(q0_u, p, dims);
+ return u - dot_vnvn(q0_u, q1_u, dims) /
+ (len_squared_vn(q1_u, dims) + dot_vnvn(q0_u, q2_u, dims));
+}
+
+static int compare_double_fn(const void *a_, const void *b_)
+{
+ const double *a = a_;
+ const double *b = b_;
+ if (*a > *b) return 1;
+ else if (*a < *b) return -1;
+ else return 0;
+}
+
+/**
+ * Given set of points and their parameterization, try to find a better parameterization.
+ */
+static bool cubic_reparameterize(
+ const Cubic *cubic,
+ const double *points_offset,
+ const uint points_offset_len,
+ const double *u,
+ const uint dims,
+
+ double *r_u_prime)
+{
+ /*
+ * Recalculate the values of u[] based on the Newton Raphson method
+ */
+
+ const double *pt = points_offset;
+ for (uint i = 0; i < points_offset_len; i++, pt += dims) {
+ r_u_prime[i] = cubic_find_root(cubic, pt, u[i], dims);
+ if (!isfinite(r_u_prime[i])) {
+ return false;
+ }
+ }
+
+ qsort(r_u_prime, points_offset_len, sizeof(double), compare_double_fn);
+
+ if ((r_u_prime[0] < 0.0) ||
+ (r_u_prime[points_offset_len - 1] > 1.0))
+ {
+ return false;
+ }
+
+ assert(r_u_prime[0] >= 0.0);
+ assert(r_u_prime[points_offset_len - 1] <= 1.0);
+ return true;
+}
+
+
+static void fit_cubic_to_points(
+ const double *points_offset,
+ const uint points_offset_len,
+#ifdef USE_LENGTH_CACHE
+ const double *points_length_cache,
+#endif
+ const double tan_l[],
+ const double tan_r[],
+ const double error_threshold,
+ const uint dims,
+ /* fill in the list */
+ CubicList *clist)
+{
+ const uint iteration_max = 4;
+ const double error_sq = sq(error_threshold);
+
+ Cubic *cubic;
+
+ if (points_offset_len == 2) {
+ cubic = cubic_alloc(dims);
+ CUBIC_VARS(cubic, dims, p0, p1, p2, p3);
+
+ copy_vnvn(p0, &points_offset[0 * dims], dims);
+ copy_vnvn(p3, &points_offset[1 * dims], dims);
+
+ const double dist = len_vnvn(p0, p3, dims) / 3.0;
+ msub_vn_vnvn_fl(p1, p0, tan_l, dist, dims);
+ madd_vn_vnvn_fl(p2, p3, tan_r, dist, dims);
+
+#ifdef USE_ORIG_INDEX_DATA
+ cubic->orig_span = 1;
+#endif
+
+ cubic_list_prepend(clist, cubic);
+ return;
+ }
+
+ double *u = malloc(sizeof(double) * points_offset_len);
+ points_calc_coord_length(
+ points_offset, points_offset_len, dims,
+#ifdef USE_LENGTH_CACHE
+ points_length_cache,
+#endif
+ u);
+
+ cubic = cubic_alloc(dims);
+
+ double error_sq_max;
+ uint split_index;
+
+ /* Parameterize points, and attempt to fit curve */
+ cubic_from_points(
+ points_offset, points_offset_len, u, tan_l, tan_r, dims, cubic);
+
+ /* Find max deviation of points to fitted curve */
+ cubic_calc_error(
+ cubic, points_offset, points_offset_len, u, dims,
+ &error_sq_max, &split_index);
+
+ if (error_sq_max < error_sq) {
+ free(u);
+ cubic_list_prepend(clist, cubic);
+ return;
+ }
+ else {
+ /* If error not too large, try some reparameterization and iteration */
+ double *u_prime = malloc(sizeof(double) * points_offset_len);
+ for (uint iter = 0; iter < iteration_max; iter++) {
+ if (!cubic_reparameterize(
+ cubic, points_offset, points_offset_len, u, dims, u_prime))
+ {
+ break;
+ }
+
+ cubic_from_points(
+ points_offset, points_offset_len, u_prime,
+ tan_l, tan_r, dims, cubic);
+ cubic_calc_error(
+ cubic, points_offset, points_offset_len, u_prime, dims,
+ &error_sq_max, &split_index);
+
+ if (error_sq_max < error_sq) {
+ free(u_prime);
+ free(u);
+ cubic_list_prepend(clist, cubic);
+ return;
+ }
+
+ SWAP(double *, u, u_prime);
+ }
+ free(u_prime);
+ }
+
+ free(u);
+ cubic_free(cubic);
+
+
+ /* Fitting failed -- split at max error point and fit recursively */
+
+ /* Check splinePoint is not an endpoint?
+ *
+ * This assert happens sometimes...
+ * Look into it but disable for now. Campbell! */
+
+ // assert(split_index > 1)
+#ifdef USE_VLA
+ double tan_center[dims];
+#else
+ double *tan_center = alloca(sizeof(double) * dims);
+#endif
+
+ const double *pt_a = &points_offset[(split_index - 1) * dims];
+ const double *pt_b = &points_offset[(split_index + 1) * dims];
+
+ assert(split_index < points_offset_len);
+ if (equals_vnvn(pt_a, pt_b, dims)) {
+ pt_a += dims;
+ }
+
+ /* tan_center = (pt_a - pt_b).normalized() */
+ normalize_vn_vnvn(tan_center, pt_a, pt_b, dims);
+
+ fit_cubic_to_points(
+ points_offset, split_index + 1,
+#ifdef USE_LENGTH_CACHE
+ points_length_cache,
+#endif
+ tan_l, tan_center, error_threshold, dims, clist);
+ fit_cubic_to_points(
+ &points_offset[split_index * dims], points_offset_len - split_index,
+#ifdef USE_LENGTH_CACHE
+ points_length_cache + split_index,
+#endif
+ tan_center, tan_r, error_threshold, dims, clist);
+
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name External API for Curve-Fitting
+ * \{ */
+
+/**
+ * Main function:
+ *
+ * Take an array of 3d points.
+ * return the cubic splines
+ */
+int curve_fit_cubic_to_points_db(
+ const double *points,
+ const uint points_len,
+ const uint dims,
+ const double error_threshold,
+ const uint *corners,
+ uint corners_len,
+
+ double **r_cubic_array, uint *r_cubic_array_len,
+ uint **r_cubic_orig_index,
+ uint **r_corner_index_array, uint *r_corner_index_len)
+{
+ uint corners_buf[2];
+ if (corners == NULL) {
+ assert(corners_len == 0);
+ corners_buf[0] = 0;
+ corners_buf[1] = points_len - 1;
+ corners = corners_buf;
+ corners_len = 2;
+ }
+
+ CubicList clist = {0};
+ clist.dims = dims;
+
+#ifdef USE_VLA
+ double tan_l[dims];
+ double tan_r[dims];
+#else
+ double *tan_l = alloca(sizeof(double) * dims);
+ double *tan_r = alloca(sizeof(double) * dims);
+#endif
+
+#ifdef USE_LENGTH_CACHE
+ double *points_length_cache = NULL;
+ uint points_length_cache_len_alloc = 0;
+#endif
+
+ uint *corner_index_array = NULL;
+ uint corner_index = 0;
+ if (r_corner_index_array && (corners != corners_buf)) {
+ corner_index_array = malloc(sizeof(uint) * corners_len);
+ corner_index_array[corner_index++] = corners[0];
+ }
+
+ for (uint i = 1; i < corners_len; i++) {
+ const uint points_offset_len = corners[i] - corners[i - 1] + 1;
+ const uint first_point = corners[i - 1];
+
+ assert(points_offset_len >= 1);
+ if (points_offset_len > 1) {
+ const double *pt_l = &points[first_point * dims];
+ const double *pt_r = &points[(first_point + points_offset_len - 1) * dims];
+ const double *pt_l_next = pt_l + dims;
+ const double *pt_r_prev = pt_r - dims;
+
+ /* tan_l = (pt_l - pt_l_next).normalized()
+ * tan_r = (pt_r_prev - pt_r).normalized()
+ */
+ normalize_vn_vnvn(tan_l, pt_l, pt_l_next, dims);
+ normalize_vn_vnvn(tan_r, pt_r_prev, pt_r, dims);
+
+#ifdef USE_LENGTH_CACHE
+ if (points_length_cache_len_alloc < points_offset_len) {
+ if (points_length_cache) {
+ free(points_length_cache);
+ }
+ points_length_cache = malloc(sizeof(double) * points_offset_len);
+ }
+ points_calc_coord_length_cache(
+ &points[first_point * dims], points_offset_len, dims,
+ points_length_cache);
+#endif
+
+ fit_cubic_to_points(
+ &points[first_point * dims], points_offset_len,
+#ifdef USE_LENGTH_CACHE
+ points_length_cache,
+#endif
+ tan_l, tan_r, error_threshold, dims, &clist);
+ }
+ else if (points_len == 1) {
+ assert(points_offset_len == 1);
+ assert(corners_len == 2);
+ assert(corners[0] == 0);
+ assert(corners[1] == 0);
+ const double *pt = &points[0];
+ Cubic *cubic = cubic_alloc(dims);
+ cubic_init(cubic, pt, pt, pt, pt, dims);
+ cubic_list_prepend(&clist, cubic);
+ }
+
+ if (corner_index_array) {
+ corner_index_array[corner_index++] = clist.len;
+ }
+ }
+
+#ifdef USE_LENGTH_CACHE
+ if (points_length_cache) {
+ free(points_length_cache);
+ }
+#endif
+
+#ifdef USE_ORIG_INDEX_DATA
+ uint *cubic_orig_index = NULL;
+ if (r_cubic_orig_index) {
+ cubic_orig_index = malloc(sizeof(uint) * (clist.len + 1));
+ }
+#else
+ *r_cubic_orig_index = NULL;
+#endif
+
+ /* allocate a contiguous array and free the linked list */
+ *r_cubic_array = cubic_list_as_array(
+ &clist
+#ifdef USE_ORIG_INDEX_DATA
+ , corners[corners_len - 1], cubic_orig_index
+#endif
+ );
+ *r_cubic_array_len = clist.len + 1;
+
+ cubic_list_clear(&clist);
+
+#ifdef USE_ORIG_INDEX_DATA
+ if (cubic_orig_index) {
+ *r_cubic_orig_index = cubic_orig_index;
+ }
+#endif
+
+ if (corner_index_array) {
+ assert(corner_index == corners_len);
+ *r_corner_index_array = corner_index_array;
+ *r_corner_index_len = corner_index;
+ }
+
+ return 0;
+}
+
+/**
+ * A version of #curve_fit_cubic_to_points_db to handle floats
+ */
+int curve_fit_cubic_to_points_fl(
+ const float *points,
+ const uint points_len,
+ const uint dims,
+ const float error_threshold,
+ const uint *corners,
+ const uint corners_len,
+
+ float **r_cubic_array, uint *r_cubic_array_len,
+ uint **r_cubic_orig_index,
+ uint **r_corner_index_array, uint *r_corner_index_len)
+{
+ const uint points_flat_len = points_len * dims;
+ double *points_db = malloc(sizeof(double) * points_flat_len);
+
+ for (uint i = 0; i < points_flat_len; i++) {
+ points_db[i] = (double)points[i];
+ }
+
+ double *cubic_array_db = NULL;
+ float *cubic_array_fl = NULL;
+ uint cubic_array_len = 0;
+
+ int result = curve_fit_cubic_to_points_db(
+ points_db, points_len, dims, error_threshold, corners, corners_len,
+ &cubic_array_db, &cubic_array_len,
+ r_cubic_orig_index,
+ r_corner_index_array, r_corner_index_len);
+ free(points_db);
+
+ if (!result) {
+ uint cubic_array_flat_len = cubic_array_len * 3 * dims;
+ cubic_array_fl = malloc(sizeof(float) * cubic_array_flat_len);
+ for (uint i = 0; i < cubic_array_flat_len; i++) {
+ cubic_array_fl[i] = (float)cubic_array_db[i];
+ }
+ free(cubic_array_db);
+ }
+
+ *r_cubic_array = cubic_array_fl;
+ *r_cubic_array_len = cubic_array_len;
+
+ return result;
+}
+
+/** \} */
diff --git a/extern/curve_fit_nd/intern/curve_fit_inline.h b/extern/curve_fit_nd/intern/curve_fit_inline.h
new file mode 100644
index 00000000000..17aa02be3e5
--- /dev/null
+++ b/extern/curve_fit_nd/intern/curve_fit_inline.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> 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.
+ */
+
+
+/** \file curve_fit_inline.h
+ * \ingroup curve_fit
+ */
+
+/** \name Simple Vector Math Lib
+ * \{ */
+
+#ifdef _MSC_VER
+# define MINLINE static __forceinline
+#else
+# define MINLINE static inline
+#endif
+
+MINLINE double sq(const double d)
+{
+ return d * d;
+}
+
+#ifndef _MSC_VER
+MINLINE double min(const double a, const double b)
+{
+ return b < a ? b : a;
+}
+
+MINLINE double max(const double a, const double b)
+{
+ return a < b ? b : a;
+}
+#endif
+
+MINLINE void zero_vn(
+ double v0[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v0[j] = 0.0;
+ }
+}
+
+MINLINE void flip_vn_vnvn(
+ double v_out[], const double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] = v0[j] + (v0[j] - v1[j]);
+ }
+}
+
+MINLINE void copy_vnvn(
+ double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v0[j] = v1[j];
+ }
+}
+
+MINLINE double dot_vnvn(
+ const double v0[], const double v1[], const uint dims)
+{
+ double d = 0.0;
+ for (uint j = 0; j < dims; j++) {
+ d += v0[j] * v1[j];
+ }
+ return d;
+}
+
+MINLINE void add_vn_vnvn(
+ double v_out[], const double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] = v0[j] + v1[j];
+ }
+}
+
+MINLINE void sub_vn_vnvn(
+ double v_out[], const double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] = v0[j] - v1[j];
+ }
+}
+
+MINLINE void iadd_vnvn(
+ double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v0[j] += v1[j];
+ }
+}
+
+MINLINE void isub_vnvn(
+ double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v0[j] -= v1[j];
+ }
+}
+
+MINLINE void madd_vn_vnvn_fl(
+ double v_out[],
+ const double v0[], const double v1[],
+ const double f, const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] = v0[j] + v1[j] * f;
+ }
+}
+
+MINLINE void msub_vn_vnvn_fl(
+ double v_out[],
+ const double v0[], const double v1[],
+ const double f, const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] = v0[j] - v1[j] * f;
+ }
+}
+
+MINLINE void miadd_vn_vn_fl(
+ double v_out[], const double v0[], double f, const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] += v0[j] * f;
+ }
+}
+
+#if 0
+MINLINE void misub_vn_vn_fl(
+ double v_out[], const double v0[], double f, const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] -= v0[j] * f;
+ }
+}
+#endif
+
+MINLINE void mul_vnvn_fl(
+ double v_out[],
+ const double v0[], const double f, const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v_out[j] = v0[j] * f;
+ }
+}
+
+MINLINE void imul_vn_fl(double v0[], const double f, const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ v0[j] *= f;
+ }
+}
+
+
+MINLINE double len_squared_vnvn(
+ const double v0[], const double v1[], const uint dims)
+{
+ double d = 0.0;
+ for (uint j = 0; j < dims; j++) {
+ d += sq(v0[j] - v1[j]);
+ }
+ return d;
+}
+
+MINLINE double len_squared_vn(
+ const double v0[], const uint dims)
+{
+ double d = 0.0;
+ for (uint j = 0; j < dims; j++) {
+ d += sq(v0[j]);
+ }
+ return d;
+}
+
+MINLINE double len_vnvn(
+ const double v0[], const double v1[], const uint dims)
+{
+ return sqrt(len_squared_vnvn(v0, v1, dims));
+}
+
+#if 0
+static double len_vn(
+ const double v0[], const uint dims)
+{
+ return sqrt(len_squared_vn(v0, dims));
+}
+
+MINLINE double normalize_vn(
+ double v0[], const uint dims)
+{
+ double d = len_squared_vn(v0, dims);
+ if (d != 0.0 && ((d = sqrt(d)) != 0.0)) {
+ imul_vn_fl(v0, 1.0 / d, dims);
+ }
+ return d;
+}
+#endif
+
+/* v_out = (v0 - v1).normalized() */
+MINLINE double normalize_vn_vnvn(
+ double v_out[],
+ const double v0[], const double v1[], const uint dims)
+{
+ double d = 0.0;
+ for (uint j = 0; j < dims; j++) {
+ double a = v0[j] - v1[j];
+ d += sq(a);
+ v_out[j] = a;
+ }
+ if (d != 0.0 && ((d = sqrt(d)) != 0.0)) {
+ imul_vn_fl(v_out, 1.0 / d, dims);
+ }
+ return d;
+}
+
+MINLINE bool is_almost_zero_ex(double val, double eps)
+{
+ return (-eps < val) && (val < eps);
+}
+
+MINLINE bool is_almost_zero(double val)
+{
+ return is_almost_zero_ex(val, 1e-8);
+}
+
+MINLINE bool equals_vnvn(
+ const double v0[], const double v1[], const uint dims)
+{
+ for (uint j = 0; j < dims; j++) {
+ if (v0[j] != v1[j]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/** \} */
diff --git a/extern/libmv/third_party/gflags/AUTHORS.txt b/extern/gflags/AUTHORS.txt
index 887918bd00e..887918bd00e 100644
--- a/extern/libmv/third_party/gflags/AUTHORS.txt
+++ b/extern/gflags/AUTHORS.txt
diff --git a/extern/gflags/CMakeLists.txt b/extern/gflags/CMakeLists.txt
new file mode 100644
index 00000000000..8977fcca457
--- /dev/null
+++ b/extern/gflags/CMakeLists.txt
@@ -0,0 +1,56 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ src
+ src/gflags
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ src/gflags.cc
+ src/gflags_completions.cc
+ src/gflags_reporting.cc
+
+ src/config.h
+ src/gflags/gflags_completions.h
+ src/gflags/gflags_declare.h
+ src/gflags/gflags_gflags.h
+ src/gflags/gflags.h
+ src/mutex.h
+ src/util.h
+)
+
+if(WIN32)
+ list(APPEND SRC
+ src/windows_port.cc
+ src/windows_port.h
+ )
+endif()
+
+add_definitions(${GFLAGS_DEFINES})
+
+blender_add_lib(extern_gflags "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/third_party/gflags/COPYING.txt b/extern/gflags/COPYING.txt
index d15b0c24134..d15b0c24134 100644
--- a/extern/libmv/third_party/gflags/COPYING.txt
+++ b/extern/gflags/COPYING.txt
diff --git a/extern/gflags/ChangeLog.txt b/extern/gflags/ChangeLog.txt
new file mode 100644
index 00000000000..eea9f83950f
--- /dev/null
+++ b/extern/gflags/ChangeLog.txt
@@ -0,0 +1,218 @@
+* Tue Mar 24 2014 - Andreas Schuh <andreas.schuh.84@gmail.com>
+
+- gflags: version 2.1.2
+- Moved project to GitHub
+- Added GFLAGS_NAMESPACE definition to gflags_declare.h
+- Fixed issue 94: Keep "google" as primary namespace and import symbols into "gflags" namespace
+- Fixed issue 96: Fix binary ABI compatibility with gflags 2.0 using "google" as primary namespace
+- Fixed issue 97/101: Removed (patched) CMake modules and enabled C language instead
+- Fixed issue 103: Set CMake policy CMP0042 to silence warning regarding MACOS_RPATH setting
+
+* Sun Mar 20 2014 - Andreas Schuh <google-gflags@googlegroups.com>
+
+- gflags: version 2.1.1
+- Fixed issue 77: GFLAGS_IS_A_DLL expands to empty string in gflags_declare.h
+- Fixed issue 79: GFLAGS_NAMESPACE not expanded to actual namespace in gflags_declare.h
+- Fixed issue 80: Allow include path to differ from GFLAGS_NAMESPACE
+
+* Thu Mar 20 2014 - Andreas Schuh <google-gflags@googlegroups.com>
+
+- gflags: version 2.1.0
+- Build system configuration using CMake instead of autotools
+- CPack packaging support for Debian/Ubuntu, Red Hat, and Mac OS X
+- Fixed issue 54: Fix "invalid suffix on literal" (C++11)
+- Fixed issue 57: Use _strdup instead of strdup on Windows
+- Fixed issue 62: Change all preprocessor include guards to start with GFLAGS_
+- Fixed issue 64: Add DEFINE_validator macro
+- Fixed issue 73: Warnings in Visual Studio 2010 and unable to compile unit test
+
+* Wed Jan 25 2012 - Google Inc. <google-gflags@googlegroups.com>
+
+- gflags: version 2.0
+- Changed the 'official' gflags email in setup.py/etc
+- Renamed google-gflags.sln to gflags.sln
+- Changed copyright text to reflect Google's relinquished ownership
+
+* Tue Dec 20 2011 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.7
+- Add CommandLineFlagInfo::flag_ptr pointing to current storage (musji)
+- PORTING: flush after writing to stderr, needed on cygwin
+- PORTING: Clean up the GFLAGS_DLL_DECL stuff better
+- Fix a bug in StringPrintf() that affected large strings (csilvers)
+- Die at configure-time when g++ isn't installed
+
+* Fri Jul 29 2011 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.6
+- BUGFIX: Fix a bug where we were leaving out a required $(top_srcdir)
+- Fix definition of clstring (jyrki)
+- Split up flag declares into its own file (jyrki)
+- Add --version support (csilvers)
+- Update the README for gflags with static libs
+- Update acx_pthread.m4 for nostdlib
+- Change ReparseCommandLineFlags to return void (csilvers)
+- Some doc typofixes and example augmentation (various)
+
+* Mon Jan 24 2011 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.5
+- Better reporting of current vs default value (handler)
+- Add API for cleaning up of memory at program-exit (jmarantz)
+- Fix macros to work inside namespaces (csilvers)
+- Use our own string typedef in case string is redefined (csilvers)
+- Updated to autoconf 2.65
+
+* Wed Oct 13 2010 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.4
+- Add a check to prevent passing 0 to DEFINE_string (jorg)
+- Reduce compile (.o) size (jyrki)
+- Some small changes to quiet debug compiles (alexk)
+- PORTING: better support static linking on windows (csilvers)
+- DOCUMENTATION: change default values, use validators, etc.
+- Update the NEWS file to be non-empty
+- Add pkg-config (.pc) files for libgflags and libgflags_nothreads
+
+* Mon Jan 4 2010 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.3
+- PORTABILITY: can now build and run tests under MSVC (csilvers)
+- Remove the python gflags code, which is now its own package (tansell)
+- Clarify that "last flag wins" in the docs (csilvers)
+- Comment danger of using GetAllFlags in validators (wojtekm)
+- PORTABILITY: Some fixes necessary for c++0x (mboerger)
+- Makefile fix: $(srcdir) -> $(top_srcdir) in one place (csilvres)
+- INSTALL: autotools to autoconf v2.64 + automake v1.11 (csilvers)
+
+* Thu Sep 10 2009 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.2
+- PORTABILITY: can now build and run tests under mingw (csilvers)
+- Using a string arg for a bool flag is a compile-time error (rbayardo)
+- Add --helpxml to gflags.py (salcianu)
+- Protect against a hypothetical global d'tor mutex problem (csilvers)
+- BUGFIX: can now define a flag after 'using namespace google' (hamaji)
+
+* Tue Apr 14 2009 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.1
+- Add both foo and nofoo for boolean flags, with --undefok (andychu)
+- Better document how validators work (wojtekm)
+- Improve binary-detection for bash-completion (mtamsky)
+- Python: Add a concept of "key flags", used with --help (salcianu)
+- Python: Robustify flag_values (salcianu)
+- Python: Add a new DEFINE_bool alias (keir, andrewliu)
+- Python: Do module introspection based on module name (dsturtevant)
+- Fix autoconf a bit better, especially on windows and solaris (ajenjo)
+- BUG FIX: gflags_nothreads was linking against the wrong lib (ajenjo)
+- BUG FIX: threads-detection failed on FreeBSD; replace it (ajenjo)
+- PORTABILITY: Quiet an internal compiler error with SUSE 10 (csilvers)
+- PORTABILITY: Update deb.sh for more recenty debuilds (csilvers)
+- PORTABILITY: #include more headers to satify new gcc's (csilvers)
+- INSTALL: Updated to autoconf 2.61 and libtool 1.5.26 (csilvers)
+
+* Fri Oct 3 2008 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.0
+- Add a missing newline to an error string (bcmills)
+- (otherwise exactly the same as gflags 1.0rc2)
+
+* Thu Sep 18 2008 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.0rc2
+- Report current flag values in --helpxml (hdn)
+- Fix compilation troubles with gcc 4.3.3 (simonb)
+- BUG FIX: I was missing a std:: in DECLARE_string (csilvers)
+- BUG FIX: Clarify in docs how to specify --bool flags (csilvers)
+- BUG FIX: Fix --helpshort for source files not in a subdir (csilvers)
+- BUG FIX: Fix python unittest for 64-bit builds (bcmills)
+
+* Tue Aug 19 2008 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 1.0rc1
+- Move #include files from google/ to gflags/ (csilvers)
+- Small optimizations to reduce binary (library) size (jyrki)
+- BUGFIX: forgot a std:: in one of the .h files (csilvers)
+- Speed up locking by making sure calls are inlined (ajenjo)
+- 64-BIT COMPATIBILITY: Use %PRId64 instead of %lld (csilvers)
+- PORTABILITY: fix Makefile to work with Cygwin (ajenjo)
+- PORTABILITY: fix code to compile under Visual Studio (ajenjo)
+- PORTABILITY: fix code to compile under Solaris 10 with CC (csilvers)
+
+* Mon Jul 21 2008 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.9
+- Add the ability to validate a command-line flag (csilvers)
+- Add completion support for commandline flags in bash (daven)
+- Add -W compile flags to Makefile, when using gcc (csilvers)
+- Allow helpstring to be NULL (cristianoc)
+- Improved documentation of classes in the .cc file (csilvers)
+- Fix python bug with AppendFlagValues + shortnames (jjtswan)
+- Use bool instead of int for boolean flags in gflags.py (bcmills)
+- Simplify the way we declare flags, now more foolproof (csilvers)
+- Better error messages when bool flags collide (colohan)
+- Only evaluate DEFINE_foo macro args once (csilvers)
+
+* Wed Mar 26 2008 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.8
+- Export DescribeOneFlag() in the API
+- Add support for automatic line wrapping at 80 cols for gflags.py
+- Bugfix: do not treat an isolated "-" the same as an isolated "--"
+- Update rpm spec to point to Google Code rather than sourceforge (!)
+- Improve documentation (including documenting thread-safety)
+- Improve #include hygiene
+- Improve testing
+
+* Thu Oct 18 2007 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.7
+- Deal even more correctly with libpthread not linked in (csilvers)
+- Add STRIP_LOG, an improved DO_NOT_SHOW_COMMANDLINE_HELP (sioffe)
+- Be more accurate printing default flag values in --help (dsturtevant)
+- Reduce .o file size a bit by using shorter namespace names (jeff)
+- Use relative install path, so 'setup.py --home' works (csilvers)
+- Notice when a boolean flag has a non-boolean default (bnmouli)
+- Broaden --helpshort to match foo-main.cc and foo_main.cc (hendrie)
+- Fix "no modules match" message for --helpshort, etc (hendrie)
+
+* Wed Aug 15 2007 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.6
+- Deal correctly with case that libpthread is not linked in (csilvers)
+- Update Makefile/tests so we pass "make distcheck" (csilvers)
+- Document and test that last assignment to a flag wins (wan)
+
+* Tue Jun 12 2007 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.5
+- Include all m4 macros in the distribution (csilvers)
+- Python: Fix broken data_files field in setup.py (sidlon)
+- Python: better string serliaizing and unparsing (abo, csimmons)
+- Fix checks for NaN and inf to work with Mac OS X (csilvers)
+
+* Thu Apr 19 2007 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.4
+- Remove is_default from GetCommandLineFlagInfo (csilvers)
+- Portability fixes: includes, strtoll, gcc4.3 errors (csilvers)
+- A few doc typo cleanups (csilvers)
+
+* Wed Mar 28 2007 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.3
+- python portability fix: use popen instead of subprocess (csilvers)
+- Add is_default to CommandLineFlagInfo (pchien)
+- Make docs a bit prettier (csilvers)
+- Actually include the python files in the distribution! :-/ (csilvers)
+
+* Mon Jan 22 2007 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.2
+- added support for python commandlineflags, as well as c++
+- gflags2man, a script to turn flags into a man page (dchristian)
+
+* Wed Dec 13 2006 - Google Inc. <opensource@google.com>
+
+- google-gflags: version 0.1
diff --git a/extern/libmv/third_party/gflags/NEWS.txt b/extern/gflags/NEWS.txt
index 74186071129..74186071129 100644
--- a/extern/libmv/third_party/gflags/NEWS.txt
+++ b/extern/gflags/NEWS.txt
diff --git a/extern/gflags/README.libmv b/extern/gflags/README.libmv
new file mode 100644
index 00000000000..bf58ccb5fd2
--- /dev/null
+++ b/extern/gflags/README.libmv
@@ -0,0 +1,19 @@
+Project: Google Flags
+URL: http://code.google.com/p/google-gflags/
+License: New BSD
+Upstream version: 2.2.0 (9db82895)
+Local modifications:
+
+- Flattened the tree and only included files needed for libmv.
+
+- config.h was originally generated on linux machine with some
+ further tweaks:
+
+ * OS_WINDOWS need to be conditinally defined from inside #ifdef WIN32
+ * Same applies yo HAVE_SHLWAPI_H
+ * Disabeld HAVE_FNMATCH_H
+
+- Removed attribute(unused) from FlagSaver.
+
+- Applied some modifications from fork https://github.com/Nazg-Gul/gflags.git
+ (see https://github.com/gflags/gflags/pull/129)
diff --git a/extern/gflags/README.md b/extern/gflags/README.md
new file mode 100644
index 00000000000..79bd2028603
--- /dev/null
+++ b/extern/gflags/README.md
@@ -0,0 +1,270 @@
+24 March 2015
+-------------
+
+I've just released gflags 2.1.2.
+
+This release completes the namespace change fixes. In particular,
+it restores binary ABI compatibility with release version 2.0.
+The deprecated "google" namespace is by default still kept as
+primary namespace while symbols are imported into the new "gflags" namespace.
+This can be overridden using the CMake variable GFLAGS_NAMESPACE.
+
+Other fixes of the build configuration are related to the (patched)
+CMake modules FindThreads.cmake and CheckTypeSize.cmake. These have
+been removed and instead the C language is enabled again even though
+gflags is written in C++ only.
+
+This release also marks the complete move of the gflags project
+from Google Code to GitHub. Email addresses of original issue
+reporters got lost in the process. Given the age of most issue reports,
+this should be negligable.
+
+Please report any further issues using the GitHub issue tracker.
+
+
+30 March 2014
+-------------
+
+I've just released gflags 2.1.1.
+
+This release fixes a few bugs in the configuration of gflags\_declare.h
+and adds a separate GFLAGS\_INCLUDE\_DIR CMake variable to the build configuration.
+Setting GFLAGS\_NAMESPACE to "google" no longer changes also the include
+path of the public header files. This allows the use of the library with
+other Google projects such as glog which still use the deprecated "google"
+namespace for the gflags library, but include it as "gflags/gflags.h".
+
+20 March 2014
+-------------
+
+I've just released gflags 2.1.
+
+The major changes are the use of CMake for the build configuration instead
+of the autotools and packaging support through CPack. The default namespace
+of all C++ symbols is now "gflags" instead of "google". This can be
+configured via the GFLAGS\_NAMESPACE variable.
+
+This release compiles with all major compilers without warnings and passed
+the unit tests on Ubuntu 12.04, Windows 7 (Visual Studio 2008 and 2010,
+Cygwin, MinGW), and Mac OS X (Xcode 5.1).
+
+The SVN repository on Google Code is now frozen and replaced by a Git
+repository such that it can be used as Git submodule by projects. The main
+hosting of this project remains at Google Code. Thanks to the distributed
+character of Git, I can push (and pull) changes from both GitHub and Google Code
+in order to keep the two public repositories in sync.
+When fixing an issue for a pull request through either of these hosting
+platforms, please reference the issue number as
+[described here](https://code.google.com/p/support/wiki/IssueTracker#Integration_with_version_control).
+For the further development, I am following the
+[Git branching model](http://nvie.com/posts/a-successful-git-branching-model/)
+with feature branch names prefixed by "feature/" and bugfix branch names
+prefixed by "bugfix/", respectively.
+
+Binary and source [packages](https://github.com/schuhschuh/gflags/releases) are available on GitHub.
+
+
+14 January 2014
+---------------
+
+The migration of the build system to CMake is almost complete.
+What remains to be done is rewriting the tests in Python such they can be
+executed on non-Unix platforms and splitting them up into separate CTest tests.
+Though merging these changes into the master branch yet remains to be done,
+it is recommended to already start using the
+[cmake-migration](https://github.com/schuhschuh/gflags/tree/cmake-migration) branch.
+
+
+20 April 2013
+-------------
+
+More than a year has past since I (Andreas) took over the maintenance for
+`gflags`. Only few minor changes have been made since then, much to my regret.
+To get more involved and stimulate participation in the further
+development of the library, I moved the project source code today to
+[GitHub](https://github.com/schuhschuh/gflags).
+I believe that the strengths of [Git](http://git-scm.com/) will allow for better community collaboration
+as well as ease the integration of changes made by others. I encourage everyone
+who would like to contribute to send me pull requests.
+Git's lightweight feature branches will also provide the right tool for more
+radical changes which should only be merged back into the master branch
+after these are complete and implement the desired behavior.
+
+The SVN repository remains accessible at Google Code and I will keep the
+master branch of the Git repository hosted at GitHub and the trunk of the
+Subversion repository synchronized. Initially, I was going to simply switch the
+Google Code project to Git, but in this case the SVN repository would be
+frozen and force everyone who would like the latest development changes to
+use Git as well. Therefore I decided to host the public Git repository at GitHub
+instead.
+
+Please continue to report any issues with gflags on Google Code. The GitHub project will
+only be used to host the Git repository.
+
+One major change of the project structure I have in mind for the next weeks
+is the migration from autotools to [CMake](http://www.cmake.org/).
+Check out the (unstable!)
+[cmake-migration](https://github.com/schuhschuh/gflags/tree/cmake-migration)
+branch on GitHub for details.
+
+
+25 January 2012
+---------------
+
+I've just released gflags 2.0.
+
+The `google-gflags` project has been renamed to `gflags`. I
+(csilvers) am stepping down as maintainer, to be replaced by Andreas
+Schuh. Welcome to the team, Andreas! I've seen the energy you have
+around gflags and the ideas you have for the project going forward,
+and look forward to having you on the team.
+
+I bumped the major version number up to 2 to reflect the new community
+ownership of the project. All the [changes](ChangeLog.txt)
+are related to the renaming. There are no functional changes from
+gflags 1.7. In particular, I've kept the code in the namespace
+`google`, though in a future version it should be renamed to `gflags`.
+I've also kept the `/usr/local/include/google/` subdirectory as
+synonym of `/usr/local/include/gflags/`, though the former name has
+been obsolete for some time now.
+
+
+18 January 2011
+---------------
+
+The `google-gflags` Google Code page has been renamed to
+`gflags`, in preparation for the project being renamed to
+`gflags`. In the coming weeks, I'll be stepping down as
+maintainer for the gflags project, and as part of that Google is
+relinquishing ownership of the project; it will now be entirely
+community run. The name change reflects that shift.
+
+
+20 December 2011
+----------------
+
+I've just released gflags 1.7. This is a minor release; the major
+change is that `CommandLineFlagInfo` now exports the address in memory
+where the flag is located. There has also been a bugfix involving
+very long --help strings, and some other minor [changes](ChangeLog.txt).
+
+29 July 2011
+------------
+
+I've just released gflags 1.6. The major new feature in this release
+is support for setting version info, so that --version does something
+useful.
+
+One minor change has required bumping the library number:
+`ReparseCommandlineFlags` now returns `void` instead of `int` (the int
+return value was always meaningless). Though I doubt anyone ever used
+this (meaningless) return value, technically it's a change to the ABI
+that requires a version bump. A bit sad.
+
+There's also a procedural change with this release: I've changed the
+internal tools used to integrate Google-supplied patches for gflags
+into the opensource release. These new tools should result in more
+frequent updates with better change descriptions. They will also
+result in future `ChangeLog` entries being much more verbose (for better
+or for worse).
+
+See the [ChangeLog](ChangeLog.txt) for a full list of changes for this release.
+
+24 January 2011
+---------------
+
+I've just released gflags 1.5. This release has only minor changes
+from 1.4, including some slightly better reporting in --help, and
+an new memory-cleanup function that can help when running gflags-using
+libraries under valgrind. The major change is to fix up the macros
+(`DEFINE_bool` and the like) to work more reliably inside namespaces.
+
+If you have not had a problem with these macros, and don't need any of
+the other changes described, there is no need to upgrade. See the
+[ChangeLog](ChangeLog.txt) for a full list of changes for this release.
+
+11 October 2010
+---------------
+
+I've just released gflags 1.4. This release has only minor changes
+from 1.3, including some documentation tweaks and some work to make
+the library smaller. If 1.3 is working well for you, there's no
+particular reason to upgrade.
+
+4 January 2010
+--------------
+
+I've just released gflags 1.3. gflags now compiles under MSVC, and
+all tests pass. I **really** never thought non-unix-y Windows folks
+would want gflags, but at least some of them do.
+
+The major news, though, is that I've separated out the python package
+into its own library, [python-gflags](http://code.google.com/p/python-gflags).
+If you're interested in the Python version of gflags, that's the place to
+get it now.
+
+10 September 2009
+-----------------
+
+I've just released gflags 1.2. The major change from gflags 1.1 is it
+now compiles under MinGW (as well as cygwin), and all tests pass. I
+never thought Windows folks would want unix-style command-line flags,
+since they're so different from the Windows style, but I guess I was
+wrong!
+
+The other changes are minor, such as support for --htmlxml in the
+python version of gflags.
+
+15 April 2009
+-------------
+
+I've just released gflags 1.1. It has only minor changes fdrom gflags
+1.0 (see the [ChangeLog](ChangeLog.txt) for details).
+The major change is that I moved to a new system for creating .deb and .rpm files.
+This allows me to create x86\_64 deb and rpm files.
+
+In the process of moving to this new system, I noticed an
+inconsistency: the tar.gz and .rpm files created libraries named
+libgflags.so, but the deb file created libgoogle-gflags.so. I have
+fixed the deb file to create libraries like the others. I'm no expert
+in debian packaging, but I believe this has caused the package name to
+change as well. Please let me know (at
+[[mailto:google-gflags@googlegroups.com](mailto:google-gflags@googlegroups.com)
+google-gflags@googlegroups.com]) if this causes problems for you --
+especially if you know of a fix! I would be happy to change the deb
+packages to add symlinks from the old library name to the new
+(libgoogle-gflags.so -> libgflags.so), but that is beyond my knowledge
+of how to make .debs.
+
+If you've tried to install a .rpm or .deb and it doesn't work for you,
+let me know. I'm excited to finally have 64-bit package files, but
+there may still be some wrinkles in the new system to iron out.
+
+1 October 2008
+--------------
+
+gflags 1.0rc2 was out for a few weeks without any issues, so gflags
+1.0 is now released. This is much like gflags 0.9. The major change
+is that the .h files have been moved from `/usr/include/google` to
+`/usr/include/gflags`. While I have backwards-compatibility
+forwarding headeds in place, please rewrite existing code to say
+```
+ #include <gflags/gflags.h>
+```
+instead of
+```
+ #include <google/gflags.h>
+```
+
+I've kept the default namespace to google. You can still change with
+with the appropriate flag to the configure script (`./configure
+--help` to see the flags). If you have feedback as to whether the
+default namespace should change to gflags, which would be a
+non-backwards-compatible change, send mail to
+`google-gflags@googlegroups.com`!
+
+Version 1.0 also has some neat new features, like support for bash
+commandline-completion of help flags. See the [ChangeLog](ChangeLog.txt)
+for more details.
+
+If I don't hear any bad news for a few weeks, I'll release 1.0-final.
diff --git a/extern/gflags/src/config.h b/extern/gflags/src/config.h
new file mode 100644
index 00000000000..8d20e222362
--- /dev/null
+++ b/extern/gflags/src/config.h
@@ -0,0 +1,114 @@
+/* Generated from config.h.in during build configuration using CMake. */
+
+// Note: This header file is only used internally. It is not part of public interface!
+
+// ---------------------------------------------------------------------------
+// System checks
+
+// Define if you build this library for a MS Windows OS.
+#ifdef WIN32
+# define OS_WINDOWS
+#endif
+
+// Define if you have the <stdint.h> header file.
+#define HAVE_STDINT_H
+
+// Define if you have the <sys/types.h> header file.
+#define HAVE_SYS_TYPES_H
+
+// Define if you have the <inttypes.h> header file.
+#define HAVE_INTTYPES_H
+
+// Define if you have the <sys/stat.h> header file.
+#define HAVE_SYS_STAT_H
+
+// Define if you have the <unistd.h> header file.
+#define HAVE_UNISTD_H
+
+// Define if you have the <fnmatch.h> header file.
+/* #undef HAVE_FNMATCH_H */
+
+// Define if you have the <shlwapi.h> header file (Windows 2000/XP).
+/* #undef HAVE_SHLWAPI_H */
+
+// Define if you have the strtoll function.
+#define HAVE_STRTOLL
+
+// Define if you have the strtoq function.
+/* #undef HAVE_STRTOQ */
+
+// Define if you have the <pthread.h> header file.
+#define HAVE_PTHREAD
+
+// Define if your pthread library defines the type pthread_rwlock_t
+#define HAVE_RWLOCK
+
+// gcc requires this to get PRId64, etc.
+#if defined(HAVE_INTTYPES_H) && !defined(__STDC_FORMAT_MACROS)
+# define __STDC_FORMAT_MACROS 1
+#endif
+
+// ---------------------------------------------------------------------------
+// Package information
+
+// Name of package.
+#define PACKAGE gflags
+
+// Define to the full name of this package.
+#define PACKAGE_NAME gflags
+
+// Define to the full name and version of this package.
+#define PACKAGE_STRING gflags 2.2.0
+
+// Define to the one symbol short name of this package.
+#define PACKAGE_TARNAME gflags-2.2.0
+
+// Define to the version of this package.
+#define PACKAGE_VERSION 2.2.0
+
+// Version number of package.
+#define VERSION PACKAGE_VERSION
+
+// Define to the address where bug reports for this package should be sent.
+#define PACKAGE_BUGREPORT https://github.com/schuhschuh/gflags/issues
+
+// ---------------------------------------------------------------------------
+// Path separator
+#ifndef PATH_SEPARATOR
+# ifdef OS_WINDOWS
+# define PATH_SEPARATOR '\\'
+# else
+# define PATH_SEPARATOR '/'
+# endif
+#endif
+
+// ---------------------------------------------------------------------------
+// Windows
+
+// Whether gflags library is a DLL.
+#ifndef GFLAGS_IS_A_DLL
+# define GFLAGS_IS_A_DLL 0
+#endif
+
+// Always export symbols when compiling a shared library as this file is only
+// included by internal modules when building the gflags library itself.
+// The gflags_declare.h header file will set it to import these symbols otherwise.
+#ifndef GFLAGS_DLL_DECL
+# if GFLAGS_IS_A_DLL && defined(_MSC_VER)
+# define GFLAGS_DLL_DECL __declspec(dllexport)
+# else
+# define GFLAGS_DLL_DECL
+# endif
+#endif
+// Flags defined by the gflags library itself must be exported
+#ifndef GFLAGS_DLL_DEFINE_FLAG
+# define GFLAGS_DLL_DEFINE_FLAG GFLAGS_DLL_DECL
+#endif
+
+#ifdef OS_WINDOWS
+// The unittests import the symbols of the shared gflags library
+# if GFLAGS_IS_A_DLL && defined(_MSC_VER)
+# define GFLAGS_DLL_DECL_FOR_UNITTESTS __declspec(dllimport)
+# endif
+# include "windows_port.h"
+#endif
diff --git a/extern/gflags/src/gflags.cc b/extern/gflags/src/gflags.cc
new file mode 100644
index 00000000000..7abe1f70da3
--- /dev/null
+++ b/extern/gflags/src/gflags.cc
@@ -0,0 +1,1966 @@
+// Copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Revamped and reorganized by Craig Silverstein
+//
+// This file contains the implementation of all our command line flags
+// stuff. Here's how everything fits together
+//
+// * FlagRegistry owns CommandLineFlags owns FlagValue.
+// * FlagSaver holds a FlagRegistry (saves it at construct time,
+// restores it at destroy time).
+// * CommandLineFlagParser lives outside that hierarchy, but works on
+// CommandLineFlags (modifying the FlagValues).
+// * Free functions like SetCommandLineOption() work via one of the
+// above (such as CommandLineFlagParser).
+//
+// In more detail:
+//
+// -- The main classes that hold flag data:
+//
+// FlagValue holds the current value of a flag. It's
+// pseudo-templatized: every operation on a FlagValue is typed. It
+// also deals with storage-lifetime issues (so flag values don't go
+// away in a destructor), which is why we need a whole class to hold a
+// variable's value.
+//
+// CommandLineFlag is all the information about a single command-line
+// flag. It has a FlagValue for the flag's current value, but also
+// the flag's name, type, etc.
+//
+// FlagRegistry is a collection of CommandLineFlags. There's the
+// global registry, which is where flags defined via DEFINE_foo()
+// live. But it's possible to define your own flag, manually, in a
+// different registry you create. (In practice, multiple registries
+// are used only by FlagSaver).
+//
+// A given FlagValue is owned by exactly one CommandLineFlag. A given
+// CommandLineFlag is owned by exactly one FlagRegistry. FlagRegistry
+// has a lock; any operation that writes to a FlagValue or
+// CommandLineFlag owned by that registry must acquire the
+// FlagRegistry lock before doing so.
+//
+// --- Some other classes and free functions:
+//
+// CommandLineFlagInfo is a client-exposed version of CommandLineFlag.
+// Once it's instantiated, it has no dependencies or relationships
+// with any other part of this file.
+//
+// FlagRegisterer is the helper class used by the DEFINE_* macros to
+// allow work to be done at global initialization time.
+//
+// CommandLineFlagParser is the class that reads from the commandline
+// and instantiates flag values based on that. It needs to poke into
+// the innards of the FlagValue->CommandLineFlag->FlagRegistry class
+// hierarchy to do that. It's careful to acquire the FlagRegistry
+// lock before doing any writing or other non-const actions.
+//
+// GetCommandLineOption is just a hook into registry routines to
+// retrieve a flag based on its name. SetCommandLineOption, on the
+// other hand, hooks into CommandLineFlagParser. Other API functions
+// are, similarly, mostly hooks into the functionality described above.
+
+#include "config.h"
+#include "gflags.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#if defined(HAVE_FNMATCH_H)
+# include <fnmatch.h>
+#elif defined(HAVE_SHLWAPI_H)
+# include <shlwapi.h>
+#endif
+#include <stdarg.h> // For va_list and related operations
+#include <stdio.h>
+#include <string.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility> // for pair<>
+#include <vector>
+
+#include "mutex.h"
+#include "util.h"
+
+using namespace MUTEX_NAMESPACE;
+
+
+// Special flags, type 1: the 'recursive' flags. They set another flag's val.
+DEFINE_string(flagfile, "", "load flags from file");
+DEFINE_string(fromenv, "", "set flags from the environment"
+ " [use 'export FLAGS_flag1=value']");
+DEFINE_string(tryfromenv, "", "set flags from the environment if present");
+
+// Special flags, type 2: the 'parsing' flags. They modify how we parse.
+DEFINE_string(undefok, "", "comma-separated list of flag names that it is okay to specify "
+ "on the command line even if the program does not define a flag "
+ "with that name. IMPORTANT: flags in this list that have "
+ "arguments MUST use the flag=value format");
+
+namespace GFLAGS_NAMESPACE {
+
+using std::map;
+using std::pair;
+using std::sort;
+using std::string;
+using std::vector;
+
+// This is used by the unittest to test error-exit code
+void GFLAGS_DLL_DECL (*gflags_exitfunc)(int) = &exit; // from stdlib.h
+
+
+// The help message indicating that the commandline flag has been
+// 'stripped'. It will not show up when doing "-help" and its
+// variants. The flag is stripped if STRIP_FLAG_HELP is set to 1
+// before including base/gflags.h
+
+// This is used by this file, and also in gflags_reporting.cc
+const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
+
+namespace {
+
+// There are also 'reporting' flags, in gflags_reporting.cc.
+
+static const char kError[] = "ERROR: ";
+
+// Indicates that undefined options are to be ignored.
+// Enables deferred processing of flags in dynamically loaded libraries.
+static bool allow_command_line_reparsing = false;
+
+static bool logging_is_probably_set_up = false;
+
+// This is a 'prototype' validate-function. 'Real' validate
+// functions, take a flag-value as an argument: ValidateFn(bool) or
+// ValidateFn(uint64). However, for easier storage, we strip off this
+// argument and then restore it when actually calling the function on
+// a flag value.
+typedef bool (*ValidateFnProto)();
+
+// Whether we should die when reporting an error.
+enum DieWhenReporting { DIE, DO_NOT_DIE };
+
+// Report Error and exit if requested.
+static void ReportError(DieWhenReporting should_die, const char* format, ...) {
+ char error_message[255];
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(error_message, sizeof(error_message), format, ap);
+ va_end(ap);
+ fprintf(stderr, "%s", error_message);
+ fflush(stderr); // should be unnecessary, but cygwin's rxvt buffers stderr
+ if (should_die == DIE) gflags_exitfunc(1);
+}
+
+
+// --------------------------------------------------------------------
+// FlagValue
+// This represent the value a single flag might have. The major
+// functionality is to convert from a string to an object of a
+// given type, and back. Thread-compatible.
+// --------------------------------------------------------------------
+
+class CommandLineFlag;
+class FlagValue {
+ public:
+ FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value);
+ ~FlagValue();
+
+ bool ParseFrom(const char* spec);
+ string ToString() const;
+
+ private:
+ friend class CommandLineFlag; // for many things, including Validate()
+ friend class GFLAGS_NAMESPACE::FlagSaverImpl; // calls New()
+ friend class FlagRegistry; // checks value_buffer_ for flags_by_ptr_ map
+ template <typename T> friend T GetFromEnv(const char*, const char*, T);
+ friend bool TryParseLocked(const CommandLineFlag*, FlagValue*,
+ const char*, string*); // for New(), CopyFrom()
+
+ enum ValueType {
+ FV_BOOL = 0,
+ FV_INT32 = 1,
+ FV_INT64 = 2,
+ FV_UINT64 = 3,
+ FV_DOUBLE = 4,
+ FV_STRING = 5,
+ FV_MAX_INDEX = 5,
+ };
+ const char* TypeName() const;
+ bool Equal(const FlagValue& x) const;
+ FlagValue* New() const; // creates a new one with default value
+ void CopyFrom(const FlagValue& x);
+ int ValueSize() const;
+
+ // Calls the given validate-fn on value_buffer_, and returns
+ // whatever it returns. But first casts validate_fn_proto to a
+ // function that takes our value as an argument (eg void
+ // (*validate_fn)(bool) for a bool flag).
+ bool Validate(const char* flagname, ValidateFnProto validate_fn_proto) const;
+
+ void* value_buffer_; // points to the buffer holding our data
+ int8 type_; // how to interpret value_
+ bool owns_value_; // whether to free value on destruct
+
+ FlagValue(const FlagValue&); // no copying!
+ void operator=(const FlagValue&);
+};
+
+
+// This could be a templated method of FlagValue, but doing so adds to the
+// size of the .o. Since there's no type-safety here anyway, macro is ok.
+#define VALUE_AS(type) *reinterpret_cast<type*>(value_buffer_)
+#define OTHER_VALUE_AS(fv, type) *reinterpret_cast<type*>(fv.value_buffer_)
+#define SET_VALUE_AS(type, value) VALUE_AS(type) = (value)
+
+FlagValue::FlagValue(void* valbuf, const char* type,
+ bool transfer_ownership_of_value)
+ : value_buffer_(valbuf),
+ owns_value_(transfer_ownership_of_value) {
+ for (type_ = 0; type_ <= FV_MAX_INDEX; ++type_) {
+ if (!strcmp(type, TypeName())) {
+ break;
+ }
+ }
+ assert(type_ <= FV_MAX_INDEX); // Unknown typename
+}
+
+FlagValue::~FlagValue() {
+ if (!owns_value_) {
+ return;
+ }
+ switch (type_) {
+ case FV_BOOL: delete reinterpret_cast<bool*>(value_buffer_); break;
+ case FV_INT32: delete reinterpret_cast<int32*>(value_buffer_); break;
+ case FV_INT64: delete reinterpret_cast<int64*>(value_buffer_); break;
+ case FV_UINT64: delete reinterpret_cast<uint64*>(value_buffer_); break;
+ case FV_DOUBLE: delete reinterpret_cast<double*>(value_buffer_); break;
+ case FV_STRING: delete reinterpret_cast<string*>(value_buffer_); break;
+ }
+}
+
+bool FlagValue::ParseFrom(const char* value) {
+ if (type_ == FV_BOOL) {
+ const char* kTrue[] = { "1", "t", "true", "y", "yes" };
+ const char* kFalse[] = { "0", "f", "false", "n", "no" };
+ COMPILE_ASSERT(sizeof(kTrue) == sizeof(kFalse), true_false_equal);
+ for (size_t i = 0; i < sizeof(kTrue)/sizeof(*kTrue); ++i) {
+ if (strcasecmp(value, kTrue[i]) == 0) {
+ SET_VALUE_AS(bool, true);
+ return true;
+ } else if (strcasecmp(value, kFalse[i]) == 0) {
+ SET_VALUE_AS(bool, false);
+ return true;
+ }
+ }
+ return false; // didn't match a legal input
+
+ } else if (type_ == FV_STRING) {
+ SET_VALUE_AS(string, value);
+ return true;
+ }
+
+ // OK, it's likely to be numeric, and we'll be using a strtoXXX method.
+ if (value[0] == '\0') // empty-string is only allowed for string type.
+ return false;
+ char* end;
+ // Leading 0x puts us in base 16. But leading 0 does not put us in base 8!
+ // It caused too many bugs when we had that behavior.
+ int base = 10; // by default
+ if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X'))
+ base = 16;
+ errno = 0;
+
+ switch (type_) {
+ case FV_INT32: {
+ const int64 r = strto64(value, &end, base);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ if (static_cast<int32>(r) != r) // worked, but number out of range
+ return false;
+ SET_VALUE_AS(int32, static_cast<int32>(r));
+ return true;
+ }
+ case FV_INT64: {
+ const int64 r = strto64(value, &end, base);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ SET_VALUE_AS(int64, r);
+ return true;
+ }
+ case FV_UINT64: {
+ while (*value == ' ') value++;
+ if (*value == '-') return false; // negative number
+ const uint64 r = strtou64(value, &end, base);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ SET_VALUE_AS(uint64, r);
+ return true;
+ }
+ case FV_DOUBLE: {
+ const double r = strtod(value, &end);
+ if (errno || end != value + strlen(value)) return false; // bad parse
+ SET_VALUE_AS(double, r);
+ return true;
+ }
+ default: {
+ assert(false); // unknown type
+ return false;
+ }
+ }
+}
+
+string FlagValue::ToString() const {
+ char intbuf[64]; // enough to hold even the biggest number
+ switch (type_) {
+ case FV_BOOL:
+ return VALUE_AS(bool) ? "true" : "false";
+ case FV_INT32:
+ snprintf(intbuf, sizeof(intbuf), "%" PRId32, VALUE_AS(int32));
+ return intbuf;
+ case FV_INT64:
+ snprintf(intbuf, sizeof(intbuf), "%" PRId64, VALUE_AS(int64));
+ return intbuf;
+ case FV_UINT64:
+ snprintf(intbuf, sizeof(intbuf), "%" PRIu64, VALUE_AS(uint64));
+ return intbuf;
+ case FV_DOUBLE:
+ snprintf(intbuf, sizeof(intbuf), "%.17g", VALUE_AS(double));
+ return intbuf;
+ case FV_STRING:
+ return VALUE_AS(string);
+ default:
+ assert(false);
+ return ""; // unknown type
+ }
+}
+
+bool FlagValue::Validate(const char* flagname,
+ ValidateFnProto validate_fn_proto) const {
+ switch (type_) {
+ case FV_BOOL:
+ return reinterpret_cast<bool (*)(const char*, bool)>(
+ validate_fn_proto)(flagname, VALUE_AS(bool));
+ case FV_INT32:
+ return reinterpret_cast<bool (*)(const char*, int32)>(
+ validate_fn_proto)(flagname, VALUE_AS(int32));
+ case FV_INT64:
+ return reinterpret_cast<bool (*)(const char*, int64)>(
+ validate_fn_proto)(flagname, VALUE_AS(int64));
+ case FV_UINT64:
+ return reinterpret_cast<bool (*)(const char*, uint64)>(
+ validate_fn_proto)(flagname, VALUE_AS(uint64));
+ case FV_DOUBLE:
+ return reinterpret_cast<bool (*)(const char*, double)>(
+ validate_fn_proto)(flagname, VALUE_AS(double));
+ case FV_STRING:
+ return reinterpret_cast<bool (*)(const char*, const string&)>(
+ validate_fn_proto)(flagname, VALUE_AS(string));
+ default:
+ assert(false); // unknown type
+ return false;
+ }
+}
+
+const char* FlagValue::TypeName() const {
+ static const char types[] =
+ "bool\0xx"
+ "int32\0x"
+ "int64\0x"
+ "uint64\0"
+ "double\0"
+ "string";
+ if (type_ > FV_MAX_INDEX) {
+ assert(false);
+ return "";
+ }
+ // Directly indexing the strings in the 'types' string, each of them is 7 bytes long.
+ return &types[type_ * 7];
+}
+
+bool FlagValue::Equal(const FlagValue& x) const {
+ if (type_ != x.type_)
+ return false;
+ switch (type_) {
+ case FV_BOOL: return VALUE_AS(bool) == OTHER_VALUE_AS(x, bool);
+ case FV_INT32: return VALUE_AS(int32) == OTHER_VALUE_AS(x, int32);
+ case FV_INT64: return VALUE_AS(int64) == OTHER_VALUE_AS(x, int64);
+ case FV_UINT64: return VALUE_AS(uint64) == OTHER_VALUE_AS(x, uint64);
+ case FV_DOUBLE: return VALUE_AS(double) == OTHER_VALUE_AS(x, double);
+ case FV_STRING: return VALUE_AS(string) == OTHER_VALUE_AS(x, string);
+ default: assert(false); return false; // unknown type
+ }
+}
+
+FlagValue* FlagValue::New() const {
+ const char *type = TypeName();
+ switch (type_) {
+ case FV_BOOL: return new FlagValue(new bool(false), type, true);
+ case FV_INT32: return new FlagValue(new int32(0), type, true);
+ case FV_INT64: return new FlagValue(new int64(0), type, true);
+ case FV_UINT64: return new FlagValue(new uint64(0), type, true);
+ case FV_DOUBLE: return new FlagValue(new double(0.0), type, true);
+ case FV_STRING: return new FlagValue(new string, type, true);
+ default: assert(false); return NULL; // unknown type
+ }
+}
+
+void FlagValue::CopyFrom(const FlagValue& x) {
+ assert(type_ == x.type_);
+ switch (type_) {
+ case FV_BOOL: SET_VALUE_AS(bool, OTHER_VALUE_AS(x, bool)); break;
+ case FV_INT32: SET_VALUE_AS(int32, OTHER_VALUE_AS(x, int32)); break;
+ case FV_INT64: SET_VALUE_AS(int64, OTHER_VALUE_AS(x, int64)); break;
+ case FV_UINT64: SET_VALUE_AS(uint64, OTHER_VALUE_AS(x, uint64)); break;
+ case FV_DOUBLE: SET_VALUE_AS(double, OTHER_VALUE_AS(x, double)); break;
+ case FV_STRING: SET_VALUE_AS(string, OTHER_VALUE_AS(x, string)); break;
+ default: assert(false); // unknown type
+ }
+}
+
+int FlagValue::ValueSize() const {
+ if (type_ > FV_MAX_INDEX) {
+ assert(false); // unknown type
+ return 0;
+ }
+ static const uint8 valuesize[] = {
+ sizeof(bool),
+ sizeof(int32),
+ sizeof(int64),
+ sizeof(uint64),
+ sizeof(double),
+ sizeof(string),
+ };
+ return valuesize[type_];
+}
+
+// --------------------------------------------------------------------
+// CommandLineFlag
+// This represents a single flag, including its name, description,
+// default value, and current value. Mostly this serves as a
+// struct, though it also knows how to register itself.
+// All CommandLineFlags are owned by a (exactly one)
+// FlagRegistry. If you wish to modify fields in this class, you
+// should acquire the FlagRegistry lock for the registry that owns
+// this flag.
+// --------------------------------------------------------------------
+
+class CommandLineFlag {
+ public:
+ // Note: we take over memory-ownership of current_val and default_val.
+ CommandLineFlag(const char* name, const char* help, const char* filename,
+ FlagValue* current_val, FlagValue* default_val);
+ ~CommandLineFlag();
+
+ const char* name() const { return name_; }
+ const char* help() const { return help_; }
+ const char* filename() const { return file_; }
+ const char* CleanFileName() const; // nixes irrelevant prefix such as homedir
+ string current_value() const { return current_->ToString(); }
+ string default_value() const { return defvalue_->ToString(); }
+ const char* type_name() const { return defvalue_->TypeName(); }
+ ValidateFnProto validate_function() const { return validate_fn_proto_; }
+ const void* flag_ptr() const { return current_->value_buffer_; }
+
+ void FillCommandLineFlagInfo(struct CommandLineFlagInfo* result);
+
+ // If validate_fn_proto_ is non-NULL, calls it on value, returns result.
+ bool Validate(const FlagValue& value) const;
+ bool ValidateCurrent() const { return Validate(*current_); }
+
+ private:
+ // for SetFlagLocked() and setting flags_by_ptr_
+ friend class FlagRegistry;
+ friend class GFLAGS_NAMESPACE::FlagSaverImpl; // for cloning the values
+ // set validate_fn
+ friend bool AddFlagValidator(const void*, ValidateFnProto);
+
+ // This copies all the non-const members: modified, processed, defvalue, etc.
+ void CopyFrom(const CommandLineFlag& src);
+
+ void UpdateModifiedBit();
+
+ const char* const name_; // Flag name
+ const char* const help_; // Help message
+ const char* const file_; // Which file did this come from?
+ bool modified_; // Set after default assignment?
+ FlagValue* defvalue_; // Default value for flag
+ FlagValue* current_; // Current value for flag
+ // This is a casted, 'generic' version of validate_fn, which actually
+ // takes a flag-value as an arg (void (*validate_fn)(bool), say).
+ // When we pass this to current_->Validate(), it will cast it back to
+ // the proper type. This may be NULL to mean we have no validate_fn.
+ ValidateFnProto validate_fn_proto_;
+
+ CommandLineFlag(const CommandLineFlag&); // no copying!
+ void operator=(const CommandLineFlag&);
+};
+
+CommandLineFlag::CommandLineFlag(const char* name, const char* help,
+ const char* filename,
+ FlagValue* current_val, FlagValue* default_val)
+ : name_(name), help_(help), file_(filename), modified_(false),
+ defvalue_(default_val), current_(current_val), validate_fn_proto_(NULL) {
+}
+
+CommandLineFlag::~CommandLineFlag() {
+ delete current_;
+ delete defvalue_;
+}
+
+const char* CommandLineFlag::CleanFileName() const {
+ // Compute top-level directory & file that this appears in
+ // search full path backwards.
+ // Stop going backwards at kRootDir; and skip by the first slash.
+ static const char kRootDir[] = ""; // can set this to root directory,
+
+ if (sizeof(kRootDir)-1 == 0) // no prefix to strip
+ return filename();
+
+ const char* clean_name = filename() + strlen(filename()) - 1;
+ while ( clean_name > filename() ) {
+ if (*clean_name == PATH_SEPARATOR) {
+ if (strncmp(clean_name, kRootDir, sizeof(kRootDir)-1) == 0) {
+ clean_name += sizeof(kRootDir)-1; // past root-dir
+ break;
+ }
+ }
+ --clean_name;
+ }
+ while ( *clean_name == PATH_SEPARATOR ) ++clean_name; // Skip any slashes
+ return clean_name;
+}
+
+void CommandLineFlag::FillCommandLineFlagInfo(
+ CommandLineFlagInfo* result) {
+ result->name = name();
+ result->type = type_name();
+ result->description = help();
+ result->current_value = current_value();
+ result->default_value = default_value();
+ result->filename = CleanFileName();
+ UpdateModifiedBit();
+ result->is_default = !modified_;
+ result->has_validator_fn = validate_function() != NULL;
+ result->flag_ptr = flag_ptr();
+}
+
+void CommandLineFlag::UpdateModifiedBit() {
+ // Update the "modified" bit in case somebody bypassed the
+ // Flags API and wrote directly through the FLAGS_name variable.
+ if (!modified_ && !current_->Equal(*defvalue_)) {
+ modified_ = true;
+ }
+}
+
+void CommandLineFlag::CopyFrom(const CommandLineFlag& src) {
+ // Note we only copy the non-const members; others are fixed at construct time
+ if (modified_ != src.modified_) modified_ = src.modified_;
+ if (!current_->Equal(*src.current_)) current_->CopyFrom(*src.current_);
+ if (!defvalue_->Equal(*src.defvalue_)) defvalue_->CopyFrom(*src.defvalue_);
+ if (validate_fn_proto_ != src.validate_fn_proto_)
+ validate_fn_proto_ = src.validate_fn_proto_;
+}
+
+bool CommandLineFlag::Validate(const FlagValue& value) const {
+
+ if (validate_function() == NULL)
+ return true;
+ else
+ return value.Validate(name(), validate_function());
+}
+
+
+// --------------------------------------------------------------------
+// FlagRegistry
+// A FlagRegistry singleton object holds all flag objects indexed
+// by their names so that if you know a flag's name (as a C
+// string), you can access or set it. If the function is named
+// FooLocked(), you must own the registry lock before calling
+// the function; otherwise, you should *not* hold the lock, and
+// the function will acquire it itself if needed.
+// --------------------------------------------------------------------
+
+struct StringCmp { // Used by the FlagRegistry map class to compare char*'s
+ bool operator() (const char* s1, const char* s2) const {
+ return (strcmp(s1, s2) < 0);
+ }
+};
+
+
+class FlagRegistry {
+ public:
+ FlagRegistry() {
+ }
+ ~FlagRegistry() {
+ // Not using STLDeleteElements as that resides in util and this
+ // class is base.
+ for (FlagMap::iterator p = flags_.begin(), e = flags_.end(); p != e; ++p) {
+ CommandLineFlag* flag = p->second;
+ delete flag;
+ }
+ }
+
+ static void DeleteGlobalRegistry() {
+ delete global_registry_;
+ global_registry_ = NULL;
+ }
+
+ // Store a flag in this registry. Takes ownership of the given pointer.
+ void RegisterFlag(CommandLineFlag* flag);
+
+ void Lock() { lock_.Lock(); }
+ void Unlock() { lock_.Unlock(); }
+
+ // Returns the flag object for the specified name, or NULL if not found.
+ CommandLineFlag* FindFlagLocked(const char* name);
+
+ // Returns the flag object whose current-value is stored at flag_ptr.
+ // That is, for whom current_->value_buffer_ == flag_ptr
+ CommandLineFlag* FindFlagViaPtrLocked(const void* flag_ptr);
+
+ // A fancier form of FindFlag that works correctly if name is of the
+ // form flag=value. In that case, we set key to point to flag, and
+ // modify v to point to the value (if present), and return the flag
+ // with the given name. If the flag does not exist, returns NULL
+ // and sets error_message.
+ CommandLineFlag* SplitArgumentLocked(const char* argument,
+ string* key, const char** v,
+ string* error_message);
+
+ // Set the value of a flag. If the flag was successfully set to
+ // value, set msg to indicate the new flag-value, and return true.
+ // Otherwise, set msg to indicate the error, leave flag unchanged,
+ // and return false. msg can be NULL.
+ bool SetFlagLocked(CommandLineFlag* flag, const char* value,
+ FlagSettingMode set_mode, string* msg);
+
+ static FlagRegistry* GlobalRegistry(); // returns a singleton registry
+
+ private:
+ friend class GFLAGS_NAMESPACE::FlagSaverImpl; // reads all the flags in order to copy them
+ friend class CommandLineFlagParser; // for ValidateAllFlags
+ friend void GFLAGS_NAMESPACE::GetAllFlags(vector<CommandLineFlagInfo>*);
+
+ // The map from name to flag, for FindFlagLocked().
+ typedef map<const char*, CommandLineFlag*, StringCmp> FlagMap;
+ typedef FlagMap::iterator FlagIterator;
+ typedef FlagMap::const_iterator FlagConstIterator;
+ FlagMap flags_;
+
+ // The map from current-value pointer to flag, fo FindFlagViaPtrLocked().
+ typedef map<const void*, CommandLineFlag*> FlagPtrMap;
+ FlagPtrMap flags_by_ptr_;
+
+ static FlagRegistry* global_registry_; // a singleton registry
+
+ Mutex lock_;
+ static Mutex global_registry_lock_;
+
+ static void InitGlobalRegistry();
+
+ // Disallow
+ FlagRegistry(const FlagRegistry&);
+ FlagRegistry& operator=(const FlagRegistry&);
+};
+
+class FlagRegistryLock {
+ public:
+ explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); }
+ ~FlagRegistryLock() { fr_->Unlock(); }
+ private:
+ FlagRegistry *const fr_;
+};
+
+
+void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
+ Lock();
+ pair<FlagIterator, bool> ins =
+ flags_.insert(pair<const char*, CommandLineFlag*>(flag->name(), flag));
+ if (ins.second == false) { // means the name was already in the map
+ if (strcmp(ins.first->second->filename(), flag->filename()) != 0) {
+ ReportError(DIE, "ERROR: flag '%s' was defined more than once "
+ "(in files '%s' and '%s').\n",
+ flag->name(),
+ ins.first->second->filename(),
+ flag->filename());
+ } else {
+ ReportError(DIE, "ERROR: something wrong with flag '%s' in file '%s'. "
+ "One possibility: file '%s' is being linked both statically "
+ "and dynamically into this executable.\n",
+ flag->name(),
+ flag->filename(), flag->filename());
+ }
+ }
+ // Also add to the flags_by_ptr_ map.
+ flags_by_ptr_[flag->current_->value_buffer_] = flag;
+ Unlock();
+}
+
+CommandLineFlag* FlagRegistry::FindFlagLocked(const char* name) {
+ FlagConstIterator i = flags_.find(name);
+ if (i == flags_.end()) {
+ return NULL;
+ } else {
+ return i->second;
+ }
+}
+
+CommandLineFlag* FlagRegistry::FindFlagViaPtrLocked(const void* flag_ptr) {
+ FlagPtrMap::const_iterator i = flags_by_ptr_.find(flag_ptr);
+ if (i == flags_by_ptr_.end()) {
+ return NULL;
+ } else {
+ return i->second;
+ }
+}
+
+CommandLineFlag* FlagRegistry::SplitArgumentLocked(const char* arg,
+ string* key,
+ const char** v,
+ string* error_message) {
+ // Find the flag object for this option
+ const char* flag_name;
+ const char* value = strchr(arg, '=');
+ if (value == NULL) {
+ key->assign(arg);
+ *v = NULL;
+ } else {
+ // Strip out the "=value" portion from arg
+ key->assign(arg, value-arg);
+ *v = ++value; // advance past the '='
+ }
+ flag_name = key->c_str();
+
+ CommandLineFlag* flag = FindFlagLocked(flag_name);
+
+ if (flag == NULL) {
+ // If we can't find the flag-name, then we should return an error.
+ // The one exception is if 1) the flag-name is 'nox', 2) there
+ // exists a flag named 'x', and 3) 'x' is a boolean flag.
+ // In that case, we want to return flag 'x'.
+ if (!(flag_name[0] == 'n' && flag_name[1] == 'o')) {
+ // flag-name is not 'nox', so we're not in the exception case.
+ *error_message = StringPrintf("%sunknown command line flag '%s'\n",
+ kError, key->c_str());
+ return NULL;
+ }
+ flag = FindFlagLocked(flag_name+2);
+ if (flag == NULL) {
+ // No flag named 'x' exists, so we're not in the exception case.
+ *error_message = StringPrintf("%sunknown command line flag '%s'\n",
+ kError, key->c_str());
+ return NULL;
+ }
+ if (strcmp(flag->type_name(), "bool") != 0) {
+ // 'x' exists but is not boolean, so we're not in the exception case.
+ *error_message = StringPrintf(
+ "%sboolean value (%s) specified for %s command line flag\n",
+ kError, key->c_str(), flag->type_name());
+ return NULL;
+ }
+ // We're in the exception case!
+ // Make up a fake value to replace the "no" we stripped out
+ key->assign(flag_name+2); // the name without the "no"
+ *v = "0";
+ }
+
+ // Assign a value if this is a boolean flag
+ if (*v == NULL && strcmp(flag->type_name(), "bool") == 0) {
+ *v = "1"; // the --nox case was already handled, so this is the --x case
+ }
+
+ return flag;
+}
+
+bool TryParseLocked(const CommandLineFlag* flag, FlagValue* flag_value,
+ const char* value, string* msg) {
+ // Use tenative_value, not flag_value, until we know value is valid.
+ FlagValue* tentative_value = flag_value->New();
+ if (!tentative_value->ParseFrom(value)) {
+ if (msg) {
+ StringAppendF(msg,
+ "%sillegal value '%s' specified for %s flag '%s'\n",
+ kError, value,
+ flag->type_name(), flag->name());
+ }
+ delete tentative_value;
+ return false;
+ } else if (!flag->Validate(*tentative_value)) {
+ if (msg) {
+ StringAppendF(msg,
+ "%sfailed validation of new value '%s' for flag '%s'\n",
+ kError, tentative_value->ToString().c_str(),
+ flag->name());
+ }
+ delete tentative_value;
+ return false;
+ } else {
+ flag_value->CopyFrom(*tentative_value);
+ if (msg) {
+ StringAppendF(msg, "%s set to %s\n",
+ flag->name(), flag_value->ToString().c_str());
+ }
+ delete tentative_value;
+ return true;
+ }
+}
+
+bool FlagRegistry::SetFlagLocked(CommandLineFlag* flag,
+ const char* value,
+ FlagSettingMode set_mode,
+ string* msg) {
+ flag->UpdateModifiedBit();
+ switch (set_mode) {
+ case SET_FLAGS_VALUE: {
+ // set or modify the flag's value
+ if (!TryParseLocked(flag, flag->current_, value, msg))
+ return false;
+ flag->modified_ = true;
+ break;
+ }
+ case SET_FLAG_IF_DEFAULT: {
+ // set the flag's value, but only if it hasn't been set by someone else
+ if (!flag->modified_) {
+ if (!TryParseLocked(flag, flag->current_, value, msg))
+ return false;
+ flag->modified_ = true;
+ } else {
+ *msg = StringPrintf("%s set to %s",
+ flag->name(), flag->current_value().c_str());
+ }
+ break;
+ }
+ case SET_FLAGS_DEFAULT: {
+ // modify the flag's default-value
+ if (!TryParseLocked(flag, flag->defvalue_, value, msg))
+ return false;
+ if (!flag->modified_) {
+ // Need to set both defvalue *and* current, in this case
+ TryParseLocked(flag, flag->current_, value, NULL);
+ }
+ break;
+ }
+ default: {
+ // unknown set_mode
+ assert(false);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Get the singleton FlagRegistry object
+FlagRegistry* FlagRegistry::global_registry_ = NULL;
+Mutex FlagRegistry::global_registry_lock_(Mutex::LINKER_INITIALIZED);
+
+FlagRegistry* FlagRegistry::GlobalRegistry() {
+ if (GetArgvSum() != 0) {
+ MutexLock acquire_lock(&global_registry_lock_);
+ if (!global_registry_) {
+ global_registry_ = new FlagRegistry;
+ }
+ } else {
+ if (!global_registry_) {
+ global_registry_ = new FlagRegistry;
+ }
+ }
+ return global_registry_;
+}
+
+// --------------------------------------------------------------------
+// CommandLineFlagParser
+// Parsing is done in two stages. In the first, we go through
+// argv. For every flag-like arg we can make sense of, we parse
+// it and set the appropriate FLAGS_* variable. For every flag-
+// like arg we can't make sense of, we store it in a vector,
+// along with an explanation of the trouble. In stage 2, we
+// handle the 'reporting' flags like --help and --mpm_version.
+// (This is via a call to HandleCommandLineHelpFlags(), in
+// gflags_reporting.cc.)
+// An optional stage 3 prints out the error messages.
+// This is a bit of a simplification. For instance, --flagfile
+// is handled as soon as it's seen in stage 1, not in stage 2.
+// --------------------------------------------------------------------
+
+class CommandLineFlagParser {
+ public:
+ // The argument is the flag-registry to register the parsed flags in
+ explicit CommandLineFlagParser(FlagRegistry* reg) : registry_(reg) {}
+ ~CommandLineFlagParser() {}
+
+ // Stage 1: Every time this is called, it reads all flags in argv.
+ // However, it ignores all flags that have been successfully set
+ // before. Typically this is only called once, so this 'reparsing'
+ // behavior isn't important. It can be useful when trying to
+ // reparse after loading a dll, though.
+ uint32 ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags);
+
+ // Stage 2: print reporting info and exit, if requested.
+ // In gflags_reporting.cc:HandleCommandLineHelpFlags().
+
+ // Stage 3: validate all the commandline flags that have validators
+ // registered.
+ void ValidateAllFlags();
+
+ // Stage 4: report any errors and return true if any were found.
+ bool ReportErrors();
+
+ // Set a particular command line option. "newval" is a string
+ // describing the new value that the option has been set to. If
+ // option_name does not specify a valid option name, or value is not
+ // a valid value for option_name, newval is empty. Does recursive
+ // processing for --flagfile and --fromenv. Returns the new value
+ // if everything went ok, or empty-string if not. (Actually, the
+ // return-string could hold many flag/value pairs due to --flagfile.)
+ // NB: Must have called registry_->Lock() before calling this function.
+ string ProcessSingleOptionLocked(CommandLineFlag* flag,
+ const char* value,
+ FlagSettingMode set_mode);
+
+ // Set a whole batch of command line options as specified by contentdata,
+ // which is in flagfile format (and probably has been read from a flagfile).
+ // Returns the new value if everything went ok, or empty-string if
+ // not. (Actually, the return-string could hold many flag/value
+ // pairs due to --flagfile.)
+ // NB: Must have called registry_->Lock() before calling this function.
+ string ProcessOptionsFromStringLocked(const string& contentdata,
+ FlagSettingMode set_mode);
+
+ // These are the 'recursive' flags, defined at the top of this file.
+ // Whenever we see these flags on the commandline, we must take action.
+ // These are called by ProcessSingleOptionLocked and, similarly, return
+ // new values if everything went ok, or the empty-string if not.
+ string ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode);
+ // diff fromenv/tryfromenv
+ string ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode,
+ bool errors_are_fatal);
+
+ private:
+ FlagRegistry* const registry_;
+ map<string, string> error_flags_; // map from name to error message
+ // This could be a set<string>, but we reuse the map to minimize the .o size
+ map<string, string> undefined_names_; // --[flag] name was not registered
+};
+
+
+// Parse a list of (comma-separated) flags.
+static void ParseFlagList(const char* value, vector<string>* flags) {
+ for (const char *p = value; p && *p; value = p) {
+ p = strchr(value, ',');
+ size_t len;
+ if (p) {
+ len = p - value;
+ p++;
+ } else {
+ len = strlen(value);
+ }
+
+ if (len == 0)
+ ReportError(DIE, "ERROR: empty flaglist entry\n");
+ if (value[0] == '-')
+ ReportError(DIE, "ERROR: flag \"%*s\" begins with '-'\n", len, value);
+
+ flags->push_back(string(value, len));
+ }
+}
+
+// Snarf an entire file into a C++ string. This is just so that we
+// can do all the I/O in one place and not worry about it everywhere.
+// Plus, it's convenient to have the whole file contents at hand.
+// Adds a newline at the end of the file.
+#define PFATAL(s) do { perror(s); gflags_exitfunc(1); } while (0)
+
+static string ReadFileIntoString(const char* filename) {
+ const int kBufSize = 8092;
+ char buffer[kBufSize];
+ string s;
+ FILE* fp;
+ if ((errno = SafeFOpen(&fp, filename, "r")) != 0) PFATAL(filename);
+ size_t n;
+ while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) {
+ if (ferror(fp)) PFATAL(filename);
+ s.append(buffer, n);
+ }
+ fclose(fp);
+ return s;
+}
+
+uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv,
+ bool remove_flags) {
+ const char *program_name = strrchr((*argv)[0], PATH_SEPARATOR); // nix path
+ program_name = (program_name == NULL ? (*argv)[0] : program_name+1);
+
+ int first_nonopt = *argc; // for non-options moved to the end
+
+ registry_->Lock();
+ for (int i = 1; i < first_nonopt; i++) {
+ char* arg = (*argv)[i];
+
+ // Like getopt(), we permute non-option flags to be at the end.
+ if (arg[0] != '-' || // must be a program argument
+ (arg[0] == '-' && arg[1] == '\0')) { // "-" is an argument, not a flag
+ memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i]));
+ (*argv)[*argc-1] = arg; // we go last
+ first_nonopt--; // we've been pushed onto the stack
+ i--; // to undo the i++ in the loop
+ continue;
+ }
+
+ if (arg[0] == '-') arg++; // allow leading '-'
+ if (arg[0] == '-') arg++; // or leading '--'
+
+ // -- alone means what it does for GNU: stop options parsing
+ if (*arg == '\0') {
+ first_nonopt = i+1;
+ break;
+ }
+
+ // Find the flag object for this option
+ string key;
+ const char* value;
+ string error_message;
+ CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value,
+ &error_message);
+ if (flag == NULL) {
+ undefined_names_[key] = ""; // value isn't actually used
+ error_flags_[key] = error_message;
+ continue;
+ }
+
+ if (value == NULL) {
+ // Boolean options are always assigned a value by SplitArgumentLocked()
+ assert(strcmp(flag->type_name(), "bool") != 0);
+ if (i+1 >= first_nonopt) {
+ // This flag needs a value, but there is nothing available
+ error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'"
+ + " is missing its argument");
+ if (flag->help() && flag->help()[0] > '\001') {
+ // Be useful in case we have a non-stripped description.
+ error_flags_[key] += string("; flag description: ") + flag->help();
+ }
+ error_flags_[key] += "\n";
+ break; // we treat this as an unrecoverable error
+ } else {
+ value = (*argv)[++i]; // read next arg for value
+
+ // Heuristic to detect the case where someone treats a string arg
+ // like a bool:
+ // --my_string_var --foo=bar
+ // We look for a flag of string type, whose value begins with a
+ // dash, and where the flag-name and value are separated by a
+ // space rather than an '='.
+ // To avoid false positives, we also require the word "true"
+ // or "false" in the help string. Without this, a valid usage
+ // "-lat -30.5" would trigger the warning. The common cases we
+ // want to solve talk about true and false as values.
+ if (value[0] == '-'
+ && strcmp(flag->type_name(), "string") == 0
+ && (strstr(flag->help(), "true")
+ || strstr(flag->help(), "false"))) {
+ LOG(WARNING) << "Did you really mean to set flag '"
+ << flag->name() << "' to the value '"
+ << value << "'?";
+ }
+ }
+ }
+
+ // TODO(csilvers): only set a flag if we hadn't set it before here
+ ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE);
+ }
+ registry_->Unlock();
+
+ if (remove_flags) { // Fix up argc and argv by removing command line flags
+ (*argv)[first_nonopt-1] = (*argv)[0];
+ (*argv) += (first_nonopt-1);
+ (*argc) -= (first_nonopt-1);
+ first_nonopt = 1; // because we still don't count argv[0]
+ }
+
+ logging_is_probably_set_up = true; // because we've parsed --logdir, etc.
+
+ return first_nonopt;
+}
+
+string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval,
+ FlagSettingMode set_mode) {
+ if (flagval.empty())
+ return "";
+
+ string msg;
+ vector<string> filename_list;
+ ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames
+ for (size_t i = 0; i < filename_list.size(); ++i) {
+ const char* file = filename_list[i].c_str();
+ msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode);
+ }
+ return msg;
+}
+
+string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
+ FlagSettingMode set_mode,
+ bool errors_are_fatal) {
+ if (flagval.empty())
+ return "";
+
+ string msg;
+ vector<string> flaglist;
+ ParseFlagList(flagval.c_str(), &flaglist);
+
+ for (size_t i = 0; i < flaglist.size(); ++i) {
+ const char* flagname = flaglist[i].c_str();
+ CommandLineFlag* flag = registry_->FindFlagLocked(flagname);
+ if (flag == NULL) {
+ error_flags_[flagname] =
+ StringPrintf("%sunknown command line flag '%s' "
+ "(via --fromenv or --tryfromenv)\n",
+ kError, flagname);
+ undefined_names_[flagname] = "";
+ continue;
+ }
+
+ const string envname = string("FLAGS_") + string(flagname);
+ string envval;
+ if (!SafeGetEnv(envname.c_str(), envval)) {
+ if (errors_are_fatal) {
+ error_flags_[flagname] = (string(kError) + envname +
+ " not found in environment\n");
+ }
+ continue;
+ }
+
+ // Avoid infinite recursion.
+ if (envval == "fromenv" || envval == "tryfromenv") {
+ error_flags_[flagname] =
+ StringPrintf("%sinfinite recursion on environment flag '%s'\n",
+ kError, envval.c_str());
+ continue;
+ }
+
+ msg += ProcessSingleOptionLocked(flag, envval.c_str(), set_mode);
+ }
+ return msg;
+}
+
+string CommandLineFlagParser::ProcessSingleOptionLocked(
+ CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) {
+ string msg;
+ if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) {
+ error_flags_[flag->name()] = msg;
+ return "";
+ }
+
+ // The recursive flags, --flagfile and --fromenv and --tryfromenv,
+ // must be dealt with as soon as they're seen. They will emit
+ // messages of their own.
+ if (strcmp(flag->name(), "flagfile") == 0) {
+ msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode);
+
+ } else if (strcmp(flag->name(), "fromenv") == 0) {
+ // last arg indicates envval-not-found is fatal (unlike in --tryfromenv)
+ msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true);
+
+ } else if (strcmp(flag->name(), "tryfromenv") == 0) {
+ msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false);
+ }
+
+ return msg;
+}
+
+void CommandLineFlagParser::ValidateAllFlags() {
+ FlagRegistryLock frl(registry_);
+ for (FlagRegistry::FlagConstIterator i = registry_->flags_.begin();
+ i != registry_->flags_.end(); ++i) {
+ if (!i->second->ValidateCurrent()) {
+ // only set a message if one isn't already there. (If there's
+ // an error message, our job is done, even if it's not exactly
+ // the same error.)
+ if (error_flags_[i->second->name()].empty())
+ error_flags_[i->second->name()] =
+ string(kError) + "--" + i->second->name() +
+ " must be set on the commandline"
+ " (default value fails validation)\n";
+ }
+ }
+}
+
+bool CommandLineFlagParser::ReportErrors() {
+ // error_flags_ indicates errors we saw while parsing.
+ // But we ignore undefined-names if ok'ed by --undef_ok
+ if (!FLAGS_undefok.empty()) {
+ vector<string> flaglist;
+ ParseFlagList(FLAGS_undefok.c_str(), &flaglist);
+ for (size_t i = 0; i < flaglist.size(); ++i) {
+ // We also deal with --no<flag>, in case the flagname was boolean
+ const string no_version = string("no") + flaglist[i];
+ if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) {
+ error_flags_[flaglist[i]] = ""; // clear the error message
+ } else if (undefined_names_.find(no_version) != undefined_names_.end()) {
+ error_flags_[no_version] = "";
+ }
+ }
+ }
+ // Likewise, if they decided to allow reparsing, all undefined-names
+ // are ok; we just silently ignore them now, and hope that a future
+ // parse will pick them up somehow.
+ if (allow_command_line_reparsing) {
+ for (map<string, string>::const_iterator it = undefined_names_.begin();
+ it != undefined_names_.end(); ++it)
+ error_flags_[it->first] = ""; // clear the error message
+ }
+
+ bool found_error = false;
+ string error_message;
+ for (map<string, string>::const_iterator it = error_flags_.begin();
+ it != error_flags_.end(); ++it) {
+ if (!it->second.empty()) {
+ error_message.append(it->second.data(), it->second.size());
+ found_error = true;
+ }
+ }
+ if (found_error)
+ ReportError(DO_NOT_DIE, "%s", error_message.c_str());
+ return found_error;
+}
+
+string CommandLineFlagParser::ProcessOptionsFromStringLocked(
+ const string& contentdata, FlagSettingMode set_mode) {
+ string retval;
+ const char* flagfile_contents = contentdata.c_str();
+ bool flags_are_relevant = true; // set to false when filenames don't match
+ bool in_filename_section = false;
+
+ const char* line_end = flagfile_contents;
+ // We read this file a line at a time.
+ for (; line_end; flagfile_contents = line_end + 1) {
+ while (*flagfile_contents && isspace(*flagfile_contents))
+ ++flagfile_contents;
+ line_end = strchr(flagfile_contents, '\n');
+ size_t len = line_end ? line_end - flagfile_contents
+ : strlen(flagfile_contents);
+ string line(flagfile_contents, len);
+
+ // Each line can be one of four things:
+ // 1) A comment line -- we skip it
+ // 2) An empty line -- we skip it
+ // 3) A list of filenames -- starts a new filenames+flags section
+ // 4) A --flag=value line -- apply if previous filenames match
+ if (line.empty() || line[0] == '#') {
+ // comment or empty line; just ignore
+
+ } else if (line[0] == '-') { // flag
+ in_filename_section = false; // instead, it was a flag-line
+ if (!flags_are_relevant) // skip this flag; applies to someone else
+ continue;
+
+ const char* name_and_val = line.c_str() + 1; // skip the leading -
+ if (*name_and_val == '-')
+ name_and_val++; // skip second - too
+ string key;
+ const char* value;
+ string error_message;
+ CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val,
+ &key, &value,
+ &error_message);
+ // By API, errors parsing flagfile lines are silently ignored.
+ if (flag == NULL) {
+ // "WARNING: flagname '" + key + "' not found\n"
+ } else if (value == NULL) {
+ // "WARNING: flagname '" + key + "' missing a value\n"
+ } else {
+ retval += ProcessSingleOptionLocked(flag, value, set_mode);
+ }
+
+ } else { // a filename!
+ if (!in_filename_section) { // start over: assume filenames don't match
+ in_filename_section = true;
+ flags_are_relevant = false;
+ }
+
+ // Split the line up at spaces into glob-patterns
+ const char* space = line.c_str(); // just has to be non-NULL
+ for (const char* word = line.c_str(); *space; word = space+1) {
+ if (flags_are_relevant) // we can stop as soon as we match
+ break;
+ space = strchr(word, ' ');
+ if (space == NULL)
+ space = word + strlen(word);
+ const string glob(word, space - word);
+ // We try matching both against the full argv0 and basename(argv0)
+ if (glob == ProgramInvocationName() // small optimization
+ || glob == ProgramInvocationShortName()
+#if defined(HAVE_FNMATCH_H)
+ || fnmatch(glob.c_str(), ProgramInvocationName(), FNM_PATHNAME) == 0
+ || fnmatch(glob.c_str(), ProgramInvocationShortName(), FNM_PATHNAME) == 0
+#elif defined(HAVE_SHLWAPI_H)
+ || PathMatchSpec(glob.c_str(), ProgramInvocationName())
+ || PathMatchSpec(glob.c_str(), ProgramInvocationShortName())
+#endif
+ ) {
+ flags_are_relevant = true;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+// --------------------------------------------------------------------
+// GetFromEnv()
+// AddFlagValidator()
+// These are helper functions for routines like BoolFromEnv() and
+// RegisterFlagValidator, defined below. They're defined here so
+// they can live in the unnamed namespace (which makes friendship
+// declarations for these classes possible).
+// --------------------------------------------------------------------
+
+template<typename T>
+T GetFromEnv(const char *varname, const char* type, T dflt) {
+ std::string valstr;
+ if (SafeGetEnv(varname, valstr)) {
+ FlagValue ifv(new T, type, true);
+ if (!ifv.ParseFrom(valstr.c_str())) {
+ ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n",
+ varname, valstr.c_str());
+ }
+ return OTHER_VALUE_AS(ifv, T);
+ } else return dflt;
+}
+
+bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
+ // We want a lock around this routine, in case two threads try to
+ // add a validator (hopefully the same one!) at once. We could use
+ // our own thread, but we need to loook at the registry anyway, so
+ // we just steal that one.
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ // First, find the flag whose current-flag storage is 'flag'.
+ // This is the CommandLineFlag whose current_->value_buffer_ == flag
+ CommandLineFlag* flag = registry->FindFlagViaPtrLocked(flag_ptr);
+ if (!flag) {
+ LOG(WARNING) << "Ignoring RegisterValidateFunction() for flag pointer "
+ << flag_ptr << ": no flag found at that address";
+ return false;
+ } else if (validate_fn_proto == flag->validate_function()) {
+ return true; // ok to register the same function over and over again
+ } else if (validate_fn_proto != NULL && flag->validate_function() != NULL) {
+ LOG(WARNING) << "Ignoring RegisterValidateFunction() for flag '"
+ << flag->name() << "': validate-fn already registered";
+ return false;
+ } else {
+ flag->validate_fn_proto_ = validate_fn_proto;
+ return true;
+ }
+}
+
+} // end unnamed namespaces
+
+
+// Now define the functions that are exported via the .h file
+
+// --------------------------------------------------------------------
+// FlagRegisterer
+// This class exists merely to have a global constructor (the
+// kind that runs before main(), that goes an initializes each
+// flag that's been declared. Note that it's very important we
+// don't have a destructor that deletes flag_, because that would
+// cause us to delete current_storage/defvalue_storage as well,
+// which can cause a crash if anything tries to access the flag
+// values in a global destructor.
+// --------------------------------------------------------------------
+
+FlagRegisterer::FlagRegisterer(const char* name, const char* type,
+ const char* help, const char* filename,
+ void* current_storage, void* defvalue_storage) {
+ if (help == NULL)
+ help = "";
+ // FlagValue expects the type-name to not include any namespace
+ // components, so we get rid of those, if any.
+ if (strchr(type, ':'))
+ type = strrchr(type, ':') + 1;
+ FlagValue* current = new FlagValue(current_storage, type, false);
+ FlagValue* defvalue = new FlagValue(defvalue_storage, type, false);
+ // Importantly, flag_ will never be deleted, so storage is always good.
+ CommandLineFlag* flag = new CommandLineFlag(name, help, filename,
+ current, defvalue);
+ FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry
+}
+
+// --------------------------------------------------------------------
+// GetAllFlags()
+// The main way the FlagRegistry class exposes its data. This
+// returns, as strings, all the info about all the flags in
+// the main registry, sorted first by filename they are defined
+// in, and then by flagname.
+// --------------------------------------------------------------------
+
+struct FilenameFlagnameCmp {
+ bool operator()(const CommandLineFlagInfo& a,
+ const CommandLineFlagInfo& b) const {
+ int cmp = strcmp(a.filename.c_str(), b.filename.c_str());
+ if (cmp == 0)
+ cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key
+ return cmp < 0;
+ }
+};
+
+void GetAllFlags(vector<CommandLineFlagInfo>* OUTPUT) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ registry->Lock();
+ for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
+ i != registry->flags_.end(); ++i) {
+ CommandLineFlagInfo fi;
+ i->second->FillCommandLineFlagInfo(&fi);
+ OUTPUT->push_back(fi);
+ }
+ registry->Unlock();
+ // Now sort the flags, first by filename they occur in, then alphabetically
+ sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp());
+}
+
+// --------------------------------------------------------------------
+// SetArgv()
+// GetArgvs()
+// GetArgv()
+// GetArgv0()
+// ProgramInvocationName()
+// ProgramInvocationShortName()
+// SetUsageMessage()
+// ProgramUsage()
+// Functions to set and get argv. Typically the setter is called
+// by ParseCommandLineFlags. Also can get the ProgramUsage string,
+// set by SetUsageMessage.
+// --------------------------------------------------------------------
+
+// These values are not protected by a Mutex because they are normally
+// set only once during program startup.
+static const char* argv0 = "UNKNOWN"; // just the program name
+static const char* cmdline = ""; // the entire command-line
+static vector<string> argvs;
+static uint32 argv_sum = 0;
+static const char* program_usage = NULL;
+
+void SetArgv(int argc, const char** argv) {
+ static bool called_set_argv = false;
+ if (called_set_argv) // we already have an argv for you
+ return;
+
+ called_set_argv = true;
+
+ assert(argc > 0); // every program has at least a progname
+ argv0 = strdup(argv[0]); // small memory leak, but fn only called once
+ assert(argv0);
+
+ string cmdline_string; // easier than doing strcats
+ for (int i = 0; i < argc; i++) {
+ if (i != 0) {
+ cmdline_string += " ";
+ }
+ cmdline_string += argv[i];
+ argvs.push_back(argv[i]);
+ }
+ cmdline = strdup(cmdline_string.c_str()); // another small memory leak
+ assert(cmdline);
+
+ // Compute a simple sum of all the chars in argv
+ for (const char* c = cmdline; *c; c++)
+ argv_sum += *c;
+}
+
+const vector<string>& GetArgvs() { return argvs; }
+const char* GetArgv() { return cmdline; }
+const char* GetArgv0() { return argv0; }
+uint32 GetArgvSum() { return argv_sum; }
+const char* ProgramInvocationName() { // like the GNU libc fn
+ return GetArgv0();
+}
+const char* ProgramInvocationShortName() { // like the GNU libc fn
+ const char* slash = strrchr(argv0, '/');
+#ifdef OS_WINDOWS
+ if (!slash) slash = strrchr(argv0, '\\');
+#endif
+ return slash ? slash + 1 : argv0;
+}
+
+void SetUsageMessage(const string& usage) {
+ if (program_usage != NULL)
+ ReportError(DIE, "ERROR: SetUsageMessage() called twice\n");
+ program_usage = strdup(usage.c_str()); // small memory leak
+}
+
+const char* ProgramUsage() {
+ if (program_usage) {
+ return program_usage;
+ }
+ return "Warning: SetUsageMessage() never called";
+}
+
+// --------------------------------------------------------------------
+// SetVersionString()
+// VersionString()
+// --------------------------------------------------------------------
+
+static const char* version_string = NULL;
+
+void SetVersionString(const string& version) {
+ if (version_string != NULL)
+ ReportError(DIE, "ERROR: SetVersionString() called twice\n");
+ version_string = strdup(version.c_str()); // small memory leak
+}
+
+const char* VersionString() {
+ return version_string ? version_string : "";
+}
+
+
+// --------------------------------------------------------------------
+// GetCommandLineOption()
+// GetCommandLineFlagInfo()
+// GetCommandLineFlagInfoOrDie()
+// SetCommandLineOption()
+// SetCommandLineOptionWithMode()
+// The programmatic way to set a flag's value, using a string
+// for its name rather than the variable itself (that is,
+// SetCommandLineOption("foo", x) rather than FLAGS_foo = x).
+// There's also a bit more flexibility here due to the various
+// set-modes, but typically these are used when you only have
+// that flag's name as a string, perhaps at runtime.
+// All of these work on the default, global registry.
+// For GetCommandLineOption, return false if no such flag
+// is known, true otherwise. We clear "value" if a suitable
+// flag is found.
+// --------------------------------------------------------------------
+
+
+bool GetCommandLineOption(const char* name, string* value) {
+ if (NULL == name)
+ return false;
+ assert(value);
+
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ CommandLineFlag* flag = registry->FindFlagLocked(name);
+ if (flag == NULL) {
+ return false;
+ } else {
+ *value = flag->current_value();
+ return true;
+ }
+}
+
+bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) {
+ if (NULL == name) return false;
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ CommandLineFlag* flag = registry->FindFlagLocked(name);
+ if (flag == NULL) {
+ return false;
+ } else {
+ assert(OUTPUT);
+ flag->FillCommandLineFlagInfo(OUTPUT);
+ return true;
+ }
+}
+
+CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) {
+ CommandLineFlagInfo info;
+ if (!GetCommandLineFlagInfo(name, &info)) {
+ fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name);
+ gflags_exitfunc(1); // almost certainly gflags_exitfunc()
+ }
+ return info;
+}
+
+string SetCommandLineOptionWithMode(const char* name, const char* value,
+ FlagSettingMode set_mode) {
+ string result;
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ CommandLineFlag* flag = registry->FindFlagLocked(name);
+ if (flag) {
+ CommandLineFlagParser parser(registry);
+ result = parser.ProcessSingleOptionLocked(flag, value, set_mode);
+ if (!result.empty()) { // in the error case, we've already logged
+ // Could consider logging this change
+ }
+ }
+ // The API of this function is that we return empty string on error
+ return result;
+}
+
+string SetCommandLineOption(const char* name, const char* value) {
+ return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE);
+}
+
+// --------------------------------------------------------------------
+// FlagSaver
+// FlagSaverImpl
+// This class stores the states of all flags at construct time,
+// and restores all flags to that state at destruct time.
+// Its major implementation challenge is that it never modifies
+// pointers in the 'main' registry, so global FLAG_* vars always
+// point to the right place.
+// --------------------------------------------------------------------
+
+class FlagSaverImpl {
+ public:
+ // Constructs an empty FlagSaverImpl object.
+ explicit FlagSaverImpl(FlagRegistry* main_registry)
+ : main_registry_(main_registry) { }
+ ~FlagSaverImpl() {
+ // reclaim memory from each of our CommandLineFlags
+ vector<CommandLineFlag*>::const_iterator it;
+ for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it)
+ delete *it;
+ }
+
+ // Saves the flag states from the flag registry into this object.
+ // It's an error to call this more than once.
+ // Must be called when the registry mutex is not held.
+ void SaveFromRegistry() {
+ FlagRegistryLock frl(main_registry_);
+ assert(backup_registry_.empty()); // call only once!
+ for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin();
+ it != main_registry_->flags_.end();
+ ++it) {
+ const CommandLineFlag* main = it->second;
+ // Sets up all the const variables in backup correctly
+ CommandLineFlag* backup = new CommandLineFlag(
+ main->name(), main->help(), main->filename(),
+ main->current_->New(), main->defvalue_->New());
+ // Sets up all the non-const variables in backup correctly
+ backup->CopyFrom(*main);
+ backup_registry_.push_back(backup); // add it to a convenient list
+ }
+ }
+
+ // Restores the saved flag states into the flag registry. We
+ // assume no flags were added or deleted from the registry since
+ // the SaveFromRegistry; if they were, that's trouble! Must be
+ // called when the registry mutex is not held.
+ void RestoreToRegistry() {
+ FlagRegistryLock frl(main_registry_);
+ vector<CommandLineFlag*>::const_iterator it;
+ for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) {
+ CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name());
+ if (main != NULL) { // if NULL, flag got deleted from registry(!)
+ main->CopyFrom(**it);
+ }
+ }
+ }
+
+ private:
+ FlagRegistry* const main_registry_;
+ vector<CommandLineFlag*> backup_registry_;
+
+ FlagSaverImpl(const FlagSaverImpl&); // no copying!
+ void operator=(const FlagSaverImpl&);
+};
+
+FlagSaver::FlagSaver()
+ : impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) {
+ impl_->SaveFromRegistry();
+}
+
+FlagSaver::~FlagSaver() {
+ impl_->RestoreToRegistry();
+ delete impl_;
+}
+
+
+// --------------------------------------------------------------------
+// CommandlineFlagsIntoString()
+// ReadFlagsFromString()
+// AppendFlagsIntoFile()
+// ReadFromFlagsFile()
+// These are mostly-deprecated routines that stick the
+// commandline flags into a file/string and read them back
+// out again. I can see a use for CommandlineFlagsIntoString,
+// for creating a flagfile, but the rest don't seem that useful
+// -- some, I think, are a poor-man's attempt at FlagSaver --
+// and are included only until we can delete them from callers.
+// Note they don't save --flagfile flags (though they do save
+// the result of having called the flagfile, of course).
+// --------------------------------------------------------------------
+
+static string TheseCommandlineFlagsIntoString(
+ const vector<CommandLineFlagInfo>& flags) {
+ vector<CommandLineFlagInfo>::const_iterator i;
+
+ size_t retval_space = 0;
+ for (i = flags.begin(); i != flags.end(); ++i) {
+ // An (over)estimate of how much space it will take to print this flag
+ retval_space += i->name.length() + i->current_value.length() + 5;
+ }
+
+ string retval;
+ retval.reserve(retval_space);
+ for (i = flags.begin(); i != flags.end(); ++i) {
+ retval += "--";
+ retval += i->name;
+ retval += "=";
+ retval += i->current_value;
+ retval += "\n";
+ }
+ return retval;
+}
+
+string CommandlineFlagsIntoString() {
+ vector<CommandLineFlagInfo> sorted_flags;
+ GetAllFlags(&sorted_flags);
+ return TheseCommandlineFlagsIntoString(sorted_flags);
+}
+
+bool ReadFlagsFromString(const string& flagfilecontents,
+ const char* /*prog_name*/, // TODO(csilvers): nix this
+ bool errors_are_fatal) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagSaverImpl saved_states(registry);
+ saved_states.SaveFromRegistry();
+
+ CommandLineFlagParser parser(registry);
+ registry->Lock();
+ parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE);
+ registry->Unlock();
+ // Should we handle --help and such when reading flags from a string? Sure.
+ HandleCommandLineHelpFlags();
+ if (parser.ReportErrors()) {
+ // Error. Restore all global flags to their previous values.
+ if (errors_are_fatal)
+ gflags_exitfunc(1);
+ saved_states.RestoreToRegistry();
+ return false;
+ }
+ return true;
+}
+
+// TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName()
+bool AppendFlagsIntoFile(const string& filename, const char *prog_name) {
+ FILE *fp;
+ if (SafeFOpen(&fp, filename.c_str(), "a") != 0) {
+ return false;
+ }
+
+ if (prog_name)
+ fprintf(fp, "%s\n", prog_name);
+
+ vector<CommandLineFlagInfo> flags;
+ GetAllFlags(&flags);
+ // But we don't want --flagfile, which leads to weird recursion issues
+ vector<CommandLineFlagInfo>::iterator i;
+ for (i = flags.begin(); i != flags.end(); ++i) {
+ if (strcmp(i->name.c_str(), "flagfile") == 0) {
+ flags.erase(i);
+ break;
+ }
+ }
+ fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str());
+
+ fclose(fp);
+ return true;
+}
+
+bool ReadFromFlagsFile(const string& filename, const char* prog_name,
+ bool errors_are_fatal) {
+ return ReadFlagsFromString(ReadFileIntoString(filename.c_str()),
+ prog_name, errors_are_fatal);
+}
+
+
+// --------------------------------------------------------------------
+// BoolFromEnv()
+// Int32FromEnv()
+// Int64FromEnv()
+// Uint64FromEnv()
+// DoubleFromEnv()
+// StringFromEnv()
+// Reads the value from the environment and returns it.
+// We use an FlagValue to make the parsing easy.
+// Example usage:
+// DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever");
+// --------------------------------------------------------------------
+
+bool BoolFromEnv(const char *v, bool dflt) {
+ return GetFromEnv(v, "bool", dflt);
+}
+int32 Int32FromEnv(const char *v, int32 dflt) {
+ return GetFromEnv(v, "int32", dflt);
+}
+int64 Int64FromEnv(const char *v, int64 dflt) {
+ return GetFromEnv(v, "int64", dflt);
+}
+uint64 Uint64FromEnv(const char *v, uint64 dflt) {
+ return GetFromEnv(v, "uint64", dflt);
+}
+double DoubleFromEnv(const char *v, double dflt) {
+ return GetFromEnv(v, "double", dflt);
+}
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996) // ignore getenv security warning
+#endif
+const char *StringFromEnv(const char *varname, const char *dflt) {
+ const char* const val = getenv(varname);
+ return val ? val : dflt;
+}
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+
+// --------------------------------------------------------------------
+// RegisterFlagValidator()
+// RegisterFlagValidator() is the function that clients use to
+// 'decorate' a flag with a validation function. Once this is
+// done, every time the flag is set (including when the flag
+// is parsed from argv), the validator-function is called.
+// These functions return true if the validator was added
+// successfully, or false if not: the flag already has a validator,
+// (only one allowed per flag), the 1st arg isn't a flag, etc.
+// This function is not thread-safe.
+// --------------------------------------------------------------------
+
+bool RegisterFlagValidator(const bool* flag,
+ bool (*validate_fn)(const char*, bool)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const int32* flag,
+ bool (*validate_fn)(const char*, int32)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const int64* flag,
+ bool (*validate_fn)(const char*, int64)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const uint64* flag,
+ bool (*validate_fn)(const char*, uint64)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const double* flag,
+ bool (*validate_fn)(const char*, double)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+bool RegisterFlagValidator(const string* flag,
+ bool (*validate_fn)(const char*, const string&)) {
+ return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
+}
+
+
+// --------------------------------------------------------------------
+// ParseCommandLineFlags()
+// ParseCommandLineNonHelpFlags()
+// HandleCommandLineHelpFlags()
+// This is the main function called from main(), to actually
+// parse the commandline. It modifies argc and argv as described
+// at the top of gflags.h. You can also divide this
+// function into two parts, if you want to do work between
+// the parsing of the flags and the printing of any help output.
+// --------------------------------------------------------------------
+
+static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv,
+ bool remove_flags, bool do_report) {
+ SetArgv(*argc, const_cast<const char**>(*argv)); // save it for later
+
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ CommandLineFlagParser parser(registry);
+
+ // When we parse the commandline flags, we'll handle --flagfile,
+ // --tryfromenv, etc. as we see them (since flag-evaluation order
+ // may be important). But sometimes apps set FLAGS_tryfromenv/etc.
+ // manually before calling ParseCommandLineFlags. We want to evaluate
+ // those too, as if they were the first flags on the commandline.
+ registry->Lock();
+ parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE);
+ // Last arg here indicates whether flag-not-found is a fatal error or not
+ parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true);
+ parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false);
+ registry->Unlock();
+
+ // Now get the flags specified on the commandline
+ const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags);
+
+ if (do_report)
+ HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc.
+
+ // See if any of the unset flags fail their validation checks
+ parser.ValidateAllFlags();
+
+ if (parser.ReportErrors()) // may cause us to exit on illegal flags
+ gflags_exitfunc(1);
+ return r;
+}
+
+uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) {
+ return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true);
+}
+
+uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv,
+ bool remove_flags) {
+ return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false);
+}
+
+// --------------------------------------------------------------------
+// AllowCommandLineReparsing()
+// ReparseCommandLineNonHelpFlags()
+// This is most useful for shared libraries. The idea is if
+// a flag is defined in a shared library that is dlopen'ed
+// sometime after main(), you can ParseCommandLineFlags before
+// the dlopen, then ReparseCommandLineNonHelpFlags() after the
+// dlopen, to get the new flags. But you have to explicitly
+// Allow() it; otherwise, you get the normal default behavior
+// of unrecognized flags calling a fatal error.
+// TODO(csilvers): this isn't used. Just delete it?
+// --------------------------------------------------------------------
+
+void AllowCommandLineReparsing() {
+ allow_command_line_reparsing = true;
+}
+
+void ReparseCommandLineNonHelpFlags() {
+ // We make a copy of argc and argv to pass in
+ const vector<string>& argvs = GetArgvs();
+ int tmp_argc = static_cast<int>(argvs.size());
+ char** tmp_argv = new char* [tmp_argc + 1];
+ for (int i = 0; i < tmp_argc; ++i)
+ tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup
+
+ ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false);
+
+ for (int i = 0; i < tmp_argc; ++i)
+ free(tmp_argv[i]);
+ delete[] tmp_argv;
+}
+
+void ShutDownCommandLineFlags() {
+ FlagRegistry::DeleteGlobalRegistry();
+}
+
+
+} // namespace GFLAGS_NAMESPACE
diff --git a/extern/gflags/src/gflags/gflags.h b/extern/gflags/src/gflags/gflags.h
new file mode 100644
index 00000000000..357eec6be7c
--- /dev/null
+++ b/extern/gflags/src/gflags/gflags.h
@@ -0,0 +1,573 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// Revamped and reorganized by Craig Silverstein
+//
+// This is the file that should be included by any file which declares
+// or defines a command line flag or wants to parse command line flags
+// or print a program usage message (which will include information about
+// flags). Executive summary, in the form of an example foo.cc file:
+//
+// #include "foo.h" // foo.h has a line "DECLARE_int32(start);"
+// #include "validators.h" // hypothetical file defining ValidateIsFile()
+//
+// DEFINE_int32(end, 1000, "The last record to read");
+//
+// DEFINE_string(filename, "my_file.txt", "The file to read");
+// // Crash if the specified file does not exist.
+// static bool dummy = RegisterFlagValidator(&FLAGS_filename,
+// &ValidateIsFile);
+//
+// DECLARE_bool(verbose); // some other file has a DEFINE_bool(verbose, ...)
+//
+// void MyFunc() {
+// if (FLAGS_verbose) printf("Records %d-%d\n", FLAGS_start, FLAGS_end);
+// }
+//
+// Then, at the command-line:
+// ./foo --noverbose --start=5 --end=100
+//
+// For more details, see
+// doc/gflags.html
+//
+// --- A note about thread-safety:
+//
+// We describe many functions in this routine as being thread-hostile,
+// thread-compatible, or thread-safe. Here are the meanings we use:
+//
+// thread-safe: it is safe for multiple threads to call this routine
+// (or, when referring to a class, methods of this class)
+// concurrently.
+// thread-hostile: it is not safe for multiple threads to call this
+// routine (or methods of this class) concurrently. In gflags,
+// most thread-hostile routines are intended to be called early in,
+// or even before, main() -- that is, before threads are spawned.
+// thread-compatible: it is safe for multiple threads to read from
+// this variable (when applied to variables), or to call const
+// methods of this class (when applied to classes), as long as no
+// other thread is writing to the variable or calling non-const
+// methods of this class.
+
+#ifndef GFLAGS_GFLAGS_H_
+#define GFLAGS_GFLAGS_H_
+
+#include <string>
+#include <vector>
+
+#include "gflags_declare.h" // IWYU pragma: export
+
+
+// We always want to export variables defined in user code
+#ifndef GFLAGS_DLL_DEFINE_FLAG
+# ifdef _MSC_VER
+# define GFLAGS_DLL_DEFINE_FLAG __declspec(dllexport)
+# else
+# define GFLAGS_DLL_DEFINE_FLAG
+# endif
+#endif
+
+
+namespace GFLAGS_NAMESPACE {
+
+
+// --------------------------------------------------------------------
+// To actually define a flag in a file, use DEFINE_bool,
+// DEFINE_string, etc. at the bottom of this file. You may also find
+// it useful to register a validator with the flag. This ensures that
+// when the flag is parsed from the commandline, or is later set via
+// SetCommandLineOption, we call the validation function. It is _not_
+// called when you assign the value to the flag directly using the = operator.
+//
+// The validation function should return true if the flag value is valid, and
+// false otherwise. If the function returns false for the new setting of the
+// flag, the flag will retain its current value. If it returns false for the
+// default value, ParseCommandLineFlags() will die.
+//
+// This function is safe to call at global construct time (as in the
+// example below).
+//
+// Example use:
+// static bool ValidatePort(const char* flagname, int32 value) {
+// if (value > 0 && value < 32768) // value is ok
+// return true;
+// printf("Invalid value for --%s: %d\n", flagname, (int)value);
+// return false;
+// }
+// DEFINE_int32(port, 0, "What port to listen on");
+// static bool dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);
+
+// Returns true if successfully registered, false if not (because the
+// first argument doesn't point to a command-line flag, or because a
+// validator is already registered for this flag).
+extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const bool* flag, bool (*validate_fn)(const char*, bool));
+extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const int32* flag, bool (*validate_fn)(const char*, int32));
+extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const int64* flag, bool (*validate_fn)(const char*, int64));
+extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const uint64* flag, bool (*validate_fn)(const char*, uint64));
+extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const double* flag, bool (*validate_fn)(const char*, double));
+extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const std::string* flag, bool (*validate_fn)(const char*, const std::string&));
+
+// Convenience macro for the registration of a flag validator
+#define DEFINE_validator(name, validator) \
+ static const bool name##_validator_registered = \
+ GFLAGS_NAMESPACE::RegisterFlagValidator(&FLAGS_##name, validator)
+
+
+// --------------------------------------------------------------------
+// These methods are the best way to get access to info about the
+// list of commandline flags. Note that these routines are pretty slow.
+// GetAllFlags: mostly-complete info about the list, sorted by file.
+// ShowUsageWithFlags: pretty-prints the list to stdout (what --help does)
+// ShowUsageWithFlagsRestrict: limit to filenames with restrict as a substr
+//
+// In addition to accessing flags, you can also access argv[0] (the program
+// name) and argv (the entire commandline), which we sock away a copy of.
+// These variables are static, so you should only set them once.
+//
+// No need to export this data only structure from DLL, avoiding VS warning 4251.
+struct CommandLineFlagInfo {
+ std::string name; // the name of the flag
+ std::string type; // the type of the flag: int32, etc
+ std::string description; // the "help text" associated with the flag
+ std::string current_value; // the current value, as a string
+ std::string default_value; // the default value, as a string
+ std::string filename; // 'cleaned' version of filename holding the flag
+ bool has_validator_fn; // true if RegisterFlagValidator called on this flag
+ bool is_default; // true if the flag has the default value and
+ // has not been set explicitly from the cmdline
+ // or via SetCommandLineOption
+ const void* flag_ptr; // pointer to the flag's current value (i.e. FLAGS_foo)
+};
+
+// Using this inside of a validator is a recipe for a deadlock.
+// TODO(user) Fix locking when validators are running, to make it safe to
+// call validators during ParseAllFlags.
+// Also make sure then to uncomment the corresponding unit test in
+// gflags_unittest.sh
+extern GFLAGS_DLL_DECL void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT);
+// These two are actually defined in gflags_reporting.cc.
+extern GFLAGS_DLL_DECL void ShowUsageWithFlags(const char *argv0); // what --help does
+extern GFLAGS_DLL_DECL void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict);
+
+// Create a descriptive string for a flag.
+// Goes to some trouble to make pretty line breaks.
+extern GFLAGS_DLL_DECL std::string DescribeOneFlag(const CommandLineFlagInfo& flag);
+
+// Thread-hostile; meant to be called before any threads are spawned.
+extern GFLAGS_DLL_DECL void SetArgv(int argc, const char** argv);
+
+// The following functions are thread-safe as long as SetArgv() is
+// only called before any threads start.
+extern GFLAGS_DLL_DECL const std::vector<std::string>& GetArgvs();
+extern GFLAGS_DLL_DECL const char* GetArgv(); // all of argv as a string
+extern GFLAGS_DLL_DECL const char* GetArgv0(); // only argv0
+extern GFLAGS_DLL_DECL uint32 GetArgvSum(); // simple checksum of argv
+extern GFLAGS_DLL_DECL const char* ProgramInvocationName(); // argv0, or "UNKNOWN" if not set
+extern GFLAGS_DLL_DECL const char* ProgramInvocationShortName(); // basename(argv0)
+
+// ProgramUsage() is thread-safe as long as SetUsageMessage() is only
+// called before any threads start.
+extern GFLAGS_DLL_DECL const char* ProgramUsage(); // string set by SetUsageMessage()
+
+// VersionString() is thread-safe as long as SetVersionString() is only
+// called before any threads start.
+extern GFLAGS_DLL_DECL const char* VersionString(); // string set by SetVersionString()
+
+
+
+// --------------------------------------------------------------------
+// Normally you access commandline flags by just saying "if (FLAGS_foo)"
+// or whatever, and set them by calling "FLAGS_foo = bar" (or, more
+// commonly, via the DEFINE_foo macro). But if you need a bit more
+// control, we have programmatic ways to get/set the flags as well.
+// These programmatic ways to access flags are thread-safe, but direct
+// access is only thread-compatible.
+
+// Return true iff the flagname was found.
+// OUTPUT is set to the flag's value, or unchanged if we return false.
+extern GFLAGS_DLL_DECL bool GetCommandLineOption(const char* name, std::string* OUTPUT);
+
+// Return true iff the flagname was found. OUTPUT is set to the flag's
+// CommandLineFlagInfo or unchanged if we return false.
+extern GFLAGS_DLL_DECL bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT);
+
+// Return the CommandLineFlagInfo of the flagname. exit() if name not found.
+// Example usage, to check if a flag's value is currently the default value:
+// if (GetCommandLineFlagInfoOrDie("foo").is_default) ...
+extern GFLAGS_DLL_DECL CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name);
+
+enum GFLAGS_DLL_DECL FlagSettingMode {
+ // update the flag's value (can call this multiple times).
+ SET_FLAGS_VALUE,
+ // update the flag's value, but *only if* it has not yet been updated
+ // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
+ SET_FLAG_IF_DEFAULT,
+ // set the flag's default value to this. If the flag has not yet updated
+ // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
+ // change the flag's current value to the new default value as well.
+ SET_FLAGS_DEFAULT
+};
+
+// Set a particular flag ("command line option"). Returns a string
+// describing the new value that the option has been set to. The
+// return value API is not well-specified, so basically just depend on
+// it to be empty if the setting failed for some reason -- the name is
+// not a valid flag name, or the value is not a valid value -- and
+// non-empty else.
+
+// SetCommandLineOption uses set_mode == SET_FLAGS_VALUE (the common case)
+extern GFLAGS_DLL_DECL std::string SetCommandLineOption (const char* name, const char* value);
+extern GFLAGS_DLL_DECL std::string SetCommandLineOptionWithMode(const char* name, const char* value, FlagSettingMode set_mode);
+
+
+// --------------------------------------------------------------------
+// Saves the states (value, default value, whether the user has set
+// the flag, registered validators, etc) of all flags, and restores
+// them when the FlagSaver is destroyed. This is very useful in
+// tests, say, when you want to let your tests change the flags, but
+// make sure that they get reverted to the original states when your
+// test is complete.
+//
+// Example usage:
+// void TestFoo() {
+// FlagSaver s1;
+// FLAG_foo = false;
+// FLAG_bar = "some value";
+//
+// // test happens here. You can return at any time
+// // without worrying about restoring the FLAG values.
+// }
+//
+// Note: This class is marked with GFLAGS_ATTRIBUTE_UNUSED because all
+// the work is done in the constructor and destructor, so in the standard
+// usage example above, the compiler would complain that it's an
+// unused variable.
+//
+// This class is thread-safe. However, its destructor writes to
+// exactly the set of flags that have changed value during its
+// lifetime, so concurrent _direct_ access to those flags
+// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe.
+
+class GFLAGS_DLL_DECL FlagSaver {
+ public:
+ FlagSaver();
+ ~FlagSaver();
+
+ private:
+ class FlagSaverImpl* impl_; // we use pimpl here to keep API steady
+
+ FlagSaver(const FlagSaver&); // no copying!
+ void operator=(const FlagSaver&);
+};
+
+// --------------------------------------------------------------------
+// Some deprecated or hopefully-soon-to-be-deprecated functions.
+
+// This is often used for logging. TODO(csilvers): figure out a better way
+extern GFLAGS_DLL_DECL std::string CommandlineFlagsIntoString();
+// Usually where this is used, a FlagSaver should be used instead.
+extern GFLAGS_DLL_DECL
+bool ReadFlagsFromString(const std::string& flagfilecontents,
+ const char* prog_name,
+ bool errors_are_fatal); // uses SET_FLAGS_VALUE
+
+// These let you manually implement --flagfile functionality.
+// DEPRECATED.
+extern GFLAGS_DLL_DECL bool AppendFlagsIntoFile(const std::string& filename, const char* prog_name);
+extern GFLAGS_DLL_DECL bool ReadFromFlagsFile(const std::string& filename, const char* prog_name, bool errors_are_fatal); // uses SET_FLAGS_VALUE
+
+
+// --------------------------------------------------------------------
+// Useful routines for initializing flags from the environment.
+// In each case, if 'varname' does not exist in the environment
+// return defval. If 'varname' does exist but is not valid
+// (e.g., not a number for an int32 flag), abort with an error.
+// Otherwise, return the value. NOTE: for booleans, for true use
+// 't' or 'T' or 'true' or '1', for false 'f' or 'F' or 'false' or '0'.
+
+extern GFLAGS_DLL_DECL bool BoolFromEnv(const char *varname, bool defval);
+extern GFLAGS_DLL_DECL int32 Int32FromEnv(const char *varname, int32 defval);
+extern GFLAGS_DLL_DECL int64 Int64FromEnv(const char *varname, int64 defval);
+extern GFLAGS_DLL_DECL uint64 Uint64FromEnv(const char *varname, uint64 defval);
+extern GFLAGS_DLL_DECL double DoubleFromEnv(const char *varname, double defval);
+extern GFLAGS_DLL_DECL const char *StringFromEnv(const char *varname, const char *defval);
+
+
+// --------------------------------------------------------------------
+// The next two functions parse gflags from main():
+
+// Set the "usage" message for this program. For example:
+// string usage("This program does nothing. Sample usage:\n");
+// usage += argv[0] + " <uselessarg1> <uselessarg2>";
+// SetUsageMessage(usage);
+// Do not include commandline flags in the usage: we do that for you!
+// Thread-hostile; meant to be called before any threads are spawned.
+extern GFLAGS_DLL_DECL void SetUsageMessage(const std::string& usage);
+
+// Sets the version string, which is emitted with --version.
+// For instance: SetVersionString("1.3");
+// Thread-hostile; meant to be called before any threads are spawned.
+extern GFLAGS_DLL_DECL void SetVersionString(const std::string& version);
+
+
+// Looks for flags in argv and parses them. Rearranges argv to put
+// flags first, or removes them entirely if remove_flags is true.
+// If a flag is defined more than once in the command line or flag
+// file, the last definition is used. Returns the index (into argv)
+// of the first non-flag argument.
+// See top-of-file for more details on this function.
+#ifndef SWIG // In swig, use ParseCommandLineFlagsScript() instead.
+extern GFLAGS_DLL_DECL uint32 ParseCommandLineFlags(int *argc, char*** argv, bool remove_flags);
+#endif
+
+
+// Calls to ParseCommandLineNonHelpFlags and then to
+// HandleCommandLineHelpFlags can be used instead of a call to
+// ParseCommandLineFlags during initialization, in order to allow for
+// changing default values for some FLAGS (via
+// e.g. SetCommandLineOptionWithMode calls) between the time of
+// command line parsing and the time of dumping help information for
+// the flags as a result of command line parsing. If a flag is
+// defined more than once in the command line or flag file, the last
+// definition is used. Returns the index (into argv) of the first
+// non-flag argument. (If remove_flags is true, will always return 1.)
+extern GFLAGS_DLL_DECL uint32 ParseCommandLineNonHelpFlags(int *argc, char*** argv, bool remove_flags);
+
+// This is actually defined in gflags_reporting.cc.
+// This function is misnamed (it also handles --version, etc.), but
+// it's too late to change that now. :-(
+extern GFLAGS_DLL_DECL void HandleCommandLineHelpFlags(); // in gflags_reporting.cc
+
+// Allow command line reparsing. Disables the error normally
+// generated when an unknown flag is found, since it may be found in a
+// later parse. Thread-hostile; meant to be called before any threads
+// are spawned.
+extern GFLAGS_DLL_DECL void AllowCommandLineReparsing();
+
+// Reparse the flags that have not yet been recognized. Only flags
+// registered since the last parse will be recognized. Any flag value
+// must be provided as part of the argument using "=", not as a
+// separate command line argument that follows the flag argument.
+// Intended for handling flags from dynamically loaded libraries,
+// since their flags are not registered until they are loaded.
+extern GFLAGS_DLL_DECL void ReparseCommandLineNonHelpFlags();
+
+// Clean up memory allocated by flags. This is only needed to reduce
+// the quantity of "potentially leaked" reports emitted by memory
+// debugging tools such as valgrind. It is not required for normal
+// operation, or for the google perftools heap-checker. It must only
+// be called when the process is about to exit, and all threads that
+// might access flags are quiescent. Referencing flags after this is
+// called will have unexpected consequences. This is not safe to run
+// when multiple threads might be running: the function is
+// thread-hostile.
+extern GFLAGS_DLL_DECL void ShutDownCommandLineFlags();
+
+
+// --------------------------------------------------------------------
+// Now come the command line flag declaration/definition macros that
+// will actually be used. They're kind of hairy. A major reason
+// for this is initialization: we want people to be able to access
+// variables in global constructors and have that not crash, even if
+// their global constructor runs before the global constructor here.
+// (Obviously, we can't guarantee the flags will have the correct
+// default value in that case, but at least accessing them is safe.)
+// The only way to do that is have flags point to a static buffer.
+// So we make one, using a union to ensure proper alignment, and
+// then use placement-new to actually set up the flag with the
+// correct default value. In the same vein, we have to worry about
+// flag access in global destructors, so FlagRegisterer has to be
+// careful never to destroy the flag-values it constructs.
+//
+// Note that when we define a flag variable FLAGS_<name>, we also
+// preemptively define a junk variable, FLAGS_no<name>. This is to
+// cause a link-time error if someone tries to define 2 flags with
+// names like "logging" and "nologging". We do this because a bool
+// flag FLAG can be set from the command line to true with a "-FLAG"
+// argument, and to false with a "-noFLAG" argument, and so this can
+// potentially avert confusion.
+//
+// We also put flags into their own namespace. It is purposefully
+// named in an opaque way that people should have trouble typing
+// directly. The idea is that DEFINE puts the flag in the weird
+// namespace, and DECLARE imports the flag from there into the current
+// namespace. The net result is to force people to use DECLARE to get
+// access to a flag, rather than saying "extern GFLAGS_DLL_DECL bool FLAGS_whatever;"
+// or some such instead. We want this so we can put extra
+// functionality (like sanity-checking) in DECLARE if we want, and
+// make sure it is picked up everywhere.
+//
+// We also put the type of the variable in the namespace, so that
+// people can't DECLARE_int32 something that they DEFINE_bool'd
+// elsewhere.
+
+class GFLAGS_DLL_DECL FlagRegisterer {
+ public:
+ FlagRegisterer(const char* name, const char* type,
+ const char* help, const char* filename,
+ void* current_storage, void* defvalue_storage);
+};
+
+// If your application #defines STRIP_FLAG_HELP to a non-zero value
+// before #including this file, we remove the help message from the
+// binary file. This can reduce the size of the resulting binary
+// somewhat, and may also be useful for security reasons.
+
+extern GFLAGS_DLL_DECL const char kStrippedFlagHelp[];
+
+
+} // namespace GFLAGS_NAMESPACE
+
+
+#ifndef SWIG // In swig, ignore the main flag declarations
+
+#if defined(STRIP_FLAG_HELP) && STRIP_FLAG_HELP > 0
+// Need this construct to avoid the 'defined but not used' warning.
+#define MAYBE_STRIPPED_HELP(txt) \
+ (false ? (txt) : GFLAGS_NAMESPACE::kStrippedFlagHelp)
+#else
+#define MAYBE_STRIPPED_HELP(txt) txt
+#endif
+
+// Each command-line flag has two variables associated with it: one
+// with the current value, and one with the default value. However,
+// we have a third variable, which is where value is assigned; it's a
+// constant. This guarantees that FLAG_##value is initialized at
+// static initialization time (e.g. before program-start) rather than
+// than global construction time (which is after program-start but
+// before main), at least when 'value' is a compile-time constant. We
+// use a small trick for the "default value" variable, and call it
+// FLAGS_no<name>. This serves the second purpose of assuring a
+// compile error if someone tries to define a flag named no<name>
+// which is illegal (--foo and --nofoo both affect the "foo" flag).
+#define DEFINE_VARIABLE(type, shorttype, name, value, help) \
+ namespace fL##shorttype { \
+ static const type FLAGS_nono##name = value; \
+ /* We always want to export defined variables, dll or no */ \
+ GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = FLAGS_nono##name; \
+ type FLAGS_no##name = FLAGS_nono##name; \
+ static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \
+ #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \
+ &FLAGS_##name, &FLAGS_no##name); \
+ } \
+ using fL##shorttype::FLAGS_##name
+
+// For DEFINE_bool, we want to do the extra check that the passed-in
+// value is actually a bool, and not a string or something that can be
+// coerced to a bool. These declarations (no definition needed!) will
+// help us do that, and never evaluate From, which is important.
+// We'll use 'sizeof(IsBool(val))' to distinguish. This code requires
+// that the compiler have different sizes for bool & double. Since
+// this is not guaranteed by the standard, we check it with a
+// COMPILE_ASSERT.
+namespace fLB {
+struct CompileAssert {};
+typedef CompileAssert expected_sizeof_double_neq_sizeof_bool[
+ (sizeof(double) != sizeof(bool)) ? 1 : -1];
+template<typename From> double GFLAGS_DLL_DECL IsBoolFlag(const From& from);
+GFLAGS_DLL_DECL bool IsBoolFlag(bool from);
+} // namespace fLB
+
+// Here are the actual DEFINE_*-macros. The respective DECLARE_*-macros
+// are in a separate include, gflags_declare.h, for reducing
+// the physical transitive size for DECLARE use.
+#define DEFINE_bool(name, val, txt) \
+ namespace fLB { \
+ typedef ::fLB::CompileAssert FLAG_##name##_value_is_not_a_bool[ \
+ (sizeof(::fLB::IsBoolFlag(val)) != sizeof(double))? 1: -1]; \
+ } \
+ DEFINE_VARIABLE(bool, B, name, val, txt)
+
+#define DEFINE_int32(name, val, txt) \
+ DEFINE_VARIABLE(GFLAGS_NAMESPACE::int32, I, \
+ name, val, txt)
+
+#define DEFINE_int64(name, val, txt) \
+ DEFINE_VARIABLE(GFLAGS_NAMESPACE::int64, I64, \
+ name, val, txt)
+
+#define DEFINE_uint64(name,val, txt) \
+ DEFINE_VARIABLE(GFLAGS_NAMESPACE::uint64, U64, \
+ name, val, txt)
+
+#define DEFINE_double(name, val, txt) \
+ DEFINE_VARIABLE(double, D, name, val, txt)
+
+// Strings are trickier, because they're not a POD, so we can't
+// construct them at static-initialization time (instead they get
+// constructed at global-constructor time, which is much later). To
+// try to avoid crashes in that case, we use a char buffer to store
+// the string, which we can static-initialize, and then placement-new
+// into it later. It's not perfect, but the best we can do.
+
+namespace fLS {
+
+inline clstring* dont_pass0toDEFINE_string(char *stringspot,
+ const char *value) {
+ return new(stringspot) clstring(value);
+}
+inline clstring* dont_pass0toDEFINE_string(char *stringspot,
+ const clstring &value) {
+ return new(stringspot) clstring(value);
+}
+inline clstring* dont_pass0toDEFINE_string(char *stringspot,
+ int value);
+} // namespace fLS
+
+// We need to define a var named FLAGS_no##name so people don't define
+// --string and --nostring. And we need a temporary place to put val
+// so we don't have to evaluate it twice. Two great needs that go
+// great together!
+// The weird 'using' + 'extern' inside the fLS namespace is to work around
+// an unknown compiler bug/issue with the gcc 4.2.1 on SUSE 10. See
+// http://code.google.com/p/google-gflags/issues/detail?id=20
+#define DEFINE_string(name, val, txt) \
+ namespace fLS { \
+ using ::fLS::clstring; \
+ static union { void* align; char s[sizeof(clstring)]; } s_##name[2]; \
+ clstring* const FLAGS_no##name = ::fLS:: \
+ dont_pass0toDEFINE_string(s_##name[0].s, \
+ val); \
+ static GFLAGS_NAMESPACE::FlagRegisterer o_##name( \
+ #name, "string", MAYBE_STRIPPED_HELP(txt), __FILE__, \
+ s_##name[0].s, new (s_##name[1].s) clstring(*FLAGS_no##name)); \
+ extern GFLAGS_DLL_DEFINE_FLAG clstring& FLAGS_##name; \
+ using fLS::FLAGS_##name; \
+ clstring& FLAGS_##name = *FLAGS_no##name; \
+ } \
+ using fLS::FLAGS_##name
+
+#endif // SWIG
+
+
+// Import gflags library symbols into alternative/deprecated namespace(s)
+#include "gflags_gflags.h"
+
+
+#endif // GFLAGS_GFLAGS_H_
diff --git a/extern/gflags/src/gflags/gflags_completions.h b/extern/gflags/src/gflags/gflags_completions.h
new file mode 100644
index 00000000000..f951c1e02d1
--- /dev/null
+++ b/extern/gflags/src/gflags/gflags_completions.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+
+//
+// Implement helpful bash-style command line flag completions
+//
+// ** Functional API:
+// HandleCommandLineCompletions() should be called early during
+// program startup, but after command line flag code has been
+// initialized, such as the beginning of HandleCommandLineHelpFlags().
+// It checks the value of the flag --tab_completion_word. If this
+// flag is empty, nothing happens here. If it contains a string,
+// however, then HandleCommandLineCompletions() will hijack the
+// process, attempting to identify the intention behind this
+// completion. Regardless of the outcome of this deduction, the
+// process will be terminated, similar to --helpshort flag
+// handling.
+//
+// ** Overview of Bash completions:
+// Bash can be told to programatically determine completions for the
+// current 'cursor word'. It does this by (in this case) invoking a
+// command with some additional arguments identifying the command
+// being executed, the word being completed, and the previous word
+// (if any). Bash then expects a sequence of output lines to be
+// printed to stdout. If these lines all contain a common prefix
+// longer than the cursor word, bash will replace the cursor word
+// with that common prefix, and display nothing. If there isn't such
+// a common prefix, bash will display the lines in pages using 'more'.
+//
+// ** Strategy taken for command line completions:
+// If we can deduce either the exact flag intended, or a common flag
+// prefix, we'll output exactly that. Otherwise, if information
+// must be displayed to the user, we'll take the opportunity to add
+// some helpful information beyond just the flag name (specifically,
+// we'll include the default flag value and as much of the flag's
+// description as can fit on a single terminal line width, as specified
+// by the flag --tab_completion_columns). Furthermore, we'll try to
+// make bash order the output such that the most useful or relevent
+// flags are the most likely to be shown at the top.
+//
+// ** Additional features:
+// To assist in finding that one really useful flag, substring matching
+// was implemented. Before pressing a <TAB> to get completion for the
+// current word, you can append one or more '?' to the flag to do
+// substring matching. Here's the semantics:
+// --foo<TAB> Show me all flags with names prefixed by 'foo'
+// --foo?<TAB> Show me all flags with 'foo' somewhere in the name
+// --foo??<TAB> Same as prior case, but also search in module
+// definition path for 'foo'
+// --foo???<TAB> Same as prior case, but also search in flag
+// descriptions for 'foo'
+// Finally, we'll trim the output to a relatively small number of
+// flags to keep bash quiet about the verbosity of output. If one
+// really wanted to see all possible matches, appending a '+' to the
+// search word will force the exhaustive list of matches to be printed.
+//
+// ** How to have bash accept completions from a binary:
+// Bash requires that it be informed about each command that programmatic
+// completion should be enabled for. Example addition to a .bashrc
+// file would be (your path to gflags_completions.sh file may differ):
+
+/*
+$ complete -o bashdefault -o default -o nospace -C \
+ '/home/build/eng/bash/bash_completions.sh --tab_completion_columns $COLUMNS' \
+ time env binary_name another_binary [...]
+*/
+
+// This would allow the following to work:
+// $ /path/to/binary_name --vmodule<TAB>
+// Or:
+// $ ./bin/path/another_binary --gfs_u<TAB>
+// (etc)
+//
+// Sadly, it appears that bash gives no easy way to force this behavior for
+// all commands. That's where the "time" in the above example comes in.
+// If you haven't specifically added a command to the list of completion
+// supported commands, you can still get completions by prefixing the
+// entire command with "env".
+// $ env /some/brand/new/binary --vmod<TAB>
+// Assuming that "binary" is a newly compiled binary, this should still
+// produce the expected completion output.
+
+
+#ifndef GFLAGS_COMPLETIONS_H_
+#define GFLAGS_COMPLETIONS_H_
+
+namespace google {
+
+extern void HandleCommandLineCompletions(void);
+
+}
+
+#endif // GFLAGS_COMPLETIONS_H_
diff --git a/extern/gflags/src/gflags/gflags_declare.h b/extern/gflags/src/gflags/gflags_declare.h
new file mode 100644
index 00000000000..9b85f46cfdc
--- /dev/null
+++ b/extern/gflags/src/gflags/gflags_declare.h
@@ -0,0 +1,141 @@
+// Copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+//
+// Revamped and reorganized by Craig Silverstein
+//
+// This is the file that should be included by any file which declares
+// command line flag.
+
+#ifndef GFLAGS_DECLARE_H_
+#define GFLAGS_DECLARE_H_
+
+
+// ---------------------------------------------------------------------------
+// Namespace of gflags library symbols.
+#define GFLAGS_NAMESPACE google
+
+// ---------------------------------------------------------------------------
+// Windows DLL import/export.
+
+// We always want to import the symbols of the gflags library
+#ifndef GFLAGS_DLL_DECL
+# if 1 && defined(_MSC_VER)
+# define GFLAGS_DLL_DECL __declspec(dllimport)
+# else
+# define GFLAGS_DLL_DECL
+# endif
+#endif
+
+// We always want to import variables declared in user code
+#ifndef GFLAGS_DLL_DECLARE_FLAG
+# ifdef _MSC_VER
+# define GFLAGS_DLL_DECLARE_FLAG __declspec(dllimport)
+# else
+# define GFLAGS_DLL_DECLARE_FLAG
+# endif
+#endif
+
+// ---------------------------------------------------------------------------
+// Flag types
+#include <string>
+#if 1
+# include <stdint.h> // the normal place uint32_t is defined
+#elif 1
+# include <sys/types.h> // the normal place u_int32_t is defined
+#elif 1
+# include <inttypes.h> // a third place for uint32_t or u_int32_t
+#endif
+
+namespace GFLAGS_NAMESPACE {
+
+#if 1 // C99
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#elif 0 // BSD
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef int64_t int64;
+typedef u_int64_t uint64;
+#elif 0 // Windows
+typedef __int32 int32;
+typedef unsigned __int32 uint32;
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+# error Do not know how to define a 32-bit integer quantity on your system
+#endif
+
+} // namespace GFLAGS_NAMESPACE
+
+
+namespace fLS {
+
+// The meaning of "string" might be different between now and when the
+// macros below get invoked (e.g., if someone is experimenting with
+// other string implementations that get defined after this file is
+// included). Save the current meaning now and use it in the macros.
+typedef std::string clstring;
+
+} // namespace fLS
+
+
+#define DECLARE_VARIABLE(type, shorttype, name) \
+ /* We always want to import declared variables, dll or no */ \
+ namespace fL##shorttype { extern GFLAGS_DLL_DECLARE_FLAG type FLAGS_##name; } \
+ using fL##shorttype::FLAGS_##name
+
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, B, name)
+
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(::GFLAGS_NAMESPACE::int32, I, name)
+
+#define DECLARE_int64(name) \
+ DECLARE_VARIABLE(::GFLAGS_NAMESPACE::int64, I64, name)
+
+#define DECLARE_uint64(name) \
+ DECLARE_VARIABLE(::GFLAGS_NAMESPACE::uint64, U64, name)
+
+#define DECLARE_double(name) \
+ DECLARE_VARIABLE(double, D, name)
+
+#define DECLARE_string(name) \
+ /* We always want to import declared variables, dll or no */ \
+ namespace fLS { \
+ using ::fLS::clstring; \
+ extern GFLAGS_DLL_DECLARE_FLAG ::fLS::clstring& FLAGS_##name; \
+ } \
+ using fLS::FLAGS_##name
+
+
+#endif // GFLAGS_DECLARE_H_
diff --git a/extern/gflags/src/gflags/gflags_gflags.h b/extern/gflags/src/gflags/gflags_gflags.h
new file mode 100644
index 00000000000..0c17825dd62
--- /dev/null
+++ b/extern/gflags/src/gflags/gflags_gflags.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2014, Andreas Schuh
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// -----------------------------------------------------------------------------
+// Imports the gflags library symbols into an alternative/deprecated namespace.
+
+#ifndef GFLAGS_GFLAGS_H_
+# error The internal header gflags_gflags.h may only be included by gflags.h
+#endif
+
+#ifndef GFLAGS_NS_GFLAGS_H_
+#define GFLAGS_NS_GFLAGS_H_
+
+
+namespace gflags {
+
+
+using GFLAGS_NAMESPACE::int32;
+using GFLAGS_NAMESPACE::uint32;
+using GFLAGS_NAMESPACE::int64;
+using GFLAGS_NAMESPACE::uint64;
+
+using GFLAGS_NAMESPACE::RegisterFlagValidator;
+using GFLAGS_NAMESPACE::CommandLineFlagInfo;
+using GFLAGS_NAMESPACE::GetAllFlags;
+using GFLAGS_NAMESPACE::ShowUsageWithFlags;
+using GFLAGS_NAMESPACE::ShowUsageWithFlagsRestrict;
+using GFLAGS_NAMESPACE::DescribeOneFlag;
+using GFLAGS_NAMESPACE::SetArgv;
+using GFLAGS_NAMESPACE::GetArgvs;
+using GFLAGS_NAMESPACE::GetArgv;
+using GFLAGS_NAMESPACE::GetArgv0;
+using GFLAGS_NAMESPACE::GetArgvSum;
+using GFLAGS_NAMESPACE::ProgramInvocationName;
+using GFLAGS_NAMESPACE::ProgramInvocationShortName;
+using GFLAGS_NAMESPACE::ProgramUsage;
+using GFLAGS_NAMESPACE::VersionString;
+using GFLAGS_NAMESPACE::GetCommandLineOption;
+using GFLAGS_NAMESPACE::GetCommandLineFlagInfo;
+using GFLAGS_NAMESPACE::GetCommandLineFlagInfoOrDie;
+using GFLAGS_NAMESPACE::FlagSettingMode;
+using GFLAGS_NAMESPACE::SET_FLAGS_VALUE;
+using GFLAGS_NAMESPACE::SET_FLAG_IF_DEFAULT;
+using GFLAGS_NAMESPACE::SET_FLAGS_DEFAULT;
+using GFLAGS_NAMESPACE::SetCommandLineOption;
+using GFLAGS_NAMESPACE::SetCommandLineOptionWithMode;
+using GFLAGS_NAMESPACE::FlagSaver;
+using GFLAGS_NAMESPACE::CommandlineFlagsIntoString;
+using GFLAGS_NAMESPACE::ReadFlagsFromString;
+using GFLAGS_NAMESPACE::AppendFlagsIntoFile;
+using GFLAGS_NAMESPACE::ReadFromFlagsFile;
+using GFLAGS_NAMESPACE::BoolFromEnv;
+using GFLAGS_NAMESPACE::Int32FromEnv;
+using GFLAGS_NAMESPACE::Int64FromEnv;
+using GFLAGS_NAMESPACE::Uint64FromEnv;
+using GFLAGS_NAMESPACE::DoubleFromEnv;
+using GFLAGS_NAMESPACE::StringFromEnv;
+using GFLAGS_NAMESPACE::SetUsageMessage;
+using GFLAGS_NAMESPACE::SetVersionString;
+using GFLAGS_NAMESPACE::ParseCommandLineNonHelpFlags;
+using GFLAGS_NAMESPACE::HandleCommandLineHelpFlags;
+using GFLAGS_NAMESPACE::AllowCommandLineReparsing;
+using GFLAGS_NAMESPACE::ReparseCommandLineNonHelpFlags;
+using GFLAGS_NAMESPACE::ShutDownCommandLineFlags;
+using GFLAGS_NAMESPACE::FlagRegisterer;
+
+#ifndef SWIG
+using GFLAGS_NAMESPACE::ParseCommandLineFlags;
+#endif
+
+
+} // namespace gflags
+
+
+#endif // GFLAGS_NS_GFLAGS_H_
diff --git a/extern/gflags/src/gflags_completions.cc b/extern/gflags/src/gflags_completions.cc
new file mode 100644
index 00000000000..d7097caeef7
--- /dev/null
+++ b/extern/gflags/src/gflags_completions.cc
@@ -0,0 +1,771 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+
+// Bash-style command line flag completion for C++ binaries
+//
+// This module implements bash-style completions. It achieves this
+// goal in the following broad chunks:
+//
+// 1) Take a to-be-completed word, and examine it for search hints
+// 2) Identify all potentially matching flags
+// 2a) If there are no matching flags, do nothing.
+// 2b) If all matching flags share a common prefix longer than the
+// completion word, output just that matching prefix
+// 3) Categorize those flags to produce a rough ordering of relevence.
+// 4) Potentially trim the set of flags returned to a smaller number
+// that bash is happier with
+// 5) Output the matching flags in groups ordered by relevence.
+// 5a) Force bash to place most-relevent groups at the top of the list
+// 5b) Trim most flag's descriptions to fit on a single terminal line
+
+
+#include "gflags_completions.h"
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // for strlen
+
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gflags.h"
+#include "util.h"
+
+using std::set;
+using std::string;
+using std::vector;
+
+
+DEFINE_string(tab_completion_word, "",
+ "If non-empty, HandleCommandLineCompletions() will hijack the "
+ "process and attempt to do bash-style command line flag "
+ "completion on this value.");
+DEFINE_int32(tab_completion_columns, 80,
+ "Number of columns to use in output for tab completion");
+
+
+namespace GFLAGS_NAMESPACE {
+
+
+namespace {
+// Function prototypes and Type forward declarations. Code may be
+// more easily understood if it is roughly ordered according to
+// control flow, rather than by C's "declare before use" ordering
+struct CompletionOptions;
+struct NotableFlags;
+
+// The entry point if flag completion is to be used.
+static void PrintFlagCompletionInfo(void);
+
+
+// 1) Examine search word
+static void CanonicalizeCursorWordAndSearchOptions(
+ const string &cursor_word,
+ string *canonical_search_token,
+ CompletionOptions *options);
+
+static bool RemoveTrailingChar(string *str, char c);
+
+
+// 2) Find all matches
+static void FindMatchingFlags(
+ const vector<CommandLineFlagInfo> &all_flags,
+ const CompletionOptions &options,
+ const string &match_token,
+ set<const CommandLineFlagInfo *> *all_matches,
+ string *longest_common_prefix);
+
+static bool DoesSingleFlagMatch(
+ const CommandLineFlagInfo &flag,
+ const CompletionOptions &options,
+ const string &match_token);
+
+
+// 3) Categorize matches
+static void CategorizeAllMatchingFlags(
+ const set<const CommandLineFlagInfo *> &all_matches,
+ const string &search_token,
+ const string &module,
+ const string &package_dir,
+ NotableFlags *notable_flags);
+
+static void TryFindModuleAndPackageDir(
+ const vector<CommandLineFlagInfo> all_flags,
+ string *module,
+ string *package_dir);
+
+
+// 4) Decide which flags to use
+static void FinalizeCompletionOutput(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ CompletionOptions *options,
+ NotableFlags *notable_flags,
+ vector<string> *completions);
+
+static void RetrieveUnusedFlags(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ const NotableFlags &notable_flags,
+ set<const CommandLineFlagInfo *> *unused_flags);
+
+
+// 5) Output matches
+static void OutputSingleGroupWithLimit(
+ const set<const CommandLineFlagInfo *> &group,
+ const string &line_indentation,
+ const string &header,
+ const string &footer,
+ bool long_output_format,
+ int *remaining_line_limit,
+ size_t *completion_elements_added,
+ vector<string> *completions);
+
+// (helpers for #5)
+static string GetShortFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info);
+
+static string GetLongFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info);
+
+
+//
+// Useful types
+
+// Try to deduce the intentions behind this completion attempt. Return the
+// canonical search term in 'canonical_search_token'. Binary search options
+// are returned in the various booleans, which should all have intuitive
+// semantics, possibly except:
+// - return_all_matching_flags: Generally, we'll trim the number of
+// returned candidates to some small number, showing those that are
+// most likely to be useful first. If this is set, however, the user
+// really does want us to return every single flag as an option.
+// - force_no_update: Any time we output lines, all of which share a
+// common prefix, bash will 'helpfully' not even bother to show the
+// output, instead changing the current word to be that common prefix.
+// If it's clear this shouldn't happen, we'll set this boolean
+struct CompletionOptions {
+ bool flag_name_substring_search;
+ bool flag_location_substring_search;
+ bool flag_description_substring_search;
+ bool return_all_matching_flags;
+ bool force_no_update;
+};
+
+// Notable flags are flags that are special or preferred for some
+// reason. For example, flags that are defined in the binary's module
+// are expected to be much more relevent than flags defined in some
+// other random location. These sets are specified roughly in precedence
+// order. Once a flag is placed in one of these 'higher' sets, it won't
+// be placed in any of the 'lower' sets.
+struct NotableFlags {
+ typedef set<const CommandLineFlagInfo *> FlagSet;
+ FlagSet perfect_match_flag;
+ FlagSet module_flags; // Found in module file
+ FlagSet package_flags; // Found in same directory as module file
+ FlagSet most_common_flags; // One of the XXX most commonly supplied flags
+ FlagSet subpackage_flags; // Found in subdirectories of package
+};
+
+
+//
+// Tab completion implementation - entry point
+static void PrintFlagCompletionInfo(void) {
+ string cursor_word = FLAGS_tab_completion_word;
+ string canonical_token;
+ CompletionOptions options = { };
+ CanonicalizeCursorWordAndSearchOptions(
+ cursor_word,
+ &canonical_token,
+ &options);
+
+ DVLOG(1) << "Identified canonical_token: '" << canonical_token << "'";
+
+ vector<CommandLineFlagInfo> all_flags;
+ set<const CommandLineFlagInfo *> matching_flags;
+ GetAllFlags(&all_flags);
+ DVLOG(2) << "Found " << all_flags.size() << " flags overall";
+
+ string longest_common_prefix;
+ FindMatchingFlags(
+ all_flags,
+ options,
+ canonical_token,
+ &matching_flags,
+ &longest_common_prefix);
+ DVLOG(1) << "Identified " << matching_flags.size() << " matching flags";
+ DVLOG(1) << "Identified " << longest_common_prefix
+ << " as longest common prefix.";
+ if (longest_common_prefix.size() > canonical_token.size()) {
+ // There's actually a shared common prefix to all matching flags,
+ // so may as well output that and quit quickly.
+ DVLOG(1) << "The common prefix '" << longest_common_prefix
+ << "' was longer than the token '" << canonical_token
+ << "'. Returning just this prefix for completion.";
+ fprintf(stdout, "--%s", longest_common_prefix.c_str());
+ return;
+ }
+ if (matching_flags.empty()) {
+ VLOG(1) << "There were no matching flags, returning nothing.";
+ return;
+ }
+
+ string module;
+ string package_dir;
+ TryFindModuleAndPackageDir(all_flags, &module, &package_dir);
+ DVLOG(1) << "Identified module: '" << module << "'";
+ DVLOG(1) << "Identified package_dir: '" << package_dir << "'";
+
+ NotableFlags notable_flags;
+ CategorizeAllMatchingFlags(
+ matching_flags,
+ canonical_token,
+ module,
+ package_dir,
+ &notable_flags);
+ DVLOG(2) << "Categorized matching flags:";
+ DVLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size();
+ DVLOG(2) << " module: " << notable_flags.module_flags.size();
+ DVLOG(2) << " package: " << notable_flags.package_flags.size();
+ DVLOG(2) << " most common: " << notable_flags.most_common_flags.size();
+ DVLOG(2) << " subpackage: " << notable_flags.subpackage_flags.size();
+
+ vector<string> completions;
+ FinalizeCompletionOutput(
+ matching_flags,
+ &options,
+ &notable_flags,
+ &completions);
+
+ if (options.force_no_update)
+ completions.push_back("~");
+
+ DVLOG(1) << "Finalized with " << completions.size()
+ << " chosen completions";
+
+ for (vector<string>::const_iterator it = completions.begin();
+ it != completions.end();
+ ++it) {
+ DVLOG(9) << " Completion entry: '" << *it << "'";
+ fprintf(stdout, "%s\n", it->c_str());
+ }
+}
+
+
+// 1) Examine search word (and helper method)
+static void CanonicalizeCursorWordAndSearchOptions(
+ const string &cursor_word,
+ string *canonical_search_token,
+ CompletionOptions *options) {
+ *canonical_search_token = cursor_word;
+ if (canonical_search_token->empty()) return;
+
+ // Get rid of leading quotes and dashes in the search term
+ if ((*canonical_search_token)[0] == '"')
+ *canonical_search_token = canonical_search_token->substr(1);
+ while ((*canonical_search_token)[0] == '-')
+ *canonical_search_token = canonical_search_token->substr(1);
+
+ options->flag_name_substring_search = false;
+ options->flag_location_substring_search = false;
+ options->flag_description_substring_search = false;
+ options->return_all_matching_flags = false;
+ options->force_no_update = false;
+
+ // Look for all search options we can deduce now. Do this by walking
+ // backwards through the term, looking for up to three '?' and up to
+ // one '+' as suffixed characters. Consume them if found, and remove
+ // them from the canonical search token.
+ int found_question_marks = 0;
+ int found_plusses = 0;
+ while (true) {
+ if (found_question_marks < 3 &&
+ RemoveTrailingChar(canonical_search_token, '?')) {
+ ++found_question_marks;
+ continue;
+ }
+ if (found_plusses < 1 &&
+ RemoveTrailingChar(canonical_search_token, '+')) {
+ ++found_plusses;
+ continue;
+ }
+ break;
+ }
+
+ switch (found_question_marks) { // all fallthroughs
+ case 3: options->flag_description_substring_search = true;
+ case 2: options->flag_location_substring_search = true;
+ case 1: options->flag_name_substring_search = true;
+ };
+
+ options->return_all_matching_flags = (found_plusses > 0);
+}
+
+// Returns true if a char was removed
+static bool RemoveTrailingChar(string *str, char c) {
+ if (str->empty()) return false;
+ if ((*str)[str->size() - 1] == c) {
+ *str = str->substr(0, str->size() - 1);
+ return true;
+ }
+ return false;
+}
+
+
+// 2) Find all matches (and helper methods)
+static void FindMatchingFlags(
+ const vector<CommandLineFlagInfo> &all_flags,
+ const CompletionOptions &options,
+ const string &match_token,
+ set<const CommandLineFlagInfo *> *all_matches,
+ string *longest_common_prefix) {
+ all_matches->clear();
+ bool first_match = true;
+ for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
+ it != all_flags.end();
+ ++it) {
+ if (DoesSingleFlagMatch(*it, options, match_token)) {
+ all_matches->insert(&*it);
+ if (first_match) {
+ first_match = false;
+ *longest_common_prefix = it->name;
+ } else {
+ if (longest_common_prefix->empty() || it->name.empty()) {
+ longest_common_prefix->clear();
+ continue;
+ }
+ string::size_type pos = 0;
+ while (pos < longest_common_prefix->size() &&
+ pos < it->name.size() &&
+ (*longest_common_prefix)[pos] == it->name[pos])
+ ++pos;
+ longest_common_prefix->erase(pos);
+ }
+ }
+ }
+}
+
+// Given the set of all flags, the parsed match options, and the
+// canonical search token, produce the set of all candidate matching
+// flags for subsequent analysis or filtering.
+static bool DoesSingleFlagMatch(
+ const CommandLineFlagInfo &flag,
+ const CompletionOptions &options,
+ const string &match_token) {
+ // Is there a prefix match?
+ string::size_type pos = flag.name.find(match_token);
+ if (pos == 0) return true;
+
+ // Is there a substring match if we want it?
+ if (options.flag_name_substring_search &&
+ pos != string::npos)
+ return true;
+
+ // Is there a location match if we want it?
+ if (options.flag_location_substring_search &&
+ flag.filename.find(match_token) != string::npos)
+ return true;
+
+ // TODO(user): All searches should probably be case-insensitive
+ // (especially this one...)
+ if (options.flag_description_substring_search &&
+ flag.description.find(match_token) != string::npos)
+ return true;
+
+ return false;
+}
+
+// 3) Categorize matches (and helper method)
+
+// Given a set of matching flags, categorize them by
+// likely relevence to this specific binary
+static void CategorizeAllMatchingFlags(
+ const set<const CommandLineFlagInfo *> &all_matches,
+ const string &search_token,
+ const string &module, // empty if we couldn't find any
+ const string &package_dir, // empty if we couldn't find any
+ NotableFlags *notable_flags) {
+ notable_flags->perfect_match_flag.clear();
+ notable_flags->module_flags.clear();
+ notable_flags->package_flags.clear();
+ notable_flags->most_common_flags.clear();
+ notable_flags->subpackage_flags.clear();
+
+ for (set<const CommandLineFlagInfo *>::const_iterator it =
+ all_matches.begin();
+ it != all_matches.end();
+ ++it) {
+ DVLOG(2) << "Examining match '" << (*it)->name << "'";
+ DVLOG(7) << " filename: '" << (*it)->filename << "'";
+ string::size_type pos = string::npos;
+ if (!package_dir.empty())
+ pos = (*it)->filename.find(package_dir);
+ string::size_type slash = string::npos;
+ if (pos != string::npos) // candidate for package or subpackage match
+ slash = (*it)->filename.find(
+ PATH_SEPARATOR,
+ pos + package_dir.size() + 1);
+
+ if ((*it)->name == search_token) {
+ // Exact match on some flag's name
+ notable_flags->perfect_match_flag.insert(*it);
+ DVLOG(3) << "Result: perfect match";
+ } else if (!module.empty() && (*it)->filename == module) {
+ // Exact match on module filename
+ notable_flags->module_flags.insert(*it);
+ DVLOG(3) << "Result: module match";
+ } else if (!package_dir.empty() &&
+ pos != string::npos && slash == string::npos) {
+ // In the package, since there was no slash after the package portion
+ notable_flags->package_flags.insert(*it);
+ DVLOG(3) << "Result: package match";
+ } else if (false) {
+ // In the list of the XXX most commonly supplied flags overall
+ // TODO(user): Compile this list.
+ DVLOG(3) << "Result: most-common match";
+ } else if (!package_dir.empty() &&
+ pos != string::npos && slash != string::npos) {
+ // In a subdirectory of the package
+ notable_flags->subpackage_flags.insert(*it);
+ DVLOG(3) << "Result: subpackage match";
+ }
+
+ DVLOG(3) << "Result: not special match";
+ }
+}
+
+static void PushNameWithSuffix(vector<string>* suffixes, const char* suffix) {
+ suffixes->push_back(
+ StringPrintf("/%s%s", ProgramInvocationShortName(), suffix));
+}
+
+static void TryFindModuleAndPackageDir(
+ const vector<CommandLineFlagInfo> all_flags,
+ string *module,
+ string *package_dir) {
+ module->clear();
+ package_dir->clear();
+
+ vector<string> suffixes;
+ // TODO(user): There's some inherant ambiguity here - multiple directories
+ // could share the same trailing folder and file structure (and even worse,
+ // same file names), causing us to be unsure as to which of the two is the
+ // actual package for this binary. In this case, we'll arbitrarily choose.
+ PushNameWithSuffix(&suffixes, ".");
+ PushNameWithSuffix(&suffixes, "-main.");
+ PushNameWithSuffix(&suffixes, "_main.");
+ // These four are new but probably merited?
+ PushNameWithSuffix(&suffixes, "-test.");
+ PushNameWithSuffix(&suffixes, "_test.");
+ PushNameWithSuffix(&suffixes, "-unittest.");
+ PushNameWithSuffix(&suffixes, "_unittest.");
+
+ for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
+ it != all_flags.end();
+ ++it) {
+ for (vector<string>::const_iterator suffix = suffixes.begin();
+ suffix != suffixes.end();
+ ++suffix) {
+ // TODO(user): Make sure the match is near the end of the string
+ if (it->filename.find(*suffix) != string::npos) {
+ *module = it->filename;
+ string::size_type sep = it->filename.rfind(PATH_SEPARATOR);
+ *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep);
+ return;
+ }
+ }
+ }
+}
+
+// Can't specialize template type on a locally defined type. Silly C++...
+struct DisplayInfoGroup {
+ const char* header;
+ const char* footer;
+ set<const CommandLineFlagInfo *> *group;
+
+ int SizeInLines() const {
+ int size_in_lines = static_cast<int>(group->size()) + 1;
+ if (strlen(header) > 0) {
+ size_in_lines++;
+ }
+ if (strlen(footer) > 0) {
+ size_in_lines++;
+ }
+ return size_in_lines;
+ }
+};
+
+// 4) Finalize and trim output flag set
+static void FinalizeCompletionOutput(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ CompletionOptions *options,
+ NotableFlags *notable_flags,
+ vector<string> *completions) {
+
+ // We want to output lines in groups. Each group needs to be indented
+ // the same to keep its lines together. Unless otherwise required,
+ // only 99 lines should be output to prevent bash from harassing the
+ // user.
+
+ // First, figure out which output groups we'll actually use. For each
+ // nonempty group, there will be ~3 lines of header & footer, plus all
+ // output lines themselves.
+ int max_desired_lines = // "999999 flags should be enough for anyone. -dave"
+ (options->return_all_matching_flags ? 999999 : 98);
+ int lines_so_far = 0;
+
+ vector<DisplayInfoGroup> output_groups;
+ bool perfect_match_found = false;
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->perfect_match_flag.empty()) {
+ perfect_match_found = true;
+ DisplayInfoGroup group =
+ { "",
+ "==========",
+ &notable_flags->perfect_match_flag };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->module_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Matching module flags *-",
+ "===========================",
+ &notable_flags->module_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->package_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Matching package flags *-",
+ "============================",
+ &notable_flags->package_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->most_common_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Commonly used flags *-",
+ "=========================",
+ &notable_flags->most_common_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ if (lines_so_far < max_desired_lines &&
+ !notable_flags->subpackage_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Matching sub-package flags *-",
+ "================================",
+ &notable_flags->subpackage_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+
+ set<const CommandLineFlagInfo *> obscure_flags; // flags not notable
+ if (lines_so_far < max_desired_lines) {
+ RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags);
+ if (!obscure_flags.empty()) {
+ DisplayInfoGroup group = {
+ "-* Other flags *-",
+ "",
+ &obscure_flags };
+ lines_so_far += group.SizeInLines();
+ output_groups.push_back(group);
+ }
+ }
+
+ // Second, go through each of the chosen output groups and output
+ // as many of those flags as we can, while remaining below our limit
+ int remaining_lines = max_desired_lines;
+ size_t completions_output = 0;
+ int indent = static_cast<int>(output_groups.size()) - 1;
+ for (vector<DisplayInfoGroup>::const_iterator it =
+ output_groups.begin();
+ it != output_groups.end();
+ ++it, --indent) {
+ OutputSingleGroupWithLimit(
+ *it->group, // group
+ string(indent, ' '), // line indentation
+ string(it->header), // header
+ string(it->footer), // footer
+ perfect_match_found, // long format
+ &remaining_lines, // line limit - reduces this by number printed
+ &completions_output, // completions (not lines) added
+ completions); // produced completions
+ perfect_match_found = false;
+ }
+
+ if (completions_output != matching_flags.size()) {
+ options->force_no_update = false;
+ completions->push_back("~ (Remaining flags hidden) ~");
+ } else {
+ options->force_no_update = true;
+ }
+}
+
+static void RetrieveUnusedFlags(
+ const set<const CommandLineFlagInfo *> &matching_flags,
+ const NotableFlags &notable_flags,
+ set<const CommandLineFlagInfo *> *unused_flags) {
+ // Remove from 'matching_flags' set all members of the sets of
+ // flags we've already printed (specifically, those in notable_flags)
+ for (set<const CommandLineFlagInfo *>::const_iterator it =
+ matching_flags.begin();
+ it != matching_flags.end();
+ ++it) {
+ if (notable_flags.perfect_match_flag.count(*it) ||
+ notable_flags.module_flags.count(*it) ||
+ notable_flags.package_flags.count(*it) ||
+ notable_flags.most_common_flags.count(*it) ||
+ notable_flags.subpackage_flags.count(*it))
+ continue;
+ unused_flags->insert(*it);
+ }
+}
+
+// 5) Output matches (and helper methods)
+
+static void OutputSingleGroupWithLimit(
+ const set<const CommandLineFlagInfo *> &group,
+ const string &line_indentation,
+ const string &header,
+ const string &footer,
+ bool long_output_format,
+ int *remaining_line_limit,
+ size_t *completion_elements_output,
+ vector<string> *completions) {
+ if (group.empty()) return;
+ if (!header.empty()) {
+ if (*remaining_line_limit < 2) return;
+ *remaining_line_limit -= 2;
+ completions->push_back(line_indentation + header);
+ completions->push_back(line_indentation + string(header.size(), '-'));
+ }
+ for (set<const CommandLineFlagInfo *>::const_iterator it = group.begin();
+ it != group.end() && *remaining_line_limit > 0;
+ ++it) {
+ --*remaining_line_limit;
+ ++*completion_elements_output;
+ completions->push_back(
+ (long_output_format
+ ? GetLongFlagLine(line_indentation, **it)
+ : GetShortFlagLine(line_indentation, **it)));
+ }
+ if (!footer.empty()) {
+ if (*remaining_line_limit < 1) return;
+ --*remaining_line_limit;
+ completions->push_back(line_indentation + footer);
+ }
+}
+
+static string GetShortFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info) {
+ string prefix;
+ bool is_string = (info.type == "string");
+ SStringPrintf(&prefix, "%s--%s [%s%s%s] ",
+ line_indentation.c_str(),
+ info.name.c_str(),
+ (is_string ? "'" : ""),
+ info.default_value.c_str(),
+ (is_string ? "'" : ""));
+ int remainder =
+ FLAGS_tab_completion_columns - static_cast<int>(prefix.size());
+ string suffix;
+ if (remainder > 0)
+ suffix =
+ (static_cast<int>(info.description.size()) > remainder ?
+ (info.description.substr(0, remainder - 3) + "...").c_str() :
+ info.description.c_str());
+ return prefix + suffix;
+}
+
+static string GetLongFlagLine(
+ const string &line_indentation,
+ const CommandLineFlagInfo &info) {
+
+ string output = DescribeOneFlag(info);
+
+ // Replace '-' with '--', and remove trailing newline before appending
+ // the module definition location.
+ string old_flagname = "-" + info.name;
+ output.replace(
+ output.find(old_flagname),
+ old_flagname.size(),
+ "-" + old_flagname);
+ // Stick a newline and indentation in front of the type and default
+ // portions of DescribeOneFlag()s description
+ static const char kNewlineWithIndent[] = "\n ";
+ output.replace(output.find(" type:"), 1, string(kNewlineWithIndent));
+ output.replace(output.find(" default:"), 1, string(kNewlineWithIndent));
+ output = StringPrintf("%s Details for '--%s':\n"
+ "%s defined: %s",
+ line_indentation.c_str(),
+ info.name.c_str(),
+ output.c_str(),
+ info.filename.c_str());
+
+ // Eliminate any doubled newlines that crept in. Specifically, if
+ // DescribeOneFlag() decided to break the line just before "type"
+ // or "default", we don't want to introduce an extra blank line
+ static const string line_of_spaces(FLAGS_tab_completion_columns, ' ');
+ static const char kDoubledNewlines[] = "\n \n";
+ for (string::size_type newlines = output.find(kDoubledNewlines);
+ newlines != string::npos;
+ newlines = output.find(kDoubledNewlines))
+ // Replace each 'doubled newline' with a single newline
+ output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n"));
+
+ for (string::size_type newline = output.find('\n');
+ newline != string::npos;
+ newline = output.find('\n')) {
+ int newline_pos = static_cast<int>(newline) % FLAGS_tab_completion_columns;
+ int missing_spaces = FLAGS_tab_completion_columns - newline_pos;
+ output.replace(newline, 1, line_of_spaces, 1, missing_spaces);
+ }
+ return output;
+}
+} // anonymous
+
+void HandleCommandLineCompletions(void) {
+ if (FLAGS_tab_completion_word.empty()) return;
+ PrintFlagCompletionInfo();
+ gflags_exitfunc(0);
+}
+
+
+} // namespace GFLAGS_NAMESPACE
diff --git a/extern/libmv/third_party/gflags/gflags_reporting.cc b/extern/gflags/src/gflags_reporting.cc
index 9cc41a7488c..9cc41a7488c 100644
--- a/extern/libmv/third_party/gflags/gflags_reporting.cc
+++ b/extern/gflags/src/gflags_reporting.cc
diff --git a/extern/gflags/src/mutex.h b/extern/gflags/src/mutex.h
new file mode 100644
index 00000000000..ff96f2b67f7
--- /dev/null
+++ b/extern/gflags/src/mutex.h
@@ -0,0 +1,348 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+//
+// A simple mutex wrapper, supporting locks and read-write locks.
+// You should assume the locks are *not* re-entrant.
+//
+// This class is meant to be internal-only and should be wrapped by an
+// internal namespace. Before you use this module, please give the
+// name of your internal namespace for this module. Or, if you want
+// to expose it, you'll want to move it to the Google namespace. We
+// cannot put this class in global namespace because there can be some
+// problems when we have multiple versions of Mutex in each shared object.
+//
+// NOTE: by default, we have #ifdef'ed out the TryLock() method.
+// This is for two reasons:
+// 1) TryLock() under Windows is a bit annoying (it requires a
+// #define to be defined very early).
+// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
+// mode.
+// If you need TryLock(), and either these two caveats are not a
+// problem for you, or you're willing to work around them, then
+// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
+// in the code below.
+//
+// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
+// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
+// Because of that, we might as well use windows locks for
+// cygwin. They seem to be more reliable than the cygwin pthreads layer.
+//
+// TRICKY IMPLEMENTATION NOTE:
+// This class is designed to be safe to use during
+// dynamic-initialization -- that is, by global constructors that are
+// run before main() starts. The issue in this case is that
+// dynamic-initialization happens in an unpredictable order, and it
+// could be that someone else's dynamic initializer could call a
+// function that tries to acquire this mutex -- but that all happens
+// before this mutex's constructor has run. (This can happen even if
+// the mutex and the function that uses the mutex are in the same .cc
+// file.) Basically, because Mutex does non-trivial work in its
+// constructor, it's not, in the naive implementation, safe to use
+// before dynamic initialization has run on it.
+//
+// The solution used here is to pair the actual mutex primitive with a
+// bool that is set to true when the mutex is dynamically initialized.
+// (Before that it's false.) Then we modify all mutex routines to
+// look at the bool, and not try to lock/unlock until the bool makes
+// it to true (which happens after the Mutex constructor has run.)
+//
+// This works because before main() starts -- particularly, during
+// dynamic initialization -- there are no threads, so a) it's ok that
+// the mutex operations are a no-op, since we don't need locking then
+// anyway; and b) we can be quite confident our bool won't change
+// state between a call to Lock() and a call to Unlock() (that would
+// require a global constructor in one translation unit to call Lock()
+// and another global constructor in another translation unit to call
+// Unlock() later, which is pretty perverse).
+//
+// That said, it's tricky, and can conceivably fail; it's safest to
+// avoid trying to acquire a mutex in a global constructor, if you
+// can. One way it can fail is that a really smart compiler might
+// initialize the bool to true at static-initialization time (too
+// early) rather than at dynamic-initialization time. To discourage
+// that, we set is_safe_ to true in code (not the constructor
+// colon-initializer) and set it to true via a function that always
+// evaluates to true, but that the compiler can't know always
+// evaluates to true. This should be good enough.
+//
+// A related issue is code that could try to access the mutex
+// after it's been destroyed in the global destructors (because
+// the Mutex global destructor runs before some other global
+// destructor, that tries to acquire the mutex). The way we
+// deal with this is by taking a constructor arg that global
+// mutexes should pass in, that causes the destructor to do no
+// work. We still depend on the compiler not doing anything
+// weird to a Mutex's memory after it is destroyed, but for a
+// static global variable, that's pretty safe.
+
+#ifndef GFLAGS_MUTEX_H_
+#define GFLAGS_MUTEX_H_
+
+#include "gflags_declare.h" // to figure out pthreads support
+
+#if defined(NO_THREADS)
+ typedef int MutexType; // to keep a lock-count
+#elif defined(OS_WINDOWS)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN // We only need minimal includes
+# endif
+# ifndef NOMINMAX
+# define NOMINMAX // Don't want windows to override min()/max()
+# endif
+# ifdef GMUTEX_TRYLOCK
+ // We need Windows NT or later for TryEnterCriticalSection(). If you
+ // don't need that functionality, you can remove these _WIN32_WINNT
+ // lines, and change TryLock() to assert(0) or something.
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+# endif
+# endif
+# include <windows.h>
+ typedef CRITICAL_SECTION MutexType;
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+ // Needed for pthread_rwlock_*. If it causes problems, you could take it
+ // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
+ // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
+ // for locking there.)
+# ifdef __linux__
+# if _XOPEN_SOURCE < 500 // including not being defined at all
+# undef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
+# endif
+# endif
+# include <pthread.h>
+ typedef pthread_rwlock_t MutexType;
+#elif defined(HAVE_PTHREAD)
+# include <pthread.h>
+ typedef pthread_mutex_t MutexType;
+#else
+# error Need to implement mutex.h for your architecture, or #define NO_THREADS
+#endif
+
+#include <assert.h>
+#include <stdlib.h> // for abort()
+
+#define MUTEX_NAMESPACE gflags_mutex_namespace
+
+namespace MUTEX_NAMESPACE {
+
+class Mutex {
+ public:
+ // This is used for the single-arg constructor
+ enum LinkerInitialized { LINKER_INITIALIZED };
+
+ // Create a Mutex that is not held by anybody. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ inline Mutex();
+ // This constructor should be used for global, static Mutex objects.
+ // It inhibits work being done by the destructor, which makes it
+ // safer for code that tries to acqiure this mutex in their global
+ // destructor.
+ inline Mutex(LinkerInitialized);
+
+ // Destructor
+ inline ~Mutex();
+
+ inline void Lock(); // Block if needed until free then acquire exclusively
+ inline void Unlock(); // Release a lock acquired via Lock()
+#ifdef GMUTEX_TRYLOCK
+ inline bool TryLock(); // If free, Lock() and return true, else return false
+#endif
+ // Note that on systems that don't support read-write locks, these may
+ // be implemented as synonyms to Lock() and Unlock(). So you can use
+ // these for efficiency, but don't use them anyplace where being able
+ // to do shared reads is necessary to avoid deadlock.
+ inline void ReaderLock(); // Block until free or shared then acquire a share
+ inline void ReaderUnlock(); // Release a read share of this Mutex
+ inline void WriterLock() { Lock(); } // Acquire an exclusive lock
+ inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
+
+ private:
+ MutexType mutex_;
+ // We want to make sure that the compiler sets is_safe_ to true only
+ // when we tell it to, and never makes assumptions is_safe_ is
+ // always true. volatile is the most reliable way to do that.
+ volatile bool is_safe_;
+ // This indicates which constructor was called.
+ bool destroy_;
+
+ inline void SetIsSafe() { is_safe_ = true; }
+
+ // Catch the error of writing Mutex when intending MutexLock.
+ Mutex(Mutex* /*ignored*/) {}
+ // Disallow "evil" constructors
+ Mutex(const Mutex&);
+ void operator=(const Mutex&);
+};
+
+// Now the implementation of Mutex for various systems
+#if defined(NO_THREADS)
+
+// When we don't have threads, we can be either reading or writing,
+// but not both. We can have lots of readers at once (in no-threads
+// mode, that's most likely to happen in recursive function calls),
+// but only one writer. We represent this by having mutex_ be -1 when
+// writing and a number > 0 when reading (and 0 when no lock is held).
+//
+// In debug mode, we assert these invariants, while in non-debug mode
+// we do nothing, for efficiency. That's why everything is in an
+// assert.
+
+Mutex::Mutex() : mutex_(0) { }
+Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { }
+Mutex::~Mutex() { assert(mutex_ == 0); }
+void Mutex::Lock() { assert(--mutex_ == -1); }
+void Mutex::Unlock() { assert(mutex_++ == -1); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
+#endif
+void Mutex::ReaderLock() { assert(++mutex_ > 0); }
+void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
+
+#elif defined(OS_WINDOWS)
+
+Mutex::Mutex() : destroy_(true) {
+ InitializeCriticalSection(&mutex_);
+ SetIsSafe();
+}
+Mutex::Mutex(LinkerInitialized) : destroy_(false) {
+ InitializeCriticalSection(&mutex_);
+ SetIsSafe();
+}
+Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); }
+void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
+void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ TryEnterCriticalSection(&mutex_) != 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+void Mutex::ReaderUnlock() { Unlock(); }
+
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() : destroy_(true) {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_rwlock_trywrlock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
+void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#undef SAFE_PTHREAD
+
+#elif defined(HAVE_PTHREAD)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() : destroy_(true) {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_mutex_trylock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); }
+void Mutex::ReaderUnlock() { Unlock(); }
+#undef SAFE_PTHREAD
+
+#endif
+
+// --------------------------------------------------------------------------
+// Some helper classes
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class MutexLock {
+ public:
+ explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
+ ~MutexLock() { mu_->Unlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ MutexLock(const MutexLock&);
+ void operator=(const MutexLock&);
+};
+
+// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
+class ReaderMutexLock {
+ public:
+ explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
+ ~ReaderMutexLock() { mu_->ReaderUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ ReaderMutexLock(const ReaderMutexLock&);
+ void operator=(const ReaderMutexLock&);
+};
+
+class WriterMutexLock {
+ public:
+ explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
+ ~WriterMutexLock() { mu_->WriterUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ WriterMutexLock(const WriterMutexLock&);
+ void operator=(const WriterMutexLock&);
+};
+
+// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
+#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
+#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
+#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
+
+} // namespace MUTEX_NAMESPACE
+
+
+#endif /* #define GFLAGS_MUTEX_H__ */
diff --git a/extern/gflags/src/util.h b/extern/gflags/src/util.h
new file mode 100644
index 00000000000..fb59b38ddc4
--- /dev/null
+++ b/extern/gflags/src/util.h
@@ -0,0 +1,374 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// ---
+//
+// Some generically useful utility routines that in google-land would
+// be their own projects. We make a shortened version here.
+
+#ifndef GFLAGS_UTIL_H_
+#define GFLAGS_UTIL_H_
+
+#include "config.h"
+
+#include <assert.h>
+#include <config.h>
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#include <stdarg.h> // for va_*
+#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
+#include <string>
+#include <errno.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h> // for mkdir
+#endif
+
+
+namespace GFLAGS_NAMESPACE {
+
+
+// This is used for unittests for death-testing. It is defined in gflags.cc.
+extern GFLAGS_DLL_DECL void (*gflags_exitfunc)(int);
+
+// Work properly if either strtoll or strtoq is on this system.
+#if defined(strtoll) || defined(HAVE_STRTOLL)
+# define strto64 strtoll
+# define strtou64 strtoull
+#elif defined(HAVE_STRTOQ)
+# define strto64 strtoq
+# define strtou64 strtouq
+// Neither strtoll nor strtoq are defined. I hope strtol works!
+#else
+# define strto64 strtol
+# define strtou64 strtoul
+#endif
+
+// If we have inttypes.h, it will have defined PRId32/etc for us.
+// If not, take our best guess.
+#ifndef PRId32
+# define PRId32 "d"
+#endif
+#ifndef PRId64
+# define PRId64 "lld"
+#endif
+#ifndef PRIu64
+# define PRIu64 "llu"
+#endif
+
+typedef signed char int8;
+typedef unsigned char uint8;
+
+// -- utility macros ---------------------------------------------------------
+
+template <bool b> struct CompileAssert;
+template <> struct CompileAssert<true> {};
+#define COMPILE_ASSERT(expr, msg) \
+ enum { assert_##msg = sizeof(CompileAssert<bool(expr)>) }
+
+// Returns the number of elements in an array.
+#define arraysize(arr) (sizeof(arr)/sizeof(*(arr)))
+
+
+// -- logging and testing ---------------------------------------------------
+
+// For now, we ignore the level for logging, and don't show *VLOG's at
+// all, except by hand-editing the lines below
+#define LOG(level) std::cerr
+#define VLOG(level) if (true) {} else std::cerr
+#define DVLOG(level) if (true) {} else std::cerr
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode. Therefore, it is safe to do things like:
+// CHECK(fp->Write(x) == 4)
+// We allow stream-like objects after this for debugging, but they're ignored.
+#define EXPECT_TRUE(condition) \
+ if (true) { \
+ if (!(condition)) { \
+ fprintf(stderr, "Check failed: %s\n", #condition); \
+ exit(1); \
+ } \
+ } else std::cerr << ""
+
+#define EXPECT_OP(op, val1, val2) \
+ if (true) { \
+ if (!((val1) op (val2))) { \
+ fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
+ exit(1); \
+ } \
+ } else std::cerr << ""
+
+#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
+#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
+#define EXPECT_LE(val1, val2) EXPECT_OP(<=, val1, val2)
+#define EXPECT_LT(val1, val2) EXPECT_OP(< , val1, val2)
+#define EXPECT_GE(val1, val2) EXPECT_OP(>=, val1, val2)
+#define EXPECT_GT(val1, val2) EXPECT_OP(> , val1, val2)
+#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
+
+// C99 declares isnan and isinf should be macros, so the #ifdef test
+// should be reliable everywhere. Of course, it's not, but these
+// are testing pertty marginal functionality anyway, so it's ok to
+// not-run them even in situations they might, with effort, be made to work.
+#ifdef isnan // Some compilers, like sun's for Solaris 10, don't define this
+#define EXPECT_NAN(arg) \
+ do { \
+ if (!isnan(arg)) { \
+ fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
+ exit(1); \
+ } \
+ } while (0)
+#else
+#define EXPECT_NAN(arg)
+#endif
+
+#ifdef isinf // Some compilers, like sun's for Solaris 10, don't define this
+#define EXPECT_INF(arg) \
+ do { \
+ if (!isinf(arg)) { \
+ fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
+ exit(1); \
+ } \
+ } while (0)
+#else
+#define EXPECT_INF(arg)
+#endif
+
+#define EXPECT_DOUBLE_EQ(val1, val2) \
+ do { \
+ if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
+ fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
+ exit(1); \
+ } \
+ } while (0)
+
+#define EXPECT_STREQ(val1, val2) \
+ do { \
+ if (strcmp((val1), (val2)) != 0) { \
+ fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
+ exit(1); \
+ } \
+ } while (0)
+
+// Call this in a .cc file where you will later call RUN_ALL_TESTS in main().
+#define TEST_INIT \
+ static std::vector<void (*)()> g_testlist; /* the tests to run */ \
+ static int RUN_ALL_TESTS() { \
+ std::vector<void (*)()>::const_iterator it; \
+ for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { \
+ (*it)(); /* The test will error-exit if there's a problem. */ \
+ } \
+ fprintf(stderr, "\nPassed %d tests\n\nPASS\n", \
+ static_cast<int>(g_testlist.size())); \
+ return 0; \
+ }
+
+// Note that this macro uses a FlagSaver to keep tests isolated.
+#define TEST(a, b) \
+ struct Test_##a##_##b { \
+ Test_##a##_##b() { g_testlist.push_back(&Run); } \
+ static void Run() { \
+ FlagSaver fs; \
+ fprintf(stderr, "Running test %s/%s\n", #a, #b); \
+ RunTest(); \
+ } \
+ static void RunTest(); \
+ }; \
+ static Test_##a##_##b g_test_##a##_##b; \
+ void Test_##a##_##b::RunTest()
+
+// This is a dummy class that eases the google->opensource transition.
+namespace testing {
+class Test {};
+}
+
+// Call this in a .cc file where you will later call EXPECT_DEATH
+#define EXPECT_DEATH_INIT \
+ static bool g_called_exit; \
+ static void CalledExit(int) { g_called_exit = true; }
+
+#define EXPECT_DEATH(fn, msg) \
+ do { \
+ g_called_exit = false; \
+ gflags_exitfunc = &CalledExit; \
+ fn; \
+ gflags_exitfunc = &exit; /* set back to its default */ \
+ if (!g_called_exit) { \
+ fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
+ exit(1); \
+ } \
+ } while (0)
+
+#define GTEST_HAS_DEATH_TEST 1
+
+// -- path routines ----------------------------------------------------------
+
+// Tries to create the directory path as a temp-dir. If it fails,
+// changes path to some directory it *can* create.
+#if defined(__MINGW32__)
+#include <io.h>
+inline void MakeTmpdir(std::string* path) {
+ if (!path->empty()) {
+ path->append("/gflags_unittest_testdir");
+ int err = mkdir(path->c_str());
+ if (err == 0 || errno == EEXIST) return;
+ }
+ // I had trouble creating a directory in /tmp from mingw
+ *path = "./gflags_unittest";
+ mkdir(path->c_str());
+}
+#elif defined(_MSC_VER)
+#include <direct.h>
+inline void MakeTmpdir(std::string* path) {
+ if (!path->empty()) {
+ int err = _mkdir(path->c_str());
+ if (err == 0 || errno == EEXIST) return;
+ }
+ char tmppath_buffer[1024];
+ int tmppath_len = GetTempPathA(sizeof(tmppath_buffer), tmppath_buffer);
+ assert(tmppath_len > 0 && tmppath_len < sizeof(tmppath_buffer));
+ assert(tmppath_buffer[tmppath_len - 1] == '\\'); // API guarantees it
+ *path = std::string(tmppath_buffer) + "gflags_unittest";
+ _mkdir(path->c_str());
+}
+#else
+inline void MakeTmpdir(std::string* path) {
+ if (!path->empty()) {
+ int err = mkdir(path->c_str(), 0755);
+ if (err == 0 || errno == EEXIST) return;
+ }
+ mkdir("/tmp/gflags_unittest", 0755);
+}
+#endif
+
+// -- string routines --------------------------------------------------------
+
+inline void InternalStringPrintf(std::string* output, const char* format,
+ va_list ap) {
+ char space[128]; // try a small buffer and hope it fits
+
+ // It's possible for methods that use a va_list to invalidate
+ // the data in it upon use. The fix is to make a copy
+ // of the structure before using it and use that copy instead.
+ va_list backup_ap;
+ va_copy(backup_ap, ap);
+ int bytes_written = vsnprintf(space, sizeof(space), format, backup_ap);
+ va_end(backup_ap);
+
+ if ((bytes_written >= 0) && (static_cast<size_t>(bytes_written) < sizeof(space))) {
+ output->append(space, bytes_written);
+ return;
+ }
+
+ // Repeatedly increase buffer size until it fits.
+ int length = sizeof(space);
+ while (true) {
+ if (bytes_written < 0) {
+ // Older snprintf() behavior. :-( Just try doubling the buffer size
+ length *= 2;
+ } else {
+ // We need exactly "bytes_written+1" characters
+ length = bytes_written+1;
+ }
+ char* buf = new char[length];
+
+ // Restore the va_list before we use it again
+ va_copy(backup_ap, ap);
+ bytes_written = vsnprintf(buf, length, format, backup_ap);
+ va_end(backup_ap);
+
+ if ((bytes_written >= 0) && (bytes_written < length)) {
+ output->append(buf, bytes_written);
+ delete[] buf;
+ return;
+ }
+ delete[] buf;
+ }
+}
+
+// Clears output before writing to it.
+inline void SStringPrintf(std::string* output, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ output->clear();
+ InternalStringPrintf(output, format, ap);
+ va_end(ap);
+}
+
+inline void StringAppendF(std::string* output, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ InternalStringPrintf(output, format, ap);
+ va_end(ap);
+}
+
+inline std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string output;
+ InternalStringPrintf(&output, format, ap);
+ va_end(ap);
+ return output;
+}
+
+inline bool SafeGetEnv(const char *varname, std::string &valstr)
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ char *val;
+ size_t sz;
+ if (_dupenv_s(&val, &sz, varname) != 0 || !val) return false;
+ valstr = val;
+ free(val);
+#else
+ const char * const val = getenv(varname);
+ if (!val) return false;
+ valstr = val;
+#endif
+ return true;
+}
+
+inline int SafeFOpen(FILE **fp, const char* fname, const char *mode)
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ return fopen_s(fp, fname, mode);
+#else
+ assert(fp != NULL);
+ *fp = fopen(fname, mode);
+ // errno only guaranteed to be set on failure
+ return ((*fp == NULL) ? errno : 0);
+#endif
+}
+
+
+} // namespace GFLAGS_NAMESPACE
+
+
+#endif // GFLAGS_UTIL_H_
diff --git a/extern/gflags/src/windows_port.cc b/extern/gflags/src/windows_port.cc
new file mode 100644
index 00000000000..b5b7194c9a4
--- /dev/null
+++ b/extern/gflags/src/windows_port.cc
@@ -0,0 +1,73 @@
+/* Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Craig Silverstein
+ */
+
+#ifndef _WIN32
+# error You should only be including windows/port.cc in a windows environment!
+#endif
+
+#include <string.h> // for strlen(), memset(), memcmp()
+#include <assert.h>
+#include <stdarg.h> // for va_list, va_start, va_end
+#include <windows.h>
+
+#include "windows_port.h"
+
+// These call the windows _vsnprintf, but always NUL-terminate.
+#if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */
+#if !(defined(_MSC_VER) && _MSC_VER >= 1900) /* msvc 2015 already defines */
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996) // ignore _vsnprintf security warning
+#endif
+int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ if (size == 0) // not even room for a \0?
+ return -1; // not what C99 says to do, but what windows does
+ str[size-1] = '\0';
+ return _vsnprintf(str, size-1, format, ap);
+}
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+int snprintf(char *str, size_t size, const char *format, ...) {
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return r;
+}
+
+#endif /* if !(defined(_MSC_VER) && _MSC_VER >= 1900) */
+#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */
diff --git a/extern/gflags/src/windows_port.h b/extern/gflags/src/windows_port.h
new file mode 100644
index 00000000000..1f546996783
--- /dev/null
+++ b/extern/gflags/src/windows_port.h
@@ -0,0 +1,133 @@
+/* Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Craig Silverstein
+ *
+ * These are some portability typedefs and defines to make it a bit
+ * easier to compile this code under VC++.
+ *
+ * Several of these are taken from glib:
+ * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
+ */
+
+#ifndef GFLAGS_WINDOWS_PORT_H_
+#define GFLAGS_WINDOWS_PORT_H_
+
+#include "config.h"
+
+// This must be defined before the windows.h is included.
+// It's needed for mutex.h, to give access to the TryLock method.
+# if !defined(_WIN32_WINNT) && !(defined( __MINGW32__) || defined(__MINGW64__))
+# define _WIN32_WINNT 0x0400
+# endif
+// We always want minimal includes
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <direct.h> /* for mkdir */
+#include <stdlib.h> /* for _putenv, getenv */
+#include <stdio.h> /* need this to override stdio's snprintf, also defines _unlink used by unit tests */
+#include <stdarg.h> /* util.h uses va_copy */
+#include <string.h> /* for _stricmp and _strdup */
+
+/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
+ * because they don't always NUL-terminate. :-( We also can't use the
+ * name vsnprintf, since windows defines that (but not snprintf (!)).
+ */
+#if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */
+#if !(defined(_MSC_VER) && _MSC_VER >= 1900) /* msvc 2015 already defines */
+extern GFLAGS_DLL_DECL int snprintf(char *str, size_t size,
+ const char *format, ...);
+extern int GFLAGS_DLL_DECL safe_vsnprintf(char *str, size_t size,
+ const char *format, va_list ap);
+#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+#define va_copy(dst, src) (dst) = (src)
+#endif
+#endif
+#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable: 4996) // ignore getenv security warning
+#endif
+inline void setenv(const char* name, const char* value, int) {
+ // In windows, it's impossible to set a variable to the empty string.
+ // We handle this by setting it to "0" and the NUL-ing out the \0.
+ // That is, we putenv("FOO=0") and then find out where in memory the
+ // putenv wrote "FOO=0", and change it in-place to "FOO=\0".
+ // c.f. http://svn.apache.org/viewvc/stdcxx/trunk/tests/src/environ.cpp?r1=611451&r2=637508&pathrev=637508
+ static const char* const kFakeZero = "0";
+ if (*value == '\0')
+ value = kFakeZero;
+ // Apparently the semantics of putenv() is that the input
+ // must live forever, so we leak memory here. :-(
+ const size_t nameval_len = strlen(name) + 1 + strlen(value) + 1;
+ char* nameval = reinterpret_cast<char*>(malloc(nameval_len));
+ snprintf(nameval, nameval_len, "%s=%s", name, value);
+ _putenv(nameval);
+ if (value == kFakeZero) {
+ nameval[nameval_len - 2] = '\0'; // works when putenv() makes no copy
+ if (*getenv(name) != '\0')
+ *getenv(name) = '\0'; // works when putenv() copies nameval
+ }
+}
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+#define strcasecmp _stricmp
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define strdup _strdup
+#define unlink _unlink
+#endif
+
+#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
+#define PRId32 "d"
+#define PRIu32 "u"
+#define PRId64 "I64d"
+#define PRIu64 "I64u"
+#endif
+
+#if !defined(__MINGW32__) && !defined(__MINGW64__)
+#define strtoq _strtoi64
+#define strtouq _strtoui64
+#define strtoll _strtoi64
+#define strtoull _strtoui64
+#define atoll _atoi64
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#endif /* GFLAGS_WINDOWS_PORT_H_ */
diff --git a/extern/glew-es/SConscript b/extern/glew-es/SConscript
deleted file mode 100644
index 7552ce84067..00000000000
--- a/extern/glew-es/SConscript
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/python
-import sys
-import os
-
-Import('env')
-
-sources = ['src/glew.c']
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_GLEW_MX']:
- defs += ['GLEW_MX']
-incs = ['include']
-
-env.BlenderLib ( 'extern_glew_es', sources, incs, defs, libtype=['extern','player'], priority=[50,230] )
diff --git a/extern/glew/SConscript b/extern/glew/SConscript
deleted file mode 100644
index a9687383a0c..00000000000
--- a/extern/glew/SConscript
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/python
-import sys
-import os
-
-Import('env')
-
-sources = ['src/glew.c']
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_GLEW_MX']:
- defs += ['GLEW_MX']
-
-incs = ['include']
-
-env.BlenderLib ( 'extern_glew', sources, incs, defs, libtype=['extern','player'], priority=[50,230] )
diff --git a/extern/glew/include/GL/glew.h b/extern/glew/include/GL/glew.h
index 51a29ef8b91..702265c38b4 100644
--- a/extern/glew/include/GL/glew.h
+++ b/extern/glew/include/GL/glew.h
@@ -1,5 +1,6 @@
/*
** The OpenGL Extension Wrangler Library
+** Copyright (C) 2008-2015, Nigel Stewart <nigels[]users sourceforge net>
** Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>
** Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>
** Copyright (C) 2002, Lev Povalahev
@@ -80,7 +81,7 @@
#define __glew_h__
#define __GLEW_H__
-#if defined(__gl_h_) || defined(__GL_H__) || defined(__X_GL_H)
+#if defined(__gl_h_) || defined(__GL_H__) || defined(_GL_H) || defined(__X_GL_H)
#error gl.h included before glew.h
#endif
#if defined(__gl2_h_)
@@ -102,6 +103,7 @@
#define __gl_h_
#define __gl2_h_
#define __GL_H__
+#define _GL_H
#define __gltypes_h_
#define __REGAL_H__
#define __X_GL_H
@@ -116,13 +118,24 @@
* GL needs GLAPI and GLAPIENTRY, GLU needs APIENTRY, CALLBACK, and wchar_t
* defined properly.
*/
-/* <windef.h> */
-#ifndef APIENTRY
+/* <windef.h> and <gl.h>*/
+#ifdef APIENTRY
+# ifndef GLAPIENTRY
+# define GLAPIENTRY APIENTRY
+# endif
+# ifndef GLEWAPIENTRY
+# define GLEWAPIENTRY APIENTRY
+# endif
+#else
#define GLEW_APIENTRY_DEFINED
-# if defined(__MINGW32__) || defined(__CYGWIN__)
-# define APIENTRY __stdcall
-# elif (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__)
+# if defined(__MINGW32__) || defined(__CYGWIN__) || (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__)
# define APIENTRY __stdcall
+# ifndef GLAPIENTRY
+# define GLAPIENTRY __stdcall
+# endif
+# ifndef GLEWAPIENTRY
+# define GLEWAPIENTRY __stdcall
+# endif
# else
# define APIENTRY
# endif
@@ -179,14 +192,6 @@ typedef _W64 int ptrdiff_t;
# endif
#endif
-#ifndef GLAPIENTRY
-#define GLAPIENTRY APIENTRY
-#endif
-
-#ifndef GLEWAPIENTRY
-#define GLEWAPIENTRY APIENTRY
-#endif
-
/*
* GLEW_STATIC is defined for static library.
* GLEW_BUILD is defined for building the DLL library.
@@ -248,6 +253,8 @@ typedef _W64 int ptrdiff_t;
#define GLAPI extern
#endif
+#endif /* _WIN32 */
+
#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif
@@ -256,8 +263,6 @@ typedef _W64 int ptrdiff_t;
#define GLEWAPIENTRY
#endif
-#endif /* _WIN32 */
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -846,7 +851,7 @@ GLAPI void GLAPIENTRY glBindTexture (GLenum target, GLuint texture);
GLAPI void GLAPIENTRY glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);
GLAPI void GLAPIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
GLAPI void GLAPIENTRY glCallList (GLuint list);
-GLAPI void GLAPIENTRY glCallLists (GLsizei n, GLenum type, const GLvoid *lists);
+GLAPI void GLAPIENTRY glCallLists (GLsizei n, GLenum type, const void *lists);
GLAPI void GLAPIENTRY glClear (GLbitfield mask);
GLAPI void GLAPIENTRY glClearAccum (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
GLAPI void GLAPIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
@@ -888,7 +893,7 @@ GLAPI void GLAPIENTRY glColor4us (GLushort red, GLushort green, GLushort blue, G
GLAPI void GLAPIENTRY glColor4usv (const GLushort *v);
GLAPI void GLAPIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GLAPI void GLAPIENTRY glColorMaterial (GLenum face, GLenum mode);
-GLAPI void GLAPIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
GLAPI void GLAPIENTRY glCopyPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);
GLAPI void GLAPIENTRY glCopyTexImage1D (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border);
GLAPI void GLAPIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
@@ -904,10 +909,10 @@ GLAPI void GLAPIENTRY glDisable (GLenum cap);
GLAPI void GLAPIENTRY glDisableClientState (GLenum array);
GLAPI void GLAPIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
GLAPI void GLAPIENTRY glDrawBuffer (GLenum mode);
-GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
-GLAPI void GLAPIENTRY glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);
+GLAPI void GLAPIENTRY glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
GLAPI void GLAPIENTRY glEdgeFlag (GLboolean flag);
-GLAPI void GLAPIENTRY glEdgeFlagPointer (GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glEdgeFlagPointer (GLsizei stride, const void *pointer);
GLAPI void GLAPIENTRY glEdgeFlagv (const GLboolean *flag);
GLAPI void GLAPIENTRY glEnable (GLenum cap);
GLAPI void GLAPIENTRY glEnableClientState (GLenum array);
@@ -952,7 +957,7 @@ GLAPI void GLAPIENTRY glGetMaterialiv (GLenum face, GLenum pname, GLint *params)
GLAPI void GLAPIENTRY glGetPixelMapfv (GLenum map, GLfloat *values);
GLAPI void GLAPIENTRY glGetPixelMapuiv (GLenum map, GLuint *values);
GLAPI void GLAPIENTRY glGetPixelMapusv (GLenum map, GLushort *values);
-GLAPI void GLAPIENTRY glGetPointerv (GLenum pname, GLvoid* *params);
+GLAPI void GLAPIENTRY glGetPointerv (GLenum pname, void* *params);
GLAPI void GLAPIENTRY glGetPolygonStipple (GLubyte *mask);
GLAPI const GLubyte * GLAPIENTRY glGetString (GLenum name);
GLAPI void GLAPIENTRY glGetTexEnvfv (GLenum target, GLenum pname, GLfloat *params);
@@ -960,14 +965,14 @@ GLAPI void GLAPIENTRY glGetTexEnviv (GLenum target, GLenum pname, GLint *params)
GLAPI void GLAPIENTRY glGetTexGendv (GLenum coord, GLenum pname, GLdouble *params);
GLAPI void GLAPIENTRY glGetTexGenfv (GLenum coord, GLenum pname, GLfloat *params);
GLAPI void GLAPIENTRY glGetTexGeniv (GLenum coord, GLenum pname, GLint *params);
-GLAPI void GLAPIENTRY glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+GLAPI void GLAPIENTRY glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
GLAPI void GLAPIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params);
GLAPI void GLAPIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params);
GLAPI void GLAPIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);
GLAPI void GLAPIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);
GLAPI void GLAPIENTRY glHint (GLenum target, GLenum mode);
GLAPI void GLAPIENTRY glIndexMask (GLuint mask);
-GLAPI void GLAPIENTRY glIndexPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glIndexPointer (GLenum type, GLsizei stride, const void *pointer);
GLAPI void GLAPIENTRY glIndexd (GLdouble c);
GLAPI void GLAPIENTRY glIndexdv (const GLdouble *c);
GLAPI void GLAPIENTRY glIndexf (GLfloat c);
@@ -979,7 +984,7 @@ GLAPI void GLAPIENTRY glIndexsv (const GLshort *c);
GLAPI void GLAPIENTRY glIndexub (GLubyte c);
GLAPI void GLAPIENTRY glIndexubv (const GLubyte *c);
GLAPI void GLAPIENTRY glInitNames (void);
-GLAPI void GLAPIENTRY glInterleavedArrays (GLenum format, GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glInterleavedArrays (GLenum format, GLsizei stride, const void *pointer);
GLAPI GLboolean GLAPIENTRY glIsEnabled (GLenum cap);
GLAPI GLboolean GLAPIENTRY glIsList (GLuint list);
GLAPI GLboolean GLAPIENTRY glIsTexture (GLuint texture);
@@ -1025,7 +1030,7 @@ GLAPI void GLAPIENTRY glNormal3i (GLint nx, GLint ny, GLint nz);
GLAPI void GLAPIENTRY glNormal3iv (const GLint *v);
GLAPI void GLAPIENTRY glNormal3s (GLshort nx, GLshort ny, GLshort nz);
GLAPI void GLAPIENTRY glNormal3sv (const GLshort *v);
-GLAPI void GLAPIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glNormalPointer (GLenum type, GLsizei stride, const void *pointer);
GLAPI void GLAPIENTRY glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);
GLAPI void GLAPIENTRY glPassThrough (GLfloat token);
GLAPI void GLAPIENTRY glPixelMapfv (GLenum map, GLsizei mapsize, const GLfloat *values);
@@ -1074,7 +1079,7 @@ GLAPI void GLAPIENTRY glRasterPos4iv (const GLint *v);
GLAPI void GLAPIENTRY glRasterPos4s (GLshort x, GLshort y, GLshort z, GLshort w);
GLAPI void GLAPIENTRY glRasterPos4sv (const GLshort *v);
GLAPI void GLAPIENTRY glReadBuffer (GLenum mode);
-GLAPI void GLAPIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+GLAPI void GLAPIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
GLAPI void GLAPIENTRY glRectd (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
GLAPI void GLAPIENTRY glRectdv (const GLdouble *v1, const GLdouble *v2);
GLAPI void GLAPIENTRY glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
@@ -1126,7 +1131,7 @@ GLAPI void GLAPIENTRY glTexCoord4i (GLint s, GLint t, GLint r, GLint q);
GLAPI void GLAPIENTRY glTexCoord4iv (const GLint *v);
GLAPI void GLAPIENTRY glTexCoord4s (GLshort s, GLshort t, GLshort r, GLshort q);
GLAPI void GLAPIENTRY glTexCoord4sv (const GLshort *v);
-GLAPI void GLAPIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
GLAPI void GLAPIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);
GLAPI void GLAPIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
GLAPI void GLAPIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);
@@ -1137,14 +1142,14 @@ GLAPI void GLAPIENTRY glTexGenf (GLenum coord, GLenum pname, GLfloat param);
GLAPI void GLAPIENTRY glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params);
GLAPI void GLAPIENTRY glTexGeni (GLenum coord, GLenum pname, GLint param);
GLAPI void GLAPIENTRY glTexGeniv (GLenum coord, GLenum pname, const GLint *params);
-GLAPI void GLAPIENTRY glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GLAPI void GLAPIENTRY glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+GLAPI void GLAPIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
GLAPI void GLAPIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
GLAPI void GLAPIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
GLAPI void GLAPIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
GLAPI void GLAPIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
-GLAPI void GLAPIENTRY glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
-GLAPI void GLAPIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GLAPI void GLAPIENTRY glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+GLAPI void GLAPIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
GLAPI void GLAPIENTRY glTranslated (GLdouble x, GLdouble y, GLdouble z);
GLAPI void GLAPIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
GLAPI void GLAPIENTRY glVertex2d (GLdouble x, GLdouble y);
@@ -1171,7 +1176,7 @@ GLAPI void GLAPIENTRY glVertex4i (GLint x, GLint y, GLint z, GLint w);
GLAPI void GLAPIENTRY glVertex4iv (const GLint *v);
GLAPI void GLAPIENTRY glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w);
GLAPI void GLAPIENTRY glVertex4sv (const GLshort *v);
-GLAPI void GLAPIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GLAPI void GLAPIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);
GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
#define GLEW_VERSION_1_1 GLEW_GET_VAR(__GLEW_VERSION_1_1)
@@ -1181,6 +1186,15 @@ GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei heigh
/* ---------------------------------- GLU ---------------------------------- */
#ifndef GLEW_NO_GLU
+# ifdef __APPLE__
+# include <Availability.h>
+# if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+# define GLEW_NO_GLU
+# endif
+# endif
+#endif
+
+#ifndef GLEW_NO_GLU
/* this is where we can safely include GLU */
# if defined(__APPLE__) && defined(__MACH__)
# include <OpenGL/glu.h>
@@ -1236,9 +1250,9 @@ GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei heigh
#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
-typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
#define glCopyTexSubImage3D GLEW_GET_FUN(__glewCopyTexSubImage3D)
#define glDrawRangeElements GLEW_GET_FUN(__glewDrawRangeElements)
@@ -1362,13 +1376,13 @@ typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level,
typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREPROC) (GLenum texture);
typedef void (GLAPIENTRY * PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLvoid *img);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, void *img);
typedef void (GLAPIENTRY * PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble m[16]);
typedef void (GLAPIENTRY * PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat m[16]);
typedef void (GLAPIENTRY * PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble m[16]);
@@ -1506,13 +1520,13 @@ typedef void (GLAPIENTRY * PFNGLSAMPLECOVERAGEPROC) (GLclampf value, GLboolean i
typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
-typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLFOGCOORDDPROC) (GLdouble coord);
typedef void (GLAPIENTRY * PFNGLFOGCOORDDVPROC) (const GLdouble *coord);
typedef void (GLAPIENTRY * PFNGLFOGCOORDFPROC) (GLfloat coord);
typedef void (GLAPIENTRY * PFNGLFOGCOORDFVPROC) (const GLfloat *coord);
typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid **indices, GLsizei drawcount);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const* indices, GLsizei drawcount);
typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);
typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);
typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);
@@ -1533,7 +1547,7 @@ typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green
typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);
typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);
typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);
-typedef void (GLAPIENTRY * PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);
typedef void (GLAPIENTRY * PFNGLWINDOWPOS2DVPROC) (const GLdouble *p);
typedef void (GLAPIENTRY * PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);
@@ -1608,18 +1622,18 @@ typedef void (GLAPIENTRY * PFNGLWINDOWPOS3SVPROC) (const GLshort *p);
#ifndef GL_VERSION_1_5
#define GL_VERSION_1_5 1
-#define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE
+#define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE
#define GL_FOG_COORD GL_FOG_COORDINATE
#define GL_FOG_COORD_ARRAY GL_FOG_COORDINATE_ARRAY
-#define GL_SRC0_RGB GL_SOURCE0_RGB
+#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING
#define GL_FOG_COORD_ARRAY_POINTER GL_FOG_COORDINATE_ARRAY_POINTER
-#define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE
-#define GL_SRC1_ALPHA GL_SOURCE1_ALPHA
-#define GL_CURRENT_FOG_COORD GL_CURRENT_FOG_COORDINATE
#define GL_FOG_COORD_ARRAY_STRIDE GL_FOG_COORDINATE_ARRAY_STRIDE
+#define GL_FOG_COORD_ARRAY_TYPE GL_FOG_COORDINATE_ARRAY_TYPE
+#define GL_FOG_COORD_SRC GL_FOG_COORDINATE_SOURCE
#define GL_SRC0_ALPHA GL_SOURCE0_ALPHA
+#define GL_SRC0_RGB GL_SOURCE0_RGB
+#define GL_SRC1_ALPHA GL_SOURCE1_ALPHA
#define GL_SRC1_RGB GL_SOURCE1_RGB
-#define GL_FOG_COORD_ARRAY_BUFFER_BINDING GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING
#define GL_SRC2_ALPHA GL_SOURCE2_ALPHA
#define GL_SRC2_RGB GL_SOURCE2_RGB
#define GL_BUFFER_SIZE 0x8764
@@ -1664,22 +1678,22 @@ typedef ptrdiff_t GLsizeiptr;
typedef void (GLAPIENTRY * PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);
typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
-typedef void (GLAPIENTRY * PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
-typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+typedef void (GLAPIENTRY * PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint* buffers);
typedef void (GLAPIENTRY * PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint* ids);
typedef void (GLAPIENTRY * PFNGLENDQUERYPROC) (GLenum target);
typedef void (GLAPIENTRY * PFNGLGENBUFFERSPROC) (GLsizei n, GLuint* buffers);
typedef void (GLAPIENTRY * PFNGLGENQUERIESPROC) (GLsizei n, GLuint* ids);
typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid** params);
-typedef void (GLAPIENTRY * PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid* data);
+typedef void (GLAPIENTRY * PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void** params);
+typedef void (GLAPIENTRY * PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void* data);
typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint* params);
typedef void (GLAPIENTRY * PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint* params);
typedef GLboolean (GLAPIENTRY * PFNGLISBUFFERPROC) (GLuint buffer);
typedef GLboolean (GLAPIENTRY * PFNGLISQUERYPROC) (GLuint id);
-typedef GLvoid* (GLAPIENTRY * PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
+typedef void* (GLAPIENTRY * PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
typedef GLboolean (GLAPIENTRY * PFNGLUNMAPBUFFERPROC) (GLenum target);
#define glBeginQuery GLEW_GET_FUN(__glewBeginQuery)
@@ -1798,16 +1812,16 @@ typedef GLboolean (GLAPIENTRY * PFNGLUNMAPBUFFERPROC) (GLenum target);
typedef void (GLAPIENTRY * PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (GLAPIENTRY * PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
-typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum, GLenum);
+typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);
typedef void (GLAPIENTRY * PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint (GLAPIENTRY * PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROC) (GLenum type);
typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (GLAPIENTRY * PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (GLAPIENTRY * PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
-typedef void (GLAPIENTRY * PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint);
+typedef void (GLAPIENTRY * PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (GLAPIENTRY * PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum* bufs);
-typedef void (GLAPIENTRY * PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint);
+typedef void (GLAPIENTRY * PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (GLAPIENTRY * PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei maxLength, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
typedef void (GLAPIENTRY * PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei* count, GLuint* shaders);
@@ -1820,16 +1834,16 @@ typedef void (GLAPIENTRY * PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, G
typedef GLint (GLAPIENTRY * PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar* name);
typedef void (GLAPIENTRY * PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint, GLenum, GLvoid**);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBDVPROC) (GLuint, GLenum, GLdouble*);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBFVPROC) (GLuint, GLenum, GLfloat*);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIVPROC) (GLuint, GLenum, GLint*);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void** pointer);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble* params);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat* params);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint* params);
typedef GLboolean (GLAPIENTRY * PFNGLISPROGRAMPROC) (GLuint program);
typedef GLboolean (GLAPIENTRY * PFNGLISSHADERPROC) (GLuint shader);
typedef void (GLAPIENTRY * PFNGLLINKPROGRAMPROC) (GLuint program);
-typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths);
+typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const* string, const GLint* length);
typedef void (GLAPIENTRY * PFNGLSTENCILFUNCSEPARATEPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);
-typedef void (GLAPIENTRY * PFNGLSTENCILMASKSEPARATEPROC) (GLenum, GLuint);
+typedef void (GLAPIENTRY * PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);
typedef void (GLAPIENTRY * PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
typedef void (GLAPIENTRY * PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
typedef void (GLAPIENTRY * PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat* value);
@@ -1888,7 +1902,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshor
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort* v);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
#define glAttachShader GLEW_GET_FUN(__glewAttachShader)
#define glBindAttribLocation GLEW_GET_FUN(__glewBindAttribLocation)
@@ -2040,14 +2054,14 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei
#ifndef GL_VERSION_3_0
#define GL_VERSION_3_0 1
-#define GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES
-#define GL_CLIP_DISTANCE5 GL_CLIP_PLANE5
+#define GL_CLIP_DISTANCE0 GL_CLIP_PLANE0
#define GL_CLIP_DISTANCE1 GL_CLIP_PLANE1
+#define GL_CLIP_DISTANCE2 GL_CLIP_PLANE2
#define GL_CLIP_DISTANCE3 GL_CLIP_PLANE3
-#define GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_R_TO_TEXTURE_ARB
-#define GL_CLIP_DISTANCE0 GL_CLIP_PLANE0
#define GL_CLIP_DISTANCE4 GL_CLIP_PLANE4
-#define GL_CLIP_DISTANCE2 GL_CLIP_PLANE2
+#define GL_CLIP_DISTANCE5 GL_CLIP_PLANE5
+#define GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_R_TO_TEXTURE_ARB
+#define GL_MAX_CLIP_DISTANCES GL_MAX_CLIP_PLANES
#define GL_MAX_VARYING_COMPONENTS GL_MAX_VARYING_FLOATS
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x0001
#define GL_MAJOR_VERSION 0x821B
@@ -2146,61 +2160,61 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei
#define GL_QUERY_BY_REGION_WAIT 0x8E15
#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
-typedef void (GLAPIENTRY * PFNGLBEGINCONDITIONALRENDERPROC) (GLuint, GLenum);
-typedef void (GLAPIENTRY * PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum);
-typedef void (GLAPIENTRY * PFNGLBINDFRAGDATALOCATIONPROC) (GLuint, GLuint, const GLchar*);
-typedef void (GLAPIENTRY * PFNGLCLAMPCOLORPROC) (GLenum, GLenum);
-typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFIPROC) (GLenum, GLint, GLfloat, GLint);
-typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFVPROC) (GLenum, GLint, const GLfloat*);
-typedef void (GLAPIENTRY * PFNGLCLEARBUFFERIVPROC) (GLenum, GLint, const GLint*);
-typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum, GLint, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLCOLORMASKIPROC) (GLuint, GLboolean, GLboolean, GLboolean, GLboolean);
-typedef void (GLAPIENTRY * PFNGLDISABLEIPROC) (GLenum, GLuint);
-typedef void (GLAPIENTRY * PFNGLENABLEIPROC) (GLenum, GLuint);
+typedef void (GLAPIENTRY * PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);
+typedef void (GLAPIENTRY * PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);
+typedef void (GLAPIENTRY * PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint colorNumber, const GLchar* name);
+typedef void (GLAPIENTRY * PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);
+typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawBuffer, GLfloat depth, GLint stencil);
+typedef void (GLAPIENTRY * PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawBuffer, const GLfloat* value);
+typedef void (GLAPIENTRY * PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawBuffer, const GLint* value);
+typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawBuffer, const GLuint* value);
+typedef void (GLAPIENTRY * PFNGLCOLORMASKIPROC) (GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+typedef void (GLAPIENTRY * PFNGLDISABLEIPROC) (GLenum cap, GLuint index);
+typedef void (GLAPIENTRY * PFNGLENABLEIPROC) (GLenum cap, GLuint index);
typedef void (GLAPIENTRY * PFNGLENDCONDITIONALRENDERPROC) (void);
typedef void (GLAPIENTRY * PFNGLENDTRANSFORMFEEDBACKPROC) (void);
-typedef void (GLAPIENTRY * PFNGLGETBOOLEANI_VPROC) (GLenum, GLuint, GLboolean*);
-typedef GLint (GLAPIENTRY * PFNGLGETFRAGDATALOCATIONPROC) (GLuint, const GLchar*);
-typedef const GLubyte* (GLAPIENTRY * PFNGLGETSTRINGIPROC) (GLenum, GLuint);
-typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIIVPROC) (GLenum, GLenum, GLint*);
-typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIUIVPROC) (GLenum, GLenum, GLuint*);
-typedef void (GLAPIENTRY * PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint, GLuint, GLsizei, GLsizei *, GLsizei *, GLenum *, GLchar *);
-typedef void (GLAPIENTRY * PFNGLGETUNIFORMUIVPROC) (GLuint, GLint, GLuint*);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIIVPROC) (GLuint, GLenum, GLint*);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint, GLenum, GLuint*);
-typedef GLboolean (GLAPIENTRY * PFNGLISENABLEDIPROC) (GLenum, GLuint);
-typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIIVPROC) (GLenum, GLenum, const GLint*);
-typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIUIVPROC) (GLenum, GLenum, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint, GLsizei, const GLchar **, GLenum);
-typedef void (GLAPIENTRY * PFNGLUNIFORM1UIPROC) (GLint, GLuint);
-typedef void (GLAPIENTRY * PFNGLUNIFORM1UIVPROC) (GLint, GLsizei, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLUNIFORM2UIPROC) (GLint, GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLUNIFORM2UIVPROC) (GLint, GLsizei, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLUNIFORM3UIPROC) (GLint, GLuint, GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLUNIFORM3UIVPROC) (GLint, GLsizei, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLUNIFORM4UIPROC) (GLint, GLuint, GLuint, GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLUNIFORM4UIVPROC) (GLint, GLsizei, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1IPROC) (GLuint, GLint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1IVPROC) (GLuint, const GLint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1UIPROC) (GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1UIVPROC) (GLuint, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2IPROC) (GLuint, GLint, GLint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2IVPROC) (GLuint, const GLint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2UIPROC) (GLuint, GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2UIVPROC) (GLuint, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3IPROC) (GLuint, GLint, GLint, GLint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3IVPROC) (GLuint, const GLint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3UIPROC) (GLuint, GLuint, GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3UIVPROC) (GLuint, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4BVPROC) (GLuint, const GLbyte*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4IPROC) (GLuint, GLint, GLint, GLint, GLint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4IVPROC) (GLuint, const GLint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4SVPROC) (GLuint, const GLshort*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UBVPROC) (GLuint, const GLubyte*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UIPROC) (GLuint, GLuint, GLuint, GLuint, GLuint);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UIVPROC) (GLuint, const GLuint*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4USVPROC) (GLuint, const GLushort*);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint, GLint, GLenum, GLsizei, const GLvoid*);
+typedef void (GLAPIENTRY * PFNGLGETBOOLEANI_VPROC) (GLenum pname, GLuint index, GLboolean* data);
+typedef GLint (GLAPIENTRY * PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar* name);
+typedef const GLubyte* (GLAPIENTRY * PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);
+typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint* params);
+typedef void (GLAPIENTRY * PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name);
+typedef void (GLAPIENTRY * PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint* params);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint* params);
+typedef GLboolean (GLAPIENTRY * PFNGLISENABLEDIPROC) (GLenum cap, GLuint index);
+typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint* params);
+typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint* params);
+typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode);
+typedef void (GLAPIENTRY * PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0);
+typedef void (GLAPIENTRY * PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);
+typedef void (GLAPIENTRY * PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (GLAPIENTRY * PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (GLAPIENTRY * PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint* value);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint v0, GLint v1);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint v0, GLuint v1);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint v0, GLint v1, GLint v2);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint v0, GLuint v1, GLuint v2);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort* v0);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void*pointer);
#define glBeginConditionalRender GLEW_GET_FUN(__glewBeginConditionalRender)
#define glBeginTransformFeedback GLEW_GET_FUN(__glewBeginTransformFeedback)
@@ -2302,10 +2316,10 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint, GLint, GLenum
#define GL_BUFFER_MAP_LENGTH 0x9120
#define GL_BUFFER_MAP_OFFSET 0x9121
-typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum, GLint, GLsizei, GLsizei);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum, GLsizei, GLenum, const GLvoid*, GLsizei);
-typedef void (GLAPIENTRY * PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint);
-typedef void (GLAPIENTRY * PFNGLTEXBUFFERPROC) (GLenum, GLenum, GLuint);
+typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount);
+typedef void (GLAPIENTRY * PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint buffer);
+typedef void (GLAPIENTRY * PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalFormat, GLuint buffer);
#define glDrawArraysInstanced GLEW_GET_FUN(__glewDrawArraysInstanced)
#define glDrawElementsInstanced GLEW_GET_FUN(__glewDrawElementsInstanced)
@@ -2344,9 +2358,9 @@ typedef void (GLAPIENTRY * PFNGLTEXBUFFERPROC) (GLenum, GLenum, GLuint);
#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
#define GL_CONTEXT_PROFILE_MASK 0x9126
-typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum, GLenum, GLuint, GLint);
-typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum, GLenum, GLint64 *);
-typedef void (GLAPIENTRY * PFNGLGETINTEGER64I_VPROC) (GLenum, GLuint, GLint64 *);
+typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);
+typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum value, GLint64 * data);
+typedef void (GLAPIENTRY * PFNGLGETINTEGER64I_VPROC) (GLenum pname, GLuint index, GLint64 * data);
#define glFramebufferTexture GLEW_GET_FUN(__glewFramebufferTexture)
#define glGetBufferParameteri64v GLEW_GET_FUN(__glewGetBufferParameteri64v)
@@ -2420,10 +2434,14 @@ typedef void (GLAPIENTRY * PFNGLMINSAMPLESHADINGPROC) (GLclampf value);
#ifndef GL_VERSION_4_2
#define GL_VERSION_4_2 1
+#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#define GL_COPY_READ_BUFFER_BINDING 0x8F36
+#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
#define GLEW_VERSION_4_2 GLEW_GET_VAR(__GLEW_VERSION_4_2)
@@ -2446,12 +2464,35 @@ typedef void (GLAPIENTRY * PFNGLMINSAMPLESHADINGPROC) (GLclampf value);
#ifndef GL_VERSION_4_4
#define GL_VERSION_4_4 1
+#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221
#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5
+#define GL_TEXTURE_BUFFER_BINDING 0x8C2A
#define GLEW_VERSION_4_4 GLEW_GET_VAR(__GLEW_VERSION_4_4)
#endif /* GL_VERSION_4_4 */
+/* ----------------------------- GL_VERSION_4_5 ---------------------------- */
+
+#ifndef GL_VERSION_4_5
+#define GL_VERSION_4_5 1
+
+#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
+
+typedef GLenum (GLAPIENTRY * PFNGLGETGRAPHICSRESETSTATUSPROC) (void);
+typedef void (GLAPIENTRY * PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLGETNTEXIMAGEPROC) (GLenum tex, GLint level, GLenum format, GLenum type, GLsizei bufSize, GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);
+
+#define glGetGraphicsResetStatus GLEW_GET_FUN(__glewGetGraphicsResetStatus)
+#define glGetnCompressedTexImage GLEW_GET_FUN(__glewGetnCompressedTexImage)
+#define glGetnTexImage GLEW_GET_FUN(__glewGetnTexImage)
+#define glGetnUniformdv GLEW_GET_FUN(__glewGetnUniformdv)
+
+#define GLEW_VERSION_4_5 GLEW_GET_VAR(__GLEW_VERSION_4_5)
+
+#endif /* GL_VERSION_4_5 */
+
/* -------------------------- GL_3DFX_multisample -------------------------- */
#ifndef GL_3DFX_multisample
@@ -2532,9 +2573,9 @@ typedef void (GLAPIENTRY * PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);
#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F
#define GL_DEBUG_CATEGORY_OTHER_AMD 0x9150
-typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam);
+typedef void (GLAPIENTRY *GLDEBUGPROCAMD)(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar* message, void* userParam);
-typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, GLvoid *userParam);
+typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam);
typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar* buf);
typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum* categories, GLuint* severities, GLuint* ids, GLsizei* lengths, GLchar* message);
@@ -2579,6 +2620,24 @@ typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GL
#endif /* GL_AMD_draw_buffers_blend */
+/* --------------------------- GL_AMD_gcn_shader --------------------------- */
+
+#ifndef GL_AMD_gcn_shader
+#define GL_AMD_gcn_shader 1
+
+#define GLEW_AMD_gcn_shader GLEW_GET_VAR(__GLEW_AMD_gcn_shader)
+
+#endif /* GL_AMD_gcn_shader */
+
+/* ------------------------ GL_AMD_gpu_shader_int64 ------------------------ */
+
+#ifndef GL_AMD_gpu_shader_int64
+#define GL_AMD_gpu_shader_int64 1
+
+#define GLEW_AMD_gpu_shader_int64 GLEW_GET_VAR(__GLEW_AMD_gpu_shader_int64)
+
+#endif /* GL_AMD_gpu_shader_int64 */
+
/* ---------------------- GL_AMD_interleaved_elements ---------------------- */
#ifndef GL_AMD_interleaved_elements
@@ -2607,8 +2666,8 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GL
#ifndef GL_AMD_multi_draw_indirect
#define GL_AMD_multi_draw_indirect 1
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);
#define glMultiDrawArraysIndirectAMD GLEW_GET_FUN(__glewMultiDrawArraysIndirectAMD)
#define glMultiDrawElementsIndirectAMD GLEW_GET_FUN(__glewMultiDrawElementsIndirectAMD)
@@ -2640,6 +2699,26 @@ typedef GLboolean (GLAPIENTRY * PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint n
#endif /* GL_AMD_name_gen_delete */
+/* ---------------------- GL_AMD_occlusion_query_event --------------------- */
+
+#ifndef GL_AMD_occlusion_query_event
+#define GL_AMD_occlusion_query_event 1
+
+#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001
+#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002
+#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004
+#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008
+#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F
+#define GL_QUERY_ALL_EVENT_BITS_AMD 0xFFFFFFFF
+
+typedef void (GLAPIENTRY * PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param);
+
+#define glQueryObjectParameteruiAMD GLEW_GET_FUN(__glewQueryObjectParameteruiAMD)
+
+#define GLEW_AMD_occlusion_query_event GLEW_GET_VAR(__GLEW_AMD_occlusion_query_event)
+
+#endif /* GL_AMD_occlusion_query_event */
+
/* ----------------------- GL_AMD_performance_monitor ---------------------- */
#ifndef GL_AMD_performance_monitor
@@ -2658,7 +2737,7 @@ typedef void (GLAPIENTRY * PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint* m
typedef void (GLAPIENTRY * PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
typedef void (GLAPIENTRY * PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint* monitors);
typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint* data, GLint *bytesWritten);
-typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);
typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei* length, GLchar *counterString);
typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint* numCounters, GLint *maxActiveCounters, GLsizei countersSize, GLuint *counters);
typedef void (GLAPIENTRY * PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei* length, GLchar *groupString);
@@ -2731,6 +2810,15 @@ typedef void (GLAPIENTRY * PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint i
#endif /* GL_AMD_seamless_cubemap_per_texture */
+/* -------------------- GL_AMD_shader_atomic_counter_ops ------------------- */
+
+#ifndef GL_AMD_shader_atomic_counter_ops
+#define GL_AMD_shader_atomic_counter_ops 1
+
+#define GLEW_AMD_shader_atomic_counter_ops GLEW_GET_VAR(__GLEW_AMD_shader_atomic_counter_ops)
+
+#endif /* GL_AMD_shader_atomic_counter_ops */
+
/* ---------------------- GL_AMD_shader_stencil_export --------------------- */
#ifndef GL_AMD_shader_stencil_export
@@ -2740,6 +2828,15 @@ typedef void (GLAPIENTRY * PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint i
#endif /* GL_AMD_shader_stencil_export */
+/* ------------------- GL_AMD_shader_stencil_value_export ------------------ */
+
+#ifndef GL_AMD_shader_stencil_value_export
+#define GL_AMD_shader_stencil_value_export 1
+
+#define GLEW_AMD_shader_stencil_value_export GLEW_GET_VAR(__GLEW_AMD_shader_stencil_value_export)
+
+#endif /* GL_AMD_shader_stencil_value_export */
+
/* ---------------------- GL_AMD_shader_trinary_minmax --------------------- */
#ifndef GL_AMD_shader_trinary_minmax
@@ -2810,6 +2907,17 @@ typedef void (GLAPIENTRY * PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint valu
#endif /* GL_AMD_transform_feedback3_lines_triangles */
+/* ----------------------- GL_AMD_transform_feedback4 ---------------------- */
+
+#ifndef GL_AMD_transform_feedback4
+#define GL_AMD_transform_feedback4 1
+
+#define GL_STREAM_RASTERIZATION_AMD 0x91A0
+
+#define GLEW_AMD_transform_feedback4 GLEW_GET_VAR(__GLEW_AMD_transform_feedback4)
+
+#endif /* GL_AMD_transform_feedback4 */
+
/* ----------------------- GL_AMD_vertex_shader_layer ---------------------- */
#ifndef GL_AMD_vertex_shader_layer
@@ -2903,7 +3011,7 @@ typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum
#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor);
#define glDrawArraysInstancedANGLE GLEW_GET_FUN(__glewDrawArraysInstancedANGLE)
@@ -3078,7 +3186,7 @@ typedef void (GLAPIENTRY * PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shad
typedef void (GLAPIENTRY * PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);
typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);
-typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer);
typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint* first, const GLsizei *count, GLsizei primcount);
typedef void (GLAPIENTRY * PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint* first, const GLsizei *count, GLsizei primcount);
@@ -3207,6 +3315,7 @@ typedef GLenum (GLAPIENTRY * PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType
#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
#define GL_RGB_422_APPLE 0x8A1F
+#define GL_RGB_RAW_422_APPLE 0x8A51
#define GLEW_APPLE_rgb_422 GLEW_GET_VAR(__GLEW_APPLE_rgb_422)
@@ -3247,8 +3356,8 @@ typedef GLenum (GLAPIENTRY * PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType
#define GL_STORAGE_CACHED_APPLE 0x85BE
#define GL_STORAGE_SHARED_APPLE 0x85BF
-typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, GLvoid **params);
-typedef void (GLAPIENTRY * PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params);
+typedef void (GLAPIENTRY * PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, void *pointer);
#define glGetTexParameterPointervAPPLE GLEW_GET_FUN(__glewGetTexParameterPointervAPPLE)
#define glTextureRangeAPPLE GLEW_GET_FUN(__glewTextureRangeAPPLE)
@@ -3303,9 +3412,9 @@ typedef GLboolean (GLAPIENTRY * PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
#define GL_STORAGE_CACHED_APPLE 0x85BE
#define GL_STORAGE_SHARED_APPLE 0x85BF
-typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);
-typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);
#define glFlushVertexArrayRangeAPPLE GLEW_GET_FUN(__glewFlushVertexArrayRangeAPPLE)
#define glVertexArrayParameteriAPPLE GLEW_GET_FUN(__glewVertexArrayParameteriAPPLE)
@@ -3390,7 +3499,7 @@ typedef void (GLAPIENTRY * PFNGLCLEARDEPTHFPROC) (GLclampf d);
typedef void (GLAPIENTRY * PFNGLDEPTHRANGEFPROC) (GLclampf n, GLclampf f);
typedef void (GLAPIENTRY * PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint* range, GLint *precision);
typedef void (GLAPIENTRY * PFNGLRELEASESHADERCOMPILERPROC) (void);
-typedef void (GLAPIENTRY * PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint* shaders, GLenum binaryformat, const GLvoid*binary, GLsizei length);
+typedef void (GLAPIENTRY * PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint* shaders, GLenum binaryformat, const void*binary, GLsizei length);
#define glClearDepthf GLEW_GET_FUN(__glewClearDepthf)
#define glDepthRangef GLEW_GET_FUN(__glewDepthRangef)
@@ -3402,6 +3511,36 @@ typedef void (GLAPIENTRY * PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint*
#endif /* GL_ARB_ES2_compatibility */
+/* ----------------------- GL_ARB_ES3_1_compatibility ---------------------- */
+
+#ifndef GL_ARB_ES3_1_compatibility
+#define GL_ARB_ES3_1_compatibility 1
+
+typedef void (GLAPIENTRY * PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers);
+
+#define glMemoryBarrierByRegion GLEW_GET_FUN(__glewMemoryBarrierByRegion)
+
+#define GLEW_ARB_ES3_1_compatibility GLEW_GET_VAR(__GLEW_ARB_ES3_1_compatibility)
+
+#endif /* GL_ARB_ES3_1_compatibility */
+
+/* ----------------------- GL_ARB_ES3_2_compatibility ---------------------- */
+
+#ifndef GL_ARB_ES3_2_compatibility
+#define GL_ARB_ES3_2_compatibility 1
+
+#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE
+#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381
+#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382
+
+typedef void (GLAPIENTRY * PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+
+#define glPrimitiveBoundingBoxARB GLEW_GET_FUN(__glewPrimitiveBoundingBoxARB)
+
+#define GLEW_ARB_ES3_2_compatibility GLEW_GET_VAR(__GLEW_ARB_ES3_2_compatibility)
+
+#endif /* GL_ARB_ES3_2_compatibility */
+
/* ------------------------ GL_ARB_ES3_compatibility ----------------------- */
#ifndef GL_ARB_ES3_compatibility
@@ -3441,8 +3580,8 @@ typedef void (GLAPIENTRY * PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint*
#define GL_ARB_base_instance 1
typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLuint baseinstance);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLuint baseinstance);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance);
#define glDrawArraysInstancedBaseInstance GLEW_GET_FUN(__glewDrawArraysInstancedBaseInstance)
#define glDrawElementsInstancedBaseInstance GLEW_GET_FUN(__glewDrawElementsInstancedBaseInstance)
@@ -3532,8 +3671,8 @@ typedef GLint (GLAPIENTRY * PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GL
#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
#define GL_BUFFER_STORAGE_FLAGS 0x8220
-typedef void (GLAPIENTRY * PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLbitfield flags);
-typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid* data, GLbitfield flags);
+typedef void (GLAPIENTRY * PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
#define glBufferStorage GLEW_GET_FUN(__glewBufferStorage)
#define glNamedBufferStorageEXT GLEW_GET_FUN(__glewNamedBufferStorageEXT)
@@ -3566,10 +3705,10 @@ typedef GLsync (GLAPIENTRY * PFNGLCREATESYNCFROMCLEVENTARBPROC) (cl_context cont
#ifndef GL_ARB_clear_buffer_object
#define GL_ARB_clear_buffer_object 1
-typedef void (GLAPIENTRY * PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const GLvoid* data);
-typedef void (GLAPIENTRY * PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const GLvoid* data);
-typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const GLvoid* data);
-typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const GLvoid* data);
+typedef void (GLAPIENTRY * PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
#define glClearBufferData GLEW_GET_FUN(__glewClearBufferData)
#define glClearBufferSubData GLEW_GET_FUN(__glewClearBufferSubData)
@@ -3587,8 +3726,8 @@ typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer,
#define GL_CLEAR_TEXTURE 0x9365
-typedef void (GLAPIENTRY * PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const GLvoid* data);
-typedef void (GLAPIENTRY * PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data);
+typedef void (GLAPIENTRY * PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);
#define glClearTexImage GLEW_GET_FUN(__glewClearTexImage)
#define glClearTexSubImage GLEW_GET_FUN(__glewClearTexSubImage)
@@ -3597,6 +3736,26 @@ typedef void (GLAPIENTRY * PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint lev
#endif /* GL_ARB_clear_texture */
+/* -------------------------- GL_ARB_clip_control -------------------------- */
+
+#ifndef GL_ARB_clip_control
+#define GL_ARB_clip_control 1
+
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_CLIP_ORIGIN 0x935C
+#define GL_CLIP_DEPTH_MODE 0x935D
+#define GL_NEGATIVE_ONE_TO_ONE 0x935E
+#define GL_ZERO_TO_ONE 0x935F
+
+typedef void (GLAPIENTRY * PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth);
+
+#define glClipControl GLEW_GET_FUN(__glewClipControl)
+
+#define GLEW_ARB_clip_control GLEW_GET_VAR(__GLEW_ARB_clip_control)
+
+#endif /* GL_ARB_clip_control */
+
/* ----------------------- GL_ARB_color_buffer_float ----------------------- */
#ifndef GL_ARB_color_buffer_float
@@ -3695,6 +3854,20 @@ typedef void (GLAPIENTRY * PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_gro
#endif /* GL_ARB_compute_variable_group_size */
+/* ------------------- GL_ARB_conditional_render_inverted ------------------ */
+
+#ifndef GL_ARB_conditional_render_inverted
+#define GL_ARB_conditional_render_inverted 1
+
+#define GL_QUERY_WAIT_INVERTED 0x8E17
+#define GL_QUERY_NO_WAIT_INVERTED 0x8E18
+#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19
+#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A
+
+#define GLEW_ARB_conditional_render_inverted GLEW_GET_VAR(__GLEW_ARB_conditional_render_inverted)
+
+#endif /* GL_ARB_conditional_render_inverted */
+
/* ----------------------- GL_ARB_conservative_depth ----------------------- */
#ifndef GL_ARB_conservative_depth
@@ -3733,6 +3906,18 @@ typedef void (GLAPIENTRY * PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum sr
#endif /* GL_ARB_copy_image */
+/* -------------------------- GL_ARB_cull_distance ------------------------- */
+
+#ifndef GL_ARB_cull_distance
+#define GL_ARB_cull_distance 1
+
+#define GL_MAX_CULL_DISTANCES 0x82F9
+#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA
+
+#define GLEW_ARB_cull_distance GLEW_GET_VAR(__GLEW_ARB_cull_distance)
+
+#endif /* GL_ARB_cull_distance */
+
/* -------------------------- GL_ARB_debug_output -------------------------- */
#ifndef GL_ARB_debug_output
@@ -3761,12 +3946,12 @@ typedef void (GLAPIENTRY * PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum sr
#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
-typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam);
+typedef void (GLAPIENTRY *GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
-typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam);
+typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam);
typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
-typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
+typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
#define glDebugMessageCallbackARB GLEW_GET_FUN(__glewDebugMessageCallbackARB)
#define glDebugMessageControlARB GLEW_GET_FUN(__glewDebugMessageControlARB)
@@ -3816,6 +4001,223 @@ typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsi
#endif /* GL_ARB_depth_texture */
+/* ----------------------- GL_ARB_derivative_control ----------------------- */
+
+#ifndef GL_ARB_derivative_control
+#define GL_ARB_derivative_control 1
+
+#define GLEW_ARB_derivative_control GLEW_GET_VAR(__GLEW_ARB_derivative_control)
+
+#endif /* GL_ARB_derivative_control */
+
+/* ----------------------- GL_ARB_direct_state_access ---------------------- */
+
+#ifndef GL_ARB_direct_state_access
+#define GL_ARB_direct_state_access 1
+
+#define GL_TEXTURE_TARGET 0x1006
+#define GL_QUERY_TARGET 0x82EA
+
+typedef void (GLAPIENTRY * PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture);
+typedef void (GLAPIENTRY * PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+typedef GLenum (GLAPIENTRY * PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLfloat depth, GLint stencil);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value);
+typedef void (GLAPIENTRY * PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint* buffers);
+typedef void (GLAPIENTRY * PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint* framebuffers);
+typedef void (GLAPIENTRY * PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint* pipelines);
+typedef void (GLAPIENTRY * PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint* ids);
+typedef void (GLAPIENTRY * PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint* renderbuffers);
+typedef void (GLAPIENTRY * PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint* samplers);
+typedef void (GLAPIENTRY * PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint* textures);
+typedef void (GLAPIENTRY * PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint* ids);
+typedef void (GLAPIENTRY * PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint* arrays);
+typedef void (GLAPIENTRY * PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);
+typedef void (GLAPIENTRY * PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);
+typedef void (GLAPIENTRY * PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);
+typedef void (GLAPIENTRY * PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture);
+typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64* params);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void** params);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint* param);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id,GLuint buffer,GLenum pname,GLintptr offset);
+typedef void (GLAPIENTRY * PFNGLGETQUERYBUFFEROBJECTIVPROC) (GLuint id,GLuint buffer,GLenum pname,GLintptr offset);
+typedef void (GLAPIENTRY * PFNGLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id,GLuint buffer,GLenum pname,GLintptr offset);
+typedef void (GLAPIENTRY * PFNGLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id,GLuint buffer,GLenum pname,GLintptr offset);
+typedef void (GLAPIENTRY * PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+typedef void (GLAPIENTRY * PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat* params);
+typedef void (GLAPIENTRY * PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint* params);
+typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat* params);
+typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64* param);
+typedef void (GLAPIENTRY * PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint* param);
+typedef void (GLAPIENTRY * PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint* param);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64* param);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint* param);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint* param);
+typedef void (GLAPIENTRY * PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments);
+typedef void (GLAPIENTRY * PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void * (GLAPIENTRY * PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access);
+typedef void * (GLAPIENTRY * PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum mode);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum* bufs);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum mode);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);
+typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer);
+typedef void (GLAPIENTRY * PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint* params);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint* params);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat* param);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint* param);
+typedef void (GLAPIENTRY * PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GLAPIENTRY * PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GLAPIENTRY * PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (GLAPIENTRY * PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GLAPIENTRY * PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer);
+typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef GLboolean (GLAPIENTRY * PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr *offsets, const GLsizei *strides);
+
+#define glBindTextureUnit GLEW_GET_FUN(__glewBindTextureUnit)
+#define glBlitNamedFramebuffer GLEW_GET_FUN(__glewBlitNamedFramebuffer)
+#define glCheckNamedFramebufferStatus GLEW_GET_FUN(__glewCheckNamedFramebufferStatus)
+#define glClearNamedBufferData GLEW_GET_FUN(__glewClearNamedBufferData)
+#define glClearNamedBufferSubData GLEW_GET_FUN(__glewClearNamedBufferSubData)
+#define glClearNamedFramebufferfi GLEW_GET_FUN(__glewClearNamedFramebufferfi)
+#define glClearNamedFramebufferfv GLEW_GET_FUN(__glewClearNamedFramebufferfv)
+#define glClearNamedFramebufferiv GLEW_GET_FUN(__glewClearNamedFramebufferiv)
+#define glClearNamedFramebufferuiv GLEW_GET_FUN(__glewClearNamedFramebufferuiv)
+#define glCompressedTextureSubImage1D GLEW_GET_FUN(__glewCompressedTextureSubImage1D)
+#define glCompressedTextureSubImage2D GLEW_GET_FUN(__glewCompressedTextureSubImage2D)
+#define glCompressedTextureSubImage3D GLEW_GET_FUN(__glewCompressedTextureSubImage3D)
+#define glCopyNamedBufferSubData GLEW_GET_FUN(__glewCopyNamedBufferSubData)
+#define glCopyTextureSubImage1D GLEW_GET_FUN(__glewCopyTextureSubImage1D)
+#define glCopyTextureSubImage2D GLEW_GET_FUN(__glewCopyTextureSubImage2D)
+#define glCopyTextureSubImage3D GLEW_GET_FUN(__glewCopyTextureSubImage3D)
+#define glCreateBuffers GLEW_GET_FUN(__glewCreateBuffers)
+#define glCreateFramebuffers GLEW_GET_FUN(__glewCreateFramebuffers)
+#define glCreateProgramPipelines GLEW_GET_FUN(__glewCreateProgramPipelines)
+#define glCreateQueries GLEW_GET_FUN(__glewCreateQueries)
+#define glCreateRenderbuffers GLEW_GET_FUN(__glewCreateRenderbuffers)
+#define glCreateSamplers GLEW_GET_FUN(__glewCreateSamplers)
+#define glCreateTextures GLEW_GET_FUN(__glewCreateTextures)
+#define glCreateTransformFeedbacks GLEW_GET_FUN(__glewCreateTransformFeedbacks)
+#define glCreateVertexArrays GLEW_GET_FUN(__glewCreateVertexArrays)
+#define glDisableVertexArrayAttrib GLEW_GET_FUN(__glewDisableVertexArrayAttrib)
+#define glEnableVertexArrayAttrib GLEW_GET_FUN(__glewEnableVertexArrayAttrib)
+#define glFlushMappedNamedBufferRange GLEW_GET_FUN(__glewFlushMappedNamedBufferRange)
+#define glGenerateTextureMipmap GLEW_GET_FUN(__glewGenerateTextureMipmap)
+#define glGetCompressedTextureImage GLEW_GET_FUN(__glewGetCompressedTextureImage)
+#define glGetNamedBufferParameteri64v GLEW_GET_FUN(__glewGetNamedBufferParameteri64v)
+#define glGetNamedBufferParameteriv GLEW_GET_FUN(__glewGetNamedBufferParameteriv)
+#define glGetNamedBufferPointerv GLEW_GET_FUN(__glewGetNamedBufferPointerv)
+#define glGetNamedBufferSubData GLEW_GET_FUN(__glewGetNamedBufferSubData)
+#define glGetNamedFramebufferAttachmentParameteriv GLEW_GET_FUN(__glewGetNamedFramebufferAttachmentParameteriv)
+#define glGetNamedFramebufferParameteriv GLEW_GET_FUN(__glewGetNamedFramebufferParameteriv)
+#define glGetNamedRenderbufferParameteriv GLEW_GET_FUN(__glewGetNamedRenderbufferParameteriv)
+#define glGetQueryBufferObjecti64v GLEW_GET_FUN(__glewGetQueryBufferObjecti64v)
+#define glGetQueryBufferObjectiv GLEW_GET_FUN(__glewGetQueryBufferObjectiv)
+#define glGetQueryBufferObjectui64v GLEW_GET_FUN(__glewGetQueryBufferObjectui64v)
+#define glGetQueryBufferObjectuiv GLEW_GET_FUN(__glewGetQueryBufferObjectuiv)
+#define glGetTextureImage GLEW_GET_FUN(__glewGetTextureImage)
+#define glGetTextureLevelParameterfv GLEW_GET_FUN(__glewGetTextureLevelParameterfv)
+#define glGetTextureLevelParameteriv GLEW_GET_FUN(__glewGetTextureLevelParameteriv)
+#define glGetTextureParameterIiv GLEW_GET_FUN(__glewGetTextureParameterIiv)
+#define glGetTextureParameterIuiv GLEW_GET_FUN(__glewGetTextureParameterIuiv)
+#define glGetTextureParameterfv GLEW_GET_FUN(__glewGetTextureParameterfv)
+#define glGetTextureParameteriv GLEW_GET_FUN(__glewGetTextureParameteriv)
+#define glGetTransformFeedbacki64_v GLEW_GET_FUN(__glewGetTransformFeedbacki64_v)
+#define glGetTransformFeedbacki_v GLEW_GET_FUN(__glewGetTransformFeedbacki_v)
+#define glGetTransformFeedbackiv GLEW_GET_FUN(__glewGetTransformFeedbackiv)
+#define glGetVertexArrayIndexed64iv GLEW_GET_FUN(__glewGetVertexArrayIndexed64iv)
+#define glGetVertexArrayIndexediv GLEW_GET_FUN(__glewGetVertexArrayIndexediv)
+#define glGetVertexArrayiv GLEW_GET_FUN(__glewGetVertexArrayiv)
+#define glInvalidateNamedFramebufferData GLEW_GET_FUN(__glewInvalidateNamedFramebufferData)
+#define glInvalidateNamedFramebufferSubData GLEW_GET_FUN(__glewInvalidateNamedFramebufferSubData)
+#define glMapNamedBuffer GLEW_GET_FUN(__glewMapNamedBuffer)
+#define glMapNamedBufferRange GLEW_GET_FUN(__glewMapNamedBufferRange)
+#define glNamedBufferData GLEW_GET_FUN(__glewNamedBufferData)
+#define glNamedBufferStorage GLEW_GET_FUN(__glewNamedBufferStorage)
+#define glNamedBufferSubData GLEW_GET_FUN(__glewNamedBufferSubData)
+#define glNamedFramebufferDrawBuffer GLEW_GET_FUN(__glewNamedFramebufferDrawBuffer)
+#define glNamedFramebufferDrawBuffers GLEW_GET_FUN(__glewNamedFramebufferDrawBuffers)
+#define glNamedFramebufferParameteri GLEW_GET_FUN(__glewNamedFramebufferParameteri)
+#define glNamedFramebufferReadBuffer GLEW_GET_FUN(__glewNamedFramebufferReadBuffer)
+#define glNamedFramebufferRenderbuffer GLEW_GET_FUN(__glewNamedFramebufferRenderbuffer)
+#define glNamedFramebufferTexture GLEW_GET_FUN(__glewNamedFramebufferTexture)
+#define glNamedFramebufferTextureLayer GLEW_GET_FUN(__glewNamedFramebufferTextureLayer)
+#define glNamedRenderbufferStorage GLEW_GET_FUN(__glewNamedRenderbufferStorage)
+#define glNamedRenderbufferStorageMultisample GLEW_GET_FUN(__glewNamedRenderbufferStorageMultisample)
+#define glTextureBuffer GLEW_GET_FUN(__glewTextureBuffer)
+#define glTextureBufferRange GLEW_GET_FUN(__glewTextureBufferRange)
+#define glTextureParameterIiv GLEW_GET_FUN(__glewTextureParameterIiv)
+#define glTextureParameterIuiv GLEW_GET_FUN(__glewTextureParameterIuiv)
+#define glTextureParameterf GLEW_GET_FUN(__glewTextureParameterf)
+#define glTextureParameterfv GLEW_GET_FUN(__glewTextureParameterfv)
+#define glTextureParameteri GLEW_GET_FUN(__glewTextureParameteri)
+#define glTextureParameteriv GLEW_GET_FUN(__glewTextureParameteriv)
+#define glTextureStorage1D GLEW_GET_FUN(__glewTextureStorage1D)
+#define glTextureStorage2D GLEW_GET_FUN(__glewTextureStorage2D)
+#define glTextureStorage2DMultisample GLEW_GET_FUN(__glewTextureStorage2DMultisample)
+#define glTextureStorage3D GLEW_GET_FUN(__glewTextureStorage3D)
+#define glTextureStorage3DMultisample GLEW_GET_FUN(__glewTextureStorage3DMultisample)
+#define glTextureSubImage1D GLEW_GET_FUN(__glewTextureSubImage1D)
+#define glTextureSubImage2D GLEW_GET_FUN(__glewTextureSubImage2D)
+#define glTextureSubImage3D GLEW_GET_FUN(__glewTextureSubImage3D)
+#define glTransformFeedbackBufferBase GLEW_GET_FUN(__glewTransformFeedbackBufferBase)
+#define glTransformFeedbackBufferRange GLEW_GET_FUN(__glewTransformFeedbackBufferRange)
+#define glUnmapNamedBuffer GLEW_GET_FUN(__glewUnmapNamedBuffer)
+#define glVertexArrayAttribBinding GLEW_GET_FUN(__glewVertexArrayAttribBinding)
+#define glVertexArrayAttribFormat GLEW_GET_FUN(__glewVertexArrayAttribFormat)
+#define glVertexArrayAttribIFormat GLEW_GET_FUN(__glewVertexArrayAttribIFormat)
+#define glVertexArrayAttribLFormat GLEW_GET_FUN(__glewVertexArrayAttribLFormat)
+#define glVertexArrayBindingDivisor GLEW_GET_FUN(__glewVertexArrayBindingDivisor)
+#define glVertexArrayElementBuffer GLEW_GET_FUN(__glewVertexArrayElementBuffer)
+#define glVertexArrayVertexBuffer GLEW_GET_FUN(__glewVertexArrayVertexBuffer)
+#define glVertexArrayVertexBuffers GLEW_GET_FUN(__glewVertexArrayVertexBuffers)
+
+#define GLEW_ARB_direct_state_access GLEW_GET_VAR(__GLEW_ARB_direct_state_access)
+
+#endif /* GL_ARB_direct_state_access */
+
/* -------------------------- GL_ARB_draw_buffers -------------------------- */
#ifndef GL_ARB_draw_buffers
@@ -3871,10 +4273,10 @@ typedef void (GLAPIENTRY * PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLen
#ifndef GL_ARB_draw_elements_base_vertex
#define GL_ARB_draw_elements_base_vertex 1
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex);
-typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const *indices, GLsizei primcount, const GLint *basevertex);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount, GLint basevertex);
+typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei* count, GLenum type, const void *const *indices, GLsizei primcount, const GLint *basevertex);
#define glDrawElementsBaseVertex GLEW_GET_FUN(__glewDrawElementsBaseVertex)
#define glDrawElementsInstancedBaseVertex GLEW_GET_FUN(__glewDrawElementsInstancedBaseVertex)
@@ -3893,8 +4295,8 @@ typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, c
#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
-typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect);
+typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);
#define glDrawArraysIndirect GLEW_GET_FUN(__glewDrawArraysIndirect)
#define glDrawElementsIndirect GLEW_GET_FUN(__glewDrawElementsIndirect)
@@ -4010,6 +4412,15 @@ typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum t
#endif /* GL_ARB_fragment_shader */
+/* -------------------- GL_ARB_fragment_shader_interlock ------------------- */
+
+#ifndef GL_ARB_fragment_shader_interlock
+#define GL_ARB_fragment_shader_interlock 1
+
+#define GLEW_ARB_fragment_shader_interlock GLEW_GET_VAR(__GLEW_ARB_fragment_shader_interlock)
+
+#endif /* GL_ARB_fragment_shader_interlock */
+
/* ------------------- GL_ARB_framebuffer_no_attachments ------------------- */
#ifndef GL_ARB_framebuffer_no_attachments
@@ -4225,8 +4636,8 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenu
#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
#define GL_PROGRAM_BINARY_FORMATS 0x87FF
-typedef void (GLAPIENTRY * PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLenum *binaryFormat, GLvoid*binary);
-typedef void (GLAPIENTRY * PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length);
+typedef void (GLAPIENTRY * PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLenum *binaryFormat, void*binary);
+typedef void (GLAPIENTRY * PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);
typedef void (GLAPIENTRY * PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);
#define glGetProgramBinary GLEW_GET_FUN(__glewGetProgramBinary)
@@ -4237,6 +4648,21 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum p
#endif /* GL_ARB_get_program_binary */
+/* ---------------------- GL_ARB_get_texture_sub_image --------------------- */
+
+#ifndef GL_ARB_get_texture_sub_image
+#define GL_ARB_get_texture_sub_image 1
+
+typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);
+typedef void (GLAPIENTRY * PFNGLGETTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels);
+
+#define glGetCompressedTextureSubImage GLEW_GET_FUN(__glewGetCompressedTextureSubImage)
+#define glGetTextureSubImage GLEW_GET_FUN(__glewGetTextureSubImage)
+
+#define GLEW_ARB_get_texture_sub_image GLEW_GET_VAR(__GLEW_ARB_get_texture_sub_image)
+
+#endif /* GL_ARB_get_texture_sub_image */
+
/* --------------------------- GL_ARB_gpu_shader5 -------------------------- */
#ifndef GL_ARB_gpu_shader5
@@ -4313,6 +4739,98 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei
#endif /* GL_ARB_gpu_shader_fp64 */
+/* ------------------------ GL_ARB_gpu_shader_int64 ------------------------ */
+
+#ifndef GL_ARB_gpu_shader_int64
+#define GL_ARB_gpu_shader_int64 1
+
+#define GL_INT64_ARB 0x140E
+#define GL_UNSIGNED_INT64_ARB 0x140F
+#define GL_INT64_VEC2_ARB 0x8FE9
+#define GL_INT64_VEC3_ARB 0x8FEA
+#define GL_INT64_VEC4_ARB 0x8FEB
+#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5
+#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6
+#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7
+
+typedef void (GLAPIENTRY * PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64* params);
+typedef void (GLAPIENTRY * PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64* params);
+typedef void (GLAPIENTRY * PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64* params);
+typedef void (GLAPIENTRY * PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64* params);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
+typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x);
+typedef void (GLAPIENTRY * PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x);
+typedef void (GLAPIENTRY * PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y);
+typedef void (GLAPIENTRY * PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y);
+typedef void (GLAPIENTRY * PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z);
+typedef void (GLAPIENTRY * PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
+typedef void (GLAPIENTRY * PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
+typedef void (GLAPIENTRY * PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64* value);
+typedef void (GLAPIENTRY * PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
+typedef void (GLAPIENTRY * PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64* value);
+
+#define glGetUniformi64vARB GLEW_GET_FUN(__glewGetUniformi64vARB)
+#define glGetUniformui64vARB GLEW_GET_FUN(__glewGetUniformui64vARB)
+#define glGetnUniformi64vARB GLEW_GET_FUN(__glewGetnUniformi64vARB)
+#define glGetnUniformui64vARB GLEW_GET_FUN(__glewGetnUniformui64vARB)
+#define glProgramUniform1i64ARB GLEW_GET_FUN(__glewProgramUniform1i64ARB)
+#define glProgramUniform1i64vARB GLEW_GET_FUN(__glewProgramUniform1i64vARB)
+#define glProgramUniform1ui64ARB GLEW_GET_FUN(__glewProgramUniform1ui64ARB)
+#define glProgramUniform1ui64vARB GLEW_GET_FUN(__glewProgramUniform1ui64vARB)
+#define glProgramUniform2i64ARB GLEW_GET_FUN(__glewProgramUniform2i64ARB)
+#define glProgramUniform2i64vARB GLEW_GET_FUN(__glewProgramUniform2i64vARB)
+#define glProgramUniform2ui64ARB GLEW_GET_FUN(__glewProgramUniform2ui64ARB)
+#define glProgramUniform2ui64vARB GLEW_GET_FUN(__glewProgramUniform2ui64vARB)
+#define glProgramUniform3i64ARB GLEW_GET_FUN(__glewProgramUniform3i64ARB)
+#define glProgramUniform3i64vARB GLEW_GET_FUN(__glewProgramUniform3i64vARB)
+#define glProgramUniform3ui64ARB GLEW_GET_FUN(__glewProgramUniform3ui64ARB)
+#define glProgramUniform3ui64vARB GLEW_GET_FUN(__glewProgramUniform3ui64vARB)
+#define glProgramUniform4i64ARB GLEW_GET_FUN(__glewProgramUniform4i64ARB)
+#define glProgramUniform4i64vARB GLEW_GET_FUN(__glewProgramUniform4i64vARB)
+#define glProgramUniform4ui64ARB GLEW_GET_FUN(__glewProgramUniform4ui64ARB)
+#define glProgramUniform4ui64vARB GLEW_GET_FUN(__glewProgramUniform4ui64vARB)
+#define glUniform1i64ARB GLEW_GET_FUN(__glewUniform1i64ARB)
+#define glUniform1i64vARB GLEW_GET_FUN(__glewUniform1i64vARB)
+#define glUniform1ui64ARB GLEW_GET_FUN(__glewUniform1ui64ARB)
+#define glUniform1ui64vARB GLEW_GET_FUN(__glewUniform1ui64vARB)
+#define glUniform2i64ARB GLEW_GET_FUN(__glewUniform2i64ARB)
+#define glUniform2i64vARB GLEW_GET_FUN(__glewUniform2i64vARB)
+#define glUniform2ui64ARB GLEW_GET_FUN(__glewUniform2ui64ARB)
+#define glUniform2ui64vARB GLEW_GET_FUN(__glewUniform2ui64vARB)
+#define glUniform3i64ARB GLEW_GET_FUN(__glewUniform3i64ARB)
+#define glUniform3i64vARB GLEW_GET_FUN(__glewUniform3i64vARB)
+#define glUniform3ui64ARB GLEW_GET_FUN(__glewUniform3ui64ARB)
+#define glUniform3ui64vARB GLEW_GET_FUN(__glewUniform3ui64vARB)
+#define glUniform4i64ARB GLEW_GET_FUN(__glewUniform4i64ARB)
+#define glUniform4i64vARB GLEW_GET_FUN(__glewUniform4i64vARB)
+#define glUniform4ui64ARB GLEW_GET_FUN(__glewUniform4ui64ARB)
+#define glUniform4ui64vARB GLEW_GET_FUN(__glewUniform4ui64vARB)
+
+#define GLEW_ARB_gpu_shader_int64 GLEW_GET_VAR(__GLEW_ARB_gpu_shader_int64)
+
+#endif /* GL_ARB_gpu_shader_int64 */
+
/* ------------------------ GL_ARB_half_float_pixel ------------------------ */
#ifndef GL_ARB_half_float_pixel
@@ -4418,12 +4936,12 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei
#define GL_REPLICATE_BORDER 0x8153
#define GL_CONVOLUTION_BORDER_COLOR 0x8154
-typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);
-typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
-typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);
@@ -4432,24 +4950,24 @@ typedef void (GLAPIENTRY * PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei s
typedef void (GLAPIENTRY * PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);
typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
-typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);
typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
-typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
-typedef void (GLAPIENTRY * PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum types, void *values);
typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);
typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
-typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
+typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
typedef void (GLAPIENTRY * PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
typedef void (GLAPIENTRY * PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);
typedef void (GLAPIENTRY * PFNGLRESETHISTOGRAMPROC) (GLenum target);
typedef void (GLAPIENTRY * PFNGLRESETMINMAXPROC) (GLenum target);
-typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
#define glColorSubTable GLEW_GET_FUN(__glewColorSubTable)
#define glColorTable GLEW_GET_FUN(__glewColorTable)
@@ -4496,8 +5014,8 @@ typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum in
#define GL_PARAMETER_BUFFER_ARB 0x80EE
#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const GLvoid *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);
#define glMultiDrawArraysIndirectCountARB GLEW_GET_FUN(__glewMultiDrawArraysIndirectCountARB)
#define glMultiDrawElementsIndirectCountARB GLEW_GET_FUN(__glewMultiDrawElementsIndirectCountARB)
@@ -4700,7 +5218,7 @@ typedef void (GLAPIENTRY * PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLin
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
typedef void (GLAPIENTRY * PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
-typedef GLvoid * (GLAPIENTRY * PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void * (GLAPIENTRY * PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
#define glFlushMappedBufferRange GLEW_GET_FUN(__glewFlushMappedBufferRange)
#define glMapBufferRange GLEW_GET_FUN(__glewMapBufferRange)
@@ -4726,7 +5244,7 @@ typedef GLvoid * (GLAPIENTRY * PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr
#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849
typedef void (GLAPIENTRY * PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);
-typedef void (GLAPIENTRY * PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, void *pointer);
typedef void (GLAPIENTRY * PFNGLMATRIXINDEXUBVARBPROC) (GLint size, GLubyte *indices);
typedef void (GLAPIENTRY * PFNGLMATRIXINDEXUIVARBPROC) (GLint size, GLuint *indices);
typedef void (GLAPIENTRY * PFNGLMATRIXINDEXUSVARBPROC) (GLint size, GLushort *indices);
@@ -4769,8 +5287,8 @@ typedef void (GLAPIENTRY * PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei co
#ifndef GL_ARB_multi_draw_indirect
#define GL_ARB_multi_draw_indirect 1
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);
#define glMultiDrawArraysIndirect GLEW_GET_FUN(__glewMultiDrawArraysIndirect)
#define glMultiDrawElementsIndirect GLEW_GET_FUN(__glewMultiDrawElementsIndirect)
@@ -4961,6 +5479,43 @@ typedef GLboolean (GLAPIENTRY * PFNGLISQUERYARBPROC) (GLuint id);
#endif /* GL_ARB_occlusion_query2 */
+/* --------------------- GL_ARB_parallel_shader_compile -------------------- */
+
+#ifndef GL_ARB_parallel_shader_compile
+#define GL_ARB_parallel_shader_compile 1
+
+#define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0
+#define GL_COMPLETION_STATUS_ARB 0x91B1
+
+typedef void (GLAPIENTRY * PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count);
+
+#define glMaxShaderCompilerThreadsARB GLEW_GET_FUN(__glewMaxShaderCompilerThreadsARB)
+
+#define GLEW_ARB_parallel_shader_compile GLEW_GET_VAR(__GLEW_ARB_parallel_shader_compile)
+
+#endif /* GL_ARB_parallel_shader_compile */
+
+/* -------------------- GL_ARB_pipeline_statistics_query ------------------- */
+
+#ifndef GL_ARB_pipeline_statistics_query
+#define GL_ARB_pipeline_statistics_query 1
+
+#define GL_VERTICES_SUBMITTED_ARB 0x82EE
+#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF
+#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0
+#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1
+#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2
+#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3
+#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4
+#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5
+#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6
+#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7
+#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
+
+#define GLEW_ARB_pipeline_statistics_query GLEW_GET_VAR(__GLEW_ARB_pipeline_statistics_query)
+
+#endif /* GL_ARB_pipeline_statistics_query */
+
/* ----------------------- GL_ARB_pixel_buffer_object ---------------------- */
#ifndef GL_ARB_pixel_buffer_object
@@ -5007,6 +5562,15 @@ typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GL
#endif /* GL_ARB_point_sprite */
+/* ----------------------- GL_ARB_post_depth_coverage ---------------------- */
+
+#ifndef GL_ARB_post_depth_coverage
+#define GL_ARB_post_depth_coverage 1
+
+#define GLEW_ARB_post_depth_coverage GLEW_GET_VAR(__GLEW_ARB_post_depth_coverage)
+
+#endif /* GL_ARB_post_depth_coverage */
+
/* --------------------- GL_ARB_program_interface_query -------------------- */
#ifndef GL_ARB_program_interface_query
@@ -5145,7 +5709,7 @@ typedef void (GLAPIENTRY * PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufS
typedef void (GLAPIENTRY * PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint* values);
typedef void (GLAPIENTRY * PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort* values);
typedef void (GLAPIENTRY * PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte* pattern);
-typedef void (GLAPIENTRY * PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void* row, GLsizei columnBufSize, GLvoid*column, GLvoid*span);
+typedef void (GLAPIENTRY * PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void* row, GLsizei columnBufSize, void*column, void*span);
typedef void (GLAPIENTRY * PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* img);
typedef void (GLAPIENTRY * PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat* params);
@@ -5196,6 +5760,30 @@ typedef void (GLAPIENTRY * PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei w
#endif /* GL_ARB_robustness_share_group_isolation */
+/* ------------------------ GL_ARB_sample_locations ------------------------ */
+
+#ifndef GL_ARB_sample_locations
+#define GL_ARB_sample_locations 1
+
+#define GL_SAMPLE_LOCATION_ARB 0x8E50
+#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341
+#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342
+#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343
+
+typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat* v);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v);
+
+#define glFramebufferSampleLocationsfvARB GLEW_GET_FUN(__glewFramebufferSampleLocationsfvARB)
+#define glNamedFramebufferSampleLocationsfvARB GLEW_GET_FUN(__glewNamedFramebufferSampleLocationsfvARB)
+
+#define GLEW_ARB_sample_locations GLEW_GET_VAR(__GLEW_ARB_sample_locations)
+
+#endif /* GL_ARB_sample_locations */
+
/* ------------------------- GL_ARB_sample_shading ------------------------- */
#ifndef GL_ARB_sample_shading
@@ -5292,7 +5880,7 @@ typedef void (GLAPIENTRY * PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum
typedef void (GLAPIENTRY * PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);
typedef void (GLAPIENTRY * PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);
-typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar ** strings);
+typedef GLuint (GLAPIENTRY * PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar * const * strings);
typedef void (GLAPIENTRY * PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint* pipelines);
typedef void (GLAPIENTRY * PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint* pipelines);
typedef void (GLAPIENTRY * PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar *infoLog);
@@ -5416,6 +6004,15 @@ typedef void (GLAPIENTRY * PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);
#endif /* GL_ARB_separate_shader_objects */
+/* -------------------- GL_ARB_shader_atomic_counter_ops ------------------- */
+
+#ifndef GL_ARB_shader_atomic_counter_ops
+#define GL_ARB_shader_atomic_counter_ops 1
+
+#define GLEW_ARB_shader_atomic_counter_ops GLEW_GET_VAR(__GLEW_ARB_shader_atomic_counter_ops)
+
+#endif /* GL_ARB_shader_atomic_counter_ops */
+
/* --------------------- GL_ARB_shader_atomic_counters --------------------- */
#ifndef GL_ARB_shader_atomic_counters
@@ -5459,6 +6056,15 @@ typedef void (GLAPIENTRY * PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint prog
#endif /* GL_ARB_shader_atomic_counters */
+/* -------------------------- GL_ARB_shader_ballot ------------------------- */
+
+#ifndef GL_ARB_shader_ballot
+#define GL_ARB_shader_ballot 1
+
+#define GLEW_ARB_shader_ballot GLEW_GET_VAR(__GLEW_ARB_shader_ballot)
+
+#endif /* GL_ARB_shader_ballot */
+
/* ----------------------- GL_ARB_shader_bit_encoding ---------------------- */
#ifndef GL_ARB_shader_bit_encoding
@@ -5468,6 +6074,15 @@ typedef void (GLAPIENTRY * PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint prog
#endif /* GL_ARB_shader_bit_encoding */
+/* -------------------------- GL_ARB_shader_clock -------------------------- */
+
+#ifndef GL_ARB_shader_clock
+#define GL_ARB_shader_clock 1
+
+#define GLEW_ARB_shader_clock GLEW_GET_VAR(__GLEW_ARB_shader_clock)
+
+#endif /* GL_ARB_shader_clock */
+
/* --------------------- GL_ARB_shader_draw_parameters --------------------- */
#ifndef GL_ARB_shader_draw_parameters
@@ -5787,6 +6402,15 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, G
#endif /* GL_ARB_shader_subroutine */
+/* ------------------ GL_ARB_shader_texture_image_samples ------------------ */
+
+#ifndef GL_ARB_shader_texture_image_samples
+#define GL_ARB_shader_texture_image_samples 1
+
+#define GLEW_ARB_shader_texture_image_samples GLEW_GET_VAR(__GLEW_ARB_shader_texture_image_samples)
+
+#endif /* GL_ARB_shader_texture_image_samples */
+
/* ----------------------- GL_ARB_shader_texture_lod ----------------------- */
#ifndef GL_ARB_shader_texture_lod
@@ -5796,6 +6420,15 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, G
#endif /* GL_ARB_shader_texture_lod */
+/* ------------------- GL_ARB_shader_viewport_layer_array ------------------ */
+
+#ifndef GL_ARB_shader_viewport_layer_array
+#define GL_ARB_shader_viewport_layer_array 1
+
+#define GLEW_ARB_shader_viewport_layer_array GLEW_GET_VAR(__GLEW_ARB_shader_viewport_layer_array)
+
+#endif /* GL_ARB_shader_viewport_layer_array */
+
/* ---------------------- GL_ARB_shading_language_100 ---------------------- */
#ifndef GL_ARB_shading_language_100
@@ -5876,6 +6509,22 @@ typedef void (GLAPIENTRY * PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen,
#endif /* GL_ARB_shadow_ambient */
+/* -------------------------- GL_ARB_sparse_buffer ------------------------- */
+
+#ifndef GL_ARB_sparse_buffer
+#define GL_ARB_sparse_buffer 1
+
+#define GL_SPARSE_STORAGE_BIT_ARB 0x0400
+#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB 0x82F8
+
+typedef void (GLAPIENTRY * PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit);
+
+#define glBufferPageCommitmentARB GLEW_GET_FUN(__glewBufferPageCommitmentARB)
+
+#define GLEW_ARB_sparse_buffer GLEW_GET_VAR(__GLEW_ARB_sparse_buffer)
+
+#endif /* GL_ARB_sparse_buffer */
+
/* ------------------------- GL_ARB_sparse_texture ------------------------- */
#ifndef GL_ARB_sparse_texture
@@ -5894,7 +6543,7 @@ typedef void (GLAPIENTRY * PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen,
#define GL_NUM_SPARSE_LEVELS_ARB 0x91AA
typedef void (GLAPIENTRY * PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
-typedef void (GLAPIENTRY * PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
+typedef void (GLAPIENTRY * PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);
#define glTexPageCommitmentARB GLEW_GET_FUN(__glewTexPageCommitmentARB)
#define glTexturePageCommitmentEXT GLEW_GET_FUN(__glewTexturePageCommitmentEXT)
@@ -5903,6 +6552,24 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, G
#endif /* GL_ARB_sparse_texture */
+/* ------------------------- GL_ARB_sparse_texture2 ------------------------ */
+
+#ifndef GL_ARB_sparse_texture2
+#define GL_ARB_sparse_texture2 1
+
+#define GLEW_ARB_sparse_texture2 GLEW_GET_VAR(__GLEW_ARB_sparse_texture2)
+
+#endif /* GL_ARB_sparse_texture2 */
+
+/* ---------------------- GL_ARB_sparse_texture_clamp ---------------------- */
+
+#ifndef GL_ARB_sparse_texture_clamp
+#define GL_ARB_sparse_texture_clamp 1
+
+#define GLEW_ARB_sparse_texture_clamp GLEW_GET_VAR(__GLEW_ARB_sparse_texture_clamp)
+
+#endif /* GL_ARB_sparse_texture_clamp */
+
/* ------------------------ GL_ARB_stencil_texturing ----------------------- */
#ifndef GL_ARB_stencil_texturing
@@ -6003,6 +6670,19 @@ typedef void (GLAPIENTRY * PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value)
#endif /* GL_ARB_tessellation_shader */
+/* ------------------------- GL_ARB_texture_barrier ------------------------ */
+
+#ifndef GL_ARB_texture_barrier
+#define GL_ARB_texture_barrier 1
+
+typedef void (GLAPIENTRY * PFNGLTEXTUREBARRIERPROC) (void);
+
+#define glTextureBarrier GLEW_GET_FUN(__glewTextureBarrier)
+
+#define GLEW_ARB_texture_barrier GLEW_GET_VAR(__GLEW_ARB_texture_barrier)
+
+#endif /* GL_ARB_texture_barrier */
+
/* ---------------------- GL_ARB_texture_border_clamp ---------------------- */
#ifndef GL_ARB_texture_border_clamp
@@ -6078,13 +6758,13 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLen
#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLvoid *img);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, void *img);
#define glCompressedTexImage1DARB GLEW_GET_FUN(__glewCompressedTexImage1DARB)
#define glCompressedTexImage2DARB GLEW_GET_FUN(__glewCompressedTexImage2DARB)
@@ -6227,6 +6907,18 @@ typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GL
#endif /* GL_ARB_texture_env_dot3 */
+/* ---------------------- GL_ARB_texture_filter_minmax --------------------- */
+
+#ifndef GL_ARB_texture_filter_minmax
+#define GL_ARB_texture_filter_minmax 1
+
+#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366
+#define GL_WEIGHTED_AVERAGE_ARB 0x9367
+
+#define GLEW_ARB_texture_filter_minmax GLEW_GET_VAR(__GLEW_ARB_texture_filter_minmax)
+
+#endif /* GL_ARB_texture_filter_minmax */
+
/* -------------------------- GL_ARB_texture_float ------------------------- */
#ifndef GL_ARB_texture_float
@@ -6321,8 +7013,8 @@ typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GL
typedef void (GLAPIENTRY * PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat* val);
typedef void (GLAPIENTRY * PFNGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask);
-typedef void (GLAPIENTRY * PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
-typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
#define glGetMultisamplefv GLEW_GET_FUN(__glewGetMultisamplefv)
#define glSampleMaski GLEW_GET_FUN(__glewSampleMaski)
@@ -6598,6 +7290,18 @@ typedef void (GLAPIENTRY * PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenu
#endif /* GL_ARB_transform_feedback_instanced */
+/* ---------------- GL_ARB_transform_feedback_overflow_query --------------- */
+
+#ifndef GL_ARB_transform_feedback_overflow_query
+#define GL_ARB_transform_feedback_overflow_query 1
+
+#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC
+#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED
+
+#define GLEW_ARB_transform_feedback_overflow_query GLEW_GET_VAR(__GLEW_ARB_transform_feedback_overflow_query)
+
+#endif /* GL_ARB_transform_feedback_overflow_query */
+
/* ------------------------ GL_ARB_transpose_matrix ------------------------ */
#ifndef GL_ARB_transpose_matrix
@@ -6669,7 +7373,7 @@ typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuin
typedef void (GLAPIENTRY * PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint* data);
typedef GLuint (GLAPIENTRY * PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar* uniformBlockName);
-typedef void (GLAPIENTRY * PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar** uniformNames, GLuint* uniformIndices);
+typedef void (GLAPIENTRY * PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar* const * uniformNames, GLuint* uniformIndices);
typedef void (GLAPIENTRY * PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
#define glBindBufferBase GLEW_GET_FUN(__glewBindBufferBase)
@@ -6762,8 +7466,15 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint s
#define GL_VERTEX_BINDING_STRIDE 0x82D8
#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
+#define GL_VERTEX_BINDING_BUFFER 0x8F4F
typedef void (GLAPIENTRY * PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
@@ -6771,6 +7482,12 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GL
typedef void (GLAPIENTRY * PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);
#define glBindVertexBuffer GLEW_GET_FUN(__glewBindVertexBuffer)
+#define glVertexArrayBindVertexBufferEXT GLEW_GET_FUN(__glewVertexArrayBindVertexBufferEXT)
+#define glVertexArrayVertexAttribBindingEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribBindingEXT)
+#define glVertexArrayVertexAttribFormatEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribFormatEXT)
+#define glVertexArrayVertexAttribIFormatEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribIFormatEXT)
+#define glVertexArrayVertexAttribLFormatEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribLFormatEXT)
+#define glVertexArrayVertexBindingDivisorEXT GLEW_GET_FUN(__glewVertexArrayVertexBindingDivisorEXT)
#define glVertexAttribBinding GLEW_GET_FUN(__glewVertexAttribBinding)
#define glVertexAttribFormat GLEW_GET_FUN(__glewVertexAttribFormat)
#define glVertexAttribIFormat GLEW_GET_FUN(__glewVertexAttribIFormat)
@@ -6830,7 +7547,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex,
#define GL_MODELVIEW31_ARB 0x873F
typedef void (GLAPIENTRY * PFNGLVERTEXBLENDARBPROC) (GLint count);
-typedef void (GLAPIENTRY * PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, void *pointer);
typedef void (GLAPIENTRY * PFNGLWEIGHTBVARBPROC) (GLint size, GLbyte *weights);
typedef void (GLAPIENTRY * PFNGLWEIGHTDVARBPROC) (GLint size, GLdouble *weights);
typedef void (GLAPIENTRY * PFNGLWEIGHTFVARBPROC) (GLint size, GLfloat *weights);
@@ -6896,15 +7613,15 @@ typedef ptrdiff_t GLintptrARB;
typedef ptrdiff_t GLsizeiptrARB;
typedef void (GLAPIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
-typedef void (GLAPIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
-typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);
+typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);
typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint* buffers);
typedef void (GLAPIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint* buffers);
typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid** params);
-typedef void (GLAPIENTRY * PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void** params);
+typedef void (GLAPIENTRY * PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);
typedef GLboolean (GLAPIENTRY * PFNGLISBUFFERARBPROC) (GLuint buffer);
-typedef GLvoid * (GLAPIENTRY * PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
+typedef void * (GLAPIENTRY * PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
typedef GLboolean (GLAPIENTRY * PFNGLUNMAPBUFFERARBPROC) (GLenum target);
#define glBindBufferARB GLEW_GET_FUN(__glewBindBufferARB)
@@ -7017,9 +7734,9 @@ typedef void (GLAPIENTRY * PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target,
typedef void (GLAPIENTRY * PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat* params);
-typedef void (GLAPIENTRY * PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string);
+typedef void (GLAPIENTRY * PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);
typedef void (GLAPIENTRY * PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid** pointer);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void** pointer);
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint* params);
@@ -7032,7 +7749,7 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target,
typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble* params);
typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat* params);
-typedef void (GLAPIENTRY * PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (GLAPIENTRY * PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);
@@ -7069,7 +7786,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLs
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort* v);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
#define glBindProgramARB GLEW_GET_FUN(__glewBindProgramARB)
#define glDeleteProgramsARB GLEW_GET_FUN(__glewDeleteProgramsARB)
@@ -7447,7 +8164,7 @@ typedef void (GLAPIENTRY * PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum* bu
typedef void (GLAPIENTRY * PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);
typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);
-typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer);
#define glDrawElementArrayATI GLEW_GET_FUN(__glewDrawElementArrayATI)
#define glDrawRangeElementArrayATI GLEW_GET_FUN(__glewDrawRangeElementArrayATI)
@@ -7490,13 +8207,13 @@ typedef void (GLAPIENTRY * PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint
#ifndef GL_ATI_fragment_shader
#define GL_ATI_fragment_shader 1
-#define GL_RED_BIT_ATI 0x00000001
#define GL_2X_BIT_ATI 0x00000001
+#define GL_RED_BIT_ATI 0x00000001
#define GL_4X_BIT_ATI 0x00000002
-#define GL_GREEN_BIT_ATI 0x00000002
#define GL_COMP_BIT_ATI 0x00000002
-#define GL_BLUE_BIT_ATI 0x00000004
+#define GL_GREEN_BIT_ATI 0x00000002
#define GL_8X_BIT_ATI 0x00000004
+#define GL_BLUE_BIT_ATI 0x00000004
#define GL_NEGATE_BIT_ATI 0x00000004
#define GL_BIAS_BIT_ATI 0x00000008
#define GL_HALF_BIT_ATI 0x00000008
@@ -7584,7 +8301,7 @@ typedef void (GLAPIENTRY * PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, c
#ifndef GL_ATI_map_object_buffer
#define GL_ATI_map_object_buffer 1
-typedef GLvoid * (GLAPIENTRY * PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
+typedef void * (GLAPIENTRY * PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);
typedef void (GLAPIENTRY * PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);
#define glMapObjectBufferATI GLEW_GET_FUN(__glewMapObjectBufferATI)
@@ -7753,8 +8470,8 @@ typedef void (GLAPIENTRY * PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum
typedef void (GLAPIENTRY * PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint* params);
typedef GLboolean (GLAPIENTRY * PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);
-typedef GLuint (GLAPIENTRY * PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage);
-typedef void (GLAPIENTRY * PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve);
+typedef GLuint (GLAPIENTRY * PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage);
+typedef void (GLAPIENTRY * PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);
typedef void (GLAPIENTRY * PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);
#define glArrayObjectATI GLEW_GET_FUN(__glewArrayObjectATI)
@@ -8098,7 +8815,7 @@ typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);
#ifndef GL_EXT_color_subtable
#define GL_EXT_color_subtable 1
-typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);
typedef void (GLAPIENTRY * PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);
#define glColorSubTableEXT GLEW_GET_FUN(__glewColorSubTableEXT)
@@ -8152,19 +8869,19 @@ typedef void (GLAPIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022
#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023
-typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image);
-typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);
+typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat* params);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);
typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint* params);
typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image);
+typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image);
typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span);
-typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column);
+typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);
+typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);
#define glConvolutionFilter1DEXT GLEW_GET_FUN(__glewConvolutionFilter1DEXT)
#define glConvolutionFilter2DEXT GLEW_GET_FUN(__glewConvolutionFilter2DEXT)
@@ -8204,8 +8921,8 @@ typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum
#define GL_MAP1_BINORMAL_EXT 0x8446
#define GL_MAP2_BINORMAL_EXT 0x8447
-typedef void (GLAPIENTRY * PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLvoid *pointer);
-typedef void (GLAPIENTRY * PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, void *pointer);
+typedef void (GLAPIENTRY * PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, void *pointer);
#define glBinormalPointerEXT GLEW_GET_FUN(__glewBinormalPointerEXT)
#define glTangentPointerEXT GLEW_GET_FUN(__glewTangentPointerEXT)
@@ -8254,6 +8971,28 @@ typedef void (GLAPIENTRY * PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat*
#endif /* GL_EXT_cull_vertex */
+/* --------------------------- GL_EXT_debug_label -------------------------- */
+
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+
+typedef void (GLAPIENTRY * PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei* length, GLchar *label);
+typedef void (GLAPIENTRY * PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar* label);
+
+#define glGetObjectLabelEXT GLEW_GET_FUN(__glewGetObjectLabelEXT)
+#define glLabelObjectEXT GLEW_GET_FUN(__glewLabelObjectEXT)
+
+#define GLEW_EXT_debug_label GLEW_GET_VAR(__GLEW_EXT_debug_label)
+
+#endif /* GL_EXT_debug_label */
+
/* -------------------------- GL_EXT_debug_marker -------------------------- */
#ifndef GL_EXT_debug_marker
@@ -8299,18 +9038,18 @@ typedef void (GLAPIENTRY * PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zma
typedef void (GLAPIENTRY * PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture);
typedef GLenum (GLAPIENTRY * PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target);
typedef void (GLAPIENTRY * PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);
+typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);
typedef void (GLAPIENTRY * PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);
typedef void (GLAPIENTRY * PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
typedef void (GLAPIENTRY * PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);
@@ -8335,8 +9074,8 @@ typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuff
typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);
typedef void (GLAPIENTRY * PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target);
typedef void (GLAPIENTRY * PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target);
-typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLvoid *img);
-typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLvoid *img);
+typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, void *img);
+typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, void *img);
typedef void (GLAPIENTRY * PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat* params);
@@ -8347,7 +9086,7 @@ typedef void (GLAPIENTRY * PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum
typedef void (GLAPIENTRY * PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
typedef void (GLAPIENTRY * PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint* params);
@@ -8356,18 +9095,18 @@ typedef void (GLAPIENTRY * PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit,
typedef void (GLAPIENTRY * PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void** params);
-typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
typedef void (GLAPIENTRY * PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat* params);
-typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string);
+typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string);
typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid** params);
-typedef void (GLAPIENTRY * PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, GLvoid** params);
-typedef void (GLAPIENTRY * PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void** params);
+typedef void (GLAPIENTRY * PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void** params);
+typedef void (GLAPIENTRY * PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);
typedef void (GLAPIENTRY * PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint* params);
@@ -8376,10 +9115,10 @@ typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, G
typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint* param);
typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint* param);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLvoid** param);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, GLvoid** param);
-typedef GLvoid * (GLAPIENTRY * PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access);
-typedef GLvoid * (GLAPIENTRY * PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void** param);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void** param);
+typedef void * (GLAPIENTRY * PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access);
+typedef void * (GLAPIENTRY * PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
typedef void (GLAPIENTRY * PFNGLMATRIXFRUSTUMEXTPROC) (GLenum matrixMode, GLdouble l, GLdouble r, GLdouble b, GLdouble t, GLdouble n, GLdouble f);
typedef void (GLAPIENTRY * PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum matrixMode);
typedef void (GLAPIENTRY * PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum matrixMode, const GLdouble* m);
@@ -8400,7 +9139,7 @@ typedef void (GLAPIENTRY * PFNGLMATRIXSCALEFEXTPROC) (GLenum matrixMode, GLfloat
typedef void (GLAPIENTRY * PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z);
typedef void (GLAPIENTRY * PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z);
typedef void (GLAPIENTRY * PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);
-typedef void (GLAPIENTRY * PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
typedef void (GLAPIENTRY * PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat* params);
typedef void (GLAPIENTRY * PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);
@@ -8411,9 +9150,9 @@ typedef void (GLAPIENTRY * PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coo
typedef void (GLAPIENTRY * PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat* params);
typedef void (GLAPIENTRY * PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param);
typedef void (GLAPIENTRY * PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint* params);
-typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint* params);
typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint* params);
typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);
@@ -8421,11 +9160,11 @@ typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLe
typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);
typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint* param);
typedef void (GLAPIENTRY * PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer);
-typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage);
-typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
typedef void (GLAPIENTRY * PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
@@ -8445,7 +9184,7 @@ typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint
typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat* params);
typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint* params);
typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint* params);
-typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string);
+typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);
typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
@@ -8484,9 +9223,9 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint progra
typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
typedef void (GLAPIENTRY * PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);
typedef void (GLAPIENTRY * PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);
-typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint* params);
typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint* params);
typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param);
@@ -8494,9 +9233,9 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLen
typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param);
typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint* param);
typedef void (GLAPIENTRY * PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer);
-typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
typedef GLboolean (GLAPIENTRY * PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);
@@ -8506,6 +9245,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint v
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);
@@ -8720,6 +9460,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, G
#define glVertexArrayNormalOffsetEXT GLEW_GET_FUN(__glewVertexArrayNormalOffsetEXT)
#define glVertexArraySecondaryColorOffsetEXT GLEW_GET_FUN(__glewVertexArraySecondaryColorOffsetEXT)
#define glVertexArrayTexCoordOffsetEXT GLEW_GET_FUN(__glewVertexArrayTexCoordOffsetEXT)
+#define glVertexArrayVertexAttribDivisorEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribDivisorEXT)
#define glVertexArrayVertexAttribIOffsetEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribIOffsetEXT)
#define glVertexArrayVertexAttribOffsetEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribOffsetEXT)
#define glVertexArrayVertexOffsetEXT GLEW_GET_FUN(__glewVertexArrayVertexOffsetEXT)
@@ -8757,7 +9498,7 @@ typedef GLboolean (GLAPIENTRY * PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GL
#define GL_EXT_draw_instanced 1
typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
-typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
#define glDrawArraysInstancedEXT GLEW_GET_FUN(__glewDrawArraysInstancedEXT)
#define glDrawElementsInstancedEXT GLEW_GET_FUN(__glewDrawElementsInstancedEXT)
@@ -8774,7 +9515,7 @@ typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsi
#define GL_MAX_ELEMENTS_VERTICES_EXT 0x80E8
#define GL_MAX_ELEMENTS_INDICES_EXT 0x80E9
-typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);
#define glDrawRangeElementsEXT GLEW_GET_FUN(__glewDrawRangeElementsEXT)
@@ -8796,7 +9537,7 @@ typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint s
#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457
-typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLFOGCOORDDEXTPROC) (GLdouble coord);
typedef void (GLAPIENTRY * PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);
typedef void (GLAPIENTRY * PFNGLFOGCOORDFEXTPROC) (GLfloat coord);
@@ -9148,7 +9889,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const G
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
#define glBindFragDataLocationEXT GLEW_GET_FUN(__glewBindFragDataLocationEXT)
#define glGetFragDataLocationEXT GLEW_GET_FUN(__glewGetFragDataLocationEXT)
@@ -9208,10 +9949,10 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLin
#define GL_MINMAX_FORMAT_EXT 0x802F
#define GL_MINMAX_SINK_EXT 0x8030
-typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values);
+typedef void (GLAPIENTRY * PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);
typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);
@@ -9320,7 +10061,7 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mod
#define GL_EXT_multi_draw_arrays 1
typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint* first, const GLsizei *count, GLsizei primcount);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, GLsizei* count, GLenum type, const GLvoid * const *indices, GLsizei primcount);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, GLsizei* count, GLenum type, const void *const *indices, GLsizei primcount);
#define glMultiDrawArraysEXT GLEW_GET_FUN(__glewMultiDrawArraysEXT)
#define glMultiDrawElementsEXT GLEW_GET_FUN(__glewMultiDrawElementsEXT)
@@ -9431,8 +10172,8 @@ typedef void (GLAPIENTRY * PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);
#define GL_TEXTURE_CUBE_MAP_ARB 0x8513
#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B
-typedef void (GLAPIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data);
-typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *data);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data);
typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params);
@@ -9538,6 +10279,30 @@ typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat b
#endif /* GL_EXT_polygon_offset */
+/* ---------------------- GL_EXT_polygon_offset_clamp ---------------------- */
+
+#ifndef GL_EXT_polygon_offset_clamp
+#define GL_EXT_polygon_offset_clamp 1
+
+#define GL_POLYGON_OFFSET_CLAMP_EXT 0x8E1B
+
+typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);
+
+#define glPolygonOffsetClampEXT GLEW_GET_FUN(__glewPolygonOffsetClampEXT)
+
+#define GLEW_EXT_polygon_offset_clamp GLEW_GET_VAR(__GLEW_EXT_polygon_offset_clamp)
+
+#endif /* GL_EXT_polygon_offset_clamp */
+
+/* ----------------------- GL_EXT_post_depth_coverage ---------------------- */
+
+#ifndef GL_EXT_post_depth_coverage
+#define GL_EXT_post_depth_coverage 1
+
+#define GLEW_EXT_post_depth_coverage GLEW_GET_VAR(__GLEW_EXT_post_depth_coverage)
+
+#endif /* GL_EXT_post_depth_coverage */
+
/* ------------------------ GL_EXT_provoking_vertex ------------------------ */
#ifndef GL_EXT_provoking_vertex
@@ -9556,6 +10321,40 @@ typedef void (GLAPIENTRY * PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode);
#endif /* GL_EXT_provoking_vertex */
+/* ----------------------- GL_EXT_raster_multisample ----------------------- */
+
+#ifndef GL_EXT_raster_multisample
+#define GL_EXT_raster_multisample 1
+
+#define GL_COLOR_SAMPLES_NV 0x8E20
+#define GL_RASTER_MULTISAMPLE_EXT 0x9327
+#define GL_RASTER_SAMPLES_EXT 0x9328
+#define GL_MAX_RASTER_SAMPLES_EXT 0x9329
+#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A
+#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B
+#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C
+#define GL_DEPTH_SAMPLES_NV 0x932D
+#define GL_STENCIL_SAMPLES_NV 0x932E
+#define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F
+#define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330
+#define GL_COVERAGE_MODULATION_TABLE_NV 0x9331
+#define GL_COVERAGE_MODULATION_NV 0x9332
+#define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333
+
+typedef void (GLAPIENTRY * PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components);
+typedef void (GLAPIENTRY * PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat* v);
+typedef void (GLAPIENTRY * PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufsize, GLfloat* v);
+typedef void (GLAPIENTRY * PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);
+
+#define glCoverageModulationNV GLEW_GET_FUN(__glewCoverageModulationNV)
+#define glCoverageModulationTableNV GLEW_GET_FUN(__glewCoverageModulationTableNV)
+#define glGetCoverageModulationTableNV GLEW_GET_FUN(__glewGetCoverageModulationTableNV)
+#define glRasterSamplesEXT GLEW_GET_FUN(__glewRasterSamplesEXT)
+
+#define GLEW_EXT_raster_multisample GLEW_GET_VAR(__GLEW_EXT_raster_multisample)
+
+#endif /* GL_EXT_raster_multisample */
+
/* ------------------------- GL_EXT_rescale_normal ------------------------- */
#ifndef GL_EXT_rescale_normal
@@ -9611,7 +10410,7 @@ typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint gr
typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);
typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);
typedef void (GLAPIENTRY * PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);
-typedef void (GLAPIENTRY * PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);
#define glSecondaryColor3bEXT GLEW_GET_FUN(__glewSecondaryColor3bEXT)
#define glSecondaryColor3bvEXT GLEW_GET_FUN(__glewSecondaryColor3bvEXT)
@@ -9667,6 +10466,15 @@ typedef void (GLAPIENTRY * PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint pr
#endif /* GL_EXT_separate_specular_color */
+/* ------------------- GL_EXT_shader_image_load_formatted ------------------ */
+
+#ifndef GL_EXT_shader_image_load_formatted
+#define GL_EXT_shader_image_load_formatted 1
+
+#define GLEW_EXT_shader_image_load_formatted GLEW_GET_VAR(__GLEW_EXT_shader_image_load_formatted)
+
+#endif /* GL_EXT_shader_image_load_formatted */
+
/* --------------------- GL_EXT_shader_image_load_store -------------------- */
#ifndef GL_EXT_shader_image_load_store
@@ -9738,6 +10546,15 @@ typedef void (GLAPIENTRY * PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers);
#endif /* GL_EXT_shader_image_load_store */
+/* ----------------------- GL_EXT_shader_integer_mix ----------------------- */
+
+#ifndef GL_EXT_shader_integer_mix
+#define GL_EXT_shader_integer_mix 1
+
+#define GLEW_EXT_shader_integer_mix GLEW_GET_VAR(__GLEW_EXT_shader_integer_mix)
+
+#endif /* GL_EXT_shader_integer_mix */
+
/* -------------------------- GL_EXT_shadow_funcs -------------------------- */
#ifndef GL_EXT_shadow_funcs
@@ -9758,6 +10575,15 @@ typedef void (GLAPIENTRY * PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers);
#endif /* GL_EXT_shared_texture_palette */
+/* ------------------------- GL_EXT_sparse_texture2 ------------------------ */
+
+#ifndef GL_EXT_sparse_texture2
+#define GL_EXT_sparse_texture2 1
+
+#define GLEW_EXT_sparse_texture2 GLEW_GET_VAR(__GLEW_EXT_sparse_texture2)
+
+#endif /* GL_EXT_sparse_texture2 */
+
/* ------------------------ GL_EXT_stencil_clear_tag ----------------------- */
#ifndef GL_EXT_stencil_clear_tag
@@ -9803,9 +10629,9 @@ typedef void (GLAPIENTRY * PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
#ifndef GL_EXT_subtexture
#define GL_EXT_subtexture 1
-typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);
#define glTexSubImage1DEXT GLEW_GET_FUN(__glewTexSubImage1DEXT)
#define glTexSubImage2DEXT GLEW_GET_FUN(__glewTexSubImage2DEXT)
@@ -9882,7 +10708,7 @@ typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint leve
#define GL_TEXTURE_WRAP_R_EXT 0x8072
#define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073
-typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);
#define glTexImage3DEXT GLEW_GET_FUN(__glewTexImage3DEXT)
@@ -10088,6 +10914,18 @@ typedef void (GLAPIENTRY * PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum interna
#endif /* GL_EXT_texture_filter_anisotropic */
+/* ---------------------- GL_EXT_texture_filter_minmax --------------------- */
+
+#ifndef GL_EXT_texture_filter_minmax
+#define GL_EXT_texture_filter_minmax 1
+
+#define GL_TEXTURE_REDUCTION_MODE_EXT 0x9366
+#define GL_WEIGHTED_AVERAGE_EXT 0x9367
+
+#define GLEW_EXT_texture_filter_minmax GLEW_GET_VAR(__GLEW_EXT_texture_filter_minmax)
+
+#endif /* GL_EXT_texture_filter_minmax */
+
/* ------------------------- GL_EXT_texture_integer ------------------------ */
#ifndef GL_EXT_texture_integer
@@ -10444,13 +11282,13 @@ typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint progra
#define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093
typedef void (GLAPIENTRY * PFNGLARRAYELEMENTEXTPROC) (GLint i);
-typedef void (GLAPIENTRY * PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
typedef void (GLAPIENTRY * PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);
typedef void (GLAPIENTRY * PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean* pointer);
-typedef void (GLAPIENTRY * PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
-typedef void (GLAPIENTRY * PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
-typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
-typedef void (GLAPIENTRY * PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (GLAPIENTRY * PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);
#define glArrayElementEXT GLEW_GET_FUN(__glewArrayElementEXT)
#define glColorPointerEXT GLEW_GET_FUN(__glewColorPointerEXT)
@@ -10504,7 +11342,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble* v);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
#define glGetVertexAttribLdvEXT GLEW_GET_FUN(__glewGetVertexAttribLdvEXT)
#define glVertexArrayVertexAttribLOffsetEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribLOffsetEXT)
@@ -10661,16 +11499,16 @@ typedef void (GLAPIENTRY * PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLe
typedef void (GLAPIENTRY * PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);
typedef void (GLAPIENTRY * PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);
typedef void (GLAPIENTRY * PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);
-typedef void (GLAPIENTRY * PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, GLvoid **data);
+typedef void (GLAPIENTRY * PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data);
typedef void (GLAPIENTRY * PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);
typedef GLboolean (GLAPIENTRY * PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);
-typedef void (GLAPIENTRY * PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, GLvoid *addr);
-typedef void (GLAPIENTRY * PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, GLvoid *addr);
+typedef void (GLAPIENTRY * PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, void *addr);
+typedef void (GLAPIENTRY * PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, void *addr);
typedef void (GLAPIENTRY * PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);
typedef void (GLAPIENTRY * PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);
typedef void (GLAPIENTRY * PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);
typedef void (GLAPIENTRY * PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);
-typedef void (GLAPIENTRY * PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, GLvoid *addr);
+typedef void (GLAPIENTRY * PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, void *addr);
typedef void (GLAPIENTRY * PFNGLVARIANTBVEXTPROC) (GLuint id, GLbyte *addr);
typedef void (GLAPIENTRY * PFNGLVARIANTDVEXTPROC) (GLuint id, GLdouble *addr);
typedef void (GLAPIENTRY * PFNGLVARIANTFVEXTPROC) (GLuint id, GLfloat *addr);
@@ -10747,7 +11585,7 @@ typedef void (GLAPIENTRY * PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum
#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F
#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510
-typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, void *pointer);
typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);
typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTFVEXTPROC) (GLfloat* weight);
@@ -10792,7 +11630,7 @@ typedef void (GLAPIENTRY * PFNGLFRAMETERMINATORGREMEDYPROC) (void);
#ifndef GL_GREMEDY_string_marker
#define GL_GREMEDY_string_marker 1
-typedef void (GLAPIENTRY * PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string);
+typedef void (GLAPIENTRY * PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string);
#define glStringMarkerGREMEDY GLEW_GET_FUN(__glewStringMarkerGREMEDY)
@@ -10867,7 +11705,7 @@ typedef void (GLAPIENTRY * PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target,
#define GL_IBM_multimode_draw_arrays 1
typedef void (GLAPIENTRY * PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum* mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);
-typedef void (GLAPIENTRY * PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum* mode, const GLsizei *count, GLenum type, const GLvoid * const *indices, GLsizei primcount, GLint modestride);
+typedef void (GLAPIENTRY * PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum* mode, const GLsizei *count, GLenum type, const void *const *indices, GLsizei primcount, GLint modestride);
#define glMultiModeDrawArraysIBM GLEW_GET_FUN(__glewMultiModeDrawArraysIBM)
#define glMultiModeDrawElementsIBM GLEW_GET_FUN(__glewMultiModeDrawElementsIBM)
@@ -10932,14 +11770,14 @@ typedef void (GLAPIENTRY * PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum* mod
#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086
#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087
-typedef void (GLAPIENTRY * PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void** pointer, GLint ptrstride);
typedef void (GLAPIENTRY * PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean ** pointer, GLint ptrstride);
-typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
-typedef void (GLAPIENTRY * PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
-typedef void (GLAPIENTRY * PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
-typedef void (GLAPIENTRY * PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
-typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
-typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const GLvoid ** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void** pointer, GLint ptrstride);
+typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void** pointer, GLint ptrstride);
#define glColorPointerListIBM GLEW_GET_FUN(__glewColorPointerListIBM)
#define glEdgeFlagPointerListIBM GLEW_GET_FUN(__glewEdgeFlagPointerListIBM)
@@ -10983,6 +11821,24 @@ typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum ty
#endif /* GL_INGR_interlace_read */
+/* ------------------- GL_INTEL_fragment_shader_ordering ------------------- */
+
+#ifndef GL_INTEL_fragment_shader_ordering
+#define GL_INTEL_fragment_shader_ordering 1
+
+#define GLEW_INTEL_fragment_shader_ordering GLEW_GET_VAR(__GLEW_INTEL_fragment_shader_ordering)
+
+#endif /* GL_INTEL_fragment_shader_ordering */
+
+/* ----------------------- GL_INTEL_framebuffer_CMAA ----------------------- */
+
+#ifndef GL_INTEL_framebuffer_CMAA
+#define GL_INTEL_framebuffer_CMAA 1
+
+#define GLEW_INTEL_framebuffer_CMAA GLEW_GET_VAR(__GLEW_INTEL_framebuffer_CMAA)
+
+#endif /* GL_INTEL_framebuffer_CMAA */
+
/* -------------------------- GL_INTEL_map_texture ------------------------- */
#ifndef GL_INTEL_map_texture
@@ -10993,7 +11849,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum ty
#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2
#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF
-typedef GLvoid * (GLAPIENTRY * PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint* stride, GLenum *layout);
+typedef void * (GLAPIENTRY * PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint* stride, GLenum *layout);
typedef void (GLAPIENTRY * PFNGLSYNCTEXTUREINTELPROC) (GLuint texture);
typedef void (GLAPIENTRY * PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level);
@@ -11030,6 +11886,58 @@ typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum typ
#endif /* GL_INTEL_parallel_arrays */
+/* ----------------------- GL_INTEL_performance_query ---------------------- */
+
+#ifndef GL_INTEL_performance_query
+#define GL_INTEL_performance_query 1
+
+#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x0000
+#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x0001
+#define GL_PERFQUERY_DONOT_FLUSH_INTEL 0x83F9
+#define GL_PERFQUERY_FLUSH_INTEL 0x83FA
+#define GL_PERFQUERY_WAIT_INTEL 0x83FB
+#define GL_PERFQUERY_COUNTER_EVENT_INTEL 0x94F0
+#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1
+#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2
+#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3
+#define GL_PERFQUERY_COUNTER_RAW_INTEL 0x94F4
+#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5
+#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8
+#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9
+#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA
+#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB
+#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC
+#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD
+#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE
+#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF
+#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500
+
+typedef void (GLAPIENTRY * PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (GLAPIENTRY * PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint* queryHandle);
+typedef void (GLAPIENTRY * PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (GLAPIENTRY * PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle);
+typedef void (GLAPIENTRY * PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint* queryId);
+typedef void (GLAPIENTRY * PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint* nextQueryId);
+typedef void (GLAPIENTRY * PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar* counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
+typedef void (GLAPIENTRY * PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);
+typedef void (GLAPIENTRY * PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar* queryName, GLuint *queryId);
+typedef void (GLAPIENTRY * PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar* queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
+
+#define glBeginPerfQueryINTEL GLEW_GET_FUN(__glewBeginPerfQueryINTEL)
+#define glCreatePerfQueryINTEL GLEW_GET_FUN(__glewCreatePerfQueryINTEL)
+#define glDeletePerfQueryINTEL GLEW_GET_FUN(__glewDeletePerfQueryINTEL)
+#define glEndPerfQueryINTEL GLEW_GET_FUN(__glewEndPerfQueryINTEL)
+#define glGetFirstPerfQueryIdINTEL GLEW_GET_FUN(__glewGetFirstPerfQueryIdINTEL)
+#define glGetNextPerfQueryIdINTEL GLEW_GET_FUN(__glewGetNextPerfQueryIdINTEL)
+#define glGetPerfCounterInfoINTEL GLEW_GET_FUN(__glewGetPerfCounterInfoINTEL)
+#define glGetPerfQueryDataINTEL GLEW_GET_FUN(__glewGetPerfQueryDataINTEL)
+#define glGetPerfQueryIdByNameINTEL GLEW_GET_FUN(__glewGetPerfQueryIdByNameINTEL)
+#define glGetPerfQueryInfoINTEL GLEW_GET_FUN(__glewGetPerfQueryInfoINTEL)
+
+#define GLEW_INTEL_performance_query GLEW_GET_VAR(__GLEW_INTEL_performance_query)
+
+#endif /* GL_INTEL_performance_query */
+
/* ------------------------ GL_INTEL_texture_scissor ----------------------- */
#ifndef GL_INTEL_texture_scissor
@@ -11045,6 +11953,57 @@ typedef void (GLAPIENTRY * PFNGLTEXSCISSORINTELPROC) (GLenum target, GLclampf tl
#endif /* GL_INTEL_texture_scissor */
+/* --------------------- GL_KHR_blend_equation_advanced -------------------- */
+
+#ifndef GL_KHR_blend_equation_advanced
+#define GL_KHR_blend_equation_advanced 1
+
+#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285
+#define GL_MULTIPLY_KHR 0x9294
+#define GL_SCREEN_KHR 0x9295
+#define GL_OVERLAY_KHR 0x9296
+#define GL_DARKEN_KHR 0x9297
+#define GL_LIGHTEN_KHR 0x9298
+#define GL_COLORDODGE_KHR 0x9299
+#define GL_COLORBURN_KHR 0x929A
+#define GL_HARDLIGHT_KHR 0x929B
+#define GL_SOFTLIGHT_KHR 0x929C
+#define GL_DIFFERENCE_KHR 0x929E
+#define GL_EXCLUSION_KHR 0x92A0
+#define GL_HSL_HUE_KHR 0x92AD
+#define GL_HSL_SATURATION_KHR 0x92AE
+#define GL_HSL_COLOR_KHR 0x92AF
+#define GL_HSL_LUMINOSITY_KHR 0x92B0
+
+typedef void (GLAPIENTRY * PFNGLBLENDBARRIERKHRPROC) (void);
+
+#define glBlendBarrierKHR GLEW_GET_FUN(__glewBlendBarrierKHR)
+
+#define GLEW_KHR_blend_equation_advanced GLEW_GET_VAR(__GLEW_KHR_blend_equation_advanced)
+
+#endif /* GL_KHR_blend_equation_advanced */
+
+/* ---------------- GL_KHR_blend_equation_advanced_coherent ---------------- */
+
+#ifndef GL_KHR_blend_equation_advanced_coherent
+#define GL_KHR_blend_equation_advanced_coherent 1
+
+#define GLEW_KHR_blend_equation_advanced_coherent GLEW_GET_VAR(__GLEW_KHR_blend_equation_advanced_coherent)
+
+#endif /* GL_KHR_blend_equation_advanced_coherent */
+
+/* ---------------------- GL_KHR_context_flush_control --------------------- */
+
+#ifndef GL_KHR_context_flush_control
+#define GL_KHR_context_flush_control 1
+
+#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB
+#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
+
+#define GLEW_KHR_context_flush_control GLEW_GET_VAR(__GLEW_KHR_context_flush_control)
+
+#endif /* GL_KHR_context_flush_control */
+
/* ------------------------------ GL_KHR_debug ----------------------------- */
#ifndef GL_KHR_debug
@@ -11091,16 +12050,16 @@ typedef void (GLAPIENTRY * PFNGLTEXSCISSORINTELPROC) (GLenum target, GLclampf tl
#define GL_DEBUG_SEVERITY_LOW 0x9148
#define GL_DEBUG_OUTPUT 0x92E0
-typedef void (APIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam);
+typedef void (GLAPIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
-typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const GLvoid *userParam);
+typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
-typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
+typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
typedef void (GLAPIENTRY * PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar *label);
-typedef void (GLAPIENTRY * PFNGLGETOBJECTPTRLABELPROC) (void* ptr, GLsizei bufSize, GLsizei* length, GLchar *label);
+typedef void (GLAPIENTRY * PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei* length, GLchar *label);
typedef void (GLAPIENTRY * PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar* label);
-typedef void (GLAPIENTRY * PFNGLOBJECTPTRLABELPROC) (void* ptr, GLsizei length, const GLchar* label);
+typedef void (GLAPIENTRY * PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar* label);
typedef void (GLAPIENTRY * PFNGLPOPDEBUGGROUPPROC) (void);
typedef void (GLAPIENTRY * PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar * message);
@@ -11119,6 +12078,92 @@ typedef void (GLAPIENTRY * PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, G
#endif /* GL_KHR_debug */
+/* ---------------------------- GL_KHR_no_error ---------------------------- */
+
+#ifndef GL_KHR_no_error
+#define GL_KHR_no_error 1
+
+#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR 0x00000008
+
+#define GLEW_KHR_no_error GLEW_GET_VAR(__GLEW_KHR_no_error)
+
+#endif /* GL_KHR_no_error */
+
+/* ------------------ GL_KHR_robust_buffer_access_behavior ----------------- */
+
+#ifndef GL_KHR_robust_buffer_access_behavior
+#define GL_KHR_robust_buffer_access_behavior 1
+
+#define GLEW_KHR_robust_buffer_access_behavior GLEW_GET_VAR(__GLEW_KHR_robust_buffer_access_behavior)
+
+#endif /* GL_KHR_robust_buffer_access_behavior */
+
+/* --------------------------- GL_KHR_robustness --------------------------- */
+
+#ifndef GL_KHR_robustness
+#define GL_KHR_robustness 1
+
+#define GL_CONTEXT_LOST 0x0507
+#define GL_LOSE_CONTEXT_ON_RESET 0x8252
+#define GL_GUILTY_CONTEXT_RESET 0x8253
+#define GL_INNOCENT_CONTEXT_RESET 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET 0x8255
+#define GL_RESET_NOTIFICATION_STRATEGY 0x8256
+#define GL_NO_RESET_NOTIFICATION 0x8261
+#define GL_CONTEXT_ROBUST_ACCESS 0x90F3
+
+typedef void (GLAPIENTRY * PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat* params);
+typedef void (GLAPIENTRY * PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint* params);
+typedef void (GLAPIENTRY * PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint* params);
+typedef void (GLAPIENTRY * PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+
+#define glGetnUniformfv GLEW_GET_FUN(__glewGetnUniformfv)
+#define glGetnUniformiv GLEW_GET_FUN(__glewGetnUniformiv)
+#define glGetnUniformuiv GLEW_GET_FUN(__glewGetnUniformuiv)
+#define glReadnPixels GLEW_GET_FUN(__glewReadnPixels)
+
+#define GLEW_KHR_robustness GLEW_GET_VAR(__GLEW_KHR_robustness)
+
+#endif /* GL_KHR_robustness */
+
+/* ------------------ GL_KHR_texture_compression_astc_hdr ------------------ */
+
+#ifndef GL_KHR_texture_compression_astc_hdr
+#define GL_KHR_texture_compression_astc_hdr 1
+
+#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
+#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
+#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
+#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
+#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
+#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
+#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
+#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
+#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
+#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
+#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
+#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
+#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
+#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
+
+#define GLEW_KHR_texture_compression_astc_hdr GLEW_GET_VAR(__GLEW_KHR_texture_compression_astc_hdr)
+
+#endif /* GL_KHR_texture_compression_astc_hdr */
+
/* ------------------ GL_KHR_texture_compression_astc_ldr ------------------ */
#ifndef GL_KHR_texture_compression_astc_ldr
@@ -11330,8 +12375,8 @@ typedef void (GLAPIENTRY * PFNGLENDCONDITIONALRENDERNVXPROC) (void);
#ifndef GL_NV_bindless_multi_draw_indirect
#define GL_NV_bindless_multi_draw_indirect 1
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
-typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);
#define glMultiDrawArraysIndirectBindlessNV GLEW_GET_FUN(__glewMultiDrawArraysIndirectBindlessNV)
#define glMultiDrawElementsIndirectBindlessNV GLEW_GET_FUN(__glewMultiDrawElementsIndirectBindlessNV)
@@ -11340,6 +12385,21 @@ typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum
#endif /* GL_NV_bindless_multi_draw_indirect */
+/* ---------------- GL_NV_bindless_multi_draw_indirect_count --------------- */
+
+#ifndef GL_NV_bindless_multi_draw_indirect_count
+#define GL_NV_bindless_multi_draw_indirect_count 1
+
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLintptr drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);
+typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);
+
+#define glMultiDrawArraysIndirectBindlessCountNV GLEW_GET_FUN(__glewMultiDrawArraysIndirectBindlessCountNV)
+#define glMultiDrawElementsIndirectBindlessCountNV GLEW_GET_FUN(__glewMultiDrawElementsIndirectBindlessCountNV)
+
+#define GLEW_NV_bindless_multi_draw_indirect_count GLEW_GET_VAR(__GLEW_NV_bindless_multi_draw_indirect_count)
+
+#endif /* GL_NV_bindless_multi_draw_indirect_count */
+
/* ------------------------- GL_NV_bindless_texture ------------------------ */
#ifndef GL_NV_bindless_texture
@@ -11382,6 +12442,10 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsiz
#ifndef GL_NV_blend_equation_advanced
#define GL_NV_blend_equation_advanced 1
+#define GL_XOR_NV 0x1506
+#define GL_RED_NV 0x1903
+#define GL_GREEN_NV 0x1904
+#define GL_BLUE_NV 0x1905
#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280
#define GL_BLEND_OVERLAP_NV 0x9281
#define GL_UNCORRELATED_NV 0x9282
@@ -11489,6 +12553,41 @@ typedef void (GLAPIENTRY * PFNGLENDCONDITIONALRENDERNVPROC) (void);
#endif /* GL_NV_conditional_render */
+/* ----------------------- GL_NV_conservative_raster ----------------------- */
+
+#ifndef GL_NV_conservative_raster
+#define GL_NV_conservative_raster 1
+
+#define GL_CONSERVATIVE_RASTERIZATION_NV 0x9346
+#define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347
+#define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348
+#define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349
+
+typedef void (GLAPIENTRY * PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits);
+
+#define glSubpixelPrecisionBiasNV GLEW_GET_FUN(__glewSubpixelPrecisionBiasNV)
+
+#define GLEW_NV_conservative_raster GLEW_GET_VAR(__GLEW_NV_conservative_raster)
+
+#endif /* GL_NV_conservative_raster */
+
+/* -------------------- GL_NV_conservative_raster_dilate ------------------- */
+
+#ifndef GL_NV_conservative_raster_dilate
+#define GL_NV_conservative_raster_dilate 1
+
+#define GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379
+#define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A
+#define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B
+
+typedef void (GLAPIENTRY * PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value);
+
+#define glConservativeRasterParameterfNV GLEW_GET_FUN(__glewConservativeRasterParameterfNV)
+
+#define GLEW_NV_conservative_raster_dilate GLEW_GET_VAR(__GLEW_NV_conservative_raster_dilate)
+
+#endif /* GL_NV_conservative_raster_dilate */
+
/* ----------------------- GL_NV_copy_depth_to_color ----------------------- */
#ifndef GL_NV_copy_depth_to_color
@@ -11620,10 +12719,10 @@ typedef void (GLAPIENTRY * PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampl
typedef void (GLAPIENTRY * PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);
typedef void (GLAPIENTRY * PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points);
+typedef void (GLAPIENTRY * PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);
typedef void (GLAPIENTRY * PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points);
+typedef void (GLAPIENTRY * PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);
typedef void (GLAPIENTRY * PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat* params);
typedef void (GLAPIENTRY * PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint* params);
@@ -11698,6 +12797,17 @@ typedef GLboolean (GLAPIENTRY * PFNGLTESTFENCENVPROC) (GLuint fence);
#endif /* GL_NV_fence */
+/* -------------------------- GL_NV_fill_rectangle ------------------------- */
+
+#ifndef GL_NV_fill_rectangle
+#define GL_NV_fill_rectangle 1
+
+#define GL_FILL_RECTANGLE_NV 0x933C
+
+#define GLEW_NV_fill_rectangle GLEW_GET_VAR(__GLEW_NV_fill_rectangle)
+
+#endif /* GL_NV_fill_rectangle */
+
/* --------------------------- GL_NV_float_buffer -------------------------- */
#ifndef GL_NV_float_buffer
@@ -11736,6 +12846,22 @@ typedef GLboolean (GLAPIENTRY * PFNGLTESTFENCENVPROC) (GLuint fence);
#endif /* GL_NV_fog_distance */
+/* -------------------- GL_NV_fragment_coverage_to_color ------------------- */
+
+#ifndef GL_NV_fragment_coverage_to_color
+#define GL_NV_fragment_coverage_to_color 1
+
+#define GL_FRAGMENT_COVERAGE_TO_COLOR_NV 0x92DD
+#define GL_FRAGMENT_COVERAGE_COLOR_NV 0x92DE
+
+typedef void (GLAPIENTRY * PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color);
+
+#define glFragmentCoverageColorNV GLEW_GET_FUN(__glewFragmentCoverageColorNV)
+
+#define GLEW_NV_fragment_coverage_to_color GLEW_GET_VAR(__GLEW_NV_fragment_coverage_to_color)
+
+#endif /* GL_NV_fragment_coverage_to_color */
+
/* ------------------------- GL_NV_fragment_program ------------------------ */
#ifndef GL_NV_fragment_program
@@ -11799,6 +12925,39 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsi
#endif /* GL_NV_fragment_program_option */
+/* -------------------- GL_NV_fragment_shader_interlock -------------------- */
+
+#ifndef GL_NV_fragment_shader_interlock
+#define GL_NV_fragment_shader_interlock 1
+
+#define GLEW_NV_fragment_shader_interlock GLEW_GET_VAR(__GLEW_NV_fragment_shader_interlock)
+
+#endif /* GL_NV_fragment_shader_interlock */
+
+/* -------------------- GL_NV_framebuffer_mixed_samples -------------------- */
+
+#ifndef GL_NV_framebuffer_mixed_samples
+#define GL_NV_framebuffer_mixed_samples 1
+
+#define GL_COLOR_SAMPLES_NV 0x8E20
+#define GL_RASTER_MULTISAMPLE_EXT 0x9327
+#define GL_RASTER_SAMPLES_EXT 0x9328
+#define GL_MAX_RASTER_SAMPLES_EXT 0x9329
+#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A
+#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B
+#define GL_EFFECTIVE_RASTER_SAMPLES_EXT 0x932C
+#define GL_DEPTH_SAMPLES_NV 0x932D
+#define GL_STENCIL_SAMPLES_NV 0x932E
+#define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F
+#define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330
+#define GL_COVERAGE_MODULATION_TABLE_NV 0x9331
+#define GL_COVERAGE_MODULATION_NV 0x9332
+#define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333
+
+#define GLEW_NV_framebuffer_mixed_samples GLEW_GET_VAR(__GLEW_NV_framebuffer_mixed_samples)
+
+#endif /* GL_NV_framebuffer_mixed_samples */
+
/* ----------------- GL_NV_framebuffer_multisample_coverage ---------------- */
#ifndef GL_NV_framebuffer_multisample_coverage
@@ -11843,6 +13002,15 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint
#endif /* GL_NV_geometry_shader4 */
+/* ------------------- GL_NV_geometry_shader_passthrough ------------------- */
+
+#ifndef GL_NV_geometry_shader_passthrough
+#define GL_NV_geometry_shader_passthrough 1
+
+#define GLEW_NV_geometry_shader_passthrough GLEW_GET_VAR(__GLEW_NV_geometry_shader_passthrough)
+
+#endif /* GL_NV_geometry_shader_passthrough */
+
/* --------------------------- GL_NV_gpu_program4 -------------------------- */
#ifndef GL_NV_gpu_program4
@@ -12136,6 +13304,24 @@ typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalf* weight);
#endif /* GL_NV_half_float */
+/* ------------------- GL_NV_internalformat_sample_query ------------------- */
+
+#ifndef GL_NV_internalformat_sample_query
+#define GL_NV_internalformat_sample_query 1
+
+#define GL_MULTISAMPLES_NV 0x9371
+#define GL_SUPERSAMPLE_SCALE_X_NV 0x9372
+#define GL_SUPERSAMPLE_SCALE_Y_NV 0x9373
+#define GL_CONFORMANT_NV 0x9374
+
+typedef void (GLAPIENTRY * PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei bufSize, GLint* params);
+
+#define glGetInternalformatSampleivNV GLEW_GET_FUN(__glewGetInternalformatSampleivNV)
+
+#define GLEW_NV_internalformat_sample_query GLEW_GET_VAR(__GLEW_NV_internalformat_sample_query)
+
+#endif /* GL_NV_internalformat_sample_query */
+
/* ------------------------ GL_NV_light_max_exponent ----------------------- */
#ifndef GL_NV_light_max_exponent
@@ -12256,8 +13442,8 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target,
#define GL_ITALIC_BIT_NV 0x02
#define GL_MOVE_TO_NV 0x02
#define GL_RELATIVE_MOVE_TO_NV 0x03
-#define GL_LINE_TO_NV 0x04
#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04
+#define GL_LINE_TO_NV 0x04
#define GL_RELATIVE_LINE_TO_NV 0x05
#define GL_HORIZONTAL_LINE_TO_NV 0x06
#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07
@@ -12281,19 +13467,32 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target,
#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17
#define GL_LARGE_CW_ARC_TO_NV 0x18
#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19
+#define GL_CONIC_CURVE_TO_NV 0x1A
+#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B
#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20
#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40
#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80
+#define GL_ROUNDED_RECT_NV 0xE8
+#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9
+#define GL_ROUNDED_RECT2_NV 0xEA
+#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB
+#define GL_ROUNDED_RECT4_NV 0xEC
+#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED
+#define GL_ROUNDED_RECT8_NV 0xEE
+#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF
#define GL_RESTART_PATH_NV 0xF0
#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2
#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4
#define GL_RECT_NV 0xF6
+#define GL_RELATIVE_RECT_NV 0xF7
#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8
#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA
#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC
#define GL_ARC_TO_NV 0xFE
#define GL_RELATIVE_ARC_TO_NV 0xFF
#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100
+#define GL_PRIMARY_COLOR_NV 0x852C
+#define GL_SECONDARY_COLOR_NV 0x852D
#define GL_PRIMARY_COLOR 0x8577
#define GL_PATH_FORMAT_SVG_NV 0x9070
#define GL_PATH_FORMAT_PS_NV 0x9071
@@ -12316,6 +13515,7 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target,
#define GL_PATH_FILL_COVER_MODE_NV 0x9082
#define GL_PATH_STROKE_COVER_MODE_NV 0x9083
#define GL_PATH_STROKE_MASK_NV 0x9084
+#define GL_PATH_STROKE_BOUND_NV 0x9086
#define GL_COUNT_UP_NV 0x9088
#define GL_COUNT_DOWN_NV 0x9089
#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A
@@ -12364,6 +13564,12 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target,
#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD
#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE
#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF
+#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368
+#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369
+#define GL_FONT_UNAVAILABLE_NV 0x936A
+#define GL_FONT_UNINTELLIGIBLE_NV 0x936B
+#define GL_STANDARD_FONT_FORMAT_NV 0x936C
+#define GL_FRAGMENT_INPUT_NV 0x936D
#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000
#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000
#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000
@@ -12377,54 +13583,70 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target,
#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000
#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000
#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000
+#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000
typedef void (GLAPIENTRY * PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath);
-typedef void (GLAPIENTRY * PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (GLAPIENTRY * PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
typedef void (GLAPIENTRY * PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode);
-typedef void (GLAPIENTRY * PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
-typedef void (GLAPIENTRY * PFNGLCOVERSTROKEPATHNVPROC) (GLuint name, GLenum coverMode);
+typedef void (GLAPIENTRY * PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (GLAPIENTRY * PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode);
typedef void (GLAPIENTRY * PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range);
typedef GLuint (GLAPIENTRY * PFNGLGENPATHSNVPROC) (GLsizei range);
typedef void (GLAPIENTRY * PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat* value);
typedef void (GLAPIENTRY * PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint* value);
-typedef void (GLAPIENTRY * PFNGLGETPATHCOMMANDSNVPROC) (GLuint name, GLubyte* commands);
-typedef void (GLAPIENTRY * PFNGLGETPATHCOORDSNVPROC) (GLuint name, GLfloat* coords);
-typedef void (GLAPIENTRY * PFNGLGETPATHDASHARRAYNVPROC) (GLuint name, GLfloat* dashArray);
+typedef void (GLAPIENTRY * PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte* commands);
+typedef void (GLAPIENTRY * PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat* coords);
+typedef void (GLAPIENTRY * PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat* dashArray);
typedef GLfloat (GLAPIENTRY * PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments);
-typedef void (GLAPIENTRY * PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint fistPathName, GLsizei numPaths, GLsizei stride, GLfloat* metrics);
-typedef void (GLAPIENTRY * PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
-typedef void (GLAPIENTRY * PFNGLGETPATHPARAMETERFVNVPROC) (GLuint name, GLenum param, GLfloat* value);
-typedef void (GLAPIENTRY * PFNGLGETPATHPARAMETERIVNVPROC) (GLuint name, GLenum param, GLint* value);
-typedef void (GLAPIENTRY * PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
+typedef void (GLAPIENTRY * PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat* metrics);
+typedef void (GLAPIENTRY * PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
+typedef void (GLAPIENTRY * PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat* value);
+typedef void (GLAPIENTRY * PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint* value);
+typedef void (GLAPIENTRY * PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
typedef void (GLAPIENTRY * PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat* value);
typedef void (GLAPIENTRY * PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint* value);
+typedef void (GLAPIENTRY * PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum* props, GLsizei bufSize, GLsizei *length, GLfloat *params);
typedef void (GLAPIENTRY * PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);
typedef GLboolean (GLAPIENTRY * PFNGLISPATHNVPROC) (GLuint path);
typedef GLboolean (GLAPIENTRY * PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y);
typedef GLboolean (GLAPIENTRY * PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y);
+typedef void (GLAPIENTRY * PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat* m);
+typedef void (GLAPIENTRY * PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat* m);
+typedef void (GLAPIENTRY * PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat* m);
+typedef void (GLAPIENTRY * PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat* m);
+typedef void (GLAPIENTRY * PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat* m);
+typedef void (GLAPIENTRY * PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat* m);
typedef void (GLAPIENTRY * PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat* coeffs);
-typedef void (GLAPIENTRY * PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, GLenum coordType, const GLvoid*coords);
-typedef void (GLAPIENTRY * PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void* coords);
+typedef void (GLAPIENTRY * PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, GLenum coordType, const void*coords);
+typedef void (GLAPIENTRY * PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);
typedef void (GLAPIENTRY * PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum zfunc);
typedef void (GLAPIENTRY * PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat* dashArray);
typedef void (GLAPIENTRY * PFNGLPATHFOGGENNVPROC) (GLenum genMode);
-typedef void (GLAPIENTRY * PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
-typedef void (GLAPIENTRY * PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void* fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const GLvoid*charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef GLenum (GLAPIENTRY * PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef GLenum (GLAPIENTRY * PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]);
+typedef void (GLAPIENTRY * PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (GLAPIENTRY * PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void*charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef GLenum (GLAPIENTRY * PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
typedef void (GLAPIENTRY * PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value);
typedef void (GLAPIENTRY * PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat* value);
typedef void (GLAPIENTRY * PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value);
typedef void (GLAPIENTRY * PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint* value);
typedef void (GLAPIENTRY * PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units);
typedef void (GLAPIENTRY * PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask);
-typedef void (GLAPIENTRY * PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void* pathString);
-typedef void (GLAPIENTRY * PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, GLenum coordType, const GLvoid*coords);
-typedef void (GLAPIENTRY * PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void* coords);
+typedef void (GLAPIENTRY * PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString);
+typedef void (GLAPIENTRY * PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte* commands, GLsizei numCoords, GLenum coordType, const void*coords);
+typedef void (GLAPIENTRY * PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);
typedef void (GLAPIENTRY * PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat* coeffs);
typedef GLboolean (GLAPIENTRY * PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat* x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);
-typedef void (GLAPIENTRY * PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (GLAPIENTRY * PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat* coeffs);
+typedef void (GLAPIENTRY * PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
typedef void (GLAPIENTRY * PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask);
-typedef void (GLAPIENTRY * PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void* paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (GLAPIENTRY * PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
typedef void (GLAPIENTRY * PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask);
+typedef void (GLAPIENTRY * PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (GLAPIENTRY * PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode);
+typedef void (GLAPIENTRY * PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (GLAPIENTRY * PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode);
typedef void (GLAPIENTRY * PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat* transformValues);
typedef void (GLAPIENTRY * PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint paths[], const GLfloat weights[]);
@@ -12448,18 +13670,28 @@ typedef void (GLAPIENTRY * PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei n
#define glGetPathSpacingNV GLEW_GET_FUN(__glewGetPathSpacingNV)
#define glGetPathTexGenfvNV GLEW_GET_FUN(__glewGetPathTexGenfvNV)
#define glGetPathTexGenivNV GLEW_GET_FUN(__glewGetPathTexGenivNV)
+#define glGetProgramResourcefvNV GLEW_GET_FUN(__glewGetProgramResourcefvNV)
#define glInterpolatePathsNV GLEW_GET_FUN(__glewInterpolatePathsNV)
#define glIsPathNV GLEW_GET_FUN(__glewIsPathNV)
#define glIsPointInFillPathNV GLEW_GET_FUN(__glewIsPointInFillPathNV)
#define glIsPointInStrokePathNV GLEW_GET_FUN(__glewIsPointInStrokePathNV)
+#define glMatrixLoad3x2fNV GLEW_GET_FUN(__glewMatrixLoad3x2fNV)
+#define glMatrixLoad3x3fNV GLEW_GET_FUN(__glewMatrixLoad3x3fNV)
+#define glMatrixLoadTranspose3x3fNV GLEW_GET_FUN(__glewMatrixLoadTranspose3x3fNV)
+#define glMatrixMult3x2fNV GLEW_GET_FUN(__glewMatrixMult3x2fNV)
+#define glMatrixMult3x3fNV GLEW_GET_FUN(__glewMatrixMult3x3fNV)
+#define glMatrixMultTranspose3x3fNV GLEW_GET_FUN(__glewMatrixMultTranspose3x3fNV)
#define glPathColorGenNV GLEW_GET_FUN(__glewPathColorGenNV)
#define glPathCommandsNV GLEW_GET_FUN(__glewPathCommandsNV)
#define glPathCoordsNV GLEW_GET_FUN(__glewPathCoordsNV)
#define glPathCoverDepthFuncNV GLEW_GET_FUN(__glewPathCoverDepthFuncNV)
#define glPathDashArrayNV GLEW_GET_FUN(__glewPathDashArrayNV)
#define glPathFogGenNV GLEW_GET_FUN(__glewPathFogGenNV)
+#define glPathGlyphIndexArrayNV GLEW_GET_FUN(__glewPathGlyphIndexArrayNV)
+#define glPathGlyphIndexRangeNV GLEW_GET_FUN(__glewPathGlyphIndexRangeNV)
#define glPathGlyphRangeNV GLEW_GET_FUN(__glewPathGlyphRangeNV)
#define glPathGlyphsNV GLEW_GET_FUN(__glewPathGlyphsNV)
+#define glPathMemoryGlyphIndexArrayNV GLEW_GET_FUN(__glewPathMemoryGlyphIndexArrayNV)
#define glPathParameterfNV GLEW_GET_FUN(__glewPathParameterfNV)
#define glPathParameterfvNV GLEW_GET_FUN(__glewPathParameterfvNV)
#define glPathParameteriNV GLEW_GET_FUN(__glewPathParameteriNV)
@@ -12471,10 +13703,15 @@ typedef void (GLAPIENTRY * PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei n
#define glPathSubCoordsNV GLEW_GET_FUN(__glewPathSubCoordsNV)
#define glPathTexGenNV GLEW_GET_FUN(__glewPathTexGenNV)
#define glPointAlongPathNV GLEW_GET_FUN(__glewPointAlongPathNV)
+#define glProgramPathFragmentInputGenNV GLEW_GET_FUN(__glewProgramPathFragmentInputGenNV)
#define glStencilFillPathInstancedNV GLEW_GET_FUN(__glewStencilFillPathInstancedNV)
#define glStencilFillPathNV GLEW_GET_FUN(__glewStencilFillPathNV)
#define glStencilStrokePathInstancedNV GLEW_GET_FUN(__glewStencilStrokePathInstancedNV)
#define glStencilStrokePathNV GLEW_GET_FUN(__glewStencilStrokePathNV)
+#define glStencilThenCoverFillPathInstancedNV GLEW_GET_FUN(__glewStencilThenCoverFillPathInstancedNV)
+#define glStencilThenCoverFillPathNV GLEW_GET_FUN(__glewStencilThenCoverFillPathNV)
+#define glStencilThenCoverStrokePathInstancedNV GLEW_GET_FUN(__glewStencilThenCoverStrokePathInstancedNV)
+#define glStencilThenCoverStrokePathNV GLEW_GET_FUN(__glewStencilThenCoverStrokePathNV)
#define glTransformPathNV GLEW_GET_FUN(__glewTransformPathNV)
#define glWeightPathsNV GLEW_GET_FUN(__glewWeightPathsNV)
@@ -12482,6 +13719,17 @@ typedef void (GLAPIENTRY * PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei n
#endif /* GL_NV_path_rendering */
+/* -------------------- GL_NV_path_rendering_shared_edge ------------------- */
+
+#ifndef GL_NV_path_rendering_shared_edge
+#define GL_NV_path_rendering_shared_edge 1
+
+#define GL_SHARED_EDGE_NV 0xC0
+
+#define GLEW_NV_path_rendering_shared_edge GLEW_GET_VAR(__GLEW_NV_path_rendering_shared_edge)
+
+#endif /* GL_NV_path_rendering_shared_edge */
+
/* ------------------------- GL_NV_pixel_data_range ------------------------ */
#ifndef GL_NV_pixel_data_range
@@ -12495,7 +13743,7 @@ typedef void (GLAPIENTRY * PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei n
#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D
typedef void (GLAPIENTRY * PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);
-typedef void (GLAPIENTRY * PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, void *pointer);
#define glFlushPixelDataRangeNV GLEW_GET_FUN(__glewFlushPixelDataRangeNV)
#define glPixelDataRangeNV GLEW_GET_FUN(__glewPixelDataRangeNV)
@@ -12677,6 +13925,39 @@ typedef void (GLAPIENTRY * PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage
#endif /* GL_NV_register_combiners2 */
+/* ------------------------- GL_NV_sample_locations ------------------------ */
+
+#ifndef GL_NV_sample_locations
+#define GL_NV_sample_locations 1
+
+#define GL_SAMPLE_LOCATION_NV 0x8E50
+#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E
+#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340
+#define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341
+#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342
+#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343
+
+typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat* v);
+typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat* v);
+
+#define glFramebufferSampleLocationsfvNV GLEW_GET_FUN(__glewFramebufferSampleLocationsfvNV)
+#define glNamedFramebufferSampleLocationsfvNV GLEW_GET_FUN(__glewNamedFramebufferSampleLocationsfvNV)
+
+#define GLEW_NV_sample_locations GLEW_GET_VAR(__GLEW_NV_sample_locations)
+
+#endif /* GL_NV_sample_locations */
+
+/* ------------------ GL_NV_sample_mask_override_coverage ------------------ */
+
+#ifndef GL_NV_sample_mask_override_coverage
+#define GL_NV_sample_mask_override_coverage 1
+
+#define GLEW_NV_sample_mask_override_coverage GLEW_GET_VAR(__GLEW_NV_sample_mask_override_coverage)
+
+#endif /* GL_NV_sample_mask_override_coverage */
+
/* ---------------------- GL_NV_shader_atomic_counters --------------------- */
#ifndef GL_NV_shader_atomic_counters
@@ -12695,6 +13976,24 @@ typedef void (GLAPIENTRY * PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage
#endif /* GL_NV_shader_atomic_float */
+/* -------------------- GL_NV_shader_atomic_fp16_vector -------------------- */
+
+#ifndef GL_NV_shader_atomic_fp16_vector
+#define GL_NV_shader_atomic_fp16_vector 1
+
+#define GLEW_NV_shader_atomic_fp16_vector GLEW_GET_VAR(__GLEW_NV_shader_atomic_fp16_vector)
+
+#endif /* GL_NV_shader_atomic_fp16_vector */
+
+/* ----------------------- GL_NV_shader_atomic_int64 ----------------------- */
+
+#ifndef GL_NV_shader_atomic_int64
+#define GL_NV_shader_atomic_int64 1
+
+#define GLEW_NV_shader_atomic_int64 GLEW_GET_VAR(__GLEW_NV_shader_atomic_int64)
+
+#endif /* GL_NV_shader_atomic_int64 */
+
/* ------------------------ GL_NV_shader_buffer_load ----------------------- */
#ifndef GL_NV_shader_buffer_load
@@ -12745,6 +14044,28 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei cou
#endif /* GL_NV_shader_storage_buffer_object */
+/* ----------------------- GL_NV_shader_thread_group ----------------------- */
+
+#ifndef GL_NV_shader_thread_group
+#define GL_NV_shader_thread_group 1
+
+#define GL_WARP_SIZE_NV 0x9339
+#define GL_WARPS_PER_SM_NV 0x933A
+#define GL_SM_COUNT_NV 0x933B
+
+#define GLEW_NV_shader_thread_group GLEW_GET_VAR(__GLEW_NV_shader_thread_group)
+
+#endif /* GL_NV_shader_thread_group */
+
+/* ---------------------- GL_NV_shader_thread_shuffle ---------------------- */
+
+#ifndef GL_NV_shader_thread_shuffle
+#define GL_NV_shader_thread_shuffle 1
+
+#define GLEW_NV_shader_thread_shuffle GLEW_GET_VAR(__GLEW_NV_shader_thread_shuffle)
+
+#endif /* GL_NV_shader_thread_shuffle */
+
/* ---------------------- GL_NV_tessellation_program5 ---------------------- */
#ifndef GL_NV_tessellation_program5
@@ -12893,8 +14214,8 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture
#define GL_OFFSET_TEXTURE_MATRIX_NV 0x86E1
#define GL_OFFSET_TEXTURE_2D_SCALE_NV 0x86E2
#define GL_OFFSET_TEXTURE_SCALE_NV 0x86E2
-#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3
#define GL_OFFSET_TEXTURE_2D_BIAS_NV 0x86E3
+#define GL_OFFSET_TEXTURE_BIAS_NV 0x86E3
#define GL_PREVIOUS_TEXTURE_INPUT_NV 0x86E4
#define GL_CONST_EYE_NV 0x86E5
#define GL_PASS_THROUGH_NV 0x86E6
@@ -13110,6 +14431,19 @@ typedef void (GLAPIENTRY * PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void);
#endif /* GL_NV_transform_feedback2 */
+/* ------------------ GL_NV_uniform_buffer_unified_memory ------------------ */
+
+#ifndef GL_NV_uniform_buffer_unified_memory
+#define GL_NV_uniform_buffer_unified_memory 1
+
+#define GL_UNIFORM_BUFFER_UNIFIED_NV 0x936E
+#define GL_UNIFORM_BUFFER_ADDRESS_NV 0x936F
+#define GL_UNIFORM_BUFFER_LENGTH_NV 0x9370
+
+#define GLEW_NV_uniform_buffer_unified_memory GLEW_GET_VAR(__GLEW_NV_uniform_buffer_unified_memory)
+
+#endif /* GL_NV_uniform_buffer_unified_memory */
+
/* -------------------------- GL_NV_vdpau_interop -------------------------- */
#ifndef GL_NV_vdpau_interop
@@ -13124,7 +14458,7 @@ typedef GLintptr GLvdpauSurfaceNV;
typedef void (GLAPIENTRY * PFNGLVDPAUFININVPROC) (void);
typedef void (GLAPIENTRY * PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei bufSize, GLsizei* length, GLint *values);
-typedef void (GLAPIENTRY * PFNGLVDPAUINITNVPROC) (const void* vdpDevice, const GLvoid*getProcAddress);
+typedef void (GLAPIENTRY * PFNGLVDPAUINITNVPROC) (const void* vdpDevice, const void*getProcAddress);
typedef void (GLAPIENTRY * PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface);
typedef void (GLAPIENTRY * PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV* surfaces);
typedef GLvdpauSurfaceNV (GLAPIENTRY * PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void* vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);
@@ -13160,7 +14494,7 @@ typedef void (GLAPIENTRY * PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV
#define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521
typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);
-typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, void *pointer);
#define glFlushVertexArrayRangeNV GLEW_GET_FUN(__glewFlushVertexArrayRangeNV)
#define glVertexArrayRangeNV GLEW_GET_FUN(__glewVertexArrayRangeNV)
@@ -13392,7 +14726,7 @@ typedef void (GLAPIENTRY * PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLu
typedef void (GLAPIENTRY * PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte* program);
typedef void (GLAPIENTRY * PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint* params);
typedef void (GLAPIENTRY * PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, GLvoid** pointer);
+typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void** pointer);
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble* params);
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint* params);
@@ -13432,7 +14766,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x,
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte* v);
-typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei n, const GLdouble* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei n, const GLfloat* v);
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei n, const GLshort* v);
@@ -13633,6 +14967,15 @@ typedef void (GLAPIENTRY * PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint vid
#endif /* GL_NV_video_capture */
+/* ------------------------- GL_NV_viewport_array2 ------------------------- */
+
+#ifndef GL_NV_viewport_array2
+#define GL_NV_viewport_array2 1
+
+#define GLEW_NV_viewport_array2 GLEW_GET_VAR(__GLEW_NV_viewport_array2)
+
+#endif /* GL_NV_viewport_array2 */
+
/* ------------------------ GL_OES_byte_coordinates ------------------------ */
#ifndef GL_OES_byte_coordinates
@@ -13679,7 +15022,7 @@ typedef void (GLAPIENTRY * PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint vid
#ifndef GL_OES_single_precision
#define GL_OES_single_precision 1
-typedef void (GLAPIENTRY * PFNGLCLEARDEPTHFOESPROC) (GLclampd depth);
+typedef void (GLAPIENTRY * PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
typedef void (GLAPIENTRY * PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat* equation);
typedef void (GLAPIENTRY * PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);
typedef void (GLAPIENTRY * PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);
@@ -13737,6 +15080,33 @@ typedef void (GLAPIENTRY * PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b,
#endif /* GL_OML_subsample */
+/* ---------------------------- GL_OVR_multiview --------------------------- */
+
+#ifndef GL_OVR_multiview
+#define GL_OVR_multiview 1
+
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
+
+typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+
+#define glFramebufferTextureMultiviewOVR GLEW_GET_FUN(__glewFramebufferTextureMultiviewOVR)
+
+#define GLEW_OVR_multiview GLEW_GET_VAR(__GLEW_OVR_multiview)
+
+#endif /* GL_OVR_multiview */
+
+/* --------------------------- GL_OVR_multiview2 --------------------------- */
+
+#ifndef GL_OVR_multiview2
+#define GL_OVR_multiview2 1
+
+#define GLEW_OVR_multiview2 GLEW_GET_VAR(__GLEW_OVR_multiview2)
+
+#endif /* GL_OVR_multiview2 */
+
/* --------------------------- GL_PGI_misc_hints --------------------------- */
#ifndef GL_PGI_misc_hints
@@ -13890,7 +15260,7 @@ typedef void (GLAPIENTRY * PFNGLGETTEXENVXVPROC) (GLenum env, GLenum pname, GLfi
typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERXVPROC) (GLenum target, GLenum pname, GLfixed* params);
typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERXPROC) (GLenum pname, GLfixed param);
typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERXVPROC) (GLenum pname, const GLfixed* params);
-typedef void (GLAPIENTRY * PFNGLPOINTSIZEPOINTEROESPROC) (GLenum type, GLsizei stride, const GLvoid* pointer);
+typedef void (GLAPIENTRY * PFNGLPOINTSIZEPOINTEROESPROC) (GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLTEXPARAMETERXVPROC) (GLenum target, GLenum pname, const GLfixed* params);
#define glClipPlanef GLEW_GET_FUN(__glewClipPlanef)
@@ -13974,7 +15344,7 @@ typedef GLboolean (GLAPIENTRY * PFNGLISSUPPORTEDREGALPROC) (const GLchar* ext);
#define GL_LOG_STATUS_REGAL 0x9320
#define GL_LOG_HTTP_REGAL 0x9321
-typedef void (APIENTRY *GLLOGPROCREGAL)(GLenum stream, GLsizei length, const GLchar *message, GLvoid *context);
+typedef void (APIENTRY *GLLOGPROCREGAL)(GLenum stream, GLsizei length, const GLchar *message, void *context);
typedef void (GLAPIENTRY * PFNGLLOGMESSAGECALLBACKREGALPROC) (GLLOGPROCREGAL callback);
@@ -13984,6 +15354,19 @@ typedef void (GLAPIENTRY * PFNGLLOGMESSAGECALLBACKREGALPROC) (GLLOGPROCREGAL cal
#endif /* GL_REGAL_log */
+/* ------------------------- GL_REGAL_proc_address ------------------------- */
+
+#ifndef GL_REGAL_proc_address
+#define GL_REGAL_proc_address 1
+
+typedef void * (GLAPIENTRY * PFNGLGETPROCADDRESSREGALPROC) (const GLchar *name);
+
+#define glGetProcAddressREGAL GLEW_GET_FUN(__glewGetProcAddressREGAL)
+
+#define GLEW_REGAL_proc_address GLEW_GET_VAR(__GLEW_REGAL_proc_address)
+
+#endif /* GL_REGAL_proc_address */
+
/* ----------------------- GL_REND_screen_coordinates ---------------------- */
#ifndef GL_REND_screen_coordinates
@@ -14152,8 +15535,8 @@ typedef void (GLAPIENTRY * PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei
#ifndef GL_SGIS_texture4D
#define GL_SGIS_texture4D 1
-typedef void (GLAPIENTRY * PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
-typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLenum format, GLenum type, const GLvoid *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLint border, GLenum format, GLenum type, const void *pixels);
+typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLenum format, GLenum type, const void *pixels);
#define glTexImage4DSGIS GLEW_GET_FUN(__glewTexImage4DSGIS)
#define glTexSubImage4DSGIS GLEW_GET_FUN(__glewTexSubImage4DSGIS)
@@ -14350,9 +15733,9 @@ typedef void (GLAPIENTRY * PFNGLFLUSHRASTERSGIXPROC) (void);
#ifndef GL_SGIX_fog_texture
#define GL_SGIX_fog_texture 1
-#define GL_TEXTURE_FOG_SGIX 0
#define GL_FOG_PATCHY_FACTOR_SGIX 0
#define GL_FRAGMENT_FOG_SGIX 0
+#define GL_TEXTURE_FOG_SGIX 0
typedef void (GLAPIENTRY * PFNGLTEXTUREFOGSGIXPROC) (GLenum pname);
@@ -14728,11 +16111,11 @@ typedef void (GLAPIENTRY * PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);
typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat* params);
typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint* params);
-typedef void (GLAPIENTRY * PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);
typedef void (GLAPIENTRY * PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);
typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat* params);
typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint* params);
-typedef void (GLAPIENTRY * PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table);
+typedef void (GLAPIENTRY * PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table);
#define glColorTableParameterfvSGI GLEW_GET_FUN(__glewColorTableParameterfvSGI)
#define glColorTableParameterivSGI GLEW_GET_FUN(__glewColorTableParameterivSGI)
@@ -14832,7 +16215,7 @@ typedef void (GLAPIENTRY * PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);
#ifndef GL_SUN_read_video_pixels
#define GL_SUN_read_video_pixels 1
-typedef void (GLAPIENTRY * PFNGLREADVIDEOPIXELSSUNPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+typedef void (GLAPIENTRY * PFNGLREADVIDEOPIXELSSUNPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
#define glReadVideoPixelsSUN GLEW_GET_FUN(__glewReadVideoPixelsSUN)
@@ -14874,7 +16257,7 @@ typedef void (GLAPIENTRY * PFNGLREADVIDEOPIXELSSUNPROC) (GLint x, GLint y, GLsiz
#define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA
#define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB
-typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void *pointer);
typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);
typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte* code);
typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);
@@ -15334,6 +16717,11 @@ GLEW_FUN_EXPORT PFNGLBLENDFUNCSEPARATEIPROC __glewBlendFuncSeparatei;
GLEW_FUN_EXPORT PFNGLBLENDFUNCIPROC __glewBlendFunci;
GLEW_FUN_EXPORT PFNGLMINSAMPLESHADINGPROC __glewMinSampleShading;
+GLEW_FUN_EXPORT PFNGLGETGRAPHICSRESETSTATUSPROC __glewGetGraphicsResetStatus;
+GLEW_FUN_EXPORT PFNGLGETNCOMPRESSEDTEXIMAGEPROC __glewGetnCompressedTexImage;
+GLEW_FUN_EXPORT PFNGLGETNTEXIMAGEPROC __glewGetnTexImage;
+GLEW_FUN_EXPORT PFNGLGETNUNIFORMDVPROC __glewGetnUniformdv;
+
GLEW_FUN_EXPORT PFNGLTBUFFERMASK3DFXPROC __glewTbufferMask3DFX;
GLEW_FUN_EXPORT PFNGLDEBUGMESSAGECALLBACKAMDPROC __glewDebugMessageCallbackAMD;
@@ -15355,6 +16743,8 @@ GLEW_FUN_EXPORT PFNGLDELETENAMESAMDPROC __glewDeleteNamesAMD;
GLEW_FUN_EXPORT PFNGLGENNAMESAMDPROC __glewGenNamesAMD;
GLEW_FUN_EXPORT PFNGLISNAMEAMDPROC __glewIsNameAMD;
+GLEW_FUN_EXPORT PFNGLQUERYOBJECTPARAMETERUIAMDPROC __glewQueryObjectParameteruiAMD;
+
GLEW_FUN_EXPORT PFNGLBEGINPERFMONITORAMDPROC __glewBeginPerfMonitorAMD;
GLEW_FUN_EXPORT PFNGLDELETEPERFMONITORSAMDPROC __glewDeletePerfMonitorsAMD;
GLEW_FUN_EXPORT PFNGLENDPERFMONITORAMDPROC __glewEndPerfMonitorAMD;
@@ -15447,6 +16837,10 @@ GLEW_FUN_EXPORT PFNGLGETSHADERPRECISIONFORMATPROC __glewGetShaderPrecisionFormat
GLEW_FUN_EXPORT PFNGLRELEASESHADERCOMPILERPROC __glewReleaseShaderCompiler;
GLEW_FUN_EXPORT PFNGLSHADERBINARYPROC __glewShaderBinary;
+GLEW_FUN_EXPORT PFNGLMEMORYBARRIERBYREGIONPROC __glewMemoryBarrierByRegion;
+
+GLEW_FUN_EXPORT PFNGLPRIMITIVEBOUNDINGBOXARBPROC __glewPrimitiveBoundingBoxARB;
+
GLEW_FUN_EXPORT PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __glewDrawArraysInstancedBaseInstance;
GLEW_FUN_EXPORT PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __glewDrawElementsInstancedBaseInstance;
GLEW_FUN_EXPORT PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __glewDrawElementsInstancedBaseVertexBaseInstance;
@@ -15484,6 +16878,8 @@ GLEW_FUN_EXPORT PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC __glewClearNamedBufferSubDat
GLEW_FUN_EXPORT PFNGLCLEARTEXIMAGEPROC __glewClearTexImage;
GLEW_FUN_EXPORT PFNGLCLEARTEXSUBIMAGEPROC __glewClearTexSubImage;
+GLEW_FUN_EXPORT PFNGLCLIPCONTROLPROC __glewClipControl;
+
GLEW_FUN_EXPORT PFNGLCLAMPCOLORARBPROC __glewClampColorARB;
GLEW_FUN_EXPORT PFNGLDISPATCHCOMPUTEPROC __glewDispatchCompute;
@@ -15500,6 +16896,104 @@ GLEW_FUN_EXPORT PFNGLDEBUGMESSAGECONTROLARBPROC __glewDebugMessageControlARB;
GLEW_FUN_EXPORT PFNGLDEBUGMESSAGEINSERTARBPROC __glewDebugMessageInsertARB;
GLEW_FUN_EXPORT PFNGLGETDEBUGMESSAGELOGARBPROC __glewGetDebugMessageLogARB;
+GLEW_FUN_EXPORT PFNGLBINDTEXTUREUNITPROC __glewBindTextureUnit;
+GLEW_FUN_EXPORT PFNGLBLITNAMEDFRAMEBUFFERPROC __glewBlitNamedFramebuffer;
+GLEW_FUN_EXPORT PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC __glewCheckNamedFramebufferStatus;
+GLEW_FUN_EXPORT PFNGLCLEARNAMEDBUFFERDATAPROC __glewClearNamedBufferData;
+GLEW_FUN_EXPORT PFNGLCLEARNAMEDBUFFERSUBDATAPROC __glewClearNamedBufferSubData;
+GLEW_FUN_EXPORT PFNGLCLEARNAMEDFRAMEBUFFERFIPROC __glewClearNamedFramebufferfi;
+GLEW_FUN_EXPORT PFNGLCLEARNAMEDFRAMEBUFFERFVPROC __glewClearNamedFramebufferfv;
+GLEW_FUN_EXPORT PFNGLCLEARNAMEDFRAMEBUFFERIVPROC __glewClearNamedFramebufferiv;
+GLEW_FUN_EXPORT PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC __glewClearNamedFramebufferuiv;
+GLEW_FUN_EXPORT PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC __glewCompressedTextureSubImage1D;
+GLEW_FUN_EXPORT PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC __glewCompressedTextureSubImage2D;
+GLEW_FUN_EXPORT PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC __glewCompressedTextureSubImage3D;
+GLEW_FUN_EXPORT PFNGLCOPYNAMEDBUFFERSUBDATAPROC __glewCopyNamedBufferSubData;
+GLEW_FUN_EXPORT PFNGLCOPYTEXTURESUBIMAGE1DPROC __glewCopyTextureSubImage1D;
+GLEW_FUN_EXPORT PFNGLCOPYTEXTURESUBIMAGE2DPROC __glewCopyTextureSubImage2D;
+GLEW_FUN_EXPORT PFNGLCOPYTEXTURESUBIMAGE3DPROC __glewCopyTextureSubImage3D;
+GLEW_FUN_EXPORT PFNGLCREATEBUFFERSPROC __glewCreateBuffers;
+GLEW_FUN_EXPORT PFNGLCREATEFRAMEBUFFERSPROC __glewCreateFramebuffers;
+GLEW_FUN_EXPORT PFNGLCREATEPROGRAMPIPELINESPROC __glewCreateProgramPipelines;
+GLEW_FUN_EXPORT PFNGLCREATEQUERIESPROC __glewCreateQueries;
+GLEW_FUN_EXPORT PFNGLCREATERENDERBUFFERSPROC __glewCreateRenderbuffers;
+GLEW_FUN_EXPORT PFNGLCREATESAMPLERSPROC __glewCreateSamplers;
+GLEW_FUN_EXPORT PFNGLCREATETEXTURESPROC __glewCreateTextures;
+GLEW_FUN_EXPORT PFNGLCREATETRANSFORMFEEDBACKSPROC __glewCreateTransformFeedbacks;
+GLEW_FUN_EXPORT PFNGLCREATEVERTEXARRAYSPROC __glewCreateVertexArrays;
+GLEW_FUN_EXPORT PFNGLDISABLEVERTEXARRAYATTRIBPROC __glewDisableVertexArrayAttrib;
+GLEW_FUN_EXPORT PFNGLENABLEVERTEXARRAYATTRIBPROC __glewEnableVertexArrayAttrib;
+GLEW_FUN_EXPORT PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC __glewFlushMappedNamedBufferRange;
+GLEW_FUN_EXPORT PFNGLGENERATETEXTUREMIPMAPPROC __glewGenerateTextureMipmap;
+GLEW_FUN_EXPORT PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC __glewGetCompressedTextureImage;
+GLEW_FUN_EXPORT PFNGLGETNAMEDBUFFERPARAMETERI64VPROC __glewGetNamedBufferParameteri64v;
+GLEW_FUN_EXPORT PFNGLGETNAMEDBUFFERPARAMETERIVPROC __glewGetNamedBufferParameteriv;
+GLEW_FUN_EXPORT PFNGLGETNAMEDBUFFERPOINTERVPROC __glewGetNamedBufferPointerv;
+GLEW_FUN_EXPORT PFNGLGETNAMEDBUFFERSUBDATAPROC __glewGetNamedBufferSubData;
+GLEW_FUN_EXPORT PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC __glewGetNamedFramebufferAttachmentParameteriv;
+GLEW_FUN_EXPORT PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC __glewGetNamedFramebufferParameteriv;
+GLEW_FUN_EXPORT PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC __glewGetNamedRenderbufferParameteriv;
+GLEW_FUN_EXPORT PFNGLGETQUERYBUFFEROBJECTI64VPROC __glewGetQueryBufferObjecti64v;
+GLEW_FUN_EXPORT PFNGLGETQUERYBUFFEROBJECTIVPROC __glewGetQueryBufferObjectiv;
+GLEW_FUN_EXPORT PFNGLGETQUERYBUFFEROBJECTUI64VPROC __glewGetQueryBufferObjectui64v;
+GLEW_FUN_EXPORT PFNGLGETQUERYBUFFEROBJECTUIVPROC __glewGetQueryBufferObjectuiv;
+GLEW_FUN_EXPORT PFNGLGETTEXTUREIMAGEPROC __glewGetTextureImage;
+GLEW_FUN_EXPORT PFNGLGETTEXTURELEVELPARAMETERFVPROC __glewGetTextureLevelParameterfv;
+GLEW_FUN_EXPORT PFNGLGETTEXTURELEVELPARAMETERIVPROC __glewGetTextureLevelParameteriv;
+GLEW_FUN_EXPORT PFNGLGETTEXTUREPARAMETERIIVPROC __glewGetTextureParameterIiv;
+GLEW_FUN_EXPORT PFNGLGETTEXTUREPARAMETERIUIVPROC __glewGetTextureParameterIuiv;
+GLEW_FUN_EXPORT PFNGLGETTEXTUREPARAMETERFVPROC __glewGetTextureParameterfv;
+GLEW_FUN_EXPORT PFNGLGETTEXTUREPARAMETERIVPROC __glewGetTextureParameteriv;
+GLEW_FUN_EXPORT PFNGLGETTRANSFORMFEEDBACKI64_VPROC __glewGetTransformFeedbacki64_v;
+GLEW_FUN_EXPORT PFNGLGETTRANSFORMFEEDBACKI_VPROC __glewGetTransformFeedbacki_v;
+GLEW_FUN_EXPORT PFNGLGETTRANSFORMFEEDBACKIVPROC __glewGetTransformFeedbackiv;
+GLEW_FUN_EXPORT PFNGLGETVERTEXARRAYINDEXED64IVPROC __glewGetVertexArrayIndexed64iv;
+GLEW_FUN_EXPORT PFNGLGETVERTEXARRAYINDEXEDIVPROC __glewGetVertexArrayIndexediv;
+GLEW_FUN_EXPORT PFNGLGETVERTEXARRAYIVPROC __glewGetVertexArrayiv;
+GLEW_FUN_EXPORT PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC __glewInvalidateNamedFramebufferData;
+GLEW_FUN_EXPORT PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC __glewInvalidateNamedFramebufferSubData;
+GLEW_FUN_EXPORT PFNGLMAPNAMEDBUFFERPROC __glewMapNamedBuffer;
+GLEW_FUN_EXPORT PFNGLMAPNAMEDBUFFERRANGEPROC __glewMapNamedBufferRange;
+GLEW_FUN_EXPORT PFNGLNAMEDBUFFERDATAPROC __glewNamedBufferData;
+GLEW_FUN_EXPORT PFNGLNAMEDBUFFERSTORAGEPROC __glewNamedBufferStorage;
+GLEW_FUN_EXPORT PFNGLNAMEDBUFFERSUBDATAPROC __glewNamedBufferSubData;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC __glewNamedFramebufferDrawBuffer;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC __glewNamedFramebufferDrawBuffers;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC __glewNamedFramebufferParameteri;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC __glewNamedFramebufferReadBuffer;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC __glewNamedFramebufferRenderbuffer;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERTEXTUREPROC __glewNamedFramebufferTexture;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC __glewNamedFramebufferTextureLayer;
+GLEW_FUN_EXPORT PFNGLNAMEDRENDERBUFFERSTORAGEPROC __glewNamedRenderbufferStorage;
+GLEW_FUN_EXPORT PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC __glewNamedRenderbufferStorageMultisample;
+GLEW_FUN_EXPORT PFNGLTEXTUREBUFFERPROC __glewTextureBuffer;
+GLEW_FUN_EXPORT PFNGLTEXTUREBUFFERRANGEPROC __glewTextureBufferRange;
+GLEW_FUN_EXPORT PFNGLTEXTUREPARAMETERIIVPROC __glewTextureParameterIiv;
+GLEW_FUN_EXPORT PFNGLTEXTUREPARAMETERIUIVPROC __glewTextureParameterIuiv;
+GLEW_FUN_EXPORT PFNGLTEXTUREPARAMETERFPROC __glewTextureParameterf;
+GLEW_FUN_EXPORT PFNGLTEXTUREPARAMETERFVPROC __glewTextureParameterfv;
+GLEW_FUN_EXPORT PFNGLTEXTUREPARAMETERIPROC __glewTextureParameteri;
+GLEW_FUN_EXPORT PFNGLTEXTUREPARAMETERIVPROC __glewTextureParameteriv;
+GLEW_FUN_EXPORT PFNGLTEXTURESTORAGE1DPROC __glewTextureStorage1D;
+GLEW_FUN_EXPORT PFNGLTEXTURESTORAGE2DPROC __glewTextureStorage2D;
+GLEW_FUN_EXPORT PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC __glewTextureStorage2DMultisample;
+GLEW_FUN_EXPORT PFNGLTEXTURESTORAGE3DPROC __glewTextureStorage3D;
+GLEW_FUN_EXPORT PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC __glewTextureStorage3DMultisample;
+GLEW_FUN_EXPORT PFNGLTEXTURESUBIMAGE1DPROC __glewTextureSubImage1D;
+GLEW_FUN_EXPORT PFNGLTEXTURESUBIMAGE2DPROC __glewTextureSubImage2D;
+GLEW_FUN_EXPORT PFNGLTEXTURESUBIMAGE3DPROC __glewTextureSubImage3D;
+GLEW_FUN_EXPORT PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC __glewTransformFeedbackBufferBase;
+GLEW_FUN_EXPORT PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC __glewTransformFeedbackBufferRange;
+GLEW_FUN_EXPORT PFNGLUNMAPNAMEDBUFFERPROC __glewUnmapNamedBuffer;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYATTRIBBINDINGPROC __glewVertexArrayAttribBinding;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYATTRIBFORMATPROC __glewVertexArrayAttribFormat;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYATTRIBIFORMATPROC __glewVertexArrayAttribIFormat;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYATTRIBLFORMATPROC __glewVertexArrayAttribLFormat;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYBINDINGDIVISORPROC __glewVertexArrayBindingDivisor;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYELEMENTBUFFERPROC __glewVertexArrayElementBuffer;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXBUFFERPROC __glewVertexArrayVertexBuffer;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXBUFFERSPROC __glewVertexArrayVertexBuffers;
+
GLEW_FUN_EXPORT PFNGLDRAWBUFFERSARBPROC __glewDrawBuffersARB;
GLEW_FUN_EXPORT PFNGLBLENDEQUATIONSEPARATEIARBPROC __glewBlendEquationSeparateiARB;
@@ -15550,6 +17044,9 @@ GLEW_FUN_EXPORT PFNGLGETPROGRAMBINARYPROC __glewGetProgramBinary;
GLEW_FUN_EXPORT PFNGLPROGRAMBINARYPROC __glewProgramBinary;
GLEW_FUN_EXPORT PFNGLPROGRAMPARAMETERIPROC __glewProgramParameteri;
+GLEW_FUN_EXPORT PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC __glewGetCompressedTextureSubImage;
+GLEW_FUN_EXPORT PFNGLGETTEXTURESUBIMAGEPROC __glewGetTextureSubImage;
+
GLEW_FUN_EXPORT PFNGLGETUNIFORMDVPROC __glewGetUniformdv;
GLEW_FUN_EXPORT PFNGLUNIFORM1DPROC __glewUniform1d;
GLEW_FUN_EXPORT PFNGLUNIFORM1DVPROC __glewUniform1dv;
@@ -15569,6 +17066,43 @@ GLEW_FUN_EXPORT PFNGLUNIFORMMATRIX4DVPROC __glewUniformMatrix4dv;
GLEW_FUN_EXPORT PFNGLUNIFORMMATRIX4X2DVPROC __glewUniformMatrix4x2dv;
GLEW_FUN_EXPORT PFNGLUNIFORMMATRIX4X3DVPROC __glewUniformMatrix4x3dv;
+GLEW_FUN_EXPORT PFNGLGETUNIFORMI64VARBPROC __glewGetUniformi64vARB;
+GLEW_FUN_EXPORT PFNGLGETUNIFORMUI64VARBPROC __glewGetUniformui64vARB;
+GLEW_FUN_EXPORT PFNGLGETNUNIFORMI64VARBPROC __glewGetnUniformi64vARB;
+GLEW_FUN_EXPORT PFNGLGETNUNIFORMUI64VARBPROC __glewGetnUniformui64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1I64ARBPROC __glewProgramUniform1i64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1I64VARBPROC __glewProgramUniform1i64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1UI64ARBPROC __glewProgramUniform1ui64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1UI64VARBPROC __glewProgramUniform1ui64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2I64ARBPROC __glewProgramUniform2i64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2I64VARBPROC __glewProgramUniform2i64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2UI64ARBPROC __glewProgramUniform2ui64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2UI64VARBPROC __glewProgramUniform2ui64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3I64ARBPROC __glewProgramUniform3i64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3I64VARBPROC __glewProgramUniform3i64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3UI64ARBPROC __glewProgramUniform3ui64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3UI64VARBPROC __glewProgramUniform3ui64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4I64ARBPROC __glewProgramUniform4i64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4I64VARBPROC __glewProgramUniform4i64vARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4UI64ARBPROC __glewProgramUniform4ui64ARB;
+GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4UI64VARBPROC __glewProgramUniform4ui64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM1I64ARBPROC __glewUniform1i64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM1I64VARBPROC __glewUniform1i64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM1UI64ARBPROC __glewUniform1ui64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM1UI64VARBPROC __glewUniform1ui64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM2I64ARBPROC __glewUniform2i64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM2I64VARBPROC __glewUniform2i64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM2UI64ARBPROC __glewUniform2ui64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM2UI64VARBPROC __glewUniform2ui64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM3I64ARBPROC __glewUniform3i64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM3I64VARBPROC __glewUniform3i64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM3UI64ARBPROC __glewUniform3ui64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM3UI64VARBPROC __glewUniform3ui64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM4I64ARBPROC __glewUniform4i64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM4I64VARBPROC __glewUniform4i64vARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM4UI64ARBPROC __glewUniform4ui64ARB;
+GLEW_FUN_EXPORT PFNGLUNIFORM4UI64VARBPROC __glewUniform4ui64vARB;
+
GLEW_FUN_EXPORT PFNGLCOLORSUBTABLEPROC __glewColorSubTable;
GLEW_FUN_EXPORT PFNGLCOLORTABLEPROC __glewColorTable;
GLEW_FUN_EXPORT PFNGLCOLORTABLEPARAMETERFVPROC __glewColorTableParameterfv;
@@ -15685,6 +17219,8 @@ GLEW_FUN_EXPORT PFNGLGETQUERYOBJECTUIVARBPROC __glewGetQueryObjectuivARB;
GLEW_FUN_EXPORT PFNGLGETQUERYIVARBPROC __glewGetQueryivARB;
GLEW_FUN_EXPORT PFNGLISQUERYARBPROC __glewIsQueryARB;
+GLEW_FUN_EXPORT PFNGLMAXSHADERCOMPILERTHREADSARBPROC __glewMaxShaderCompilerThreadsARB;
+
GLEW_FUN_EXPORT PFNGLPOINTPARAMETERFARBPROC __glewPointParameterfARB;
GLEW_FUN_EXPORT PFNGLPOINTPARAMETERFVARBPROC __glewPointParameterfvARB;
@@ -15718,6 +17254,9 @@ GLEW_FUN_EXPORT PFNGLGETNUNIFORMIVARBPROC __glewGetnUniformivARB;
GLEW_FUN_EXPORT PFNGLGETNUNIFORMUIVARBPROC __glewGetnUniformuivARB;
GLEW_FUN_EXPORT PFNGLREADNPIXELSARBPROC __glewReadnPixelsARB;
+GLEW_FUN_EXPORT PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC __glewFramebufferSampleLocationsfvARB;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC __glewNamedFramebufferSampleLocationsfvARB;
+
GLEW_FUN_EXPORT PFNGLMINSAMPLESHADINGARBPROC __glewMinSampleShadingARB;
GLEW_FUN_EXPORT PFNGLBINDSAMPLERPROC __glewBindSampler;
@@ -15859,6 +17398,8 @@ GLEW_FUN_EXPORT PFNGLGETNAMEDSTRINGIVARBPROC __glewGetNamedStringivARB;
GLEW_FUN_EXPORT PFNGLISNAMEDSTRINGARBPROC __glewIsNamedStringARB;
GLEW_FUN_EXPORT PFNGLNAMEDSTRINGARBPROC __glewNamedStringARB;
+GLEW_FUN_EXPORT PFNGLBUFFERPAGECOMMITMENTARBPROC __glewBufferPageCommitmentARB;
+
GLEW_FUN_EXPORT PFNGLTEXPAGECOMMITMENTARBPROC __glewTexPageCommitmentARB;
GLEW_FUN_EXPORT PFNGLTEXTUREPAGECOMMITMENTEXTPROC __glewTexturePageCommitmentEXT;
@@ -15873,6 +17414,8 @@ GLEW_FUN_EXPORT PFNGLWAITSYNCPROC __glewWaitSync;
GLEW_FUN_EXPORT PFNGLPATCHPARAMETERFVPROC __glewPatchParameterfv;
GLEW_FUN_EXPORT PFNGLPATCHPARAMETERIPROC __glewPatchParameteri;
+GLEW_FUN_EXPORT PFNGLTEXTUREBARRIERPROC __glewTextureBarrier;
+
GLEW_FUN_EXPORT PFNGLTEXBUFFERARBPROC __glewTexBufferARB;
GLEW_FUN_EXPORT PFNGLTEXBUFFERRANGEPROC __glewTexBufferRange;
@@ -15958,6 +17501,12 @@ GLEW_FUN_EXPORT PFNGLVERTEXATTRIBL4DVPROC __glewVertexAttribL4dv;
GLEW_FUN_EXPORT PFNGLVERTEXATTRIBLPOINTERPROC __glewVertexAttribLPointer;
GLEW_FUN_EXPORT PFNGLBINDVERTEXBUFFERPROC __glewBindVertexBuffer;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC __glewVertexArrayBindVertexBufferEXT;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC __glewVertexArrayVertexAttribBindingEXT;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC __glewVertexArrayVertexAttribFormatEXT;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC __glewVertexArrayVertexAttribIFormatEXT;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC __glewVertexArrayVertexAttribLFormatEXT;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC __glewVertexArrayVertexBindingDivisorEXT;
GLEW_FUN_EXPORT PFNGLVERTEXATTRIBBINDINGPROC __glewVertexAttribBinding;
GLEW_FUN_EXPORT PFNGLVERTEXATTRIBFORMATPROC __glewVertexAttribFormat;
GLEW_FUN_EXPORT PFNGLVERTEXATTRIBIFORMATPROC __glewVertexAttribIFormat;
@@ -16263,6 +17812,9 @@ GLEW_FUN_EXPORT PFNGLCOPYTEXSUBIMAGE3DEXTPROC __glewCopyTexSubImage3DEXT;
GLEW_FUN_EXPORT PFNGLCULLPARAMETERDVEXTPROC __glewCullParameterdvEXT;
GLEW_FUN_EXPORT PFNGLCULLPARAMETERFVEXTPROC __glewCullParameterfvEXT;
+GLEW_FUN_EXPORT PFNGLGETOBJECTLABELEXTPROC __glewGetObjectLabelEXT;
+GLEW_FUN_EXPORT PFNGLLABELOBJECTEXTPROC __glewLabelObjectEXT;
+
GLEW_FUN_EXPORT PFNGLINSERTEVENTMARKEREXTPROC __glewInsertEventMarkerEXT;
GLEW_FUN_EXPORT PFNGLPOPGROUPMARKEREXTPROC __glewPopGroupMarkerEXT;
GLEW_FUN_EXPORT PFNGLPUSHGROUPMARKEREXTPROC __glewPushGroupMarkerEXT;
@@ -16479,6 +18031,7 @@ GLEW_FUN_EXPORT PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC __glewVertexArrayMult
GLEW_FUN_EXPORT PFNGLVERTEXARRAYNORMALOFFSETEXTPROC __glewVertexArrayNormalOffsetEXT;
GLEW_FUN_EXPORT PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC __glewVertexArraySecondaryColorOffsetEXT;
GLEW_FUN_EXPORT PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC __glewVertexArrayTexCoordOffsetEXT;
+GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC __glewVertexArrayVertexAttribDivisorEXT;
GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC __glewVertexArrayVertexAttribIOffsetEXT;
GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC __glewVertexArrayVertexAttribOffsetEXT;
GLEW_FUN_EXPORT PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC __glewVertexArrayVertexOffsetEXT;
@@ -16626,8 +18179,15 @@ GLEW_FUN_EXPORT PFNGLPOINTPARAMETERFVEXTPROC __glewPointParameterfvEXT;
GLEW_FUN_EXPORT PFNGLPOLYGONOFFSETEXTPROC __glewPolygonOffsetEXT;
+GLEW_FUN_EXPORT PFNGLPOLYGONOFFSETCLAMPEXTPROC __glewPolygonOffsetClampEXT;
+
GLEW_FUN_EXPORT PFNGLPROVOKINGVERTEXEXTPROC __glewProvokingVertexEXT;
+GLEW_FUN_EXPORT PFNGLCOVERAGEMODULATIONNVPROC __glewCoverageModulationNV;
+GLEW_FUN_EXPORT PFNGLCOVERAGEMODULATIONTABLENVPROC __glewCoverageModulationTableNV;
+GLEW_FUN_EXPORT PFNGLGETCOVERAGEMODULATIONTABLENVPROC __glewGetCoverageModulationTableNV;
+GLEW_FUN_EXPORT PFNGLRASTERSAMPLESEXTPROC __glewRasterSamplesEXT;
+
GLEW_FUN_EXPORT PFNGLBEGINSCENEEXTPROC __glewBeginSceneEXT;
GLEW_FUN_EXPORT PFNGLENDSCENEEXTPROC __glewEndSceneEXT;
@@ -16797,9 +18357,22 @@ GLEW_FUN_EXPORT PFNGLNORMALPOINTERVINTELPROC __glewNormalPointervINTEL;
GLEW_FUN_EXPORT PFNGLTEXCOORDPOINTERVINTELPROC __glewTexCoordPointervINTEL;
GLEW_FUN_EXPORT PFNGLVERTEXPOINTERVINTELPROC __glewVertexPointervINTEL;
+GLEW_FUN_EXPORT PFNGLBEGINPERFQUERYINTELPROC __glewBeginPerfQueryINTEL;
+GLEW_FUN_EXPORT PFNGLCREATEPERFQUERYINTELPROC __glewCreatePerfQueryINTEL;
+GLEW_FUN_EXPORT PFNGLDELETEPERFQUERYINTELPROC __glewDeletePerfQueryINTEL;
+GLEW_FUN_EXPORT PFNGLENDPERFQUERYINTELPROC __glewEndPerfQueryINTEL;
+GLEW_FUN_EXPORT PFNGLGETFIRSTPERFQUERYIDINTELPROC __glewGetFirstPerfQueryIdINTEL;
+GLEW_FUN_EXPORT PFNGLGETNEXTPERFQUERYIDINTELPROC __glewGetNextPerfQueryIdINTEL;
+GLEW_FUN_EXPORT PFNGLGETPERFCOUNTERINFOINTELPROC __glewGetPerfCounterInfoINTEL;
+GLEW_FUN_EXPORT PFNGLGETPERFQUERYDATAINTELPROC __glewGetPerfQueryDataINTEL;
+GLEW_FUN_EXPORT PFNGLGETPERFQUERYIDBYNAMEINTELPROC __glewGetPerfQueryIdByNameINTEL;
+GLEW_FUN_EXPORT PFNGLGETPERFQUERYINFOINTELPROC __glewGetPerfQueryInfoINTEL;
+
GLEW_FUN_EXPORT PFNGLTEXSCISSORFUNCINTELPROC __glewTexScissorFuncINTEL;
GLEW_FUN_EXPORT PFNGLTEXSCISSORINTELPROC __glewTexScissorINTEL;
+GLEW_FUN_EXPORT PFNGLBLENDBARRIERKHRPROC __glewBlendBarrierKHR;
+
GLEW_FUN_EXPORT PFNGLDEBUGMESSAGECALLBACKPROC __glewDebugMessageCallback;
GLEW_FUN_EXPORT PFNGLDEBUGMESSAGECONTROLPROC __glewDebugMessageControl;
GLEW_FUN_EXPORT PFNGLDEBUGMESSAGEINSERTPROC __glewDebugMessageInsert;
@@ -16811,6 +18384,11 @@ GLEW_FUN_EXPORT PFNGLOBJECTPTRLABELPROC __glewObjectPtrLabel;
GLEW_FUN_EXPORT PFNGLPOPDEBUGGROUPPROC __glewPopDebugGroup;
GLEW_FUN_EXPORT PFNGLPUSHDEBUGGROUPPROC __glewPushDebugGroup;
+GLEW_FUN_EXPORT PFNGLGETNUNIFORMFVPROC __glewGetnUniformfv;
+GLEW_FUN_EXPORT PFNGLGETNUNIFORMIVPROC __glewGetnUniformiv;
+GLEW_FUN_EXPORT PFNGLGETNUNIFORMUIVPROC __glewGetnUniformuiv;
+GLEW_FUN_EXPORT PFNGLREADNPIXELSPROC __glewReadnPixels;
+
GLEW_FUN_EXPORT PFNGLBUFFERREGIONENABLEDPROC __glewBufferRegionEnabled;
GLEW_FUN_EXPORT PFNGLDELETEBUFFERREGIONPROC __glewDeleteBufferRegion;
GLEW_FUN_EXPORT PFNGLDRAWBUFFERREGIONPROC __glewDrawBufferRegion;
@@ -16850,6 +18428,9 @@ GLEW_FUN_EXPORT PFNGLENDCONDITIONALRENDERNVXPROC __glewEndConditionalRenderNVX;
GLEW_FUN_EXPORT PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC __glewMultiDrawArraysIndirectBindlessNV;
GLEW_FUN_EXPORT PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC __glewMultiDrawElementsIndirectBindlessNV;
+GLEW_FUN_EXPORT PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC __glewMultiDrawArraysIndirectBindlessCountNV;
+GLEW_FUN_EXPORT PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC __glewMultiDrawElementsIndirectBindlessCountNV;
+
GLEW_FUN_EXPORT PFNGLGETIMAGEHANDLENVPROC __glewGetImageHandleNV;
GLEW_FUN_EXPORT PFNGLGETTEXTUREHANDLENVPROC __glewGetTextureHandleNV;
GLEW_FUN_EXPORT PFNGLGETTEXTURESAMPLERHANDLENVPROC __glewGetTextureSamplerHandleNV;
@@ -16870,6 +18451,10 @@ GLEW_FUN_EXPORT PFNGLBLENDPARAMETERINVPROC __glewBlendParameteriNV;
GLEW_FUN_EXPORT PFNGLBEGINCONDITIONALRENDERNVPROC __glewBeginConditionalRenderNV;
GLEW_FUN_EXPORT PFNGLENDCONDITIONALRENDERNVPROC __glewEndConditionalRenderNV;
+GLEW_FUN_EXPORT PFNGLSUBPIXELPRECISIONBIASNVPROC __glewSubpixelPrecisionBiasNV;
+
+GLEW_FUN_EXPORT PFNGLCONSERVATIVERASTERPARAMETERFNVPROC __glewConservativeRasterParameterfNV;
+
GLEW_FUN_EXPORT PFNGLCOPYIMAGESUBDATANVPROC __glewCopyImageSubDataNV;
GLEW_FUN_EXPORT PFNGLCLEARDEPTHDNVPROC __glewClearDepthdNV;
@@ -16900,6 +18485,8 @@ GLEW_FUN_EXPORT PFNGLISFENCENVPROC __glewIsFenceNV;
GLEW_FUN_EXPORT PFNGLSETFENCENVPROC __glewSetFenceNV;
GLEW_FUN_EXPORT PFNGLTESTFENCENVPROC __glewTestFenceNV;
+GLEW_FUN_EXPORT PFNGLFRAGMENTCOVERAGECOLORNVPROC __glewFragmentCoverageColorNV;
+
GLEW_FUN_EXPORT PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC __glewGetProgramNamedParameterdvNV;
GLEW_FUN_EXPORT PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC __glewGetProgramNamedParameterfvNV;
GLEW_FUN_EXPORT PFNGLPROGRAMNAMEDPARAMETER4DNVPROC __glewProgramNamedParameter4dNV;
@@ -17006,6 +18593,8 @@ GLEW_FUN_EXPORT PFNGLVERTEXATTRIBS4HVNVPROC __glewVertexAttribs4hvNV;
GLEW_FUN_EXPORT PFNGLVERTEXWEIGHTHNVPROC __glewVertexWeighthNV;
GLEW_FUN_EXPORT PFNGLVERTEXWEIGHTHVNVPROC __glewVertexWeighthvNV;
+GLEW_FUN_EXPORT PFNGLGETINTERNALFORMATSAMPLEIVNVPROC __glewGetInternalformatSampleivNV;
+
GLEW_FUN_EXPORT PFNGLBEGINOCCLUSIONQUERYNVPROC __glewBeginOcclusionQueryNV;
GLEW_FUN_EXPORT PFNGLDELETEOCCLUSIONQUERIESNVPROC __glewDeleteOcclusionQueriesNV;
GLEW_FUN_EXPORT PFNGLENDOCCLUSIONQUERYNVPROC __glewEndOcclusionQueryNV;
@@ -17038,18 +18627,28 @@ GLEW_FUN_EXPORT PFNGLGETPATHPARAMETERIVNVPROC __glewGetPathParameterivNV;
GLEW_FUN_EXPORT PFNGLGETPATHSPACINGNVPROC __glewGetPathSpacingNV;
GLEW_FUN_EXPORT PFNGLGETPATHTEXGENFVNVPROC __glewGetPathTexGenfvNV;
GLEW_FUN_EXPORT PFNGLGETPATHTEXGENIVNVPROC __glewGetPathTexGenivNV;
+GLEW_FUN_EXPORT PFNGLGETPROGRAMRESOURCEFVNVPROC __glewGetProgramResourcefvNV;
GLEW_FUN_EXPORT PFNGLINTERPOLATEPATHSNVPROC __glewInterpolatePathsNV;
GLEW_FUN_EXPORT PFNGLISPATHNVPROC __glewIsPathNV;
GLEW_FUN_EXPORT PFNGLISPOINTINFILLPATHNVPROC __glewIsPointInFillPathNV;
GLEW_FUN_EXPORT PFNGLISPOINTINSTROKEPATHNVPROC __glewIsPointInStrokePathNV;
+GLEW_FUN_EXPORT PFNGLMATRIXLOAD3X2FNVPROC __glewMatrixLoad3x2fNV;
+GLEW_FUN_EXPORT PFNGLMATRIXLOAD3X3FNVPROC __glewMatrixLoad3x3fNV;
+GLEW_FUN_EXPORT PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC __glewMatrixLoadTranspose3x3fNV;
+GLEW_FUN_EXPORT PFNGLMATRIXMULT3X2FNVPROC __glewMatrixMult3x2fNV;
+GLEW_FUN_EXPORT PFNGLMATRIXMULT3X3FNVPROC __glewMatrixMult3x3fNV;
+GLEW_FUN_EXPORT PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC __glewMatrixMultTranspose3x3fNV;
GLEW_FUN_EXPORT PFNGLPATHCOLORGENNVPROC __glewPathColorGenNV;
GLEW_FUN_EXPORT PFNGLPATHCOMMANDSNVPROC __glewPathCommandsNV;
GLEW_FUN_EXPORT PFNGLPATHCOORDSNVPROC __glewPathCoordsNV;
GLEW_FUN_EXPORT PFNGLPATHCOVERDEPTHFUNCNVPROC __glewPathCoverDepthFuncNV;
GLEW_FUN_EXPORT PFNGLPATHDASHARRAYNVPROC __glewPathDashArrayNV;
GLEW_FUN_EXPORT PFNGLPATHFOGGENNVPROC __glewPathFogGenNV;
+GLEW_FUN_EXPORT PFNGLPATHGLYPHINDEXARRAYNVPROC __glewPathGlyphIndexArrayNV;
+GLEW_FUN_EXPORT PFNGLPATHGLYPHINDEXRANGENVPROC __glewPathGlyphIndexRangeNV;
GLEW_FUN_EXPORT PFNGLPATHGLYPHRANGENVPROC __glewPathGlyphRangeNV;
GLEW_FUN_EXPORT PFNGLPATHGLYPHSNVPROC __glewPathGlyphsNV;
+GLEW_FUN_EXPORT PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC __glewPathMemoryGlyphIndexArrayNV;
GLEW_FUN_EXPORT PFNGLPATHPARAMETERFNVPROC __glewPathParameterfNV;
GLEW_FUN_EXPORT PFNGLPATHPARAMETERFVNVPROC __glewPathParameterfvNV;
GLEW_FUN_EXPORT PFNGLPATHPARAMETERINVPROC __glewPathParameteriNV;
@@ -17061,10 +18660,15 @@ GLEW_FUN_EXPORT PFNGLPATHSUBCOMMANDSNVPROC __glewPathSubCommandsNV;
GLEW_FUN_EXPORT PFNGLPATHSUBCOORDSNVPROC __glewPathSubCoordsNV;
GLEW_FUN_EXPORT PFNGLPATHTEXGENNVPROC __glewPathTexGenNV;
GLEW_FUN_EXPORT PFNGLPOINTALONGPATHNVPROC __glewPointAlongPathNV;
+GLEW_FUN_EXPORT PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC __glewProgramPathFragmentInputGenNV;
GLEW_FUN_EXPORT PFNGLSTENCILFILLPATHINSTANCEDNVPROC __glewStencilFillPathInstancedNV;
GLEW_FUN_EXPORT PFNGLSTENCILFILLPATHNVPROC __glewStencilFillPathNV;
GLEW_FUN_EXPORT PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC __glewStencilStrokePathInstancedNV;
GLEW_FUN_EXPORT PFNGLSTENCILSTROKEPATHNVPROC __glewStencilStrokePathNV;
+GLEW_FUN_EXPORT PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC __glewStencilThenCoverFillPathInstancedNV;
+GLEW_FUN_EXPORT PFNGLSTENCILTHENCOVERFILLPATHNVPROC __glewStencilThenCoverFillPathNV;
+GLEW_FUN_EXPORT PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC __glewStencilThenCoverStrokePathInstancedNV;
+GLEW_FUN_EXPORT PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC __glewStencilThenCoverStrokePathNV;
GLEW_FUN_EXPORT PFNGLTRANSFORMPATHNVPROC __glewTransformPathNV;
GLEW_FUN_EXPORT PFNGLWEIGHTPATHSNVPROC __glewWeightPathsNV;
@@ -17101,6 +18705,9 @@ GLEW_FUN_EXPORT PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC __glewGetFinalCombin
GLEW_FUN_EXPORT PFNGLCOMBINERSTAGEPARAMETERFVNVPROC __glewCombinerStageParameterfvNV;
GLEW_FUN_EXPORT PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC __glewGetCombinerStageParameterfvNV;
+GLEW_FUN_EXPORT PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewFramebufferSampleLocationsfvNV;
+GLEW_FUN_EXPORT PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewNamedFramebufferSampleLocationsfvNV;
+
GLEW_FUN_EXPORT PFNGLGETBUFFERPARAMETERUI64VNVPROC __glewGetBufferParameterui64vNV;
GLEW_FUN_EXPORT PFNGLGETINTEGERUI64VNVPROC __glewGetIntegerui64vNV;
GLEW_FUN_EXPORT PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC __glewGetNamedBufferParameterui64vNV;
@@ -17276,6 +18883,8 @@ GLEW_FUN_EXPORT PFNGLFRUSTUMFOESPROC __glewFrustumfOES;
GLEW_FUN_EXPORT PFNGLGETCLIPPLANEFOESPROC __glewGetClipPlanefOES;
GLEW_FUN_EXPORT PFNGLORTHOFOESPROC __glewOrthofOES;
+GLEW_FUN_EXPORT PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __glewFramebufferTextureMultiviewOVR;
+
GLEW_FUN_EXPORT PFNGLALPHAFUNCXPROC __glewAlphaFuncx;
GLEW_FUN_EXPORT PFNGLCLEARCOLORXPROC __glewClearColorx;
GLEW_FUN_EXPORT PFNGLCLEARDEPTHXPROC __glewClearDepthx;
@@ -17329,6 +18938,8 @@ GLEW_FUN_EXPORT PFNGLISSUPPORTEDREGALPROC __glewIsSupportedREGAL;
GLEW_FUN_EXPORT PFNGLLOGMESSAGECALLBACKREGALPROC __glewLogMessageCallbackREGAL;
+GLEW_FUN_EXPORT PFNGLGETPROCADDRESSREGALPROC __glewGetProcAddressREGAL;
+
GLEW_FUN_EXPORT PFNGLDETAILTEXFUNCSGISPROC __glewDetailTexFuncSGIS;
GLEW_FUN_EXPORT PFNGLGETDETAILTEXFUNCSGISPROC __glewGetDetailTexFuncSGIS;
@@ -17483,6 +19094,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_1;
GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_2;
GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_3;
GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_4;
+GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_5;
GLEW_VAR_EXPORT GLboolean __GLEW_3DFX_multisample;
GLEW_VAR_EXPORT GLboolean __GLEW_3DFX_tbuffer;
GLEW_VAR_EXPORT GLboolean __GLEW_3DFX_texture_compression_FXT1;
@@ -17491,20 +19103,26 @@ GLEW_VAR_EXPORT GLboolean __GLEW_AMD_conservative_depth;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_debug_output;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_depth_clamp_separate;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_draw_buffers_blend;
+GLEW_VAR_EXPORT GLboolean __GLEW_AMD_gcn_shader;
+GLEW_VAR_EXPORT GLboolean __GLEW_AMD_gpu_shader_int64;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_interleaved_elements;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_multi_draw_indirect;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_name_gen_delete;
+GLEW_VAR_EXPORT GLboolean __GLEW_AMD_occlusion_query_event;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_performance_monitor;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_pinned_memory;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_query_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_sample_positions;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_seamless_cubemap_per_texture;
+GLEW_VAR_EXPORT GLboolean __GLEW_AMD_shader_atomic_counter_ops;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_shader_stencil_export;
+GLEW_VAR_EXPORT GLboolean __GLEW_AMD_shader_stencil_value_export;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_shader_trinary_minmax;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_sparse_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_stencil_operation_extended;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_texture_texture4;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_transform_feedback3_lines_triangles;
+GLEW_VAR_EXPORT GLboolean __GLEW_AMD_transform_feedback4;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_vertex_shader_layer;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_vertex_shader_tessellator;
GLEW_VAR_EXPORT GLboolean __GLEW_AMD_vertex_shader_viewport_index;
@@ -17538,6 +19156,8 @@ GLEW_VAR_EXPORT GLboolean __GLEW_APPLE_vertex_array_range;
GLEW_VAR_EXPORT GLboolean __GLEW_APPLE_vertex_program_evaluators;
GLEW_VAR_EXPORT GLboolean __GLEW_APPLE_ycbcr_422;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_ES2_compatibility;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_ES3_1_compatibility;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_ES3_2_compatibility;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_ES3_compatibility;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_arrays_of_arrays;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_base_instance;
@@ -17547,18 +19167,23 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_buffer_storage;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_cl_event;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_clear_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_clear_texture;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_clip_control;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_color_buffer_float;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compatibility;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compressed_texture_pixel_storage;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compute_shader;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compute_variable_group_size;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_conditional_render_inverted;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_conservative_depth;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_copy_buffer;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_copy_image;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_cull_distance;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_debug_output;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_depth_buffer_float;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_depth_clamp;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_depth_texture;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_derivative_control;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_direct_state_access;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_buffers;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_buffers_blend;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_elements_base_vertex;
@@ -17572,13 +19197,16 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_fragment_layer_viewport;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_fragment_program;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_fragment_program_shadow;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_fragment_shader;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_fragment_shader_interlock;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_framebuffer_no_attachments;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_framebuffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_framebuffer_sRGB;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_geometry_shader4;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_get_program_binary;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_get_texture_sub_image;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_gpu_shader5;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_gpu_shader_fp64;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_gpu_shader_int64;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_half_float_pixel;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_half_float_vertex;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_imaging;
@@ -17596,9 +19224,12 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_multisample;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_multitexture;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_occlusion_query;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_occlusion_query2;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_parallel_shader_compile;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_pipeline_statistics_query;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_pixel_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_point_parameters;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_point_sprite;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_post_depth_coverage;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_program_interface_query;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_provoking_vertex;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_query_buffer_object;
@@ -17606,13 +19237,17 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robust_buffer_access_behavior;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robustness;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robustness_application_isolation;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robustness_share_group_isolation;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sample_locations;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sample_shading;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sampler_objects;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_seamless_cube_map;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_seamless_cubemap_per_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_separate_shader_objects;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_atomic_counter_ops;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_atomic_counters;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_ballot;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_bit_encoding;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_clock;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_draw_parameters;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_group_vote;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_image_load_store;
@@ -17622,17 +19257,23 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_precision;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_stencil_export;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_storage_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_subroutine;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_texture_image_samples;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_texture_lod;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_viewport_layer_array;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shading_language_100;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shading_language_420pack;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shading_language_include;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shading_language_packing;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shadow;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shadow_ambient;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sparse_buffer;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sparse_texture;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sparse_texture2;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sparse_texture_clamp;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_stencil_texturing;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sync;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_tessellation_shader;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_barrier;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_border_clamp;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_buffer_object_rgb32;
@@ -17646,6 +19287,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_env_add;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_env_combine;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_env_crossbar;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_env_dot3;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_filter_minmax;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_float;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_gather;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_mirror_clamp_to_edge;
@@ -17666,6 +19308,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_timer_query;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_transform_feedback2;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_transform_feedback3;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_transform_feedback_instanced;
+GLEW_VAR_EXPORT GLboolean __GLEW_ARB_transform_feedback_overflow_query;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_transpose_matrix;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_uniform_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_array_bgra;
@@ -17720,6 +19363,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_EXT_convolution;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_coordinate_frame;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_copy_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_cull_vertex;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_debug_label;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_debug_marker;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_depth_bounds_test;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_direct_state_access;
@@ -17754,15 +19398,21 @@ GLEW_VAR_EXPORT GLboolean __GLEW_EXT_pixel_transform;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_pixel_transform_color_table;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_point_parameters;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_polygon_offset;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_polygon_offset_clamp;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_post_depth_coverage;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_provoking_vertex;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_raster_multisample;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_rescale_normal;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_scene_marker;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_secondary_color;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_separate_shader_objects;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_separate_specular_color;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_shader_image_load_formatted;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_shader_image_load_store;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_shader_integer_mix;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_shadow_funcs;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_shared_texture_palette;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_sparse_texture2;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_stencil_clear_tag;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_stencil_two_side;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_stencil_wrap;
@@ -17782,6 +19432,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_env_add;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_env_combine;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_env_dot3;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_filter_anisotropic;
+GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_filter_minmax;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_integer;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_lod_bias;
GLEW_VAR_EXPORT GLboolean __GLEW_EXT_texture_mirror_clamp;
@@ -17815,10 +19466,20 @@ GLEW_VAR_EXPORT GLboolean __GLEW_IBM_texture_mirrored_repeat;
GLEW_VAR_EXPORT GLboolean __GLEW_IBM_vertex_array_lists;
GLEW_VAR_EXPORT GLboolean __GLEW_INGR_color_clamp;
GLEW_VAR_EXPORT GLboolean __GLEW_INGR_interlace_read;
+GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_fragment_shader_ordering;
+GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_framebuffer_CMAA;
GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_map_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_parallel_arrays;
+GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_performance_query;
GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_texture_scissor;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_blend_equation_advanced;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_blend_equation_advanced_coherent;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_context_flush_control;
GLEW_VAR_EXPORT GLboolean __GLEW_KHR_debug;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_no_error;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_robust_buffer_access_behavior;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_robustness;
+GLEW_VAR_EXPORT GLboolean __GLEW_KHR_texture_compression_astc_hdr;
GLEW_VAR_EXPORT GLboolean __GLEW_KHR_texture_compression_astc_ldr;
GLEW_VAR_EXPORT GLboolean __GLEW_KTX_buffer_region;
GLEW_VAR_EXPORT GLboolean __GLEW_MESAX_texture_stack;
@@ -17829,12 +19490,15 @@ GLEW_VAR_EXPORT GLboolean __GLEW_MESA_ycbcr_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_NVX_conditional_render;
GLEW_VAR_EXPORT GLboolean __GLEW_NVX_gpu_memory_info;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_bindless_multi_draw_indirect;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_bindless_multi_draw_indirect_count;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_bindless_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_blend_equation_advanced;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_blend_equation_advanced_coherent;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_blend_square;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_compute_program5;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_conditional_render;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_conservative_raster;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_conservative_raster_dilate;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_copy_depth_to_color;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_copy_image;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_deep_texture3D;
@@ -17845,21 +19509,27 @@ GLEW_VAR_EXPORT GLboolean __GLEW_NV_draw_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_evaluators;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_explicit_multisample;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_fence;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_fill_rectangle;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_float_buffer;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_fog_distance;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_fragment_coverage_to_color;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_fragment_program;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_fragment_program2;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_fragment_program4;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_fragment_program_option;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_fragment_shader_interlock;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_framebuffer_mixed_samples;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_framebuffer_multisample_coverage;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_geometry_program4;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_geometry_shader4;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_geometry_shader_passthrough;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program4;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program5;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program5_mem_extended;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program_fp64;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_shader5;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_half_float;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_internalformat_sample_query;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_light_max_exponent;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_multisample_coverage;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_multisample_filter_hint;
@@ -17868,16 +19538,23 @@ GLEW_VAR_EXPORT GLboolean __GLEW_NV_packed_depth_stencil;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_parameter_buffer_object;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_parameter_buffer_object2;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_path_rendering;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_path_rendering_shared_edge;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_pixel_data_range;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_point_sprite;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_present_video;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_primitive_restart;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_register_combiners;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_register_combiners2;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_sample_locations;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_sample_mask_override_coverage;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_atomic_counters;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_atomic_float;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_atomic_fp16_vector;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_atomic_int64;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_buffer_load;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_storage_buffer_object;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_thread_group;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_thread_shuffle;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_tessellation_program5;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_texgen_emboss;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_texgen_reflection;
@@ -17892,6 +19569,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_NV_texture_shader2;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_texture_shader3;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_transform_feedback;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_transform_feedback2;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_uniform_buffer_unified_memory;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_vdpau_interop;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_vertex_array_range;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_vertex_array_range2;
@@ -17904,6 +19582,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_NV_vertex_program2_option;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_vertex_program3;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_vertex_program4;
GLEW_VAR_EXPORT GLboolean __GLEW_NV_video_capture;
+GLEW_VAR_EXPORT GLboolean __GLEW_NV_viewport_array2;
GLEW_VAR_EXPORT GLboolean __GLEW_OES_byte_coordinates;
GLEW_VAR_EXPORT GLboolean __GLEW_OES_compressed_paletted_texture;
GLEW_VAR_EXPORT GLboolean __GLEW_OES_read_format;
@@ -17911,6 +19590,8 @@ GLEW_VAR_EXPORT GLboolean __GLEW_OES_single_precision;
GLEW_VAR_EXPORT GLboolean __GLEW_OML_interlace;
GLEW_VAR_EXPORT GLboolean __GLEW_OML_resample;
GLEW_VAR_EXPORT GLboolean __GLEW_OML_subsample;
+GLEW_VAR_EXPORT GLboolean __GLEW_OVR_multiview;
+GLEW_VAR_EXPORT GLboolean __GLEW_OVR_multiview2;
GLEW_VAR_EXPORT GLboolean __GLEW_PGI_misc_hints;
GLEW_VAR_EXPORT GLboolean __GLEW_PGI_vertex_hints;
GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_ES1_0_compatibility;
@@ -17919,6 +19600,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_enable;
GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_error_string;
GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_extension_query;
GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_log;
+GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_proc_address;
GLEW_VAR_EXPORT GLboolean __GLEW_REND_screen_coordinates;
GLEW_VAR_EXPORT GLboolean __GLEW_S3_s3tc;
GLEW_VAR_EXPORT GLboolean __GLEW_SGIS_color_range;
@@ -18001,6 +19683,17 @@ GLEW_VAR_EXPORT GLboolean __GLEW_WIN_swap_hint;
#define GLEW_VERSION_MINOR 3
#define GLEW_VERSION_MICRO 4
+/* ------------------------------------------------------------------------- */
+
+/* GLEW version info */
+
+/*
+VERSION 1.13.0
+VERSION_MAJOR 1
+VERSION_MINOR 13
+VERSION_MICRO 0
+*/
+
/* API */
#ifdef GLEW_MX
@@ -18042,8 +19735,6 @@ GLEWAPI const GLubyte * GLEWAPIENTRY glewGetString (GLenum name);
#ifdef GLEW_APIENTRY_DEFINED
#undef GLEW_APIENTRY_DEFINED
#undef APIENTRY
-#undef GLAPIENTRY
-#define GLAPIENTRY
#endif
#ifdef GLEW_CALLBACK_DEFINED
diff --git a/extern/glew/include/GL/glxew.h b/extern/glew/include/GL/glxew.h
index 76a5f0d82ae..d803d260b37 100644
--- a/extern/glew/include/GL/glxew.h
+++ b/extern/glew/include/GL/glxew.h
@@ -1,5 +1,6 @@
/*
** The OpenGL Extension Wrangler Library
+** Copyright (C) 2008-2015, Nigel Stewart <nigels[]users sourceforge net>
** Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>
** Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>
** Copyright (C) 2002, Lev Povalahev
@@ -200,12 +201,12 @@ typedef Display* ( * PFNGLXGETCURRENTDISPLAYPROC) (void);
#ifndef GLX_VERSION_1_3
#define GLX_VERSION_1_3 1
-#define GLX_RGBA_BIT 0x00000001
#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001
+#define GLX_RGBA_BIT 0x00000001
#define GLX_WINDOW_BIT 0x00000001
#define GLX_COLOR_INDEX_BIT 0x00000002
-#define GLX_PIXMAP_BIT 0x00000002
#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002
+#define GLX_PIXMAP_BIT 0x00000002
#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004
#define GLX_PBUFFER_BIT 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008
@@ -386,6 +387,19 @@ typedef Bool ( * PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (GLXContext ctx);
#endif /* GLX_AMD_gpu_association */
+/* --------------------- GLX_ARB_context_flush_control --------------------- */
+
+#ifndef GLX_ARB_context_flush_control
+#define GLX_ARB_context_flush_control 1
+
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
+#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
+
+#define GLXEW_ARB_context_flush_control GLXEW_GET_VAR(__GLXEW_ARB_context_flush_control)
+
+#endif /* GLX_ARB_context_flush_control */
+
/* ------------------------- GLX_ARB_create_context ------------------------ */
#ifndef GLX_ARB_create_context
@@ -437,8 +451,8 @@ typedef GLXContext ( * PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display* dpy, GLXFBCo
#ifndef GLX_ARB_fbconfig_float
#define GLX_ARB_fbconfig_float 1
-#define GLX_RGBA_FLOAT_BIT 0x00000004
-#define GLX_RGBA_FLOAT_TYPE 0x20B9
+#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004
+#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9
#define GLXEW_ARB_fbconfig_float GLXEW_GET_VAR(__GLXEW_ARB_fbconfig_float)
@@ -665,6 +679,19 @@ typedef int ( * PFNGLXQUERYCONTEXTINFOEXTPROC) (Display* dpy, GLXContext context
#endif /* GLX_EXT_scene_marker */
+/* -------------------------- GLX_EXT_stereo_tree -------------------------- */
+
+#ifndef GLX_EXT_stereo_tree
+#define GLX_EXT_stereo_tree 1
+
+#define GLX_STEREO_NOTIFY_EXT 0x00000000
+#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
+#define GLX_STEREO_TREE_EXT 0x20F5
+
+#define GLXEW_EXT_stereo_tree GLXEW_GET_VAR(__GLXEW_EXT_stereo_tree)
+
+#endif /* GLX_EXT_stereo_tree */
+
/* -------------------------- GLX_EXT_swap_control ------------------------- */
#ifndef GLX_EXT_swap_control
@@ -831,6 +858,38 @@ typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPMESAPROC) (Display* dpy, XVisualInfo
#endif /* GLX_MESA_pixmap_colormap */
+/* ------------------------ GLX_MESA_query_renderer ------------------------ */
+
+#ifndef GLX_MESA_query_renderer
+#define GLX_MESA_query_renderer 1
+
+#define GLX_RENDERER_VENDOR_ID_MESA 0x8183
+#define GLX_RENDERER_DEVICE_ID_MESA 0x8184
+#define GLX_RENDERER_VERSION_MESA 0x8185
+#define GLX_RENDERER_ACCELERATED_MESA 0x8186
+#define GLX_RENDERER_VIDEO_MEMORY_MESA 0x8187
+#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188
+#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189
+#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A
+#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B
+#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C
+#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D
+#define GLX_RENDERER_ID_MESA 0x818E
+
+typedef Bool ( * PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int* value);
+typedef const char* ( * PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute);
+typedef Bool ( * PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display* dpy, int screen, int renderer, int attribute, unsigned int *value);
+typedef const char* ( * PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute);
+
+#define glXQueryCurrentRendererIntegerMESA GLXEW_GET_FUN(__glewXQueryCurrentRendererIntegerMESA)
+#define glXQueryCurrentRendererStringMESA GLXEW_GET_FUN(__glewXQueryCurrentRendererStringMESA)
+#define glXQueryRendererIntegerMESA GLXEW_GET_FUN(__glewXQueryRendererIntegerMESA)
+#define glXQueryRendererStringMESA GLXEW_GET_FUN(__glewXQueryRendererStringMESA)
+
+#define GLXEW_MESA_query_renderer GLXEW_GET_VAR(__GLXEW_MESA_query_renderer)
+
+#endif /* GLX_MESA_query_renderer */
+
/* ------------------------ GLX_MESA_release_buffers ----------------------- */
#ifndef GLX_MESA_release_buffers
@@ -875,6 +934,21 @@ typedef int ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned int interval);
#endif /* GLX_MESA_swap_control */
+/* --------------------------- GLX_NV_copy_buffer -------------------------- */
+
+#ifndef GLX_NV_copy_buffer
+#define GLX_NV_copy_buffer 1
+
+typedef void ( * PFNGLXCOPYBUFFERSUBDATANVPROC) (Display* dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+typedef void ( * PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) (Display* dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+
+#define glXCopyBufferSubDataNV GLXEW_GET_FUN(__glewXCopyBufferSubDataNV)
+#define glXNamedCopyBufferSubDataNV GLXEW_GET_FUN(__glewXNamedCopyBufferSubDataNV)
+
+#define GLXEW_NV_copy_buffer GLXEW_GET_VAR(__GLXEW_NV_copy_buffer)
+
+#endif /* GLX_NV_copy_buffer */
+
/* --------------------------- GLX_NV_copy_image --------------------------- */
#ifndef GLX_NV_copy_image
@@ -888,6 +962,19 @@ typedef void ( * PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx,
#endif /* GLX_NV_copy_image */
+/* ------------------------ GLX_NV_delay_before_swap ----------------------- */
+
+#ifndef GLX_NV_delay_before_swap
+#define GLX_NV_delay_before_swap 1
+
+typedef Bool ( * PFNGLXDELAYBEFORESWAPNVPROC) (Display* dpy, GLXDrawable drawable, GLfloat seconds);
+
+#define glXDelayBeforeSwapNV GLXEW_GET_FUN(__glewXDelayBeforeSwapNV)
+
+#define GLXEW_NV_delay_before_swap GLXEW_GET_VAR(__GLXEW_NV_delay_before_swap)
+
+#endif /* GLX_NV_delay_before_swap */
+
/* -------------------------- GLX_NV_float_buffer -------------------------- */
#ifndef GLX_NV_float_buffer
@@ -993,10 +1080,10 @@ typedef void ( * PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display* dpy, GLXVideoC
#endif /* GLX_NV_video_capture */
-/* -------------------------- GLX_NV_video_output -------------------------- */
+/* ---------------------------- GLX_NV_video_out --------------------------- */
-#ifndef GLX_NV_video_output
-#define GLX_NV_video_output 1
+#ifndef GLX_NV_video_out
+#define GLX_NV_video_out 1
#define GLX_VIDEO_OUT_COLOR_NV 0x20C3
#define GLX_VIDEO_OUT_ALPHA_NV 0x20C4
@@ -1023,9 +1110,9 @@ typedef int ( * PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display* dpy, GLXPbuffer pbuf,
#define glXReleaseVideoImageNV GLXEW_GET_FUN(__glewXReleaseVideoImageNV)
#define glXSendPbufferToVideoNV GLXEW_GET_FUN(__glewXSendPbufferToVideoNV)
-#define GLXEW_NV_video_output GLXEW_GET_VAR(__GLXEW_NV_video_output)
+#define GLXEW_NV_video_out GLXEW_GET_VAR(__GLXEW_NV_video_out)
-#endif /* GLX_NV_video_output */
+#endif /* GLX_NV_video_out */
/* -------------------------- GLX_OML_swap_method -------------------------- */
@@ -1111,10 +1198,10 @@ typedef Bool ( * PFNGLXWAITFORSBCOMLPROC) (Display* dpy, GLXDrawable drawable, i
#ifndef GLX_SGIX_fbconfig
#define GLX_SGIX_fbconfig 1
-#define GLX_WINDOW_BIT_SGIX 0x00000001
#define GLX_RGBA_BIT_SGIX 0x00000001
-#define GLX_PIXMAP_BIT_SGIX 0x00000002
+#define GLX_WINDOW_BIT_SGIX 0x00000001
#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002
+#define GLX_PIXMAP_BIT_SGIX 0x00000002
#define GLX_SCREEN_EXT 0x800C
#define GLX_DRAWABLE_TYPE_SGIX 0x8010
#define GLX_RENDER_TYPE_SGIX 0x8011
@@ -1151,8 +1238,8 @@ typedef XVisualInfo* ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLX
#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX 0x00000001
#define GLX_PIPE_RECT_SGIX 0x00000001
-#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002
#define GLX_HYPERPIPE_RENDER_PIPE_SGIX 0x00000002
+#define GLX_PIPE_RECT_LIMITS_SGIX 0x00000002
#define GLX_HYPERPIPE_STEREO_SGIX 0x00000003
#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX 0x00000004
#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80
@@ -1218,8 +1305,8 @@ typedef GLXHyperpipeNetworkSGIX * ( * PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Disp
#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001
#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002
-#define GLX_PBUFFER_BIT_SGIX 0x00000004
#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004
+#define GLX_PBUFFER_BIT_SGIX 0x00000004
#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008
#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010
#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020
@@ -1473,6 +1560,11 @@ GLXEW_FUN_EXPORT PFNGLXCOPYSUBBUFFERMESAPROC __glewXCopySubBufferMESA;
GLXEW_FUN_EXPORT PFNGLXCREATEGLXPIXMAPMESAPROC __glewXCreateGLXPixmapMESA;
+GLXEW_FUN_EXPORT PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC __glewXQueryCurrentRendererIntegerMESA;
+GLXEW_FUN_EXPORT PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC __glewXQueryCurrentRendererStringMESA;
+GLXEW_FUN_EXPORT PFNGLXQUERYRENDERERINTEGERMESAPROC __glewXQueryRendererIntegerMESA;
+GLXEW_FUN_EXPORT PFNGLXQUERYRENDERERSTRINGMESAPROC __glewXQueryRendererStringMESA;
+
GLXEW_FUN_EXPORT PFNGLXRELEASEBUFFERSMESAPROC __glewXReleaseBuffersMESA;
GLXEW_FUN_EXPORT PFNGLXSET3DFXMODEMESAPROC __glewXSet3DfxModeMESA;
@@ -1480,8 +1572,13 @@ GLXEW_FUN_EXPORT PFNGLXSET3DFXMODEMESAPROC __glewXSet3DfxModeMESA;
GLXEW_FUN_EXPORT PFNGLXGETSWAPINTERVALMESAPROC __glewXGetSwapIntervalMESA;
GLXEW_FUN_EXPORT PFNGLXSWAPINTERVALMESAPROC __glewXSwapIntervalMESA;
+GLXEW_FUN_EXPORT PFNGLXCOPYBUFFERSUBDATANVPROC __glewXCopyBufferSubDataNV;
+GLXEW_FUN_EXPORT PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC __glewXNamedCopyBufferSubDataNV;
+
GLXEW_FUN_EXPORT PFNGLXCOPYIMAGESUBDATANVPROC __glewXCopyImageSubDataNV;
+GLXEW_FUN_EXPORT PFNGLXDELAYBEFORESWAPNVPROC __glewXDelayBeforeSwapNV;
+
GLXEW_FUN_EXPORT PFNGLXBINDVIDEODEVICENVPROC __glewXBindVideoDeviceNV;
GLXEW_FUN_EXPORT PFNGLXENUMERATEVIDEODEVICESNVPROC __glewXEnumerateVideoDevicesNV;
@@ -1574,6 +1671,7 @@ GLXEW_VAR_EXPORT GLboolean __GLXEW_VERSION_1_3;
GLXEW_VAR_EXPORT GLboolean __GLXEW_VERSION_1_4;
GLXEW_VAR_EXPORT GLboolean __GLXEW_3DFX_multisample;
GLXEW_VAR_EXPORT GLboolean __GLXEW_AMD_gpu_association;
+GLXEW_VAR_EXPORT GLboolean __GLXEW_ARB_context_flush_control;
GLXEW_VAR_EXPORT GLboolean __GLXEW_ARB_create_context;
GLXEW_VAR_EXPORT GLboolean __GLXEW_ARB_create_context_profile;
GLXEW_VAR_EXPORT GLboolean __GLXEW_ARB_create_context_robustness;
@@ -1593,6 +1691,7 @@ GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_fbconfig_packed_float;
GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_framebuffer_sRGB;
GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_import_context;
GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_scene_marker;
+GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_stereo_tree;
GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_swap_control;
GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_swap_control_tear;
GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_texture_from_pixmap;
@@ -1602,17 +1701,20 @@ GLXEW_VAR_EXPORT GLboolean __GLXEW_INTEL_swap_event;
GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_agp_offset;
GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_copy_sub_buffer;
GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_pixmap_colormap;
+GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_query_renderer;
GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_release_buffers;
GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_set_3dfx_mode;
GLXEW_VAR_EXPORT GLboolean __GLXEW_MESA_swap_control;
+GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_copy_buffer;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_copy_image;
+GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_delay_before_swap;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_float_buffer;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_multisample_coverage;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_present_video;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_swap_group;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_vertex_array_range;
GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_video_capture;
-GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_video_output;
+GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_video_out;
GLXEW_VAR_EXPORT GLboolean __GLXEW_OML_swap_method;
GLXEW_VAR_EXPORT GLboolean __GLXEW_OML_sync_control;
GLXEW_VAR_EXPORT GLboolean __GLXEW_SGIS_blended_overlay;
@@ -1653,11 +1755,12 @@ GLEWAPI GLboolean GLEWAPIENTRY glxewContextIsSupported (const GLXEWContext *ctx,
#else /* GLEW_MX */
+GLEWAPI GLenum GLEWAPIENTRY glxewInit ();
+GLEWAPI GLboolean GLEWAPIENTRY glxewIsSupported (const char *name);
+
#define GLXEW_GET_VAR(x) (*(const GLboolean*)&x)
#define GLXEW_GET_FUN(x) x
-GLEWAPI GLboolean GLEWAPIENTRY glxewIsSupported (const char *name);
-
#endif /* GLEW_MX */
GLEWAPI GLboolean GLEWAPIENTRY glxewGetExtension (const char *name);
diff --git a/extern/glew/include/GL/wglew.h b/extern/glew/include/GL/wglew.h
index 8659841d359..23e4d3fbaba 100644
--- a/extern/glew/include/GL/wglew.h
+++ b/extern/glew/include/GL/wglew.h
@@ -1,5 +1,6 @@
/*
** The OpenGL Extension Wrangler Library
+** Copyright (C) 2008-2015, Nigel Stewart <nigels[]users sourceforge net>
** Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>
** Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>
** Copyright (C) 2002, Lev Povalahev
@@ -182,6 +183,19 @@ typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, in
#endif /* WGL_ARB_buffer_region */
+/* --------------------- WGL_ARB_context_flush_control --------------------- */
+
+#ifndef WGL_ARB_context_flush_control
+#define WGL_ARB_context_flush_control 1
+
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
+#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
+
+#define WGLEW_ARB_context_flush_control WGLEW_GET_VAR(__WGLEW_ARB_context_flush_control)
+
+#endif /* WGL_ARB_context_flush_control */
+
/* ------------------------- WGL_ARB_create_context ------------------------ */
#ifndef WGL_ARB_create_context
@@ -928,6 +942,19 @@ typedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcNa
#endif /* WGL_NV_copy_image */
+/* ------------------------ WGL_NV_delay_before_swap ----------------------- */
+
+#ifndef WGL_NV_delay_before_swap
+#define WGL_NV_delay_before_swap 1
+
+typedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds);
+
+#define wglDelayBeforeSwapNV WGLEW_GET_FUN(__wglewDelayBeforeSwapNV)
+
+#define WGLEW_NV_delay_before_swap WGLEW_GET_VAR(__WGLEW_NV_delay_before_swap)
+
+#endif /* WGL_NV_delay_before_swap */
+
/* -------------------------- WGL_NV_float_buffer -------------------------- */
#ifndef WGL_NV_float_buffer
@@ -1291,6 +1318,8 @@ WGLEW_FUN_EXPORT PFNWGLDXUNREGISTEROBJECTNVPROC __wglewDXUnregisterObjectNV;
WGLEW_FUN_EXPORT PFNWGLCOPYIMAGESUBDATANVPROC __wglewCopyImageSubDataNV;
+WGLEW_FUN_EXPORT PFNWGLDELAYBEFORESWAPNVPROC __wglewDelayBeforeSwapNV;
+
WGLEW_FUN_EXPORT PFNWGLCREATEAFFINITYDCNVPROC __wglewCreateAffinityDCNV;
WGLEW_FUN_EXPORT PFNWGLDELETEDCNVPROC __wglewDeleteDCNV;
WGLEW_FUN_EXPORT PFNWGLENUMGPUDEVICESNVPROC __wglewEnumGpuDevicesNV;
@@ -1334,6 +1363,7 @@ WGLEW_VAR_EXPORT GLboolean __WGLEW_3DFX_multisample;
WGLEW_VAR_EXPORT GLboolean __WGLEW_3DL_stereo_control;
WGLEW_VAR_EXPORT GLboolean __WGLEW_AMD_gpu_association;
WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_buffer_region;
+WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_context_flush_control;
WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_create_context;
WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_create_context_profile;
WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_create_context_robustness;
@@ -1371,6 +1401,7 @@ WGLEW_VAR_EXPORT GLboolean __WGLEW_I3D_swap_frame_usage;
WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_DX_interop;
WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_DX_interop2;
WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_copy_image;
+WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_delay_before_swap;
WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_float_buffer;
WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_gpu_affinity;
WGLEW_VAR_EXPORT GLboolean __WGLEW_NV_multisample_coverage;
@@ -1403,11 +1434,12 @@ GLEWAPI GLboolean GLEWAPIENTRY wglewContextIsSupported (const WGLEWContext *ctx,
#else /* GLEW_MX */
+GLEWAPI GLenum GLEWAPIENTRY wglewInit ();
+GLEWAPI GLboolean GLEWAPIENTRY wglewIsSupported (const char *name);
+
#define WGLEW_GET_VAR(x) (*(const GLboolean*)&x)
#define WGLEW_GET_FUN(x) x
-GLEWAPI GLboolean GLEWAPIENTRY wglewIsSupported (const char *name);
-
#endif /* GLEW_MX */
GLEWAPI GLboolean GLEWAPIENTRY wglewGetExtension (const char *name);
diff --git a/extern/glew/src/glew.c b/extern/glew/src/glew.c
index d075b524883..0ed5520dae2 100644
--- a/extern/glew/src/glew.c
+++ b/extern/glew/src/glew.c
@@ -1,5 +1,6 @@
/*
** The OpenGL Extension Wrangler Library
+** Copyright (C) 2008-2015, Nigel Stewart <nigels[]users sourceforge net>
** Copyright (C) 2002-2008, Milan Ikits <milan ikits[]ieee org>
** Copyright (C) 2002-2008, Marcelo E. Magallon <mmagallo[]debian org>
** Copyright (C) 2002, Lev Povalahev
@@ -33,10 +34,12 @@
#if defined(_WIN32)
# include <GL/wglew.h>
-#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
+#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
# include <GL/glxew.h>
#endif
+#include <stddef.h> /* For size_t */
+
/*
* Define glewGetContext and related helper macros.
*/
@@ -66,7 +69,23 @@
# define GLXEW_CONTEXT_ARG_DEF_LIST void
#endif /* GLEW_MX */
-#if defined(__sgi) || defined (__sun) || defined(GLEW_APPLE_GLX)
+#if defined(GLEW_REGAL)
+
+/* In GLEW_REGAL mode we call direcly into the linked
+ libRegal.so glGetProcAddressREGAL for looking up
+ the GL function pointers. */
+
+# undef glGetProcAddressREGAL
+# ifdef WIN32
+extern void * __stdcall glGetProcAddressREGAL(const GLchar *name);
+static void * (__stdcall * regalGetProcAddress) (const GLchar *) = glGetProcAddressREGAL;
+# else
+extern void * glGetProcAddressREGAL(const GLchar *name);
+static void * (*regalGetProcAddress) (const GLchar *) = glGetProcAddressREGAL;
+# endif
+# define glGetProcAddressREGAL GLEW_GET_FUN(__glewGetProcAddressREGAL)
+
+#elif defined(__sgi) || defined (__sun) || defined(__HAIKU__) || defined(GLEW_APPLE_GLX)
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
@@ -104,11 +123,7 @@ void* NSGLGetProcAddress (const GLubyte *name)
void* addr;
if (NULL == image)
{
-#ifdef GLEW_REGAL
- image = dlopen("libRegal.dylib", RTLD_LAZY);
-#else
image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
-#endif
}
if( !image ) return NULL;
addr = dlsym(image, (const char*)name);
@@ -130,11 +145,7 @@ void* NSGLGetProcAddress (const GLubyte *name)
char* symbolName;
if (NULL == image)
{
-#ifdef GLEW_REGAL
- image = NSAddImage("libRegal.dylib", NSADDIMAGE_OPTION_RETURN_ON_ERROR);
-#else
image = NSAddImage("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", NSADDIMAGE_OPTION_RETURN_ON_ERROR);
-#endif
}
/* prepend a '_' for the Unix C symbol mangling convention */
symbolName = malloc(strlen((const char*)name) + 2);
@@ -158,11 +169,13 @@ void* NSGLGetProcAddress (const GLubyte *name)
/*
* Define glewGetProcAddress.
*/
-#if defined(_WIN32)
+#if defined(GLEW_REGAL)
+# define glewGetProcAddress(name) regalGetProcAddress((const GLchar *) name)
+#elif defined(_WIN32)
# define glewGetProcAddress(name) wglGetProcAddress((LPCSTR)name)
#elif defined(__APPLE__) && !defined(GLEW_APPLE_GLX)
# define glewGetProcAddress(name) NSGLGetProcAddress(name)
-#elif defined(__sgi) || defined(__sun)
+#elif defined(__sgi) || defined(__sun) || defined(__HAIKU__)
# define glewGetProcAddress(name) dlGetProcAddress(name)
#elif defined(__ANDROID__)
# define glewGetProcAddress(name) NULL /* TODO */
@@ -173,9 +186,33 @@ void* NSGLGetProcAddress (const GLubyte *name)
#endif
/*
- * Define GLboolean const cast.
+ * Redefine GLEW_GET_VAR etc without const cast
*/
-#define CONST_CAST(x) (*(GLboolean*)&x)
+
+#undef GLEW_GET_VAR
+#ifdef GLEW_MX
+# define GLEW_GET_VAR(x) (glewGetContext()->x)
+#else /* GLEW_MX */
+# define GLEW_GET_VAR(x) (x)
+#endif /* GLEW_MX */
+
+#ifdef WGLEW_GET_VAR
+# undef WGLEW_GET_VAR
+# ifdef GLEW_MX
+# define WGLEW_GET_VAR(x) (wglewGetContext()->x)
+# else /* GLEW_MX */
+# define WGLEW_GET_VAR(x) (x)
+# endif /* GLEW_MX */
+#endif /* WGLEW_GET_VAR */
+
+#ifdef GLXEW_GET_VAR
+# undef GLXEW_GET_VAR
+# ifdef GLEW_MX
+# define GLXEW_GET_VAR(x) (glxewGetContext()->x)
+# else /* GLEW_MX */
+# define GLXEW_GET_VAR(x) (x)
+# endif /* GLEW_MX */
+#endif /* GLXEW_GET_VAR */
/*
* GLEW, just like OpenGL or GLU, does not rely on the standard C library.
@@ -206,7 +243,7 @@ static GLboolean _glewStrSame (const GLubyte* a, const GLubyte* b, GLuint n)
return i == n ? GL_TRUE : GL_FALSE;
}
-static GLboolean _glewStrSame1 (GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb)
+static GLboolean _glewStrSame1 (const GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb)
{
while (*na > 0 && (**a == ' ' || **a == '\n' || **a == '\r' || **a == '\t'))
{
@@ -227,7 +264,7 @@ static GLboolean _glewStrSame1 (GLubyte** a, GLuint* na, const GLubyte* b, GLuin
return GL_FALSE;
}
-static GLboolean _glewStrSame2 (GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb)
+static GLboolean _glewStrSame2 (const GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb)
{
if(*na >= nb)
{
@@ -243,7 +280,7 @@ static GLboolean _glewStrSame2 (GLubyte** a, GLuint* na, const GLubyte* b, GLuin
return GL_FALSE;
}
-static GLboolean _glewStrSame3 (GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb)
+static GLboolean _glewStrSame3 (const GLubyte** a, GLuint* na, const GLubyte* b, GLuint nb)
{
if(*na >= nb)
{
@@ -575,6 +612,11 @@ PFNGLBLENDFUNCSEPARATEIPROC __glewBlendFuncSeparatei = NULL;
PFNGLBLENDFUNCIPROC __glewBlendFunci = NULL;
PFNGLMINSAMPLESHADINGPROC __glewMinSampleShading = NULL;
+PFNGLGETGRAPHICSRESETSTATUSPROC __glewGetGraphicsResetStatus = NULL;
+PFNGLGETNCOMPRESSEDTEXIMAGEPROC __glewGetnCompressedTexImage = NULL;
+PFNGLGETNTEXIMAGEPROC __glewGetnTexImage = NULL;
+PFNGLGETNUNIFORMDVPROC __glewGetnUniformdv = NULL;
+
PFNGLTBUFFERMASK3DFXPROC __glewTbufferMask3DFX = NULL;
PFNGLDEBUGMESSAGECALLBACKAMDPROC __glewDebugMessageCallbackAMD = NULL;
@@ -596,6 +638,8 @@ PFNGLDELETENAMESAMDPROC __glewDeleteNamesAMD = NULL;
PFNGLGENNAMESAMDPROC __glewGenNamesAMD = NULL;
PFNGLISNAMEAMDPROC __glewIsNameAMD = NULL;
+PFNGLQUERYOBJECTPARAMETERUIAMDPROC __glewQueryObjectParameteruiAMD = NULL;
+
PFNGLBEGINPERFMONITORAMDPROC __glewBeginPerfMonitorAMD = NULL;
PFNGLDELETEPERFMONITORSAMDPROC __glewDeletePerfMonitorsAMD = NULL;
PFNGLENDPERFMONITORAMDPROC __glewEndPerfMonitorAMD = NULL;
@@ -688,6 +732,10 @@ PFNGLGETSHADERPRECISIONFORMATPROC __glewGetShaderPrecisionFormat = NULL;
PFNGLRELEASESHADERCOMPILERPROC __glewReleaseShaderCompiler = NULL;
PFNGLSHADERBINARYPROC __glewShaderBinary = NULL;
+PFNGLMEMORYBARRIERBYREGIONPROC __glewMemoryBarrierByRegion = NULL;
+
+PFNGLPRIMITIVEBOUNDINGBOXARBPROC __glewPrimitiveBoundingBoxARB = NULL;
+
PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __glewDrawArraysInstancedBaseInstance = NULL;
PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __glewDrawElementsInstancedBaseInstance = NULL;
PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __glewDrawElementsInstancedBaseVertexBaseInstance = NULL;
@@ -725,6 +773,8 @@ PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC __glewClearNamedBufferSubDataEXT = NULL;
PFNGLCLEARTEXIMAGEPROC __glewClearTexImage = NULL;
PFNGLCLEARTEXSUBIMAGEPROC __glewClearTexSubImage = NULL;
+PFNGLCLIPCONTROLPROC __glewClipControl = NULL;
+
PFNGLCLAMPCOLORARBPROC __glewClampColorARB = NULL;
PFNGLDISPATCHCOMPUTEPROC __glewDispatchCompute = NULL;
@@ -741,6 +791,104 @@ PFNGLDEBUGMESSAGECONTROLARBPROC __glewDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC __glewDebugMessageInsertARB = NULL;
PFNGLGETDEBUGMESSAGELOGARBPROC __glewGetDebugMessageLogARB = NULL;
+PFNGLBINDTEXTUREUNITPROC __glewBindTextureUnit = NULL;
+PFNGLBLITNAMEDFRAMEBUFFERPROC __glewBlitNamedFramebuffer = NULL;
+PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC __glewCheckNamedFramebufferStatus = NULL;
+PFNGLCLEARNAMEDBUFFERDATAPROC __glewClearNamedBufferData = NULL;
+PFNGLCLEARNAMEDBUFFERSUBDATAPROC __glewClearNamedBufferSubData = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERFIPROC __glewClearNamedFramebufferfi = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERFVPROC __glewClearNamedFramebufferfv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERIVPROC __glewClearNamedFramebufferiv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC __glewClearNamedFramebufferuiv = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC __glewCompressedTextureSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC __glewCompressedTextureSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC __glewCompressedTextureSubImage3D = NULL;
+PFNGLCOPYNAMEDBUFFERSUBDATAPROC __glewCopyNamedBufferSubData = NULL;
+PFNGLCOPYTEXTURESUBIMAGE1DPROC __glewCopyTextureSubImage1D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE2DPROC __glewCopyTextureSubImage2D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE3DPROC __glewCopyTextureSubImage3D = NULL;
+PFNGLCREATEBUFFERSPROC __glewCreateBuffers = NULL;
+PFNGLCREATEFRAMEBUFFERSPROC __glewCreateFramebuffers = NULL;
+PFNGLCREATEPROGRAMPIPELINESPROC __glewCreateProgramPipelines = NULL;
+PFNGLCREATEQUERIESPROC __glewCreateQueries = NULL;
+PFNGLCREATERENDERBUFFERSPROC __glewCreateRenderbuffers = NULL;
+PFNGLCREATESAMPLERSPROC __glewCreateSamplers = NULL;
+PFNGLCREATETEXTURESPROC __glewCreateTextures = NULL;
+PFNGLCREATETRANSFORMFEEDBACKSPROC __glewCreateTransformFeedbacks = NULL;
+PFNGLCREATEVERTEXARRAYSPROC __glewCreateVertexArrays = NULL;
+PFNGLDISABLEVERTEXARRAYATTRIBPROC __glewDisableVertexArrayAttrib = NULL;
+PFNGLENABLEVERTEXARRAYATTRIBPROC __glewEnableVertexArrayAttrib = NULL;
+PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC __glewFlushMappedNamedBufferRange = NULL;
+PFNGLGENERATETEXTUREMIPMAPPROC __glewGenerateTextureMipmap = NULL;
+PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC __glewGetCompressedTextureImage = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERI64VPROC __glewGetNamedBufferParameteri64v = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERIVPROC __glewGetNamedBufferParameteriv = NULL;
+PFNGLGETNAMEDBUFFERPOINTERVPROC __glewGetNamedBufferPointerv = NULL;
+PFNGLGETNAMEDBUFFERSUBDATAPROC __glewGetNamedBufferSubData = NULL;
+PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC __glewGetNamedFramebufferAttachmentParameteriv = NULL;
+PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC __glewGetNamedFramebufferParameteriv = NULL;
+PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC __glewGetNamedRenderbufferParameteriv = NULL;
+PFNGLGETQUERYBUFFEROBJECTI64VPROC __glewGetQueryBufferObjecti64v = NULL;
+PFNGLGETQUERYBUFFEROBJECTIVPROC __glewGetQueryBufferObjectiv = NULL;
+PFNGLGETQUERYBUFFEROBJECTUI64VPROC __glewGetQueryBufferObjectui64v = NULL;
+PFNGLGETQUERYBUFFEROBJECTUIVPROC __glewGetQueryBufferObjectuiv = NULL;
+PFNGLGETTEXTUREIMAGEPROC __glewGetTextureImage = NULL;
+PFNGLGETTEXTURELEVELPARAMETERFVPROC __glewGetTextureLevelParameterfv = NULL;
+PFNGLGETTEXTURELEVELPARAMETERIVPROC __glewGetTextureLevelParameteriv = NULL;
+PFNGLGETTEXTUREPARAMETERIIVPROC __glewGetTextureParameterIiv = NULL;
+PFNGLGETTEXTUREPARAMETERIUIVPROC __glewGetTextureParameterIuiv = NULL;
+PFNGLGETTEXTUREPARAMETERFVPROC __glewGetTextureParameterfv = NULL;
+PFNGLGETTEXTUREPARAMETERIVPROC __glewGetTextureParameteriv = NULL;
+PFNGLGETTRANSFORMFEEDBACKI64_VPROC __glewGetTransformFeedbacki64_v = NULL;
+PFNGLGETTRANSFORMFEEDBACKI_VPROC __glewGetTransformFeedbacki_v = NULL;
+PFNGLGETTRANSFORMFEEDBACKIVPROC __glewGetTransformFeedbackiv = NULL;
+PFNGLGETVERTEXARRAYINDEXED64IVPROC __glewGetVertexArrayIndexed64iv = NULL;
+PFNGLGETVERTEXARRAYINDEXEDIVPROC __glewGetVertexArrayIndexediv = NULL;
+PFNGLGETVERTEXARRAYIVPROC __glewGetVertexArrayiv = NULL;
+PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC __glewInvalidateNamedFramebufferData = NULL;
+PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC __glewInvalidateNamedFramebufferSubData = NULL;
+PFNGLMAPNAMEDBUFFERPROC __glewMapNamedBuffer = NULL;
+PFNGLMAPNAMEDBUFFERRANGEPROC __glewMapNamedBufferRange = NULL;
+PFNGLNAMEDBUFFERDATAPROC __glewNamedBufferData = NULL;
+PFNGLNAMEDBUFFERSTORAGEPROC __glewNamedBufferStorage = NULL;
+PFNGLNAMEDBUFFERSUBDATAPROC __glewNamedBufferSubData = NULL;
+PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC __glewNamedFramebufferDrawBuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC __glewNamedFramebufferDrawBuffers = NULL;
+PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC __glewNamedFramebufferParameteri = NULL;
+PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC __glewNamedFramebufferReadBuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC __glewNamedFramebufferRenderbuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTUREPROC __glewNamedFramebufferTexture = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC __glewNamedFramebufferTextureLayer = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEPROC __glewNamedRenderbufferStorage = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC __glewNamedRenderbufferStorageMultisample = NULL;
+PFNGLTEXTUREBUFFERPROC __glewTextureBuffer = NULL;
+PFNGLTEXTUREBUFFERRANGEPROC __glewTextureBufferRange = NULL;
+PFNGLTEXTUREPARAMETERIIVPROC __glewTextureParameterIiv = NULL;
+PFNGLTEXTUREPARAMETERIUIVPROC __glewTextureParameterIuiv = NULL;
+PFNGLTEXTUREPARAMETERFPROC __glewTextureParameterf = NULL;
+PFNGLTEXTUREPARAMETERFVPROC __glewTextureParameterfv = NULL;
+PFNGLTEXTUREPARAMETERIPROC __glewTextureParameteri = NULL;
+PFNGLTEXTUREPARAMETERIVPROC __glewTextureParameteriv = NULL;
+PFNGLTEXTURESTORAGE1DPROC __glewTextureStorage1D = NULL;
+PFNGLTEXTURESTORAGE2DPROC __glewTextureStorage2D = NULL;
+PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC __glewTextureStorage2DMultisample = NULL;
+PFNGLTEXTURESTORAGE3DPROC __glewTextureStorage3D = NULL;
+PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC __glewTextureStorage3DMultisample = NULL;
+PFNGLTEXTURESUBIMAGE1DPROC __glewTextureSubImage1D = NULL;
+PFNGLTEXTURESUBIMAGE2DPROC __glewTextureSubImage2D = NULL;
+PFNGLTEXTURESUBIMAGE3DPROC __glewTextureSubImage3D = NULL;
+PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC __glewTransformFeedbackBufferBase = NULL;
+PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC __glewTransformFeedbackBufferRange = NULL;
+PFNGLUNMAPNAMEDBUFFERPROC __glewUnmapNamedBuffer = NULL;
+PFNGLVERTEXARRAYATTRIBBINDINGPROC __glewVertexArrayAttribBinding = NULL;
+PFNGLVERTEXARRAYATTRIBFORMATPROC __glewVertexArrayAttribFormat = NULL;
+PFNGLVERTEXARRAYATTRIBIFORMATPROC __glewVertexArrayAttribIFormat = NULL;
+PFNGLVERTEXARRAYATTRIBLFORMATPROC __glewVertexArrayAttribLFormat = NULL;
+PFNGLVERTEXARRAYBINDINGDIVISORPROC __glewVertexArrayBindingDivisor = NULL;
+PFNGLVERTEXARRAYELEMENTBUFFERPROC __glewVertexArrayElementBuffer = NULL;
+PFNGLVERTEXARRAYVERTEXBUFFERPROC __glewVertexArrayVertexBuffer = NULL;
+PFNGLVERTEXARRAYVERTEXBUFFERSPROC __glewVertexArrayVertexBuffers = NULL;
+
PFNGLDRAWBUFFERSARBPROC __glewDrawBuffersARB = NULL;
PFNGLBLENDEQUATIONSEPARATEIARBPROC __glewBlendEquationSeparateiARB = NULL;
@@ -791,6 +939,9 @@ PFNGLGETPROGRAMBINARYPROC __glewGetProgramBinary = NULL;
PFNGLPROGRAMBINARYPROC __glewProgramBinary = NULL;
PFNGLPROGRAMPARAMETERIPROC __glewProgramParameteri = NULL;
+PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC __glewGetCompressedTextureSubImage = NULL;
+PFNGLGETTEXTURESUBIMAGEPROC __glewGetTextureSubImage = NULL;
+
PFNGLGETUNIFORMDVPROC __glewGetUniformdv = NULL;
PFNGLUNIFORM1DPROC __glewUniform1d = NULL;
PFNGLUNIFORM1DVPROC __glewUniform1dv = NULL;
@@ -810,6 +961,43 @@ PFNGLUNIFORMMATRIX4DVPROC __glewUniformMatrix4dv = NULL;
PFNGLUNIFORMMATRIX4X2DVPROC __glewUniformMatrix4x2dv = NULL;
PFNGLUNIFORMMATRIX4X3DVPROC __glewUniformMatrix4x3dv = NULL;
+PFNGLGETUNIFORMI64VARBPROC __glewGetUniformi64vARB = NULL;
+PFNGLGETUNIFORMUI64VARBPROC __glewGetUniformui64vARB = NULL;
+PFNGLGETNUNIFORMI64VARBPROC __glewGetnUniformi64vARB = NULL;
+PFNGLGETNUNIFORMUI64VARBPROC __glewGetnUniformui64vARB = NULL;
+PFNGLPROGRAMUNIFORM1I64ARBPROC __glewProgramUniform1i64ARB = NULL;
+PFNGLPROGRAMUNIFORM1I64VARBPROC __glewProgramUniform1i64vARB = NULL;
+PFNGLPROGRAMUNIFORM1UI64ARBPROC __glewProgramUniform1ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM1UI64VARBPROC __glewProgramUniform1ui64vARB = NULL;
+PFNGLPROGRAMUNIFORM2I64ARBPROC __glewProgramUniform2i64ARB = NULL;
+PFNGLPROGRAMUNIFORM2I64VARBPROC __glewProgramUniform2i64vARB = NULL;
+PFNGLPROGRAMUNIFORM2UI64ARBPROC __glewProgramUniform2ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM2UI64VARBPROC __glewProgramUniform2ui64vARB = NULL;
+PFNGLPROGRAMUNIFORM3I64ARBPROC __glewProgramUniform3i64ARB = NULL;
+PFNGLPROGRAMUNIFORM3I64VARBPROC __glewProgramUniform3i64vARB = NULL;
+PFNGLPROGRAMUNIFORM3UI64ARBPROC __glewProgramUniform3ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM3UI64VARBPROC __glewProgramUniform3ui64vARB = NULL;
+PFNGLPROGRAMUNIFORM4I64ARBPROC __glewProgramUniform4i64ARB = NULL;
+PFNGLPROGRAMUNIFORM4I64VARBPROC __glewProgramUniform4i64vARB = NULL;
+PFNGLPROGRAMUNIFORM4UI64ARBPROC __glewProgramUniform4ui64ARB = NULL;
+PFNGLPROGRAMUNIFORM4UI64VARBPROC __glewProgramUniform4ui64vARB = NULL;
+PFNGLUNIFORM1I64ARBPROC __glewUniform1i64ARB = NULL;
+PFNGLUNIFORM1I64VARBPROC __glewUniform1i64vARB = NULL;
+PFNGLUNIFORM1UI64ARBPROC __glewUniform1ui64ARB = NULL;
+PFNGLUNIFORM1UI64VARBPROC __glewUniform1ui64vARB = NULL;
+PFNGLUNIFORM2I64ARBPROC __glewUniform2i64ARB = NULL;
+PFNGLUNIFORM2I64VARBPROC __glewUniform2i64vARB = NULL;
+PFNGLUNIFORM2UI64ARBPROC __glewUniform2ui64ARB = NULL;
+PFNGLUNIFORM2UI64VARBPROC __glewUniform2ui64vARB = NULL;
+PFNGLUNIFORM3I64ARBPROC __glewUniform3i64ARB = NULL;
+PFNGLUNIFORM3I64VARBPROC __glewUniform3i64vARB = NULL;
+PFNGLUNIFORM3UI64ARBPROC __glewUniform3ui64ARB = NULL;
+PFNGLUNIFORM3UI64VARBPROC __glewUniform3ui64vARB = NULL;
+PFNGLUNIFORM4I64ARBPROC __glewUniform4i64ARB = NULL;
+PFNGLUNIFORM4I64VARBPROC __glewUniform4i64vARB = NULL;
+PFNGLUNIFORM4UI64ARBPROC __glewUniform4ui64ARB = NULL;
+PFNGLUNIFORM4UI64VARBPROC __glewUniform4ui64vARB = NULL;
+
PFNGLCOLORSUBTABLEPROC __glewColorSubTable = NULL;
PFNGLCOLORTABLEPROC __glewColorTable = NULL;
PFNGLCOLORTABLEPARAMETERFVPROC __glewColorTableParameterfv = NULL;
@@ -926,6 +1114,8 @@ PFNGLGETQUERYOBJECTUIVARBPROC __glewGetQueryObjectuivARB = NULL;
PFNGLGETQUERYIVARBPROC __glewGetQueryivARB = NULL;
PFNGLISQUERYARBPROC __glewIsQueryARB = NULL;
+PFNGLMAXSHADERCOMPILERTHREADSARBPROC __glewMaxShaderCompilerThreadsARB = NULL;
+
PFNGLPOINTPARAMETERFARBPROC __glewPointParameterfARB = NULL;
PFNGLPOINTPARAMETERFVARBPROC __glewPointParameterfvARB = NULL;
@@ -959,6 +1149,9 @@ PFNGLGETNUNIFORMIVARBPROC __glewGetnUniformivARB = NULL;
PFNGLGETNUNIFORMUIVARBPROC __glewGetnUniformuivARB = NULL;
PFNGLREADNPIXELSARBPROC __glewReadnPixelsARB = NULL;
+PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC __glewFramebufferSampleLocationsfvARB = NULL;
+PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC __glewNamedFramebufferSampleLocationsfvARB = NULL;
+
PFNGLMINSAMPLESHADINGARBPROC __glewMinSampleShadingARB = NULL;
PFNGLBINDSAMPLERPROC __glewBindSampler = NULL;
@@ -1100,6 +1293,8 @@ PFNGLGETNAMEDSTRINGIVARBPROC __glewGetNamedStringivARB = NULL;
PFNGLISNAMEDSTRINGARBPROC __glewIsNamedStringARB = NULL;
PFNGLNAMEDSTRINGARBPROC __glewNamedStringARB = NULL;
+PFNGLBUFFERPAGECOMMITMENTARBPROC __glewBufferPageCommitmentARB = NULL;
+
PFNGLTEXPAGECOMMITMENTARBPROC __glewTexPageCommitmentARB = NULL;
PFNGLTEXTUREPAGECOMMITMENTEXTPROC __glewTexturePageCommitmentEXT = NULL;
@@ -1114,6 +1309,8 @@ PFNGLWAITSYNCPROC __glewWaitSync = NULL;
PFNGLPATCHPARAMETERFVPROC __glewPatchParameterfv = NULL;
PFNGLPATCHPARAMETERIPROC __glewPatchParameteri = NULL;
+PFNGLTEXTUREBARRIERPROC __glewTextureBarrier = NULL;
+
PFNGLTEXBUFFERARBPROC __glewTexBufferARB = NULL;
PFNGLTEXBUFFERRANGEPROC __glewTexBufferRange = NULL;
@@ -1199,6 +1396,12 @@ PFNGLVERTEXATTRIBL4DVPROC __glewVertexAttribL4dv = NULL;
PFNGLVERTEXATTRIBLPOINTERPROC __glewVertexAttribLPointer = NULL;
PFNGLBINDVERTEXBUFFERPROC __glewBindVertexBuffer = NULL;
+PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC __glewVertexArrayBindVertexBufferEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC __glewVertexArrayVertexAttribBindingEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC __glewVertexArrayVertexAttribFormatEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC __glewVertexArrayVertexAttribIFormatEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC __glewVertexArrayVertexAttribLFormatEXT = NULL;
+PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC __glewVertexArrayVertexBindingDivisorEXT = NULL;
PFNGLVERTEXATTRIBBINDINGPROC __glewVertexAttribBinding = NULL;
PFNGLVERTEXATTRIBFORMATPROC __glewVertexAttribFormat = NULL;
PFNGLVERTEXATTRIBIFORMATPROC __glewVertexAttribIFormat = NULL;
@@ -1504,6 +1707,9 @@ PFNGLCOPYTEXSUBIMAGE3DEXTPROC __glewCopyTexSubImage3DEXT = NULL;
PFNGLCULLPARAMETERDVEXTPROC __glewCullParameterdvEXT = NULL;
PFNGLCULLPARAMETERFVEXTPROC __glewCullParameterfvEXT = NULL;
+PFNGLGETOBJECTLABELEXTPROC __glewGetObjectLabelEXT = NULL;
+PFNGLLABELOBJECTEXTPROC __glewLabelObjectEXT = NULL;
+
PFNGLINSERTEVENTMARKEREXTPROC __glewInsertEventMarkerEXT = NULL;
PFNGLPOPGROUPMARKEREXTPROC __glewPopGroupMarkerEXT = NULL;
PFNGLPUSHGROUPMARKEREXTPROC __glewPushGroupMarkerEXT = NULL;
@@ -1720,6 +1926,7 @@ PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC __glewVertexArrayMultiTexCoordOffsetE
PFNGLVERTEXARRAYNORMALOFFSETEXTPROC __glewVertexArrayNormalOffsetEXT = NULL;
PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC __glewVertexArraySecondaryColorOffsetEXT = NULL;
PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC __glewVertexArrayTexCoordOffsetEXT = NULL;
+PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC __glewVertexArrayVertexAttribDivisorEXT = NULL;
PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC __glewVertexArrayVertexAttribIOffsetEXT = NULL;
PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC __glewVertexArrayVertexAttribOffsetEXT = NULL;
PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC __glewVertexArrayVertexOffsetEXT = NULL;
@@ -1867,8 +2074,15 @@ PFNGLPOINTPARAMETERFVEXTPROC __glewPointParameterfvEXT = NULL;
PFNGLPOLYGONOFFSETEXTPROC __glewPolygonOffsetEXT = NULL;
+PFNGLPOLYGONOFFSETCLAMPEXTPROC __glewPolygonOffsetClampEXT = NULL;
+
PFNGLPROVOKINGVERTEXEXTPROC __glewProvokingVertexEXT = NULL;
+PFNGLCOVERAGEMODULATIONNVPROC __glewCoverageModulationNV = NULL;
+PFNGLCOVERAGEMODULATIONTABLENVPROC __glewCoverageModulationTableNV = NULL;
+PFNGLGETCOVERAGEMODULATIONTABLENVPROC __glewGetCoverageModulationTableNV = NULL;
+PFNGLRASTERSAMPLESEXTPROC __glewRasterSamplesEXT = NULL;
+
PFNGLBEGINSCENEEXTPROC __glewBeginSceneEXT = NULL;
PFNGLENDSCENEEXTPROC __glewEndSceneEXT = NULL;
@@ -2038,9 +2252,22 @@ PFNGLNORMALPOINTERVINTELPROC __glewNormalPointervINTEL = NULL;
PFNGLTEXCOORDPOINTERVINTELPROC __glewTexCoordPointervINTEL = NULL;
PFNGLVERTEXPOINTERVINTELPROC __glewVertexPointervINTEL = NULL;
+PFNGLBEGINPERFQUERYINTELPROC __glewBeginPerfQueryINTEL = NULL;
+PFNGLCREATEPERFQUERYINTELPROC __glewCreatePerfQueryINTEL = NULL;
+PFNGLDELETEPERFQUERYINTELPROC __glewDeletePerfQueryINTEL = NULL;
+PFNGLENDPERFQUERYINTELPROC __glewEndPerfQueryINTEL = NULL;
+PFNGLGETFIRSTPERFQUERYIDINTELPROC __glewGetFirstPerfQueryIdINTEL = NULL;
+PFNGLGETNEXTPERFQUERYIDINTELPROC __glewGetNextPerfQueryIdINTEL = NULL;
+PFNGLGETPERFCOUNTERINFOINTELPROC __glewGetPerfCounterInfoINTEL = NULL;
+PFNGLGETPERFQUERYDATAINTELPROC __glewGetPerfQueryDataINTEL = NULL;
+PFNGLGETPERFQUERYIDBYNAMEINTELPROC __glewGetPerfQueryIdByNameINTEL = NULL;
+PFNGLGETPERFQUERYINFOINTELPROC __glewGetPerfQueryInfoINTEL = NULL;
+
PFNGLTEXSCISSORFUNCINTELPROC __glewTexScissorFuncINTEL = NULL;
PFNGLTEXSCISSORINTELPROC __glewTexScissorINTEL = NULL;
+PFNGLBLENDBARRIERKHRPROC __glewBlendBarrierKHR = NULL;
+
PFNGLDEBUGMESSAGECALLBACKPROC __glewDebugMessageCallback = NULL;
PFNGLDEBUGMESSAGECONTROLPROC __glewDebugMessageControl = NULL;
PFNGLDEBUGMESSAGEINSERTPROC __glewDebugMessageInsert = NULL;
@@ -2052,6 +2279,11 @@ PFNGLOBJECTPTRLABELPROC __glewObjectPtrLabel = NULL;
PFNGLPOPDEBUGGROUPPROC __glewPopDebugGroup = NULL;
PFNGLPUSHDEBUGGROUPPROC __glewPushDebugGroup = NULL;
+PFNGLGETNUNIFORMFVPROC __glewGetnUniformfv = NULL;
+PFNGLGETNUNIFORMIVPROC __glewGetnUniformiv = NULL;
+PFNGLGETNUNIFORMUIVPROC __glewGetnUniformuiv = NULL;
+PFNGLREADNPIXELSPROC __glewReadnPixels = NULL;
+
PFNGLBUFFERREGIONENABLEDPROC __glewBufferRegionEnabled = NULL;
PFNGLDELETEBUFFERREGIONPROC __glewDeleteBufferRegion = NULL;
PFNGLDRAWBUFFERREGIONPROC __glewDrawBufferRegion = NULL;
@@ -2091,6 +2323,9 @@ PFNGLENDCONDITIONALRENDERNVXPROC __glewEndConditionalRenderNVX = NULL;
PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC __glewMultiDrawArraysIndirectBindlessNV = NULL;
PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC __glewMultiDrawElementsIndirectBindlessNV = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC __glewMultiDrawArraysIndirectBindlessCountNV = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC __glewMultiDrawElementsIndirectBindlessCountNV = NULL;
+
PFNGLGETIMAGEHANDLENVPROC __glewGetImageHandleNV = NULL;
PFNGLGETTEXTUREHANDLENVPROC __glewGetTextureHandleNV = NULL;
PFNGLGETTEXTURESAMPLERHANDLENVPROC __glewGetTextureSamplerHandleNV = NULL;
@@ -2111,6 +2346,10 @@ PFNGLBLENDPARAMETERINVPROC __glewBlendParameteriNV = NULL;
PFNGLBEGINCONDITIONALRENDERNVPROC __glewBeginConditionalRenderNV = NULL;
PFNGLENDCONDITIONALRENDERNVPROC __glewEndConditionalRenderNV = NULL;
+PFNGLSUBPIXELPRECISIONBIASNVPROC __glewSubpixelPrecisionBiasNV = NULL;
+
+PFNGLCONSERVATIVERASTERPARAMETERFNVPROC __glewConservativeRasterParameterfNV = NULL;
+
PFNGLCOPYIMAGESUBDATANVPROC __glewCopyImageSubDataNV = NULL;
PFNGLCLEARDEPTHDNVPROC __glewClearDepthdNV = NULL;
@@ -2141,6 +2380,8 @@ PFNGLISFENCENVPROC __glewIsFenceNV = NULL;
PFNGLSETFENCENVPROC __glewSetFenceNV = NULL;
PFNGLTESTFENCENVPROC __glewTestFenceNV = NULL;
+PFNGLFRAGMENTCOVERAGECOLORNVPROC __glewFragmentCoverageColorNV = NULL;
+
PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC __glewGetProgramNamedParameterdvNV = NULL;
PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC __glewGetProgramNamedParameterfvNV = NULL;
PFNGLPROGRAMNAMEDPARAMETER4DNVPROC __glewProgramNamedParameter4dNV = NULL;
@@ -2247,6 +2488,8 @@ PFNGLVERTEXATTRIBS4HVNVPROC __glewVertexAttribs4hvNV = NULL;
PFNGLVERTEXWEIGHTHNVPROC __glewVertexWeighthNV = NULL;
PFNGLVERTEXWEIGHTHVNVPROC __glewVertexWeighthvNV = NULL;
+PFNGLGETINTERNALFORMATSAMPLEIVNVPROC __glewGetInternalformatSampleivNV = NULL;
+
PFNGLBEGINOCCLUSIONQUERYNVPROC __glewBeginOcclusionQueryNV = NULL;
PFNGLDELETEOCCLUSIONQUERIESNVPROC __glewDeleteOcclusionQueriesNV = NULL;
PFNGLENDOCCLUSIONQUERYNVPROC __glewEndOcclusionQueryNV = NULL;
@@ -2279,18 +2522,28 @@ PFNGLGETPATHPARAMETERIVNVPROC __glewGetPathParameterivNV = NULL;
PFNGLGETPATHSPACINGNVPROC __glewGetPathSpacingNV = NULL;
PFNGLGETPATHTEXGENFVNVPROC __glewGetPathTexGenfvNV = NULL;
PFNGLGETPATHTEXGENIVNVPROC __glewGetPathTexGenivNV = NULL;
+PFNGLGETPROGRAMRESOURCEFVNVPROC __glewGetProgramResourcefvNV = NULL;
PFNGLINTERPOLATEPATHSNVPROC __glewInterpolatePathsNV = NULL;
PFNGLISPATHNVPROC __glewIsPathNV = NULL;
PFNGLISPOINTINFILLPATHNVPROC __glewIsPointInFillPathNV = NULL;
PFNGLISPOINTINSTROKEPATHNVPROC __glewIsPointInStrokePathNV = NULL;
+PFNGLMATRIXLOAD3X2FNVPROC __glewMatrixLoad3x2fNV = NULL;
+PFNGLMATRIXLOAD3X3FNVPROC __glewMatrixLoad3x3fNV = NULL;
+PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC __glewMatrixLoadTranspose3x3fNV = NULL;
+PFNGLMATRIXMULT3X2FNVPROC __glewMatrixMult3x2fNV = NULL;
+PFNGLMATRIXMULT3X3FNVPROC __glewMatrixMult3x3fNV = NULL;
+PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC __glewMatrixMultTranspose3x3fNV = NULL;
PFNGLPATHCOLORGENNVPROC __glewPathColorGenNV = NULL;
PFNGLPATHCOMMANDSNVPROC __glewPathCommandsNV = NULL;
PFNGLPATHCOORDSNVPROC __glewPathCoordsNV = NULL;
PFNGLPATHCOVERDEPTHFUNCNVPROC __glewPathCoverDepthFuncNV = NULL;
PFNGLPATHDASHARRAYNVPROC __glewPathDashArrayNV = NULL;
PFNGLPATHFOGGENNVPROC __glewPathFogGenNV = NULL;
+PFNGLPATHGLYPHINDEXARRAYNVPROC __glewPathGlyphIndexArrayNV = NULL;
+PFNGLPATHGLYPHINDEXRANGENVPROC __glewPathGlyphIndexRangeNV = NULL;
PFNGLPATHGLYPHRANGENVPROC __glewPathGlyphRangeNV = NULL;
PFNGLPATHGLYPHSNVPROC __glewPathGlyphsNV = NULL;
+PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC __glewPathMemoryGlyphIndexArrayNV = NULL;
PFNGLPATHPARAMETERFNVPROC __glewPathParameterfNV = NULL;
PFNGLPATHPARAMETERFVNVPROC __glewPathParameterfvNV = NULL;
PFNGLPATHPARAMETERINVPROC __glewPathParameteriNV = NULL;
@@ -2302,10 +2555,15 @@ PFNGLPATHSUBCOMMANDSNVPROC __glewPathSubCommandsNV = NULL;
PFNGLPATHSUBCOORDSNVPROC __glewPathSubCoordsNV = NULL;
PFNGLPATHTEXGENNVPROC __glewPathTexGenNV = NULL;
PFNGLPOINTALONGPATHNVPROC __glewPointAlongPathNV = NULL;
+PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC __glewProgramPathFragmentInputGenNV = NULL;
PFNGLSTENCILFILLPATHINSTANCEDNVPROC __glewStencilFillPathInstancedNV = NULL;
PFNGLSTENCILFILLPATHNVPROC __glewStencilFillPathNV = NULL;
PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC __glewStencilStrokePathInstancedNV = NULL;
PFNGLSTENCILSTROKEPATHNVPROC __glewStencilStrokePathNV = NULL;
+PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC __glewStencilThenCoverFillPathInstancedNV = NULL;
+PFNGLSTENCILTHENCOVERFILLPATHNVPROC __glewStencilThenCoverFillPathNV = NULL;
+PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC __glewStencilThenCoverStrokePathInstancedNV = NULL;
+PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC __glewStencilThenCoverStrokePathNV = NULL;
PFNGLTRANSFORMPATHNVPROC __glewTransformPathNV = NULL;
PFNGLWEIGHTPATHSNVPROC __glewWeightPathsNV = NULL;
@@ -2342,6 +2600,9 @@ PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC __glewGetFinalCombinerInputParameter
PFNGLCOMBINERSTAGEPARAMETERFVNVPROC __glewCombinerStageParameterfvNV = NULL;
PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC __glewGetCombinerStageParameterfvNV = NULL;
+PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewFramebufferSampleLocationsfvNV = NULL;
+PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC __glewNamedFramebufferSampleLocationsfvNV = NULL;
+
PFNGLGETBUFFERPARAMETERUI64VNVPROC __glewGetBufferParameterui64vNV = NULL;
PFNGLGETINTEGERUI64VNVPROC __glewGetIntegerui64vNV = NULL;
PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC __glewGetNamedBufferParameterui64vNV = NULL;
@@ -2517,6 +2778,8 @@ PFNGLFRUSTUMFOESPROC __glewFrustumfOES = NULL;
PFNGLGETCLIPPLANEFOESPROC __glewGetClipPlanefOES = NULL;
PFNGLORTHOFOESPROC __glewOrthofOES = NULL;
+PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __glewFramebufferTextureMultiviewOVR = NULL;
+
PFNGLALPHAFUNCXPROC __glewAlphaFuncx = NULL;
PFNGLCLEARCOLORXPROC __glewClearColorx = NULL;
PFNGLCLEARDEPTHXPROC __glewClearDepthx = NULL;
@@ -2570,6 +2833,8 @@ PFNGLISSUPPORTEDREGALPROC __glewIsSupportedREGAL = NULL;
PFNGLLOGMESSAGECALLBACKREGALPROC __glewLogMessageCallbackREGAL = NULL;
+PFNGLGETPROCADDRESSREGALPROC __glewGetProcAddressREGAL = NULL;
+
PFNGLDETAILTEXFUNCSGISPROC __glewDetailTexFuncSGIS = NULL;
PFNGLGETDETAILTEXFUNCSGISPROC __glewGetDetailTexFuncSGIS = NULL;
@@ -2723,6 +2988,7 @@ GLboolean __GLEW_VERSION_4_1 = GL_FALSE;
GLboolean __GLEW_VERSION_4_2 = GL_FALSE;
GLboolean __GLEW_VERSION_4_3 = GL_FALSE;
GLboolean __GLEW_VERSION_4_4 = GL_FALSE;
+GLboolean __GLEW_VERSION_4_5 = GL_FALSE;
GLboolean __GLEW_3DFX_multisample = GL_FALSE;
GLboolean __GLEW_3DFX_tbuffer = GL_FALSE;
GLboolean __GLEW_3DFX_texture_compression_FXT1 = GL_FALSE;
@@ -2731,20 +2997,26 @@ GLboolean __GLEW_AMD_conservative_depth = GL_FALSE;
GLboolean __GLEW_AMD_debug_output = GL_FALSE;
GLboolean __GLEW_AMD_depth_clamp_separate = GL_FALSE;
GLboolean __GLEW_AMD_draw_buffers_blend = GL_FALSE;
+GLboolean __GLEW_AMD_gcn_shader = GL_FALSE;
+GLboolean __GLEW_AMD_gpu_shader_int64 = GL_FALSE;
GLboolean __GLEW_AMD_interleaved_elements = GL_FALSE;
GLboolean __GLEW_AMD_multi_draw_indirect = GL_FALSE;
GLboolean __GLEW_AMD_name_gen_delete = GL_FALSE;
+GLboolean __GLEW_AMD_occlusion_query_event = GL_FALSE;
GLboolean __GLEW_AMD_performance_monitor = GL_FALSE;
GLboolean __GLEW_AMD_pinned_memory = GL_FALSE;
GLboolean __GLEW_AMD_query_buffer_object = GL_FALSE;
GLboolean __GLEW_AMD_sample_positions = GL_FALSE;
GLboolean __GLEW_AMD_seamless_cubemap_per_texture = GL_FALSE;
+GLboolean __GLEW_AMD_shader_atomic_counter_ops = GL_FALSE;
GLboolean __GLEW_AMD_shader_stencil_export = GL_FALSE;
+GLboolean __GLEW_AMD_shader_stencil_value_export = GL_FALSE;
GLboolean __GLEW_AMD_shader_trinary_minmax = GL_FALSE;
GLboolean __GLEW_AMD_sparse_texture = GL_FALSE;
GLboolean __GLEW_AMD_stencil_operation_extended = GL_FALSE;
GLboolean __GLEW_AMD_texture_texture4 = GL_FALSE;
GLboolean __GLEW_AMD_transform_feedback3_lines_triangles = GL_FALSE;
+GLboolean __GLEW_AMD_transform_feedback4 = GL_FALSE;
GLboolean __GLEW_AMD_vertex_shader_layer = GL_FALSE;
GLboolean __GLEW_AMD_vertex_shader_tessellator = GL_FALSE;
GLboolean __GLEW_AMD_vertex_shader_viewport_index = GL_FALSE;
@@ -2778,6 +3050,8 @@ GLboolean __GLEW_APPLE_vertex_array_range = GL_FALSE;
GLboolean __GLEW_APPLE_vertex_program_evaluators = GL_FALSE;
GLboolean __GLEW_APPLE_ycbcr_422 = GL_FALSE;
GLboolean __GLEW_ARB_ES2_compatibility = GL_FALSE;
+GLboolean __GLEW_ARB_ES3_1_compatibility = GL_FALSE;
+GLboolean __GLEW_ARB_ES3_2_compatibility = GL_FALSE;
GLboolean __GLEW_ARB_ES3_compatibility = GL_FALSE;
GLboolean __GLEW_ARB_arrays_of_arrays = GL_FALSE;
GLboolean __GLEW_ARB_base_instance = GL_FALSE;
@@ -2787,18 +3061,23 @@ GLboolean __GLEW_ARB_buffer_storage = GL_FALSE;
GLboolean __GLEW_ARB_cl_event = GL_FALSE;
GLboolean __GLEW_ARB_clear_buffer_object = GL_FALSE;
GLboolean __GLEW_ARB_clear_texture = GL_FALSE;
+GLboolean __GLEW_ARB_clip_control = GL_FALSE;
GLboolean __GLEW_ARB_color_buffer_float = GL_FALSE;
GLboolean __GLEW_ARB_compatibility = GL_FALSE;
GLboolean __GLEW_ARB_compressed_texture_pixel_storage = GL_FALSE;
GLboolean __GLEW_ARB_compute_shader = GL_FALSE;
GLboolean __GLEW_ARB_compute_variable_group_size = GL_FALSE;
+GLboolean __GLEW_ARB_conditional_render_inverted = GL_FALSE;
GLboolean __GLEW_ARB_conservative_depth = GL_FALSE;
GLboolean __GLEW_ARB_copy_buffer = GL_FALSE;
GLboolean __GLEW_ARB_copy_image = GL_FALSE;
+GLboolean __GLEW_ARB_cull_distance = GL_FALSE;
GLboolean __GLEW_ARB_debug_output = GL_FALSE;
GLboolean __GLEW_ARB_depth_buffer_float = GL_FALSE;
GLboolean __GLEW_ARB_depth_clamp = GL_FALSE;
GLboolean __GLEW_ARB_depth_texture = GL_FALSE;
+GLboolean __GLEW_ARB_derivative_control = GL_FALSE;
+GLboolean __GLEW_ARB_direct_state_access = GL_FALSE;
GLboolean __GLEW_ARB_draw_buffers = GL_FALSE;
GLboolean __GLEW_ARB_draw_buffers_blend = GL_FALSE;
GLboolean __GLEW_ARB_draw_elements_base_vertex = GL_FALSE;
@@ -2812,13 +3091,16 @@ GLboolean __GLEW_ARB_fragment_layer_viewport = GL_FALSE;
GLboolean __GLEW_ARB_fragment_program = GL_FALSE;
GLboolean __GLEW_ARB_fragment_program_shadow = GL_FALSE;
GLboolean __GLEW_ARB_fragment_shader = GL_FALSE;
+GLboolean __GLEW_ARB_fragment_shader_interlock = GL_FALSE;
GLboolean __GLEW_ARB_framebuffer_no_attachments = GL_FALSE;
GLboolean __GLEW_ARB_framebuffer_object = GL_FALSE;
GLboolean __GLEW_ARB_framebuffer_sRGB = GL_FALSE;
GLboolean __GLEW_ARB_geometry_shader4 = GL_FALSE;
GLboolean __GLEW_ARB_get_program_binary = GL_FALSE;
+GLboolean __GLEW_ARB_get_texture_sub_image = GL_FALSE;
GLboolean __GLEW_ARB_gpu_shader5 = GL_FALSE;
GLboolean __GLEW_ARB_gpu_shader_fp64 = GL_FALSE;
+GLboolean __GLEW_ARB_gpu_shader_int64 = GL_FALSE;
GLboolean __GLEW_ARB_half_float_pixel = GL_FALSE;
GLboolean __GLEW_ARB_half_float_vertex = GL_FALSE;
GLboolean __GLEW_ARB_imaging = GL_FALSE;
@@ -2836,9 +3118,12 @@ GLboolean __GLEW_ARB_multisample = GL_FALSE;
GLboolean __GLEW_ARB_multitexture = GL_FALSE;
GLboolean __GLEW_ARB_occlusion_query = GL_FALSE;
GLboolean __GLEW_ARB_occlusion_query2 = GL_FALSE;
+GLboolean __GLEW_ARB_parallel_shader_compile = GL_FALSE;
+GLboolean __GLEW_ARB_pipeline_statistics_query = GL_FALSE;
GLboolean __GLEW_ARB_pixel_buffer_object = GL_FALSE;
GLboolean __GLEW_ARB_point_parameters = GL_FALSE;
GLboolean __GLEW_ARB_point_sprite = GL_FALSE;
+GLboolean __GLEW_ARB_post_depth_coverage = GL_FALSE;
GLboolean __GLEW_ARB_program_interface_query = GL_FALSE;
GLboolean __GLEW_ARB_provoking_vertex = GL_FALSE;
GLboolean __GLEW_ARB_query_buffer_object = GL_FALSE;
@@ -2846,13 +3131,17 @@ GLboolean __GLEW_ARB_robust_buffer_access_behavior = GL_FALSE;
GLboolean __GLEW_ARB_robustness = GL_FALSE;
GLboolean __GLEW_ARB_robustness_application_isolation = GL_FALSE;
GLboolean __GLEW_ARB_robustness_share_group_isolation = GL_FALSE;
+GLboolean __GLEW_ARB_sample_locations = GL_FALSE;
GLboolean __GLEW_ARB_sample_shading = GL_FALSE;
GLboolean __GLEW_ARB_sampler_objects = GL_FALSE;
GLboolean __GLEW_ARB_seamless_cube_map = GL_FALSE;
GLboolean __GLEW_ARB_seamless_cubemap_per_texture = GL_FALSE;
GLboolean __GLEW_ARB_separate_shader_objects = GL_FALSE;
+GLboolean __GLEW_ARB_shader_atomic_counter_ops = GL_FALSE;
GLboolean __GLEW_ARB_shader_atomic_counters = GL_FALSE;
+GLboolean __GLEW_ARB_shader_ballot = GL_FALSE;
GLboolean __GLEW_ARB_shader_bit_encoding = GL_FALSE;
+GLboolean __GLEW_ARB_shader_clock = GL_FALSE;
GLboolean __GLEW_ARB_shader_draw_parameters = GL_FALSE;
GLboolean __GLEW_ARB_shader_group_vote = GL_FALSE;
GLboolean __GLEW_ARB_shader_image_load_store = GL_FALSE;
@@ -2862,17 +3151,23 @@ GLboolean __GLEW_ARB_shader_precision = GL_FALSE;
GLboolean __GLEW_ARB_shader_stencil_export = GL_FALSE;
GLboolean __GLEW_ARB_shader_storage_buffer_object = GL_FALSE;
GLboolean __GLEW_ARB_shader_subroutine = GL_FALSE;
+GLboolean __GLEW_ARB_shader_texture_image_samples = GL_FALSE;
GLboolean __GLEW_ARB_shader_texture_lod = GL_FALSE;
+GLboolean __GLEW_ARB_shader_viewport_layer_array = GL_FALSE;
GLboolean __GLEW_ARB_shading_language_100 = GL_FALSE;
GLboolean __GLEW_ARB_shading_language_420pack = GL_FALSE;
GLboolean __GLEW_ARB_shading_language_include = GL_FALSE;
GLboolean __GLEW_ARB_shading_language_packing = GL_FALSE;
GLboolean __GLEW_ARB_shadow = GL_FALSE;
GLboolean __GLEW_ARB_shadow_ambient = GL_FALSE;
+GLboolean __GLEW_ARB_sparse_buffer = GL_FALSE;
GLboolean __GLEW_ARB_sparse_texture = GL_FALSE;
+GLboolean __GLEW_ARB_sparse_texture2 = GL_FALSE;
+GLboolean __GLEW_ARB_sparse_texture_clamp = GL_FALSE;
GLboolean __GLEW_ARB_stencil_texturing = GL_FALSE;
GLboolean __GLEW_ARB_sync = GL_FALSE;
GLboolean __GLEW_ARB_tessellation_shader = GL_FALSE;
+GLboolean __GLEW_ARB_texture_barrier = GL_FALSE;
GLboolean __GLEW_ARB_texture_border_clamp = GL_FALSE;
GLboolean __GLEW_ARB_texture_buffer_object = GL_FALSE;
GLboolean __GLEW_ARB_texture_buffer_object_rgb32 = GL_FALSE;
@@ -2886,6 +3181,7 @@ GLboolean __GLEW_ARB_texture_env_add = GL_FALSE;
GLboolean __GLEW_ARB_texture_env_combine = GL_FALSE;
GLboolean __GLEW_ARB_texture_env_crossbar = GL_FALSE;
GLboolean __GLEW_ARB_texture_env_dot3 = GL_FALSE;
+GLboolean __GLEW_ARB_texture_filter_minmax = GL_FALSE;
GLboolean __GLEW_ARB_texture_float = GL_FALSE;
GLboolean __GLEW_ARB_texture_gather = GL_FALSE;
GLboolean __GLEW_ARB_texture_mirror_clamp_to_edge = GL_FALSE;
@@ -2906,6 +3202,7 @@ GLboolean __GLEW_ARB_timer_query = GL_FALSE;
GLboolean __GLEW_ARB_transform_feedback2 = GL_FALSE;
GLboolean __GLEW_ARB_transform_feedback3 = GL_FALSE;
GLboolean __GLEW_ARB_transform_feedback_instanced = GL_FALSE;
+GLboolean __GLEW_ARB_transform_feedback_overflow_query = GL_FALSE;
GLboolean __GLEW_ARB_transpose_matrix = GL_FALSE;
GLboolean __GLEW_ARB_uniform_buffer_object = GL_FALSE;
GLboolean __GLEW_ARB_vertex_array_bgra = GL_FALSE;
@@ -2960,6 +3257,7 @@ GLboolean __GLEW_EXT_convolution = GL_FALSE;
GLboolean __GLEW_EXT_coordinate_frame = GL_FALSE;
GLboolean __GLEW_EXT_copy_texture = GL_FALSE;
GLboolean __GLEW_EXT_cull_vertex = GL_FALSE;
+GLboolean __GLEW_EXT_debug_label = GL_FALSE;
GLboolean __GLEW_EXT_debug_marker = GL_FALSE;
GLboolean __GLEW_EXT_depth_bounds_test = GL_FALSE;
GLboolean __GLEW_EXT_direct_state_access = GL_FALSE;
@@ -2994,15 +3292,21 @@ GLboolean __GLEW_EXT_pixel_transform = GL_FALSE;
GLboolean __GLEW_EXT_pixel_transform_color_table = GL_FALSE;
GLboolean __GLEW_EXT_point_parameters = GL_FALSE;
GLboolean __GLEW_EXT_polygon_offset = GL_FALSE;
+GLboolean __GLEW_EXT_polygon_offset_clamp = GL_FALSE;
+GLboolean __GLEW_EXT_post_depth_coverage = GL_FALSE;
GLboolean __GLEW_EXT_provoking_vertex = GL_FALSE;
+GLboolean __GLEW_EXT_raster_multisample = GL_FALSE;
GLboolean __GLEW_EXT_rescale_normal = GL_FALSE;
GLboolean __GLEW_EXT_scene_marker = GL_FALSE;
GLboolean __GLEW_EXT_secondary_color = GL_FALSE;
GLboolean __GLEW_EXT_separate_shader_objects = GL_FALSE;
GLboolean __GLEW_EXT_separate_specular_color = GL_FALSE;
+GLboolean __GLEW_EXT_shader_image_load_formatted = GL_FALSE;
GLboolean __GLEW_EXT_shader_image_load_store = GL_FALSE;
+GLboolean __GLEW_EXT_shader_integer_mix = GL_FALSE;
GLboolean __GLEW_EXT_shadow_funcs = GL_FALSE;
GLboolean __GLEW_EXT_shared_texture_palette = GL_FALSE;
+GLboolean __GLEW_EXT_sparse_texture2 = GL_FALSE;
GLboolean __GLEW_EXT_stencil_clear_tag = GL_FALSE;
GLboolean __GLEW_EXT_stencil_two_side = GL_FALSE;
GLboolean __GLEW_EXT_stencil_wrap = GL_FALSE;
@@ -3022,6 +3326,7 @@ GLboolean __GLEW_EXT_texture_env_add = GL_FALSE;
GLboolean __GLEW_EXT_texture_env_combine = GL_FALSE;
GLboolean __GLEW_EXT_texture_env_dot3 = GL_FALSE;
GLboolean __GLEW_EXT_texture_filter_anisotropic = GL_FALSE;
+GLboolean __GLEW_EXT_texture_filter_minmax = GL_FALSE;
GLboolean __GLEW_EXT_texture_integer = GL_FALSE;
GLboolean __GLEW_EXT_texture_lod_bias = GL_FALSE;
GLboolean __GLEW_EXT_texture_mirror_clamp = GL_FALSE;
@@ -3055,10 +3360,20 @@ GLboolean __GLEW_IBM_texture_mirrored_repeat = GL_FALSE;
GLboolean __GLEW_IBM_vertex_array_lists = GL_FALSE;
GLboolean __GLEW_INGR_color_clamp = GL_FALSE;
GLboolean __GLEW_INGR_interlace_read = GL_FALSE;
+GLboolean __GLEW_INTEL_fragment_shader_ordering = GL_FALSE;
+GLboolean __GLEW_INTEL_framebuffer_CMAA = GL_FALSE;
GLboolean __GLEW_INTEL_map_texture = GL_FALSE;
GLboolean __GLEW_INTEL_parallel_arrays = GL_FALSE;
+GLboolean __GLEW_INTEL_performance_query = GL_FALSE;
GLboolean __GLEW_INTEL_texture_scissor = GL_FALSE;
+GLboolean __GLEW_KHR_blend_equation_advanced = GL_FALSE;
+GLboolean __GLEW_KHR_blend_equation_advanced_coherent = GL_FALSE;
+GLboolean __GLEW_KHR_context_flush_control = GL_FALSE;
GLboolean __GLEW_KHR_debug = GL_FALSE;
+GLboolean __GLEW_KHR_no_error = GL_FALSE;
+GLboolean __GLEW_KHR_robust_buffer_access_behavior = GL_FALSE;
+GLboolean __GLEW_KHR_robustness = GL_FALSE;
+GLboolean __GLEW_KHR_texture_compression_astc_hdr = GL_FALSE;
GLboolean __GLEW_KHR_texture_compression_astc_ldr = GL_FALSE;
GLboolean __GLEW_KTX_buffer_region = GL_FALSE;
GLboolean __GLEW_MESAX_texture_stack = GL_FALSE;
@@ -3069,12 +3384,15 @@ GLboolean __GLEW_MESA_ycbcr_texture = GL_FALSE;
GLboolean __GLEW_NVX_conditional_render = GL_FALSE;
GLboolean __GLEW_NVX_gpu_memory_info = GL_FALSE;
GLboolean __GLEW_NV_bindless_multi_draw_indirect = GL_FALSE;
+GLboolean __GLEW_NV_bindless_multi_draw_indirect_count = GL_FALSE;
GLboolean __GLEW_NV_bindless_texture = GL_FALSE;
GLboolean __GLEW_NV_blend_equation_advanced = GL_FALSE;
GLboolean __GLEW_NV_blend_equation_advanced_coherent = GL_FALSE;
GLboolean __GLEW_NV_blend_square = GL_FALSE;
GLboolean __GLEW_NV_compute_program5 = GL_FALSE;
GLboolean __GLEW_NV_conditional_render = GL_FALSE;
+GLboolean __GLEW_NV_conservative_raster = GL_FALSE;
+GLboolean __GLEW_NV_conservative_raster_dilate = GL_FALSE;
GLboolean __GLEW_NV_copy_depth_to_color = GL_FALSE;
GLboolean __GLEW_NV_copy_image = GL_FALSE;
GLboolean __GLEW_NV_deep_texture3D = GL_FALSE;
@@ -3085,21 +3403,27 @@ GLboolean __GLEW_NV_draw_texture = GL_FALSE;
GLboolean __GLEW_NV_evaluators = GL_FALSE;
GLboolean __GLEW_NV_explicit_multisample = GL_FALSE;
GLboolean __GLEW_NV_fence = GL_FALSE;
+GLboolean __GLEW_NV_fill_rectangle = GL_FALSE;
GLboolean __GLEW_NV_float_buffer = GL_FALSE;
GLboolean __GLEW_NV_fog_distance = GL_FALSE;
+GLboolean __GLEW_NV_fragment_coverage_to_color = GL_FALSE;
GLboolean __GLEW_NV_fragment_program = GL_FALSE;
GLboolean __GLEW_NV_fragment_program2 = GL_FALSE;
GLboolean __GLEW_NV_fragment_program4 = GL_FALSE;
GLboolean __GLEW_NV_fragment_program_option = GL_FALSE;
+GLboolean __GLEW_NV_fragment_shader_interlock = GL_FALSE;
+GLboolean __GLEW_NV_framebuffer_mixed_samples = GL_FALSE;
GLboolean __GLEW_NV_framebuffer_multisample_coverage = GL_FALSE;
GLboolean __GLEW_NV_geometry_program4 = GL_FALSE;
GLboolean __GLEW_NV_geometry_shader4 = GL_FALSE;
+GLboolean __GLEW_NV_geometry_shader_passthrough = GL_FALSE;
GLboolean __GLEW_NV_gpu_program4 = GL_FALSE;
GLboolean __GLEW_NV_gpu_program5 = GL_FALSE;
GLboolean __GLEW_NV_gpu_program5_mem_extended = GL_FALSE;
GLboolean __GLEW_NV_gpu_program_fp64 = GL_FALSE;
GLboolean __GLEW_NV_gpu_shader5 = GL_FALSE;
GLboolean __GLEW_NV_half_float = GL_FALSE;
+GLboolean __GLEW_NV_internalformat_sample_query = GL_FALSE;
GLboolean __GLEW_NV_light_max_exponent = GL_FALSE;
GLboolean __GLEW_NV_multisample_coverage = GL_FALSE;
GLboolean __GLEW_NV_multisample_filter_hint = GL_FALSE;
@@ -3108,16 +3432,23 @@ GLboolean __GLEW_NV_packed_depth_stencil = GL_FALSE;
GLboolean __GLEW_NV_parameter_buffer_object = GL_FALSE;
GLboolean __GLEW_NV_parameter_buffer_object2 = GL_FALSE;
GLboolean __GLEW_NV_path_rendering = GL_FALSE;
+GLboolean __GLEW_NV_path_rendering_shared_edge = GL_FALSE;
GLboolean __GLEW_NV_pixel_data_range = GL_FALSE;
GLboolean __GLEW_NV_point_sprite = GL_FALSE;
GLboolean __GLEW_NV_present_video = GL_FALSE;
GLboolean __GLEW_NV_primitive_restart = GL_FALSE;
GLboolean __GLEW_NV_register_combiners = GL_FALSE;
GLboolean __GLEW_NV_register_combiners2 = GL_FALSE;
+GLboolean __GLEW_NV_sample_locations = GL_FALSE;
+GLboolean __GLEW_NV_sample_mask_override_coverage = GL_FALSE;
GLboolean __GLEW_NV_shader_atomic_counters = GL_FALSE;
GLboolean __GLEW_NV_shader_atomic_float = GL_FALSE;
+GLboolean __GLEW_NV_shader_atomic_fp16_vector = GL_FALSE;
+GLboolean __GLEW_NV_shader_atomic_int64 = GL_FALSE;
GLboolean __GLEW_NV_shader_buffer_load = GL_FALSE;
GLboolean __GLEW_NV_shader_storage_buffer_object = GL_FALSE;
+GLboolean __GLEW_NV_shader_thread_group = GL_FALSE;
+GLboolean __GLEW_NV_shader_thread_shuffle = GL_FALSE;
GLboolean __GLEW_NV_tessellation_program5 = GL_FALSE;
GLboolean __GLEW_NV_texgen_emboss = GL_FALSE;
GLboolean __GLEW_NV_texgen_reflection = GL_FALSE;
@@ -3132,6 +3463,7 @@ GLboolean __GLEW_NV_texture_shader2 = GL_FALSE;
GLboolean __GLEW_NV_texture_shader3 = GL_FALSE;
GLboolean __GLEW_NV_transform_feedback = GL_FALSE;
GLboolean __GLEW_NV_transform_feedback2 = GL_FALSE;
+GLboolean __GLEW_NV_uniform_buffer_unified_memory = GL_FALSE;
GLboolean __GLEW_NV_vdpau_interop = GL_FALSE;
GLboolean __GLEW_NV_vertex_array_range = GL_FALSE;
GLboolean __GLEW_NV_vertex_array_range2 = GL_FALSE;
@@ -3144,6 +3476,7 @@ GLboolean __GLEW_NV_vertex_program2_option = GL_FALSE;
GLboolean __GLEW_NV_vertex_program3 = GL_FALSE;
GLboolean __GLEW_NV_vertex_program4 = GL_FALSE;
GLboolean __GLEW_NV_video_capture = GL_FALSE;
+GLboolean __GLEW_NV_viewport_array2 = GL_FALSE;
GLboolean __GLEW_OES_byte_coordinates = GL_FALSE;
GLboolean __GLEW_OES_compressed_paletted_texture = GL_FALSE;
GLboolean __GLEW_OES_read_format = GL_FALSE;
@@ -3151,6 +3484,8 @@ GLboolean __GLEW_OES_single_precision = GL_FALSE;
GLboolean __GLEW_OML_interlace = GL_FALSE;
GLboolean __GLEW_OML_resample = GL_FALSE;
GLboolean __GLEW_OML_subsample = GL_FALSE;
+GLboolean __GLEW_OVR_multiview = GL_FALSE;
+GLboolean __GLEW_OVR_multiview2 = GL_FALSE;
GLboolean __GLEW_PGI_misc_hints = GL_FALSE;
GLboolean __GLEW_PGI_vertex_hints = GL_FALSE;
GLboolean __GLEW_REGAL_ES1_0_compatibility = GL_FALSE;
@@ -3159,6 +3494,7 @@ GLboolean __GLEW_REGAL_enable = GL_FALSE;
GLboolean __GLEW_REGAL_error_string = GL_FALSE;
GLboolean __GLEW_REGAL_extension_query = GL_FALSE;
GLboolean __GLEW_REGAL_log = GL_FALSE;
+GLboolean __GLEW_REGAL_proc_address = GL_FALSE;
GLboolean __GLEW_REND_screen_coordinates = GL_FALSE;
GLboolean __GLEW_S3_s3tc = GL_FALSE;
GLboolean __GLEW_SGIS_color_range = GL_FALSE;
@@ -3240,10 +3576,6 @@ static GLboolean _glewInit_GL_VERSION_1_2 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_VERSION_1_2 */
-#ifdef GL_VERSION_1_2_1
-
-#endif /* GL_VERSION_1_2_1 */
-
#ifdef GL_VERSION_1_3
static GLboolean _glewInit_GL_VERSION_1_3 (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3643,25 +3975,21 @@ static GLboolean _glewInit_GL_VERSION_4_0 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_VERSION_4_0 */
-#ifdef GL_VERSION_4_1
-
-#endif /* GL_VERSION_4_1 */
-
-#ifdef GL_VERSION_4_2
-
-#endif /* GL_VERSION_4_2 */
-
-#ifdef GL_VERSION_4_3
-
-#endif /* GL_VERSION_4_3 */
+#ifdef GL_VERSION_4_5
-#ifdef GL_VERSION_4_4
+static GLboolean _glewInit_GL_VERSION_4_5 (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#endif /* GL_VERSION_4_4 */
+ r = ((glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)glewGetProcAddress((const GLubyte*)"glGetGraphicsResetStatus")) == NULL) || r;
+ r = ((glGetnCompressedTexImage = (PFNGLGETNCOMPRESSEDTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetnCompressedTexImage")) == NULL) || r;
+ r = ((glGetnTexImage = (PFNGLGETNTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetnTexImage")) == NULL) || r;
+ r = ((glGetnUniformdv = (PFNGLGETNUNIFORMDVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformdv")) == NULL) || r;
-#ifdef GL_3DFX_multisample
+ return r;
+}
-#endif /* GL_3DFX_multisample */
+#endif /* GL_VERSION_4_5 */
#ifdef GL_3DFX_tbuffer
@@ -3676,18 +4004,6 @@ static GLboolean _glewInit_GL_3DFX_tbuffer (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_3DFX_tbuffer */
-#ifdef GL_3DFX_texture_compression_FXT1
-
-#endif /* GL_3DFX_texture_compression_FXT1 */
-
-#ifdef GL_AMD_blend_minmax_factor
-
-#endif /* GL_AMD_blend_minmax_factor */
-
-#ifdef GL_AMD_conservative_depth
-
-#endif /* GL_AMD_conservative_depth */
-
#ifdef GL_AMD_debug_output
static GLboolean _glewInit_GL_AMD_debug_output (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3704,10 +4020,6 @@ static GLboolean _glewInit_GL_AMD_debug_output (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_AMD_debug_output */
-#ifdef GL_AMD_depth_clamp_separate
-
-#endif /* GL_AMD_depth_clamp_separate */
-
#ifdef GL_AMD_draw_buffers_blend
static GLboolean _glewInit_GL_AMD_draw_buffers_blend (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3766,6 +4078,19 @@ static GLboolean _glewInit_GL_AMD_name_gen_delete (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_AMD_name_gen_delete */
+#ifdef GL_AMD_occlusion_query_event
+
+static GLboolean _glewInit_GL_AMD_occlusion_query_event (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glQueryObjectParameteruiAMD = (PFNGLQUERYOBJECTPARAMETERUIAMDPROC)glewGetProcAddress((const GLubyte*)"glQueryObjectParameteruiAMD")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_AMD_occlusion_query_event */
+
#ifdef GL_AMD_performance_monitor
static GLboolean _glewInit_GL_AMD_performance_monitor (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3789,14 +4114,6 @@ static GLboolean _glewInit_GL_AMD_performance_monitor (GLEW_CONTEXT_ARG_DEF_INIT
#endif /* GL_AMD_performance_monitor */
-#ifdef GL_AMD_pinned_memory
-
-#endif /* GL_AMD_pinned_memory */
-
-#ifdef GL_AMD_query_buffer_object
-
-#endif /* GL_AMD_query_buffer_object */
-
#ifdef GL_AMD_sample_positions
static GLboolean _glewInit_GL_AMD_sample_positions (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3810,18 +4127,6 @@ static GLboolean _glewInit_GL_AMD_sample_positions (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_AMD_sample_positions */
-#ifdef GL_AMD_seamless_cubemap_per_texture
-
-#endif /* GL_AMD_seamless_cubemap_per_texture */
-
-#ifdef GL_AMD_shader_stencil_export
-
-#endif /* GL_AMD_shader_stencil_export */
-
-#ifdef GL_AMD_shader_trinary_minmax
-
-#endif /* GL_AMD_shader_trinary_minmax */
-
#ifdef GL_AMD_sparse_texture
static GLboolean _glewInit_GL_AMD_sparse_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3849,18 +4154,6 @@ static GLboolean _glewInit_GL_AMD_stencil_operation_extended (GLEW_CONTEXT_ARG_D
#endif /* GL_AMD_stencil_operation_extended */
-#ifdef GL_AMD_texture_texture4
-
-#endif /* GL_AMD_texture_texture4 */
-
-#ifdef GL_AMD_transform_feedback3_lines_triangles
-
-#endif /* GL_AMD_transform_feedback3_lines_triangles */
-
-#ifdef GL_AMD_vertex_shader_layer
-
-#endif /* GL_AMD_vertex_shader_layer */
-
#ifdef GL_AMD_vertex_shader_tessellator
static GLboolean _glewInit_GL_AMD_vertex_shader_tessellator (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3875,14 +4168,6 @@ static GLboolean _glewInit_GL_AMD_vertex_shader_tessellator (GLEW_CONTEXT_ARG_DE
#endif /* GL_AMD_vertex_shader_tessellator */
-#ifdef GL_AMD_vertex_shader_viewport_index
-
-#endif /* GL_AMD_vertex_shader_viewport_index */
-
-#ifdef GL_ANGLE_depth_texture
-
-#endif /* GL_ANGLE_depth_texture */
-
#ifdef GL_ANGLE_framebuffer_blit
static GLboolean _glewInit_GL_ANGLE_framebuffer_blit (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3924,30 +4209,6 @@ static GLboolean _glewInit_GL_ANGLE_instanced_arrays (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ANGLE_instanced_arrays */
-#ifdef GL_ANGLE_pack_reverse_row_order
-
-#endif /* GL_ANGLE_pack_reverse_row_order */
-
-#ifdef GL_ANGLE_program_binary
-
-#endif /* GL_ANGLE_program_binary */
-
-#ifdef GL_ANGLE_texture_compression_dxt1
-
-#endif /* GL_ANGLE_texture_compression_dxt1 */
-
-#ifdef GL_ANGLE_texture_compression_dxt3
-
-#endif /* GL_ANGLE_texture_compression_dxt3 */
-
-#ifdef GL_ANGLE_texture_compression_dxt5
-
-#endif /* GL_ANGLE_texture_compression_dxt5 */
-
-#ifdef GL_ANGLE_texture_usage
-
-#endif /* GL_ANGLE_texture_usage */
-
#ifdef GL_ANGLE_timer_query
static GLboolean _glewInit_GL_ANGLE_timer_query (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -3984,14 +4245,6 @@ static GLboolean _glewInit_GL_ANGLE_translated_shader_source (GLEW_CONTEXT_ARG_D
#endif /* GL_ANGLE_translated_shader_source */
-#ifdef GL_APPLE_aux_depth_stencil
-
-#endif /* GL_APPLE_aux_depth_stencil */
-
-#ifdef GL_APPLE_client_storage
-
-#endif /* GL_APPLE_client_storage */
-
#ifdef GL_APPLE_element_array
static GLboolean _glewInit_GL_APPLE_element_array (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4029,10 +4282,6 @@ static GLboolean _glewInit_GL_APPLE_fence (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_APPLE_fence */
-#ifdef GL_APPLE_float_pixels
-
-#endif /* GL_APPLE_float_pixels */
-
#ifdef GL_APPLE_flush_buffer_range
static GLboolean _glewInit_GL_APPLE_flush_buffer_range (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4062,22 +4311,6 @@ static GLboolean _glewInit_GL_APPLE_object_purgeable (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_APPLE_object_purgeable */
-#ifdef GL_APPLE_pixel_buffer
-
-#endif /* GL_APPLE_pixel_buffer */
-
-#ifdef GL_APPLE_rgb_422
-
-#endif /* GL_APPLE_rgb_422 */
-
-#ifdef GL_APPLE_row_bytes
-
-#endif /* GL_APPLE_row_bytes */
-
-#ifdef GL_APPLE_specular_vector
-
-#endif /* GL_APPLE_specular_vector */
-
#ifdef GL_APPLE_texture_range
static GLboolean _glewInit_GL_APPLE_texture_range (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4092,10 +4325,6 @@ static GLboolean _glewInit_GL_APPLE_texture_range (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_APPLE_texture_range */
-#ifdef GL_APPLE_transform_hint
-
-#endif /* GL_APPLE_transform_hint */
-
#ifdef GL_APPLE_vertex_array_object
static GLboolean _glewInit_GL_APPLE_vertex_array_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4146,10 +4375,6 @@ static GLboolean _glewInit_GL_APPLE_vertex_program_evaluators (GLEW_CONTEXT_ARG_
#endif /* GL_APPLE_vertex_program_evaluators */
-#ifdef GL_APPLE_ycbcr_422
-
-#endif /* GL_APPLE_ycbcr_422 */
-
#ifdef GL_ARB_ES2_compatibility
static GLboolean _glewInit_GL_ARB_ES2_compatibility (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4167,13 +4392,31 @@ static GLboolean _glewInit_GL_ARB_ES2_compatibility (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_ES2_compatibility */
-#ifdef GL_ARB_ES3_compatibility
+#ifdef GL_ARB_ES3_1_compatibility
-#endif /* GL_ARB_ES3_compatibility */
+static GLboolean _glewInit_GL_ARB_ES3_1_compatibility (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GL_ARB_arrays_of_arrays
+ r = ((glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)glewGetProcAddress((const GLubyte*)"glMemoryBarrierByRegion")) == NULL) || r;
-#endif /* GL_ARB_arrays_of_arrays */
+ return r;
+}
+
+#endif /* GL_ARB_ES3_1_compatibility */
+
+#ifdef GL_ARB_ES3_2_compatibility
+
+static GLboolean _glewInit_GL_ARB_ES3_2_compatibility (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glPrimitiveBoundingBoxARB = (PFNGLPRIMITIVEBOUNDINGBOXARBPROC)glewGetProcAddress((const GLubyte*)"glPrimitiveBoundingBoxARB")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_ARB_ES3_2_compatibility */
#ifdef GL_ARB_base_instance
@@ -4289,26 +4532,31 @@ static GLboolean _glewInit_GL_ARB_clear_texture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_clear_texture */
-#ifdef GL_ARB_color_buffer_float
+#ifdef GL_ARB_clip_control
-static GLboolean _glewInit_GL_ARB_color_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT)
+static GLboolean _glewInit_GL_ARB_clip_control (GLEW_CONTEXT_ARG_DEF_INIT)
{
GLboolean r = GL_FALSE;
- r = ((glClampColorARB = (PFNGLCLAMPCOLORARBPROC)glewGetProcAddress((const GLubyte*)"glClampColorARB")) == NULL) || r;
+ r = ((glClipControl = (PFNGLCLIPCONTROLPROC)glewGetProcAddress((const GLubyte*)"glClipControl")) == NULL) || r;
return r;
}
-#endif /* GL_ARB_color_buffer_float */
+#endif /* GL_ARB_clip_control */
-#ifdef GL_ARB_compatibility
+#ifdef GL_ARB_color_buffer_float
-#endif /* GL_ARB_compatibility */
+static GLboolean _glewInit_GL_ARB_color_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GL_ARB_compressed_texture_pixel_storage
+ r = ((glClampColorARB = (PFNGLCLAMPCOLORARBPROC)glewGetProcAddress((const GLubyte*)"glClampColorARB")) == NULL) || r;
-#endif /* GL_ARB_compressed_texture_pixel_storage */
+ return r;
+}
+
+#endif /* GL_ARB_color_buffer_float */
#ifdef GL_ARB_compute_shader
@@ -4337,10 +4585,6 @@ static GLboolean _glewInit_GL_ARB_compute_variable_group_size (GLEW_CONTEXT_ARG_
#endif /* GL_ARB_compute_variable_group_size */
-#ifdef GL_ARB_conservative_depth
-
-#endif /* GL_ARB_conservative_depth */
-
#ifdef GL_ARB_copy_buffer
static GLboolean _glewInit_GL_ARB_copy_buffer (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4383,17 +4627,114 @@ static GLboolean _glewInit_GL_ARB_debug_output (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_debug_output */
-#ifdef GL_ARB_depth_buffer_float
-
-#endif /* GL_ARB_depth_buffer_float */
-
-#ifdef GL_ARB_depth_clamp
-
-#endif /* GL_ARB_depth_clamp */
-
-#ifdef GL_ARB_depth_texture
-
-#endif /* GL_ARB_depth_texture */
+#ifdef GL_ARB_direct_state_access
+
+static GLboolean _glewInit_GL_ARB_direct_state_access (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC)glewGetProcAddress((const GLubyte*)"glBindTextureUnit")) == NULL) || r;
+ r = ((glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBlitNamedFramebuffer")) == NULL) || r;
+ r = ((glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)glewGetProcAddress((const GLubyte*)"glCheckNamedFramebufferStatus")) == NULL) || r;
+ r = ((glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glClearNamedBufferData")) == NULL) || r;
+ r = ((glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glClearNamedBufferSubData")) == NULL) || r;
+ r = ((glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferfi")) == NULL) || r;
+ r = ((glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferfv")) == NULL) || r;
+ r = ((glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferiv")) == NULL) || r;
+ r = ((glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)glewGetProcAddress((const GLubyte*)"glClearNamedFramebufferuiv")) == NULL) || r;
+ r = ((glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage1D")) == NULL) || r;
+ r = ((glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage2D")) == NULL) || r;
+ r = ((glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCompressedTextureSubImage3D")) == NULL) || r;
+ r = ((glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glCopyNamedBufferSubData")) == NULL) || r;
+ r = ((glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage1D")) == NULL) || r;
+ r = ((glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage2D")) == NULL) || r;
+ r = ((glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glCopyTextureSubImage3D")) == NULL) || r;
+ r = ((glCreateBuffers = (PFNGLCREATEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glCreateBuffers")) == NULL) || r;
+ r = ((glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glCreateFramebuffers")) == NULL) || r;
+ r = ((glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC)glewGetProcAddress((const GLubyte*)"glCreateProgramPipelines")) == NULL) || r;
+ r = ((glCreateQueries = (PFNGLCREATEQUERIESPROC)glewGetProcAddress((const GLubyte*)"glCreateQueries")) == NULL) || r;
+ r = ((glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glCreateRenderbuffers")) == NULL) || r;
+ r = ((glCreateSamplers = (PFNGLCREATESAMPLERSPROC)glewGetProcAddress((const GLubyte*)"glCreateSamplers")) == NULL) || r;
+ r = ((glCreateTextures = (PFNGLCREATETEXTURESPROC)glewGetProcAddress((const GLubyte*)"glCreateTextures")) == NULL) || r;
+ r = ((glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC)glewGetProcAddress((const GLubyte*)"glCreateTransformFeedbacks")) == NULL) || r;
+ r = ((glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC)glewGetProcAddress((const GLubyte*)"glCreateVertexArrays")) == NULL) || r;
+ r = ((glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC)glewGetProcAddress((const GLubyte*)"glDisableVertexArrayAttrib")) == NULL) || r;
+ r = ((glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC)glewGetProcAddress((const GLubyte*)"glEnableVertexArrayAttrib")) == NULL) || r;
+ r = ((glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glFlushMappedNamedBufferRange")) == NULL) || r;
+ r = ((glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)glewGetProcAddress((const GLubyte*)"glGenerateTextureMipmap")) == NULL) || r;
+ r = ((glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTextureImage")) == NULL) || r;
+ r = ((glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferParameteri64v")) == NULL) || r;
+ r = ((glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferParameteriv")) == NULL) || r;
+ r = ((glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferPointerv")) == NULL) || r;
+ r = ((glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glGetNamedBufferSubData")) == NULL) || r;
+ r = ((glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferAttachmentParameteriv")) == NULL) || r;
+ r = ((glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedFramebufferParameteriv")) == NULL) || r;
+ r = ((glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetNamedRenderbufferParameteriv")) == NULL) || r;
+ r = ((glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjecti64v")) == NULL) || r;
+ r = ((glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjectiv")) == NULL) || r;
+ r = ((glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjectui64v")) == NULL) || r;
+ r = ((glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC)glewGetProcAddress((const GLubyte*)"glGetQueryBufferObjectuiv")) == NULL) || r;
+ r = ((glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetTextureImage")) == NULL) || r;
+ r = ((glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureLevelParameterfv")) == NULL) || r;
+ r = ((glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureLevelParameteriv")) == NULL) || r;
+ r = ((glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterIiv")) == NULL) || r;
+ r = ((glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterIuiv")) == NULL) || r;
+ r = ((glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameterfv")) == NULL) || r;
+ r = ((glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glGetTextureParameteriv")) == NULL) || r;
+ r = ((glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbacki64_v")) == NULL) || r;
+ r = ((glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbacki_v")) == NULL) || r;
+ r = ((glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC)glewGetProcAddress((const GLubyte*)"glGetTransformFeedbackiv")) == NULL) || r;
+ r = ((glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayIndexed64iv")) == NULL) || r;
+ r = ((glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayIndexediv")) == NULL) || r;
+ r = ((glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC)glewGetProcAddress((const GLubyte*)"glGetVertexArrayiv")) == NULL) || r;
+ r = ((glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glInvalidateNamedFramebufferData")) == NULL) || r;
+ r = ((glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glInvalidateNamedFramebufferSubData")) == NULL) || r;
+ r = ((glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC)glewGetProcAddress((const GLubyte*)"glMapNamedBuffer")) == NULL) || r;
+ r = ((glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glMapNamedBufferRange")) == NULL) || r;
+ r = ((glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferData")) == NULL) || r;
+ r = ((glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferStorage")) == NULL) || r;
+ r = ((glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferSubData")) == NULL) || r;
+ r = ((glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferDrawBuffer")) == NULL) || r;
+ r = ((glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferDrawBuffers")) == NULL) || r;
+ r = ((glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferParameteri")) == NULL) || r;
+ r = ((glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferReadBuffer")) == NULL) || r;
+ r = ((glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferRenderbuffer")) == NULL) || r;
+ r = ((glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTexture")) == NULL) || r;
+ r = ((glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferTextureLayer")) == NULL) || r;
+ r = ((glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorage")) == NULL) || r;
+ r = ((glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageMultisample")) == NULL) || r;
+ r = ((glTextureBuffer = (PFNGLTEXTUREBUFFERPROC)glewGetProcAddress((const GLubyte*)"glTextureBuffer")) == NULL) || r;
+ r = ((glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glTextureBufferRange")) == NULL) || r;
+ r = ((glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterIiv")) == NULL) || r;
+ r = ((glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterIuiv")) == NULL) || r;
+ r = ((glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterf")) == NULL) || r;
+ r = ((glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameterfv")) == NULL) || r;
+ r = ((glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glTextureParameteri")) == NULL) || r;
+ r = ((glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC)glewGetProcAddress((const GLubyte*)"glTextureParameteriv")) == NULL) || r;
+ r = ((glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage1D")) == NULL) || r;
+ r = ((glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage2D")) == NULL) || r;
+ r = ((glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage2DMultisample")) == NULL) || r;
+ r = ((glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage3D")) == NULL) || r;
+ r = ((glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)glewGetProcAddress((const GLubyte*)"glTextureStorage3DMultisample")) == NULL) || r;
+ r = ((glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage1D")) == NULL) || r;
+ r = ((glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage2D")) == NULL) || r;
+ r = ((glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC)glewGetProcAddress((const GLubyte*)"glTextureSubImage3D")) == NULL) || r;
+ r = ((glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackBufferBase")) == NULL) || r;
+ r = ((glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)glewGetProcAddress((const GLubyte*)"glTransformFeedbackBufferRange")) == NULL) || r;
+ r = ((glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC)glewGetProcAddress((const GLubyte*)"glUnmapNamedBuffer")) == NULL) || r;
+ r = ((glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribBinding")) == NULL) || r;
+ r = ((glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribFormat")) == NULL) || r;
+ r = ((glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribIFormat")) == NULL) || r;
+ r = ((glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayAttribLFormat")) == NULL) || r;
+ r = ((glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayBindingDivisor")) == NULL) || r;
+ r = ((glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayElementBuffer")) == NULL) || r;
+ r = ((glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexBuffer")) == NULL) || r;
+ r = ((glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexBuffers")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_ARB_direct_state_access */
#ifdef GL_ARB_draw_buffers
@@ -4454,42 +4795,6 @@ static GLboolean _glewInit_GL_ARB_draw_indirect (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_draw_indirect */
-#ifdef GL_ARB_draw_instanced
-
-#endif /* GL_ARB_draw_instanced */
-
-#ifdef GL_ARB_enhanced_layouts
-
-#endif /* GL_ARB_enhanced_layouts */
-
-#ifdef GL_ARB_explicit_attrib_location
-
-#endif /* GL_ARB_explicit_attrib_location */
-
-#ifdef GL_ARB_explicit_uniform_location
-
-#endif /* GL_ARB_explicit_uniform_location */
-
-#ifdef GL_ARB_fragment_coord_conventions
-
-#endif /* GL_ARB_fragment_coord_conventions */
-
-#ifdef GL_ARB_fragment_layer_viewport
-
-#endif /* GL_ARB_fragment_layer_viewport */
-
-#ifdef GL_ARB_fragment_program
-
-#endif /* GL_ARB_fragment_program */
-
-#ifdef GL_ARB_fragment_program_shadow
-
-#endif /* GL_ARB_fragment_program_shadow */
-
-#ifdef GL_ARB_fragment_shader
-
-#endif /* GL_ARB_fragment_shader */
-
#ifdef GL_ARB_framebuffer_no_attachments
static GLboolean _glewInit_GL_ARB_framebuffer_no_attachments (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4538,10 +4843,6 @@ static GLboolean _glewInit_GL_ARB_framebuffer_object (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_framebuffer_object */
-#ifdef GL_ARB_framebuffer_sRGB
-
-#endif /* GL_ARB_framebuffer_sRGB */
-
#ifdef GL_ARB_geometry_shader4
static GLboolean _glewInit_GL_ARB_geometry_shader4 (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4573,9 +4874,19 @@ static GLboolean _glewInit_GL_ARB_get_program_binary (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_get_program_binary */
-#ifdef GL_ARB_gpu_shader5
+#ifdef GL_ARB_get_texture_sub_image
-#endif /* GL_ARB_gpu_shader5 */
+static GLboolean _glewInit_GL_ARB_get_texture_sub_image (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetCompressedTextureSubImage")) == NULL) || r;
+ r = ((glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glGetTextureSubImage")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_ARB_get_texture_sub_image */
#ifdef GL_ARB_gpu_shader_fp64
@@ -4607,13 +4918,53 @@ static GLboolean _glewInit_GL_ARB_gpu_shader_fp64 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_gpu_shader_fp64 */
-#ifdef GL_ARB_half_float_pixel
-
-#endif /* GL_ARB_half_float_pixel */
-
-#ifdef GL_ARB_half_float_vertex
-
-#endif /* GL_ARB_half_float_vertex */
+#ifdef GL_ARB_gpu_shader_int64
+
+static GLboolean _glewInit_GL_ARB_gpu_shader_int64 (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glGetUniformi64vARB = (PFNGLGETUNIFORMI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformi64vARB")) == NULL) || r;
+ r = ((glGetUniformui64vARB = (PFNGLGETUNIFORMUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetUniformui64vARB")) == NULL) || r;
+ r = ((glGetnUniformi64vARB = (PFNGLGETNUNIFORMI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformi64vARB")) == NULL) || r;
+ r = ((glGetnUniformui64vARB = (PFNGLGETNUNIFORMUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformui64vARB")) == NULL) || r;
+ r = ((glProgramUniform1i64ARB = (PFNGLPROGRAMUNIFORM1I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i64ARB")) == NULL) || r;
+ r = ((glProgramUniform1i64vARB = (PFNGLPROGRAMUNIFORM1I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1i64vARB")) == NULL) || r;
+ r = ((glProgramUniform1ui64ARB = (PFNGLPROGRAMUNIFORM1UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui64ARB")) == NULL) || r;
+ r = ((glProgramUniform1ui64vARB = (PFNGLPROGRAMUNIFORM1UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ui64vARB")) == NULL) || r;
+ r = ((glProgramUniform2i64ARB = (PFNGLPROGRAMUNIFORM2I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i64ARB")) == NULL) || r;
+ r = ((glProgramUniform2i64vARB = (PFNGLPROGRAMUNIFORM2I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2i64vARB")) == NULL) || r;
+ r = ((glProgramUniform2ui64ARB = (PFNGLPROGRAMUNIFORM2UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui64ARB")) == NULL) || r;
+ r = ((glProgramUniform2ui64vARB = (PFNGLPROGRAMUNIFORM2UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ui64vARB")) == NULL) || r;
+ r = ((glProgramUniform3i64ARB = (PFNGLPROGRAMUNIFORM3I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i64ARB")) == NULL) || r;
+ r = ((glProgramUniform3i64vARB = (PFNGLPROGRAMUNIFORM3I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3i64vARB")) == NULL) || r;
+ r = ((glProgramUniform3ui64ARB = (PFNGLPROGRAMUNIFORM3UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui64ARB")) == NULL) || r;
+ r = ((glProgramUniform3ui64vARB = (PFNGLPROGRAMUNIFORM3UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ui64vARB")) == NULL) || r;
+ r = ((glProgramUniform4i64ARB = (PFNGLPROGRAMUNIFORM4I64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i64ARB")) == NULL) || r;
+ r = ((glProgramUniform4i64vARB = (PFNGLPROGRAMUNIFORM4I64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4i64vARB")) == NULL) || r;
+ r = ((glProgramUniform4ui64ARB = (PFNGLPROGRAMUNIFORM4UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui64ARB")) == NULL) || r;
+ r = ((glProgramUniform4ui64vARB = (PFNGLPROGRAMUNIFORM4UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ui64vARB")) == NULL) || r;
+ r = ((glUniform1i64ARB = (PFNGLUNIFORM1I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1i64ARB")) == NULL) || r;
+ r = ((glUniform1i64vARB = (PFNGLUNIFORM1I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1i64vARB")) == NULL) || r;
+ r = ((glUniform1ui64ARB = (PFNGLUNIFORM1UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui64ARB")) == NULL) || r;
+ r = ((glUniform1ui64vARB = (PFNGLUNIFORM1UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform1ui64vARB")) == NULL) || r;
+ r = ((glUniform2i64ARB = (PFNGLUNIFORM2I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2i64ARB")) == NULL) || r;
+ r = ((glUniform2i64vARB = (PFNGLUNIFORM2I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2i64vARB")) == NULL) || r;
+ r = ((glUniform2ui64ARB = (PFNGLUNIFORM2UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui64ARB")) == NULL) || r;
+ r = ((glUniform2ui64vARB = (PFNGLUNIFORM2UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform2ui64vARB")) == NULL) || r;
+ r = ((glUniform3i64ARB = (PFNGLUNIFORM3I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3i64ARB")) == NULL) || r;
+ r = ((glUniform3i64vARB = (PFNGLUNIFORM3I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3i64vARB")) == NULL) || r;
+ r = ((glUniform3ui64ARB = (PFNGLUNIFORM3UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui64ARB")) == NULL) || r;
+ r = ((glUniform3ui64vARB = (PFNGLUNIFORM3UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform3ui64vARB")) == NULL) || r;
+ r = ((glUniform4i64ARB = (PFNGLUNIFORM4I64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4i64ARB")) == NULL) || r;
+ r = ((glUniform4i64vARB = (PFNGLUNIFORM4I64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4i64vARB")) == NULL) || r;
+ r = ((glUniform4ui64ARB = (PFNGLUNIFORM4UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui64ARB")) == NULL) || r;
+ r = ((glUniform4ui64vARB = (PFNGLUNIFORM4UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniform4ui64vARB")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_ARB_gpu_shader_int64 */
#ifdef GL_ARB_imaging
@@ -4733,10 +5084,6 @@ static GLboolean _glewInit_GL_ARB_invalidate_subdata (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_invalidate_subdata */
-#ifdef GL_ARB_map_buffer_alignment
-
-#endif /* GL_ARB_map_buffer_alignment */
-
#ifdef GL_ARB_map_buffer_range
static GLboolean _glewInit_GL_ARB_map_buffer_range (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4879,13 +5226,18 @@ static GLboolean _glewInit_GL_ARB_occlusion_query (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_occlusion_query */
-#ifdef GL_ARB_occlusion_query2
+#ifdef GL_ARB_parallel_shader_compile
-#endif /* GL_ARB_occlusion_query2 */
+static GLboolean _glewInit_GL_ARB_parallel_shader_compile (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GL_ARB_pixel_buffer_object
+ r = ((glMaxShaderCompilerThreadsARB = (PFNGLMAXSHADERCOMPILERTHREADSARBPROC)glewGetProcAddress((const GLubyte*)"glMaxShaderCompilerThreadsARB")) == NULL) || r;
-#endif /* GL_ARB_pixel_buffer_object */
+ return r;
+}
+
+#endif /* GL_ARB_parallel_shader_compile */
#ifdef GL_ARB_point_parameters
@@ -4901,10 +5253,6 @@ static GLboolean _glewInit_GL_ARB_point_parameters (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_point_parameters */
-#ifdef GL_ARB_point_sprite
-
-#endif /* GL_ARB_point_sprite */
-
#ifdef GL_ARB_program_interface_query
static GLboolean _glewInit_GL_ARB_program_interface_query (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4936,14 +5284,6 @@ static GLboolean _glewInit_GL_ARB_provoking_vertex (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_provoking_vertex */
-#ifdef GL_ARB_query_buffer_object
-
-#endif /* GL_ARB_query_buffer_object */
-
-#ifdef GL_ARB_robust_buffer_access_behavior
-
-#endif /* GL_ARB_robust_buffer_access_behavior */
-
#ifdef GL_ARB_robustness
static GLboolean _glewInit_GL_ARB_robustness (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -4976,13 +5316,19 @@ static GLboolean _glewInit_GL_ARB_robustness (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_robustness */
-#ifdef GL_ARB_robustness_application_isolation
+#ifdef GL_ARB_sample_locations
-#endif /* GL_ARB_robustness_application_isolation */
+static GLboolean _glewInit_GL_ARB_sample_locations (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GL_ARB_robustness_share_group_isolation
+ r = ((glFramebufferSampleLocationsfvARB = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)glewGetProcAddress((const GLubyte*)"glFramebufferSampleLocationsfvARB")) == NULL) || r;
+ r = ((glNamedFramebufferSampleLocationsfvARB = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferSampleLocationsfvARB")) == NULL) || r;
-#endif /* GL_ARB_robustness_share_group_isolation */
+ return r;
+}
+
+#endif /* GL_ARB_sample_locations */
#ifdef GL_ARB_sample_shading
@@ -5023,14 +5369,6 @@ static GLboolean _glewInit_GL_ARB_sampler_objects (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_sampler_objects */
-#ifdef GL_ARB_seamless_cube_map
-
-#endif /* GL_ARB_seamless_cube_map */
-
-#ifdef GL_ARB_seamless_cubemap_per_texture
-
-#endif /* GL_ARB_seamless_cubemap_per_texture */
-
#ifdef GL_ARB_separate_shader_objects
static GLboolean _glewInit_GL_ARB_separate_shader_objects (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5116,18 +5454,6 @@ static GLboolean _glewInit_GL_ARB_shader_atomic_counters (GLEW_CONTEXT_ARG_DEF_I
#endif /* GL_ARB_shader_atomic_counters */
-#ifdef GL_ARB_shader_bit_encoding
-
-#endif /* GL_ARB_shader_bit_encoding */
-
-#ifdef GL_ARB_shader_draw_parameters
-
-#endif /* GL_ARB_shader_draw_parameters */
-
-#ifdef GL_ARB_shader_group_vote
-
-#endif /* GL_ARB_shader_group_vote */
-
#ifdef GL_ARB_shader_image_load_store
static GLboolean _glewInit_GL_ARB_shader_image_load_store (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5142,10 +5468,6 @@ static GLboolean _glewInit_GL_ARB_shader_image_load_store (GLEW_CONTEXT_ARG_DEF_
#endif /* GL_ARB_shader_image_load_store */
-#ifdef GL_ARB_shader_image_size
-
-#endif /* GL_ARB_shader_image_size */
-
#ifdef GL_ARB_shader_objects
static GLboolean _glewInit_GL_ARB_shader_objects (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5197,14 +5519,6 @@ static GLboolean _glewInit_GL_ARB_shader_objects (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_shader_objects */
-#ifdef GL_ARB_shader_precision
-
-#endif /* GL_ARB_shader_precision */
-
-#ifdef GL_ARB_shader_stencil_export
-
-#endif /* GL_ARB_shader_stencil_export */
-
#ifdef GL_ARB_shader_storage_buffer_object
static GLboolean _glewInit_GL_ARB_shader_storage_buffer_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5238,18 +5552,6 @@ static GLboolean _glewInit_GL_ARB_shader_subroutine (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_shader_subroutine */
-#ifdef GL_ARB_shader_texture_lod
-
-#endif /* GL_ARB_shader_texture_lod */
-
-#ifdef GL_ARB_shading_language_100
-
-#endif /* GL_ARB_shading_language_100 */
-
-#ifdef GL_ARB_shading_language_420pack
-
-#endif /* GL_ARB_shading_language_420pack */
-
#ifdef GL_ARB_shading_language_include
static GLboolean _glewInit_GL_ARB_shading_language_include (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5268,17 +5570,18 @@ static GLboolean _glewInit_GL_ARB_shading_language_include (GLEW_CONTEXT_ARG_DEF
#endif /* GL_ARB_shading_language_include */
-#ifdef GL_ARB_shading_language_packing
-
-#endif /* GL_ARB_shading_language_packing */
+#ifdef GL_ARB_sparse_buffer
-#ifdef GL_ARB_shadow
+static GLboolean _glewInit_GL_ARB_sparse_buffer (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#endif /* GL_ARB_shadow */
+ r = ((glBufferPageCommitmentARB = (PFNGLBUFFERPAGECOMMITMENTARBPROC)glewGetProcAddress((const GLubyte*)"glBufferPageCommitmentARB")) == NULL) || r;
-#ifdef GL_ARB_shadow_ambient
+ return r;
+}
-#endif /* GL_ARB_shadow_ambient */
+#endif /* GL_ARB_sparse_buffer */
#ifdef GL_ARB_sparse_texture
@@ -5294,10 +5597,6 @@ static GLboolean _glewInit_GL_ARB_sparse_texture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_sparse_texture */
-#ifdef GL_ARB_stencil_texturing
-
-#endif /* GL_ARB_stencil_texturing */
-
#ifdef GL_ARB_sync
static GLboolean _glewInit_GL_ARB_sync (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5331,9 +5630,18 @@ static GLboolean _glewInit_GL_ARB_tessellation_shader (GLEW_CONTEXT_ARG_DEF_INIT
#endif /* GL_ARB_tessellation_shader */
-#ifdef GL_ARB_texture_border_clamp
+#ifdef GL_ARB_texture_barrier
-#endif /* GL_ARB_texture_border_clamp */
+static GLboolean _glewInit_GL_ARB_texture_barrier (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glTextureBarrier = (PFNGLTEXTUREBARRIERPROC)glewGetProcAddress((const GLubyte*)"glTextureBarrier")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_ARB_texture_barrier */
#ifdef GL_ARB_texture_buffer_object
@@ -5348,10 +5656,6 @@ static GLboolean _glewInit_GL_ARB_texture_buffer_object (GLEW_CONTEXT_ARG_DEF_IN
#endif /* GL_ARB_texture_buffer_object */
-#ifdef GL_ARB_texture_buffer_object_rgb32
-
-#endif /* GL_ARB_texture_buffer_object_rgb32 */
-
#ifdef GL_ARB_texture_buffer_range
static GLboolean _glewInit_GL_ARB_texture_buffer_range (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5385,54 +5689,6 @@ static GLboolean _glewInit_GL_ARB_texture_compression (GLEW_CONTEXT_ARG_DEF_INIT
#endif /* GL_ARB_texture_compression */
-#ifdef GL_ARB_texture_compression_bptc
-
-#endif /* GL_ARB_texture_compression_bptc */
-
-#ifdef GL_ARB_texture_compression_rgtc
-
-#endif /* GL_ARB_texture_compression_rgtc */
-
-#ifdef GL_ARB_texture_cube_map
-
-#endif /* GL_ARB_texture_cube_map */
-
-#ifdef GL_ARB_texture_cube_map_array
-
-#endif /* GL_ARB_texture_cube_map_array */
-
-#ifdef GL_ARB_texture_env_add
-
-#endif /* GL_ARB_texture_env_add */
-
-#ifdef GL_ARB_texture_env_combine
-
-#endif /* GL_ARB_texture_env_combine */
-
-#ifdef GL_ARB_texture_env_crossbar
-
-#endif /* GL_ARB_texture_env_crossbar */
-
-#ifdef GL_ARB_texture_env_dot3
-
-#endif /* GL_ARB_texture_env_dot3 */
-
-#ifdef GL_ARB_texture_float
-
-#endif /* GL_ARB_texture_float */
-
-#ifdef GL_ARB_texture_gather
-
-#endif /* GL_ARB_texture_gather */
-
-#ifdef GL_ARB_texture_mirror_clamp_to_edge
-
-#endif /* GL_ARB_texture_mirror_clamp_to_edge */
-
-#ifdef GL_ARB_texture_mirrored_repeat
-
-#endif /* GL_ARB_texture_mirrored_repeat */
-
#ifdef GL_ARB_texture_multisample
static GLboolean _glewInit_GL_ARB_texture_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5449,34 +5705,6 @@ static GLboolean _glewInit_GL_ARB_texture_multisample (GLEW_CONTEXT_ARG_DEF_INIT
#endif /* GL_ARB_texture_multisample */
-#ifdef GL_ARB_texture_non_power_of_two
-
-#endif /* GL_ARB_texture_non_power_of_two */
-
-#ifdef GL_ARB_texture_query_levels
-
-#endif /* GL_ARB_texture_query_levels */
-
-#ifdef GL_ARB_texture_query_lod
-
-#endif /* GL_ARB_texture_query_lod */
-
-#ifdef GL_ARB_texture_rectangle
-
-#endif /* GL_ARB_texture_rectangle */
-
-#ifdef GL_ARB_texture_rg
-
-#endif /* GL_ARB_texture_rg */
-
-#ifdef GL_ARB_texture_rgb10_a2ui
-
-#endif /* GL_ARB_texture_rgb10_a2ui */
-
-#ifdef GL_ARB_texture_stencil8
-
-#endif /* GL_ARB_texture_stencil8 */
-
#ifdef GL_ARB_texture_storage
static GLboolean _glewInit_GL_ARB_texture_storage (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5511,10 +5739,6 @@ static GLboolean _glewInit_GL_ARB_texture_storage_multisample (GLEW_CONTEXT_ARG_
#endif /* GL_ARB_texture_storage_multisample */
-#ifdef GL_ARB_texture_swizzle
-
-#endif /* GL_ARB_texture_swizzle */
-
#ifdef GL_ARB_texture_view
static GLboolean _glewInit_GL_ARB_texture_view (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5630,10 +5854,6 @@ static GLboolean _glewInit_GL_ARB_uniform_buffer_object (GLEW_CONTEXT_ARG_DEF_IN
#endif /* GL_ARB_uniform_buffer_object */
-#ifdef GL_ARB_vertex_array_bgra
-
-#endif /* GL_ARB_vertex_array_bgra */
-
#ifdef GL_ARB_vertex_array_object
static GLboolean _glewInit_GL_ARB_vertex_array_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5679,6 +5899,12 @@ static GLboolean _glewInit_GL_ARB_vertex_attrib_binding (GLEW_CONTEXT_ARG_DEF_IN
GLboolean r = GL_FALSE;
r = ((glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)glewGetProcAddress((const GLubyte*)"glBindVertexBuffer")) == NULL) || r;
+ r = ((glVertexArrayBindVertexBufferEXT = (PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayBindVertexBufferEXT")) == NULL) || r;
+ r = ((glVertexArrayVertexAttribBindingEXT = (PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribBindingEXT")) == NULL) || r;
+ r = ((glVertexArrayVertexAttribFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribFormatEXT")) == NULL) || r;
+ r = ((glVertexArrayVertexAttribIFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribIFormatEXT")) == NULL) || r;
+ r = ((glVertexArrayVertexAttribLFormatEXT = (PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribLFormatEXT")) == NULL) || r;
+ r = ((glVertexArrayVertexBindingDivisorEXT = (PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexBindingDivisorEXT")) == NULL) || r;
r = ((glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribBinding")) == NULL) || r;
r = ((glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribFormat")) == NULL) || r;
r = ((glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribIFormat")) == NULL) || r;
@@ -5824,10 +6050,6 @@ static GLboolean _glewInit_GL_ARB_vertex_shader (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_vertex_shader */
-#ifdef GL_ARB_vertex_type_10f_11f_11f_rev
-
-#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */
-
#ifdef GL_ARB_vertex_type_2_10_10_10_rev
static GLboolean _glewInit_GL_ARB_vertex_type_2_10_10_10_rev (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -5928,22 +6150,6 @@ static GLboolean _glewInit_GL_ARB_window_pos (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ARB_window_pos */
-#ifdef GL_ATIX_point_sprites
-
-#endif /* GL_ATIX_point_sprites */
-
-#ifdef GL_ATIX_texture_env_combine3
-
-#endif /* GL_ATIX_texture_env_combine3 */
-
-#ifdef GL_ATIX_texture_env_route
-
-#endif /* GL_ATIX_texture_env_route */
-
-#ifdef GL_ATIX_vertex_shader_output_point_size
-
-#endif /* GL_ATIX_vertex_shader_output_point_size */
-
#ifdef GL_ATI_draw_buffers
static GLboolean _glewInit_GL_ATI_draw_buffers (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6028,10 +6234,6 @@ static GLboolean _glewInit_GL_ATI_map_object_buffer (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ATI_map_object_buffer */
-#ifdef GL_ATI_meminfo
-
-#endif /* GL_ATI_meminfo */
-
#ifdef GL_ATI_pn_triangles
static GLboolean _glewInit_GL_ATI_pn_triangles (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6060,30 +6262,6 @@ static GLboolean _glewInit_GL_ATI_separate_stencil (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ATI_separate_stencil */
-#ifdef GL_ATI_shader_texture_lod
-
-#endif /* GL_ATI_shader_texture_lod */
-
-#ifdef GL_ATI_text_fragment_shader
-
-#endif /* GL_ATI_text_fragment_shader */
-
-#ifdef GL_ATI_texture_compression_3dc
-
-#endif /* GL_ATI_texture_compression_3dc */
-
-#ifdef GL_ATI_texture_env_combine3
-
-#endif /* GL_ATI_texture_env_combine3 */
-
-#ifdef GL_ATI_texture_float
-
-#endif /* GL_ATI_texture_float */
-
-#ifdef GL_ATI_texture_mirror_once
-
-#endif /* GL_ATI_texture_mirror_once */
-
#ifdef GL_ATI_vertex_array_object
static GLboolean _glewInit_GL_ATI_vertex_array_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6180,22 +6358,6 @@ static GLboolean _glewInit_GL_ATI_vertex_streams (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_ATI_vertex_streams */
-#ifdef GL_EXT_422_pixels
-
-#endif /* GL_EXT_422_pixels */
-
-#ifdef GL_EXT_Cg_shader
-
-#endif /* GL_EXT_Cg_shader */
-
-#ifdef GL_EXT_abgr
-
-#endif /* GL_EXT_abgr */
-
-#ifdef GL_EXT_bgra
-
-#endif /* GL_EXT_bgra */
-
#ifdef GL_EXT_bindable_uniform
static GLboolean _glewInit_GL_EXT_bindable_uniform (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6250,10 +6412,6 @@ static GLboolean _glewInit_GL_EXT_blend_func_separate (GLEW_CONTEXT_ARG_DEF_INIT
#endif /* GL_EXT_blend_func_separate */
-#ifdef GL_EXT_blend_logic_op
-
-#endif /* GL_EXT_blend_logic_op */
-
#ifdef GL_EXT_blend_minmax
static GLboolean _glewInit_GL_EXT_blend_minmax (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6267,18 +6425,6 @@ static GLboolean _glewInit_GL_EXT_blend_minmax (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_blend_minmax */
-#ifdef GL_EXT_blend_subtract
-
-#endif /* GL_EXT_blend_subtract */
-
-#ifdef GL_EXT_clip_volume_hint
-
-#endif /* GL_EXT_clip_volume_hint */
-
-#ifdef GL_EXT_cmyka
-
-#endif /* GL_EXT_cmyka */
-
#ifdef GL_EXT_color_subtable
static GLboolean _glewInit_GL_EXT_color_subtable (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6377,6 +6523,20 @@ static GLboolean _glewInit_GL_EXT_cull_vertex (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_cull_vertex */
+#ifdef GL_EXT_debug_label
+
+static GLboolean _glewInit_GL_EXT_debug_label (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC)glewGetProcAddress((const GLubyte*)"glGetObjectLabelEXT")) == NULL) || r;
+ r = ((glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC)glewGetProcAddress((const GLubyte*)"glLabelObjectEXT")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_EXT_debug_label */
+
#ifdef GL_EXT_debug_marker
static GLboolean _glewInit_GL_EXT_debug_marker (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6621,6 +6781,7 @@ static GLboolean _glewInit_GL_EXT_direct_state_access (GLEW_CONTEXT_ARG_DEF_INIT
r = ((glVertexArrayNormalOffsetEXT = (PFNGLVERTEXARRAYNORMALOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayNormalOffsetEXT")) == NULL) || r;
r = ((glVertexArraySecondaryColorOffsetEXT = (PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArraySecondaryColorOffsetEXT")) == NULL) || r;
r = ((glVertexArrayTexCoordOffsetEXT = (PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayTexCoordOffsetEXT")) == NULL) || r;
+ r = ((glVertexArrayVertexAttribDivisorEXT = (PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribDivisorEXT")) == NULL) || r;
r = ((glVertexArrayVertexAttribIOffsetEXT = (PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribIOffsetEXT")) == NULL) || r;
r = ((glVertexArrayVertexAttribOffsetEXT = (PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexAttribOffsetEXT")) == NULL) || r;
r = ((glVertexArrayVertexOffsetEXT = (PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC)glewGetProcAddress((const GLubyte*)"glVertexArrayVertexOffsetEXT")) == NULL) || r;
@@ -6748,10 +6909,6 @@ static GLboolean _glewInit_GL_EXT_framebuffer_multisample (GLEW_CONTEXT_ARG_DEF_
#endif /* GL_EXT_framebuffer_multisample */
-#ifdef GL_EXT_framebuffer_multisample_blit_scaled
-
-#endif /* GL_EXT_framebuffer_multisample_blit_scaled */
-
#ifdef GL_EXT_framebuffer_object
static GLboolean _glewInit_GL_EXT_framebuffer_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6781,10 +6938,6 @@ static GLboolean _glewInit_GL_EXT_framebuffer_object (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_framebuffer_object */
-#ifdef GL_EXT_framebuffer_sRGB
-
-#endif /* GL_EXT_framebuffer_sRGB */
-
#ifdef GL_EXT_geometry_shader4
static GLboolean _glewInit_GL_EXT_geometry_shader4 (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6882,10 +7035,6 @@ static GLboolean _glewInit_GL_EXT_histogram (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_histogram */
-#ifdef GL_EXT_index_array_formats
-
-#endif /* GL_EXT_index_array_formats */
-
#ifdef GL_EXT_index_func
static GLboolean _glewInit_GL_EXT_index_func (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6912,10 +7061,6 @@ static GLboolean _glewInit_GL_EXT_index_material (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_index_material */
-#ifdef GL_EXT_index_texture
-
-#endif /* GL_EXT_index_texture */
-
#ifdef GL_EXT_light_texture
static GLboolean _glewInit_GL_EXT_light_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6931,10 +7076,6 @@ static GLboolean _glewInit_GL_EXT_light_texture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_light_texture */
-#ifdef GL_EXT_misc_attribute
-
-#endif /* GL_EXT_misc_attribute */
-
#ifdef GL_EXT_multi_draw_arrays
static GLboolean _glewInit_GL_EXT_multi_draw_arrays (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6963,18 +7104,6 @@ static GLboolean _glewInit_GL_EXT_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_multisample */
-#ifdef GL_EXT_packed_depth_stencil
-
-#endif /* GL_EXT_packed_depth_stencil */
-
-#ifdef GL_EXT_packed_float
-
-#endif /* GL_EXT_packed_float */
-
-#ifdef GL_EXT_packed_pixels
-
-#endif /* GL_EXT_packed_pixels */
-
#ifdef GL_EXT_paletted_texture
static GLboolean _glewInit_GL_EXT_paletted_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -6991,10 +7120,6 @@ static GLboolean _glewInit_GL_EXT_paletted_texture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_paletted_texture */
-#ifdef GL_EXT_pixel_buffer_object
-
-#endif /* GL_EXT_pixel_buffer_object */
-
#ifdef GL_EXT_pixel_transform
static GLboolean _glewInit_GL_EXT_pixel_transform (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7013,10 +7138,6 @@ static GLboolean _glewInit_GL_EXT_pixel_transform (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_pixel_transform */
-#ifdef GL_EXT_pixel_transform_color_table
-
-#endif /* GL_EXT_pixel_transform_color_table */
-
#ifdef GL_EXT_point_parameters
static GLboolean _glewInit_GL_EXT_point_parameters (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7044,6 +7165,19 @@ static GLboolean _glewInit_GL_EXT_polygon_offset (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_polygon_offset */
+#ifdef GL_EXT_polygon_offset_clamp
+
+static GLboolean _glewInit_GL_EXT_polygon_offset_clamp (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glPolygonOffsetClampEXT = (PFNGLPOLYGONOFFSETCLAMPEXTPROC)glewGetProcAddress((const GLubyte*)"glPolygonOffsetClampEXT")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_EXT_polygon_offset_clamp */
+
#ifdef GL_EXT_provoking_vertex
static GLboolean _glewInit_GL_EXT_provoking_vertex (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7057,9 +7191,21 @@ static GLboolean _glewInit_GL_EXT_provoking_vertex (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_provoking_vertex */
-#ifdef GL_EXT_rescale_normal
+#ifdef GL_EXT_raster_multisample
-#endif /* GL_EXT_rescale_normal */
+static GLboolean _glewInit_GL_EXT_raster_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glCoverageModulationNV = (PFNGLCOVERAGEMODULATIONNVPROC)glewGetProcAddress((const GLubyte*)"glCoverageModulationNV")) == NULL) || r;
+ r = ((glCoverageModulationTableNV = (PFNGLCOVERAGEMODULATIONTABLENVPROC)glewGetProcAddress((const GLubyte*)"glCoverageModulationTableNV")) == NULL) || r;
+ r = ((glGetCoverageModulationTableNV = (PFNGLGETCOVERAGEMODULATIONTABLENVPROC)glewGetProcAddress((const GLubyte*)"glGetCoverageModulationTableNV")) == NULL) || r;
+ r = ((glRasterSamplesEXT = (PFNGLRASTERSAMPLESEXTPROC)glewGetProcAddress((const GLubyte*)"glRasterSamplesEXT")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_EXT_raster_multisample */
#ifdef GL_EXT_scene_marker
@@ -7119,10 +7265,6 @@ static GLboolean _glewInit_GL_EXT_separate_shader_objects (GLEW_CONTEXT_ARG_DEF_
#endif /* GL_EXT_separate_shader_objects */
-#ifdef GL_EXT_separate_specular_color
-
-#endif /* GL_EXT_separate_specular_color */
-
#ifdef GL_EXT_shader_image_load_store
static GLboolean _glewInit_GL_EXT_shader_image_load_store (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7137,18 +7279,6 @@ static GLboolean _glewInit_GL_EXT_shader_image_load_store (GLEW_CONTEXT_ARG_DEF_
#endif /* GL_EXT_shader_image_load_store */
-#ifdef GL_EXT_shadow_funcs
-
-#endif /* GL_EXT_shadow_funcs */
-
-#ifdef GL_EXT_shared_texture_palette
-
-#endif /* GL_EXT_shared_texture_palette */
-
-#ifdef GL_EXT_stencil_clear_tag
-
-#endif /* GL_EXT_stencil_clear_tag */
-
#ifdef GL_EXT_stencil_two_side
static GLboolean _glewInit_GL_EXT_stencil_two_side (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7162,10 +7292,6 @@ static GLboolean _glewInit_GL_EXT_stencil_two_side (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_stencil_two_side */
-#ifdef GL_EXT_stencil_wrap
-
-#endif /* GL_EXT_stencil_wrap */
-
#ifdef GL_EXT_subtexture
static GLboolean _glewInit_GL_EXT_subtexture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7181,10 +7307,6 @@ static GLboolean _glewInit_GL_EXT_subtexture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_subtexture */
-#ifdef GL_EXT_texture
-
-#endif /* GL_EXT_texture */
-
#ifdef GL_EXT_texture3D
static GLboolean _glewInit_GL_EXT_texture3D (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7224,50 +7346,6 @@ static GLboolean _glewInit_GL_EXT_texture_buffer_object (GLEW_CONTEXT_ARG_DEF_IN
#endif /* GL_EXT_texture_buffer_object */
-#ifdef GL_EXT_texture_compression_dxt1
-
-#endif /* GL_EXT_texture_compression_dxt1 */
-
-#ifdef GL_EXT_texture_compression_latc
-
-#endif /* GL_EXT_texture_compression_latc */
-
-#ifdef GL_EXT_texture_compression_rgtc
-
-#endif /* GL_EXT_texture_compression_rgtc */
-
-#ifdef GL_EXT_texture_compression_s3tc
-
-#endif /* GL_EXT_texture_compression_s3tc */
-
-#ifdef GL_EXT_texture_cube_map
-
-#endif /* GL_EXT_texture_cube_map */
-
-#ifdef GL_EXT_texture_edge_clamp
-
-#endif /* GL_EXT_texture_edge_clamp */
-
-#ifdef GL_EXT_texture_env
-
-#endif /* GL_EXT_texture_env */
-
-#ifdef GL_EXT_texture_env_add
-
-#endif /* GL_EXT_texture_env_add */
-
-#ifdef GL_EXT_texture_env_combine
-
-#endif /* GL_EXT_texture_env_combine */
-
-#ifdef GL_EXT_texture_env_dot3
-
-#endif /* GL_EXT_texture_env_dot3 */
-
-#ifdef GL_EXT_texture_filter_anisotropic
-
-#endif /* GL_EXT_texture_filter_anisotropic */
-
#ifdef GL_EXT_texture_integer
static GLboolean _glewInit_GL_EXT_texture_integer (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7286,14 +7364,6 @@ static GLboolean _glewInit_GL_EXT_texture_integer (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_texture_integer */
-#ifdef GL_EXT_texture_lod_bias
-
-#endif /* GL_EXT_texture_lod_bias */
-
-#ifdef GL_EXT_texture_mirror_clamp
-
-#endif /* GL_EXT_texture_mirror_clamp */
-
#ifdef GL_EXT_texture_object
static GLboolean _glewInit_GL_EXT_texture_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7325,30 +7395,6 @@ static GLboolean _glewInit_GL_EXT_texture_perturb_normal (GLEW_CONTEXT_ARG_DEF_I
#endif /* GL_EXT_texture_perturb_normal */
-#ifdef GL_EXT_texture_rectangle
-
-#endif /* GL_EXT_texture_rectangle */
-
-#ifdef GL_EXT_texture_sRGB
-
-#endif /* GL_EXT_texture_sRGB */
-
-#ifdef GL_EXT_texture_sRGB_decode
-
-#endif /* GL_EXT_texture_sRGB_decode */
-
-#ifdef GL_EXT_texture_shared_exponent
-
-#endif /* GL_EXT_texture_shared_exponent */
-
-#ifdef GL_EXT_texture_snorm
-
-#endif /* GL_EXT_texture_snorm */
-
-#ifdef GL_EXT_texture_swizzle
-
-#endif /* GL_EXT_texture_swizzle */
-
#ifdef GL_EXT_timer_query
static GLboolean _glewInit_GL_EXT_timer_query (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7402,10 +7448,6 @@ static GLboolean _glewInit_GL_EXT_vertex_array (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_EXT_vertex_array */
-#ifdef GL_EXT_vertex_array_bgra
-
-#endif /* GL_EXT_vertex_array_bgra */
-
#ifdef GL_EXT_vertex_attrib_64bit
static GLboolean _glewInit_GL_EXT_vertex_attrib_64bit (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7537,10 +7579,6 @@ static GLboolean _glewInit_GL_GREMEDY_string_marker (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_GREMEDY_string_marker */
-#ifdef GL_HP_convolution_border_modes
-
-#endif /* GL_HP_convolution_border_modes */
-
#ifdef GL_HP_image_transform
static GLboolean _glewInit_GL_HP_image_transform (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7559,18 +7597,6 @@ static GLboolean _glewInit_GL_HP_image_transform (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_HP_image_transform */
-#ifdef GL_HP_occlusion_test
-
-#endif /* GL_HP_occlusion_test */
-
-#ifdef GL_HP_texture_lighting
-
-#endif /* GL_HP_texture_lighting */
-
-#ifdef GL_IBM_cull_vertex
-
-#endif /* GL_IBM_cull_vertex */
-
#ifdef GL_IBM_multimode_draw_arrays
static GLboolean _glewInit_GL_IBM_multimode_draw_arrays (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7585,18 +7611,6 @@ static GLboolean _glewInit_GL_IBM_multimode_draw_arrays (GLEW_CONTEXT_ARG_DEF_IN
#endif /* GL_IBM_multimode_draw_arrays */
-#ifdef GL_IBM_rasterpos_clip
-
-#endif /* GL_IBM_rasterpos_clip */
-
-#ifdef GL_IBM_static_data
-
-#endif /* GL_IBM_static_data */
-
-#ifdef GL_IBM_texture_mirrored_repeat
-
-#endif /* GL_IBM_texture_mirrored_repeat */
-
#ifdef GL_IBM_vertex_array_lists
static GLboolean _glewInit_GL_IBM_vertex_array_lists (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7617,14 +7631,6 @@ static GLboolean _glewInit_GL_IBM_vertex_array_lists (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_IBM_vertex_array_lists */
-#ifdef GL_INGR_color_clamp
-
-#endif /* GL_INGR_color_clamp */
-
-#ifdef GL_INGR_interlace_read
-
-#endif /* GL_INGR_interlace_read */
-
#ifdef GL_INTEL_map_texture
static GLboolean _glewInit_GL_INTEL_map_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7656,6 +7662,28 @@ static GLboolean _glewInit_GL_INTEL_parallel_arrays (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_INTEL_parallel_arrays */
+#ifdef GL_INTEL_performance_query
+
+static GLboolean _glewInit_GL_INTEL_performance_query (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glBeginPerfQueryINTEL = (PFNGLBEGINPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glBeginPerfQueryINTEL")) == NULL) || r;
+ r = ((glCreatePerfQueryINTEL = (PFNGLCREATEPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glCreatePerfQueryINTEL")) == NULL) || r;
+ r = ((glDeletePerfQueryINTEL = (PFNGLDELETEPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glDeletePerfQueryINTEL")) == NULL) || r;
+ r = ((glEndPerfQueryINTEL = (PFNGLENDPERFQUERYINTELPROC)glewGetProcAddress((const GLubyte*)"glEndPerfQueryINTEL")) == NULL) || r;
+ r = ((glGetFirstPerfQueryIdINTEL = (PFNGLGETFIRSTPERFQUERYIDINTELPROC)glewGetProcAddress((const GLubyte*)"glGetFirstPerfQueryIdINTEL")) == NULL) || r;
+ r = ((glGetNextPerfQueryIdINTEL = (PFNGLGETNEXTPERFQUERYIDINTELPROC)glewGetProcAddress((const GLubyte*)"glGetNextPerfQueryIdINTEL")) == NULL) || r;
+ r = ((glGetPerfCounterInfoINTEL = (PFNGLGETPERFCOUNTERINFOINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfCounterInfoINTEL")) == NULL) || r;
+ r = ((glGetPerfQueryDataINTEL = (PFNGLGETPERFQUERYDATAINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfQueryDataINTEL")) == NULL) || r;
+ r = ((glGetPerfQueryIdByNameINTEL = (PFNGLGETPERFQUERYIDBYNAMEINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfQueryIdByNameINTEL")) == NULL) || r;
+ r = ((glGetPerfQueryInfoINTEL = (PFNGLGETPERFQUERYINFOINTELPROC)glewGetProcAddress((const GLubyte*)"glGetPerfQueryInfoINTEL")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_INTEL_performance_query */
+
#ifdef GL_INTEL_texture_scissor
static GLboolean _glewInit_GL_INTEL_texture_scissor (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7670,6 +7698,19 @@ static GLboolean _glewInit_GL_INTEL_texture_scissor (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_INTEL_texture_scissor */
+#ifdef GL_KHR_blend_equation_advanced
+
+static GLboolean _glewInit_GL_KHR_blend_equation_advanced (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glBlendBarrierKHR = (PFNGLBLENDBARRIERKHRPROC)glewGetProcAddress((const GLubyte*)"glBlendBarrierKHR")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_KHR_blend_equation_advanced */
+
#ifdef GL_KHR_debug
static GLboolean _glewInit_GL_KHR_debug (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7692,9 +7733,21 @@ static GLboolean _glewInit_GL_KHR_debug (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_KHR_debug */
-#ifdef GL_KHR_texture_compression_astc_ldr
+#ifdef GL_KHR_robustness
-#endif /* GL_KHR_texture_compression_astc_ldr */
+static GLboolean _glewInit_GL_KHR_robustness (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformfv")) == NULL) || r;
+ r = ((glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformiv")) == NULL) || r;
+ r = ((glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)glewGetProcAddress((const GLubyte*)"glGetnUniformuiv")) == NULL) || r;
+ r = ((glReadnPixels = (PFNGLREADNPIXELSPROC)glewGetProcAddress((const GLubyte*)"glReadnPixels")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_KHR_robustness */
#ifdef GL_KTX_buffer_region
@@ -7713,14 +7766,6 @@ static GLboolean _glewInit_GL_KTX_buffer_region (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_KTX_buffer_region */
-#ifdef GL_MESAX_texture_stack
-
-#endif /* GL_MESAX_texture_stack */
-
-#ifdef GL_MESA_pack_invert
-
-#endif /* GL_MESA_pack_invert */
-
#ifdef GL_MESA_resize_buffers
static GLboolean _glewInit_GL_MESA_resize_buffers (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7770,10 +7815,6 @@ static GLboolean _glewInit_GL_MESA_window_pos (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_MESA_window_pos */
-#ifdef GL_MESA_ycbcr_texture
-
-#endif /* GL_MESA_ycbcr_texture */
-
#ifdef GL_NVX_conditional_render
static GLboolean _glewInit_GL_NVX_conditional_render (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7788,10 +7829,6 @@ static GLboolean _glewInit_GL_NVX_conditional_render (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NVX_conditional_render */
-#ifdef GL_NVX_gpu_memory_info
-
-#endif /* GL_NVX_gpu_memory_info */
-
#ifdef GL_NV_bindless_multi_draw_indirect
static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7806,6 +7843,20 @@ static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect (GLEW_CONTEXT_ARG_
#endif /* GL_NV_bindless_multi_draw_indirect */
+#ifdef GL_NV_bindless_multi_draw_indirect_count
+
+static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect_count (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glMultiDrawArraysIndirectBindlessCountNV = (PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectBindlessCountNV")) == NULL) || r;
+ r = ((glMultiDrawElementsIndirectBindlessCountNV = (PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectBindlessCountNV")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_NV_bindless_multi_draw_indirect_count */
+
#ifdef GL_NV_bindless_texture
static GLboolean _glewInit_GL_NV_bindless_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7845,18 +7896,6 @@ static GLboolean _glewInit_GL_NV_blend_equation_advanced (GLEW_CONTEXT_ARG_DEF_I
#endif /* GL_NV_blend_equation_advanced */
-#ifdef GL_NV_blend_equation_advanced_coherent
-
-#endif /* GL_NV_blend_equation_advanced_coherent */
-
-#ifdef GL_NV_blend_square
-
-#endif /* GL_NV_blend_square */
-
-#ifdef GL_NV_compute_program5
-
-#endif /* GL_NV_compute_program5 */
-
#ifdef GL_NV_conditional_render
static GLboolean _glewInit_GL_NV_conditional_render (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7871,9 +7910,31 @@ static GLboolean _glewInit_GL_NV_conditional_render (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_conditional_render */
-#ifdef GL_NV_copy_depth_to_color
+#ifdef GL_NV_conservative_raster
-#endif /* GL_NV_copy_depth_to_color */
+static GLboolean _glewInit_GL_NV_conservative_raster (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glSubpixelPrecisionBiasNV = (PFNGLSUBPIXELPRECISIONBIASNVPROC)glewGetProcAddress((const GLubyte*)"glSubpixelPrecisionBiasNV")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_NV_conservative_raster */
+
+#ifdef GL_NV_conservative_raster_dilate
+
+static GLboolean _glewInit_GL_NV_conservative_raster_dilate (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glConservativeRasterParameterfNV = (PFNGLCONSERVATIVERASTERPARAMETERFNVPROC)glewGetProcAddress((const GLubyte*)"glConservativeRasterParameterfNV")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GL_NV_conservative_raster_dilate */
#ifdef GL_NV_copy_image
@@ -7888,10 +7949,6 @@ static GLboolean _glewInit_GL_NV_copy_image (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_copy_image */
-#ifdef GL_NV_deep_texture3D
-
-#endif /* GL_NV_deep_texture3D */
-
#ifdef GL_NV_depth_buffer_float
static GLboolean _glewInit_GL_NV_depth_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7907,14 +7964,6 @@ static GLboolean _glewInit_GL_NV_depth_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_depth_buffer_float */
-#ifdef GL_NV_depth_clamp
-
-#endif /* GL_NV_depth_clamp */
-
-#ifdef GL_NV_depth_range_unclamped
-
-#endif /* GL_NV_depth_range_unclamped */
-
#ifdef GL_NV_draw_texture
static GLboolean _glewInit_GL_NV_draw_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -7983,13 +8032,18 @@ static GLboolean _glewInit_GL_NV_fence (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_fence */
-#ifdef GL_NV_float_buffer
+#ifdef GL_NV_fragment_coverage_to_color
-#endif /* GL_NV_float_buffer */
+static GLboolean _glewInit_GL_NV_fragment_coverage_to_color (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GL_NV_fog_distance
+ r = ((glFragmentCoverageColorNV = (PFNGLFRAGMENTCOVERAGECOLORNVPROC)glewGetProcAddress((const GLubyte*)"glFragmentCoverageColorNV")) == NULL) || r;
-#endif /* GL_NV_fog_distance */
+ return r;
+}
+
+#endif /* GL_NV_fragment_coverage_to_color */
#ifdef GL_NV_fragment_program
@@ -8009,18 +8063,6 @@ static GLboolean _glewInit_GL_NV_fragment_program (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_fragment_program */
-#ifdef GL_NV_fragment_program2
-
-#endif /* GL_NV_fragment_program2 */
-
-#ifdef GL_NV_fragment_program4
-
-#endif /* GL_NV_fragment_program4 */
-
-#ifdef GL_NV_fragment_program_option
-
-#endif /* GL_NV_fragment_program_option */
-
#ifdef GL_NV_framebuffer_multisample_coverage
static GLboolean _glewInit_GL_NV_framebuffer_multisample_coverage (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8047,10 +8089,6 @@ static GLboolean _glewInit_GL_NV_geometry_program4 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_geometry_program4 */
-#ifdef GL_NV_geometry_shader4
-
-#endif /* GL_NV_geometry_shader4 */
-
#ifdef GL_NV_gpu_program4
static GLboolean _glewInit_GL_NV_gpu_program4 (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8075,18 +8113,6 @@ static GLboolean _glewInit_GL_NV_gpu_program4 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_gpu_program4 */
-#ifdef GL_NV_gpu_program5
-
-#endif /* GL_NV_gpu_program5 */
-
-#ifdef GL_NV_gpu_program5_mem_extended
-
-#endif /* GL_NV_gpu_program5_mem_extended */
-
-#ifdef GL_NV_gpu_program_fp64
-
-#endif /* GL_NV_gpu_program_fp64 */
-
#ifdef GL_NV_gpu_shader5
static GLboolean _glewInit_GL_NV_gpu_shader5 (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8191,17 +8217,18 @@ static GLboolean _glewInit_GL_NV_half_float (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_half_float */
-#ifdef GL_NV_light_max_exponent
+#ifdef GL_NV_internalformat_sample_query
-#endif /* GL_NV_light_max_exponent */
-
-#ifdef GL_NV_multisample_coverage
+static GLboolean _glewInit_GL_NV_internalformat_sample_query (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#endif /* GL_NV_multisample_coverage */
+ r = ((glGetInternalformatSampleivNV = (PFNGLGETINTERNALFORMATSAMPLEIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetInternalformatSampleivNV")) == NULL) || r;
-#ifdef GL_NV_multisample_filter_hint
+ return r;
+}
-#endif /* GL_NV_multisample_filter_hint */
+#endif /* GL_NV_internalformat_sample_query */
#ifdef GL_NV_occlusion_query
@@ -8222,10 +8249,6 @@ static GLboolean _glewInit_GL_NV_occlusion_query (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_occlusion_query */
-#ifdef GL_NV_packed_depth_stencil
-
-#endif /* GL_NV_packed_depth_stencil */
-
#ifdef GL_NV_parameter_buffer_object
static GLboolean _glewInit_GL_NV_parameter_buffer_object (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8241,10 +8264,6 @@ static GLboolean _glewInit_GL_NV_parameter_buffer_object (GLEW_CONTEXT_ARG_DEF_I
#endif /* GL_NV_parameter_buffer_object */
-#ifdef GL_NV_parameter_buffer_object2
-
-#endif /* GL_NV_parameter_buffer_object2 */
-
#ifdef GL_NV_path_rendering
static GLboolean _glewInit_GL_NV_path_rendering (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8271,18 +8290,28 @@ static GLboolean _glewInit_GL_NV_path_rendering (GLEW_CONTEXT_ARG_DEF_INIT)
r = ((glGetPathSpacingNV = (PFNGLGETPATHSPACINGNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathSpacingNV")) == NULL) || r;
r = ((glGetPathTexGenfvNV = (PFNGLGETPATHTEXGENFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathTexGenfvNV")) == NULL) || r;
r = ((glGetPathTexGenivNV = (PFNGLGETPATHTEXGENIVNVPROC)glewGetProcAddress((const GLubyte*)"glGetPathTexGenivNV")) == NULL) || r;
+ r = ((glGetProgramResourcefvNV = (PFNGLGETPROGRAMRESOURCEFVNVPROC)glewGetProcAddress((const GLubyte*)"glGetProgramResourcefvNV")) == NULL) || r;
r = ((glInterpolatePathsNV = (PFNGLINTERPOLATEPATHSNVPROC)glewGetProcAddress((const GLubyte*)"glInterpolatePathsNV")) == NULL) || r;
r = ((glIsPathNV = (PFNGLISPATHNVPROC)glewGetProcAddress((const GLubyte*)"glIsPathNV")) == NULL) || r;
r = ((glIsPointInFillPathNV = (PFNGLISPOINTINFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glIsPointInFillPathNV")) == NULL) || r;
r = ((glIsPointInStrokePathNV = (PFNGLISPOINTINSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glIsPointInStrokePathNV")) == NULL) || r;
+ r = ((glMatrixLoad3x2fNV = (PFNGLMATRIXLOAD3X2FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoad3x2fNV")) == NULL) || r;
+ r = ((glMatrixLoad3x3fNV = (PFNGLMATRIXLOAD3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoad3x3fNV")) == NULL) || r;
+ r = ((glMatrixLoadTranspose3x3fNV = (PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixLoadTranspose3x3fNV")) == NULL) || r;
+ r = ((glMatrixMult3x2fNV = (PFNGLMATRIXMULT3X2FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixMult3x2fNV")) == NULL) || r;
+ r = ((glMatrixMult3x3fNV = (PFNGLMATRIXMULT3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixMult3x3fNV")) == NULL) || r;
+ r = ((glMatrixMultTranspose3x3fNV = (PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC)glewGetProcAddress((const GLubyte*)"glMatrixMultTranspose3x3fNV")) == NULL) || r;
r = ((glPathColorGenNV = (PFNGLPATHCOLORGENNVPROC)glewGetProcAddress((const GLubyte*)"glPathColorGenNV")) == NULL) || r;
r = ((glPathCommandsNV = (PFNGLPATHCOMMANDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathCommandsNV")) == NULL) || r;
r = ((glPathCoordsNV = (PFNGLPATHCOORDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathCoordsNV")) == NULL) || r;
r = ((glPathCoverDepthFuncNV = (PFNGLPATHCOVERDEPTHFUNCNVPROC)glewGetProcAddress((const GLubyte*)"glPathCoverDepthFuncNV")) == NULL) || r;
r = ((glPathDashArrayNV = (PFNGLPATHDASHARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glPathDashArrayNV")) == NULL) || r;
r = ((glPathFogGenNV = (PFNGLPATHFOGGENNVPROC)glewGetProcAddress((const GLubyte*)"glPathFogGenNV")) == NULL) || r;
+ r = ((glPathGlyphIndexArrayNV = (PFNGLPATHGLYPHINDEXARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphIndexArrayNV")) == NULL) || r;
+ r = ((glPathGlyphIndexRangeNV = (PFNGLPATHGLYPHINDEXRANGENVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphIndexRangeNV")) == NULL) || r;
r = ((glPathGlyphRangeNV = (PFNGLPATHGLYPHRANGENVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphRangeNV")) == NULL) || r;
r = ((glPathGlyphsNV = (PFNGLPATHGLYPHSNVPROC)glewGetProcAddress((const GLubyte*)"glPathGlyphsNV")) == NULL) || r;
+ r = ((glPathMemoryGlyphIndexArrayNV = (PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC)glewGetProcAddress((const GLubyte*)"glPathMemoryGlyphIndexArrayNV")) == NULL) || r;
r = ((glPathParameterfNV = (PFNGLPATHPARAMETERFNVPROC)glewGetProcAddress((const GLubyte*)"glPathParameterfNV")) == NULL) || r;
r = ((glPathParameterfvNV = (PFNGLPATHPARAMETERFVNVPROC)glewGetProcAddress((const GLubyte*)"glPathParameterfvNV")) == NULL) || r;
r = ((glPathParameteriNV = (PFNGLPATHPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glPathParameteriNV")) == NULL) || r;
@@ -8294,10 +8323,15 @@ static GLboolean _glewInit_GL_NV_path_rendering (GLEW_CONTEXT_ARG_DEF_INIT)
r = ((glPathSubCoordsNV = (PFNGLPATHSUBCOORDSNVPROC)glewGetProcAddress((const GLubyte*)"glPathSubCoordsNV")) == NULL) || r;
r = ((glPathTexGenNV = (PFNGLPATHTEXGENNVPROC)glewGetProcAddress((const GLubyte*)"glPathTexGenNV")) == NULL) || r;
r = ((glPointAlongPathNV = (PFNGLPOINTALONGPATHNVPROC)glewGetProcAddress((const GLubyte*)"glPointAlongPathNV")) == NULL) || r;
+ r = ((glProgramPathFragmentInputGenNV = (PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC)glewGetProcAddress((const GLubyte*)"glProgramPathFragmentInputGenNV")) == NULL) || r;
r = ((glStencilFillPathInstancedNV = (PFNGLSTENCILFILLPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilFillPathInstancedNV")) == NULL) || r;
r = ((glStencilFillPathNV = (PFNGLSTENCILFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilFillPathNV")) == NULL) || r;
r = ((glStencilStrokePathInstancedNV = (PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilStrokePathInstancedNV")) == NULL) || r;
r = ((glStencilStrokePathNV = (PFNGLSTENCILSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilStrokePathNV")) == NULL) || r;
+ r = ((glStencilThenCoverFillPathInstancedNV = (PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverFillPathInstancedNV")) == NULL) || r;
+ r = ((glStencilThenCoverFillPathNV = (PFNGLSTENCILTHENCOVERFILLPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverFillPathNV")) == NULL) || r;
+ r = ((glStencilThenCoverStrokePathInstancedNV = (PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverStrokePathInstancedNV")) == NULL) || r;
+ r = ((glStencilThenCoverStrokePathNV = (PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC)glewGetProcAddress((const GLubyte*)"glStencilThenCoverStrokePathNV")) == NULL) || r;
r = ((glTransformPathNV = (PFNGLTRANSFORMPATHNVPROC)glewGetProcAddress((const GLubyte*)"glTransformPathNV")) == NULL) || r;
r = ((glWeightPathsNV = (PFNGLWEIGHTPATHSNVPROC)glewGetProcAddress((const GLubyte*)"glWeightPathsNV")) == NULL) || r;
@@ -8405,13 +8439,19 @@ static GLboolean _glewInit_GL_NV_register_combiners2 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_register_combiners2 */
-#ifdef GL_NV_shader_atomic_counters
+#ifdef GL_NV_sample_locations
-#endif /* GL_NV_shader_atomic_counters */
+static GLboolean _glewInit_GL_NV_sample_locations (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GL_NV_shader_atomic_float
+ r = ((glFramebufferSampleLocationsfvNV = (PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)glewGetProcAddress((const GLubyte*)"glFramebufferSampleLocationsfvNV")) == NULL) || r;
+ r = ((glNamedFramebufferSampleLocationsfvNV = (PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC)glewGetProcAddress((const GLubyte*)"glNamedFramebufferSampleLocationsfvNV")) == NULL) || r;
-#endif /* GL_NV_shader_atomic_float */
+ return r;
+}
+
+#endif /* GL_NV_sample_locations */
#ifdef GL_NV_shader_buffer_load
@@ -8438,22 +8478,6 @@ static GLboolean _glewInit_GL_NV_shader_buffer_load (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_shader_buffer_load */
-#ifdef GL_NV_shader_storage_buffer_object
-
-#endif /* GL_NV_shader_storage_buffer_object */
-
-#ifdef GL_NV_tessellation_program5
-
-#endif /* GL_NV_tessellation_program5 */
-
-#ifdef GL_NV_texgen_emboss
-
-#endif /* GL_NV_texgen_emboss */
-
-#ifdef GL_NV_texgen_reflection
-
-#endif /* GL_NV_texgen_reflection */
-
#ifdef GL_NV_texture_barrier
static GLboolean _glewInit_GL_NV_texture_barrier (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8467,18 +8491,6 @@ static GLboolean _glewInit_GL_NV_texture_barrier (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_texture_barrier */
-#ifdef GL_NV_texture_compression_vtc
-
-#endif /* GL_NV_texture_compression_vtc */
-
-#ifdef GL_NV_texture_env_combine4
-
-#endif /* GL_NV_texture_env_combine4 */
-
-#ifdef GL_NV_texture_expand_normal
-
-#endif /* GL_NV_texture_expand_normal */
-
#ifdef GL_NV_texture_multisample
static GLboolean _glewInit_GL_NV_texture_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8497,22 +8509,6 @@ static GLboolean _glewInit_GL_NV_texture_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_texture_multisample */
-#ifdef GL_NV_texture_rectangle
-
-#endif /* GL_NV_texture_rectangle */
-
-#ifdef GL_NV_texture_shader
-
-#endif /* GL_NV_texture_shader */
-
-#ifdef GL_NV_texture_shader2
-
-#endif /* GL_NV_texture_shader2 */
-
-#ifdef GL_NV_texture_shader3
-
-#endif /* GL_NV_texture_shader3 */
-
#ifdef GL_NV_transform_feedback
static GLboolean _glewInit_GL_NV_transform_feedback (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8591,10 +8587,6 @@ static GLboolean _glewInit_GL_NV_vertex_array_range (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_vertex_array_range */
-#ifdef GL_NV_vertex_array_range2
-
-#endif /* GL_NV_vertex_array_range2 */
-
#ifdef GL_NV_vertex_attrib_integer_64bit
static GLboolean _glewInit_GL_NV_vertex_attrib_integer_64bit (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8726,26 +8718,6 @@ static GLboolean _glewInit_GL_NV_vertex_program (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_vertex_program */
-#ifdef GL_NV_vertex_program1_1
-
-#endif /* GL_NV_vertex_program1_1 */
-
-#ifdef GL_NV_vertex_program2
-
-#endif /* GL_NV_vertex_program2 */
-
-#ifdef GL_NV_vertex_program2_option
-
-#endif /* GL_NV_vertex_program2_option */
-
-#ifdef GL_NV_vertex_program3
-
-#endif /* GL_NV_vertex_program3 */
-
-#ifdef GL_NV_vertex_program4
-
-#endif /* GL_NV_vertex_program4 */
-
#ifdef GL_NV_video_capture
static GLboolean _glewInit_GL_NV_video_capture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8770,18 +8742,6 @@ static GLboolean _glewInit_GL_NV_video_capture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_NV_video_capture */
-#ifdef GL_OES_byte_coordinates
-
-#endif /* GL_OES_byte_coordinates */
-
-#ifdef GL_OES_compressed_paletted_texture
-
-#endif /* GL_OES_compressed_paletted_texture */
-
-#ifdef GL_OES_read_format
-
-#endif /* GL_OES_read_format */
-
#ifdef GL_OES_single_precision
static GLboolean _glewInit_GL_OES_single_precision (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8800,25 +8760,18 @@ static GLboolean _glewInit_GL_OES_single_precision (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_OES_single_precision */
-#ifdef GL_OML_interlace
-
-#endif /* GL_OML_interlace */
-
-#ifdef GL_OML_resample
-
-#endif /* GL_OML_resample */
+#ifdef GL_OVR_multiview
-#ifdef GL_OML_subsample
-
-#endif /* GL_OML_subsample */
-
-#ifdef GL_PGI_misc_hints
+static GLboolean _glewInit_GL_OVR_multiview (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#endif /* GL_PGI_misc_hints */
+ r = ((glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)glewGetProcAddress((const GLubyte*)"glFramebufferTextureMultiviewOVR")) == NULL) || r;
-#ifdef GL_PGI_vertex_hints
+ return r;
+}
-#endif /* GL_PGI_vertex_hints */
+#endif /* GL_OVR_multiview */
#ifdef GL_REGAL_ES1_0_compatibility
@@ -8888,10 +8841,6 @@ static GLboolean _glewInit_GL_REGAL_ES1_1_compatibility (GLEW_CONTEXT_ARG_DEF_IN
#endif /* GL_REGAL_ES1_1_compatibility */
-#ifdef GL_REGAL_enable
-
-#endif /* GL_REGAL_enable */
-
#ifdef GL_REGAL_error_string
static GLboolean _glewInit_GL_REGAL_error_string (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8932,17 +8881,18 @@ static GLboolean _glewInit_GL_REGAL_log (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_REGAL_log */
-#ifdef GL_REND_screen_coordinates
+#ifdef GL_REGAL_proc_address
-#endif /* GL_REND_screen_coordinates */
-
-#ifdef GL_S3_s3tc
+static GLboolean _glewInit_GL_REGAL_proc_address (GLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#endif /* GL_S3_s3tc */
+ r = ((glGetProcAddressREGAL = (PFNGLGETPROCADDRESSREGALPROC)glewGetProcAddress((const GLubyte*)"glGetProcAddressREGAL")) == NULL) || r;
-#ifdef GL_SGIS_color_range
+ return r;
+}
-#endif /* GL_SGIS_color_range */
+#endif /* GL_REGAL_proc_address */
#ifdef GL_SGIS_detail_texture
@@ -8972,10 +8922,6 @@ static GLboolean _glewInit_GL_SGIS_fog_function (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIS_fog_function */
-#ifdef GL_SGIS_generate_mipmap
-
-#endif /* GL_SGIS_generate_mipmap */
-
#ifdef GL_SGIS_multisample
static GLboolean _glewInit_GL_SGIS_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -8990,14 +8936,6 @@ static GLboolean _glewInit_GL_SGIS_multisample (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIS_multisample */
-#ifdef GL_SGIS_pixel_texture
-
-#endif /* GL_SGIS_pixel_texture */
-
-#ifdef GL_SGIS_point_line_texgen
-
-#endif /* GL_SGIS_point_line_texgen */
-
#ifdef GL_SGIS_sharpen_texture
static GLboolean _glewInit_GL_SGIS_sharpen_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9026,14 +8964,6 @@ static GLboolean _glewInit_GL_SGIS_texture4D (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIS_texture4D */
-#ifdef GL_SGIS_texture_border_clamp
-
-#endif /* GL_SGIS_texture_border_clamp */
-
-#ifdef GL_SGIS_texture_edge_clamp
-
-#endif /* GL_SGIS_texture_edge_clamp */
-
#ifdef GL_SGIS_texture_filter4
static GLboolean _glewInit_GL_SGIS_texture_filter4 (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9048,14 +8978,6 @@ static GLboolean _glewInit_GL_SGIS_texture_filter4 (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIS_texture_filter4 */
-#ifdef GL_SGIS_texture_lod
-
-#endif /* GL_SGIS_texture_lod */
-
-#ifdef GL_SGIS_texture_select
-
-#endif /* GL_SGIS_texture_select */
-
#ifdef GL_SGIX_async
static GLboolean _glewInit_GL_SGIX_async (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9074,30 +8996,6 @@ static GLboolean _glewInit_GL_SGIX_async (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIX_async */
-#ifdef GL_SGIX_async_histogram
-
-#endif /* GL_SGIX_async_histogram */
-
-#ifdef GL_SGIX_async_pixel
-
-#endif /* GL_SGIX_async_pixel */
-
-#ifdef GL_SGIX_blend_alpha_minmax
-
-#endif /* GL_SGIX_blend_alpha_minmax */
-
-#ifdef GL_SGIX_clipmap
-
-#endif /* GL_SGIX_clipmap */
-
-#ifdef GL_SGIX_convolution_accuracy
-
-#endif /* GL_SGIX_convolution_accuracy */
-
-#ifdef GL_SGIX_depth_texture
-
-#endif /* GL_SGIX_depth_texture */
-
#ifdef GL_SGIX_flush_raster
static GLboolean _glewInit_GL_SGIX_flush_raster (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9111,10 +9009,6 @@ static GLboolean _glewInit_GL_SGIX_flush_raster (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIX_flush_raster */
-#ifdef GL_SGIX_fog_offset
-
-#endif /* GL_SGIX_fog_offset */
-
#ifdef GL_SGIX_fog_texture
static GLboolean _glewInit_GL_SGIX_fog_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9170,18 +9064,6 @@ static GLboolean _glewInit_GL_SGIX_framezoom (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIX_framezoom */
-#ifdef GL_SGIX_interlace
-
-#endif /* GL_SGIX_interlace */
-
-#ifdef GL_SGIX_ir_instrument1
-
-#endif /* GL_SGIX_ir_instrument1 */
-
-#ifdef GL_SGIX_list_priority
-
-#endif /* GL_SGIX_list_priority */
-
#ifdef GL_SGIX_pixel_texture
static GLboolean _glewInit_GL_SGIX_pixel_texture (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9195,10 +9077,6 @@ static GLboolean _glewInit_GL_SGIX_pixel_texture (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIX_pixel_texture */
-#ifdef GL_SGIX_pixel_texture_bits
-
-#endif /* GL_SGIX_pixel_texture_bits */
-
#ifdef GL_SGIX_reference_plane
static GLboolean _glewInit_GL_SGIX_reference_plane (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9212,18 +9090,6 @@ static GLboolean _glewInit_GL_SGIX_reference_plane (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIX_reference_plane */
-#ifdef GL_SGIX_resample
-
-#endif /* GL_SGIX_resample */
-
-#ifdef GL_SGIX_shadow
-
-#endif /* GL_SGIX_shadow */
-
-#ifdef GL_SGIX_shadow_ambient
-
-#endif /* GL_SGIX_shadow_ambient */
-
#ifdef GL_SGIX_sprite
static GLboolean _glewInit_GL_SGIX_sprite (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9253,46 +9119,6 @@ static GLboolean _glewInit_GL_SGIX_tag_sample_buffer (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGIX_tag_sample_buffer */
-#ifdef GL_SGIX_texture_add_env
-
-#endif /* GL_SGIX_texture_add_env */
-
-#ifdef GL_SGIX_texture_coordinate_clamp
-
-#endif /* GL_SGIX_texture_coordinate_clamp */
-
-#ifdef GL_SGIX_texture_lod_bias
-
-#endif /* GL_SGIX_texture_lod_bias */
-
-#ifdef GL_SGIX_texture_multi_buffer
-
-#endif /* GL_SGIX_texture_multi_buffer */
-
-#ifdef GL_SGIX_texture_range
-
-#endif /* GL_SGIX_texture_range */
-
-#ifdef GL_SGIX_texture_scale_bias
-
-#endif /* GL_SGIX_texture_scale_bias */
-
-#ifdef GL_SGIX_vertex_preclip
-
-#endif /* GL_SGIX_vertex_preclip */
-
-#ifdef GL_SGIX_vertex_preclip_hint
-
-#endif /* GL_SGIX_vertex_preclip_hint */
-
-#ifdef GL_SGIX_ycrcb
-
-#endif /* GL_SGIX_ycrcb */
-
-#ifdef GL_SGI_color_matrix
-
-#endif /* GL_SGI_color_matrix */
-
#ifdef GL_SGI_color_table
static GLboolean _glewInit_GL_SGI_color_table (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9312,10 +9138,6 @@ static GLboolean _glewInit_GL_SGI_color_table (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SGI_color_table */
-#ifdef GL_SGI_texture_color_table
-
-#endif /* GL_SGI_texture_color_table */
-
#ifdef GL_SUNX_constant_data
static GLboolean _glewInit_GL_SUNX_constant_data (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9329,10 +9151,6 @@ static GLboolean _glewInit_GL_SUNX_constant_data (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SUNX_constant_data */
-#ifdef GL_SUN_convolution_border_modes
-
-#endif /* GL_SUN_convolution_border_modes */
-
#ifdef GL_SUN_global_alpha
static GLboolean _glewInit_GL_SUN_global_alpha (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9353,10 +9171,6 @@ static GLboolean _glewInit_GL_SUN_global_alpha (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SUN_global_alpha */
-#ifdef GL_SUN_mesh_array
-
-#endif /* GL_SUN_mesh_array */
-
#ifdef GL_SUN_read_video_pixels
static GLboolean _glewInit_GL_SUN_read_video_pixels (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9370,10 +9184,6 @@ static GLboolean _glewInit_GL_SUN_read_video_pixels (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SUN_read_video_pixels */
-#ifdef GL_SUN_slice_accum
-
-#endif /* GL_SUN_slice_accum */
-
#ifdef GL_SUN_triangle_list
static GLboolean _glewInit_GL_SUN_triangle_list (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9445,14 +9255,6 @@ static GLboolean _glewInit_GL_SUN_vertex (GLEW_CONTEXT_ARG_DEF_INIT)
#endif /* GL_SUN_vertex */
-#ifdef GL_WIN_phong_shading
-
-#endif /* GL_WIN_phong_shading */
-
-#ifdef GL_WIN_specular_fog
-
-#endif /* GL_WIN_specular_fog */
-
#ifdef GL_WIN_swap_hint
static GLboolean _glewInit_GL_WIN_swap_hint (GLEW_CONTEXT_ARG_DEF_INIT)
@@ -9512,23 +9314,24 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST)
}
else
{
- CONST_CAST(GLEW_VERSION_4_4) = ( major > 4 ) || ( major == 4 && minor >= 4 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_4_3) = GLEW_VERSION_4_4 == GL_TRUE || ( major == 4 && minor >= 3 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_4_2) = GLEW_VERSION_4_3 == GL_TRUE || ( major == 4 && minor >= 2 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_4_1) = GLEW_VERSION_4_2 == GL_TRUE || ( major == 4 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_4_0) = GLEW_VERSION_4_1 == GL_TRUE || ( major == 4 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_3_3) = GLEW_VERSION_4_0 == GL_TRUE || ( major == 3 && minor >= 3 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_3_2) = GLEW_VERSION_3_3 == GL_TRUE || ( major == 3 && minor >= 2 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_3_1) = GLEW_VERSION_3_2 == GL_TRUE || ( major == 3 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_3_0) = GLEW_VERSION_3_1 == GL_TRUE || ( major == 3 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_2_1) = GLEW_VERSION_3_0 == GL_TRUE || ( major == 2 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_2_0) = GLEW_VERSION_2_1 == GL_TRUE || ( major == 2 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_1_5) = GLEW_VERSION_2_0 == GL_TRUE || ( major == 1 && minor >= 5 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_1_4) = GLEW_VERSION_1_5 == GL_TRUE || ( major == 1 && minor >= 4 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_1_3) = GLEW_VERSION_1_4 == GL_TRUE || ( major == 1 && minor >= 3 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_1_2_1) = GLEW_VERSION_1_3 == GL_TRUE ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_1_2) = GLEW_VERSION_1_2_1 == GL_TRUE || ( major == 1 && minor >= 2 ) ? GL_TRUE : GL_FALSE;
- CONST_CAST(GLEW_VERSION_1_1) = GLEW_VERSION_1_2 == GL_TRUE || ( major == 1 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_4_5 = ( major > 4 ) || ( major == 4 && minor >= 5 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_4_4 = GLEW_VERSION_4_5 == GL_TRUE || ( major == 4 && minor >= 4 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_4_3 = GLEW_VERSION_4_4 == GL_TRUE || ( major == 4 && minor >= 3 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_4_2 = GLEW_VERSION_4_3 == GL_TRUE || ( major == 4 && minor >= 2 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_4_1 = GLEW_VERSION_4_2 == GL_TRUE || ( major == 4 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_4_0 = GLEW_VERSION_4_1 == GL_TRUE || ( major == 4 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_3_3 = GLEW_VERSION_4_0 == GL_TRUE || ( major == 3 && minor >= 3 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_3_2 = GLEW_VERSION_3_3 == GL_TRUE || ( major == 3 && minor >= 2 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_3_1 = GLEW_VERSION_3_2 == GL_TRUE || ( major == 3 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_3_0 = GLEW_VERSION_3_1 == GL_TRUE || ( major == 3 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_2_1 = GLEW_VERSION_3_0 == GL_TRUE || ( major == 2 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_2_0 = GLEW_VERSION_2_1 == GL_TRUE || ( major == 2 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_1_5 = GLEW_VERSION_2_0 == GL_TRUE || ( major == 1 && minor >= 5 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_1_4 = GLEW_VERSION_1_5 == GL_TRUE || ( major == 1 && minor >= 4 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_1_3 = GLEW_VERSION_1_4 == GL_TRUE || ( major == 1 && minor >= 3 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_1_2_1 = GLEW_VERSION_1_3 == GL_TRUE ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_1_2 = GLEW_VERSION_1_2_1 == GL_TRUE || ( major == 1 && minor >= 2 ) ? GL_TRUE : GL_FALSE;
+ GLEW_VERSION_1_1 = GLEW_VERSION_1_2 == GL_TRUE || ( major == 1 && minor >= 1 ) ? GL_TRUE : GL_FALSE;
}
/* query opengl extensions string */
@@ -9539,39 +9342,39 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST)
/* initialize extensions */
#ifdef GL_VERSION_1_2
- if (glewExperimental || GLEW_VERSION_1_2) CONST_CAST(GLEW_VERSION_1_2) = !_glewInit_GL_VERSION_1_2(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_1_2) GLEW_VERSION_1_2 = !_glewInit_GL_VERSION_1_2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_1_2 */
#ifdef GL_VERSION_1_2_1
#endif /* GL_VERSION_1_2_1 */
#ifdef GL_VERSION_1_3
- if (glewExperimental || GLEW_VERSION_1_3) CONST_CAST(GLEW_VERSION_1_3) = !_glewInit_GL_VERSION_1_3(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_1_3) GLEW_VERSION_1_3 = !_glewInit_GL_VERSION_1_3(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_1_3 */
#ifdef GL_VERSION_1_4
- if (glewExperimental || GLEW_VERSION_1_4) CONST_CAST(GLEW_VERSION_1_4) = !_glewInit_GL_VERSION_1_4(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_1_4) GLEW_VERSION_1_4 = !_glewInit_GL_VERSION_1_4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_1_4 */
#ifdef GL_VERSION_1_5
- if (glewExperimental || GLEW_VERSION_1_5) CONST_CAST(GLEW_VERSION_1_5) = !_glewInit_GL_VERSION_1_5(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_1_5) GLEW_VERSION_1_5 = !_glewInit_GL_VERSION_1_5(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_1_5 */
#ifdef GL_VERSION_2_0
- if (glewExperimental || GLEW_VERSION_2_0) CONST_CAST(GLEW_VERSION_2_0) = !_glewInit_GL_VERSION_2_0(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_2_0) GLEW_VERSION_2_0 = !_glewInit_GL_VERSION_2_0(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_2_0 */
#ifdef GL_VERSION_2_1
- if (glewExperimental || GLEW_VERSION_2_1) CONST_CAST(GLEW_VERSION_2_1) = !_glewInit_GL_VERSION_2_1(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_2_1) GLEW_VERSION_2_1 = !_glewInit_GL_VERSION_2_1(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_2_1 */
#ifdef GL_VERSION_3_0
- if (glewExperimental || GLEW_VERSION_3_0) CONST_CAST(GLEW_VERSION_3_0) = !_glewInit_GL_VERSION_3_0(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_3_0) GLEW_VERSION_3_0 = !_glewInit_GL_VERSION_3_0(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_3_0 */
#ifdef GL_VERSION_3_1
- if (glewExperimental || GLEW_VERSION_3_1) CONST_CAST(GLEW_VERSION_3_1) = !_glewInit_GL_VERSION_3_1(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_3_1) GLEW_VERSION_3_1 = !_glewInit_GL_VERSION_3_1(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_3_1 */
#ifdef GL_VERSION_3_2
- if (glewExperimental || GLEW_VERSION_3_2) CONST_CAST(GLEW_VERSION_3_2) = !_glewInit_GL_VERSION_3_2(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_3_2) GLEW_VERSION_3_2 = !_glewInit_GL_VERSION_3_2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_3_2 */
#ifdef GL_VERSION_3_3
- if (glewExperimental || GLEW_VERSION_3_3) CONST_CAST(GLEW_VERSION_3_3) = !_glewInit_GL_VERSION_3_3(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_3_3) GLEW_VERSION_3_3 = !_glewInit_GL_VERSION_3_3(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_3_3 */
#ifdef GL_VERSION_4_0
- if (glewExperimental || GLEW_VERSION_4_0) CONST_CAST(GLEW_VERSION_4_0) = !_glewInit_GL_VERSION_4_0(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLEW_VERSION_4_0) GLEW_VERSION_4_0 = !_glewInit_GL_VERSION_4_0(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_VERSION_4_0 */
#ifdef GL_VERSION_4_1
#endif /* GL_VERSION_4_1 */
@@ -9581,1740 +9384,1978 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST)
#endif /* GL_VERSION_4_3 */
#ifdef GL_VERSION_4_4
#endif /* GL_VERSION_4_4 */
+#ifdef GL_VERSION_4_5
+ if (glewExperimental || GLEW_VERSION_4_5) GLEW_VERSION_4_5 = !_glewInit_GL_VERSION_4_5(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_VERSION_4_5 */
#ifdef GL_3DFX_multisample
- CONST_CAST(GLEW_3DFX_multisample) = _glewSearchExtension("GL_3DFX_multisample", extStart, extEnd);
+ GLEW_3DFX_multisample = _glewSearchExtension("GL_3DFX_multisample", extStart, extEnd);
#endif /* GL_3DFX_multisample */
#ifdef GL_3DFX_tbuffer
- CONST_CAST(GLEW_3DFX_tbuffer) = _glewSearchExtension("GL_3DFX_tbuffer", extStart, extEnd);
- if (glewExperimental || GLEW_3DFX_tbuffer) CONST_CAST(GLEW_3DFX_tbuffer) = !_glewInit_GL_3DFX_tbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_3DFX_tbuffer = _glewSearchExtension("GL_3DFX_tbuffer", extStart, extEnd);
+ if (glewExperimental || GLEW_3DFX_tbuffer) GLEW_3DFX_tbuffer = !_glewInit_GL_3DFX_tbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_3DFX_tbuffer */
#ifdef GL_3DFX_texture_compression_FXT1
- CONST_CAST(GLEW_3DFX_texture_compression_FXT1) = _glewSearchExtension("GL_3DFX_texture_compression_FXT1", extStart, extEnd);
+ GLEW_3DFX_texture_compression_FXT1 = _glewSearchExtension("GL_3DFX_texture_compression_FXT1", extStart, extEnd);
#endif /* GL_3DFX_texture_compression_FXT1 */
#ifdef GL_AMD_blend_minmax_factor
- CONST_CAST(GLEW_AMD_blend_minmax_factor) = _glewSearchExtension("GL_AMD_blend_minmax_factor", extStart, extEnd);
+ GLEW_AMD_blend_minmax_factor = _glewSearchExtension("GL_AMD_blend_minmax_factor", extStart, extEnd);
#endif /* GL_AMD_blend_minmax_factor */
#ifdef GL_AMD_conservative_depth
- CONST_CAST(GLEW_AMD_conservative_depth) = _glewSearchExtension("GL_AMD_conservative_depth", extStart, extEnd);
+ GLEW_AMD_conservative_depth = _glewSearchExtension("GL_AMD_conservative_depth", extStart, extEnd);
#endif /* GL_AMD_conservative_depth */
#ifdef GL_AMD_debug_output
- CONST_CAST(GLEW_AMD_debug_output) = _glewSearchExtension("GL_AMD_debug_output", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_debug_output) CONST_CAST(GLEW_AMD_debug_output) = !_glewInit_GL_AMD_debug_output(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_debug_output = _glewSearchExtension("GL_AMD_debug_output", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_debug_output) GLEW_AMD_debug_output = !_glewInit_GL_AMD_debug_output(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_debug_output */
#ifdef GL_AMD_depth_clamp_separate
- CONST_CAST(GLEW_AMD_depth_clamp_separate) = _glewSearchExtension("GL_AMD_depth_clamp_separate", extStart, extEnd);
+ GLEW_AMD_depth_clamp_separate = _glewSearchExtension("GL_AMD_depth_clamp_separate", extStart, extEnd);
#endif /* GL_AMD_depth_clamp_separate */
#ifdef GL_AMD_draw_buffers_blend
- CONST_CAST(GLEW_AMD_draw_buffers_blend) = _glewSearchExtension("GL_AMD_draw_buffers_blend", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_draw_buffers_blend) CONST_CAST(GLEW_AMD_draw_buffers_blend) = !_glewInit_GL_AMD_draw_buffers_blend(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_draw_buffers_blend = _glewSearchExtension("GL_AMD_draw_buffers_blend", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_draw_buffers_blend) GLEW_AMD_draw_buffers_blend = !_glewInit_GL_AMD_draw_buffers_blend(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_draw_buffers_blend */
+#ifdef GL_AMD_gcn_shader
+ GLEW_AMD_gcn_shader = _glewSearchExtension("GL_AMD_gcn_shader", extStart, extEnd);
+#endif /* GL_AMD_gcn_shader */
+#ifdef GL_AMD_gpu_shader_int64
+ GLEW_AMD_gpu_shader_int64 = _glewSearchExtension("GL_AMD_gpu_shader_int64", extStart, extEnd);
+#endif /* GL_AMD_gpu_shader_int64 */
#ifdef GL_AMD_interleaved_elements
- CONST_CAST(GLEW_AMD_interleaved_elements) = _glewSearchExtension("GL_AMD_interleaved_elements", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_interleaved_elements) CONST_CAST(GLEW_AMD_interleaved_elements) = !_glewInit_GL_AMD_interleaved_elements(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_interleaved_elements = _glewSearchExtension("GL_AMD_interleaved_elements", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_interleaved_elements) GLEW_AMD_interleaved_elements = !_glewInit_GL_AMD_interleaved_elements(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_interleaved_elements */
#ifdef GL_AMD_multi_draw_indirect
- CONST_CAST(GLEW_AMD_multi_draw_indirect) = _glewSearchExtension("GL_AMD_multi_draw_indirect", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_multi_draw_indirect) CONST_CAST(GLEW_AMD_multi_draw_indirect) = !_glewInit_GL_AMD_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_multi_draw_indirect = _glewSearchExtension("GL_AMD_multi_draw_indirect", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_multi_draw_indirect) GLEW_AMD_multi_draw_indirect = !_glewInit_GL_AMD_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_multi_draw_indirect */
#ifdef GL_AMD_name_gen_delete
- CONST_CAST(GLEW_AMD_name_gen_delete) = _glewSearchExtension("GL_AMD_name_gen_delete", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_name_gen_delete) CONST_CAST(GLEW_AMD_name_gen_delete) = !_glewInit_GL_AMD_name_gen_delete(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_name_gen_delete = _glewSearchExtension("GL_AMD_name_gen_delete", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_name_gen_delete) GLEW_AMD_name_gen_delete = !_glewInit_GL_AMD_name_gen_delete(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_name_gen_delete */
+#ifdef GL_AMD_occlusion_query_event
+ GLEW_AMD_occlusion_query_event = _glewSearchExtension("GL_AMD_occlusion_query_event", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_occlusion_query_event) GLEW_AMD_occlusion_query_event = !_glewInit_GL_AMD_occlusion_query_event(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_AMD_occlusion_query_event */
#ifdef GL_AMD_performance_monitor
- CONST_CAST(GLEW_AMD_performance_monitor) = _glewSearchExtension("GL_AMD_performance_monitor", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_performance_monitor) CONST_CAST(GLEW_AMD_performance_monitor) = !_glewInit_GL_AMD_performance_monitor(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_performance_monitor = _glewSearchExtension("GL_AMD_performance_monitor", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_performance_monitor) GLEW_AMD_performance_monitor = !_glewInit_GL_AMD_performance_monitor(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_performance_monitor */
#ifdef GL_AMD_pinned_memory
- CONST_CAST(GLEW_AMD_pinned_memory) = _glewSearchExtension("GL_AMD_pinned_memory", extStart, extEnd);
+ GLEW_AMD_pinned_memory = _glewSearchExtension("GL_AMD_pinned_memory", extStart, extEnd);
#endif /* GL_AMD_pinned_memory */
#ifdef GL_AMD_query_buffer_object
- CONST_CAST(GLEW_AMD_query_buffer_object) = _glewSearchExtension("GL_AMD_query_buffer_object", extStart, extEnd);
+ GLEW_AMD_query_buffer_object = _glewSearchExtension("GL_AMD_query_buffer_object", extStart, extEnd);
#endif /* GL_AMD_query_buffer_object */
#ifdef GL_AMD_sample_positions
- CONST_CAST(GLEW_AMD_sample_positions) = _glewSearchExtension("GL_AMD_sample_positions", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_sample_positions) CONST_CAST(GLEW_AMD_sample_positions) = !_glewInit_GL_AMD_sample_positions(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_sample_positions = _glewSearchExtension("GL_AMD_sample_positions", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_sample_positions) GLEW_AMD_sample_positions = !_glewInit_GL_AMD_sample_positions(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_sample_positions */
#ifdef GL_AMD_seamless_cubemap_per_texture
- CONST_CAST(GLEW_AMD_seamless_cubemap_per_texture) = _glewSearchExtension("GL_AMD_seamless_cubemap_per_texture", extStart, extEnd);
+ GLEW_AMD_seamless_cubemap_per_texture = _glewSearchExtension("GL_AMD_seamless_cubemap_per_texture", extStart, extEnd);
#endif /* GL_AMD_seamless_cubemap_per_texture */
+#ifdef GL_AMD_shader_atomic_counter_ops
+ GLEW_AMD_shader_atomic_counter_ops = _glewSearchExtension("GL_AMD_shader_atomic_counter_ops", extStart, extEnd);
+#endif /* GL_AMD_shader_atomic_counter_ops */
#ifdef GL_AMD_shader_stencil_export
- CONST_CAST(GLEW_AMD_shader_stencil_export) = _glewSearchExtension("GL_AMD_shader_stencil_export", extStart, extEnd);
+ GLEW_AMD_shader_stencil_export = _glewSearchExtension("GL_AMD_shader_stencil_export", extStart, extEnd);
#endif /* GL_AMD_shader_stencil_export */
+#ifdef GL_AMD_shader_stencil_value_export
+ GLEW_AMD_shader_stencil_value_export = _glewSearchExtension("GL_AMD_shader_stencil_value_export", extStart, extEnd);
+#endif /* GL_AMD_shader_stencil_value_export */
#ifdef GL_AMD_shader_trinary_minmax
- CONST_CAST(GLEW_AMD_shader_trinary_minmax) = _glewSearchExtension("GL_AMD_shader_trinary_minmax", extStart, extEnd);
+ GLEW_AMD_shader_trinary_minmax = _glewSearchExtension("GL_AMD_shader_trinary_minmax", extStart, extEnd);
#endif /* GL_AMD_shader_trinary_minmax */
#ifdef GL_AMD_sparse_texture
- CONST_CAST(GLEW_AMD_sparse_texture) = _glewSearchExtension("GL_AMD_sparse_texture", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_sparse_texture) CONST_CAST(GLEW_AMD_sparse_texture) = !_glewInit_GL_AMD_sparse_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_sparse_texture = _glewSearchExtension("GL_AMD_sparse_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_sparse_texture) GLEW_AMD_sparse_texture = !_glewInit_GL_AMD_sparse_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_sparse_texture */
#ifdef GL_AMD_stencil_operation_extended
- CONST_CAST(GLEW_AMD_stencil_operation_extended) = _glewSearchExtension("GL_AMD_stencil_operation_extended", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_stencil_operation_extended) CONST_CAST(GLEW_AMD_stencil_operation_extended) = !_glewInit_GL_AMD_stencil_operation_extended(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_stencil_operation_extended = _glewSearchExtension("GL_AMD_stencil_operation_extended", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_stencil_operation_extended) GLEW_AMD_stencil_operation_extended = !_glewInit_GL_AMD_stencil_operation_extended(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_stencil_operation_extended */
#ifdef GL_AMD_texture_texture4
- CONST_CAST(GLEW_AMD_texture_texture4) = _glewSearchExtension("GL_AMD_texture_texture4", extStart, extEnd);
+ GLEW_AMD_texture_texture4 = _glewSearchExtension("GL_AMD_texture_texture4", extStart, extEnd);
#endif /* GL_AMD_texture_texture4 */
#ifdef GL_AMD_transform_feedback3_lines_triangles
- CONST_CAST(GLEW_AMD_transform_feedback3_lines_triangles) = _glewSearchExtension("GL_AMD_transform_feedback3_lines_triangles", extStart, extEnd);
+ GLEW_AMD_transform_feedback3_lines_triangles = _glewSearchExtension("GL_AMD_transform_feedback3_lines_triangles", extStart, extEnd);
#endif /* GL_AMD_transform_feedback3_lines_triangles */
+#ifdef GL_AMD_transform_feedback4
+ GLEW_AMD_transform_feedback4 = _glewSearchExtension("GL_AMD_transform_feedback4", extStart, extEnd);
+#endif /* GL_AMD_transform_feedback4 */
#ifdef GL_AMD_vertex_shader_layer
- CONST_CAST(GLEW_AMD_vertex_shader_layer) = _glewSearchExtension("GL_AMD_vertex_shader_layer", extStart, extEnd);
+ GLEW_AMD_vertex_shader_layer = _glewSearchExtension("GL_AMD_vertex_shader_layer", extStart, extEnd);
#endif /* GL_AMD_vertex_shader_layer */
#ifdef GL_AMD_vertex_shader_tessellator
- CONST_CAST(GLEW_AMD_vertex_shader_tessellator) = _glewSearchExtension("GL_AMD_vertex_shader_tessellator", extStart, extEnd);
- if (glewExperimental || GLEW_AMD_vertex_shader_tessellator) CONST_CAST(GLEW_AMD_vertex_shader_tessellator) = !_glewInit_GL_AMD_vertex_shader_tessellator(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_AMD_vertex_shader_tessellator = _glewSearchExtension("GL_AMD_vertex_shader_tessellator", extStart, extEnd);
+ if (glewExperimental || GLEW_AMD_vertex_shader_tessellator) GLEW_AMD_vertex_shader_tessellator = !_glewInit_GL_AMD_vertex_shader_tessellator(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_AMD_vertex_shader_tessellator */
#ifdef GL_AMD_vertex_shader_viewport_index
- CONST_CAST(GLEW_AMD_vertex_shader_viewport_index) = _glewSearchExtension("GL_AMD_vertex_shader_viewport_index", extStart, extEnd);
+ GLEW_AMD_vertex_shader_viewport_index = _glewSearchExtension("GL_AMD_vertex_shader_viewport_index", extStart, extEnd);
#endif /* GL_AMD_vertex_shader_viewport_index */
#ifdef GL_ANGLE_depth_texture
- CONST_CAST(GLEW_ANGLE_depth_texture) = _glewSearchExtension("GL_ANGLE_depth_texture", extStart, extEnd);
+ GLEW_ANGLE_depth_texture = _glewSearchExtension("GL_ANGLE_depth_texture", extStart, extEnd);
#endif /* GL_ANGLE_depth_texture */
#ifdef GL_ANGLE_framebuffer_blit
- CONST_CAST(GLEW_ANGLE_framebuffer_blit) = _glewSearchExtension("GL_ANGLE_framebuffer_blit", extStart, extEnd);
- if (glewExperimental || GLEW_ANGLE_framebuffer_blit) CONST_CAST(GLEW_ANGLE_framebuffer_blit) = !_glewInit_GL_ANGLE_framebuffer_blit(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ANGLE_framebuffer_blit = _glewSearchExtension("GL_ANGLE_framebuffer_blit", extStart, extEnd);
+ if (glewExperimental || GLEW_ANGLE_framebuffer_blit) GLEW_ANGLE_framebuffer_blit = !_glewInit_GL_ANGLE_framebuffer_blit(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ANGLE_framebuffer_blit */
#ifdef GL_ANGLE_framebuffer_multisample
- CONST_CAST(GLEW_ANGLE_framebuffer_multisample) = _glewSearchExtension("GL_ANGLE_framebuffer_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_ANGLE_framebuffer_multisample) CONST_CAST(GLEW_ANGLE_framebuffer_multisample) = !_glewInit_GL_ANGLE_framebuffer_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ANGLE_framebuffer_multisample = _glewSearchExtension("GL_ANGLE_framebuffer_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_ANGLE_framebuffer_multisample) GLEW_ANGLE_framebuffer_multisample = !_glewInit_GL_ANGLE_framebuffer_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ANGLE_framebuffer_multisample */
#ifdef GL_ANGLE_instanced_arrays
- CONST_CAST(GLEW_ANGLE_instanced_arrays) = _glewSearchExtension("GL_ANGLE_instanced_arrays", extStart, extEnd);
- if (glewExperimental || GLEW_ANGLE_instanced_arrays) CONST_CAST(GLEW_ANGLE_instanced_arrays) = !_glewInit_GL_ANGLE_instanced_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ANGLE_instanced_arrays = _glewSearchExtension("GL_ANGLE_instanced_arrays", extStart, extEnd);
+ if (glewExperimental || GLEW_ANGLE_instanced_arrays) GLEW_ANGLE_instanced_arrays = !_glewInit_GL_ANGLE_instanced_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ANGLE_instanced_arrays */
#ifdef GL_ANGLE_pack_reverse_row_order
- CONST_CAST(GLEW_ANGLE_pack_reverse_row_order) = _glewSearchExtension("GL_ANGLE_pack_reverse_row_order", extStart, extEnd);
+ GLEW_ANGLE_pack_reverse_row_order = _glewSearchExtension("GL_ANGLE_pack_reverse_row_order", extStart, extEnd);
#endif /* GL_ANGLE_pack_reverse_row_order */
#ifdef GL_ANGLE_program_binary
- CONST_CAST(GLEW_ANGLE_program_binary) = _glewSearchExtension("GL_ANGLE_program_binary", extStart, extEnd);
+ GLEW_ANGLE_program_binary = _glewSearchExtension("GL_ANGLE_program_binary", extStart, extEnd);
#endif /* GL_ANGLE_program_binary */
#ifdef GL_ANGLE_texture_compression_dxt1
- CONST_CAST(GLEW_ANGLE_texture_compression_dxt1) = _glewSearchExtension("GL_ANGLE_texture_compression_dxt1", extStart, extEnd);
+ GLEW_ANGLE_texture_compression_dxt1 = _glewSearchExtension("GL_ANGLE_texture_compression_dxt1", extStart, extEnd);
#endif /* GL_ANGLE_texture_compression_dxt1 */
#ifdef GL_ANGLE_texture_compression_dxt3
- CONST_CAST(GLEW_ANGLE_texture_compression_dxt3) = _glewSearchExtension("GL_ANGLE_texture_compression_dxt3", extStart, extEnd);
+ GLEW_ANGLE_texture_compression_dxt3 = _glewSearchExtension("GL_ANGLE_texture_compression_dxt3", extStart, extEnd);
#endif /* GL_ANGLE_texture_compression_dxt3 */
#ifdef GL_ANGLE_texture_compression_dxt5
- CONST_CAST(GLEW_ANGLE_texture_compression_dxt5) = _glewSearchExtension("GL_ANGLE_texture_compression_dxt5", extStart, extEnd);
+ GLEW_ANGLE_texture_compression_dxt5 = _glewSearchExtension("GL_ANGLE_texture_compression_dxt5", extStart, extEnd);
#endif /* GL_ANGLE_texture_compression_dxt5 */
#ifdef GL_ANGLE_texture_usage
- CONST_CAST(GLEW_ANGLE_texture_usage) = _glewSearchExtension("GL_ANGLE_texture_usage", extStart, extEnd);
+ GLEW_ANGLE_texture_usage = _glewSearchExtension("GL_ANGLE_texture_usage", extStart, extEnd);
#endif /* GL_ANGLE_texture_usage */
#ifdef GL_ANGLE_timer_query
- CONST_CAST(GLEW_ANGLE_timer_query) = _glewSearchExtension("GL_ANGLE_timer_query", extStart, extEnd);
- if (glewExperimental || GLEW_ANGLE_timer_query) CONST_CAST(GLEW_ANGLE_timer_query) = !_glewInit_GL_ANGLE_timer_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ANGLE_timer_query = _glewSearchExtension("GL_ANGLE_timer_query", extStart, extEnd);
+ if (glewExperimental || GLEW_ANGLE_timer_query) GLEW_ANGLE_timer_query = !_glewInit_GL_ANGLE_timer_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ANGLE_timer_query */
#ifdef GL_ANGLE_translated_shader_source
- CONST_CAST(GLEW_ANGLE_translated_shader_source) = _glewSearchExtension("GL_ANGLE_translated_shader_source", extStart, extEnd);
- if (glewExperimental || GLEW_ANGLE_translated_shader_source) CONST_CAST(GLEW_ANGLE_translated_shader_source) = !_glewInit_GL_ANGLE_translated_shader_source(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ANGLE_translated_shader_source = _glewSearchExtension("GL_ANGLE_translated_shader_source", extStart, extEnd);
+ if (glewExperimental || GLEW_ANGLE_translated_shader_source) GLEW_ANGLE_translated_shader_source = !_glewInit_GL_ANGLE_translated_shader_source(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ANGLE_translated_shader_source */
#ifdef GL_APPLE_aux_depth_stencil
- CONST_CAST(GLEW_APPLE_aux_depth_stencil) = _glewSearchExtension("GL_APPLE_aux_depth_stencil", extStart, extEnd);
+ GLEW_APPLE_aux_depth_stencil = _glewSearchExtension("GL_APPLE_aux_depth_stencil", extStart, extEnd);
#endif /* GL_APPLE_aux_depth_stencil */
#ifdef GL_APPLE_client_storage
- CONST_CAST(GLEW_APPLE_client_storage) = _glewSearchExtension("GL_APPLE_client_storage", extStart, extEnd);
+ GLEW_APPLE_client_storage = _glewSearchExtension("GL_APPLE_client_storage", extStart, extEnd);
#endif /* GL_APPLE_client_storage */
#ifdef GL_APPLE_element_array
- CONST_CAST(GLEW_APPLE_element_array) = _glewSearchExtension("GL_APPLE_element_array", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_element_array) CONST_CAST(GLEW_APPLE_element_array) = !_glewInit_GL_APPLE_element_array(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_element_array = _glewSearchExtension("GL_APPLE_element_array", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_element_array) GLEW_APPLE_element_array = !_glewInit_GL_APPLE_element_array(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_element_array */
#ifdef GL_APPLE_fence
- CONST_CAST(GLEW_APPLE_fence) = _glewSearchExtension("GL_APPLE_fence", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_fence) CONST_CAST(GLEW_APPLE_fence) = !_glewInit_GL_APPLE_fence(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_fence = _glewSearchExtension("GL_APPLE_fence", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_fence) GLEW_APPLE_fence = !_glewInit_GL_APPLE_fence(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_fence */
#ifdef GL_APPLE_float_pixels
- CONST_CAST(GLEW_APPLE_float_pixels) = _glewSearchExtension("GL_APPLE_float_pixels", extStart, extEnd);
+ GLEW_APPLE_float_pixels = _glewSearchExtension("GL_APPLE_float_pixels", extStart, extEnd);
#endif /* GL_APPLE_float_pixels */
#ifdef GL_APPLE_flush_buffer_range
- CONST_CAST(GLEW_APPLE_flush_buffer_range) = _glewSearchExtension("GL_APPLE_flush_buffer_range", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_flush_buffer_range) CONST_CAST(GLEW_APPLE_flush_buffer_range) = !_glewInit_GL_APPLE_flush_buffer_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_flush_buffer_range = _glewSearchExtension("GL_APPLE_flush_buffer_range", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_flush_buffer_range) GLEW_APPLE_flush_buffer_range = !_glewInit_GL_APPLE_flush_buffer_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_flush_buffer_range */
#ifdef GL_APPLE_object_purgeable
- CONST_CAST(GLEW_APPLE_object_purgeable) = _glewSearchExtension("GL_APPLE_object_purgeable", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_object_purgeable) CONST_CAST(GLEW_APPLE_object_purgeable) = !_glewInit_GL_APPLE_object_purgeable(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_object_purgeable = _glewSearchExtension("GL_APPLE_object_purgeable", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_object_purgeable) GLEW_APPLE_object_purgeable = !_glewInit_GL_APPLE_object_purgeable(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_object_purgeable */
#ifdef GL_APPLE_pixel_buffer
- CONST_CAST(GLEW_APPLE_pixel_buffer) = _glewSearchExtension("GL_APPLE_pixel_buffer", extStart, extEnd);
+ GLEW_APPLE_pixel_buffer = _glewSearchExtension("GL_APPLE_pixel_buffer", extStart, extEnd);
#endif /* GL_APPLE_pixel_buffer */
#ifdef GL_APPLE_rgb_422
- CONST_CAST(GLEW_APPLE_rgb_422) = _glewSearchExtension("GL_APPLE_rgb_422", extStart, extEnd);
+ GLEW_APPLE_rgb_422 = _glewSearchExtension("GL_APPLE_rgb_422", extStart, extEnd);
#endif /* GL_APPLE_rgb_422 */
#ifdef GL_APPLE_row_bytes
- CONST_CAST(GLEW_APPLE_row_bytes) = _glewSearchExtension("GL_APPLE_row_bytes", extStart, extEnd);
+ GLEW_APPLE_row_bytes = _glewSearchExtension("GL_APPLE_row_bytes", extStart, extEnd);
#endif /* GL_APPLE_row_bytes */
#ifdef GL_APPLE_specular_vector
- CONST_CAST(GLEW_APPLE_specular_vector) = _glewSearchExtension("GL_APPLE_specular_vector", extStart, extEnd);
+ GLEW_APPLE_specular_vector = _glewSearchExtension("GL_APPLE_specular_vector", extStart, extEnd);
#endif /* GL_APPLE_specular_vector */
#ifdef GL_APPLE_texture_range
- CONST_CAST(GLEW_APPLE_texture_range) = _glewSearchExtension("GL_APPLE_texture_range", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_texture_range) CONST_CAST(GLEW_APPLE_texture_range) = !_glewInit_GL_APPLE_texture_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_texture_range = _glewSearchExtension("GL_APPLE_texture_range", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_texture_range) GLEW_APPLE_texture_range = !_glewInit_GL_APPLE_texture_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_texture_range */
#ifdef GL_APPLE_transform_hint
- CONST_CAST(GLEW_APPLE_transform_hint) = _glewSearchExtension("GL_APPLE_transform_hint", extStart, extEnd);
+ GLEW_APPLE_transform_hint = _glewSearchExtension("GL_APPLE_transform_hint", extStart, extEnd);
#endif /* GL_APPLE_transform_hint */
#ifdef GL_APPLE_vertex_array_object
- CONST_CAST(GLEW_APPLE_vertex_array_object) = _glewSearchExtension("GL_APPLE_vertex_array_object", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_vertex_array_object) CONST_CAST(GLEW_APPLE_vertex_array_object) = !_glewInit_GL_APPLE_vertex_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_vertex_array_object = _glewSearchExtension("GL_APPLE_vertex_array_object", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_vertex_array_object) GLEW_APPLE_vertex_array_object = !_glewInit_GL_APPLE_vertex_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_vertex_array_object */
#ifdef GL_APPLE_vertex_array_range
- CONST_CAST(GLEW_APPLE_vertex_array_range) = _glewSearchExtension("GL_APPLE_vertex_array_range", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_vertex_array_range) CONST_CAST(GLEW_APPLE_vertex_array_range) = !_glewInit_GL_APPLE_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_vertex_array_range = _glewSearchExtension("GL_APPLE_vertex_array_range", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_vertex_array_range) GLEW_APPLE_vertex_array_range = !_glewInit_GL_APPLE_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_vertex_array_range */
#ifdef GL_APPLE_vertex_program_evaluators
- CONST_CAST(GLEW_APPLE_vertex_program_evaluators) = _glewSearchExtension("GL_APPLE_vertex_program_evaluators", extStart, extEnd);
- if (glewExperimental || GLEW_APPLE_vertex_program_evaluators) CONST_CAST(GLEW_APPLE_vertex_program_evaluators) = !_glewInit_GL_APPLE_vertex_program_evaluators(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_APPLE_vertex_program_evaluators = _glewSearchExtension("GL_APPLE_vertex_program_evaluators", extStart, extEnd);
+ if (glewExperimental || GLEW_APPLE_vertex_program_evaluators) GLEW_APPLE_vertex_program_evaluators = !_glewInit_GL_APPLE_vertex_program_evaluators(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_APPLE_vertex_program_evaluators */
#ifdef GL_APPLE_ycbcr_422
- CONST_CAST(GLEW_APPLE_ycbcr_422) = _glewSearchExtension("GL_APPLE_ycbcr_422", extStart, extEnd);
+ GLEW_APPLE_ycbcr_422 = _glewSearchExtension("GL_APPLE_ycbcr_422", extStart, extEnd);
#endif /* GL_APPLE_ycbcr_422 */
#ifdef GL_ARB_ES2_compatibility
- CONST_CAST(GLEW_ARB_ES2_compatibility) = _glewSearchExtension("GL_ARB_ES2_compatibility", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_ES2_compatibility) CONST_CAST(GLEW_ARB_ES2_compatibility) = !_glewInit_GL_ARB_ES2_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_ES2_compatibility = _glewSearchExtension("GL_ARB_ES2_compatibility", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_ES2_compatibility) GLEW_ARB_ES2_compatibility = !_glewInit_GL_ARB_ES2_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_ES2_compatibility */
+#ifdef GL_ARB_ES3_1_compatibility
+ GLEW_ARB_ES3_1_compatibility = _glewSearchExtension("GL_ARB_ES3_1_compatibility", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_ES3_1_compatibility) GLEW_ARB_ES3_1_compatibility = !_glewInit_GL_ARB_ES3_1_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_ES3_1_compatibility */
+#ifdef GL_ARB_ES3_2_compatibility
+ GLEW_ARB_ES3_2_compatibility = _glewSearchExtension("GL_ARB_ES3_2_compatibility", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_ES3_2_compatibility) GLEW_ARB_ES3_2_compatibility = !_glewInit_GL_ARB_ES3_2_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_ES3_2_compatibility */
#ifdef GL_ARB_ES3_compatibility
- CONST_CAST(GLEW_ARB_ES3_compatibility) = _glewSearchExtension("GL_ARB_ES3_compatibility", extStart, extEnd);
+ GLEW_ARB_ES3_compatibility = _glewSearchExtension("GL_ARB_ES3_compatibility", extStart, extEnd);
#endif /* GL_ARB_ES3_compatibility */
#ifdef GL_ARB_arrays_of_arrays
- CONST_CAST(GLEW_ARB_arrays_of_arrays) = _glewSearchExtension("GL_ARB_arrays_of_arrays", extStart, extEnd);
+ GLEW_ARB_arrays_of_arrays = _glewSearchExtension("GL_ARB_arrays_of_arrays", extStart, extEnd);
#endif /* GL_ARB_arrays_of_arrays */
#ifdef GL_ARB_base_instance
- CONST_CAST(GLEW_ARB_base_instance) = _glewSearchExtension("GL_ARB_base_instance", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_base_instance) CONST_CAST(GLEW_ARB_base_instance) = !_glewInit_GL_ARB_base_instance(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_base_instance = _glewSearchExtension("GL_ARB_base_instance", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_base_instance) GLEW_ARB_base_instance = !_glewInit_GL_ARB_base_instance(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_base_instance */
#ifdef GL_ARB_bindless_texture
- CONST_CAST(GLEW_ARB_bindless_texture) = _glewSearchExtension("GL_ARB_bindless_texture", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_bindless_texture) CONST_CAST(GLEW_ARB_bindless_texture) = !_glewInit_GL_ARB_bindless_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_bindless_texture = _glewSearchExtension("GL_ARB_bindless_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_bindless_texture) GLEW_ARB_bindless_texture = !_glewInit_GL_ARB_bindless_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_bindless_texture */
#ifdef GL_ARB_blend_func_extended
- CONST_CAST(GLEW_ARB_blend_func_extended) = _glewSearchExtension("GL_ARB_blend_func_extended", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_blend_func_extended) CONST_CAST(GLEW_ARB_blend_func_extended) = !_glewInit_GL_ARB_blend_func_extended(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_blend_func_extended = _glewSearchExtension("GL_ARB_blend_func_extended", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_blend_func_extended) GLEW_ARB_blend_func_extended = !_glewInit_GL_ARB_blend_func_extended(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_blend_func_extended */
#ifdef GL_ARB_buffer_storage
- CONST_CAST(GLEW_ARB_buffer_storage) = _glewSearchExtension("GL_ARB_buffer_storage", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_buffer_storage) CONST_CAST(GLEW_ARB_buffer_storage) = !_glewInit_GL_ARB_buffer_storage(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_buffer_storage = _glewSearchExtension("GL_ARB_buffer_storage", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_buffer_storage) GLEW_ARB_buffer_storage = !_glewInit_GL_ARB_buffer_storage(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_buffer_storage */
#ifdef GL_ARB_cl_event
- CONST_CAST(GLEW_ARB_cl_event) = _glewSearchExtension("GL_ARB_cl_event", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_cl_event) CONST_CAST(GLEW_ARB_cl_event) = !_glewInit_GL_ARB_cl_event(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_cl_event = _glewSearchExtension("GL_ARB_cl_event", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_cl_event) GLEW_ARB_cl_event = !_glewInit_GL_ARB_cl_event(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_cl_event */
#ifdef GL_ARB_clear_buffer_object
- CONST_CAST(GLEW_ARB_clear_buffer_object) = _glewSearchExtension("GL_ARB_clear_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_clear_buffer_object) CONST_CAST(GLEW_ARB_clear_buffer_object) = !_glewInit_GL_ARB_clear_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_clear_buffer_object = _glewSearchExtension("GL_ARB_clear_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_clear_buffer_object) GLEW_ARB_clear_buffer_object = !_glewInit_GL_ARB_clear_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_clear_buffer_object */
#ifdef GL_ARB_clear_texture
- CONST_CAST(GLEW_ARB_clear_texture) = _glewSearchExtension("GL_ARB_clear_texture", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_clear_texture) CONST_CAST(GLEW_ARB_clear_texture) = !_glewInit_GL_ARB_clear_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_clear_texture = _glewSearchExtension("GL_ARB_clear_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_clear_texture) GLEW_ARB_clear_texture = !_glewInit_GL_ARB_clear_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_clear_texture */
+#ifdef GL_ARB_clip_control
+ GLEW_ARB_clip_control = _glewSearchExtension("GL_ARB_clip_control", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_clip_control) GLEW_ARB_clip_control = !_glewInit_GL_ARB_clip_control(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_clip_control */
#ifdef GL_ARB_color_buffer_float
- CONST_CAST(GLEW_ARB_color_buffer_float) = _glewSearchExtension("GL_ARB_color_buffer_float", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_color_buffer_float) CONST_CAST(GLEW_ARB_color_buffer_float) = !_glewInit_GL_ARB_color_buffer_float(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_color_buffer_float = _glewSearchExtension("GL_ARB_color_buffer_float", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_color_buffer_float) GLEW_ARB_color_buffer_float = !_glewInit_GL_ARB_color_buffer_float(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_color_buffer_float */
#ifdef GL_ARB_compatibility
- CONST_CAST(GLEW_ARB_compatibility) = _glewSearchExtension("GL_ARB_compatibility", extStart, extEnd);
+ GLEW_ARB_compatibility = _glewSearchExtension("GL_ARB_compatibility", extStart, extEnd);
#endif /* GL_ARB_compatibility */
#ifdef GL_ARB_compressed_texture_pixel_storage
- CONST_CAST(GLEW_ARB_compressed_texture_pixel_storage) = _glewSearchExtension("GL_ARB_compressed_texture_pixel_storage", extStart, extEnd);
+ GLEW_ARB_compressed_texture_pixel_storage = _glewSearchExtension("GL_ARB_compressed_texture_pixel_storage", extStart, extEnd);
#endif /* GL_ARB_compressed_texture_pixel_storage */
#ifdef GL_ARB_compute_shader
- CONST_CAST(GLEW_ARB_compute_shader) = _glewSearchExtension("GL_ARB_compute_shader", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_compute_shader) CONST_CAST(GLEW_ARB_compute_shader) = !_glewInit_GL_ARB_compute_shader(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_compute_shader = _glewSearchExtension("GL_ARB_compute_shader", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_compute_shader) GLEW_ARB_compute_shader = !_glewInit_GL_ARB_compute_shader(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_compute_shader */
#ifdef GL_ARB_compute_variable_group_size
- CONST_CAST(GLEW_ARB_compute_variable_group_size) = _glewSearchExtension("GL_ARB_compute_variable_group_size", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_compute_variable_group_size) CONST_CAST(GLEW_ARB_compute_variable_group_size) = !_glewInit_GL_ARB_compute_variable_group_size(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_compute_variable_group_size = _glewSearchExtension("GL_ARB_compute_variable_group_size", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_compute_variable_group_size) GLEW_ARB_compute_variable_group_size = !_glewInit_GL_ARB_compute_variable_group_size(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_compute_variable_group_size */
+#ifdef GL_ARB_conditional_render_inverted
+ GLEW_ARB_conditional_render_inverted = _glewSearchExtension("GL_ARB_conditional_render_inverted", extStart, extEnd);
+#endif /* GL_ARB_conditional_render_inverted */
#ifdef GL_ARB_conservative_depth
- CONST_CAST(GLEW_ARB_conservative_depth) = _glewSearchExtension("GL_ARB_conservative_depth", extStart, extEnd);
+ GLEW_ARB_conservative_depth = _glewSearchExtension("GL_ARB_conservative_depth", extStart, extEnd);
#endif /* GL_ARB_conservative_depth */
#ifdef GL_ARB_copy_buffer
- CONST_CAST(GLEW_ARB_copy_buffer) = _glewSearchExtension("GL_ARB_copy_buffer", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_copy_buffer) CONST_CAST(GLEW_ARB_copy_buffer) = !_glewInit_GL_ARB_copy_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_copy_buffer = _glewSearchExtension("GL_ARB_copy_buffer", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_copy_buffer) GLEW_ARB_copy_buffer = !_glewInit_GL_ARB_copy_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_copy_buffer */
#ifdef GL_ARB_copy_image
- CONST_CAST(GLEW_ARB_copy_image) = _glewSearchExtension("GL_ARB_copy_image", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_copy_image) CONST_CAST(GLEW_ARB_copy_image) = !_glewInit_GL_ARB_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_copy_image = _glewSearchExtension("GL_ARB_copy_image", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_copy_image) GLEW_ARB_copy_image = !_glewInit_GL_ARB_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_copy_image */
+#ifdef GL_ARB_cull_distance
+ GLEW_ARB_cull_distance = _glewSearchExtension("GL_ARB_cull_distance", extStart, extEnd);
+#endif /* GL_ARB_cull_distance */
#ifdef GL_ARB_debug_output
- CONST_CAST(GLEW_ARB_debug_output) = _glewSearchExtension("GL_ARB_debug_output", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_debug_output) CONST_CAST(GLEW_ARB_debug_output) = !_glewInit_GL_ARB_debug_output(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_debug_output = _glewSearchExtension("GL_ARB_debug_output", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_debug_output) GLEW_ARB_debug_output = !_glewInit_GL_ARB_debug_output(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_debug_output */
#ifdef GL_ARB_depth_buffer_float
- CONST_CAST(GLEW_ARB_depth_buffer_float) = _glewSearchExtension("GL_ARB_depth_buffer_float", extStart, extEnd);
+ GLEW_ARB_depth_buffer_float = _glewSearchExtension("GL_ARB_depth_buffer_float", extStart, extEnd);
#endif /* GL_ARB_depth_buffer_float */
#ifdef GL_ARB_depth_clamp
- CONST_CAST(GLEW_ARB_depth_clamp) = _glewSearchExtension("GL_ARB_depth_clamp", extStart, extEnd);
+ GLEW_ARB_depth_clamp = _glewSearchExtension("GL_ARB_depth_clamp", extStart, extEnd);
#endif /* GL_ARB_depth_clamp */
#ifdef GL_ARB_depth_texture
- CONST_CAST(GLEW_ARB_depth_texture) = _glewSearchExtension("GL_ARB_depth_texture", extStart, extEnd);
+ GLEW_ARB_depth_texture = _glewSearchExtension("GL_ARB_depth_texture", extStart, extEnd);
#endif /* GL_ARB_depth_texture */
+#ifdef GL_ARB_derivative_control
+ GLEW_ARB_derivative_control = _glewSearchExtension("GL_ARB_derivative_control", extStart, extEnd);
+#endif /* GL_ARB_derivative_control */
+#ifdef GL_ARB_direct_state_access
+ GLEW_ARB_direct_state_access = _glewSearchExtension("GL_ARB_direct_state_access", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_direct_state_access) GLEW_ARB_direct_state_access = !_glewInit_GL_ARB_direct_state_access(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_direct_state_access */
#ifdef GL_ARB_draw_buffers
- CONST_CAST(GLEW_ARB_draw_buffers) = _glewSearchExtension("GL_ARB_draw_buffers", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_draw_buffers) CONST_CAST(GLEW_ARB_draw_buffers) = !_glewInit_GL_ARB_draw_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_draw_buffers = _glewSearchExtension("GL_ARB_draw_buffers", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_draw_buffers) GLEW_ARB_draw_buffers = !_glewInit_GL_ARB_draw_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_draw_buffers */
#ifdef GL_ARB_draw_buffers_blend
- CONST_CAST(GLEW_ARB_draw_buffers_blend) = _glewSearchExtension("GL_ARB_draw_buffers_blend", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_draw_buffers_blend) CONST_CAST(GLEW_ARB_draw_buffers_blend) = !_glewInit_GL_ARB_draw_buffers_blend(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_draw_buffers_blend = _glewSearchExtension("GL_ARB_draw_buffers_blend", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_draw_buffers_blend) GLEW_ARB_draw_buffers_blend = !_glewInit_GL_ARB_draw_buffers_blend(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_draw_buffers_blend */
#ifdef GL_ARB_draw_elements_base_vertex
- CONST_CAST(GLEW_ARB_draw_elements_base_vertex) = _glewSearchExtension("GL_ARB_draw_elements_base_vertex", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_draw_elements_base_vertex) CONST_CAST(GLEW_ARB_draw_elements_base_vertex) = !_glewInit_GL_ARB_draw_elements_base_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_draw_elements_base_vertex = _glewSearchExtension("GL_ARB_draw_elements_base_vertex", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_draw_elements_base_vertex) GLEW_ARB_draw_elements_base_vertex = !_glewInit_GL_ARB_draw_elements_base_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_draw_elements_base_vertex */
#ifdef GL_ARB_draw_indirect
- CONST_CAST(GLEW_ARB_draw_indirect) = _glewSearchExtension("GL_ARB_draw_indirect", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_draw_indirect) CONST_CAST(GLEW_ARB_draw_indirect) = !_glewInit_GL_ARB_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_draw_indirect = _glewSearchExtension("GL_ARB_draw_indirect", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_draw_indirect) GLEW_ARB_draw_indirect = !_glewInit_GL_ARB_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_draw_indirect */
#ifdef GL_ARB_draw_instanced
- CONST_CAST(GLEW_ARB_draw_instanced) = _glewSearchExtension("GL_ARB_draw_instanced", extStart, extEnd);
+ GLEW_ARB_draw_instanced = _glewSearchExtension("GL_ARB_draw_instanced", extStart, extEnd);
#endif /* GL_ARB_draw_instanced */
#ifdef GL_ARB_enhanced_layouts
- CONST_CAST(GLEW_ARB_enhanced_layouts) = _glewSearchExtension("GL_ARB_enhanced_layouts", extStart, extEnd);
+ GLEW_ARB_enhanced_layouts = _glewSearchExtension("GL_ARB_enhanced_layouts", extStart, extEnd);
#endif /* GL_ARB_enhanced_layouts */
#ifdef GL_ARB_explicit_attrib_location
- CONST_CAST(GLEW_ARB_explicit_attrib_location) = _glewSearchExtension("GL_ARB_explicit_attrib_location", extStart, extEnd);
+ GLEW_ARB_explicit_attrib_location = _glewSearchExtension("GL_ARB_explicit_attrib_location", extStart, extEnd);
#endif /* GL_ARB_explicit_attrib_location */
#ifdef GL_ARB_explicit_uniform_location
- CONST_CAST(GLEW_ARB_explicit_uniform_location) = _glewSearchExtension("GL_ARB_explicit_uniform_location", extStart, extEnd);
+ GLEW_ARB_explicit_uniform_location = _glewSearchExtension("GL_ARB_explicit_uniform_location", extStart, extEnd);
#endif /* GL_ARB_explicit_uniform_location */
#ifdef GL_ARB_fragment_coord_conventions
- CONST_CAST(GLEW_ARB_fragment_coord_conventions) = _glewSearchExtension("GL_ARB_fragment_coord_conventions", extStart, extEnd);
+ GLEW_ARB_fragment_coord_conventions = _glewSearchExtension("GL_ARB_fragment_coord_conventions", extStart, extEnd);
#endif /* GL_ARB_fragment_coord_conventions */
#ifdef GL_ARB_fragment_layer_viewport
- CONST_CAST(GLEW_ARB_fragment_layer_viewport) = _glewSearchExtension("GL_ARB_fragment_layer_viewport", extStart, extEnd);
+ GLEW_ARB_fragment_layer_viewport = _glewSearchExtension("GL_ARB_fragment_layer_viewport", extStart, extEnd);
#endif /* GL_ARB_fragment_layer_viewport */
#ifdef GL_ARB_fragment_program
- CONST_CAST(GLEW_ARB_fragment_program) = _glewSearchExtension("GL_ARB_fragment_program", extStart, extEnd);
+ GLEW_ARB_fragment_program = _glewSearchExtension("GL_ARB_fragment_program", extStart, extEnd);
#endif /* GL_ARB_fragment_program */
#ifdef GL_ARB_fragment_program_shadow
- CONST_CAST(GLEW_ARB_fragment_program_shadow) = _glewSearchExtension("GL_ARB_fragment_program_shadow", extStart, extEnd);
+ GLEW_ARB_fragment_program_shadow = _glewSearchExtension("GL_ARB_fragment_program_shadow", extStart, extEnd);
#endif /* GL_ARB_fragment_program_shadow */
#ifdef GL_ARB_fragment_shader
- CONST_CAST(GLEW_ARB_fragment_shader) = _glewSearchExtension("GL_ARB_fragment_shader", extStart, extEnd);
+ GLEW_ARB_fragment_shader = _glewSearchExtension("GL_ARB_fragment_shader", extStart, extEnd);
#endif /* GL_ARB_fragment_shader */
+#ifdef GL_ARB_fragment_shader_interlock
+ GLEW_ARB_fragment_shader_interlock = _glewSearchExtension("GL_ARB_fragment_shader_interlock", extStart, extEnd);
+#endif /* GL_ARB_fragment_shader_interlock */
#ifdef GL_ARB_framebuffer_no_attachments
- CONST_CAST(GLEW_ARB_framebuffer_no_attachments) = _glewSearchExtension("GL_ARB_framebuffer_no_attachments", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_framebuffer_no_attachments) CONST_CAST(GLEW_ARB_framebuffer_no_attachments) = !_glewInit_GL_ARB_framebuffer_no_attachments(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_framebuffer_no_attachments = _glewSearchExtension("GL_ARB_framebuffer_no_attachments", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_framebuffer_no_attachments) GLEW_ARB_framebuffer_no_attachments = !_glewInit_GL_ARB_framebuffer_no_attachments(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_framebuffer_no_attachments */
#ifdef GL_ARB_framebuffer_object
- CONST_CAST(GLEW_ARB_framebuffer_object) = _glewSearchExtension("GL_ARB_framebuffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_framebuffer_object) CONST_CAST(GLEW_ARB_framebuffer_object) = !_glewInit_GL_ARB_framebuffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_framebuffer_object = _glewSearchExtension("GL_ARB_framebuffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_framebuffer_object) GLEW_ARB_framebuffer_object = !_glewInit_GL_ARB_framebuffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_framebuffer_object */
#ifdef GL_ARB_framebuffer_sRGB
- CONST_CAST(GLEW_ARB_framebuffer_sRGB) = _glewSearchExtension("GL_ARB_framebuffer_sRGB", extStart, extEnd);
+ GLEW_ARB_framebuffer_sRGB = _glewSearchExtension("GL_ARB_framebuffer_sRGB", extStart, extEnd);
#endif /* GL_ARB_framebuffer_sRGB */
#ifdef GL_ARB_geometry_shader4
- CONST_CAST(GLEW_ARB_geometry_shader4) = _glewSearchExtension("GL_ARB_geometry_shader4", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_geometry_shader4) CONST_CAST(GLEW_ARB_geometry_shader4) = !_glewInit_GL_ARB_geometry_shader4(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_geometry_shader4 = _glewSearchExtension("GL_ARB_geometry_shader4", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_geometry_shader4) GLEW_ARB_geometry_shader4 = !_glewInit_GL_ARB_geometry_shader4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_geometry_shader4 */
#ifdef GL_ARB_get_program_binary
- CONST_CAST(GLEW_ARB_get_program_binary) = _glewSearchExtension("GL_ARB_get_program_binary", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_get_program_binary) CONST_CAST(GLEW_ARB_get_program_binary) = !_glewInit_GL_ARB_get_program_binary(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_get_program_binary = _glewSearchExtension("GL_ARB_get_program_binary", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_get_program_binary) GLEW_ARB_get_program_binary = !_glewInit_GL_ARB_get_program_binary(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_get_program_binary */
+#ifdef GL_ARB_get_texture_sub_image
+ GLEW_ARB_get_texture_sub_image = _glewSearchExtension("GL_ARB_get_texture_sub_image", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_get_texture_sub_image) GLEW_ARB_get_texture_sub_image = !_glewInit_GL_ARB_get_texture_sub_image(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_get_texture_sub_image */
#ifdef GL_ARB_gpu_shader5
- CONST_CAST(GLEW_ARB_gpu_shader5) = _glewSearchExtension("GL_ARB_gpu_shader5", extStart, extEnd);
+ GLEW_ARB_gpu_shader5 = _glewSearchExtension("GL_ARB_gpu_shader5", extStart, extEnd);
#endif /* GL_ARB_gpu_shader5 */
#ifdef GL_ARB_gpu_shader_fp64
- CONST_CAST(GLEW_ARB_gpu_shader_fp64) = _glewSearchExtension("GL_ARB_gpu_shader_fp64", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_gpu_shader_fp64) CONST_CAST(GLEW_ARB_gpu_shader_fp64) = !_glewInit_GL_ARB_gpu_shader_fp64(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_gpu_shader_fp64 = _glewSearchExtension("GL_ARB_gpu_shader_fp64", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_gpu_shader_fp64) GLEW_ARB_gpu_shader_fp64 = !_glewInit_GL_ARB_gpu_shader_fp64(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_gpu_shader_fp64 */
+#ifdef GL_ARB_gpu_shader_int64
+ GLEW_ARB_gpu_shader_int64 = _glewSearchExtension("GL_ARB_gpu_shader_int64", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_gpu_shader_int64) GLEW_ARB_gpu_shader_int64 = !_glewInit_GL_ARB_gpu_shader_int64(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_gpu_shader_int64 */
#ifdef GL_ARB_half_float_pixel
- CONST_CAST(GLEW_ARB_half_float_pixel) = _glewSearchExtension("GL_ARB_half_float_pixel", extStart, extEnd);
+ GLEW_ARB_half_float_pixel = _glewSearchExtension("GL_ARB_half_float_pixel", extStart, extEnd);
#endif /* GL_ARB_half_float_pixel */
#ifdef GL_ARB_half_float_vertex
- CONST_CAST(GLEW_ARB_half_float_vertex) = _glewSearchExtension("GL_ARB_half_float_vertex", extStart, extEnd);
+ GLEW_ARB_half_float_vertex = _glewSearchExtension("GL_ARB_half_float_vertex", extStart, extEnd);
#endif /* GL_ARB_half_float_vertex */
#ifdef GL_ARB_imaging
- CONST_CAST(GLEW_ARB_imaging) = _glewSearchExtension("GL_ARB_imaging", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_imaging) CONST_CAST(GLEW_ARB_imaging) = !_glewInit_GL_ARB_imaging(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_imaging = _glewSearchExtension("GL_ARB_imaging", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_imaging) GLEW_ARB_imaging = !_glewInit_GL_ARB_imaging(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_imaging */
#ifdef GL_ARB_indirect_parameters
- CONST_CAST(GLEW_ARB_indirect_parameters) = _glewSearchExtension("GL_ARB_indirect_parameters", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_indirect_parameters) CONST_CAST(GLEW_ARB_indirect_parameters) = !_glewInit_GL_ARB_indirect_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_indirect_parameters = _glewSearchExtension("GL_ARB_indirect_parameters", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_indirect_parameters) GLEW_ARB_indirect_parameters = !_glewInit_GL_ARB_indirect_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_indirect_parameters */
#ifdef GL_ARB_instanced_arrays
- CONST_CAST(GLEW_ARB_instanced_arrays) = _glewSearchExtension("GL_ARB_instanced_arrays", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_instanced_arrays) CONST_CAST(GLEW_ARB_instanced_arrays) = !_glewInit_GL_ARB_instanced_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_instanced_arrays = _glewSearchExtension("GL_ARB_instanced_arrays", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_instanced_arrays) GLEW_ARB_instanced_arrays = !_glewInit_GL_ARB_instanced_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_instanced_arrays */
#ifdef GL_ARB_internalformat_query
- CONST_CAST(GLEW_ARB_internalformat_query) = _glewSearchExtension("GL_ARB_internalformat_query", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_internalformat_query) CONST_CAST(GLEW_ARB_internalformat_query) = !_glewInit_GL_ARB_internalformat_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_internalformat_query = _glewSearchExtension("GL_ARB_internalformat_query", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_internalformat_query) GLEW_ARB_internalformat_query = !_glewInit_GL_ARB_internalformat_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_internalformat_query */
#ifdef GL_ARB_internalformat_query2
- CONST_CAST(GLEW_ARB_internalformat_query2) = _glewSearchExtension("GL_ARB_internalformat_query2", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_internalformat_query2) CONST_CAST(GLEW_ARB_internalformat_query2) = !_glewInit_GL_ARB_internalformat_query2(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_internalformat_query2 = _glewSearchExtension("GL_ARB_internalformat_query2", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_internalformat_query2) GLEW_ARB_internalformat_query2 = !_glewInit_GL_ARB_internalformat_query2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_internalformat_query2 */
#ifdef GL_ARB_invalidate_subdata
- CONST_CAST(GLEW_ARB_invalidate_subdata) = _glewSearchExtension("GL_ARB_invalidate_subdata", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_invalidate_subdata) CONST_CAST(GLEW_ARB_invalidate_subdata) = !_glewInit_GL_ARB_invalidate_subdata(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_invalidate_subdata = _glewSearchExtension("GL_ARB_invalidate_subdata", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_invalidate_subdata) GLEW_ARB_invalidate_subdata = !_glewInit_GL_ARB_invalidate_subdata(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_invalidate_subdata */
#ifdef GL_ARB_map_buffer_alignment
- CONST_CAST(GLEW_ARB_map_buffer_alignment) = _glewSearchExtension("GL_ARB_map_buffer_alignment", extStart, extEnd);
+ GLEW_ARB_map_buffer_alignment = _glewSearchExtension("GL_ARB_map_buffer_alignment", extStart, extEnd);
#endif /* GL_ARB_map_buffer_alignment */
#ifdef GL_ARB_map_buffer_range
- CONST_CAST(GLEW_ARB_map_buffer_range) = _glewSearchExtension("GL_ARB_map_buffer_range", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_map_buffer_range) CONST_CAST(GLEW_ARB_map_buffer_range) = !_glewInit_GL_ARB_map_buffer_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_map_buffer_range = _glewSearchExtension("GL_ARB_map_buffer_range", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_map_buffer_range) GLEW_ARB_map_buffer_range = !_glewInit_GL_ARB_map_buffer_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_map_buffer_range */
#ifdef GL_ARB_matrix_palette
- CONST_CAST(GLEW_ARB_matrix_palette) = _glewSearchExtension("GL_ARB_matrix_palette", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_matrix_palette) CONST_CAST(GLEW_ARB_matrix_palette) = !_glewInit_GL_ARB_matrix_palette(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_matrix_palette = _glewSearchExtension("GL_ARB_matrix_palette", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_matrix_palette) GLEW_ARB_matrix_palette = !_glewInit_GL_ARB_matrix_palette(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_matrix_palette */
#ifdef GL_ARB_multi_bind
- CONST_CAST(GLEW_ARB_multi_bind) = _glewSearchExtension("GL_ARB_multi_bind", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_multi_bind) CONST_CAST(GLEW_ARB_multi_bind) = !_glewInit_GL_ARB_multi_bind(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_multi_bind = _glewSearchExtension("GL_ARB_multi_bind", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_multi_bind) GLEW_ARB_multi_bind = !_glewInit_GL_ARB_multi_bind(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_multi_bind */
#ifdef GL_ARB_multi_draw_indirect
- CONST_CAST(GLEW_ARB_multi_draw_indirect) = _glewSearchExtension("GL_ARB_multi_draw_indirect", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_multi_draw_indirect) CONST_CAST(GLEW_ARB_multi_draw_indirect) = !_glewInit_GL_ARB_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_multi_draw_indirect = _glewSearchExtension("GL_ARB_multi_draw_indirect", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_multi_draw_indirect) GLEW_ARB_multi_draw_indirect = !_glewInit_GL_ARB_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_multi_draw_indirect */
#ifdef GL_ARB_multisample
- CONST_CAST(GLEW_ARB_multisample) = _glewSearchExtension("GL_ARB_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_multisample) CONST_CAST(GLEW_ARB_multisample) = !_glewInit_GL_ARB_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_multisample = _glewSearchExtension("GL_ARB_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_multisample) GLEW_ARB_multisample = !_glewInit_GL_ARB_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_multisample */
#ifdef GL_ARB_multitexture
- CONST_CAST(GLEW_ARB_multitexture) = _glewSearchExtension("GL_ARB_multitexture", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_multitexture) CONST_CAST(GLEW_ARB_multitexture) = !_glewInit_GL_ARB_multitexture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_multitexture = _glewSearchExtension("GL_ARB_multitexture", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_multitexture) GLEW_ARB_multitexture = !_glewInit_GL_ARB_multitexture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_multitexture */
#ifdef GL_ARB_occlusion_query
- CONST_CAST(GLEW_ARB_occlusion_query) = _glewSearchExtension("GL_ARB_occlusion_query", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_occlusion_query) CONST_CAST(GLEW_ARB_occlusion_query) = !_glewInit_GL_ARB_occlusion_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_occlusion_query = _glewSearchExtension("GL_ARB_occlusion_query", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_occlusion_query) GLEW_ARB_occlusion_query = !_glewInit_GL_ARB_occlusion_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_occlusion_query */
#ifdef GL_ARB_occlusion_query2
- CONST_CAST(GLEW_ARB_occlusion_query2) = _glewSearchExtension("GL_ARB_occlusion_query2", extStart, extEnd);
+ GLEW_ARB_occlusion_query2 = _glewSearchExtension("GL_ARB_occlusion_query2", extStart, extEnd);
#endif /* GL_ARB_occlusion_query2 */
+#ifdef GL_ARB_parallel_shader_compile
+ GLEW_ARB_parallel_shader_compile = _glewSearchExtension("GL_ARB_parallel_shader_compile", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_parallel_shader_compile) GLEW_ARB_parallel_shader_compile = !_glewInit_GL_ARB_parallel_shader_compile(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_parallel_shader_compile */
+#ifdef GL_ARB_pipeline_statistics_query
+ GLEW_ARB_pipeline_statistics_query = _glewSearchExtension("GL_ARB_pipeline_statistics_query", extStart, extEnd);
+#endif /* GL_ARB_pipeline_statistics_query */
#ifdef GL_ARB_pixel_buffer_object
- CONST_CAST(GLEW_ARB_pixel_buffer_object) = _glewSearchExtension("GL_ARB_pixel_buffer_object", extStart, extEnd);
+ GLEW_ARB_pixel_buffer_object = _glewSearchExtension("GL_ARB_pixel_buffer_object", extStart, extEnd);
#endif /* GL_ARB_pixel_buffer_object */
#ifdef GL_ARB_point_parameters
- CONST_CAST(GLEW_ARB_point_parameters) = _glewSearchExtension("GL_ARB_point_parameters", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_point_parameters) CONST_CAST(GLEW_ARB_point_parameters) = !_glewInit_GL_ARB_point_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_point_parameters = _glewSearchExtension("GL_ARB_point_parameters", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_point_parameters) GLEW_ARB_point_parameters = !_glewInit_GL_ARB_point_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_point_parameters */
#ifdef GL_ARB_point_sprite
- CONST_CAST(GLEW_ARB_point_sprite) = _glewSearchExtension("GL_ARB_point_sprite", extStart, extEnd);
+ GLEW_ARB_point_sprite = _glewSearchExtension("GL_ARB_point_sprite", extStart, extEnd);
#endif /* GL_ARB_point_sprite */
+#ifdef GL_ARB_post_depth_coverage
+ GLEW_ARB_post_depth_coverage = _glewSearchExtension("GL_ARB_post_depth_coverage", extStart, extEnd);
+#endif /* GL_ARB_post_depth_coverage */
#ifdef GL_ARB_program_interface_query
- CONST_CAST(GLEW_ARB_program_interface_query) = _glewSearchExtension("GL_ARB_program_interface_query", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_program_interface_query) CONST_CAST(GLEW_ARB_program_interface_query) = !_glewInit_GL_ARB_program_interface_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_program_interface_query = _glewSearchExtension("GL_ARB_program_interface_query", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_program_interface_query) GLEW_ARB_program_interface_query = !_glewInit_GL_ARB_program_interface_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_program_interface_query */
#ifdef GL_ARB_provoking_vertex
- CONST_CAST(GLEW_ARB_provoking_vertex) = _glewSearchExtension("GL_ARB_provoking_vertex", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_provoking_vertex) CONST_CAST(GLEW_ARB_provoking_vertex) = !_glewInit_GL_ARB_provoking_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_provoking_vertex = _glewSearchExtension("GL_ARB_provoking_vertex", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_provoking_vertex) GLEW_ARB_provoking_vertex = !_glewInit_GL_ARB_provoking_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_provoking_vertex */
#ifdef GL_ARB_query_buffer_object
- CONST_CAST(GLEW_ARB_query_buffer_object) = _glewSearchExtension("GL_ARB_query_buffer_object", extStart, extEnd);
+ GLEW_ARB_query_buffer_object = _glewSearchExtension("GL_ARB_query_buffer_object", extStart, extEnd);
#endif /* GL_ARB_query_buffer_object */
#ifdef GL_ARB_robust_buffer_access_behavior
- CONST_CAST(GLEW_ARB_robust_buffer_access_behavior) = _glewSearchExtension("GL_ARB_robust_buffer_access_behavior", extStart, extEnd);
+ GLEW_ARB_robust_buffer_access_behavior = _glewSearchExtension("GL_ARB_robust_buffer_access_behavior", extStart, extEnd);
#endif /* GL_ARB_robust_buffer_access_behavior */
#ifdef GL_ARB_robustness
- CONST_CAST(GLEW_ARB_robustness) = _glewSearchExtension("GL_ARB_robustness", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_robustness) CONST_CAST(GLEW_ARB_robustness) = !_glewInit_GL_ARB_robustness(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_robustness = _glewSearchExtension("GL_ARB_robustness", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_robustness) GLEW_ARB_robustness = !_glewInit_GL_ARB_robustness(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_robustness */
#ifdef GL_ARB_robustness_application_isolation
- CONST_CAST(GLEW_ARB_robustness_application_isolation) = _glewSearchExtension("GL_ARB_robustness_application_isolation", extStart, extEnd);
+ GLEW_ARB_robustness_application_isolation = _glewSearchExtension("GL_ARB_robustness_application_isolation", extStart, extEnd);
#endif /* GL_ARB_robustness_application_isolation */
#ifdef GL_ARB_robustness_share_group_isolation
- CONST_CAST(GLEW_ARB_robustness_share_group_isolation) = _glewSearchExtension("GL_ARB_robustness_share_group_isolation", extStart, extEnd);
+ GLEW_ARB_robustness_share_group_isolation = _glewSearchExtension("GL_ARB_robustness_share_group_isolation", extStart, extEnd);
#endif /* GL_ARB_robustness_share_group_isolation */
+#ifdef GL_ARB_sample_locations
+ GLEW_ARB_sample_locations = _glewSearchExtension("GL_ARB_sample_locations", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_sample_locations) GLEW_ARB_sample_locations = !_glewInit_GL_ARB_sample_locations(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_sample_locations */
#ifdef GL_ARB_sample_shading
- CONST_CAST(GLEW_ARB_sample_shading) = _glewSearchExtension("GL_ARB_sample_shading", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_sample_shading) CONST_CAST(GLEW_ARB_sample_shading) = !_glewInit_GL_ARB_sample_shading(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_sample_shading = _glewSearchExtension("GL_ARB_sample_shading", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_sample_shading) GLEW_ARB_sample_shading = !_glewInit_GL_ARB_sample_shading(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_sample_shading */
#ifdef GL_ARB_sampler_objects
- CONST_CAST(GLEW_ARB_sampler_objects) = _glewSearchExtension("GL_ARB_sampler_objects", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_sampler_objects) CONST_CAST(GLEW_ARB_sampler_objects) = !_glewInit_GL_ARB_sampler_objects(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_sampler_objects = _glewSearchExtension("GL_ARB_sampler_objects", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_sampler_objects) GLEW_ARB_sampler_objects = !_glewInit_GL_ARB_sampler_objects(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_sampler_objects */
#ifdef GL_ARB_seamless_cube_map
- CONST_CAST(GLEW_ARB_seamless_cube_map) = _glewSearchExtension("GL_ARB_seamless_cube_map", extStart, extEnd);
+ GLEW_ARB_seamless_cube_map = _glewSearchExtension("GL_ARB_seamless_cube_map", extStart, extEnd);
#endif /* GL_ARB_seamless_cube_map */
#ifdef GL_ARB_seamless_cubemap_per_texture
- CONST_CAST(GLEW_ARB_seamless_cubemap_per_texture) = _glewSearchExtension("GL_ARB_seamless_cubemap_per_texture", extStart, extEnd);
+ GLEW_ARB_seamless_cubemap_per_texture = _glewSearchExtension("GL_ARB_seamless_cubemap_per_texture", extStart, extEnd);
#endif /* GL_ARB_seamless_cubemap_per_texture */
#ifdef GL_ARB_separate_shader_objects
- CONST_CAST(GLEW_ARB_separate_shader_objects) = _glewSearchExtension("GL_ARB_separate_shader_objects", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_separate_shader_objects) CONST_CAST(GLEW_ARB_separate_shader_objects) = !_glewInit_GL_ARB_separate_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_separate_shader_objects = _glewSearchExtension("GL_ARB_separate_shader_objects", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_separate_shader_objects) GLEW_ARB_separate_shader_objects = !_glewInit_GL_ARB_separate_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_separate_shader_objects */
+#ifdef GL_ARB_shader_atomic_counter_ops
+ GLEW_ARB_shader_atomic_counter_ops = _glewSearchExtension("GL_ARB_shader_atomic_counter_ops", extStart, extEnd);
+#endif /* GL_ARB_shader_atomic_counter_ops */
#ifdef GL_ARB_shader_atomic_counters
- CONST_CAST(GLEW_ARB_shader_atomic_counters) = _glewSearchExtension("GL_ARB_shader_atomic_counters", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_shader_atomic_counters) CONST_CAST(GLEW_ARB_shader_atomic_counters) = !_glewInit_GL_ARB_shader_atomic_counters(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_shader_atomic_counters = _glewSearchExtension("GL_ARB_shader_atomic_counters", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_shader_atomic_counters) GLEW_ARB_shader_atomic_counters = !_glewInit_GL_ARB_shader_atomic_counters(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_shader_atomic_counters */
+#ifdef GL_ARB_shader_ballot
+ GLEW_ARB_shader_ballot = _glewSearchExtension("GL_ARB_shader_ballot", extStart, extEnd);
+#endif /* GL_ARB_shader_ballot */
#ifdef GL_ARB_shader_bit_encoding
- CONST_CAST(GLEW_ARB_shader_bit_encoding) = _glewSearchExtension("GL_ARB_shader_bit_encoding", extStart, extEnd);
+ GLEW_ARB_shader_bit_encoding = _glewSearchExtension("GL_ARB_shader_bit_encoding", extStart, extEnd);
#endif /* GL_ARB_shader_bit_encoding */
+#ifdef GL_ARB_shader_clock
+ GLEW_ARB_shader_clock = _glewSearchExtension("GL_ARB_shader_clock", extStart, extEnd);
+#endif /* GL_ARB_shader_clock */
#ifdef GL_ARB_shader_draw_parameters
- CONST_CAST(GLEW_ARB_shader_draw_parameters) = _glewSearchExtension("GL_ARB_shader_draw_parameters", extStart, extEnd);
+ GLEW_ARB_shader_draw_parameters = _glewSearchExtension("GL_ARB_shader_draw_parameters", extStart, extEnd);
#endif /* GL_ARB_shader_draw_parameters */
#ifdef GL_ARB_shader_group_vote
- CONST_CAST(GLEW_ARB_shader_group_vote) = _glewSearchExtension("GL_ARB_shader_group_vote", extStart, extEnd);
+ GLEW_ARB_shader_group_vote = _glewSearchExtension("GL_ARB_shader_group_vote", extStart, extEnd);
#endif /* GL_ARB_shader_group_vote */
#ifdef GL_ARB_shader_image_load_store
- CONST_CAST(GLEW_ARB_shader_image_load_store) = _glewSearchExtension("GL_ARB_shader_image_load_store", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_shader_image_load_store) CONST_CAST(GLEW_ARB_shader_image_load_store) = !_glewInit_GL_ARB_shader_image_load_store(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_shader_image_load_store = _glewSearchExtension("GL_ARB_shader_image_load_store", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_shader_image_load_store) GLEW_ARB_shader_image_load_store = !_glewInit_GL_ARB_shader_image_load_store(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_shader_image_load_store */
#ifdef GL_ARB_shader_image_size
- CONST_CAST(GLEW_ARB_shader_image_size) = _glewSearchExtension("GL_ARB_shader_image_size", extStart, extEnd);
+ GLEW_ARB_shader_image_size = _glewSearchExtension("GL_ARB_shader_image_size", extStart, extEnd);
#endif /* GL_ARB_shader_image_size */
#ifdef GL_ARB_shader_objects
- CONST_CAST(GLEW_ARB_shader_objects) = _glewSearchExtension("GL_ARB_shader_objects", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_shader_objects) CONST_CAST(GLEW_ARB_shader_objects) = !_glewInit_GL_ARB_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_shader_objects = _glewSearchExtension("GL_ARB_shader_objects", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_shader_objects) GLEW_ARB_shader_objects = !_glewInit_GL_ARB_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_shader_objects */
#ifdef GL_ARB_shader_precision
- CONST_CAST(GLEW_ARB_shader_precision) = _glewSearchExtension("GL_ARB_shader_precision", extStart, extEnd);
+ GLEW_ARB_shader_precision = _glewSearchExtension("GL_ARB_shader_precision", extStart, extEnd);
#endif /* GL_ARB_shader_precision */
#ifdef GL_ARB_shader_stencil_export
- CONST_CAST(GLEW_ARB_shader_stencil_export) = _glewSearchExtension("GL_ARB_shader_stencil_export", extStart, extEnd);
+ GLEW_ARB_shader_stencil_export = _glewSearchExtension("GL_ARB_shader_stencil_export", extStart, extEnd);
#endif /* GL_ARB_shader_stencil_export */
#ifdef GL_ARB_shader_storage_buffer_object
- CONST_CAST(GLEW_ARB_shader_storage_buffer_object) = _glewSearchExtension("GL_ARB_shader_storage_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_shader_storage_buffer_object) CONST_CAST(GLEW_ARB_shader_storage_buffer_object) = !_glewInit_GL_ARB_shader_storage_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_shader_storage_buffer_object = _glewSearchExtension("GL_ARB_shader_storage_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_shader_storage_buffer_object) GLEW_ARB_shader_storage_buffer_object = !_glewInit_GL_ARB_shader_storage_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_shader_storage_buffer_object */
#ifdef GL_ARB_shader_subroutine
- CONST_CAST(GLEW_ARB_shader_subroutine) = _glewSearchExtension("GL_ARB_shader_subroutine", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_shader_subroutine) CONST_CAST(GLEW_ARB_shader_subroutine) = !_glewInit_GL_ARB_shader_subroutine(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_shader_subroutine = _glewSearchExtension("GL_ARB_shader_subroutine", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_shader_subroutine) GLEW_ARB_shader_subroutine = !_glewInit_GL_ARB_shader_subroutine(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_shader_subroutine */
+#ifdef GL_ARB_shader_texture_image_samples
+ GLEW_ARB_shader_texture_image_samples = _glewSearchExtension("GL_ARB_shader_texture_image_samples", extStart, extEnd);
+#endif /* GL_ARB_shader_texture_image_samples */
#ifdef GL_ARB_shader_texture_lod
- CONST_CAST(GLEW_ARB_shader_texture_lod) = _glewSearchExtension("GL_ARB_shader_texture_lod", extStart, extEnd);
+ GLEW_ARB_shader_texture_lod = _glewSearchExtension("GL_ARB_shader_texture_lod", extStart, extEnd);
#endif /* GL_ARB_shader_texture_lod */
+#ifdef GL_ARB_shader_viewport_layer_array
+ GLEW_ARB_shader_viewport_layer_array = _glewSearchExtension("GL_ARB_shader_viewport_layer_array", extStart, extEnd);
+#endif /* GL_ARB_shader_viewport_layer_array */
#ifdef GL_ARB_shading_language_100
- CONST_CAST(GLEW_ARB_shading_language_100) = _glewSearchExtension("GL_ARB_shading_language_100", extStart, extEnd);
+ GLEW_ARB_shading_language_100 = _glewSearchExtension("GL_ARB_shading_language_100", extStart, extEnd);
#endif /* GL_ARB_shading_language_100 */
#ifdef GL_ARB_shading_language_420pack
- CONST_CAST(GLEW_ARB_shading_language_420pack) = _glewSearchExtension("GL_ARB_shading_language_420pack", extStart, extEnd);
+ GLEW_ARB_shading_language_420pack = _glewSearchExtension("GL_ARB_shading_language_420pack", extStart, extEnd);
#endif /* GL_ARB_shading_language_420pack */
#ifdef GL_ARB_shading_language_include
- CONST_CAST(GLEW_ARB_shading_language_include) = _glewSearchExtension("GL_ARB_shading_language_include", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_shading_language_include) CONST_CAST(GLEW_ARB_shading_language_include) = !_glewInit_GL_ARB_shading_language_include(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_shading_language_include = _glewSearchExtension("GL_ARB_shading_language_include", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_shading_language_include) GLEW_ARB_shading_language_include = !_glewInit_GL_ARB_shading_language_include(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_shading_language_include */
#ifdef GL_ARB_shading_language_packing
- CONST_CAST(GLEW_ARB_shading_language_packing) = _glewSearchExtension("GL_ARB_shading_language_packing", extStart, extEnd);
+ GLEW_ARB_shading_language_packing = _glewSearchExtension("GL_ARB_shading_language_packing", extStart, extEnd);
#endif /* GL_ARB_shading_language_packing */
#ifdef GL_ARB_shadow
- CONST_CAST(GLEW_ARB_shadow) = _glewSearchExtension("GL_ARB_shadow", extStart, extEnd);
+ GLEW_ARB_shadow = _glewSearchExtension("GL_ARB_shadow", extStart, extEnd);
#endif /* GL_ARB_shadow */
#ifdef GL_ARB_shadow_ambient
- CONST_CAST(GLEW_ARB_shadow_ambient) = _glewSearchExtension("GL_ARB_shadow_ambient", extStart, extEnd);
+ GLEW_ARB_shadow_ambient = _glewSearchExtension("GL_ARB_shadow_ambient", extStart, extEnd);
#endif /* GL_ARB_shadow_ambient */
+#ifdef GL_ARB_sparse_buffer
+ GLEW_ARB_sparse_buffer = _glewSearchExtension("GL_ARB_sparse_buffer", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_sparse_buffer) GLEW_ARB_sparse_buffer = !_glewInit_GL_ARB_sparse_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_sparse_buffer */
#ifdef GL_ARB_sparse_texture
- CONST_CAST(GLEW_ARB_sparse_texture) = _glewSearchExtension("GL_ARB_sparse_texture", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_sparse_texture) CONST_CAST(GLEW_ARB_sparse_texture) = !_glewInit_GL_ARB_sparse_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_sparse_texture = _glewSearchExtension("GL_ARB_sparse_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_sparse_texture) GLEW_ARB_sparse_texture = !_glewInit_GL_ARB_sparse_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_sparse_texture */
+#ifdef GL_ARB_sparse_texture2
+ GLEW_ARB_sparse_texture2 = _glewSearchExtension("GL_ARB_sparse_texture2", extStart, extEnd);
+#endif /* GL_ARB_sparse_texture2 */
+#ifdef GL_ARB_sparse_texture_clamp
+ GLEW_ARB_sparse_texture_clamp = _glewSearchExtension("GL_ARB_sparse_texture_clamp", extStart, extEnd);
+#endif /* GL_ARB_sparse_texture_clamp */
#ifdef GL_ARB_stencil_texturing
- CONST_CAST(GLEW_ARB_stencil_texturing) = _glewSearchExtension("GL_ARB_stencil_texturing", extStart, extEnd);
+ GLEW_ARB_stencil_texturing = _glewSearchExtension("GL_ARB_stencil_texturing", extStart, extEnd);
#endif /* GL_ARB_stencil_texturing */
#ifdef GL_ARB_sync
- CONST_CAST(GLEW_ARB_sync) = _glewSearchExtension("GL_ARB_sync", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_sync) CONST_CAST(GLEW_ARB_sync) = !_glewInit_GL_ARB_sync(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_sync = _glewSearchExtension("GL_ARB_sync", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_sync) GLEW_ARB_sync = !_glewInit_GL_ARB_sync(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_sync */
#ifdef GL_ARB_tessellation_shader
- CONST_CAST(GLEW_ARB_tessellation_shader) = _glewSearchExtension("GL_ARB_tessellation_shader", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_tessellation_shader) CONST_CAST(GLEW_ARB_tessellation_shader) = !_glewInit_GL_ARB_tessellation_shader(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_tessellation_shader = _glewSearchExtension("GL_ARB_tessellation_shader", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_tessellation_shader) GLEW_ARB_tessellation_shader = !_glewInit_GL_ARB_tessellation_shader(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_tessellation_shader */
+#ifdef GL_ARB_texture_barrier
+ GLEW_ARB_texture_barrier = _glewSearchExtension("GL_ARB_texture_barrier", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_barrier) GLEW_ARB_texture_barrier = !_glewInit_GL_ARB_texture_barrier(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_ARB_texture_barrier */
#ifdef GL_ARB_texture_border_clamp
- CONST_CAST(GLEW_ARB_texture_border_clamp) = _glewSearchExtension("GL_ARB_texture_border_clamp", extStart, extEnd);
+ GLEW_ARB_texture_border_clamp = _glewSearchExtension("GL_ARB_texture_border_clamp", extStart, extEnd);
#endif /* GL_ARB_texture_border_clamp */
#ifdef GL_ARB_texture_buffer_object
- CONST_CAST(GLEW_ARB_texture_buffer_object) = _glewSearchExtension("GL_ARB_texture_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_buffer_object) CONST_CAST(GLEW_ARB_texture_buffer_object) = !_glewInit_GL_ARB_texture_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_buffer_object = _glewSearchExtension("GL_ARB_texture_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_buffer_object) GLEW_ARB_texture_buffer_object = !_glewInit_GL_ARB_texture_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_buffer_object */
#ifdef GL_ARB_texture_buffer_object_rgb32
- CONST_CAST(GLEW_ARB_texture_buffer_object_rgb32) = _glewSearchExtension("GL_ARB_texture_buffer_object_rgb32", extStart, extEnd);
+ GLEW_ARB_texture_buffer_object_rgb32 = _glewSearchExtension("GL_ARB_texture_buffer_object_rgb32", extStart, extEnd);
#endif /* GL_ARB_texture_buffer_object_rgb32 */
#ifdef GL_ARB_texture_buffer_range
- CONST_CAST(GLEW_ARB_texture_buffer_range) = _glewSearchExtension("GL_ARB_texture_buffer_range", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_buffer_range) CONST_CAST(GLEW_ARB_texture_buffer_range) = !_glewInit_GL_ARB_texture_buffer_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_buffer_range = _glewSearchExtension("GL_ARB_texture_buffer_range", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_buffer_range) GLEW_ARB_texture_buffer_range = !_glewInit_GL_ARB_texture_buffer_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_buffer_range */
#ifdef GL_ARB_texture_compression
- CONST_CAST(GLEW_ARB_texture_compression) = _glewSearchExtension("GL_ARB_texture_compression", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_compression) CONST_CAST(GLEW_ARB_texture_compression) = !_glewInit_GL_ARB_texture_compression(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_compression = _glewSearchExtension("GL_ARB_texture_compression", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_compression) GLEW_ARB_texture_compression = !_glewInit_GL_ARB_texture_compression(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_compression */
#ifdef GL_ARB_texture_compression_bptc
- CONST_CAST(GLEW_ARB_texture_compression_bptc) = _glewSearchExtension("GL_ARB_texture_compression_bptc", extStart, extEnd);
+ GLEW_ARB_texture_compression_bptc = _glewSearchExtension("GL_ARB_texture_compression_bptc", extStart, extEnd);
#endif /* GL_ARB_texture_compression_bptc */
#ifdef GL_ARB_texture_compression_rgtc
- CONST_CAST(GLEW_ARB_texture_compression_rgtc) = _glewSearchExtension("GL_ARB_texture_compression_rgtc", extStart, extEnd);
+ GLEW_ARB_texture_compression_rgtc = _glewSearchExtension("GL_ARB_texture_compression_rgtc", extStart, extEnd);
#endif /* GL_ARB_texture_compression_rgtc */
#ifdef GL_ARB_texture_cube_map
- CONST_CAST(GLEW_ARB_texture_cube_map) = _glewSearchExtension("GL_ARB_texture_cube_map", extStart, extEnd);
+ GLEW_ARB_texture_cube_map = _glewSearchExtension("GL_ARB_texture_cube_map", extStart, extEnd);
#endif /* GL_ARB_texture_cube_map */
#ifdef GL_ARB_texture_cube_map_array
- CONST_CAST(GLEW_ARB_texture_cube_map_array) = _glewSearchExtension("GL_ARB_texture_cube_map_array", extStart, extEnd);
+ GLEW_ARB_texture_cube_map_array = _glewSearchExtension("GL_ARB_texture_cube_map_array", extStart, extEnd);
#endif /* GL_ARB_texture_cube_map_array */
#ifdef GL_ARB_texture_env_add
- CONST_CAST(GLEW_ARB_texture_env_add) = _glewSearchExtension("GL_ARB_texture_env_add", extStart, extEnd);
+ GLEW_ARB_texture_env_add = _glewSearchExtension("GL_ARB_texture_env_add", extStart, extEnd);
#endif /* GL_ARB_texture_env_add */
#ifdef GL_ARB_texture_env_combine
- CONST_CAST(GLEW_ARB_texture_env_combine) = _glewSearchExtension("GL_ARB_texture_env_combine", extStart, extEnd);
+ GLEW_ARB_texture_env_combine = _glewSearchExtension("GL_ARB_texture_env_combine", extStart, extEnd);
#endif /* GL_ARB_texture_env_combine */
#ifdef GL_ARB_texture_env_crossbar
- CONST_CAST(GLEW_ARB_texture_env_crossbar) = _glewSearchExtension("GL_ARB_texture_env_crossbar", extStart, extEnd);
+ GLEW_ARB_texture_env_crossbar = _glewSearchExtension("GL_ARB_texture_env_crossbar", extStart, extEnd);
#endif /* GL_ARB_texture_env_crossbar */
#ifdef GL_ARB_texture_env_dot3
- CONST_CAST(GLEW_ARB_texture_env_dot3) = _glewSearchExtension("GL_ARB_texture_env_dot3", extStart, extEnd);
+ GLEW_ARB_texture_env_dot3 = _glewSearchExtension("GL_ARB_texture_env_dot3", extStart, extEnd);
#endif /* GL_ARB_texture_env_dot3 */
+#ifdef GL_ARB_texture_filter_minmax
+ GLEW_ARB_texture_filter_minmax = _glewSearchExtension("GL_ARB_texture_filter_minmax", extStart, extEnd);
+#endif /* GL_ARB_texture_filter_minmax */
#ifdef GL_ARB_texture_float
- CONST_CAST(GLEW_ARB_texture_float) = _glewSearchExtension("GL_ARB_texture_float", extStart, extEnd);
+ GLEW_ARB_texture_float = _glewSearchExtension("GL_ARB_texture_float", extStart, extEnd);
#endif /* GL_ARB_texture_float */
#ifdef GL_ARB_texture_gather
- CONST_CAST(GLEW_ARB_texture_gather) = _glewSearchExtension("GL_ARB_texture_gather", extStart, extEnd);
+ GLEW_ARB_texture_gather = _glewSearchExtension("GL_ARB_texture_gather", extStart, extEnd);
#endif /* GL_ARB_texture_gather */
#ifdef GL_ARB_texture_mirror_clamp_to_edge
- CONST_CAST(GLEW_ARB_texture_mirror_clamp_to_edge) = _glewSearchExtension("GL_ARB_texture_mirror_clamp_to_edge", extStart, extEnd);
+ GLEW_ARB_texture_mirror_clamp_to_edge = _glewSearchExtension("GL_ARB_texture_mirror_clamp_to_edge", extStart, extEnd);
#endif /* GL_ARB_texture_mirror_clamp_to_edge */
#ifdef GL_ARB_texture_mirrored_repeat
- CONST_CAST(GLEW_ARB_texture_mirrored_repeat) = _glewSearchExtension("GL_ARB_texture_mirrored_repeat", extStart, extEnd);
+ GLEW_ARB_texture_mirrored_repeat = _glewSearchExtension("GL_ARB_texture_mirrored_repeat", extStart, extEnd);
#endif /* GL_ARB_texture_mirrored_repeat */
#ifdef GL_ARB_texture_multisample
- CONST_CAST(GLEW_ARB_texture_multisample) = _glewSearchExtension("GL_ARB_texture_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_multisample) CONST_CAST(GLEW_ARB_texture_multisample) = !_glewInit_GL_ARB_texture_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_multisample = _glewSearchExtension("GL_ARB_texture_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_multisample) GLEW_ARB_texture_multisample = !_glewInit_GL_ARB_texture_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_multisample */
#ifdef GL_ARB_texture_non_power_of_two
- CONST_CAST(GLEW_ARB_texture_non_power_of_two) = _glewSearchExtension("GL_ARB_texture_non_power_of_two", extStart, extEnd);
+ GLEW_ARB_texture_non_power_of_two = _glewSearchExtension("GL_ARB_texture_non_power_of_two", extStart, extEnd);
#endif /* GL_ARB_texture_non_power_of_two */
#ifdef GL_ARB_texture_query_levels
- CONST_CAST(GLEW_ARB_texture_query_levels) = _glewSearchExtension("GL_ARB_texture_query_levels", extStart, extEnd);
+ GLEW_ARB_texture_query_levels = _glewSearchExtension("GL_ARB_texture_query_levels", extStart, extEnd);
#endif /* GL_ARB_texture_query_levels */
#ifdef GL_ARB_texture_query_lod
- CONST_CAST(GLEW_ARB_texture_query_lod) = _glewSearchExtension("GL_ARB_texture_query_lod", extStart, extEnd);
+ GLEW_ARB_texture_query_lod = _glewSearchExtension("GL_ARB_texture_query_lod", extStart, extEnd);
#endif /* GL_ARB_texture_query_lod */
#ifdef GL_ARB_texture_rectangle
- CONST_CAST(GLEW_ARB_texture_rectangle) = _glewSearchExtension("GL_ARB_texture_rectangle", extStart, extEnd);
+ GLEW_ARB_texture_rectangle = _glewSearchExtension("GL_ARB_texture_rectangle", extStart, extEnd);
#endif /* GL_ARB_texture_rectangle */
#ifdef GL_ARB_texture_rg
- CONST_CAST(GLEW_ARB_texture_rg) = _glewSearchExtension("GL_ARB_texture_rg", extStart, extEnd);
+ GLEW_ARB_texture_rg = _glewSearchExtension("GL_ARB_texture_rg", extStart, extEnd);
#endif /* GL_ARB_texture_rg */
#ifdef GL_ARB_texture_rgb10_a2ui
- CONST_CAST(GLEW_ARB_texture_rgb10_a2ui) = _glewSearchExtension("GL_ARB_texture_rgb10_a2ui", extStart, extEnd);
+ GLEW_ARB_texture_rgb10_a2ui = _glewSearchExtension("GL_ARB_texture_rgb10_a2ui", extStart, extEnd);
#endif /* GL_ARB_texture_rgb10_a2ui */
#ifdef GL_ARB_texture_stencil8
- CONST_CAST(GLEW_ARB_texture_stencil8) = _glewSearchExtension("GL_ARB_texture_stencil8", extStart, extEnd);
+ GLEW_ARB_texture_stencil8 = _glewSearchExtension("GL_ARB_texture_stencil8", extStart, extEnd);
#endif /* GL_ARB_texture_stencil8 */
#ifdef GL_ARB_texture_storage
- CONST_CAST(GLEW_ARB_texture_storage) = _glewSearchExtension("GL_ARB_texture_storage", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_storage) CONST_CAST(GLEW_ARB_texture_storage) = !_glewInit_GL_ARB_texture_storage(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_storage = _glewSearchExtension("GL_ARB_texture_storage", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_storage) GLEW_ARB_texture_storage = !_glewInit_GL_ARB_texture_storage(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_storage */
#ifdef GL_ARB_texture_storage_multisample
- CONST_CAST(GLEW_ARB_texture_storage_multisample) = _glewSearchExtension("GL_ARB_texture_storage_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_storage_multisample) CONST_CAST(GLEW_ARB_texture_storage_multisample) = !_glewInit_GL_ARB_texture_storage_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_storage_multisample = _glewSearchExtension("GL_ARB_texture_storage_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_storage_multisample) GLEW_ARB_texture_storage_multisample = !_glewInit_GL_ARB_texture_storage_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_storage_multisample */
#ifdef GL_ARB_texture_swizzle
- CONST_CAST(GLEW_ARB_texture_swizzle) = _glewSearchExtension("GL_ARB_texture_swizzle", extStart, extEnd);
+ GLEW_ARB_texture_swizzle = _glewSearchExtension("GL_ARB_texture_swizzle", extStart, extEnd);
#endif /* GL_ARB_texture_swizzle */
#ifdef GL_ARB_texture_view
- CONST_CAST(GLEW_ARB_texture_view) = _glewSearchExtension("GL_ARB_texture_view", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_texture_view) CONST_CAST(GLEW_ARB_texture_view) = !_glewInit_GL_ARB_texture_view(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_texture_view = _glewSearchExtension("GL_ARB_texture_view", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_texture_view) GLEW_ARB_texture_view = !_glewInit_GL_ARB_texture_view(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_texture_view */
#ifdef GL_ARB_timer_query
- CONST_CAST(GLEW_ARB_timer_query) = _glewSearchExtension("GL_ARB_timer_query", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_timer_query) CONST_CAST(GLEW_ARB_timer_query) = !_glewInit_GL_ARB_timer_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_timer_query = _glewSearchExtension("GL_ARB_timer_query", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_timer_query) GLEW_ARB_timer_query = !_glewInit_GL_ARB_timer_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_timer_query */
#ifdef GL_ARB_transform_feedback2
- CONST_CAST(GLEW_ARB_transform_feedback2) = _glewSearchExtension("GL_ARB_transform_feedback2", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_transform_feedback2) CONST_CAST(GLEW_ARB_transform_feedback2) = !_glewInit_GL_ARB_transform_feedback2(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_transform_feedback2 = _glewSearchExtension("GL_ARB_transform_feedback2", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_transform_feedback2) GLEW_ARB_transform_feedback2 = !_glewInit_GL_ARB_transform_feedback2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_transform_feedback2 */
#ifdef GL_ARB_transform_feedback3
- CONST_CAST(GLEW_ARB_transform_feedback3) = _glewSearchExtension("GL_ARB_transform_feedback3", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_transform_feedback3) CONST_CAST(GLEW_ARB_transform_feedback3) = !_glewInit_GL_ARB_transform_feedback3(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_transform_feedback3 = _glewSearchExtension("GL_ARB_transform_feedback3", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_transform_feedback3) GLEW_ARB_transform_feedback3 = !_glewInit_GL_ARB_transform_feedback3(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_transform_feedback3 */
#ifdef GL_ARB_transform_feedback_instanced
- CONST_CAST(GLEW_ARB_transform_feedback_instanced) = _glewSearchExtension("GL_ARB_transform_feedback_instanced", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_transform_feedback_instanced) CONST_CAST(GLEW_ARB_transform_feedback_instanced) = !_glewInit_GL_ARB_transform_feedback_instanced(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_transform_feedback_instanced = _glewSearchExtension("GL_ARB_transform_feedback_instanced", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_transform_feedback_instanced) GLEW_ARB_transform_feedback_instanced = !_glewInit_GL_ARB_transform_feedback_instanced(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_transform_feedback_instanced */
+#ifdef GL_ARB_transform_feedback_overflow_query
+ GLEW_ARB_transform_feedback_overflow_query = _glewSearchExtension("GL_ARB_transform_feedback_overflow_query", extStart, extEnd);
+#endif /* GL_ARB_transform_feedback_overflow_query */
#ifdef GL_ARB_transpose_matrix
- CONST_CAST(GLEW_ARB_transpose_matrix) = _glewSearchExtension("GL_ARB_transpose_matrix", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_transpose_matrix) CONST_CAST(GLEW_ARB_transpose_matrix) = !_glewInit_GL_ARB_transpose_matrix(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_transpose_matrix = _glewSearchExtension("GL_ARB_transpose_matrix", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_transpose_matrix) GLEW_ARB_transpose_matrix = !_glewInit_GL_ARB_transpose_matrix(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_transpose_matrix */
#ifdef GL_ARB_uniform_buffer_object
- CONST_CAST(GLEW_ARB_uniform_buffer_object) = _glewSearchExtension("GL_ARB_uniform_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_uniform_buffer_object) CONST_CAST(GLEW_ARB_uniform_buffer_object) = !_glewInit_GL_ARB_uniform_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_uniform_buffer_object = _glewSearchExtension("GL_ARB_uniform_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_uniform_buffer_object) GLEW_ARB_uniform_buffer_object = !_glewInit_GL_ARB_uniform_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_uniform_buffer_object */
#ifdef GL_ARB_vertex_array_bgra
- CONST_CAST(GLEW_ARB_vertex_array_bgra) = _glewSearchExtension("GL_ARB_vertex_array_bgra", extStart, extEnd);
+ GLEW_ARB_vertex_array_bgra = _glewSearchExtension("GL_ARB_vertex_array_bgra", extStart, extEnd);
#endif /* GL_ARB_vertex_array_bgra */
#ifdef GL_ARB_vertex_array_object
- CONST_CAST(GLEW_ARB_vertex_array_object) = _glewSearchExtension("GL_ARB_vertex_array_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_array_object) CONST_CAST(GLEW_ARB_vertex_array_object) = !_glewInit_GL_ARB_vertex_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_array_object = _glewSearchExtension("GL_ARB_vertex_array_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_array_object) GLEW_ARB_vertex_array_object = !_glewInit_GL_ARB_vertex_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_array_object */
#ifdef GL_ARB_vertex_attrib_64bit
- CONST_CAST(GLEW_ARB_vertex_attrib_64bit) = _glewSearchExtension("GL_ARB_vertex_attrib_64bit", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_attrib_64bit) CONST_CAST(GLEW_ARB_vertex_attrib_64bit) = !_glewInit_GL_ARB_vertex_attrib_64bit(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_attrib_64bit = _glewSearchExtension("GL_ARB_vertex_attrib_64bit", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_attrib_64bit) GLEW_ARB_vertex_attrib_64bit = !_glewInit_GL_ARB_vertex_attrib_64bit(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_attrib_64bit */
#ifdef GL_ARB_vertex_attrib_binding
- CONST_CAST(GLEW_ARB_vertex_attrib_binding) = _glewSearchExtension("GL_ARB_vertex_attrib_binding", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_attrib_binding) CONST_CAST(GLEW_ARB_vertex_attrib_binding) = !_glewInit_GL_ARB_vertex_attrib_binding(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_attrib_binding = _glewSearchExtension("GL_ARB_vertex_attrib_binding", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_attrib_binding) GLEW_ARB_vertex_attrib_binding = !_glewInit_GL_ARB_vertex_attrib_binding(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_attrib_binding */
#ifdef GL_ARB_vertex_blend
- CONST_CAST(GLEW_ARB_vertex_blend) = _glewSearchExtension("GL_ARB_vertex_blend", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_blend) CONST_CAST(GLEW_ARB_vertex_blend) = !_glewInit_GL_ARB_vertex_blend(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_blend = _glewSearchExtension("GL_ARB_vertex_blend", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_blend) GLEW_ARB_vertex_blend = !_glewInit_GL_ARB_vertex_blend(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_blend */
#ifdef GL_ARB_vertex_buffer_object
- CONST_CAST(GLEW_ARB_vertex_buffer_object) = _glewSearchExtension("GL_ARB_vertex_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_buffer_object) CONST_CAST(GLEW_ARB_vertex_buffer_object) = !_glewInit_GL_ARB_vertex_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_buffer_object = _glewSearchExtension("GL_ARB_vertex_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_buffer_object) GLEW_ARB_vertex_buffer_object = !_glewInit_GL_ARB_vertex_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_buffer_object */
#ifdef GL_ARB_vertex_program
- CONST_CAST(GLEW_ARB_vertex_program) = _glewSearchExtension("GL_ARB_vertex_program", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_program) CONST_CAST(GLEW_ARB_vertex_program) = !_glewInit_GL_ARB_vertex_program(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_program = _glewSearchExtension("GL_ARB_vertex_program", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_program) GLEW_ARB_vertex_program = !_glewInit_GL_ARB_vertex_program(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_program */
#ifdef GL_ARB_vertex_shader
- CONST_CAST(GLEW_ARB_vertex_shader) = _glewSearchExtension("GL_ARB_vertex_shader", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_shader) CONST_CAST(GLEW_ARB_vertex_shader) = !_glewInit_GL_ARB_vertex_shader(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_shader = _glewSearchExtension("GL_ARB_vertex_shader", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_shader) { GLEW_ARB_vertex_shader = !_glewInit_GL_ARB_vertex_shader(GLEW_CONTEXT_ARG_VAR_INIT); _glewInit_GL_ARB_vertex_program(GLEW_CONTEXT_ARG_VAR_INIT); }
#endif /* GL_ARB_vertex_shader */
#ifdef GL_ARB_vertex_type_10f_11f_11f_rev
- CONST_CAST(GLEW_ARB_vertex_type_10f_11f_11f_rev) = _glewSearchExtension("GL_ARB_vertex_type_10f_11f_11f_rev", extStart, extEnd);
+ GLEW_ARB_vertex_type_10f_11f_11f_rev = _glewSearchExtension("GL_ARB_vertex_type_10f_11f_11f_rev", extStart, extEnd);
#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */
#ifdef GL_ARB_vertex_type_2_10_10_10_rev
- CONST_CAST(GLEW_ARB_vertex_type_2_10_10_10_rev) = _glewSearchExtension("GL_ARB_vertex_type_2_10_10_10_rev", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_vertex_type_2_10_10_10_rev) CONST_CAST(GLEW_ARB_vertex_type_2_10_10_10_rev) = !_glewInit_GL_ARB_vertex_type_2_10_10_10_rev(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_vertex_type_2_10_10_10_rev = _glewSearchExtension("GL_ARB_vertex_type_2_10_10_10_rev", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_vertex_type_2_10_10_10_rev) GLEW_ARB_vertex_type_2_10_10_10_rev = !_glewInit_GL_ARB_vertex_type_2_10_10_10_rev(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_vertex_type_2_10_10_10_rev */
#ifdef GL_ARB_viewport_array
- CONST_CAST(GLEW_ARB_viewport_array) = _glewSearchExtension("GL_ARB_viewport_array", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_viewport_array) CONST_CAST(GLEW_ARB_viewport_array) = !_glewInit_GL_ARB_viewport_array(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_viewport_array = _glewSearchExtension("GL_ARB_viewport_array", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_viewport_array) GLEW_ARB_viewport_array = !_glewInit_GL_ARB_viewport_array(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_viewport_array */
#ifdef GL_ARB_window_pos
- CONST_CAST(GLEW_ARB_window_pos) = _glewSearchExtension("GL_ARB_window_pos", extStart, extEnd);
- if (glewExperimental || GLEW_ARB_window_pos) CONST_CAST(GLEW_ARB_window_pos) = !_glewInit_GL_ARB_window_pos(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ARB_window_pos = _glewSearchExtension("GL_ARB_window_pos", extStart, extEnd);
+ if (glewExperimental || GLEW_ARB_window_pos) GLEW_ARB_window_pos = !_glewInit_GL_ARB_window_pos(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ARB_window_pos */
#ifdef GL_ATIX_point_sprites
- CONST_CAST(GLEW_ATIX_point_sprites) = _glewSearchExtension("GL_ATIX_point_sprites", extStart, extEnd);
+ GLEW_ATIX_point_sprites = _glewSearchExtension("GL_ATIX_point_sprites", extStart, extEnd);
#endif /* GL_ATIX_point_sprites */
#ifdef GL_ATIX_texture_env_combine3
- CONST_CAST(GLEW_ATIX_texture_env_combine3) = _glewSearchExtension("GL_ATIX_texture_env_combine3", extStart, extEnd);
+ GLEW_ATIX_texture_env_combine3 = _glewSearchExtension("GL_ATIX_texture_env_combine3", extStart, extEnd);
#endif /* GL_ATIX_texture_env_combine3 */
#ifdef GL_ATIX_texture_env_route
- CONST_CAST(GLEW_ATIX_texture_env_route) = _glewSearchExtension("GL_ATIX_texture_env_route", extStart, extEnd);
+ GLEW_ATIX_texture_env_route = _glewSearchExtension("GL_ATIX_texture_env_route", extStart, extEnd);
#endif /* GL_ATIX_texture_env_route */
#ifdef GL_ATIX_vertex_shader_output_point_size
- CONST_CAST(GLEW_ATIX_vertex_shader_output_point_size) = _glewSearchExtension("GL_ATIX_vertex_shader_output_point_size", extStart, extEnd);
+ GLEW_ATIX_vertex_shader_output_point_size = _glewSearchExtension("GL_ATIX_vertex_shader_output_point_size", extStart, extEnd);
#endif /* GL_ATIX_vertex_shader_output_point_size */
#ifdef GL_ATI_draw_buffers
- CONST_CAST(GLEW_ATI_draw_buffers) = _glewSearchExtension("GL_ATI_draw_buffers", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_draw_buffers) CONST_CAST(GLEW_ATI_draw_buffers) = !_glewInit_GL_ATI_draw_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_draw_buffers = _glewSearchExtension("GL_ATI_draw_buffers", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_draw_buffers) GLEW_ATI_draw_buffers = !_glewInit_GL_ATI_draw_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_draw_buffers */
#ifdef GL_ATI_element_array
- CONST_CAST(GLEW_ATI_element_array) = _glewSearchExtension("GL_ATI_element_array", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_element_array) CONST_CAST(GLEW_ATI_element_array) = !_glewInit_GL_ATI_element_array(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_element_array = _glewSearchExtension("GL_ATI_element_array", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_element_array) GLEW_ATI_element_array = !_glewInit_GL_ATI_element_array(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_element_array */
#ifdef GL_ATI_envmap_bumpmap
- CONST_CAST(GLEW_ATI_envmap_bumpmap) = _glewSearchExtension("GL_ATI_envmap_bumpmap", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_envmap_bumpmap) CONST_CAST(GLEW_ATI_envmap_bumpmap) = !_glewInit_GL_ATI_envmap_bumpmap(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_envmap_bumpmap = _glewSearchExtension("GL_ATI_envmap_bumpmap", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_envmap_bumpmap) GLEW_ATI_envmap_bumpmap = !_glewInit_GL_ATI_envmap_bumpmap(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_envmap_bumpmap */
#ifdef GL_ATI_fragment_shader
- CONST_CAST(GLEW_ATI_fragment_shader) = _glewSearchExtension("GL_ATI_fragment_shader", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_fragment_shader) CONST_CAST(GLEW_ATI_fragment_shader) = !_glewInit_GL_ATI_fragment_shader(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_fragment_shader = _glewSearchExtension("GL_ATI_fragment_shader", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_fragment_shader) GLEW_ATI_fragment_shader = !_glewInit_GL_ATI_fragment_shader(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_fragment_shader */
#ifdef GL_ATI_map_object_buffer
- CONST_CAST(GLEW_ATI_map_object_buffer) = _glewSearchExtension("GL_ATI_map_object_buffer", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_map_object_buffer) CONST_CAST(GLEW_ATI_map_object_buffer) = !_glewInit_GL_ATI_map_object_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_map_object_buffer = _glewSearchExtension("GL_ATI_map_object_buffer", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_map_object_buffer) GLEW_ATI_map_object_buffer = !_glewInit_GL_ATI_map_object_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_map_object_buffer */
#ifdef GL_ATI_meminfo
- CONST_CAST(GLEW_ATI_meminfo) = _glewSearchExtension("GL_ATI_meminfo", extStart, extEnd);
+ GLEW_ATI_meminfo = _glewSearchExtension("GL_ATI_meminfo", extStart, extEnd);
#endif /* GL_ATI_meminfo */
#ifdef GL_ATI_pn_triangles
- CONST_CAST(GLEW_ATI_pn_triangles) = _glewSearchExtension("GL_ATI_pn_triangles", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_pn_triangles) CONST_CAST(GLEW_ATI_pn_triangles) = !_glewInit_GL_ATI_pn_triangles(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_pn_triangles = _glewSearchExtension("GL_ATI_pn_triangles", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_pn_triangles) GLEW_ATI_pn_triangles = !_glewInit_GL_ATI_pn_triangles(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_pn_triangles */
#ifdef GL_ATI_separate_stencil
- CONST_CAST(GLEW_ATI_separate_stencil) = _glewSearchExtension("GL_ATI_separate_stencil", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_separate_stencil) CONST_CAST(GLEW_ATI_separate_stencil) = !_glewInit_GL_ATI_separate_stencil(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_separate_stencil = _glewSearchExtension("GL_ATI_separate_stencil", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_separate_stencil) GLEW_ATI_separate_stencil = !_glewInit_GL_ATI_separate_stencil(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_separate_stencil */
#ifdef GL_ATI_shader_texture_lod
- CONST_CAST(GLEW_ATI_shader_texture_lod) = _glewSearchExtension("GL_ATI_shader_texture_lod", extStart, extEnd);
+ GLEW_ATI_shader_texture_lod = _glewSearchExtension("GL_ATI_shader_texture_lod", extStart, extEnd);
#endif /* GL_ATI_shader_texture_lod */
#ifdef GL_ATI_text_fragment_shader
- CONST_CAST(GLEW_ATI_text_fragment_shader) = _glewSearchExtension("GL_ATI_text_fragment_shader", extStart, extEnd);
+ GLEW_ATI_text_fragment_shader = _glewSearchExtension("GL_ATI_text_fragment_shader", extStart, extEnd);
#endif /* GL_ATI_text_fragment_shader */
#ifdef GL_ATI_texture_compression_3dc
- CONST_CAST(GLEW_ATI_texture_compression_3dc) = _glewSearchExtension("GL_ATI_texture_compression_3dc", extStart, extEnd);
+ GLEW_ATI_texture_compression_3dc = _glewSearchExtension("GL_ATI_texture_compression_3dc", extStart, extEnd);
#endif /* GL_ATI_texture_compression_3dc */
#ifdef GL_ATI_texture_env_combine3
- CONST_CAST(GLEW_ATI_texture_env_combine3) = _glewSearchExtension("GL_ATI_texture_env_combine3", extStart, extEnd);
+ GLEW_ATI_texture_env_combine3 = _glewSearchExtension("GL_ATI_texture_env_combine3", extStart, extEnd);
#endif /* GL_ATI_texture_env_combine3 */
#ifdef GL_ATI_texture_float
- CONST_CAST(GLEW_ATI_texture_float) = _glewSearchExtension("GL_ATI_texture_float", extStart, extEnd);
+ GLEW_ATI_texture_float = _glewSearchExtension("GL_ATI_texture_float", extStart, extEnd);
#endif /* GL_ATI_texture_float */
#ifdef GL_ATI_texture_mirror_once
- CONST_CAST(GLEW_ATI_texture_mirror_once) = _glewSearchExtension("GL_ATI_texture_mirror_once", extStart, extEnd);
+ GLEW_ATI_texture_mirror_once = _glewSearchExtension("GL_ATI_texture_mirror_once", extStart, extEnd);
#endif /* GL_ATI_texture_mirror_once */
#ifdef GL_ATI_vertex_array_object
- CONST_CAST(GLEW_ATI_vertex_array_object) = _glewSearchExtension("GL_ATI_vertex_array_object", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_vertex_array_object) CONST_CAST(GLEW_ATI_vertex_array_object) = !_glewInit_GL_ATI_vertex_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_vertex_array_object = _glewSearchExtension("GL_ATI_vertex_array_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_vertex_array_object) GLEW_ATI_vertex_array_object = !_glewInit_GL_ATI_vertex_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_vertex_array_object */
#ifdef GL_ATI_vertex_attrib_array_object
- CONST_CAST(GLEW_ATI_vertex_attrib_array_object) = _glewSearchExtension("GL_ATI_vertex_attrib_array_object", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_vertex_attrib_array_object) CONST_CAST(GLEW_ATI_vertex_attrib_array_object) = !_glewInit_GL_ATI_vertex_attrib_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_vertex_attrib_array_object = _glewSearchExtension("GL_ATI_vertex_attrib_array_object", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_vertex_attrib_array_object) GLEW_ATI_vertex_attrib_array_object = !_glewInit_GL_ATI_vertex_attrib_array_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_vertex_attrib_array_object */
#ifdef GL_ATI_vertex_streams
- CONST_CAST(GLEW_ATI_vertex_streams) = _glewSearchExtension("GL_ATI_vertex_streams", extStart, extEnd);
- if (glewExperimental || GLEW_ATI_vertex_streams) CONST_CAST(GLEW_ATI_vertex_streams) = !_glewInit_GL_ATI_vertex_streams(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_ATI_vertex_streams = _glewSearchExtension("GL_ATI_vertex_streams", extStart, extEnd);
+ if (glewExperimental || GLEW_ATI_vertex_streams) GLEW_ATI_vertex_streams = !_glewInit_GL_ATI_vertex_streams(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_ATI_vertex_streams */
#ifdef GL_EXT_422_pixels
- CONST_CAST(GLEW_EXT_422_pixels) = _glewSearchExtension("GL_EXT_422_pixels", extStart, extEnd);
+ GLEW_EXT_422_pixels = _glewSearchExtension("GL_EXT_422_pixels", extStart, extEnd);
#endif /* GL_EXT_422_pixels */
#ifdef GL_EXT_Cg_shader
- CONST_CAST(GLEW_EXT_Cg_shader) = _glewSearchExtension("GL_EXT_Cg_shader", extStart, extEnd);
+ GLEW_EXT_Cg_shader = _glewSearchExtension("GL_EXT_Cg_shader", extStart, extEnd);
#endif /* GL_EXT_Cg_shader */
#ifdef GL_EXT_abgr
- CONST_CAST(GLEW_EXT_abgr) = _glewSearchExtension("GL_EXT_abgr", extStart, extEnd);
+ GLEW_EXT_abgr = _glewSearchExtension("GL_EXT_abgr", extStart, extEnd);
#endif /* GL_EXT_abgr */
#ifdef GL_EXT_bgra
- CONST_CAST(GLEW_EXT_bgra) = _glewSearchExtension("GL_EXT_bgra", extStart, extEnd);
+ GLEW_EXT_bgra = _glewSearchExtension("GL_EXT_bgra", extStart, extEnd);
#endif /* GL_EXT_bgra */
#ifdef GL_EXT_bindable_uniform
- CONST_CAST(GLEW_EXT_bindable_uniform) = _glewSearchExtension("GL_EXT_bindable_uniform", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_bindable_uniform) CONST_CAST(GLEW_EXT_bindable_uniform) = !_glewInit_GL_EXT_bindable_uniform(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_bindable_uniform = _glewSearchExtension("GL_EXT_bindable_uniform", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_bindable_uniform) GLEW_EXT_bindable_uniform = !_glewInit_GL_EXT_bindable_uniform(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_bindable_uniform */
#ifdef GL_EXT_blend_color
- CONST_CAST(GLEW_EXT_blend_color) = _glewSearchExtension("GL_EXT_blend_color", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_blend_color) CONST_CAST(GLEW_EXT_blend_color) = !_glewInit_GL_EXT_blend_color(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_blend_color = _glewSearchExtension("GL_EXT_blend_color", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_blend_color) GLEW_EXT_blend_color = !_glewInit_GL_EXT_blend_color(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_blend_color */
#ifdef GL_EXT_blend_equation_separate
- CONST_CAST(GLEW_EXT_blend_equation_separate) = _glewSearchExtension("GL_EXT_blend_equation_separate", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_blend_equation_separate) CONST_CAST(GLEW_EXT_blend_equation_separate) = !_glewInit_GL_EXT_blend_equation_separate(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_blend_equation_separate = _glewSearchExtension("GL_EXT_blend_equation_separate", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_blend_equation_separate) GLEW_EXT_blend_equation_separate = !_glewInit_GL_EXT_blend_equation_separate(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_blend_equation_separate */
#ifdef GL_EXT_blend_func_separate
- CONST_CAST(GLEW_EXT_blend_func_separate) = _glewSearchExtension("GL_EXT_blend_func_separate", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_blend_func_separate) CONST_CAST(GLEW_EXT_blend_func_separate) = !_glewInit_GL_EXT_blend_func_separate(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_blend_func_separate = _glewSearchExtension("GL_EXT_blend_func_separate", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_blend_func_separate) GLEW_EXT_blend_func_separate = !_glewInit_GL_EXT_blend_func_separate(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_blend_func_separate */
#ifdef GL_EXT_blend_logic_op
- CONST_CAST(GLEW_EXT_blend_logic_op) = _glewSearchExtension("GL_EXT_blend_logic_op", extStart, extEnd);
+ GLEW_EXT_blend_logic_op = _glewSearchExtension("GL_EXT_blend_logic_op", extStart, extEnd);
#endif /* GL_EXT_blend_logic_op */
#ifdef GL_EXT_blend_minmax
- CONST_CAST(GLEW_EXT_blend_minmax) = _glewSearchExtension("GL_EXT_blend_minmax", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_blend_minmax) CONST_CAST(GLEW_EXT_blend_minmax) = !_glewInit_GL_EXT_blend_minmax(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_blend_minmax = _glewSearchExtension("GL_EXT_blend_minmax", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_blend_minmax) GLEW_EXT_blend_minmax = !_glewInit_GL_EXT_blend_minmax(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_blend_minmax */
#ifdef GL_EXT_blend_subtract
- CONST_CAST(GLEW_EXT_blend_subtract) = _glewSearchExtension("GL_EXT_blend_subtract", extStart, extEnd);
+ GLEW_EXT_blend_subtract = _glewSearchExtension("GL_EXT_blend_subtract", extStart, extEnd);
#endif /* GL_EXT_blend_subtract */
#ifdef GL_EXT_clip_volume_hint
- CONST_CAST(GLEW_EXT_clip_volume_hint) = _glewSearchExtension("GL_EXT_clip_volume_hint", extStart, extEnd);
+ GLEW_EXT_clip_volume_hint = _glewSearchExtension("GL_EXT_clip_volume_hint", extStart, extEnd);
#endif /* GL_EXT_clip_volume_hint */
#ifdef GL_EXT_cmyka
- CONST_CAST(GLEW_EXT_cmyka) = _glewSearchExtension("GL_EXT_cmyka", extStart, extEnd);
+ GLEW_EXT_cmyka = _glewSearchExtension("GL_EXT_cmyka", extStart, extEnd);
#endif /* GL_EXT_cmyka */
#ifdef GL_EXT_color_subtable
- CONST_CAST(GLEW_EXT_color_subtable) = _glewSearchExtension("GL_EXT_color_subtable", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_color_subtable) CONST_CAST(GLEW_EXT_color_subtable) = !_glewInit_GL_EXT_color_subtable(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_color_subtable = _glewSearchExtension("GL_EXT_color_subtable", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_color_subtable) GLEW_EXT_color_subtable = !_glewInit_GL_EXT_color_subtable(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_color_subtable */
#ifdef GL_EXT_compiled_vertex_array
- CONST_CAST(GLEW_EXT_compiled_vertex_array) = _glewSearchExtension("GL_EXT_compiled_vertex_array", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_compiled_vertex_array) CONST_CAST(GLEW_EXT_compiled_vertex_array) = !_glewInit_GL_EXT_compiled_vertex_array(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_compiled_vertex_array = _glewSearchExtension("GL_EXT_compiled_vertex_array", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_compiled_vertex_array) GLEW_EXT_compiled_vertex_array = !_glewInit_GL_EXT_compiled_vertex_array(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_compiled_vertex_array */
#ifdef GL_EXT_convolution
- CONST_CAST(GLEW_EXT_convolution) = _glewSearchExtension("GL_EXT_convolution", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_convolution) CONST_CAST(GLEW_EXT_convolution) = !_glewInit_GL_EXT_convolution(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_convolution = _glewSearchExtension("GL_EXT_convolution", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_convolution) GLEW_EXT_convolution = !_glewInit_GL_EXT_convolution(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_convolution */
#ifdef GL_EXT_coordinate_frame
- CONST_CAST(GLEW_EXT_coordinate_frame) = _glewSearchExtension("GL_EXT_coordinate_frame", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_coordinate_frame) CONST_CAST(GLEW_EXT_coordinate_frame) = !_glewInit_GL_EXT_coordinate_frame(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_coordinate_frame = _glewSearchExtension("GL_EXT_coordinate_frame", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_coordinate_frame) GLEW_EXT_coordinate_frame = !_glewInit_GL_EXT_coordinate_frame(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_coordinate_frame */
#ifdef GL_EXT_copy_texture
- CONST_CAST(GLEW_EXT_copy_texture) = _glewSearchExtension("GL_EXT_copy_texture", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_copy_texture) CONST_CAST(GLEW_EXT_copy_texture) = !_glewInit_GL_EXT_copy_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_copy_texture = _glewSearchExtension("GL_EXT_copy_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_copy_texture) GLEW_EXT_copy_texture = !_glewInit_GL_EXT_copy_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_copy_texture */
#ifdef GL_EXT_cull_vertex
- CONST_CAST(GLEW_EXT_cull_vertex) = _glewSearchExtension("GL_EXT_cull_vertex", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_cull_vertex) CONST_CAST(GLEW_EXT_cull_vertex) = !_glewInit_GL_EXT_cull_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_cull_vertex = _glewSearchExtension("GL_EXT_cull_vertex", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_cull_vertex) GLEW_EXT_cull_vertex = !_glewInit_GL_EXT_cull_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_cull_vertex */
+#ifdef GL_EXT_debug_label
+ GLEW_EXT_debug_label = _glewSearchExtension("GL_EXT_debug_label", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_debug_label) GLEW_EXT_debug_label = !_glewInit_GL_EXT_debug_label(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_EXT_debug_label */
#ifdef GL_EXT_debug_marker
- CONST_CAST(GLEW_EXT_debug_marker) = _glewSearchExtension("GL_EXT_debug_marker", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_debug_marker) CONST_CAST(GLEW_EXT_debug_marker) = !_glewInit_GL_EXT_debug_marker(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_debug_marker = _glewSearchExtension("GL_EXT_debug_marker", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_debug_marker) GLEW_EXT_debug_marker = !_glewInit_GL_EXT_debug_marker(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_debug_marker */
#ifdef GL_EXT_depth_bounds_test
- CONST_CAST(GLEW_EXT_depth_bounds_test) = _glewSearchExtension("GL_EXT_depth_bounds_test", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_depth_bounds_test) CONST_CAST(GLEW_EXT_depth_bounds_test) = !_glewInit_GL_EXT_depth_bounds_test(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_depth_bounds_test = _glewSearchExtension("GL_EXT_depth_bounds_test", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_depth_bounds_test) GLEW_EXT_depth_bounds_test = !_glewInit_GL_EXT_depth_bounds_test(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_depth_bounds_test */
#ifdef GL_EXT_direct_state_access
- CONST_CAST(GLEW_EXT_direct_state_access) = _glewSearchExtension("GL_EXT_direct_state_access", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_direct_state_access) CONST_CAST(GLEW_EXT_direct_state_access) = !_glewInit_GL_EXT_direct_state_access(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_direct_state_access = _glewSearchExtension("GL_EXT_direct_state_access", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_direct_state_access) GLEW_EXT_direct_state_access = !_glewInit_GL_EXT_direct_state_access(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_direct_state_access */
#ifdef GL_EXT_draw_buffers2
- CONST_CAST(GLEW_EXT_draw_buffers2) = _glewSearchExtension("GL_EXT_draw_buffers2", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_draw_buffers2) CONST_CAST(GLEW_EXT_draw_buffers2) = !_glewInit_GL_EXT_draw_buffers2(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_draw_buffers2 = _glewSearchExtension("GL_EXT_draw_buffers2", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_draw_buffers2) GLEW_EXT_draw_buffers2 = !_glewInit_GL_EXT_draw_buffers2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_draw_buffers2 */
#ifdef GL_EXT_draw_instanced
- CONST_CAST(GLEW_EXT_draw_instanced) = _glewSearchExtension("GL_EXT_draw_instanced", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_draw_instanced) CONST_CAST(GLEW_EXT_draw_instanced) = !_glewInit_GL_EXT_draw_instanced(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_draw_instanced = _glewSearchExtension("GL_EXT_draw_instanced", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_draw_instanced) GLEW_EXT_draw_instanced = !_glewInit_GL_EXT_draw_instanced(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_draw_instanced */
#ifdef GL_EXT_draw_range_elements
- CONST_CAST(GLEW_EXT_draw_range_elements) = _glewSearchExtension("GL_EXT_draw_range_elements", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_draw_range_elements) CONST_CAST(GLEW_EXT_draw_range_elements) = !_glewInit_GL_EXT_draw_range_elements(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_draw_range_elements = _glewSearchExtension("GL_EXT_draw_range_elements", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_draw_range_elements) GLEW_EXT_draw_range_elements = !_glewInit_GL_EXT_draw_range_elements(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_draw_range_elements */
#ifdef GL_EXT_fog_coord
- CONST_CAST(GLEW_EXT_fog_coord) = _glewSearchExtension("GL_EXT_fog_coord", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_fog_coord) CONST_CAST(GLEW_EXT_fog_coord) = !_glewInit_GL_EXT_fog_coord(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_fog_coord = _glewSearchExtension("GL_EXT_fog_coord", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_fog_coord) GLEW_EXT_fog_coord = !_glewInit_GL_EXT_fog_coord(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_fog_coord */
#ifdef GL_EXT_fragment_lighting
- CONST_CAST(GLEW_EXT_fragment_lighting) = _glewSearchExtension("GL_EXT_fragment_lighting", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_fragment_lighting) CONST_CAST(GLEW_EXT_fragment_lighting) = !_glewInit_GL_EXT_fragment_lighting(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_fragment_lighting = _glewSearchExtension("GL_EXT_fragment_lighting", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_fragment_lighting) GLEW_EXT_fragment_lighting = !_glewInit_GL_EXT_fragment_lighting(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_fragment_lighting */
#ifdef GL_EXT_framebuffer_blit
- CONST_CAST(GLEW_EXT_framebuffer_blit) = _glewSearchExtension("GL_EXT_framebuffer_blit", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_framebuffer_blit) CONST_CAST(GLEW_EXT_framebuffer_blit) = !_glewInit_GL_EXT_framebuffer_blit(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_framebuffer_blit = _glewSearchExtension("GL_EXT_framebuffer_blit", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_framebuffer_blit) GLEW_EXT_framebuffer_blit = !_glewInit_GL_EXT_framebuffer_blit(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_framebuffer_blit */
#ifdef GL_EXT_framebuffer_multisample
- CONST_CAST(GLEW_EXT_framebuffer_multisample) = _glewSearchExtension("GL_EXT_framebuffer_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_framebuffer_multisample) CONST_CAST(GLEW_EXT_framebuffer_multisample) = !_glewInit_GL_EXT_framebuffer_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_framebuffer_multisample = _glewSearchExtension("GL_EXT_framebuffer_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_framebuffer_multisample) GLEW_EXT_framebuffer_multisample = !_glewInit_GL_EXT_framebuffer_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_framebuffer_multisample */
#ifdef GL_EXT_framebuffer_multisample_blit_scaled
- CONST_CAST(GLEW_EXT_framebuffer_multisample_blit_scaled) = _glewSearchExtension("GL_EXT_framebuffer_multisample_blit_scaled", extStart, extEnd);
+ GLEW_EXT_framebuffer_multisample_blit_scaled = _glewSearchExtension("GL_EXT_framebuffer_multisample_blit_scaled", extStart, extEnd);
#endif /* GL_EXT_framebuffer_multisample_blit_scaled */
#ifdef GL_EXT_framebuffer_object
- CONST_CAST(GLEW_EXT_framebuffer_object) = _glewSearchExtension("GL_EXT_framebuffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_framebuffer_object) CONST_CAST(GLEW_EXT_framebuffer_object) = !_glewInit_GL_EXT_framebuffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_framebuffer_object = _glewSearchExtension("GL_EXT_framebuffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_framebuffer_object) GLEW_EXT_framebuffer_object = !_glewInit_GL_EXT_framebuffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_framebuffer_object */
#ifdef GL_EXT_framebuffer_sRGB
- CONST_CAST(GLEW_EXT_framebuffer_sRGB) = _glewSearchExtension("GL_EXT_framebuffer_sRGB", extStart, extEnd);
+ GLEW_EXT_framebuffer_sRGB = _glewSearchExtension("GL_EXT_framebuffer_sRGB", extStart, extEnd);
#endif /* GL_EXT_framebuffer_sRGB */
#ifdef GL_EXT_geometry_shader4
- CONST_CAST(GLEW_EXT_geometry_shader4) = _glewSearchExtension("GL_EXT_geometry_shader4", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_geometry_shader4) CONST_CAST(GLEW_EXT_geometry_shader4) = !_glewInit_GL_EXT_geometry_shader4(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_geometry_shader4 = _glewSearchExtension("GL_EXT_geometry_shader4", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_geometry_shader4) GLEW_EXT_geometry_shader4 = !_glewInit_GL_EXT_geometry_shader4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_geometry_shader4 */
#ifdef GL_EXT_gpu_program_parameters
- CONST_CAST(GLEW_EXT_gpu_program_parameters) = _glewSearchExtension("GL_EXT_gpu_program_parameters", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_gpu_program_parameters) CONST_CAST(GLEW_EXT_gpu_program_parameters) = !_glewInit_GL_EXT_gpu_program_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_gpu_program_parameters = _glewSearchExtension("GL_EXT_gpu_program_parameters", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_gpu_program_parameters) GLEW_EXT_gpu_program_parameters = !_glewInit_GL_EXT_gpu_program_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_gpu_program_parameters */
#ifdef GL_EXT_gpu_shader4
- CONST_CAST(GLEW_EXT_gpu_shader4) = _glewSearchExtension("GL_EXT_gpu_shader4", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_gpu_shader4) CONST_CAST(GLEW_EXT_gpu_shader4) = !_glewInit_GL_EXT_gpu_shader4(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_gpu_shader4 = _glewSearchExtension("GL_EXT_gpu_shader4", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_gpu_shader4) GLEW_EXT_gpu_shader4 = !_glewInit_GL_EXT_gpu_shader4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_gpu_shader4 */
#ifdef GL_EXT_histogram
- CONST_CAST(GLEW_EXT_histogram) = _glewSearchExtension("GL_EXT_histogram", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_histogram) CONST_CAST(GLEW_EXT_histogram) = !_glewInit_GL_EXT_histogram(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_histogram = _glewSearchExtension("GL_EXT_histogram", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_histogram) GLEW_EXT_histogram = !_glewInit_GL_EXT_histogram(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_histogram */
#ifdef GL_EXT_index_array_formats
- CONST_CAST(GLEW_EXT_index_array_formats) = _glewSearchExtension("GL_EXT_index_array_formats", extStart, extEnd);
+ GLEW_EXT_index_array_formats = _glewSearchExtension("GL_EXT_index_array_formats", extStart, extEnd);
#endif /* GL_EXT_index_array_formats */
#ifdef GL_EXT_index_func
- CONST_CAST(GLEW_EXT_index_func) = _glewSearchExtension("GL_EXT_index_func", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_index_func) CONST_CAST(GLEW_EXT_index_func) = !_glewInit_GL_EXT_index_func(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_index_func = _glewSearchExtension("GL_EXT_index_func", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_index_func) GLEW_EXT_index_func = !_glewInit_GL_EXT_index_func(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_index_func */
#ifdef GL_EXT_index_material
- CONST_CAST(GLEW_EXT_index_material) = _glewSearchExtension("GL_EXT_index_material", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_index_material) CONST_CAST(GLEW_EXT_index_material) = !_glewInit_GL_EXT_index_material(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_index_material = _glewSearchExtension("GL_EXT_index_material", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_index_material) GLEW_EXT_index_material = !_glewInit_GL_EXT_index_material(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_index_material */
#ifdef GL_EXT_index_texture
- CONST_CAST(GLEW_EXT_index_texture) = _glewSearchExtension("GL_EXT_index_texture", extStart, extEnd);
+ GLEW_EXT_index_texture = _glewSearchExtension("GL_EXT_index_texture", extStart, extEnd);
#endif /* GL_EXT_index_texture */
#ifdef GL_EXT_light_texture
- CONST_CAST(GLEW_EXT_light_texture) = _glewSearchExtension("GL_EXT_light_texture", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_light_texture) CONST_CAST(GLEW_EXT_light_texture) = !_glewInit_GL_EXT_light_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_light_texture = _glewSearchExtension("GL_EXT_light_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_light_texture) GLEW_EXT_light_texture = !_glewInit_GL_EXT_light_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_light_texture */
#ifdef GL_EXT_misc_attribute
- CONST_CAST(GLEW_EXT_misc_attribute) = _glewSearchExtension("GL_EXT_misc_attribute", extStart, extEnd);
+ GLEW_EXT_misc_attribute = _glewSearchExtension("GL_EXT_misc_attribute", extStart, extEnd);
#endif /* GL_EXT_misc_attribute */
#ifdef GL_EXT_multi_draw_arrays
- CONST_CAST(GLEW_EXT_multi_draw_arrays) = _glewSearchExtension("GL_EXT_multi_draw_arrays", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_multi_draw_arrays) CONST_CAST(GLEW_EXT_multi_draw_arrays) = !_glewInit_GL_EXT_multi_draw_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_multi_draw_arrays = _glewSearchExtension("GL_EXT_multi_draw_arrays", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_multi_draw_arrays) GLEW_EXT_multi_draw_arrays = !_glewInit_GL_EXT_multi_draw_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_multi_draw_arrays */
#ifdef GL_EXT_multisample
- CONST_CAST(GLEW_EXT_multisample) = _glewSearchExtension("GL_EXT_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_multisample) CONST_CAST(GLEW_EXT_multisample) = !_glewInit_GL_EXT_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_multisample = _glewSearchExtension("GL_EXT_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_multisample) GLEW_EXT_multisample = !_glewInit_GL_EXT_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_multisample */
#ifdef GL_EXT_packed_depth_stencil
- CONST_CAST(GLEW_EXT_packed_depth_stencil) = _glewSearchExtension("GL_EXT_packed_depth_stencil", extStart, extEnd);
+ GLEW_EXT_packed_depth_stencil = _glewSearchExtension("GL_EXT_packed_depth_stencil", extStart, extEnd);
#endif /* GL_EXT_packed_depth_stencil */
#ifdef GL_EXT_packed_float
- CONST_CAST(GLEW_EXT_packed_float) = _glewSearchExtension("GL_EXT_packed_float", extStart, extEnd);
+ GLEW_EXT_packed_float = _glewSearchExtension("GL_EXT_packed_float", extStart, extEnd);
#endif /* GL_EXT_packed_float */
#ifdef GL_EXT_packed_pixels
- CONST_CAST(GLEW_EXT_packed_pixels) = _glewSearchExtension("GL_EXT_packed_pixels", extStart, extEnd);
+ GLEW_EXT_packed_pixels = _glewSearchExtension("GL_EXT_packed_pixels", extStart, extEnd);
#endif /* GL_EXT_packed_pixels */
#ifdef GL_EXT_paletted_texture
- CONST_CAST(GLEW_EXT_paletted_texture) = _glewSearchExtension("GL_EXT_paletted_texture", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_paletted_texture) CONST_CAST(GLEW_EXT_paletted_texture) = !_glewInit_GL_EXT_paletted_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_paletted_texture = _glewSearchExtension("GL_EXT_paletted_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_paletted_texture) GLEW_EXT_paletted_texture = !_glewInit_GL_EXT_paletted_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_paletted_texture */
#ifdef GL_EXT_pixel_buffer_object
- CONST_CAST(GLEW_EXT_pixel_buffer_object) = _glewSearchExtension("GL_EXT_pixel_buffer_object", extStart, extEnd);
+ GLEW_EXT_pixel_buffer_object = _glewSearchExtension("GL_EXT_pixel_buffer_object", extStart, extEnd);
#endif /* GL_EXT_pixel_buffer_object */
#ifdef GL_EXT_pixel_transform
- CONST_CAST(GLEW_EXT_pixel_transform) = _glewSearchExtension("GL_EXT_pixel_transform", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_pixel_transform) CONST_CAST(GLEW_EXT_pixel_transform) = !_glewInit_GL_EXT_pixel_transform(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_pixel_transform = _glewSearchExtension("GL_EXT_pixel_transform", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_pixel_transform) GLEW_EXT_pixel_transform = !_glewInit_GL_EXT_pixel_transform(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_pixel_transform */
#ifdef GL_EXT_pixel_transform_color_table
- CONST_CAST(GLEW_EXT_pixel_transform_color_table) = _glewSearchExtension("GL_EXT_pixel_transform_color_table", extStart, extEnd);
+ GLEW_EXT_pixel_transform_color_table = _glewSearchExtension("GL_EXT_pixel_transform_color_table", extStart, extEnd);
#endif /* GL_EXT_pixel_transform_color_table */
#ifdef GL_EXT_point_parameters
- CONST_CAST(GLEW_EXT_point_parameters) = _glewSearchExtension("GL_EXT_point_parameters", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_point_parameters) CONST_CAST(GLEW_EXT_point_parameters) = !_glewInit_GL_EXT_point_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_point_parameters = _glewSearchExtension("GL_EXT_point_parameters", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_point_parameters) GLEW_EXT_point_parameters = !_glewInit_GL_EXT_point_parameters(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_point_parameters */
#ifdef GL_EXT_polygon_offset
- CONST_CAST(GLEW_EXT_polygon_offset) = _glewSearchExtension("GL_EXT_polygon_offset", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_polygon_offset) CONST_CAST(GLEW_EXT_polygon_offset) = !_glewInit_GL_EXT_polygon_offset(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_polygon_offset = _glewSearchExtension("GL_EXT_polygon_offset", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_polygon_offset) GLEW_EXT_polygon_offset = !_glewInit_GL_EXT_polygon_offset(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_polygon_offset */
+#ifdef GL_EXT_polygon_offset_clamp
+ GLEW_EXT_polygon_offset_clamp = _glewSearchExtension("GL_EXT_polygon_offset_clamp", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_polygon_offset_clamp) GLEW_EXT_polygon_offset_clamp = !_glewInit_GL_EXT_polygon_offset_clamp(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_EXT_polygon_offset_clamp */
+#ifdef GL_EXT_post_depth_coverage
+ GLEW_EXT_post_depth_coverage = _glewSearchExtension("GL_EXT_post_depth_coverage", extStart, extEnd);
+#endif /* GL_EXT_post_depth_coverage */
#ifdef GL_EXT_provoking_vertex
- CONST_CAST(GLEW_EXT_provoking_vertex) = _glewSearchExtension("GL_EXT_provoking_vertex", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_provoking_vertex) CONST_CAST(GLEW_EXT_provoking_vertex) = !_glewInit_GL_EXT_provoking_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_provoking_vertex = _glewSearchExtension("GL_EXT_provoking_vertex", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_provoking_vertex) GLEW_EXT_provoking_vertex = !_glewInit_GL_EXT_provoking_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_provoking_vertex */
+#ifdef GL_EXT_raster_multisample
+ GLEW_EXT_raster_multisample = _glewSearchExtension("GL_EXT_raster_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_raster_multisample) GLEW_EXT_raster_multisample = !_glewInit_GL_EXT_raster_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_EXT_raster_multisample */
#ifdef GL_EXT_rescale_normal
- CONST_CAST(GLEW_EXT_rescale_normal) = _glewSearchExtension("GL_EXT_rescale_normal", extStart, extEnd);
+ GLEW_EXT_rescale_normal = _glewSearchExtension("GL_EXT_rescale_normal", extStart, extEnd);
#endif /* GL_EXT_rescale_normal */
#ifdef GL_EXT_scene_marker
- CONST_CAST(GLEW_EXT_scene_marker) = _glewSearchExtension("GL_EXT_scene_marker", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_scene_marker) CONST_CAST(GLEW_EXT_scene_marker) = !_glewInit_GL_EXT_scene_marker(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_scene_marker = _glewSearchExtension("GL_EXT_scene_marker", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_scene_marker) GLEW_EXT_scene_marker = !_glewInit_GL_EXT_scene_marker(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_scene_marker */
#ifdef GL_EXT_secondary_color
- CONST_CAST(GLEW_EXT_secondary_color) = _glewSearchExtension("GL_EXT_secondary_color", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_secondary_color) CONST_CAST(GLEW_EXT_secondary_color) = !_glewInit_GL_EXT_secondary_color(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_secondary_color = _glewSearchExtension("GL_EXT_secondary_color", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_secondary_color) GLEW_EXT_secondary_color = !_glewInit_GL_EXT_secondary_color(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_secondary_color */
#ifdef GL_EXT_separate_shader_objects
- CONST_CAST(GLEW_EXT_separate_shader_objects) = _glewSearchExtension("GL_EXT_separate_shader_objects", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_separate_shader_objects) CONST_CAST(GLEW_EXT_separate_shader_objects) = !_glewInit_GL_EXT_separate_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_separate_shader_objects = _glewSearchExtension("GL_EXT_separate_shader_objects", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_separate_shader_objects) GLEW_EXT_separate_shader_objects = !_glewInit_GL_EXT_separate_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_separate_shader_objects */
#ifdef GL_EXT_separate_specular_color
- CONST_CAST(GLEW_EXT_separate_specular_color) = _glewSearchExtension("GL_EXT_separate_specular_color", extStart, extEnd);
+ GLEW_EXT_separate_specular_color = _glewSearchExtension("GL_EXT_separate_specular_color", extStart, extEnd);
#endif /* GL_EXT_separate_specular_color */
+#ifdef GL_EXT_shader_image_load_formatted
+ GLEW_EXT_shader_image_load_formatted = _glewSearchExtension("GL_EXT_shader_image_load_formatted", extStart, extEnd);
+#endif /* GL_EXT_shader_image_load_formatted */
#ifdef GL_EXT_shader_image_load_store
- CONST_CAST(GLEW_EXT_shader_image_load_store) = _glewSearchExtension("GL_EXT_shader_image_load_store", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_shader_image_load_store) CONST_CAST(GLEW_EXT_shader_image_load_store) = !_glewInit_GL_EXT_shader_image_load_store(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_shader_image_load_store = _glewSearchExtension("GL_EXT_shader_image_load_store", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_shader_image_load_store) GLEW_EXT_shader_image_load_store = !_glewInit_GL_EXT_shader_image_load_store(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_shader_image_load_store */
+#ifdef GL_EXT_shader_integer_mix
+ GLEW_EXT_shader_integer_mix = _glewSearchExtension("GL_EXT_shader_integer_mix", extStart, extEnd);
+#endif /* GL_EXT_shader_integer_mix */
#ifdef GL_EXT_shadow_funcs
- CONST_CAST(GLEW_EXT_shadow_funcs) = _glewSearchExtension("GL_EXT_shadow_funcs", extStart, extEnd);
+ GLEW_EXT_shadow_funcs = _glewSearchExtension("GL_EXT_shadow_funcs", extStart, extEnd);
#endif /* GL_EXT_shadow_funcs */
#ifdef GL_EXT_shared_texture_palette
- CONST_CAST(GLEW_EXT_shared_texture_palette) = _glewSearchExtension("GL_EXT_shared_texture_palette", extStart, extEnd);
+ GLEW_EXT_shared_texture_palette = _glewSearchExtension("GL_EXT_shared_texture_palette", extStart, extEnd);
#endif /* GL_EXT_shared_texture_palette */
+#ifdef GL_EXT_sparse_texture2
+ GLEW_EXT_sparse_texture2 = _glewSearchExtension("GL_EXT_sparse_texture2", extStart, extEnd);
+#endif /* GL_EXT_sparse_texture2 */
#ifdef GL_EXT_stencil_clear_tag
- CONST_CAST(GLEW_EXT_stencil_clear_tag) = _glewSearchExtension("GL_EXT_stencil_clear_tag", extStart, extEnd);
+ GLEW_EXT_stencil_clear_tag = _glewSearchExtension("GL_EXT_stencil_clear_tag", extStart, extEnd);
#endif /* GL_EXT_stencil_clear_tag */
#ifdef GL_EXT_stencil_two_side
- CONST_CAST(GLEW_EXT_stencil_two_side) = _glewSearchExtension("GL_EXT_stencil_two_side", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_stencil_two_side) CONST_CAST(GLEW_EXT_stencil_two_side) = !_glewInit_GL_EXT_stencil_two_side(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_stencil_two_side = _glewSearchExtension("GL_EXT_stencil_two_side", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_stencil_two_side) GLEW_EXT_stencil_two_side = !_glewInit_GL_EXT_stencil_two_side(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_stencil_two_side */
#ifdef GL_EXT_stencil_wrap
- CONST_CAST(GLEW_EXT_stencil_wrap) = _glewSearchExtension("GL_EXT_stencil_wrap", extStart, extEnd);
+ GLEW_EXT_stencil_wrap = _glewSearchExtension("GL_EXT_stencil_wrap", extStart, extEnd);
#endif /* GL_EXT_stencil_wrap */
#ifdef GL_EXT_subtexture
- CONST_CAST(GLEW_EXT_subtexture) = _glewSearchExtension("GL_EXT_subtexture", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_subtexture) CONST_CAST(GLEW_EXT_subtexture) = !_glewInit_GL_EXT_subtexture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_subtexture = _glewSearchExtension("GL_EXT_subtexture", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_subtexture) GLEW_EXT_subtexture = !_glewInit_GL_EXT_subtexture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_subtexture */
#ifdef GL_EXT_texture
- CONST_CAST(GLEW_EXT_texture) = _glewSearchExtension("GL_EXT_texture", extStart, extEnd);
+ GLEW_EXT_texture = _glewSearchExtension("GL_EXT_texture", extStart, extEnd);
#endif /* GL_EXT_texture */
#ifdef GL_EXT_texture3D
- CONST_CAST(GLEW_EXT_texture3D) = _glewSearchExtension("GL_EXT_texture3D", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_texture3D) CONST_CAST(GLEW_EXT_texture3D) = !_glewInit_GL_EXT_texture3D(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_texture3D = _glewSearchExtension("GL_EXT_texture3D", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_texture3D) GLEW_EXT_texture3D = !_glewInit_GL_EXT_texture3D(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_texture3D */
#ifdef GL_EXT_texture_array
- CONST_CAST(GLEW_EXT_texture_array) = _glewSearchExtension("GL_EXT_texture_array", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_texture_array) CONST_CAST(GLEW_EXT_texture_array) = !_glewInit_GL_EXT_texture_array(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_texture_array = _glewSearchExtension("GL_EXT_texture_array", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_texture_array) GLEW_EXT_texture_array = !_glewInit_GL_EXT_texture_array(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_texture_array */
#ifdef GL_EXT_texture_buffer_object
- CONST_CAST(GLEW_EXT_texture_buffer_object) = _glewSearchExtension("GL_EXT_texture_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_texture_buffer_object) CONST_CAST(GLEW_EXT_texture_buffer_object) = !_glewInit_GL_EXT_texture_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_texture_buffer_object = _glewSearchExtension("GL_EXT_texture_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_texture_buffer_object) GLEW_EXT_texture_buffer_object = !_glewInit_GL_EXT_texture_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_texture_buffer_object */
#ifdef GL_EXT_texture_compression_dxt1
- CONST_CAST(GLEW_EXT_texture_compression_dxt1) = _glewSearchExtension("GL_EXT_texture_compression_dxt1", extStart, extEnd);
+ GLEW_EXT_texture_compression_dxt1 = _glewSearchExtension("GL_EXT_texture_compression_dxt1", extStart, extEnd);
#endif /* GL_EXT_texture_compression_dxt1 */
#ifdef GL_EXT_texture_compression_latc
- CONST_CAST(GLEW_EXT_texture_compression_latc) = _glewSearchExtension("GL_EXT_texture_compression_latc", extStart, extEnd);
+ GLEW_EXT_texture_compression_latc = _glewSearchExtension("GL_EXT_texture_compression_latc", extStart, extEnd);
#endif /* GL_EXT_texture_compression_latc */
#ifdef GL_EXT_texture_compression_rgtc
- CONST_CAST(GLEW_EXT_texture_compression_rgtc) = _glewSearchExtension("GL_EXT_texture_compression_rgtc", extStart, extEnd);
+ GLEW_EXT_texture_compression_rgtc = _glewSearchExtension("GL_EXT_texture_compression_rgtc", extStart, extEnd);
#endif /* GL_EXT_texture_compression_rgtc */
#ifdef GL_EXT_texture_compression_s3tc
- CONST_CAST(GLEW_EXT_texture_compression_s3tc) = _glewSearchExtension("GL_EXT_texture_compression_s3tc", extStart, extEnd);
+ GLEW_EXT_texture_compression_s3tc = _glewSearchExtension("GL_EXT_texture_compression_s3tc", extStart, extEnd);
#endif /* GL_EXT_texture_compression_s3tc */
#ifdef GL_EXT_texture_cube_map
- CONST_CAST(GLEW_EXT_texture_cube_map) = _glewSearchExtension("GL_EXT_texture_cube_map", extStart, extEnd);
+ GLEW_EXT_texture_cube_map = _glewSearchExtension("GL_EXT_texture_cube_map", extStart, extEnd);
#endif /* GL_EXT_texture_cube_map */
#ifdef GL_EXT_texture_edge_clamp
- CONST_CAST(GLEW_EXT_texture_edge_clamp) = _glewSearchExtension("GL_EXT_texture_edge_clamp", extStart, extEnd);
+ GLEW_EXT_texture_edge_clamp = _glewSearchExtension("GL_EXT_texture_edge_clamp", extStart, extEnd);
#endif /* GL_EXT_texture_edge_clamp */
#ifdef GL_EXT_texture_env
- CONST_CAST(GLEW_EXT_texture_env) = _glewSearchExtension("GL_EXT_texture_env", extStart, extEnd);
+ GLEW_EXT_texture_env = _glewSearchExtension("GL_EXT_texture_env", extStart, extEnd);
#endif /* GL_EXT_texture_env */
#ifdef GL_EXT_texture_env_add
- CONST_CAST(GLEW_EXT_texture_env_add) = _glewSearchExtension("GL_EXT_texture_env_add", extStart, extEnd);
+ GLEW_EXT_texture_env_add = _glewSearchExtension("GL_EXT_texture_env_add", extStart, extEnd);
#endif /* GL_EXT_texture_env_add */
#ifdef GL_EXT_texture_env_combine
- CONST_CAST(GLEW_EXT_texture_env_combine) = _glewSearchExtension("GL_EXT_texture_env_combine", extStart, extEnd);
+ GLEW_EXT_texture_env_combine = _glewSearchExtension("GL_EXT_texture_env_combine", extStart, extEnd);
#endif /* GL_EXT_texture_env_combine */
#ifdef GL_EXT_texture_env_dot3
- CONST_CAST(GLEW_EXT_texture_env_dot3) = _glewSearchExtension("GL_EXT_texture_env_dot3", extStart, extEnd);
+ GLEW_EXT_texture_env_dot3 = _glewSearchExtension("GL_EXT_texture_env_dot3", extStart, extEnd);
#endif /* GL_EXT_texture_env_dot3 */
#ifdef GL_EXT_texture_filter_anisotropic
- CONST_CAST(GLEW_EXT_texture_filter_anisotropic) = _glewSearchExtension("GL_EXT_texture_filter_anisotropic", extStart, extEnd);
+ GLEW_EXT_texture_filter_anisotropic = _glewSearchExtension("GL_EXT_texture_filter_anisotropic", extStart, extEnd);
#endif /* GL_EXT_texture_filter_anisotropic */
+#ifdef GL_EXT_texture_filter_minmax
+ GLEW_EXT_texture_filter_minmax = _glewSearchExtension("GL_EXT_texture_filter_minmax", extStart, extEnd);
+#endif /* GL_EXT_texture_filter_minmax */
#ifdef GL_EXT_texture_integer
- CONST_CAST(GLEW_EXT_texture_integer) = _glewSearchExtension("GL_EXT_texture_integer", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_texture_integer) CONST_CAST(GLEW_EXT_texture_integer) = !_glewInit_GL_EXT_texture_integer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_texture_integer = _glewSearchExtension("GL_EXT_texture_integer", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_texture_integer) GLEW_EXT_texture_integer = !_glewInit_GL_EXT_texture_integer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_texture_integer */
#ifdef GL_EXT_texture_lod_bias
- CONST_CAST(GLEW_EXT_texture_lod_bias) = _glewSearchExtension("GL_EXT_texture_lod_bias", extStart, extEnd);
+ GLEW_EXT_texture_lod_bias = _glewSearchExtension("GL_EXT_texture_lod_bias", extStart, extEnd);
#endif /* GL_EXT_texture_lod_bias */
#ifdef GL_EXT_texture_mirror_clamp
- CONST_CAST(GLEW_EXT_texture_mirror_clamp) = _glewSearchExtension("GL_EXT_texture_mirror_clamp", extStart, extEnd);
+ GLEW_EXT_texture_mirror_clamp = _glewSearchExtension("GL_EXT_texture_mirror_clamp", extStart, extEnd);
#endif /* GL_EXT_texture_mirror_clamp */
#ifdef GL_EXT_texture_object
- CONST_CAST(GLEW_EXT_texture_object) = _glewSearchExtension("GL_EXT_texture_object", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_texture_object) CONST_CAST(GLEW_EXT_texture_object) = !_glewInit_GL_EXT_texture_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_texture_object = _glewSearchExtension("GL_EXT_texture_object", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_texture_object) GLEW_EXT_texture_object = !_glewInit_GL_EXT_texture_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_texture_object */
#ifdef GL_EXT_texture_perturb_normal
- CONST_CAST(GLEW_EXT_texture_perturb_normal) = _glewSearchExtension("GL_EXT_texture_perturb_normal", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_texture_perturb_normal) CONST_CAST(GLEW_EXT_texture_perturb_normal) = !_glewInit_GL_EXT_texture_perturb_normal(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_texture_perturb_normal = _glewSearchExtension("GL_EXT_texture_perturb_normal", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_texture_perturb_normal) GLEW_EXT_texture_perturb_normal = !_glewInit_GL_EXT_texture_perturb_normal(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_texture_perturb_normal */
#ifdef GL_EXT_texture_rectangle
- CONST_CAST(GLEW_EXT_texture_rectangle) = _glewSearchExtension("GL_EXT_texture_rectangle", extStart, extEnd);
+ GLEW_EXT_texture_rectangle = _glewSearchExtension("GL_EXT_texture_rectangle", extStart, extEnd);
#endif /* GL_EXT_texture_rectangle */
#ifdef GL_EXT_texture_sRGB
- CONST_CAST(GLEW_EXT_texture_sRGB) = _glewSearchExtension("GL_EXT_texture_sRGB", extStart, extEnd);
+ GLEW_EXT_texture_sRGB = _glewSearchExtension("GL_EXT_texture_sRGB", extStart, extEnd);
#endif /* GL_EXT_texture_sRGB */
#ifdef GL_EXT_texture_sRGB_decode
- CONST_CAST(GLEW_EXT_texture_sRGB_decode) = _glewSearchExtension("GL_EXT_texture_sRGB_decode", extStart, extEnd);
+ GLEW_EXT_texture_sRGB_decode = _glewSearchExtension("GL_EXT_texture_sRGB_decode", extStart, extEnd);
#endif /* GL_EXT_texture_sRGB_decode */
#ifdef GL_EXT_texture_shared_exponent
- CONST_CAST(GLEW_EXT_texture_shared_exponent) = _glewSearchExtension("GL_EXT_texture_shared_exponent", extStart, extEnd);
+ GLEW_EXT_texture_shared_exponent = _glewSearchExtension("GL_EXT_texture_shared_exponent", extStart, extEnd);
#endif /* GL_EXT_texture_shared_exponent */
#ifdef GL_EXT_texture_snorm
- CONST_CAST(GLEW_EXT_texture_snorm) = _glewSearchExtension("GL_EXT_texture_snorm", extStart, extEnd);
+ GLEW_EXT_texture_snorm = _glewSearchExtension("GL_EXT_texture_snorm", extStart, extEnd);
#endif /* GL_EXT_texture_snorm */
#ifdef GL_EXT_texture_swizzle
- CONST_CAST(GLEW_EXT_texture_swizzle) = _glewSearchExtension("GL_EXT_texture_swizzle", extStart, extEnd);
+ GLEW_EXT_texture_swizzle = _glewSearchExtension("GL_EXT_texture_swizzle", extStart, extEnd);
#endif /* GL_EXT_texture_swizzle */
#ifdef GL_EXT_timer_query
- CONST_CAST(GLEW_EXT_timer_query) = _glewSearchExtension("GL_EXT_timer_query", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_timer_query) CONST_CAST(GLEW_EXT_timer_query) = !_glewInit_GL_EXT_timer_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_timer_query = _glewSearchExtension("GL_EXT_timer_query", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_timer_query) GLEW_EXT_timer_query = !_glewInit_GL_EXT_timer_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_timer_query */
#ifdef GL_EXT_transform_feedback
- CONST_CAST(GLEW_EXT_transform_feedback) = _glewSearchExtension("GL_EXT_transform_feedback", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_transform_feedback) CONST_CAST(GLEW_EXT_transform_feedback) = !_glewInit_GL_EXT_transform_feedback(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_transform_feedback = _glewSearchExtension("GL_EXT_transform_feedback", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_transform_feedback) GLEW_EXT_transform_feedback = !_glewInit_GL_EXT_transform_feedback(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_transform_feedback */
#ifdef GL_EXT_vertex_array
- CONST_CAST(GLEW_EXT_vertex_array) = _glewSearchExtension("GL_EXT_vertex_array", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_vertex_array) CONST_CAST(GLEW_EXT_vertex_array) = !_glewInit_GL_EXT_vertex_array(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_vertex_array = _glewSearchExtension("GL_EXT_vertex_array", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_vertex_array) GLEW_EXT_vertex_array = !_glewInit_GL_EXT_vertex_array(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_vertex_array */
#ifdef GL_EXT_vertex_array_bgra
- CONST_CAST(GLEW_EXT_vertex_array_bgra) = _glewSearchExtension("GL_EXT_vertex_array_bgra", extStart, extEnd);
+ GLEW_EXT_vertex_array_bgra = _glewSearchExtension("GL_EXT_vertex_array_bgra", extStart, extEnd);
#endif /* GL_EXT_vertex_array_bgra */
#ifdef GL_EXT_vertex_attrib_64bit
- CONST_CAST(GLEW_EXT_vertex_attrib_64bit) = _glewSearchExtension("GL_EXT_vertex_attrib_64bit", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_vertex_attrib_64bit) CONST_CAST(GLEW_EXT_vertex_attrib_64bit) = !_glewInit_GL_EXT_vertex_attrib_64bit(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_vertex_attrib_64bit = _glewSearchExtension("GL_EXT_vertex_attrib_64bit", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_vertex_attrib_64bit) GLEW_EXT_vertex_attrib_64bit = !_glewInit_GL_EXT_vertex_attrib_64bit(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_vertex_attrib_64bit */
#ifdef GL_EXT_vertex_shader
- CONST_CAST(GLEW_EXT_vertex_shader) = _glewSearchExtension("GL_EXT_vertex_shader", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_vertex_shader) CONST_CAST(GLEW_EXT_vertex_shader) = !_glewInit_GL_EXT_vertex_shader(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_vertex_shader = _glewSearchExtension("GL_EXT_vertex_shader", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_vertex_shader) GLEW_EXT_vertex_shader = !_glewInit_GL_EXT_vertex_shader(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_vertex_shader */
#ifdef GL_EXT_vertex_weighting
- CONST_CAST(GLEW_EXT_vertex_weighting) = _glewSearchExtension("GL_EXT_vertex_weighting", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_vertex_weighting) CONST_CAST(GLEW_EXT_vertex_weighting) = !_glewInit_GL_EXT_vertex_weighting(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_vertex_weighting = _glewSearchExtension("GL_EXT_vertex_weighting", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_vertex_weighting) GLEW_EXT_vertex_weighting = !_glewInit_GL_EXT_vertex_weighting(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_vertex_weighting */
#ifdef GL_EXT_x11_sync_object
- CONST_CAST(GLEW_EXT_x11_sync_object) = _glewSearchExtension("GL_EXT_x11_sync_object", extStart, extEnd);
- if (glewExperimental || GLEW_EXT_x11_sync_object) CONST_CAST(GLEW_EXT_x11_sync_object) = !_glewInit_GL_EXT_x11_sync_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_EXT_x11_sync_object = _glewSearchExtension("GL_EXT_x11_sync_object", extStart, extEnd);
+ if (glewExperimental || GLEW_EXT_x11_sync_object) GLEW_EXT_x11_sync_object = !_glewInit_GL_EXT_x11_sync_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_EXT_x11_sync_object */
#ifdef GL_GREMEDY_frame_terminator
- CONST_CAST(GLEW_GREMEDY_frame_terminator) = _glewSearchExtension("GL_GREMEDY_frame_terminator", extStart, extEnd);
- if (glewExperimental || GLEW_GREMEDY_frame_terminator) CONST_CAST(GLEW_GREMEDY_frame_terminator) = !_glewInit_GL_GREMEDY_frame_terminator(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_GREMEDY_frame_terminator = _glewSearchExtension("GL_GREMEDY_frame_terminator", extStart, extEnd);
+ if (glewExperimental || GLEW_GREMEDY_frame_terminator) GLEW_GREMEDY_frame_terminator = !_glewInit_GL_GREMEDY_frame_terminator(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_GREMEDY_frame_terminator */
#ifdef GL_GREMEDY_string_marker
- CONST_CAST(GLEW_GREMEDY_string_marker) = _glewSearchExtension("GL_GREMEDY_string_marker", extStart, extEnd);
- if (glewExperimental || GLEW_GREMEDY_string_marker) CONST_CAST(GLEW_GREMEDY_string_marker) = !_glewInit_GL_GREMEDY_string_marker(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_GREMEDY_string_marker = _glewSearchExtension("GL_GREMEDY_string_marker", extStart, extEnd);
+ if (glewExperimental || GLEW_GREMEDY_string_marker) GLEW_GREMEDY_string_marker = !_glewInit_GL_GREMEDY_string_marker(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_GREMEDY_string_marker */
#ifdef GL_HP_convolution_border_modes
- CONST_CAST(GLEW_HP_convolution_border_modes) = _glewSearchExtension("GL_HP_convolution_border_modes", extStart, extEnd);
+ GLEW_HP_convolution_border_modes = _glewSearchExtension("GL_HP_convolution_border_modes", extStart, extEnd);
#endif /* GL_HP_convolution_border_modes */
#ifdef GL_HP_image_transform
- CONST_CAST(GLEW_HP_image_transform) = _glewSearchExtension("GL_HP_image_transform", extStart, extEnd);
- if (glewExperimental || GLEW_HP_image_transform) CONST_CAST(GLEW_HP_image_transform) = !_glewInit_GL_HP_image_transform(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_HP_image_transform = _glewSearchExtension("GL_HP_image_transform", extStart, extEnd);
+ if (glewExperimental || GLEW_HP_image_transform) GLEW_HP_image_transform = !_glewInit_GL_HP_image_transform(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_HP_image_transform */
#ifdef GL_HP_occlusion_test
- CONST_CAST(GLEW_HP_occlusion_test) = _glewSearchExtension("GL_HP_occlusion_test", extStart, extEnd);
+ GLEW_HP_occlusion_test = _glewSearchExtension("GL_HP_occlusion_test", extStart, extEnd);
#endif /* GL_HP_occlusion_test */
#ifdef GL_HP_texture_lighting
- CONST_CAST(GLEW_HP_texture_lighting) = _glewSearchExtension("GL_HP_texture_lighting", extStart, extEnd);
+ GLEW_HP_texture_lighting = _glewSearchExtension("GL_HP_texture_lighting", extStart, extEnd);
#endif /* GL_HP_texture_lighting */
#ifdef GL_IBM_cull_vertex
- CONST_CAST(GLEW_IBM_cull_vertex) = _glewSearchExtension("GL_IBM_cull_vertex", extStart, extEnd);
+ GLEW_IBM_cull_vertex = _glewSearchExtension("GL_IBM_cull_vertex", extStart, extEnd);
#endif /* GL_IBM_cull_vertex */
#ifdef GL_IBM_multimode_draw_arrays
- CONST_CAST(GLEW_IBM_multimode_draw_arrays) = _glewSearchExtension("GL_IBM_multimode_draw_arrays", extStart, extEnd);
- if (glewExperimental || GLEW_IBM_multimode_draw_arrays) CONST_CAST(GLEW_IBM_multimode_draw_arrays) = !_glewInit_GL_IBM_multimode_draw_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_IBM_multimode_draw_arrays = _glewSearchExtension("GL_IBM_multimode_draw_arrays", extStart, extEnd);
+ if (glewExperimental || GLEW_IBM_multimode_draw_arrays) GLEW_IBM_multimode_draw_arrays = !_glewInit_GL_IBM_multimode_draw_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_IBM_multimode_draw_arrays */
#ifdef GL_IBM_rasterpos_clip
- CONST_CAST(GLEW_IBM_rasterpos_clip) = _glewSearchExtension("GL_IBM_rasterpos_clip", extStart, extEnd);
+ GLEW_IBM_rasterpos_clip = _glewSearchExtension("GL_IBM_rasterpos_clip", extStart, extEnd);
#endif /* GL_IBM_rasterpos_clip */
#ifdef GL_IBM_static_data
- CONST_CAST(GLEW_IBM_static_data) = _glewSearchExtension("GL_IBM_static_data", extStart, extEnd);
+ GLEW_IBM_static_data = _glewSearchExtension("GL_IBM_static_data", extStart, extEnd);
#endif /* GL_IBM_static_data */
#ifdef GL_IBM_texture_mirrored_repeat
- CONST_CAST(GLEW_IBM_texture_mirrored_repeat) = _glewSearchExtension("GL_IBM_texture_mirrored_repeat", extStart, extEnd);
+ GLEW_IBM_texture_mirrored_repeat = _glewSearchExtension("GL_IBM_texture_mirrored_repeat", extStart, extEnd);
#endif /* GL_IBM_texture_mirrored_repeat */
#ifdef GL_IBM_vertex_array_lists
- CONST_CAST(GLEW_IBM_vertex_array_lists) = _glewSearchExtension("GL_IBM_vertex_array_lists", extStart, extEnd);
- if (glewExperimental || GLEW_IBM_vertex_array_lists) CONST_CAST(GLEW_IBM_vertex_array_lists) = !_glewInit_GL_IBM_vertex_array_lists(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_IBM_vertex_array_lists = _glewSearchExtension("GL_IBM_vertex_array_lists", extStart, extEnd);
+ if (glewExperimental || GLEW_IBM_vertex_array_lists) GLEW_IBM_vertex_array_lists = !_glewInit_GL_IBM_vertex_array_lists(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_IBM_vertex_array_lists */
#ifdef GL_INGR_color_clamp
- CONST_CAST(GLEW_INGR_color_clamp) = _glewSearchExtension("GL_INGR_color_clamp", extStart, extEnd);
+ GLEW_INGR_color_clamp = _glewSearchExtension("GL_INGR_color_clamp", extStart, extEnd);
#endif /* GL_INGR_color_clamp */
#ifdef GL_INGR_interlace_read
- CONST_CAST(GLEW_INGR_interlace_read) = _glewSearchExtension("GL_INGR_interlace_read", extStart, extEnd);
+ GLEW_INGR_interlace_read = _glewSearchExtension("GL_INGR_interlace_read", extStart, extEnd);
#endif /* GL_INGR_interlace_read */
+#ifdef GL_INTEL_fragment_shader_ordering
+ GLEW_INTEL_fragment_shader_ordering = _glewSearchExtension("GL_INTEL_fragment_shader_ordering", extStart, extEnd);
+#endif /* GL_INTEL_fragment_shader_ordering */
+#ifdef GL_INTEL_framebuffer_CMAA
+ GLEW_INTEL_framebuffer_CMAA = _glewSearchExtension("GL_INTEL_framebuffer_CMAA", extStart, extEnd);
+#endif /* GL_INTEL_framebuffer_CMAA */
#ifdef GL_INTEL_map_texture
- CONST_CAST(GLEW_INTEL_map_texture) = _glewSearchExtension("GL_INTEL_map_texture", extStart, extEnd);
- if (glewExperimental || GLEW_INTEL_map_texture) CONST_CAST(GLEW_INTEL_map_texture) = !_glewInit_GL_INTEL_map_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_INTEL_map_texture = _glewSearchExtension("GL_INTEL_map_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_INTEL_map_texture) GLEW_INTEL_map_texture = !_glewInit_GL_INTEL_map_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_INTEL_map_texture */
#ifdef GL_INTEL_parallel_arrays
- CONST_CAST(GLEW_INTEL_parallel_arrays) = _glewSearchExtension("GL_INTEL_parallel_arrays", extStart, extEnd);
- if (glewExperimental || GLEW_INTEL_parallel_arrays) CONST_CAST(GLEW_INTEL_parallel_arrays) = !_glewInit_GL_INTEL_parallel_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_INTEL_parallel_arrays = _glewSearchExtension("GL_INTEL_parallel_arrays", extStart, extEnd);
+ if (glewExperimental || GLEW_INTEL_parallel_arrays) GLEW_INTEL_parallel_arrays = !_glewInit_GL_INTEL_parallel_arrays(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_INTEL_parallel_arrays */
+#ifdef GL_INTEL_performance_query
+ GLEW_INTEL_performance_query = _glewSearchExtension("GL_INTEL_performance_query", extStart, extEnd);
+ if (glewExperimental || GLEW_INTEL_performance_query) GLEW_INTEL_performance_query = !_glewInit_GL_INTEL_performance_query(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_INTEL_performance_query */
#ifdef GL_INTEL_texture_scissor
- CONST_CAST(GLEW_INTEL_texture_scissor) = _glewSearchExtension("GL_INTEL_texture_scissor", extStart, extEnd);
- if (glewExperimental || GLEW_INTEL_texture_scissor) CONST_CAST(GLEW_INTEL_texture_scissor) = !_glewInit_GL_INTEL_texture_scissor(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_INTEL_texture_scissor = _glewSearchExtension("GL_INTEL_texture_scissor", extStart, extEnd);
+ if (glewExperimental || GLEW_INTEL_texture_scissor) GLEW_INTEL_texture_scissor = !_glewInit_GL_INTEL_texture_scissor(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_INTEL_texture_scissor */
+#ifdef GL_KHR_blend_equation_advanced
+ GLEW_KHR_blend_equation_advanced = _glewSearchExtension("GL_KHR_blend_equation_advanced", extStart, extEnd);
+ if (glewExperimental || GLEW_KHR_blend_equation_advanced) GLEW_KHR_blend_equation_advanced = !_glewInit_GL_KHR_blend_equation_advanced(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_KHR_blend_equation_advanced */
+#ifdef GL_KHR_blend_equation_advanced_coherent
+ GLEW_KHR_blend_equation_advanced_coherent = _glewSearchExtension("GL_KHR_blend_equation_advanced_coherent", extStart, extEnd);
+#endif /* GL_KHR_blend_equation_advanced_coherent */
+#ifdef GL_KHR_context_flush_control
+ GLEW_KHR_context_flush_control = _glewSearchExtension("GL_KHR_context_flush_control", extStart, extEnd);
+#endif /* GL_KHR_context_flush_control */
#ifdef GL_KHR_debug
- CONST_CAST(GLEW_KHR_debug) = _glewSearchExtension("GL_KHR_debug", extStart, extEnd);
- if (glewExperimental || GLEW_KHR_debug) CONST_CAST(GLEW_KHR_debug) = !_glewInit_GL_KHR_debug(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_KHR_debug = _glewSearchExtension("GL_KHR_debug", extStart, extEnd);
+ if (glewExperimental || GLEW_KHR_debug) GLEW_KHR_debug = !_glewInit_GL_KHR_debug(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_KHR_debug */
+#ifdef GL_KHR_no_error
+ GLEW_KHR_no_error = _glewSearchExtension("GL_KHR_no_error", extStart, extEnd);
+#endif /* GL_KHR_no_error */
+#ifdef GL_KHR_robust_buffer_access_behavior
+ GLEW_KHR_robust_buffer_access_behavior = _glewSearchExtension("GL_KHR_robust_buffer_access_behavior", extStart, extEnd);
+#endif /* GL_KHR_robust_buffer_access_behavior */
+#ifdef GL_KHR_robustness
+ GLEW_KHR_robustness = _glewSearchExtension("GL_KHR_robustness", extStart, extEnd);
+ if (glewExperimental || GLEW_KHR_robustness) GLEW_KHR_robustness = !_glewInit_GL_KHR_robustness(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_KHR_robustness */
+#ifdef GL_KHR_texture_compression_astc_hdr
+ GLEW_KHR_texture_compression_astc_hdr = _glewSearchExtension("GL_KHR_texture_compression_astc_hdr", extStart, extEnd);
+#endif /* GL_KHR_texture_compression_astc_hdr */
#ifdef GL_KHR_texture_compression_astc_ldr
- CONST_CAST(GLEW_KHR_texture_compression_astc_ldr) = _glewSearchExtension("GL_KHR_texture_compression_astc_ldr", extStart, extEnd);
+ GLEW_KHR_texture_compression_astc_ldr = _glewSearchExtension("GL_KHR_texture_compression_astc_ldr", extStart, extEnd);
#endif /* GL_KHR_texture_compression_astc_ldr */
#ifdef GL_KTX_buffer_region
- CONST_CAST(GLEW_KTX_buffer_region) = _glewSearchExtension("GL_KTX_buffer_region", extStart, extEnd);
- if (glewExperimental || GLEW_KTX_buffer_region) CONST_CAST(GLEW_KTX_buffer_region) = !_glewInit_GL_KTX_buffer_region(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_KTX_buffer_region = _glewSearchExtension("GL_KTX_buffer_region", extStart, extEnd);
+ if (glewExperimental || GLEW_KTX_buffer_region) GLEW_KTX_buffer_region = !_glewInit_GL_KTX_buffer_region(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_KTX_buffer_region */
#ifdef GL_MESAX_texture_stack
- CONST_CAST(GLEW_MESAX_texture_stack) = _glewSearchExtension("GL_MESAX_texture_stack", extStart, extEnd);
+ GLEW_MESAX_texture_stack = _glewSearchExtension("GL_MESAX_texture_stack", extStart, extEnd);
#endif /* GL_MESAX_texture_stack */
#ifdef GL_MESA_pack_invert
- CONST_CAST(GLEW_MESA_pack_invert) = _glewSearchExtension("GL_MESA_pack_invert", extStart, extEnd);
+ GLEW_MESA_pack_invert = _glewSearchExtension("GL_MESA_pack_invert", extStart, extEnd);
#endif /* GL_MESA_pack_invert */
#ifdef GL_MESA_resize_buffers
- CONST_CAST(GLEW_MESA_resize_buffers) = _glewSearchExtension("GL_MESA_resize_buffers", extStart, extEnd);
- if (glewExperimental || GLEW_MESA_resize_buffers) CONST_CAST(GLEW_MESA_resize_buffers) = !_glewInit_GL_MESA_resize_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_MESA_resize_buffers = _glewSearchExtension("GL_MESA_resize_buffers", extStart, extEnd);
+ if (glewExperimental || GLEW_MESA_resize_buffers) GLEW_MESA_resize_buffers = !_glewInit_GL_MESA_resize_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_MESA_resize_buffers */
#ifdef GL_MESA_window_pos
- CONST_CAST(GLEW_MESA_window_pos) = _glewSearchExtension("GL_MESA_window_pos", extStart, extEnd);
- if (glewExperimental || GLEW_MESA_window_pos) CONST_CAST(GLEW_MESA_window_pos) = !_glewInit_GL_MESA_window_pos(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_MESA_window_pos = _glewSearchExtension("GL_MESA_window_pos", extStart, extEnd);
+ if (glewExperimental || GLEW_MESA_window_pos) GLEW_MESA_window_pos = !_glewInit_GL_MESA_window_pos(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_MESA_window_pos */
#ifdef GL_MESA_ycbcr_texture
- CONST_CAST(GLEW_MESA_ycbcr_texture) = _glewSearchExtension("GL_MESA_ycbcr_texture", extStart, extEnd);
+ GLEW_MESA_ycbcr_texture = _glewSearchExtension("GL_MESA_ycbcr_texture", extStart, extEnd);
#endif /* GL_MESA_ycbcr_texture */
#ifdef GL_NVX_conditional_render
- CONST_CAST(GLEW_NVX_conditional_render) = _glewSearchExtension("GL_NVX_conditional_render", extStart, extEnd);
- if (glewExperimental || GLEW_NVX_conditional_render) CONST_CAST(GLEW_NVX_conditional_render) = !_glewInit_GL_NVX_conditional_render(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NVX_conditional_render = _glewSearchExtension("GL_NVX_conditional_render", extStart, extEnd);
+ if (glewExperimental || GLEW_NVX_conditional_render) GLEW_NVX_conditional_render = !_glewInit_GL_NVX_conditional_render(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NVX_conditional_render */
#ifdef GL_NVX_gpu_memory_info
- CONST_CAST(GLEW_NVX_gpu_memory_info) = _glewSearchExtension("GL_NVX_gpu_memory_info", extStart, extEnd);
+ GLEW_NVX_gpu_memory_info = _glewSearchExtension("GL_NVX_gpu_memory_info", extStart, extEnd);
#endif /* GL_NVX_gpu_memory_info */
#ifdef GL_NV_bindless_multi_draw_indirect
- CONST_CAST(GLEW_NV_bindless_multi_draw_indirect) = _glewSearchExtension("GL_NV_bindless_multi_draw_indirect", extStart, extEnd);
- if (glewExperimental || GLEW_NV_bindless_multi_draw_indirect) CONST_CAST(GLEW_NV_bindless_multi_draw_indirect) = !_glewInit_GL_NV_bindless_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_bindless_multi_draw_indirect = _glewSearchExtension("GL_NV_bindless_multi_draw_indirect", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_bindless_multi_draw_indirect) GLEW_NV_bindless_multi_draw_indirect = !_glewInit_GL_NV_bindless_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_bindless_multi_draw_indirect */
+#ifdef GL_NV_bindless_multi_draw_indirect_count
+ GLEW_NV_bindless_multi_draw_indirect_count = _glewSearchExtension("GL_NV_bindless_multi_draw_indirect_count", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_bindless_multi_draw_indirect_count) GLEW_NV_bindless_multi_draw_indirect_count = !_glewInit_GL_NV_bindless_multi_draw_indirect_count(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_NV_bindless_multi_draw_indirect_count */
#ifdef GL_NV_bindless_texture
- CONST_CAST(GLEW_NV_bindless_texture) = _glewSearchExtension("GL_NV_bindless_texture", extStart, extEnd);
- if (glewExperimental || GLEW_NV_bindless_texture) CONST_CAST(GLEW_NV_bindless_texture) = !_glewInit_GL_NV_bindless_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_bindless_texture = _glewSearchExtension("GL_NV_bindless_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_bindless_texture) GLEW_NV_bindless_texture = !_glewInit_GL_NV_bindless_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_bindless_texture */
#ifdef GL_NV_blend_equation_advanced
- CONST_CAST(GLEW_NV_blend_equation_advanced) = _glewSearchExtension("GL_NV_blend_equation_advanced", extStart, extEnd);
- if (glewExperimental || GLEW_NV_blend_equation_advanced) CONST_CAST(GLEW_NV_blend_equation_advanced) = !_glewInit_GL_NV_blend_equation_advanced(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_blend_equation_advanced = _glewSearchExtension("GL_NV_blend_equation_advanced", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_blend_equation_advanced) GLEW_NV_blend_equation_advanced = !_glewInit_GL_NV_blend_equation_advanced(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_blend_equation_advanced */
#ifdef GL_NV_blend_equation_advanced_coherent
- CONST_CAST(GLEW_NV_blend_equation_advanced_coherent) = _glewSearchExtension("GL_NV_blend_equation_advanced_coherent", extStart, extEnd);
+ GLEW_NV_blend_equation_advanced_coherent = _glewSearchExtension("GL_NV_blend_equation_advanced_coherent", extStart, extEnd);
#endif /* GL_NV_blend_equation_advanced_coherent */
#ifdef GL_NV_blend_square
- CONST_CAST(GLEW_NV_blend_square) = _glewSearchExtension("GL_NV_blend_square", extStart, extEnd);
+ GLEW_NV_blend_square = _glewSearchExtension("GL_NV_blend_square", extStart, extEnd);
#endif /* GL_NV_blend_square */
#ifdef GL_NV_compute_program5
- CONST_CAST(GLEW_NV_compute_program5) = _glewSearchExtension("GL_NV_compute_program5", extStart, extEnd);
+ GLEW_NV_compute_program5 = _glewSearchExtension("GL_NV_compute_program5", extStart, extEnd);
#endif /* GL_NV_compute_program5 */
#ifdef GL_NV_conditional_render
- CONST_CAST(GLEW_NV_conditional_render) = _glewSearchExtension("GL_NV_conditional_render", extStart, extEnd);
- if (glewExperimental || GLEW_NV_conditional_render) CONST_CAST(GLEW_NV_conditional_render) = !_glewInit_GL_NV_conditional_render(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_conditional_render = _glewSearchExtension("GL_NV_conditional_render", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_conditional_render) GLEW_NV_conditional_render = !_glewInit_GL_NV_conditional_render(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_conditional_render */
+#ifdef GL_NV_conservative_raster
+ GLEW_NV_conservative_raster = _glewSearchExtension("GL_NV_conservative_raster", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_conservative_raster) GLEW_NV_conservative_raster = !_glewInit_GL_NV_conservative_raster(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_NV_conservative_raster */
+#ifdef GL_NV_conservative_raster_dilate
+ GLEW_NV_conservative_raster_dilate = _glewSearchExtension("GL_NV_conservative_raster_dilate", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_conservative_raster_dilate) GLEW_NV_conservative_raster_dilate = !_glewInit_GL_NV_conservative_raster_dilate(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_NV_conservative_raster_dilate */
#ifdef GL_NV_copy_depth_to_color
- CONST_CAST(GLEW_NV_copy_depth_to_color) = _glewSearchExtension("GL_NV_copy_depth_to_color", extStart, extEnd);
+ GLEW_NV_copy_depth_to_color = _glewSearchExtension("GL_NV_copy_depth_to_color", extStart, extEnd);
#endif /* GL_NV_copy_depth_to_color */
#ifdef GL_NV_copy_image
- CONST_CAST(GLEW_NV_copy_image) = _glewSearchExtension("GL_NV_copy_image", extStart, extEnd);
- if (glewExperimental || GLEW_NV_copy_image) CONST_CAST(GLEW_NV_copy_image) = !_glewInit_GL_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_copy_image = _glewSearchExtension("GL_NV_copy_image", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_copy_image) GLEW_NV_copy_image = !_glewInit_GL_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_copy_image */
#ifdef GL_NV_deep_texture3D
- CONST_CAST(GLEW_NV_deep_texture3D) = _glewSearchExtension("GL_NV_deep_texture3D", extStart, extEnd);
+ GLEW_NV_deep_texture3D = _glewSearchExtension("GL_NV_deep_texture3D", extStart, extEnd);
#endif /* GL_NV_deep_texture3D */
#ifdef GL_NV_depth_buffer_float
- CONST_CAST(GLEW_NV_depth_buffer_float) = _glewSearchExtension("GL_NV_depth_buffer_float", extStart, extEnd);
- if (glewExperimental || GLEW_NV_depth_buffer_float) CONST_CAST(GLEW_NV_depth_buffer_float) = !_glewInit_GL_NV_depth_buffer_float(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_depth_buffer_float = _glewSearchExtension("GL_NV_depth_buffer_float", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_depth_buffer_float) GLEW_NV_depth_buffer_float = !_glewInit_GL_NV_depth_buffer_float(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_depth_buffer_float */
#ifdef GL_NV_depth_clamp
- CONST_CAST(GLEW_NV_depth_clamp) = _glewSearchExtension("GL_NV_depth_clamp", extStart, extEnd);
+ GLEW_NV_depth_clamp = _glewSearchExtension("GL_NV_depth_clamp", extStart, extEnd);
#endif /* GL_NV_depth_clamp */
#ifdef GL_NV_depth_range_unclamped
- CONST_CAST(GLEW_NV_depth_range_unclamped) = _glewSearchExtension("GL_NV_depth_range_unclamped", extStart, extEnd);
+ GLEW_NV_depth_range_unclamped = _glewSearchExtension("GL_NV_depth_range_unclamped", extStart, extEnd);
#endif /* GL_NV_depth_range_unclamped */
#ifdef GL_NV_draw_texture
- CONST_CAST(GLEW_NV_draw_texture) = _glewSearchExtension("GL_NV_draw_texture", extStart, extEnd);
- if (glewExperimental || GLEW_NV_draw_texture) CONST_CAST(GLEW_NV_draw_texture) = !_glewInit_GL_NV_draw_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_draw_texture = _glewSearchExtension("GL_NV_draw_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_draw_texture) GLEW_NV_draw_texture = !_glewInit_GL_NV_draw_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_draw_texture */
#ifdef GL_NV_evaluators
- CONST_CAST(GLEW_NV_evaluators) = _glewSearchExtension("GL_NV_evaluators", extStart, extEnd);
- if (glewExperimental || GLEW_NV_evaluators) CONST_CAST(GLEW_NV_evaluators) = !_glewInit_GL_NV_evaluators(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_evaluators = _glewSearchExtension("GL_NV_evaluators", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_evaluators) GLEW_NV_evaluators = !_glewInit_GL_NV_evaluators(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_evaluators */
#ifdef GL_NV_explicit_multisample
- CONST_CAST(GLEW_NV_explicit_multisample) = _glewSearchExtension("GL_NV_explicit_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_NV_explicit_multisample) CONST_CAST(GLEW_NV_explicit_multisample) = !_glewInit_GL_NV_explicit_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_explicit_multisample = _glewSearchExtension("GL_NV_explicit_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_explicit_multisample) GLEW_NV_explicit_multisample = !_glewInit_GL_NV_explicit_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_explicit_multisample */
#ifdef GL_NV_fence
- CONST_CAST(GLEW_NV_fence) = _glewSearchExtension("GL_NV_fence", extStart, extEnd);
- if (glewExperimental || GLEW_NV_fence) CONST_CAST(GLEW_NV_fence) = !_glewInit_GL_NV_fence(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_fence = _glewSearchExtension("GL_NV_fence", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_fence) GLEW_NV_fence = !_glewInit_GL_NV_fence(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_fence */
+#ifdef GL_NV_fill_rectangle
+ GLEW_NV_fill_rectangle = _glewSearchExtension("GL_NV_fill_rectangle", extStart, extEnd);
+#endif /* GL_NV_fill_rectangle */
#ifdef GL_NV_float_buffer
- CONST_CAST(GLEW_NV_float_buffer) = _glewSearchExtension("GL_NV_float_buffer", extStart, extEnd);
+ GLEW_NV_float_buffer = _glewSearchExtension("GL_NV_float_buffer", extStart, extEnd);
#endif /* GL_NV_float_buffer */
#ifdef GL_NV_fog_distance
- CONST_CAST(GLEW_NV_fog_distance) = _glewSearchExtension("GL_NV_fog_distance", extStart, extEnd);
+ GLEW_NV_fog_distance = _glewSearchExtension("GL_NV_fog_distance", extStart, extEnd);
#endif /* GL_NV_fog_distance */
+#ifdef GL_NV_fragment_coverage_to_color
+ GLEW_NV_fragment_coverage_to_color = _glewSearchExtension("GL_NV_fragment_coverage_to_color", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_fragment_coverage_to_color) GLEW_NV_fragment_coverage_to_color = !_glewInit_GL_NV_fragment_coverage_to_color(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_NV_fragment_coverage_to_color */
#ifdef GL_NV_fragment_program
- CONST_CAST(GLEW_NV_fragment_program) = _glewSearchExtension("GL_NV_fragment_program", extStart, extEnd);
- if (glewExperimental || GLEW_NV_fragment_program) CONST_CAST(GLEW_NV_fragment_program) = !_glewInit_GL_NV_fragment_program(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_fragment_program = _glewSearchExtension("GL_NV_fragment_program", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_fragment_program) GLEW_NV_fragment_program = !_glewInit_GL_NV_fragment_program(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_fragment_program */
#ifdef GL_NV_fragment_program2
- CONST_CAST(GLEW_NV_fragment_program2) = _glewSearchExtension("GL_NV_fragment_program2", extStart, extEnd);
+ GLEW_NV_fragment_program2 = _glewSearchExtension("GL_NV_fragment_program2", extStart, extEnd);
#endif /* GL_NV_fragment_program2 */
#ifdef GL_NV_fragment_program4
- CONST_CAST(GLEW_NV_fragment_program4) = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
+ GLEW_NV_fragment_program4 = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
#endif /* GL_NV_fragment_program4 */
#ifdef GL_NV_fragment_program_option
- CONST_CAST(GLEW_NV_fragment_program_option) = _glewSearchExtension("GL_NV_fragment_program_option", extStart, extEnd);
+ GLEW_NV_fragment_program_option = _glewSearchExtension("GL_NV_fragment_program_option", extStart, extEnd);
#endif /* GL_NV_fragment_program_option */
+#ifdef GL_NV_fragment_shader_interlock
+ GLEW_NV_fragment_shader_interlock = _glewSearchExtension("GL_NV_fragment_shader_interlock", extStart, extEnd);
+#endif /* GL_NV_fragment_shader_interlock */
+#ifdef GL_NV_framebuffer_mixed_samples
+ GLEW_NV_framebuffer_mixed_samples = _glewSearchExtension("GL_NV_framebuffer_mixed_samples", extStart, extEnd);
+#endif /* GL_NV_framebuffer_mixed_samples */
#ifdef GL_NV_framebuffer_multisample_coverage
- CONST_CAST(GLEW_NV_framebuffer_multisample_coverage) = _glewSearchExtension("GL_NV_framebuffer_multisample_coverage", extStart, extEnd);
- if (glewExperimental || GLEW_NV_framebuffer_multisample_coverage) CONST_CAST(GLEW_NV_framebuffer_multisample_coverage) = !_glewInit_GL_NV_framebuffer_multisample_coverage(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_framebuffer_multisample_coverage = _glewSearchExtension("GL_NV_framebuffer_multisample_coverage", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_framebuffer_multisample_coverage) GLEW_NV_framebuffer_multisample_coverage = !_glewInit_GL_NV_framebuffer_multisample_coverage(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_framebuffer_multisample_coverage */
#ifdef GL_NV_geometry_program4
- CONST_CAST(GLEW_NV_geometry_program4) = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
- if (glewExperimental || GLEW_NV_geometry_program4) CONST_CAST(GLEW_NV_geometry_program4) = !_glewInit_GL_NV_geometry_program4(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_geometry_program4 = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_geometry_program4) GLEW_NV_geometry_program4 = !_glewInit_GL_NV_geometry_program4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_geometry_program4 */
#ifdef GL_NV_geometry_shader4
- CONST_CAST(GLEW_NV_geometry_shader4) = _glewSearchExtension("GL_NV_geometry_shader4", extStart, extEnd);
+ GLEW_NV_geometry_shader4 = _glewSearchExtension("GL_NV_geometry_shader4", extStart, extEnd);
#endif /* GL_NV_geometry_shader4 */
+#ifdef GL_NV_geometry_shader_passthrough
+ GLEW_NV_geometry_shader_passthrough = _glewSearchExtension("GL_NV_geometry_shader_passthrough", extStart, extEnd);
+#endif /* GL_NV_geometry_shader_passthrough */
#ifdef GL_NV_gpu_program4
- CONST_CAST(GLEW_NV_gpu_program4) = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
- if (glewExperimental || GLEW_NV_gpu_program4) CONST_CAST(GLEW_NV_gpu_program4) = !_glewInit_GL_NV_gpu_program4(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_gpu_program4 = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_gpu_program4) GLEW_NV_gpu_program4 = !_glewInit_GL_NV_gpu_program4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_gpu_program4 */
#ifdef GL_NV_gpu_program5
- CONST_CAST(GLEW_NV_gpu_program5) = _glewSearchExtension("GL_NV_gpu_program5", extStart, extEnd);
+ GLEW_NV_gpu_program5 = _glewSearchExtension("GL_NV_gpu_program5", extStart, extEnd);
#endif /* GL_NV_gpu_program5 */
#ifdef GL_NV_gpu_program5_mem_extended
- CONST_CAST(GLEW_NV_gpu_program5_mem_extended) = _glewSearchExtension("GL_NV_gpu_program5_mem_extended", extStart, extEnd);
+ GLEW_NV_gpu_program5_mem_extended = _glewSearchExtension("GL_NV_gpu_program5_mem_extended", extStart, extEnd);
#endif /* GL_NV_gpu_program5_mem_extended */
#ifdef GL_NV_gpu_program_fp64
- CONST_CAST(GLEW_NV_gpu_program_fp64) = _glewSearchExtension("GL_NV_gpu_program_fp64", extStart, extEnd);
+ GLEW_NV_gpu_program_fp64 = _glewSearchExtension("GL_NV_gpu_program_fp64", extStart, extEnd);
#endif /* GL_NV_gpu_program_fp64 */
#ifdef GL_NV_gpu_shader5
- CONST_CAST(GLEW_NV_gpu_shader5) = _glewSearchExtension("GL_NV_gpu_shader5", extStart, extEnd);
- if (glewExperimental || GLEW_NV_gpu_shader5) CONST_CAST(GLEW_NV_gpu_shader5) = !_glewInit_GL_NV_gpu_shader5(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_gpu_shader5 = _glewSearchExtension("GL_NV_gpu_shader5", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_gpu_shader5) GLEW_NV_gpu_shader5 = !_glewInit_GL_NV_gpu_shader5(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_gpu_shader5 */
#ifdef GL_NV_half_float
- CONST_CAST(GLEW_NV_half_float) = _glewSearchExtension("GL_NV_half_float", extStart, extEnd);
- if (glewExperimental || GLEW_NV_half_float) CONST_CAST(GLEW_NV_half_float) = !_glewInit_GL_NV_half_float(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_half_float = _glewSearchExtension("GL_NV_half_float", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_half_float) GLEW_NV_half_float = !_glewInit_GL_NV_half_float(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_half_float */
+#ifdef GL_NV_internalformat_sample_query
+ GLEW_NV_internalformat_sample_query = _glewSearchExtension("GL_NV_internalformat_sample_query", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_internalformat_sample_query) GLEW_NV_internalformat_sample_query = !_glewInit_GL_NV_internalformat_sample_query(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_NV_internalformat_sample_query */
#ifdef GL_NV_light_max_exponent
- CONST_CAST(GLEW_NV_light_max_exponent) = _glewSearchExtension("GL_NV_light_max_exponent", extStart, extEnd);
+ GLEW_NV_light_max_exponent = _glewSearchExtension("GL_NV_light_max_exponent", extStart, extEnd);
#endif /* GL_NV_light_max_exponent */
#ifdef GL_NV_multisample_coverage
- CONST_CAST(GLEW_NV_multisample_coverage) = _glewSearchExtension("GL_NV_multisample_coverage", extStart, extEnd);
+ GLEW_NV_multisample_coverage = _glewSearchExtension("GL_NV_multisample_coverage", extStart, extEnd);
#endif /* GL_NV_multisample_coverage */
#ifdef GL_NV_multisample_filter_hint
- CONST_CAST(GLEW_NV_multisample_filter_hint) = _glewSearchExtension("GL_NV_multisample_filter_hint", extStart, extEnd);
+ GLEW_NV_multisample_filter_hint = _glewSearchExtension("GL_NV_multisample_filter_hint", extStart, extEnd);
#endif /* GL_NV_multisample_filter_hint */
#ifdef GL_NV_occlusion_query
- CONST_CAST(GLEW_NV_occlusion_query) = _glewSearchExtension("GL_NV_occlusion_query", extStart, extEnd);
- if (glewExperimental || GLEW_NV_occlusion_query) CONST_CAST(GLEW_NV_occlusion_query) = !_glewInit_GL_NV_occlusion_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_occlusion_query = _glewSearchExtension("GL_NV_occlusion_query", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_occlusion_query) GLEW_NV_occlusion_query = !_glewInit_GL_NV_occlusion_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_occlusion_query */
#ifdef GL_NV_packed_depth_stencil
- CONST_CAST(GLEW_NV_packed_depth_stencil) = _glewSearchExtension("GL_NV_packed_depth_stencil", extStart, extEnd);
+ GLEW_NV_packed_depth_stencil = _glewSearchExtension("GL_NV_packed_depth_stencil", extStart, extEnd);
#endif /* GL_NV_packed_depth_stencil */
#ifdef GL_NV_parameter_buffer_object
- CONST_CAST(GLEW_NV_parameter_buffer_object) = _glewSearchExtension("GL_NV_parameter_buffer_object", extStart, extEnd);
- if (glewExperimental || GLEW_NV_parameter_buffer_object) CONST_CAST(GLEW_NV_parameter_buffer_object) = !_glewInit_GL_NV_parameter_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_parameter_buffer_object = _glewSearchExtension("GL_NV_parameter_buffer_object", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_parameter_buffer_object) GLEW_NV_parameter_buffer_object = !_glewInit_GL_NV_parameter_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_parameter_buffer_object */
#ifdef GL_NV_parameter_buffer_object2
- CONST_CAST(GLEW_NV_parameter_buffer_object2) = _glewSearchExtension("GL_NV_parameter_buffer_object2", extStart, extEnd);
+ GLEW_NV_parameter_buffer_object2 = _glewSearchExtension("GL_NV_parameter_buffer_object2", extStart, extEnd);
#endif /* GL_NV_parameter_buffer_object2 */
#ifdef GL_NV_path_rendering
- CONST_CAST(GLEW_NV_path_rendering) = _glewSearchExtension("GL_NV_path_rendering", extStart, extEnd);
- if (glewExperimental || GLEW_NV_path_rendering) CONST_CAST(GLEW_NV_path_rendering) = !_glewInit_GL_NV_path_rendering(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_path_rendering = _glewSearchExtension("GL_NV_path_rendering", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_path_rendering) GLEW_NV_path_rendering = !_glewInit_GL_NV_path_rendering(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_path_rendering */
+#ifdef GL_NV_path_rendering_shared_edge
+ GLEW_NV_path_rendering_shared_edge = _glewSearchExtension("GL_NV_path_rendering_shared_edge", extStart, extEnd);
+#endif /* GL_NV_path_rendering_shared_edge */
#ifdef GL_NV_pixel_data_range
- CONST_CAST(GLEW_NV_pixel_data_range) = _glewSearchExtension("GL_NV_pixel_data_range", extStart, extEnd);
- if (glewExperimental || GLEW_NV_pixel_data_range) CONST_CAST(GLEW_NV_pixel_data_range) = !_glewInit_GL_NV_pixel_data_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_pixel_data_range = _glewSearchExtension("GL_NV_pixel_data_range", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_pixel_data_range) GLEW_NV_pixel_data_range = !_glewInit_GL_NV_pixel_data_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_pixel_data_range */
#ifdef GL_NV_point_sprite
- CONST_CAST(GLEW_NV_point_sprite) = _glewSearchExtension("GL_NV_point_sprite", extStart, extEnd);
- if (glewExperimental || GLEW_NV_point_sprite) CONST_CAST(GLEW_NV_point_sprite) = !_glewInit_GL_NV_point_sprite(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_point_sprite = _glewSearchExtension("GL_NV_point_sprite", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_point_sprite) GLEW_NV_point_sprite = !_glewInit_GL_NV_point_sprite(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_point_sprite */
#ifdef GL_NV_present_video
- CONST_CAST(GLEW_NV_present_video) = _glewSearchExtension("GL_NV_present_video", extStart, extEnd);
- if (glewExperimental || GLEW_NV_present_video) CONST_CAST(GLEW_NV_present_video) = !_glewInit_GL_NV_present_video(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_present_video = _glewSearchExtension("GL_NV_present_video", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_present_video) GLEW_NV_present_video = !_glewInit_GL_NV_present_video(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_present_video */
#ifdef GL_NV_primitive_restart
- CONST_CAST(GLEW_NV_primitive_restart) = _glewSearchExtension("GL_NV_primitive_restart", extStart, extEnd);
- if (glewExperimental || GLEW_NV_primitive_restart) CONST_CAST(GLEW_NV_primitive_restart) = !_glewInit_GL_NV_primitive_restart(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_primitive_restart = _glewSearchExtension("GL_NV_primitive_restart", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_primitive_restart) GLEW_NV_primitive_restart = !_glewInit_GL_NV_primitive_restart(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_primitive_restart */
#ifdef GL_NV_register_combiners
- CONST_CAST(GLEW_NV_register_combiners) = _glewSearchExtension("GL_NV_register_combiners", extStart, extEnd);
- if (glewExperimental || GLEW_NV_register_combiners) CONST_CAST(GLEW_NV_register_combiners) = !_glewInit_GL_NV_register_combiners(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_register_combiners = _glewSearchExtension("GL_NV_register_combiners", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_register_combiners) GLEW_NV_register_combiners = !_glewInit_GL_NV_register_combiners(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_register_combiners */
#ifdef GL_NV_register_combiners2
- CONST_CAST(GLEW_NV_register_combiners2) = _glewSearchExtension("GL_NV_register_combiners2", extStart, extEnd);
- if (glewExperimental || GLEW_NV_register_combiners2) CONST_CAST(GLEW_NV_register_combiners2) = !_glewInit_GL_NV_register_combiners2(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_register_combiners2 = _glewSearchExtension("GL_NV_register_combiners2", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_register_combiners2) GLEW_NV_register_combiners2 = !_glewInit_GL_NV_register_combiners2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_register_combiners2 */
+#ifdef GL_NV_sample_locations
+ GLEW_NV_sample_locations = _glewSearchExtension("GL_NV_sample_locations", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_sample_locations) GLEW_NV_sample_locations = !_glewInit_GL_NV_sample_locations(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_NV_sample_locations */
+#ifdef GL_NV_sample_mask_override_coverage
+ GLEW_NV_sample_mask_override_coverage = _glewSearchExtension("GL_NV_sample_mask_override_coverage", extStart, extEnd);
+#endif /* GL_NV_sample_mask_override_coverage */
#ifdef GL_NV_shader_atomic_counters
- CONST_CAST(GLEW_NV_shader_atomic_counters) = _glewSearchExtension("GL_NV_shader_atomic_counters", extStart, extEnd);
+ GLEW_NV_shader_atomic_counters = _glewSearchExtension("GL_NV_shader_atomic_counters", extStart, extEnd);
#endif /* GL_NV_shader_atomic_counters */
#ifdef GL_NV_shader_atomic_float
- CONST_CAST(GLEW_NV_shader_atomic_float) = _glewSearchExtension("GL_NV_shader_atomic_float", extStart, extEnd);
+ GLEW_NV_shader_atomic_float = _glewSearchExtension("GL_NV_shader_atomic_float", extStart, extEnd);
#endif /* GL_NV_shader_atomic_float */
+#ifdef GL_NV_shader_atomic_fp16_vector
+ GLEW_NV_shader_atomic_fp16_vector = _glewSearchExtension("GL_NV_shader_atomic_fp16_vector", extStart, extEnd);
+#endif /* GL_NV_shader_atomic_fp16_vector */
+#ifdef GL_NV_shader_atomic_int64
+ GLEW_NV_shader_atomic_int64 = _glewSearchExtension("GL_NV_shader_atomic_int64", extStart, extEnd);
+#endif /* GL_NV_shader_atomic_int64 */
#ifdef GL_NV_shader_buffer_load
- CONST_CAST(GLEW_NV_shader_buffer_load) = _glewSearchExtension("GL_NV_shader_buffer_load", extStart, extEnd);
- if (glewExperimental || GLEW_NV_shader_buffer_load) CONST_CAST(GLEW_NV_shader_buffer_load) = !_glewInit_GL_NV_shader_buffer_load(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_shader_buffer_load = _glewSearchExtension("GL_NV_shader_buffer_load", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_shader_buffer_load) GLEW_NV_shader_buffer_load = !_glewInit_GL_NV_shader_buffer_load(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_shader_buffer_load */
#ifdef GL_NV_shader_storage_buffer_object
- CONST_CAST(GLEW_NV_shader_storage_buffer_object) = _glewSearchExtension("GL_NV_shader_storage_buffer_object", extStart, extEnd);
+ GLEW_NV_shader_storage_buffer_object = _glewSearchExtension("GL_NV_shader_storage_buffer_object", extStart, extEnd);
#endif /* GL_NV_shader_storage_buffer_object */
+#ifdef GL_NV_shader_thread_group
+ GLEW_NV_shader_thread_group = _glewSearchExtension("GL_NV_shader_thread_group", extStart, extEnd);
+#endif /* GL_NV_shader_thread_group */
+#ifdef GL_NV_shader_thread_shuffle
+ GLEW_NV_shader_thread_shuffle = _glewSearchExtension("GL_NV_shader_thread_shuffle", extStart, extEnd);
+#endif /* GL_NV_shader_thread_shuffle */
#ifdef GL_NV_tessellation_program5
- CONST_CAST(GLEW_NV_tessellation_program5) = _glewSearchExtension("GL_NV_gpu_program5", extStart, extEnd);
+ GLEW_NV_tessellation_program5 = _glewSearchExtension("GL_NV_gpu_program5", extStart, extEnd);
#endif /* GL_NV_tessellation_program5 */
#ifdef GL_NV_texgen_emboss
- CONST_CAST(GLEW_NV_texgen_emboss) = _glewSearchExtension("GL_NV_texgen_emboss", extStart, extEnd);
+ GLEW_NV_texgen_emboss = _glewSearchExtension("GL_NV_texgen_emboss", extStart, extEnd);
#endif /* GL_NV_texgen_emboss */
#ifdef GL_NV_texgen_reflection
- CONST_CAST(GLEW_NV_texgen_reflection) = _glewSearchExtension("GL_NV_texgen_reflection", extStart, extEnd);
+ GLEW_NV_texgen_reflection = _glewSearchExtension("GL_NV_texgen_reflection", extStart, extEnd);
#endif /* GL_NV_texgen_reflection */
#ifdef GL_NV_texture_barrier
- CONST_CAST(GLEW_NV_texture_barrier) = _glewSearchExtension("GL_NV_texture_barrier", extStart, extEnd);
- if (glewExperimental || GLEW_NV_texture_barrier) CONST_CAST(GLEW_NV_texture_barrier) = !_glewInit_GL_NV_texture_barrier(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_texture_barrier = _glewSearchExtension("GL_NV_texture_barrier", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_texture_barrier) GLEW_NV_texture_barrier = !_glewInit_GL_NV_texture_barrier(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_texture_barrier */
#ifdef GL_NV_texture_compression_vtc
- CONST_CAST(GLEW_NV_texture_compression_vtc) = _glewSearchExtension("GL_NV_texture_compression_vtc", extStart, extEnd);
+ GLEW_NV_texture_compression_vtc = _glewSearchExtension("GL_NV_texture_compression_vtc", extStart, extEnd);
#endif /* GL_NV_texture_compression_vtc */
#ifdef GL_NV_texture_env_combine4
- CONST_CAST(GLEW_NV_texture_env_combine4) = _glewSearchExtension("GL_NV_texture_env_combine4", extStart, extEnd);
+ GLEW_NV_texture_env_combine4 = _glewSearchExtension("GL_NV_texture_env_combine4", extStart, extEnd);
#endif /* GL_NV_texture_env_combine4 */
#ifdef GL_NV_texture_expand_normal
- CONST_CAST(GLEW_NV_texture_expand_normal) = _glewSearchExtension("GL_NV_texture_expand_normal", extStart, extEnd);
+ GLEW_NV_texture_expand_normal = _glewSearchExtension("GL_NV_texture_expand_normal", extStart, extEnd);
#endif /* GL_NV_texture_expand_normal */
#ifdef GL_NV_texture_multisample
- CONST_CAST(GLEW_NV_texture_multisample) = _glewSearchExtension("GL_NV_texture_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_NV_texture_multisample) CONST_CAST(GLEW_NV_texture_multisample) = !_glewInit_GL_NV_texture_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_texture_multisample = _glewSearchExtension("GL_NV_texture_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_texture_multisample) GLEW_NV_texture_multisample = !_glewInit_GL_NV_texture_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_texture_multisample */
#ifdef GL_NV_texture_rectangle
- CONST_CAST(GLEW_NV_texture_rectangle) = _glewSearchExtension("GL_NV_texture_rectangle", extStart, extEnd);
+ GLEW_NV_texture_rectangle = _glewSearchExtension("GL_NV_texture_rectangle", extStart, extEnd);
#endif /* GL_NV_texture_rectangle */
#ifdef GL_NV_texture_shader
- CONST_CAST(GLEW_NV_texture_shader) = _glewSearchExtension("GL_NV_texture_shader", extStart, extEnd);
+ GLEW_NV_texture_shader = _glewSearchExtension("GL_NV_texture_shader", extStart, extEnd);
#endif /* GL_NV_texture_shader */
#ifdef GL_NV_texture_shader2
- CONST_CAST(GLEW_NV_texture_shader2) = _glewSearchExtension("GL_NV_texture_shader2", extStart, extEnd);
+ GLEW_NV_texture_shader2 = _glewSearchExtension("GL_NV_texture_shader2", extStart, extEnd);
#endif /* GL_NV_texture_shader2 */
#ifdef GL_NV_texture_shader3
- CONST_CAST(GLEW_NV_texture_shader3) = _glewSearchExtension("GL_NV_texture_shader3", extStart, extEnd);
+ GLEW_NV_texture_shader3 = _glewSearchExtension("GL_NV_texture_shader3", extStart, extEnd);
#endif /* GL_NV_texture_shader3 */
#ifdef GL_NV_transform_feedback
- CONST_CAST(GLEW_NV_transform_feedback) = _glewSearchExtension("GL_NV_transform_feedback", extStart, extEnd);
- if (glewExperimental || GLEW_NV_transform_feedback) CONST_CAST(GLEW_NV_transform_feedback) = !_glewInit_GL_NV_transform_feedback(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_transform_feedback = _glewSearchExtension("GL_NV_transform_feedback", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_transform_feedback) GLEW_NV_transform_feedback = !_glewInit_GL_NV_transform_feedback(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_transform_feedback */
#ifdef GL_NV_transform_feedback2
- CONST_CAST(GLEW_NV_transform_feedback2) = _glewSearchExtension("GL_NV_transform_feedback2", extStart, extEnd);
- if (glewExperimental || GLEW_NV_transform_feedback2) CONST_CAST(GLEW_NV_transform_feedback2) = !_glewInit_GL_NV_transform_feedback2(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_transform_feedback2 = _glewSearchExtension("GL_NV_transform_feedback2", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_transform_feedback2) GLEW_NV_transform_feedback2 = !_glewInit_GL_NV_transform_feedback2(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_transform_feedback2 */
+#ifdef GL_NV_uniform_buffer_unified_memory
+ GLEW_NV_uniform_buffer_unified_memory = _glewSearchExtension("GL_NV_uniform_buffer_unified_memory", extStart, extEnd);
+#endif /* GL_NV_uniform_buffer_unified_memory */
#ifdef GL_NV_vdpau_interop
- CONST_CAST(GLEW_NV_vdpau_interop) = _glewSearchExtension("GL_NV_vdpau_interop", extStart, extEnd);
- if (glewExperimental || GLEW_NV_vdpau_interop) CONST_CAST(GLEW_NV_vdpau_interop) = !_glewInit_GL_NV_vdpau_interop(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_vdpau_interop = _glewSearchExtension("GL_NV_vdpau_interop", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_vdpau_interop) GLEW_NV_vdpau_interop = !_glewInit_GL_NV_vdpau_interop(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_vdpau_interop */
#ifdef GL_NV_vertex_array_range
- CONST_CAST(GLEW_NV_vertex_array_range) = _glewSearchExtension("GL_NV_vertex_array_range", extStart, extEnd);
- if (glewExperimental || GLEW_NV_vertex_array_range) CONST_CAST(GLEW_NV_vertex_array_range) = !_glewInit_GL_NV_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_vertex_array_range = _glewSearchExtension("GL_NV_vertex_array_range", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_vertex_array_range) GLEW_NV_vertex_array_range = !_glewInit_GL_NV_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_vertex_array_range */
#ifdef GL_NV_vertex_array_range2
- CONST_CAST(GLEW_NV_vertex_array_range2) = _glewSearchExtension("GL_NV_vertex_array_range2", extStart, extEnd);
+ GLEW_NV_vertex_array_range2 = _glewSearchExtension("GL_NV_vertex_array_range2", extStart, extEnd);
#endif /* GL_NV_vertex_array_range2 */
#ifdef GL_NV_vertex_attrib_integer_64bit
- CONST_CAST(GLEW_NV_vertex_attrib_integer_64bit) = _glewSearchExtension("GL_NV_vertex_attrib_integer_64bit", extStart, extEnd);
- if (glewExperimental || GLEW_NV_vertex_attrib_integer_64bit) CONST_CAST(GLEW_NV_vertex_attrib_integer_64bit) = !_glewInit_GL_NV_vertex_attrib_integer_64bit(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_vertex_attrib_integer_64bit = _glewSearchExtension("GL_NV_vertex_attrib_integer_64bit", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_vertex_attrib_integer_64bit) GLEW_NV_vertex_attrib_integer_64bit = !_glewInit_GL_NV_vertex_attrib_integer_64bit(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_vertex_attrib_integer_64bit */
#ifdef GL_NV_vertex_buffer_unified_memory
- CONST_CAST(GLEW_NV_vertex_buffer_unified_memory) = _glewSearchExtension("GL_NV_vertex_buffer_unified_memory", extStart, extEnd);
- if (glewExperimental || GLEW_NV_vertex_buffer_unified_memory) CONST_CAST(GLEW_NV_vertex_buffer_unified_memory) = !_glewInit_GL_NV_vertex_buffer_unified_memory(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_vertex_buffer_unified_memory = _glewSearchExtension("GL_NV_vertex_buffer_unified_memory", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_vertex_buffer_unified_memory) GLEW_NV_vertex_buffer_unified_memory = !_glewInit_GL_NV_vertex_buffer_unified_memory(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_vertex_buffer_unified_memory */
#ifdef GL_NV_vertex_program
- CONST_CAST(GLEW_NV_vertex_program) = _glewSearchExtension("GL_NV_vertex_program", extStart, extEnd);
- if (glewExperimental || GLEW_NV_vertex_program) CONST_CAST(GLEW_NV_vertex_program) = !_glewInit_GL_NV_vertex_program(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_vertex_program = _glewSearchExtension("GL_NV_vertex_program", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_vertex_program) GLEW_NV_vertex_program = !_glewInit_GL_NV_vertex_program(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_vertex_program */
#ifdef GL_NV_vertex_program1_1
- CONST_CAST(GLEW_NV_vertex_program1_1) = _glewSearchExtension("GL_NV_vertex_program1_1", extStart, extEnd);
+ GLEW_NV_vertex_program1_1 = _glewSearchExtension("GL_NV_vertex_program1_1", extStart, extEnd);
#endif /* GL_NV_vertex_program1_1 */
#ifdef GL_NV_vertex_program2
- CONST_CAST(GLEW_NV_vertex_program2) = _glewSearchExtension("GL_NV_vertex_program2", extStart, extEnd);
+ GLEW_NV_vertex_program2 = _glewSearchExtension("GL_NV_vertex_program2", extStart, extEnd);
#endif /* GL_NV_vertex_program2 */
#ifdef GL_NV_vertex_program2_option
- CONST_CAST(GLEW_NV_vertex_program2_option) = _glewSearchExtension("GL_NV_vertex_program2_option", extStart, extEnd);
+ GLEW_NV_vertex_program2_option = _glewSearchExtension("GL_NV_vertex_program2_option", extStart, extEnd);
#endif /* GL_NV_vertex_program2_option */
#ifdef GL_NV_vertex_program3
- CONST_CAST(GLEW_NV_vertex_program3) = _glewSearchExtension("GL_NV_vertex_program3", extStart, extEnd);
+ GLEW_NV_vertex_program3 = _glewSearchExtension("GL_NV_vertex_program3", extStart, extEnd);
#endif /* GL_NV_vertex_program3 */
#ifdef GL_NV_vertex_program4
- CONST_CAST(GLEW_NV_vertex_program4) = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
+ GLEW_NV_vertex_program4 = _glewSearchExtension("GL_NV_gpu_program4", extStart, extEnd);
#endif /* GL_NV_vertex_program4 */
#ifdef GL_NV_video_capture
- CONST_CAST(GLEW_NV_video_capture) = _glewSearchExtension("GL_NV_video_capture", extStart, extEnd);
- if (glewExperimental || GLEW_NV_video_capture) CONST_CAST(GLEW_NV_video_capture) = !_glewInit_GL_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_NV_video_capture = _glewSearchExtension("GL_NV_video_capture", extStart, extEnd);
+ if (glewExperimental || GLEW_NV_video_capture) GLEW_NV_video_capture = !_glewInit_GL_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_NV_video_capture */
+#ifdef GL_NV_viewport_array2
+ GLEW_NV_viewport_array2 = _glewSearchExtension("GL_NV_viewport_array2", extStart, extEnd);
+#endif /* GL_NV_viewport_array2 */
#ifdef GL_OES_byte_coordinates
- CONST_CAST(GLEW_OES_byte_coordinates) = _glewSearchExtension("GL_OES_byte_coordinates", extStart, extEnd);
+ GLEW_OES_byte_coordinates = _glewSearchExtension("GL_OES_byte_coordinates", extStart, extEnd);
#endif /* GL_OES_byte_coordinates */
#ifdef GL_OES_compressed_paletted_texture
- CONST_CAST(GLEW_OES_compressed_paletted_texture) = _glewSearchExtension("GL_OES_compressed_paletted_texture", extStart, extEnd);
+ GLEW_OES_compressed_paletted_texture = _glewSearchExtension("GL_OES_compressed_paletted_texture", extStart, extEnd);
#endif /* GL_OES_compressed_paletted_texture */
#ifdef GL_OES_read_format
- CONST_CAST(GLEW_OES_read_format) = _glewSearchExtension("GL_OES_read_format", extStart, extEnd);
+ GLEW_OES_read_format = _glewSearchExtension("GL_OES_read_format", extStart, extEnd);
#endif /* GL_OES_read_format */
#ifdef GL_OES_single_precision
- CONST_CAST(GLEW_OES_single_precision) = _glewSearchExtension("GL_OES_single_precision", extStart, extEnd);
- if (glewExperimental || GLEW_OES_single_precision) CONST_CAST(GLEW_OES_single_precision) = !_glewInit_GL_OES_single_precision(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_OES_single_precision = _glewSearchExtension("GL_OES_single_precision", extStart, extEnd);
+ if (glewExperimental || GLEW_OES_single_precision) GLEW_OES_single_precision = !_glewInit_GL_OES_single_precision(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_OES_single_precision */
#ifdef GL_OML_interlace
- CONST_CAST(GLEW_OML_interlace) = _glewSearchExtension("GL_OML_interlace", extStart, extEnd);
+ GLEW_OML_interlace = _glewSearchExtension("GL_OML_interlace", extStart, extEnd);
#endif /* GL_OML_interlace */
#ifdef GL_OML_resample
- CONST_CAST(GLEW_OML_resample) = _glewSearchExtension("GL_OML_resample", extStart, extEnd);
+ GLEW_OML_resample = _glewSearchExtension("GL_OML_resample", extStart, extEnd);
#endif /* GL_OML_resample */
#ifdef GL_OML_subsample
- CONST_CAST(GLEW_OML_subsample) = _glewSearchExtension("GL_OML_subsample", extStart, extEnd);
+ GLEW_OML_subsample = _glewSearchExtension("GL_OML_subsample", extStart, extEnd);
#endif /* GL_OML_subsample */
+#ifdef GL_OVR_multiview
+ GLEW_OVR_multiview = _glewSearchExtension("GL_OVR_multiview", extStart, extEnd);
+ if (glewExperimental || GLEW_OVR_multiview) GLEW_OVR_multiview = !_glewInit_GL_OVR_multiview(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_OVR_multiview */
+#ifdef GL_OVR_multiview2
+ GLEW_OVR_multiview2 = _glewSearchExtension("GL_OVR_multiview2", extStart, extEnd);
+#endif /* GL_OVR_multiview2 */
#ifdef GL_PGI_misc_hints
- CONST_CAST(GLEW_PGI_misc_hints) = _glewSearchExtension("GL_PGI_misc_hints", extStart, extEnd);
+ GLEW_PGI_misc_hints = _glewSearchExtension("GL_PGI_misc_hints", extStart, extEnd);
#endif /* GL_PGI_misc_hints */
#ifdef GL_PGI_vertex_hints
- CONST_CAST(GLEW_PGI_vertex_hints) = _glewSearchExtension("GL_PGI_vertex_hints", extStart, extEnd);
+ GLEW_PGI_vertex_hints = _glewSearchExtension("GL_PGI_vertex_hints", extStart, extEnd);
#endif /* GL_PGI_vertex_hints */
#ifdef GL_REGAL_ES1_0_compatibility
- CONST_CAST(GLEW_REGAL_ES1_0_compatibility) = _glewSearchExtension("GL_REGAL_ES1_0_compatibility", extStart, extEnd);
- if (glewExperimental || GLEW_REGAL_ES1_0_compatibility) CONST_CAST(GLEW_REGAL_ES1_0_compatibility) = !_glewInit_GL_REGAL_ES1_0_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_REGAL_ES1_0_compatibility = _glewSearchExtension("GL_REGAL_ES1_0_compatibility", extStart, extEnd);
+ if (glewExperimental || GLEW_REGAL_ES1_0_compatibility) GLEW_REGAL_ES1_0_compatibility = !_glewInit_GL_REGAL_ES1_0_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_REGAL_ES1_0_compatibility */
#ifdef GL_REGAL_ES1_1_compatibility
- CONST_CAST(GLEW_REGAL_ES1_1_compatibility) = _glewSearchExtension("GL_REGAL_ES1_1_compatibility", extStart, extEnd);
- if (glewExperimental || GLEW_REGAL_ES1_1_compatibility) CONST_CAST(GLEW_REGAL_ES1_1_compatibility) = !_glewInit_GL_REGAL_ES1_1_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_REGAL_ES1_1_compatibility = _glewSearchExtension("GL_REGAL_ES1_1_compatibility", extStart, extEnd);
+ if (glewExperimental || GLEW_REGAL_ES1_1_compatibility) GLEW_REGAL_ES1_1_compatibility = !_glewInit_GL_REGAL_ES1_1_compatibility(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_REGAL_ES1_1_compatibility */
#ifdef GL_REGAL_enable
- CONST_CAST(GLEW_REGAL_enable) = _glewSearchExtension("GL_REGAL_enable", extStart, extEnd);
+ GLEW_REGAL_enable = _glewSearchExtension("GL_REGAL_enable", extStart, extEnd);
#endif /* GL_REGAL_enable */
#ifdef GL_REGAL_error_string
- CONST_CAST(GLEW_REGAL_error_string) = _glewSearchExtension("GL_REGAL_error_string", extStart, extEnd);
- if (glewExperimental || GLEW_REGAL_error_string) CONST_CAST(GLEW_REGAL_error_string) = !_glewInit_GL_REGAL_error_string(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_REGAL_error_string = _glewSearchExtension("GL_REGAL_error_string", extStart, extEnd);
+ if (glewExperimental || GLEW_REGAL_error_string) GLEW_REGAL_error_string = !_glewInit_GL_REGAL_error_string(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_REGAL_error_string */
#ifdef GL_REGAL_extension_query
- CONST_CAST(GLEW_REGAL_extension_query) = _glewSearchExtension("GL_REGAL_extension_query", extStart, extEnd);
- if (glewExperimental || GLEW_REGAL_extension_query) CONST_CAST(GLEW_REGAL_extension_query) = !_glewInit_GL_REGAL_extension_query(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_REGAL_extension_query = _glewSearchExtension("GL_REGAL_extension_query", extStart, extEnd);
+ if (glewExperimental || GLEW_REGAL_extension_query) GLEW_REGAL_extension_query = !_glewInit_GL_REGAL_extension_query(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_REGAL_extension_query */
#ifdef GL_REGAL_log
- CONST_CAST(GLEW_REGAL_log) = _glewSearchExtension("GL_REGAL_log", extStart, extEnd);
- if (glewExperimental || GLEW_REGAL_log) CONST_CAST(GLEW_REGAL_log) = !_glewInit_GL_REGAL_log(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_REGAL_log = _glewSearchExtension("GL_REGAL_log", extStart, extEnd);
+ if (glewExperimental || GLEW_REGAL_log) GLEW_REGAL_log = !_glewInit_GL_REGAL_log(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_REGAL_log */
+#ifdef GL_REGAL_proc_address
+ GLEW_REGAL_proc_address = _glewSearchExtension("GL_REGAL_proc_address", extStart, extEnd);
+ if (glewExperimental || GLEW_REGAL_proc_address) GLEW_REGAL_proc_address = !_glewInit_GL_REGAL_proc_address(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GL_REGAL_proc_address */
#ifdef GL_REND_screen_coordinates
- CONST_CAST(GLEW_REND_screen_coordinates) = _glewSearchExtension("GL_REND_screen_coordinates", extStart, extEnd);
+ GLEW_REND_screen_coordinates = _glewSearchExtension("GL_REND_screen_coordinates", extStart, extEnd);
#endif /* GL_REND_screen_coordinates */
#ifdef GL_S3_s3tc
- CONST_CAST(GLEW_S3_s3tc) = _glewSearchExtension("GL_S3_s3tc", extStart, extEnd);
+ GLEW_S3_s3tc = _glewSearchExtension("GL_S3_s3tc", extStart, extEnd);
#endif /* GL_S3_s3tc */
#ifdef GL_SGIS_color_range
- CONST_CAST(GLEW_SGIS_color_range) = _glewSearchExtension("GL_SGIS_color_range", extStart, extEnd);
+ GLEW_SGIS_color_range = _glewSearchExtension("GL_SGIS_color_range", extStart, extEnd);
#endif /* GL_SGIS_color_range */
#ifdef GL_SGIS_detail_texture
- CONST_CAST(GLEW_SGIS_detail_texture) = _glewSearchExtension("GL_SGIS_detail_texture", extStart, extEnd);
- if (glewExperimental || GLEW_SGIS_detail_texture) CONST_CAST(GLEW_SGIS_detail_texture) = !_glewInit_GL_SGIS_detail_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIS_detail_texture = _glewSearchExtension("GL_SGIS_detail_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIS_detail_texture) GLEW_SGIS_detail_texture = !_glewInit_GL_SGIS_detail_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIS_detail_texture */
#ifdef GL_SGIS_fog_function
- CONST_CAST(GLEW_SGIS_fog_function) = _glewSearchExtension("GL_SGIS_fog_function", extStart, extEnd);
- if (glewExperimental || GLEW_SGIS_fog_function) CONST_CAST(GLEW_SGIS_fog_function) = !_glewInit_GL_SGIS_fog_function(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIS_fog_function = _glewSearchExtension("GL_SGIS_fog_function", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIS_fog_function) GLEW_SGIS_fog_function = !_glewInit_GL_SGIS_fog_function(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIS_fog_function */
#ifdef GL_SGIS_generate_mipmap
- CONST_CAST(GLEW_SGIS_generate_mipmap) = _glewSearchExtension("GL_SGIS_generate_mipmap", extStart, extEnd);
+ GLEW_SGIS_generate_mipmap = _glewSearchExtension("GL_SGIS_generate_mipmap", extStart, extEnd);
#endif /* GL_SGIS_generate_mipmap */
#ifdef GL_SGIS_multisample
- CONST_CAST(GLEW_SGIS_multisample) = _glewSearchExtension("GL_SGIS_multisample", extStart, extEnd);
- if (glewExperimental || GLEW_SGIS_multisample) CONST_CAST(GLEW_SGIS_multisample) = !_glewInit_GL_SGIS_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIS_multisample = _glewSearchExtension("GL_SGIS_multisample", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIS_multisample) GLEW_SGIS_multisample = !_glewInit_GL_SGIS_multisample(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIS_multisample */
#ifdef GL_SGIS_pixel_texture
- CONST_CAST(GLEW_SGIS_pixel_texture) = _glewSearchExtension("GL_SGIS_pixel_texture", extStart, extEnd);
+ GLEW_SGIS_pixel_texture = _glewSearchExtension("GL_SGIS_pixel_texture", extStart, extEnd);
#endif /* GL_SGIS_pixel_texture */
#ifdef GL_SGIS_point_line_texgen
- CONST_CAST(GLEW_SGIS_point_line_texgen) = _glewSearchExtension("GL_SGIS_point_line_texgen", extStart, extEnd);
+ GLEW_SGIS_point_line_texgen = _glewSearchExtension("GL_SGIS_point_line_texgen", extStart, extEnd);
#endif /* GL_SGIS_point_line_texgen */
#ifdef GL_SGIS_sharpen_texture
- CONST_CAST(GLEW_SGIS_sharpen_texture) = _glewSearchExtension("GL_SGIS_sharpen_texture", extStart, extEnd);
- if (glewExperimental || GLEW_SGIS_sharpen_texture) CONST_CAST(GLEW_SGIS_sharpen_texture) = !_glewInit_GL_SGIS_sharpen_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIS_sharpen_texture = _glewSearchExtension("GL_SGIS_sharpen_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIS_sharpen_texture) GLEW_SGIS_sharpen_texture = !_glewInit_GL_SGIS_sharpen_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIS_sharpen_texture */
#ifdef GL_SGIS_texture4D
- CONST_CAST(GLEW_SGIS_texture4D) = _glewSearchExtension("GL_SGIS_texture4D", extStart, extEnd);
- if (glewExperimental || GLEW_SGIS_texture4D) CONST_CAST(GLEW_SGIS_texture4D) = !_glewInit_GL_SGIS_texture4D(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIS_texture4D = _glewSearchExtension("GL_SGIS_texture4D", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIS_texture4D) GLEW_SGIS_texture4D = !_glewInit_GL_SGIS_texture4D(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIS_texture4D */
#ifdef GL_SGIS_texture_border_clamp
- CONST_CAST(GLEW_SGIS_texture_border_clamp) = _glewSearchExtension("GL_SGIS_texture_border_clamp", extStart, extEnd);
+ GLEW_SGIS_texture_border_clamp = _glewSearchExtension("GL_SGIS_texture_border_clamp", extStart, extEnd);
#endif /* GL_SGIS_texture_border_clamp */
#ifdef GL_SGIS_texture_edge_clamp
- CONST_CAST(GLEW_SGIS_texture_edge_clamp) = _glewSearchExtension("GL_SGIS_texture_edge_clamp", extStart, extEnd);
+ GLEW_SGIS_texture_edge_clamp = _glewSearchExtension("GL_SGIS_texture_edge_clamp", extStart, extEnd);
#endif /* GL_SGIS_texture_edge_clamp */
#ifdef GL_SGIS_texture_filter4
- CONST_CAST(GLEW_SGIS_texture_filter4) = _glewSearchExtension("GL_SGIS_texture_filter4", extStart, extEnd);
- if (glewExperimental || GLEW_SGIS_texture_filter4) CONST_CAST(GLEW_SGIS_texture_filter4) = !_glewInit_GL_SGIS_texture_filter4(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIS_texture_filter4 = _glewSearchExtension("GL_SGIS_texture_filter4", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIS_texture_filter4) GLEW_SGIS_texture_filter4 = !_glewInit_GL_SGIS_texture_filter4(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIS_texture_filter4 */
#ifdef GL_SGIS_texture_lod
- CONST_CAST(GLEW_SGIS_texture_lod) = _glewSearchExtension("GL_SGIS_texture_lod", extStart, extEnd);
+ GLEW_SGIS_texture_lod = _glewSearchExtension("GL_SGIS_texture_lod", extStart, extEnd);
#endif /* GL_SGIS_texture_lod */
#ifdef GL_SGIS_texture_select
- CONST_CAST(GLEW_SGIS_texture_select) = _glewSearchExtension("GL_SGIS_texture_select", extStart, extEnd);
+ GLEW_SGIS_texture_select = _glewSearchExtension("GL_SGIS_texture_select", extStart, extEnd);
#endif /* GL_SGIS_texture_select */
#ifdef GL_SGIX_async
- CONST_CAST(GLEW_SGIX_async) = _glewSearchExtension("GL_SGIX_async", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_async) CONST_CAST(GLEW_SGIX_async) = !_glewInit_GL_SGIX_async(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_async = _glewSearchExtension("GL_SGIX_async", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_async) GLEW_SGIX_async = !_glewInit_GL_SGIX_async(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_async */
#ifdef GL_SGIX_async_histogram
- CONST_CAST(GLEW_SGIX_async_histogram) = _glewSearchExtension("GL_SGIX_async_histogram", extStart, extEnd);
+ GLEW_SGIX_async_histogram = _glewSearchExtension("GL_SGIX_async_histogram", extStart, extEnd);
#endif /* GL_SGIX_async_histogram */
#ifdef GL_SGIX_async_pixel
- CONST_CAST(GLEW_SGIX_async_pixel) = _glewSearchExtension("GL_SGIX_async_pixel", extStart, extEnd);
+ GLEW_SGIX_async_pixel = _glewSearchExtension("GL_SGIX_async_pixel", extStart, extEnd);
#endif /* GL_SGIX_async_pixel */
#ifdef GL_SGIX_blend_alpha_minmax
- CONST_CAST(GLEW_SGIX_blend_alpha_minmax) = _glewSearchExtension("GL_SGIX_blend_alpha_minmax", extStart, extEnd);
+ GLEW_SGIX_blend_alpha_minmax = _glewSearchExtension("GL_SGIX_blend_alpha_minmax", extStart, extEnd);
#endif /* GL_SGIX_blend_alpha_minmax */
#ifdef GL_SGIX_clipmap
- CONST_CAST(GLEW_SGIX_clipmap) = _glewSearchExtension("GL_SGIX_clipmap", extStart, extEnd);
+ GLEW_SGIX_clipmap = _glewSearchExtension("GL_SGIX_clipmap", extStart, extEnd);
#endif /* GL_SGIX_clipmap */
#ifdef GL_SGIX_convolution_accuracy
- CONST_CAST(GLEW_SGIX_convolution_accuracy) = _glewSearchExtension("GL_SGIX_convolution_accuracy", extStart, extEnd);
+ GLEW_SGIX_convolution_accuracy = _glewSearchExtension("GL_SGIX_convolution_accuracy", extStart, extEnd);
#endif /* GL_SGIX_convolution_accuracy */
#ifdef GL_SGIX_depth_texture
- CONST_CAST(GLEW_SGIX_depth_texture) = _glewSearchExtension("GL_SGIX_depth_texture", extStart, extEnd);
+ GLEW_SGIX_depth_texture = _glewSearchExtension("GL_SGIX_depth_texture", extStart, extEnd);
#endif /* GL_SGIX_depth_texture */
#ifdef GL_SGIX_flush_raster
- CONST_CAST(GLEW_SGIX_flush_raster) = _glewSearchExtension("GL_SGIX_flush_raster", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_flush_raster) CONST_CAST(GLEW_SGIX_flush_raster) = !_glewInit_GL_SGIX_flush_raster(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_flush_raster = _glewSearchExtension("GL_SGIX_flush_raster", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_flush_raster) GLEW_SGIX_flush_raster = !_glewInit_GL_SGIX_flush_raster(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_flush_raster */
#ifdef GL_SGIX_fog_offset
- CONST_CAST(GLEW_SGIX_fog_offset) = _glewSearchExtension("GL_SGIX_fog_offset", extStart, extEnd);
+ GLEW_SGIX_fog_offset = _glewSearchExtension("GL_SGIX_fog_offset", extStart, extEnd);
#endif /* GL_SGIX_fog_offset */
#ifdef GL_SGIX_fog_texture
- CONST_CAST(GLEW_SGIX_fog_texture) = _glewSearchExtension("GL_SGIX_fog_texture", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_fog_texture) CONST_CAST(GLEW_SGIX_fog_texture) = !_glewInit_GL_SGIX_fog_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_fog_texture = _glewSearchExtension("GL_SGIX_fog_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_fog_texture) GLEW_SGIX_fog_texture = !_glewInit_GL_SGIX_fog_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_fog_texture */
#ifdef GL_SGIX_fragment_specular_lighting
- CONST_CAST(GLEW_SGIX_fragment_specular_lighting) = _glewSearchExtension("GL_SGIX_fragment_specular_lighting", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_fragment_specular_lighting) CONST_CAST(GLEW_SGIX_fragment_specular_lighting) = !_glewInit_GL_SGIX_fragment_specular_lighting(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_fragment_specular_lighting = _glewSearchExtension("GL_SGIX_fragment_specular_lighting", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_fragment_specular_lighting) GLEW_SGIX_fragment_specular_lighting = !_glewInit_GL_SGIX_fragment_specular_lighting(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_fragment_specular_lighting */
#ifdef GL_SGIX_framezoom
- CONST_CAST(GLEW_SGIX_framezoom) = _glewSearchExtension("GL_SGIX_framezoom", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_framezoom) CONST_CAST(GLEW_SGIX_framezoom) = !_glewInit_GL_SGIX_framezoom(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_framezoom = _glewSearchExtension("GL_SGIX_framezoom", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_framezoom) GLEW_SGIX_framezoom = !_glewInit_GL_SGIX_framezoom(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_framezoom */
#ifdef GL_SGIX_interlace
- CONST_CAST(GLEW_SGIX_interlace) = _glewSearchExtension("GL_SGIX_interlace", extStart, extEnd);
+ GLEW_SGIX_interlace = _glewSearchExtension("GL_SGIX_interlace", extStart, extEnd);
#endif /* GL_SGIX_interlace */
#ifdef GL_SGIX_ir_instrument1
- CONST_CAST(GLEW_SGIX_ir_instrument1) = _glewSearchExtension("GL_SGIX_ir_instrument1", extStart, extEnd);
+ GLEW_SGIX_ir_instrument1 = _glewSearchExtension("GL_SGIX_ir_instrument1", extStart, extEnd);
#endif /* GL_SGIX_ir_instrument1 */
#ifdef GL_SGIX_list_priority
- CONST_CAST(GLEW_SGIX_list_priority) = _glewSearchExtension("GL_SGIX_list_priority", extStart, extEnd);
+ GLEW_SGIX_list_priority = _glewSearchExtension("GL_SGIX_list_priority", extStart, extEnd);
#endif /* GL_SGIX_list_priority */
#ifdef GL_SGIX_pixel_texture
- CONST_CAST(GLEW_SGIX_pixel_texture) = _glewSearchExtension("GL_SGIX_pixel_texture", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_pixel_texture) CONST_CAST(GLEW_SGIX_pixel_texture) = !_glewInit_GL_SGIX_pixel_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_pixel_texture = _glewSearchExtension("GL_SGIX_pixel_texture", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_pixel_texture) GLEW_SGIX_pixel_texture = !_glewInit_GL_SGIX_pixel_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_pixel_texture */
#ifdef GL_SGIX_pixel_texture_bits
- CONST_CAST(GLEW_SGIX_pixel_texture_bits) = _glewSearchExtension("GL_SGIX_pixel_texture_bits", extStart, extEnd);
+ GLEW_SGIX_pixel_texture_bits = _glewSearchExtension("GL_SGIX_pixel_texture_bits", extStart, extEnd);
#endif /* GL_SGIX_pixel_texture_bits */
#ifdef GL_SGIX_reference_plane
- CONST_CAST(GLEW_SGIX_reference_plane) = _glewSearchExtension("GL_SGIX_reference_plane", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_reference_plane) CONST_CAST(GLEW_SGIX_reference_plane) = !_glewInit_GL_SGIX_reference_plane(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_reference_plane = _glewSearchExtension("GL_SGIX_reference_plane", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_reference_plane) GLEW_SGIX_reference_plane = !_glewInit_GL_SGIX_reference_plane(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_reference_plane */
#ifdef GL_SGIX_resample
- CONST_CAST(GLEW_SGIX_resample) = _glewSearchExtension("GL_SGIX_resample", extStart, extEnd);
+ GLEW_SGIX_resample = _glewSearchExtension("GL_SGIX_resample", extStart, extEnd);
#endif /* GL_SGIX_resample */
#ifdef GL_SGIX_shadow
- CONST_CAST(GLEW_SGIX_shadow) = _glewSearchExtension("GL_SGIX_shadow", extStart, extEnd);
+ GLEW_SGIX_shadow = _glewSearchExtension("GL_SGIX_shadow", extStart, extEnd);
#endif /* GL_SGIX_shadow */
#ifdef GL_SGIX_shadow_ambient
- CONST_CAST(GLEW_SGIX_shadow_ambient) = _glewSearchExtension("GL_SGIX_shadow_ambient", extStart, extEnd);
+ GLEW_SGIX_shadow_ambient = _glewSearchExtension("GL_SGIX_shadow_ambient", extStart, extEnd);
#endif /* GL_SGIX_shadow_ambient */
#ifdef GL_SGIX_sprite
- CONST_CAST(GLEW_SGIX_sprite) = _glewSearchExtension("GL_SGIX_sprite", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_sprite) CONST_CAST(GLEW_SGIX_sprite) = !_glewInit_GL_SGIX_sprite(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_sprite = _glewSearchExtension("GL_SGIX_sprite", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_sprite) GLEW_SGIX_sprite = !_glewInit_GL_SGIX_sprite(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_sprite */
#ifdef GL_SGIX_tag_sample_buffer
- CONST_CAST(GLEW_SGIX_tag_sample_buffer) = _glewSearchExtension("GL_SGIX_tag_sample_buffer", extStart, extEnd);
- if (glewExperimental || GLEW_SGIX_tag_sample_buffer) CONST_CAST(GLEW_SGIX_tag_sample_buffer) = !_glewInit_GL_SGIX_tag_sample_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGIX_tag_sample_buffer = _glewSearchExtension("GL_SGIX_tag_sample_buffer", extStart, extEnd);
+ if (glewExperimental || GLEW_SGIX_tag_sample_buffer) GLEW_SGIX_tag_sample_buffer = !_glewInit_GL_SGIX_tag_sample_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGIX_tag_sample_buffer */
#ifdef GL_SGIX_texture_add_env
- CONST_CAST(GLEW_SGIX_texture_add_env) = _glewSearchExtension("GL_SGIX_texture_add_env", extStart, extEnd);
+ GLEW_SGIX_texture_add_env = _glewSearchExtension("GL_SGIX_texture_add_env", extStart, extEnd);
#endif /* GL_SGIX_texture_add_env */
#ifdef GL_SGIX_texture_coordinate_clamp
- CONST_CAST(GLEW_SGIX_texture_coordinate_clamp) = _glewSearchExtension("GL_SGIX_texture_coordinate_clamp", extStart, extEnd);
+ GLEW_SGIX_texture_coordinate_clamp = _glewSearchExtension("GL_SGIX_texture_coordinate_clamp", extStart, extEnd);
#endif /* GL_SGIX_texture_coordinate_clamp */
#ifdef GL_SGIX_texture_lod_bias
- CONST_CAST(GLEW_SGIX_texture_lod_bias) = _glewSearchExtension("GL_SGIX_texture_lod_bias", extStart, extEnd);
+ GLEW_SGIX_texture_lod_bias = _glewSearchExtension("GL_SGIX_texture_lod_bias", extStart, extEnd);
#endif /* GL_SGIX_texture_lod_bias */
#ifdef GL_SGIX_texture_multi_buffer
- CONST_CAST(GLEW_SGIX_texture_multi_buffer) = _glewSearchExtension("GL_SGIX_texture_multi_buffer", extStart, extEnd);
+ GLEW_SGIX_texture_multi_buffer = _glewSearchExtension("GL_SGIX_texture_multi_buffer", extStart, extEnd);
#endif /* GL_SGIX_texture_multi_buffer */
#ifdef GL_SGIX_texture_range
- CONST_CAST(GLEW_SGIX_texture_range) = _glewSearchExtension("GL_SGIX_texture_range", extStart, extEnd);
+ GLEW_SGIX_texture_range = _glewSearchExtension("GL_SGIX_texture_range", extStart, extEnd);
#endif /* GL_SGIX_texture_range */
#ifdef GL_SGIX_texture_scale_bias
- CONST_CAST(GLEW_SGIX_texture_scale_bias) = _glewSearchExtension("GL_SGIX_texture_scale_bias", extStart, extEnd);
+ GLEW_SGIX_texture_scale_bias = _glewSearchExtension("GL_SGIX_texture_scale_bias", extStart, extEnd);
#endif /* GL_SGIX_texture_scale_bias */
#ifdef GL_SGIX_vertex_preclip
- CONST_CAST(GLEW_SGIX_vertex_preclip) = _glewSearchExtension("GL_SGIX_vertex_preclip", extStart, extEnd);
+ GLEW_SGIX_vertex_preclip = _glewSearchExtension("GL_SGIX_vertex_preclip", extStart, extEnd);
#endif /* GL_SGIX_vertex_preclip */
#ifdef GL_SGIX_vertex_preclip_hint
- CONST_CAST(GLEW_SGIX_vertex_preclip_hint) = _glewSearchExtension("GL_SGIX_vertex_preclip_hint", extStart, extEnd);
+ GLEW_SGIX_vertex_preclip_hint = _glewSearchExtension("GL_SGIX_vertex_preclip_hint", extStart, extEnd);
#endif /* GL_SGIX_vertex_preclip_hint */
#ifdef GL_SGIX_ycrcb
- CONST_CAST(GLEW_SGIX_ycrcb) = _glewSearchExtension("GL_SGIX_ycrcb", extStart, extEnd);
+ GLEW_SGIX_ycrcb = _glewSearchExtension("GL_SGIX_ycrcb", extStart, extEnd);
#endif /* GL_SGIX_ycrcb */
#ifdef GL_SGI_color_matrix
- CONST_CAST(GLEW_SGI_color_matrix) = _glewSearchExtension("GL_SGI_color_matrix", extStart, extEnd);
+ GLEW_SGI_color_matrix = _glewSearchExtension("GL_SGI_color_matrix", extStart, extEnd);
#endif /* GL_SGI_color_matrix */
#ifdef GL_SGI_color_table
- CONST_CAST(GLEW_SGI_color_table) = _glewSearchExtension("GL_SGI_color_table", extStart, extEnd);
- if (glewExperimental || GLEW_SGI_color_table) CONST_CAST(GLEW_SGI_color_table) = !_glewInit_GL_SGI_color_table(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SGI_color_table = _glewSearchExtension("GL_SGI_color_table", extStart, extEnd);
+ if (glewExperimental || GLEW_SGI_color_table) GLEW_SGI_color_table = !_glewInit_GL_SGI_color_table(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SGI_color_table */
#ifdef GL_SGI_texture_color_table
- CONST_CAST(GLEW_SGI_texture_color_table) = _glewSearchExtension("GL_SGI_texture_color_table", extStart, extEnd);
+ GLEW_SGI_texture_color_table = _glewSearchExtension("GL_SGI_texture_color_table", extStart, extEnd);
#endif /* GL_SGI_texture_color_table */
#ifdef GL_SUNX_constant_data
- CONST_CAST(GLEW_SUNX_constant_data) = _glewSearchExtension("GL_SUNX_constant_data", extStart, extEnd);
- if (glewExperimental || GLEW_SUNX_constant_data) CONST_CAST(GLEW_SUNX_constant_data) = !_glewInit_GL_SUNX_constant_data(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SUNX_constant_data = _glewSearchExtension("GL_SUNX_constant_data", extStart, extEnd);
+ if (glewExperimental || GLEW_SUNX_constant_data) GLEW_SUNX_constant_data = !_glewInit_GL_SUNX_constant_data(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SUNX_constant_data */
#ifdef GL_SUN_convolution_border_modes
- CONST_CAST(GLEW_SUN_convolution_border_modes) = _glewSearchExtension("GL_SUN_convolution_border_modes", extStart, extEnd);
+ GLEW_SUN_convolution_border_modes = _glewSearchExtension("GL_SUN_convolution_border_modes", extStart, extEnd);
#endif /* GL_SUN_convolution_border_modes */
#ifdef GL_SUN_global_alpha
- CONST_CAST(GLEW_SUN_global_alpha) = _glewSearchExtension("GL_SUN_global_alpha", extStart, extEnd);
- if (glewExperimental || GLEW_SUN_global_alpha) CONST_CAST(GLEW_SUN_global_alpha) = !_glewInit_GL_SUN_global_alpha(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SUN_global_alpha = _glewSearchExtension("GL_SUN_global_alpha", extStart, extEnd);
+ if (glewExperimental || GLEW_SUN_global_alpha) GLEW_SUN_global_alpha = !_glewInit_GL_SUN_global_alpha(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SUN_global_alpha */
#ifdef GL_SUN_mesh_array
- CONST_CAST(GLEW_SUN_mesh_array) = _glewSearchExtension("GL_SUN_mesh_array", extStart, extEnd);
+ GLEW_SUN_mesh_array = _glewSearchExtension("GL_SUN_mesh_array", extStart, extEnd);
#endif /* GL_SUN_mesh_array */
#ifdef GL_SUN_read_video_pixels
- CONST_CAST(GLEW_SUN_read_video_pixels) = _glewSearchExtension("GL_SUN_read_video_pixels", extStart, extEnd);
- if (glewExperimental || GLEW_SUN_read_video_pixels) CONST_CAST(GLEW_SUN_read_video_pixels) = !_glewInit_GL_SUN_read_video_pixels(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SUN_read_video_pixels = _glewSearchExtension("GL_SUN_read_video_pixels", extStart, extEnd);
+ if (glewExperimental || GLEW_SUN_read_video_pixels) GLEW_SUN_read_video_pixels = !_glewInit_GL_SUN_read_video_pixels(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SUN_read_video_pixels */
#ifdef GL_SUN_slice_accum
- CONST_CAST(GLEW_SUN_slice_accum) = _glewSearchExtension("GL_SUN_slice_accum", extStart, extEnd);
+ GLEW_SUN_slice_accum = _glewSearchExtension("GL_SUN_slice_accum", extStart, extEnd);
#endif /* GL_SUN_slice_accum */
#ifdef GL_SUN_triangle_list
- CONST_CAST(GLEW_SUN_triangle_list) = _glewSearchExtension("GL_SUN_triangle_list", extStart, extEnd);
- if (glewExperimental || GLEW_SUN_triangle_list) CONST_CAST(GLEW_SUN_triangle_list) = !_glewInit_GL_SUN_triangle_list(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SUN_triangle_list = _glewSearchExtension("GL_SUN_triangle_list", extStart, extEnd);
+ if (glewExperimental || GLEW_SUN_triangle_list) GLEW_SUN_triangle_list = !_glewInit_GL_SUN_triangle_list(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SUN_triangle_list */
#ifdef GL_SUN_vertex
- CONST_CAST(GLEW_SUN_vertex) = _glewSearchExtension("GL_SUN_vertex", extStart, extEnd);
- if (glewExperimental || GLEW_SUN_vertex) CONST_CAST(GLEW_SUN_vertex) = !_glewInit_GL_SUN_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_SUN_vertex = _glewSearchExtension("GL_SUN_vertex", extStart, extEnd);
+ if (glewExperimental || GLEW_SUN_vertex) GLEW_SUN_vertex = !_glewInit_GL_SUN_vertex(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_SUN_vertex */
#ifdef GL_WIN_phong_shading
- CONST_CAST(GLEW_WIN_phong_shading) = _glewSearchExtension("GL_WIN_phong_shading", extStart, extEnd);
+ GLEW_WIN_phong_shading = _glewSearchExtension("GL_WIN_phong_shading", extStart, extEnd);
#endif /* GL_WIN_phong_shading */
#ifdef GL_WIN_specular_fog
- CONST_CAST(GLEW_WIN_specular_fog) = _glewSearchExtension("GL_WIN_specular_fog", extStart, extEnd);
+ GLEW_WIN_specular_fog = _glewSearchExtension("GL_WIN_specular_fog", extStart, extEnd);
#endif /* GL_WIN_specular_fog */
#ifdef GL_WIN_swap_hint
- CONST_CAST(GLEW_WIN_swap_hint) = _glewSearchExtension("GL_WIN_swap_hint", extStart, extEnd);
- if (glewExperimental || GLEW_WIN_swap_hint) CONST_CAST(GLEW_WIN_swap_hint) = !_glewInit_GL_WIN_swap_hint(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLEW_WIN_swap_hint = _glewSearchExtension("GL_WIN_swap_hint", extStart, extEnd);
+ if (glewExperimental || GLEW_WIN_swap_hint) GLEW_WIN_swap_hint = !_glewInit_GL_WIN_swap_hint(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GL_WIN_swap_hint */
return GLEW_OK;
@@ -11433,6 +11474,8 @@ PFNWGLDXUNREGISTEROBJECTNVPROC __wglewDXUnregisterObjectNV = NULL;
PFNWGLCOPYIMAGESUBDATANVPROC __wglewCopyImageSubDataNV = NULL;
+PFNWGLDELAYBEFORESWAPNVPROC __wglewDelayBeforeSwapNV = NULL;
+
PFNWGLCREATEAFFINITYDCNVPROC __wglewCreateAffinityDCNV = NULL;
PFNWGLDELETEDCNVPROC __wglewDeleteDCNV = NULL;
PFNWGLENUMGPUDEVICESNVPROC __wglewEnumGpuDevicesNV = NULL;
@@ -11476,6 +11519,7 @@ GLboolean __WGLEW_3DFX_multisample = GL_FALSE;
GLboolean __WGLEW_3DL_stereo_control = GL_FALSE;
GLboolean __WGLEW_AMD_gpu_association = GL_FALSE;
GLboolean __WGLEW_ARB_buffer_region = GL_FALSE;
+GLboolean __WGLEW_ARB_context_flush_control = GL_FALSE;
GLboolean __WGLEW_ARB_create_context = GL_FALSE;
GLboolean __WGLEW_ARB_create_context_profile = GL_FALSE;
GLboolean __WGLEW_ARB_create_context_robustness = GL_FALSE;
@@ -11513,6 +11557,7 @@ GLboolean __WGLEW_I3D_swap_frame_usage = GL_FALSE;
GLboolean __WGLEW_NV_DX_interop = GL_FALSE;
GLboolean __WGLEW_NV_DX_interop2 = GL_FALSE;
GLboolean __WGLEW_NV_copy_image = GL_FALSE;
+GLboolean __WGLEW_NV_delay_before_swap = GL_FALSE;
GLboolean __WGLEW_NV_float_buffer = GL_FALSE;
GLboolean __WGLEW_NV_gpu_affinity = GL_FALSE;
GLboolean __WGLEW_NV_multisample_coverage = GL_FALSE;
@@ -11527,10 +11572,6 @@ GLboolean __WGLEW_OML_sync_control = GL_FALSE;
#endif /* !GLEW_MX */
-#ifdef WGL_3DFX_multisample
-
-#endif /* WGL_3DFX_multisample */
-
#ifdef WGL_3DL_stereo_control
static GLboolean _glewInit_WGL_3DL_stereo_control (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11594,14 +11635,6 @@ static GLboolean _glewInit_WGL_ARB_create_context (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_ARB_create_context */
-#ifdef WGL_ARB_create_context_profile
-
-#endif /* WGL_ARB_create_context_profile */
-
-#ifdef WGL_ARB_create_context_robustness
-
-#endif /* WGL_ARB_create_context_robustness */
-
#ifdef WGL_ARB_extensions_string
static GLboolean _glewInit_WGL_ARB_extensions_string (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11615,10 +11648,6 @@ static GLboolean _glewInit_WGL_ARB_extensions_string (WGLEW_CONTEXT_ARG_DEF_INIT
#endif /* WGL_ARB_extensions_string */
-#ifdef WGL_ARB_framebuffer_sRGB
-
-#endif /* WGL_ARB_framebuffer_sRGB */
-
#ifdef WGL_ARB_make_current_read
static GLboolean _glewInit_WGL_ARB_make_current_read (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11633,10 +11662,6 @@ static GLboolean _glewInit_WGL_ARB_make_current_read (WGLEW_CONTEXT_ARG_DEF_INIT
#endif /* WGL_ARB_make_current_read */
-#ifdef WGL_ARB_multisample
-
-#endif /* WGL_ARB_multisample */
-
#ifdef WGL_ARB_pbuffer
static GLboolean _glewInit_WGL_ARB_pbuffer (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11669,10 +11694,6 @@ static GLboolean _glewInit_WGL_ARB_pixel_format (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_ARB_pixel_format */
-#ifdef WGL_ARB_pixel_format_float
-
-#endif /* WGL_ARB_pixel_format_float */
-
#ifdef WGL_ARB_render_texture
static GLboolean _glewInit_WGL_ARB_render_texture (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11688,34 +11709,6 @@ static GLboolean _glewInit_WGL_ARB_render_texture (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_ARB_render_texture */
-#ifdef WGL_ARB_robustness_application_isolation
-
-#endif /* WGL_ARB_robustness_application_isolation */
-
-#ifdef WGL_ARB_robustness_share_group_isolation
-
-#endif /* WGL_ARB_robustness_share_group_isolation */
-
-#ifdef WGL_ATI_pixel_format_float
-
-#endif /* WGL_ATI_pixel_format_float */
-
-#ifdef WGL_ATI_render_texture_rectangle
-
-#endif /* WGL_ATI_render_texture_rectangle */
-
-#ifdef WGL_EXT_create_context_es2_profile
-
-#endif /* WGL_EXT_create_context_es2_profile */
-
-#ifdef WGL_EXT_create_context_es_profile
-
-#endif /* WGL_EXT_create_context_es_profile */
-
-#ifdef WGL_EXT_depth_float
-
-#endif /* WGL_EXT_depth_float */
-
#ifdef WGL_EXT_display_color_table
static GLboolean _glewInit_WGL_EXT_display_color_table (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11745,10 +11738,6 @@ static GLboolean _glewInit_WGL_EXT_extensions_string (WGLEW_CONTEXT_ARG_DEF_INIT
#endif /* WGL_EXT_extensions_string */
-#ifdef WGL_EXT_framebuffer_sRGB
-
-#endif /* WGL_EXT_framebuffer_sRGB */
-
#ifdef WGL_EXT_make_current_read
static GLboolean _glewInit_WGL_EXT_make_current_read (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11763,10 +11752,6 @@ static GLboolean _glewInit_WGL_EXT_make_current_read (WGLEW_CONTEXT_ARG_DEF_INIT
#endif /* WGL_EXT_make_current_read */
-#ifdef WGL_EXT_multisample
-
-#endif /* WGL_EXT_multisample */
-
#ifdef WGL_EXT_pbuffer
static GLboolean _glewInit_WGL_EXT_pbuffer (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11799,10 +11784,6 @@ static GLboolean _glewInit_WGL_EXT_pixel_format (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_EXT_pixel_format */
-#ifdef WGL_EXT_pixel_format_packed_float
-
-#endif /* WGL_EXT_pixel_format_packed_float */
-
#ifdef WGL_EXT_swap_control
static GLboolean _glewInit_WGL_EXT_swap_control (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11817,10 +11798,6 @@ static GLboolean _glewInit_WGL_EXT_swap_control (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_EXT_swap_control */
-#ifdef WGL_EXT_swap_control_tear
-
-#endif /* WGL_EXT_swap_control_tear */
-
#ifdef WGL_I3D_digital_video_control
static GLboolean _glewInit_WGL_I3D_digital_video_control (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11943,10 +11920,6 @@ static GLboolean _glewInit_WGL_NV_DX_interop (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_NV_DX_interop */
-#ifdef WGL_NV_DX_interop2
-
-#endif /* WGL_NV_DX_interop2 */
-
#ifdef WGL_NV_copy_image
static GLboolean _glewInit_WGL_NV_copy_image (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -11960,9 +11933,18 @@ static GLboolean _glewInit_WGL_NV_copy_image (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_NV_copy_image */
-#ifdef WGL_NV_float_buffer
+#ifdef WGL_NV_delay_before_swap
-#endif /* WGL_NV_float_buffer */
+static GLboolean _glewInit_WGL_NV_delay_before_swap (WGLEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((wglDelayBeforeSwapNV = (PFNWGLDELAYBEFORESWAPNVPROC)glewGetProcAddress((const GLubyte*)"wglDelayBeforeSwapNV")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* WGL_NV_delay_before_swap */
#ifdef WGL_NV_gpu_affinity
@@ -11981,10 +11963,6 @@ static GLboolean _glewInit_WGL_NV_gpu_affinity (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_NV_gpu_affinity */
-#ifdef WGL_NV_multisample_coverage
-
-#endif /* WGL_NV_multisample_coverage */
-
#ifdef WGL_NV_present_video
static GLboolean _glewInit_WGL_NV_present_video (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -12000,14 +11978,6 @@ static GLboolean _glewInit_WGL_NV_present_video (WGLEW_CONTEXT_ARG_DEF_INIT)
#endif /* WGL_NV_present_video */
-#ifdef WGL_NV_render_depth_texture
-
-#endif /* WGL_NV_render_depth_texture */
-
-#ifdef WGL_NV_render_texture_rectangle
-
-#endif /* WGL_NV_render_texture_rectangle */
-
#ifdef WGL_NV_swap_group
static GLboolean _glewInit_WGL_NV_swap_group (WGLEW_CONTEXT_ARG_DEF_INIT)
@@ -12115,7 +12085,11 @@ GLboolean GLEWAPIENTRY wglewGetExtension (const char* name)
return _glewSearchExtension(name, start, end);
}
+#ifdef GLEW_MX
GLenum GLEWAPIENTRY wglewContextInit (WGLEW_CONTEXT_ARG_DEF_LIST)
+#else
+GLenum GLEWAPIENTRY wglewInit (WGLEW_CONTEXT_ARG_DEF_LIST)
+#endif
{
GLboolean crippled;
const GLubyte* extStart;
@@ -12135,196 +12109,203 @@ GLenum GLEWAPIENTRY wglewContextInit (WGLEW_CONTEXT_ARG_DEF_LIST)
/* initialize extensions */
crippled = _wglewGetExtensionsStringARB == NULL && _wglewGetExtensionsStringEXT == NULL;
#ifdef WGL_3DFX_multisample
- CONST_CAST(WGLEW_3DFX_multisample) = _glewSearchExtension("WGL_3DFX_multisample", extStart, extEnd);
+ WGLEW_3DFX_multisample = _glewSearchExtension("WGL_3DFX_multisample", extStart, extEnd);
#endif /* WGL_3DFX_multisample */
#ifdef WGL_3DL_stereo_control
- CONST_CAST(WGLEW_3DL_stereo_control) = _glewSearchExtension("WGL_3DL_stereo_control", extStart, extEnd);
- if (glewExperimental || WGLEW_3DL_stereo_control|| crippled) CONST_CAST(WGLEW_3DL_stereo_control)= !_glewInit_WGL_3DL_stereo_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_3DL_stereo_control = _glewSearchExtension("WGL_3DL_stereo_control", extStart, extEnd);
+ if (glewExperimental || WGLEW_3DL_stereo_control|| crippled) WGLEW_3DL_stereo_control= !_glewInit_WGL_3DL_stereo_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_3DL_stereo_control */
#ifdef WGL_AMD_gpu_association
- CONST_CAST(WGLEW_AMD_gpu_association) = _glewSearchExtension("WGL_AMD_gpu_association", extStart, extEnd);
- if (glewExperimental || WGLEW_AMD_gpu_association|| crippled) CONST_CAST(WGLEW_AMD_gpu_association)= !_glewInit_WGL_AMD_gpu_association(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_AMD_gpu_association = _glewSearchExtension("WGL_AMD_gpu_association", extStart, extEnd);
+ if (glewExperimental || WGLEW_AMD_gpu_association|| crippled) WGLEW_AMD_gpu_association= !_glewInit_WGL_AMD_gpu_association(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_AMD_gpu_association */
#ifdef WGL_ARB_buffer_region
- CONST_CAST(WGLEW_ARB_buffer_region) = _glewSearchExtension("WGL_ARB_buffer_region", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_buffer_region|| crippled) CONST_CAST(WGLEW_ARB_buffer_region)= !_glewInit_WGL_ARB_buffer_region(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_buffer_region = _glewSearchExtension("WGL_ARB_buffer_region", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_buffer_region|| crippled) WGLEW_ARB_buffer_region= !_glewInit_WGL_ARB_buffer_region(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_buffer_region */
+#ifdef WGL_ARB_context_flush_control
+ WGLEW_ARB_context_flush_control = _glewSearchExtension("WGL_ARB_context_flush_control", extStart, extEnd);
+#endif /* WGL_ARB_context_flush_control */
#ifdef WGL_ARB_create_context
- CONST_CAST(WGLEW_ARB_create_context) = _glewSearchExtension("WGL_ARB_create_context", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_create_context|| crippled) CONST_CAST(WGLEW_ARB_create_context)= !_glewInit_WGL_ARB_create_context(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_create_context = _glewSearchExtension("WGL_ARB_create_context", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_create_context|| crippled) WGLEW_ARB_create_context= !_glewInit_WGL_ARB_create_context(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_create_context */
#ifdef WGL_ARB_create_context_profile
- CONST_CAST(WGLEW_ARB_create_context_profile) = _glewSearchExtension("WGL_ARB_create_context_profile", extStart, extEnd);
+ WGLEW_ARB_create_context_profile = _glewSearchExtension("WGL_ARB_create_context_profile", extStart, extEnd);
#endif /* WGL_ARB_create_context_profile */
#ifdef WGL_ARB_create_context_robustness
- CONST_CAST(WGLEW_ARB_create_context_robustness) = _glewSearchExtension("WGL_ARB_create_context_robustness", extStart, extEnd);
+ WGLEW_ARB_create_context_robustness = _glewSearchExtension("WGL_ARB_create_context_robustness", extStart, extEnd);
#endif /* WGL_ARB_create_context_robustness */
#ifdef WGL_ARB_extensions_string
- CONST_CAST(WGLEW_ARB_extensions_string) = _glewSearchExtension("WGL_ARB_extensions_string", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_extensions_string|| crippled) CONST_CAST(WGLEW_ARB_extensions_string)= !_glewInit_WGL_ARB_extensions_string(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_extensions_string = _glewSearchExtension("WGL_ARB_extensions_string", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_extensions_string|| crippled) WGLEW_ARB_extensions_string= !_glewInit_WGL_ARB_extensions_string(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_extensions_string */
#ifdef WGL_ARB_framebuffer_sRGB
- CONST_CAST(WGLEW_ARB_framebuffer_sRGB) = _glewSearchExtension("WGL_ARB_framebuffer_sRGB", extStart, extEnd);
+ WGLEW_ARB_framebuffer_sRGB = _glewSearchExtension("WGL_ARB_framebuffer_sRGB", extStart, extEnd);
#endif /* WGL_ARB_framebuffer_sRGB */
#ifdef WGL_ARB_make_current_read
- CONST_CAST(WGLEW_ARB_make_current_read) = _glewSearchExtension("WGL_ARB_make_current_read", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_make_current_read|| crippled) CONST_CAST(WGLEW_ARB_make_current_read)= !_glewInit_WGL_ARB_make_current_read(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_make_current_read = _glewSearchExtension("WGL_ARB_make_current_read", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_make_current_read|| crippled) WGLEW_ARB_make_current_read= !_glewInit_WGL_ARB_make_current_read(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_make_current_read */
#ifdef WGL_ARB_multisample
- CONST_CAST(WGLEW_ARB_multisample) = _glewSearchExtension("WGL_ARB_multisample", extStart, extEnd);
+ WGLEW_ARB_multisample = _glewSearchExtension("WGL_ARB_multisample", extStart, extEnd);
#endif /* WGL_ARB_multisample */
#ifdef WGL_ARB_pbuffer
- CONST_CAST(WGLEW_ARB_pbuffer) = _glewSearchExtension("WGL_ARB_pbuffer", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_pbuffer|| crippled) CONST_CAST(WGLEW_ARB_pbuffer)= !_glewInit_WGL_ARB_pbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_pbuffer = _glewSearchExtension("WGL_ARB_pbuffer", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_pbuffer|| crippled) WGLEW_ARB_pbuffer= !_glewInit_WGL_ARB_pbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_pbuffer */
#ifdef WGL_ARB_pixel_format
- CONST_CAST(WGLEW_ARB_pixel_format) = _glewSearchExtension("WGL_ARB_pixel_format", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_pixel_format|| crippled) CONST_CAST(WGLEW_ARB_pixel_format)= !_glewInit_WGL_ARB_pixel_format(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_pixel_format = _glewSearchExtension("WGL_ARB_pixel_format", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_pixel_format|| crippled) WGLEW_ARB_pixel_format= !_glewInit_WGL_ARB_pixel_format(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_pixel_format */
#ifdef WGL_ARB_pixel_format_float
- CONST_CAST(WGLEW_ARB_pixel_format_float) = _glewSearchExtension("WGL_ARB_pixel_format_float", extStart, extEnd);
+ WGLEW_ARB_pixel_format_float = _glewSearchExtension("WGL_ARB_pixel_format_float", extStart, extEnd);
#endif /* WGL_ARB_pixel_format_float */
#ifdef WGL_ARB_render_texture
- CONST_CAST(WGLEW_ARB_render_texture) = _glewSearchExtension("WGL_ARB_render_texture", extStart, extEnd);
- if (glewExperimental || WGLEW_ARB_render_texture|| crippled) CONST_CAST(WGLEW_ARB_render_texture)= !_glewInit_WGL_ARB_render_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_ARB_render_texture = _glewSearchExtension("WGL_ARB_render_texture", extStart, extEnd);
+ if (glewExperimental || WGLEW_ARB_render_texture|| crippled) WGLEW_ARB_render_texture= !_glewInit_WGL_ARB_render_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_ARB_render_texture */
#ifdef WGL_ARB_robustness_application_isolation
- CONST_CAST(WGLEW_ARB_robustness_application_isolation) = _glewSearchExtension("WGL_ARB_robustness_application_isolation", extStart, extEnd);
+ WGLEW_ARB_robustness_application_isolation = _glewSearchExtension("WGL_ARB_robustness_application_isolation", extStart, extEnd);
#endif /* WGL_ARB_robustness_application_isolation */
#ifdef WGL_ARB_robustness_share_group_isolation
- CONST_CAST(WGLEW_ARB_robustness_share_group_isolation) = _glewSearchExtension("WGL_ARB_robustness_share_group_isolation", extStart, extEnd);
+ WGLEW_ARB_robustness_share_group_isolation = _glewSearchExtension("WGL_ARB_robustness_share_group_isolation", extStart, extEnd);
#endif /* WGL_ARB_robustness_share_group_isolation */
#ifdef WGL_ATI_pixel_format_float
- CONST_CAST(WGLEW_ATI_pixel_format_float) = _glewSearchExtension("WGL_ATI_pixel_format_float", extStart, extEnd);
+ WGLEW_ATI_pixel_format_float = _glewSearchExtension("WGL_ATI_pixel_format_float", extStart, extEnd);
#endif /* WGL_ATI_pixel_format_float */
#ifdef WGL_ATI_render_texture_rectangle
- CONST_CAST(WGLEW_ATI_render_texture_rectangle) = _glewSearchExtension("WGL_ATI_render_texture_rectangle", extStart, extEnd);
+ WGLEW_ATI_render_texture_rectangle = _glewSearchExtension("WGL_ATI_render_texture_rectangle", extStart, extEnd);
#endif /* WGL_ATI_render_texture_rectangle */
#ifdef WGL_EXT_create_context_es2_profile
- CONST_CAST(WGLEW_EXT_create_context_es2_profile) = _glewSearchExtension("WGL_EXT_create_context_es2_profile", extStart, extEnd);
+ WGLEW_EXT_create_context_es2_profile = _glewSearchExtension("WGL_EXT_create_context_es2_profile", extStart, extEnd);
#endif /* WGL_EXT_create_context_es2_profile */
#ifdef WGL_EXT_create_context_es_profile
- CONST_CAST(WGLEW_EXT_create_context_es_profile) = _glewSearchExtension("WGL_EXT_create_context_es_profile", extStart, extEnd);
+ WGLEW_EXT_create_context_es_profile = _glewSearchExtension("WGL_EXT_create_context_es_profile", extStart, extEnd);
#endif /* WGL_EXT_create_context_es_profile */
#ifdef WGL_EXT_depth_float
- CONST_CAST(WGLEW_EXT_depth_float) = _glewSearchExtension("WGL_EXT_depth_float", extStart, extEnd);
+ WGLEW_EXT_depth_float = _glewSearchExtension("WGL_EXT_depth_float", extStart, extEnd);
#endif /* WGL_EXT_depth_float */
#ifdef WGL_EXT_display_color_table
- CONST_CAST(WGLEW_EXT_display_color_table) = _glewSearchExtension("WGL_EXT_display_color_table", extStart, extEnd);
- if (glewExperimental || WGLEW_EXT_display_color_table|| crippled) CONST_CAST(WGLEW_EXT_display_color_table)= !_glewInit_WGL_EXT_display_color_table(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_EXT_display_color_table = _glewSearchExtension("WGL_EXT_display_color_table", extStart, extEnd);
+ if (glewExperimental || WGLEW_EXT_display_color_table|| crippled) WGLEW_EXT_display_color_table= !_glewInit_WGL_EXT_display_color_table(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_EXT_display_color_table */
#ifdef WGL_EXT_extensions_string
- CONST_CAST(WGLEW_EXT_extensions_string) = _glewSearchExtension("WGL_EXT_extensions_string", extStart, extEnd);
- if (glewExperimental || WGLEW_EXT_extensions_string|| crippled) CONST_CAST(WGLEW_EXT_extensions_string)= !_glewInit_WGL_EXT_extensions_string(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_EXT_extensions_string = _glewSearchExtension("WGL_EXT_extensions_string", extStart, extEnd);
+ if (glewExperimental || WGLEW_EXT_extensions_string|| crippled) WGLEW_EXT_extensions_string= !_glewInit_WGL_EXT_extensions_string(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_EXT_extensions_string */
#ifdef WGL_EXT_framebuffer_sRGB
- CONST_CAST(WGLEW_EXT_framebuffer_sRGB) = _glewSearchExtension("WGL_EXT_framebuffer_sRGB", extStart, extEnd);
+ WGLEW_EXT_framebuffer_sRGB = _glewSearchExtension("WGL_EXT_framebuffer_sRGB", extStart, extEnd);
#endif /* WGL_EXT_framebuffer_sRGB */
#ifdef WGL_EXT_make_current_read
- CONST_CAST(WGLEW_EXT_make_current_read) = _glewSearchExtension("WGL_EXT_make_current_read", extStart, extEnd);
- if (glewExperimental || WGLEW_EXT_make_current_read|| crippled) CONST_CAST(WGLEW_EXT_make_current_read)= !_glewInit_WGL_EXT_make_current_read(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_EXT_make_current_read = _glewSearchExtension("WGL_EXT_make_current_read", extStart, extEnd);
+ if (glewExperimental || WGLEW_EXT_make_current_read|| crippled) WGLEW_EXT_make_current_read= !_glewInit_WGL_EXT_make_current_read(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_EXT_make_current_read */
#ifdef WGL_EXT_multisample
- CONST_CAST(WGLEW_EXT_multisample) = _glewSearchExtension("WGL_EXT_multisample", extStart, extEnd);
+ WGLEW_EXT_multisample = _glewSearchExtension("WGL_EXT_multisample", extStart, extEnd);
#endif /* WGL_EXT_multisample */
#ifdef WGL_EXT_pbuffer
- CONST_CAST(WGLEW_EXT_pbuffer) = _glewSearchExtension("WGL_EXT_pbuffer", extStart, extEnd);
- if (glewExperimental || WGLEW_EXT_pbuffer|| crippled) CONST_CAST(WGLEW_EXT_pbuffer)= !_glewInit_WGL_EXT_pbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_EXT_pbuffer = _glewSearchExtension("WGL_EXT_pbuffer", extStart, extEnd);
+ if (glewExperimental || WGLEW_EXT_pbuffer|| crippled) WGLEW_EXT_pbuffer= !_glewInit_WGL_EXT_pbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_EXT_pbuffer */
#ifdef WGL_EXT_pixel_format
- CONST_CAST(WGLEW_EXT_pixel_format) = _glewSearchExtension("WGL_EXT_pixel_format", extStart, extEnd);
- if (glewExperimental || WGLEW_EXT_pixel_format|| crippled) CONST_CAST(WGLEW_EXT_pixel_format)= !_glewInit_WGL_EXT_pixel_format(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_EXT_pixel_format = _glewSearchExtension("WGL_EXT_pixel_format", extStart, extEnd);
+ if (glewExperimental || WGLEW_EXT_pixel_format|| crippled) WGLEW_EXT_pixel_format= !_glewInit_WGL_EXT_pixel_format(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_EXT_pixel_format */
#ifdef WGL_EXT_pixel_format_packed_float
- CONST_CAST(WGLEW_EXT_pixel_format_packed_float) = _glewSearchExtension("WGL_EXT_pixel_format_packed_float", extStart, extEnd);
+ WGLEW_EXT_pixel_format_packed_float = _glewSearchExtension("WGL_EXT_pixel_format_packed_float", extStart, extEnd);
#endif /* WGL_EXT_pixel_format_packed_float */
#ifdef WGL_EXT_swap_control
- CONST_CAST(WGLEW_EXT_swap_control) = _glewSearchExtension("WGL_EXT_swap_control", extStart, extEnd);
- if (glewExperimental || WGLEW_EXT_swap_control|| crippled) CONST_CAST(WGLEW_EXT_swap_control)= !_glewInit_WGL_EXT_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_EXT_swap_control = _glewSearchExtension("WGL_EXT_swap_control", extStart, extEnd);
+ if (glewExperimental || WGLEW_EXT_swap_control|| crippled) WGLEW_EXT_swap_control= !_glewInit_WGL_EXT_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_EXT_swap_control */
#ifdef WGL_EXT_swap_control_tear
- CONST_CAST(WGLEW_EXT_swap_control_tear) = _glewSearchExtension("WGL_EXT_swap_control_tear", extStart, extEnd);
+ WGLEW_EXT_swap_control_tear = _glewSearchExtension("WGL_EXT_swap_control_tear", extStart, extEnd);
#endif /* WGL_EXT_swap_control_tear */
#ifdef WGL_I3D_digital_video_control
- CONST_CAST(WGLEW_I3D_digital_video_control) = _glewSearchExtension("WGL_I3D_digital_video_control", extStart, extEnd);
- if (glewExperimental || WGLEW_I3D_digital_video_control|| crippled) CONST_CAST(WGLEW_I3D_digital_video_control)= !_glewInit_WGL_I3D_digital_video_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_I3D_digital_video_control = _glewSearchExtension("WGL_I3D_digital_video_control", extStart, extEnd);
+ if (glewExperimental || WGLEW_I3D_digital_video_control|| crippled) WGLEW_I3D_digital_video_control= !_glewInit_WGL_I3D_digital_video_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_I3D_digital_video_control */
#ifdef WGL_I3D_gamma
- CONST_CAST(WGLEW_I3D_gamma) = _glewSearchExtension("WGL_I3D_gamma", extStart, extEnd);
- if (glewExperimental || WGLEW_I3D_gamma|| crippled) CONST_CAST(WGLEW_I3D_gamma)= !_glewInit_WGL_I3D_gamma(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_I3D_gamma = _glewSearchExtension("WGL_I3D_gamma", extStart, extEnd);
+ if (glewExperimental || WGLEW_I3D_gamma|| crippled) WGLEW_I3D_gamma= !_glewInit_WGL_I3D_gamma(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_I3D_gamma */
#ifdef WGL_I3D_genlock
- CONST_CAST(WGLEW_I3D_genlock) = _glewSearchExtension("WGL_I3D_genlock", extStart, extEnd);
- if (glewExperimental || WGLEW_I3D_genlock|| crippled) CONST_CAST(WGLEW_I3D_genlock)= !_glewInit_WGL_I3D_genlock(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_I3D_genlock = _glewSearchExtension("WGL_I3D_genlock", extStart, extEnd);
+ if (glewExperimental || WGLEW_I3D_genlock|| crippled) WGLEW_I3D_genlock= !_glewInit_WGL_I3D_genlock(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_I3D_genlock */
#ifdef WGL_I3D_image_buffer
- CONST_CAST(WGLEW_I3D_image_buffer) = _glewSearchExtension("WGL_I3D_image_buffer", extStart, extEnd);
- if (glewExperimental || WGLEW_I3D_image_buffer|| crippled) CONST_CAST(WGLEW_I3D_image_buffer)= !_glewInit_WGL_I3D_image_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_I3D_image_buffer = _glewSearchExtension("WGL_I3D_image_buffer", extStart, extEnd);
+ if (glewExperimental || WGLEW_I3D_image_buffer|| crippled) WGLEW_I3D_image_buffer= !_glewInit_WGL_I3D_image_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_I3D_image_buffer */
#ifdef WGL_I3D_swap_frame_lock
- CONST_CAST(WGLEW_I3D_swap_frame_lock) = _glewSearchExtension("WGL_I3D_swap_frame_lock", extStart, extEnd);
- if (glewExperimental || WGLEW_I3D_swap_frame_lock|| crippled) CONST_CAST(WGLEW_I3D_swap_frame_lock)= !_glewInit_WGL_I3D_swap_frame_lock(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_I3D_swap_frame_lock = _glewSearchExtension("WGL_I3D_swap_frame_lock", extStart, extEnd);
+ if (glewExperimental || WGLEW_I3D_swap_frame_lock|| crippled) WGLEW_I3D_swap_frame_lock= !_glewInit_WGL_I3D_swap_frame_lock(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_I3D_swap_frame_lock */
#ifdef WGL_I3D_swap_frame_usage
- CONST_CAST(WGLEW_I3D_swap_frame_usage) = _glewSearchExtension("WGL_I3D_swap_frame_usage", extStart, extEnd);
- if (glewExperimental || WGLEW_I3D_swap_frame_usage|| crippled) CONST_CAST(WGLEW_I3D_swap_frame_usage)= !_glewInit_WGL_I3D_swap_frame_usage(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_I3D_swap_frame_usage = _glewSearchExtension("WGL_I3D_swap_frame_usage", extStart, extEnd);
+ if (glewExperimental || WGLEW_I3D_swap_frame_usage|| crippled) WGLEW_I3D_swap_frame_usage= !_glewInit_WGL_I3D_swap_frame_usage(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_I3D_swap_frame_usage */
#ifdef WGL_NV_DX_interop
- CONST_CAST(WGLEW_NV_DX_interop) = _glewSearchExtension("WGL_NV_DX_interop", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_DX_interop|| crippled) CONST_CAST(WGLEW_NV_DX_interop)= !_glewInit_WGL_NV_DX_interop(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_DX_interop = _glewSearchExtension("WGL_NV_DX_interop", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_DX_interop|| crippled) WGLEW_NV_DX_interop= !_glewInit_WGL_NV_DX_interop(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_DX_interop */
#ifdef WGL_NV_DX_interop2
- CONST_CAST(WGLEW_NV_DX_interop2) = _glewSearchExtension("WGL_NV_DX_interop2", extStart, extEnd);
+ WGLEW_NV_DX_interop2 = _glewSearchExtension("WGL_NV_DX_interop2", extStart, extEnd);
#endif /* WGL_NV_DX_interop2 */
#ifdef WGL_NV_copy_image
- CONST_CAST(WGLEW_NV_copy_image) = _glewSearchExtension("WGL_NV_copy_image", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_copy_image|| crippled) CONST_CAST(WGLEW_NV_copy_image)= !_glewInit_WGL_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_copy_image = _glewSearchExtension("WGL_NV_copy_image", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_copy_image|| crippled) WGLEW_NV_copy_image= !_glewInit_WGL_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_copy_image */
+#ifdef WGL_NV_delay_before_swap
+ WGLEW_NV_delay_before_swap = _glewSearchExtension("WGL_NV_delay_before_swap", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_delay_before_swap|| crippled) WGLEW_NV_delay_before_swap= !_glewInit_WGL_NV_delay_before_swap(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* WGL_NV_delay_before_swap */
#ifdef WGL_NV_float_buffer
- CONST_CAST(WGLEW_NV_float_buffer) = _glewSearchExtension("WGL_NV_float_buffer", extStart, extEnd);
+ WGLEW_NV_float_buffer = _glewSearchExtension("WGL_NV_float_buffer", extStart, extEnd);
#endif /* WGL_NV_float_buffer */
#ifdef WGL_NV_gpu_affinity
- CONST_CAST(WGLEW_NV_gpu_affinity) = _glewSearchExtension("WGL_NV_gpu_affinity", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_gpu_affinity|| crippled) CONST_CAST(WGLEW_NV_gpu_affinity)= !_glewInit_WGL_NV_gpu_affinity(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_gpu_affinity = _glewSearchExtension("WGL_NV_gpu_affinity", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_gpu_affinity|| crippled) WGLEW_NV_gpu_affinity= !_glewInit_WGL_NV_gpu_affinity(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_gpu_affinity */
#ifdef WGL_NV_multisample_coverage
- CONST_CAST(WGLEW_NV_multisample_coverage) = _glewSearchExtension("WGL_NV_multisample_coverage", extStart, extEnd);
+ WGLEW_NV_multisample_coverage = _glewSearchExtension("WGL_NV_multisample_coverage", extStart, extEnd);
#endif /* WGL_NV_multisample_coverage */
#ifdef WGL_NV_present_video
- CONST_CAST(WGLEW_NV_present_video) = _glewSearchExtension("WGL_NV_present_video", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_present_video|| crippled) CONST_CAST(WGLEW_NV_present_video)= !_glewInit_WGL_NV_present_video(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_present_video = _glewSearchExtension("WGL_NV_present_video", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_present_video|| crippled) WGLEW_NV_present_video= !_glewInit_WGL_NV_present_video(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_present_video */
#ifdef WGL_NV_render_depth_texture
- CONST_CAST(WGLEW_NV_render_depth_texture) = _glewSearchExtension("WGL_NV_render_depth_texture", extStart, extEnd);
+ WGLEW_NV_render_depth_texture = _glewSearchExtension("WGL_NV_render_depth_texture", extStart, extEnd);
#endif /* WGL_NV_render_depth_texture */
#ifdef WGL_NV_render_texture_rectangle
- CONST_CAST(WGLEW_NV_render_texture_rectangle) = _glewSearchExtension("WGL_NV_render_texture_rectangle", extStart, extEnd);
+ WGLEW_NV_render_texture_rectangle = _glewSearchExtension("WGL_NV_render_texture_rectangle", extStart, extEnd);
#endif /* WGL_NV_render_texture_rectangle */
#ifdef WGL_NV_swap_group
- CONST_CAST(WGLEW_NV_swap_group) = _glewSearchExtension("WGL_NV_swap_group", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_swap_group|| crippled) CONST_CAST(WGLEW_NV_swap_group)= !_glewInit_WGL_NV_swap_group(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_swap_group = _glewSearchExtension("WGL_NV_swap_group", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_swap_group|| crippled) WGLEW_NV_swap_group= !_glewInit_WGL_NV_swap_group(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_swap_group */
#ifdef WGL_NV_vertex_array_range
- CONST_CAST(WGLEW_NV_vertex_array_range) = _glewSearchExtension("WGL_NV_vertex_array_range", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_vertex_array_range|| crippled) CONST_CAST(WGLEW_NV_vertex_array_range)= !_glewInit_WGL_NV_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_vertex_array_range = _glewSearchExtension("WGL_NV_vertex_array_range", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_vertex_array_range|| crippled) WGLEW_NV_vertex_array_range= !_glewInit_WGL_NV_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_vertex_array_range */
#ifdef WGL_NV_video_capture
- CONST_CAST(WGLEW_NV_video_capture) = _glewSearchExtension("WGL_NV_video_capture", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_video_capture|| crippled) CONST_CAST(WGLEW_NV_video_capture)= !_glewInit_WGL_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_video_capture = _glewSearchExtension("WGL_NV_video_capture", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_video_capture|| crippled) WGLEW_NV_video_capture= !_glewInit_WGL_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_video_capture */
#ifdef WGL_NV_video_output
- CONST_CAST(WGLEW_NV_video_output) = _glewSearchExtension("WGL_NV_video_output", extStart, extEnd);
- if (glewExperimental || WGLEW_NV_video_output|| crippled) CONST_CAST(WGLEW_NV_video_output)= !_glewInit_WGL_NV_video_output(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_NV_video_output = _glewSearchExtension("WGL_NV_video_output", extStart, extEnd);
+ if (glewExperimental || WGLEW_NV_video_output|| crippled) WGLEW_NV_video_output= !_glewInit_WGL_NV_video_output(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_NV_video_output */
#ifdef WGL_OML_sync_control
- CONST_CAST(WGLEW_OML_sync_control) = _glewSearchExtension("WGL_OML_sync_control", extStart, extEnd);
- if (glewExperimental || WGLEW_OML_sync_control|| crippled) CONST_CAST(WGLEW_OML_sync_control)= !_glewInit_WGL_OML_sync_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ WGLEW_OML_sync_control = _glewSearchExtension("WGL_OML_sync_control", extStart, extEnd);
+ if (glewExperimental || WGLEW_OML_sync_control|| crippled) WGLEW_OML_sync_control= !_glewInit_WGL_OML_sync_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* WGL_OML_sync_control */
return GLEW_OK;
}
-#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
+#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
PFNGLXGETCURRENTDISPLAYPROC __glewXGetCurrentDisplay = NULL;
@@ -12378,6 +12359,11 @@ PFNGLXCOPYSUBBUFFERMESAPROC __glewXCopySubBufferMESA = NULL;
PFNGLXCREATEGLXPIXMAPMESAPROC __glewXCreateGLXPixmapMESA = NULL;
+PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC __glewXQueryCurrentRendererIntegerMESA = NULL;
+PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC __glewXQueryCurrentRendererStringMESA = NULL;
+PFNGLXQUERYRENDERERINTEGERMESAPROC __glewXQueryRendererIntegerMESA = NULL;
+PFNGLXQUERYRENDERERSTRINGMESAPROC __glewXQueryRendererStringMESA = NULL;
+
PFNGLXRELEASEBUFFERSMESAPROC __glewXReleaseBuffersMESA = NULL;
PFNGLXSET3DFXMODEMESAPROC __glewXSet3DfxModeMESA = NULL;
@@ -12385,8 +12371,13 @@ PFNGLXSET3DFXMODEMESAPROC __glewXSet3DfxModeMESA = NULL;
PFNGLXGETSWAPINTERVALMESAPROC __glewXGetSwapIntervalMESA = NULL;
PFNGLXSWAPINTERVALMESAPROC __glewXSwapIntervalMESA = NULL;
+PFNGLXCOPYBUFFERSUBDATANVPROC __glewXCopyBufferSubDataNV = NULL;
+PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC __glewXNamedCopyBufferSubDataNV = NULL;
+
PFNGLXCOPYIMAGESUBDATANVPROC __glewXCopyImageSubDataNV = NULL;
+PFNGLXDELAYBEFORESWAPNVPROC __glewXDelayBeforeSwapNV = NULL;
+
PFNGLXBINDVIDEODEVICENVPROC __glewXBindVideoDeviceNV = NULL;
PFNGLXENUMERATEVIDEODEVICESNVPROC __glewXEnumerateVideoDevicesNV = NULL;
@@ -12476,6 +12467,7 @@ GLboolean __GLXEW_VERSION_1_3 = GL_FALSE;
GLboolean __GLXEW_VERSION_1_4 = GL_FALSE;
GLboolean __GLXEW_3DFX_multisample = GL_FALSE;
GLboolean __GLXEW_AMD_gpu_association = GL_FALSE;
+GLboolean __GLXEW_ARB_context_flush_control = GL_FALSE;
GLboolean __GLXEW_ARB_create_context = GL_FALSE;
GLboolean __GLXEW_ARB_create_context_profile = GL_FALSE;
GLboolean __GLXEW_ARB_create_context_robustness = GL_FALSE;
@@ -12495,6 +12487,7 @@ GLboolean __GLXEW_EXT_fbconfig_packed_float = GL_FALSE;
GLboolean __GLXEW_EXT_framebuffer_sRGB = GL_FALSE;
GLboolean __GLXEW_EXT_import_context = GL_FALSE;
GLboolean __GLXEW_EXT_scene_marker = GL_FALSE;
+GLboolean __GLXEW_EXT_stereo_tree = GL_FALSE;
GLboolean __GLXEW_EXT_swap_control = GL_FALSE;
GLboolean __GLXEW_EXT_swap_control_tear = GL_FALSE;
GLboolean __GLXEW_EXT_texture_from_pixmap = GL_FALSE;
@@ -12504,17 +12497,20 @@ GLboolean __GLXEW_INTEL_swap_event = GL_FALSE;
GLboolean __GLXEW_MESA_agp_offset = GL_FALSE;
GLboolean __GLXEW_MESA_copy_sub_buffer = GL_FALSE;
GLboolean __GLXEW_MESA_pixmap_colormap = GL_FALSE;
+GLboolean __GLXEW_MESA_query_renderer = GL_FALSE;
GLboolean __GLXEW_MESA_release_buffers = GL_FALSE;
GLboolean __GLXEW_MESA_set_3dfx_mode = GL_FALSE;
GLboolean __GLXEW_MESA_swap_control = GL_FALSE;
+GLboolean __GLXEW_NV_copy_buffer = GL_FALSE;
GLboolean __GLXEW_NV_copy_image = GL_FALSE;
+GLboolean __GLXEW_NV_delay_before_swap = GL_FALSE;
GLboolean __GLXEW_NV_float_buffer = GL_FALSE;
GLboolean __GLXEW_NV_multisample_coverage = GL_FALSE;
GLboolean __GLXEW_NV_present_video = GL_FALSE;
GLboolean __GLXEW_NV_swap_group = GL_FALSE;
GLboolean __GLXEW_NV_vertex_array_range = GL_FALSE;
GLboolean __GLXEW_NV_video_capture = GL_FALSE;
-GLboolean __GLXEW_NV_video_output = GL_FALSE;
+GLboolean __GLXEW_NV_video_out = GL_FALSE;
GLboolean __GLXEW_OML_swap_method = GL_FALSE;
GLboolean __GLXEW_OML_sync_control = GL_FALSE;
GLboolean __GLXEW_SGIS_blended_overlay = GL_FALSE;
@@ -12579,14 +12575,6 @@ static GLboolean _glewInit_GLX_VERSION_1_3 (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_VERSION_1_3 */
-#ifdef GLX_VERSION_1_4
-
-#endif /* GLX_VERSION_1_4 */
-
-#ifdef GLX_3DFX_multisample
-
-#endif /* GLX_3DFX_multisample */
-
#ifdef GLX_AMD_gpu_association
static GLboolean _glewInit_GLX_AMD_gpu_association (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12621,46 +12609,6 @@ static GLboolean _glewInit_GLX_ARB_create_context (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_ARB_create_context */
-#ifdef GLX_ARB_create_context_profile
-
-#endif /* GLX_ARB_create_context_profile */
-
-#ifdef GLX_ARB_create_context_robustness
-
-#endif /* GLX_ARB_create_context_robustness */
-
-#ifdef GLX_ARB_fbconfig_float
-
-#endif /* GLX_ARB_fbconfig_float */
-
-#ifdef GLX_ARB_framebuffer_sRGB
-
-#endif /* GLX_ARB_framebuffer_sRGB */
-
-#ifdef GLX_ARB_get_proc_address
-
-#endif /* GLX_ARB_get_proc_address */
-
-#ifdef GLX_ARB_multisample
-
-#endif /* GLX_ARB_multisample */
-
-#ifdef GLX_ARB_robustness_application_isolation
-
-#endif /* GLX_ARB_robustness_application_isolation */
-
-#ifdef GLX_ARB_robustness_share_group_isolation
-
-#endif /* GLX_ARB_robustness_share_group_isolation */
-
-#ifdef GLX_ARB_vertex_buffer_object
-
-#endif /* GLX_ARB_vertex_buffer_object */
-
-#ifdef GLX_ATI_pixel_format_float
-
-#endif /* GLX_ATI_pixel_format_float */
-
#ifdef GLX_ATI_render_texture
static GLboolean _glewInit_GLX_ATI_render_texture (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12676,26 +12624,6 @@ static GLboolean _glewInit_GLX_ATI_render_texture (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_ATI_render_texture */
-#ifdef GLX_EXT_buffer_age
-
-#endif /* GLX_EXT_buffer_age */
-
-#ifdef GLX_EXT_create_context_es2_profile
-
-#endif /* GLX_EXT_create_context_es2_profile */
-
-#ifdef GLX_EXT_create_context_es_profile
-
-#endif /* GLX_EXT_create_context_es_profile */
-
-#ifdef GLX_EXT_fbconfig_packed_float
-
-#endif /* GLX_EXT_fbconfig_packed_float */
-
-#ifdef GLX_EXT_framebuffer_sRGB
-
-#endif /* GLX_EXT_framebuffer_sRGB */
-
#ifdef GLX_EXT_import_context
static GLboolean _glewInit_GLX_EXT_import_context (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12712,10 +12640,6 @@ static GLboolean _glewInit_GLX_EXT_import_context (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_EXT_import_context */
-#ifdef GLX_EXT_scene_marker
-
-#endif /* GLX_EXT_scene_marker */
-
#ifdef GLX_EXT_swap_control
static GLboolean _glewInit_GLX_EXT_swap_control (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12729,10 +12653,6 @@ static GLboolean _glewInit_GLX_EXT_swap_control (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_EXT_swap_control */
-#ifdef GLX_EXT_swap_control_tear
-
-#endif /* GLX_EXT_swap_control_tear */
-
#ifdef GLX_EXT_texture_from_pixmap
static GLboolean _glewInit_GLX_EXT_texture_from_pixmap (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12747,18 +12667,6 @@ static GLboolean _glewInit_GLX_EXT_texture_from_pixmap (GLXEW_CONTEXT_ARG_DEF_IN
#endif /* GLX_EXT_texture_from_pixmap */
-#ifdef GLX_EXT_visual_info
-
-#endif /* GLX_EXT_visual_info */
-
-#ifdef GLX_EXT_visual_rating
-
-#endif /* GLX_EXT_visual_rating */
-
-#ifdef GLX_INTEL_swap_event
-
-#endif /* GLX_INTEL_swap_event */
-
#ifdef GLX_MESA_agp_offset
static GLboolean _glewInit_GLX_MESA_agp_offset (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12798,6 +12706,22 @@ static GLboolean _glewInit_GLX_MESA_pixmap_colormap (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_MESA_pixmap_colormap */
+#ifdef GLX_MESA_query_renderer
+
+static GLboolean _glewInit_GLX_MESA_query_renderer (GLXEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glXQueryCurrentRendererIntegerMESA = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC)glewGetProcAddress((const GLubyte*)"glXQueryCurrentRendererIntegerMESA")) == NULL) || r;
+ r = ((glXQueryCurrentRendererStringMESA = (PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC)glewGetProcAddress((const GLubyte*)"glXQueryCurrentRendererStringMESA")) == NULL) || r;
+ r = ((glXQueryRendererIntegerMESA = (PFNGLXQUERYRENDERERINTEGERMESAPROC)glewGetProcAddress((const GLubyte*)"glXQueryRendererIntegerMESA")) == NULL) || r;
+ r = ((glXQueryRendererStringMESA = (PFNGLXQUERYRENDERERSTRINGMESAPROC)glewGetProcAddress((const GLubyte*)"glXQueryRendererStringMESA")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GLX_MESA_query_renderer */
+
#ifdef GLX_MESA_release_buffers
static GLboolean _glewInit_GLX_MESA_release_buffers (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12838,6 +12762,20 @@ static GLboolean _glewInit_GLX_MESA_swap_control (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_MESA_swap_control */
+#ifdef GLX_NV_copy_buffer
+
+static GLboolean _glewInit_GLX_NV_copy_buffer (GLXEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
+
+ r = ((glXCopyBufferSubDataNV = (PFNGLXCOPYBUFFERSUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glXCopyBufferSubDataNV")) == NULL) || r;
+ r = ((glXNamedCopyBufferSubDataNV = (PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC)glewGetProcAddress((const GLubyte*)"glXNamedCopyBufferSubDataNV")) == NULL) || r;
+
+ return r;
+}
+
+#endif /* GLX_NV_copy_buffer */
+
#ifdef GLX_NV_copy_image
static GLboolean _glewInit_GLX_NV_copy_image (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -12851,13 +12789,18 @@ static GLboolean _glewInit_GLX_NV_copy_image (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_NV_copy_image */
-#ifdef GLX_NV_float_buffer
+#ifdef GLX_NV_delay_before_swap
-#endif /* GLX_NV_float_buffer */
+static GLboolean _glewInit_GLX_NV_delay_before_swap (GLXEW_CONTEXT_ARG_DEF_INIT)
+{
+ GLboolean r = GL_FALSE;
-#ifdef GLX_NV_multisample_coverage
+ r = ((glXDelayBeforeSwapNV = (PFNGLXDELAYBEFORESWAPNVPROC)glewGetProcAddress((const GLubyte*)"glXDelayBeforeSwapNV")) == NULL) || r;
-#endif /* GLX_NV_multisample_coverage */
+ return r;
+}
+
+#endif /* GLX_NV_delay_before_swap */
#ifdef GLX_NV_present_video
@@ -12922,9 +12865,9 @@ static GLboolean _glewInit_GLX_NV_video_capture (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_NV_video_capture */
-#ifdef GLX_NV_video_output
+#ifdef GLX_NV_video_out
-static GLboolean _glewInit_GLX_NV_video_output (GLXEW_CONTEXT_ARG_DEF_INIT)
+static GLboolean _glewInit_GLX_NV_video_out (GLXEW_CONTEXT_ARG_DEF_INIT)
{
GLboolean r = GL_FALSE;
@@ -12938,11 +12881,7 @@ static GLboolean _glewInit_GLX_NV_video_output (GLXEW_CONTEXT_ARG_DEF_INIT)
return r;
}
-#endif /* GLX_NV_video_output */
-
-#ifdef GLX_OML_swap_method
-
-#endif /* GLX_OML_swap_method */
+#endif /* GLX_NV_video_out */
#ifdef GLX_OML_sync_control
@@ -12961,22 +12900,6 @@ static GLboolean _glewInit_GLX_OML_sync_control (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_OML_sync_control */
-#ifdef GLX_SGIS_blended_overlay
-
-#endif /* GLX_SGIS_blended_overlay */
-
-#ifdef GLX_SGIS_color_range
-
-#endif /* GLX_SGIS_color_range */
-
-#ifdef GLX_SGIS_multisample
-
-#endif /* GLX_SGIS_multisample */
-
-#ifdef GLX_SGIS_shared_multisample
-
-#endif /* GLX_SGIS_shared_multisample */
-
#ifdef GLX_SGIX_fbconfig
static GLboolean _glewInit_GLX_SGIX_fbconfig (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -13076,10 +12999,6 @@ static GLboolean _glewInit_GLX_SGIX_video_resize (GLXEW_CONTEXT_ARG_DEF_INIT)
#endif /* GLX_SGIX_video_resize */
-#ifdef GLX_SGIX_visual_select_group
-
-#endif /* GLX_SGIX_visual_select_group */
-
#ifdef GLX_SGI_cushion
static GLboolean _glewInit_GLX_SGI_cushion (GLXEW_CONTEXT_ARG_DEF_INIT)
@@ -13175,7 +13094,11 @@ GLboolean glxewGetExtension (const char* name)
return _glewSearchExtension(name, start, end);
}
+#ifdef GLEW_MX
GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
+#else
+GLenum glxewInit (GLXEW_CONTEXT_ARG_DEF_LIST)
+#endif
{
int major, minor;
const GLubyte* extStart;
@@ -13183,11 +13106,11 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
/* initialize core GLX 1.2 */
if (_glewInit_GLX_VERSION_1_2(GLEW_CONTEXT_ARG_VAR_INIT)) return GLEW_ERROR_GLX_VERSION_11_ONLY;
/* initialize flags */
- CONST_CAST(GLXEW_VERSION_1_0) = GL_TRUE;
- CONST_CAST(GLXEW_VERSION_1_1) = GL_TRUE;
- CONST_CAST(GLXEW_VERSION_1_2) = GL_TRUE;
- CONST_CAST(GLXEW_VERSION_1_3) = GL_TRUE;
- CONST_CAST(GLXEW_VERSION_1_4) = GL_TRUE;
+ GLXEW_VERSION_1_0 = GL_TRUE;
+ GLXEW_VERSION_1_1 = GL_TRUE;
+ GLXEW_VERSION_1_2 = GL_TRUE;
+ GLXEW_VERSION_1_3 = GL_TRUE;
+ GLXEW_VERSION_1_4 = GL_TRUE;
/* query GLX version */
glXQueryVersion(glXGetCurrentDisplay(), &major, &minor);
if (major == 1 && minor <= 3)
@@ -13195,11 +13118,11 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
switch (minor)
{
case 3:
- CONST_CAST(GLXEW_VERSION_1_4) = GL_FALSE;
+ GLXEW_VERSION_1_4 = GL_FALSE;
break;
case 2:
- CONST_CAST(GLXEW_VERSION_1_4) = GL_FALSE;
- CONST_CAST(GLXEW_VERSION_1_3) = GL_FALSE;
+ GLXEW_VERSION_1_4 = GL_FALSE;
+ GLXEW_VERSION_1_3 = GL_FALSE;
break;
default:
return GLEW_ERROR_GLX_VERSION_11_ONLY;
@@ -13215,224 +13138,242 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
extEnd = extStart + _glewStrLen(extStart);
/* initialize extensions */
#ifdef GLX_VERSION_1_3
- if (glewExperimental || GLXEW_VERSION_1_3) CONST_CAST(GLXEW_VERSION_1_3) = !_glewInit_GLX_VERSION_1_3(GLEW_CONTEXT_ARG_VAR_INIT);
+ if (glewExperimental || GLXEW_VERSION_1_3) GLXEW_VERSION_1_3 = !_glewInit_GLX_VERSION_1_3(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_VERSION_1_3 */
#ifdef GLX_3DFX_multisample
- CONST_CAST(GLXEW_3DFX_multisample) = _glewSearchExtension("GLX_3DFX_multisample", extStart, extEnd);
+ GLXEW_3DFX_multisample = _glewSearchExtension("GLX_3DFX_multisample", extStart, extEnd);
#endif /* GLX_3DFX_multisample */
#ifdef GLX_AMD_gpu_association
- CONST_CAST(GLXEW_AMD_gpu_association) = _glewSearchExtension("GLX_AMD_gpu_association", extStart, extEnd);
- if (glewExperimental || GLXEW_AMD_gpu_association) CONST_CAST(GLXEW_AMD_gpu_association) = !_glewInit_GLX_AMD_gpu_association(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_AMD_gpu_association = _glewSearchExtension("GLX_AMD_gpu_association", extStart, extEnd);
+ if (glewExperimental || GLXEW_AMD_gpu_association) GLXEW_AMD_gpu_association = !_glewInit_GLX_AMD_gpu_association(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_AMD_gpu_association */
+#ifdef GLX_ARB_context_flush_control
+ GLXEW_ARB_context_flush_control = _glewSearchExtension("GLX_ARB_context_flush_control", extStart, extEnd);
+#endif /* GLX_ARB_context_flush_control */
#ifdef GLX_ARB_create_context
- CONST_CAST(GLXEW_ARB_create_context) = _glewSearchExtension("GLX_ARB_create_context", extStart, extEnd);
- if (glewExperimental || GLXEW_ARB_create_context) CONST_CAST(GLXEW_ARB_create_context) = !_glewInit_GLX_ARB_create_context(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_ARB_create_context = _glewSearchExtension("GLX_ARB_create_context", extStart, extEnd);
+ if (glewExperimental || GLXEW_ARB_create_context) GLXEW_ARB_create_context = !_glewInit_GLX_ARB_create_context(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_ARB_create_context */
#ifdef GLX_ARB_create_context_profile
- CONST_CAST(GLXEW_ARB_create_context_profile) = _glewSearchExtension("GLX_ARB_create_context_profile", extStart, extEnd);
+ GLXEW_ARB_create_context_profile = _glewSearchExtension("GLX_ARB_create_context_profile", extStart, extEnd);
#endif /* GLX_ARB_create_context_profile */
#ifdef GLX_ARB_create_context_robustness
- CONST_CAST(GLXEW_ARB_create_context_robustness) = _glewSearchExtension("GLX_ARB_create_context_robustness", extStart, extEnd);
+ GLXEW_ARB_create_context_robustness = _glewSearchExtension("GLX_ARB_create_context_robustness", extStart, extEnd);
#endif /* GLX_ARB_create_context_robustness */
#ifdef GLX_ARB_fbconfig_float
- CONST_CAST(GLXEW_ARB_fbconfig_float) = _glewSearchExtension("GLX_ARB_fbconfig_float", extStart, extEnd);
+ GLXEW_ARB_fbconfig_float = _glewSearchExtension("GLX_ARB_fbconfig_float", extStart, extEnd);
#endif /* GLX_ARB_fbconfig_float */
#ifdef GLX_ARB_framebuffer_sRGB
- CONST_CAST(GLXEW_ARB_framebuffer_sRGB) = _glewSearchExtension("GLX_ARB_framebuffer_sRGB", extStart, extEnd);
+ GLXEW_ARB_framebuffer_sRGB = _glewSearchExtension("GLX_ARB_framebuffer_sRGB", extStart, extEnd);
#endif /* GLX_ARB_framebuffer_sRGB */
#ifdef GLX_ARB_get_proc_address
- CONST_CAST(GLXEW_ARB_get_proc_address) = _glewSearchExtension("GLX_ARB_get_proc_address", extStart, extEnd);
+ GLXEW_ARB_get_proc_address = _glewSearchExtension("GLX_ARB_get_proc_address", extStart, extEnd);
#endif /* GLX_ARB_get_proc_address */
#ifdef GLX_ARB_multisample
- CONST_CAST(GLXEW_ARB_multisample) = _glewSearchExtension("GLX_ARB_multisample", extStart, extEnd);
+ GLXEW_ARB_multisample = _glewSearchExtension("GLX_ARB_multisample", extStart, extEnd);
#endif /* GLX_ARB_multisample */
#ifdef GLX_ARB_robustness_application_isolation
- CONST_CAST(GLXEW_ARB_robustness_application_isolation) = _glewSearchExtension("GLX_ARB_robustness_application_isolation", extStart, extEnd);
+ GLXEW_ARB_robustness_application_isolation = _glewSearchExtension("GLX_ARB_robustness_application_isolation", extStart, extEnd);
#endif /* GLX_ARB_robustness_application_isolation */
#ifdef GLX_ARB_robustness_share_group_isolation
- CONST_CAST(GLXEW_ARB_robustness_share_group_isolation) = _glewSearchExtension("GLX_ARB_robustness_share_group_isolation", extStart, extEnd);
+ GLXEW_ARB_robustness_share_group_isolation = _glewSearchExtension("GLX_ARB_robustness_share_group_isolation", extStart, extEnd);
#endif /* GLX_ARB_robustness_share_group_isolation */
#ifdef GLX_ARB_vertex_buffer_object
- CONST_CAST(GLXEW_ARB_vertex_buffer_object) = _glewSearchExtension("GLX_ARB_vertex_buffer_object", extStart, extEnd);
+ GLXEW_ARB_vertex_buffer_object = _glewSearchExtension("GLX_ARB_vertex_buffer_object", extStart, extEnd);
#endif /* GLX_ARB_vertex_buffer_object */
#ifdef GLX_ATI_pixel_format_float
- CONST_CAST(GLXEW_ATI_pixel_format_float) = _glewSearchExtension("GLX_ATI_pixel_format_float", extStart, extEnd);
+ GLXEW_ATI_pixel_format_float = _glewSearchExtension("GLX_ATI_pixel_format_float", extStart, extEnd);
#endif /* GLX_ATI_pixel_format_float */
#ifdef GLX_ATI_render_texture
- CONST_CAST(GLXEW_ATI_render_texture) = _glewSearchExtension("GLX_ATI_render_texture", extStart, extEnd);
- if (glewExperimental || GLXEW_ATI_render_texture) CONST_CAST(GLXEW_ATI_render_texture) = !_glewInit_GLX_ATI_render_texture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_ATI_render_texture = _glewSearchExtension("GLX_ATI_render_texture", extStart, extEnd);
+ if (glewExperimental || GLXEW_ATI_render_texture) GLXEW_ATI_render_texture = !_glewInit_GLX_ATI_render_texture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_ATI_render_texture */
#ifdef GLX_EXT_buffer_age
- CONST_CAST(GLXEW_EXT_buffer_age) = _glewSearchExtension("GLX_EXT_buffer_age", extStart, extEnd);
+ GLXEW_EXT_buffer_age = _glewSearchExtension("GLX_EXT_buffer_age", extStart, extEnd);
#endif /* GLX_EXT_buffer_age */
#ifdef GLX_EXT_create_context_es2_profile
- CONST_CAST(GLXEW_EXT_create_context_es2_profile) = _glewSearchExtension("GLX_EXT_create_context_es2_profile", extStart, extEnd);
+ GLXEW_EXT_create_context_es2_profile = _glewSearchExtension("GLX_EXT_create_context_es2_profile", extStart, extEnd);
#endif /* GLX_EXT_create_context_es2_profile */
#ifdef GLX_EXT_create_context_es_profile
- CONST_CAST(GLXEW_EXT_create_context_es_profile) = _glewSearchExtension("GLX_EXT_create_context_es_profile", extStart, extEnd);
+ GLXEW_EXT_create_context_es_profile = _glewSearchExtension("GLX_EXT_create_context_es_profile", extStart, extEnd);
#endif /* GLX_EXT_create_context_es_profile */
#ifdef GLX_EXT_fbconfig_packed_float
- CONST_CAST(GLXEW_EXT_fbconfig_packed_float) = _glewSearchExtension("GLX_EXT_fbconfig_packed_float", extStart, extEnd);
+ GLXEW_EXT_fbconfig_packed_float = _glewSearchExtension("GLX_EXT_fbconfig_packed_float", extStart, extEnd);
#endif /* GLX_EXT_fbconfig_packed_float */
#ifdef GLX_EXT_framebuffer_sRGB
- CONST_CAST(GLXEW_EXT_framebuffer_sRGB) = _glewSearchExtension("GLX_EXT_framebuffer_sRGB", extStart, extEnd);
+ GLXEW_EXT_framebuffer_sRGB = _glewSearchExtension("GLX_EXT_framebuffer_sRGB", extStart, extEnd);
#endif /* GLX_EXT_framebuffer_sRGB */
#ifdef GLX_EXT_import_context
- CONST_CAST(GLXEW_EXT_import_context) = _glewSearchExtension("GLX_EXT_import_context", extStart, extEnd);
- if (glewExperimental || GLXEW_EXT_import_context) CONST_CAST(GLXEW_EXT_import_context) = !_glewInit_GLX_EXT_import_context(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_EXT_import_context = _glewSearchExtension("GLX_EXT_import_context", extStart, extEnd);
+ if (glewExperimental || GLXEW_EXT_import_context) GLXEW_EXT_import_context = !_glewInit_GLX_EXT_import_context(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_EXT_import_context */
#ifdef GLX_EXT_scene_marker
- CONST_CAST(GLXEW_EXT_scene_marker) = _glewSearchExtension("GLX_EXT_scene_marker", extStart, extEnd);
+ GLXEW_EXT_scene_marker = _glewSearchExtension("GLX_EXT_scene_marker", extStart, extEnd);
#endif /* GLX_EXT_scene_marker */
+#ifdef GLX_EXT_stereo_tree
+ GLXEW_EXT_stereo_tree = _glewSearchExtension("GLX_EXT_stereo_tree", extStart, extEnd);
+#endif /* GLX_EXT_stereo_tree */
#ifdef GLX_EXT_swap_control
- CONST_CAST(GLXEW_EXT_swap_control) = _glewSearchExtension("GLX_EXT_swap_control", extStart, extEnd);
- if (glewExperimental || GLXEW_EXT_swap_control) CONST_CAST(GLXEW_EXT_swap_control) = !_glewInit_GLX_EXT_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_EXT_swap_control = _glewSearchExtension("GLX_EXT_swap_control", extStart, extEnd);
+ if (glewExperimental || GLXEW_EXT_swap_control) GLXEW_EXT_swap_control = !_glewInit_GLX_EXT_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_EXT_swap_control */
#ifdef GLX_EXT_swap_control_tear
- CONST_CAST(GLXEW_EXT_swap_control_tear) = _glewSearchExtension("GLX_EXT_swap_control_tear", extStart, extEnd);
+ GLXEW_EXT_swap_control_tear = _glewSearchExtension("GLX_EXT_swap_control_tear", extStart, extEnd);
#endif /* GLX_EXT_swap_control_tear */
#ifdef GLX_EXT_texture_from_pixmap
- CONST_CAST(GLXEW_EXT_texture_from_pixmap) = _glewSearchExtension("GLX_EXT_texture_from_pixmap", extStart, extEnd);
- if (glewExperimental || GLXEW_EXT_texture_from_pixmap) CONST_CAST(GLXEW_EXT_texture_from_pixmap) = !_glewInit_GLX_EXT_texture_from_pixmap(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_EXT_texture_from_pixmap = _glewSearchExtension("GLX_EXT_texture_from_pixmap", extStart, extEnd);
+ if (glewExperimental || GLXEW_EXT_texture_from_pixmap) GLXEW_EXT_texture_from_pixmap = !_glewInit_GLX_EXT_texture_from_pixmap(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_EXT_texture_from_pixmap */
#ifdef GLX_EXT_visual_info
- CONST_CAST(GLXEW_EXT_visual_info) = _glewSearchExtension("GLX_EXT_visual_info", extStart, extEnd);
+ GLXEW_EXT_visual_info = _glewSearchExtension("GLX_EXT_visual_info", extStart, extEnd);
#endif /* GLX_EXT_visual_info */
#ifdef GLX_EXT_visual_rating
- CONST_CAST(GLXEW_EXT_visual_rating) = _glewSearchExtension("GLX_EXT_visual_rating", extStart, extEnd);
+ GLXEW_EXT_visual_rating = _glewSearchExtension("GLX_EXT_visual_rating", extStart, extEnd);
#endif /* GLX_EXT_visual_rating */
#ifdef GLX_INTEL_swap_event
- CONST_CAST(GLXEW_INTEL_swap_event) = _glewSearchExtension("GLX_INTEL_swap_event", extStart, extEnd);
+ GLXEW_INTEL_swap_event = _glewSearchExtension("GLX_INTEL_swap_event", extStart, extEnd);
#endif /* GLX_INTEL_swap_event */
#ifdef GLX_MESA_agp_offset
- CONST_CAST(GLXEW_MESA_agp_offset) = _glewSearchExtension("GLX_MESA_agp_offset", extStart, extEnd);
- if (glewExperimental || GLXEW_MESA_agp_offset) CONST_CAST(GLXEW_MESA_agp_offset) = !_glewInit_GLX_MESA_agp_offset(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_MESA_agp_offset = _glewSearchExtension("GLX_MESA_agp_offset", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_agp_offset) GLXEW_MESA_agp_offset = !_glewInit_GLX_MESA_agp_offset(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_MESA_agp_offset */
#ifdef GLX_MESA_copy_sub_buffer
- CONST_CAST(GLXEW_MESA_copy_sub_buffer) = _glewSearchExtension("GLX_MESA_copy_sub_buffer", extStart, extEnd);
- if (glewExperimental || GLXEW_MESA_copy_sub_buffer) CONST_CAST(GLXEW_MESA_copy_sub_buffer) = !_glewInit_GLX_MESA_copy_sub_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_MESA_copy_sub_buffer = _glewSearchExtension("GLX_MESA_copy_sub_buffer", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_copy_sub_buffer) GLXEW_MESA_copy_sub_buffer = !_glewInit_GLX_MESA_copy_sub_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_MESA_copy_sub_buffer */
#ifdef GLX_MESA_pixmap_colormap
- CONST_CAST(GLXEW_MESA_pixmap_colormap) = _glewSearchExtension("GLX_MESA_pixmap_colormap", extStart, extEnd);
- if (glewExperimental || GLXEW_MESA_pixmap_colormap) CONST_CAST(GLXEW_MESA_pixmap_colormap) = !_glewInit_GLX_MESA_pixmap_colormap(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_MESA_pixmap_colormap = _glewSearchExtension("GLX_MESA_pixmap_colormap", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_pixmap_colormap) GLXEW_MESA_pixmap_colormap = !_glewInit_GLX_MESA_pixmap_colormap(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_MESA_pixmap_colormap */
+#ifdef GLX_MESA_query_renderer
+ GLXEW_MESA_query_renderer = _glewSearchExtension("GLX_MESA_query_renderer", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_query_renderer) GLXEW_MESA_query_renderer = !_glewInit_GLX_MESA_query_renderer(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GLX_MESA_query_renderer */
#ifdef GLX_MESA_release_buffers
- CONST_CAST(GLXEW_MESA_release_buffers) = _glewSearchExtension("GLX_MESA_release_buffers", extStart, extEnd);
- if (glewExperimental || GLXEW_MESA_release_buffers) CONST_CAST(GLXEW_MESA_release_buffers) = !_glewInit_GLX_MESA_release_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_MESA_release_buffers = _glewSearchExtension("GLX_MESA_release_buffers", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_release_buffers) GLXEW_MESA_release_buffers = !_glewInit_GLX_MESA_release_buffers(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_MESA_release_buffers */
#ifdef GLX_MESA_set_3dfx_mode
- CONST_CAST(GLXEW_MESA_set_3dfx_mode) = _glewSearchExtension("GLX_MESA_set_3dfx_mode", extStart, extEnd);
- if (glewExperimental || GLXEW_MESA_set_3dfx_mode) CONST_CAST(GLXEW_MESA_set_3dfx_mode) = !_glewInit_GLX_MESA_set_3dfx_mode(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_MESA_set_3dfx_mode = _glewSearchExtension("GLX_MESA_set_3dfx_mode", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_set_3dfx_mode) GLXEW_MESA_set_3dfx_mode = !_glewInit_GLX_MESA_set_3dfx_mode(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_MESA_set_3dfx_mode */
#ifdef GLX_MESA_swap_control
- CONST_CAST(GLXEW_MESA_swap_control) = _glewSearchExtension("GLX_MESA_swap_control", extStart, extEnd);
- if (glewExperimental || GLXEW_MESA_swap_control) CONST_CAST(GLXEW_MESA_swap_control) = !_glewInit_GLX_MESA_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_MESA_swap_control = _glewSearchExtension("GLX_MESA_swap_control", extStart, extEnd);
+ if (glewExperimental || GLXEW_MESA_swap_control) GLXEW_MESA_swap_control = !_glewInit_GLX_MESA_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_MESA_swap_control */
+#ifdef GLX_NV_copy_buffer
+ GLXEW_NV_copy_buffer = _glewSearchExtension("GLX_NV_copy_buffer", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_copy_buffer) GLXEW_NV_copy_buffer = !_glewInit_GLX_NV_copy_buffer(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GLX_NV_copy_buffer */
#ifdef GLX_NV_copy_image
- CONST_CAST(GLXEW_NV_copy_image) = _glewSearchExtension("GLX_NV_copy_image", extStart, extEnd);
- if (glewExperimental || GLXEW_NV_copy_image) CONST_CAST(GLXEW_NV_copy_image) = !_glewInit_GLX_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_NV_copy_image = _glewSearchExtension("GLX_NV_copy_image", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_copy_image) GLXEW_NV_copy_image = !_glewInit_GLX_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_NV_copy_image */
+#ifdef GLX_NV_delay_before_swap
+ GLXEW_NV_delay_before_swap = _glewSearchExtension("GLX_NV_delay_before_swap", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_delay_before_swap) GLXEW_NV_delay_before_swap = !_glewInit_GLX_NV_delay_before_swap(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GLX_NV_delay_before_swap */
#ifdef GLX_NV_float_buffer
- CONST_CAST(GLXEW_NV_float_buffer) = _glewSearchExtension("GLX_NV_float_buffer", extStart, extEnd);
+ GLXEW_NV_float_buffer = _glewSearchExtension("GLX_NV_float_buffer", extStart, extEnd);
#endif /* GLX_NV_float_buffer */
#ifdef GLX_NV_multisample_coverage
- CONST_CAST(GLXEW_NV_multisample_coverage) = _glewSearchExtension("GLX_NV_multisample_coverage", extStart, extEnd);
+ GLXEW_NV_multisample_coverage = _glewSearchExtension("GLX_NV_multisample_coverage", extStart, extEnd);
#endif /* GLX_NV_multisample_coverage */
#ifdef GLX_NV_present_video
- CONST_CAST(GLXEW_NV_present_video) = _glewSearchExtension("GLX_NV_present_video", extStart, extEnd);
- if (glewExperimental || GLXEW_NV_present_video) CONST_CAST(GLXEW_NV_present_video) = !_glewInit_GLX_NV_present_video(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_NV_present_video = _glewSearchExtension("GLX_NV_present_video", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_present_video) GLXEW_NV_present_video = !_glewInit_GLX_NV_present_video(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_NV_present_video */
#ifdef GLX_NV_swap_group
- CONST_CAST(GLXEW_NV_swap_group) = _glewSearchExtension("GLX_NV_swap_group", extStart, extEnd);
- if (glewExperimental || GLXEW_NV_swap_group) CONST_CAST(GLXEW_NV_swap_group) = !_glewInit_GLX_NV_swap_group(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_NV_swap_group = _glewSearchExtension("GLX_NV_swap_group", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_swap_group) GLXEW_NV_swap_group = !_glewInit_GLX_NV_swap_group(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_NV_swap_group */
#ifdef GLX_NV_vertex_array_range
- CONST_CAST(GLXEW_NV_vertex_array_range) = _glewSearchExtension("GLX_NV_vertex_array_range", extStart, extEnd);
- if (glewExperimental || GLXEW_NV_vertex_array_range) CONST_CAST(GLXEW_NV_vertex_array_range) = !_glewInit_GLX_NV_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_NV_vertex_array_range = _glewSearchExtension("GLX_NV_vertex_array_range", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_vertex_array_range) GLXEW_NV_vertex_array_range = !_glewInit_GLX_NV_vertex_array_range(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_NV_vertex_array_range */
#ifdef GLX_NV_video_capture
- CONST_CAST(GLXEW_NV_video_capture) = _glewSearchExtension("GLX_NV_video_capture", extStart, extEnd);
- if (glewExperimental || GLXEW_NV_video_capture) CONST_CAST(GLXEW_NV_video_capture) = !_glewInit_GLX_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_NV_video_capture = _glewSearchExtension("GLX_NV_video_capture", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_video_capture) GLXEW_NV_video_capture = !_glewInit_GLX_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_NV_video_capture */
-#ifdef GLX_NV_video_output
- CONST_CAST(GLXEW_NV_video_output) = _glewSearchExtension("GLX_NV_video_output", extStart, extEnd);
- if (glewExperimental || GLXEW_NV_video_output) CONST_CAST(GLXEW_NV_video_output) = !_glewInit_GLX_NV_video_output(GLEW_CONTEXT_ARG_VAR_INIT);
-#endif /* GLX_NV_video_output */
+#ifdef GLX_NV_video_out
+ GLXEW_NV_video_out = _glewSearchExtension("GLX_NV_video_out", extStart, extEnd);
+ if (glewExperimental || GLXEW_NV_video_out) GLXEW_NV_video_out = !_glewInit_GLX_NV_video_out(GLEW_CONTEXT_ARG_VAR_INIT);
+#endif /* GLX_NV_video_out */
#ifdef GLX_OML_swap_method
- CONST_CAST(GLXEW_OML_swap_method) = _glewSearchExtension("GLX_OML_swap_method", extStart, extEnd);
+ GLXEW_OML_swap_method = _glewSearchExtension("GLX_OML_swap_method", extStart, extEnd);
#endif /* GLX_OML_swap_method */
#ifdef GLX_OML_sync_control
- CONST_CAST(GLXEW_OML_sync_control) = _glewSearchExtension("GLX_OML_sync_control", extStart, extEnd);
- if (glewExperimental || GLXEW_OML_sync_control) CONST_CAST(GLXEW_OML_sync_control) = !_glewInit_GLX_OML_sync_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_OML_sync_control = _glewSearchExtension("GLX_OML_sync_control", extStart, extEnd);
+ if (glewExperimental || GLXEW_OML_sync_control) GLXEW_OML_sync_control = !_glewInit_GLX_OML_sync_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_OML_sync_control */
#ifdef GLX_SGIS_blended_overlay
- CONST_CAST(GLXEW_SGIS_blended_overlay) = _glewSearchExtension("GLX_SGIS_blended_overlay", extStart, extEnd);
+ GLXEW_SGIS_blended_overlay = _glewSearchExtension("GLX_SGIS_blended_overlay", extStart, extEnd);
#endif /* GLX_SGIS_blended_overlay */
#ifdef GLX_SGIS_color_range
- CONST_CAST(GLXEW_SGIS_color_range) = _glewSearchExtension("GLX_SGIS_color_range", extStart, extEnd);
+ GLXEW_SGIS_color_range = _glewSearchExtension("GLX_SGIS_color_range", extStart, extEnd);
#endif /* GLX_SGIS_color_range */
#ifdef GLX_SGIS_multisample
- CONST_CAST(GLXEW_SGIS_multisample) = _glewSearchExtension("GLX_SGIS_multisample", extStart, extEnd);
+ GLXEW_SGIS_multisample = _glewSearchExtension("GLX_SGIS_multisample", extStart, extEnd);
#endif /* GLX_SGIS_multisample */
#ifdef GLX_SGIS_shared_multisample
- CONST_CAST(GLXEW_SGIS_shared_multisample) = _glewSearchExtension("GLX_SGIS_shared_multisample", extStart, extEnd);
+ GLXEW_SGIS_shared_multisample = _glewSearchExtension("GLX_SGIS_shared_multisample", extStart, extEnd);
#endif /* GLX_SGIS_shared_multisample */
#ifdef GLX_SGIX_fbconfig
- CONST_CAST(GLXEW_SGIX_fbconfig) = _glewSearchExtension("GLX_SGIX_fbconfig", extStart, extEnd);
- if (glewExperimental || GLXEW_SGIX_fbconfig) CONST_CAST(GLXEW_SGIX_fbconfig) = !_glewInit_GLX_SGIX_fbconfig(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGIX_fbconfig = _glewSearchExtension("GLX_SGIX_fbconfig", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGIX_fbconfig) GLXEW_SGIX_fbconfig = !_glewInit_GLX_SGIX_fbconfig(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGIX_fbconfig */
#ifdef GLX_SGIX_hyperpipe
- CONST_CAST(GLXEW_SGIX_hyperpipe) = _glewSearchExtension("GLX_SGIX_hyperpipe", extStart, extEnd);
- if (glewExperimental || GLXEW_SGIX_hyperpipe) CONST_CAST(GLXEW_SGIX_hyperpipe) = !_glewInit_GLX_SGIX_hyperpipe(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGIX_hyperpipe = _glewSearchExtension("GLX_SGIX_hyperpipe", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGIX_hyperpipe) GLXEW_SGIX_hyperpipe = !_glewInit_GLX_SGIX_hyperpipe(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGIX_hyperpipe */
#ifdef GLX_SGIX_pbuffer
- CONST_CAST(GLXEW_SGIX_pbuffer) = _glewSearchExtension("GLX_SGIX_pbuffer", extStart, extEnd);
- if (glewExperimental || GLXEW_SGIX_pbuffer) CONST_CAST(GLXEW_SGIX_pbuffer) = !_glewInit_GLX_SGIX_pbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGIX_pbuffer = _glewSearchExtension("GLX_SGIX_pbuffer", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGIX_pbuffer) GLXEW_SGIX_pbuffer = !_glewInit_GLX_SGIX_pbuffer(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGIX_pbuffer */
#ifdef GLX_SGIX_swap_barrier
- CONST_CAST(GLXEW_SGIX_swap_barrier) = _glewSearchExtension("GLX_SGIX_swap_barrier", extStart, extEnd);
- if (glewExperimental || GLXEW_SGIX_swap_barrier) CONST_CAST(GLXEW_SGIX_swap_barrier) = !_glewInit_GLX_SGIX_swap_barrier(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGIX_swap_barrier = _glewSearchExtension("GLX_SGIX_swap_barrier", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGIX_swap_barrier) GLXEW_SGIX_swap_barrier = !_glewInit_GLX_SGIX_swap_barrier(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGIX_swap_barrier */
#ifdef GLX_SGIX_swap_group
- CONST_CAST(GLXEW_SGIX_swap_group) = _glewSearchExtension("GLX_SGIX_swap_group", extStart, extEnd);
- if (glewExperimental || GLXEW_SGIX_swap_group) CONST_CAST(GLXEW_SGIX_swap_group) = !_glewInit_GLX_SGIX_swap_group(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGIX_swap_group = _glewSearchExtension("GLX_SGIX_swap_group", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGIX_swap_group) GLXEW_SGIX_swap_group = !_glewInit_GLX_SGIX_swap_group(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGIX_swap_group */
#ifdef GLX_SGIX_video_resize
- CONST_CAST(GLXEW_SGIX_video_resize) = _glewSearchExtension("GLX_SGIX_video_resize", extStart, extEnd);
- if (glewExperimental || GLXEW_SGIX_video_resize) CONST_CAST(GLXEW_SGIX_video_resize) = !_glewInit_GLX_SGIX_video_resize(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGIX_video_resize = _glewSearchExtension("GLX_SGIX_video_resize", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGIX_video_resize) GLXEW_SGIX_video_resize = !_glewInit_GLX_SGIX_video_resize(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGIX_video_resize */
#ifdef GLX_SGIX_visual_select_group
- CONST_CAST(GLXEW_SGIX_visual_select_group) = _glewSearchExtension("GLX_SGIX_visual_select_group", extStart, extEnd);
+ GLXEW_SGIX_visual_select_group = _glewSearchExtension("GLX_SGIX_visual_select_group", extStart, extEnd);
#endif /* GLX_SGIX_visual_select_group */
#ifdef GLX_SGI_cushion
- CONST_CAST(GLXEW_SGI_cushion) = _glewSearchExtension("GLX_SGI_cushion", extStart, extEnd);
- if (glewExperimental || GLXEW_SGI_cushion) CONST_CAST(GLXEW_SGI_cushion) = !_glewInit_GLX_SGI_cushion(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGI_cushion = _glewSearchExtension("GLX_SGI_cushion", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGI_cushion) GLXEW_SGI_cushion = !_glewInit_GLX_SGI_cushion(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGI_cushion */
#ifdef GLX_SGI_make_current_read
- CONST_CAST(GLXEW_SGI_make_current_read) = _glewSearchExtension("GLX_SGI_make_current_read", extStart, extEnd);
- if (glewExperimental || GLXEW_SGI_make_current_read) CONST_CAST(GLXEW_SGI_make_current_read) = !_glewInit_GLX_SGI_make_current_read(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGI_make_current_read = _glewSearchExtension("GLX_SGI_make_current_read", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGI_make_current_read) GLXEW_SGI_make_current_read = !_glewInit_GLX_SGI_make_current_read(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGI_make_current_read */
#ifdef GLX_SGI_swap_control
- CONST_CAST(GLXEW_SGI_swap_control) = _glewSearchExtension("GLX_SGI_swap_control", extStart, extEnd);
- if (glewExperimental || GLXEW_SGI_swap_control) CONST_CAST(GLXEW_SGI_swap_control) = !_glewInit_GLX_SGI_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGI_swap_control = _glewSearchExtension("GLX_SGI_swap_control", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGI_swap_control) GLXEW_SGI_swap_control = !_glewInit_GLX_SGI_swap_control(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGI_swap_control */
#ifdef GLX_SGI_video_sync
- CONST_CAST(GLXEW_SGI_video_sync) = _glewSearchExtension("GLX_SGI_video_sync", extStart, extEnd);
- if (glewExperimental || GLXEW_SGI_video_sync) CONST_CAST(GLXEW_SGI_video_sync) = !_glewInit_GLX_SGI_video_sync(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SGI_video_sync = _glewSearchExtension("GLX_SGI_video_sync", extStart, extEnd);
+ if (glewExperimental || GLXEW_SGI_video_sync) GLXEW_SGI_video_sync = !_glewInit_GLX_SGI_video_sync(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SGI_video_sync */
#ifdef GLX_SUN_get_transparent_index
- CONST_CAST(GLXEW_SUN_get_transparent_index) = _glewSearchExtension("GLX_SUN_get_transparent_index", extStart, extEnd);
- if (glewExperimental || GLXEW_SUN_get_transparent_index) CONST_CAST(GLXEW_SUN_get_transparent_index) = !_glewInit_GLX_SUN_get_transparent_index(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SUN_get_transparent_index = _glewSearchExtension("GLX_SUN_get_transparent_index", extStart, extEnd);
+ if (glewExperimental || GLXEW_SUN_get_transparent_index) GLXEW_SUN_get_transparent_index = !_glewInit_GLX_SUN_get_transparent_index(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SUN_get_transparent_index */
#ifdef GLX_SUN_video_resize
- CONST_CAST(GLXEW_SUN_video_resize) = _glewSearchExtension("GLX_SUN_video_resize", extStart, extEnd);
- if (glewExperimental || GLXEW_SUN_video_resize) CONST_CAST(GLXEW_SUN_video_resize) = !_glewInit_GLX_SUN_video_resize(GLEW_CONTEXT_ARG_VAR_INIT);
+ GLXEW_SUN_video_resize = _glewSearchExtension("GLX_SUN_video_resize", extStart, extEnd);
+ if (glewExperimental || GLXEW_SUN_video_resize) GLXEW_SUN_video_resize = !_glewInit_GLX_SUN_video_resize(GLEW_CONTEXT_ARG_VAR_INIT);
#endif /* GLX_SUN_video_resize */
return GLEW_OK;
}
-#endif /* !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */
+#endif /* !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */
/* ------------------------------------------------------------------------ */
@@ -13446,8 +13387,8 @@ const GLubyte * GLEWAPIENTRY glewGetErrorString (GLenum error)
(const GLubyte*)"GLX 1.2 and up are not supported",
(const GLubyte*)"Unknown error"
};
- const int max_error = sizeof(_glewErrorString)/sizeof(*_glewErrorString) - 1;
- return _glewErrorString[(int)error > max_error ? max_error : (int)error];
+ const size_t max_error = sizeof(_glewErrorString)/sizeof(*_glewErrorString) - 1;
+ return _glewErrorString[(size_t)error > max_error ? max_error : (size_t)error];
}
const GLubyte * GLEWAPIENTRY glewGetString (GLenum name)
@@ -13455,13 +13396,13 @@ const GLubyte * GLEWAPIENTRY glewGetString (GLenum name)
static const GLubyte* _glewString[] =
{
(const GLubyte*)NULL,
- (const GLubyte*)"1.10.0",
+ (const GLubyte*)"1.13.0",
(const GLubyte*)"1",
- (const GLubyte*)"10",
+ (const GLubyte*)"13",
(const GLubyte*)"0"
};
- const int max_string = sizeof(_glewString)/sizeof(*_glewString) - 1;
- return _glewString[(int)name > max_string ? 0 : (int)name];
+ const size_t max_string = sizeof(_glewString)/sizeof(*_glewString) - 1;
+ return _glewString[(size_t)name > max_string ? 0 : (size_t)name];
}
/* ------------------------------------------------------------------------ */
@@ -13470,21 +13411,15 @@ GLboolean glewExperimental = GL_FALSE;
#if !defined(GLEW_MX)
-#if defined(_WIN32)
-extern GLenum GLEWAPIENTRY wglewContextInit (void);
-#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX))
-extern GLenum GLEWAPIENTRY glxewContextInit (void);
-#endif /* _WIN32 */
-
GLenum GLEWAPIENTRY glewInit (void)
{
GLenum r;
r = glewContextInit();
if ( r != 0 ) return r;
#if defined(_WIN32)
- return wglewContextInit();
-#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) /* _UNIX */
- return glxewContextInit();
+ return wglewInit();
+#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) /* _UNIX */
+ return glxewInit();
#else
return r;
#endif /* _WIN32 */
@@ -13497,7 +13432,7 @@ GLboolean GLEWAPIENTRY glewContextIsSupported (const GLEWContext* ctx, const cha
GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
#endif
{
- GLubyte* pos = (GLubyte*)name;
+ const GLubyte* pos = (const GLubyte*)name;
GLuint len = _glewStrLen(pos);
GLboolean ret = GL_TRUE;
while (ret && len > 0)
@@ -13618,6 +13553,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_VERSION_4_5
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_5", 3))
+ {
+ ret = GLEW_VERSION_4_5;
+ continue;
+ }
+#endif
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"3DFX_", 5))
{
@@ -13680,6 +13622,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_AMD_gcn_shader
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"gcn_shader", 10))
+ {
+ ret = GLEW_AMD_gcn_shader;
+ continue;
+ }
+#endif
+#ifdef GL_AMD_gpu_shader_int64
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_int64", 16))
+ {
+ ret = GLEW_AMD_gpu_shader_int64;
+ continue;
+ }
+#endif
#ifdef GL_AMD_interleaved_elements
if (_glewStrSame3(&pos, &len, (const GLubyte*)"interleaved_elements", 20))
{
@@ -13701,6 +13657,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_AMD_occlusion_query_event
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"occlusion_query_event", 21))
+ {
+ ret = GLEW_AMD_occlusion_query_event;
+ continue;
+ }
+#endif
#ifdef GL_AMD_performance_monitor
if (_glewStrSame3(&pos, &len, (const GLubyte*)"performance_monitor", 19))
{
@@ -13736,6 +13699,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_AMD_shader_atomic_counter_ops
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counter_ops", 25))
+ {
+ ret = GLEW_AMD_shader_atomic_counter_ops;
+ continue;
+ }
+#endif
#ifdef GL_AMD_shader_stencil_export
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_stencil_export", 21))
{
@@ -13743,6 +13713,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_AMD_shader_stencil_value_export
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_stencil_value_export", 27))
+ {
+ ret = GLEW_AMD_shader_stencil_value_export;
+ continue;
+ }
+#endif
#ifdef GL_AMD_shader_trinary_minmax
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_trinary_minmax", 21))
{
@@ -13778,6 +13755,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_AMD_transform_feedback4
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback4", 19))
+ {
+ ret = GLEW_AMD_transform_feedback4;
+ continue;
+ }
+#endif
#ifdef GL_AMD_vertex_shader_layer
if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_shader_layer", 19))
{
@@ -14018,6 +14002,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_ES3_1_compatibility
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES3_1_compatibility", 19))
+ {
+ ret = GLEW_ARB_ES3_1_compatibility;
+ continue;
+ }
+#endif
+#ifdef GL_ARB_ES3_2_compatibility
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES3_2_compatibility", 19))
+ {
+ ret = GLEW_ARB_ES3_2_compatibility;
+ continue;
+ }
+#endif
#ifdef GL_ARB_ES3_compatibility
if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES3_compatibility", 17))
{
@@ -14081,6 +14079,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_clip_control
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"clip_control", 12))
+ {
+ ret = GLEW_ARB_clip_control;
+ continue;
+ }
+#endif
#ifdef GL_ARB_color_buffer_float
if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_buffer_float", 18))
{
@@ -14116,6 +14121,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_conditional_render_inverted
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"conditional_render_inverted", 27))
+ {
+ ret = GLEW_ARB_conditional_render_inverted;
+ continue;
+ }
+#endif
#ifdef GL_ARB_conservative_depth
if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_depth", 18))
{
@@ -14137,6 +14149,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_cull_distance
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"cull_distance", 13))
+ {
+ ret = GLEW_ARB_cull_distance;
+ continue;
+ }
+#endif
#ifdef GL_ARB_debug_output
if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_output", 12))
{
@@ -14165,6 +14184,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_derivative_control
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"derivative_control", 18))
+ {
+ ret = GLEW_ARB_derivative_control;
+ continue;
+ }
+#endif
+#ifdef GL_ARB_direct_state_access
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"direct_state_access", 19))
+ {
+ ret = GLEW_ARB_direct_state_access;
+ continue;
+ }
+#endif
#ifdef GL_ARB_draw_buffers
if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_buffers", 12))
{
@@ -14256,6 +14289,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_fragment_shader_interlock
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader_interlock", 25))
+ {
+ ret = GLEW_ARB_fragment_shader_interlock;
+ continue;
+ }
+#endif
#ifdef GL_ARB_framebuffer_no_attachments
if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_no_attachments", 26))
{
@@ -14291,6 +14331,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_get_texture_sub_image
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"get_texture_sub_image", 21))
+ {
+ ret = GLEW_ARB_get_texture_sub_image;
+ continue;
+ }
+#endif
#ifdef GL_ARB_gpu_shader5
if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader5", 11))
{
@@ -14305,6 +14352,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_gpu_shader_int64
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_shader_int64", 16))
+ {
+ ret = GLEW_ARB_gpu_shader_int64;
+ continue;
+ }
+#endif
#ifdef GL_ARB_half_float_pixel
if (_glewStrSame3(&pos, &len, (const GLubyte*)"half_float_pixel", 16))
{
@@ -14424,6 +14478,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_parallel_shader_compile
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"parallel_shader_compile", 23))
+ {
+ ret = GLEW_ARB_parallel_shader_compile;
+ continue;
+ }
+#endif
+#ifdef GL_ARB_pipeline_statistics_query
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"pipeline_statistics_query", 25))
+ {
+ ret = GLEW_ARB_pipeline_statistics_query;
+ continue;
+ }
+#endif
#ifdef GL_ARB_pixel_buffer_object
if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_buffer_object", 19))
{
@@ -14445,6 +14513,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_post_depth_coverage
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"post_depth_coverage", 19))
+ {
+ ret = GLEW_ARB_post_depth_coverage;
+ continue;
+ }
+#endif
#ifdef GL_ARB_program_interface_query
if (_glewStrSame3(&pos, &len, (const GLubyte*)"program_interface_query", 23))
{
@@ -14494,6 +14569,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_sample_locations
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_locations", 16))
+ {
+ ret = GLEW_ARB_sample_locations;
+ continue;
+ }
+#endif
#ifdef GL_ARB_sample_shading
if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_shading", 14))
{
@@ -14529,6 +14611,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_shader_atomic_counter_ops
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counter_ops", 25))
+ {
+ ret = GLEW_ARB_shader_atomic_counter_ops;
+ continue;
+ }
+#endif
#ifdef GL_ARB_shader_atomic_counters
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counters", 22))
{
@@ -14536,6 +14625,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_shader_ballot
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_ballot", 13))
+ {
+ ret = GLEW_ARB_shader_ballot;
+ continue;
+ }
+#endif
#ifdef GL_ARB_shader_bit_encoding
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_bit_encoding", 19))
{
@@ -14543,6 +14639,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_shader_clock
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_clock", 12))
+ {
+ ret = GLEW_ARB_shader_clock;
+ continue;
+ }
+#endif
#ifdef GL_ARB_shader_draw_parameters
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_draw_parameters", 22))
{
@@ -14606,6 +14709,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_shader_texture_image_samples
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_texture_image_samples", 28))
+ {
+ ret = GLEW_ARB_shader_texture_image_samples;
+ continue;
+ }
+#endif
#ifdef GL_ARB_shader_texture_lod
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_texture_lod", 18))
{
@@ -14613,6 +14723,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_shader_viewport_layer_array
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_viewport_layer_array", 27))
+ {
+ ret = GLEW_ARB_shader_viewport_layer_array;
+ continue;
+ }
+#endif
#ifdef GL_ARB_shading_language_100
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shading_language_100", 20))
{
@@ -14655,6 +14772,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_sparse_buffer
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_buffer", 13))
+ {
+ ret = GLEW_ARB_sparse_buffer;
+ continue;
+ }
+#endif
#ifdef GL_ARB_sparse_texture
if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture", 14))
{
@@ -14662,6 +14786,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_sparse_texture2
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture2", 15))
+ {
+ ret = GLEW_ARB_sparse_texture2;
+ continue;
+ }
+#endif
+#ifdef GL_ARB_sparse_texture_clamp
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture_clamp", 20))
+ {
+ ret = GLEW_ARB_sparse_texture_clamp;
+ continue;
+ }
+#endif
#ifdef GL_ARB_stencil_texturing
if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_texturing", 17))
{
@@ -14683,6 +14821,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_texture_barrier
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_barrier", 15))
+ {
+ ret = GLEW_ARB_texture_barrier;
+ continue;
+ }
+#endif
#ifdef GL_ARB_texture_border_clamp
if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_border_clamp", 20))
{
@@ -14774,6 +14919,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_texture_filter_minmax
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter_minmax", 21))
+ {
+ ret = GLEW_ARB_texture_filter_minmax;
+ continue;
+ }
+#endif
#ifdef GL_ARB_texture_float
if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_float", 13))
{
@@ -14914,6 +15066,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_ARB_transform_feedback_overflow_query
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"transform_feedback_overflow_query", 33))
+ {
+ ret = GLEW_ARB_transform_feedback_overflow_query;
+ continue;
+ }
+#endif
#ifdef GL_ARB_transpose_matrix
if (_glewStrSame3(&pos, &len, (const GLubyte*)"transpose_matrix", 16))
{
@@ -15301,6 +15460,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_debug_label
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_label", 11))
+ {
+ ret = GLEW_EXT_debug_label;
+ continue;
+ }
+#endif
#ifdef GL_EXT_debug_marker
if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug_marker", 12))
{
@@ -15539,6 +15705,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_polygon_offset_clamp
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"polygon_offset_clamp", 20))
+ {
+ ret = GLEW_EXT_polygon_offset_clamp;
+ continue;
+ }
+#endif
+#ifdef GL_EXT_post_depth_coverage
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"post_depth_coverage", 19))
+ {
+ ret = GLEW_EXT_post_depth_coverage;
+ continue;
+ }
+#endif
#ifdef GL_EXT_provoking_vertex
if (_glewStrSame3(&pos, &len, (const GLubyte*)"provoking_vertex", 16))
{
@@ -15546,6 +15726,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_raster_multisample
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"raster_multisample", 18))
+ {
+ ret = GLEW_EXT_raster_multisample;
+ continue;
+ }
+#endif
#ifdef GL_EXT_rescale_normal
if (_glewStrSame3(&pos, &len, (const GLubyte*)"rescale_normal", 14))
{
@@ -15581,6 +15768,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_shader_image_load_formatted
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_load_formatted", 27))
+ {
+ ret = GLEW_EXT_shader_image_load_formatted;
+ continue;
+ }
+#endif
#ifdef GL_EXT_shader_image_load_store
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_load_store", 23))
{
@@ -15588,6 +15782,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_shader_integer_mix
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_integer_mix", 18))
+ {
+ ret = GLEW_EXT_shader_integer_mix;
+ continue;
+ }
+#endif
#ifdef GL_EXT_shadow_funcs
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shadow_funcs", 12))
{
@@ -15602,6 +15803,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_sparse_texture2
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture2", 15))
+ {
+ ret = GLEW_EXT_sparse_texture2;
+ continue;
+ }
+#endif
#ifdef GL_EXT_stencil_clear_tag
if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_clear_tag", 17))
{
@@ -15735,6 +15943,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_EXT_texture_filter_minmax
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_filter_minmax", 21))
+ {
+ ret = GLEW_EXT_texture_filter_minmax;
+ continue;
+ }
+#endif
#ifdef GL_EXT_texture_integer
if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_integer", 15))
{
@@ -15981,6 +16196,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"INTEL_", 6))
{
+#ifdef GL_INTEL_fragment_shader_ordering
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader_ordering", 24))
+ {
+ ret = GLEW_INTEL_fragment_shader_ordering;
+ continue;
+ }
+#endif
+#ifdef GL_INTEL_framebuffer_CMAA
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_CMAA", 16))
+ {
+ ret = GLEW_INTEL_framebuffer_CMAA;
+ continue;
+ }
+#endif
#ifdef GL_INTEL_map_texture
if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_texture", 11))
{
@@ -15995,6 +16224,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_INTEL_performance_query
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"performance_query", 17))
+ {
+ ret = GLEW_INTEL_performance_query;
+ continue;
+ }
+#endif
#ifdef GL_INTEL_texture_scissor
if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_scissor", 15))
{
@@ -16005,6 +16241,27 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"KHR_", 4))
{
+#ifdef GL_KHR_blend_equation_advanced
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced", 23))
+ {
+ ret = GLEW_KHR_blend_equation_advanced;
+ continue;
+ }
+#endif
+#ifdef GL_KHR_blend_equation_advanced_coherent
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced_coherent", 32))
+ {
+ ret = GLEW_KHR_blend_equation_advanced_coherent;
+ continue;
+ }
+#endif
+#ifdef GL_KHR_context_flush_control
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"context_flush_control", 21))
+ {
+ ret = GLEW_KHR_context_flush_control;
+ continue;
+ }
+#endif
#ifdef GL_KHR_debug
if (_glewStrSame3(&pos, &len, (const GLubyte*)"debug", 5))
{
@@ -16012,6 +16269,34 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_KHR_no_error
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"no_error", 8))
+ {
+ ret = GLEW_KHR_no_error;
+ continue;
+ }
+#endif
+#ifdef GL_KHR_robust_buffer_access_behavior
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"robust_buffer_access_behavior", 29))
+ {
+ ret = GLEW_KHR_robust_buffer_access_behavior;
+ continue;
+ }
+#endif
+#ifdef GL_KHR_robustness
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness", 10))
+ {
+ ret = GLEW_KHR_robustness;
+ continue;
+ }
+#endif
+#ifdef GL_KHR_texture_compression_astc_hdr
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_hdr", 28))
+ {
+ ret = GLEW_KHR_texture_compression_astc_hdr;
+ continue;
+ }
+#endif
#ifdef GL_KHR_texture_compression_astc_ldr
if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_astc_ldr", 28))
{
@@ -16097,6 +16382,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_bindless_multi_draw_indirect_count
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_multi_draw_indirect_count", 34))
+ {
+ ret = GLEW_NV_bindless_multi_draw_indirect_count;
+ continue;
+ }
+#endif
#ifdef GL_NV_bindless_texture
if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_texture", 16))
{
@@ -16139,6 +16431,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_conservative_raster
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_raster", 19))
+ {
+ ret = GLEW_NV_conservative_raster;
+ continue;
+ }
+#endif
+#ifdef GL_NV_conservative_raster_dilate
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_raster_dilate", 26))
+ {
+ ret = GLEW_NV_conservative_raster_dilate;
+ continue;
+ }
+#endif
#ifdef GL_NV_copy_depth_to_color
if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_depth_to_color", 19))
{
@@ -16209,6 +16515,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_fill_rectangle
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"fill_rectangle", 14))
+ {
+ ret = GLEW_NV_fill_rectangle;
+ continue;
+ }
+#endif
#ifdef GL_NV_float_buffer
if (_glewStrSame3(&pos, &len, (const GLubyte*)"float_buffer", 12))
{
@@ -16223,6 +16536,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_fragment_coverage_to_color
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_coverage_to_color", 26))
+ {
+ ret = GLEW_NV_fragment_coverage_to_color;
+ continue;
+ }
+#endif
#ifdef GL_NV_fragment_program
if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_program", 16))
{
@@ -16251,6 +16571,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_fragment_shader_interlock
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"fragment_shader_interlock", 25))
+ {
+ ret = GLEW_NV_fragment_shader_interlock;
+ continue;
+ }
+#endif
+#ifdef GL_NV_framebuffer_mixed_samples
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_mixed_samples", 25))
+ {
+ ret = GLEW_NV_framebuffer_mixed_samples;
+ continue;
+ }
+#endif
#ifdef GL_NV_framebuffer_multisample_coverage
if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample_coverage", 32))
{
@@ -16272,6 +16606,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_geometry_shader_passthrough
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"geometry_shader_passthrough", 27))
+ {
+ ret = GLEW_NV_geometry_shader_passthrough;
+ continue;
+ }
+#endif
#ifdef GL_NV_gpu_program4
if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program4", 12))
{
@@ -16314,6 +16655,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_internalformat_sample_query
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"internalformat_sample_query", 27))
+ {
+ ret = GLEW_NV_internalformat_sample_query;
+ continue;
+ }
+#endif
#ifdef GL_NV_light_max_exponent
if (_glewStrSame3(&pos, &len, (const GLubyte*)"light_max_exponent", 18))
{
@@ -16370,6 +16718,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_path_rendering_shared_edge
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"path_rendering_shared_edge", 26))
+ {
+ ret = GLEW_NV_path_rendering_shared_edge;
+ continue;
+ }
+#endif
#ifdef GL_NV_pixel_data_range
if (_glewStrSame3(&pos, &len, (const GLubyte*)"pixel_data_range", 16))
{
@@ -16412,6 +16767,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_sample_locations
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_locations", 16))
+ {
+ ret = GLEW_NV_sample_locations;
+ continue;
+ }
+#endif
+#ifdef GL_NV_sample_mask_override_coverage
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"sample_mask_override_coverage", 29))
+ {
+ ret = GLEW_NV_sample_mask_override_coverage;
+ continue;
+ }
+#endif
#ifdef GL_NV_shader_atomic_counters
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counters", 22))
{
@@ -16426,6 +16795,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_shader_atomic_fp16_vector
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_fp16_vector", 25))
+ {
+ ret = GLEW_NV_shader_atomic_fp16_vector;
+ continue;
+ }
+#endif
+#ifdef GL_NV_shader_atomic_int64
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_int64", 19))
+ {
+ ret = GLEW_NV_shader_atomic_int64;
+ continue;
+ }
+#endif
#ifdef GL_NV_shader_buffer_load
if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_buffer_load", 18))
{
@@ -16440,6 +16823,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_shader_thread_group
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_thread_group", 19))
+ {
+ ret = GLEW_NV_shader_thread_group;
+ continue;
+ }
+#endif
+#ifdef GL_NV_shader_thread_shuffle
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_thread_shuffle", 21))
+ {
+ ret = GLEW_NV_shader_thread_shuffle;
+ continue;
+ }
+#endif
#ifdef GL_NV_tessellation_program5
if (_glewStrSame3(&pos, &len, (const GLubyte*)"tessellation_program5", 21))
{
@@ -16538,6 +16935,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_uniform_buffer_unified_memory
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"uniform_buffer_unified_memory", 29))
+ {
+ ret = GLEW_NV_uniform_buffer_unified_memory;
+ continue;
+ }
+#endif
#ifdef GL_NV_vdpau_interop
if (_glewStrSame3(&pos, &len, (const GLubyte*)"vdpau_interop", 13))
{
@@ -16622,6 +17026,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_NV_viewport_array2
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"viewport_array2", 15))
+ {
+ ret = GLEW_NV_viewport_array2;
+ continue;
+ }
+#endif
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"OES_", 4))
{
@@ -16678,6 +17089,23 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
}
#endif
}
+ if (_glewStrSame2(&pos, &len, (const GLubyte*)"OVR_", 4))
+ {
+#ifdef GL_OVR_multiview
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiview", 9))
+ {
+ ret = GLEW_OVR_multiview;
+ continue;
+ }
+#endif
+#ifdef GL_OVR_multiview2
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"multiview2", 10))
+ {
+ ret = GLEW_OVR_multiview2;
+ continue;
+ }
+#endif
+ }
if (_glewStrSame2(&pos, &len, (const GLubyte*)"PGI_", 4))
{
#ifdef GL_PGI_misc_hints
@@ -16739,6 +17167,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GL_REGAL_proc_address
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"proc_address", 12))
+ {
+ ret = GLEW_REGAL_proc_address;
+ continue;
+ }
+#endif
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"REND_", 5))
{
@@ -17212,7 +17647,7 @@ GLboolean GLEWAPIENTRY wglewContextIsSupported (const WGLEWContext* ctx, const c
GLboolean GLEWAPIENTRY wglewIsSupported (const char* name)
#endif
{
- GLubyte* pos = (GLubyte*)name;
+ const GLubyte* pos = (const GLubyte*)name;
GLuint len = _glewStrLen(pos);
GLboolean ret = GL_TRUE;
while (ret && len > 0)
@@ -17258,6 +17693,13 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name)
continue;
}
#endif
+#ifdef WGL_ARB_context_flush_control
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"context_flush_control", 21))
+ {
+ ret = WGLEW_ARB_context_flush_control;
+ continue;
+ }
+#endif
#ifdef WGL_ARB_create_context
if (_glewStrSame3(&pos, &len, (const GLubyte*)"create_context", 14))
{
@@ -17529,6 +17971,13 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name)
continue;
}
#endif
+#ifdef WGL_NV_delay_before_swap
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"delay_before_swap", 17))
+ {
+ ret = WGLEW_NV_delay_before_swap;
+ continue;
+ }
+#endif
#ifdef WGL_NV_float_buffer
if (_glewStrSame3(&pos, &len, (const GLubyte*)"float_buffer", 12))
{
@@ -17616,7 +18065,7 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name)
return ret;
}
-#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX)
+#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX)
#if defined(GLEW_MX)
GLboolean glxewContextIsSupported (const GLXEWContext* ctx, const char* name)
@@ -17624,7 +18073,7 @@ GLboolean glxewContextIsSupported (const GLXEWContext* ctx, const char* name)
GLboolean glxewIsSupported (const char* name)
#endif
{
- GLubyte* pos = (GLubyte*)name;
+ const GLubyte* pos = (const GLubyte*)name;
GLuint len = _glewStrLen(pos);
GLboolean ret = GL_TRUE;
while (ret && len > 0)
@@ -17677,6 +18126,13 @@ GLboolean glxewIsSupported (const char* name)
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"ARB_", 4))
{
+#ifdef GLX_ARB_context_flush_control
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"context_flush_control", 21))
+ {
+ ret = GLXEW_ARB_context_flush_control;
+ continue;
+ }
+#endif
#ifdef GLX_ARB_create_context
if (_glewStrSame3(&pos, &len, (const GLubyte*)"create_context", 14))
{
@@ -17816,6 +18272,13 @@ GLboolean glxewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GLX_EXT_stereo_tree
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"stereo_tree", 11))
+ {
+ ret = GLXEW_EXT_stereo_tree;
+ continue;
+ }
+#endif
#ifdef GLX_EXT_swap_control
if (_glewStrSame3(&pos, &len, (const GLubyte*)"swap_control", 12))
{
@@ -17885,6 +18348,13 @@ GLboolean glxewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GLX_MESA_query_renderer
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"query_renderer", 14))
+ {
+ ret = GLXEW_MESA_query_renderer;
+ continue;
+ }
+#endif
#ifdef GLX_MESA_release_buffers
if (_glewStrSame3(&pos, &len, (const GLubyte*)"release_buffers", 15))
{
@@ -17909,6 +18379,13 @@ GLboolean glxewIsSupported (const char* name)
}
if (_glewStrSame2(&pos, &len, (const GLubyte*)"NV_", 3))
{
+#ifdef GLX_NV_copy_buffer
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_buffer", 11))
+ {
+ ret = GLXEW_NV_copy_buffer;
+ continue;
+ }
+#endif
#ifdef GLX_NV_copy_image
if (_glewStrSame3(&pos, &len, (const GLubyte*)"copy_image", 10))
{
@@ -17916,6 +18393,13 @@ GLboolean glxewIsSupported (const char* name)
continue;
}
#endif
+#ifdef GLX_NV_delay_before_swap
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"delay_before_swap", 17))
+ {
+ ret = GLXEW_NV_delay_before_swap;
+ continue;
+ }
+#endif
#ifdef GLX_NV_float_buffer
if (_glewStrSame3(&pos, &len, (const GLubyte*)"float_buffer", 12))
{
@@ -17958,10 +18442,10 @@ GLboolean glxewIsSupported (const char* name)
continue;
}
#endif
-#ifdef GLX_NV_video_output
- if (_glewStrSame3(&pos, &len, (const GLubyte*)"video_output", 12))
+#ifdef GLX_NV_video_out
+ if (_glewStrSame3(&pos, &len, (const GLubyte*)"video_out", 9))
{
- ret = GLXEW_NV_video_output;
+ ret = GLXEW_NV_video_out;
continue;
}
#endif
diff --git a/extern/glog/AUTHORS b/extern/glog/AUTHORS
new file mode 100644
index 00000000000..72959a02585
--- /dev/null
+++ b/extern/glog/AUTHORS
@@ -0,0 +1,18 @@
+# This is the official list of glog authors for copyright purposes.
+# This file is distinct from the CONTRIBUTORS files.
+# See the latter for an explanation.
+#
+# Names should be added to this file as:
+# Name or Organization <email address>
+# The email address is not required for organizations.
+#
+# Please keep the list sorted.
+
+Abhishek Parmar <abhishek@orng.net>
+Brian Silverman <bsilver16384@gmail.com>
+Google Inc.
+Michael Tanner <michael@tannertaxpro.com>
+romange <romange@users.noreply.github.com>
+Sergiu Dotenco <sergiu.dotenco@th-nuernberg.de>
+tbennun <tbennun@gmail.com>
+Teddy Reed <teddy@prosauce.org>
diff --git a/extern/glog/CMakeLists.txt b/extern/glog/CMakeLists.txt
new file mode 100644
index 00000000000..15e6aff9714
--- /dev/null
+++ b/extern/glog/CMakeLists.txt
@@ -0,0 +1,92 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2016, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ src
+ ../gflags/src
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ src/logging.cc
+ src/raw_logging.cc
+ src/utilities.cc
+ src/vlog_is_on.cc
+
+ src/utilities.h
+
+ src/config.h
+ src/config_freebsd.h
+ src/config_hurd.h
+ src/config_linux.h
+ src/config_mac.h
+
+ src/base/commandlineflags.h
+ src/base/googleinit.h
+ src/base/mutex.h
+
+ src/stacktrace.h
+ src/stacktrace_generic-inl.h
+ src/stacktrace_libunwind-inl.h
+ src/stacktrace_powerpc-inl.h
+ src/stacktrace_x86_64-inl.h
+ src/stacktrace_x86-inl.h
+)
+
+if(WIN32)
+ list(APPEND SRC
+ src/windows/port.cc
+
+ src/windows/glog/raw_logging.h
+ src/windows/glog/vlog_is_on.h
+ src/windows/glog/logging.h
+ src/windows/glog/log_severity.h
+ src/windows/port.h
+ src/windows/config.h
+ )
+
+ list(APPEND INC
+ src/windows
+ )
+else()
+ list(APPEND SRC
+ src/demangle.cc
+ src/signalhandler.cc
+ src/symbolize.cc
+
+ src/demangle.h
+ src/glog/logging.h
+ src/glog/log_severity.h
+ src/glog/raw_logging.h
+ src/glog/vlog_is_on.h
+ src/symbolize.h
+ )
+endif()
+
+add_definitions(${GFLAGS_DEFINES})
+add_definitions(${GLOG_DEFINES})
+
+blender_add_lib(extern_glog "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/third_party/glog/COPYING b/extern/glog/COPYING
index 38396b580b3..38396b580b3 100644
--- a/extern/libmv/third_party/glog/COPYING
+++ b/extern/glog/COPYING
diff --git a/extern/libmv/third_party/glog/ChangeLog b/extern/glog/ChangeLog
index d1b42484416..d1b42484416 100644
--- a/extern/libmv/third_party/glog/ChangeLog
+++ b/extern/glog/ChangeLog
diff --git a/extern/libmv/third_party/glog/NEWS b/extern/glog/NEWS
index e69de29bb2d..e69de29bb2d 100644
--- a/extern/libmv/third_party/glog/NEWS
+++ b/extern/glog/NEWS
diff --git a/extern/libmv/third_party/glog/README b/extern/glog/README
index 77efd37505a..77efd37505a 100644
--- a/extern/libmv/third_party/glog/README
+++ b/extern/glog/README
diff --git a/extern/glog/README.libmv b/extern/glog/README.libmv
new file mode 100644
index 00000000000..6e82cbbacdf
--- /dev/null
+++ b/extern/glog/README.libmv
@@ -0,0 +1,9 @@
+Project: Google Logging
+URL: http://code.google.com/p/google-glog/
+License: New BSD
+Upstream version: 0.3.4, 4d391fe
+Local modifications:
+* Added per-platform config.h files so no configuration-time
+ checks for functions and so are needed.
+* Applied changes from a fork https://github.com/Nazg-Gul/glog
+ (see https://github.com/google/glog/pull/81)
diff --git a/extern/glog/src/base/commandlineflags.h b/extern/glog/src/base/commandlineflags.h
new file mode 100644
index 00000000000..c8d50890269
--- /dev/null
+++ b/extern/glog/src/base/commandlineflags.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ---
+// This file is a compatibility layer that defines Google's version of
+// command line flags that are used for configuration.
+//
+// We put flags into their own namespace. It is purposefully
+// named in an opaque way that people should have trouble typing
+// directly. The idea is that DEFINE puts the flag in the weird
+// namespace, and DECLARE imports the flag from there into the
+// current namespace. The net result is to force people to use
+// DECLARE to get access to a flag, rather than saying
+// extern bool FLAGS_logtostderr;
+// or some such instead. We want this so we can put extra
+// functionality (like sanity-checking) in DECLARE if we want,
+// and make sure it is picked up everywhere.
+//
+// We also put the type of the variable in the namespace, so that
+// people can't DECLARE_int32 something that they DEFINE_bool'd
+// elsewhere.
+#ifndef BASE_COMMANDLINEFLAGS_H__
+#define BASE_COMMANDLINEFLAGS_H__
+
+#include "config.h"
+#include <string>
+#include <string.h> // for memchr
+#include <stdlib.h> // for getenv
+
+#ifdef HAVE_LIB_GFLAGS
+
+#include <gflags/gflags.h>
+
+#else
+
+#include "glog/logging.h"
+
+#define DECLARE_VARIABLE(type, shorttype, name, tn) \
+ namespace fL##shorttype { \
+ extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
+ } \
+ using fL##shorttype::FLAGS_##name
+#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
+ namespace fL##shorttype { \
+ GOOGLE_GLOG_DLL_DECL type FLAGS_##name(value); \
+ char FLAGS_no##name; \
+ } \
+ using fL##shorttype::FLAGS_##name
+
+// bool specialization
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, B, name, bool)
+#define DEFINE_bool(name, value, meaning) \
+ DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
+
+// int32 specialization
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
+#define DEFINE_int32(name, value, meaning) \
+ DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
+
+// Special case for string, because we have to specify the namespace
+// std::string, which doesn't play nicely with our FLAG__namespace hackery.
+#define DECLARE_string(name) \
+ namespace fLS { \
+ extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \
+ } \
+ using fLS::FLAGS_##name
+#define DEFINE_string(name, value, meaning) \
+ namespace fLS { \
+ std::string FLAGS_##name##_buf(value); \
+ GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name = FLAGS_##name##_buf; \
+ char FLAGS_no##name; \
+ } \
+ using fLS::FLAGS_##name
+
+#endif // HAVE_LIB_GFLAGS
+
+// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
+// have GLOG_* environ variables even if we have gflags installed.
+//
+// If both an environment variable and a flag are specified, the value
+// specified by a flag wins. E.g., if GLOG_v=0 and --v=1, the
+// verbosity will be 1, not 0.
+
+#define GLOG_DEFINE_bool(name, value, meaning) \
+ DEFINE_bool(name, EnvToBool("GLOG_" #name, value), meaning)
+
+#define GLOG_DEFINE_int32(name, value, meaning) \
+ DEFINE_int32(name, EnvToInt("GLOG_" #name, value), meaning)
+
+#define GLOG_DEFINE_string(name, value, meaning) \
+ DEFINE_string(name, EnvToString("GLOG_" #name, value), meaning)
+
+// These macros (could be functions, but I don't want to bother with a .cc
+// file), make it easier to initialize flags from the environment.
+
+#define EnvToString(envname, dflt) \
+ (!getenv(envname) ? (dflt) : getenv(envname))
+
+#define EnvToBool(envname, dflt) \
+ (!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL)
+
+#define EnvToInt(envname, dflt) \
+ (!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10))
+
+#endif // BASE_COMMANDLINEFLAGS_H__
diff --git a/extern/libmv/third_party/glog/src/base/googleinit.h b/extern/glog/src/base/googleinit.h
index 5a8b515cd60..5a8b515cd60 100644
--- a/extern/libmv/third_party/glog/src/base/googleinit.h
+++ b/extern/glog/src/base/googleinit.h
diff --git a/extern/glog/src/base/mutex.h b/extern/glog/src/base/mutex.h
new file mode 100644
index 00000000000..ced2b9950ed
--- /dev/null
+++ b/extern/glog/src/base/mutex.h
@@ -0,0 +1,333 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---
+// Author: Craig Silverstein.
+//
+// A simple mutex wrapper, supporting locks and read-write locks.
+// You should assume the locks are *not* re-entrant.
+//
+// To use: you should define the following macros in your configure.ac:
+// ACX_PTHREAD
+// AC_RWLOCK
+// The latter is defined in ../autoconf.
+//
+// This class is meant to be internal-only and should be wrapped by an
+// internal namespace. Before you use this module, please give the
+// name of your internal namespace for this module. Or, if you want
+// to expose it, you'll want to move it to the Google namespace. We
+// cannot put this class in global namespace because there can be some
+// problems when we have multiple versions of Mutex in each shared object.
+//
+// NOTE: by default, we have #ifdef'ed out the TryLock() method.
+// This is for two reasons:
+// 1) TryLock() under Windows is a bit annoying (it requires a
+// #define to be defined very early).
+// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
+// mode.
+// If you need TryLock(), and either these two caveats are not a
+// problem for you, or you're willing to work around them, then
+// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
+// in the code below.
+//
+// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
+// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
+// Because of that, we might as well use windows locks for
+// cygwin. They seem to be more reliable than the cygwin pthreads layer.
+//
+// TRICKY IMPLEMENTATION NOTE:
+// This class is designed to be safe to use during
+// dynamic-initialization -- that is, by global constructors that are
+// run before main() starts. The issue in this case is that
+// dynamic-initialization happens in an unpredictable order, and it
+// could be that someone else's dynamic initializer could call a
+// function that tries to acquire this mutex -- but that all happens
+// before this mutex's constructor has run. (This can happen even if
+// the mutex and the function that uses the mutex are in the same .cc
+// file.) Basically, because Mutex does non-trivial work in its
+// constructor, it's not, in the naive implementation, safe to use
+// before dynamic initialization has run on it.
+//
+// The solution used here is to pair the actual mutex primitive with a
+// bool that is set to true when the mutex is dynamically initialized.
+// (Before that it's false.) Then we modify all mutex routines to
+// look at the bool, and not try to lock/unlock until the bool makes
+// it to true (which happens after the Mutex constructor has run.)
+//
+// This works because before main() starts -- particularly, during
+// dynamic initialization -- there are no threads, so a) it's ok that
+// the mutex operations are a no-op, since we don't need locking then
+// anyway; and b) we can be quite confident our bool won't change
+// state between a call to Lock() and a call to Unlock() (that would
+// require a global constructor in one translation unit to call Lock()
+// and another global constructor in another translation unit to call
+// Unlock() later, which is pretty perverse).
+//
+// That said, it's tricky, and can conceivably fail; it's safest to
+// avoid trying to acquire a mutex in a global constructor, if you
+// can. One way it can fail is that a really smart compiler might
+// initialize the bool to true at static-initialization time (too
+// early) rather than at dynamic-initialization time. To discourage
+// that, we set is_safe_ to true in code (not the constructor
+// colon-initializer) and set it to true via a function that always
+// evaluates to true, but that the compiler can't know always
+// evaluates to true. This should be good enough.
+
+#ifndef GOOGLE_MUTEX_H_
+#define GOOGLE_MUTEX_H_
+
+#include "config.h" // to figure out pthreads support
+
+#if defined(NO_THREADS)
+ typedef int MutexType; // to keep a lock-count
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN // We only need minimal includes
+# endif
+# ifdef GMUTEX_TRYLOCK
+ // We need Windows NT or later for TryEnterCriticalSection(). If you
+ // don't need that functionality, you can remove these _WIN32_WINNT
+ // lines, and change TryLock() to assert(0) or something.
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+# endif
+# endif
+// To avoid macro definition of ERROR.
+# ifndef NOGDI
+# define NOGDI
+# endif
+// To avoid macro definition of min/max.
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# include <windows.h>
+ typedef CRITICAL_SECTION MutexType;
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+ // Needed for pthread_rwlock_*. If it causes problems, you could take it
+ // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
+ // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
+ // for locking there.)
+# ifdef __linux__
+# ifndef _XOPEN_SOURCE // Some other header might have already set it for us.
+# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
+# endif
+# endif
+# include <pthread.h>
+ typedef pthread_rwlock_t MutexType;
+#elif defined(HAVE_PTHREAD)
+# include <pthread.h>
+ typedef pthread_mutex_t MutexType;
+#else
+# error Need to implement mutex.h for your architecture, or #define NO_THREADS
+#endif
+
+// We need to include these header files after defining _XOPEN_SOURCE
+// as they may define the _XOPEN_SOURCE macro.
+#include <assert.h>
+#include <stdlib.h> // for abort()
+
+#define MUTEX_NAMESPACE glog_internal_namespace_
+
+namespace MUTEX_NAMESPACE {
+
+class Mutex {
+ public:
+ // Create a Mutex that is not held by anybody. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ // See below for a recommendation for constructing global Mutex
+ // objects.
+ inline Mutex();
+
+ // Destructor
+ inline ~Mutex();
+
+ inline void Lock(); // Block if needed until free then acquire exclusively
+ inline void Unlock(); // Release a lock acquired via Lock()
+#ifdef GMUTEX_TRYLOCK
+ inline bool TryLock(); // If free, Lock() and return true, else return false
+#endif
+ // Note that on systems that don't support read-write locks, these may
+ // be implemented as synonyms to Lock() and Unlock(). So you can use
+ // these for efficiency, but don't use them anyplace where being able
+ // to do shared reads is necessary to avoid deadlock.
+ inline void ReaderLock(); // Block until free or shared then acquire a share
+ inline void ReaderUnlock(); // Release a read share of this Mutex
+ inline void WriterLock() { Lock(); } // Acquire an exclusive lock
+ inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
+
+ // TODO(hamaji): Do nothing, implement correctly.
+ inline void AssertHeld() {}
+
+ private:
+ MutexType mutex_;
+ // We want to make sure that the compiler sets is_safe_ to true only
+ // when we tell it to, and never makes assumptions is_safe_ is
+ // always true. volatile is the most reliable way to do that.
+ volatile bool is_safe_;
+
+ inline void SetIsSafe() { is_safe_ = true; }
+
+ // Catch the error of writing Mutex when intending MutexLock.
+ Mutex(Mutex* /*ignored*/) {}
+ // Disallow "evil" constructors
+ Mutex(const Mutex&);
+ void operator=(const Mutex&);
+};
+
+// Now the implementation of Mutex for various systems
+#if defined(NO_THREADS)
+
+// When we don't have threads, we can be either reading or writing,
+// but not both. We can have lots of readers at once (in no-threads
+// mode, that's most likely to happen in recursive function calls),
+// but only one writer. We represent this by having mutex_ be -1 when
+// writing and a number > 0 when reading (and 0 when no lock is held).
+//
+// In debug mode, we assert these invariants, while in non-debug mode
+// we do nothing, for efficiency. That's why everything is in an
+// assert.
+
+Mutex::Mutex() : mutex_(0) { }
+Mutex::~Mutex() { assert(mutex_ == 0); }
+void Mutex::Lock() { assert(--mutex_ == -1); }
+void Mutex::Unlock() { assert(mutex_++ == -1); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
+#endif
+void Mutex::ReaderLock() { assert(++mutex_ > 0); }
+void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
+
+#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
+
+Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
+Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
+void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
+void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ TryEnterCriticalSection(&mutex_) != 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
+void Mutex::ReaderUnlock() { Unlock(); }
+
+#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_rwlock_trywrlock(&mutex_) == 0 :
+ true; }
+#endif
+void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
+void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
+#undef SAFE_PTHREAD
+
+#elif defined(HAVE_PTHREAD)
+
+#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
+ if (is_safe_ && fncall(&mutex_) != 0) abort(); \
+} while (0)
+
+Mutex::Mutex() {
+ SetIsSafe();
+ if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
+}
+Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
+void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
+void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
+#ifdef GMUTEX_TRYLOCK
+bool Mutex::TryLock() { return is_safe_ ?
+ pthread_mutex_trylock(&mutex_) == 0 : true; }
+#endif
+void Mutex::ReaderLock() { Lock(); }
+void Mutex::ReaderUnlock() { Unlock(); }
+#undef SAFE_PTHREAD
+
+#endif
+
+// --------------------------------------------------------------------------
+// Some helper classes
+
+// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
+class MutexLock {
+ public:
+ explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
+ ~MutexLock() { mu_->Unlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ MutexLock(const MutexLock&);
+ void operator=(const MutexLock&);
+};
+
+// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
+class ReaderMutexLock {
+ public:
+ explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
+ ~ReaderMutexLock() { mu_->ReaderUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ ReaderMutexLock(const ReaderMutexLock&);
+ void operator=(const ReaderMutexLock&);
+};
+
+class WriterMutexLock {
+ public:
+ explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
+ ~WriterMutexLock() { mu_->WriterUnlock(); }
+ private:
+ Mutex * const mu_;
+ // Disallow "evil" constructors
+ WriterMutexLock(const WriterMutexLock&);
+ void operator=(const WriterMutexLock&);
+};
+
+// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
+#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
+#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
+#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
+
+} // namespace MUTEX_NAMESPACE
+
+using namespace MUTEX_NAMESPACE;
+
+#undef MUTEX_NAMESPACE
+
+#endif /* #define GOOGLE_MUTEX_H__ */
diff --git a/extern/libmv/third_party/glog/src/config.h b/extern/glog/src/config.h
index f5c9c0b0a7b..f5c9c0b0a7b 100644
--- a/extern/libmv/third_party/glog/src/config.h
+++ b/extern/glog/src/config.h
diff --git a/extern/glog/src/config_freebsd.h b/extern/glog/src/config_freebsd.h
new file mode 100644
index 00000000000..d97b7e16c61
--- /dev/null
+++ b/extern/glog/src/config_freebsd.h
@@ -0,0 +1,192 @@
+/* define if glog doesn't use RTTI */
+/* #undef DISABLE_RTTI */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+/* #undef HAVE_DLADDR */
+
+/* Define if you have the `snprintf' function */
+#define HAVE_SNPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+/* #undef HAVE_EXECINFO_H */
+
+/* Define if you have the `fcntl' function */
+#define HAVE_FCNTL
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#define HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+/* #undef HAVE_LIBUNWIND_H */
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS
+
+/* define if you have google gmock library */
+/* #undef HAVE_LIB_GMOCK */
+
+/* define if you have google gtest library */
+/* #undef HAVE_LIB_GTEST */
+
+/* define if you have libunwind */
+/* #undef HAVE_LIB_UNWIND */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H
+
+/* define to disable multithreading support. */
+/* #undef NO_THREADS */
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES
+
+/* Define if you have the 'pread' function */
+#define HAVE_PREAD
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H
+
+/* Define if you have the 'pwrite' function */
+#define HAVE_PWRITE
+
+/* define if the compiler implements pthread_rwlock_* */
+#define HAVE_RWLOCK 1
+
+/* Define if you have the 'sigaction' function */
+#define HAVE_SIGACTION
+
+/* Define if you have the `sigaltstack' function */
+#define HAVE_SIGALTSTACK 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define to 1 if you have the <syscall.h> header file. */
+/* #undef HAVE_SYSCALL_H */
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucontext.h> header file. */
+#define HAVE_SYS_UCONTEXT_H
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+#define HAVE_UCONTEXT_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <unwind.h> header file. */
+#define HAVE_UNWIND_H 1
+
+/* define if the compiler supports using expression for operator */
+#define HAVE_USING_OPERATOR
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__
+
+/* define if your compiler has __builtin_expect */
+#define HAVE___BUILTIN_EXPECT 1
+
+/* define if your compiler has __sync_val_compare_and_swap */
+#define HAVE___SYNC_VAL_COMPARE_AND_SWAP
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+/* #undef LT_OBJDIR */
+
+/* Name of package */
+/* #undef PACKAGE */
+
+/* Define to the address where bug reports for this package should be sent. */
+/* #undef PACKAGE_BUGREPORT */
+
+/* Define to the full name of this package. */
+/* #undef PACKAGE_NAME */
+
+/* Define to the full name and version of this package. */
+/* #undef PACKAGE_STRING */
+
+/* Define to the one symbol short name of this package. */
+/* #undef PACKAGE_TARNAME */
+
+/* Define to the home page for this package. */
+/* #undef PACKAGE_URL */
+
+/* Define to the version of this package. */
+/* #undef PACKAGE_VERSION */
+
+/* How to access the PC from a struct ucontext */
+/* #undef PC_FROM_UCONTEXT */
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* location of source code */
+#define TEST_SRC_DIR "."
+
+/* Version number of package */
+/* #undef VERSION */
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+#define GOOGLE_GLOG_DLL_DECL
+
+/* isn't getting defined by configure script when clang compilers are used
+ and cuases compilation errors in stactrace/unwind modules */
+#ifdef __clang__
+# define NO_FRAME_POINTER
+#endif
diff --git a/extern/glog/src/config_hurd.h b/extern/glog/src/config_hurd.h
new file mode 100644
index 00000000000..32cad59075e
--- /dev/null
+++ b/extern/glog/src/config_hurd.h
@@ -0,0 +1,192 @@
+/* define if glog doesn't use RTTI */
+/* #undef DISABLE_RTTI */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+/* #undef HAVE_DLADDR */
+
+/* Define if you have the `snprintf' function */
+#define HAVE_SNPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H
+
+/* Define if you have the `fcntl' function */
+#define HAVE_FCNTL
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+/* #undef HAVE_LIBPTHREAD */
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+#define HAVE_LIBUNWIND_H
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS
+
+/* define if you have google gmock library */
+/* #undef HAVE_LIB_GMOCK */
+
+/* define if you have google gtest library */
+/* #undef HAVE_LIB_GTEST */
+
+/* define if you have libunwind */
+/* #undef HAVE_LIB_UNWIND */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H
+
+/* define to disable multithreading support. */
+/* #undef NO_THREADS */
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES
+
+/* Define if you have the 'pread' function */
+#define HAVE_PREAD
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H
+
+/* Define if you have the 'pwrite' function */
+#define HAVE_PWRITE
+
+/* define if the compiler implements pthread_rwlock_* */
+/* #undef HAVE_RWLOCK */
+
+/* Define if you have the 'sigaction' function */
+#define HAVE_SIGACTION
+
+/* Define if you have the `sigaltstack' function */
+/* #undef HAVE_SIGALTSTACK */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define to 1 if you have the <syscall.h> header file. */
+#define HAVE_SYSCALL_H
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucontext.h> header file. */
+/* #undef HAVE_SYS_UCONTEXT_H */
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+#define HAVE_UCONTEXT_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <unwind.h> header file. */
+#define HAVE_UNWIND_H 1
+
+/* define if the compiler supports using expression for operator */
+#define HAVE_USING_OPERATOR
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__
+
+/* define if your compiler has __builtin_expect */
+#define HAVE___BUILTIN_EXPECT 1
+
+/* define if your compiler has __sync_val_compare_and_swap */
+#define HAVE___SYNC_VAL_COMPARE_AND_SWAP
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+/* #undef LT_OBJDIR */
+
+/* Name of package */
+/* #undef PACKAGE */
+
+/* Define to the address where bug reports for this package should be sent. */
+/* #undef PACKAGE_BUGREPORT */
+
+/* Define to the full name of this package. */
+/* #undef PACKAGE_NAME */
+
+/* Define to the full name and version of this package. */
+/* #undef PACKAGE_STRING */
+
+/* Define to the one symbol short name of this package. */
+/* #undef PACKAGE_TARNAME */
+
+/* Define to the home page for this package. */
+/* #undef PACKAGE_URL */
+
+/* Define to the version of this package. */
+/* #undef PACKAGE_VERSION */
+
+/* How to access the PC from a struct ucontext */
+#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
+ #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
+#elif defined(_M_IX86) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+ #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
+#else
+ #undef PC_FROM_UCONTEXT
+#endif
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 4
+
+/* Define to 1 if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* location of source code */
+#define TEST_SRC_DIR "."
+
+/* Version number of package */
+/* #undef VERSION */
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+#define GOOGLE_GLOG_DLL_DECL
diff --git a/extern/glog/src/config_linux.h b/extern/glog/src/config_linux.h
new file mode 100644
index 00000000000..b3a3325bc1b
--- /dev/null
+++ b/extern/glog/src/config_linux.h
@@ -0,0 +1,192 @@
+/* define if glog doesn't use RTTI */
+/* #undef DISABLE_RTTI */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+/* #undef HAVE_DLADDR */
+
+/* Define if you have the `snprintf' function */
+#define HAVE_SNPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H
+
+/* Define if you have the `fcntl' function */
+#define HAVE_FCNTL
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+/* #undef HAVE_LIBPTHREAD */
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+#define HAVE_LIBUNWIND_H
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS
+
+/* define if you have google gmock library */
+/* #undef HAVE_LIB_GMOCK */
+
+/* define if you have google gtest library */
+/* #undef HAVE_LIB_GTEST */
+
+/* define if you have libunwind */
+/* #undef HAVE_LIB_UNWIND */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H
+
+/* define to disable multithreading support. */
+/* #undef NO_THREADS */
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES
+
+/* Define if you have the 'pread' function */
+#define HAVE_PREAD
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H
+
+/* Define if you have the 'pwrite' function */
+#define HAVE_PWRITE
+
+/* define if the compiler implements pthread_rwlock_* */
+/* #undef HAVE_RWLOCK */
+
+/* Define if you have the 'sigaction' function */
+#define HAVE_SIGACTION
+
+/* Define if you have the `sigaltstack' function */
+/* #undef HAVE_SIGALTSTACK */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define to 1 if you have the <syscall.h> header file. */
+#define HAVE_SYSCALL_H
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucontext.h> header file. */
+/* #undef HAVE_SYS_UCONTEXT_H */
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+#define HAVE_UCONTEXT_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <unwind.h> header file. */
+#define HAVE_UNWIND_H 1
+
+/* define if the compiler supports using expression for operator */
+#define HAVE_USING_OPERATOR
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__
+
+/* define if your compiler has __builtin_expect */
+#define HAVE___BUILTIN_EXPECT 1
+
+/* define if your compiler has __sync_val_compare_and_swap */
+#define HAVE___SYNC_VAL_COMPARE_AND_SWAP
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+/* #undef LT_OBJDIR */
+
+/* Name of package */
+/* #undef PACKAGE */
+
+/* Define to the address where bug reports for this package should be sent. */
+/* #undef PACKAGE_BUGREPORT */
+
+/* Define to the full name of this package. */
+/* #undef PACKAGE_NAME */
+
+/* Define to the full name and version of this package. */
+/* #undef PACKAGE_STRING */
+
+/* Define to the one symbol short name of this package. */
+/* #undef PACKAGE_TARNAME */
+
+/* Define to the home page for this package. */
+/* #undef PACKAGE_URL */
+
+/* Define to the version of this package. */
+/* #undef PACKAGE_VERSION */
+
+/* How to access the PC from a struct ucontext */
+#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
+ #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
+#elif defined(_M_IX86) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
+ #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
+#else
+ #undef PC_FROM_UCONTEXT
+#endif
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* location of source code */
+#define TEST_SRC_DIR "."
+
+/* Version number of package */
+/* #undef VERSION */
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+#define GOOGLE_GLOG_DLL_DECL
diff --git a/extern/glog/src/config_mac.h b/extern/glog/src/config_mac.h
new file mode 100644
index 00000000000..4f008b5f67c
--- /dev/null
+++ b/extern/glog/src/config_mac.h
@@ -0,0 +1,186 @@
+/* define if glog doesn't use RTTI */
+/* #undef DISABLE_RTTI */
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Define if you have the `dladdr' function */
+/* #undef HAVE_DLADDR */
+
+/* Define if you have the `snprintf' function */
+#define HAVE_SNPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H
+
+/* Define if you have the `fcntl' function */
+#define HAVE_FCNTL
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+/* #undef HAVE_LIBPTHREAD */
+
+/* Define to 1 if you have the <libunwind.h> header file. */
+#define HAVE_LIBUNWIND_H
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS
+
+/* define if you have google gmock library */
+/* #undef HAVE_LIB_GMOCK */
+
+/* define if you have google gtest library */
+/* #undef HAVE_LIB_GTEST */
+
+/* define if you have libunwind */
+/* #undef HAVE_LIB_UNWIND */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H
+
+/* define to disable multithreading support. */
+/* #undef NO_THREADS */
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES
+
+/* Define if you have the 'pread' function */
+#define HAVE_PREAD
+
+/* Define if you have POSIX threads libraries and header files. */
+#define HAVE_PTHREAD
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H
+
+/* Define if you have the 'pwrite' function */
+#define HAVE_PWRITE
+
+/* define if the compiler implements pthread_rwlock_* */
+/* #undef HAVE_RWLOCK */
+
+/* Define if you have the 'sigaction' function */
+#define HAVE_SIGACTION
+
+/* Define if you have the `sigaltstack' function */
+/* #undef HAVE_SIGALTSTACK */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define to 1 if you have the <syscall.h> header file. */
+/* #undef HAVE_SYSCALL_H */
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#define HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/ucontext.h> header file. */
+#define HAVE_SYS_UCONTEXT_H 1
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#define HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <ucontext.h> header file. */
+/* #undef HAVE_UCONTEXT_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <unwind.h> header file. */
+#define HAVE_UNWIND_H 1
+
+/* define if the compiler supports using expression for operator */
+#define HAVE_USING_OPERATOR
+
+/* define if your compiler has __attribute__ */
+#define HAVE___ATTRIBUTE__
+
+/* define if your compiler has __builtin_expect */
+#define HAVE___BUILTIN_EXPECT 1
+
+/* define if your compiler has __sync_val_compare_and_swap */
+#define HAVE___SYNC_VAL_COMPARE_AND_SWAP
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+/* #undef LT_OBJDIR */
+
+/* Name of package */
+/* #undef PACKAGE */
+
+/* Define to the address where bug reports for this package should be sent. */
+/* #undef PACKAGE_BUGREPORT */
+
+/* Define to the full name of this package. */
+/* #undef PACKAGE_NAME */
+
+/* Define to the full name and version of this package. */
+/* #undef PACKAGE_STRING */
+
+/* Define to the one symbol short name of this package. */
+/* #undef PACKAGE_TARNAME */
+
+/* Define to the home page for this package. */
+/* #undef PACKAGE_URL */
+
+/* Define to the version of this package. */
+/* #undef PACKAGE_VERSION */
+
+/* How to access the PC from a struct ucontext */
+/* #undef PC_FROM_UCONTEXT */
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE std
+
+/* location of source code */
+#define TEST_SRC_DIR "."
+
+/* Version number of package */
+/* #undef VERSION */
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+#define GOOGLE_GLOG_DLL_DECL
diff --git a/extern/libmv/third_party/glog/src/demangle.cc b/extern/glog/src/demangle.cc
index e858181a68f..e858181a68f 100644
--- a/extern/libmv/third_party/glog/src/demangle.cc
+++ b/extern/glog/src/demangle.cc
diff --git a/extern/glog/src/demangle.h b/extern/glog/src/demangle.h
new file mode 100644
index 00000000000..265302997fc
--- /dev/null
+++ b/extern/glog/src/demangle.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces. We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling. More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments. It just skips them. However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv | f() | f()
+// | _Z1fi | f() | f(int)
+// | _Z3foo3bar | foo() | foo(bar)
+// | _Z1fIiEvi | f<>() | void f<int>(int)
+// | _ZN1N1fE | N::f | N::f
+// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
+// | _Zrm1XS_" | operator%() | operator%(X, X)
+// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
+// | _Z1fSs | f() | f(std::basic_string<char,
+// | | | std::char_traits<char>,
+// | | | std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef BASE_DEMANGLE_H_
+#define BASE_DEMANGLE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Demangle "mangled". On success, return true and write the
+// demangled symbol name to "out". Otherwise, return false.
+// "out" is modified even if demangling is unsuccessful.
+bool GOOGLE_GLOG_DLL_DECL Demangle(const char *mangled, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // BASE_DEMANGLE_H_
diff --git a/extern/libmv/third_party/glog/src/glog/log_severity.h b/extern/glog/src/glog/log_severity.h
index 99945a426da..99945a426da 100644
--- a/extern/libmv/third_party/glog/src/glog/log_severity.h
+++ b/extern/glog/src/glog/log_severity.h
diff --git a/extern/glog/src/glog/logging.h b/extern/glog/src/glog/logging.h
new file mode 100644
index 00000000000..c632fcaca1b
--- /dev/null
+++ b/extern/glog/src/glog/logging.h
@@ -0,0 +1,1631 @@
+// Copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Ray Sidney
+//
+// This file contains #include information about logging-related stuff.
+// Pretty much everybody needs to #include this file so that they can
+// log various happenings.
+//
+#ifdef WIN32
+# include "windows/glog/logging.h"
+#else // WIN32
+
+#ifndef _LOGGING_H_
+#define _LOGGING_H_
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <iosfwd>
+#include <ostream>
+#include <sstream>
+#include <string>
+#if 1
+# include <unistd.h>
+#endif
+#include <vector>
+
+#if defined(_MSC_VER)
+#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
+ __pragma(warning(disable:n))
+#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
+#else
+#define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
+#define GLOG_MSVC_POP_WARNING()
+#endif
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// We care a lot about number of bits things take up. Unfortunately,
+// systems define their bit-specific ints in a lot of different ways.
+// We use our own way, and have a typedef to get there.
+// Note: these commands below may look like "#if 1" or "#if 0", but
+// that's because they were constructed that way at ./configure time.
+// Look at logging.h.in to see how they're calculated (based on your config).
+#if 1
+#include <stdint.h> // the normal place uint16_t is defined
+#endif
+#if 1
+#include <sys/types.h> // the normal place u_int16_t is defined
+#endif
+#if 1
+#include <inttypes.h> // a third place for uint16_t or u_int16_t
+#endif
+
+#if 1
+#include <gflags/gflags.h>
+#endif
+
+namespace google {
+
+#if 1 // the C99 format
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#elif 1 // the BSD format
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef int64_t int64;
+typedef u_int64_t uint64;
+#elif 0 // the windows (vc7) format
+typedef __int32 int32;
+typedef unsigned __int32 uint32;
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+#error Do not know how to define a 32-bit integer quantity on your system
+#endif
+
+}
+
+// The global value of GOOGLE_STRIP_LOG. All the messages logged to
+// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.
+// If it can be determined at compile time that the message will not be
+// printed, the statement will be compiled out.
+//
+// Example: to strip out all INFO and WARNING messages, use the value
+// of 2 below. To make an exception for WARNING messages from a single
+// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
+// base/logging.h
+#ifndef GOOGLE_STRIP_LOG
+#define GOOGLE_STRIP_LOG 0
+#endif
+
+// GCC can be told that a certain branch is not likely to be taken (for
+// instance, a CHECK failure), and use that information in static analysis.
+// Giving it this information can help it optimize for the common case in
+// the absence of better information (ie. -fprofile-arcs).
+//
+#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
+#if 1
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
+#else
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
+#endif
+#endif
+
+#ifndef GOOGLE_PREDICT_FALSE
+#if 1
+#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#else
+#define GOOGLE_PREDICT_FALSE(x) x
+#endif
+#endif
+
+#ifndef GOOGLE_PREDICT_TRUE
+#if 1
+#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#else
+#define GOOGLE_PREDICT_TRUE(x) x
+#endif
+#endif
+
+
+// Make a bunch of macros for logging. The way to log things is to stream
+// things to LOG(<a particular severity level>). E.g.,
+//
+// LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can capture log messages in a string, rather than reporting them
+// immediately:
+//
+// vector<string> errors;
+// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num;
+//
+// This pushes back the new error onto 'errors'; if given a NULL pointer,
+// it reports the error via LOG(ERROR).
+//
+// You can also do conditional logging:
+//
+// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// You can also do occasional logging (log every n'th occurrence of an
+// event):
+//
+// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed. Note that the special google::COUNTER value is used
+// to identify which repetition is happening.
+//
+// You can also do occasional conditional logging (log every n'th
+// occurrence of an event, when condition is satisfied):
+//
+// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
+// << "th big cookie";
+//
+// You can log messages the first N times your code executes a line. E.g.
+//
+// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
+//
+// Outputs log messages for the first 20 times it is executed.
+//
+// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.
+// These log to syslog as well as to the normal logs. If you use these at
+// all, you need to be aware that syslog can drastically reduce performance,
+// especially if it is configured for remote logging! Don't use these
+// unless you fully understand this and have a concrete need to use them.
+// Even then, try to minimize your use of them.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+// DLOG(INFO) << "Found cookies";
+//
+// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.
+//
+// We also have
+//
+// LOG_ASSERT(assertion);
+// DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}
+// b. VLOG(1) and lower messages to be printed from file.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs"
+// d. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character) wildcards.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level"
+// condition macros for sample cases, when some extra computation and
+// preparation for logs is not needed.
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+// VLOG_EVERY_N(1, 10)
+// << "I'm printed every 10th occurrence, and when you run the program "
+// "with --v=1 or more. Present occurence is " << google::COUNTER;
+// VLOG_IF_EVERY_N(1, (size > 1024), 10)
+// << "I'm printed on every 10th occurence of case when size is more "
+// " than 1024, when you run the program with --v=1 or more. ";
+// "Present occurence is " << google::COUNTER;
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+// Note that messages of a given severity are logged not only in the
+// logfile for that severity, but also in all logfiles of lower severity.
+// E.g., a message of severity FATAL will be logged to the logfiles of
+// severity FATAL, ERROR, WARNING, and INFO.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// Unless otherwise specified, logs will be written to the filename
+// "<program name>.<hostname>.<user name>.log.<severity level>.", followed
+// by the date, time, and pid (you can't prevent the date, time, and pid
+// from being in the filename).
+//
+// The logging code takes two flags:
+// --v=# set the verbose level
+// --logtostderr log all the messages to stderr instead of to logfiles
+
+// LOG LINE PREFIX FORMAT
+//
+// Log lines have this form:
+//
+// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+//
+// where the fields are defined as follows:
+//
+// L A single character, representing the log level
+// (eg 'I' for INFO)
+// mm The month (zero padded; ie May is '05')
+// dd The day (zero padded)
+// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
+// threadid The space-padded thread ID as returned by GetTID()
+// (this matches the PID on Linux)
+// file The file name
+// line The line number
+// msg The user-supplied message
+//
+// Example:
+//
+// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
+// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
+//
+// NOTE: although the microseconds are useful for comparing events on
+// a single machine, clocks on different machines may not be well
+// synchronized. Hence, use caution when comparing the low bits of
+// timestamps from different machines.
+
+#ifndef DECLARE_VARIABLE
+#define MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#define DECLARE_VARIABLE(type, shorttype, name, tn) \
+ namespace fL##shorttype { \
+ extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
+ } \
+ using fL##shorttype::FLAGS_##name
+
+// bool specialization
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, B, name, bool)
+
+// int32 specialization
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(google::int32, I, name, int32)
+
+// Special case for string, because we have to specify the namespace
+// std::string, which doesn't play nicely with our FLAG__namespace hackery.
+#define DECLARE_string(name) \
+ namespace fLS { \
+ extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \
+ } \
+ using fLS::FLAGS_##name
+#endif
+
+// Set whether log messages go to stderr instead of logfiles
+DECLARE_bool(logtostderr);
+
+// Set whether log messages go to stderr in addition to logfiles.
+DECLARE_bool(alsologtostderr);
+
+// Set color messages logged to stderr (if supported by terminal).
+DECLARE_bool(colorlogtostderr);
+
+// Log messages at a level >= this flag are automatically sent to
+// stderr in addition to log files.
+DECLARE_int32(stderrthreshold);
+
+// Set whether the log prefix should be prepended to each line of output.
+DECLARE_bool(log_prefix);
+
+// Log messages at a level <= this flag are buffered.
+// Log messages at a higher level are flushed immediately.
+DECLARE_int32(logbuflevel);
+
+// Sets the maximum number of seconds which logs may be buffered for.
+DECLARE_int32(logbufsecs);
+
+// Log suppression level: messages logged at a lower level than this
+// are suppressed.
+DECLARE_int32(minloglevel);
+
+// If specified, logfiles are written into this directory instead of the
+// default logging directory.
+DECLARE_string(log_dir);
+
+// Set the log file mode.
+DECLARE_int32(logfile_mode);
+
+// Sets the path of the directory into which to put additional links
+// to the log files.
+DECLARE_string(log_link);
+
+DECLARE_int32(v); // in vlog_is_on.cc
+
+// Sets the maximum log file size (in MB).
+DECLARE_int32(max_log_size);
+
+// Sets whether to avoid logging to the disk if the disk is full.
+DECLARE_bool(stop_logging_if_full_disk);
+
+#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef DECLARE_VARIABLE
+#undef DECLARE_bool
+#undef DECLARE_int32
+#undef DECLARE_string
+#endif
+
+// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for
+// security reasons. See LOG(severtiy) below.
+
+// A few definitions of macros that don't generate much code. Since
+// LOG(INFO) and its ilk are used all over our code, it's
+// better to have compact code for these operations.
+
+#if GOOGLE_STRIP_LOG == 0
+#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_INFO(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_INFO, message)
+#else
+#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
+#define LOG_TO_STRING_INFO(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 1
+#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_WARNING)
+#define LOG_TO_STRING_WARNING(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_WARNING, message)
+#else
+#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
+#define LOG_TO_STRING_WARNING(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 2
+#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ERROR)
+#define LOG_TO_STRING_ERROR(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ERROR, message)
+#else
+#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
+#define LOG_TO_STRING_ERROR(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_FATAL(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_FATAL, message)
+#else
+#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
+#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
+#endif
+
+// For DFATAL, we want to use LogMessage (as opposed to
+// LogMessageFatal), to be consistent with the original behavior.
+#ifdef NDEBUG
+#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
+#elif GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_FATAL)
+#else
+#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
+#endif
+
+#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog)
+#define SYSLOG_INFO(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+// A very useful logging macro to log windows errors:
+#define LOG_SYSRESULT(result) \
+ if (FAILED(HRESULT_FROM_WIN32(result))) { \
+ LPSTR message = NULL; \
+ LPSTR msg = reinterpret_cast<LPSTR>(&message); \
+ DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
+ FORMAT_MESSAGE_FROM_SYSTEM, \
+ 0, result, 0, msg, 100, NULL); \
+ if (message_length > 0) { \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \
+ &google::LogMessage::SendToLog).stream() \
+ << reinterpret_cast<const char*>(message); \
+ LocalFree(message); \
+ } \
+ }
+#endif
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+#define SYSLOG(severity) SYSLOG_ ## severity(0).stream()
+
+namespace google {
+
+// They need the definitions of integer types.
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Initialize google's logging library. You will see the program name
+// specified by argv0 in log outputs.
+GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0);
+
+// Shutdown google's logging library.
+GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging();
+
+// Install a function which will be called after LOG(FATAL).
+GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)());
+
+class LogSink; // defined below
+
+// If a non-NULL sink pointer is given, we push this message to that sink.
+// For LOG_TO_SINK we then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and passing/storing them
+// somewhere more specific than the global log of the process.
+// Argument types:
+// LogSink* sink;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+#define LOG_TO_SINK(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::GLOG_ ## severity, \
+ static_cast<google::LogSink*>(sink), true).stream()
+#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::GLOG_ ## severity, \
+ static_cast<google::LogSink*>(sink), false).stream()
+
+// If a non-NULL string pointer is given, we write this message to that string.
+// We then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and storing them somewhere more
+// specific than the global log of the process.
+// Argument types:
+// string* message;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+// NOTE: LOG(severity) expands to LogMessage().stream() for the specified
+// severity.
+#define LOG_TO_STRING(severity, message) \
+ LOG_TO_STRING_##severity(static_cast<string*>(message)).stream()
+
+// If a non-NULL pointer is given, we push the message onto the end
+// of a vector of strings; otherwise, we report it with LOG(severity).
+// This is handy for capturing messages and perhaps passing them back
+// to the caller, rather than reporting them immediately.
+// Argument types:
+// LogSeverity severity;
+// vector<string> *outvec;
+// The cast is to disambiguate NULL arguments.
+#define LOG_STRING(severity, outvec) \
+ LOG_TO_STRING_##severity(static_cast<std::vector<std::string>*>(outvec)).stream()
+
+#define LOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+#define SYSLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+#define SYSLOG_ASSERT(condition) \
+ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode. Therefore, it is safe to do things like:
+// CHECK(fp->Write(x) == 4)
+#define CHECK(condition) \
+ LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A container for a string pointer which can be evaluated to a bool -
+// true iff the pointer is NULL.
+struct CheckOpString {
+ CheckOpString(std::string* str) : str_(str) { }
+ // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
+ // so there's no point in cleaning up str_.
+ operator bool() const {
+ return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL);
+ }
+ std::string* str_;
+};
+
+// Function is overloaded for integral types to allow static const
+// integrals declared in classes and not defined to be used as arguments to
+// CHECK* macros. It's not encouraged though.
+template <class T>
+inline const T& GetReferenceableValue(const T& t) { return t; }
+inline char GetReferenceableValue(char t) { return t; }
+inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
+inline signed char GetReferenceableValue(signed char t) { return t; }
+inline short GetReferenceableValue(short t) { return t; }
+inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
+inline int GetReferenceableValue(int t) { return t; }
+inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
+inline long GetReferenceableValue(long t) { return t; }
+inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
+inline long long GetReferenceableValue(long long t) { return t; }
+inline unsigned long long GetReferenceableValue(unsigned long long t) {
+ return t;
+}
+
+// This is a dummy class to define the following operator.
+struct DummyClassToDefineOperator {};
+
+}
+
+// Define global operator<< to declare using ::operator<<.
+// This declaration will allow use to use CHECK macros for user
+// defined classes which have operator<< (e.g., stl_logging.h).
+inline std::ostream& operator<<(
+ std::ostream& out, const google::DummyClassToDefineOperator&) {
+ return out;
+}
+
+namespace google {
+
+// This formats a value for a failing CHECK_XX statement. Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << v;
+}
+
+// Overrides for char types provide readable values for unprintable
+// characters.
+template <> GOOGLE_GLOG_DLL_DECL
+void MakeCheckOpValueString(std::ostream* os, const char& v);
+template <> GOOGLE_GLOG_DLL_DECL
+void MakeCheckOpValueString(std::ostream* os, const signed char& v);
+template <> GOOGLE_GLOG_DLL_DECL
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
+
+// Build the error message string. Specify no inlining for code size.
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
+ __attribute__((noinline));
+
+namespace base {
+namespace internal {
+
+// If "s" is less than base_logging::INFO, returns base_logging::INFO.
+// If "s" is greater than base_logging::FATAL, returns
+// base_logging::ERROR. Otherwise, returns "s".
+LogSeverity NormalizeSeverity(LogSeverity s);
+
+} // namespace internal
+
+// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
+// statement. See MakeCheckOpString for sample usage. Other
+// approaches were considered: use of a template method (e.g.,
+// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
+// base::Print<T2>, &v2), however this approach has complications
+// related to volatile arguments and function-pointer arguments).
+class GOOGLE_GLOG_DLL_DECL CheckOpMessageBuilder {
+ public:
+ // Inserts "exprtext" and " (" to the stream.
+ explicit CheckOpMessageBuilder(const char *exprtext);
+ // Deletes "stream_".
+ ~CheckOpMessageBuilder();
+ // For inserting the first variable.
+ std::ostream* ForVar1() { return stream_; }
+ // For inserting the second variable (adds an intermediate " vs. ").
+ std::ostream* ForVar2();
+ // Get the result (inserts the closing ")").
+ std::string* NewString();
+
+ private:
+ std::ostringstream *stream_;
+};
+
+} // namespace base
+
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
+ base::CheckOpMessageBuilder comb(exprtext);
+ MakeCheckOpValueString(comb.ForVar1(), v1);
+ MakeCheckOpValueString(comb.ForVar2(), v2);
+ return comb.NewString();
+}
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <typename T1, typename T2> \
+ inline std::string* name##Impl(const T1& v1, const T2& v2, \
+ const char* exprtext) { \
+ if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
+ else return MakeCheckOpString(v1, v2, exprtext); \
+ } \
+ inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
+ return name##Impl<int, int>(v1, v2, exprtext); \
+ }
+
+// We use the full name Check_EQ, Check_NE, etc. in case the file including
+// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
+// This happens if, for example, those are used as token names in a
+// yacc grammar.
+DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)?
+DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead.
+DEFINE_CHECK_OP_IMPL(Check_LE, <=)
+DEFINE_CHECK_OP_IMPL(Check_LT, < )
+DEFINE_CHECK_OP_IMPL(Check_GE, >=)
+DEFINE_CHECK_OP_IMPL(Check_GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+
+#if defined(STATIC_ANALYSIS)
+// Only for static analysis tool to know that it is equivalent to assert
+#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
+#elif !defined(NDEBUG)
+// In debug mode, avoid constructing CheckOpStrings if possible,
+// to reduce the overhead of CHECK statments by 2x.
+// Real DCHECK-heavy tests have seen 1.5x speedups.
+
+// The meaning of "string" might be different between now and
+// when this macro gets invoked (e.g., if someone is experimenting
+// with other string implementations that get defined after this
+// file is included). Save the current meaning now and use it
+// in the macro.
+typedef std::string _Check_string;
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::_Check_string* _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, \
+ google::CheckOpString(_result)).stream()
+#else
+// In optimized mode, use CheckOpString to hint to compiler that
+// the while condition is unlikely.
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::CheckOpString _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, _result).stream()
+#endif // STATIC_ANALYSIS, !NDEBUG
+
+#if GOOGLE_STRIP_LOG <= 3
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
+#else
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
+#endif // STRIP_LOG <= 3
+
+// Equality/Inequality checks - compare two values, and log a FATAL message
+// including the two values when the result is not as expected. The values
+// must have operator<<(ostream, ...) defined.
+//
+// You may append to the error message like so:
+// CHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// CHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These don't compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
+
+// Check that the input is non NULL. This very useful in constructor
+// initializer lists.
+
+#define CHECK_NOTNULL(val) \
+ google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+
+// Helper functions for string comparisons.
+// To avoid bloat, the definitions are in logging.cc.
+#define DECLARE_CHECK_STROP_IMPL(func, expected) \
+ GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \
+ const char* s1, const char* s2, const char* names);
+DECLARE_CHECK_STROP_IMPL(strcmp, true)
+DECLARE_CHECK_STROP_IMPL(strcmp, false)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, true)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
+#undef DECLARE_CHECK_STROP_IMPL
+
+// Helper macro for string comparisons.
+// Don't use this macro directly in your code, use CHECK_STREQ et al below.
+#define CHECK_STROP(func, op, expected, s1, s2) \
+ while (google::CheckOpString _result = \
+ google::Check##func##expected##Impl((s1), (s2), \
+ #s1 " " #op " " #s2)) \
+ LOG(FATAL) << *_result.str_
+
+
+// String (char*) equality/inequality checks.
+// CASE versions are case-insensitive.
+//
+// Note that "s1" and "s2" may be temporary strings which are destroyed
+// by the compiler at the end of the current "full expression"
+// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
+
+#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
+#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)
+#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)
+
+#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
+#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
+
+#define CHECK_DOUBLE_EQ(val1, val2) \
+ do { \
+ CHECK_LE((val1), (val2)+0.000000000000001L); \
+ CHECK_GE((val1), (val2)-0.000000000000001L); \
+ } while (0)
+
+#define CHECK_NEAR(val1, val2, margin) \
+ do { \
+ CHECK_LE((val1), (val2)+(margin)); \
+ CHECK_GE((val1), (val2)-(margin)); \
+ } while (0)
+
+// perror()..googly style!
+//
+// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and
+// CHECK equivalents with the addition that they postpend a description
+// of the current state of errno to their output lines.
+
+#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()
+
+#define GOOGLE_PLOG(severity, counter) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, counter, \
+ &google::LogMessage::SendToLog)
+
+#define PLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
+
+// A CHECK() macro that postpends errno if the condition is false. E.g.
+//
+// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }
+#define PCHECK(condition) \
+ PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A CHECK() macro that lets you assert the success of a function that
+// returns -1 and sets errno in case of an error. E.g.
+//
+// CHECK_ERR(mkdir(path, 0700));
+//
+// or
+//
+// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename;
+#define CHECK_ERR(invocation) \
+PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \
+ << #invocation
+
+// Use macro expansion to create, for each use of LOG_EVERY_N(), static
+// variables with the __LINE__ expansion as part of the variable name.
+#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
+#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line
+
+#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
+#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
+
+#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (condition && \
+ ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0; \
+ if (LOG_OCCURRENCES <= n) \
+ ++LOG_OCCURRENCES; \
+ if (LOG_OCCURRENCES <= n) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+namespace glog_internal_namespace_ {
+template <bool>
+struct CompileAssert {
+};
+struct CrashReason;
+
+// Returns true if FailureSignalHandler is installed.
+bool IsFailureSignalHandlerInstalled();
+} // namespace glog_internal_namespace_
+
+#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
+ typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+#define LOG_EVERY_N(severity, n) \
+ GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \
+ google::NUM_SEVERITIES, \
+ INVALID_REQUESTED_LOG_SEVERITY); \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define SYSLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog)
+
+#define PLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_FIRST_N(severity, n) \
+ SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_IF_EVERY_N(severity, condition, n) \
+ SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog)
+
+// We want the special COUNTER value available for LOG_EVERY_X()'ed messages
+enum PRIVATE_Counter {COUNTER};
+
+#ifdef GLOG_NO_ABBREVIATED_SEVERITIES
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR.
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+#define SYSLOG_0 SYSLOG_ERROR
+#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity GLOG_0 = GLOG_ERROR;
+#else
+// Users may include windows.h after logging.h without
+// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.
+// For this case, we cannot detect if ERROR is defined before users
+// actually use ERROR. Let's make an undefined symbol to warn users.
+# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail
+# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG
+# define SYSLOG_0 GLOG_ERROR_MSG
+# define LOG_TO_STRING_0 GLOG_ERROR_MSG
+# define GLOG_0 GLOG_ERROR_MSG
+#endif
+
+// Plus some debug-logging macros that get compiled to nothing for production
+
+#ifndef NDEBUG
+
+#define DLOG(severity) LOG(severity)
+#define DVLOG(verboselevel) VLOG(verboselevel)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ LOG_IF_EVERY_N(severity, condition, n)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+
+// debug-only checking. not executed in NDEBUG mode.
+#define DCHECK(condition) CHECK(condition)
+#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
+#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
+#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
+#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
+#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
+#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
+#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
+#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
+#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
+#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
+#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
+
+#else // NDEBUG
+
+#define DLOG(severity) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DVLOG(verboselevel) \
+ (true || !VLOG_IS_ON(verboselevel)) ?\
+ (void) 0 : google::LogMessageVoidify() & LOG(INFO)
+
+#define DLOG_IF(severity, condition) \
+ (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_EVERY_N(severity, n) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_ASSERT(condition) \
+ true ? (void) 0 : LOG_ASSERT(condition)
+
+// MSVC warning C4127: conditional expression is constant
+#define DCHECK(condition) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK(condition)
+
+#define DCHECK_EQ(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)
+
+#define DCHECK_NE(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)
+
+#define DCHECK_LE(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)
+
+#define DCHECK_LT(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)
+
+#define DCHECK_GE(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)
+
+#define DCHECK_GT(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)
+
+// You may see warnings in release mode if you don't use the return
+// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.
+#define DCHECK_NOTNULL(val) (val)
+
+#define DCHECK_STREQ(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)
+
+#define DCHECK_STRCASEEQ(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)
+
+#define DCHECK_STRNE(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)
+
+#define DCHECK_STRCASENE(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
+
+#endif // NDEBUG
+
+// Log only in verbose mode.
+
+#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
+
+#define VLOG_IF(verboselevel, condition) \
+ LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
+
+#define VLOG_EVERY_N(verboselevel, n) \
+ LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)
+
+#define VLOG_IF_EVERY_N(verboselevel, condition, n) \
+ LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
+
+namespace base_logging {
+
+// LogMessage::LogStream is a std::ostream backed by this streambuf.
+// This class ignores overflow and leaves two bytes at the end of the
+// buffer to allow for a '\n' and '\0'.
+class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf {
+ public:
+ // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
+ LogStreamBuf(char *buf, int len) {
+ setp(buf, buf + len - 2);
+ }
+ // This effectively ignores overflow.
+ virtual int_type overflow(int_type ch) {
+ return ch;
+ }
+
+ // Legacy public ostrstream method.
+ size_t pcount() const { return pptr() - pbase(); }
+ char* pbase() const { return std::streambuf::pbase(); }
+};
+
+} // namespace base_logging
+
+//
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class GOOGLE_GLOG_DLL_DECL LogMessage {
+public:
+ enum {
+ // Passing kNoLogPrefix for the line number disables the
+ // log-message prefix. Useful for using the LogMessage
+ // infrastructure as a printing utility. See also the --log_prefix
+ // flag for controlling the log-message prefix on an
+ // application-wide basis.
+ kNoLogPrefix = -1
+ };
+
+ // LogStream inherit from non-DLL-exported class (std::ostrstream)
+ // and VC++ produces a warning for this situation.
+ // However, MSDN says "C4275 can be ignored in Microsoft Visual C++
+ // 2005 if you are deriving from a type in the Standard C++ Library"
+ // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+ // Let's just ignore the warning.
+#ifdef _MSC_VER
+# pragma warning(disable: 4275)
+#endif
+ class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
+#ifdef _MSC_VER
+# pragma warning(default: 4275)
+#endif
+ public:
+ LogStream(char *buf, int len, int ctr)
+ : std::ostream(NULL),
+ streambuf_(buf, len),
+ ctr_(ctr),
+ self_(this) {
+ rdbuf(&streambuf_);
+ }
+
+ int ctr() const { return ctr_; }
+ void set_ctr(int ctr) { ctr_ = ctr; }
+ LogStream* self() const { return self_; }
+
+ // Legacy std::streambuf methods.
+ size_t pcount() const { return streambuf_.pcount(); }
+ char* pbase() const { return streambuf_.pbase(); }
+ char* str() const { return pbase(); }
+
+ private:
+ LogStream(const LogStream&);
+ LogStream& operator=(const LogStream&);
+ base_logging::LogStreamBuf streambuf_;
+ int ctr_; // Counter hack (for the LOG_EVERY_X() macro)
+ LogStream *self_; // Consistency check hack
+ };
+
+public:
+ // icc 8 requires this typedef to avoid an internal compiler error.
+ typedef void (LogMessage::*SendMethod)();
+
+ LogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ SendMethod send_method);
+
+ // Two special constructors that generate reduced amounts of code at
+ // LOG call sites for common cases.
+
+ // Used for LOG(INFO): Implied are:
+ // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 19 bytes per call site.
+ LogMessage(const char* file, int line);
+
+ // Used for LOG(severity) where severity != INFO. Implied
+ // are: ctr = 0, send_method = &LogMessage::SendToLog
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 17 bytes per call site.
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // Constructor to log this message to a specified sink (if not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if
+ // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.
+ LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,
+ bool also_send_to_log);
+
+ // Constructor where we also give a vector<string> pointer
+ // for storing the messages (if the pointer is not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::vector<std::string>* outvec);
+
+ // Constructor where we also give a string pointer for storing the
+ // message (if the pointer is not NULL). Implied are: ctr = 0,
+ // send_method = &LogMessage::WriteToStringAndLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* message);
+
+ // A special constructor used for check failures
+ LogMessage(const char* file, int line, const CheckOpString& result);
+
+ ~LogMessage();
+
+ // Flush a buffered message to the sink set in the constructor. Always
+ // called by the destructor, it may also be called from elsewhere if
+ // needed. Only the first call is actioned; any later ones are ignored.
+ void Flush();
+
+ // An arbitrary limit on the length of a single log message. This
+ // is so that streaming can be done more efficiently.
+ static const size_t kMaxLogMessageLen;
+
+ // Theses should not be called directly outside of logging.*,
+ // only passed as SendMethod arguments to other LogMessage methods:
+ void SendToLog(); // Actually dispatch to the logs
+ void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
+
+ // Call abort() or similar to perform LOG(FATAL) crash.
+ static void __attribute__((noreturn)) Fail();
+
+ std::ostream& stream();
+
+ int preserved_errno() const;
+
+ // Must be called without the log_mutex held. (L < log_mutex)
+ static int64 num_messages(int severity);
+
+ struct LogMessageData;
+
+private:
+ // Fully internal SendMethod cases:
+ void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs
+ void SendToSink(); // Send to sink if provided, do nothing otherwise.
+
+ // Write to string if provided and dispatch to the logs.
+ void WriteToStringAndLog();
+
+ void SaveOrSendToLog(); // Save to stringvec if provided, else to logs
+
+ void Init(const char* file, int line, LogSeverity severity,
+ void (LogMessage::*send_method)());
+
+ // Used to fill in crash information during LOG(FATAL) failures.
+ void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
+
+ // Counts of messages sent at each priority:
+ static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex
+
+ // We keep the data in a separate struct so that each instance of
+ // LogMessage uses less stack space.
+ LogMessageData* allocated_;
+ LogMessageData* data_;
+
+ friend class LogDestination;
+
+ LogMessage(const LogMessage&);
+ void operator=(const LogMessage&);
+};
+
+// This class happens to be thread-hostile because all instances share
+// a single data buffer, but since it can only be created just before
+// the process dies, we don't worry so much.
+class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
+ public:
+ LogMessageFatal(const char* file, int line);
+ LogMessageFatal(const char* file, int line, const CheckOpString& result);
+ __attribute__((noreturn)) ~LogMessageFatal();
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const severity, std::string const &msg) {
+ LogMessage(__FILE__, __LINE__, severity).stream() << msg;
+}
+
+// A macro alternative of LogAtLevel. New code may want to use this
+// version since there are two advantages: 1. this version outputs the
+// file name and the line number where this macro is put like other
+// LOG macros, 2. this macro can be used as C++ stream.
+#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
+
+// A small helper for CHECK_NOTNULL().
+template <typename T>
+T* CheckNotNull(const char *file, int line, const char *names, T* t) {
+ if (t == NULL) {
+ LogMessageFatal(file, line, new std::string(names));
+ }
+ return t;
+}
+
+// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
+// only works if ostream is a LogStream. If the ostream is not a
+// LogStream you'll get an assert saying as much at runtime.
+GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os,
+ const PRIVATE_Counter&);
+
+
+// Derived class for PLOG*() above.
+class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage {
+ public:
+
+ ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ void (LogMessage::*send_method)());
+
+ // Postpends ": strerror(errno) [errno]".
+ ~ErrnoLogMessage();
+
+ private:
+ ErrnoLogMessage(const ErrnoLogMessage&);
+ void operator=(const ErrnoLogMessage&);
+};
+
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+
+class GOOGLE_GLOG_DLL_DECL LogMessageVoidify {
+ public:
+ LogMessageVoidify() { }
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) { }
+};
+
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity);
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-hostile because it ignores
+// locking -- used for catastrophic failures.
+GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity);
+
+//
+// Set the destination to which a particular severity level of log
+// messages is sent. If base_filename is "", it means "don't log this
+// severity". Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity,
+ const char* base_filename);
+
+//
+// Set the basename of the symlink to the latest log file at a given
+// severity. If symlink_basename is empty, do not make a symlink. If
+// you don't call this function, the symlink basename is the
+// invocation name of the program. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename);
+
+//
+// Used to send logs to some other kind of destination
+// Users should subclass LogSink and override send to do whatever they want.
+// Implementations must be thread-safe because a shared instance will
+// be called from whichever thread ran the LOG(XXX) line.
+class GOOGLE_GLOG_DLL_DECL LogSink {
+ public:
+ virtual ~LogSink();
+
+ // Sink's logging logic (message_len is such as to exclude '\n' at the end).
+ // This method can't use LOG() or CHECK() as logging system mutex(s) are held
+ // during this call.
+ virtual void send(LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) = 0;
+
+ // Redefine this to implement waiting for
+ // the sink's logging logic to complete.
+ // It will be called after each send() returns,
+ // but before that LogMessage exits or crashes.
+ // By default this function does nothing.
+ // Using this function one can implement complex logic for send()
+ // that itself involves logging; and do all this w/o causing deadlocks and
+ // inconsistent rearrangement of log messages.
+ // E.g. if a LogSink has thread-specific actions, the send() method
+ // can simply add the message to a queue and wake up another thread that
+ // handles real logging while itself making some LOG() calls;
+ // WaitTillSent() can be implemented to wait for that logic to complete.
+ // See our unittest for an example.
+ virtual void WaitTillSent();
+
+ // Returns the normal text output of the log message.
+ // Can be useful to implement send().
+ static std::string ToString(LogSeverity severity, const char* file, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len);
+};
+
+// Add or remove a LogSink as a consumer of logging data. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination);
+GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);
+
+//
+// Specify an "extension" added to the filename specified via
+// SetLogDestination. This applies to all severity levels. It's
+// often used to append the port we're listening on to the logfile
+// name. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(
+ const char* filename_extension);
+
+//
+// Make it so that all log messages of at least a particular severity
+// are logged to stderr (in addition to logging to the usual log
+// file(s)). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);
+
+//
+// Make it so that all log messages go only to stderr. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void LogToStderr();
+
+//
+// Make it so that all log messages of at least a particular severity are
+// logged via email to a list of addresses (in addition to logging to the
+// usual log file(s)). The list of addresses is just a string containing
+// the email addresses to send to (separated by spaces, say). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,
+ const char* addresses);
+
+// A simple function that sends email. dest is a commma-separated
+// list of addressess. Thread-safe.
+GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,
+ const char *subject, const char *body);
+
+GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();
+
+// For tests only: Clear the internal [cached] list of logging directories to
+// force a refresh the next time GetLoggingDirectories is called.
+// Thread-hostile.
+void TestOnly_ClearLoggingDirectoriesList();
+
+// Returns a set of existing temporary directories, which will be a
+// subset of the directories returned by GetLogginDirectories().
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(
+ std::vector<std::string>* list);
+
+// Print any fatal message again -- useful to call from signal handler
+// so that the last thing in the output is the fatal message.
+// Thread-hostile, but a race is unlikely.
+GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();
+
+// Truncate a log file that may be the append-only output of multiple
+// processes and hence can't simply be renamed/reopened (typically a
+// stdout/stderr). If the file "path" is > "limit" bytes, copy the
+// last "keep" bytes to offset 0 and truncate the rest. Since we could
+// be racing with other writers, this approach has the potential to
+// lose very small amounts of data. For security, only follow symlinks
+// if the path is /proc/self/fd/*
+GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,
+ int64 limit, int64 keep);
+
+// Truncate stdout and stderr if they are over the value specified by
+// --max_log_size; keep the final 1MB. This function has the same
+// race condition as TruncateLogFile.
+GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();
+
+// Return the string representation of the provided LogSeverity level.
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
+
+// ---------------------------------------------------------------------
+// Implementation details that are not useful to most clients
+// ---------------------------------------------------------------------
+
+// A Logger is the interface used by logging modules to emit entries
+// to a log. A typical implementation will dump formatted data to a
+// sequence of files. We also provide interfaces that will forward
+// the data to another thread so that the invoker never blocks.
+// Implementations should be thread-safe since the logging system
+// will write to them from multiple threads.
+
+namespace base {
+
+class GOOGLE_GLOG_DLL_DECL Logger {
+ public:
+ virtual ~Logger();
+
+ // Writes "message[0,message_len-1]" corresponding to an event that
+ // occurred at "timestamp". If "force_flush" is true, the log file
+ // is flushed immediately.
+ //
+ // The input message has already been formatted as deemed
+ // appropriate by the higher level logging facility. For example,
+ // textual log messages already contain timestamps, and the
+ // file:linenumber header.
+ virtual void Write(bool force_flush,
+ time_t timestamp,
+ const char* message,
+ int message_len) = 0;
+
+ // Flush any buffered messages
+ virtual void Flush() = 0;
+
+ // Get the current LOG file size.
+ // The returned value is approximate since some
+ // logged data may not have been flushed to disk yet.
+ virtual uint32 LogSize() = 0;
+};
+
+// Get the logger for the specified severity level. The logger
+// remains the property of the logging module and should not be
+// deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level);
+
+// Set the logger for the specified severity level. The logger
+// becomes the property of the logging module and should not
+// be deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger);
+
+}
+
+// glibc has traditionally implemented two incompatible versions of
+// strerror_r(). There is a poorly defined convention for picking the
+// version that we want, but it is not clear whether it even works with
+// all versions of glibc.
+// So, instead, we provide this wrapper that automatically detects the
+// version that is in use, and then implements POSIX semantics.
+// N.B. In addition to what POSIX says, we also guarantee that "buf" will
+// be set to an empty string, if this function failed. This means, in most
+// cases, you do not need to check the error code and you can directly
+// use the value of "buf". It will never have an undefined value.
+// DEPRECATED: Use StrError(int) instead.
+GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len);
+
+// A thread-safe replacement for strerror(). Returns a string describing the
+// given POSIX error code.
+GOOGLE_GLOG_DLL_DECL std::string StrError(int err);
+
+// A class for which we define operator<<, which does nothing.
+class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream {
+ public:
+ // Initialize the LogStream so the messages can be written somewhere
+ // (they'll never be actually displayed). This will be needed if a
+ // NullStream& is implicitly converted to LogStream&, in which case
+ // the overloaded NullStream::operator<< will not be invoked.
+ NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream(const char* /*file*/, int /*line*/,
+ const CheckOpString& /*result*/) :
+ LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream &stream() { return *this; }
+ private:
+ // A very short buffer for messages (which we discard anyway). This
+ // will be needed if NullStream& converted to LogStream& (e.g. as a
+ // result of a conditional expression).
+ char message_buffer_[2];
+};
+
+// Do nothing. This operator is inline, allowing the message to be
+// compiled away. The message will not be compiled away if we do
+// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when
+// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly
+// converted to LogStream and the message will be computed and then
+// quietly discarded.
+template<class T>
+inline NullStream& operator<<(NullStream &str, const T &) { return str; }
+
+// Similar to NullStream, but aborts the program (without stack
+// trace), like LogMessageFatal.
+class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
+ public:
+ NullStreamFatal() { }
+ NullStreamFatal(const char* file, int line, const CheckOpString& result) :
+ NullStream(file, line, result) { }
+ __attribute__((noreturn)) ~NullStreamFatal() throw () { _exit(1); }
+};
+
+// Install a signal handler that will dump signal information and a stack
+// trace when the program crashes on certain signals. We'll install the
+// signal handler for the following signals.
+//
+// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.
+//
+// By default, the signal handler will write the failure dump to the
+// standard error. You can customize the destination by installing your
+// own writer function by InstallFailureWriter() below.
+//
+// Note on threading:
+//
+// The function should be called before threads are created, if you want
+// to use the failure signal handler for all threads. The stack trace
+// will be shown only for the thread that receives the signal. In other
+// words, stack traces of other threads won't be shown.
+GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler();
+
+// Installs a function that is used for writing the failure dump. "data"
+// is the pointer to the beginning of a message to be written, and "size"
+// is the size of the message. You should not expect the data is
+// terminated with '\0'.
+GOOGLE_GLOG_DLL_DECL void InstallFailureWriter(
+ void (*writer)(const char* data, int size));
+
+}
+
+#endif // _LOGGING_H_
+
+#endif // WIN32
diff --git a/extern/glog/src/glog/raw_logging.h b/extern/glog/src/glog/raw_logging.h
new file mode 100644
index 00000000000..de751d8a6b2
--- /dev/null
+++ b/extern/glog/src/glog/raw_logging.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Maxim Lifantsev
+//
+// Thread-safe logging routines that do not allocate any memory or
+// acquire any locks, and can therefore be used by low-level memory
+// allocation and synchronization code.
+#ifdef WIN32
+# include "windows/glog/raw_logging.h"
+#else // WIN32
+
+#ifndef BASE_RAW_LOGGING_H_
+#define BASE_RAW_LOGGING_H_
+
+#include <time.h>
+
+namespace google {
+
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+
+// This is similar to LOG(severity) << format... and VLOG(level) << format..,
+// but
+// * it is to be used ONLY by low-level modules that can't use normal LOG()
+// * it is desiged to be a low-level logger that does not allocate any
+// memory and does not need any locks, hence:
+// * it logs straight and ONLY to STDERR w/o buffering
+// * it uses an explicit format and arguments list
+// * it will silently chop off really long message strings
+// Usage example:
+// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
+// RAW_VLOG(3, "status is %i", status);
+// These will print an almost standard log lines like this to stderr only:
+// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+// I0821 211317 file.cc:142] RAW: status is 20
+#define RAW_LOG(severity, ...) \
+ do { \
+ switch (google::GLOG_ ## severity) { \
+ case 0: \
+ RAW_LOG_INFO(__VA_ARGS__); \
+ break; \
+ case 1: \
+ RAW_LOG_WARNING(__VA_ARGS__); \
+ break; \
+ case 2: \
+ RAW_LOG_ERROR(__VA_ARGS__); \
+ break; \
+ case 3: \
+ RAW_LOG_FATAL(__VA_ARGS__); \
+ break; \
+ default: \
+ break; \
+ } \
+ } while (0)
+
+// The following STRIP_LOG testing is performed in the header file so that it's
+// possible to completely compile out the logging code and the log messages.
+#if STRIP_LOG == 0
+#define RAW_VLOG(verboselevel, ...) \
+ do { \
+ if (VLOG_IS_ON(verboselevel)) { \
+ RAW_LOG_INFO(__VA_ARGS__); \
+ } \
+ } while (0)
+#else
+#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG == 0
+
+#if STRIP_LOG == 0
+#define RAW_LOG_INFO(...) google::RawLog__(google::GLOG_INFO, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG == 0
+
+#if STRIP_LOG <= 1
+#define RAW_LOG_WARNING(...) google::RawLog__(google::GLOG_WARNING, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG <= 1
+
+#if STRIP_LOG <= 2
+#define RAW_LOG_ERROR(...) google::RawLog__(google::GLOG_ERROR, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
+#endif // STRIP_LOG <= 2
+
+#if STRIP_LOG <= 3
+#define RAW_LOG_FATAL(...) google::RawLog__(google::GLOG_FATAL, \
+ __FILE__, __LINE__, __VA_ARGS__)
+#else
+#define RAW_LOG_FATAL(...) \
+ do { \
+ google::RawLogStub__(0, __VA_ARGS__); \
+ exit(1); \
+ } while (0)
+#endif // STRIP_LOG <= 3
+
+// Similar to CHECK(condition) << message,
+// but for low-level modules: we use only RAW_LOG that does not allocate memory.
+// We do not want to provide args list here to encourage this usage:
+// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
+// so that the args are not computed when not needed.
+#define RAW_CHECK(condition, message) \
+ do { \
+ if (!(condition)) { \
+ RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
+ } \
+ } while (0)
+
+// Debug versions of RAW_LOG and RAW_CHECK
+#ifndef NDEBUG
+
+#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
+#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
+
+#else // NDEBUG
+
+#define RAW_DLOG(severity, ...) \
+ while (false) \
+ RAW_LOG(severity, __VA_ARGS__)
+#define RAW_DCHECK(condition, message) \
+ while (false) \
+ RAW_CHECK(condition, message)
+
+#endif // NDEBUG
+
+// Stub log function used to work around for unused variable warnings when
+// building with STRIP_LOG > 0.
+static inline void RawLogStub__(int /* ignored */, ...) {
+}
+
+// Helper function to implement RAW_LOG and RAW_VLOG
+// Logs format... at "severity" level, reporting it
+// as called from file:line.
+// This does not allocate memory or acquire locks.
+GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
+ const char* file,
+ int line,
+ const char* format, ...)
+ ;
+
+// Hack to propagate time information into this module so that
+// this module does not have to directly call localtime_r(),
+// which could allocate memory.
+GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs);
+
+}
+
+#endif // BASE_RAW_LOGGING_H_
+
+#endif // WIN32
diff --git a/extern/libmv/third_party/glog/src/glog/vlog_is_on.h b/extern/glog/src/glog/vlog_is_on.h
index 02b0b867097..02b0b867097 100644
--- a/extern/libmv/third_party/glog/src/glog/vlog_is_on.h
+++ b/extern/glog/src/glog/vlog_is_on.h
diff --git a/extern/glog/src/logging.cc b/extern/glog/src/logging.cc
new file mode 100644
index 00000000000..6552f46efdd
--- /dev/null
+++ b/extern/glog/src/logging.cc
@@ -0,0 +1,2089 @@
+// Copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#define _GNU_SOURCE 1 // needed for O_NOFOLLOW and pread()/pwrite()
+
+#include "utilities.h"
+
+#include <algorithm>
+#include <assert.h>
+#include <iomanip>
+#include <string>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // For _exit.
+#endif
+#include <climits>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h> // For uname.
+#endif
+#include <fcntl.h>
+#include <cstdio>
+#include <iostream>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+#include <vector>
+#include <errno.h> // for errno
+#include <sstream>
+#include "base/commandlineflags.h" // to get the program name
+#include "glog/logging.h"
+#include "glog/raw_logging.h"
+#include "base/googleinit.h"
+
+#ifdef HAVE_STACKTRACE
+# include "stacktrace.h"
+#endif
+
+using std::string;
+using std::vector;
+using std::setw;
+using std::setfill;
+using std::hex;
+using std::dec;
+using std::min;
+using std::ostream;
+using std::ostringstream;
+
+using std::FILE;
+using std::fwrite;
+using std::fclose;
+using std::fflush;
+using std::fprintf;
+using std::perror;
+
+#ifdef __QNX__
+using std::fdopen;
+#endif
+
+#ifdef _WIN32
+#define fdopen _fdopen
+#endif
+
+// There is no thread annotation support.
+#define EXCLUSIVE_LOCKS_REQUIRED(mu)
+
+static bool BoolFromEnv(const char *varname, bool defval) {
+ const char* const valstr = getenv(varname);
+ if (!valstr) {
+ return defval;
+ }
+ return memchr("tTyY1\0", valstr[0], 6) != NULL;
+}
+
+GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
+ "log messages go to stderr instead of logfiles");
+GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
+ "log messages go to stderr in addition to logfiles");
+GLOG_DEFINE_bool(colorlogtostderr, false,
+ "color messages logged to stderr (if supported by terminal)");
+#ifdef OS_LINUX
+GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
+ "Logs can grow very quickly and they are rarely read before they "
+ "need to be evicted from memory. Instead, drop them from memory "
+ "as soon as they are flushed to disk.");
+_START_GOOGLE_NAMESPACE_
+namespace logging {
+static const int64 kPageSize = getpagesize();
+}
+_END_GOOGLE_NAMESPACE_
+#endif
+
+// By default, errors (including fatal errors) get logged to stderr as
+// well as the file.
+//
+// The default is ERROR instead of FATAL so that users can see problems
+// when they run a program without having to look in another file.
+DEFINE_int32(stderrthreshold,
+ GOOGLE_NAMESPACE::GLOG_ERROR,
+ "log messages at or above this level are copied to stderr in "
+ "addition to logfiles. This flag obsoletes --alsologtostderr.");
+
+GLOG_DEFINE_string(alsologtoemail, "",
+ "log messages go to these email addresses "
+ "in addition to logfiles");
+GLOG_DEFINE_bool(log_prefix, true,
+ "Prepend the log prefix to the start of each log line");
+GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
+ "actually get logged anywhere");
+GLOG_DEFINE_int32(logbuflevel, 0,
+ "Buffer log messages logged at this level or lower"
+ " (-1 means don't buffer; 0 means buffer INFO only;"
+ " ...)");
+GLOG_DEFINE_int32(logbufsecs, 30,
+ "Buffer log messages for at most this many seconds");
+GLOG_DEFINE_int32(logemaillevel, 999,
+ "Email log messages logged at this level or higher"
+ " (0 means email all; 3 means email FATAL only;"
+ " ...)");
+GLOG_DEFINE_string(logmailer, "/bin/mail",
+ "Mailer used to send logging email");
+
+// Compute the default value for --log_dir
+static const char* DefaultLogDir() {
+ const char* env;
+ env = getenv("GOOGLE_LOG_DIR");
+ if (env != NULL && env[0] != '\0') {
+ return env;
+ }
+ env = getenv("TEST_TMPDIR");
+ if (env != NULL && env[0] != '\0') {
+ return env;
+ }
+ return "";
+}
+
+GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
+
+GLOG_DEFINE_string(log_dir, DefaultLogDir(),
+ "If specified, logfiles are written into this directory instead "
+ "of the default logging directory.");
+GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
+ "files in this directory");
+
+GLOG_DEFINE_int32(max_log_size, 1800,
+ "approx. maximum log file size (in MB). A value of 0 will "
+ "be silently overridden to 1.");
+
+GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
+ "Stop attempting to log to disk if the disk is full.");
+
+GLOG_DEFINE_string(log_backtrace_at, "",
+ "Emit a backtrace when logging at file:linenum.");
+
+// TODO(hamaji): consider windows
+#define PATH_SEPARATOR '/'
+
+#ifndef HAVE_PREAD
+#if defined(OS_WINDOWS)
+#include <BaseTsd.h>
+#define ssize_t SSIZE_T
+#endif
+static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
+ off_t orig_offset = lseek(fd, 0, SEEK_CUR);
+ if (orig_offset == (off_t)-1)
+ return -1;
+ if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
+ return -1;
+ ssize_t len = read(fd, buf, count);
+ if (len < 0)
+ return len;
+ if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
+ return -1;
+ return len;
+}
+#endif // !HAVE_PREAD
+
+#ifndef HAVE_PWRITE
+static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
+ off_t orig_offset = lseek(fd, 0, SEEK_CUR);
+ if (orig_offset == (off_t)-1)
+ return -1;
+ if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
+ return -1;
+ ssize_t len = write(fd, buf, count);
+ if (len < 0)
+ return len;
+ if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
+ return -1;
+ return len;
+}
+#endif // !HAVE_PWRITE
+
+static void GetHostName(string* hostname) {
+#if defined(HAVE_SYS_UTSNAME_H)
+ struct utsname buf;
+ if (0 != uname(&buf)) {
+ // ensure null termination on failure
+ *buf.nodename = '\0';
+ }
+ *hostname = buf.nodename;
+#elif defined(OS_WINDOWS)
+ char buf[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
+ if (GetComputerNameA(buf, &len)) {
+ *hostname = buf;
+ } else {
+ hostname->clear();
+ }
+#else
+# warning There is no way to retrieve the host name.
+ *hostname = "(unknown)";
+#endif
+}
+
+// Returns true iff terminal supports using colors in output.
+static bool TerminalSupportsColor() {
+ bool term_supports_color = false;
+#ifdef OS_WINDOWS
+ // on Windows TERM variable is usually not set, but the console does
+ // support colors.
+ term_supports_color = true;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = getenv("TERM");
+ if (term != NULL && term[0] != '\0') {
+ term_supports_color =
+ !strcmp(term, "xterm") ||
+ !strcmp(term, "xterm-color") ||
+ !strcmp(term, "xterm-256color") ||
+ !strcmp(term, "screen-256color") ||
+ !strcmp(term, "screen") ||
+ !strcmp(term, "linux") ||
+ !strcmp(term, "cygwin");
+ }
+#endif
+ return term_supports_color;
+}
+
+_START_GOOGLE_NAMESPACE_
+
+enum GLogColor {
+ COLOR_DEFAULT,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW
+};
+
+static GLogColor SeverityToColor(LogSeverity severity) {
+ assert(severity >= 0 && severity < NUM_SEVERITIES);
+ GLogColor color = COLOR_DEFAULT;
+ switch (severity) {
+ case GLOG_INFO:
+ color = COLOR_DEFAULT;
+ break;
+ case GLOG_WARNING:
+ color = COLOR_YELLOW;
+ break;
+ case GLOG_ERROR:
+ case GLOG_FATAL:
+ color = COLOR_RED;
+ break;
+ default:
+ // should never get here.
+ assert(false);
+ }
+ return color;
+}
+
+#ifdef OS_WINDOWS
+
+// Returns the character attribute for the given color.
+static WORD GetColorAttribute(GLogColor color) {
+ switch (color) {
+ case COLOR_RED: return FOREGROUND_RED;
+ case COLOR_GREEN: return FOREGROUND_GREEN;
+ case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+ default: return 0;
+ }
+}
+
+#else
+
+// Returns the ANSI color code for the given color.
+static const char* GetAnsiColorCode(GLogColor color) {
+ switch (color) {
+ case COLOR_RED: return "1";
+ case COLOR_GREEN: return "2";
+ case COLOR_YELLOW: return "3";
+ case COLOR_DEFAULT: return "";
+ };
+ return NULL; // stop warning about return type.
+}
+
+#endif // OS_WINDOWS
+
+// Safely get max_log_size, overriding to 1 if it somehow gets defined as 0
+static int32 MaxLogSize() {
+ return (FLAGS_max_log_size > 0 ? FLAGS_max_log_size : 1);
+}
+
+// An arbitrary limit on the length of a single log message. This
+// is so that streaming can be done more efficiently.
+const size_t LogMessage::kMaxLogMessageLen = 30000;
+
+struct LogMessage::LogMessageData {
+ LogMessageData();
+
+ int preserved_errno_; // preserved errno
+ // Buffer space; contains complete message text.
+ char message_text_[LogMessage::kMaxLogMessageLen+1];
+ LogStream stream_;
+ char severity_; // What level is this LogMessage logged at?
+ int line_; // line number where logging call is.
+ void (LogMessage::*send_method_)(); // Call this in destructor to send
+ union { // At most one of these is used: union to keep the size low.
+ LogSink* sink_; // NULL or sink to send message to
+ std::vector<std::string>* outvec_; // NULL or vector to push message onto
+ std::string* message_; // NULL or string to write message into
+ };
+ time_t timestamp_; // Time of creation of LogMessage
+ struct ::tm tm_time_; // Time of creation of LogMessage
+ size_t num_prefix_chars_; // # of chars of prefix in this message
+ size_t num_chars_to_log_; // # of chars of msg to send to log
+ size_t num_chars_to_syslog_; // # of chars of msg to send to syslog
+ const char* basename_; // basename of file that called LOG
+ const char* fullname_; // fullname of file that called LOG
+ bool has_been_flushed_; // false => data has not been flushed
+ bool first_fatal_; // true => this was first fatal msg
+
+ private:
+ LogMessageData(const LogMessageData&);
+ void operator=(const LogMessageData&);
+};
+
+// A mutex that allows only one thread to log at a time, to keep things from
+// getting jumbled. Some other very uncommon logging operations (like
+// changing the destination file for log messages of a given severity) also
+// lock this mutex. Please be sure that anybody who might possibly need to
+// lock it does so.
+static Mutex log_mutex;
+
+// Number of messages sent at each severity. Under log_mutex.
+int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
+
+// Globally disable log writing (if disk is full)
+static bool stop_writing = false;
+
+const char*const LogSeverityNames[NUM_SEVERITIES] = {
+ "INFO", "WARNING", "ERROR", "FATAL"
+};
+
+// Has the user called SetExitOnDFatal(true)?
+static bool exit_on_dfatal = true;
+
+const char* GetLogSeverityName(LogSeverity severity) {
+ return LogSeverityNames[severity];
+}
+
+static bool SendEmailInternal(const char*dest, const char *subject,
+ const char*body, bool use_logging);
+
+base::Logger::~Logger() {
+}
+
+namespace {
+
+// Encapsulates all file-system related state
+class LogFileObject : public base::Logger {
+ public:
+ LogFileObject(LogSeverity severity, const char* base_filename);
+ ~LogFileObject();
+
+ virtual void Write(bool force_flush, // Should we force a flush here?
+ time_t timestamp, // Timestamp for this entry
+ const char* message,
+ int message_len);
+
+ // Configuration options
+ void SetBasename(const char* basename);
+ void SetExtension(const char* ext);
+ void SetSymlinkBasename(const char* symlink_basename);
+
+ // Normal flushing routine
+ virtual void Flush();
+
+ // It is the actual file length for the system loggers,
+ // i.e., INFO, ERROR, etc.
+ virtual uint32 LogSize() {
+ MutexLock l(&lock_);
+ return file_length_;
+ }
+
+ // Internal flush routine. Exposed so that FlushLogFilesUnsafe()
+ // can avoid grabbing a lock. Usually Flush() calls it after
+ // acquiring lock_.
+ void FlushUnlocked();
+
+ private:
+ static const uint32 kRolloverAttemptFrequency = 0x20;
+
+ Mutex lock_;
+ bool base_filename_selected_;
+ string base_filename_;
+ string symlink_basename_;
+ string filename_extension_; // option users can specify (eg to add port#)
+ FILE* file_;
+ LogSeverity severity_;
+ uint32 bytes_since_flush_;
+ uint32 file_length_;
+ unsigned int rollover_attempt_;
+ int64 next_flush_time_; // cycle count at which to flush log
+
+ // Actually create a logfile using the value of base_filename_ and the
+ // supplied argument time_pid_string
+ // REQUIRES: lock_ is held
+ bool CreateLogfile(const string& time_pid_string);
+};
+
+} // namespace
+
+class LogDestination {
+ public:
+ friend class LogMessage;
+ friend void ReprintFatalMessage();
+ friend base::Logger* base::GetLogger(LogSeverity);
+ friend void base::SetLogger(LogSeverity, base::Logger*);
+
+ // These methods are just forwarded to by their global versions.
+ static void SetLogDestination(LogSeverity severity,
+ const char* base_filename);
+ static void SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename);
+ static void AddLogSink(LogSink *destination);
+ static void RemoveLogSink(LogSink *destination);
+ static void SetLogFilenameExtension(const char* filename_extension);
+ static void SetStderrLogging(LogSeverity min_severity);
+ static void SetEmailLogging(LogSeverity min_severity, const char* addresses);
+ static void LogToStderr();
+ // Flush all log files that are at least at the given severity level
+ static void FlushLogFiles(int min_severity);
+ static void FlushLogFilesUnsafe(int min_severity);
+
+ // we set the maximum size of our packet to be 1400, the logic being
+ // to prevent fragmentation.
+ // Really this number is arbitrary.
+ static const int kNetworkBytes = 1400;
+
+ static const string& hostname();
+ static const bool& terminal_supports_color() {
+ return terminal_supports_color_;
+ }
+
+ static void DeleteLogDestinations();
+
+ private:
+ LogDestination(LogSeverity severity, const char* base_filename);
+ ~LogDestination() { }
+
+ // Take a log message of a particular severity and log it to stderr
+ // iff it's of a high enough severity to deserve it.
+ static void MaybeLogToStderr(LogSeverity severity, const char* message,
+ size_t len);
+
+ // Take a log message of a particular severity and log it to email
+ // iff it's of a high enough severity to deserve it.
+ static void MaybeLogToEmail(LogSeverity severity, const char* message,
+ size_t len);
+ // Take a log message of a particular severity and log it to a file
+ // iff the base filename is not "" (which means "don't log to me")
+ static void MaybeLogToLogfile(LogSeverity severity,
+ time_t timestamp,
+ const char* message, size_t len);
+ // Take a log message of a particular severity and log it to the file
+ // for that severity and also for all files with severity less than
+ // this severity.
+ static void LogToAllLogfiles(LogSeverity severity,
+ time_t timestamp,
+ const char* message, size_t len);
+
+ // Send logging info to all registered sinks.
+ static void LogToSinks(LogSeverity severity,
+ const char *full_filename,
+ const char *base_filename,
+ int line,
+ const struct ::tm* tm_time,
+ const char* message,
+ size_t message_len);
+
+ // Wait for all registered sinks via WaitTillSent
+ // including the optional one in "data".
+ static void WaitForSinks(LogMessage::LogMessageData* data);
+
+ static LogDestination* log_destination(LogSeverity severity);
+
+ LogFileObject fileobject_;
+ base::Logger* logger_; // Either &fileobject_, or wrapper around it
+
+ static LogDestination* log_destinations_[NUM_SEVERITIES];
+ static LogSeverity email_logging_severity_;
+ static string addresses_;
+ static string hostname_;
+ static bool terminal_supports_color_;
+
+ // arbitrary global logging destinations.
+ static vector<LogSink*>* sinks_;
+
+ // Protects the vector sinks_,
+ // but not the LogSink objects its elements reference.
+ static Mutex sink_mutex_;
+
+ // Disallow
+ LogDestination(const LogDestination&);
+ LogDestination& operator=(const LogDestination&);
+};
+
+// Errors do not get logged to email by default.
+LogSeverity LogDestination::email_logging_severity_ = 99999;
+
+string LogDestination::addresses_;
+string LogDestination::hostname_;
+
+vector<LogSink*>* LogDestination::sinks_ = NULL;
+Mutex LogDestination::sink_mutex_;
+bool LogDestination::terminal_supports_color_ = TerminalSupportsColor();
+
+/* static */
+const string& LogDestination::hostname() {
+ if (hostname_.empty()) {
+ GetHostName(&hostname_);
+ if (hostname_.empty()) {
+ hostname_ = "(unknown)";
+ }
+ }
+ return hostname_;
+}
+
+LogDestination::LogDestination(LogSeverity severity,
+ const char* base_filename)
+ : fileobject_(severity, base_filename),
+ logger_(&fileobject_) {
+}
+
+inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
+ // assume we have the log_mutex or we simply don't care
+ // about it
+ for (int i = min_severity; i < NUM_SEVERITIES; i++) {
+ LogDestination* log = log_destinations_[i];
+ if (log != NULL) {
+ // Flush the base fileobject_ logger directly instead of going
+ // through any wrappers to reduce chance of deadlock.
+ log->fileobject_.FlushUnlocked();
+ }
+ }
+}
+
+inline void LogDestination::FlushLogFiles(int min_severity) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ for (int i = min_severity; i < NUM_SEVERITIES; i++) {
+ LogDestination* log = log_destination(i);
+ if (log != NULL) {
+ log->logger_->Flush();
+ }
+ }
+}
+
+inline void LogDestination::SetLogDestination(LogSeverity severity,
+ const char* base_filename) {
+ assert(severity >= 0 && severity < NUM_SEVERITIES);
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ log_destination(severity)->fileobject_.SetBasename(base_filename);
+}
+
+inline void LogDestination::SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename) {
+ CHECK_GE(severity, 0);
+ CHECK_LT(severity, NUM_SEVERITIES);
+ MutexLock l(&log_mutex);
+ log_destination(severity)->fileobject_.SetSymlinkBasename(symlink_basename);
+}
+
+inline void LogDestination::AddLogSink(LogSink *destination) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&sink_mutex_);
+ if (!sinks_) sinks_ = new vector<LogSink*>;
+ sinks_->push_back(destination);
+}
+
+inline void LogDestination::RemoveLogSink(LogSink *destination) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&sink_mutex_);
+ // This doesn't keep the sinks in order, but who cares?
+ if (sinks_) {
+ for (int i = sinks_->size() - 1; i >= 0; i--) {
+ if ((*sinks_)[i] == destination) {
+ (*sinks_)[i] = (*sinks_)[sinks_->size() - 1];
+ sinks_->pop_back();
+ break;
+ }
+ }
+ }
+}
+
+inline void LogDestination::SetLogFilenameExtension(const char* ext) {
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ for ( int severity = 0; severity < NUM_SEVERITIES; ++severity ) {
+ log_destination(severity)->fileobject_.SetExtension(ext);
+ }
+}
+
+inline void LogDestination::SetStderrLogging(LogSeverity min_severity) {
+ assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ FLAGS_stderrthreshold = min_severity;
+}
+
+inline void LogDestination::LogToStderr() {
+ // *Don't* put this stuff in a mutex lock, since SetStderrLogging &
+ // SetLogDestination already do the locking!
+ SetStderrLogging(0); // thus everything is "also" logged to stderr
+ for ( int i = 0; i < NUM_SEVERITIES; ++i ) {
+ SetLogDestination(i, ""); // "" turns off logging to a logfile
+ }
+}
+
+inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
+ const char* addresses) {
+ assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // all this stuff.
+ MutexLock l(&log_mutex);
+ LogDestination::email_logging_severity_ = min_severity;
+ LogDestination::addresses_ = addresses;
+}
+
+static void ColoredWriteToStderr(LogSeverity severity,
+ const char* message, size_t len) {
+ const GLogColor color =
+ (LogDestination::terminal_supports_color() && FLAGS_colorlogtostderr) ?
+ SeverityToColor(severity) : COLOR_DEFAULT;
+
+ // Avoid using cerr from this module since we may get called during
+ // exit code, and cerr may be partially or fully destroyed by then.
+ if (COLOR_DEFAULT == color) {
+ fwrite(message, len, 1, stderr);
+ return;
+ }
+#ifdef OS_WINDOWS
+ const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stderr_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+
+ // We need to flush the stream buffers into the console before each
+ // SetConsoleTextAttribute call lest it affect the text that is already
+ // printed but has not yet reached the console.
+ fflush(stderr);
+ SetConsoleTextAttribute(stderr_handle,
+ GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ fwrite(message, len, 1, stderr);
+ fflush(stderr);
+ // Restores the text color.
+ SetConsoleTextAttribute(stderr_handle, old_color_attrs);
+#else
+ fprintf(stderr, "\033[0;3%sm", GetAnsiColorCode(color));
+ fwrite(message, len, 1, stderr);
+ fprintf(stderr, "\033[m"); // Resets the terminal to default.
+#endif // OS_WINDOWS
+}
+
+static void WriteToStderr(const char* message, size_t len) {
+ // Avoid using cerr from this module since we may get called during
+ // exit code, and cerr may be partially or fully destroyed by then.
+ fwrite(message, len, 1, stderr);
+}
+
+inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
+ const char* message, size_t len) {
+ if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
+ ColoredWriteToStderr(severity, message, len);
+#ifdef OS_WINDOWS
+ // On Windows, also output to the debugger
+ ::OutputDebugStringA(string(message,len).c_str());
+#endif
+ }
+}
+
+
+inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
+ const char* message, size_t len) {
+ if (severity >= email_logging_severity_ ||
+ severity >= FLAGS_logemaillevel) {
+ string to(FLAGS_alsologtoemail);
+ if (!addresses_.empty()) {
+ if (!to.empty()) {
+ to += ",";
+ }
+ to += addresses_;
+ }
+ const string subject(string("[LOG] ") + LogSeverityNames[severity] + ": " +
+ glog_internal_namespace_::ProgramInvocationShortName());
+ string body(hostname());
+ body += "\n\n";
+ body.append(message, len);
+
+ // should NOT use SendEmail(). The caller of this function holds the
+ // log_mutex and SendEmail() calls LOG/VLOG which will block trying to
+ // acquire the log_mutex object. Use SendEmailInternal() and set
+ // use_logging to false.
+ SendEmailInternal(to.c_str(), subject.c_str(), body.c_str(), false);
+ }
+}
+
+
+inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
+ time_t timestamp,
+ const char* message,
+ size_t len) {
+ const bool should_flush = severity > FLAGS_logbuflevel;
+ LogDestination* destination = log_destination(severity);
+ destination->logger_->Write(should_flush, timestamp, message, len);
+}
+
+inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
+ time_t timestamp,
+ const char* message,
+ size_t len) {
+
+ if ( FLAGS_logtostderr ) { // global flag: never log to file
+ ColoredWriteToStderr(severity, message, len);
+ } else {
+ for (int i = severity; i >= 0; --i)
+ LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
+ }
+}
+
+inline void LogDestination::LogToSinks(LogSeverity severity,
+ const char *full_filename,
+ const char *base_filename,
+ int line,
+ const struct ::tm* tm_time,
+ const char* message,
+ size_t message_len) {
+ ReaderMutexLock l(&sink_mutex_);
+ if (sinks_) {
+ for (int i = sinks_->size() - 1; i >= 0; i--) {
+ (*sinks_)[i]->send(severity, full_filename, base_filename,
+ line, tm_time, message, message_len);
+ }
+ }
+}
+
+inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
+ ReaderMutexLock l(&sink_mutex_);
+ if (sinks_) {
+ for (int i = sinks_->size() - 1; i >= 0; i--) {
+ (*sinks_)[i]->WaitTillSent();
+ }
+ }
+ const bool send_to_sink =
+ (data->send_method_ == &LogMessage::SendToSink) ||
+ (data->send_method_ == &LogMessage::SendToSinkAndLog);
+ if (send_to_sink && data->sink_ != NULL) {
+ data->sink_->WaitTillSent();
+ }
+}
+
+LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
+
+inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
+ assert(severity >=0 && severity < NUM_SEVERITIES);
+ if (!log_destinations_[severity]) {
+ log_destinations_[severity] = new LogDestination(severity, NULL);
+ }
+ return log_destinations_[severity];
+}
+
+void LogDestination::DeleteLogDestinations() {
+ for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
+ delete log_destinations_[severity];
+ log_destinations_[severity] = NULL;
+ }
+ MutexLock l(&sink_mutex_);
+ delete sinks_;
+}
+
+namespace {
+
+LogFileObject::LogFileObject(LogSeverity severity,
+ const char* base_filename)
+ : base_filename_selected_(base_filename != NULL),
+ base_filename_((base_filename != NULL) ? base_filename : ""),
+ symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),
+ filename_extension_(),
+ file_(NULL),
+ severity_(severity),
+ bytes_since_flush_(0),
+ file_length_(0),
+ rollover_attempt_(kRolloverAttemptFrequency-1),
+ next_flush_time_(0) {
+ assert(severity >= 0);
+ assert(severity < NUM_SEVERITIES);
+}
+
+LogFileObject::~LogFileObject() {
+ MutexLock l(&lock_);
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ }
+}
+
+void LogFileObject::SetBasename(const char* basename) {
+ MutexLock l(&lock_);
+ base_filename_selected_ = true;
+ if (base_filename_ != basename) {
+ // Get rid of old log file since we are changing names
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+ base_filename_ = basename;
+ }
+}
+
+void LogFileObject::SetExtension(const char* ext) {
+ MutexLock l(&lock_);
+ if (filename_extension_ != ext) {
+ // Get rid of old log file since we are changing names
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+ filename_extension_ = ext;
+ }
+}
+
+void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
+ MutexLock l(&lock_);
+ symlink_basename_ = symlink_basename;
+}
+
+void LogFileObject::Flush() {
+ MutexLock l(&lock_);
+ FlushUnlocked();
+}
+
+void LogFileObject::FlushUnlocked(){
+ if (file_ != NULL) {
+ fflush(file_);
+ bytes_since_flush_ = 0;
+ }
+ // Figure out when we are due for another flush.
+ const int64 next = (FLAGS_logbufsecs
+ * static_cast<int64>(1000000)); // in usec
+ next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
+}
+
+bool LogFileObject::CreateLogfile(const string& time_pid_string) {
+ string string_filename = base_filename_+filename_extension_+
+ time_pid_string;
+ const char* filename = string_filename.c_str();
+ int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, FLAGS_logfile_mode);
+ if (fd == -1) return false;
+#ifdef HAVE_FCNTL
+ // Mark the file close-on-exec. We don't really care if this fails
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ file_ = fdopen(fd, "a"); // Make a FILE*.
+ if (file_ == NULL) { // Man, we're screwed!
+ close(fd);
+ unlink(filename); // Erase the half-baked evidence: an unusable log file
+ return false;
+ }
+
+ // We try to create a symlink called <program_name>.<severity>,
+ // which is easier to use. (Every time we create a new logfile,
+ // we destroy the old symlink and create a new one, so it always
+ // points to the latest logfile.) If it fails, we're sad but it's
+ // no error.
+ if (!symlink_basename_.empty()) {
+ // take directory from filename
+ const char* slash = strrchr(filename, PATH_SEPARATOR);
+ const string linkname =
+ symlink_basename_ + '.' + LogSeverityNames[severity_];
+ string linkpath;
+ if ( slash ) linkpath = string(filename, slash-filename+1); // get dirname
+ linkpath += linkname;
+ unlink(linkpath.c_str()); // delete old one if it exists
+
+#if defined(OS_WINDOWS)
+ // TODO(hamaji): Create lnk file on Windows?
+#elif defined(HAVE_UNISTD_H)
+ // We must have unistd.h.
+ // Make the symlink be relative (in the same dir) so that if the
+ // entire log directory gets relocated the link is still valid.
+ const char *linkdest = slash ? (slash + 1) : filename;
+ if (symlink(linkdest, linkpath.c_str()) != 0) {
+ // silently ignore failures
+ }
+
+ // Make an additional link to the log file in a place specified by
+ // FLAGS_log_link, if indicated
+ if (!FLAGS_log_link.empty()) {
+ linkpath = FLAGS_log_link + "/" + linkname;
+ unlink(linkpath.c_str()); // delete old one if it exists
+ if (symlink(filename, linkpath.c_str()) != 0) {
+ // silently ignore failures
+ }
+ }
+#endif
+ }
+
+ return true; // Everything worked
+}
+
+void LogFileObject::Write(bool force_flush,
+ time_t timestamp,
+ const char* message,
+ int message_len) {
+ MutexLock l(&lock_);
+
+ // We don't log if the base_name_ is "" (which means "don't write")
+ if (base_filename_selected_ && base_filename_.empty()) {
+ return;
+ }
+
+ if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
+ PidHasChanged()) {
+ if (file_ != NULL) fclose(file_);
+ file_ = NULL;
+ file_length_ = bytes_since_flush_ = 0;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+
+ // If there's no destination file, make one before outputting
+ if (file_ == NULL) {
+ // Try to rollover the log file every 32 log messages. The only time
+ // this could matter would be when we have trouble creating the log
+ // file. If that happens, we'll lose lots of log messages, of course!
+ if (++rollover_attempt_ != kRolloverAttemptFrequency) return;
+ rollover_attempt_ = 0;
+
+ struct ::tm tm_time;
+ localtime_r(&timestamp, &tm_time);
+
+ // The logfile's filename will have the date/time & pid in it
+ ostringstream time_pid_stream;
+ time_pid_stream.fill('0');
+ time_pid_stream << 1900+tm_time.tm_year
+ << setw(2) << 1+tm_time.tm_mon
+ << setw(2) << tm_time.tm_mday
+ << '-'
+ << setw(2) << tm_time.tm_hour
+ << setw(2) << tm_time.tm_min
+ << setw(2) << tm_time.tm_sec
+ << '.'
+ << GetMainThreadPid();
+ const string& time_pid_string = time_pid_stream.str();
+
+ if (base_filename_selected_) {
+ if (!CreateLogfile(time_pid_string)) {
+ perror("Could not create log file");
+ fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
+ time_pid_string.c_str());
+ return;
+ }
+ } else {
+ // If no base filename for logs of this severity has been set, use a
+ // default base filename of
+ // "<program name>.<hostname>.<user name>.log.<severity level>.". So
+ // logfiles will have names like
+ // webserver.examplehost.root.log.INFO.19990817-150000.4354, where
+ // 19990817 is a date (1999 August 17), 150000 is a time (15:00:00),
+ // and 4354 is the pid of the logging process. The date & time reflect
+ // when the file was created for output.
+ //
+ // Where does the file get put? Successively try the directories
+ // "/tmp", and "."
+ string stripped_filename(
+ glog_internal_namespace_::ProgramInvocationShortName());
+ string hostname;
+ GetHostName(&hostname);
+
+ string uidname = MyUserName();
+ // We should not call CHECK() here because this function can be
+ // called after holding on to log_mutex. We don't want to
+ // attempt to hold on to the same mutex, and get into a
+ // deadlock. Simply use a name like invalid-user.
+ if (uidname.empty()) uidname = "invalid-user";
+
+ stripped_filename = stripped_filename+'.'+hostname+'.'
+ +uidname+".log."
+ +LogSeverityNames[severity_]+'.';
+ // We're going to (potentially) try to put logs in several different dirs
+ const vector<string> & log_dirs = GetLoggingDirectories();
+
+ // Go through the list of dirs, and try to create the log file in each
+ // until we succeed or run out of options
+ bool success = false;
+ for (vector<string>::const_iterator dir = log_dirs.begin();
+ dir != log_dirs.end();
+ ++dir) {
+ base_filename_ = *dir + "/" + stripped_filename;
+ if ( CreateLogfile(time_pid_string) ) {
+ success = true;
+ break;
+ }
+ }
+ // If we never succeeded, we have to give up
+ if ( success == false ) {
+ perror("Could not create logging file");
+ fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
+ time_pid_string.c_str());
+ return;
+ }
+ }
+
+ // Write a header message into the log file
+ ostringstream file_header_stream;
+ file_header_stream.fill('0');
+ file_header_stream << "Log file created at: "
+ << 1900+tm_time.tm_year << '/'
+ << setw(2) << 1+tm_time.tm_mon << '/'
+ << setw(2) << tm_time.tm_mday
+ << ' '
+ << setw(2) << tm_time.tm_hour << ':'
+ << setw(2) << tm_time.tm_min << ':'
+ << setw(2) << tm_time.tm_sec << '\n'
+ << "Running on machine: "
+ << LogDestination::hostname() << '\n'
+ << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
+ << "threadid file:line] msg" << '\n';
+ const string& file_header_string = file_header_stream.str();
+
+ const int header_len = file_header_string.size();
+ fwrite(file_header_string.data(), 1, header_len, file_);
+ file_length_ += header_len;
+ bytes_since_flush_ += header_len;
+ }
+
+ // Write to LOG file
+ if ( !stop_writing ) {
+ // fwrite() doesn't return an error when the disk is full, for
+ // messages that are less than 4096 bytes. When the disk is full,
+ // it returns the message length for messages that are less than
+ // 4096 bytes. fwrite() returns 4096 for message lengths that are
+ // greater than 4096, thereby indicating an error.
+ errno = 0;
+ fwrite(message, 1, message_len, file_);
+ if ( FLAGS_stop_logging_if_full_disk &&
+ errno == ENOSPC ) { // disk full, stop writing to disk
+ stop_writing = true; // until the disk is
+ return;
+ } else {
+ file_length_ += message_len;
+ bytes_since_flush_ += message_len;
+ }
+ } else {
+ if ( CycleClock_Now() >= next_flush_time_ )
+ stop_writing = false; // check to see if disk has free space.
+ return; // no need to flush
+ }
+
+ // See important msgs *now*. Also, flush logs at least every 10^6 chars,
+ // or every "FLAGS_logbufsecs" seconds.
+ if ( force_flush ||
+ (bytes_since_flush_ >= 1000000) ||
+ (CycleClock_Now() >= next_flush_time_) ) {
+ FlushUnlocked();
+#ifdef OS_LINUX
+ if (FLAGS_drop_log_memory) {
+ if (file_length_ >= logging::kPageSize) {
+ // don't evict the most recent page
+ uint32 len = file_length_ & ~(logging::kPageSize - 1);
+ posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED);
+ }
+ }
+#endif
+ }
+}
+
+} // namespace
+
+
+// Static log data space to avoid alloc failures in a LOG(FATAL)
+//
+// Since multiple threads may call LOG(FATAL), and we want to preserve
+// the data from the first call, we allocate two sets of space. One
+// for exclusive use by the first thread, and one for shared use by
+// all other threads.
+static Mutex fatal_msg_lock;
+static CrashReason crash_reason;
+static bool fatal_msg_exclusive = true;
+static LogMessage::LogMessageData fatal_msg_data_exclusive;
+static LogMessage::LogMessageData fatal_msg_data_shared;
+
+LogMessage::LogMessageData::LogMessageData()
+ : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ int ctr, void (LogMessage::*send_method)())
+ : allocated_(NULL) {
+ Init(file, line, severity, send_method);
+ data_->stream_.set_ctr(ctr);
+}
+
+LogMessage::LogMessage(const char* file, int line,
+ const CheckOpString& result)
+ : allocated_(NULL) {
+ Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);
+ stream() << "Check failed: " << (*result.str_) << " ";
+}
+
+LogMessage::LogMessage(const char* file, int line)
+ : allocated_(NULL) {
+ Init(file, line, GLOG_INFO, &LogMessage::SendToLog);
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+ : allocated_(NULL) {
+ Init(file, line, severity, &LogMessage::SendToLog);
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ LogSink* sink, bool also_send_to_log)
+ : allocated_(NULL) {
+ Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog :
+ &LogMessage::SendToSink);
+ data_->sink_ = sink; // override Init()'s setting to NULL
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ vector<string> *outvec)
+ : allocated_(NULL) {
+ Init(file, line, severity, &LogMessage::SaveOrSendToLog);
+ data_->outvec_ = outvec; // override Init()'s setting to NULL
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+ string *message)
+ : allocated_(NULL) {
+ Init(file, line, severity, &LogMessage::WriteToStringAndLog);
+ data_->message_ = message; // override Init()'s setting to NULL
+}
+
+void LogMessage::Init(const char* file,
+ int line,
+ LogSeverity severity,
+ void (LogMessage::*send_method)()) {
+ allocated_ = NULL;
+ if (severity != GLOG_FATAL || !exit_on_dfatal) {
+ allocated_ = new LogMessageData();
+ data_ = allocated_;
+ data_->first_fatal_ = false;
+ } else {
+ MutexLock l(&fatal_msg_lock);
+ if (fatal_msg_exclusive) {
+ fatal_msg_exclusive = false;
+ data_ = &fatal_msg_data_exclusive;
+ data_->first_fatal_ = true;
+ } else {
+ data_ = &fatal_msg_data_shared;
+ data_->first_fatal_ = false;
+ }
+ }
+
+ stream().fill('0');
+ data_->preserved_errno_ = errno;
+ data_->severity_ = severity;
+ data_->line_ = line;
+ data_->send_method_ = send_method;
+ data_->sink_ = NULL;
+ data_->outvec_ = NULL;
+ WallTime now = WallTime_Now();
+ data_->timestamp_ = static_cast<time_t>(now);
+ localtime_r(&data_->timestamp_, &data_->tm_time_);
+ int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
+ RawLog__SetLastTime(data_->tm_time_, usecs);
+
+ data_->num_chars_to_log_ = 0;
+ data_->num_chars_to_syslog_ = 0;
+ data_->basename_ = const_basename(file);
+ data_->fullname_ = file;
+ data_->has_been_flushed_ = false;
+
+ // If specified, prepend a prefix to each line. For example:
+ // I1018 160715 f5d4fbb0 logging.cc:1153]
+ // (log level, GMT month, date, time, thread_id, file basename, line)
+ // We exclude the thread_id for the default thread.
+ if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
+ stream() << LogSeverityNames[severity][0]
+ << setw(2) << 1+data_->tm_time_.tm_mon
+ << setw(2) << data_->tm_time_.tm_mday
+ << ' '
+ << setw(2) << data_->tm_time_.tm_hour << ':'
+ << setw(2) << data_->tm_time_.tm_min << ':'
+ << setw(2) << data_->tm_time_.tm_sec << "."
+ << setw(6) << usecs
+ << ' '
+ << setfill(' ') << setw(5)
+ << static_cast<unsigned int>(GetTID()) << setfill('0')
+ << ' '
+ << data_->basename_ << ':' << data_->line_ << "] ";
+ }
+ data_->num_prefix_chars_ = data_->stream_.pcount();
+
+ if (!FLAGS_log_backtrace_at.empty()) {
+ char fileline[128];
+ snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
+#ifdef HAVE_STACKTRACE
+ if (!strcmp(FLAGS_log_backtrace_at.c_str(), fileline)) {
+ string stacktrace;
+ DumpStackTraceToString(&stacktrace);
+ stream() << " (stacktrace:\n" << stacktrace << ") ";
+ }
+#endif
+ }
+}
+
+LogMessage::~LogMessage() {
+ Flush();
+ delete allocated_;
+}
+
+int LogMessage::preserved_errno() const {
+ return data_->preserved_errno_;
+}
+
+ostream& LogMessage::stream() {
+ return data_->stream_;
+}
+
+// Flush buffered message, called by the destructor, or any other function
+// that needs to synchronize the log.
+void LogMessage::Flush() {
+ if (data_->has_been_flushed_ || data_->severity_ < FLAGS_minloglevel)
+ return;
+
+ data_->num_chars_to_log_ = data_->stream_.pcount();
+ data_->num_chars_to_syslog_ =
+ data_->num_chars_to_log_ - data_->num_prefix_chars_;
+
+ // Do we need to add a \n to the end of this message?
+ bool append_newline =
+ (data_->message_text_[data_->num_chars_to_log_-1] != '\n');
+ char original_final_char = '\0';
+
+ // If we do need to add a \n, we'll do it by violating the memory of the
+ // ostrstream buffer. This is quick, and we'll make sure to undo our
+ // modification before anything else is done with the ostrstream. It
+ // would be preferable not to do things this way, but it seems to be
+ // the best way to deal with this.
+ if (append_newline) {
+ original_final_char = data_->message_text_[data_->num_chars_to_log_];
+ data_->message_text_[data_->num_chars_to_log_++] = '\n';
+ }
+
+ // Prevent any subtle race conditions by wrapping a mutex lock around
+ // the actual logging action per se.
+ {
+ MutexLock l(&log_mutex);
+ (this->*(data_->send_method_))();
+ ++num_messages_[static_cast<int>(data_->severity_)];
+ }
+ LogDestination::WaitForSinks(data_);
+
+ if (append_newline) {
+ // Fix the ostrstream back how it was before we screwed with it.
+ // It's 99.44% certain that we don't need to worry about doing this.
+ data_->message_text_[data_->num_chars_to_log_-1] = original_final_char;
+ }
+
+ // If errno was already set before we enter the logging call, we'll
+ // set it back to that value when we return from the logging call.
+ // It happens often that we log an error message after a syscall
+ // failure, which can potentially set the errno to some other
+ // values. We would like to preserve the original errno.
+ if (data_->preserved_errno_ != 0) {
+ errno = data_->preserved_errno_;
+ }
+
+ // Note that this message is now safely logged. If we're asked to flush
+ // again, as a result of destruction, say, we'll do nothing on future calls.
+ data_->has_been_flushed_ = true;
+}
+
+// Copy of first FATAL log message so that we can print it out again
+// after all the stack traces. To preserve legacy behavior, we don't
+// use fatal_msg_data_exclusive.
+static time_t fatal_time;
+static char fatal_message[256];
+
+void ReprintFatalMessage() {
+ if (fatal_message[0]) {
+ const int n = strlen(fatal_message);
+ if (!FLAGS_logtostderr) {
+ // Also write to stderr (don't color to avoid terminal checks)
+ WriteToStderr(fatal_message, n);
+ }
+ LogDestination::LogToAllLogfiles(GLOG_ERROR, fatal_time, fatal_message, n);
+ }
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ static bool already_warned_before_initgoogle = false;
+
+ log_mutex.AssertHeld();
+
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+
+ // Messages of a given severity get logged to lower severity logs, too
+
+ if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {
+ const char w[] = "WARNING: Logging before InitGoogleLogging() is "
+ "written to STDERR\n";
+ WriteToStderr(w, strlen(w));
+ already_warned_before_initgoogle = true;
+ }
+
+ // global flag: never log to file if set. Also -- don't log to a
+ // file if we haven't parsed the command line flags to get the
+ // program name.
+ if (FLAGS_logtostderr || !IsGoogleLoggingInitialized()) {
+ ColoredWriteToStderr(data_->severity_,
+ data_->message_text_, data_->num_chars_to_log_);
+
+ // this could be protected by a flag if necessary.
+ LogDestination::LogToSinks(data_->severity_,
+ data_->fullname_, data_->basename_,
+ data_->line_, &data_->tm_time_,
+ data_->message_text_ + data_->num_prefix_chars_,
+ (data_->num_chars_to_log_ -
+ data_->num_prefix_chars_ - 1));
+ } else {
+
+ // log this message to all log files of severity <= severity_
+ LogDestination::LogToAllLogfiles(data_->severity_, data_->timestamp_,
+ data_->message_text_,
+ data_->num_chars_to_log_);
+
+ LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,
+ data_->num_chars_to_log_);
+ LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
+ data_->num_chars_to_log_);
+ LogDestination::LogToSinks(data_->severity_,
+ data_->fullname_, data_->basename_,
+ data_->line_, &data_->tm_time_,
+ data_->message_text_ + data_->num_prefix_chars_,
+ (data_->num_chars_to_log_
+ - data_->num_prefix_chars_ - 1));
+ // NOTE: -1 removes trailing \n
+ }
+
+ // If we log a FATAL message, flush all the log destinations, then toss
+ // a signal for others to catch. We leave the logs in a state that
+ // someone else can use them (as long as they flush afterwards)
+ if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {
+ if (data_->first_fatal_) {
+ // Store crash information so that it is accessible from within signal
+ // handlers that may be invoked later.
+ RecordCrashReason(&crash_reason);
+ SetCrashReason(&crash_reason);
+
+ // Store shortened fatal message for other logs and GWQ status
+ const int copy = min<int>(data_->num_chars_to_log_,
+ sizeof(fatal_message)-1);
+ memcpy(fatal_message, data_->message_text_, copy);
+ fatal_message[copy] = '\0';
+ fatal_time = data_->timestamp_;
+ }
+
+ if (!FLAGS_logtostderr) {
+ for (int i = 0; i < NUM_SEVERITIES; ++i) {
+ if ( LogDestination::log_destinations_[i] )
+ LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
+ }
+ }
+
+ // release the lock that our caller (directly or indirectly)
+ // LogMessage::~LogMessage() grabbed so that signal handlers
+ // can use the logging facility. Alternately, we could add
+ // an entire unsafe logging interface to bypass locking
+ // for signal handlers but this seems simpler.
+ log_mutex.Unlock();
+ LogDestination::WaitForSinks(data_);
+
+ const char* message = "*** Check failure stack trace: ***\n";
+ if (write(STDERR_FILENO, message, strlen(message)) < 0) {
+ // Ignore errors.
+ }
+ Fail();
+ }
+}
+
+void LogMessage::RecordCrashReason(
+ glog_internal_namespace_::CrashReason* reason) {
+ reason->filename = fatal_msg_data_exclusive.fullname_;
+ reason->line_number = fatal_msg_data_exclusive.line_;
+ reason->message = fatal_msg_data_exclusive.message_text_ +
+ fatal_msg_data_exclusive.num_prefix_chars_;
+#ifdef HAVE_STACKTRACE
+ // Retrieve the stack trace, omitting the logging frames that got us here.
+ reason->depth = GetStackTrace(reason->stack, ARRAYSIZE(reason->stack), 4);
+#else
+ reason->depth = 0;
+#endif
+}
+
+#ifdef HAVE___ATTRIBUTE__
+# define ATTRIBUTE_NORETURN __attribute__((noreturn))
+#else
+# define ATTRIBUTE_NORETURN
+#endif
+
+static void logging_fail() ATTRIBUTE_NORETURN;
+
+static void logging_fail() {
+#if defined(_DEBUG) && defined(_MSC_VER)
+ // When debugging on windows, avoid the obnoxious dialog and make
+ // it possible to continue past a LOG(FATAL) in the debugger
+ __debugbreak();
+#else
+ abort();
+#endif
+}
+
+typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
+
+GOOGLE_GLOG_DLL_DECL
+logging_fail_func_t g_logging_fail_func = &logging_fail;
+
+void InstallFailureFunction(void (*fail_func)()) {
+ g_logging_fail_func = (logging_fail_func_t)fail_func;
+}
+
+void LogMessage::Fail() {
+ g_logging_fail_func();
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ if (data_->sink_ != NULL) {
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+ data_->sink_->send(data_->severity_, data_->fullname_, data_->basename_,
+ data_->line_, &data_->tm_time_,
+ data_->message_text_ + data_->num_prefix_chars_,
+ (data_->num_chars_to_log_ -
+ data_->num_prefix_chars_ - 1));
+ }
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ SendToSink();
+ SendToLog();
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ if (data_->outvec_ != NULL) {
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+ // Omit prefix of message and trailing newline when recording in outvec_.
+ const char *start = data_->message_text_ + data_->num_prefix_chars_;
+ int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
+ data_->outvec_->push_back(string(start, len));
+ } else {
+ SendToLog();
+ }
+}
+
+void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+ if (data_->message_ != NULL) {
+ RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+ data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+ // Omit prefix of message and trailing newline when writing to message_.
+ const char *start = data_->message_text_ + data_->num_prefix_chars_;
+ int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
+ data_->message_->assign(start, len);
+ }
+ SendToLog();
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSyslogAndLog() {
+#ifdef HAVE_SYSLOG_H
+ // Before any calls to syslog(), make a single call to openlog()
+ static bool openlog_already_called = false;
+ if (!openlog_already_called) {
+ openlog(glog_internal_namespace_::ProgramInvocationShortName(),
+ LOG_CONS | LOG_NDELAY | LOG_PID,
+ LOG_USER);
+ openlog_already_called = true;
+ }
+
+ // This array maps Google severity levels to syslog levels
+ const int SEVERITY_TO_LEVEL[] = { LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG };
+ syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)], "%.*s",
+ int(data_->num_chars_to_syslog_),
+ data_->message_text_ + data_->num_prefix_chars_);
+ SendToLog();
+#else
+ LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
+#endif
+}
+
+base::Logger* base::GetLogger(LogSeverity severity) {
+ MutexLock l(&log_mutex);
+ return LogDestination::log_destination(severity)->logger_;
+}
+
+void base::SetLogger(LogSeverity severity, base::Logger* logger) {
+ MutexLock l(&log_mutex);
+ LogDestination::log_destination(severity)->logger_ = logger;
+}
+
+// L < log_mutex. Acquires and releases mutex_.
+int64 LogMessage::num_messages(int severity) {
+ MutexLock l(&log_mutex);
+ return num_messages_[severity];
+}
+
+// Output the COUNTER value. This is only valid if ostream is a
+// LogStream.
+ostream& operator<<(ostream &os, const PRIVATE_Counter&) {
+#ifdef DISABLE_RTTI
+ LogMessage::LogStream *log = static_cast<LogMessage::LogStream*>(&os);
+#else
+ LogMessage::LogStream *log = dynamic_cast<LogMessage::LogStream*>(&os);
+#endif
+ CHECK(log && log == log->self())
+ << "You must not use COUNTER with non-glog ostream";
+ os << log->ctr();
+ return os;
+}
+
+ErrnoLogMessage::ErrnoLogMessage(const char* file, int line,
+ LogSeverity severity, int ctr,
+ void (LogMessage::*send_method)())
+ : LogMessage(file, line, severity, ctr, send_method) {
+}
+
+ErrnoLogMessage::~ErrnoLogMessage() {
+ // Don't access errno directly because it may have been altered
+ // while streaming the message.
+ stream() << ": " << StrError(preserved_errno()) << " ["
+ << preserved_errno() << "]";
+}
+
+void FlushLogFiles(LogSeverity min_severity) {
+ LogDestination::FlushLogFiles(min_severity);
+}
+
+void FlushLogFilesUnsafe(LogSeverity min_severity) {
+ LogDestination::FlushLogFilesUnsafe(min_severity);
+}
+
+void SetLogDestination(LogSeverity severity, const char* base_filename) {
+ LogDestination::SetLogDestination(severity, base_filename);
+}
+
+void SetLogSymlink(LogSeverity severity, const char* symlink_basename) {
+ LogDestination::SetLogSymlink(severity, symlink_basename);
+}
+
+LogSink::~LogSink() {
+}
+
+void LogSink::WaitTillSent() {
+ // noop default
+}
+
+string LogSink::ToString(LogSeverity severity, const char* file, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) {
+ ostringstream stream(string(message, message_len));
+ stream.fill('0');
+
+ // FIXME(jrvb): Updating this to use the correct value for usecs
+ // requires changing the signature for both this method and
+ // LogSink::send(). This change needs to be done in a separate CL
+ // so subclasses of LogSink can be updated at the same time.
+ int usecs = 0;
+
+ stream << LogSeverityNames[severity][0]
+ << setw(2) << 1+tm_time->tm_mon
+ << setw(2) << tm_time->tm_mday
+ << ' '
+ << setw(2) << tm_time->tm_hour << ':'
+ << setw(2) << tm_time->tm_min << ':'
+ << setw(2) << tm_time->tm_sec << '.'
+ << setw(6) << usecs
+ << ' '
+ << setfill(' ') << setw(5) << GetTID() << setfill('0')
+ << ' '
+ << file << ':' << line << "] ";
+
+ stream << string(message, message_len);
+ return stream.str();
+}
+
+void AddLogSink(LogSink *destination) {
+ LogDestination::AddLogSink(destination);
+}
+
+void RemoveLogSink(LogSink *destination) {
+ LogDestination::RemoveLogSink(destination);
+}
+
+void SetLogFilenameExtension(const char* ext) {
+ LogDestination::SetLogFilenameExtension(ext);
+}
+
+void SetStderrLogging(LogSeverity min_severity) {
+ LogDestination::SetStderrLogging(min_severity);
+}
+
+void SetEmailLogging(LogSeverity min_severity, const char* addresses) {
+ LogDestination::SetEmailLogging(min_severity, addresses);
+}
+
+void LogToStderr() {
+ LogDestination::LogToStderr();
+}
+
+namespace base {
+namespace internal {
+
+bool GetExitOnDFatal();
+bool GetExitOnDFatal() {
+ MutexLock l(&log_mutex);
+ return exit_on_dfatal;
+}
+
+// Determines whether we exit the program for a LOG(DFATAL) message in
+// debug mode. It does this by skipping the call to Fail/FailQuietly.
+// This is intended for testing only.
+//
+// This can have some effects on LOG(FATAL) as well. Failure messages
+// are always allocated (rather than sharing a buffer), the crash
+// reason is not recorded, the "gwq" status message is not updated,
+// and the stack trace is not recorded. The LOG(FATAL) *will* still
+// exit the program. Since this function is used only in testing,
+// these differences are acceptable.
+void SetExitOnDFatal(bool value);
+void SetExitOnDFatal(bool value) {
+ MutexLock l(&log_mutex);
+ exit_on_dfatal = value;
+}
+
+} // namespace internal
+} // namespace base
+
+// use_logging controls whether the logging functions LOG/VLOG are used
+// to log errors. It should be set to false when the caller holds the
+// log_mutex.
+static bool SendEmailInternal(const char*dest, const char *subject,
+ const char*body, bool use_logging) {
+ if (dest && *dest) {
+ if ( use_logging ) {
+ VLOG(1) << "Trying to send TITLE:" << subject
+ << " BODY:" << body << " to " << dest;
+ } else {
+ fprintf(stderr, "Trying to send TITLE: %s BODY: %s to %s\n",
+ subject, body, dest);
+ }
+
+ string cmd =
+ FLAGS_logmailer + " -s\"" + subject + "\" " + dest;
+ FILE* pipe = popen(cmd.c_str(), "w");
+ if (pipe != NULL) {
+ // Add the body if we have one
+ if (body)
+ fwrite(body, sizeof(char), strlen(body), pipe);
+ bool ok = pclose(pipe) != -1;
+ if ( !ok ) {
+ if ( use_logging ) {
+ LOG(ERROR) << "Problems sending mail to " << dest << ": "
+ << StrError(errno);
+ } else {
+ fprintf(stderr, "Problems sending mail to %s: %s\n",
+ dest, StrError(errno).c_str());
+ }
+ }
+ return ok;
+ } else {
+ if ( use_logging ) {
+ LOG(ERROR) << "Unable to send mail to " << dest;
+ } else {
+ fprintf(stderr, "Unable to send mail to %s\n", dest);
+ }
+ }
+ }
+ return false;
+}
+
+bool SendEmail(const char*dest, const char *subject, const char*body){
+ return SendEmailInternal(dest, subject, body, true);
+}
+
+static void GetTempDirectories(vector<string>* list) {
+ list->clear();
+#ifdef OS_WINDOWS
+ // On windows we'll try to find a directory in this order:
+ // C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)
+ // C:/TMP/
+ // C:/TEMP/
+ // C:/WINDOWS/ or C:/WINNT/
+ // .
+ char tmp[MAX_PATH];
+ if (GetTempPathA(MAX_PATH, tmp))
+ list->push_back(tmp);
+ list->push_back("C:\\tmp\\");
+ list->push_back("C:\\temp\\");
+#else
+ // Directories, in order of preference. If we find a dir that
+ // exists, we stop adding other less-preferred dirs
+ const char * candidates[] = {
+ // Non-null only during unittest/regtest
+ getenv("TEST_TMPDIR"),
+
+ // Explicitly-supplied temp dirs
+ getenv("TMPDIR"), getenv("TMP"),
+
+ // If all else fails
+ "/tmp",
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE(candidates); i++) {
+ const char *d = candidates[i];
+ if (!d) continue; // Empty env var
+
+ // Make sure we don't surprise anyone who's expecting a '/'
+ string dstr = d;
+ if (dstr[dstr.size() - 1] != '/') {
+ dstr += "/";
+ }
+ list->push_back(dstr);
+
+ struct stat statbuf;
+ if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {
+ // We found a dir that exists - we're done.
+ return;
+ }
+ }
+
+#endif
+}
+
+static vector<string>* logging_directories_list;
+
+const vector<string>& GetLoggingDirectories() {
+ // Not strictly thread-safe but we're called early in InitGoogle().
+ if (logging_directories_list == NULL) {
+ logging_directories_list = new vector<string>;
+
+ if ( !FLAGS_log_dir.empty() ) {
+ // A dir was specified, we should use it
+ logging_directories_list->push_back(FLAGS_log_dir.c_str());
+ } else {
+ GetTempDirectories(logging_directories_list);
+#ifdef OS_WINDOWS
+ char tmp[MAX_PATH];
+ if (GetWindowsDirectoryA(tmp, MAX_PATH))
+ logging_directories_list->push_back(tmp);
+ logging_directories_list->push_back(".\\");
+#else
+ logging_directories_list->push_back("./");
+#endif
+ }
+ }
+ return *logging_directories_list;
+}
+
+void TestOnly_ClearLoggingDirectoriesList() {
+ fprintf(stderr, "TestOnly_ClearLoggingDirectoriesList should only be "
+ "called from test code.\n");
+ delete logging_directories_list;
+ logging_directories_list = NULL;
+}
+
+void GetExistingTempDirectories(vector<string>* list) {
+ GetTempDirectories(list);
+ vector<string>::iterator i_dir = list->begin();
+ while( i_dir != list->end() ) {
+ // zero arg to access means test for existence; no constant
+ // defined on windows
+ if ( access(i_dir->c_str(), 0) ) {
+ i_dir = list->erase(i_dir);
+ } else {
+ ++i_dir;
+ }
+ }
+}
+
+void TruncateLogFile(const char *path, int64 limit, int64 keep) {
+#ifdef HAVE_UNISTD_H
+ struct stat statbuf;
+ const int kCopyBlockSize = 8 << 10;
+ char copybuf[kCopyBlockSize];
+ int64 read_offset, write_offset;
+ // Don't follow symlinks unless they're our own fd symlinks in /proc
+ int flags = O_RDWR;
+ // TODO(hamaji): Support other environments.
+#ifdef OS_LINUX
+ const char *procfd_prefix = "/proc/self/fd/";
+ if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;
+#endif
+
+ int fd = open(path, flags);
+ if (fd == -1) {
+ if (errno == EFBIG) {
+ // The log file in question has got too big for us to open. The
+ // real fix for this would be to compile logging.cc (or probably
+ // all of base/...) with -D_FILE_OFFSET_BITS=64 but that's
+ // rather scary.
+ // Instead just truncate the file to something we can manage
+ if (truncate(path, 0) == -1) {
+ PLOG(ERROR) << "Unable to truncate " << path;
+ } else {
+ LOG(ERROR) << "Truncated " << path << " due to EFBIG error";
+ }
+ } else {
+ PLOG(ERROR) << "Unable to open " << path;
+ }
+ return;
+ }
+
+ if (fstat(fd, &statbuf) == -1) {
+ PLOG(ERROR) << "Unable to fstat()";
+ goto out_close_fd;
+ }
+
+ // See if the path refers to a regular file bigger than the
+ // specified limit
+ if (!S_ISREG(statbuf.st_mode)) goto out_close_fd;
+ if (statbuf.st_size <= limit) goto out_close_fd;
+ if (statbuf.st_size <= keep) goto out_close_fd;
+
+ // This log file is too large - we need to truncate it
+ LOG(INFO) << "Truncating " << path << " to " << keep << " bytes";
+
+ // Copy the last "keep" bytes of the file to the beginning of the file
+ read_offset = statbuf.st_size - keep;
+ write_offset = 0;
+ int bytesin, bytesout;
+ while ((bytesin = pread(fd, copybuf, sizeof(copybuf), read_offset)) > 0) {
+ bytesout = pwrite(fd, copybuf, bytesin, write_offset);
+ if (bytesout == -1) {
+ PLOG(ERROR) << "Unable to write to " << path;
+ break;
+ } else if (bytesout != bytesin) {
+ LOG(ERROR) << "Expected to write " << bytesin << ", wrote " << bytesout;
+ }
+ read_offset += bytesin;
+ write_offset += bytesout;
+ }
+ if (bytesin == -1) PLOG(ERROR) << "Unable to read from " << path;
+
+ // Truncate the remainder of the file. If someone else writes to the
+ // end of the file after our last read() above, we lose their latest
+ // data. Too bad ...
+ if (ftruncate(fd, write_offset) == -1) {
+ PLOG(ERROR) << "Unable to truncate " << path;
+ }
+
+ out_close_fd:
+ close(fd);
+#else
+ LOG(ERROR) << "No log truncation support.";
+#endif
+}
+
+void TruncateStdoutStderr() {
+#ifdef HAVE_UNISTD_H
+ int64 limit = MaxLogSize() << 20;
+ int64 keep = 1 << 20;
+ TruncateLogFile("/proc/self/fd/1", limit, keep);
+ TruncateLogFile("/proc/self/fd/2", limit, keep);
+#else
+ LOG(ERROR) << "No log truncation support.";
+#endif
+}
+
+
+// Helper functions for string comparisons.
+#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
+ string* Check##func##expected##Impl(const char* s1, const char* s2, \
+ const char* names) { \
+ bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
+ if (equal == expected) return NULL; \
+ else { \
+ ostringstream ss; \
+ if (!s1) s1 = ""; \
+ if (!s2) s2 = ""; \
+ ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
+ return new string(ss.str()); \
+ } \
+ }
+DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
+DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
+DEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true)
+DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)
+#undef DEFINE_CHECK_STROP_IMPL
+
+int posix_strerror_r(int err, char *buf, size_t len) {
+ // Sanity check input parameters
+ if (buf == NULL || len <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Reset buf and errno, and try calling whatever version of strerror_r()
+ // is implemented by glibc
+ buf[0] = '\000';
+ int old_errno = errno;
+ errno = 0;
+ char *rc = reinterpret_cast<char *>(strerror_r(err, buf, len));
+
+ // Both versions set errno on failure
+ if (errno) {
+ // Should already be there, but better safe than sorry
+ buf[0] = '\000';
+ return -1;
+ }
+ errno = old_errno;
+
+ // POSIX is vague about whether the string will be terminated, although
+ // is indirectly implies that typically ERANGE will be returned, instead
+ // of truncating the string. This is different from the GNU implementation.
+ // We play it safe by always terminating the string explicitly.
+ buf[len-1] = '\000';
+
+ // If the function succeeded, we can use its exit code to determine the
+ // semantics implemented by glibc
+ if (!rc) {
+ return 0;
+ } else {
+ // GNU semantics detected
+ if (rc == buf) {
+ return 0;
+ } else {
+ buf[0] = '\000';
+#if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
+ if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
+ // This means an error on MacOSX or FreeBSD.
+ return -1;
+ }
+#endif
+ strncat(buf, rc, len-1);
+ return 0;
+ }
+ }
+}
+
+string StrError(int err) {
+ char buf[100];
+ int rc = posix_strerror_r(err, buf, sizeof(buf));
+ if ((rc < 0) || (buf[0] == '\000')) {
+ snprintf(buf, sizeof(buf), "Error number %d", err);
+ }
+ return buf;
+}
+
+LogMessageFatal::LogMessageFatal(const char* file, int line) :
+ LogMessage(file, line, GLOG_FATAL) {}
+
+LogMessageFatal::LogMessageFatal(const char* file, int line,
+ const CheckOpString& result) :
+ LogMessage(file, line, result) {}
+
+LogMessageFatal::~LogMessageFatal() {
+ Flush();
+ LogMessage::Fail();
+}
+
+namespace base {
+
+CheckOpMessageBuilder::CheckOpMessageBuilder(const char *exprtext)
+ : stream_(new ostringstream) {
+ *stream_ << exprtext << " (";
+}
+
+CheckOpMessageBuilder::~CheckOpMessageBuilder() {
+ delete stream_;
+}
+
+ostream* CheckOpMessageBuilder::ForVar2() {
+ *stream_ << " vs. ";
+ return stream_;
+}
+
+string* CheckOpMessageBuilder::NewString() {
+ *stream_ << ")";
+ return new string(stream_->str());
+}
+
+} // namespace base
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const char& v) {
+ if (v >= 32 && v <= 126) {
+ (*os) << "'" << v << "'";
+ } else {
+ (*os) << "char value " << (short)v;
+ }
+}
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
+ if (v >= 32 && v <= 126) {
+ (*os) << "'" << v << "'";
+ } else {
+ (*os) << "signed char value " << (short)v;
+ }
+}
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
+ if (v >= 32 && v <= 126) {
+ (*os) << "'" << v << "'";
+ } else {
+ (*os) << "unsigned char value " << (unsigned short)v;
+ }
+}
+
+void InitGoogleLogging(const char* argv0) {
+ glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
+}
+
+void ShutdownGoogleLogging() {
+ glog_internal_namespace_::ShutdownGoogleLoggingUtilities();
+ LogDestination::DeleteLogDestinations();
+ delete logging_directories_list;
+ logging_directories_list = NULL;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/raw_logging.cc b/extern/glog/src/raw_logging.cc
index 7a7409bbf34..7a7409bbf34 100644
--- a/extern/libmv/third_party/glog/src/raw_logging.cc
+++ b/extern/glog/src/raw_logging.cc
diff --git a/extern/glog/src/signalhandler.cc b/extern/glog/src/signalhandler.cc
new file mode 100644
index 00000000000..a7aef8b99d2
--- /dev/null
+++ b/extern/glog/src/signalhandler.cc
@@ -0,0 +1,375 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// Implementation of InstallFailureSignalHandler().
+
+#include "utilities.h"
+#include "stacktrace.h"
+#include "symbolize.h"
+#include "glog/logging.h"
+
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_UCONTEXT_H
+# include <ucontext.h>
+#endif
+#ifdef HAVE_SYS_UCONTEXT_H
+# include <sys/ucontext.h>
+#endif
+#include <algorithm>
+
+_START_GOOGLE_NAMESPACE_
+
+// TOOD(hamaji): Use signal instead of sigaction?
+#ifdef HAVE_SIGACTION
+
+namespace {
+
+// We'll install the failure signal handler for these signals. We could
+// use strsignal() to get signal names, but we don't use it to avoid
+// introducing yet another #ifdef complication.
+//
+// The list should be synced with the comment in signalhandler.h.
+const struct {
+ int number;
+ const char *name;
+} kFailureSignals[] = {
+ { SIGSEGV, "SIGSEGV" },
+ { SIGILL, "SIGILL" },
+ { SIGFPE, "SIGFPE" },
+ { SIGABRT, "SIGABRT" },
+ { SIGBUS, "SIGBUS" },
+ { SIGTERM, "SIGTERM" },
+};
+
+// Returns the program counter from signal context, NULL if unknown.
+void* GetPC(void* ucontext_in_void) {
+#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
+ if (ucontext_in_void != NULL) {
+ ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
+ return (void*)context->PC_FROM_UCONTEXT;
+ }
+#endif
+ return NULL;
+}
+
+// The class is used for formatting error messages. We don't use printf()
+// as it's not async signal safe.
+class MinimalFormatter {
+ public:
+ MinimalFormatter(char *buffer, int size)
+ : buffer_(buffer),
+ cursor_(buffer),
+ end_(buffer + size) {
+ }
+
+ // Returns the number of bytes written in the buffer.
+ int num_bytes_written() const { return cursor_ - buffer_; }
+
+ // Appends string from "str" and updates the internal cursor.
+ void AppendString(const char* str) {
+ int i = 0;
+ while (str[i] != '\0' && cursor_ + i < end_) {
+ cursor_[i] = str[i];
+ ++i;
+ }
+ cursor_ += i;
+ }
+
+ // Formats "number" in "radix" and updates the internal cursor.
+ // Lowercase letters are used for 'a' - 'z'.
+ void AppendUint64(uint64 number, int radix) {
+ int i = 0;
+ while (cursor_ + i < end_) {
+ const int tmp = number % radix;
+ number /= radix;
+ cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
+ ++i;
+ if (number == 0) {
+ break;
+ }
+ }
+ // Reverse the bytes written.
+ std::reverse(cursor_, cursor_ + i);
+ cursor_ += i;
+ }
+
+ // Formats "number" as hexadecimal number, and updates the internal
+ // cursor. Padding will be added in front if needed.
+ void AppendHexWithPadding(uint64 number, int width) {
+ char* start = cursor_;
+ AppendString("0x");
+ AppendUint64(number, 16);
+ // Move to right and add padding in front if needed.
+ if (cursor_ < start + width) {
+ const int64 delta = start + width - cursor_;
+ std::copy(start, cursor_, start + delta);
+ std::fill(start, start + delta, ' ');
+ cursor_ = start + width;
+ }
+ }
+
+ private:
+ char *buffer_;
+ char *cursor_;
+ const char * const end_;
+};
+
+// Writes the given data with the size to the standard error.
+void WriteToStderr(const char* data, int size) {
+ if (write(STDERR_FILENO, data, size) < 0) {
+ // Ignore errors.
+ }
+}
+
+// The writer function can be changed by InstallFailureWriter().
+void (*g_failure_writer)(const char* data, int size) = WriteToStderr;
+
+// Dumps time information. We don't dump human-readable time information
+// as localtime() is not guaranteed to be async signal safe.
+void DumpTimeInfo() {
+ time_t time_in_sec = time(NULL);
+ char buf[256]; // Big enough for time info.
+ MinimalFormatter formatter(buf, sizeof(buf));
+ formatter.AppendString("*** Aborted at ");
+ formatter.AppendUint64(time_in_sec, 10);
+ formatter.AppendString(" (unix time)");
+ formatter.AppendString(" try \"date -d @");
+ formatter.AppendUint64(time_in_sec, 10);
+ formatter.AppendString("\" if you are using GNU date ***\n");
+ g_failure_writer(buf, formatter.num_bytes_written());
+}
+
+// Dumps information about the signal to STDERR.
+void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
+ // Get the signal name.
+ const char* signal_name = NULL;
+ for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
+ if (signal_number == kFailureSignals[i].number) {
+ signal_name = kFailureSignals[i].name;
+ }
+ }
+
+ char buf[256]; // Big enough for signal info.
+ MinimalFormatter formatter(buf, sizeof(buf));
+
+ formatter.AppendString("*** ");
+ if (signal_name) {
+ formatter.AppendString(signal_name);
+ } else {
+ // Use the signal number if the name is unknown. The signal name
+ // should be known, but just in case.
+ formatter.AppendString("Signal ");
+ formatter.AppendUint64(signal_number, 10);
+ }
+ formatter.AppendString(" (@0x");
+ formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
+ formatter.AppendString(")");
+ formatter.AppendString(" received by PID ");
+ formatter.AppendUint64(getpid(), 10);
+ formatter.AppendString(" (TID 0x");
+ // We assume pthread_t is an integral number or a pointer, rather
+ // than a complex struct. In some environments, pthread_self()
+ // returns an uint64 but in some other environments pthread_self()
+ // returns a pointer. Hence we use C-style cast here, rather than
+ // reinterpret/static_cast, to support both types of environments.
+ formatter.AppendUint64((uintptr_t)pthread_self(), 16);
+ formatter.AppendString(") ");
+ // Only linux has the PID of the signal sender in si_pid.
+#ifdef OS_LINUX
+ formatter.AppendString("from PID ");
+ formatter.AppendUint64(siginfo->si_pid, 10);
+ formatter.AppendString("; ");
+#endif
+ formatter.AppendString("stack trace: ***\n");
+ g_failure_writer(buf, formatter.num_bytes_written());
+}
+
+// Dumps information about the stack frame to STDERR.
+void DumpStackFrameInfo(const char* prefix, void* pc) {
+ // Get the symbol name.
+ const char *symbol = "(unknown)";
+ char symbolized[1024]; // Big enough for a sane symbol.
+ // Symbolizes the previous address of pc because pc may be in the
+ // next function.
+ if (Symbolize(reinterpret_cast<char *>(pc) - 1,
+ symbolized, sizeof(symbolized))) {
+ symbol = symbolized;
+ }
+
+ char buf[1024]; // Big enough for stack frame info.
+ MinimalFormatter formatter(buf, sizeof(buf));
+
+ formatter.AppendString(prefix);
+ formatter.AppendString("@ ");
+ const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
+ formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
+ formatter.AppendString(" ");
+ formatter.AppendString(symbol);
+ formatter.AppendString("\n");
+ g_failure_writer(buf, formatter.num_bytes_written());
+}
+
+// Invoke the default signal handler.
+void InvokeDefaultSignalHandler(int signal_number) {
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_handler = SIG_DFL;
+ sigaction(signal_number, &sig_action, NULL);
+ kill(getpid(), signal_number);
+}
+
+// This variable is used for protecting FailureSignalHandler() from
+// dumping stuff while another thread is doing it. Our policy is to let
+// the first thread dump stuff and let other threads wait.
+// See also comments in FailureSignalHandler().
+static pthread_t* g_entered_thread_id_pointer = NULL;
+
+// Dumps signal and stack frame information, and invokes the default
+// signal handler once our job is done.
+void FailureSignalHandler(int signal_number,
+ siginfo_t *signal_info,
+ void *ucontext) {
+ // First check if we've already entered the function. We use an atomic
+ // compare and swap operation for platforms that support it. For other
+ // platforms, we use a naive method that could lead to a subtle race.
+
+ // We assume pthread_self() is async signal safe, though it's not
+ // officially guaranteed.
+ pthread_t my_thread_id = pthread_self();
+ // NOTE: We could simply use pthread_t rather than pthread_t* for this,
+ // if pthread_self() is guaranteed to return non-zero value for thread
+ // ids, but there is no such guarantee. We need to distinguish if the
+ // old value (value returned from __sync_val_compare_and_swap) is
+ // different from the original value (in this case NULL).
+ pthread_t* old_thread_id_pointer =
+ glog_internal_namespace_::sync_val_compare_and_swap(
+ &g_entered_thread_id_pointer,
+ static_cast<pthread_t*>(NULL),
+ &my_thread_id);
+ if (old_thread_id_pointer != NULL) {
+ // We've already entered the signal handler. What should we do?
+ if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
+ // It looks the current thread is reentering the signal handler.
+ // Something must be going wrong (maybe we are reentering by another
+ // type of signal?). Kill ourself by the default signal handler.
+ InvokeDefaultSignalHandler(signal_number);
+ }
+ // Another thread is dumping stuff. Let's wait until that thread
+ // finishes the job and kills the process.
+ while (true) {
+ sleep(1);
+ }
+ }
+ // This is the first time we enter the signal handler. We are going to
+ // do some interesting stuff from here.
+ // TODO(satorux): We might want to set timeout here using alarm(), but
+ // mixing alarm() and sleep() can be a bad idea.
+
+ // First dump time info.
+ DumpTimeInfo();
+
+ // Get the program counter from ucontext.
+ void *pc = GetPC(ucontext);
+ DumpStackFrameInfo("PC: ", pc);
+
+#ifdef HAVE_STACKTRACE
+ // Get the stack traces.
+ void *stack[32];
+ // +1 to exclude this function.
+ const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
+ DumpSignalInfo(signal_number, signal_info);
+ // Dump the stack traces.
+ for (int i = 0; i < depth; ++i) {
+ DumpStackFrameInfo(" ", stack[i]);
+ }
+#endif
+
+ // *** TRANSITION ***
+ //
+ // BEFORE this point, all code must be async-termination-safe!
+ // (See WARNING above.)
+ //
+ // AFTER this point, we do unsafe things, like using LOG()!
+ // The process could be terminated or hung at any time. We try to
+ // do more useful things first and riskier things later.
+
+ // Flush the logs before we do anything in case 'anything'
+ // causes problems.
+ FlushLogFilesUnsafe(0);
+
+ // Kill ourself by the default signal handler.
+ InvokeDefaultSignalHandler(signal_number);
+}
+
+} // namespace
+
+#endif // HAVE_SIGACTION
+
+namespace glog_internal_namespace_ {
+
+bool IsFailureSignalHandlerInstalled() {
+#ifdef HAVE_SIGACTION
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sigaction(SIGABRT, NULL, &sig_action);
+ if (sig_action.sa_sigaction == &FailureSignalHandler)
+ return true;
+#endif // HAVE_SIGACTION
+ return false;
+}
+
+} // namespace glog_internal_namespace_
+
+void InstallFailureSignalHandler() {
+#ifdef HAVE_SIGACTION
+ // Build the sigaction struct.
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_flags |= SA_SIGINFO;
+ sig_action.sa_sigaction = &FailureSignalHandler;
+
+ for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
+ CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
+ }
+#endif // HAVE_SIGACTION
+}
+
+void InstallFailureWriter(void (*writer)(const char* data, int size)) {
+#ifdef HAVE_SIGACTION
+ g_failure_writer = writer;
+#endif // HAVE_SIGACTION
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/stacktrace.h b/extern/glog/src/stacktrace.h
index 8c3e8fe8f8d..8c3e8fe8f8d 100644
--- a/extern/libmv/third_party/glog/src/stacktrace.h
+++ b/extern/glog/src/stacktrace.h
diff --git a/extern/libmv/third_party/glog/src/stacktrace_generic-inl.h b/extern/glog/src/stacktrace_generic-inl.h
index fad81d3e3f4..fad81d3e3f4 100644
--- a/extern/libmv/third_party/glog/src/stacktrace_generic-inl.h
+++ b/extern/glog/src/stacktrace_generic-inl.h
diff --git a/extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h b/extern/glog/src/stacktrace_libunwind-inl.h
index 0dc14c6506e..0dc14c6506e 100644
--- a/extern/libmv/third_party/glog/src/stacktrace_libunwind-inl.h
+++ b/extern/glog/src/stacktrace_libunwind-inl.h
diff --git a/extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h b/extern/glog/src/stacktrace_powerpc-inl.h
index 1090ddedbc7..1090ddedbc7 100644
--- a/extern/libmv/third_party/glog/src/stacktrace_powerpc-inl.h
+++ b/extern/glog/src/stacktrace_powerpc-inl.h
diff --git a/extern/libmv/third_party/glog/src/stacktrace_x86-inl.h b/extern/glog/src/stacktrace_x86-inl.h
index cfd31f783e3..cfd31f783e3 100644
--- a/extern/libmv/third_party/glog/src/stacktrace_x86-inl.h
+++ b/extern/glog/src/stacktrace_x86-inl.h
diff --git a/extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h b/extern/glog/src/stacktrace_x86_64-inl.h
index f7d1dca85bc..f7d1dca85bc 100644
--- a/extern/libmv/third_party/glog/src/stacktrace_x86_64-inl.h
+++ b/extern/glog/src/stacktrace_x86_64-inl.h
diff --git a/extern/glog/src/symbolize.cc b/extern/glog/src/symbolize.cc
new file mode 100644
index 00000000000..6211e85e5db
--- /dev/null
+++ b/extern/glog/src/symbolize.cc
@@ -0,0 +1,848 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+// Stack-footprint reduction work done by Raksit Ashok
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks. We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym) = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym) = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses
+// some functions which are not guaranteed to be so, such as memchr()
+// and memmove(). We assume they are async-signal-safe.
+//
+// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
+// macro to add platform specific defines (e.g. OS_OPENBSD).
+
+#ifdef GLOG_BUILD_CONFIG_INCLUDE
+#include GLOG_BUILD_CONFIG_INCLUDE
+#endif // GLOG_BUILD_CONFIG_INCLUDE
+
+#include "utilities.h"
+
+#if defined(HAVE_SYMBOLIZE)
+
+#include <limits>
+
+#include "symbolize.h"
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe. Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+
+// A wrapper for abort() to make it callable in ? :.
+static int AssertFail() {
+ abort();
+ return 0; // Should not reach.
+}
+
+#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
+
+static SymbolizeCallback g_symbolize_callback = NULL;
+void InstallSymbolizeCallback(SymbolizeCallback callback) {
+ g_symbolize_callback = callback;
+}
+
+static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
+ NULL;
+void InstallSymbolizeOpenObjectFileCallback(
+ SymbolizeOpenObjectFileCallback callback) {
+ g_symbolize_open_object_file_callback = callback;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
+ char demangled[256]; // Big enough for sane demangled symbols.
+ if (Demangle(out, demangled, sizeof(demangled))) {
+ // Demangling succeeded. Copy to out if the space allows.
+ size_t len = strlen(demangled);
+ if (len + 1 <= (size_t)out_size) { // +1 for '\0'.
+ SAFE_ASSERT(len < sizeof(demangled));
+ memmove(out, demangled, len + 1);
+ }
+ }
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#if defined(__ELF__)
+
+#include <dlfcn.h>
+#if defined(OS_OPENBSD)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "symbolize.h"
+#include "config.h"
+#include "glog/raw_logging.h"
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
+
+_START_GOOGLE_NAMESPACE_
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR. On
+// success, return the number of bytes read. Otherwise, return -1.
+static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+ SAFE_ASSERT(fd >= 0);
+ SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
+ char *buf0 = reinterpret_cast<char *>(buf);
+ ssize_t num_bytes = 0;
+ while (num_bytes < count) {
+ ssize_t len;
+ NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+ if (len < 0) { // There was an error other than EINTR.
+ return -1;
+ }
+ if (len == 0) { // Reached EOF.
+ break;
+ }
+ num_bytes += len;
+ }
+ SAFE_ASSERT(num_bytes <= count);
+ return num_bytes;
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf". On success,
+// return the number of bytes read. Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf,
+ const size_t count, const off_t offset) {
+ off_t off = lseek(fd, offset, SEEK_SET);
+ if (off == (off_t)-1) {
+ return -1;
+ }
+ return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR. On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf,
+ const size_t count, const off_t offset) {
+ ssize_t len = ReadFromOffset(fd, buf, count, offset);
+ return len == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return -1;
+ }
+ if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+ return -1;
+ }
+ return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true. Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
+ ElfW(Word) type, ElfW(Shdr) *out) {
+ // Read at most 16 section headers at a time to save read calls.
+ ElfW(Shdr) buf[16];
+ for (int i = 0; i < sh_num;) {
+ const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+ const ssize_t num_bytes_to_read =
+ (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
+ const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
+ sh_offset + i * sizeof(buf[0]));
+ SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+ const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+ SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
+ for (int j = 0; j < num_headers_in_buf; ++j) {
+ if (buf[j].sh_type == type) {
+ *out = buf[j];
+ return true;
+ }
+ }
+ i += num_headers_in_buf;
+ }
+ return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+ ElfW(Shdr) *out) {
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return false;
+ }
+
+ ElfW(Shdr) shstrtab;
+ off_t shstrtab_offset = (elf_header.e_shoff +
+ elf_header.e_shentsize * elf_header.e_shstrndx);
+ if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+ return false;
+ }
+
+ for (int i = 0; i < elf_header.e_shnum; ++i) {
+ off_t section_header_offset = (elf_header.e_shoff +
+ elf_header.e_shentsize * i);
+ if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+ return false;
+ }
+ char header_name[kMaxSectionNameLen];
+ if (sizeof(header_name) < name_len) {
+ RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
+ "section will not be found (even if present).", name, name_len);
+ // No point in even trying.
+ return false;
+ }
+ off_t name_offset = shstrtab.sh_offset + out->sh_name;
+ ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+ if (n_read == -1) {
+ return false;
+ } else if (n_read != name_len) {
+ // Short read -- name could be at end of file.
+ continue;
+ }
+ if (memcmp(header_name, name, name_len) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc". On success, return true and write the symbol name
+// to out. Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
+ uint64_t symbol_offset, const ElfW(Shdr) *strtab,
+ const ElfW(Shdr) *symtab) {
+ if (symtab == NULL) {
+ return false;
+ }
+ const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+ for (int i = 0; i < num_symbols;) {
+ off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+
+ // If we are reading Elf64_Sym's, we want to limit this array to
+ // 32 elements (to keep stack consumption low), otherwise we can
+ // have a 64 element Elf32_Sym array.
+#if __WORDSIZE == 64
+#define NUM_SYMBOLS 32
+#else
+#define NUM_SYMBOLS 64
+#endif
+
+ // Read at most NUM_SYMBOLS symbols at once to save read() calls.
+ ElfW(Sym) buf[NUM_SYMBOLS];
+ const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+ SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+ const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+ SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+ for (int j = 0; j < num_symbols_in_buf; ++j) {
+ const ElfW(Sym)& symbol = buf[j];
+ uint64_t start_address = symbol.st_value;
+ start_address += symbol_offset;
+ uint64_t end_address = start_address + symbol.st_size;
+ if (symbol.st_value != 0 && // Skip null value symbols.
+ symbol.st_shndx != 0 && // Skip undefined symbols.
+ start_address <= pc && pc < end_address) {
+ ssize_t len1 = ReadFromOffset(fd, out, out_size,
+ strtab->sh_offset + symbol.st_name);
+ if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+ return false;
+ }
+ return true; // Obtained the symbol name.
+ }
+ }
+ i += num_symbols_in_buf;
+ }
+ return false;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd". Process
+// both regular and dynamic symbol tables if necessary. On success,
+// write the symbol name to "out" and return true. Otherwise, return
+// false.
+static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
+ char *out, int out_size,
+ uint64_t map_start_address) {
+ // Read the ELF header.
+ ElfW(Ehdr) elf_header;
+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+ return false;
+ }
+
+ uint64_t symbol_offset = 0;
+ if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
+ symbol_offset = map_start_address;
+ }
+
+ ElfW(Shdr) symtab, strtab;
+
+ // Consult a regular symbol table first.
+ if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+ SHT_SYMTAB, &symtab)) {
+ if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+ symtab.sh_link * sizeof(symtab))) {
+ return false;
+ }
+ if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+ &strtab, &symtab)) {
+ return true; // Found the symbol in a regular symbol table.
+ }
+ }
+
+ // If the symbol is not found, then consult a dynamic symbol table.
+ if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+ SHT_DYNSYM, &symtab)) {
+ if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+ symtab.sh_link * sizeof(symtab))) {
+ return false;
+ }
+ if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+ &strtab, &symtab)) {
+ return true; // Found the symbol in a dynamic symbol table.
+ }
+ }
+
+ return false;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+struct FileDescriptor {
+ const int fd_;
+ explicit FileDescriptor(int fd) : fd_(fd) {}
+ ~FileDescriptor() {
+ if (fd_ >= 0) {
+ NO_INTR(close(fd_));
+ }
+ }
+ int get() { return fd_; }
+
+ private:
+ explicit FileDescriptor(const FileDescriptor&);
+ void operator=(const FileDescriptor&);
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+ explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
+ buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
+ }
+
+ // Read '\n'-terminated line from file. On success, modify "bol"
+ // and "eol", then return true. Otherwise, return false.
+ //
+ // Note: if the last line doesn't end with '\n', the line will be
+ // dropped. It's an intentional behavior to make the code simple.
+ bool ReadLine(const char **bol, const char **eol) {
+ if (BufferIsEmpty()) { // First time.
+ const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+ if (num_bytes <= 0) { // EOF or error.
+ return false;
+ }
+ eod_ = buf_ + num_bytes;
+ bol_ = buf_;
+ } else {
+ bol_ = eol_ + 1; // Advance to the next line in the buffer.
+ SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
+ if (!HasCompleteLine()) {
+ const int incomplete_line_length = eod_ - bol_;
+ // Move the trailing incomplete line to the beginning.
+ memmove(buf_, bol_, incomplete_line_length);
+ // Read text from file and append it.
+ char * const append_pos = buf_ + incomplete_line_length;
+ const int capacity_left = buf_len_ - incomplete_line_length;
+ const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
+ capacity_left);
+ if (num_bytes <= 0) { // EOF or error.
+ return false;
+ }
+ eod_ = append_pos + num_bytes;
+ bol_ = buf_;
+ }
+ }
+ eol_ = FindLineFeed();
+ if (eol_ == NULL) { // '\n' not found. Malformed line.
+ return false;
+ }
+ *eol_ = '\0'; // Replace '\n' with '\0'.
+
+ *bol = bol_;
+ *eol = eol_;
+ return true;
+ }
+
+ // Beginning of line.
+ const char *bol() {
+ return bol_;
+ }
+
+ // End of line.
+ const char *eol() {
+ return eol_;
+ }
+
+ private:
+ explicit LineReader(const LineReader&);
+ void operator=(const LineReader&);
+
+ char *FindLineFeed() {
+ return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+ }
+
+ bool BufferIsEmpty() {
+ return buf_ == eod_;
+ }
+
+ bool HasCompleteLine() {
+ return !BufferIsEmpty() && FindLineFeed() != NULL;
+ }
+
+ const int fd_;
+ char * const buf_;
+ const int buf_len_;
+ char *bol_;
+ char *eol_;
+ const char *eod_; // End of data in "buf_".
+};
+} // namespace
+
+// Place the hex number read from "start" into "*hex". The pointer to
+// the first non-hex character or "end" is returned.
+static char *GetHex(const char *start, const char *end, uint64_t *hex) {
+ *hex = 0;
+ const char *p;
+ for (p = start; p < end; ++p) {
+ int ch = *p;
+ if ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
+ *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+ } else { // Encountered the first non-hex character.
+ break;
+ }
+ }
+ SAFE_ASSERT(p <= end);
+ return const_cast<char *>(p);
+}
+
+// Searches for the object file (from /proc/self/maps) that contains
+// the specified pc. If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file. If the object
+// file is opened successfully, returns the file descriptor. Otherwise,
+// returns -1. |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
+static ATTRIBUTE_NOINLINE int
+OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
+ uint64_t &start_address,
+ uint64_t &base_address,
+ char *out_file_name,
+ int out_file_name_size) {
+ int object_fd;
+
+ // Open /proc/self/maps.
+ int maps_fd;
+ NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
+ FileDescriptor wrapped_maps_fd(maps_fd);
+ if (wrapped_maps_fd.get() < 0) {
+ return -1;
+ }
+
+ // Iterate over maps and look for the map containing the pc. Then
+ // look into the symbol tables inside.
+ char buf[1024]; // Big enough for line of sane /proc/self/maps
+ int num_maps = 0;
+ LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+ while (true) {
+ num_maps++;
+ const char *cursor;
+ const char *eol;
+ if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
+ return -1;
+ }
+
+ // Start parsing line in /proc/self/maps. Here is an example:
+ //
+ // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
+ //
+ // We want start address (08048000), end address (0804c000), flags
+ // (r-xp) and file name (/bin/cat).
+
+ // Read start address.
+ cursor = GetHex(cursor, eol, &start_address);
+ if (cursor == eol || *cursor != '-') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip '-'.
+
+ // Read end address.
+ uint64_t end_address;
+ cursor = GetHex(cursor, eol, &end_address);
+ if (cursor == eol || *cursor != ' ') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip ' '.
+
+ // Check start and end addresses.
+ if (!(start_address <= pc && pc < end_address)) {
+ continue; // We skip this map. PC isn't in this map.
+ }
+
+ // Read flags. Skip flags until we encounter a space or eol.
+ const char * const flags_start = cursor;
+ while (cursor < eol && *cursor != ' ') {
+ ++cursor;
+ }
+ // We expect at least four letters for flags (ex. "r-xp").
+ if (cursor == eol || cursor < flags_start + 4) {
+ return -1; // Malformed line.
+ }
+
+ // Check flags. We are only interested in "r-x" maps.
+ if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
+ continue; // We skip this map.
+ }
+ ++cursor; // Skip ' '.
+
+ // Read file offset.
+ uint64_t file_offset;
+ cursor = GetHex(cursor, eol, &file_offset);
+ if (cursor == eol || *cursor != ' ') {
+ return -1; // Malformed line.
+ }
+ ++cursor; // Skip ' '.
+
+ // Don't subtract 'start_address' from the first entry:
+ // * If a binary is compiled w/o -pie, then the first entry in
+ // process maps is likely the binary itself (all dynamic libs
+ // are mapped higher in address space). For such a binary,
+ // instruction offset in binary coincides with the actual
+ // instruction address in virtual memory (as code section
+ // is mapped to a fixed memory range).
+ // * If a binary is compiled with -pie, all the modules are
+ // mapped high at address space (in particular, higher than
+ // shadow memory of the tool), so the module can't be the
+ // first entry.
+ base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
+
+ // Skip to file name. "cursor" now points to dev. We need to
+ // skip at least two spaces for dev and inode.
+ int num_spaces = 0;
+ while (cursor < eol) {
+ if (*cursor == ' ') {
+ ++num_spaces;
+ } else if (num_spaces >= 2) {
+ // The first non-space character after skipping two spaces
+ // is the beginning of the file name.
+ break;
+ }
+ ++cursor;
+ }
+ if (cursor == eol) {
+ return -1; // Malformed line.
+ }
+
+ // Finally, "cursor" now points to file name of our interest.
+ NO_INTR(object_fd = open(cursor, O_RDONLY));
+ if (object_fd < 0) {
+ // Failed to open object file. Copy the object file name to
+ // |out_file_name|.
+ strncpy(out_file_name, cursor, out_file_name_size);
+ // Making sure |out_file_name| is always null-terminated.
+ out_file_name[out_file_name_size - 1] = '\0';
+ return -1;
+ }
+ return object_fd;
+ }
+}
+
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+static char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+ // Make sure we can write at least one NUL byte.
+ size_t n = 1;
+ if (n > sz)
+ return NULL;
+
+ if (base < 2 || base > 16) {
+ buf[0] = '\000';
+ return NULL;
+ }
+
+ char *start = buf;
+
+ uintptr_t j = i;
+
+ // Handle negative numbers (only for base 10).
+ if (i < 0 && base == 10) {
+ j = -i;
+
+ // Make sure we can write the '-' character.
+ if (++n > sz) {
+ buf[0] = '\000';
+ return NULL;
+ }
+ *start++ = '-';
+ }
+
+ // Loop until we have converted the entire number. Output at least one
+ // character (i.e. '0').
+ char *ptr = start;
+ do {
+ // Make sure there is still enough space left in our output buffer.
+ if (++n > sz) {
+ buf[0] = '\000';
+ return NULL;
+ }
+
+ // Output the next digit.
+ *ptr++ = "0123456789abcdef"[j % base];
+ j /= base;
+
+ if (padding > 0)
+ padding--;
+ } while (j > 0 || padding > 0);
+
+ // Terminate the output with a NUL character.
+ *ptr = '\000';
+
+ // Conversion to ASCII actually resulted in the digits being in reverse
+ // order. We can't easily generate them in forward order, as we can't tell
+ // the number of characters needed until we are done converting.
+ // So, now, we reverse the string (except for the possible "-" sign).
+ while (--ptr > start) {
+ char ch = *ptr;
+ *ptr = *start;
+ *start++ = ch;
+ }
+ return buf;
+}
+
+// Safely appends string |source| to string |dest|. Never writes past the
+// buffer size |dest_size| and guarantees that |dest| is null-terminated.
+static void SafeAppendString(const char* source, char* dest, int dest_size) {
+ int dest_string_length = strlen(dest);
+ SAFE_ASSERT(dest_string_length < dest_size);
+ dest += dest_string_length;
+ dest_size -= dest_string_length;
+ strncpy(dest, source, dest_size);
+ // Making sure |dest| is always null-terminated.
+ dest[dest_size - 1] = '\0';
+}
+
+// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
+// Never writes past the buffer size |dest_size| and guarantees that |dest| is
+// null-terminated.
+static void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
+ // 64-bit numbers in hex can have up to 16 digits.
+ char buf[17] = {'\0'};
+ SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
+}
+
+// The implementation of our symbolization routine. If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns true and write the symbol name to "out".
+// Otherwise, returns false. If Callback function is installed via
+// InstallSymbolizeCallback(), the function is also called in this function,
+// and "out" is used as its output.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+ int out_size) {
+ uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
+ uint64_t start_address = 0;
+ uint64_t base_address = 0;
+ int object_fd = -1;
+
+ if (out_size < 1) {
+ return false;
+ }
+ out[0] = '\0';
+ SafeAppendString("(", out, out_size);
+
+ if (g_symbolize_open_object_file_callback) {
+ object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
+ base_address, out + 1,
+ out_size - 1);
+ } else {
+ object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
+ base_address,
+ out + 1,
+ out_size - 1);
+ }
+
+ // Check whether a file name was returned.
+ if (object_fd < 0) {
+ if (out[1]) {
+ // The object file containing PC was determined successfully however the
+ // object file was not opened successfully. This is still considered
+ // success because the object file name and offset are known and tools
+ // like asan_symbolize.py can be used for the symbolization.
+ out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
+ SafeAppendString("+0x", out, out_size);
+ SafeAppendHexNumber(pc0 - base_address, out, out_size);
+ SafeAppendString(")", out, out_size);
+ return true;
+ }
+ // Failed to determine the object file containing PC. Bail out.
+ return false;
+ }
+ FileDescriptor wrapped_object_fd(object_fd);
+ int elf_type = FileGetElfType(wrapped_object_fd.get());
+ if (elf_type == -1) {
+ return false;
+ }
+ if (g_symbolize_callback) {
+ // Run the call back if it's installed.
+ // Note: relocation (and much of the rest of this code) will be
+ // wrong for prelinked shared libraries and PIE executables.
+ uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+ int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
+ pc, out, out_size,
+ relocation);
+ if (num_bytes_written > 0) {
+ out += num_bytes_written;
+ out_size -= num_bytes_written;
+ }
+ }
+ if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
+ out, out_size, start_address)) {
+ return false;
+ }
+
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+
+#include <dlfcn.h>
+#include <string.h>
+
+_START_GOOGLE_NAMESPACE_
+
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+ int out_size) {
+ Dl_info info;
+ if (dladdr(pc, &info)) {
+ if ((int)strlen(info.dli_sname) < out_size) {
+ strcpy(out, info.dli_sname);
+ // Symbolization succeeded. Now we try to demangle the symbol.
+ DemangleInplace(out, out_size);
+ return true;
+ }
+ }
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else
+# error BUG: HAVE_SYMBOLIZE was wrongly set
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+bool Symbolize(void *pc, char *out, int out_size) {
+ SAFE_ASSERT(out_size >= 0);
+ return SymbolizeAndDemangle(pc, out, out_size);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else /* HAVE_SYMBOLIZE */
+
+#include <assert.h>
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// TODO: Support other environments.
+bool Symbolize(void *pc, char *out, int out_size) {
+ assert(0);
+ return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/extern/libmv/third_party/glog/src/symbolize.h b/extern/glog/src/symbolize.h
index f617184249c..f617184249c 100644
--- a/extern/libmv/third_party/glog/src/symbolize.h
+++ b/extern/glog/src/symbolize.h
diff --git a/extern/glog/src/utilities.cc b/extern/glog/src/utilities.cc
new file mode 100644
index 00000000000..296fa7a67f3
--- /dev/null
+++ b/extern/glog/src/utilities.cc
@@ -0,0 +1,352 @@
+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Shinichiro Hamaji
+
+#include "utilities.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <signal.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <time.h>
+#if defined(HAVE_SYSCALL_H)
+#include <syscall.h> // for syscall()
+#elif defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h> // for syscall()
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "base/googleinit.h"
+
+using std::string;
+
+_START_GOOGLE_NAMESPACE_
+
+static const char* g_program_invocation_short_name = NULL;
+static pthread_t g_main_thread_id;
+
+_END_GOOGLE_NAMESPACE_
+
+// The following APIs are all internal.
+#ifdef HAVE_STACKTRACE
+
+#include "stacktrace.h"
+#include "symbolize.h"
+#include "base/commandlineflags.h"
+
+GLOG_DEFINE_bool(symbolize_stacktrace, true,
+ "Symbolize the stack trace in the tombstone");
+
+_START_GOOGLE_NAMESPACE_
+
+typedef void DebugWriter(const char*, void*);
+
+// The %p field width for printf() functions is two characters per byte.
+// For some environments, add two extra bytes for the leading "0x".
+static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
+
+static void DebugWriteToStderr(const char* data, void *) {
+ // This one is signal-safe.
+ if (write(STDERR_FILENO, data, strlen(data)) < 0) {
+ // Ignore errors.
+ }
+}
+
+static void DebugWriteToString(const char* data, void *arg) {
+ reinterpret_cast<string*>(arg)->append(data);
+}
+
+#ifdef HAVE_SYMBOLIZE
+// Print a program counter and its symbol name.
+static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
+ const char * const prefix) {
+ char tmp[1024];
+ const char *symbol = "(unknown)";
+ // Symbolizes the previous address of pc because pc may be in the
+ // next function. The overrun happens when the function ends with
+ // a call to a function annotated noreturn (e.g. CHECK).
+ if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
+ symbol = tmp;
+ }
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
+ prefix, kPrintfPointerFieldWidth, pc, symbol);
+ writerfn(buf, arg);
+}
+#endif
+
+static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
+ const char * const prefix) {
+ char buf[100];
+ snprintf(buf, sizeof(buf), "%s@ %*p\n",
+ prefix, kPrintfPointerFieldWidth, pc);
+ writerfn(buf, arg);
+}
+
+// Dump current stack trace as directed by writerfn
+static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
+ // Print stack trace
+ void* stack[32];
+ int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
+ for (int i = 0; i < depth; i++) {
+#if defined(HAVE_SYMBOLIZE)
+ if (FLAGS_symbolize_stacktrace) {
+ DumpPCAndSymbol(writerfn, arg, stack[i], " ");
+ } else {
+ DumpPC(writerfn, arg, stack[i], " ");
+ }
+#else
+ DumpPC(writerfn, arg, stack[i], " ");
+#endif
+ }
+}
+
+static void DumpStackTraceAndExit() {
+ DumpStackTrace(1, DebugWriteToStderr, NULL);
+
+ // TOOD(hamaji): Use signal instead of sigaction?
+#ifdef HAVE_SIGACTION
+ if (IsFailureSignalHandlerInstalled()) {
+ // Set the default signal handler for SIGABRT, to avoid invoking our
+ // own signal handler installed by InstallFailureSignalHandler().
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_handler = SIG_DFL;
+ sigaction(SIGABRT, &sig_action, NULL);
+ }
+#endif // HAVE_SIGACTION
+
+ abort();
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif // HAVE_STACKTRACE
+
+_START_GOOGLE_NAMESPACE_
+
+namespace glog_internal_namespace_ {
+
+const char* ProgramInvocationShortName() {
+ if (g_program_invocation_short_name != NULL) {
+ return g_program_invocation_short_name;
+ } else {
+ // TODO(hamaji): Use /proc/self/cmdline and so?
+ return "UNKNOWN";
+ }
+}
+
+bool IsGoogleLoggingInitialized() {
+ return g_program_invocation_short_name != NULL;
+}
+
+bool is_default_thread() {
+ if (g_program_invocation_short_name == NULL) {
+ // InitGoogleLogging() not yet called, so unlikely to be in a different
+ // thread
+ return true;
+ } else {
+ return pthread_equal(pthread_self(), g_main_thread_id);
+ }
+}
+
+#ifdef OS_WINDOWS
+struct timeval {
+ long tv_sec, tv_usec;
+};
+
+// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
+// See COPYING for copyright information.
+static int gettimeofday(struct timeval *tv, void* tz) {
+#define EPOCHFILETIME (116444736000000000ULL)
+ FILETIME ft;
+ LARGE_INTEGER li;
+ uint64 tt;
+
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ tt = (li.QuadPart - EPOCHFILETIME) / 10;
+ tv->tv_sec = tt / 1000000;
+ tv->tv_usec = tt % 1000000;
+
+ return 0;
+}
+#endif
+
+int64 CycleClock_Now() {
+ // TODO(hamaji): temporary impementation - it might be too slow.
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
+}
+
+int64 UsecToCycles(int64 usec) {
+ return usec;
+}
+
+WallTime WallTime_Now() {
+ // Now, cycle clock is retuning microseconds since the epoch.
+ return CycleClock_Now() * 0.000001;
+}
+
+static int32 g_main_thread_pid = getpid();
+int32 GetMainThreadPid() {
+ return g_main_thread_pid;
+}
+
+bool PidHasChanged() {
+ int32 pid = getpid();
+ if (g_main_thread_pid == pid) {
+ return false;
+ }
+ g_main_thread_pid = pid;
+ return true;
+}
+
+pid_t GetTID() {
+ // On Linux and MacOSX, we try to use gettid().
+#if defined OS_LINUX || defined OS_MACOSX
+#ifndef __NR_gettid
+#ifdef OS_MACOSX
+#define __NR_gettid SYS_gettid
+#elif ! defined __i386__
+#error "Must define __NR_gettid for non-x86 platforms"
+#else
+#define __NR_gettid 224
+#endif
+#endif
+ static bool lacks_gettid = false;
+ if (!lacks_gettid) {
+ pid_t tid = syscall(__NR_gettid);
+ if (tid != -1) {
+ return tid;
+ }
+ // Technically, this variable has to be volatile, but there is a small
+ // performance penalty in accessing volatile variables and there should
+ // not be any serious adverse effect if a thread does not immediately see
+ // the value change to "true".
+ lacks_gettid = true;
+ }
+#endif // OS_LINUX || OS_MACOSX
+
+ // If gettid() could not be used, we use one of the following.
+#if defined OS_LINUX
+ return getpid(); // Linux: getpid returns thread ID when gettid is absent
+#elif defined OS_WINDOWS || defined OS_CYGWIN
+ return GetCurrentThreadId();
+#else
+ // If none of the techniques above worked, we use pthread_self().
+ return (pid_t)(uintptr_t)pthread_self();
+#endif
+}
+
+const char* const_basename(const char* filepath) {
+ const char* base = strrchr(filepath, '/');
+#ifdef OS_WINDOWS // Look for either path separator in Windows
+ if (!base)
+ base = strrchr(filepath, '\\');
+#endif
+ return base ? (base+1) : filepath;
+}
+
+static string g_my_user_name;
+const string& MyUserName() {
+ return g_my_user_name;
+}
+static void MyUserNameInitializer() {
+ // TODO(hamaji): Probably this is not portable.
+#if defined(OS_WINDOWS)
+ const char* user = getenv("USERNAME");
+#else
+ const char* user = getenv("USER");
+#endif
+ if (user != NULL) {
+ g_my_user_name = user;
+ } else {
+ g_my_user_name = "invalid-user";
+ }
+}
+REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
+
+#ifdef HAVE_STACKTRACE
+void DumpStackTraceToString(string* stacktrace) {
+ DumpStackTrace(1, DebugWriteToString, stacktrace);
+}
+#endif
+
+// We use an atomic operation to prevent problems with calling CrashReason
+// from inside the Mutex implementation (potentially through RAW_CHECK).
+static const CrashReason* g_reason = 0;
+
+void SetCrashReason(const CrashReason* r) {
+ sync_val_compare_and_swap(&g_reason,
+ reinterpret_cast<const CrashReason*>(0),
+ r);
+}
+
+void InitGoogleLoggingUtilities(const char* argv0) {
+ CHECK(!IsGoogleLoggingInitialized())
+ << "You called InitGoogleLogging() twice!";
+ const char* slash = strrchr(argv0, '/');
+#ifdef OS_WINDOWS
+ if (!slash) slash = strrchr(argv0, '\\');
+#endif
+ g_program_invocation_short_name = slash ? slash + 1 : argv0;
+ g_main_thread_id = pthread_self();
+
+#ifdef HAVE_STACKTRACE
+ InstallFailureFunction(&DumpStackTraceAndExit);
+#endif
+}
+
+void ShutdownGoogleLoggingUtilities() {
+ CHECK(IsGoogleLoggingInitialized())
+ << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
+ g_program_invocation_short_name = NULL;
+#ifdef HAVE_SYSLOG_H
+ closelog();
+#endif
+}
+
+} // namespace glog_internal_namespace_
+
+_END_GOOGLE_NAMESPACE_
+
+// Make an implementation of stacktrace compiled.
+#ifdef STACKTRACE_H
+# include STACKTRACE_H
+#endif
diff --git a/extern/libmv/third_party/glog/src/utilities.h b/extern/glog/src/utilities.h
index 4f41c92e434..4f41c92e434 100644
--- a/extern/libmv/third_party/glog/src/utilities.h
+++ b/extern/glog/src/utilities.h
diff --git a/extern/glog/src/vlog_is_on.cc b/extern/glog/src/vlog_is_on.cc
new file mode 100644
index 00000000000..e8fdbae7dcb
--- /dev/null
+++ b/extern/glog/src/vlog_is_on.cc
@@ -0,0 +1,257 @@
+// Copyright (c) 1999, 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Ray Sidney and many others
+//
+// Broken out from logging.cc by Soren Lassen
+// logging_unittest.cc covers the functionality herein
+
+#include "utilities.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cstdio>
+#include <string>
+#include "base/commandlineflags.h"
+#include "glog/logging.h"
+#include "glog/raw_logging.h"
+#include "base/googleinit.h"
+
+// glog doesn't have annotation
+#define ANNOTATE_BENIGN_RACE(address, description)
+
+using std::string;
+
+GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
+" Overridable by --vmodule.");
+
+GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
+" Argument is a comma-separated list of <module name>=<log level>."
+" <module name> is a glob pattern, matched against the filename base"
+" (that is, name ignoring .cc/.h./-inl.h)."
+" <log level> overrides any value given by --v.");
+
+_START_GOOGLE_NAMESPACE_
+
+namespace glog_internal_namespace_ {
+
+// Used by logging_unittests.cc so can't make it static here.
+GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
+ size_t patt_len,
+ const char* str,
+ size_t str_len);
+
+// Implementation of fnmatch that does not need 0-termination
+// of arguments and does not allocate any memory,
+// but we only support "*" and "?" wildcards, not the "[...]" patterns.
+// It's not a static function for the unittest.
+GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
+ size_t patt_len,
+ const char* str,
+ size_t str_len) {
+ size_t p = 0;
+ size_t s = 0;
+ while (1) {
+ if (p == patt_len && s == str_len) return true;
+ if (p == patt_len) return false;
+ if (s == str_len) return p+1 == patt_len && pattern[p] == '*';
+ if (pattern[p] == str[s] || pattern[p] == '?') {
+ p += 1;
+ s += 1;
+ continue;
+ }
+ if (pattern[p] == '*') {
+ if (p+1 == patt_len) return true;
+ do {
+ if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
+ return true;
+ }
+ s += 1;
+ } while (s != str_len);
+ return false;
+ }
+ return false;
+ }
+}
+
+} // namespace glog_internal_namespace_
+
+using glog_internal_namespace_::SafeFNMatch_;
+
+int32 kLogSiteUninitialized = 1000;
+
+// List of per-module log levels from FLAGS_vmodule.
+// Once created each element is never deleted/modified
+// except for the vlog_level: other threads will read VModuleInfo blobs
+// w/o locks and we'll store pointers to vlog_level at VLOG locations
+// that will never go away.
+// We can't use an STL struct here as we wouldn't know
+// when it's safe to delete/update it: other threads need to use it w/o locks.
+struct VModuleInfo {
+ string module_pattern;
+ mutable int32 vlog_level; // Conceptually this is an AtomicWord, but it's
+ // too much work to use AtomicWord type here
+ // w/o much actual benefit.
+ const VModuleInfo* next;
+};
+
+// This protects the following global variables.
+static Mutex vmodule_lock;
+// Pointer to head of the VModuleInfo list.
+// It's a map from module pattern to logging level for those module(s).
+static VModuleInfo* vmodule_list = 0;
+// Boolean initialization flag.
+static bool inited_vmodule = false;
+
+// L >= vmodule_lock.
+static void VLOG2Initializer() {
+ vmodule_lock.AssertHeld();
+ // Can now parse --vmodule flag and initialize mapping of module-specific
+ // logging levels.
+ inited_vmodule = false;
+ const char* vmodule = FLAGS_vmodule.c_str();
+ const char* sep;
+ VModuleInfo* head = NULL;
+ VModuleInfo* tail = NULL;
+ while ((sep = strchr(vmodule, '=')) != NULL) {
+ string pattern(vmodule, sep - vmodule);
+ int module_level;
+ if (sscanf(sep, "=%d", &module_level) == 1) {
+ VModuleInfo* info = new VModuleInfo;
+ info->module_pattern = pattern;
+ info->vlog_level = module_level;
+ if (head) tail->next = info;
+ else head = info;
+ tail = info;
+ }
+ // Skip past this entry
+ vmodule = strchr(sep, ',');
+ if (vmodule == NULL) break;
+ vmodule++; // Skip past ","
+ }
+ if (head) { // Put them into the list at the head:
+ tail->next = vmodule_list;
+ vmodule_list = head;
+ }
+ inited_vmodule = true;
+}
+
+// This can be called very early, so we use SpinLock and RAW_VLOG here.
+int SetVLOGLevel(const char* module_pattern, int log_level) {
+ int result = FLAGS_v;
+ int const pattern_len = strlen(module_pattern);
+ bool found = false;
+ {
+ MutexLock l(&vmodule_lock); // protect whole read-modify-write
+ for (const VModuleInfo* info = vmodule_list;
+ info != NULL; info = info->next) {
+ if (info->module_pattern == module_pattern) {
+ if (!found) {
+ result = info->vlog_level;
+ found = true;
+ }
+ info->vlog_level = log_level;
+ } else if (!found &&
+ SafeFNMatch_(info->module_pattern.c_str(),
+ info->module_pattern.size(),
+ module_pattern, pattern_len)) {
+ result = info->vlog_level;
+ found = true;
+ }
+ }
+ if (!found) {
+ VModuleInfo* info = new VModuleInfo;
+ info->module_pattern = module_pattern;
+ info->vlog_level = log_level;
+ info->next = vmodule_list;
+ vmodule_list = info;
+ }
+ }
+ RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
+ return result;
+}
+
+// NOTE: Individual VLOG statements cache the integer log level pointers.
+// NOTE: This function must not allocate memory or require any locks.
+bool InitVLOG3__(int32** site_flag, int32* site_default,
+ const char* fname, int32 verbose_level) {
+ MutexLock l(&vmodule_lock);
+ bool read_vmodule_flag = inited_vmodule;
+ if (!read_vmodule_flag) {
+ VLOG2Initializer();
+ }
+
+ // protect the errno global in case someone writes:
+ // VLOG(..) << "The last error was " << strerror(errno)
+ int old_errno = errno;
+
+ // site_default normally points to FLAGS_v
+ int32* site_flag_value = site_default;
+
+ // Get basename for file
+ const char* base = strrchr(fname, '/');
+ base = base ? (base+1) : fname;
+ const char* base_end = strchr(base, '.');
+ size_t base_length = base_end ? size_t(base_end - base) : strlen(base);
+
+ // Trim out trailing "-inl" if any
+ if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
+ base_length -= 4;
+ }
+
+ // TODO: Trim out _unittest suffix? Perhaps it is better to have
+ // the extra control and just leave it there.
+
+ // find target in vector of modules, replace site_flag_value with
+ // a module-specific verbose level, if any.
+ for (const VModuleInfo* info = vmodule_list;
+ info != NULL; info = info->next) {
+ if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
+ base, base_length)) {
+ site_flag_value = &info->vlog_level;
+ // value at info->vlog_level is now what controls
+ // the VLOG at the caller site forever
+ break;
+ }
+ }
+
+ // Cache the vlog value pointer if --vmodule flag has been parsed.
+ ANNOTATE_BENIGN_RACE(site_flag,
+ "*site_flag may be written by several threads,"
+ " but the value will be the same");
+ if (read_vmodule_flag) *site_flag = site_flag_value;
+
+ // restore the errno in case something recoverable went wrong during
+ // the initialization of the VLOG mechanism (see above note "protect the..")
+ errno = old_errno;
+ return *site_flag_value >= verbose_level;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/extern/glog/src/windows/config.h b/extern/glog/src/windows/config.h
new file mode 100644
index 00000000000..1cc2533daa5
--- /dev/null
+++ b/extern/glog/src/windows/config.h
@@ -0,0 +1,28 @@
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* define if you have google gflags library */
+#define HAVE_LIB_GFLAGS 1
+
+/* Namespace for Google classes */
+#define GOOGLE_NAMESPACE google
+
+/* Stops putting the code inside the Google namespace */
+#define _END_GOOGLE_NAMESPACE_ }
+
+/* Puts following code inside the Google namespace */
+#define _START_GOOGLE_NAMESPACE_ namespace google {
+
+#if defined(__MINGW32__) || (defined(_MSC_VER) && (_MSC_VER >= 1900))
+# define HAVE_SNPRINTF
+#endif
+
+/* Always the empty-string on non-windows systems. On windows, should be
+ "__declspec(dllexport)". This way, when we compile the dll, we export our
+ functions/classes. It's safe to define this here because config.h is only
+ used internally, to compile the DLL, and every DLL source file #includes
+ "config.h" before anything else. */
+#ifndef GOOGLE_GLOG_DLL_DECL
+# define GOOGLE_GLOG_IS_A_DLL 1 /* not set if you're statically linking */
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllexport)
+# define GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS __declspec(dllimport)
+#endif
diff --git a/extern/libmv/third_party/glog/src/windows/glog/log_severity.h b/extern/glog/src/windows/glog/log_severity.h
index 22a4191ab8b..22a4191ab8b 100644
--- a/extern/libmv/third_party/glog/src/windows/glog/log_severity.h
+++ b/extern/glog/src/windows/glog/log_severity.h
diff --git a/extern/glog/src/windows/glog/logging.h b/extern/glog/src/windows/glog/logging.h
new file mode 100644
index 00000000000..50135329d77
--- /dev/null
+++ b/extern/glog/src/windows/glog/logging.h
@@ -0,0 +1,1616 @@
+// This file is automatically generated from src/glog/logging.h.in
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+
+// Copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Ray Sidney
+//
+// This file contains #include information about logging-related stuff.
+// Pretty much everybody needs to #include this file so that they can
+// log various happenings.
+//
+#ifndef _LOGGING_H_
+#define _LOGGING_H_
+
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <iosfwd>
+#include <ostream>
+#include <sstream>
+#include <string>
+#if 0
+# include <unistd.h>
+#endif
+#include <vector>
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef GOOGLE_GLOG_DLL_DECL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
+# else
+# define GOOGLE_GLOG_DLL_DECL
+# endif
+#endif
+#if defined(_MSC_VER)
+#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
+ __pragma(warning(disable:n))
+#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
+#else
+#define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
+#define GLOG_MSVC_POP_WARNING()
+#endif
+
+// We care a lot about number of bits things take up. Unfortunately,
+// systems define their bit-specific ints in a lot of different ways.
+// We use our own way, and have a typedef to get there.
+// Note: these commands below may look like "#if 1" or "#if 0", but
+// that's because they were constructed that way at ./configure time.
+// Look at logging.h.in to see how they're calculated (based on your config).
+#ifdef __MINGW32__
+#include <stdint.h> // the normal place uint16_t is defined
+#endif
+#ifdef __MINGW32__
+#include <sys/types.h> // the normal place u_int16_t is defined
+#endif
+#ifdef __MINGW32__
+#include <inttypes.h> // a third place for uint16_t or u_int16_t
+#endif
+
+#if 1
+#include <gflags/gflags.h>
+#endif
+
+#ifdef __MINGW32__
+# include <stdlib.h>
+# include <unistd.h>
+# define _exit(x) exit(x)
+#endif
+
+namespace google {
+
+#if defined(__MINGW32__) // the C99 format
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+#elif 0 // the BSD format
+typedef int32_t int32;
+typedef u_int32_t uint32;
+typedef int64_t int64;
+typedef u_int64_t uint64;
+#elif defined(_MSC_VER) // the windows (vc7) format
+typedef __int32 int32;
+typedef unsigned __int32 uint32;
+typedef __int64 int64;
+typedef unsigned __int64 uint64;
+#else
+#error Do not know how to define a 32-bit integer quantity on your system
+#endif
+
+}
+
+// The global value of GOOGLE_STRIP_LOG. All the messages logged to
+// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.
+// If it can be determined at compile time that the message will not be
+// printed, the statement will be compiled out.
+//
+// Example: to strip out all INFO and WARNING messages, use the value
+// of 2 below. To make an exception for WARNING messages from a single
+// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
+// base/logging.h
+#ifndef GOOGLE_STRIP_LOG
+#define GOOGLE_STRIP_LOG 0
+#endif
+
+// GCC can be told that a certain branch is not likely to be taken (for
+// instance, a CHECK failure), and use that information in static analysis.
+// Giving it this information can help it optimize for the common case in
+// the absence of better information (ie. -fprofile-arcs).
+//
+#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
+#if 0
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
+#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#else
+#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
+#define GOOGLE_PREDICT_FALSE(x) x
+#define GOOGLE_PREDICT_TRUE(x) x
+#endif
+#endif
+
+// Make a bunch of macros for logging. The way to log things is to stream
+// things to LOG(<a particular severity level>). E.g.,
+//
+// LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can capture log messages in a string, rather than reporting them
+// immediately:
+//
+// vector<string> errors;
+// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num;
+//
+// This pushes back the new error onto 'errors'; if given a NULL pointer,
+// it reports the error via LOG(ERROR).
+//
+// You can also do conditional logging:
+//
+// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// You can also do occasional logging (log every n'th occurrence of an
+// event):
+//
+// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed. Note that the special google::COUNTER value is used
+// to identify which repetition is happening.
+//
+// You can also do occasional conditional logging (log every n'th
+// occurrence of an event, when condition is satisfied):
+//
+// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
+// << "th big cookie";
+//
+// You can log messages the first N times your code executes a line. E.g.
+//
+// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
+//
+// Outputs log messages for the first 20 times it is executed.
+//
+// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.
+// These log to syslog as well as to the normal logs. If you use these at
+// all, you need to be aware that syslog can drastically reduce performance,
+// especially if it is configured for remote logging! Don't use these
+// unless you fully understand this and have a concrete need to use them.
+// Even then, try to minimize your use of them.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+// DLOG(INFO) << "Found cookies";
+//
+// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.
+//
+// We also have
+//
+// LOG_ASSERT(assertion);
+// DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}
+// b. VLOG(1) and lower messages to be printed from file.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs"
+// d. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character) wildcards.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level"
+// condition macros for sample cases, when some extra computation and
+// preparation for logs is not needed.
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+// VLOG_EVERY_N(1, 10)
+// << "I'm printed every 10th occurrence, and when you run the program "
+// "with --v=1 or more. Present occurence is " << google::COUNTER;
+// VLOG_IF_EVERY_N(1, (size > 1024), 10)
+// << "I'm printed on every 10th occurence of case when size is more "
+// " than 1024, when you run the program with --v=1 or more. ";
+// "Present occurence is " << google::COUNTER;
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+// Note that messages of a given severity are logged not only in the
+// logfile for that severity, but also in all logfiles of lower severity.
+// E.g., a message of severity FATAL will be logged to the logfiles of
+// severity FATAL, ERROR, WARNING, and INFO.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// Unless otherwise specified, logs will be written to the filename
+// "<program name>.<hostname>.<user name>.log.<severity level>.", followed
+// by the date, time, and pid (you can't prevent the date, time, and pid
+// from being in the filename).
+//
+// The logging code takes two flags:
+// --v=# set the verbose level
+// --logtostderr log all the messages to stderr instead of to logfiles
+
+// LOG LINE PREFIX FORMAT
+//
+// Log lines have this form:
+//
+// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+//
+// where the fields are defined as follows:
+//
+// L A single character, representing the log level
+// (eg 'I' for INFO)
+// mm The month (zero padded; ie May is '05')
+// dd The day (zero padded)
+// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
+// threadid The space-padded thread ID as returned by GetTID()
+// (this matches the PID on Linux)
+// file The file name
+// line The line number
+// msg The user-supplied message
+//
+// Example:
+//
+// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
+// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
+//
+// NOTE: although the microseconds are useful for comparing events on
+// a single machine, clocks on different machines may not be well
+// synchronized. Hence, use caution when comparing the low bits of
+// timestamps from different machines.
+
+#ifndef DECLARE_VARIABLE
+#define MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#define DECLARE_VARIABLE(type, shorttype, name, tn) \
+ namespace fL##shorttype { \
+ extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
+ } \
+ using fL##shorttype::FLAGS_##name
+
+// bool specialization
+#define DECLARE_bool(name) \
+ DECLARE_VARIABLE(bool, B, name, bool)
+
+// int32 specialization
+#define DECLARE_int32(name) \
+ DECLARE_VARIABLE(google::int32, I, name, int32)
+
+// Special case for string, because we have to specify the namespace
+// std::string, which doesn't play nicely with our FLAG__namespace hackery.
+#define DECLARE_string(name) \
+ namespace fLS { \
+ extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \
+ } \
+ using fLS::FLAGS_##name
+#endif
+
+// Set whether log messages go to stderr instead of logfiles
+DECLARE_bool(logtostderr);
+
+// Set whether log messages go to stderr in addition to logfiles.
+DECLARE_bool(alsologtostderr);
+
+// Set color messages logged to stderr (if supported by terminal).
+DECLARE_bool(colorlogtostderr);
+
+// Log messages at a level >= this flag are automatically sent to
+// stderr in addition to log files.
+DECLARE_int32(stderrthreshold);
+
+// Set whether the log prefix should be prepended to each line of output.
+DECLARE_bool(log_prefix);
+
+// Log messages at a level <= this flag are buffered.
+// Log messages at a higher level are flushed immediately.
+DECLARE_int32(logbuflevel);
+
+// Sets the maximum number of seconds which logs may be buffered for.
+DECLARE_int32(logbufsecs);
+
+// Log suppression level: messages logged at a lower level than this
+// are suppressed.
+DECLARE_int32(minloglevel);
+
+// If specified, logfiles are written into this directory instead of the
+// default logging directory.
+DECLARE_string(log_dir);
+
+// Sets the path of the directory into which to put additional links
+// to the log files.
+DECLARE_string(log_link);
+
+DECLARE_int32(v); // in vlog_is_on.cc
+
+// Sets the maximum log file size (in MB).
+DECLARE_int32(max_log_size);
+
+// Sets whether to avoid logging to the disk if the disk is full.
+DECLARE_bool(stop_logging_if_full_disk);
+
+#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS
+#undef DECLARE_VARIABLE
+#undef DECLARE_bool
+#undef DECLARE_int32
+#undef DECLARE_string
+#endif
+
+// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for
+// security reasons. See LOG(severtiy) below.
+
+// A few definitions of macros that don't generate much code. Since
+// LOG(INFO) and its ilk are used all over our code, it's
+// better to have compact code for these operations.
+
+#if GOOGLE_STRIP_LOG == 0
+#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_INFO(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_INFO, message)
+#else
+#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
+#define LOG_TO_STRING_INFO(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 1
+#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_WARNING)
+#define LOG_TO_STRING_WARNING(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_WARNING, message)
+#else
+#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
+#define LOG_TO_STRING_WARNING(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 2
+#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ERROR)
+#define LOG_TO_STRING_ERROR(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ERROR, message)
+#else
+#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
+#define LOG_TO_STRING_ERROR(message) google::NullStream()
+#endif
+
+#if GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \
+ __FILE__, __LINE__)
+#define LOG_TO_STRING_FATAL(message) google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_FATAL, message)
+#else
+#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
+#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
+#endif
+
+// For DFATAL, we want to use LogMessage (as opposed to
+// LogMessageFatal), to be consistent with the original behavior.
+#ifdef NDEBUG
+#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
+#elif GOOGLE_STRIP_LOG <= 3
+#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_FATAL)
+#else
+#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
+#endif
+
+#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog)
+#define SYSLOG_INFO(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_WARNING(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_ERROR(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_FATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+#define GOOGLE_LOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToLog)
+#define SYSLOG_DFATAL(counter) \
+ google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
+ &google::LogMessage::SendToSyslogAndLog)
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+// A very useful logging macro to log windows errors:
+#define LOG_SYSRESULT(result) \
+ if (FAILED(HRESULT_FROM_WIN32(result))) { \
+ LPSTR message = NULL; \
+ LPSTR msg = reinterpret_cast<LPSTR>(&message); \
+ DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
+ FORMAT_MESSAGE_FROM_SYSTEM, \
+ 0, result, 0, msg, 100, NULL); \
+ if (message_length > 0) { \
+ google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \
+ &google::LogMessage::SendToLog).stream() \
+ << reinterpret_cast<const char*>(message); \
+ LocalFree(message); \
+ } \
+ }
+#endif
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+#define SYSLOG(severity) SYSLOG_ ## severity(0).stream()
+
+namespace google {
+
+// They need the definitions of integer types.
+#include "glog/log_severity.h"
+#include "glog/vlog_is_on.h"
+
+// Initialize google's logging library. You will see the program name
+// specified by argv0 in log outputs.
+GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0);
+
+// Shutdown google's logging library.
+GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging();
+
+// Install a function which will be called after LOG(FATAL).
+GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)());
+
+class LogSink; // defined below
+
+// If a non-NULL sink pointer is given, we push this message to that sink.
+// For LOG_TO_SINK we then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and passing/storing them
+// somewhere more specific than the global log of the process.
+// Argument types:
+// LogSink* sink;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+#define LOG_TO_SINK(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::GLOG_ ## severity, \
+ static_cast<google::LogSink*>(sink), true).stream()
+#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \
+ google::LogMessage( \
+ __FILE__, __LINE__, \
+ google::GLOG_ ## severity, \
+ static_cast<google::LogSink*>(sink), false).stream()
+
+// If a non-NULL string pointer is given, we write this message to that string.
+// We then do normal LOG(severity) logging as well.
+// This is useful for capturing messages and storing them somewhere more
+// specific than the global log of the process.
+// Argument types:
+// string* message;
+// LogSeverity severity;
+// The cast is to disambiguate NULL arguments.
+// NOTE: LOG(severity) expands to LogMessage().stream() for the specified
+// severity.
+#define LOG_TO_STRING(severity, message) \
+ LOG_TO_STRING_##severity(static_cast<string*>(message)).stream()
+
+// If a non-NULL pointer is given, we push the message onto the end
+// of a vector of strings; otherwise, we report it with LOG(severity).
+// This is handy for capturing messages and perhaps passing them back
+// to the caller, rather than reporting them immediately.
+// Argument types:
+// LogSeverity severity;
+// vector<string> *outvec;
+// The cast is to disambiguate NULL arguments.
+#define LOG_STRING(severity, outvec) \
+ LOG_TO_STRING_##severity(static_cast<vector<string>*>(outvec)).stream()
+
+#define LOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+#define SYSLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+#define SYSLOG_ASSERT(condition) \
+ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode. Therefore, it is safe to do things like:
+// CHECK(fp->Write(x) == 4)
+#define CHECK(condition) \
+ LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A container for a string pointer which can be evaluated to a bool -
+// true iff the pointer is NULL.
+struct CheckOpString {
+ CheckOpString(std::string* str) : str_(str) { }
+ // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
+ // so there's no point in cleaning up str_.
+ operator bool() const {
+ return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL);
+ }
+ std::string* str_;
+};
+
+// Function is overloaded for integral types to allow static const
+// integrals declared in classes and not defined to be used as arguments to
+// CHECK* macros. It's not encouraged though.
+template <class T>
+inline const T& GetReferenceableValue(const T& t) { return t; }
+inline char GetReferenceableValue(char t) { return t; }
+inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
+inline signed char GetReferenceableValue(signed char t) { return t; }
+inline short GetReferenceableValue(short t) { return t; }
+inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
+inline int GetReferenceableValue(int t) { return t; }
+inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
+inline long GetReferenceableValue(long t) { return t; }
+inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
+inline long long GetReferenceableValue(long long t) { return t; }
+inline unsigned long long GetReferenceableValue(unsigned long long t) {
+ return t;
+}
+
+// This is a dummy class to define the following operator.
+struct DummyClassToDefineOperator {};
+
+}
+
+// Define global operator<< to declare using ::operator<<.
+// This declaration will allow use to use CHECK macros for user
+// defined classes which have operator<< (e.g., stl_logging.h).
+inline std::ostream& operator<<(
+ std::ostream& out, const google::DummyClassToDefineOperator&) {
+ return out;
+}
+
+namespace google {
+
+// This formats a value for a failing CHECK_XX statement. Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << v;
+}
+
+// Overrides for char types provide readable values for unprintable
+// characters.
+template <> GOOGLE_GLOG_DLL_DECL
+void MakeCheckOpValueString(std::ostream* os, const char& v);
+template <> GOOGLE_GLOG_DLL_DECL
+void MakeCheckOpValueString(std::ostream* os, const signed char& v);
+template <> GOOGLE_GLOG_DLL_DECL
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
+
+// Build the error message string. Specify no inlining for code size.
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
+ ;
+
+namespace base {
+namespace internal {
+
+// If "s" is less than base_logging::INFO, returns base_logging::INFO.
+// If "s" is greater than base_logging::FATAL, returns
+// base_logging::ERROR. Otherwise, returns "s".
+LogSeverity NormalizeSeverity(LogSeverity s);
+
+} // namespace internal
+
+// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
+// statement. See MakeCheckOpString for sample usage. Other
+// approaches were considered: use of a template method (e.g.,
+// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
+// base::Print<T2>, &v2), however this approach has complications
+// related to volatile arguments and function-pointer arguments).
+class GOOGLE_GLOG_DLL_DECL CheckOpMessageBuilder {
+ public:
+ // Inserts "exprtext" and " (" to the stream.
+ explicit CheckOpMessageBuilder(const char *exprtext);
+ // Deletes "stream_".
+ ~CheckOpMessageBuilder();
+ // For inserting the first variable.
+ std::ostream* ForVar1() { return stream_; }
+ // For inserting the second variable (adds an intermediate " vs. ").
+ std::ostream* ForVar2();
+ // Get the result (inserts the closing ")").
+ std::string* NewString();
+
+ private:
+ std::ostringstream *stream_;
+};
+
+} // namespace base
+
+template <typename T1, typename T2>
+std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
+ base::CheckOpMessageBuilder comb(exprtext);
+ MakeCheckOpValueString(comb.ForVar1(), v1);
+ MakeCheckOpValueString(comb.ForVar2(), v2);
+ return comb.NewString();
+}
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <typename T1, typename T2> \
+ inline std::string* name##Impl(const T1& v1, const T2& v2, \
+ const char* exprtext) { \
+ if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
+ else return MakeCheckOpString(v1, v2, exprtext); \
+ } \
+ inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
+ return name##Impl<int, int>(v1, v2, exprtext); \
+ }
+
+// We use the full name Check_EQ, Check_NE, etc. in case the file including
+// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
+// This happens if, for example, those are used as token names in a
+// yacc grammar.
+DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)?
+DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead.
+DEFINE_CHECK_OP_IMPL(Check_LE, <=)
+DEFINE_CHECK_OP_IMPL(Check_LT, < )
+DEFINE_CHECK_OP_IMPL(Check_GE, >=)
+DEFINE_CHECK_OP_IMPL(Check_GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+
+#if defined(STATIC_ANALYSIS)
+// Only for static analysis tool to know that it is equivalent to assert
+#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
+#elif !defined(NDEBUG)
+// In debug mode, avoid constructing CheckOpStrings if possible,
+// to reduce the overhead of CHECK statments by 2x.
+// Real DCHECK-heavy tests have seen 1.5x speedups.
+
+// The meaning of "string" might be different between now and
+// when this macro gets invoked (e.g., if someone is experimenting
+// with other string implementations that get defined after this
+// file is included). Save the current meaning now and use it
+// in the macro.
+typedef std::string _Check_string;
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::_Check_string* _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, \
+ google::CheckOpString(_result)).stream()
+#else
+// In optimized mode, use CheckOpString to hint to compiler that
+// the while condition is unlikely.
+#define CHECK_OP_LOG(name, op, val1, val2, log) \
+ while (google::CheckOpString _result = \
+ google::Check##name##Impl( \
+ google::GetReferenceableValue(val1), \
+ google::GetReferenceableValue(val2), \
+ #val1 " " #op " " #val2)) \
+ log(__FILE__, __LINE__, _result).stream()
+#endif // STATIC_ANALYSIS, !NDEBUG
+
+#if GOOGLE_STRIP_LOG <= 3
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
+#else
+#define CHECK_OP(name, op, val1, val2) \
+ CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
+#endif // STRIP_LOG <= 3
+
+// Equality/Inequality checks - compare two values, and log a FATAL message
+// including the two values when the result is not as expected. The values
+// must have operator<<(ostream, ...) defined.
+//
+// You may append to the error message like so:
+// CHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// CHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These don't compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
+
+// Check that the input is non NULL. This very useful in constructor
+// initializer lists.
+
+#define CHECK_NOTNULL(val) \
+ google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+
+// Helper functions for string comparisons.
+// To avoid bloat, the definitions are in logging.cc.
+#define DECLARE_CHECK_STROP_IMPL(func, expected) \
+ GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \
+ const char* s1, const char* s2, const char* names);
+DECLARE_CHECK_STROP_IMPL(strcmp, true)
+DECLARE_CHECK_STROP_IMPL(strcmp, false)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, true)
+DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
+#undef DECLARE_CHECK_STROP_IMPL
+
+// Helper macro for string comparisons.
+// Don't use this macro directly in your code, use CHECK_STREQ et al below.
+#define CHECK_STROP(func, op, expected, s1, s2) \
+ while (google::CheckOpString _result = \
+ google::Check##func##expected##Impl((s1), (s2), \
+ #s1 " " #op " " #s2)) \
+ LOG(FATAL) << *_result.str_
+
+
+// String (char*) equality/inequality checks.
+// CASE versions are case-insensitive.
+//
+// Note that "s1" and "s2" may be temporary strings which are destroyed
+// by the compiler at the end of the current "full expression"
+// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
+
+#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
+#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
+#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)
+#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)
+
+#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
+#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
+
+#define CHECK_DOUBLE_EQ(val1, val2) \
+ do { \
+ CHECK_LE((val1), (val2)+0.000000000000001L); \
+ CHECK_GE((val1), (val2)-0.000000000000001L); \
+ } while (0)
+
+#define CHECK_NEAR(val1, val2, margin) \
+ do { \
+ CHECK_LE((val1), (val2)+(margin)); \
+ CHECK_GE((val1), (val2)-(margin)); \
+ } while (0)
+
+// perror()..googly style!
+//
+// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and
+// CHECK equivalents with the addition that they postpend a description
+// of the current state of errno to their output lines.
+
+#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()
+
+#define GOOGLE_PLOG(severity, counter) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, counter, \
+ &google::LogMessage::SendToLog)
+
+#define PLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
+
+// A CHECK() macro that postpends errno if the condition is false. E.g.
+//
+// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }
+#define PCHECK(condition) \
+ PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
+ << "Check failed: " #condition " "
+
+// A CHECK() macro that lets you assert the success of a function that
+// returns -1 and sets errno in case of an error. E.g.
+//
+// CHECK_ERR(mkdir(path, 0700));
+//
+// or
+//
+// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename;
+#define CHECK_ERR(invocation) \
+PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \
+ << #invocation
+
+// Use macro expansion to create, for each use of LOG_EVERY_N(), static
+// variables with the __LINE__ expansion as part of the variable name.
+#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
+#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line
+
+#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
+#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
+
+#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (condition && \
+ ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
+ ++LOG_OCCURRENCES; \
+ if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
+ if (LOG_OCCURRENCES_MOD_N == 1) \
+ google::ErrnoLogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \
+ static int LOG_OCCURRENCES = 0; \
+ if (LOG_OCCURRENCES <= n) \
+ ++LOG_OCCURRENCES; \
+ if (LOG_OCCURRENCES <= n) \
+ google::LogMessage( \
+ __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
+ &what_to_do).stream()
+
+namespace glog_internal_namespace_ {
+template <bool>
+struct CompileAssert {
+};
+struct CrashReason;
+
+// Returns true if FailureSignalHandler is installed.
+bool IsFailureSignalHandlerInstalled();
+} // namespace glog_internal_namespace_
+
+#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
+ typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+#define LOG_EVERY_N(severity, n) \
+ GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \
+ google::NUM_SEVERITIES, \
+ INVALID_REQUESTED_LOG_SEVERITY); \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define SYSLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog)
+
+#define PLOG_EVERY_N(severity, n) \
+ SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_FIRST_N(severity, n) \
+ SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)
+
+#define LOG_IF_EVERY_N(severity, condition, n) \
+ SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog)
+
+// We want the special COUNTER value available for LOG_EVERY_X()'ed messages
+enum PRIVATE_Counter {COUNTER};
+
+#ifdef GLOG_NO_ABBREVIATED_SEVERITIES
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR.
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+#define SYSLOG_0 SYSLOG_ERROR
+#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity GLOG_0 = GLOG_ERROR;
+#else
+// Users may include windows.h after logging.h without
+// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.
+// For this case, we cannot detect if ERROR is defined before users
+// actually use ERROR. Let's make an undefined symbol to warn users.
+# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail
+# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG
+# define SYSLOG_0 GLOG_ERROR_MSG
+# define LOG_TO_STRING_0 GLOG_ERROR_MSG
+# define GLOG_0 GLOG_ERROR_MSG
+#endif
+
+// Plus some debug-logging macros that get compiled to nothing for production
+
+#ifndef NDEBUG
+
+#define DLOG(severity) LOG(severity)
+#define DVLOG(verboselevel) VLOG(verboselevel)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ LOG_IF_EVERY_N(severity, condition, n)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+
+// debug-only checking. not executed in NDEBUG mode.
+#define DCHECK(condition) CHECK(condition)
+#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
+#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
+#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
+#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
+#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
+#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
+#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
+#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
+#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
+#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
+#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
+
+#else // NDEBUG
+
+#define DLOG(severity) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DVLOG(verboselevel) \
+ (true || !VLOG_IS_ON(verboselevel)) ?\
+ (void) 0 : google::LogMessageVoidify() & LOG(INFO)
+
+#define DLOG_IF(severity, condition) \
+ (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_EVERY_N(severity, n) \
+ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_IF_EVERY_N(severity, condition, n) \
+ (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_ASSERT(condition) \
+ true ? (void) 0 : LOG_ASSERT(condition)
+
+// MSVC warning C4127: conditional expression is constant
+#define DCHECK(condition) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK(condition)
+
+#define DCHECK_EQ(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)
+
+#define DCHECK_NE(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)
+
+#define DCHECK_LE(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)
+
+#define DCHECK_LT(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)
+
+#define DCHECK_GE(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)
+
+#define DCHECK_GT(val1, val2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)
+
+// You may see warnings in release mode if you don't use the return
+// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.
+#define DCHECK_NOTNULL(val) (val)
+
+#define DCHECK_STREQ(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)
+
+#define DCHECK_STRCASEEQ(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)
+
+#define DCHECK_STRNE(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)
+
+#define DCHECK_STRCASENE(str1, str2) \
+ GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
+ while (false) \
+ GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
+
+#endif // NDEBUG
+
+// Log only in verbose mode.
+
+#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
+
+#define VLOG_IF(verboselevel, condition) \
+ LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
+
+#define VLOG_EVERY_N(verboselevel, n) \
+ LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)
+
+#define VLOG_IF_EVERY_N(verboselevel, condition, n) \
+ LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
+
+namespace base_logging {
+
+// LogMessage::LogStream is a std::ostream backed by this streambuf.
+// This class ignores overflow and leaves two bytes at the end of the
+// buffer to allow for a '\n' and '\0'.
+class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf {
+ public:
+ // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
+ LogStreamBuf(char *buf, int len) {
+ setp(buf, buf + len - 2);
+ }
+ // This effectively ignores overflow.
+ virtual int_type overflow(int_type ch) {
+ return ch;
+ }
+
+ // Legacy public ostrstream method.
+ size_t pcount() const { return pptr() - pbase(); }
+ char* pbase() const { return std::streambuf::pbase(); }
+};
+
+} // namespace base_logging
+
+//
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class GOOGLE_GLOG_DLL_DECL LogMessage {
+public:
+ enum {
+ // Passing kNoLogPrefix for the line number disables the
+ // log-message prefix. Useful for using the LogMessage
+ // infrastructure as a printing utility. See also the --log_prefix
+ // flag for controlling the log-message prefix on an
+ // application-wide basis.
+ kNoLogPrefix = -1
+ };
+
+ // LogStream inherit from non-DLL-exported class (std::ostrstream)
+ // and VC++ produces a warning for this situation.
+ // However, MSDN says "C4275 can be ignored in Microsoft Visual C++
+ // 2005 if you are deriving from a type in the Standard C++ Library"
+ // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+ // Let's just ignore the warning.
+#ifdef _MSC_VER
+# pragma warning(disable: 4275)
+#endif
+ class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
+#ifdef _MSC_VER
+# pragma warning(default: 4275)
+#endif
+ public:
+ LogStream(char *buf, int len, int ctr)
+ : std::ostream(NULL),
+ streambuf_(buf, len),
+ ctr_(ctr),
+ self_(this) {
+ rdbuf(&streambuf_);
+ }
+
+ int ctr() const { return ctr_; }
+ void set_ctr(int ctr) { ctr_ = ctr; }
+ LogStream* self() const { return self_; }
+
+ // Legacy std::streambuf methods.
+ size_t pcount() const { return streambuf_.pcount(); }
+ char* pbase() const { return streambuf_.pbase(); }
+ char* str() const { return pbase(); }
+
+ private:
+ base_logging::LogStreamBuf streambuf_;
+ int ctr_; // Counter hack (for the LOG_EVERY_X() macro)
+ LogStream *self_; // Consistency check hack
+ };
+
+public:
+ // icc 8 requires this typedef to avoid an internal compiler error.
+ typedef void (LogMessage::*SendMethod)();
+
+ LogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ SendMethod send_method);
+
+ // Two special constructors that generate reduced amounts of code at
+ // LOG call sites for common cases.
+
+ // Used for LOG(INFO): Implied are:
+ // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 19 bytes per call site.
+ LogMessage(const char* file, int line);
+
+ // Used for LOG(severity) where severity != INFO. Implied
+ // are: ctr = 0, send_method = &LogMessage::SendToLog
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves 17 bytes per call site.
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // Constructor to log this message to a specified sink (if not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if
+ // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.
+ LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,
+ bool also_send_to_log);
+
+ // Constructor where we also give a vector<string> pointer
+ // for storing the messages (if the pointer is not NULL).
+ // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::vector<std::string>* outvec);
+
+ // Constructor where we also give a string pointer for storing the
+ // message (if the pointer is not NULL). Implied are: ctr = 0,
+ // send_method = &LogMessage::WriteToStringAndLog.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* message);
+
+ // A special constructor used for check failures
+ LogMessage(const char* file, int line, const CheckOpString& result);
+
+ ~LogMessage();
+
+ // Flush a buffered message to the sink set in the constructor. Always
+ // called by the destructor, it may also be called from elsewhere if
+ // needed. Only the first call is actioned; any later ones are ignored.
+ void Flush();
+
+ // An arbitrary limit on the length of a single log message. This
+ // is so that streaming can be done more efficiently.
+ static const size_t kMaxLogMessageLen;
+
+ // Theses should not be called directly outside of logging.*,
+ // only passed as SendMethod arguments to other LogMessage methods:
+ void SendToLog(); // Actually dispatch to the logs
+ void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
+
+ // Call abort() or similar to perform LOG(FATAL) crash.
+ static void Fail() ;
+
+ std::ostream& stream();
+
+ int preserved_errno() const;
+
+ // Must be called without the log_mutex held. (L < log_mutex)
+ static int64 num_messages(int severity);
+
+ struct LogMessageData;
+
+private:
+ // Fully internal SendMethod cases:
+ void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs
+ void SendToSink(); // Send to sink if provided, do nothing otherwise.
+
+ // Write to string if provided and dispatch to the logs.
+ void WriteToStringAndLog();
+
+ void SaveOrSendToLog(); // Save to stringvec if provided, else to logs
+
+ void Init(const char* file, int line, LogSeverity severity,
+ void (LogMessage::*send_method)());
+
+ // Used to fill in crash information during LOG(FATAL) failures.
+ void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
+
+ // Counts of messages sent at each priority:
+ static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex
+
+ // We keep the data in a separate struct so that each instance of
+ // LogMessage uses less stack space.
+ LogMessageData* allocated_;
+ LogMessageData* data_;
+
+ friend class LogDestination;
+
+ LogMessage(const LogMessage&);
+ void operator=(const LogMessage&);
+};
+
+// This class happens to be thread-hostile because all instances share
+// a single data buffer, but since it can only be created just before
+// the process dies, we don't worry so much.
+class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
+ public:
+ LogMessageFatal(const char* file, int line);
+ LogMessageFatal(const char* file, int line, const CheckOpString& result);
+ ~LogMessageFatal() ;
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const severity, std::string const &msg) {
+ LogMessage(__FILE__, __LINE__, severity).stream() << msg;
+}
+
+// A macro alternative of LogAtLevel. New code may want to use this
+// version since there are two advantages: 1. this version outputs the
+// file name and the line number where this macro is put like other
+// LOG macros, 2. this macro can be used as C++ stream.
+#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
+
+// A small helper for CHECK_NOTNULL().
+template <typename T>
+T* CheckNotNull(const char *file, int line, const char *names, T* t) {
+ if (t == NULL) {
+ LogMessageFatal(file, line, new std::string(names));
+ }
+ return t;
+}
+
+// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
+// only works if ostream is a LogStream. If the ostream is not a
+// LogStream you'll get an assert saying as much at runtime.
+GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os,
+ const PRIVATE_Counter&);
+
+
+// Derived class for PLOG*() above.
+class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage {
+ public:
+
+ ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr,
+ void (LogMessage::*send_method)());
+
+ // Postpends ": strerror(errno) [errno]".
+ ~ErrnoLogMessage();
+
+ private:
+ ErrnoLogMessage(const ErrnoLogMessage&);
+ void operator=(const ErrnoLogMessage&);
+};
+
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+
+class GOOGLE_GLOG_DLL_DECL LogMessageVoidify {
+ public:
+ LogMessageVoidify() { }
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) { }
+};
+
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity);
+
+// Flushes all log files that contains messages that are at least of
+// the specified severity level. Thread-hostile because it ignores
+// locking -- used for catastrophic failures.
+GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity);
+
+//
+// Set the destination to which a particular severity level of log
+// messages is sent. If base_filename is "", it means "don't log this
+// severity". Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity,
+ const char* base_filename);
+
+//
+// Set the basename of the symlink to the latest log file at a given
+// severity. If symlink_basename is empty, do not make a symlink. If
+// you don't call this function, the symlink basename is the
+// invocation name of the program. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity,
+ const char* symlink_basename);
+
+//
+// Used to send logs to some other kind of destination
+// Users should subclass LogSink and override send to do whatever they want.
+// Implementations must be thread-safe because a shared instance will
+// be called from whichever thread ran the LOG(XXX) line.
+class GOOGLE_GLOG_DLL_DECL LogSink {
+ public:
+ virtual ~LogSink();
+
+ // Sink's logging logic (message_len is such as to exclude '\n' at the end).
+ // This method can't use LOG() or CHECK() as logging system mutex(s) are held
+ // during this call.
+ virtual void send(LogSeverity severity, const char* full_filename,
+ const char* base_filename, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len) = 0;
+
+ // Redefine this to implement waiting for
+ // the sink's logging logic to complete.
+ // It will be called after each send() returns,
+ // but before that LogMessage exits or crashes.
+ // By default this function does nothing.
+ // Using this function one can implement complex logic for send()
+ // that itself involves logging; and do all this w/o causing deadlocks and
+ // inconsistent rearrangement of log messages.
+ // E.g. if a LogSink has thread-specific actions, the send() method
+ // can simply add the message to a queue and wake up another thread that
+ // handles real logging while itself making some LOG() calls;
+ // WaitTillSent() can be implemented to wait for that logic to complete.
+ // See our unittest for an example.
+ virtual void WaitTillSent();
+
+ // Returns the normal text output of the log message.
+ // Can be useful to implement send().
+ static std::string ToString(LogSeverity severity, const char* file, int line,
+ const struct ::tm* tm_time,
+ const char* message, size_t message_len);
+};
+
+// Add or remove a LogSink as a consumer of logging data. Thread-safe.
+GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination);
+GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);
+
+//
+// Specify an "extension" added to the filename specified via
+// SetLogDestination. This applies to all severity levels. It's
+// often used to append the port we're listening on to the logfile
+// name. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(
+ const char* filename_extension);
+
+//
+// Make it so that all log messages of at least a particular severity
+// are logged to stderr (in addition to logging to the usual log
+// file(s)). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);
+
+//
+// Make it so that all log messages go only to stderr. Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void LogToStderr();
+
+//
+// Make it so that all log messages of at least a particular severity are
+// logged via email to a list of addresses (in addition to logging to the
+// usual log file(s)). The list of addresses is just a string containing
+// the email addresses to send to (separated by spaces, say). Thread-safe.
+//
+GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,
+ const char* addresses);
+
+// A simple function that sends email. dest is a commma-separated
+// list of addressess. Thread-safe.
+GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,
+ const char *subject, const char *body);
+
+GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();
+
+// For tests only: Clear the internal [cached] list of logging directories to
+// force a refresh the next time GetLoggingDirectories is called.
+// Thread-hostile.
+void TestOnly_ClearLoggingDirectoriesList();
+
+// Returns a set of existing temporary directories, which will be a
+// subset of the directories returned by GetLogginDirectories().
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(
+ std::vector<std::string>* list);
+
+// Print any fatal message again -- useful to call from signal handler
+// so that the last thing in the output is the fatal message.
+// Thread-hostile, but a race is unlikely.
+GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();
+
+// Truncate a log file that may be the append-only output of multiple
+// processes and hence can't simply be renamed/reopened (typically a
+// stdout/stderr). If the file "path" is > "limit" bytes, copy the
+// last "keep" bytes to offset 0 and truncate the rest. Since we could
+// be racing with other writers, this approach has the potential to
+// lose very small amounts of data. For security, only follow symlinks
+// if the path is /proc/self/fd/*
+GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,
+ int64 limit, int64 keep);
+
+// Truncate stdout and stderr if they are over the value specified by
+// --max_log_size; keep the final 1MB. This function has the same
+// race condition as TruncateLogFile.
+GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();
+
+// Return the string representation of the provided LogSeverity level.
+// Thread-safe.
+GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
+
+// ---------------------------------------------------------------------
+// Implementation details that are not useful to most clients
+// ---------------------------------------------------------------------
+
+// A Logger is the interface used by logging modules to emit entries
+// to a log. A typical implementation will dump formatted data to a
+// sequence of files. We also provide interfaces that will forward
+// the data to another thread so that the invoker never blocks.
+// Implementations should be thread-safe since the logging system
+// will write to them from multiple threads.
+
+namespace base {
+
+class GOOGLE_GLOG_DLL_DECL Logger {
+ public:
+ virtual ~Logger();
+
+ // Writes "message[0,message_len-1]" corresponding to an event that
+ // occurred at "timestamp". If "force_flush" is true, the log file
+ // is flushed immediately.
+ //
+ // The input message has already been formatted as deemed
+ // appropriate by the higher level logging facility. For example,
+ // textual log messages already contain timestamps, and the
+ // file:linenumber header.
+ virtual void Write(bool force_flush,
+ time_t timestamp,
+ const char* message,
+ int message_len) = 0;
+
+ // Flush any buffered messages
+ virtual void Flush() = 0;
+
+ // Get the current LOG file size.
+ // The returned value is approximate since some
+ // logged data may not have been flushed to disk yet.
+ virtual uint32 LogSize() = 0;
+};
+
+// Get the logger for the specified severity level. The logger
+// remains the property of the logging module and should not be
+// deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level);
+
+// Set the logger for the specified severity level. The logger
+// becomes the property of the logging module and should not
+// be deleted by the caller. Thread-safe.
+extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger);
+
+}
+
+// glibc has traditionally implemented two incompatible versions of
+// strerror_r(). There is a poorly defined convention for picking the
+// version that we want, but it is not clear whether it even works with
+// all versions of glibc.
+// So, instead, we provide this wrapper that automatically detects the
+// version that is in use, and then implements POSIX semantics.
+// N.B. In addition to what POSIX says, we also guarantee that "buf" will
+// be set to an empty string, if this function failed. This means, in most
+// cases, you do not need to check the error code and you can directly
+// use the value of "buf". It will never have an undefined value.
+// DEPRECATED: Use StrError(int) instead.
+GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len);
+
+// A thread-safe replacement for strerror(). Returns a string describing the
+// given POSIX error code.
+GOOGLE_GLOG_DLL_DECL std::string StrError(int err);
+
+// A class for which we define operator<<, which does nothing.
+class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream {
+ public:
+ // Initialize the LogStream so the messages can be written somewhere
+ // (they'll never be actually displayed). This will be needed if a
+ // NullStream& is implicitly converted to LogStream&, in which case
+ // the overloaded NullStream::operator<< will not be invoked.
+ NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream(const char* /*file*/, int /*line*/,
+ const CheckOpString& /*result*/) :
+ LogMessage::LogStream(message_buffer_, 1, 0) { }
+ NullStream &stream() { return *this; }
+ private:
+ // A very short buffer for messages (which we discard anyway). This
+ // will be needed if NullStream& converted to LogStream& (e.g. as a
+ // result of a conditional expression).
+ char message_buffer_[2];
+};
+
+// Do nothing. This operator is inline, allowing the message to be
+// compiled away. The message will not be compiled away if we do
+// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when
+// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly
+// converted to LogStream and the message will be computed and then
+// quietly discarded.
+template<class T>
+inline NullStream& operator<<(NullStream &str, const T &) { return str; }
+
+// Similar to NullStream, but aborts the program (without stack
+// trace), like LogMessageFatal.
+class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
+ public:
+ NullStreamFatal() { }
+ NullStreamFatal(const char* file, int line, const CheckOpString& result) :
+ NullStream(file, line, result) { }
+ ~NullStreamFatal() { _exit(1); }
+};
+
+// Install a signal handler that will dump signal information and a stack
+// trace when the program crashes on certain signals. We'll install the
+// signal handler for the following signals.
+//
+// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.
+//
+// By default, the signal handler will write the failure dump to the
+// standard error. You can customize the destination by installing your
+// own writer function by InstallFailureWriter() below.
+//
+// Note on threading:
+//
+// The function should be called before threads are created, if you want
+// to use the failure signal handler for all threads. The stack trace
+// will be shown only for the thread that receives the signal. In other
+// words, stack traces of other threads won't be shown.
+GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler();
+
+// Installs a function that is used for writing the failure dump. "data"
+// is the pointer to the beginning of a message to be written, and "size"
+// is the size of the message. You should not expect the data is
+// terminated with '\0'.
+GOOGLE_GLOG_DLL_DECL void InstallFailureWriter(
+ void (*writer)(const char* data, int size));
+
+}
+
+#endif // _LOGGING_H_
diff --git a/extern/libmv/third_party/glog/src/windows/glog/raw_logging.h b/extern/glog/src/windows/glog/raw_logging.h
index 4757a719db7..4757a719db7 100644
--- a/extern/libmv/third_party/glog/src/windows/glog/raw_logging.h
+++ b/extern/glog/src/windows/glog/raw_logging.h
diff --git a/extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h b/extern/glog/src/windows/glog/vlog_is_on.h
index 409a4011b38..409a4011b38 100644
--- a/extern/libmv/third_party/glog/src/windows/glog/vlog_is_on.h
+++ b/extern/glog/src/windows/glog/vlog_is_on.h
diff --git a/extern/glog/src/windows/port.cc b/extern/glog/src/windows/port.cc
new file mode 100644
index 00000000000..d9943254ee5
--- /dev/null
+++ b/extern/glog/src/windows/port.cc
@@ -0,0 +1,66 @@
+/* Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Craig Silverstein
+ * Copied from google-perftools and modified by Shinichiro Hamaji
+ */
+
+#ifndef _WIN32
+# error You should only be including windows/port.cc in a windows environment!
+#endif
+
+#include "config.h"
+#include <stdarg.h> // for va_list, va_start, va_end
+#include <string.h> // for strstr()
+#include <assert.h>
+#include <string>
+#include <vector>
+#include "port.h"
+
+using std::string;
+using std::vector;
+
+// These call the windows _vsnprintf, but always NUL-terminate.
+int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
+ if (size == 0) // not even room for a \0?
+ return -1; // not what C99 says to do, but what windows does
+ str[size-1] = '\0';
+ return _vsnprintf(str, size-1, format, ap);
+}
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t size, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ const int r = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return r;
+}
+#endif
diff --git a/extern/glog/src/windows/port.h b/extern/glog/src/windows/port.h
new file mode 100644
index 00000000000..02c6f6e77b2
--- /dev/null
+++ b/extern/glog/src/windows/port.h
@@ -0,0 +1,168 @@
+/* Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Craig Silverstein
+ * Copied from google-perftools and modified by Shinichiro Hamaji
+ *
+ * These are some portability typedefs and defines to make it a bit
+ * easier to compile this code under VC++.
+ *
+ * Several of these are taken from glib:
+ * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
+ */
+
+#ifndef CTEMPLATE_WINDOWS_PORT_H_
+#define CTEMPLATE_WINDOWS_PORT_H_
+
+#include "config.h"
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
+#endif
+
+#include <windows.h>
+#include <winsock.h> /* for gethostname */
+#include <io.h> /* because we so often use open/close/etc */
+#include <direct.h> /* for _getcwd() */
+#include <process.h> /* for _getpid() */
+#include <stdio.h> /* read in vsnprintf decl. before redifining it */
+#include <stdarg.h> /* template_dictionary.cc uses va_copy */
+#include <string.h> /* for _strnicmp(), strerror_s() */
+#include <time.h> /* for localtime_s() */
+/* Note: the C++ #includes are all together at the bottom. This file is
+ * used by both C and C++ code, so we put all the C++ together.
+ */
+
+#ifdef _MSC_VER
+
+/* 4244: otherwise we get problems when substracting two size_t's to an int
+ * 4251: it's complaining about a private struct I've chosen not to dllexport
+ * 4355: we use this in a constructor, but we do it safely
+ * 4715: for some reason VC++ stopped realizing you can't return after abort()
+ * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
+ * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
+ */
+#pragma warning(disable:4244 4251 4355 4715 4800 4996)
+
+/* file I/O */
+#define PATH_MAX 1024
+#define access _access
+#define getcwd _getcwd
+#define open _open
+#define read _read
+#define write _write
+#define lseek _lseek
+#define close _close
+#define popen _popen
+#define pclose _pclose
+#define R_OK 04 /* read-only (for access()) */
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#ifndef __MINGW32__
+enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
+#endif
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+
+/* Not quite as lightweight as a hard-link, but more than good enough for us. */
+#define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
+
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+
+/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
+/* VC11 provides std::hash */
+#if defined(_MSC_VER) && (_MSC_VER < 1700)
+#define hash hash_compare
+#endif
+
+/* Sleep is in ms, on windows */
+#define sleep(secs) Sleep((secs) * 1000)
+
+/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
+ * because they don't always NUL-terminate. :-( We also can't use the
+ * name vsnprintf, since windows defines that (but not snprintf (!)).
+ */
+#ifndef HAVE_SNPRINTF
+extern int GOOGLE_GLOG_DLL_DECL snprintf(char *str, size_t size,
+ const char *format, ...);
+#endif
+extern int GOOGLE_GLOG_DLL_DECL safe_vsnprintf(char *str, size_t size,
+ const char *format, va_list ap);
+#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
+#ifndef va_copy
+#define va_copy(dst, src) (dst) = (src)
+#endif
+
+/* Windows doesn't support specifying the number of buckets as a
+ * hash_map constructor arg, so we leave this blank.
+ */
+#define CTEMPLATE_SMALL_HASHTABLE
+
+#define DEFAULT_TEMPLATE_ROOTDIR ".."
+
+// ----------------------------------- SYSTEM/PROCESS
+typedef int pid_t;
+#define getpid _getpid
+
+#endif // _MSC_VER
+
+// ----------------------------------- THREADS
+typedef DWORD pthread_t;
+typedef DWORD pthread_key_t;
+typedef LONG pthread_once_t;
+enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
+#define pthread_self GetCurrentThreadId
+#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
+
+inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
+ localtime_s(result, timep);
+ return result;
+}
+
+inline char* strerror_r(int errnum, char* buf, size_t buflen) {
+#ifdef FREE_WINDOWS
+ strncpy(buf, "Not implemented yet", buflen);
+ return buf;
+#else
+ strerror_s(buf, buflen, errnum);
+ return buf;
+#endif
+}
+
+#ifndef __cplusplus
+/* I don't see how to get inlining for C code in MSVC. Ah well. */
+#define inline
+#endif
+
+#endif /* _WIN32 */
+
+#endif /* CTEMPLATE_WINDOWS_PORT_H_ */
diff --git a/extern/glog/src/windows/preprocess.sh b/extern/glog/src/windows/preprocess.sh
new file mode 100755
index 00000000000..5398988e7ea
--- /dev/null
+++ b/extern/glog/src/windows/preprocess.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+# Copyright (c) 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# ---
+# Author: Craig Silverstein
+# Copied from google-perftools and modified by Shinichiro Hamaji
+#
+# This script is meant to be run at distribution-generation time, for
+# instance by autogen.sh. It does some of the work configure would
+# normally do, for windows systems. In particular, it expands all the
+# @...@ variables found in .in files, and puts them here, in the windows
+# directory.
+#
+# This script should be run before any new release.
+
+if [ -z "$1" ]; then
+ echo "USAGE: $0 <src/ directory>"
+ exit 1
+fi
+
+DLLDEF_MACRO_NAME="GLOG_DLL_DECL"
+
+# The text we put in every .h files we create. As a courtesy, we'll
+# include a helpful comment for windows users as to how to use
+# GLOG_DLL_DECL. Apparently sed expands \n into a newline. Good!
+DLLDEF_DEFINES="\
+// NOTE: if you are statically linking the template library into your binary\n\
+// (rather than using the template .dll), set '/D $DLLDEF_MACRO_NAME='\n\
+// as a compiler flag in your project file to turn off the dllimports.\n\
+#ifndef $DLLDEF_MACRO_NAME\n\
+# define $DLLDEF_MACRO_NAME __declspec(dllimport)\n\
+#endif"
+
+# Read all the windows config info into variables
+# In order for the 'set' to take, this requires putting all in a subshell.
+(
+ while read define varname value; do
+ [ "$define" != "#define" ] && continue
+ eval "$varname='$value'"
+ done
+
+ # Process all the .in files in the "glog" subdirectory
+ mkdir -p "$1/windows/glog"
+ for file in `echo "$1"/glog/*.in`; do
+ echo "Processing $file"
+ outfile="$1/windows/glog/`basename $file .in`"
+
+ echo "\
+// This file is automatically generated from $file
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+" > "$outfile"
+ # Besides replacing @...@, we also need to turn on dllimport
+ # We also need to replace hash by hash_compare (annoying we hard-code :-( )
+ sed -e "s!@ac_windows_dllexport@!$DLLDEF_MACRO_NAME!g" \
+ -e "s!@ac_windows_dllexport_defines@!$DLLDEF_DEFINES!g" \
+ -e "s!@ac_cv_cxx_hash_map@!$HASH_MAP_H!g" \
+ -e "s!@ac_cv_cxx_hash_namespace@!$HASH_NAMESPACE!g" \
+ -e "s!@ac_cv_cxx_hash_set@!$HASH_SET_H!g" \
+ -e "s!@ac_cv_have_stdint_h@!0!g" \
+ -e "s!@ac_cv_have_systypes_h@!0!g" \
+ -e "s!@ac_cv_have_inttypes_h@!0!g" \
+ -e "s!@ac_cv_have_unistd_h@!0!g" \
+ -e "s!@ac_cv_have_uint16_t@!0!g" \
+ -e "s!@ac_cv_have_u_int16_t@!0!g" \
+ -e "s!@ac_cv_have___uint16@!1!g" \
+ -e "s!@ac_cv_have_libgflags@!0!g" \
+ -e "s!@ac_cv_have___builtin_expect@!0!g" \
+ -e "s!@ac_cv_cxx_using_operator@!1!g" \
+ -e "s!@ac_cv___attribute___noreturn@!!g" \
+ -e "s!@ac_cv___attribute___noinline@!!g" \
+ -e "s!@ac_cv___attribute___printf_4_5@!!g" \
+ -e "s!@ac_google_attribute@!${HAVE___ATTRIBUTE__:-0}!g" \
+ -e "s!@ac_google_end_namespace@!$_END_GOOGLE_NAMESPACE_!g" \
+ -e "s!@ac_google_namespace@!$GOOGLE_NAMESPACE!g" \
+ -e "s!@ac_google_start_namespace@!$_START_GOOGLE_NAMESPACE_!g" \
+ -e "s!@ac_htmlparser_namespace@!$HTMLPARSER_NAMESPACE!g" \
+ -e "s!\\bhash\\b!hash_compare!g" \
+ "$file" >> "$outfile"
+ done
+) < "$1/windows/config.h"
+
+# log_severity.h isn't a .in file.
+echo "\
+// This file is automatically generated from $1/glog/log_severity.h
+// using src/windows/preprocess.sh.
+// DO NOT EDIT!
+" > "$1/windows/glog/log_severity.h"
+cat "$1/glog/log_severity.h" >> "$1/windows/glog/log_severity.h"
+
+echo "DONE"
diff --git a/extern/gtest/include/gtest/gtest.h b/extern/gtest/include/gtest/gtest.h
index 6fa0a3925e7..69a8e72da5f 100644
--- a/extern/gtest/include/gtest/gtest.h
+++ b/extern/gtest/include/gtest/gtest.h
@@ -1873,7 +1873,7 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// Define this macro to 1 to omit the definition of FAIL(), which is a
// generic name and clashes with some other libraries.
-#if !GTEST_DONT_DEFINE_FAIL
+#if !defined(GTEST_DONT_DEFINE_FAIL) || !GTEST_DONT_DEFINE_FAIL
# define FAIL() GTEST_FAIL()
#endif
@@ -1882,7 +1882,7 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// Define this macro to 1 to omit the definition of SUCCEED(), which
// is a generic name and clashes with some other libraries.
-#if !GTEST_DONT_DEFINE_SUCCEED
+#if !defined(GTEST_DONT_DEFINE_SUCCEED) || !GTEST_DONT_DEFINE_SUCCEED
# define SUCCEED() GTEST_SUCCEED()
#endif
@@ -2007,27 +2007,27 @@ class TestWithParam : public Test, public WithParamInterface<T> {
// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
// ASSERT_XY(), which clashes with some users' own code.
-#if !GTEST_DONT_DEFINE_ASSERT_EQ
+#if !defined(GTEST_DONT_DEFINE_ASSERT_EQ) || !GTEST_DONT_DEFINE_ASSERT_EQ
# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
#endif
-#if !GTEST_DONT_DEFINE_ASSERT_NE
+#if !defined(GTEST_DONT_DEFINE_ASSERT_NE) || !GTEST_DONT_DEFINE_ASSERT_NE
# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
#endif
-#if !GTEST_DONT_DEFINE_ASSERT_LE
+#if !defined(GTEST_DONT_DEFINE_ASSERT_LE) || !GTEST_DONT_DEFINE_ASSERT_LE
# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
#endif
-#if !GTEST_DONT_DEFINE_ASSERT_LT
+#if !defined(GTEST_DONT_DEFINE_ASSERT_LT) || !GTEST_DONT_DEFINE_ASSERT_LT
# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
#endif
-#if !GTEST_DONT_DEFINE_ASSERT_GE
+#if !defined(GTEST_DONT_DEFINE_ASSERT_GE) || !GTEST_DONT_DEFINE_ASSERT_GE
# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
#endif
-#if !GTEST_DONT_DEFINE_ASSERT_GT
+#if !defined(GTEST_DONT_DEFINE_ASSERT_GT) || !GTEST_DONT_DEFINE_ASSERT_GT
# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
#endif
@@ -2238,7 +2238,7 @@ bool StaticAssertTypeEq() {
// Define this macro to 1 to omit the definition of TEST(), which
// is a generic name and clashes with some other libraries.
-#if !GTEST_DONT_DEFINE_TEST
+#if !defined(GTEST_DONT_DEFINE_TEST) || !GTEST_DONT_DEFINE_TEST
# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
#endif
diff --git a/extern/gtest/include/gtest/internal/gtest-port.h b/extern/gtest/include/gtest/internal/gtest-port.h
index dc4fe0cb6b8..5ff2c29ad43 100644
--- a/extern/gtest/include/gtest/internal/gtest-port.h
+++ b/extern/gtest/include/gtest/internal/gtest-port.h
@@ -274,7 +274,7 @@
// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a
// value for __cplusplus, and recent versions of clang, gcc, and
// probably other compilers set that too in C++11 mode.
-# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L
+# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
// Compiling in at least C++11 mode.
# define GTEST_LANG_CXX11 1
# else
@@ -282,6 +282,28 @@
# endif
#endif
+#ifndef GTEST_OS_WINDOWS
+# define GTEST_OS_WINDOWS 0
+#endif
+#ifndef GTEST_OS_WINDOWS_MOBILE
+# define GTEST_OS_WINDOWS_MOBILE 0
+#endif
+#ifndef GTEST_OS_LINUX_ANDROID
+# define GTEST_OS_LINUX_ANDROID 0
+#endif
+#ifndef GTEST_OS_QNX
+# define GTEST_OS_QNX 0
+#endif
+#ifndef GTEST_OS_SYMBIAN
+# define GTEST_OS_SYMBIAN 0
+#endif
+#ifndef GTEST_OS_CYGWIN
+# define GTEST_OS_CYGWIN 0
+#endif
+#ifndef GTEST_OS_SOLARIS
+# define GTEST_OS_SOLARIS 0
+#endif
+
// Brings in definitions for functions used in the testing::internal::posix
// namespace (read, write, close, chdir, isatty, stat). We do not currently
// use them on Windows Mobile.
@@ -527,6 +549,8 @@
// can build with clang but need to use gcc4.2's libstdc++).
# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325)
# define GTEST_ENV_HAS_STD_TUPLE_ 1
+# else
+# define GTEST_ENV_HAS_STD_TUPLE_ 0
# endif
# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_
@@ -1823,7 +1847,7 @@ inline void Abort() { abort(); }
// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate
// function in order to achieve that. We use macro definition here because
// snprintf is a variadic function.
-#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
// MSVC 2005 and above support variadic macros.
# define GTEST_SNPRINTF_(buffer, size, format, ...) \
_snprintf_s(buffer, size, size, format, __VA_ARGS__)
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
deleted file mode 100644
index 089743567f0..00000000000
--- a/extern/libmv/CMakeLists.txt
+++ /dev/null
@@ -1,349 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# Contributor(s): Blender Foundation,
-# Sergey Sharybin
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-set(INC
- .
-)
-
-set(INC_SYS
-)
-
-set(SRC
- libmv-capi.h
-)
-
-if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
- list(APPEND INC
- third_party/gflags
- third_party/gflags/gflags
- third_party/glog/src
- third_party/ceres/include
- third_party/ceres/config
- ../../intern/guardedalloc
- )
-
- list(APPEND INC_SYS
- ${EIGEN3_INCLUDE_DIRS}
- ${PNG_INCLUDE_DIRS}
- ${ZLIB_INCLUDE_DIRS}
- )
-
- if(WIN32)
- list(APPEND INC
- third_party/glog/src/windows
- )
-
- if(NOT MINGW)
- list(APPEND INC
- third_party/msinttypes
- )
- endif()
- endif()
-
- add_definitions(
- -DWITH_LIBMV_GUARDED_ALLOC
- -DGOOGLE_GLOG_DLL_DECL=
- -DLIBMV_NO_FAST_DETECTOR=
- )
-endif()
-
-if(WITH_LIBMV)
- TEST_SHARED_PTR_SUPPORT()
- if(SHARED_PTR_FOUND)
- if(SHARED_PTR_TR1_MEMORY_HEADER)
- add_definitions(-DCERES_TR1_MEMORY_HEADER)
- endif()
- if(SHARED_PTR_TR1_NAMESPACE)
- add_definitions(-DCERES_TR1_SHARED_PTR)
- endif()
- else()
- message(FATAL_ERROR "Unable to find shared_ptr.")
- endif()
-
- list(APPEND SRC
- intern/autotrack.cc
- intern/camera_intrinsics.cc
- intern/detector.cc
- intern/frame_accessor.cc
- intern/homography.cc
- intern/image.cc
- intern/logging.cc
- intern/reconstruction.cc
- intern/track_region.cc
- intern/tracks.cc
- intern/tracksN.cc
- libmv/autotrack/autotrack.cc
- libmv/autotrack/predict_tracks.cc
- libmv/autotrack/tracks.cc
- libmv/base/aligned_malloc.cc
- libmv/image/array_nd.cc
- libmv/image/convolve.cc
- libmv/multiview/conditioning.cc
- libmv/multiview/euclidean_resection.cc
- libmv/multiview/fundamental.cc
- libmv/multiview/homography.cc
- libmv/multiview/panography.cc
- libmv/multiview/panography_kernel.cc
- libmv/multiview/projection.cc
- libmv/multiview/triangulation.cc
- libmv/numeric/numeric.cc
- libmv/numeric/poly.cc
- libmv/simple_pipeline/bundle.cc
- libmv/simple_pipeline/camera_intrinsics.cc
- libmv/simple_pipeline/detect.cc
- libmv/simple_pipeline/distortion_models.cc
- libmv/simple_pipeline/initialize_reconstruction.cc
- libmv/simple_pipeline/intersect.cc
- libmv/simple_pipeline/keyframe_selection.cc
- libmv/simple_pipeline/modal_solver.cc
- libmv/simple_pipeline/pipeline.cc
- libmv/simple_pipeline/reconstruction.cc
- libmv/simple_pipeline/reconstruction_scale.cc
- libmv/simple_pipeline/resect.cc
- libmv/simple_pipeline/tracks.cc
- libmv/tracking/brute_region_tracker.cc
- libmv/tracking/hybrid_region_tracker.cc
- libmv/tracking/klt_region_tracker.cc
- libmv/tracking/pyramid_region_tracker.cc
- libmv/tracking/retrack_region_tracker.cc
- libmv/tracking/track_region.cc
- libmv/tracking/trklt_region_tracker.cc
-
-
- intern/autotrack.h
- intern/camera_intrinsics.h
- intern/detector.h
- intern/frame_accessor.h
- intern/homography.h
- intern/image.h
- intern/logging.h
- intern/reconstruction.h
- intern/track_region.h
- intern/tracks.h
- intern/tracksN.h
- libmv/autotrack/autotrack.h
- libmv/autotrack/callbacks.h
- libmv/autotrack/frame_accessor.h
- libmv/autotrack/marker.h
- libmv/autotrack/model.h
- libmv/autotrack/predict_tracks.h
- libmv/autotrack/quad.h
- libmv/autotrack/reconstruction.h
- libmv/autotrack/region.h
- libmv/autotrack/tracks.h
- libmv/base/aligned_malloc.h
- libmv/base/id_generator.h
- libmv/base/scoped_ptr.h
- libmv/base/vector.h
- libmv/base/vector_utils.h
- libmv/image/array_nd.h
- libmv/image/convolve.h
- libmv/image/correlation.h
- libmv/image/image_converter.h
- libmv/image/image_drawing.h
- libmv/image/image.h
- libmv/image/sample.h
- libmv/image/tuple.h
- libmv/logging/logging.h
- libmv/multiview/conditioning.h
- libmv/multiview/euclidean_resection.h
- libmv/multiview/fundamental.h
- libmv/multiview/homography_error.h
- libmv/multiview/homography.h
- libmv/multiview/homography_parameterization.h
- libmv/multiview/nviewtriangulation.h
- libmv/multiview/panography.h
- libmv/multiview/panography_kernel.h
- libmv/multiview/projection.h
- libmv/multiview/resection.h
- libmv/multiview/triangulation.h
- libmv/multiview/two_view_kernel.h
- libmv/numeric/dogleg.h
- libmv/numeric/function_derivative.h
- libmv/numeric/levenberg_marquardt.h
- libmv/numeric/numeric.h
- libmv/numeric/poly.h
- libmv/simple_pipeline/bundle.h
- libmv/simple_pipeline/callbacks.h
- libmv/simple_pipeline/camera_intrinsics.h
- libmv/simple_pipeline/camera_intrinsics_impl.h
- libmv/simple_pipeline/detect.h
- libmv/simple_pipeline/distortion_models.h
- libmv/simple_pipeline/initialize_reconstruction.h
- libmv/simple_pipeline/intersect.h
- libmv/simple_pipeline/keyframe_selection.h
- libmv/simple_pipeline/modal_solver.h
- libmv/simple_pipeline/pipeline.h
- libmv/simple_pipeline/reconstruction.h
- libmv/simple_pipeline/reconstruction_scale.h
- libmv/simple_pipeline/resect.h
- libmv/simple_pipeline/tracks.h
- libmv/tracking/brute_region_tracker.h
- libmv/tracking/hybrid_region_tracker.h
- libmv/tracking/kalman_filter.h
- libmv/tracking/klt_region_tracker.h
- libmv/tracking/pyramid_region_tracker.h
- libmv/tracking/region_tracker.h
- libmv/tracking/retrack_region_tracker.h
- libmv/tracking/track_region.h
- libmv/tracking/trklt_region_tracker.h
-
- third_party/msinttypes/inttypes.h
- third_party/msinttypes/stdint.h
- )
-
-
- if(WITH_GTESTS)
- blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "" "")
-
- BLENDER_SRC_GTEST("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_vector" "./libmv/base/vector_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_array_nd" "./libmv/image/array_nd_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_convolve" "./libmv/image/convolve_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_image" "./libmv/image/image_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_sample" "./libmv/image/sample_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_tuple" "./libmv/image/tuple_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_homography" "./libmv/multiview/homography_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_panography" "./libmv/multiview/panography_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_projection" "./libmv/multiview/projection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_resection" "./libmv/multiview/resection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_numeric" "./libmv/numeric/numeric_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_poly" "./libmv/numeric/poly_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- BLENDER_SRC_GTEST("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
- endif()
-else()
- list(APPEND SRC
- intern/stub.cc
- )
-endif()
-
-blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
-
-if(WITH_LIBMV)
- add_subdirectory(third_party)
-endif()
-
-# make GLog a separate target, so it can be used for gtest as well.
-if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
- # We compile GLog together with GFlag so we don't worry about
- # adding extra lib to linker.
- set(GLOG_SRC
- third_party/gflags/gflags.cc
- third_party/gflags/gflags_completions.cc
- third_party/gflags/gflags_reporting.cc
-
- third_party/gflags/config.h
- third_party/gflags/gflags/gflags_completions.h
- third_party/gflags/gflags/gflags_declare.h
- third_party/gflags/gflags/gflags.h
- third_party/gflags/mutex.h
- third_party/gflags/util.h
- )
-
- if(WIN32)
- list(APPEND GLOG_SRC
- third_party/glog/src/logging.cc
- third_party/glog/src/raw_logging.cc
- third_party/glog/src/utilities.cc
- third_party/glog/src/vlog_is_on.cc
- third_party/glog/src/windows/port.cc
-
- third_party/glog/src/utilities.h
- third_party/glog/src/stacktrace_generic-inl.h
- third_party/glog/src/stacktrace.h
- third_party/glog/src/stacktrace_x86_64-inl.h
- third_party/glog/src/base/googleinit.h
- third_party/glog/src/base/mutex.h
- third_party/glog/src/base/commandlineflags.h
- third_party/glog/src/stacktrace_powerpc-inl.h
- third_party/glog/src/stacktrace_x86-inl.h
- third_party/glog/src/config.h
- third_party/glog/src/stacktrace_libunwind-inl.h
- third_party/glog/src/windows/glog/raw_logging.h
- third_party/glog/src/windows/glog/vlog_is_on.h
- third_party/glog/src/windows/glog/logging.h
- third_party/glog/src/windows/glog/log_severity.h
- third_party/glog/src/windows/port.h
- third_party/glog/src/windows/config.h
-
- third_party/gflags/windows_port.cc
- third_party/gflags/windows_port.h
- )
- else()
- list(APPEND GLOG_SRC
- third_party/glog/src/demangle.cc
- third_party/glog/src/logging.cc
- third_party/glog/src/raw_logging.cc
- third_party/glog/src/signalhandler.cc
- third_party/glog/src/symbolize.cc
- third_party/glog/src/utilities.cc
- third_party/glog/src/vlog_is_on.cc
-
- third_party/glog/src/base/commandlineflags.h
- third_party/glog/src/base/googleinit.h
- third_party/glog/src/base/mutex.h
- third_party/glog/src/config_freebsd.h
- third_party/glog/src/config.h
- third_party/glog/src/config_hurd.h
- third_party/glog/src/config_linux.h
- third_party/glog/src/config_mac.h
- third_party/glog/src/demangle.h
- third_party/glog/src/glog/logging.h
- third_party/glog/src/glog/log_severity.h
- third_party/glog/src/glog/raw_logging.h
- third_party/glog/src/glog/vlog_is_on.h
- third_party/glog/src/stacktrace_generic-inl.h
- third_party/glog/src/stacktrace.h
- third_party/glog/src/stacktrace_libunwind-inl.h
- third_party/glog/src/stacktrace_powerpc-inl.h
- third_party/glog/src/stacktrace_x86_64-inl.h
- third_party/glog/src/stacktrace_x86-inl.h
- third_party/glog/src/symbolize.h
- third_party/glog/src/utilities.h
- )
- endif()
-
- blender_add_lib(extern_glog "${GLOG_SRC}" "${INC}" "${INC_SYS}")
-endif()
diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog
deleted file mode 100644
index 0bb340b2491..00000000000
--- a/extern/libmv/ChangeLog
+++ /dev/null
@@ -1,707 +0,0 @@
-commit 7d6020d2ec42c6cb2749bc891186b4880d26d40b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Dec 31 15:32:07 2014 +0500
-
- Update GLog to latest upstream revision 143
-
- Mainly to solve compilation error with demangle.cc.
-
-commit 5dc746700eaf85cb674f0fb73ff3c1b49a7f6315
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Dec 12 14:59:55 2014 +0500
-
- Update GFlags to latest release 2.1.1
-
- Main purpose of this (andsome of upcoming) update is to check if the
- upstream sources are useable without any modifications for us. And if
- not, then we'll need to consider moving some changes into upstream.
-
- This commit contains an one-to-one copy of the upstream GFlags library
- and also changes namespace usage since it's changed in the upstream.
-
-commit 6fe6d75f7e90e161b44643b953f058a3829a5247
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Sat Nov 1 02:53:36 2014 +0500
-
- Libmv: Code cleanup, mixed class/struct in declaration/definition
-
-commit d2a5f7953812d2d09765431b59c6c4ac72faf35b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Oct 30 23:13:53 2014 +0500
-
- Libmv: Support disabled color channels in tracking settings
-
- This was never ported to a new tracking pipeline and now it's done using
- FrameAccessor::Transform routines. Quite striaghtforward, but i've changed
- order of grayscale conversion in blender side with call of transform callback.
-
- This way it's much easier to perform rescaling in libmv side.
-
-commit d976e034cdf74b34860e0632d7b29713f47c5756
-Author: Keir Mierle <mierle@gmail.com>
-Date: Sat Aug 23 00:38:01 2014 -0700
-
- Minor keyframe selection cleanups
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D757
-
-commit bc99ca55dadfca89fde0f93764397c2fe028943d
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Sat Aug 23 01:55:32 2014 +0600
-
- implement backward prediction
-
- The title actually says it all, just extend current implementation
- of PredictMarkerPosition() to cases when tracking happens in the reverse
- order (from the end frame to start).
-
- it's still doesn't solve all the ambiguity happening in the function
- in cases when one tracks the feature and then re-tracks it in order
- to refine the sliding. This is considered a separate TODO for now and
- will likely be solved by passing tracking direction to the prediction
- function.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D663
-
-commit 5b87682d98df65ade02638bc6482d824cf0dd0b3
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 21 22:45:22 2014 -0700
-
- Make libmv compile on Ubuntu 14.04
-
- Reviewers: fsiddi
-
- Reviewed By: fsiddi
-
- Subscribers: sergey
-
- Differential Revision: https://developer.blender.org/D755
-
-commit 0a81db623c458e0384b4f7060d1bcff8993fb469
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Jul 23 00:42:00 2014 +0600
-
- Fix wrong residual blocks counter
-
- This happened in cases when having zero-weighted tracks
- and could lead to some assert failures on marking parameter
- block constant.
-
-commit 2824dbac54cacf74828678be7a5c9fd960ce83e2
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Jul 18 12:52:03 2014 +0600
-
- Fix search area sliding issue
-
- The only way to do this is to store search region in floats
- and round when we need to sample it. Otherwise you'll always
- have sliding effect caused by rounding the issues, especially
- when doing incremental offset (thing which happens in the
- prediction code).
-
- Pretty much straightforward change apart from stuff to be kept
- in mind: offset calculation int should happen relative to the
- rounded search region. This is because tracker works in the space
- of the search window image which get's rounded on the frame access,
-
- This makes API a bit creepy because frame accessor uses the same
- Region struct as the search window in Marker and ideally we would
- need to have either IntRegion or Region<int> in order to make
- Libmv fully track on what's getting rounded and when.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D616
-
-commit 04862c479332308be47a0f27361402444ace8880
-Author: Keir Mierle <mierle@gmail.com>
-Date: Fri May 9 23:00:03 2014 +0200
-
- Start the automatic 2D tracking code
-
- This starts the 2D automatic tracking code. It is totally unfinished.
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D523
-
-commit be679f67d807a2139c1f7d7e2ca45141940b30d5
-Author: Keir Mierle <mierle@gmail.com>
-Date: Fri May 9 14:36:04 2014 +0200
-
- Also shift the search window
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D520
-
-commit 66b8f5eef2633ebcde32a388fc14c60171011821
-Author: Keir Mierle <mierle@gmail.com>
-Date: Fri May 9 13:06:28 2014 +0200
-
- Change the search region to absolute frame coordinates
-
- Smarter Eigen usage
-
- Better error logging
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D519
-
-commit a08193319ae409fad8f08887eae1f79f02e91eaa
-Author: Keir Mierle <mierle@gmail.com>
-Date: Fri May 9 12:02:47 2014 +0200
-
- First cut at predictive tracing
-
- This adds a Kalman filter-based approach to predict where a marker
- will go in the next frame to track. Hopefully this will make the
- tracker work faster by avoiding lengthy searches. This code
- compiles, but is otherwise untested, and likely does not work.
-
- Fix else branch
-
- Add some tests
-
- Update patch coordinates as well (and test)
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D518
-
-commit 607ffb2f62b56e34a841abbb952d83e19cd1e23c
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu May 8 16:05:28 2014 +0200
-
- Add constructor to AutoTrack
-
-commit c39e20a0c27da3733804c3848454b5d4c4f0e66b
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu May 8 16:04:20 2014 +0200
-
- Fix GetMarker compilation issue
-
-commit 8dd93e431b6e44439c803bfd26ec2669b656177e
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu May 8 15:50:26 2014 +0200
-
- Expose GetMarker() in AutoTrack
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D516
-
-commit 4405dff60ea08d454b64da1a7c0595d9328cf8a3
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu May 8 15:38:14 2014 +0200
-
- Add public SetMarkers to AutoTrack
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D515
-
-commit c90837f6db276a3b1f610eaad509155f6a43b24f
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu May 8 15:17:48 2014 +0200
-
- Make autotrack skeleton compile
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D514
-
-commit be01baa2e82e36f63e548f073157e68d2ff870c0
-Author: Keir Mierle <mierle@gmail.com>
-Date: Wed May 7 18:48:55 2014 +0200
-
- Add preliminary TrackMarkerToFrame in autotrack
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D509
-
-commit 0cab028d591b3d08672ca86eb6c6e4ac1aacf1d0
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed May 7 17:59:11 2014 +0200
-
- Remove assert from ArrayND Resize
-
- That assert broke initialization of arrays which doesn't
- own the data since constructor uses Resize to set shape
- and strides.
-
- Strides are still to be fixed, but that's for later.
-
-commit 64f9c118029a9351e9023e96527c120e1d724d5b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed May 7 17:42:21 2014 +0200
-
- Fix ArrayND freeing the data it doesn't own
-
- Can't really guarantee it works fully correct now,
- but at least this check is needed anyway and compilation
- works just fine.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D508
-
-commit 0618f1c8e88dfc738cdde55784da80b889905e7c
-Author: Keir Mierle <mierle@gmail.com>
-Date: Wed May 7 12:03:32 2014 +0200
-
- Minor changes
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D505
-
-commit 5c34335e1bb90c4ed701ee830c718ed4e20dbffa
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed May 7 11:12:23 2014 +0200
-
- Fix compilation error in frame accessor
-
- - int64 is not a standard type, we've got int64_t defined in
- std int. We also have an msvc port of this header, so should
- not be an issue.
-
- - Fixed inconsistency in usage of CacheKey and Key, used Key.
-
- - Some functions weren't marked as virtual.
-
- Additional change: added self to authors.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D504
-
-commit 06bc207614e262cd688e2c3ed820ade7c77bdb66
-Author: Keir Mierle <mierle@gmail.com>
-Date: Tue May 6 22:30:59 2014 +0200
-
- Start new Tracks implementation
-
- This adds the new Tracks implementation, as well as a
- trivial test to show it compiles.
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D502
-
-commit 25ce061e6da69881460ba7718bb0d660a2380a02
-Author: Keir Mierle <mierle@gmail.com>
-Date: Tue May 6 19:10:51 2014 +0200
-
- Add Reconstruction class for new API
-
- This starts the new Reconstruction class (with support for e.g. planes). This
- also starts the new namespace "mv" which will eventually have all the symbols
- we wish to export.
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D501
-
-commit 0a6af3e29016048978aea607673340500e050339
-Author: Keir Mierle <mierle@gmail.com>
-Date: Tue May 6 17:52:53 2014 +0200
-
- Add a new Tracks implementation
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D500
-
-commit 887b68d29c2b198f4939f9ab5153881aa2c1806e
-Author: Keir Mierle <mierle@gmail.com>
-Date: Tue May 6 17:01:39 2014 +0200
-
- Initial commit of unfinished AutoTrack API
-
- This starts the creating the new AutoTrack API. The new API will
- make it possible for libmv to do full autotracking, including
- predictive tracking and also support multiple motion models (3D
- planes etc).
-
- The first goal (not in this patch) is to convert Blender to use
- the new API without adding any new functionality.
-
- Note: This does not add any of the API to the build system!
- It likely does not compile.
-
- Reviewers: sergey
-
- Reviewed By: sergey
-
- Differential Revision: https://developer.blender.org/D499
-
-commit 08cc227d431d257d27f300fbb8e6991e663302da
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Tue May 6 13:09:22 2014 +0200
-
- Fix homography test failure
-
- It was caused by assuming that reconstructed homography matrix
- should look exactly the same as the matrix used to generate a
- test case.
-
- It's not actually valid assumption because different-looking
- matrices could correspond to the same exact transform.
-
- In this change we make it so actual "re-projected" vectors
- are being checked, not the values in matrix. This makes it
- more predictable verification.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D488
-
-commit 0b7d83dc9627447dc7df64d7e3a468aefe9ddc13
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Apr 23 19:14:55 2014 +0600
-
- Fix compilation on OSX after previous commit
-
- EXPECT_EQ wasn't defined in the scope.
-
-commit d14049e00dabf8fdf49056779f0a3718fbb39e8f
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Apr 23 15:08:16 2014 +0600
-
- Move aligned malloc implementation into own file
-
- It was rather stupid having it in brute region tracker,
- now it is in own file in base library (which was also
- added in this commit, before this it consist of header
- files only).
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D479
-
-commit 0ddf3851bfcb8de43660b119a25a77a25674200d
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Mon Apr 21 14:14:03 2014 +0600
-
- Optimization of PearsonProductMomentCorrelation
-
- Pass the arrays by reference rather than by value,
- should give some percent of speedup.
-
- Also don't pass the dimensions to the function but
- get them from the images themselves.
-
- Hopefully this will give some %% of tracker speedup.
-
-commit f68fdbe5896a6c5bd8b500caeec61b876c5e44c6
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Mon Apr 21 14:10:43 2014 +0600
-
- Fix wrong assert in ResizeImage()
-
- The assert didn't make any sense because ComputeBoundingBox()
- is intended to return bounding box in the following way:
- (xmin, xmax, ymin, ymax).
-
-commit 1d386b6775a71c499e9b8e4a288c0785c4937677
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Apr 17 18:42:43 2014 +0600
-
- Add unit tests for buffer (un)distortion
-
- Currently only uses identity camera intrinsics just to
- see whether lookup grids are properly allocated.
-
- Should prevent accidents like that one happened recently
- with crashing Blender after Libmv re-integration.
-
-commit e1fe41b6604771ba769a9b15eb2f489fbf7af251
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Apr 17 17:52:23 2014 +0600
-
- Fix offset array not being properly allocated
-
- We really do need unit test for buffer (un)distortion,
- didn't notice this bug for until new Libmv has been
- integrated into Blender.
-
-commit ee21415a353396df67ef21e82adaffab2a8d2a0a
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Apr 17 16:26:12 2014 +0600
-
- Support multiple distortion models, including a new division model
-
- This commit makes it so CameraIntrinsics is no longer hardcoded
- to use the traditional polynomial radial distortion model. Currently
- the distortion code has generic logic which is shared between
- different distortion models, but had no other models until now.
-
- This moves everything specific to the polynomial radial distortion
- to a subclass PolynomialDistortionCameraIntrinsics(), and adds a
- new division distortion model suitable for cameras such as the
- GoPro which have much stronger distortion due to their fisheye lens.
-
- This also cleans up the internal API of CameraIntrinsics to make
- it easier to understand and reduces old C-style code.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- CC: jta
-
- Differential Revision: https://developer.blender.org/D335
-
-commit 313252083f6dfa69a93c287bed81dec616503c1b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Tue Apr 15 18:23:38 2014 +0600
-
- Fix failure of the image transform linear test
-
- Mainly was caused by the flakyness of image rotation in cases
- when image has even size. The test was expecting the transform
- code to rotate the image around pixel corner, which isn't a
- common behavior in image processing applications. Rotation
- is usually done around the pixel center.
-
- So now made it so RotateImage() rotates the image around the
- pixel center which gives 100% proper result for odd sized images
- (i.e. center pixel stays untouched).
-
- Also made the tests to use odd image sizes which are more
- predictable by the humans. We can use even sized images in the
- tests as well but their result wouldn't be so much spectacular.
-
- Another issue with the tests was caused by RescaleImageTranslation
- test which did expect things which are not happening in the
- function.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D463
-
-commit 80d6945bf5f996b97cd41df0e422afce5e10e7f9
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Mon Apr 14 00:01:32 2014 +0600
-
- Unit tests for feature detector
-
- Currently covers only simplest cases with synthetic images.
- Also at this point mainly Harris detector is being testes,
- other detectors behaves a bit unexpected on synthetic images
- and this is to be investigated further.
-
- Tests will be extended further later.
-
- Additional change:
-
- - Added constructor to Feature structure
- - Added operator << for feature for easier debug dumps.
-
- TODO: Some tests are not giving the result which i was expected
- to. This is to be investigated further by finding the reference
- detector implementation. For until then keeping that tests
- commented out.
-
- Reviewers: keir
-
- Reviewed By: keir
-
- Differential Revision: https://developer.blender.org/D316
-
-commit 397c3d3ed46eb4967eb285c8369cc125bea4b132
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Apr 4 16:17:57 2014 +0600
-
- Compilation error fix
-
- Not totally sure why this is needed, but multiview indeed
- uses V3D library still, so it needs to be linked against it.
-
- Patc by Martijn Berger, thanks!
-
-commit 1c36279239cbffe152493106eb04e55df7ebd649
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Apr 4 14:03:43 2014 +0600
-
- Upgrade Eigen to 3.2.1 version
-
- To main reasons for this:
- - Probably this would solve strict compiler warnings
- - It brings new stuff like sparse LU decomposition which
- might be useful in the future.
-
-commit de698f442934f475478463445f78a00ea632e823
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Apr 3 15:08:26 2014 +0600
-
- Fix compilation error when using make from the sources root
-
- - Don't force flann to be static. It's a general rule on linux
- to have dynamic libraries for all the bits instead of having
- statically-linked dynamic libraries.
-
- - Some weirdo stuff was happening around OpenExif, it was only
- built on Apple, so don't link targets against this lib on
- other platforms.
-
- - Some libraries were missing for qt-tracker.
-
-commit 901b146f28825d3e05f4157ca2a34ae00261b91a
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Mar 26 17:44:09 2014 +0600
-
- Fix bad memory write in BA code when having zero-weighted tracks
-
- Issue was really stupid and caused by the wrong vector initialization.
-
-commit d14a372dfe09c7339f267c4904a541fbe2efec43
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Mar 21 16:02:41 2014 +0600
-
- Attempt to fix compilation error with msvc2013
-
-commit 933531580b4dc4b65601d785cedc16506d615d7b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Mar 20 23:07:34 2014 +0600
-
- Compilation fixes for MinGW
-
- Many thanks to Antony Riakiotakis for the patch!
-
-commit f1aefcbf58fe04ea2967434f39f703bb486777c8
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Feb 27 16:21:19 2014 +0600
-
- Implement separate BA step for tracks which have constant zero weight
-
- This is needed to minimize their reprojection error over the footage.
- Without this extra step positions of such tracks were calculated by
- algebraic intersection code only, which doesn't give best precision.
-
-commit bcf7f9470b2ea33cf89a31a72037ec03be631637
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Feb 27 14:16:42 2014 +0600
-
- Avoid zero-sized problem when doing euclidean intersection
-
- Zero-sized problem might occur when intersecting track with
- constant zero weight. For such tracks we'll just use result
- of algebraic intersection.
-
- TODO: We probably need to have a separate BA step to adjust
- positions of tracks with constant zero weight.
-
-commit f884bb20a93189b8210639f3de939c64177d66b3
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Feb 26 18:00:40 2014 +0600
-
- Ignore zero weighted markers in keyframe selection
-
- It doesn't make sense to use zero-weighted tracks as a correspondences
- in keyframe selection.
-
- Such tracks are not guaranteed to be tracked accurately because their
- purpose is to add reference points in 3D space without affecting the
- solution.
-
-commit 74db5175cdbcabe673b82eef59c88fb7f342c43f
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Feb 26 13:23:02 2014 +0600
-
- Tweaks to make bundling into Blender warning-less
-
- Mainly issue i caused by conflicts in include directories,
- so glog used to include config.h from gflags. It might be
- fixed by splitting gflags/glog from Libmv in Blender build
- system but that's not something fun to work on. Fixed by
- making include directories bit more explicit.
-
- Also solved no-previous-prototype warnings.
-
-commit bc4bc66af0115069562b79e837ccf4fd95c8f97e
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 21 14:55:13 2014 +0600
-
- Raise epsilon used for model solver test
-
- It was too much small leading to false failure triggering
- caused simply by precision issues.
-
-commit bf750590a6af4af3622c01fd1004c44da60484a7
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Tue Feb 18 23:35:52 2014 +0600
-
- Made it possible to link against Ceres installed on the system
-
- Main purpose of this is to get away from bundled Ceres library
- which is not so trivial to re-bundle and takes some to do this
- (not talking about CMake options conflicts and pollution).
-
- Enabled by setting WITH_SYSTEM_CERES=ON. Default paths to search
- Ceres library:
-
- - /usr/local
- - /sw
- - /opt/local
- - /opt/csw
- - /opt/lib/ceres
-
- You might also specify Ceres root directory using CERES_ROOT_DIR
- variable (both CMake and environment variables are supported).
-
- If your Ceres is build statically, you're to control all additional
- libraries needed to link against using CMAKE_EXE_LINKER_FLAGS.
-
-commit c9156fbf80c86853806844b754b1e48f45c5ec11
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Tue Feb 18 19:38:22 2014 +0600
-
- Remove .orig file which was added by accident
diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript
deleted file mode 100644
index 251e5835d64..00000000000
--- a/extern/libmv/SConscript
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/python
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-import sys
-import os
-
-Import('env')
-
-defs = []
-incs = '.'
-
-if env['WITH_BF_LIBMV'] or (env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_LOGGING']):
- defs.append('GOOGLE_GLOG_DLL_DECL=')
- defs.append('WITH_LIBMV_GUARDED_ALLOC')
- defs.append('LIBMV_NO_FAST_DETECTOR')
-
- incs += ' ../Eigen3 third_party/gflags third_party/gflags/gflags third_party/glog/src third_party/ceres/include third_party/ceres/config ../../intern/guardedalloc'
- incs += ' ' + env['BF_PNG_INC']
- incs += ' ' + env['BF_ZLIB_INC']
-
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog'
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- incs += ' ./third_party/msinttypes'
- else:
- incs += ' ./third_party/glog/src'
-
-if env['WITH_BF_LIBMV']:
- if not env['WITH_SHARED_PTR_SUPPORT']:
- print("-- Unable to find shared_ptr which is required for compilation.")
- exit(1)
-
- if env['SHARED_PTR_HEADER'] == 'tr1/memory':
- defs.append('CERES_TR1_MEMORY_HEADER')
- if env['SHARED_PTR_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_TR1_SHARED_PTR')
-
- src = env.Glob('intern/*.cc')
- src.remove('intern' + os.sep + 'stub.cc')
- src += env.Glob('libmv/autotrack/*.cc')
- src += env.Glob('libmv/base/*.cc')
- src += env.Glob('libmv/image/*.cc')
- src += env.Glob('libmv/multiview/*.cc')
- src += env.Glob('libmv/numeric/*.cc')
- src += env.Glob('libmv/simple_pipeline/*.cc')
- src += env.Glob('libmv/tracking/*.cc')
-else:
- src = env.Glob("intern/stub.cc")
-
-src = [src for src in src if src.find('_test.cc') == -1]
-
-env.BlenderLib(libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137])
-
-if env['WITH_BF_LIBMV'] or (env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_LOGGING']):
- glog_src = []
- glog_src += env.Glob("third_party/gflags/*.cc")
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- glog_src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
- glog_src += ['./third_party/glog/src/windows/port.cc']
- else:
- glog_src.remove('third_party/gflags/windows_port.cc')
- glog_src += env.Glob("third_party/glog/src/*.cc")
-
- env.BlenderLib(libname = 'extern_glog', sources=glog_src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137])
-
-if env['WITH_BF_LIBMV']:
- SConscript(['third_party/SConscript'])
diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh
deleted file mode 100755
index ac4190041bd..00000000000
--- a/extern/libmv/bundle.sh
+++ /dev/null
@@ -1,344 +0,0 @@
-#!/bin/sh
-
-if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then
- echo Proceeding as requested by command line ...
-else
- echo "*** Please run again with --i-really-know-what-im-doing ..."
- exit 1
-fi
-
-BRANCH="master"
-
-repo="git://git.blender.org/libmv.git"
-tmp=`mktemp -d`
-
-git clone -b $BRANCH $repo $tmp/libmv
-
-git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log -n 50 > ChangeLog
-
-find libmv -type f -not -iwholename '*.svn*' -exec rm -rf {} \;
-find third_party -type f -not -iwholename '*.svn*' -not -iwholename '*third_party/ceres*' \
- -not -iwholename '*third_party/SConscript*' -not -iwholename '*third_party/CMakeLists.txt*' \
- -exec rm -rf {} \;
-
-cat "files.txt" | while read f; do
- mkdir -p `dirname $f`
- cp $tmp/libmv/src/$f $f
-done
-
-rm -rf $tmp
-
-chmod 664 ./third_party/glog/src/windows/*.cc ./third_party/glog/src/windows/*.h ./third_party/glog/src/windows/glog/*.h
-
-sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v _test.cc | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d`
-headers=`find ./libmv -type f -iname '*.h' | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d`
-
-third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v glog | grep -v gflags | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d`
-third_headers=`find ./third_party -type f -iname '*.h' | grep -v glog | grep -v gflags | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d`
-
-third_glog_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t\t/' | sort -d`
-third_glog_headers=`find ./third_party -type f -iname '*.h' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t\t/' | sort -d`
-
-third_gflags_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep gflags | grep -v windows | sed -r 's/^\.\//\t\t/' | sort -d`
-third_gflags_headers=`find ./third_party -type f -iname '*.h' | grep gflags | grep -v windows | sed -r 's/^\.\//\t\t/' | sort -d`
-
-tests=`find ./libmv -type f -iname '*_test.cc' | sort -d | awk ' { name=gensub(".*/([A-Za-z_]+)_test.cc", "\\\\1", $1); printf("\t\tBLENDER_SRC_GTEST(\"libmv_%s\" \"%s\" \"libmv_test_dataset;extern_libmv;extern_ceres\")\n", name, $1) } '`
-
-src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
-src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
-src=""
-win_src=""
-for x in $src_dir $src_third_dir; do
- t=""
-
- if test `echo "$x" | grep -c glog ` -eq 1; then
- continue;
- fi
-
- if stat $x/*.cpp > /dev/null 2>&1; then
- t=" src += env.Glob('`echo $x'/*.cpp'`')"
- fi
-
- if stat $x/*.c > /dev/null 2>&1; then
- if [ -z "$t" ]; then
- t=" src += env.Glob('`echo $x'/*.c'`')"
- else
- t="$t + env.Glob('`echo $x'/*.c'`')"
- fi
- fi
-
- if stat $x/*.cc > /dev/null 2>&1; then
- if [ -z "$t" ]; then
- t=" src += env.Glob('`echo $x'/*.cc'`')"
- else
- t="$t + env.Glob('`echo $x'/*.cc'`')"
- fi
- fi
-
- if test `echo $x | grep -c "windows\|gflags" ` -eq 0; then
- if [ -z "$src" ]; then
- src=$t
- else
- src=`echo "$src\n$t"`
- fi
- else
- if [ -z "$win_src" ]; then
- win_src=`echo " $t"`
- else
- win_src=`echo "$win_src\n $t"`
- fi
- fi
-done
-
-cat > CMakeLists.txt << EOF
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# Contributor(s): Blender Foundation,
-# Sergey Sharybin
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-set(INC
- .
-)
-
-set(INC_SYS
-)
-
-set(SRC
- libmv-capi.h
-)
-
-if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
- list(APPEND INC
- third_party/gflags
- third_party/gflags/gflags
- third_party/glog/src
- third_party/ceres/include
- third_party/ceres/config
- ../../intern/guardedalloc
- )
-
- list(APPEND INC_SYS
- \${EIGEN3_INCLUDE_DIRS}
- \${PNG_INCLUDE_DIRS}
- \${ZLIB_INCLUDE_DIRS}
- )
-
- if(WIN32)
- list(APPEND INC
- third_party/glog/src/windows
- )
-
- if(NOT MINGW)
- list(APPEND INC
- third_party/msinttypes
- )
- endif()
- endif()
-
- add_definitions(
- -DWITH_LIBMV_GUARDED_ALLOC
- -DGOOGLE_GLOG_DLL_DECL=
- -DLIBMV_NO_FAST_DETECTOR=
- )
-endif()
-
-if(WITH_LIBMV)
- TEST_SHARED_PTR_SUPPORT()
- if(SHARED_PTR_FOUND)
- if(SHARED_PTR_TR1_MEMORY_HEADER)
- add_definitions(-DCERES_TR1_MEMORY_HEADER)
- endif()
- if(SHARED_PTR_TR1_NAMESPACE)
- add_definitions(-DCERES_TR1_SHARED_PTR)
- endif()
- else()
- message(FATAL_ERROR "Unable to find shared_ptr.")
- endif()
-
- list(APPEND SRC
- intern/autotrack.cc
- intern/camera_intrinsics.cc
- intern/detector.cc
- intern/frame_accessor.cc
- intern/homography.cc
- intern/image.cc
- intern/logging.cc
- intern/reconstruction.cc
- intern/track_region.cc
- intern/tracks.cc
- intern/tracksN.cc
-${sources}
-${third_sources}
-
- intern/autotrack.h
- intern/camera_intrinsics.h
- intern/detector.h
- intern/frame_accessor.h
- intern/homography.h
- intern/image.h
- intern/logging.h
- intern/reconstruction.h
- intern/track_region.h
- intern/tracks.h
- intern/tracksN.h
-${headers}
-
-${third_headers}
- )
-
-
- if(WITH_GTESTS)
- blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "${INC}" "${INC_SYS}")
-
-${tests}
- endif()
-else()
- list(APPEND SRC
- intern/stub.cc
- )
-endif()
-
-blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
-
-if(WITH_LIBMV)
- add_subdirectory(third_party)
-endif()
-
-# make GLog a separate target, so it can be used for gtest as well.
-if(WITH_LIBMV OR WITH_GTESTS OR (WITH_CYCLES AND WITH_CYCLES_LOGGING))
- # We compile GLog together with GFlag so we don't worry about
- # adding extra lib to linker.
- set(GLOG_SRC
-${third_gflags_sources}
-
-${third_gflags_headers}
- )
-
- if(WIN32)
- list(APPEND GLOG_SRC
- third_party/glog/src/logging.cc
- third_party/glog/src/raw_logging.cc
- third_party/glog/src/utilities.cc
- third_party/glog/src/vlog_is_on.cc
- third_party/glog/src/windows/port.cc
-
- third_party/glog/src/utilities.h
- third_party/glog/src/stacktrace_generic-inl.h
- third_party/glog/src/stacktrace.h
- third_party/glog/src/stacktrace_x86_64-inl.h
- third_party/glog/src/base/googleinit.h
- third_party/glog/src/base/mutex.h
- third_party/glog/src/base/commandlineflags.h
- third_party/glog/src/stacktrace_powerpc-inl.h
- third_party/glog/src/stacktrace_x86-inl.h
- third_party/glog/src/config.h
- third_party/glog/src/stacktrace_libunwind-inl.h
- third_party/glog/src/windows/glog/raw_logging.h
- third_party/glog/src/windows/glog/vlog_is_on.h
- third_party/glog/src/windows/glog/logging.h
- third_party/glog/src/windows/glog/log_severity.h
- third_party/glog/src/windows/port.h
- third_party/glog/src/windows/config.h
-
- third_party/gflags/windows_port.cc
- third_party/gflags/windows_port.h
- )
- else()
- list(APPEND GLOG_SRC
-${third_glog_sources}
-
-${third_glog_headers}
- )
- endif()
-
- blender_add_lib(extern_glog "\${GLOG_SRC}" "\${INC}" "\${INC_SYS}")
-endif()
-EOF
-
-cat > SConscript << EOF
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-import sys
-import os
-
-Import('env')
-
-defs = []
-incs = '.'
-
-if env['WITH_BF_LIBMV'] or (env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_LOGGING']):
- defs.append('GOOGLE_GLOG_DLL_DECL=')
- defs.append('WITH_LIBMV_GUARDED_ALLOC')
- defs.append('LIBMV_NO_FAST_DETECTOR')
-
- incs += ' ../Eigen3 third_party/gflags third_party/gflags/gflags third_party/glog/src third_party/ceres/include third_party/ceres/config ../../intern/guardedalloc'
- incs += ' ' + env['BF_PNG_INC']
- incs += ' ' + env['BF_ZLIB_INC']
-
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog'
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- incs += ' ./third_party/msinttypes'
- else:
- incs += ' ./third_party/glog/src'
-
-if env['WITH_BF_LIBMV']:
- if not env['WITH_SHARED_PTR_SUPPORT']:
- print("-- Unable to find shared_ptr which is required for compilation.")
- exit(1)
-
- if env['SHARED_PTR_HEADER'] == 'tr1/memory':
- defs.append('CERES_TR1_MEMORY_HEADER')
- if env['SHARED_PTR_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_TR1_SHARED_PTR')
-
- src = env.Glob('intern/*.cc')
- src.remove('intern' + os.sep + 'stub.cc')
-$src
-else:
- src = env.Glob("intern/stub.cc")
-
-src = [src for src in src if src.find('_test.cc') == -1]
-
-env.BlenderLib(libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137])
-
-if env['WITH_BF_LIBMV'] or (env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_LOGGING']):
- glog_src = []
- glog_src += env.Glob("third_party/gflags/*.cc")
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- glog_src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
- glog_src += ['./third_party/glog/src/windows/port.cc']
- else:
- glog_src.remove('third_party/gflags/windows_port.cc')
- glog_src += env.Glob("third_party/glog/src/*.cc")
-
- env.BlenderLib(libname = 'extern_glog', sources=glog_src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137])
-
-if env['WITH_BF_LIBMV']:
- SConscript(['third_party/SConscript'])
-EOF
diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt
deleted file mode 100644
index 11f8ef24781..00000000000
--- a/extern/libmv/files.txt
+++ /dev/null
@@ -1,196 +0,0 @@
-libmv/autotrack/autotrack.cc
-libmv/autotrack/autotrack.h
-libmv/autotrack/callbacks.h
-libmv/autotrack/frame_accessor.h
-libmv/autotrack/marker.h
-libmv/autotrack/model.h
-libmv/autotrack/predict_tracks.cc
-libmv/autotrack/predict_tracks.h
-libmv/autotrack/predict_tracks_test.cc
-libmv/autotrack/quad.h
-libmv/autotrack/reconstruction.h
-libmv/autotrack/region.h
-libmv/autotrack/tracks.cc
-libmv/autotrack/tracks.h
-libmv/autotrack/tracks_test.cc
-libmv/base/aligned_malloc.cc
-libmv/base/aligned_malloc.h
-libmv/base/id_generator.h
-libmv/base/scoped_ptr.h
-libmv/base/scoped_ptr_test.cc
-libmv/base/vector.h
-libmv/base/vector_test.cc
-libmv/base/vector_utils.h
-libmv/image/array_nd.cc
-libmv/image/array_nd.h
-libmv/image/array_nd_test.cc
-libmv/image/convolve.cc
-libmv/image/convolve.h
-libmv/image/convolve_test.cc
-libmv/image/correlation.h
-libmv/image/image_converter.h
-libmv/image/image_drawing.h
-libmv/image/image.h
-libmv/image/image_test.cc
-libmv/image/sample.h
-libmv/image/sample_test.cc
-libmv/image/tuple.h
-libmv/image/tuple_test.cc
-libmv/logging/logging.h
-libmv/multiview/conditioning.cc
-libmv/multiview/conditioning.h
-libmv/multiview/euclidean_resection.cc
-libmv/multiview/euclidean_resection.h
-libmv/multiview/euclidean_resection_test.cc
-libmv/multiview/fundamental.cc
-libmv/multiview/fundamental.h
-libmv/multiview/fundamental_test.cc
-libmv/multiview/homography.cc
-libmv/multiview/homography_error.h
-libmv/multiview/homography.h
-libmv/multiview/homography_parameterization.h
-libmv/multiview/homography_test.cc
-libmv/multiview/nviewtriangulation.h
-libmv/multiview/nviewtriangulation_test.cc
-libmv/multiview/panography.cc
-libmv/multiview/panography.h
-libmv/multiview/panography_kernel.cc
-libmv/multiview/panography_kernel.h
-libmv/multiview/panography_test.cc
-libmv/multiview/projection.cc
-libmv/multiview/projection.h
-libmv/multiview/projection_test.cc
-libmv/multiview/resection.h
-libmv/multiview/resection_test.cc
-libmv/multiview/test_data_sets.cc
-libmv/multiview/test_data_sets.h
-libmv/multiview/triangulation.cc
-libmv/multiview/triangulation.h
-libmv/multiview/triangulation_test.cc
-libmv/multiview/two_view_kernel.h
-libmv/numeric/dogleg.h
-libmv/numeric/dogleg_test.cc
-libmv/numeric/function_derivative.h
-libmv/numeric/function_derivative_test.cc
-libmv/numeric/levenberg_marquardt.h
-libmv/numeric/levenberg_marquardt_test.cc
-libmv/numeric/numeric.cc
-libmv/numeric/numeric.h
-libmv/numeric/numeric_test.cc
-libmv/numeric/poly.cc
-libmv/numeric/poly.h
-libmv/numeric/poly_test.cc
-libmv/simple_pipeline/bundle.cc
-libmv/simple_pipeline/bundle.h
-libmv/simple_pipeline/callbacks.h
-libmv/simple_pipeline/camera_intrinsics.cc
-libmv/simple_pipeline/camera_intrinsics.h
-libmv/simple_pipeline/camera_intrinsics_impl.h
-libmv/simple_pipeline/camera_intrinsics_test.cc
-libmv/simple_pipeline/detect.cc
-libmv/simple_pipeline/detect.h
-libmv/simple_pipeline/detect_test.cc
-libmv/simple_pipeline/distortion_models.cc
-libmv/simple_pipeline/distortion_models.h
-libmv/simple_pipeline/initialize_reconstruction.cc
-libmv/simple_pipeline/initialize_reconstruction.h
-libmv/simple_pipeline/intersect.cc
-libmv/simple_pipeline/intersect.h
-libmv/simple_pipeline/intersect_test.cc
-libmv/simple_pipeline/keyframe_selection.cc
-libmv/simple_pipeline/keyframe_selection.h
-libmv/simple_pipeline/keyframe_selection_test.cc
-libmv/simple_pipeline/modal_solver.cc
-libmv/simple_pipeline/modal_solver.h
-libmv/simple_pipeline/modal_solver_test.cc
-libmv/simple_pipeline/pipeline.cc
-libmv/simple_pipeline/pipeline.h
-libmv/simple_pipeline/reconstruction.cc
-libmv/simple_pipeline/reconstruction.h
-libmv/simple_pipeline/reconstruction_scale.cc
-libmv/simple_pipeline/reconstruction_scale.h
-libmv/simple_pipeline/resect.cc
-libmv/simple_pipeline/resect.h
-libmv/simple_pipeline/resect_test.cc
-libmv/simple_pipeline/tracks.cc
-libmv/simple_pipeline/tracks.h
-libmv/tracking/brute_region_tracker.cc
-libmv/tracking/brute_region_tracker.h
-libmv/tracking/brute_region_tracker_test.cc
-libmv/tracking/hybrid_region_tracker.cc
-libmv/tracking/hybrid_region_tracker.h
-libmv/tracking/kalman_filter.h
-libmv/tracking/klt_region_tracker.cc
-libmv/tracking/klt_region_tracker.h
-libmv/tracking/klt_region_tracker_test.cc
-libmv/tracking/pyramid_region_tracker.cc
-libmv/tracking/pyramid_region_tracker.h
-libmv/tracking/pyramid_region_tracker_test.cc
-libmv/tracking/region_tracker.h
-libmv/tracking/retrack_region_tracker.cc
-libmv/tracking/retrack_region_tracker.h
-libmv/tracking/track_region.cc
-libmv/tracking/track_region.h
-libmv/tracking/trklt_region_tracker.cc
-libmv/tracking/trklt_region_tracker.h
-third_party/gflags/AUTHORS.txt
-third_party/gflags/ChangeLog.txt
-third_party/gflags/config.h
-third_party/gflags/COPYING.txt
-third_party/gflags/gflags.cc
-third_party/gflags/gflags_completions.cc
-third_party/gflags/gflags/gflags_completions.h
-third_party/gflags/gflags/gflags_declare.h
-third_party/gflags/gflags/gflags.h
-third_party/gflags/gflags_reporting.cc
-third_party/gflags/mutex.h
-third_party/gflags/NEWS.txt
-third_party/gflags/README.libmv
-third_party/gflags/util.h
-third_party/gflags/windows_port.cc
-third_party/gflags/windows_port.h
-third_party/glog/AUTHORS
-third_party/glog/ChangeLog
-third_party/glog/COPYING
-third_party/glog/NEWS
-third_party/glog/README
-third_party/glog/README.libmv
-third_party/glog/src/base/commandlineflags.h
-third_party/glog/src/base/googleinit.h
-third_party/glog/src/base/mutex.h
-third_party/glog/src/config_freebsd.h
-third_party/glog/src/config.h
-third_party/glog/src/config_hurd.h
-third_party/glog/src/config_linux.h
-third_party/glog/src/config_mac.h
-third_party/glog/src/demangle.cc
-third_party/glog/src/demangle.h
-third_party/glog/src/glog/logging.h
-third_party/glog/src/glog/log_severity.h
-third_party/glog/src/glog/raw_logging.h
-third_party/glog/src/glog/vlog_is_on.h
-third_party/glog/src/logging.cc
-third_party/glog/src/raw_logging.cc
-third_party/glog/src/signalhandler.cc
-third_party/glog/src/stacktrace_generic-inl.h
-third_party/glog/src/stacktrace.h
-third_party/glog/src/stacktrace_libunwind-inl.h
-third_party/glog/src/stacktrace_powerpc-inl.h
-third_party/glog/src/stacktrace_x86_64-inl.h
-third_party/glog/src/stacktrace_x86-inl.h
-third_party/glog/src/symbolize.cc
-third_party/glog/src/symbolize.h
-third_party/glog/src/utilities.cc
-third_party/glog/src/utilities.h
-third_party/glog/src/vlog_is_on.cc
-third_party/glog/src/windows/config.h
-third_party/glog/src/windows/glog/logging.h
-third_party/glog/src/windows/glog/log_severity.h
-third_party/glog/src/windows/glog/raw_logging.h
-third_party/glog/src/windows/glog/vlog_is_on.h
-third_party/glog/src/windows/port.cc
-third_party/glog/src/windows/port.h
-third_party/glog/src/windows/preprocess.sh
-third_party/msinttypes/inttypes.h
-third_party/msinttypes/README.libmv
-third_party/msinttypes/stdint.h
diff --git a/extern/libmv/intern/camera_intrinsics.cc b/extern/libmv/intern/camera_intrinsics.cc
deleted file mode 100644
index 0ce757cc93b..00000000000
--- a/extern/libmv/intern/camera_intrinsics.cc
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2011 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "intern/camera_intrinsics.h"
-#include "intern/utildefines.h"
-#include "libmv/simple_pipeline/camera_intrinsics.h"
-
-using libmv::CameraIntrinsics;
-using libmv::DivisionCameraIntrinsics;
-using libmv::PolynomialCameraIntrinsics;
-
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) {
- CameraIntrinsics *camera_intrinsics =
- libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
- return (libmv_CameraIntrinsics *) camera_intrinsics;
-}
-
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
- const libmv_CameraIntrinsics* libmv_intrinsics) {
- const CameraIntrinsics *orig_intrinsics =
- (const CameraIntrinsics *) libmv_intrinsics;
-
- CameraIntrinsics *new_intrinsics = NULL;
- switch (orig_intrinsics->GetDistortionModelType()) {
- case libmv::DISTORTION_MODEL_POLYNOMIAL:
- {
- const PolynomialCameraIntrinsics *polynomial_intrinsics =
- static_cast<const PolynomialCameraIntrinsics*>(orig_intrinsics);
- new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics,
- *polynomial_intrinsics);
- break;
- }
- case libmv::DISTORTION_MODEL_DIVISION:
- {
- const DivisionCameraIntrinsics *division_intrinsics =
- static_cast<const DivisionCameraIntrinsics*>(orig_intrinsics);
- new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics,
- *division_intrinsics);
- break;
- }
- default:
- assert(!"Unknown distortion model");
- }
- return (libmv_CameraIntrinsics *) new_intrinsics;
-}
-
-void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) {
- LIBMV_OBJECT_DELETE(libmv_intrinsics, CameraIntrinsics);
-}
-
-void libmv_cameraIntrinsicsUpdate(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- libmv_CameraIntrinsics* libmv_intrinsics) {
- CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
-
- double focal_length = libmv_camera_intrinsics_options->focal_length;
- double principal_x = libmv_camera_intrinsics_options->principal_point_x;
- double principal_y = libmv_camera_intrinsics_options->principal_point_y;
- int image_width = libmv_camera_intrinsics_options->image_width;
- int image_height = libmv_camera_intrinsics_options->image_height;
-
- /* Try avoid unnecessary updates, so pre-computed distortion grids
- * are not freed.
- */
-
- if (camera_intrinsics->focal_length() != focal_length) {
- camera_intrinsics->SetFocalLength(focal_length, focal_length);
- }
-
- if (camera_intrinsics->principal_point_x() != principal_x ||
- camera_intrinsics->principal_point_y() != principal_y) {
- camera_intrinsics->SetPrincipalPoint(principal_x, principal_y);
- }
-
- if (camera_intrinsics->image_width() != image_width ||
- camera_intrinsics->image_height() != image_height) {
- camera_intrinsics->SetImageSize(image_width, image_height);
- }
-
- switch (libmv_camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- {
- assert(camera_intrinsics->GetDistortionModelType() ==
- libmv::DISTORTION_MODEL_POLYNOMIAL);
-
- PolynomialCameraIntrinsics *polynomial_intrinsics =
- (PolynomialCameraIntrinsics *) camera_intrinsics;
-
- double k1 = libmv_camera_intrinsics_options->polynomial_k1;
- double k2 = libmv_camera_intrinsics_options->polynomial_k2;
- double k3 = libmv_camera_intrinsics_options->polynomial_k3;
-
- if (polynomial_intrinsics->k1() != k1 ||
- polynomial_intrinsics->k2() != k2 ||
- polynomial_intrinsics->k3() != k3) {
- polynomial_intrinsics->SetRadialDistortion(k1, k2, k3);
- }
- break;
- }
-
- case LIBMV_DISTORTION_MODEL_DIVISION:
- {
- assert(camera_intrinsics->GetDistortionModelType() ==
- libmv::DISTORTION_MODEL_DIVISION);
-
- DivisionCameraIntrinsics *division_intrinsics =
- (DivisionCameraIntrinsics *) camera_intrinsics;
-
- double k1 = libmv_camera_intrinsics_options->division_k1;
- double k2 = libmv_camera_intrinsics_options->division_k2;
-
- if (division_intrinsics->k1() != k1 ||
- division_intrinsics->k2() != k2) {
- division_intrinsics->SetDistortion(k1, k2);
- }
-
- break;
- }
-
- default:
- assert(!"Unknown distortion model");
- }
-}
-
-void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics,
- int threads) {
- CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- camera_intrinsics->SetThreads(threads);
-}
-
-void libmv_cameraIntrinsicsExtractOptions(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
- const CameraIntrinsics *camera_intrinsics =
- (const CameraIntrinsics *) libmv_intrinsics;
-
- // Fill in options which are common for all distortion models.
- camera_intrinsics_options->focal_length = camera_intrinsics->focal_length();
- camera_intrinsics_options->principal_point_x =
- camera_intrinsics->principal_point_x();
- camera_intrinsics_options->principal_point_y =
- camera_intrinsics->principal_point_y();
-
- camera_intrinsics_options->image_width = camera_intrinsics->image_width();
- camera_intrinsics_options->image_height = camera_intrinsics->image_height();
-
- switch (camera_intrinsics->GetDistortionModelType()) {
- case libmv::DISTORTION_MODEL_POLYNOMIAL:
- {
- const PolynomialCameraIntrinsics *polynomial_intrinsics =
- static_cast<const PolynomialCameraIntrinsics *>(camera_intrinsics);
- camera_intrinsics_options->distortion_model =
- LIBMV_DISTORTION_MODEL_POLYNOMIAL;
- camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1();
- camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2();
- camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3();
- camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1();
- camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p2();
- break;
- }
-
- case libmv::DISTORTION_MODEL_DIVISION:
- {
- const DivisionCameraIntrinsics *division_intrinsics =
- static_cast<const DivisionCameraIntrinsics *>(camera_intrinsics);
- camera_intrinsics_options->distortion_model =
- LIBMV_DISTORTION_MODEL_DIVISION;
- camera_intrinsics_options->division_k1 = division_intrinsics->k1();
- camera_intrinsics_options->division_k2 = division_intrinsics->k2();
- break;
- }
-
- default:
- assert(!"Uknown distortion model");
- }
-}
-
-void libmv_cameraIntrinsicsUndistortByte(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
- int width,
- int height,
- float overscan,
- int channels,
- unsigned char* destination_image) {
- CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- camera_intrinsics->UndistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
-}
-
-void libmv_cameraIntrinsicsUndistortFloat(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- const float* source_image,
- int width,
- int height,
- float overscan,
- int channels,
- float* destination_image) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- intrinsics->UndistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
-}
-
-void libmv_cameraIntrinsicsDistortByte(
- const struct libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
- int width,
- int height,
- float overscan,
- int channels,
- unsigned char *destination_image) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- intrinsics->DistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
-}
-
-void libmv_cameraIntrinsicsDistortFloat(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- float* source_image,
- int width,
- int height,
- float overscan,
- int channels,
- float* destination_image) {
- CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
- intrinsics->DistortBuffer(source_image,
- width, height,
- overscan,
- channels,
- destination_image);
-}
-
-void libmv_cameraIntrinsicsApply(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- double x,
- double y,
- double* x1,
- double* y1) {
- /* Do a lens distortion if focal length is non-zero only. */
- if (libmv_camera_intrinsics_options->focal_length) {
- CameraIntrinsics* camera_intrinsics =
- libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
- camera_intrinsics->ApplyIntrinsics(x, y, x1, y1);
- LIBMV_OBJECT_DELETE(camera_intrinsics, CameraIntrinsics);
- }
-}
-
-void libmv_cameraIntrinsicsInvert(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- double x,
- double y,
- double* x1,
- double* y1) {
- /* Do a lens un-distortion if focal length is non-zero only/ */
- if (libmv_camera_intrinsics_options->focal_length) {
- CameraIntrinsics *camera_intrinsics =
- libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
- camera_intrinsics->InvertIntrinsics(x, y, x1, y1);
- LIBMV_OBJECT_DELETE(camera_intrinsics, CameraIntrinsics);
- }
-}
-
-static void libmv_cameraIntrinsicsFillFromOptions(
- const libmv_CameraIntrinsicsOptions* camera_intrinsics_options,
- CameraIntrinsics* camera_intrinsics) {
- camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length,
- camera_intrinsics_options->focal_length);
-
- camera_intrinsics->SetPrincipalPoint(
- camera_intrinsics_options->principal_point_x,
- camera_intrinsics_options->principal_point_y);
-
- camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width,
- camera_intrinsics_options->image_height);
-
- switch (camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- {
- PolynomialCameraIntrinsics *polynomial_intrinsics =
- static_cast<PolynomialCameraIntrinsics*>(camera_intrinsics);
-
- polynomial_intrinsics->SetRadialDistortion(
- camera_intrinsics_options->polynomial_k1,
- camera_intrinsics_options->polynomial_k2,
- camera_intrinsics_options->polynomial_k3);
-
- break;
- }
-
- case LIBMV_DISTORTION_MODEL_DIVISION:
- {
- DivisionCameraIntrinsics *division_intrinsics =
- static_cast<DivisionCameraIntrinsics*>(camera_intrinsics);
-
- division_intrinsics->SetDistortion(
- camera_intrinsics_options->division_k1,
- camera_intrinsics_options->division_k2);
- break;
- }
-
- default:
- assert(!"Unknown distortion model");
- }
-}
-
-CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
- const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
- CameraIntrinsics *camera_intrinsics = NULL;
- switch (camera_intrinsics_options->distortion_model) {
- case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
- camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics);
- break;
- case LIBMV_DISTORTION_MODEL_DIVISION:
- camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics);
- break;
- default:
- assert(!"Unknown distortion model");
- }
- libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options,
- camera_intrinsics);
- return camera_intrinsics;
-}
diff --git a/extern/libmv/intern/camera_intrinsics.h b/extern/libmv/intern/camera_intrinsics.h
deleted file mode 100644
index 9910d16a108..00000000000
--- a/extern/libmv/intern/camera_intrinsics.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2011 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef LIBMV_C_API_CAMERA_INTRINSICS_H_
-#define LIBMV_C_API_CAMERA_INTRINSICS_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics;
-
-enum {
- LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0,
- LIBMV_DISTORTION_MODEL_DIVISION = 1,
-};
-
-typedef struct libmv_CameraIntrinsicsOptions {
- // Common settings of all distortion models.
- int distortion_model;
- int image_width, image_height;
- double focal_length;
- double principal_point_x, principal_point_y;
-
- // Radial distortion model.
- double polynomial_k1, polynomial_k2, polynomial_k3;
- double polynomial_p1, polynomial_p2;
-
- // Division distortion model.
- double division_k1, division_k2;
-} libmv_CameraIntrinsicsOptions;
-
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options);
-
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
- const libmv_CameraIntrinsics* libmv_intrinsics);
-
-void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics);
-void libmv_cameraIntrinsicsUpdate(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- libmv_CameraIntrinsics* libmv_intrinsics);
-
-void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics,
- int threads);
-
-void libmv_cameraIntrinsicsExtractOptions(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- libmv_CameraIntrinsicsOptions* camera_intrinsics_options);
-
-void libmv_cameraIntrinsicsUndistortByte(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
- int width,
- int height,
- float overscan,
- int channels,
- unsigned char* destination_image);
-
-void libmv_cameraIntrinsicsUndistortFloat(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- const float* source_image,
- int width,
- int height,
- float overscan,
- int channels,
- float* destination_image);
-
-void libmv_cameraIntrinsicsDistortByte(
- const struct libmv_CameraIntrinsics* libmv_intrinsics,
- const unsigned char *source_image,
- int width,
- int height,
- float overscan,
- int channels,
- unsigned char *destination_image);
-
-void libmv_cameraIntrinsicsDistortFloat(
- const libmv_CameraIntrinsics* libmv_intrinsics,
- float* source_image,
- int width,
- int height,
- float overscan,
- int channels,
- float* destination_image);
-
-void libmv_cameraIntrinsicsApply(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- double x,
- double y,
- double* x1,
- double* y1);
-
-void libmv_cameraIntrinsicsInvert(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- double x,
- double y,
- double* x1,
- double* y1);
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-
-namespace libmv {
- class CameraIntrinsics;
-}
-
-libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
- const libmv_CameraIntrinsicsOptions* camera_intrinsics_options);
-#endif
-
-#endif // LIBMV_C_API_CAMERA_INTRINSICS_H_
diff --git a/extern/libmv/intern/frame_accessor.cc b/extern/libmv/intern/frame_accessor.cc
deleted file mode 100644
index 8bf2cab914b..00000000000
--- a/extern/libmv/intern/frame_accessor.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "intern/frame_accessor.h"
-#include "intern/image.h"
-#include "intern/utildefines.h"
-#include "libmv/autotrack/frame_accessor.h"
-#include "libmv/autotrack/region.h"
-#include "libmv/image/image.h"
-
-namespace {
-
-using libmv::FloatImage;
-using mv::FrameAccessor;
-using mv::Region;
-
-struct LibmvFrameAccessor : public FrameAccessor {
- LibmvFrameAccessor(libmv_FrameAccessorUserData* user_data,
- libmv_GetImageCallback get_image_callback,
- libmv_ReleaseImageCallback release_image_callback)
- : user_data_(user_data),
- get_image_callback_(get_image_callback),
- release_image_callback_(release_image_callback) { }
-
- libmv_InputMode get_libmv_input_mode(InputMode input_mode) {
- switch (input_mode) {
-#define CHECK_INPUT_MODE(mode) \
- case mode: \
- return LIBMV_IMAGE_MODE_ ## mode;
- CHECK_INPUT_MODE(MONO)
- CHECK_INPUT_MODE(RGBA)
-#undef CHECK_INPUT_MODE
- }
- assert(!"unknown input mode passed from Libmv.");
- // TODO(sergey): Proper error handling here in the future.
- return LIBMV_IMAGE_MODE_MONO;
- }
-
- void get_libmv_region(const Region& region,
- libmv_Region* libmv_region) {
- libmv_region->min[0] = region.min(0);
- libmv_region->min[1] = region.min(1);
- libmv_region->max[0] = region.max(0);
- libmv_region->max[1] = region.max(1);
- }
-
- Key GetImage(int clip,
- int frame,
- InputMode input_mode,
- int downscale,
- const Region* region,
- const Transform* transform,
- FloatImage* destination) {
- float *float_buffer;
- int width, height, channels;
- libmv_Region libmv_region;
- if (region) {
- get_libmv_region(*region, &libmv_region);
- }
- Key cache_key = get_image_callback_(user_data_,
- clip,
- frame,
- get_libmv_input_mode(input_mode),
- downscale,
- region != NULL ? &libmv_region : NULL,
- (libmv_FrameTransform*) transform,
- &float_buffer,
- &width,
- &height,
- &channels);
-
- // TODO(sergey): Dumb code for until we can set data directly.
- FloatImage temp_image(float_buffer,
- height,
- width,
- channels);
- destination->CopyFrom(temp_image);
-
- return cache_key;
- }
-
- void ReleaseImage(Key cache_key) {
- release_image_callback_(cache_key);
- }
-
- bool GetClipDimensions(int clip, int *width, int *height) {
- return false;
- }
-
- int NumClips() {
- return 1;
- }
-
- int NumFrames(int clip) {
- return 0;
- }
-
- libmv_FrameAccessorUserData* user_data_;
- libmv_GetImageCallback get_image_callback_;
- libmv_ReleaseImageCallback release_image_callback_;
-};
-
-} // namespace
-
-libmv_FrameAccessor* libmv_FrameAccessorNew(
- libmv_FrameAccessorUserData* user_data,
- libmv_GetImageCallback get_image_callback,
- libmv_ReleaseImageCallback release_image_callback) {
- return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor,
- user_data,
- get_image_callback,
- release_image_callback);
-}
-
-void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) {
- LIBMV_OBJECT_DELETE(frame_accessor, LibmvFrameAccessor);
-}
-
-int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform) {
- return ((FrameAccessor::Transform*) transform)->key();
-}
-
-void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform,
- const libmv_FloatImage *input_image,
- libmv_FloatImage *output_image) {
- const FloatImage input(input_image->buffer,
- input_image->height,
- input_image->width,
- input_image->channels);
-
- FloatImage output;
- ((FrameAccessor::Transform*) transform)->run(input,
- &output);
-
- int num_pixels = output.Width() *output.Height() * output.Depth();
- output_image->buffer = new float[num_pixels];
- memcpy(output_image->buffer, output.Data(), num_pixels * sizeof(float));
- output_image->width = output.Width();
- output_image->height = output.Height();
- output_image->channels = output.Depth();
-}
diff --git a/extern/libmv/intern/stub.cc b/extern/libmv/intern/stub.cc
deleted file mode 100644
index 5d667baa880..00000000000
--- a/extern/libmv/intern/stub.cc
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "libmv-capi.h"
-
-#include <cstdlib>
-#include <cstring>
-
-/* ************ Logging ************ */
-
-void libmv_initLogging(const char * /*argv0*/) {
-}
-
-void libmv_startDebugLogging(void) {
-}
-
-void libmv_setLoggingVerbosity(int /*verbosity*/) {
-}
-
-/* ************ Planar tracker ************ */
-
-/* TrackRegion (new planar tracker) */
-int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/,
- const float * /*image1*/,
- int /*image1_width*/,
- int /*image1_height*/,
- const float * /*image2*/,
- int /*image2_width*/,
- int /*image2_height*/,
- const double *x1,
- const double *y1,
- libmv_TrackRegionResult *result,
- double *x2,
- double *y2) {
- /* Convert to doubles for the libmv api. The four corners and the center. */
- for (int i = 0; i < 5; ++i) {
- x2[i] = x1[i];
- y2[i] = y1[i];
- }
-
- result->termination = -1;
- result->termination_reason = "Built without libmv support";
- result->correlation = 0.0;
-
- return false;
-}
-
-void libmv_samplePlanarPatchFloat(const float * /*image*/,
- int /*width*/,
- int /*height*/,
- int /*channels*/,
- const double * /*xs*/,
- const double * /*ys*/,
- int /*num_samples_x*/,
- int /*num_samples_y*/,
- const float * /*mask*/,
- float * /*patch*/,
- double * /*warped_position_x*/,
- double * /*warped_position_y*/) {
- /* TODO(sergey): implement */
-}
-
-void libmv_samplePlanarPatchByte(const unsigned char * /*image*/,
- int /*width*/,
- int /*height*/,
- int /*channels*/,
- const double * /*xs*/,
- const double * /*ys*/,
- int /*num_samples_x*/, int /*num_samples_y*/,
- const float * /*mask*/,
- unsigned char * /*patch*/,
- double * /*warped_position_x*/,
- double * /*warped_position_y*/) {
- /* TODO(sergey): implement */
-}
-
-void libmv_floatImageDestroy(libmv_FloatImage* /*image*/)
-{
-}
-
-/* ************ Tracks ************ */
-
-libmv_Tracks *libmv_tracksNew(void) {
- return NULL;
-}
-
-void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/,
- int /*image*/,
- int /*track*/,
- double /*x*/,
- double /*y*/,
- double /*weight*/) {
-}
-
-void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) {
-}
-
-/* ************ Reconstruction solver ************ */
-
-libmv_Reconstruction *libmv_solveReconstruction(
- const libmv_Tracks * /*libmv_tracks*/,
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
- libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
- reconstruct_progress_update_cb /*progress_update_callback*/,
- void * /*callback_customdata*/) {
- return NULL;
-}
-
-libmv_Reconstruction *libmv_solveModal(
- const libmv_Tracks * /*libmv_tracks*/,
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
- const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
- reconstruct_progress_update_cb /*progress_update_callback*/,
- void * /*callback_customdata*/) {
- return NULL;
-}
-
-int libmv_reconstructionIsValid(libmv_Reconstruction * /*libmv_reconstruction*/) {
- return 0;
-}
-
-int libmv_reprojectionPointForTrack(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
- int /*track*/,
- double /*pos*/[3]) {
- return 0;
-}
-
-double libmv_reprojectionErrorForTrack(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
- int /*track*/) {
- return 0.0;
-}
-
-double libmv_reprojectionErrorForImage(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
- int /*image*/) {
- return 0.0;
-}
-
-int libmv_reprojectionCameraForImage(
- const libmv_Reconstruction * /*libmv_reconstruction*/,
- int /*image*/,
- double /*mat*/[4][4]) {
- return 0;
-}
-
-double libmv_reprojectionError(
- const libmv_Reconstruction * /*libmv_reconstruction*/) {
- return 0.0;
-}
-
-void libmv_reconstructionDestroy(
- struct libmv_Reconstruction * /*libmv_reconstruction*/) {
-}
-
-/* ************ Feature detector ************ */
-
-libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/,
- int /*width*/,
- int /*height*/,
- int /*channels*/,
- libmv_DetectOptions * /*options*/) {
- return NULL;
-}
-
-struct libmv_Features *libmv_detectFeaturesFloat(
- const float * /*image_buffer*/,
- int /*width*/,
- int /*height*/,
- int /*channels*/,
- libmv_DetectOptions * /*options*/) {
- return NULL;
-}
-
-int libmv_countFeatures(const libmv_Features * /*libmv_features*/) {
- return 0;
-}
-
-void libmv_getFeature(const libmv_Features * /*libmv_features*/,
- int /*number*/,
- double *x,
- double *y,
- double *score,
- double *size) {
- *x = 0.0;
- *y = 0.0;
- *score = 0.0;
- *size = 0.0;
-}
-
-void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) {
-}
-
-/* ************ Camera intrinsics ************ */
-
-libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
- libmv_Reconstruction * /*libmv_reconstruction*/) {
- return NULL;
-}
-
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) {
- return NULL;
-}
-
-libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
- const libmv_CameraIntrinsics * /*libmvIntrinsics*/) {
- return NULL;
-}
-
-void libmv_cameraIntrinsicsDestroy(
- libmv_CameraIntrinsics * /*libmvIntrinsics*/) {
-}
-
-void libmv_cameraIntrinsicsUpdate(
- const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
- libmv_CameraIntrinsics * /*libmv_intrinsics*/) {
-}
-
-void libmv_cameraIntrinsicsSetThreads(
- libmv_CameraIntrinsics * /*libmv_intrinsics*/,
- int /*threads*/) {
-}
-
-void libmv_cameraIntrinsicsExtractOptions(
- const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
- libmv_CameraIntrinsicsOptions *camera_intrinsics_options) {
- memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions));
- camera_intrinsics_options->focal_length = 1.0;
-}
-
-void libmv_cameraIntrinsicsUndistortByte(
- const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
- const unsigned char *source_image,
- int width, int height,
- float overscan, int channels,
- unsigned char *destination_image) {
- memcpy(destination_image, source_image,
- channels * width * height * sizeof(unsigned char));
-}
-
-void libmv_cameraIntrinsicsUndistortFloat(
- const libmv_CameraIntrinsics* /*libmv_intrinsics*/,
- const float* source_image,
- int width,
- int height,
- float overscan,
- int channels,
- float* destination_image) {
- memcpy(destination_image, source_image,
- channels * width * height * sizeof(float));
-}
-
-void libmv_cameraIntrinsicsDistortByte(
- const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/,
- const unsigned char *source_image,
- int width,
- int height,
- float overscan,
- int channels,
- unsigned char *destination_image) {
- memcpy(destination_image, source_image,
- channels * width * height * sizeof(unsigned char));
-}
-
-void libmv_cameraIntrinsicsDistortFloat(
- const libmv_CameraIntrinsics* /*libmv_intrinsics*/,
- float* source_image,
- int width,
- int height,
- float overscan,
- int channels,
- float* destination_image) {
- memcpy(destination_image, source_image,
- channels * width * height * sizeof(float));
-}
-
-/* ************ utils ************ */
-
-void libmv_cameraIntrinsicsApply(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- double x,
- double y,
- double* x1,
- double* y1) {
- double focal_length = libmv_camera_intrinsics_options->focal_length;
- double principal_x = libmv_camera_intrinsics_options->principal_point_x;
- double principal_y = libmv_camera_intrinsics_options->principal_point_y;
- *x1 = x * focal_length + principal_x;
- *y1 = y * focal_length + principal_y;
-}
-
-void libmv_cameraIntrinsicsInvert(
- const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
- double x,
- double y,
- double* x1,
- double* y1) {
- double focal_length = libmv_camera_intrinsics_options->focal_length;
- double principal_x = libmv_camera_intrinsics_options->principal_point_x;
- double principal_y = libmv_camera_intrinsics_options->principal_point_y;
- *x1 = (x - principal_x) / focal_length;
- *y1 = (y - principal_y) / focal_length;
-}
-
-void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2],
- /* const */ double (*x2)[2],
- int num_points,
- double H[3][3]) {
- memset(H, 0, sizeof(double[3][3]));
- H[0][0] = 1.0f;
- H[1][1] = 1.0f;
- H[2][2] = 1.0f;
-}
-
-/* ************ autotrack ************ */
-
-libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/)
-{
- return NULL;
-}
-
-void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/)
-{
-}
-
-void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/,
- const libmv_AutoTrackOptions* /*options*/)
-{
-}
-
-int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/,
- const libmv_TrackRegionOptions* /*libmv_options*/,
- libmv_Marker * /*libmv_tracker_marker*/,
- libmv_TrackRegionResult* /*libmv_result*/)
-{
- return 0;
-}
-
-void libmv_autoTrackAddMarker(libmv_AutoTrack* /*libmv_autotrack*/,
- const libmv_Marker* /*libmv_marker*/)
-{
-}
-
-int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/,
- int /*clip*/,
- int /*frame*/,
- int /*track*/,
- libmv_Marker* /*libmv_marker*/)
-{
- return 0;
-}
-
-/* ************ frame accessor ************ */
-
-libmv_FrameAccessor* libmv_FrameAccessorNew(
- libmv_FrameAccessorUserData* /*user_data**/,
- libmv_GetImageCallback /*get_image_callback*/,
- libmv_ReleaseImageCallback /*release_image_callback*/)
-{
- return NULL;
-}
-
-void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/)
-{
-}
-
-int64_t libmv_frameAccessorgetTransformKey(
- const libmv_FrameTransform * /*transform*/)
-{
- return 0;
-}
-
-void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* /*transform*/,
- const libmv_FloatImage* /*input_image*/,
- libmv_FloatImage* /*output_image*/)
-{
-}
-
diff --git a/extern/libmv/intern/track_region.cc b/extern/libmv/intern/track_region.cc
deleted file mode 100644
index 24fbc78c1a1..00000000000
--- a/extern/libmv/intern/track_region.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2011 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation,
- * Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "intern/track_region.h"
-#include "intern/image.h"
-#include "intern/utildefines.h"
-#include "libmv/image/image.h"
-#include "libmv/tracking/track_region.h"
-
-/* define this to generate PNG images with content of search areas
- tracking between which failed */
-#undef DUMP_FAILURE
-
-/* define this to generate PNG images with content of search areas
- on every itteration of tracking */
-#undef DUMP_ALWAYS
-
-using libmv::FloatImage;
-using libmv::TrackRegionOptions;
-using libmv::TrackRegionResult;
-using libmv::TrackRegion;
-
-void libmv_configureTrackRegionOptions(
- const libmv_TrackRegionOptions& options,
- TrackRegionOptions* track_region_options) {
- switch (options.motion_model) {
-#define LIBMV_CONVERT(the_model) \
- case TrackRegionOptions::the_model: \
- track_region_options->mode = TrackRegionOptions::the_model; \
- break;
- LIBMV_CONVERT(TRANSLATION)
- LIBMV_CONVERT(TRANSLATION_ROTATION)
- LIBMV_CONVERT(TRANSLATION_SCALE)
- LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE)
- LIBMV_CONVERT(AFFINE)
- LIBMV_CONVERT(HOMOGRAPHY)
-#undef LIBMV_CONVERT
- }
-
- track_region_options->minimum_correlation = options.minimum_correlation;
- track_region_options->max_iterations = options.num_iterations;
- track_region_options->sigma = options.sigma;
- track_region_options->num_extra_points = 1;
- track_region_options->image1_mask = NULL;
- track_region_options->use_brute_initialization = options.use_brute;
- /* TODO(keir): This will make some cases better, but may be a regression until
- * the motion model is in. Since this is on trunk, enable it for now.
- *
- * TODO(sergey): This gives much worse results on mango footage (see 04_2e)
- * so disabling for now for until proper prediction model is landed.
- *
- * The thing is, currently blender sends input coordinates as the guess to
- * region tracker and in case of fast motion such an early out ruins the track.
- */
- track_region_options->attempt_refine_before_brute = false;
- track_region_options->use_normalized_intensities = options.use_normalization;
-}
-
-void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result,
- libmv_TrackRegionResult* result) {
- result->termination = (int) track_region_result.termination;
- result->termination_reason = "";
- result->correlation = track_region_result.correlation;
-}
-
-int libmv_trackRegion(const libmv_TrackRegionOptions* options,
- const float* image1,
- int image1_width,
- int image1_height,
- const float* image2,
- int image2_width,
- int image2_height,
- const double* x1,
- const double* y1,
- libmv_TrackRegionResult* result,
- double* x2,
- double* y2) {
- double xx1[5], yy1[5];
- double xx2[5], yy2[5];
- bool tracking_result = false;
-
- // Convert to doubles for the libmv api. The four corners and the center.
- for (int i = 0; i < 5; ++i) {
- xx1[i] = x1[i];
- yy1[i] = y1[i];
- xx2[i] = x2[i];
- yy2[i] = y2[i];
- }
-
- TrackRegionOptions track_region_options;
- FloatImage image1_mask;
-
- libmv_configureTrackRegionOptions(*options, &track_region_options);
- if (options->image1_mask) {
- libmv_floatBufferToFloatImage(options->image1_mask,
- image1_width,
- image1_height,
- 1,
- &image1_mask);
-
- track_region_options.image1_mask = &image1_mask;
- }
-
- // Convert from raw float buffers to libmv's FloatImage.
- FloatImage old_patch, new_patch;
- libmv_floatBufferToFloatImage(image1,
- image1_width,
- image1_height,
- 1,
- &old_patch);
- libmv_floatBufferToFloatImage(image2,
- image2_width,
- image2_height,
- 1,
- &new_patch);
-
- TrackRegionResult track_region_result;
- TrackRegion(old_patch, new_patch,
- xx1, yy1,
- track_region_options,
- xx2, yy2,
- &track_region_result);
-
- // Convert to floats for the blender api.
- for (int i = 0; i < 5; ++i) {
- x2[i] = xx2[i];
- y2[i] = yy2[i];
- }
-
- // TODO(keir): Update the termination string with failure details.
- if (track_region_result.termination == TrackRegionResult::CONVERGENCE ||
- track_region_result.termination == TrackRegionResult::NO_CONVERGENCE) {
- tracking_result = true;
- }
-
- // Debug dump of patches.
-#if defined(DUMP_FAILURE) || defined(DUMP_ALWAYS)
- bool need_dump = !tracking_result;
-
-# ifdef DUMP_ALWAYS
- need_dump = true;
-# endif
-
- if (need_dump) {
- libmv_saveImage(old_patch, "old_patch", x1[4], y1[4]);
- libmv_saveImage(new_patch, "new_patch", x2[4], y2[4]);
- if (options->image1_mask) {
- libmv_saveImage(image1_mask, "mask", x2[4], y2[4]);
- }
- }
-#endif
-
- return tracking_result;
-}
diff --git a/extern/libmv/intern/utildefines.h b/extern/libmv/intern/utildefines.h
deleted file mode 100644
index 7366b242cf7..00000000000
--- a/extern/libmv/intern/utildefines.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef LIBMV_C_API_UTILDEFINES_H_
-#define LIBMV_C_API_UTILDEFINES_H_
-
-#if defined(_MSC_VER)
-# define __func__ __FUNCTION__
-# define snprintf _snprintf
-#endif
-
-#ifdef WITH_LIBMV_GUARDED_ALLOC
-# include "MEM_guardedalloc.h"
-# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW
-# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
-# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
-# define LIBMV_STRUCT_NEW(type, count) \
- (type*)MEM_mallocN(sizeof(type) * count, __func__)
-# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what)
-#else
-// Need this to keep libmv-capi potentially standalone.
-# if defined __GNUC__ || defined __sun
-# define LIBMV_OBJECT_NEW(type, args ...) \
- new(malloc(sizeof(type))) type(args)
-# else
-# define LIBMV_OBJECT_NEW(type, ...) \
- new(malloc(sizeof(type))) type(__VA_ARGS__)
-#endif
-# define LIBMV_OBJECT_DELETE(what, type) \
- { \
- if (what) { \
- ((type*)(what))->~type(); \
- free(what); \
- } \
- } (void)0
-# define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count)
-# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0
-#endif
-
-#endif // LIBMV_C_API_UTILDEFINES_H_
diff --git a/extern/libmv/libmv/autotrack/predict_tracks_test.cc b/extern/libmv/libmv/autotrack/predict_tracks_test.cc
deleted file mode 100644
index fc90e260d94..00000000000
--- a/extern/libmv/libmv/autotrack/predict_tracks_test.cc
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2014 libmv authors.
-//
-// 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.
-//
-// Author: mierle@gmail.com (Keir Mierle)
-
-#include "libmv/autotrack/predict_tracks.h"
-
-#include "libmv/autotrack/marker.h"
-#include "libmv/autotrack/tracks.h"
-#include "libmv/logging/logging.h"
-#include "testing/testing.h"
-
-namespace mv {
-
-void AddMarker(int frame, float x, float y, Tracks* tracks) {
- Marker marker;
- marker.clip = marker.track = 0;
- marker.frame = frame;
- marker.center.x() = x;
- marker.center.y() = y;
- marker.patch.coordinates << x - 1, y - 1,
- x + 1, y - 1,
- x + 1, y + 1,
- x - 1, y + 1;
- tracks->AddMarker(marker);
-}
-
-TEST(PredictMarkerPosition, EasyLinearMotion) {
- Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
- AddMarker(2, 3.0, 10.0, &tracks);
- AddMarker(3, 4.0, 15.0, &tracks);
- AddMarker(4, 5.0, 20.0, &tracks);
- AddMarker(5, 6.0, 25.0, &tracks);
- AddMarker(6, 7.0, 30.0, &tracks);
- AddMarker(7, 8.0, 35.0, &tracks);
-
- Marker predicted;
- predicted.clip = 0;
- predicted.track = 0;
- predicted.frame = 8;
-
- PredictMarkerPosition(tracks, &predicted);
- double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
- LG << "Got error: " << error;
- EXPECT_LT(error, 0.1);
-
- // Check the patch coordinates as well.
- double x = 9, y = 40.0;
- Quad2Df expected_patch;
- expected_patch.coordinates << x - 1, y - 1,
- x + 1, y - 1,
- x + 1, y + 1,
- x - 1, y + 1;
-
- error = (expected_patch.coordinates - predicted.patch.coordinates).norm();
- LG << "Patch error: " << error;
- EXPECT_LT(error, 0.1);
-}
-
-TEST(PredictMarkerPosition, EasyBackwardLinearMotion) {
- Tracks tracks;
- AddMarker(8, 1.0, 0.0, &tracks);
- AddMarker(7, 2.0, 5.0, &tracks);
- AddMarker(6, 3.0, 10.0, &tracks);
- AddMarker(5, 4.0, 15.0, &tracks);
- AddMarker(4, 5.0, 20.0, &tracks);
- AddMarker(3, 6.0, 25.0, &tracks);
- AddMarker(2, 7.0, 30.0, &tracks);
- AddMarker(1, 8.0, 35.0, &tracks);
-
- Marker predicted;
- predicted.clip = 0;
- predicted.track = 0;
- predicted.frame = 0;
-
- PredictMarkerPosition(tracks, &predicted);
- LG << predicted;
- double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
- LG << "Got error: " << error;
- EXPECT_LT(error, 0.1);
-
- // Check the patch coordinates as well.
- double x = 9.0, y = 40.0;
- Quad2Df expected_patch;
- expected_patch.coordinates << x - 1, y - 1,
- x + 1, y - 1,
- x + 1, y + 1,
- x - 1, y + 1;
-
- error = (expected_patch.coordinates - predicted.patch.coordinates).norm();
- LG << "Patch error: " << error;
- EXPECT_LT(error, 0.1);
-}
-
-TEST(PredictMarkerPosition, TwoFrameGap) {
- Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
- AddMarker(2, 3.0, 10.0, &tracks);
- AddMarker(3, 4.0, 15.0, &tracks);
- AddMarker(4, 5.0, 20.0, &tracks);
- AddMarker(5, 6.0, 25.0, &tracks);
- AddMarker(6, 7.0, 30.0, &tracks);
- // Missing frame 7!
-
- Marker predicted;
- predicted.clip = 0;
- predicted.track = 0;
- predicted.frame = 8;
-
- PredictMarkerPosition(tracks, &predicted);
- double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
- LG << "Got error: " << error;
- EXPECT_LT(error, 0.1);
-}
-
-TEST(PredictMarkerPosition, FourFrameGap) {
- Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
- AddMarker(2, 3.0, 10.0, &tracks);
- AddMarker(3, 4.0, 15.0, &tracks);
- // Missing frames 4, 5, 6, 7.
-
- Marker predicted;
- predicted.clip = 0;
- predicted.track = 0;
- predicted.frame = 8;
-
- PredictMarkerPosition(tracks, &predicted);
- double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
- LG << "Got error: " << error;
- EXPECT_LT(error, 2.0); // Generous error due to larger prediction window.
-}
-
-TEST(PredictMarkerPosition, MultipleGaps) {
- Tracks tracks;
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
- AddMarker(2, 3.0, 10.0, &tracks);
- // AddMarker(3, 4.0, 15.0, &tracks); // Note the 3-frame gap.
- // AddMarker(4, 5.0, 20.0, &tracks);
- // AddMarker(5, 6.0, 25.0, &tracks);
- AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement.
- // AddMarker(7, 8.0, 35.0, &tracks);
-
- Marker predicted;
- predicted.clip = 0;
- predicted.track = 0;
- predicted.frame = 8;
-
- PredictMarkerPosition(tracks, &predicted);
- double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
- LG << "Got error: " << error;
- EXPECT_LT(error, 1.0); // Generous error due to larger prediction window.
-}
-
-TEST(PredictMarkerPosition, MarkersInRandomOrder) {
- Tracks tracks;
-
- // This is the same as the easy, except that the tracks are randomly ordered.
- AddMarker(0, 1.0, 0.0, &tracks);
- AddMarker(2, 3.0, 10.0, &tracks);
- AddMarker(7, 8.0, 35.0, &tracks);
- AddMarker(5, 6.0, 25.0, &tracks);
- AddMarker(4, 5.0, 20.0, &tracks);
- AddMarker(3, 4.0, 15.0, &tracks);
- AddMarker(6, 7.0, 30.0, &tracks);
- AddMarker(1, 2.0, 5.0, &tracks);
-
- Marker predicted;
- predicted.clip = 0;
- predicted.track = 0;
- predicted.frame = 8;
-
- PredictMarkerPosition(tracks, &predicted);
- double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
- LG << "Got error: " << error;
- EXPECT_LT(error, 0.1);
-}
-
-} // namespace mv
diff --git a/extern/libmv/libmv/base/aligned_malloc.cc b/extern/libmv/libmv/base/aligned_malloc.cc
deleted file mode 100644
index 9141186f196..00000000000
--- a/extern/libmv/libmv/base/aligned_malloc.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2014 libmv authors.
-//
-// 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.
-
-#include "libmv/base/aligned_malloc.h"
-#include "libmv/logging/logging.h"
-
-#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
-// Needed for memalign on Linux and _aligned_alloc on Windows.
-# ifdef FREE_WINDOWS
-/* make sure _aligned_malloc is included */
-# ifdef __MSVCRT_VERSION__
-# undef __MSVCRT_VERSION__
-# endif
-
-# define __MSVCRT_VERSION__ 0x0700
-# endif // FREE_WINDOWS
-
-# include <malloc.h>
-#else
-// Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
-// stdilb instead.
-# include <cstdlib>
-#endif
-
-namespace libmv {
-
-void *aligned_malloc(int size, int alignment) {
-#ifdef _WIN32
- return _aligned_malloc(size, alignment);
-#elif __APPLE__
- // On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
- // they work natively with SSE types with no further work.
- CHECK_EQ(alignment, 16);
- return malloc(size);
-#elif defined(__FreeBSD__) || defined(__NetBSD__)
- void *result;
-
- if (posix_memalign(&result, alignment, size)) {
- // non-zero means allocation error
- // either no allocation or bad alignment value
- return NULL;
- }
- return result;
-#else // This is for Linux.
- return memalign(alignment, size);
-#endif
-}
-
-void aligned_free(void *ptr) {
-#ifdef _WIN32
- _aligned_free(ptr);
-#else
- free(ptr);
-#endif
-}
-
-} // namespace libmv
diff --git a/extern/libmv/libmv/image/array_nd.h b/extern/libmv/libmv/image/array_nd.h
deleted file mode 100644
index b56a765223b..00000000000
--- a/extern/libmv/libmv/image/array_nd.h
+++ /dev/null
@@ -1,496 +0,0 @@
-// Copyright (c) 2007, 2008 libmv authors.
-//
-// 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.
-
-#ifndef LIBMV_IMAGE_ARRAY_ND_H
-#define LIBMV_IMAGE_ARRAY_ND_H
-
-#include <cassert>
-#include <cstdio>
-#include <cstring>
-
-#include "libmv/image/tuple.h"
-
-namespace libmv {
-
-class BaseArray {};
-
-/// A multidimensional array class.
-template <typename T, int N>
-class ArrayND : public BaseArray {
- public:
- typedef T Scalar;
-
- /// Type for the multidimensional indices.
- typedef Tuple<int, N> Index;
-
- /// Create an empty array.
- ArrayND() : data_(NULL), own_data_(true) { Resize(Index(0)); }
-
- /// Create an array with the specified shape.
- ArrayND(const Index &shape) : data_(NULL), own_data_(true) { Resize(shape); }
-
- /// Create an array with the specified shape.
- ArrayND(int *shape) : data_(NULL), own_data_(true) { Resize(shape); }
-
- /// Copy constructor.
- ArrayND(const ArrayND<T, N> &b) : data_(NULL), own_data_(true) {
- ResizeLike(b);
- std::memcpy(Data(), b.Data(), sizeof(T) * Size());
- }
-
- ArrayND(int s0) : data_(NULL), own_data_(true) { Resize(s0); }
- ArrayND(int s0, int s1) : data_(NULL), own_data_(true) { Resize(s0, s1); }
- ArrayND(int s0, int s1, int s2) : data_(NULL), own_data_(true) {
- Resize(s0, s1, s2);
- }
-
- ArrayND(T* data, int s0, int s1, int s2) : data_(data), own_data_(false) {
- Resize(s0, s1, s2);
- }
-
- /// Destructor deletes pixel data.
- ~ArrayND() {
- if (own_data_) {
- delete [] data_;
- }
- }
-
- /// Assignation copies pixel data.
- ArrayND &operator=(const ArrayND<T, N> &b) {
- assert(this != &b);
- ResizeLike(b);
- std::memcpy(Data(), b.Data(), sizeof(T) * Size());
- return *this;
- }
-
- const Index &Shapes() const {
- return shape_;
- }
-
- const Index &Strides() const {
- return strides_;
- }
-
- /// Create an array of shape s.
- void Resize(const Index &new_shape) {
- if (data_ != NULL && shape_ == new_shape) {
- // Don't bother realloacting if the shapes match.
- return;
- }
- shape_.Reset(new_shape);
- strides_(N - 1) = 1;
- for (int i = N - 1; i > 0; --i) {
- strides_(i - 1) = strides_(i) * shape_(i);
- }
- if (own_data_) {
- delete [] data_;
- data_ = NULL;
- if (Size() > 0) {
- data_ = new T[Size()];
- }
- }
- }
-
- template<typename D>
- void ResizeLike(const ArrayND<D, N> &other) {
- Resize(other.Shape());
- }
-
- /// Resizes the array to shape s. All data is lost.
- void Resize(const int *new_shape_array) {
- Resize(Index(new_shape_array));
- }
-
- /// Resize a 1D array to length s0.
- void Resize(int s0) {
- assert(N == 1);
- int shape[] = {s0};
- Resize(shape);
- }
-
- /// Resize a 2D array to shape (s0,s1).
- void Resize(int s0, int s1) {
- int shape[N] = {s0, s1};
- for (int i = 2; i < N; ++i) {
- shape[i] = 1;
- }
- Resize(shape);
- }
-
- // Match Eigen2's API.
- void resize(int rows, int cols) {
- Resize(rows, cols);
- }
-
- /// Resize a 3D array to shape (s0,s1,s2).
- void Resize(int s0, int s1, int s2) {
- assert(N == 3);
- int shape[] = {s0, s1, s2};
- Resize(shape);
- }
-
- template<typename D>
- void CopyFrom(const ArrayND<D, N> &other) {
- ResizeLike(other);
- T *data = Data();
- const D *other_data = other.Data();
- for (int i = 0; i < Size(); ++i) {
- data[i] = T(other_data[i]);
- }
- }
-
- void Fill(T value) {
- for (int i = 0; i < Size(); ++i) {
- Data()[i] = value;
- }
- }
-
- // Match Eigen's API.
- void fill(T value) {
- for (int i = 0; i < Size(); ++i) {
- Data()[i] = value;
- }
- }
-
- /// Return a tuple containing the length of each axis.
- const Index &Shape() const {
- return shape_;
- }
-
- /// Return the length of an axis.
- int Shape(int axis) const {
- return shape_(axis);
- }
-
- /// Return the distance between neighboring elements along axis.
- int Stride(int axis) const {
- return strides_(axis);
- }
-
- /// Return the number of elements of the array.
- int Size() const {
- int size = 1;
- for (int i = 0; i < N; ++i)
- size *= Shape(i);
- return size;
- }
-
- /// Return the total amount of memory used by the array.
- int MemorySizeInBytes() const {
- return sizeof(*this) + Size() * sizeof(T);
- }
-
- /// Pointer to the first element of the array.
- T *Data() { return data_; }
-
- /// Constant pointer to the first element of the array.
- const T *Data() const { return data_; }
-
- /// Distance between the first element and the element at position index.
- int Offset(const Index &index) const {
- int offset = 0;
- for (int i = 0; i < N; ++i)
- offset += index(i) * Stride(i);
- return offset;
- }
-
- /// 1D specialization.
- int Offset(int i0) const {
- assert(N == 1);
- return i0 * Stride(0);
- }
-
- /// 2D specialization.
- int Offset(int i0, int i1) const {
- assert(N == 2);
- return i0 * Stride(0) + i1 * Stride(1);
- }
-
- /// 3D specialization.
- int Offset(int i0, int i1, int i2) const {
- assert(N == 3);
- return i0 * Stride(0) + i1 * Stride(1) + i2 * Stride(2);
- }
-
- /// Return a reference to the element at position index.
- T &operator()(const Index &index) {
- // TODO(pau) Boundary checking in debug mode.
- return *( Data() + Offset(index) );
- }
-
- /// 1D specialization.
- T &operator()(int i0) {
- return *( Data() + Offset(i0) );
- }
-
- /// 2D specialization.
- T &operator()(int i0, int i1) {
- assert(0 <= i0 && i0 < Shape(0));
- assert(0 <= i1 && i1 < Shape(1));
- return *(Data() + Offset(i0, i1));
- }
-
- /// 3D specialization.
- T &operator()(int i0, int i1, int i2) {
- assert(0 <= i0 && i0 < Shape(0));
- assert(0 <= i1 && i1 < Shape(1));
- assert(0 <= i2 && i2 < Shape(2));
- return *(Data() + Offset(i0, i1, i2));
- }
-
- /// Return a constant reference to the element at position index.
- const T &operator()(const Index &index) const {
- return *(Data() + Offset(index));
- }
-
- /// 1D specialization.
- const T &operator()(int i0) const {
- return *(Data() + Offset(i0));
- }
-
- /// 2D specialization.
- const T &operator()(int i0, int i1) const {
- assert(0 <= i0 && i0 < Shape(0));
- assert(0 <= i1 && i1 < Shape(1));
- return *(Data() + Offset(i0, i1));
- }
-
- /// 3D specialization.
- const T &operator()(int i0, int i1, int i2) const {
- return *(Data() + Offset(i0, i1, i2));
- }
-
- /// True if index is inside array.
- bool Contains(const Index &index) const {
- for (int i = 0; i < N; ++i)
- if (index(i) < 0 || index(i) >= Shape(i))
- return false;
- return true;
- }
-
- /// 1D specialization.
- bool Contains(int i0) const {
- return 0 <= i0 && i0 < Shape(0);
- }
-
- /// 2D specialization.
- bool Contains(int i0, int i1) const {
- return 0 <= i0 && i0 < Shape(0)
- && 0 <= i1 && i1 < Shape(1);
- }
-
- /// 3D specialization.
- bool Contains(int i0, int i1, int i2) const {
- return 0 <= i0 && i0 < Shape(0)
- && 0 <= i1 && i1 < Shape(1)
- && 0 <= i2 && i2 < Shape(2);
- }
-
- bool operator==(const ArrayND<T, N> &other) const {
- if (shape_ != other.shape_) return false;
- if (strides_ != other.strides_) return false;
- for (int i = 0; i < Size(); ++i) {
- if (this->Data()[i] != other.Data()[i])
- return false;
- }
- return true;
- }
-
- bool operator!=(const ArrayND<T, N> &other) const {
- return !(*this == other);
- }
-
- ArrayND<T, N> operator*(const ArrayND<T, N> &other) const {
- assert(Shape() = other.Shape());
- ArrayND<T, N> res;
- res.ResizeLike(*this);
- for (int i = 0; i < res.Size(); ++i) {
- res.Data()[i] = Data()[i] * other.Data()[i];
- }
- return res;
- }
-
- protected:
- /// The number of element in each dimension.
- Index shape_;
-
- /// How to jump to neighbors in each dimension.
- Index strides_;
-
- /// Pointer to the first element of the array.
- T *data_;
-
- /// Flag if this Array either own or reference the data
- bool own_data_;
-};
-
-/// 3D array (row, column, channel).
-template <typename T>
-class Array3D : public ArrayND<T, 3> {
- typedef ArrayND<T, 3> Base;
- public:
- Array3D()
- : Base() {
- }
- Array3D(int height, int width, int depth = 1)
- : Base(height, width, depth) {
- }
- Array3D(T* data, int height, int width, int depth = 1)
- : Base(data, height, width, depth) {
- }
-
- void Resize(int height, int width, int depth = 1) {
- Base::Resize(height, width, depth);
- }
-
- int Height() const {
- return Base::Shape(0);
- }
- int Width() const {
- return Base::Shape(1);
- }
- int Depth() const {
- return Base::Shape(2);
- }
-
- // Match Eigen2's API so that Array3D's and Mat*'s can work together via
- // template magic.
- int rows() const { return Height(); }
- int cols() const { return Width(); }
- int depth() const { return Depth(); }
-
- int Get_Step() const { return Width()*Depth(); }
-
- /// Enable accessing with 2 indices for grayscale images.
- T &operator()(int i0, int i1, int i2 = 0) {
- assert(0 <= i0 && i0 < Height());
- assert(0 <= i1 && i1 < Width());
- return Base::operator()(i0, i1, i2);
- }
- const T &operator()(int i0, int i1, int i2 = 0) const {
- assert(0 <= i0 && i0 < Height());
- assert(0 <= i1 && i1 < Width());
- return Base::operator()(i0, i1, i2);
- }
-};
-
-typedef Array3D<unsigned char> Array3Du;
-typedef Array3D<unsigned int> Array3Dui;
-typedef Array3D<int> Array3Di;
-typedef Array3D<float> Array3Df;
-typedef Array3D<short> Array3Ds;
-
-void SplitChannels(const Array3Df &input,
- Array3Df *channel0,
- Array3Df *channel1,
- Array3Df *channel2);
-
-void PrintArray(const Array3Df &array);
-
-/** Convert a float array into a byte array by scaling values by 255* (max-min).
- * where max and min are automatically detected
- * (if automatic_range_detection = true)
- * \note and TODO this automatic detection only works when the image contains
- * at least one pixel of both bounds.
- **/
-void FloatArrayToScaledByteArray(const Array3Df &float_array,
- Array3Du *byte_array,
- bool automatic_range_detection = false);
-
-//! Convert a byte array into a float array by dividing values by 255.
-void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
- Array3Df *float_array);
-
-template <typename AArrayType, typename BArrayType, typename CArrayType>
-void MultiplyElements(const AArrayType &a,
- const BArrayType &b,
- CArrayType *c) {
- // This function does an element-wise multiply between
- // the two Arrays A and B, and stores the result in C.
- // A and B must have the same dimensions.
- assert(a.Shape() == b.Shape());
- c->ResizeLike(a);
-
- // To perform the multiplcation, a "current" index into the N-dimensions of
- // the A and B matrix specifies which elements are being multiplied.
- typename CArrayType::Index index;
-
- // The index starts at the maximum value for each dimension
- const typename CArrayType::Index& cShape = c->Shape();
- for ( int i = 0; i < CArrayType::Index::SIZE; ++i )
- index(i) = cShape(i) - 1;
-
- // After each multiplication, the highest-dimensional index is reduced.
- // if this reduces it less than zero, it resets to its maximum value
- // and decrements the index of the next lower dimension.
- // This ripple-action continues until the entire new array has been
- // calculated, indicated by dimension zero having a negative index.
- while ( index(0) >= 0 ) {
- (*c)(index) = a(index) * b(index);
-
- int dimension = CArrayType::Index::SIZE - 1;
- index(dimension) = index(dimension) - 1;
- while ( dimension > 0 && index(dimension) < 0 ) {
- index(dimension) = cShape(dimension) - 1;
- index(dimension - 1) = index(dimension - 1) - 1;
- --dimension;
- }
- }
-}
-
-template <typename TA, typename TB, typename TC>
-void MultiplyElements(const ArrayND<TA, 3> &a,
- const ArrayND<TB, 3> &b,
- ArrayND<TC, 3> *c) {
- // Specialization for N==3
- c->ResizeLike(a);
- assert(a.Shape(0) == b.Shape(0));
- assert(a.Shape(1) == b.Shape(1));
- assert(a.Shape(2) == b.Shape(2));
- for (int i = 0; i < a.Shape(0); ++i) {
- for (int j = 0; j < a.Shape(1); ++j) {
- for (int k = 0; k < a.Shape(2); ++k) {
- (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k));
- }
- }
- }
-}
-
-template <typename TA, typename TB, typename TC>
-void MultiplyElements(const Array3D<TA> &a,
- const Array3D<TB> &b,
- Array3D<TC> *c) {
- // Specialization for N==3
- c->ResizeLike(a);
- assert(a.Shape(0) == b.Shape(0));
- assert(a.Shape(1) == b.Shape(1));
- assert(a.Shape(2) == b.Shape(2));
- for (int i = 0; i < a.Shape(0); ++i) {
- for (int j = 0; j < a.Shape(1); ++j) {
- for (int k = 0; k < a.Shape(2); ++k) {
- (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k));
- }
- }
- }
-}
-
-} // namespace libmv
-
-#endif // LIBMV_IMAGE_ARRAY_ND_H
diff --git a/extern/libmv/libmv/multiview/euclidean_resection_test.cc b/extern/libmv/libmv/multiview/euclidean_resection_test.cc
deleted file mode 100644
index 5ec9dbda3cf..00000000000
--- a/extern/libmv/libmv/multiview/euclidean_resection_test.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (c) 2009 libmv authors.
-//
-// 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.
-
-#include "libmv/multiview/euclidean_resection.h"
-#include "libmv/numeric/numeric.h"
-#include "libmv/logging/logging.h"
-#include "libmv/multiview/projection.h"
-#include "testing/testing.h"
-
-using namespace libmv::euclidean_resection;
-using namespace libmv;
-
-// Generates all necessary inputs and expected outputs for EuclideanResection.
-void CreateCameraSystem(const Mat3& KK,
- const Mat3X& x_image,
- const Vec& X_distances,
- const Mat3& R_input,
- const Vec3& T_input,
- Mat2X *x_camera,
- Mat3X *X_world,
- Mat3 *R_expected,
- Vec3 *T_expected) {
- int num_points = x_image.cols();
-
- Mat3X x_unit_cam(3, num_points);
- x_unit_cam = KK.inverse() * x_image;
-
- // Create normalized camera coordinates to be used as an input to the PnP
- // function, instead of using NormalizeColumnVectors(&x_unit_cam).
- *x_camera = x_unit_cam.block(0, 0, 2, num_points);
- for (int i = 0; i < num_points; ++i) {
- x_unit_cam.col(i).normalize();
- }
-
- // Create the 3D points in the camera system.
- Mat X_camera(3, num_points);
- for (int i = 0; i < num_points; ++i) {
- X_camera.col(i) = X_distances(i) * x_unit_cam.col(i);
- }
-
- // Apply the transformation to the camera 3D points
- Mat translation_matrix(3, num_points);
- translation_matrix.row(0).setConstant(T_input(0));
- translation_matrix.row(1).setConstant(T_input(1));
- translation_matrix.row(2).setConstant(T_input(2));
-
- *X_world = R_input * X_camera + translation_matrix;
-
- // Create the expected result for comparison.
- *R_expected = R_input.transpose();
- *T_expected = *R_expected * (-T_input);
-};
-
-TEST(AbsoluteOrientation, QuaternionSolution) {
- int num_points = 4;
- Mat X;
- Mat Xp;
- X = 100 * Mat::Random(3, num_points);
-
- // Create a random translation and rotation.
- Mat3 R_input;
- R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
-
- Vec3 t_input;
- t_input.setRandom();
- t_input = 100 * t_input;
-
- Mat translation_matrix(3, num_points);
- translation_matrix.row(0).setConstant(t_input(0));
- translation_matrix.row(1).setConstant(t_input(1));
- translation_matrix.row(2).setConstant(t_input(2));
-
- // Create the transformed 3D points Xp as Xp = R * X + t.
- Xp = R_input * X + translation_matrix;
-
- // Output variables.
- Mat3 R;
- Vec3 t;
-
- AbsoluteOrientation(X, Xp, &R, &t);
-
- EXPECT_MATRIX_NEAR(t, t_input, 1e-6);
- EXPECT_MATRIX_NEAR(R, R_input, 1e-8);
-}
-
-TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
- // In this test only the translation and rotation are random. The image
- // points are selected from a real case and are well conditioned.
- Vec2i image_dimensions;
- image_dimensions << 1600, 1200;
-
- Mat3 KK;
- KK << 2796, 0, 804,
- 0 , 2796, 641,
- 0, 0, 1;
-
- // The real image points.
- int num_points = 4;
- Mat3X x_image(3, num_points);
- x_image << 1164.06, 734.948, 749.599, 430.727,
- 681.386, 844.59, 496.315, 580.775,
- 1, 1, 1, 1;
-
-
- // A vector of the 4 distances to the 3D points.
- Vec X_distances = 100 * Vec::Random(num_points).array().abs();
-
- // Create the random camera motion R and t that resection should recover.
- Mat3 R_input;
- R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
-
- Vec3 T_input;
- T_input.setRandom();
- T_input = 100 * T_input;
-
- // Create the camera system, also getting the expected result of the
- // transformation.
- Mat3 R_expected;
- Vec3 T_expected;
- Mat3X X_world;
- Mat2X x_camera;
- CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
- &x_camera, &X_world, &R_expected, &T_expected);
-
- // Finally, run the code under test.
- Mat3 R_output;
- Vec3 T_output;
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_ANSAR_DANIILIDIS);
-
- EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
- EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
-
- // For now, the EPnP doesn't have a non-linear optimization step and so is
- // not precise enough with only 4 points.
- //
- // TODO(jmichot): Reenable this test when there is nonlinear refinement.
-#if 0
- R_output.setIdentity();
- T_output.setZero();
-
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_EPNP);
-
- EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
- EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/
-#endif
-}
-
-// TODO(jmichot): Reduce the code duplication here with the code above.
-TEST(EuclideanResection, Points6AllRandomInput) {
- Mat3 KK;
- KK << 2796, 0, 804,
- 0 , 2796, 641,
- 0, 0, 1;
-
- // Create random image points for a 1600x1200 image.
- int w = 1600;
- int h = 1200;
- int num_points = 6;
- Mat3X x_image(3, num_points);
- x_image.row(0) = w * Vec::Random(num_points).array().abs();
- x_image.row(1) = h * Vec::Random(num_points).array().abs();
- x_image.row(2).setOnes();
-
- // Normalized camera coordinates to be used as an input to the PnP function.
- Mat2X x_camera;
- Vec X_distances = 100 * Vec::Random(num_points).array().abs();
-
- // Create the random camera motion R and t that resection should recover.
- Mat3 R_input;
- R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
- * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
-
- Vec3 T_input;
- T_input.setRandom();
- T_input = 100 * T_input;
-
- // Create the camera system.
- Mat3 R_expected;
- Vec3 T_expected;
- Mat3X X_world;
- CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
- &x_camera, &X_world, &R_expected, &T_expected);
-
- // Test each of the resection methods.
- {
- Mat3 R_output;
- Vec3 T_output;
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_ANSAR_DANIILIDIS);
- EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
- EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
- }
- {
- Mat3 R_output;
- Vec3 T_output;
- EuclideanResection(x_camera, X_world,
- &R_output, &T_output,
- RESECTION_EPNP);
- EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
- EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
- }
- {
- Mat3 R_output;
- Vec3 T_output;
- EuclideanResection(x_image, X_world, KK,
- &R_output, &T_output);
- EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
- EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
- }
-}
diff --git a/extern/libmv/libmv/multiview/fundamental.h b/extern/libmv/libmv/multiview/fundamental.h
deleted file mode 100644
index 51067aefc2b..00000000000
--- a/extern/libmv/libmv/multiview/fundamental.h
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright (c) 2007, 2008, 2011 libmv authors.
-//
-// 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.
-
-#ifndef LIBMV_MULTIVIEW_FUNDAMENTAL_H_
-#define LIBMV_MULTIVIEW_FUNDAMENTAL_H_
-
-#include <vector>
-
-#include "libmv/numeric/numeric.h"
-
-namespace libmv {
-
-void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2);
-void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F);
-
-/**
- * The normalized 8-point fundamental matrix solver.
- */
-double NormalizedEightPointSolver(const Mat &x1,
- const Mat &x2,
- Mat3 *F);
-
-/**
- * 7 points (minimal case, points coordinates must be normalized before):
- */
-double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- std::vector<Mat3> *F);
-
-/**
- * 7 points (points coordinates must be in image space):
- */
-double FundamentalFromCorrespondences7Point(const Mat &x1,
- const Mat &x2,
- std::vector<Mat3> *F);
-
-/**
- * 8 points (points coordinates must be in image space):
- */
-double NormalizedEightPointSolver(const Mat &x1,
- const Mat &x2,
- Mat3 *F);
-
-/**
- * Fundamental matrix utility function:
- */
-void EnforceFundamentalRank2Constraint(Mat3 *F);
-
-void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized);
-
-/**
- * Approximate squared reprojection errror.
- *
- * See page 287 of HZ equation 11.9. This avoids triangulating the point,
- * relying only on the entries in F.
- */
-double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
-
-/**
- * Calculates the sum of the distances from the points to the epipolar lines.
- *
- * See page 288 of HZ equation 11.10.
- */
-double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
-
-/**
- * Compute the relative camera motion between two cameras.
- *
- * Given the motion parameters of two cameras, computes the motion parameters
- * of the second one assuming the first one to be at the origin.
- * If T1 and T2 are the camera motions, the computed relative motion is
- * T = T2 T1^{-1}
- */
-void RelativeCameraMotion(const Mat3 &R1,
- const Vec3 &t1,
- const Mat3 &R2,
- const Vec3 &t2,
- Mat3 *R,
- Vec3 *t);
-
-void EssentialFromFundamental(const Mat3 &F,
- const Mat3 &K1,
- const Mat3 &K2,
- Mat3 *E);
-
-void FundamentalFromEssential(const Mat3 &E,
- const Mat3 &K1,
- const Mat3 &K2,
- Mat3 *F);
-
-void EssentialFromRt(const Mat3 &R1,
- const Vec3 &t1,
- const Mat3 &R2,
- const Vec3 &t2,
- Mat3 *E);
-
-void MotionFromEssential(const Mat3 &E,
- std::vector<Mat3> *Rs,
- std::vector<Vec3> *ts);
-
-/**
- * Choose one of the four possible motion solutions from an essential matrix.
- *
- * Decides the right solution by checking that the triangulation of a match
- * x1--x2 lies in front of the cameras. See HZ 9.6 pag 259 (9.6.3 Geometrical
- * interpretation of the 4 solutions)
- *
- * \return index of the right solution or -1 if no solution.
- */
-int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
- const std::vector<Vec3> &ts,
- const Mat3 &K1,
- const Vec2 &x1,
- const Mat3 &K2,
- const Vec2 &x2);
-
-bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
- const Mat3 &K1,
- const Vec2 &x1,
- const Mat3 &K2,
- const Vec2 &x2,
- Mat3 *R,
- Vec3 *t);
-
-/**
- * Find closest essential matrix E to fundamental F
- */
-void FundamentalToEssential(const Mat3 &F, Mat3 *E);
-
-/**
- * This structure contains options that controls how the fundamental
- * estimation operates.
- *
- * Defaults should be suitable for a wide range of use cases, but
- * better performance and accuracy might require tweaking/
- */
-struct EstimateFundamentalOptions {
- // Default constructor which sets up a options for generic usage.
- EstimateFundamentalOptions(void);
-
- // Maximal number of iterations for refinement step.
- int max_num_iterations;
-
- // Expected average of symmetric epipolar distance between
- // actual destination points and original ones transformed by
- // estimated fundamental matrix.
- //
- // Refinement will finish as soon as average of symmetric
- // epipolar distance is less or equal to this value.
- //
- // This distance is measured in the same units as input points are.
- double expected_average_symmetric_distance;
-};
-
-/**
- * Fundamental transformation estimation.
- *
- * This function estimates the fundamental transformation from a list of 2D
- * correspondences by doing algebraic estimation first followed with result
- * refinement.
- */
-bool EstimateFundamentalFromCorrespondences(
- const Mat &x1,
- const Mat &x2,
- const EstimateFundamentalOptions &options,
- Mat3 *F);
-
-} // namespace libmv
-
-#endif // LIBMV_MULTIVIEW_FUNDAMENTAL_H_
diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc
deleted file mode 100644
index 346acb3afd9..00000000000
--- a/extern/libmv/libmv/multiview/homography.cc
+++ /dev/null
@@ -1,470 +0,0 @@
-// Copyright (c) 2008, 2009 libmv authors.
-//
-// 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.
-
-#include "libmv/multiview/homography.h"
-
-#include "ceres/ceres.h"
-#include "libmv/logging/logging.h"
-#include "libmv/multiview/conditioning.h"
-#include "libmv/multiview/homography_parameterization.h"
-
-namespace libmv {
-/** 2D Homography transformation estimation in the case that points are in
- * euclidean coordinates.
- *
- * x = H y
- * x and y vector must have the same direction, we could write
- * crossproduct(|x|, * H * |y| ) = |0|
- *
- * | 0 -1 x2| |a b c| |y1| |0|
- * | 1 0 -x1| * |d e f| * |y2| = |0|
- * |-x2 x1 0| |g h 1| |1 | |0|
- *
- * That gives :
- *
- * (-d+x2*g)*y1 + (-e+x2*h)*y2 + -f+x2 |0|
- * (a-x1*g)*y1 + (b-x1*h)*y2 + c-x1 = |0|
- * (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0|
- */
-static bool Homography2DFromCorrespondencesLinearEuc(
- const Mat &x1,
- const Mat &x2,
- Mat3 *H,
- double expected_precision) {
- assert(2 == x1.rows());
- assert(4 <= x1.cols());
- assert(x1.rows() == x2.rows());
- assert(x1.cols() == x2.cols());
-
- int n = x1.cols();
- MatX8 L = Mat::Zero(n * 3, 8);
- Mat b = Mat::Zero(n * 3, 1);
- for (int i = 0; i < n; ++i) {
- int j = 3 * i;
- L(j, 0) = x1(0, i); // a
- L(j, 1) = x1(1, i); // b
- L(j, 2) = 1.0; // c
- L(j, 6) = -x2(0, i) * x1(0, i); // g
- L(j, 7) = -x2(0, i) * x1(1, i); // h
- b(j, 0) = x2(0, i); // i
-
- ++j;
- L(j, 3) = x1(0, i); // d
- L(j, 4) = x1(1, i); // e
- L(j, 5) = 1.0; // f
- L(j, 6) = -x2(1, i) * x1(0, i); // g
- L(j, 7) = -x2(1, i) * x1(1, i); // h
- b(j, 0) = x2(1, i); // i
-
- // This ensures better stability
- // TODO(julien) make a lite version without this 3rd set
- ++j;
- L(j, 0) = x2(1, i) * x1(0, i); // a
- L(j, 1) = x2(1, i) * x1(1, i); // b
- L(j, 2) = x2(1, i); // c
- L(j, 3) = -x2(0, i) * x1(0, i); // d
- L(j, 4) = -x2(0, i) * x1(1, i); // e
- L(j, 5) = -x2(0, i); // f
- }
- // Solve Lx=B
- Vec h = L.fullPivLu().solve(b);
- Homography2DNormalizedParameterization<double>::To(h, H);
- if ((L * h).isApprox(b, expected_precision)) {
- return true;
- } else {
- return false;
- }
-}
-
-/** 2D Homography transformation estimation in the case that points are in
- * homogeneous coordinates.
- *
- * | 0 -x3 x2| |a b c| |y1| -x3*d+x2*g -x3*e+x2*h -x3*f+x2*1 |y1| (-x3*d+x2*g)*y1 (-x3*e+x2*h)*y2 (-x3*f+x2*1)*y3 |0|
- * | x3 0 -x1| * |d e f| * |y2| = x3*a-x1*g x3*b-x1*h x3*c-x1*1 * |y2| = (x3*a-x1*g)*y1 (x3*b-x1*h)*y2 (x3*c-x1*1)*y3 = |0|
- * |-x2 x1 0| |g h 1| |y3| -x2*a+x1*d -x2*b+x1*e -x2*c+x1*f |y3| (-x2*a+x1*d)*y1 (-x2*b+x1*e)*y2 (-x2*c+x1*f)*y3 |0|
- * X = |a b c d e f g h|^t
- */
-bool Homography2DFromCorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- Mat3 *H,
- double expected_precision) {
- if (x1.rows() == 2) {
- return Homography2DFromCorrespondencesLinearEuc(x1, x2, H,
- expected_precision);
- }
- assert(3 == x1.rows());
- assert(4 <= x1.cols());
- assert(x1.rows() == x2.rows());
- assert(x1.cols() == x2.cols());
-
- const int x = 0;
- const int y = 1;
- const int w = 2;
- int n = x1.cols();
- MatX8 L = Mat::Zero(n * 3, 8);
- Mat b = Mat::Zero(n * 3, 1);
- for (int i = 0; i < n; ++i) {
- int j = 3 * i;
- L(j, 0) = x2(w, i) * x1(x, i); // a
- L(j, 1) = x2(w, i) * x1(y, i); // b
- L(j, 2) = x2(w, i) * x1(w, i); // c
- L(j, 6) = -x2(x, i) * x1(x, i); // g
- L(j, 7) = -x2(x, i) * x1(y, i); // h
- b(j, 0) = x2(x, i) * x1(w, i);
-
- ++j;
- L(j, 3) = x2(w, i) * x1(x, i); // d
- L(j, 4) = x2(w, i) * x1(y, i); // e
- L(j, 5) = x2(w, i) * x1(w, i); // f
- L(j, 6) = -x2(y, i) * x1(x, i); // g
- L(j, 7) = -x2(y, i) * x1(y, i); // h
- b(j, 0) = x2(y, i) * x1(w, i);
-
- // This ensures better stability
- ++j;
- L(j, 0) = x2(y, i) * x1(x, i); // a
- L(j, 1) = x2(y, i) * x1(y, i); // b
- L(j, 2) = x2(y, i) * x1(w, i); // c
- L(j, 3) = -x2(x, i) * x1(x, i); // d
- L(j, 4) = -x2(x, i) * x1(y, i); // e
- L(j, 5) = -x2(x, i) * x1(w, i); // f
- }
- // Solve Lx=B
- Vec h = L.fullPivLu().solve(b);
- if ((L * h).isApprox(b, expected_precision)) {
- Homography2DNormalizedParameterization<double>::To(h, H);
- return true;
- } else {
- return false;
- }
-}
-
-// Default settings for homography estimation which should be suitable
-// for a wide range of use cases.
-EstimateHomographyOptions::EstimateHomographyOptions(void) :
- use_normalization(true),
- max_num_iterations(50),
- expected_average_symmetric_distance(1e-16) {
-}
-
-namespace {
-void GetNormalizedPoints(const Mat &original_points,
- Mat *normalized_points,
- Mat3 *normalization_matrix) {
- IsotropicPreconditionerFromPoints(original_points, normalization_matrix);
- ApplyTransformationToPoints(original_points,
- *normalization_matrix,
- normalized_points);
-}
-
-// Cost functor which computes symmetric geometric distance
-// used for homography matrix refinement.
-class HomographySymmetricGeometricCostFunctor {
- public:
- HomographySymmetricGeometricCostFunctor(const Vec2 &x,
- const Vec2 &y) {
- xx_ = x(0);
- xy_ = x(1);
- yx_ = y(0);
- yy_ = y(1);
- }
-
- template<typename T>
- bool operator()(const T *homography_parameters, T *residuals) const {
- typedef Eigen::Matrix<T, 3, 3> Mat3;
- typedef Eigen::Matrix<T, 3, 1> Vec3;
-
- Mat3 H(homography_parameters);
-
- Vec3 x(T(xx_), T(xy_), T(1.0));
- Vec3 y(T(yx_), T(yy_), T(1.0));
-
- Vec3 H_x = H * x;
- Vec3 Hinv_y = H.inverse() * y;
-
- H_x /= H_x(2);
- Hinv_y /= Hinv_y(2);
-
- // This is a forward error.
- residuals[0] = H_x(0) - T(yx_);
- residuals[1] = H_x(1) - T(yy_);
-
- // This is a backward error.
- residuals[2] = Hinv_y(0) - T(xx_);
- residuals[3] = Hinv_y(1) - T(xy_);
-
- return true;
- }
-
- // TODO(sergey): Think of better naming.
- double xx_, xy_;
- double yx_, yy_;
-};
-
-// Termination checking callback used for homography estimation.
-// It finished the minimization as soon as actual average of
-// symmetric geometric distance is less or equal to the expected
-// average value.
-class TerminationCheckingCallback : public ceres::IterationCallback {
- public:
- TerminationCheckingCallback(const Mat &x1, const Mat &x2,
- const EstimateHomographyOptions &options,
- Mat3 *H)
- : options_(options), x1_(x1), x2_(x2), H_(H) {}
-
- virtual ceres::CallbackReturnType operator()(
- const ceres::IterationSummary& summary) {
- // If the step wasn't successful, there's nothing to do.
- if (!summary.step_is_successful) {
- return ceres::SOLVER_CONTINUE;
- }
-
- // Calculate average of symmetric geometric distance.
- double average_distance = 0.0;
- for (int i = 0; i < x1_.cols(); i++) {
- average_distance = SymmetricGeometricDistance(*H_,
- x1_.col(i),
- x2_.col(i));
- }
- average_distance /= x1_.cols();
-
- if (average_distance <= options_.expected_average_symmetric_distance) {
- return ceres::SOLVER_TERMINATE_SUCCESSFULLY;
- }
-
- return ceres::SOLVER_CONTINUE;
- }
-
- private:
- const EstimateHomographyOptions &options_;
- const Mat &x1_;
- const Mat &x2_;
- Mat3 *H_;
-};
-} // namespace
-
-/** 2D Homography transformation estimation in the case that points are in
- * euclidean coordinates.
- */
-bool EstimateHomography2DFromCorrespondences(
- const Mat &x1,
- const Mat &x2,
- const EstimateHomographyOptions &options,
- Mat3 *H) {
- // TODO(sergey): Support homogenous coordinates, not just euclidean.
-
- assert(2 == x1.rows());
- assert(4 <= x1.cols());
- assert(x1.rows() == x2.rows());
- assert(x1.cols() == x2.cols());
-
- Mat3 T1 = Mat3::Identity(),
- T2 = Mat3::Identity();
-
- // Step 1: Algebraic homography estimation.
- Mat x1_normalized, x2_normalized;
-
- if (options.use_normalization) {
- LG << "Estimating homography using normalization.";
- GetNormalizedPoints(x1, &x1_normalized, &T1);
- GetNormalizedPoints(x2, &x2_normalized, &T2);
- } else {
- x1_normalized = x1;
- x2_normalized = x2;
- }
-
- // Assume algebraic estiation always suceeds,
- Homography2DFromCorrespondencesLinear(x1_normalized, x2_normalized, H);
-
- // Denormalize the homography matrix.
- if (options.use_normalization) {
- *H = T2.inverse() * (*H) * T1;
- }
-
- LG << "Estimated matrix after algebraic estimation:\n" << *H;
-
- // Step 2: Refine matrix using Ceres minimizer.
- ceres::Problem problem;
- for (int i = 0; i < x1.cols(); i++) {
- HomographySymmetricGeometricCostFunctor
- *homography_symmetric_geometric_cost_function =
- new HomographySymmetricGeometricCostFunctor(x1.col(i),
- x2.col(i));
-
- problem.AddResidualBlock(
- new ceres::AutoDiffCostFunction<
- HomographySymmetricGeometricCostFunctor,
- 4, // num_residuals
- 9>(homography_symmetric_geometric_cost_function),
- NULL,
- H->data());
- }
-
- // Configure the solve.
- ceres::Solver::Options solver_options;
- solver_options.linear_solver_type = ceres::DENSE_QR;
- solver_options.max_num_iterations = options.max_num_iterations;
- solver_options.update_state_every_iteration = true;
-
- // Terminate if the average symmetric distance is good enough.
- TerminationCheckingCallback callback(x1, x2, options, H);
- solver_options.callbacks.push_back(&callback);
-
- // Run the solve.
- ceres::Solver::Summary summary;
- ceres::Solve(solver_options, &problem, &summary);
-
- VLOG(1) << "Summary:\n" << summary.FullReport();
-
- LG << "Final refined matrix:\n" << *H;
-
- return summary.IsSolutionUsable();
-}
-
-/**
- * x2 ~ A * x1
- * x2^t * Hi * A *x1 = 0
- * H1 = H2 = H3 =
- * | 0 0 0 1| |-x2w| |0 0 0 0| | 0 | | 0 0 1 0| |-x2z|
- * | 0 0 0 0| -> | 0 | |0 0 1 0| -> |-x2z| | 0 0 0 0| -> | 0 |
- * | 0 0 0 0| | 0 | |0-1 0 0| | x2y| |-1 0 0 0| | x2x|
- * |-1 0 0 0| | x2x| |0 0 0 0| | 0 | | 0 0 0 0| | 0 |
- * H4 = H5 = H6 =
- * |0 0 0 0| | 0 | | 0 1 0 0| |-x2y| |0 0 0 0| | 0 |
- * |0 0 0 1| -> |-x2w| |-1 0 0 0| -> | x2x| |0 0 0 0| -> | 0 |
- * |0 0 0 0| | 0 | | 0 0 0 0| | 0 | |0 0 0 1| |-x2w|
- * |0-1 0 0| | x2y| | 0 0 0 0| | 0 | |0 0-1 0| | x2z|
- * |a b c d|
- * A = |e f g h|
- * |i j k l|
- * |m n o 1|
- *
- * x2^t * H1 * A *x1 = (-x2w*a +x2x*m )*x1x + (-x2w*b +x2x*n )*x1y + (-x2w*c +x2x*o )*x1z + (-x2w*d +x2x*1 )*x1w = 0
- * x2^t * H2 * A *x1 = (-x2z*e +x2y*i )*x1x + (-x2z*f +x2y*j )*x1y + (-x2z*g +x2y*k )*x1z + (-x2z*h +x2y*l )*x1w = 0
- * x2^t * H3 * A *x1 = (-x2z*a +x2x*i )*x1x + (-x2z*b +x2x*j )*x1y + (-x2z*c +x2x*k )*x1z + (-x2z*d +x2x*l )*x1w = 0
- * x2^t * H4 * A *x1 = (-x2w*e +x2y*m )*x1x + (-x2w*f +x2y*n )*x1y + (-x2w*g +x2y*o )*x1z + (-x2w*h +x2y*1 )*x1w = 0
- * x2^t * H5 * A *x1 = (-x2y*a +x2x*e )*x1x + (-x2y*b +x2x*f )*x1y + (-x2y*c +x2x*g )*x1z + (-x2y*d +x2x*h )*x1w = 0
- * x2^t * H6 * A *x1 = (-x2w*i +x2z*m )*x1x + (-x2w*j +x2z*n )*x1y + (-x2w*k +x2z*o )*x1z + (-x2w*l +x2z*1 )*x1w = 0
- *
- * X = |a b c d e f g h i j k l m n o|^t
-*/
-bool Homography3DFromCorrespondencesLinear(const Mat &x1,
- const Mat &x2,
- Mat4 *H,
- double expected_precision) {
- assert(4 == x1.rows());
- assert(5 <= x1.cols());
- assert(x1.rows() == x2.rows());
- assert(x1.cols() == x2.cols());
- const int x = 0;
- const int y = 1;
- const int z = 2;
- const int w = 3;
- int n = x1.cols();
- MatX15 L = Mat::Zero(n * 6, 15);
- Mat b = Mat::Zero(n * 6, 1);
- for (int i = 0; i < n; ++i) {
- int j = 6 * i;
- L(j, 0) = -x2(w, i) * x1(x, i); // a
- L(j, 1) = -x2(w, i) * x1(y, i); // b
- L(j, 2) = -x2(w, i) * x1(z, i); // c
- L(j, 3) = -x2(w, i) * x1(w, i); // d
- L(j, 12) = x2(x, i) * x1(x, i); // m
- L(j, 13) = x2(x, i) * x1(y, i); // n
- L(j, 14) = x2(x, i) * x1(z, i); // o
- b(j, 0) = -x2(x, i) * x1(w, i);
-
- ++j;
- L(j, 4) = -x2(z, i) * x1(x, i); // e
- L(j, 5) = -x2(z, i) * x1(y, i); // f
- L(j, 6) = -x2(z, i) * x1(z, i); // g
- L(j, 7) = -x2(z, i) * x1(w, i); // h
- L(j, 8) = x2(y, i) * x1(x, i); // i
- L(j, 9) = x2(y, i) * x1(y, i); // j
- L(j, 10) = x2(y, i) * x1(z, i); // k
- L(j, 11) = x2(y, i) * x1(w, i); // l
-
- ++j;
- L(j, 0) = -x2(z, i) * x1(x, i); // a
- L(j, 1) = -x2(z, i) * x1(y, i); // b
- L(j, 2) = -x2(z, i) * x1(z, i); // c
- L(j, 3) = -x2(z, i) * x1(w, i); // d
- L(j, 8) = x2(x, i) * x1(x, i); // i
- L(j, 9) = x2(x, i) * x1(y, i); // j
- L(j, 10) = x2(x, i) * x1(z, i); // k
- L(j, 11) = x2(x, i) * x1(w, i); // l
-
- ++j;
- L(j, 4) = -x2(w, i) * x1(x, i); // e
- L(j, 5) = -x2(w, i) * x1(y, i); // f
- L(j, 6) = -x2(w, i) * x1(z, i); // g
- L(j, 7) = -x2(w, i) * x1(w, i); // h
- L(j, 12) = x2(y, i) * x1(x, i); // m
- L(j, 13) = x2(y, i) * x1(y, i); // n
- L(j, 14) = x2(y, i) * x1(z, i); // o
- b(j, 0) = -x2(y, i) * x1(w, i);
-
- ++j;
- L(j, 0) = -x2(y, i) * x1(x, i); // a
- L(j, 1) = -x2(y, i) * x1(y, i); // b
- L(j, 2) = -x2(y, i) * x1(z, i); // c
- L(j, 3) = -x2(y, i) * x1(w, i); // d
- L(j, 4) = x2(x, i) * x1(x, i); // e
- L(j, 5) = x2(x, i) * x1(y, i); // f
- L(j, 6) = x2(x, i) * x1(z, i); // g
- L(j, 7) = x2(x, i) * x1(w, i); // h
-
- ++j;
- L(j, 8) = -x2(w, i) * x1(x, i); // i
- L(j, 9) = -x2(w, i) * x1(y, i); // j
- L(j, 10) = -x2(w, i) * x1(z, i); // k
- L(j, 11) = -x2(w, i) * x1(w, i); // l
- L(j, 12) = x2(z, i) * x1(x, i); // m
- L(j, 13) = x2(z, i) * x1(y, i); // n
- L(j, 14) = x2(z, i) * x1(z, i); // o
- b(j, 0) = -x2(z, i) * x1(w, i);
- }
- // Solve Lx=B
- Vec h = L.fullPivLu().solve(b);
- if ((L * h).isApprox(b, expected_precision)) {
- Homography3DNormalizedParameterization<double>::To(h, H);
- return true;
- } else {
- return false;
- }
-}
-
-double SymmetricGeometricDistance(const Mat3 &H,
- const Vec2 &x1,
- const Vec2 &x2) {
- Vec3 x(x1(0), x1(1), 1.0);
- Vec3 y(x2(0), x2(1), 1.0);
-
- Vec3 H_x = H * x;
- Vec3 Hinv_y = H.inverse() * y;
-
- H_x /= H_x(2);
- Hinv_y /= Hinv_y(2);
-
- return (H_x.head<2>() - y.head<2>()).squaredNorm() +
- (Hinv_y.head<2>() - x.head<2>()).squaredNorm();
-}
-
-} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/projection_test.cc b/extern/libmv/libmv/multiview/projection_test.cc
deleted file mode 100644
index c060bfb0681..00000000000
--- a/extern/libmv/libmv/multiview/projection_test.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2007, 2008 libmv authors.
-//
-// 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.
-
-#include <iostream>
-
-#include "libmv/multiview/projection.h"
-#include "libmv/numeric/numeric.h"
-#include "testing/testing.h"
-
-namespace {
-using namespace libmv;
-
-TEST(Projection, P_From_KRt) {
- Mat3 K, Kp;
- K << 10, 1, 30,
- 0, 20, 40,
- 0, 0, 1;
-
- Mat3 R, Rp;
- R << 1, 0, 0,
- 0, 1, 0,
- 0, 0, 1;
-
- Vec3 t, tp;
- t << 1, 2, 3;
-
- Mat34 P;
- P_From_KRt(K, R, t, &P);
- KRt_From_P(P, &Kp, &Rp, &tp);
-
- EXPECT_MATRIX_NEAR(K, Kp, 1e-8);
- EXPECT_MATRIX_NEAR(R, Rp, 1e-8);
- EXPECT_MATRIX_NEAR(t, tp, 1e-8);
-
- // TODO(keir): Change the code to ensure det(R) == 1, which is not currently
- // the case. Also add a test for that here.
-}
-
-Vec4 GetRandomPoint() {
- Vec4 X;
- X.setRandom();
- X(3) = 1;
- return X;
-}
-
-TEST(Projection, isInFrontOfCamera) {
- Mat34 P;
- P << 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0;
-
- Vec4 X_front = GetRandomPoint();
- Vec4 X_back = GetRandomPoint();
- X_front(2) = 10; // Any point in the positive Z direction
- // where Z > 1 is infront of the camera.
- X_back(2) = -10; // Any point int he negative Z dirstaion
- // is behind the camera.
-
- bool res_front = isInFrontOfCamera(P, X_front);
- bool res_back = isInFrontOfCamera(P, X_back);
-
- EXPECT_EQ(true, res_front);
- EXPECT_EQ(false, res_back);
-}
-
-TEST(AutoCalibration, ProjectionShiftPrincipalPoint) {
- Mat34 P1, P2;
- P1 << 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0;
- P2 << 1, 0, 3, 0,
- 0, 1, 4, 0,
- 0, 0, 1, 0;
- Mat34 P1_computed, P2_computed;
- ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed);
- ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed);
-
- EXPECT_MATRIX_EQ(P1, P1_computed);
- EXPECT_MATRIX_EQ(P2, P2_computed);
-}
-
-TEST(AutoCalibration, ProjectionChangeAspectRatio) {
- Mat34 P1, P2;
- P1 << 1, 0, 3, 0,
- 0, 1, 4, 0,
- 0, 0, 1, 0;
- P2 << 1, 0, 3, 0,
- 0, 2, 4, 0,
- 0, 0, 1, 0;
- Mat34 P1_computed, P2_computed;
- ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed);
- ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed);
-
- EXPECT_MATRIX_EQ(P1, P1_computed);
- EXPECT_MATRIX_EQ(P2, P2_computed);
-}
-
-} // namespace
diff --git a/extern/libmv/libmv/numeric/numeric.h b/extern/libmv/libmv/numeric/numeric.h
deleted file mode 100644
index 55d4c7d4651..00000000000
--- a/extern/libmv/libmv/numeric/numeric.h
+++ /dev/null
@@ -1,502 +0,0 @@
-// Copyright (c) 2007, 2008 libmv authors.
-//
-// 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.
-//
-// Matrix and vector classes, based on Eigen2.
-//
-// Avoid using Eigen2 classes directly; instead typedef them here.
-
-#ifndef LIBMV_NUMERIC_NUMERIC_H
-#define LIBMV_NUMERIC_NUMERIC_H
-
-#include <Eigen/Cholesky>
-#include <Eigen/Core>
-#include <Eigen/Eigenvalues>
-#include <Eigen/Geometry>
-#include <Eigen/LU>
-#include <Eigen/QR>
-#include <Eigen/SVD>
-
-#if !defined(__MINGW64__)
-# if defined(_WIN32) || defined(__APPLE__) || \
- defined(__FreeBSD__) || defined(__NetBSD__)
-static void sincos(double x, double *sinx, double *cosx) {
- *sinx = sin(x);
- *cosx = cos(x);
-}
-# endif
-#endif // !__MINGW64__
-
-#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
-inline long lround(double d) {
- return (long)(d>0 ? d+0.5 : ceil(d-0.5));
-}
-# if _MSC_VER < 1800
-inline int round(double d) {
- return (d>0) ? int(d+0.5) : int(d-0.5);
-}
-# endif // _MSC_VER < 1800
-typedef unsigned int uint;
-#endif // _WIN32
-
-namespace libmv {
-
-typedef Eigen::MatrixXd Mat;
-typedef Eigen::VectorXd Vec;
-
-typedef Eigen::MatrixXf Matf;
-typedef Eigen::VectorXf Vecf;
-
-typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic> Matu;
-typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> Vecu;
-typedef Eigen::Matrix<unsigned int, 2, 1> Vec2u;
-
-typedef Eigen::Matrix<double, 2, 2> Mat2;
-typedef Eigen::Matrix<double, 2, 3> Mat23;
-typedef Eigen::Matrix<double, 3, 3> Mat3;
-typedef Eigen::Matrix<double, 3, 4> Mat34;
-typedef Eigen::Matrix<double, 3, 5> Mat35;
-typedef Eigen::Matrix<double, 4, 1> Mat41;
-typedef Eigen::Matrix<double, 4, 3> Mat43;
-typedef Eigen::Matrix<double, 4, 4> Mat4;
-typedef Eigen::Matrix<double, 4, 6> Mat46;
-typedef Eigen::Matrix<float, 2, 2> Mat2f;
-typedef Eigen::Matrix<float, 2, 3> Mat23f;
-typedef Eigen::Matrix<float, 3, 3> Mat3f;
-typedef Eigen::Matrix<float, 3, 4> Mat34f;
-typedef Eigen::Matrix<float, 3, 5> Mat35f;
-typedef Eigen::Matrix<float, 4, 3> Mat43f;
-typedef Eigen::Matrix<float, 4, 4> Mat4f;
-typedef Eigen::Matrix<float, 4, 6> Mat46f;
-
-typedef Eigen::Matrix<double, 3, 3, Eigen::RowMajor> RMat3;
-typedef Eigen::Matrix<double, 4, 4, Eigen::RowMajor> RMat4;
-
-typedef Eigen::Matrix<double, 2, Eigen::Dynamic> Mat2X;
-typedef Eigen::Matrix<double, 3, Eigen::Dynamic> Mat3X;
-typedef Eigen::Matrix<double, 4, Eigen::Dynamic> Mat4X;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 15> MatX15;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 16> MatX16;
-
-typedef Eigen::Vector2d Vec2;
-typedef Eigen::Vector3d Vec3;
-typedef Eigen::Vector4d Vec4;
-typedef Eigen::Matrix<double, 5, 1> Vec5;
-typedef Eigen::Matrix<double, 6, 1> Vec6;
-typedef Eigen::Matrix<double, 7, 1> Vec7;
-typedef Eigen::Matrix<double, 8, 1> Vec8;
-typedef Eigen::Matrix<double, 9, 1> Vec9;
-typedef Eigen::Matrix<double, 10, 1> Vec10;
-typedef Eigen::Matrix<double, 11, 1> Vec11;
-typedef Eigen::Matrix<double, 12, 1> Vec12;
-typedef Eigen::Matrix<double, 13, 1> Vec13;
-typedef Eigen::Matrix<double, 14, 1> Vec14;
-typedef Eigen::Matrix<double, 15, 1> Vec15;
-typedef Eigen::Matrix<double, 16, 1> Vec16;
-typedef Eigen::Matrix<double, 17, 1> Vec17;
-typedef Eigen::Matrix<double, 18, 1> Vec18;
-typedef Eigen::Matrix<double, 19, 1> Vec19;
-typedef Eigen::Matrix<double, 20, 1> Vec20;
-
-typedef Eigen::Vector2f Vec2f;
-typedef Eigen::Vector3f Vec3f;
-typedef Eigen::Vector4f Vec4f;
-
-typedef Eigen::VectorXi VecXi;
-
-typedef Eigen::Vector2i Vec2i;
-typedef Eigen::Vector3i Vec3i;
-typedef Eigen::Vector4i Vec4i;
-
-typedef Eigen::Matrix<float,
- Eigen::Dynamic,
- Eigen::Dynamic,
- Eigen::RowMajor> RMatf;
-
-typedef Eigen::NumTraits<double> EigenDouble;
-
-using Eigen::Map;
-using Eigen::Dynamic;
-using Eigen::Matrix;
-
-// Find U, s, and VT such that
-//
-// A = U * diag(s) * VT
-//
-template <typename TMat, typename TVec>
-inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) {
- assert(0);
-}
-
-// Solve the linear system Ax = 0 via SVD. Store the solution in x, such that
-// ||x|| = 1.0. Return the singluar value corresponding to the solution.
-// Destroys A and resizes x if necessary.
-// TODO(maclean): Take the SVD of the transpose instead of this zero padding.
-template <typename TMat, typename TVec>
-double Nullspace(TMat *A, TVec *nullspace) {
- Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
- (*nullspace) = svd.matrixV().col(A->cols()-1);
- if (A->rows() >= A->cols())
- return svd.singularValues()(A->cols()-1);
- else
- return 0.0;
-}
-
-// Solve the linear system Ax = 0 via SVD. Finds two solutions, x1 and x2, such
-// that x1 is the best solution and x2 is the next best solution (in the L2
-// norm sense). Store the solution in x1 and x2, such that ||x|| = 1.0. Return
-// the singluar value corresponding to the solution x1. Destroys A and resizes
-// x if necessary.
-template <typename TMat, typename TVec1, typename TVec2>
-double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) {
- Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
- *x1 = svd.matrixV().col(A->cols() - 1);
- *x2 = svd.matrixV().col(A->cols() - 2);
- if (A->rows() >= A->cols())
- return svd.singularValues()(A->cols()-1);
- else
- return 0.0;
-}
-
-// In place transpose for square matrices.
-template<class TA>
-inline void TransposeInPlace(TA *A) {
- *A = A->transpose().eval();
-}
-
-template<typename TVec>
-inline double NormL1(const TVec &x) {
- return x.array().abs().sum();
-}
-
-template<typename TVec>
-inline double NormL2(const TVec &x) {
- return x.norm();
-}
-
-template<typename TVec>
-inline double NormLInfinity(const TVec &x) {
- return x.array().abs().maxCoeff();
-}
-
-template<typename TVec>
-inline double DistanceL1(const TVec &x, const TVec &y) {
- return (x - y).array().abs().sum();
-}
-
-template<typename TVec>
-inline double DistanceL2(const TVec &x, const TVec &y) {
- return (x - y).norm();
-}
-template<typename TVec>
-inline double DistanceLInfinity(const TVec &x, const TVec &y) {
- return (x - y).array().abs().maxCoeff();
-}
-
-// Normalize a vector with the L1 norm, and return the norm before it was
-// normalized.
-template<typename TVec>
-inline double NormalizeL1(TVec *x) {
- double norm = NormL1(*x);
- *x /= norm;
- return norm;
-}
-
-// Normalize a vector with the L2 norm, and return the norm before it was
-// normalized.
-template<typename TVec>
-inline double NormalizeL2(TVec *x) {
- double norm = NormL2(*x);
- *x /= norm;
- return norm;
-}
-
-// Normalize a vector with the L^Infinity norm, and return the norm before it
-// was normalized.
-template<typename TVec>
-inline double NormalizeLInfinity(TVec *x) {
- double norm = NormLInfinity(*x);
- *x /= norm;
- return norm;
-}
-
-// Return the square of a number.
-template<typename T>
-inline T Square(T x) {
- return x * x;
-}
-
-Mat3 RotationAroundX(double angle);
-Mat3 RotationAroundY(double angle);
-Mat3 RotationAroundZ(double angle);
-
-// Returns the rotation matrix of a rotation of angle |axis| around axis.
-// This is computed using the Rodrigues formula, see:
-// http://mathworld.wolfram.com/RodriguesRotationFormula.html
-Mat3 RotationRodrigues(const Vec3 &axis);
-
-// Make a rotation matrix such that center becomes the direction of the
-// positive z-axis, and y is oriented close to up.
-Mat3 LookAt(Vec3 center);
-
-// Return a diagonal matrix from a vector containg the diagonal values.
-template <typename TVec>
-inline Mat Diag(const TVec &x) {
- return x.asDiagonal();
-}
-
-template<typename TMat>
-inline double FrobeniusNorm(const TMat &A) {
- return sqrt(A.array().abs2().sum());
-}
-
-template<typename TMat>
-inline double FrobeniusDistance(const TMat &A, const TMat &B) {
- return FrobeniusNorm(A - B);
-}
-
-inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) {
- return x.cross(y);
-}
-
-Mat3 CrossProductMatrix(const Vec3 &x);
-
-void MeanAndVarianceAlongRows(const Mat &A,
- Vec *mean_pointer,
- Vec *variance_pointer);
-
-#if _WIN32
- // TODO(bomboze): un-#if this for both platforms once tested under Windows
- /* This solution was extensively discussed here
- http://forum.kde.org/viewtopic.php?f=74&t=61940 */
- #define SUM_OR_DYNAMIC(x, y) (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x+y)
-
- template<typename Derived1, typename Derived2>
- struct hstack_return {
- typedef typename Derived1::Scalar Scalar;
- enum {
- RowsAtCompileTime = Derived1::RowsAtCompileTime,
- ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime,
- Derived2::ColsAtCompileTime),
- Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
- MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime,
- MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime,
- Derived2::MaxColsAtCompileTime)
- };
- typedef Eigen::Matrix<Scalar,
- RowsAtCompileTime,
- ColsAtCompileTime,
- Options,
- MaxRowsAtCompileTime,
- MaxColsAtCompileTime> type;
- };
-
- template<typename Derived1, typename Derived2>
- typename hstack_return<Derived1, Derived2>::type
- HStack(const Eigen::MatrixBase<Derived1>& lhs,
- const Eigen::MatrixBase<Derived2>& rhs) {
- typename hstack_return<Derived1, Derived2>::type res;
- res.resize(lhs.rows(), lhs.cols()+rhs.cols());
- res << lhs, rhs;
- return res;
- };
-
-
- template<typename Derived1, typename Derived2>
- struct vstack_return {
- typedef typename Derived1::Scalar Scalar;
- enum {
- RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime,
- Derived2::RowsAtCompileTime),
- ColsAtCompileTime = Derived1::ColsAtCompileTime,
- Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
- MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime,
- Derived2::MaxRowsAtCompileTime),
- MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime
- };
- typedef Eigen::Matrix<Scalar,
- RowsAtCompileTime,
- ColsAtCompileTime,
- Options,
- MaxRowsAtCompileTime,
- MaxColsAtCompileTime> type;
- };
-
- template<typename Derived1, typename Derived2>
- typename vstack_return<Derived1, Derived2>::type
- VStack(const Eigen::MatrixBase<Derived1>& lhs,
- const Eigen::MatrixBase<Derived2>& rhs) {
- typename vstack_return<Derived1, Derived2>::type res;
- res.resize(lhs.rows()+rhs.rows(), lhs.cols());
- res << lhs, rhs;
- return res;
- };
-
-
-#else // _WIN32
-
- // Since it is not possible to typedef privately here, use a macro.
- // Always take dynamic columns if either side is dynamic.
- #define COLS \
- ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \
- ? Eigen::Dynamic : (ColsLeft + ColsRight))
-
- // Same as above, except that prefer fixed size if either is fixed.
- #define ROWS \
- ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \
- ? Eigen::Dynamic \
- : ((RowsLeft == Eigen::Dynamic) \
- ? RowsRight \
- : RowsLeft \
- ) \
- )
-
- // TODO(keir): Add a static assert if both rows are at compiletime.
- template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
- Eigen::Matrix<T, ROWS, COLS>
- HStack(const Eigen::Matrix<T, RowsLeft, ColsLeft> &left,
- const Eigen::Matrix<T, RowsRight, ColsRight> &right) {
- assert(left.rows() == right.rows());
- int n = left.rows();
- int m1 = left.cols();
- int m2 = right.cols();
-
- Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2);
- stacked.block(0, 0, n, m1) = left;
- stacked.block(0, m1, n, m2) = right;
- return stacked;
- }
-
- // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but
- // the duplication is worse.
- // TODO(keir): Add a static assert if both rows are at compiletime.
- // TODO(keir): Mail eigen list about making this work for general expressions
- // rather than only matrix types.
- template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
- Eigen::Matrix<T, COLS, ROWS>
- VStack(const Eigen::Matrix<T, ColsLeft, RowsLeft> &top,
- const Eigen::Matrix<T, ColsRight, RowsRight> &bottom) {
- assert(top.cols() == bottom.cols());
- int n1 = top.rows();
- int n2 = bottom.rows();
- int m = top.cols();
-
- Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m);
- stacked.block(0, 0, n1, m) = top;
- stacked.block(n1, 0, n2, m) = bottom;
- return stacked;
- }
- #undef COLS
- #undef ROWS
-#endif // _WIN32
-
-
-
-void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked);
-
-template<typename TTop, typename TBot, typename TStacked>
-void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) {
- assert(top.cols() == bottom.cols());
- int n1 = top.rows();
- int n2 = bottom.rows();
- int m = top.cols();
-
- stacked->resize(n1 + n2, m);
- stacked->block(0, 0, n1, m) = top;
- stacked->block(n1, 0, n2, m) = bottom;
-}
-
-void MatrixColumn(const Mat &A, int i, Vec2 *v);
-void MatrixColumn(const Mat &A, int i, Vec3 *v);
-void MatrixColumn(const Mat &A, int i, Vec4 *v);
-
-template <typename TMat, typename TCols>
-TMat ExtractColumns(const TMat &A, const TCols &columns) {
- TMat compressed(A.rows(), columns.size());
- for (int i = 0; i < columns.size(); ++i) {
- compressed.col(i) = A.col(columns[i]);
- }
- return compressed;
-}
-
-template <typename TMat, typename TDest>
-void reshape(const TMat &a, int rows, int cols, TDest *b) {
- assert(a.rows()*a.cols() == rows*cols);
- b->resize(rows, cols);
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < cols; j++) {
- (*b)(i, j) = a[cols*i + j];
- }
- }
-}
-
-inline bool isnan(double i) {
-#ifdef WIN32
- return _isnan(i) > 0;
-#else
- return std::isnan(i);
-#endif
-}
-
-/// Ceil function that has the same behaviour for positive
-/// and negative values
-template <typename FloatType>
-FloatType ceil0(const FloatType& value) {
- FloatType result = std::ceil(std::fabs(value));
- return (value < 0.0) ? -result : result;
-}
-
-/// Returns the skew anti-symmetric matrix of a vector
-inline Mat3 SkewMat(const Vec3 &x) {
- Mat3 skew;
- skew << 0 , -x(2), x(1),
- x(2), 0 , -x(0),
- -x(1), x(0), 0;
- return skew;
-}
-/// Returns the skew anti-symmetric matrix of a vector with only
-/// the first two (independent) lines
-inline Mat23 SkewMatMinimal(const Vec2 &x) {
- Mat23 skew;
- skew << 0, -1, x(1),
- 1, 0, -x(0);
- return skew;
-}
-
-/// Returns the rotaiton matrix built from given vector of euler angles
-inline Mat3 RotationFromEulerVector(Vec3 euler_vector) {
- double theta = euler_vector.norm();
- if (theta == 0.0) {
- return Mat3::Identity();
- }
- Vec3 w = euler_vector / theta;
- Mat3 w_hat = CrossProductMatrix(w);
- return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta));
-}
-} // namespace libmv
-
-#endif // LIBMV_NUMERIC_NUMERIC_H
diff --git a/extern/libmv/libmv/numeric/poly_test.cc b/extern/libmv/libmv/numeric/poly_test.cc
deleted file mode 100644
index ea50383190f..00000000000
--- a/extern/libmv/libmv/numeric/poly_test.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2007, 2008 libmv authors.
-//
-// 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.
-
-#include "libmv/numeric/numeric.h"
-#include "libmv/numeric/poly.h"
-#include "testing/testing.h"
-
-using namespace libmv;
-
-namespace {
-
-// Find the polynomial coefficients of x in the equation
-//
-// (x - a)(x - b)(x - c) == 0
-//
-// by expanding to
-//
-// x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0.
-// = p = q = r
-void CoeffsForCubicZeros(double a, double b, double c,
- double *p, double *q, double *r) {
- *p = -(c + b + a);
- *q = (a * b + (b + a) * c);
- *r = -a * b * c;
-}
-// Find the polynomial coefficients of x in the equation
-//
-// (x - a)(x - b)(x - c)(x - d) == 0
-//
-// by expanding to
-//
-// x^4 - (d+c+b+a) * x^3 + (d*(c+b+a) + a*b+(b+a)*c) * x^2
-// - (d*(a*b+(b+a)*c)+a*b*c) * x + a*b*c*d = 0.
-void CoeffsForQuarticZeros(double a, double b, double c, double d,
- double *p, double *q, double *r, double *s) {
- *p = -(d + c + b + a);
- *q = (d * (c + b + a) + a * b + (b + a) * c);
- *r = -(d * (a * b + (b + a) * c) + a * b * c);
- *s = a * b * c *d;
-}
-
-TEST(Poly, SolveCubicPolynomial) {
- double a, b, c, aa, bb, cc;
- double p, q, r;
-
- a = 1; b = 2; c = 3;
- CoeffsForCubicZeros(a, b, c, &p, &q, &r);
- ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
- EXPECT_NEAR(a, aa, 1e-10);
- EXPECT_NEAR(b, bb, 1e-10);
- EXPECT_NEAR(c, cc, 1e-10);
-
- a = 0; b = 1; c = 3;
- CoeffsForCubicZeros(a, b, c, &p, &q, &r);
- ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
- EXPECT_NEAR(a, aa, 1e-10);
- EXPECT_NEAR(b, bb, 1e-10);
- EXPECT_NEAR(c, cc, 1e-10);
-
- a = -10; b = 0; c = 1;
- CoeffsForCubicZeros(a, b, c, &p, &q, &r);
- ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
- EXPECT_NEAR(a, aa, 1e-10);
- EXPECT_NEAR(b, bb, 1e-10);
- EXPECT_NEAR(c, cc, 1e-10);
-
- a = -8; b = 1; c = 3;
- CoeffsForCubicZeros(a, b, c, &p, &q, &r);
- ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
- EXPECT_NEAR(a, aa, 1e-10);
- EXPECT_NEAR(b, bb, 1e-10);
- EXPECT_NEAR(c, cc, 1e-10);
-
- a = 28; b = 28; c = 105;
- CoeffsForCubicZeros(a, b, c, &p, &q, &r);
- ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
- EXPECT_NEAR(a, aa, 1e-10);
- EXPECT_NEAR(b, bb, 1e-10);
- EXPECT_NEAR(c, cc, 1e-10);
-}
-} // namespace
diff --git a/extern/libmv/libmv/simple_pipeline/detect_test.cc b/extern/libmv/libmv/simple_pipeline/detect_test.cc
deleted file mode 100644
index fe57e3d04a2..00000000000
--- a/extern/libmv/libmv/simple_pipeline/detect_test.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (c) 2014 libmv authors.
-//
-// 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.
-
-#include "libmv/simple_pipeline/detect.h"
-
-#include "testing/testing.h"
-#include "libmv/logging/logging.h"
-
-namespace libmv {
-
-namespace {
-
-void PreformSinglePointTest(const DetectOptions &options) {
- // Prepare the image.
- FloatImage image(15, 15);
- image.fill(1.0);
- image(7, 7) = 0.0;
-
- // Run the detector.
- vector<Feature> detected_features;
- Detect(image, options, &detected_features);
-
- // Check detected features matches our expectations.
- EXPECT_EQ(1, detected_features.size());
- if (detected_features.size() == 1) {
- Feature &feature = detected_features[0];
- EXPECT_EQ(7, feature.x);
- EXPECT_EQ(7, feature.y);
- }
-}
-
-void PreformCheckerBoardTest(const DetectOptions &options) {
- // Prepare the image.
- FloatImage image(30, 30);
- for (int y = 0; y < image.Height(); ++y) {
- for (int x = 0; x < image.Width(); ++x) {
- image(y, x) = (x / 10 + y / 10) % 2 ? 1.0 : 0.0;
- }
- }
-
- // Run the detector.
- vector<Feature> detected_features;
- Detect(image, options, &detected_features);
-
- // Check detected features matches our expectations.
-
- // We expect here only corners of a center square to be
- // considered a feature points.
- EXPECT_EQ(4, detected_features.size());
-
- // We don't know which side of the corner detector will choose,
- // so what we're checking here is that detected feature is from
- // any side of the corner.
- //
- // This doesn't check whether there're multiple features which
- // are placed on different sides of the same corner. The way we
- // deal with this is requiring min_distance to be greater than 2px.
- for (int i = 0; i < detected_features.size(); ++i) {
- Feature &feature = detected_features[i];
- int rounded_x = ((feature.x + 1) / 10) * 10,
- rounded_y = ((feature.y + 1) / 10) * 10;
- EXPECT_LE(1, std::abs(feature.x - rounded_x));
- EXPECT_LE(1, std::abs(feature.y - rounded_y));
- }
-}
-
-void CheckExpectedFeatures(const vector<Feature> &detected_features,
- const vector<Feature> &expected_features) {
- EXPECT_EQ(expected_features.size(), detected_features.size());
-
- // That's unsafe to iterate over vectors when their lengths
- // doesn't match. And it doesn't make any sense actually since
- // the test will already be considered failed here.
- if (expected_features.size() != detected_features.size()) {
- return;
- }
-
- for (int i = 0; i < expected_features.size(); ++i) {
- const Feature &extected_feature = expected_features[i];
- bool found = false;
- for (int j = 0; j < detected_features.size(); ++j) {
- const Feature &detected_feature = detected_features[j];
- if (extected_feature.x == detected_feature.x &&
- extected_feature.y == detected_feature.y) {
- found = true;
- break;
- }
- }
- EXPECT_TRUE(found);
- }
-}
-
-void PreformSingleTriangleTest(const DetectOptions &options) {
- // Prepare the image.
- FloatImage image(15, 21);
- image.fill(1.0);
-
- int vertex_x = 10, vertex_y = 5;
- for (int i = 0; i < 6; ++i) {
- int current_x = vertex_x - i,
- current_y = vertex_y + i;
- for (int j = 0; j < i * 2 + 1; ++j, ++current_x) {
- image(current_y, current_x) = 0.0;
- }
- }
-
- // Run the detector.
- vector<Feature> detected_features;
- Detect(image, options, &detected_features);
-
- // Check detected features matches our expectations.
- vector<Feature> expected_features;
- expected_features.push_back(Feature(6, 10));
- expected_features.push_back(Feature(14, 10));
- expected_features.push_back(Feature(10, 6));
-
- CheckExpectedFeatures(detected_features, expected_features);
-}
-
-} // namespace
-
-#ifndef LIBMV_NO_FAST_DETECTOR
-TEST(Detect, FASTSinglePointTest) {
- DetectOptions options;
- options.type = DetectOptions::FAST;
- options.min_distance = 0;
- options.fast_min_trackness = 1;
-
- PreformSinglePointTest(options);
-}
-#endif // LIBMV_NO_FAST_DETECTOR
-
-#if 0
-// TODO(sergey): FAST doesn't detect checker board corners, but should it?
-TEST(Detect, FASTCheckerBoardTest) {
- DetectOptions options;
- options.type = DetectOptions::FAST;
- options.min_distance = 0;
- options.fast_min_trackness = 1;
-
- PreformCheckerBoardTest(options);
-}
-#endif
-
-#if 0
-// TODO(sergey): FAST doesn't detect triangle corners!
-TEST(Detect, FASTSingleTriangleTest) {
- DetectOptions options;
- options.type = DetectOptions::FAST;
- options.margin = 3;
- options.min_distance = 0;
- options.fast_min_trackness = 2;
-
- PreformSingleTriangleTest(options);
-}
-#endif
-
-#if 0
-// TODO(sergey): This doesn't actually detect single point,
-// but should it or it's expected that Moravec wouldn't consider
-// single point as feature?
-//
-// Uncomment this or remove as soon as we know answer for the
-// question.
-TEST(Detect, MoravecSinglePointTest) {
- DetectOptions options;
- options.type = DetectOptions::MORAVEC;
- options.min_distance = 0;
- options.moravec_max_count = 10;
-
- PreformSinglePointTest(options);
-}
-
-// TODO(sergey): Moravec doesn't detect checker board corners, but should it?
-TEST(Detect, MoravecCheckerBoardTest) {
- DetectOptions options;
- options.type = DetectOptions::MORAVEC;
- options.min_distance = 0;
- options.moravec_max_count = 10;
-
- PreformCheckerBoardTest(options);
-}
-#endif
-
-TEST(Detect, HarrisSinglePointTest) {
- DetectOptions options;
- options.type = DetectOptions::HARRIS;
-
- // Set this to non-zero so image corners are not considered
- // a feature points and avoid center point neighbors to be
- // considered a features as well.
- options.margin = 3;
- options.min_distance = 3;
-
- PreformSinglePointTest(options);
-}
-
-TEST(Detect, HarrisSingleTriangleTest) {
- DetectOptions options;
- options.type = DetectOptions::HARRIS;
-
- options.margin = 3;
- options.min_distance = 2;
- options.harris_threshold = 1e-3;
-
- PreformSingleTriangleTest(options);
-}
-
-// TODO(sergey): Add tests for margin option.
-
-// TODO(sergey): Add tests for min_distance option.
-
-} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc
deleted file mode 100644
index caccce68cbe..00000000000
--- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) 2012 libmv authors.
-//
-// 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.
-
-#include "libmv/simple_pipeline/modal_solver.h"
-
-#include <cstdio>
-
-#include "ceres/ceres.h"
-#include "ceres/rotation.h"
-#include "libmv/logging/logging.h"
-#include "libmv/multiview/panography.h"
-
-#ifdef _MSC_VER
-# define snprintf _snprintf
-#endif
-
-namespace libmv {
-
-namespace {
-void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) {
- X(0) = marker.x;
- X(1) = marker.y;
- X(2) = 1.0;
-
- X *= 5.0 / X.norm();
-}
-
-void ModalSolverLogProress(ProgressUpdateCallback *update_callback,
- double progress) {
- if (update_callback) {
- char message[256];
-
- snprintf(message, sizeof(message), "Solving progress %d%%",
- (int)(progress * 100));
-
- update_callback->invoke(progress, message);
- }
-}
-
-struct ModalReprojectionError {
- ModalReprojectionError(double observed_x,
- double observed_y,
- const double weight,
- const Vec3 &bundle)
- : observed_x_(observed_x), observed_y_(observed_y),
- weight_(weight), bundle_(bundle) { }
-
- template <typename T>
- bool operator()(const T* quaternion, // Rotation quaternion
- T* residuals) const {
- T R[9];
- ceres::QuaternionToRotation(quaternion, R);
-
- // Convert bundle position from double to T.
- T X[3];
- X[0] = T(bundle_(0));
- X[1] = T(bundle_(1));
- X[2] = T(bundle_(2));
-
- // Compute projective coordinates: x = RX.
- T x[3];
- x[0] = R[0]*X[0] + R[3]*X[1] + R[6]*X[2];
- x[1] = R[1]*X[0] + R[4]*X[1] + R[7]*X[2];
- x[2] = R[2]*X[0] + R[5]*X[1] + R[8]*X[2];
-
- // Compute normalized coordinates: x /= x[2].
- T xn = x[0] / x[2];
- T yn = x[1] / x[2];
-
- // The error is the difference between reprojected
- // and observed marker position.
- residuals[0] = xn - T(observed_x_);
- residuals[1] = yn - T(observed_y_);
-
- return true;
- }
-
- double observed_x_;
- double observed_y_;
- double weight_;
- Vec3 bundle_;
-};
-} // namespace
-
-void ModalSolver(const Tracks &tracks,
- EuclideanReconstruction *reconstruction,
- ProgressUpdateCallback *update_callback) {
- int max_image = tracks.MaxImage();
- int max_track = tracks.MaxTrack();
-
- LG << "Max image: " << max_image;
- LG << "Max track: " << max_track;
-
- // For minimization we're using quaternions.
- Vec3 zero_rotation = Vec3::Zero();
- Vec4 quaternion;
- ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0));
-
- for (int image = 0; image <= max_image; ++image) {
- vector<Marker> all_markers = tracks.MarkersInImage(image);
-
- ModalSolverLogProress(update_callback, (float) image / max_image);
-
- // Skip empty images without doing anything.
- if (all_markers.size() == 0) {
- LG << "Skipping image: " << image;
- continue;
- }
-
- // STEP 1: Estimate rotation analytically.
- Mat3 current_R;
- ceres::QuaternionToRotation(&quaternion(0), &current_R(0, 0));
-
- // Construct point cloud for current and previous images,
- // using markers appear at current image for which we know
- // 3D positions.
- Mat x1, x2;
- for (int i = 0; i < all_markers.size(); ++i) {
- Marker &marker = all_markers[i];
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
- if (point) {
- Vec3 X;
- ProjectMarkerOnSphere(marker, X);
-
- int last_column = x1.cols();
- x1.conservativeResize(3, last_column + 1);
- x2.conservativeResize(3, last_column + 1);
-
- x1.col(last_column) = current_R * point->X;
- x2.col(last_column) = X;
- }
- }
-
- if (x1.cols() >= 2) {
- Mat3 delta_R;
-
- // Compute delta rotation matrix for two point clouds.
- // Could be a bit confusing at first glance, but order
- // of clouds is indeed so.
- GetR_FixedCameraCenter(x2, x1, 1.0, &delta_R);
-
- // Convert delta rotation form matrix to final image
- // rotation stored in a quaternion
- Vec3 delta_angle_axis;
- ceres::RotationMatrixToAngleAxis(&delta_R(0, 0), &delta_angle_axis(0));
-
- Vec3 current_angle_axis;
- ceres::QuaternionToAngleAxis(&quaternion(0), &current_angle_axis(0));
-
- Vec3 angle_axis = current_angle_axis + delta_angle_axis;
-
- ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0));
-
- LG << "Analytically computed quaternion "
- << quaternion.transpose();
- }
-
- // STEP 2: Refine rotation with Ceres.
- ceres::Problem problem;
-
- ceres::LocalParameterization* quaternion_parameterization =
- new ceres::QuaternionParameterization;
-
- int num_residuals = 0;
- for (int i = 0; i < all_markers.size(); ++i) {
- Marker &marker = all_markers[i];
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
-
- if (point && marker.weight != 0.0) {
- problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
- ModalReprojectionError,
- 2, /* num_residuals */
- 4>(new ModalReprojectionError(marker.x,
- marker.y,
- marker.weight,
- point->X)),
- NULL,
- &quaternion(0));
- num_residuals++;
-
- problem.SetParameterization(&quaternion(0),
- quaternion_parameterization);
- }
- }
-
- LG << "Number of residuals: " << num_residuals;
-
- if (num_residuals) {
- // Configure the solve.
- ceres::Solver::Options solver_options;
- solver_options.linear_solver_type = ceres::DENSE_QR;
- solver_options.max_num_iterations = 50;
- solver_options.update_state_every_iteration = true;
- solver_options.gradient_tolerance = 1e-36;
- solver_options.parameter_tolerance = 1e-36;
- solver_options.function_tolerance = 1e-36;
-
- // Run the solve.
- ceres::Solver::Summary summary;
- ceres::Solve(solver_options, &problem, &summary);
-
- LG << "Summary:\n" << summary.FullReport();
- LG << "Refined quaternion " << quaternion.transpose();
- }
-
- // Convert quaternion to rotation matrix.
- Mat3 R;
- ceres::QuaternionToRotation(&quaternion(0), &R(0, 0));
- reconstruction->InsertCamera(image, R, Vec3::Zero());
-
- // STEP 3: reproject all new markers appeared at image
-
- // Check if there're new markers appeared on current image
- // and reproject them on sphere to obtain 3D position/
- for (int track = 0; track <= max_track; ++track) {
- if (!reconstruction->PointForTrack(track)) {
- Marker marker = tracks.MarkerInImageForTrack(image, track);
-
- if (marker.image == image) {
- // New track appeared on this image,
- // project it's position onto sphere.
-
- LG << "Projecting track " << track << " at image " << image;
-
- Vec3 X;
- ProjectMarkerOnSphere(marker, X);
- reconstruction->InsertPoint(track, R.inverse() * X);
- }
- }
- }
- }
-}
-
-} // namespace libmv
diff --git a/extern/libmv/mkfiles.sh b/extern/libmv/mkfiles.sh
deleted file mode 100755
index c7c8c33f725..00000000000
--- a/extern/libmv/mkfiles.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-find ./libmv/ -type f | sed -r 's/^\.\///' | sort > files.txt
-find ./third_party/ -mindepth 2 -type f | grep -v third_party/ceres | sed -r 's/^\.\///' | sort >> files.txt
diff --git a/extern/libmv/third_party/CMakeLists.txt b/extern/libmv/third_party/CMakeLists.txt
deleted file mode 100644
index 6212fe480b1..00000000000
--- a/extern/libmv/third_party/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-
-add_subdirectory(ceres)
diff --git a/extern/libmv/third_party/SConscript b/extern/libmv/third_party/SConscript
deleted file mode 100644
index b05692e385f..00000000000
--- a/extern/libmv/third_party/SConscript
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/python
-
-SConscript(['ceres/SConscript'])
diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt
deleted file mode 100644
index 694982ec606..00000000000
--- a/extern/libmv/third_party/ceres/CMakeLists.txt
+++ /dev/null
@@ -1,359 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2012, Blender Foundation
-# All rights reserved.
-#
-# Contributor(s): Blender Foundation,
-# Sergey Sharybin
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-set(INC
- .
- include
- internal
- config
- ../gflags
- ../../
-)
-
-set(INC_SYS
- ${EIGEN3_INCLUDE_DIRS}
-)
-
-set(SRC
- internal/ceres/array_utils.cc
- internal/ceres/blas.cc
- internal/ceres/block_evaluate_preparer.cc
- internal/ceres/block_jacobian_writer.cc
- internal/ceres/block_jacobi_preconditioner.cc
- internal/ceres/block_random_access_dense_matrix.cc
- internal/ceres/block_random_access_diagonal_matrix.cc
- internal/ceres/block_random_access_matrix.cc
- internal/ceres/block_random_access_sparse_matrix.cc
- internal/ceres/block_sparse_matrix.cc
- internal/ceres/block_structure.cc
- internal/ceres/callbacks.cc
- internal/ceres/canonical_views_clustering.cc
- internal/ceres/c_api.cc
- internal/ceres/cgnr_solver.cc
- internal/ceres/compressed_col_sparse_matrix_utils.cc
- internal/ceres/compressed_row_jacobian_writer.cc
- internal/ceres/compressed_row_sparse_matrix.cc
- internal/ceres/conditioned_cost_function.cc
- internal/ceres/conjugate_gradients_solver.cc
- internal/ceres/coordinate_descent_minimizer.cc
- internal/ceres/corrector.cc
- internal/ceres/covariance.cc
- internal/ceres/covariance_impl.cc
- internal/ceres/cxsparse.cc
- internal/ceres/dense_normal_cholesky_solver.cc
- internal/ceres/dense_qr_solver.cc
- internal/ceres/dense_sparse_matrix.cc
- internal/ceres/detect_structure.cc
- internal/ceres/dogleg_strategy.cc
- internal/ceres/dynamic_compressed_row_jacobian_writer.cc
- internal/ceres/dynamic_compressed_row_sparse_matrix.cc
- internal/ceres/evaluator.cc
- internal/ceres/file.cc
- internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
- internal/ceres/generated/schur_eliminator_d_d_d.cc
- internal/ceres/gradient_checking_cost_function.cc
- internal/ceres/gradient_problem.cc
- internal/ceres/gradient_problem_solver.cc
- internal/ceres/implicit_schur_complement.cc
- internal/ceres/incomplete_lq_factorization.cc
- internal/ceres/iterative_schur_complement_solver.cc
- internal/ceres/lapack.cc
- internal/ceres/levenberg_marquardt_strategy.cc
- internal/ceres/linear_least_squares_problems.cc
- internal/ceres/linear_operator.cc
- internal/ceres/linear_solver.cc
- internal/ceres/line_search.cc
- internal/ceres/line_search_direction.cc
- internal/ceres/line_search_minimizer.cc
- internal/ceres/line_search_preprocessor.cc
- internal/ceres/local_parameterization.cc
- internal/ceres/loss_function.cc
- internal/ceres/low_rank_inverse_hessian.cc
- internal/ceres/minimizer.cc
- internal/ceres/normal_prior.cc
- internal/ceres/parameter_block_ordering.cc
- internal/ceres/partitioned_matrix_view.cc
- internal/ceres/polynomial.cc
- internal/ceres/preconditioner.cc
- internal/ceres/preprocessor.cc
- internal/ceres/problem.cc
- internal/ceres/problem_impl.cc
- internal/ceres/program.cc
- internal/ceres/reorder_program.cc
- internal/ceres/residual_block.cc
- internal/ceres/residual_block_utils.cc
- internal/ceres/schur_complement_solver.cc
- internal/ceres/schur_eliminator.cc
- internal/ceres/schur_jacobi_preconditioner.cc
- internal/ceres/scratch_evaluate_preparer.cc
- internal/ceres/single_linkage_clustering.cc
- internal/ceres/solver.cc
- internal/ceres/solver_utils.cc
- internal/ceres/sparse_matrix.cc
- internal/ceres/sparse_normal_cholesky_solver.cc
- internal/ceres/split.cc
- internal/ceres/stringprintf.cc
- internal/ceres/suitesparse.cc
- internal/ceres/triplet_sparse_matrix.cc
- internal/ceres/trust_region_minimizer.cc
- internal/ceres/trust_region_preprocessor.cc
- internal/ceres/trust_region_strategy.cc
- internal/ceres/types.cc
- internal/ceres/visibility_based_preconditioner.cc
- internal/ceres/visibility.cc
- internal/ceres/wall_time.cc
-
- include/ceres/autodiff_cost_function.h
- include/ceres/autodiff_local_parameterization.h
- include/ceres/c_api.h
- include/ceres/ceres.h
- include/ceres/conditioned_cost_function.h
- include/ceres/cost_function.h
- include/ceres/cost_function_to_functor.h
- include/ceres/covariance.h
- include/ceres/crs_matrix.h
- include/ceres/dynamic_autodiff_cost_function.h
- include/ceres/dynamic_numeric_diff_cost_function.h
- include/ceres/fpclassify.h
- include/ceres/gradient_checker.h
- include/ceres/gradient_problem.h
- include/ceres/gradient_problem_solver.h
- include/ceres/internal/autodiff.h
- include/ceres/internal/disable_warnings.h
- include/ceres/internal/eigen.h
- include/ceres/internal/fixed_array.h
- include/ceres/internal/macros.h
- include/ceres/internal/manual_constructor.h
- include/ceres/internal/numeric_diff.h
- include/ceres/internal/port.h
- include/ceres/internal/reenable_warnings.h
- include/ceres/internal/scoped_ptr.h
- include/ceres/internal/variadic_evaluate.h
- include/ceres/iteration_callback.h
- include/ceres/jet.h
- include/ceres/local_parameterization.h
- include/ceres/loss_function.h
- include/ceres/normal_prior.h
- include/ceres/numeric_diff_cost_function.h
- include/ceres/ordered_groups.h
- include/ceres/problem.h
- include/ceres/rotation.h
- include/ceres/sized_cost_function.h
- include/ceres/solver.h
- include/ceres/types.h
- include/ceres/version.h
- internal/ceres/array_utils.h
- internal/ceres/blas.h
- internal/ceres/block_evaluate_preparer.h
- internal/ceres/block_jacobian_writer.h
- internal/ceres/block_jacobi_preconditioner.h
- internal/ceres/block_random_access_dense_matrix.h
- internal/ceres/block_random_access_diagonal_matrix.h
- internal/ceres/block_random_access_matrix.h
- internal/ceres/block_random_access_sparse_matrix.h
- internal/ceres/block_sparse_matrix.h
- internal/ceres/block_structure.h
- internal/ceres/callbacks.h
- internal/ceres/canonical_views_clustering.h
- internal/ceres/casts.h
- internal/ceres/cgnr_linear_operator.h
- internal/ceres/cgnr_solver.h
- internal/ceres/collections_port.h
- internal/ceres/compressed_col_sparse_matrix_utils.h
- internal/ceres/compressed_row_jacobian_writer.h
- internal/ceres/compressed_row_sparse_matrix.h
- internal/ceres/conjugate_gradients_solver.h
- internal/ceres/coordinate_descent_minimizer.h
- internal/ceres/corrector.h
- internal/ceres/covariance_impl.h
- internal/ceres/cxsparse.h
- internal/ceres/dense_jacobian_writer.h
- internal/ceres/dense_normal_cholesky_solver.h
- internal/ceres/dense_qr_solver.h
- internal/ceres/dense_sparse_matrix.h
- internal/ceres/detect_structure.h
- internal/ceres/dogleg_strategy.h
- internal/ceres/dynamic_compressed_row_finalizer.h
- internal/ceres/dynamic_compressed_row_jacobian_writer.h
- internal/ceres/dynamic_compressed_row_sparse_matrix.h
- internal/ceres/evaluator.h
- internal/ceres/execution_summary.h
- internal/ceres/file.h
- internal/ceres/gradient_checking_cost_function.h
- internal/ceres/gradient_problem_evaluator.h
- internal/ceres/graph_algorithms.h
- internal/ceres/graph.h
- internal/ceres/implicit_schur_complement.h
- internal/ceres/incomplete_lq_factorization.h
- internal/ceres/integral_types.h
- internal/ceres/iterative_schur_complement_solver.h
- internal/ceres/lapack.h
- internal/ceres/levenberg_marquardt_strategy.h
- internal/ceres/linear_least_squares_problems.h
- internal/ceres/linear_operator.h
- internal/ceres/linear_solver.h
- internal/ceres/line_search_direction.h
- internal/ceres/line_search.h
- internal/ceres/line_search_minimizer.h
- internal/ceres/line_search_preprocessor.h
- internal/ceres/low_rank_inverse_hessian.h
- internal/ceres/map_util.h
- internal/ceres/minimizer.h
- internal/ceres/mutex.h
- internal/ceres/parameter_block.h
- internal/ceres/parameter_block_ordering.h
- internal/ceres/partitioned_matrix_view.h
- internal/ceres/partitioned_matrix_view_impl.h
- internal/ceres/polynomial.h
- internal/ceres/preconditioner.h
- internal/ceres/preprocessor.h
- internal/ceres/problem_impl.h
- internal/ceres/program_evaluator.h
- internal/ceres/program.h
- internal/ceres/random.h
- internal/ceres/reorder_program.h
- internal/ceres/residual_block.h
- internal/ceres/residual_block_utils.h
- internal/ceres/schur_complement_solver.h
- internal/ceres/schur_eliminator.h
- internal/ceres/schur_eliminator_impl.h
- internal/ceres/schur_jacobi_preconditioner.h
- internal/ceres/scratch_evaluate_preparer.h
- internal/ceres/single_linkage_clustering.h
- internal/ceres/small_blas.h
- internal/ceres/solver_utils.h
- internal/ceres/sparse_matrix.h
- internal/ceres/sparse_normal_cholesky_solver.h
- internal/ceres/split.h
- internal/ceres/stl_util.h
- internal/ceres/stringprintf.h
- internal/ceres/suitesparse.h
- internal/ceres/triplet_sparse_matrix.h
- internal/ceres/trust_region_minimizer.h
- internal/ceres/trust_region_preprocessor.h
- internal/ceres/trust_region_strategy.h
- internal/ceres/visibility_based_preconditioner.h
- internal/ceres/visibility.h
- internal/ceres/wall_time.h
-)
-
-if(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
- list(APPEND SRC
- internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
- internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
- internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
- internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
- internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
- internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
- internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
- internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
- internal/ceres/generated/schur_eliminator_2_2_2.cc
- internal/ceres/generated/schur_eliminator_2_2_3.cc
- internal/ceres/generated/schur_eliminator_2_2_4.cc
- internal/ceres/generated/schur_eliminator_2_2_d.cc
- internal/ceres/generated/schur_eliminator_2_3_3.cc
- internal/ceres/generated/schur_eliminator_2_3_4.cc
- internal/ceres/generated/schur_eliminator_2_3_9.cc
- internal/ceres/generated/schur_eliminator_2_3_d.cc
- internal/ceres/generated/schur_eliminator_2_4_3.cc
- internal/ceres/generated/schur_eliminator_2_4_4.cc
- internal/ceres/generated/schur_eliminator_2_4_8.cc
- internal/ceres/generated/schur_eliminator_2_4_9.cc
- internal/ceres/generated/schur_eliminator_2_4_d.cc
- internal/ceres/generated/schur_eliminator_2_d_d.cc
- internal/ceres/generated/schur_eliminator_4_4_2.cc
- internal/ceres/generated/schur_eliminator_4_4_3.cc
- internal/ceres/generated/schur_eliminator_4_4_4.cc
- internal/ceres/generated/schur_eliminator_4_4_d.cc
- )
-else()
- add_definitions(-DCERES_RESTRICT_SCHUR_SPECIALIZATION)
-endif()
-
-if(WIN32)
- list(APPEND INC
- ../glog/src/windows
- )
-
- if(NOT MINGW)
- list(APPEND INC
- ../msinttypes
- )
- endif()
-else()
- list(APPEND INC
- ../glog/src
- )
-endif()
-
-add_definitions(
- -DCERES_HAVE_PTHREAD
- -DCERES_NO_SUITESPARSE
- -DCERES_NO_CXSPARSE
- -DCERES_NO_LAPACK
- -DCERES_HAVE_RWLOCK
-)
-
-if(WITH_OPENMP)
- add_definitions(
- -DCERES_USE_OPENMP
- )
-endif()
-
-TEST_UNORDERED_MAP_SUPPORT()
-if(HAVE_STD_UNORDERED_MAP_HEADER)
- if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
- add_definitions(-DCERES_STD_UNORDERED_MAP)
- else()
- if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
- add_definitions(-DCERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
- else()
- add_definitions(-DCERES_NO_UNORDERED_MAP)
- message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
- endif()
- endif()
-else()
- if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
- add_definitions(-DCERES_TR1_UNORDERED_MAP)
- else()
- add_definitions(-DCERES_NO_UNORDERED_MAP)
- message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
- endif()
-endif()
-
-blender_add_lib(extern_ceres "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libmv/third_party/ceres/ChangeLog b/extern/libmv/third_party/ceres/ChangeLog
deleted file mode 100644
index b4f78ee0731..00000000000
--- a/extern/libmv/third_party/ceres/ChangeLog
+++ /dev/null
@@ -1,673 +0,0 @@
-commit 0435246de5f45e69b2c97d244ed61bedd340215a
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Oct 8 18:12:53 2014 -0700
-
- Add seene to users.rst
-
- Change-Id: If40726775a3d4b234b6e10517fe9943d122a3384
-
-commit fdf32b315f39553639f0becf078ad4eec763a10e
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Oct 8 16:04:32 2014 -0700
-
- Fix some errant tabs.
-
- Change-Id: Iaf1906eaade49467ba282656cf0a10879d258b1f
-
-commit 6768b3586a027bb850c0a50e2a27380f5d80142a
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Oct 8 12:48:16 2014 -0700
-
- Minor cleanups in preparation for a release.
-
- 1. Fix the release script to ignore the version.h checking.
- 2. Fix some ceres documentation formatting errors.
-
- Change-Id: I3fd6b85e771b242f463d6a36c3efd8d691f9242f
-
-commit 7b6bd1cd31aa0b8cb7fb97600c1b9999846e3152
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Oct 2 16:16:26 2014 -0700
-
- Documentation update.
-
- 1. Complete restructuring of the documentation to account for
- GradientProblemSolver.
- 2. Update the version history to account for changes since 1.9.0.
- 3. Add links and document the various examples that ship with ceres.
- 4. Documentation for GradientProblem GradientProblemSolver.
-
- Change-Id: If3a18f2850cbc98be1bc34435e9ea468785b8b27
-
-commit b7d321f505e936b6c09aeb43ae3f7b1252388a95
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Oct 3 15:47:59 2014 -0700
-
- Relax the warning/error handing in GCC.
-
- Thanks to Matthew Woehlke for suggesting this.
-
- Change-Id: Iae754465c086b0841a7816df1a36781371d0dc9a
-
-commit 94c6e7d27b5d48d81ab54ed9cdcbc55c3c099311
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Oct 1 15:55:13 2014 -0700
-
- Improve multithreading when using inner iterations.
-
- Inner iterations by default would use problems where the evaluator
- was configured to use exactly one thread for doing the evaluation.
- This is fine when there are multiple inner iteration problems
- being executed concurrently, but every now and then there are
- problem decompositions where there is just one parameter block
- in the current independent set and it touches every single
- residual block. In such cases it is essential that the evaluator
- be configured to use multiple threads.
-
- We now pay attention to the size of the independent set and
- dynamically configure the number of threads being used by the
- outer loop and the evaluator loop.
-
- Thanks to William Rucklidge for reporting this issue and providing
- a test problem to debug.
-
- Change-Id: Iaff9a4ab6d2658cf7b61ea213575d23aab604e3b
-
-commit 9e11cd16d09403b9270e621e839d5948b6a74b8d
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Sep 29 14:27:58 2014 -0700
-
- Faster BlockRandomAccessSparseMatrix::SymmetricRightMultiply.
-
- Trade a small amount of memory to improve the cache coherency of
- the SymmetricRightMultiply operation.
-
- The resulting code leads to a 10-20% speedup in the linear solver
- end to end.
-
- Change-Id: I8ab2fe152099e849b211b5b19e4ef9f03d8e7f1c
-
-commit 46b8461fd010c1e7ffce6bb2bdf8a84b659d5e09
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Sep 29 15:10:58 2014 -0700
-
- Various minor fixes from William Rucklidge.
-
- Change-Id: Ibe731d5db374ad8ee148d62a9fdd8d726b607a3f
-
-commit b44cfdef25f6bf0917a23b3fd65cce38aa6a3362
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Sep 29 07:53:54 2014 -0700
-
- Let ITERATIVE_SCHUR use an explicit Schur Complement matrix.
-
- Up till now ITERATIVE_SCHUR evaluates matrix-vector products
- between the Schur complement and a vector implicitly by exploiting
- the algebraic expression for the Schur complement.
-
- This cost of this evaluation scales with the number of non-zeros
- in the Jacobian.
-
- For small to medium sized problems there is a sweet spot where
- computing the Schur complement is cheap enough that it is much
- more efficient to explicitly compute it and use it for evaluating
- the matrix-vector products.
-
- This changes implements support for an explicit Schur complement
- in ITERATIVE_SCHUR in combination with the SCHUR_JACOBI preconditioner.
-
- API wise a new bool Solver::Options::use_explicit_schur_complement
- has been added.
-
- The implementation extends the SparseSchurComplementSolver to use
- Conjugate Gradients.
-
- Example speedup:
-
- use_explicit_schur_complement = false
-
- Time (in seconds):
- Preprocessor 0.585
-
- Residual evaluation 0.319
- Jacobian evaluation 1.590
- Linear solver 25.685
- Minimizer 27.990
-
- Postprocessor 0.010
- Total 28.585
-
- use_explicit_schur_complement = true
-
- Time (in seconds):
- Preprocessor 0.638
-
- Residual evaluation 0.318
- Jacobian evaluation 1.507
- Linear solver 5.930
- Minimizer 8.144
-
- Postprocessor 0.010
- Total 8.791
-
- Which indicates an end-to-end speedup of more than 3x, with the linear
- solver being sped up by > 4x.
-
- The idea to explore this optimization was inspired by the recent paper:
-
- Mining structure fragments for smart bundle adjustment
- L. Carlone, P. Alcantarilla, H. Chiu, K. Zsolt, F. Dellaert
- British Machine Vision Conference, 2014
-
- which uses a more complicated algorithm to compute parts of the
- Schur complement to speed up the matrix-vector product.
-
- Change-Id: I95324af0ab351faa1600f5204039a1d2a64ae61d
-
-commit 4ad91490827f2ebebcc70d17e63ef653bf06fd0d
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Sep 24 23:54:18 2014 -0700
-
- Simplify the Block Jacobi and Schur Jacobi preconditioners.
-
- 1. Extend the implementation of BlockRandomAccessDiagonalMatrix
- by adding Invert and RightMultiply methods.
-
- 2. Simplify the implementation of the Schur Jacobi preconditioner
- using these new methods.
-
- 3. Replace the custom storage used inside Block Jacobi preconditioner
- with BlockRandomAccessDiagonalMatrix and simplify its implementation
- too.
-
- Change-Id: I9d4888b35f0f228c08244abbdda5298b3ce9c466
-
-commit 8f7be1036b853addc33224d97b92412b5a1281b6
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Sep 29 08:13:35 2014 -0700
-
- Fix a formatting error TrustRegionMinimizer logging.
-
- Change-Id: Iad1873c51eece46c3fdee1356d154367cfd7925e
-
-commit c99872d48e322662ea19efb9010a62b7432687ae
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Sep 24 21:30:02 2014 -0700
-
- Add BlockRandomAccessSparseMatrix::SymmetricRightMultiply.
-
- Change-Id: Ib06a22a209b4c985ba218162dfb6bf46bd93169e
-
-commit d3ecd18625ba260e0d00912a305a448b566acc59
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Sep 23 10:12:42 2014 -0700
-
- Add an explicit include for local_parameterization.h
-
- Thanks to cooordz for reporting this.
-
- Change-Id: I7d345404e362a94ff1eb433ad6b9dcc4960ba76d
-
-commit 5dd76869cf45122c79579423f09e0de08cf04092
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Fri Sep 19 16:08:25 2014 +0100
-
- Fix unused-function warning with Eigen < 3.2.2.
-
- - CreateBlockJacobian() is only ever used when Eigen >= 3.2.2 is
- detected, but was previously defined whenever CERES_USE_EIGEN_SPARSE
- was defined with no check on the Eigen version.
- - This resulted in an unused-function compile warning that became an
- error due to -Werror, preventing compilation when using Eigen < 3.2.2.
-
- Change-Id: I24628ff329f14b087ece66bf2626bdc0de4ba224
-
-commit 820cb7b14831aa03eca1e8186000cebfdf0a42f3
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Sep 17 09:46:08 2014 -0700
-
- Add solver_utils.cc to Android.mk
-
- Change-Id: I358522971711280f4362a1fa39b1568160e21e63
-
-commit 092b94970a073f8b47179d96160226fc19095898
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Sep 5 11:56:29 2014 -0700
-
- Add GradientProblem and GradientProblemSolver.
-
- The line search minimizer in Ceres does not require that the
- problems that is solving is a sum of squares. Over the past
- year there have been multiple requests to expose this algorithm
- on its own so that it can be used to solve unconstrained
- non-linear minimization problems on its own.
-
- With this change, a new optimization problem called
- GradientProblem is introduced which is basically a thin
- wrapper around a user defined functor that evaluates cost
- and gradients (FirstOrderFunction) and an optional LocalParameterization.
-
- Corresponding to it, a GradientProblemSolver and its associated
- options and summary structs are introduced too.
-
- An example that uses the new API to find the minimum of Rosenbrock's
- function is also added.
-
- Change-Id: I42bf687540da25de991e9bdb00e321239244e8b4
-
-commit 6c45d6b891aac01489b478a021f99081c61792cb
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Sep 11 07:48:30 2014 -0700
-
- Add more inspection methods to Problem.
-
- Problem::GetCostFunctionForResidualBlock
- Problem::GetLossFunctionForResidualBlock
-
- are added, so that users do not have to maintain this mapping
- outside the Problem.
-
- Change-Id: I38356dfa094b2c7eec90651dafeaf3a33c5f5f56
-
-commit 6ad9b8e2ae66c9009441d0f9304486ec8dfa9a6a
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Sep 9 14:29:28 2014 -0700
-
- Ignore row/column blocks structure when using dynamic sparsity
-
- The row/column blocks can be huge when using dynamic sparsity. This
- can result in very large memory usage when augmenting the jacobian
- with the LM diagonal.
-
- Thanks to Mingsong Dou for reporting this.
-
- Change-Id: I6aa140ceefa98389ae17958f89ca76e0c76f95b8
-
-commit 7e43460d42e20be1ba13121655dbbfd0d1c751ae
-Author: Martin Baeuml <baeuml@gmail.com>
-Date: Mon Sep 8 16:49:06 2014 +0200
-
- Fix a few typos in the documentation.
-
- Change-Id: I541db56b2b81ae758e233ce850d78c3cbb4b6fa3
-
-commit 1aef66eeae7042902655a11b0d6a1a32900abb7b
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Sep 7 21:18:44 2014 -0700
-
- Remove errant space.
-
- Change-Id: Iedc06960417a9b938d57f623b4beb87a98e3d081
-
-commit 89080ab153a33008782759187fa8e9af7d2f83f1
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Sep 6 21:13:48 2014 -0700
-
- Add LocalParameterization::MultiplyByJacobian.
-
- This is needed to efficiently support LocalParameterization objects
- in GradientProblemSolver.
-
- Change-Id: Ic7b715b8be694b099dc95d6707a67474297533e6
-
-commit d76da16f49d419ae3664ca1bdc2286c1ea78ebed
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Sep 7 18:42:49 2014 -0700
-
- Move some routines to solver_utils.h/cc
-
- This moves a couple of routines from solver.cc into solver_utils.h/cc
- so that they can also be used by the upcoming GradientProblemSolver.
-
- Change-Id: I627b32ad3dc639422aacde78a8e391459d947e99
-
-commit cbf03ac292a0c0e9e6b7fcc1b08b67e95965922f
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Sep 6 21:07:08 2014 -0700
-
- Make LineSearchMinimizer consistent with TrustRegionMinimizer.
-
- Change the logic for how IterationSummary objects are added to
- Summary::iterations to match the one in TrustRegionMinimizer.
-
- Change-Id: I57851ad8294e58f83b9115cca9c24695d86ee92a
-
-commit f04c32319751e1efd610acd3699bca0a6dd6c6d1
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Sep 6 21:05:41 2014 -0700
-
- Fix some obsolete documentation in CostFunction::Evaluate
-
- Change-Id: I1d7ee5c596fbf6a4d886dce5b989c8eb18af2dce
-
-commit 9263547c02a1807532b159c217e7acd124d3db10
-Author: Johannes Schönberger <hannesschoenberger@gmail.com>
-Date: Sat Sep 6 17:26:15 2014 -0400
-
- Fix CG solver options for ITERATIVE_SCHUR, which did not copy min_num_iterations
-
- Change-Id: If31bc53b49ec20426fd438b79b8fa1f69d11e861
-
-commit b41f048256d1a8184cbe874b5a96dffa7fa4630d
-Author: Martin Baeuml <baeuml@gmail.com>
-Date: Fri Sep 5 15:03:32 2014 +0200
-
- Remove obsolete include of numeric_diff_functor.h.
-
- numeric_diff_functor.h was removed and does not exist anymore.
-
- Change-Id: I07bf04bf81142551e867b95b83a0653e11cad54c
-
-commit b7fb6056a717cc3c372cfb7115c527ee8bc05ddb
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Sep 3 11:19:02 2014 -0700
-
- Remove NumericDiffFunctor.
-
- Its API was broken, and its implementation was an unnecessary
- layer of abstraction over CostFunctionToFunctor.
-
- Change-Id: I18fc261fc6a3620b51a9eeb4dde0af03d753af69
-
-commit 175fa8ff09049110a8509409f60cee5fd52cdbe6
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Sep 2 06:49:08 2014 -0700
-
- CostFunctionToFunctor allows dynamic number of residuals.
-
- The code itself was perfectly capable of handling residuals, but there
- was an overly strict runtime check that had to be removed.
-
- Thanks to Domink Reitzle for reporting this.
-
- Change-Id: I6a6d000a7c5203dd5945a61b4caeda1b8aeb09c9
-
-commit 70ace0d5a5601901288974fcf27919754260cf0e
-Author: Johannes Schönberger <hannesschoenberger@gmail.com>
-Date: Sat Aug 30 15:52:34 2014 -0400
-
- Fix max. linear solver iterations in ConjugateGradientsSolver
-
- Change-Id: Ice0cef46441dbc1c121eeb42113667a46c96936f
-
-commit c5d8d0680250f5eb554577d30d28fc805b03fab9
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 29 20:31:19 2014 -0700
-
- Fix a unused function error with Eigen version 3.2.1 or less.
-
- Thanks to Johannes Schoenberger for reporting this.
-
- Change-Id: Ie17d28f2a68734a978a8c95007724bc4055de43a
-
-commit 0e1cc2a55488e4cf381833baaa3531c02ce9d69e
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 29 09:16:56 2014 -0700
-
- Fix the build on Eigen version 3.2.1 and older.
-
- Change-Id: I18f5cb5d42113737d7b8f78a67acee28bd5b3e08
-
-commit 5f96c62b56222f27e606f2246a8a16b6942af8d1
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 23:06:17 2014 -0700
-
- Add Block AMD ordering for SPARSE_SCHUR + EIGEN_SPARSE.
-
- Ordering routines for the Schur complement when using EIGEN_SPARSE.
- Also integration into SchurComplementSolver.
-
- Part of this CL is also a refactoring of the block jacobian matrix
- construction.
-
- Change-Id: I11d665cc7d4867c64190e6fed1118f4d2e13d59b
-
-commit 7344626c04d19ca1dc4871c377c4422c744b1bca
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 22:03:09 2014 -0700
-
- Let EIGEN_SPARSE + SPARSE_NORMAL_CHOLESKY use block AMD.
-
- Modify SparseNormalCholeskySolver to use a pre-ordered Jacobian
- matrix.
-
- Change-Id: Ib4d725d7a2d7bb94ea76dbb3a9b172784dbc8ea0
-
-commit 9f7032369ea4e432f0fb507cb6d2209741ee6946
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 21:46:43 2014 -0700
-
- Block AMD for SparseNormalCholesky + EIGEN_SPARSE.
-
- This is just the reordering routine. The integration with
- SparseNormalCholesky shall happen in a subsequent CL.
-
- Change-Id: I39ddc32aa66b11c368faf75404850fa0ae0d2b3a
-
-commit b9331cd4077100d645be22a912d5743eeda72878
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 14:42:27 2014 -0700
-
- Cleanup reorder_program.cc
-
- Program::SetParameterOffsetsAndIndex() was being called willy nilly.
- Now the invariant is that any function that actually reorders the
- program, updates the offsets and indices.
-
- Also the logic around handling EIGEN_SPARSE has been simplified in
- anticipation of the block AMD code that is forthcoming.
-
- Last but not the least, num_eliminate_blocks, which is a rather
- cryptic name to begin with has been replaced by the more meaningful
- size_of_first_elimination_group.
-
- Change-Id: I77e684f699a93b53e76aa406d64f40f8704df813
-
-commit 79491a3f4a3939a3cce4644da7a998b7782b963a
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 13:57:50 2014 -0700
-
- Solver::FullReport now reports build config.
-
- The header of Summary::FullReport now looks like
-
- Solver Summary (v 1.10.0-suitesparse-cxsparse-lapack-no_openmp)
-
- Original Reduced
- Parameter blocks 22122 22122
- Parameters 66462 66462
- Residual blocks 83718 83718
- Residual 167436 167436
-
- Change-Id: Id1b81bbf90ba412d19e2dd3687eeb9d372b72c1b
-
-commit 48068c753e91d77f6c96ef2d529a27ef8ee3947c
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 13:03:40 2014 -0700
-
- Lint cleanup from William Rucklidge.
-
- Change-Id: Ie0e0aa58440be7a4f67dcd633dbb6f1bb0c051a8
-
-commit 6a51b135e6298e8ba44a58cc2b54a170ab61a82f
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 28 10:48:29 2014 -0700
-
- Fix solver_test.cc
-
- When Eigen is not installed, Solver::IsValid was not detecting
- it correctly.
-
- Change-Id: Id285a84d829a9e20bc5de663adfca66ac31e08f3
-
-commit 62a8d64453ee41dae56710a4eead3fadf2fe1a4e
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 27 22:54:00 2014 -0700
-
- Expand check for lack of a sparse linear algebra library.
-
- The LinearSolver factory was creating a NULL linear solver
- if only Eigen's sparse linear algebra backend was available.
-
- Thanks to Michael Samples and Domink Reitzle for reporting this.
-
- Change-Id: I35e3a6c0fd0da2a31934adb5dfe4cad29577cc73
-
-commit 12eb389b4ec4113a2260c1a192a1d3f8d1b6a2d3
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 27 22:18:33 2014 -0700
-
- Fix Eigen Row/ColMajor bug in NumericDiffCostFunction.
-
- If the parameter block size is 1, asking Eigen to create
- a row-major matrix triggers a compile time error. Previously
- we were handling the case where the number of rows in the
- jacobian block was known statically, but the problem is present
- when the nummber of rows is dynamic.
-
- This CL fixes this problem.
-
- Thanks to Dominik Reitzle for reporting this.
-
- Change-Id: I99c3eec3558e66ebf4efa51c4dee8ce292ffe0c1
-
-commit 6c25185bb1643d8d0f3d8e1a7b82a058156aa869
-Author: Alex Stewart <alexs.mac@gmail.com>
-Date: Thu Aug 28 16:07:51 2014 +0100
-
- Fix crash in Covariance if # threads > 1 requested without OpenMP.
-
- - Previously if options.num_threads > 1 was given to Covariance compiled
- without OpenMP, a CHECK() would be triggered in program_evalutor.
-
- Change-Id: Iaade4f5ed5326b0c59a7014c750c41ee026e1124
-
-commit 6f89d850fb4ace0104abccf467c4fe37ad378b79
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 27 11:51:50 2014 -0700
-
- Further build breakage fixes.
-
- 1. Allow the minimum number of linear solver iterations to be zero.
- 2. Fix conjugate gradients solver's iteration loop to be sane again.
-
- Change-Id: I8594815fec940c2b30e28eb58ec5d8baacf13dae
-
-commit dd596d0f0d6d08951efc2c11a639b546db2080c6
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 27 11:26:50 2014 -0700
-
- Fix the broken build.
-
- Change-Id: I083cf1cca1bf4cca956193022d450364e73f833a
-
-commit d906afae22b05b9b9a9a2657924f4c0bf1a9b5ea
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 25 22:32:38 2014 -0700
-
- A number of bug fixes.
-
- 1. Fix a build breakage in graph_test.
- 2. Respect Solver::Options::min_num_linear_solver_iterations in
- conjugate_gradients_solver.cc
-
- Thanks to Johannes Schönberger for reporting these.
-
- Change-Id: Ib32e3929bf5d92dd576ae5b53d4d88797095136e
-
-commit dab955928c6d0942d6acc5b5f1c4c11260d0767d
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Aug 17 13:14:50 2014 -0700
-
- Add an unweighted graph.
-
- Rename Graph -> WeightedGraph.
- Add a new Graph class, which is cheaper to construct and
- work with if the weights are not needed.
-
- This cuts down the cost of building the Hessian graph
- significantly.
-
- Change-Id: Id0cfc81dd2c0bb5ff8f63a1b55aa133c53c0c869
-
-commit a0c282adbd268c2ad82551fab31fe1cf8d0c4282
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sun Aug 24 22:19:03 2014 -0700
-
- Add EIGEN_STRONG_INLINE annotation to jet.h
-
- This improves performance when using MSVC on Windows. On GCC
- there will be no effect.
-
- Change-Id: I555a81ff6823c2855d64773073f75af50c48d716
-
-commit 20de0a7793c574e964350a623446136889f74632
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date: Mon Aug 25 17:05:54 2014 +0200
-
- Fixed Malformed regex
-
- I got the following error with MSVC:
- Syntax error at index 9 in simple regular expression "NumGroups()": '(' is unsupported.
-
- Change-Id: Id1952831d81d3eb5d73bbed8c311914c4c8ab51f
-
-commit ccf8aea988269841d84d746e52164d5056c67a10
-Author: Björn Piltz <bjornpiltz@gmail.com>
-Date: Mon Aug 25 16:16:01 2014 +0200
-
- Fixed MSVC error C2124: divide or mod by zero
-
- Alternatively, if quiet_NaN is not available on all platforms a workaround would be:
- volatile double zero = 0.0;
- double x = 1.0/zero;
- The 'volatile' is needed to shut up "warning C4723: potential divide by 0".
-
- Change-Id: If2bbdab8540595aa2e0079e1eb6b6fed6d4a6ef7
-
-commit 8de27be218d42b282d7f15867733ad07058b0887
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Aug 19 08:22:40 2014 -0700
-
- Fix a bug in TrustRegionPreprocessor
-
- TrustRegionPreprocessor was not setting Minimizer::Options::is_constrained.
- This meant that the line search for bounds constraints was not being
- invoked for bounds constrained problems.
-
- And some minor lint cleanup.
-
- Change-Id: I18852cfaf1b33fd90b7d8c196f2063c128126658
-
-commit 1745dd615b3897a3ef9896acfdba67eee1739bf4
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Jun 5 21:30:13 2014 -0700
-
- Refactor SolverImpl.
-
- Replace SolverImpl with
-
- a. A minimizer specific preprocessor class.
- b. A generic Solve function inside solver.cc
- c. Presummarize and Postsummarize functions to handle
- updates to the summary object.
-
- The existing SolverImpl class was a mixture of the above three
- things and was increasingly complicated code to follow. This change,
- breaks it into its three separate constituents, with the aims of
- better separation of concerns and thus better testability and
- reliability.
-
- The call to Solver::Solve() now consists of
-
- 1. Presummarize - summarize the given state of the problem and solver
- options.
- 2. Preprocess - Setup everything that is needed to call the minimizer.
- This includes, removing redundant parameter and residual blocks,
- setting up the reordering for the linear solver, creating the
- linear solver, evaluator, inner iteration minimizer etc.
- 3. Minimize.
- 4. Post summarize - summarize the result of the preprocessing and the
- solve.
-
- Change-Id: I80f35cfc9f2cbf78f1df4aceace27075779d8a3a
diff --git a/extern/libmv/third_party/ceres/SConscript b/extern/libmv/third_party/ceres/SConscript
deleted file mode 100644
index f53d54ba94b..00000000000
--- a/extern/libmv/third_party/ceres/SConscript
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/python
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-import sys
-import os
-
-Import('env')
-
-src = []
-defs = []
-
-src += env.Glob('internal/ceres/*.cc')
-if env['WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS']:
- src += env.Glob('internal/ceres/generated/*.cc')
-else:
- src += env.Glob('internal/ceres/generated/schur_eliminator_d_d_d.cc')
- src += env.Glob('internal/ceres/generated/partitioned_matrix_view_d_d_d.cc')
- defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION')
-
-defs.append('CERES_HAVE_PTHREAD')
-defs.append('CERES_NO_SUITESPARSE')
-defs.append('CERES_NO_CXSPARSE')
-defs.append('CERES_NO_LAPACK')
-defs.append('CERES_HAVE_RWLOCK')
-
-if env['WITH_BF_OPENMP']:
- defs.append('CERES_USE_OPENMP')
-
-if env['WITH_UNORDERED_MAP_SUPPORT']:
- if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
- if env['UNORDERED_MAP_NAMESPACE'] == 'std':
- defs.append('CERES_STD_UNORDERED_MAP')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_TR1_UNORDERED_MAP')
-else:
- print("-- Replacing unordered_map/set with map/set (warning: slower!)")
- defs.append('CERES_NO_UNORDERED_MAP')
-
-if not env['WITH_SHARED_PTR_SUPPORT']:
- print("-- Unable to find shared_ptr which is required for compilation.")
- exit(1)
-
-if env['SHARED_PTR_HEADER'] == 'tr1/memory':
- defs.append('CERES_TR1_MEMORY_HEADER')
-if env['SHARED_PTR_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_TR1_SHARED_PTR')
-
-incs = '. ../../ ../../../Eigen3 ./include ./internal ../gflags ./config'
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- incs += ' ../msinttypes'
-
- incs += ' ../glog/src/windows'
-else:
- incs += ' ../glog/src'
-
-env.BlenderLib ( libname = 'extern_ceres', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137])
diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh
deleted file mode 100755
index 0becc87dd4f..00000000000
--- a/extern/libmv/third_party/ceres/bundle.sh
+++ /dev/null
@@ -1,267 +0,0 @@
-#!/bin/sh
-
-if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then
- echo Proceeding as requested by command line ...
-else
- echo "*** Please run again with --i-really-know-what-im-doing ..."
- exit 1
-fi
-
-repo="https://ceres-solver.googlesource.com/ceres-solver"
-branch="master"
-#tag="1.4.0"
-tag=""
-tmp=`mktemp -d`
-checkout="$tmp/ceres"
-
-GIT="git --git-dir $tmp/ceres/.git --work-tree $checkout"
-
-git clone $repo $checkout
-
-if [ $branch != "master" ]; then
- $GIT checkout -t remotes/origin/$branch
-else
- if [ "x$tag" != "x" ]; then
- $GIT checkout $tag
- fi
-fi
-
-$GIT log -n 50 > ChangeLog
-
-for p in `cat ./patches/series`; do
- echo "Applying patch $p..."
- cat ./patches/$p | patch -d $tmp/ceres -p1
-done
-
-find include -type f -not -iwholename '*.svn*' -exec rm -rf {} \;
-find internal -type f -not -iwholename '*.svn*' -exec rm -rf {} \;
-
-cat "files.txt" | while read f; do
- mkdir -p `dirname $f`
- cp $tmp/ceres/$f $f
-done
-
-rm -rf $tmp
-
-sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/' | \
- grep -v -E 'schur_eliminator_[0-9]_[0-9d]_[0-9d].cc' | \
- grep -v -E 'partitioned_matrix_view_[0-9]_[0-9d]_[0-9d].cc' | sort -d`
-generated_sources=`find ./include ./internal -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t\t/' | \
- grep -E 'schur_eliminator_[0-9]_[0-9d]_[0-9d].cc|partitioned_matrix_view_[0-9]_[0-9d]_[0-9d].cc' | sort -d`
-headers=`find ./include ./internal -type f -iname '*.h' | sed -r 's/^\.\//\t/' | sort -d`
-
-src_dir=`find ./internal -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t/' | sort -d | uniq`
-src=""
-for x in $src_dir $src_third_dir; do
- t=""
-
- if test `echo "$x" | grep -c glog ` -eq 1; then
- continue;
- fi
-
- if test `echo "$x" | grep -c generated` -eq 1; then
- continue;
- fi
-
- if stat $x/*.cpp > /dev/null 2>&1; then
- t="src += env.Glob('`echo $x'/*.cpp'`')"
- fi
-
- if stat $x/*.c > /dev/null 2>&1; then
- if [ -z "$t" ]; then
- t="src += env.Glob('`echo $x'/*.c'`')"
- else
- t="$t + env.Glob('`echo $x'/*.c'`')"
- fi
- fi
-
- if stat $x/*.cc > /dev/null 2>&1; then
- if [ -z "$t" ]; then
- t="src += env.Glob('`echo $x'/*.cc'`')"
- else
- t="$t + env.Glob('`echo $x'/*.cc'`')"
- fi
- fi
-
- if [ -z "$src" ]; then
- src=$t
- else
- src=`echo "$src\n$t"`
- fi
-done
-
-cat > CMakeLists.txt << EOF
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2012, Blender Foundation
-# All rights reserved.
-#
-# Contributor(s): Blender Foundation,
-# Sergey Sharybin
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-set(INC
- .
- include
- internal
- config
- ../gflags
- ../../
-)
-
-set(INC_SYS
- ${EIGEN3_INCLUDE_DIRS}
-)
-
-set(SRC
-${sources}
-
-${headers}
-)
-
-if(WITH_LIBMV_SCHUR_SPECIALIZATIONS)
- list(APPEND SRC
-${generated_sources}
- )
-else()
- add_definitions(-DCERES_RESTRICT_SCHUR_SPECIALIZATION)
-endif()
-
-if(WIN32)
- list(APPEND INC
- ../glog/src/windows
- )
-
- if(NOT MINGW)
- list(APPEND INC
- ../msinttypes
- )
- endif()
-else()
- list(APPEND INC
- ../glog/src
- )
-endif()
-
-add_definitions(
- -DCERES_HAVE_PTHREAD
- -DCERES_NO_SUITESPARSE
- -DCERES_NO_CXSPARSE
- -DCERES_NO_LAPACK
- -DCERES_HAVE_RWLOCK
-)
-
-if(WITH_OPENMP)
- add_definitions(
- -DCERES_USE_OPENMP
- )
-endif()
-
-TEST_UNORDERED_MAP_SUPPORT()
-if(HAVE_STD_UNORDERED_MAP_HEADER)
- if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
- add_definitions(-DCERES_STD_UNORDERED_MAP)
- else()
- if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
- add_definitions(-DCERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
- else()
- add_definitions(-DCERES_NO_UNORDERED_MAP)
- message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
- endif()
- endif()
-else()
- if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
- add_definitions(-DCERES_TR1_UNORDERED_MAP)
- else()
- add_definitions(-DCERES_NO_UNORDERED_MAP)
- message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
- endif()
-endif()
-
-blender_add_lib(extern_ceres "\${SRC}" "\${INC}" "\${INC_SYS}")
-EOF
-
-cat > SConscript << EOF
-#!/usr/bin/env python
-
-# NOTE: This file is automatically generated by bundle.sh script
-# If you're doing changes in this file, please update template
-# in that script too
-
-import sys
-import os
-
-Import('env')
-
-src = []
-defs = []
-
-$src
-if env['WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS']:
- src += env.Glob('internal/ceres/generated/*.cc')
-else:
- src += env.Glob('internal/ceres/generated/schur_eliminator_d_d_d.cc')
- src += env.Glob('internal/ceres/generated/partitioned_matrix_view_d_d_d.cc')
- defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION')
-
-defs.append('CERES_HAVE_PTHREAD')
-defs.append('CERES_NO_SUITESPARSE')
-defs.append('CERES_NO_CXSPARSE')
-defs.append('CERES_NO_LAPACK')
-defs.append('CERES_HAVE_RWLOCK')
-
-if env['WITH_BF_OPENMP']:
- defs.append('CERES_USE_OPENMP')
-
-if env['WITH_UNORDERED_MAP_SUPPORT']:
- if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
- if env['UNORDERED_MAP_NAMESPACE'] == 'std':
- defs.append('CERES_STD_UNORDERED_MAP')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_TR1_UNORDERED_MAP')
-else:
- print("-- Replacing unordered_map/set with map/set (warning: slower!)")
- defs.append('CERES_NO_UNORDERED_MAP')
-
-if not env['WITH_SHARED_PTR_SUPPORT']:
- print("-- Unable to find shared_ptr which is required for compilation.")
- exit(1)
-
-if env['SHARED_PTR_HEADER'] == 'tr1/memory':
- defs.append('CERES_TR1_MEMORY_HEADER')
-if env['SHARED_PTR_NAMESPACE'] == 'std::tr1':
- defs.append('CERES_TR1_SHARED_PTR')
-
-incs = '. ../../ ../../../Eigen3 ./include ./internal ../gflags ./config'
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- incs += ' ../msinttypes'
-
- incs += ' ../glog/src/windows'
-else:
- incs += ' ../glog/src'
-
-env.BlenderLib ( libname = 'extern_ceres', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137])
-EOF
diff --git a/extern/libmv/third_party/ceres/config/ceres/internal/config.h b/extern/libmv/third_party/ceres/config/ceres/internal/config.h
deleted file mode 100644
index c9d2c16e865..00000000000
--- a/extern/libmv/third_party/ceres/config/ceres/internal/config.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: alexs.mac@gmail.com (Alex Stewart)
-
-// Default (empty) configuration options for Ceres.
-//
-// IMPORTANT: Most users of Ceres will not use this file, when compiling Ceres
-// with CMake, CMake will configure a new config.h with the currently
-// selected Ceres compile options and copy it into the source
-// directory before compilation. However, for some users of Ceres
-// who compile without CMake, this file ensures that Ceres will
-// compile, with the user either specifying manually the Ceres
-// compile options, or passing them directly through the compiler.
-
-#ifndef CERES_PUBLIC_INTERNAL_CONFIG_H_
-#define CERES_PUBLIC_INTERNAL_CONFIG_H_
-
-
-#endif // CERES_PUBLIC_INTERNAL_CONFIG_H_
diff --git a/extern/libmv/third_party/ceres/files.txt b/extern/libmv/third_party/ceres/files.txt
deleted file mode 100644
index d1bd69672c8..00000000000
--- a/extern/libmv/third_party/ceres/files.txt
+++ /dev/null
@@ -1,258 +0,0 @@
-include/ceres/autodiff_cost_function.h
-include/ceres/autodiff_local_parameterization.h
-include/ceres/c_api.h
-include/ceres/ceres.h
-include/ceres/conditioned_cost_function.h
-include/ceres/cost_function.h
-include/ceres/cost_function_to_functor.h
-include/ceres/covariance.h
-include/ceres/crs_matrix.h
-include/ceres/dynamic_autodiff_cost_function.h
-include/ceres/dynamic_numeric_diff_cost_function.h
-include/ceres/fpclassify.h
-include/ceres/gradient_checker.h
-include/ceres/gradient_problem.h
-include/ceres/gradient_problem_solver.h
-include/ceres/internal/autodiff.h
-include/ceres/internal/disable_warnings.h
-include/ceres/internal/eigen.h
-include/ceres/internal/fixed_array.h
-include/ceres/internal/macros.h
-include/ceres/internal/manual_constructor.h
-include/ceres/internal/numeric_diff.h
-include/ceres/internal/port.h
-include/ceres/internal/reenable_warnings.h
-include/ceres/internal/scoped_ptr.h
-include/ceres/internal/variadic_evaluate.h
-include/ceres/iteration_callback.h
-include/ceres/jet.h
-include/ceres/local_parameterization.h
-include/ceres/loss_function.h
-include/ceres/normal_prior.h
-include/ceres/numeric_diff_cost_function.h
-include/ceres/ordered_groups.h
-include/ceres/problem.h
-include/ceres/rotation.h
-include/ceres/sized_cost_function.h
-include/ceres/solver.h
-include/ceres/types.h
-include/ceres/version.h
-internal/ceres/array_utils.cc
-internal/ceres/array_utils.h
-internal/ceres/blas.cc
-internal/ceres/blas.h
-internal/ceres/block_evaluate_preparer.cc
-internal/ceres/block_evaluate_preparer.h
-internal/ceres/block_jacobian_writer.cc
-internal/ceres/block_jacobian_writer.h
-internal/ceres/block_jacobi_preconditioner.cc
-internal/ceres/block_jacobi_preconditioner.h
-internal/ceres/block_random_access_dense_matrix.cc
-internal/ceres/block_random_access_dense_matrix.h
-internal/ceres/block_random_access_diagonal_matrix.cc
-internal/ceres/block_random_access_diagonal_matrix.h
-internal/ceres/block_random_access_matrix.cc
-internal/ceres/block_random_access_matrix.h
-internal/ceres/block_random_access_sparse_matrix.cc
-internal/ceres/block_random_access_sparse_matrix.h
-internal/ceres/block_sparse_matrix.cc
-internal/ceres/block_sparse_matrix.h
-internal/ceres/block_structure.cc
-internal/ceres/block_structure.h
-internal/ceres/callbacks.cc
-internal/ceres/callbacks.h
-internal/ceres/canonical_views_clustering.cc
-internal/ceres/canonical_views_clustering.h
-internal/ceres/c_api.cc
-internal/ceres/casts.h
-internal/ceres/cgnr_linear_operator.h
-internal/ceres/cgnr_solver.cc
-internal/ceres/cgnr_solver.h
-internal/ceres/collections_port.h
-internal/ceres/compressed_col_sparse_matrix_utils.cc
-internal/ceres/compressed_col_sparse_matrix_utils.h
-internal/ceres/compressed_row_jacobian_writer.cc
-internal/ceres/compressed_row_jacobian_writer.h
-internal/ceres/compressed_row_sparse_matrix.cc
-internal/ceres/compressed_row_sparse_matrix.h
-internal/ceres/conditioned_cost_function.cc
-internal/ceres/conjugate_gradients_solver.cc
-internal/ceres/conjugate_gradients_solver.h
-internal/ceres/coordinate_descent_minimizer.cc
-internal/ceres/coordinate_descent_minimizer.h
-internal/ceres/corrector.cc
-internal/ceres/corrector.h
-internal/ceres/covariance.cc
-internal/ceres/covariance_impl.cc
-internal/ceres/covariance_impl.h
-internal/ceres/cxsparse.cc
-internal/ceres/cxsparse.h
-internal/ceres/dense_jacobian_writer.h
-internal/ceres/dense_normal_cholesky_solver.cc
-internal/ceres/dense_normal_cholesky_solver.h
-internal/ceres/dense_qr_solver.cc
-internal/ceres/dense_qr_solver.h
-internal/ceres/dense_sparse_matrix.cc
-internal/ceres/dense_sparse_matrix.h
-internal/ceres/detect_structure.cc
-internal/ceres/detect_structure.h
-internal/ceres/dogleg_strategy.cc
-internal/ceres/dogleg_strategy.h
-internal/ceres/dynamic_compressed_row_finalizer.h
-internal/ceres/dynamic_compressed_row_jacobian_writer.cc
-internal/ceres/dynamic_compressed_row_jacobian_writer.h
-internal/ceres/dynamic_compressed_row_sparse_matrix.cc
-internal/ceres/dynamic_compressed_row_sparse_matrix.h
-internal/ceres/evaluator.cc
-internal/ceres/evaluator.h
-internal/ceres/execution_summary.h
-internal/ceres/file.cc
-internal/ceres/file.h
-internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
-internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
-internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
-internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
-internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
-internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
-internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
-internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
-internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
-internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
-internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
-internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
-internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
-internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
-internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
-internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
-internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
-internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
-internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
-internal/ceres/generated/schur_eliminator_2_2_2.cc
-internal/ceres/generated/schur_eliminator_2_2_3.cc
-internal/ceres/generated/schur_eliminator_2_2_4.cc
-internal/ceres/generated/schur_eliminator_2_2_d.cc
-internal/ceres/generated/schur_eliminator_2_3_3.cc
-internal/ceres/generated/schur_eliminator_2_3_4.cc
-internal/ceres/generated/schur_eliminator_2_3_9.cc
-internal/ceres/generated/schur_eliminator_2_3_d.cc
-internal/ceres/generated/schur_eliminator_2_4_3.cc
-internal/ceres/generated/schur_eliminator_2_4_4.cc
-internal/ceres/generated/schur_eliminator_2_4_8.cc
-internal/ceres/generated/schur_eliminator_2_4_9.cc
-internal/ceres/generated/schur_eliminator_2_4_d.cc
-internal/ceres/generated/schur_eliminator_2_d_d.cc
-internal/ceres/generated/schur_eliminator_4_4_2.cc
-internal/ceres/generated/schur_eliminator_4_4_3.cc
-internal/ceres/generated/schur_eliminator_4_4_4.cc
-internal/ceres/generated/schur_eliminator_4_4_d.cc
-internal/ceres/generated/schur_eliminator_d_d_d.cc
-internal/ceres/generate_eliminator_specialization.py
-internal/ceres/generate_partitioned_matrix_view_specializations.py
-internal/ceres/gradient_checking_cost_function.cc
-internal/ceres/gradient_checking_cost_function.h
-internal/ceres/gradient_problem.cc
-internal/ceres/gradient_problem_evaluator.h
-internal/ceres/gradient_problem_solver.cc
-internal/ceres/graph_algorithms.h
-internal/ceres/graph.h
-internal/ceres/implicit_schur_complement.cc
-internal/ceres/implicit_schur_complement.h
-internal/ceres/incomplete_lq_factorization.cc
-internal/ceres/incomplete_lq_factorization.h
-internal/ceres/integral_types.h
-internal/ceres/iterative_schur_complement_solver.cc
-internal/ceres/iterative_schur_complement_solver.h
-internal/ceres/lapack.cc
-internal/ceres/lapack.h
-internal/ceres/levenberg_marquardt_strategy.cc
-internal/ceres/levenberg_marquardt_strategy.h
-internal/ceres/linear_least_squares_problems.cc
-internal/ceres/linear_least_squares_problems.h
-internal/ceres/linear_operator.cc
-internal/ceres/linear_operator.h
-internal/ceres/linear_solver.cc
-internal/ceres/linear_solver.h
-internal/ceres/line_search.cc
-internal/ceres/line_search_direction.cc
-internal/ceres/line_search_direction.h
-internal/ceres/line_search.h
-internal/ceres/line_search_minimizer.cc
-internal/ceres/line_search_minimizer.h
-internal/ceres/line_search_preprocessor.cc
-internal/ceres/line_search_preprocessor.h
-internal/ceres/local_parameterization.cc
-internal/ceres/loss_function.cc
-internal/ceres/low_rank_inverse_hessian.cc
-internal/ceres/low_rank_inverse_hessian.h
-internal/ceres/map_util.h
-internal/ceres/minimizer.cc
-internal/ceres/minimizer.h
-internal/ceres/mutex.h
-internal/ceres/normal_prior.cc
-internal/ceres/parameter_block.h
-internal/ceres/parameter_block_ordering.cc
-internal/ceres/parameter_block_ordering.h
-internal/ceres/partitioned_matrix_view.cc
-internal/ceres/partitioned_matrix_view.h
-internal/ceres/partitioned_matrix_view_impl.h
-internal/ceres/polynomial.cc
-internal/ceres/polynomial.h
-internal/ceres/preconditioner.cc
-internal/ceres/preconditioner.h
-internal/ceres/preprocessor.cc
-internal/ceres/preprocessor.h
-internal/ceres/problem.cc
-internal/ceres/problem_impl.cc
-internal/ceres/problem_impl.h
-internal/ceres/program.cc
-internal/ceres/program_evaluator.h
-internal/ceres/program.h
-internal/ceres/random.h
-internal/ceres/reorder_program.cc
-internal/ceres/reorder_program.h
-internal/ceres/residual_block.cc
-internal/ceres/residual_block.h
-internal/ceres/residual_block_utils.cc
-internal/ceres/residual_block_utils.h
-internal/ceres/schur_complement_solver.cc
-internal/ceres/schur_complement_solver.h
-internal/ceres/schur_eliminator.cc
-internal/ceres/schur_eliminator.h
-internal/ceres/schur_eliminator_impl.h
-internal/ceres/schur_jacobi_preconditioner.cc
-internal/ceres/schur_jacobi_preconditioner.h
-internal/ceres/scratch_evaluate_preparer.cc
-internal/ceres/scratch_evaluate_preparer.h
-internal/ceres/single_linkage_clustering.cc
-internal/ceres/single_linkage_clustering.h
-internal/ceres/small_blas.h
-internal/ceres/solver.cc
-internal/ceres/solver_utils.cc
-internal/ceres/solver_utils.h
-internal/ceres/sparse_matrix.cc
-internal/ceres/sparse_matrix.h
-internal/ceres/sparse_normal_cholesky_solver.cc
-internal/ceres/sparse_normal_cholesky_solver.h
-internal/ceres/split.cc
-internal/ceres/split.h
-internal/ceres/stl_util.h
-internal/ceres/stringprintf.cc
-internal/ceres/stringprintf.h
-internal/ceres/suitesparse.cc
-internal/ceres/suitesparse.h
-internal/ceres/triplet_sparse_matrix.cc
-internal/ceres/triplet_sparse_matrix.h
-internal/ceres/trust_region_minimizer.cc
-internal/ceres/trust_region_minimizer.h
-internal/ceres/trust_region_preprocessor.cc
-internal/ceres/trust_region_preprocessor.h
-internal/ceres/trust_region_strategy.cc
-internal/ceres/trust_region_strategy.h
-internal/ceres/types.cc
-internal/ceres/visibility_based_preconditioner.cc
-internal/ceres/visibility_based_preconditioner.h
-internal/ceres/visibility.cc
-internal/ceres/visibility.h
-internal/ceres/wall_time.cc
-internal/ceres/wall_time.h
-config/ceres/internal/config.h
diff --git a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
deleted file mode 100644
index 7c0fa79ad0b..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
+++ /dev/null
@@ -1,227 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Create CostFunctions as needed by the least squares framework, with
-// Jacobians computed via automatic differentiation. For more
-// information on automatic differentation, see the wikipedia article
-// at http://en.wikipedia.org/wiki/Automatic_differentiation
-//
-// To get an auto differentiated cost function, you must define a class with a
-// templated operator() (a functor) that computes the cost function in terms of
-// the template parameter T. The autodiff framework substitutes appropriate
-// "jet" objects for T in order to compute the derivative when necessary, but
-// this is hidden, and you should write the function as if T were a scalar type
-// (e.g. a double-precision floating point number).
-//
-// The function must write the computed value in the last argument
-// (the only non-const one) and return true to indicate
-// success. Please see cost_function.h for details on how the return
-// value maybe used to impose simple constraints on the parameter
-// block.
-//
-// For example, consider a scalar error e = k - x'y, where both x and y are
-// two-dimensional column vector parameters, the prime sign indicates
-// transposition, and k is a constant. The form of this error, which is the
-// difference between a constant and an expression, is a common pattern in least
-// squares problems. For example, the value x'y might be the model expectation
-// for a series of measurements, where there is an instance of the cost function
-// for each measurement k.
-//
-// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
-// the squaring is implicitly done by the optimization framework.
-//
-// To write an auto-differentiable cost function for the above model, first
-// define the object
-//
-// class MyScalarCostFunctor {
-// MyScalarCostFunctor(double k): k_(k) {}
-//
-// template <typename T>
-// bool operator()(const T* const x , const T* const y, T* e) const {
-// e[0] = T(k_) - x[0] * y[0] + x[1] * y[1];
-// return true;
-// }
-//
-// private:
-// double k_;
-// };
-//
-// Note that in the declaration of operator() the input parameters x and y come
-// first, and are passed as const pointers to arrays of T. If there were three
-// input parameters, then the third input parameter would come after y. The
-// output is always the last parameter, and is also a pointer to an array. In
-// the example above, e is a scalar, so only e[0] is set.
-//
-// Then given this class definition, the auto differentiated cost function for
-// it can be constructed as follows.
-//
-// CostFunction* cost_function
-// = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
-// new MyScalarCostFunctor(1.0)); ^ ^ ^
-// | | |
-// Dimension of residual -----+ | |
-// Dimension of x ---------------+ |
-// Dimension of y ------------------+
-//
-// In this example, there is usually an instance for each measumerent of k.
-//
-// In the instantiation above, the template parameters following
-// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
-// 1-dimensional output from two arguments, both 2-dimensional.
-//
-// AutoDiffCostFunction also supports cost functions with a
-// runtime-determined number of residuals. For example:
-//
-// CostFunction* cost_function
-// = new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
-// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
-// runtime_number_of_residuals); <----+ | | |
-// | | | |
-// | | | |
-// Actual number of residuals ------+ | | |
-// Indicate dynamic number of residuals --------+ | |
-// Dimension of x ------------------------------------+ |
-// Dimension of y ---------------------------------------+
-//
-// The framework can currently accommodate cost functions of up to 10
-// independent variables, and there is no limit on the dimensionality
-// of each of them.
-//
-// WARNING #1: Since the functor will get instantiated with different types for
-// T, you must to convert from other numeric types to T before mixing
-// computations with other variables of type T. In the example above, this is
-// seen where instead of using k_ directly, k_ is wrapped with T(k_).
-//
-// WARNING #2: A common beginner's error when first using autodiff cost
-// functions is to get the sizing wrong. In particular, there is a tendency to
-// set the template parameters to (dimension of residual, number of parameters)
-// instead of passing a dimension parameter for *every parameter*. In the
-// example above, that would be <MyScalarCostFunctor, 1, 2>, which is missing
-// the last '2' argument. Please be careful when setting the size parameters.
-
-#ifndef CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
-#define CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
-
-#include "ceres/internal/autodiff.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/sized_cost_function.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-// A cost function which computes the derivative of the cost with respect to
-// the parameters (a.k.a. the jacobian) using an autodifferentiation framework.
-// The first template argument is the functor object, described in the header
-// comment. The second argument is the dimension of the residual (or
-// ceres::DYNAMIC to indicate it will be set at runtime), and subsequent
-// arguments describe the size of the Nth parameter, one per parameter.
-//
-// The constructors take ownership of the cost functor.
-//
-// If the number of residuals (argument kNumResiduals below) is
-// ceres::DYNAMIC, then the two-argument constructor must be used. The
-// second constructor takes a number of residuals (in addition to the
-// templated number of residuals). This allows for varying the number
-// of residuals for a single autodiff cost function at runtime.
-template <typename CostFunctor,
- int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
- int N0, // Number of parameters in block 0.
- int N1 = 0, // Number of parameters in block 1.
- int N2 = 0, // Number of parameters in block 2.
- int N3 = 0, // Number of parameters in block 3.
- int N4 = 0, // Number of parameters in block 4.
- int N5 = 0, // Number of parameters in block 5.
- int N6 = 0, // Number of parameters in block 6.
- int N7 = 0, // Number of parameters in block 7.
- int N8 = 0, // Number of parameters in block 8.
- int N9 = 0> // Number of parameters in block 9.
-class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9> {
- public:
- // Takes ownership of functor. Uses the template-provided value for the
- // number of residuals ("kNumResiduals").
- explicit AutoDiffCostFunction(CostFunctor* functor)
- : functor_(functor) {
- CHECK_NE(kNumResiduals, DYNAMIC)
- << "Can't run the fixed-size constructor if the "
- << "number of residuals is set to ceres::DYNAMIC.";
- }
-
- // Takes ownership of functor. Ignores the template-provided
- // kNumResiduals in favor of the "num_residuals" argument provided.
- //
- // This allows for having autodiff cost functions which return varying
- // numbers of residuals at runtime.
- AutoDiffCostFunction(CostFunctor* functor, int num_residuals)
- : functor_(functor) {
- CHECK_EQ(kNumResiduals, DYNAMIC)
- << "Can't run the dynamic-size constructor if the "
- << "number of residuals is not ceres::DYNAMIC.";
- SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9>
- ::set_num_residuals(num_residuals);
- }
-
- virtual ~AutoDiffCostFunction() {}
-
- // Implementation details follow; clients of the autodiff cost function should
- // not have to examine below here.
- //
- // To handle varardic cost functions, some template magic is needed. It's
- // mostly hidden inside autodiff.h.
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- if (!jacobians) {
- return internal::VariadicEvaluate<
- CostFunctor, double, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
- ::Call(*functor_, parameters, residuals);
- }
- return internal::AutoDiff<CostFunctor, double,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate(
- *functor_,
- parameters,
- SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9>::num_residuals(),
- residuals,
- jacobians);
- }
-
- private:
- internal::scoped_ptr<CostFunctor> functor_;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/autodiff_local_parameterization.h b/extern/libmv/third_party/ceres/include/ceres/autodiff_local_parameterization.h
deleted file mode 100644
index c100d4825d2..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/autodiff_local_parameterization.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sergey.vfx@gmail.com (Sergey Sharybin)
-// mierle@gmail.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
-#define CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
-
-#include "ceres/internal/autodiff.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/local_parameterization.h"
-
-namespace ceres {
-
-// Create local parameterization with Jacobians computed via automatic
-// differentiation. For more information on local parameterizations,
-// see include/ceres/local_parameterization.h
-//
-// To get an auto differentiated local parameterization, you must define
-// a class with a templated operator() (a functor) that computes
-//
-// x_plus_delta = Plus(x, delta);
-//
-// the template parameter T. The autodiff framework substitutes appropriate
-// "Jet" objects for T in order to compute the derivative when necessary, but
-// this is hidden, and you should write the function as if T were a scalar type
-// (e.g. a double-precision floating point number).
-//
-// The function must write the computed value in the last argument (the only
-// non-const one) and return true to indicate success.
-//
-// For example, Quaternions have a three dimensional local
-// parameterization. It's plus operation can be implemented as (taken
-// from internal/ceres/auto_diff_local_parameterization_test.cc)
-//
-// struct QuaternionPlus {
-// template<typename T>
-// bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-// const T squared_norm_delta =
-// delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
-//
-// T q_delta[4];
-// if (squared_norm_delta > T(0.0)) {
-// T norm_delta = sqrt(squared_norm_delta);
-// const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
-// q_delta[0] = cos(norm_delta);
-// q_delta[1] = sin_delta_by_delta * delta[0];
-// q_delta[2] = sin_delta_by_delta * delta[1];
-// q_delta[3] = sin_delta_by_delta * delta[2];
-// } else {
-// // We do not just use q_delta = [1,0,0,0] here because that is a
-// // constant and when used for automatic differentiation will
-// // lead to a zero derivative. Instead we take a first order
-// // approximation and evaluate it at zero.
-// q_delta[0] = T(1.0);
-// q_delta[1] = delta[0];
-// q_delta[2] = delta[1];
-// q_delta[3] = delta[2];
-// }
-//
-// QuaternionProduct(q_delta, x, x_plus_delta);
-// return true;
-// }
-// };
-//
-// Then given this struct, the auto differentiated local
-// parameterization can now be constructed as
-//
-// LocalParameterization* local_parameterization =
-// new AutoDiffLocalParameterization<QuaternionPlus, 4, 3>;
-// | |
-// Global Size ---------------+ |
-// Local Size -------------------+
-//
-// WARNING: Since the functor will get instantiated with different types for
-// T, you must to convert from other numeric types to T before mixing
-// computations with other variables of type T. In the example above, this is
-// seen where instead of using k_ directly, k_ is wrapped with T(k_).
-
-template <typename Functor, int kGlobalSize, int kLocalSize>
-class AutoDiffLocalParameterization : public LocalParameterization {
- public:
- AutoDiffLocalParameterization() :
- functor_(new Functor()) {}
-
- // Takes ownership of functor.
- explicit AutoDiffLocalParameterization(Functor* functor) :
- functor_(functor) {}
-
- virtual ~AutoDiffLocalParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const {
- return (*functor_)(x, delta, x_plus_delta);
- }
-
- virtual bool ComputeJacobian(const double* x, double* jacobian) const {
- double zero_delta[kLocalSize];
- for (int i = 0; i < kLocalSize; ++i) {
- zero_delta[i] = 0.0;
- }
-
- double x_plus_delta[kGlobalSize];
- for (int i = 0; i < kGlobalSize; ++i) {
- x_plus_delta[i] = 0.0;
- }
-
- const double* parameter_ptrs[2] = {x, zero_delta};
- double* jacobian_ptrs[2] = { NULL, jacobian };
- return internal::AutoDiff<Functor, double, kGlobalSize, kLocalSize>
- ::Differentiate(*functor_,
- parameter_ptrs,
- kGlobalSize,
- x_plus_delta,
- jacobian_ptrs);
- }
-
- virtual int GlobalSize() const { return kGlobalSize; }
- virtual int LocalSize() const { return kLocalSize; }
-
- private:
- internal::scoped_ptr<Functor> functor_;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/c_api.h b/extern/libmv/third_party/ceres/include/ceres/c_api.h
deleted file mode 100644
index 71f41fd226b..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/c_api.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Ceres Solver - A fast non-linear least squares minimizer
- * Copyright 2013 Google Inc. All rights reserved.
- * http://code.google.com/p/ceres-solver/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * - Neither the name of Google Inc. nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * Author: mierle@gmail.com (Keir Mierle)
- *
- * A minimal C API for Ceres. Not all functionality is included. This API is
- * not intended for clients of Ceres, but is instead intended for easing the
- * process of binding Ceres to other languages.
- *
- * Currently this is a work in progress.
- */
-
-#ifndef CERES_PUBLIC_C_API_H_
-#define CERES_PUBLIC_C_API_H_
-
-#include "ceres/internal/port.h"
-#include "ceres/internal/disable_warnings.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Init the Ceres private data. Must be called before anything else. */
-CERES_EXPORT void ceres_init();
-
-/* Equivalent to CostFunction::Evaluate() in the C++ API.
- *
- * The user may keep private information inside the opaque user_data object.
- * The pointer here is the same one passed in the ceres_add_residual_block().
- */
-typedef int (*ceres_cost_function_t)(void* user_data,
- double** parameters,
- double* residuals,
- double** jacobians);
-
-/* Equivalent to LossFunction::Evaluate() from the C++ API. */
-typedef void (*ceres_loss_function_t)(void* user_data,
- double squared_norm,
- double out[3]);
-
-/* Create callback data for Ceres' stock loss functions.
- *
- * Ceres has several loss functions available by default, and these functions
- * expose those to the C API. To use the stock loss functions, call
- * ceres_create_*_loss_data(), which internally creates an instance of one of
- * the stock loss functions (for example ceres::CauchyLoss), and pass the
- * returned "loss_function_data" along with the ceres_stock_loss_function to
- * ceres_add_residual_block().
- *
- * For example:
- *
- * void* cauchy_loss_function_data =
- * ceres_create_cauchy_loss_function_data(1.2, 0.0);
- * ceres_problem_add_residual_block(
- * problem,
- * my_cost_function,
- * my_cost_function_data,
- * ceres_stock_loss_function,
- * cauchy_loss_function_data,
- * 1,
- * 2,
- * parameter_sizes,
- * parameter_pointers);
- * ...
- * ceres_free_stock_loss_function_data(cauchy_loss_function_data);
- *
- * See loss_function.h for the details of each loss function.
- */
-CERES_EXPORT void* ceres_create_huber_loss_function_data(double a);
-CERES_EXPORT void* ceres_create_softl1_loss_function_data(double a);
-CERES_EXPORT void* ceres_create_cauchy_loss_function_data(double a);
-CERES_EXPORT void* ceres_create_arctan_loss_function_data(double a);
-CERES_EXPORT void* ceres_create_tolerant_loss_function_data(double a, double b);
-
-/* Free the given stock loss function data. */
-CERES_EXPORT void ceres_free_stock_loss_function_data(void* loss_function_data);
-
-/* This is an implementation of ceres_loss_function_t contained within Ceres
- * itself, intended as a way to access the various stock Ceres loss functions
- * from the C API. This should be passed to ceres_add_residual() below, in
- * combination with a user_data pointer generated by
- * ceres_create_stock_loss_function() above. */
-CERES_EXPORT void ceres_stock_loss_function(void* user_data,
- double squared_norm,
- double out[3]);
-
-/* Equivalent to Problem from the C++ API. */
-struct ceres_problem_s;
-typedef struct ceres_problem_s ceres_problem_t;
-
-struct ceres_residual_block_id_s;
-typedef struct ceres_residual_block_id_s ceres_residual_block_id_t;
-
-/* Create and destroy a problem */
-/* TODO(keir): Add options for the problem. */
-CERES_EXPORT ceres_problem_t* ceres_create_problem();
-CERES_EXPORT void ceres_free_problem(ceres_problem_t* problem);
-
-/* Add a residual block. */
-CERES_EXPORT ceres_residual_block_id_t* ceres_problem_add_residual_block(
- ceres_problem_t* problem,
- ceres_cost_function_t cost_function,
- void* cost_function_data,
- ceres_loss_function_t loss_function,
- void* loss_function_data,
- int num_residuals,
- int num_parameter_blocks,
- int* parameter_block_sizes,
- double** parameters);
-
-CERES_EXPORT void ceres_solve(ceres_problem_t* problem);
-
-/* TODO(keir): Figure out a way to pass a config in. */
-
-#ifdef __cplusplus
-}
-#endif
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif /* CERES_PUBLIC_C_API_H_ */
diff --git a/extern/libmv/third_party/ceres/include/ceres/ceres.h b/extern/libmv/third_party/ceres/include/ceres/ceres.h
deleted file mode 100644
index 7c8981e2994..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/ceres.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// This is a forwarding header containing the public symbols exported from
-// Ceres. Anything in the "ceres" namespace is available for use.
-
-#ifndef CERES_PUBLIC_CERES_H_
-#define CERES_PUBLIC_CERES_H_
-
-#include "ceres/autodiff_cost_function.h"
-#include "ceres/autodiff_local_parameterization.h"
-#include "ceres/cost_function.h"
-#include "ceres/cost_function_to_functor.h"
-#include "ceres/covariance.h"
-#include "ceres/crs_matrix.h"
-#include "ceres/dynamic_autodiff_cost_function.h"
-#include "ceres/dynamic_numeric_diff_cost_function.h"
-#include "ceres/gradient_problem.h"
-#include "ceres/gradient_problem_solver.h"
-#include "ceres/iteration_callback.h"
-#include "ceres/jet.h"
-#include "ceres/local_parameterization.h"
-#include "ceres/loss_function.h"
-#include "ceres/numeric_diff_cost_function.h"
-#include "ceres/ordered_groups.h"
-#include "ceres/problem.h"
-#include "ceres/sized_cost_function.h"
-#include "ceres/solver.h"
-#include "ceres/types.h"
-#include "ceres/version.h"
-
-#endif // CERES_PUBLIC_CERES_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/conditioned_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/conditioned_cost_function.h
deleted file mode 100644
index 3f0087c7815..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/conditioned_cost_function.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wjr@google.com (William Rucklidge)
-//
-// This file contains a cost function that can apply a transformation to
-// each residual value before they are square-summed.
-
-#ifndef CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
-#define CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
-
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// This class allows you to apply different conditioning to the residual
-// values of a wrapped cost function. An example where this is useful is
-// where you have an existing cost function that produces N values, but you
-// want the total cost to be something other than just the sum of these
-// squared values - maybe you want to apply a different scaling to some
-// values, to change their contribution to the cost.
-//
-// Usage:
-//
-// // my_cost_function produces N residuals
-// CostFunction* my_cost_function = ...
-// CHECK_EQ(N, my_cost_function->num_residuals());
-// vector<CostFunction*> conditioners;
-//
-// // Make N 1x1 cost functions (1 parameter, 1 residual)
-// CostFunction* f_1 = ...
-// conditioners.push_back(f_1);
-// ...
-// CostFunction* f_N = ...
-// conditioners.push_back(f_N);
-// ConditionedCostFunction* ccf =
-// new ConditionedCostFunction(my_cost_function, conditioners);
-//
-// Now ccf's residual i (i=0..N-1) will be passed though the i'th conditioner.
-//
-// ccf_residual[i] = f_i(my_cost_function_residual[i])
-//
-// and the Jacobian will be affected appropriately.
-class CERES_EXPORT ConditionedCostFunction : public CostFunction {
- public:
- // Builds a cost function based on a wrapped cost function, and a
- // per-residual conditioner. Takes ownership of all of the wrapped cost
- // functions, or not, depending on the ownership parameter. Conditioners
- // may be NULL, in which case the corresponding residual is not modified.
- ConditionedCostFunction(CostFunction* wrapped_cost_function,
- const vector<CostFunction*>& conditioners,
- Ownership ownership);
- virtual ~ConditionedCostFunction();
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const;
-
- private:
- internal::scoped_ptr<CostFunction> wrapped_cost_function_;
- vector<CostFunction*> conditioners_;
- Ownership ownership_;
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_CONDITIONED_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/cost_function.h b/extern/libmv/third_party/ceres/include/ceres/cost_function.h
deleted file mode 100644
index fe8fc07d2ce..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/cost_function.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// keir@google.m (Keir Mierle)
-//
-// This is the interface through which the least squares solver accesses the
-// residual and Jacobian of the least squares problem. Users are expected to
-// subclass CostFunction to define their own terms in the least squares problem.
-//
-// It is recommended that users define templated residual functors for use as
-// arguments for AutoDiffCostFunction (see autodiff_cost_function.h), instead of
-// directly implementing the CostFunction interface. This often results in both
-// shorter code and faster execution than hand-coded derivatives. However,
-// specialized cases may demand direct implementation of the lower-level
-// CostFunction interface; for example, this is true when calling legacy code
-// which is not templated on numeric types.
-
-#ifndef CERES_PUBLIC_COST_FUNCTION_H_
-#define CERES_PUBLIC_COST_FUNCTION_H_
-
-#include <vector>
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// This class implements the computation of the cost (a.k.a. residual) terms as
-// a function of the input (control) variables, and is the interface for users
-// to describe their least squares problem to Ceres. In other words, this is the
-// modelling layer between users and the Ceres optimizer. The signature of the
-// function (number and sizes of input parameter blocks and number of outputs)
-// is stored in parameter_block_sizes_ and num_residuals_ respectively. User
-// code inheriting from this class is expected to set these two members with the
-// corresponding accessors. This information will be verified by the Problem
-// when added with AddResidualBlock().
-class CERES_EXPORT CostFunction {
- public:
- CostFunction() : num_residuals_(0) {}
-
- virtual ~CostFunction() {}
-
- // Inputs:
- //
- // parameters is an array of pointers to arrays containing the
- // various parameter blocks. parameters has the same number of
- // elements as parameter_block_sizes_. Parameter blocks are in the
- // same order as parameter_block_sizes_.i.e.,
- //
- // parameters_[i] = double[parameter_block_sizes_[i]]
- //
- // Outputs:
- //
- // residuals is an array of size num_residuals_.
- //
- // jacobians is an array of size parameter_block_sizes_ containing
- // pointers to storage for jacobian blocks corresponding to each
- // parameter block. Jacobian blocks are in the same order as
- // parameter_block_sizes, i.e. jacobians[i], is an
- // array that contains num_residuals_* parameter_block_sizes_[i]
- // elements. Each jacobian block is stored in row-major order, i.e.,
- //
- // jacobians[i][r*parameter_block_size_[i] + c] =
- // d residual[r] / d parameters[i][c]
- //
- // If jacobians is NULL, then no derivatives are returned; this is
- // the case when computing cost only. If jacobians[i] is NULL, then
- // the jacobian block corresponding to the i'th parameter block must
- // not to be returned.
- //
- // The return value indicates whether the computation of the
- // residuals and/or jacobians was successful or not.
- //
- // This can be used to communicate numerical failures in jacobian
- // computations for instance.
- //
- // A more interesting and common use is to impose constraints on the
- // parameters. If the initial values of the parameter blocks satisfy
- // the constraints, then returning false whenever the constraints
- // are not satisfied will prevent the solver from moving into the
- // infeasible region. This is not a very sophisticated mechanism for
- // enforcing constraints, but is often good enough.
- //
- // Note that it is important that the initial values of the
- // parameter block must be feasible, otherwise the solver will
- // declare a numerical problem at iteration 0.
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const = 0;
-
- const vector<int32>& parameter_block_sizes() const {
- return parameter_block_sizes_;
- }
-
- int num_residuals() const {
- return num_residuals_;
- }
-
- protected:
- vector<int32>* mutable_parameter_block_sizes() {
- return &parameter_block_sizes_;
- }
-
- void set_num_residuals(int num_residuals) {
- num_residuals_ = num_residuals;
- }
-
- private:
- // Cost function signature metadata: number of inputs & their sizes,
- // number of outputs (residuals).
- vector<int32> parameter_block_sizes_;
- int num_residuals_;
- CERES_DISALLOW_COPY_AND_ASSIGN(CostFunction);
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h b/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h
deleted file mode 100644
index b4a516e0ab1..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h
+++ /dev/null
@@ -1,750 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// CostFunctionToFunctor is an adapter class that allows users to use
-// CostFunction objects in templated functors which are to be used for
-// automatic differentiation. This allows the user to seamlessly mix
-// analytic, numeric and automatic differentiation.
-//
-// For example, let us assume that
-//
-// class IntrinsicProjection : public SizedCostFunction<2, 5, 3> {
-// public:
-// IntrinsicProjection(const double* observations);
-// virtual bool Evaluate(double const* const* parameters,
-// double* residuals,
-// double** jacobians) const;
-// };
-//
-// is a cost function that implements the projection of a point in its
-// local coordinate system onto its image plane and subtracts it from
-// the observed point projection. It can compute its residual and
-// either via analytic or numerical differentiation can compute its
-// jacobians.
-//
-// Now we would like to compose the action of this CostFunction with
-// the action of camera extrinsics, i.e., rotation and
-// translation. Say we have a templated function
-//
-// template<typename T>
-// void RotateAndTranslatePoint(const T* rotation,
-// const T* translation,
-// const T* point,
-// T* result);
-//
-// Then we can now do the following,
-//
-// struct CameraProjection {
-// CameraProjection(double* observation) {
-// intrinsic_projection_.reset(
-// new CostFunctionToFunctor<2, 5, 3>(
-// new IntrinsicProjection(observation_)));
-// }
-// template <typename T>
-// bool operator()(const T* rotation,
-// const T* translation,
-// const T* intrinsics,
-// const T* point,
-// T* residual) const {
-// T transformed_point[3];
-// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
-//
-// // Note that we call intrinsic_projection_, just like it was
-// // any other templated functor.
-//
-// return (*intrinsic_projection_)(intrinsics, transformed_point, residual);
-// }
-//
-// private:
-// scoped_ptr<CostFunctionToFunctor<2,5,3> > intrinsic_projection_;
-// };
-
-#ifndef CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
-#define CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
-
-#include <numeric>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-
-template <int kNumResiduals,
- int N0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
- int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
-class CostFunctionToFunctor {
- public:
- explicit CostFunctionToFunctor(CostFunction* cost_function)
- : cost_function_(cost_function) {
- CHECK_NOTNULL(cost_function);
- CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
-
- // This block breaks the 80 column rule to keep it somewhat readable.
- CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0)))
- << "Zero block cannot precede a non-zero block. Block sizes are "
- << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
- << N8 << ", " << N9;
-
- const vector<int32>& parameter_block_sizes =
- cost_function->parameter_block_sizes();
- const int num_parameter_blocks =
- (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
- (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
- CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks);
-
- CHECK_EQ(N0, parameter_block_sizes[0]);
- if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT
- if (parameter_block_sizes.size() > 2) CHECK_EQ(N2, parameter_block_sizes[2]); // NOLINT
- if (parameter_block_sizes.size() > 3) CHECK_EQ(N3, parameter_block_sizes[3]); // NOLINT
- if (parameter_block_sizes.size() > 4) CHECK_EQ(N4, parameter_block_sizes[4]); // NOLINT
- if (parameter_block_sizes.size() > 5) CHECK_EQ(N5, parameter_block_sizes[5]); // NOLINT
- if (parameter_block_sizes.size() > 6) CHECK_EQ(N6, parameter_block_sizes[6]); // NOLINT
- if (parameter_block_sizes.size() > 7) CHECK_EQ(N7, parameter_block_sizes[7]); // NOLINT
- if (parameter_block_sizes.size() > 8) CHECK_EQ(N8, parameter_block_sizes[8]); // NOLINT
- if (parameter_block_sizes.size() > 9) CHECK_EQ(N9, parameter_block_sizes[9]); // NOLINT
-
- CHECK_EQ(accumulate(parameter_block_sizes.begin(),
- parameter_block_sizes.end(), 0),
- N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9);
- }
-
- bool operator()(const double* x0, double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_EQ(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
-
- return cost_function_->Evaluate(&x0, residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(2);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(3);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(4);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(5);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(6);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(7);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- const double* x7,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(8);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- parameter_blocks[7] = x7;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- const double* x7,
- const double* x8,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(9);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- parameter_blocks[7] = x7;
- parameter_blocks[8] = x8;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- bool operator()(const double* x0,
- const double* x1,
- const double* x2,
- const double* x3,
- const double* x4,
- const double* x5,
- const double* x6,
- const double* x7,
- const double* x8,
- const double* x9,
- double* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_NE(N9, 0);
- internal::FixedArray<const double*> parameter_blocks(10);
- parameter_blocks[0] = x0;
- parameter_blocks[1] = x1;
- parameter_blocks[2] = x2;
- parameter_blocks[3] = x3;
- parameter_blocks[4] = x4;
- parameter_blocks[5] = x5;
- parameter_blocks[6] = x6;
- parameter_blocks[7] = x7;
- parameter_blocks[8] = x8;
- parameter_blocks[9] = x9;
- return cost_function_->Evaluate(parameter_blocks.get(), residuals, NULL);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0, JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_EQ(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- return EvaluateWithJets(&x0, residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_EQ(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(2);
- jets[0] = x0;
- jets[1] = x1;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_EQ(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(3);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_EQ(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(4);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_EQ(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(5);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_EQ(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(6);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_EQ(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(7);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- const JetT* x7,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_EQ(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(8);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- jets[7] = x7;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- const JetT* x7,
- const JetT* x8,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_EQ(N9, 0);
- internal::FixedArray<const JetT*> jets(9);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- jets[7] = x7;
- jets[8] = x8;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- template <typename JetT>
- bool operator()(const JetT* x0,
- const JetT* x1,
- const JetT* x2,
- const JetT* x3,
- const JetT* x4,
- const JetT* x5,
- const JetT* x6,
- const JetT* x7,
- const JetT* x8,
- const JetT* x9,
- JetT* residuals) const {
- CHECK_NE(N0, 0);
- CHECK_NE(N1, 0);
- CHECK_NE(N2, 0);
- CHECK_NE(N3, 0);
- CHECK_NE(N4, 0);
- CHECK_NE(N5, 0);
- CHECK_NE(N6, 0);
- CHECK_NE(N7, 0);
- CHECK_NE(N8, 0);
- CHECK_NE(N9, 0);
- internal::FixedArray<const JetT*> jets(10);
- jets[0] = x0;
- jets[1] = x1;
- jets[2] = x2;
- jets[3] = x3;
- jets[4] = x4;
- jets[5] = x5;
- jets[6] = x6;
- jets[7] = x7;
- jets[8] = x8;
- jets[9] = x9;
- return EvaluateWithJets(jets.get(), residuals);
- }
-
- private:
- template <typename JetT>
- bool EvaluateWithJets(const JetT** inputs, JetT* output) const {
- const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
- const vector<int32>& parameter_block_sizes =
- cost_function_->parameter_block_sizes();
- const int num_parameter_blocks = parameter_block_sizes.size();
- const int num_residuals = cost_function_->num_residuals();
-
- internal::FixedArray<double> parameters(kNumParameters);
- internal::FixedArray<double*> parameter_blocks(num_parameter_blocks);
- internal::FixedArray<double> jacobians(num_residuals * kNumParameters);
- internal::FixedArray<double*> jacobian_blocks(num_parameter_blocks);
- internal::FixedArray<double> residuals(num_residuals);
-
- // Build a set of arrays to get the residuals and jacobians from
- // the CostFunction wrapped by this functor.
- double* parameter_ptr = parameters.get();
- double* jacobian_ptr = jacobians.get();
- for (int i = 0; i < num_parameter_blocks; ++i) {
- parameter_blocks[i] = parameter_ptr;
- jacobian_blocks[i] = jacobian_ptr;
- for (int j = 0; j < parameter_block_sizes[i]; ++j) {
- *parameter_ptr++ = inputs[i][j].a;
- }
- jacobian_ptr += num_residuals * parameter_block_sizes[i];
- }
-
- if (!cost_function_->Evaluate(parameter_blocks.get(),
- residuals.get(),
- jacobian_blocks.get())) {
- return false;
- }
-
- // Now that we have the incoming Jets, which are carrying the
- // partial derivatives of each of the inputs w.r.t to some other
- // underlying parameters. The derivative of the outputs of the
- // cost function w.r.t to the same underlying parameters can now
- // be computed by applying the chain rule.
- //
- // d output[i] d output[i] d input[j]
- // -------------- = sum_j ----------- * ------------
- // d parameter[k] d input[j] d parameter[k]
- //
- // d input[j]
- // -------------- = inputs[j], so
- // d parameter[k]
- //
- // outputJet[i] = sum_k jacobian[i][k] * inputJet[k]
- //
- // The following loop, iterates over the residuals, computing one
- // output jet at a time.
- for (int i = 0; i < num_residuals; ++i) {
- output[i].a = residuals[i];
- output[i].v.setZero();
-
- for (int j = 0; j < num_parameter_blocks; ++j) {
- const int32 block_size = parameter_block_sizes[j];
- for (int k = 0; k < parameter_block_sizes[j]; ++k) {
- output[i].v +=
- jacobian_blocks[j][i * block_size + k] * inputs[j][k].v;
- }
- }
- }
-
- return true;
- }
-
- private:
- internal::scoped_ptr<CostFunction> cost_function_;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_COST_FUNCTION_TO_FUNCTOR_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/covariance.h b/extern/libmv/third_party/ceres/include/ceres/covariance.h
deleted file mode 100644
index 35fde4de05d..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/covariance.h
+++ /dev/null
@@ -1,384 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_COVARIANCE_H_
-#define CERES_PUBLIC_COVARIANCE_H_
-
-#include <utility>
-#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-class Problem;
-
-namespace internal {
-class CovarianceImpl;
-} // namespace internal
-
-// WARNING
-// =======
-// It is very easy to use this class incorrectly without understanding
-// the underlying mathematics. Please read and understand the
-// documentation completely before attempting to use this class.
-//
-//
-// This class allows the user to evaluate the covariance for a
-// non-linear least squares problem and provides random access to its
-// blocks
-//
-// Background
-// ==========
-// One way to assess the quality of the solution returned by a
-// non-linear least squares solve is to analyze the covariance of the
-// solution.
-//
-// Let us consider the non-linear regression problem
-//
-// y = f(x) + N(0, I)
-//
-// i.e., the observation y is a random non-linear function of the
-// independent variable x with mean f(x) and identity covariance. Then
-// the maximum likelihood estimate of x given observations y is the
-// solution to the non-linear least squares problem:
-//
-// x* = arg min_x |f(x)|^2
-//
-// And the covariance of x* is given by
-//
-// C(x*) = inverse[J'(x*)J(x*)]
-//
-// Here J(x*) is the Jacobian of f at x*. The above formula assumes
-// that J(x*) has full column rank.
-//
-// If J(x*) is rank deficient, then the covariance matrix C(x*) is
-// also rank deficient and is given by
-//
-// C(x*) = pseudoinverse[J'(x*)J(x*)]
-//
-// Note that in the above, we assumed that the covariance
-// matrix for y was identity. This is an important assumption. If this
-// is not the case and we have
-//
-// y = f(x) + N(0, S)
-//
-// Where S is a positive semi-definite matrix denoting the covariance
-// of y, then the maximum likelihood problem to be solved is
-//
-// x* = arg min_x f'(x) inverse[S] f(x)
-//
-// and the corresponding covariance estimate of x* is given by
-//
-// C(x*) = inverse[J'(x*) inverse[S] J(x*)]
-//
-// So, if it is the case that the observations being fitted to have a
-// covariance matrix not equal to identity, then it is the user's
-// responsibility that the corresponding cost functions are correctly
-// scaled, e.g. in the above case the cost function for this problem
-// should evaluate S^{-1/2} f(x) instead of just f(x), where S^{-1/2}
-// is the inverse square root of the covariance matrix S.
-//
-// This class allows the user to evaluate the covariance for a
-// non-linear least squares problem and provides random access to its
-// blocks. The computation assumes that the CostFunctions compute
-// residuals such that their covariance is identity.
-//
-// Since the computation of the covariance matrix requires computing
-// the inverse of a potentially large matrix, this can involve a
-// rather large amount of time and memory. However, it is usually the
-// case that the user is only interested in a small part of the
-// covariance matrix. Quite often just the block diagonal. This class
-// allows the user to specify the parts of the covariance matrix that
-// she is interested in and then uses this information to only compute
-// and store those parts of the covariance matrix.
-//
-// Rank of the Jacobian
-// --------------------
-// As we noted above, if the jacobian is rank deficient, then the
-// inverse of J'J is not defined and instead a pseudo inverse needs to
-// be computed.
-//
-// The rank deficiency in J can be structural -- columns which are
-// always known to be zero or numerical -- depending on the exact
-// values in the Jacobian.
-//
-// Structural rank deficiency occurs when the problem contains
-// parameter blocks that are constant. This class correctly handles
-// structural rank deficiency like that.
-//
-// Numerical rank deficiency, where the rank of the matrix cannot be
-// predicted by its sparsity structure and requires looking at its
-// numerical values is more complicated. Here again there are two
-// cases.
-//
-// a. The rank deficiency arises from overparameterization. e.g., a
-// four dimensional quaternion used to parameterize SO(3), which is
-// a three dimensional manifold. In cases like this, the user should
-// use an appropriate LocalParameterization. Not only will this lead
-// to better numerical behaviour of the Solver, it will also expose
-// the rank deficiency to the Covariance object so that it can
-// handle it correctly.
-//
-// b. More general numerical rank deficiency in the Jacobian
-// requires the computation of the so called Singular Value
-// Decomposition (SVD) of J'J. We do not know how to do this for
-// large sparse matrices efficiently. For small and moderate sized
-// problems this is done using dense linear algebra.
-//
-// Gauge Invariance
-// ----------------
-// In structure from motion (3D reconstruction) problems, the
-// reconstruction is ambiguous upto a similarity transform. This is
-// known as a Gauge Ambiguity. Handling Gauges correctly requires the
-// use of SVD or custom inversion algorithms. For small problems the
-// user can use the dense algorithm. For more details see
-//
-// Ken-ichi Kanatani, Daniel D. Morris: Gauges and gauge
-// transformations for uncertainty description of geometric structure
-// with indeterminacy. IEEE Transactions on Information Theory 47(5):
-// 2017-2028 (2001)
-//
-// Example Usage
-// =============
-//
-// double x[3];
-// double y[2];
-//
-// Problem problem;
-// problem.AddParameterBlock(x, 3);
-// problem.AddParameterBlock(y, 2);
-// <Build Problem>
-// <Solve Problem>
-//
-// Covariance::Options options;
-// Covariance covariance(options);
-//
-// vector<pair<const double*, const double*> > covariance_blocks;
-// covariance_blocks.push_back(make_pair(x, x));
-// covariance_blocks.push_back(make_pair(y, y));
-// covariance_blocks.push_back(make_pair(x, y));
-//
-// CHECK(covariance.Compute(covariance_blocks, &problem));
-//
-// double covariance_xx[3 * 3];
-// double covariance_yy[2 * 2];
-// double covariance_xy[3 * 2];
-// covariance.GetCovarianceBlock(x, x, covariance_xx)
-// covariance.GetCovarianceBlock(y, y, covariance_yy)
-// covariance.GetCovarianceBlock(x, y, covariance_xy)
-//
-class CERES_EXPORT Covariance {
- public:
- struct CERES_EXPORT Options {
- Options()
-#ifndef CERES_NO_SUITESPARSE
- : algorithm_type(SUITE_SPARSE_QR),
-#else
- : algorithm_type(EIGEN_SPARSE_QR),
-#endif
- min_reciprocal_condition_number(1e-14),
- null_space_rank(0),
- num_threads(1),
- apply_loss_function(true) {
- }
-
- // Ceres supports three different algorithms for covariance
- // estimation, which represent different tradeoffs in speed,
- // accuracy and reliability.
- //
- // 1. DENSE_SVD uses Eigen's JacobiSVD to perform the
- // computations. It computes the singular value decomposition
- //
- // U * S * V' = J
- //
- // and then uses it to compute the pseudo inverse of J'J as
- //
- // pseudoinverse[J'J]^ = V * pseudoinverse[S] * V'
- //
- // It is an accurate but slow method and should only be used
- // for small to moderate sized problems. It can handle
- // full-rank as well as rank deficient Jacobians.
- //
- // 2. EIGEN_SPARSE_QR uses the sparse QR factorization algorithm
- // in Eigen to compute the decomposition
- //
- // Q * R = J
- //
- // [J'J]^-1 = [R*R']^-1
- //
- // It is a moderately fast algorithm for sparse matrices.
- //
- // 3. SUITE_SPARSE_QR uses the SuiteSparseQR sparse QR
- // factorization algorithm. It uses dense linear algebra and is
- // multi threaded, so for large sparse sparse matrices it is
- // significantly faster than EIGEN_SPARSE_QR.
- //
- // Neither EIGEN_SPARSE_QR not SUITE_SPARSE_QR are capable of
- // computing the covariance if the Jacobian is rank deficient.
- CovarianceAlgorithmType algorithm_type;
-
- // If the Jacobian matrix is near singular, then inverting J'J
- // will result in unreliable results, e.g, if
- //
- // J = [1.0 1.0 ]
- // [1.0 1.0000001 ]
- //
- // which is essentially a rank deficient matrix, we have
- //
- // inv(J'J) = [ 2.0471e+14 -2.0471e+14]
- // [-2.0471e+14 2.0471e+14]
- //
- // This is not a useful result. Therefore, by default
- // Covariance::Compute will return false if a rank deficient
- // Jacobian is encountered. How rank deficiency is detected
- // depends on the algorithm being used.
- //
- // 1. DENSE_SVD
- //
- // min_sigma / max_sigma < sqrt(min_reciprocal_condition_number)
- //
- // where min_sigma and max_sigma are the minimum and maxiumum
- // singular values of J respectively.
- //
- // 2. SUITE_SPARSE_QR and EIGEN_SPARSE_QR
- //
- // rank(J) < num_col(J)
- //
- // Here rank(J) is the estimate of the rank of J returned by the
- // sparse QR factorization algorithm. It is a fairly reliable
- // indication of rank deficiency.
- //
- double min_reciprocal_condition_number;
-
- // When using DENSE_SVD, the user has more control in dealing with
- // singular and near singular covariance matrices.
- //
- // As mentioned above, when the covariance matrix is near
- // singular, instead of computing the inverse of J'J, the
- // Moore-Penrose pseudoinverse of J'J should be computed.
- //
- // If J'J has the eigen decomposition (lambda_i, e_i), where
- // lambda_i is the i^th eigenvalue and e_i is the corresponding
- // eigenvector, then the inverse of J'J is
- //
- // inverse[J'J] = sum_i e_i e_i' / lambda_i
- //
- // and computing the pseudo inverse involves dropping terms from
- // this sum that correspond to small eigenvalues.
- //
- // How terms are dropped is controlled by
- // min_reciprocal_condition_number and null_space_rank.
- //
- // If null_space_rank is non-negative, then the smallest
- // null_space_rank eigenvalue/eigenvectors are dropped
- // irrespective of the magnitude of lambda_i. If the ratio of the
- // smallest non-zero eigenvalue to the largest eigenvalue in the
- // truncated matrix is still below
- // min_reciprocal_condition_number, then the Covariance::Compute()
- // will fail and return false.
- //
- // Setting null_space_rank = -1 drops all terms for which
- //
- // lambda_i / lambda_max < min_reciprocal_condition_number.
- //
- // This option has no effect on the SUITE_SPARSE_QR and
- // EIGEN_SPARSE_QR algorithms.
- int null_space_rank;
-
- int num_threads;
-
- // Even though the residual blocks in the problem may contain loss
- // functions, setting apply_loss_function to false will turn off
- // the application of the loss function to the output of the cost
- // function and in turn its effect on the covariance.
- //
- // TODO(sameergaarwal): Expand this based on Jim's experiments.
- bool apply_loss_function;
- };
-
- explicit Covariance(const Options& options);
- ~Covariance();
-
- // Compute a part of the covariance matrix.
- //
- // The vector covariance_blocks, indexes into the covariance matrix
- // block-wise using pairs of parameter blocks. This allows the
- // covariance estimation algorithm to only compute and store these
- // blocks.
- //
- // Since the covariance matrix is symmetric, if the user passes
- // (block1, block2), then GetCovarianceBlock can be called with
- // block1, block2 as well as block2, block1.
- //
- // covariance_blocks cannot contain duplicates. Bad things will
- // happen if they do.
- //
- // Note that the list of covariance_blocks is only used to determine
- // what parts of the covariance matrix are computed. The full
- // Jacobian is used to do the computation, i.e. they do not have an
- // impact on what part of the Jacobian is used for computation.
- //
- // The return value indicates the success or failure of the
- // covariance computation. Please see the documentation for
- // Covariance::Options for more on the conditions under which this
- // function returns false.
- bool Compute(
- const vector<pair<const double*, const double*> >& covariance_blocks,
- Problem* problem);
-
- // Return the block of the covariance matrix corresponding to
- // parameter_block1 and parameter_block2.
- //
- // Compute must be called before the first call to
- // GetCovarianceBlock and the pair <parameter_block1,
- // parameter_block2> OR the pair <parameter_block2,
- // parameter_block1> must have been present in the vector
- // covariance_blocks when Compute was called. Otherwise
- // GetCovarianceBlock will return false.
- //
- // covariance_block must point to a memory location that can store a
- // parameter_block1_size x parameter_block2_size matrix. The
- // returned covariance will be a row-major matrix.
- bool GetCovarianceBlock(const double* parameter_block1,
- const double* parameter_block2,
- double* covariance_block) const;
-
- private:
- internal::scoped_ptr<internal::CovarianceImpl> impl_;
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_COVARIANCE_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
deleted file mode 100644
index d2d62894194..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_CRS_MATRIX_H_
-#define CERES_PUBLIC_CRS_MATRIX_H_
-
-#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// A compressed row sparse matrix used primarily for communicating the
-// Jacobian matrix to the user.
-struct CERES_EXPORT CRSMatrix {
- CRSMatrix() : num_rows(0), num_cols(0) {}
-
- int num_rows;
- int num_cols;
-
- // A compressed row matrix stores its contents in three arrays,
- // rows, cols and values.
- //
- // rows is a num_rows + 1 sized array that points into the cols and
- // values array. For each row i:
- //
- // cols[rows[i]] ... cols[rows[i + 1] - 1] are the indices of the
- // non-zero columns of row i.
- //
- // values[rows[i]] .. values[rows[i + 1] - 1] are the values of the
- // corresponding entries.
- //
- // cols and values contain as many entries as there are non-zeros in
- // the matrix.
- //
- // e.g, consider the 3x4 sparse matrix
- //
- // [ 0 10 0 4 ]
- // [ 0 2 -3 2 ]
- // [ 1 2 0 0 ]
- //
- // The three arrays will be:
- //
- //
- // -row0- ---row1--- -row2-
- // rows = [ 0, 2, 5, 7]
- // cols = [ 1, 3, 1, 2, 3, 0, 1]
- // values = [10, 4, 2, -3, 2, 1, 2]
-
- vector<int> cols;
- vector<int> rows;
- vector<double> values;
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_CRS_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
deleted file mode 100644
index f9342cdbab9..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
+++ /dev/null
@@ -1,260 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// mierle@gmail.com (Keir Mierle)
-//
-// This autodiff implementation differs from the one found in
-// autodiff_cost_function.h by supporting autodiff on cost functions
-// with variable numbers of parameters with variable sizes. With the
-// other implementation, all the sizes (both the number of parameter
-// blocks and the size of each block) must be fixed at compile time.
-//
-// The functor API differs slightly from the API for fixed size
-// autodiff; the expected interface for the cost functors is:
-//
-// struct MyCostFunctor {
-// template<typename T>
-// bool operator()(T const* const* parameters, T* residuals) const {
-// // Use parameters[i] to access the i'th parameter block.
-// }
-// }
-//
-// Since the sizing of the parameters is done at runtime, you must
-// also specify the sizes after creating the dynamic autodiff cost
-// function. For example:
-//
-// DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
-// new MyCostFunctor());
-// cost_function.AddParameterBlock(5);
-// cost_function.AddParameterBlock(10);
-// cost_function.SetNumResiduals(21);
-//
-// Under the hood, the implementation evaluates the cost function
-// multiple times, computing a small set of the derivatives (four by
-// default, controlled by the Stride template parameter) with each
-// pass. There is a tradeoff with the size of the passes; you may want
-// to experiment with the stride.
-
-#ifndef CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
-#define CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
-
-#include <cmath>
-#include <numeric>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/jet.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-template <typename CostFunctor, int Stride = 4>
-class DynamicAutoDiffCostFunction : public CostFunction {
- public:
- explicit DynamicAutoDiffCostFunction(CostFunctor* functor)
- : functor_(functor) {}
-
- virtual ~DynamicAutoDiffCostFunction() {}
-
- void AddParameterBlock(int size) {
- mutable_parameter_block_sizes()->push_back(size);
- }
-
- void SetNumResiduals(int num_residuals) {
- set_num_residuals(num_residuals);
- }
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- CHECK_GT(num_residuals(), 0)
- << "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
- << "before DynamicAutoDiffCostFunction::Evaluate().";
-
- if (jacobians == NULL) {
- return (*functor_)(parameters, residuals);
- }
-
- // The difficulty with Jets, as implemented in Ceres, is that they were
- // originally designed for strictly compile-sized use. At this point, there
- // is a large body of code that assumes inside a cost functor it is
- // acceptable to do e.g. T(1.5) and get an appropriately sized jet back.
- //
- // Unfortunately, it is impossible to communicate the expected size of a
- // dynamically sized jet to the static instantiations that existing code
- // depends on.
- //
- // To work around this issue, the solution here is to evaluate the
- // jacobians in a series of passes, each one computing Stripe *
- // num_residuals() derivatives. This is done with small, fixed-size jets.
- const int num_parameter_blocks = parameter_block_sizes().size();
- const int num_parameters = std::accumulate(parameter_block_sizes().begin(),
- parameter_block_sizes().end(),
- 0);
-
- // Allocate scratch space for the strided evaluation.
- vector<Jet<double, Stride> > input_jets(num_parameters);
- vector<Jet<double, Stride> > output_jets(num_residuals());
-
- // Make the parameter pack that is sent to the functor (reused).
- vector<Jet<double, Stride>* > jet_parameters(num_parameter_blocks,
- static_cast<Jet<double, Stride>* >(NULL));
- int num_active_parameters = 0;
-
- // To handle constant parameters between non-constant parameter blocks, the
- // start position --- a raw parameter index --- of each contiguous block of
- // non-constant parameters is recorded in start_derivative_section.
- vector<int> start_derivative_section;
- bool in_derivative_section = false;
- int parameter_cursor = 0;
-
- // Discover the derivative sections and set the parameter values.
- for (int i = 0; i < num_parameter_blocks; ++i) {
- jet_parameters[i] = &input_jets[parameter_cursor];
-
- const int parameter_block_size = parameter_block_sizes()[i];
- if (jacobians[i] != NULL) {
- if (!in_derivative_section) {
- start_derivative_section.push_back(parameter_cursor);
- in_derivative_section = true;
- }
-
- num_active_parameters += parameter_block_size;
- } else {
- in_derivative_section = false;
- }
-
- for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) {
- input_jets[parameter_cursor].a = parameters[i][j];
- }
- }
-
- // When `num_active_parameters % Stride != 0` then it can be the case
- // that `active_parameter_count < Stride` while parameter_cursor is less
- // than the total number of parameters and with no remaining non-constant
- // parameter blocks. Pushing parameter_cursor (the total number of
- // parameters) as a final entry to start_derivative_section is required
- // because if a constant parameter block is encountered after the
- // last non-constant block then current_derivative_section is incremented
- // and would otherwise index an invalid position in
- // start_derivative_section. Setting the final element to the total number
- // of parameters means that this can only happen at most once in the loop
- // below.
- start_derivative_section.push_back(parameter_cursor);
-
- // Evaluate all of the strides. Each stride is a chunk of the derivative to
- // evaluate, typically some size proportional to the size of the SIMD
- // registers of the CPU.
- int num_strides = static_cast<int>(ceil(num_active_parameters /
- static_cast<float>(Stride)));
-
- int current_derivative_section = 0;
- int current_derivative_section_cursor = 0;
-
- for (int pass = 0; pass < num_strides; ++pass) {
- // Set most of the jet components to zero, except for
- // non-constant #Stride parameters.
- const int initial_derivative_section = current_derivative_section;
- const int initial_derivative_section_cursor =
- current_derivative_section_cursor;
-
- int active_parameter_count = 0;
- parameter_cursor = 0;
-
- for (int i = 0; i < num_parameter_blocks; ++i) {
- for (int j = 0; j < parameter_block_sizes()[i];
- ++j, parameter_cursor++) {
- input_jets[parameter_cursor].v.setZero();
- if (active_parameter_count < Stride &&
- parameter_cursor >= (
- start_derivative_section[current_derivative_section] +
- current_derivative_section_cursor)) {
- if (jacobians[i] != NULL) {
- input_jets[parameter_cursor].v[active_parameter_count] = 1.0;
- ++active_parameter_count;
- ++current_derivative_section_cursor;
- } else {
- ++current_derivative_section;
- current_derivative_section_cursor = 0;
- }
- }
- }
- }
-
- if (!(*functor_)(&jet_parameters[0], &output_jets[0])) {
- return false;
- }
-
- // Copy the pieces of the jacobians into their final place.
- active_parameter_count = 0;
-
- current_derivative_section = initial_derivative_section;
- current_derivative_section_cursor = initial_derivative_section_cursor;
-
- for (int i = 0, parameter_cursor = 0; i < num_parameter_blocks; ++i) {
- for (int j = 0; j < parameter_block_sizes()[i];
- ++j, parameter_cursor++) {
- if (active_parameter_count < Stride &&
- parameter_cursor >= (
- start_derivative_section[current_derivative_section] +
- current_derivative_section_cursor)) {
- if (jacobians[i] != NULL) {
- for (int k = 0; k < num_residuals(); ++k) {
- jacobians[i][k * parameter_block_sizes()[i] + j] =
- output_jets[k].v[active_parameter_count];
- }
- ++active_parameter_count;
- ++current_derivative_section_cursor;
- } else {
- ++current_derivative_section;
- current_derivative_section_cursor = 0;
- }
- }
- }
- }
-
- // Only copy the residuals over once (even though we compute them on
- // every loop).
- if (pass == num_strides - 1) {
- for (int k = 0; k < num_residuals(); ++k) {
- residuals[k] = output_jets[k].a;
- }
- }
- }
- return true;
- }
-
- private:
- internal::scoped_ptr<CostFunctor> functor_;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
deleted file mode 100644
index 2b6e8260286..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
+++ /dev/null
@@ -1,265 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: mierle@gmail.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-// thadh@gmail.com (Thad Hughes)
-//
-// This numeric diff implementation differs from the one found in
-// numeric_diff_cost_function.h by supporting numericdiff on cost
-// functions with variable numbers of parameters with variable
-// sizes. With the other implementation, all the sizes (both the
-// number of parameter blocks and the size of each block) must be
-// fixed at compile time.
-//
-// The functor API differs slightly from the API for fixed size
-// numeric diff; the expected interface for the cost functors is:
-//
-// struct MyCostFunctor {
-// template<typename T>
-// bool operator()(double const* const* parameters, double* residuals) const {
-// // Use parameters[i] to access the i'th parameter block.
-// }
-// }
-//
-// Since the sizing of the parameters is done at runtime, you must
-// also specify the sizes after creating the
-// DynamicNumericDiffCostFunction. For example:
-//
-// DynamicAutoDiffCostFunction<MyCostFunctor, CENTRAL> cost_function(
-// new MyCostFunctor());
-// cost_function.AddParameterBlock(5);
-// cost_function.AddParameterBlock(10);
-// cost_function.SetNumResiduals(21);
-
-#ifndef CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
-#define CERES_PUBLIC_DYNAMIC_NUMERIC_DIFF_COST_FUNCTION_H_
-
-#include <cmath>
-#include <numeric>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/numeric_diff.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-template <typename CostFunctor, NumericDiffMethod method = CENTRAL>
-class DynamicNumericDiffCostFunction : public CostFunction {
- public:
- explicit DynamicNumericDiffCostFunction(const CostFunctor* functor,
- Ownership ownership = TAKE_OWNERSHIP,
- double relative_step_size = 1e-6)
- : functor_(functor),
- ownership_(ownership),
- relative_step_size_(relative_step_size) {
- }
-
- virtual ~DynamicNumericDiffCostFunction() {
- if (ownership_ != TAKE_OWNERSHIP) {
- functor_.release();
- }
- }
-
- void AddParameterBlock(int size) {
- mutable_parameter_block_sizes()->push_back(size);
- }
-
- void SetNumResiduals(int num_residuals) {
- set_num_residuals(num_residuals);
- }
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- CHECK_GT(num_residuals(), 0)
- << "You must call DynamicNumericDiffCostFunction::SetNumResiduals() "
- << "before DynamicNumericDiffCostFunction::Evaluate().";
-
- const vector<int32>& block_sizes = parameter_block_sizes();
- CHECK(!block_sizes.empty())
- << "You must call DynamicNumericDiffCostFunction::AddParameterBlock() "
- << "before DynamicNumericDiffCostFunction::Evaluate().";
-
- const bool status = EvaluateCostFunctor(parameters, residuals);
- if (jacobians == NULL || !status) {
- return status;
- }
-
- // Create local space for a copy of the parameters which will get mutated.
- int parameters_size = accumulate(block_sizes.begin(), block_sizes.end(), 0);
- vector<double> parameters_copy(parameters_size);
- vector<double*> parameters_references_copy(block_sizes.size());
- parameters_references_copy[0] = &parameters_copy[0];
- for (int block = 1; block < block_sizes.size(); ++block) {
- parameters_references_copy[block] = parameters_references_copy[block - 1]
- + block_sizes[block - 1];
- }
-
- // Copy the parameters into the local temp space.
- for (int block = 0; block < block_sizes.size(); ++block) {
- memcpy(parameters_references_copy[block],
- parameters[block],
- block_sizes[block] * sizeof(*parameters[block]));
- }
-
- for (int block = 0; block < block_sizes.size(); ++block) {
- if (jacobians[block] != NULL &&
- !EvaluateJacobianForParameterBlock(block_sizes[block],
- block,
- relative_step_size_,
- residuals,
- &parameters_references_copy[0],
- jacobians)) {
- return false;
- }
- }
- return true;
- }
-
- private:
- bool EvaluateJacobianForParameterBlock(const int parameter_block_size,
- const int parameter_block,
- const double relative_step_size,
- double const* residuals_at_eval_point,
- double** parameters,
- double** jacobians) const {
- using Eigen::Map;
- using Eigen::Matrix;
- using Eigen::Dynamic;
- using Eigen::RowMajor;
-
- typedef Matrix<double, Dynamic, 1> ResidualVector;
- typedef Matrix<double, Dynamic, 1> ParameterVector;
- typedef Matrix<double, Dynamic, Dynamic, RowMajor> JacobianMatrix;
-
- int num_residuals = this->num_residuals();
-
- Map<JacobianMatrix> parameter_jacobian(jacobians[parameter_block],
- num_residuals,
- parameter_block_size);
-
- // Mutate one element at a time and then restore.
- Map<ParameterVector> x_plus_delta(parameters[parameter_block],
- parameter_block_size);
- ParameterVector x(x_plus_delta);
- ParameterVector step_size = x.array().abs() * relative_step_size;
-
- // To handle cases where a paremeter is exactly zero, instead use
- // the mean step_size for the other dimensions.
- double fallback_step_size = step_size.sum() / step_size.rows();
- if (fallback_step_size == 0.0) {
- // If all the parameters are zero, there's no good answer. Use the given
- // relative step_size as absolute step_size and hope for the best.
- fallback_step_size = relative_step_size;
- }
-
- // For each parameter in the parameter block, use finite
- // differences to compute the derivative for that parameter.
- for (int j = 0; j < parameter_block_size; ++j) {
- if (step_size(j) == 0.0) {
- // The parameter is exactly zero, so compromise and use the
- // mean step_size from the other parameters. This can break in
- // many cases, but it's hard to pick a good number without
- // problem specific knowledge.
- step_size(j) = fallback_step_size;
- }
- x_plus_delta(j) = x(j) + step_size(j);
-
- ResidualVector residuals(num_residuals);
- if (!EvaluateCostFunctor(parameters, &residuals[0])) {
- // Something went wrong; bail.
- return false;
- }
-
- // Compute this column of the jacobian in 3 steps:
- // 1. Store residuals for the forward part.
- // 2. Subtract residuals for the backward (or 0) part.
- // 3. Divide out the run.
- parameter_jacobian.col(j).matrix() = residuals;
-
- double one_over_h = 1 / step_size(j);
- if (method == CENTRAL) {
- // Compute the function on the other side of x(j).
- x_plus_delta(j) = x(j) - step_size(j);
-
- if (!EvaluateCostFunctor(parameters, &residuals[0])) {
- // Something went wrong; bail.
- return false;
- }
-
- parameter_jacobian.col(j) -= residuals;
- one_over_h /= 2;
- } else {
- // Forward difference only; reuse existing residuals evaluation.
- parameter_jacobian.col(j) -=
- Map<const ResidualVector>(residuals_at_eval_point, num_residuals);
- }
- x_plus_delta(j) = x(j); // Restore x_plus_delta.
-
- // Divide out the run to get slope.
- parameter_jacobian.col(j) *= one_over_h;
- }
- return true;
- }
-
- bool EvaluateCostFunctor(double const* const* parameters,
- double* residuals) const {
- return EvaluateCostFunctorImpl(functor_.get(),
- parameters,
- residuals,
- functor_.get());
- }
-
- // Helper templates to allow evaluation of a functor or a
- // CostFunction.
- bool EvaluateCostFunctorImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const void* /* NOT USED */) const {
- return (*functor)(parameters, residuals);
- }
-
- bool EvaluateCostFunctorImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const CostFunction* /* NOT USED */) const {
- return functor->Evaluate(parameters, residuals, NULL);
- }
-
- internal::scoped_ptr<const CostFunctor> functor_;
- Ownership ownership_;
- const double relative_step_size_;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
deleted file mode 100644
index da8a4d086b8..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Portable floating point classification. The names are picked such that they
-// do not collide with macros. For example, "isnan" in C99 is a macro and hence
-// does not respect namespaces.
-//
-// TODO(keir): Finish porting!
-
-#ifndef CERES_PUBLIC_FPCLASSIFY_H_
-#define CERES_PUBLIC_FPCLASSIFY_H_
-
-#if defined(_MSC_VER)
-#include <float.h>
-#endif
-
-#include <limits>
-
-namespace ceres {
-
-#if defined(_MSC_VER)
-
-inline bool IsFinite (double x) { return _finite(x) != 0; }
-inline bool IsInfinite(double x) { return _finite(x) == 0 && _isnan(x) == 0; }
-inline bool IsNaN (double x) { return _isnan(x) != 0; }
-inline bool IsNormal (double x) {
- int classification = _fpclass(x);
- return classification == _FPCLASS_NN ||
- classification == _FPCLASS_PN;
-}
-
-#elif defined(ANDROID) && defined(_STLPORT_VERSION)
-
-// On Android, when using the STLPort, the C++ isnan and isnormal functions
-// are defined as macros.
-inline bool IsNaN (double x) { return isnan(x); }
-inline bool IsNormal (double x) { return isnormal(x); }
-// On Android NDK r6, when using STLPort, the isinf and isfinite functions are
-// not available, so reimplement them.
-inline bool IsInfinite(double x) {
- return x == std::numeric_limits<double>::infinity() ||
- x == -std::numeric_limits<double>::infinity();
-}
-inline bool IsFinite(double x) {
- return !isnan(x) && !IsInfinite(x);
-}
-
-# else
-
-// These definitions are for the normal Unix suspects.
-inline bool IsFinite (double x) { return std::isfinite(x); }
-inline bool IsInfinite(double x) { return std::isinf(x); }
-inline bool IsNaN (double x) { return std::isnan(x); }
-inline bool IsNormal (double x) { return std::isnormal(x); }
-
-#endif
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_FPCLASSIFY_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h
deleted file mode 100644
index 79ebae5f13e..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h
+++ /dev/null
@@ -1,222 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-// Copyright 2007 Google Inc. All Rights Reserved.
-//
-// Author: wjr@google.com (William Rucklidge)
-//
-// This file contains a class that exercises a cost function, to make sure
-// that it is computing reasonable derivatives. It compares the Jacobians
-// computed by the cost function with those obtained by finite
-// differences.
-
-#ifndef CERES_PUBLIC_GRADIENT_CHECKER_H_
-#define CERES_PUBLIC_GRADIENT_CHECKER_H_
-
-#include <cstddef>
-#include <algorithm>
-#include <vector>
-
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/numeric_diff_cost_function.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-// An object that exercises a cost function, to compare the answers that it
-// gives with derivatives estimated using finite differencing.
-//
-// The only likely usage of this is for testing.
-//
-// How to use: Fill in an array of pointers to parameter blocks for your
-// CostFunction, and then call Probe(). Check that the return value is
-// 'true'. See prober_test.cc for an example.
-//
-// This is templated similarly to NumericDiffCostFunction, as it internally
-// uses that.
-template <typename CostFunctionToProbe,
- int M = 0, int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0>
-class GradientChecker {
- public:
- // Here we stash some results from the probe, for later
- // inspection.
- struct GradientCheckResults {
- // Computed cost.
- Vector cost;
-
- // The sizes of these matrices are dictated by the cost function's
- // parameter and residual block sizes. Each vector's length will
- // term->parameter_block_sizes().size(), and each matrix is the
- // Jacobian of the residual with respect to the corresponding parameter
- // block.
-
- // Derivatives as computed by the cost function.
- vector<Matrix> term_jacobians;
-
- // Derivatives as computed by finite differencing.
- vector<Matrix> finite_difference_jacobians;
-
- // Infinity-norm of term_jacobians - finite_difference_jacobians.
- double error_jacobians;
- };
-
- // Checks the Jacobian computed by a cost function.
- //
- // probe_point: The parameter values at which to probe.
- // error_tolerance: A threshold for the infinity-norm difference
- // between the Jacobians. If the Jacobians differ by more than
- // this amount, then the probe fails.
- //
- // term: The cost function to test. Not retained after this call returns.
- //
- // results: On return, the two Jacobians (and other information)
- // will be stored here. May be NULL.
- //
- // Returns true if no problems are detected and the difference between the
- // Jacobians is less than error_tolerance.
- static bool Probe(double const* const* probe_point,
- double error_tolerance,
- CostFunctionToProbe *term,
- GradientCheckResults* results) {
- CHECK_NOTNULL(probe_point);
- CHECK_NOTNULL(term);
- LOG(INFO) << "-------------------- Starting Probe() --------------------";
-
- // We need a GradientCheckeresults, whether or not they supplied one.
- internal::scoped_ptr<GradientCheckResults> owned_results;
- if (results == NULL) {
- owned_results.reset(new GradientCheckResults);
- results = owned_results.get();
- }
-
- // Do a consistency check between the term and the template parameters.
- CHECK_EQ(M, term->num_residuals());
- const int num_residuals = M;
- const vector<int32>& block_sizes = term->parameter_block_sizes();
- const int num_blocks = block_sizes.size();
-
- CHECK_LE(num_blocks, 5) << "Unable to test functions that take more "
- << "than 5 parameter blocks";
- if (N0) {
- CHECK_EQ(N0, block_sizes[0]);
- CHECK_GE(num_blocks, 1);
- } else {
- CHECK_LT(num_blocks, 1);
- }
- if (N1) {
- CHECK_EQ(N1, block_sizes[1]);
- CHECK_GE(num_blocks, 2);
- } else {
- CHECK_LT(num_blocks, 2);
- }
- if (N2) {
- CHECK_EQ(N2, block_sizes[2]);
- CHECK_GE(num_blocks, 3);
- } else {
- CHECK_LT(num_blocks, 3);
- }
- if (N3) {
- CHECK_EQ(N3, block_sizes[3]);
- CHECK_GE(num_blocks, 4);
- } else {
- CHECK_LT(num_blocks, 4);
- }
- if (N4) {
- CHECK_EQ(N4, block_sizes[4]);
- CHECK_GE(num_blocks, 5);
- } else {
- CHECK_LT(num_blocks, 5);
- }
-
- results->term_jacobians.clear();
- results->term_jacobians.resize(num_blocks);
- results->finite_difference_jacobians.clear();
- results->finite_difference_jacobians.resize(num_blocks);
-
- internal::FixedArray<double*> term_jacobian_pointers(num_blocks);
- internal::FixedArray<double*>
- finite_difference_jacobian_pointers(num_blocks);
- for (int i = 0; i < num_blocks; i++) {
- results->term_jacobians[i].resize(num_residuals, block_sizes[i]);
- term_jacobian_pointers[i] = results->term_jacobians[i].data();
- results->finite_difference_jacobians[i].resize(
- num_residuals, block_sizes[i]);
- finite_difference_jacobian_pointers[i] =
- results->finite_difference_jacobians[i].data();
- }
- results->cost.resize(num_residuals, 1);
-
- CHECK(term->Evaluate(probe_point, results->cost.data(),
- term_jacobian_pointers.get()));
- NumericDiffCostFunction<CostFunctionToProbe, CENTRAL, M, N0, N1, N2, N3, N4>
- numeric_term(term, DO_NOT_TAKE_OWNERSHIP);
- CHECK(numeric_term.Evaluate(probe_point, results->cost.data(),
- finite_difference_jacobian_pointers.get()));
-
- results->error_jacobians = 0;
- for (int i = 0; i < num_blocks; i++) {
- Matrix jacobian_difference = results->term_jacobians[i] -
- results->finite_difference_jacobians[i];
- results->error_jacobians =
- std::max(results->error_jacobians,
- jacobian_difference.lpNorm<Eigen::Infinity>());
- }
-
- LOG(INFO) << "========== term-computed derivatives ==========";
- for (int i = 0; i < num_blocks; i++) {
- LOG(INFO) << "term_computed block " << i;
- LOG(INFO) << "\n" << results->term_jacobians[i];
- }
-
- LOG(INFO) << "========== finite-difference derivatives ==========";
- for (int i = 0; i < num_blocks; i++) {
- LOG(INFO) << "finite_difference block " << i;
- LOG(INFO) << "\n" << results->finite_difference_jacobians[i];
- }
-
- LOG(INFO) << "========== difference ==========";
- for (int i = 0; i < num_blocks; i++) {
- LOG(INFO) << "difference block " << i;
- LOG(INFO) << (results->term_jacobians[i] -
- results->finite_difference_jacobians[i]);
- }
-
- LOG(INFO) << "||difference|| = " << results->error_jacobians;
-
- return results->error_jacobians < error_tolerance;
- }
-
- private:
- CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker);
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_GRADIENT_CHECKER_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_problem.h b/extern/libmv/third_party/ceres/include/ceres/gradient_problem.h
deleted file mode 100644
index 55a8be1df09..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/gradient_problem.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_H_
-#define CERES_PUBLIC_GRADIENT_PROBLEM_H_
-
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/local_parameterization.h"
-
-namespace ceres {
-
-class FirstOrderFunction;
-
-// Instances of GradientProblem represent general non-linear
-// optimization problems that must be solved using just the value of
-// the objective function and its gradient. Unlike the Problem class,
-// which can only be used to model non-linear least squares problems,
-// instances of GradientProblem not restricted in the form of the
-// objective function.
-//
-// Structurally GradientProblem is a composition of a
-// FirstOrderFunction and optionally a LocalParameterization.
-//
-// The FirstOrderFunction is responsible for evaluating the cost and
-// gradient of the objective function.
-//
-// The LocalParameterization is responsible for going back and forth
-// between the ambient space and the local tangent space. (See
-// local_parameterization.h for more details). When a
-// LocalParameterization is not provided, then the tangent space is
-// assumed to coincide with the ambient Euclidean space that the
-// gradient vector lives in.
-//
-// Example usage:
-//
-// The following demonstrate the problem construction for Rosenbrock's function
-//
-// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
-//
-// class Rosenbrock : public ceres::FirstOrderFunction {
-// public:
-// virtual ~Rosenbrock() {}
-//
-// virtual bool Evaluate(const double* parameters,
-// double* cost,
-// double* gradient) const {
-// const double x = parameters[0];
-// const double y = parameters[1];
-//
-// cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
-// if (gradient != NULL) {
-// gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
-// gradient[1] = 200.0 * (y - x * x);
-// }
-// return true;
-// };
-//
-// virtual int NumParameters() const { return 2; };
-// };
-//
-// ceres::GradientProblem problem(new Rosenbrock());
-class CERES_EXPORT GradientProblem {
- public:
- // Takes ownership of the function.
- explicit GradientProblem(FirstOrderFunction* function);
-
- // Takes ownership of the function and the parameterization.
- GradientProblem(FirstOrderFunction* function,
- LocalParameterization* parameterization);
-
- int NumParameters() const;
- int NumLocalParameters() const;
-
- // This call is not thread safe.
- bool Evaluate(const double* parameters, double* cost, double* gradient) const;
- bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
-
- private:
- internal::scoped_ptr<FirstOrderFunction> function_;
- internal::scoped_ptr<LocalParameterization> parameterization_;
- internal::scoped_array<double> scratch_;
-};
-
-// A FirstOrderFunction object implements the evaluation of a function
-// and its gradient.
-class CERES_EXPORT FirstOrderFunction {
- public:
- virtual ~FirstOrderFunction() {}
- // cost is never NULL. gradient may be null.
- virtual bool Evaluate(const double* const parameters,
- double* cost,
- double* gradient) const = 0;
- virtual int NumParameters() const = 0;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_GRADIENT_PROBLEM_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h b/extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h
deleted file mode 100644
index db706f7dbaf..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/gradient_problem_solver.h
+++ /dev/null
@@ -1,353 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
-#define CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
-
-#include <cmath>
-#include <string>
-#include <vector>
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/iteration_callback.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-class GradientProblem;
-
-class CERES_EXPORT GradientProblemSolver {
- public:
- virtual ~GradientProblemSolver();
-
- // The options structure contains, not surprisingly, options that control how
- // the solver operates. The defaults should be suitable for a wide range of
- // problems; however, better performance is often obtainable with tweaking.
- //
- // The constants are defined inside types.h
- struct CERES_EXPORT Options {
- // Default constructor that sets up a generic sparse problem.
- Options() {
- line_search_direction_type = LBFGS;
- line_search_type = WOLFE;
- nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
- max_lbfgs_rank = 20;
- use_approximate_eigenvalue_bfgs_scaling = false;
- line_search_interpolation_type = CUBIC;
- min_line_search_step_size = 1e-9;
- line_search_sufficient_function_decrease = 1e-4;
- max_line_search_step_contraction = 1e-3;
- min_line_search_step_contraction = 0.6;
- max_num_line_search_step_size_iterations = 20;
- max_num_line_search_direction_restarts = 5;
- line_search_sufficient_curvature_decrease = 0.9;
- max_line_search_step_expansion = 10.0;
- max_num_iterations = 50;
- max_solver_time_in_seconds = 1e9;
- function_tolerance = 1e-6;
- gradient_tolerance = 1e-10;
- logging_type = PER_MINIMIZER_ITERATION;
- minimizer_progress_to_stdout = false;
- }
-
- // Returns true if the options struct has a valid
- // configuration. Returns false otherwise, and fills in *error
- // with a message describing the problem.
- bool IsValid(string* error) const;
-
- // Minimizer options ----------------------------------------
- LineSearchDirectionType line_search_direction_type;
- LineSearchType line_search_type;
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
-
- // The LBFGS hessian approximation is a low rank approximation to
- // the inverse of the Hessian matrix. The rank of the
- // approximation determines (linearly) the space and time
- // complexity of using the approximation. Higher the rank, the
- // better is the quality of the approximation. The increase in
- // quality is however is bounded for a number of reasons.
- //
- // 1. The method only uses secant information and not actual
- // derivatives.
- //
- // 2. The Hessian approximation is constrained to be positive
- // definite.
- //
- // So increasing this rank to a large number will cost time and
- // space complexity without the corresponding increase in solution
- // quality. There are no hard and fast rules for choosing the
- // maximum rank. The best choice usually requires some problem
- // specific experimentation.
- //
- // For more theoretical and implementation details of the LBFGS
- // method, please see:
- //
- // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
- // Limited Storage". Mathematics of Computation 35 (151): 773–782.
- int max_lbfgs_rank;
-
- // As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
- // the initial inverse Hessian approximation is taken to be the Identity.
- // However, Oren showed that using instead I * \gamma, where \gamma is
- // chosen to approximate an eigenvalue of the true inverse Hessian can
- // result in improved convergence in a wide variety of cases. Setting
- // use_approximate_eigenvalue_bfgs_scaling to true enables this scaling.
- //
- // It is important to note that approximate eigenvalue scaling does not
- // always improve convergence, and that it can in fact significantly degrade
- // performance for certain classes of problem, which is why it is disabled
- // by default. In particular it can degrade performance when the
- // sensitivity of the problem to different parameters varies significantly,
- // as in this case a single scalar factor fails to capture this variation
- // and detrimentally downscales parts of the jacobian approximation which
- // correspond to low-sensitivity parameters. It can also reduce the
- // robustness of the solution to errors in the jacobians.
- //
- // Oren S.S., Self-scaling variable metric (SSVM) algorithms
- // Part II: Implementation and experiments, Management Science,
- // 20(5), 863-874, 1974.
- bool use_approximate_eigenvalue_bfgs_scaling;
-
- // Degree of the polynomial used to approximate the objective
- // function. Valid values are BISECTION, QUADRATIC and CUBIC.
- //
- // BISECTION corresponds to pure backtracking search with no
- // interpolation.
- LineSearchInterpolationType line_search_interpolation_type;
-
- // If during the line search, the step_size falls below this
- // value, it is truncated to zero.
- double min_line_search_step_size;
-
- // Line search parameters.
-
- // Solving the line search problem exactly is computationally
- // prohibitive. Fortunately, line search based optimization
- // algorithms can still guarantee convergence if instead of an
- // exact solution, the line search algorithm returns a solution
- // which decreases the value of the objective function
- // sufficiently. More precisely, we are looking for a step_size
- // s.t.
- //
- // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
- //
- double line_search_sufficient_function_decrease;
-
- // In each iteration of the line search,
- //
- // new_step_size >= max_line_search_step_contraction * step_size
- //
- // Note that by definition, for contraction:
- //
- // 0 < max_step_contraction < min_step_contraction < 1
- //
- double max_line_search_step_contraction;
-
- // In each iteration of the line search,
- //
- // new_step_size <= min_line_search_step_contraction * step_size
- //
- // Note that by definition, for contraction:
- //
- // 0 < max_step_contraction < min_step_contraction < 1
- //
- double min_line_search_step_contraction;
-
- // Maximum number of trial step size iterations during each line search,
- // if a step size satisfying the search conditions cannot be found within
- // this number of trials, the line search will terminate.
- int max_num_line_search_step_size_iterations;
-
- // Maximum number of restarts of the line search direction algorithm before
- // terminating the optimization. Restarts of the line search direction
- // algorithm occur when the current algorithm fails to produce a new descent
- // direction. This typically indicates a numerical failure, or a breakdown
- // in the validity of the approximations used.
- int max_num_line_search_direction_restarts;
-
- // The strong Wolfe conditions consist of the Armijo sufficient
- // decrease condition, and an additional requirement that the
- // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
- // conditions) of the gradient along the search direction
- // decreases sufficiently. Precisely, this second condition
- // is that we seek a step_size s.t.
- //
- // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
- //
- // Where f() is the line search objective and f'() is the derivative
- // of f w.r.t step_size (d f / d step_size).
- double line_search_sufficient_curvature_decrease;
-
- // During the bracketing phase of the Wolfe search, the step size is
- // increased until either a point satisfying the Wolfe conditions is
- // found, or an upper bound for a bracket containing a point satisfying
- // the conditions is found. Precisely, at each iteration of the
- // expansion:
- //
- // new_step_size <= max_step_expansion * step_size.
- //
- // By definition for expansion, max_step_expansion > 1.0.
- double max_line_search_step_expansion;
-
- // Maximum number of iterations for the minimizer to run for.
- int max_num_iterations;
-
- // Maximum time for which the minimizer should run for.
- double max_solver_time_in_seconds;
-
- // Minimizer terminates when
- //
- // (new_cost - old_cost) < function_tolerance * old_cost;
- //
- double function_tolerance;
-
- // Minimizer terminates when
- //
- // max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
- //
- // This value should typically be 1e-4 * function_tolerance.
- double gradient_tolerance;
-
- // Logging options ---------------------------------------------------------
-
- LoggingType logging_type;
-
- // By default the Minimizer progress is logged to VLOG(1), which
- // is sent to STDERR depending on the vlog level. If this flag is
- // set to true, and logging_type is not SILENT, the logging output
- // is sent to STDOUT.
- bool minimizer_progress_to_stdout;
-
- // Callbacks that are executed at the end of each iteration of the
- // Minimizer. An iteration may terminate midway, either due to
- // numerical failures or because one of the convergence tests has
- // been satisfied. In this case none of the callbacks are
- // executed.
-
- // Callbacks are executed in the order that they are specified in
- // this vector. By default, parameter blocks are updated only at
- // the end of the optimization, i.e when the Minimizer
- // terminates. This behaviour is controlled by
- // update_state_every_variable. If the user wishes to have access
- // to the update parameter blocks when his/her callbacks are
- // executed, then set update_state_every_iteration to true.
- //
- // The solver does NOT take ownership of these pointers.
- vector<IterationCallback*> callbacks;
- };
-
- struct CERES_EXPORT Summary {
- Summary();
-
- // A brief one line description of the state of the solver after
- // termination.
- string BriefReport() const;
-
- // A full multiline description of the state of the solver after
- // termination.
- string FullReport() const;
-
- bool IsSolutionUsable() const;
-
- // Minimizer summary -------------------------------------------------
- TerminationType termination_type;
-
- // Reason why the solver terminated.
- string message;
-
- // Cost of the problem (value of the objective function) before
- // the optimization.
- double initial_cost;
-
- // Cost of the problem (value of the objective function) after the
- // optimization.
- double final_cost;
-
- // IterationSummary for each minimizer iteration in order.
- vector<IterationSummary> iterations;
-
- // Sum total of all time spent inside Ceres when Solve is called.
- double total_time_in_seconds;
-
- // Time (in seconds) spent evaluating the cost.
- double cost_evaluation_time_in_seconds;
-
- // Time (in seconds) spent evaluating the gradient.
- double gradient_evaluation_time_in_seconds;
-
- // Number of parameters in the probem.
- int num_parameters;
-
- // Dimension of the tangent space of the problem.
- int num_local_parameters;
-
- // Type of line search direction used.
- LineSearchDirectionType line_search_direction_type;
-
- // Type of the line search algorithm used.
- LineSearchType line_search_type;
-
- // When performing line search, the degree of the polynomial used
- // to approximate the objective function.
- LineSearchInterpolationType line_search_interpolation_type;
-
- // If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
- // then this indicates the particular variant of non-linear
- // conjugate gradient used.
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
-
- // If the type of the line search direction is LBFGS, then this
- // indicates the rank of the Hessian approximation.
- int max_lbfgs_rank;
- };
-
- // Once a least squares problem has been built, this function takes
- // the problem and optimizes it based on the values of the options
- // parameters. Upon return, a detailed summary of the work performed
- // by the preprocessor, the non-linear minmizer and the linear
- // solver are reported in the summary object.
- virtual void Solve(const GradientProblemSolver::Options& options,
- const GradientProblem& problem,
- double* parameters,
- GradientProblemSolver::Summary* summary);
-};
-
-// Helper function which avoids going through the interface.
-CERES_EXPORT void Solve(const GradientProblemSolver::Options& options,
- const GradientProblem& problem,
- double* parameters,
- GradientProblemSolver::Summary* summary);
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_GRADIENT_PROBLEM_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
deleted file mode 100644
index 3a96625e3fd..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
+++ /dev/null
@@ -1,317 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Computation of the Jacobian matrix for vector-valued functions of multiple
-// variables, using automatic differentiation based on the implementation of
-// dual numbers in jet.h. Before reading the rest of this file, it is adivsable
-// to read jet.h's header comment in detail.
-//
-// The helper wrapper AutoDiff::Differentiate() computes the jacobian of
-// functors with templated operator() taking this form:
-//
-// struct F {
-// template<typename T>
-// bool operator()(const T *x, const T *y, ..., T *z) {
-// // Compute z[] based on x[], y[], ...
-// // return true if computation succeeded, false otherwise.
-// }
-// };
-//
-// All inputs and outputs may be vector-valued.
-//
-// To understand how jets are used to compute the jacobian, a
-// picture may help. Consider a vector-valued function, F, returning 3
-// dimensions and taking a vector-valued parameter of 4 dimensions:
-//
-// y x
-// [ * ] F [ * ]
-// [ * ] <--- [ * ]
-// [ * ] [ * ]
-// [ * ]
-//
-// Similar to the 2-parameter example for f described in jet.h, computing the
-// jacobian dy/dx is done by substutiting a suitable jet object for x and all
-// intermediate steps of the computation of F. Since x is has 4 dimensions, use
-// a Jet<double, 4>.
-//
-// Before substituting a jet object for x, the dual components are set
-// appropriately for each dimension of x:
-//
-// y x
-// [ * | * * * * ] f [ * | 1 0 0 0 ] x0
-// [ * | * * * * ] <--- [ * | 0 1 0 0 ] x1
-// [ * | * * * * ] [ * | 0 0 1 0 ] x2
-// ---+--- [ * | 0 0 0 1 ] x3
-// | ^ ^ ^ ^
-// dy/dx | | | +----- infinitesimal for x3
-// | | +------- infinitesimal for x2
-// | +--------- infinitesimal for x1
-// +----------- infinitesimal for x0
-//
-// The reason to set the internal 4x4 submatrix to the identity is that we wish
-// to take the derivative of y separately with respect to each dimension of x.
-// Each column of the 4x4 identity is therefore for a single component of the
-// independent variable x.
-//
-// Then the jacobian of the mapping, dy/dx, is the 3x4 sub-matrix of the
-// extended y vector, indicated in the above diagram.
-//
-// Functors with multiple parameters
-// ---------------------------------
-// In practice, it is often convenient to use a function f of two or more
-// vector-valued parameters, for example, x[3] and z[6]. Unfortunately, the jet
-// framework is designed for a single-parameter vector-valued input. The wrapper
-// in this file addresses this issue adding support for functions with one or
-// more parameter vectors.
-//
-// To support multiple parameters, all the parameter vectors are concatenated
-// into one and treated as a single parameter vector, except that since the
-// functor expects different inputs, we need to construct the jets as if they
-// were part of a single parameter vector. The extended jets are passed
-// separately for each parameter.
-//
-// For example, consider a functor F taking two vector parameters, p[2] and
-// q[3], and producing an output y[4]:
-//
-// struct F {
-// template<typename T>
-// bool operator()(const T *p, const T *q, T *z) {
-// // ...
-// }
-// };
-//
-// In this case, the necessary jet type is Jet<double, 5>. Here is a
-// visualization of the jet objects in this case:
-//
-// Dual components for p ----+
-// |
-// -+-
-// y [ * | 1 0 | 0 0 0 ] --- p[0]
-// [ * | 0 1 | 0 0 0 ] --- p[1]
-// [ * | . . | + + + ] |
-// [ * | . . | + + + ] v
-// [ * | . . | + + + ] <--- F(p, q)
-// [ * | . . | + + + ] ^
-// ^^^ ^^^^^ |
-// dy/dp dy/dq [ * | 0 0 | 1 0 0 ] --- q[0]
-// [ * | 0 0 | 0 1 0 ] --- q[1]
-// [ * | 0 0 | 0 0 1 ] --- q[2]
-// --+--
-// |
-// Dual components for q --------------+
-//
-// where the 4x2 submatrix (marked with ".") and 4x3 submatrix (marked with "+"
-// of y in the above diagram are the derivatives of y with respect to p and q
-// respectively. This is how autodiff works for functors taking multiple vector
-// valued arguments (up to 6).
-//
-// Jacobian NULL pointers
-// ----------------------
-// In general, the functions below will accept NULL pointers for all or some of
-// the Jacobian parameters, meaning that those Jacobians will not be computed.
-
-#ifndef CERES_PUBLIC_INTERNAL_AUTODIFF_H_
-#define CERES_PUBLIC_INTERNAL_AUTODIFF_H_
-
-#include <stddef.h>
-
-#include "ceres/jet.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/variadic_evaluate.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// Extends src by a 1st order pertubation for every dimension and puts it in
-// dst. The size of src is N. Since this is also used for perturbations in
-// blocked arrays, offset is used to shift which part of the jet the
-// perturbation occurs. This is used to set up the extended x augmented by an
-// identity matrix. The JetT type should be a Jet type, and T should be a
-// numeric type (e.g. double). For example,
-//
-// 0 1 2 3 4 5 6 7 8
-// dst[0] [ * | . . | 1 0 0 | . . . ]
-// dst[1] [ * | . . | 0 1 0 | . . . ]
-// dst[2] [ * | . . | 0 0 1 | . . . ]
-//
-// is what would get put in dst if N was 3, offset was 3, and the jet type JetT
-// was 8-dimensional.
-template <typename JetT, typename T, int N>
-inline void Make1stOrderPerturbation(int offset, const T* src, JetT* dst) {
- DCHECK(src);
- DCHECK(dst);
- for (int j = 0; j < N; ++j) {
- dst[j].a = src[j];
- dst[j].v.setZero();
- dst[j].v[offset + j] = T(1.0);
- }
-}
-
-// Takes the 0th order part of src, assumed to be a Jet type, and puts it in
-// dst. This is used to pick out the "vector" part of the extended y.
-template <typename JetT, typename T>
-inline void Take0thOrderPart(int M, const JetT *src, T dst) {
- DCHECK(src);
- for (int i = 0; i < M; ++i) {
- dst[i] = src[i].a;
- }
-}
-
-// Takes N 1st order parts, starting at index N0, and puts them in the M x N
-// matrix 'dst'. This is used to pick out the "matrix" parts of the extended y.
-template <typename JetT, typename T, int N0, int N>
-inline void Take1stOrderPart(const int M, const JetT *src, T *dst) {
- DCHECK(src);
- DCHECK(dst);
- for (int i = 0; i < M; ++i) {
- Eigen::Map<Eigen::Matrix<T, N, 1> >(dst + N * i, N) =
- src[i].v.template segment<N>(N0);
- }
-}
-
-// This is in a struct because default template parameters on a
-// function are not supported in C++03 (though it is available in
-// C++0x). N0 through N5 are the dimension of the input arguments to
-// the user supplied functor.
-template <typename Functor, typename T,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
- int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
-struct AutoDiff {
- static bool Differentiate(const Functor& functor,
- T const *const *parameters,
- int num_outputs,
- T *function_value,
- T **jacobians) {
- // This block breaks the 80 column rule to keep it somewhat readable.
- DCHECK_GT(num_outputs, 0);
- DCHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0)))
- << "Zero block cannot precede a non-zero block. Block sizes are "
- << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
- << N8 << ", " << N9;
-
- typedef Jet<T, N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9> JetT;
- FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(
- N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9 + num_outputs);
-
- // These are the positions of the respective jets in the fixed array x.
- const int jet0 = 0;
- const int jet1 = N0;
- const int jet2 = N0 + N1;
- const int jet3 = N0 + N1 + N2;
- const int jet4 = N0 + N1 + N2 + N3;
- const int jet5 = N0 + N1 + N2 + N3 + N4;
- const int jet6 = N0 + N1 + N2 + N3 + N4 + N5;
- const int jet7 = N0 + N1 + N2 + N3 + N4 + N5 + N6;
- const int jet8 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7;
- const int jet9 = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8;
-
- const JetT *unpacked_parameters[10] = {
- x.get() + jet0,
- x.get() + jet1,
- x.get() + jet2,
- x.get() + jet3,
- x.get() + jet4,
- x.get() + jet5,
- x.get() + jet6,
- x.get() + jet7,
- x.get() + jet8,
- x.get() + jet9,
- };
-
- JetT* output = x.get() + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
-
-#define CERES_MAKE_1ST_ORDER_PERTURBATION(i) \
- if (N ## i) { \
- internal::Make1stOrderPerturbation<JetT, T, N ## i>( \
- jet ## i, \
- parameters[i], \
- x.get() + jet ## i); \
- }
- CERES_MAKE_1ST_ORDER_PERTURBATION(0);
- CERES_MAKE_1ST_ORDER_PERTURBATION(1);
- CERES_MAKE_1ST_ORDER_PERTURBATION(2);
- CERES_MAKE_1ST_ORDER_PERTURBATION(3);
- CERES_MAKE_1ST_ORDER_PERTURBATION(4);
- CERES_MAKE_1ST_ORDER_PERTURBATION(5);
- CERES_MAKE_1ST_ORDER_PERTURBATION(6);
- CERES_MAKE_1ST_ORDER_PERTURBATION(7);
- CERES_MAKE_1ST_ORDER_PERTURBATION(8);
- CERES_MAKE_1ST_ORDER_PERTURBATION(9);
-#undef CERES_MAKE_1ST_ORDER_PERTURBATION
-
- if (!VariadicEvaluate<Functor, JetT,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
- functor, unpacked_parameters, output)) {
- return false;
- }
-
- internal::Take0thOrderPart(num_outputs, output, function_value);
-
-#define CERES_TAKE_1ST_ORDER_PERTURBATION(i) \
- if (N ## i) { \
- if (jacobians[i]) { \
- internal::Take1stOrderPart<JetT, T, \
- jet ## i, \
- N ## i>(num_outputs, \
- output, \
- jacobians[i]); \
- } \
- }
- CERES_TAKE_1ST_ORDER_PERTURBATION(0);
- CERES_TAKE_1ST_ORDER_PERTURBATION(1);
- CERES_TAKE_1ST_ORDER_PERTURBATION(2);
- CERES_TAKE_1ST_ORDER_PERTURBATION(3);
- CERES_TAKE_1ST_ORDER_PERTURBATION(4);
- CERES_TAKE_1ST_ORDER_PERTURBATION(5);
- CERES_TAKE_1ST_ORDER_PERTURBATION(6);
- CERES_TAKE_1ST_ORDER_PERTURBATION(7);
- CERES_TAKE_1ST_ORDER_PERTURBATION(8);
- CERES_TAKE_1ST_ORDER_PERTURBATION(9);
-#undef CERES_TAKE_1ST_ORDER_PERTURBATION
- return true;
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_AUTODIFF_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h b/extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h
deleted file mode 100644
index 78924de1346..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/disable_warnings.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// This file has the sole purpose to silence warnings when including Ceres.
-
-// This is not your usual header guard. The macro CERES_WARNINGS_DISABLED
-// shows up again in reenable_warnings.h.
-#ifndef CERES_WARNINGS_DISABLED
-#define CERES_WARNINGS_DISABLED
-
-#ifdef _MSC_VER
-#pragma warning( push )
-// Disable the warning C4251 which is trigerred by stl classes in
-// Ceres' public interface. To quote MSDN: "C4251 can be ignored "
-// "if you are deriving from a type in the Standard C++ Library"
-#pragma warning( disable : 4251 )
-#endif
-
-#endif // CERES_WARNINGS_DISABLED
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/eigen.h b/extern/libmv/third_party/ceres/include/ceres/internal/eigen.h
deleted file mode 100644
index 85df54b8f99..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/eigen.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_EIGEN_H_
-#define CERES_INTERNAL_EIGEN_H_
-
-#include "Eigen/Core"
-
-namespace ceres {
-
-typedef Eigen::Matrix<double, Eigen::Dynamic, 1> Vector;
-typedef Eigen::Matrix<double,
- Eigen::Dynamic,
- Eigen::Dynamic,
- Eigen::RowMajor> Matrix;
-typedef Eigen::Map<Vector> VectorRef;
-typedef Eigen::Map<Matrix> MatrixRef;
-typedef Eigen::Map<const Vector> ConstVectorRef;
-typedef Eigen::Map<const Matrix> ConstMatrixRef;
-
-// Column major matrices for DenseSparseMatrix/DenseQRSolver
-typedef Eigen::Matrix<double,
- Eigen::Dynamic,
- Eigen::Dynamic,
- Eigen::ColMajor> ColMajorMatrix;
-
-typedef Eigen::Map<ColMajorMatrix, 0,
- Eigen::Stride<Eigen::Dynamic, 1> > ColMajorMatrixRef;
-
-typedef Eigen::Map<const ColMajorMatrix,
- 0,
- Eigen::Stride<Eigen::Dynamic, 1> > ConstColMajorMatrixRef;
-
-
-
-// C++ does not support templated typdefs, thus the need for this
-// struct so that we can support statically sized Matrix and Maps.
-template <int num_rows = Eigen::Dynamic, int num_cols = Eigen::Dynamic>
-struct EigenTypes {
- typedef Eigen::Matrix <double, num_rows, num_cols, Eigen::RowMajor>
- Matrix;
-
- typedef Eigen::Map<
- Eigen::Matrix<double, num_rows, num_cols, Eigen::RowMajor> >
- MatrixRef;
-
- typedef Eigen::Matrix <double, num_rows, 1>
- Vector;
-
- typedef Eigen::Map <
- Eigen::Matrix<double, num_rows, 1> >
- VectorRef;
-
-
- typedef Eigen::Map<
- const Eigen::Matrix<double, num_rows, num_cols, Eigen::RowMajor> >
- ConstMatrixRef;
-
- typedef Eigen::Map <
- const Eigen::Matrix<double, num_rows, 1> >
- ConstVectorRef;
-};
-
-} // namespace ceres
-
-#endif // CERES_INTERNAL_EIGEN_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
deleted file mode 100644
index 694070b228c..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: rennie@google.com (Jeffrey Rennie)
-// Author: sanjay@google.com (Sanjay Ghemawat) -- renamed to FixedArray
-
-#ifndef CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
-#define CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
-
-#include <cstddef>
-#include "Eigen/Core"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/manual_constructor.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// A FixedArray<T> represents a non-resizable array of T where the
-// length of the array does not need to be a compile time constant.
-//
-// FixedArray allocates small arrays inline, and large arrays on
-// the heap. It is a good replacement for non-standard and deprecated
-// uses of alloca() and variable length arrays (a GCC extension).
-//
-// FixedArray keeps performance fast for small arrays, because it
-// avoids heap operations. It also helps reduce the chances of
-// accidentally overflowing your stack if large input is passed to
-// your function.
-//
-// Also, FixedArray is useful for writing portable code. Not all
-// compilers support arrays of dynamic size.
-
-// Most users should not specify an inline_elements argument and let
-// FixedArray<> automatically determine the number of elements
-// to store inline based on sizeof(T).
-//
-// If inline_elements is specified, the FixedArray<> implementation
-// will store arrays of length <= inline_elements inline.
-//
-// Finally note that unlike vector<T> FixedArray<T> will not zero-initialize
-// simple types like int, double, bool, etc.
-//
-// Non-POD types will be default-initialized just like regular vectors or
-// arrays.
-
-#if defined(_WIN64)
- typedef __int64 ssize_t;
-#elif defined(_WIN32)
- typedef __int32 ssize_t;
-#endif
-
-template <typename T, ssize_t inline_elements = -1>
-class FixedArray {
- public:
- // For playing nicely with stl:
- typedef T value_type;
- typedef T* iterator;
- typedef T const* const_iterator;
- typedef T& reference;
- typedef T const& const_reference;
- typedef T* pointer;
- typedef std::ptrdiff_t difference_type;
- typedef size_t size_type;
-
- // REQUIRES: n >= 0
- // Creates an array object that can store "n" elements.
- //
- // FixedArray<T> will not zero-initialiaze POD (simple) types like int,
- // double, bool, etc.
- // Non-POD types will be default-initialized just like regular vectors or
- // arrays.
- explicit FixedArray(size_type n);
-
- // Releases any resources.
- ~FixedArray();
-
- // Returns the length of the array.
- inline size_type size() const { return size_; }
-
- // Returns the memory size of the array in bytes.
- inline size_t memsize() const { return size_ * sizeof(T); }
-
- // Returns a pointer to the underlying element array.
- inline const T* get() const { return &array_[0].element; }
- inline T* get() { return &array_[0].element; }
-
- // REQUIRES: 0 <= i < size()
- // Returns a reference to the "i"th element.
- inline T& operator[](size_type i) {
- DCHECK_LT(i, size_);
- return array_[i].element;
- }
-
- // REQUIRES: 0 <= i < size()
- // Returns a reference to the "i"th element.
- inline const T& operator[](size_type i) const {
- DCHECK_LT(i, size_);
- return array_[i].element;
- }
-
- inline iterator begin() { return &array_[0].element; }
- inline iterator end() { return &array_[size_].element; }
-
- inline const_iterator begin() const { return &array_[0].element; }
- inline const_iterator end() const { return &array_[size_].element; }
-
- private:
- // Container to hold elements of type T. This is necessary to handle
- // the case where T is a a (C-style) array. The size of InnerContainer
- // and T must be the same, otherwise callers' assumptions about use
- // of this code will be broken.
- struct InnerContainer {
- T element;
- };
-
- // How many elements should we store inline?
- // a. If not specified, use a default of 256 bytes (256 bytes
- // seems small enough to not cause stack overflow or unnecessary
- // stack pollution, while still allowing stack allocation for
- // reasonably long character arrays.
- // b. Never use 0 length arrays (not ISO C++)
- static const size_type S1 = ((inline_elements < 0)
- ? (256/sizeof(T)) : inline_elements);
- static const size_type S2 = (S1 <= 0) ? 1 : S1;
- static const size_type kInlineElements = S2;
-
- size_type const size_;
- InnerContainer* const array_;
-
- // Allocate some space, not an array of elements of type T, so that we can
- // skip calling the T constructors and destructors for space we never use.
- ManualConstructor<InnerContainer> inline_space_[kInlineElements];
-};
-
-// Implementation details follow
-
-template <class T, ssize_t S>
-inline FixedArray<T, S>::FixedArray(typename FixedArray<T, S>::size_type n)
- : size_(n),
- array_((n <= kInlineElements
- ? reinterpret_cast<InnerContainer*>(inline_space_)
- : new InnerContainer[n])) {
- // Construct only the elements actually used.
- if (array_ == reinterpret_cast<InnerContainer*>(inline_space_)) {
- for (size_t i = 0; i != size_; ++i) {
- inline_space_[i].Init();
- }
- }
-}
-
-template <class T, ssize_t S>
-inline FixedArray<T, S>::~FixedArray() {
- if (array_ != reinterpret_cast<InnerContainer*>(inline_space_)) {
- delete[] array_;
- } else {
- for (size_t i = 0; i != size_; ++i) {
- inline_space_[i].Destroy();
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
deleted file mode 100644
index 1ed55be6e03..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
+++ /dev/null
@@ -1,170 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-//
-// Various Google-specific macros.
-//
-// This code is compiled directly on many platforms, including client
-// platforms like Windows, Mac, and embedded systems. Before making
-// any changes here, make sure that you're not breaking any platforms.
-
-#ifndef CERES_PUBLIC_INTERNAL_MACROS_H_
-#define CERES_PUBLIC_INTERNAL_MACROS_H_
-
-#include <cstddef> // For size_t.
-
-// A macro to disallow the copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-//
-// For disallowing only assign or copy, write the code directly, but declare
-// the intend in a comment, for example:
-//
-// void operator=(const TypeName&); // _DISALLOW_ASSIGN
-
-// Note, that most uses of CERES_DISALLOW_ASSIGN and CERES_DISALLOW_COPY
-// are broken semantically, one should either use disallow both or
-// neither. Try to avoid these in new code.
-#define CERES_DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
-// A macro to disallow all the implicit constructors, namely the
-// default constructor, copy constructor and operator= functions.
-//
-// This should be used in the private: declarations for a class
-// that wants to prevent anyone from instantiating it. This is
-// especially useful for classes containing only static methods.
-#define CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
- TypeName(); \
- CERES_DISALLOW_COPY_AND_ASSIGN(TypeName)
-
-// The arraysize(arr) macro returns the # of elements in an array arr.
-// The expression is a compile-time constant, and therefore can be
-// used in defining new arrays, for example. If you use arraysize on
-// a pointer by mistake, you will get a compile-time error.
-//
-// One caveat is that arraysize() doesn't accept any array of an
-// anonymous type or a type defined inside a function. In these rare
-// cases, you have to use the unsafe ARRAYSIZE() macro below. This is
-// due to a limitation in C++'s template system. The limitation might
-// eventually be removed, but it hasn't happened yet.
-
-// This template function declaration is used in defining arraysize.
-// Note that the function doesn't need an implementation, as we only
-// use its type.
-template <typename T, size_t N>
-char (&ArraySizeHelper(T (&array)[N]))[N];
-
-// That gcc wants both of these prototypes seems mysterious. VC, for
-// its part, can't decide which to use (another mystery). Matching of
-// template overloads: the final frontier.
-#ifndef _WIN32
-template <typename T, size_t N>
-char (&ArraySizeHelper(const T (&array)[N]))[N];
-#endif
-
-#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-
-// ARRAYSIZE performs essentially the same calculation as arraysize,
-// but can be used on anonymous types or types defined inside
-// functions. It's less safe than arraysize as it accepts some
-// (although not all) pointers. Therefore, you should use arraysize
-// whenever possible.
-//
-// The expression ARRAYSIZE(a) is a compile-time constant of type
-// size_t.
-//
-// ARRAYSIZE catches a few type errors. If you see a compiler error
-//
-// "warning: division by zero in ..."
-//
-// when using ARRAYSIZE, you are (wrongfully) giving it a pointer.
-// You should only use ARRAYSIZE on statically allocated arrays.
-//
-// The following comments are on the implementation details, and can
-// be ignored by the users.
-//
-// ARRAYSIZE(arr) works by inspecting sizeof(arr) (the # of bytes in
-// the array) and sizeof(*(arr)) (the # of bytes in one array
-// element). If the former is divisible by the latter, perhaps arr is
-// indeed an array, in which case the division result is the # of
-// elements in the array. Otherwise, arr cannot possibly be an array,
-// and we generate a compiler error to prevent the code from
-// compiling.
-//
-// Since the size of bool is implementation-defined, we need to cast
-// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
-// result has type size_t.
-//
-// This macro is not perfect as it wrongfully accepts certain
-// pointers, namely where the pointer size is divisible by the pointee
-// size. Since all our code has to go through a 32-bit compiler,
-// where a pointer is 4 bytes, this means all pointers to a type whose
-// size is 3 or greater than 4 will be (righteously) rejected.
-//
-// Kudos to Jorg Brown for this simple and elegant implementation.
-//
-// - wan 2005-11-16
-//
-// Starting with Visual C++ 2005, WinNT.h includes ARRAYSIZE. However,
-// the definition comes from the over-broad windows.h header that
-// introduces a macro, ERROR, that conflicts with the logging framework
-// that Ceres uses. Instead, rename ARRAYSIZE to CERES_ARRAYSIZE.
-#define CERES_ARRAYSIZE(a) \
- ((sizeof(a) / sizeof(*(a))) / \
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-
-// Tell the compiler to warn about unused return values for functions
-// declared with this macro. The macro should be used on function
-// declarations following the argument list:
-//
-// Sprocket* AllocateSprocket() MUST_USE_RESULT;
-//
-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
- && !defined(COMPILER_ICC)
-#define CERES_MUST_USE_RESULT __attribute__ ((warn_unused_result))
-#else
-#define CERES_MUST_USE_RESULT
-#endif
-
-// Platform independent macros to get aligned memory allocations.
-// For example
-//
-// MyFoo my_foo CERES_ALIGN_ATTRIBUTE(16);
-//
-// Gives us an instance of MyFoo which is aligned at a 16 byte
-// boundary.
-#if defined(_MSC_VER)
-#define CERES_ALIGN_ATTRIBUTE(n) __declspec(align(n))
-#define CERES_ALIGN_OF(T) __alignof(T)
-#elif defined(__GNUC__)
-#define CERES_ALIGN_ATTRIBUTE(n) __attribute__((aligned(n)))
-#define CERES_ALIGN_OF(T) __alignof(T)
-#endif
-
-#endif // CERES_PUBLIC_INTERNAL_MACROS_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
deleted file mode 100644
index 7ea723d2a83..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: kenton@google.com (Kenton Varda)
-//
-// ManualConstructor statically-allocates space in which to store some
-// object, but does not initialize it. You can then call the constructor
-// and destructor for the object yourself as you see fit. This is useful
-// for memory management optimizations, where you want to initialize and
-// destroy an object multiple times but only allocate it once.
-//
-// (When I say ManualConstructor statically allocates space, I mean that
-// the ManualConstructor object itself is forced to be the right size.)
-
-#ifndef CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
-#define CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
-
-#include <new>
-
-namespace ceres {
-namespace internal {
-
-// ------- Define CERES_ALIGNED_CHAR_ARRAY --------------------------------
-
-#ifndef CERES_ALIGNED_CHAR_ARRAY
-
-// Because MSVC and older GCCs require that the argument to their alignment
-// construct to be a literal constant integer, we use a template instantiated
-// at all the possible powers of two.
-template<int alignment, int size> struct AlignType { };
-template<int size> struct AlignType<0, size> { typedef char result[size]; };
-
-#if !defined(CERES_ALIGN_ATTRIBUTE)
-#define CERES_ALIGNED_CHAR_ARRAY you_must_define_CERES_ALIGNED_CHAR_ARRAY_for_your_compiler
-#else // !defined(CERES_ALIGN_ATTRIBUTE)
-
-#define CERES_ALIGN_TYPE_TEMPLATE(X) \
- template<int size> struct AlignType<X, size> { \
- typedef CERES_ALIGN_ATTRIBUTE(X) char result[size]; \
- }
-
-CERES_ALIGN_TYPE_TEMPLATE(1);
-CERES_ALIGN_TYPE_TEMPLATE(2);
-CERES_ALIGN_TYPE_TEMPLATE(4);
-CERES_ALIGN_TYPE_TEMPLATE(8);
-CERES_ALIGN_TYPE_TEMPLATE(16);
-CERES_ALIGN_TYPE_TEMPLATE(32);
-CERES_ALIGN_TYPE_TEMPLATE(64);
-CERES_ALIGN_TYPE_TEMPLATE(128);
-CERES_ALIGN_TYPE_TEMPLATE(256);
-CERES_ALIGN_TYPE_TEMPLATE(512);
-CERES_ALIGN_TYPE_TEMPLATE(1024);
-CERES_ALIGN_TYPE_TEMPLATE(2048);
-CERES_ALIGN_TYPE_TEMPLATE(4096);
-CERES_ALIGN_TYPE_TEMPLATE(8192);
-// Any larger and MSVC++ will complain.
-
-#undef CERES_ALIGN_TYPE_TEMPLATE
-
-#define CERES_ALIGNED_CHAR_ARRAY(T, Size) \
- typename AlignType<CERES_ALIGN_OF(T), sizeof(T) * Size>::result
-
-#endif // !defined(CERES_ALIGN_ATTRIBUTE)
-
-#endif // CERES_ALIGNED_CHAR_ARRAY
-
-template <typename Type>
-class ManualConstructor {
- public:
- // No constructor or destructor because one of the most useful uses of
- // this class is as part of a union, and members of a union cannot have
- // constructors or destructors. And, anyway, the whole point of this
- // class is to bypass these.
-
- inline Type* get() {
- return reinterpret_cast<Type*>(space_);
- }
- inline const Type* get() const {
- return reinterpret_cast<const Type*>(space_);
- }
-
- inline Type* operator->() { return get(); }
- inline const Type* operator->() const { return get(); }
-
- inline Type& operator*() { return *get(); }
- inline const Type& operator*() const { return *get(); }
-
- // This is needed to get around the strict aliasing warning GCC generates.
- inline void* space() {
- return reinterpret_cast<void*>(space_);
- }
-
- // You can pass up to four constructor arguments as arguments of Init().
- inline void Init() {
- new(space()) Type;
- }
-
- template <typename T1>
- inline void Init(const T1& p1) {
- new(space()) Type(p1);
- }
-
- template <typename T1, typename T2>
- inline void Init(const T1& p1, const T2& p2) {
- new(space()) Type(p1, p2);
- }
-
- template <typename T1, typename T2, typename T3>
- inline void Init(const T1& p1, const T2& p2, const T3& p3) {
- new(space()) Type(p1, p2, p3);
- }
-
- template <typename T1, typename T2, typename T3, typename T4>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
- new(space()) Type(p1, p2, p3, p4);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5) {
- new(space()) Type(p1, p2, p3, p4, p5);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6) {
- new(space()) Type(p1, p2, p3, p4, p5, p6);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8,
- const T9& p9) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8,
- const T9& p9, const T10& p10) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
- }
-
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
- inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
- const T5& p5, const T6& p6, const T7& p7, const T8& p8,
- const T9& p9, const T10& p10, const T11& p11) {
- new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
- }
-
- inline void Destroy() {
- get()->~Type();
- }
-
- private:
- CERES_ALIGNED_CHAR_ARRAY(Type, 1) space_;
-};
-
-#undef CERES_ALIGNED_CHAR_ARRAY
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_MANUAL_CONSTRUCTOR_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h b/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h
deleted file mode 100644
index 3b264b45af3..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// mierle@gmail.com (Keir Mierle)
-//
-// Finite differencing routine used by NumericDiffCostFunction.
-
-#ifndef CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
-#define CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
-
-#include <cstring>
-
-#include "Eigen/Dense"
-#include "ceres/cost_function.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/internal/variadic_evaluate.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-
-namespace ceres {
-namespace internal {
-
-// Helper templates that allow evaluation of a variadic functor or a
-// CostFunction object.
-template <typename CostFunctor,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9 >
-bool EvaluateImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const void* /* NOT USED */) {
- return VariadicEvaluate<CostFunctor,
- double,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
- *functor,
- parameters,
- residuals);
-}
-
-template <typename CostFunctor,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9 >
-bool EvaluateImpl(const CostFunctor* functor,
- double const* const* parameters,
- double* residuals,
- const CostFunction* /* NOT USED */) {
- return functor->Evaluate(parameters, residuals, NULL);
-}
-
-// This is split from the main class because C++ doesn't allow partial template
-// specializations for member functions. The alternative is to repeat the main
-// class for differing numbers of parameters, which is also unfortunate.
-template <typename CostFunctor,
- NumericDiffMethod kMethod,
- int kNumResiduals,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9,
- int kParameterBlock,
- int kParameterBlockSize>
-struct NumericDiff {
- // Mutates parameters but must restore them before return.
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctor* functor,
- double const* residuals_at_eval_point,
- const double relative_step_size,
- int num_residuals,
- double **parameters,
- double *jacobian) {
- using Eigen::Map;
- using Eigen::Matrix;
- using Eigen::RowMajor;
- using Eigen::ColMajor;
-
- const int NUM_RESIDUALS =
- (kNumResiduals != ceres::DYNAMIC ? kNumResiduals : num_residuals);
-
- typedef Matrix<double, kNumResiduals, 1> ResidualVector;
- typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
-
- // The convoluted reasoning for choosing the Row/Column major
- // ordering of the matrix is an artifact of the restrictions in
- // Eigen that prevent it from creating RowMajor matrices with a
- // single column. In these cases, we ask for a ColMajor matrix.
- typedef Matrix<double,
- kNumResiduals,
- kParameterBlockSize,
- (kParameterBlockSize == 1) ? ColMajor : RowMajor>
- JacobianMatrix;
-
- Map<JacobianMatrix> parameter_jacobian(jacobian,
- NUM_RESIDUALS,
- kParameterBlockSize);
-
- // Mutate 1 element at a time and then restore.
- Map<ParameterVector> x_plus_delta(parameters[kParameterBlock],
- kParameterBlockSize);
- ParameterVector x(x_plus_delta);
- ParameterVector step_size = x.array().abs() * relative_step_size;
-
- // To handle cases where a parameter is exactly zero, instead use
- // the mean step_size for the other dimensions. If all the
- // parameters are zero, there's no good answer. Take
- // relative_step_size as a guess and hope for the best.
- const double fallback_step_size =
- (step_size.sum() == 0)
- ? relative_step_size
- : step_size.sum() / step_size.rows();
-
- // For each parameter in the parameter block, use finite differences to
- // compute the derivative for that parameter.
-
- ResidualVector residuals(NUM_RESIDUALS);
- for (int j = 0; j < kParameterBlockSize; ++j) {
- const double delta =
- (step_size(j) == 0.0) ? fallback_step_size : step_size(j);
-
- x_plus_delta(j) = x(j) + delta;
-
- if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
- functor, parameters, residuals.data(), functor)) {
- return false;
- }
-
- // Compute this column of the jacobian in 3 steps:
- // 1. Store residuals for the forward part.
- // 2. Subtract residuals for the backward (or 0) part.
- // 3. Divide out the run.
- parameter_jacobian.col(j) = residuals;
-
- double one_over_delta = 1.0 / delta;
- if (kMethod == CENTRAL) {
- // Compute the function on the other side of x(j).
- x_plus_delta(j) = x(j) - delta;
-
- if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
- functor, parameters, residuals.data(), functor)) {
- return false;
- }
-
- parameter_jacobian.col(j) -= residuals;
- one_over_delta /= 2;
- } else {
- // Forward difference only; reuse existing residuals evaluation.
- parameter_jacobian.col(j) -=
- Map<const ResidualVector>(residuals_at_eval_point, NUM_RESIDUALS);
- }
- x_plus_delta(j) = x(j); // Restore x_plus_delta.
-
- // Divide out the run to get slope.
- parameter_jacobian.col(j) *= one_over_delta;
- }
- return true;
- }
-};
-
-template <typename CostFunctor,
- NumericDiffMethod kMethod,
- int kNumResiduals,
- int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9,
- int kParameterBlock>
-struct NumericDiff<CostFunctor, kMethod, kNumResiduals,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9,
- kParameterBlock, 0> {
- // Mutates parameters but must restore them before return.
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctor* functor,
- double const* residuals_at_eval_point,
- const double relative_step_size,
- const int num_residuals,
- double **parameters,
- double *jacobian) {
- LOG(FATAL) << "Control should never reach here.";
- return true;
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/port.h b/extern/libmv/third_party/ceres/include/ceres/internal/port.h
deleted file mode 100644
index e38eb713aa8..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/port.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_PUBLIC_INTERNAL_PORT_H_
-#define CERES_PUBLIC_INTERNAL_PORT_H_
-
-// This file needs to compile as c code.
-#ifdef __cplusplus
-
-#include <string>
-
-#include "ceres/internal/config.h"
-
-#if defined(CERES_TR1_MEMORY_HEADER)
-#include <tr1/memory>
-#else
-#include <memory>
-#endif
-
-namespace ceres {
-
-// It is unfortunate that this import of the entire standard namespace is
-// necessary. The reasons are historical and won't be explained here, but
-// suffice to say it is not a mistake and can't be removed without breaking
-// things outside of the Ceres optimization package.
-using namespace std;
-
-// This is necessary to properly handle the case that there is a different
-// "string" implementation in the global namespace.
-using std::string;
-
-#if defined(CERES_TR1_SHARED_PTR)
-using std::tr1::shared_ptr;
-#else
-using std::shared_ptr;
-#endif
-
-} // namespace ceres
-
-#endif // __cplusplus
-
-// A macro to signal which functions and classes are exported when
-// building a DLL with MSVC.
-//
-// Note that the ordering here is important, CERES_BUILDING_SHARED_LIBRARY
-// is only defined locally when Ceres is compiled, it is never exported to
-// users. However, in order that we do not have to configure config.h
-// separately for building vs installing, if we are using MSVC and building
-// a shared library, then both CERES_BUILDING_SHARED_LIBRARY and
-// CERES_USING_SHARED_LIBRARY will be defined when Ceres is compiled.
-// Hence it is important that the check for CERES_BUILDING_SHARED_LIBRARY
-// happens first.
-#if defined(_MSC_VER) && defined(CERES_BUILDING_SHARED_LIBRARY)
-# define CERES_EXPORT __declspec(dllexport)
-#elif defined(_MSC_VER) && defined(CERES_USING_SHARED_LIBRARY)
-# define CERES_EXPORT __declspec(dllimport)
-#else
-# define CERES_EXPORT
-#endif
-
-#endif // CERES_PUBLIC_INTERNAL_PORT_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h b/extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h
deleted file mode 100644
index 1f477d8d2ac..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/reenable_warnings.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-
-// This is not your usual header guard. See disable_warnings.h
-#ifdef CERES_WARNINGS_DISABLED
-#undef CERES_WARNINGS_DISABLED
-
-#ifdef _MSC_VER
-#pragma warning( pop )
-#endif
-
-#endif // CERES_WARNINGS_DISABLED
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
deleted file mode 100644
index 5dfb551243c..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
+++ /dev/null
@@ -1,310 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: jorg@google.com (Jorg Brown)
-//
-// This is an implementation designed to match the anticipated future TR2
-// implementation of the scoped_ptr class, and its closely-related brethren,
-// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
-
-#ifndef CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
-#define CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
-
-#include <assert.h>
-#include <stdlib.h>
-#include <cstddef>
-#include <algorithm>
-
-namespace ceres {
-namespace internal {
-
-template <class C> class scoped_ptr;
-template <class C, class Free> class scoped_ptr_malloc;
-template <class C> class scoped_array;
-
-template <class C>
-scoped_ptr<C> make_scoped_ptr(C *);
-
-// A scoped_ptr<T> is like a T*, except that the destructor of
-// scoped_ptr<T> automatically deletes the pointer it holds (if
-// any). That is, scoped_ptr<T> owns the T object that it points
-// to. Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to
-// a T object. Also like T*, scoped_ptr<T> is thread-compatible, and
-// once you dereference it, you get the threadsafety guarantees of T.
-//
-// The size of a scoped_ptr is small: sizeof(scoped_ptr<C>) == sizeof(C*)
-template <class C>
-class scoped_ptr {
- public:
- // The element type
- typedef C element_type;
-
- // Constructor. Defaults to intializing with NULL.
- // There is no way to create an uninitialized scoped_ptr.
- // The input parameter must be allocated with new.
- explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
-
- // Destructor. If there is a C object, delete it.
- // We don't need to test ptr_ == NULL because C++ does that for us.
- ~scoped_ptr() {
- enum { type_must_be_complete = sizeof(C) };
- delete ptr_;
- }
-
- // Reset. Deletes the current owned object, if any.
- // Then takes ownership of a new object, if given.
- // this->reset(this->get()) works.
- void reset(C* p = NULL) {
- if (p != ptr_) {
- enum { type_must_be_complete = sizeof(C) };
- delete ptr_;
- ptr_ = p;
- }
- }
-
- // Accessors to get the owned object.
- // operator* and operator-> will assert() if there is no current object.
- C& operator*() const {
- assert(ptr_ != NULL);
- return *ptr_;
- }
- C* operator->() const {
- assert(ptr_ != NULL);
- return ptr_;
- }
- C* get() const { return ptr_; }
-
- // Comparison operators.
- // These return whether a scoped_ptr and a raw pointer refer to
- // the same object, not just to two different but equal objects.
- bool operator==(const C* p) const { return ptr_ == p; }
- bool operator!=(const C* p) const { return ptr_ != p; }
-
- // Swap two scoped pointers.
- void swap(scoped_ptr& p2) {
- C* tmp = ptr_;
- ptr_ = p2.ptr_;
- p2.ptr_ = tmp;
- }
-
- // Release a pointer.
- // The return value is the current pointer held by this object.
- // If this object holds a NULL pointer, the return value is NULL.
- // After this operation, this object will hold a NULL pointer,
- // and will not own the object any more.
- C* release() {
- C* retVal = ptr_;
- ptr_ = NULL;
- return retVal;
- }
-
- private:
- C* ptr_;
-
- // google3 friend class that can access copy ctor (although if it actually
- // calls a copy ctor, there will be a problem) see below
- friend scoped_ptr<C> make_scoped_ptr<C>(C *p);
-
- // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't
- // make sense, and if C2 == C, it still doesn't make sense because you should
- // never have the same object owned by two different scoped_ptrs.
- template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
- template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
-
- // Disallow evil constructors
- scoped_ptr(const scoped_ptr&);
- void operator=(const scoped_ptr&);
-};
-
-// Free functions
-template <class C>
-inline void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {
- p1.swap(p2);
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_ptr<C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_ptr<const C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_ptr<C>& p2) {
- return p1 != p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_ptr<const C>& p2) {
- return p1 != p2.get();
-}
-
-template <class C>
-scoped_ptr<C> make_scoped_ptr(C *p) {
- // This does nothing but to return a scoped_ptr of the type that the passed
- // pointer is of. (This eliminates the need to specify the name of T when
- // making a scoped_ptr that is used anonymously/temporarily.) From an
- // access control point of view, we construct an unnamed scoped_ptr here
- // which we return and thus copy-construct. Hence, we need to have access
- // to scoped_ptr::scoped_ptr(scoped_ptr const &). However, it is guaranteed
- // that we never actually call the copy constructor, which is a good thing
- // as we would call the temporary's object destructor (and thus delete p)
- // if we actually did copy some object, here.
- return scoped_ptr<C>(p);
-}
-
-// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
-// with new [] and the destructor deletes objects with delete [].
-//
-// As with scoped_ptr<C>, a scoped_array<C> either points to an object
-// or is NULL. A scoped_array<C> owns the object that it points to.
-// scoped_array<T> is thread-compatible, and once you index into it,
-// the returned objects have only the threadsafety guarantees of T.
-//
-// Size: sizeof(scoped_array<C>) == sizeof(C*)
-template <class C>
-class scoped_array {
- public:
- // The element type
- typedef C element_type;
-
- // Constructor. Defaults to intializing with NULL.
- // There is no way to create an uninitialized scoped_array.
- // The input parameter must be allocated with new [].
- explicit scoped_array(C* p = NULL) : array_(p) { }
-
- // Destructor. If there is a C object, delete it.
- // We don't need to test ptr_ == NULL because C++ does that for us.
- ~scoped_array() {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- }
-
- // Reset. Deletes the current owned object, if any.
- // Then takes ownership of a new object, if given.
- // this->reset(this->get()) works.
- void reset(C* p = NULL) {
- if (p != array_) {
- enum { type_must_be_complete = sizeof(C) };
- delete[] array_;
- array_ = p;
- }
- }
-
- // Get one element of the current object.
- // Will assert() if there is no current object, or index i is negative.
- C& operator[](std::ptrdiff_t i) const {
- assert(i >= 0);
- assert(array_ != NULL);
- return array_[i];
- }
-
- // Get a pointer to the zeroth element of the current object.
- // If there is no current object, return NULL.
- C* get() const {
- return array_;
- }
-
- // Comparison operators.
- // These return whether a scoped_array and a raw pointer refer to
- // the same array, not just to two different but equal arrays.
- bool operator==(const C* p) const { return array_ == p; }
- bool operator!=(const C* p) const { return array_ != p; }
-
- // Swap two scoped arrays.
- void swap(scoped_array& p2) {
- C* tmp = array_;
- array_ = p2.array_;
- p2.array_ = tmp;
- }
-
- // Release an array.
- // The return value is the current pointer held by this object.
- // If this object holds a NULL pointer, the return value is NULL.
- // After this operation, this object will hold a NULL pointer,
- // and will not own the object any more.
- C* release() {
- C* retVal = array_;
- array_ = NULL;
- return retVal;
- }
-
- private:
- C* array_;
-
- // Forbid comparison of different scoped_array types.
- template <class C2> bool operator==(scoped_array<C2> const& p2) const;
- template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
-
- // Disallow evil constructors
- scoped_array(const scoped_array&);
- void operator=(const scoped_array&);
-};
-
-// Free functions
-template <class C>
-inline void swap(scoped_array<C>& p1, scoped_array<C>& p2) {
- p1.swap(p2);
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_array<C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator==(const C* p1, const scoped_array<const C>& p2) {
- return p1 == p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_array<C>& p2) {
- return p1 != p2.get();
-}
-
-template <class C>
-inline bool operator!=(const C* p1, const scoped_array<const C>& p2) {
- return p1 != p2.get();
-}
-
-// This class wraps the c library function free() in a class that can be
-// passed as a template argument to scoped_ptr_malloc below.
-class ScopedPtrMallocFree {
- public:
- inline void operator()(void* x) const {
- free(x);
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_SCOPED_PTR_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h b/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h
deleted file mode 100644
index 9a473d5b25c..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// mierle@gmail.com (Keir Mierle)
-
-#ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
-#define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
-
-#include <stddef.h>
-
-#include "ceres/jet.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// This block of quasi-repeated code calls the user-supplied functor, which may
-// take a variable number of arguments. This is accomplished by specializing the
-// struct based on the size of the trailing parameters; parameters with 0 size
-// are assumed missing.
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8, int N9>
-struct VariadicEvaluate {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- input[7],
- input[8],
- input[9],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7, int N8>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, N8, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- input[7],
- input[8],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6, int N7>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, N7, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- input[7],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5, int N6>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, N6, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- input[6],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4,
- int N5>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, N5, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- input[5],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3, int N4>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, N4, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- input[4],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2, int N3>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, N3, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- input[3],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1, int N2>
-struct VariadicEvaluate<Functor, T, N0, N1, N2, 0, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- input[2],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0, int N1>
-struct VariadicEvaluate<Functor, T, N0, N1, 0, 0, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- input[1],
- output);
- }
-};
-
-template<typename Functor, typename T, int N0>
-struct VariadicEvaluate<Functor, T, N0, 0, 0, 0, 0, 0, 0, 0, 0, 0> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- output);
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
deleted file mode 100644
index 237ada6e0c9..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
+++ /dev/null
@@ -1,225 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// When an iteration callback is specified, Ceres calls the callback
-// after each minimizer step (if the minimizer has not converged) and
-// passes it an IterationSummary object, defined below.
-
-#ifndef CERES_PUBLIC_ITERATION_CALLBACK_H_
-#define CERES_PUBLIC_ITERATION_CALLBACK_H_
-
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// This struct describes the state of the optimizer after each
-// iteration of the minimization.
-struct CERES_EXPORT IterationSummary {
- IterationSummary()
- : iteration(0),
- step_is_valid(false),
- step_is_nonmonotonic(false),
- step_is_successful(false),
- cost(0.0),
- cost_change(0.0),
- gradient_max_norm(0.0),
- gradient_norm(0.0),
- step_norm(0.0),
- eta(0.0),
- step_size(0.0),
- line_search_function_evaluations(0),
- line_search_gradient_evaluations(0),
- line_search_iterations(0),
- linear_solver_iterations(0),
- iteration_time_in_seconds(0.0),
- step_solver_time_in_seconds(0.0),
- cumulative_time_in_seconds(0.0) {}
-
- // Current iteration number.
- int32 iteration;
-
- // Step was numerically valid, i.e., all values are finite and the
- // step reduces the value of the linearized model.
- //
- // Note: step_is_valid is false when iteration = 0.
- bool step_is_valid;
-
- // Step did not reduce the value of the objective function
- // sufficiently, but it was accepted because of the relaxed
- // acceptance criterion used by the non-monotonic trust region
- // algorithm.
- //
- // Note: step_is_nonmonotonic is false when iteration = 0;
- bool step_is_nonmonotonic;
-
- // Whether or not the minimizer accepted this step or not. If the
- // ordinary trust region algorithm is used, this means that the
- // relative reduction in the objective function value was greater
- // than Solver::Options::min_relative_decrease. However, if the
- // non-monotonic trust region algorithm is used
- // (Solver::Options:use_nonmonotonic_steps = true), then even if the
- // relative decrease is not sufficient, the algorithm may accept the
- // step and the step is declared successful.
- //
- // Note: step_is_successful is false when iteration = 0.
- bool step_is_successful;
-
- // Value of the objective function.
- double cost;
-
- // Change in the value of the objective function in this
- // iteration. This can be positive or negative.
- double cost_change;
-
- // Infinity norm of the gradient vector.
- double gradient_max_norm;
-
- // 2-norm of the gradient vector.
- double gradient_norm;
-
- // 2-norm of the size of the step computed by the optimization
- // algorithm.
- double step_norm;
-
- // For trust region algorithms, the ratio of the actual change in
- // cost and the change in the cost of the linearized approximation.
- double relative_decrease;
-
- // Size of the trust region at the end of the current iteration. For
- // the Levenberg-Marquardt algorithm, the regularization parameter
- // mu = 1.0 / trust_region_radius.
- double trust_region_radius;
-
- // For the inexact step Levenberg-Marquardt algorithm, this is the
- // relative accuracy with which the Newton(LM) step is solved. This
- // number affects only the iterative solvers capable of solving
- // linear systems inexactly. Factorization-based exact solvers
- // ignore it.
- double eta;
-
- // Step sized computed by the line search algorithm.
- double step_size;
-
- // Number of function value evaluations used by the line search algorithm.
- int line_search_function_evaluations;
-
- // Number of function gradient evaluations used by the line search algorithm.
- int line_search_gradient_evaluations;
-
- // Number of iterations taken by the line search algorithm.
- int line_search_iterations;
-
- // Number of iterations taken by the linear solver to solve for the
- // Newton step.
- int linear_solver_iterations;
-
- // All times reported below are wall times.
-
- // Time (in seconds) spent inside the minimizer loop in the current
- // iteration.
- double iteration_time_in_seconds;
-
- // Time (in seconds) spent inside the trust region step solver.
- double step_solver_time_in_seconds;
-
- // Time (in seconds) since the user called Solve().
- double cumulative_time_in_seconds;
-};
-
-// Interface for specifying callbacks that are executed at the end of
-// each iteration of the Minimizer. The solver uses the return value
-// of operator() to decide whether to continue solving or to
-// terminate. The user can return three values.
-//
-// SOLVER_ABORT indicates that the callback detected an abnormal
-// situation. The solver returns without updating the parameter blocks
-// (unless Solver::Options::update_state_every_iteration is set
-// true). Solver returns with Solver::Summary::termination_type set to
-// USER_ABORT.
-//
-// SOLVER_TERMINATE_SUCCESSFULLY indicates that there is no need to
-// optimize anymore (some user specified termination criterion has
-// been met). Solver returns with Solver::Summary::termination_type
-// set to USER_SUCCESS.
-//
-// SOLVER_CONTINUE indicates that the solver should continue
-// optimizing.
-//
-// For example, the following Callback is used internally by Ceres to
-// log the progress of the optimization.
-//
-// Callback for logging the state of the minimizer to STDERR or STDOUT
-// depending on the user's preferences and logging level.
-//
-// class LoggingCallback : public IterationCallback {
-// public:
-// explicit LoggingCallback(bool log_to_stdout)
-// : log_to_stdout_(log_to_stdout) {}
-//
-// ~LoggingCallback() {}
-//
-// CallbackReturnType operator()(const IterationSummary& summary) {
-// const char* kReportRowFormat =
-// "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
-// "rho:% 3.2e mu:% 3.2e eta:% 3.2e li:% 3d";
-// string output = StringPrintf(kReportRowFormat,
-// summary.iteration,
-// summary.cost,
-// summary.cost_change,
-// summary.gradient_max_norm,
-// summary.step_norm,
-// summary.relative_decrease,
-// summary.trust_region_radius,
-// summary.eta,
-// summary.linear_solver_iterations);
-// if (log_to_stdout_) {
-// cout << output << endl;
-// } else {
-// VLOG(1) << output;
-// }
-// return SOLVER_CONTINUE;
-// }
-//
-// private:
-// const bool log_to_stdout_;
-// };
-//
-class CERES_EXPORT IterationCallback {
- public:
- virtual ~IterationCallback() {}
- virtual CallbackReturnType operator()(const IterationSummary& summary) = 0;
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_ITERATION_CALLBACK_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/jet.h b/extern/libmv/third_party/ceres/include/ceres/jet.h
deleted file mode 100644
index 74ce1e9dd53..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/jet.h
+++ /dev/null
@@ -1,670 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A simple implementation of N-dimensional dual numbers, for automatically
-// computing exact derivatives of functions.
-//
-// While a complete treatment of the mechanics of automatic differentation is
-// beyond the scope of this header (see
-// http://en.wikipedia.org/wiki/Automatic_differentiation for details), the
-// basic idea is to extend normal arithmetic with an extra element, "e," often
-// denoted with the greek symbol epsilon, such that e != 0 but e^2 = 0. Dual
-// numbers are extensions of the real numbers analogous to complex numbers:
-// whereas complex numbers augment the reals by introducing an imaginary unit i
-// such that i^2 = -1, dual numbers introduce an "infinitesimal" unit e such
-// that e^2 = 0. Dual numbers have two components: the "real" component and the
-// "infinitesimal" component, generally written as x + y*e. Surprisingly, this
-// leads to a convenient method for computing exact derivatives without needing
-// to manipulate complicated symbolic expressions.
-//
-// For example, consider the function
-//
-// f(x) = x^2 ,
-//
-// evaluated at 10. Using normal arithmetic, f(10) = 100, and df/dx(10) = 20.
-// Next, augument 10 with an infinitesimal to get:
-//
-// f(10 + e) = (10 + e)^2
-// = 100 + 2 * 10 * e + e^2
-// = 100 + 20 * e -+-
-// -- |
-// | +--- This is zero, since e^2 = 0
-// |
-// +----------------- This is df/dx!
-//
-// Note that the derivative of f with respect to x is simply the infinitesimal
-// component of the value of f(x + e). So, in order to take the derivative of
-// any function, it is only necessary to replace the numeric "object" used in
-// the function with one extended with infinitesimals. The class Jet, defined in
-// this header, is one such example of this, where substitution is done with
-// templates.
-//
-// To handle derivatives of functions taking multiple arguments, different
-// infinitesimals are used, one for each variable to take the derivative of. For
-// example, consider a scalar function of two scalar parameters x and y:
-//
-// f(x, y) = x^2 + x * y
-//
-// Following the technique above, to compute the derivatives df/dx and df/dy for
-// f(1, 3) involves doing two evaluations of f, the first time replacing x with
-// x + e, the second time replacing y with y + e.
-//
-// For df/dx:
-//
-// f(1 + e, y) = (1 + e)^2 + (1 + e) * 3
-// = 1 + 2 * e + 3 + 3 * e
-// = 4 + 5 * e
-//
-// --> df/dx = 5
-//
-// For df/dy:
-//
-// f(1, 3 + e) = 1^2 + 1 * (3 + e)
-// = 1 + 3 + e
-// = 4 + e
-//
-// --> df/dy = 1
-//
-// To take the gradient of f with the implementation of dual numbers ("jets") in
-// this file, it is necessary to create a single jet type which has components
-// for the derivative in x and y, and passing them to a templated version of f:
-//
-// template<typename T>
-// T f(const T &x, const T &y) {
-// return x * x + x * y;
-// }
-//
-// // The "2" means there should be 2 dual number components.
-// Jet<double, 2> x(0); // Pick the 0th dual number for x.
-// Jet<double, 2> y(1); // Pick the 1st dual number for y.
-// Jet<double, 2> z = f(x, y);
-//
-// LOG(INFO) << "df/dx = " << z.a[0]
-// << "df/dy = " << z.a[1];
-//
-// Most users should not use Jet objects directly; a wrapper around Jet objects,
-// which makes computing the derivative, gradient, or jacobian of templated
-// functors simple, is in autodiff.h. Even autodiff.h should not be used
-// directly; instead autodiff_cost_function.h is typically the file of interest.
-//
-// For the more mathematically inclined, this file implements first-order
-// "jets". A 1st order jet is an element of the ring
-//
-// T[N] = T[t_1, ..., t_N] / (t_1, ..., t_N)^2
-//
-// which essentially means that each jet consists of a "scalar" value 'a' from T
-// and a 1st order perturbation vector 'v' of length N:
-//
-// x = a + \sum_i v[i] t_i
-//
-// A shorthand is to write an element as x = a + u, where u is the pertubation.
-// Then, the main point about the arithmetic of jets is that the product of
-// perturbations is zero:
-//
-// (a + u) * (b + v) = ab + av + bu + uv
-// = ab + (av + bu) + 0
-//
-// which is what operator* implements below. Addition is simpler:
-//
-// (a + u) + (b + v) = (a + b) + (u + v).
-//
-// The only remaining question is how to evaluate the function of a jet, for
-// which we use the chain rule:
-//
-// f(a + u) = f(a) + f'(a) u
-//
-// where f'(a) is the (scalar) derivative of f at a.
-//
-// By pushing these things through sufficiently and suitably templated
-// functions, we can do automatic differentiation. Just be sure to turn on
-// function inlining and common-subexpression elimination, or it will be very
-// slow!
-//
-// WARNING: Most Ceres users should not directly include this file or know the
-// details of how jets work. Instead the suggested method for automatic
-// derivatives is to use autodiff_cost_function.h, which is a wrapper around
-// both jets.h and autodiff.h to make taking derivatives of cost functions for
-// use in Ceres easier.
-
-#ifndef CERES_PUBLIC_JET_H_
-#define CERES_PUBLIC_JET_H_
-
-#include <cmath>
-#include <iosfwd>
-#include <iostream> // NOLINT
-#include <limits>
-#include <string>
-
-#include "Eigen/Core"
-#include "ceres/fpclassify.h"
-
-namespace ceres {
-
-template <typename T, int N>
-struct Jet {
- enum { DIMENSION = N };
-
- // Default-construct "a" because otherwise this can lead to false errors about
- // uninitialized uses when other classes relying on default constructed T
- // (where T is a Jet<T, N>). This usually only happens in opt mode. Note that
- // the C++ standard mandates that e.g. default constructed doubles are
- // initialized to 0.0; see sections 8.5 of the C++03 standard.
- Jet() : a() {
- v.setZero();
- }
-
- // Constructor from scalar: a + 0.
- explicit Jet(const T& value) {
- a = value;
- v.setZero();
- }
-
- // Constructor from scalar plus variable: a + t_i.
- Jet(const T& value, int k) {
- a = value;
- v.setZero();
- v[k] = T(1.0);
- }
-
- // Constructor from scalar and vector part
- // The use of Eigen::DenseBase allows Eigen expressions
- // to be passed in without being fully evaluated until
- // they are assigned to v
- template<typename Derived>
- EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived> &v)
- : a(a), v(v) {
- }
-
- // Compound operators
- Jet<T, N>& operator+=(const Jet<T, N> &y) {
- *this = *this + y;
- return *this;
- }
-
- Jet<T, N>& operator-=(const Jet<T, N> &y) {
- *this = *this - y;
- return *this;
- }
-
- Jet<T, N>& operator*=(const Jet<T, N> &y) {
- *this = *this * y;
- return *this;
- }
-
- Jet<T, N>& operator/=(const Jet<T, N> &y) {
- *this = *this / y;
- return *this;
- }
-
- // The scalar part.
- T a;
-
- // The infinitesimal part.
- //
- // Note the Eigen::DontAlign bit is needed here because this object
- // gets allocated on the stack and as part of other arrays and
- // structs. Forcing the right alignment there is the source of much
- // pain and suffering. Even if that works, passing Jets around to
- // functions by value has problems because the C++ ABI does not
- // guarantee alignment for function arguments.
- //
- // Setting the DontAlign bit prevents Eigen from using SSE for the
- // various operations on Jets. This is a small performance penalty
- // since the AutoDiff code will still expose much of the code as
- // statically sized loops to the compiler. But given the subtle
- // issues that arise due to alignment, especially when dealing with
- // multiple platforms, it seems to be a trade off worth making.
- Eigen::Matrix<T, N, 1, Eigen::DontAlign> v;
-};
-
-// Unary +
-template<typename T, int N> inline
-Jet<T, N> const& operator+(const Jet<T, N>& f) {
- return f;
-}
-
-// TODO(keir): Try adding __attribute__((always_inline)) to these functions to
-// see if it causes a performance increase.
-
-// Unary -
-template<typename T, int N> inline
-Jet<T, N> operator-(const Jet<T, N>&f) {
- return Jet<T, N>(-f.a, -f.v);
-}
-
-// Binary +
-template<typename T, int N> inline
-Jet<T, N> operator+(const Jet<T, N>& f,
- const Jet<T, N>& g) {
- return Jet<T, N>(f.a + g.a, f.v + g.v);
-}
-
-// Binary + with a scalar: x + s
-template<typename T, int N> inline
-Jet<T, N> operator+(const Jet<T, N>& f, T s) {
- return Jet<T, N>(f.a + s, f.v);
-}
-
-// Binary + with a scalar: s + x
-template<typename T, int N> inline
-Jet<T, N> operator+(T s, const Jet<T, N>& f) {
- return Jet<T, N>(f.a + s, f.v);
-}
-
-// Binary -
-template<typename T, int N> inline
-Jet<T, N> operator-(const Jet<T, N>& f,
- const Jet<T, N>& g) {
- return Jet<T, N>(f.a - g.a, f.v - g.v);
-}
-
-// Binary - with a scalar: x - s
-template<typename T, int N> inline
-Jet<T, N> operator-(const Jet<T, N>& f, T s) {
- return Jet<T, N>(f.a - s, f.v);
-}
-
-// Binary - with a scalar: s - x
-template<typename T, int N> inline
-Jet<T, N> operator-(T s, const Jet<T, N>& f) {
- return Jet<T, N>(s - f.a, -f.v);
-}
-
-// Binary *
-template<typename T, int N> inline
-Jet<T, N> operator*(const Jet<T, N>& f,
- const Jet<T, N>& g) {
- return Jet<T, N>(f.a * g.a, f.a * g.v + f.v * g.a);
-}
-
-// Binary * with a scalar: x * s
-template<typename T, int N> inline
-Jet<T, N> operator*(const Jet<T, N>& f, T s) {
- return Jet<T, N>(f.a * s, f.v * s);
-}
-
-// Binary * with a scalar: s * x
-template<typename T, int N> inline
-Jet<T, N> operator*(T s, const Jet<T, N>& f) {
- return Jet<T, N>(f.a * s, f.v * s);
-}
-
-// Binary /
-template<typename T, int N> inline
-Jet<T, N> operator/(const Jet<T, N>& f,
- const Jet<T, N>& g) {
- // This uses:
- //
- // a + u (a + u)(b - v) (a + u)(b - v)
- // ----- = -------------- = --------------
- // b + v (b + v)(b - v) b^2
- //
- // which holds because v*v = 0.
- const T g_a_inverse = T(1.0) / g.a;
- const T f_a_by_g_a = f.a * g_a_inverse;
- return Jet<T, N>(f.a * g_a_inverse, (f.v - f_a_by_g_a * g.v) * g_a_inverse);
-}
-
-// Binary / with a scalar: s / x
-template<typename T, int N> inline
-Jet<T, N> operator/(T s, const Jet<T, N>& g) {
- const T minus_s_g_a_inverse2 = -s / (g.a * g.a);
- return Jet<T, N>(s / g.a, g.v * minus_s_g_a_inverse2);
-}
-
-// Binary / with a scalar: x / s
-template<typename T, int N> inline
-Jet<T, N> operator/(const Jet<T, N>& f, T s) {
- const T s_inverse = 1.0 / s;
- return Jet<T, N>(f.a * s_inverse, f.v * s_inverse);
-}
-
-// Binary comparison operators for both scalars and jets.
-#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op) \
-template<typename T, int N> inline \
-bool operator op(const Jet<T, N>& f, const Jet<T, N>& g) { \
- return f.a op g.a; \
-} \
-template<typename T, int N> inline \
-bool operator op(const T& s, const Jet<T, N>& g) { \
- return s op g.a; \
-} \
-template<typename T, int N> inline \
-bool operator op(const Jet<T, N>& f, const T& s) { \
- return f.a op s; \
-}
-CERES_DEFINE_JET_COMPARISON_OPERATOR( < ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( <= ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( > ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( >= ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( == ) // NOLINT
-CERES_DEFINE_JET_COMPARISON_OPERATOR( != ) // NOLINT
-#undef CERES_DEFINE_JET_COMPARISON_OPERATOR
-
-// Pull some functions from namespace std.
-//
-// This is necessary because we want to use the same name (e.g. 'sqrt') for
-// double-valued and Jet-valued functions, but we are not allowed to put
-// Jet-valued functions inside namespace std.
-//
-// TODO(keir): Switch to "using".
-inline double abs (double x) { return std::abs(x); }
-inline double log (double x) { return std::log(x); }
-inline double exp (double x) { return std::exp(x); }
-inline double sqrt (double x) { return std::sqrt(x); }
-inline double cos (double x) { return std::cos(x); }
-inline double acos (double x) { return std::acos(x); }
-inline double sin (double x) { return std::sin(x); }
-inline double asin (double x) { return std::asin(x); }
-inline double tan (double x) { return std::tan(x); }
-inline double atan (double x) { return std::atan(x); }
-inline double sinh (double x) { return std::sinh(x); }
-inline double cosh (double x) { return std::cosh(x); }
-inline double tanh (double x) { return std::tanh(x); }
-inline double pow (double x, double y) { return std::pow(x, y); }
-inline double atan2(double y, double x) { return std::atan2(y, x); }
-
-// In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
-
-// abs(x + h) ~= x + h or -(x + h)
-template <typename T, int N> inline
-Jet<T, N> abs(const Jet<T, N>& f) {
- return f.a < T(0.0) ? -f : f;
-}
-
-// log(a + h) ~= log(a) + h / a
-template <typename T, int N> inline
-Jet<T, N> log(const Jet<T, N>& f) {
- const T a_inverse = T(1.0) / f.a;
- return Jet<T, N>(log(f.a), f.v * a_inverse);
-}
-
-// exp(a + h) ~= exp(a) + exp(a) h
-template <typename T, int N> inline
-Jet<T, N> exp(const Jet<T, N>& f) {
- const T tmp = exp(f.a);
- return Jet<T, N>(tmp, tmp * f.v);
-}
-
-// sqrt(a + h) ~= sqrt(a) + h / (2 sqrt(a))
-template <typename T, int N> inline
-Jet<T, N> sqrt(const Jet<T, N>& f) {
- const T tmp = sqrt(f.a);
- const T two_a_inverse = T(1.0) / (T(2.0) * tmp);
- return Jet<T, N>(tmp, f.v * two_a_inverse);
-}
-
-// cos(a + h) ~= cos(a) - sin(a) h
-template <typename T, int N> inline
-Jet<T, N> cos(const Jet<T, N>& f) {
- return Jet<T, N>(cos(f.a), - sin(f.a) * f.v);
-}
-
-// acos(a + h) ~= acos(a) - 1 / sqrt(1 - a^2) h
-template <typename T, int N> inline
-Jet<T, N> acos(const Jet<T, N>& f) {
- const T tmp = - T(1.0) / sqrt(T(1.0) - f.a * f.a);
- return Jet<T, N>(acos(f.a), tmp * f.v);
-}
-
-// sin(a + h) ~= sin(a) + cos(a) h
-template <typename T, int N> inline
-Jet<T, N> sin(const Jet<T, N>& f) {
- return Jet<T, N>(sin(f.a), cos(f.a) * f.v);
-}
-
-// asin(a + h) ~= asin(a) + 1 / sqrt(1 - a^2) h
-template <typename T, int N> inline
-Jet<T, N> asin(const Jet<T, N>& f) {
- const T tmp = T(1.0) / sqrt(T(1.0) - f.a * f.a);
- return Jet<T, N>(asin(f.a), tmp * f.v);
-}
-
-// tan(a + h) ~= tan(a) + (1 + tan(a)^2) h
-template <typename T, int N> inline
-Jet<T, N> tan(const Jet<T, N>& f) {
- const T tan_a = tan(f.a);
- const T tmp = T(1.0) + tan_a * tan_a;
- return Jet<T, N>(tan_a, tmp * f.v);
-}
-
-// atan(a + h) ~= atan(a) + 1 / (1 + a^2) h
-template <typename T, int N> inline
-Jet<T, N> atan(const Jet<T, N>& f) {
- const T tmp = T(1.0) / (T(1.0) + f.a * f.a);
- return Jet<T, N>(atan(f.a), tmp * f.v);
-}
-
-// sinh(a + h) ~= sinh(a) + cosh(a) h
-template <typename T, int N> inline
-Jet<T, N> sinh(const Jet<T, N>& f) {
- return Jet<T, N>(sinh(f.a), cosh(f.a) * f.v);
-}
-
-// cosh(a + h) ~= cosh(a) + sinh(a) h
-template <typename T, int N> inline
-Jet<T, N> cosh(const Jet<T, N>& f) {
- return Jet<T, N>(cosh(f.a), sinh(f.a) * f.v);
-}
-
-// tanh(a + h) ~= tanh(a) + (1 - tanh(a)^2) h
-template <typename T, int N> inline
-Jet<T, N> tanh(const Jet<T, N>& f) {
- const T tanh_a = tanh(f.a);
- const T tmp = T(1.0) - tanh_a * tanh_a;
- return Jet<T, N>(tanh_a, tmp * f.v);
-}
-
-// Jet Classification. It is not clear what the appropriate semantics are for
-// these classifications. This picks that IsFinite and isnormal are "all"
-// operations, i.e. all elements of the jet must be finite for the jet itself
-// to be finite (or normal). For IsNaN and IsInfinite, the answer is less
-// clear. This takes a "any" approach for IsNaN and IsInfinite such that if any
-// part of a jet is nan or inf, then the entire jet is nan or inf. This leads
-// to strange situations like a jet can be both IsInfinite and IsNaN, but in
-// practice the "any" semantics are the most useful for e.g. checking that
-// derivatives are sane.
-
-// The jet is finite if all parts of the jet are finite.
-template <typename T, int N> inline
-bool IsFinite(const Jet<T, N>& f) {
- if (!IsFinite(f.a)) {
- return false;
- }
- for (int i = 0; i < N; ++i) {
- if (!IsFinite(f.v[i])) {
- return false;
- }
- }
- return true;
-}
-
-// The jet is infinite if any part of the jet is infinite.
-template <typename T, int N> inline
-bool IsInfinite(const Jet<T, N>& f) {
- if (IsInfinite(f.a)) {
- return true;
- }
- for (int i = 0; i < N; i++) {
- if (IsInfinite(f.v[i])) {
- return true;
- }
- }
- return false;
-}
-
-// The jet is NaN if any part of the jet is NaN.
-template <typename T, int N> inline
-bool IsNaN(const Jet<T, N>& f) {
- if (IsNaN(f.a)) {
- return true;
- }
- for (int i = 0; i < N; ++i) {
- if (IsNaN(f.v[i])) {
- return true;
- }
- }
- return false;
-}
-
-// The jet is normal if all parts of the jet are normal.
-template <typename T, int N> inline
-bool IsNormal(const Jet<T, N>& f) {
- if (!IsNormal(f.a)) {
- return false;
- }
- for (int i = 0; i < N; ++i) {
- if (!IsNormal(f.v[i])) {
- return false;
- }
- }
- return true;
-}
-
-// atan2(b + db, a + da) ~= atan2(b, a) + (- b da + a db) / (a^2 + b^2)
-//
-// In words: the rate of change of theta is 1/r times the rate of
-// change of (x, y) in the positive angular direction.
-template <typename T, int N> inline
-Jet<T, N> atan2(const Jet<T, N>& g, const Jet<T, N>& f) {
- // Note order of arguments:
- //
- // f = a + da
- // g = b + db
-
- T const tmp = T(1.0) / (f.a * f.a + g.a * g.a);
- return Jet<T, N>(atan2(g.a, f.a), tmp * (- g.a * f.v + f.a * g.v));
-}
-
-
-// pow -- base is a differentiable function, exponent is a constant.
-// (a+da)^p ~= a^p + p*a^(p-1) da
-template <typename T, int N> inline
-Jet<T, N> pow(const Jet<T, N>& f, double g) {
- T const tmp = g * pow(f.a, g - T(1.0));
- return Jet<T, N>(pow(f.a, g), tmp * f.v);
-}
-
-// pow -- base is a constant, exponent is a differentiable function.
-// (a)^(p+dp) ~= a^p + a^p log(a) dp
-template <typename T, int N> inline
-Jet<T, N> pow(double f, const Jet<T, N>& g) {
- T const tmp = pow(f, g.a);
- return Jet<T, N>(tmp, log(f) * tmp * g.v);
-}
-
-
-// pow -- both base and exponent are differentiable functions.
-// (a+da)^(b+db) ~= a^b + b * a^(b-1) da + a^b log(a) * db
-template <typename T, int N> inline
-Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
- T const tmp1 = pow(f.a, g.a);
- T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
- T const tmp3 = tmp1 * log(f.a);
-
- return Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
-}
-
-// Define the helper functions Eigen needs to embed Jet types.
-//
-// NOTE(keir): machine_epsilon() and precision() are missing, because they don't
-// work with nested template types (e.g. where the scalar is itself templated).
-// Among other things, this means that decompositions of Jet's does not work,
-// for example
-//
-// Matrix<Jet<T, N> ... > A, x, b;
-// ...
-// A.solve(b, &x)
-//
-// does not work and will fail with a strange compiler error.
-//
-// TODO(keir): This is an Eigen 2.0 limitation that is lifted in 3.0. When we
-// switch to 3.0, also add the rest of the specialization functionality.
-template<typename T, int N> inline const Jet<T, N>& ei_conj(const Jet<T, N>& x) { return x; } // NOLINT
-template<typename T, int N> inline const Jet<T, N>& ei_real(const Jet<T, N>& x) { return x; } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_imag(const Jet<T, N>& ) { return Jet<T, N>(0.0); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_abs (const Jet<T, N>& x) { return fabs(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_abs2(const Jet<T, N>& x) { return x * x; } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_sqrt(const Jet<T, N>& x) { return sqrt(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_exp (const Jet<T, N>& x) { return exp(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_log (const Jet<T, N>& x) { return log(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_sin (const Jet<T, N>& x) { return sin(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_cos (const Jet<T, N>& x) { return cos(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_tan (const Jet<T, N>& x) { return tan(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_atan(const Jet<T, N>& x) { return atan(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_sinh(const Jet<T, N>& x) { return sinh(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_cosh(const Jet<T, N>& x) { return cosh(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_tanh(const Jet<T, N>& x) { return tanh(x); } // NOLINT
-template<typename T, int N> inline Jet<T, N> ei_pow (const Jet<T, N>& x, Jet<T, N> y) { return pow(x, y); } // NOLINT
-
-// Note: This has to be in the ceres namespace for argument dependent lookup to
-// function correctly. Otherwise statements like CHECK_LE(x, 2.0) fail with
-// strange compile errors.
-template <typename T, int N>
-inline std::ostream &operator<<(std::ostream &s, const Jet<T, N>& z) {
- return s << "[" << z.a << " ; " << z.v.transpose() << "]";
-}
-
-} // namespace ceres
-
-namespace Eigen {
-
-// Creating a specialization of NumTraits enables placing Jet objects inside
-// Eigen arrays, getting all the goodness of Eigen combined with autodiff.
-template<typename T, int N>
-struct NumTraits<ceres::Jet<T, N> > {
- typedef ceres::Jet<T, N> Real;
- typedef ceres::Jet<T, N> NonInteger;
- typedef ceres::Jet<T, N> Nested;
-
- static typename ceres::Jet<T, N> dummy_precision() {
- return ceres::Jet<T, N>(1e-12);
- }
-
- static inline Real epsilon() {
- return Real(std::numeric_limits<T>::epsilon());
- }
-
- enum {
- IsComplex = 0,
- IsInteger = 0,
- IsSigned,
- ReadCost = 1,
- AddCost = 1,
- // For Jet types, multiplication is more expensive than addition.
- MulCost = 3,
- HasFloatingPoint = 1,
- RequireInitialization = 1
- };
-};
-
-} // namespace Eigen
-
-#endif // CERES_PUBLIC_JET_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/local_parameterization.h b/extern/libmv/third_party/ceres/include/ceres/local_parameterization.h
deleted file mode 100644
index 656c4d46662..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/local_parameterization.h
+++ /dev/null
@@ -1,217 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
-#define CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
-
-#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// Purpose: Sometimes parameter blocks x can overparameterize a problem
-//
-// min f(x)
-// x
-//
-// In that case it is desirable to choose a parameterization for the
-// block itself to remove the null directions of the cost. More
-// generally, if x lies on a manifold of a smaller dimension than the
-// ambient space that it is embedded in, then it is numerically and
-// computationally more effective to optimize it using a
-// parameterization that lives in the tangent space of that manifold
-// at each point.
-//
-// For example, a sphere in three dimensions is a 2 dimensional
-// manifold, embedded in a three dimensional space. At each point on
-// the sphere, the plane tangent to it defines a two dimensional
-// tangent space. For a cost function defined on this sphere, given a
-// point x, moving in the direction normal to the sphere at that point
-// is not useful. Thus a better way to do a local optimization is to
-// optimize over two dimensional vector delta in the tangent space at
-// that point and then "move" to the point x + delta, where the move
-// operation involves projecting back onto the sphere. Doing so
-// removes a redundent dimension from the optimization, making it
-// numerically more robust and efficient.
-//
-// More generally we can define a function
-//
-// x_plus_delta = Plus(x, delta),
-//
-// where x_plus_delta has the same size as x, and delta is of size
-// less than or equal to x. The function Plus, generalizes the
-// definition of vector addition. Thus it satisfies the identify
-//
-// Plus(x, 0) = x, for all x.
-//
-// A trivial version of Plus is when delta is of the same size as x
-// and
-//
-// Plus(x, delta) = x + delta
-//
-// A more interesting case if x is two dimensional vector, and the
-// user wishes to hold the first coordinate constant. Then, delta is a
-// scalar and Plus is defined as
-//
-// Plus(x, delta) = x + [0] * delta
-// [1]
-//
-// An example that occurs commonly in Structure from Motion problems
-// is when camera rotations are parameterized using Quaternion. There,
-// it is useful only make updates orthogonal to that 4-vector defining
-// the quaternion. One way to do this is to let delta be a 3
-// dimensional vector and define Plus to be
-//
-// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x
-//
-// The multiplication between the two 4-vectors on the RHS is the
-// standard quaternion product.
-//
-// Given g and a point x, optimizing f can now be restated as
-//
-// min f(Plus(x, delta))
-// delta
-//
-// Given a solution delta to this problem, the optimal value is then
-// given by
-//
-// x* = Plus(x, delta)
-//
-// The class LocalParameterization defines the function Plus and its
-// Jacobian which is needed to compute the Jacobian of f w.r.t delta.
-class CERES_EXPORT LocalParameterization {
- public:
- virtual ~LocalParameterization();
-
- // Generalization of the addition operation,
- //
- // x_plus_delta = Plus(x, delta)
- //
- // with the condition that Plus(x, 0) = x.
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const = 0;
-
- // The jacobian of Plus(x, delta) w.r.t delta at delta = 0.
- //
- // jacobian is a row-major GlobalSize() x LocalSize() matrix.
- virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0;
-
- // local_matrix = global_matrix * jacobian
- //
- // global_matrix is a num_rows x GlobalSize row major matrix.
- // local_matrix is a num_rows x LocalSize row major matrix.
- // jacobian(x) is the matrix returned by ComputeJacobian at x.
- //
- // This is only used by GradientProblem. For most normal uses, it is
- // okay to use the default implementation.
- virtual bool MultiplyByJacobian(const double* x,
- const int num_rows,
- const double* global_matrix,
- double* local_matrix) const;
-
- // Size of x.
- virtual int GlobalSize() const = 0;
-
- // Size of delta.
- virtual int LocalSize() const = 0;
-};
-
-// Some basic parameterizations
-
-// Identity Parameterization: Plus(x, delta) = x + delta
-class CERES_EXPORT IdentityParameterization : public LocalParameterization {
- public:
- explicit IdentityParameterization(int size);
- virtual ~IdentityParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual bool MultiplyByJacobian(const double* x,
- const int num_cols,
- const double* global_matrix,
- double* local_matrix) const;
- virtual int GlobalSize() const { return size_; }
- virtual int LocalSize() const { return size_; }
-
- private:
- const int size_;
-};
-
-// Hold a subset of the parameters inside a parameter block constant.
-class CERES_EXPORT SubsetParameterization : public LocalParameterization {
- public:
- explicit SubsetParameterization(int size,
- const vector<int>& constant_parameters);
- virtual ~SubsetParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual bool MultiplyByJacobian(const double* x,
- const int num_cols,
- const double* global_matrix,
- double* local_matrix) const;
- virtual int GlobalSize() const {
- return static_cast<int>(constancy_mask_.size());
- }
- virtual int LocalSize() const { return local_size_; }
-
- private:
- const int local_size_;
- vector<int> constancy_mask_;
-};
-
-// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x
-// with * being the quaternion multiplication operator. Here we assume
-// that the first element of the quaternion vector is the real (cos
-// theta) part.
-class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
- public:
- virtual ~QuaternionParameterization() {}
- virtual bool Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const;
- virtual bool ComputeJacobian(const double* x,
- double* jacobian) const;
- virtual int GlobalSize() const { return 4; }
- virtual int LocalSize() const { return 3; }
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/loss_function.h b/extern/libmv/third_party/ceres/include/ceres/loss_function.h
deleted file mode 100644
index 2c585009990..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/loss_function.h
+++ /dev/null
@@ -1,401 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// The LossFunction interface is the way users describe how residuals
-// are converted to cost terms for the overall problem cost function.
-// For the exact manner in which loss functions are converted to the
-// overall cost for a problem, see problem.h.
-//
-// For least squares problem where there are no outliers and standard
-// squared loss is expected, it is not necessary to create a loss
-// function; instead passing a NULL to the problem when adding
-// residuals implies a standard squared loss.
-//
-// For least squares problems where the minimization may encounter
-// input terms that contain outliers, that is, completely bogus
-// measurements, it is important to use a loss function that reduces
-// their associated penalty.
-//
-// Consider a structure from motion problem. The unknowns are 3D
-// points and camera parameters, and the measurements are image
-// coordinates describing the expected reprojected position for a
-// point in a camera. For example, we want to model the geometry of a
-// street scene with fire hydrants and cars, observed by a moving
-// camera with unknown parameters, and the only 3D points we care
-// about are the pointy tippy-tops of the fire hydrants. Our magic
-// image processing algorithm, which is responsible for producing the
-// measurements that are input to Ceres, has found and matched all
-// such tippy-tops in all image frames, except that in one of the
-// frame it mistook a car's headlight for a hydrant. If we didn't do
-// anything special (i.e. if we used a basic quadratic loss), the
-// residual for the erroneous measurement will result in extreme error
-// due to the quadratic nature of squared loss. This results in the
-// entire solution getting pulled away from the optimimum to reduce
-// the large error that would otherwise be attributed to the wrong
-// measurement.
-//
-// Using a robust loss function, the cost for large residuals is
-// reduced. In the example above, this leads to outlier terms getting
-// downweighted so they do not overly influence the final solution.
-//
-// What cost function is best?
-//
-// In general, there isn't a principled way to select a robust loss
-// function. The authors suggest starting with a non-robust cost, then
-// only experimenting with robust loss functions if standard squared
-// loss doesn't work.
-
-#ifndef CERES_PUBLIC_LOSS_FUNCTION_H_
-#define CERES_PUBLIC_LOSS_FUNCTION_H_
-
-#include "glog/logging.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-class CERES_EXPORT LossFunction {
- public:
- virtual ~LossFunction() {}
-
- // For a residual vector with squared 2-norm 'sq_norm', this method
- // is required to fill in the value and derivatives of the loss
- // function (rho in this example):
- //
- // out[0] = rho(sq_norm),
- // out[1] = rho'(sq_norm),
- // out[2] = rho''(sq_norm),
- //
- // Here the convention is that the contribution of a term to the
- // cost function is given by 1/2 rho(s), where
- //
- // s = ||residuals||^2.
- //
- // Calling the method with a negative value of 's' is an error and
- // the implementations are not required to handle that case.
- //
- // Most sane choices of rho() satisfy:
- //
- // rho(0) = 0,
- // rho'(0) = 1,
- // rho'(s) < 1 in outlier region,
- // rho''(s) < 0 in outlier region,
- //
- // so that they mimic the least squares cost for small residuals.
- virtual void Evaluate(double sq_norm, double out[3]) const = 0;
-};
-
-// Some common implementations follow below.
-//
-// Note: in the region of interest (i.e. s < 3) we have:
-// TrivialLoss >= HuberLoss >= SoftLOneLoss >= CauchyLoss
-
-
-// This corresponds to no robustification.
-//
-// rho(s) = s
-//
-// At s = 0: rho = [0, 1, 0].
-//
-// It is not normally necessary to use this, as passing NULL for the
-// loss function when building the problem accomplishes the same
-// thing.
-class CERES_EXPORT TrivialLoss : public LossFunction {
- public:
- virtual void Evaluate(double, double*) const;
-};
-
-// Scaling
-// -------
-// Given one robustifier
-// s -> rho(s)
-// one can change the length scale at which robustification takes
-// place, by adding a scale factor 'a' as follows:
-//
-// s -> a^2 rho(s / a^2).
-//
-// The first and second derivatives are:
-//
-// s -> rho'(s / a^2),
-// s -> (1 / a^2) rho''(s / a^2),
-//
-// but the behaviour near s = 0 is the same as the original function,
-// i.e.
-//
-// rho(s) = s + higher order terms,
-// a^2 rho(s / a^2) = s + higher order terms.
-//
-// The scalar 'a' should be positive.
-//
-// The reason for the appearance of squaring is that 'a' is in the
-// units of the residual vector norm whereas 's' is a squared
-// norm. For applications it is more convenient to specify 'a' than
-// its square. The commonly used robustifiers below are described in
-// un-scaled format (a = 1) but their implementations work for any
-// non-zero value of 'a'.
-
-// Huber.
-//
-// rho(s) = s for s <= 1,
-// rho(s) = 2 sqrt(s) - 1 for s >= 1.
-//
-// At s = 0: rho = [0, 1, 0].
-//
-// The scaling parameter 'a' corresponds to 'delta' on this page:
-// http://en.wikipedia.org/wiki/Huber_Loss_Function
-class CERES_EXPORT HuberLoss : public LossFunction {
- public:
- explicit HuberLoss(double a) : a_(a), b_(a * a) { }
- virtual void Evaluate(double, double*) const;
-
- private:
- const double a_;
- // b = a^2.
- const double b_;
-};
-
-// Soft L1, similar to Huber but smooth.
-//
-// rho(s) = 2 (sqrt(1 + s) - 1).
-//
-// At s = 0: rho = [0, 1, -1/2].
-class CERES_EXPORT SoftLOneLoss : public LossFunction {
- public:
- explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) { }
- virtual void Evaluate(double, double*) const;
-
- private:
- // b = a^2.
- const double b_;
- // c = 1 / a^2.
- const double c_;
-};
-
-// Inspired by the Cauchy distribution
-//
-// rho(s) = log(1 + s).
-//
-// At s = 0: rho = [0, 1, -1].
-class CERES_EXPORT CauchyLoss : public LossFunction {
- public:
- explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) { }
- virtual void Evaluate(double, double*) const;
-
- private:
- // b = a^2.
- const double b_;
- // c = 1 / a^2.
- const double c_;
-};
-
-// Loss that is capped beyond a certain level using the arc-tangent function.
-// The scaling parameter 'a' determines the level where falloff occurs.
-// For costs much smaller than 'a', the loss function is linear and behaves like
-// TrivialLoss, and for values much larger than 'a' the value asymptotically
-// approaches the constant value of a * PI / 2.
-//
-// rho(s) = a atan(s / a).
-//
-// At s = 0: rho = [0, 1, 0].
-class CERES_EXPORT ArctanLoss : public LossFunction {
- public:
- explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) { }
- virtual void Evaluate(double, double*) const;
-
- private:
- const double a_;
- // b = 1 / a^2.
- const double b_;
-};
-
-// Loss function that maps to approximately zero cost in a range around the
-// origin, and reverts to linear in error (quadratic in cost) beyond this range.
-// The tolerance parameter 'a' sets the nominal point at which the
-// transition occurs, and the transition size parameter 'b' sets the nominal
-// distance over which most of the transition occurs. Both a and b must be
-// greater than zero, and typically b will be set to a fraction of a.
-// The slope rho'[s] varies smoothly from about 0 at s <= a - b to
-// about 1 at s >= a + b.
-//
-// The term is computed as:
-//
-// rho(s) = b log(1 + exp((s - a) / b)) - c0.
-//
-// where c0 is chosen so that rho(0) == 0
-//
-// c0 = b log(1 + exp(-a / b)
-//
-// This has the following useful properties:
-//
-// rho(s) == 0 for s = 0
-// rho'(s) ~= 0 for s << a - b
-// rho'(s) ~= 1 for s >> a + b
-// rho''(s) > 0 for all s
-//
-// In addition, all derivatives are continuous, and the curvature is
-// concentrated in the range a - b to a + b.
-//
-// At s = 0: rho = [0, ~0, ~0].
-class CERES_EXPORT TolerantLoss : public LossFunction {
- public:
- explicit TolerantLoss(double a, double b);
- virtual void Evaluate(double, double*) const;
-
- private:
- const double a_, b_, c_;
-};
-
-// Composition of two loss functions. The error is the result of first
-// evaluating g followed by f to yield the composition f(g(s)).
-// The loss functions must not be NULL.
-class ComposedLoss : public LossFunction {
- public:
- explicit ComposedLoss(const LossFunction* f, Ownership ownership_f,
- const LossFunction* g, Ownership ownership_g);
- virtual ~ComposedLoss();
- virtual void Evaluate(double, double*) const;
-
- private:
- internal::scoped_ptr<const LossFunction> f_, g_;
- const Ownership ownership_f_, ownership_g_;
-};
-
-// The discussion above has to do with length scaling: it affects the space
-// in which s is measured. Sometimes you want to simply scale the output
-// value of the robustifier. For example, you might want to weight
-// different error terms differently (e.g., weight pixel reprojection
-// errors differently from terrain errors).
-//
-// If rho is the wrapped robustifier, then this simply outputs
-// s -> a * rho(s)
-//
-// The first and second derivatives are, not surprisingly
-// s -> a * rho'(s)
-// s -> a * rho''(s)
-//
-// Since we treat the a NULL Loss function as the Identity loss
-// function, rho = NULL is a valid input and will result in the input
-// being scaled by a. This provides a simple way of implementing a
-// scaled ResidualBlock.
-class CERES_EXPORT ScaledLoss : public LossFunction {
- public:
- // Constructs a ScaledLoss wrapping another loss function. Takes
- // ownership of the wrapped loss function or not depending on the
- // ownership parameter.
- ScaledLoss(const LossFunction* rho, double a, Ownership ownership) :
- rho_(rho), a_(a), ownership_(ownership) { }
-
- virtual ~ScaledLoss() {
- if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
- rho_.release();
- }
- }
- virtual void Evaluate(double, double*) const;
-
- private:
- internal::scoped_ptr<const LossFunction> rho_;
- const double a_;
- const Ownership ownership_;
- CERES_DISALLOW_COPY_AND_ASSIGN(ScaledLoss);
-};
-
-// Sometimes after the optimization problem has been constructed, we
-// wish to mutate the scale of the loss function. For example, when
-// performing estimation from data which has substantial outliers,
-// convergence can be improved by starting out with a large scale,
-// optimizing the problem and then reducing the scale. This can have
-// better convergence behaviour than just using a loss function with a
-// small scale.
-//
-// This templated class allows the user to implement a loss function
-// whose scale can be mutated after an optimization problem has been
-// constructed.
-//
-// Example usage
-//
-// Problem problem;
-//
-// // Add parameter blocks
-//
-// CostFunction* cost_function =
-// new AutoDiffCostFunction < UW_Camera_Mapper, 2, 9, 3>(
-// new UW_Camera_Mapper(feature_x, feature_y));
-//
-// LossFunctionWrapper* loss_function(new HuberLoss(1.0), TAKE_OWNERSHIP);
-//
-// problem.AddResidualBlock(cost_function, loss_function, parameters);
-//
-// Solver::Options options;
-// Solger::Summary summary;
-//
-// Solve(options, &problem, &summary)
-//
-// loss_function->Reset(new HuberLoss(1.0), TAKE_OWNERSHIP);
-//
-// Solve(options, &problem, &summary)
-//
-class CERES_EXPORT LossFunctionWrapper : public LossFunction {
- public:
- LossFunctionWrapper(LossFunction* rho, Ownership ownership)
- : rho_(rho), ownership_(ownership) {
- }
-
- virtual ~LossFunctionWrapper() {
- if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
- rho_.release();
- }
- }
-
- virtual void Evaluate(double sq_norm, double out[3]) const {
- CHECK_NOTNULL(rho_.get());
- rho_->Evaluate(sq_norm, out);
- }
-
- void Reset(LossFunction* rho, Ownership ownership) {
- if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
- rho_.release();
- }
- rho_.reset(rho);
- ownership_ = ownership;
- }
-
- private:
- internal::scoped_ptr<const LossFunction> rho_;
- Ownership ownership_;
- CERES_DISALLOW_COPY_AND_ASSIGN(LossFunctionWrapper);
-};
-
-} // namespace ceres
-
-#include "ceres/internal/disable_warnings.h"
-
-#endif // CERES_PUBLIC_LOSS_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/normal_prior.h b/extern/libmv/third_party/ceres/include/ceres/normal_prior.h
deleted file mode 100644
index df665054530..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/normal_prior.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Cost term that implements a prior on a parameter block using a
-// normal distribution.
-
-#ifndef CERES_PUBLIC_NORMAL_PRIOR_H_
-#define CERES_PUBLIC_NORMAL_PRIOR_H_
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// Implements a cost function of the form
-//
-// cost(x) = ||A(x - b)||^2
-//
-// where, the matrix A and the vector b are fixed and x is the
-// variable. In case the user is interested in implementing a cost
-// function of the form
-//
-// cost(x) = (x - mu)^T S^{-1} (x - mu)
-//
-// where, mu is a vector and S is a covariance matrix, then, A =
-// S^{-1/2}, i.e the matrix A is the square root of the inverse of the
-// covariance, also known as the stiffness matrix. There are however
-// no restrictions on the shape of A. It is free to be rectangular,
-// which would be the case if the covariance matrix S is rank
-// deficient.
-
-class CERES_EXPORT NormalPrior: public CostFunction {
- public:
- // Check that the number of rows in the vector b are the same as the
- // number of columns in the matrix A, crash otherwise.
- NormalPrior(const Matrix& A, const Vector& b);
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const;
- private:
- Matrix A_;
- Vector b_;
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_NORMAL_PRIOR_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h
deleted file mode 100644
index de6b74ad552..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h
+++ /dev/null
@@ -1,315 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-//
-// Create CostFunctions as needed by the least squares framework with jacobians
-// computed via numeric (a.k.a. finite) differentiation. For more details see
-// http://en.wikipedia.org/wiki/Numerical_differentiation.
-//
-// To get an numerically differentiated cost function, you must define
-// a class with a operator() (a functor) that computes the residuals.
-//
-// The function must write the computed value in the last argument
-// (the only non-const one) and return true to indicate success.
-// Please see cost_function.h for details on how the return value
-// maybe used to impose simple constraints on the parameter block.
-//
-// For example, consider a scalar error e = k - x'y, where both x and y are
-// two-dimensional column vector parameters, the prime sign indicates
-// transposition, and k is a constant. The form of this error, which is the
-// difference between a constant and an expression, is a common pattern in least
-// squares problems. For example, the value x'y might be the model expectation
-// for a series of measurements, where there is an instance of the cost function
-// for each measurement k.
-//
-// The actual cost added to the total problem is e^2, or (k - x'k)^2; however,
-// the squaring is implicitly done by the optimization framework.
-//
-// To write an numerically-differentiable cost function for the above model, first
-// define the object
-//
-// class MyScalarCostFunctor {
-// MyScalarCostFunctor(double k): k_(k) {}
-//
-// bool operator()(const double* const x,
-// const double* const y,
-// double* residuals) const {
-// residuals[0] = k_ - x[0] * y[0] + x[1] * y[1];
-// return true;
-// }
-//
-// private:
-// double k_;
-// };
-//
-// Note that in the declaration of operator() the input parameters x
-// and y come first, and are passed as const pointers to arrays of
-// doubles. If there were three input parameters, then the third input
-// parameter would come after y. The output is always the last
-// parameter, and is also a pointer to an array. In the example above,
-// the residual is a scalar, so only residuals[0] is set.
-//
-// Then given this class definition, the numerically differentiated
-// cost function with central differences used for computing the
-// derivative can be constructed as follows.
-//
-// CostFunction* cost_function
-// = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
-// new MyScalarCostFunctor(1.0)); ^ ^ ^ ^
-// | | | |
-// Finite Differencing Scheme -+ | | |
-// Dimension of residual ------------+ | |
-// Dimension of x ----------------------+ |
-// Dimension of y -------------------------+
-//
-// In this example, there is usually an instance for each measurement of k.
-//
-// In the instantiation above, the template parameters following
-// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing
-// a 1-dimensional output from two arguments, both 2-dimensional.
-//
-// NumericDiffCostFunction also supports cost functions with a
-// runtime-determined number of residuals. For example:
-//
-// CostFunction* cost_function
-// = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
-// new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
-// TAKE_OWNERSHIP, | | |
-// runtime_number_of_residuals); <----+ | | |
-// | | | |
-// | | | |
-// Actual number of residuals ------+ | | |
-// Indicate dynamic number of residuals --------------------+ | |
-// Dimension of x ------------------------------------------------+ |
-// Dimension of y ---------------------------------------------------+
-//
-// The framework can currently accommodate cost functions of up to 10
-// independent variables, and there is no limit on the dimensionality
-// of each of them.
-//
-// The central difference method is considerably more accurate at the cost of
-// twice as many function evaluations than forward difference. Consider using
-// central differences begin with, and only after that works, trying forward
-// difference to improve performance.
-//
-// WARNING #1: A common beginner's error when first using
-// NumericDiffCostFunction is to get the sizing wrong. In particular,
-// there is a tendency to set the template parameters to (dimension of
-// residual, number of parameters) instead of passing a dimension
-// parameter for *every parameter*. In the example above, that would
-// be <MyScalarCostFunctor, 1, 2>, which is missing the last '2'
-// argument. Please be careful when setting the size parameters.
-//
-////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////
-//
-// ALTERNATE INTERFACE
-//
-// For a variety of reason, including compatibility with legacy code,
-// NumericDiffCostFunction can also take CostFunction objects as
-// input. The following describes how.
-//
-// To get a numerically differentiated cost function, define a
-// subclass of CostFunction such that the Evaluate() function ignores
-// the jacobian parameter. The numeric differentiation wrapper will
-// fill in the jacobian parameter if necessary by repeatedly calling
-// the Evaluate() function with small changes to the appropriate
-// parameters, and computing the slope. For performance, the numeric
-// differentiation wrapper class is templated on the concrete cost
-// function, even though it could be implemented only in terms of the
-// virtual CostFunction interface.
-//
-// The numerically differentiated version of a cost function for a cost function
-// can be constructed as follows:
-//
-// CostFunction* cost_function
-// = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
-// new MyCostFunction(...), TAKE_OWNERSHIP);
-//
-// where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
-// respectively. Look at the tests for a more detailed example.
-//
-// TODO(keir): Characterize accuracy; mention pitfalls; provide alternatives.
-
-#ifndef CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
-#define CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
-
-#include "Eigen/Dense"
-#include "ceres/cost_function.h"
-#include "ceres/internal/numeric_diff.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/sized_cost_function.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-template <typename CostFunctor,
- NumericDiffMethod method = CENTRAL,
- int kNumResiduals = 0, // Number of residuals, or ceres::DYNAMIC
- int N0 = 0, // Number of parameters in block 0.
- int N1 = 0, // Number of parameters in block 1.
- int N2 = 0, // Number of parameters in block 2.
- int N3 = 0, // Number of parameters in block 3.
- int N4 = 0, // Number of parameters in block 4.
- int N5 = 0, // Number of parameters in block 5.
- int N6 = 0, // Number of parameters in block 6.
- int N7 = 0, // Number of parameters in block 7.
- int N8 = 0, // Number of parameters in block 8.
- int N9 = 0> // Number of parameters in block 9.
-class NumericDiffCostFunction
- : public SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9> {
- public:
- NumericDiffCostFunction(CostFunctor* functor,
- Ownership ownership = TAKE_OWNERSHIP,
- int num_residuals = kNumResiduals,
- const double relative_step_size = 1e-6)
- :functor_(functor),
- ownership_(ownership),
- relative_step_size_(relative_step_size) {
- if (kNumResiduals == DYNAMIC) {
- SizedCostFunction<kNumResiduals,
- N0, N1, N2, N3, N4,
- N5, N6, N7, N8, N9>
- ::set_num_residuals(num_residuals);
- }
- }
-
- ~NumericDiffCostFunction() {
- if (ownership_ != TAKE_OWNERSHIP) {
- functor_.release();
- }
- }
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- using internal::FixedArray;
- using internal::NumericDiff;
-
- const int kNumParameters = N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
- const int kNumParameterBlocks =
- (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) +
- (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0);
-
- // Get the function value (residuals) at the the point to evaluate.
- if (!internal::EvaluateImpl<CostFunctor,
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
- functor_.get(),
- parameters,
- residuals,
- functor_.get())) {
- return false;
- }
-
- if (jacobians == NULL) {
- return true;
- }
-
- // Create a copy of the parameters which will get mutated.
- FixedArray<double> parameters_copy(kNumParameters);
- FixedArray<double*> parameters_reference_copy(kNumParameterBlocks);
-
- parameters_reference_copy[0] = parameters_copy.get();
- if (N1) parameters_reference_copy[1] = parameters_reference_copy[0] + N0;
- if (N2) parameters_reference_copy[2] = parameters_reference_copy[1] + N1;
- if (N3) parameters_reference_copy[3] = parameters_reference_copy[2] + N2;
- if (N4) parameters_reference_copy[4] = parameters_reference_copy[3] + N3;
- if (N5) parameters_reference_copy[5] = parameters_reference_copy[4] + N4;
- if (N6) parameters_reference_copy[6] = parameters_reference_copy[5] + N5;
- if (N7) parameters_reference_copy[7] = parameters_reference_copy[6] + N6;
- if (N8) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
- if (N9) parameters_reference_copy[9] = parameters_reference_copy[8] + N8;
-
-#define COPY_PARAMETER_BLOCK(block) \
- if (N ## block) memcpy(parameters_reference_copy[block], \
- parameters[block], \
- sizeof(double) * N ## block); // NOLINT
-
- COPY_PARAMETER_BLOCK(0);
- COPY_PARAMETER_BLOCK(1);
- COPY_PARAMETER_BLOCK(2);
- COPY_PARAMETER_BLOCK(3);
- COPY_PARAMETER_BLOCK(4);
- COPY_PARAMETER_BLOCK(5);
- COPY_PARAMETER_BLOCK(6);
- COPY_PARAMETER_BLOCK(7);
- COPY_PARAMETER_BLOCK(8);
- COPY_PARAMETER_BLOCK(9);
-
-#undef COPY_PARAMETER_BLOCK
-
-#define EVALUATE_JACOBIAN_FOR_BLOCK(block) \
- if (N ## block && jacobians[block] != NULL) { \
- if (!NumericDiff<CostFunctor, \
- method, \
- kNumResiduals, \
- N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, \
- block, \
- N ## block >::EvaluateJacobianForParameterBlock( \
- functor_.get(), \
- residuals, \
- relative_step_size_, \
- SizedCostFunction<kNumResiduals, \
- N0, N1, N2, N3, N4, \
- N5, N6, N7, N8, N9>::num_residuals(), \
- parameters_reference_copy.get(), \
- jacobians[block])) { \
- return false; \
- } \
- }
-
- EVALUATE_JACOBIAN_FOR_BLOCK(0);
- EVALUATE_JACOBIAN_FOR_BLOCK(1);
- EVALUATE_JACOBIAN_FOR_BLOCK(2);
- EVALUATE_JACOBIAN_FOR_BLOCK(3);
- EVALUATE_JACOBIAN_FOR_BLOCK(4);
- EVALUATE_JACOBIAN_FOR_BLOCK(5);
- EVALUATE_JACOBIAN_FOR_BLOCK(6);
- EVALUATE_JACOBIAN_FOR_BLOCK(7);
- EVALUATE_JACOBIAN_FOR_BLOCK(8);
- EVALUATE_JACOBIAN_FOR_BLOCK(9);
-
-#undef EVALUATE_JACOBIAN_FOR_BLOCK
-
- return true;
- }
-
- private:
- internal::scoped_ptr<CostFunctor> functor_;
- Ownership ownership_;
- const double relative_step_size_;
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_NUMERIC_DIFF_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h b/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h
deleted file mode 100644
index c316d712e97..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h
+++ /dev/null
@@ -1,201 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_ORDERED_GROUPS_H_
-#define CERES_PUBLIC_ORDERED_GROUPS_H_
-
-#include <map>
-#include <set>
-#include <vector>
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-// A class for storing and manipulating an ordered collection of
-// groups/sets with the following semantics:
-//
-// Group ids are non-negative integer values. Elements are any type
-// that can serve as a key in a map or an element of a set.
-//
-// An element can only belong to one group at a time. A group may
-// contain an arbitrary number of elements.
-//
-// Groups are ordered by their group id.
-template <typename T>
-class OrderedGroups {
- public:
- // Add an element to a group. If a group with this id does not
- // exist, one is created. This method can be called any number of
- // times for the same element. Group ids should be non-negative
- // numbers.
- //
- // Return value indicates if adding the element was a success.
- bool AddElementToGroup(const T element, const int group) {
- if (group < 0) {
- return false;
- }
-
- typename map<T, int>::const_iterator it = element_to_group_.find(element);
- if (it != element_to_group_.end()) {
- if (it->second == group) {
- // Element is already in the right group, nothing to do.
- return true;
- }
-
- group_to_elements_[it->second].erase(element);
- if (group_to_elements_[it->second].size() == 0) {
- group_to_elements_.erase(it->second);
- }
- }
-
- element_to_group_[element] = group;
- group_to_elements_[group].insert(element);
- return true;
- }
-
- void Clear() {
- group_to_elements_.clear();
- element_to_group_.clear();
- }
-
- // Remove the element, no matter what group it is in. Return value
- // indicates if the element was actually removed.
- bool Remove(const T element) {
- const int current_group = GroupId(element);
- if (current_group < 0) {
- return false;
- }
-
- group_to_elements_[current_group].erase(element);
-
- if (group_to_elements_[current_group].size() == 0) {
- // If the group is empty, then get rid of it.
- group_to_elements_.erase(current_group);
- }
-
- element_to_group_.erase(element);
- return true;
- }
-
- // Bulk remove elements. The return value indicates the number of
- // elements successfully removed.
- int Remove(const vector<T>& elements) {
- if (NumElements() == 0 || elements.size() == 0) {
- return 0;
- }
-
- int num_removed = 0;
- for (int i = 0; i < elements.size(); ++i) {
- num_removed += Remove(elements[i]);
- }
- return num_removed;
- }
-
- // Reverse the order of the groups in place.
- void Reverse() {
- typename map<int, set<T> >::reverse_iterator it =
- group_to_elements_.rbegin();
- map<int, set<T> > new_group_to_elements;
- new_group_to_elements[it->first] = it->second;
-
- int new_group_id = it->first + 1;
- for (++it; it != group_to_elements_.rend(); ++it) {
- for (typename set<T>::const_iterator element_it = it->second.begin();
- element_it != it->second.end();
- ++element_it) {
- element_to_group_[*element_it] = new_group_id;
- }
- new_group_to_elements[new_group_id] = it->second;
- new_group_id++;
- }
-
- group_to_elements_.swap(new_group_to_elements);
- }
-
- // Return the group id for the element. If the element is not a
- // member of any group, return -1.
- int GroupId(const T element) const {
- typename map<T, int>::const_iterator it = element_to_group_.find(element);
- if (it == element_to_group_.end()) {
- return -1;
- }
- return it->second;
- }
-
- bool IsMember(const T element) const {
- typename map<T, int>::const_iterator it = element_to_group_.find(element);
- return (it != element_to_group_.end());
- }
-
- // This function always succeeds, i.e., implicitly there exists a
- // group for every integer.
- int GroupSize(const int group) const {
- typename map<int, set<T> >::const_iterator it =
- group_to_elements_.find(group);
- return (it == group_to_elements_.end()) ? 0 : it->second.size();
- }
-
- int NumElements() const {
- return element_to_group_.size();
- }
-
- // Number of groups with one or more elements.
- int NumGroups() const {
- return group_to_elements_.size();
- }
-
- // The first group with one or more elements. Calling this when
- // there are no groups with non-zero elements will result in a
- // crash.
- int MinNonZeroGroup() const {
- CHECK_NE(NumGroups(), 0);
- return group_to_elements_.begin()->first;
- }
-
- const map<int, set<T> >& group_to_elements() const {
- return group_to_elements_;
- }
-
- const map<T, int>& element_to_group() const {
- return element_to_group_;
- }
-
- private:
- map<int, set<T> > group_to_elements_;
- map<T, int> element_to_group_;
-};
-
-// Typedef for the most commonly used version of OrderedGroups.
-typedef OrderedGroups<double*> ParameterBlockOrdering;
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_ORDERED_GROUP_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/problem.h b/extern/libmv/third_party/ceres/include/ceres/problem.h
deleted file mode 100644
index f75ede3a5c6..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/problem.h
+++ /dev/null
@@ -1,481 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// keir@google.com (Keir Mierle)
-//
-// The Problem object is used to build and hold least squares problems.
-
-#ifndef CERES_PUBLIC_PROBLEM_H_
-#define CERES_PUBLIC_PROBLEM_H_
-
-#include <cstddef>
-#include <map>
-#include <set>
-#include <vector>
-
-#include "glog/logging.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-
-namespace ceres {
-
-class CostFunction;
-class LossFunction;
-class LocalParameterization;
-class Solver;
-struct CRSMatrix;
-
-namespace internal {
-class Preprocessor;
-class ProblemImpl;
-class ParameterBlock;
-class ResidualBlock;
-} // namespace internal
-
-// A ResidualBlockId is an opaque handle clients can use to remove residual
-// blocks from a Problem after adding them.
-typedef internal::ResidualBlock* ResidualBlockId;
-
-// A class to represent non-linear least squares problems. Such
-// problems have a cost function that is a sum of error terms (known
-// as "residuals"), where each residual is a function of some subset
-// of the parameters. The cost function takes the form
-//
-// N 1
-// SUM --- loss( || r_i1, r_i2,..., r_ik ||^2 ),
-// i=1 2
-//
-// where
-//
-// r_ij is residual number i, component j; the residual is a
-// function of some subset of the parameters x1...xk. For
-// example, in a structure from motion problem a residual
-// might be the difference between a measured point in an
-// image and the reprojected position for the matching
-// camera, point pair. The residual would have two
-// components, error in x and error in y.
-//
-// loss(y) is the loss function; for example, squared error or
-// Huber L1 loss. If loss(y) = y, then the cost function is
-// non-robustified least squares.
-//
-// This class is specifically designed to address the important subset
-// of "sparse" least squares problems, where each component of the
-// residual depends only on a small number number of parameters, even
-// though the total number of residuals and parameters may be very
-// large. This property affords tremendous gains in scale, allowing
-// efficient solving of large problems that are otherwise
-// inaccessible.
-//
-// The canonical example of a sparse least squares problem is
-// "structure-from-motion" (SFM), where the parameters are points and
-// cameras, and residuals are reprojection errors. Typically a single
-// residual will depend only on 9 parameters (3 for the point, 6 for
-// the camera).
-//
-// To create a least squares problem, use the AddResidualBlock() and
-// AddParameterBlock() methods, documented below. Here is an example least
-// squares problem containing 3 parameter blocks of sizes 3, 4 and 5
-// respectively and two residual terms of size 2 and 6:
-//
-// double x1[] = { 1.0, 2.0, 3.0 };
-// double x2[] = { 1.0, 2.0, 3.0, 5.0 };
-// double x3[] = { 1.0, 2.0, 3.0, 6.0, 7.0 };
-//
-// Problem problem;
-//
-// problem.AddResidualBlock(new MyUnaryCostFunction(...), x1);
-// problem.AddResidualBlock(new MyBinaryCostFunction(...), x2, x3);
-//
-// Please see cost_function.h for details of the CostFunction object.
-class CERES_EXPORT Problem {
- public:
- struct CERES_EXPORT Options {
- Options()
- : cost_function_ownership(TAKE_OWNERSHIP),
- loss_function_ownership(TAKE_OWNERSHIP),
- local_parameterization_ownership(TAKE_OWNERSHIP),
- enable_fast_removal(false),
- disable_all_safety_checks(false) {}
-
- // These flags control whether the Problem object owns the cost
- // functions, loss functions, and parameterizations passed into
- // the Problem. If set to TAKE_OWNERSHIP, then the problem object
- // will delete the corresponding cost or loss functions on
- // destruction. The destructor is careful to delete the pointers
- // only once, since sharing cost/loss/parameterizations is
- // allowed.
- Ownership cost_function_ownership;
- Ownership loss_function_ownership;
- Ownership local_parameterization_ownership;
-
- // If true, trades memory for faster RemoveResidualBlock() and
- // RemoveParameterBlock() operations.
- //
- // By default, RemoveParameterBlock() and RemoveResidualBlock() take time
- // proportional to the size of the entire problem. If you only ever remove
- // parameters or residuals from the problem occassionally, this might be
- // acceptable. However, if you have memory to spare, enable this option to
- // make RemoveParameterBlock() take time proportional to the number of
- // residual blocks that depend on it, and RemoveResidualBlock() take (on
- // average) constant time.
- //
- // The increase in memory usage is twofold: an additonal hash set per
- // parameter block containing all the residuals that depend on the parameter
- // block; and a hash set in the problem containing all residuals.
- bool enable_fast_removal;
-
- // By default, Ceres performs a variety of safety checks when constructing
- // the problem. There is a small but measurable performance penalty to
- // these checks, typically around 5% of construction time. If you are sure
- // your problem construction is correct, and 5% of the problem construction
- // time is truly an overhead you want to avoid, then you can set
- // disable_all_safety_checks to true.
- //
- // WARNING: Do not set this to true, unless you are absolutely sure of what
- // you are doing.
- bool disable_all_safety_checks;
- };
-
- // The default constructor is equivalent to the
- // invocation Problem(Problem::Options()).
- Problem();
- explicit Problem(const Options& options);
-
- ~Problem();
-
- // Add a residual block to the overall cost function. The cost
- // function carries with it information about the sizes of the
- // parameter blocks it expects. The function checks that these match
- // the sizes of the parameter blocks listed in parameter_blocks. The
- // program aborts if a mismatch is detected. loss_function can be
- // NULL, in which case the cost of the term is just the squared norm
- // of the residuals.
- //
- // The user has the option of explicitly adding the parameter blocks
- // using AddParameterBlock. This causes additional correctness
- // checking; however, AddResidualBlock implicitly adds the parameter
- // blocks if they are not present, so calling AddParameterBlock
- // explicitly is not required.
- //
- // The Problem object by default takes ownership of the
- // cost_function and loss_function pointers. These objects remain
- // live for the life of the Problem object. If the user wishes to
- // keep control over the destruction of these objects, then they can
- // do this by setting the corresponding enums in the Options struct.
- //
- // Note: Even though the Problem takes ownership of cost_function
- // and loss_function, it does not preclude the user from re-using
- // them in another residual block. The destructor takes care to call
- // delete on each cost_function or loss_function pointer only once,
- // regardless of how many residual blocks refer to them.
- //
- // Example usage:
- //
- // double x1[] = {1.0, 2.0, 3.0};
- // double x2[] = {1.0, 2.0, 5.0, 6.0};
- // double x3[] = {3.0, 6.0, 2.0, 5.0, 1.0};
- //
- // Problem problem;
- //
- // problem.AddResidualBlock(new MyUnaryCostFunction(...), NULL, x1);
- // problem.AddResidualBlock(new MyBinaryCostFunction(...), NULL, x2, x1);
- //
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- const vector<double*>& parameter_blocks);
-
- // Convenience methods for adding residuals with a small number of
- // parameters. This is the common case. Instead of specifying the
- // parameter block arguments as a vector, list them as pointers.
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8,
- double* x9);
-
- // Add a parameter block with appropriate size to the problem.
- // Repeated calls with the same arguments are ignored. Repeated
- // calls with the same double pointer but a different size results
- // in undefined behaviour.
- void AddParameterBlock(double* values, int size);
-
- // Add a parameter block with appropriate size and parameterization
- // to the problem. Repeated calls with the same arguments are
- // ignored. Repeated calls with the same double pointer but a
- // different size results in undefined behaviour.
- void AddParameterBlock(double* values,
- int size,
- LocalParameterization* local_parameterization);
-
- // Remove a parameter block from the problem. The parameterization of the
- // parameter block, if it exists, will persist until the deletion of the
- // problem (similar to cost/loss functions in residual block removal). Any
- // residual blocks that depend on the parameter are also removed, as
- // described above in RemoveResidualBlock().
- //
- // If Problem::Options::enable_fast_removal is true, then the
- // removal is fast (almost constant time). Otherwise, removing a parameter
- // block will incur a scan of the entire Problem object.
- //
- // WARNING: Removing a residual or parameter block will destroy the implicit
- // ordering, rendering the jacobian or residuals returned from the solver
- // uninterpretable. If you depend on the evaluated jacobian, do not use
- // remove! This may change in a future release.
- void RemoveParameterBlock(double* values);
-
- // Remove a residual block from the problem. Any parameters that the residual
- // block depends on are not removed. The cost and loss functions for the
- // residual block will not get deleted immediately; won't happen until the
- // problem itself is deleted.
- //
- // WARNING: Removing a residual or parameter block will destroy the implicit
- // ordering, rendering the jacobian or residuals returned from the solver
- // uninterpretable. If you depend on the evaluated jacobian, do not use
- // remove! This may change in a future release.
- void RemoveResidualBlock(ResidualBlockId residual_block);
-
- // Hold the indicated parameter block constant during optimization.
- void SetParameterBlockConstant(double* values);
-
- // Allow the indicated parameter block to vary during optimization.
- void SetParameterBlockVariable(double* values);
-
- // Set the local parameterization for one of the parameter blocks.
- // The local_parameterization is owned by the Problem by default. It
- // is acceptable to set the same parameterization for multiple
- // parameters; the destructor is careful to delete local
- // parameterizations only once. The local parameterization can only
- // be set once per parameter, and cannot be changed once set.
- void SetParameterization(double* values,
- LocalParameterization* local_parameterization);
-
- // Get the local parameterization object associated with this
- // parameter block. If there is no parameterization object
- // associated then NULL is returned.
- const LocalParameterization* GetParameterization(double* values) const;
-
- // Set the lower/upper bound for the parameter with position "index".
- void SetParameterLowerBound(double* values, int index, double lower_bound);
- void SetParameterUpperBound(double* values, int index, double upper_bound);
-
- // Number of parameter blocks in the problem. Always equals
- // parameter_blocks().size() and parameter_block_sizes().size().
- int NumParameterBlocks() const;
-
- // The size of the parameter vector obtained by summing over the
- // sizes of all the parameter blocks.
- int NumParameters() const;
-
- // Number of residual blocks in the problem. Always equals
- // residual_blocks().size().
- int NumResidualBlocks() const;
-
- // The size of the residual vector obtained by summing over the
- // sizes of all of the residual blocks.
- int NumResiduals() const;
-
- // The size of the parameter block.
- int ParameterBlockSize(const double* values) const;
-
- // The size of local parameterization for the parameter block. If
- // there is no local parameterization associated with this parameter
- // block, then ParameterBlockLocalSize = ParameterBlockSize.
- int ParameterBlockLocalSize(const double* values) const;
-
- // Is the given parameter block present in this problem or not?
- bool HasParameterBlock(const double* values) const;
-
- // Fills the passed parameter_blocks vector with pointers to the
- // parameter blocks currently in the problem. After this call,
- // parameter_block.size() == NumParameterBlocks.
- void GetParameterBlocks(vector<double*>* parameter_blocks) const;
-
- // Fills the passed residual_blocks vector with pointers to the
- // residual blocks currently in the problem. After this call,
- // residual_blocks.size() == NumResidualBlocks.
- void GetResidualBlocks(vector<ResidualBlockId>* residual_blocks) const;
-
- // Get all the parameter blocks that depend on the given residual block.
- void GetParameterBlocksForResidualBlock(
- const ResidualBlockId residual_block,
- vector<double*>* parameter_blocks) const;
-
- // Get the CostFunction for the given residual block.
- const CostFunction* GetCostFunctionForResidualBlock(
- const ResidualBlockId residual_block) const;
-
- // Get the LossFunction for the given residual block. Returns NULL
- // if no loss function is associated with this residual block.
- const LossFunction* GetLossFunctionForResidualBlock(
- const ResidualBlockId residual_block) const;
-
- // Get all the residual blocks that depend on the given parameter block.
- //
- // If Problem::Options::enable_fast_removal is true, then
- // getting the residual blocks is fast and depends only on the number of
- // residual blocks. Otherwise, getting the residual blocks for a parameter
- // block will incur a scan of the entire Problem object.
- void GetResidualBlocksForParameterBlock(
- const double* values,
- vector<ResidualBlockId>* residual_blocks) const;
-
- // Options struct to control Problem::Evaluate.
- struct EvaluateOptions {
- EvaluateOptions()
- : apply_loss_function(true),
- num_threads(1) {
- }
-
- // The set of parameter blocks for which evaluation should be
- // performed. This vector determines the order that parameter
- // blocks occur in the gradient vector and in the columns of the
- // jacobian matrix. If parameter_blocks is empty, then it is
- // assumed to be equal to vector containing ALL the parameter
- // blocks. Generally speaking the parameter blocks will occur in
- // the order in which they were added to the problem. But, this
- // may change if the user removes any parameter blocks from the
- // problem.
- //
- // NOTE: This vector should contain the same pointers as the ones
- // used to add parameter blocks to the Problem. These parameter
- // block should NOT point to new memory locations. Bad things will
- // happen otherwise.
- vector<double*> parameter_blocks;
-
- // The set of residual blocks to evaluate. This vector determines
- // the order in which the residuals occur, and how the rows of the
- // jacobian are ordered. If residual_blocks is empty, then it is
- // assumed to be equal to the vector containing all the residual
- // blocks. If this vector is empty, then it is assumed to be equal
- // to a vector containing ALL the residual blocks. Generally
- // speaking the residual blocks will occur in the order in which
- // they were added to the problem. But, this may change if the
- // user removes any residual blocks from the problem.
- vector<ResidualBlockId> residual_blocks;
-
- // Even though the residual blocks in the problem may contain loss
- // functions, setting apply_loss_function to false will turn off
- // the application of the loss function to the output of the cost
- // function. This is of use for example if the user wishes to
- // analyse the solution quality by studying the distribution of
- // residuals before and after the solve.
- bool apply_loss_function;
-
- int num_threads;
- };
-
- // Evaluate Problem. Any of the output pointers can be NULL. Which
- // residual blocks and parameter blocks are used is controlled by
- // the EvaluateOptions struct above.
- //
- // Note 1: The evaluation will use the values stored in the memory
- // locations pointed to by the parameter block pointers used at the
- // time of the construction of the problem. i.e.,
- //
- // Problem problem;
- // double x = 1;
- // problem.AddResidualBlock(new MyCostFunction, NULL, &x);
- //
- // double cost = 0.0;
- // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
- //
- // The cost is evaluated at x = 1. If you wish to evaluate the
- // problem at x = 2, then
- //
- // x = 2;
- // problem.Evaluate(Problem::EvaluateOptions(), &cost, NULL, NULL, NULL);
- //
- // is the way to do so.
- //
- // Note 2: If no local parameterizations are used, then the size of
- // the gradient vector (and the number of columns in the jacobian)
- // is the sum of the sizes of all the parameter blocks. If a
- // parameter block has a local parameterization, then it contributes
- // "LocalSize" entries to the gradient vector (and the number of
- // columns in the jacobian).
- bool Evaluate(const EvaluateOptions& options,
- double* cost,
- vector<double>* residuals,
- vector<double>* gradient,
- CRSMatrix* jacobian);
-
- private:
- friend class Solver;
- friend class Covariance;
- internal::scoped_ptr<internal::ProblemImpl> problem_impl_;
- CERES_DISALLOW_COPY_AND_ASSIGN(Problem);
-};
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_PROBLEM_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/rotation.h b/extern/libmv/third_party/ceres/include/ceres/rotation.h
deleted file mode 100644
index e3dbfe84a5a..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/rotation.h
+++ /dev/null
@@ -1,645 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-//
-// Templated functions for manipulating rotations. The templated
-// functions are useful when implementing functors for automatic
-// differentiation.
-//
-// In the following, the Quaternions are laid out as 4-vectors, thus:
-//
-// q[0] scalar part.
-// q[1] coefficient of i.
-// q[2] coefficient of j.
-// q[3] coefficient of k.
-//
-// where: i*i = j*j = k*k = -1 and i*j = k, j*k = i, k*i = j.
-
-#ifndef CERES_PUBLIC_ROTATION_H_
-#define CERES_PUBLIC_ROTATION_H_
-
-#include <algorithm>
-#include <cmath>
-#include "glog/logging.h"
-
-namespace ceres {
-
-// Trivial wrapper to index linear arrays as matrices, given a fixed
-// column and row stride. When an array "T* array" is wrapped by a
-//
-// (const) MatrixAdapter<T, row_stride, col_stride> M"
-//
-// the expression M(i, j) is equivalent to
-//
-// arrary[i * row_stride + j * col_stride]
-//
-// Conversion functions to and from rotation matrices accept
-// MatrixAdapters to permit using row-major and column-major layouts,
-// and rotation matrices embedded in larger matrices (such as a 3x4
-// projection matrix).
-template <typename T, int row_stride, int col_stride>
-struct MatrixAdapter;
-
-// Convenience functions to create a MatrixAdapter that treats the
-// array pointed to by "pointer" as a 3x3 (contiguous) column-major or
-// row-major matrix.
-template <typename T>
-MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer);
-
-template <typename T>
-MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer);
-
-// Convert a value in combined axis-angle representation to a quaternion.
-// The value angle_axis is a triple whose norm is an angle in radians,
-// and whose direction is aligned with the axis of rotation,
-// and quaternion is a 4-tuple that will contain the resulting quaternion.
-// The implementation may be used with auto-differentiation up to the first
-// derivative, higher derivatives may have unexpected results near the origin.
-template<typename T>
-void AngleAxisToQuaternion(const T* angle_axis, T* quaternion);
-
-// Convert a quaternion to the equivalent combined axis-angle representation.
-// The value quaternion must be a unit quaternion - it is not normalized first,
-// and angle_axis will be filled with a value whose norm is the angle of
-// rotation in radians, and whose direction is the axis of rotation.
-// The implemention may be used with auto-differentiation up to the first
-// derivative, higher derivatives may have unexpected results near the origin.
-template<typename T>
-void QuaternionToAngleAxis(const T* quaternion, T* angle_axis);
-
-// Conversions between 3x3 rotation matrix (in column major order) and
-// axis-angle rotation representations. Templated for use with
-// autodifferentiation.
-template <typename T>
-void RotationMatrixToAngleAxis(const T* R, T* angle_axis);
-
-template <typename T, int row_stride, int col_stride>
-void RotationMatrixToAngleAxis(
- const MatrixAdapter<const T, row_stride, col_stride>& R,
- T* angle_axis);
-
-template <typename T>
-void AngleAxisToRotationMatrix(const T* angle_axis, T* R);
-
-template <typename T, int row_stride, int col_stride>
-void AngleAxisToRotationMatrix(
- const T* angle_axis,
- const MatrixAdapter<T, row_stride, col_stride>& R);
-
-// Conversions between 3x3 rotation matrix (in row major order) and
-// Euler angle (in degrees) rotation representations.
-//
-// The {pitch,roll,yaw} Euler angles are rotations around the {x,y,z}
-// axes, respectively. They are applied in that same order, so the
-// total rotation R is Rz * Ry * Rx.
-template <typename T>
-void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
-
-template <typename T, int row_stride, int col_stride>
-void EulerAnglesToRotationMatrix(
- const T* euler,
- const MatrixAdapter<T, row_stride, col_stride>& R);
-
-// Convert a 4-vector to a 3x3 scaled rotation matrix.
-//
-// The choice of rotation is such that the quaternion [1 0 0 0] goes to an
-// identity matrix and for small a, b, c the quaternion [1 a b c] goes to
-// the matrix
-//
-// [ 0 -c b ]
-// I + 2 [ c 0 -a ] + higher order terms
-// [ -b a 0 ]
-//
-// which corresponds to a Rodrigues approximation, the last matrix being
-// the cross-product matrix of [a b c]. Together with the property that
-// R(q1 * q2) = R(q1) * R(q2) this uniquely defines the mapping from q to R.
-//
-// The rotation matrix is row-major.
-//
-// No normalization of the quaternion is performed, i.e.
-// R = ||q||^2 * Q, where Q is an orthonormal matrix
-// such that det(Q) = 1 and Q*Q' = I
-template <typename T> inline
-void QuaternionToScaledRotation(const T q[4], T R[3 * 3]);
-
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToScaledRotation(
- const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R);
-
-// Same as above except that the rotation matrix is normalized by the
-// Frobenius norm, so that R * R' = I (and det(R) = 1).
-template <typename T> inline
-void QuaternionToRotation(const T q[4], T R[3 * 3]);
-
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToRotation(
- const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R);
-
-// Rotates a point pt by a quaternion q:
-//
-// result = R(q) * pt
-//
-// Assumes the quaternion is unit norm. This assumption allows us to
-// write the transform as (something)*pt + pt, as is clear from the
-// formula below. If you pass in a quaternion with |q|^2 = 2 then you
-// WILL NOT get back 2 times the result you get for a unit quaternion.
-template <typename T> inline
-void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
-
-// With this function you do not need to assume that q has unit norm.
-// It does assume that the norm is non-zero.
-template <typename T> inline
-void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]);
-
-// zw = z * w, where * is the Quaternion product between 4 vectors.
-template<typename T> inline
-void QuaternionProduct(const T z[4], const T w[4], T zw[4]);
-
-// xy = x cross y;
-template<typename T> inline
-void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]);
-
-template<typename T> inline
-T DotProduct(const T x[3], const T y[3]);
-
-// y = R(angle_axis) * x;
-template<typename T> inline
-void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]);
-
-// --- IMPLEMENTATION
-
-template<typename T, int row_stride, int col_stride>
-struct MatrixAdapter {
- T* pointer_;
- explicit MatrixAdapter(T* pointer)
- : pointer_(pointer)
- {}
-
- T& operator()(int r, int c) const {
- return pointer_[r * row_stride + c * col_stride];
- }
-};
-
-template <typename T>
-MatrixAdapter<T, 1, 3> ColumnMajorAdapter3x3(T* pointer) {
- return MatrixAdapter<T, 1, 3>(pointer);
-}
-
-template <typename T>
-MatrixAdapter<T, 3, 1> RowMajorAdapter3x3(T* pointer) {
- return MatrixAdapter<T, 3, 1>(pointer);
-}
-
-template<typename T>
-inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
- const T& a0 = angle_axis[0];
- const T& a1 = angle_axis[1];
- const T& a2 = angle_axis[2];
- const T theta_squared = a0 * a0 + a1 * a1 + a2 * a2;
-
- // For points not at the origin, the full conversion is numerically stable.
- if (theta_squared > T(0.0)) {
- const T theta = sqrt(theta_squared);
- const T half_theta = theta * T(0.5);
- const T k = sin(half_theta) / theta;
- quaternion[0] = cos(half_theta);
- quaternion[1] = a0 * k;
- quaternion[2] = a1 * k;
- quaternion[3] = a2 * k;
- } else {
- // At the origin, sqrt() will produce NaN in the derivative since
- // the argument is zero. By approximating with a Taylor series,
- // and truncating at one term, the value and first derivatives will be
- // computed correctly when Jets are used.
- const T k(0.5);
- quaternion[0] = T(1.0);
- quaternion[1] = a0 * k;
- quaternion[2] = a1 * k;
- quaternion[3] = a2 * k;
- }
-}
-
-template<typename T>
-inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
- const T& q1 = quaternion[1];
- const T& q2 = quaternion[2];
- const T& q3 = quaternion[3];
- const T sin_squared_theta = q1 * q1 + q2 * q2 + q3 * q3;
-
- // For quaternions representing non-zero rotation, the conversion
- // is numerically stable.
- if (sin_squared_theta > T(0.0)) {
- const T sin_theta = sqrt(sin_squared_theta);
- const T& cos_theta = quaternion[0];
-
- // If cos_theta is negative, theta is greater than pi/2, which
- // means that angle for the angle_axis vector which is 2 * theta
- // would be greater than pi.
- //
- // While this will result in the correct rotation, it does not
- // result in a normalized angle-axis vector.
- //
- // In that case we observe that 2 * theta ~ 2 * theta - 2 * pi,
- // which is equivalent saying
- //
- // theta - pi = atan(sin(theta - pi), cos(theta - pi))
- // = atan(-sin(theta), -cos(theta))
- //
- const T two_theta =
- T(2.0) * ((cos_theta < 0.0)
- ? atan2(-sin_theta, -cos_theta)
- : atan2(sin_theta, cos_theta));
- const T k = two_theta / sin_theta;
- angle_axis[0] = q1 * k;
- angle_axis[1] = q2 * k;
- angle_axis[2] = q3 * k;
- } else {
- // For zero rotation, sqrt() will produce NaN in the derivative since
- // the argument is zero. By approximating with a Taylor series,
- // and truncating at one term, the value and first derivatives will be
- // computed correctly when Jets are used.
- const T k(2.0);
- angle_axis[0] = q1 * k;
- angle_axis[1] = q2 * k;
- angle_axis[2] = q3 * k;
- }
-}
-
-// The conversion of a rotation matrix to the angle-axis form is
-// numerically problematic when then rotation angle is close to zero
-// or to Pi. The following implementation detects when these two cases
-// occurs and deals with them by taking code paths that are guaranteed
-// to not perform division by a small number.
-template <typename T>
-inline void RotationMatrixToAngleAxis(const T* R, T* angle_axis) {
- RotationMatrixToAngleAxis(ColumnMajorAdapter3x3(R), angle_axis);
-}
-
-template <typename T, int row_stride, int col_stride>
-void RotationMatrixToAngleAxis(
- const MatrixAdapter<const T, row_stride, col_stride>& R,
- T* angle_axis) {
- // x = k * 2 * sin(theta), where k is the axis of rotation.
- angle_axis[0] = R(2, 1) - R(1, 2);
- angle_axis[1] = R(0, 2) - R(2, 0);
- angle_axis[2] = R(1, 0) - R(0, 1);
-
- static const T kOne = T(1.0);
- static const T kTwo = T(2.0);
-
- // Since the right hand side may give numbers just above 1.0 or
- // below -1.0 leading to atan misbehaving, we threshold.
- T costheta = std::min(std::max((R(0, 0) + R(1, 1) + R(2, 2) - kOne) / kTwo,
- T(-1.0)),
- kOne);
-
- // sqrt is guaranteed to give non-negative results, so we only
- // threshold above.
- T sintheta = std::min(sqrt(angle_axis[0] * angle_axis[0] +
- angle_axis[1] * angle_axis[1] +
- angle_axis[2] * angle_axis[2]) / kTwo,
- kOne);
-
- // Use the arctan2 to get the right sign on theta
- const T theta = atan2(sintheta, costheta);
-
- // Case 1: sin(theta) is large enough, so dividing by it is not a
- // problem. We do not use abs here, because while jets.h imports
- // std::abs into the namespace, here in this file, abs resolves to
- // the int version of the function, which returns zero always.
- //
- // We use a threshold much larger then the machine epsilon, because
- // if sin(theta) is small, not only do we risk overflow but even if
- // that does not occur, just dividing by a small number will result
- // in numerical garbage. So we play it safe.
- static const double kThreshold = 1e-12;
- if ((sintheta > kThreshold) || (sintheta < -kThreshold)) {
- const T r = theta / (kTwo * sintheta);
- for (int i = 0; i < 3; ++i) {
- angle_axis[i] *= r;
- }
- return;
- }
-
- // Case 2: theta ~ 0, means sin(theta) ~ theta to a good
- // approximation.
- if (costheta > 0.0) {
- const T kHalf = T(0.5);
- for (int i = 0; i < 3; ++i) {
- angle_axis[i] *= kHalf;
- }
- return;
- }
-
- // Case 3: theta ~ pi, this is the hard case. Since theta is large,
- // and sin(theta) is small. Dividing by theta by sin(theta) will
- // either give an overflow or worse still numerically meaningless
- // results. Thus we use an alternate more complicated formula
- // here.
-
- // Since cos(theta) is negative, division by (1-cos(theta)) cannot
- // overflow.
- const T inv_one_minus_costheta = kOne / (kOne - costheta);
-
- // We now compute the absolute value of coordinates of the axis
- // vector using the diagonal entries of R. To resolve the sign of
- // these entries, we compare the sign of angle_axis[i]*sin(theta)
- // with the sign of sin(theta). If they are the same, then
- // angle_axis[i] should be positive, otherwise negative.
- for (int i = 0; i < 3; ++i) {
- angle_axis[i] = theta * sqrt((R(i, i) - costheta) * inv_one_minus_costheta);
- if (((sintheta < 0.0) && (angle_axis[i] > 0.0)) ||
- ((sintheta > 0.0) && (angle_axis[i] < 0.0))) {
- angle_axis[i] = -angle_axis[i];
- }
- }
-}
-
-template <typename T>
-inline void AngleAxisToRotationMatrix(const T* angle_axis, T* R) {
- AngleAxisToRotationMatrix(angle_axis, ColumnMajorAdapter3x3(R));
-}
-
-template <typename T, int row_stride, int col_stride>
-void AngleAxisToRotationMatrix(
- const T* angle_axis,
- const MatrixAdapter<T, row_stride, col_stride>& R) {
- static const T kOne = T(1.0);
- const T theta2 = DotProduct(angle_axis, angle_axis);
- if (theta2 > T(std::numeric_limits<double>::epsilon())) {
- // We want to be careful to only evaluate the square root if the
- // norm of the angle_axis vector is greater than zero. Otherwise
- // we get a division by zero.
- const T theta = sqrt(theta2);
- const T wx = angle_axis[0] / theta;
- const T wy = angle_axis[1] / theta;
- const T wz = angle_axis[2] / theta;
-
- const T costheta = cos(theta);
- const T sintheta = sin(theta);
-
- R(0, 0) = costheta + wx*wx*(kOne - costheta);
- R(1, 0) = wz*sintheta + wx*wy*(kOne - costheta);
- R(2, 0) = -wy*sintheta + wx*wz*(kOne - costheta);
- R(0, 1) = wx*wy*(kOne - costheta) - wz*sintheta;
- R(1, 1) = costheta + wy*wy*(kOne - costheta);
- R(2, 1) = wx*sintheta + wy*wz*(kOne - costheta);
- R(0, 2) = wy*sintheta + wx*wz*(kOne - costheta);
- R(1, 2) = -wx*sintheta + wy*wz*(kOne - costheta);
- R(2, 2) = costheta + wz*wz*(kOne - costheta);
- } else {
- // Near zero, we switch to using the first order Taylor expansion.
- R(0, 0) = kOne;
- R(1, 0) = angle_axis[2];
- R(2, 0) = -angle_axis[1];
- R(0, 1) = -angle_axis[2];
- R(1, 1) = kOne;
- R(2, 1) = angle_axis[0];
- R(0, 2) = angle_axis[1];
- R(1, 2) = -angle_axis[0];
- R(2, 2) = kOne;
- }
-}
-
-template <typename T>
-inline void EulerAnglesToRotationMatrix(const T* euler,
- const int row_stride_parameter,
- T* R) {
- CHECK_EQ(row_stride_parameter, 3);
- EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R));
-}
-
-template <typename T, int row_stride, int col_stride>
-void EulerAnglesToRotationMatrix(
- const T* euler,
- const MatrixAdapter<T, row_stride, col_stride>& R) {
- const double kPi = 3.14159265358979323846;
- const T degrees_to_radians(kPi / 180.0);
-
- const T pitch(euler[0] * degrees_to_radians);
- const T roll(euler[1] * degrees_to_radians);
- const T yaw(euler[2] * degrees_to_radians);
-
- const T c1 = cos(yaw);
- const T s1 = sin(yaw);
- const T c2 = cos(roll);
- const T s2 = sin(roll);
- const T c3 = cos(pitch);
- const T s3 = sin(pitch);
-
- R(0, 0) = c1*c2;
- R(0, 1) = -s1*c3 + c1*s2*s3;
- R(0, 2) = s1*s3 + c1*s2*c3;
-
- R(1, 0) = s1*c2;
- R(1, 1) = c1*c3 + s1*s2*s3;
- R(1, 2) = -c1*s3 + s1*s2*c3;
-
- R(2, 0) = -s2;
- R(2, 1) = c2*s3;
- R(2, 2) = c2*c3;
-}
-
-template <typename T> inline
-void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
- QuaternionToScaledRotation(q, RowMajorAdapter3x3(R));
-}
-
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToScaledRotation(
- const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R) {
- // Make convenient names for elements of q.
- T a = q[0];
- T b = q[1];
- T c = q[2];
- T d = q[3];
- // This is not to eliminate common sub-expression, but to
- // make the lines shorter so that they fit in 80 columns!
- T aa = a * a;
- T ab = a * b;
- T ac = a * c;
- T ad = a * d;
- T bb = b * b;
- T bc = b * c;
- T bd = b * d;
- T cc = c * c;
- T cd = c * d;
- T dd = d * d;
-
- R(0, 0) = aa + bb - cc - dd; R(0, 1) = T(2) * (bc - ad); R(0, 2) = T(2) * (ac + bd); // NOLINT
- R(1, 0) = T(2) * (ad + bc); R(1, 1) = aa - bb + cc - dd; R(1, 2) = T(2) * (cd - ab); // NOLINT
- R(2, 0) = T(2) * (bd - ac); R(2, 1) = T(2) * (ab + cd); R(2, 2) = aa - bb - cc + dd; // NOLINT
-}
-
-template <typename T> inline
-void QuaternionToRotation(const T q[4], T R[3 * 3]) {
- QuaternionToRotation(q, RowMajorAdapter3x3(R));
-}
-
-template <typename T, int row_stride, int col_stride> inline
-void QuaternionToRotation(const T q[4],
- const MatrixAdapter<T, row_stride, col_stride>& R) {
- QuaternionToScaledRotation(q, R);
-
- T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
- CHECK_NE(normalizer, T(0));
- normalizer = T(1) / normalizer;
-
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- R(i, j) *= normalizer;
- }
- }
-}
-
-template <typename T> inline
-void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
- const T t2 = q[0] * q[1];
- const T t3 = q[0] * q[2];
- const T t4 = q[0] * q[3];
- const T t5 = -q[1] * q[1];
- const T t6 = q[1] * q[2];
- const T t7 = q[1] * q[3];
- const T t8 = -q[2] * q[2];
- const T t9 = q[2] * q[3];
- const T t1 = -q[3] * q[3];
- result[0] = T(2) * ((t8 + t1) * pt[0] + (t6 - t4) * pt[1] + (t3 + t7) * pt[2]) + pt[0]; // NOLINT
- result[1] = T(2) * ((t4 + t6) * pt[0] + (t5 + t1) * pt[1] + (t9 - t2) * pt[2]) + pt[1]; // NOLINT
- result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2]; // NOLINT
-}
-
-template <typename T> inline
-void QuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
- // 'scale' is 1 / norm(q).
- const T scale = T(1) / sqrt(q[0] * q[0] +
- q[1] * q[1] +
- q[2] * q[2] +
- q[3] * q[3]);
-
- // Make unit-norm version of q.
- const T unit[4] = {
- scale * q[0],
- scale * q[1],
- scale * q[2],
- scale * q[3],
- };
-
- UnitQuaternionRotatePoint(unit, pt, result);
-}
-
-template<typename T> inline
-void QuaternionProduct(const T z[4], const T w[4], T zw[4]) {
- zw[0] = z[0] * w[0] - z[1] * w[1] - z[2] * w[2] - z[3] * w[3];
- zw[1] = z[0] * w[1] + z[1] * w[0] + z[2] * w[3] - z[3] * w[2];
- zw[2] = z[0] * w[2] - z[1] * w[3] + z[2] * w[0] + z[3] * w[1];
- zw[3] = z[0] * w[3] + z[1] * w[2] - z[2] * w[1] + z[3] * w[0];
-}
-
-// xy = x cross y;
-template<typename T> inline
-void CrossProduct(const T x[3], const T y[3], T x_cross_y[3]) {
- x_cross_y[0] = x[1] * y[2] - x[2] * y[1];
- x_cross_y[1] = x[2] * y[0] - x[0] * y[2];
- x_cross_y[2] = x[0] * y[1] - x[1] * y[0];
-}
-
-template<typename T> inline
-T DotProduct(const T x[3], const T y[3]) {
- return (x[0] * y[0] + x[1] * y[1] + x[2] * y[2]);
-}
-
-template<typename T> inline
-void AngleAxisRotatePoint(const T angle_axis[3], const T pt[3], T result[3]) {
- const T theta2 = DotProduct(angle_axis, angle_axis);
- if (theta2 > T(std::numeric_limits<double>::epsilon())) {
- // Away from zero, use the rodriguez formula
- //
- // result = pt costheta +
- // (w x pt) * sintheta +
- // w (w . pt) (1 - costheta)
- //
- // We want to be careful to only evaluate the square root if the
- // norm of the angle_axis vector is greater than zero. Otherwise
- // we get a division by zero.
- //
- const T theta = sqrt(theta2);
- const T costheta = cos(theta);
- const T sintheta = sin(theta);
- const T theta_inverse = 1.0 / theta;
-
- const T w[3] = { angle_axis[0] * theta_inverse,
- angle_axis[1] * theta_inverse,
- angle_axis[2] * theta_inverse };
-
- // Explicitly inlined evaluation of the cross product for
- // performance reasons.
- const T w_cross_pt[3] = { w[1] * pt[2] - w[2] * pt[1],
- w[2] * pt[0] - w[0] * pt[2],
- w[0] * pt[1] - w[1] * pt[0] };
- const T tmp =
- (w[0] * pt[0] + w[1] * pt[1] + w[2] * pt[2]) * (T(1.0) - costheta);
-
- result[0] = pt[0] * costheta + w_cross_pt[0] * sintheta + w[0] * tmp;
- result[1] = pt[1] * costheta + w_cross_pt[1] * sintheta + w[1] * tmp;
- result[2] = pt[2] * costheta + w_cross_pt[2] * sintheta + w[2] * tmp;
- } else {
- // Near zero, the first order Taylor approximation of the rotation
- // matrix R corresponding to a vector w and angle w is
- //
- // R = I + hat(w) * sin(theta)
- //
- // But sintheta ~ theta and theta * w = angle_axis, which gives us
- //
- // R = I + hat(w)
- //
- // and actually performing multiplication with the point pt, gives us
- // R * pt = pt + w x pt.
- //
- // Switching to the Taylor expansion near zero provides meaningful
- // derivatives when evaluated using Jets.
- //
- // Explicitly inlined evaluation of the cross product for
- // performance reasons.
- const T w_cross_pt[3] = { angle_axis[1] * pt[2] - angle_axis[2] * pt[1],
- angle_axis[2] * pt[0] - angle_axis[0] * pt[2],
- angle_axis[0] * pt[1] - angle_axis[1] * pt[0] };
-
- result[0] = pt[0] + w_cross_pt[0];
- result[1] = pt[1] + w_cross_pt[1];
- result[2] = pt[2] + w_cross_pt[2];
- }
-}
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_ROTATION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h b/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
deleted file mode 100644
index 4f98d4eb95c..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A convenience class for cost functions which are statically sized.
-// Compared to the dynamically-sized base class, this reduces boilerplate.
-//
-// The kNumResiduals template parameter can be a constant such as 2 or 5, or it
-// can be ceres::DYNAMIC. If kNumResiduals is ceres::DYNAMIC, then subclasses
-// are responsible for calling set_num_residuals() at runtime.
-
-#ifndef CERES_PUBLIC_SIZED_COST_FUNCTION_H_
-#define CERES_PUBLIC_SIZED_COST_FUNCTION_H_
-
-#include "ceres/types.h"
-#include "ceres/cost_function.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-template<int kNumResiduals,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0,
- int N5 = 0, int N6 = 0, int N7 = 0, int N8 = 0, int N9 = 0>
-class SizedCostFunction : public CostFunction {
- public:
- SizedCostFunction() {
- CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC)
- << "Cost functions must have at least one residual block.";
-
- // This block breaks the 80 column rule to keep it somewhat readable.
- CHECK((!N1 && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5 && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && !N6 && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && !N7 && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && !N8 && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && !N9) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0) && (N6 > 0) && (N7 > 0) && (N8 > 0) && (N9 > 0)))
- << "Zero block cannot precede a non-zero block. Block sizes are "
- << "(ignore trailing 0s): " << N0 << ", " << N1 << ", " << N2 << ", "
- << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
- << N8 << ", " << N9;
-
- set_num_residuals(kNumResiduals);
-
-#define ADD_PARAMETER_BLOCK(N) \
- if (N) mutable_parameter_block_sizes()->push_back(N);
- ADD_PARAMETER_BLOCK(N0);
- ADD_PARAMETER_BLOCK(N1);
- ADD_PARAMETER_BLOCK(N2);
- ADD_PARAMETER_BLOCK(N3);
- ADD_PARAMETER_BLOCK(N4);
- ADD_PARAMETER_BLOCK(N5);
- ADD_PARAMETER_BLOCK(N6);
- ADD_PARAMETER_BLOCK(N7);
- ADD_PARAMETER_BLOCK(N8);
- ADD_PARAMETER_BLOCK(N9);
-#undef ADD_PARAMETER_BLOCK
- }
-
- virtual ~SizedCostFunction() { }
-
- // Subclasses must implement Evaluate().
-};
-
-} // namespace ceres
-
-#endif // CERES_PUBLIC_SIZED_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/solver.h b/extern/libmv/third_party/ceres/include/ceres/solver.h
deleted file mode 100644
index a5efa2a3915..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/solver.h
+++ /dev/null
@@ -1,1004 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_SOLVER_H_
-#define CERES_PUBLIC_SOLVER_H_
-
-#include <cmath>
-#include <string>
-#include <vector>
-#include "ceres/crs_matrix.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/iteration_callback.h"
-#include "ceres/ordered_groups.h"
-#include "ceres/types.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-class Problem;
-
-// Interface for non-linear least squares solvers.
-class CERES_EXPORT Solver {
- public:
- virtual ~Solver();
-
- // The options structure contains, not surprisingly, options that control how
- // the solver operates. The defaults should be suitable for a wide range of
- // problems; however, better performance is often obtainable with tweaking.
- //
- // The constants are defined inside types.h
- struct CERES_EXPORT Options {
- // Default constructor that sets up a generic sparse problem.
- Options() {
- minimizer_type = TRUST_REGION;
- line_search_direction_type = LBFGS;
- line_search_type = WOLFE;
- nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
- max_lbfgs_rank = 20;
- use_approximate_eigenvalue_bfgs_scaling = false;
- line_search_interpolation_type = CUBIC;
- min_line_search_step_size = 1e-9;
- line_search_sufficient_function_decrease = 1e-4;
- max_line_search_step_contraction = 1e-3;
- min_line_search_step_contraction = 0.6;
- max_num_line_search_step_size_iterations = 20;
- max_num_line_search_direction_restarts = 5;
- line_search_sufficient_curvature_decrease = 0.9;
- max_line_search_step_expansion = 10.0;
- trust_region_strategy_type = LEVENBERG_MARQUARDT;
- dogleg_type = TRADITIONAL_DOGLEG;
- use_nonmonotonic_steps = false;
- max_consecutive_nonmonotonic_steps = 5;
- max_num_iterations = 50;
- max_solver_time_in_seconds = 1e9;
- num_threads = 1;
- initial_trust_region_radius = 1e4;
- max_trust_region_radius = 1e16;
- min_trust_region_radius = 1e-32;
- min_relative_decrease = 1e-3;
- min_lm_diagonal = 1e-6;
- max_lm_diagonal = 1e32;
- max_num_consecutive_invalid_steps = 5;
- function_tolerance = 1e-6;
- gradient_tolerance = 1e-10;
- parameter_tolerance = 1e-8;
-
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) && !defined(CERES_ENABLE_LGPL_CODE)
- linear_solver_type = DENSE_QR;
-#else
- linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-#endif
-
- preconditioner_type = JACOBI;
- visibility_clustering_type = CANONICAL_VIEWS;
- dense_linear_algebra_library_type = EIGEN;
-
- // Choose a default sparse linear algebra library in the order:
- //
- // SUITE_SPARSE > CX_SPARSE > EIGEN_SPARSE
-#if !defined(CERES_NO_SUITESPARSE)
- sparse_linear_algebra_library_type = SUITE_SPARSE;
-#else
- #if !defined(CERES_NO_CXSPARSE)
- sparse_linear_algebra_library_type = CX_SPARSE;
- #else
- #if defined(CERES_USE_EIGEN_SPARSE)
- sparse_linear_algebra_library_type = EIGEN_SPARSE;
- #endif
- #endif
-#endif
-
- num_linear_solver_threads = 1;
- use_explicit_schur_complement = false;
- use_postordering = false;
- dynamic_sparsity = false;
- min_linear_solver_iterations = 0;
- max_linear_solver_iterations = 500;
- eta = 1e-1;
- jacobi_scaling = true;
- use_inner_iterations = false;
- inner_iteration_tolerance = 1e-3;
- logging_type = PER_MINIMIZER_ITERATION;
- minimizer_progress_to_stdout = false;
- trust_region_problem_dump_directory = "/tmp";
- trust_region_problem_dump_format_type = TEXTFILE;
- check_gradients = false;
- gradient_check_relative_precision = 1e-8;
- numeric_derivative_relative_step_size = 1e-6;
- update_state_every_iteration = false;
- }
-
- // Returns true if the options struct has a valid
- // configuration. Returns false otherwise, and fills in *error
- // with a message describing the problem.
- bool IsValid(string* error) const;
-
- // Minimizer options ----------------------------------------
-
- // Ceres supports the two major families of optimization strategies -
- // Trust Region and Line Search.
- //
- // 1. The line search approach first finds a descent direction
- // along which the objective function will be reduced and then
- // computes a step size that decides how far should move along
- // that direction. The descent direction can be computed by
- // various methods, such as gradient descent, Newton's method and
- // Quasi-Newton method. The step size can be determined either
- // exactly or inexactly.
- //
- // 2. The trust region approach approximates the objective
- // function using using a model function (often a quadratic) over
- // a subset of the search space known as the trust region. If the
- // model function succeeds in minimizing the true objective
- // function the trust region is expanded; conversely, otherwise it
- // is contracted and the model optimization problem is solved
- // again.
- //
- // Trust region methods are in some sense dual to line search methods:
- // trust region methods first choose a step size (the size of the
- // trust region) and then a step direction while line search methods
- // first choose a step direction and then a step size.
- MinimizerType minimizer_type;
-
- LineSearchDirectionType line_search_direction_type;
- LineSearchType line_search_type;
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
-
- // The LBFGS hessian approximation is a low rank approximation to
- // the inverse of the Hessian matrix. The rank of the
- // approximation determines (linearly) the space and time
- // complexity of using the approximation. Higher the rank, the
- // better is the quality of the approximation. The increase in
- // quality is however is bounded for a number of reasons.
- //
- // 1. The method only uses secant information and not actual
- // derivatives.
- //
- // 2. The Hessian approximation is constrained to be positive
- // definite.
- //
- // So increasing this rank to a large number will cost time and
- // space complexity without the corresponding increase in solution
- // quality. There are no hard and fast rules for choosing the
- // maximum rank. The best choice usually requires some problem
- // specific experimentation.
- //
- // For more theoretical and implementation details of the LBFGS
- // method, please see:
- //
- // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with
- // Limited Storage". Mathematics of Computation 35 (151): 773–782.
- int max_lbfgs_rank;
-
- // As part of the (L)BFGS update step (BFGS) / right-multiply step (L-BFGS),
- // the initial inverse Hessian approximation is taken to be the Identity.
- // However, Oren showed that using instead I * \gamma, where \gamma is
- // chosen to approximate an eigenvalue of the true inverse Hessian can
- // result in improved convergence in a wide variety of cases. Setting
- // use_approximate_eigenvalue_bfgs_scaling to true enables this scaling.
- //
- // It is important to note that approximate eigenvalue scaling does not
- // always improve convergence, and that it can in fact significantly degrade
- // performance for certain classes of problem, which is why it is disabled
- // by default. In particular it can degrade performance when the
- // sensitivity of the problem to different parameters varies significantly,
- // as in this case a single scalar factor fails to capture this variation
- // and detrimentally downscales parts of the jacobian approximation which
- // correspond to low-sensitivity parameters. It can also reduce the
- // robustness of the solution to errors in the jacobians.
- //
- // Oren S.S., Self-scaling variable metric (SSVM) algorithms
- // Part II: Implementation and experiments, Management Science,
- // 20(5), 863-874, 1974.
- bool use_approximate_eigenvalue_bfgs_scaling;
-
- // Degree of the polynomial used to approximate the objective
- // function. Valid values are BISECTION, QUADRATIC and CUBIC.
- //
- // BISECTION corresponds to pure backtracking search with no
- // interpolation.
- LineSearchInterpolationType line_search_interpolation_type;
-
- // If during the line search, the step_size falls below this
- // value, it is truncated to zero.
- double min_line_search_step_size;
-
- // Line search parameters.
-
- // Solving the line search problem exactly is computationally
- // prohibitive. Fortunately, line search based optimization
- // algorithms can still guarantee convergence if instead of an
- // exact solution, the line search algorithm returns a solution
- // which decreases the value of the objective function
- // sufficiently. More precisely, we are looking for a step_size
- // s.t.
- //
- // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
- //
- double line_search_sufficient_function_decrease;
-
- // In each iteration of the line search,
- //
- // new_step_size >= max_line_search_step_contraction * step_size
- //
- // Note that by definition, for contraction:
- //
- // 0 < max_step_contraction < min_step_contraction < 1
- //
- double max_line_search_step_contraction;
-
- // In each iteration of the line search,
- //
- // new_step_size <= min_line_search_step_contraction * step_size
- //
- // Note that by definition, for contraction:
- //
- // 0 < max_step_contraction < min_step_contraction < 1
- //
- double min_line_search_step_contraction;
-
- // Maximum number of trial step size iterations during each line search,
- // if a step size satisfying the search conditions cannot be found within
- // this number of trials, the line search will terminate.
- int max_num_line_search_step_size_iterations;
-
- // Maximum number of restarts of the line search direction algorithm before
- // terminating the optimization. Restarts of the line search direction
- // algorithm occur when the current algorithm fails to produce a new descent
- // direction. This typically indicates a numerical failure, or a breakdown
- // in the validity of the approximations used.
- int max_num_line_search_direction_restarts;
-
- // The strong Wolfe conditions consist of the Armijo sufficient
- // decrease condition, and an additional requirement that the
- // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
- // conditions) of the gradient along the search direction
- // decreases sufficiently. Precisely, this second condition
- // is that we seek a step_size s.t.
- //
- // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
- //
- // Where f() is the line search objective and f'() is the derivative
- // of f w.r.t step_size (d f / d step_size).
- double line_search_sufficient_curvature_decrease;
-
- // During the bracketing phase of the Wolfe search, the step size is
- // increased until either a point satisfying the Wolfe conditions is
- // found, or an upper bound for a bracket containing a point satisfying
- // the conditions is found. Precisely, at each iteration of the
- // expansion:
- //
- // new_step_size <= max_step_expansion * step_size.
- //
- // By definition for expansion, max_step_expansion > 1.0.
- double max_line_search_step_expansion;
-
- TrustRegionStrategyType trust_region_strategy_type;
-
- // Type of dogleg strategy to use.
- DoglegType dogleg_type;
-
- // The classical trust region methods are descent methods, in that
- // they only accept a point if it strictly reduces the value of
- // the objective function.
- //
- // Relaxing this requirement allows the algorithm to be more
- // efficient in the long term at the cost of some local increase
- // in the value of the objective function.
- //
- // This is because allowing for non-decreasing objective function
- // values in a princpled manner allows the algorithm to "jump over
- // boulders" as the method is not restricted to move into narrow
- // valleys while preserving its convergence properties.
- //
- // Setting use_nonmonotonic_steps to true enables the
- // non-monotonic trust region algorithm as described by Conn,
- // Gould & Toint in "Trust Region Methods", Section 10.1.
- //
- // The parameter max_consecutive_nonmonotonic_steps controls the
- // window size used by the step selection algorithm to accept
- // non-monotonic steps.
- //
- // Even though the value of the objective function may be larger
- // than the minimum value encountered over the course of the
- // optimization, the final parameters returned to the user are the
- // ones corresponding to the minimum cost over all iterations.
- bool use_nonmonotonic_steps;
- int max_consecutive_nonmonotonic_steps;
-
- // Maximum number of iterations for the minimizer to run for.
- int max_num_iterations;
-
- // Maximum time for which the minimizer should run for.
- double max_solver_time_in_seconds;
-
- // Number of threads used by Ceres for evaluating the cost and
- // jacobians.
- int num_threads;
-
- // Trust region minimizer settings.
- double initial_trust_region_radius;
- double max_trust_region_radius;
-
- // Minimizer terminates when the trust region radius becomes
- // smaller than this value.
- double min_trust_region_radius;
-
- // Lower bound for the relative decrease before a step is
- // accepted.
- double min_relative_decrease;
-
- // For the Levenberg-Marquadt algorithm, the scaled diagonal of
- // the normal equations J'J is used to control the size of the
- // trust region. Extremely small and large values along the
- // diagonal can make this regularization scheme
- // fail. max_lm_diagonal and min_lm_diagonal, clamp the values of
- // diag(J'J) from above and below. In the normal course of
- // operation, the user should not have to modify these parameters.
- double min_lm_diagonal;
- double max_lm_diagonal;
-
- // Sometimes due to numerical conditioning problems or linear
- // solver flakiness, the trust region strategy may return a
- // numerically invalid step that can be fixed by reducing the
- // trust region size. So the TrustRegionMinimizer allows for a few
- // successive invalid steps before it declares NUMERICAL_FAILURE.
- int max_num_consecutive_invalid_steps;
-
- // Minimizer terminates when
- //
- // (new_cost - old_cost) < function_tolerance * old_cost;
- //
- double function_tolerance;
-
- // Minimizer terminates when
- //
- // max_i |x - Project(Plus(x, -g(x))| < gradient_tolerance
- //
- // This value should typically be 1e-4 * function_tolerance.
- double gradient_tolerance;
-
- // Minimizer terminates when
- //
- // |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
- //
- double parameter_tolerance;
-
- // Linear least squares solver options -------------------------------------
-
- LinearSolverType linear_solver_type;
-
- // Type of preconditioner to use with the iterative linear solvers.
- PreconditionerType preconditioner_type;
-
- // Type of clustering algorithm to use for visibility based
- // preconditioning. This option is used only when the
- // preconditioner_type is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
- VisibilityClusteringType visibility_clustering_type;
-
- // Ceres supports using multiple dense linear algebra libraries
- // for dense matrix factorizations. Currently EIGEN and LAPACK are
- // the valid choices. EIGEN is always available, LAPACK refers to
- // the system BLAS + LAPACK library which may or may not be
- // available.
- //
- // This setting affects the DENSE_QR, DENSE_NORMAL_CHOLESKY and
- // DENSE_SCHUR solvers. For small to moderate sized probem EIGEN
- // is a fine choice but for large problems, an optimized LAPACK +
- // BLAS implementation can make a substantial difference in
- // performance.
- DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
-
- // Ceres supports using multiple sparse linear algebra libraries
- // for sparse matrix ordering and factorizations. Currently,
- // SUITE_SPARSE and CX_SPARSE are the valid choices, depending on
- // whether they are linked into Ceres at build time.
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
-
- // Number of threads used by Ceres to solve the Newton
- // step. Currently only the SPARSE_SCHUR solver is capable of
- // using this setting.
- int num_linear_solver_threads;
-
- // The order in which variables are eliminated in a linear solver
- // can have a significant of impact on the efficiency and accuracy
- // of the method. e.g., when doing sparse Cholesky factorization,
- // there are matrices for which a good ordering will give a
- // Cholesky factor with O(n) storage, where as a bad ordering will
- // result in an completely dense factor.
- //
- // Ceres allows the user to provide varying amounts of hints to
- // the solver about the variable elimination ordering to use. This
- // can range from no hints, where the solver is free to decide the
- // best possible ordering based on the user's choices like the
- // linear solver being used, to an exact order in which the
- // variables should be eliminated, and a variety of possibilities
- // in between.
- //
- // Instances of the ParameterBlockOrdering class are used to
- // communicate this information to Ceres.
- //
- // Formally an ordering is an ordered partitioning of the
- // parameter blocks, i.e, each parameter block belongs to exactly
- // one group, and each group has a unique non-negative integer
- // associated with it, that determines its order in the set of
- // groups.
- //
- // Given such an ordering, Ceres ensures that the parameter blocks in
- // the lowest numbered group are eliminated first, and then the
- // parmeter blocks in the next lowest numbered group and so on. Within
- // each group, Ceres is free to order the parameter blocks as it
- // chooses.
- //
- // If NULL, then all parameter blocks are assumed to be in the
- // same group and the solver is free to decide the best
- // ordering.
- //
- // e.g. Consider the linear system
- //
- // x + y = 3
- // 2x + 3y = 7
- //
- // There are two ways in which it can be solved. First eliminating x
- // from the two equations, solving for y and then back substituting
- // for x, or first eliminating y, solving for x and back substituting
- // for y. The user can construct three orderings here.
- //
- // {0: x}, {1: y} - eliminate x first.
- // {0: y}, {1: x} - eliminate y first.
- // {0: x, y} - Solver gets to decide the elimination order.
- //
- // Thus, to have Ceres determine the ordering automatically using
- // heuristics, put all the variables in group 0 and to control the
- // ordering for every variable, create groups 0..N-1, one per
- // variable, in the desired order.
- //
- // Bundle Adjustment
- // -----------------
- //
- // A particular case of interest is bundle adjustment, where the user
- // has two options. The default is to not specify an ordering at all,
- // the solver will see that the user wants to use a Schur type solver
- // and figure out the right elimination ordering.
- //
- // But if the user already knows what parameter blocks are points and
- // what are cameras, they can save preprocessing time by partitioning
- // the parameter blocks into two groups, one for the points and one
- // for the cameras, where the group containing the points has an id
- // smaller than the group containing cameras.
- shared_ptr<ParameterBlockOrdering> linear_solver_ordering;
-
- // Use an explicitly computed Schur complement matrix with
- // ITERATIVE_SCHUR.
- //
- // By default this option is disabled and ITERATIVE_SCHUR
- // evaluates evaluates matrix-vector products between the Schur
- // complement and a vector implicitly by exploiting the algebraic
- // expression for the Schur complement.
- //
- // The cost of this evaluation scales with the number of non-zeros
- // in the Jacobian.
- //
- // For small to medium sized problems there is a sweet spot where
- // computing the Schur complement is cheap enough that it is much
- // more efficient to explicitly compute it and use it for evaluating
- // the matrix-vector products.
- //
- // Enabling this option tells ITERATIVE_SCHUR to use an explicitly
- // computed Schur complement.
- //
- // NOTE: This option can only be used with the SCHUR_JACOBI
- // preconditioner.
- bool use_explicit_schur_complement;
-
- // Sparse Cholesky factorization algorithms use a fill-reducing
- // ordering to permute the columns of the Jacobian matrix. There
- // are two ways of doing this.
-
- // 1. Compute the Jacobian matrix in some order and then have the
- // factorization algorithm permute the columns of the Jacobian.
-
- // 2. Compute the Jacobian with its columns already permuted.
-
- // The first option incurs a significant memory penalty. The
- // factorization algorithm has to make a copy of the permuted
- // Jacobian matrix, thus Ceres pre-permutes the columns of the
- // Jacobian matrix and generally speaking, there is no performance
- // penalty for doing so.
-
- // In some rare cases, it is worth using a more complicated
- // reordering algorithm which has slightly better runtime
- // performance at the expense of an extra copy of the Jacobian
- // matrix. Setting use_postordering to true enables this tradeoff.
- bool use_postordering;
-
- // Some non-linear least squares problems are symbolically dense but
- // numerically sparse. i.e. at any given state only a small number
- // of jacobian entries are non-zero, but the position and number of
- // non-zeros is different depending on the state. For these problems
- // it can be useful to factorize the sparse jacobian at each solver
- // iteration instead of including all of the zero entries in a single
- // general factorization.
- //
- // If your problem does not have this property (or you do not know),
- // then it is probably best to keep this false, otherwise it will
- // likely lead to worse performance.
-
- // This settings affects the SPARSE_NORMAL_CHOLESKY solver.
- bool dynamic_sparsity;
-
- // Some non-linear least squares problems have additional
- // structure in the way the parameter blocks interact that it is
- // beneficial to modify the way the trust region step is computed.
- //
- // e.g., consider the following regression problem
- //
- // y = a_1 exp(b_1 x) + a_2 exp(b_3 x^2 + c_1)
- //
- // Given a set of pairs{(x_i, y_i)}, the user wishes to estimate
- // a_1, a_2, b_1, b_2, and c_1.
- //
- // Notice here that the expression on the left is linear in a_1
- // and a_2, and given any value for b_1, b_2 and c_1, it is
- // possible to use linear regression to estimate the optimal
- // values of a_1 and a_2. Indeed, its possible to analytically
- // eliminate the variables a_1 and a_2 from the problem all
- // together. Problems like these are known as separable least
- // squares problem and the most famous algorithm for solving them
- // is the Variable Projection algorithm invented by Golub &
- // Pereyra.
- //
- // Similar structure can be found in the matrix factorization with
- // missing data problem. There the corresponding algorithm is
- // known as Wiberg's algorithm.
- //
- // Ruhe & Wedin (Algorithms for Separable Nonlinear Least Squares
- // Problems, SIAM Reviews, 22(3), 1980) present an analyis of
- // various algorithms for solving separable non-linear least
- // squares problems and refer to "Variable Projection" as
- // Algorithm I in their paper.
- //
- // Implementing Variable Projection is tedious and expensive, and
- // they present a simpler algorithm, which they refer to as
- // Algorithm II, where once the Newton/Trust Region step has been
- // computed for the whole problem (a_1, a_2, b_1, b_2, c_1) and
- // additional optimization step is performed to estimate a_1 and
- // a_2 exactly.
- //
- // This idea can be generalized to cases where the residual is not
- // linear in a_1 and a_2, i.e., Solve for the trust region step
- // for the full problem, and then use it as the starting point to
- // further optimize just a_1 and a_2. For the linear case, this
- // amounts to doing a single linear least squares solve. For
- // non-linear problems, any method for solving the a_1 and a_2
- // optimization problems will do. The only constraint on a_1 and
- // a_2 is that they do not co-occur in any residual block.
- //
- // This idea can be further generalized, by not just optimizing
- // (a_1, a_2), but decomposing the graph corresponding to the
- // Hessian matrix's sparsity structure in a collection of
- // non-overlapping independent sets and optimizing each of them.
- //
- // Setting "use_inner_iterations" to true enables the use of this
- // non-linear generalization of Ruhe & Wedin's Algorithm II. This
- // version of Ceres has a higher iteration complexity, but also
- // displays better convergence behaviour per iteration. Setting
- // Solver::Options::num_threads to the maximum number possible is
- // highly recommended.
- bool use_inner_iterations;
-
- // If inner_iterations is true, then the user has two choices.
- //
- // 1. Let the solver heuristically decide which parameter blocks
- // to optimize in each inner iteration. To do this leave
- // Solver::Options::inner_iteration_ordering untouched.
- //
- // 2. Specify a collection of of ordered independent sets. Where
- // the lower numbered groups are optimized before the higher
- // number groups. Each group must be an independent set. Not
- // all parameter blocks need to be present in the ordering.
- shared_ptr<ParameterBlockOrdering> inner_iteration_ordering;
-
- // Generally speaking, inner iterations make significant progress
- // in the early stages of the solve and then their contribution
- // drops down sharply, at which point the time spent doing inner
- // iterations is not worth it.
- //
- // Once the relative decrease in the objective function due to
- // inner iterations drops below inner_iteration_tolerance, the use
- // of inner iterations in subsequent trust region minimizer
- // iterations is disabled.
- double inner_iteration_tolerance;
-
- // Minimum number of iterations for which the linear solver should
- // run, even if the convergence criterion is satisfied.
- int min_linear_solver_iterations;
-
- // Maximum number of iterations for which the linear solver should
- // run. If the solver does not converge in less than
- // max_linear_solver_iterations, then it returns MAX_ITERATIONS,
- // as its termination type.
- int max_linear_solver_iterations;
-
- // Forcing sequence parameter. The truncated Newton solver uses
- // this number to control the relative accuracy with which the
- // Newton step is computed.
- //
- // This constant is passed to ConjugateGradientsSolver which uses
- // it to terminate the iterations when
- //
- // (Q_i - Q_{i-1})/Q_i < eta/i
- double eta;
-
- // Normalize the jacobian using Jacobi scaling before calling
- // the linear least squares solver.
- bool jacobi_scaling;
-
- // Logging options ---------------------------------------------------------
-
- LoggingType logging_type;
-
- // By default the Minimizer progress is logged to VLOG(1), which
- // is sent to STDERR depending on the vlog level. If this flag is
- // set to true, and logging_type is not SILENT, the logging output
- // is sent to STDOUT.
- bool minimizer_progress_to_stdout;
-
- // List of iterations at which the minimizer should dump the trust
- // region problem. Useful for testing and benchmarking. If empty
- // (default), no problems are dumped.
- vector<int> trust_region_minimizer_iterations_to_dump;
-
- // Directory to which the problems should be written to. Should be
- // non-empty if trust_region_minimizer_iterations_to_dump is
- // non-empty and trust_region_problem_dump_format_type is not
- // CONSOLE.
- string trust_region_problem_dump_directory;
- DumpFormatType trust_region_problem_dump_format_type;
-
- // Finite differences options ----------------------------------------------
-
- // Check all jacobians computed by each residual block with finite
- // differences. This is expensive since it involves computing the
- // derivative by normal means (e.g. user specified, autodiff,
- // etc), then also computing it using finite differences. The
- // results are compared, and if they differ substantially, details
- // are printed to the log.
- bool check_gradients;
-
- // Relative precision to check for in the gradient checker. If the
- // relative difference between an element in a jacobian exceeds
- // this number, then the jacobian for that cost term is dumped.
- double gradient_check_relative_precision;
-
- // Relative shift used for taking numeric derivatives. For finite
- // differencing, each dimension is evaluated at slightly shifted
- // values; for the case of central difference, this is what gets
- // evaluated:
- //
- // delta = numeric_derivative_relative_step_size;
- // f_initial = f(x)
- // f_forward = f((1 + delta) * x)
- // f_backward = f((1 - delta) * x)
- //
- // The finite differencing is done along each dimension. The
- // reason to use a relative (rather than absolute) step size is
- // that this way, numeric differentation works for functions where
- // the arguments are typically large (e.g. 1e9) and when the
- // values are small (e.g. 1e-5). It is possible to construct
- // "torture cases" which break this finite difference heuristic,
- // but they do not come up often in practice.
- //
- // TODO(keir): Pick a smarter number than the default above! In
- // theory a good choice is sqrt(eps) * x, which for doubles means
- // about 1e-8 * x. However, I have found this number too
- // optimistic. This number should be exposed for users to change.
- double numeric_derivative_relative_step_size;
-
- // If true, the user's parameter blocks are updated at the end of
- // every Minimizer iteration, otherwise they are updated when the
- // Minimizer terminates. This is useful if, for example, the user
- // wishes to visualize the state of the optimization every
- // iteration.
- bool update_state_every_iteration;
-
- // Callbacks that are executed at the end of each iteration of the
- // Minimizer. An iteration may terminate midway, either due to
- // numerical failures or because one of the convergence tests has
- // been satisfied. In this case none of the callbacks are
- // executed.
-
- // Callbacks are executed in the order that they are specified in
- // this vector. By default, parameter blocks are updated only at
- // the end of the optimization, i.e when the Minimizer
- // terminates. This behaviour is controlled by
- // update_state_every_variable. If the user wishes to have access
- // to the update parameter blocks when his/her callbacks are
- // executed, then set update_state_every_iteration to true.
- //
- // The solver does NOT take ownership of these pointers.
- vector<IterationCallback*> callbacks;
- };
-
- struct CERES_EXPORT Summary {
- Summary();
-
- // A brief one line description of the state of the solver after
- // termination.
- string BriefReport() const;
-
- // A full multiline description of the state of the solver after
- // termination.
- string FullReport() const;
-
- bool IsSolutionUsable() const;
-
- // Minimizer summary -------------------------------------------------
- MinimizerType minimizer_type;
-
- TerminationType termination_type;
-
- // Reason why the solver terminated.
- string message;
-
- // Cost of the problem (value of the objective function) before
- // the optimization.
- double initial_cost;
-
- // Cost of the problem (value of the objective function) after the
- // optimization.
- double final_cost;
-
- // The part of the total cost that comes from residual blocks that
- // were held fixed by the preprocessor because all the parameter
- // blocks that they depend on were fixed.
- double fixed_cost;
-
- // IterationSummary for each minimizer iteration in order.
- vector<IterationSummary> iterations;
-
- // Number of minimizer iterations in which the step was
- // accepted. Unless use_non_monotonic_steps is true this is also
- // the number of steps in which the objective function value/cost
- // went down.
- int num_successful_steps;
-
- // Number of minimizer iterations in which the step was rejected
- // either because it did not reduce the cost enough or the step
- // was not numerically valid.
- int num_unsuccessful_steps;
-
- // Number of times inner iterations were performed.
- int num_inner_iteration_steps;
-
- // All times reported below are wall times.
-
- // When the user calls Solve, before the actual optimization
- // occurs, Ceres performs a number of preprocessing steps. These
- // include error checks, memory allocations, and reorderings. This
- // time is accounted for as preprocessing time.
- double preprocessor_time_in_seconds;
-
- // Time spent in the TrustRegionMinimizer.
- double minimizer_time_in_seconds;
-
- // After the Minimizer is finished, some time is spent in
- // re-evaluating residuals etc. This time is accounted for in the
- // postprocessor time.
- double postprocessor_time_in_seconds;
-
- // Some total of all time spent inside Ceres when Solve is called.
- double total_time_in_seconds;
-
- // Time (in seconds) spent in the linear solver computing the
- // trust region step.
- double linear_solver_time_in_seconds;
-
- // Time (in seconds) spent evaluating the residual vector.
- double residual_evaluation_time_in_seconds;
-
- // Time (in seconds) spent evaluating the jacobian matrix.
- double jacobian_evaluation_time_in_seconds;
-
- // Time (in seconds) spent doing inner iterations.
- double inner_iteration_time_in_seconds;
-
- // Number of parameter blocks in the problem.
- int num_parameter_blocks;
-
- // Number of parameters in the probem.
- int num_parameters;
-
- // Dimension of the tangent space of the problem (or the number of
- // columns in the Jacobian for the problem). This is different
- // from num_parameters if a parameter block is associated with a
- // LocalParameterization
- int num_effective_parameters;
-
- // Number of residual blocks in the problem.
- int num_residual_blocks;
-
- // Number of residuals in the problem.
- int num_residuals;
-
- // Number of parameter blocks in the problem after the inactive
- // and constant parameter blocks have been removed. A parameter
- // block is inactive if no residual block refers to it.
- int num_parameter_blocks_reduced;
-
- // Number of parameters in the reduced problem.
- int num_parameters_reduced;
-
- // Dimension of the tangent space of the reduced problem (or the
- // number of columns in the Jacobian for the reduced
- // problem). This is different from num_parameters_reduced if a
- // parameter block in the reduced problem is associated with a
- // LocalParameterization.
- int num_effective_parameters_reduced;
-
- // Number of residual blocks in the reduced problem.
- int num_residual_blocks_reduced;
-
- // Number of residuals in the reduced problem.
- int num_residuals_reduced;
-
- // Number of threads specified by the user for Jacobian and
- // residual evaluation.
- int num_threads_given;
-
- // Number of threads actually used by the solver for Jacobian and
- // residual evaluation. This number is not equal to
- // num_threads_given if OpenMP is not available.
- int num_threads_used;
-
- // Number of threads specified by the user for solving the trust
- // region problem.
- int num_linear_solver_threads_given;
-
- // Number of threads actually used by the solver for solving the
- // trust region problem. This number is not equal to
- // num_threads_given if OpenMP is not available.
- int num_linear_solver_threads_used;
-
- // Type of the linear solver requested by the user.
- LinearSolverType linear_solver_type_given;
-
- // Type of the linear solver actually used. This may be different
- // from linear_solver_type_given if Ceres determines that the
- // problem structure is not compatible with the linear solver
- // requested or if the linear solver requested by the user is not
- // available, e.g. The user requested SPARSE_NORMAL_CHOLESKY but
- // no sparse linear algebra library was available.
- LinearSolverType linear_solver_type_used;
-
- // Size of the elimination groups given by the user as hints to
- // the linear solver.
- vector<int> linear_solver_ordering_given;
-
- // Size of the parameter groups used by the solver when ordering
- // the columns of the Jacobian. This maybe different from
- // linear_solver_ordering_given if the user left
- // linear_solver_ordering_given blank and asked for an automatic
- // ordering, or if the problem contains some constant or inactive
- // parameter blocks.
- vector<int> linear_solver_ordering_used;
-
- // True if the user asked for inner iterations to be used as part
- // of the optimization.
- bool inner_iterations_given;
-
- // True if the user asked for inner iterations to be used as part
- // of the optimization and the problem structure was such that
- // they were actually performed. e.g., in a problem with just one
- // parameter block, inner iterations are not performed.
- bool inner_iterations_used;
-
- // Size of the parameter groups given by the user for performing
- // inner iterations.
- vector<int> inner_iteration_ordering_given;
-
- // Size of the parameter groups given used by the solver for
- // performing inner iterations. This maybe different from
- // inner_iteration_ordering_given if the user left
- // inner_iteration_ordering_given blank and asked for an automatic
- // ordering, or if the problem contains some constant or inactive
- // parameter blocks.
- vector<int> inner_iteration_ordering_used;
-
- // Type of the preconditioner requested by the user.
- PreconditionerType preconditioner_type_given;
-
- // Type of the preconditioner actually used. This may be different
- // from linear_solver_type_given if Ceres determines that the
- // problem structure is not compatible with the linear solver
- // requested or if the linear solver requested by the user is not
- // available.
- PreconditionerType preconditioner_type_used;
-
- // Type of clustering algorithm used for visibility based
- // preconditioning. Only meaningful when the preconditioner_type
- // is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
- VisibilityClusteringType visibility_clustering_type;
-
- // Type of trust region strategy.
- TrustRegionStrategyType trust_region_strategy_type;
-
- // Type of dogleg strategy used for solving the trust region
- // problem.
- DoglegType dogleg_type;
-
- // Type of the dense linear algebra library used.
- DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
-
- // Type of the sparse linear algebra library used.
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
-
- // Type of line search direction used.
- LineSearchDirectionType line_search_direction_type;
-
- // Type of the line search algorithm used.
- LineSearchType line_search_type;
-
- // When performing line search, the degree of the polynomial used
- // to approximate the objective function.
- LineSearchInterpolationType line_search_interpolation_type;
-
- // If the line search direction is NONLINEAR_CONJUGATE_GRADIENT,
- // then this indicates the particular variant of non-linear
- // conjugate gradient used.
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
-
- // If the type of the line search direction is LBFGS, then this
- // indicates the rank of the Hessian approximation.
- int max_lbfgs_rank;
- };
-
- // Once a least squares problem has been built, this function takes
- // the problem and optimizes it based on the values of the options
- // parameters. Upon return, a detailed summary of the work performed
- // by the preprocessor, the non-linear minmizer and the linear
- // solver are reported in the summary object.
- virtual void Solve(const Options& options,
- Problem* problem,
- Solver::Summary* summary);
-};
-
-// Helper function which avoids going through the interface.
-CERES_EXPORT void Solve(const Solver::Options& options,
- Problem* problem,
- Solver::Summary* summary);
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/types.h b/extern/libmv/third_party/ceres/include/ceres/types.h
deleted file mode 100644
index a07c8933e64..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/types.h
+++ /dev/null
@@ -1,487 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Enums and other top level class definitions.
-//
-// Note: internal/types.cc defines stringification routines for some
-// of these enums. Please update those routines if you extend or
-// remove enums from here.
-
-#ifndef CERES_PUBLIC_TYPES_H_
-#define CERES_PUBLIC_TYPES_H_
-
-#include <string>
-
-#include "ceres/internal/port.h"
-#include "ceres/internal/disable_warnings.h"
-
-namespace ceres {
-
-// Basic integer types. These typedefs are in the Ceres namespace to avoid
-// conflicts with other packages having similar typedefs.
-typedef int int32;
-
-// Argument type used in interfaces that can optionally take ownership
-// of a passed in argument. If TAKE_OWNERSHIP is passed, the called
-// object takes ownership of the pointer argument, and will call
-// delete on it upon completion.
-enum Ownership {
- DO_NOT_TAKE_OWNERSHIP,
- TAKE_OWNERSHIP
-};
-
-// TODO(keir): Considerably expand the explanations of each solver type.
-enum LinearSolverType {
- // These solvers are for general rectangular systems formed from the
- // normal equations A'A x = A'b. They are direct solvers and do not
- // assume any special problem structure.
-
- // Solve the normal equations using a dense Cholesky solver; based
- // on Eigen.
- DENSE_NORMAL_CHOLESKY,
-
- // Solve the normal equations using a dense QR solver; based on
- // Eigen.
- DENSE_QR,
-
- // Solve the normal equations using a sparse cholesky solver; requires
- // SuiteSparse or CXSparse.
- SPARSE_NORMAL_CHOLESKY,
-
- // Specialized solvers, specific to problems with a generalized
- // bi-partitite structure.
-
- // Solves the reduced linear system using a dense Cholesky solver;
- // based on Eigen.
- DENSE_SCHUR,
-
- // Solves the reduced linear system using a sparse Cholesky solver;
- // based on CHOLMOD.
- SPARSE_SCHUR,
-
- // Solves the reduced linear system using Conjugate Gradients, based
- // on a new Ceres implementation. Suitable for large scale
- // problems.
- ITERATIVE_SCHUR,
-
- // Conjugate gradients on the normal equations.
- CGNR
-};
-
-enum PreconditionerType {
- // Trivial preconditioner - the identity matrix.
- IDENTITY,
-
- // Block diagonal of the Gauss-Newton Hessian.
- JACOBI,
-
- // Note: The following three preconditioners can only be used with
- // the ITERATIVE_SCHUR solver. They are well suited for Structure
- // from Motion problems.
-
- // Block diagonal of the Schur complement. This preconditioner may
- // only be used with the ITERATIVE_SCHUR solver.
- SCHUR_JACOBI,
-
- // Visibility clustering based preconditioners.
- //
- // The following two preconditioners use the visibility structure of
- // the scene to determine the sparsity structure of the
- // preconditioner. This is done using a clustering algorithm. The
- // available visibility clustering algorithms are described below.
- //
- // Note: Requires SuiteSparse.
- CLUSTER_JACOBI,
- CLUSTER_TRIDIAGONAL
-};
-
-enum VisibilityClusteringType {
- // Canonical views algorithm as described in
- //
- // "Scene Summarization for Online Image Collections", Ian Simon, Noah
- // Snavely, Steven M. Seitz, ICCV 2007.
- //
- // This clustering algorithm can be quite slow, but gives high
- // quality clusters. The original visibility based clustering paper
- // used this algorithm.
- CANONICAL_VIEWS,
-
- // The classic single linkage algorithm. It is extremely fast as
- // compared to CANONICAL_VIEWS, but can give slightly poorer
- // results. For problems with large number of cameras though, this
- // is generally a pretty good option.
- //
- // If you are using SCHUR_JACOBI preconditioner and have SuiteSparse
- // available, CLUSTER_JACOBI and CLUSTER_TRIDIAGONAL in combination
- // with the SINGLE_LINKAGE algorithm will generally give better
- // results.
- SINGLE_LINKAGE
-};
-
-enum SparseLinearAlgebraLibraryType {
- // High performance sparse Cholesky factorization and approximate
- // minimum degree ordering.
- SUITE_SPARSE,
-
- // A lightweight replacment for SuiteSparse, which does not require
- // a LAPACK/BLAS implementation. Consequently, its performance is
- // also a bit lower than SuiteSparse.
- CX_SPARSE,
-
- // Eigen's sparse linear algebra routines. In particular Ceres uses
- // the Simplicial LDLT routines.
- EIGEN_SPARSE
-};
-
-enum DenseLinearAlgebraLibraryType {
- EIGEN,
- LAPACK
-};
-
-// Logging options
-// The options get progressively noisier.
-enum LoggingType {
- SILENT,
- PER_MINIMIZER_ITERATION
-};
-
-enum MinimizerType {
- LINE_SEARCH,
- TRUST_REGION
-};
-
-enum LineSearchDirectionType {
- // Negative of the gradient.
- STEEPEST_DESCENT,
-
- // A generalization of the Conjugate Gradient method to non-linear
- // functions. The generalization can be performed in a number of
- // different ways, resulting in a variety of search directions. The
- // precise choice of the non-linear conjugate gradient algorithm
- // used is determined by NonlinerConjuateGradientType.
- NONLINEAR_CONJUGATE_GRADIENT,
-
- // BFGS, and it's limited memory approximation L-BFGS, are quasi-Newton
- // algorithms that approximate the Hessian matrix by iteratively refining
- // an initial estimate with rank-one updates using the gradient at each
- // iteration. They are a generalisation of the Secant method and satisfy
- // the Secant equation. The Secant equation has an infinium of solutions
- // in multiple dimensions, as there are N*(N+1)/2 degrees of freedom in a
- // symmetric matrix but only N conditions are specified by the Secant
- // equation. The requirement that the Hessian approximation be positive
- // definite imposes another N additional constraints, but that still leaves
- // remaining degrees-of-freedom. (L)BFGS methods uniquely deteremine the
- // approximate Hessian by imposing the additional constraints that the
- // approximation at the next iteration must be the 'closest' to the current
- // approximation (the nature of how this proximity is measured is actually
- // the defining difference between a family of quasi-Newton methods including
- // (L)BFGS & DFP). (L)BFGS is currently regarded as being the best known
- // general quasi-Newton method.
- //
- // The principal difference between BFGS and L-BFGS is that whilst BFGS
- // maintains a full, dense approximation to the (inverse) Hessian, L-BFGS
- // maintains only a window of the last M observations of the parameters and
- // gradients. Using this observation history, the calculation of the next
- // search direction can be computed without requiring the construction of the
- // full dense inverse Hessian approximation. This is particularly important
- // for problems with a large number of parameters, where storage of an N-by-N
- // matrix in memory would be prohibitive.
- //
- // For more details on BFGS see:
- //
- // Broyden, C.G., "The Convergence of a Class of Double-rank Minimization
- // Algorithms,"; J. Inst. Maths. Applics., Vol. 6, pp 76–90, 1970.
- //
- // Fletcher, R., "A New Approach to Variable Metric Algorithms,"
- // Computer Journal, Vol. 13, pp 317–322, 1970.
- //
- // Goldfarb, D., "A Family of Variable Metric Updates Derived by Variational
- // Means," Mathematics of Computing, Vol. 24, pp 23–26, 1970.
- //
- // Shanno, D.F., "Conditioning of Quasi-Newton Methods for Function
- // Minimization," Mathematics of Computing, Vol. 24, pp 647–656, 1970.
- //
- // For more details on L-BFGS see:
- //
- // Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
- // Storage". Mathematics of Computation 35 (151): 773–782.
- //
- // Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
- // "Representations of Quasi-Newton Matrices and their use in
- // Limited Memory Methods". Mathematical Programming 63 (4):
- // 129–156.
- //
- // A general reference for both methods:
- //
- // Nocedal J., Wright S., Numerical Optimization, 2nd Ed. Springer, 1999.
- LBFGS,
- BFGS,
-};
-
-// Nonliner conjugate gradient methods are a generalization of the
-// method of Conjugate Gradients for linear systems. The
-// generalization can be carried out in a number of different ways
-// leading to number of different rules for computing the search
-// direction. Ceres provides a number of different variants. For more
-// details see Numerical Optimization by Nocedal & Wright.
-enum NonlinearConjugateGradientType {
- FLETCHER_REEVES,
- POLAK_RIBIERE,
- HESTENES_STIEFEL,
-};
-
-enum LineSearchType {
- // Backtracking line search with polynomial interpolation or
- // bisection.
- ARMIJO,
- WOLFE,
-};
-
-// Ceres supports different strategies for computing the trust region
-// step.
-enum TrustRegionStrategyType {
- // The default trust region strategy is to use the step computation
- // used in the Levenberg-Marquardt algorithm. For more details see
- // levenberg_marquardt_strategy.h
- LEVENBERG_MARQUARDT,
-
- // Powell's dogleg algorithm interpolates between the Cauchy point
- // and the Gauss-Newton step. It is particularly useful if the
- // LEVENBERG_MARQUARDT algorithm is making a large number of
- // unsuccessful steps. For more details see dogleg_strategy.h.
- //
- // NOTES:
- //
- // 1. This strategy has not been experimented with or tested as
- // extensively as LEVENBERG_MARQUARDT, and therefore it should be
- // considered EXPERIMENTAL for now.
- //
- // 2. For now this strategy should only be used with exact
- // factorization based linear solvers, i.e., SPARSE_SCHUR,
- // DENSE_SCHUR, DENSE_QR and SPARSE_NORMAL_CHOLESKY.
- DOGLEG
-};
-
-// Ceres supports two different dogleg strategies.
-// The "traditional" dogleg method by Powell and the
-// "subspace" method described in
-// R. H. Byrd, R. B. Schnabel, and G. A. Shultz,
-// "Approximate solution of the trust region problem by minimization
-// over two-dimensional subspaces", Mathematical Programming,
-// 40 (1988), pp. 247--263
-enum DoglegType {
- // The traditional approach constructs a dogleg path
- // consisting of two line segments and finds the furthest
- // point on that path that is still inside the trust region.
- TRADITIONAL_DOGLEG,
-
- // The subspace approach finds the exact minimum of the model
- // constrained to the subspace spanned by the dogleg path.
- SUBSPACE_DOGLEG
-};
-
-enum TerminationType {
- // Minimizer terminated because one of the convergence criterion set
- // by the user was satisfied.
- //
- // 1. (new_cost - old_cost) < function_tolerance * old_cost;
- // 2. max_i |gradient_i| < gradient_tolerance
- // 3. |step|_2 <= parameter_tolerance * ( |x|_2 + parameter_tolerance)
- //
- // The user's parameter blocks will be updated with the solution.
- CONVERGENCE,
-
- // The solver ran for maximum number of iterations or maximum amount
- // of time specified by the user, but none of the convergence
- // criterion specified by the user were met. The user's parameter
- // blocks will be updated with the solution found so far.
- NO_CONVERGENCE,
-
- // The minimizer terminated because of an error. The user's
- // parameter blocks will not be updated.
- FAILURE,
-
- // Using an IterationCallback object, user code can control the
- // minimizer. The following enums indicate that the user code was
- // responsible for termination.
- //
- // Minimizer terminated successfully because a user
- // IterationCallback returned SOLVER_TERMINATE_SUCCESSFULLY.
- //
- // The user's parameter blocks will be updated with the solution.
- USER_SUCCESS,
-
- // Minimizer terminated because because a user IterationCallback
- // returned SOLVER_ABORT.
- //
- // The user's parameter blocks will not be updated.
- USER_FAILURE
-};
-
-// Enums used by the IterationCallback instances to indicate to the
-// solver whether it should continue solving, the user detected an
-// error or the solution is good enough and the solver should
-// terminate.
-enum CallbackReturnType {
- // Continue solving to next iteration.
- SOLVER_CONTINUE,
-
- // Terminate solver, and do not update the parameter blocks upon
- // return. Unless the user has set
- // Solver:Options:::update_state_every_iteration, in which case the
- // state would have been updated every iteration
- // anyways. Solver::Summary::termination_type is set to USER_ABORT.
- SOLVER_ABORT,
-
- // Terminate solver, update state and
- // return. Solver::Summary::termination_type is set to USER_SUCCESS.
- SOLVER_TERMINATE_SUCCESSFULLY
-};
-
-// The format in which linear least squares problems should be logged
-// when Solver::Options::lsqp_iterations_to_dump is non-empty.
-enum DumpFormatType {
- // Print the linear least squares problem in a human readable format
- // to stderr. The Jacobian is printed as a dense matrix. The vectors
- // D, x and f are printed as dense vectors. This should only be used
- // for small problems.
- CONSOLE,
-
- // Write out the linear least squares problem to the directory
- // pointed to by Solver::Options::lsqp_dump_directory as text files
- // which can be read into MATLAB/Octave. The Jacobian is dumped as a
- // text file containing (i,j,s) triplets, the vectors D, x and f are
- // dumped as text files containing a list of their values.
- //
- // A MATLAB/octave script called lm_iteration_???.m is also output,
- // which can be used to parse and load the problem into memory.
- TEXTFILE
-};
-
-// For SizedCostFunction and AutoDiffCostFunction, DYNAMIC can be
-// specified for the number of residuals. If specified, then the
-// number of residuas for that cost function can vary at runtime.
-enum DimensionType {
- DYNAMIC = -1
-};
-
-enum NumericDiffMethod {
- CENTRAL,
- FORWARD
-};
-
-enum LineSearchInterpolationType {
- BISECTION,
- QUADRATIC,
- CUBIC
-};
-
-enum CovarianceAlgorithmType {
- DENSE_SVD,
- SUITE_SPARSE_QR,
- EIGEN_SPARSE_QR
-};
-
-CERES_EXPORT const char* LinearSolverTypeToString(
- LinearSolverType type);
-CERES_EXPORT bool StringToLinearSolverType(string value,
- LinearSolverType* type);
-
-CERES_EXPORT const char* PreconditionerTypeToString(PreconditionerType type);
-CERES_EXPORT bool StringToPreconditionerType(string value,
- PreconditionerType* type);
-
-CERES_EXPORT const char* VisibilityClusteringTypeToString(
- VisibilityClusteringType type);
-CERES_EXPORT bool StringToVisibilityClusteringType(string value,
- VisibilityClusteringType* type);
-
-CERES_EXPORT const char* SparseLinearAlgebraLibraryTypeToString(
- SparseLinearAlgebraLibraryType type);
-CERES_EXPORT bool StringToSparseLinearAlgebraLibraryType(
- string value,
- SparseLinearAlgebraLibraryType* type);
-
-CERES_EXPORT const char* DenseLinearAlgebraLibraryTypeToString(
- DenseLinearAlgebraLibraryType type);
-CERES_EXPORT bool StringToDenseLinearAlgebraLibraryType(
- string value,
- DenseLinearAlgebraLibraryType* type);
-
-CERES_EXPORT const char* TrustRegionStrategyTypeToString(
- TrustRegionStrategyType type);
-CERES_EXPORT bool StringToTrustRegionStrategyType(string value,
- TrustRegionStrategyType* type);
-
-CERES_EXPORT const char* DoglegTypeToString(DoglegType type);
-CERES_EXPORT bool StringToDoglegType(string value, DoglegType* type);
-
-CERES_EXPORT const char* MinimizerTypeToString(MinimizerType type);
-CERES_EXPORT bool StringToMinimizerType(string value, MinimizerType* type);
-
-CERES_EXPORT const char* LineSearchDirectionTypeToString(
- LineSearchDirectionType type);
-CERES_EXPORT bool StringToLineSearchDirectionType(string value,
- LineSearchDirectionType* type);
-
-CERES_EXPORT const char* LineSearchTypeToString(LineSearchType type);
-CERES_EXPORT bool StringToLineSearchType(string value, LineSearchType* type);
-
-CERES_EXPORT const char* NonlinearConjugateGradientTypeToString(
- NonlinearConjugateGradientType type);
-CERES_EXPORT bool StringToNonlinearConjugateGradientType(
- string value,
- NonlinearConjugateGradientType* type);
-
-CERES_EXPORT const char* LineSearchInterpolationTypeToString(
- LineSearchInterpolationType type);
-CERES_EXPORT bool StringToLineSearchInterpolationType(
- string value,
- LineSearchInterpolationType* type);
-
-CERES_EXPORT const char* CovarianceAlgorithmTypeToString(
- CovarianceAlgorithmType type);
-CERES_EXPORT bool StringToCovarianceAlgorithmType(
- string value,
- CovarianceAlgorithmType* type);
-
-CERES_EXPORT const char* TerminationTypeToString(TerminationType type);
-
-CERES_EXPORT bool IsSchurType(LinearSolverType type);
-CERES_EXPORT bool IsSparseLinearAlgebraLibraryTypeAvailable(
- SparseLinearAlgebraLibraryType type);
-CERES_EXPORT bool IsDenseLinearAlgebraLibraryTypeAvailable(
- DenseLinearAlgebraLibraryType type);
-
-} // namespace ceres
-
-#include "ceres/internal/reenable_warnings.h"
-
-#endif // CERES_PUBLIC_TYPES_H_
diff --git a/extern/libmv/third_party/ceres/include/ceres/version.h b/extern/libmv/third_party/ceres/include/ceres/version.h
deleted file mode 100644
index 370b08af73e..00000000000
--- a/extern/libmv/third_party/ceres/include/ceres/version.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: mierle@gmail.com (Keir Mierle)
-
-#ifndef CERES_PUBLIC_VERSION_H_
-#define CERES_PUBLIC_VERSION_H_
-
-#define CERES_VERSION_MAJOR 1
-#define CERES_VERSION_MINOR 10
-#define CERES_VERSION_REVISION 0
-#define CERES_VERSION_ABI 1
-
-// Classic CPP stringifcation; the extra level of indirection allows the
-// preprocessor to expand the macro before being converted to a string.
-#define CERES_TO_STRING_HELPER(x) #x
-#define CERES_TO_STRING(x) CERES_TO_STRING_HELPER(x)
-
-// The Ceres version as a string; for example "1.9.0".
-#define CERES_VERSION_STRING CERES_TO_STRING(CERES_VERSION_MAJOR) "." \
- CERES_TO_STRING(CERES_VERSION_MINOR) "." \
- CERES_TO_STRING(CERES_VERSION_REVISION)
-
-#endif // CERES_PUBLIC_VERSION_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/array_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/array_utils.cc
deleted file mode 100644
index 205ddaf27c9..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/array_utils.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/array_utils.h"
-
-#include <algorithm>
-#include <cmath>
-#include <cstddef>
-#include <string>
-#include <vector>
-#include "ceres/fpclassify.h"
-#include "ceres/stringprintf.h"
-
-namespace ceres {
-namespace internal {
-
-// It is a near impossibility that user code generates this exact
-// value in normal operation, thus we will use it to fill arrays
-// before passing them to user code. If on return an element of the
-// array still contains this value, we will assume that the user code
-// did not write to that memory location.
-const double kImpossibleValue = 1e302;
-
-bool IsArrayValid(const int size, const double* x) {
- if (x != NULL) {
- for (int i = 0; i < size; ++i) {
- if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) {
- return false;
- }
- }
- }
- return true;
-}
-
-int FindInvalidValue(const int size, const double* x) {
- if (x == NULL) {
- return size;
- }
-
- for (int i = 0; i < size; ++i) {
- if (!IsFinite(x[i]) || (x[i] == kImpossibleValue)) {
- return i;
- }
- }
-
- return size;
-};
-
-void InvalidateArray(const int size, double* x) {
- if (x != NULL) {
- for (int i = 0; i < size; ++i) {
- x[i] = kImpossibleValue;
- }
- }
-}
-
-void AppendArrayToString(const int size, const double* x, string* result) {
- for (int i = 0; i < size; ++i) {
- if (x == NULL) {
- StringAppendF(result, "Not Computed ");
- } else {
- if (x[i] == kImpossibleValue) {
- StringAppendF(result, "Uninitialized ");
- } else {
- StringAppendF(result, "%12g ", x[i]);
- }
- }
- }
-}
-
-void MapValuesToContiguousRange(const int size, int* array) {
- std::vector<int> unique_values(array, array + size);
- std::sort(unique_values.begin(), unique_values.end());
- unique_values.erase(std::unique(unique_values.begin(),
- unique_values.end()),
- unique_values.end());
-
- for (int i = 0; i < size; ++i) {
- array[i] = std::lower_bound(unique_values.begin(),
- unique_values.end(),
- array[i]) - unique_values.begin();
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
deleted file mode 100644
index 7f56947066b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Utility routines for validating arrays.
-//
-// These are useful for detecting two common class of errors.
-//
-// 1. Uninitialized memory - where the user for some reason did not
-// compute part of an array, but the code expects it.
-//
-// 2. Numerical failure while computing the cost/residual/jacobian,
-// e.g. NaN, infinities etc. This is particularly useful since the
-// automatic differentiation code does computations that are not
-// evident to the user and can silently generate hard to debug errors.
-
-#ifndef CERES_INTERNAL_ARRAY_UTILS_H_
-#define CERES_INTERNAL_ARRAY_UTILS_H_
-
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-// Fill the array x with an impossible value that the user code is
-// never expected to compute.
-void InvalidateArray(int size, double* x);
-
-// Check if all the entries of the array x are valid, i.e. all the
-// values in the array should be finite and none of them should be
-// equal to the "impossible" value used by InvalidateArray.
-bool IsArrayValid(int size, const double* x);
-
-// If the array contains an invalid value, return the index for it,
-// otherwise return size.
-int FindInvalidValue(const int size, const double* x);
-
-// Utility routine to print an array of doubles to a string. If the
-// array pointer is NULL, it is treated as an array of zeros.
-void AppendArrayToString(const int size, const double* x, string* result);
-
-extern const double kImpossibleValue;
-
-// This routine takes an array of integer values, sorts and uniques
-// them and then maps each value in the array to its position in the
-// sorted+uniqued array. By doing this, if there are are k unique
-// values in the array, each value is replaced by an integer in the
-// range [0, k-1], while preserving their relative order.
-//
-// For example
-//
-// [1 0 3 5 0 1 5]
-//
-// gets mapped to
-//
-// [1 0 2 3 0 1 3]
-void MapValuesToContiguousRange(int size, int* array);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_ARRAY_UTILS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/blas.cc b/extern/libmv/third_party/ceres/internal/ceres/blas.cc
deleted file mode 100644
index b919e13c4a9..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/blas.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/blas.h"
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-extern "C" void dsyrk_(char* uplo,
- char* trans,
- int* n,
- int* k,
- double* alpha,
- double* a,
- int* lda,
- double* beta,
- double* c,
- int* ldc);
-
-namespace ceres {
-namespace internal {
-
-void BLAS::SymmetricRankKUpdate(int num_rows,
- int num_cols,
- const double* a,
- bool transpose,
- double alpha,
- double beta,
- double* c) {
-#ifdef CERES_NO_LAPACK
- LOG(FATAL) << "Ceres was built without a BLAS library.";
-#else
- char uplo = 'L';
- char trans = transpose ? 'T' : 'N';
- int n = transpose ? num_cols : num_rows;
- int k = transpose ? num_rows : num_cols;
- int lda = k;
- int ldc = n;
- dsyrk_(&uplo,
- &trans,
- &n,
- &k,
- &alpha,
- const_cast<double*>(a),
- &lda,
- &beta,
- c,
- &ldc);
-#endif
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/blas.h b/extern/libmv/third_party/ceres/internal/ceres/blas.h
deleted file mode 100644
index 2ab666395b9..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/blas.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Wrapper functions around BLAS functions.
-
-#ifndef CERES_INTERNAL_BLAS_H_
-#define CERES_INTERNAL_BLAS_H_
-
-namespace ceres {
-namespace internal {
-
-class BLAS {
- public:
- // transpose = true : c = alpha * a'a + beta * c;
- // transpose = false : c = alpha * aa' + beta * c;
- //
- // Assumes column major matrices.
- static void SymmetricRankKUpdate(int num_rows,
- int num_cols,
- const double* a,
- bool transpose,
- double alpha,
- double beta,
- double* c);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLAS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc b/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc
deleted file mode 100644
index 9edc4fa23bd..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/block_evaluate_preparer.h"
-
-#include <vector>
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/casts.h"
-#include "ceres/parameter_block.h"
-#include "ceres/residual_block.h"
-#include "ceres/sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-void BlockEvaluatePreparer::Init(int const* const* jacobian_layout,
- int max_derivatives_per_residual_block) {
- jacobian_layout_ = jacobian_layout;
- scratch_evaluate_preparer_.Init(max_derivatives_per_residual_block);
-}
-
-// Point the jacobian blocks directly into the block sparse matrix.
-void BlockEvaluatePreparer::Prepare(const ResidualBlock* residual_block,
- int residual_block_index,
- SparseMatrix* jacobian,
- double** jacobians) {
- // If the overall jacobian is not available, use the scratch space.
- if (jacobian == NULL) {
- scratch_evaluate_preparer_.Prepare(residual_block,
- residual_block_index,
- jacobian,
- jacobians);
- return;
- }
-
- double* jacobian_values =
- down_cast<BlockSparseMatrix*>(jacobian)->mutable_values();
-
- const int* jacobian_block_offset = jacobian_layout_[residual_block_index];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- if (!residual_block->parameter_blocks()[j]->IsConstant()) {
- jacobians[j] = jacobian_values + *jacobian_block_offset;
-
- // The jacobian_block_offset can't be indexed with 'j' since the code
- // that creates the layout strips out any blocks for inactive
- // parameters. Instead, bump the pointer for active parameters only.
- jacobian_block_offset++;
- } else {
- jacobians[j] = NULL;
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h b/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h
deleted file mode 100644
index 354acc031f4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_evaluate_preparer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A evaluate preparer which puts jacobian the evaluated jacobian blocks
-// directly into their final resting place in an overall block sparse matrix.
-// The evaluator takes care to avoid evaluating the jacobian for fixed
-// parameters.
-
-#ifndef CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
-#define CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
-
-#include "ceres/scratch_evaluate_preparer.h"
-
-namespace ceres {
-namespace internal {
-
-class ResidualBlock;
-class SparseMatrix;
-
-class BlockEvaluatePreparer {
- public:
- // Using Init() instead of a constructor allows for allocating this structure
- // with new[]. This is because C++ doesn't allow passing arguments to objects
- // constructed with new[] (as opposed to plain 'new').
- void Init(int const* const* jacobian_layout,
- int max_derivatives_per_residual_block);
-
- // EvaluatePreparer interface
-
- // Point the jacobian blocks directly into the block sparse matrix, if
- // jacobian is non-null. Otherwise, uses an internal per-thread buffer to
- // store the jacobians temporarily.
- void Prepare(const ResidualBlock* residual_block,
- int residual_block_index,
- SparseMatrix* jacobian,
- double** jacobians);
-
- private:
- int const* const* jacobian_layout_;
-
- // For the case that the overall jacobian is not available, but the
- // individual jacobians are requested, use a pass-through scratch evaluate
- // preparer.
- ScratchEvaluatePreparer scratch_evaluate_preparer_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
deleted file mode 100644
index 7f79a4f993d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/block_jacobi_preconditioner.h"
-
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/block_random_access_diagonal_matrix.h"
-#include "ceres/casts.h"
-#include "ceres/integral_types.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-BlockJacobiPreconditioner::BlockJacobiPreconditioner(
- const BlockSparseMatrix& A) {
- const CompressedRowBlockStructure* bs = A.block_structure();
- vector<int> blocks(bs->cols.size());
- for (int i = 0; i < blocks.size(); ++i) {
- blocks[i] = bs->cols[i].size;
- }
-
- m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
-}
-
-BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {}
-
-bool BlockJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
- const double* D) {
- const CompressedRowBlockStructure* bs = A.block_structure();
- const double* values = A.values();
- m_->SetZero();
- for (int i = 0; i < bs->rows.size(); ++i) {
- const int row_block_size = bs->rows[i].block.size;
- const vector<Cell>& cells = bs->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- const int block_id = cells[j].block_id;
- const int col_block_size = bs->cols[block_id].size;
-
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = m_->GetCell(block_id, block_id,
- &r, &c,
- &row_stride, &col_stride);
- MatrixRef m(cell_info->values, row_stride, col_stride);
- ConstMatrixRef b(values + cells[j].position,
- row_block_size,
- col_block_size);
- m.block(r, c, col_block_size, col_block_size) += b.transpose() * b;
- }
- }
-
- if (D != NULL) {
- // Add the diagonal.
- int position = 0;
- for (int i = 0; i < bs->cols.size(); ++i) {
- const int block_size = bs->cols[i].size;
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = m_->GetCell(i, i,
- &r, &c,
- &row_stride, &col_stride);
- MatrixRef m(cell_info->values, row_stride, col_stride);
- m.block(r, c, block_size, block_size).diagonal() +=
- ConstVectorRef(D + position, block_size).array().square().matrix();
- position += block_size;
- }
- }
-
- m_->Invert();
- return true;
-}
-
-void BlockJacobiPreconditioner::RightMultiply(const double* x,
- double* y) const {
- m_->RightMultiply(x, y);
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
deleted file mode 100644
index e23e0e2d24c..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
-#define CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
-
-#include <vector>
-#include "ceres/block_random_access_diagonal_matrix.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/preconditioner.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockSparseMatrix;
-struct CompressedRowBlockStructure;
-
-// A block Jacobi preconditioner. This is intended for use with
-// conjugate gradients, or other iterative symmetric solvers. To use
-// the preconditioner, create one by passing a BlockSparseMatrix "A"
-// to the constructor. This fixes the sparsity pattern to the pattern
-// of the matrix A^TA.
-//
-// Before each use of the preconditioner in a solve with conjugate gradients,
-// update the matrix by running Update(A, D). The values of the matrix A are
-// inspected to construct the preconditioner. The vector D is applied as the
-// D^TD diagonal term.
-class BlockJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
- public:
- // A must remain valid while the BlockJacobiPreconditioner is.
- explicit BlockJacobiPreconditioner(const BlockSparseMatrix& A);
- virtual ~BlockJacobiPreconditioner();
-
- // Preconditioner interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const { return m_->num_rows(); }
- virtual int num_cols() const { return m_->num_rows(); }
-
- const BlockRandomAccessDiagonalMatrix& matrix() const { return *m_; }
- private:
- virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
-
- scoped_ptr<BlockRandomAccessDiagonalMatrix> m_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc
deleted file mode 100644
index f90c350cc80..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/block_jacobian_writer.h"
-
-#include "ceres/block_evaluate_preparer.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-// Given the residual block ordering, build a lookup table to determine which
-// per-parameter jacobian goes where in the overall program jacobian.
-//
-// Since we expect to use a Schur type linear solver to solve the LM step, take
-// extra care to place the E blocks and the F blocks contiguously. E blocks are
-// the first num_eliminate_blocks parameter blocks as indicated by the parameter
-// block ordering. The remaining parameter blocks are the F blocks.
-//
-// TODO(keir): Consider if we should use a boolean for each parameter block
-// instead of num_eliminate_blocks.
-void BuildJacobianLayout(const Program& program,
- int num_eliminate_blocks,
- vector<int*>* jacobian_layout,
- vector<int>* jacobian_layout_storage) {
- const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
-
- // Iterate over all the active residual blocks and determine how many E blocks
- // are there. This will determine where the F blocks start in the jacobian
- // matrix. Also compute the number of jacobian blocks.
- int f_block_pos = 0;
- int num_jacobian_blocks = 0;
- for (int i = 0; i < residual_blocks.size(); ++i) {
- ResidualBlock* residual_block = residual_blocks[i];
- const int num_residuals = residual_block->NumResiduals();
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
-
- // Advance f_block_pos over each E block for this residual.
- for (int j = 0; j < num_parameter_blocks; ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- if (!parameter_block->IsConstant()) {
- // Only count blocks for active parameters.
- num_jacobian_blocks++;
- if (parameter_block->index() < num_eliminate_blocks) {
- f_block_pos += num_residuals * parameter_block->LocalSize();
- }
- }
- }
- }
-
- // We now know that the E blocks are laid out starting at zero, and the F
- // blocks are laid out starting at f_block_pos. Iterate over the residual
- // blocks again, and this time fill the jacobian_layout array with the
- // position information.
-
- jacobian_layout->resize(program.NumResidualBlocks());
- jacobian_layout_storage->resize(num_jacobian_blocks);
-
- int e_block_pos = 0;
- int* jacobian_pos = &(*jacobian_layout_storage)[0];
- for (int i = 0; i < residual_blocks.size(); ++i) {
- const ResidualBlock* residual_block = residual_blocks[i];
- const int num_residuals = residual_block->NumResiduals();
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
-
- (*jacobian_layout)[i] = jacobian_pos;
- for (int j = 0; j < num_parameter_blocks; ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- const int parameter_block_index = parameter_block->index();
- if (parameter_block->IsConstant()) {
- continue;
- }
- const int jacobian_block_size =
- num_residuals * parameter_block->LocalSize();
- if (parameter_block_index < num_eliminate_blocks) {
- *jacobian_pos = e_block_pos;
- e_block_pos += jacobian_block_size;
- } else {
- *jacobian_pos = f_block_pos;
- f_block_pos += jacobian_block_size;
- }
- jacobian_pos++;
- }
- }
-}
-
-} // namespace
-
-BlockJacobianWriter::BlockJacobianWriter(const Evaluator::Options& options,
- Program* program)
- : program_(program) {
- CHECK_GE(options.num_eliminate_blocks, 0)
- << "num_eliminate_blocks must be greater than 0.";
-
- BuildJacobianLayout(*program,
- options.num_eliminate_blocks,
- &jacobian_layout_,
- &jacobian_layout_storage_);
-}
-
-// Create evaluate prepareres that point directly into the final jacobian. This
-// makes the final Write() a nop.
-BlockEvaluatePreparer* BlockJacobianWriter::CreateEvaluatePreparers(
- int num_threads) {
- int max_derivatives_per_residual_block =
- program_->MaxDerivativesPerResidualBlock();
-
- BlockEvaluatePreparer* preparers = new BlockEvaluatePreparer[num_threads];
- for (int i = 0; i < num_threads; i++) {
- preparers[i].Init(&jacobian_layout_[0], max_derivatives_per_residual_block);
- }
- return preparers;
-}
-
-SparseMatrix* BlockJacobianWriter::CreateJacobian() const {
- CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
-
- const vector<ParameterBlock*>& parameter_blocks =
- program_->parameter_blocks();
-
- // Construct the column blocks.
- bs->cols.resize(parameter_blocks.size());
- for (int i = 0, cursor = 0; i < parameter_blocks.size(); ++i) {
- CHECK_NE(parameter_blocks[i]->index(), -1);
- CHECK(!parameter_blocks[i]->IsConstant());
- bs->cols[i].size = parameter_blocks[i]->LocalSize();
- bs->cols[i].position = cursor;
- cursor += bs->cols[i].size;
- }
-
- // Construct the cells in each row.
- const vector<ResidualBlock*>& residual_blocks =
- program_->residual_blocks();
- int row_block_position = 0;
- bs->rows.resize(residual_blocks.size());
- for (int i = 0; i < residual_blocks.size(); ++i) {
- const ResidualBlock* residual_block = residual_blocks[i];
- CompressedRow* row = &bs->rows[i];
-
- row->block.size = residual_block->NumResiduals();
- row->block.position = row_block_position;
- row_block_position += row->block.size;
-
- // Size the row by the number of active parameters in this residual.
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- int num_active_parameter_blocks = 0;
- for (int j = 0; j < num_parameter_blocks; ++j) {
- if (residual_block->parameter_blocks()[j]->index() != -1) {
- num_active_parameter_blocks++;
- }
- }
- row->cells.resize(num_active_parameter_blocks);
-
- // Add layout information for the active parameters in this row.
- for (int j = 0, k = 0; j < num_parameter_blocks; ++j) {
- const ParameterBlock* parameter_block =
- residual_block->parameter_blocks()[j];
- if (!parameter_block->IsConstant()) {
- Cell& cell = row->cells[k];
- cell.block_id = parameter_block->index();
- cell.position = jacobian_layout_[i][k];
-
- // Only increment k for active parameters, since there is only layout
- // information for active parameters.
- k++;
- }
- }
-
- sort(row->cells.begin(), row->cells.end(), CellLessThan);
- }
-
- BlockSparseMatrix* jacobian = new BlockSparseMatrix(bs);
- CHECK_NOTNULL(jacobian);
- return jacobian;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.h b/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.h
deleted file mode 100644
index 140c7211129..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobian_writer.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A jacobian writer that writes to block sparse matrices. The "writer" name is
-// misleading, since the Write() operation on the block jacobian writer does not
-// write anything. Instead, the Prepare() method on the BlockEvaluatePreparers
-// makes a jacobians array which has direct pointers into the block sparse
-// jacobian. When the cost function is evaluated, the jacobian blocks get placed
-// directly in their final location.
-
-#ifndef CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
-#define CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
-
-#include <vector>
-#include "ceres/evaluator.h"
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockEvaluatePreparer;
-class Program;
-class SparseMatrix;
-
-class BlockJacobianWriter {
- public:
- BlockJacobianWriter(const Evaluator::Options& options,
- Program* program);
-
- // JacobianWriter interface.
-
- // Create evaluate prepareres that point directly into the final jacobian.
- // This makes the final Write() a nop.
- BlockEvaluatePreparer* CreateEvaluatePreparers(int num_threads);
-
- SparseMatrix* CreateJacobian() const;
-
- void Write(int /* residual_id */,
- int /* residual_offset */,
- double** /* jacobians */,
- SparseMatrix* /* jacobian */) {
- // This is a noop since the blocks were written directly into their final
- // position by the outside evaluate call, thanks to the jacobians array
- // prepared by the BlockEvaluatePreparers.
- }
-
- private:
- Program* program_;
-
- // Stores the position of each residual / parameter jacobian.
- //
- // The block sparse matrix that this writer writes to is stored as a set of
- // contiguos dense blocks, one after each other; see BlockSparseMatrix. The
- // "double* values_" member of the block sparse matrix contains all of these
- // blocks. Given a pointer to the first element of a block and the size of
- // that block, it's possible to write to it.
- //
- // In the case of a block sparse jacobian, the jacobian writer needs a way to
- // find the offset in the values_ array of each residual/parameter jacobian
- // block.
- //
- // That is the purpose of jacobian_layout_.
- //
- // In particular, jacobian_layout_[i][j] is the offset in the values_ array of
- // the derivative of residual block i with respect to the parameter block at
- // active argument position j.
- //
- // The active qualifier means that non-active parameters do not count. Care
- // must be taken when indexing into jacobian_layout_ to account for this.
- // Consider a single residual example:
- //
- // r(x, y, z)
- //
- // with r in R^3, x in R^4, y in R^2, and z in R^5.
- // Take y as a constant (non-active) parameter.
- // Take r as residual number 0.
- //
- // In this case, the active arguments are only (x, z), so the active argument
- // position for x is 0, and the active argument position for z is 1. This is
- // similar to thinking of r as taking only 2 parameters:
- //
- // r(x, z)
- //
- // There are only 2 jacobian blocks: dr/dx and dr/dz. jacobian_layout_ would
- // have the following contents:
- //
- // jacobian_layout_[0] = { 0, 12 }
- //
- // which indicates that dr/dx is located at values_[0], and dr/dz is at
- // values_[12]. See BlockEvaluatePreparer::Prepare()'s comments about 'j'.
- vector<int*> jacobian_layout_;
-
- // The pointers in jacobian_layout_ point directly into this vector.
- vector<int> jacobian_layout_storage_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
deleted file mode 100644
index e5822792fa1..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/block_random_access_dense_matrix.h"
-
-#include <vector>
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-BlockRandomAccessDenseMatrix::BlockRandomAccessDenseMatrix(
- const vector<int>& blocks) {
- const int num_blocks = blocks.size();
- block_layout_.resize(num_blocks, 0);
- num_rows_ = 0;
- for (int i = 0; i < num_blocks; ++i) {
- block_layout_[i] = num_rows_;
- num_rows_ += blocks[i];
- }
-
- values_.reset(new double[num_rows_ * num_rows_]);
-
- cell_infos_.reset(new CellInfo[num_blocks * num_blocks]);
- for (int i = 0; i < num_blocks * num_blocks; ++i) {
- cell_infos_[i].values = values_.get();
- }
-
- SetZero();
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-BlockRandomAccessDenseMatrix::~BlockRandomAccessDenseMatrix() {
-}
-
-CellInfo* BlockRandomAccessDenseMatrix::GetCell(const int row_block_id,
- const int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride) {
- *row = block_layout_[row_block_id];
- *col = block_layout_[col_block_id];
- *row_stride = num_rows_;
- *col_stride = num_rows_;
- return &cell_infos_[row_block_id * block_layout_.size() + col_block_id];
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-void BlockRandomAccessDenseMatrix::SetZero() {
- if (num_rows_) {
- VectorRef(values_.get(), num_rows_ * num_rows_).setZero();
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h
deleted file mode 100644
index d160fd96013..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
-#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
-
-#include "ceres/block_random_access_matrix.h"
-
-#include <vector>
-
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-namespace internal {
-
-// A square block random accessible matrix with the same row and
-// column block structure. All cells are stored in the same single
-// array, so that its also accessible as a dense matrix of size
-// num_rows x num_cols.
-//
-// This class is NOT thread safe. Since all n^2 cells are stored,
-// GetCell never returns NULL for any (row_block_id, col_block_id)
-// pair.
-//
-// ReturnCell is a nop.
-class BlockRandomAccessDenseMatrix : public BlockRandomAccessMatrix {
- public:
- // blocks is a vector of block sizes. The resulting matrix has
- // blocks.size() * blocks.size() cells.
- explicit BlockRandomAccessDenseMatrix(const vector<int>& blocks);
-
- // The destructor is not thread safe. It assumes that no one is
- // modifying any cells when the matrix is being destroyed.
- virtual ~BlockRandomAccessDenseMatrix();
-
- // BlockRandomAccessMatrix interface.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride);
-
- // This is not a thread safe method, it assumes that no cell is
- // locked.
- virtual void SetZero();
-
- // Since the matrix is square with the same row and column block
- // structure, num_rows() = num_cols().
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_rows_; }
-
- // The underlying matrix storing the cells.
- const double* values() const { return values_.get(); }
- double* mutable_values() { return values_.get(); }
-
- private:
- int num_rows_;
- vector<int> block_layout_;
- scoped_array<double> values_;
- scoped_array<CellInfo> cell_infos_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDenseMatrix);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
deleted file mode 100644
index b7ff33184cb..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/block_random_access_diagonal_matrix.h"
-
-#include <algorithm>
-#include <set>
-#include <utility>
-#include <vector>
-#include "Eigen/Dense"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/stl_util.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// TODO(sameeragarwal): Drop the dependence on TripletSparseMatrix.
-
-BlockRandomAccessDiagonalMatrix::BlockRandomAccessDiagonalMatrix(
- const vector<int>& blocks)
- : blocks_(blocks) {
- // Build the row/column layout vector and count the number of scalar
- // rows/columns.
- int num_cols = 0;
- int num_nonzeros = 0;
- vector<int> block_positions;
- for (int i = 0; i < blocks_.size(); ++i) {
- block_positions.push_back(num_cols);
- num_cols += blocks_[i];
- num_nonzeros += blocks_[i] * blocks_[i];
- }
-
- VLOG(1) << "Matrix Size [" << num_cols
- << "," << num_cols
- << "] " << num_nonzeros;
-
- tsm_.reset(new TripletSparseMatrix(num_cols, num_cols, num_nonzeros));
- tsm_->set_num_nonzeros(num_nonzeros);
- int* rows = tsm_->mutable_rows();
- int* cols = tsm_->mutable_cols();
- double* values = tsm_->mutable_values();
-
- int pos = 0;
- for (int i = 0; i < blocks_.size(); ++i) {
- const int block_size = blocks_[i];
- layout_.push_back(new CellInfo(values + pos));
- const int block_begin = block_positions[i];
- for (int r = 0; r < block_size; ++r) {
- for (int c = 0; c < block_size; ++c, ++pos) {
- rows[pos] = block_begin + r;
- cols[pos] = block_begin + c;
- }
- }
- }
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-BlockRandomAccessDiagonalMatrix::~BlockRandomAccessDiagonalMatrix() {
- STLDeleteContainerPointers(layout_.begin(), layout_.end());
-}
-
-CellInfo* BlockRandomAccessDiagonalMatrix::GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride) {
- if (row_block_id != col_block_id) {
- return NULL;
- }
- const int stride = blocks_[row_block_id];
-
- // Each cell is stored contiguously as its own little dense matrix.
- *row = 0;
- *col = 0;
- *row_stride = stride;
- *col_stride = stride;
- return layout_[row_block_id];
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-void BlockRandomAccessDiagonalMatrix::SetZero() {
- if (tsm_->num_nonzeros()) {
- VectorRef(tsm_->mutable_values(),
- tsm_->num_nonzeros()).setZero();
- }
-}
-
-void BlockRandomAccessDiagonalMatrix::Invert() {
- double* values = tsm_->mutable_values();
- for (int i = 0; i < blocks_.size(); ++i) {
- const int block_size = blocks_[i];
- MatrixRef block(values, block_size, block_size);
- block =
- block
- .selfadjointView<Eigen::Upper>()
- .llt()
- .solve(Matrix::Identity(block_size, block_size));
- values += block_size * block_size;
- }
-}
-
-void BlockRandomAccessDiagonalMatrix::RightMultiply(const double* x,
- double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
- const double* values = tsm_->values();
- for (int i = 0; i < blocks_.size(); ++i) {
- const int block_size = blocks_[i];
- ConstMatrixRef block(values, block_size, block_size);
- VectorRef(y, block_size).noalias() += block * ConstVectorRef(x, block_size);
- x += block_size;
- y += block_size;
- values += block_size * block_size;
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h
deleted file mode 100644
index ea9967817db..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
-#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
-
-#include <set>
-#include <vector>
-#include <utility>
-#include "ceres/mutex.h"
-#include "ceres/block_random_access_matrix.h"
-#include "ceres/collections_port.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/integral_types.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-// A thread safe block diagonal matrix implementation of
-// BlockRandomAccessMatrix.
-class BlockRandomAccessDiagonalMatrix : public BlockRandomAccessMatrix {
- public:
- // blocks is an array of block sizes.
- explicit BlockRandomAccessDiagonalMatrix(const vector<int>& blocks);
-
- // The destructor is not thread safe. It assumes that no one is
- // modifying any cells when the matrix is being destroyed.
- virtual ~BlockRandomAccessDiagonalMatrix();
-
- // BlockRandomAccessMatrix Interface.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride);
-
- // This is not a thread safe method, it assumes that no cell is
- // locked.
- virtual void SetZero();
-
- // Invert the matrix assuming that each block is positive definite.
- void Invert();
-
- // y += S * x
- void RightMultiply(const double* x, double* y) const;
-
- // Since the matrix is square, num_rows() == num_cols().
- virtual int num_rows() const { return tsm_->num_rows(); }
- virtual int num_cols() const { return tsm_->num_cols(); }
-
- const TripletSparseMatrix* matrix() const { return tsm_.get(); }
- TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
-
- private:
- // row/column block sizes.
- const vector<int> blocks_;
- vector<CellInfo*> layout_;
-
- // The underlying matrix object which actually stores the cells.
- scoped_ptr<TripletSparseMatrix> tsm_;
-
- friend class BlockRandomAccessDiagonalMatrixTest;
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessDiagonalMatrix);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.cc
deleted file mode 100644
index 58fe4a10de3..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/block_random_access_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-BlockRandomAccessMatrix::~BlockRandomAccessMatrix() {
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h
deleted file mode 100644
index b76cb78b160..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_matrix.h
+++ /dev/null
@@ -1,132 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Interface for matrices that allow block based random access.
-
-#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
-#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
-
-#include "ceres/mutex.h"
-
-namespace ceres {
-namespace internal {
-
-// A matrix implementing the BlockRandomAccessMatrix interface is a
-// matrix whose rows and columns are divided into blocks. For example
-// the matrix A:
-//
-// 3 4 5
-// A = 5 [c_11 c_12 c_13]
-// 4 [c_21 c_22 c_23]
-//
-// has row blocks of size 5 and 4, and column blocks of size 3, 4 and
-// 5. It has six cells corresponding to the six row-column block
-// combinations.
-//
-// BlockRandomAccessMatrix objects provide access to cells c_ij using
-// the GetCell method. when a cell is present, GetCell will return a
-// CellInfo object containing a pointer to an array which contains the
-// cell as a submatrix and a mutex that guards this submatrix. If the
-// user is accessing the matrix concurrently, it is his responsibility
-// to use the mutex to exclude other writers from writing to the cell
-// concurrently.
-//
-// There is no requirement that all cells be present, i.e. the matrix
-// itself can be block sparse. When a cell is not present, the GetCell
-// method will return a NULL pointer.
-//
-// There is no requirement about how the cells are stored beyond that
-// form a dense submatrix of a larger dense matrix. Like everywhere
-// else in Ceres, RowMajor storage assumed.
-//
-// Example usage:
-//
-// BlockRandomAccessMatrix* A = new BlockRandomAccessMatrixSubClass(...)
-//
-// int row, col, row_stride, col_stride;
-// CellInfo* cell = A->GetCell(row_block_id, col_block_id,
-// &row, &col,
-// &row_stride, &col_stride);
-//
-// if (cell != NULL) {
-// MatrixRef m(cell->values, row_stride, col_stride);
-// CeresMutexLock l(&cell->m);
-// m.block(row, col, row_block_size, col_block_size) = ...
-// }
-
-// Structure to carry a pointer to the array containing a cell and the
-// Mutex guarding it.
-struct CellInfo {
- CellInfo()
- : values(NULL) {
- }
-
- explicit CellInfo(double* ptr)
- : values(ptr) {
- }
-
- double* values;
- Mutex m;
-};
-
-class BlockRandomAccessMatrix {
- public:
- virtual ~BlockRandomAccessMatrix();
-
- // If the cell (row_block_id, col_block_id) is present, then return
- // a CellInfo with a pointer to the dense matrix containing it,
- // otherwise return NULL. The dense matrix containing this cell has
- // size row_stride, col_stride and the cell is located at position
- // (row, col) within this matrix.
- //
- // The size of the cell is row_block_size x col_block_size is
- // assumed known to the caller. row_block_size less than or equal to
- // row_stride and col_block_size is upper bounded by col_stride.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride) = 0;
-
- // Zero out the values of the array. The structure of the matrix
- // (size and sparsity) is preserved.
- virtual void SetZero() = 0;
-
- // Number of scalar rows and columns in the matrix, i.e the sum of
- // all row blocks and column block sizes respectively.
- virtual int num_rows() const = 0;
- virtual int num_cols() const = 0;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
deleted file mode 100644
index c43a9b78feb..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
+++ /dev/null
@@ -1,191 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/block_random_access_sparse_matrix.h"
-
-#include <algorithm>
-#include <set>
-#include <utility>
-#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/mutex.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
- const vector<int>& blocks,
- const set<pair<int, int> >& block_pairs)
- : kMaxRowBlocks(10 * 1000 * 1000),
- blocks_(blocks) {
- CHECK_LT(blocks.size(), kMaxRowBlocks);
-
- // Build the row/column layout vector and count the number of scalar
- // rows/columns.
- int num_cols = 0;
- block_positions_.reserve(blocks_.size());
- for (int i = 0; i < blocks_.size(); ++i) {
- block_positions_.push_back(num_cols);
- num_cols += blocks_[i];
- }
-
- // Count the number of scalar non-zero entries and build the layout
- // object for looking into the values array of the
- // TripletSparseMatrix.
- int num_nonzeros = 0;
- for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
- it != block_pairs.end();
- ++it) {
- const int row_block_size = blocks_[it->first];
- const int col_block_size = blocks_[it->second];
- num_nonzeros += row_block_size * col_block_size;
- }
-
- VLOG(1) << "Matrix Size [" << num_cols
- << "," << num_cols
- << "] " << num_nonzeros;
-
- tsm_.reset(new TripletSparseMatrix(num_cols, num_cols, num_nonzeros));
- tsm_->set_num_nonzeros(num_nonzeros);
- int* rows = tsm_->mutable_rows();
- int* cols = tsm_->mutable_cols();
- double* values = tsm_->mutable_values();
-
- int pos = 0;
- for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
- it != block_pairs.end();
- ++it) {
- const int row_block_size = blocks_[it->first];
- const int col_block_size = blocks_[it->second];
- cell_values_.push_back(make_pair(make_pair(it->first, it->second),
- values + pos));
- layout_[IntPairToLong(it->first, it->second)] =
- new CellInfo(values + pos);
- pos += row_block_size * col_block_size;
- }
-
- // Fill the sparsity pattern of the underlying matrix.
- for (set<pair<int, int> >::const_iterator it = block_pairs.begin();
- it != block_pairs.end();
- ++it) {
- const int row_block_id = it->first;
- const int col_block_id = it->second;
- const int row_block_size = blocks_[row_block_id];
- const int col_block_size = blocks_[col_block_id];
- int pos =
- layout_[IntPairToLong(row_block_id, col_block_id)]->values - values;
- for (int r = 0; r < row_block_size; ++r) {
- for (int c = 0; c < col_block_size; ++c, ++pos) {
- rows[pos] = block_positions_[row_block_id] + r;
- cols[pos] = block_positions_[col_block_id] + c;
- values[pos] = 1.0;
- DCHECK_LT(rows[pos], tsm_->num_rows());
- DCHECK_LT(cols[pos], tsm_->num_rows());
- }
- }
- }
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-BlockRandomAccessSparseMatrix::~BlockRandomAccessSparseMatrix() {
- for (LayoutType::iterator it = layout_.begin();
- it != layout_.end();
- ++it) {
- delete it->second;
- }
-}
-
-CellInfo* BlockRandomAccessSparseMatrix::GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride) {
- const LayoutType::iterator it =
- layout_.find(IntPairToLong(row_block_id, col_block_id));
- if (it == layout_.end()) {
- return NULL;
- }
-
- // Each cell is stored contiguously as its own little dense matrix.
- *row = 0;
- *col = 0;
- *row_stride = blocks_[row_block_id];
- *col_stride = blocks_[col_block_id];
- return it->second;
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-void BlockRandomAccessSparseMatrix::SetZero() {
- if (tsm_->num_nonzeros()) {
- VectorRef(tsm_->mutable_values(),
- tsm_->num_nonzeros()).setZero();
- }
-}
-
-void BlockRandomAccessSparseMatrix::SymmetricRightMultiply(const double* x,
- double* y) const {
- vector< pair<pair<int, int>, double*> >::const_iterator it =
- cell_values_.begin();
- for (; it != cell_values_.end(); ++it) {
- const int row = it->first.first;
- const int row_block_size = blocks_[row];
- const int row_block_pos = block_positions_[row];
-
- const int col = it->first.second;
- const int col_block_size = blocks_[col];
- const int col_block_pos = block_positions_[col];
-
- MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- it->second, row_block_size, col_block_size,
- x + col_block_pos,
- y + row_block_pos);
-
- // Since the matrix is symmetric, but only the upper triangular
- // part is stored, if the block being accessed is not a diagonal
- // block, then use the same block to do the corresponding lower
- // triangular multiply also.
- if (row != col) {
- MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- it->second, row_block_size, col_block_size,
- x + row_block_pos,
- y + col_block_pos);
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h
deleted file mode 100644
index 51b5d20cfe0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h
+++ /dev/null
@@ -1,128 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
-
-#include <set>
-#include <vector>
-#include <utility>
-#include "ceres/mutex.h"
-#include "ceres/block_random_access_matrix.h"
-#include "ceres/collections_port.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/integral_types.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "ceres/small_blas.h"
-
-namespace ceres {
-namespace internal {
-
-// A thread safe square block sparse implementation of
-// BlockRandomAccessMatrix. Internally a TripletSparseMatrix is used
-// for doing the actual storage. This class augments this matrix with
-// an unordered_map that allows random read/write access.
-class BlockRandomAccessSparseMatrix : public BlockRandomAccessMatrix {
- public:
- // blocks is an array of block sizes. block_pairs is a set of
- // <row_block_id, col_block_id> pairs to identify the non-zero cells
- // of this matrix.
- BlockRandomAccessSparseMatrix(const vector<int>& blocks,
- const set<pair<int, int> >& block_pairs);
-
- // The destructor is not thread safe. It assumes that no one is
- // modifying any cells when the matrix is being destroyed.
- virtual ~BlockRandomAccessSparseMatrix();
-
- // BlockRandomAccessMatrix Interface.
- virtual CellInfo* GetCell(int row_block_id,
- int col_block_id,
- int* row,
- int* col,
- int* row_stride,
- int* col_stride);
-
- // This is not a thread safe method, it assumes that no cell is
- // locked.
- virtual void SetZero();
-
- // Assume that the matrix is symmetric and only one half of the
- // matrix is stored.
- //
- // y += S * x
- void SymmetricRightMultiply(const double* x, double* y) const;
-
- // Since the matrix is square, num_rows() == num_cols().
- virtual int num_rows() const { return tsm_->num_rows(); }
- virtual int num_cols() const { return tsm_->num_cols(); }
-
- // Access to the underlying matrix object.
- const TripletSparseMatrix* matrix() const { return tsm_.get(); }
- TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
-
- private:
- int64 IntPairToLong(int row, int col) const {
- return row * kMaxRowBlocks + col;
- }
-
- void LongToIntPair(int64 index, int* row, int* col) const {
- *row = index / kMaxRowBlocks;
- *col = index % kMaxRowBlocks;
- }
-
- const int64 kMaxRowBlocks;
-
- // row/column block sizes.
- const vector<int> blocks_;
- vector<int> block_positions_;
-
- // A mapping from <row_block_id, col_block_id> to the position in
- // the values array of tsm_ where the block is stored.
- typedef HashMap<long int, CellInfo* > LayoutType;
- LayoutType layout_;
-
- // In order traversal of contents of the matrix. This allows us to
- // implement a matrix-vector which is 20% faster than using the
- // iterator in the Layout object instead.
- vector<pair<pair<int, int>, double*> > cell_values_;
- // The underlying matrix object which actually stores the cells.
- scoped_ptr<TripletSparseMatrix> tsm_;
-
- friend class BlockRandomAccessSparseMatrixTest;
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockRandomAccessSparseMatrix);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc
deleted file mode 100644
index a4872626114..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/block_sparse_matrix.h"
-
-#include <cstddef>
-#include <algorithm>
-#include <vector>
-#include "ceres/block_structure.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/small_blas.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-BlockSparseMatrix::~BlockSparseMatrix() {}
-
-BlockSparseMatrix::BlockSparseMatrix(
- CompressedRowBlockStructure* block_structure)
- : num_rows_(0),
- num_cols_(0),
- num_nonzeros_(0),
- values_(NULL),
- block_structure_(block_structure) {
- CHECK_NOTNULL(block_structure_.get());
-
- // Count the number of columns in the matrix.
- for (int i = 0; i < block_structure_->cols.size(); ++i) {
- num_cols_ += block_structure_->cols[i].size;
- }
-
- // Count the number of non-zero entries and the number of rows in
- // the matrix.
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_size = block_structure_->rows[i].block.size;
- num_rows_ += row_block_size;
-
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- num_nonzeros_ += col_block_size * row_block_size;
- }
- }
-
- CHECK_GE(num_rows_, 0);
- CHECK_GE(num_cols_, 0);
- CHECK_GE(num_nonzeros_, 0);
- VLOG(2) << "Allocating values array with "
- << num_nonzeros_ * sizeof(double) << " bytes."; // NOLINT
- values_.reset(new double[num_nonzeros_]);
- CHECK_NOTNULL(values_.get());
-}
-
-void BlockSparseMatrix::SetZero() {
- fill(values_.get(), values_.get() + num_nonzeros_, 0.0);
-}
-
-void BlockSparseMatrix::RightMultiply(const double* x, double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
-
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_pos = block_structure_->rows[i].block.position;
- int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- int col_block_pos = block_structure_->cols[col_block_id].position;
- MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- values_.get() + cells[j].position, row_block_size, col_block_size,
- x + col_block_pos,
- y + row_block_pos);
- }
- }
-}
-
-void BlockSparseMatrix::LeftMultiply(const double* x, double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
-
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_pos = block_structure_->rows[i].block.position;
- int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- int col_block_pos = block_structure_->cols[col_block_id].position;
- MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- values_.get() + cells[j].position, row_block_size, col_block_size,
- x + row_block_pos,
- y + col_block_pos);
- }
- }
-}
-
-void BlockSparseMatrix::SquaredColumnNorm(double* x) const {
- CHECK_NOTNULL(x);
- VectorRef(x, num_cols_).setZero();
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- int col_block_pos = block_structure_->cols[col_block_id].position;
- const MatrixRef m(values_.get() + cells[j].position,
- row_block_size, col_block_size);
- VectorRef(x + col_block_pos, col_block_size) += m.colwise().squaredNorm();
- }
- }
-}
-
-void BlockSparseMatrix::ScaleColumns(const double* scale) {
- CHECK_NOTNULL(scale);
-
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- int col_block_pos = block_structure_->cols[col_block_id].position;
- MatrixRef m(values_.get() + cells[j].position,
- row_block_size, col_block_size);
- m *= ConstVectorRef(scale + col_block_pos, col_block_size).asDiagonal();
- }
- }
-}
-
-void BlockSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- CHECK_NOTNULL(dense_matrix);
-
- dense_matrix->resize(num_rows_, num_cols_);
- dense_matrix->setZero();
- Matrix& m = *dense_matrix;
-
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_pos = block_structure_->rows[i].block.position;
- int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- int col_block_pos = block_structure_->cols[col_block_id].position;
- int jac_pos = cells[j].position;
- m.block(row_block_pos, col_block_pos, row_block_size, col_block_size)
- += MatrixRef(values_.get() + jac_pos, row_block_size, col_block_size);
- }
- }
-}
-
-void BlockSparseMatrix::ToTripletSparseMatrix(
- TripletSparseMatrix* matrix) const {
- CHECK_NOTNULL(matrix);
-
- matrix->Reserve(num_nonzeros_);
- matrix->Resize(num_rows_, num_cols_);
- matrix->SetZero();
-
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- int row_block_pos = block_structure_->rows[i].block.position;
- int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- int col_block_id = cells[j].block_id;
- int col_block_size = block_structure_->cols[col_block_id].size;
- int col_block_pos = block_structure_->cols[col_block_id].position;
- int jac_pos = cells[j].position;
- for (int r = 0; r < row_block_size; ++r) {
- for (int c = 0; c < col_block_size; ++c, ++jac_pos) {
- matrix->mutable_rows()[jac_pos] = row_block_pos + r;
- matrix->mutable_cols()[jac_pos] = col_block_pos + c;
- matrix->mutable_values()[jac_pos] = values_[jac_pos];
- }
- }
- }
- }
- matrix->set_num_nonzeros(num_nonzeros_);
-}
-
-// Return a pointer to the block structure. We continue to hold
-// ownership of the object though.
-const CompressedRowBlockStructure* BlockSparseMatrix::block_structure()
- const {
- return block_structure_.get();
-}
-
-void BlockSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
- for (int i = 0; i < block_structure_->rows.size(); ++i) {
- const int row_block_pos = block_structure_->rows[i].block.position;
- const int row_block_size = block_structure_->rows[i].block.size;
- const vector<Cell>& cells = block_structure_->rows[i].cells;
- for (int j = 0; j < cells.size(); ++j) {
- const int col_block_id = cells[j].block_id;
- const int col_block_size = block_structure_->cols[col_block_id].size;
- const int col_block_pos = block_structure_->cols[col_block_id].position;
- int jac_pos = cells[j].position;
- for (int r = 0; r < row_block_size; ++r) {
- for (int c = 0; c < col_block_size; ++c) {
- fprintf(file, "% 10d % 10d %17f\n",
- row_block_pos + r,
- col_block_pos + c,
- values_[jac_pos++]);
- }
- }
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h
deleted file mode 100644
index e17d12a706e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_sparse_matrix.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Implementation of the SparseMatrix interface for block sparse
-// matrices.
-
-#ifndef CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
-
-#include "ceres/block_structure.h"
-#include "ceres/sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-namespace internal {
-
-class TripletSparseMatrix;
-
-// This class implements the SparseMatrix interface for storing and
-// manipulating block sparse matrices. The block structure is stored
-// in the CompressedRowBlockStructure object and one is needed to
-// initialize the matrix. For details on how the blocks structure of
-// the matrix is stored please see the documentation
-//
-// internal/ceres/block_structure.h
-//
-class BlockSparseMatrix : public SparseMatrix {
- public:
- // Construct a block sparse matrix with a fully initialized
- // CompressedRowBlockStructure objected. The matrix takes over
- // ownership of this object and destroys it upon destruction.
- //
- // TODO(sameeragarwal): Add a function which will validate legal
- // CompressedRowBlockStructure objects.
- explicit BlockSparseMatrix(CompressedRowBlockStructure* block_structure);
-
- BlockSparseMatrix();
- virtual ~BlockSparseMatrix();
-
- // Implementation of SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
-
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_cols_; }
- virtual int num_nonzeros() const { return num_nonzeros_; }
- virtual const double* values() const { return values_.get(); }
- virtual double* mutable_values() { return values_.get(); }
-
- void ToTripletSparseMatrix(TripletSparseMatrix* matrix) const;
- const CompressedRowBlockStructure* block_structure() const;
-
- private:
- int num_rows_;
- int num_cols_;
- int max_num_nonzeros_;
- int num_nonzeros_;
- scoped_array<double> values_;
- scoped_ptr<CompressedRowBlockStructure> block_structure_;
- CERES_DISALLOW_COPY_AND_ASSIGN(BlockSparseMatrix);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc b/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc
deleted file mode 100644
index 00c4ce2814b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_structure.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/block_structure.h"
-
-namespace ceres {
-namespace internal {
-
-bool CellLessThan(const Cell& lhs, const Cell& rhs) {
- if (lhs.block_id == rhs.block_id) {
- return (lhs.position < rhs.position);
- }
- return (lhs.block_id < rhs.block_id);
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/block_structure.h b/extern/libmv/third_party/ceres/internal/ceres/block_structure.h
deleted file mode 100644
index 656716ef022..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/block_structure.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Block structure objects are used to carry information about the
-// dense block structure of sparse matrices. The BlockSparseMatrix
-// object uses the BlockStructure objects to keep track of the matrix
-// structure and operate upon it. This allows us to use more cache
-// friendly block oriented linear algebra operations on the matrix
-// instead of accessing it one scalar entry at a time.
-
-#ifndef CERES_INTERNAL_BLOCK_STRUCTURE_H_
-#define CERES_INTERNAL_BLOCK_STRUCTURE_H_
-
-#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-typedef int32 BlockSize;
-
-struct Block {
- Block() : size(-1), position(-1) {}
- Block(int size_, int position_) : size(size_), position(position_) {}
-
- BlockSize size;
- int position; // Position along the row/column.
-};
-
-struct Cell {
- Cell() : block_id(-1), position(-1) {}
- Cell(int block_id_, int position_)
- : block_id(block_id_), position(position_) {}
-
- // Column or row block id as the case maybe.
- int block_id;
- // Where in the values array of the jacobian is this cell located.
- int position;
-};
-
-// Order cell by their block_id;
-bool CellLessThan(const Cell& lhs, const Cell& rhs);
-
-struct CompressedList {
- Block block;
- vector<Cell> cells;
-};
-
-typedef CompressedList CompressedRow;
-typedef CompressedList CompressedColumn;
-
-struct CompressedRowBlockStructure {
- vector<Block> cols;
- vector<CompressedRow> rows;
-};
-
-struct CompressedColumnBlockStructure {
- vector<Block> rows;
- vector<CompressedColumn> cols;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_BLOCK_STRUCTURE_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/c_api.cc b/extern/libmv/third_party/ceres/internal/ceres/c_api.cc
deleted file mode 100644
index 1fd01c9f0bd..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/c_api.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: mierle@gmail.com (Keir Mierle)
-//
-// An incomplete C API for Ceres.
-//
-// TODO(keir): Figure out why logging does not seem to work.
-
-#include "ceres/c_api.h"
-
-#include <vector>
-#include <iostream>
-#include <string>
-#include "ceres/cost_function.h"
-#include "ceres/loss_function.h"
-#include "ceres/problem.h"
-#include "ceres/solver.h"
-#include "ceres/types.h" // for std
-#include "glog/logging.h"
-
-using ceres::Problem;
-
-void ceres_init() {
- // This is not ideal, but it's not clear what to do if there is no gflags and
- // no access to command line arguments.
- char message[] = "<unknown>";
- google::InitGoogleLogging(message);
-}
-
-ceres_problem_t* ceres_create_problem() {
- return reinterpret_cast<ceres_problem_t*>(new Problem);
-}
-
-void ceres_free_problem(ceres_problem_t* problem) {
- delete reinterpret_cast<Problem*>(problem);
-}
-
-// This cost function wraps a C-level function pointer from the user, to bridge
-// between C and C++.
-class CallbackCostFunction : public ceres::CostFunction {
- public:
- CallbackCostFunction(ceres_cost_function_t cost_function,
- void* user_data,
- int num_residuals,
- int num_parameter_blocks,
- int* parameter_block_sizes)
- : cost_function_(cost_function),
- user_data_(user_data) {
- set_num_residuals(num_residuals);
- for (int i = 0; i < num_parameter_blocks; ++i) {
- mutable_parameter_block_sizes()->push_back(parameter_block_sizes[i]);
- }
- }
-
- virtual ~CallbackCostFunction() {}
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- return (*cost_function_)(user_data_,
- const_cast<double**>(parameters),
- residuals,
- jacobians);
- }
-
- private:
- ceres_cost_function_t cost_function_;
- void* user_data_;
-};
-
-// This loss function wraps a C-level function pointer from the user, to bridge
-// between C and C++.
-class CallbackLossFunction : public ceres::LossFunction {
- public:
- explicit CallbackLossFunction(ceres_loss_function_t loss_function,
- void* user_data)
- : loss_function_(loss_function), user_data_(user_data) {}
- virtual void Evaluate(double sq_norm, double* rho) const {
- (*loss_function_)(user_data_, sq_norm, rho);
- }
-
- private:
- ceres_loss_function_t loss_function_;
- void* user_data_;
-};
-
-// Wrappers for the stock loss functions.
-void* ceres_create_huber_loss_function_data(double a) {
- return new ceres::HuberLoss(a);
-}
-void* ceres_create_softl1_loss_function_data(double a) {
- return new ceres::SoftLOneLoss(a);
-}
-void* ceres_create_cauchy_loss_function_data(double a) {
- return new ceres::CauchyLoss(a);
-}
-void* ceres_create_arctan_loss_function_data(double a) {
- return new ceres::ArctanLoss(a);
-}
-void* ceres_create_tolerant_loss_function_data(double a, double b) {
- return new ceres::TolerantLoss(a, b);
-}
-
-void ceres_free_stock_loss_function_data(void* loss_function_data) {
- delete reinterpret_cast<ceres::LossFunction*>(loss_function_data);
-}
-
-void ceres_stock_loss_function(void* user_data,
- double squared_norm,
- double out[3]) {
- reinterpret_cast<ceres::LossFunction*>(user_data)
- ->Evaluate(squared_norm, out);
-}
-
-ceres_residual_block_id_t* ceres_problem_add_residual_block(
- ceres_problem_t* problem,
- ceres_cost_function_t cost_function,
- void* cost_function_data,
- ceres_loss_function_t loss_function,
- void* loss_function_data,
- int num_residuals,
- int num_parameter_blocks,
- int* parameter_block_sizes,
- double** parameters) {
- Problem* ceres_problem = reinterpret_cast<Problem*>(problem);
-
- ceres::CostFunction* callback_cost_function =
- new CallbackCostFunction(cost_function,
- cost_function_data,
- num_residuals,
- num_parameter_blocks,
- parameter_block_sizes);
-
- ceres::LossFunction* callback_loss_function = NULL;
- if (loss_function != NULL) {
- callback_loss_function = new CallbackLossFunction(loss_function,
- loss_function_data);
- }
-
- std::vector<double*> parameter_blocks(parameters,
- parameters + num_parameter_blocks);
- return reinterpret_cast<ceres_residual_block_id_t*>(
- ceres_problem->AddResidualBlock(callback_cost_function,
- callback_loss_function,
- parameter_blocks));
-}
-
-void ceres_solve(ceres_problem_t* c_problem) {
- Problem* problem = reinterpret_cast<Problem*>(c_problem);
-
- // TODO(keir): Obviously, this way of setting options won't scale or last.
- // Instead, figure out a way to specify some of the options without
- // duplicating everything.
- ceres::Solver::Options options;
- options.max_num_iterations = 100;
- options.linear_solver_type = ceres::DENSE_QR;
- options.minimizer_progress_to_stdout = true;
-
- ceres::Solver::Summary summary;
- ceres::Solve(options, problem, &summary);
- std::cout << summary.FullReport() << "\n";
-}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/callbacks.cc b/extern/libmv/third_party/ceres/internal/ceres/callbacks.cc
deleted file mode 100644
index 7d5ce2548e4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/callbacks.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include <iostream> // NO LINT
-#include "ceres/callbacks.h"
-#include "ceres/program.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-StateUpdatingCallback::StateUpdatingCallback(Program* program,
- double* parameters)
- : program_(program), parameters_(parameters) {}
-
-StateUpdatingCallback::~StateUpdatingCallback() {}
-
-CallbackReturnType StateUpdatingCallback::operator()(
- const IterationSummary& summary) {
- if (summary.step_is_successful) {
- program_->StateVectorToParameterBlocks(parameters_);
- program_->CopyParameterBlockStateToUserState();
- }
- return SOLVER_CONTINUE;
-}
-
-LoggingCallback::LoggingCallback(const MinimizerType minimizer_type,
- const bool log_to_stdout)
- : minimizer_type(minimizer_type),
- log_to_stdout_(log_to_stdout) {}
-
-LoggingCallback::~LoggingCallback() {}
-
-CallbackReturnType LoggingCallback::operator()(
- const IterationSummary& summary) {
- string output;
- if (minimizer_type == LINE_SEARCH) {
- const char* kReportRowFormat =
- "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
- "s:% 3.2e e:% 3d it:% 3.2e tt:% 3.2e";
- output = StringPrintf(kReportRowFormat,
- summary.iteration,
- summary.cost,
- summary.cost_change,
- summary.gradient_max_norm,
- summary.step_norm,
- summary.step_size,
- summary.line_search_function_evaluations,
- summary.iteration_time_in_seconds,
- summary.cumulative_time_in_seconds);
- } else if (minimizer_type == TRUST_REGION) {
- if (summary.iteration == 0) {
- output = "iter cost cost_change |gradient| |step| tr_ratio tr_radius ls_iter iter_time total_time\n";
- }
- const char* kReportRowFormat =
- "% 4d % 8e % 3.2e % 3.2e % 3.2e % 3.2e % 3.2e % 4d % 3.2e % 3.2e";
- output += StringPrintf(kReportRowFormat,
- summary.iteration,
- summary.cost,
- summary.cost_change,
- summary.gradient_max_norm,
- summary.step_norm,
- summary.relative_decrease,
- summary.trust_region_radius,
- summary.linear_solver_iterations,
- summary.iteration_time_in_seconds,
- summary.cumulative_time_in_seconds);
- } else {
- LOG(FATAL) << "Unknown minimizer type.";
- }
-
- if (log_to_stdout_) {
- cout << output << endl;
- } else {
- VLOG(1) << output;
- }
- return SOLVER_CONTINUE;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/callbacks.h b/extern/libmv/third_party/ceres/internal/ceres/callbacks.h
deleted file mode 100644
index 93704dfd6d1..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/callbacks.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_CALLBACKS_H_
-#define CERES_INTERNAL_CALLBACKS_H_
-
-#include <string>
-#include "ceres/iteration_callback.h"
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-class Program;
-
-// Callback for updating the externally visible state of parameter
-// blocks.
-class StateUpdatingCallback : public IterationCallback {
- public:
- StateUpdatingCallback(Program* program, double* parameters);
- virtual ~StateUpdatingCallback();
- virtual CallbackReturnType operator()(const IterationSummary& summary);
- private:
- Program* program_;
- double* parameters_;
-};
-
-// Callback for logging the state of the minimizer to STDERR or
-// STDOUT depending on the user's preferences and logging level.
-class LoggingCallback : public IterationCallback {
- public:
- LoggingCallback(MinimizerType minimizer_type, bool log_to_stdout);
- virtual ~LoggingCallback();
- virtual CallbackReturnType operator()(const IterationSummary& summary);
-
- private:
- const MinimizerType minimizer_type;
- const bool log_to_stdout_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_CALLBACKS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc
deleted file mode 100644
index 9bbab4b2377..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: David Gallup (dgallup@google.com)
-// Sameer Agarwal (sameeragarwal@google.com)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include "ceres/canonical_views_clustering.h"
-
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-#include "ceres/internal/macros.h"
-#include "ceres/map_util.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-typedef HashMap<int, int> IntMap;
-typedef HashSet<int> IntSet;
-
-class CanonicalViewsClustering {
- public:
- CanonicalViewsClustering() {}
-
- // Compute the canonical views clustering of the vertices of the
- // graph. centers will contain the vertices that are the identified
- // as the canonical views/cluster centers, and membership is a map
- // from vertices to cluster_ids. The i^th cluster center corresponds
- // to the i^th cluster. It is possible depending on the
- // configuration of the clustering algorithm that some of the
- // vertices may not be assigned to any cluster. In this case they
- // are assigned to a cluster with id = kInvalidClusterId.
- void ComputeClustering(const CanonicalViewsClusteringOptions& options,
- const WeightedGraph<int>& graph,
- vector<int>* centers,
- IntMap* membership);
-
- private:
- void FindValidViews(IntSet* valid_views) const;
- double ComputeClusteringQualityDifference(const int candidate,
- const vector<int>& centers) const;
- void UpdateCanonicalViewAssignments(const int canonical_view);
- void ComputeClusterMembership(const vector<int>& centers,
- IntMap* membership) const;
-
- CanonicalViewsClusteringOptions options_;
- const WeightedGraph<int>* graph_;
- // Maps a view to its representative canonical view (its cluster
- // center).
- IntMap view_to_canonical_view_;
- // Maps a view to its similarity to its current cluster center.
- HashMap<int, double> view_to_canonical_view_similarity_;
- CERES_DISALLOW_COPY_AND_ASSIGN(CanonicalViewsClustering);
-};
-
-void ComputeCanonicalViewsClustering(
- const CanonicalViewsClusteringOptions& options,
- const WeightedGraph<int>& graph,
- vector<int>* centers,
- IntMap* membership) {
- time_t start_time = time(NULL);
- CanonicalViewsClustering cv;
- cv.ComputeClustering(options, graph, centers, membership);
- VLOG(2) << "Canonical views clustering time (secs): "
- << time(NULL) - start_time;
-}
-
-// Implementation of CanonicalViewsClustering
-void CanonicalViewsClustering::ComputeClustering(
- const CanonicalViewsClusteringOptions& options,
- const WeightedGraph<int>& graph,
- vector<int>* centers,
- IntMap* membership) {
- options_ = options;
- CHECK_NOTNULL(centers)->clear();
- CHECK_NOTNULL(membership)->clear();
- graph_ = &graph;
-
- IntSet valid_views;
- FindValidViews(&valid_views);
- while (valid_views.size() > 0) {
- // Find the next best canonical view.
- double best_difference = -std::numeric_limits<double>::max();
- int best_view = 0;
-
- // TODO(sameeragarwal): Make this loop multi-threaded.
- for (IntSet::const_iterator view = valid_views.begin();
- view != valid_views.end();
- ++view) {
- const double difference =
- ComputeClusteringQualityDifference(*view, *centers);
- if (difference > best_difference) {
- best_difference = difference;
- best_view = *view;
- }
- }
-
- CHECK_GT(best_difference, -std::numeric_limits<double>::max());
-
- // Add canonical view if quality improves, or if minimum is not
- // yet met, otherwise break.
- if ((best_difference <= 0) &&
- (centers->size() >= options_.min_views)) {
- break;
- }
-
- centers->push_back(best_view);
- valid_views.erase(best_view);
- UpdateCanonicalViewAssignments(best_view);
- }
-
- ComputeClusterMembership(*centers, membership);
-}
-
-// Return the set of vertices of the graph which have valid vertex
-// weights.
-void CanonicalViewsClustering::FindValidViews(
- IntSet* valid_views) const {
- const IntSet& views = graph_->vertices();
- for (IntSet::const_iterator view = views.begin();
- view != views.end();
- ++view) {
- if (graph_->VertexWeight(*view) != WeightedGraph<int>::InvalidWeight()) {
- valid_views->insert(*view);
- }
- }
-}
-
-// Computes the difference in the quality score if 'candidate' were
-// added to the set of canonical views.
-double CanonicalViewsClustering::ComputeClusteringQualityDifference(
- const int candidate,
- const vector<int>& centers) const {
- // View score.
- double difference =
- options_.view_score_weight * graph_->VertexWeight(candidate);
-
- // Compute how much the quality score changes if the candidate view
- // was added to the list of canonical views and its nearest
- // neighbors became members of its cluster.
- const IntSet& neighbors = graph_->Neighbors(candidate);
- for (IntSet::const_iterator neighbor = neighbors.begin();
- neighbor != neighbors.end();
- ++neighbor) {
- const double old_similarity =
- FindWithDefault(view_to_canonical_view_similarity_, *neighbor, 0.0);
- const double new_similarity = graph_->EdgeWeight(*neighbor, candidate);
- if (new_similarity > old_similarity) {
- difference += new_similarity - old_similarity;
- }
- }
-
- // Number of views penalty.
- difference -= options_.size_penalty_weight;
-
- // Orthogonality.
- for (int i = 0; i < centers.size(); ++i) {
- difference -= options_.similarity_penalty_weight *
- graph_->EdgeWeight(centers[i], candidate);
- }
-
- return difference;
-}
-
-// Reassign views if they're more similar to the new canonical view.
-void CanonicalViewsClustering::UpdateCanonicalViewAssignments(
- const int canonical_view) {
- const IntSet& neighbors = graph_->Neighbors(canonical_view);
- for (IntSet::const_iterator neighbor = neighbors.begin();
- neighbor != neighbors.end();
- ++neighbor) {
- const double old_similarity =
- FindWithDefault(view_to_canonical_view_similarity_, *neighbor, 0.0);
- const double new_similarity =
- graph_->EdgeWeight(*neighbor, canonical_view);
- if (new_similarity > old_similarity) {
- view_to_canonical_view_[*neighbor] = canonical_view;
- view_to_canonical_view_similarity_[*neighbor] = new_similarity;
- }
- }
-}
-
-// Assign a cluster id to each view.
-void CanonicalViewsClustering::ComputeClusterMembership(
- const vector<int>& centers,
- IntMap* membership) const {
- CHECK_NOTNULL(membership)->clear();
-
- // The i^th cluster has cluster id i.
- IntMap center_to_cluster_id;
- for (int i = 0; i < centers.size(); ++i) {
- center_to_cluster_id[centers[i]] = i;
- }
-
- static const int kInvalidClusterId = -1;
-
- const IntSet& views = graph_->vertices();
- for (IntSet::const_iterator view = views.begin();
- view != views.end();
- ++view) {
- IntMap::const_iterator it =
- view_to_canonical_view_.find(*view);
- int cluster_id = kInvalidClusterId;
- if (it != view_to_canonical_view_.end()) {
- cluster_id = FindOrDie(center_to_cluster_id, it->second);
- }
-
- InsertOrDie(membership, *view, cluster_id);
- }
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
diff --git a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
deleted file mode 100644
index d3fa5725831..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// An implementation of the Canonical Views clustering algorithm from
-// "Scene Summarization for Online Image Collections", Ian Simon, Noah
-// Snavely, Steven M. Seitz, ICCV 2007.
-//
-// More details can be found at
-// http://grail.cs.washington.edu/projects/canonview/
-//
-// Ceres uses this algorithm to perform view clustering for
-// constructing visibility based preconditioners.
-
-#ifndef CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
-#define CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include <vector>
-
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-
-namespace ceres {
-namespace internal {
-
-struct CanonicalViewsClusteringOptions;
-
-// Compute a partitioning of the vertices of the graph using the
-// canonical views clustering algorithm.
-//
-// In the following we will use the terms vertices and views
-// interchangably. Given a weighted Graph G(V,E), the canonical views
-// of G are the the set of vertices that best "summarize" the content
-// of the graph. If w_ij i s the weight connecting the vertex i to
-// vertex j, and C is the set of canonical views. Then the objective
-// of the canonical views algorithm is
-//
-// E[C] = sum_[i in V] max_[j in C] w_ij
-// - size_penalty_weight * |C|
-// - similarity_penalty_weight * sum_[i in C, j in C, j > i] w_ij
-//
-// alpha is the size penalty that penalizes large number of canonical
-// views.
-//
-// beta is the similarity penalty that penalizes canonical views that
-// are too similar to other canonical views.
-//
-// Thus the canonical views algorithm tries to find a canonical view
-// for each vertex in the graph which best explains it, while trying
-// to minimize the number of canonical views and the overlap between
-// them.
-//
-// We further augment the above objective function by allowing for per
-// vertex weights, higher weights indicating a higher preference for
-// being chosen as a canonical view. Thus if w_i is the vertex weight
-// for vertex i, the objective function is then
-//
-// E[C] = sum_[i in V] max_[j in C] w_ij
-// - size_penalty_weight * |C|
-// - similarity_penalty_weight * sum_[i in C, j in C, j > i] w_ij
-// + view_score_weight * sum_[i in C] w_i
-//
-// centers will contain the vertices that are the identified
-// as the canonical views/cluster centers, and membership is a map
-// from vertices to cluster_ids. The i^th cluster center corresponds
-// to the i^th cluster.
-//
-// It is possible depending on the configuration of the clustering
-// algorithm that some of the vertices may not be assigned to any
-// cluster. In this case they are assigned to a cluster with id = -1;
-void ComputeCanonicalViewsClustering(
- const CanonicalViewsClusteringOptions& options,
- const WeightedGraph<int>& graph,
- vector<int>* centers,
- HashMap<int, int>* membership);
-
-struct CanonicalViewsClusteringOptions {
- CanonicalViewsClusteringOptions()
- : min_views(3),
- size_penalty_weight(5.75),
- similarity_penalty_weight(100.0),
- view_score_weight(0.0) {
- }
- // The minimum number of canonical views to compute.
- int min_views;
-
- // Penalty weight for the number of canonical views. A higher
- // number will result in fewer canonical views.
- double size_penalty_weight;
-
- // Penalty weight for the diversity (orthogonality) of the
- // canonical views. A higher number will encourage less similar
- // canonical views.
- double similarity_penalty_weight;
-
- // Weight for per-view scores. Lower weight places less
- // confidence in the view scores.
- double view_score_weight;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
-#endif // CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/casts.h b/extern/libmv/third_party/ceres/internal/ceres/casts.h
deleted file mode 100644
index 99cf2186cc7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/casts.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_CASTS_H_
-#define CERES_INTERNAL_CASTS_H_
-
-#include <cassert>
-#include <cstddef> // For NULL.
-
-namespace ceres {
-
-// Identity metafunction.
-template <class T>
-struct identity_ {
- typedef T type;
-};
-
-// Use implicit_cast as a safe version of static_cast or const_cast
-// for implicit conversions. For example:
-// - Upcasting in a type hierarchy.
-// - Performing arithmetic conversions (int32 to int64, int to double, etc.).
-// - Adding const or volatile qualifiers.
-//
-// In general, implicit_cast can be used to convert this code
-// To to = from;
-// DoSomething(to);
-// to this
-// DoSomething(implicit_cast<To>(from));
-//
-// base::identity_ is used to make a non-deduced context, which
-// forces all callers to explicitly specify the template argument.
-template<typename To>
-inline To implicit_cast(typename identity_<To>::type to) {
- return to;
-}
-
-// This version of implicit_cast is used when two template arguments
-// are specified. It's obsolete and should not be used.
-template<typename To, typename From>
-inline To implicit_cast(typename identity_<From>::type const &f) {
- return f;
-}
-
-// When you upcast (that is, cast a pointer from type Foo to type
-// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
-// always succeed. When you downcast (that is, cast a pointer from
-// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
-// how do you know the pointer is really of type SubclassOfFoo? It
-// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
-// when you downcast, you should use this macro. In debug mode, we
-// use dynamic_cast<> to double-check the downcast is legal (we die
-// if it's not). In normal mode, we do the efficient static_cast<>
-// instead. Thus, it's important to test in debug mode to make sure
-// the cast is legal!
-// This is the only place in the code we should use dynamic_cast<>.
-// In particular, you SHOULDN'T be using dynamic_cast<> in order to
-// do RTTI (eg code like this:
-// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
-// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
-// You should design the code some other way not to need this.
-
-template<typename To, typename From> // use like this: down_cast<T*>(foo);
-inline To down_cast(From* f) { // so we only accept pointers
- // Ensures that To is a sub-type of From *. This test is here only
- // for compile-time type checking, and has no overhead in an
- // optimized build at run-time, as it will be optimized away
- // completely.
-
- // TODO(csilvers): This should use COMPILE_ASSERT.
- if (false) {
- implicit_cast<From*, To>(NULL);
- }
-
- // uses RTTI in dbg and fastbuild. asserts are disabled in opt builds.
- assert(f == NULL || dynamic_cast<To>(f) != NULL); // NOLINT
- return static_cast<To>(f);
-}
-
-} // namespace ceres
-
-#endif // CERES_INTERNAL_CASTS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_linear_operator.h b/extern/libmv/third_party/ceres/internal/ceres/cgnr_linear_operator.h
deleted file mode 100644
index f32d8d95c19..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_linear_operator.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
-#define CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
-
-#include <algorithm>
-#include "ceres/linear_operator.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-class SparseMatrix;
-
-// A linear operator which takes a matrix A and a diagonal vector D and
-// performs products of the form
-//
-// (A^T A + D^T D)x
-//
-// This is used to implement iterative general sparse linear solving with
-// conjugate gradients, where A is the Jacobian and D is a regularizing
-// parameter. A brief proof that D^T D is the correct regularizer:
-//
-// Given a regularized least squares problem:
-//
-// min ||Ax - b||^2 + ||Dx||^2
-// x
-//
-// First expand into matrix notation:
-//
-// (Ax - b)^T (Ax - b) + xD^TDx
-//
-// Then multiply out to get:
-//
-// = xA^TAx - 2b^T Ax + b^Tb + xD^TDx
-//
-// Take the derivative:
-//
-// 0 = 2A^TAx - 2A^T b + 2 D^TDx
-// 0 = A^TAx - A^T b + D^TDx
-// 0 = (A^TA + D^TD)x - A^T b
-//
-// Thus, the symmetric system we need to solve for CGNR is
-//
-// Sx = z
-//
-// with S = A^TA + D^TD
-// and z = A^T b
-//
-// Note: This class is not thread safe, since it uses some temporary storage.
-class CgnrLinearOperator : public LinearOperator {
- public:
- CgnrLinearOperator(const LinearOperator& A, const double *D)
- : A_(A), D_(D), z_(new double[A.num_rows()]) {
- }
- virtual ~CgnrLinearOperator() {}
-
- virtual void RightMultiply(const double* x, double* y) const {
- std::fill(z_.get(), z_.get() + A_.num_rows(), 0.0);
-
- // z = Ax
- A_.RightMultiply(x, z_.get());
-
- // y = y + Atz
- A_.LeftMultiply(z_.get(), y);
-
- // y = y + DtDx
- if (D_ != NULL) {
- int n = A_.num_cols();
- VectorRef(y, n).array() += ConstVectorRef(D_, n).array().square() *
- ConstVectorRef(x, n).array();
- }
- }
-
- virtual void LeftMultiply(const double* x, double* y) const {
- RightMultiply(x, y);
- }
-
- virtual int num_rows() const { return A_.num_cols(); }
- virtual int num_cols() const { return A_.num_cols(); }
-
- private:
- const LinearOperator& A_;
- const double* D_;
- scoped_array<double> z_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
deleted file mode 100644
index 88e61d9ed1b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/cgnr_solver.h"
-
-#include "ceres/block_jacobi_preconditioner.h"
-#include "ceres/cgnr_linear_operator.h"
-#include "ceres/conjugate_gradients_solver.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_solver.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-CgnrSolver::CgnrSolver(const LinearSolver::Options& options)
- : options_(options),
- preconditioner_(NULL) {
- if (options_.preconditioner_type != JACOBI &&
- options_.preconditioner_type != IDENTITY) {
- LOG(FATAL) << "CGNR only supports IDENTITY and JACOBI preconditioners.";
- }
-}
-
-LinearSolver::Summary CgnrSolver::SolveImpl(
- BlockSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("CgnrSolver::Solve");
-
- // Form z = Atb.
- Vector z(A->num_cols());
- z.setZero();
- A->LeftMultiply(b, z.data());
-
- // Precondition if necessary.
- LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
- if (options_.preconditioner_type == JACOBI) {
- if (preconditioner_.get() == NULL) {
- preconditioner_.reset(new BlockJacobiPreconditioner(*A));
- }
- preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner = preconditioner_.get();
- }
-
- // Solve (AtA + DtD)x = z (= Atb).
- VectorRef(x, A->num_cols()).setZero();
- CgnrLinearOperator lhs(*A, per_solve_options.D);
- event_logger.AddEvent("Setup");
-
- ConjugateGradientsSolver conjugate_gradient_solver(options_);
- LinearSolver::Summary summary =
- conjugate_gradient_solver.Solve(&lhs, z.data(), cg_per_solve_options, x);
- event_logger.AddEvent("Solve");
- return summary;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
deleted file mode 100644
index c63484c628b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_CGNR_SOLVER_H_
-#define CERES_INTERNAL_CGNR_SOLVER_H_
-
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-
-namespace ceres {
-namespace internal {
-
-class Preconditioner;
-
-class BlockJacobiPreconditioner;
-
-// A conjugate gradients on the normal equations solver. This directly solves
-// for the solution to
-//
-// (A^T A + D^T D)x = A^T b
-//
-// as required for solving for x in the least squares sense. Currently only
-// block diagonal preconditioning is supported.
-class CgnrSolver : public BlockSparseMatrixSolver {
- public:
- explicit CgnrSolver(const LinearSolver::Options& options);
- virtual Summary SolveImpl(
- BlockSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- private:
- const LinearSolver::Options options_;
- scoped_ptr<Preconditioner> preconditioner_;
- CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_CGNR_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
deleted file mode 100644
index 3f976b9fb59..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Portable HashMap and HashSet, and a specialized overload for hashing pairs.
-
-#ifndef CERES_INTERNAL_COLLECTIONS_PORT_H_
-#define CERES_INTERNAL_COLLECTIONS_PORT_H_
-
-#include "ceres/internal/port.h"
-
-#if defined(CERES_NO_UNORDERED_MAP)
-# include <map>
-# include <set>
-#endif
-
-#if defined(CERES_TR1_UNORDERED_MAP)
-# include <tr1/unordered_map>
-# include <tr1/unordered_set>
-# define CERES_HASH_NAMESPACE_START namespace std { namespace tr1 {
-# define CERES_HASH_NAMESPACE_END } }
-#endif
-
-#if defined(CERES_STD_UNORDERED_MAP)
-# include <unordered_map>
-# include <unordered_set>
-# define CERES_HASH_NAMESPACE_START namespace std {
-# define CERES_HASH_NAMESPACE_END }
-#endif
-
-#if defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-# include <unordered_map>
-# include <unordered_set>
-# define CERES_HASH_NAMESPACE_START namespace std { namespace tr1 {
-# define CERES_HASH_NAMESPACE_END } }
-#endif
-
-#if !defined(CERES_NO_UNORDERED_MAP) && !defined(CERES_TR1_UNORDERED_MAP) && \
- !defined(CERES_STD_UNORDERED_MAP) && !defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
-# error One of: CERES_NO_UNORDERED_MAP, CERES_TR1_UNORDERED_MAP,\
- CERES_STD_UNORDERED_MAP, CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
-#endif
-
-#include <utility>
-#include "ceres/integral_types.h"
-#include "ceres/internal/port.h"
-
-// Some systems don't have access to unordered_map/unordered_set. In
-// that case, substitute the hash map/set with normal map/set. The
-// price to pay is slower speed for some operations.
-#if defined(CERES_NO_UNORDERED_MAP)
-
-namespace ceres {
-namespace internal {
-
-template<typename K, typename V>
-struct HashMap : map<K, V> {};
-
-template<typename K>
-struct HashSet : set<K> {};
-
-} // namespace internal
-} // namespace ceres
-
-#else
-
-namespace ceres {
-namespace internal {
-
-#if defined(CERES_TR1_UNORDERED_MAP) || \
- defined(CERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
-template<typename K, typename V>
-struct HashMap : std::tr1::unordered_map<K, V> {};
-template<typename K>
-struct HashSet : std::tr1::unordered_set<K> {};
-#endif
-
-#if defined(CERES_STD_UNORDERED_MAP)
-template<typename K, typename V>
-struct HashMap : std::unordered_map<K, V> {};
-template<typename K>
-struct HashSet : std::unordered_set<K> {};
-#endif
-
-#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
-#define GG_LONGLONG(x) x##I64
-#define GG_ULONGLONG(x) x##UI64
-#else
-#define GG_LONGLONG(x) x##LL
-#define GG_ULONGLONG(x) x##ULL
-#endif
-
-// The hash function is due to Bob Jenkins (see
-// http://burtleburtle.net/bob/hash/index.html). Each mix takes 36 instructions,
-// in 18 cycles if you're lucky. On x86 architectures, this requires 45
-// instructions in 27 cycles, if you're lucky.
-//
-// 32bit version
-inline void hash_mix(uint32& a, uint32& b, uint32& c) {
- a -= b; a -= c; a ^= (c>>13);
- b -= c; b -= a; b ^= (a<<8);
- c -= a; c -= b; c ^= (b>>13);
- a -= b; a -= c; a ^= (c>>12);
- b -= c; b -= a; b ^= (a<<16);
- c -= a; c -= b; c ^= (b>>5);
- a -= b; a -= c; a ^= (c>>3);
- b -= c; b -= a; b ^= (a<<10);
- c -= a; c -= b; c ^= (b>>15);
-}
-
-// 64bit version
-inline void hash_mix(uint64& a, uint64& b, uint64& c) {
- a -= b; a -= c; a ^= (c>>43);
- b -= c; b -= a; b ^= (a<<9);
- c -= a; c -= b; c ^= (b>>8);
- a -= b; a -= c; a ^= (c>>38);
- b -= c; b -= a; b ^= (a<<23);
- c -= a; c -= b; c ^= (b>>5);
- a -= b; a -= c; a ^= (c>>35);
- b -= c; b -= a; b ^= (a<<49);
- c -= a; c -= b; c ^= (b>>11);
-}
-
-inline uint32 Hash32NumWithSeed(uint32 num, uint32 c) {
- // The golden ratio; an arbitrary value.
- uint32 b = 0x9e3779b9UL;
- hash_mix(num, b, c);
- return c;
-}
-
-inline uint64 Hash64NumWithSeed(uint64 num, uint64 c) {
- // More of the golden ratio.
- uint64 b = GG_ULONGLONG(0xe08c1d668b756f82);
- hash_mix(num, b, c);
- return c;
-}
-
-} // namespace internal
-} // namespace ceres
-
-// Since on some platforms this is a doubly-nested namespace (std::tr1) and
-// others it is not, the entire namespace line must be in a macro.
-CERES_HASH_NAMESPACE_START
-
-// The outrageously annoying specializations below are for portability reasons.
-// In short, it's not possible to have two overloads of hash<pair<T1, T2>
-
-// Hasher for STL pairs. Requires hashers for both members to be defined.
-template<typename T>
-struct hash<pair<T, T> > {
- size_t operator()(const pair<T, T>& p) const {
- size_t h1 = hash<T>()(p.first);
- size_t h2 = hash<T>()(p.second);
- // The decision below is at compile time
- return (sizeof(h1) <= sizeof(ceres::internal::uint32)) ?
- ceres::internal::Hash32NumWithSeed(h1, h2) :
- ceres::internal::Hash64NumWithSeed(h1, h2);
- }
- // Less than operator for MSVC.
- bool operator()(const pair<T, T>& a,
- const pair<T, T>& b) const {
- return a < b;
- }
- static const size_t bucket_size = 4; // These are required by MSVC
- static const size_t min_buckets = 8; // 4 and 8 are defaults.
-};
-
-CERES_HASH_NAMESPACE_END
-
-#endif // CERES_NO_UNORDERED_MAP
-#endif // CERES_INTERNAL_COLLECTIONS_PORT_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
deleted file mode 100644
index b62a6ed3830..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/compressed_col_sparse_matrix_utils.h"
-
-#include <vector>
-#include <algorithm>
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-void CompressedColumnScalarMatrixToBlockMatrix(const int* scalar_rows,
- const int* scalar_cols,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks,
- vector<int>* block_rows,
- vector<int>* block_cols) {
- CHECK_NOTNULL(block_rows)->clear();
- CHECK_NOTNULL(block_cols)->clear();
- const int num_row_blocks = row_blocks.size();
- const int num_col_blocks = col_blocks.size();
-
- vector<int> row_block_starts(num_row_blocks);
- for (int i = 0, cursor = 0; i < num_row_blocks; ++i) {
- row_block_starts[i] = cursor;
- cursor += row_blocks[i];
- }
-
- // This loop extracts the block sparsity of the scalar sparse matrix
- // It does so by iterating over the columns, but only considering
- // the columns corresponding to the first element of each column
- // block. Within each column, the inner loop iterates over the rows,
- // and detects the presence of a row block by checking for the
- // presence of a non-zero entry corresponding to its first element.
- block_cols->push_back(0);
- int c = 0;
- for (int col_block = 0; col_block < num_col_blocks; ++col_block) {
- int column_size = 0;
- for (int idx = scalar_cols[c]; idx < scalar_cols[c + 1]; ++idx) {
- vector<int>::const_iterator it = lower_bound(row_block_starts.begin(),
- row_block_starts.end(),
- scalar_rows[idx]);
- // Since we are using lower_bound, it will return the row id
- // where the row block starts. For everything but the first row
- // of the block, where these values will be the same, we can
- // skip, as we only need the first row to detect the presence of
- // the block.
- //
- // For rows all but the first row in the last row block,
- // lower_bound will return row_block_starts.end(), but those can
- // be skipped like the rows in other row blocks too.
- if (it == row_block_starts.end() || *it != scalar_rows[idx]) {
- continue;
- }
-
- block_rows->push_back(it - row_block_starts.begin());
- ++column_size;
- }
- block_cols->push_back(block_cols->back() + column_size);
- c += col_blocks[col_block];
- }
-}
-
-void BlockOrderingToScalarOrdering(const vector<int>& blocks,
- const vector<int>& block_ordering,
- vector<int>* scalar_ordering) {
- CHECK_EQ(blocks.size(), block_ordering.size());
- const int num_blocks = blocks.size();
-
- // block_starts = [0, block1, block1 + block2 ..]
- vector<int> block_starts(num_blocks);
- for (int i = 0, cursor = 0; i < num_blocks ; ++i) {
- block_starts[i] = cursor;
- cursor += blocks[i];
- }
-
- scalar_ordering->resize(block_starts.back() + blocks.back());
- int cursor = 0;
- for (int i = 0; i < num_blocks; ++i) {
- const int block_id = block_ordering[i];
- const int block_size = blocks[block_id];
- int block_position = block_starts[block_id];
- for (int j = 0; j < block_size; ++j) {
- (*scalar_ordering)[cursor++] = block_position++;
- }
- }
-}
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h b/extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
deleted file mode 100644
index c8de2a1591a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
-#define CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
-
-#include <vector>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-// Extract the block sparsity pattern of the scalar compressed columns
-// matrix and return it in compressed column form. The compressed
-// column form is stored in two vectors block_rows, and block_cols,
-// which correspond to the row and column arrays in a compressed
-// column sparse matrix.
-//
-// If c_ij is the block in the matrix A corresponding to row block i
-// and column block j, then it is expected that A contains at least
-// one non-zero entry corresponding to the top left entry of c_ij,
-// as that entry is used to detect the presence of a non-zero c_ij.
-void CompressedColumnScalarMatrixToBlockMatrix(const int* scalar_rows,
- const int* scalar_cols,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks,
- vector<int>* block_rows,
- vector<int>* block_cols);
-
-// Given a set of blocks and a permutation of these blocks, compute
-// the corresponding "scalar" ordering, where the scalar ordering of
-// size sum(blocks).
-void BlockOrderingToScalarOrdering(const vector<int>& blocks,
- const vector<int>& block_ordering,
- vector<int>* scalar_ordering);
-
-// Solve the linear system
-//
-// R * solution = rhs
-//
-// Where R is an upper triangular compressed column sparse matrix.
-template <typename IntegerType>
-void SolveUpperTriangularInPlace(IntegerType num_cols,
- const IntegerType* rows,
- const IntegerType* cols,
- const double* values,
- double* rhs_and_solution) {
- for (IntegerType c = num_cols - 1; c >= 0; --c) {
- rhs_and_solution[c] /= values[cols[c + 1] - 1];
- for (IntegerType idx = cols[c]; idx < cols[c + 1] - 1; ++idx) {
- const IntegerType r = rows[idx];
- const double v = values[idx];
- rhs_and_solution[r] -= v * rhs_and_solution[c];
- }
- }
-}
-
-// Solve the linear system
-//
-// R' * solution = rhs
-//
-// Where R is an upper triangular compressed column sparse matrix.
-template <typename IntegerType>
-void SolveUpperTriangularTransposeInPlace(IntegerType num_cols,
- const IntegerType* rows,
- const IntegerType* cols,
- const double* values,
- double* rhs_and_solution) {
- for (IntegerType c = 0; c < num_cols; ++c) {
- for (IntegerType idx = cols[c]; idx < cols[c + 1] - 1; ++idx) {
- const IntegerType r = rows[idx];
- const double v = values[idx];
- rhs_and_solution[c] -= v * rhs_and_solution[r];
- }
- rhs_and_solution[c] = rhs_and_solution[c] / values[cols[c + 1] - 1];
- }
-}
-
-// Given a upper triangular matrix R in compressed column form, solve
-// the linear system,
-//
-// R'R x = b
-//
-// Where b is all zeros except for rhs_nonzero_index, where it is
-// equal to one.
-//
-// The function exploits this knowledge to reduce the number of
-// floating point operations.
-template <typename IntegerType>
-void SolveRTRWithSparseRHS(IntegerType num_cols,
- const IntegerType* rows,
- const IntegerType* cols,
- const double* values,
- const int rhs_nonzero_index,
- double* solution) {
- fill(solution, solution + num_cols, 0.0);
- solution[rhs_nonzero_index] = 1.0 / values[cols[rhs_nonzero_index + 1] - 1];
-
- for (IntegerType c = rhs_nonzero_index + 1; c < num_cols; ++c) {
- for (IntegerType idx = cols[c]; idx < cols[c + 1] - 1; ++idx) {
- const IntegerType r = rows[idx];
- if (r < rhs_nonzero_index) continue;
- const double v = values[idx];
- solution[c] -= v * solution[r];
- }
- solution[c] = solution[c] / values[cols[c + 1] - 1];
- }
-
- SolveUpperTriangularInPlace(num_cols, rows, cols, values, solution);
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
deleted file mode 100644
index ed8db14c99a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
+++ /dev/null
@@ -1,226 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/compressed_row_jacobian_writer.h"
-
-#include "ceres/casts.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/scratch_evaluate_preparer.h"
-
-namespace ceres {
-namespace internal {
-
-void CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors(
- const Program* program, CompressedRowSparseMatrix* jacobian) {
- const vector<ParameterBlock*>& parameter_blocks =
- program->parameter_blocks();
- vector<int>& col_blocks = *(jacobian->mutable_col_blocks());
- col_blocks.resize(parameter_blocks.size());
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- col_blocks[i] = parameter_blocks[i]->LocalSize();
- }
-
- const vector<ResidualBlock*>& residual_blocks =
- program->residual_blocks();
- vector<int>& row_blocks = *(jacobian->mutable_row_blocks());
- row_blocks.resize(residual_blocks.size());
- for (int i = 0; i < residual_blocks.size(); ++i) {
- row_blocks[i] = residual_blocks[i]->NumResiduals();
- }
-}
-
-void CompressedRowJacobianWriter::GetOrderedParameterBlocks(
- const Program* program,
- int residual_id,
- vector<pair<int, int> >* evaluated_jacobian_blocks) {
- const ResidualBlock* residual_block =
- program->residual_blocks()[residual_id];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
-
- for (int j = 0; j < num_parameter_blocks; ++j) {
- const ParameterBlock* parameter_block =
- residual_block->parameter_blocks()[j];
- if (!parameter_block->IsConstant()) {
- evaluated_jacobian_blocks->push_back(
- make_pair(parameter_block->index(), j));
- }
- }
- sort(evaluated_jacobian_blocks->begin(), evaluated_jacobian_blocks->end());
-}
-
-SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
- const vector<ResidualBlock*>& residual_blocks =
- program_->residual_blocks();
-
- int total_num_residuals = program_->NumResiduals();
- int total_num_effective_parameters = program_->NumEffectiveParameters();
-
- // Count the number of jacobian nonzeros.
- int num_jacobian_nonzeros = 0;
- for (int i = 0; i < residual_blocks.size(); ++i) {
- ResidualBlock* residual_block = residual_blocks[i];
- const int num_residuals = residual_block->NumResiduals();
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- if (!parameter_block->IsConstant()) {
- num_jacobian_nonzeros += num_residuals * parameter_block->LocalSize();
- }
- }
- }
-
- // Allocate storage for the jacobian with some extra space at the end.
- // Allocate more space than needed to store the jacobian so that when the LM
- // algorithm adds the diagonal, no reallocation is necessary. This reduces
- // peak memory usage significantly.
- CompressedRowSparseMatrix* jacobian =
- new CompressedRowSparseMatrix(
- total_num_residuals,
- total_num_effective_parameters,
- num_jacobian_nonzeros + total_num_effective_parameters);
-
- // At this stage, the CompressedRowSparseMatrix is an invalid state. But this
- // seems to be the only way to construct it without doing a memory copy.
- int* rows = jacobian->mutable_rows();
- int* cols = jacobian->mutable_cols();
- int row_pos = 0;
- rows[0] = 0;
- for (int i = 0; i < residual_blocks.size(); ++i) {
- const ResidualBlock* residual_block = residual_blocks[i];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
-
- // Count the number of derivatives for a row of this residual block and
- // build a list of active parameter block indices.
- int num_derivatives = 0;
- vector<int> parameter_indices;
- for (int j = 0; j < num_parameter_blocks; ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- if (!parameter_block->IsConstant()) {
- parameter_indices.push_back(parameter_block->index());
- num_derivatives += parameter_block->LocalSize();
- }
- }
-
- // Sort the parameters by their position in the state vector.
- sort(parameter_indices.begin(), parameter_indices.end());
- CHECK(unique(parameter_indices.begin(), parameter_indices.end()) ==
- parameter_indices.end())
- << "Ceres internal error: "
- << "Duplicate parameter blocks detected in a cost function. "
- << "This should never happen. Please report this to "
- << "the Ceres developers.";
-
- // Update the row indices.
- const int num_residuals = residual_block->NumResiduals();
- for (int j = 0; j < num_residuals; ++j) {
- rows[row_pos + j + 1] = rows[row_pos + j] + num_derivatives;
- }
-
- // Iterate over parameter blocks in the order which they occur in the
- // parameter vector. This code mirrors that in Write(), where jacobian
- // values are updated.
- int col_pos = 0;
- for (int j = 0; j < parameter_indices.size(); ++j) {
- ParameterBlock* parameter_block =
- program_->parameter_blocks()[parameter_indices[j]];
- const int parameter_block_size = parameter_block->LocalSize();
-
- for (int r = 0; r < num_residuals; ++r) {
- // This is the position in the values array of the jacobian where this
- // row of the jacobian block should go.
- const int column_block_begin = rows[row_pos + r] + col_pos;
-
- for (int c = 0; c < parameter_block_size; ++c) {
- cols[column_block_begin + c] = parameter_block->delta_offset() + c;
- }
- }
- col_pos += parameter_block_size;
- }
- row_pos += num_residuals;
- }
- CHECK_EQ(num_jacobian_nonzeros, rows[total_num_residuals]);
-
- PopulateJacobianRowAndColumnBlockVectors(program_, jacobian);
-
- return jacobian;
-}
-
-void CompressedRowJacobianWriter::Write(int residual_id,
- int residual_offset,
- double **jacobians,
- SparseMatrix* base_jacobian) {
- CompressedRowSparseMatrix* jacobian =
- down_cast<CompressedRowSparseMatrix*>(base_jacobian);
-
- double* jacobian_values = jacobian->mutable_values();
- const int* jacobian_rows = jacobian->rows();
-
- const ResidualBlock* residual_block =
- program_->residual_blocks()[residual_id];
- const int num_residuals = residual_block->NumResiduals();
-
- vector<pair<int, int> > evaluated_jacobian_blocks;
- GetOrderedParameterBlocks(program_, residual_id, &evaluated_jacobian_blocks);
-
- // Where in the current row does the jacobian for a parameter block begin.
- int col_pos = 0;
-
- // Iterate over the jacobian blocks in increasing order of their
- // positions in the reduced parameter vector.
- for (int i = 0; i < evaluated_jacobian_blocks.size(); ++i) {
- const ParameterBlock* parameter_block =
- program_->parameter_blocks()[evaluated_jacobian_blocks[i].first];
- const int argument = evaluated_jacobian_blocks[i].second;
- const int parameter_block_size = parameter_block->LocalSize();
-
- // Copy one row of the jacobian block at a time.
- for (int r = 0; r < num_residuals; ++r) {
- // Position of the r^th row of the current jacobian block.
- const double* block_row_begin =
- jacobians[argument] + r * parameter_block_size;
-
- // Position in the values array of the jacobian where this
- // row of the jacobian block should go.
- double* column_block_begin =
- jacobian_values + jacobian_rows[residual_offset + r] + col_pos;
-
- copy(block_row_begin,
- block_row_begin + parameter_block_size,
- column_block_begin);
- }
- col_pos += parameter_block_size;
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h
deleted file mode 100644
index a722a7c28e3..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A jacobian writer that directly writes to compressed row sparse matrices.
-
-#ifndef CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
-#define CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
-
-#include "ceres/evaluator.h"
-#include "ceres/scratch_evaluate_preparer.h"
-
-namespace ceres {
-namespace internal {
-
-class CompressedRowSparseMatrix;
-class Program;
-class SparseMatrix;
-
-class CompressedRowJacobianWriter {
- public:
- CompressedRowJacobianWriter(Evaluator::Options /* ignored */,
- Program* program)
- : program_(program) {
- }
-
- // PopulateJacobianRowAndColumnBlockVectors sets col_blocks and
- // row_blocks for a CompressedRowSparseMatrix, based on the
- // parameter block sizes and residual sizes respectively from the
- // program. This is useful when Solver::Options::use_block_amd =
- // true;
- //
- // This function is static so that it is available to other jacobian
- // writers which use CompressedRowSparseMatrix (or derived types).
- // (Jacobian writers do not fall under any type hierarchy; they only
- // have to provide an interface as specified in program_evaluator.h).
- static void PopulateJacobianRowAndColumnBlockVectors(
- const Program* program,
- CompressedRowSparseMatrix* jacobian);
-
- // It is necessary to determine the order of the jacobian blocks
- // before copying them into a CompressedRowSparseMatrix (or derived
- // type). Just because a cost function uses parameter blocks 1
- // after 2 in its arguments does not mean that the block 1 occurs
- // before block 2 in the column layout of the jacobian. Thus,
- // GetOrderedParameterBlocks determines the order by sorting the
- // jacobian blocks by their position in the state vector.
- //
- // This function is static so that it is available to other jacobian
- // writers which use CompressedRowSparseMatrix (or derived types).
- // (Jacobian writers do not fall under any type hierarchy; they only
- // have to provide an interface as specified in
- // program_evaluator.h).
- static void GetOrderedParameterBlocks(
- const Program* program,
- int residual_id,
- vector<pair<int, int> >* evaluated_jacobian_blocks);
-
- // JacobianWriter interface.
-
- // Since the compressed row matrix has different layout than that
- // assumed by the cost functions, use scratch space to store the
- // jacobians temporarily then copy them over to the larger jacobian
- // in the Write() function.
- ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads) {
- return ScratchEvaluatePreparer::Create(*program_, num_threads);
- }
-
- SparseMatrix* CreateJacobian() const;
-
- void Write(int residual_id,
- int residual_offset,
- double **jacobians,
- SparseMatrix* base_jacobian);
-
- private:
- Program* program_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc
deleted file mode 100644
index 7993ed6917a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc
+++ /dev/null
@@ -1,544 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/compressed_row_sparse_matrix.h"
-
-#include <algorithm>
-#include <numeric>
-#include <vector>
-#include "ceres/crs_matrix.h"
-#include "ceres/internal/port.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-// Helper functor used by the constructor for reordering the contents
-// of a TripletSparseMatrix. This comparator assumes thay there are no
-// duplicates in the pair of arrays rows and cols, i.e., there is no
-// indices i and j (not equal to each other) s.t.
-//
-// rows[i] == rows[j] && cols[i] == cols[j]
-//
-// If this is the case, this functor will not be a StrictWeakOrdering.
-struct RowColLessThan {
- RowColLessThan(const int* rows, const int* cols)
- : rows(rows), cols(cols) {
- }
-
- bool operator()(const int x, const int y) const {
- if (rows[x] == rows[y]) {
- return (cols[x] < cols[y]);
- }
- return (rows[x] < rows[y]);
- }
-
- const int* rows;
- const int* cols;
-};
-
-} // namespace
-
-// This constructor gives you a semi-initialized CompressedRowSparseMatrix.
-CompressedRowSparseMatrix::CompressedRowSparseMatrix(int num_rows,
- int num_cols,
- int max_num_nonzeros) {
- num_rows_ = num_rows;
- num_cols_ = num_cols;
- rows_.resize(num_rows + 1, 0);
- cols_.resize(max_num_nonzeros, 0);
- values_.resize(max_num_nonzeros, 0.0);
-
-
- VLOG(1) << "# of rows: " << num_rows_
- << " # of columns: " << num_cols_
- << " max_num_nonzeros: " << cols_.size()
- << ". Allocating " << (num_rows_ + 1) * sizeof(int) + // NOLINT
- cols_.size() * sizeof(int) + // NOLINT
- cols_.size() * sizeof(double); // NOLINT
-}
-
-CompressedRowSparseMatrix::CompressedRowSparseMatrix(
- const TripletSparseMatrix& m) {
- num_rows_ = m.num_rows();
- num_cols_ = m.num_cols();
-
- rows_.resize(num_rows_ + 1, 0);
- cols_.resize(m.num_nonzeros(), 0);
- values_.resize(m.max_num_nonzeros(), 0.0);
-
- // index is the list of indices into the TripletSparseMatrix m.
- vector<int> index(m.num_nonzeros(), 0);
- for (int i = 0; i < m.num_nonzeros(); ++i) {
- index[i] = i;
- }
-
- // Sort index such that the entries of m are ordered by row and ties
- // are broken by column.
- sort(index.begin(), index.end(), RowColLessThan(m.rows(), m.cols()));
-
- VLOG(1) << "# of rows: " << num_rows_
- << " # of columns: " << num_cols_
- << " max_num_nonzeros: " << cols_.size()
- << ". Allocating "
- << ((num_rows_ + 1) * sizeof(int) + // NOLINT
- cols_.size() * sizeof(int) + // NOLINT
- cols_.size() * sizeof(double)); // NOLINT
-
- // Copy the contents of the cols and values array in the order given
- // by index and count the number of entries in each row.
- for (int i = 0; i < m.num_nonzeros(); ++i) {
- const int idx = index[i];
- ++rows_[m.rows()[idx] + 1];
- cols_[i] = m.cols()[idx];
- values_[i] = m.values()[idx];
- }
-
- // Find the cumulative sum of the row counts.
- for (int i = 1; i < num_rows_ + 1; ++i) {
- rows_[i] += rows_[i - 1];
- }
-
- CHECK_EQ(num_nonzeros(), m.num_nonzeros());
-}
-
-CompressedRowSparseMatrix::CompressedRowSparseMatrix(const double* diagonal,
- int num_rows) {
- CHECK_NOTNULL(diagonal);
-
- num_rows_ = num_rows;
- num_cols_ = num_rows;
- rows_.resize(num_rows + 1);
- cols_.resize(num_rows);
- values_.resize(num_rows);
-
- rows_[0] = 0;
- for (int i = 0; i < num_rows_; ++i) {
- cols_[i] = i;
- values_[i] = diagonal[i];
- rows_[i + 1] = i + 1;
- }
-
- CHECK_EQ(num_nonzeros(), num_rows);
-}
-
-CompressedRowSparseMatrix::~CompressedRowSparseMatrix() {
-}
-
-void CompressedRowSparseMatrix::SetZero() {
- fill(values_.begin(), values_.end(), 0);
-}
-
-void CompressedRowSparseMatrix::RightMultiply(const double* x,
- double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
-
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- y[r] += values_[idx] * x[cols_[idx]];
- }
- }
-}
-
-void CompressedRowSparseMatrix::LeftMultiply(const double* x, double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
-
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- y[cols_[idx]] += values_[idx] * x[r];
- }
- }
-}
-
-void CompressedRowSparseMatrix::SquaredColumnNorm(double* x) const {
- CHECK_NOTNULL(x);
-
- fill(x, x + num_cols_, 0.0);
- for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
- x[cols_[idx]] += values_[idx] * values_[idx];
- }
-}
-
-void CompressedRowSparseMatrix::ScaleColumns(const double* scale) {
- CHECK_NOTNULL(scale);
-
- for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
- values_[idx] *= scale[cols_[idx]];
- }
-}
-
-void CompressedRowSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- CHECK_NOTNULL(dense_matrix);
- dense_matrix->resize(num_rows_, num_cols_);
- dense_matrix->setZero();
-
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- (*dense_matrix)(r, cols_[idx]) = values_[idx];
- }
- }
-}
-
-void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
- CHECK_GE(delta_rows, 0);
- CHECK_LE(delta_rows, num_rows_);
-
- num_rows_ -= delta_rows;
- rows_.resize(num_rows_ + 1);
-
- // Walk the list of row blocks until we reach the new number of rows
- // and the drop the rest of the row blocks.
- int num_row_blocks = 0;
- int num_rows = 0;
- while (num_row_blocks < row_blocks_.size() && num_rows < num_rows_) {
- num_rows += row_blocks_[num_row_blocks];
- ++num_row_blocks;
- }
-
- row_blocks_.resize(num_row_blocks);
-}
-
-void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
- CHECK_EQ(m.num_cols(), num_cols_);
-
- CHECK(row_blocks_.size() == 0 || m.row_blocks().size() !=0)
- << "Cannot append a matrix with row blocks to one without and vice versa."
- << "This matrix has : " << row_blocks_.size() << " row blocks."
- << "The matrix being appended has: " << m.row_blocks().size()
- << " row blocks.";
-
- if (cols_.size() < num_nonzeros() + m.num_nonzeros()) {
- cols_.resize(num_nonzeros() + m.num_nonzeros());
- values_.resize(num_nonzeros() + m.num_nonzeros());
- }
-
- // Copy the contents of m into this matrix.
- copy(m.cols(), m.cols() + m.num_nonzeros(), &cols_[num_nonzeros()]);
- copy(m.values(), m.values() + m.num_nonzeros(), &values_[num_nonzeros()]);
- rows_.resize(num_rows_ + m.num_rows() + 1);
- // new_rows = [rows_, m.row() + rows_[num_rows_]]
- fill(rows_.begin() + num_rows_,
- rows_.begin() + num_rows_ + m.num_rows() + 1,
- rows_[num_rows_]);
-
- for (int r = 0; r < m.num_rows() + 1; ++r) {
- rows_[num_rows_ + r] += m.rows()[r];
- }
-
- num_rows_ += m.num_rows();
- row_blocks_.insert(row_blocks_.end(), m.row_blocks().begin(), m.row_blocks().end());
-}
-
-void CompressedRowSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- fprintf(file,
- "% 10d % 10d %17f\n",
- r,
- cols_[idx],
- values_[idx]);
- }
- }
-}
-
-void CompressedRowSparseMatrix::ToCRSMatrix(CRSMatrix* matrix) const {
- matrix->num_rows = num_rows_;
- matrix->num_cols = num_cols_;
- matrix->rows = rows_;
- matrix->cols = cols_;
- matrix->values = values_;
-
- // Trim.
- matrix->rows.resize(matrix->num_rows + 1);
- matrix->cols.resize(matrix->rows[matrix->num_rows]);
- matrix->values.resize(matrix->rows[matrix->num_rows]);
-}
-
-void CompressedRowSparseMatrix::SetMaxNumNonZeros(int num_nonzeros) {
- CHECK_GE(num_nonzeros, 0);
-
- cols_.resize(num_nonzeros);
- values_.resize(num_nonzeros);
-}
-
-void CompressedRowSparseMatrix::SolveLowerTriangularInPlace(
- double* solution) const {
- for (int r = 0; r < num_rows_; ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1] - 1; ++idx) {
- solution[r] -= values_[idx] * solution[cols_[idx]];
- }
- solution[r] /= values_[rows_[r + 1] - 1];
- }
-}
-
-void CompressedRowSparseMatrix::SolveLowerTriangularTransposeInPlace(
- double* solution) const {
- for (int r = num_rows_ - 1; r >= 0; --r) {
- solution[r] /= values_[rows_[r + 1] - 1];
- for (int idx = rows_[r + 1] - 2; idx >= rows_[r]; --idx) {
- solution[cols_[idx]] -= values_[idx] * solution[r];
- }
- }
-}
-
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
- const double* diagonal,
- const vector<int>& blocks) {
- int num_rows = 0;
- int num_nonzeros = 0;
- for (int i = 0; i < blocks.size(); ++i) {
- num_rows += blocks[i];
- num_nonzeros += blocks[i] * blocks[i];
- }
-
- CompressedRowSparseMatrix* matrix =
- new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros);
-
- int* rows = matrix->mutable_rows();
- int* cols = matrix->mutable_cols();
- double* values = matrix->mutable_values();
- fill(values, values + num_nonzeros, 0.0);
-
- int idx_cursor = 0;
- int col_cursor = 0;
- for (int i = 0; i < blocks.size(); ++i) {
- const int block_size = blocks[i];
- for (int r = 0; r < block_size; ++r) {
- *(rows++) = idx_cursor;
- values[idx_cursor + r] = diagonal[col_cursor + r];
- for (int c = 0; c < block_size; ++c, ++idx_cursor) {
- *(cols++) = col_cursor + c;
- }
- }
- col_cursor += block_size;
- }
- *rows = idx_cursor;
-
- *matrix->mutable_row_blocks() = blocks;
- *matrix->mutable_col_blocks() = blocks;
-
- CHECK_EQ(idx_cursor, num_nonzeros);
- CHECK_EQ(col_cursor, num_rows);
- return matrix;
-}
-
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::Transpose() const {
- CompressedRowSparseMatrix* transpose =
- new CompressedRowSparseMatrix(num_cols_, num_rows_, num_nonzeros());
-
- int* transpose_rows = transpose->mutable_rows();
- int* transpose_cols = transpose->mutable_cols();
- double* transpose_values = transpose->mutable_values();
-
- for (int idx = 0; idx < num_nonzeros(); ++idx) {
- ++transpose_rows[cols_[idx] + 1];
- }
-
- for (int i = 1; i < transpose->num_rows() + 1; ++i) {
- transpose_rows[i] += transpose_rows[i - 1];
- }
-
- for (int r = 0; r < num_rows(); ++r) {
- for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
- const int c = cols_[idx];
- const int transpose_idx = transpose_rows[c]++;
- transpose_cols[transpose_idx] = r;
- transpose_values[transpose_idx] = values_[idx];
- }
- }
-
- for (int i = transpose->num_rows() - 1; i > 0 ; --i) {
- transpose_rows[i] = transpose_rows[i - 1];
- }
- transpose_rows[0] = 0;
-
- *(transpose->mutable_row_blocks()) = col_blocks_;
- *(transpose->mutable_col_blocks()) = row_blocks_;
-
- return transpose;
-}
-
-namespace {
-// A ProductTerm is a term in the outer product of a matrix with
-// itself.
-struct ProductTerm {
- ProductTerm(const int row, const int col, const int index)
- : row(row), col(col), index(index) {
- }
-
- bool operator<(const ProductTerm& right) const {
- if (row == right.row) {
- if (col == right.col) {
- return index < right.index;
- }
- return col < right.col;
- }
- return row < right.row;
- }
-
- int row;
- int col;
- int index;
-};
-
-CompressedRowSparseMatrix*
-CompressAndFillProgram(const int num_rows,
- const int num_cols,
- const vector<ProductTerm>& product,
- vector<int>* program) {
- CHECK_GT(product.size(), 0);
-
- // Count the number of unique product term, which in turn is the
- // number of non-zeros in the outer product.
- int num_nonzeros = 1;
- for (int i = 1; i < product.size(); ++i) {
- if (product[i].row != product[i - 1].row ||
- product[i].col != product[i - 1].col) {
- ++num_nonzeros;
- }
- }
-
- CompressedRowSparseMatrix* matrix =
- new CompressedRowSparseMatrix(num_rows, num_cols, num_nonzeros);
-
- int* crsm_rows = matrix->mutable_rows();
- std::fill(crsm_rows, crsm_rows + num_rows + 1, 0);
- int* crsm_cols = matrix->mutable_cols();
- std::fill(crsm_cols, crsm_cols + num_nonzeros, 0);
-
- CHECK_NOTNULL(program)->clear();
- program->resize(product.size());
-
- // Iterate over the sorted product terms. This means each row is
- // filled one at a time, and we are able to assign a position in the
- // values array to each term.
- //
- // If terms repeat, i.e., they contribute to the same entry in the
- // result matrix), then they do not affect the sparsity structure of
- // the result matrix.
- int nnz = 0;
- crsm_cols[0] = product[0].col;
- crsm_rows[product[0].row + 1]++;
- (*program)[product[0].index] = nnz;
- for (int i = 1; i < product.size(); ++i) {
- const ProductTerm& previous = product[i - 1];
- const ProductTerm& current = product[i];
-
- // Sparsity structure is updated only if the term is not a repeat.
- if (previous.row != current.row || previous.col != current.col) {
- crsm_cols[++nnz] = current.col;
- crsm_rows[current.row + 1]++;
- }
-
- // All terms get assigned the position in the values array where
- // their value is accumulated.
- (*program)[current.index] = nnz;
- }
-
- for (int i = 1; i < num_rows + 1; ++i) {
- crsm_rows[i] += crsm_rows[i - 1];
- }
-
- return matrix;
-}
-
-} // namespace
-
-CompressedRowSparseMatrix*
-CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
- const CompressedRowSparseMatrix& m,
- vector<int>* program) {
- CHECK_NOTNULL(program)->clear();
- CHECK_GT(m.num_nonzeros(), 0) << "Congratulations, "
- << "you found a bug in Ceres. Please report it.";
-
- vector<ProductTerm> product;
- const vector<int>& row_blocks = m.row_blocks();
- int row_block_begin = 0;
- // Iterate over row blocks
- for (int row_block = 0; row_block < row_blocks.size(); ++row_block) {
- const int row_block_end = row_block_begin + row_blocks[row_block];
- // Compute the outer product terms for just one row per row block.
- const int r = row_block_begin;
- // Compute the lower triangular part of the product.
- for (int idx1 = m.rows()[r]; idx1 < m.rows()[r + 1]; ++idx1) {
- for (int idx2 = m.rows()[r]; idx2 <= idx1; ++idx2) {
- product.push_back(ProductTerm(m.cols()[idx1], m.cols()[idx2], product.size()));
- }
- }
- row_block_begin = row_block_end;
- }
- CHECK_EQ(row_block_begin, m.num_rows());
- sort(product.begin(), product.end());
- return CompressAndFillProgram(m.num_cols(), m.num_cols(), product, program);
-}
-
-void CompressedRowSparseMatrix::ComputeOuterProduct(
- const CompressedRowSparseMatrix& m,
- const vector<int>& program,
- CompressedRowSparseMatrix* result) {
- result->SetZero();
- double* values = result->mutable_values();
- const vector<int>& row_blocks = m.row_blocks();
-
- int cursor = 0;
- int row_block_begin = 0;
- const double* m_values = m.values();
- const int* m_rows = m.rows();
- // Iterate over row blocks.
- for (int row_block = 0; row_block < row_blocks.size(); ++row_block) {
- const int row_block_end = row_block_begin + row_blocks[row_block];
- const int saved_cursor = cursor;
- for (int r = row_block_begin; r < row_block_end; ++r) {
- // Reuse the program segment for each row in this row block.
- cursor = saved_cursor;
- const int row_begin = m_rows[r];
- const int row_end = m_rows[r + 1];
- for (int idx1 = row_begin; idx1 < row_end; ++idx1) {
- const double v1 = m_values[idx1];
- for (int idx2 = row_begin; idx2 <= idx1; ++idx2, ++cursor) {
- values[program[cursor]] += v1 * m_values[idx2];
- }
- }
- }
- row_block_begin = row_block_end;
- }
-
- CHECK_EQ(row_block_begin, m.num_rows());
- CHECK_EQ(cursor, program.size());
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
deleted file mode 100644
index a0ba7eeb6ce..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
-
-#include <vector>
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/sparse_matrix.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-struct CRSMatrix;
-
-namespace internal {
-
-class TripletSparseMatrix;
-
-class CompressedRowSparseMatrix : public SparseMatrix {
- public:
- // Build a matrix with the same content as the TripletSparseMatrix
- // m. TripletSparseMatrix objects are easier to construct
- // incrementally, so we use them to initialize SparseMatrix
- // objects.
- //
- // We assume that m does not have any repeated entries.
- explicit CompressedRowSparseMatrix(const TripletSparseMatrix& m);
-
- // Use this constructor only if you know what you are doing. This
- // creates a "blank" matrix with the appropriate amount of memory
- // allocated. However, the object itself is in an inconsistent state
- // as the rows and cols matrices do not match the values of
- // num_rows, num_cols and max_num_nonzeros.
- //
- // The use case for this constructor is that when the user knows the
- // size of the matrix to begin with and wants to update the layout
- // manually, instead of going via the indirect route of first
- // constructing a TripletSparseMatrix, which leads to more than
- // double the peak memory usage.
- CompressedRowSparseMatrix(int num_rows,
- int num_cols,
- int max_num_nonzeros);
-
- // Build a square sparse diagonal matrix with num_rows rows and
- // columns. The diagonal m(i,i) = diagonal(i);
- CompressedRowSparseMatrix(const double* diagonal, int num_rows);
-
- virtual ~CompressedRowSparseMatrix();
-
- // SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
-
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_cols_; }
- virtual int num_nonzeros() const { return rows_[num_rows_]; }
- virtual const double* values() const { return &values_[0]; }
- virtual double* mutable_values() { return &values_[0]; }
-
- // Delete the bottom delta_rows.
- // num_rows -= delta_rows
- void DeleteRows(int delta_rows);
-
- // Append the contents of m to the bottom of this matrix. m must
- // have the same number of columns as this matrix.
- void AppendRows(const CompressedRowSparseMatrix& m);
-
- void ToCRSMatrix(CRSMatrix* matrix) const;
-
- // Low level access methods that expose the structure of the matrix.
- const int* cols() const { return &cols_[0]; }
- int* mutable_cols() { return &cols_[0]; }
-
- const int* rows() const { return &rows_[0]; }
- int* mutable_rows() { return &rows_[0]; }
-
- const vector<int>& row_blocks() const { return row_blocks_; }
- vector<int>* mutable_row_blocks() { return &row_blocks_; }
-
- const vector<int>& col_blocks() const { return col_blocks_; }
- vector<int>* mutable_col_blocks() { return &col_blocks_; }
-
- // Destructive array resizing method.
- void SetMaxNumNonZeros(int num_nonzeros);
-
- // Non-destructive array resizing method.
- void set_num_rows(const int num_rows) { num_rows_ = num_rows; }
- void set_num_cols(const int num_cols) { num_cols_ = num_cols; }
-
- void SolveLowerTriangularInPlace(double* solution) const;
- void SolveLowerTriangularTransposeInPlace(double* solution) const;
-
- CompressedRowSparseMatrix* Transpose() const;
-
- static CompressedRowSparseMatrix* CreateBlockDiagonalMatrix(
- const double* diagonal,
- const vector<int>& blocks);
-
- // Compute the sparsity structure of the product m.transpose() * m
- // and create a CompressedRowSparseMatrix corresponding to it.
- //
- // Also compute a "program" vector, which for every term in the
- // outer product points to the entry in the values array of the
- // result matrix where it should be accumulated.
- //
- // This program is used by the ComputeOuterProduct function below to
- // compute the outer product.
- //
- // Since the entries of the program are the same for rows with the
- // same sparsity structure, the program only stores the result for
- // one row per row block. The ComputeOuterProduct function reuses
- // this information for each row in the row block.
- static CompressedRowSparseMatrix* CreateOuterProductMatrixAndProgram(
- const CompressedRowSparseMatrix& m,
- vector<int>* program);
-
- // Compute the values array for the expression m.transpose() * m,
- // where the matrix used to store the result and a program have been
- // created using the CreateOuterProductMatrixAndProgram function
- // above.
- static void ComputeOuterProduct(const CompressedRowSparseMatrix& m,
- const vector<int>& program,
- CompressedRowSparseMatrix* result);
-
- private:
- int num_rows_;
- int num_cols_;
- vector<int> rows_;
- vector<int> cols_;
- vector<double> values_;
-
- // If the matrix has an underlying block structure, then it can also
- // carry with it row and column block sizes. This is auxilliary and
- // optional information for use by algorithms operating on the
- // matrix. The class itself does not make use of this information in
- // any way.
- vector<int> row_blocks_;
- vector<int> col_blocks_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(CompressedRowSparseMatrix);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc
deleted file mode 100644
index 7322790f717..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/conditioned_cost_function.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wjr@google.com (William Rucklidge)
-//
-// This file contains the implementation of the conditioned cost function.
-
-#include "ceres/conditioned_cost_function.h"
-
-#include <cstddef>
-
-#include "ceres/internal/eigen.h"
-#include "ceres/stl_util.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-// This cost function has the same dimensions (parameters, residuals) as
-// the one it's wrapping.
-ConditionedCostFunction::ConditionedCostFunction(
- CostFunction* wrapped_cost_function,
- const vector<CostFunction*>& conditioners,
- Ownership ownership)
- : wrapped_cost_function_(wrapped_cost_function),
- conditioners_(conditioners),
- ownership_(ownership) {
- // Set up our dimensions.
- set_num_residuals(wrapped_cost_function_->num_residuals());
- *mutable_parameter_block_sizes() =
- wrapped_cost_function_->parameter_block_sizes();
-
- // Sanity-check the conditioners' dimensions.
- CHECK_EQ(wrapped_cost_function_->num_residuals(), conditioners_.size());
- for (int i = 0; i < wrapped_cost_function_->num_residuals(); i++) {
- if (conditioners[i]) {
- CHECK_EQ(1, conditioners[i]->num_residuals());
- CHECK_EQ(1, conditioners[i]->parameter_block_sizes().size());
- CHECK_EQ(1, conditioners[i]->parameter_block_sizes()[0]);
- }
- }
-}
-
-ConditionedCostFunction::~ConditionedCostFunction() {
- if (ownership_ == TAKE_OWNERSHIP) {
- STLDeleteElements(&conditioners_);
- } else {
- wrapped_cost_function_.release();
- }
-}
-
-bool ConditionedCostFunction::Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- bool success = wrapped_cost_function_->Evaluate(parameters, residuals,
- jacobians);
- if (!success) {
- return false;
- }
-
- for (int r = 0; r < wrapped_cost_function_->num_residuals(); r++) {
- // On output, we want to have
- // residuals[r] = conditioners[r](wrapped_residuals[r])
- // For parameter block i, column c,
- // jacobians[i][r*parameter_block_size_[i] + c] =
- // = d residual[r] / d parameters[i][c]
- // = conditioners[r]'(wrapped_residuals[r]) *
- // d wrapped_residuals[r] / d parameters[i][c]
- if (conditioners_[r]) {
- double conditioner_derivative;
- double* conditioner_derivative_pointer = &conditioner_derivative;
- double** conditioner_derivative_pointer2 =
- &conditioner_derivative_pointer;
- if (!jacobians) {
- conditioner_derivative_pointer2 = NULL;
- }
-
- double unconditioned_residual = residuals[r];
- double* parameter_pointer = &unconditioned_residual;
- success = conditioners_[r]->Evaluate(&parameter_pointer,
- &residuals[r],
- conditioner_derivative_pointer2);
- if (!success) {
- return false;
- }
-
- if (jacobians) {
- for (int i = 0;
- i < wrapped_cost_function_->parameter_block_sizes().size();
- i++) {
- if (jacobians[i]) {
- int parameter_block_size =
- wrapped_cost_function_->parameter_block_sizes()[i];
- VectorRef jacobian_row(jacobians[i] + r * parameter_block_size,
- parameter_block_size, 1);
- jacobian_row *= conditioner_derivative;
- }
- }
- }
- }
- }
- return true;
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc
deleted file mode 100644
index 3071a0918e4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// A preconditioned conjugate gradients solver
-// (ConjugateGradientsSolver) for positive semidefinite linear
-// systems.
-//
-// We have also augmented the termination criterion used by this
-// solver to support not just residual based termination but also
-// termination based on decrease in the value of the quadratic model
-// that CG optimizes.
-
-#include "ceres/conjugate_gradients_solver.h"
-
-#include <cmath>
-#include <cstddef>
-#include "ceres/fpclassify.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_operator.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-bool IsZeroOrInfinity(double x) {
- return ((x == 0.0) || (IsInfinite(x)));
-}
-
-} // namespace
-
-ConjugateGradientsSolver::ConjugateGradientsSolver(
- const LinearSolver::Options& options)
- : options_(options) {
-}
-
-LinearSolver::Summary ConjugateGradientsSolver::Solve(
- LinearOperator* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- CHECK_NOTNULL(A);
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(b);
- CHECK_EQ(A->num_rows(), A->num_cols());
-
- LinearSolver::Summary summary;
- summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
- summary.message = "Maximum number of iterations reached.";
- summary.num_iterations = 0;
-
- const int num_cols = A->num_cols();
- VectorRef xref(x, num_cols);
- ConstVectorRef bref(b, num_cols);
-
- const double norm_b = bref.norm();
- if (norm_b == 0.0) {
- xref.setZero();
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Convergence. |b| = 0.";
- return summary;
- }
-
- Vector r(num_cols);
- Vector p(num_cols);
- Vector z(num_cols);
- Vector tmp(num_cols);
-
- const double tol_r = per_solve_options.r_tolerance * norm_b;
-
- tmp.setZero();
- A->RightMultiply(x, tmp.data());
- r = bref - tmp;
- double norm_r = r.norm();
- if (options_.min_num_iterations == 0 && norm_r <= tol_r) {
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message =
- StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
- return summary;
- }
-
- double rho = 1.0;
-
- // Initial value of the quadratic model Q = x'Ax - 2 * b'x.
- double Q0 = -1.0 * xref.dot(bref + r);
-
- for (summary.num_iterations = 1;; ++summary.num_iterations) {
-
- // Apply preconditioner
- if (per_solve_options.preconditioner != NULL) {
- z.setZero();
- per_solve_options.preconditioner->RightMultiply(r.data(), z.data());
- } else {
- z = r;
- }
-
- double last_rho = rho;
- rho = r.dot(z);
- if (IsZeroOrInfinity(rho)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = StringPrintf("Numerical failure. rho = r'z = %e.", rho);
- break;
- };
-
- if (summary.num_iterations == 1) {
- p = z;
- } else {
- double beta = rho / last_rho;
- if (IsZeroOrInfinity(beta)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = StringPrintf(
- "Numerical failure. beta = rho_n / rho_{n-1} = %e.", beta);
- break;
- }
- p = z + beta * p;
- }
-
- Vector& q = z;
- q.setZero();
- A->RightMultiply(p.data(), q.data());
- const double pq = p.dot(q);
- if ((pq <= 0) || IsInfinite(pq)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = StringPrintf("Numerical failure. p'q = %e.", pq);
- break;
- }
-
- const double alpha = rho / pq;
- if (IsInfinite(alpha)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message =
- StringPrintf("Numerical failure. alpha = rho / pq = %e", alpha);
- break;
- }
-
- xref = xref + alpha * p;
-
- // Ideally we would just use the update r = r - alpha*q to keep
- // track of the residual vector. However this estimate tends to
- // drift over time due to round off errors. Thus every
- // residual_reset_period iterations, we calculate the residual as
- // r = b - Ax. We do not do this every iteration because this
- // requires an additional matrix vector multiply which would
- // double the complexity of the CG algorithm.
- if (summary.num_iterations % options_.residual_reset_period == 0) {
- tmp.setZero();
- A->RightMultiply(x, tmp.data());
- r = bref - tmp;
- } else {
- r = r - alpha * q;
- }
-
- // Quadratic model based termination.
- // Q1 = x'Ax - 2 * b' x.
- const double Q1 = -1.0 * xref.dot(bref + r);
-
- // For PSD matrices A, let
- //
- // Q(x) = x'Ax - 2b'x
- //
- // be the cost of the quadratic function defined by A and b. Then,
- // the solver terminates at iteration i if
- //
- // i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
- //
- // This termination criterion is more useful when using CG to
- // solve the Newton step. This particular convergence test comes
- // from Stephen Nash's work on truncated Newton
- // methods. References:
- //
- // 1. Stephen G. Nash & Ariela Sofer, Assessing A Search
- // Direction Within A Truncated Newton Method, Operation
- // Research Letters 9(1990) 219-221.
- //
- // 2. Stephen G. Nash, A Survey of Truncated Newton Methods,
- // Journal of Computational and Applied Mathematics,
- // 124(1-2), 45-59, 2000.
- //
- const double zeta = summary.num_iterations * (Q1 - Q0) / Q1;
- if (zeta < per_solve_options.q_tolerance &&
- summary.num_iterations >= options_.min_num_iterations) {
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message =
- StringPrintf("Convergence: zeta = %e < %e",
- zeta,
- per_solve_options.q_tolerance);
- break;
- }
- Q0 = Q1;
-
- // Residual based termination.
- norm_r = r. norm();
- if (norm_r <= tol_r &&
- summary.num_iterations >= options_.min_num_iterations) {
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message =
- StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
- break;
- }
-
- if (summary.num_iterations >= options_.max_num_iterations) {
- break;
- }
- }
-
- return summary;
-};
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h b/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h
deleted file mode 100644
index b8dfa56b526..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/conjugate_gradients_solver.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Preconditioned Conjugate Gradients based solver for positive
-// semidefinite linear systems.
-
-#ifndef CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
-#define CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
-
-#include "ceres/linear_solver.h"
-#include "ceres/internal/macros.h"
-
-namespace ceres {
-namespace internal {
-
-class LinearOperator;
-
-// This class implements the now classical Conjugate Gradients
-// algorithm of Hestenes & Stiefel for solving postive semidefinite
-// linear sytems. Optionally it can use a preconditioner also to
-// reduce the condition number of the linear system and improve the
-// convergence rate. Modern references for Conjugate Gradients are the
-// books by Yousef Saad and Trefethen & Bau. This implementation of CG
-// has been augmented with additional termination tests that are
-// needed for forcing early termination when used as part of an
-// inexact Newton solver.
-//
-// For more details see the documentation for
-// LinearSolver::PerSolveOptions::r_tolerance and
-// LinearSolver::PerSolveOptions::q_tolerance in linear_solver.h.
-class ConjugateGradientsSolver : public LinearSolver {
- public:
- explicit ConjugateGradientsSolver(const LinearSolver::Options& options);
- virtual Summary Solve(LinearOperator* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- private:
- const LinearSolver::Options options_;
- CERES_DISALLOW_COPY_AND_ASSIGN(ConjugateGradientsSolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
deleted file mode 100644
index 0d8adee7cd8..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/coordinate_descent_minimizer.h"
-
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
-#include <iterator>
-#include <numeric>
-#include <vector>
-#include "ceres/evaluator.h"
-#include "ceres/linear_solver.h"
-#include "ceres/minimizer.h"
-#include "ceres/parameter_block.h"
-#include "ceres/parameter_block_ordering.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/solver.h"
-#include "ceres/trust_region_minimizer.h"
-#include "ceres/trust_region_strategy.h"
-#include "ceres/parameter_block_ordering.h"
-
-namespace ceres {
-namespace internal {
-
-CoordinateDescentMinimizer::~CoordinateDescentMinimizer() {
-}
-
-bool CoordinateDescentMinimizer::Init(
- const Program& program,
- const ProblemImpl::ParameterMap& parameter_map,
- const ParameterBlockOrdering& ordering,
- string* error) {
- parameter_blocks_.clear();
- independent_set_offsets_.clear();
- independent_set_offsets_.push_back(0);
-
- // Serialize the OrderedGroups into a vector of parameter block
- // offsets for parallel access.
- map<ParameterBlock*, int> parameter_block_index;
- map<int, set<double*> > group_to_elements = ordering.group_to_elements();
- for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
- it != group_to_elements.end();
- ++it) {
- for (set<double*>::const_iterator ptr_it = it->second.begin();
- ptr_it != it->second.end();
- ++ptr_it) {
- parameter_blocks_.push_back(parameter_map.find(*ptr_it)->second);
- parameter_block_index[parameter_blocks_.back()] =
- parameter_blocks_.size() - 1;
- }
- independent_set_offsets_.push_back(
- independent_set_offsets_.back() + it->second.size());
- }
-
- // The ordering does not have to contain all parameter blocks, so
- // assign zero offsets/empty independent sets to these parameter
- // blocks.
- const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- if (!ordering.IsMember(parameter_blocks[i]->mutable_user_state())) {
- parameter_blocks_.push_back(parameter_blocks[i]);
- independent_set_offsets_.push_back(independent_set_offsets_.back());
- }
- }
-
- // Compute the set of residual blocks that depend on each parameter
- // block.
- residual_blocks_.resize(parameter_block_index.size());
- const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
- for (int i = 0; i < residual_blocks.size(); ++i) {
- ResidualBlock* residual_block = residual_blocks[i];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- const map<ParameterBlock*, int>::const_iterator it =
- parameter_block_index.find(parameter_block);
- if (it != parameter_block_index.end()) {
- residual_blocks_[it->second].push_back(residual_block);
- }
- }
- }
-
- evaluator_options_.linear_solver_type = DENSE_QR;
- evaluator_options_.num_eliminate_blocks = 0;
- evaluator_options_.num_threads = 1;
-
- return true;
-}
-
-void CoordinateDescentMinimizer::Minimize(
- const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary) {
- // Set the state and mark all parameter blocks constant.
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- ParameterBlock* parameter_block = parameter_blocks_[i];
- parameter_block->SetState(parameters + parameter_block->state_offset());
- parameter_block->SetConstant();
- }
-
- scoped_array<LinearSolver*> linear_solvers(
- new LinearSolver*[options.num_threads]);
-
- LinearSolver::Options linear_solver_options;
- linear_solver_options.type = DENSE_QR;
-
- for (int i = 0; i < options.num_threads; ++i) {
- linear_solvers[i] = LinearSolver::Create(linear_solver_options);
- }
-
- for (int i = 0; i < independent_set_offsets_.size() - 1; ++i) {
- const int num_problems =
- independent_set_offsets_[i + 1] - independent_set_offsets_[i];
- // No point paying the price for an OpemMP call if the set is of
- // size zero.
- if (num_problems == 0) {
- continue;
- }
-
-#ifdef CERES_USE_OPENMP
- const int num_inner_iteration_threads =
- min(options.num_threads, num_problems);
- evaluator_options_.num_threads =
- max(1, options.num_threads / num_inner_iteration_threads);
-
- // The parameter blocks in each independent set can be optimized
- // in parallel, since they do not co-occur in any residual block.
-#pragma omp parallel for num_threads(num_inner_iteration_threads)
-#endif
- for (int j = independent_set_offsets_[i];
- j < independent_set_offsets_[i + 1];
- ++j) {
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
-
- ParameterBlock* parameter_block = parameter_blocks_[j];
- const int old_index = parameter_block->index();
- const int old_delta_offset = parameter_block->delta_offset();
- parameter_block->SetVarying();
- parameter_block->set_index(0);
- parameter_block->set_delta_offset(0);
-
- Program inner_program;
- inner_program.mutable_parameter_blocks()->push_back(parameter_block);
- *inner_program.mutable_residual_blocks() = residual_blocks_[j];
-
- // TODO(sameeragarwal): Better error handling. Right now we
- // assume that this is not going to lead to problems of any
- // sort. Basically we should be checking for numerical failure
- // of some sort.
- //
- // On the other hand, if the optimization is a failure, that in
- // some ways is fine, since it won't change the parameters and
- // we are fine.
- Solver::Summary inner_summary;
- Solve(&inner_program,
- linear_solvers[thread_id],
- parameters + parameter_block->state_offset(),
- &inner_summary);
-
- parameter_block->set_index(old_index);
- parameter_block->set_delta_offset(old_delta_offset);
- parameter_block->SetState(parameters + parameter_block->state_offset());
- parameter_block->SetConstant();
- }
- }
-
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- parameter_blocks_[i]->SetVarying();
- }
-
- for (int i = 0; i < options.num_threads; ++i) {
- delete linear_solvers[i];
- }
-}
-
-// Solve the optimization problem for one parameter block.
-void CoordinateDescentMinimizer::Solve(Program* program,
- LinearSolver* linear_solver,
- double* parameter,
- Solver::Summary* summary) {
- *summary = Solver::Summary();
- summary->initial_cost = 0.0;
- summary->fixed_cost = 0.0;
- summary->final_cost = 0.0;
- string error;
-
- Minimizer::Options minimizer_options;
- minimizer_options.evaluator.reset(
- CHECK_NOTNULL(Evaluator::Create(evaluator_options_, program, &error)));
- minimizer_options.jacobian.reset(
- CHECK_NOTNULL(minimizer_options.evaluator->CreateJacobian()));
-
- TrustRegionStrategy::Options trs_options;
- trs_options.linear_solver = linear_solver;
- minimizer_options.trust_region_strategy.reset(
- CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options)));
- minimizer_options.is_silent = true;
-
- TrustRegionMinimizer minimizer;
- minimizer.Minimize(minimizer_options, parameter, summary);
-}
-
-bool CoordinateDescentMinimizer::IsOrderingValid(
- const Program& program,
- const ParameterBlockOrdering& ordering,
- string* message) {
- const map<int, set<double*> >& group_to_elements =
- ordering.group_to_elements();
-
- // Verify that each group is an independent set
- map<int, set<double*> >::const_iterator it = group_to_elements.begin();
- for ( ; it != group_to_elements.end(); ++it) {
- if (!program.IsParameterBlockSetIndependent(it->second)) {
- *message =
- StringPrintf("The user-provided "
- "parameter_blocks_for_inner_iterations does not "
- "form an independent set. Group Id: %d", it->first);
- return false;
- }
- }
- return true;
-}
-
-// Find a recursive decomposition of the Hessian matrix as a set
-// of independent sets of decreasing size and invert it. This
-// seems to work better in practice, i.e., Cameras before
-// points.
-ParameterBlockOrdering* CoordinateDescentMinimizer::CreateOrdering(
- const Program& program) {
- scoped_ptr<ParameterBlockOrdering> ordering(new ParameterBlockOrdering);
- ComputeRecursiveIndependentSetOrdering(program, ordering.get());
- ordering->Reverse();
- return ordering.release();
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
deleted file mode 100644
index c1f8ffcd02a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
-#define CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
-
-#include <string>
-#include <vector>
-
-#include "ceres/evaluator.h"
-#include "ceres/minimizer.h"
-#include "ceres/problem_impl.h"
-#include "ceres/solver.h"
-
-namespace ceres {
-namespace internal {
-
-class Program;
-class LinearSolver;
-
-// Given a Program, and a ParameterBlockOrdering which partitions
-// (non-exhaustively) the Hessian matrix into independent sets,
-// perform coordinate descent on the parameter blocks in the
-// ordering. The independent set structure allows for all parameter
-// blocks in the same independent set to be optimized in parallel, and
-// the order of the independent set determines the order in which the
-// parameter block groups are optimized.
-//
-// The minimizer assumes that none of the parameter blocks in the
-// program are constant.
-class CoordinateDescentMinimizer : public Minimizer {
- public:
- bool Init(const Program& program,
- const ProblemImpl::ParameterMap& parameter_map,
- const ParameterBlockOrdering& ordering,
- string* error);
-
- // Minimizer interface.
- virtual ~CoordinateDescentMinimizer();
- virtual void Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary);
-
- // Verify that each group in the ordering forms an independent set.
- static bool IsOrderingValid(const Program& program,
- const ParameterBlockOrdering& ordering,
- string* message);
-
- // Find a recursive decomposition of the Hessian matrix as a set
- // of independent sets of decreasing size and invert it. This
- // seems to work better in practice, i.e., Cameras before
- // points.
- static ParameterBlockOrdering* CreateOrdering(const Program& program);
-
- private:
- void Solve(Program* program,
- LinearSolver* linear_solver,
- double* parameters,
- Solver::Summary* summary);
-
- vector<ParameterBlock*> parameter_blocks_;
- vector<vector<ResidualBlock*> > residual_blocks_;
- // The optimization is performed in rounds. In each round all the
- // parameter blocks that form one independent set are optimized in
- // parallel. This array, marks the boundaries of the independent
- // sets in parameter_blocks_.
- vector<int> independent_set_offsets_;
-
- Evaluator::Options evaluator_options_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
deleted file mode 100644
index 581fc6d4fc0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/corrector.h"
-
-#include <cstddef>
-#include <cmath>
-#include "ceres/internal/eigen.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-Corrector::Corrector(const double sq_norm, const double rho[3]) {
- CHECK_GE(sq_norm, 0.0);
- sqrt_rho1_ = sqrt(rho[1]);
-
- // If sq_norm = 0.0, the correction becomes trivial, the residual
- // and the jacobian are scaled by the squareroot of the derivative
- // of rho. Handling this case explicitly avoids the divide by zero
- // error that would occur below.
- //
- // The case where rho'' < 0 also gets special handling. Technically
- // it shouldn't, and the computation of the scaling should proceed
- // as below, however we found in experiments that applying the
- // curvature correction when rho'' < 0, which is the case when we
- // are in the outlier region slows down the convergence of the
- // algorithm significantly.
- //
- // Thus, we have divided the action of the robustifier into two
- // parts. In the inliner region, we do the full second order
- // correction which re-wights the gradient of the function by the
- // square root of the derivative of rho, and the Gauss-Newton
- // Hessian gets both the scaling and the rank-1 curvature
- // correction. Normaly, alpha is upper bounded by one, but with this
- // change, alpha is bounded above by zero.
- //
- // Empirically we have observed that the full Triggs correction and
- // the clamped correction both start out as very good approximations
- // to the loss function when we are in the convex part of the
- // function, but as the function starts transitioning from convex to
- // concave, the Triggs approximation diverges more and more and
- // ultimately becomes linear. The clamped Triggs model however
- // remains quadratic.
- //
- // The reason why the Triggs approximation becomes so poor is
- // because the curvature correction that it applies to the gauss
- // newton hessian goes from being a full rank correction to a rank
- // deficient correction making the inversion of the Hessian fraught
- // with all sorts of misery and suffering.
- //
- // The clamped correction retains its quadratic nature and inverting it
- // is always well formed.
- if ((sq_norm == 0.0) || (rho[2] <= 0.0)) {
- residual_scaling_ = sqrt_rho1_;
- alpha_sq_norm_ = 0.0;
- return;
- }
-
- // We now require that the first derivative of the loss function be
- // positive only if the second derivative is positive. This is
- // because when the second derivative is non-positive, we do not use
- // the second order correction suggested by BANS and instead use a
- // simpler first order strategy which does not use a division by the
- // gradient of the loss function.
- CHECK_GT(rho[1], 0.0);
-
- // Calculate the smaller of the two solutions to the equation
- //
- // 0.5 * alpha^2 - alpha - rho'' / rho' * z'z = 0.
- //
- // Start by calculating the discriminant D.
- const double D = 1.0 + 2.0 * sq_norm * rho[2] / rho[1];
-
- // Since both rho[1] and rho[2] are guaranteed to be positive at
- // this point, we know that D > 1.0.
-
- const double alpha = 1.0 - sqrt(D);
-
- // Calculate the constants needed by the correction routines.
- residual_scaling_ = sqrt_rho1_ / (1 - alpha);
- alpha_sq_norm_ = alpha / sq_norm;
-}
-
-void Corrector::CorrectResiduals(const int num_rows, double* residuals) {
- DCHECK(residuals != NULL);
- // Equation 11 in BANS.
- VectorRef(residuals, num_rows) *= residual_scaling_;
-}
-
-void Corrector::CorrectJacobian(const int num_rows,
- const int num_cols,
- double* residuals,
- double* jacobian) {
- DCHECK(residuals != NULL);
- DCHECK(jacobian != NULL);
-
- // The common case (rho[2] <= 0).
- if (alpha_sq_norm_ == 0.0) {
- VectorRef(jacobian, num_rows * num_cols) *= sqrt_rho1_;
- return;
- }
-
- // Equation 11 in BANS.
- //
- // J = sqrt(rho) * (J - alpha^2 r * r' J)
- //
- // In days gone by this loop used to be a single Eigen expression of
- // the form
- //
- // J = sqrt_rho1_ * (J - alpha_sq_norm_ * r* (r.transpose() * J));
- //
- // Which turns out to about 17x slower on bal problems. The reason
- // is that Eigen is unable to figure out that this expression can be
- // evaluated columnwise and ends up creating a temporary.
- for (int c = 0; c < num_cols; ++c) {
- double r_transpose_j = 0.0;
- for (int r = 0; r < num_rows; ++r) {
- r_transpose_j += jacobian[r * num_cols + c] * residuals[r];
- }
-
- for (int r = 0; r < num_rows; ++r) {
- jacobian[r * num_cols + c] = sqrt_rho1_ *
- (jacobian[r * num_cols + c] -
- alpha_sq_norm_ * residuals[r] * r_transpose_j);
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/corrector.h b/extern/libmv/third_party/ceres/internal/ceres/corrector.h
deleted file mode 100644
index 2137221784e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/corrector.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Class definition for the object that is responsible for applying a
-// second order correction to the Gauss-Newton based on the ideas in
-// BANS by Triggs et al.
-
-#ifndef CERES_INTERNAL_CORRECTOR_H_
-#define CERES_INTERNAL_CORRECTOR_H_
-
-namespace ceres {
-namespace internal {
-
-// Corrector is responsible for applying the second order correction
-// to the residual and jacobian of a least squares problem based on a
-// radial robust loss.
-//
-// The key idea here is to look at the expressions for the robustified
-// gauss newton approximation and then take its squareroot to get the
-// corresponding corrections to the residual and jacobian. For the
-// full expressions see Eq. 10 and 11 in BANS by Triggs et al.
-class Corrector {
- public:
- // The constructor takes the squared norm, the value, the first and
- // second derivatives of the LossFunction. It precalculates some of
- // the constants that are needed to apply the correction. The
- // correction constant alpha is constrained to be smaller than 1, if
- // it becomes larger than 1, then it will reverse the sign of the
- // residual and the correction. If alpha is equal to 1 will result
- // in a divide by zero error. Thus we constrain alpha to be upper
- // bounded by 1 - epsilon_.
- //
- // rho[1] needs to be positive. The constructor will crash if this
- // condition is not met.
- //
- // In practical use CorrectJacobian should always be called before
- // CorrectResidual, because the jacobian correction depends on the
- // value of the uncorrected residual values.
- explicit Corrector(double sq_norm, const double rho[3]);
-
- // residuals *= sqrt(rho[1]) / (1 - alpha)
- void CorrectResiduals(int num_rows, double* residuals);
-
- // jacobian = sqrt(rho[1]) * jacobian -
- // sqrt(rho[1]) * alpha / sq_norm * residuals residuals' * jacobian.
- //
- // The method assumes that the jacobian has row-major storage. It is
- // the caller's responsibility to ensure that the pointer to
- // jacobian is not null.
- void CorrectJacobian(int num_rows,
- int num_cols,
- double* residuals,
- double* jacobian);
-
- private:
- double sqrt_rho1_;
- double residual_scaling_;
- double alpha_sq_norm_;
-};
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_CORRECTOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/covariance.cc b/extern/libmv/third_party/ceres/internal/ceres/covariance.cc
deleted file mode 100644
index 35146c582b2..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/covariance.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/covariance.h"
-
-#include <utility>
-#include <vector>
-#include "ceres/covariance_impl.h"
-#include "ceres/problem.h"
-#include "ceres/problem_impl.h"
-
-namespace ceres {
-
-Covariance::Covariance(const Covariance::Options& options) {
- impl_.reset(new internal::CovarianceImpl(options));
-}
-
-Covariance::~Covariance() {
-}
-
-bool Covariance::Compute(
- const vector<pair<const double*, const double*> >& covariance_blocks,
- Problem* problem) {
- return impl_->Compute(covariance_blocks, problem->problem_impl_.get());
-}
-
-bool Covariance::GetCovarianceBlock(const double* parameter_block1,
- const double* parameter_block2,
- double* covariance_block) const {
- return impl_->GetCovarianceBlock(parameter_block1,
- parameter_block2,
- covariance_block);
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/covariance_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/covariance_impl.cc
deleted file mode 100644
index cfbfb445343..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/covariance_impl.cc
+++ /dev/null
@@ -1,760 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/covariance_impl.h"
-
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
-#include <algorithm>
-#include <cstdlib>
-#include <utility>
-#include <vector>
-#include "Eigen/SparseCore"
-
-// Suppress unused local variable warning from Eigen Ordering.h #included by
-// SparseQR in Eigen 3.2.0. This was fixed in Eigen 3.2.1, but 3.2.0 is still
-// widely used (Ubuntu 14.04), and Ceres won't compile otherwise due to -Werror.
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4189 )
-#else
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
-#endif
-#include "Eigen/SparseQR"
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#else
-#pragma GCC diagnostic pop
-#endif
-
-#include "Eigen/SVD"
-#include "ceres/compressed_col_sparse_matrix_utils.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/covariance.h"
-#include "ceres/crs_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/map_util.h"
-#include "ceres/parameter_block.h"
-#include "ceres/problem_impl.h"
-#include "ceres/suitesparse.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-typedef vector<pair<const double*, const double*> > CovarianceBlocks;
-
-CovarianceImpl::CovarianceImpl(const Covariance::Options& options)
- : options_(options),
- is_computed_(false),
- is_valid_(false) {
-#ifndef CERES_USE_OPENMP
- if (options_.num_threads > 1) {
- LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_threads = 1 is supported. Switching "
- << "to single threaded mode.";
- options_.num_threads = 1;
- }
-#endif
- evaluate_options_.num_threads = options_.num_threads;
- evaluate_options_.apply_loss_function = options_.apply_loss_function;
-}
-
-CovarianceImpl::~CovarianceImpl() {
-}
-
-bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks,
- ProblemImpl* problem) {
- problem_ = problem;
- parameter_block_to_row_index_.clear();
- covariance_matrix_.reset(NULL);
- is_valid_ = (ComputeCovarianceSparsity(covariance_blocks, problem) &&
- ComputeCovarianceValues());
- is_computed_ = true;
- return is_valid_;
-}
-
-bool CovarianceImpl::GetCovarianceBlock(const double* original_parameter_block1,
- const double* original_parameter_block2,
- double* covariance_block) const {
- CHECK(is_computed_)
- << "Covariance::GetCovarianceBlock called before Covariance::Compute";
- CHECK(is_valid_)
- << "Covariance::GetCovarianceBlock called when Covariance::Compute "
- << "returned false.";
-
- // If either of the two parameter blocks is constant, then the
- // covariance block is also zero.
- if (constant_parameter_blocks_.count(original_parameter_block1) > 0 ||
- constant_parameter_blocks_.count(original_parameter_block2) > 0) {
- const ProblemImpl::ParameterMap& parameter_map = problem_->parameter_map();
- ParameterBlock* block1 =
- FindOrDie(parameter_map,
- const_cast<double*>(original_parameter_block1));
-
- ParameterBlock* block2 =
- FindOrDie(parameter_map,
- const_cast<double*>(original_parameter_block2));
- const int block1_size = block1->Size();
- const int block2_size = block2->Size();
- MatrixRef(covariance_block, block1_size, block2_size).setZero();
- return true;
- }
-
- const double* parameter_block1 = original_parameter_block1;
- const double* parameter_block2 = original_parameter_block2;
- const bool transpose = parameter_block1 > parameter_block2;
- if (transpose) {
- std::swap(parameter_block1, parameter_block2);
- }
-
- // Find where in the covariance matrix the block is located.
- const int row_begin =
- FindOrDie(parameter_block_to_row_index_, parameter_block1);
- const int col_begin =
- FindOrDie(parameter_block_to_row_index_, parameter_block2);
- const int* rows = covariance_matrix_->rows();
- const int* cols = covariance_matrix_->cols();
- const int row_size = rows[row_begin + 1] - rows[row_begin];
- const int* cols_begin = cols + rows[row_begin];
-
- // The only part that requires work is walking the compressed column
- // vector to determine where the set of columns correspnding to the
- // covariance block begin.
- int offset = 0;
- while (cols_begin[offset] != col_begin && offset < row_size) {
- ++offset;
- }
-
- if (offset == row_size) {
- LOG(ERROR) << "Unable to find covariance block for "
- << original_parameter_block1 << " "
- << original_parameter_block2;
- return false;
- }
-
- const ProblemImpl::ParameterMap& parameter_map = problem_->parameter_map();
- ParameterBlock* block1 =
- FindOrDie(parameter_map, const_cast<double*>(parameter_block1));
- ParameterBlock* block2 =
- FindOrDie(parameter_map, const_cast<double*>(parameter_block2));
- const LocalParameterization* local_param1 = block1->local_parameterization();
- const LocalParameterization* local_param2 = block2->local_parameterization();
- const int block1_size = block1->Size();
- const int block1_local_size = block1->LocalSize();
- const int block2_size = block2->Size();
- const int block2_local_size = block2->LocalSize();
-
- ConstMatrixRef cov(covariance_matrix_->values() + rows[row_begin],
- block1_size,
- row_size);
-
- // Fast path when there are no local parameterizations.
- if (local_param1 == NULL && local_param2 == NULL) {
- if (transpose) {
- MatrixRef(covariance_block, block2_size, block1_size) =
- cov.block(0, offset, block1_size, block2_size).transpose();
- } else {
- MatrixRef(covariance_block, block1_size, block2_size) =
- cov.block(0, offset, block1_size, block2_size);
- }
- return true;
- }
-
- // If local parameterizations are used then the covariance that has
- // been computed is in the tangent space and it needs to be lifted
- // back to the ambient space.
- //
- // This is given by the formula
- //
- // C'_12 = J_1 C_12 J_2'
- //
- // Where C_12 is the local tangent space covariance for parameter
- // blocks 1 and 2. J_1 and J_2 are respectively the local to global
- // jacobians for parameter blocks 1 and 2.
- //
- // See Result 5.11 on page 142 of Hartley & Zisserman (2nd Edition)
- // for a proof.
- //
- // TODO(sameeragarwal): Add caching of local parameterization, so
- // that they are computed just once per parameter block.
- Matrix block1_jacobian(block1_size, block1_local_size);
- if (local_param1 == NULL) {
- block1_jacobian.setIdentity();
- } else {
- local_param1->ComputeJacobian(parameter_block1, block1_jacobian.data());
- }
-
- Matrix block2_jacobian(block2_size, block2_local_size);
- // Fast path if the user is requesting a diagonal block.
- if (parameter_block1 == parameter_block2) {
- block2_jacobian = block1_jacobian;
- } else {
- if (local_param2 == NULL) {
- block2_jacobian.setIdentity();
- } else {
- local_param2->ComputeJacobian(parameter_block2, block2_jacobian.data());
- }
- }
-
- if (transpose) {
- MatrixRef(covariance_block, block2_size, block1_size) =
- block2_jacobian *
- cov.block(0, offset, block1_local_size, block2_local_size).transpose() *
- block1_jacobian.transpose();
- } else {
- MatrixRef(covariance_block, block1_size, block2_size) =
- block1_jacobian *
- cov.block(0, offset, block1_local_size, block2_local_size) *
- block2_jacobian.transpose();
- }
-
- return true;
-}
-
-// Determine the sparsity pattern of the covariance matrix based on
-// the block pairs requested by the user.
-bool CovarianceImpl::ComputeCovarianceSparsity(
- const CovarianceBlocks& original_covariance_blocks,
- ProblemImpl* problem) {
- EventLogger event_logger("CovarianceImpl::ComputeCovarianceSparsity");
-
- // Determine an ordering for the parameter block, by sorting the
- // parameter blocks by their pointers.
- vector<double*> all_parameter_blocks;
- problem->GetParameterBlocks(&all_parameter_blocks);
- const ProblemImpl::ParameterMap& parameter_map = problem->parameter_map();
- constant_parameter_blocks_.clear();
- vector<double*>& active_parameter_blocks = evaluate_options_.parameter_blocks;
- active_parameter_blocks.clear();
- for (int i = 0; i < all_parameter_blocks.size(); ++i) {
- double* parameter_block = all_parameter_blocks[i];
-
- ParameterBlock* block = FindOrDie(parameter_map, parameter_block);
- if (block->IsConstant()) {
- constant_parameter_blocks_.insert(parameter_block);
- } else {
- active_parameter_blocks.push_back(parameter_block);
- }
- }
-
- sort(active_parameter_blocks.begin(), active_parameter_blocks.end());
-
- // Compute the number of rows. Map each parameter block to the
- // first row corresponding to it in the covariance matrix using the
- // ordering of parameter blocks just constructed.
- int num_rows = 0;
- parameter_block_to_row_index_.clear();
- for (int i = 0; i < active_parameter_blocks.size(); ++i) {
- double* parameter_block = active_parameter_blocks[i];
- const int parameter_block_size =
- problem->ParameterBlockLocalSize(parameter_block);
- parameter_block_to_row_index_[parameter_block] = num_rows;
- num_rows += parameter_block_size;
- }
-
- // Compute the number of non-zeros in the covariance matrix. Along
- // the way flip any covariance blocks which are in the lower
- // triangular part of the matrix.
- int num_nonzeros = 0;
- CovarianceBlocks covariance_blocks;
- for (int i = 0; i < original_covariance_blocks.size(); ++i) {
- const pair<const double*, const double*>& block_pair =
- original_covariance_blocks[i];
- if (constant_parameter_blocks_.count(block_pair.first) > 0 ||
- constant_parameter_blocks_.count(block_pair.second) > 0) {
- continue;
- }
-
- int index1 = FindOrDie(parameter_block_to_row_index_, block_pair.first);
- int index2 = FindOrDie(parameter_block_to_row_index_, block_pair.second);
- const int size1 = problem->ParameterBlockLocalSize(block_pair.first);
- const int size2 = problem->ParameterBlockLocalSize(block_pair.second);
- num_nonzeros += size1 * size2;
-
- // Make sure we are constructing a block upper triangular matrix.
- if (index1 > index2) {
- covariance_blocks.push_back(make_pair(block_pair.second,
- block_pair.first));
- } else {
- covariance_blocks.push_back(block_pair);
- }
- }
-
- if (covariance_blocks.size() == 0) {
- VLOG(2) << "No non-zero covariance blocks found";
- covariance_matrix_.reset(NULL);
- return true;
- }
-
- // Sort the block pairs. As a consequence we get the covariance
- // blocks as they will occur in the CompressedRowSparseMatrix that
- // will store the covariance.
- sort(covariance_blocks.begin(), covariance_blocks.end());
-
- // Fill the sparsity pattern of the covariance matrix.
- covariance_matrix_.reset(
- new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros));
-
- int* rows = covariance_matrix_->mutable_rows();
- int* cols = covariance_matrix_->mutable_cols();
-
- // Iterate over parameter blocks and in turn over the rows of the
- // covariance matrix. For each parameter block, look in the upper
- // triangular part of the covariance matrix to see if there are any
- // blocks requested by the user. If this is the case then fill out a
- // set of compressed rows corresponding to this parameter block.
- //
- // The key thing that makes this loop work is the fact that the
- // row/columns of the covariance matrix are ordered by the pointer
- // values of the parameter blocks. Thus iterating over the keys of
- // parameter_block_to_row_index_ corresponds to iterating over the
- // rows of the covariance matrix in order.
- int i = 0; // index into covariance_blocks.
- int cursor = 0; // index into the covariance matrix.
- for (map<const double*, int>::const_iterator it =
- parameter_block_to_row_index_.begin();
- it != parameter_block_to_row_index_.end();
- ++it) {
- const double* row_block = it->first;
- const int row_block_size = problem->ParameterBlockLocalSize(row_block);
- int row_begin = it->second;
-
- // Iterate over the covariance blocks contained in this row block
- // and count the number of columns in this row block.
- int num_col_blocks = 0;
- int num_columns = 0;
- for (int j = i; j < covariance_blocks.size(); ++j, ++num_col_blocks) {
- const pair<const double*, const double*>& block_pair =
- covariance_blocks[j];
- if (block_pair.first != row_block) {
- break;
- }
- num_columns += problem->ParameterBlockLocalSize(block_pair.second);
- }
-
- // Fill out all the compressed rows for this parameter block.
- for (int r = 0; r < row_block_size; ++r) {
- rows[row_begin + r] = cursor;
- for (int c = 0; c < num_col_blocks; ++c) {
- const double* col_block = covariance_blocks[i + c].second;
- const int col_block_size = problem->ParameterBlockLocalSize(col_block);
- int col_begin = FindOrDie(parameter_block_to_row_index_, col_block);
- for (int k = 0; k < col_block_size; ++k) {
- cols[cursor++] = col_begin++;
- }
- }
- }
-
- i+= num_col_blocks;
- }
-
- rows[num_rows] = cursor;
- return true;
-}
-
-bool CovarianceImpl::ComputeCovarianceValues() {
- switch (options_.algorithm_type) {
- case DENSE_SVD:
- return ComputeCovarianceValuesUsingDenseSVD();
-#ifndef CERES_NO_SUITESPARSE
- case SUITE_SPARSE_QR:
- return ComputeCovarianceValuesUsingSuiteSparseQR();
-#else
- LOG(ERROR) << "SuiteSparse is required to use the "
- << "SUITE_SPARSE_QR algorithm.";
- return false;
-#endif
- case EIGEN_SPARSE_QR:
- return ComputeCovarianceValuesUsingEigenSparseQR();
- default:
- LOG(ERROR) << "Unsupported covariance estimation algorithm type: "
- << CovarianceAlgorithmTypeToString(options_.algorithm_type);
- return false;
- }
- return false;
-}
-
-bool CovarianceImpl::ComputeCovarianceValuesUsingSuiteSparseQR() {
- EventLogger event_logger(
- "CovarianceImpl::ComputeCovarianceValuesUsingSparseQR");
-
-#ifndef CERES_NO_SUITESPARSE
- if (covariance_matrix_.get() == NULL) {
- // Nothing to do, all zeros covariance matrix.
- return true;
- }
-
- CRSMatrix jacobian;
- problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
- event_logger.AddEvent("Evaluate");
-
- // Construct a compressed column form of the Jacobian.
- const int num_rows = jacobian.num_rows;
- const int num_cols = jacobian.num_cols;
- const int num_nonzeros = jacobian.values.size();
-
- vector<SuiteSparse_long> transpose_rows(num_cols + 1, 0);
- vector<SuiteSparse_long> transpose_cols(num_nonzeros, 0);
- vector<double> transpose_values(num_nonzeros, 0);
-
- for (int idx = 0; idx < num_nonzeros; ++idx) {
- transpose_rows[jacobian.cols[idx] + 1] += 1;
- }
-
- for (int i = 1; i < transpose_rows.size(); ++i) {
- transpose_rows[i] += transpose_rows[i - 1];
- }
-
- for (int r = 0; r < num_rows; ++r) {
- for (int idx = jacobian.rows[r]; idx < jacobian.rows[r + 1]; ++idx) {
- const int c = jacobian.cols[idx];
- const int transpose_idx = transpose_rows[c];
- transpose_cols[transpose_idx] = r;
- transpose_values[transpose_idx] = jacobian.values[idx];
- ++transpose_rows[c];
- }
- }
-
- for (int i = transpose_rows.size() - 1; i > 0 ; --i) {
- transpose_rows[i] = transpose_rows[i - 1];
- }
- transpose_rows[0] = 0;
-
- cholmod_sparse cholmod_jacobian;
- cholmod_jacobian.nrow = num_rows;
- cholmod_jacobian.ncol = num_cols;
- cholmod_jacobian.nzmax = num_nonzeros;
- cholmod_jacobian.nz = NULL;
- cholmod_jacobian.p = reinterpret_cast<void*>(&transpose_rows[0]);
- cholmod_jacobian.i = reinterpret_cast<void*>(&transpose_cols[0]);
- cholmod_jacobian.x = reinterpret_cast<void*>(&transpose_values[0]);
- cholmod_jacobian.z = NULL;
- cholmod_jacobian.stype = 0; // Matrix is not symmetric.
- cholmod_jacobian.itype = CHOLMOD_LONG;
- cholmod_jacobian.xtype = CHOLMOD_REAL;
- cholmod_jacobian.dtype = CHOLMOD_DOUBLE;
- cholmod_jacobian.sorted = 1;
- cholmod_jacobian.packed = 1;
-
- cholmod_common cc;
- cholmod_l_start(&cc);
-
- cholmod_sparse* R = NULL;
- SuiteSparse_long* permutation = NULL;
-
- // Compute a Q-less QR factorization of the Jacobian. Since we are
- // only interested in inverting J'J = R'R, we do not need Q. This
- // saves memory and gives us R as a permuted compressed column
- // sparse matrix.
- //
- // TODO(sameeragarwal): Currently the symbolic factorization and the
- // numeric factorization is done at the same time, and this does not
- // explicitly account for the block column and row structure in the
- // matrix. When using AMD, we have observed in the past that
- // computing the ordering with the block matrix is significantly
- // more efficient, both in runtime as well as the quality of
- // ordering computed. So, it maybe worth doing that analysis
- // separately.
- const SuiteSparse_long rank =
- SuiteSparseQR<double>(SPQR_ORDERING_BESTAMD,
- SPQR_DEFAULT_TOL,
- cholmod_jacobian.ncol,
- &cholmod_jacobian,
- &R,
- &permutation,
- &cc);
- event_logger.AddEvent("Numeric Factorization");
- CHECK_NOTNULL(permutation);
- CHECK_NOTNULL(R);
-
- if (rank < cholmod_jacobian.ncol) {
- LOG(ERROR) << "Jacobian matrix is rank deficient. "
- << "Number of columns: " << cholmod_jacobian.ncol
- << " rank: " << rank;
- free(permutation);
- cholmod_l_free_sparse(&R, &cc);
- cholmod_l_finish(&cc);
- return false;
- }
-
- vector<int> inverse_permutation(num_cols);
- for (SuiteSparse_long i = 0; i < num_cols; ++i) {
- inverse_permutation[permutation[i]] = i;
- }
-
- const int* rows = covariance_matrix_->rows();
- const int* cols = covariance_matrix_->cols();
- double* values = covariance_matrix_->mutable_values();
-
- // The following loop exploits the fact that the i^th column of A^{-1}
- // is given by the solution to the linear system
- //
- // A x = e_i
- //
- // where e_i is a vector with e(i) = 1 and all other entries zero.
- //
- // Since the covariance matrix is symmetric, the i^th row and column
- // are equal.
- const int num_threads = options_.num_threads;
- scoped_array<double> workspace(new double[num_threads * num_cols]);
-
-#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
- for (int r = 0; r < num_cols; ++r) {
- const int row_begin = rows[r];
- const int row_end = rows[r + 1];
- if (row_end == row_begin) {
- continue;
- }
-
-# ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-# else
- int thread_id = 0;
-# endif
-
- double* solution = workspace.get() + thread_id * num_cols;
- SolveRTRWithSparseRHS<SuiteSparse_long>(
- num_cols,
- static_cast<SuiteSparse_long*>(R->i),
- static_cast<SuiteSparse_long*>(R->p),
- static_cast<double*>(R->x),
- inverse_permutation[r],
- solution);
- for (int idx = row_begin; idx < row_end; ++idx) {
- const int c = cols[idx];
- values[idx] = solution[inverse_permutation[c]];
- }
- }
-
- free(permutation);
- cholmod_l_free_sparse(&R, &cc);
- cholmod_l_finish(&cc);
- event_logger.AddEvent("Inversion");
- return true;
-
-#else // CERES_NO_SUITESPARSE
-
- return false;
-
-#endif // CERES_NO_SUITESPARSE
-}
-
-bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
- EventLogger event_logger(
- "CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD");
- if (covariance_matrix_.get() == NULL) {
- // Nothing to do, all zeros covariance matrix.
- return true;
- }
-
- CRSMatrix jacobian;
- problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
- event_logger.AddEvent("Evaluate");
-
- Matrix dense_jacobian(jacobian.num_rows, jacobian.num_cols);
- dense_jacobian.setZero();
- for (int r = 0; r < jacobian.num_rows; ++r) {
- for (int idx = jacobian.rows[r]; idx < jacobian.rows[r + 1]; ++idx) {
- const int c = jacobian.cols[idx];
- dense_jacobian(r, c) = jacobian.values[idx];
- }
- }
- event_logger.AddEvent("ConvertToDenseMatrix");
-
- Eigen::JacobiSVD<Matrix> svd(dense_jacobian,
- Eigen::ComputeThinU | Eigen::ComputeThinV);
-
- event_logger.AddEvent("SingularValueDecomposition");
-
- const Vector singular_values = svd.singularValues();
- const int num_singular_values = singular_values.rows();
- Vector inverse_squared_singular_values(num_singular_values);
- inverse_squared_singular_values.setZero();
-
- const double max_singular_value = singular_values[0];
- const double min_singular_value_ratio =
- sqrt(options_.min_reciprocal_condition_number);
-
- const bool automatic_truncation = (options_.null_space_rank < 0);
- const int max_rank = min(num_singular_values,
- num_singular_values - options_.null_space_rank);
-
- // Compute the squared inverse of the singular values. Truncate the
- // computation based on min_singular_value_ratio and
- // null_space_rank. When either of these two quantities are active,
- // the resulting covariance matrix is a Moore-Penrose inverse
- // instead of a regular inverse.
- for (int i = 0; i < max_rank; ++i) {
- const double singular_value_ratio = singular_values[i] / max_singular_value;
- if (singular_value_ratio < min_singular_value_ratio) {
- // Since the singular values are in decreasing order, if
- // automatic truncation is enabled, then from this point on
- // all values will fail the ratio test and there is nothing to
- // do in this loop.
- if (automatic_truncation) {
- break;
- } else {
- LOG(ERROR) << "Cholesky factorization of J'J is not reliable. "
- << "Reciprocal condition number: "
- << singular_value_ratio * singular_value_ratio << " "
- << "min_reciprocal_condition_number: "
- << options_.min_reciprocal_condition_number;
- return false;
- }
- }
-
- inverse_squared_singular_values[i] =
- 1.0 / (singular_values[i] * singular_values[i]);
- }
-
- Matrix dense_covariance =
- svd.matrixV() *
- inverse_squared_singular_values.asDiagonal() *
- svd.matrixV().transpose();
- event_logger.AddEvent("PseudoInverse");
-
- const int num_rows = covariance_matrix_->num_rows();
- const int* rows = covariance_matrix_->rows();
- const int* cols = covariance_matrix_->cols();
- double* values = covariance_matrix_->mutable_values();
-
- for (int r = 0; r < num_rows; ++r) {
- for (int idx = rows[r]; idx < rows[r + 1]; ++idx) {
- const int c = cols[idx];
- values[idx] = dense_covariance(r, c);
- }
- }
- event_logger.AddEvent("CopyToCovarianceMatrix");
- return true;
-}
-
-bool CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR() {
- EventLogger event_logger(
- "CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR");
- if (covariance_matrix_.get() == NULL) {
- // Nothing to do, all zeros covariance matrix.
- return true;
- }
-
- CRSMatrix jacobian;
- problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
- event_logger.AddEvent("Evaluate");
-
- typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix;
-
- // Convert the matrix to column major order as required by SparseQR.
- EigenSparseMatrix sparse_jacobian =
- Eigen::MappedSparseMatrix<double, Eigen::RowMajor>(
- jacobian.num_rows, jacobian.num_cols,
- static_cast<int>(jacobian.values.size()),
- jacobian.rows.data(), jacobian.cols.data(), jacobian.values.data());
- event_logger.AddEvent("ConvertToSparseMatrix");
-
- Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int> >
- qr_solver(sparse_jacobian);
- event_logger.AddEvent("QRDecomposition");
-
- if(qr_solver.info() != Eigen::Success) {
- LOG(ERROR) << "Eigen::SparseQR decomposition failed.";
- return false;
- }
-
- if (qr_solver.rank() < jacobian.num_cols) {
- LOG(ERROR) << "Jacobian matrix is rank deficient. "
- << "Number of columns: " << jacobian.num_cols
- << " rank: " << qr_solver.rank();
- return false;
- }
-
- const int* rows = covariance_matrix_->rows();
- const int* cols = covariance_matrix_->cols();
- double* values = covariance_matrix_->mutable_values();
-
- // Compute the inverse column permutation used by QR factorization.
- Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> inverse_permutation =
- qr_solver.colsPermutation().inverse();
-
- // The following loop exploits the fact that the i^th column of A^{-1}
- // is given by the solution to the linear system
- //
- // A x = e_i
- //
- // where e_i is a vector with e(i) = 1 and all other entries zero.
- //
- // Since the covariance matrix is symmetric, the i^th row and column
- // are equal.
- const int num_cols = jacobian.num_cols;
- const int num_threads = options_.num_threads;
- scoped_array<double> workspace(new double[num_threads * num_cols]);
-
-#pragma omp parallel for num_threads(num_threads) schedule(dynamic)
- for (int r = 0; r < num_cols; ++r) {
- const int row_begin = rows[r];
- const int row_end = rows[r + 1];
- if (row_end == row_begin) {
- continue;
- }
-
-# ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-# else
- int thread_id = 0;
-# endif
-
- double* solution = workspace.get() + thread_id * num_cols;
- SolveRTRWithSparseRHS<int>(
- num_cols,
- qr_solver.matrixR().innerIndexPtr(),
- qr_solver.matrixR().outerIndexPtr(),
- &qr_solver.matrixR().data().value(0),
- inverse_permutation.indices().coeff(r),
- solution);
-
- // Assign the values of the computed covariance using the
- // inverse permutation used in the QR factorization.
- for (int idx = row_begin; idx < row_end; ++idx) {
- const int c = cols[idx];
- values[idx] = solution[inverse_permutation.indices().coeff(c)];
- }
- }
-
- event_logger.AddEvent("Inverse");
-
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/covariance_impl.h b/extern/libmv/third_party/ceres/internal/ceres/covariance_impl.h
deleted file mode 100644
index 135f4a1d624..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/covariance_impl.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_COVARIANCE_IMPL_H_
-#define CERES_INTERNAL_COVARIANCE_IMPL_H_
-
-#include <map>
-#include <set>
-#include <utility>
-#include <vector>
-#include "ceres/covariance.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/problem_impl.h"
-#include "ceres/suitesparse.h"
-
-namespace ceres {
-
-namespace internal {
-
-class CompressedRowSparseMatrix;
-
-class CovarianceImpl {
- public:
- explicit CovarianceImpl(const Covariance::Options& options);
- ~CovarianceImpl();
-
- bool Compute(
- const vector<pair<const double*, const double*> >& covariance_blocks,
- ProblemImpl* problem);
-
- bool GetCovarianceBlock(const double* parameter_block1,
- const double* parameter_block2,
- double* covariance_block) const;
-
- bool ComputeCovarianceSparsity(
- const vector<pair<const double*, const double*> >& covariance_blocks,
- ProblemImpl* problem);
-
- bool ComputeCovarianceValues();
- bool ComputeCovarianceValuesUsingDenseSVD();
- bool ComputeCovarianceValuesUsingSuiteSparseQR();
- bool ComputeCovarianceValuesUsingEigenSparseQR();
-
- const CompressedRowSparseMatrix* covariance_matrix() const {
- return covariance_matrix_.get();
- }
-
- private:
- ProblemImpl* problem_;
- Covariance::Options options_;
- Problem::EvaluateOptions evaluate_options_;
- bool is_computed_;
- bool is_valid_;
- map<const double*, int> parameter_block_to_row_index_;
- set<const double*> constant_parameter_blocks_;
- scoped_ptr<CompressedRowSparseMatrix> covariance_matrix_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_COVARIANCE_IMPL_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
deleted file mode 100644
index 87503d06c99..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
+++ /dev/null
@@ -1,217 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: strandmark@google.com (Petter Strandmark)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-#include "ceres/cxsparse.h"
-
-#include <vector>
-#include "ceres/compressed_col_sparse_matrix_utils.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/internal/port.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-CXSparse::CXSparse() : scratch_(NULL), scratch_size_(0) {
-}
-
-CXSparse::~CXSparse() {
- if (scratch_size_ > 0) {
- cs_di_free(scratch_);
- }
-}
-
-
-bool CXSparse::SolveCholesky(cs_di* A,
- cs_dis* symbolic_factorization,
- double* b) {
- // Make sure we have enough scratch space available.
- if (scratch_size_ < A->n) {
- if (scratch_size_ > 0) {
- cs_di_free(scratch_);
- }
- scratch_ =
- reinterpret_cast<CS_ENTRY*>(cs_di_malloc(A->n, sizeof(CS_ENTRY)));
- scratch_size_ = A->n;
- }
-
- // Solve using Cholesky factorization
- csn* numeric_factorization = cs_di_chol(A, symbolic_factorization);
- if (numeric_factorization == NULL) {
- LOG(WARNING) << "Cholesky factorization failed.";
- return false;
- }
-
- // When the Cholesky factorization succeeded, these methods are
- // guaranteed to succeeded as well. In the comments below, "x"
- // refers to the scratch space.
- //
- // Set x = P * b.
- cs_di_ipvec(symbolic_factorization->pinv, b, scratch_, A->n);
- // Set x = L \ x.
- cs_di_lsolve(numeric_factorization->L, scratch_);
- // Set x = L' \ x.
- cs_di_ltsolve(numeric_factorization->L, scratch_);
- // Set b = P' * x.
- cs_di_pvec(symbolic_factorization->pinv, scratch_, b, A->n);
-
- // Free Cholesky factorization.
- cs_di_nfree(numeric_factorization);
- return true;
-}
-
-cs_dis* CXSparse::AnalyzeCholesky(cs_di* A) {
- // order = 1 for Cholesky factorization.
- return cs_schol(1, A);
-}
-
-cs_dis* CXSparse::AnalyzeCholeskyWithNaturalOrdering(cs_di* A) {
- // order = 0 for Natural ordering.
- return cs_schol(0, A);
-}
-
-cs_dis* CXSparse::BlockAnalyzeCholesky(cs_di* A,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks) {
- const int num_row_blocks = row_blocks.size();
- const int num_col_blocks = col_blocks.size();
-
- vector<int> block_rows;
- vector<int> block_cols;
- CompressedColumnScalarMatrixToBlockMatrix(A->i,
- A->p,
- row_blocks,
- col_blocks,
- &block_rows,
- &block_cols);
- cs_di block_matrix;
- block_matrix.m = num_row_blocks;
- block_matrix.n = num_col_blocks;
- block_matrix.nz = -1;
- block_matrix.nzmax = block_rows.size();
- block_matrix.p = &block_cols[0];
- block_matrix.i = &block_rows[0];
- block_matrix.x = NULL;
-
- int* ordering = cs_amd(1, &block_matrix);
- vector<int> block_ordering(num_row_blocks, -1);
- copy(ordering, ordering + num_row_blocks, &block_ordering[0]);
- cs_free(ordering);
-
- vector<int> scalar_ordering;
- BlockOrderingToScalarOrdering(row_blocks, block_ordering, &scalar_ordering);
-
- cs_dis* symbolic_factorization =
- reinterpret_cast<cs_dis*>(cs_calloc(1, sizeof(cs_dis)));
- symbolic_factorization->pinv = cs_pinv(&scalar_ordering[0], A->n);
- cs* permuted_A = cs_symperm(A, symbolic_factorization->pinv, 0);
-
- symbolic_factorization->parent = cs_etree(permuted_A, 0);
- int* postordering = cs_post(symbolic_factorization->parent, A->n);
- int* column_counts = cs_counts(permuted_A,
- symbolic_factorization->parent,
- postordering,
- 0);
- cs_free(postordering);
- cs_spfree(permuted_A);
-
- symbolic_factorization->cp = (int*) cs_malloc(A->n+1, sizeof(int));
- symbolic_factorization->lnz = cs_cumsum(symbolic_factorization->cp,
- column_counts,
- A->n);
- symbolic_factorization->unz = symbolic_factorization->lnz;
-
- cs_free(column_counts);
-
- if (symbolic_factorization->lnz < 0) {
- cs_sfree(symbolic_factorization);
- symbolic_factorization = NULL;
- }
-
- return symbolic_factorization;
-}
-
-cs_di CXSparse::CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A) {
- cs_di At;
- At.m = A->num_cols();
- At.n = A->num_rows();
- At.nz = -1;
- At.nzmax = A->num_nonzeros();
- At.p = A->mutable_rows();
- At.i = A->mutable_cols();
- At.x = A->mutable_values();
- return At;
-}
-
-cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) {
- cs_di_sparse tsm_wrapper;
- tsm_wrapper.nzmax = tsm->num_nonzeros();
- tsm_wrapper.nz = tsm->num_nonzeros();
- tsm_wrapper.m = tsm->num_rows();
- tsm_wrapper.n = tsm->num_cols();
- tsm_wrapper.p = tsm->mutable_cols();
- tsm_wrapper.i = tsm->mutable_rows();
- tsm_wrapper.x = tsm->mutable_values();
-
- return cs_compress(&tsm_wrapper);
-}
-
-void CXSparse::ApproximateMinimumDegreeOrdering(cs_di* A, int* ordering) {
- int* cs_ordering = cs_amd(1, A);
- copy(cs_ordering, cs_ordering + A->m, ordering);
- cs_free(cs_ordering);
-}
-
-cs_di* CXSparse::TransposeMatrix(cs_di* A) {
- return cs_di_transpose(A, 1);
-}
-
-cs_di* CXSparse::MatrixMatrixMultiply(cs_di* A, cs_di* B) {
- return cs_di_multiply(A, B);
-}
-
-void CXSparse::Free(cs_di* sparse_matrix) {
- cs_di_spfree(sparse_matrix);
-}
-
-void CXSparse::Free(cs_dis* symbolic_factorization) {
- cs_di_sfree(symbolic_factorization);
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_CXSPARSE
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
deleted file mode 100644
index 5868401b961..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: strandmark@google.com (Petter Strandmark)
-
-#ifndef CERES_INTERNAL_CXSPARSE_H_
-#define CERES_INTERNAL_CXSPARSE_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-#include <vector>
-#include "cs.h"
-
-namespace ceres {
-namespace internal {
-
-class CompressedRowSparseMatrix;
-class TripletSparseMatrix;
-
-// This object provides access to solving linear systems using Cholesky
-// factorization with a known symbolic factorization. This features does not
-// explicity exist in CXSparse. The methods in the class are nonstatic because
-// the class manages internal scratch space.
-class CXSparse {
- public:
- CXSparse();
- ~CXSparse();
-
- // Solves a symmetric linear system A * x = b using Cholesky factorization.
- // A - The system matrix.
- // symbolic_factorization - The symbolic factorization of A. This is obtained
- // from AnalyzeCholesky.
- // b - The right hand size of the linear equation. This
- // array will also recieve the solution.
- // Returns false if Cholesky factorization of A fails.
- bool SolveCholesky(cs_di* A, cs_dis* symbolic_factorization, double* b);
-
- // Creates a sparse matrix from a compressed-column form. No memory is
- // allocated or copied; the structure A is filled out with info from the
- // argument.
- cs_di CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
-
- // Creates a new matrix from a triplet form. Deallocate the returned matrix
- // with Free. May return NULL if the compression or allocation fails.
- cs_di* CreateSparseMatrix(TripletSparseMatrix* A);
-
- // B = A'
- //
- // The returned matrix should be deallocated with Free when not used
- // anymore.
- cs_di* TransposeMatrix(cs_di* A);
-
- // C = A * B
- //
- // The returned matrix should be deallocated with Free when not used
- // anymore.
- cs_di* MatrixMatrixMultiply(cs_di* A, cs_di* B);
-
- // Computes a symbolic factorization of A that can be used in SolveCholesky.
- //
- // The returned matrix should be deallocated with Free when not used anymore.
- cs_dis* AnalyzeCholesky(cs_di* A);
-
- // Computes a symbolic factorization of A that can be used in
- // SolveCholesky, but does not compute a fill-reducing ordering.
- //
- // The returned matrix should be deallocated with Free when not used anymore.
- cs_dis* AnalyzeCholeskyWithNaturalOrdering(cs_di* A);
-
- // Computes a symbolic factorization of A that can be used in
- // SolveCholesky. The difference from AnalyzeCholesky is that this
- // function first detects the block sparsity of the matrix using
- // information about the row and column blocks and uses this block
- // sparse matrix to find a fill-reducing ordering. This ordering is
- // then used to find a symbolic factorization. This can result in a
- // significant performance improvement AnalyzeCholesky on block
- // sparse matrices.
- //
- // The returned matrix should be deallocated with Free when not used
- // anymore.
- cs_dis* BlockAnalyzeCholesky(cs_di* A,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks);
-
- // Compute an fill-reducing approximate minimum degree ordering of
- // the matrix A. ordering should be non-NULL and should point to
- // enough memory to hold the ordering for the rows of A.
- void ApproximateMinimumDegreeOrdering(cs_di* A, int* ordering);
-
- void Free(cs_di* sparse_matrix);
- void Free(cs_dis* symbolic_factorization);
-
- private:
- // Cached scratch space
- CS_ENTRY* scratch_;
- int scratch_size_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#else // CERES_NO_CXSPARSE
-
-typedef void cs_dis;
-
-class CXSparse {
- public:
- void Free(void*) {};
-
-};
-#endif // CERES_NO_CXSPARSE
-
-#endif // CERES_INTERNAL_CXSPARSE_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h b/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
deleted file mode 100644
index be743a8591c..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A jacobian writer that writes to dense Eigen matrices.
-
-#ifndef CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
-#define CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
-
-#include "ceres/casts.h"
-#include "ceres/dense_sparse_matrix.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/scratch_evaluate_preparer.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-class DenseJacobianWriter {
- public:
- DenseJacobianWriter(Evaluator::Options /* ignored */,
- Program* program)
- : program_(program) {
- }
-
- // JacobianWriter interface.
-
- // Since the dense matrix has different layout than that assumed by the cost
- // functions, use scratch space to store the jacobians temporarily then copy
- // them over to the larger jacobian later.
- ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads) {
- return ScratchEvaluatePreparer::Create(*program_, num_threads);
- }
-
- SparseMatrix* CreateJacobian() const {
- return new DenseSparseMatrix(program_->NumResiduals(),
- program_->NumEffectiveParameters(),
- true);
- }
-
- void Write(int residual_id,
- int residual_offset,
- double **jacobians,
- SparseMatrix* jacobian) {
- DenseSparseMatrix* dense_jacobian;
- if (jacobian != NULL) {
- dense_jacobian = down_cast<DenseSparseMatrix*>(jacobian);
- }
- const ResidualBlock* residual_block =
- program_->residual_blocks()[residual_id];
- int num_parameter_blocks = residual_block->NumParameterBlocks();
- int num_residuals = residual_block->NumResiduals();
-
- // Now copy the jacobians for each parameter into the dense jacobian matrix.
- for (int j = 0; j < num_parameter_blocks; ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
-
- // If the parameter block is fixed, then there is nothing to do.
- if (parameter_block->IsConstant()) {
- continue;
- }
-
- const int parameter_block_size = parameter_block->LocalSize();
- ConstMatrixRef parameter_jacobian(jacobians[j],
- num_residuals,
- parameter_block_size);
-
- dense_jacobian->mutable_matrix().block(
- residual_offset,
- parameter_block->delta_offset(),
- num_residuals,
- parameter_block_size) = parameter_jacobian;
- }
- }
-
- private:
- Program* program_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
deleted file mode 100644
index f44d6da824c..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/dense_normal_cholesky_solver.h"
-
-#include <cstddef>
-
-#include "Eigen/Dense"
-#include "ceres/blas.h"
-#include "ceres/dense_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/lapack.h"
-#include "ceres/linear_solver.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-namespace internal {
-
-DenseNormalCholeskySolver::DenseNormalCholeskySolver(
- const LinearSolver::Options& options)
- : options_(options) {}
-
-LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- if (options_.dense_linear_algebra_library_type == EIGEN) {
- return SolveUsingEigen(A, b, per_solve_options, x);
- } else {
- return SolveUsingLAPACK(A, b, per_solve_options, x);
- }
-}
-
-LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingEigen(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("DenseNormalCholeskySolver::Solve");
-
- const int num_rows = A->num_rows();
- const int num_cols = A->num_cols();
-
- ConstColMajorMatrixRef Aref = A->matrix();
- Matrix lhs(num_cols, num_cols);
- lhs.setZero();
-
- event_logger.AddEvent("Setup");
-
- // lhs += A'A
- //
- // Using rankUpdate instead of GEMM, exposes the fact that its the
- // same matrix being multiplied with itself and that the product is
- // symmetric.
- lhs.selfadjointView<Eigen::Upper>().rankUpdate(Aref.transpose());
-
- // rhs = A'b
- Vector rhs = Aref.transpose() * ConstVectorRef(b, num_rows);
-
- if (per_solve_options.D != NULL) {
- ConstVectorRef D(per_solve_options.D, num_cols);
- lhs += D.array().square().matrix().asDiagonal();
- }
- event_logger.AddEvent("Product");
-
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- Eigen::LLT<Matrix, Eigen::Upper> llt =
- lhs.selfadjointView<Eigen::Upper>().llt();
-
- if (llt.info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen LLT decomposition failed.";
- } else {
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
- }
-
- VectorRef(x, num_cols) = llt.solve(rhs);
- event_logger.AddEvent("Solve");
- return summary;
-}
-
-LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingLAPACK(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("DenseNormalCholeskySolver::Solve");
-
- if (per_solve_options.D != NULL) {
- // Temporarily append a diagonal block to the A matrix, but undo
- // it before returning the matrix to the user.
- A->AppendDiagonal(per_solve_options.D);
- }
-
- const int num_cols = A->num_cols();
- Matrix lhs(num_cols, num_cols);
- event_logger.AddEvent("Setup");
-
- // lhs = A'A
- //
- // Note: This is a bit delicate, it assumes that the stride on this
- // matrix is the same as the number of rows.
- BLAS::SymmetricRankKUpdate(A->num_rows(),
- num_cols,
- A->values(),
- true,
- 1.0,
- 0.0,
- lhs.data());
-
- if (per_solve_options.D != NULL) {
- // Undo the modifications to the matrix A.
- A->RemoveDiagonal();
- }
-
- // TODO(sameeragarwal): Replace this with a gemv call for true blasness.
- // rhs = A'b
- VectorRef(x, num_cols) =
- A->matrix().transpose() * ConstVectorRef(b, A->num_rows());
- event_logger.AddEvent("Product");
-
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type =
- LAPACK::SolveInPlaceUsingCholesky(num_cols,
- lhs.data(),
- x,
- &summary.message);
- event_logger.AddEvent("Solve");
- return summary;
-}
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h b/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h
deleted file mode 100644
index e35053f5234..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Solve dense rectangular systems Ax = b by forming the normal
-// equations and solving them using the Cholesky factorization.
-
-#ifndef CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
-#define CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
-
-#include "ceres/linear_solver.h"
-#include "ceres/internal/macros.h"
-
-namespace ceres {
-namespace internal {
-
-class DenseSparseMatrix;
-
-// This class implements the LinearSolver interface for solving
-// rectangular/unsymmetric (well constrained) linear systems of the
-// form
-//
-// Ax = b
-//
-// Since there does not usually exist a solution that satisfies these
-// equations, the solver instead solves the linear least squares
-// problem
-//
-// min_x |Ax - b|^2
-//
-// Setting the gradient of the above optimization problem to zero
-// gives us the normal equations
-//
-// A'Ax = A'b
-//
-// A'A is a positive definite matrix (hopefully), and the resulting
-// linear system can be solved using Cholesky factorization.
-//
-// If the PerSolveOptions struct has a non-null array D, then the
-// augmented/regularized linear system
-//
-// [ A ]x = [b]
-// [ diag(D) ] [0]
-//
-// is solved.
-//
-// This class uses the LDLT factorization routines from the Eigen
-// library. This solver always returns a solution, it is the user's
-// responsibility to judge if the solution is good enough for their
-// purposes.
-class DenseNormalCholeskySolver: public DenseSparseMatrixSolver {
- public:
- explicit DenseNormalCholeskySolver(const LinearSolver::Options& options);
-
- private:
- virtual LinearSolver::Summary SolveImpl(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- LinearSolver::Summary SolveUsingLAPACK(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- LinearSolver::Summary SolveUsingEigen(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- const LinearSolver::Options options_;
- CERES_DISALLOW_COPY_AND_ASSIGN(DenseNormalCholeskySolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
deleted file mode 100644
index 4388357bd2d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/dense_qr_solver.h"
-
-
-#include <cstddef>
-#include "Eigen/Dense"
-#include "ceres/dense_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/lapack.h"
-#include "ceres/linear_solver.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-namespace internal {
-
-DenseQRSolver::DenseQRSolver(const LinearSolver::Options& options)
- : options_(options) {
- work_.resize(1);
-}
-
-LinearSolver::Summary DenseQRSolver::SolveImpl(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- if (options_.dense_linear_algebra_library_type == EIGEN) {
- return SolveUsingEigen(A, b, per_solve_options, x);
- } else {
- return SolveUsingLAPACK(A, b, per_solve_options, x);
- }
-}
-
-LinearSolver::Summary DenseQRSolver::SolveUsingLAPACK(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("DenseQRSolver::Solve");
-
- const int num_rows = A->num_rows();
- const int num_cols = A->num_cols();
-
- if (per_solve_options.D != NULL) {
- // Temporarily append a diagonal block to the A matrix, but undo
- // it before returning the matrix to the user.
- A->AppendDiagonal(per_solve_options.D);
- }
-
- // TODO(sameeragarwal): Since we are copying anyways, the diagonal
- // can be appended to the matrix instead of doing it on A.
- lhs_ = A->matrix();
-
- if (per_solve_options.D != NULL) {
- // Undo the modifications to the matrix A.
- A->RemoveDiagonal();
- }
-
- // rhs = [b;0] to account for the additional rows in the lhs.
- if (rhs_.rows() != lhs_.rows()) {
- rhs_.resize(lhs_.rows());
- }
- rhs_.setZero();
- rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
-
- if (work_.rows() == 1) {
- const int work_size =
- LAPACK::EstimateWorkSizeForQR(lhs_.rows(), lhs_.cols());
- VLOG(3) << "Working memory for Dense QR factorization: "
- << work_size * sizeof(double);
- work_.resize(work_size);
- }
-
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LAPACK::SolveInPlaceUsingQR(lhs_.rows(),
- lhs_.cols(),
- lhs_.data(),
- work_.rows(),
- work_.data(),
- rhs_.data(),
- &summary.message);
- event_logger.AddEvent("Solve");
- if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
- VectorRef(x, num_cols) = rhs_.head(num_cols);
- }
-
- event_logger.AddEvent("TearDown");
- return summary;
-}
-
-LinearSolver::Summary DenseQRSolver::SolveUsingEigen(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("DenseQRSolver::Solve");
-
- const int num_rows = A->num_rows();
- const int num_cols = A->num_cols();
-
- if (per_solve_options.D != NULL) {
- // Temporarily append a diagonal block to the A matrix, but undo
- // it before returning the matrix to the user.
- A->AppendDiagonal(per_solve_options.D);
- }
-
- // rhs = [b;0] to account for the additional rows in the lhs.
- const int augmented_num_rows =
- num_rows + ((per_solve_options.D != NULL) ? num_cols : 0);
- if (rhs_.rows() != augmented_num_rows) {
- rhs_.resize(augmented_num_rows);
- rhs_.setZero();
- }
- rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
- event_logger.AddEvent("Setup");
-
- // Solve the system.
- VectorRef(x, num_cols) = A->matrix().householderQr().solve(rhs_);
- event_logger.AddEvent("Solve");
-
- if (per_solve_options.D != NULL) {
- // Undo the modifications to the matrix A.
- A->RemoveDiagonal();
- }
-
- // We always succeed, since the QR solver returns the best solution
- // it can. It is the job of the caller to determine if the solution
- // is good enough or not.
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- event_logger.AddEvent("TearDown");
- return summary;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
deleted file mode 100644
index e745c63cb44..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Solve dense rectangular systems Ax = b using the QR factorization.
-#ifndef CERES_INTERNAL_DENSE_QR_SOLVER_H_
-#define CERES_INTERNAL_DENSE_QR_SOLVER_H_
-
-#include "ceres/linear_solver.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/macros.h"
-
-namespace ceres {
-namespace internal {
-
-class DenseSparseMatrix;
-
-// This class implements the LinearSolver interface for solving
-// rectangular/unsymmetric (well constrained) linear systems of the
-// form
-//
-// Ax = b
-//
-// Since there does not usually exist a solution that satisfies these
-// equations, the solver instead solves the linear least squares
-// problem
-//
-// min_x |Ax - b|^2
-//
-// The solution strategy is based on computing the QR decomposition of
-// A, i.e.
-//
-// A = QR
-//
-// Where Q is an orthonormal matrix and R is an upper triangular
-// matrix. Then
-//
-// Ax = b
-// QRx = b
-// Q'QRx = Q'b
-// Rx = Q'b
-// x = R^{-1} Q'b
-//
-// If the PerSolveOptions struct has a non-null array D, then the
-// augmented/regularized linear system
-//
-// [ A ]x = [b]
-// [ diag(D) ] [0]
-//
-// is solved.
-//
-// This class uses the dense QR factorization routines from the Eigen
-// library. This solver always returns a solution, it is the user's
-// responsibility to judge if the solution is good enough for their
-// purposes.
-class DenseQRSolver: public DenseSparseMatrixSolver {
- public:
- explicit DenseQRSolver(const LinearSolver::Options& options);
-
- private:
- virtual LinearSolver::Summary SolveImpl(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- LinearSolver::Summary SolveUsingEigen(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- LinearSolver::Summary SolveUsingLAPACK(
- DenseSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- const LinearSolver::Options options_;
- ColMajorMatrix lhs_;
- Vector rhs_;
- Vector work_;
- CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DENSE_QR_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
deleted file mode 100644
index d67474fed32..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/dense_sparse_matrix.h"
-
-#include <algorithm>
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols)
- : has_diagonal_appended_(false),
- has_diagonal_reserved_(false) {
- m_.resize(num_rows, num_cols);
- m_.setZero();
-}
-
-DenseSparseMatrix::DenseSparseMatrix(int num_rows,
- int num_cols,
- bool reserve_diagonal)
- : has_diagonal_appended_(false),
- has_diagonal_reserved_(reserve_diagonal) {
- if (reserve_diagonal) {
- // Allocate enough space for the diagonal.
- m_.resize(num_rows + num_cols, num_cols);
- } else {
- m_.resize(num_rows, num_cols);
- }
- m_.setZero();
-}
-
-DenseSparseMatrix::DenseSparseMatrix(const TripletSparseMatrix& m)
- : m_(Eigen::MatrixXd::Zero(m.num_rows(), m.num_cols())),
- has_diagonal_appended_(false),
- has_diagonal_reserved_(false) {
- const double *values = m.values();
- const int *rows = m.rows();
- const int *cols = m.cols();
- int num_nonzeros = m.num_nonzeros();
-
- for (int i = 0; i < num_nonzeros; ++i) {
- m_(rows[i], cols[i]) += values[i];
- }
-}
-
-DenseSparseMatrix::DenseSparseMatrix(const ColMajorMatrix& m)
- : m_(m),
- has_diagonal_appended_(false),
- has_diagonal_reserved_(false) {
-}
-
-void DenseSparseMatrix::SetZero() {
- m_.setZero();
-}
-
-void DenseSparseMatrix::RightMultiply(const double* x, double* y) const {
- VectorRef(y, num_rows()) += matrix() * ConstVectorRef(x, num_cols());
-}
-
-void DenseSparseMatrix::LeftMultiply(const double* x, double* y) const {
- VectorRef(y, num_cols()) +=
- matrix().transpose() * ConstVectorRef(x, num_rows());
-}
-
-void DenseSparseMatrix::SquaredColumnNorm(double* x) const {
- VectorRef(x, num_cols()) = m_.colwise().squaredNorm();
-}
-
-void DenseSparseMatrix::ScaleColumns(const double* scale) {
- m_ *= ConstVectorRef(scale, num_cols()).asDiagonal();
-}
-
-void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- *dense_matrix = m_.block(0, 0, num_rows(), num_cols());
-}
-
-void DenseSparseMatrix::AppendDiagonal(double *d) {
- CHECK(!has_diagonal_appended_);
- if (!has_diagonal_reserved_) {
- ColMajorMatrix tmp = m_;
- m_.resize(m_.rows() + m_.cols(), m_.cols());
- m_.setZero();
- m_.block(0, 0, tmp.rows(), tmp.cols()) = tmp;
- has_diagonal_reserved_ = true;
- }
-
- m_.bottomLeftCorner(m_.cols(), m_.cols()) =
- ConstVectorRef(d, m_.cols()).asDiagonal();
- has_diagonal_appended_ = true;
-}
-
-void DenseSparseMatrix::RemoveDiagonal() {
- CHECK(has_diagonal_appended_);
- has_diagonal_appended_ = false;
- // Leave the diagonal reserved.
-}
-
-int DenseSparseMatrix::num_rows() const {
- if (has_diagonal_reserved_ && !has_diagonal_appended_) {
- return m_.rows() - m_.cols();
- }
- return m_.rows();
-}
-
-int DenseSparseMatrix::num_cols() const {
- return m_.cols();
-}
-
-int DenseSparseMatrix::num_nonzeros() const {
- if (has_diagonal_reserved_ && !has_diagonal_appended_) {
- return (m_.rows() - m_.cols()) * m_.cols();
- }
- return m_.rows() * m_.cols();
-}
-
-ConstColMajorMatrixRef DenseSparseMatrix::matrix() const {
- return ConstColMajorMatrixRef(
- m_.data(),
- ((has_diagonal_reserved_ && !has_diagonal_appended_)
- ? m_.rows() - m_.cols()
- : m_.rows()),
- m_.cols(),
- Eigen::Stride<Eigen::Dynamic, 1>(m_.rows(), 1));
-}
-
-ColMajorMatrixRef DenseSparseMatrix::mutable_matrix() {
- return ColMajorMatrixRef(
- m_.data(),
- ((has_diagonal_reserved_ && !has_diagonal_appended_)
- ? m_.rows() - m_.cols()
- : m_.rows()),
- m_.cols(),
- Eigen::Stride<Eigen::Dynamic, 1>(m_.rows(), 1));
-}
-
-
-void DenseSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
- const int active_rows =
- (has_diagonal_reserved_ && !has_diagonal_appended_)
- ? (m_.rows() - m_.cols())
- : m_.rows();
-
- for (int r = 0; r < active_rows; ++r) {
- for (int c = 0; c < m_.cols(); ++c) {
- fprintf(file, "% 10d % 10d %17f\n", r, c, m_(r, c));
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
deleted file mode 100644
index 981e2d14562..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A dense matrix implemented under the SparseMatrix interface.
-
-#ifndef CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
-
-#include "ceres/sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class TripletSparseMatrix;
-
-class DenseSparseMatrix : public SparseMatrix {
- public:
- // Build a matrix with the same content as the TripletSparseMatrix
- // m. This assumes that m does not have any repeated entries.
- explicit DenseSparseMatrix(const TripletSparseMatrix& m);
- explicit DenseSparseMatrix(const ColMajorMatrix& m);
-
- DenseSparseMatrix(int num_rows, int num_cols);
- DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal);
-
- virtual ~DenseSparseMatrix() {}
-
- // SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
- virtual int num_rows() const;
- virtual int num_cols() const;
- virtual int num_nonzeros() const;
- virtual const double* values() const { return m_.data(); }
- virtual double* mutable_values() { return m_.data(); }
-
- ConstColMajorMatrixRef matrix() const;
- ColMajorMatrixRef mutable_matrix();
-
- // Only one diagonal can be appended at a time. The diagonal is appended to
- // as a new set of rows, e.g.
- //
- // Original matrix:
- //
- // x x x
- // x x x
- // x x x
- //
- // After append diagonal (1, 2, 3):
- //
- // x x x
- // x x x
- // x x x
- // 1 0 0
- // 0 2 0
- // 0 0 3
- //
- // Calling RemoveDiagonal removes the block. It is a fatal error to append a
- // diagonal to a matrix that already has an appended diagonal, and it is also
- // a fatal error to remove a diagonal from a matrix that has none.
- void AppendDiagonal(double *d);
- void RemoveDiagonal();
-
- private:
- ColMajorMatrix m_;
- bool has_diagonal_appended_;
- bool has_diagonal_reserved_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc b/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc
deleted file mode 100644
index ea5bf2e9690..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/detect_structure.h"
-#include "ceres/internal/eigen.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-void DetectStructure(const CompressedRowBlockStructure& bs,
- const int num_eliminate_blocks,
- int* row_block_size,
- int* e_block_size,
- int* f_block_size) {
- const int num_row_blocks = bs.rows.size();
- *row_block_size = 0;
- *e_block_size = 0;
- *f_block_size = 0;
-
- // Iterate over row blocks of the matrix, checking if row_block,
- // e_block or f_block sizes remain constant.
- for (int r = 0; r < num_row_blocks; ++r) {
- const CompressedRow& row = bs.rows[r];
- // We do not care about the sizes of the blocks in rows which do
- // not contain e_blocks.
- if (row.cells.front().block_id >= num_eliminate_blocks) {
- break;
- }
- const int e_block_id = row.cells.front().block_id;
-
- if (*row_block_size == 0) {
- *row_block_size = row.block.size;
- } else if (*row_block_size != Eigen::Dynamic &&
- *row_block_size != row.block.size) {
- VLOG(2) << "Dynamic row block size because the block size changed from "
- << *row_block_size << " to "
- << row.block.size;
- *row_block_size = Eigen::Dynamic;
- }
-
-
- if (*e_block_size == 0) {
- *e_block_size = bs.cols[e_block_id].size;
- } else if (*e_block_size != Eigen::Dynamic &&
- *e_block_size != bs.cols[e_block_id].size) {
- VLOG(2) << "Dynamic e block size because the block size changed from "
- << *e_block_size << " to "
- << bs.cols[e_block_id].size;
- *e_block_size = Eigen::Dynamic;
- }
-
- if (*f_block_size == 0) {
- if (row.cells.size() > 1) {
- const int f_block_id = row.cells[1].block_id;
- *f_block_size = bs.cols[f_block_id].size;
- }
- } else if (*f_block_size != Eigen::Dynamic) {
- for (int c = 1; c < row.cells.size(); ++c) {
- if (*f_block_size != bs.cols[row.cells[c].block_id].size) {
- VLOG(2) << "Dynamic f block size because the block size "
- << "changed from " << *f_block_size << " to "
- << bs.cols[row.cells[c].block_id].size;
- *f_block_size = Eigen::Dynamic;
- break;
- }
- }
- }
-
- const bool is_everything_dynamic = (*row_block_size == Eigen::Dynamic &&
- *e_block_size == Eigen::Dynamic &&
- *f_block_size == Eigen::Dynamic);
- if (is_everything_dynamic) {
- break;
- }
- }
-
- CHECK_NE(*row_block_size, 0) << "No rows found";
- CHECK_NE(*e_block_size, 0) << "No e type blocks found";
- VLOG(1) << "Schur complement static structure <"
- << *row_block_size << ","
- << *e_block_size << ","
- << *f_block_size << ">.";
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h b/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h
deleted file mode 100644
index 5f8e1b4ff46..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/detect_structure.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_DETECT_STRUCTURE_H_
-#define CERES_INTERNAL_DETECT_STRUCTURE_H_
-
-#include "ceres/block_structure.h"
-
-namespace ceres {
-namespace internal {
-
-// Detect static blocks in the problem sparsity. For rows containing
-// e_blocks, we are interested in detecting if the size of the row
-// blocks, e_blocks and the f_blocks remain constant. If they do, then
-// we can use template specialization to improve the performance of
-// the block level linear algebra operations used by the
-// SchurEliminator.
-//
-// If a block size is not constant, we return Eigen::Dynamic as the
-// value. This just means that the eliminator uses dynamically sized
-// linear algebra operations rather than static operations whose size
-// is known as compile time.
-//
-// For more details about e_blocks and f_blocks, see
-// schur_eliminator.h. This information is used to initialized an
-// appropriate template specialization of SchurEliminator.
-void DetectStructure(const CompressedRowBlockStructure& bs,
- const int num_eliminate_blocks,
- int* row_block_size,
- int* e_block_size,
- int* f_block_size);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DETECT_STRUCTURE_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
deleted file mode 100644
index f29376db793..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
+++ /dev/null
@@ -1,717 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/dogleg_strategy.h"
-
-#include <cmath>
-#include "Eigen/Dense"
-#include "ceres/array_utils.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_least_squares_problems.h"
-#include "ceres/linear_solver.h"
-#include "ceres/polynomial.h"
-#include "ceres/sparse_matrix.h"
-#include "ceres/trust_region_strategy.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-const double kMaxMu = 1.0;
-const double kMinMu = 1e-8;
-}
-
-DoglegStrategy::DoglegStrategy(const TrustRegionStrategy::Options& options)
- : linear_solver_(options.linear_solver),
- radius_(options.initial_radius),
- max_radius_(options.max_radius),
- min_diagonal_(options.min_lm_diagonal),
- max_diagonal_(options.max_lm_diagonal),
- mu_(kMinMu),
- min_mu_(kMinMu),
- max_mu_(kMaxMu),
- mu_increase_factor_(10.0),
- increase_threshold_(0.75),
- decrease_threshold_(0.25),
- dogleg_step_norm_(0.0),
- reuse_(false),
- dogleg_type_(options.dogleg_type) {
- CHECK_NOTNULL(linear_solver_);
- CHECK_GT(min_diagonal_, 0.0);
- CHECK_LE(min_diagonal_, max_diagonal_);
- CHECK_GT(max_radius_, 0.0);
-}
-
-// If the reuse_ flag is not set, then the Cauchy point (scaled
-// gradient) and the new Gauss-Newton step are computed from
-// scratch. The Dogleg step is then computed as interpolation of these
-// two vectors.
-TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
- const TrustRegionStrategy::PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals,
- double* step) {
- CHECK_NOTNULL(jacobian);
- CHECK_NOTNULL(residuals);
- CHECK_NOTNULL(step);
-
- const int n = jacobian->num_cols();
- if (reuse_) {
- // Gauss-Newton and gradient vectors are always available, only a
- // new interpolant need to be computed. For the subspace case,
- // the subspace and the two-dimensional model are also still valid.
- switch (dogleg_type_) {
- case TRADITIONAL_DOGLEG:
- ComputeTraditionalDoglegStep(step);
- break;
-
- case SUBSPACE_DOGLEG:
- ComputeSubspaceDoglegStep(step);
- break;
- }
- TrustRegionStrategy::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- return summary;
- }
-
- reuse_ = true;
- // Check that we have the storage needed to hold the various
- // temporary vectors.
- if (diagonal_.rows() != n) {
- diagonal_.resize(n, 1);
- gradient_.resize(n, 1);
- gauss_newton_step_.resize(n, 1);
- }
-
- // Vector used to form the diagonal matrix that is used to
- // regularize the Gauss-Newton solve and that defines the
- // elliptical trust region
- //
- // || D * step || <= radius_ .
- //
- jacobian->SquaredColumnNorm(diagonal_.data());
- for (int i = 0; i < n; ++i) {
- diagonal_[i] = min(max(diagonal_[i], min_diagonal_), max_diagonal_);
- }
- diagonal_ = diagonal_.array().sqrt();
-
- ComputeGradient(jacobian, residuals);
- ComputeCauchyPoint(jacobian);
-
- LinearSolver::Summary linear_solver_summary =
- ComputeGaussNewtonStep(per_solve_options, jacobian, residuals);
-
- TrustRegionStrategy::Summary summary;
- summary.residual_norm = linear_solver_summary.residual_norm;
- summary.num_iterations = linear_solver_summary.num_iterations;
- summary.termination_type = linear_solver_summary.termination_type;
-
- if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
- return summary;
- }
-
- if (linear_solver_summary.termination_type != LINEAR_SOLVER_FAILURE) {
- switch (dogleg_type_) {
- // Interpolate the Cauchy point and the Gauss-Newton step.
- case TRADITIONAL_DOGLEG:
- ComputeTraditionalDoglegStep(step);
- break;
-
- // Find the minimum in the subspace defined by the
- // Cauchy point and the (Gauss-)Newton step.
- case SUBSPACE_DOGLEG:
- if (!ComputeSubspaceModel(jacobian)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- break;
- }
- ComputeSubspaceDoglegStep(step);
- break;
- }
- }
-
- return summary;
-}
-
-// The trust region is assumed to be elliptical with the
-// diagonal scaling matrix D defined by sqrt(diagonal_).
-// It is implemented by substituting step' = D * step.
-// The trust region for step' is spherical.
-// The gradient, the Gauss-Newton step, the Cauchy point,
-// and all calculations involving the Jacobian have to
-// be adjusted accordingly.
-void DoglegStrategy::ComputeGradient(
- SparseMatrix* jacobian,
- const double* residuals) {
- gradient_.setZero();
- jacobian->LeftMultiply(residuals, gradient_.data());
- gradient_.array() /= diagonal_.array();
-}
-
-// The Cauchy point is the global minimizer of the quadratic model
-// along the one-dimensional subspace spanned by the gradient.
-void DoglegStrategy::ComputeCauchyPoint(SparseMatrix* jacobian) {
- // alpha * -gradient is the Cauchy point.
- Vector Jg(jacobian->num_rows());
- Jg.setZero();
- // The Jacobian is scaled implicitly by computing J * (D^-1 * (D^-1 * g))
- // instead of (J * D^-1) * (D^-1 * g).
- Vector scaled_gradient =
- (gradient_.array() / diagonal_.array()).matrix();
- jacobian->RightMultiply(scaled_gradient.data(), Jg.data());
- alpha_ = gradient_.squaredNorm() / Jg.squaredNorm();
-}
-
-// The dogleg step is defined as the intersection of the trust region
-// boundary with the piecewise linear path from the origin to the Cauchy
-// point and then from there to the Gauss-Newton point (global minimizer
-// of the model function). The Gauss-Newton point is taken if it lies
-// within the trust region.
-void DoglegStrategy::ComputeTraditionalDoglegStep(double* dogleg) {
- VectorRef dogleg_step(dogleg, gradient_.rows());
-
- // Case 1. The Gauss-Newton step lies inside the trust region, and
- // is therefore the optimal solution to the trust-region problem.
- const double gradient_norm = gradient_.norm();
- const double gauss_newton_norm = gauss_newton_step_.norm();
- if (gauss_newton_norm <= radius_) {
- dogleg_step = gauss_newton_step_;
- dogleg_step_norm_ = gauss_newton_norm;
- dogleg_step.array() /= diagonal_.array();
- VLOG(3) << "GaussNewton step size: " << dogleg_step_norm_
- << " radius: " << radius_;
- return;
- }
-
- // Case 2. The Cauchy point and the Gauss-Newton steps lie outside
- // the trust region. Rescale the Cauchy point to the trust region
- // and return.
- if (gradient_norm * alpha_ >= radius_) {
- dogleg_step = -(radius_ / gradient_norm) * gradient_;
- dogleg_step_norm_ = radius_;
- dogleg_step.array() /= diagonal_.array();
- VLOG(3) << "Cauchy step size: " << dogleg_step_norm_
- << " radius: " << radius_;
- return;
- }
-
- // Case 3. The Cauchy point is inside the trust region and the
- // Gauss-Newton step is outside. Compute the line joining the two
- // points and the point on it which intersects the trust region
- // boundary.
-
- // a = alpha * -gradient
- // b = gauss_newton_step
- const double b_dot_a = -alpha_ * gradient_.dot(gauss_newton_step_);
- const double a_squared_norm = pow(alpha_ * gradient_norm, 2.0);
- const double b_minus_a_squared_norm =
- a_squared_norm - 2 * b_dot_a + pow(gauss_newton_norm, 2);
-
- // c = a' (b - a)
- // = alpha * -gradient' gauss_newton_step - alpha^2 |gradient|^2
- const double c = b_dot_a - a_squared_norm;
- const double d = sqrt(c * c + b_minus_a_squared_norm *
- (pow(radius_, 2.0) - a_squared_norm));
-
- double beta =
- (c <= 0)
- ? (d - c) / b_minus_a_squared_norm
- : (radius_ * radius_ - a_squared_norm) / (d + c);
- dogleg_step = (-alpha_ * (1.0 - beta)) * gradient_
- + beta * gauss_newton_step_;
- dogleg_step_norm_ = dogleg_step.norm();
- dogleg_step.array() /= diagonal_.array();
- VLOG(3) << "Dogleg step size: " << dogleg_step_norm_
- << " radius: " << radius_;
-}
-
-// The subspace method finds the minimum of the two-dimensional problem
-//
-// min. 1/2 x' B' H B x + g' B x
-// s.t. || B x ||^2 <= r^2
-//
-// where r is the trust region radius and B is the matrix with unit columns
-// spanning the subspace defined by the steepest descent and Newton direction.
-// This subspace by definition includes the Gauss-Newton point, which is
-// therefore taken if it lies within the trust region.
-void DoglegStrategy::ComputeSubspaceDoglegStep(double* dogleg) {
- VectorRef dogleg_step(dogleg, gradient_.rows());
-
- // The Gauss-Newton point is inside the trust region if |GN| <= radius_.
- // This test is valid even though radius_ is a length in the two-dimensional
- // subspace while gauss_newton_step_ is expressed in the (scaled)
- // higher dimensional original space. This is because
- //
- // 1. gauss_newton_step_ by definition lies in the subspace, and
- // 2. the subspace basis is orthonormal.
- //
- // As a consequence, the norm of the gauss_newton_step_ in the subspace is
- // the same as its norm in the original space.
- const double gauss_newton_norm = gauss_newton_step_.norm();
- if (gauss_newton_norm <= radius_) {
- dogleg_step = gauss_newton_step_;
- dogleg_step_norm_ = gauss_newton_norm;
- dogleg_step.array() /= diagonal_.array();
- VLOG(3) << "GaussNewton step size: " << dogleg_step_norm_
- << " radius: " << radius_;
- return;
- }
-
- // The optimum lies on the boundary of the trust region. The above problem
- // therefore becomes
- //
- // min. 1/2 x^T B^T H B x + g^T B x
- // s.t. || B x ||^2 = r^2
- //
- // Notice the equality in the constraint.
- //
- // This can be solved by forming the Lagrangian, solving for x(y), where
- // y is the Lagrange multiplier, using the gradient of the objective, and
- // putting x(y) back into the constraint. This results in a fourth order
- // polynomial in y, which can be solved using e.g. the companion matrix.
- // See the description of MakePolynomialForBoundaryConstrainedProblem for
- // details. The result is up to four real roots y*, not all of which
- // correspond to feasible points. The feasible points x(y*) have to be
- // tested for optimality.
-
- if (subspace_is_one_dimensional_) {
- // The subspace is one-dimensional, so both the gradient and
- // the Gauss-Newton step point towards the same direction.
- // In this case, we move along the gradient until we reach the trust
- // region boundary.
- dogleg_step = -(radius_ / gradient_.norm()) * gradient_;
- dogleg_step_norm_ = radius_;
- dogleg_step.array() /= diagonal_.array();
- VLOG(3) << "Dogleg subspace step size (1D): " << dogleg_step_norm_
- << " radius: " << radius_;
- return;
- }
-
- Vector2d minimum(0.0, 0.0);
- if (!FindMinimumOnTrustRegionBoundary(&minimum)) {
- // For the positive semi-definite case, a traditional dogleg step
- // is taken in this case.
- LOG(WARNING) << "Failed to compute polynomial roots. "
- << "Taking traditional dogleg step instead.";
- ComputeTraditionalDoglegStep(dogleg);
- return;
- }
-
- // Test first order optimality at the minimum.
- // The first order KKT conditions state that the minimum x*
- // has to satisfy either || x* ||^2 < r^2 (i.e. has to lie within
- // the trust region), or
- //
- // (B x* + g) + y x* = 0
- //
- // for some positive scalar y.
- // Here, as it is already known that the minimum lies on the boundary, the
- // latter condition is tested. To allow for small imprecisions, we test if
- // the angle between (B x* + g) and -x* is smaller than acos(0.99).
- // The exact value of the cosine is arbitrary but should be close to 1.
- //
- // This condition should not be violated. If it is, the minimum was not
- // correctly determined.
- const double kCosineThreshold = 0.99;
- const Vector2d grad_minimum = subspace_B_ * minimum + subspace_g_;
- const double cosine_angle = -minimum.dot(grad_minimum) /
- (minimum.norm() * grad_minimum.norm());
- if (cosine_angle < kCosineThreshold) {
- LOG(WARNING) << "First order optimality seems to be violated "
- << "in the subspace method!\n"
- << "Cosine of angle between x and B x + g is "
- << cosine_angle << ".\n"
- << "Taking a regular dogleg step instead.\n"
- << "Please consider filing a bug report if this "
- << "happens frequently or consistently.\n";
- ComputeTraditionalDoglegStep(dogleg);
- return;
- }
-
- // Create the full step from the optimal 2d solution.
- dogleg_step = subspace_basis_ * minimum;
- dogleg_step_norm_ = radius_;
- dogleg_step.array() /= diagonal_.array();
- VLOG(3) << "Dogleg subspace step size: " << dogleg_step_norm_
- << " radius: " << radius_;
-}
-
-// Build the polynomial that defines the optimal Lagrange multipliers.
-// Let the Lagrangian be
-//
-// L(x, y) = 0.5 x^T B x + x^T g + y (0.5 x^T x - 0.5 r^2). (1)
-//
-// Stationary points of the Lagrangian are given by
-//
-// 0 = d L(x, y) / dx = Bx + g + y x (2)
-// 0 = d L(x, y) / dy = 0.5 x^T x - 0.5 r^2 (3)
-//
-// For any given y, we can solve (2) for x as
-//
-// x(y) = -(B + y I)^-1 g . (4)
-//
-// As B + y I is 2x2, we form the inverse explicitly:
-//
-// (B + y I)^-1 = (1 / det(B + y I)) adj(B + y I) (5)
-//
-// where adj() denotes adjugation. This should be safe, as B is positive
-// semi-definite and y is necessarily positive, so (B + y I) is indeed
-// invertible.
-// Plugging (5) into (4) and the result into (3), then dividing by 0.5 we
-// obtain
-//
-// 0 = (1 / det(B + y I))^2 g^T adj(B + y I)^T adj(B + y I) g - r^2
-// (6)
-//
-// or
-//
-// det(B + y I)^2 r^2 = g^T adj(B + y I)^T adj(B + y I) g (7a)
-// = g^T adj(B)^T adj(B) g
-// + 2 y g^T adj(B)^T g + y^2 g^T g (7b)
-//
-// as
-//
-// adj(B + y I) = adj(B) + y I = adj(B)^T + y I . (8)
-//
-// The left hand side can be expressed explicitly using
-//
-// det(B + y I) = det(B) + y tr(B) + y^2 . (9)
-//
-// So (7) is a polynomial in y of degree four.
-// Bringing everything back to the left hand side, the coefficients can
-// be read off as
-//
-// y^4 r^2
-// + y^3 2 r^2 tr(B)
-// + y^2 (r^2 tr(B)^2 + 2 r^2 det(B) - g^T g)
-// + y^1 (2 r^2 det(B) tr(B) - 2 g^T adj(B)^T g)
-// + y^0 (r^2 det(B)^2 - g^T adj(B)^T adj(B) g)
-//
-Vector DoglegStrategy::MakePolynomialForBoundaryConstrainedProblem() const {
- const double detB = subspace_B_.determinant();
- const double trB = subspace_B_.trace();
- const double r2 = radius_ * radius_;
- Matrix2d B_adj;
- B_adj << subspace_B_(1, 1) , -subspace_B_(0, 1),
- -subspace_B_(1, 0) , subspace_B_(0, 0);
-
- Vector polynomial(5);
- polynomial(0) = r2;
- polynomial(1) = 2.0 * r2 * trB;
- polynomial(2) = r2 * (trB * trB + 2.0 * detB) - subspace_g_.squaredNorm();
- polynomial(3) = -2.0 * (subspace_g_.transpose() * B_adj * subspace_g_
- - r2 * detB * trB);
- polynomial(4) = r2 * detB * detB - (B_adj * subspace_g_).squaredNorm();
-
- return polynomial;
-}
-
-// Given a Lagrange multiplier y that corresponds to a stationary point
-// of the Lagrangian L(x, y), compute the corresponding x from the
-// equation
-//
-// 0 = d L(x, y) / dx
-// = B * x + g + y * x
-// = (B + y * I) * x + g
-//
-DoglegStrategy::Vector2d DoglegStrategy::ComputeSubspaceStepFromRoot(
- double y) const {
- const Matrix2d B_i = subspace_B_ + y * Matrix2d::Identity();
- return -B_i.partialPivLu().solve(subspace_g_);
-}
-
-// This function evaluates the quadratic model at a point x in the
-// subspace spanned by subspace_basis_.
-double DoglegStrategy::EvaluateSubspaceModel(const Vector2d& x) const {
- return 0.5 * x.dot(subspace_B_ * x) + subspace_g_.dot(x);
-}
-
-// This function attempts to solve the boundary-constrained subspace problem
-//
-// min. 1/2 x^T B^T H B x + g^T B x
-// s.t. || B x ||^2 = r^2
-//
-// where B is an orthonormal subspace basis and r is the trust-region radius.
-//
-// This is done by finding the roots of a fourth degree polynomial. If the
-// root finding fails, the function returns false and minimum will be set
-// to (0, 0). If it succeeds, true is returned.
-//
-// In the failure case, another step should be taken, such as the traditional
-// dogleg step.
-bool DoglegStrategy::FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const {
- CHECK_NOTNULL(minimum);
-
- // Return (0, 0) in all error cases.
- minimum->setZero();
-
- // Create the fourth-degree polynomial that is a necessary condition for
- // optimality.
- const Vector polynomial = MakePolynomialForBoundaryConstrainedProblem();
-
- // Find the real parts y_i of its roots (not only the real roots).
- Vector roots_real;
- if (!FindPolynomialRoots(polynomial, &roots_real, NULL)) {
- // Failed to find the roots of the polynomial, i.e. the candidate
- // solutions of the constrained problem. Report this back to the caller.
- return false;
- }
-
- // For each root y, compute B x(y) and check for feasibility.
- // Notice that there should always be four roots, as the leading term of
- // the polynomial is r^2 and therefore non-zero. However, as some roots
- // may be complex, the real parts are not necessarily unique.
- double minimum_value = std::numeric_limits<double>::max();
- bool valid_root_found = false;
- for (int i = 0; i < roots_real.size(); ++i) {
- const Vector2d x_i = ComputeSubspaceStepFromRoot(roots_real(i));
-
- // Not all roots correspond to points on the trust region boundary.
- // There are at most four candidate solutions. As we are interested
- // in the minimum, it is safe to consider all of them after projecting
- // them onto the trust region boundary.
- if (x_i.norm() > 0) {
- const double f_i = EvaluateSubspaceModel((radius_ / x_i.norm()) * x_i);
- valid_root_found = true;
- if (f_i < minimum_value) {
- minimum_value = f_i;
- *minimum = x_i;
- }
- }
- }
-
- return valid_root_found;
-}
-
-LinearSolver::Summary DoglegStrategy::ComputeGaussNewtonStep(
- const PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals) {
- const int n = jacobian->num_cols();
- LinearSolver::Summary linear_solver_summary;
- linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
-
- // The Jacobian matrix is often quite poorly conditioned. Thus it is
- // necessary to add a diagonal matrix at the bottom to prevent the
- // linear solver from failing.
- //
- // We do this by computing the same diagonal matrix as the one used
- // by Levenberg-Marquardt (other choices are possible), and scaling
- // it by a small constant (independent of the trust region radius).
- //
- // If the solve fails, the multiplier to the diagonal is increased
- // up to max_mu_ by a factor of mu_increase_factor_ every time. If
- // the linear solver is still not successful, the strategy returns
- // with LINEAR_SOLVER_FAILURE.
- //
- // Next time when a new Gauss-Newton step is requested, the
- // multiplier starts out from the last successful solve.
- //
- // When a step is declared successful, the multiplier is decreased
- // by half of mu_increase_factor_.
-
- while (mu_ < max_mu_) {
- // Dogleg, as far as I (sameeragarwal) understand it, requires a
- // reasonably good estimate of the Gauss-Newton step. This means
- // that we need to solve the normal equations more or less
- // exactly. This is reflected in the values of the tolerances set
- // below.
- //
- // For now, this strategy should only be used with exact
- // factorization based solvers, for which these tolerances are
- // automatically satisfied.
- //
- // The right way to combine inexact solves with trust region
- // methods is to use Stiehaug's method.
- LinearSolver::PerSolveOptions solve_options;
- solve_options.q_tolerance = 0.0;
- solve_options.r_tolerance = 0.0;
-
- lm_diagonal_ = diagonal_ * std::sqrt(mu_);
- solve_options.D = lm_diagonal_.data();
-
- // As in the LevenbergMarquardtStrategy, solve Jy = r instead
- // of Jx = -r and later set x = -y to avoid having to modify
- // either jacobian or residuals.
- InvalidateArray(n, gauss_newton_step_.data());
- linear_solver_summary = linear_solver_->Solve(jacobian,
- residuals,
- solve_options,
- gauss_newton_step_.data());
-
- if (per_solve_options.dump_format_type == CONSOLE ||
- (per_solve_options.dump_format_type != CONSOLE &&
- !per_solve_options.dump_filename_base.empty())) {
- if (!DumpLinearLeastSquaresProblem(per_solve_options.dump_filename_base,
- per_solve_options.dump_format_type,
- jacobian,
- solve_options.D,
- residuals,
- gauss_newton_step_.data(),
- 0)) {
- LOG(ERROR) << "Unable to dump trust region problem."
- << " Filename base: "
- << per_solve_options.dump_filename_base;
- }
- }
-
- if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
- return linear_solver_summary;
- }
-
- if (linear_solver_summary.termination_type == LINEAR_SOLVER_FAILURE ||
- !IsArrayValid(n, gauss_newton_step_.data())) {
- mu_ *= mu_increase_factor_;
- VLOG(2) << "Increasing mu " << mu_;
- linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
- continue;
- }
- break;
- }
-
- if (linear_solver_summary.termination_type != LINEAR_SOLVER_FAILURE) {
- // The scaled Gauss-Newton step is D * GN:
- //
- // - (D^-1 J^T J D^-1)^-1 (D^-1 g)
- // = - D (J^T J)^-1 D D^-1 g
- // = D -(J^T J)^-1 g
- //
- gauss_newton_step_.array() *= -diagonal_.array();
- }
-
- return linear_solver_summary;
-}
-
-void DoglegStrategy::StepAccepted(double step_quality) {
- CHECK_GT(step_quality, 0.0);
-
- if (step_quality < decrease_threshold_) {
- radius_ *= 0.5;
- }
-
- if (step_quality > increase_threshold_) {
- radius_ = max(radius_, 3.0 * dogleg_step_norm_);
- }
-
- // Reduce the regularization multiplier, in the hope that whatever
- // was causing the rank deficiency has gone away and we can return
- // to doing a pure Gauss-Newton solve.
- mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_);
- reuse_ = false;
-}
-
-void DoglegStrategy::StepRejected(double step_quality) {
- radius_ *= 0.5;
- reuse_ = true;
-}
-
-void DoglegStrategy::StepIsInvalid() {
- mu_ *= mu_increase_factor_;
- reuse_ = false;
-}
-
-double DoglegStrategy::Radius() const {
- return radius_;
-}
-
-bool DoglegStrategy::ComputeSubspaceModel(SparseMatrix* jacobian) {
- // Compute an orthogonal basis for the subspace using QR decomposition.
- Matrix basis_vectors(jacobian->num_cols(), 2);
- basis_vectors.col(0) = gradient_;
- basis_vectors.col(1) = gauss_newton_step_;
- Eigen::ColPivHouseholderQR<Matrix> basis_qr(basis_vectors);
-
- switch (basis_qr.rank()) {
- case 0:
- // This should never happen, as it implies that both the gradient
- // and the Gauss-Newton step are zero. In this case, the minimizer should
- // have stopped due to the gradient being too small.
- LOG(ERROR) << "Rank of subspace basis is 0. "
- << "This means that the gradient at the current iterate is "
- << "zero but the optimization has not been terminated. "
- << "You may have found a bug in Ceres.";
- return false;
-
- case 1:
- // Gradient and Gauss-Newton step coincide, so we lie on one of the
- // major axes of the quadratic problem. In this case, we simply move
- // along the gradient until we reach the trust region boundary.
- subspace_is_one_dimensional_ = true;
- return true;
-
- case 2:
- subspace_is_one_dimensional_ = false;
- break;
-
- default:
- LOG(ERROR) << "Rank of the subspace basis matrix is reported to be "
- << "greater than 2. As the matrix contains only two "
- << "columns this cannot be true and is indicative of "
- << "a bug.";
- return false;
- }
-
- // The subspace is two-dimensional, so compute the subspace model.
- // Given the basis U, this is
- //
- // subspace_g_ = g_scaled^T U
- //
- // and
- //
- // subspace_B_ = U^T (J_scaled^T J_scaled) U
- //
- // As J_scaled = J * D^-1, the latter becomes
- //
- // subspace_B_ = ((U^T D^-1) J^T) (J (D^-1 U))
- // = (J (D^-1 U))^T (J (D^-1 U))
-
- subspace_basis_ =
- basis_qr.householderQ() * Matrix::Identity(jacobian->num_cols(), 2);
-
- subspace_g_ = subspace_basis_.transpose() * gradient_;
-
- Eigen::Matrix<double, 2, Eigen::Dynamic, Eigen::RowMajor>
- Jb(2, jacobian->num_rows());
- Jb.setZero();
-
- Vector tmp;
- tmp = (subspace_basis_.col(0).array() / diagonal_.array()).matrix();
- jacobian->RightMultiply(tmp.data(), Jb.row(0).data());
- tmp = (subspace_basis_.col(1).array() / diagonal_.array()).matrix();
- jacobian->RightMultiply(tmp.data(), Jb.row(1).data());
-
- subspace_B_ = Jb * Jb.transpose();
-
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
deleted file mode 100644
index 71c785cc3f7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_DOGLEG_STRATEGY_H_
-#define CERES_INTERNAL_DOGLEG_STRATEGY_H_
-
-#include "ceres/linear_solver.h"
-#include "ceres/trust_region_strategy.h"
-
-namespace ceres {
-namespace internal {
-
-// Dogleg step computation and trust region sizing strategy based on
-// on "Methods for Nonlinear Least Squares" by K. Madsen, H.B. Nielsen
-// and O. Tingleff. Available to download from
-//
-// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
-//
-// One minor modification is that instead of computing the pure
-// Gauss-Newton step, we compute a regularized version of it. This is
-// because the Jacobian is often rank-deficient and in such cases
-// using a direct solver leads to numerical failure.
-//
-// If SUBSPACE is passed as the type argument to the constructor, the
-// DoglegStrategy follows the approach by Shultz, Schnabel, Byrd.
-// This finds the exact optimum over the two-dimensional subspace
-// spanned by the two Dogleg vectors.
-class DoglegStrategy : public TrustRegionStrategy {
- public:
- explicit DoglegStrategy(const TrustRegionStrategy::Options& options);
- virtual ~DoglegStrategy() {}
-
- // TrustRegionStrategy interface
- virtual Summary ComputeStep(const PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals,
- double* step);
- virtual void StepAccepted(double step_quality);
- virtual void StepRejected(double step_quality);
- virtual void StepIsInvalid();
-
- virtual double Radius() const;
-
- // These functions are predominantly for testing.
- Vector gradient() const { return gradient_; }
- Vector gauss_newton_step() const { return gauss_newton_step_; }
- Matrix subspace_basis() const { return subspace_basis_; }
- Vector subspace_g() const { return subspace_g_; }
- Matrix subspace_B() const { return subspace_B_; }
-
- private:
- typedef Eigen::Matrix<double, 2, 1, Eigen::DontAlign> Vector2d;
- typedef Eigen::Matrix<double, 2, 2, Eigen::DontAlign> Matrix2d;
-
- LinearSolver::Summary ComputeGaussNewtonStep(
- const PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals);
- void ComputeCauchyPoint(SparseMatrix* jacobian);
- void ComputeGradient(SparseMatrix* jacobian, const double* residuals);
- void ComputeTraditionalDoglegStep(double* step);
- bool ComputeSubspaceModel(SparseMatrix* jacobian);
- void ComputeSubspaceDoglegStep(double* step);
-
- bool FindMinimumOnTrustRegionBoundary(Vector2d* minimum) const;
- Vector MakePolynomialForBoundaryConstrainedProblem() const;
- Vector2d ComputeSubspaceStepFromRoot(double lambda) const;
- double EvaluateSubspaceModel(const Vector2d& x) const;
-
- LinearSolver* linear_solver_;
- double radius_;
- const double max_radius_;
-
- const double min_diagonal_;
- const double max_diagonal_;
-
- // mu is used to scale the diagonal matrix used to make the
- // Gauss-Newton solve full rank. In each solve, the strategy starts
- // out with mu = min_mu, and tries values upto max_mu. If the user
- // reports an invalid step, the value of mu_ is increased so that
- // the next solve starts with a stronger regularization.
- //
- // If a successful step is reported, then the value of mu_ is
- // decreased with a lower bound of min_mu_.
- double mu_;
- const double min_mu_;
- const double max_mu_;
- const double mu_increase_factor_;
- const double increase_threshold_;
- const double decrease_threshold_;
-
- Vector diagonal_; // sqrt(diag(J^T J))
- Vector lm_diagonal_;
-
- Vector gradient_;
- Vector gauss_newton_step_;
-
- // cauchy_step = alpha * gradient
- double alpha_;
- double dogleg_step_norm_;
-
- // When, ComputeStep is called, reuse_ indicates whether the
- // Gauss-Newton and Cauchy steps from the last call to ComputeStep
- // can be reused or not.
- //
- // If the user called StepAccepted, then it is expected that the
- // user has recomputed the Jacobian matrix and new Gauss-Newton
- // solve is needed and reuse is set to false.
- //
- // If the user called StepRejected, then it is expected that the
- // user wants to solve the trust region problem with the same matrix
- // but a different trust region radius and the Gauss-Newton and
- // Cauchy steps can be reused to compute the Dogleg, thus reuse is
- // set to true.
- //
- // If the user called StepIsInvalid, then there was a numerical
- // problem with the step computed in the last call to ComputeStep,
- // and the regularization used to do the Gauss-Newton solve is
- // increased and a new solve should be done when ComputeStep is
- // called again, thus reuse is set to false.
- bool reuse_;
-
- // The dogleg type determines how the minimum of the local
- // quadratic model is found.
- DoglegType dogleg_type_;
-
- // If the type is SUBSPACE_DOGLEG, the two-dimensional
- // model 1/2 x^T B x + g^T x has to be computed and stored.
- bool subspace_is_one_dimensional_;
- Matrix subspace_basis_;
- Vector2d subspace_g_;
- Matrix2d subspace_B_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DOGLEG_STRATEGY_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h b/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
deleted file mode 100644
index 5e6b0d84510..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: richie.stebbing@gmail.com (Richard Stebbing)
-
-#ifndef CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALIZER_H_
-#define CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALIZER_H_
-
-#include "ceres/casts.h"
-#include "ceres/dynamic_compressed_row_sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-struct DynamicCompressedRowJacobianFinalizer {
- void operator()(SparseMatrix* base_jacobian, int num_parameters) {
- DynamicCompressedRowSparseMatrix* jacobian =
- down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
- jacobian->Finalize(num_parameters);
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALISER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc b/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
deleted file mode 100644
index b46cb797ff2..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: richie.stebbing@gmail.com (Richard Stebbing)
-
-#include "ceres/compressed_row_jacobian_writer.h"
-#include "ceres/dynamic_compressed_row_jacobian_writer.h"
-#include "ceres/casts.h"
-#include "ceres/dynamic_compressed_row_sparse_matrix.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-
-namespace ceres {
-namespace internal {
-
-ScratchEvaluatePreparer*
-DynamicCompressedRowJacobianWriter::CreateEvaluatePreparers(int num_threads) {
- return ScratchEvaluatePreparer::Create(*program_, num_threads);
-}
-
-SparseMatrix* DynamicCompressedRowJacobianWriter::CreateJacobian() const {
- // Initialize `jacobian` with zero number of `max_num_nonzeros`.
- const int num_residuals = program_->NumResiduals();
- const int num_effective_parameters = program_->NumEffectiveParameters();
-
- DynamicCompressedRowSparseMatrix* jacobian =
- new DynamicCompressedRowSparseMatrix(num_residuals,
- num_effective_parameters,
- 0);
-
- vector<int>* row_blocks = jacobian->mutable_row_blocks();
- for (int i = 0; i < jacobian->num_rows(); ++i) {
- row_blocks->push_back(1);
- }
-
- vector<int>* col_blocks = jacobian->mutable_col_blocks();
- for (int i = 0; i < jacobian->num_cols(); ++i) {
- col_blocks->push_back(1);
- }
-
- return jacobian;
-}
-
-void DynamicCompressedRowJacobianWriter::Write(int residual_id,
- int residual_offset,
- double **jacobians,
- SparseMatrix* base_jacobian) {
- DynamicCompressedRowSparseMatrix* jacobian =
- down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
-
- // Get the `residual_block` of interest.
- const ResidualBlock* residual_block =
- program_->residual_blocks()[residual_id];
- const int num_residuals = residual_block->NumResiduals();
-
- vector<pair<int, int> > evaluated_jacobian_blocks;
- CompressedRowJacobianWriter::GetOrderedParameterBlocks(
- program_, residual_id, &evaluated_jacobian_blocks);
-
- // `residual_offset` is the residual row in the global jacobian.
- // Empty the jacobian rows.
- jacobian->ClearRows(residual_offset, num_residuals);
-
- // Iterate over each parameter block.
- for (int i = 0; i < evaluated_jacobian_blocks.size(); ++i) {
- const ParameterBlock* parameter_block =
- program_->parameter_blocks()[evaluated_jacobian_blocks[i].first];
- const int parameter_block_jacobian_index =
- evaluated_jacobian_blocks[i].second;
- const int parameter_block_size = parameter_block->LocalSize();
-
- // For each parameter block only insert its non-zero entries.
- for (int r = 0; r < num_residuals; ++r) {
- for (int c = 0; c < parameter_block_size; ++c) {
- const double& v = jacobians[parameter_block_jacobian_index][
- r * parameter_block_size + c];
- // Only insert non-zero entries.
- if (v != 0.0) {
- jacobian->InsertEntry(
- residual_offset + r, parameter_block->delta_offset() + c, v);
- }
- }
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h b/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
deleted file mode 100644
index df9581b145d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: richie.stebbing@gmail.com (Richard Stebbing)
-//
-// A jacobian writer that directly writes to dynamic compressed row sparse
-// matrices.
-
-#ifndef CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
-#define CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
-
-#include "ceres/evaluator.h"
-#include "ceres/scratch_evaluate_preparer.h"
-
-namespace ceres {
-namespace internal {
-
-class Program;
-class SparseMatrix;
-
-class DynamicCompressedRowJacobianWriter {
- public:
- DynamicCompressedRowJacobianWriter(Evaluator::Options /* ignored */,
- Program* program)
- : program_(program) {
- }
-
- // JacobianWriter interface.
-
- // The compressed row matrix has different layout than that assumed by
- // the cost functions. The scratch space is therefore used to store
- // the jacobians (including zeros) temporarily before only the non-zero
- // entries are copied over to the larger jacobian in `Write`.
- ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads);
-
- // Return a `DynamicCompressedRowSparseMatrix` which is filled by
- // `Write`. Note that `Finalize` must be called to make the
- // `CompressedRowSparseMatrix` interface valid.
- SparseMatrix* CreateJacobian() const;
-
- // Write only the non-zero jacobian entries for a residual block
- // (specified by `residual_id`) into `base_jacobian`, starting at the row
- // specifed by `residual_offset`.
- //
- // This method is thread-safe over residual blocks (each `residual_id`).
- void Write(int residual_id,
- int residual_offset,
- double **jacobians,
- SparseMatrix* base_jacobian);
-
- private:
- Program* program_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
deleted file mode 100644
index f285d52a342..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: richie.stebbing@gmail.com (Richard Stebbing)
-
-#include <cstring>
-#include "ceres/dynamic_compressed_row_sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-DynamicCompressedRowSparseMatrix::DynamicCompressedRowSparseMatrix(
- int num_rows,
- int num_cols,
- int initial_max_num_nonzeros)
- : CompressedRowSparseMatrix(num_rows,
- num_cols,
- initial_max_num_nonzeros) {
- dynamic_cols_.resize(num_rows);
- dynamic_values_.resize(num_rows);
- }
-
-void DynamicCompressedRowSparseMatrix::InsertEntry(int row,
- int col,
- const double& value) {
- CHECK_GE(row, 0);
- CHECK_LT(row, num_rows());
- CHECK_GE(col, 0);
- CHECK_LT(col, num_cols());
- dynamic_cols_[row].push_back(col);
- dynamic_values_[row].push_back(value);
-}
-
-void DynamicCompressedRowSparseMatrix::ClearRows(int row_start,
- int num_rows) {
- for (int r = 0; r < num_rows; ++r) {
- const int i = row_start + r;
- CHECK_GE(i, 0);
- CHECK_LT(i, this->num_rows());
- dynamic_cols_[i].resize(0);
- dynamic_values_[i].resize(0);
- }
-}
-
-void DynamicCompressedRowSparseMatrix::Finalize(int num_additional_elements) {
- // `num_additional_elements` is provided as an argument so that additional
- // storage can be reserved when it is known by the finalizer.
- CHECK_GE(num_additional_elements, 0);
-
- // Count the number of non-zeros and resize `cols_` and `values_`.
- int num_jacobian_nonzeros = 0;
- for (int i = 0; i < dynamic_cols_.size(); ++i) {
- num_jacobian_nonzeros += dynamic_cols_[i].size();
- }
-
- SetMaxNumNonZeros(num_jacobian_nonzeros + num_additional_elements);
-
- // Flatten `dynamic_cols_` into `cols_` and `dynamic_values_`
- // into `values_`.
- int index_into_values_and_cols = 0;
- for (int i = 0; i < num_rows(); ++i) {
- mutable_rows()[i] = index_into_values_and_cols;
- const int num_nonzero_columns = dynamic_cols_[i].size();
- if (num_nonzero_columns > 0) {
- memcpy(mutable_cols() + index_into_values_and_cols,
- &dynamic_cols_[i][0],
- dynamic_cols_[i].size() * sizeof(dynamic_cols_[0][0]));
- memcpy(mutable_values() + index_into_values_and_cols,
- &dynamic_values_[i][0],
- dynamic_values_[i].size() * sizeof(dynamic_values_[0][0]));
- index_into_values_and_cols += dynamic_cols_[i].size();
- }
- }
- mutable_rows()[num_rows()] = index_into_values_and_cols;
-
- CHECK_EQ(index_into_values_and_cols, num_jacobian_nonzeros)
- << "Ceres bug: final index into values_ and cols_ should be equal to "
- << "the number of jacobian nonzeros. Please contact the developers!";
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
deleted file mode 100644
index 7a89a708658..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: richie.stebbing@gmail.com (Richard Stebbing)
-//
-// A compressed row sparse matrix that provides an extended interface to
-// allow dynamic insertion of entries. This is provided for the use case
-// where the sparsity structure and number of non-zero entries is dynamic.
-// This flexibility is achieved by using an (internal) scratch space that
-// allows independent insertion of entries into each row (thread-safe).
-// Once insertion is complete, the `Finalize` method must be called to ensure
-// that the underlying `CompressedRowSparseMatrix` is consistent.
-//
-// This should only be used if you really do need a dynamic sparsity pattern.
-
-#ifndef CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
-
-#include "ceres/compressed_row_sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-class DynamicCompressedRowSparseMatrix : public CompressedRowSparseMatrix {
- public:
- // Set the number of rows and columns for the underlyig
- // `CompressedRowSparseMatrix` and set the initial number of maximum non-zero
- // entries. Note that following the insertion of entries, when `Finalize`
- // is called the number of non-zeros is determined and all internal
- // structures are adjusted as required. If you know the upper limit on the
- // number of non-zeros, then passing this value here can prevent future
- // memory reallocations which may improve performance. Otherwise, if no
- // upper limit is available a value of 0 is sufficient.
- //
- // Typical usage of this class is to define a new instance with a given
- // number of rows, columns and maximum number of non-zero elements
- // (if available). Next, entries are inserted at row and column positions
- // using `InsertEntry`. Finally, once all elements have been inserted,
- // `Finalize` must be called to make the underlying
- // `CompressedRowSparseMatrix` consistent.
- DynamicCompressedRowSparseMatrix(int num_rows,
- int num_cols,
- int initial_max_num_nonzeros);
-
- // Insert an entry at a given row and column position. This method is
- // thread-safe across rows i.e. different threads can insert values
- // simultaneously into different rows. It should be emphasised that this
- // method always inserts a new entry and does not check for existing
- // entries at the specified row and column position. Duplicate entries
- // for a given row and column position will result in undefined
- // behavior.
- void InsertEntry(int row, int col, const double& value);
-
- // Clear all entries for rows, starting from row index `row_start`
- // and proceeding for `num_rows`.
- void ClearRows(int row_start, int num_rows);
-
- // Make the underlying internal `CompressedRowSparseMatrix` data structures
- // consistent. Additional space for non-zero entries in the
- // `CompressedRowSparseMatrix` can be reserved by specifying
- // `num_additional_elements`. This is useful when it is known that rows will
- // be appended to the `CompressedRowSparseMatrix` (e.g. appending a diagonal
- // matrix to the jacobian) as it prevents need for future reallocation.
- void Finalize(int num_additional_elements);
-
- private:
- vector<vector<int> > dynamic_cols_;
- vector<vector<double> > dynamic_values_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc b/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc
deleted file mode 100644
index c94c62c29b5..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include <vector>
-#include "ceres/block_evaluate_preparer.h"
-#include "ceres/block_jacobian_writer.h"
-#include "ceres/compressed_row_jacobian_writer.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/crs_matrix.h"
-#include "ceres/dense_jacobian_writer.h"
-#include "ceres/dynamic_compressed_row_finalizer.h"
-#include "ceres/dynamic_compressed_row_jacobian_writer.h"
-#include "ceres/evaluator.h"
-#include "ceres/internal/port.h"
-#include "ceres/program_evaluator.h"
-#include "ceres/scratch_evaluate_preparer.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-Evaluator::~Evaluator() {}
-
-Evaluator* Evaluator::Create(const Evaluator::Options& options,
- Program* program,
- string* error) {
- switch (options.linear_solver_type) {
- case DENSE_QR:
- case DENSE_NORMAL_CHOLESKY:
- return new ProgramEvaluator<ScratchEvaluatePreparer,
- DenseJacobianWriter>(options,
- program);
- case DENSE_SCHUR:
- case SPARSE_SCHUR:
- case ITERATIVE_SCHUR:
- case CGNR:
- return new ProgramEvaluator<BlockEvaluatePreparer,
- BlockJacobianWriter>(options,
- program);
- case SPARSE_NORMAL_CHOLESKY:
- if (options.dynamic_sparsity) {
- return new ProgramEvaluator<ScratchEvaluatePreparer,
- DynamicCompressedRowJacobianWriter,
- DynamicCompressedRowJacobianFinalizer>(
- options, program);
- } else {
- return new ProgramEvaluator<ScratchEvaluatePreparer,
- CompressedRowJacobianWriter>(options,
- program);
- }
-
- default:
- *error = "Invalid Linear Solver Type. Unable to create evaluator.";
- return NULL;
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
deleted file mode 100644
index 8fc60b87869..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
+++ /dev/null
@@ -1,205 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_EVALUATOR_H_
-#define CERES_INTERNAL_EVALUATOR_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "ceres/execution_summary.h"
-#include "ceres/internal/port.h"
-#include "ceres/types.h"
-
-namespace ceres {
-
-struct CRSMatrix;
-
-namespace internal {
-
-class Program;
-class SparseMatrix;
-
-// The Evaluator interface offers a way to interact with a least squares cost
-// function that is useful for an optimizer that wants to minimize the least
-// squares objective. This insulates the optimizer from issues like Jacobian
-// storage, parameterization, etc.
-class Evaluator {
- public:
- virtual ~Evaluator();
-
- struct Options {
- Options()
- : num_threads(1),
- num_eliminate_blocks(-1),
- linear_solver_type(DENSE_QR),
- dynamic_sparsity(false) {}
-
- int num_threads;
- int num_eliminate_blocks;
- LinearSolverType linear_solver_type;
- bool dynamic_sparsity;
- };
-
- static Evaluator* Create(const Options& options,
- Program* program,
- string* error);
-
- // This is used for computing the cost, residual and Jacobian for
- // returning to the user. For actually solving the optimization
- // problem, the optimization algorithm uses the ProgramEvaluator
- // objects directly.
- //
- // The residual, gradients and jacobian pointers can be NULL, in
- // which case they will not be evaluated. cost cannot be NULL.
- //
- // The parallelism of the evaluator is controlled by num_threads; it
- // should be at least 1.
- //
- // Note: That this function does not take a parameter vector as
- // input. The parameter blocks are evaluated on the values contained
- // in the arrays pointed to by their user_state pointers.
- //
- // Also worth noting is that this function mutates program by
- // calling Program::SetParameterOffsetsAndIndex() on it so that an
- // evaluator object can be constructed.
- static bool Evaluate(Program* program,
- int num_threads,
- double* cost,
- vector<double>* residuals,
- vector<double>* gradient,
- CRSMatrix* jacobian);
-
- // Build and return a sparse matrix for storing and working with the Jacobian
- // of the objective function. The jacobian has dimensions
- // NumEffectiveParameters() by NumParameters(), and is typically extremely
- // sparse. Since the sparsity pattern of the Jacobian remains constant over
- // the lifetime of the optimization problem, this method is used to
- // instantiate a SparseMatrix object with the appropriate sparsity structure
- // (which can be an expensive operation) and then reused by the optimization
- // algorithm and the various linear solvers.
- //
- // It is expected that the classes implementing this interface will be aware
- // of their client's requirements for the kind of sparse matrix storage and
- // layout that is needed for an efficient implementation. For example
- // CompressedRowOptimizationProblem creates a compressed row representation of
- // the jacobian for use with CHOLMOD, where as BlockOptimizationProblem
- // creates a BlockSparseMatrix representation of the jacobian for use in the
- // Schur complement based methods.
- virtual SparseMatrix* CreateJacobian() const = 0;
-
-
- // Options struct to control Evaluator::Evaluate;
- struct EvaluateOptions {
- EvaluateOptions()
- : apply_loss_function(true) {
- }
-
- // If false, the loss function correction is not applied to the
- // residual blocks.
- bool apply_loss_function;
- };
-
- // Evaluate the cost function for the given state. Returns the cost,
- // residuals, and jacobian in the corresponding arguments. Both residuals and
- // jacobian are optional; to avoid computing them, pass NULL.
- //
- // If non-NULL, the Jacobian must have a suitable sparsity pattern; only the
- // values array of the jacobian is modified.
- //
- // state is an array of size NumParameters(), cost is a pointer to a single
- // double, and residuals is an array of doubles of size NumResiduals().
- virtual bool Evaluate(const EvaluateOptions& evaluate_options,
- const double* state,
- double* cost,
- double* residuals,
- double* gradient,
- SparseMatrix* jacobian) = 0;
-
- // Variant of Evaluator::Evaluate where the user wishes to use the
- // default EvaluateOptions struct. This is mostly here as a
- // convenience method.
- bool Evaluate(const double* state,
- double* cost,
- double* residuals,
- double* gradient,
- SparseMatrix* jacobian) {
- return Evaluate(EvaluateOptions(),
- state,
- cost,
- residuals,
- gradient,
- jacobian);
- }
-
- // Make a change delta (of size NumEffectiveParameters()) to state (of size
- // NumParameters()) and store the result in state_plus_delta.
- //
- // In the case that there are no parameterizations used, this is equivalent to
- //
- // state_plus_delta[i] = state[i] + delta[i] ;
- //
- // however, the mapping is more complicated in the case of parameterizations
- // like quaternions. This is the same as the "Plus()" operation in
- // local_parameterization.h, but operating over the entire state vector for a
- // problem.
- virtual bool Plus(const double* state,
- const double* delta,
- double* state_plus_delta) const = 0;
-
- // The number of parameters in the optimization problem.
- virtual int NumParameters() const = 0;
-
- // This is the effective number of parameters that the optimizer may adjust.
- // This applies when there are parameterizations on some of the parameters.
- virtual int NumEffectiveParameters() const = 0;
-
- // The number of residuals in the optimization problem.
- virtual int NumResiduals() const = 0;
-
- // The following two methods return copies instead of references so
- // that the base class implementation does not have to worry about
- // life time issues. Further, these calls are not expected to be
- // frequent or performance sensitive.
- virtual map<string, int> CallStatistics() const {
- return map<string, int>();
- }
-
- virtual map<string, double> TimeStatistics() const {
- return map<string, double>();
- }
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_EVALUATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h
deleted file mode 100644
index 29bdc69ecd7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_EXECUTION_SUMMARY_H_
-#define CERES_INTERNAL_EXECUTION_SUMMARY_H_
-
-#include <map>
-#include <string>
-
-#include "ceres/internal/port.h"
-#include "ceres/wall_time.h"
-#include "ceres/mutex.h"
-
-namespace ceres {
-namespace internal {
-
-// Struct used by various objects to report statistics and other
-// information about their execution. e.g., ExecutionSummary::times
-// can be used for reporting times associated with various activities.
-class ExecutionSummary {
- public:
- void IncrementTimeBy(const string& name, const double value) {
- CeresMutexLock l(&times_mutex_);
- times_[name] += value;
- }
-
- void IncrementCall(const string& name) {
- CeresMutexLock l(&calls_mutex_);
- calls_[name] += 1;
- }
-
- const map<string, double>& times() const { return times_; }
- const map<string, int>& calls() const { return calls_; }
-
- private:
- Mutex times_mutex_;
- map<string, double> times_;
-
- Mutex calls_mutex_;
- map<string, int> calls_;
-};
-
-class ScopedExecutionTimer {
- public:
- ScopedExecutionTimer(const string& name, ExecutionSummary* summary)
- : start_time_(WallTimeInSeconds()),
- name_(name),
- summary_(summary) {}
-
- ~ScopedExecutionTimer() {
- summary_->IncrementTimeBy(name_, WallTimeInSeconds() - start_time_);
- }
-
- private:
- const double start_time_;
- const string name_;
- ExecutionSummary* summary_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_EXECUTION_SUMMARY_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/file.cc b/extern/libmv/third_party/ceres/internal/ceres/file.cc
deleted file mode 100644
index 5226c85e6ee..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/file.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Really simple file IO.
-
-#include "ceres/file.h"
-
-#include <cstdio>
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-using std::string;
-
-void WriteStringToFileOrDie(const string &data, const string &filename) {
- FILE* file_descriptor = fopen(filename.c_str(), "wb");
- if (!file_descriptor) {
- LOG(FATAL) << "Couldn't write to file: " << filename;
- }
- fwrite(data.c_str(), 1, data.size(), file_descriptor);
- fclose(file_descriptor);
-}
-
-void ReadFileToStringOrDie(const string &filename, string *data) {
- FILE* file_descriptor = fopen(filename.c_str(), "r");
-
- if (!file_descriptor) {
- LOG(FATAL) << "Couldn't read file: " << filename;
- }
-
- // Resize the input buffer appropriately.
- fseek(file_descriptor, 0L, SEEK_END);
- int num_bytes = ftell(file_descriptor);
- data->resize(num_bytes);
-
- // Read the data.
- fseek(file_descriptor, 0L, SEEK_SET);
- int num_read = fread(&((*data)[0]),
- sizeof((*data)[0]),
- num_bytes,
- file_descriptor);
- if (num_read != num_bytes) {
- LOG(FATAL) << "Couldn't read all of " << filename
- << "expected bytes: " << num_bytes * sizeof((*data)[0])
- << "actual bytes: " << num_read;
- }
- fclose(file_descriptor);
-}
-
-string JoinPath(const string& dirname, const string& basename) {
-#ifdef _WIN32
- static const char separator = '\\';
-#else
- static const char separator = '/';
-#endif // _WIN32
-
- if ((!basename.empty() && basename[0] == separator) || dirname.empty()) {
- return basename;
- } else if (dirname[dirname.size() - 1] == separator) {
- return dirname + basename;
- } else {
- return dirname + string(&separator, 1) + basename;
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/file.h b/extern/libmv/third_party/ceres/internal/ceres/file.h
deleted file mode 100644
index 4741d650646..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/file.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Simple file IO support. This is a portability shim.
-
-#ifndef CERES_INTERNAL_FILE_H_
-#define CERES_INTERNAL_FILE_H_
-
-#include <string>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-void WriteStringToFileOrDie(const string &data, const string &filename);
-void ReadFileToStringOrDie(const string &filename, string *data);
-
-// Join two path components, adding a slash if necessary. If basename is an
-// absolute path then JoinPath ignores dirname and simply returns basename.
-string JoinPath(const string& dirname, const string& basename);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_FILE_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py b/extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py
deleted file mode 100644
index 2ec3c5b42ca..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generate_eliminator_specialization.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-# http://code.google.com/p/ceres-solver/
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-# * Neither the name of Google Inc. nor the names of its contributors may be
-# used to endorse or promote products derived from this software without
-# specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: sameeragarwal@google.com (Sameer Agarwal)
-#
-# Script for explicitly generating template specialization of the
-# SchurEliminator class. It is a rather large class
-# and the number of explicit instantiations is also large. Explicitly
-# generating these instantiations in separate .cc files breaks the
-# compilation into separate compilation unit rather than one large cc
-# file which takes 2+GB of RAM to compile.
-#
-# This script creates two sets of files.
-#
-# 1. schur_eliminator_x_x_x.cc
-# where, the x indicates the template parameters and
-#
-# 2. schur_eliminator.cc
-#
-# that contains a factory function for instantiating these classes
-# based on runtime parameters.
-#
-# The list of tuples, specializations indicates the set of
-# specializations that is generated.
-
-# Set of template specializations to generate
-SPECIALIZATIONS = [(2, 2, 2),
- (2, 2, 3),
- (2, 2, 4),
- (2, 2, "Eigen::Dynamic"),
- (2, 3, 3),
- (2, 3, 4),
- (2, 3, 9),
- (2, 3, "Eigen::Dynamic"),
- (2, 4, 3),
- (2, 4, 4),
- (2, 4, 8),
- (2, 4, 9),
- (2, 4, "Eigen::Dynamic"),
- (2, "Eigen::Dynamic", "Eigen::Dynamic"),
- (4, 4, 2),
- (4, 4, 3),
- (4, 4, 4),
- (4, 4, "Eigen::Dynamic"),
- ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
-HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-"""
-
-DYNAMIC_FILE = """
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<%s, %s, %s>;
-
-} // namespace internal
-} // namespace ceres
-"""
-
-SPECIALIZATION_FILE = """
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<%s, %s, %s>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
-"""
-
-FACTORY_FILE_HEADER = """
-#include "ceres/linear_solver.h"
-#include "ceres/schur_eliminator.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-SchurEliminatorBase*
-SchurEliminatorBase::Create(const LinearSolver::Options& options) {
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-"""
-
-FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) &&
- (options.e_block_size == %s) &&
- (options.f_block_size == %s)) {
- return new SchurEliminator<%s, %s, %s>(options);
- }
-"""
-
-FACTORY_FOOTER = """
-#endif
- VLOG(1) << "Template specializations not found for <"
- << options.row_block_size << ","
- << options.e_block_size << ","
- << options.f_block_size << ">";
- return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
-}
-
-} // namespace internal
-} // namespace ceres
-"""
-
-
-def SuffixForSize(size):
- if size == "Eigen::Dynamic":
- return "d"
- return str(size)
-
-
-def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
- return "_".join([prefix] + map(SuffixForSize, (row_block_size,
- e_block_size,
- f_block_size)))
-
-
-def Specialize():
- """
- Generate specialization code and the conditionals to instantiate it.
- """
- f = open("schur_eliminator.cc", "w")
- f.write(HEADER)
- f.write(FACTORY_FILE_HEADER)
-
- for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
- output = SpecializationFilename("generated/schur_eliminator",
- row_block_size,
- e_block_size,
- f_block_size) + ".cc"
- fptr = open(output, "w")
- fptr.write(HEADER)
-
- template = SPECIALIZATION_FILE
- if (row_block_size == "Eigen::Dynamic" and
- e_block_size == "Eigen::Dynamic" and
- f_block_size == "Eigen::Dynamic"):
- template = DYNAMIC_FILE
-
- fptr.write(template % (row_block_size, e_block_size, f_block_size))
- fptr.close()
-
- f.write(FACTORY_CONDITIONAL % (row_block_size,
- e_block_size,
- f_block_size,
- row_block_size,
- e_block_size,
- f_block_size))
- f.write(FACTORY_FOOTER)
- f.close()
-
-
-if __name__ == "__main__":
- Specialize()
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py b/extern/libmv/third_party/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py
deleted file mode 100644
index c9bdf238ce0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generate_partitioned_matrix_view_specializations.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2013 Google Inc. All rights reserved.
-# http://code.google.com/p/ceres-solver/
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-# * Neither the name of Google Inc. nor the names of its contributors may be
-# used to endorse or promote products derived from this software without
-# specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# Author: sameeragarwal@google.com (Sameer Agarwal)
-#
-# Script for explicitly generating template specialization of the
-# PartitionedMatrixView class. Explicitly generating these
-# instantiations in separate .cc files breaks the compilation into
-# separate compilation unit rather than one large cc file.
-#
-# This script creates two sets of files.
-#
-# 1. partitioned_matrix_view_x_x_x.cc
-# where the x indicates the template parameters and
-#
-# 2. partitioned_matrix_view.cc
-#
-# that contains a factory function for instantiating these classes
-# based on runtime parameters.
-#
-# The list of tuples, specializations indicates the set of
-# specializations that is generated.
-
-# Set of template specializations to generate
-SPECIALIZATIONS = [(2, 2, 2),
- (2, 2, 3),
- (2, 2, 4),
- (2, 2, "Eigen::Dynamic"),
- (2, 3, 3),
- (2, 3, 4),
- (2, 3, 9),
- (2, 3, "Eigen::Dynamic"),
- (2, 4, 3),
- (2, 4, 4),
- (2, 4, 8),
- (2, 4, 9),
- (2, 4, "Eigen::Dynamic"),
- (2, "Eigen::Dynamic", "Eigen::Dynamic"),
- (4, 4, 2),
- (4, 4, 3),
- (4, 4, 4),
- (4, 4, "Eigen::Dynamic"),
- ("Eigen::Dynamic", "Eigen::Dynamic", "Eigen::Dynamic")]
-HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-"""
-
-DYNAMIC_FILE = """
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<%s, %s, %s>;
-
-} // namespace internal
-} // namespace ceres
-"""
-
-SPECIALIZATION_FILE = """
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<%s, %s, %s>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
-"""
-
-FACTORY_FILE_HEADER = """
-#include "ceres/linear_solver.h"
-#include "ceres/partitioned_matrix_view.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-PartitionedMatrixViewBase*
-PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
- const BlockSparseMatrix& matrix) {
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-"""
-
-FACTORY_CONDITIONAL = """ if ((options.row_block_size == %s) &&
- (options.e_block_size == %s) &&
- (options.f_block_size == %s)) {
- return new PartitionedMatrixView<%s, %s, %s>(
- matrix, options.elimination_groups[0]);
- }
-"""
-
-FACTORY_FOOTER = """
-#endif
- VLOG(1) << "Template specializations not found for <"
- << options.row_block_size << ","
- << options.e_block_size << ","
- << options.f_block_size << ">";
- return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
-};
-
-} // namespace internal
-} // namespace ceres
-"""
-
-
-def SuffixForSize(size):
- if size == "Eigen::Dynamic":
- return "d"
- return str(size)
-
-
-def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
- return "_".join([prefix] + map(SuffixForSize, (row_block_size,
- e_block_size,
- f_block_size)))
-
-
-def Specialize():
- """
- Generate specialization code and the conditionals to instantiate it.
- """
- f = open("partitioned_matrix_view.cc", "w")
- f.write(HEADER)
- f.write(FACTORY_FILE_HEADER)
-
- for row_block_size, e_block_size, f_block_size in SPECIALIZATIONS:
- output = SpecializationFilename("generated/partitioned_matrix_view",
- row_block_size,
- e_block_size,
- f_block_size) + ".cc"
- fptr = open(output, "w")
- fptr.write(HEADER)
-
- template = SPECIALIZATION_FILE
- if (row_block_size == "Eigen::Dynamic" and
- e_block_size == "Eigen::Dynamic" and
- f_block_size == "Eigen::Dynamic"):
- template = DYNAMIC_FILE
-
- fptr.write(template % (row_block_size, e_block_size, f_block_size))
- fptr.close()
-
- f.write(FACTORY_CONDITIONAL % (row_block_size,
- e_block_size,
- f_block_size,
- row_block_size,
- e_block_size,
- f_block_size))
- f.write(FACTORY_FOOTER)
- f.close()
-
-
-if __name__ == "__main__":
- Specialize()
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
deleted file mode 100644
index a7d802ad8c0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 2, 2>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
deleted file mode 100644
index 89e6f7750b1..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 2, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
deleted file mode 100644
index 3a3e8b67243..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 2, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
deleted file mode 100644
index 661f135cd10..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 2, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
deleted file mode 100644
index e79e001d6c6..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 3, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
deleted file mode 100644
index 2f1ae68d66a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 3, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
deleted file mode 100644
index ab405503925..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 3, 9>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
deleted file mode 100644
index 89ecff73319..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 3, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
deleted file mode 100644
index 182707d7df7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 4, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
deleted file mode 100644
index a2cf8f4a9dd..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 4, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
deleted file mode 100644
index a2637691cb0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 4, 8>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
deleted file mode 100644
index d853860326e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 4, 9>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
deleted file mode 100644
index 7d622fcabbb..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, 4, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
deleted file mode 100644
index 31981cae461..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
deleted file mode 100644
index d51ab5ff715..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<4, 4, 2>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
deleted file mode 100644
index 4b17fbdecde..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<4, 4, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
deleted file mode 100644
index 7b5fe0f35a7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<4, 4, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
deleted file mode 100644
index c31fed395a8..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<4, 4, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
deleted file mode 100644
index a3308ede789..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-
-#include "ceres/partitioned_matrix_view_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
deleted file mode 100644
index db2a4dc6b44..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 2, 2>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
deleted file mode 100644
index f53c12a4373..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 2, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
deleted file mode 100644
index 9e29383b00f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 2, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
deleted file mode 100644
index 541def6fc37..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 2, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
deleted file mode 100644
index e450263825b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 3, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
deleted file mode 100644
index 0618c684af8..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 3, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
deleted file mode 100644
index c1ca665d45f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 3, 9>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
deleted file mode 100644
index 1b6092c75a9..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 3, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
deleted file mode 100644
index edce8ef717b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 4, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
deleted file mode 100644
index a6f3c52d7f2..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 4, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
deleted file mode 100644
index bf2f0abb1cf..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 4, 8>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
deleted file mode 100644
index a63d0bbe0a6..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 4, 9>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
deleted file mode 100644
index b3a7fffb33e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, 4, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
deleted file mode 100644
index f4d28cd1642..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
deleted file mode 100644
index d1eadc1fc83..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<4, 4, 2>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
deleted file mode 100644
index c340dbfc754..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<4, 4, 3>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
deleted file mode 100644
index b7d58ad026f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<4, 4, 4>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
deleted file mode 100644
index 47e00592b4e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<4, 4, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc b/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
deleted file mode 100644
index d54a03cadd4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-
-#include "ceres/schur_eliminator_impl.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-template class SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>;
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
deleted file mode 100644
index 3272848a499..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/gradient_checking_cost_function.h"
-
-#include <algorithm>
-#include <cmath>
-#include <numeric>
-#include <string>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/parameter_block.h"
-#include "ceres/problem.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/dynamic_numeric_diff_cost_function.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-// True if x and y have an absolute relative difference less than
-// relative_precision and false otherwise. Stores the relative and absolute
-// difference in relative/absolute_error if non-NULL.
-bool IsClose(double x, double y, double relative_precision,
- double *relative_error,
- double *absolute_error) {
- double local_absolute_error;
- double local_relative_error;
- if (!absolute_error) {
- absolute_error = &local_absolute_error;
- }
- if (!relative_error) {
- relative_error = &local_relative_error;
- }
- *absolute_error = fabs(x - y);
- *relative_error = *absolute_error / max(fabs(x), fabs(y));
- if (x == 0 || y == 0) {
- // If x or y is exactly zero, then relative difference doesn't have any
- // meaning. Take the absolute difference instead.
- *relative_error = *absolute_error;
- }
- return fabs(*relative_error) < fabs(relative_precision);
-}
-
-class GradientCheckingCostFunction : public CostFunction {
- public:
- GradientCheckingCostFunction(const CostFunction* function,
- double relative_step_size,
- double relative_precision,
- const string& extra_info)
- : function_(function),
- relative_precision_(relative_precision),
- extra_info_(extra_info) {
- DynamicNumericDiffCostFunction<CostFunction, CENTRAL>*
- finite_diff_cost_function =
- new DynamicNumericDiffCostFunction<CostFunction, CENTRAL>(
- function,
- DO_NOT_TAKE_OWNERSHIP,
- relative_step_size);
-
- const vector<int32>& parameter_block_sizes =
- function->parameter_block_sizes();
- for (int i = 0; i < parameter_block_sizes.size(); ++i) {
- finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]);
- }
- *mutable_parameter_block_sizes() = parameter_block_sizes;
- set_num_residuals(function->num_residuals());
- finite_diff_cost_function->SetNumResiduals(num_residuals());
- finite_diff_cost_function_.reset(finite_diff_cost_function);
- }
-
- virtual ~GradientCheckingCostFunction() { }
-
- virtual bool Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- if (!jacobians) {
- // Nothing to check in this case; just forward.
- return function_->Evaluate(parameters, residuals, NULL);
- }
-
- int num_residuals = function_->num_residuals();
-
- // Make space for the jacobians of the two methods.
- const vector<int32>& block_sizes = function_->parameter_block_sizes();
- vector<Matrix> term_jacobians(block_sizes.size());
- vector<Matrix> finite_difference_jacobians(block_sizes.size());
- vector<double*> term_jacobian_pointers(block_sizes.size());
- vector<double*> finite_difference_jacobian_pointers(block_sizes.size());
- for (int i = 0; i < block_sizes.size(); i++) {
- term_jacobians[i].resize(num_residuals, block_sizes[i]);
- term_jacobian_pointers[i] = term_jacobians[i].data();
- finite_difference_jacobians[i].resize(num_residuals, block_sizes[i]);
- finite_difference_jacobian_pointers[i] =
- finite_difference_jacobians[i].data();
- }
-
- // Evaluate the derivative using the user supplied code.
- if (!function_->Evaluate(parameters,
- residuals,
- &term_jacobian_pointers[0])) {
- LOG(WARNING) << "Function evaluation failed.";
- return false;
- }
-
- // Evaluate the derivative using numeric derivatives.
- finite_diff_cost_function_->Evaluate(
- parameters,
- residuals,
- &finite_difference_jacobian_pointers[0]);
-
- // See if any elements have relative error larger than the threshold.
- int num_bad_jacobian_components = 0;
- double worst_relative_error = 0;
-
- // Accumulate the error message for all the jacobians, since it won't get
- // output if there are no bad jacobian components.
- string m;
- for (int k = 0; k < block_sizes.size(); k++) {
- // Copy the original jacobian blocks into the jacobians array.
- if (jacobians[k] != NULL) {
- MatrixRef(jacobians[k],
- term_jacobians[k].rows(),
- term_jacobians[k].cols()) = term_jacobians[k];
- }
-
- StringAppendF(&m,
- "========== "
- "Jacobian for " "block %d: (%ld by %ld)) "
- "==========\n",
- k,
- static_cast<long>(term_jacobians[k].rows()),
- static_cast<long>(term_jacobians[k].cols()));
- // The funny spacing creates appropriately aligned column headers.
- m += " block row col user dx/dy num diff dx/dy "
- "abs error relative error parameter residual\n";
-
- for (int i = 0; i < term_jacobians[k].rows(); i++) {
- for (int j = 0; j < term_jacobians[k].cols(); j++) {
- double term_jacobian = term_jacobians[k](i, j);
- double finite_jacobian = finite_difference_jacobians[k](i, j);
- double relative_error, absolute_error;
- bool bad_jacobian_entry =
- !IsClose(term_jacobian,
- finite_jacobian,
- relative_precision_,
- &relative_error,
- &absolute_error);
- worst_relative_error = std::max(worst_relative_error,
- relative_error);
-
- StringAppendF(&m, "%6d %4d %4d %17g %17g %17g %17g %17g %17g",
- k, i, j,
- term_jacobian, finite_jacobian,
- absolute_error, relative_error,
- parameters[k][j],
- residuals[i]);
-
- if (bad_jacobian_entry) {
- num_bad_jacobian_components++;
- StringAppendF(
- &m, " ------ (%d,%d,%d) Relative error worse than %g",
- k, i, j, relative_precision_);
- }
- m += "\n";
- }
- }
- }
-
- // Since there were some bad errors, dump comprehensive debug info.
- if (num_bad_jacobian_components) {
- string header = StringPrintf("Detected %d bad jacobian component(s). "
- "Worst relative error was %g.\n",
- num_bad_jacobian_components,
- worst_relative_error);
- if (!extra_info_.empty()) {
- header += "Extra info for this residual: " + extra_info_ + "\n";
- }
- LOG(WARNING) << "\n" << header << m;
- }
- return true;
- }
-
- private:
- const CostFunction* function_;
- internal::scoped_ptr<CostFunction> finite_diff_cost_function_;
- double relative_precision_;
- string extra_info_;
-};
-
-} // namespace
-
-CostFunction *CreateGradientCheckingCostFunction(
- const CostFunction *cost_function,
- double relative_step_size,
- double relative_precision,
- const string& extra_info) {
- return new GradientCheckingCostFunction(cost_function,
- relative_step_size,
- relative_precision,
- extra_info);
-}
-
-ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
- double relative_step_size,
- double relative_precision) {
- // We create new CostFunctions by wrapping the original CostFunction
- // in a gradient checking CostFunction. So its okay for the
- // ProblemImpl to take ownership of it and destroy it. The
- // LossFunctions and LocalParameterizations are reused and since
- // they are owned by problem_impl, gradient_checking_problem_impl
- // should not take ownership of it.
- Problem::Options gradient_checking_problem_options;
- gradient_checking_problem_options.cost_function_ownership = TAKE_OWNERSHIP;
- gradient_checking_problem_options.loss_function_ownership =
- DO_NOT_TAKE_OWNERSHIP;
- gradient_checking_problem_options.local_parameterization_ownership =
- DO_NOT_TAKE_OWNERSHIP;
-
- ProblemImpl* gradient_checking_problem_impl = new ProblemImpl(
- gradient_checking_problem_options);
-
- Program* program = problem_impl->mutable_program();
-
- // For every ParameterBlock in problem_impl, create a new parameter
- // block with the same local parameterization and constancy.
- const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- ParameterBlock* parameter_block = parameter_blocks[i];
- gradient_checking_problem_impl->AddParameterBlock(
- parameter_block->mutable_user_state(),
- parameter_block->Size(),
- parameter_block->mutable_local_parameterization());
-
- if (parameter_block->IsConstant()) {
- gradient_checking_problem_impl->SetParameterBlockConstant(
- parameter_block->mutable_user_state());
- }
- }
-
- // For every ResidualBlock in problem_impl, create a new
- // ResidualBlock by wrapping its CostFunction inside a
- // GradientCheckingCostFunction.
- const vector<ResidualBlock*>& residual_blocks = program->residual_blocks();
- for (int i = 0; i < residual_blocks.size(); ++i) {
- ResidualBlock* residual_block = residual_blocks[i];
-
- // Build a human readable string which identifies the
- // ResidualBlock. This is used by the GradientCheckingCostFunction
- // when logging debugging information.
- string extra_info = StringPrintf(
- "Residual block id %d; depends on parameters [", i);
- vector<double*> parameter_blocks;
- for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
- parameter_blocks.push_back(parameter_block->mutable_user_state());
- StringAppendF(&extra_info, "%p", parameter_block->mutable_user_state());
- extra_info += (j < residual_block->NumParameterBlocks() - 1) ? ", " : "]";
- }
-
- // Wrap the original CostFunction in a GradientCheckingCostFunction.
- CostFunction* gradient_checking_cost_function =
- CreateGradientCheckingCostFunction(residual_block->cost_function(),
- relative_step_size,
- relative_precision,
- extra_info);
-
- // The const_cast is necessary because
- // ProblemImpl::AddResidualBlock can potentially take ownership of
- // the LossFunction, but in this case we are guaranteed that this
- // will not be the case, so this const_cast is harmless.
- gradient_checking_problem_impl->AddResidualBlock(
- gradient_checking_cost_function,
- const_cast<LossFunction*>(residual_block->loss_function()),
- parameter_blocks);
- }
-
- // Normally, when a problem is given to the solver, we guarantee
- // that the state pointers for each parameter block point to the
- // user provided data. Since we are creating this new problem from a
- // problem given to us at an arbitrary stage of the solve, we cannot
- // depend on this being the case, so we explicitly call
- // SetParameterBlockStatePtrsToUserStatePtrs to ensure that this is
- // the case.
- gradient_checking_problem_impl
- ->mutable_program()
- ->SetParameterBlockStatePtrsToUserStatePtrs();
-
- return gradient_checking_problem_impl;
-}
-
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.h b/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.h
deleted file mode 100644
index d49c8e6c244..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
-#define CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
-
-#include <string>
-
-#include "ceres/cost_function.h"
-
-namespace ceres {
-namespace internal {
-
-class ProblemImpl;
-
-// Creates a CostFunction that checks the jacobians that cost_function computes
-// with finite differences. Bad results are logged; required precision is
-// controlled by relative_precision and the numeric differentiation step size is
-// controlled with relative_step_size. See solver.h for a better explanation of
-// relative_step_size. Caller owns result.
-//
-// The condition enforced is that
-//
-// (J_actual(i, j) - J_numeric(i, j))
-// ------------------------------------ < relative_precision
-// max(J_actual(i, j), J_numeric(i, j))
-//
-// where J_actual(i, j) is the jacobian as computed by the supplied cost
-// function (by the user) and J_numeric is the jacobian as computed by finite
-// differences.
-//
-// Note: This is quite inefficient and is intended only for debugging.
-CostFunction* CreateGradientCheckingCostFunction(
- const CostFunction* cost_function,
- double relative_step_size,
- double relative_precision,
- const string& extra_info);
-
-// Create a new ProblemImpl object from the input problem_impl, where
-// each CostFunctions in problem_impl are wrapped inside a
-// GradientCheckingCostFunctions. This gives us a ProblemImpl object
-// which checks its derivatives against estimates from numeric
-// differentiation everytime a ResidualBlock is evaluated.
-//
-// relative_step_size and relative_precision are parameters to control
-// the numeric differentiation and the relative tolerance between the
-// jacobian computed by the CostFunctions in problem_impl and
-// jacobians obtained by numerically differentiating them. For more
-// details see the documentation for
-// CreateGradientCheckingCostFunction above.
-ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl,
- double relative_step_size,
- double relative_precision);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc
deleted file mode 100644
index 8f9a842bd89..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/gradient_problem.h"
-#include "ceres/local_parameterization.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-GradientProblem::GradientProblem(FirstOrderFunction* function)
- : function_(function),
- parameterization_(
- new IdentityParameterization(function_->NumParameters())),
- scratch_(new double[function_->NumParameters()]) {
-}
-
-GradientProblem::GradientProblem(FirstOrderFunction* function,
- LocalParameterization* parameterization)
- : function_(function),
- parameterization_(parameterization),
- scratch_(new double[function_->NumParameters()]) {
- CHECK_EQ(function_->NumParameters(), parameterization_->GlobalSize());
-}
-
-int GradientProblem::NumParameters() const {
- return function_->NumParameters();
-}
-
-int GradientProblem::NumLocalParameters() const {
- return parameterization_->LocalSize();
-}
-
-
-bool GradientProblem::Evaluate(const double* parameters,
- double* cost,
- double* gradient) const {
- if (gradient == NULL) {
- return function_->Evaluate(parameters, cost, NULL);
- }
-
- return (function_->Evaluate(parameters, cost, scratch_.get()) &&
- parameterization_->MultiplyByJacobian(parameters,
- 1,
- scratch_.get(),
- gradient));
-}
-
-bool GradientProblem::Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const {
- return parameterization_->Plus(x, delta, x_plus_delta);
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h
deleted file mode 100644
index 20053de2af6..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_evaluator.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
-#define CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
-
-#include <map>
-#include <string>
-
-#include "ceres/evaluator.h"
-#include "ceres/execution_summary.h"
-#include "ceres/gradient_problem.h"
-#include "ceres/internal/port.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-namespace internal {
-
-class GradientProblemEvaluator : public Evaluator {
- public:
- explicit GradientProblemEvaluator(const GradientProblem& problem)
- : problem_(problem) {}
- virtual ~GradientProblemEvaluator() {}
- virtual SparseMatrix* CreateJacobian() const { return NULL; }
- virtual bool Evaluate(const EvaluateOptions& evaluate_options,
- const double* state,
- double* cost,
- double* residuals,
- double* gradient,
- SparseMatrix* jacobian) {
- CHECK(jacobian == NULL);
- ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
- ScopedExecutionTimer call_type_timer(
- gradient == NULL ? "Evaluator::Cost" : "Evaluator::Gradient",
- &execution_summary_);
- return problem_.Evaluate(state, cost, gradient);
- }
-
- virtual bool Plus(const double* state,
- const double* delta,
- double* state_plus_delta) const {
- return problem_.Plus(state, delta, state_plus_delta);
- }
-
- virtual int NumParameters() const {
- return problem_.NumParameters();
- }
-
- virtual int NumEffectiveParameters() const {
- return problem_.NumLocalParameters();
- }
-
- virtual int NumResiduals() const { return 1; }
-
- virtual map<string, int> CallStatistics() const {
- return execution_summary_.calls();
- }
-
- virtual map<string, double> TimeStatistics() const {
- return execution_summary_.times();
- }
-
- private:
- const GradientProblem& problem_;
- ::ceres::internal::ExecutionSummary execution_summary_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc
deleted file mode 100644
index 4024f4cc4e6..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/gradient_problem_solver.cc
+++ /dev/null
@@ -1,270 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/gradient_problem_solver.h"
-
-#include "ceres/callbacks.h"
-#include "ceres/gradient_problem.h"
-#include "ceres/gradient_problem_evaluator.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/map_util.h"
-#include "ceres/minimizer.h"
-#include "ceres/solver.h"
-#include "ceres/solver_utils.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-using internal::StringPrintf;
-using internal::StringAppendF;
-
-namespace {
-
-Solver::Options GradientProblemSolverOptionsToSolverOptions(
- const GradientProblemSolver::Options& options) {
-#define COPY_OPTION(x) solver_options.x = options.x
-
- Solver::Options solver_options;
- solver_options.minimizer_type = LINE_SEARCH;
- COPY_OPTION(line_search_direction_type);
- COPY_OPTION(line_search_type);
- COPY_OPTION(nonlinear_conjugate_gradient_type);
- COPY_OPTION(max_lbfgs_rank);
- COPY_OPTION(use_approximate_eigenvalue_bfgs_scaling);
- COPY_OPTION(line_search_interpolation_type);
- COPY_OPTION(min_line_search_step_size);
- COPY_OPTION(line_search_sufficient_function_decrease);
- COPY_OPTION(max_line_search_step_contraction);
- COPY_OPTION(min_line_search_step_contraction);
- COPY_OPTION(max_num_line_search_step_size_iterations);
- COPY_OPTION(max_num_line_search_direction_restarts);
- COPY_OPTION(line_search_sufficient_curvature_decrease);
- COPY_OPTION(max_line_search_step_expansion);
- COPY_OPTION(max_num_iterations);
- COPY_OPTION(max_solver_time_in_seconds);
- COPY_OPTION(function_tolerance);
- COPY_OPTION(gradient_tolerance);
- COPY_OPTION(logging_type);
- COPY_OPTION(minimizer_progress_to_stdout);
- COPY_OPTION(callbacks);
- return solver_options;
-#undef COPY_OPTION
-}
-
-
-} // namespace
-
-GradientProblemSolver::~GradientProblemSolver() {
-}
-
-void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
- const GradientProblem& problem,
- double* parameters_ptr,
- GradientProblemSolver::Summary* summary) {
- using internal::scoped_ptr;
- using internal::WallTimeInSeconds;
- using internal::Minimizer;
- using internal::GradientProblemEvaluator;
- using internal::LoggingCallback;
- using internal::SetSummaryFinalCost;
-
- double start_time = WallTimeInSeconds();
- Solver::Options solver_options =
- GradientProblemSolverOptionsToSolverOptions(options);
-
- *CHECK_NOTNULL(summary) = Summary();
- summary->num_parameters = problem.NumParameters();
- summary->num_local_parameters = problem.NumLocalParameters();
- summary->line_search_direction_type = options.line_search_direction_type; // NOLINT
- summary->line_search_interpolation_type = options.line_search_interpolation_type; // NOLINT
- summary->line_search_type = options.line_search_type;
- summary->max_lbfgs_rank = options.max_lbfgs_rank;
- summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT
-
- // Check validity
- if (!solver_options.IsValid(&summary->message)) {
- LOG(ERROR) << "Terminating: " << summary->message;
- return;
- }
-
- // Assuming that the parameter blocks in the program have been
- Minimizer::Options minimizer_options;
- minimizer_options = Minimizer::Options(solver_options);
- minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem));
-
- scoped_ptr<IterationCallback> logging_callback;
- if (options.logging_type != SILENT) {
- logging_callback.reset(
- new LoggingCallback(LINE_SEARCH, options.minimizer_progress_to_stdout));
- minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
- logging_callback.get());
- }
-
- scoped_ptr<Minimizer> minimizer(Minimizer::Create(LINE_SEARCH));
- Vector solution(problem.NumParameters());
- VectorRef parameters(parameters_ptr, problem.NumParameters());
- solution = parameters;
-
- Solver::Summary solver_summary;
- solver_summary.fixed_cost = 0.0;
- solver_summary.preprocessor_time_in_seconds = 0.0;
- solver_summary.postprocessor_time_in_seconds = 0.0;
-
- minimizer->Minimize(minimizer_options, solution.data(), &solver_summary);
-
- summary->termination_type = solver_summary.termination_type;
- summary->message = solver_summary.message;
- summary->initial_cost = solver_summary.initial_cost;
- summary->final_cost = solver_summary.final_cost;
- summary->iterations = solver_summary.iterations;
-
- if (summary->IsSolutionUsable()) {
- parameters = solution;
- SetSummaryFinalCost(summary);
- }
-
- const map<string, double>& evaluator_time_statistics =
- minimizer_options.evaluator->TimeStatistics();
- summary->cost_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
- summary->gradient_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
-
- summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
-}
-
-// Invalid values for most fields, to ensure that we are not
-// accidentally reporting default values.
-GradientProblemSolver::Summary::Summary()
- : termination_type(FAILURE),
- message("ceres::GradientProblemSolve was not called."),
- initial_cost(-1.0),
- final_cost(-1.0),
- total_time_in_seconds(-1.0),
- cost_evaluation_time_in_seconds(-1.0),
- gradient_evaluation_time_in_seconds(-1.0),
- num_parameters(-1),
- num_local_parameters(-1),
- line_search_direction_type(LBFGS),
- line_search_type(ARMIJO),
- line_search_interpolation_type(BISECTION),
- nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
- max_lbfgs_rank(-1) {
-}
-
-bool GradientProblemSolver::Summary::IsSolutionUsable() const {
- return internal::IsSolutionUsable(*this);
-}
-
-string GradientProblemSolver::Summary::BriefReport() const {
- return StringPrintf("Ceres GradientProblemSolver Report: "
- "Iterations: %d, "
- "Initial cost: %e, "
- "Final cost: %e, "
- "Termination: %s",
- static_cast<int>(iterations.size()),
- initial_cost,
- final_cost,
- TerminationTypeToString(termination_type));
-};
-
-string GradientProblemSolver::Summary::FullReport() const {
- using internal::VersionString;
-
- string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
-
- StringAppendF(&report, "Parameters % 25d\n", num_parameters);
- if (num_local_parameters != num_parameters) {
- StringAppendF(&report, "Local parameters % 25d\n",
- num_local_parameters);
- }
-
- string line_search_direction_string;
- if (line_search_direction_type == LBFGS) {
- line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
- } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
- line_search_direction_string =
- NonlinearConjugateGradientTypeToString(
- nonlinear_conjugate_gradient_type);
- } else {
- line_search_direction_string =
- LineSearchDirectionTypeToString(line_search_direction_type);
- }
-
- StringAppendF(&report, "Line search direction %19s\n",
- line_search_direction_string.c_str());
-
- const string line_search_type_string =
- StringPrintf("%s %s",
- LineSearchInterpolationTypeToString(
- line_search_interpolation_type),
- LineSearchTypeToString(line_search_type));
- StringAppendF(&report, "Line search type %19s\n",
- line_search_type_string.c_str());
- StringAppendF(&report, "\n");
-
- StringAppendF(&report, "\nCost:\n");
- StringAppendF(&report, "Initial % 30e\n", initial_cost);
- if (termination_type != FAILURE &&
- termination_type != USER_FAILURE) {
- StringAppendF(&report, "Final % 30e\n", final_cost);
- StringAppendF(&report, "Change % 30e\n",
- initial_cost - final_cost);
- }
-
- StringAppendF(&report, "\nMinimizer iterations % 16d\n",
- static_cast<int>(iterations.size()));
-
- StringAppendF(&report, "\nTime (in seconds):\n");
-
- StringAppendF(&report, "\n Cost evaluation %23.3f\n",
- cost_evaluation_time_in_seconds);
- StringAppendF(&report, " Gradient evaluation %23.3f\n",
- gradient_evaluation_time_in_seconds);
-
- StringAppendF(&report, "Total %25.3f\n\n",
- total_time_in_seconds);
-
- StringAppendF(&report, "Termination: %25s (%s)\n",
- TerminationTypeToString(termination_type), message.c_str());
- return report;
-};
-
-void Solve(const GradientProblemSolver::Options& options,
- const GradientProblem& problem,
- double* parameters,
- GradientProblemSolver::Summary* summary) {
- GradientProblemSolver solver;
- solver.Solve(options, problem, parameters, summary);
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph.h b/extern/libmv/third_party/ceres/internal/ceres/graph.h
deleted file mode 100644
index f639d15323d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/graph.h
+++ /dev/null
@@ -1,223 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_GRAPH_H_
-#define CERES_INTERNAL_GRAPH_H_
-
-#include <limits>
-#include <utility>
-#include "ceres/integral_types.h"
-#include "ceres/map_util.h"
-#include "ceres/collections_port.h"
-#include "ceres/internal/macros.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// A unweighted undirected graph templated over the vertex ids. Vertex
-// should be hashable.
-template <typename Vertex>
-class Graph {
- public:
- Graph() {}
-
- // Add a vertex.
- void AddVertex(const Vertex& vertex) {
- if (vertices_.insert(vertex).second) {
- edges_[vertex] = HashSet<Vertex>();
- }
- }
-
- bool RemoveVertex(const Vertex& vertex) {
- if (vertices_.find(vertex) == vertices_.end()) {
- return false;
- }
-
- vertices_.erase(vertex);
- const HashSet<Vertex>& sinks = edges_[vertex];
- for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
- it != sinks.end(); ++it) {
- edges_[*it].erase(vertex);
- }
-
- edges_.erase(vertex);
- return true;
- }
-
- // Add an edge between the vertex1 and vertex2. Calling AddEdge on a
- // pair of vertices which do not exist in the graph yet will result
- // in undefined behavior.
- //
- // It is legal to call this method repeatedly for the same set of
- // vertices.
- void AddEdge(const Vertex& vertex1, const Vertex& vertex2) {
- DCHECK(vertices_.find(vertex1) != vertices_.end());
- DCHECK(vertices_.find(vertex2) != vertices_.end());
-
- if (edges_[vertex1].insert(vertex2).second) {
- edges_[vertex2].insert(vertex1);
- }
- }
-
- // Calling Neighbors on a vertex not in the graph will result in
- // undefined behaviour.
- const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
- return FindOrDie(edges_, vertex);
- }
-
- const HashSet<Vertex>& vertices() const {
- return vertices_;
- }
-
- private:
- HashSet<Vertex> vertices_;
- HashMap<Vertex, HashSet<Vertex> > edges_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(Graph);
-};
-
-// A weighted undirected graph templated over the vertex ids. Vertex
-// should be hashable and comparable.
-template <typename Vertex>
-class WeightedGraph {
- public:
- WeightedGraph() {}
-
- // Add a weighted vertex. If the vertex already exists in the graph,
- // its weight is set to the new weight.
- void AddVertex(const Vertex& vertex, double weight) {
- if (vertices_.find(vertex) == vertices_.end()) {
- vertices_.insert(vertex);
- edges_[vertex] = HashSet<Vertex>();
- }
- vertex_weights_[vertex] = weight;
- }
-
- // Uses weight = 1.0. If vertex already exists, its weight is set to
- // 1.0.
- void AddVertex(const Vertex& vertex) {
- AddVertex(vertex, 1.0);
- }
-
- bool RemoveVertex(const Vertex& vertex) {
- if (vertices_.find(vertex) == vertices_.end()) {
- return false;
- }
-
- vertices_.erase(vertex);
- vertex_weights_.erase(vertex);
- const HashSet<Vertex>& sinks = edges_[vertex];
- for (typename HashSet<Vertex>::const_iterator it = sinks.begin();
- it != sinks.end(); ++it) {
- if (vertex < *it) {
- edge_weights_.erase(make_pair(vertex, *it));
- } else {
- edge_weights_.erase(make_pair(*it, vertex));
- }
- edges_[*it].erase(vertex);
- }
-
- edges_.erase(vertex);
- return true;
- }
-
- // Add a weighted edge between the vertex1 and vertex2. Calling
- // AddEdge on a pair of vertices which do not exist in the graph yet
- // will result in undefined behavior.
- //
- // It is legal to call this method repeatedly for the same set of
- // vertices.
- void AddEdge(const Vertex& vertex1, const Vertex& vertex2, double weight) {
- DCHECK(vertices_.find(vertex1) != vertices_.end());
- DCHECK(vertices_.find(vertex2) != vertices_.end());
-
- if (edges_[vertex1].insert(vertex2).second) {
- edges_[vertex2].insert(vertex1);
- }
-
- if (vertex1 < vertex2) {
- edge_weights_[make_pair(vertex1, vertex2)] = weight;
- } else {
- edge_weights_[make_pair(vertex2, vertex1)] = weight;
- }
- }
-
- // Uses weight = 1.0.
- void AddEdge(const Vertex& vertex1, const Vertex& vertex2) {
- AddEdge(vertex1, vertex2, 1.0);
- }
-
- // Calling VertexWeight on a vertex not in the graph will result in
- // undefined behavior.
- double VertexWeight(const Vertex& vertex) const {
- return FindOrDie(vertex_weights_, vertex);
- }
-
- // Calling EdgeWeight on a pair of vertices where either one of the
- // vertices is not present in the graph will result in undefined
- // behaviour. If there is no edge connecting vertex1 and vertex2,
- // the edge weight is zero.
- double EdgeWeight(const Vertex& vertex1, const Vertex& vertex2) const {
- if (vertex1 < vertex2) {
- return FindWithDefault(edge_weights_, make_pair(vertex1, vertex2), 0.0);
- } else {
- return FindWithDefault(edge_weights_, make_pair(vertex2, vertex1), 0.0);
- }
- }
-
- // Calling Neighbors on a vertex not in the graph will result in
- // undefined behaviour.
- const HashSet<Vertex>& Neighbors(const Vertex& vertex) const {
- return FindOrDie(edges_, vertex);
- }
-
- const HashSet<Vertex>& vertices() const {
- return vertices_;
- }
-
- static double InvalidWeight() {
- return std::numeric_limits<double>::quiet_NaN();
- };
-
- private:
- HashSet<Vertex> vertices_;
- HashMap<Vertex, double> vertex_weights_;
- HashMap<Vertex, HashSet<Vertex> > edges_;
- HashMap<pair<Vertex, Vertex>, double> edge_weights_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(WeightedGraph);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_GRAPH_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
deleted file mode 100644
index fb75e2f45f2..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
+++ /dev/null
@@ -1,363 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Various algorithms that operate on undirected graphs.
-
-#ifndef CERES_INTERNAL_GRAPH_ALGORITHMS_H_
-#define CERES_INTERNAL_GRAPH_ALGORITHMS_H_
-
-#include <algorithm>
-#include <vector>
-#include <utility>
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// Compare two vertices of a graph by their degrees, if the degrees
-// are equal then order them by their ids.
-template <typename Vertex>
-class VertexTotalOrdering {
- public:
- explicit VertexTotalOrdering(const Graph<Vertex>& graph)
- : graph_(graph) {}
-
- bool operator()(const Vertex& lhs, const Vertex& rhs) const {
- if (graph_.Neighbors(lhs).size() == graph_.Neighbors(rhs).size()) {
- return lhs < rhs;
- }
- return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size();
- }
-
- private:
- const Graph<Vertex>& graph_;
-};
-
-template <typename Vertex>
-class VertexDegreeLessThan {
- public:
- explicit VertexDegreeLessThan(const Graph<Vertex>& graph)
- : graph_(graph) {}
-
- bool operator()(const Vertex& lhs, const Vertex& rhs) const {
- return graph_.Neighbors(lhs).size() < graph_.Neighbors(rhs).size();
- }
-
- private:
- const Graph<Vertex>& graph_;
-};
-
-// Order the vertices of a graph using its (approximately) largest
-// independent set, where an independent set of a graph is a set of
-// vertices that have no edges connecting them. The maximum
-// independent set problem is NP-Hard, but there are effective
-// approximation algorithms available. The implementation here uses a
-// breadth first search that explores the vertices in order of
-// increasing degree. The same idea is used by Saad & Li in "MIQR: A
-// multilevel incomplete QR preconditioner for large sparse
-// least-squares problems", SIMAX, 2007.
-//
-// Given a undirected graph G(V,E), the algorithm is a greedy BFS
-// search where the vertices are explored in increasing order of their
-// degree. The output vector ordering contains elements of S in
-// increasing order of their degree, followed by elements of V - S in
-// increasing order of degree. The return value of the function is the
-// cardinality of S.
-template <typename Vertex>
-int IndependentSetOrdering(const Graph<Vertex>& graph,
- vector<Vertex>* ordering) {
- const HashSet<Vertex>& vertices = graph.vertices();
- const int num_vertices = vertices.size();
-
- CHECK_NOTNULL(ordering);
- ordering->clear();
- ordering->reserve(num_vertices);
-
- // Colors for labeling the graph during the BFS.
- const char kWhite = 0;
- const char kGrey = 1;
- const char kBlack = 2;
-
- // Mark all vertices white.
- HashMap<Vertex, char> vertex_color;
- vector<Vertex> vertex_queue;
- for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- vertex_color[*it] = kWhite;
- vertex_queue.push_back(*it);
- }
-
-
- sort(vertex_queue.begin(), vertex_queue.end(),
- VertexTotalOrdering<Vertex>(graph));
-
- // Iterate over vertex_queue. Pick the first white vertex, add it
- // to the independent set. Mark it black and its neighbors grey.
- for (int i = 0; i < vertex_queue.size(); ++i) {
- const Vertex& vertex = vertex_queue[i];
- if (vertex_color[vertex] != kWhite) {
- continue;
- }
-
- ordering->push_back(vertex);
- vertex_color[vertex] = kBlack;
- const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
- for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
- it != neighbors.end();
- ++it) {
- vertex_color[*it] = kGrey;
- }
- }
-
- int independent_set_size = ordering->size();
-
- // Iterate over the vertices and add all the grey vertices to the
- // ordering. At this stage there should only be black or grey
- // vertices in the graph.
- for (typename vector<Vertex>::const_iterator it = vertex_queue.begin();
- it != vertex_queue.end();
- ++it) {
- const Vertex vertex = *it;
- DCHECK(vertex_color[vertex] != kWhite);
- if (vertex_color[vertex] != kBlack) {
- ordering->push_back(vertex);
- }
- }
-
- CHECK_EQ(ordering->size(), num_vertices);
- return independent_set_size;
-}
-
-// Same as above with one important difference. The ordering parameter
-// is an input/output parameter which carries an initial ordering of
-// the vertices of the graph. The greedy independent set algorithm
-// starts by sorting the vertices in increasing order of their
-// degree. The input ordering is used to stabilize this sort, i.e., if
-// two vertices have the same degree then they are ordered in the same
-// order in which they occur in "ordering".
-//
-// This is useful in eliminating non-determinism from the Schur
-// ordering algorithm over all.
-template <typename Vertex>
-int StableIndependentSetOrdering(const Graph<Vertex>& graph,
- vector<Vertex>* ordering) {
- CHECK_NOTNULL(ordering);
- const HashSet<Vertex>& vertices = graph.vertices();
- const int num_vertices = vertices.size();
- CHECK_EQ(vertices.size(), ordering->size());
-
- // Colors for labeling the graph during the BFS.
- const char kWhite = 0;
- const char kGrey = 1;
- const char kBlack = 2;
-
- vector<Vertex> vertex_queue(*ordering);
-
- stable_sort(vertex_queue.begin(), vertex_queue.end(),
- VertexDegreeLessThan<Vertex>(graph));
-
- // Mark all vertices white.
- HashMap<Vertex, char> vertex_color;
- for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- vertex_color[*it] = kWhite;
- }
-
- ordering->clear();
- ordering->reserve(num_vertices);
- // Iterate over vertex_queue. Pick the first white vertex, add it
- // to the independent set. Mark it black and its neighbors grey.
- for (int i = 0; i < vertex_queue.size(); ++i) {
- const Vertex& vertex = vertex_queue[i];
- if (vertex_color[vertex] != kWhite) {
- continue;
- }
-
- ordering->push_back(vertex);
- vertex_color[vertex] = kBlack;
- const HashSet<Vertex>& neighbors = graph.Neighbors(vertex);
- for (typename HashSet<Vertex>::const_iterator it = neighbors.begin();
- it != neighbors.end();
- ++it) {
- vertex_color[*it] = kGrey;
- }
- }
-
- int independent_set_size = ordering->size();
-
- // Iterate over the vertices and add all the grey vertices to the
- // ordering. At this stage there should only be black or grey
- // vertices in the graph.
- for (typename vector<Vertex>::const_iterator it = vertex_queue.begin();
- it != vertex_queue.end();
- ++it) {
- const Vertex vertex = *it;
- DCHECK(vertex_color[vertex] != kWhite);
- if (vertex_color[vertex] != kBlack) {
- ordering->push_back(vertex);
- }
- }
-
- CHECK_EQ(ordering->size(), num_vertices);
- return independent_set_size;
-}
-
-// Find the connected component for a vertex implemented using the
-// find and update operation for disjoint-set. Recursively traverse
-// the disjoint set structure till you reach a vertex whose connected
-// component has the same id as the vertex itself. Along the way
-// update the connected components of all the vertices. This updating
-// is what gives this data structure its efficiency.
-template <typename Vertex>
-Vertex FindConnectedComponent(const Vertex& vertex,
- HashMap<Vertex, Vertex>* union_find) {
- typename HashMap<Vertex, Vertex>::iterator it = union_find->find(vertex);
- DCHECK(it != union_find->end());
- if (it->second != vertex) {
- it->second = FindConnectedComponent(it->second, union_find);
- }
-
- return it->second;
-}
-
-// Compute a degree two constrained Maximum Spanning Tree/forest of
-// the input graph. Caller owns the result.
-//
-// Finding degree 2 spanning tree of a graph is not always
-// possible. For example a star graph, i.e. a graph with n-nodes
-// where one node is connected to the other n-1 nodes does not have
-// a any spanning trees of degree less than n-1.Even if such a tree
-// exists, finding such a tree is NP-Hard.
-
-// We get around both of these problems by using a greedy, degree
-// constrained variant of Kruskal's algorithm. We start with a graph
-// G_T with the same vertex set V as the input graph G(V,E) but an
-// empty edge set. We then iterate over the edges of G in decreasing
-// order of weight, adding them to G_T if doing so does not create a
-// cycle in G_T} and the degree of all the vertices in G_T remains
-// bounded by two. This O(|E|) algorithm results in a degree-2
-// spanning forest, or a collection of linear paths that span the
-// graph G.
-template <typename Vertex>
-WeightedGraph<Vertex>*
-Degree2MaximumSpanningForest(const WeightedGraph<Vertex>& graph) {
- // Array of edges sorted in decreasing order of their weights.
- vector<pair<double, pair<Vertex, Vertex> > > weighted_edges;
- WeightedGraph<Vertex>* forest = new WeightedGraph<Vertex>();
-
- // Disjoint-set to keep track of the connected components in the
- // maximum spanning tree.
- HashMap<Vertex, Vertex> disjoint_set;
-
- // Sort of the edges in the graph in decreasing order of their
- // weight. Also add the vertices of the graph to the Maximum
- // Spanning Tree graph and set each vertex to be its own connected
- // component in the disjoint_set structure.
- const HashSet<Vertex>& vertices = graph.vertices();
- for (typename HashSet<Vertex>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- const Vertex vertex1 = *it;
- forest->AddVertex(vertex1, graph.VertexWeight(vertex1));
- disjoint_set[vertex1] = vertex1;
-
- const HashSet<Vertex>& neighbors = graph.Neighbors(vertex1);
- for (typename HashSet<Vertex>::const_iterator it2 = neighbors.begin();
- it2 != neighbors.end();
- ++it2) {
- const Vertex vertex2 = *it2;
- if (vertex1 >= vertex2) {
- continue;
- }
- const double weight = graph.EdgeWeight(vertex1, vertex2);
- weighted_edges.push_back(make_pair(weight, make_pair(vertex1, vertex2)));
- }
- }
-
- // The elements of this vector, are pairs<edge_weight,
- // edge>. Sorting it using the reverse iterators gives us the edges
- // in decreasing order of edges.
- sort(weighted_edges.rbegin(), weighted_edges.rend());
-
- // Greedily add edges to the spanning tree/forest as long as they do
- // not violate the degree/cycle constraint.
- for (int i =0; i < weighted_edges.size(); ++i) {
- const pair<Vertex, Vertex>& edge = weighted_edges[i].second;
- const Vertex vertex1 = edge.first;
- const Vertex vertex2 = edge.second;
-
- // Check if either of the vertices are of degree 2 already, in
- // which case adding this edge will violate the degree 2
- // constraint.
- if ((forest->Neighbors(vertex1).size() == 2) ||
- (forest->Neighbors(vertex2).size() == 2)) {
- continue;
- }
-
- // Find the id of the connected component to which the two
- // vertices belong to. If the id is the same, it means that the
- // two of them are already connected to each other via some other
- // vertex, and adding this edge will create a cycle.
- Vertex root1 = FindConnectedComponent(vertex1, &disjoint_set);
- Vertex root2 = FindConnectedComponent(vertex2, &disjoint_set);
-
- if (root1 == root2) {
- continue;
- }
-
- // This edge can be added, add an edge in either direction with
- // the same weight as the original graph.
- const double edge_weight = graph.EdgeWeight(vertex1, vertex2);
- forest->AddEdge(vertex1, vertex2, edge_weight);
- forest->AddEdge(vertex2, vertex1, edge_weight);
-
- // Connected the two connected components by updating the
- // disjoint_set structure. Always connect the connected component
- // with the greater index with the connected component with the
- // smaller index. This should ensure shallower trees, for quicker
- // lookup.
- if (root2 < root1) {
- std::swap(root1, root2);
- };
-
- disjoint_set[root2] = root1;
- }
- return forest;
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_GRAPH_ALGORITHMS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc b/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc
deleted file mode 100644
index 2da6235f513..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/implicit_schur_complement.h"
-
-#include "Eigen/Dense"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-ImplicitSchurComplement::ImplicitSchurComplement(
- const LinearSolver::Options& options)
- : options_(options),
- D_(NULL),
- b_(NULL) {
-}
-
-ImplicitSchurComplement::~ImplicitSchurComplement() {
-}
-
-void ImplicitSchurComplement::Init(const BlockSparseMatrix& A,
- const double* D,
- const double* b) {
- // Since initialization is reasonably heavy, perhaps we can save on
- // constructing a new object everytime.
- if (A_ == NULL) {
- A_.reset(PartitionedMatrixViewBase::Create(options_, A));
- }
-
- D_ = D;
- b_ = b;
-
- // Initialize temporary storage and compute the block diagonals of
- // E'E and F'E.
- if (block_diagonal_EtE_inverse_ == NULL) {
- block_diagonal_EtE_inverse_.reset(A_->CreateBlockDiagonalEtE());
- if (options_.preconditioner_type == JACOBI) {
- block_diagonal_FtF_inverse_.reset(A_->CreateBlockDiagonalFtF());
- }
- rhs_.resize(A_->num_cols_f());
- rhs_.setZero();
- tmp_rows_.resize(A_->num_rows());
- tmp_e_cols_.resize(A_->num_cols_e());
- tmp_e_cols_2_.resize(A_->num_cols_e());
- tmp_f_cols_.resize(A_->num_cols_f());
- } else {
- A_->UpdateBlockDiagonalEtE(block_diagonal_EtE_inverse_.get());
- if (options_.preconditioner_type == JACOBI) {
- A_->UpdateBlockDiagonalFtF(block_diagonal_FtF_inverse_.get());
- }
- }
-
- // The block diagonals of the augmented linear system contain
- // contributions from the diagonal D if it is non-null. Add that to
- // the block diagonals and invert them.
- AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get());
- if (options_.preconditioner_type == JACOBI) {
- AddDiagonalAndInvert((D_ == NULL) ? NULL : D_ + A_->num_cols_e(),
- block_diagonal_FtF_inverse_.get());
- }
-
- // Compute the RHS of the Schur complement system.
- UpdateRhs();
-}
-
-// Evaluate the product
-//
-// Sx = [F'F - F'E (E'E)^-1 E'F]x
-//
-// By breaking it down into individual matrix vector products
-// involving the matrices E and F. This is implemented using a
-// PartitionedMatrixView of the input matrix A.
-void ImplicitSchurComplement::RightMultiply(const double* x, double* y) const {
- // y1 = F x
- tmp_rows_.setZero();
- A_->RightMultiplyF(x, tmp_rows_.data());
-
- // y2 = E' y1
- tmp_e_cols_.setZero();
- A_->LeftMultiplyE(tmp_rows_.data(), tmp_e_cols_.data());
-
- // y3 = -(E'E)^-1 y2
- tmp_e_cols_2_.setZero();
- block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(),
- tmp_e_cols_2_.data());
- tmp_e_cols_2_ *= -1.0;
-
- // y1 = y1 + E y3
- A_->RightMultiplyE(tmp_e_cols_2_.data(), tmp_rows_.data());
-
- // y5 = D * x
- if (D_ != NULL) {
- ConstVectorRef Dref(D_ + A_->num_cols_e(), num_cols());
- VectorRef(y, num_cols()) =
- (Dref.array().square() *
- ConstVectorRef(x, num_cols()).array()).matrix();
- } else {
- VectorRef(y, num_cols()).setZero();
- }
-
- // y = y5 + F' y1
- A_->LeftMultiplyF(tmp_rows_.data(), y);
-}
-
-// Given a block diagonal matrix and an optional array of diagonal
-// entries D, add them to the diagonal of the matrix and compute the
-// inverse of each diagonal block.
-void ImplicitSchurComplement::AddDiagonalAndInvert(
- const double* D,
- BlockSparseMatrix* block_diagonal) {
- const CompressedRowBlockStructure* block_diagonal_structure =
- block_diagonal->block_structure();
- for (int r = 0; r < block_diagonal_structure->rows.size(); ++r) {
- const int row_block_pos = block_diagonal_structure->rows[r].block.position;
- const int row_block_size = block_diagonal_structure->rows[r].block.size;
- const Cell& cell = block_diagonal_structure->rows[r].cells[0];
- MatrixRef m(block_diagonal->mutable_values() + cell.position,
- row_block_size, row_block_size);
-
- if (D != NULL) {
- ConstVectorRef d(D + row_block_pos, row_block_size);
- m += d.array().square().matrix().asDiagonal();
- }
-
- m = m
- .selfadjointView<Eigen::Upper>()
- .llt()
- .solve(Matrix::Identity(row_block_size, row_block_size));
- }
-}
-
-// Similar to RightMultiply, use the block structure of the matrix A
-// to compute y = (E'E)^-1 (E'b - E'F x).
-void ImplicitSchurComplement::BackSubstitute(const double* x, double* y) {
- const int num_cols_e = A_->num_cols_e();
- const int num_cols_f = A_->num_cols_f();
- const int num_cols = A_->num_cols();
- const int num_rows = A_->num_rows();
-
- // y1 = F x
- tmp_rows_.setZero();
- A_->RightMultiplyF(x, tmp_rows_.data());
-
- // y2 = b - y1
- tmp_rows_ = ConstVectorRef(b_, num_rows) - tmp_rows_;
-
- // y3 = E' y2
- tmp_e_cols_.setZero();
- A_->LeftMultiplyE(tmp_rows_.data(), tmp_e_cols_.data());
-
- // y = (E'E)^-1 y3
- VectorRef(y, num_cols).setZero();
- block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(), y);
-
- // The full solution vector y has two blocks. The first block of
- // variables corresponds to the eliminated variables, which we just
- // computed via back substitution. The second block of variables
- // corresponds to the Schur complement system, so we just copy those
- // values from the solution to the Schur complement.
- VectorRef(y + num_cols_e, num_cols_f) = ConstVectorRef(x, num_cols_f);
-}
-
-// Compute the RHS of the Schur complement system.
-//
-// rhs = F'b - F'E (E'E)^-1 E'b
-//
-// Like BackSubstitute, we use the block structure of A to implement
-// this using a series of matrix vector products.
-void ImplicitSchurComplement::UpdateRhs() {
- // y1 = E'b
- tmp_e_cols_.setZero();
- A_->LeftMultiplyE(b_, tmp_e_cols_.data());
-
- // y2 = (E'E)^-1 y1
- Vector y2 = Vector::Zero(A_->num_cols_e());
- block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(), y2.data());
-
- // y3 = E y2
- tmp_rows_.setZero();
- A_->RightMultiplyE(y2.data(), tmp_rows_.data());
-
- // y3 = b - y3
- tmp_rows_ = ConstVectorRef(b_, A_->num_rows()) - tmp_rows_;
-
- // rhs = F' y3
- rhs_.setZero();
- A_->LeftMultiplyF(tmp_rows_.data(), rhs_.data());
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h b/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h
deleted file mode 100644
index c992bdc206e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/implicit_schur_complement.h
+++ /dev/null
@@ -1,167 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// An iterative solver for solving the Schur complement/reduced camera
-// linear system that arise in SfM problems.
-
-#ifndef CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
-#define CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
-
-#include "ceres/linear_operator.h"
-#include "ceres/linear_solver.h"
-#include "ceres/partitioned_matrix_view.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockSparseMatrix;
-
-// This class implements various linear algebraic operations related
-// to the Schur complement without explicitly forming it.
-//
-//
-// Given a reactangular linear system Ax = b, where
-//
-// A = [E F]
-//
-// The normal equations are given by
-//
-// A'Ax = A'b
-//
-// |E'E E'F||y| = |E'b|
-// |F'E F'F||z| |F'b|
-//
-// and the Schur complement system is given by
-//
-// [F'F - F'E (E'E)^-1 E'F] z = F'b - F'E (E'E)^-1 E'b
-//
-// Now if we wish to solve Ax = b in the least squares sense, one way
-// is to form this Schur complement system and solve it using
-// Preconditioned Conjugate Gradients.
-//
-// The key operation in a conjugate gradient solver is the evaluation of the
-// matrix vector product with the Schur complement
-//
-// S = F'F - F'E (E'E)^-1 E'F
-//
-// It is straightforward to see that matrix vector products with S can
-// be evaluated without storing S in memory. Instead, given (E'E)^-1
-// (which for our purposes is an easily inverted block diagonal
-// matrix), it can be done in terms of matrix vector products with E,
-// F and (E'E)^-1. This class implements this functionality and other
-// auxilliary bits needed to implement a CG solver on the Schur
-// complement using the PartitionedMatrixView object.
-//
-// THREAD SAFETY: This class is nqot thread safe. In particular, the
-// RightMultiply (and the LeftMultiply) methods are not thread safe as
-// they depend on mutable arrays used for the temporaries needed to
-// compute the product y += Sx;
-class ImplicitSchurComplement : public LinearOperator {
- public:
- // num_eliminate_blocks is the number of E blocks in the matrix
- // A.
- //
- // preconditioner indicates whether the inverse of the matrix F'F
- // should be computed or not as a preconditioner for the Schur
- // Complement.
- //
- // TODO(sameeragarwal): Get rid of the two bools below and replace
- // them with enums.
- ImplicitSchurComplement(const LinearSolver::Options& options);
- virtual ~ImplicitSchurComplement();
-
- // Initialize the Schur complement for a linear least squares
- // problem of the form
- //
- // |A | x = |b|
- // |diag(D)| |0|
- //
- // If D is null, then it is treated as a zero dimensional matrix. It
- // is important that the matrix A have a BlockStructure object
- // associated with it and has a block structure that is compatible
- // with the SchurComplement solver.
- void Init(const BlockSparseMatrix& A, const double* D, const double* b);
-
- // y += Sx, where S is the Schur complement.
- virtual void RightMultiply(const double* x, double* y) const;
-
- // The Schur complement is a symmetric positive definite matrix,
- // thus the left and right multiply operators are the same.
- virtual void LeftMultiply(const double* x, double* y) const {
- RightMultiply(x, y);
- }
-
- // y = (E'E)^-1 (E'b - E'F x). Given an estimate of the solution to
- // the Schur complement system, this method computes the value of
- // the e_block variables that were eliminated to form the Schur
- // complement.
- void BackSubstitute(const double* x, double* y);
-
- virtual int num_rows() const { return A_->num_cols_f(); }
- virtual int num_cols() const { return A_->num_cols_f(); }
- const Vector& rhs() const { return rhs_; }
-
- const BlockSparseMatrix* block_diagonal_EtE_inverse() const {
- return block_diagonal_EtE_inverse_.get();
- }
-
- const BlockSparseMatrix* block_diagonal_FtF_inverse() const {
- return block_diagonal_FtF_inverse_.get();
- }
-
- private:
- void AddDiagonalAndInvert(const double* D, BlockSparseMatrix* matrix);
- void UpdateRhs();
-
- const LinearSolver::Options& options_;
-
- scoped_ptr<PartitionedMatrixViewBase> A_;
- const double* D_;
- const double* b_;
-
- scoped_ptr<BlockSparseMatrix> block_diagonal_EtE_inverse_;
- scoped_ptr<BlockSparseMatrix> block_diagonal_FtF_inverse_;
-
- Vector rhs_;
-
- // Temporary storage vectors used to implement RightMultiply.
- mutable Vector tmp_rows_;
- mutable Vector tmp_e_cols_;
- mutable Vector tmp_e_cols_2_;
- mutable Vector tmp_f_cols_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.cc b/extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.cc
deleted file mode 100644
index 6ba38ec8eec..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/incomplete_lq_factorization.h"
-
-#include <vector>
-#include <utility>
-#include <cmath>
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// Normalize a row and return it's norm.
-inline double NormalizeRow(const int row, CompressedRowSparseMatrix* matrix) {
- const int row_begin = matrix->rows()[row];
- const int row_end = matrix->rows()[row + 1];
-
- double* values = matrix->mutable_values();
- double norm = 0.0;
- for (int i = row_begin; i < row_end; ++i) {
- norm += values[i] * values[i];
- }
-
- norm = sqrt(norm);
- const double inverse_norm = 1.0 / norm;
- for (int i = row_begin; i < row_end; ++i) {
- values[i] *= inverse_norm;
- }
-
- return norm;
-}
-
-// Compute a(row_a,:) * b(row_b, :)'
-inline double RowDotProduct(const CompressedRowSparseMatrix& a,
- const int row_a,
- const CompressedRowSparseMatrix& b,
- const int row_b) {
- const int* a_rows = a.rows();
- const int* a_cols = a.cols();
- const double* a_values = a.values();
-
- const int* b_rows = b.rows();
- const int* b_cols = b.cols();
- const double* b_values = b.values();
-
- const int row_a_end = a_rows[row_a + 1];
- const int row_b_end = b_rows[row_b + 1];
-
- int idx_a = a_rows[row_a];
- int idx_b = b_rows[row_b];
- double dot_product = 0.0;
- while (idx_a < row_a_end && idx_b < row_b_end) {
- if (a_cols[idx_a] == b_cols[idx_b]) {
- dot_product += a_values[idx_a++] * b_values[idx_b++];
- }
-
- while (a_cols[idx_a] < b_cols[idx_b] && idx_a < row_a_end) {
- ++idx_a;
- }
-
- while (a_cols[idx_a] > b_cols[idx_b] && idx_b < row_b_end) {
- ++idx_b;
- }
- }
-
- return dot_product;
-}
-
-struct SecondGreaterThan {
- public:
- bool operator()(const pair<int, double>& lhs,
- const pair<int, double>& rhs) const {
- return (fabs(lhs.second) > fabs(rhs.second));
- }
-};
-
-// In the row vector dense_row(0:num_cols), drop values smaller than
-// the max_value * drop_tolerance. Of the remaining non-zero values,
-// choose at most level_of_fill values and then add the resulting row
-// vector to matrix.
-
-void DropEntriesAndAddRow(const Vector& dense_row,
- const int num_entries,
- const int level_of_fill,
- const double drop_tolerance,
- vector<pair<int, double> >* scratch,
- CompressedRowSparseMatrix* matrix) {
- int* rows = matrix->mutable_rows();
- int* cols = matrix->mutable_cols();
- double* values = matrix->mutable_values();
- int num_nonzeros = rows[matrix->num_rows()];
-
- if (num_entries == 0) {
- matrix->set_num_rows(matrix->num_rows() + 1);
- rows[matrix->num_rows()] = num_nonzeros;
- return;
- }
-
- const double max_value = dense_row.head(num_entries).cwiseAbs().maxCoeff();
- const double threshold = drop_tolerance * max_value;
-
- int scratch_count = 0;
- for (int i = 0; i < num_entries; ++i) {
- if (fabs(dense_row[i]) > threshold) {
- pair<int, double>& entry = (*scratch)[scratch_count];
- entry.first = i;
- entry.second = dense_row[i];
- ++scratch_count;
- }
- }
-
- if (scratch_count > level_of_fill) {
- nth_element(scratch->begin(),
- scratch->begin() + level_of_fill,
- scratch->begin() + scratch_count,
- SecondGreaterThan());
- scratch_count = level_of_fill;
- sort(scratch->begin(), scratch->begin() + scratch_count);
- }
-
- for (int i = 0; i < scratch_count; ++i) {
- const pair<int, double>& entry = (*scratch)[i];
- cols[num_nonzeros] = entry.first;
- values[num_nonzeros] = entry.second;
- ++num_nonzeros;
- }
-
- matrix->set_num_rows(matrix->num_rows() + 1);
- rows[matrix->num_rows()] = num_nonzeros;
-}
-
-// Saad's Incomplete LQ factorization algorithm.
-CompressedRowSparseMatrix* IncompleteLQFactorization(
- const CompressedRowSparseMatrix& matrix,
- const int l_level_of_fill,
- const double l_drop_tolerance,
- const int q_level_of_fill,
- const double q_drop_tolerance) {
- const int num_rows = matrix.num_rows();
- const int num_cols = matrix.num_cols();
- const int* rows = matrix.rows();
- const int* cols = matrix.cols();
- const double* values = matrix.values();
-
- CompressedRowSparseMatrix* l =
- new CompressedRowSparseMatrix(num_rows,
- num_rows,
- l_level_of_fill * num_rows);
- l->set_num_rows(0);
-
- CompressedRowSparseMatrix q(num_rows, num_cols, q_level_of_fill * num_rows);
- q.set_num_rows(0);
-
- int* l_rows = l->mutable_rows();
- int* l_cols = l->mutable_cols();
- double* l_values = l->mutable_values();
-
- int* q_rows = q.mutable_rows();
- int* q_cols = q.mutable_cols();
- double* q_values = q.mutable_values();
-
- Vector l_i(num_rows);
- Vector q_i(num_cols);
- vector<pair<int, double> > scratch(num_cols);
- for (int i = 0; i < num_rows; ++i) {
- // l_i = q * matrix(i,:)');
- l_i.setZero();
- for (int j = 0; j < i; ++j) {
- l_i(j) = RowDotProduct(matrix, i, q, j);
- }
- DropEntriesAndAddRow(l_i,
- i,
- l_level_of_fill,
- l_drop_tolerance,
- &scratch,
- l);
-
- // q_i = matrix(i,:) - q(0:i-1,:) * l_i);
- q_i.setZero();
- for (int idx = rows[i]; idx < rows[i + 1]; ++idx) {
- q_i(cols[idx]) = values[idx];
- }
-
- for (int j = l_rows[i]; j < l_rows[i + 1]; ++j) {
- const int r = l_cols[j];
- const double lij = l_values[j];
- for (int idx = q_rows[r]; idx < q_rows[r + 1]; ++idx) {
- q_i(q_cols[idx]) -= lij * q_values[idx];
- }
- }
- DropEntriesAndAddRow(q_i,
- num_cols,
- q_level_of_fill,
- q_drop_tolerance,
- &scratch,
- &q);
-
- // lii = |qi|
- l_cols[l->num_nonzeros()] = i;
- l_values[l->num_nonzeros()] = NormalizeRow(i, &q);
- l_rows[l->num_rows()] += 1;
- }
-
- return l;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.h b/extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.h
deleted file mode 100644
index e678463cf8d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/incomplete_lq_factorization.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_INCOMPLETE_LQ_FACTORIZATION_H_
-#define CERES_INTERNAL_INCOMPLETE_LQ_FACTORIZATION_H_
-
-#include <vector>
-#include <utility>
-#include "ceres/compressed_row_sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-// Incomplete LQ factorization as described in
-//
-// Preconditioning techniques for indefinite and nonsymmetric linear
-// systems. Yousef Saad, Preprint RIACS-ILQ-TR, RIACS, NASA Ames
-// Research Center, Moffett Field, CA, 1987.
-//
-// An incomplete LQ factorization of a matrix A is a decomposition
-//
-// A = LQ + E
-//
-// Where L is a lower triangular matrix, and Q is a near orthonormal
-// matrix. The extent of orthonormality depends on E. E is the "drop"
-// matrix. Each row of L has a maximum of l_level_of_fill entries, and
-// all non-zero entries are within l_drop_tolerance of the largest
-// entry. Each row of Q has a maximum of q_level_of_fill entries and
-// all non-zero entries are within q_drop_tolerance of the largest
-// entry.
-//
-// E is the error of the incomplete factorization.
-//
-// The purpose of incomplete factorizations is preconditioning and
-// there one only needs the L matrix, therefore this function just
-// returns L.
-//
-// Caller owns the result.
-CompressedRowSparseMatrix* IncompleteLQFactorization(
- const CompressedRowSparseMatrix& matrix,
- const int l_level_of_fill,
- const double l_drop_tolerance,
- const int q_level_of_fill,
- const double q_drop_tolerance);
-
-// In the row vector dense_row(0:num_cols), drop values smaller than
-// the max_value * drop_tolerance. Of the remaining non-zero values,
-// choose at most level_of_fill values and then add the resulting row
-// vector to matrix.
-//
-// scratch is used to prevent allocations inside this function. It is
-// assumed that scratch is of size matrix->num_cols().
-void DropEntriesAndAddRow(const Vector& dense_row,
- const int num_entries,
- const int level_of_fill,
- const double drop_tolerance,
- vector<pair<int, double> >* scratch,
- CompressedRowSparseMatrix* matrix);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_INCOMPLETE_LQ_FACTORIZATION_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/integral_types.h b/extern/libmv/third_party/ceres/internal/ceres/integral_types.h
deleted file mode 100644
index d4913f53745..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/integral_types.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Portable typedefs for various fixed-size integers. Uses template
-// metaprogramming instead of fragile compiler defines.
-
-#ifndef CERES_INTERNAL_INTEGRAL_TYPES_H_
-#define CERES_INTERNAL_INTEGRAL_TYPES_H_
-
-namespace ceres {
-namespace internal {
-
-// Compile time ternary on types.
-template<bool kCondition, typename kTrueType, typename kFalseType>
-struct Ternary {
- typedef kTrueType type;
-};
-template<typename kTrueType, typename kFalseType>
-struct Ternary<false, kTrueType, kFalseType> {
- typedef kFalseType type;
-};
-
-#define CERES_INTSIZE(TYPE) \
- typename Ternary<sizeof(TYPE) * 8 == kBits, TYPE,
-
-template<int kBits>
-struct Integer {
- typedef
- CERES_INTSIZE(char)
- CERES_INTSIZE(short)
- CERES_INTSIZE(int)
- CERES_INTSIZE(long int)
- CERES_INTSIZE(long long)
- void>::type >::type >::type >::type >::type
- type;
-};
-
-template<int kBits>
-struct UnsignedInteger {
- typedef
- CERES_INTSIZE(unsigned char)
- CERES_INTSIZE(unsigned short)
- CERES_INTSIZE(unsigned int)
- CERES_INTSIZE(unsigned long int)
- CERES_INTSIZE(unsigned long long)
- void>::type >::type >::type >::type >::type
- type;
-};
-
-#undef CERES_INTSIZE
-
-typedef Integer< 8>::type int8;
-typedef Integer<32>::type int32;
-typedef Integer<64>::type int64;
-
-typedef UnsignedInteger< 8>::type uint8;
-typedef UnsignedInteger<16>::type uint16;
-typedef UnsignedInteger<32>::type uint32;
-typedef UnsignedInteger<64>::type uint64;
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_INTEGRAL_TYPES_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
deleted file mode 100644
index 0cf08fef5f7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/iterative_schur_complement_solver.h"
-
-#include <algorithm>
-#include <cstring>
-#include <vector>
-
-#include "Eigen/Dense"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/conjugate_gradients_solver.h"
-#include "ceres/detect_structure.h"
-#include "ceres/implicit_schur_complement.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-#include "ceres/preconditioner.h"
-#include "ceres/schur_jacobi_preconditioner.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "ceres/visibility_based_preconditioner.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-IterativeSchurComplementSolver::IterativeSchurComplementSolver(
- const LinearSolver::Options& options)
- : options_(options) {
-}
-
-IterativeSchurComplementSolver::~IterativeSchurComplementSolver() {
-}
-
-LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
- BlockSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("IterativeSchurComplementSolver::Solve");
-
- CHECK_NOTNULL(A->block_structure());
- const int num_eliminate_blocks = options_.elimination_groups[0];
- // Initialize a ImplicitSchurComplement object.
- if (schur_complement_ == NULL) {
- DetectStructure(*(A->block_structure()),
- num_eliminate_blocks,
- &options_.row_block_size,
- &options_.e_block_size,
- &options_.f_block_size);
- schur_complement_.reset(new ImplicitSchurComplement(options_));
- }
- schur_complement_->Init(*A, per_solve_options.D, b);
-
- const int num_schur_complement_blocks =
- A->block_structure()->cols.size() - num_eliminate_blocks;
- if (num_schur_complement_blocks == 0) {
- VLOG(2) << "No parameter blocks left in the schur complement.";
- LinearSolver::Summary cg_summary;
- cg_summary.num_iterations = 0;
- cg_summary.termination_type = LINEAR_SOLVER_SUCCESS;
- schur_complement_->BackSubstitute(NULL, x);
- return cg_summary;
- }
-
- // Initialize the solution to the Schur complement system to zero.
- reduced_linear_system_solution_.resize(schur_complement_->num_rows());
- reduced_linear_system_solution_.setZero();
-
- // Instantiate a conjugate gradient solver that runs on the Schur
- // complement matrix with the block diagonal of the matrix F'F as
- // the preconditioner.
- LinearSolver::Options cg_options;
- cg_options.min_num_iterations = options_.min_num_iterations;
- cg_options.max_num_iterations = options_.max_num_iterations;
- ConjugateGradientsSolver cg_solver(cg_options);
- LinearSolver::PerSolveOptions cg_per_solve_options;
-
- cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
- cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
-
- Preconditioner::Options preconditioner_options;
- preconditioner_options.type = options_.preconditioner_type;
- preconditioner_options.visibility_clustering_type =
- options_.visibility_clustering_type;
- preconditioner_options.sparse_linear_algebra_library_type =
- options_.sparse_linear_algebra_library_type;
- preconditioner_options.num_threads = options_.num_threads;
- preconditioner_options.row_block_size = options_.row_block_size;
- preconditioner_options.e_block_size = options_.e_block_size;
- preconditioner_options.f_block_size = options_.f_block_size;
- preconditioner_options.elimination_groups = options_.elimination_groups;
-
- switch (options_.preconditioner_type) {
- case IDENTITY:
- break;
- case JACOBI:
- preconditioner_.reset(
- new SparseMatrixPreconditionerWrapper(
- schur_complement_->block_diagonal_FtF_inverse()));
- break;
- case SCHUR_JACOBI:
- if (preconditioner_.get() == NULL) {
- preconditioner_.reset(
- new SchurJacobiPreconditioner(*A->block_structure(),
- preconditioner_options));
- }
- break;
- case CLUSTER_JACOBI:
- case CLUSTER_TRIDIAGONAL:
- if (preconditioner_.get() == NULL) {
- preconditioner_.reset(
- new VisibilityBasedPreconditioner(*A->block_structure(),
- preconditioner_options));
- }
- break;
- default:
- LOG(FATAL) << "Unknown Preconditioner Type";
- }
-
- bool preconditioner_update_was_successful = true;
- if (preconditioner_.get() != NULL) {
- preconditioner_update_was_successful =
- preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner = preconditioner_.get();
- }
- event_logger.AddEvent("Setup");
-
- LinearSolver::Summary cg_summary;
- cg_summary.num_iterations = 0;
- cg_summary.termination_type = LINEAR_SOLVER_FAILURE;
-
- // TODO(sameeragarwal): Refactor preconditioners to return a more
- // sane message.
- cg_summary.message = "Preconditioner update failed.";
- if (preconditioner_update_was_successful) {
- cg_summary = cg_solver.Solve(schur_complement_.get(),
- schur_complement_->rhs().data(),
- cg_per_solve_options,
- reduced_linear_system_solution_.data());
- if (cg_summary.termination_type != LINEAR_SOLVER_FAILURE &&
- cg_summary.termination_type != LINEAR_SOLVER_FATAL_ERROR) {
- schur_complement_->BackSubstitute(
- reduced_linear_system_solution_.data(), x);
- }
- }
- event_logger.AddEvent("Solve");
- return cg_summary;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
deleted file mode 100644
index b056a694478..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
-#define CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
-
-#include "ceres/linear_solver.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockSparseMatrix;
-class ImplicitSchurComplement;
-class Preconditioner;
-
-// This class implements an iterative solver for the linear least
-// squares problems that have a bi-partite sparsity structure common
-// to Structure from Motion problems.
-//
-// The algorithm used by this solver was developed in a series of
-// papers - "Agarwal et al, Bundle Adjustment in the Large, ECCV 2010"
-// and "Wu et al, Multicore Bundle Adjustment, submitted to CVPR
-// 2011" at the Univeristy of Washington.
-//
-// The key idea is that one can run Conjugate Gradients on the Schur
-// Complement system without explicitly forming the Schur Complement
-// in memory. The heavy lifting for this is done by the
-// ImplicitSchurComplement class. Not forming the Schur complement in
-// memory and factoring it results in substantial savings in time and
-// memory. Further, iterative solvers like this open up the
-// possibility of solving the Newton equations in a non-linear solver
-// only approximately and terminating early, thereby saving even more
-// time.
-//
-// For the curious, running CG on the Schur complement is the same as
-// running CG on the Normal Equations with an SSOR preconditioner. For
-// a proof of this fact and others related to this solver please see
-// the section on Domain Decomposition Methods in Saad's book
-// "Iterative Methods for Sparse Linear Systems".
-class IterativeSchurComplementSolver : public BlockSparseMatrixSolver {
- public:
- explicit IterativeSchurComplementSolver(const LinearSolver::Options& options);
- virtual ~IterativeSchurComplementSolver();
-
- private:
- virtual LinearSolver::Summary SolveImpl(
- BlockSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& options,
- double* x);
-
- LinearSolver::Options options_;
- scoped_ptr<internal::ImplicitSchurComplement> schur_complement_;
- scoped_ptr<Preconditioner> preconditioner_;
- Vector reduced_linear_system_solution_;
- CERES_DISALLOW_COPY_AND_ASSIGN(IterativeSchurComplementSolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/lapack.cc b/extern/libmv/third_party/ceres/internal/ceres/lapack.cc
deleted file mode 100644
index e124d757024..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/lapack.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/lapack.h"
-
-#include "ceres/internal/port.h"
-#include "ceres/linear_solver.h"
-#include "glog/logging.h"
-
-// C interface to the LAPACK Cholesky factorization and triangular solve.
-extern "C" void dpotrf_(char* uplo,
- int* n,
- double* a,
- int* lda,
- int* info);
-
-extern "C" void dpotrs_(char* uplo,
- int* n,
- int* nrhs,
- double* a,
- int* lda,
- double* b,
- int* ldb,
- int* info);
-
-extern "C" void dgels_(char* uplo,
- int* m,
- int* n,
- int* nrhs,
- double* a,
- int* lda,
- double* b,
- int* ldb,
- double* work,
- int* lwork,
- int* info);
-
-
-namespace ceres {
-namespace internal {
-
-LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
- int num_rows,
- const double* in_lhs,
- double* rhs_and_solution,
- string* message) {
-#ifdef CERES_NO_LAPACK
- LOG(FATAL) << "Ceres was built without a BLAS library.";
- return LINEAR_SOLVER_FATAL_ERROR;
-#else
- char uplo = 'L';
- int n = num_rows;
- int info = 0;
- int nrhs = 1;
- double* lhs = const_cast<double*>(in_lhs);
-
- dpotrf_(&uplo, &n, lhs, &n, &info);
- if (info < 0) {
- LOG(FATAL) << "Congratulations, you found a bug in Ceres."
- << "Please report it."
- << "LAPACK::dpotrf fatal error."
- << "Argument: " << -info << " is invalid.";
- return LINEAR_SOLVER_FATAL_ERROR;
- }
-
- if (info > 0) {
- *message =
- StringPrintf(
- "LAPACK::dpotrf numerical failure. "
- "The leading minor of order %d is not positive definite.", info);
- return LINEAR_SOLVER_FAILURE;
- }
-
- dpotrs_(&uplo, &n, &nrhs, lhs, &n, rhs_and_solution, &n, &info);
- if (info < 0) {
- LOG(FATAL) << "Congratulations, you found a bug in Ceres."
- << "Please report it."
- << "LAPACK::dpotrs fatal error."
- << "Argument: " << -info << " is invalid.";
- return LINEAR_SOLVER_FATAL_ERROR;
- }
-
- *message = "Success";
- return LINEAR_SOLVER_SUCCESS;
-#endif
-};
-
-int LAPACK::EstimateWorkSizeForQR(int num_rows, int num_cols) {
-#ifdef CERES_NO_LAPACK
- LOG(FATAL) << "Ceres was built without a LAPACK library.";
- return -1;
-#else
- char trans = 'N';
- int nrhs = 1;
- int lwork = -1;
- double work;
- int info = 0;
- dgels_(&trans,
- &num_rows,
- &num_cols,
- &nrhs,
- NULL,
- &num_rows,
- NULL,
- &num_rows,
- &work,
- &lwork,
- &info);
-
- if (info < 0) {
- LOG(FATAL) << "Congratulations, you found a bug in Ceres."
- << "Please report it."
- << "LAPACK::dgels fatal error."
- << "Argument: " << -info << " is invalid.";
- }
- return static_cast<int>(work);
-#endif
-}
-
-LinearSolverTerminationType LAPACK::SolveInPlaceUsingQR(
- int num_rows,
- int num_cols,
- const double* in_lhs,
- int work_size,
- double* work,
- double* rhs_and_solution,
- string* message) {
-#ifdef CERES_NO_LAPACK
- LOG(FATAL) << "Ceres was built without a LAPACK library.";
- return LINEAR_SOLVER_FATAL_ERROR;
-#else
- char trans = 'N';
- int m = num_rows;
- int n = num_cols;
- int nrhs = 1;
- int lda = num_rows;
- int ldb = num_rows;
- int info = 0;
- double* lhs = const_cast<double*>(in_lhs);
-
- dgels_(&trans,
- &m,
- &n,
- &nrhs,
- lhs,
- &lda,
- rhs_and_solution,
- &ldb,
- work,
- &work_size,
- &info);
-
- if (info < 0) {
- LOG(FATAL) << "Congratulations, you found a bug in Ceres."
- << "Please report it."
- << "LAPACK::dgels fatal error."
- << "Argument: " << -info << " is invalid.";
- }
-
- *message = "Success.";
- return LINEAR_SOLVER_SUCCESS;
-#endif
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/lapack.h b/extern/libmv/third_party/ceres/internal/ceres/lapack.h
deleted file mode 100644
index 8933c2c8d83..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/lapack.h
+++ /dev/null
@@ -1,100 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LAPACK_H_
-#define CERES_INTERNAL_LAPACK_H_
-
-#include <string>
-#include "ceres/internal/port.h"
-#include "ceres/linear_solver.h"
-
-namespace ceres {
-namespace internal {
-
-class LAPACK {
- public:
- // Solve
- //
- // lhs * solution = rhs
- //
- // using a Cholesky factorization. Here
- // lhs is a symmetric positive definite matrix. It is assumed to be
- // column major and only the lower triangular part of the matrix is
- // referenced.
- //
- // This function uses the LAPACK dpotrf and dpotrs routines.
- //
- // The return value and the message string together describe whether
- // the solver terminated successfully or not and if so, what was the
- // reason for failure.
- static LinearSolverTerminationType SolveInPlaceUsingCholesky(
- int num_rows,
- const double* lhs,
- double* rhs_and_solution,
- string* message);
-
- // The SolveUsingQR function requires a buffer for its temporary
- // computation. This function given the size of the lhs matrix will
- // return the size of the buffer needed.
- static int EstimateWorkSizeForQR(int num_rows, int num_cols);
-
- // Solve
- //
- // lhs * solution = rhs
- //
- // using a dense QR factorization. lhs is an arbitrary (possibly
- // rectangular) matrix with full column rank.
- //
- // work is an array of size work_size that this routine uses for its
- // temporary storage. The optimal size of this array can be obtained
- // by calling EstimateWorkSizeForQR.
- //
- // When calling, rhs_and_solution contains the rhs, and upon return
- // the first num_col entries are the solution.
- //
- // This function uses the LAPACK dgels routine.
- //
- // The return value and the message string together describe whether
- // the solver terminated successfully or not and if so, what was the
- // reason for failure.
- static LinearSolverTerminationType SolveInPlaceUsingQR(
- int num_rows,
- int num_cols,
- const double* lhs,
- int work_size,
- double* work,
- double* rhs_and_solution,
- string* message);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LAPACK_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc
deleted file mode 100644
index ce3b69a8005..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/levenberg_marquardt_strategy.h"
-
-#include <cmath>
-#include "Eigen/Core"
-#include "ceres/array_utils.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_least_squares_problems.h"
-#include "ceres/linear_solver.h"
-#include "ceres/sparse_matrix.h"
-#include "ceres/trust_region_strategy.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-LevenbergMarquardtStrategy::LevenbergMarquardtStrategy(
- const TrustRegionStrategy::Options& options)
- : linear_solver_(options.linear_solver),
- radius_(options.initial_radius),
- max_radius_(options.max_radius),
- min_diagonal_(options.min_lm_diagonal),
- max_diagonal_(options.max_lm_diagonal),
- decrease_factor_(2.0),
- reuse_diagonal_(false) {
- CHECK_NOTNULL(linear_solver_);
- CHECK_GT(min_diagonal_, 0.0);
- CHECK_LE(min_diagonal_, max_diagonal_);
- CHECK_GT(max_radius_, 0.0);
-}
-
-LevenbergMarquardtStrategy::~LevenbergMarquardtStrategy() {
-}
-
-TrustRegionStrategy::Summary LevenbergMarquardtStrategy::ComputeStep(
- const TrustRegionStrategy::PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals,
- double* step) {
- CHECK_NOTNULL(jacobian);
- CHECK_NOTNULL(residuals);
- CHECK_NOTNULL(step);
-
- const int num_parameters = jacobian->num_cols();
- if (!reuse_diagonal_) {
- if (diagonal_.rows() != num_parameters) {
- diagonal_.resize(num_parameters, 1);
- }
-
- jacobian->SquaredColumnNorm(diagonal_.data());
- for (int i = 0; i < num_parameters; ++i) {
- diagonal_[i] = min(max(diagonal_[i], min_diagonal_), max_diagonal_);
- }
- }
-
- lm_diagonal_ = (diagonal_ / radius_).array().sqrt();
-
- LinearSolver::PerSolveOptions solve_options;
- solve_options.D = lm_diagonal_.data();
- solve_options.q_tolerance = per_solve_options.eta;
- // Disable r_tolerance checking. Since we only care about
- // termination via the q_tolerance. As Nash and Sofer show,
- // r_tolerance based termination is essentially useless in
- // Truncated Newton methods.
- solve_options.r_tolerance = -1.0;
-
- // Invalidate the output array lm_step, so that we can detect if
- // the linear solver generated numerical garbage. This is known
- // to happen for the DENSE_QR and then DENSE_SCHUR solver when
- // the Jacobin is severly rank deficient and mu is too small.
- InvalidateArray(num_parameters, step);
-
- // Instead of solving Jx = -r, solve Jy = r.
- // Then x can be found as x = -y, but the inputs jacobian and residuals
- // do not need to be modified.
- LinearSolver::Summary linear_solver_summary =
- linear_solver_->Solve(jacobian, residuals, solve_options, step);
-
- if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
- LOG(WARNING) << "Linear solver fatal error.";
- } else if (linear_solver_summary.termination_type == LINEAR_SOLVER_FAILURE ||
- !IsArrayValid(num_parameters, step)) {
- LOG(WARNING) << "Linear solver failure. Failed to compute a finite step.";
- linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
- } else {
- VectorRef(step, num_parameters) *= -1.0;
- }
- reuse_diagonal_ = true;
-
- if (per_solve_options.dump_format_type == CONSOLE ||
- (per_solve_options.dump_format_type != CONSOLE &&
- !per_solve_options.dump_filename_base.empty())) {
- if (!DumpLinearLeastSquaresProblem(per_solve_options.dump_filename_base,
- per_solve_options.dump_format_type,
- jacobian,
- solve_options.D,
- residuals,
- step,
- 0)) {
- LOG(ERROR) << "Unable to dump trust region problem."
- << " Filename base: " << per_solve_options.dump_filename_base;
- }
- }
-
-
- TrustRegionStrategy::Summary summary;
- summary.residual_norm = linear_solver_summary.residual_norm;
- summary.num_iterations = linear_solver_summary.num_iterations;
- summary.termination_type = linear_solver_summary.termination_type;
- return summary;
-}
-
-void LevenbergMarquardtStrategy::StepAccepted(double step_quality) {
- CHECK_GT(step_quality, 0.0);
- radius_ = radius_ / std::max(1.0 / 3.0,
- 1.0 - pow(2.0 * step_quality - 1.0, 3));
- radius_ = std::min(max_radius_, radius_);
- decrease_factor_ = 2.0;
- reuse_diagonal_ = false;
-}
-
-void LevenbergMarquardtStrategy::StepRejected(double step_quality) {
- radius_ = radius_ / decrease_factor_;
- decrease_factor_ *= 2.0;
- reuse_diagonal_ = true;
-}
-
-double LevenbergMarquardtStrategy::Radius() const {
- return radius_;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
deleted file mode 100644
index 344e3285422..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
+++ /dev/null
@@ -1,87 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
-#define CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
-
-#include "ceres/internal/eigen.h"
-#include "ceres/trust_region_strategy.h"
-
-namespace ceres {
-namespace internal {
-
-// Levenberg-Marquardt step computation and trust region sizing
-// strategy based on on "Methods for Nonlinear Least Squares" by
-// K. Madsen, H.B. Nielsen and O. Tingleff. Available to download from
-//
-// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
-class LevenbergMarquardtStrategy : public TrustRegionStrategy {
- public:
- explicit LevenbergMarquardtStrategy(
- const TrustRegionStrategy::Options& options);
- virtual ~LevenbergMarquardtStrategy();
-
- // TrustRegionStrategy interface
- virtual TrustRegionStrategy::Summary ComputeStep(
- const TrustRegionStrategy::PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals,
- double* step);
- virtual void StepAccepted(double step_quality);
- virtual void StepRejected(double step_quality);
- virtual void StepIsInvalid() {
- // Treat the current step as a rejected step with no increase in
- // solution quality. Since rejected steps lead to decrease in the
- // size of the trust region, the next time ComputeStep is called,
- // this will lead to a better conditioned system.
- StepRejected(0.0);
- }
-
- virtual double Radius() const;
-
- private:
- LinearSolver* linear_solver_;
- double radius_;
- double max_radius_;
- const double min_diagonal_;
- const double max_diagonal_;
- double decrease_factor_;
- bool reuse_diagonal_;
- Vector diagonal_; // diagonal_ = diag(J'J)
- // Scaled copy of diagonal_. Stored here as optimization to prevent
- // allocations in every iteration and reuse when a step fails and
- // ComputeStep is called again.
- Vector lm_diagonal_; // lm_diagonal_ = diagonal_ / radius_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc
deleted file mode 100644
index 7ff11646dd3..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search.cc
+++ /dev/null
@@ -1,821 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include <iomanip>
-#include <iostream> // NOLINT
-
-#include "ceres/line_search.h"
-
-#include "ceres/fpclassify.h"
-#include "ceres/evaluator.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/polynomial.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-// Precision used for floating point values in error message output.
-const int kErrorMessageNumericPrecision = 8;
-
-FunctionSample ValueSample(const double x, const double value) {
- FunctionSample sample;
- sample.x = x;
- sample.value = value;
- sample.value_is_valid = true;
- return sample;
-};
-
-FunctionSample ValueAndGradientSample(const double x,
- const double value,
- const double gradient) {
- FunctionSample sample;
- sample.x = x;
- sample.value = value;
- sample.gradient = gradient;
- sample.value_is_valid = true;
- sample.gradient_is_valid = true;
- return sample;
-};
-
-} // namespace
-
-
-std::ostream& operator<<(std::ostream &os, const FunctionSample& sample);
-
-// Convenience stream operator for pushing FunctionSamples into log messages.
-std::ostream& operator<<(std::ostream &os, const FunctionSample& sample) {
- os << sample.ToDebugString();
- return os;
-}
-
-LineSearch::LineSearch(const LineSearch::Options& options)
- : options_(options) {}
-
-LineSearch* LineSearch::Create(const LineSearchType line_search_type,
- const LineSearch::Options& options,
- string* error) {
- LineSearch* line_search = NULL;
- switch (line_search_type) {
- case ceres::ARMIJO:
- line_search = new ArmijoLineSearch(options);
- break;
- case ceres::WOLFE:
- line_search = new WolfeLineSearch(options);
- break;
- default:
- *error = string("Invalid line search algorithm type: ") +
- LineSearchTypeToString(line_search_type) +
- string(", unable to create line search.");
- return NULL;
- }
- return line_search;
-}
-
-LineSearchFunction::LineSearchFunction(Evaluator* evaluator)
- : evaluator_(evaluator),
- position_(evaluator->NumParameters()),
- direction_(evaluator->NumEffectiveParameters()),
- evaluation_point_(evaluator->NumParameters()),
- scaled_direction_(evaluator->NumEffectiveParameters()),
- gradient_(evaluator->NumEffectiveParameters()) {
-}
-
-void LineSearchFunction::Init(const Vector& position,
- const Vector& direction) {
- position_ = position;
- direction_ = direction;
-}
-
-bool LineSearchFunction::Evaluate(double x, double* f, double* g) {
- scaled_direction_ = x * direction_;
- if (!evaluator_->Plus(position_.data(),
- scaled_direction_.data(),
- evaluation_point_.data())) {
- return false;
- }
-
- if (g == NULL) {
- return (evaluator_->Evaluate(evaluation_point_.data(),
- f, NULL, NULL, NULL) &&
- IsFinite(*f));
- }
-
- if (!evaluator_->Evaluate(evaluation_point_.data(),
- f,
- NULL,
- gradient_.data(), NULL)) {
- return false;
- }
-
- *g = direction_.dot(gradient_);
- return IsFinite(*f) && IsFinite(*g);
-}
-
-double LineSearchFunction::DirectionInfinityNorm() const {
- return direction_.lpNorm<Eigen::Infinity>();
-}
-
-// Returns step_size \in [min_step_size, max_step_size] which minimizes the
-// polynomial of degree defined by interpolation_type which interpolates all
-// of the provided samples with valid values.
-double LineSearch::InterpolatingPolynomialMinimizingStepSize(
- const LineSearchInterpolationType& interpolation_type,
- const FunctionSample& lowerbound,
- const FunctionSample& previous,
- const FunctionSample& current,
- const double min_step_size,
- const double max_step_size) const {
- if (!current.value_is_valid ||
- (interpolation_type == BISECTION &&
- max_step_size <= current.x)) {
- // Either: sample is invalid; or we are using BISECTION and contracting
- // the step size.
- return min(max(current.x * 0.5, min_step_size), max_step_size);
- } else if (interpolation_type == BISECTION) {
- CHECK_GT(max_step_size, current.x);
- // We are expanding the search (during a Wolfe bracketing phase) using
- // BISECTION interpolation. Using BISECTION when trying to expand is
- // strictly speaking an oxymoron, but we define this to mean always taking
- // the maximum step size so that the Armijo & Wolfe implementations are
- // agnostic to the interpolation type.
- return max_step_size;
- }
- // Only check if lower-bound is valid here, where it is required
- // to avoid replicating current.value_is_valid == false
- // behaviour in WolfeLineSearch.
- CHECK(lowerbound.value_is_valid)
- << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
- << "Ceres bug: lower-bound sample for interpolation is invalid, "
- << "please contact the developers!, interpolation_type: "
- << LineSearchInterpolationTypeToString(interpolation_type)
- << ", lowerbound: " << lowerbound << ", previous: " << previous
- << ", current: " << current;
-
- // Select step size by interpolating the function and gradient values
- // and minimizing the corresponding polynomial.
- vector<FunctionSample> samples;
- samples.push_back(lowerbound);
-
- if (interpolation_type == QUADRATIC) {
- // Two point interpolation using function values and the
- // gradient at the lower bound.
- samples.push_back(ValueSample(current.x, current.value));
-
- if (previous.value_is_valid) {
- // Three point interpolation, using function values and the
- // gradient at the lower bound.
- samples.push_back(ValueSample(previous.x, previous.value));
- }
- } else if (interpolation_type == CUBIC) {
- // Two point interpolation using the function values and the gradients.
- samples.push_back(current);
-
- if (previous.value_is_valid) {
- // Three point interpolation using the function values and
- // the gradients.
- samples.push_back(previous);
- }
- } else {
- LOG(FATAL) << "Ceres bug: No handler for interpolation_type: "
- << LineSearchInterpolationTypeToString(interpolation_type)
- << ", please contact the developers!";
- }
-
- double step_size = 0.0, unused_min_value = 0.0;
- MinimizeInterpolatingPolynomial(samples, min_step_size, max_step_size,
- &step_size, &unused_min_value);
- return step_size;
-}
-
-ArmijoLineSearch::ArmijoLineSearch(const LineSearch::Options& options)
- : LineSearch(options) {}
-
-void ArmijoLineSearch::Search(const double step_size_estimate,
- const double initial_cost,
- const double initial_gradient,
- Summary* summary) {
- *CHECK_NOTNULL(summary) = LineSearch::Summary();
- CHECK_GE(step_size_estimate, 0.0);
- CHECK_GT(options().sufficient_decrease, 0.0);
- CHECK_LT(options().sufficient_decrease, 1.0);
- CHECK_GT(options().max_num_iterations, 0);
- Function* function = options().function;
-
- // Note initial_cost & initial_gradient are evaluated at step_size = 0,
- // not step_size_estimate, which is our starting guess.
- const FunctionSample initial_position =
- ValueAndGradientSample(0.0, initial_cost, initial_gradient);
-
- FunctionSample previous = ValueAndGradientSample(0.0, 0.0, 0.0);
- previous.value_is_valid = false;
-
- FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
- current.value_is_valid = false;
-
- // As the Armijo line search algorithm always uses the initial point, for
- // which both the function value and derivative are known, when fitting a
- // minimizing polynomial, we can fit up to a quadratic without requiring the
- // gradient at the current query point.
- const bool interpolation_uses_gradient_at_current_sample =
- options().interpolation_type == CUBIC;
- const double descent_direction_max_norm =
- static_cast<const LineSearchFunction*>(function)->DirectionInfinityNorm();
-
- ++summary->num_function_evaluations;
- if (interpolation_uses_gradient_at_current_sample) {
- ++summary->num_gradient_evaluations;
- }
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- interpolation_uses_gradient_at_current_sample
- ? &current.gradient : NULL);
- current.gradient_is_valid =
- interpolation_uses_gradient_at_current_sample && current.value_is_valid;
- while (!current.value_is_valid ||
- current.value > (initial_cost
- + options().sufficient_decrease
- * initial_gradient
- * current.x)) {
- // If current.value_is_valid is false, we treat it as if the cost at that
- // point is not large enough to satisfy the sufficient decrease condition.
- ++summary->num_iterations;
- if (summary->num_iterations >= options().max_num_iterations) {
- summary->error =
- StringPrintf("Line search failed: Armijo failed to find a point "
- "satisfying the sufficient decrease condition within "
- "specified max_num_iterations: %d.",
- options().max_num_iterations);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- return;
- }
-
- const double step_size =
- this->InterpolatingPolynomialMinimizingStepSize(
- options().interpolation_type,
- initial_position,
- previous,
- current,
- (options().max_step_contraction * current.x),
- (options().min_step_contraction * current.x));
-
- if (step_size * descent_direction_max_norm < options().min_step_size) {
- summary->error =
- StringPrintf("Line search failed: step_size too small: %.5e "
- "with descent_direction_max_norm: %.5e.", step_size,
- descent_direction_max_norm);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- return;
- }
-
- previous = current;
- current.x = step_size;
-
- ++summary->num_function_evaluations;
- if (interpolation_uses_gradient_at_current_sample) {
- ++summary->num_gradient_evaluations;
- }
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- interpolation_uses_gradient_at_current_sample
- ? &current.gradient : NULL);
- current.gradient_is_valid =
- interpolation_uses_gradient_at_current_sample && current.value_is_valid;
- }
-
- summary->optimal_step_size = current.x;
- summary->success = true;
-}
-
-WolfeLineSearch::WolfeLineSearch(const LineSearch::Options& options)
- : LineSearch(options) {}
-
-void WolfeLineSearch::Search(const double step_size_estimate,
- const double initial_cost,
- const double initial_gradient,
- Summary* summary) {
- *CHECK_NOTNULL(summary) = LineSearch::Summary();
- // All parameters should have been validated by the Solver, but as
- // invalid values would produce crazy nonsense, hard check them here.
- CHECK_GE(step_size_estimate, 0.0);
- CHECK_GT(options().sufficient_decrease, 0.0);
- CHECK_GT(options().sufficient_curvature_decrease,
- options().sufficient_decrease);
- CHECK_LT(options().sufficient_curvature_decrease, 1.0);
- CHECK_GT(options().max_step_expansion, 1.0);
-
- // Note initial_cost & initial_gradient are evaluated at step_size = 0,
- // not step_size_estimate, which is our starting guess.
- const FunctionSample initial_position =
- ValueAndGradientSample(0.0, initial_cost, initial_gradient);
-
- bool do_zoom_search = false;
- // Important: The high/low in bracket_high & bracket_low refer to their
- // _function_ values, not their step sizes i.e. it is _not_ required that
- // bracket_low.x < bracket_high.x.
- FunctionSample solution, bracket_low, bracket_high;
-
- // Wolfe bracketing phase: Increases step_size until either it finds a point
- // that satisfies the (strong) Wolfe conditions, or an interval that brackets
- // step sizes which satisfy the conditions. From Nocedal & Wright [1] p61 the
- // interval: (step_size_{k-1}, step_size_{k}) contains step lengths satisfying
- // the strong Wolfe conditions if one of the following conditions are met:
- //
- // 1. step_size_{k} violates the sufficient decrease (Armijo) condition.
- // 2. f(step_size_{k}) >= f(step_size_{k-1}).
- // 3. f'(step_size_{k}) >= 0.
- //
- // Caveat: If f(step_size_{k}) is invalid, then step_size is reduced, ignoring
- // this special case, step_size monotonically increases during bracketing.
- if (!this->BracketingPhase(initial_position,
- step_size_estimate,
- &bracket_low,
- &bracket_high,
- &do_zoom_search,
- summary)) {
- // Failed to find either a valid point, a valid bracket satisfying the Wolfe
- // conditions, or even a step size > minimum tolerance satisfying the Armijo
- // condition.
- return;
- }
-
- if (!do_zoom_search) {
- // Either: Bracketing phase already found a point satisfying the strong
- // Wolfe conditions, thus no Zoom required.
- //
- // Or: Bracketing failed to find a valid bracket or a point satisfying the
- // strong Wolfe conditions within max_num_iterations, or whilst searching
- // shrank the bracket width until it was below our minimum tolerance.
- // As these are 'artificial' constraints, and we would otherwise fail to
- // produce a valid point when ArmijoLineSearch would succeed, we return the
- // point with the lowest cost found thus far which satsifies the Armijo
- // condition (but not the Wolfe conditions).
- summary->optimal_step_size = bracket_low.x;
- summary->success = true;
- return;
- }
-
- VLOG(3) << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
- << "Starting line search zoom phase with bracket_low: "
- << bracket_low << ", bracket_high: " << bracket_high
- << ", bracket width: " << fabs(bracket_low.x - bracket_high.x)
- << ", bracket abs delta cost: "
- << fabs(bracket_low.value - bracket_high.value);
-
- // Wolfe Zoom phase: Called when the Bracketing phase finds an interval of
- // non-zero, finite width that should bracket step sizes which satisfy the
- // (strong) Wolfe conditions (before finding a step size that satisfies the
- // conditions). Zoom successively decreases the size of the interval until a
- // step size which satisfies the Wolfe conditions is found. The interval is
- // defined by bracket_low & bracket_high, which satisfy:
- //
- // 1. The interval bounded by step sizes: bracket_low.x & bracket_high.x
- // contains step sizes that satsify the strong Wolfe conditions.
- // 2. bracket_low.x is of all the step sizes evaluated *which satisifed the
- // Armijo sufficient decrease condition*, the one which generated the
- // smallest function value, i.e. bracket_low.value <
- // f(all other steps satisfying Armijo).
- // - Note that this does _not_ (necessarily) mean that initially
- // bracket_low.value < bracket_high.value (although this is typical)
- // e.g. when bracket_low = initial_position, and bracket_high is the
- // first sample, and which does not satisfy the Armijo condition,
- // but still has bracket_high.value < initial_position.value.
- // 3. bracket_high is chosen after bracket_low, s.t.
- // bracket_low.gradient * (bracket_high.x - bracket_low.x) < 0.
- if (!this->ZoomPhase(initial_position,
- bracket_low,
- bracket_high,
- &solution,
- summary) && !solution.value_is_valid) {
- // Failed to find a valid point (given the specified decrease parameters)
- // within the specified bracket.
- return;
- }
- // Ensure that if we ran out of iterations whilst zooming the bracket, or
- // shrank the bracket width to < tolerance and failed to find a point which
- // satisfies the strong Wolfe curvature condition, that we return the point
- // amongst those found thus far, which minimizes f() and satisfies the Armijo
- // condition.
- solution =
- solution.value_is_valid && solution.value <= bracket_low.value
- ? solution : bracket_low;
-
- summary->optimal_step_size = solution.x;
- summary->success = true;
-}
-
-// Returns true if either:
-//
-// A termination condition satisfying the (strong) Wolfe bracketing conditions
-// is found:
-//
-// - A valid point, defined as a bracket of zero width [zoom not required].
-// - A valid bracket (of width > tolerance), [zoom required].
-//
-// Or, searching was stopped due to an 'artificial' constraint, i.e. not
-// a condition imposed / required by the underlying algorithm, but instead an
-// engineering / implementation consideration. But a step which exceeds the
-// minimum step size, and satsifies the Armijo condition was still found,
-// and should thus be used [zoom not required].
-//
-// Returns false if no step size > minimum step size was found which
-// satisfies at least the Armijo condition.
-bool WolfeLineSearch::BracketingPhase(
- const FunctionSample& initial_position,
- const double step_size_estimate,
- FunctionSample* bracket_low,
- FunctionSample* bracket_high,
- bool* do_zoom_search,
- Summary* summary) {
- Function* function = options().function;
-
- FunctionSample previous = initial_position;
- FunctionSample current = ValueAndGradientSample(step_size_estimate, 0.0, 0.0);
- current.value_is_valid = false;
-
- const double descent_direction_max_norm =
- static_cast<const LineSearchFunction*>(function)->DirectionInfinityNorm();
-
- *do_zoom_search = false;
- *bracket_low = initial_position;
-
- // As we require the gradient to evaluate the Wolfe condition, we always
- // calculate it together with the value, irrespective of the interpolation
- // type. As opposed to only calculating the gradient after the Armijo
- // condition is satisifed, as the computational saving from this approach
- // would be slight (perhaps even negative due to the extra call). Also,
- // always calculating the value & gradient together protects against us
- // reporting invalid solutions if the cost function returns slightly different
- // function values when evaluated with / without gradients (due to numerical
- // issues).
- ++summary->num_function_evaluations;
- ++summary->num_gradient_evaluations;
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- &current.gradient);
- current.gradient_is_valid = current.value_is_valid;
-
- while (true) {
- ++summary->num_iterations;
-
- if (current.value_is_valid &&
- (current.value > (initial_position.value
- + options().sufficient_decrease
- * initial_position.gradient
- * current.x) ||
- (previous.value_is_valid && current.value > previous.value))) {
- // Bracket found: current step size violates Armijo sufficient decrease
- // condition, or has stepped past an inflection point of f() relative to
- // previous step size.
- *do_zoom_search = true;
- *bracket_low = previous;
- *bracket_high = current;
- VLOG(3) << std::scientific
- << std::setprecision(kErrorMessageNumericPrecision)
- << "Bracket found: current step (" << current.x
- << ") violates Armijo sufficient condition, or has passed an "
- << "inflection point of f() based on value.";
- break;
- }
-
- if (current.value_is_valid &&
- fabs(current.gradient) <=
- -options().sufficient_curvature_decrease * initial_position.gradient) {
- // Current step size satisfies the strong Wolfe conditions, and is thus a
- // valid termination point, therefore a Zoom not required.
- *bracket_low = current;
- *bracket_high = current;
- VLOG(3) << std::scientific
- << std::setprecision(kErrorMessageNumericPrecision)
- << "Bracketing phase found step size: " << current.x
- << ", satisfying strong Wolfe conditions, initial_position: "
- << initial_position << ", current: " << current;
- break;
-
- } else if (current.value_is_valid && current.gradient >= 0) {
- // Bracket found: current step size has stepped past an inflection point
- // of f(), but Armijo sufficient decrease is still satisfied and
- // f(current) is our best minimum thus far. Remember step size
- // monotonically increases, thus previous_step_size < current_step_size
- // even though f(previous) > f(current).
- *do_zoom_search = true;
- // Note inverse ordering from first bracket case.
- *bracket_low = current;
- *bracket_high = previous;
- VLOG(3) << "Bracket found: current step (" << current.x
- << ") satisfies Armijo, but has gradient >= 0, thus have passed "
- << "an inflection point of f().";
- break;
-
- } else if (current.value_is_valid &&
- fabs(current.x - previous.x) * descent_direction_max_norm
- < options().min_step_size) {
- // We have shrunk the search bracket to a width less than our tolerance,
- // and still not found either a point satisfying the strong Wolfe
- // conditions, or a valid bracket containing such a point. Stop searching
- // and set bracket_low to the size size amongst all those tested which
- // minimizes f() and satisfies the Armijo condition.
- LOG_IF(WARNING, !options().is_silent)
- << "Line search failed: Wolfe bracketing phase shrank "
- << "bracket width: " << fabs(current.x - previous.x)
- << ", to < tolerance: " << options().min_step_size
- << ", with descent_direction_max_norm: "
- << descent_direction_max_norm << ", and failed to find "
- << "a point satisfying the strong Wolfe conditions or a "
- << "bracketing containing such a point. Accepting "
- << "point found satisfying Armijo condition only, to "
- << "allow continuation.";
- *bracket_low = current;
- break;
-
- } else if (summary->num_iterations >= options().max_num_iterations) {
- // Check num iterations bound here so that we always evaluate the
- // max_num_iterations-th iteration against all conditions, and
- // then perform no additional (unused) evaluations.
- summary->error =
- StringPrintf("Line search failed: Wolfe bracketing phase failed to "
- "find a point satisfying strong Wolfe conditions, or a "
- "bracket containing such a point within specified "
- "max_num_iterations: %d", options().max_num_iterations);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- // Ensure that bracket_low is always set to the step size amongst all
- // those tested which minimizes f() and satisfies the Armijo condition
- // when we terminate due to the 'artificial' max_num_iterations condition.
- *bracket_low =
- current.value_is_valid && current.value < bracket_low->value
- ? current : *bracket_low;
- break;
- }
- // Either: f(current) is invalid; or, f(current) is valid, but does not
- // satisfy the strong Wolfe conditions itself, or the conditions for
- // being a boundary of a bracket.
-
- // If f(current) is valid, (but meets no criteria) expand the search by
- // increasing the step size.
- const double max_step_size =
- current.value_is_valid
- ? (current.x * options().max_step_expansion) : current.x;
-
- // We are performing 2-point interpolation only here, but the API of
- // InterpolatingPolynomialMinimizingStepSize() allows for up to
- // 3-point interpolation, so pad call with a sample with an invalid
- // value that will therefore be ignored.
- const FunctionSample unused_previous;
- DCHECK(!unused_previous.value_is_valid);
- // Contracts step size if f(current) is not valid.
- const double step_size =
- this->InterpolatingPolynomialMinimizingStepSize(
- options().interpolation_type,
- previous,
- unused_previous,
- current,
- previous.x,
- max_step_size);
- if (step_size * descent_direction_max_norm < options().min_step_size) {
- summary->error =
- StringPrintf("Line search failed: step_size too small: %.5e "
- "with descent_direction_max_norm: %.5e", step_size,
- descent_direction_max_norm);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- return false;
- }
-
- previous = current.value_is_valid ? current : previous;
- current.x = step_size;
-
- ++summary->num_function_evaluations;
- ++summary->num_gradient_evaluations;
- current.value_is_valid =
- function->Evaluate(current.x,
- &current.value,
- &current.gradient);
- current.gradient_is_valid = current.value_is_valid;
- }
-
- // Ensure that even if a valid bracket was found, we will only mark a zoom
- // as required if the bracket's width is greater than our minimum tolerance.
- if (*do_zoom_search &&
- fabs(bracket_high->x - bracket_low->x) * descent_direction_max_norm
- < options().min_step_size) {
- *do_zoom_search = false;
- }
-
- return true;
-}
-
-// Returns true iff solution satisfies the strong Wolfe conditions. Otherwise,
-// on return false, if we stopped searching due to the 'artificial' condition of
-// reaching max_num_iterations, solution is the step size amongst all those
-// tested, which satisfied the Armijo decrease condition and minimized f().
-bool WolfeLineSearch::ZoomPhase(const FunctionSample& initial_position,
- FunctionSample bracket_low,
- FunctionSample bracket_high,
- FunctionSample* solution,
- Summary* summary) {
- Function* function = options().function;
-
- CHECK(bracket_low.value_is_valid && bracket_low.gradient_is_valid)
- << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
- << "Ceres bug: f_low input to Wolfe Zoom invalid, please contact "
- << "the developers!, initial_position: " << initial_position
- << ", bracket_low: " << bracket_low
- << ", bracket_high: "<< bracket_high;
- // We do not require bracket_high.gradient_is_valid as the gradient condition
- // for a valid bracket is only dependent upon bracket_low.gradient, and
- // in order to minimize jacobian evaluations, bracket_high.gradient may
- // not have been calculated (if bracket_high.value does not satisfy the
- // Armijo sufficient decrease condition and interpolation method does not
- // require it).
- //
- // We also do not require that: bracket_low.value < bracket_high.value,
- // although this is typical. This is to deal with the case when
- // bracket_low = initial_position, bracket_high is the first sample,
- // and bracket_high does not satisfy the Armijo condition, but still has
- // bracket_high.value < initial_position.value.
- CHECK(bracket_high.value_is_valid)
- << std::scientific << std::setprecision(kErrorMessageNumericPrecision)
- << "Ceres bug: f_high input to Wolfe Zoom invalid, please "
- << "contact the developers!, initial_position: " << initial_position
- << ", bracket_low: " << bracket_low
- << ", bracket_high: "<< bracket_high;
-
- if (bracket_low.gradient * (bracket_high.x - bracket_low.x) >= 0) {
- // The third condition for a valid initial bracket:
- //
- // 3. bracket_high is chosen after bracket_low, s.t.
- // bracket_low.gradient * (bracket_high.x - bracket_low.x) < 0.
- //
- // is not satisfied. As this can happen when the users' cost function
- // returns inconsistent gradient values relative to the function values,
- // we do not CHECK_LT(), but we do stop processing and return an invalid
- // value.
- summary->error =
- StringPrintf("Line search failed: Wolfe zoom phase passed a bracket "
- "which does not satisfy: bracket_low.gradient * "
- "(bracket_high.x - bracket_low.x) < 0 [%.8e !< 0] "
- "with initial_position: %s, bracket_low: %s, bracket_high:"
- " %s, the most likely cause of which is the cost function "
- "returning inconsistent gradient & function values.",
- bracket_low.gradient * (bracket_high.x - bracket_low.x),
- initial_position.ToDebugString().c_str(),
- bracket_low.ToDebugString().c_str(),
- bracket_high.ToDebugString().c_str());
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- solution->value_is_valid = false;
- return false;
- }
-
- const int num_bracketing_iterations = summary->num_iterations;
- const double descent_direction_max_norm =
- static_cast<const LineSearchFunction*>(function)->DirectionInfinityNorm();
-
- while (true) {
- // Set solution to bracket_low, as it is our best step size (smallest f())
- // found thus far and satisfies the Armijo condition, even though it does
- // not satisfy the Wolfe condition.
- *solution = bracket_low;
- if (summary->num_iterations >= options().max_num_iterations) {
- summary->error =
- StringPrintf("Line search failed: Wolfe zoom phase failed to "
- "find a point satisfying strong Wolfe conditions "
- "within specified max_num_iterations: %d, "
- "(num iterations taken for bracketing: %d).",
- options().max_num_iterations, num_bracketing_iterations);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- return false;
- }
- if (fabs(bracket_high.x - bracket_low.x) * descent_direction_max_norm
- < options().min_step_size) {
- // Bracket width has been reduced below tolerance, and no point satisfying
- // the strong Wolfe conditions has been found.
- summary->error =
- StringPrintf("Line search failed: Wolfe zoom bracket width: %.5e "
- "too small with descent_direction_max_norm: %.5e.",
- fabs(bracket_high.x - bracket_low.x),
- descent_direction_max_norm);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- return false;
- }
-
- ++summary->num_iterations;
- // Polynomial interpolation requires inputs ordered according to step size,
- // not f(step size).
- const FunctionSample& lower_bound_step =
- bracket_low.x < bracket_high.x ? bracket_low : bracket_high;
- const FunctionSample& upper_bound_step =
- bracket_low.x < bracket_high.x ? bracket_high : bracket_low;
- // We are performing 2-point interpolation only here, but the API of
- // InterpolatingPolynomialMinimizingStepSize() allows for up to
- // 3-point interpolation, so pad call with a sample with an invalid
- // value that will therefore be ignored.
- const FunctionSample unused_previous;
- DCHECK(!unused_previous.value_is_valid);
- solution->x =
- this->InterpolatingPolynomialMinimizingStepSize(
- options().interpolation_type,
- lower_bound_step,
- unused_previous,
- upper_bound_step,
- lower_bound_step.x,
- upper_bound_step.x);
- // No check on magnitude of step size being too small here as it is
- // lower-bounded by the initial bracket start point, which was valid.
- //
- // As we require the gradient to evaluate the Wolfe condition, we always
- // calculate it together with the value, irrespective of the interpolation
- // type. As opposed to only calculating the gradient after the Armijo
- // condition is satisifed, as the computational saving from this approach
- // would be slight (perhaps even negative due to the extra call). Also,
- // always calculating the value & gradient together protects against us
- // reporting invalid solutions if the cost function returns slightly
- // different function values when evaluated with / without gradients (due
- // to numerical issues).
- ++summary->num_function_evaluations;
- ++summary->num_gradient_evaluations;
- solution->value_is_valid =
- function->Evaluate(solution->x,
- &solution->value,
- &solution->gradient);
- solution->gradient_is_valid = solution->value_is_valid;
- if (!solution->value_is_valid) {
- summary->error =
- StringPrintf("Line search failed: Wolfe Zoom phase found "
- "step_size: %.5e, for which function is invalid, "
- "between low_step: %.5e and high_step: %.5e "
- "at which function is valid.",
- solution->x, bracket_low.x, bracket_high.x);
- LOG_IF(WARNING, !options().is_silent) << summary->error;
- return false;
- }
-
- VLOG(3) << "Zoom iteration: "
- << summary->num_iterations - num_bracketing_iterations
- << ", bracket_low: " << bracket_low
- << ", bracket_high: " << bracket_high
- << ", minimizing solution: " << *solution;
-
- if ((solution->value > (initial_position.value
- + options().sufficient_decrease
- * initial_position.gradient
- * solution->x)) ||
- (solution->value >= bracket_low.value)) {
- // Armijo sufficient decrease not satisfied, or not better
- // than current lowest sample, use as new upper bound.
- bracket_high = *solution;
- continue;
- }
-
- // Armijo sufficient decrease satisfied, check strong Wolfe condition.
- if (fabs(solution->gradient) <=
- -options().sufficient_curvature_decrease * initial_position.gradient) {
- // Found a valid termination point satisfying strong Wolfe conditions.
- VLOG(3) << std::scientific
- << std::setprecision(kErrorMessageNumericPrecision)
- << "Zoom phase found step size: " << solution->x
- << ", satisfying strong Wolfe conditions.";
- break;
-
- } else if (solution->gradient * (bracket_high.x - bracket_low.x) >= 0) {
- bracket_high = bracket_low;
- }
-
- bracket_low = *solution;
- }
- // Solution contains a valid point which satisfies the strong Wolfe
- // conditions.
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.h b/extern/libmv/third_party/ceres/internal/ceres/line_search.h
deleted file mode 100644
index 97b9bc68cfe..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search.h
+++ /dev/null
@@ -1,299 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Interface for and implementation of various Line search algorithms.
-
-#ifndef CERES_INTERNAL_LINE_SEARCH_H_
-#define CERES_INTERNAL_LINE_SEARCH_H_
-
-#include <string>
-#include <vector>
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class Evaluator;
-struct FunctionSample;
-
-// Line search is another name for a one dimensional optimization
-// algorithm. The name "line search" comes from the fact one
-// dimensional optimization problems that arise as subproblems of
-// general multidimensional optimization problems.
-//
-// While finding the exact minimum of a one dimensionl function is
-// hard, instances of LineSearch find a point that satisfies a
-// sufficient decrease condition. Depending on the particular
-// condition used, we get a variety of different line search
-// algorithms, e.g., Armijo, Wolfe etc.
-class LineSearch {
- public:
- class Function;
-
- struct Options {
- Options()
- : interpolation_type(CUBIC),
- sufficient_decrease(1e-4),
- max_step_contraction(1e-3),
- min_step_contraction(0.9),
- min_step_size(1e-9),
- max_num_iterations(20),
- sufficient_curvature_decrease(0.9),
- max_step_expansion(10.0),
- is_silent(false),
- function(NULL) {}
-
- // Degree of the polynomial used to approximate the objective
- // function.
- LineSearchInterpolationType interpolation_type;
-
- // Armijo and Wolfe line search parameters.
-
- // Solving the line search problem exactly is computationally
- // prohibitive. Fortunately, line search based optimization
- // algorithms can still guarantee convergence if instead of an
- // exact solution, the line search algorithm returns a solution
- // which decreases the value of the objective function
- // sufficiently. More precisely, we are looking for a step_size
- // s.t.
- //
- // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
- double sufficient_decrease;
-
- // In each iteration of the Armijo / Wolfe line search,
- //
- // new_step_size >= max_step_contraction * step_size
- //
- // Note that by definition, for contraction:
- //
- // 0 < max_step_contraction < min_step_contraction < 1
- //
- double max_step_contraction;
-
- // In each iteration of the Armijo / Wolfe line search,
- //
- // new_step_size <= min_step_contraction * step_size
- // Note that by definition, for contraction:
- //
- // 0 < max_step_contraction < min_step_contraction < 1
- //
- double min_step_contraction;
-
- // If during the line search, the step_size falls below this
- // value, it is truncated to zero.
- double min_step_size;
-
- // Maximum number of trial step size iterations during each line search,
- // if a step size satisfying the search conditions cannot be found within
- // this number of trials, the line search will terminate.
- int max_num_iterations;
-
- // Wolfe-specific line search parameters.
-
- // The strong Wolfe conditions consist of the Armijo sufficient
- // decrease condition, and an additional requirement that the
- // step-size be chosen s.t. the _magnitude_ ('strong' Wolfe
- // conditions) of the gradient along the search direction
- // decreases sufficiently. Precisely, this second condition
- // is that we seek a step_size s.t.
- //
- // |f'(step_size)| <= sufficient_curvature_decrease * |f'(0)|
- //
- // Where f() is the line search objective and f'() is the derivative
- // of f w.r.t step_size (d f / d step_size).
- double sufficient_curvature_decrease;
-
- // During the bracketing phase of the Wolfe search, the step size is
- // increased until either a point satisfying the Wolfe conditions is
- // found, or an upper bound for a bracket containing a point satisfying
- // the conditions is found. Precisely, at each iteration of the
- // expansion:
- //
- // new_step_size <= max_step_expansion * step_size.
- //
- // By definition for expansion, max_step_expansion > 1.0.
- double max_step_expansion;
-
- bool is_silent;
-
- // The one dimensional function that the line search algorithm
- // minimizes.
- Function* function;
- };
-
- // An object used by the line search to access the function values
- // and gradient of the one dimensional function being optimized.
- //
- // In practice, this object will provide access to the objective
- // function value and the directional derivative of the underlying
- // optimization problem along a specific search direction.
- //
- // See LineSearchFunction for an example implementation.
- class Function {
- public:
- virtual ~Function() {}
- // Evaluate the line search objective
- //
- // f(x) = p(position + x * direction)
- //
- // Where, p is the objective function of the general optimization
- // problem.
- //
- // g is the gradient f'(x) at x.
- //
- // f must not be null. The gradient is computed only if g is not null.
- virtual bool Evaluate(double x, double* f, double* g) = 0;
- };
-
- // Result of the line search.
- struct Summary {
- Summary()
- : success(false),
- optimal_step_size(0.0),
- num_function_evaluations(0),
- num_gradient_evaluations(0),
- num_iterations(0) {}
-
- bool success;
- double optimal_step_size;
- int num_function_evaluations;
- int num_gradient_evaluations;
- int num_iterations;
- string error;
- };
-
- explicit LineSearch(const LineSearch::Options& options);
- virtual ~LineSearch() {}
-
- static LineSearch* Create(const LineSearchType line_search_type,
- const LineSearch::Options& options,
- string* error);
-
- // Perform the line search.
- //
- // step_size_estimate must be a positive number.
- //
- // initial_cost and initial_gradient are the values and gradient of
- // the function at zero.
- // summary must not be null and will contain the result of the line
- // search.
- //
- // Summary::success is true if a non-zero step size is found.
- virtual void Search(double step_size_estimate,
- double initial_cost,
- double initial_gradient,
- Summary* summary) = 0;
- double InterpolatingPolynomialMinimizingStepSize(
- const LineSearchInterpolationType& interpolation_type,
- const FunctionSample& lowerbound_sample,
- const FunctionSample& previous_sample,
- const FunctionSample& current_sample,
- const double min_step_size,
- const double max_step_size) const;
-
- protected:
- const LineSearch::Options& options() const { return options_; }
-
- private:
- LineSearch::Options options_;
-};
-
-class LineSearchFunction : public LineSearch::Function {
- public:
- explicit LineSearchFunction(Evaluator* evaluator);
- virtual ~LineSearchFunction() {}
- void Init(const Vector& position, const Vector& direction);
- virtual bool Evaluate(double x, double* f, double* g);
- double DirectionInfinityNorm() const;
-
- private:
- Evaluator* evaluator_;
- Vector position_;
- Vector direction_;
-
- // evaluation_point = Evaluator::Plus(position_, x * direction_);
- Vector evaluation_point_;
-
- // scaled_direction = x * direction_;
- Vector scaled_direction_;
- Vector gradient_;
-};
-
-// Backtracking and interpolation based Armijo line search. This
-// implementation is based on the Armijo line search that ships in the
-// minFunc package by Mark Schmidt.
-//
-// For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html
-class ArmijoLineSearch : public LineSearch {
- public:
- explicit ArmijoLineSearch(const LineSearch::Options& options);
- virtual ~ArmijoLineSearch() {}
- virtual void Search(double step_size_estimate,
- double initial_cost,
- double initial_gradient,
- Summary* summary);
-};
-
-// Bracketing / Zoom Strong Wolfe condition line search. This implementation
-// is based on the pseudo-code algorithm presented in Nocedal & Wright [1]
-// (p60-61) with inspiration from the WolfeLineSearch which ships with the
-// minFunc package by Mark Schmidt [2].
-//
-// [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed., Springer, 1999.
-// [2] http://www.di.ens.fr/~mschmidt/Software/minFunc.html.
-class WolfeLineSearch : public LineSearch {
- public:
- explicit WolfeLineSearch(const LineSearch::Options& options);
- virtual ~WolfeLineSearch() {}
- virtual void Search(double step_size_estimate,
- double initial_cost,
- double initial_gradient,
- Summary* summary);
- // Returns true iff either a valid point, or valid bracket are found.
- bool BracketingPhase(const FunctionSample& initial_position,
- const double step_size_estimate,
- FunctionSample* bracket_low,
- FunctionSample* bracket_high,
- bool* perform_zoom_search,
- Summary* summary);
- // Returns true iff final_line_sample satisfies strong Wolfe conditions.
- bool ZoomPhase(const FunctionSample& initial_position,
- FunctionSample bracket_low,
- FunctionSample bracket_high,
- FunctionSample* solution,
- Summary* summary);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINE_SEARCH_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc
deleted file mode 100644
index dddcecdb196..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc
+++ /dev/null
@@ -1,372 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/line_search_direction.h"
-#include "ceres/line_search_minimizer.h"
-#include "ceres/low_rank_inverse_hessian.h"
-#include "ceres/internal/eigen.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-class SteepestDescent : public LineSearchDirection {
- public:
- virtual ~SteepestDescent() {}
- bool NextDirection(const LineSearchMinimizer::State& previous,
- const LineSearchMinimizer::State& current,
- Vector* search_direction) {
- *search_direction = -current.gradient;
- return true;
- }
-};
-
-class NonlinearConjugateGradient : public LineSearchDirection {
- public:
- NonlinearConjugateGradient(const NonlinearConjugateGradientType type,
- const double function_tolerance)
- : type_(type),
- function_tolerance_(function_tolerance) {
- }
-
- bool NextDirection(const LineSearchMinimizer::State& previous,
- const LineSearchMinimizer::State& current,
- Vector* search_direction) {
- double beta = 0.0;
- Vector gradient_change;
- switch (type_) {
- case FLETCHER_REEVES:
- beta = current.gradient_squared_norm / previous.gradient_squared_norm;
- break;
- case POLAK_RIBIERE:
- gradient_change = current.gradient - previous.gradient;
- beta = (current.gradient.dot(gradient_change) /
- previous.gradient_squared_norm);
- break;
- case HESTENES_STIEFEL:
- gradient_change = current.gradient - previous.gradient;
- beta = (current.gradient.dot(gradient_change) /
- previous.search_direction.dot(gradient_change));
- break;
- default:
- LOG(FATAL) << "Unknown nonlinear conjugate gradient type: " << type_;
- }
-
- *search_direction = -current.gradient + beta * previous.search_direction;
- const double directional_derivative =
- current.gradient.dot(*search_direction);
- if (directional_derivative > -function_tolerance_) {
- LOG(WARNING) << "Restarting non-linear conjugate gradients: "
- << directional_derivative;
- *search_direction = -current.gradient;
- };
-
- return true;
- }
-
- private:
- const NonlinearConjugateGradientType type_;
- const double function_tolerance_;
-};
-
-class LBFGS : public LineSearchDirection {
- public:
- LBFGS(const int num_parameters,
- const int max_lbfgs_rank,
- const bool use_approximate_eigenvalue_bfgs_scaling)
- : low_rank_inverse_hessian_(num_parameters,
- max_lbfgs_rank,
- use_approximate_eigenvalue_bfgs_scaling),
- is_positive_definite_(true) {}
-
- virtual ~LBFGS() {}
-
- bool NextDirection(const LineSearchMinimizer::State& previous,
- const LineSearchMinimizer::State& current,
- Vector* search_direction) {
- CHECK(is_positive_definite_)
- << "Ceres bug: NextDirection() called on L-BFGS after inverse Hessian "
- << "approximation has become indefinite, please contact the "
- << "developers!";
-
- low_rank_inverse_hessian_.Update(
- previous.search_direction * previous.step_size,
- current.gradient - previous.gradient);
-
- search_direction->setZero();
- low_rank_inverse_hessian_.RightMultiply(current.gradient.data(),
- search_direction->data());
- *search_direction *= -1.0;
-
- if (search_direction->dot(current.gradient) >= 0.0) {
- LOG(WARNING) << "Numerical failure in L-BFGS update: inverse Hessian "
- << "approximation is not positive definite, and thus "
- << "initial gradient for search direction is positive: "
- << search_direction->dot(current.gradient);
- is_positive_definite_ = false;
- return false;
- }
-
- return true;
- }
-
- private:
- LowRankInverseHessian low_rank_inverse_hessian_;
- bool is_positive_definite_;
-};
-
-class BFGS : public LineSearchDirection {
- public:
- BFGS(const int num_parameters,
- const bool use_approximate_eigenvalue_scaling)
- : num_parameters_(num_parameters),
- use_approximate_eigenvalue_scaling_(use_approximate_eigenvalue_scaling),
- initialized_(false),
- is_positive_definite_(true) {
- LOG_IF(WARNING, num_parameters_ >= 1e3)
- << "BFGS line search being created with: " << num_parameters_
- << " parameters, this will allocate a dense approximate inverse Hessian"
- << " of size: " << num_parameters_ << " x " << num_parameters_
- << ", consider using the L-BFGS memory-efficient line search direction "
- << "instead.";
- // Construct inverse_hessian_ after logging warning about size s.t. if the
- // allocation crashes us, the log will highlight what the issue likely was.
- inverse_hessian_ = Matrix::Identity(num_parameters, num_parameters);
- }
-
- virtual ~BFGS() {}
-
- bool NextDirection(const LineSearchMinimizer::State& previous,
- const LineSearchMinimizer::State& current,
- Vector* search_direction) {
- CHECK(is_positive_definite_)
- << "Ceres bug: NextDirection() called on BFGS after inverse Hessian "
- << "approximation has become indefinite, please contact the "
- << "developers!";
-
- const Vector delta_x = previous.search_direction * previous.step_size;
- const Vector delta_gradient = current.gradient - previous.gradient;
- const double delta_x_dot_delta_gradient = delta_x.dot(delta_gradient);
-
- // The (L)BFGS algorithm explicitly requires that the secant equation:
- //
- // B_{k+1} * s_k = y_k
- //
- // Is satisfied at each iteration, where B_{k+1} is the approximated
- // Hessian at the k+1-th iteration, s_k = (x_{k+1} - x_{k}) and
- // y_k = (grad_{k+1} - grad_{k}). As the approximated Hessian must be
- // positive definite, this is equivalent to the condition:
- //
- // s_k^T * y_k > 0 [s_k^T * B_{k+1} * s_k = s_k^T * y_k > 0]
- //
- // This condition would always be satisfied if the function was strictly
- // convex, alternatively, it is always satisfied provided that a Wolfe line
- // search is used (even if the function is not strictly convex). See [1]
- // (p138) for a proof.
- //
- // Although Ceres will always use a Wolfe line search when using (L)BFGS,
- // practical implementation considerations mean that the line search
- // may return a point that satisfies only the Armijo condition, and thus
- // could violate the Secant equation. As such, we will only use a step
- // to update the Hessian approximation if:
- //
- // s_k^T * y_k > tolerance
- //
- // It is important that tolerance is very small (and >=0), as otherwise we
- // might skip the update too often and fail to capture important curvature
- // information in the Hessian. For example going from 1e-10 -> 1e-14
- // improves the NIST benchmark score from 43/54 to 53/54.
- //
- // [1] Nocedal J, Wright S, Numerical Optimization, 2nd Ed. Springer, 1999.
- //
- // TODO(alexs.mac): Consider using Damped BFGS update instead of
- // skipping update.
- const double kBFGSSecantConditionHessianUpdateTolerance = 1e-14;
- if (delta_x_dot_delta_gradient <=
- kBFGSSecantConditionHessianUpdateTolerance) {
- VLOG(2) << "Skipping BFGS Update, delta_x_dot_delta_gradient too "
- << "small: " << delta_x_dot_delta_gradient << ", tolerance: "
- << kBFGSSecantConditionHessianUpdateTolerance
- << " (Secant condition).";
- } else {
- // Update dense inverse Hessian approximation.
-
- if (!initialized_ && use_approximate_eigenvalue_scaling_) {
- // Rescale the initial inverse Hessian approximation (H_0) to be
- // iteratively updated so that it is of similar 'size' to the true
- // inverse Hessian at the start point. As shown in [1]:
- //
- // \gamma = (delta_gradient_{0}' * delta_x_{0}) /
- // (delta_gradient_{0}' * delta_gradient_{0})
- //
- // Satisfies:
- //
- // (1 / \lambda_m) <= \gamma <= (1 / \lambda_1)
- //
- // Where \lambda_1 & \lambda_m are the smallest and largest eigenvalues
- // of the true initial Hessian (not the inverse) respectively. Thus,
- // \gamma is an approximate eigenvalue of the true inverse Hessian, and
- // choosing: H_0 = I * \gamma will yield a starting point that has a
- // similar scale to the true inverse Hessian. This technique is widely
- // reported to often improve convergence, however this is not
- // universally true, particularly if there are errors in the initial
- // gradients, or if there are significant differences in the sensitivity
- // of the problem to the parameters (i.e. the range of the magnitudes of
- // the components of the gradient is large).
- //
- // The original origin of this rescaling trick is somewhat unclear, the
- // earliest reference appears to be Oren [1], however it is widely
- // discussed without specific attributation in various texts including
- // [2] (p143).
- //
- // [1] Oren S.S., Self-scaling variable metric (SSVM) algorithms
- // Part II: Implementation and experiments, Management Science,
- // 20(5), 863-874, 1974.
- // [2] Nocedal J., Wright S., Numerical Optimization, Springer, 1999.
- const double approximate_eigenvalue_scale =
- delta_x_dot_delta_gradient / delta_gradient.dot(delta_gradient);
- inverse_hessian_ *= approximate_eigenvalue_scale;
-
- VLOG(4) << "Applying approximate_eigenvalue_scale: "
- << approximate_eigenvalue_scale << " to initial inverse "
- << "Hessian approximation.";
- }
- initialized_ = true;
-
- // Efficient O(num_parameters^2) BFGS update [2].
- //
- // Starting from dense BFGS update detailed in Nocedal [2] p140/177 and
- // using: y_k = delta_gradient, s_k = delta_x:
- //
- // \rho_k = 1.0 / (s_k' * y_k)
- // V_k = I - \rho_k * y_k * s_k'
- // H_k = (V_k' * H_{k-1} * V_k) + (\rho_k * s_k * s_k')
- //
- // This update involves matrix, matrix products which naively O(N^3),
- // however we can exploit our knowledge that H_k is positive definite
- // and thus by defn. symmetric to reduce the cost of the update:
- //
- // Expanding the update above yields:
- //
- // H_k = H_{k-1} +
- // \rho_k * ( (1.0 + \rho_k * y_k' * H_k * y_k) * s_k * s_k' -
- // (s_k * y_k' * H_k + H_k * y_k * s_k') )
- //
- // Using: A = (s_k * y_k' * H_k), and the knowledge that H_k = H_k', the
- // last term simplifies to (A + A'). Note that although A is not symmetric
- // (A + A') is symmetric. For ease of construction we also define
- // B = (1 + \rho_k * y_k' * H_k * y_k) * s_k * s_k', which is by defn
- // symmetric due to construction from: s_k * s_k'.
- //
- // Now we can write the BFGS update as:
- //
- // H_k = H_{k-1} + \rho_k * (B - (A + A'))
-
- // For efficiency, as H_k is by defn. symmetric, we will only maintain the
- // *lower* triangle of H_k (and all intermediary terms).
-
- const double rho_k = 1.0 / delta_x_dot_delta_gradient;
-
- // Calculate: A = s_k * y_k' * H_k
- Matrix A = delta_x * (delta_gradient.transpose() *
- inverse_hessian_.selfadjointView<Eigen::Lower>());
-
- // Calculate scalar: (1 + \rho_k * y_k' * H_k * y_k)
- const double delta_x_times_delta_x_transpose_scale_factor =
- (1.0 + (rho_k * delta_gradient.transpose() *
- inverse_hessian_.selfadjointView<Eigen::Lower>() *
- delta_gradient));
- // Calculate: B = (1 + \rho_k * y_k' * H_k * y_k) * s_k * s_k'
- Matrix B = Matrix::Zero(num_parameters_, num_parameters_);
- B.selfadjointView<Eigen::Lower>().
- rankUpdate(delta_x, delta_x_times_delta_x_transpose_scale_factor);
-
- // Finally, update inverse Hessian approximation according to:
- // H_k = H_{k-1} + \rho_k * (B - (A + A')). Note that (A + A') is
- // symmetric, even though A is not.
- inverse_hessian_.triangularView<Eigen::Lower>() +=
- rho_k * (B - A - A.transpose());
- }
-
- *search_direction =
- inverse_hessian_.selfadjointView<Eigen::Lower>() *
- (-1.0 * current.gradient);
-
- if (search_direction->dot(current.gradient) >= 0.0) {
- LOG(WARNING) << "Numerical failure in BFGS update: inverse Hessian "
- << "approximation is not positive definite, and thus "
- << "initial gradient for search direction is positive: "
- << search_direction->dot(current.gradient);
- is_positive_definite_ = false;
- return false;
- }
-
- return true;
- }
-
- private:
- const int num_parameters_;
- const bool use_approximate_eigenvalue_scaling_;
- Matrix inverse_hessian_;
- bool initialized_;
- bool is_positive_definite_;
-};
-
-LineSearchDirection*
-LineSearchDirection::Create(const LineSearchDirection::Options& options) {
- if (options.type == STEEPEST_DESCENT) {
- return new SteepestDescent;
- }
-
- if (options.type == NONLINEAR_CONJUGATE_GRADIENT) {
- return new NonlinearConjugateGradient(
- options.nonlinear_conjugate_gradient_type,
- options.function_tolerance);
- }
-
- if (options.type == ceres::LBFGS) {
- return new ceres::internal::LBFGS(
- options.num_parameters,
- options.max_lbfgs_rank,
- options.use_approximate_eigenvalue_bfgs_scaling);
- }
-
- if (options.type == ceres::BFGS) {
- return new ceres::internal::BFGS(
- options.num_parameters,
- options.use_approximate_eigenvalue_bfgs_scaling);
- }
-
- LOG(ERROR) << "Unknown line search direction type: " << options.type;
- return NULL;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h
deleted file mode 100644
index c77fdc8e65b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
-#define CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
-
-#include "ceres/internal/eigen.h"
-#include "ceres/line_search_minimizer.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class LineSearchDirection {
- public:
- struct Options {
- Options()
- : num_parameters(0),
- type(LBFGS),
- nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
- function_tolerance(1e-12),
- max_lbfgs_rank(20),
- use_approximate_eigenvalue_bfgs_scaling(true) {
- }
-
- int num_parameters;
- LineSearchDirectionType type;
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
- double function_tolerance;
- int max_lbfgs_rank;
- bool use_approximate_eigenvalue_bfgs_scaling;
- };
-
- static LineSearchDirection* Create(const Options& options);
-
- virtual ~LineSearchDirection() {}
- virtual bool NextDirection(const LineSearchMinimizer::State& previous,
- const LineSearchMinimizer::State& current,
- Vector* search_direction) = 0;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc
deleted file mode 100644
index ad28ffb137d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc
+++ /dev/null
@@ -1,409 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Generic loop for line search based optimization algorithms.
-//
-// This is primarily inpsired by the minFunc packaged written by Mark
-// Schmidt.
-//
-// http://www.di.ens.fr/~mschmidt/Software/minFunc.html
-//
-// For details on the theory and implementation see "Numerical
-// Optimization" by Nocedal & Wright.
-
-#include "ceres/line_search_minimizer.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <cmath>
-#include <string>
-#include <vector>
-
-#include "Eigen/Dense"
-#include "ceres/array_utils.h"
-#include "ceres/evaluator.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/line_search.h"
-#include "ceres/line_search_direction.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-// TODO(sameeragarwal): I think there is a small bug here, in that if
-// the evaluation fails, then the state can contain garbage. Look at
-// this more carefully.
-bool Evaluate(Evaluator* evaluator,
- const Vector& x,
- LineSearchMinimizer::State* state,
- string* message) {
- if (!evaluator->Evaluate(x.data(),
- &(state->cost),
- NULL,
- state->gradient.data(),
- NULL)) {
- *message = "Gradient evaluation failed.";
- return false;
- }
-
- Vector negative_gradient = -state->gradient;
- Vector projected_gradient_step(x.size());
- if (!evaluator->Plus(x.data(),
- negative_gradient.data(),
- projected_gradient_step.data())) {
- *message = "projected_gradient_step = Plus(x, -gradient) failed.";
- return false;
- }
-
- state->gradient_squared_norm = (x - projected_gradient_step).squaredNorm();
- state->gradient_max_norm =
- (x - projected_gradient_step).lpNorm<Eigen::Infinity>();
- return true;
-}
-
-} // namespace
-
-void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary) {
- const bool is_not_silent = !options.is_silent;
- double start_time = WallTimeInSeconds();
- double iteration_start_time = start_time;
-
- Evaluator* evaluator = CHECK_NOTNULL(options.evaluator.get());
- const int num_parameters = evaluator->NumParameters();
- const int num_effective_parameters = evaluator->NumEffectiveParameters();
-
- summary->termination_type = NO_CONVERGENCE;
- summary->num_successful_steps = 0;
- summary->num_unsuccessful_steps = 0;
-
- VectorRef x(parameters, num_parameters);
-
- State current_state(num_parameters, num_effective_parameters);
- State previous_state(num_parameters, num_effective_parameters);
-
- Vector delta(num_effective_parameters);
- Vector x_plus_delta(num_parameters);
-
- IterationSummary iteration_summary;
- iteration_summary.iteration = 0;
- iteration_summary.step_is_valid = false;
- iteration_summary.step_is_successful = false;
- iteration_summary.cost_change = 0.0;
- iteration_summary.gradient_max_norm = 0.0;
- iteration_summary.gradient_norm = 0.0;
- iteration_summary.step_norm = 0.0;
- iteration_summary.linear_solver_iterations = 0;
- iteration_summary.step_solver_time_in_seconds = 0;
-
- // Do initial cost and Jacobian evaluation.
- if (!Evaluate(evaluator, x, &current_state, &summary->message)) {
- summary->termination_type = FAILURE;
- summary->message = "Initial cost and jacobian evaluation failed. "
- "More details: " + summary->message;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- summary->initial_cost = current_state.cost + summary->fixed_cost;
- iteration_summary.cost = current_state.cost + summary->fixed_cost;
-
- iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
- iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
-
- if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
- summary->message = StringPrintf("Gradient tolerance reached. "
- "Gradient max norm: %e <= %e",
- iteration_summary.gradient_max_norm,
- options.gradient_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- iteration_summary.iteration_time_in_seconds =
- WallTimeInSeconds() - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds =
- WallTimeInSeconds() - start_time
- + summary->preprocessor_time_in_seconds;
- summary->iterations.push_back(iteration_summary);
-
- LineSearchDirection::Options line_search_direction_options;
- line_search_direction_options.num_parameters = num_effective_parameters;
- line_search_direction_options.type = options.line_search_direction_type;
- line_search_direction_options.nonlinear_conjugate_gradient_type =
- options.nonlinear_conjugate_gradient_type;
- line_search_direction_options.max_lbfgs_rank = options.max_lbfgs_rank;
- line_search_direction_options.use_approximate_eigenvalue_bfgs_scaling =
- options.use_approximate_eigenvalue_bfgs_scaling;
- scoped_ptr<LineSearchDirection> line_search_direction(
- LineSearchDirection::Create(line_search_direction_options));
-
- LineSearchFunction line_search_function(evaluator);
-
- LineSearch::Options line_search_options;
- line_search_options.interpolation_type =
- options.line_search_interpolation_type;
- line_search_options.min_step_size = options.min_line_search_step_size;
- line_search_options.sufficient_decrease =
- options.line_search_sufficient_function_decrease;
- line_search_options.max_step_contraction =
- options.max_line_search_step_contraction;
- line_search_options.min_step_contraction =
- options.min_line_search_step_contraction;
- line_search_options.max_num_iterations =
- options.max_num_line_search_step_size_iterations;
- line_search_options.sufficient_curvature_decrease =
- options.line_search_sufficient_curvature_decrease;
- line_search_options.max_step_expansion =
- options.max_line_search_step_expansion;
- line_search_options.function = &line_search_function;
-
- scoped_ptr<LineSearch>
- line_search(LineSearch::Create(options.line_search_type,
- line_search_options,
- &summary->message));
- if (line_search.get() == NULL) {
- summary->termination_type = FAILURE;
- LOG_IF(ERROR, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- LineSearch::Summary line_search_summary;
- int num_line_search_direction_restarts = 0;
-
- while (true) {
- if (!RunCallbacks(options, iteration_summary, summary)) {
- break;
- }
-
- iteration_start_time = WallTimeInSeconds();
- if (iteration_summary.iteration >= options.max_num_iterations) {
- summary->message = "Maximum number of iterations reached.";
- summary->termination_type = NO_CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- break;
- }
-
- const double total_solver_time = iteration_start_time - start_time +
- summary->preprocessor_time_in_seconds;
- if (total_solver_time >= options.max_solver_time_in_seconds) {
- summary->message = "Maximum solver time reached.";
- summary->termination_type = NO_CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- break;
- }
-
- iteration_summary = IterationSummary();
- iteration_summary.iteration = summary->iterations.back().iteration + 1;
- iteration_summary.step_is_valid = false;
- iteration_summary.step_is_successful = false;
-
- bool line_search_status = true;
- if (iteration_summary.iteration == 1) {
- current_state.search_direction = -current_state.gradient;
- } else {
- line_search_status = line_search_direction->NextDirection(
- previous_state,
- current_state,
- &current_state.search_direction);
- }
-
- if (!line_search_status &&
- num_line_search_direction_restarts >=
- options.max_num_line_search_direction_restarts) {
- // Line search direction failed to generate a new direction, and we
- // have already reached our specified maximum number of restarts,
- // terminate optimization.
- summary->message =
- StringPrintf("Line search direction failure: specified "
- "max_num_line_search_direction_restarts: %d reached.",
- options.max_num_line_search_direction_restarts);
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- break;
- } else if (!line_search_status) {
- // Restart line search direction with gradient descent on first iteration
- // as we have not yet reached our maximum number of restarts.
- CHECK_LT(num_line_search_direction_restarts,
- options.max_num_line_search_direction_restarts);
-
- ++num_line_search_direction_restarts;
- LOG_IF(WARNING, is_not_silent)
- << "Line search direction algorithm: "
- << LineSearchDirectionTypeToString(
- options.line_search_direction_type)
- << ", failed to produce a valid new direction at "
- << "iteration: " << iteration_summary.iteration
- << ". Restarting, number of restarts: "
- << num_line_search_direction_restarts << " / "
- << options.max_num_line_search_direction_restarts
- << " [max].";
- line_search_direction.reset(
- LineSearchDirection::Create(line_search_direction_options));
- current_state.search_direction = -current_state.gradient;
- }
-
- line_search_function.Init(x, current_state.search_direction);
- current_state.directional_derivative =
- current_state.gradient.dot(current_state.search_direction);
-
- // TODO(sameeragarwal): Refactor this into its own object and add
- // explanations for the various choices.
- //
- // Note that we use !line_search_status to ensure that we treat cases when
- // we restarted the line search direction equivalently to the first
- // iteration.
- const double initial_step_size =
- (iteration_summary.iteration == 1 || !line_search_status)
- ? min(1.0, 1.0 / current_state.gradient_max_norm)
- : min(1.0, 2.0 * (current_state.cost - previous_state.cost) /
- current_state.directional_derivative);
- // By definition, we should only ever go forwards along the specified search
- // direction in a line search, most likely cause for this being violated
- // would be a numerical failure in the line search direction calculation.
- if (initial_step_size < 0.0) {
- summary->message =
- StringPrintf("Numerical failure in line search, initial_step_size is "
- "negative: %.5e, directional_derivative: %.5e, "
- "(current_cost - previous_cost): %.5e",
- initial_step_size, current_state.directional_derivative,
- (current_state.cost - previous_state.cost));
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- break;
- }
-
- line_search->Search(initial_step_size,
- current_state.cost,
- current_state.directional_derivative,
- &line_search_summary);
- if (!line_search_summary.success) {
- summary->message =
- StringPrintf("Numerical failure in line search, failed to find "
- "a valid step size, (did not run out of iterations) "
- "using initial_step_size: %.5e, initial_cost: %.5e, "
- "initial_gradient: %.5e.",
- initial_step_size, current_state.cost,
- current_state.directional_derivative);
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- summary->termination_type = FAILURE;
- break;
- }
-
- current_state.step_size = line_search_summary.optimal_step_size;
- delta = current_state.step_size * current_state.search_direction;
-
- previous_state = current_state;
- iteration_summary.step_solver_time_in_seconds =
- WallTimeInSeconds() - iteration_start_time;
-
- if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
- summary->termination_type = FAILURE;
- summary->message =
- "x_plus_delta = Plus(x, delta) failed. This should not happen "
- "as the step was valid when it was selected by the line search.";
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- break;
- } else if (!Evaluate(evaluator,
- x_plus_delta,
- &current_state,
- &summary->message)) {
- summary->termination_type = FAILURE;
- summary->message =
- "Step failed to evaluate. This should not happen as the step was "
- "valid when it was selected by the line search. More details: " +
- summary->message;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- break;
- } else {
- x = x_plus_delta;
- }
-
- iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
- iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm);
- iteration_summary.cost_change = previous_state.cost - current_state.cost;
- iteration_summary.cost = current_state.cost + summary->fixed_cost;
- iteration_summary.step_norm = delta.norm();
- iteration_summary.step_is_valid = true;
- iteration_summary.step_is_successful = true;
- iteration_summary.step_norm = delta.norm();
- iteration_summary.step_size = current_state.step_size;
- iteration_summary.line_search_function_evaluations =
- line_search_summary.num_function_evaluations;
- iteration_summary.line_search_gradient_evaluations =
- line_search_summary.num_gradient_evaluations;
- iteration_summary.line_search_iterations =
- line_search_summary.num_iterations;
- iteration_summary.iteration_time_in_seconds =
- WallTimeInSeconds() - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds =
- WallTimeInSeconds() - start_time
- + summary->preprocessor_time_in_seconds;
-
- ++summary->num_successful_steps;
-
- if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
- summary->message = StringPrintf("Gradient tolerance reached. "
- "Gradient max norm: %e <= %e",
- iteration_summary.gradient_max_norm,
- options.gradient_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- break;
- }
-
- const double absolute_function_tolerance =
- options.function_tolerance * previous_state.cost;
- if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
- summary->message =
- StringPrintf("Function tolerance reached. "
- "|cost_change|/cost: %e <= %e",
- fabs(iteration_summary.cost_change) /
- previous_state.cost,
- options.function_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- break;
- }
-
- summary->iterations.push_back(iteration_summary);
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h
deleted file mode 100644
index f82f13984a8..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
-#define CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
-
-#include "ceres/minimizer.h"
-#include "ceres/solver.h"
-#include "ceres/types.h"
-#include "ceres/internal/eigen.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// Generic line search minimization algorithm.
-//
-// For example usage, see SolverImpl::Minimize.
-class LineSearchMinimizer : public Minimizer {
- public:
- struct State {
- State(int num_parameters,
- int num_effective_parameters)
- : cost(0.0),
- gradient(num_effective_parameters),
- gradient_squared_norm(0.0),
- search_direction(num_effective_parameters),
- directional_derivative(0.0),
- step_size(0.0) {
- }
-
- double cost;
- Vector gradient;
- double gradient_squared_norm;
- double gradient_max_norm;
- Vector search_direction;
- double directional_derivative;
- double step_size;
- };
-
- ~LineSearchMinimizer() {}
- virtual void Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc
deleted file mode 100644
index bf17dee351d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/line_search_preprocessor.h"
-
-#include <numeric>
-#include <string>
-#include "ceres/evaluator.h"
-#include "ceres/minimizer.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-bool IsProgramValid(const Program& program, string* error) {
- if (program.IsBoundsConstrained()) {
- *error = "LINE_SEARCH Minimizer does not support bounds.";
- return false;
- }
- return program.ParameterBlocksAreFinite(error);
-}
-
-bool SetupEvaluator(PreprocessedProblem* pp) {
- pp->evaluator_options = Evaluator::Options();
- // This ensures that we get a Block Jacobian Evaluator without any
- // requirement on orderings.
- pp->evaluator_options.linear_solver_type = CGNR;
- pp->evaluator_options.num_eliminate_blocks = 0;
- pp->evaluator_options.num_threads = pp->options.num_threads;
- pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
- pp->reduced_program.get(),
- &pp->error));
- return (pp->evaluator.get() != NULL);
-}
-
-} // namespace
-
-LineSearchPreprocessor::~LineSearchPreprocessor() {
-}
-
-bool LineSearchPreprocessor::Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* pp) {
- CHECK_NOTNULL(pp);
- pp->options = options;
- ChangeNumThreadsIfNeeded(&pp->options);
-
- pp->problem = problem;
- Program* program = problem->mutable_program();
- if (!IsProgramValid(*program, &pp->error)) {
- return false;
- }
-
- pp->reduced_program.reset(
- program->CreateReducedProgram(&pp->removed_parameter_blocks,
- &pp->fixed_cost,
- &pp->error));
-
- if (pp->reduced_program.get() == NULL) {
- return false;
- }
-
- if (pp->reduced_program->NumParameterBlocks() == 0) {
- return true;
- }
-
- if (!SetupEvaluator(pp)) {
- return false;
- }
-
- SetupCommonMinimizerOptions(pp);
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h
deleted file mode 100644
index 54b968bc29e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/line_search_preprocessor.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
-#define CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
-
-#include "ceres/preprocessor.h"
-
-namespace ceres {
-namespace internal {
-
-class LineSearchPreprocessor : public Preprocessor {
- public:
- virtual ~LineSearchPreprocessor();
- virtual bool Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* preprocessed_problem);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
deleted file mode 100644
index 24ba565daf9..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
+++ /dev/null
@@ -1,628 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/linear_least_squares_problems.h"
-
-#include <cstdio>
-#include <string>
-#include <vector>
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/casts.h"
-#include "ceres/file.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/stringprintf.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id) {
- switch (id) {
- case 0:
- return LinearLeastSquaresProblem0();
- case 1:
- return LinearLeastSquaresProblem1();
- case 2:
- return LinearLeastSquaresProblem2();
- case 3:
- return LinearLeastSquaresProblem3();
- default:
- LOG(FATAL) << "Unknown problem id requested " << id;
- }
- return NULL;
-}
-
-/*
-A = [1 2]
- [3 4]
- [6 -10]
-
-b = [ 8
- 18
- -18]
-
-x = [2
- 3]
-
-D = [1
- 2]
-
-x_D = [1.78448275;
- 2.82327586;]
- */
-LinearLeastSquaresProblem* LinearLeastSquaresProblem0() {
- LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
-
- TripletSparseMatrix* A = new TripletSparseMatrix(3, 2, 6);
- problem->b.reset(new double[3]);
- problem->D.reset(new double[2]);
-
- problem->x.reset(new double[2]);
- problem->x_D.reset(new double[2]);
-
- int* Ai = A->mutable_rows();
- int* Aj = A->mutable_cols();
- double* Ax = A->mutable_values();
-
- int counter = 0;
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j< 2; ++j) {
- Ai[counter]=i;
- Aj[counter]=j;
- ++counter;
- }
- };
-
- Ax[0] = 1.;
- Ax[1] = 2.;
- Ax[2] = 3.;
- Ax[3] = 4.;
- Ax[4] = 6;
- Ax[5] = -10;
- A->set_num_nonzeros(6);
- problem->A.reset(A);
-
- problem->b[0] = 8;
- problem->b[1] = 18;
- problem->b[2] = -18;
-
- problem->x[0] = 2.0;
- problem->x[1] = 3.0;
-
- problem->D[0] = 1;
- problem->D[1] = 2;
-
- problem->x_D[0] = 1.78448275;
- problem->x_D[1] = 2.82327586;
- return problem;
-}
-
-
-/*
- A = [1 0 | 2 0 0
- 3 0 | 0 4 0
- 0 5 | 0 0 6
- 0 7 | 8 0 0
- 0 9 | 1 0 0
- 0 0 | 1 1 1]
-
- b = [0
- 1
- 2
- 3
- 4
- 5]
-
- c = A'* b = [ 3
- 67
- 33
- 9
- 17]
-
- A'A = [10 0 2 12 0
- 0 155 65 0 30
- 2 65 70 1 1
- 12 0 1 17 1
- 0 30 1 1 37]
-
- S = [ 42.3419 -1.4000 -11.5806
- -1.4000 2.6000 1.0000
- 11.5806 1.0000 31.1935]
-
- r = [ 4.3032
- 5.4000
- 5.0323]
-
- S\r = [ 0.2102
- 2.1367
- 0.1388]
-
- A\b = [-2.3061
- 0.3172
- 0.2102
- 2.1367
- 0.1388]
-*/
-// The following two functions create a TripletSparseMatrix and a
-// BlockSparseMatrix version of this problem.
-
-// TripletSparseMatrix version.
-LinearLeastSquaresProblem* LinearLeastSquaresProblem1() {
- int num_rows = 6;
- int num_cols = 5;
-
- LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
- TripletSparseMatrix* A = new TripletSparseMatrix(num_rows,
- num_cols,
- num_rows * num_cols);
- problem->b.reset(new double[num_rows]);
- problem->D.reset(new double[num_cols]);
- problem->num_eliminate_blocks = 2;
-
- int* rows = A->mutable_rows();
- int* cols = A->mutable_cols();
- double* values = A->mutable_values();
-
- int nnz = 0;
-
- // Row 1
- {
- rows[nnz] = 0;
- cols[nnz] = 0;
- values[nnz++] = 1;
-
- rows[nnz] = 0;
- cols[nnz] = 2;
- values[nnz++] = 2;
- }
-
- // Row 2
- {
- rows[nnz] = 1;
- cols[nnz] = 0;
- values[nnz++] = 3;
-
- rows[nnz] = 1;
- cols[nnz] = 3;
- values[nnz++] = 4;
- }
-
- // Row 3
- {
- rows[nnz] = 2;
- cols[nnz] = 1;
- values[nnz++] = 5;
-
- rows[nnz] = 2;
- cols[nnz] = 4;
- values[nnz++] = 6;
- }
-
- // Row 4
- {
- rows[nnz] = 3;
- cols[nnz] = 1;
- values[nnz++] = 7;
-
- rows[nnz] = 3;
- cols[nnz] = 2;
- values[nnz++] = 8;
- }
-
- // Row 5
- {
- rows[nnz] = 4;
- cols[nnz] = 1;
- values[nnz++] = 9;
-
- rows[nnz] = 4;
- cols[nnz] = 2;
- values[nnz++] = 1;
- }
-
- // Row 6
- {
- rows[nnz] = 5;
- cols[nnz] = 2;
- values[nnz++] = 1;
-
- rows[nnz] = 5;
- cols[nnz] = 3;
- values[nnz++] = 1;
-
- rows[nnz] = 5;
- cols[nnz] = 4;
- values[nnz++] = 1;
- }
-
- A->set_num_nonzeros(nnz);
- CHECK(A->IsValid());
-
- problem->A.reset(A);
-
- for (int i = 0; i < num_cols; ++i) {
- problem->D.get()[i] = 1;
- }
-
- for (int i = 0; i < num_rows; ++i) {
- problem->b.get()[i] = i;
- }
-
- return problem;
-}
-
-// BlockSparseMatrix version
-LinearLeastSquaresProblem* LinearLeastSquaresProblem2() {
- int num_rows = 6;
- int num_cols = 5;
-
- LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
-
- problem->b.reset(new double[num_rows]);
- problem->D.reset(new double[num_cols]);
- problem->num_eliminate_blocks = 2;
-
- CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
- scoped_array<double> values(new double[num_rows * num_cols]);
-
- for (int c = 0; c < num_cols; ++c) {
- bs->cols.push_back(Block());
- bs->cols.back().size = 1;
- bs->cols.back().position = c;
- }
-
- int nnz = 0;
-
- // Row 1
- {
- values[nnz++] = 1;
- values[nnz++] = 2;
-
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 0;
- row.cells.push_back(Cell(0, 0));
- row.cells.push_back(Cell(2, 1));
- }
-
- // Row 2
- {
- values[nnz++] = 3;
- values[nnz++] = 4;
-
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 1;
- row.cells.push_back(Cell(0, 2));
- row.cells.push_back(Cell(3, 3));
- }
-
- // Row 3
- {
- values[nnz++] = 5;
- values[nnz++] = 6;
-
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 2;
- row.cells.push_back(Cell(1, 4));
- row.cells.push_back(Cell(4, 5));
- }
-
- // Row 4
- {
- values[nnz++] = 7;
- values[nnz++] = 8;
-
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 3;
- row.cells.push_back(Cell(1, 6));
- row.cells.push_back(Cell(2, 7));
- }
-
- // Row 5
- {
- values[nnz++] = 9;
- values[nnz++] = 1;
-
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 4;
- row.cells.push_back(Cell(1, 8));
- row.cells.push_back(Cell(2, 9));
- }
-
- // Row 6
- {
- values[nnz++] = 1;
- values[nnz++] = 1;
- values[nnz++] = 1;
-
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 5;
- row.cells.push_back(Cell(2, 10));
- row.cells.push_back(Cell(3, 11));
- row.cells.push_back(Cell(4, 12));
- }
-
- BlockSparseMatrix* A = new BlockSparseMatrix(bs);
- memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
-
- for (int i = 0; i < num_cols; ++i) {
- problem->D.get()[i] = 1;
- }
-
- for (int i = 0; i < num_rows; ++i) {
- problem->b.get()[i] = i;
- }
-
- problem->A.reset(A);
-
- return problem;
-}
-
-
-/*
- A = [1 0
- 3 0
- 0 5
- 0 7
- 0 9
- 0 0]
-
- b = [0
- 1
- 2
- 3
- 4
- 5]
-*/
-// BlockSparseMatrix version
-LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
- int num_rows = 5;
- int num_cols = 2;
-
- LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
-
- problem->b.reset(new double[num_rows]);
- problem->D.reset(new double[num_cols]);
- problem->num_eliminate_blocks = 2;
-
- CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
- scoped_array<double> values(new double[num_rows * num_cols]);
-
- for (int c = 0; c < num_cols; ++c) {
- bs->cols.push_back(Block());
- bs->cols.back().size = 1;
- bs->cols.back().position = c;
- }
-
- int nnz = 0;
-
- // Row 1
- {
- values[nnz++] = 1;
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 0;
- row.cells.push_back(Cell(0, 0));
- }
-
- // Row 2
- {
- values[nnz++] = 3;
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 1;
- row.cells.push_back(Cell(0, 1));
- }
-
- // Row 3
- {
- values[nnz++] = 5;
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 2;
- row.cells.push_back(Cell(1, 2));
- }
-
- // Row 4
- {
- values[nnz++] = 7;
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 3;
- row.cells.push_back(Cell(1, 3));
- }
-
- // Row 5
- {
- values[nnz++] = 9;
- bs->rows.push_back(CompressedRow());
- CompressedRow& row = bs->rows.back();
- row.block.size = 1;
- row.block.position = 4;
- row.cells.push_back(Cell(1, 4));
- }
-
- BlockSparseMatrix* A = new BlockSparseMatrix(bs);
- memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
-
- for (int i = 0; i < num_cols; ++i) {
- problem->D.get()[i] = 1;
- }
-
- for (int i = 0; i < num_rows; ++i) {
- problem->b.get()[i] = i;
- }
-
- problem->A.reset(A);
-
- return problem;
-}
-
-namespace {
-bool DumpLinearLeastSquaresProblemToConsole(const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- Matrix AA;
- A->ToDenseMatrix(&AA);
- LOG(INFO) << "A^T: \n" << AA.transpose();
-
- if (D != NULL) {
- LOG(INFO) << "A's appended diagonal:\n"
- << ConstVectorRef(D, A->num_cols());
- }
-
- if (b != NULL) {
- LOG(INFO) << "b: \n" << ConstVectorRef(b, A->num_rows());
- }
-
- if (x != NULL) {
- LOG(INFO) << "x: \n" << ConstVectorRef(x, A->num_cols());
- }
- return true;
-};
-
-void WriteArrayToFileOrDie(const string& filename,
- const double* x,
- const int size) {
- CHECK_NOTNULL(x);
- VLOG(2) << "Writing array to: " << filename;
- FILE* fptr = fopen(filename.c_str(), "w");
- CHECK_NOTNULL(fptr);
- for (int i = 0; i < size; ++i) {
- fprintf(fptr, "%17f\n", x[i]);
- }
- fclose(fptr);
-}
-
-bool DumpLinearLeastSquaresProblemToTextFile(const string& filename_base,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- LOG(INFO) << "writing to: " << filename_base << "*";
-
- string matlab_script;
- StringAppendF(&matlab_script,
- "function lsqp = load_trust_region_problem()\n");
- StringAppendF(&matlab_script,
- "lsqp.num_rows = %d;\n", A->num_rows());
- StringAppendF(&matlab_script,
- "lsqp.num_cols = %d;\n", A->num_cols());
-
- {
- string filename = filename_base + "_A.txt";
- FILE* fptr = fopen(filename.c_str(), "w");
- CHECK_NOTNULL(fptr);
- A->ToTextFile(fptr);
- fclose(fptr);
- StringAppendF(&matlab_script,
- "tmp = load('%s', '-ascii');\n", filename.c_str());
- StringAppendF(
- &matlab_script,
- "lsqp.A = sparse(tmp(:, 1) + 1, tmp(:, 2) + 1, tmp(:, 3), %d, %d);\n",
- A->num_rows(),
- A->num_cols());
- }
-
-
- if (D != NULL) {
- string filename = filename_base + "_D.txt";
- WriteArrayToFileOrDie(filename, D, A->num_cols());
- StringAppendF(&matlab_script,
- "lsqp.D = load('%s', '-ascii');\n", filename.c_str());
- }
-
- if (b != NULL) {
- string filename = filename_base + "_b.txt";
- WriteArrayToFileOrDie(filename, b, A->num_rows());
- StringAppendF(&matlab_script,
- "lsqp.b = load('%s', '-ascii');\n", filename.c_str());
- }
-
- if (x != NULL) {
- string filename = filename_base + "_x.txt";
- WriteArrayToFileOrDie(filename, x, A->num_cols());
- StringAppendF(&matlab_script,
- "lsqp.x = load('%s', '-ascii');\n", filename.c_str());
- }
-
- string matlab_filename = filename_base + ".m";
- WriteStringToFileOrDie(matlab_script, matlab_filename);
- return true;
-}
-} // namespace
-
-bool DumpLinearLeastSquaresProblem(const string& filename_base,
- DumpFormatType dump_format_type,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
- switch (dump_format_type) {
- case CONSOLE:
- return DumpLinearLeastSquaresProblemToConsole(A, D, b, x,
- num_eliminate_blocks);
- case TEXTFILE:
- return DumpLinearLeastSquaresProblemToTextFile(filename_base,
- A, D, b, x,
- num_eliminate_blocks);
- default:
- LOG(FATAL) << "Unknown DumpFormatType " << dump_format_type;
- };
-
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h
deleted file mode 100644
index fdeed70de62..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
-#define CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
-
-#include <string>
-#include <vector>
-#include "ceres/sparse_matrix.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-namespace internal {
-
-// Structure defining a linear least squares problem and if possible
-// ground truth solutions. To be used by various LinearSolver tests.
-struct LinearLeastSquaresProblem {
- LinearLeastSquaresProblem()
- : A(NULL), b(NULL), D(NULL), num_eliminate_blocks(0),
- x(NULL), x_D(NULL) {
- }
-
- scoped_ptr<SparseMatrix> A;
- scoped_array<double> b;
- scoped_array<double> D;
- // If using the schur eliminator then how many of the variable
- // blocks are e_type blocks.
- int num_eliminate_blocks;
-
- // Solution to min_x |Ax - b|^2
- scoped_array<double> x;
- // Solution to min_x |Ax - b|^2 + |Dx|^2
- scoped_array<double> x_D;
-};
-
-// Factories for linear least squares problem.
-LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id);
-
-LinearLeastSquaresProblem* LinearLeastSquaresProblem0();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem1();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem2();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem3();
-
-// Write the linear least squares problem to disk. The exact format
-// depends on dump_format_type.
-bool DumpLinearLeastSquaresProblem(const string& filename_base,
- DumpFormatType dump_format_type,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks);
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_operator.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_operator.cc
deleted file mode 100644
index 4b59fa13009..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_operator.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/linear_operator.h"
-
-namespace ceres {
-namespace internal {
-
-LinearOperator::~LinearOperator() {
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_operator.h b/extern/libmv/third_party/ceres/internal/ceres/linear_operator.h
deleted file mode 100644
index d5c15cee6a9..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_operator.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Base classes for access to an linear operator.
-
-#ifndef CERES_INTERNAL_LINEAR_OPERATOR_H_
-#define CERES_INTERNAL_LINEAR_OPERATOR_H_
-
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-// This is an abstract base class for linear operators. It supports
-// access to size information and left and right multiply operators.
-class LinearOperator {
- public:
- virtual ~LinearOperator();
-
- // y = y + Ax;
- virtual void RightMultiply(const double* x, double* y) const = 0;
- // y = y + A'x;
- virtual void LeftMultiply(const double* x, double* y) const = 0;
-
- virtual int num_rows() const = 0;
- virtual int num_cols() const = 0;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINEAR_OPERATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc
deleted file mode 100644
index e479b751363..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/linear_solver.h"
-
-#include "ceres/cgnr_solver.h"
-#include "ceres/dense_normal_cholesky_solver.h"
-#include "ceres/dense_qr_solver.h"
-#include "ceres/iterative_schur_complement_solver.h"
-#include "ceres/schur_complement_solver.h"
-#include "ceres/sparse_normal_cholesky_solver.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-LinearSolver::~LinearSolver() {
-}
-
-LinearSolverType LinearSolver::LinearSolverForZeroEBlocks(
- LinearSolverType linear_solver_type) {
- if (!IsSchurType(linear_solver_type)) {
- return linear_solver_type;
- }
-
- if (linear_solver_type == SPARSE_SCHUR) {
- return SPARSE_NORMAL_CHOLESKY;
- }
-
- if (linear_solver_type == DENSE_SCHUR) {
- // TODO(sameeragarwal): This is probably not a great choice.
- // Ideally, we should have a DENSE_NORMAL_CHOLESKY, that can take
- // a BlockSparseMatrix as input.
- return DENSE_QR;
- }
-
- if (linear_solver_type == ITERATIVE_SCHUR) {
- return CGNR;
- }
-
- return linear_solver_type;
-}
-
-LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) {
- switch (options.type) {
- case CGNR:
- return new CgnrSolver(options);
-
- case SPARSE_NORMAL_CHOLESKY:
-#if defined(CERES_NO_SUITESPARSE) && \
- defined(CERES_NO_CXSPARSE) && \
- !defined(CERES_USE_EIGEN_SPARSE)
- return NULL;
-#else
- return new SparseNormalCholeskySolver(options);
-#endif
-
- case SPARSE_SCHUR:
-#if defined(CERES_NO_SUITESPARSE) && \
- defined(CERES_NO_CXSPARSE) && \
- !defined(CERES_USE_EIGEN_SPARSE)
- return NULL;
-#else
- return new SparseSchurComplementSolver(options);
-#endif
-
- case DENSE_SCHUR:
- return new DenseSchurComplementSolver(options);
-
- case ITERATIVE_SCHUR:
- if (options.use_explicit_schur_complement) {
- return new SparseSchurComplementSolver(options);
- } else {
- return new IterativeSchurComplementSolver(options);
- }
-
- case DENSE_QR:
- return new DenseQRSolver(options);
-
- case DENSE_NORMAL_CHOLESKY:
- return new DenseNormalCholeskySolver(options);
-
- default:
- LOG(FATAL) << "Unknown linear solver type :"
- << options.type;
- return NULL; // MSVC doesn't understand that LOG(FATAL) never returns.
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
deleted file mode 100644
index 5f59765f074..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
+++ /dev/null
@@ -1,362 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Abstract interface for objects solving linear systems of various
-// kinds.
-
-#ifndef CERES_INTERNAL_LINEAR_SOLVER_H_
-#define CERES_INTERNAL_LINEAR_SOLVER_H_
-
-#include <cstddef>
-#include <map>
-#include <string>
-#include <vector>
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/casts.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/dense_sparse_matrix.h"
-#include "ceres/execution_summary.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-enum LinearSolverTerminationType {
- // Termination criterion was met.
- LINEAR_SOLVER_SUCCESS,
-
- // Solver ran for max_num_iterations and terminated before the
- // termination tolerance could be satisfied.
- LINEAR_SOLVER_NO_CONVERGENCE,
-
- // Solver was terminated due to numerical problems, generally due to
- // the linear system being poorly conditioned.
- LINEAR_SOLVER_FAILURE,
-
- // Solver failed with a fatal error that cannot be recovered from,
- // e.g. CHOLMOD ran out of memory when computing the symbolic or
- // numeric factorization or an underlying library was called with
- // the wrong arguments.
- LINEAR_SOLVER_FATAL_ERROR
-};
-
-
-class LinearOperator;
-
-// Abstract base class for objects that implement algorithms for
-// solving linear systems
-//
-// Ax = b
-//
-// It is expected that a single instance of a LinearSolver object
-// maybe used multiple times for solving multiple linear systems with
-// the same sparsity structure. This allows them to cache and reuse
-// information across solves. This means that calling Solve on the
-// same LinearSolver instance with two different linear systems will
-// result in undefined behaviour.
-//
-// Subclasses of LinearSolver use two structs to configure themselves.
-// The Options struct configures the LinearSolver object for its
-// lifetime. The PerSolveOptions struct is used to specify options for
-// a particular Solve call.
-class LinearSolver {
- public:
- struct Options {
- Options()
- : type(SPARSE_NORMAL_CHOLESKY),
- preconditioner_type(JACOBI),
- visibility_clustering_type(CANONICAL_VIEWS),
- dense_linear_algebra_library_type(EIGEN),
- sparse_linear_algebra_library_type(SUITE_SPARSE),
- use_postordering(false),
- dynamic_sparsity(false),
- use_explicit_schur_complement(false),
- min_num_iterations(1),
- max_num_iterations(1),
- num_threads(1),
- residual_reset_period(10),
- row_block_size(Eigen::Dynamic),
- e_block_size(Eigen::Dynamic),
- f_block_size(Eigen::Dynamic) {
- }
-
- LinearSolverType type;
- PreconditionerType preconditioner_type;
- VisibilityClusteringType visibility_clustering_type;
- DenseLinearAlgebraLibraryType dense_linear_algebra_library_type;
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
-
- // See solver.h for information about these flags.
- bool use_postordering;
- bool dynamic_sparsity;
- bool use_explicit_schur_complement;
-
- // Number of internal iterations that the solver uses. This
- // parameter only makes sense for iterative solvers like CG.
- int min_num_iterations;
- int max_num_iterations;
-
- // If possible, how many threads can the solver use.
- int num_threads;
-
- // Hints about the order in which the parameter blocks should be
- // eliminated by the linear solver.
- //
- // For example if elimination_groups is a vector of size k, then
- // the linear solver is informed that it should eliminate the
- // parameter blocks 0 ... elimination_groups[0] - 1 first, and
- // then elimination_groups[0] ... elimination_groups[1] - 1 and so
- // on. Within each elimination group, the linear solver is free to
- // choose how the parameter blocks are ordered. Different linear
- // solvers have differing requirements on elimination_groups.
- //
- // The most common use is for Schur type solvers, where there
- // should be at least two elimination groups and the first
- // elimination group must form an independent set in the normal
- // equations. The first elimination group corresponds to the
- // num_eliminate_blocks in the Schur type solvers.
- vector<int> elimination_groups;
-
- // Iterative solvers, e.g. Preconditioned Conjugate Gradients
- // maintain a cheap estimate of the residual which may become
- // inaccurate over time. Thus for non-zero values of this
- // parameter, the solver can be told to recalculate the value of
- // the residual using a |b - Ax| evaluation.
- int residual_reset_period;
-
- // If the block sizes in a BlockSparseMatrix are fixed, then in
- // some cases the Schur complement based solvers can detect and
- // specialize on them.
- //
- // It is expected that these parameters are set programmatically
- // rather than manually.
- //
- // Please see schur_complement_solver.h and schur_eliminator.h for
- // more details.
- int row_block_size;
- int e_block_size;
- int f_block_size;
- };
-
- // Options for the Solve method.
- struct PerSolveOptions {
- PerSolveOptions()
- : D(NULL),
- preconditioner(NULL),
- r_tolerance(0.0),
- q_tolerance(0.0) {
- }
-
- // This option only makes sense for unsymmetric linear solvers
- // that can solve rectangular linear systems.
- //
- // Given a matrix A, an optional diagonal matrix D as a vector,
- // and a vector b, the linear solver will solve for
- //
- // | A | x = | b |
- // | D | | 0 |
- //
- // If D is null, then it is treated as zero, and the solver returns
- // the solution to
- //
- // A x = b
- //
- // In either case, x is the vector that solves the following
- // optimization problem.
- //
- // arg min_x ||Ax - b||^2 + ||Dx||^2
- //
- // Here A is a matrix of size m x n, with full column rank. If A
- // does not have full column rank, the results returned by the
- // solver cannot be relied on. D, if it is not null is an array of
- // size n. b is an array of size m and x is an array of size n.
- double * D;
-
- // This option only makes sense for iterative solvers.
- //
- // In general the performance of an iterative linear solver
- // depends on the condition number of the matrix A. For example
- // the convergence rate of the conjugate gradients algorithm
- // is proportional to the square root of the condition number.
- //
- // One particularly useful technique for improving the
- // conditioning of a linear system is to precondition it. In its
- // simplest form a preconditioner is a matrix M such that instead
- // of solving Ax = b, we solve the linear system AM^{-1} y = b
- // instead, where M is such that the condition number k(AM^{-1})
- // is smaller than the conditioner k(A). Given the solution to
- // this system, x = M^{-1} y. The iterative solver takes care of
- // the mechanics of solving the preconditioned system and
- // returning the corrected solution x. The user only needs to
- // supply a linear operator.
- //
- // A null preconditioner is equivalent to an identity matrix being
- // used a preconditioner.
- LinearOperator* preconditioner;
-
-
- // The following tolerance related options only makes sense for
- // iterative solvers. Direct solvers ignore them.
-
- // Solver terminates when
- //
- // |Ax - b| <= r_tolerance * |b|.
- //
- // This is the most commonly used termination criterion for
- // iterative solvers.
- double r_tolerance;
-
- // For PSD matrices A, let
- //
- // Q(x) = x'Ax - 2b'x
- //
- // be the cost of the quadratic function defined by A and b. Then,
- // the solver terminates at iteration i if
- //
- // i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
- //
- // This termination criterion is more useful when using CG to
- // solve the Newton step. This particular convergence test comes
- // from Stephen Nash's work on truncated Newton
- // methods. References:
- //
- // 1. Stephen G. Nash & Ariela Sofer, Assessing A Search
- // Direction Within A Truncated Newton Method, Operation
- // Research Letters 9(1990) 219-221.
- //
- // 2. Stephen G. Nash, A Survey of Truncated Newton Methods,
- // Journal of Computational and Applied Mathematics,
- // 124(1-2), 45-59, 2000.
- //
- double q_tolerance;
- };
-
- // Summary of a call to the Solve method. We should move away from
- // the true/false method for determining solver success. We should
- // let the summary object do the talking.
- struct Summary {
- Summary()
- : residual_norm(0.0),
- num_iterations(-1),
- termination_type(LINEAR_SOLVER_FAILURE) {
- }
-
- double residual_norm;
- int num_iterations;
- LinearSolverTerminationType termination_type;
- string message;
- };
-
- // If the optimization problem is such that there are no remaining
- // e-blocks, a Schur type linear solver cannot be used. If the
- // linear solver is of Schur type, this function implements a policy
- // to select an alternate nearest linear solver to the one selected
- // by the user. The input linear_solver_type is returned otherwise.
- static LinearSolverType LinearSolverForZeroEBlocks(
- LinearSolverType linear_solver_type);
-
- virtual ~LinearSolver();
-
- // Solve Ax = b.
- virtual Summary Solve(LinearOperator* A,
- const double* b,
- const PerSolveOptions& per_solve_options,
- double* x) = 0;
-
- // The following two methods return copies instead of references so
- // that the base class implementation does not have to worry about
- // life time issues. Further, these calls are not expected to be
- // frequent or performance sensitive.
- virtual map<string, int> CallStatistics() const {
- return map<string, int>();
- }
-
- virtual map<string, double> TimeStatistics() const {
- return map<string, double>();
- }
-
- // Factory
- static LinearSolver* Create(const Options& options);
-};
-
-// This templated subclass of LinearSolver serves as a base class for
-// other linear solvers that depend on the particular matrix layout of
-// the underlying linear operator. For example some linear solvers
-// need low level access to the TripletSparseMatrix implementing the
-// LinearOperator interface. This class hides those implementation
-// details behind a private virtual method, and has the Solve method
-// perform the necessary upcasting.
-template <typename MatrixType>
-class TypedLinearSolver : public LinearSolver {
- public:
- virtual ~TypedLinearSolver() {}
- virtual LinearSolver::Summary Solve(
- LinearOperator* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_);
- CHECK_NOTNULL(A);
- CHECK_NOTNULL(b);
- CHECK_NOTNULL(x);
- return SolveImpl(down_cast<MatrixType*>(A), b, per_solve_options, x);
- }
-
- virtual map<string, int> CallStatistics() const {
- return execution_summary_.calls();
- }
-
- virtual map<string, double> TimeStatistics() const {
- return execution_summary_.times();
- }
-
- private:
- virtual LinearSolver::Summary SolveImpl(
- MatrixType* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) = 0;
-
- ExecutionSummary execution_summary_;
-};
-
-// Linear solvers that depend on acccess to the low level structure of
-// a SparseMatrix.
-typedef TypedLinearSolver<BlockSparseMatrix> BlockSparseMatrixSolver; // NOLINT
-typedef TypedLinearSolver<CompressedRowSparseMatrix> CompressedRowSparseMatrixSolver; // NOLINT
-typedef TypedLinearSolver<DenseSparseMatrix> DenseSparseMatrixSolver; // NOLINT
-typedef TypedLinearSolver<TripletSparseMatrix> TripletSparseMatrixSolver; // NOLINT
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LINEAR_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc b/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc
deleted file mode 100644
index a4832c57443..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/local_parameterization.cc
+++ /dev/null
@@ -1,183 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/local_parameterization.h"
-
-#include "ceres/internal/eigen.h"
-#include "ceres/rotation.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-LocalParameterization::~LocalParameterization() {
-}
-
-bool LocalParameterization::MultiplyByJacobian(const double* x,
- const int num_rows,
- const double* global_matrix,
- double* local_matrix) const {
- Matrix jacobian(GlobalSize(), LocalSize());
- if (!ComputeJacobian(x, jacobian.data())) {
- return false;
- }
-
- MatrixRef(local_matrix, num_rows, LocalSize()) =
- ConstMatrixRef(global_matrix, num_rows, GlobalSize()) * jacobian;
- return true;
-}
-
-IdentityParameterization::IdentityParameterization(const int size)
- : size_(size) {
- CHECK_GT(size, 0);
-}
-
-bool IdentityParameterization::Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const {
- VectorRef(x_plus_delta, size_) =
- ConstVectorRef(x, size_) + ConstVectorRef(delta, size_);
- return true;
-}
-
-bool IdentityParameterization::ComputeJacobian(const double* x,
- double* jacobian) const {
- MatrixRef(jacobian, size_, size_) = Matrix::Identity(size_, size_);
- return true;
-}
-
-bool IdentityParameterization::MultiplyByJacobian(const double* x,
- const int num_cols,
- const double* global_matrix,
- double* local_matrix) const {
- std::copy(global_matrix,
- global_matrix + num_cols * GlobalSize(),
- local_matrix);
- return true;
-}
-
-SubsetParameterization::SubsetParameterization(
- int size,
- const vector<int>& constant_parameters)
- : local_size_(size - constant_parameters.size()),
- constancy_mask_(size, 0) {
- CHECK_GT(constant_parameters.size(), 0)
- << "The set of constant parameters should contain at least "
- << "one element. If you do not wish to hold any parameters "
- << "constant, then do not use a SubsetParameterization";
-
- vector<int> constant = constant_parameters;
- sort(constant.begin(), constant.end());
- CHECK(unique(constant.begin(), constant.end()) == constant.end())
- << "The set of constant parameters cannot contain duplicates";
- CHECK_LT(constant_parameters.size(), size)
- << "Number of parameters held constant should be less "
- << "than the size of the parameter block. If you wish "
- << "to hold the entire parameter block constant, then a "
- << "efficient way is to directly mark it as constant "
- << "instead of using a LocalParameterization to do so.";
- CHECK_GE(*min_element(constant.begin(), constant.end()), 0);
- CHECK_LT(*max_element(constant.begin(), constant.end()), size);
-
- for (int i = 0; i < constant_parameters.size(); ++i) {
- constancy_mask_[constant_parameters[i]] = 1;
- }
-}
-
-bool SubsetParameterization::Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const {
- for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
- if (constancy_mask_[i]) {
- x_plus_delta[i] = x[i];
- } else {
- x_plus_delta[i] = x[i] + delta[j++];
- }
- }
- return true;
-}
-
-bool SubsetParameterization::ComputeJacobian(const double* x,
- double* jacobian) const {
- MatrixRef m(jacobian, constancy_mask_.size(), local_size_);
- m.setZero();
- for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) {
- if (!constancy_mask_[i]) {
- m(i, j++) = 1.0;
- }
- }
- return true;
-}
-
-bool SubsetParameterization::MultiplyByJacobian(const double* x,
- const int num_rows,
- const double* global_matrix,
- double* local_matrix) const {
- for (int row = 0; row < num_rows; ++row) {
- for (int col = 0, j = 0; col < constancy_mask_.size(); ++col) {
- if (!constancy_mask_[col]) {
- local_matrix[row * LocalSize() + j++] =
- global_matrix[row * GlobalSize() + col];
- }
- }
- }
- return true;
-}
-
-bool QuaternionParameterization::Plus(const double* x,
- const double* delta,
- double* x_plus_delta) const {
- const double norm_delta =
- sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
- if (norm_delta > 0.0) {
- const double sin_delta_by_delta = (sin(norm_delta) / norm_delta);
- double q_delta[4];
- q_delta[0] = cos(norm_delta);
- q_delta[1] = sin_delta_by_delta * delta[0];
- q_delta[2] = sin_delta_by_delta * delta[1];
- q_delta[3] = sin_delta_by_delta * delta[2];
- QuaternionProduct(q_delta, x, x_plus_delta);
- } else {
- for (int i = 0; i < 4; ++i) {
- x_plus_delta[i] = x[i];
- }
- }
- return true;
-}
-
-bool QuaternionParameterization::ComputeJacobian(const double* x,
- double* jacobian) const {
- jacobian[0] = -x[1]; jacobian[1] = -x[2]; jacobian[2] = -x[3]; // NOLINT
- jacobian[3] = x[0]; jacobian[4] = x[3]; jacobian[5] = -x[2]; // NOLINT
- jacobian[6] = -x[3]; jacobian[7] = x[0]; jacobian[8] = x[1]; // NOLINT
- jacobian[9] = x[2]; jacobian[10] = -x[1]; jacobian[11] = x[0]; // NOLINT
- return true;
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc b/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc
deleted file mode 100644
index 62b545be12f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/loss_function.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Purpose: See .h file.
-
-#include "ceres/loss_function.h"
-
-#include <cmath>
-#include <cstddef>
-#include <limits>
-
-namespace ceres {
-
-void TrivialLoss::Evaluate(double s, double rho[3]) const {
- rho[0] = s;
- rho[1] = 1.0;
- rho[2] = 0.0;
-}
-
-void HuberLoss::Evaluate(double s, double rho[3]) const {
- if (s > b_) {
- // Outlier region.
- // 'r' is always positive.
- const double r = sqrt(s);
- rho[0] = 2.0 * a_ * r - b_;
- rho[1] = std::max(std::numeric_limits<double>::min(), a_ / r);
- rho[2] = - rho[1] / (2.0 * s);
- } else {
- // Inlier region.
- rho[0] = s;
- rho[1] = 1.0;
- rho[2] = 0.0;
- }
-}
-
-void SoftLOneLoss::Evaluate(double s, double rho[3]) const {
- const double sum = 1.0 + s * c_;
- const double tmp = sqrt(sum);
- // 'sum' and 'tmp' are always positive, assuming that 's' is.
- rho[0] = 2.0 * b_ * (tmp - 1.0);
- rho[1] = std::max(std::numeric_limits<double>::min(), 1.0 / tmp);
- rho[2] = - (c_ * rho[1]) / (2.0 * sum);
-}
-
-void CauchyLoss::Evaluate(double s, double rho[3]) const {
- const double sum = 1.0 + s * c_;
- const double inv = 1.0 / sum;
- // 'sum' and 'inv' are always positive, assuming that 's' is.
- rho[0] = b_ * log(sum);
- rho[1] = std::max(std::numeric_limits<double>::min(), inv);
- rho[2] = - c_ * (inv * inv);
-}
-
-void ArctanLoss::Evaluate(double s, double rho[3]) const {
- const double sum = 1 + s * s * b_;
- const double inv = 1 / sum;
- // 'sum' and 'inv' are always positive.
- rho[0] = a_ * atan2(s, a_);
- rho[1] = std::max(std::numeric_limits<double>::min(), inv);
- rho[2] = -2.0 * s * b_ * (inv * inv);
-}
-
-TolerantLoss::TolerantLoss(double a, double b)
- : a_(a),
- b_(b),
- c_(b * log(1.0 + exp(-a / b))) {
- CHECK_GE(a, 0.0);
- CHECK_GT(b, 0.0);
-}
-
-void TolerantLoss::Evaluate(double s, double rho[3]) const {
- const double x = (s - a_) / b_;
- // The basic equation is rho[0] = b ln(1 + e^x). However, if e^x is too
- // large, it will overflow. Since numerically 1 + e^x == e^x when the
- // x is greater than about ln(2^53) for doubles, beyond this threshold
- // we substitute x for ln(1 + e^x) as a numerically equivalent approximation.
- static const double kLog2Pow53 = 36.7; // ln(MathLimits<double>::kEpsilon).
- if (x > kLog2Pow53) {
- rho[0] = s - a_ - c_;
- rho[1] = 1.0;
- rho[2] = 0.0;
- } else {
- const double e_x = exp(x);
- rho[0] = b_ * log(1.0 + e_x) - c_;
- rho[1] = std::max(std::numeric_limits<double>::min(), e_x / (1.0 + e_x));
- rho[2] = 0.5 / (b_ * (1.0 + cosh(x)));
- }
-}
-
-ComposedLoss::ComposedLoss(const LossFunction* f, Ownership ownership_f,
- const LossFunction* g, Ownership ownership_g)
- : f_(CHECK_NOTNULL(f)),
- g_(CHECK_NOTNULL(g)),
- ownership_f_(ownership_f),
- ownership_g_(ownership_g) {
-}
-
-ComposedLoss::~ComposedLoss() {
- if (ownership_f_ == DO_NOT_TAKE_OWNERSHIP) {
- f_.release();
- }
- if (ownership_g_ == DO_NOT_TAKE_OWNERSHIP) {
- g_.release();
- }
-}
-
-void ComposedLoss::Evaluate(double s, double rho[3]) const {
- double rho_f[3], rho_g[3];
- g_->Evaluate(s, rho_g);
- f_->Evaluate(rho_g[0], rho_f);
- rho[0] = rho_f[0];
- // f'(g(s)) * g'(s).
- rho[1] = rho_f[1] * rho_g[1];
- // f''(g(s)) * g'(s) * g'(s) + f'(g(s)) * g''(s).
- rho[2] = rho_f[2] * rho_g[1] * rho_g[1] + rho_f[1] * rho_g[2];
-}
-
-void ScaledLoss::Evaluate(double s, double rho[3]) const {
- if (rho_.get() == NULL) {
- rho[0] = a_ * s;
- rho[1] = a_;
- rho[2] = 0.0;
- } else {
- rho_->Evaluate(s, rho);
- rho[0] *= a_;
- rho[1] *= a_;
- rho[2] *= a_;
- }
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
deleted file mode 100644
index 4816e3c20f0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
+++ /dev/null
@@ -1,186 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include <list>
-
-#include "ceres/internal/eigen.h"
-#include "ceres/low_rank_inverse_hessian.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// The (L)BFGS algorithm explicitly requires that the secant equation:
-//
-// B_{k+1} * s_k = y_k
-//
-// Is satisfied at each iteration, where B_{k+1} is the approximated
-// Hessian at the k+1-th iteration, s_k = (x_{k+1} - x_{k}) and
-// y_k = (grad_{k+1} - grad_{k}). As the approximated Hessian must be
-// positive definite, this is equivalent to the condition:
-//
-// s_k^T * y_k > 0 [s_k^T * B_{k+1} * s_k = s_k^T * y_k > 0]
-//
-// This condition would always be satisfied if the function was strictly
-// convex, alternatively, it is always satisfied provided that a Wolfe line
-// search is used (even if the function is not strictly convex). See [1]
-// (p138) for a proof.
-//
-// Although Ceres will always use a Wolfe line search when using (L)BFGS,
-// practical implementation considerations mean that the line search
-// may return a point that satisfies only the Armijo condition, and thus
-// could violate the Secant equation. As such, we will only use a step
-// to update the Hessian approximation if:
-//
-// s_k^T * y_k > tolerance
-//
-// It is important that tolerance is very small (and >=0), as otherwise we
-// might skip the update too often and fail to capture important curvature
-// information in the Hessian. For example going from 1e-10 -> 1e-14 improves
-// the NIST benchmark score from 43/54 to 53/54.
-//
-// [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed. Springer, 1999.
-//
-// TODO(alexs.mac): Consider using Damped BFGS update instead of
-// skipping update.
-const double kLBFGSSecantConditionHessianUpdateTolerance = 1e-14;
-
-LowRankInverseHessian::LowRankInverseHessian(
- int num_parameters,
- int max_num_corrections,
- bool use_approximate_eigenvalue_scaling)
- : num_parameters_(num_parameters),
- max_num_corrections_(max_num_corrections),
- use_approximate_eigenvalue_scaling_(use_approximate_eigenvalue_scaling),
- approximate_eigenvalue_scale_(1.0),
- delta_x_history_(num_parameters, max_num_corrections),
- delta_gradient_history_(num_parameters, max_num_corrections),
- delta_x_dot_delta_gradient_(max_num_corrections) {
-}
-
-bool LowRankInverseHessian::Update(const Vector& delta_x,
- const Vector& delta_gradient) {
- const double delta_x_dot_delta_gradient = delta_x.dot(delta_gradient);
- if (delta_x_dot_delta_gradient <=
- kLBFGSSecantConditionHessianUpdateTolerance) {
- VLOG(2) << "Skipping L-BFGS Update, delta_x_dot_delta_gradient too "
- << "small: " << delta_x_dot_delta_gradient << ", tolerance: "
- << kLBFGSSecantConditionHessianUpdateTolerance
- << " (Secant condition).";
- return false;
- }
-
-
- int next = indices_.size();
- // Once the size of the list reaches max_num_corrections_, simulate
- // a circular buffer by removing the first element of the list and
- // making it the next position where the LBFGS history is stored.
- if (next == max_num_corrections_) {
- next = indices_.front();
- indices_.pop_front();
- }
-
- indices_.push_back(next);
- delta_x_history_.col(next) = delta_x;
- delta_gradient_history_.col(next) = delta_gradient;
- delta_x_dot_delta_gradient_(next) = delta_x_dot_delta_gradient;
- approximate_eigenvalue_scale_ =
- delta_x_dot_delta_gradient / delta_gradient.squaredNorm();
- return true;
-}
-
-void LowRankInverseHessian::RightMultiply(const double* x_ptr,
- double* y_ptr) const {
- ConstVectorRef gradient(x_ptr, num_parameters_);
- VectorRef search_direction(y_ptr, num_parameters_);
-
- search_direction = gradient;
-
- const int num_corrections = indices_.size();
- Vector alpha(num_corrections);
-
- for (std::list<int>::const_reverse_iterator it = indices_.rbegin();
- it != indices_.rend();
- ++it) {
- const double alpha_i = delta_x_history_.col(*it).dot(search_direction) /
- delta_x_dot_delta_gradient_(*it);
- search_direction -= alpha_i * delta_gradient_history_.col(*it);
- alpha(*it) = alpha_i;
- }
-
- if (use_approximate_eigenvalue_scaling_) {
- // Rescale the initial inverse Hessian approximation (H_0) to be iteratively
- // updated so that it is of similar 'size' to the true inverse Hessian along
- // the most recent search direction. As shown in [1]:
- //
- // \gamma_k = (delta_gradient_{k-1}' * delta_x_{k-1}) /
- // (delta_gradient_{k-1}' * delta_gradient_{k-1})
- //
- // Satisfies:
- //
- // (1 / \lambda_m) <= \gamma_k <= (1 / \lambda_1)
- //
- // Where \lambda_1 & \lambda_m are the smallest and largest eigenvalues of
- // the true Hessian (not the inverse) along the most recent search direction
- // respectively. Thus \gamma is an approximate eigenvalue of the true
- // inverse Hessian, and choosing: H_0 = I * \gamma will yield a starting
- // point that has a similar scale to the true inverse Hessian. This
- // technique is widely reported to often improve convergence, however this
- // is not universally true, particularly if there are errors in the initial
- // jacobians, or if there are significant differences in the sensitivity
- // of the problem to the parameters (i.e. the range of the magnitudes of
- // the components of the gradient is large).
- //
- // The original origin of this rescaling trick is somewhat unclear, the
- // earliest reference appears to be Oren [1], however it is widely discussed
- // without specific attributation in various texts including [2] (p143/178).
- //
- // [1] Oren S.S., Self-scaling variable metric (SSVM) algorithms Part II:
- // Implementation and experiments, Management Science,
- // 20(5), 863-874, 1974.
- // [2] Nocedal J., Wright S., Numerical Optimization, Springer, 1999.
- search_direction *= approximate_eigenvalue_scale_;
-
- VLOG(4) << "Applying approximate_eigenvalue_scale: "
- << approximate_eigenvalue_scale_ << " to initial inverse Hessian "
- << "approximation.";
- }
-
- for (std::list<int>::const_iterator it = indices_.begin();
- it != indices_.end();
- ++it) {
- const double beta = delta_gradient_history_.col(*it).dot(search_direction) /
- delta_x_dot_delta_gradient_(*it);
- search_direction += delta_x_history_.col(*it) * (alpha(*it) - beta);
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
deleted file mode 100644
index 19ab7606aa0..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Limited memory positive definite approximation to the inverse
-// Hessian, using the LBFGS algorithm
-
-#ifndef CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
-#define CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
-
-#include <list>
-
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_operator.h"
-
-namespace ceres {
-namespace internal {
-
-// LowRankInverseHessian is a positive definite approximation to the
-// Hessian using the limited memory variant of the
-// Broyden-Fletcher-Goldfarb-Shanno (BFGS)secant formula for
-// approximating the Hessian.
-//
-// Other update rules like the Davidon-Fletcher-Powell (DFP) are
-// possible, but the BFGS rule is considered the best performing one.
-//
-// The limited memory variant was developed by Nocedal and further
-// enhanced with scaling rule by Byrd, Nocedal and Schanbel.
-//
-// Nocedal, J. (1980). "Updating Quasi-Newton Matrices with Limited
-// Storage". Mathematics of Computation 35 (151): 773–782.
-//
-// Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
-// "Representations of Quasi-Newton Matrices and their use in
-// Limited Memory Methods". Mathematical Programming 63 (4):
-class LowRankInverseHessian : public LinearOperator {
- public:
- // num_parameters is the row/column size of the Hessian.
- // max_num_corrections is the rank of the Hessian approximation.
- // use_approximate_eigenvalue_scaling controls whether the initial
- // inverse Hessian used during Right/LeftMultiply() is scaled by
- // the approximate eigenvalue of the true inverse Hessian at the
- // current operating point.
- // The approximation uses:
- // 2 * max_num_corrections * num_parameters + max_num_corrections
- // doubles.
- LowRankInverseHessian(int num_parameters,
- int max_num_corrections,
- bool use_approximate_eigenvalue_scaling);
- virtual ~LowRankInverseHessian() {}
-
- // Update the low rank approximation. delta_x is the change in the
- // domain of Hessian, and delta_gradient is the change in the
- // gradient. The update copies the delta_x and delta_gradient
- // vectors, and gets rid of the oldest delta_x and delta_gradient
- // vectors if the number of corrections is already equal to
- // max_num_corrections.
- bool Update(const Vector& delta_x, const Vector& delta_gradient);
-
- // LinearOperator interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const {
- RightMultiply(x, y);
- }
- virtual int num_rows() const { return num_parameters_; }
- virtual int num_cols() const { return num_parameters_; }
-
- private:
- const int num_parameters_;
- const int max_num_corrections_;
- const bool use_approximate_eigenvalue_scaling_;
- double approximate_eigenvalue_scale_;
- ColMajorMatrix delta_x_history_;
- ColMajorMatrix delta_gradient_history_;
- Vector delta_x_dot_delta_gradient_;
- std::list<int> indices_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/map_util.h b/extern/libmv/third_party/ceres/internal/ceres/map_util.h
deleted file mode 100644
index 929c6b36982..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/map_util.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// Originally by Anton Carver
-
-#ifndef CERES_INTERNAL_MAP_UTIL_H_
-#define CERES_INTERNAL_MAP_UTIL_H_
-
-#include <utility>
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-// Perform a lookup in a map or hash_map, assuming that the key exists.
-// Crash if it does not.
-//
-// This is intended as a replacement for operator[] as an rvalue (for reading)
-// when the key is guaranteed to exist.
-//
-// operator[] is discouraged for several reasons:
-// * It has a side-effect of inserting missing keys
-// * It is not thread-safe (even when it is not inserting, it can still
-// choose to resize the underlying storage)
-// * It invalidates iterators (when it chooses to resize)
-// * It default constructs a value object even if it doesn't need to
-//
-// This version assumes the key is printable, and includes it in the fatal log
-// message.
-template <class Collection>
-const typename Collection::value_type::second_type&
-FindOrDie(const Collection& collection,
- const typename Collection::value_type::first_type& key) {
- typename Collection::const_iterator it = collection.find(key);
- CHECK(it != collection.end()) << "Map key not found: " << key;
- return it->second;
-}
-
-// Perform a lookup in a map or hash_map.
-// If the key is present in the map then the value associated with that
-// key is returned, otherwise the value passed as a default is returned.
-template <class Collection>
-const typename Collection::value_type::second_type&
-FindWithDefault(const Collection& collection,
- const typename Collection::value_type::first_type& key,
- const typename Collection::value_type::second_type& value) {
- typename Collection::const_iterator it = collection.find(key);
- if (it == collection.end()) {
- return value;
- }
- return it->second;
-}
-
-// Insert a new key and value into a map or hash_map.
-// If the key is not present in the map the key and value are
-// inserted, otherwise nothing happens. True indicates that an insert
-// took place, false indicates the key was already present.
-template <class Collection>
-bool InsertIfNotPresent(
- Collection * const collection,
- const typename Collection::value_type::first_type& key,
- const typename Collection::value_type::second_type& value) {
- pair<typename Collection::iterator, bool> ret =
- collection->insert(typename Collection::value_type(key, value));
- return ret.second;
-}
-
-// Perform a lookup in a map or hash_map.
-// Same as above but the returned pointer is not const and can be used to change
-// the stored value.
-template <class Collection>
-typename Collection::value_type::second_type*
-FindOrNull(Collection& collection, // NOLINT
- const typename Collection::value_type::first_type& key) {
- typename Collection::iterator it = collection.find(key);
- if (it == collection.end()) {
- return 0;
- }
- return &it->second;
-}
-
-// Test to see if a set, map, hash_set or hash_map contains a particular key.
-// Returns true if the key is in the collection.
-template <class Collection, class Key>
-bool ContainsKey(const Collection& collection, const Key& key) {
- typename Collection::const_iterator it = collection.find(key);
- return it != collection.end();
-}
-
-// Inserts a new key/value into a map or hash_map.
-// Dies if the key is already present.
-template<class Collection>
-void InsertOrDie(Collection* const collection,
- const typename Collection::value_type::first_type& key,
- const typename Collection::value_type::second_type& data) {
- typedef typename Collection::value_type value_type;
- CHECK(collection->insert(value_type(key, data)).second)
- << "duplicate key: " << key;
-}
-
-} // namespace ceres
-
-#endif // CERES_INTERNAL_MAP_UTIL_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
deleted file mode 100644
index 558921b8441..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/line_search_minimizer.h"
-#include "ceres/minimizer.h"
-#include "ceres/trust_region_minimizer.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-Minimizer* Minimizer::Create(MinimizerType minimizer_type) {
- if (minimizer_type == TRUST_REGION) {
- return new TrustRegionMinimizer;
- }
-
- if (minimizer_type == LINE_SEARCH) {
- return new LineSearchMinimizer;
- }
-
- LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
- return NULL;
-}
-
-
-Minimizer::~Minimizer() {}
-
-bool Minimizer::RunCallbacks(const Minimizer::Options& options,
- const IterationSummary& iteration_summary,
- Solver::Summary* summary) {
- const bool is_not_silent = !options.is_silent;
- CallbackReturnType status = SOLVER_CONTINUE;
- int i = 0;
- while (status == SOLVER_CONTINUE && i < options.callbacks.size()) {
- status = (*options.callbacks[i])(iteration_summary);
- ++i;
- }
- switch (status) {
- case SOLVER_CONTINUE:
- return true;
- case SOLVER_TERMINATE_SUCCESSFULLY:
- summary->termination_type = USER_SUCCESS;
- summary->message = "User callback returned SOLVER_TERMINATE_SUCCESSFULLY.";
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return false;
- case SOLVER_ABORT:
- summary->termination_type = USER_FAILURE;
- summary->message = "User callback returned SOLVER_ABORT.";
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return false;
- default:
- LOG(FATAL) << "Unknown type of user callback status";
- }
- return false;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
deleted file mode 100644
index dabf07e583a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
+++ /dev/null
@@ -1,202 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_MINIMIZER_H_
-#define CERES_INTERNAL_MINIMIZER_H_
-
-#include <string>
-#include <vector>
-#include "ceres/internal/port.h"
-#include "ceres/iteration_callback.h"
-#include "ceres/solver.h"
-
-namespace ceres {
-namespace internal {
-
-class Evaluator;
-class SparseMatrix;
-class TrustRegionStrategy;
-class CoordinateDescentMinimizer;
-class LinearSolver;
-
-// Interface for non-linear least squares solvers.
-class Minimizer {
- public:
- // Options struct to control the behaviour of the Minimizer. Please
- // see solver.h for detailed information about the meaning and
- // default values of each of these parameters.
- struct Options {
- Options() {
- Init(Solver::Options());
- }
-
- explicit Options(const Solver::Options& options) {
- Init(options);
- }
-
- void Init(const Solver::Options& options) {
- num_threads = options.num_threads;
- max_num_iterations = options.max_num_iterations;
- max_solver_time_in_seconds = options.max_solver_time_in_seconds;
- max_step_solver_retries = 5;
- gradient_tolerance = options.gradient_tolerance;
- parameter_tolerance = options.parameter_tolerance;
- function_tolerance = options.function_tolerance;
- min_relative_decrease = options.min_relative_decrease;
- eta = options.eta;
- jacobi_scaling = options.jacobi_scaling;
- use_nonmonotonic_steps = options.use_nonmonotonic_steps;
- max_consecutive_nonmonotonic_steps =
- options.max_consecutive_nonmonotonic_steps;
- trust_region_problem_dump_directory =
- options.trust_region_problem_dump_directory;
- trust_region_minimizer_iterations_to_dump =
- options.trust_region_minimizer_iterations_to_dump;
- trust_region_problem_dump_format_type =
- options.trust_region_problem_dump_format_type;
- max_num_consecutive_invalid_steps =
- options.max_num_consecutive_invalid_steps;
- min_trust_region_radius = options.min_trust_region_radius;
- line_search_direction_type = options.line_search_direction_type;
- line_search_type = options.line_search_type;
- nonlinear_conjugate_gradient_type =
- options.nonlinear_conjugate_gradient_type;
- max_lbfgs_rank = options.max_lbfgs_rank;
- use_approximate_eigenvalue_bfgs_scaling =
- options.use_approximate_eigenvalue_bfgs_scaling;
- line_search_interpolation_type =
- options.line_search_interpolation_type;
- min_line_search_step_size = options.min_line_search_step_size;
- line_search_sufficient_function_decrease =
- options.line_search_sufficient_function_decrease;
- max_line_search_step_contraction =
- options.max_line_search_step_contraction;
- min_line_search_step_contraction =
- options.min_line_search_step_contraction;
- max_num_line_search_step_size_iterations =
- options.max_num_line_search_step_size_iterations;
- max_num_line_search_direction_restarts =
- options.max_num_line_search_direction_restarts;
- line_search_sufficient_curvature_decrease =
- options.line_search_sufficient_curvature_decrease;
- max_line_search_step_expansion =
- options.max_line_search_step_expansion;
- inner_iteration_tolerance = options.inner_iteration_tolerance;
- is_silent = (options.logging_type == SILENT);
- is_constrained = false;
- callbacks = options.callbacks;
- }
-
- int max_num_iterations;
- double max_solver_time_in_seconds;
- int num_threads;
-
- // Number of times the linear solver should be retried in case of
- // numerical failure. The retries are done by exponentially scaling up
- // mu at each retry. This leads to stronger and stronger
- // regularization making the linear least squares problem better
- // conditioned at each retry.
- int max_step_solver_retries;
- double gradient_tolerance;
- double parameter_tolerance;
- double function_tolerance;
- double min_relative_decrease;
- double eta;
- bool jacobi_scaling;
- bool use_nonmonotonic_steps;
- int max_consecutive_nonmonotonic_steps;
- vector<int> trust_region_minimizer_iterations_to_dump;
- DumpFormatType trust_region_problem_dump_format_type;
- string trust_region_problem_dump_directory;
- int max_num_consecutive_invalid_steps;
- double min_trust_region_radius;
- LineSearchDirectionType line_search_direction_type;
- LineSearchType line_search_type;
- NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
- int max_lbfgs_rank;
- bool use_approximate_eigenvalue_bfgs_scaling;
- LineSearchInterpolationType line_search_interpolation_type;
- double min_line_search_step_size;
- double line_search_sufficient_function_decrease;
- double max_line_search_step_contraction;
- double min_line_search_step_contraction;
- int max_num_line_search_step_size_iterations;
- int max_num_line_search_direction_restarts;
- double line_search_sufficient_curvature_decrease;
- double max_line_search_step_expansion;
- double inner_iteration_tolerance;
-
- // If true, then all logging is disabled.
- bool is_silent;
-
- // Use a bounds constrained optimization algorithm.
- bool is_constrained;
-
- // List of callbacks that are executed by the Minimizer at the end
- // of each iteration.
- //
- // The Options struct does not own these pointers.
- vector<IterationCallback*> callbacks;
-
- // Object responsible for evaluating the cost, residuals and
- // Jacobian matrix.
- shared_ptr<Evaluator> evaluator;
-
- // Object responsible for actually computing the trust region
- // step, and sizing the trust region radius.
- shared_ptr<TrustRegionStrategy> trust_region_strategy;
-
- // Object holding the Jacobian matrix. It is assumed that the
- // sparsity structure of the matrix has already been initialized
- // and will remain constant for the life time of the
- // optimization.
- shared_ptr<SparseMatrix> jacobian;
-
- shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
- };
-
- static Minimizer* Create(MinimizerType minimizer_type);
- static bool RunCallbacks(const Options& options,
- const IterationSummary& iteration_summary,
- Solver::Summary* summary);
-
- virtual ~Minimizer();
- // Note: The minimizer is expected to update the state of the
- // parameters array every iteration. This is required for the
- // StateUpdatingCallback to work.
- virtual void Minimize(const Options& options,
- double* parameters,
- Solver::Summary* summary) = 0;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_MINIMIZER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/mutex.h b/extern/libmv/third_party/ceres/internal/ceres/mutex.h
deleted file mode 100644
index 97e2cd360c2..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/mutex.h
+++ /dev/null
@@ -1,329 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Craig Silverstein.
-//
-// A simple mutex wrapper, supporting locks and read-write locks.
-// You should assume the locks are *not* re-entrant.
-//
-// This class is meant to be internal-only and should be wrapped by an
-// internal namespace. Before you use this module, please give the
-// name of your internal namespace for this module. Or, if you want
-// to expose it, you'll want to move it to the Google namespace. We
-// cannot put this class in global namespace because there can be some
-// problems when we have multiple versions of Mutex in each shared object.
-//
-// NOTE: by default, we have #ifdef'ed out the TryLock() method.
-// This is for two reasons:
-// 1) TryLock() under Windows is a bit annoying (it requires a
-// #define to be defined very early).
-// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
-// mode.
-// If you need TryLock(), and either these two caveats are not a
-// problem for you, or you're willing to work around them, then
-// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
-// in the code below.
-//
-// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
-// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
-// Because of that, we might as well use windows locks for
-// cygwin. They seem to be more reliable than the cygwin pthreads layer.
-//
-// TRICKY IMPLEMENTATION NOTE:
-// This class is designed to be safe to use during
-// dynamic-initialization -- that is, by global constructors that are
-// run before main() starts. The issue in this case is that
-// dynamic-initialization happens in an unpredictable order, and it
-// could be that someone else's dynamic initializer could call a
-// function that tries to acquire this mutex -- but that all happens
-// before this mutex's constructor has run. (This can happen even if
-// the mutex and the function that uses the mutex are in the same .cc
-// file.) Basically, because Mutex does non-trivial work in its
-// constructor, it's not, in the naive implementation, safe to use
-// before dynamic initialization has run on it.
-//
-// The solution used here is to pair the actual mutex primitive with a
-// bool that is set to true when the mutex is dynamically initialized.
-// (Before that it's false.) Then we modify all mutex routines to
-// look at the bool, and not try to lock/unlock until the bool makes
-// it to true (which happens after the Mutex constructor has run.)
-//
-// This works because before main() starts -- particularly, during
-// dynamic initialization -- there are no threads, so a) it's ok that
-// the mutex operations are a no-op, since we don't need locking then
-// anyway; and b) we can be quite confident our bool won't change
-// state between a call to Lock() and a call to Unlock() (that would
-// require a global constructor in one translation unit to call Lock()
-// and another global constructor in another translation unit to call
-// Unlock() later, which is pretty perverse).
-//
-// That said, it's tricky, and can conceivably fail; it's safest to
-// avoid trying to acquire a mutex in a global constructor, if you
-// can. One way it can fail is that a really smart compiler might
-// initialize the bool to true at static-initialization time (too
-// early) rather than at dynamic-initialization time. To discourage
-// that, we set is_safe_ to true in code (not the constructor
-// colon-initializer) and set it to true via a function that always
-// evaluates to true, but that the compiler can't know always
-// evaluates to true. This should be good enough.
-
-#ifndef CERES_INTERNAL_MUTEX_H_
-#define CERES_INTERNAL_MUTEX_H_
-
-#include "ceres/internal/port.h"
-
-#if defined(CERES_NO_THREADS)
- typedef int MutexType; // to keep a lock-count
-#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
-# define CERES_WIN32_LEAN_AND_MEAN // We only need minimal includes
-# ifdef CERES_GMUTEX_TRYLOCK
- // We need Windows NT or later for TryEnterCriticalSection(). If you
- // don't need that functionality, you can remove these _WIN32_WINNT
- // lines, and change TryLock() to assert(0) or something.
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0400
-# endif
-# endif
-// Unfortunately, windows.h defines a bunch of macros with common
-// names. Two in particular need avoiding: ERROR and min/max.
-// To avoid macro definition of ERROR.
-# define NOGDI
-// To avoid macro definition of min/max.
-# ifndef NOMINMAX
-# define NOMINMAX
-# endif
-# include <windows.h>
- typedef CRITICAL_SECTION MutexType;
-#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
- // Needed for pthread_rwlock_*. If it causes problems, you could take it
- // out, but then you'd have to unset CERES_HAVE_RWLOCK (at least on linux --
- // it *does* cause problems for FreeBSD, or MacOSX, but isn't needed for
- // locking there.)
-# if defined(__linux__) && !defined(_XOPEN_SOURCE)
-# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
-# endif
-# include <pthread.h>
- typedef pthread_rwlock_t MutexType;
-#elif defined(CERES_HAVE_PTHREAD)
-# include <pthread.h>
- typedef pthread_mutex_t MutexType;
-#else
-# error Need to implement mutex.h for your architecture, or #define NO_THREADS
-#endif
-
-// We need to include these header files after defining _XOPEN_SOURCE
-// as they may define the _XOPEN_SOURCE macro.
-#include <assert.h>
-#include <stdlib.h> // for abort()
-
-namespace ceres {
-namespace internal {
-
-class Mutex {
- public:
- // Create a Mutex that is not held by anybody. This constructor is
- // typically used for Mutexes allocated on the heap or the stack.
- // See below for a recommendation for constructing global Mutex
- // objects.
- inline Mutex();
-
- // Destructor
- inline ~Mutex();
-
- inline void Lock(); // Block if needed until free then acquire exclusively
- inline void Unlock(); // Release a lock acquired via Lock()
-#ifdef CERES_GMUTEX_TRYLOCK
- inline bool TryLock(); // If free, Lock() and return true, else return false
-#endif
- // Note that on systems that don't support read-write locks, these may
- // be implemented as synonyms to Lock() and Unlock(). So you can use
- // these for efficiency, but don't use them anyplace where being able
- // to do shared reads is necessary to avoid deadlock.
- inline void ReaderLock(); // Block until free or shared then acquire a share
- inline void ReaderUnlock(); // Release a read share of this Mutex
- inline void WriterLock() { Lock(); } // Acquire an exclusive lock
- inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
-
- // TODO(hamaji): Do nothing, implement correctly.
- inline void AssertHeld() {}
-
- private:
- MutexType mutex_;
- // We want to make sure that the compiler sets is_safe_ to true only
- // when we tell it to, and never makes assumptions is_safe_ is
- // always true. volatile is the most reliable way to do that.
- volatile bool is_safe_;
-
- inline void SetIsSafe() { is_safe_ = true; }
-
- // Catch the error of writing Mutex when intending MutexLock.
- Mutex(Mutex* /*ignored*/) {}
- // Disallow "evil" constructors
- Mutex(const Mutex&);
- void operator=(const Mutex&);
-};
-
-// Now the implementation of Mutex for various systems
-#if defined(CERES_NO_THREADS)
-
-// When we don't have threads, we can be either reading or writing,
-// but not both. We can have lots of readers at once (in no-threads
-// mode, that's most likely to happen in recursive function calls),
-// but only one writer. We represent this by having mutex_ be -1 when
-// writing and a number > 0 when reading (and 0 when no lock is held).
-//
-// In debug mode, we assert these invariants, while in non-debug mode
-// we do nothing, for efficiency. That's why everything is in an
-// assert.
-
-Mutex::Mutex() : mutex_(0) { }
-Mutex::~Mutex() { assert(mutex_ == 0); }
-void Mutex::Lock() { assert(--mutex_ == -1); }
-void Mutex::Unlock() { assert(mutex_++ == -1); }
-#ifdef CERES_GMUTEX_TRYLOCK
-bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
-#endif
-void Mutex::ReaderLock() { assert(++mutex_ > 0); }
-void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
-
-#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
-
-Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
-Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
-void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
-void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- TryEnterCriticalSection(&mutex_) != 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
-void Mutex::ReaderUnlock() { Unlock(); }
-
-#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
-
-#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() {
- SetIsSafe();
- if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_rwlock_destroy); }
-void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_rwlock_wrlock); }
-void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); }
-#ifdef CERES_GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_rwlock_trywrlock(&mutex_) == 0 :
- true; }
-#endif
-void Mutex::ReaderLock() { CERES_SAFE_PTHREAD(pthread_rwlock_rdlock); }
-void Mutex::ReaderUnlock() { CERES_SAFE_PTHREAD(pthread_rwlock_unlock); }
-#undef CERES_SAFE_PTHREAD
-
-#elif defined(CERES_HAVE_PTHREAD)
-
-#define CERES_SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() {
- SetIsSafe();
- if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { CERES_SAFE_PTHREAD(pthread_mutex_destroy); }
-void Mutex::Lock() { CERES_SAFE_PTHREAD(pthread_mutex_lock); }
-void Mutex::Unlock() { CERES_SAFE_PTHREAD(pthread_mutex_unlock); }
-#ifdef CERES_GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_mutex_trylock(&mutex_) == 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); }
-void Mutex::ReaderUnlock() { Unlock(); }
-#undef CERES_SAFE_PTHREAD
-
-#endif
-
-// --------------------------------------------------------------------------
-// Some helper classes
-
-// Note: The weird "Ceres" prefix for the class is a workaround for having two
-// similar mutex.h files included in the same translation unit. This is a
-// problem because macros do not respect C++ namespaces, and as a result, this
-// does not work well (e.g. inside Chrome). The offending macros are
-// "MutexLock(x) COMPILE_ASSERT(false)". To work around this, "Ceres" is
-// prefixed to the class names; this permits defining the classes.
-
-// CeresMutexLock(mu) acquires mu when constructed and releases it
-// when destroyed.
-class CeresMutexLock {
- public:
- explicit CeresMutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
- ~CeresMutexLock() { mu_->Unlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- CeresMutexLock(const CeresMutexLock&);
- void operator=(const CeresMutexLock&);
-};
-
-// CeresReaderMutexLock and CeresWriterMutexLock do the same, for rwlocks
-class CeresReaderMutexLock {
- public:
- explicit CeresReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
- ~CeresReaderMutexLock() { mu_->ReaderUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- CeresReaderMutexLock(const CeresReaderMutexLock&);
- void operator=(const CeresReaderMutexLock&);
-};
-
-class CeresWriterMutexLock {
- public:
- explicit CeresWriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
- ~CeresWriterMutexLock() { mu_->WriterUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- CeresWriterMutexLock(const CeresWriterMutexLock&);
- void operator=(const CeresWriterMutexLock&);
-};
-
-// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
-#define CeresMutexLock(x) \
- COMPILE_ASSERT(0, ceres_mutex_lock_decl_missing_var_name)
-#define CeresReaderMutexLock(x) \
- COMPILE_ASSERT(0, ceres_rmutex_lock_decl_missing_var_name)
-#define CeresWriterMutexLock(x) \
- COMPILE_ASSERT(0, ceres_wmutex_lock_decl_missing_var_name)
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_MUTEX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc b/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc
deleted file mode 100644
index 392d728fb32..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/normal_prior.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/normal_prior.h"
-
-#include <cstddef>
-#include <vector>
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-NormalPrior::NormalPrior(const Matrix& A, const Vector& b)
- : A_(A), b_(b) {
- CHECK_GT(b_.rows(), 0);
- CHECK_GT(A_.rows(), 0);
- CHECK_EQ(b_.rows(), A.cols());
- set_num_residuals(A_.rows());
- mutable_parameter_block_sizes()->push_back(b_.rows());
-}
-
-bool NormalPrior::Evaluate(double const* const* parameters,
- double* residuals,
- double** jacobians) const {
- ConstVectorRef p(parameters[0], parameter_block_sizes()[0]);
- VectorRef r(residuals, num_residuals());
- // The following line should read
- // r = A_ * (p - b_);
- // The extra eval is to get around a bug in the eigen library.
- r = A_ * (p - b_).eval();
- if ((jacobians != NULL) && (jacobians[0] != NULL)) {
- MatrixRef(jacobians[0], num_residuals(), parameter_block_sizes()[0]) = A_;
- }
- return true;
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
deleted file mode 100644
index 7bc823d4ec6..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
+++ /dev/null
@@ -1,397 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_PARAMETER_BLOCK_H_
-#define CERES_INTERNAL_PARAMETER_BLOCK_H_
-
-#include <algorithm>
-#include <cstdlib>
-#include <limits>
-#include <string>
-#include "ceres/array_utils.h"
-#include "ceres/collections_port.h"
-#include "ceres/integral_types.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/local_parameterization.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-class ProblemImpl;
-class ResidualBlock;
-
-// The parameter block encodes the location of the user's original value, and
-// also the "current state" of the parameter. The evaluator uses whatever is in
-// the current state of the parameter when evaluating. This is inlined since the
-// methods are performance sensitive.
-//
-// The class is not thread-safe, unless only const methods are called. The
-// parameter block may also hold a pointer to a local parameterization; the
-// parameter block does not take ownership of this pointer, so the user is
-// responsible for the proper disposal of the local parameterization.
-class ParameterBlock {
- public:
- // TODO(keir): Decide what data structure is best here. Should this be a set?
- // Probably not, because sets are memory inefficient. However, if it's a
- // vector, you can get into pathological linear performance when removing a
- // residual block from a problem where all the residual blocks depend on one
- // parameter; for example, shared focal length in a bundle adjustment
- // problem. It might be worth making a custom structure that is just an array
- // when it is small, but transitions to a hash set when it has more elements.
- //
- // For now, use a hash set.
- typedef HashSet<ResidualBlock*> ResidualBlockSet;
-
- // Create a parameter block with the user state, size, and index specified.
- // The size is the size of the parameter block and the index is the position
- // of the parameter block inside a Program (if any).
- ParameterBlock(double* user_state, int size, int index) {
- Init(user_state, size, index, NULL);
- }
-
- ParameterBlock(double* user_state,
- int size,
- int index,
- LocalParameterization* local_parameterization) {
- Init(user_state, size, index, local_parameterization);
- }
-
- // The size of the parameter block.
- int Size() const { return size_; }
-
- // Manipulate the parameter state.
- bool SetState(const double* x) {
- CHECK(x != NULL)
- << "Tried to set the state of constant parameter "
- << "with user location " << user_state_;
- CHECK(!is_constant_)
- << "Tried to set the state of constant parameter "
- << "with user location " << user_state_;
-
- state_ = x;
- return UpdateLocalParameterizationJacobian();
- }
-
- // Copy the current parameter state out to x. This is "GetState()" rather than
- // simply "state()" since it is actively copying the data into the passed
- // pointer.
- void GetState(double *x) const {
- if (x != state_) {
- memcpy(x, state_, sizeof(*state_) * size_);
- }
- }
-
- // Direct pointers to the current state.
- const double* state() const { return state_; }
- const double* user_state() const { return user_state_; }
- double* mutable_user_state() { return user_state_; }
- LocalParameterization* local_parameterization() const {
- return local_parameterization_;
- }
- LocalParameterization* mutable_local_parameterization() {
- return local_parameterization_;
- }
-
- // Set this parameter block to vary or not.
- void SetConstant() { is_constant_ = true; }
- void SetVarying() { is_constant_ = false; }
- bool IsConstant() const { return is_constant_; }
-
- // This parameter block's index in an array.
- int index() const { return index_; }
- void set_index(int index) { index_ = index; }
-
- // This parameter offset inside a larger state vector.
- int state_offset() const { return state_offset_; }
- void set_state_offset(int state_offset) { state_offset_ = state_offset; }
-
- // This parameter offset inside a larger delta vector.
- int delta_offset() const { return delta_offset_; }
- void set_delta_offset(int delta_offset) { delta_offset_ = delta_offset; }
-
- // Methods relating to the parameter block's parameterization.
-
- // The local to global jacobian. Returns NULL if there is no local
- // parameterization for this parameter block. The returned matrix is row-major
- // and has Size() rows and LocalSize() columns.
- const double* LocalParameterizationJacobian() const {
- return local_parameterization_jacobian_.get();
- }
-
- int LocalSize() const {
- return (local_parameterization_ == NULL)
- ? size_
- : local_parameterization_->LocalSize();
- }
-
- // Set the parameterization. The parameterization can be set exactly once;
- // multiple calls to set the parameterization to different values will crash.
- // It is an error to pass NULL for the parameterization. The parameter block
- // does not take ownership of the parameterization.
- void SetParameterization(LocalParameterization* new_parameterization) {
- CHECK(new_parameterization != NULL) << "NULL parameterization invalid.";
- CHECK(new_parameterization->GlobalSize() == size_)
- << "Invalid parameterization for parameter block. The parameter block "
- << "has size " << size_ << " while the parameterization has a global "
- << "size of " << new_parameterization->GlobalSize() << ". Did you "
- << "accidentally use the wrong parameter block or parameterization?";
- if (new_parameterization != local_parameterization_) {
- CHECK(local_parameterization_ == NULL)
- << "Can't re-set the local parameterization; it leads to "
- << "ambiguous ownership.";
- local_parameterization_ = new_parameterization;
- local_parameterization_jacobian_.reset(
- new double[local_parameterization_->GlobalSize() *
- local_parameterization_->LocalSize()]);
- CHECK(UpdateLocalParameterizationJacobian())
- << "Local parameterization Jacobian computation failed for x: "
- << ConstVectorRef(state_, Size()).transpose();
- } else {
- // Ignore the case that the parameterizations match.
- }
- }
-
- void SetUpperBound(int index, double upper_bound) {
- CHECK_LT(index, size_);
-
- if (upper_bounds_.get() == NULL) {
- upper_bounds_.reset(new double[size_]);
- std::fill(upper_bounds_.get(),
- upper_bounds_.get() + size_,
- std::numeric_limits<double>::max());
- }
-
- upper_bounds_[index] = upper_bound;
- };
-
- void SetLowerBound(int index, double lower_bound) {
- CHECK_LT(index, size_);
-
- if (lower_bounds_.get() == NULL) {
- lower_bounds_.reset(new double[size_]);
- std::fill(lower_bounds_.get(),
- lower_bounds_.get() + size_,
- -std::numeric_limits<double>::max());
- }
-
- lower_bounds_[index] = lower_bound;
- }
-
- // Generalization of the addition operation. This is the same as
- // LocalParameterization::Plus() followed by projection onto the
- // hyper cube implied by the bounds constraints.
- bool Plus(const double *x, const double* delta, double* x_plus_delta) {
- if (local_parameterization_ != NULL) {
- if (!local_parameterization_->Plus(x, delta, x_plus_delta)) {
- return false;
- }
- } else {
- VectorRef(x_plus_delta, size_) = ConstVectorRef(x, size_) +
- ConstVectorRef(delta, size_);
- }
-
- // Project onto the box constraints.
- if (lower_bounds_.get() != NULL) {
- for (int i = 0; i < size_; ++i) {
- x_plus_delta[i] = std::max(x_plus_delta[i], lower_bounds_[i]);
- }
- }
-
- if (upper_bounds_.get() != NULL) {
- for (int i = 0; i < size_; ++i) {
- x_plus_delta[i] = std::min(x_plus_delta[i], upper_bounds_[i]);
- }
- }
-
- return true;
- }
-
- string ToString() const {
- return StringPrintf("{ user_state=%p, state=%p, size=%d, "
- "constant=%d, index=%d, state_offset=%d, "
- "delta_offset=%d }",
- user_state_,
- state_,
- size_,
- is_constant_,
- index_,
- state_offset_,
- delta_offset_);
- }
-
- void EnableResidualBlockDependencies() {
- CHECK(residual_blocks_.get() == NULL)
- << "Ceres bug: There is already a residual block collection "
- << "for parameter block: " << ToString();
- residual_blocks_.reset(new ResidualBlockSet);
- }
-
- void AddResidualBlock(ResidualBlock* residual_block) {
- CHECK(residual_blocks_.get() != NULL)
- << "Ceres bug: The residual block collection is null for parameter "
- << "block: " << ToString();
- residual_blocks_->insert(residual_block);
- }
-
- void RemoveResidualBlock(ResidualBlock* residual_block) {
- CHECK(residual_blocks_.get() != NULL)
- << "Ceres bug: The residual block collection is null for parameter "
- << "block: " << ToString();
- CHECK(residual_blocks_->find(residual_block) != residual_blocks_->end())
- << "Ceres bug: Missing residual for parameter block: " << ToString();
- residual_blocks_->erase(residual_block);
- }
-
- // This is only intended for iterating; perhaps this should only expose
- // .begin() and .end().
- ResidualBlockSet* mutable_residual_blocks() {
- return residual_blocks_.get();
- }
-
- double LowerBoundForParameter(int index) const {
- if (lower_bounds_.get() == NULL) {
- return -std::numeric_limits<double>::max();
- } else {
- return lower_bounds_[index];
- }
- }
-
- double UpperBoundForParameter(int index) const {
- if (upper_bounds_.get() == NULL) {
- return std::numeric_limits<double>::max();
- } else {
- return upper_bounds_[index];
- }
- }
-
- private:
- void Init(double* user_state,
- int size,
- int index,
- LocalParameterization* local_parameterization) {
- user_state_ = user_state;
- size_ = size;
- index_ = index;
- is_constant_ = false;
- state_ = user_state_;
-
- local_parameterization_ = NULL;
- if (local_parameterization != NULL) {
- SetParameterization(local_parameterization);
- }
-
- state_offset_ = -1;
- delta_offset_ = -1;
- }
-
- bool UpdateLocalParameterizationJacobian() {
- if (local_parameterization_ == NULL) {
- return true;
- }
-
- // Update the local to global Jacobian. In some cases this is
- // wasted effort; if this is a bottleneck, we will find a solution
- // at that time.
-
- const int jacobian_size = Size() * LocalSize();
- InvalidateArray(jacobian_size,
- local_parameterization_jacobian_.get());
- if (!local_parameterization_->ComputeJacobian(
- state_,
- local_parameterization_jacobian_.get())) {
- LOG(WARNING) << "Local parameterization Jacobian computation failed"
- "for x: " << ConstVectorRef(state_, Size()).transpose();
- return false;
- }
-
- if (!IsArrayValid(jacobian_size, local_parameterization_jacobian_.get())) {
- LOG(WARNING) << "Local parameterization Jacobian computation returned"
- << "an invalid matrix for x: "
- << ConstVectorRef(state_, Size()).transpose()
- << "\n Jacobian matrix : "
- << ConstMatrixRef(local_parameterization_jacobian_.get(),
- Size(),
- LocalSize());
- return false;
- }
- return true;
- }
-
- double* user_state_;
- int size_;
- bool is_constant_;
- LocalParameterization* local_parameterization_;
-
- // The "state" of the parameter. These fields are only needed while the
- // solver is running. While at first glance using mutable is a bad idea, this
- // ends up simplifying the internals of Ceres enough to justify the potential
- // pitfalls of using "mutable."
- mutable const double* state_;
- mutable scoped_array<double> local_parameterization_jacobian_;
-
- // The index of the parameter. This is used by various other parts of Ceres to
- // permit switching from a ParameterBlock* to an index in another array.
- int32 index_;
-
- // The offset of this parameter block inside a larger state vector.
- int32 state_offset_;
-
- // The offset of this parameter block inside a larger delta vector.
- int32 delta_offset_;
-
- // If non-null, contains the residual blocks this parameter block is in.
- scoped_ptr<ResidualBlockSet> residual_blocks_;
-
- // Upper and lower bounds for the parameter block. SetUpperBound
- // and SetLowerBound lazily initialize the upper_bounds_ and
- // lower_bounds_ arrays. If they are never called, then memory for
- // these arrays is never allocated. Thus for problems where there
- // are no bounds, or only one sided bounds we do not pay the cost of
- // allocating memory for the inactive bounds constraints.
- //
- // Upon initialization these arrays are initialized to
- // std::numeric_limits<double>::max() and
- // -std::numeric_limits<double>::max() respectively which correspond
- // to the parameter block being unconstrained.
- scoped_array<double> upper_bounds_;
- scoped_array<double> lower_bounds_;
-
- // Necessary so ProblemImpl can clean up the parameterizations.
- friend class ProblemImpl;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PARAMETER_BLOCK_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
deleted file mode 100644
index 1525de90d60..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/parameter_block_ordering.h"
-
-#include "ceres/graph.h"
-#include "ceres/graph_algorithms.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/map_util.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-int ComputeStableSchurOrdering(const Program& program,
- vector<ParameterBlock*>* ordering) {
- CHECK_NOTNULL(ordering)->clear();
- EventLogger event_logger("ComputeStableSchurOrdering");
- scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
- event_logger.AddEvent("CreateHessianGraph");
-
- const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
- const HashSet<ParameterBlock*>& vertices = graph->vertices();
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- if (vertices.count(parameter_blocks[i]) > 0) {
- ordering->push_back(parameter_blocks[i]);
- }
- }
- event_logger.AddEvent("Preordering");
-
- int independent_set_size = StableIndependentSetOrdering(*graph, ordering);
- event_logger.AddEvent("StableIndependentSet");
-
- // Add the excluded blocks to back of the ordering vector.
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- ParameterBlock* parameter_block = parameter_blocks[i];
- if (parameter_block->IsConstant()) {
- ordering->push_back(parameter_block);
- }
- }
- event_logger.AddEvent("ConstantParameterBlocks");
-
- return independent_set_size;
-}
-
-int ComputeSchurOrdering(const Program& program,
- vector<ParameterBlock*>* ordering) {
- CHECK_NOTNULL(ordering)->clear();
-
- scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
- int independent_set_size = IndependentSetOrdering(*graph, ordering);
- const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
-
- // Add the excluded blocks to back of the ordering vector.
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- ParameterBlock* parameter_block = parameter_blocks[i];
- if (parameter_block->IsConstant()) {
- ordering->push_back(parameter_block);
- }
- }
-
- return independent_set_size;
-}
-
-void ComputeRecursiveIndependentSetOrdering(const Program& program,
- ParameterBlockOrdering* ordering) {
- CHECK_NOTNULL(ordering)->Clear();
- const vector<ParameterBlock*> parameter_blocks = program.parameter_blocks();
- scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
-
- int num_covered = 0;
- int round = 0;
- while (num_covered < parameter_blocks.size()) {
- vector<ParameterBlock*> independent_set_ordering;
- const int independent_set_size =
- IndependentSetOrdering(*graph, &independent_set_ordering);
- for (int i = 0; i < independent_set_size; ++i) {
- ParameterBlock* parameter_block = independent_set_ordering[i];
- ordering->AddElementToGroup(parameter_block->mutable_user_state(), round);
- graph->RemoveVertex(parameter_block);
- }
- num_covered += independent_set_size;
- ++round;
- }
-}
-
-Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
- Graph<ParameterBlock*>* graph = CHECK_NOTNULL(new Graph<ParameterBlock*>);
- const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- ParameterBlock* parameter_block = parameter_blocks[i];
- if (!parameter_block->IsConstant()) {
- graph->AddVertex(parameter_block);
- }
- }
-
- const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
- for (int i = 0; i < residual_blocks.size(); ++i) {
- const ResidualBlock* residual_block = residual_blocks[i];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- ParameterBlock* const* parameter_blocks =
- residual_block->parameter_blocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- if (parameter_blocks[j]->IsConstant()) {
- continue;
- }
-
- for (int k = j + 1; k < num_parameter_blocks; ++k) {
- if (parameter_blocks[k]->IsConstant()) {
- continue;
- }
-
- graph->AddEdge(parameter_blocks[j], parameter_blocks[k]);
- }
- }
- }
-
- return graph;
-}
-
-void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
- vector<int>* group_sizes) {
- CHECK_NOTNULL(group_sizes)->clear();
- if (ordering == NULL) {
- return;
- }
-
- const map<int, set<double*> >& group_to_elements =
- ordering->group_to_elements();
- for (map<int, set<double*> >::const_iterator it = group_to_elements.begin();
- it != group_to_elements.end();
- ++it) {
- group_sizes->push_back(it->second.size());
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
deleted file mode 100644
index 5de99511138..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
-#define CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
-
-#include <vector>
-#include "ceres/ordered_groups.h"
-#include "ceres/graph.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class Program;
-class ParameterBlock;
-
-// Uses an approximate independent set ordering to order the parameter
-// blocks of a problem so that it is suitable for use with Schur
-// complement based solvers. The output variable ordering contains an
-// ordering of the parameter blocks and the return value is size of
-// the independent set or the number of e_blocks (see
-// schur_complement_solver.h for an explanation). Constant parameters
-// are added to the end.
-//
-// The ordering vector has the structure
-//
-// ordering = [independent set,
-// complement of the independent set,
-// fixed blocks]
-int ComputeSchurOrdering(const Program& program,
- vector<ParameterBlock* >* ordering);
-
-// Same as above, except that ties while computing the independent set
-// ordering are resolved in favour of the order in which the parameter
-// blocks occur in the program.
-int ComputeStableSchurOrdering(const Program& program,
- vector<ParameterBlock* >* ordering);
-
-// Use an approximate independent set ordering to decompose the
-// parameter blocks of a problem in a sequence of independent
-// sets. The ordering covers all the non-constant parameter blocks in
-// the program.
-void ComputeRecursiveIndependentSetOrdering(const Program& program,
- ParameterBlockOrdering* ordering);
-
-// Builds a graph on the parameter blocks of a Problem, whose
-// structure reflects the sparsity structure of the Hessian. Each
-// vertex corresponds to a parameter block in the Problem except for
-// parameter blocks that are marked constant. An edge connects two
-// parameter blocks, if they co-occur in a residual block.
-Graph<ParameterBlock*>* CreateHessianGraph(const Program& program);
-
-// Iterate over each of the groups in order of their priority and fill
-// summary with their sizes.
-void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
- vector<int>* group_sizes);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc b/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc
deleted file mode 100644
index d745a9b358d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of PartitionedMatrixView.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_partitioned_matrix_view_specializations.py.
-// Editing it manually is not recommended.
-
-#include "ceres/linear_solver.h"
-#include "ceres/partitioned_matrix_view.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-PartitionedMatrixViewBase*
-PartitionedMatrixViewBase::Create(const LinearSolver::Options& options,
- const BlockSparseMatrix& matrix) {
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 2)) {
- return new PartitionedMatrixView<2, 2, 2>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<2, 2, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<2, 2, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, 2, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<2, 3, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<2, 3, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 9)) {
- return new PartitionedMatrixView<2, 3, 9>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, 3, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<2, 4, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<2, 4, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 8)) {
- return new PartitionedMatrixView<2, 4, 8>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 9)) {
- return new PartitionedMatrixView<2, 4, 9>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, 4, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 2)) {
- return new PartitionedMatrixView<4, 4, 2>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new PartitionedMatrixView<4, 4, 3>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new PartitionedMatrixView<4, 4, 4>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<4, 4, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
- if ((options.row_block_size == Eigen::Dynamic) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
- }
-
-#endif
- VLOG(1) << "Template specializations not found for <"
- << options.row_block_size << ","
- << options.e_block_size << ","
- << options.f_block_size << ">";
- return new PartitionedMatrixView<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
- matrix, options.elimination_groups[0]);
-};
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.h b/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.h
deleted file mode 100644
index 661252d404f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// For generalized bi-partite Jacobian matrices that arise in
-// Structure from Motion related problems, it is sometimes useful to
-// have access to the two parts of the matrix as linear operators
-// themselves. This class provides that functionality.
-
-#ifndef CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
-#define CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
-
-#include <algorithm>
-#include <cstring>
-#include <vector>
-
-#include "ceres/block_structure.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_solver.h"
-#include "ceres/small_blas.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// Given generalized bi-partite matrix A = [E F], with the same block
-// structure as required by the Schur complement based solver, found
-// in explicit_schur_complement_solver.h, provide access to the
-// matrices E and F and their outer products E'E and F'F with
-// themselves.
-//
-// Lack of BlockStructure object will result in a crash and if the
-// block structure of the matrix does not satisfy the requirements of
-// the Schur complement solver it will result in unpredictable and
-// wrong output.
-class PartitionedMatrixViewBase {
- public:
- virtual ~PartitionedMatrixViewBase() {}
-
- // y += E'x
- virtual void LeftMultiplyE(const double* x, double* y) const = 0;
-
- // y += F'x
- virtual void LeftMultiplyF(const double* x, double* y) const = 0;
-
- // y += Ex
- virtual void RightMultiplyE(const double* x, double* y) const = 0;
-
- // y += Fx
- virtual void RightMultiplyF(const double* x, double* y) const = 0;
-
- // Create and return the block diagonal of the matrix E'E.
- virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const = 0;
-
- // Create and return the block diagonal of the matrix F'F. Caller
- // owns the result.
- virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const = 0;
-
- // Compute the block diagonal of the matrix E'E and store it in
- // block_diagonal. The matrix block_diagonal is expected to have a
- // BlockStructure (preferably created using
- // CreateBlockDiagonalMatrixEtE) which is has the same structure as
- // the block diagonal of E'E.
- virtual void UpdateBlockDiagonalEtE(
- BlockSparseMatrix* block_diagonal) const = 0;
-
- // Compute the block diagonal of the matrix F'F and store it in
- // block_diagonal. The matrix block_diagonal is expected to have a
- // BlockStructure (preferably created using
- // CreateBlockDiagonalMatrixFtF) which is has the same structure as
- // the block diagonal of F'F.
- virtual void UpdateBlockDiagonalFtF(
- BlockSparseMatrix* block_diagonal) const = 0;
-
- virtual int num_col_blocks_e() const = 0;
- virtual int num_col_blocks_f() const = 0;
- virtual int num_cols_e() const = 0;
- virtual int num_cols_f() const = 0;
- virtual int num_rows() const = 0;
- virtual int num_cols() const = 0;
-
- static PartitionedMatrixViewBase* Create(const LinearSolver::Options& options,
- const BlockSparseMatrix& matrix);
-};
-
-template <int kRowBlockSize = Eigen::Dynamic,
- int kEBlockSize = Eigen::Dynamic,
- int kFBlockSize = Eigen::Dynamic >
-class PartitionedMatrixView : public PartitionedMatrixViewBase {
- public:
- // matrix = [E F], where the matrix E contains the first
- // num_col_blocks_a column blocks.
- PartitionedMatrixView(const BlockSparseMatrix& matrix, int num_col_blocks_e);
-
- virtual ~PartitionedMatrixView();
- virtual void LeftMultiplyE(const double* x, double* y) const;
- virtual void LeftMultiplyF(const double* x, double* y) const;
- virtual void RightMultiplyE(const double* x, double* y) const;
- virtual void RightMultiplyF(const double* x, double* y) const;
- virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const;
- virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const;
- virtual void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const;
- virtual void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const;
- virtual int num_col_blocks_e() const { return num_col_blocks_e_; }
- virtual int num_col_blocks_f() const { return num_col_blocks_f_; }
- virtual int num_cols_e() const { return num_cols_e_; }
- virtual int num_cols_f() const { return num_cols_f_; }
- virtual int num_rows() const { return matrix_.num_rows(); }
- virtual int num_cols() const { return matrix_.num_cols(); }
-
- private:
- BlockSparseMatrix* CreateBlockDiagonalMatrixLayout(int start_col_block,
- int end_col_block) const;
-
- const BlockSparseMatrix& matrix_;
- int num_row_blocks_e_;
- int num_col_blocks_e_;
- int num_col_blocks_f_;
- int num_cols_e_;
- int num_cols_f_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h b/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h
deleted file mode 100644
index ae7f776e6b1..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h
+++ /dev/null
@@ -1,380 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/partitioned_matrix_view.h"
-
-#include <algorithm>
-#include <cstring>
-#include <vector>
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/small_blas.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-PartitionedMatrixView(
- const BlockSparseMatrix& matrix,
- int num_col_blocks_e)
- : matrix_(matrix),
- num_col_blocks_e_(num_col_blocks_e) {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
- CHECK_NOTNULL(bs);
-
- num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
-
- // Compute the number of row blocks in E. The number of row blocks
- // in E maybe less than the number of row blocks in the input matrix
- // as some of the row blocks at the bottom may not have any
- // e_blocks. For a definition of what an e_block is, please see
- // explicit_schur_complement_solver.h
- num_row_blocks_e_ = 0;
- for (int r = 0; r < bs->rows.size(); ++r) {
- const vector<Cell>& cells = bs->rows[r].cells;
- if (cells[0].block_id < num_col_blocks_e_) {
- ++num_row_blocks_e_;
- }
- }
-
- // Compute the number of columns in E and F.
- num_cols_e_ = 0;
- num_cols_f_ = 0;
-
- for (int c = 0; c < bs->cols.size(); ++c) {
- const Block& block = bs->cols[c];
- if (c < num_col_blocks_e_) {
- num_cols_e_ += block.size;
- } else {
- num_cols_f_ += block.size;
- }
- }
-
- CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-~PartitionedMatrixView() {
-}
-
-// The next four methods don't seem to be particularly cache
-// friendly. This is an artifact of how the BlockStructure of the
-// input matrix is constructed. These methods will benefit from
-// multithreading as well as improved data layout.
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-RightMultiplyE(const double* x, double* y) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
- // Iterate over the first num_row_blocks_e_ row blocks, and multiply
- // by the first cell in each row block.
- const double* values = matrix_.values();
- for (int r = 0; r < num_row_blocks_e_; ++r) {
- const Cell& cell = bs->rows[r].cells[0];
- const int row_block_pos = bs->rows[r].block.position;
- const int row_block_size = bs->rows[r].block.size;
- const int col_block_id = cell.block_id;
- const int col_block_pos = bs->cols[col_block_id].position;
- const int col_block_size = bs->cols[col_block_id].size;
- MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
- values + cell.position, row_block_size, col_block_size,
- x + col_block_pos,
- y + row_block_pos);
- }
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-RightMultiplyF(const double* x, double* y) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
- // Iterate over row blocks, and if the row block is in E, then
- // multiply by all the cells except the first one which is of type
- // E. If the row block is not in E (i.e its in the bottom
- // num_row_blocks - num_row_blocks_e row blocks), then all the cells
- // are of type F and multiply by them all.
- const double* values = matrix_.values();
- for (int r = 0; r < num_row_blocks_e_; ++r) {
- const int row_block_pos = bs->rows[r].block.position;
- const int row_block_size = bs->rows[r].block.size;
- const vector<Cell>& cells = bs->rows[r].cells;
- for (int c = 1; c < cells.size(); ++c) {
- const int col_block_id = cells[c].block_id;
- const int col_block_pos = bs->cols[col_block_id].position;
- const int col_block_size = bs->cols[col_block_id].size;
- MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
- values + cells[c].position, row_block_size, col_block_size,
- x + col_block_pos - num_cols_e_,
- y + row_block_pos);
- }
- }
-
- for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
- const int row_block_pos = bs->rows[r].block.position;
- const int row_block_size = bs->rows[r].block.size;
- const vector<Cell>& cells = bs->rows[r].cells;
- for (int c = 0; c < cells.size(); ++c) {
- const int col_block_id = cells[c].block_id;
- const int col_block_pos = bs->cols[col_block_id].position;
- const int col_block_size = bs->cols[col_block_id].size;
- MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- values + cells[c].position, row_block_size, col_block_size,
- x + col_block_pos - num_cols_e_,
- y + row_block_pos);
- }
- }
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-LeftMultiplyE(const double* x, double* y) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
- // Iterate over the first num_row_blocks_e_ row blocks, and multiply
- // by the first cell in each row block.
- const double* values = matrix_.values();
- for (int r = 0; r < num_row_blocks_e_; ++r) {
- const Cell& cell = bs->rows[r].cells[0];
- const int row_block_pos = bs->rows[r].block.position;
- const int row_block_size = bs->rows[r].block.size;
- const int col_block_id = cell.block_id;
- const int col_block_pos = bs->cols[col_block_id].position;
- const int col_block_size = bs->cols[col_block_id].size;
- MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
- values + cell.position, row_block_size, col_block_size,
- x + row_block_pos,
- y + col_block_pos);
- }
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-LeftMultiplyF(const double* x, double* y) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
- // Iterate over row blocks, and if the row block is in E, then
- // multiply by all the cells except the first one which is of type
- // E. If the row block is not in E (i.e its in the bottom
- // num_row_blocks - num_row_blocks_e row blocks), then all the cells
- // are of type F and multiply by them all.
- const double* values = matrix_.values();
- for (int r = 0; r < num_row_blocks_e_; ++r) {
- const int row_block_pos = bs->rows[r].block.position;
- const int row_block_size = bs->rows[r].block.size;
- const vector<Cell>& cells = bs->rows[r].cells;
- for (int c = 1; c < cells.size(); ++c) {
- const int col_block_id = cells[c].block_id;
- const int col_block_pos = bs->cols[col_block_id].position;
- const int col_block_size = bs->cols[col_block_id].size;
- MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
- values + cells[c].position, row_block_size, col_block_size,
- x + row_block_pos,
- y + col_block_pos - num_cols_e_);
- }
- }
-
- for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
- const int row_block_pos = bs->rows[r].block.position;
- const int row_block_size = bs->rows[r].block.size;
- const vector<Cell>& cells = bs->rows[r].cells;
- for (int c = 0; c < cells.size(); ++c) {
- const int col_block_id = cells[c].block_id;
- const int col_block_pos = bs->cols[col_block_id].position;
- const int col_block_size = bs->cols[col_block_id].size;
- MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- values + cells[c].position, row_block_size, col_block_size,
- x + row_block_pos,
- y + col_block_pos - num_cols_e_);
- }
- }
-}
-
-// Given a range of columns blocks of a matrix m, compute the block
-// structure of the block diagonal of the matrix m(:,
-// start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
-// and return a BlockSparseMatrix with the this block structure. The
-// caller owns the result.
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-BlockSparseMatrix*
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-CreateBlockDiagonalMatrixLayout(int start_col_block, int end_col_block) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
- CompressedRowBlockStructure* block_diagonal_structure =
- new CompressedRowBlockStructure;
-
- int block_position = 0;
- int diagonal_cell_position = 0;
-
- // Iterate over the column blocks, creating a new diagonal block for
- // each column block.
- for (int c = start_col_block; c < end_col_block; ++c) {
- const Block& block = bs->cols[c];
- block_diagonal_structure->cols.push_back(Block());
- Block& diagonal_block = block_diagonal_structure->cols.back();
- diagonal_block.size = block.size;
- diagonal_block.position = block_position;
-
- block_diagonal_structure->rows.push_back(CompressedRow());
- CompressedRow& row = block_diagonal_structure->rows.back();
- row.block = diagonal_block;
-
- row.cells.push_back(Cell());
- Cell& cell = row.cells.back();
- cell.block_id = c - start_col_block;
- cell.position = diagonal_cell_position;
-
- block_position += block.size;
- diagonal_cell_position += block.size * block.size;
- }
-
- // Build a BlockSparseMatrix with the just computed block
- // structure.
- return new BlockSparseMatrix(block_diagonal_structure);
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-BlockSparseMatrix*
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-CreateBlockDiagonalEtE() const {
- BlockSparseMatrix* block_diagonal =
- CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
- UpdateBlockDiagonalEtE(block_diagonal);
- return block_diagonal;
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-BlockSparseMatrix*
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-CreateBlockDiagonalFtF() const {
- BlockSparseMatrix* block_diagonal =
- CreateBlockDiagonalMatrixLayout(
- num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
- UpdateBlockDiagonalFtF(block_diagonal);
- return block_diagonal;
-}
-
-// Similar to the code in RightMultiplyE, except instead of the matrix
-// vector multiply its an outer product.
-//
-// block_diagonal = block_diagonal(E'E)
-//
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-UpdateBlockDiagonalEtE(
- BlockSparseMatrix* block_diagonal) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
- const CompressedRowBlockStructure* block_diagonal_structure =
- block_diagonal->block_structure();
-
- block_diagonal->SetZero();
- const double* values = matrix_.values();
- for (int r = 0; r < num_row_blocks_e_ ; ++r) {
- const Cell& cell = bs->rows[r].cells[0];
- const int row_block_size = bs->rows[r].block.size;
- const int block_id = cell.block_id;
- const int col_block_size = bs->cols[block_id].size;
- const int cell_position =
- block_diagonal_structure->rows[block_id].cells[0].position;
-
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
- values + cell.position, row_block_size, col_block_size,
- values + cell.position, row_block_size, col_block_size,
- block_diagonal->mutable_values() + cell_position,
- 0, 0, col_block_size, col_block_size);
- }
-}
-
-// Similar to the code in RightMultiplyF, except instead of the matrix
-// vector multiply its an outer product.
-//
-// block_diagonal = block_diagonal(F'F)
-//
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
- const CompressedRowBlockStructure* bs = matrix_.block_structure();
- const CompressedRowBlockStructure* block_diagonal_structure =
- block_diagonal->block_structure();
-
- block_diagonal->SetZero();
- const double* values = matrix_.values();
- for (int r = 0; r < num_row_blocks_e_; ++r) {
- const int row_block_size = bs->rows[r].block.size;
- const vector<Cell>& cells = bs->rows[r].cells;
- for (int c = 1; c < cells.size(); ++c) {
- const int col_block_id = cells[c].block_id;
- const int col_block_size = bs->cols[col_block_id].size;
- const int diagonal_block_id = col_block_id - num_col_blocks_e_;
- const int cell_position =
- block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
-
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
- values + cells[c].position, row_block_size, col_block_size,
- values + cells[c].position, row_block_size, col_block_size,
- block_diagonal->mutable_values() + cell_position,
- 0, 0, col_block_size, col_block_size);
- }
- }
-
- for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
- const int row_block_size = bs->rows[r].block.size;
- const vector<Cell>& cells = bs->rows[r].cells;
- for (int c = 0; c < cells.size(); ++c) {
- const int col_block_id = cells[c].block_id;
- const int col_block_size = bs->cols[col_block_id].size;
- const int diagonal_block_id = col_block_id - num_col_blocks_e_;
- const int cell_position =
- block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
-
- MatrixTransposeMatrixMultiply
- <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
- values + cells[c].position, row_block_size, col_block_size,
- values + cells[c].position, row_block_size, col_block_size,
- block_diagonal->mutable_values() + cell_position,
- 0, 0, col_block_size, col_block_size);
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc
deleted file mode 100644
index 75f43de409a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc
+++ /dev/null
@@ -1,394 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: moll.markus@arcor.de (Markus Moll)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/polynomial.h"
-
-#include <cmath>
-#include <cstddef>
-#include <vector>
-
-#include "Eigen/Dense"
-#include "ceres/internal/port.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-// Balancing function as described by B. N. Parlett and C. Reinsch,
-// "Balancing a Matrix for Calculation of Eigenvalues and Eigenvectors".
-// In: Numerische Mathematik, Volume 13, Number 4 (1969), 293-304,
-// Springer Berlin / Heidelberg. DOI: 10.1007/BF02165404
-void BalanceCompanionMatrix(Matrix* companion_matrix_ptr) {
- CHECK_NOTNULL(companion_matrix_ptr);
- Matrix& companion_matrix = *companion_matrix_ptr;
- Matrix companion_matrix_offdiagonal = companion_matrix;
- companion_matrix_offdiagonal.diagonal().setZero();
-
- const int degree = companion_matrix.rows();
-
- // gamma <= 1 controls how much a change in the scaling has to
- // lower the 1-norm of the companion matrix to be accepted.
- //
- // gamma = 1 seems to lead to cycles (numerical issues?), so
- // we set it slightly lower.
- const double gamma = 0.9;
-
- // Greedily scale row/column pairs until there is no change.
- bool scaling_has_changed;
- do {
- scaling_has_changed = false;
-
- for (int i = 0; i < degree; ++i) {
- const double row_norm = companion_matrix_offdiagonal.row(i).lpNorm<1>();
- const double col_norm = companion_matrix_offdiagonal.col(i).lpNorm<1>();
-
- // Decompose row_norm/col_norm into mantissa * 2^exponent,
- // where 0.5 <= mantissa < 1. Discard mantissa (return value
- // of frexp), as only the exponent is needed.
- int exponent = 0;
- std::frexp(row_norm / col_norm, &exponent);
- exponent /= 2;
-
- if (exponent != 0) {
- const double scaled_col_norm = std::ldexp(col_norm, exponent);
- const double scaled_row_norm = std::ldexp(row_norm, -exponent);
- if (scaled_col_norm + scaled_row_norm < gamma * (col_norm + row_norm)) {
- // Accept the new scaling. (Multiplication by powers of 2 should not
- // introduce rounding errors (ignoring non-normalized numbers and
- // over- or underflow))
- scaling_has_changed = true;
- companion_matrix_offdiagonal.row(i) *= std::ldexp(1.0, -exponent);
- companion_matrix_offdiagonal.col(i) *= std::ldexp(1.0, exponent);
- }
- }
- }
- } while (scaling_has_changed);
-
- companion_matrix_offdiagonal.diagonal() = companion_matrix.diagonal();
- companion_matrix = companion_matrix_offdiagonal;
- VLOG(3) << "Balanced companion matrix is\n" << companion_matrix;
-}
-
-void BuildCompanionMatrix(const Vector& polynomial,
- Matrix* companion_matrix_ptr) {
- CHECK_NOTNULL(companion_matrix_ptr);
- Matrix& companion_matrix = *companion_matrix_ptr;
-
- const int degree = polynomial.size() - 1;
-
- companion_matrix.resize(degree, degree);
- companion_matrix.setZero();
- companion_matrix.diagonal(-1).setOnes();
- companion_matrix.col(degree - 1) = -polynomial.reverse().head(degree);
-}
-
-// Remove leading terms with zero coefficients.
-Vector RemoveLeadingZeros(const Vector& polynomial_in) {
- int i = 0;
- while (i < (polynomial_in.size() - 1) && polynomial_in(i) == 0.0) {
- ++i;
- }
- return polynomial_in.tail(polynomial_in.size() - i);
-}
-
-void FindLinearPolynomialRoots(const Vector& polynomial,
- Vector* real,
- Vector* imaginary) {
- CHECK_EQ(polynomial.size(), 2);
- if (real != NULL) {
- real->resize(1);
- (*real)(0) = -polynomial(1) / polynomial(0);
- }
-
- if (imaginary != NULL) {
- imaginary->setZero(1);
- }
-}
-
-void FindQuadraticPolynomialRoots(const Vector& polynomial,
- Vector* real,
- Vector* imaginary) {
- CHECK_EQ(polynomial.size(), 3);
- const double a = polynomial(0);
- const double b = polynomial(1);
- const double c = polynomial(2);
- const double D = b * b - 4 * a * c;
- const double sqrt_D = sqrt(fabs(D));
- if (real != NULL) {
- real->setZero(2);
- }
- if (imaginary != NULL) {
- imaginary->setZero(2);
- }
-
- // Real roots.
- if (D >= 0) {
- if (real != NULL) {
- // Stable quadratic roots according to BKP Horn.
- // http://people.csail.mit.edu/bkph/articles/Quadratics.pdf
- if (b >= 0) {
- (*real)(0) = (-b - sqrt_D) / (2.0 * a);
- (*real)(1) = (2.0 * c) / (-b - sqrt_D);
- } else {
- (*real)(0) = (2.0 * c) / (-b + sqrt_D);
- (*real)(1) = (-b + sqrt_D) / (2.0 * a);
- }
- }
- return;
- }
-
- // Use the normal quadratic formula for the complex case.
- if (real != NULL) {
- (*real)(0) = -b / (2.0 * a);
- (*real)(1) = -b / (2.0 * a);
- }
- if (imaginary != NULL) {
- (*imaginary)(0) = sqrt_D / (2.0 * a);
- (*imaginary)(1) = -sqrt_D / (2.0 * a);
- }
-}
-} // namespace
-
-bool FindPolynomialRoots(const Vector& polynomial_in,
- Vector* real,
- Vector* imaginary) {
- if (polynomial_in.size() == 0) {
- LOG(ERROR) << "Invalid polynomial of size 0 passed to FindPolynomialRoots";
- return false;
- }
-
- Vector polynomial = RemoveLeadingZeros(polynomial_in);
- const int degree = polynomial.size() - 1;
-
- VLOG(3) << "Input polynomial: " << polynomial_in.transpose();
- if (polynomial.size() != polynomial_in.size()) {
- VLOG(3) << "Trimmed polynomial: " << polynomial.transpose();
- }
-
- // Is the polynomial constant?
- if (degree == 0) {
- LOG(WARNING) << "Trying to extract roots from a constant "
- << "polynomial in FindPolynomialRoots";
- // We return true with no roots, not false, as if the polynomial is constant
- // it is correct that there are no roots. It is not the case that they were
- // there, but that we have failed to extract them.
- return true;
- }
-
- // Linear
- if (degree == 1) {
- FindLinearPolynomialRoots(polynomial, real, imaginary);
- return true;
- }
-
- // Quadratic
- if (degree == 2) {
- FindQuadraticPolynomialRoots(polynomial, real, imaginary);
- return true;
- }
-
- // The degree is now known to be at least 3. For cubic or higher
- // roots we use the method of companion matrices.
-
- // Divide by leading term
- const double leading_term = polynomial(0);
- polynomial /= leading_term;
-
- // Build and balance the companion matrix to the polynomial.
- Matrix companion_matrix(degree, degree);
- BuildCompanionMatrix(polynomial, &companion_matrix);
- BalanceCompanionMatrix(&companion_matrix);
-
- // Find its (complex) eigenvalues.
- Eigen::EigenSolver<Matrix> solver(companion_matrix, false);
- if (solver.info() != Eigen::Success) {
- LOG(ERROR) << "Failed to extract eigenvalues from companion matrix.";
- return false;
- }
-
- // Output roots
- if (real != NULL) {
- *real = solver.eigenvalues().real();
- } else {
- LOG(WARNING) << "NULL pointer passed as real argument to "
- << "FindPolynomialRoots. Real parts of the roots will not "
- << "be returned.";
- }
- if (imaginary != NULL) {
- *imaginary = solver.eigenvalues().imag();
- }
- return true;
-}
-
-Vector DifferentiatePolynomial(const Vector& polynomial) {
- const int degree = polynomial.rows() - 1;
- CHECK_GE(degree, 0);
-
- // Degree zero polynomials are constants, and their derivative does
- // not result in a smaller degree polynomial, just a degree zero
- // polynomial with value zero.
- if (degree == 0) {
- return Eigen::VectorXd::Zero(1);
- }
-
- Vector derivative(degree);
- for (int i = 0; i < degree; ++i) {
- derivative(i) = (degree - i) * polynomial(i);
- }
-
- return derivative;
-}
-
-void MinimizePolynomial(const Vector& polynomial,
- const double x_min,
- const double x_max,
- double* optimal_x,
- double* optimal_value) {
- // Find the minimum of the polynomial at the two ends.
- //
- // We start by inspecting the middle of the interval. Technically
- // this is not needed, but we do this to make this code as close to
- // the minFunc package as possible.
- *optimal_x = (x_min + x_max) / 2.0;
- *optimal_value = EvaluatePolynomial(polynomial, *optimal_x);
-
- const double x_min_value = EvaluatePolynomial(polynomial, x_min);
- if (x_min_value < *optimal_value) {
- *optimal_value = x_min_value;
- *optimal_x = x_min;
- }
-
- const double x_max_value = EvaluatePolynomial(polynomial, x_max);
- if (x_max_value < *optimal_value) {
- *optimal_value = x_max_value;
- *optimal_x = x_max;
- }
-
- // If the polynomial is linear or constant, we are done.
- if (polynomial.rows() <= 2) {
- return;
- }
-
- const Vector derivative = DifferentiatePolynomial(polynomial);
- Vector roots_real;
- if (!FindPolynomialRoots(derivative, &roots_real, NULL)) {
- LOG(WARNING) << "Unable to find the critical points of "
- << "the interpolating polynomial.";
- return;
- }
-
- // This is a bit of an overkill, as some of the roots may actually
- // have a complex part, but its simpler to just check these values.
- for (int i = 0; i < roots_real.rows(); ++i) {
- const double root = roots_real(i);
- if ((root < x_min) || (root > x_max)) {
- continue;
- }
-
- const double value = EvaluatePolynomial(polynomial, root);
- if (value < *optimal_value) {
- *optimal_value = value;
- *optimal_x = root;
- }
- }
-}
-
-string FunctionSample::ToDebugString() const {
- return StringPrintf("[x: %.8e, value: %.8e, gradient: %.8e, "
- "value_is_valid: %d, gradient_is_valid: %d]",
- x, value, gradient, value_is_valid, gradient_is_valid);
-}
-
-Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples) {
- const int num_samples = samples.size();
- int num_constraints = 0;
- for (int i = 0; i < num_samples; ++i) {
- if (samples[i].value_is_valid) {
- ++num_constraints;
- }
- if (samples[i].gradient_is_valid) {
- ++num_constraints;
- }
- }
-
- const int degree = num_constraints - 1;
-
- Matrix lhs = Matrix::Zero(num_constraints, num_constraints);
- Vector rhs = Vector::Zero(num_constraints);
-
- int row = 0;
- for (int i = 0; i < num_samples; ++i) {
- const FunctionSample& sample = samples[i];
- if (sample.value_is_valid) {
- for (int j = 0; j <= degree; ++j) {
- lhs(row, j) = pow(sample.x, degree - j);
- }
- rhs(row) = sample.value;
- ++row;
- }
-
- if (sample.gradient_is_valid) {
- for (int j = 0; j < degree; ++j) {
- lhs(row, j) = (degree - j) * pow(sample.x, degree - j - 1);
- }
- rhs(row) = sample.gradient;
- ++row;
- }
- }
-
- return lhs.fullPivLu().solve(rhs);
-}
-
-void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
- double x_min,
- double x_max,
- double* optimal_x,
- double* optimal_value) {
- const Vector polynomial = FindInterpolatingPolynomial(samples);
- MinimizePolynomial(polynomial, x_min, x_max, optimal_x, optimal_value);
- for (int i = 0; i < samples.size(); ++i) {
- const FunctionSample& sample = samples[i];
- if ((sample.x < x_min) || (sample.x > x_max)) {
- continue;
- }
-
- const double value = EvaluatePolynomial(polynomial, sample.x);
- if (value < *optimal_value) {
- *optimal_x = sample.x;
- *optimal_value = value;
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial.h b/extern/libmv/third_party/ceres/internal/ceres/polynomial.h
deleted file mode 100644
index 80ce77e6ae1..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/polynomial.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: moll.markus@arcor.de (Markus Moll)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
-#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
-
-#include <vector>
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-// All polynomials are assumed to be the form
-//
-// sum_{i=0}^N polynomial(i) x^{N-i}.
-//
-// and are given by a vector of coefficients of size N + 1.
-
-// Evaluate the polynomial at x using the Horner scheme.
-inline double EvaluatePolynomial(const Vector& polynomial, double x) {
- double v = 0.0;
- for (int i = 0; i < polynomial.size(); ++i) {
- v = v * x + polynomial(i);
- }
- return v;
-}
-
-// Use the companion matrix eigenvalues to determine the roots of the
-// polynomial.
-//
-// This function returns true on success, false otherwise.
-// Failure indicates that the polynomial is invalid (of size 0) or
-// that the eigenvalues of the companion matrix could not be computed.
-// On failure, a more detailed message will be written to LOG(ERROR).
-// If real is not NULL, the real parts of the roots will be returned in it.
-// Likewise, if imaginary is not NULL, imaginary parts will be returned in it.
-bool FindPolynomialRoots(const Vector& polynomial,
- Vector* real,
- Vector* imaginary);
-
-// Return the derivative of the given polynomial. It is assumed that
-// the input polynomial is at least of degree zero.
-Vector DifferentiatePolynomial(const Vector& polynomial);
-
-// Find the minimum value of the polynomial in the interval [x_min,
-// x_max]. The minimum is obtained by computing all the roots of the
-// derivative of the input polynomial. All real roots within the
-// interval [x_min, x_max] are considered as well as the end points
-// x_min and x_max. Since polynomials are differentiable functions,
-// this ensures that the true minimum is found.
-void MinimizePolynomial(const Vector& polynomial,
- double x_min,
- double x_max,
- double* optimal_x,
- double* optimal_value);
-
-// Structure for storing sample values of a function.
-//
-// Clients can use this struct to communicate the value of the
-// function and or its gradient at a given point x.
-struct FunctionSample {
- FunctionSample()
- : x(0.0),
- value(0.0),
- value_is_valid(false),
- gradient(0.0),
- gradient_is_valid(false) {
- }
- string ToDebugString() const;
-
- double x;
- double value; // value = f(x)
- bool value_is_valid;
- double gradient; // gradient = f'(x)
- bool gradient_is_valid;
-};
-
-// Given a set of function value and/or gradient samples, find a
-// polynomial whose value and gradients are exactly equal to the ones
-// in samples.
-//
-// Generally speaking,
-//
-// degree = # values + # gradients - 1
-//
-// Of course its possible to sample a polynomial any number of times,
-// in which case, generally speaking the spurious higher order
-// coefficients will be zero.
-Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples);
-
-// Interpolate the function described by samples with a polynomial,
-// and minimize it on the interval [x_min, x_max]. Depending on the
-// input samples, it is possible that the interpolation or the root
-// finding algorithms may fail due to numerical difficulties. But the
-// function is guaranteed to return its best guess of an answer, by
-// considering the samples and the end points as possible solutions.
-void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
- double x_min,
- double x_max,
- double* optimal_x,
- double* optimal_value);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc
deleted file mode 100644
index 062347fccc1..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/preconditioner.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-Preconditioner::~Preconditioner() {
-}
-
-PreconditionerType Preconditioner::PreconditionerForZeroEBlocks(
- PreconditionerType preconditioner_type) {
- if (preconditioner_type == SCHUR_JACOBI ||
- preconditioner_type == CLUSTER_JACOBI ||
- preconditioner_type == CLUSTER_TRIDIAGONAL) {
- return JACOBI;
- }
- return preconditioner_type;
-}
-
-SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
- const SparseMatrix* matrix)
- : matrix_(CHECK_NOTNULL(matrix)) {
-}
-
-SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {
-}
-
-bool SparseMatrixPreconditionerWrapper::UpdateImpl(const SparseMatrix& A,
- const double* D) {
- return true;
-}
-
-void SparseMatrixPreconditionerWrapper::RightMultiply(const double* x,
- double* y) const {
- matrix_->RightMultiply(x, y);
-}
-
-int SparseMatrixPreconditionerWrapper::num_rows() const {
- return matrix_->num_rows();
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h
deleted file mode 100644
index e8d5994269a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h
+++ /dev/null
@@ -1,177 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_PRECONDITIONER_H_
-#define CERES_INTERNAL_PRECONDITIONER_H_
-
-#include <vector>
-#include "ceres/casts.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/linear_operator.h"
-#include "ceres/sparse_matrix.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockSparseMatrix;
-class SparseMatrix;
-
-class Preconditioner : public LinearOperator {
- public:
- struct Options {
- Options()
- : type(JACOBI),
- visibility_clustering_type(CANONICAL_VIEWS),
- sparse_linear_algebra_library_type(SUITE_SPARSE),
- num_threads(1),
- row_block_size(Eigen::Dynamic),
- e_block_size(Eigen::Dynamic),
- f_block_size(Eigen::Dynamic) {
- }
-
- PreconditionerType type;
- VisibilityClusteringType visibility_clustering_type;
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type;
-
- // If possible, how many threads the preconditioner can use.
- int num_threads;
-
- // Hints about the order in which the parameter blocks should be
- // eliminated by the linear solver.
- //
- // For example if elimination_groups is a vector of size k, then
- // the linear solver is informed that it should eliminate the
- // parameter blocks 0 ... elimination_groups[0] - 1 first, and
- // then elimination_groups[0] ... elimination_groups[1] - 1 and so
- // on. Within each elimination group, the linear solver is free to
- // choose how the parameter blocks are ordered. Different linear
- // solvers have differing requirements on elimination_groups.
- //
- // The most common use is for Schur type solvers, where there
- // should be at least two elimination groups and the first
- // elimination group must form an independent set in the normal
- // equations. The first elimination group corresponds to the
- // num_eliminate_blocks in the Schur type solvers.
- vector<int> elimination_groups;
-
- // If the block sizes in a BlockSparseMatrix are fixed, then in
- // some cases the Schur complement based solvers can detect and
- // specialize on them.
- //
- // It is expected that these parameters are set programmatically
- // rather than manually.
- //
- // Please see schur_complement_solver.h and schur_eliminator.h for
- // more details.
- int row_block_size;
- int e_block_size;
- int f_block_size;
- };
-
- // If the optimization problem is such that there are no remaining
- // e-blocks, ITERATIVE_SCHUR with a Schur type preconditioner cannot
- // be used. This function returns JACOBI if a preconditioner for
- // ITERATIVE_SCHUR is used. The input preconditioner_type is
- // returned otherwise.
- static PreconditionerType PreconditionerForZeroEBlocks(
- PreconditionerType preconditioner_type);
-
- virtual ~Preconditioner();
-
- // Update the numerical value of the preconditioner for the linear
- // system:
- //
- // | A | x = |b|
- // |diag(D)| |0|
- //
- // for some vector b. It is important that the matrix A have the
- // same block structure as the one used to construct this object.
- //
- // D can be NULL, in which case its interpreted as a diagonal matrix
- // of size zero.
- virtual bool Update(const LinearOperator& A, const double* D) = 0;
-
- // LinearOperator interface. Since the operator is symmetric,
- // LeftMultiply and num_cols are just calls to RightMultiply and
- // num_rows respectively. Update() must be called before
- // RightMultiply can be called.
- virtual void RightMultiply(const double* x, double* y) const = 0;
- virtual void LeftMultiply(const double* x, double* y) const {
- return RightMultiply(x, y);
- }
-
- virtual int num_rows() const = 0;
- virtual int num_cols() const {
- return num_rows();
- }
-};
-
-// This templated subclass of Preconditioner serves as a base class for
-// other preconditioners that depend on the particular matrix layout of
-// the underlying linear operator.
-template <typename MatrixType>
-class TypedPreconditioner : public Preconditioner {
- public:
- virtual ~TypedPreconditioner() {}
- virtual bool Update(const LinearOperator& A, const double* D) {
- return UpdateImpl(*down_cast<const MatrixType*>(&A), D);
- }
-
- private:
- virtual bool UpdateImpl(const MatrixType& A, const double* D) = 0;
-};
-
-// Preconditioners that depend on acccess to the low level structure
-// of a SparseMatrix.
-typedef TypedPreconditioner<SparseMatrix> SparseMatrixPreconditioner; // NOLINT
-typedef TypedPreconditioner<BlockSparseMatrix> BlockSparseMatrixPreconditioner; // NOLINT
-typedef TypedPreconditioner<CompressedRowSparseMatrix> CompressedRowSparseMatrixPreconditioner; // NOLINT
-
-// Wrap a SparseMatrix object as a preconditioner.
-class SparseMatrixPreconditionerWrapper : public SparseMatrixPreconditioner {
- public:
- // Wrapper does NOT take ownership of the matrix pointer.
- explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix);
- virtual ~SparseMatrixPreconditionerWrapper();
-
- // Preconditioner interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const;
-
- private:
- virtual bool UpdateImpl(const SparseMatrix& A, const double* D);
- const SparseMatrix* matrix_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc b/extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc
deleted file mode 100644
index 318c5e2ebef..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/preprocessor.cc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/callbacks.h"
-#include "ceres/gradient_checking_cost_function.h"
-#include "ceres/line_search_preprocessor.h"
-#include "ceres/preprocessor.h"
-#include "ceres/problem_impl.h"
-#include "ceres/solver.h"
-#include "ceres/trust_region_preprocessor.h"
-
-namespace ceres {
-namespace internal {
-
-Preprocessor* Preprocessor::Create(MinimizerType minimizer_type) {
- if (minimizer_type == TRUST_REGION) {
- return new TrustRegionPreprocessor;
- }
-
- if (minimizer_type == LINE_SEARCH) {
- return new LineSearchPreprocessor;
- }
-
- LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
- return NULL;
-}
-
-Preprocessor::~Preprocessor() {
-}
-
-void ChangeNumThreadsIfNeeded(Solver::Options* options) {
-#ifndef CERES_USE_OPENMP
- if (options->num_threads > 1) {
- LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_threads = 1 is supported. Switching "
- << "to single threaded mode.";
- options->num_threads = 1;
- }
-
- // Only the Trust Region solver currently uses a linear solver.
- if (options->minimizer_type == TRUST_REGION &&
- options->num_linear_solver_threads > 1) {
- LOG(WARNING)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_linear_solver_threads=1 is supported. Switching "
- << "to single threaded mode.";
- options->num_linear_solver_threads = 1;
- }
-#endif // CERES_USE_OPENMP
-}
-
-void SetupCommonMinimizerOptions(PreprocessedProblem* pp) {
- const Solver::Options& options = pp->options;
- Program* program = pp->reduced_program.get();
-
- // Assuming that the parameter blocks in the program have been
- // reordered as needed, extract them into a contiguous vector.
- pp->reduced_parameters.resize(program->NumParameters());
- double* reduced_parameters = pp->reduced_parameters.data();
- program->ParameterBlocksToStateVector(reduced_parameters);
-
- Minimizer::Options& minimizer_options = pp->minimizer_options;
- minimizer_options = Minimizer::Options(options);
- minimizer_options.evaluator = pp->evaluator;
-
- if (options.logging_type != SILENT) {
- pp->logging_callback.reset(
- new LoggingCallback(options.minimizer_type,
- options.minimizer_progress_to_stdout));
- minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
- pp->logging_callback.get());
- }
-
- if (options.update_state_every_iteration) {
- pp->state_updating_callback.reset(
- new StateUpdatingCallback(program, reduced_parameters));
- // This must get pushed to the front of the callbacks so that it
- // is run before any of the user callbacks.
- minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
- pp->state_updating_callback.get());
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/preprocessor.h b/extern/libmv/third_party/ceres/internal/ceres/preprocessor.h
deleted file mode 100644
index b4ca5b11747..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/preprocessor.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_PREPROCESSOR_H_
-#define CERES_INTERNAL_PREPROCESSOR_H_
-
-#include "ceres/coordinate_descent_minimizer.h"
-#include "ceres/evaluator.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/iteration_callback.h"
-#include "ceres/linear_solver.h"
-#include "ceres/minimizer.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/solver.h"
-
-namespace ceres {
-namespace internal {
-
-struct PreprocessedProblem;
-
-// Given a Problem object and a Solver::Options object indicating the
-// configuration of the solver, the job of the Preprocessor is to
-// analyze the Problem and perform the setup needed to solve it using
-// the desired Minimization algorithm. The setup involves removing
-// redundancies in the input problem (inactive parameter and residual
-// blocks), finding fill reducing orderings as needed, configuring and
-// creating various objects needed by the Minimizer to solve the
-// problem such as an evaluator, a linear solver etc.
-//
-// Each Minimizer (LineSearchMinimizer and TrustRegionMinimizer) comes
-// with a corresponding Preprocessor (LineSearchPreprocessor and
-// TrustRegionPreprocessor) that knows about its needs and performs
-// the preprocessing needed.
-//
-// The output of the Preprocessor is stored in a PreprocessedProblem
-// object.
-class Preprocessor {
-public:
- // Factory.
- static Preprocessor* Create(MinimizerType minimizer_type);
- virtual ~Preprocessor();
- virtual bool Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* pp) = 0;
-};
-
-// A PreprocessedProblem is the result of running the Preprocessor on
-// a Problem and Solver::Options object.
-struct PreprocessedProblem {
- PreprocessedProblem()
- : fixed_cost(0.0) {
- }
-
- string error;
- Solver::Options options;
- LinearSolver::Options linear_solver_options;
- Evaluator::Options evaluator_options;
- Minimizer::Options minimizer_options;
-
- ProblemImpl* problem;
- scoped_ptr<ProblemImpl> gradient_checking_problem;
- scoped_ptr<Program> reduced_program;
- scoped_ptr<LinearSolver> linear_solver;
- scoped_ptr<IterationCallback> logging_callback;
- scoped_ptr<IterationCallback> state_updating_callback;
-
- shared_ptr<Evaluator> evaluator;
- shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
-
- vector<double*> removed_parameter_blocks;
- Vector reduced_parameters;
- double fixed_cost;
-};
-
-// Common functions used by various preprocessors.
-
-// If OpenMP support is not available and user has requested more than
-// one thread, then set the *_num_threads options as needed to 1.
-void ChangeNumThreadsIfNeeded(Solver::Options* options);
-
-// Extract the effective parameter vector from the preprocessed
-// problem and setup bits of the Minimizer::Options object that are
-// common to all Preprocessors.
-void SetupCommonMinimizerOptions(PreprocessedProblem* pp);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PREPROCESSOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem.cc b/extern/libmv/third_party/ceres/internal/ceres/problem.cc
deleted file mode 100644
index bbfaa98769f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/problem.cc
+++ /dev/null
@@ -1,271 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// keir@google.com (Keir Mierle)
-
-#include "ceres/problem.h"
-
-#include <vector>
-#include "ceres/crs_matrix.h"
-#include "ceres/problem_impl.h"
-
-namespace ceres {
-
-Problem::Problem() : problem_impl_(new internal::ProblemImpl) {}
-Problem::Problem(const Problem::Options& options)
- : problem_impl_(new internal::ProblemImpl(options)) {}
-Problem::~Problem() {}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- const vector<double*>& parameter_blocks) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- parameter_blocks);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6, x7);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8) {
- return problem_impl_->AddResidualBlock(cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6, x7, x8);
-}
-
-ResidualBlockId Problem::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8, double* x9) {
- return problem_impl_->AddResidualBlock(
- cost_function,
- loss_function,
- x0, x1, x2, x3, x4, x5, x6, x7, x8, x9);
-}
-
-void Problem::AddParameterBlock(double* values, int size) {
- problem_impl_->AddParameterBlock(values, size);
-}
-
-void Problem::AddParameterBlock(double* values,
- int size,
- LocalParameterization* local_parameterization) {
- problem_impl_->AddParameterBlock(values, size, local_parameterization);
-}
-
-void Problem::RemoveResidualBlock(ResidualBlockId residual_block) {
- problem_impl_->RemoveResidualBlock(residual_block);
-}
-
-void Problem::RemoveParameterBlock(double* values) {
- problem_impl_->RemoveParameterBlock(values);
-}
-
-void Problem::SetParameterBlockConstant(double* values) {
- problem_impl_->SetParameterBlockConstant(values);
-}
-
-void Problem::SetParameterBlockVariable(double* values) {
- problem_impl_->SetParameterBlockVariable(values);
-}
-
-void Problem::SetParameterization(
- double* values,
- LocalParameterization* local_parameterization) {
- problem_impl_->SetParameterization(values, local_parameterization);
-}
-
-const LocalParameterization* Problem::GetParameterization(
- double* values) const {
- return problem_impl_->GetParameterization(values);
-}
-
-void Problem::SetParameterLowerBound(double* values,
- int index,
- double lower_bound) {
- problem_impl_->SetParameterLowerBound(values, index, lower_bound);
-}
-
-void Problem::SetParameterUpperBound(double* values,
- int index,
- double upper_bound) {
- problem_impl_->SetParameterUpperBound(values, index, upper_bound);
-}
-
-bool Problem::Evaluate(const EvaluateOptions& evaluate_options,
- double* cost,
- vector<double>* residuals,
- vector<double>* gradient,
- CRSMatrix* jacobian) {
- return problem_impl_->Evaluate(evaluate_options,
- cost,
- residuals,
- gradient,
- jacobian);
-}
-
-int Problem::NumParameterBlocks() const {
- return problem_impl_->NumParameterBlocks();
-}
-
-int Problem::NumParameters() const {
- return problem_impl_->NumParameters();
-}
-
-int Problem::NumResidualBlocks() const {
- return problem_impl_->NumResidualBlocks();
-}
-
-int Problem::NumResiduals() const {
- return problem_impl_->NumResiduals();
-}
-
-int Problem::ParameterBlockSize(const double* parameter_block) const {
- return problem_impl_->ParameterBlockSize(parameter_block);
-};
-
-int Problem::ParameterBlockLocalSize(const double* parameter_block) const {
- return problem_impl_->ParameterBlockLocalSize(parameter_block);
-};
-
-bool Problem::HasParameterBlock(const double* values) const {
- return problem_impl_->HasParameterBlock(values);
-}
-
-void Problem::GetParameterBlocks(vector<double*>* parameter_blocks) const {
- problem_impl_->GetParameterBlocks(parameter_blocks);
-}
-
-void Problem::GetResidualBlocks(
- vector<ResidualBlockId>* residual_blocks) const {
- problem_impl_->GetResidualBlocks(residual_blocks);
-}
-
-void Problem::GetParameterBlocksForResidualBlock(
- const ResidualBlockId residual_block,
- vector<double*>* parameter_blocks) const {
- problem_impl_->GetParameterBlocksForResidualBlock(residual_block,
- parameter_blocks);
-}
-
-const CostFunction* Problem::GetCostFunctionForResidualBlock(
- const ResidualBlockId residual_block) const {
- return problem_impl_->GetCostFunctionForResidualBlock(residual_block);
-}
-
-const LossFunction* Problem::GetLossFunctionForResidualBlock(
- const ResidualBlockId residual_block) const {
- return problem_impl_->GetLossFunctionForResidualBlock(residual_block);
-}
-
-void Problem::GetResidualBlocksForParameterBlock(
- const double* values,
- vector<ResidualBlockId>* residual_blocks) const {
- problem_impl_->GetResidualBlocksForParameterBlock(values,
- residual_blocks);
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
deleted file mode 100644
index 67cac94d6ac..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
+++ /dev/null
@@ -1,872 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// mierle@gmail.com (Keir Mierle)
-
-#include "ceres/problem_impl.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <iterator>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-#include "ceres/casts.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/cost_function.h"
-#include "ceres/crs_matrix.h"
-#include "ceres/evaluator.h"
-#include "ceres/loss_function.h"
-#include "ceres/map_util.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/stl_util.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-typedef map<double*, internal::ParameterBlock*> ParameterMap;
-
-namespace {
-internal::ParameterBlock* FindParameterBlockOrDie(
- const ParameterMap& parameter_map,
- double* parameter_block) {
- ParameterMap::const_iterator it = parameter_map.find(parameter_block);
- CHECK(it != parameter_map.end())
- << "Parameter block not found: " << parameter_block;
- return it->second;
-}
-
-// Returns true if two regions of memory, a and b, with sizes size_a and size_b
-// respectively, overlap.
-bool RegionsAlias(const double* a, int size_a,
- const double* b, int size_b) {
- return (a < b) ? b < (a + size_a)
- : a < (b + size_b);
-}
-
-void CheckForNoAliasing(double* existing_block,
- int existing_block_size,
- double* new_block,
- int new_block_size) {
- CHECK(!RegionsAlias(existing_block, existing_block_size,
- new_block, new_block_size))
- << "Aliasing detected between existing parameter block at memory "
- << "location " << existing_block
- << " and has size " << existing_block_size << " with new parameter "
- << "block that has memory address " << new_block << " and would have "
- << "size " << new_block_size << ".";
-}
-
-} // namespace
-
-ParameterBlock* ProblemImpl::InternalAddParameterBlock(double* values,
- int size) {
- CHECK(values != NULL) << "Null pointer passed to AddParameterBlock "
- << "for a parameter with size " << size;
-
- // Ignore the request if there is a block for the given pointer already.
- ParameterMap::iterator it = parameter_block_map_.find(values);
- if (it != parameter_block_map_.end()) {
- if (!options_.disable_all_safety_checks) {
- int existing_size = it->second->Size();
- CHECK(size == existing_size)
- << "Tried adding a parameter block with the same double pointer, "
- << values << ", twice, but with different block sizes. Original "
- << "size was " << existing_size << " but new size is "
- << size;
- }
- return it->second;
- }
-
- if (!options_.disable_all_safety_checks) {
- // Before adding the parameter block, also check that it doesn't alias any
- // other parameter blocks.
- if (!parameter_block_map_.empty()) {
- ParameterMap::iterator lb = parameter_block_map_.lower_bound(values);
-
- // If lb is not the first block, check the previous block for aliasing.
- if (lb != parameter_block_map_.begin()) {
- ParameterMap::iterator previous = lb;
- --previous;
- CheckForNoAliasing(previous->first,
- previous->second->Size(),
- values,
- size);
- }
-
- // If lb is not off the end, check lb for aliasing.
- if (lb != parameter_block_map_.end()) {
- CheckForNoAliasing(lb->first,
- lb->second->Size(),
- values,
- size);
- }
- }
- }
-
- // Pass the index of the new parameter block as well to keep the index in
- // sync with the position of the parameter in the program's parameter vector.
- ParameterBlock* new_parameter_block =
- new ParameterBlock(values, size, program_->parameter_blocks_.size());
-
- // For dynamic problems, add the list of dependent residual blocks, which is
- // empty to start.
- if (options_.enable_fast_removal) {
- new_parameter_block->EnableResidualBlockDependencies();
- }
- parameter_block_map_[values] = new_parameter_block;
- program_->parameter_blocks_.push_back(new_parameter_block);
- return new_parameter_block;
-}
-
-void ProblemImpl::InternalRemoveResidualBlock(ResidualBlock* residual_block) {
- CHECK_NOTNULL(residual_block);
- // Perform no check on the validity of residual_block, that is handled in
- // the public method: RemoveResidualBlock().
-
- // If needed, remove the parameter dependencies on this residual block.
- if (options_.enable_fast_removal) {
- const int num_parameter_blocks_for_residual =
- residual_block->NumParameterBlocks();
- for (int i = 0; i < num_parameter_blocks_for_residual; ++i) {
- residual_block->parameter_blocks()[i]
- ->RemoveResidualBlock(residual_block);
- }
-
- ResidualBlockSet::iterator it = residual_block_set_.find(residual_block);
- residual_block_set_.erase(it);
- }
- DeleteBlockInVector(program_->mutable_residual_blocks(), residual_block);
-}
-
-// Deletes the residual block in question, assuming there are no other
-// references to it inside the problem (e.g. by another parameter). Referenced
-// cost and loss functions are tucked away for future deletion, since it is not
-// possible to know whether other parts of the problem depend on them without
-// doing a full scan.
-void ProblemImpl::DeleteBlock(ResidualBlock* residual_block) {
- // The const casts here are legit, since ResidualBlock holds these
- // pointers as const pointers but we have ownership of them and
- // have the right to destroy them when the destructor is called.
- if (options_.cost_function_ownership == TAKE_OWNERSHIP &&
- residual_block->cost_function() != NULL) {
- cost_functions_to_delete_.push_back(
- const_cast<CostFunction*>(residual_block->cost_function()));
- }
- if (options_.loss_function_ownership == TAKE_OWNERSHIP &&
- residual_block->loss_function() != NULL) {
- loss_functions_to_delete_.push_back(
- const_cast<LossFunction*>(residual_block->loss_function()));
- }
- delete residual_block;
-}
-
-// Deletes the parameter block in question, assuming there are no other
-// references to it inside the problem (e.g. by any residual blocks).
-// Referenced parameterizations are tucked away for future deletion, since it
-// is not possible to know whether other parts of the problem depend on them
-// without doing a full scan.
-void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) {
- if (options_.local_parameterization_ownership == TAKE_OWNERSHIP &&
- parameter_block->local_parameterization() != NULL) {
- local_parameterizations_to_delete_.push_back(
- parameter_block->mutable_local_parameterization());
- }
- parameter_block_map_.erase(parameter_block->mutable_user_state());
- delete parameter_block;
-}
-
-ProblemImpl::ProblemImpl() : program_(new internal::Program) {}
-ProblemImpl::ProblemImpl(const Problem::Options& options)
- : options_(options),
- program_(new internal::Program) {}
-
-ProblemImpl::~ProblemImpl() {
- // Collect the unique cost/loss functions and delete the residuals.
- const int num_residual_blocks = program_->residual_blocks_.size();
- cost_functions_to_delete_.reserve(num_residual_blocks);
- loss_functions_to_delete_.reserve(num_residual_blocks);
- for (int i = 0; i < program_->residual_blocks_.size(); ++i) {
- DeleteBlock(program_->residual_blocks_[i]);
- }
-
- // Collect the unique parameterizations and delete the parameters.
- for (int i = 0; i < program_->parameter_blocks_.size(); ++i) {
- DeleteBlock(program_->parameter_blocks_[i]);
- }
-
- // Delete the owned cost/loss functions and parameterizations.
- STLDeleteUniqueContainerPointers(local_parameterizations_to_delete_.begin(),
- local_parameterizations_to_delete_.end());
- STLDeleteUniqueContainerPointers(cost_functions_to_delete_.begin(),
- cost_functions_to_delete_.end());
- STLDeleteUniqueContainerPointers(loss_functions_to_delete_.begin(),
- loss_functions_to_delete_.end());
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- const vector<double*>& parameter_blocks) {
- CHECK_NOTNULL(cost_function);
- CHECK_EQ(parameter_blocks.size(),
- cost_function->parameter_block_sizes().size());
-
- // Check the sizes match.
- const vector<int32>& parameter_block_sizes =
- cost_function->parameter_block_sizes();
-
- if (!options_.disable_all_safety_checks) {
- CHECK_EQ(parameter_block_sizes.size(), parameter_blocks.size())
- << "Number of blocks input is different than the number of blocks "
- << "that the cost function expects.";
-
- // Check for duplicate parameter blocks.
- vector<double*> sorted_parameter_blocks(parameter_blocks);
- sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
- vector<double*>::const_iterator duplicate_items =
- unique(sorted_parameter_blocks.begin(),
- sorted_parameter_blocks.end());
- if (duplicate_items != sorted_parameter_blocks.end()) {
- string blocks;
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- blocks += StringPrintf(" %p ", parameter_blocks[i]);
- }
-
- LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
- << "are not allowed. Parameter block pointers: ["
- << blocks << "]";
- }
- }
-
- // Add parameter blocks and convert the double*'s to parameter blocks.
- vector<ParameterBlock*> parameter_block_ptrs(parameter_blocks.size());
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- parameter_block_ptrs[i] =
- InternalAddParameterBlock(parameter_blocks[i],
- parameter_block_sizes[i]);
- }
-
- if (!options_.disable_all_safety_checks) {
- // Check that the block sizes match the block sizes expected by the
- // cost_function.
- for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
- CHECK_EQ(cost_function->parameter_block_sizes()[i],
- parameter_block_ptrs[i]->Size())
- << "The cost function expects parameter block " << i
- << " of size " << cost_function->parameter_block_sizes()[i]
- << " but was given a block of size "
- << parameter_block_ptrs[i]->Size();
- }
- }
-
- ResidualBlock* new_residual_block =
- new ResidualBlock(cost_function,
- loss_function,
- parameter_block_ptrs,
- program_->residual_blocks_.size());
-
- // Add dependencies on the residual to the parameter blocks.
- if (options_.enable_fast_removal) {
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- parameter_block_ptrs[i]->AddResidualBlock(new_residual_block);
- }
- }
-
- program_->residual_blocks_.push_back(new_residual_block);
-
- if (options_.enable_fast_removal) {
- residual_block_set_.insert(new_residual_block);
- }
-
- return new_residual_block;
-}
-
-// Unfortunately, macros don't help much to reduce this code, and var args don't
-// work because of the ambiguous case that there is no loss function.
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- residual_parameters.push_back(x7);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- residual_parameters.push_back(x7);
- residual_parameters.push_back(x8);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-ResidualBlock* ProblemImpl::AddResidualBlock(
- CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2, double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8, double* x9) {
- vector<double*> residual_parameters;
- residual_parameters.push_back(x0);
- residual_parameters.push_back(x1);
- residual_parameters.push_back(x2);
- residual_parameters.push_back(x3);
- residual_parameters.push_back(x4);
- residual_parameters.push_back(x5);
- residual_parameters.push_back(x6);
- residual_parameters.push_back(x7);
- residual_parameters.push_back(x8);
- residual_parameters.push_back(x9);
- return AddResidualBlock(cost_function, loss_function, residual_parameters);
-}
-
-void ProblemImpl::AddParameterBlock(double* values, int size) {
- InternalAddParameterBlock(values, size);
-}
-
-void ProblemImpl::AddParameterBlock(
- double* values,
- int size,
- LocalParameterization* local_parameterization) {
- ParameterBlock* parameter_block =
- InternalAddParameterBlock(values, size);
- if (local_parameterization != NULL) {
- parameter_block->SetParameterization(local_parameterization);
- }
-}
-
-// Delete a block from a vector of blocks, maintaining the indexing invariant.
-// This is done in constant time by moving an element from the end of the
-// vector over the element to remove, then popping the last element. It
-// destroys the ordering in the interest of speed.
-template<typename Block>
-void ProblemImpl::DeleteBlockInVector(vector<Block*>* mutable_blocks,
- Block* block_to_remove) {
- CHECK_EQ((*mutable_blocks)[block_to_remove->index()], block_to_remove)
- << "You found a Ceres bug! \n"
- << "Block requested: "
- << block_to_remove->ToString() << "\n"
- << "Block present: "
- << (*mutable_blocks)[block_to_remove->index()]->ToString();
-
- // Prepare the to-be-moved block for the new, lower-in-index position by
- // setting the index to the blocks final location.
- Block* tmp = mutable_blocks->back();
- tmp->set_index(block_to_remove->index());
-
- // Overwrite the to-be-deleted residual block with the one at the end.
- (*mutable_blocks)[block_to_remove->index()] = tmp;
-
- DeleteBlock(block_to_remove);
-
- // The block is gone so shrink the vector of blocks accordingly.
- mutable_blocks->pop_back();
-}
-
-void ProblemImpl::RemoveResidualBlock(ResidualBlock* residual_block) {
- CHECK_NOTNULL(residual_block);
-
- // Verify that residual_block identifies a residual in the current problem.
- const string residual_not_found_message =
- StringPrintf("Residual block to remove: %p not found. This usually means "
- "one of three things have happened:\n"
- " 1) residual_block is uninitialised and points to a random "
- "area in memory.\n"
- " 2) residual_block represented a residual that was added to"
- " the problem, but referred to a parameter block which has "
- "since been removed, which removes all residuals which "
- "depend on that parameter block, and was thus removed.\n"
- " 3) residual_block referred to a residual that has already "
- "been removed from the problem (by the user).",
- residual_block);
- if (options_.enable_fast_removal) {
- CHECK(residual_block_set_.find(residual_block) !=
- residual_block_set_.end())
- << residual_not_found_message;
- } else {
- // Perform a full search over all current residuals.
- CHECK(std::find(program_->residual_blocks().begin(),
- program_->residual_blocks().end(),
- residual_block) != program_->residual_blocks().end())
- << residual_not_found_message;
- }
-
- InternalRemoveResidualBlock(residual_block);
-}
-
-void ProblemImpl::RemoveParameterBlock(double* values) {
- ParameterBlock* parameter_block =
- FindParameterBlockOrDie(parameter_block_map_, values);
-
- if (options_.enable_fast_removal) {
- // Copy the dependent residuals from the parameter block because the set of
- // dependents will change after each call to RemoveResidualBlock().
- vector<ResidualBlock*> residual_blocks_to_remove(
- parameter_block->mutable_residual_blocks()->begin(),
- parameter_block->mutable_residual_blocks()->end());
- for (int i = 0; i < residual_blocks_to_remove.size(); ++i) {
- InternalRemoveResidualBlock(residual_blocks_to_remove[i]);
- }
- } else {
- // Scan all the residual blocks to remove ones that depend on the parameter
- // block. Do the scan backwards since the vector changes while iterating.
- const int num_residual_blocks = NumResidualBlocks();
- for (int i = num_residual_blocks - 1; i >= 0; --i) {
- ResidualBlock* residual_block =
- (*(program_->mutable_residual_blocks()))[i];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- if (residual_block->parameter_blocks()[j] == parameter_block) {
- InternalRemoveResidualBlock(residual_block);
- // The parameter blocks are guaranteed unique.
- break;
- }
- }
- }
- }
- DeleteBlockInVector(program_->mutable_parameter_blocks(), parameter_block);
-}
-
-void ProblemImpl::SetParameterBlockConstant(double* values) {
- FindParameterBlockOrDie(parameter_block_map_, values)->SetConstant();
-}
-
-void ProblemImpl::SetParameterBlockVariable(double* values) {
- FindParameterBlockOrDie(parameter_block_map_, values)->SetVarying();
-}
-
-void ProblemImpl::SetParameterization(
- double* values,
- LocalParameterization* local_parameterization) {
- FindParameterBlockOrDie(parameter_block_map_, values)
- ->SetParameterization(local_parameterization);
-}
-
-const LocalParameterization* ProblemImpl::GetParameterization(
- double* values) const {
- return FindParameterBlockOrDie(parameter_block_map_, values)
- ->local_parameterization();
-}
-
-void ProblemImpl::SetParameterLowerBound(double* values,
- int index,
- double lower_bound) {
- FindParameterBlockOrDie(parameter_block_map_, values)
- ->SetLowerBound(index, lower_bound);
-}
-
-void ProblemImpl::SetParameterUpperBound(double* values,
- int index,
- double upper_bound) {
- FindParameterBlockOrDie(parameter_block_map_, values)
- ->SetUpperBound(index, upper_bound);
-}
-
-bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
- double* cost,
- vector<double>* residuals,
- vector<double>* gradient,
- CRSMatrix* jacobian) {
- if (cost == NULL &&
- residuals == NULL &&
- gradient == NULL &&
- jacobian == NULL) {
- LOG(INFO) << "Nothing to do.";
- return true;
- }
-
- // If the user supplied residual blocks, then use them, otherwise
- // take the residual blocks from the underlying program.
- Program program;
- *program.mutable_residual_blocks() =
- ((evaluate_options.residual_blocks.size() > 0)
- ? evaluate_options.residual_blocks : program_->residual_blocks());
-
- const vector<double*>& parameter_block_ptrs =
- evaluate_options.parameter_blocks;
-
- vector<ParameterBlock*> variable_parameter_blocks;
- vector<ParameterBlock*>& parameter_blocks =
- *program.mutable_parameter_blocks();
-
- if (parameter_block_ptrs.size() == 0) {
- // The user did not provide any parameter blocks, so default to
- // using all the parameter blocks in the order that they are in
- // the underlying program object.
- parameter_blocks = program_->parameter_blocks();
- } else {
- // The user supplied a vector of parameter blocks. Using this list
- // requires a number of steps.
-
- // 1. Convert double* into ParameterBlock*
- parameter_blocks.resize(parameter_block_ptrs.size());
- for (int i = 0; i < parameter_block_ptrs.size(); ++i) {
- parameter_blocks[i] =
- FindParameterBlockOrDie(parameter_block_map_,
- parameter_block_ptrs[i]);
- }
-
- // 2. The user may have only supplied a subset of parameter
- // blocks, so identify the ones that are not supplied by the user
- // and are NOT constant. These parameter blocks are stored in
- // variable_parameter_blocks.
- //
- // To ensure that the parameter blocks are not included in the
- // columns of the jacobian, we need to make sure that they are
- // constant during evaluation and then make them variable again
- // after we are done.
- vector<ParameterBlock*> all_parameter_blocks(program_->parameter_blocks());
- vector<ParameterBlock*> included_parameter_blocks(
- program.parameter_blocks());
-
- vector<ParameterBlock*> excluded_parameter_blocks;
- sort(all_parameter_blocks.begin(), all_parameter_blocks.end());
- sort(included_parameter_blocks.begin(), included_parameter_blocks.end());
- set_difference(all_parameter_blocks.begin(),
- all_parameter_blocks.end(),
- included_parameter_blocks.begin(),
- included_parameter_blocks.end(),
- back_inserter(excluded_parameter_blocks));
-
- variable_parameter_blocks.reserve(excluded_parameter_blocks.size());
- for (int i = 0; i < excluded_parameter_blocks.size(); ++i) {
- ParameterBlock* parameter_block = excluded_parameter_blocks[i];
- if (!parameter_block->IsConstant()) {
- variable_parameter_blocks.push_back(parameter_block);
- parameter_block->SetConstant();
- }
- }
- }
-
- // Setup the Parameter indices and offsets before an evaluator can
- // be constructed and used.
- program.SetParameterOffsetsAndIndex();
-
- Evaluator::Options evaluator_options;
-
- // Even though using SPARSE_NORMAL_CHOLESKY requires SuiteSparse or
- // CXSparse, here it just being used for telling the evaluator to
- // use a SparseRowCompressedMatrix for the jacobian. This is because
- // the Evaluator decides the storage for the Jacobian based on the
- // type of linear solver being used.
- evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
- evaluator_options.num_threads = evaluate_options.num_threads;
-
- string error;
- scoped_ptr<Evaluator> evaluator(
- Evaluator::Create(evaluator_options, &program, &error));
- if (evaluator.get() == NULL) {
- LOG(ERROR) << "Unable to create an Evaluator object. "
- << "Error: " << error
- << "This is a Ceres bug; please contact the developers!";
-
- // Make the parameter blocks that were temporarily marked
- // constant, variable again.
- for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
- variable_parameter_blocks[i]->SetVarying();
- }
-
- program_->SetParameterBlockStatePtrsToUserStatePtrs();
- program_->SetParameterOffsetsAndIndex();
- return false;
- }
-
- if (residuals !=NULL) {
- residuals->resize(evaluator->NumResiduals());
- }
-
- if (gradient != NULL) {
- gradient->resize(evaluator->NumEffectiveParameters());
- }
-
- scoped_ptr<CompressedRowSparseMatrix> tmp_jacobian;
- if (jacobian != NULL) {
- tmp_jacobian.reset(
- down_cast<CompressedRowSparseMatrix*>(evaluator->CreateJacobian()));
- }
-
- // Point the state pointers to the user state pointers. This is
- // needed so that we can extract a parameter vector which is then
- // passed to Evaluator::Evaluate.
- program.SetParameterBlockStatePtrsToUserStatePtrs();
-
- // Copy the value of the parameter blocks into a vector, since the
- // Evaluate::Evaluate method needs its input as such. The previous
- // call to SetParameterBlockStatePtrsToUserStatePtrs ensures that
- // these values are the ones corresponding to the actual state of
- // the parameter blocks, rather than the temporary state pointer
- // used for evaluation.
- Vector parameters(program.NumParameters());
- program.ParameterBlocksToStateVector(parameters.data());
-
- double tmp_cost = 0;
-
- Evaluator::EvaluateOptions evaluator_evaluate_options;
- evaluator_evaluate_options.apply_loss_function =
- evaluate_options.apply_loss_function;
- bool status = evaluator->Evaluate(evaluator_evaluate_options,
- parameters.data(),
- &tmp_cost,
- residuals != NULL ? &(*residuals)[0] : NULL,
- gradient != NULL ? &(*gradient)[0] : NULL,
- tmp_jacobian.get());
-
- // Make the parameter blocks that were temporarily marked constant,
- // variable again.
- for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
- variable_parameter_blocks[i]->SetVarying();
- }
-
- if (status) {
- if (cost != NULL) {
- *cost = tmp_cost;
- }
- if (jacobian != NULL) {
- tmp_jacobian->ToCRSMatrix(jacobian);
- }
- }
-
- program_->SetParameterBlockStatePtrsToUserStatePtrs();
- program_->SetParameterOffsetsAndIndex();
- return status;
-}
-
-int ProblemImpl::NumParameterBlocks() const {
- return program_->NumParameterBlocks();
-}
-
-int ProblemImpl::NumParameters() const {
- return program_->NumParameters();
-}
-
-int ProblemImpl::NumResidualBlocks() const {
- return program_->NumResidualBlocks();
-}
-
-int ProblemImpl::NumResiduals() const {
- return program_->NumResiduals();
-}
-
-int ProblemImpl::ParameterBlockSize(const double* parameter_block) const {
- return FindParameterBlockOrDie(parameter_block_map_,
- const_cast<double*>(parameter_block))->Size();
-};
-
-int ProblemImpl::ParameterBlockLocalSize(const double* parameter_block) const {
- return FindParameterBlockOrDie(
- parameter_block_map_, const_cast<double*>(parameter_block))->LocalSize();
-};
-
-bool ProblemImpl::HasParameterBlock(const double* parameter_block) const {
- return (parameter_block_map_.find(const_cast<double*>(parameter_block)) !=
- parameter_block_map_.end());
-}
-
-void ProblemImpl::GetParameterBlocks(vector<double*>* parameter_blocks) const {
- CHECK_NOTNULL(parameter_blocks);
- parameter_blocks->resize(0);
- for (ParameterMap::const_iterator it = parameter_block_map_.begin();
- it != parameter_block_map_.end();
- ++it) {
- parameter_blocks->push_back(it->first);
- }
-}
-
-void ProblemImpl::GetResidualBlocks(
- vector<ResidualBlockId>* residual_blocks) const {
- CHECK_NOTNULL(residual_blocks);
- *residual_blocks = program().residual_blocks();
-}
-
-void ProblemImpl::GetParameterBlocksForResidualBlock(
- const ResidualBlockId residual_block,
- vector<double*>* parameter_blocks) const {
- int num_parameter_blocks = residual_block->NumParameterBlocks();
- CHECK_NOTNULL(parameter_blocks)->resize(num_parameter_blocks);
- for (int i = 0; i < num_parameter_blocks; ++i) {
- (*parameter_blocks)[i] =
- residual_block->parameter_blocks()[i]->mutable_user_state();
- }
-}
-
-const CostFunction* ProblemImpl::GetCostFunctionForResidualBlock(
- const ResidualBlockId residual_block) const {
- return residual_block->cost_function();
-}
-
-const LossFunction* ProblemImpl::GetLossFunctionForResidualBlock(
- const ResidualBlockId residual_block) const {
- return residual_block->loss_function();
-}
-
-void ProblemImpl::GetResidualBlocksForParameterBlock(
- const double* values,
- vector<ResidualBlockId>* residual_blocks) const {
- ParameterBlock* parameter_block =
- FindParameterBlockOrDie(parameter_block_map_,
- const_cast<double*>(values));
-
- if (options_.enable_fast_removal) {
- // In this case the residual blocks that depend on the parameter block are
- // stored in the parameter block already, so just copy them out.
- CHECK_NOTNULL(residual_blocks)->resize(
- parameter_block->mutable_residual_blocks()->size());
- std::copy(parameter_block->mutable_residual_blocks()->begin(),
- parameter_block->mutable_residual_blocks()->end(),
- residual_blocks->begin());
- return;
- }
-
- // Find residual blocks that depend on the parameter block.
- CHECK_NOTNULL(residual_blocks)->clear();
- const int num_residual_blocks = NumResidualBlocks();
- for (int i = 0; i < num_residual_blocks; ++i) {
- ResidualBlock* residual_block =
- (*(program_->mutable_residual_blocks()))[i];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- if (residual_block->parameter_blocks()[j] == parameter_block) {
- residual_blocks->push_back(residual_block);
- // The parameter blocks are guaranteed unique.
- break;
- }
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
deleted file mode 100644
index 3d84de83c5a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
+++ /dev/null
@@ -1,225 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// This is the implementation of the public Problem API. The pointer to
-// implementation (PIMPL) idiom makes it possible for Ceres internal code to
-// refer to the private data members without needing to exposing it to the
-// world. An alternative to PIMPL is to have a factory which returns instances
-// of a virtual base class; while that approach would work, it requires clients
-// to always put a Problem object into a scoped pointer; this needlessly muddies
-// client code for little benefit. Therefore, the PIMPL comprise was chosen.
-
-#ifndef CERES_PUBLIC_PROBLEM_IMPL_H_
-#define CERES_PUBLIC_PROBLEM_IMPL_H_
-
-#include <map>
-#include <vector>
-
-#include "ceres/internal/macros.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/collections_port.h"
-#include "ceres/problem.h"
-#include "ceres/types.h"
-
-namespace ceres {
-
-class CostFunction;
-class LossFunction;
-class LocalParameterization;
-struct CRSMatrix;
-
-namespace internal {
-
-class Program;
-class ResidualBlock;
-
-class ProblemImpl {
- public:
- typedef map<double*, ParameterBlock*> ParameterMap;
- typedef HashSet<ResidualBlock*> ResidualBlockSet;
-
- ProblemImpl();
- explicit ProblemImpl(const Problem::Options& options);
-
- ~ProblemImpl();
-
- // See the public problem.h file for description of these methods.
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- const vector<double*>& parameter_blocks);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8);
- ResidualBlockId AddResidualBlock(CostFunction* cost_function,
- LossFunction* loss_function,
- double* x0, double* x1, double* x2,
- double* x3, double* x4, double* x5,
- double* x6, double* x7, double* x8,
- double* x9);
- void AddParameterBlock(double* values, int size);
- void AddParameterBlock(double* values,
- int size,
- LocalParameterization* local_parameterization);
-
- void RemoveResidualBlock(ResidualBlock* residual_block);
- void RemoveParameterBlock(double* values);
-
- void SetParameterBlockConstant(double* values);
- void SetParameterBlockVariable(double* values);
- void SetParameterization(double* values,
- LocalParameterization* local_parameterization);
- const LocalParameterization* GetParameterization(double* values) const;
-
- void SetParameterLowerBound(double* values, int index, double lower_bound);
- void SetParameterUpperBound(double* values, int index, double upper_bound);
-
- bool Evaluate(const Problem::EvaluateOptions& options,
- double* cost,
- vector<double>* residuals,
- vector<double>* gradient,
- CRSMatrix* jacobian);
-
- int NumParameterBlocks() const;
- int NumParameters() const;
- int NumResidualBlocks() const;
- int NumResiduals() const;
-
- int ParameterBlockSize(const double* parameter_block) const;
- int ParameterBlockLocalSize(const double* parameter_block) const;
-
- bool HasParameterBlock(const double* parameter_block) const;
-
- void GetParameterBlocks(vector<double*>* parameter_blocks) const;
- void GetResidualBlocks(vector<ResidualBlockId>* residual_blocks) const;
-
- void GetParameterBlocksForResidualBlock(
- const ResidualBlockId residual_block,
- vector<double*>* parameter_blocks) const;
-
- const CostFunction* GetCostFunctionForResidualBlock(
- const ResidualBlockId residual_block) const;
- const LossFunction* GetLossFunctionForResidualBlock(
- const ResidualBlockId residual_block) const;
-
- void GetResidualBlocksForParameterBlock(
- const double* values,
- vector<ResidualBlockId>* residual_blocks) const;
-
- const Program& program() const { return *program_; }
- Program* mutable_program() { return program_.get(); }
-
- const ParameterMap& parameter_map() const { return parameter_block_map_; }
- const ResidualBlockSet& residual_block_set() const {
- CHECK(options_.enable_fast_removal)
- << "Fast removal not enabled, residual_block_set is not maintained.";
- return residual_block_set_;
- }
-
- private:
- ParameterBlock* InternalAddParameterBlock(double* values, int size);
- void InternalRemoveResidualBlock(ResidualBlock* residual_block);
-
- bool InternalEvaluate(Program* program,
- double* cost,
- vector<double>* residuals,
- vector<double>* gradient,
- CRSMatrix* jacobian);
-
- // Delete the arguments in question. These differ from the Remove* functions
- // in that they do not clean up references to the block to delete; they
- // merely delete them.
- template<typename Block>
- void DeleteBlockInVector(vector<Block*>* mutable_blocks,
- Block* block_to_remove);
- void DeleteBlock(ResidualBlock* residual_block);
- void DeleteBlock(ParameterBlock* parameter_block);
-
- const Problem::Options options_;
-
- // The mapping from user pointers to parameter blocks.
- map<double*, ParameterBlock*> parameter_block_map_;
-
- // Iff enable_fast_removal is enabled, contains the current residual blocks.
- ResidualBlockSet residual_block_set_;
-
- // The actual parameter and residual blocks.
- internal::scoped_ptr<internal::Program> program_;
-
- // When removing residual and parameter blocks, cost/loss functions and
- // parameterizations have ambiguous ownership. Instead of scanning the entire
- // problem to see if the cost/loss/parameterization is shared with other
- // residual or parameter blocks, buffer them until destruction.
- //
- // TODO(keir): See if it makes sense to use sets instead.
- vector<CostFunction*> cost_functions_to_delete_;
- vector<LossFunction*> loss_functions_to_delete_;
- vector<LocalParameterization*> local_parameterizations_to_delete_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(ProblemImpl);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_PUBLIC_PROBLEM_IMPL_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/program.cc b/extern/libmv/third_party/ceres/internal/ceres/program.cc
deleted file mode 100644
index 1d0a1573e3b..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/program.cc
+++ /dev/null
@@ -1,517 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/program.h"
-
-#include <map>
-#include <vector>
-#include "ceres/array_utils.h"
-#include "ceres/casts.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/cost_function.h"
-#include "ceres/evaluator.h"
-#include "ceres/internal/port.h"
-#include "ceres/local_parameterization.h"
-#include "ceres/loss_function.h"
-#include "ceres/map_util.h"
-#include "ceres/parameter_block.h"
-#include "ceres/problem.h"
-#include "ceres/residual_block.h"
-#include "ceres/stl_util.h"
-#include "ceres/triplet_sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-Program::Program() {}
-
-Program::Program(const Program& program)
- : parameter_blocks_(program.parameter_blocks_),
- residual_blocks_(program.residual_blocks_) {
-}
-
-const vector<ParameterBlock*>& Program::parameter_blocks() const {
- return parameter_blocks_;
-}
-
-const vector<ResidualBlock*>& Program::residual_blocks() const {
- return residual_blocks_;
-}
-
-vector<ParameterBlock*>* Program::mutable_parameter_blocks() {
- return &parameter_blocks_;
-}
-
-vector<ResidualBlock*>* Program::mutable_residual_blocks() {
- return &residual_blocks_;
-}
-
-bool Program::StateVectorToParameterBlocks(const double *state) {
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- if (!parameter_blocks_[i]->IsConstant() &&
- !parameter_blocks_[i]->SetState(state)) {
- return false;
- }
- state += parameter_blocks_[i]->Size();
- }
- return true;
-}
-
-void Program::ParameterBlocksToStateVector(double *state) const {
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- parameter_blocks_[i]->GetState(state);
- state += parameter_blocks_[i]->Size();
- }
-}
-
-void Program::CopyParameterBlockStateToUserState() {
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- parameter_blocks_[i]->GetState(parameter_blocks_[i]->mutable_user_state());
- }
-}
-
-bool Program::SetParameterBlockStatePtrsToUserStatePtrs() {
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- if (!parameter_blocks_[i]->IsConstant() &&
- !parameter_blocks_[i]->SetState(parameter_blocks_[i]->user_state())) {
- return false;
- }
- }
- return true;
-}
-
-bool Program::Plus(const double* state,
- const double* delta,
- double* state_plus_delta) const {
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- if (!parameter_blocks_[i]->Plus(state, delta, state_plus_delta)) {
- return false;
- }
- state += parameter_blocks_[i]->Size();
- delta += parameter_blocks_[i]->LocalSize();
- state_plus_delta += parameter_blocks_[i]->Size();
- }
- return true;
-}
-
-void Program::SetParameterOffsetsAndIndex() {
- // Set positions for all parameters appearing as arguments to residuals to one
- // past the end of the parameter block array.
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- ResidualBlock* residual_block = residual_blocks_[i];
- for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
- residual_block->parameter_blocks()[j]->set_index(-1);
- }
- }
- // For parameters that appear in the program, set their position and offset.
- int state_offset = 0;
- int delta_offset = 0;
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- parameter_blocks_[i]->set_index(i);
- parameter_blocks_[i]->set_state_offset(state_offset);
- parameter_blocks_[i]->set_delta_offset(delta_offset);
- state_offset += parameter_blocks_[i]->Size();
- delta_offset += parameter_blocks_[i]->LocalSize();
- }
-}
-
-bool Program::IsValid() const {
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- const ResidualBlock* residual_block = residual_blocks_[i];
- if (residual_block->index() != i) {
- LOG(WARNING) << "Residual block: " << i
- << " has incorrect index: " << residual_block->index();
- return false;
- }
- }
-
- int state_offset = 0;
- int delta_offset = 0;
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
- if (parameter_block->index() != i ||
- parameter_block->state_offset() != state_offset ||
- parameter_block->delta_offset() != delta_offset) {
- LOG(WARNING) << "Parameter block: " << i
- << "has incorrect indexing information: "
- << parameter_block->ToString();
- return false;
- }
-
- state_offset += parameter_blocks_[i]->Size();
- delta_offset += parameter_blocks_[i]->LocalSize();
- }
-
- return true;
-}
-
-bool Program::ParameterBlocksAreFinite(string* message) const {
- CHECK_NOTNULL(message);
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
- const double* array = parameter_block->user_state();
- const int size = parameter_block->Size();
- const int invalid_index = FindInvalidValue(size, array);
- if (invalid_index != size) {
- *message = StringPrintf(
- "ParameterBlock: %p with size %d has at least one invalid value.\n"
- "First invalid value is at index: %d.\n"
- "Parameter block values: ",
- array, size, invalid_index);
- AppendArrayToString(size, array, message);
- return false;
- }
- }
- return true;
-}
-
-bool Program::IsBoundsConstrained() const {
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
- if (parameter_block->IsConstant()) {
- continue;
- }
- const int size = parameter_block->Size();
- for (int j = 0; j < size; ++j) {
- const double lower_bound = parameter_block->LowerBoundForParameter(j);
- const double upper_bound = parameter_block->UpperBoundForParameter(j);
- if (lower_bound > -std::numeric_limits<double>::max() ||
- upper_bound < std::numeric_limits<double>::max()) {
- return true;
- }
- }
- }
- return false;
-}
-
-bool Program::IsFeasible(string* message) const {
- CHECK_NOTNULL(message);
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
- const double* parameters = parameter_block->user_state();
- const int size = parameter_block->Size();
- if (parameter_block->IsConstant()) {
- // Constant parameter blocks must start in the feasible region
- // to ultimately produce a feasible solution, since Ceres cannot
- // change them.
- for (int j = 0; j < size; ++j) {
- const double lower_bound = parameter_block->LowerBoundForParameter(j);
- const double upper_bound = parameter_block->UpperBoundForParameter(j);
- if (parameters[j] < lower_bound || parameters[j] > upper_bound) {
- *message = StringPrintf(
- "ParameterBlock: %p with size %d has at least one infeasible "
- "value."
- "\nFirst infeasible value is at index: %d."
- "\nLower bound: %e, value: %e, upper bound: %e"
- "\nParameter block values: ",
- parameters, size, j, lower_bound, parameters[j], upper_bound);
- AppendArrayToString(size, parameters, message);
- return false;
- }
- }
- } else {
- // Variable parameter blocks must have non-empty feasible
- // regions, otherwise there is no way to produce a feasible
- // solution.
- for (int j = 0; j < size; ++j) {
- const double lower_bound = parameter_block->LowerBoundForParameter(j);
- const double upper_bound = parameter_block->UpperBoundForParameter(j);
- if (lower_bound >= upper_bound) {
- *message = StringPrintf(
- "ParameterBlock: %p with size %d has at least one infeasible "
- "bound."
- "\nFirst infeasible bound is at index: %d."
- "\nLower bound: %e, upper bound: %e"
- "\nParameter block values: ",
- parameters, size, j, lower_bound, upper_bound);
- AppendArrayToString(size, parameters, message);
- return false;
- }
- }
- }
- }
-
- return true;
-}
-
-Program* Program::CreateReducedProgram(vector<double*>* removed_parameter_blocks,
- double* fixed_cost,
- string* error) const {
- CHECK_NOTNULL(removed_parameter_blocks);
- CHECK_NOTNULL(fixed_cost);
- CHECK_NOTNULL(error);
-
- scoped_ptr<Program> reduced_program(new Program(*this));
- if (!reduced_program->RemoveFixedBlocks(removed_parameter_blocks,
- fixed_cost,
- error)) {
- return NULL;
- }
-
- reduced_program->SetParameterOffsetsAndIndex();
- return reduced_program.release();
-}
-
-bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
- double* fixed_cost,
- string* error) {
- CHECK_NOTNULL(removed_parameter_blocks);
- CHECK_NOTNULL(fixed_cost);
- CHECK_NOTNULL(error);
-
- scoped_array<double> residual_block_evaluate_scratch;
- residual_block_evaluate_scratch.reset(
- new double[MaxScratchDoublesNeededForEvaluate()]);
- *fixed_cost = 0.0;
-
- // Mark all the parameters as unused. Abuse the index member of the
- // parameter blocks for the marking.
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- parameter_blocks_[i]->set_index(-1);
- }
-
- // Filter out residual that have all-constant parameters, and mark
- // all the parameter blocks that appear in residuals.
- int num_active_residual_blocks = 0;
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- ResidualBlock* residual_block = residual_blocks_[i];
- int num_parameter_blocks = residual_block->NumParameterBlocks();
-
- // Determine if the residual block is fixed, and also mark varying
- // parameters that appear in the residual block.
- bool all_constant = true;
- for (int k = 0; k < num_parameter_blocks; k++) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[k];
- if (!parameter_block->IsConstant()) {
- all_constant = false;
- parameter_block->set_index(1);
- }
- }
-
- if (!all_constant) {
- residual_blocks_[num_active_residual_blocks++] = residual_block;
- continue;
- }
-
- // The residual is constant and will be removed, so its cost is
- // added to the variable fixed_cost.
- double cost = 0.0;
- if (!residual_block->Evaluate(true,
- &cost,
- NULL,
- NULL,
- residual_block_evaluate_scratch.get())) {
- *error = StringPrintf("Evaluation of the residual %d failed during "
- "removal of fixed residual blocks.", i);
- return false;
- }
- *fixed_cost += cost;
- }
- residual_blocks_.resize(num_active_residual_blocks);
-
- // Filter out unused or fixed parameter blocks.
- int num_active_parameter_blocks = 0;
- removed_parameter_blocks->clear();
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- ParameterBlock* parameter_block = parameter_blocks_[i];
- if (parameter_block->index() == -1) {
- removed_parameter_blocks->push_back(parameter_block->mutable_user_state());
- } else {
- parameter_blocks_[num_active_parameter_blocks++] = parameter_block;
- }
- }
- parameter_blocks_.resize(num_active_parameter_blocks);
-
- if (!(((NumResidualBlocks() == 0) &&
- (NumParameterBlocks() == 0)) ||
- ((NumResidualBlocks() != 0) &&
- (NumParameterBlocks() != 0)))) {
- *error = "Congratulations, you found a bug in Ceres. Please report it.";
- return false;
- }
-
- return true;
-}
-
-bool Program::IsParameterBlockSetIndependent(const set<double*>& independent_set) const {
- // Loop over each residual block and ensure that no two parameter
- // blocks in the same residual block are part of
- // parameter_block_ptrs as that would violate the assumption that it
- // is an independent set in the Hessian matrix.
- for (vector<ResidualBlock*>::const_iterator it = residual_blocks_.begin();
- it != residual_blocks_.end();
- ++it) {
- ParameterBlock* const* parameter_blocks = (*it)->parameter_blocks();
- const int num_parameter_blocks = (*it)->NumParameterBlocks();
- int count = 0;
- for (int i = 0; i < num_parameter_blocks; ++i) {
- count += independent_set.count(
- parameter_blocks[i]->mutable_user_state());
- }
- if (count > 1) {
- return false;
- }
- }
- return true;
-}
-
-TripletSparseMatrix* Program::CreateJacobianBlockSparsityTranspose() const {
- // Matrix to store the block sparsity structure of the Jacobian.
- TripletSparseMatrix* tsm =
- new TripletSparseMatrix(NumParameterBlocks(),
- NumResidualBlocks(),
- 10 * NumResidualBlocks());
- int num_nonzeros = 0;
- int* rows = tsm->mutable_rows();
- int* cols = tsm->mutable_cols();
- double* values = tsm->mutable_values();
-
- for (int c = 0; c < residual_blocks_.size(); ++c) {
- const ResidualBlock* residual_block = residual_blocks_[c];
- const int num_parameter_blocks = residual_block->NumParameterBlocks();
- ParameterBlock* const* parameter_blocks =
- residual_block->parameter_blocks();
-
- for (int j = 0; j < num_parameter_blocks; ++j) {
- if (parameter_blocks[j]->IsConstant()) {
- continue;
- }
-
- // Re-size the matrix if needed.
- if (num_nonzeros >= tsm->max_num_nonzeros()) {
- tsm->set_num_nonzeros(num_nonzeros);
- tsm->Reserve(2 * num_nonzeros);
- rows = tsm->mutable_rows();
- cols = tsm->mutable_cols();
- values = tsm->mutable_values();
- }
-
- const int r = parameter_blocks[j]->index();
- rows[num_nonzeros] = r;
- cols[num_nonzeros] = c;
- values[num_nonzeros] = 1.0;
- ++num_nonzeros;
- }
- }
-
- tsm->set_num_nonzeros(num_nonzeros);
- return tsm;
-}
-
-int Program::NumResidualBlocks() const {
- return residual_blocks_.size();
-}
-
-int Program::NumParameterBlocks() const {
- return parameter_blocks_.size();
-}
-
-int Program::NumResiduals() const {
- int num_residuals = 0;
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- num_residuals += residual_blocks_[i]->NumResiduals();
- }
- return num_residuals;
-}
-
-int Program::NumParameters() const {
- int num_parameters = 0;
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- num_parameters += parameter_blocks_[i]->Size();
- }
- return num_parameters;
-}
-
-int Program::NumEffectiveParameters() const {
- int num_parameters = 0;
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- num_parameters += parameter_blocks_[i]->LocalSize();
- }
- return num_parameters;
-}
-
-int Program::MaxScratchDoublesNeededForEvaluate() const {
- // Compute the scratch space needed for evaluate.
- int max_scratch_bytes_for_evaluate = 0;
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- max_scratch_bytes_for_evaluate =
- max(max_scratch_bytes_for_evaluate,
- residual_blocks_[i]->NumScratchDoublesForEvaluate());
- }
- return max_scratch_bytes_for_evaluate;
-}
-
-int Program::MaxDerivativesPerResidualBlock() const {
- int max_derivatives = 0;
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- int derivatives = 0;
- ResidualBlock* residual_block = residual_blocks_[i];
- int num_parameters = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameters; ++j) {
- derivatives += residual_block->NumResiduals() *
- residual_block->parameter_blocks()[j]->LocalSize();
- }
- max_derivatives = max(max_derivatives, derivatives);
- }
- return max_derivatives;
-}
-
-int Program::MaxParametersPerResidualBlock() const {
- int max_parameters = 0;
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- max_parameters = max(max_parameters,
- residual_blocks_[i]->NumParameterBlocks());
- }
- return max_parameters;
-}
-
-int Program::MaxResidualsPerResidualBlock() const {
- int max_residuals = 0;
- for (int i = 0; i < residual_blocks_.size(); ++i) {
- max_residuals = max(max_residuals,
- residual_blocks_[i]->NumResiduals());
- }
- return max_residuals;
-}
-
-string Program::ToString() const {
- string ret = "Program dump\n";
- ret += StringPrintf("Number of parameter blocks: %d\n", NumParameterBlocks());
- ret += StringPrintf("Number of parameters: %d\n", NumParameters());
- ret += "Parameters:\n";
- for (int i = 0; i < parameter_blocks_.size(); ++i) {
- ret += StringPrintf("%d: %s\n",
- i, parameter_blocks_[i]->ToString().c_str());
- }
- return ret;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/program.h b/extern/libmv/third_party/ceres/internal/ceres/program.h
deleted file mode 100644
index c7b22c4d244..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/program.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_PROGRAM_H_
-#define CERES_INTERNAL_PROGRAM_H_
-
-#include <set>
-#include <string>
-#include <vector>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-class ParameterBlock;
-class ProblemImpl;
-class ResidualBlock;
-class TripletSparseMatrix;
-
-// A nonlinear least squares optimization problem. This is different from the
-// similarly-named "Problem" object, which offers a mutation interface for
-// adding and modifying parameters and residuals. The Program contains the core
-// part of the Problem, which is the parameters and the residuals, stored in a
-// particular ordering. The ordering is critical, since it defines the mapping
-// between (residual, parameter) pairs and a position in the jacobian of the
-// objective function. Various parts of Ceres transform one Program into
-// another; for example, the first stage of solving involves stripping all
-// constant parameters and residuals. This is in contrast with Problem, which is
-// not built for transformation.
-class Program {
- public:
- Program();
- explicit Program(const Program& program);
-
- // The ordered parameter and residual blocks for the program.
- const vector<ParameterBlock*>& parameter_blocks() const;
- const vector<ResidualBlock*>& residual_blocks() const;
- vector<ParameterBlock*>* mutable_parameter_blocks();
- vector<ResidualBlock*>* mutable_residual_blocks();
-
- // Serialize to/from the program and update states.
- //
- // NOTE: Setting the state of a parameter block can trigger the
- // computation of the Jacobian of its local parameterization. If
- // this computation fails for some reason, then this method returns
- // false and the state of the parameter blocks cannot be trusted.
- bool StateVectorToParameterBlocks(const double *state);
- void ParameterBlocksToStateVector(double *state) const;
-
- // Copy internal state to the user's parameters.
- void CopyParameterBlockStateToUserState();
-
- // Set the parameter block pointers to the user pointers. Since this
- // runs parameter block set state internally, which may call local
- // parameterizations, this can fail. False is returned on failure.
- bool SetParameterBlockStatePtrsToUserStatePtrs();
-
- // Update a state vector for the program given a delta.
- bool Plus(const double* state,
- const double* delta,
- double* state_plus_delta) const;
-
- // Set the parameter indices and offsets. This permits mapping backward
- // from a ParameterBlock* to an index in the parameter_blocks() vector. For
- // any parameter block p, after calling SetParameterOffsetsAndIndex(), it
- // is true that
- //
- // parameter_blocks()[p->index()] == p
- //
- // If a parameter appears in a residual but not in the parameter block, then
- // it will have an index of -1.
- //
- // This also updates p->state_offset() and p->delta_offset(), which are the
- // position of the parameter in the state and delta vector respectively.
- void SetParameterOffsetsAndIndex();
-
- // Check if the internal state of the program (the indexing and the
- // offsets) are correct.
- bool IsValid() const;
-
- bool ParameterBlocksAreFinite(string* message) const;
-
- // Returns true if the program has any non-constant parameter blocks
- // which have non-trivial bounds constraints.
- bool IsBoundsConstrained() const;
-
- // Returns false, if the program has any constant parameter blocks
- // which are not feasible, or any variable parameter blocks which
- // have a lower bound greater than or equal to the upper bound.
- bool IsFeasible(string* message) const;
-
- // Loop over each residual block and ensure that no two parameter
- // blocks in the same residual block are part of
- // parameter_blocks as that would violate the assumption that it
- // is an independent set in the Hessian matrix.
- bool IsParameterBlockSetIndependent(const set<double*>& independent_set) const;
-
- // Create a TripletSparseMatrix which contains the zero-one
- // structure corresponding to the block sparsity of the transpose of
- // the Jacobian matrix.
- //
- // Caller owns the result.
- TripletSparseMatrix* CreateJacobianBlockSparsityTranspose() const;
-
- // Create a copy of this program and removes constant parameter
- // blocks and residual blocks with no varying parameter blocks while
- // preserving their relative order.
- //
- // removed_parameter_blocks on exit will contain the list of
- // parameter blocks that were removed.
- //
- // fixed_cost will be equal to the sum of the costs of the residual
- // blocks that were removed.
- //
- // If there was a problem, then the function will return a NULL
- // pointer and error will contain a human readable description of
- // the problem.
- Program* CreateReducedProgram(vector<double*>* removed_parameter_blocks,
- double* fixed_cost,
- string* error) const;
-
- // See problem.h for what these do.
- int NumParameterBlocks() const;
- int NumParameters() const;
- int NumEffectiveParameters() const;
- int NumResidualBlocks() const;
- int NumResiduals() const;
-
- int MaxScratchDoublesNeededForEvaluate() const;
- int MaxDerivativesPerResidualBlock() const;
- int MaxParametersPerResidualBlock() const;
- int MaxResidualsPerResidualBlock() const;
-
- // A human-readable dump of the parameter blocks for debugging.
- // TODO(keir): If necessary, also dump the residual blocks.
- string ToString() const;
-
- private:
- // Remove constant parameter blocks and residual blocks with no
- // varying parameter blocks while preserving their relative order.
- //
- // removed_parameter_blocks on exit will contain the list of
- // parameter blocks that were removed.
- //
- // fixed_cost will be equal to the sum of the costs of the residual
- // blocks that were removed.
- //
- // If there was a problem, then the function will return false and
- // error will contain a human readable description of the problem.
- bool RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
- double* fixed_cost,
- string* message);
-
- // The Program does not own the ParameterBlock or ResidualBlock objects.
- vector<ParameterBlock*> parameter_blocks_;
- vector<ResidualBlock*> residual_blocks_;
-
- friend class ProblemImpl;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PROGRAM_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
deleted file mode 100644
index 672c233b379..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
+++ /dev/null
@@ -1,379 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// The ProgramEvaluator runs the cost functions contained in each residual block
-// and stores the result into a jacobian. The particular type of jacobian is
-// abstracted out using two template parameters:
-//
-// - An "EvaluatePreparer" that is responsible for creating the array with
-// pointers to the jacobian blocks where the cost function evaluates to.
-// - A "JacobianWriter" that is responsible for storing the resulting
-// jacobian blocks in the passed sparse matrix.
-//
-// This abstraction affords an efficient evaluator implementation while still
-// supporting writing to multiple sparse matrix formats. For example, when the
-// ProgramEvaluator is parameterized for writing to block sparse matrices, the
-// residual jacobians are written directly into their final position in the
-// block sparse matrix by the user's CostFunction; there is no copying.
-//
-// The evaluation is threaded with OpenMP.
-//
-// The EvaluatePreparer and JacobianWriter interfaces are as follows:
-//
-// class EvaluatePreparer {
-// // Prepare the jacobians array for use as the destination of a call to
-// // a cost function's evaluate method.
-// void Prepare(const ResidualBlock* residual_block,
-// int residual_block_index,
-// SparseMatrix* jacobian,
-// double** jacobians);
-// }
-//
-// class JacobianWriter {
-// // Create a jacobian that this writer can write. Same as
-// // Evaluator::CreateJacobian.
-// SparseMatrix* CreateJacobian() const;
-//
-// // Create num_threads evaluate preparers. Caller owns result which must
-// // be freed with delete[]. Resulting preparers are valid while *this is.
-// EvaluatePreparer* CreateEvaluatePreparers(int num_threads);
-//
-// // Write the block jacobians from a residual block evaluation to the
-// // larger sparse jacobian.
-// void Write(int residual_id,
-// int residual_offset,
-// double** jacobians,
-// SparseMatrix* jacobian);
-// }
-//
-// Note: The ProgramEvaluator is not thread safe, since internally it maintains
-// some per-thread scratch space.
-
-#ifndef CERES_INTERNAL_PROGRAM_EVALUATOR_H_
-#define CERES_INTERNAL_PROGRAM_EVALUATOR_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
-#include <map>
-#include <string>
-#include <vector>
-#include "ceres/execution_summary.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/small_blas.h"
-
-namespace ceres {
-namespace internal {
-
-struct NullJacobianFinalizer {
- void operator()(SparseMatrix* jacobian, int num_parameters) {}
-};
-
-template<typename EvaluatePreparer,
- typename JacobianWriter,
- typename JacobianFinalizer = NullJacobianFinalizer>
-class ProgramEvaluator : public Evaluator {
- public:
- ProgramEvaluator(const Evaluator::Options &options, Program* program)
- : options_(options),
- program_(program),
- jacobian_writer_(options, program),
- evaluate_preparers_(
- jacobian_writer_.CreateEvaluatePreparers(options.num_threads)) {
-#ifndef CERES_USE_OPENMP
- CHECK_EQ(1, options_.num_threads)
- << "OpenMP support is not compiled into this binary; "
- << "only options.num_threads=1 is supported.";
-#endif
-
- BuildResidualLayout(*program, &residual_layout_);
- evaluate_scratch_.reset(CreateEvaluatorScratch(*program,
- options.num_threads));
- }
-
- // Implementation of Evaluator interface.
- SparseMatrix* CreateJacobian() const {
- return jacobian_writer_.CreateJacobian();
- }
-
- bool Evaluate(const Evaluator::EvaluateOptions& evaluate_options,
- const double* state,
- double* cost,
- double* residuals,
- double* gradient,
- SparseMatrix* jacobian) {
- ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
- ScopedExecutionTimer call_type_timer(gradient == NULL && jacobian == NULL
- ? "Evaluator::Residual"
- : "Evaluator::Jacobian",
- &execution_summary_);
-
- // The parameters are stateful, so set the state before evaluating.
- if (!program_->StateVectorToParameterBlocks(state)) {
- return false;
- }
-
- if (residuals != NULL) {
- VectorRef(residuals, program_->NumResiduals()).setZero();
- }
-
- if (jacobian != NULL) {
- jacobian->SetZero();
- }
-
- // Each thread gets it's own cost and evaluate scratch space.
- for (int i = 0; i < options_.num_threads; ++i) {
- evaluate_scratch_[i].cost = 0.0;
- if (gradient != NULL) {
- VectorRef(evaluate_scratch_[i].gradient.get(),
- program_->NumEffectiveParameters()).setZero();
- }
- }
-
- // This bool is used to disable the loop if an error is encountered
- // without breaking out of it. The remaining loop iterations are still run,
- // but with an empty body, and so will finish quickly.
- bool abort = false;
- int num_residual_blocks = program_->NumResidualBlocks();
-#pragma omp parallel for num_threads(options_.num_threads)
- for (int i = 0; i < num_residual_blocks; ++i) {
-// Disable the loop instead of breaking, as required by OpenMP.
-#pragma omp flush(abort)
- if (abort) {
- continue;
- }
-
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
- EvaluatePreparer* preparer = &evaluate_preparers_[thread_id];
- EvaluateScratch* scratch = &evaluate_scratch_[thread_id];
-
- // Prepare block residuals if requested.
- const ResidualBlock* residual_block = program_->residual_blocks()[i];
- double* block_residuals = NULL;
- if (residuals != NULL) {
- block_residuals = residuals + residual_layout_[i];
- } else if (gradient != NULL) {
- block_residuals = scratch->residual_block_residuals.get();
- }
-
- // Prepare block jacobians if requested.
- double** block_jacobians = NULL;
- if (jacobian != NULL || gradient != NULL) {
- preparer->Prepare(residual_block,
- i,
- jacobian,
- scratch->jacobian_block_ptrs.get());
- block_jacobians = scratch->jacobian_block_ptrs.get();
- }
-
- // Evaluate the cost, residuals, and jacobians.
- double block_cost;
- if (!residual_block->Evaluate(
- evaluate_options.apply_loss_function,
- &block_cost,
- block_residuals,
- block_jacobians,
- scratch->residual_block_evaluate_scratch.get())) {
- abort = true;
-// This ensures that the OpenMP threads have a consistent view of 'abort'. Do
-// the flush inside the failure case so that there is usually only one
-// synchronization point per loop iteration instead of two.
-#pragma omp flush(abort)
- continue;
- }
-
- scratch->cost += block_cost;
-
- // Store the jacobians, if they were requested.
- if (jacobian != NULL) {
- jacobian_writer_.Write(i,
- residual_layout_[i],
- block_jacobians,
- jacobian);
- }
-
- // Compute and store the gradient, if it was requested.
- if (gradient != NULL) {
- int num_residuals = residual_block->NumResiduals();
- int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- const ParameterBlock* parameter_block =
- residual_block->parameter_blocks()[j];
- if (parameter_block->IsConstant()) {
- continue;
- }
-
- MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- block_jacobians[j],
- num_residuals,
- parameter_block->LocalSize(),
- block_residuals,
- scratch->gradient.get() + parameter_block->delta_offset());
- }
- }
- }
-
- if (!abort) {
- const int num_parameters = program_->NumEffectiveParameters();
-
- // Sum the cost and gradient (if requested) from each thread.
- (*cost) = 0.0;
- if (gradient != NULL) {
- VectorRef(gradient, num_parameters).setZero();
- }
- for (int i = 0; i < options_.num_threads; ++i) {
- (*cost) += evaluate_scratch_[i].cost;
- if (gradient != NULL) {
- VectorRef(gradient, num_parameters) +=
- VectorRef(evaluate_scratch_[i].gradient.get(), num_parameters);
- }
- }
-
- // Finalize the Jacobian if it is available.
- // `num_parameters` is passed to the finalizer so that additional
- // storage can be reserved for additional diagonal elements if
- // necessary.
- if (jacobian != NULL) {
- JacobianFinalizer f;
- f(jacobian, num_parameters);
- }
- }
- return !abort;
- }
-
- bool Plus(const double* state,
- const double* delta,
- double* state_plus_delta) const {
- return program_->Plus(state, delta, state_plus_delta);
- }
-
- int NumParameters() const {
- return program_->NumParameters();
- }
- int NumEffectiveParameters() const {
- return program_->NumEffectiveParameters();
- }
-
- int NumResiduals() const {
- return program_->NumResiduals();
- }
-
- virtual map<string, int> CallStatistics() const {
- return execution_summary_.calls();
- }
-
- virtual map<string, double> TimeStatistics() const {
- return execution_summary_.times();
- }
-
- private:
- // Per-thread scratch space needed to evaluate and store each residual block.
- struct EvaluateScratch {
- void Init(int max_parameters_per_residual_block,
- int max_scratch_doubles_needed_for_evaluate,
- int max_residuals_per_residual_block,
- int num_parameters) {
- residual_block_evaluate_scratch.reset(
- new double[max_scratch_doubles_needed_for_evaluate]);
- gradient.reset(new double[num_parameters]);
- VectorRef(gradient.get(), num_parameters).setZero();
- residual_block_residuals.reset(
- new double[max_residuals_per_residual_block]);
- jacobian_block_ptrs.reset(
- new double*[max_parameters_per_residual_block]);
- }
-
- double cost;
- scoped_array<double> residual_block_evaluate_scratch;
- // The gradient in the local parameterization.
- scoped_array<double> gradient;
- // Enough space to store the residual for the largest residual block.
- scoped_array<double> residual_block_residuals;
- scoped_array<double*> jacobian_block_ptrs;
- };
-
- static void BuildResidualLayout(const Program& program,
- vector<int>* residual_layout) {
- const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
- residual_layout->resize(program.NumResidualBlocks());
- int residual_pos = 0;
- for (int i = 0; i < residual_blocks.size(); ++i) {
- const int num_residuals = residual_blocks[i]->NumResiduals();
- (*residual_layout)[i] = residual_pos;
- residual_pos += num_residuals;
- }
- }
-
- // Create scratch space for each thread evaluating the program.
- static EvaluateScratch* CreateEvaluatorScratch(const Program& program,
- int num_threads) {
- int max_parameters_per_residual_block =
- program.MaxParametersPerResidualBlock();
- int max_scratch_doubles_needed_for_evaluate =
- program.MaxScratchDoublesNeededForEvaluate();
- int max_residuals_per_residual_block =
- program.MaxResidualsPerResidualBlock();
- int num_parameters = program.NumEffectiveParameters();
-
- EvaluateScratch* evaluate_scratch = new EvaluateScratch[num_threads];
- for (int i = 0; i < num_threads; i++) {
- evaluate_scratch[i].Init(max_parameters_per_residual_block,
- max_scratch_doubles_needed_for_evaluate,
- max_residuals_per_residual_block,
- num_parameters);
- }
- return evaluate_scratch;
- }
-
- Evaluator::Options options_;
- Program* program_;
- JacobianWriter jacobian_writer_;
- scoped_array<EvaluatePreparer> evaluate_preparers_;
- scoped_array<EvaluateScratch> evaluate_scratch_;
- vector<int> residual_layout_;
- ::ceres::internal::ExecutionSummary execution_summary_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_PROGRAM_EVALUATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/random.h b/extern/libmv/third_party/ceres/internal/ceres/random.h
deleted file mode 100644
index 352c0032b5a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/random.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_RANDOM_H_
-#define CERES_INTERNAL_RANDOM_H_
-
-#include <cmath>
-#include <cstdlib>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-
-inline void SetRandomState(int state) {
- srand(state);
-}
-
-inline int Uniform(int n) {
- return rand() % n;
-}
-
-inline double RandDouble() {
- double r = static_cast<double>(rand());
- return r / RAND_MAX;
-}
-
-// Box-Muller algorithm for normal random number generation.
-// http://en.wikipedia.org/wiki/Box-Muller_transform
-inline double RandNormal() {
- double x1, x2, w;
- do {
- x1 = 2.0 * RandDouble() - 1.0;
- x2 = 2.0 * RandDouble() - 1.0;
- w = x1 * x1 + x2 * x2;
- } while ( w >= 1.0 || w == 0.0 );
-
- w = sqrt((-2.0 * log(w)) / w);
- return x1 * w;
-}
-
-} // namespace ceres
-
-#endif // CERES_INTERNAL_RANDOM_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc b/extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc
deleted file mode 100644
index aa3d4cec396..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/reorder_program.cc
+++ /dev/null
@@ -1,578 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/reorder_program.h"
-
-#include <algorithm>
-#include <numeric>
-#include <vector>
-
-#include "ceres/cxsparse.h"
-#include "ceres/internal/port.h"
-#include "ceres/ordered_groups.h"
-#include "ceres/parameter_block.h"
-#include "ceres/parameter_block_ordering.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-#include "ceres/solver.h"
-#include "ceres/suitesparse.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "Eigen/SparseCore"
-
-#ifdef CERES_USE_EIGEN_SPARSE
-#include "Eigen/OrderingMethods"
-#endif
-
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-// Find the minimum index of any parameter block to the given
-// residual. Parameter blocks that have indices greater than
-// size_of_first_elimination_group are considered to have an index
-// equal to size_of_first_elimination_group.
-static int MinParameterBlock(const ResidualBlock* residual_block,
- int size_of_first_elimination_group) {
- int min_parameter_block_position = size_of_first_elimination_group;
- for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
- if (!parameter_block->IsConstant()) {
- CHECK_NE(parameter_block->index(), -1)
- << "Did you forget to call Program::SetParameterOffsetsAndIndex()? "
- << "This is a Ceres bug; please contact the developers!";
- min_parameter_block_position = std::min(parameter_block->index(),
- min_parameter_block_position);
- }
- }
- return min_parameter_block_position;
-}
-
-#if EIGEN_VERSION_AT_LEAST(3, 2, 2) && defined(CERES_USE_EIGEN_SPARSE)
-Eigen::SparseMatrix<int> CreateBlockJacobian(
- const TripletSparseMatrix& block_jacobian_transpose) {
- typedef Eigen::SparseMatrix<int> SparseMatrix;
- typedef Eigen::Triplet<int> Triplet;
-
- const int* rows = block_jacobian_transpose.rows();
- const int* cols = block_jacobian_transpose.cols();
- int num_nonzeros = block_jacobian_transpose.num_nonzeros();
- std::vector<Triplet> triplets;
- triplets.reserve(num_nonzeros);
- for (int i = 0; i < num_nonzeros; ++i) {
- triplets.push_back(Triplet(cols[i], rows[i], 1));
- }
-
- SparseMatrix block_jacobian(block_jacobian_transpose.num_cols(),
- block_jacobian_transpose.num_rows());
- block_jacobian.setFromTriplets(triplets.begin(), triplets.end());
- return block_jacobian;
-}
-#endif
-
-void OrderingForSparseNormalCholeskyUsingSuiteSparse(
- const TripletSparseMatrix& tsm_block_jacobian_transpose,
- const vector<ParameterBlock*>& parameter_blocks,
- const ParameterBlockOrdering& parameter_block_ordering,
- int* ordering) {
-#ifdef CERES_NO_SUITESPARSE
- LOG(FATAL) << "Congratulations, you found a Ceres bug! "
- << "Please report this error to the developers.";
-#else
- SuiteSparse ss;
- cholmod_sparse* block_jacobian_transpose =
- ss.CreateSparseMatrix(
- const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
-
- // No CAMD or the user did not supply a useful ordering, then just
- // use regular AMD.
- if (parameter_block_ordering.NumGroups() <= 1 ||
- !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
- ss.ApproximateMinimumDegreeOrdering(block_jacobian_transpose, &ordering[0]);
- } else {
- vector<int> constraints;
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- constraints.push_back(
- parameter_block_ordering.GroupId(
- parameter_blocks[i]->mutable_user_state()));
- }
- ss.ConstrainedApproximateMinimumDegreeOrdering(block_jacobian_transpose,
- &constraints[0],
- ordering);
- }
-
- ss.Free(block_jacobian_transpose);
-#endif // CERES_NO_SUITESPARSE
-}
-
-void OrderingForSparseNormalCholeskyUsingCXSparse(
- const TripletSparseMatrix& tsm_block_jacobian_transpose,
- int* ordering) {
-#ifdef CERES_NO_CXSPARSE
- LOG(FATAL) << "Congratulations, you found a Ceres bug! "
- << "Please report this error to the developers.";
-#else // CERES_NO_CXSPARSE
- // CXSparse works with J'J instead of J'. So compute the block
- // sparsity for J'J and compute an approximate minimum degree
- // ordering.
- CXSparse cxsparse;
- cs_di* block_jacobian_transpose;
- block_jacobian_transpose =
- cxsparse.CreateSparseMatrix(
- const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
- cs_di* block_jacobian = cxsparse.TransposeMatrix(block_jacobian_transpose);
- cs_di* block_hessian =
- cxsparse.MatrixMatrixMultiply(block_jacobian_transpose, block_jacobian);
- cxsparse.Free(block_jacobian);
- cxsparse.Free(block_jacobian_transpose);
-
- cxsparse.ApproximateMinimumDegreeOrdering(block_hessian, ordering);
- cxsparse.Free(block_hessian);
-#endif // CERES_NO_CXSPARSE
-}
-
-
-#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
-void OrderingForSparseNormalCholeskyUsingEigenSparse(
- const TripletSparseMatrix& tsm_block_jacobian_transpose,
- int* ordering) {
-#ifndef CERES_USE_EIGEN_SPARSE
- LOG(FATAL) <<
- "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
- "because Ceres was not built with support for "
- "Eigen's SimplicialLDLT decomposition. "
- "This requires enabling building with -DEIGENSPARSE=ON.";
-#else
-
- // This conversion from a TripletSparseMatrix to a Eigen::Triplet
- // matrix is unfortunate, but unavoidable for now. It is not a
- // significant performance penalty in the grand scheme of
- // things. The right thing to do here would be to get a compressed
- // row sparse matrix representation of the jacobian and go from
- // there. But that is a project for another day.
- typedef Eigen::SparseMatrix<int> SparseMatrix;
-
- const SparseMatrix block_jacobian =
- CreateBlockJacobian(tsm_block_jacobian_transpose);
- const SparseMatrix block_hessian =
- block_jacobian.transpose() * block_jacobian;
-
- Eigen::AMDOrdering<int> amd_ordering;
- Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
- amd_ordering(block_hessian, perm);
- for (int i = 0; i < block_hessian.rows(); ++i) {
- ordering[i] = perm.indices()[i];
- }
-#endif // CERES_USE_EIGEN_SPARSE
-}
-#endif
-
-} // namespace
-
-bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
- const ParameterBlockOrdering& ordering,
- Program* program,
- string* error) {
- const int num_parameter_blocks = program->NumParameterBlocks();
- if (ordering.NumElements() != num_parameter_blocks) {
- *error = StringPrintf("User specified ordering does not have the same "
- "number of parameters as the problem. The problem"
- "has %d blocks while the ordering has %d blocks.",
- num_parameter_blocks,
- ordering.NumElements());
- return false;
- }
-
- vector<ParameterBlock*>* parameter_blocks =
- program->mutable_parameter_blocks();
- parameter_blocks->clear();
-
- const map<int, set<double*> >& groups =
- ordering.group_to_elements();
-
- for (map<int, set<double*> >::const_iterator group_it = groups.begin();
- group_it != groups.end();
- ++group_it) {
- const set<double*>& group = group_it->second;
- for (set<double*>::const_iterator parameter_block_ptr_it = group.begin();
- parameter_block_ptr_it != group.end();
- ++parameter_block_ptr_it) {
- ProblemImpl::ParameterMap::const_iterator parameter_block_it =
- parameter_map.find(*parameter_block_ptr_it);
- if (parameter_block_it == parameter_map.end()) {
- *error = StringPrintf("User specified ordering contains a pointer "
- "to a double that is not a parameter block in "
- "the problem. The invalid double is in group: %d",
- group_it->first);
- return false;
- }
- parameter_blocks->push_back(parameter_block_it->second);
- }
- }
- return true;
-}
-
-bool LexicographicallyOrderResidualBlocks(
- const int size_of_first_elimination_group,
- Program* program,
- string* error) {
- CHECK_GE(size_of_first_elimination_group, 1)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
-
- // Create a histogram of the number of residuals for each E block. There is an
- // extra bucket at the end to catch all non-eliminated F blocks.
- vector<int> residual_blocks_per_e_block(size_of_first_elimination_group + 1);
- vector<ResidualBlock*>* residual_blocks = program->mutable_residual_blocks();
- vector<int> min_position_per_residual(residual_blocks->size());
- for (int i = 0; i < residual_blocks->size(); ++i) {
- ResidualBlock* residual_block = (*residual_blocks)[i];
- int position = MinParameterBlock(residual_block,
- size_of_first_elimination_group);
- min_position_per_residual[i] = position;
- DCHECK_LE(position, size_of_first_elimination_group);
- residual_blocks_per_e_block[position]++;
- }
-
- // Run a cumulative sum on the histogram, to obtain offsets to the start of
- // each histogram bucket (where each bucket is for the residuals for that
- // E-block).
- vector<int> offsets(size_of_first_elimination_group + 1);
- std::partial_sum(residual_blocks_per_e_block.begin(),
- residual_blocks_per_e_block.end(),
- offsets.begin());
- CHECK_EQ(offsets.back(), residual_blocks->size())
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
-
- CHECK(find(residual_blocks_per_e_block.begin(),
- residual_blocks_per_e_block.end() - 1, 0) !=
- residual_blocks_per_e_block.end())
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
-
- // Fill in each bucket with the residual blocks for its corresponding E block.
- // Each bucket is individually filled from the back of the bucket to the front
- // of the bucket. The filling order among the buckets is dictated by the
- // residual blocks. This loop uses the offsets as counters; subtracting one
- // from each offset as a residual block is placed in the bucket. When the
- // filling is finished, the offset pointerts should have shifted down one
- // entry (this is verified below).
- vector<ResidualBlock*> reordered_residual_blocks(
- (*residual_blocks).size(), static_cast<ResidualBlock*>(NULL));
- for (int i = 0; i < residual_blocks->size(); ++i) {
- int bucket = min_position_per_residual[i];
-
- // Decrement the cursor, which should now point at the next empty position.
- offsets[bucket]--;
-
- // Sanity.
- CHECK(reordered_residual_blocks[offsets[bucket]] == NULL)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
-
- reordered_residual_blocks[offsets[bucket]] = (*residual_blocks)[i];
- }
-
- // Sanity check #1: The difference in bucket offsets should match the
- // histogram sizes.
- for (int i = 0; i < size_of_first_elimination_group; ++i) {
- CHECK_EQ(residual_blocks_per_e_block[i], offsets[i + 1] - offsets[i])
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
- }
- // Sanity check #2: No NULL's left behind.
- for (int i = 0; i < reordered_residual_blocks.size(); ++i) {
- CHECK(reordered_residual_blocks[i] != NULL)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
- }
-
- // Now that the residuals are collected by E block, swap them in place.
- swap(*program->mutable_residual_blocks(), reordered_residual_blocks);
- return true;
-}
-
-// Pre-order the columns corresponding to the schur complement if
-// possible.
-void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
- const ParameterBlockOrdering& parameter_block_ordering,
- Program* program) {
-#ifndef CERES_NO_SUITESPARSE
- SuiteSparse ss;
- if (!SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
- return;
- }
-
- vector<int> constraints;
- vector<ParameterBlock*>& parameter_blocks =
- *(program->mutable_parameter_blocks());
-
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- constraints.push_back(
- parameter_block_ordering.GroupId(
- parameter_blocks[i]->mutable_user_state()));
- }
-
- // Renumber the entries of constraints to be contiguous integers
- // as camd requires that the group ids be in the range [0,
- // parameter_blocks.size() - 1].
- MapValuesToContiguousRange(constraints.size(), &constraints[0]);
-
- // Compute a block sparse presentation of J'.
- scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
- program->CreateJacobianBlockSparsityTranspose());
-
- cholmod_sparse* block_jacobian_transpose =
- ss.CreateSparseMatrix(tsm_block_jacobian_transpose.get());
-
- vector<int> ordering(parameter_blocks.size(), 0);
- ss.ConstrainedApproximateMinimumDegreeOrdering(block_jacobian_transpose,
- &constraints[0],
- &ordering[0]);
- ss.Free(block_jacobian_transpose);
-
- const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
- for (int i = 0; i < program->NumParameterBlocks(); ++i) {
- parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
- }
-
- program->SetParameterOffsetsAndIndex();
-#endif
-}
-
-void MaybeReorderSchurComplementColumnsUsingEigen(
- const int size_of_first_elimination_group,
- const ProblemImpl::ParameterMap& parameter_map,
- Program* program) {
-#if !EIGEN_VERSION_AT_LEAST(3, 2, 2) || !defined(CERES_USE_EIGEN_SPARSE)
- return;
-#else
-
- scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
- program->CreateJacobianBlockSparsityTranspose());
-
- typedef Eigen::SparseMatrix<int> SparseMatrix;
- const SparseMatrix block_jacobian =
- CreateBlockJacobian(*tsm_block_jacobian_transpose);
- const int num_rows = block_jacobian.rows();
- const int num_cols = block_jacobian.cols();
-
- // Vertically partition the jacobian in parameter blocks of type E
- // and F.
- const SparseMatrix E =
- block_jacobian.block(0,
- 0,
- num_rows,
- size_of_first_elimination_group);
- const SparseMatrix F =
- block_jacobian.block(0,
- size_of_first_elimination_group,
- num_rows,
- num_cols - size_of_first_elimination_group);
-
- // Block sparsity pattern of the schur complement.
- const SparseMatrix block_schur_complement =
- F.transpose() * F - F.transpose() * E * E.transpose() * F;
-
- Eigen::AMDOrdering<int> amd_ordering;
- Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
- amd_ordering(block_schur_complement, perm);
-
- const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
- vector<ParameterBlock*> ordering(num_cols);
-
- // The ordering of the first size_of_first_elimination_group does
- // not matter, so we preserve the existing ordering.
- for (int i = 0; i < size_of_first_elimination_group; ++i) {
- ordering[i] = parameter_blocks[i];
- }
-
- // For the rest of the blocks, use the ordering computed using AMD.
- for (int i = 0; i < block_schur_complement.cols(); ++i) {
- ordering[size_of_first_elimination_group + i] =
- parameter_blocks[size_of_first_elimination_group + perm.indices()[i]];
- }
-
- swap(*program->mutable_parameter_blocks(), ordering);
- program->SetParameterOffsetsAndIndex();
-#endif
-}
-
-bool ReorderProgramForSchurTypeLinearSolver(
- const LinearSolverType linear_solver_type,
- const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
- const ProblemImpl::ParameterMap& parameter_map,
- ParameterBlockOrdering* parameter_block_ordering,
- Program* program,
- string* error) {
- if (parameter_block_ordering->NumElements() !=
- program->NumParameterBlocks()) {
- *error = StringPrintf(
- "The program has %d parameter blocks, but the parameter block "
- "ordering has %d parameter blocks.",
- program->NumParameterBlocks(),
- parameter_block_ordering->NumElements());
- return false;
- }
-
- if (parameter_block_ordering->NumGroups() == 1) {
- // If the user supplied an parameter_block_ordering with just one
- // group, it is equivalent to the user supplying NULL as an
- // parameter_block_ordering. Ceres is completely free to choose the
- // parameter block ordering as it sees fit. For Schur type solvers,
- // this means that the user wishes for Ceres to identify the
- // e_blocks, which we do by computing a maximal independent set.
- vector<ParameterBlock*> schur_ordering;
- const int size_of_first_elimination_group =
- ComputeStableSchurOrdering(*program, &schur_ordering);
-
- CHECK_EQ(schur_ordering.size(), program->NumParameterBlocks())
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
-
- // Update the parameter_block_ordering object.
- for (int i = 0; i < schur_ordering.size(); ++i) {
- double* parameter_block = schur_ordering[i]->mutable_user_state();
- const int group_id = (i < size_of_first_elimination_group) ? 0 : 1;
- parameter_block_ordering->AddElementToGroup(parameter_block, group_id);
- }
-
- // We could call ApplyOrdering but this is cheaper and
- // simpler.
- swap(*program->mutable_parameter_blocks(), schur_ordering);
- } else {
- // The user provided an ordering with more than one elimination
- // group.
-
- // Verify that the first elimination group is an independent set.
- const set<double*>& first_elimination_group =
- parameter_block_ordering
- ->group_to_elements()
- .begin()
- ->second;
- if (!program->IsParameterBlockSetIndependent(first_elimination_group)) {
- *error =
- StringPrintf("The first elimination group in the parameter block "
- "ordering of size %zd is not an independent set",
- first_elimination_group.size());
- return false;
- }
-
- if (!ApplyOrdering(parameter_map,
- *parameter_block_ordering,
- program,
- error)) {
- return false;
- }
- }
-
- program->SetParameterOffsetsAndIndex();
-
- const int size_of_first_elimination_group =
- parameter_block_ordering->group_to_elements().begin()->second.size();
-
- if (linear_solver_type == SPARSE_SCHUR) {
- if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
- MaybeReorderSchurComplementColumnsUsingSuiteSparse(
- *parameter_block_ordering,
- program);
- } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
- MaybeReorderSchurComplementColumnsUsingEigen(
- size_of_first_elimination_group,
- parameter_map,
- program);
- }
- }
-
- // Schur type solvers also require that their residual blocks be
- // lexicographically ordered.
- if (!LexicographicallyOrderResidualBlocks(size_of_first_elimination_group,
- program,
- error)) {
- return false;
- }
-
- return true;
-}
-
-bool ReorderProgramForSparseNormalCholesky(
- const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
- const ParameterBlockOrdering& parameter_block_ordering,
- Program* program,
- string* error) {
- // Compute a block sparse presentation of J'.
- scoped_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
- program->CreateJacobianBlockSparsityTranspose());
-
- vector<int> ordering(program->NumParameterBlocks(), 0);
- vector<ParameterBlock*>& parameter_blocks =
- *(program->mutable_parameter_blocks());
-
- if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
- OrderingForSparseNormalCholeskyUsingSuiteSparse(
- *tsm_block_jacobian_transpose,
- parameter_blocks,
- parameter_block_ordering,
- &ordering[0]);
- } else if (sparse_linear_algebra_library_type == CX_SPARSE) {
- OrderingForSparseNormalCholeskyUsingCXSparse(
- *tsm_block_jacobian_transpose,
- &ordering[0]);
- } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
-#if EIGEN_VERSION_AT_LEAST(3, 2, 2)
- OrderingForSparseNormalCholeskyUsingEigenSparse(
- *tsm_block_jacobian_transpose,
- &ordering[0]);
-#else
- // For Eigen versions less than 3.2.2, there is nothing to do as
- // older versions of Eigen do not expose a method for doing
- // symbolic analysis on pre-ordered matrices, so a block
- // pre-ordering is a bit pointless.
-
- return true;
-#endif
- }
-
- // Apply ordering.
- const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
- for (int i = 0; i < program->NumParameterBlocks(); ++i) {
- parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
- }
-
- program->SetParameterOffsetsAndIndex();
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/reorder_program.h b/extern/libmv/third_party/ceres/internal/ceres/reorder_program.h
deleted file mode 100644
index 0474c1fb912..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/reorder_program.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_REORDER_PROGRAM_H_
-#define CERES_INTERNAL_REORDER_PROGRAM_H_
-
-#include <string>
-#include "ceres/internal/port.h"
-#include "ceres/parameter_block_ordering.h"
-#include "ceres/problem_impl.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-class Program;
-
-// Reorder the parameter blocks in program using the ordering
-bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
- const ParameterBlockOrdering& ordering,
- Program* program,
- string* error);
-
-// Reorder the residuals for program, if necessary, so that the residuals
-// involving each E block occur together. This is a necessary condition for the
-// Schur eliminator, which works on these "row blocks" in the jacobian.
-bool LexicographicallyOrderResidualBlocks(int size_of_first_elimination_group,
- Program* program,
- string* error);
-
-// Schur type solvers require that all parameter blocks eliminated
-// by the Schur eliminator occur before others and the residuals be
-// sorted in lexicographic order of their parameter blocks.
-//
-// If the parameter_block_ordering only contains one elimination
-// group then a maximal independent set is computed and used as the
-// first elimination group, otherwise the user's ordering is used.
-//
-// If the linear solver type is SPARSE_SCHUR and support for
-// constrained fill-reducing ordering is available in the sparse
-// linear algebra library (SuiteSparse version >= 4.2.0) then
-// columns of the schur complement matrix are ordered to reduce the
-// fill-in the Cholesky factorization.
-//
-// Upon return, ordering contains the parameter block ordering that
-// was used to order the program.
-bool ReorderProgramForSchurTypeLinearSolver(
- LinearSolverType linear_solver_type,
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
- const ProblemImpl::ParameterMap& parameter_map,
- ParameterBlockOrdering* parameter_block_ordering,
- Program* program,
- string* error);
-
-// Sparse cholesky factorization routines when doing the sparse
-// cholesky factorization of the Jacobian matrix, reorders its
-// columns to reduce the fill-in. Compute this permutation and
-// re-order the parameter blocks.
-//
-// When using SuiteSparse, if the parameter_block_ordering contains
-// more than one elimination group and support for constrained
-// fill-reducing ordering is available in the sparse linear algebra
-// library (SuiteSparse version >= 4.2.0) then the fill reducing
-// ordering will take it into account, otherwise it will be ignored.
-bool ReorderProgramForSparseNormalCholesky(
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
- const ParameterBlockOrdering& parameter_block_ordering,
- Program* program,
- string* error);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_REORDER_PROGRAM_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
deleted file mode 100644
index 621082ac0ea..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/residual_block.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <vector>
-#include "ceres/corrector.h"
-#include "ceres/parameter_block.h"
-#include "ceres/residual_block_utils.h"
-#include "ceres/cost_function.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/local_parameterization.h"
-#include "ceres/loss_function.h"
-#include "ceres/small_blas.h"
-
-using Eigen::Dynamic;
-
-namespace ceres {
-namespace internal {
-
-ResidualBlock::ResidualBlock(const CostFunction* cost_function,
- const LossFunction* loss_function,
- const vector<ParameterBlock*>& parameter_blocks,
- int index)
- : cost_function_(cost_function),
- loss_function_(loss_function),
- parameter_blocks_(
- new ParameterBlock* [
- cost_function->parameter_block_sizes().size()]),
- index_(index) {
- std::copy(parameter_blocks.begin(),
- parameter_blocks.end(),
- parameter_blocks_.get());
-}
-
-bool ResidualBlock::Evaluate(const bool apply_loss_function,
- double* cost,
- double* residuals,
- double** jacobians,
- double* scratch) const {
- const int num_parameter_blocks = NumParameterBlocks();
- const int num_residuals = cost_function_->num_residuals();
-
- // Collect the parameters from their blocks. This will rarely allocate, since
- // residuals taking more than 8 parameter block arguments are rare.
- FixedArray<const double*, 8> parameters(num_parameter_blocks);
- for (int i = 0; i < num_parameter_blocks; ++i) {
- parameters[i] = parameter_blocks_[i]->state();
- }
-
- // Put pointers into the scratch space into global_jacobians as appropriate.
- FixedArray<double*, 8> global_jacobians(num_parameter_blocks);
- if (jacobians != NULL) {
- for (int i = 0; i < num_parameter_blocks; ++i) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
- if (jacobians[i] != NULL &&
- parameter_block->LocalParameterizationJacobian() != NULL) {
- global_jacobians[i] = scratch;
- scratch += num_residuals * parameter_block->Size();
- } else {
- global_jacobians[i] = jacobians[i];
- }
- }
- }
-
- // If the caller didn't request residuals, use the scratch space for them.
- bool outputting_residuals = (residuals != NULL);
- if (!outputting_residuals) {
- residuals = scratch;
- }
-
- // Invalidate the evaluation buffers so that we can check them after
- // the CostFunction::Evaluate call, to see if all the return values
- // that were required were written to and that they are finite.
- double** eval_jacobians = (jacobians != NULL) ? global_jacobians.get() : NULL;
-
- InvalidateEvaluation(*this, cost, residuals, eval_jacobians);
-
- if (!cost_function_->Evaluate(parameters.get(), residuals, eval_jacobians)) {
- return false;
- }
-
- if (!IsEvaluationValid(*this,
- parameters.get(),
- cost,
- residuals,
- eval_jacobians)) {
- string message =
- "\n\n"
- "Error in evaluating the ResidualBlock.\n\n"
- "There are two possible reasons. Either the CostFunction did not evaluate and fill all \n" // NOLINT
- "residual and jacobians that were requested or there was a non-finite value (nan/infinite)\n" // NOLINT
- "generated during the or jacobian computation. \n\n" +
- EvaluationToString(*this,
- parameters.get(),
- cost,
- residuals,
- eval_jacobians);
- LOG(WARNING) << message;
- return false;
- }
-
- double squared_norm = VectorRef(residuals, num_residuals).squaredNorm();
-
- // Update the jacobians with the local parameterizations.
- if (jacobians != NULL) {
- for (int i = 0; i < num_parameter_blocks; ++i) {
- if (jacobians[i] != NULL) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
-
- // Apply local reparameterization to the jacobians.
- if (parameter_block->LocalParameterizationJacobian() != NULL) {
- // jacobians[i] = global_jacobians[i] * global_to_local_jacobian.
- MatrixMatrixMultiply<Dynamic, Dynamic, Dynamic, Dynamic, 0>(
- global_jacobians[i],
- num_residuals,
- parameter_block->Size(),
- parameter_block->LocalParameterizationJacobian(),
- parameter_block->Size(),
- parameter_block->LocalSize(),
- jacobians[i], 0, 0, num_residuals, parameter_block->LocalSize());
- }
- }
- }
- }
-
- if (loss_function_ == NULL || !apply_loss_function) {
- *cost = 0.5 * squared_norm;
- return true;
- }
-
- double rho[3];
- loss_function_->Evaluate(squared_norm, rho);
- *cost = 0.5 * rho[0];
-
- // No jacobians and not outputting residuals? All done. Doing an early exit
- // here avoids constructing the "Corrector" object below in a common case.
- if (jacobians == NULL && !outputting_residuals) {
- return true;
- }
-
- // Correct for the effects of the loss function. The jacobians need to be
- // corrected before the residuals, since they use the uncorrected residuals.
- Corrector correct(squared_norm, rho);
- if (jacobians != NULL) {
- for (int i = 0; i < num_parameter_blocks; ++i) {
- if (jacobians[i] != NULL) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
-
- // Correct the jacobians for the loss function.
- correct.CorrectJacobian(num_residuals,
- parameter_block->LocalSize(),
- residuals,
- jacobians[i]);
- }
- }
- }
-
- // Correct the residuals with the loss function.
- if (outputting_residuals) {
- correct.CorrectResiduals(num_residuals, residuals);
- }
- return true;
-}
-
-int ResidualBlock::NumScratchDoublesForEvaluate() const {
- // Compute the amount of scratch space needed to store the full-sized
- // jacobians. For parameters that have no local parameterization no storage
- // is needed and the passed-in jacobian array is used directly. Also include
- // space to store the residuals, which is needed for cost-only evaluations.
- // This is slightly pessimistic, since both won't be needed all the time, but
- // the amount of excess should not cause problems for the caller.
- int num_parameters = NumParameterBlocks();
- int scratch_doubles = 1;
- for (int i = 0; i < num_parameters; ++i) {
- const ParameterBlock* parameter_block = parameter_blocks_[i];
- if (!parameter_block->IsConstant() &&
- parameter_block->LocalParameterizationJacobian() != NULL) {
- scratch_doubles += parameter_block->Size();
- }
- }
- scratch_doubles *= NumResiduals();
- return scratch_doubles;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
deleted file mode 100644
index 9c3671bb0a4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
+++ /dev/null
@@ -1,148 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// keir@google.com (Keir Mierle)
-//
-// Purpose : Class and struct definitions for parameter and residual blocks.
-
-#ifndef CERES_INTERNAL_RESIDUAL_BLOCK_H_
-#define CERES_INTERNAL_RESIDUAL_BLOCK_H_
-
-#include <string>
-#include <vector>
-
-#include "ceres/cost_function.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-
-namespace ceres {
-
-class LossFunction;
-
-namespace internal {
-
-class ParameterBlock;
-
-// A term in the least squares problem. The mathematical form of each term in
-// the overall least-squares cost function is:
-//
-// 1
-// --- loss_function( || cost_function(block1, block2, ...) ||^2 ),
-// 2
-//
-// Storing the cost function and the loss function separately permits optimizing
-// the problem with standard non-linear least techniques, without requiring a
-// more general non-linear solver.
-//
-// The residual block stores pointers to but does not own the cost functions,
-// loss functions, and parameter blocks.
-class ResidualBlock {
- public:
- // Construct the residual block with the given cost/loss functions. Loss may
- // be null. The index is the index of the residual block in the Program's
- // residual_blocks array.
- ResidualBlock(const CostFunction* cost_function,
- const LossFunction* loss_function,
- const vector<ParameterBlock*>& parameter_blocks,
- int index);
-
- // Evaluates the residual term, storing the scalar cost in *cost, the residual
- // components in *residuals, and the jacobians between the parameters and
- // residuals in jacobians[i], in row-major order. If residuals is NULL, the
- // residuals are not computed. If jacobians is NULL, no jacobians are
- // computed. If jacobians[i] is NULL, then the jacobian for that parameter is
- // not computed.
- //
- // Evaluate needs scratch space which must be supplied by the caller via
- // scratch. The array should have at least NumScratchDoublesForEvaluate()
- // space available.
- //
- // The return value indicates the success or failure. If the function returns
- // false, the caller should expect the the output memory locations to have
- // been modified.
- //
- // The returned cost and jacobians have had robustification and local
- // parameterizations applied already; for example, the jacobian for a
- // 4-dimensional quaternion parameter using the "QuaternionParameterization"
- // is num_residuals by 3 instead of num_residuals by 4.
- //
- // apply_loss_function as the name implies allows the user to switch
- // the application of the loss function on and off.
- bool Evaluate(bool apply_loss_function,
- double* cost,
- double* residuals,
- double** jacobians,
- double* scratch) const;
-
-
- const CostFunction* cost_function() const { return cost_function_; }
- const LossFunction* loss_function() const { return loss_function_; }
-
- // Access the parameter blocks for this residual. The array has size
- // NumParameterBlocks().
- ParameterBlock* const* parameter_blocks() const {
- return parameter_blocks_.get();
- }
-
- // Number of variable blocks that this residual term depends on.
- int NumParameterBlocks() const {
- return cost_function_->parameter_block_sizes().size();
- }
-
- // The size of the residual vector returned by this residual function.
- int NumResiduals() const { return cost_function_->num_residuals(); }
-
- // The minimum amount of scratch space needed to pass to Evaluate().
- int NumScratchDoublesForEvaluate() const;
-
- // This residual block's index in an array.
- int index() const { return index_; }
- void set_index(int index) { index_ = index; }
-
- string ToString() {
- return StringPrintf("{residual block; index=%d}", index_);
- }
-
- private:
- const CostFunction* cost_function_;
- const LossFunction* loss_function_;
- scoped_array<ParameterBlock*> parameter_blocks_;
-
- // The index of the residual, typically in a Program. This is only to permit
- // switching from a ResidualBlock* to an index in the Program's array, needed
- // to do efficient removals.
- int32 index_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_RESIDUAL_BLOCK_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
deleted file mode 100644
index d2564a7692e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/residual_block_utils.h"
-
-#include <cmath>
-#include <cstddef>
-#include <limits>
-#include "ceres/array_utils.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/parameter_block.h"
-#include "ceres/residual_block.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-void InvalidateEvaluation(const ResidualBlock& block,
- double* cost,
- double* residuals,
- double** jacobians) {
- const int num_parameter_blocks = block.NumParameterBlocks();
- const int num_residuals = block.NumResiduals();
-
- InvalidateArray(1, cost);
- InvalidateArray(num_residuals, residuals);
- if (jacobians != NULL) {
- for (int i = 0; i < num_parameter_blocks; ++i) {
- const int parameter_block_size = block.parameter_blocks()[i]->Size();
- InvalidateArray(num_residuals * parameter_block_size, jacobians[i]);
- }
- }
-}
-
-string EvaluationToString(const ResidualBlock& block,
- double const* const* parameters,
- double* cost,
- double* residuals,
- double** jacobians) {
- CHECK_NOTNULL(cost);
- CHECK_NOTNULL(residuals);
-
- const int num_parameter_blocks = block.NumParameterBlocks();
- const int num_residuals = block.NumResiduals();
- string result = "";
-
- StringAppendF(&result,
- "Residual Block size: %d parameter blocks x %d residuals\n\n",
- num_parameter_blocks, num_residuals);
- result +=
- "For each parameter block, the value of the parameters are printed in the first column \n" // NOLINT
- "and the value of the jacobian under the corresponding residual. If a ParameterBlock was \n" // NOLINT
- "held constant then the corresponding jacobian is printed as 'Not Computed'. If an entry \n" // NOLINT
- "of the Jacobian/residual array was requested but was not written to by user code, it is \n" // NOLINT
- "indicated by 'Uninitialized'. This is an error. Residuals or Jacobian values evaluating \n" // NOLINT
- "to Inf or NaN is also an error. \n\n"; // NOLINT
-
- string space = "Residuals: ";
- result += space;
- AppendArrayToString(num_residuals, residuals, &result);
- StringAppendF(&result, "\n\n");
-
- for (int i = 0; i < num_parameter_blocks; ++i) {
- const int parameter_block_size = block.parameter_blocks()[i]->Size();
- StringAppendF(
- &result, "Parameter Block %d, size: %d\n", i, parameter_block_size);
- StringAppendF(&result, "\n");
- for (int j = 0; j < parameter_block_size; ++j) {
- AppendArrayToString(1, parameters[i] + j, &result);
- StringAppendF(&result, "| ");
- for (int k = 0; k < num_residuals; ++k) {
- AppendArrayToString(1,
- (jacobians != NULL && jacobians[i] != NULL)
- ? jacobians[i] + k * parameter_block_size + j
- : NULL,
- &result);
- }
- StringAppendF(&result, "\n");
- }
- StringAppendF(&result, "\n");
- }
- StringAppendF(&result, "\n");
- return result;
-}
-
-bool IsEvaluationValid(const ResidualBlock& block,
- double const* const* parameters,
- double* cost,
- double* residuals,
- double** jacobians) {
- const int num_parameter_blocks = block.NumParameterBlocks();
- const int num_residuals = block.NumResiduals();
-
- if (!IsArrayValid(num_residuals, residuals)) {
- return false;
- }
-
- if (jacobians != NULL) {
- for (int i = 0; i < num_parameter_blocks; ++i) {
- const int parameter_block_size = block.parameter_blocks()[i]->Size();
- if (!IsArrayValid(num_residuals * parameter_block_size, jacobians[i])) {
- return false;
- }
- }
- }
-
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h
deleted file mode 100644
index 7051c2112fd..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Utility routines for ResidualBlock evaluation.
-//
-// These are useful for detecting two common class of errors.
-//
-// 1. Uninitialized memory - where the user for some reason did not
-// compute part of a cost/residual/jacobian.
-//
-// 2. Numerical failure while computing the cost/residual/jacobian,
-// e.g. NaN, infinities etc. This is particularly useful since the
-// automatic differentiation code does computations that are not
-// evident to the user and can silently generate hard to debug errors.
-
-#ifndef CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
-#define CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
-
-#include <string>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-class ResidualBlock;
-
-// Invalidate cost, resdual and jacobian arrays (if not NULL).
-void InvalidateEvaluation(const ResidualBlock& block,
- double* cost,
- double* residuals,
- double** jacobians);
-
-// Check if any of the arrays cost, residuals or jacobians contains an
-// NaN, return true if it does.
-bool IsEvaluationValid(const ResidualBlock& block,
- double const* const* parameters,
- double* cost,
- double* residuals,
- double** jacobians);
-
-// Create a string representation of the Residual block containing the
-// value of the parameters, residuals and jacobians if present.
-// Useful for debugging output.
-string EvaluationToString(const ResidualBlock& block,
- double const* const* parameters,
- double* cost,
- double* residuals,
- double** jacobians);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
deleted file mode 100644
index 33f812b8c96..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
+++ /dev/null
@@ -1,664 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/internal/port.h"
-
-#include <algorithm>
-#include <ctime>
-#include <set>
-#include <vector>
-
-#include "ceres/block_random_access_dense_matrix.h"
-#include "ceres/block_random_access_matrix.h"
-#include "ceres/block_random_access_sparse_matrix.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/conjugate_gradients_solver.h"
-#include "ceres/cxsparse.h"
-#include "ceres/detect_structure.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/lapack.h"
-#include "ceres/linear_solver.h"
-#include "ceres/schur_complement_solver.h"
-#include "ceres/suitesparse.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-#include "Eigen/Dense"
-#include "Eigen/SparseCore"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-class BlockRandomAccessSparseMatrixAdapter : public LinearOperator {
- public:
- explicit BlockRandomAccessSparseMatrixAdapter(
- const BlockRandomAccessSparseMatrix& m)
- : m_(m) {
- }
-
- virtual ~BlockRandomAccessSparseMatrixAdapter() {}
-
- // y = y + Ax;
- virtual void RightMultiply(const double* x, double* y) const {
- m_.SymmetricRightMultiply(x, y);
- }
-
- // y = y + A'x;
- virtual void LeftMultiply(const double* x, double* y) const {
- m_.SymmetricRightMultiply(x, y);
- }
-
- virtual int num_rows() const { return m_.num_rows(); }
- virtual int num_cols() const { return m_.num_rows(); }
-
- private:
- const BlockRandomAccessSparseMatrix& m_;
-};
-
-class BlockRandomAccessDiagonalMatrixAdapter : public LinearOperator {
- public:
- explicit BlockRandomAccessDiagonalMatrixAdapter(
- const BlockRandomAccessDiagonalMatrix& m)
- : m_(m) {
- }
-
- virtual ~BlockRandomAccessDiagonalMatrixAdapter() {}
-
- // y = y + Ax;
- virtual void RightMultiply(const double* x, double* y) const {
- m_.RightMultiply(x, y);
- }
-
- // y = y + A'x;
- virtual void LeftMultiply(const double* x, double* y) const {
- m_.RightMultiply(x, y);
- }
-
- virtual int num_rows() const { return m_.num_rows(); }
- virtual int num_cols() const { return m_.num_rows(); }
-
- private:
- const BlockRandomAccessDiagonalMatrix& m_;
-};
-
-} // namespace
-
-LinearSolver::Summary SchurComplementSolver::SolveImpl(
- BlockSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x) {
- EventLogger event_logger("SchurComplementSolver::Solve");
-
- if (eliminator_.get() == NULL) {
- InitStorage(A->block_structure());
- DetectStructure(*A->block_structure(),
- options_.elimination_groups[0],
- &options_.row_block_size,
- &options_.e_block_size,
- &options_.f_block_size);
- eliminator_.reset(CHECK_NOTNULL(SchurEliminatorBase::Create(options_)));
- eliminator_->Init(options_.elimination_groups[0], A->block_structure());
- };
- fill(x, x + A->num_cols(), 0.0);
- event_logger.AddEvent("Setup");
-
- eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get());
- event_logger.AddEvent("Eliminate");
-
- double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
- const LinearSolver::Summary summary =
- SolveReducedLinearSystem(per_solve_options, reduced_solution);
- event_logger.AddEvent("ReducedSolve");
-
- if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
- eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x);
- event_logger.AddEvent("BackSubstitute");
- }
-
- return summary;
-}
-
-// Initialize a BlockRandomAccessDenseMatrix to store the Schur
-// complement.
-void DenseSchurComplementSolver::InitStorage(
- const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().elimination_groups[0];
- const int num_col_blocks = bs->cols.size();
-
- vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
- for (int i = num_eliminate_blocks, j = 0;
- i < num_col_blocks;
- ++i, ++j) {
- blocks[j] = bs->cols[i].size;
- }
-
- set_lhs(new BlockRandomAccessDenseMatrix(blocks));
- set_rhs(new double[lhs()->num_rows()]);
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessDenseMatrix. The linear system is solved using
-// Eigen's Cholesky factorization.
-LinearSolver::Summary
-DenseSchurComplementSolver::SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- const BlockRandomAccessDenseMatrix* m =
- down_cast<const BlockRandomAccessDenseMatrix*>(lhs());
- const int num_rows = m->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- return summary;
- }
-
- summary.num_iterations = 1;
-
- if (options().dense_linear_algebra_library_type == EIGEN) {
- Eigen::LLT<Matrix, Eigen::Upper> llt =
- ConstMatrixRef(m->values(), num_rows, num_rows)
- .selfadjointView<Eigen::Upper>()
- .llt();
- if (llt.info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message =
- "Eigen failure. Unable to perform dense Cholesky factorization.";
- return summary;
- }
-
- VectorRef(solution, num_rows) = llt.solve(ConstVectorRef(rhs(), num_rows));
- } else {
- VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
- summary.termination_type =
- LAPACK::SolveInPlaceUsingCholesky(num_rows,
- m->values(),
- solution,
- &summary.message);
- }
-
- return summary;
-}
-
-SparseSchurComplementSolver::SparseSchurComplementSolver(
- const LinearSolver::Options& options)
- : SchurComplementSolver(options),
- factor_(NULL),
- cxsparse_factor_(NULL) {
-}
-
-SparseSchurComplementSolver::~SparseSchurComplementSolver() {
- if (factor_ != NULL) {
- ss_.Free(factor_);
- factor_ = NULL;
- }
-
- if (cxsparse_factor_ != NULL) {
- cxsparse_.Free(cxsparse_factor_);
- cxsparse_factor_ = NULL;
- }
-}
-
-// Determine the non-zero blocks in the Schur Complement matrix, and
-// initialize a BlockRandomAccessSparseMatrix object.
-void SparseSchurComplementSolver::InitStorage(
- const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().elimination_groups[0];
- const int num_col_blocks = bs->cols.size();
- const int num_row_blocks = bs->rows.size();
-
- blocks_.resize(num_col_blocks - num_eliminate_blocks, 0);
- for (int i = num_eliminate_blocks; i < num_col_blocks; ++i) {
- blocks_[i - num_eliminate_blocks] = bs->cols[i].size;
- }
-
- set<pair<int, int> > block_pairs;
- for (int i = 0; i < blocks_.size(); ++i) {
- block_pairs.insert(make_pair(i, i));
- }
-
- int r = 0;
- while (r < num_row_blocks) {
- int e_block_id = bs->rows[r].cells.front().block_id;
- if (e_block_id >= num_eliminate_blocks) {
- break;
- }
- vector<int> f_blocks;
-
- // Add to the chunk until the first block in the row is
- // different than the one in the first row for the chunk.
- for (; r < num_row_blocks; ++r) {
- const CompressedRow& row = bs->rows[r];
- if (row.cells.front().block_id != e_block_id) {
- break;
- }
-
- // Iterate over the blocks in the row, ignoring the first
- // block since it is the one to be eliminated.
- for (int c = 1; c < row.cells.size(); ++c) {
- const Cell& cell = row.cells[c];
- f_blocks.push_back(cell.block_id - num_eliminate_blocks);
- }
- }
-
- sort(f_blocks.begin(), f_blocks.end());
- f_blocks.erase(unique(f_blocks.begin(), f_blocks.end()), f_blocks.end());
- for (int i = 0; i < f_blocks.size(); ++i) {
- for (int j = i + 1; j < f_blocks.size(); ++j) {
- block_pairs.insert(make_pair(f_blocks[i], f_blocks[j]));
- }
- }
- }
-
- // Remaing rows do not contribute to the chunks and directly go
- // into the schur complement via an outer product.
- for (; r < num_row_blocks; ++r) {
- const CompressedRow& row = bs->rows[r];
- CHECK_GE(row.cells.front().block_id, num_eliminate_blocks);
- for (int i = 0; i < row.cells.size(); ++i) {
- int r_block1_id = row.cells[i].block_id - num_eliminate_blocks;
- for (int j = 0; j < row.cells.size(); ++j) {
- int r_block2_id = row.cells[j].block_id - num_eliminate_blocks;
- if (r_block1_id <= r_block2_id) {
- block_pairs.insert(make_pair(r_block1_id, r_block2_id));
- }
- }
- }
- }
-
- set_lhs(new BlockRandomAccessSparseMatrix(blocks_, block_pairs));
- set_rhs(new double[lhs()->num_rows()]);
-}
-
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
- if (options().type == ITERATIVE_SCHUR) {
- CHECK(options().use_explicit_schur_complement);
- return SolveReducedLinearSystemUsingConjugateGradients(per_solve_options,
- solution);
- }
-
- switch (options().sparse_linear_algebra_library_type) {
- case SUITE_SPARSE:
- return SolveReducedLinearSystemUsingSuiteSparse(per_solve_options,
- solution);
- case CX_SPARSE:
- return SolveReducedLinearSystemUsingCXSparse(per_solve_options,
- solution);
- case EIGEN_SPARSE:
- return SolveReducedLinearSystemUsingEigen(per_solve_options,
- solution);
- default:
- LOG(FATAL) << "Unknown sparse linear algebra library : "
- << options().sparse_linear_algebra_library_type;
- }
-
- return LinearSolver::Summary();
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessSparseMatrix. The linear system is solved using
-// CHOLMOD's sparse cholesky factorization routines.
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
-#ifdef CERES_NO_SUITESPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message = "Ceres was not built with SuiteSparse support. "
- "Therefore, SPARSE_SCHUR cannot be used with SUITE_SPARSE";
- return summary;
-
-#else
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- TripletSparseMatrix* tsm =
- const_cast<TripletSparseMatrix*>(
- down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
- const int num_rows = tsm->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- return summary;
- }
-
- summary.num_iterations = 1;
- cholmod_sparse* cholmod_lhs = NULL;
- if (options().use_postordering) {
- // If we are going to do a full symbolic analysis of the schur
- // complement matrix from scratch and not rely on the
- // pre-ordering, then the fastest path in cholmod_factorize is the
- // one corresponding to upper triangular matrices.
-
- // Create a upper triangular symmetric matrix.
- cholmod_lhs = ss_.CreateSparseMatrix(tsm);
- cholmod_lhs->stype = 1;
-
- if (factor_ == NULL) {
- factor_ = ss_.BlockAnalyzeCholesky(cholmod_lhs,
- blocks_,
- blocks_,
- &summary.message);
- }
- } else {
- // If we are going to use the natural ordering (i.e. rely on the
- // pre-ordering computed by solver_impl.cc), then the fastest
- // path in cholmod_factorize is the one corresponding to lower
- // triangular matrices.
-
- // Create a upper triangular symmetric matrix.
- cholmod_lhs = ss_.CreateSparseMatrixTranspose(tsm);
- cholmod_lhs->stype = -1;
-
- if (factor_ == NULL) {
- factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(cholmod_lhs,
- &summary.message);
- }
- }
-
- if (factor_ == NULL) {
- ss_.Free(cholmod_lhs);
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- // No need to set message as it has already been set by the
- // symbolic analysis routines above.
- return summary;
- }
-
- summary.termination_type =
- ss_.Cholesky(cholmod_lhs, factor_, &summary.message);
-
- ss_.Free(cholmod_lhs);
-
- if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
- // No need to set message as it has already been set by the
- // numeric factorization routine above.
- return summary;
- }
-
- cholmod_dense* cholmod_rhs =
- ss_.CreateDenseVector(const_cast<double*>(rhs()), num_rows, num_rows);
- cholmod_dense* cholmod_solution = ss_.Solve(factor_,
- cholmod_rhs,
- &summary.message);
- ss_.Free(cholmod_rhs);
-
- if (cholmod_solution == NULL) {
- summary.message =
- "SuiteSparse failure. Unable to perform triangular solve.";
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- return summary;
- }
-
- VectorRef(solution, num_rows)
- = VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
- ss_.Free(cholmod_solution);
- return summary;
-#endif // CERES_NO_SUITESPARSE
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessSparseMatrix. The linear system is solved using
-// CXSparse's sparse cholesky factorization routines.
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingCXSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
-#ifdef CERES_NO_CXSPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message = "Ceres was not built with CXSparse support. "
- "Therefore, SPARSE_SCHUR cannot be used with CX_SPARSE";
- return summary;
-
-#else
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- // Extract the TripletSparseMatrix that is used for actually storing S.
- TripletSparseMatrix* tsm =
- const_cast<TripletSparseMatrix*>(
- down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
- const int num_rows = tsm->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- return summary;
- }
-
- cs_di* lhs = CHECK_NOTNULL(cxsparse_.CreateSparseMatrix(tsm));
- VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
-
- // Compute symbolic factorization if not available.
- if (cxsparse_factor_ == NULL) {
- cxsparse_factor_ = cxsparse_.BlockAnalyzeCholesky(lhs, blocks_, blocks_);
- }
-
- if (cxsparse_factor_ == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "CXSparse failure. Unable to find symbolic factorization.";
- } else if (!cxsparse_.SolveCholesky(lhs, cxsparse_factor_, solution)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "CXSparse::SolveCholesky failed.";
- }
-
- cxsparse_.Free(lhs);
- return summary;
-#endif // CERES_NO_CXPARSE
-}
-
-// Solve the system Sx = r, assuming that the matrix S is stored in a
-// BlockRandomAccessSparseMatrix. The linear system is solved using
-// Eigen's sparse cholesky factorization routines.
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingEigen(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
-#ifndef CERES_USE_EIGEN_SPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_SCHUR cannot be used with EIGEN_SPARSE. "
- "Ceres was not built with support for "
- "Eigen's SimplicialLDLT decomposition. "
- "This requires enabling building with -DEIGENSPARSE=ON.";
- return summary;
-
-#else
- EventLogger event_logger("SchurComplementSolver::EigenSolve");
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- // Extract the TripletSparseMatrix that is used for actually storing S.
- TripletSparseMatrix* tsm =
- const_cast<TripletSparseMatrix*>(
- down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
- const int num_rows = tsm->num_rows();
-
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- return summary;
- }
-
- // This is an upper triangular matrix.
- CompressedRowSparseMatrix crsm(*tsm);
- // Map this to a column major, lower triangular matrix.
- Eigen::MappedSparseMatrix<double, Eigen::ColMajor> eigen_lhs(
- crsm.num_rows(),
- crsm.num_rows(),
- crsm.num_nonzeros(),
- crsm.mutable_rows(),
- crsm.mutable_cols(),
- crsm.mutable_values());
- event_logger.AddEvent("ToCompressedRowSparseMatrix");
-
- // Compute symbolic factorization if one does not exist.
- if (simplicial_ldlt_.get() == NULL) {
- simplicial_ldlt_.reset(new SimplicialLDLT);
- // This ordering is quite bad. The scalar ordering produced by the
- // AMD algorithm is quite bad and can be an order of magnitude
- // worse than the one computed using the block version of the
- // algorithm.
- simplicial_ldlt_->analyzePattern(eigen_lhs);
- event_logger.AddEvent("Analysis");
- if (simplicial_ldlt_->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "Eigen failure. Unable to find symbolic factorization.";
- return summary;
- }
- }
-
- simplicial_ldlt_->factorize(eigen_lhs);
- event_logger.AddEvent("Factorize");
- if (simplicial_ldlt_->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to find numeric factoriztion.";
- return summary;
- }
-
- VectorRef(solution, num_rows) =
- simplicial_ldlt_->solve(ConstVectorRef(rhs(), num_rows));
- event_logger.AddEvent("Solve");
- if (simplicial_ldlt_->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to do triangular solve.";
- }
-
- return summary;
-#endif // CERES_USE_EIGEN_SPARSE
-}
-
-LinearSolver::Summary
-SparseSchurComplementSolver::SolveReducedLinearSystemUsingConjugateGradients(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) {
- const int num_rows = lhs()->num_rows();
- // The case where there are no f blocks, and the system is block
- // diagonal.
- if (num_rows == 0) {
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
- return summary;
- }
-
- // Only SCHUR_JACOBI is supported over here right now.
- CHECK_EQ(options().preconditioner_type, SCHUR_JACOBI);
-
- if (preconditioner_.get() == NULL) {
- preconditioner_.reset(new BlockRandomAccessDiagonalMatrix(blocks_));
- }
-
- BlockRandomAccessSparseMatrix* sc =
- down_cast<BlockRandomAccessSparseMatrix*>(
- const_cast<BlockRandomAccessMatrix*>(lhs()));
-
- // Extract block diagonal from the Schur complement to construct the
- // schur_jacobi preconditioner.
- for (int i = 0; i < blocks_.size(); ++i) {
- const int block_size = blocks_[i];
-
- int sc_r, sc_c, sc_row_stride, sc_col_stride;
- CellInfo* sc_cell_info =
- CHECK_NOTNULL(sc->GetCell(i, i,
- &sc_r, &sc_c,
- &sc_row_stride, &sc_col_stride));
- MatrixRef sc_m(sc_cell_info->values, sc_row_stride, sc_col_stride);
-
- int pre_r, pre_c, pre_row_stride, pre_col_stride;
- CellInfo* pre_cell_info = CHECK_NOTNULL(
- preconditioner_->GetCell(i, i,
- &pre_r, &pre_c,
- &pre_row_stride, &pre_col_stride));
- MatrixRef pre_m(pre_cell_info->values, pre_row_stride, pre_col_stride);
-
- pre_m.block(pre_r, pre_c, block_size, block_size) =
- sc_m.block(sc_r, sc_c, block_size, block_size);
- }
- preconditioner_->Invert();
-
- VectorRef(solution, num_rows).setZero();
-
- scoped_ptr<LinearOperator> lhs_adapter(
- new BlockRandomAccessSparseMatrixAdapter(*sc));
- scoped_ptr<LinearOperator> preconditioner_adapter(
- new BlockRandomAccessDiagonalMatrixAdapter(*preconditioner_));
-
-
- LinearSolver::Options cg_options;
- cg_options.min_num_iterations = options().min_num_iterations;
- cg_options.max_num_iterations = options().max_num_iterations;
- ConjugateGradientsSolver cg_solver(cg_options);
-
- LinearSolver::PerSolveOptions cg_per_solve_options;
- cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
- cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
- cg_per_solve_options.preconditioner = preconditioner_adapter.get();
-
- return cg_solver.Solve(lhs_adapter.get(),
- rhs(),
- cg_per_solve_options,
- solution);
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
deleted file mode 100644
index 93d23e3d012..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
+++ /dev/null
@@ -1,226 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
-#define CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
-
-#include <set>
-#include <utility>
-#include <vector>
-
-#include "ceres/internal/port.h"
-
-#include "ceres/block_random_access_matrix.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/cxsparse.h"
-#include "ceres/linear_solver.h"
-#include "ceres/schur_eliminator.h"
-#include "ceres/suitesparse.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "ceres/block_random_access_diagonal_matrix.h"
-
-#ifdef CERES_USE_EIGEN_SPARSE
-#include "Eigen/SparseCholesky"
-#include "Eigen/OrderingMethods"
-#endif
-
-namespace ceres {
-namespace internal {
-
-class BlockSparseMatrix;
-
-// Base class for Schur complement based linear least squares
-// solvers. It assumes that the input linear system Ax = b can be
-// partitioned into
-//
-// E y + F z = b
-//
-// Where x = [y;z] is a partition of the variables. The paritioning
-// of the variables is such that, E'E is a block diagonal
-// matrix. Further, the rows of A are ordered so that for every
-// variable block in y, all the rows containing that variable block
-// occur as a vertically contiguous block. i.e the matrix A looks like
-//
-// E F
-// A = [ y1 0 0 0 | z1 0 0 0 z5]
-// [ y1 0 0 0 | z1 z2 0 0 0]
-// [ 0 y2 0 0 | 0 0 z3 0 0]
-// [ 0 0 y3 0 | z1 z2 z3 z4 z5]
-// [ 0 0 y3 0 | z1 0 0 0 z5]
-// [ 0 0 0 y4 | 0 0 0 0 z5]
-// [ 0 0 0 y4 | 0 z2 0 0 0]
-// [ 0 0 0 y4 | 0 0 0 0 0]
-// [ 0 0 0 0 | z1 0 0 0 0]
-// [ 0 0 0 0 | 0 0 z3 z4 z5]
-//
-// This structure should be reflected in the corresponding
-// CompressedRowBlockStructure object associated with A. The linear
-// system Ax = b should either be well posed or the array D below
-// should be non-null and the diagonal matrix corresponding to it
-// should be non-singular.
-//
-// SchurComplementSolver has two sub-classes.
-//
-// DenseSchurComplementSolver: For problems where the Schur complement
-// matrix is small and dense, or if CHOLMOD/SuiteSparse is not
-// installed. For structure from motion problems, this is solver can
-// be used for problems with upto a few hundred cameras.
-//
-// SparseSchurComplementSolver: For problems where the Schur
-// complement matrix is large and sparse. It requires that
-// CHOLMOD/SuiteSparse be installed, as it uses CHOLMOD to find a
-// sparse Cholesky factorization of the Schur complement. This solver
-// can be used for solving structure from motion problems with tens of
-// thousands of cameras, though depending on the exact sparsity
-// structure, it maybe better to use an iterative solver.
-//
-// The two solvers can be instantiated by calling
-// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
-// set to DENSE_SCHUR and SPARSE_SCHUR
-// respectively. LinearSolver::Options::elimination_groups[0] should be
-// at least 1.
-class SchurComplementSolver : public BlockSparseMatrixSolver {
- public:
- explicit SchurComplementSolver(const LinearSolver::Options& options)
- : options_(options) {
- CHECK_GT(options.elimination_groups.size(), 1);
- CHECK_GT(options.elimination_groups[0], 0);
- }
-
- // LinearSolver methods
- virtual ~SchurComplementSolver() {}
- virtual LinearSolver::Summary SolveImpl(
- BlockSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
-
- protected:
- const LinearSolver::Options& options() const { return options_; }
-
- const BlockRandomAccessMatrix* lhs() const { return lhs_.get(); }
- void set_lhs(BlockRandomAccessMatrix* lhs) { lhs_.reset(lhs); }
- const double* rhs() const { return rhs_.get(); }
- void set_rhs(double* rhs) { rhs_.reset(rhs); }
-
- private:
- virtual void InitStorage(const CompressedRowBlockStructure* bs) = 0;
- virtual LinearSolver::Summary SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution) = 0;
-
- LinearSolver::Options options_;
-
- scoped_ptr<SchurEliminatorBase> eliminator_;
- scoped_ptr<BlockRandomAccessMatrix> lhs_;
- scoped_array<double> rhs_;
-
- CERES_DISALLOW_COPY_AND_ASSIGN(SchurComplementSolver);
-};
-
-// Dense Cholesky factorization based solver.
-class DenseSchurComplementSolver : public SchurComplementSolver {
- public:
- explicit DenseSchurComplementSolver(const LinearSolver::Options& options)
- : SchurComplementSolver(options) {}
- virtual ~DenseSchurComplementSolver() {}
-
- private:
- virtual void InitStorage(const CompressedRowBlockStructure* bs);
- virtual LinearSolver::Summary SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
-
- CERES_DISALLOW_COPY_AND_ASSIGN(DenseSchurComplementSolver);
-};
-
-// Sparse Cholesky factorization based solver.
-class SparseSchurComplementSolver : public SchurComplementSolver {
- public:
- explicit SparseSchurComplementSolver(const LinearSolver::Options& options);
- virtual ~SparseSchurComplementSolver();
-
- private:
- virtual void InitStorage(const CompressedRowBlockStructure* bs);
- virtual LinearSolver::Summary SolveReducedLinearSystem(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingSuiteSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingCXSparse(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingEigen(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
- LinearSolver::Summary SolveReducedLinearSystemUsingConjugateGradients(
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* solution);
-
- // Size of the blocks in the Schur complement.
- vector<int> blocks_;
-
- SuiteSparse ss_;
- // Symbolic factorization of the reduced linear system. Precomputed
- // once and reused in subsequent calls.
- cholmod_factor* factor_;
-
- CXSparse cxsparse_;
- // Cached factorization
- cs_dis* cxsparse_factor_;
-
-#ifdef CERES_USE_EIGEN_SPARSE
-
- // The preprocessor gymnastics here are dealing with the fact that
- // before version 3.2.2, Eigen did not support a third template
- // parameter to specify the ordering.
-#if EIGEN_VERSION_AT_LEAST(3,2,2)
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower,
- Eigen::NaturalOrdering<int> >
- SimplicialLDLT;
-#else
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Lower>
- SimplicialLDLT;
-#endif
-
- scoped_ptr<SimplicialLDLT> simplicial_ldlt_;
-#endif
-
- scoped_ptr<BlockRandomAccessDiagonalMatrix> preconditioner_;
- CERES_DISALLOW_COPY_AND_ASSIGN(SparseSchurComplementSolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.cc
deleted file mode 100644
index 4d9b175b139..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Template specialization of SchurEliminator.
-//
-// ========================================
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-//=========================================
-//
-// This file is generated using generate_eliminator_specialization.py.
-// Editing it manually is not recommended.
-
-#include "ceres/linear_solver.h"
-#include "ceres/schur_eliminator.h"
-#include "ceres/internal/eigen.h"
-
-namespace ceres {
-namespace internal {
-
-SchurEliminatorBase*
-SchurEliminatorBase::Create(const LinearSolver::Options& options) {
-#ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 2)) {
- return new SchurEliminator<2, 2, 2>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<2, 2, 3>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<2, 2, 4>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 2) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, 2, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<2, 3, 3>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<2, 3, 4>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == 9)) {
- return new SchurEliminator<2, 3, 9>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 3) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, 3, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<2, 4, 3>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<2, 4, 4>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 8)) {
- return new SchurEliminator<2, 4, 8>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 9)) {
- return new SchurEliminator<2, 4, 9>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, 4, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 2) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 2)) {
- return new SchurEliminator<4, 4, 2>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 3)) {
- return new SchurEliminator<4, 4, 3>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == 4)) {
- return new SchurEliminator<4, 4, 4>(options);
- }
- if ((options.row_block_size == 4) &&
- (options.e_block_size == 4) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<4, 4, Eigen::Dynamic>(options);
- }
- if ((options.row_block_size == Eigen::Dynamic) &&
- (options.e_block_size == Eigen::Dynamic) &&
- (options.f_block_size == Eigen::Dynamic)) {
- return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
- }
-
-#endif
- VLOG(1) << "Template specializations not found for <"
- << options.row_block_size << ","
- << options.e_block_size << ","
- << options.f_block_size << ">";
- return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(options);
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.h b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.h
deleted file mode 100644
index 8fe8b9c88b7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator.h
+++ /dev/null
@@ -1,355 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_SCHUR_ELIMINATOR_H_
-#define CERES_INTERNAL_SCHUR_ELIMINATOR_H_
-
-#include <map>
-#include <vector>
-#include "ceres/mutex.h"
-#include "ceres/block_random_access_matrix.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/linear_solver.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-namespace internal {
-
-// Classes implementing the SchurEliminatorBase interface implement
-// variable elimination for linear least squares problems. Assuming
-// that the input linear system Ax = b can be partitioned into
-//
-// E y + F z = b
-//
-// Where x = [y;z] is a partition of the variables. The paritioning
-// of the variables is such that, E'E is a block diagonal matrix. Or
-// in other words, the parameter blocks in E form an independent set
-// of the of the graph implied by the block matrix A'A. Then, this
-// class provides the functionality to compute the Schur complement
-// system
-//
-// S z = r
-//
-// where
-//
-// S = F'F - F'E (E'E)^{-1} E'F and r = F'b - F'E(E'E)^(-1) E'b
-//
-// This is the Eliminate operation, i.e., construct the linear system
-// obtained by eliminating the variables in E.
-//
-// The eliminator also provides the reverse functionality, i.e. given
-// values for z it can back substitute for the values of y, by solving the
-// linear system
-//
-// Ey = b - F z
-//
-// which is done by observing that
-//
-// y = (E'E)^(-1) [E'b - E'F z]
-//
-// The eliminator has a number of requirements.
-//
-// The rows of A are ordered so that for every variable block in y,
-// all the rows containing that variable block occur as a vertically
-// contiguous block. i.e the matrix A looks like
-//
-// E F chunk
-// A = [ y1 0 0 0 | z1 0 0 0 z5] 1
-// [ y1 0 0 0 | z1 z2 0 0 0] 1
-// [ 0 y2 0 0 | 0 0 z3 0 0] 2
-// [ 0 0 y3 0 | z1 z2 z3 z4 z5] 3
-// [ 0 0 y3 0 | z1 0 0 0 z5] 3
-// [ 0 0 0 y4 | 0 0 0 0 z5] 4
-// [ 0 0 0 y4 | 0 z2 0 0 0] 4
-// [ 0 0 0 y4 | 0 0 0 0 0] 4
-// [ 0 0 0 0 | z1 0 0 0 0] non chunk blocks
-// [ 0 0 0 0 | 0 0 z3 z4 z5] non chunk blocks
-//
-// This structure should be reflected in the corresponding
-// CompressedRowBlockStructure object associated with A. The linear
-// system Ax = b should either be well posed or the array D below
-// should be non-null and the diagonal matrix corresponding to it
-// should be non-singular. For simplicity of exposition only the case
-// with a null D is described.
-//
-// The usual way to do the elimination is as follows. Starting with
-//
-// E y + F z = b
-//
-// we can form the normal equations,
-//
-// E'E y + E'F z = E'b
-// F'E y + F'F z = F'b
-//
-// multiplying both sides of the first equation by (E'E)^(-1) and then
-// by F'E we get
-//
-// F'E y + F'E (E'E)^(-1) E'F z = F'E (E'E)^(-1) E'b
-// F'E y + F'F z = F'b
-//
-// now subtracting the two equations we get
-//
-// [FF' - F'E (E'E)^(-1) E'F] z = F'b - F'E(E'E)^(-1) E'b
-//
-// Instead of forming the normal equations and operating on them as
-// general sparse matrices, the algorithm here deals with one
-// parameter block in y at a time. The rows corresponding to a single
-// parameter block yi are known as a chunk, and the algorithm operates
-// on one chunk at a time. The mathematics remains the same since the
-// reduced linear system can be shown to be the sum of the reduced
-// linear systems for each chunk. This can be seen by observing two
-// things.
-//
-// 1. E'E is a block diagonal matrix.
-//
-// 2. When E'F is computed, only the terms within a single chunk
-// interact, i.e for y1 column blocks when transposed and multiplied
-// with F, the only non-zero contribution comes from the blocks in
-// chunk1.
-//
-// Thus, the reduced linear system
-//
-// FF' - F'E (E'E)^(-1) E'F
-//
-// can be re-written as
-//
-// sum_k F_k F_k' - F_k'E_k (E_k'E_k)^(-1) E_k' F_k
-//
-// Where the sum is over chunks and E_k'E_k is dense matrix of size y1
-// x y1.
-//
-// Advanced usage. Uptil now it has been assumed that the user would
-// be interested in all of the Schur Complement S. However, it is also
-// possible to use this eliminator to obtain an arbitrary submatrix of
-// the full Schur complement. When the eliminator is generating the
-// blocks of S, it asks the RandomAccessBlockMatrix instance passed to
-// it if it has storage for that block. If it does, the eliminator
-// computes/updates it, if not it is skipped. This is useful when one
-// is interested in constructing a preconditioner based on the Schur
-// Complement, e.g., computing the block diagonal of S so that it can
-// be used as a preconditioner for an Iterative Substructuring based
-// solver [See Agarwal et al, Bundle Adjustment in the Large, ECCV
-// 2008 for an example of such use].
-//
-// Example usage: Please see schur_complement_solver.cc
-class SchurEliminatorBase {
- public:
- virtual ~SchurEliminatorBase() {}
-
- // Initialize the eliminator. It is the user's responsibilty to call
- // this function before calling Eliminate or BackSubstitute. It is
- // also the caller's responsibilty to ensure that the
- // CompressedRowBlockStructure object passed to this method is the
- // same one (or is equivalent to) the one associated with the
- // BlockSparseMatrix objects below.
- virtual void Init(int num_eliminate_blocks,
- const CompressedRowBlockStructure* bs) = 0;
-
- // Compute the Schur complement system from the augmented linear
- // least squares problem [A;D] x = [b;0]. The left hand side and the
- // right hand side of the reduced linear system are returned in lhs
- // and rhs respectively.
- //
- // It is the caller's responsibility to construct and initialize
- // lhs. Depending upon the structure of the lhs object passed here,
- // the full or a submatrix of the Schur complement will be computed.
- //
- // Since the Schur complement is a symmetric matrix, only the upper
- // triangular part of the Schur complement is computed.
- virtual void Eliminate(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- BlockRandomAccessMatrix* lhs,
- double* rhs) = 0;
-
- // Given values for the variables z in the F block of A, solve for
- // the optimal values of the variables y corresponding to the E
- // block in A.
- virtual void BackSubstitute(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- const double* z,
- double* y) = 0;
- // Factory
- static SchurEliminatorBase* Create(const LinearSolver::Options& options);
-};
-
-// Templated implementation of the SchurEliminatorBase interface. The
-// templating is on the sizes of the row, e and f blocks sizes in the
-// input matrix. In many problems, the sizes of one or more of these
-// blocks are constant, in that case, its worth passing these
-// parameters as template arguments so that they are visible to the
-// compiler and can be used for compile time optimization of the low
-// level linear algebra routines.
-//
-// This implementation is mulithreaded using OpenMP. The level of
-// parallelism is controlled by LinearSolver::Options::num_threads.
-template <int kRowBlockSize = Eigen::Dynamic,
- int kEBlockSize = Eigen::Dynamic,
- int kFBlockSize = Eigen::Dynamic >
-class SchurEliminator : public SchurEliminatorBase {
- public:
- explicit SchurEliminator(const LinearSolver::Options& options)
- : num_threads_(options.num_threads) {
- }
-
- // SchurEliminatorBase Interface
- virtual ~SchurEliminator();
- virtual void Init(int num_eliminate_blocks,
- const CompressedRowBlockStructure* bs);
- virtual void Eliminate(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- BlockRandomAccessMatrix* lhs,
- double* rhs);
- virtual void BackSubstitute(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- const double* z,
- double* y);
-
- private:
- // Chunk objects store combinatorial information needed to
- // efficiently eliminate a whole chunk out of the least squares
- // problem. Consider the first chunk in the example matrix above.
- //
- // [ y1 0 0 0 | z1 0 0 0 z5]
- // [ y1 0 0 0 | z1 z2 0 0 0]
- //
- // One of the intermediate quantities that needs to be calculated is
- // for each row the product of the y block transposed with the
- // non-zero z block, and the sum of these blocks across rows. A
- // temporary array "buffer_" is used for computing and storing them
- // and the buffer_layout maps the indices of the z-blocks to
- // position in the buffer_ array. The size of the chunk is the
- // number of row blocks/residual blocks for the particular y block
- // being considered.
- //
- // For the example chunk shown above,
- //
- // size = 2
- //
- // The entries of buffer_layout will be filled in the following order.
- //
- // buffer_layout[z1] = 0
- // buffer_layout[z5] = y1 * z1
- // buffer_layout[z2] = y1 * z1 + y1 * z5
- typedef map<int, int> BufferLayoutType;
- struct Chunk {
- Chunk() : size(0) {}
- int size;
- int start;
- BufferLayoutType buffer_layout;
- };
-
- void ChunkDiagonalBlockAndGradient(
- const Chunk& chunk,
- const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix* eet,
- double* g,
- double* buffer,
- BlockRandomAccessMatrix* lhs);
-
- void UpdateRhs(const Chunk& chunk,
- const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- const double* inverse_ete_g,
- double* rhs);
-
- void ChunkOuterProduct(const CompressedRowBlockStructure* bs,
- const Matrix& inverse_eet,
- const double* buffer,
- const BufferLayoutType& buffer_layout,
- BlockRandomAccessMatrix* lhs);
- void EBlockRowOuterProduct(const BlockSparseMatrix* A,
- int row_block_index,
- BlockRandomAccessMatrix* lhs);
-
-
- void NoEBlockRowsUpdate(const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- BlockRandomAccessMatrix* lhs,
- double* rhs);
-
- void NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
- int row_block_index,
- BlockRandomAccessMatrix* lhs);
-
- int num_eliminate_blocks_;
-
- // Block layout of the columns of the reduced linear system. Since
- // the f blocks can be of varying size, this vector stores the
- // position of each f block in the row/col of the reduced linear
- // system. Thus lhs_row_layout_[i] is the row/col position of the
- // i^th f block.
- vector<int> lhs_row_layout_;
-
- // Combinatorial structure of the chunks in A. For more information
- // see the documentation of the Chunk object above.
- vector<Chunk> chunks_;
-
- // TODO(sameeragarwal): The following two arrays contain per-thread
- // storage. They should be refactored into a per thread struct.
-
- // Buffer to store the products of the y and z blocks generated
- // during the elimination phase. buffer_ is of size num_threads *
- // buffer_size_. Each thread accesses the chunk
- //
- // [thread_id * buffer_size_ , (thread_id + 1) * buffer_size_]
- //
- scoped_array<double> buffer_;
-
- // Buffer to store per thread matrix matrix products used by
- // ChunkOuterProduct. Like buffer_ it is of size num_threads *
- // buffer_size_. Each thread accesses the chunk
- //
- // [thread_id * buffer_size_ , (thread_id + 1) * buffer_size_ -1]
- //
- scoped_array<double> chunk_outer_product_buffer_;
-
- int buffer_size_;
- int num_threads_;
- int uneliminated_row_begins_;
-
- // Locks for the blocks in the right hand side of the reduced linear
- // system.
- vector<Mutex*> rhs_locks_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SCHUR_ELIMINATOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
deleted file mode 100644
index 305d94e8cc7..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
+++ /dev/null
@@ -1,699 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// TODO(sameeragarwal): row_block_counter can perhaps be replaced by
-// Chunk::start ?
-
-#ifndef CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
-#define CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
-
-// Eigen has an internal threshold switching between different matrix
-// multiplication algorithms. In particular for matrices larger than
-// EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD it uses a cache friendly
-// matrix matrix product algorithm that has a higher setup cost. For
-// matrix sizes close to this threshold, especially when the matrices
-// are thin and long, the default choice may not be optimal. This is
-// the case for us, as the default choice causes a 30% performance
-// regression when we moved from Eigen2 to Eigen3.
-
-#define EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD 10
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
-#include <algorithm>
-#include <map>
-#include "ceres/block_random_access_matrix.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/block_structure.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/map_util.h"
-#include "ceres/schur_eliminator.h"
-#include "ceres/small_blas.h"
-#include "ceres/stl_util.h"
-#include "Eigen/Dense"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::~SchurEliminator() {
- STLDeleteElements(&rhs_locks_);
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-Init(int num_eliminate_blocks, const CompressedRowBlockStructure* bs) {
- CHECK_GT(num_eliminate_blocks, 0)
- << "SchurComplementSolver cannot be initialized with "
- << "num_eliminate_blocks = 0.";
-
- num_eliminate_blocks_ = num_eliminate_blocks;
-
- const int num_col_blocks = bs->cols.size();
- const int num_row_blocks = bs->rows.size();
-
- buffer_size_ = 1;
- chunks_.clear();
- lhs_row_layout_.clear();
-
- int lhs_num_rows = 0;
- // Add a map object for each block in the reduced linear system
- // and build the row/column block structure of the reduced linear
- // system.
- lhs_row_layout_.resize(num_col_blocks - num_eliminate_blocks_);
- for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {
- lhs_row_layout_[i - num_eliminate_blocks_] = lhs_num_rows;
- lhs_num_rows += bs->cols[i].size;
- }
-
- int r = 0;
- // Iterate over the row blocks of A, and detect the chunks. The
- // matrix should already have been ordered so that all rows
- // containing the same y block are vertically contiguous. Along
- // the way also compute the amount of space each chunk will need
- // to perform the elimination.
- while (r < num_row_blocks) {
- const int chunk_block_id = bs->rows[r].cells.front().block_id;
- if (chunk_block_id >= num_eliminate_blocks_) {
- break;
- }
-
- chunks_.push_back(Chunk());
- Chunk& chunk = chunks_.back();
- chunk.size = 0;
- chunk.start = r;
- int buffer_size = 0;
- const int e_block_size = bs->cols[chunk_block_id].size;
-
- // Add to the chunk until the first block in the row is
- // different than the one in the first row for the chunk.
- while (r + chunk.size < num_row_blocks) {
- const CompressedRow& row = bs->rows[r + chunk.size];
- if (row.cells.front().block_id != chunk_block_id) {
- break;
- }
-
- // Iterate over the blocks in the row, ignoring the first
- // block since it is the one to be eliminated.
- for (int c = 1; c < row.cells.size(); ++c) {
- const Cell& cell = row.cells[c];
- if (InsertIfNotPresent(
- &(chunk.buffer_layout), cell.block_id, buffer_size)) {
- buffer_size += e_block_size * bs->cols[cell.block_id].size;
- }
- }
-
- buffer_size_ = max(buffer_size, buffer_size_);
- ++chunk.size;
- }
-
- CHECK_GT(chunk.size, 0);
- r += chunk.size;
- }
- const Chunk& chunk = chunks_.back();
-
- uneliminated_row_begins_ = chunk.start + chunk.size;
- if (num_threads_ > 1) {
- random_shuffle(chunks_.begin(), chunks_.end());
- }
-
- buffer_.reset(new double[buffer_size_ * num_threads_]);
-
- // chunk_outer_product_buffer_ only needs to store e_block_size *
- // f_block_size, which is always less than buffer_size_, so we just
- // allocate buffer_size_ per thread.
- chunk_outer_product_buffer_.reset(new double[buffer_size_ * num_threads_]);
-
- STLDeleteElements(&rhs_locks_);
- rhs_locks_.resize(num_col_blocks - num_eliminate_blocks_);
- for (int i = 0; i < num_col_blocks - num_eliminate_blocks_; ++i) {
- rhs_locks_[i] = new Mutex;
- }
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-Eliminate(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- BlockRandomAccessMatrix* lhs,
- double* rhs) {
- if (lhs->num_rows() > 0) {
- lhs->SetZero();
- VectorRef(rhs, lhs->num_rows()).setZero();
- }
-
- const CompressedRowBlockStructure* bs = A->block_structure();
- const int num_col_blocks = bs->cols.size();
-
- // Add the diagonal to the schur complement.
- if (D != NULL) {
-#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
- for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {
- const int block_id = i - num_eliminate_blocks_;
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block_id, block_id,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- const int block_size = bs->cols[i].size;
- typename EigenTypes<kFBlockSize>::ConstVectorRef
- diag(D + bs->cols[i].position, block_size);
-
- CeresMutexLock l(&cell_info->m);
- MatrixRef m(cell_info->values, row_stride, col_stride);
- m.block(r, c, block_size, block_size).diagonal()
- += diag.array().square().matrix();
- }
- }
- }
-
- // Eliminate y blocks one chunk at a time. For each chunk,x3
- // compute the entries of the normal equations and the gradient
- // vector block corresponding to the y block and then apply
- // Gaussian elimination to them. The matrix ete stores the normal
- // matrix corresponding to the block being eliminated and array
- // buffer_ contains the non-zero blocks in the row corresponding
- // to this y block in the normal equations. This computation is
- // done in ChunkDiagonalBlockAndGradient. UpdateRhs then applies
- // gaussian elimination to the rhs of the normal equations,
- // updating the rhs of the reduced linear system by modifying rhs
- // blocks for all the z blocks that share a row block/residual
- // term with the y block. EliminateRowOuterProduct does the
- // corresponding operation for the lhs of the reduced linear
- // system.
-#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
- for (int i = 0; i < chunks_.size(); ++i) {
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
- double* buffer = buffer_.get() + thread_id * buffer_size_;
- const Chunk& chunk = chunks_[i];
- const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
- const int e_block_size = bs->cols[e_block_id].size;
-
- VectorRef(buffer, buffer_size_).setZero();
-
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
- ete(e_block_size, e_block_size);
-
- if (D != NULL) {
- const typename EigenTypes<kEBlockSize>::ConstVectorRef
- diag(D + bs->cols[e_block_id].position, e_block_size);
- ete = diag.array().square().matrix().asDiagonal();
- } else {
- ete.setZero();
- }
-
- FixedArray<double, 8> g(e_block_size);
- typename EigenTypes<kEBlockSize>::VectorRef gref(g.get(), e_block_size);
- gref.setZero();
-
- // We are going to be computing
- //
- // S += F'F - F'E(E'E)^{-1}E'F
- //
- // for each Chunk. The computation is broken down into a number of
- // function calls as below.
-
- // Compute the outer product of the e_blocks with themselves (ete
- // = E'E). Compute the product of the e_blocks with the
- // corresonding f_blocks (buffer = E'F), the gradient of the terms
- // in this chunk (g) and add the outer product of the f_blocks to
- // Schur complement (S += F'F).
- ChunkDiagonalBlockAndGradient(
- chunk, A, b, chunk.start, &ete, g.get(), buffer, lhs);
-
- // Normally one wouldn't compute the inverse explicitly, but
- // e_block_size will typically be a small number like 3, in
- // which case its much faster to compute the inverse once and
- // use it to multiply other matrices/vectors instead of doing a
- // Solve call over and over again.
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix inverse_ete =
- ete
- .template selfadjointView<Eigen::Upper>()
- .llt()
- .solve(Matrix::Identity(e_block_size, e_block_size));
-
- // For the current chunk compute and update the rhs of the reduced
- // linear system.
- //
- // rhs = F'b - F'E(E'E)^(-1) E'b
-
- FixedArray<double, 8> inverse_ete_g(e_block_size);
- MatrixVectorMultiply<kEBlockSize, kEBlockSize, 0>(
- inverse_ete.data(),
- e_block_size,
- e_block_size,
- g.get(),
- inverse_ete_g.get());
-
- UpdateRhs(chunk, A, b, chunk.start, inverse_ete_g.get(), rhs);
-
- // S -= F'E(E'E)^{-1}E'F
- ChunkOuterProduct(bs, inverse_ete, buffer, chunk.buffer_layout, lhs);
- }
-
- // For rows with no e_blocks, the schur complement update reduces to
- // S += F'F.
- NoEBlockRowsUpdate(A, b, uneliminated_row_begins_, lhs, rhs);
-}
-
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-BackSubstitute(const BlockSparseMatrix* A,
- const double* b,
- const double* D,
- const double* z,
- double* y) {
- const CompressedRowBlockStructure* bs = A->block_structure();
-#pragma omp parallel for num_threads(num_threads_) schedule(dynamic)
- for (int i = 0; i < chunks_.size(); ++i) {
- const Chunk& chunk = chunks_[i];
- const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
- const int e_block_size = bs->cols[e_block_id].size;
-
- double* y_ptr = y + bs->cols[e_block_id].position;
- typename EigenTypes<kEBlockSize>::VectorRef y_block(y_ptr, e_block_size);
-
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix
- ete(e_block_size, e_block_size);
- if (D != NULL) {
- const typename EigenTypes<kEBlockSize>::ConstVectorRef
- diag(D + bs->cols[e_block_id].position, e_block_size);
- ete = diag.array().square().matrix().asDiagonal();
- } else {
- ete.setZero();
- }
-
- const double* values = A->values();
- for (int j = 0; j < chunk.size; ++j) {
- const CompressedRow& row = bs->rows[chunk.start + j];
- const Cell& e_cell = row.cells.front();
- DCHECK_EQ(e_block_id, e_cell.block_id);
-
- FixedArray<double, 8> sj(row.block.size);
-
- typename EigenTypes<kRowBlockSize>::VectorRef(sj.get(), row.block.size) =
- typename EigenTypes<kRowBlockSize>::ConstVectorRef
- (b + bs->rows[chunk.start + j].block.position, row.block.size);
-
- for (int c = 1; c < row.cells.size(); ++c) {
- const int f_block_id = row.cells[c].block_id;
- const int f_block_size = bs->cols[f_block_id].size;
- const int r_block = f_block_id - num_eliminate_blocks_;
-
- MatrixVectorMultiply<kRowBlockSize, kFBlockSize, -1>(
- values + row.cells[c].position, row.block.size, f_block_size,
- z + lhs_row_layout_[r_block],
- sj.get());
- }
-
- MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- sj.get(),
- y_ptr);
-
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- values + e_cell.position, row.block.size, e_block_size,
- ete.data(), 0, 0, e_block_size, e_block_size);
- }
-
- ete.llt().solveInPlace(y_block);
- }
-}
-
-// Update the rhs of the reduced linear system. Compute
-//
-// F'b - F'E(E'E)^(-1) E'b
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-UpdateRhs(const Chunk& chunk,
- const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- const double* inverse_ete_g,
- double* rhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
- const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
- const int e_block_size = bs->cols[e_block_id].size;
-
- int b_pos = bs->rows[row_block_counter].block.position;
- const double* values = A->values();
- for (int j = 0; j < chunk.size; ++j) {
- const CompressedRow& row = bs->rows[row_block_counter + j];
- const Cell& e_cell = row.cells.front();
-
- typename EigenTypes<kRowBlockSize>::Vector sj =
- typename EigenTypes<kRowBlockSize>::ConstVectorRef
- (b + b_pos, row.block.size);
-
- MatrixVectorMultiply<kRowBlockSize, kEBlockSize, -1>(
- values + e_cell.position, row.block.size, e_block_size,
- inverse_ete_g, sj.data());
-
- for (int c = 1; c < row.cells.size(); ++c) {
- const int block_id = row.cells[c].block_id;
- const int block_size = bs->cols[block_id].size;
- const int block = block_id - num_eliminate_blocks_;
- CeresMutexLock l(rhs_locks_[block]);
- MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
- values + row.cells[c].position,
- row.block.size, block_size,
- sj.data(), rhs + lhs_row_layout_[block]);
- }
- b_pos += row.block.size;
- }
-}
-
-// Given a Chunk - set of rows with the same e_block, e.g. in the
-// following Chunk with two rows.
-//
-// E F
-// [ y11 0 0 0 | z11 0 0 0 z51]
-// [ y12 0 0 0 | z12 z22 0 0 0]
-//
-// this function computes twp matrices. The diagonal block matrix
-//
-// ete = y11 * y11' + y12 * y12'
-//
-// and the off diagonal blocks in the Guass Newton Hessian.
-//
-// buffer = [y11'(z11 + z12), y12' * z22, y11' * z51]
-//
-// which are zero compressed versions of the block sparse matrices E'E
-// and E'F.
-//
-// and the gradient of the e_block, E'b.
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-ChunkDiagonalBlockAndGradient(
- const Chunk& chunk,
- const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix* ete,
- double* g,
- double* buffer,
- BlockRandomAccessMatrix* lhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
-
- int b_pos = bs->rows[row_block_counter].block.position;
- const int e_block_size = ete->rows();
-
- // Iterate over the rows in this chunk, for each row, compute the
- // contribution of its F blocks to the Schur complement, the
- // contribution of its E block to the matrix EE' (ete), and the
- // corresponding block in the gradient vector.
- const double* values = A->values();
- for (int j = 0; j < chunk.size; ++j) {
- const CompressedRow& row = bs->rows[row_block_counter + j];
-
- if (row.cells.size() > 1) {
- EBlockRowOuterProduct(A, row_block_counter + j, lhs);
- }
-
- // Extract the e_block, ETE += E_i' E_i
- const Cell& e_cell = row.cells.front();
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- values + e_cell.position, row.block.size, e_block_size,
- ete->data(), 0, 0, e_block_size, e_block_size);
-
- // g += E_i' b_i
- MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- b + b_pos,
- g);
-
-
- // buffer = E'F. This computation is done by iterating over the
- // f_blocks for each row in the chunk.
- for (int c = 1; c < row.cells.size(); ++c) {
- const int f_block_id = row.cells[c].block_id;
- const int f_block_size = bs->cols[f_block_id].size;
- double* buffer_ptr =
- buffer + FindOrDie(chunk.buffer_layout, f_block_id);
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kEBlockSize, kRowBlockSize, kFBlockSize, 1>(
- values + e_cell.position, row.block.size, e_block_size,
- values + row.cells[c].position, row.block.size, f_block_size,
- buffer_ptr, 0, 0, e_block_size, f_block_size);
- }
- b_pos += row.block.size;
- }
-}
-
-// Compute the outer product F'E(E'E)^{-1}E'F and subtract it from the
-// Schur complement matrix, i.e
-//
-// S -= F'E(E'E)^{-1}E'F.
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-ChunkOuterProduct(const CompressedRowBlockStructure* bs,
- const Matrix& inverse_ete,
- const double* buffer,
- const BufferLayoutType& buffer_layout,
- BlockRandomAccessMatrix* lhs) {
- // This is the most computationally expensive part of this
- // code. Profiling experiments reveal that the bottleneck is not the
- // computation of the right-hand matrix product, but memory
- // references to the left hand side.
- const int e_block_size = inverse_ete.rows();
- BufferLayoutType::const_iterator it1 = buffer_layout.begin();
-
-#ifdef CERES_USE_OPENMP
- int thread_id = omp_get_thread_num();
-#else
- int thread_id = 0;
-#endif
- double* b1_transpose_inverse_ete =
- chunk_outer_product_buffer_.get() + thread_id * buffer_size_;
-
- // S(i,j) -= bi' * ete^{-1} b_j
- for (; it1 != buffer_layout.end(); ++it1) {
- const int block1 = it1->first - num_eliminate_blocks_;
- const int block1_size = bs->cols[it1->first].size;
- MatrixTransposeMatrixMultiply
- <kEBlockSize, kFBlockSize, kEBlockSize, kEBlockSize, 0>(
- buffer + it1->second, e_block_size, block1_size,
- inverse_ete.data(), e_block_size, e_block_size,
- b1_transpose_inverse_ete, 0, 0, block1_size, e_block_size);
-
- BufferLayoutType::const_iterator it2 = it1;
- for (; it2 != buffer_layout.end(); ++it2) {
- const int block2 = it2->first - num_eliminate_blocks_;
-
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block1, block2,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- const int block2_size = bs->cols[it2->first].size;
- CeresMutexLock l(&cell_info->m);
- MatrixMatrixMultiply
- <kFBlockSize, kEBlockSize, kEBlockSize, kFBlockSize, -1>(
- b1_transpose_inverse_ete, block1_size, e_block_size,
- buffer + it2->second, e_block_size, block2_size,
- cell_info->values, r, c, row_stride, col_stride);
- }
- }
- }
-}
-
-// For rows with no e_blocks, the schur complement update reduces to S
-// += F'F. This function iterates over the rows of A with no e_block,
-// and calls NoEBlockRowOuterProduct on each row.
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-NoEBlockRowsUpdate(const BlockSparseMatrix* A,
- const double* b,
- int row_block_counter,
- BlockRandomAccessMatrix* lhs,
- double* rhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
- const double* values = A->values();
- for (; row_block_counter < bs->rows.size(); ++row_block_counter) {
- const CompressedRow& row = bs->rows[row_block_counter];
- for (int c = 0; c < row.cells.size(); ++c) {
- const int block_id = row.cells[c].block_id;
- const int block_size = bs->cols[block_id].size;
- const int block = block_id - num_eliminate_blocks_;
- MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
- values + row.cells[c].position, row.block.size, block_size,
- b + row.block.position,
- rhs + lhs_row_layout_[block]);
- }
- NoEBlockRowOuterProduct(A, row_block_counter, lhs);
- }
-}
-
-
-// A row r of A, which has no e_blocks gets added to the Schur
-// Complement as S += r r'. This function is responsible for computing
-// the contribution of a single row r to the Schur complement. It is
-// very similar in structure to EBlockRowOuterProduct except for
-// one difference. It does not use any of the template
-// parameters. This is because the algorithm used for detecting the
-// static structure of the matrix A only pays attention to rows with
-// e_blocks. This is becase rows without e_blocks are rare and
-// typically arise from regularization terms in the original
-// optimization problem, and have a very different structure than the
-// rows with e_blocks. Including them in the static structure
-// detection will lead to most template parameters being set to
-// dynamic. Since the number of rows without e_blocks is small, the
-// lack of templating is not an issue.
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-NoEBlockRowOuterProduct(const BlockSparseMatrix* A,
- int row_block_index,
- BlockRandomAccessMatrix* lhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
- const CompressedRow& row = bs->rows[row_block_index];
- const double* values = A->values();
- for (int i = 0; i < row.cells.size(); ++i) {
- const int block1 = row.cells[i].block_id - num_eliminate_blocks_;
- DCHECK_GE(block1, 0);
-
- const int block1_size = bs->cols[row.cells[i].block_id].size;
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block1, block1,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- CeresMutexLock l(&cell_info->m);
- // This multiply currently ignores the fact that this is a
- // symmetric outer product.
- MatrixTransposeMatrixMultiply
- <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
- values + row.cells[i].position, row.block.size, block1_size,
- values + row.cells[i].position, row.block.size, block1_size,
- cell_info->values, r, c, row_stride, col_stride);
- }
-
- for (int j = i + 1; j < row.cells.size(); ++j) {
- const int block2 = row.cells[j].block_id - num_eliminate_blocks_;
- DCHECK_GE(block2, 0);
- DCHECK_LT(block1, block2);
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block1, block2,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- const int block2_size = bs->cols[row.cells[j].block_id].size;
- CeresMutexLock l(&cell_info->m);
- MatrixTransposeMatrixMultiply
- <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
- values + row.cells[i].position, row.block.size, block1_size,
- values + row.cells[j].position, row.block.size, block2_size,
- cell_info->values, r, c, row_stride, col_stride);
- }
- }
- }
-}
-
-// For a row with an e_block, compute the contribition S += F'F. This
-// function has the same structure as NoEBlockRowOuterProduct, except
-// that this function uses the template parameters.
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-void
-SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::
-EBlockRowOuterProduct(const BlockSparseMatrix* A,
- int row_block_index,
- BlockRandomAccessMatrix* lhs) {
- const CompressedRowBlockStructure* bs = A->block_structure();
- const CompressedRow& row = bs->rows[row_block_index];
- const double* values = A->values();
- for (int i = 1; i < row.cells.size(); ++i) {
- const int block1 = row.cells[i].block_id - num_eliminate_blocks_;
- DCHECK_GE(block1, 0);
-
- const int block1_size = bs->cols[row.cells[i].block_id].size;
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block1, block1,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- CeresMutexLock l(&cell_info->m);
- // block += b1.transpose() * b1;
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
- values + row.cells[i].position, row.block.size, block1_size,
- values + row.cells[i].position, row.block.size, block1_size,
- cell_info->values, r, c, row_stride, col_stride);
- }
-
- for (int j = i + 1; j < row.cells.size(); ++j) {
- const int block2 = row.cells[j].block_id - num_eliminate_blocks_;
- DCHECK_GE(block2, 0);
- DCHECK_LT(block1, block2);
- const int block2_size = bs->cols[row.cells[j].block_id].size;
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = lhs->GetCell(block1, block2,
- &r, &c,
- &row_stride, &col_stride);
- if (cell_info != NULL) {
- // block += b1.transpose() * b2;
- CeresMutexLock l(&cell_info->m);
- MatrixTransposeMatrixMultiply
- <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
- values + row.cells[i].position, row.block.size, block1_size,
- values + row.cells[j].position, row.block.size, block2_size,
- cell_info->values, r, c, row_stride, col_stride);
- }
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
deleted file mode 100644
index cbdb7086102..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/schur_jacobi_preconditioner.h"
-
-#include <utility>
-#include <vector>
-#include "ceres/block_random_access_diagonal_matrix.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/collections_port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-#include "ceres/schur_eliminator.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-SchurJacobiPreconditioner::SchurJacobiPreconditioner(
- const CompressedRowBlockStructure& bs,
- const Preconditioner::Options& options)
- : options_(options) {
- CHECK_GT(options_.elimination_groups.size(), 1);
- CHECK_GT(options_.elimination_groups[0], 0);
- const int num_blocks = bs.cols.size() - options_.elimination_groups[0];
- CHECK_GT(num_blocks, 0)
- << "Jacobian should have atleast 1 f_block for "
- << "SCHUR_JACOBI preconditioner.";
-
- vector<int> blocks(num_blocks);
- for (int i = 0; i < num_blocks; ++i) {
- blocks[i] = bs.cols[i + options_.elimination_groups[0]].size;
- }
-
- m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
- InitEliminator(bs);
-}
-
-SchurJacobiPreconditioner::~SchurJacobiPreconditioner() {
-}
-
-// Initialize the SchurEliminator.
-void SchurJacobiPreconditioner::InitEliminator(
- const CompressedRowBlockStructure& bs) {
- LinearSolver::Options eliminator_options;
- eliminator_options.elimination_groups = options_.elimination_groups;
- eliminator_options.num_threads = options_.num_threads;
- eliminator_options.e_block_size = options_.e_block_size;
- eliminator_options.f_block_size = options_.f_block_size;
- eliminator_options.row_block_size = options_.row_block_size;
- eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
- eliminator_->Init(eliminator_options.elimination_groups[0], &bs);
-}
-
-// Update the values of the preconditioner matrix and factorize it.
-bool SchurJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
- const double* D) {
- const int num_rows = m_->num_rows();
- CHECK_GT(num_rows, 0);
-
- // We need a dummy rhs vector and a dummy b vector since the Schur
- // eliminator combines the computation of the reduced camera matrix
- // with the computation of the right hand side of that linear
- // system.
- //
- // TODO(sameeragarwal): Perhaps its worth refactoring the
- // SchurEliminator::Eliminate function to allow NULL for the rhs. As
- // of now it does not seem to be worth the effort.
- Vector rhs = Vector::Zero(m_->num_rows());
- Vector b = Vector::Zero(A.num_rows());
-
- // Compute a subset of the entries of the Schur complement.
- eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data());
- m_->Invert();
- return true;
-}
-
-void SchurJacobiPreconditioner::RightMultiply(const double* x,
- double* y) const {
- m_->RightMultiply(x, y);
-}
-
-int SchurJacobiPreconditioner::num_rows() const {
- return m_->num_rows();
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
deleted file mode 100644
index 8b528e25075..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Detailed descriptions of these preconditions beyond what is
-// documented here can be found in
-//
-// Bundle Adjustment in the Large
-// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
-// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
-
-#ifndef CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
-#define CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
-
-#include <set>
-#include <vector>
-#include <utility>
-#include "ceres/collections_port.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/preconditioner.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockRandomAccessDiagonalMatrix;
-class BlockSparseMatrix;
-struct CompressedRowBlockStructure;
-class SchurEliminatorBase;
-
-// This class implements the SCHUR_JACOBI preconditioner for Structure
-// from Motion/Bundle Adjustment problems. Full mathematical details
-// can be found in
-//
-// Bundle Adjustment in the Large
-// S. Agarwal, N. Snavely, S. Seitz & R. Szeliski, ECCV 2010
-// http://www.cs.washington.edu/homes/sagarwal/bal.pdf
-//
-// Example usage:
-//
-// Preconditioner::Options options;
-// options.preconditioner_type = SCHUR_JACOBI;
-// options.elimination_groups.push_back(num_points);
-// options.elimination_groups.push_back(num_cameras);
-// SchurJacobiPreconditioner preconditioner(
-// *A.block_structure(), options);
-// preconditioner.Update(A, NULL);
-// preconditioner.RightMultiply(x, y);
-//
-class SchurJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
- public:
- // Initialize the symbolic structure of the preconditioner. bs is
- // the block structure of the linear system to be solved. It is used
- // to determine the sparsity structure of the preconditioner matrix.
- //
- // It has the same structural requirement as other Schur complement
- // based solvers. Please see schur_eliminator.h for more details.
- SchurJacobiPreconditioner(const CompressedRowBlockStructure& bs,
- const Preconditioner::Options& options);
- virtual ~SchurJacobiPreconditioner();
-
- // Preconditioner interface.
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const;
-
- private:
- void InitEliminator(const CompressedRowBlockStructure& bs);
- virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
-
- Preconditioner::Options options_;
- scoped_ptr<SchurEliminatorBase> eliminator_;
- // Preconditioner matrix.
- scoped_ptr<BlockRandomAccessDiagonalMatrix> m_;
- CERES_DISALLOW_COPY_AND_ASSIGN(SchurJacobiPreconditioner);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc b/extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc
deleted file mode 100644
index 6f0ceefd87d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/scratch_evaluate_preparer.h"
-
-#include "ceres/parameter_block.h"
-#include "ceres/program.h"
-#include "ceres/residual_block.h"
-
-namespace ceres {
-namespace internal {
-
-ScratchEvaluatePreparer* ScratchEvaluatePreparer::Create(
- const Program &program,
- int num_threads) {
- ScratchEvaluatePreparer* preparers = new ScratchEvaluatePreparer[num_threads];
- int max_derivatives_per_residual_block =
- program.MaxDerivativesPerResidualBlock();
- for (int i = 0; i < num_threads; i++) {
- preparers[i].Init(max_derivatives_per_residual_block);
- }
- return preparers;
-}
-
-void ScratchEvaluatePreparer::Init(int max_derivatives_per_residual_block) {
- jacobian_scratch_.reset(
- new double[max_derivatives_per_residual_block]);
-}
-
-// Point the jacobian blocks into the scratch area of this evaluate preparer.
-void ScratchEvaluatePreparer::Prepare(const ResidualBlock* residual_block,
- int /* residual_block_index */,
- SparseMatrix* /* jacobian */,
- double** jacobians) {
- double* jacobian_block_cursor = jacobian_scratch_.get();
- int num_residuals = residual_block->NumResiduals();
- int num_parameter_blocks = residual_block->NumParameterBlocks();
- for (int j = 0; j < num_parameter_blocks; ++j) {
- const ParameterBlock* parameter_block =
- residual_block->parameter_blocks()[j];
- if (parameter_block->IsConstant()) {
- jacobians[j] = NULL;
- } else {
- jacobians[j] = jacobian_block_cursor;
- jacobian_block_cursor += num_residuals * parameter_block->LocalSize();
- }
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h b/extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h
deleted file mode 100644
index 6b127081976..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h
+++ /dev/null
@@ -1,69 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-//
-// A scratch evaluate preparer provides temporary storage for the jacobians that
-// are created when running user-provided cost functions. The evaluator takes
-// care to avoid evaluating the jacobian for fixed parameters.
-
-#ifndef CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
-#define CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
-
-#include "ceres/internal/scoped_ptr.h"
-
-namespace ceres {
-namespace internal {
-
-class Program;
-class ResidualBlock;
-class SparseMatrix;
-
-class ScratchEvaluatePreparer {
- public:
- // Create num_threads ScratchEvaluatePreparers.
- static ScratchEvaluatePreparer* Create(const Program &program,
- int num_threads);
-
- // EvaluatePreparer interface
- void Init(int max_derivatives_per_residual_block);
- void Prepare(const ResidualBlock* residual_block,
- int residual_block_index,
- SparseMatrix* jacobian,
- double** jacobians);
-
- private:
- // Scratch space for the jacobians; each jacobian is packed one after another.
- // There is enough scratch to hold all the jacobians for the largest residual.
- scoped_array<double> jacobian_scratch_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.cc b/extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.cc
deleted file mode 100644
index f0f7e0e1e06..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include "ceres/single_linkage_clustering.h"
-
-#include "ceres/graph.h"
-#include "ceres/collections_port.h"
-#include "ceres/graph_algorithms.h"
-
-namespace ceres {
-namespace internal {
-
-int ComputeSingleLinkageClustering(
- const SingleLinkageClusteringOptions& options,
- const WeightedGraph<int>& graph,
- HashMap<int, int>* membership) {
- CHECK_NOTNULL(membership)->clear();
-
- // Initially each vertex is in its own cluster.
- const HashSet<int>& vertices = graph.vertices();
- for (HashSet<int>::const_iterator it = vertices.begin();
- it != vertices.end();
- ++it) {
- (*membership)[*it] = *it;
- }
-
- for (HashSet<int>::const_iterator it1 = vertices.begin();
- it1 != vertices.end();
- ++it1) {
- const int vertex1 = *it1;
- const HashSet<int>& neighbors = graph.Neighbors(vertex1);
- for (HashSet<int>::const_iterator it2 = neighbors.begin();
- it2 != neighbors.end();
- ++it2) {
- const int vertex2 = *it2;
-
- // Since the graph is undirected, only pay attention to one side
- // of the edge and ignore weak edges.
- if ((vertex1 > vertex2) ||
- (graph.EdgeWeight(vertex1, vertex2) < options.min_similarity)) {
- continue;
- }
-
- // Use a union-find algorithm to keep track of the clusters.
- const int c1 = FindConnectedComponent(vertex1, membership);
- const int c2 = FindConnectedComponent(vertex2, membership);
-
- if (c1 == c2) {
- continue;
- }
-
- if (c1 < c2) {
- (*membership)[c2] = c1;
- } else {
- (*membership)[c1] = c2;
- }
- }
- }
-
- // Make sure that every vertex is connected directly to the vertex
- // identifying the cluster.
- int num_clusters = 0;
- for (HashMap<int, int>::iterator it = membership->begin();
- it != membership->end();
- ++it) {
- it->second = FindConnectedComponent(it->first, membership);
- if (it->first == it->second) {
- ++num_clusters;
- }
- }
-
- return num_clusters;
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
diff --git a/extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.h b/extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.h
deleted file mode 100644
index 79c4da114c2..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/single_linkage_clustering.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
-#define CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-
-namespace ceres {
-namespace internal {
-
-struct SingleLinkageClusteringOptions {
- SingleLinkageClusteringOptions()
- : min_similarity(0.99) {
- }
-
- // Graph edges with edge weight less than min_similarity are ignored
- // during the clustering process.
- double min_similarity;
-};
-
-// Compute a partitioning of the vertices of the graph using the
-// single linkage clustering algorithm. Edges with weight less than
-// SingleLinkageClusteringOptions::min_similarity will be ignored.
-//
-// membership upon return will contain a mapping from the vertices of
-// the graph to an integer indicating the identity of the cluster that
-// it belongs to.
-//
-// The return value of this function is the number of clusters
-// identified by the algorithm.
-int ComputeSingleLinkageClustering(
- const SingleLinkageClusteringOptions& options,
- const WeightedGraph<int>& graph,
- HashMap<int, int>* membership);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
-#endif // CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/small_blas.h b/extern/libmv/third_party/ceres/internal/ceres/small_blas.h
deleted file mode 100644
index 5639664b925..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/small_blas.h
+++ /dev/null
@@ -1,381 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Simple blas functions for use in the Schur Eliminator. These are
-// fairly basic implementations which already yield a significant
-// speedup in the eliminator performance.
-
-#ifndef CERES_INTERNAL_SMALL_BLAS_H_
-#define CERES_INTERNAL_SMALL_BLAS_H_
-
-#include "ceres/internal/port.h"
-#include "ceres/internal/eigen.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// The following three macros are used to share code and reduce
-// template junk across the various GEMM variants.
-#define CERES_GEMM_BEGIN(name) \
- template<int kRowA, int kColA, int kRowB, int kColB, int kOperation> \
- inline void name(const double* A, \
- const int num_row_a, \
- const int num_col_a, \
- const double* B, \
- const int num_row_b, \
- const int num_col_b, \
- double* C, \
- const int start_row_c, \
- const int start_col_c, \
- const int row_stride_c, \
- const int col_stride_c)
-
-#define CERES_GEMM_NAIVE_HEADER \
- DCHECK_GT(num_row_a, 0); \
- DCHECK_GT(num_col_a, 0); \
- DCHECK_GT(num_row_b, 0); \
- DCHECK_GT(num_col_b, 0); \
- DCHECK_GE(start_row_c, 0); \
- DCHECK_GE(start_col_c, 0); \
- DCHECK_GT(row_stride_c, 0); \
- DCHECK_GT(col_stride_c, 0); \
- DCHECK((kRowA == Eigen::Dynamic) || (kRowA == num_row_a)); \
- DCHECK((kColA == Eigen::Dynamic) || (kColA == num_col_a)); \
- DCHECK((kRowB == Eigen::Dynamic) || (kRowB == num_row_b)); \
- DCHECK((kColB == Eigen::Dynamic) || (kColB == num_col_b)); \
- const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a); \
- const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a); \
- const int NUM_ROW_B = (kColB != Eigen::Dynamic ? kRowB : num_row_b); \
- const int NUM_COL_B = (kColB != Eigen::Dynamic ? kColB : num_col_b);
-
-#define CERES_GEMM_EIGEN_HEADER \
- const typename EigenTypes<kRowA, kColA>::ConstMatrixRef \
- Aref(A, num_row_a, num_col_a); \
- const typename EigenTypes<kRowB, kColB>::ConstMatrixRef \
- Bref(B, num_row_b, num_col_b); \
- MatrixRef Cref(C, row_stride_c, col_stride_c); \
-
-#define CERES_CALL_GEMM(name) \
- name<kRowA, kColA, kRowB, kColB, kOperation>( \
- A, num_row_a, num_col_a, \
- B, num_row_b, num_col_b, \
- C, start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-
-// For the matrix-matrix functions below, there are three variants for
-// each functionality. Foo, FooNaive and FooEigen. Foo is the one to
-// be called by the user. FooNaive is a basic loop based
-// implementation and FooEigen uses Eigen's implementation. Foo
-// chooses between FooNaive and FooEigen depending on how many of the
-// template arguments are fixed at compile time. Currently, FooEigen
-// is called if all matrix dimensions are compile time
-// constants. FooNaive is called otherwise. This leads to the best
-// performance currently.
-//
-// The MatrixMatrixMultiply variants compute:
-//
-// C op A * B;
-//
-// The MatrixTransposeMatrixMultiply variants compute:
-//
-// C op A' * B
-//
-// where op can be +=, -=, or =.
-//
-// The template parameters (kRowA, kColA, kRowB, kColB) allow
-// specialization of the loop at compile time. If this information is
-// not available, then Eigen::Dynamic should be used as the template
-// argument.
-//
-// kOperation = 1 -> C += A * B
-// kOperation = -1 -> C -= A * B
-// kOperation = 0 -> C = A * B
-//
-// The functions can write into matrices C which are larger than the
-// matrix A * B. This is done by specifying the true size of C via
-// row_stride_c and col_stride_c, and then indicating where A * B
-// should be written into by start_row_c and start_col_c.
-//
-// Graphically if row_stride_c = 10, col_stride_c = 12, start_row_c =
-// 4 and start_col_c = 5, then if A = 3x2 and B = 2x4, we get
-//
-// ------------
-// ------------
-// ------------
-// ------------
-// -----xxxx---
-// -----xxxx---
-// -----xxxx---
-// ------------
-// ------------
-// ------------
-//
-CERES_GEMM_BEGIN(MatrixMatrixMultiplyEigen) {
- CERES_GEMM_EIGEN_HEADER
- Eigen::Block<MatrixRef, kRowA, kColB>
- block(Cref, start_row_c, start_col_c, num_row_a, num_col_b);
-
- if (kOperation > 0) {
- block.noalias() += Aref * Bref;
- } else if (kOperation < 0) {
- block.noalias() -= Aref * Bref;
- } else {
- block.noalias() = Aref * Bref;
- }
-}
-
-CERES_GEMM_BEGIN(MatrixMatrixMultiplyNaive) {
- CERES_GEMM_NAIVE_HEADER
- DCHECK_EQ(NUM_COL_A, NUM_ROW_B);
-
- const int NUM_ROW_C = NUM_ROW_A;
- const int NUM_COL_C = NUM_COL_B;
- DCHECK_LE(start_row_c + NUM_ROW_C, row_stride_c);
- DCHECK_LE(start_col_c + NUM_COL_C, col_stride_c);
-
- for (int row = 0; row < NUM_ROW_C; ++row) {
- for (int col = 0; col < NUM_COL_C; ++col) {
- double tmp = 0.0;
- for (int k = 0; k < NUM_COL_A; ++k) {
- tmp += A[row * NUM_COL_A + k] * B[k * NUM_COL_B + col];
- }
-
- const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
- if (kOperation > 0) {
- C[index] += tmp;
- } else if (kOperation < 0) {
- C[index] -= tmp;
- } else {
- C[index] = tmp;
- }
- }
- }
-}
-
-CERES_GEMM_BEGIN(MatrixMatrixMultiply) {
-#ifdef CERES_NO_CUSTOM_BLAS
-
- CERES_CALL_GEMM(MatrixMatrixMultiplyEigen)
- return;
-
-#else
-
- if (kRowA != Eigen::Dynamic && kColA != Eigen::Dynamic &&
- kRowB != Eigen::Dynamic && kColB != Eigen::Dynamic) {
- CERES_CALL_GEMM(MatrixMatrixMultiplyEigen)
- } else {
- CERES_CALL_GEMM(MatrixMatrixMultiplyNaive)
- }
-
-#endif
-}
-
-CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiplyEigen) {
- CERES_GEMM_EIGEN_HEADER
- Eigen::Block<MatrixRef, kColA, kColB> block(Cref,
- start_row_c, start_col_c,
- num_col_a, num_col_b);
- if (kOperation > 0) {
- block.noalias() += Aref.transpose() * Bref;
- } else if (kOperation < 0) {
- block.noalias() -= Aref.transpose() * Bref;
- } else {
- block.noalias() = Aref.transpose() * Bref;
- }
-}
-
-CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiplyNaive) {
- CERES_GEMM_NAIVE_HEADER
- DCHECK_EQ(NUM_ROW_A, NUM_ROW_B);
-
- const int NUM_ROW_C = NUM_COL_A;
- const int NUM_COL_C = NUM_COL_B;
- DCHECK_LE(start_row_c + NUM_ROW_C, row_stride_c);
- DCHECK_LE(start_col_c + NUM_COL_C, col_stride_c);
-
- for (int row = 0; row < NUM_ROW_C; ++row) {
- for (int col = 0; col < NUM_COL_C; ++col) {
- double tmp = 0.0;
- for (int k = 0; k < NUM_ROW_A; ++k) {
- tmp += A[k * NUM_COL_A + row] * B[k * NUM_COL_B + col];
- }
-
- const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
- if (kOperation > 0) {
- C[index]+= tmp;
- } else if (kOperation < 0) {
- C[index]-= tmp;
- } else {
- C[index]= tmp;
- }
- }
- }
-}
-
-CERES_GEMM_BEGIN(MatrixTransposeMatrixMultiply) {
-#ifdef CERES_NO_CUSTOM_BLAS
-
- CERES_CALL_GEMM(MatrixTransposeMatrixMultiplyEigen)
- return;
-
-#else
-
- if (kRowA != Eigen::Dynamic && kColA != Eigen::Dynamic &&
- kRowB != Eigen::Dynamic && kColB != Eigen::Dynamic) {
- CERES_CALL_GEMM(MatrixTransposeMatrixMultiplyEigen)
- } else {
- CERES_CALL_GEMM(MatrixTransposeMatrixMultiplyNaive)
- }
-
-#endif
-}
-
-// Matrix-Vector multiplication
-//
-// c op A * b;
-//
-// where op can be +=, -=, or =.
-//
-// The template parameters (kRowA, kColA) allow specialization of the
-// loop at compile time. If this information is not available, then
-// Eigen::Dynamic should be used as the template argument.
-//
-// kOperation = 1 -> c += A' * b
-// kOperation = -1 -> c -= A' * b
-// kOperation = 0 -> c = A' * b
-template<int kRowA, int kColA, int kOperation>
-inline void MatrixVectorMultiply(const double* A,
- const int num_row_a,
- const int num_col_a,
- const double* b,
- double* c) {
-#ifdef CERES_NO_CUSTOM_BLAS
- const typename EigenTypes<kRowA, kColA>::ConstMatrixRef
- Aref(A, num_row_a, num_col_a);
- const typename EigenTypes<kColA>::ConstVectorRef bref(b, num_col_a);
- typename EigenTypes<kRowA>::VectorRef cref(c, num_row_a);
-
- // lazyProduct works better than .noalias() for matrix-vector
- // products.
- if (kOperation > 0) {
- cref += Aref.lazyProduct(bref);
- } else if (kOperation < 0) {
- cref -= Aref.lazyProduct(bref);
- } else {
- cref = Aref.lazyProduct(bref);
- }
-#else
-
- DCHECK_GT(num_row_a, 0);
- DCHECK_GT(num_col_a, 0);
- DCHECK((kRowA == Eigen::Dynamic) || (kRowA == num_row_a));
- DCHECK((kColA == Eigen::Dynamic) || (kColA == num_col_a));
-
- const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a);
- const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a);
-
- for (int row = 0; row < NUM_ROW_A; ++row) {
- double tmp = 0.0;
- for (int col = 0; col < NUM_COL_A; ++col) {
- tmp += A[row * NUM_COL_A + col] * b[col];
- }
-
- if (kOperation > 0) {
- c[row] += tmp;
- } else if (kOperation < 0) {
- c[row] -= tmp;
- } else {
- c[row] = tmp;
- }
- }
-#endif // CERES_NO_CUSTOM_BLAS
-}
-
-// Similar to MatrixVectorMultiply, except that A is transposed, i.e.,
-//
-// c op A' * b;
-template<int kRowA, int kColA, int kOperation>
-inline void MatrixTransposeVectorMultiply(const double* A,
- const int num_row_a,
- const int num_col_a,
- const double* b,
- double* c) {
-#ifdef CERES_NO_CUSTOM_BLAS
- const typename EigenTypes<kRowA, kColA>::ConstMatrixRef
- Aref(A, num_row_a, num_col_a);
- const typename EigenTypes<kRowA>::ConstVectorRef bref(b, num_row_a);
- typename EigenTypes<kColA>::VectorRef cref(c, num_col_a);
-
- // lazyProduct works better than .noalias() for matrix-vector
- // products.
- if (kOperation > 0) {
- cref += Aref.transpose().lazyProduct(bref);
- } else if (kOperation < 0) {
- cref -= Aref.transpose().lazyProduct(bref);
- } else {
- cref = Aref.transpose().lazyProduct(bref);
- }
-#else
-
- DCHECK_GT(num_row_a, 0);
- DCHECK_GT(num_col_a, 0);
- DCHECK((kRowA == Eigen::Dynamic) || (kRowA == num_row_a));
- DCHECK((kColA == Eigen::Dynamic) || (kColA == num_col_a));
-
- const int NUM_ROW_A = (kRowA != Eigen::Dynamic ? kRowA : num_row_a);
- const int NUM_COL_A = (kColA != Eigen::Dynamic ? kColA : num_col_a);
-
- for (int row = 0; row < NUM_COL_A; ++row) {
- double tmp = 0.0;
- for (int col = 0; col < NUM_ROW_A; ++col) {
- tmp += A[col * NUM_COL_A + row] * b[col];
- }
-
- if (kOperation > 0) {
- c[row] += tmp;
- } else if (kOperation < 0) {
- c[row] -= tmp;
- } else {
- c[row] = tmp;
- }
- }
-#endif // CERES_NO_CUSTOM_BLAS
-}
-
-#undef CERES_GEMM_BEGIN
-#undef CERES_GEMM_EIGEN_HEADER
-#undef CERES_GEMM_NAIVE_HEADER
-#undef CERES_CALL_GEMM
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SMALL_BLAS_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver.cc b/extern/libmv/third_party/ceres/internal/ceres/solver.cc
deleted file mode 100644
index 3512e156f9e..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/solver.cc
+++ /dev/null
@@ -1,808 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-// sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/solver.h"
-
-#include <algorithm>
-#include <sstream> // NOLINT
-#include <vector>
-#include "ceres/gradient_checking_cost_function.h"
-#include "ceres/internal/port.h"
-#include "ceres/parameter_block_ordering.h"
-#include "ceres/preprocessor.h"
-#include "ceres/problem.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/solver_utils.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-namespace {
-
-#define OPTION_OP(x, y, OP) \
- if (!(options.x OP y)) { \
- std::stringstream ss; \
- ss << "Invalid configuration. "; \
- ss << string("Solver::Options::" #x " = ") << options.x << ". "; \
- ss << "Violated constraint: "; \
- ss << string("Solver::Options::" #x " " #OP " "#y); \
- *error = ss.str(); \
- return false; \
- }
-
-#define OPTION_OP_OPTION(x, y, OP) \
- if (!(options.x OP options.y)) { \
- std::stringstream ss; \
- ss << "Invalid configuration. "; \
- ss << string("Solver::Options::" #x " = ") << options.x << ". "; \
- ss << string("Solver::Options::" #y " = ") << options.y << ". "; \
- ss << "Violated constraint: "; \
- ss << string("Solver::Options::" #x); \
- ss << string(#OP " Solver::Options::" #y "."); \
- *error = ss.str(); \
- return false; \
- }
-
-#define OPTION_GE(x, y) OPTION_OP(x, y, >=);
-#define OPTION_GT(x, y) OPTION_OP(x, y, >);
-#define OPTION_LE(x, y) OPTION_OP(x, y, <=);
-#define OPTION_LT(x, y) OPTION_OP(x, y, <);
-#define OPTION_LE_OPTION(x, y) OPTION_OP_OPTION(x, y, <=)
-#define OPTION_LT_OPTION(x, y) OPTION_OP_OPTION(x, y, <)
-
-bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
- OPTION_GE(max_num_iterations, 0);
- OPTION_GE(max_solver_time_in_seconds, 0.0);
- OPTION_GE(function_tolerance, 0.0);
- OPTION_GE(gradient_tolerance, 0.0);
- OPTION_GE(parameter_tolerance, 0.0);
- OPTION_GT(num_threads, 0);
- OPTION_GT(num_linear_solver_threads, 0);
- if (options.check_gradients) {
- OPTION_GT(gradient_check_relative_precision, 0.0);
- OPTION_GT(numeric_derivative_relative_step_size, 0.0);
- }
- return true;
-}
-
-bool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
- OPTION_GT(initial_trust_region_radius, 0.0);
- OPTION_GT(min_trust_region_radius, 0.0);
- OPTION_GT(max_trust_region_radius, 0.0);
- OPTION_LE_OPTION(min_trust_region_radius, max_trust_region_radius);
- OPTION_LE_OPTION(min_trust_region_radius, initial_trust_region_radius);
- OPTION_LE_OPTION(initial_trust_region_radius, max_trust_region_radius);
- OPTION_GE(min_relative_decrease, 0.0);
- OPTION_GE(min_lm_diagonal, 0.0);
- OPTION_GE(max_lm_diagonal, 0.0);
- OPTION_LE_OPTION(min_lm_diagonal, max_lm_diagonal);
- OPTION_GE(max_num_consecutive_invalid_steps, 0);
- OPTION_GT(eta, 0.0);
- OPTION_GE(min_linear_solver_iterations, 0);
- OPTION_GE(max_linear_solver_iterations, 1);
- OPTION_LE_OPTION(min_linear_solver_iterations, max_linear_solver_iterations);
-
- if (options.use_inner_iterations) {
- OPTION_GE(inner_iteration_tolerance, 0.0);
- }
-
- if (options.use_nonmonotonic_steps) {
- OPTION_GT(max_consecutive_nonmonotonic_steps, 0);
- }
-
- if (options.linear_solver_type == ITERATIVE_SCHUR &&
- options.use_explicit_schur_complement &&
- options.preconditioner_type != SCHUR_JACOBI) {
- *error = "use_explicit_schur_complement only supports "
- "SCHUR_JACOBI as the preconditioner.";
- return false;
- }
-
- if (options.preconditioner_type == CLUSTER_JACOBI &&
- options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
- *error = "CLUSTER_JACOBI requires "
- "Solver::Options::sparse_linear_algebra_library_type to be "
- "SUITE_SPARSE";
- return false;
- }
-
- if (options.preconditioner_type == CLUSTER_TRIDIAGONAL &&
- options.sparse_linear_algebra_library_type != SUITE_SPARSE) {
- *error = "CLUSTER_TRIDIAGONAL requires "
- "Solver::Options::sparse_linear_algebra_library_type to be "
- "SUITE_SPARSE";
- return false;
- }
-
-#ifdef CERES_NO_LAPACK
- if (options.dense_linear_algebra_library_type == LAPACK) {
- if (options.linear_solver_type == DENSE_NORMAL_CHOLESKY) {
- *error = "Can't use DENSE_NORMAL_CHOLESKY with LAPACK because "
- "LAPACK was not enabled when Ceres was built.";
- return false;
- }
-
- if (options.linear_solver_type == DENSE_QR) {
- *error = "Can't use DENSE_QR with LAPACK because "
- "LAPACK was not enabled when Ceres was built.";
- return false;
- }
-
- if (options.linear_solver_type == DENSE_SCHUR) {
- *error = "Can't use DENSE_SCHUR with LAPACK because "
- "LAPACK was not enabled when Ceres was built.";
- return false;
- }
- }
-#endif
-
-#ifdef CERES_NO_SUITESPARSE
- if (options.sparse_linear_algebra_library_type == SUITE_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY with SUITESPARSE because "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- }
-
- if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR with SUITESPARSE because "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- }
-
- if (options.preconditioner_type == CLUSTER_JACOBI) {
- *error = "CLUSTER_JACOBI preconditioner not supported. "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- }
-
- if (options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
- *error = "CLUSTER_TRIDIAGONAL preconditioner not supported. "
- "SuiteSparse was not enabled when Ceres was built.";
- return false;
- }
- }
-#endif
-
-#ifdef CERES_NO_CXSPARSE
- if (options.sparse_linear_algebra_library_type == CX_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY with CX_SPARSE because "
- "CXSparse was not enabled when Ceres was built.";
- return false;
- }
-
- if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR with CX_SPARSE because "
- "CXSparse was not enabled when Ceres was built.";
- return false;
- }
- }
-#endif
-
-#ifndef CERES_USE_EIGEN_SPARSE
- if (options.sparse_linear_algebra_library_type == EIGEN_SPARSE) {
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY) {
- *error = "Can't use SPARSE_NORMAL_CHOLESKY with EIGEN_SPARSE because "
- "Eigen's sparse linear algebra was not enabled when Ceres was "
- "built.";
- return false;
- }
-
- if (options.linear_solver_type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR with EIGEN_SPARSE because "
- "Eigen's sparse linear algebra was not enabled when Ceres was "
- "built.";
- return false;
- }
- }
-#endif
-
- if (options.trust_region_strategy_type == DOGLEG) {
- if (options.linear_solver_type == ITERATIVE_SCHUR ||
- options.linear_solver_type == CGNR) {
- *error = "DOGLEG only supports exact factorization based linear "
- "solvers. If you want to use an iterative solver please "
- "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
- return false;
- }
- }
-
- if (options.trust_region_minimizer_iterations_to_dump.size() > 0 &&
- options.trust_region_problem_dump_format_type != CONSOLE &&
- options.trust_region_problem_dump_directory.empty()) {
- *error = "Solver::Options::trust_region_problem_dump_directory is empty.";
- return false;
- }
-
- if (options.dynamic_sparsity &&
- options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
- *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
- return false;
- }
-
- return true;
-}
-
-bool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
- OPTION_GT(max_lbfgs_rank, 0);
- OPTION_GT(min_line_search_step_size, 0.0);
- OPTION_GT(max_line_search_step_contraction, 0.0);
- OPTION_LT(max_line_search_step_contraction, 1.0);
- OPTION_LT_OPTION(max_line_search_step_contraction,
- min_line_search_step_contraction);
- OPTION_LE(min_line_search_step_contraction, 1.0);
- OPTION_GT(max_num_line_search_step_size_iterations, 0);
- OPTION_GT(line_search_sufficient_function_decrease, 0.0);
- OPTION_LT_OPTION(line_search_sufficient_function_decrease,
- line_search_sufficient_curvature_decrease);
- OPTION_LT(line_search_sufficient_curvature_decrease, 1.0);
- OPTION_GT(max_line_search_step_expansion, 1.0);
-
- if ((options.line_search_direction_type == ceres::BFGS ||
- options.line_search_direction_type == ceres::LBFGS) &&
- options.line_search_type != ceres::WOLFE) {
- *error =
- string("Invalid configuration: Solver::Options::line_search_type = ")
- + string(LineSearchTypeToString(options.line_search_type))
- + string(". When using (L)BFGS, "
- "Solver::Options::line_search_type must be set to WOLFE.");
- return false;
- }
-
- // Warn user if they have requested BISECTION interpolation, but constraints
- // on max/min step size change during line search prevent bisection scaling
- // from occurring. Warn only, as this is likely a user mistake, but one which
- // does not prevent us from continuing.
- LOG_IF(WARNING,
- (options.line_search_interpolation_type == ceres::BISECTION &&
- (options.max_line_search_step_contraction > 0.5 ||
- options.min_line_search_step_contraction < 0.5)))
- << "Line search interpolation type is BISECTION, but specified "
- << "max_line_search_step_contraction: "
- << options.max_line_search_step_contraction << ", and "
- << "min_line_search_step_contraction: "
- << options.min_line_search_step_contraction
- << ", prevent bisection (0.5) scaling, continuing with solve regardless.";
-
- return true;
-}
-
-#undef OPTION_OP
-#undef OPTION_OP_OPTION
-#undef OPTION_GT
-#undef OPTION_GE
-#undef OPTION_LE
-#undef OPTION_LT
-#undef OPTION_LE_OPTION
-#undef OPTION_LT_OPTION
-
-void StringifyOrdering(const vector<int>& ordering, string* report) {
- if (ordering.size() == 0) {
- internal::StringAppendF(report, "AUTOMATIC");
- return;
- }
-
- for (int i = 0; i < ordering.size() - 1; ++i) {
- internal::StringAppendF(report, "%d, ", ordering[i]);
- }
- internal::StringAppendF(report, "%d", ordering.back());
-}
-
-void SummarizeGivenProgram(const internal::Program& program,
- Solver::Summary* summary) {
- summary->num_parameter_blocks = program.NumParameterBlocks();
- summary->num_parameters = program.NumParameters();
- summary->num_effective_parameters = program.NumEffectiveParameters();
- summary->num_residual_blocks = program.NumResidualBlocks();
- summary->num_residuals = program.NumResiduals();
-}
-
-void SummarizeReducedProgram(const internal::Program& program,
- Solver::Summary* summary) {
- summary->num_parameter_blocks_reduced = program.NumParameterBlocks();
- summary->num_parameters_reduced = program.NumParameters();
- summary->num_effective_parameters_reduced = program.NumEffectiveParameters();
- summary->num_residual_blocks_reduced = program.NumResidualBlocks();
- summary->num_residuals_reduced = program.NumResiduals();
-}
-
-void PreSolveSummarize(const Solver::Options& options,
- const internal::ProblemImpl* problem,
- Solver::Summary* summary) {
- SummarizeGivenProgram(problem->program(), summary);
- internal::OrderingToGroupSizes(options.linear_solver_ordering.get(),
- &(summary->linear_solver_ordering_given));
- internal::OrderingToGroupSizes(options.inner_iteration_ordering.get(),
- &(summary->inner_iteration_ordering_given));
-
- summary->dense_linear_algebra_library_type = options.dense_linear_algebra_library_type; // NOLINT
- summary->dogleg_type = options.dogleg_type;
- summary->inner_iteration_time_in_seconds = 0.0;
- summary->inner_iterations_given = options.use_inner_iterations;
- summary->line_search_direction_type = options.line_search_direction_type; // NOLINT
- summary->line_search_interpolation_type = options.line_search_interpolation_type; // NOLINT
- summary->line_search_type = options.line_search_type;
- summary->linear_solver_type_given = options.linear_solver_type;
- summary->max_lbfgs_rank = options.max_lbfgs_rank;
- summary->minimizer_type = options.minimizer_type;
- summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT
- summary->num_linear_solver_threads_given = options.num_linear_solver_threads; // NOLINT
- summary->num_threads_given = options.num_threads;
- summary->preconditioner_type_given = options.preconditioner_type;
- summary->sparse_linear_algebra_library_type = options.sparse_linear_algebra_library_type; // NOLINT
- summary->trust_region_strategy_type = options.trust_region_strategy_type; // NOLINT
- summary->visibility_clustering_type = options.visibility_clustering_type; // NOLINT
-}
-
-void PostSolveSummarize(const internal::PreprocessedProblem& pp,
- Solver::Summary* summary) {
- internal::OrderingToGroupSizes(pp.options.linear_solver_ordering.get(),
- &(summary->linear_solver_ordering_used));
- internal::OrderingToGroupSizes(pp.options.inner_iteration_ordering.get(),
- &(summary->inner_iteration_ordering_used));
-
- summary->inner_iterations_used = pp.inner_iteration_minimizer.get() != NULL; // NOLINT
- summary->linear_solver_type_used = pp.options.linear_solver_type;
- summary->num_linear_solver_threads_used = pp.options.num_linear_solver_threads; // NOLINT
- summary->num_threads_used = pp.options.num_threads;
- summary->preconditioner_type_used = pp.options.preconditioner_type; // NOLINT
-
- internal::SetSummaryFinalCost(summary);
-
- if (pp.reduced_program.get() != NULL) {
- SummarizeReducedProgram(*pp.reduced_program, summary);
- }
-
- // It is possible that no evaluator was created. This would be the
- // case if the preprocessor failed, or if the reduced problem did
- // not contain any parameter blocks. Thus, only extract the
- // evaluator statistics if one exists.
- if (pp.evaluator.get() != NULL) {
- const map<string, double>& evaluator_time_statistics =
- pp.evaluator->TimeStatistics();
- summary->residual_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Residual", 0.0);
- summary->jacobian_evaluation_time_in_seconds =
- FindWithDefault(evaluator_time_statistics, "Evaluator::Jacobian", 0.0);
- }
-
- // Again, like the evaluator, there may or may not be a linear
- // solver from which we can extract run time statistics. In
- // particular the line search solver does not use a linear solver.
- if (pp.linear_solver.get() != NULL) {
- const map<string, double>& linear_solver_time_statistics =
- pp.linear_solver->TimeStatistics();
- summary->linear_solver_time_in_seconds =
- FindWithDefault(linear_solver_time_statistics,
- "LinearSolver::Solve",
- 0.0);
- }
-}
-
-void Minimize(internal::PreprocessedProblem* pp,
- Solver::Summary* summary) {
- using internal::Program;
- using internal::scoped_ptr;
- using internal::Minimizer;
-
- Program* program = pp->reduced_program.get();
- if (pp->reduced_program->NumParameterBlocks() == 0) {
- summary->message = "Function tolerance reached. "
- "No non-constant parameter blocks found.";
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, pp->options.logging_type != SILENT) << summary->message;
- summary->initial_cost = summary->fixed_cost;
- summary->final_cost = summary->fixed_cost;
- return;
- }
-
- scoped_ptr<Minimizer> minimizer(
- Minimizer::Create(pp->options.minimizer_type));
- minimizer->Minimize(pp->minimizer_options,
- pp->reduced_parameters.data(),
- summary);
-
- if (summary->IsSolutionUsable()) {
- program->StateVectorToParameterBlocks(pp->reduced_parameters.data());
- program->CopyParameterBlockStateToUserState();
- }
-}
-
-} // namespace
-
-bool Solver::Options::IsValid(string* error) const {
- if (!CommonOptionsAreValid(*this, error)) {
- return false;
- }
-
- if (minimizer_type == TRUST_REGION) {
- return TrustRegionOptionsAreValid(*this, error);
- }
-
- CHECK_EQ(minimizer_type, LINE_SEARCH);
- return LineSearchOptionsAreValid(*this, error);
-}
-
-Solver::~Solver() {}
-
-void Solver::Solve(const Solver::Options& options,
- Problem* problem,
- Solver::Summary* summary) {
- using internal::PreprocessedProblem;
- using internal::Preprocessor;
- using internal::ProblemImpl;
- using internal::Program;
- using internal::scoped_ptr;
- using internal::WallTimeInSeconds;
-
- CHECK_NOTNULL(problem);
- CHECK_NOTNULL(summary);
-
- double start_time = WallTimeInSeconds();
- *summary = Summary();
- if (!options.IsValid(&summary->message)) {
- LOG(ERROR) << "Terminating: " << summary->message;
- return;
- }
-
- ProblemImpl* problem_impl = problem->problem_impl_.get();
- Program* program = problem_impl->mutable_program();
- PreSolveSummarize(options, problem_impl, summary);
-
- // Make sure that all the parameter blocks states are set to the
- // values provided by the user.
- program->SetParameterBlockStatePtrsToUserStatePtrs();
-
- scoped_ptr<internal::ProblemImpl> gradient_checking_problem;
- if (options.check_gradients) {
- gradient_checking_problem.reset(
- CreateGradientCheckingProblemImpl(
- problem_impl,
- options.numeric_derivative_relative_step_size,
- options.gradient_check_relative_precision));
- problem_impl = gradient_checking_problem.get();
- program = problem_impl->mutable_program();
- }
-
- scoped_ptr<Preprocessor> preprocessor(
- Preprocessor::Create(options.minimizer_type));
- PreprocessedProblem pp;
- const bool status = preprocessor->Preprocess(options, problem_impl, &pp);
- summary->fixed_cost = pp.fixed_cost;
- summary->preprocessor_time_in_seconds = WallTimeInSeconds() - start_time;
-
- if (status) {
- const double minimizer_start_time = WallTimeInSeconds();
- Minimize(&pp, summary);
- summary->minimizer_time_in_seconds =
- WallTimeInSeconds() - minimizer_start_time;
- } else {
- summary->message = pp.error;
- }
-
- const double postprocessor_start_time = WallTimeInSeconds();
- problem_impl = problem->problem_impl_.get();
- program = problem_impl->mutable_program();
- // On exit, ensure that the parameter blocks again point at the user
- // provided values and the parameter blocks are numbered according
- // to their position in the original user provided program.
- program->SetParameterBlockStatePtrsToUserStatePtrs();
- program->SetParameterOffsetsAndIndex();
- PostSolveSummarize(pp, summary);
- summary->postprocessor_time_in_seconds =
- WallTimeInSeconds() - postprocessor_start_time;
-
- summary->total_time_in_seconds = WallTimeInSeconds() - start_time;
-}
-
-void Solve(const Solver::Options& options,
- Problem* problem,
- Solver::Summary* summary) {
- Solver solver;
- solver.Solve(options, problem, summary);
-}
-
-Solver::Summary::Summary()
- // Invalid values for most fields, to ensure that we are not
- // accidentally reporting default values.
- : minimizer_type(TRUST_REGION),
- termination_type(FAILURE),
- message("ceres::Solve was not called."),
- initial_cost(-1.0),
- final_cost(-1.0),
- fixed_cost(-1.0),
- num_successful_steps(-1),
- num_unsuccessful_steps(-1),
- num_inner_iteration_steps(-1),
- preprocessor_time_in_seconds(-1.0),
- minimizer_time_in_seconds(-1.0),
- postprocessor_time_in_seconds(-1.0),
- total_time_in_seconds(-1.0),
- linear_solver_time_in_seconds(-1.0),
- residual_evaluation_time_in_seconds(-1.0),
- jacobian_evaluation_time_in_seconds(-1.0),
- inner_iteration_time_in_seconds(-1.0),
- num_parameter_blocks(-1),
- num_parameters(-1),
- num_effective_parameters(-1),
- num_residual_blocks(-1),
- num_residuals(-1),
- num_parameter_blocks_reduced(-1),
- num_parameters_reduced(-1),
- num_effective_parameters_reduced(-1),
- num_residual_blocks_reduced(-1),
- num_residuals_reduced(-1),
- num_threads_given(-1),
- num_threads_used(-1),
- num_linear_solver_threads_given(-1),
- num_linear_solver_threads_used(-1),
- linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
- linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
- inner_iterations_given(false),
- inner_iterations_used(false),
- preconditioner_type_given(IDENTITY),
- preconditioner_type_used(IDENTITY),
- visibility_clustering_type(CANONICAL_VIEWS),
- trust_region_strategy_type(LEVENBERG_MARQUARDT),
- dense_linear_algebra_library_type(EIGEN),
- sparse_linear_algebra_library_type(SUITE_SPARSE),
- line_search_direction_type(LBFGS),
- line_search_type(ARMIJO),
- line_search_interpolation_type(BISECTION),
- nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
- max_lbfgs_rank(-1) {
-}
-
-using internal::StringAppendF;
-using internal::StringPrintf;
-
-string Solver::Summary::BriefReport() const {
- return StringPrintf("Ceres Solver Report: "
- "Iterations: %d, "
- "Initial cost: %e, "
- "Final cost: %e, "
- "Termination: %s",
- num_successful_steps + num_unsuccessful_steps,
- initial_cost,
- final_cost,
- TerminationTypeToString(termination_type));
-};
-
-string Solver::Summary::FullReport() const {
- using internal::VersionString;
-
- string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
-
- StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
- StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
- num_parameter_blocks, num_parameter_blocks_reduced);
- StringAppendF(&report, "Parameters % 25d% 25d\n",
- num_parameters, num_parameters_reduced);
- if (num_effective_parameters_reduced != num_parameters_reduced) {
- StringAppendF(&report, "Effective parameters% 25d% 25d\n",
- num_effective_parameters, num_effective_parameters_reduced);
- }
- StringAppendF(&report, "Residual blocks % 25d% 25d\n",
- num_residual_blocks, num_residual_blocks_reduced);
- StringAppendF(&report, "Residual % 25d% 25d\n",
- num_residuals, num_residuals_reduced);
-
- if (minimizer_type == TRUST_REGION) {
- // TRUST_SEARCH HEADER
- StringAppendF(&report, "\nMinimizer %19s\n",
- "TRUST_REGION");
-
- if (linear_solver_type_used == DENSE_NORMAL_CHOLESKY ||
- linear_solver_type_used == DENSE_SCHUR ||
- linear_solver_type_used == DENSE_QR) {
- StringAppendF(&report, "\nDense linear algebra library %15s\n",
- DenseLinearAlgebraLibraryTypeToString(
- dense_linear_algebra_library_type));
- }
-
- if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
- linear_solver_type_used == SPARSE_SCHUR ||
- (linear_solver_type_used == ITERATIVE_SCHUR &&
- (preconditioner_type_used == CLUSTER_JACOBI ||
- preconditioner_type_used == CLUSTER_TRIDIAGONAL))) {
- StringAppendF(&report, "\nSparse linear algebra library %15s\n",
- SparseLinearAlgebraLibraryTypeToString(
- sparse_linear_algebra_library_type));
- }
-
- StringAppendF(&report, "Trust region strategy %19s",
- TrustRegionStrategyTypeToString(
- trust_region_strategy_type));
- if (trust_region_strategy_type == DOGLEG) {
- if (dogleg_type == TRADITIONAL_DOGLEG) {
- StringAppendF(&report, " (TRADITIONAL)");
- } else {
- StringAppendF(&report, " (SUBSPACE)");
- }
- }
- StringAppendF(&report, "\n");
- StringAppendF(&report, "\n");
-
- StringAppendF(&report, "%45s %21s\n", "Given", "Used");
- StringAppendF(&report, "Linear solver %25s%25s\n",
- LinearSolverTypeToString(linear_solver_type_given),
- LinearSolverTypeToString(linear_solver_type_used));
-
- if (linear_solver_type_given == CGNR ||
- linear_solver_type_given == ITERATIVE_SCHUR) {
- StringAppendF(&report, "Preconditioner %25s%25s\n",
- PreconditionerTypeToString(preconditioner_type_given),
- PreconditionerTypeToString(preconditioner_type_used));
- }
-
- if (preconditioner_type_used == CLUSTER_JACOBI ||
- preconditioner_type_used == CLUSTER_TRIDIAGONAL) {
- StringAppendF(&report, "Visibility clustering%24s%25s\n",
- VisibilityClusteringTypeToString(
- visibility_clustering_type),
- VisibilityClusteringTypeToString(
- visibility_clustering_type));
- }
- StringAppendF(&report, "Threads % 25d% 25d\n",
- num_threads_given, num_threads_used);
- StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
- num_linear_solver_threads_given,
- num_linear_solver_threads_used);
-
- if (IsSchurType(linear_solver_type_used)) {
- string given;
- StringifyOrdering(linear_solver_ordering_given, &given);
- string used;
- StringifyOrdering(linear_solver_ordering_used, &used);
- StringAppendF(&report,
- "Linear solver ordering %22s %24s\n",
- given.c_str(),
- used.c_str());
- }
-
- if (inner_iterations_given) {
- StringAppendF(&report,
- "Use inner iterations %20s %20s\n",
- inner_iterations_given ? "True" : "False",
- inner_iterations_used ? "True" : "False");
- }
-
- if (inner_iterations_used) {
- string given;
- StringifyOrdering(inner_iteration_ordering_given, &given);
- string used;
- StringifyOrdering(inner_iteration_ordering_used, &used);
- StringAppendF(&report,
- "Inner iteration ordering %20s %24s\n",
- given.c_str(),
- used.c_str());
- }
- } else {
- // LINE_SEARCH HEADER
- StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
-
-
- string line_search_direction_string;
- if (line_search_direction_type == LBFGS) {
- line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
- } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
- line_search_direction_string =
- NonlinearConjugateGradientTypeToString(
- nonlinear_conjugate_gradient_type);
- } else {
- line_search_direction_string =
- LineSearchDirectionTypeToString(line_search_direction_type);
- }
-
- StringAppendF(&report, "Line search direction %19s\n",
- line_search_direction_string.c_str());
-
- const string line_search_type_string =
- StringPrintf("%s %s",
- LineSearchInterpolationTypeToString(
- line_search_interpolation_type),
- LineSearchTypeToString(line_search_type));
- StringAppendF(&report, "Line search type %19s\n",
- line_search_type_string.c_str());
- StringAppendF(&report, "\n");
-
- StringAppendF(&report, "%45s %21s\n", "Given", "Used");
- StringAppendF(&report, "Threads % 25d% 25d\n",
- num_threads_given, num_threads_used);
- }
-
- StringAppendF(&report, "\nCost:\n");
- StringAppendF(&report, "Initial % 30e\n", initial_cost);
- if (termination_type != FAILURE &&
- termination_type != USER_FAILURE) {
- StringAppendF(&report, "Final % 30e\n", final_cost);
- StringAppendF(&report, "Change % 30e\n",
- initial_cost - final_cost);
- }
-
- StringAppendF(&report, "\nMinimizer iterations % 16d\n",
- num_successful_steps + num_unsuccessful_steps);
-
- // Successful/Unsuccessful steps only matter in the case of the
- // trust region solver. Line search terminates when it encounters
- // the first unsuccessful step.
- if (minimizer_type == TRUST_REGION) {
- StringAppendF(&report, "Successful steps % 14d\n",
- num_successful_steps);
- StringAppendF(&report, "Unsuccessful steps % 14d\n",
- num_unsuccessful_steps);
- }
- if (inner_iterations_used) {
- StringAppendF(&report, "Steps with inner iterations % 14d\n",
- num_inner_iteration_steps);
- }
-
- StringAppendF(&report, "\nTime (in seconds):\n");
- StringAppendF(&report, "Preprocessor %25.3f\n",
- preprocessor_time_in_seconds);
-
- StringAppendF(&report, "\n Residual evaluation %23.3f\n",
- residual_evaluation_time_in_seconds);
- StringAppendF(&report, " Jacobian evaluation %23.3f\n",
- jacobian_evaluation_time_in_seconds);
-
- if (minimizer_type == TRUST_REGION) {
- StringAppendF(&report, " Linear solver %23.3f\n",
- linear_solver_time_in_seconds);
- }
-
- if (inner_iterations_used) {
- StringAppendF(&report, " Inner iterations %23.3f\n",
- inner_iteration_time_in_seconds);
- }
-
- StringAppendF(&report, "Minimizer %25.3f\n\n",
- minimizer_time_in_seconds);
-
- StringAppendF(&report, "Postprocessor %24.3f\n",
- postprocessor_time_in_seconds);
-
- StringAppendF(&report, "Total %25.3f\n\n",
- total_time_in_seconds);
-
- StringAppendF(&report, "Termination: %25s (%s)\n",
- TerminationTypeToString(termination_type), message.c_str());
- return report;
-};
-
-bool Solver::Summary::IsSolutionUsable() const {
- return internal::IsSolutionUsable(*this);
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_utils.cc b/extern/libmv/third_party/ceres/internal/ceres/solver_utils.cc
deleted file mode 100644
index bd304e7ac5d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/solver_utils.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include <string>
-
-#include "ceres/internal/port.h"
-#include "ceres/version.h"
-
-namespace ceres {
-namespace internal {
-
-string VersionString() {
- string value = string(CERES_VERSION_STRING);
-
-#ifdef CERES_NO_LAPACK
- value += "-no_lapack";
-#else
- value += "-lapack";
-#endif
-
-#ifndef CERES_NO_SUITESPARSE
- value += "-suitesparse";
-#endif
-
-#ifndef CERES_NO_CXSPARSE
- value += "-cxsparse";
-#endif
-
-#ifdef CERES_USE_EIGEN_SPARSE
- value += "-eigensparse";
-#endif
-
-#ifdef CERES_RESTRUCT_SCHUR_SPECIALIZATIONS
- value += "-no_schur_specializations";
-#endif
-
-#ifdef CERES_USE_OPENMP
- value += "-openmp";
-#else
- value += "-no_openmp";
-#endif
-
-#ifdef CERES_NO_CUSTOM_BLAS
- value += "-no_custom_blas";
-#endif
-
- return value;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_utils.h b/extern/libmv/third_party/ceres/internal/ceres/solver_utils.h
deleted file mode 100644
index 41c8a6e1292..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/solver_utils.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include <algorithm>
-#include <string>
-
-namespace ceres {
-namespace internal {
-
-template <typename SummaryType>
-bool IsSolutionUsable(const SummaryType& summary) {
- return (summary.termination_type == CONVERGENCE ||
- summary.termination_type == NO_CONVERGENCE ||
- summary.termination_type == USER_SUCCESS);
-}
-
-template <typename SummaryType>
-void SetSummaryFinalCost(SummaryType* summary) {
- summary->final_cost = summary->initial_cost;
- // We need the loop here, instead of just looking at the last
- // iteration because the minimizer maybe making non-monotonic steps.
- for (int i = 0; i < summary->iterations.size(); ++i) {
- const IterationSummary& iteration_summary = summary->iterations[i];
- summary->final_cost = min(iteration_summary.cost, summary->final_cost);
- }
-}
-
-string VersionString();
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.cc
deleted file mode 100644
index 55336fd3130..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-SparseMatrix::~SparseMatrix() {
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h
deleted file mode 100644
index f3b96712a70..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/sparse_matrix.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Interface definition for sparse matrices.
-
-#ifndef CERES_INTERNAL_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_SPARSE_MATRIX_H_
-
-#include <cstdio>
-#include "ceres/linear_operator.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-// This class defines the interface for storing and manipulating
-// sparse matrices. The key property that differentiates different
-// sparse matrices is how they are organized in memory and how the
-// information about the sparsity structure of the matrix is
-// stored. This has significant implications for linear solvers
-// operating on these matrices.
-//
-// To deal with the different kinds of layouts, we will assume that a
-// sparse matrix will have a two part representation. A values array
-// that will be used to store the entries of the sparse matrix and
-// some sort of a layout object that tells the user the sparsity
-// structure and layout of the values array. For example in case of
-// the TripletSparseMatrix, this information is carried in the rows
-// and cols arrays and for the BlockSparseMatrix, this information is
-// carried in the CompressedRowBlockStructure object.
-//
-// This interface deliberately does not contain any information about
-// the structure of the sparse matrix as that seems to be highly
-// matrix type dependent and we are at this stage unable to come up
-// with an efficient high level interface that spans multiple sparse
-// matrix types.
-class SparseMatrix : public LinearOperator {
- public:
- virtual ~SparseMatrix();
-
- // y += Ax;
- virtual void RightMultiply(const double* x, double* y) const = 0;
- // y += A'x;
- virtual void LeftMultiply(const double* x, double* y) const = 0;
-
- // In MATLAB notation sum(A.*A, 1)
- virtual void SquaredColumnNorm(double* x) const = 0;
- // A = A * diag(scale)
- virtual void ScaleColumns(const double* scale) = 0;
-
- // A = 0. A->num_nonzeros() == 0 is true after this call. The
- // sparsity pattern is preserved.
- virtual void SetZero() = 0;
-
- // Resize and populate dense_matrix with a dense version of the
- // sparse matrix.
- virtual void ToDenseMatrix(Matrix* dense_matrix) const = 0;
-
- // Write out the matrix as a sequence of (i,j,s) triplets. This
- // format is useful for loading the matrix into MATLAB/octave as a
- // sparse matrix.
- virtual void ToTextFile(FILE* file) const = 0;
-
- // Accessors for the values array that stores the entries of the
- // sparse matrix. The exact interpreptation of the values of this
- // array depends on the particular kind of SparseMatrix being
- // accessed.
- virtual double* mutable_values() = 0;
- virtual const double* values() const = 0;
-
- virtual int num_rows() const = 0;
- virtual int num_cols() const = 0;
- virtual int num_nonzeros() const = 0;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SPARSE_MATRIX_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
deleted file mode 100644
index 94f7e5803c4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
+++ /dev/null
@@ -1,439 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/sparse_normal_cholesky_solver.h"
-
-#include <algorithm>
-#include <cstring>
-#include <ctime>
-
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/cxsparse.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-#include "ceres/suitesparse.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-#include "Eigen/SparseCore"
-
-#ifdef CERES_USE_EIGEN_SPARSE
-#include "Eigen/SparseCholesky"
-#endif
-
-namespace ceres {
-namespace internal {
-namespace {
-
-#ifdef CERES_USE_EIGEN_SPARSE
-// A templated factorized and solve function, which allows us to use
-// the same code independent of whether a AMD or a Natural ordering is
-// used.
-template <typename SimplicialCholeskySolver>
-LinearSolver::Summary SimplicialLDLTSolve(
- Eigen::MappedSparseMatrix<double, Eigen::ColMajor>& lhs,
- const bool do_symbolic_analysis,
- SimplicialCholeskySolver* solver,
- double* rhs_and_solution,
- EventLogger* event_logger) {
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- if (do_symbolic_analysis) {
- solver->analyzePattern(lhs);
- event_logger->AddEvent("Analyze");
- if (solver->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "Eigen failure. Unable to find symbolic factorization.";
- return summary;
- }
- }
-
- solver->factorize(lhs);
- event_logger->AddEvent("Factorize");
- if (solver->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to find numeric factorization.";
- return summary;
- }
-
- const Vector rhs = VectorRef(rhs_and_solution, lhs.cols());
-
- VectorRef(rhs_and_solution, lhs.cols()) = solver->solve(rhs);
- event_logger->AddEvent("Solve");
- if (solver->info() != Eigen::Success) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "Eigen failure. Unable to do triangular solve.";
- return summary;
- }
-
- return summary;
-}
-
-#endif // CERES_USE_EIGEN_SPARSE
-
-} // namespace
-
-SparseNormalCholeskySolver::SparseNormalCholeskySolver(
- const LinearSolver::Options& options)
- : factor_(NULL),
- cxsparse_factor_(NULL),
- options_(options) {
-}
-
-void SparseNormalCholeskySolver::FreeFactorization() {
- if (factor_ != NULL) {
- ss_.Free(factor_);
- factor_ = NULL;
- }
-
- if (cxsparse_factor_ != NULL) {
- cxsparse_.Free(cxsparse_factor_);
- cxsparse_factor_ = NULL;
- }
-}
-
-SparseNormalCholeskySolver::~SparseNormalCholeskySolver() {
- FreeFactorization();
-}
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl(
- CompressedRowSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double * x) {
-
- const int num_cols = A->num_cols();
- VectorRef(x, num_cols).setZero();
- A->LeftMultiply(b, x);
-
- if (per_solve_options.D != NULL) {
- // Temporarily append a diagonal block to the A matrix, but undo
- // it before returning the matrix to the user.
- scoped_ptr<CompressedRowSparseMatrix> regularizer;
- if (A->col_blocks().size() > 0) {
- regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
- per_solve_options.D, A->col_blocks()));
- } else {
- regularizer.reset(new CompressedRowSparseMatrix(
- per_solve_options.D, num_cols));
- }
- A->AppendRows(*regularizer);
- }
-
- LinearSolver::Summary summary;
- switch (options_.sparse_linear_algebra_library_type) {
- case SUITE_SPARSE:
- summary = SolveImplUsingSuiteSparse(A, per_solve_options, x);
- break;
- case CX_SPARSE:
- summary = SolveImplUsingCXSparse(A, per_solve_options, x);
- break;
- case EIGEN_SPARSE:
- summary = SolveImplUsingEigen(A, per_solve_options, x);
- break;
- default:
- LOG(FATAL) << "Unknown sparse linear algebra library : "
- << options_.sparse_linear_algebra_library_type;
- }
-
- if (per_solve_options.D != NULL) {
- A->DeleteRows(num_cols);
- }
-
- return summary;
-}
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingEigen(
- CompressedRowSparseMatrix* A,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double * rhs_and_solution) {
-#ifndef CERES_USE_EIGEN_SPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
- "because Ceres was not built with support for "
- "Eigen's SimplicialLDLT decomposition. "
- "This requires enabling building with -DEIGENSPARSE=ON.";
- return summary;
-
-#else
-
- EventLogger event_logger("SparseNormalCholeskySolver::Eigen::Solve");
- // Compute the normal equations. J'J delta = J'f and solve them
- // using a sparse Cholesky factorization. Notice that when compared
- // to SuiteSparse we have to explicitly compute the normal equations
- // before they can be factorized. CHOLMOD/SuiteSparse on the other
- // hand can just work off of Jt to compute the Cholesky
- // factorization of the normal equations.
- //
- // TODO(sameeragarwal): See note about how this maybe a bad idea for
- // dynamic sparsity.
- if (outer_product_.get() == NULL) {
- outer_product_.reset(
- CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
- *A, &pattern_));
- }
-
- CompressedRowSparseMatrix::ComputeOuterProduct(
- *A, pattern_, outer_product_.get());
-
- // Map to an upper triangular column major matrix.
- //
- // outer_product_ is a compressed row sparse matrix and in lower
- // triangular form, when mapped to a compressed column sparse
- // matrix, it becomes an upper triangular matrix.
- Eigen::MappedSparseMatrix<double, Eigen::ColMajor> AtA(
- outer_product_->num_rows(),
- outer_product_->num_rows(),
- outer_product_->num_nonzeros(),
- outer_product_->mutable_rows(),
- outer_product_->mutable_cols(),
- outer_product_->mutable_values());
-
- // Dynamic sparsity means that we cannot depend on a static analysis
- // of sparsity structure of the jacobian, so we compute a new
- // symbolic factorization every time.
- if (options_.dynamic_sparsity) {
- amd_ldlt_.reset(NULL);
- }
-
- bool do_symbolic_analysis = false;
-
- // If using post ordering or dynamic sparsity, or an old version of
- // Eigen, we cannot depend on a preordered jacobian, so we work with
- // a SimplicialLDLT decomposition with AMD ordering.
- if (options_.use_postordering ||
- options_.dynamic_sparsity ||
- !EIGEN_VERSION_AT_LEAST(3, 2, 2)) {
- if (amd_ldlt_.get() == NULL) {
- amd_ldlt_.reset(new SimplicialLDLTWithAMDOrdering);
- do_symbolic_analysis = true;
- }
-
- return SimplicialLDLTSolve(AtA,
- do_symbolic_analysis,
- amd_ldlt_.get(),
- rhs_and_solution,
- &event_logger);
- }
-
-#if EIGEN_VERSION_AT_LEAST(3,2,2)
- // The common case
- if (natural_ldlt_.get() == NULL) {
- natural_ldlt_.reset(new SimplicialLDLTWithNaturalOrdering);
- do_symbolic_analysis = true;
- }
-
- return SimplicialLDLTSolve(AtA,
- do_symbolic_analysis,
- natural_ldlt_.get(),
- rhs_and_solution,
- &event_logger);
-#endif
-
-#endif // EIGEN_USE_EIGEN_SPARSE
-}
-
-
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
- CompressedRowSparseMatrix* A,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double * rhs_and_solution) {
-#ifdef CERES_NO_CXSPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_NORMAL_CHOLESKY cannot be used with CX_SPARSE "
- "because Ceres was not built with support for CXSparse. "
- "This requires enabling building with -DCXSPARSE=ON.";
-
- return summary;
-
-#else
-
- EventLogger event_logger("SparseNormalCholeskySolver::CXSparse::Solve");
-
- LinearSolver::Summary summary;
- summary.num_iterations = 1;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.message = "Success.";
-
- // Compute the normal equations. J'J delta = J'f and solve them
- // using a sparse Cholesky factorization. Notice that when compared
- // to SuiteSparse we have to explicitly compute the normal equations
- // before they can be factorized. CHOLMOD/SuiteSparse on the other
- // hand can just work off of Jt to compute the Cholesky
- // factorization of the normal equations.
- //
- // TODO(sameeragarwal): If dynamic sparsity is enabled, then this is
- // not a good idea performance wise, since the jacobian has far too
- // many entries and the program will go crazy with memory.
- if (outer_product_.get() == NULL) {
- outer_product_.reset(
- CompressedRowSparseMatrix::CreateOuterProductMatrixAndProgram(
- *A, &pattern_));
- }
-
- CompressedRowSparseMatrix::ComputeOuterProduct(
- *A, pattern_, outer_product_.get());
- cs_di AtA_view =
- cxsparse_.CreateSparseMatrixTransposeView(outer_product_.get());
- cs_di* AtA = &AtA_view;
-
- event_logger.AddEvent("Setup");
-
- // Compute symbolic factorization if not available.
- if (options_.dynamic_sparsity) {
- FreeFactorization();
- }
- if (cxsparse_factor_ == NULL) {
- if (options_.use_postordering) {
- cxsparse_factor_ = cxsparse_.BlockAnalyzeCholesky(AtA,
- A->col_blocks(),
- A->col_blocks());
- } else {
- if (options_.dynamic_sparsity) {
- cxsparse_factor_ = cxsparse_.AnalyzeCholesky(AtA);
- } else {
- cxsparse_factor_ = cxsparse_.AnalyzeCholeskyWithNaturalOrdering(AtA);
- }
- }
- }
- event_logger.AddEvent("Analysis");
-
- if (cxsparse_factor_ == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "CXSparse failure. Unable to find symbolic factorization.";
- } else if (!cxsparse_.SolveCholesky(AtA,
- cxsparse_factor_,
- rhs_and_solution)) {
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- summary.message = "CXSparse::SolveCholesky failed.";
- }
- event_logger.AddEvent("Solve");
-
- return summary;
-#endif
-}
-
-LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
- CompressedRowSparseMatrix* A,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double * rhs_and_solution) {
-#ifdef CERES_NO_SUITESPARSE
-
- LinearSolver::Summary summary;
- summary.num_iterations = 0;
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- summary.message =
- "SPARSE_NORMAL_CHOLESKY cannot be used with SUITE_SPARSE "
- "because Ceres was not built with support for SuiteSparse. "
- "This requires enabling building with -DSUITESPARSE=ON.";
- return summary;
-
-#else
-
- EventLogger event_logger("SparseNormalCholeskySolver::SuiteSparse::Solve");
- LinearSolver::Summary summary;
- summary.termination_type = LINEAR_SOLVER_SUCCESS;
- summary.num_iterations = 1;
- summary.message = "Success.";
-
- const int num_cols = A->num_cols();
- cholmod_sparse lhs = ss_.CreateSparseMatrixTransposeView(A);
- event_logger.AddEvent("Setup");
-
- if (options_.dynamic_sparsity) {
- FreeFactorization();
- }
- if (factor_ == NULL) {
- if (options_.use_postordering) {
- factor_ = ss_.BlockAnalyzeCholesky(&lhs,
- A->col_blocks(),
- A->row_blocks(),
- &summary.message);
- } else {
- if (options_.dynamic_sparsity) {
- factor_ = ss_.AnalyzeCholesky(&lhs, &summary.message);
- } else {
- factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&lhs,
- &summary.message);
- }
- }
- }
- event_logger.AddEvent("Analysis");
-
- if (factor_ == NULL) {
- summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
- // No need to set message as it has already been set by the
- // symbolic analysis routines above.
- return summary;
- }
-
- summary.termination_type = ss_.Cholesky(&lhs, factor_, &summary.message);
- if (summary.termination_type != LINEAR_SOLVER_SUCCESS) {
- return summary;
- }
-
- cholmod_dense* rhs = ss_.CreateDenseVector(rhs_and_solution,
- num_cols,
- num_cols);
- cholmod_dense* solution = ss_.Solve(factor_, rhs, &summary.message);
- event_logger.AddEvent("Solve");
-
- ss_.Free(rhs);
- if (solution != NULL) {
- memcpy(rhs_and_solution, solution->x, num_cols * sizeof(*rhs_and_solution));
- ss_.Free(solution);
- } else {
- // No need to set message as it has already been set by the
- // numeric factorization routine above.
- summary.termination_type = LINEAR_SOLVER_FAILURE;
- }
-
- event_logger.AddEvent("Teardown");
- return summary;
-#endif
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
deleted file mode 100644
index 12c05245075..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// A solver for sparse linear least squares problem based on solving
-// the normal equations via a sparse cholesky factorization.
-
-#ifndef CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
-#define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
-
-#include <vector>
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#include "ceres/internal/macros.h"
-#include "ceres/linear_solver.h"
-#include "ceres/suitesparse.h"
-#include "ceres/cxsparse.h"
-
-#ifdef CERES_USE_EIGEN_SPARSE
-#include "Eigen/SparseCholesky"
-#endif
-
-namespace ceres {
-namespace internal {
-
-class CompressedRowSparseMatrix;
-
-// Solves the normal equations (A'A + D'D) x = A'b, using the CHOLMOD sparse
-// cholesky solver.
-class SparseNormalCholeskySolver : public CompressedRowSparseMatrixSolver {
- public:
- explicit SparseNormalCholeskySolver(const LinearSolver::Options& options);
- virtual ~SparseNormalCholeskySolver();
-
- private:
- virtual LinearSolver::Summary SolveImpl(
- CompressedRowSparseMatrix* A,
- const double* b,
- const LinearSolver::PerSolveOptions& options,
- double* x);
-
- LinearSolver::Summary SolveImplUsingSuiteSparse(
- CompressedRowSparseMatrix* A,
- const LinearSolver::PerSolveOptions& options,
- double* rhs_and_solution);
-
- // Crashes if CSparse is not installed.
- LinearSolver::Summary SolveImplUsingCXSparse(
- CompressedRowSparseMatrix* A,
- const LinearSolver::PerSolveOptions& options,
- double* rhs_and_solution);
-
- // Crashes if CERES_USE_EIGEN_SPARSE is not defined.
- LinearSolver::Summary SolveImplUsingEigen(
- CompressedRowSparseMatrix* A,
- const LinearSolver::PerSolveOptions& options,
- double* rhs_and_solution);
-
- void FreeFactorization();
-
- SuiteSparse ss_;
- // Cached factorization
- cholmod_factor* factor_;
-
- CXSparse cxsparse_;
- // Cached factorization
- cs_dis* cxsparse_factor_;
-
-#ifdef CERES_USE_EIGEN_SPARSE
-
- // The preprocessor gymnastics here are dealing with the fact that
- // before version 3.2.2, Eigen did not support a third template
- // parameter to specify the ordering.
-#if EIGEN_VERSION_AT_LEAST(3,2,2)
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper,
- Eigen::NaturalOrdering<int> >
- SimplicialLDLTWithNaturalOrdering;
- scoped_ptr<SimplicialLDLTWithNaturalOrdering> natural_ldlt_;
-
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper,
- Eigen::AMDOrdering<int> >
- SimplicialLDLTWithAMDOrdering;
- scoped_ptr<SimplicialLDLTWithAMDOrdering> amd_ldlt_;
-
-#else
- typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>, Eigen::Upper>
- SimplicialLDLTWithAMDOrdering;
-
- scoped_ptr<SimplicialLDLTWithAMDOrdering> amd_ldlt_;
-#endif
-
-#endif
-
- scoped_ptr<CompressedRowSparseMatrix> outer_product_;
- vector<int> pattern_;
- const LinearSolver::Options options_;
- CERES_DISALLOW_COPY_AND_ASSIGN(SparseNormalCholeskySolver);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.cc b/extern/libmv/third_party/ceres/internal/ceres/split.cc
deleted file mode 100644
index 3edbc281340..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/split.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/split.h"
-
-#include <string>
-#include <vector>
-#include <iterator>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-
-// If we know how much to allocate for a vector of strings, we can allocate the
-// vector<string> only once and directly to the right size. This saves in
-// between 33-66 % of memory space needed for the result, and runs faster in the
-// microbenchmarks.
-//
-// The reserve is only implemented for the single character delim.
-//
-// The implementation for counting is cut-and-pasted from
-// SplitStringToIteratorUsing. I could have written my own counting iterator,
-// and use the existing template function, but probably this is more clear and
-// more sure to get optimized to reasonable code.
-static int CalculateReserveForVector(const string& full, const char* delim) {
- int count = 0;
- if (delim[0] != '\0' && delim[1] == '\0') {
- // Optimize the common case where delim is a single character.
- char c = delim[0];
- const char* p = full.data();
- const char* end = p + full.size();
- while (p != end) {
- if (*p == c) { // This could be optimized with hasless(v,1) trick.
- ++p;
- } else {
- while (++p != end && *p != c) {
- // Skip to the next occurence of the delimiter.
- }
- ++count;
- }
- }
- }
- return count;
-}
-
-template <typename StringType, typename ITR>
-static inline
-void SplitStringToIteratorUsing(const StringType& full,
- const char* delim,
- ITR& result) {
- // Optimize the common case where delim is a single character.
- if (delim[0] != '\0' && delim[1] == '\0') {
- char c = delim[0];
- const char* p = full.data();
- const char* end = p + full.size();
- while (p != end) {
- if (*p == c) {
- ++p;
- } else {
- const char* start = p;
- while (++p != end && *p != c) {
- // Skip to the next occurence of the delimiter.
- }
- *result++ = StringType(start, p - start);
- }
- }
- return;
- }
-
- string::size_type begin_index, end_index;
- begin_index = full.find_first_not_of(delim);
- while (begin_index != string::npos) {
- end_index = full.find_first_of(delim, begin_index);
- if (end_index == string::npos) {
- *result++ = full.substr(begin_index);
- return;
- }
- *result++ = full.substr(begin_index, (end_index - begin_index));
- begin_index = full.find_first_not_of(delim, end_index);
- }
-}
-
-void SplitStringUsing(const string& full,
- const char* delim,
- vector<string>* result) {
- result->reserve(result->size() + CalculateReserveForVector(full, delim));
- back_insert_iterator< vector<string> > it(*result);
- SplitStringToIteratorUsing(full, delim, it);
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.h b/extern/libmv/third_party/ceres/internal/ceres/split.h
deleted file mode 100644
index 2334d26037f..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/split.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2011 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_SPLIT_H_
-#define CERES_INTERNAL_SPLIT_H_
-
-#include <string>
-#include <vector>
-#include "ceres/internal/port.h"
-
-namespace ceres {
-
-// Split a string using one or more character delimiters, presented as a
-// nul-terminated c string. Append the components to 'result'. If there are
-// consecutive delimiters, this function skips over all of them.
-void SplitStringUsing(const string& full, const char* delim,
- vector<string>* res);
-
-} // namespace ceres
-
-#endif // CERES_INTERNAL_SPLIT_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
deleted file mode 100644
index 08f15ec8398..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_STL_UTIL_H_
-#define CERES_INTERNAL_STL_UTIL_H_
-
-#include <algorithm>
-
-namespace ceres {
-
-// STLDeleteContainerPointers()
-// For a range within a container of pointers, calls delete
-// (non-array version) on these pointers.
-// NOTE: for these three functions, we could just implement a DeleteObject
-// functor and then call for_each() on the range and functor, but this
-// requires us to pull in all of algorithm.h, which seems expensive.
-// For hash_[multi]set, it is important that this deletes behind the iterator
-// because the hash_set may call the hash function on the iterator when it is
-// advanced, which could result in the hash function trying to deference a
-// stale pointer.
-template <class ForwardIterator>
-void STLDeleteContainerPointers(ForwardIterator begin,
- ForwardIterator end) {
- while (begin != end) {
- ForwardIterator temp = begin;
- ++begin;
- delete *temp;
- }
-}
-
-// Variant of STLDeleteContainerPointers which allows the container to
-// contain duplicates.
-template <class ForwardIterator>
-void STLDeleteUniqueContainerPointers(ForwardIterator begin,
- ForwardIterator end) {
- sort(begin, end);
- ForwardIterator new_end = unique(begin, end);
- while (begin != new_end) {
- ForwardIterator temp = begin;
- ++begin;
- delete *temp;
- }
-}
-
-// STLDeleteElements() deletes all the elements in an STL container and clears
-// the container. This function is suitable for use with a vector, set,
-// hash_set, or any other STL container which defines sensible begin(), end(),
-// and clear() methods.
-//
-// If container is NULL, this function is a no-op.
-//
-// As an alternative to calling STLDeleteElements() directly, consider
-// ElementDeleter (defined below), which ensures that your container's elements
-// are deleted when the ElementDeleter goes out of scope.
-template <class T>
-void STLDeleteElements(T *container) {
- if (!container) return;
- STLDeleteContainerPointers(container->begin(), container->end());
- container->clear();
-}
-
-} // namespace ceres
-
-#endif // CERES_INTERNAL_STL_UTIL_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
deleted file mode 100644
index 0f85f05e056..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Sanjay Ghemawat
-
-#include "ceres/stringprintf.h"
-
-#include <cerrno>
-#include <cstdarg> // For va_list and related operations
-#include <cstdio> // MSVC requires this for _vsnprintf
-#include <string>
-#include <vector>
-
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-#ifdef _MSC_VER
-enum { IS_COMPILER_MSVC = 1 };
-#if _MSC_VER < 1800
-#define va_copy(d, s) ((d) = (s))
-#endif
-#else
-enum { IS_COMPILER_MSVC = 0 };
-#endif
-
-void StringAppendV(string* dst, const char* format, va_list ap) {
- // First try with a small fixed size buffer
- char space[1024];
-
- // It's possible for methods that use a va_list to invalidate
- // the data in it upon use. The fix is to make a copy
- // of the structure before using it and use that copy instead.
- va_list backup_ap;
- va_copy(backup_ap, ap);
- int result = vsnprintf(space, sizeof(space), format, backup_ap);
- va_end(backup_ap);
-
- if (result < sizeof(space)) {
- if (result >= 0) {
- // Normal case -- everything fit.
- dst->append(space, result);
- return;
- }
-
- if (IS_COMPILER_MSVC) {
- // Error or MSVC running out of space. MSVC 8.0 and higher
- // can be asked about space needed with the special idiom below:
- va_copy(backup_ap, ap);
- result = vsnprintf(NULL, 0, format, backup_ap);
- va_end(backup_ap);
- }
-
- if (result < 0) {
- // Just an error.
- return;
- }
- }
-
- // Increase the buffer size to the size requested by vsnprintf,
- // plus one for the closing \0.
- int length = result+1;
- char* buf = new char[length];
-
- // Restore the va_list before we use it again
- va_copy(backup_ap, ap);
- result = vsnprintf(buf, length, format, backup_ap);
- va_end(backup_ap);
-
- if (result >= 0 && result < length) {
- // It fit
- dst->append(buf, result);
- }
- delete[] buf;
-}
-
-
-string StringPrintf(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- string result;
- StringAppendV(&result, format, ap);
- va_end(ap);
- return result;
-}
-
-const string& SStringPrintf(string* dst, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- dst->clear();
- StringAppendV(dst, format, ap);
- va_end(ap);
- return *dst;
-}
-
-void StringAppendF(string* dst, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- StringAppendV(dst, format, ap);
- va_end(ap);
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
deleted file mode 100644
index cd1be142aed..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Sanjay Ghemawat
-//
-// Printf variants that place their output in a C++ string.
-//
-// Usage:
-// string result = StringPrintf("%d %s\n", 10, "hello");
-// SStringPrintf(&result, "%d %s\n", 10, "hello");
-// StringAppendF(&result, "%d %s\n", 20, "there");
-
-#ifndef CERES_INTERNAL_STRINGPRINTF_H_
-#define CERES_INTERNAL_STRINGPRINTF_H_
-
-#include <cstdarg>
-#include <string>
-
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-#if (defined(__GNUC__) || defined(__clang__))
-// Tell the compiler to do printf format string checking if the compiler
-// supports it; see the 'format' attribute in
-// <http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html>.
-//
-// N.B.: As the GCC manual states, "[s]ince non-static C++ methods
-// have an implicit 'this' argument, the arguments of such methods
-// should be counted from two, not one."
-#define CERES_PRINTF_ATTRIBUTE(string_index, first_to_check) \
- __attribute__((__format__ (__printf__, string_index, first_to_check)))
-#define CERES_SCANF_ATTRIBUTE(string_index, first_to_check) \
- __attribute__((__format__ (__scanf__, string_index, first_to_check)))
-#else
-#define CERES_PRINTF_ATTRIBUTE(string_index, first_to_check)
-#endif
-
-// Return a C++ string.
-extern string StringPrintf(const char* format, ...)
- // Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(1, 2);
-
-// Store result into a supplied string and return it.
-extern const string& SStringPrintf(string* dst, const char* format, ...)
- // Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(2, 3);
-
-// Append result to a supplied string.
-extern void StringAppendF(string* dst, const char* format, ...)
- // Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(2, 3);
-
-// Lower-level routine that takes a va_list and appends to a specified string.
-// All other routines are just convenience wrappers around it.
-extern void StringAppendV(string* dst, const char* format, va_list ap);
-
-#undef CERES_PRINTF_ATTRIBUTE
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_STRINGPRINTF_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
deleted file mode 100644
index 1df7566e00a..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
+++ /dev/null
@@ -1,347 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-#include "ceres/suitesparse.h"
-
-#include <vector>
-#include "cholmod.h"
-#include "ceres/compressed_col_sparse_matrix_utils.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/linear_solver.h"
-#include "ceres/triplet_sparse_matrix.h"
-
-namespace ceres {
-namespace internal {
-
-SuiteSparse::SuiteSparse() {
- cholmod_start(&cc_);
-}
-
-SuiteSparse::~SuiteSparse() {
- cholmod_finish(&cc_);
-}
-
-cholmod_sparse* SuiteSparse::CreateSparseMatrix(TripletSparseMatrix* A) {
- cholmod_triplet triplet;
-
- triplet.nrow = A->num_rows();
- triplet.ncol = A->num_cols();
- triplet.nzmax = A->max_num_nonzeros();
- triplet.nnz = A->num_nonzeros();
- triplet.i = reinterpret_cast<void*>(A->mutable_rows());
- triplet.j = reinterpret_cast<void*>(A->mutable_cols());
- triplet.x = reinterpret_cast<void*>(A->mutable_values());
- triplet.stype = 0; // Matrix is not symmetric.
- triplet.itype = CHOLMOD_INT;
- triplet.xtype = CHOLMOD_REAL;
- triplet.dtype = CHOLMOD_DOUBLE;
-
- return cholmod_triplet_to_sparse(&triplet, triplet.nnz, &cc_);
-}
-
-
-cholmod_sparse* SuiteSparse::CreateSparseMatrixTranspose(
- TripletSparseMatrix* A) {
- cholmod_triplet triplet;
-
- triplet.ncol = A->num_rows(); // swap row and columns
- triplet.nrow = A->num_cols();
- triplet.nzmax = A->max_num_nonzeros();
- triplet.nnz = A->num_nonzeros();
-
- // swap rows and columns
- triplet.j = reinterpret_cast<void*>(A->mutable_rows());
- triplet.i = reinterpret_cast<void*>(A->mutable_cols());
- triplet.x = reinterpret_cast<void*>(A->mutable_values());
- triplet.stype = 0; // Matrix is not symmetric.
- triplet.itype = CHOLMOD_INT;
- triplet.xtype = CHOLMOD_REAL;
- triplet.dtype = CHOLMOD_DOUBLE;
-
- return cholmod_triplet_to_sparse(&triplet, triplet.nnz, &cc_);
-}
-
-cholmod_sparse SuiteSparse::CreateSparseMatrixTransposeView(
- CompressedRowSparseMatrix* A) {
- cholmod_sparse m;
- m.nrow = A->num_cols();
- m.ncol = A->num_rows();
- m.nzmax = A->num_nonzeros();
- m.nz = NULL;
- m.p = reinterpret_cast<void*>(A->mutable_rows());
- m.i = reinterpret_cast<void*>(A->mutable_cols());
- m.x = reinterpret_cast<void*>(A->mutable_values());
- m.z = NULL;
- m.stype = 0; // Matrix is not symmetric.
- m.itype = CHOLMOD_INT;
- m.xtype = CHOLMOD_REAL;
- m.dtype = CHOLMOD_DOUBLE;
- m.sorted = 1;
- m.packed = 1;
-
- return m;
-}
-
-cholmod_dense* SuiteSparse::CreateDenseVector(const double* x,
- int in_size,
- int out_size) {
- CHECK_LE(in_size, out_size);
- cholmod_dense* v = cholmod_zeros(out_size, 1, CHOLMOD_REAL, &cc_);
- if (x != NULL) {
- memcpy(v->x, x, in_size*sizeof(*x));
- }
- return v;
-}
-
-cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A,
- string* message) {
- // Cholmod can try multiple re-ordering strategies to find a fill
- // reducing ordering. Here we just tell it use AMD with automatic
- // matrix dependence choice of supernodal versus simplicial
- // factorization.
- cc_.nmethods = 1;
- cc_.method[0].ordering = CHOLMOD_AMD;
- cc_.supernodal = CHOLMOD_AUTO;
-
- cholmod_factor* factor = cholmod_analyze(A, &cc_);
- if (VLOG_IS_ON(2)) {
- cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
- }
-
- if (cc_.status != CHOLMOD_OK) {
- *message = StringPrintf("cholmod_analyze failed. error code: %d",
- cc_.status);
- return NULL;
- }
-
- return CHECK_NOTNULL(factor);
-}
-
-cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(
- cholmod_sparse* A,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks,
- string* message) {
- vector<int> ordering;
- if (!BlockAMDOrdering(A, row_blocks, col_blocks, &ordering)) {
- return NULL;
- }
- return AnalyzeCholeskyWithUserOrdering(A, ordering, message);
-}
-
-cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
- cholmod_sparse* A,
- const vector<int>& ordering,
- string* message) {
- CHECK_EQ(ordering.size(), A->nrow);
-
- cc_.nmethods = 1;
- cc_.method[0].ordering = CHOLMOD_GIVEN;
-
- cholmod_factor* factor =
- cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), NULL, 0, &cc_);
- if (VLOG_IS_ON(2)) {
- cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
- }
- if (cc_.status != CHOLMOD_OK) {
- *message = StringPrintf("cholmod_analyze failed. error code: %d",
- cc_.status);
- return NULL;
- }
-
- return CHECK_NOTNULL(factor);
-}
-
-cholmod_factor* SuiteSparse::AnalyzeCholeskyWithNaturalOrdering(
- cholmod_sparse* A,
- string* message) {
- cc_.nmethods = 1;
- cc_.method[0].ordering = CHOLMOD_NATURAL;
- cc_.postorder = 0;
-
- cholmod_factor* factor = cholmod_analyze(A, &cc_);
- if (VLOG_IS_ON(2)) {
- cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
- }
- if (cc_.status != CHOLMOD_OK) {
- *message = StringPrintf("cholmod_analyze failed. error code: %d",
- cc_.status);
- return NULL;
- }
-
- return CHECK_NOTNULL(factor);
-}
-
-bool SuiteSparse::BlockAMDOrdering(const cholmod_sparse* A,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks,
- vector<int>* ordering) {
- const int num_row_blocks = row_blocks.size();
- const int num_col_blocks = col_blocks.size();
-
- // Arrays storing the compressed column structure of the matrix
- // incoding the block sparsity of A.
- vector<int> block_cols;
- vector<int> block_rows;
-
- CompressedColumnScalarMatrixToBlockMatrix(reinterpret_cast<const int*>(A->i),
- reinterpret_cast<const int*>(A->p),
- row_blocks,
- col_blocks,
- &block_rows,
- &block_cols);
-
- cholmod_sparse_struct block_matrix;
- block_matrix.nrow = num_row_blocks;
- block_matrix.ncol = num_col_blocks;
- block_matrix.nzmax = block_rows.size();
- block_matrix.p = reinterpret_cast<void*>(&block_cols[0]);
- block_matrix.i = reinterpret_cast<void*>(&block_rows[0]);
- block_matrix.x = NULL;
- block_matrix.stype = A->stype;
- block_matrix.itype = CHOLMOD_INT;
- block_matrix.xtype = CHOLMOD_PATTERN;
- block_matrix.dtype = CHOLMOD_DOUBLE;
- block_matrix.sorted = 1;
- block_matrix.packed = 1;
-
- vector<int> block_ordering(num_row_blocks);
- if (!cholmod_amd(&block_matrix, NULL, 0, &block_ordering[0], &cc_)) {
- return false;
- }
-
- BlockOrderingToScalarOrdering(row_blocks, block_ordering, ordering);
- return true;
-}
-
-LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
- cholmod_factor* L,
- string* message) {
- CHECK_NOTNULL(A);
- CHECK_NOTNULL(L);
-
- // Save the current print level and silence CHOLMOD, otherwise
- // CHOLMOD is prone to dumping stuff to stderr, which can be
- // distracting when the error (matrix is indefinite) is not a fatal
- // failure.
- const int old_print_level = cc_.print;
- cc_.print = 0;
-
- cc_.quick_return_if_not_posdef = 1;
- int cholmod_status = cholmod_factorize(A, L, &cc_);
- cc_.print = old_print_level;
-
- // TODO(sameeragarwal): This switch statement is not consistent. It
- // treats all kinds of CHOLMOD failures as warnings. Some of these
- // like out of memory are definitely not warnings. The problem is
- // that the return value Cholesky is two valued, but the state of
- // the linear solver is really three valued. SUCCESS,
- // NON_FATAL_FAILURE (e.g., indefinite matrix) and FATAL_FAILURE
- // (e.g. out of memory).
- switch (cc_.status) {
- case CHOLMOD_NOT_INSTALLED:
- *message = "CHOLMOD failure: Method not installed.";
- return LINEAR_SOLVER_FATAL_ERROR;
- case CHOLMOD_OUT_OF_MEMORY:
- *message = "CHOLMOD failure: Out of memory.";
- return LINEAR_SOLVER_FATAL_ERROR;
- case CHOLMOD_TOO_LARGE:
- *message = "CHOLMOD failure: Integer overflow occured.";
- return LINEAR_SOLVER_FATAL_ERROR;
- case CHOLMOD_INVALID:
- *message = "CHOLMOD failure: Invalid input.";
- return LINEAR_SOLVER_FATAL_ERROR;
- case CHOLMOD_NOT_POSDEF:
- *message = "CHOLMOD warning: Matrix not positive definite.";
- return LINEAR_SOLVER_FAILURE;
- case CHOLMOD_DSMALL:
- *message = "CHOLMOD warning: D for LDL' or diag(L) or "
- "LL' has tiny absolute value.";
- return LINEAR_SOLVER_FAILURE;
- case CHOLMOD_OK:
- if (cholmod_status != 0) {
- return LINEAR_SOLVER_SUCCESS;
- }
-
- *message = "CHOLMOD failure: cholmod_factorize returned false "
- "but cholmod_common::status is CHOLMOD_OK."
- "Please report this to ceres-solver@googlegroups.com.";
- return LINEAR_SOLVER_FATAL_ERROR;
- default:
- *message =
- StringPrintf("Unknown cholmod return code: %d. "
- "Please report this to ceres-solver@googlegroups.com.",
- cc_.status);
- return LINEAR_SOLVER_FATAL_ERROR;
- }
-
- return LINEAR_SOLVER_FATAL_ERROR;
-}
-
-cholmod_dense* SuiteSparse::Solve(cholmod_factor* L,
- cholmod_dense* b,
- string* message) {
- if (cc_.status != CHOLMOD_OK) {
- *message = "cholmod_solve failed. CHOLMOD status is not CHOLMOD_OK";
- return NULL;
- }
-
- return cholmod_solve(CHOLMOD_A, L, b, &cc_);
-}
-
-bool SuiteSparse::ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
- int* ordering) {
- return cholmod_amd(matrix, NULL, 0, ordering, &cc_);
-}
-
-bool SuiteSparse::ConstrainedApproximateMinimumDegreeOrdering(
- cholmod_sparse* matrix,
- int* constraints,
- int* ordering) {
-#ifndef CERES_NO_CAMD
- return cholmod_camd(matrix, NULL, 0, constraints, ordering, &cc_);
-#else
- LOG(FATAL) << "Congratulations you have found a bug in Ceres."
- << "Ceres Solver was compiled with SuiteSparse "
- << "version 4.1.0 or less. Calling this function "
- << "in that case is a bug. Please contact the"
- << "the Ceres Solver developers.";
- return false;
-#endif
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
deleted file mode 100644
index baab8998b29..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
+++ /dev/null
@@ -1,306 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// A simple C++ interface to the SuiteSparse and CHOLMOD libraries.
-
-#ifndef CERES_INTERNAL_SUITESPARSE_H_
-#define CERES_INTERNAL_SUITESPARSE_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include <cstring>
-#include <string>
-#include <vector>
-
-#include "ceres/internal/port.h"
-#include "ceres/linear_solver.h"
-#include "cholmod.h"
-#include "glog/logging.h"
-#include "SuiteSparseQR.hpp"
-
-// Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
-// if SuiteSparse was compiled with Metis support. This makes
-// calling and linking into cholmod_camd problematic even though it
-// has nothing to do with Metis. This has been fixed reliably in
-// 4.2.0.
-//
-// The fix was actually committed in 4.1.0, but there is
-// some confusion about a silent update to the tar ball, so we are
-// being conservative and choosing the next minor version where
-// things are stable.
-#if (SUITESPARSE_VERSION < 4002)
-#define CERES_NO_CAMD
-#endif
-
-// UF_long is deprecated but SuiteSparse_long is only available in
-// newer versions of SuiteSparse. So for older versions of
-// SuiteSparse, we define SuiteSparse_long to be the same as UF_long,
-// which is what recent versions of SuiteSparse do anyways.
-#ifndef SuiteSparse_long
-#define SuiteSparse_long UF_long
-#endif
-
-namespace ceres {
-namespace internal {
-
-class CompressedRowSparseMatrix;
-class TripletSparseMatrix;
-
-// The raw CHOLMOD and SuiteSparseQR libraries have a slightly
-// cumbersome c like calling format. This object abstracts it away and
-// provides the user with a simpler interface. The methods here cannot
-// be static as a cholmod_common object serves as a global variable
-// for all cholmod function calls.
-class SuiteSparse {
- public:
- SuiteSparse();
- ~SuiteSparse();
-
- // Functions for building cholmod_sparse objects from sparse
- // matrices stored in triplet form. The matrix A is not
- // modifed. Called owns the result.
- cholmod_sparse* CreateSparseMatrix(TripletSparseMatrix* A);
-
- // This function works like CreateSparseMatrix, except that the
- // return value corresponds to A' rather than A.
- cholmod_sparse* CreateSparseMatrixTranspose(TripletSparseMatrix* A);
-
- // Create a cholmod_sparse wrapper around the contents of A. This is
- // a shallow object, which refers to the contents of A and does not
- // use the SuiteSparse machinery to allocate memory.
- cholmod_sparse CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
-
- // Given a vector x, build a cholmod_dense vector of size out_size
- // with the first in_size entries copied from x. If x is NULL, then
- // an all zeros vector is returned. Caller owns the result.
- cholmod_dense* CreateDenseVector(const double* x, int in_size, int out_size);
-
- // The matrix A is scaled using the matrix whose diagonal is the
- // vector scale. mode describes how scaling is applied. Possible
- // values are CHOLMOD_ROW for row scaling - diag(scale) * A,
- // CHOLMOD_COL for column scaling - A * diag(scale) and CHOLMOD_SYM
- // for symmetric scaling which scales both the rows and the columns
- // - diag(scale) * A * diag(scale).
- void Scale(cholmod_dense* scale, int mode, cholmod_sparse* A) {
- cholmod_scale(scale, mode, A, &cc_);
- }
-
- // Create and return a matrix m = A * A'. Caller owns the
- // result. The matrix A is not modified.
- cholmod_sparse* AATranspose(cholmod_sparse* A) {
- cholmod_sparse*m = cholmod_aat(A, NULL, A->nrow, 1, &cc_);
- m->stype = 1; // Pay attention to the upper triangular part.
- return m;
- }
-
- // y = alpha * A * x + beta * y. Only y is modified.
- void SparseDenseMultiply(cholmod_sparse* A, double alpha, double beta,
- cholmod_dense* x, cholmod_dense* y) {
- double alpha_[2] = {alpha, 0};
- double beta_[2] = {beta, 0};
- cholmod_sdmult(A, 0, alpha_, beta_, x, y, &cc_);
- }
-
- // Find an ordering of A or AA' (if A is unsymmetric) that minimizes
- // the fill-in in the Cholesky factorization of the corresponding
- // matrix. This is done by using the AMD algorithm.
- //
- // Using this ordering, the symbolic Cholesky factorization of A (or
- // AA') is computed and returned.
- //
- // A is not modified, only the pattern of non-zeros of A is used,
- // the actual numerical values in A are of no consequence.
- //
- // message contains an explanation of the failures if any.
- //
- // Caller owns the result.
- cholmod_factor* AnalyzeCholesky(cholmod_sparse* A, string* message);
-
- cholmod_factor* BlockAnalyzeCholesky(cholmod_sparse* A,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks,
- string* message);
-
- // If A is symmetric, then compute the symbolic Cholesky
- // factorization of A(ordering, ordering). If A is unsymmetric, then
- // compute the symbolic factorization of
- // A(ordering,:) A(ordering,:)'.
- //
- // A is not modified, only the pattern of non-zeros of A is used,
- // the actual numerical values in A are of no consequence.
- //
- // message contains an explanation of the failures if any.
- //
- // Caller owns the result.
- cholmod_factor* AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A,
- const vector<int>& ordering,
- string* message);
-
- // Perform a symbolic factorization of A without re-ordering A. No
- // postordering of the elimination tree is performed. This ensures
- // that the symbolic factor does not introduce an extra permutation
- // on the matrix. See the documentation for CHOLMOD for more details.
- //
- // message contains an explanation of the failures if any.
- cholmod_factor* AnalyzeCholeskyWithNaturalOrdering(cholmod_sparse* A,
- string* message);
-
- // Use the symbolic factorization in L, to find the numerical
- // factorization for the matrix A or AA^T. Return true if
- // successful, false otherwise. L contains the numeric factorization
- // on return.
- //
- // message contains an explanation of the failures if any.
- LinearSolverTerminationType Cholesky(cholmod_sparse* A,
- cholmod_factor* L,
- string* message);
-
- // Given a Cholesky factorization of a matrix A = LL^T, solve the
- // linear system Ax = b, and return the result. If the Solve fails
- // NULL is returned. Caller owns the result.
- //
- // message contains an explanation of the failures if any.
- cholmod_dense* Solve(cholmod_factor* L, cholmod_dense* b, string* message);
-
- // By virtue of the modeling layer in Ceres being block oriented,
- // all the matrices used by Ceres are also block oriented. When
- // doing sparse direct factorization of these matrices the
- // fill-reducing ordering algorithms (in particular AMD) can either
- // be run on the block or the scalar form of these matrices. The two
- // SuiteSparse::AnalyzeCholesky methods allows the the client to
- // compute the symbolic factorization of a matrix by either using
- // AMD on the matrix or a user provided ordering of the rows.
- //
- // But since the underlying matrices are block oriented, it is worth
- // running AMD on just the block structre of these matrices and then
- // lifting these block orderings to a full scalar ordering. This
- // preserves the block structure of the permuted matrix, and exposes
- // more of the super-nodal structure of the matrix to the numerical
- // factorization routines.
- //
- // Find the block oriented AMD ordering of a matrix A, whose row and
- // column blocks are given by row_blocks, and col_blocks
- // respectively. The matrix may or may not be symmetric. The entries
- // of col_blocks do not need to sum to the number of columns in
- // A. If this is the case, only the first sum(col_blocks) are used
- // to compute the ordering.
- bool BlockAMDOrdering(const cholmod_sparse* A,
- const vector<int>& row_blocks,
- const vector<int>& col_blocks,
- vector<int>* ordering);
-
- // Find a fill reducing approximate minimum degree
- // ordering. ordering is expected to be large enough to hold the
- // ordering.
- bool ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix, int* ordering);
-
-
- // Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
- // if SuiteSparse was compiled with Metis support. This makes
- // calling and linking into cholmod_camd problematic even though it
- // has nothing to do with Metis. This has been fixed reliably in
- // 4.2.0.
- //
- // The fix was actually committed in 4.1.0, but there is
- // some confusion about a silent update to the tar ball, so we are
- // being conservative and choosing the next minor version where
- // things are stable.
- static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
- return (SUITESPARSE_VERSION>4001);
- }
-
- // Find a fill reducing approximate minimum degree
- // ordering. constraints is an array which associates with each
- // column of the matrix an elimination group. i.e., all columns in
- // group 0 are eliminated first, all columns in group 1 are
- // eliminated next etc. This function finds a fill reducing ordering
- // that obeys these constraints.
- //
- // Calling ApproximateMinimumDegreeOrdering is equivalent to calling
- // ConstrainedApproximateMinimumDegreeOrdering with a constraint
- // array that puts all columns in the same elimination group.
- //
- // If CERES_NO_CAMD is defined then calling this function will
- // result in a crash.
- bool ConstrainedApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
- int* constraints,
- int* ordering);
-
- void Free(cholmod_sparse* m) { cholmod_free_sparse(&m, &cc_); }
- void Free(cholmod_dense* m) { cholmod_free_dense(&m, &cc_); }
- void Free(cholmod_factor* m) { cholmod_free_factor(&m, &cc_); }
-
- void Print(cholmod_sparse* m, const string& name) {
- cholmod_print_sparse(m, const_cast<char*>(name.c_str()), &cc_);
- }
-
- void Print(cholmod_dense* m, const string& name) {
- cholmod_print_dense(m, const_cast<char*>(name.c_str()), &cc_);
- }
-
- void Print(cholmod_triplet* m, const string& name) {
- cholmod_print_triplet(m, const_cast<char*>(name.c_str()), &cc_);
- }
-
- cholmod_common* mutable_cc() { return &cc_; }
-
- private:
- cholmod_common cc_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#else // CERES_NO_SUITESPARSE
-
-typedef void cholmod_factor;
-
-class SuiteSparse {
- public:
- // Defining this static function even when SuiteSparse is not
- // available, allows client code to check for the presence of CAMD
- // without checking for the absence of the CERES_NO_CAMD symbol.
- //
- // This is safer because the symbol maybe missing due to a user
- // accidently not including suitesparse.h in their code when
- // checking for the symbol.
- static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
- return false;
- }
-
- void Free(void*) {};
-};
-
-#endif // CERES_NO_SUITESPARSE
-
-#endif // CERES_INTERNAL_SUITESPARSE_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
deleted file mode 100644
index 824b123bc28..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/triplet_sparse_matrix.h"
-
-#include <algorithm>
-#include <cstddef>
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-TripletSparseMatrix::TripletSparseMatrix()
- : num_rows_(0),
- num_cols_(0),
- max_num_nonzeros_(0),
- num_nonzeros_(0),
- rows_(NULL),
- cols_(NULL),
- values_(NULL) {}
-
-TripletSparseMatrix::~TripletSparseMatrix() {}
-
-TripletSparseMatrix::TripletSparseMatrix(int num_rows,
- int num_cols,
- int max_num_nonzeros)
- : num_rows_(num_rows),
- num_cols_(num_cols),
- max_num_nonzeros_(max_num_nonzeros),
- num_nonzeros_(0),
- rows_(NULL),
- cols_(NULL),
- values_(NULL) {
- // All the sizes should at least be zero
- CHECK_GE(num_rows, 0);
- CHECK_GE(num_cols, 0);
- CHECK_GE(max_num_nonzeros, 0);
- AllocateMemory();
-}
-
-TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig)
- : SparseMatrix(),
- num_rows_(orig.num_rows_),
- num_cols_(orig.num_cols_),
- max_num_nonzeros_(orig.max_num_nonzeros_),
- num_nonzeros_(orig.num_nonzeros_),
- rows_(NULL),
- cols_(NULL),
- values_(NULL) {
- AllocateMemory();
- CopyData(orig);
-}
-
-TripletSparseMatrix& TripletSparseMatrix::operator=(
- const TripletSparseMatrix& rhs) {
- num_rows_ = rhs.num_rows_;
- num_cols_ = rhs.num_cols_;
- num_nonzeros_ = rhs.num_nonzeros_;
- max_num_nonzeros_ = rhs.max_num_nonzeros_;
- AllocateMemory();
- CopyData(rhs);
- return *this;
-}
-
-bool TripletSparseMatrix::AllTripletsWithinBounds() const {
- for (int i = 0; i < num_nonzeros_; ++i) {
- if ((rows_[i] < 0) || (rows_[i] >= num_rows_) ||
- (cols_[i] < 0) || (cols_[i] >= num_cols_))
- return false;
- }
- return true;
-}
-
-void TripletSparseMatrix::Reserve(int new_max_num_nonzeros) {
- CHECK_LE(num_nonzeros_, new_max_num_nonzeros)
- << "Reallocation will cause data loss";
-
- // Nothing to do if we have enough space already.
- if (new_max_num_nonzeros <= max_num_nonzeros_)
- return;
-
- int* new_rows = new int[new_max_num_nonzeros];
- int* new_cols = new int[new_max_num_nonzeros];
- double* new_values = new double[new_max_num_nonzeros];
-
- for (int i = 0; i < num_nonzeros_; ++i) {
- new_rows[i] = rows_[i];
- new_cols[i] = cols_[i];
- new_values[i] = values_[i];
- }
-
- rows_.reset(new_rows);
- cols_.reset(new_cols);
- values_.reset(new_values);
-
- max_num_nonzeros_ = new_max_num_nonzeros;
-}
-
-void TripletSparseMatrix::SetZero() {
- fill(values_.get(), values_.get() + max_num_nonzeros_, 0.0);
- num_nonzeros_ = 0;
-}
-
-void TripletSparseMatrix::set_num_nonzeros(int num_nonzeros) {
- CHECK_GE(num_nonzeros, 0);
- CHECK_LE(num_nonzeros, max_num_nonzeros_);
- num_nonzeros_ = num_nonzeros;
-};
-
-void TripletSparseMatrix::AllocateMemory() {
- rows_.reset(new int[max_num_nonzeros_]);
- cols_.reset(new int[max_num_nonzeros_]);
- values_.reset(new double[max_num_nonzeros_]);
-}
-
-void TripletSparseMatrix::CopyData(const TripletSparseMatrix& orig) {
- for (int i = 0; i < num_nonzeros_; ++i) {
- rows_[i] = orig.rows_[i];
- cols_[i] = orig.cols_[i];
- values_[i] = orig.values_[i];
- }
-}
-
-void TripletSparseMatrix::RightMultiply(const double* x, double* y) const {
- for (int i = 0; i < num_nonzeros_; ++i) {
- y[rows_[i]] += values_[i]*x[cols_[i]];
- }
-}
-
-void TripletSparseMatrix::LeftMultiply(const double* x, double* y) const {
- for (int i = 0; i < num_nonzeros_; ++i) {
- y[cols_[i]] += values_[i]*x[rows_[i]];
- }
-}
-
-void TripletSparseMatrix::SquaredColumnNorm(double* x) const {
- CHECK_NOTNULL(x);
- VectorRef(x, num_cols_).setZero();
- for (int i = 0; i < num_nonzeros_; ++i) {
- x[cols_[i]] += values_[i] * values_[i];
- }
-}
-
-void TripletSparseMatrix::ScaleColumns(const double* scale) {
- CHECK_NOTNULL(scale);
- for (int i = 0; i < num_nonzeros_; ++i) {
- values_[i] = values_[i] * scale[cols_[i]];
- }
-}
-
-void TripletSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- dense_matrix->resize(num_rows_, num_cols_);
- dense_matrix->setZero();
- Matrix& m = *dense_matrix;
- for (int i = 0; i < num_nonzeros_; ++i) {
- m(rows_[i], cols_[i]) += values_[i];
- }
-}
-
-void TripletSparseMatrix::AppendRows(const TripletSparseMatrix& B) {
- CHECK_EQ(B.num_cols(), num_cols_);
- Reserve(num_nonzeros_ + B.num_nonzeros_);
- for (int i = 0; i < B.num_nonzeros_; ++i) {
- rows_.get()[num_nonzeros_] = B.rows()[i] + num_rows_;
- cols_.get()[num_nonzeros_] = B.cols()[i];
- values_.get()[num_nonzeros_++] = B.values()[i];
- }
- num_rows_ = num_rows_ + B.num_rows();
-}
-
-void TripletSparseMatrix::AppendCols(const TripletSparseMatrix& B) {
- CHECK_EQ(B.num_rows(), num_rows_);
- Reserve(num_nonzeros_ + B.num_nonzeros_);
- for (int i = 0; i < B.num_nonzeros_; ++i, ++num_nonzeros_) {
- rows_.get()[num_nonzeros_] = B.rows()[i];
- cols_.get()[num_nonzeros_] = B.cols()[i] + num_cols_;
- values_.get()[num_nonzeros_] = B.values()[i];
- }
- num_cols_ = num_cols_ + B.num_cols();
-}
-
-
-void TripletSparseMatrix::Resize(int new_num_rows, int new_num_cols) {
- if ((new_num_rows >= num_rows_) && (new_num_cols >= num_cols_)) {
- num_rows_ = new_num_rows;
- num_cols_ = new_num_cols;
- return;
- }
-
- num_rows_ = new_num_rows;
- num_cols_ = new_num_cols;
-
- int* r_ptr = rows_.get();
- int* c_ptr = cols_.get();
- double* v_ptr = values_.get();
-
- int dropped_terms = 0;
- for (int i = 0; i < num_nonzeros_; ++i) {
- if ((r_ptr[i] < num_rows_) && (c_ptr[i] < num_cols_)) {
- if (dropped_terms) {
- r_ptr[i-dropped_terms] = r_ptr[i];
- c_ptr[i-dropped_terms] = c_ptr[i];
- v_ptr[i-dropped_terms] = v_ptr[i];
- }
- } else {
- ++dropped_terms;
- }
- }
- num_nonzeros_ -= dropped_terms;
-}
-
-TripletSparseMatrix* TripletSparseMatrix::CreateSparseDiagonalMatrix(
- const double* values, int num_rows) {
- TripletSparseMatrix* m =
- new TripletSparseMatrix(num_rows, num_rows, num_rows);
- for (int i = 0; i < num_rows; ++i) {
- m->mutable_rows()[i] = i;
- m->mutable_cols()[i] = i;
- m->mutable_values()[i] = values[i];
- }
- m->set_num_nonzeros(num_rows);
- return m;
-}
-
-void TripletSparseMatrix::ToTextFile(FILE* file) const {
- CHECK_NOTNULL(file);
- for (int i = 0; i < num_nonzeros_; ++i) {
- fprintf(file, "% 10d % 10d %17f\n", rows_[i], cols_[i], values_[i]);
- }
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h
deleted file mode 100644
index 4d7cde7fe9c..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.h
+++ /dev/null
@@ -1,129 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
-#define CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
-
-#include "ceres/sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-// An implementation of the SparseMatrix interface to store and
-// manipulate sparse matrices in triplet (i,j,s) form. This object is
-// inspired by the design of the cholmod_triplet struct used in the
-// SuiteSparse package and is memory layout compatible with it.
-class TripletSparseMatrix : public SparseMatrix {
- public:
- TripletSparseMatrix();
- TripletSparseMatrix(int num_rows, int num_cols, int max_num_nonzeros);
- explicit TripletSparseMatrix(const TripletSparseMatrix& orig);
-
- TripletSparseMatrix& operator=(const TripletSparseMatrix& rhs);
-
- ~TripletSparseMatrix();
-
- // Implementation of the SparseMatrix interface.
- virtual void SetZero();
- virtual void RightMultiply(const double* x, double* y) const;
- virtual void LeftMultiply(const double* x, double* y) const;
- virtual void SquaredColumnNorm(double* x) const;
- virtual void ScaleColumns(const double* scale);
- virtual void ToDenseMatrix(Matrix* dense_matrix) const;
- virtual void ToTextFile(FILE* file) const;
- virtual int num_rows() const { return num_rows_; }
- virtual int num_cols() const { return num_cols_; }
- virtual int num_nonzeros() const { return num_nonzeros_; }
- virtual const double* values() const { return values_.get(); }
- virtual double* mutable_values() { return values_.get(); }
- virtual void set_num_nonzeros(int num_nonzeros);
-
- // Increase max_num_nonzeros and correspondingly increase the size
- // of rows_, cols_ and values_. If new_max_num_nonzeros is smaller
- // than max_num_nonzeros_, then num_non_zeros should be less than or
- // equal to new_max_num_nonzeros, otherwise data loss is possible
- // and the method crashes.
- void Reserve(int new_max_num_nonzeros);
-
- // Append the matrix B at the bottom of this matrix. B should have
- // the same number of columns as num_cols_.
- void AppendRows(const TripletSparseMatrix& B);
-
- // Append the matrix B at the right of this matrix. B should have
- // the same number of rows as num_rows_;
- void AppendCols(const TripletSparseMatrix& B);
-
- // Resize the matrix. Entries which fall outside the new matrix
- // bounds are dropped and the num_non_zeros changed accordingly.
- void Resize(int new_num_rows, int new_num_cols);
-
- int max_num_nonzeros() const { return max_num_nonzeros_; }
- const int* rows() const { return rows_.get(); }
- const int* cols() const { return cols_.get(); }
- int* mutable_rows() { return rows_.get(); }
- int* mutable_cols() { return cols_.get(); }
-
- // Returns true if the entries of the matrix obey the row, column,
- // and column size bounds and false otherwise.
- bool AllTripletsWithinBounds() const;
-
- bool IsValid() const { return AllTripletsWithinBounds(); }
-
- // Build a sparse diagonal matrix of size num_rows x num_rows from
- // the array values. Entries of the values array are copied into the
- // sparse matrix.
- static TripletSparseMatrix* CreateSparseDiagonalMatrix(const double* values,
- int num_rows);
-
- private:
- void AllocateMemory();
- void CopyData(const TripletSparseMatrix& orig);
-
- int num_rows_;
- int num_cols_;
- int max_num_nonzeros_;
- int num_nonzeros_;
-
- // The data is stored as three arrays. For each i, values_[i] is
- // stored at the location (rows_[i], cols_[i]). If the there are
- // multiple entries with the same (rows_[i], cols_[i]), the values_
- // entries corresponding to them are summed up.
- scoped_array<int> rows_;
- scoped_array<int> cols_;
- scoped_array<double> values_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H__
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
deleted file mode 100644
index 926bced6226..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
+++ /dev/null
@@ -1,690 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/trust_region_minimizer.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <cmath>
-#include <cstring>
-#include <limits>
-#include <string>
-#include <vector>
-
-#include "Eigen/Core"
-#include "ceres/array_utils.h"
-#include "ceres/coordinate_descent_minimizer.h"
-#include "ceres/evaluator.h"
-#include "ceres/file.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/line_search.h"
-#include "ceres/linear_least_squares_problems.h"
-#include "ceres/sparse_matrix.h"
-#include "ceres/stringprintf.h"
-#include "ceres/trust_region_strategy.h"
-#include "ceres/types.h"
-#include "ceres/wall_time.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-LineSearch::Summary DoLineSearch(const Minimizer::Options& options,
- const Vector& x,
- const Vector& gradient,
- const double cost,
- const Vector& delta,
- Evaluator* evaluator) {
- LineSearchFunction line_search_function(evaluator);
-
- LineSearch::Options line_search_options;
- line_search_options.is_silent = true;
- line_search_options.interpolation_type =
- options.line_search_interpolation_type;
- line_search_options.min_step_size = options.min_line_search_step_size;
- line_search_options.sufficient_decrease =
- options.line_search_sufficient_function_decrease;
- line_search_options.max_step_contraction =
- options.max_line_search_step_contraction;
- line_search_options.min_step_contraction =
- options.min_line_search_step_contraction;
- line_search_options.max_num_iterations =
- options.max_num_line_search_step_size_iterations;
- line_search_options.sufficient_curvature_decrease =
- options.line_search_sufficient_curvature_decrease;
- line_search_options.max_step_expansion =
- options.max_line_search_step_expansion;
- line_search_options.function = &line_search_function;
-
- string message;
- scoped_ptr<LineSearch>
- line_search(CHECK_NOTNULL(
- LineSearch::Create(ceres::ARMIJO,
- line_search_options,
- &message)));
- LineSearch::Summary summary;
- line_search_function.Init(x, delta);
- // Try the trust region step.
- line_search->Search(1.0, cost, gradient.dot(delta), &summary);
- if (!summary.success) {
- // If that was not successful, try the negative gradient as a
- // search direction.
- line_search_function.Init(x, -gradient);
- line_search->Search(1.0, cost, -gradient.squaredNorm(), &summary);
- }
- return summary;
-}
-
-} // namespace
-
-// Compute a scaling vector that is used to improve the conditioning
-// of the Jacobian.
-void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian,
- double* scale) const {
- jacobian.SquaredColumnNorm(scale);
- for (int i = 0; i < jacobian.num_cols(); ++i) {
- scale[i] = 1.0 / (1.0 + sqrt(scale[i]));
- }
-}
-
-void TrustRegionMinimizer::Init(const Minimizer::Options& options) {
- options_ = options;
- sort(options_.trust_region_minimizer_iterations_to_dump.begin(),
- options_.trust_region_minimizer_iterations_to_dump.end());
-}
-
-void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary) {
- double start_time = WallTimeInSeconds();
- double iteration_start_time = start_time;
- Init(options);
-
- Evaluator* evaluator = CHECK_NOTNULL(options_.evaluator.get());
- SparseMatrix* jacobian = CHECK_NOTNULL(options_.jacobian.get());
- TrustRegionStrategy* strategy =
- CHECK_NOTNULL(options_.trust_region_strategy.get());
-
- const bool is_not_silent = !options.is_silent;
-
- // If the problem is bounds constrained, then enable the use of a
- // line search after the trust region step has been computed. This
- // line search will automatically use a projected test point onto
- // the feasible set, there by guaranteeing the feasibility of the
- // final output.
- //
- // TODO(sameeragarwal): Make line search available more generally.
- const bool use_line_search = options.is_constrained;
-
- summary->termination_type = NO_CONVERGENCE;
- summary->num_successful_steps = 0;
- summary->num_unsuccessful_steps = 0;
-
- const int num_parameters = evaluator->NumParameters();
- const int num_effective_parameters = evaluator->NumEffectiveParameters();
- const int num_residuals = evaluator->NumResiduals();
-
- Vector residuals(num_residuals);
- Vector trust_region_step(num_effective_parameters);
- Vector delta(num_effective_parameters);
- Vector x_plus_delta(num_parameters);
- Vector gradient(num_effective_parameters);
- Vector model_residuals(num_residuals);
- Vector scale(num_effective_parameters);
- Vector negative_gradient(num_effective_parameters);
- Vector projected_gradient_step(num_parameters);
-
- IterationSummary iteration_summary;
- iteration_summary.iteration = 0;
- iteration_summary.step_is_valid = false;
- iteration_summary.step_is_successful = false;
- iteration_summary.cost_change = 0.0;
- iteration_summary.gradient_max_norm = 0.0;
- iteration_summary.gradient_norm = 0.0;
- iteration_summary.step_norm = 0.0;
- iteration_summary.relative_decrease = 0.0;
- iteration_summary.trust_region_radius = strategy->Radius();
- iteration_summary.eta = options_.eta;
- iteration_summary.linear_solver_iterations = 0;
- iteration_summary.step_solver_time_in_seconds = 0;
-
- VectorRef x_min(parameters, num_parameters);
- Vector x = x_min;
- // Project onto the feasible set.
- if (options.is_constrained) {
- delta.setZero();
- if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
- summary->message =
- "Unable to project initial point onto the feasible set.";
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
- x_min = x_plus_delta;
- x = x_plus_delta;
- }
-
- double x_norm = x.norm();
-
- // Do initial cost and Jacobian evaluation.
- double cost = 0.0;
- if (!evaluator->Evaluate(x.data(),
- &cost,
- residuals.data(),
- gradient.data(),
- jacobian)) {
- summary->message = "Residual and Jacobian evaluation failed.";
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- negative_gradient = -gradient;
- if (!evaluator->Plus(x.data(),
- negative_gradient.data(),
- projected_gradient_step.data())) {
- summary->message = "Unable to compute gradient step.";
- summary->termination_type = FAILURE;
- LOG(ERROR) << "Terminating: " << summary->message;
- return;
- }
-
- summary->initial_cost = cost + summary->fixed_cost;
- iteration_summary.cost = cost + summary->fixed_cost;
- iteration_summary.gradient_max_norm =
- (x - projected_gradient_step).lpNorm<Eigen::Infinity>();
- iteration_summary.gradient_norm = (x - projected_gradient_step).norm();
-
- if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
- summary->message = StringPrintf("Gradient tolerance reached. "
- "Gradient max norm: %e <= %e",
- iteration_summary.gradient_max_norm,
- options_.gradient_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- if (options_.jacobi_scaling) {
- EstimateScale(*jacobian, scale.data());
- jacobian->ScaleColumns(scale.data());
- } else {
- scale.setOnes();
- }
-
- iteration_summary.iteration_time_in_seconds =
- WallTimeInSeconds() - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds =
- WallTimeInSeconds() - start_time
- + summary->preprocessor_time_in_seconds;
- summary->iterations.push_back(iteration_summary);
-
- int num_consecutive_nonmonotonic_steps = 0;
- double minimum_cost = cost;
- double reference_cost = cost;
- double accumulated_reference_model_cost_change = 0.0;
- double candidate_cost = cost;
- double accumulated_candidate_model_cost_change = 0.0;
- int num_consecutive_invalid_steps = 0;
- bool inner_iterations_are_enabled =
- options.inner_iteration_minimizer.get() != NULL;
- while (true) {
- bool inner_iterations_were_useful = false;
- if (!RunCallbacks(options, iteration_summary, summary)) {
- return;
- }
-
- iteration_start_time = WallTimeInSeconds();
- if (iteration_summary.iteration >= options_.max_num_iterations) {
- summary->message = "Maximum number of iterations reached.";
- summary->termination_type = NO_CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- const double total_solver_time = iteration_start_time - start_time +
- summary->preprocessor_time_in_seconds;
- if (total_solver_time >= options_.max_solver_time_in_seconds) {
- summary->message = "Maximum solver time reached.";
- summary->termination_type = NO_CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- const double strategy_start_time = WallTimeInSeconds();
- TrustRegionStrategy::PerSolveOptions per_solve_options;
- per_solve_options.eta = options_.eta;
- if (find(options_.trust_region_minimizer_iterations_to_dump.begin(),
- options_.trust_region_minimizer_iterations_to_dump.end(),
- iteration_summary.iteration) !=
- options_.trust_region_minimizer_iterations_to_dump.end()) {
- per_solve_options.dump_format_type =
- options_.trust_region_problem_dump_format_type;
- per_solve_options.dump_filename_base =
- JoinPath(options_.trust_region_problem_dump_directory,
- StringPrintf("ceres_solver_iteration_%03d",
- iteration_summary.iteration));
- } else {
- per_solve_options.dump_format_type = TEXTFILE;
- per_solve_options.dump_filename_base.clear();
- }
-
- TrustRegionStrategy::Summary strategy_summary =
- strategy->ComputeStep(per_solve_options,
- jacobian,
- residuals.data(),
- trust_region_step.data());
-
- if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
- summary->message =
- "Linear solver failed due to unrecoverable "
- "non-numeric causes. Please see the error log for clues. ";
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- iteration_summary = IterationSummary();
- iteration_summary.iteration = summary->iterations.back().iteration + 1;
- iteration_summary.step_solver_time_in_seconds =
- WallTimeInSeconds() - strategy_start_time;
- iteration_summary.linear_solver_iterations =
- strategy_summary.num_iterations;
- iteration_summary.step_is_valid = false;
- iteration_summary.step_is_successful = false;
-
- double model_cost_change = 0.0;
- if (strategy_summary.termination_type != LINEAR_SOLVER_FAILURE) {
- // new_model_cost
- // = 1/2 [f + J * step]^2
- // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ]
- // model_cost_change
- // = cost - new_model_cost
- // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step]
- // = -f'J * step - step' * J' * J * step / 2
- model_residuals.setZero();
- jacobian->RightMultiply(trust_region_step.data(), model_residuals.data());
- model_cost_change =
- - model_residuals.dot(residuals + model_residuals / 2.0);
-
- if (model_cost_change < 0.0) {
- VLOG_IF(1, is_not_silent)
- << "Invalid step: current_cost: " << cost
- << " absolute difference " << model_cost_change
- << " relative difference " << (model_cost_change / cost);
- } else {
- iteration_summary.step_is_valid = true;
- }
- }
-
- if (!iteration_summary.step_is_valid) {
- // Invalid steps can happen due to a number of reasons, and we
- // allow a limited number of successive failures, and return with
- // FAILURE if this limit is exceeded.
- if (++num_consecutive_invalid_steps >=
- options_.max_num_consecutive_invalid_steps) {
- summary->message = StringPrintf(
- "Number of successive invalid steps more "
- "than Solver::Options::max_num_consecutive_invalid_steps: %d",
- options_.max_num_consecutive_invalid_steps);
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- // We are going to try and reduce the trust region radius and
- // solve again. To do this, we are going to treat this iteration
- // as an unsuccessful iteration. Since the various callbacks are
- // still executed, we are going to fill the iteration summary
- // with data that assumes a step of length zero and no progress.
- iteration_summary.cost = cost + summary->fixed_cost;
- iteration_summary.cost_change = 0.0;
- iteration_summary.gradient_max_norm =
- summary->iterations.back().gradient_max_norm;
- iteration_summary.gradient_norm =
- summary->iterations.back().gradient_norm;
- iteration_summary.step_norm = 0.0;
- iteration_summary.relative_decrease = 0.0;
- iteration_summary.eta = options_.eta;
- } else {
- // The step is numerically valid, so now we can judge its quality.
- num_consecutive_invalid_steps = 0;
-
- // Undo the Jacobian column scaling.
- delta = (trust_region_step.array() * scale.array()).matrix();
-
- // Try improving the step further by using an ARMIJO line
- // search.
- //
- // TODO(sameeragarwal): What happens to trust region sizing as
- // it interacts with the line search ?
- if (use_line_search) {
- const LineSearch::Summary line_search_summary =
- DoLineSearch(options, x, gradient, cost, delta, evaluator);
- if (line_search_summary.success) {
- delta *= line_search_summary.optimal_step_size;
- }
- }
-
- double new_cost = std::numeric_limits<double>::max();
- if (evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
- if (!evaluator->Evaluate(x_plus_delta.data(),
- &new_cost,
- NULL,
- NULL,
- NULL)) {
- LOG(WARNING) << "Step failed to evaluate. "
- << "Treating it as a step with infinite cost";
- new_cost = numeric_limits<double>::max();
- }
- } else {
- LOG(WARNING) << "x_plus_delta = Plus(x, delta) failed. "
- << "Treating it as a step with infinite cost";
- }
-
- if (new_cost < std::numeric_limits<double>::max()) {
- // Check if performing an inner iteration will make it better.
- if (inner_iterations_are_enabled) {
- ++summary->num_inner_iteration_steps;
- double inner_iteration_start_time = WallTimeInSeconds();
- const double x_plus_delta_cost = new_cost;
- Vector inner_iteration_x = x_plus_delta;
- Solver::Summary inner_iteration_summary;
- options.inner_iteration_minimizer->Minimize(options,
- inner_iteration_x.data(),
- &inner_iteration_summary);
- if (!evaluator->Evaluate(inner_iteration_x.data(),
- &new_cost,
- NULL, NULL, NULL)) {
- VLOG_IF(2, is_not_silent) << "Inner iteration failed.";
- new_cost = x_plus_delta_cost;
- } else {
- x_plus_delta = inner_iteration_x;
- // Boost the model_cost_change, since the inner iteration
- // improvements are not accounted for by the trust region.
- model_cost_change += x_plus_delta_cost - new_cost;
- VLOG_IF(2, is_not_silent)
- << "Inner iteration succeeded; Current cost: " << cost
- << " Trust region step cost: " << x_plus_delta_cost
- << " Inner iteration cost: " << new_cost;
-
- inner_iterations_were_useful = new_cost < cost;
-
- const double inner_iteration_relative_progress =
- 1.0 - new_cost / x_plus_delta_cost;
- // Disable inner iterations once the relative improvement
- // drops below tolerance.
- inner_iterations_are_enabled =
- (inner_iteration_relative_progress >
- options.inner_iteration_tolerance);
- VLOG_IF(2, is_not_silent && !inner_iterations_are_enabled)
- << "Disabling inner iterations. Progress : "
- << inner_iteration_relative_progress;
- }
- summary->inner_iteration_time_in_seconds +=
- WallTimeInSeconds() - inner_iteration_start_time;
- }
- }
-
- iteration_summary.step_norm = (x - x_plus_delta).norm();
-
- // Convergence based on parameter_tolerance.
- const double step_size_tolerance = options_.parameter_tolerance *
- (x_norm + options_.parameter_tolerance);
- if (iteration_summary.step_norm <= step_size_tolerance) {
- summary->message =
- StringPrintf("Parameter tolerance reached. "
- "Relative step_norm: %e <= %e.",
- (iteration_summary.step_norm /
- (x_norm + options_.parameter_tolerance)),
- options_.parameter_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- iteration_summary.cost_change = cost - new_cost;
- const double absolute_function_tolerance =
- options_.function_tolerance * cost;
- if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
- summary->message =
- StringPrintf("Function tolerance reached. "
- "|cost_change|/cost: %e <= %e",
- fabs(iteration_summary.cost_change) / cost,
- options_.function_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- const double relative_decrease =
- iteration_summary.cost_change / model_cost_change;
-
- const double historical_relative_decrease =
- (reference_cost - new_cost) /
- (accumulated_reference_model_cost_change + model_cost_change);
-
- // If monotonic steps are being used, then the relative_decrease
- // is the usual ratio of the change in objective function value
- // divided by the change in model cost.
- //
- // If non-monotonic steps are allowed, then we take the maximum
- // of the relative_decrease and the
- // historical_relative_decrease, which measures the increase
- // from a reference iteration. The model cost change is
- // estimated by accumulating the model cost changes since the
- // reference iteration. The historical relative_decrease offers
- // a boost to a step which is not too bad compared to the
- // reference iteration, allowing for non-monotonic steps.
- iteration_summary.relative_decrease =
- options.use_nonmonotonic_steps
- ? max(relative_decrease, historical_relative_decrease)
- : relative_decrease;
-
- // Normally, the quality of a trust region step is measured by
- // the ratio
- //
- // cost_change
- // r = -----------------
- // model_cost_change
- //
- // All the change in the nonlinear objective is due to the trust
- // region step so this ratio is a good measure of the quality of
- // the trust region radius. However, when inner iterations are
- // being used, cost_change includes the contribution of the
- // inner iterations and its not fair to credit it all to the
- // trust region algorithm. So we change the ratio to be
- //
- // cost_change
- // r = ------------------------------------------------
- // (model_cost_change + inner_iteration_cost_change)
- //
- // In most cases this is fine, but it can be the case that the
- // change in solution quality due to inner iterations is so large
- // and the trust region step is so bad, that this ratio can become
- // quite small.
- //
- // This can cause the trust region loop to reject this step. To
- // get around this, we expicitly check if the inner iterations
- // led to a net decrease in the objective function value. If
- // they did, we accept the step even if the trust region ratio
- // is small.
- //
- // Notice that we do not just check that cost_change is positive
- // which is a weaker condition and would render the
- // min_relative_decrease threshold useless. Instead, we keep
- // track of inner_iterations_were_useful, which is true only
- // when inner iterations lead to a net decrease in the cost.
- iteration_summary.step_is_successful =
- (inner_iterations_were_useful ||
- iteration_summary.relative_decrease >
- options_.min_relative_decrease);
-
- if (iteration_summary.step_is_successful) {
- accumulated_candidate_model_cost_change += model_cost_change;
- accumulated_reference_model_cost_change += model_cost_change;
-
- if (!inner_iterations_were_useful &&
- relative_decrease <= options_.min_relative_decrease) {
- iteration_summary.step_is_nonmonotonic = true;
- VLOG_IF(2, is_not_silent)
- << "Non-monotonic step! "
- << " relative_decrease: "
- << relative_decrease
- << " historical_relative_decrease: "
- << historical_relative_decrease;
- }
- }
- }
-
- if (iteration_summary.step_is_successful) {
- ++summary->num_successful_steps;
- strategy->StepAccepted(iteration_summary.relative_decrease);
-
- x = x_plus_delta;
- x_norm = x.norm();
-
- // Step looks good, evaluate the residuals and Jacobian at this
- // point.
- if (!evaluator->Evaluate(x.data(),
- &cost,
- residuals.data(),
- gradient.data(),
- jacobian)) {
- summary->message = "Residual and Jacobian evaluation failed.";
- summary->termination_type = FAILURE;
- LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- negative_gradient = -gradient;
- if (!evaluator->Plus(x.data(),
- negative_gradient.data(),
- projected_gradient_step.data())) {
- summary->message =
- "projected_gradient_step = Plus(x, -gradient) failed.";
- summary->termination_type = FAILURE;
- LOG(ERROR) << "Terminating: " << summary->message;
- return;
- }
-
- iteration_summary.gradient_max_norm =
- (x - projected_gradient_step).lpNorm<Eigen::Infinity>();
- iteration_summary.gradient_norm = (x - projected_gradient_step).norm();
-
- if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) {
- summary->message = StringPrintf("Gradient tolerance reached. "
- "Gradient max norm: %e <= %e",
- iteration_summary.gradient_max_norm,
- options_.gradient_tolerance);
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message;
- return;
- }
-
- if (options_.jacobi_scaling) {
- jacobian->ScaleColumns(scale.data());
- }
-
- // Update the best, reference and candidate iterates.
- //
- // Based on algorithm 10.1.2 (page 357) of "Trust Region
- // Methods" by Conn Gould & Toint, or equations 33-40 of
- // "Non-monotone trust-region algorithms for nonlinear
- // optimization subject to convex constraints" by Phil Toint,
- // Mathematical Programming, 77, 1997.
- if (cost < minimum_cost) {
- // A step that improves solution quality was found.
- x_min = x;
- minimum_cost = cost;
- // Set the candidate iterate to the current point.
- candidate_cost = cost;
- num_consecutive_nonmonotonic_steps = 0;
- accumulated_candidate_model_cost_change = 0.0;
- } else {
- ++num_consecutive_nonmonotonic_steps;
- if (cost > candidate_cost) {
- // The current iterate is has a higher cost than the
- // candidate iterate. Set the candidate to this point.
- VLOG_IF(2, is_not_silent)
- << "Updating the candidate iterate to the current point.";
- candidate_cost = cost;
- accumulated_candidate_model_cost_change = 0.0;
- }
-
- // At this point we have made too many non-monotonic steps and
- // we are going to reset the value of the reference iterate so
- // as to force the algorithm to descend.
- //
- // This is the case because the candidate iterate has a value
- // greater than minimum_cost but smaller than the reference
- // iterate.
- if (num_consecutive_nonmonotonic_steps ==
- options.max_consecutive_nonmonotonic_steps) {
- VLOG_IF(2, is_not_silent)
- << "Resetting the reference point to the candidate point";
- reference_cost = candidate_cost;
- accumulated_reference_model_cost_change =
- accumulated_candidate_model_cost_change;
- }
- }
- } else {
- ++summary->num_unsuccessful_steps;
- if (iteration_summary.step_is_valid) {
- strategy->StepRejected(iteration_summary.relative_decrease);
- } else {
- strategy->StepIsInvalid();
- }
- }
-
- iteration_summary.cost = cost + summary->fixed_cost;
- iteration_summary.trust_region_radius = strategy->Radius();
- if (iteration_summary.trust_region_radius <
- options_.min_trust_region_radius) {
- summary->message = "Termination. Minimum trust region radius reached.";
- summary->termination_type = CONVERGENCE;
- VLOG_IF(1, is_not_silent) << summary->message;
- return;
- }
-
- iteration_summary.iteration_time_in_seconds =
- WallTimeInSeconds() - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds =
- WallTimeInSeconds() - start_time
- + summary->preprocessor_time_in_seconds;
- summary->iterations.push_back(iteration_summary);
- }
-}
-
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
deleted file mode 100644
index 9a022843233..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
-#define CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
-
-#include "ceres/minimizer.h"
-#include "ceres/solver.h"
-#include "ceres/types.h"
-
-namespace ceres {
-namespace internal {
-
-// Generic trust region minimization algorithm. The heavy lifting is
-// done by a TrustRegionStrategy object passed in as part of options.
-//
-// For example usage, see SolverImpl::Minimize.
-class TrustRegionMinimizer : public Minimizer {
- public:
- ~TrustRegionMinimizer() {}
- virtual void Minimize(const Minimizer::Options& options,
- double* parameters,
- Solver::Summary* summary);
-
- private:
- void Init(const Minimizer::Options& options);
- void EstimateScale(const SparseMatrix& jacobian, double* scale) const;
- bool MaybeDumpLinearLeastSquaresProblem(const int iteration,
- const SparseMatrix* jacobian,
- const double* residuals,
- const double* step) const;
-
- Minimizer::Options options_;
-};
-
-} // namespace internal
-} // namespace ceres
-#endif // CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.cc
deleted file mode 100644
index 22ea1ec8c80..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.cc
+++ /dev/null
@@ -1,358 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/trust_region_preprocessor.h"
-
-#include <numeric>
-#include <string>
-#include "ceres/callbacks.h"
-#include "ceres/evaluator.h"
-#include "ceres/linear_solver.h"
-#include "ceres/minimizer.h"
-#include "ceres/parameter_block.h"
-#include "ceres/preconditioner.h"
-#include "ceres/preprocessor.h"
-#include "ceres/problem_impl.h"
-#include "ceres/program.h"
-#include "ceres/reorder_program.h"
-#include "ceres/suitesparse.h"
-#include "ceres/trust_region_strategy.h"
-#include "ceres/wall_time.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-ParameterBlockOrdering* CreateDefaultLinearSolverOrdering(
- const Program& program) {
- ParameterBlockOrdering* ordering = new ParameterBlockOrdering;
- const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
- for (int i = 0; i < parameter_blocks.size(); ++i) {
- ordering->AddElementToGroup(
- const_cast<double*>(parameter_blocks[i]->user_state()), 0);
- }
- return ordering;
-}
-
-// Check if all the user supplied values in the parameter blocks are
-// sane or not, and if the program is feasible or not.
-bool IsProgramValid(const Program& program, string* error) {
- return (program.ParameterBlocksAreFinite(error) &&
- program.IsFeasible(error));
-}
-
-void AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
- Solver::Options* options) {
- if (!IsSchurType(options->linear_solver_type)) {
- return;
- }
-
- const LinearSolverType linear_solver_type_given = options->linear_solver_type;
- const PreconditionerType preconditioner_type_given =
- options->preconditioner_type;
- options->linear_solver_type = LinearSolver::LinearSolverForZeroEBlocks(
- linear_solver_type_given);
-
- string message;
- if (linear_solver_type_given == ITERATIVE_SCHUR) {
- options->preconditioner_type = Preconditioner::PreconditionerForZeroEBlocks(
- preconditioner_type_given);
-
- message =
- StringPrintf(
- "No E blocks. Switching from %s(%s) to %s(%s).",
- LinearSolverTypeToString(linear_solver_type_given),
- PreconditionerTypeToString(preconditioner_type_given),
- LinearSolverTypeToString(options->linear_solver_type),
- PreconditionerTypeToString(options->preconditioner_type));
- } else {
- message =
- StringPrintf(
- "No E blocks. Switching from %s to %s.",
- LinearSolverTypeToString(linear_solver_type_given),
- LinearSolverTypeToString(options->linear_solver_type));
- }
-
- VLOG_IF(1, options->logging_type != SILENT) << message;
-}
-
-// For Schur type and SPARSE_NORMAL_CHOLESKY linear solvers, reorder
-// the program to reduce fill-in and increase cache coherency.
-bool ReorderProgram(PreprocessedProblem* pp) {
- Solver::Options& options = pp->options;
- if (IsSchurType(options.linear_solver_type)) {
- return ReorderProgramForSchurTypeLinearSolver(
- options.linear_solver_type,
- options.sparse_linear_algebra_library_type,
- pp->problem->parameter_map(),
- options.linear_solver_ordering.get(),
- pp->reduced_program.get(),
- &pp->error);
- }
-
- if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY &&
- !options.dynamic_sparsity) {
- return ReorderProgramForSparseNormalCholesky(
- options.sparse_linear_algebra_library_type,
- *options.linear_solver_ordering,
- pp->reduced_program.get(),
- &pp->error);
- }
-
- return true;
-}
-
-// Configure and create a linear solver object. In doing so, if a
-// sparse direct factorization based linear solver is being used, then
-// find a fill reducing ordering and reorder the program as needed
-// too.
-bool SetupLinearSolver(PreprocessedProblem* pp) {
- Solver::Options& options = pp->options;
- if (options.linear_solver_ordering.get() == NULL) {
- // If the user has not supplied a linear solver ordering, then we
- // assume that they are giving all the freedom to us in choosing
- // the best possible ordering. This intent can be indicated by
- // putting all the parameter blocks in the same elimination group.
- options.linear_solver_ordering.reset(
- CreateDefaultLinearSolverOrdering(*pp->reduced_program));
- } else {
- // If the user supplied an ordering, then check if the first
- // elimination group is still non-empty after the reduced problem
- // has been constructed.
- //
- // This is important for Schur type linear solvers, where the
- // first elimination group is special -- it needs to be an
- // independent set.
- //
- // If the first elimination group is empty, then we cannot use the
- // user's requested linear solver (and a preconditioner as the
- // case may be) so we must use a different one.
- ParameterBlockOrdering* ordering = options.linear_solver_ordering.get();
- const int min_group_id = ordering->MinNonZeroGroup();
- ordering->Remove(pp->removed_parameter_blocks);
- if (IsSchurType(options.linear_solver_type) &&
- min_group_id != ordering->MinNonZeroGroup()) {
- AlternateLinearSolverAndPreconditionerForSchurTypeLinearSolver(
- &options);
- }
- }
-
- // Reorder the program to reduce fill in and improve cache coherency
- // of the Jacobian.
- if (!ReorderProgram(pp)) {
- return false;
- }
-
- // Configure the linear solver.
- pp->linear_solver_options = LinearSolver::Options();
- pp->linear_solver_options.min_num_iterations =
- options.min_linear_solver_iterations;
- pp->linear_solver_options.max_num_iterations =
- options.max_linear_solver_iterations;
- pp->linear_solver_options.type = options.linear_solver_type;
- pp->linear_solver_options.preconditioner_type = options.preconditioner_type;
- pp->linear_solver_options.visibility_clustering_type =
- options.visibility_clustering_type;
- pp->linear_solver_options.sparse_linear_algebra_library_type =
- options.sparse_linear_algebra_library_type;
- pp->linear_solver_options.dense_linear_algebra_library_type =
- options.dense_linear_algebra_library_type;
- pp->linear_solver_options.use_explicit_schur_complement =
- options.use_explicit_schur_complement;
- pp->linear_solver_options.dynamic_sparsity = options.dynamic_sparsity;
- pp->linear_solver_options.num_threads = options.num_linear_solver_threads;
-
- // Ignore user's postordering preferences and force it to be true if
- // cholmod_camd is not available. This ensures that the linear
- // solver does not assume that a fill-reducing pre-ordering has been
- // done.
- pp->linear_solver_options.use_postordering = options.use_postordering;
- if (options.linear_solver_type == SPARSE_SCHUR &&
- options.sparse_linear_algebra_library_type == SUITE_SPARSE &&
- !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
- pp->linear_solver_options.use_postordering = true;
- }
-
- OrderingToGroupSizes(options.linear_solver_ordering.get(),
- &pp->linear_solver_options.elimination_groups);
-
- // Schur type solvers expect at least two elimination groups. If
- // there is only one elimination group, then it is guaranteed that
- // this group only contains e_blocks. Thus we add a dummy
- // elimination group with zero blocks in it.
- if (IsSchurType(pp->linear_solver_options.type) &&
- pp->linear_solver_options.elimination_groups.size() == 1) {
- pp->linear_solver_options.elimination_groups.push_back(0);
- }
-
- pp->linear_solver.reset(LinearSolver::Create(pp->linear_solver_options));
- return (pp->linear_solver.get() != NULL);
-}
-
-// Configure and create the evaluator.
-bool SetupEvaluator(PreprocessedProblem* pp) {
- const Solver::Options& options = pp->options;
- pp->evaluator_options = Evaluator::Options();
- pp->evaluator_options.linear_solver_type = options.linear_solver_type;
- pp->evaluator_options.num_eliminate_blocks = 0;
- if (IsSchurType(options.linear_solver_type)) {
- pp->evaluator_options.num_eliminate_blocks =
- options
- .linear_solver_ordering
- ->group_to_elements().begin()
- ->second.size();
- }
-
- pp->evaluator_options.num_threads = options.num_threads;
- pp->evaluator_options.dynamic_sparsity = options.dynamic_sparsity;
- pp->evaluator.reset(Evaluator::Create(pp->evaluator_options,
- pp->reduced_program.get(),
- &pp->error));
-
- return (pp->evaluator.get() != NULL);
-}
-
-// If the user requested inner iterations, then find an inner
-// iteration ordering as needed and configure and create a
-// CoordinateDescentMinimizer object to perform the inner iterations.
-bool SetupInnerIterationMinimizer(PreprocessedProblem* pp) {
- Solver::Options& options = pp->options;
- if (!options.use_inner_iterations) {
- return true;
- }
-
- // With just one parameter block, the outer iteration of the trust
- // region method and inner iterations are doing exactly the same
- // thing, and thus inner iterations are not needed.
- if (pp->reduced_program->NumParameterBlocks() == 1) {
- LOG(WARNING) << "Reduced problem only contains one parameter block."
- << "Disabling inner iterations.";
- return true;
- }
-
- if (options.inner_iteration_ordering.get() != NULL) {
- // If the user supplied an ordering, then remove the set of
- // inactive parameter blocks from it
- options.inner_iteration_ordering->Remove(pp->removed_parameter_blocks);
- if (options.inner_iteration_ordering->NumElements() == 0) {
- LOG(WARNING) << "No remaining elements in the inner iteration ordering.";
- return true;
- }
-
- // Validate the reduced ordering.
- if (!CoordinateDescentMinimizer::IsOrderingValid(
- *pp->reduced_program,
- *options.inner_iteration_ordering,
- &pp->error)) {
- return false;
- }
- } else {
- // The user did not supply an ordering, so create one.
- options.inner_iteration_ordering.reset(
- CoordinateDescentMinimizer::CreateOrdering(*pp->reduced_program));
- }
-
- pp->inner_iteration_minimizer.reset(new CoordinateDescentMinimizer);
- return pp->inner_iteration_minimizer->Init(*pp->reduced_program,
- pp->problem->parameter_map(),
- *options.inner_iteration_ordering,
- &pp->error);
-}
-
-// Configure and create a TrustRegionMinimizer object.
-void SetupMinimizerOptions(PreprocessedProblem* pp) {
- const Solver::Options& options = pp->options;
-
- SetupCommonMinimizerOptions(pp);
- pp->minimizer_options.is_constrained =
- pp->reduced_program->IsBoundsConstrained();
- pp->minimizer_options.jacobian.reset(pp->evaluator->CreateJacobian());
- pp->minimizer_options.inner_iteration_minimizer =
- pp->inner_iteration_minimizer;
-
- TrustRegionStrategy::Options strategy_options;
- strategy_options.linear_solver = pp->linear_solver.get();
- strategy_options.initial_radius =
- options.initial_trust_region_radius;
- strategy_options.max_radius = options.max_trust_region_radius;
- strategy_options.min_lm_diagonal = options.min_lm_diagonal;
- strategy_options.max_lm_diagonal = options.max_lm_diagonal;
- strategy_options.trust_region_strategy_type =
- options.trust_region_strategy_type;
- strategy_options.dogleg_type = options.dogleg_type;
- pp->minimizer_options.trust_region_strategy.reset(
- CHECK_NOTNULL(TrustRegionStrategy::Create(strategy_options)));
-}
-
-} // namespace
-
-TrustRegionPreprocessor::~TrustRegionPreprocessor() {
-}
-
-bool TrustRegionPreprocessor::Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* pp) {
- CHECK_NOTNULL(pp);
- pp->options = options;
- ChangeNumThreadsIfNeeded(&pp->options);
-
- pp->problem = problem;
- Program* program = problem->mutable_program();
- if (!IsProgramValid(*program, &pp->error)) {
- return false;
- }
-
- pp->reduced_program.reset(
- program->CreateReducedProgram(&pp->removed_parameter_blocks,
- &pp->fixed_cost,
- &pp->error));
-
- if (pp->reduced_program.get() == NULL) {
- return false;
- }
-
- if (pp->reduced_program->NumParameterBlocks() == 0) {
- // The reduced problem has no parameter or residual blocks. There
- // is nothing more to do.
- return true;
- }
-
- if (!SetupLinearSolver(pp) ||
- !SetupEvaluator(pp) ||
- !SetupInnerIterationMinimizer(pp)) {
- return false;
- }
-
- SetupMinimizerOptions(pp);
- return true;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.h
deleted file mode 100644
index ba70ff92e73..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_preprocessor.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2014 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
-#define CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
-
-#include "ceres/preprocessor.h"
-
-namespace ceres {
-namespace internal {
-
-class TrustRegionPreprocessor : public Preprocessor {
- public:
- virtual ~TrustRegionPreprocessor();
- virtual bool Preprocess(const Solver::Options& options,
- ProblemImpl* problem,
- PreprocessedProblem* preprocessed_problem);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
deleted file mode 100644
index c68269d0449..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012, 2013 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-// keir@google.com (Keir Mierle)
-
-#include "ceres/trust_region_strategy.h"
-#include "ceres/dogleg_strategy.h"
-#include "ceres/levenberg_marquardt_strategy.h"
-
-namespace ceres {
-namespace internal {
-
-TrustRegionStrategy::~TrustRegionStrategy() {}
-
-TrustRegionStrategy* TrustRegionStrategy::Create(const Options& options) {
- switch (options.trust_region_strategy_type) {
- case LEVENBERG_MARQUARDT:
- return new LevenbergMarquardtStrategy(options);
- case DOGLEG:
- return new DoglegStrategy(options);
- default:
- LOG(FATAL) << "Unknown trust region strategy: "
- << options.trust_region_strategy_type;
- }
-
- LOG(FATAL) << "Unknown trust region strategy: "
- << options.trust_region_strategy_type;
- return NULL;
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
deleted file mode 100644
index 998514fbfa5..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
+++ /dev/null
@@ -1,164 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
-#define CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
-
-#include <string>
-#include "ceres/internal/port.h"
-#include "ceres/linear_solver.h"
-
-namespace ceres {
-namespace internal {
-
-class LinearSolver;
-class SparseMatrix;
-
-// Interface for classes implementing various trust region strategies
-// for nonlinear least squares problems.
-//
-// The object is expected to maintain and update a trust region
-// radius, which it then uses to solve for the trust region step using
-// the jacobian matrix and residual vector.
-//
-// Here the term trust region radius is used loosely, as the strategy
-// is free to treat it as guidance and violate it as need be. e.g.,
-// the LevenbergMarquardtStrategy uses the inverse of the trust region
-// radius to scale the damping term, which controls the step size, but
-// does not set a hard limit on its size.
-class TrustRegionStrategy {
- public:
- struct Options {
- Options()
- : trust_region_strategy_type(LEVENBERG_MARQUARDT),
- initial_radius(1e4),
- max_radius(1e32),
- min_lm_diagonal(1e-6),
- max_lm_diagonal(1e32),
- dogleg_type(TRADITIONAL_DOGLEG) {
- }
-
- TrustRegionStrategyType trust_region_strategy_type;
- // Linear solver used for actually solving the trust region step.
- LinearSolver* linear_solver;
- double initial_radius;
- double max_radius;
-
- // Minimum and maximum values of the diagonal damping matrix used
- // by LevenbergMarquardtStrategy. The DoglegStrategy also uses
- // these bounds to construct a regularizing diagonal to ensure
- // that the Gauss-Newton step computation is of full rank.
- double min_lm_diagonal;
- double max_lm_diagonal;
-
- // Further specify which dogleg method to use
- DoglegType dogleg_type;
- };
-
- // Per solve options.
- struct PerSolveOptions {
- PerSolveOptions()
- : eta(0),
- dump_filename_base(""),
- dump_format_type(TEXTFILE) {
- }
-
- // Forcing sequence for inexact solves.
- double eta;
-
- // If non-empty and dump_format_type is not CONSOLE, the trust
- // regions strategy will write the linear system to file(s) with
- // name starting with dump_filename_base. If dump_format_type is
- // CONSOLE then dump_filename_base will be ignored and the linear
- // system will be written to the standard error.
- string dump_filename_base;
- DumpFormatType dump_format_type;
- };
-
- struct Summary {
- Summary()
- : residual_norm(0.0),
- num_iterations(-1),
- termination_type(LINEAR_SOLVER_FAILURE) {
- }
-
- // If the trust region problem is,
- //
- // 1/2 x'Ax + b'x + c,
- //
- // then
- //
- // residual_norm = |Ax -b|
- double residual_norm;
-
- // Number of iterations used by the linear solver. If a linear
- // solver was not called (e.g., DogLegStrategy after an
- // unsuccessful step), then this would be zero.
- int num_iterations;
-
- // Status of the linear solver used to solve the Newton system.
- LinearSolverTerminationType termination_type;
- };
-
- virtual ~TrustRegionStrategy();
-
- // Use the current radius to solve for the trust region step.
- virtual Summary ComputeStep(const PerSolveOptions& per_solve_options,
- SparseMatrix* jacobian,
- const double* residuals,
- double* step) = 0;
-
- // Inform the strategy that the current step has been accepted, and
- // that the ratio of the decrease in the non-linear objective to the
- // decrease in the trust region model is step_quality.
- virtual void StepAccepted(double step_quality) = 0;
-
- // Inform the strategy that the current step has been rejected, and
- // that the ratio of the decrease in the non-linear objective to the
- // decrease in the trust region model is step_quality.
- virtual void StepRejected(double step_quality) = 0;
-
- // Inform the strategy that the current step has been rejected
- // because it was found to be numerically invalid.
- // StepRejected/StepAccepted will not be called for this step, and
- // the strategy is free to do what it wants with this information.
- virtual void StepIsInvalid() = 0;
-
- // Current trust region radius.
- virtual double Radius() const = 0;
-
- // Factory.
- static TrustRegionStrategy* Create(const Options& options);
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/types.cc b/extern/libmv/third_party/ceres/internal/ceres/types.cc
deleted file mode 100644
index 47102616ee8..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/types.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include <algorithm>
-#include <cctype>
-#include <string>
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-#define CASESTR(x) case x: return #x
-#define STRENUM(x) if (value == #x) { *type = x; return true;}
-
-static void UpperCase(string* input) {
- std::transform(input->begin(), input->end(), input->begin(), ::toupper);
-}
-
-const char* LinearSolverTypeToString(LinearSolverType type) {
- switch (type) {
- CASESTR(DENSE_NORMAL_CHOLESKY);
- CASESTR(DENSE_QR);
- CASESTR(SPARSE_NORMAL_CHOLESKY);
- CASESTR(DENSE_SCHUR);
- CASESTR(SPARSE_SCHUR);
- CASESTR(ITERATIVE_SCHUR);
- CASESTR(CGNR);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToLinearSolverType(string value, LinearSolverType* type) {
- UpperCase(&value);
- STRENUM(DENSE_NORMAL_CHOLESKY);
- STRENUM(DENSE_QR);
- STRENUM(SPARSE_NORMAL_CHOLESKY);
- STRENUM(DENSE_SCHUR);
- STRENUM(SPARSE_SCHUR);
- STRENUM(ITERATIVE_SCHUR);
- STRENUM(CGNR);
- return false;
-}
-
-const char* PreconditionerTypeToString(PreconditionerType type) {
- switch (type) {
- CASESTR(IDENTITY);
- CASESTR(JACOBI);
- CASESTR(SCHUR_JACOBI);
- CASESTR(CLUSTER_JACOBI);
- CASESTR(CLUSTER_TRIDIAGONAL);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToPreconditionerType(string value, PreconditionerType* type) {
- UpperCase(&value);
- STRENUM(IDENTITY);
- STRENUM(JACOBI);
- STRENUM(SCHUR_JACOBI);
- STRENUM(CLUSTER_JACOBI);
- STRENUM(CLUSTER_TRIDIAGONAL);
- return false;
-}
-
-const char* SparseLinearAlgebraLibraryTypeToString(
- SparseLinearAlgebraLibraryType type) {
- switch (type) {
- CASESTR(SUITE_SPARSE);
- CASESTR(CX_SPARSE);
- CASESTR(EIGEN_SPARSE);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToSparseLinearAlgebraLibraryType(
- string value,
- SparseLinearAlgebraLibraryType* type) {
- UpperCase(&value);
- STRENUM(SUITE_SPARSE);
- STRENUM(CX_SPARSE);
- STRENUM(EIGEN_SPARSE);
- return false;
-}
-
-const char* DenseLinearAlgebraLibraryTypeToString(
- DenseLinearAlgebraLibraryType type) {
- switch (type) {
- CASESTR(EIGEN);
- CASESTR(LAPACK);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToDenseLinearAlgebraLibraryType(
- string value,
- DenseLinearAlgebraLibraryType* type) {
- UpperCase(&value);
- STRENUM(EIGEN);
- STRENUM(LAPACK);
- return false;
-}
-
-const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type) {
- switch (type) {
- CASESTR(LEVENBERG_MARQUARDT);
- CASESTR(DOGLEG);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToTrustRegionStrategyType(string value,
- TrustRegionStrategyType* type) {
- UpperCase(&value);
- STRENUM(LEVENBERG_MARQUARDT);
- STRENUM(DOGLEG);
- return false;
-}
-
-const char* DoglegTypeToString(DoglegType type) {
- switch (type) {
- CASESTR(TRADITIONAL_DOGLEG);
- CASESTR(SUBSPACE_DOGLEG);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToDoglegType(string value, DoglegType* type) {
- UpperCase(&value);
- STRENUM(TRADITIONAL_DOGLEG);
- STRENUM(SUBSPACE_DOGLEG);
- return false;
-}
-
-const char* MinimizerTypeToString(MinimizerType type) {
- switch (type) {
- CASESTR(TRUST_REGION);
- CASESTR(LINE_SEARCH);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToMinimizerType(string value, MinimizerType* type) {
- UpperCase(&value);
- STRENUM(TRUST_REGION);
- STRENUM(LINE_SEARCH);
- return false;
-}
-
-const char* LineSearchDirectionTypeToString(LineSearchDirectionType type) {
- switch (type) {
- CASESTR(STEEPEST_DESCENT);
- CASESTR(NONLINEAR_CONJUGATE_GRADIENT);
- CASESTR(LBFGS);
- CASESTR(BFGS);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToLineSearchDirectionType(string value,
- LineSearchDirectionType* type) {
- UpperCase(&value);
- STRENUM(STEEPEST_DESCENT);
- STRENUM(NONLINEAR_CONJUGATE_GRADIENT);
- STRENUM(LBFGS);
- STRENUM(BFGS);
- return false;
-}
-
-const char* LineSearchTypeToString(LineSearchType type) {
- switch (type) {
- CASESTR(ARMIJO);
- CASESTR(WOLFE);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToLineSearchType(string value, LineSearchType* type) {
- UpperCase(&value);
- STRENUM(ARMIJO);
- STRENUM(WOLFE);
- return false;
-}
-
-const char* LineSearchInterpolationTypeToString(
- LineSearchInterpolationType type) {
- switch (type) {
- CASESTR(BISECTION);
- CASESTR(QUADRATIC);
- CASESTR(CUBIC);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToLineSearchInterpolationType(
- string value,
- LineSearchInterpolationType* type) {
- UpperCase(&value);
- STRENUM(BISECTION);
- STRENUM(QUADRATIC);
- STRENUM(CUBIC);
- return false;
-}
-
-const char* NonlinearConjugateGradientTypeToString(
- NonlinearConjugateGradientType type) {
- switch (type) {
- CASESTR(FLETCHER_REEVES);
- CASESTR(POLAK_RIBIERE);
- CASESTR(HESTENES_STIEFEL);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToNonlinearConjugateGradientType(
- string value,
- NonlinearConjugateGradientType* type) {
- UpperCase(&value);
- STRENUM(FLETCHER_REEVES);
- STRENUM(POLAK_RIBIERE);
- STRENUM(HESTENES_STIEFEL);
- return false;
-}
-
-const char* CovarianceAlgorithmTypeToString(
- CovarianceAlgorithmType type) {
- switch (type) {
- CASESTR(DENSE_SVD);
- CASESTR(EIGEN_SPARSE_QR);
- CASESTR(SUITE_SPARSE_QR);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToCovarianceAlgorithmType(
- string value,
- CovarianceAlgorithmType* type) {
- UpperCase(&value);
- STRENUM(DENSE_SVD);
- STRENUM(EIGEN_SPARSE_QR);
- STRENUM(SUITE_SPARSE_QR);
- return false;
-}
-
-const char* VisibilityClusteringTypeToString(
- VisibilityClusteringType type) {
- switch (type) {
- CASESTR(CANONICAL_VIEWS);
- CASESTR(SINGLE_LINKAGE);
- default:
- return "UNKNOWN";
- }
-}
-
-bool StringToVisibilityClusteringType(
- string value,
- VisibilityClusteringType* type) {
- UpperCase(&value);
- STRENUM(CANONICAL_VIEWS);
- STRENUM(SINGLE_LINKAGE);
- return false;
-}
-
-const char* TerminationTypeToString(TerminationType type) {
- switch (type) {
- CASESTR(CONVERGENCE);
- CASESTR(NO_CONVERGENCE);
- CASESTR(FAILURE);
- CASESTR(USER_SUCCESS);
- CASESTR(USER_FAILURE);
- default:
- return "UNKNOWN";
- }
-}
-
-#undef CASESTR
-#undef STRENUM
-
-bool IsSchurType(LinearSolverType type) {
- return ((type == SPARSE_SCHUR) ||
- (type == DENSE_SCHUR) ||
- (type == ITERATIVE_SCHUR));
-}
-
-bool IsSparseLinearAlgebraLibraryTypeAvailable(
- SparseLinearAlgebraLibraryType type) {
- if (type == SUITE_SPARSE) {
-#ifdef CERES_NO_SUITESPARSE
- return false;
-#else
- return true;
-#endif
- }
-
- if (type == CX_SPARSE) {
-#ifdef CERES_NO_CXSPARSE
- return false;
-#else
- return true;
-#endif
- }
-
- LOG(WARNING) << "Unknown sparse linear algebra library " << type;
- return false;
-}
-
-bool IsDenseLinearAlgebraLibraryTypeAvailable(
- DenseLinearAlgebraLibraryType type) {
- if (type == EIGEN) {
- return true;
- }
- if (type == LAPACK) {
-#ifdef CERES_NO_LAPACK
- return false;
-#else
- return true;
-#endif
- }
-
- LOG(WARNING) << "Unknown dense linear algebra library " << type;
- return false;
-}
-
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
deleted file mode 100644
index da8beedc663..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: kushalav@google.com (Avanish Kushal)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include "ceres/visibility.h"
-
-#include <cmath>
-#include <ctime>
-#include <algorithm>
-#include <set>
-#include <vector>
-#include <utility>
-#include "ceres/block_structure.h"
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-void ComputeVisibility(const CompressedRowBlockStructure& block_structure,
- const int num_eliminate_blocks,
- vector< set<int> >* visibility) {
- CHECK_NOTNULL(visibility);
-
- // Clear the visibility vector and resize it to hold a
- // vector for each camera.
- visibility->resize(0);
- visibility->resize(block_structure.cols.size() - num_eliminate_blocks);
-
- for (int i = 0; i < block_structure.rows.size(); ++i) {
- const vector<Cell>& cells = block_structure.rows[i].cells;
- int block_id = cells[0].block_id;
- // If the first block is not an e_block, then skip this row block.
- if (block_id >= num_eliminate_blocks) {
- continue;
- }
-
- for (int j = 1; j < cells.size(); ++j) {
- int camera_block_id = cells[j].block_id - num_eliminate_blocks;
- DCHECK_GE(camera_block_id, 0);
- DCHECK_LT(camera_block_id, visibility->size());
- (*visibility)[camera_block_id].insert(block_id);
- }
- }
-}
-
-WeightedGraph<int>* CreateSchurComplementGraph(
- const vector<set<int> >& visibility) {
- const time_t start_time = time(NULL);
- // Compute the number of e_blocks/point blocks. Since the visibility
- // set for each e_block/camera contains the set of e_blocks/points
- // visible to it, we find the maximum across all visibility sets.
- int num_points = 0;
- for (int i = 0; i < visibility.size(); i++) {
- if (visibility[i].size() > 0) {
- num_points = max(num_points, (*visibility[i].rbegin()) + 1);
- }
- }
-
- // Invert the visibility. The input is a camera->point mapping,
- // which tells us which points are visible in which
- // cameras. However, to compute the sparsity structure of the Schur
- // Complement efficiently, its better to have the point->camera
- // mapping.
- vector<set<int> > inverse_visibility(num_points);
- for (int i = 0; i < visibility.size(); i++) {
- const set<int>& visibility_set = visibility[i];
- for (set<int>::const_iterator it = visibility_set.begin();
- it != visibility_set.end();
- ++it) {
- inverse_visibility[*it].insert(i);
- }
- }
-
- // Map from camera pairs to number of points visible to both cameras
- // in the pair.
- HashMap<pair<int, int>, int > camera_pairs;
-
- // Count the number of points visible to each camera/f_block pair.
- for (vector<set<int> >::const_iterator it = inverse_visibility.begin();
- it != inverse_visibility.end();
- ++it) {
- const set<int>& inverse_visibility_set = *it;
- for (set<int>::const_iterator camera1 = inverse_visibility_set.begin();
- camera1 != inverse_visibility_set.end();
- ++camera1) {
- set<int>::const_iterator camera2 = camera1;
- for (++camera2; camera2 != inverse_visibility_set.end(); ++camera2) {
- ++(camera_pairs[make_pair(*camera1, *camera2)]);
- }
- }
- }
-
- WeightedGraph<int>* graph = new WeightedGraph<int>;
-
- // Add vertices and initialize the pairs for self edges so that self
- // edges are guaranteed. This is needed for the Canonical views
- // algorithm to work correctly.
- static const double kSelfEdgeWeight = 1.0;
- for (int i = 0; i < visibility.size(); ++i) {
- graph->AddVertex(i);
- graph->AddEdge(i, i, kSelfEdgeWeight);
- }
-
- // Add an edge for each camera pair.
- for (HashMap<pair<int, int>, int>::const_iterator it = camera_pairs.begin();
- it != camera_pairs.end();
- ++it) {
- const int camera1 = it->first.first;
- const int camera2 = it->first.second;
- CHECK_NE(camera1, camera2);
-
- const int count = it->second;
- // Static cast necessary for Windows.
- const double weight = static_cast<double>(count) /
- (sqrt(static_cast<double>(
- visibility[camera1].size() * visibility[camera2].size())));
- graph->AddEdge(camera1, camera2, weight);
- }
-
- VLOG(2) << "Schur complement graph time: " << (time(NULL) - start_time);
- return graph;
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.h b/extern/libmv/third_party/ceres/internal/ceres/visibility.h
deleted file mode 100644
index 322efe9bea4..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: kushalav@google.com (Avanish Kushal)
-// sameeragarwal@google.com (Sameer Agarwal)
-//
-// Functions to manipulate visibility information from the block
-// structure of sparse matrices.
-
-#ifndef CERES_INTERNAL_VISIBILITY_H_
-#define CERES_INTERNAL_VISIBILITY_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include <set>
-#include <vector>
-#include "ceres/graph.h"
-
-namespace ceres {
-namespace internal {
-
-struct CompressedRowBlockStructure;
-
-// Given a compressed row block structure, computes the set of
-// e_blocks "visible" to each f_block. If an e_block co-occurs with an
-// f_block in a residual block, it is visible to the f_block. The
-// first num_eliminate_blocks columns blocks are e_blocks and the rest
-// f_blocks.
-//
-// In a structure from motion problem, e_blocks correspond to 3D
-// points and f_blocks correspond to cameras.
-void ComputeVisibility(const CompressedRowBlockStructure& block_structure,
- int num_eliminate_blocks,
- vector<set<int> >* visibility);
-
-// Given f_block visibility as computed by the ComputeVisibility
-// function above, construct and return a graph whose vertices are
-// f_blocks and an edge connects two vertices if they have atleast one
-// e_block in common. The weight of this edge is normalized dot
-// product between the visibility vectors of the two
-// vertices/f_blocks.
-//
-// This graph reflects the sparsity structure of reduced camera
-// matrix/Schur complement matrix obtained by eliminating the e_blocks
-// from the normal equations.
-//
-// Caller acquires ownership of the returned WeightedGraph pointer
-// (heap-allocated).
-WeightedGraph<int>* CreateSchurComplementGraph(
- const vector<set<int> >& visibility);
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
-#endif // CERES_INTERNAL_VISIBILITY_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
deleted file mode 100644
index c7ed0493d8c..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
+++ /dev/null
@@ -1,625 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_SUITESPARSE
-
-#include "ceres/visibility_based_preconditioner.h"
-
-#include <algorithm>
-#include <functional>
-#include <iterator>
-#include <set>
-#include <utility>
-#include <vector>
-#include "Eigen/Dense"
-#include "ceres/block_random_access_sparse_matrix.h"
-#include "ceres/block_sparse_matrix.h"
-#include "ceres/canonical_views_clustering.h"
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-#include "ceres/graph_algorithms.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-#include "ceres/schur_eliminator.h"
-#include "ceres/single_linkage_clustering.h"
-#include "ceres/visibility.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// TODO(sameeragarwal): Currently these are magic weights for the
-// preconditioner construction. Move these higher up into the Options
-// struct and provide some guidelines for choosing them.
-//
-// This will require some more work on the clustering algorithm and
-// possibly some more refactoring of the code.
-static const double kCanonicalViewsSizePenaltyWeight = 3.0;
-static const double kCanonicalViewsSimilarityPenaltyWeight = 0.0;
-static const double kSingleLinkageMinSimilarity = 0.9;
-
-VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
- const CompressedRowBlockStructure& bs,
- const Preconditioner::Options& options)
- : options_(options),
- num_blocks_(0),
- num_clusters_(0),
- factor_(NULL) {
- CHECK_GT(options_.elimination_groups.size(), 1);
- CHECK_GT(options_.elimination_groups[0], 0);
- CHECK(options_.type == CLUSTER_JACOBI ||
- options_.type == CLUSTER_TRIDIAGONAL)
- << "Unknown preconditioner type: " << options_.type;
- num_blocks_ = bs.cols.size() - options_.elimination_groups[0];
- CHECK_GT(num_blocks_, 0)
- << "Jacobian should have atleast 1 f_block for "
- << "visibility based preconditioning.";
-
- // Vector of camera block sizes
- block_size_.resize(num_blocks_);
- for (int i = 0; i < num_blocks_; ++i) {
- block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
- }
-
- const time_t start_time = time(NULL);
- switch (options_.type) {
- case CLUSTER_JACOBI:
- ComputeClusterJacobiSparsity(bs);
- break;
- case CLUSTER_TRIDIAGONAL:
- ComputeClusterTridiagonalSparsity(bs);
- break;
- default:
- LOG(FATAL) << "Unknown preconditioner type";
- }
- const time_t structure_time = time(NULL);
- InitStorage(bs);
- const time_t storage_time = time(NULL);
- InitEliminator(bs);
- const time_t eliminator_time = time(NULL);
-
- // Allocate temporary storage for a vector used during
- // RightMultiply.
- tmp_rhs_ = CHECK_NOTNULL(ss_.CreateDenseVector(NULL,
- m_->num_rows(),
- m_->num_rows()));
- const time_t init_time = time(NULL);
- VLOG(2) << "init time: "
- << init_time - start_time
- << " structure time: " << structure_time - start_time
- << " storage time:" << storage_time - structure_time
- << " eliminator time: " << eliminator_time - storage_time;
-}
-
-VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() {
- if (factor_ != NULL) {
- ss_.Free(factor_);
- factor_ = NULL;
- }
- if (tmp_rhs_ != NULL) {
- ss_.Free(tmp_rhs_);
- tmp_rhs_ = NULL;
- }
-}
-
-// Determine the sparsity structure of the CLUSTER_JACOBI
-// preconditioner. It clusters cameras using their scene
-// visibility. The clusters form the diagonal blocks of the
-// preconditioner matrix.
-void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
- const CompressedRowBlockStructure& bs) {
- vector<set<int> > visibility;
- ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
- CHECK_EQ(num_blocks_, visibility.size());
- ClusterCameras(visibility);
- cluster_pairs_.clear();
- for (int i = 0; i < num_clusters_; ++i) {
- cluster_pairs_.insert(make_pair(i, i));
- }
-}
-
-// Determine the sparsity structure of the CLUSTER_TRIDIAGONAL
-// preconditioner. It clusters cameras using using the scene
-// visibility and then finds the strongly interacting pairs of
-// clusters by constructing another graph with the clusters as
-// vertices and approximating it with a degree-2 maximum spanning
-// forest. The set of edges in this forest are the cluster pairs.
-void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity(
- const CompressedRowBlockStructure& bs) {
- vector<set<int> > visibility;
- ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
- CHECK_EQ(num_blocks_, visibility.size());
- ClusterCameras(visibility);
-
- // Construct a weighted graph on the set of clusters, where the
- // edges are the number of 3D points/e_blocks visible in both the
- // clusters at the ends of the edge. Return an approximate degree-2
- // maximum spanning forest of this graph.
- vector<set<int> > cluster_visibility;
- ComputeClusterVisibility(visibility, &cluster_visibility);
- scoped_ptr<WeightedGraph<int> > cluster_graph(
- CHECK_NOTNULL(CreateClusterGraph(cluster_visibility)));
- scoped_ptr<WeightedGraph<int> > forest(
- CHECK_NOTNULL(Degree2MaximumSpanningForest(*cluster_graph)));
- ForestToClusterPairs(*forest, &cluster_pairs_);
-}
-
-// Allocate storage for the preconditioner matrix.
-void VisibilityBasedPreconditioner::InitStorage(
- const CompressedRowBlockStructure& bs) {
- ComputeBlockPairsInPreconditioner(bs);
- m_.reset(new BlockRandomAccessSparseMatrix(block_size_, block_pairs_));
-}
-
-// Call the canonical views algorithm and cluster the cameras based on
-// their visibility sets. The visibility set of a camera is the set of
-// e_blocks/3D points in the scene that are seen by it.
-//
-// The cluster_membership_ vector is updated to indicate cluster
-// memberships for each camera block.
-void VisibilityBasedPreconditioner::ClusterCameras(
- const vector<set<int> >& visibility) {
- scoped_ptr<WeightedGraph<int> > schur_complement_graph(
- CHECK_NOTNULL(CreateSchurComplementGraph(visibility)));
-
- HashMap<int, int> membership;
-
- if (options_.visibility_clustering_type == CANONICAL_VIEWS) {
- vector<int> centers;
- CanonicalViewsClusteringOptions clustering_options;
- clustering_options.size_penalty_weight =
- kCanonicalViewsSizePenaltyWeight;
- clustering_options.similarity_penalty_weight =
- kCanonicalViewsSimilarityPenaltyWeight;
- ComputeCanonicalViewsClustering(clustering_options,
- *schur_complement_graph,
- &centers,
- &membership);
- num_clusters_ = centers.size();
- } else if (options_.visibility_clustering_type == SINGLE_LINKAGE) {
- SingleLinkageClusteringOptions clustering_options;
- clustering_options.min_similarity =
- kSingleLinkageMinSimilarity;
- num_clusters_ = ComputeSingleLinkageClustering(clustering_options,
- *schur_complement_graph,
- &membership);
- } else {
- LOG(FATAL) << "Unknown visibility clustering algorithm.";
- }
-
- CHECK_GT(num_clusters_, 0);
- VLOG(2) << "num_clusters: " << num_clusters_;
- FlattenMembershipMap(membership, &cluster_membership_);
-}
-
-// Compute the block sparsity structure of the Schur complement
-// matrix. For each pair of cameras contributing a non-zero cell to
-// the schur complement, determine if that cell is present in the
-// preconditioner or not.
-//
-// A pair of cameras contribute a cell to the preconditioner if they
-// are part of the same cluster or if the the two clusters that they
-// belong have an edge connecting them in the degree-2 maximum
-// spanning forest.
-//
-// For example, a camera pair (i,j) where i belonges to cluster1 and
-// j belongs to cluster2 (assume that cluster1 < cluster2).
-//
-// The cell corresponding to (i,j) is present in the preconditioner
-// if cluster1 == cluster2 or the pair (cluster1, cluster2) were
-// connected by an edge in the degree-2 maximum spanning forest.
-//
-// Since we have already expanded the forest into a set of camera
-// pairs/edges, including self edges, the check can be reduced to
-// checking membership of (cluster1, cluster2) in cluster_pairs_.
-void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner(
- const CompressedRowBlockStructure& bs) {
- block_pairs_.clear();
- for (int i = 0; i < num_blocks_; ++i) {
- block_pairs_.insert(make_pair(i, i));
- }
-
- int r = 0;
- const int num_row_blocks = bs.rows.size();
- const int num_eliminate_blocks = options_.elimination_groups[0];
-
- // Iterate over each row of the matrix. The block structure of the
- // matrix is assumed to be sorted in order of the e_blocks/point
- // blocks. Thus all row blocks containing an e_block/point occur
- // contiguously. Further, if present, an e_block is always the first
- // parameter block in each row block. These structural assumptions
- // are common to all Schur complement based solvers in Ceres.
- //
- // For each e_block/point block we identify the set of cameras
- // seeing it. The cross product of this set with itself is the set
- // of non-zero cells contibuted by this e_block.
- //
- // The time complexity of this is O(nm^2) where, n is the number of
- // 3d points and m is the maximum number of cameras seeing any
- // point, which for most scenes is a fairly small number.
- while (r < num_row_blocks) {
- int e_block_id = bs.rows[r].cells.front().block_id;
- if (e_block_id >= num_eliminate_blocks) {
- // Skip the rows whose first block is an f_block.
- break;
- }
-
- set<int> f_blocks;
- for (; r < num_row_blocks; ++r) {
- const CompressedRow& row = bs.rows[r];
- if (row.cells.front().block_id != e_block_id) {
- break;
- }
-
- // Iterate over the blocks in the row, ignoring the first block
- // since it is the one to be eliminated and adding the rest to
- // the list of f_blocks associated with this e_block.
- for (int c = 1; c < row.cells.size(); ++c) {
- const Cell& cell = row.cells[c];
- const int f_block_id = cell.block_id - num_eliminate_blocks;
- CHECK_GE(f_block_id, 0);
- f_blocks.insert(f_block_id);
- }
- }
-
- for (set<int>::const_iterator block1 = f_blocks.begin();
- block1 != f_blocks.end();
- ++block1) {
- set<int>::const_iterator block2 = block1;
- ++block2;
- for (; block2 != f_blocks.end(); ++block2) {
- if (IsBlockPairInPreconditioner(*block1, *block2)) {
- block_pairs_.insert(make_pair(*block1, *block2));
- }
- }
- }
- }
-
- // The remaining rows which do not contain any e_blocks.
- for (; r < num_row_blocks; ++r) {
- const CompressedRow& row = bs.rows[r];
- CHECK_GE(row.cells.front().block_id, num_eliminate_blocks);
- for (int i = 0; i < row.cells.size(); ++i) {
- const int block1 = row.cells[i].block_id - num_eliminate_blocks;
- for (int j = 0; j < row.cells.size(); ++j) {
- const int block2 = row.cells[j].block_id - num_eliminate_blocks;
- if (block1 <= block2) {
- if (IsBlockPairInPreconditioner(block1, block2)) {
- block_pairs_.insert(make_pair(block1, block2));
- }
- }
- }
- }
- }
-
- VLOG(1) << "Block pair stats: " << block_pairs_.size();
-}
-
-// Initialize the SchurEliminator.
-void VisibilityBasedPreconditioner::InitEliminator(
- const CompressedRowBlockStructure& bs) {
- LinearSolver::Options eliminator_options;
- eliminator_options.elimination_groups = options_.elimination_groups;
- eliminator_options.num_threads = options_.num_threads;
- eliminator_options.e_block_size = options_.e_block_size;
- eliminator_options.f_block_size = options_.f_block_size;
- eliminator_options.row_block_size = options_.row_block_size;
- eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
- eliminator_->Init(eliminator_options.elimination_groups[0], &bs);
-}
-
-// Update the values of the preconditioner matrix and factorize it.
-bool VisibilityBasedPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
- const double* D) {
- const time_t start_time = time(NULL);
- const int num_rows = m_->num_rows();
- CHECK_GT(num_rows, 0);
-
- // We need a dummy rhs vector and a dummy b vector since the Schur
- // eliminator combines the computation of the reduced camera matrix
- // with the computation of the right hand side of that linear
- // system.
- //
- // TODO(sameeragarwal): Perhaps its worth refactoring the
- // SchurEliminator::Eliminate function to allow NULL for the rhs. As
- // of now it does not seem to be worth the effort.
- Vector rhs = Vector::Zero(m_->num_rows());
- Vector b = Vector::Zero(A.num_rows());
-
- // Compute a subset of the entries of the Schur complement.
- eliminator_->Eliminate(&A, b.data(), D, m_.get(), rhs.data());
-
- // Try factorizing the matrix. For CLUSTER_JACOBI, this should
- // always succeed modulo some numerical/conditioning problems. For
- // CLUSTER_TRIDIAGONAL, in general the preconditioner matrix as
- // constructed is not positive definite. However, we will go ahead
- // and try factorizing it. If it works, great, otherwise we scale
- // all the cells in the preconditioner corresponding to the edges in
- // the degree-2 forest and that guarantees positive
- // definiteness. The proof of this fact can be found in Lemma 1 in
- // "Visibility Based Preconditioning for Bundle Adjustment".
- //
- // Doing the factorization like this saves us matrix mass when
- // scaling is not needed, which is quite often in our experience.
- LinearSolverTerminationType status = Factorize();
-
- if (status == LINEAR_SOLVER_FATAL_ERROR) {
- return false;
- }
-
- // The scaling only affects the tri-diagonal case, since
- // ScaleOffDiagonalBlocks only pays attenion to the cells that
- // belong to the edges of the degree-2 forest. In the CLUSTER_JACOBI
- // case, the preconditioner is guaranteed to be positive
- // semidefinite.
- if (status == LINEAR_SOLVER_FAILURE && options_.type == CLUSTER_TRIDIAGONAL) {
- VLOG(1) << "Unscaled factorization failed. Retrying with off-diagonal "
- << "scaling";
- ScaleOffDiagonalCells();
- status = Factorize();
- }
-
- VLOG(2) << "Compute time: " << time(NULL) - start_time;
- return (status == LINEAR_SOLVER_SUCCESS);
-}
-
-// Consider the preconditioner matrix as meta-block matrix, whose
-// blocks correspond to the clusters. Then cluster pairs corresponding
-// to edges in the degree-2 forest are off diagonal entries of this
-// matrix. Scaling these off-diagonal entries by 1/2 forces this
-// matrix to be positive definite.
-void VisibilityBasedPreconditioner::ScaleOffDiagonalCells() {
- for (set< pair<int, int> >::const_iterator it = block_pairs_.begin();
- it != block_pairs_.end();
- ++it) {
- const int block1 = it->first;
- const int block2 = it->second;
- if (!IsBlockPairOffDiagonal(block1, block2)) {
- continue;
- }
-
- int r, c, row_stride, col_stride;
- CellInfo* cell_info = m_->GetCell(block1, block2,
- &r, &c,
- &row_stride, &col_stride);
- CHECK(cell_info != NULL)
- << "Cell missing for block pair (" << block1 << "," << block2 << ")"
- << " cluster pair (" << cluster_membership_[block1]
- << " " << cluster_membership_[block2] << ")";
-
- // Ah the magic of tri-diagonal matrices and diagonal
- // dominance. See Lemma 1 in "Visibility Based Preconditioning
- // For Bundle Adjustment".
- MatrixRef m(cell_info->values, row_stride, col_stride);
- m.block(r, c, block_size_[block1], block_size_[block2]) *= 0.5;
- }
-}
-
-// Compute the sparse Cholesky factorization of the preconditioner
-// matrix.
-LinearSolverTerminationType VisibilityBasedPreconditioner::Factorize() {
- // Extract the TripletSparseMatrix that is used for actually storing
- // S and convert it into a cholmod_sparse object.
- cholmod_sparse* lhs = ss_.CreateSparseMatrix(
- down_cast<BlockRandomAccessSparseMatrix*>(
- m_.get())->mutable_matrix());
-
- // The matrix is symmetric, and the upper triangular part of the
- // matrix contains the values.
- lhs->stype = 1;
-
- // TODO(sameeragarwal): Refactor to pipe this up and out.
- string status;
-
- // Symbolic factorization is computed if we don't already have one handy.
- if (factor_ == NULL) {
- factor_ = ss_.BlockAnalyzeCholesky(lhs, block_size_, block_size_, &status);
- }
-
- const LinearSolverTerminationType termination_type =
- (factor_ != NULL)
- ? ss_.Cholesky(lhs, factor_, &status)
- : LINEAR_SOLVER_FATAL_ERROR;
-
- ss_.Free(lhs);
- return termination_type;
-}
-
-void VisibilityBasedPreconditioner::RightMultiply(const double* x,
- double* y) const {
- CHECK_NOTNULL(x);
- CHECK_NOTNULL(y);
- SuiteSparse* ss = const_cast<SuiteSparse*>(&ss_);
-
- const int num_rows = m_->num_rows();
- memcpy(CHECK_NOTNULL(tmp_rhs_)->x, x, m_->num_rows() * sizeof(*x));
- // TODO(sameeragarwal): Better error handling.
- string status;
- cholmod_dense* solution =
- CHECK_NOTNULL(ss->Solve(factor_, tmp_rhs_, &status));
- memcpy(y, solution->x, sizeof(*y) * num_rows);
- ss->Free(solution);
-}
-
-int VisibilityBasedPreconditioner::num_rows() const {
- return m_->num_rows();
-}
-
-// Classify camera/f_block pairs as in and out of the preconditioner,
-// based on whether the cluster pair that they belong to is in the
-// preconditioner or not.
-bool VisibilityBasedPreconditioner::IsBlockPairInPreconditioner(
- const int block1,
- const int block2) const {
- int cluster1 = cluster_membership_[block1];
- int cluster2 = cluster_membership_[block2];
- if (cluster1 > cluster2) {
- std::swap(cluster1, cluster2);
- }
- return (cluster_pairs_.count(make_pair(cluster1, cluster2)) > 0);
-}
-
-bool VisibilityBasedPreconditioner::IsBlockPairOffDiagonal(
- const int block1,
- const int block2) const {
- return (cluster_membership_[block1] != cluster_membership_[block2]);
-}
-
-// Convert a graph into a list of edges that includes self edges for
-// each vertex.
-void VisibilityBasedPreconditioner::ForestToClusterPairs(
- const WeightedGraph<int>& forest,
- HashSet<pair<int, int> >* cluster_pairs) const {
- CHECK_NOTNULL(cluster_pairs)->clear();
- const HashSet<int>& vertices = forest.vertices();
- CHECK_EQ(vertices.size(), num_clusters_);
-
- // Add all the cluster pairs corresponding to the edges in the
- // forest.
- for (HashSet<int>::const_iterator it1 = vertices.begin();
- it1 != vertices.end();
- ++it1) {
- const int cluster1 = *it1;
- cluster_pairs->insert(make_pair(cluster1, cluster1));
- const HashSet<int>& neighbors = forest.Neighbors(cluster1);
- for (HashSet<int>::const_iterator it2 = neighbors.begin();
- it2 != neighbors.end();
- ++it2) {
- const int cluster2 = *it2;
- if (cluster1 < cluster2) {
- cluster_pairs->insert(make_pair(cluster1, cluster2));
- }
- }
- }
-}
-
-// The visibilty set of a cluster is the union of the visibilty sets
-// of all its cameras. In other words, the set of points visible to
-// any camera in the cluster.
-void VisibilityBasedPreconditioner::ComputeClusterVisibility(
- const vector<set<int> >& visibility,
- vector<set<int> >* cluster_visibility) const {
- CHECK_NOTNULL(cluster_visibility)->resize(0);
- cluster_visibility->resize(num_clusters_);
- for (int i = 0; i < num_blocks_; ++i) {
- const int cluster_id = cluster_membership_[i];
- (*cluster_visibility)[cluster_id].insert(visibility[i].begin(),
- visibility[i].end());
- }
-}
-
-// Construct a graph whose vertices are the clusters, and the edge
-// weights are the number of 3D points visible to cameras in both the
-// vertices.
-WeightedGraph<int>* VisibilityBasedPreconditioner::CreateClusterGraph(
- const vector<set<int> >& cluster_visibility) const {
- WeightedGraph<int>* cluster_graph = new WeightedGraph<int>;
-
- for (int i = 0; i < num_clusters_; ++i) {
- cluster_graph->AddVertex(i);
- }
-
- for (int i = 0; i < num_clusters_; ++i) {
- const set<int>& cluster_i = cluster_visibility[i];
- for (int j = i+1; j < num_clusters_; ++j) {
- vector<int> intersection;
- const set<int>& cluster_j = cluster_visibility[j];
- set_intersection(cluster_i.begin(), cluster_i.end(),
- cluster_j.begin(), cluster_j.end(),
- back_inserter(intersection));
-
- if (intersection.size() > 0) {
- // Clusters interact strongly when they share a large number
- // of 3D points. The degree-2 maximum spanning forest
- // alorithm, iterates on the edges in decreasing order of
- // their weight, which is the number of points shared by the
- // two cameras that it connects.
- cluster_graph->AddEdge(i, j, intersection.size());
- }
- }
- }
- return cluster_graph;
-}
-
-// Canonical views clustering returns a HashMap from vertices to
-// cluster ids. Convert this into a flat array for quick lookup. It is
-// possible that some of the vertices may not be associated with any
-// cluster. In that case, randomly assign them to one of the clusters.
-//
-// The cluster ids can be non-contiguous integers. So as we flatten
-// the membership_map, we also map the cluster ids to a contiguous set
-// of integers so that the cluster ids are in [0, num_clusters_).
-void VisibilityBasedPreconditioner::FlattenMembershipMap(
- const HashMap<int, int>& membership_map,
- vector<int>* membership_vector) const {
- CHECK_NOTNULL(membership_vector)->resize(0);
- membership_vector->resize(num_blocks_, -1);
-
- HashMap<int, int> cluster_id_to_index;
- // Iterate over the cluster membership map and update the
- // cluster_membership_ vector assigning arbitrary cluster ids to
- // the few cameras that have not been clustered.
- for (HashMap<int, int>::const_iterator it = membership_map.begin();
- it != membership_map.end();
- ++it) {
- const int camera_id = it->first;
- int cluster_id = it->second;
-
- // If the view was not clustered, randomly assign it to one of the
- // clusters. This preserves the mathematical correctness of the
- // preconditioner. If there are too many views which are not
- // clustered, it may lead to some quality degradation though.
- //
- // TODO(sameeragarwal): Check if a large number of views have not
- // been clustered and deal with it?
- if (cluster_id == -1) {
- cluster_id = camera_id % num_clusters_;
- }
-
- const int index = FindWithDefault(cluster_id_to_index,
- cluster_id,
- cluster_id_to_index.size());
-
- if (index == cluster_id_to_index.size()) {
- cluster_id_to_index[cluster_id] = index;
- }
-
- CHECK_LT(index, num_clusters_);
- membership_vector->at(camera_id) = index;
- }
-}
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_NO_SUITESPARSE
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
deleted file mode 100644
index 2f6922dce54..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
+++ /dev/null
@@ -1,232 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Preconditioners for linear systems that arise in Structure from
-// Motion problems. VisibilityBasedPreconditioner implements:
-//
-// CLUSTER_JACOBI
-// CLUSTER_TRIDIAGONAL
-//
-// Detailed descriptions of these preconditions beyond what is
-// documented here can be found in
-//
-// Visibility Based Preconditioning for Bundle Adjustment
-// A. Kushal & S. Agarwal, CVPR 2012.
-//
-// http://www.cs.washington.edu/homes/sagarwal/vbp.pdf
-//
-// The two preconditioners share enough code that its most efficient
-// to implement them as part of the same code base.
-
-#ifndef CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
-#define CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
-
-#include <set>
-#include <vector>
-#include <utility>
-#include "ceres/collections_port.h"
-#include "ceres/graph.h"
-#include "ceres/internal/macros.h"
-#include "ceres/internal/scoped_ptr.h"
-#include "ceres/linear_solver.h"
-#include "ceres/preconditioner.h"
-#include "ceres/suitesparse.h"
-
-namespace ceres {
-namespace internal {
-
-class BlockRandomAccessSparseMatrix;
-class BlockSparseMatrix;
-struct CompressedRowBlockStructure;
-class SchurEliminatorBase;
-
-// This class implements visibility based preconditioners for
-// Structure from Motion/Bundle Adjustment problems. The name
-// VisibilityBasedPreconditioner comes from the fact that the sparsity
-// structure of the preconditioner matrix is determined by analyzing
-// the visibility structure of the scene, i.e. which cameras see which
-// points.
-//
-// The key idea of visibility based preconditioning is to identify
-// cameras that we expect have strong interactions, and then using the
-// entries in the Schur complement matrix corresponding to these
-// camera pairs as an approximation to the full Schur complement.
-//
-// CLUSTER_JACOBI identifies these camera pairs by clustering cameras,
-// and considering all non-zero camera pairs within each cluster. The
-// clustering in the current implementation is done using the
-// Canonical Views algorithm of Simon et al. (see
-// canonical_views_clustering.h). For the purposes of clustering, the
-// similarity or the degree of interaction between a pair of cameras
-// is measured by counting the number of points visible in both the
-// cameras. Thus the name VisibilityBasedPreconditioner. Further, if we
-// were to permute the parameter blocks such that all the cameras in
-// the same cluster occur contiguously, the preconditioner matrix will
-// be a block diagonal matrix with blocks corresponding to the
-// clusters. Thus in analogy with the Jacobi preconditioner we refer
-// to this as the CLUSTER_JACOBI preconditioner.
-//
-// CLUSTER_TRIDIAGONAL adds more mass to the CLUSTER_JACOBI
-// preconditioner by considering the interaction between clusters and
-// identifying strong interactions between cluster pairs. This is done
-// by constructing a weighted graph on the clusters, with the weight
-// on the edges connecting two clusters proportional to the number of
-// 3D points visible to cameras in both the clusters. A degree-2
-// maximum spanning forest is identified in this graph and the camera
-// pairs contained in the edges of this forest are added to the
-// preconditioner. The detailed reasoning for this construction is
-// explained in the paper mentioned above.
-//
-// Degree-2 spanning trees and forests have the property that they
-// correspond to tri-diagonal matrices. Thus there exist a permutation
-// of the camera blocks under which the CLUSTER_TRIDIAGONAL
-// preconditioner matrix is a block tridiagonal matrix, and thus the
-// name for the preconditioner.
-//
-// Thread Safety: This class is NOT thread safe.
-//
-// Example usage:
-//
-// LinearSolver::Options options;
-// options.preconditioner_type = CLUSTER_JACOBI;
-// options.elimination_groups.push_back(num_points);
-// options.elimination_groups.push_back(num_cameras);
-// VisibilityBasedPreconditioner preconditioner(
-// *A.block_structure(), options);
-// preconditioner.Update(A, NULL);
-// preconditioner.RightMultiply(x, y);
-//
-#ifndef CERES_NO_SUITESPARSE
-class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
- public:
- // Initialize the symbolic structure of the preconditioner. bs is
- // the block structure of the linear system to be solved. It is used
- // to determine the sparsity structure of the preconditioner matrix.
- //
- // It has the same structural requirement as other Schur complement
- // based solvers. Please see schur_eliminator.h for more details.
- VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const Preconditioner::Options& options);
- virtual ~VisibilityBasedPreconditioner();
-
- // Preconditioner interface
- virtual void RightMultiply(const double* x, double* y) const;
- virtual int num_rows() const;
-
- friend class VisibilityBasedPreconditionerTest;
-
- private:
- virtual bool UpdateImpl(const BlockSparseMatrix& A, const double* D);
- void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
- void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
- void InitStorage(const CompressedRowBlockStructure& bs);
- void InitEliminator(const CompressedRowBlockStructure& bs);
- LinearSolverTerminationType Factorize();
- void ScaleOffDiagonalCells();
-
- void ClusterCameras(const vector< set<int> >& visibility);
- void FlattenMembershipMap(const HashMap<int, int>& membership_map,
- vector<int>* membership_vector) const;
- void ComputeClusterVisibility(const vector<set<int> >& visibility,
- vector<set<int> >* cluster_visibility) const;
- WeightedGraph<int>* CreateClusterGraph(
- const vector<set<int> >& visibility) const;
- void ForestToClusterPairs(const WeightedGraph<int>& forest,
- HashSet<pair<int, int> >* cluster_pairs) const;
- void ComputeBlockPairsInPreconditioner(const CompressedRowBlockStructure& bs);
- bool IsBlockPairInPreconditioner(int block1, int block2) const;
- bool IsBlockPairOffDiagonal(int block1, int block2) const;
-
- Preconditioner::Options options_;
-
- // Number of parameter blocks in the schur complement.
- int num_blocks_;
- int num_clusters_;
-
- // Sizes of the blocks in the schur complement.
- vector<int> block_size_;
-
- // Mapping from cameras to clusters.
- vector<int> cluster_membership_;
-
- // Non-zero camera pairs from the schur complement matrix that are
- // present in the preconditioner, sorted by row (first element of
- // each pair), then column (second).
- set<pair<int, int> > block_pairs_;
-
- // Set of cluster pairs (including self pairs (i,i)) in the
- // preconditioner.
- HashSet<pair<int, int> > cluster_pairs_;
- scoped_ptr<SchurEliminatorBase> eliminator_;
-
- // Preconditioner matrix.
- scoped_ptr<BlockRandomAccessSparseMatrix> m_;
-
- // RightMultiply is a const method for LinearOperators. It is
- // implemented using CHOLMOD's sparse triangular matrix solve
- // function. This however requires non-const access to the
- // SuiteSparse context object, even though it does not result in any
- // of the state of the preconditioner being modified.
- SuiteSparse ss_;
-
- // Symbolic and numeric factorization of the preconditioner.
- cholmod_factor* factor_;
-
- // Temporary vector used by RightMultiply.
- cholmod_dense* tmp_rhs_;
- CERES_DISALLOW_COPY_AND_ASSIGN(VisibilityBasedPreconditioner);
-};
-#else // SuiteSparse
-// If SuiteSparse is not compiled in, the preconditioner is not
-// available.
-class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
- public:
- VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const Preconditioner::Options& options) {
- LOG(FATAL) << "Visibility based preconditioning is not available. Please "
- "build Ceres with SuiteSparse.";
- }
- virtual ~VisibilityBasedPreconditioner() {}
- virtual void RightMultiply(const double* x, double* y) const {}
- virtual void LeftMultiply(const double* x, double* y) const {}
- virtual int num_rows() const { return -1; }
- virtual int num_cols() const { return -1; }
-
- private:
- bool UpdateImpl(const BlockSparseMatrix& A, const double* D) {
- return false;
- }
-};
-#endif // CERES_NO_SUITESPARSE
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc
deleted file mode 100644
index 85c4417552d..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: strandmark@google.com (Petter Strandmark)
-
-#include "ceres/wall_time.h"
-
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#else
-#include <ctime>
-#endif
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <sys/time.h>
-#endif
-
-namespace ceres {
-namespace internal {
-
-double WallTimeInSeconds() {
-#ifdef CERES_USE_OPENMP
- return omp_get_wtime();
-#else
-#ifdef _WIN32
- return static_cast<double>(std::time(NULL));
-#else
- timeval time_val;
- gettimeofday(&time_val, NULL);
- return (time_val.tv_sec + time_val.tv_usec * 1e-6);
-#endif
-#endif
-}
-
-EventLogger::EventLogger(const string& logger_name)
- : start_time_(WallTimeInSeconds()),
- last_event_time_(start_time_),
- events_("") {
- StringAppendF(&events_,
- "\n%s\n Delta Cumulative\n",
- logger_name.c_str());
-}
-
-EventLogger::~EventLogger() {
- if (VLOG_IS_ON(3)) {
- AddEvent("Total");
- VLOG(2) << "\n" << events_ << "\n";
- }
-}
-
-void EventLogger::AddEvent(const string& event_name) {
- if (!VLOG_IS_ON(3)) {
- return;
- }
-
- const double current_time = WallTimeInSeconds();
- const double relative_time_delta = current_time - last_event_time_;
- const double absolute_time_delta = current_time - start_time_;
- last_event_time_ = current_time;
-
- StringAppendF(&events_,
- " %30s : %10.5f %10.5f\n",
- event_name.c_str(),
- relative_time_delta,
- absolute_time_delta);
-}
-
-} // namespace internal
-} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.h b/extern/libmv/third_party/ceres/internal/ceres/wall_time.h
deleted file mode 100644
index 37f5568a125..00000000000
--- a/extern/libmv/third_party/ceres/internal/ceres/wall_time.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2012 Google Inc. All rights reserved.
-// http://code.google.com/p/ceres-solver/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of Google Inc. nor the names of its contributors may be
-// used to endorse or promote products derived from this software without
-// specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: strandmark@google.com (Petter Strandmark)
-
-#ifndef CERES_INTERNAL_WALL_TIME_H_
-#define CERES_INTERNAL_WALL_TIME_H_
-
-#include <map>
-#include <string>
-#include "ceres/internal/port.h"
-#include "ceres/stringprintf.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-// Returns time, in seconds, from some arbitrary starting point. If
-// OpenMP is available then the high precision openmp_get_wtime()
-// function is used. Otherwise on unixes, gettimeofday is used. The
-// granularity is in seconds on windows systems.
-double WallTimeInSeconds();
-
-// Log a series of events, recording for each event the time elapsed
-// since the last event and since the creation of the object.
-//
-// The information is output to VLOG(3) upon destruction. A
-// name::Total event is added as the final event right before
-// destruction.
-//
-// Example usage:
-//
-// void Foo() {
-// EventLogger event_logger("Foo");
-// Bar1();
-// event_logger.AddEvent("Bar1")
-// Bar2();
-// event_logger.AddEvent("Bar2")
-// Bar3();
-// }
-//
-// Will produce output that looks like
-//
-// Foo
-// Bar1: time1 time1
-// Bar2: time2 time1 + time2;
-// Total: time3 time1 + time2 + time3;
-class EventLogger {
- public:
- explicit EventLogger(const string& logger_name);
- ~EventLogger();
- void AddEvent(const string& event_name);
-
- private:
- const double start_time_;
- double last_event_time_;
- string events_;
-};
-
-} // namespace internal
-} // namespace ceres
-
-#endif // CERES_INTERNAL_WALL_TIME_H_
diff --git a/extern/libmv/third_party/gflags/ChangeLog.txt b/extern/libmv/third_party/gflags/ChangeLog.txt
deleted file mode 100644
index e14d88e35f2..00000000000
--- a/extern/libmv/third_party/gflags/ChangeLog.txt
+++ /dev/null
@@ -1,208 +0,0 @@
-* Sun Mar 20 2014 - Andreas Schuh <google-gflags@googlegroups.com>
-
-- gflags: version 2.1.1
-- Fixed issue 77: GFLAGS_IS_A_DLL expands to empty string in gflags_declare.h
-- Fixed issue 79: GFLAGS_NAMESPACE not expanded to actual namespace in gflags_declare.h
-- Fixed issue 80: Allow include path to differ from GFLAGS_NAMESPACE
-
-* Thu Mar 20 2014 - Andreas Schuh <google-gflags@googlegroups.com>
-
-- gflags: version 2.1.0
-- Build system configuration using CMake instead of autotools
-- CPack packaging support for Debian/Ubuntu, Red Hat, and Mac OS X
-- Fixed issue 54: Fix "invalid suffix on literal" (C++11)
-- Fixed issue 57: Use _strdup instead of strdup on Windows
-- Fixed issue 62: Change all preprocessor include guards to start with GFLAGS_
-- Fixed issue 64: Add DEFINE_validator macro
-- Fixed issue 73: Warnings in Visual Studio 2010 and unable to compile unit test
-
-* Wed Jan 25 2012 - Google Inc. <google-gflags@googlegroups.com>
-
-- gflags: version 2.0
-- Changed the 'official' gflags email in setup.py/etc
-- Renamed google-gflags.sln to gflags.sln
-- Changed copyright text to reflect Google's relinquished ownership
-
-* Tue Dec 20 2011 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.7
-- Add CommandLineFlagInfo::flag_ptr pointing to current storage (musji)
-- PORTING: flush after writing to stderr, needed on cygwin
-- PORTING: Clean up the GFLAGS_DLL_DECL stuff better
-- Fix a bug in StringPrintf() that affected large strings (csilvers)
-- Die at configure-time when g++ isn't installed
-
-* Fri Jul 29 2011 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.6
-- BUGFIX: Fix a bug where we were leaving out a required $(top_srcdir)
-- Fix definition of clstring (jyrki)
-- Split up flag declares into its own file (jyrki)
-- Add --version support (csilvers)
-- Update the README for gflags with static libs
-- Update acx_pthread.m4 for nostdlib
-- Change ReparseCommandLineFlags to return void (csilvers)
-- Some doc typofixes and example augmentation (various)
-
-* Mon Jan 24 2011 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.5
-- Better reporting of current vs default value (handler)
-- Add API for cleaning up of memory at program-exit (jmarantz)
-- Fix macros to work inside namespaces (csilvers)
-- Use our own string typedef in case string is redefined (csilvers)
-- Updated to autoconf 2.65
-
-* Wed Oct 13 2010 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.4
-- Add a check to prevent passing 0 to DEFINE_string (jorg)
-- Reduce compile (.o) size (jyrki)
-- Some small changes to quiet debug compiles (alexk)
-- PORTING: better support static linking on windows (csilvers)
-- DOCUMENTATION: change default values, use validators, etc.
-- Update the NEWS file to be non-empty
-- Add pkg-config (.pc) files for libgflags and libgflags_nothreads
-
-* Mon Jan 4 2010 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.3
-- PORTABILITY: can now build and run tests under MSVC (csilvers)
-- Remove the python gflags code, which is now its own package (tansell)
-- Clarify that "last flag wins" in the docs (csilvers)
-- Comment danger of using GetAllFlags in validators (wojtekm)
-- PORTABILITY: Some fixes necessary for c++0x (mboerger)
-- Makefile fix: $(srcdir) -> $(top_srcdir) in one place (csilvres)
-- INSTALL: autotools to autoconf v2.64 + automake v1.11 (csilvers)
-
-* Thu Sep 10 2009 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.2
-- PORTABILITY: can now build and run tests under mingw (csilvers)
-- Using a string arg for a bool flag is a compile-time error (rbayardo)
-- Add --helpxml to gflags.py (salcianu)
-- Protect against a hypothetical global d'tor mutex problem (csilvers)
-- BUGFIX: can now define a flag after 'using namespace google' (hamaji)
-
-* Tue Apr 14 2009 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.1
-- Add both foo and nofoo for boolean flags, with --undefok (andychu)
-- Better document how validators work (wojtekm)
-- Improve binary-detection for bash-completion (mtamsky)
-- Python: Add a concept of "key flags", used with --help (salcianu)
-- Python: Robustify flag_values (salcianu)
-- Python: Add a new DEFINE_bool alias (keir, andrewliu)
-- Python: Do module introspection based on module name (dsturtevant)
-- Fix autoconf a bit better, especially on windows and solaris (ajenjo)
-- BUG FIX: gflags_nothreads was linking against the wrong lib (ajenjo)
-- BUG FIX: threads-detection failed on FreeBSD; replace it (ajenjo)
-- PORTABILITY: Quiet an internal compiler error with SUSE 10 (csilvers)
-- PORTABILITY: Update deb.sh for more recenty debuilds (csilvers)
-- PORTABILITY: #include more headers to satify new gcc's (csilvers)
-- INSTALL: Updated to autoconf 2.61 and libtool 1.5.26 (csilvers)
-
-* Fri Oct 3 2008 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.0
-- Add a missing newline to an error string (bcmills)
-- (otherwise exactly the same as gflags 1.0rc2)
-
-* Thu Sep 18 2008 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.0rc2
-- Report current flag values in --helpxml (hdn)
-- Fix compilation troubles with gcc 4.3.3 (simonb)
-- BUG FIX: I was missing a std:: in DECLARE_string (csilvers)
-- BUG FIX: Clarify in docs how to specify --bool flags (csilvers)
-- BUG FIX: Fix --helpshort for source files not in a subdir (csilvers)
-- BUG FIX: Fix python unittest for 64-bit builds (bcmills)
-
-* Tue Aug 19 2008 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 1.0rc1
-- Move #include files from google/ to gflags/ (csilvers)
-- Small optimizations to reduce binary (library) size (jyrki)
-- BUGFIX: forgot a std:: in one of the .h files (csilvers)
-- Speed up locking by making sure calls are inlined (ajenjo)
-- 64-BIT COMPATIBILITY: Use %PRId64 instead of %lld (csilvers)
-- PORTABILITY: fix Makefile to work with Cygwin (ajenjo)
-- PORTABILITY: fix code to compile under Visual Studio (ajenjo)
-- PORTABILITY: fix code to compile under Solaris 10 with CC (csilvers)
-
-* Mon Jul 21 2008 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.9
-- Add the ability to validate a command-line flag (csilvers)
-- Add completion support for commandline flags in bash (daven)
-- Add -W compile flags to Makefile, when using gcc (csilvers)
-- Allow helpstring to be NULL (cristianoc)
-- Improved documentation of classes in the .cc file (csilvers)
-- Fix python bug with AppendFlagValues + shortnames (jjtswan)
-- Use bool instead of int for boolean flags in gflags.py (bcmills)
-- Simplify the way we declare flags, now more foolproof (csilvers)
-- Better error messages when bool flags collide (colohan)
-- Only evaluate DEFINE_foo macro args once (csilvers)
-
-* Wed Mar 26 2008 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.8
-- Export DescribeOneFlag() in the API
-- Add support for automatic line wrapping at 80 cols for gflags.py
-- Bugfix: do not treat an isolated "-" the same as an isolated "--"
-- Update rpm spec to point to Google Code rather than sourceforge (!)
-- Improve documentation (including documenting thread-safety)
-- Improve #include hygiene
-- Improve testing
-
-* Thu Oct 18 2007 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.7
-- Deal even more correctly with libpthread not linked in (csilvers)
-- Add STRIP_LOG, an improved DO_NOT_SHOW_COMMANDLINE_HELP (sioffe)
-- Be more accurate printing default flag values in --help (dsturtevant)
-- Reduce .o file size a bit by using shorter namespace names (jeff)
-- Use relative install path, so 'setup.py --home' works (csilvers)
-- Notice when a boolean flag has a non-boolean default (bnmouli)
-- Broaden --helpshort to match foo-main.cc and foo_main.cc (hendrie)
-- Fix "no modules match" message for --helpshort, etc (hendrie)
-
-* Wed Aug 15 2007 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.6
-- Deal correctly with case that libpthread is not linked in (csilvers)
-- Update Makefile/tests so we pass "make distcheck" (csilvers)
-- Document and test that last assignment to a flag wins (wan)
-
-* Tue Jun 12 2007 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.5
-- Include all m4 macros in the distribution (csilvers)
-- Python: Fix broken data_files field in setup.py (sidlon)
-- Python: better string serliaizing and unparsing (abo, csimmons)
-- Fix checks for NaN and inf to work with Mac OS X (csilvers)
-
-* Thu Apr 19 2007 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.4
-- Remove is_default from GetCommandLineFlagInfo (csilvers)
-- Portability fixes: includes, strtoll, gcc4.3 errors (csilvers)
-- A few doc typo cleanups (csilvers)
-
-* Wed Mar 28 2007 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.3
-- python portability fix: use popen instead of subprocess (csilvers)
-- Add is_default to CommandLineFlagInfo (pchien)
-- Make docs a bit prettier (csilvers)
-- Actually include the python files in the distribution! :-/ (csilvers)
-
-* Mon Jan 22 2007 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.2
-- added support for python commandlineflags, as well as c++
-- gflags2man, a script to turn flags into a man page (dchristian)
-
-* Wed Dec 13 2006 - Google Inc. <opensource@google.com>
-
-- google-gflags: version 0.1
diff --git a/extern/libmv/third_party/gflags/README.libmv b/extern/libmv/third_party/gflags/README.libmv
deleted file mode 100644
index f4310b39bbb..00000000000
--- a/extern/libmv/third_party/gflags/README.libmv
+++ /dev/null
@@ -1,18 +0,0 @@
-Project: Google Flags
-URL: http://code.google.com/p/google-gflags/
-License: New BSD
-Upstream version: 2.1.1
-Local modifications:
-
-- Flattened the tree and only included files needed for libmv.
-
-- config.h was originally generated on linux machine with some
- further tweaks:
-
- * OS_WINDOWS need to be conditinally defined from inside #ifdef WIN32
- * Same applies yo HAVE_SHLWAPI_H
- * Disabeld HAVE_FNMATCH_H
-
-- Removed attribute(unused) from FlagSaver.
-
- TODO(keir): Import and use gflags for Windows from upstream.
diff --git a/extern/libmv/third_party/gflags/config.h b/extern/libmv/third_party/gflags/config.h
deleted file mode 100644
index 858510835c1..00000000000
--- a/extern/libmv/third_party/gflags/config.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* Generated from config.h.in during build configuration using CMake. */
-
-// Note: This header file is only used internally. It is not part of public interface!
-
-// ---------------------------------------------------------------------------
-// System checks
-
-// Define if you build this library for a MS Windows OS.
-#ifdef WIN32
-# define OS_WINDOWS
-#endif
-
-// Define if you have the <stdint.h> header file.
-#define HAVE_STDINT_H
-
-// Define if you have the <sys/types.h> header file.
-#define HAVE_SYS_TYPES_H
-
-// Define if you have the <inttypes.h> header file.
-#define HAVE_INTTYPES_H
-
-// Define if you have the <sys/stat.h> header file.
-#define HAVE_SYS_STAT_H
-
-// Define if you have the <unistd.h> header file.
-#define HAVE_UNISTD_H
-
-// Define if you have the <fnmatch.h> header file.
-/* #undef HAVE_FNMATCH_H */
-
-// Define if you have the <shlwapi.h> header file (Windows 2000/XP).
-#undef HAVE_SHLWAPI_H
-
-// Define if you have the strtoll function.
-#define HAVE_STRTOLL
-
-// Define if you have the strtoq function.
-/* #undef HAVE_STRTOQ */
-
-// Define if you have the <pthread.h> header file.
-#define HAVE_PTHREAD
-
-// Define if your pthread library defines the type pthread_rwlock_t
-#define HAVE_RWLOCK
-
-// gcc requires this to get PRId64, etc.
-#if defined(HAVE_INTTYPES_H) && !defined(__STDC_FORMAT_MACROS)
-# define __STDC_FORMAT_MACROS 1
-#endif
-
-// ---------------------------------------------------------------------------
-// Package information
-
-// Name of package.
-#define PACKAGE gflags
-
-// Define to the full name of this package.
-#define PACKAGE_NAME gflags
-
-// Define to the full name and version of this package.
-#define PACKAGE_STRING gflags 2.1.1
-
-// Define to the one symbol short name of this package.
-#define PACKAGE_TARNAME gflags-2.1.1
-
-// Define to the version of this package.
-#define PACKAGE_VERSION 2.1.1
-
-// Version number of package.
-#define VERSION PACKAGE_VERSION
-
-// Define to the address where bug reports for this package should be sent.
-#define PACKAGE_BUGREPORT https://code.google.com/p/gflags/issues/
-
-// Namespace of gflags library symbols.
-#define GFLAGS_NAMESPACE gflags
-
-// ---------------------------------------------------------------------------
-// Path separator
-#ifndef PATH_SEPARATOR
-# ifdef OS_WINDOWS
-# define PATH_SEPARATOR '\\'
-# else
-# define PATH_SEPARATOR '/'
-# endif
-#endif
-
-// ---------------------------------------------------------------------------
-// Windows
-
-// Whether gflags library is a DLL.
-#ifndef GFLAGS_IS_A_DLL
-# define GFLAGS_IS_A_DLL 0
-#endif
-
-// Always export symbols when compiling a shared library as this file is only
-// included by internal modules when building the gflags library itself.
-// The gflags_declare.h header file will set it to import these symbols otherwise.
-#ifndef GFLAGS_DLL_DECL
-# if GFLAGS_IS_A_DLL && defined(_MSC_VER)
-# define GFLAGS_DLL_DECL __declspec(dllexport)
-# else
-# define GFLAGS_DLL_DECL
-# endif
-#endif
-// Flags defined by the gflags library itself must be exported
-#ifndef GFLAGS_DLL_DEFINE_FLAG
-# define GFLAGS_DLL_DEFINE_FLAG GFLAGS_DLL_DECL
-#endif
-
-#ifdef OS_WINDOWS
-// The unittests import the symbols of the shared gflags library
-# if GFLAGS_IS_A_DLL && defined(_MSC_VER)
-# define GFLAGS_DLL_DECL_FOR_UNITTESTS __declspec(dllimport)
-# endif
-# include "windows_port.h"
-#endif
diff --git a/extern/libmv/third_party/gflags/gflags.cc b/extern/libmv/third_party/gflags/gflags.cc
deleted file mode 100644
index 285050fe9ec..00000000000
--- a/extern/libmv/third_party/gflags/gflags.cc
+++ /dev/null
@@ -1,1957 +0,0 @@
-// Copyright (c) 1999, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// ---
-// Revamped and reorganized by Craig Silverstein
-//
-// This file contains the implementation of all our command line flags
-// stuff. Here's how everything fits together
-//
-// * FlagRegistry owns CommandLineFlags owns FlagValue.
-// * FlagSaver holds a FlagRegistry (saves it at construct time,
-// restores it at destroy time).
-// * CommandLineFlagParser lives outside that hierarchy, but works on
-// CommandLineFlags (modifying the FlagValues).
-// * Free functions like SetCommandLineOption() work via one of the
-// above (such as CommandLineFlagParser).
-//
-// In more detail:
-//
-// -- The main classes that hold flag data:
-//
-// FlagValue holds the current value of a flag. It's
-// pseudo-templatized: every operation on a FlagValue is typed. It
-// also deals with storage-lifetime issues (so flag values don't go
-// away in a destructor), which is why we need a whole class to hold a
-// variable's value.
-//
-// CommandLineFlag is all the information about a single command-line
-// flag. It has a FlagValue for the flag's current value, but also
-// the flag's name, type, etc.
-//
-// FlagRegistry is a collection of CommandLineFlags. There's the
-// global registry, which is where flags defined via DEFINE_foo()
-// live. But it's possible to define your own flag, manually, in a
-// different registry you create. (In practice, multiple registries
-// are used only by FlagSaver).
-//
-// A given FlagValue is owned by exactly one CommandLineFlag. A given
-// CommandLineFlag is owned by exactly one FlagRegistry. FlagRegistry
-// has a lock; any operation that writes to a FlagValue or
-// CommandLineFlag owned by that registry must acquire the
-// FlagRegistry lock before doing so.
-//
-// --- Some other classes and free functions:
-//
-// CommandLineFlagInfo is a client-exposed version of CommandLineFlag.
-// Once it's instantiated, it has no dependencies or relationships
-// with any other part of this file.
-//
-// FlagRegisterer is the helper class used by the DEFINE_* macros to
-// allow work to be done at global initialization time.
-//
-// CommandLineFlagParser is the class that reads from the commandline
-// and instantiates flag values based on that. It needs to poke into
-// the innards of the FlagValue->CommandLineFlag->FlagRegistry class
-// hierarchy to do that. It's careful to acquire the FlagRegistry
-// lock before doing any writing or other non-const actions.
-//
-// GetCommandLineOption is just a hook into registry routines to
-// retrieve a flag based on its name. SetCommandLineOption, on the
-// other hand, hooks into CommandLineFlagParser. Other API functions
-// are, similarly, mostly hooks into the functionality described above.
-
-#include "config.h"
-#include "gflags.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#if defined(HAVE_FNMATCH_H)
-# include <fnmatch.h>
-#elif defined(HAVE_SHLWAPI_H)
-# include <shlwapi.h>
-#endif
-#include <stdarg.h> // For va_list and related operations
-#include <stdio.h>
-#include <string.h>
-
-#include <algorithm>
-#include <map>
-#include <string>
-#include <utility> // for pair<>
-#include <vector>
-
-#include "mutex.h"
-#include "util.h"
-
-// Special flags, type 1: the 'recursive' flags. They set another flag's val.
-DEFINE_string(flagfile, "", "load flags from file");
-DEFINE_string(fromenv, "", "set flags from the environment"
- " [use 'export FLAGS_flag1=value']");
-DEFINE_string(tryfromenv, "", "set flags from the environment if present");
-
-// Special flags, type 2: the 'parsing' flags. They modify how we parse.
-DEFINE_string(undefok, "", "comma-separated list of flag names that it is okay to specify "
- "on the command line even if the program does not define a flag "
- "with that name. IMPORTANT: flags in this list that have "
- "arguments MUST use the flag=value format");
-
-namespace GFLAGS_NAMESPACE {
-
-using std::map;
-using std::pair;
-using std::sort;
-using std::string;
-using std::vector;
-
-// This is used by the unittest to test error-exit code
-void GFLAGS_DLL_DECL (*gflags_exitfunc)(int) = &exit; // from stdlib.h
-
-
-// The help message indicating that the commandline flag has been
-// 'stripped'. It will not show up when doing "-help" and its
-// variants. The flag is stripped if STRIP_FLAG_HELP is set to 1
-// before including base/gflags.h
-
-// This is used by this file, and also in gflags_reporting.cc
-const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
-
-namespace {
-
-// There are also 'reporting' flags, in gflags_reporting.cc.
-
-static const char kError[] = "ERROR: ";
-
-// Indicates that undefined options are to be ignored.
-// Enables deferred processing of flags in dynamically loaded libraries.
-static bool allow_command_line_reparsing = false;
-
-static bool logging_is_probably_set_up = false;
-
-// This is a 'prototype' validate-function. 'Real' validate
-// functions, take a flag-value as an argument: ValidateFn(bool) or
-// ValidateFn(uint64). However, for easier storage, we strip off this
-// argument and then restore it when actually calling the function on
-// a flag value.
-typedef bool (*ValidateFnProto)();
-
-// Whether we should die when reporting an error.
-enum DieWhenReporting { DIE, DO_NOT_DIE };
-
-// Report Error and exit if requested.
-static void ReportError(DieWhenReporting should_die, const char* format, ...) {
- char error_message[255];
- va_list ap;
- va_start(ap, format);
- vsnprintf(error_message, sizeof(error_message), format, ap);
- va_end(ap);
- fprintf(stderr, "%s", error_message);
- fflush(stderr); // should be unnecessary, but cygwin's rxvt buffers stderr
- if (should_die == DIE) gflags_exitfunc(1);
-}
-
-
-// --------------------------------------------------------------------
-// FlagValue
-// This represent the value a single flag might have. The major
-// functionality is to convert from a string to an object of a
-// given type, and back. Thread-compatible.
-// --------------------------------------------------------------------
-
-class CommandLineFlag;
-class FlagValue {
- public:
- FlagValue(void* valbuf, const char* type, bool transfer_ownership_of_value);
- ~FlagValue();
-
- bool ParseFrom(const char* spec);
- string ToString() const;
-
- private:
- friend class CommandLineFlag; // for many things, including Validate()
- friend class GFLAGS_NAMESPACE::FlagSaverImpl; // calls New()
- friend class FlagRegistry; // checks value_buffer_ for flags_by_ptr_ map
- template <typename T> friend T GetFromEnv(const char*, const char*, T);
- friend bool TryParseLocked(const CommandLineFlag*, FlagValue*,
- const char*, string*); // for New(), CopyFrom()
-
- enum ValueType {
- FV_BOOL = 0,
- FV_INT32 = 1,
- FV_INT64 = 2,
- FV_UINT64 = 3,
- FV_DOUBLE = 4,
- FV_STRING = 5,
- FV_MAX_INDEX = 5,
- };
- const char* TypeName() const;
- bool Equal(const FlagValue& x) const;
- FlagValue* New() const; // creates a new one with default value
- void CopyFrom(const FlagValue& x);
- int ValueSize() const;
-
- // Calls the given validate-fn on value_buffer_, and returns
- // whatever it returns. But first casts validate_fn_proto to a
- // function that takes our value as an argument (eg void
- // (*validate_fn)(bool) for a bool flag).
- bool Validate(const char* flagname, ValidateFnProto validate_fn_proto) const;
-
- void* value_buffer_; // points to the buffer holding our data
- int8 type_; // how to interpret value_
- bool owns_value_; // whether to free value on destruct
-
- FlagValue(const FlagValue&); // no copying!
- void operator=(const FlagValue&);
-};
-
-
-// This could be a templated method of FlagValue, but doing so adds to the
-// size of the .o. Since there's no type-safety here anyway, macro is ok.
-#define VALUE_AS(type) *reinterpret_cast<type*>(value_buffer_)
-#define OTHER_VALUE_AS(fv, type) *reinterpret_cast<type*>(fv.value_buffer_)
-#define SET_VALUE_AS(type, value) VALUE_AS(type) = (value)
-
-FlagValue::FlagValue(void* valbuf, const char* type,
- bool transfer_ownership_of_value)
- : value_buffer_(valbuf),
- owns_value_(transfer_ownership_of_value) {
- for (type_ = 0; type_ <= FV_MAX_INDEX; ++type_) {
- if (!strcmp(type, TypeName())) {
- break;
- }
- }
- assert(type_ <= FV_MAX_INDEX); // Unknown typename
-}
-
-FlagValue::~FlagValue() {
- if (!owns_value_) {
- return;
- }
- switch (type_) {
- case FV_BOOL: delete reinterpret_cast<bool*>(value_buffer_); break;
- case FV_INT32: delete reinterpret_cast<int32*>(value_buffer_); break;
- case FV_INT64: delete reinterpret_cast<int64*>(value_buffer_); break;
- case FV_UINT64: delete reinterpret_cast<uint64*>(value_buffer_); break;
- case FV_DOUBLE: delete reinterpret_cast<double*>(value_buffer_); break;
- case FV_STRING: delete reinterpret_cast<string*>(value_buffer_); break;
- }
-}
-
-bool FlagValue::ParseFrom(const char* value) {
- if (type_ == FV_BOOL) {
- const char* kTrue[] = { "1", "t", "true", "y", "yes" };
- const char* kFalse[] = { "0", "f", "false", "n", "no" };
- COMPILE_ASSERT(sizeof(kTrue) == sizeof(kFalse), true_false_equal);
- for (size_t i = 0; i < sizeof(kTrue)/sizeof(*kTrue); ++i) {
- if (strcasecmp(value, kTrue[i]) == 0) {
- SET_VALUE_AS(bool, true);
- return true;
- } else if (strcasecmp(value, kFalse[i]) == 0) {
- SET_VALUE_AS(bool, false);
- return true;
- }
- }
- return false; // didn't match a legal input
-
- } else if (type_ == FV_STRING) {
- SET_VALUE_AS(string, value);
- return true;
- }
-
- // OK, it's likely to be numeric, and we'll be using a strtoXXX method.
- if (value[0] == '\0') // empty-string is only allowed for string type.
- return false;
- char* end;
- // Leading 0x puts us in base 16. But leading 0 does not put us in base 8!
- // It caused too many bugs when we had that behavior.
- int base = 10; // by default
- if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X'))
- base = 16;
- errno = 0;
-
- switch (type_) {
- case FV_INT32: {
- const int64 r = strto64(value, &end, base);
- if (errno || end != value + strlen(value)) return false; // bad parse
- if (static_cast<int32>(r) != r) // worked, but number out of range
- return false;
- SET_VALUE_AS(int32, static_cast<int32>(r));
- return true;
- }
- case FV_INT64: {
- const int64 r = strto64(value, &end, base);
- if (errno || end != value + strlen(value)) return false; // bad parse
- SET_VALUE_AS(int64, r);
- return true;
- }
- case FV_UINT64: {
- while (*value == ' ') value++;
- if (*value == '-') return false; // negative number
- const uint64 r = strtou64(value, &end, base);
- if (errno || end != value + strlen(value)) return false; // bad parse
- SET_VALUE_AS(uint64, r);
- return true;
- }
- case FV_DOUBLE: {
- const double r = strtod(value, &end);
- if (errno || end != value + strlen(value)) return false; // bad parse
- SET_VALUE_AS(double, r);
- return true;
- }
- default: {
- assert(false); // unknown type
- return false;
- }
- }
-}
-
-string FlagValue::ToString() const {
- char intbuf[64]; // enough to hold even the biggest number
- switch (type_) {
- case FV_BOOL:
- return VALUE_AS(bool) ? "true" : "false";
- case FV_INT32:
- snprintf(intbuf, sizeof(intbuf), "%" PRId32, VALUE_AS(int32));
- return intbuf;
- case FV_INT64:
- snprintf(intbuf, sizeof(intbuf), "%" PRId64, VALUE_AS(int64));
- return intbuf;
- case FV_UINT64:
- snprintf(intbuf, sizeof(intbuf), "%" PRIu64, VALUE_AS(uint64));
- return intbuf;
- case FV_DOUBLE:
- snprintf(intbuf, sizeof(intbuf), "%.17g", VALUE_AS(double));
- return intbuf;
- case FV_STRING:
- return VALUE_AS(string);
- default:
- assert(false);
- return ""; // unknown type
- }
-}
-
-bool FlagValue::Validate(const char* flagname,
- ValidateFnProto validate_fn_proto) const {
- switch (type_) {
- case FV_BOOL:
- return reinterpret_cast<bool (*)(const char*, bool)>(
- validate_fn_proto)(flagname, VALUE_AS(bool));
- case FV_INT32:
- return reinterpret_cast<bool (*)(const char*, int32)>(
- validate_fn_proto)(flagname, VALUE_AS(int32));
- case FV_INT64:
- return reinterpret_cast<bool (*)(const char*, int64)>(
- validate_fn_proto)(flagname, VALUE_AS(int64));
- case FV_UINT64:
- return reinterpret_cast<bool (*)(const char*, uint64)>(
- validate_fn_proto)(flagname, VALUE_AS(uint64));
- case FV_DOUBLE:
- return reinterpret_cast<bool (*)(const char*, double)>(
- validate_fn_proto)(flagname, VALUE_AS(double));
- case FV_STRING:
- return reinterpret_cast<bool (*)(const char*, const string&)>(
- validate_fn_proto)(flagname, VALUE_AS(string));
- default:
- assert(false); // unknown type
- return false;
- }
-}
-
-const char* FlagValue::TypeName() const {
- static const char types[] =
- "bool\0xx"
- "int32\0x"
- "int64\0x"
- "uint64\0"
- "double\0"
- "string";
- if (type_ > FV_MAX_INDEX) {
- assert(false);
- return "";
- }
- // Directly indexing the strings in the 'types' string, each of them is 7 bytes long.
- return &types[type_ * 7];
-}
-
-bool FlagValue::Equal(const FlagValue& x) const {
- if (type_ != x.type_)
- return false;
- switch (type_) {
- case FV_BOOL: return VALUE_AS(bool) == OTHER_VALUE_AS(x, bool);
- case FV_INT32: return VALUE_AS(int32) == OTHER_VALUE_AS(x, int32);
- case FV_INT64: return VALUE_AS(int64) == OTHER_VALUE_AS(x, int64);
- case FV_UINT64: return VALUE_AS(uint64) == OTHER_VALUE_AS(x, uint64);
- case FV_DOUBLE: return VALUE_AS(double) == OTHER_VALUE_AS(x, double);
- case FV_STRING: return VALUE_AS(string) == OTHER_VALUE_AS(x, string);
- default: assert(false); return false; // unknown type
- }
-}
-
-FlagValue* FlagValue::New() const {
- const char *type = TypeName();
- switch (type_) {
- case FV_BOOL: return new FlagValue(new bool(false), type, true);
- case FV_INT32: return new FlagValue(new int32(0), type, true);
- case FV_INT64: return new FlagValue(new int64(0), type, true);
- case FV_UINT64: return new FlagValue(new uint64(0), type, true);
- case FV_DOUBLE: return new FlagValue(new double(0.0), type, true);
- case FV_STRING: return new FlagValue(new string, type, true);
- default: assert(false); return NULL; // unknown type
- }
-}
-
-void FlagValue::CopyFrom(const FlagValue& x) {
- assert(type_ == x.type_);
- switch (type_) {
- case FV_BOOL: SET_VALUE_AS(bool, OTHER_VALUE_AS(x, bool)); break;
- case FV_INT32: SET_VALUE_AS(int32, OTHER_VALUE_AS(x, int32)); break;
- case FV_INT64: SET_VALUE_AS(int64, OTHER_VALUE_AS(x, int64)); break;
- case FV_UINT64: SET_VALUE_AS(uint64, OTHER_VALUE_AS(x, uint64)); break;
- case FV_DOUBLE: SET_VALUE_AS(double, OTHER_VALUE_AS(x, double)); break;
- case FV_STRING: SET_VALUE_AS(string, OTHER_VALUE_AS(x, string)); break;
- default: assert(false); // unknown type
- }
-}
-
-int FlagValue::ValueSize() const {
- if (type_ > FV_MAX_INDEX) {
- assert(false); // unknown type
- return 0;
- }
- static const uint8 valuesize[] = {
- sizeof(bool),
- sizeof(int32),
- sizeof(int64),
- sizeof(uint64),
- sizeof(double),
- sizeof(string),
- };
- return valuesize[type_];
-}
-
-// --------------------------------------------------------------------
-// CommandLineFlag
-// This represents a single flag, including its name, description,
-// default value, and current value. Mostly this serves as a
-// struct, though it also knows how to register itself.
-// All CommandLineFlags are owned by a (exactly one)
-// FlagRegistry. If you wish to modify fields in this class, you
-// should acquire the FlagRegistry lock for the registry that owns
-// this flag.
-// --------------------------------------------------------------------
-
-class CommandLineFlag {
- public:
- // Note: we take over memory-ownership of current_val and default_val.
- CommandLineFlag(const char* name, const char* help, const char* filename,
- FlagValue* current_val, FlagValue* default_val);
- ~CommandLineFlag();
-
- const char* name() const { return name_; }
- const char* help() const { return help_; }
- const char* filename() const { return file_; }
- const char* CleanFileName() const; // nixes irrelevant prefix such as homedir
- string current_value() const { return current_->ToString(); }
- string default_value() const { return defvalue_->ToString(); }
- const char* type_name() const { return defvalue_->TypeName(); }
- ValidateFnProto validate_function() const { return validate_fn_proto_; }
- const void* flag_ptr() const { return current_->value_buffer_; }
-
- void FillCommandLineFlagInfo(struct CommandLineFlagInfo* result);
-
- // If validate_fn_proto_ is non-NULL, calls it on value, returns result.
- bool Validate(const FlagValue& value) const;
- bool ValidateCurrent() const { return Validate(*current_); }
-
- private:
- // for SetFlagLocked() and setting flags_by_ptr_
- friend class FlagRegistry;
- friend class GFLAGS_NAMESPACE::FlagSaverImpl; // for cloning the values
- // set validate_fn
- friend bool AddFlagValidator(const void*, ValidateFnProto);
-
- // This copies all the non-const members: modified, processed, defvalue, etc.
- void CopyFrom(const CommandLineFlag& src);
-
- void UpdateModifiedBit();
-
- const char* const name_; // Flag name
- const char* const help_; // Help message
- const char* const file_; // Which file did this come from?
- bool modified_; // Set after default assignment?
- FlagValue* defvalue_; // Default value for flag
- FlagValue* current_; // Current value for flag
- // This is a casted, 'generic' version of validate_fn, which actually
- // takes a flag-value as an arg (void (*validate_fn)(bool), say).
- // When we pass this to current_->Validate(), it will cast it back to
- // the proper type. This may be NULL to mean we have no validate_fn.
- ValidateFnProto validate_fn_proto_;
-
- CommandLineFlag(const CommandLineFlag&); // no copying!
- void operator=(const CommandLineFlag&);
-};
-
-CommandLineFlag::CommandLineFlag(const char* name, const char* help,
- const char* filename,
- FlagValue* current_val, FlagValue* default_val)
- : name_(name), help_(help), file_(filename), modified_(false),
- defvalue_(default_val), current_(current_val), validate_fn_proto_(NULL) {
-}
-
-CommandLineFlag::~CommandLineFlag() {
- delete current_;
- delete defvalue_;
-}
-
-const char* CommandLineFlag::CleanFileName() const {
- // Compute top-level directory & file that this appears in
- // search full path backwards.
- // Stop going backwards at kRootDir; and skip by the first slash.
- static const char kRootDir[] = ""; // can set this to root directory,
-
- if (sizeof(kRootDir)-1 == 0) // no prefix to strip
- return filename();
-
- const char* clean_name = filename() + strlen(filename()) - 1;
- while ( clean_name > filename() ) {
- if (*clean_name == PATH_SEPARATOR) {
- if (strncmp(clean_name, kRootDir, sizeof(kRootDir)-1) == 0) {
- clean_name += sizeof(kRootDir)-1; // past root-dir
- break;
- }
- }
- --clean_name;
- }
- while ( *clean_name == PATH_SEPARATOR ) ++clean_name; // Skip any slashes
- return clean_name;
-}
-
-void CommandLineFlag::FillCommandLineFlagInfo(
- CommandLineFlagInfo* result) {
- result->name = name();
- result->type = type_name();
- result->description = help();
- result->current_value = current_value();
- result->default_value = default_value();
- result->filename = CleanFileName();
- UpdateModifiedBit();
- result->is_default = !modified_;
- result->has_validator_fn = validate_function() != NULL;
- result->flag_ptr = flag_ptr();
-}
-
-void CommandLineFlag::UpdateModifiedBit() {
- // Update the "modified" bit in case somebody bypassed the
- // Flags API and wrote directly through the FLAGS_name variable.
- if (!modified_ && !current_->Equal(*defvalue_)) {
- modified_ = true;
- }
-}
-
-void CommandLineFlag::CopyFrom(const CommandLineFlag& src) {
- // Note we only copy the non-const members; others are fixed at construct time
- if (modified_ != src.modified_) modified_ = src.modified_;
- if (!current_->Equal(*src.current_)) current_->CopyFrom(*src.current_);
- if (!defvalue_->Equal(*src.defvalue_)) defvalue_->CopyFrom(*src.defvalue_);
- if (validate_fn_proto_ != src.validate_fn_proto_)
- validate_fn_proto_ = src.validate_fn_proto_;
-}
-
-bool CommandLineFlag::Validate(const FlagValue& value) const {
-
- if (validate_function() == NULL)
- return true;
- else
- return value.Validate(name(), validate_function());
-}
-
-
-// --------------------------------------------------------------------
-// FlagRegistry
-// A FlagRegistry singleton object holds all flag objects indexed
-// by their names so that if you know a flag's name (as a C
-// string), you can access or set it. If the function is named
-// FooLocked(), you must own the registry lock before calling
-// the function; otherwise, you should *not* hold the lock, and
-// the function will acquire it itself if needed.
-// --------------------------------------------------------------------
-
-struct StringCmp { // Used by the FlagRegistry map class to compare char*'s
- bool operator() (const char* s1, const char* s2) const {
- return (strcmp(s1, s2) < 0);
- }
-};
-
-
-class FlagRegistry {
- public:
- FlagRegistry() {
- }
- ~FlagRegistry() {
- // Not using STLDeleteElements as that resides in util and this
- // class is base.
- for (FlagMap::iterator p = flags_.begin(), e = flags_.end(); p != e; ++p) {
- CommandLineFlag* flag = p->second;
- delete flag;
- }
- }
-
- static void DeleteGlobalRegistry() {
- delete global_registry_;
- global_registry_ = NULL;
- }
-
- // Store a flag in this registry. Takes ownership of the given pointer.
- void RegisterFlag(CommandLineFlag* flag);
-
- void Lock() { lock_.Lock(); }
- void Unlock() { lock_.Unlock(); }
-
- // Returns the flag object for the specified name, or NULL if not found.
- CommandLineFlag* FindFlagLocked(const char* name);
-
- // Returns the flag object whose current-value is stored at flag_ptr.
- // That is, for whom current_->value_buffer_ == flag_ptr
- CommandLineFlag* FindFlagViaPtrLocked(const void* flag_ptr);
-
- // A fancier form of FindFlag that works correctly if name is of the
- // form flag=value. In that case, we set key to point to flag, and
- // modify v to point to the value (if present), and return the flag
- // with the given name. If the flag does not exist, returns NULL
- // and sets error_message.
- CommandLineFlag* SplitArgumentLocked(const char* argument,
- string* key, const char** v,
- string* error_message);
-
- // Set the value of a flag. If the flag was successfully set to
- // value, set msg to indicate the new flag-value, and return true.
- // Otherwise, set msg to indicate the error, leave flag unchanged,
- // and return false. msg can be NULL.
- bool SetFlagLocked(CommandLineFlag* flag, const char* value,
- FlagSettingMode set_mode, string* msg);
-
- static FlagRegistry* GlobalRegistry(); // returns a singleton registry
-
- private:
- friend class GFLAGS_NAMESPACE::FlagSaverImpl; // reads all the flags in order to copy them
- friend class CommandLineFlagParser; // for ValidateAllFlags
- friend void GFLAGS_NAMESPACE::GetAllFlags(vector<CommandLineFlagInfo>*);
-
- // The map from name to flag, for FindFlagLocked().
- typedef map<const char*, CommandLineFlag*, StringCmp> FlagMap;
- typedef FlagMap::iterator FlagIterator;
- typedef FlagMap::const_iterator FlagConstIterator;
- FlagMap flags_;
-
- // The map from current-value pointer to flag, fo FindFlagViaPtrLocked().
- typedef map<const void*, CommandLineFlag*> FlagPtrMap;
- FlagPtrMap flags_by_ptr_;
-
- static FlagRegistry* global_registry_; // a singleton registry
-
- Mutex lock_;
- static Mutex global_registry_lock_;
-
- static void InitGlobalRegistry();
-
- // Disallow
- FlagRegistry(const FlagRegistry&);
- FlagRegistry& operator=(const FlagRegistry&);
-};
-
-class FlagRegistryLock {
- public:
- explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); }
- ~FlagRegistryLock() { fr_->Unlock(); }
- private:
- FlagRegistry *const fr_;
-};
-
-
-void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
- Lock();
- pair<FlagIterator, bool> ins =
- flags_.insert(pair<const char*, CommandLineFlag*>(flag->name(), flag));
- if (ins.second == false) { // means the name was already in the map
- if (strcmp(ins.first->second->filename(), flag->filename()) != 0) {
- ReportError(DIE, "ERROR: flag '%s' was defined more than once "
- "(in files '%s' and '%s').\n",
- flag->name(),
- ins.first->second->filename(),
- flag->filename());
- } else {
- ReportError(DIE, "ERROR: something wrong with flag '%s' in file '%s'. "
- "One possibility: file '%s' is being linked both statically "
- "and dynamically into this executable.\n",
- flag->name(),
- flag->filename(), flag->filename());
- }
- }
- // Also add to the flags_by_ptr_ map.
- flags_by_ptr_[flag->current_->value_buffer_] = flag;
- Unlock();
-}
-
-CommandLineFlag* FlagRegistry::FindFlagLocked(const char* name) {
- FlagConstIterator i = flags_.find(name);
- if (i == flags_.end()) {
- return NULL;
- } else {
- return i->second;
- }
-}
-
-CommandLineFlag* FlagRegistry::FindFlagViaPtrLocked(const void* flag_ptr) {
- FlagPtrMap::const_iterator i = flags_by_ptr_.find(flag_ptr);
- if (i == flags_by_ptr_.end()) {
- return NULL;
- } else {
- return i->second;
- }
-}
-
-CommandLineFlag* FlagRegistry::SplitArgumentLocked(const char* arg,
- string* key,
- const char** v,
- string* error_message) {
- // Find the flag object for this option
- const char* flag_name;
- const char* value = strchr(arg, '=');
- if (value == NULL) {
- key->assign(arg);
- *v = NULL;
- } else {
- // Strip out the "=value" portion from arg
- key->assign(arg, value-arg);
- *v = ++value; // advance past the '='
- }
- flag_name = key->c_str();
-
- CommandLineFlag* flag = FindFlagLocked(flag_name);
-
- if (flag == NULL) {
- // If we can't find the flag-name, then we should return an error.
- // The one exception is if 1) the flag-name is 'nox', 2) there
- // exists a flag named 'x', and 3) 'x' is a boolean flag.
- // In that case, we want to return flag 'x'.
- if (!(flag_name[0] == 'n' && flag_name[1] == 'o')) {
- // flag-name is not 'nox', so we're not in the exception case.
- *error_message = StringPrintf("%sunknown command line flag '%s'\n",
- kError, key->c_str());
- return NULL;
- }
- flag = FindFlagLocked(flag_name+2);
- if (flag == NULL) {
- // No flag named 'x' exists, so we're not in the exception case.
- *error_message = StringPrintf("%sunknown command line flag '%s'\n",
- kError, key->c_str());
- return NULL;
- }
- if (strcmp(flag->type_name(), "bool") != 0) {
- // 'x' exists but is not boolean, so we're not in the exception case.
- *error_message = StringPrintf(
- "%sboolean value (%s) specified for %s command line flag\n",
- kError, key->c_str(), flag->type_name());
- return NULL;
- }
- // We're in the exception case!
- // Make up a fake value to replace the "no" we stripped out
- key->assign(flag_name+2); // the name without the "no"
- *v = "0";
- }
-
- // Assign a value if this is a boolean flag
- if (*v == NULL && strcmp(flag->type_name(), "bool") == 0) {
- *v = "1"; // the --nox case was already handled, so this is the --x case
- }
-
- return flag;
-}
-
-bool TryParseLocked(const CommandLineFlag* flag, FlagValue* flag_value,
- const char* value, string* msg) {
- // Use tenative_value, not flag_value, until we know value is valid.
- FlagValue* tentative_value = flag_value->New();
- if (!tentative_value->ParseFrom(value)) {
- if (msg) {
- StringAppendF(msg,
- "%sillegal value '%s' specified for %s flag '%s'\n",
- kError, value,
- flag->type_name(), flag->name());
- }
- delete tentative_value;
- return false;
- } else if (!flag->Validate(*tentative_value)) {
- if (msg) {
- StringAppendF(msg,
- "%sfailed validation of new value '%s' for flag '%s'\n",
- kError, tentative_value->ToString().c_str(),
- flag->name());
- }
- delete tentative_value;
- return false;
- } else {
- flag_value->CopyFrom(*tentative_value);
- if (msg) {
- StringAppendF(msg, "%s set to %s\n",
- flag->name(), flag_value->ToString().c_str());
- }
- delete tentative_value;
- return true;
- }
-}
-
-bool FlagRegistry::SetFlagLocked(CommandLineFlag* flag,
- const char* value,
- FlagSettingMode set_mode,
- string* msg) {
- flag->UpdateModifiedBit();
- switch (set_mode) {
- case SET_FLAGS_VALUE: {
- // set or modify the flag's value
- if (!TryParseLocked(flag, flag->current_, value, msg))
- return false;
- flag->modified_ = true;
- break;
- }
- case SET_FLAG_IF_DEFAULT: {
- // set the flag's value, but only if it hasn't been set by someone else
- if (!flag->modified_) {
- if (!TryParseLocked(flag, flag->current_, value, msg))
- return false;
- flag->modified_ = true;
- } else {
- *msg = StringPrintf("%s set to %s",
- flag->name(), flag->current_value().c_str());
- }
- break;
- }
- case SET_FLAGS_DEFAULT: {
- // modify the flag's default-value
- if (!TryParseLocked(flag, flag->defvalue_, value, msg))
- return false;
- if (!flag->modified_) {
- // Need to set both defvalue *and* current, in this case
- TryParseLocked(flag, flag->current_, value, NULL);
- }
- break;
- }
- default: {
- // unknown set_mode
- assert(false);
- return false;
- }
- }
-
- return true;
-}
-
-// Get the singleton FlagRegistry object
-FlagRegistry* FlagRegistry::global_registry_ = NULL;
-Mutex FlagRegistry::global_registry_lock_(Mutex::LINKER_INITIALIZED);
-
-FlagRegistry* FlagRegistry::GlobalRegistry() {
- MutexLock acquire_lock(&global_registry_lock_);
- if (!global_registry_) {
- global_registry_ = new FlagRegistry;
- }
- return global_registry_;
-}
-
-// --------------------------------------------------------------------
-// CommandLineFlagParser
-// Parsing is done in two stages. In the first, we go through
-// argv. For every flag-like arg we can make sense of, we parse
-// it and set the appropriate FLAGS_* variable. For every flag-
-// like arg we can't make sense of, we store it in a vector,
-// along with an explanation of the trouble. In stage 2, we
-// handle the 'reporting' flags like --help and --mpm_version.
-// (This is via a call to HandleCommandLineHelpFlags(), in
-// gflags_reporting.cc.)
-// An optional stage 3 prints out the error messages.
-// This is a bit of a simplification. For instance, --flagfile
-// is handled as soon as it's seen in stage 1, not in stage 2.
-// --------------------------------------------------------------------
-
-class CommandLineFlagParser {
- public:
- // The argument is the flag-registry to register the parsed flags in
- explicit CommandLineFlagParser(FlagRegistry* reg) : registry_(reg) {}
- ~CommandLineFlagParser() {}
-
- // Stage 1: Every time this is called, it reads all flags in argv.
- // However, it ignores all flags that have been successfully set
- // before. Typically this is only called once, so this 'reparsing'
- // behavior isn't important. It can be useful when trying to
- // reparse after loading a dll, though.
- uint32 ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags);
-
- // Stage 2: print reporting info and exit, if requested.
- // In gflags_reporting.cc:HandleCommandLineHelpFlags().
-
- // Stage 3: validate all the commandline flags that have validators
- // registered.
- void ValidateAllFlags();
-
- // Stage 4: report any errors and return true if any were found.
- bool ReportErrors();
-
- // Set a particular command line option. "newval" is a string
- // describing the new value that the option has been set to. If
- // option_name does not specify a valid option name, or value is not
- // a valid value for option_name, newval is empty. Does recursive
- // processing for --flagfile and --fromenv. Returns the new value
- // if everything went ok, or empty-string if not. (Actually, the
- // return-string could hold many flag/value pairs due to --flagfile.)
- // NB: Must have called registry_->Lock() before calling this function.
- string ProcessSingleOptionLocked(CommandLineFlag* flag,
- const char* value,
- FlagSettingMode set_mode);
-
- // Set a whole batch of command line options as specified by contentdata,
- // which is in flagfile format (and probably has been read from a flagfile).
- // Returns the new value if everything went ok, or empty-string if
- // not. (Actually, the return-string could hold many flag/value
- // pairs due to --flagfile.)
- // NB: Must have called registry_->Lock() before calling this function.
- string ProcessOptionsFromStringLocked(const string& contentdata,
- FlagSettingMode set_mode);
-
- // These are the 'recursive' flags, defined at the top of this file.
- // Whenever we see these flags on the commandline, we must take action.
- // These are called by ProcessSingleOptionLocked and, similarly, return
- // new values if everything went ok, or the empty-string if not.
- string ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode);
- // diff fromenv/tryfromenv
- string ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode,
- bool errors_are_fatal);
-
- private:
- FlagRegistry* const registry_;
- map<string, string> error_flags_; // map from name to error message
- // This could be a set<string>, but we reuse the map to minimize the .o size
- map<string, string> undefined_names_; // --[flag] name was not registered
-};
-
-
-// Parse a list of (comma-separated) flags.
-static void ParseFlagList(const char* value, vector<string>* flags) {
- for (const char *p = value; p && *p; value = p) {
- p = strchr(value, ',');
- size_t len;
- if (p) {
- len = p - value;
- p++;
- } else {
- len = strlen(value);
- }
-
- if (len == 0)
- ReportError(DIE, "ERROR: empty flaglist entry\n");
- if (value[0] == '-')
- ReportError(DIE, "ERROR: flag \"%*s\" begins with '-'\n", len, value);
-
- flags->push_back(string(value, len));
- }
-}
-
-// Snarf an entire file into a C++ string. This is just so that we
-// can do all the I/O in one place and not worry about it everywhere.
-// Plus, it's convenient to have the whole file contents at hand.
-// Adds a newline at the end of the file.
-#define PFATAL(s) do { perror(s); gflags_exitfunc(1); } while (0)
-
-static string ReadFileIntoString(const char* filename) {
- const int kBufSize = 8092;
- char buffer[kBufSize];
- string s;
- FILE* fp;
- if ((errno = SafeFOpen(&fp, filename, "r")) != 0) PFATAL(filename);
- size_t n;
- while ( (n=fread(buffer, 1, kBufSize, fp)) > 0 ) {
- if (ferror(fp)) PFATAL(filename);
- s.append(buffer, n);
- }
- fclose(fp);
- return s;
-}
-
-uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv,
- bool remove_flags) {
- const char *program_name = strrchr((*argv)[0], PATH_SEPARATOR); // nix path
- program_name = (program_name == NULL ? (*argv)[0] : program_name+1);
-
- int first_nonopt = *argc; // for non-options moved to the end
-
- registry_->Lock();
- for (int i = 1; i < first_nonopt; i++) {
- char* arg = (*argv)[i];
-
- // Like getopt(), we permute non-option flags to be at the end.
- if (arg[0] != '-' || // must be a program argument
- (arg[0] == '-' && arg[1] == '\0')) { // "-" is an argument, not a flag
- memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i]));
- (*argv)[*argc-1] = arg; // we go last
- first_nonopt--; // we've been pushed onto the stack
- i--; // to undo the i++ in the loop
- continue;
- }
-
- if (arg[0] == '-') arg++; // allow leading '-'
- if (arg[0] == '-') arg++; // or leading '--'
-
- // -- alone means what it does for GNU: stop options parsing
- if (*arg == '\0') {
- first_nonopt = i+1;
- break;
- }
-
- // Find the flag object for this option
- string key;
- const char* value;
- string error_message;
- CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value,
- &error_message);
- if (flag == NULL) {
- undefined_names_[key] = ""; // value isn't actually used
- error_flags_[key] = error_message;
- continue;
- }
-
- if (value == NULL) {
- // Boolean options are always assigned a value by SplitArgumentLocked()
- assert(strcmp(flag->type_name(), "bool") != 0);
- if (i+1 >= first_nonopt) {
- // This flag needs a value, but there is nothing available
- error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'"
- + " is missing its argument");
- if (flag->help() && flag->help()[0] > '\001') {
- // Be useful in case we have a non-stripped description.
- error_flags_[key] += string("; flag description: ") + flag->help();
- }
- error_flags_[key] += "\n";
- break; // we treat this as an unrecoverable error
- } else {
- value = (*argv)[++i]; // read next arg for value
-
- // Heuristic to detect the case where someone treats a string arg
- // like a bool:
- // --my_string_var --foo=bar
- // We look for a flag of string type, whose value begins with a
- // dash, and where the flag-name and value are separated by a
- // space rather than an '='.
- // To avoid false positives, we also require the word "true"
- // or "false" in the help string. Without this, a valid usage
- // "-lat -30.5" would trigger the warning. The common cases we
- // want to solve talk about true and false as values.
- if (value[0] == '-'
- && strcmp(flag->type_name(), "string") == 0
- && (strstr(flag->help(), "true")
- || strstr(flag->help(), "false"))) {
- LOG(WARNING) << "Did you really mean to set flag '"
- << flag->name() << "' to the value '"
- << value << "'?";
- }
- }
- }
-
- // TODO(csilvers): only set a flag if we hadn't set it before here
- ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE);
- }
- registry_->Unlock();
-
- if (remove_flags) { // Fix up argc and argv by removing command line flags
- (*argv)[first_nonopt-1] = (*argv)[0];
- (*argv) += (first_nonopt-1);
- (*argc) -= (first_nonopt-1);
- first_nonopt = 1; // because we still don't count argv[0]
- }
-
- logging_is_probably_set_up = true; // because we've parsed --logdir, etc.
-
- return first_nonopt;
-}
-
-string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval,
- FlagSettingMode set_mode) {
- if (flagval.empty())
- return "";
-
- string msg;
- vector<string> filename_list;
- ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames
- for (size_t i = 0; i < filename_list.size(); ++i) {
- const char* file = filename_list[i].c_str();
- msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode);
- }
- return msg;
-}
-
-string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
- FlagSettingMode set_mode,
- bool errors_are_fatal) {
- if (flagval.empty())
- return "";
-
- string msg;
- vector<string> flaglist;
- ParseFlagList(flagval.c_str(), &flaglist);
-
- for (size_t i = 0; i < flaglist.size(); ++i) {
- const char* flagname = flaglist[i].c_str();
- CommandLineFlag* flag = registry_->FindFlagLocked(flagname);
- if (flag == NULL) {
- error_flags_[flagname] =
- StringPrintf("%sunknown command line flag '%s' "
- "(via --fromenv or --tryfromenv)\n",
- kError, flagname);
- undefined_names_[flagname] = "";
- continue;
- }
-
- const string envname = string("FLAGS_") + string(flagname);
- string envval;
- if (!SafeGetEnv(envname.c_str(), envval)) {
- if (errors_are_fatal) {
- error_flags_[flagname] = (string(kError) + envname +
- " not found in environment\n");
- }
- continue;
- }
-
- // Avoid infinite recursion.
- if (envval == "fromenv" || envval == "tryfromenv") {
- error_flags_[flagname] =
- StringPrintf("%sinfinite recursion on environment flag '%s'\n",
- kError, envval.c_str());
- continue;
- }
-
- msg += ProcessSingleOptionLocked(flag, envval.c_str(), set_mode);
- }
- return msg;
-}
-
-string CommandLineFlagParser::ProcessSingleOptionLocked(
- CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) {
- string msg;
- if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) {
- error_flags_[flag->name()] = msg;
- return "";
- }
-
- // The recursive flags, --flagfile and --fromenv and --tryfromenv,
- // must be dealt with as soon as they're seen. They will emit
- // messages of their own.
- if (strcmp(flag->name(), "flagfile") == 0) {
- msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode);
-
- } else if (strcmp(flag->name(), "fromenv") == 0) {
- // last arg indicates envval-not-found is fatal (unlike in --tryfromenv)
- msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true);
-
- } else if (strcmp(flag->name(), "tryfromenv") == 0) {
- msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false);
- }
-
- return msg;
-}
-
-void CommandLineFlagParser::ValidateAllFlags() {
- FlagRegistryLock frl(registry_);
- for (FlagRegistry::FlagConstIterator i = registry_->flags_.begin();
- i != registry_->flags_.end(); ++i) {
- if (!i->second->ValidateCurrent()) {
- // only set a message if one isn't already there. (If there's
- // an error message, our job is done, even if it's not exactly
- // the same error.)
- if (error_flags_[i->second->name()].empty())
- error_flags_[i->second->name()] =
- string(kError) + "--" + i->second->name() +
- " must be set on the commandline"
- " (default value fails validation)\n";
- }
- }
-}
-
-bool CommandLineFlagParser::ReportErrors() {
- // error_flags_ indicates errors we saw while parsing.
- // But we ignore undefined-names if ok'ed by --undef_ok
- if (!FLAGS_undefok.empty()) {
- vector<string> flaglist;
- ParseFlagList(FLAGS_undefok.c_str(), &flaglist);
- for (size_t i = 0; i < flaglist.size(); ++i) {
- // We also deal with --no<flag>, in case the flagname was boolean
- const string no_version = string("no") + flaglist[i];
- if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) {
- error_flags_[flaglist[i]] = ""; // clear the error message
- } else if (undefined_names_.find(no_version) != undefined_names_.end()) {
- error_flags_[no_version] = "";
- }
- }
- }
- // Likewise, if they decided to allow reparsing, all undefined-names
- // are ok; we just silently ignore them now, and hope that a future
- // parse will pick them up somehow.
- if (allow_command_line_reparsing) {
- for (map<string, string>::const_iterator it = undefined_names_.begin();
- it != undefined_names_.end(); ++it)
- error_flags_[it->first] = ""; // clear the error message
- }
-
- bool found_error = false;
- string error_message;
- for (map<string, string>::const_iterator it = error_flags_.begin();
- it != error_flags_.end(); ++it) {
- if (!it->second.empty()) {
- error_message.append(it->second.data(), it->second.size());
- found_error = true;
- }
- }
- if (found_error)
- ReportError(DO_NOT_DIE, "%s", error_message.c_str());
- return found_error;
-}
-
-string CommandLineFlagParser::ProcessOptionsFromStringLocked(
- const string& contentdata, FlagSettingMode set_mode) {
- string retval;
- const char* flagfile_contents = contentdata.c_str();
- bool flags_are_relevant = true; // set to false when filenames don't match
- bool in_filename_section = false;
-
- const char* line_end = flagfile_contents;
- // We read this file a line at a time.
- for (; line_end; flagfile_contents = line_end + 1) {
- while (*flagfile_contents && isspace(*flagfile_contents))
- ++flagfile_contents;
- line_end = strchr(flagfile_contents, '\n');
- size_t len = line_end ? line_end - flagfile_contents
- : strlen(flagfile_contents);
- string line(flagfile_contents, len);
-
- // Each line can be one of four things:
- // 1) A comment line -- we skip it
- // 2) An empty line -- we skip it
- // 3) A list of filenames -- starts a new filenames+flags section
- // 4) A --flag=value line -- apply if previous filenames match
- if (line.empty() || line[0] == '#') {
- // comment or empty line; just ignore
-
- } else if (line[0] == '-') { // flag
- in_filename_section = false; // instead, it was a flag-line
- if (!flags_are_relevant) // skip this flag; applies to someone else
- continue;
-
- const char* name_and_val = line.c_str() + 1; // skip the leading -
- if (*name_and_val == '-')
- name_and_val++; // skip second - too
- string key;
- const char* value;
- string error_message;
- CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val,
- &key, &value,
- &error_message);
- // By API, errors parsing flagfile lines are silently ignored.
- if (flag == NULL) {
- // "WARNING: flagname '" + key + "' not found\n"
- } else if (value == NULL) {
- // "WARNING: flagname '" + key + "' missing a value\n"
- } else {
- retval += ProcessSingleOptionLocked(flag, value, set_mode);
- }
-
- } else { // a filename!
- if (!in_filename_section) { // start over: assume filenames don't match
- in_filename_section = true;
- flags_are_relevant = false;
- }
-
- // Split the line up at spaces into glob-patterns
- const char* space = line.c_str(); // just has to be non-NULL
- for (const char* word = line.c_str(); *space; word = space+1) {
- if (flags_are_relevant) // we can stop as soon as we match
- break;
- space = strchr(word, ' ');
- if (space == NULL)
- space = word + strlen(word);
- const string glob(word, space - word);
- // We try matching both against the full argv0 and basename(argv0)
- if (glob == ProgramInvocationName() // small optimization
- || glob == ProgramInvocationShortName()
-#if defined(HAVE_FNMATCH_H)
- || fnmatch(glob.c_str(), ProgramInvocationName(), FNM_PATHNAME) == 0
- || fnmatch(glob.c_str(), ProgramInvocationShortName(), FNM_PATHNAME) == 0
-#elif defined(HAVE_SHLWAPI_H)
- || PathMatchSpec(glob.c_str(), ProgramInvocationName())
- || PathMatchSpec(glob.c_str(), ProgramInvocationShortName())
-#endif
- ) {
- flags_are_relevant = true;
- }
- }
- }
- }
- return retval;
-}
-
-// --------------------------------------------------------------------
-// GetFromEnv()
-// AddFlagValidator()
-// These are helper functions for routines like BoolFromEnv() and
-// RegisterFlagValidator, defined below. They're defined here so
-// they can live in the unnamed namespace (which makes friendship
-// declarations for these classes possible).
-// --------------------------------------------------------------------
-
-template<typename T>
-T GetFromEnv(const char *varname, const char* type, T dflt) {
- std::string valstr;
- if (SafeGetEnv(varname, valstr)) {
- FlagValue ifv(new T, type, true);
- if (!ifv.ParseFrom(valstr.c_str())) {
- ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n",
- varname, valstr.c_str());
- }
- return OTHER_VALUE_AS(ifv, T);
- } else return dflt;
-}
-
-bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
- // We want a lock around this routine, in case two threads try to
- // add a validator (hopefully the same one!) at once. We could use
- // our own thread, but we need to loook at the registry anyway, so
- // we just steal that one.
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
- // First, find the flag whose current-flag storage is 'flag'.
- // This is the CommandLineFlag whose current_->value_buffer_ == flag
- CommandLineFlag* flag = registry->FindFlagViaPtrLocked(flag_ptr);
- if (!flag) {
- LOG(WARNING) << "Ignoring RegisterValidateFunction() for flag pointer "
- << flag_ptr << ": no flag found at that address";
- return false;
- } else if (validate_fn_proto == flag->validate_function()) {
- return true; // ok to register the same function over and over again
- } else if (validate_fn_proto != NULL && flag->validate_function() != NULL) {
- LOG(WARNING) << "Ignoring RegisterValidateFunction() for flag '"
- << flag->name() << "': validate-fn already registered";
- return false;
- } else {
- flag->validate_fn_proto_ = validate_fn_proto;
- return true;
- }
-}
-
-} // end unnamed namespaces
-
-
-// Now define the functions that are exported via the .h file
-
-// --------------------------------------------------------------------
-// FlagRegisterer
-// This class exists merely to have a global constructor (the
-// kind that runs before main(), that goes an initializes each
-// flag that's been declared. Note that it's very important we
-// don't have a destructor that deletes flag_, because that would
-// cause us to delete current_storage/defvalue_storage as well,
-// which can cause a crash if anything tries to access the flag
-// values in a global destructor.
-// --------------------------------------------------------------------
-
-FlagRegisterer::FlagRegisterer(const char* name, const char* type,
- const char* help, const char* filename,
- void* current_storage, void* defvalue_storage) {
- if (help == NULL)
- help = "";
- // FlagValue expects the type-name to not include any namespace
- // components, so we get rid of those, if any.
- if (strchr(type, ':'))
- type = strrchr(type, ':') + 1;
- FlagValue* current = new FlagValue(current_storage, type, false);
- FlagValue* defvalue = new FlagValue(defvalue_storage, type, false);
- // Importantly, flag_ will never be deleted, so storage is always good.
- CommandLineFlag* flag = new CommandLineFlag(name, help, filename,
- current, defvalue);
- FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry
-}
-
-// --------------------------------------------------------------------
-// GetAllFlags()
-// The main way the FlagRegistry class exposes its data. This
-// returns, as strings, all the info about all the flags in
-// the main registry, sorted first by filename they are defined
-// in, and then by flagname.
-// --------------------------------------------------------------------
-
-struct FilenameFlagnameCmp {
- bool operator()(const CommandLineFlagInfo& a,
- const CommandLineFlagInfo& b) const {
- int cmp = strcmp(a.filename.c_str(), b.filename.c_str());
- if (cmp == 0)
- cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key
- return cmp < 0;
- }
-};
-
-void GetAllFlags(vector<CommandLineFlagInfo>* OUTPUT) {
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- registry->Lock();
- for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
- i != registry->flags_.end(); ++i) {
- CommandLineFlagInfo fi;
- i->second->FillCommandLineFlagInfo(&fi);
- OUTPUT->push_back(fi);
- }
- registry->Unlock();
- // Now sort the flags, first by filename they occur in, then alphabetically
- sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp());
-}
-
-// --------------------------------------------------------------------
-// SetArgv()
-// GetArgvs()
-// GetArgv()
-// GetArgv0()
-// ProgramInvocationName()
-// ProgramInvocationShortName()
-// SetUsageMessage()
-// ProgramUsage()
-// Functions to set and get argv. Typically the setter is called
-// by ParseCommandLineFlags. Also can get the ProgramUsage string,
-// set by SetUsageMessage.
-// --------------------------------------------------------------------
-
-// These values are not protected by a Mutex because they are normally
-// set only once during program startup.
-static const char* argv0 = "UNKNOWN"; // just the program name
-static const char* cmdline = ""; // the entire command-line
-static vector<string> argvs;
-static uint32 argv_sum = 0;
-static const char* program_usage = NULL;
-
-void SetArgv(int argc, const char** argv) {
- static bool called_set_argv = false;
- if (called_set_argv) // we already have an argv for you
- return;
-
- called_set_argv = true;
-
- assert(argc > 0); // every program has at least a progname
- argv0 = strdup(argv[0]); // small memory leak, but fn only called once
- assert(argv0);
-
- string cmdline_string; // easier than doing strcats
- for (int i = 0; i < argc; i++) {
- if (i != 0) {
- cmdline_string += " ";
- }
- cmdline_string += argv[i];
- argvs.push_back(argv[i]);
- }
- cmdline = strdup(cmdline_string.c_str()); // another small memory leak
- assert(cmdline);
-
- // Compute a simple sum of all the chars in argv
- for (const char* c = cmdline; *c; c++)
- argv_sum += *c;
-}
-
-const vector<string>& GetArgvs() { return argvs; }
-const char* GetArgv() { return cmdline; }
-const char* GetArgv0() { return argv0; }
-uint32 GetArgvSum() { return argv_sum; }
-const char* ProgramInvocationName() { // like the GNU libc fn
- return GetArgv0();
-}
-const char* ProgramInvocationShortName() { // like the GNU libc fn
- const char* slash = strrchr(argv0, '/');
-#ifdef OS_WINDOWS
- if (!slash) slash = strrchr(argv0, '\\');
-#endif
- return slash ? slash + 1 : argv0;
-}
-
-void SetUsageMessage(const string& usage) {
- if (program_usage != NULL)
- ReportError(DIE, "ERROR: SetUsageMessage() called twice\n");
- program_usage = strdup(usage.c_str()); // small memory leak
-}
-
-const char* ProgramUsage() {
- if (program_usage) {
- return program_usage;
- }
- return "Warning: SetUsageMessage() never called";
-}
-
-// --------------------------------------------------------------------
-// SetVersionString()
-// VersionString()
-// --------------------------------------------------------------------
-
-static const char* version_string = NULL;
-
-void SetVersionString(const string& version) {
- if (version_string != NULL)
- ReportError(DIE, "ERROR: SetVersionString() called twice\n");
- version_string = strdup(version.c_str()); // small memory leak
-}
-
-const char* VersionString() {
- return version_string ? version_string : "";
-}
-
-
-// --------------------------------------------------------------------
-// GetCommandLineOption()
-// GetCommandLineFlagInfo()
-// GetCommandLineFlagInfoOrDie()
-// SetCommandLineOption()
-// SetCommandLineOptionWithMode()
-// The programmatic way to set a flag's value, using a string
-// for its name rather than the variable itself (that is,
-// SetCommandLineOption("foo", x) rather than FLAGS_foo = x).
-// There's also a bit more flexibility here due to the various
-// set-modes, but typically these are used when you only have
-// that flag's name as a string, perhaps at runtime.
-// All of these work on the default, global registry.
-// For GetCommandLineOption, return false if no such flag
-// is known, true otherwise. We clear "value" if a suitable
-// flag is found.
-// --------------------------------------------------------------------
-
-
-bool GetCommandLineOption(const char* name, string* value) {
- if (NULL == name)
- return false;
- assert(value);
-
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
- CommandLineFlag* flag = registry->FindFlagLocked(name);
- if (flag == NULL) {
- return false;
- } else {
- *value = flag->current_value();
- return true;
- }
-}
-
-bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) {
- if (NULL == name) return false;
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
- CommandLineFlag* flag = registry->FindFlagLocked(name);
- if (flag == NULL) {
- return false;
- } else {
- assert(OUTPUT);
- flag->FillCommandLineFlagInfo(OUTPUT);
- return true;
- }
-}
-
-CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) {
- CommandLineFlagInfo info;
- if (!GetCommandLineFlagInfo(name, &info)) {
- fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name);
- gflags_exitfunc(1); // almost certainly gflags_exitfunc()
- }
- return info;
-}
-
-string SetCommandLineOptionWithMode(const char* name, const char* value,
- FlagSettingMode set_mode) {
- string result;
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagRegistryLock frl(registry);
- CommandLineFlag* flag = registry->FindFlagLocked(name);
- if (flag) {
- CommandLineFlagParser parser(registry);
- result = parser.ProcessSingleOptionLocked(flag, value, set_mode);
- if (!result.empty()) { // in the error case, we've already logged
- // Could consider logging this change
- }
- }
- // The API of this function is that we return empty string on error
- return result;
-}
-
-string SetCommandLineOption(const char* name, const char* value) {
- return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE);
-}
-
-// --------------------------------------------------------------------
-// FlagSaver
-// FlagSaverImpl
-// This class stores the states of all flags at construct time,
-// and restores all flags to that state at destruct time.
-// Its major implementation challenge is that it never modifies
-// pointers in the 'main' registry, so global FLAG_* vars always
-// point to the right place.
-// --------------------------------------------------------------------
-
-class FlagSaverImpl {
- public:
- // Constructs an empty FlagSaverImpl object.
- explicit FlagSaverImpl(FlagRegistry* main_registry)
- : main_registry_(main_registry) { }
- ~FlagSaverImpl() {
- // reclaim memory from each of our CommandLineFlags
- vector<CommandLineFlag*>::const_iterator it;
- for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it)
- delete *it;
- }
-
- // Saves the flag states from the flag registry into this object.
- // It's an error to call this more than once.
- // Must be called when the registry mutex is not held.
- void SaveFromRegistry() {
- FlagRegistryLock frl(main_registry_);
- assert(backup_registry_.empty()); // call only once!
- for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin();
- it != main_registry_->flags_.end();
- ++it) {
- const CommandLineFlag* main = it->second;
- // Sets up all the const variables in backup correctly
- CommandLineFlag* backup = new CommandLineFlag(
- main->name(), main->help(), main->filename(),
- main->current_->New(), main->defvalue_->New());
- // Sets up all the non-const variables in backup correctly
- backup->CopyFrom(*main);
- backup_registry_.push_back(backup); // add it to a convenient list
- }
- }
-
- // Restores the saved flag states into the flag registry. We
- // assume no flags were added or deleted from the registry since
- // the SaveFromRegistry; if they were, that's trouble! Must be
- // called when the registry mutex is not held.
- void RestoreToRegistry() {
- FlagRegistryLock frl(main_registry_);
- vector<CommandLineFlag*>::const_iterator it;
- for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) {
- CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name());
- if (main != NULL) { // if NULL, flag got deleted from registry(!)
- main->CopyFrom(**it);
- }
- }
- }
-
- private:
- FlagRegistry* const main_registry_;
- vector<CommandLineFlag*> backup_registry_;
-
- FlagSaverImpl(const FlagSaverImpl&); // no copying!
- void operator=(const FlagSaverImpl&);
-};
-
-FlagSaver::FlagSaver()
- : impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) {
- impl_->SaveFromRegistry();
-}
-
-FlagSaver::~FlagSaver() {
- impl_->RestoreToRegistry();
- delete impl_;
-}
-
-
-// --------------------------------------------------------------------
-// CommandlineFlagsIntoString()
-// ReadFlagsFromString()
-// AppendFlagsIntoFile()
-// ReadFromFlagsFile()
-// These are mostly-deprecated routines that stick the
-// commandline flags into a file/string and read them back
-// out again. I can see a use for CommandlineFlagsIntoString,
-// for creating a flagfile, but the rest don't seem that useful
-// -- some, I think, are a poor-man's attempt at FlagSaver --
-// and are included only until we can delete them from callers.
-// Note they don't save --flagfile flags (though they do save
-// the result of having called the flagfile, of course).
-// --------------------------------------------------------------------
-
-static string TheseCommandlineFlagsIntoString(
- const vector<CommandLineFlagInfo>& flags) {
- vector<CommandLineFlagInfo>::const_iterator i;
-
- size_t retval_space = 0;
- for (i = flags.begin(); i != flags.end(); ++i) {
- // An (over)estimate of how much space it will take to print this flag
- retval_space += i->name.length() + i->current_value.length() + 5;
- }
-
- string retval;
- retval.reserve(retval_space);
- for (i = flags.begin(); i != flags.end(); ++i) {
- retval += "--";
- retval += i->name;
- retval += "=";
- retval += i->current_value;
- retval += "\n";
- }
- return retval;
-}
-
-string CommandlineFlagsIntoString() {
- vector<CommandLineFlagInfo> sorted_flags;
- GetAllFlags(&sorted_flags);
- return TheseCommandlineFlagsIntoString(sorted_flags);
-}
-
-bool ReadFlagsFromString(const string& flagfilecontents,
- const char* /*prog_name*/, // TODO(csilvers): nix this
- bool errors_are_fatal) {
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- FlagSaverImpl saved_states(registry);
- saved_states.SaveFromRegistry();
-
- CommandLineFlagParser parser(registry);
- registry->Lock();
- parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE);
- registry->Unlock();
- // Should we handle --help and such when reading flags from a string? Sure.
- HandleCommandLineHelpFlags();
- if (parser.ReportErrors()) {
- // Error. Restore all global flags to their previous values.
- if (errors_are_fatal)
- gflags_exitfunc(1);
- saved_states.RestoreToRegistry();
- return false;
- }
- return true;
-}
-
-// TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName()
-bool AppendFlagsIntoFile(const string& filename, const char *prog_name) {
- FILE *fp;
- if (SafeFOpen(&fp, filename.c_str(), "a") != 0) {
- return false;
- }
-
- if (prog_name)
- fprintf(fp, "%s\n", prog_name);
-
- vector<CommandLineFlagInfo> flags;
- GetAllFlags(&flags);
- // But we don't want --flagfile, which leads to weird recursion issues
- vector<CommandLineFlagInfo>::iterator i;
- for (i = flags.begin(); i != flags.end(); ++i) {
- if (strcmp(i->name.c_str(), "flagfile") == 0) {
- flags.erase(i);
- break;
- }
- }
- fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str());
-
- fclose(fp);
- return true;
-}
-
-bool ReadFromFlagsFile(const string& filename, const char* prog_name,
- bool errors_are_fatal) {
- return ReadFlagsFromString(ReadFileIntoString(filename.c_str()),
- prog_name, errors_are_fatal);
-}
-
-
-// --------------------------------------------------------------------
-// BoolFromEnv()
-// Int32FromEnv()
-// Int64FromEnv()
-// Uint64FromEnv()
-// DoubleFromEnv()
-// StringFromEnv()
-// Reads the value from the environment and returns it.
-// We use an FlagValue to make the parsing easy.
-// Example usage:
-// DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever");
-// --------------------------------------------------------------------
-
-bool BoolFromEnv(const char *v, bool dflt) {
- return GetFromEnv(v, "bool", dflt);
-}
-int32 Int32FromEnv(const char *v, int32 dflt) {
- return GetFromEnv(v, "int32", dflt);
-}
-int64 Int64FromEnv(const char *v, int64 dflt) {
- return GetFromEnv(v, "int64", dflt);
-}
-uint64 Uint64FromEnv(const char *v, uint64 dflt) {
- return GetFromEnv(v, "uint64", dflt);
-}
-double DoubleFromEnv(const char *v, double dflt) {
- return GetFromEnv(v, "double", dflt);
-}
-
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4996) // ignore getenv security warning
-#endif
-const char *StringFromEnv(const char *varname, const char *dflt) {
- const char* const val = getenv(varname);
- return val ? val : dflt;
-}
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
-
-
-// --------------------------------------------------------------------
-// RegisterFlagValidator()
-// RegisterFlagValidator() is the function that clients use to
-// 'decorate' a flag with a validation function. Once this is
-// done, every time the flag is set (including when the flag
-// is parsed from argv), the validator-function is called.
-// These functions return true if the validator was added
-// successfully, or false if not: the flag already has a validator,
-// (only one allowed per flag), the 1st arg isn't a flag, etc.
-// This function is not thread-safe.
-// --------------------------------------------------------------------
-
-bool RegisterFlagValidator(const bool* flag,
- bool (*validate_fn)(const char*, bool)) {
- return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
-}
-bool RegisterFlagValidator(const int32* flag,
- bool (*validate_fn)(const char*, int32)) {
- return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
-}
-bool RegisterFlagValidator(const int64* flag,
- bool (*validate_fn)(const char*, int64)) {
- return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
-}
-bool RegisterFlagValidator(const uint64* flag,
- bool (*validate_fn)(const char*, uint64)) {
- return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
-}
-bool RegisterFlagValidator(const double* flag,
- bool (*validate_fn)(const char*, double)) {
- return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
-}
-bool RegisterFlagValidator(const string* flag,
- bool (*validate_fn)(const char*, const string&)) {
- return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
-}
-
-
-// --------------------------------------------------------------------
-// ParseCommandLineFlags()
-// ParseCommandLineNonHelpFlags()
-// HandleCommandLineHelpFlags()
-// This is the main function called from main(), to actually
-// parse the commandline. It modifies argc and argv as described
-// at the top of gflags.h. You can also divide this
-// function into two parts, if you want to do work between
-// the parsing of the flags and the printing of any help output.
-// --------------------------------------------------------------------
-
-static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv,
- bool remove_flags, bool do_report) {
- SetArgv(*argc, const_cast<const char**>(*argv)); // save it for later
-
- FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
- CommandLineFlagParser parser(registry);
-
- // When we parse the commandline flags, we'll handle --flagfile,
- // --tryfromenv, etc. as we see them (since flag-evaluation order
- // may be important). But sometimes apps set FLAGS_tryfromenv/etc.
- // manually before calling ParseCommandLineFlags. We want to evaluate
- // those too, as if they were the first flags on the commandline.
- registry->Lock();
- parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE);
- // Last arg here indicates whether flag-not-found is a fatal error or not
- parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true);
- parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false);
- registry->Unlock();
-
- // Now get the flags specified on the commandline
- const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags);
-
- if (do_report)
- HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc.
-
- // See if any of the unset flags fail their validation checks
- parser.ValidateAllFlags();
-
- if (parser.ReportErrors()) // may cause us to exit on illegal flags
- gflags_exitfunc(1);
- return r;
-}
-
-uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) {
- return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true);
-}
-
-uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv,
- bool remove_flags) {
- return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false);
-}
-
-// --------------------------------------------------------------------
-// AllowCommandLineReparsing()
-// ReparseCommandLineNonHelpFlags()
-// This is most useful for shared libraries. The idea is if
-// a flag is defined in a shared library that is dlopen'ed
-// sometime after main(), you can ParseCommandLineFlags before
-// the dlopen, then ReparseCommandLineNonHelpFlags() after the
-// dlopen, to get the new flags. But you have to explicitly
-// Allow() it; otherwise, you get the normal default behavior
-// of unrecognized flags calling a fatal error.
-// TODO(csilvers): this isn't used. Just delete it?
-// --------------------------------------------------------------------
-
-void AllowCommandLineReparsing() {
- allow_command_line_reparsing = true;
-}
-
-void ReparseCommandLineNonHelpFlags() {
- // We make a copy of argc and argv to pass in
- const vector<string>& argvs = GetArgvs();
- int tmp_argc = static_cast<int>(argvs.size());
- char** tmp_argv = new char* [tmp_argc + 1];
- for (int i = 0; i < tmp_argc; ++i)
- tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup
-
- ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false);
-
- for (int i = 0; i < tmp_argc; ++i)
- free(tmp_argv[i]);
- delete[] tmp_argv;
-}
-
-void ShutDownCommandLineFlags() {
- FlagRegistry::DeleteGlobalRegistry();
-}
-
-
-} // namespace GFLAGS_NAMESPACE
diff --git a/extern/libmv/third_party/gflags/gflags/gflags.h b/extern/libmv/third_party/gflags/gflags/gflags.h
deleted file mode 100644
index 797a54cac52..00000000000
--- a/extern/libmv/third_party/gflags/gflags/gflags.h
+++ /dev/null
@@ -1,568 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// ---
-// Revamped and reorganized by Craig Silverstein
-//
-// This is the file that should be included by any file which declares
-// or defines a command line flag or wants to parse command line flags
-// or print a program usage message (which will include information about
-// flags). Executive summary, in the form of an example foo.cc file:
-//
-// #include "foo.h" // foo.h has a line "DECLARE_int32(start);"
-// #include "validators.h" // hypothetical file defining ValidateIsFile()
-//
-// DEFINE_int32(end, 1000, "The last record to read");
-//
-// DEFINE_string(filename, "my_file.txt", "The file to read");
-// // Crash if the specified file does not exist.
-// static bool dummy = RegisterFlagValidator(&FLAGS_filename,
-// &ValidateIsFile);
-//
-// DECLARE_bool(verbose); // some other file has a DEFINE_bool(verbose, ...)
-//
-// void MyFunc() {
-// if (FLAGS_verbose) printf("Records %d-%d\n", FLAGS_start, FLAGS_end);
-// }
-//
-// Then, at the command-line:
-// ./foo --noverbose --start=5 --end=100
-//
-// For more details, see
-// doc/gflags.html
-//
-// --- A note about thread-safety:
-//
-// We describe many functions in this routine as being thread-hostile,
-// thread-compatible, or thread-safe. Here are the meanings we use:
-//
-// thread-safe: it is safe for multiple threads to call this routine
-// (or, when referring to a class, methods of this class)
-// concurrently.
-// thread-hostile: it is not safe for multiple threads to call this
-// routine (or methods of this class) concurrently. In gflags,
-// most thread-hostile routines are intended to be called early in,
-// or even before, main() -- that is, before threads are spawned.
-// thread-compatible: it is safe for multiple threads to read from
-// this variable (when applied to variables), or to call const
-// methods of this class (when applied to classes), as long as no
-// other thread is writing to the variable or calling non-const
-// methods of this class.
-
-#ifndef GFLAGS_GFLAGS_H_
-#define GFLAGS_GFLAGS_H_
-
-#include <string>
-#include <vector>
-
-#include "gflags_declare.h" // IWYU pragma: export
-
-
-// We always want to export variables defined in user code
-#ifndef GFLAGS_DLL_DEFINE_FLAG
-# if 0 && defined(_MSC_VER)
-# define GFLAGS_DLL_DEFINE_FLAG __declspec(dllexport)
-# else
-# define GFLAGS_DLL_DEFINE_FLAG
-# endif
-#endif
-
-
-namespace gflags {
-
-
-// --------------------------------------------------------------------
-// To actually define a flag in a file, use DEFINE_bool,
-// DEFINE_string, etc. at the bottom of this file. You may also find
-// it useful to register a validator with the flag. This ensures that
-// when the flag is parsed from the commandline, or is later set via
-// SetCommandLineOption, we call the validation function. It is _not_
-// called when you assign the value to the flag directly using the = operator.
-//
-// The validation function should return true if the flag value is valid, and
-// false otherwise. If the function returns false for the new setting of the
-// flag, the flag will retain its current value. If it returns false for the
-// default value, ParseCommandLineFlags() will die.
-//
-// This function is safe to call at global construct time (as in the
-// example below).
-//
-// Example use:
-// static bool ValidatePort(const char* flagname, int32 value) {
-// if (value > 0 && value < 32768) // value is ok
-// return true;
-// printf("Invalid value for --%s: %d\n", flagname, (int)value);
-// return false;
-// }
-// DEFINE_int32(port, 0, "What port to listen on");
-// static bool dummy = RegisterFlagValidator(&FLAGS_port, &ValidatePort);
-
-// Returns true if successfully registered, false if not (because the
-// first argument doesn't point to a command-line flag, or because a
-// validator is already registered for this flag).
-extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const bool* flag, bool (*validate_fn)(const char*, bool));
-extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const int32* flag, bool (*validate_fn)(const char*, int32));
-extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const int64* flag, bool (*validate_fn)(const char*, int64));
-extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const uint64* flag, bool (*validate_fn)(const char*, uint64));
-extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const double* flag, bool (*validate_fn)(const char*, double));
-extern GFLAGS_DLL_DECL bool RegisterFlagValidator(const std::string* flag, bool (*validate_fn)(const char*, const std::string&));
-
-// Convenience macro for the registration of a flag validator
-#define DEFINE_validator(name, validator) \
- static const bool name##_validator_registered = \
- gflags::RegisterFlagValidator(&FLAGS_##name, validator)
-
-
-// --------------------------------------------------------------------
-// These methods are the best way to get access to info about the
-// list of commandline flags. Note that these routines are pretty slow.
-// GetAllFlags: mostly-complete info about the list, sorted by file.
-// ShowUsageWithFlags: pretty-prints the list to stdout (what --help does)
-// ShowUsageWithFlagsRestrict: limit to filenames with restrict as a substr
-//
-// In addition to accessing flags, you can also access argv[0] (the program
-// name) and argv (the entire commandline), which we sock away a copy of.
-// These variables are static, so you should only set them once.
-//
-// No need to export this data only structure from DLL, avoiding VS warning 4251.
-struct CommandLineFlagInfo {
- std::string name; // the name of the flag
- std::string type; // the type of the flag: int32, etc
- std::string description; // the "help text" associated with the flag
- std::string current_value; // the current value, as a string
- std::string default_value; // the default value, as a string
- std::string filename; // 'cleaned' version of filename holding the flag
- bool has_validator_fn; // true if RegisterFlagValidator called on this flag
- bool is_default; // true if the flag has the default value and
- // has not been set explicitly from the cmdline
- // or via SetCommandLineOption
- const void* flag_ptr; // pointer to the flag's current value (i.e. FLAGS_foo)
-};
-
-// Using this inside of a validator is a recipe for a deadlock.
-// TODO(user) Fix locking when validators are running, to make it safe to
-// call validators during ParseAllFlags.
-// Also make sure then to uncomment the corresponding unit test in
-// gflags_unittest.sh
-extern GFLAGS_DLL_DECL void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT);
-// These two are actually defined in gflags_reporting.cc.
-extern GFLAGS_DLL_DECL void ShowUsageWithFlags(const char *argv0); // what --help does
-extern GFLAGS_DLL_DECL void ShowUsageWithFlagsRestrict(const char *argv0, const char *restrict);
-
-// Create a descriptive string for a flag.
-// Goes to some trouble to make pretty line breaks.
-extern GFLAGS_DLL_DECL std::string DescribeOneFlag(const CommandLineFlagInfo& flag);
-
-// Thread-hostile; meant to be called before any threads are spawned.
-extern GFLAGS_DLL_DECL void SetArgv(int argc, const char** argv);
-
-// The following functions are thread-safe as long as SetArgv() is
-// only called before any threads start.
-extern GFLAGS_DLL_DECL const std::vector<std::string>& GetArgvs();
-extern GFLAGS_DLL_DECL const char* GetArgv(); // all of argv as a string
-extern GFLAGS_DLL_DECL const char* GetArgv0(); // only argv0
-extern GFLAGS_DLL_DECL uint32 GetArgvSum(); // simple checksum of argv
-extern GFLAGS_DLL_DECL const char* ProgramInvocationName(); // argv0, or "UNKNOWN" if not set
-extern GFLAGS_DLL_DECL const char* ProgramInvocationShortName(); // basename(argv0)
-
-// ProgramUsage() is thread-safe as long as SetUsageMessage() is only
-// called before any threads start.
-extern GFLAGS_DLL_DECL const char* ProgramUsage(); // string set by SetUsageMessage()
-
-// VersionString() is thread-safe as long as SetVersionString() is only
-// called before any threads start.
-extern GFLAGS_DLL_DECL const char* VersionString(); // string set by SetVersionString()
-
-
-
-// --------------------------------------------------------------------
-// Normally you access commandline flags by just saying "if (FLAGS_foo)"
-// or whatever, and set them by calling "FLAGS_foo = bar" (or, more
-// commonly, via the DEFINE_foo macro). But if you need a bit more
-// control, we have programmatic ways to get/set the flags as well.
-// These programmatic ways to access flags are thread-safe, but direct
-// access is only thread-compatible.
-
-// Return true iff the flagname was found.
-// OUTPUT is set to the flag's value, or unchanged if we return false.
-extern GFLAGS_DLL_DECL bool GetCommandLineOption(const char* name, std::string* OUTPUT);
-
-// Return true iff the flagname was found. OUTPUT is set to the flag's
-// CommandLineFlagInfo or unchanged if we return false.
-extern GFLAGS_DLL_DECL bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT);
-
-// Return the CommandLineFlagInfo of the flagname. exit() if name not found.
-// Example usage, to check if a flag's value is currently the default value:
-// if (GetCommandLineFlagInfoOrDie("foo").is_default) ...
-extern GFLAGS_DLL_DECL CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name);
-
-enum GFLAGS_DLL_DECL FlagSettingMode {
- // update the flag's value (can call this multiple times).
- SET_FLAGS_VALUE,
- // update the flag's value, but *only if* it has not yet been updated
- // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
- SET_FLAG_IF_DEFAULT,
- // set the flag's default value to this. If the flag has not yet updated
- // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
- // change the flag's current value to the new default value as well.
- SET_FLAGS_DEFAULT
-};
-
-// Set a particular flag ("command line option"). Returns a string
-// describing the new value that the option has been set to. The
-// return value API is not well-specified, so basically just depend on
-// it to be empty if the setting failed for some reason -- the name is
-// not a valid flag name, or the value is not a valid value -- and
-// non-empty else.
-
-// SetCommandLineOption uses set_mode == SET_FLAGS_VALUE (the common case)
-extern GFLAGS_DLL_DECL std::string SetCommandLineOption (const char* name, const char* value);
-extern GFLAGS_DLL_DECL std::string SetCommandLineOptionWithMode(const char* name, const char* value, FlagSettingMode set_mode);
-
-
-// --------------------------------------------------------------------
-// Saves the states (value, default value, whether the user has set
-// the flag, registered validators, etc) of all flags, and restores
-// them when the FlagSaver is destroyed. This is very useful in
-// tests, say, when you want to let your tests change the flags, but
-// make sure that they get reverted to the original states when your
-// test is complete.
-//
-// Example usage:
-// void TestFoo() {
-// FlagSaver s1;
-// FLAG_foo = false;
-// FLAG_bar = "some value";
-//
-// // test happens here. You can return at any time
-// // without worrying about restoring the FLAG values.
-// }
-//
-// Note: This class is marked with GFLAGS_ATTRIBUTE_UNUSED because all
-// the work is done in the constructor and destructor, so in the standard
-// usage example above, the compiler would complain that it's an
-// unused variable.
-//
-// This class is thread-safe. However, its destructor writes to
-// exactly the set of flags that have changed value during its
-// lifetime, so concurrent _direct_ access to those flags
-// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe.
-
-class GFLAGS_DLL_DECL FlagSaver {
- public:
- FlagSaver();
- ~FlagSaver();
-
- private:
- class FlagSaverImpl* impl_; // we use pimpl here to keep API steady
-
- FlagSaver(const FlagSaver&); // no copying!
- void operator=(const FlagSaver&);
-};
-
-// --------------------------------------------------------------------
-// Some deprecated or hopefully-soon-to-be-deprecated functions.
-
-// This is often used for logging. TODO(csilvers): figure out a better way
-extern GFLAGS_DLL_DECL std::string CommandlineFlagsIntoString();
-// Usually where this is used, a FlagSaver should be used instead.
-extern GFLAGS_DLL_DECL
-bool ReadFlagsFromString(const std::string& flagfilecontents,
- const char* prog_name,
- bool errors_are_fatal); // uses SET_FLAGS_VALUE
-
-// These let you manually implement --flagfile functionality.
-// DEPRECATED.
-extern GFLAGS_DLL_DECL bool AppendFlagsIntoFile(const std::string& filename, const char* prog_name);
-extern GFLAGS_DLL_DECL bool ReadFromFlagsFile(const std::string& filename, const char* prog_name, bool errors_are_fatal); // uses SET_FLAGS_VALUE
-
-
-// --------------------------------------------------------------------
-// Useful routines for initializing flags from the environment.
-// In each case, if 'varname' does not exist in the environment
-// return defval. If 'varname' does exist but is not valid
-// (e.g., not a number for an int32 flag), abort with an error.
-// Otherwise, return the value. NOTE: for booleans, for true use
-// 't' or 'T' or 'true' or '1', for false 'f' or 'F' or 'false' or '0'.
-
-extern GFLAGS_DLL_DECL bool BoolFromEnv(const char *varname, bool defval);
-extern GFLAGS_DLL_DECL int32 Int32FromEnv(const char *varname, int32 defval);
-extern GFLAGS_DLL_DECL int64 Int64FromEnv(const char *varname, int64 defval);
-extern GFLAGS_DLL_DECL uint64 Uint64FromEnv(const char *varname, uint64 defval);
-extern GFLAGS_DLL_DECL double DoubleFromEnv(const char *varname, double defval);
-extern GFLAGS_DLL_DECL const char *StringFromEnv(const char *varname, const char *defval);
-
-
-// --------------------------------------------------------------------
-// The next two functions parse gflags from main():
-
-// Set the "usage" message for this program. For example:
-// string usage("This program does nothing. Sample usage:\n");
-// usage += argv[0] + " <uselessarg1> <uselessarg2>";
-// SetUsageMessage(usage);
-// Do not include commandline flags in the usage: we do that for you!
-// Thread-hostile; meant to be called before any threads are spawned.
-extern GFLAGS_DLL_DECL void SetUsageMessage(const std::string& usage);
-
-// Sets the version string, which is emitted with --version.
-// For instance: SetVersionString("1.3");
-// Thread-hostile; meant to be called before any threads are spawned.
-extern GFLAGS_DLL_DECL void SetVersionString(const std::string& version);
-
-
-// Looks for flags in argv and parses them. Rearranges argv to put
-// flags first, or removes them entirely if remove_flags is true.
-// If a flag is defined more than once in the command line or flag
-// file, the last definition is used. Returns the index (into argv)
-// of the first non-flag argument.
-// See top-of-file for more details on this function.
-#ifndef SWIG // In swig, use ParseCommandLineFlagsScript() instead.
-extern GFLAGS_DLL_DECL uint32 ParseCommandLineFlags(int *argc, char*** argv, bool remove_flags);
-#endif
-
-
-// Calls to ParseCommandLineNonHelpFlags and then to
-// HandleCommandLineHelpFlags can be used instead of a call to
-// ParseCommandLineFlags during initialization, in order to allow for
-// changing default values for some FLAGS (via
-// e.g. SetCommandLineOptionWithMode calls) between the time of
-// command line parsing and the time of dumping help information for
-// the flags as a result of command line parsing. If a flag is
-// defined more than once in the command line or flag file, the last
-// definition is used. Returns the index (into argv) of the first
-// non-flag argument. (If remove_flags is true, will always return 1.)
-extern GFLAGS_DLL_DECL uint32 ParseCommandLineNonHelpFlags(int *argc, char*** argv, bool remove_flags);
-
-// This is actually defined in gflags_reporting.cc.
-// This function is misnamed (it also handles --version, etc.), but
-// it's too late to change that now. :-(
-extern GFLAGS_DLL_DECL void HandleCommandLineHelpFlags(); // in gflags_reporting.cc
-
-// Allow command line reparsing. Disables the error normally
-// generated when an unknown flag is found, since it may be found in a
-// later parse. Thread-hostile; meant to be called before any threads
-// are spawned.
-extern GFLAGS_DLL_DECL void AllowCommandLineReparsing();
-
-// Reparse the flags that have not yet been recognized. Only flags
-// registered since the last parse will be recognized. Any flag value
-// must be provided as part of the argument using "=", not as a
-// separate command line argument that follows the flag argument.
-// Intended for handling flags from dynamically loaded libraries,
-// since their flags are not registered until they are loaded.
-extern GFLAGS_DLL_DECL void ReparseCommandLineNonHelpFlags();
-
-// Clean up memory allocated by flags. This is only needed to reduce
-// the quantity of "potentially leaked" reports emitted by memory
-// debugging tools such as valgrind. It is not required for normal
-// operation, or for the google perftools heap-checker. It must only
-// be called when the process is about to exit, and all threads that
-// might access flags are quiescent. Referencing flags after this is
-// called will have unexpected consequences. This is not safe to run
-// when multiple threads might be running: the function is
-// thread-hostile.
-extern GFLAGS_DLL_DECL void ShutDownCommandLineFlags();
-
-
-// --------------------------------------------------------------------
-// Now come the command line flag declaration/definition macros that
-// will actually be used. They're kind of hairy. A major reason
-// for this is initialization: we want people to be able to access
-// variables in global constructors and have that not crash, even if
-// their global constructor runs before the global constructor here.
-// (Obviously, we can't guarantee the flags will have the correct
-// default value in that case, but at least accessing them is safe.)
-// The only way to do that is have flags point to a static buffer.
-// So we make one, using a union to ensure proper alignment, and
-// then use placement-new to actually set up the flag with the
-// correct default value. In the same vein, we have to worry about
-// flag access in global destructors, so FlagRegisterer has to be
-// careful never to destroy the flag-values it constructs.
-//
-// Note that when we define a flag variable FLAGS_<name>, we also
-// preemptively define a junk variable, FLAGS_no<name>. This is to
-// cause a link-time error if someone tries to define 2 flags with
-// names like "logging" and "nologging". We do this because a bool
-// flag FLAG can be set from the command line to true with a "-FLAG"
-// argument, and to false with a "-noFLAG" argument, and so this can
-// potentially avert confusion.
-//
-// We also put flags into their own namespace. It is purposefully
-// named in an opaque way that people should have trouble typing
-// directly. The idea is that DEFINE puts the flag in the weird
-// namespace, and DECLARE imports the flag from there into the current
-// namespace. The net result is to force people to use DECLARE to get
-// access to a flag, rather than saying "extern GFLAGS_DLL_DECL bool FLAGS_whatever;"
-// or some such instead. We want this so we can put extra
-// functionality (like sanity-checking) in DECLARE if we want, and
-// make sure it is picked up everywhere.
-//
-// We also put the type of the variable in the namespace, so that
-// people can't DECLARE_int32 something that they DEFINE_bool'd
-// elsewhere.
-
-class GFLAGS_DLL_DECL FlagRegisterer {
- public:
- FlagRegisterer(const char* name, const char* type,
- const char* help, const char* filename,
- void* current_storage, void* defvalue_storage);
-};
-
-// If your application #defines STRIP_FLAG_HELP to a non-zero value
-// before #including this file, we remove the help message from the
-// binary file. This can reduce the size of the resulting binary
-// somewhat, and may also be useful for security reasons.
-
-extern GFLAGS_DLL_DECL const char kStrippedFlagHelp[];
-
-
-} // namespace gflags
-
-
-#ifndef SWIG // In swig, ignore the main flag declarations
-
-#if defined(STRIP_FLAG_HELP) && STRIP_FLAG_HELP > 0
-// Need this construct to avoid the 'defined but not used' warning.
-#define MAYBE_STRIPPED_HELP(txt) \
- (false ? (txt) : gflags::kStrippedFlagHelp)
-#else
-#define MAYBE_STRIPPED_HELP(txt) txt
-#endif
-
-// Each command-line flag has two variables associated with it: one
-// with the current value, and one with the default value. However,
-// we have a third variable, which is where value is assigned; it's a
-// constant. This guarantees that FLAG_##value is initialized at
-// static initialization time (e.g. before program-start) rather than
-// than global construction time (which is after program-start but
-// before main), at least when 'value' is a compile-time constant. We
-// use a small trick for the "default value" variable, and call it
-// FLAGS_no<name>. This serves the second purpose of assuring a
-// compile error if someone tries to define a flag named no<name>
-// which is illegal (--foo and --nofoo both affect the "foo" flag).
-#define DEFINE_VARIABLE(type, shorttype, name, value, help) \
- namespace fL##shorttype { \
- static const type FLAGS_nono##name = value; \
- /* We always want to export defined variables, dll or no */ \
- GFLAGS_DLL_DEFINE_FLAG type FLAGS_##name = FLAGS_nono##name; \
- type FLAGS_no##name = FLAGS_nono##name; \
- static gflags::FlagRegisterer o_##name( \
- #name, #type, MAYBE_STRIPPED_HELP(help), __FILE__, \
- &FLAGS_##name, &FLAGS_no##name); \
- } \
- using fL##shorttype::FLAGS_##name
-
-// For DEFINE_bool, we want to do the extra check that the passed-in
-// value is actually a bool, and not a string or something that can be
-// coerced to a bool. These declarations (no definition needed!) will
-// help us do that, and never evaluate From, which is important.
-// We'll use 'sizeof(IsBool(val))' to distinguish. This code requires
-// that the compiler have different sizes for bool & double. Since
-// this is not guaranteed by the standard, we check it with a
-// COMPILE_ASSERT.
-namespace fLB {
-struct CompileAssert {};
-typedef CompileAssert expected_sizeof_double_neq_sizeof_bool[
- (sizeof(double) != sizeof(bool)) ? 1 : -1];
-template<typename From> double GFLAGS_DLL_DECL IsBoolFlag(const From& from);
-GFLAGS_DLL_DECL bool IsBoolFlag(bool from);
-} // namespace fLB
-
-// Here are the actual DEFINE_*-macros. The respective DECLARE_*-macros
-// are in a separate include, gflags_declare.h, for reducing
-// the physical transitive size for DECLARE use.
-#define DEFINE_bool(name, val, txt) \
- namespace fLB { \
- typedef ::fLB::CompileAssert FLAG_##name##_value_is_not_a_bool[ \
- (sizeof(::fLB::IsBoolFlag(val)) != sizeof(double)) ? 1 : -1]; \
- } \
- DEFINE_VARIABLE(bool, B, name, val, txt)
-
-#define DEFINE_int32(name, val, txt) \
- DEFINE_VARIABLE(gflags::int32, I, \
- name, val, txt)
-
-#define DEFINE_int64(name, val, txt) \
- DEFINE_VARIABLE(gflags::int64, I64, \
- name, val, txt)
-
-#define DEFINE_uint64(name,val, txt) \
- DEFINE_VARIABLE(gflags::uint64, U64, \
- name, val, txt)
-
-#define DEFINE_double(name, val, txt) \
- DEFINE_VARIABLE(double, D, name, val, txt)
-
-// Strings are trickier, because they're not a POD, so we can't
-// construct them at static-initialization time (instead they get
-// constructed at global-constructor time, which is much later). To
-// try to avoid crashes in that case, we use a char buffer to store
-// the string, which we can static-initialize, and then placement-new
-// into it later. It's not perfect, but the best we can do.
-
-namespace fLS {
-
-inline clstring* dont_pass0toDEFINE_string(char *stringspot,
- const char *value) {
- return new(stringspot) clstring(value);
-}
-inline clstring* dont_pass0toDEFINE_string(char *stringspot,
- const clstring &value) {
- return new(stringspot) clstring(value);
-}
-inline clstring* dont_pass0toDEFINE_string(char *stringspot,
- int value);
-} // namespace fLS
-
-// We need to define a var named FLAGS_no##name so people don't define
-// --string and --nostring. And we need a temporary place to put val
-// so we don't have to evaluate it twice. Two great needs that go
-// great together!
-// The weird 'using' + 'extern' inside the fLS namespace is to work around
-// an unknown compiler bug/issue with the gcc 4.2.1 on SUSE 10. See
-// http://code.google.com/p/google-gflags/issues/detail?id=20
-#define DEFINE_string(name, val, txt) \
- namespace fLS { \
- using ::fLS::clstring; \
- static union { void* align; char s[sizeof(clstring)]; } s_##name[2]; \
- clstring* const FLAGS_no##name = ::fLS:: \
- dont_pass0toDEFINE_string(s_##name[0].s, \
- val); \
- static gflags::FlagRegisterer o_##name( \
- #name, "string", MAYBE_STRIPPED_HELP(txt), __FILE__, \
- s_##name[0].s, new (s_##name[1].s) clstring(*FLAGS_no##name)); \
- extern GFLAGS_DLL_DEFINE_FLAG clstring& FLAGS_##name; \
- using fLS::FLAGS_##name; \
- clstring& FLAGS_##name = *FLAGS_no##name; \
- } \
- using fLS::FLAGS_##name
-
-#endif // SWIG
-
-#endif // GFLAGS_GFLAGS_H_
diff --git a/extern/libmv/third_party/gflags/gflags/gflags_completions.h b/extern/libmv/third_party/gflags/gflags/gflags_completions.h
deleted file mode 100644
index 2fa0db6d48a..00000000000
--- a/extern/libmv/third_party/gflags/gflags/gflags_completions.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// ---
-
-//
-// Implement helpful bash-style command line flag completions
-//
-// ** Functional API:
-// HandleCommandLineCompletions() should be called early during
-// program startup, but after command line flag code has been
-// initialized, such as the beginning of HandleCommandLineHelpFlags().
-// It checks the value of the flag --tab_completion_word. If this
-// flag is empty, nothing happens here. If it contains a string,
-// however, then HandleCommandLineCompletions() will hijack the
-// process, attempting to identify the intention behind this
-// completion. Regardless of the outcome of this deduction, the
-// process will be terminated, similar to --helpshort flag
-// handling.
-//
-// ** Overview of Bash completions:
-// Bash can be told to programatically determine completions for the
-// current 'cursor word'. It does this by (in this case) invoking a
-// command with some additional arguments identifying the command
-// being executed, the word being completed, and the previous word
-// (if any). Bash then expects a sequence of output lines to be
-// printed to stdout. If these lines all contain a common prefix
-// longer than the cursor word, bash will replace the cursor word
-// with that common prefix, and display nothing. If there isn't such
-// a common prefix, bash will display the lines in pages using 'more'.
-//
-// ** Strategy taken for command line completions:
-// If we can deduce either the exact flag intended, or a common flag
-// prefix, we'll output exactly that. Otherwise, if information
-// must be displayed to the user, we'll take the opportunity to add
-// some helpful information beyond just the flag name (specifically,
-// we'll include the default flag value and as much of the flag's
-// description as can fit on a single terminal line width, as specified
-// by the flag --tab_completion_columns). Furthermore, we'll try to
-// make bash order the output such that the most useful or relevent
-// flags are the most likely to be shown at the top.
-//
-// ** Additional features:
-// To assist in finding that one really useful flag, substring matching
-// was implemented. Before pressing a <TAB> to get completion for the
-// current word, you can append one or more '?' to the flag to do
-// substring matching. Here's the semantics:
-// --foo<TAB> Show me all flags with names prefixed by 'foo'
-// --foo?<TAB> Show me all flags with 'foo' somewhere in the name
-// --foo??<TAB> Same as prior case, but also search in module
-// definition path for 'foo'
-// --foo???<TAB> Same as prior case, but also search in flag
-// descriptions for 'foo'
-// Finally, we'll trim the output to a relatively small number of
-// flags to keep bash quiet about the verbosity of output. If one
-// really wanted to see all possible matches, appending a '+' to the
-// search word will force the exhaustive list of matches to be printed.
-//
-// ** How to have bash accept completions from a binary:
-// Bash requires that it be informed about each command that programmatic
-// completion should be enabled for. Example addition to a .bashrc
-// file would be (your path to gflags_completions.sh file may differ):
-
-/*
-$ complete -o bashdefault -o default -o nospace -C \
- '/home/build/eng/bash/bash_completions.sh --tab_completion_columns $COLUMNS' \
- time env binary_name another_binary [...]
-*/
-
-// This would allow the following to work:
-// $ /path/to/binary_name --vmodule<TAB>
-// Or:
-// $ ./bin/path/another_binary --gfs_u<TAB>
-// (etc)
-//
-// Sadly, it appears that bash gives no easy way to force this behavior for
-// all commands. That's where the "time" in the above example comes in.
-// If you haven't specifically added a command to the list of completion
-// supported commands, you can still get completions by prefixing the
-// entire command with "env".
-// $ env /some/brand/new/binary --vmod<TAB>
-// Assuming that "binary" is a newly compiled binary, this should still
-// produce the expected completion output.
-
-
-#ifndef GFLAGS_COMPLETIONS_H_
-#define GFLAGS_COMPLETIONS_H_
-
-namespace gflags {
-
-extern void HandleCommandLineCompletions(void);
-
-}
-
-#endif // GFLAGS_COMPLETIONS_H_
diff --git a/extern/libmv/third_party/gflags/gflags/gflags_declare.h b/extern/libmv/third_party/gflags/gflags/gflags_declare.h
deleted file mode 100644
index 335c389b610..00000000000
--- a/extern/libmv/third_party/gflags/gflags/gflags_declare.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 1999, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// ---
-//
-// Revamped and reorganized by Craig Silverstein
-//
-// This is the file that should be included by any file which declares
-// command line flag.
-
-#ifndef GFLAGS_DECLARE_H_
-#define GFLAGS_DECLARE_H_
-
-// ---------------------------------------------------------------------------
-// Windows DLL import/export.
-
-// We always want to import the symbols of the gflags library
-#ifndef GFLAGS_DLL_DECL
-# if 0 && defined(_MSC_VER)
-# define GFLAGS_DLL_DECL __declspec(dllimport)
-# else
-# define GFLAGS_DLL_DECL
-# endif
-#endif
-
-// We always want to import variables declared in user code
-#ifndef GFLAGS_DLL_DECLARE_FLAG
-# if 0 && defined(_MSC_VER)
-# define GFLAGS_DLL_DECLARE_FLAG __declspec(dllimport)
-# else
-# define GFLAGS_DLL_DECLARE_FLAG
-# endif
-#endif
-
-// ---------------------------------------------------------------------------
-// Flag types
-#include <string>
-#if 1
-# include <stdint.h> // the normal place uint32_t is defined
-#elif 1
-# include <sys/types.h> // the normal place u_int32_t is defined
-#elif 1
-# include <inttypes.h> // a third place for uint32_t or u_int32_t
-#endif
-
-namespace gflags {
-
-#if 1 // C99
-typedef int32_t int32;
-typedef uint32_t uint32;
-typedef int64_t int64;
-typedef uint64_t uint64;
-#elif 0 // BSD
-typedef int32_t int32;
-typedef u_int32_t uint32;
-typedef int64_t int64;
-typedef u_int64_t uint64;
-#elif 0 // Windows
-typedef __int32 int32;
-typedef unsigned __int32 uint32;
-typedef __int64 int64;
-typedef unsigned __int64 uint64;
-#else
-# error Do not know how to define a 32-bit integer quantity on your system
-#endif
-
-} // namespace gflags
-
-
-namespace fLS {
-
-// The meaning of "string" might be different between now and when the
-// macros below get invoked (e.g., if someone is experimenting with
-// other string implementations that get defined after this file is
-// included). Save the current meaning now and use it in the macros.
-typedef std::string clstring;
-
-} // namespace fLS
-
-
-#define DECLARE_VARIABLE(type, shorttype, name) \
- /* We always want to import declared variables, dll or no */ \
- namespace fL##shorttype { extern GFLAGS_DLL_DECLARE_FLAG type FLAGS_##name; } \
- using fL##shorttype::FLAGS_##name
-
-#define DECLARE_bool(name) \
- DECLARE_VARIABLE(bool, B, name)
-
-#define DECLARE_int32(name) \
- DECLARE_VARIABLE(::gflags::int32, I, name)
-
-#define DECLARE_int64(name) \
- DECLARE_VARIABLE(::gflags::int64, I64, name)
-
-#define DECLARE_uint64(name) \
- DECLARE_VARIABLE(::gflags::uint64, U64, name)
-
-#define DECLARE_double(name) \
- DECLARE_VARIABLE(double, D, name)
-
-#define DECLARE_string(name) \
- /* We always want to import declared variables, dll or no */ \
- namespace fLS { \
- using ::fLS::clstring; \
- extern GFLAGS_DLL_DECLARE_FLAG ::fLS::clstring& FLAGS_##name; \
- } \
- using fLS::FLAGS_##name
-
-
-#endif // GFLAGS_DECLARE_H_
diff --git a/extern/libmv/third_party/gflags/gflags_completions.cc b/extern/libmv/third_party/gflags/gflags_completions.cc
deleted file mode 100644
index 3a476230ff9..00000000000
--- a/extern/libmv/third_party/gflags/gflags_completions.cc
+++ /dev/null
@@ -1,769 +0,0 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// ---
-
-// Bash-style command line flag completion for C++ binaries
-//
-// This module implements bash-style completions. It achieves this
-// goal in the following broad chunks:
-//
-// 1) Take a to-be-completed word, and examine it for search hints
-// 2) Identify all potentially matching flags
-// 2a) If there are no matching flags, do nothing.
-// 2b) If all matching flags share a common prefix longer than the
-// completion word, output just that matching prefix
-// 3) Categorize those flags to produce a rough ordering of relevence.
-// 4) Potentially trim the set of flags returned to a smaller number
-// that bash is happier with
-// 5) Output the matching flags in groups ordered by relevence.
-// 5a) Force bash to place most-relevent groups at the top of the list
-// 5b) Trim most flag's descriptions to fit on a single terminal line
-
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for strlen
-
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "gflags.h"
-#include "util.h"
-
-using std::set;
-using std::string;
-using std::vector;
-
-
-DEFINE_string(tab_completion_word, "",
- "If non-empty, HandleCommandLineCompletions() will hijack the "
- "process and attempt to do bash-style command line flag "
- "completion on this value.");
-DEFINE_int32(tab_completion_columns, 80,
- "Number of columns to use in output for tab completion");
-
-
-namespace GFLAGS_NAMESPACE {
-
-
-namespace {
-// Function prototypes and Type forward declarations. Code may be
-// more easily understood if it is roughly ordered according to
-// control flow, rather than by C's "declare before use" ordering
-struct CompletionOptions;
-struct NotableFlags;
-
-// The entry point if flag completion is to be used.
-static void PrintFlagCompletionInfo(void);
-
-
-// 1) Examine search word
-static void CanonicalizeCursorWordAndSearchOptions(
- const string &cursor_word,
- string *canonical_search_token,
- CompletionOptions *options);
-
-static bool RemoveTrailingChar(string *str, char c);
-
-
-// 2) Find all matches
-static void FindMatchingFlags(
- const vector<CommandLineFlagInfo> &all_flags,
- const CompletionOptions &options,
- const string &match_token,
- set<const CommandLineFlagInfo *> *all_matches,
- string *longest_common_prefix);
-
-static bool DoesSingleFlagMatch(
- const CommandLineFlagInfo &flag,
- const CompletionOptions &options,
- const string &match_token);
-
-
-// 3) Categorize matches
-static void CategorizeAllMatchingFlags(
- const set<const CommandLineFlagInfo *> &all_matches,
- const string &search_token,
- const string &module,
- const string &package_dir,
- NotableFlags *notable_flags);
-
-static void TryFindModuleAndPackageDir(
- const vector<CommandLineFlagInfo> all_flags,
- string *module,
- string *package_dir);
-
-
-// 4) Decide which flags to use
-static void FinalizeCompletionOutput(
- const set<const CommandLineFlagInfo *> &matching_flags,
- CompletionOptions *options,
- NotableFlags *notable_flags,
- vector<string> *completions);
-
-static void RetrieveUnusedFlags(
- const set<const CommandLineFlagInfo *> &matching_flags,
- const NotableFlags &notable_flags,
- set<const CommandLineFlagInfo *> *unused_flags);
-
-
-// 5) Output matches
-static void OutputSingleGroupWithLimit(
- const set<const CommandLineFlagInfo *> &group,
- const string &line_indentation,
- const string &header,
- const string &footer,
- bool long_output_format,
- int *remaining_line_limit,
- size_t *completion_elements_added,
- vector<string> *completions);
-
-// (helpers for #5)
-static string GetShortFlagLine(
- const string &line_indentation,
- const CommandLineFlagInfo &info);
-
-static string GetLongFlagLine(
- const string &line_indentation,
- const CommandLineFlagInfo &info);
-
-
-//
-// Useful types
-
-// Try to deduce the intentions behind this completion attempt. Return the
-// canonical search term in 'canonical_search_token'. Binary search options
-// are returned in the various booleans, which should all have intuitive
-// semantics, possibly except:
-// - return_all_matching_flags: Generally, we'll trim the number of
-// returned candidates to some small number, showing those that are
-// most likely to be useful first. If this is set, however, the user
-// really does want us to return every single flag as an option.
-// - force_no_update: Any time we output lines, all of which share a
-// common prefix, bash will 'helpfully' not even bother to show the
-// output, instead changing the current word to be that common prefix.
-// If it's clear this shouldn't happen, we'll set this boolean
-struct CompletionOptions {
- bool flag_name_substring_search;
- bool flag_location_substring_search;
- bool flag_description_substring_search;
- bool return_all_matching_flags;
- bool force_no_update;
-};
-
-// Notable flags are flags that are special or preferred for some
-// reason. For example, flags that are defined in the binary's module
-// are expected to be much more relevent than flags defined in some
-// other random location. These sets are specified roughly in precedence
-// order. Once a flag is placed in one of these 'higher' sets, it won't
-// be placed in any of the 'lower' sets.
-struct NotableFlags {
- typedef set<const CommandLineFlagInfo *> FlagSet;
- FlagSet perfect_match_flag;
- FlagSet module_flags; // Found in module file
- FlagSet package_flags; // Found in same directory as module file
- FlagSet most_common_flags; // One of the XXX most commonly supplied flags
- FlagSet subpackage_flags; // Found in subdirectories of package
-};
-
-
-//
-// Tab completion implementation - entry point
-static void PrintFlagCompletionInfo(void) {
- string cursor_word = FLAGS_tab_completion_word;
- string canonical_token;
- CompletionOptions options = { };
- CanonicalizeCursorWordAndSearchOptions(
- cursor_word,
- &canonical_token,
- &options);
-
- DVLOG(1) << "Identified canonical_token: '" << canonical_token << "'";
-
- vector<CommandLineFlagInfo> all_flags;
- set<const CommandLineFlagInfo *> matching_flags;
- GetAllFlags(&all_flags);
- DVLOG(2) << "Found " << all_flags.size() << " flags overall";
-
- string longest_common_prefix;
- FindMatchingFlags(
- all_flags,
- options,
- canonical_token,
- &matching_flags,
- &longest_common_prefix);
- DVLOG(1) << "Identified " << matching_flags.size() << " matching flags";
- DVLOG(1) << "Identified " << longest_common_prefix
- << " as longest common prefix.";
- if (longest_common_prefix.size() > canonical_token.size()) {
- // There's actually a shared common prefix to all matching flags,
- // so may as well output that and quit quickly.
- DVLOG(1) << "The common prefix '" << longest_common_prefix
- << "' was longer than the token '" << canonical_token
- << "'. Returning just this prefix for completion.";
- fprintf(stdout, "--%s", longest_common_prefix.c_str());
- return;
- }
- if (matching_flags.empty()) {
- VLOG(1) << "There were no matching flags, returning nothing.";
- return;
- }
-
- string module;
- string package_dir;
- TryFindModuleAndPackageDir(all_flags, &module, &package_dir);
- DVLOG(1) << "Identified module: '" << module << "'";
- DVLOG(1) << "Identified package_dir: '" << package_dir << "'";
-
- NotableFlags notable_flags;
- CategorizeAllMatchingFlags(
- matching_flags,
- canonical_token,
- module,
- package_dir,
- &notable_flags);
- DVLOG(2) << "Categorized matching flags:";
- DVLOG(2) << " perfect_match: " << notable_flags.perfect_match_flag.size();
- DVLOG(2) << " module: " << notable_flags.module_flags.size();
- DVLOG(2) << " package: " << notable_flags.package_flags.size();
- DVLOG(2) << " most common: " << notable_flags.most_common_flags.size();
- DVLOG(2) << " subpackage: " << notable_flags.subpackage_flags.size();
-
- vector<string> completions;
- FinalizeCompletionOutput(
- matching_flags,
- &options,
- &notable_flags,
- &completions);
-
- if (options.force_no_update)
- completions.push_back("~");
-
- DVLOG(1) << "Finalized with " << completions.size()
- << " chosen completions";
-
- for (vector<string>::const_iterator it = completions.begin();
- it != completions.end();
- ++it) {
- DVLOG(9) << " Completion entry: '" << *it << "'";
- fprintf(stdout, "%s\n", it->c_str());
- }
-}
-
-
-// 1) Examine search word (and helper method)
-static void CanonicalizeCursorWordAndSearchOptions(
- const string &cursor_word,
- string *canonical_search_token,
- CompletionOptions *options) {
- *canonical_search_token = cursor_word;
- if (canonical_search_token->empty()) return;
-
- // Get rid of leading quotes and dashes in the search term
- if ((*canonical_search_token)[0] == '"')
- *canonical_search_token = canonical_search_token->substr(1);
- while ((*canonical_search_token)[0] == '-')
- *canonical_search_token = canonical_search_token->substr(1);
-
- options->flag_name_substring_search = false;
- options->flag_location_substring_search = false;
- options->flag_description_substring_search = false;
- options->return_all_matching_flags = false;
- options->force_no_update = false;
-
- // Look for all search options we can deduce now. Do this by walking
- // backwards through the term, looking for up to three '?' and up to
- // one '+' as suffixed characters. Consume them if found, and remove
- // them from the canonical search token.
- int found_question_marks = 0;
- int found_plusses = 0;
- while (true) {
- if (found_question_marks < 3 &&
- RemoveTrailingChar(canonical_search_token, '?')) {
- ++found_question_marks;
- continue;
- }
- if (found_plusses < 1 &&
- RemoveTrailingChar(canonical_search_token, '+')) {
- ++found_plusses;
- continue;
- }
- break;
- }
-
- switch (found_question_marks) { // all fallthroughs
- case 3: options->flag_description_substring_search = true;
- case 2: options->flag_location_substring_search = true;
- case 1: options->flag_name_substring_search = true;
- };
-
- options->return_all_matching_flags = (found_plusses > 0);
-}
-
-// Returns true if a char was removed
-static bool RemoveTrailingChar(string *str, char c) {
- if (str->empty()) return false;
- if ((*str)[str->size() - 1] == c) {
- *str = str->substr(0, str->size() - 1);
- return true;
- }
- return false;
-}
-
-
-// 2) Find all matches (and helper methods)
-static void FindMatchingFlags(
- const vector<CommandLineFlagInfo> &all_flags,
- const CompletionOptions &options,
- const string &match_token,
- set<const CommandLineFlagInfo *> *all_matches,
- string *longest_common_prefix) {
- all_matches->clear();
- bool first_match = true;
- for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
- it != all_flags.end();
- ++it) {
- if (DoesSingleFlagMatch(*it, options, match_token)) {
- all_matches->insert(&*it);
- if (first_match) {
- first_match = false;
- *longest_common_prefix = it->name;
- } else {
- if (longest_common_prefix->empty() || it->name.empty()) {
- longest_common_prefix->clear();
- continue;
- }
- string::size_type pos = 0;
- while (pos < longest_common_prefix->size() &&
- pos < it->name.size() &&
- (*longest_common_prefix)[pos] == it->name[pos])
- ++pos;
- longest_common_prefix->erase(pos);
- }
- }
- }
-}
-
-// Given the set of all flags, the parsed match options, and the
-// canonical search token, produce the set of all candidate matching
-// flags for subsequent analysis or filtering.
-static bool DoesSingleFlagMatch(
- const CommandLineFlagInfo &flag,
- const CompletionOptions &options,
- const string &match_token) {
- // Is there a prefix match?
- string::size_type pos = flag.name.find(match_token);
- if (pos == 0) return true;
-
- // Is there a substring match if we want it?
- if (options.flag_name_substring_search &&
- pos != string::npos)
- return true;
-
- // Is there a location match if we want it?
- if (options.flag_location_substring_search &&
- flag.filename.find(match_token) != string::npos)
- return true;
-
- // TODO(user): All searches should probably be case-insensitive
- // (especially this one...)
- if (options.flag_description_substring_search &&
- flag.description.find(match_token) != string::npos)
- return true;
-
- return false;
-}
-
-// 3) Categorize matches (and helper method)
-
-// Given a set of matching flags, categorize them by
-// likely relevence to this specific binary
-static void CategorizeAllMatchingFlags(
- const set<const CommandLineFlagInfo *> &all_matches,
- const string &search_token,
- const string &module, // empty if we couldn't find any
- const string &package_dir, // empty if we couldn't find any
- NotableFlags *notable_flags) {
- notable_flags->perfect_match_flag.clear();
- notable_flags->module_flags.clear();
- notable_flags->package_flags.clear();
- notable_flags->most_common_flags.clear();
- notable_flags->subpackage_flags.clear();
-
- for (set<const CommandLineFlagInfo *>::const_iterator it =
- all_matches.begin();
- it != all_matches.end();
- ++it) {
- DVLOG(2) << "Examining match '" << (*it)->name << "'";
- DVLOG(7) << " filename: '" << (*it)->filename << "'";
- string::size_type pos = string::npos;
- if (!package_dir.empty())
- pos = (*it)->filename.find(package_dir);
- string::size_type slash = string::npos;
- if (pos != string::npos) // candidate for package or subpackage match
- slash = (*it)->filename.find(
- PATH_SEPARATOR,
- pos + package_dir.size() + 1);
-
- if ((*it)->name == search_token) {
- // Exact match on some flag's name
- notable_flags->perfect_match_flag.insert(*it);
- DVLOG(3) << "Result: perfect match";
- } else if (!module.empty() && (*it)->filename == module) {
- // Exact match on module filename
- notable_flags->module_flags.insert(*it);
- DVLOG(3) << "Result: module match";
- } else if (!package_dir.empty() &&
- pos != string::npos && slash == string::npos) {
- // In the package, since there was no slash after the package portion
- notable_flags->package_flags.insert(*it);
- DVLOG(3) << "Result: package match";
- } else if (false) {
- // In the list of the XXX most commonly supplied flags overall
- // TODO(user): Compile this list.
- DVLOG(3) << "Result: most-common match";
- } else if (!package_dir.empty() &&
- pos != string::npos && slash != string::npos) {
- // In a subdirectory of the package
- notable_flags->subpackage_flags.insert(*it);
- DVLOG(3) << "Result: subpackage match";
- }
-
- DVLOG(3) << "Result: not special match";
- }
-}
-
-static void PushNameWithSuffix(vector<string>* suffixes, const char* suffix) {
- suffixes->push_back(
- StringPrintf("/%s%s", ProgramInvocationShortName(), suffix));
-}
-
-static void TryFindModuleAndPackageDir(
- const vector<CommandLineFlagInfo> all_flags,
- string *module,
- string *package_dir) {
- module->clear();
- package_dir->clear();
-
- vector<string> suffixes;
- // TODO(user): There's some inherant ambiguity here - multiple directories
- // could share the same trailing folder and file structure (and even worse,
- // same file names), causing us to be unsure as to which of the two is the
- // actual package for this binary. In this case, we'll arbitrarily choose.
- PushNameWithSuffix(&suffixes, ".");
- PushNameWithSuffix(&suffixes, "-main.");
- PushNameWithSuffix(&suffixes, "_main.");
- // These four are new but probably merited?
- PushNameWithSuffix(&suffixes, "-test.");
- PushNameWithSuffix(&suffixes, "_test.");
- PushNameWithSuffix(&suffixes, "-unittest.");
- PushNameWithSuffix(&suffixes, "_unittest.");
-
- for (vector<CommandLineFlagInfo>::const_iterator it = all_flags.begin();
- it != all_flags.end();
- ++it) {
- for (vector<string>::const_iterator suffix = suffixes.begin();
- suffix != suffixes.end();
- ++suffix) {
- // TODO(user): Make sure the match is near the end of the string
- if (it->filename.find(*suffix) != string::npos) {
- *module = it->filename;
- string::size_type sep = it->filename.rfind(PATH_SEPARATOR);
- *package_dir = it->filename.substr(0, (sep == string::npos) ? 0 : sep);
- return;
- }
- }
- }
-}
-
-// Can't specialize template type on a locally defined type. Silly C++...
-struct DisplayInfoGroup {
- const char* header;
- const char* footer;
- set<const CommandLineFlagInfo *> *group;
-
- int SizeInLines() const {
- int size_in_lines = static_cast<int>(group->size()) + 1;
- if (strlen(header) > 0) {
- size_in_lines++;
- }
- if (strlen(footer) > 0) {
- size_in_lines++;
- }
- return size_in_lines;
- }
-};
-
-// 4) Finalize and trim output flag set
-static void FinalizeCompletionOutput(
- const set<const CommandLineFlagInfo *> &matching_flags,
- CompletionOptions *options,
- NotableFlags *notable_flags,
- vector<string> *completions) {
-
- // We want to output lines in groups. Each group needs to be indented
- // the same to keep its lines together. Unless otherwise required,
- // only 99 lines should be output to prevent bash from harassing the
- // user.
-
- // First, figure out which output groups we'll actually use. For each
- // nonempty group, there will be ~3 lines of header & footer, plus all
- // output lines themselves.
- int max_desired_lines = // "999999 flags should be enough for anyone. -dave"
- (options->return_all_matching_flags ? 999999 : 98);
- int lines_so_far = 0;
-
- vector<DisplayInfoGroup> output_groups;
- bool perfect_match_found = false;
- if (lines_so_far < max_desired_lines &&
- !notable_flags->perfect_match_flag.empty()) {
- perfect_match_found = true;
- DisplayInfoGroup group =
- { "",
- "==========",
- &notable_flags->perfect_match_flag };
- lines_so_far += group.SizeInLines();
- output_groups.push_back(group);
- }
- if (lines_so_far < max_desired_lines &&
- !notable_flags->module_flags.empty()) {
- DisplayInfoGroup group = {
- "-* Matching module flags *-",
- "===========================",
- &notable_flags->module_flags };
- lines_so_far += group.SizeInLines();
- output_groups.push_back(group);
- }
- if (lines_so_far < max_desired_lines &&
- !notable_flags->package_flags.empty()) {
- DisplayInfoGroup group = {
- "-* Matching package flags *-",
- "============================",
- &notable_flags->package_flags };
- lines_so_far += group.SizeInLines();
- output_groups.push_back(group);
- }
- if (lines_so_far < max_desired_lines &&
- !notable_flags->most_common_flags.empty()) {
- DisplayInfoGroup group = {
- "-* Commonly used flags *-",
- "=========================",
- &notable_flags->most_common_flags };
- lines_so_far += group.SizeInLines();
- output_groups.push_back(group);
- }
- if (lines_so_far < max_desired_lines &&
- !notable_flags->subpackage_flags.empty()) {
- DisplayInfoGroup group = {
- "-* Matching sub-package flags *-",
- "================================",
- &notable_flags->subpackage_flags };
- lines_so_far += group.SizeInLines();
- output_groups.push_back(group);
- }
-
- set<const CommandLineFlagInfo *> obscure_flags; // flags not notable
- if (lines_so_far < max_desired_lines) {
- RetrieveUnusedFlags(matching_flags, *notable_flags, &obscure_flags);
- if (!obscure_flags.empty()) {
- DisplayInfoGroup group = {
- "-* Other flags *-",
- "",
- &obscure_flags };
- lines_so_far += group.SizeInLines();
- output_groups.push_back(group);
- }
- }
-
- // Second, go through each of the chosen output groups and output
- // as many of those flags as we can, while remaining below our limit
- int remaining_lines = max_desired_lines;
- size_t completions_output = 0;
- int indent = static_cast<int>(output_groups.size()) - 1;
- for (vector<DisplayInfoGroup>::const_iterator it =
- output_groups.begin();
- it != output_groups.end();
- ++it, --indent) {
- OutputSingleGroupWithLimit(
- *it->group, // group
- string(indent, ' '), // line indentation
- string(it->header), // header
- string(it->footer), // footer
- perfect_match_found, // long format
- &remaining_lines, // line limit - reduces this by number printed
- &completions_output, // completions (not lines) added
- completions); // produced completions
- perfect_match_found = false;
- }
-
- if (completions_output != matching_flags.size()) {
- options->force_no_update = false;
- completions->push_back("~ (Remaining flags hidden) ~");
- } else {
- options->force_no_update = true;
- }
-}
-
-static void RetrieveUnusedFlags(
- const set<const CommandLineFlagInfo *> &matching_flags,
- const NotableFlags &notable_flags,
- set<const CommandLineFlagInfo *> *unused_flags) {
- // Remove from 'matching_flags' set all members of the sets of
- // flags we've already printed (specifically, those in notable_flags)
- for (set<const CommandLineFlagInfo *>::const_iterator it =
- matching_flags.begin();
- it != matching_flags.end();
- ++it) {
- if (notable_flags.perfect_match_flag.count(*it) ||
- notable_flags.module_flags.count(*it) ||
- notable_flags.package_flags.count(*it) ||
- notable_flags.most_common_flags.count(*it) ||
- notable_flags.subpackage_flags.count(*it))
- continue;
- unused_flags->insert(*it);
- }
-}
-
-// 5) Output matches (and helper methods)
-
-static void OutputSingleGroupWithLimit(
- const set<const CommandLineFlagInfo *> &group,
- const string &line_indentation,
- const string &header,
- const string &footer,
- bool long_output_format,
- int *remaining_line_limit,
- size_t *completion_elements_output,
- vector<string> *completions) {
- if (group.empty()) return;
- if (!header.empty()) {
- if (*remaining_line_limit < 2) return;
- *remaining_line_limit -= 2;
- completions->push_back(line_indentation + header);
- completions->push_back(line_indentation + string(header.size(), '-'));
- }
- for (set<const CommandLineFlagInfo *>::const_iterator it = group.begin();
- it != group.end() && *remaining_line_limit > 0;
- ++it) {
- --*remaining_line_limit;
- ++*completion_elements_output;
- completions->push_back(
- (long_output_format
- ? GetLongFlagLine(line_indentation, **it)
- : GetShortFlagLine(line_indentation, **it)));
- }
- if (!footer.empty()) {
- if (*remaining_line_limit < 1) return;
- --*remaining_line_limit;
- completions->push_back(line_indentation + footer);
- }
-}
-
-static string GetShortFlagLine(
- const string &line_indentation,
- const CommandLineFlagInfo &info) {
- string prefix;
- bool is_string = (info.type == "string");
- SStringPrintf(&prefix, "%s--%s [%s%s%s] ",
- line_indentation.c_str(),
- info.name.c_str(),
- (is_string ? "'" : ""),
- info.default_value.c_str(),
- (is_string ? "'" : ""));
- int remainder =
- FLAGS_tab_completion_columns - static_cast<int>(prefix.size());
- string suffix;
- if (remainder > 0)
- suffix =
- (static_cast<int>(info.description.size()) > remainder ?
- (info.description.substr(0, remainder - 3) + "...").c_str() :
- info.description.c_str());
- return prefix + suffix;
-}
-
-static string GetLongFlagLine(
- const string &line_indentation,
- const CommandLineFlagInfo &info) {
-
- string output = DescribeOneFlag(info);
-
- // Replace '-' with '--', and remove trailing newline before appending
- // the module definition location.
- string old_flagname = "-" + info.name;
- output.replace(
- output.find(old_flagname),
- old_flagname.size(),
- "-" + old_flagname);
- // Stick a newline and indentation in front of the type and default
- // portions of DescribeOneFlag()s description
- static const char kNewlineWithIndent[] = "\n ";
- output.replace(output.find(" type:"), 1, string(kNewlineWithIndent));
- output.replace(output.find(" default:"), 1, string(kNewlineWithIndent));
- output = StringPrintf("%s Details for '--%s':\n"
- "%s defined: %s",
- line_indentation.c_str(),
- info.name.c_str(),
- output.c_str(),
- info.filename.c_str());
-
- // Eliminate any doubled newlines that crept in. Specifically, if
- // DescribeOneFlag() decided to break the line just before "type"
- // or "default", we don't want to introduce an extra blank line
- static const string line_of_spaces(FLAGS_tab_completion_columns, ' ');
- static const char kDoubledNewlines[] = "\n \n";
- for (string::size_type newlines = output.find(kDoubledNewlines);
- newlines != string::npos;
- newlines = output.find(kDoubledNewlines))
- // Replace each 'doubled newline' with a single newline
- output.replace(newlines, sizeof(kDoubledNewlines) - 1, string("\n"));
-
- for (string::size_type newline = output.find('\n');
- newline != string::npos;
- newline = output.find('\n')) {
- int newline_pos = static_cast<int>(newline) % FLAGS_tab_completion_columns;
- int missing_spaces = FLAGS_tab_completion_columns - newline_pos;
- output.replace(newline, 1, line_of_spaces, 1, missing_spaces);
- }
- return output;
-}
-} // anonymous
-
-void HandleCommandLineCompletions(void) {
- if (FLAGS_tab_completion_word.empty()) return;
- PrintFlagCompletionInfo();
- gflags_exitfunc(0);
-}
-
-
-} // namespace GFLAGS_NAMESPACE
diff --git a/extern/libmv/third_party/gflags/mutex.h b/extern/libmv/third_party/gflags/mutex.h
deleted file mode 100644
index 0bdd9d5f2a5..00000000000
--- a/extern/libmv/third_party/gflags/mutex.h
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// ---
-//
-// A simple mutex wrapper, supporting locks and read-write locks.
-// You should assume the locks are *not* re-entrant.
-//
-// This class is meant to be internal-only and should be wrapped by an
-// internal namespace. Before you use this module, please give the
-// name of your internal namespace for this module. Or, if you want
-// to expose it, you'll want to move it to the Google namespace. We
-// cannot put this class in global namespace because there can be some
-// problems when we have multiple versions of Mutex in each shared object.
-//
-// NOTE: by default, we have #ifdef'ed out the TryLock() method.
-// This is for two reasons:
-// 1) TryLock() under Windows is a bit annoying (it requires a
-// #define to be defined very early).
-// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
-// mode.
-// If you need TryLock(), and either these two caveats are not a
-// problem for you, or you're willing to work around them, then
-// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
-// in the code below.
-//
-// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
-// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
-// Because of that, we might as well use windows locks for
-// cygwin. They seem to be more reliable than the cygwin pthreads layer.
-//
-// TRICKY IMPLEMENTATION NOTE:
-// This class is designed to be safe to use during
-// dynamic-initialization -- that is, by global constructors that are
-// run before main() starts. The issue in this case is that
-// dynamic-initialization happens in an unpredictable order, and it
-// could be that someone else's dynamic initializer could call a
-// function that tries to acquire this mutex -- but that all happens
-// before this mutex's constructor has run. (This can happen even if
-// the mutex and the function that uses the mutex are in the same .cc
-// file.) Basically, because Mutex does non-trivial work in its
-// constructor, it's not, in the naive implementation, safe to use
-// before dynamic initialization has run on it.
-//
-// The solution used here is to pair the actual mutex primitive with a
-// bool that is set to true when the mutex is dynamically initialized.
-// (Before that it's false.) Then we modify all mutex routines to
-// look at the bool, and not try to lock/unlock until the bool makes
-// it to true (which happens after the Mutex constructor has run.)
-//
-// This works because before main() starts -- particularly, during
-// dynamic initialization -- there are no threads, so a) it's ok that
-// the mutex operations are a no-op, since we don't need locking then
-// anyway; and b) we can be quite confident our bool won't change
-// state between a call to Lock() and a call to Unlock() (that would
-// require a global constructor in one translation unit to call Lock()
-// and another global constructor in another translation unit to call
-// Unlock() later, which is pretty perverse).
-//
-// That said, it's tricky, and can conceivably fail; it's safest to
-// avoid trying to acquire a mutex in a global constructor, if you
-// can. One way it can fail is that a really smart compiler might
-// initialize the bool to true at static-initialization time (too
-// early) rather than at dynamic-initialization time. To discourage
-// that, we set is_safe_ to true in code (not the constructor
-// colon-initializer) and set it to true via a function that always
-// evaluates to true, but that the compiler can't know always
-// evaluates to true. This should be good enough.
-//
-// A related issue is code that could try to access the mutex
-// after it's been destroyed in the global destructors (because
-// the Mutex global destructor runs before some other global
-// destructor, that tries to acquire the mutex). The way we
-// deal with this is by taking a constructor arg that global
-// mutexes should pass in, that causes the destructor to do no
-// work. We still depend on the compiler not doing anything
-// weird to a Mutex's memory after it is destroyed, but for a
-// static global variable, that's pretty safe.
-
-#ifndef GFLAGS_MUTEX_H_
-#define GFLAGS_MUTEX_H_
-
-#include "gflags_declare.h" // to figure out pthreads support
-
-#if defined(NO_THREADS)
- typedef int MutexType; // to keep a lock-count
-#elif defined(OS_WINDOWS)
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN // We only need minimal includes
-# endif
-# ifndef NOMINMAX
-# define NOMINMAX // Don't want windows to override min()/max()
-# endif
-# ifdef GMUTEX_TRYLOCK
- // We need Windows NT or later for TryEnterCriticalSection(). If you
- // don't need that functionality, you can remove these _WIN32_WINNT
- // lines, and change TryLock() to assert(0) or something.
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0400
-# endif
-# endif
-# include <windows.h>
- typedef CRITICAL_SECTION MutexType;
-#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
- // Needed for pthread_rwlock_*. If it causes problems, you could take it
- // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
- // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
- // for locking there.)
-# ifdef __linux__
-# if _XOPEN_SOURCE < 500 // including not being defined at all
-# undef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
-# endif
-# endif
-# include <pthread.h>
- typedef pthread_rwlock_t MutexType;
-#elif defined(HAVE_PTHREAD)
-# include <pthread.h>
- typedef pthread_mutex_t MutexType;
-#else
-# error Need to implement mutex.h for your architecture, or #define NO_THREADS
-#endif
-
-#include <assert.h>
-#include <stdlib.h> // for abort()
-
-#define MUTEX_NAMESPACE gflags_mutex_namespace
-
-namespace MUTEX_NAMESPACE {
-
-class Mutex {
- public:
- // This is used for the single-arg constructor
- enum LinkerInitialized { LINKER_INITIALIZED };
-
- // Create a Mutex that is not held by anybody. This constructor is
- // typically used for Mutexes allocated on the heap or the stack.
- inline Mutex();
- // This constructor should be used for global, static Mutex objects.
- // It inhibits work being done by the destructor, which makes it
- // safer for code that tries to acqiure this mutex in their global
- // destructor.
- inline Mutex(LinkerInitialized);
-
- // Destructor
- inline ~Mutex();
-
- inline void Lock(); // Block if needed until free then acquire exclusively
- inline void Unlock(); // Release a lock acquired via Lock()
-#ifdef GMUTEX_TRYLOCK
- inline bool TryLock(); // If free, Lock() and return true, else return false
-#endif
- // Note that on systems that don't support read-write locks, these may
- // be implemented as synonyms to Lock() and Unlock(). So you can use
- // these for efficiency, but don't use them anyplace where being able
- // to do shared reads is necessary to avoid deadlock.
- inline void ReaderLock(); // Block until free or shared then acquire a share
- inline void ReaderUnlock(); // Release a read share of this Mutex
- inline void WriterLock() { Lock(); } // Acquire an exclusive lock
- inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
-
- private:
- MutexType mutex_;
- // We want to make sure that the compiler sets is_safe_ to true only
- // when we tell it to, and never makes assumptions is_safe_ is
- // always true. volatile is the most reliable way to do that.
- volatile bool is_safe_;
- // This indicates which constructor was called.
- bool destroy_;
-
- inline void SetIsSafe() { is_safe_ = true; }
-
- // Catch the error of writing Mutex when intending MutexLock.
- Mutex(Mutex* /*ignored*/) {}
- // Disallow "evil" constructors
- Mutex(const Mutex&);
- void operator=(const Mutex&);
-};
-
-// Now the implementation of Mutex for various systems
-#if defined(NO_THREADS)
-
-// When we don't have threads, we can be either reading or writing,
-// but not both. We can have lots of readers at once (in no-threads
-// mode, that's most likely to happen in recursive function calls),
-// but only one writer. We represent this by having mutex_ be -1 when
-// writing and a number > 0 when reading (and 0 when no lock is held).
-//
-// In debug mode, we assert these invariants, while in non-debug mode
-// we do nothing, for efficiency. That's why everything is in an
-// assert.
-
-Mutex::Mutex() : mutex_(0) { }
-Mutex::Mutex(Mutex::LinkerInitialized) : mutex_(0) { }
-Mutex::~Mutex() { assert(mutex_ == 0); }
-void Mutex::Lock() { assert(--mutex_ == -1); }
-void Mutex::Unlock() { assert(mutex_++ == -1); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
-#endif
-void Mutex::ReaderLock() { assert(++mutex_ > 0); }
-void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
-
-#elif defined(OS_WINDOWS)
-
-Mutex::Mutex() : destroy_(true) {
- InitializeCriticalSection(&mutex_);
- SetIsSafe();
-}
-Mutex::Mutex(LinkerInitialized) : destroy_(false) {
- InitializeCriticalSection(&mutex_);
- SetIsSafe();
-}
-Mutex::~Mutex() { if (destroy_) DeleteCriticalSection(&mutex_); }
-void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
-void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- TryEnterCriticalSection(&mutex_) != 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
-void Mutex::ReaderUnlock() { Unlock(); }
-
-#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
-
-#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() : destroy_(true) {
- SetIsSafe();
- if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
- SetIsSafe();
- if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_rwlock_destroy); }
-void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
-void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_rwlock_trywrlock(&mutex_) == 0 : true; }
-#endif
-void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
-void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
-#undef SAFE_PTHREAD
-
-#elif defined(HAVE_PTHREAD)
-
-#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() : destroy_(true) {
- SetIsSafe();
- if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::Mutex(Mutex::LinkerInitialized) : destroy_(false) {
- SetIsSafe();
- if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { if (destroy_) SAFE_PTHREAD(pthread_mutex_destroy); }
-void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
-void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_mutex_trylock(&mutex_) == 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); }
-void Mutex::ReaderUnlock() { Unlock(); }
-#undef SAFE_PTHREAD
-
-#endif
-
-// --------------------------------------------------------------------------
-// Some helper classes
-
-// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
-class MutexLock {
- public:
- explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
- ~MutexLock() { mu_->Unlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- MutexLock(const MutexLock&);
- void operator=(const MutexLock&);
-};
-
-// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
-class ReaderMutexLock {
- public:
- explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
- ~ReaderMutexLock() { mu_->ReaderUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- ReaderMutexLock(const ReaderMutexLock&);
- void operator=(const ReaderMutexLock&);
-};
-
-class WriterMutexLock {
- public:
- explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
- ~WriterMutexLock() { mu_->WriterUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- WriterMutexLock(const WriterMutexLock&);
- void operator=(const WriterMutexLock&);
-};
-
-// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
-#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
-#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
-#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
-
-} // namespace MUTEX_NAMESPACE
-
-using namespace MUTEX_NAMESPACE;
-
-#undef MUTEX_NAMESPACE
-
-#endif /* #define GFLAGS_MUTEX_H__ */
diff --git a/extern/libmv/third_party/gflags/util.h b/extern/libmv/third_party/gflags/util.h
deleted file mode 100644
index 366e1be22e2..00000000000
--- a/extern/libmv/third_party/gflags/util.h
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright (c) 2011, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// ---
-//
-// Some generically useful utility routines that in google-land would
-// be their own projects. We make a shortened version here.
-
-#ifndef GFLAGS_UTIL_H_
-#define GFLAGS_UTIL_H_
-
-#include "config.h"
-
-#include <assert.h>
-#include <config.h>
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#include <stdarg.h> // for va_*
-#include <stdlib.h>
-#include <stdio.h>
-#include <iostream>
-#include <string>
-#include <errno.h>
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h> // for mkdir
-#endif
-
-
-namespace GFLAGS_NAMESPACE {
-
-
-// This is used for unittests for death-testing. It is defined in gflags.cc.
-extern GFLAGS_DLL_DECL void (*gflags_exitfunc)(int);
-
-// Work properly if either strtoll or strtoq is on this system.
-#if defined(strtoll) || defined(HAVE_STRTOLL)
-# define strto64 strtoll
-# define strtou64 strtoull
-#elif defined(HAVE_STRTOQ)
-# define strto64 strtoq
-# define strtou64 strtouq
-// Neither strtoll nor strtoq are defined. I hope strtol works!
-#else
-# define strto64 strtol
-# define strtou64 strtoul
-#endif
-
-// If we have inttypes.h, it will have defined PRId32/etc for us.
-// If not, take our best guess.
-#ifndef PRId32
-# define PRId32 "d"
-#endif
-#ifndef PRId64
-# define PRId64 "lld"
-#endif
-#ifndef PRIu64
-# define PRIu64 "llu"
-#endif
-
-typedef signed char int8;
-typedef unsigned char uint8;
-
-// -- utility macros ---------------------------------------------------------
-
-template <bool> struct CompileAssert {};
-#define COMPILE_ASSERT(expr, msg) \
- typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
-// Returns the number of elements in an array.
-#define arraysize(arr) (sizeof(arr)/sizeof(*(arr)))
-
-
-// -- logging and testing ---------------------------------------------------
-
-// For now, we ignore the level for logging, and don't show *VLOG's at
-// all, except by hand-editing the lines below
-#define LOG(level) std::cerr
-#define VLOG(level) if (true) {} else std::cerr
-#define DVLOG(level) if (true) {} else std::cerr
-
-// CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
-// compilation mode. Therefore, it is safe to do things like:
-// CHECK(fp->Write(x) == 4)
-// We allow stream-like objects after this for debugging, but they're ignored.
-#define EXPECT_TRUE(condition) \
- if (true) { \
- if (!(condition)) { \
- fprintf(stderr, "Check failed: %s\n", #condition); \
- exit(1); \
- } \
- } else std::cerr << ""
-
-#define EXPECT_OP(op, val1, val2) \
- if (true) { \
- if (!((val1) op (val2))) { \
- fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
- exit(1); \
- } \
- } else std::cerr << ""
-
-#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
-#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
-#define EXPECT_LE(val1, val2) EXPECT_OP(<=, val1, val2)
-#define EXPECT_LT(val1, val2) EXPECT_OP(< , val1, val2)
-#define EXPECT_GE(val1, val2) EXPECT_OP(>=, val1, val2)
-#define EXPECT_GT(val1, val2) EXPECT_OP(> , val1, val2)
-#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
-
-// C99 declares isnan and isinf should be macros, so the #ifdef test
-// should be reliable everywhere. Of course, it's not, but these
-// are testing pertty marginal functionality anyway, so it's ok to
-// not-run them even in situations they might, with effort, be made to work.
-#ifdef isnan // Some compilers, like sun's for Solaris 10, don't define this
-#define EXPECT_NAN(arg) \
- do { \
- if (!isnan(arg)) { \
- fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
- exit(1); \
- } \
- } while (0)
-#else
-#define EXPECT_NAN(arg)
-#endif
-
-#ifdef isinf // Some compilers, like sun's for Solaris 10, don't define this
-#define EXPECT_INF(arg) \
- do { \
- if (!isinf(arg)) { \
- fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
- exit(1); \
- } \
- } while (0)
-#else
-#define EXPECT_INF(arg)
-#endif
-
-#define EXPECT_DOUBLE_EQ(val1, val2) \
- do { \
- if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
- fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
- exit(1); \
- } \
- } while (0)
-
-#define EXPECT_STREQ(val1, val2) \
- do { \
- if (strcmp((val1), (val2)) != 0) { \
- fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
- exit(1); \
- } \
- } while (0)
-
-// Call this in a .cc file where you will later call RUN_ALL_TESTS in main().
-#define TEST_INIT \
- static std::vector<void (*)()> g_testlist; /* the tests to run */ \
- static int RUN_ALL_TESTS() { \
- std::vector<void (*)()>::const_iterator it; \
- for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { \
- (*it)(); /* The test will error-exit if there's a problem. */ \
- } \
- fprintf(stderr, "\nPassed %d tests\n\nPASS\n", \
- static_cast<int>(g_testlist.size())); \
- return 0; \
- }
-
-// Note that this macro uses a FlagSaver to keep tests isolated.
-#define TEST(a, b) \
- struct Test_##a##_##b { \
- Test_##a##_##b() { g_testlist.push_back(&Run); } \
- static void Run() { \
- FlagSaver fs; \
- fprintf(stderr, "Running test %s/%s\n", #a, #b); \
- RunTest(); \
- } \
- static void RunTest(); \
- }; \
- static Test_##a##_##b g_test_##a##_##b; \
- void Test_##a##_##b::RunTest()
-
-// This is a dummy class that eases the google->opensource transition.
-namespace testing {
-class Test {};
-}
-
-// Call this in a .cc file where you will later call EXPECT_DEATH
-#define EXPECT_DEATH_INIT \
- static bool g_called_exit; \
- static void CalledExit(int) { g_called_exit = true; }
-
-#define EXPECT_DEATH(fn, msg) \
- do { \
- g_called_exit = false; \
- gflags_exitfunc = &CalledExit; \
- fn; \
- gflags_exitfunc = &exit; /* set back to its default */ \
- if (!g_called_exit) { \
- fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
- exit(1); \
- } \
- } while (0)
-
-#define GTEST_HAS_DEATH_TEST 1
-
-// -- path routines ----------------------------------------------------------
-
-// Tries to create the directory path as a temp-dir. If it fails,
-// changes path to some directory it *can* create.
-#if defined(__MINGW32__)
-#include <io.h>
-inline void MakeTmpdir(std::string* path) {
- if (!path->empty()) {
- path->append("/gflags_unittest_testdir");
- int err = mkdir(path->c_str());
- if (err == 0 || errno == EEXIST) return;
- }
- // I had trouble creating a directory in /tmp from mingw
- *path = "./gflags_unittest";
- mkdir(path->c_str());
-}
-#elif defined(_MSC_VER)
-#include <direct.h>
-inline void MakeTmpdir(std::string* path) {
- if (!path->empty()) {
- int err = _mkdir(path->c_str());
- if (err == 0 || errno == EEXIST) return;
- }
- char tmppath_buffer[1024];
- int tmppath_len = GetTempPathA(sizeof(tmppath_buffer), tmppath_buffer);
- assert(tmppath_len > 0 && tmppath_len < sizeof(tmppath_buffer));
- assert(tmppath_buffer[tmppath_len - 1] == '\\'); // API guarantees it
- *path = std::string(tmppath_buffer) + "gflags_unittest";
- _mkdir(path->c_str());
-}
-#else
-inline void MakeTmpdir(std::string* path) {
- if (!path->empty()) {
- int err = mkdir(path->c_str(), 0755);
- if (err == 0 || errno == EEXIST) return;
- }
- mkdir("/tmp/gflags_unittest", 0755);
-}
-#endif
-
-// -- string routines --------------------------------------------------------
-
-inline void InternalStringPrintf(std::string* output, const char* format,
- va_list ap) {
- char space[128]; // try a small buffer and hope it fits
-
- // It's possible for methods that use a va_list to invalidate
- // the data in it upon use. The fix is to make a copy
- // of the structure before using it and use that copy instead.
- va_list backup_ap;
- va_copy(backup_ap, ap);
- int bytes_written = vsnprintf(space, sizeof(space), format, backup_ap);
- va_end(backup_ap);
-
- if ((bytes_written >= 0) && (static_cast<size_t>(bytes_written) < sizeof(space))) {
- output->append(space, bytes_written);
- return;
- }
-
- // Repeatedly increase buffer size until it fits.
- int length = sizeof(space);
- while (true) {
- if (bytes_written < 0) {
- // Older snprintf() behavior. :-( Just try doubling the buffer size
- length *= 2;
- } else {
- // We need exactly "bytes_written+1" characters
- length = bytes_written+1;
- }
- char* buf = new char[length];
-
- // Restore the va_list before we use it again
- va_copy(backup_ap, ap);
- bytes_written = vsnprintf(buf, length, format, backup_ap);
- va_end(backup_ap);
-
- if ((bytes_written >= 0) && (bytes_written < length)) {
- output->append(buf, bytes_written);
- delete[] buf;
- return;
- }
- delete[] buf;
- }
-}
-
-// Clears output before writing to it.
-inline void SStringPrintf(std::string* output, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- output->clear();
- InternalStringPrintf(output, format, ap);
- va_end(ap);
-}
-
-inline void StringAppendF(std::string* output, const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- InternalStringPrintf(output, format, ap);
- va_end(ap);
-}
-
-inline std::string StringPrintf(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- std::string output;
- InternalStringPrintf(&output, format, ap);
- va_end(ap);
- return output;
-}
-
-inline bool SafeGetEnv(const char *varname, std::string &valstr)
-{
-#if defined(_MSC_VER) && _MSC_VER >= 1400
- char *val;
- size_t sz;
- if (_dupenv_s(&val, &sz, varname) != 0 || !val) return false;
- valstr = val;
- free(val);
-#else
- const char * const val = getenv(varname);
- if (!val) return false;
- valstr = val;
-#endif
- return true;
-}
-
-inline int SafeFOpen(FILE **fp, const char* fname, const char *mode)
-{
-#if defined(_MSC_VER) && _MSC_VER >= 1400
- return fopen_s(fp, fname, mode);
-#else
- assert(fp != NULL);
- *fp = fopen(fname, mode);
- // errno only guaranteed to be set on failure
- return ((*fp == NULL) ? errno : 0);
-#endif
-}
-
-
-} // namespace GFLAGS_NAMESPACE
-
-
-#endif // GFLAGS_UTIL_H_
diff --git a/extern/libmv/third_party/gflags/windows_port.cc b/extern/libmv/third_party/gflags/windows_port.cc
deleted file mode 100644
index 1f40458e888..00000000000
--- a/extern/libmv/third_party/gflags/windows_port.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Copyright (c) 2009, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ---
- * Author: Craig Silverstein
- */
-
-#ifndef _WIN32
-# error You should only be including windows/port.cc in a windows environment!
-#endif
-
-#include <string.h> // for strlen(), memset(), memcmp()
-#include <assert.h>
-#include <stdarg.h> // for va_list, va_start, va_end
-#include <windows.h>
-
-#include "windows_port.h"
-
-// These call the windows _vsnprintf, but always NUL-terminate.
-#if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */
-
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4996) // ignore _vsnprintf security warning
-#endif
-int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
- if (size == 0) // not even room for a \0?
- return -1; // not what C99 says to do, but what windows does
- str[size-1] = '\0';
- return _vsnprintf(str, size-1, format, ap);
-}
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
-
-int snprintf(char *str, size_t size, const char *format, ...) {
- int r;
- va_list ap;
- va_start(ap, format);
- r = vsnprintf(str, size, format, ap);
- va_end(ap);
- return r;
-}
-
-#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */
diff --git a/extern/libmv/third_party/gflags/windows_port.h b/extern/libmv/third_party/gflags/windows_port.h
deleted file mode 100644
index c8ff24f8f00..00000000000
--- a/extern/libmv/third_party/gflags/windows_port.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Copyright (c) 2009, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ---
- * Author: Craig Silverstein
- *
- * These are some portability typedefs and defines to make it a bit
- * easier to compile this code under VC++.
- *
- * Several of these are taken from glib:
- * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
- */
-
-#ifndef GFLAGS_WINDOWS_PORT_H_
-#define GFLAGS_WINDOWS_PORT_H_
-
-#include "config.h"
-
-// This must be defined before the windows.h is included.
-// It's needed for mutex.h, to give access to the TryLock method.
-# if !defined(_WIN32_WINNT) && !(defined( __MINGW32__) || defined(__MINGW64__))
-# define _WIN32_WINNT 0x0400
-# endif
-// We always want minimal includes
-#ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-#endif
-#include <windows.h>
-#include <direct.h> /* for mkdir */
-#include <stdlib.h> /* for _putenv, getenv */
-#include <stdio.h> /* need this to override stdio's snprintf, also defines _unlink used by unit tests */
-#include <stdarg.h> /* util.h uses va_copy */
-#include <string.h> /* for _stricmp and _strdup */
-
-/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
- * because they don't always NUL-terminate. :-( We also can't use the
- * name vsnprintf, since windows defines that (but not snprintf (!)).
- */
-#if !defined(__MINGW32__) && !defined(__MINGW64__) /* mingw already defines */
-extern GFLAGS_DLL_DECL int snprintf(char *str, size_t size,
- const char *format, ...);
-extern int GFLAGS_DLL_DECL safe_vsnprintf(char *str, size_t size,
- const char *format, va_list ap);
-#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
-#define va_copy(dst, src) (dst) = (src)
-#endif /* #if !defined(__MINGW32__) && !defined(__MINGW64__) */
-
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4996) // ignore getenv security warning
-#endif
-inline void setenv(const char* name, const char* value, int) {
- // In windows, it's impossible to set a variable to the empty string.
- // We handle this by setting it to "0" and the NUL-ing out the \0.
- // That is, we putenv("FOO=0") and then find out where in memory the
- // putenv wrote "FOO=0", and change it in-place to "FOO=\0".
- // c.f. http://svn.apache.org/viewvc/stdcxx/trunk/tests/src/environ.cpp?r1=611451&r2=637508&pathrev=637508
- static const char* const kFakeZero = "0";
- if (*value == '\0')
- value = kFakeZero;
- // Apparently the semantics of putenv() is that the input
- // must live forever, so we leak memory here. :-(
- const size_t nameval_len = strlen(name) + 1 + strlen(value) + 1;
- char* nameval = reinterpret_cast<char*>(malloc(nameval_len));
- snprintf(nameval, nameval_len, "%s=%s", name, value);
- _putenv(nameval);
- if (value == kFakeZero) {
- nameval[nameval_len - 2] = '\0'; // works when putenv() makes no copy
- if (*getenv(name) != '\0')
- *getenv(name) = '\0'; // works when putenv() copies nameval
- }
-}
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
-
-#define strcasecmp _stricmp
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400
-#define strdup _strdup
-#define unlink _unlink
-#endif
-
-#define PRId32 "d"
-#define PRIu32 "u"
-#define PRId64 "I64d"
-#define PRIu64 "I64u"
-
-#if !defined(__MINGW32__) && !defined(__MINGW64__)
-#define strtoq _strtoi64
-#define strtouq _strtoui64
-#define strtoll _strtoi64
-#define strtoull _strtoui64
-#define atoll _atoi64
-#endif
-
-#ifndef PATH_MAX
-#define PATH_MAX 1024
-#endif
-
-#endif /* GFLAGS_WINDOWS_PORT_H_ */
diff --git a/extern/libmv/third_party/glog/AUTHORS b/extern/libmv/third_party/glog/AUTHORS
deleted file mode 100644
index ee92be88dcf..00000000000
--- a/extern/libmv/third_party/glog/AUTHORS
+++ /dev/null
@@ -1,2 +0,0 @@
-opensource@google.com
-
diff --git a/extern/libmv/third_party/glog/README.libmv b/extern/libmv/third_party/glog/README.libmv
deleted file mode 100644
index 10e51fa6df4..00000000000
--- a/extern/libmv/third_party/glog/README.libmv
+++ /dev/null
@@ -1,9 +0,0 @@
-Project: Google Logging
-URL: http://code.google.com/p/google-glog/
-License: New BSD
-Upstream version: 0.3.3, r143
-Local modifications:
-* Added per-platform config.h files so no configuration-time
- checks for functions and so are needed.
-* See glog_tweaks.patch to see other tweaks which are done
- against glog upstream.
diff --git a/extern/libmv/third_party/glog/src/base/commandlineflags.h b/extern/libmv/third_party/glog/src/base/commandlineflags.h
deleted file mode 100644
index 529540ea461..00000000000
--- a/extern/libmv/third_party/glog/src/base/commandlineflags.h
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// ---
-// This file is a compatibility layer that defines Google's version of
-// command line flags that are used for configuration.
-//
-// We put flags into their own namespace. It is purposefully
-// named in an opaque way that people should have trouble typing
-// directly. The idea is that DEFINE puts the flag in the weird
-// namespace, and DECLARE imports the flag from there into the
-// current namespace. The net result is to force people to use
-// DECLARE to get access to a flag, rather than saying
-// extern bool FLAGS_logtostderr;
-// or some such instead. We want this so we can put extra
-// functionality (like sanity-checking) in DECLARE if we want,
-// and make sure it is picked up everywhere.
-//
-// We also put the type of the variable in the namespace, so that
-// people can't DECLARE_int32 something that they DEFINE_bool'd
-// elsewhere.
-#ifndef BASE_COMMANDLINEFLAGS_H__
-#define BASE_COMMANDLINEFLAGS_H__
-
-#include "../config.h"
-#include <string>
-#include <string.h> // for memchr
-#include <stdlib.h> // for getenv
-
-#ifdef HAVE_LIB_GFLAGS
-
-#include <gflags/gflags.h>
-
-#else
-
-#include "glog/logging.h"
-
-#define DECLARE_VARIABLE(type, shorttype, name, tn) \
- namespace fL##shorttype { \
- extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
- } \
- using fL##shorttype::FLAGS_##name
-#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
- namespace fL##shorttype { \
- GOOGLE_GLOG_DLL_DECL type FLAGS_##name(value); \
- char FLAGS_no##name; \
- } \
- using fL##shorttype::FLAGS_##name
-
-// bool specialization
-#define DECLARE_bool(name) \
- DECLARE_VARIABLE(bool, B, name, bool)
-#define DEFINE_bool(name, value, meaning) \
- DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
-
-// int32 specialization
-#define DECLARE_int32(name) \
- DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
-#define DEFINE_int32(name, value, meaning) \
- DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
-
-// Special case for string, because we have to specify the namespace
-// std::string, which doesn't play nicely with our FLAG__namespace hackery.
-#define DECLARE_string(name) \
- namespace fLS { \
- extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \
- } \
- using fLS::FLAGS_##name
-#define DEFINE_string(name, value, meaning) \
- namespace fLS { \
- std::string FLAGS_##name##_buf(value); \
- GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name = FLAGS_##name##_buf; \
- char FLAGS_no##name; \
- } \
- using fLS::FLAGS_##name
-
-#endif // HAVE_LIB_GFLAGS
-
-// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
-// have GLOG_* environ variables even if we have gflags installed.
-//
-// If both an environment variable and a flag are specified, the value
-// specified by a flag wins. E.g., if GLOG_v=0 and --v=1, the
-// verbosity will be 1, not 0.
-
-#define GLOG_DEFINE_bool(name, value, meaning) \
- DEFINE_bool(name, EnvToBool("GLOG_" #name, value), meaning)
-
-#define GLOG_DEFINE_int32(name, value, meaning) \
- DEFINE_int32(name, EnvToInt("GLOG_" #name, value), meaning)
-
-#define GLOG_DEFINE_string(name, value, meaning) \
- DEFINE_string(name, EnvToString("GLOG_" #name, value), meaning)
-
-// These macros (could be functions, but I don't want to bother with a .cc
-// file), make it easier to initialize flags from the environment.
-
-#define EnvToString(envname, dflt) \
- (!getenv(envname) ? (dflt) : getenv(envname))
-
-#define EnvToBool(envname, dflt) \
- (!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL)
-
-#define EnvToInt(envname, dflt) \
- (!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10))
-
-#endif // BASE_COMMANDLINEFLAGS_H__
diff --git a/extern/libmv/third_party/glog/src/base/mutex.h b/extern/libmv/third_party/glog/src/base/mutex.h
deleted file mode 100644
index 36fc55c4dcb..00000000000
--- a/extern/libmv/third_party/glog/src/base/mutex.h
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright (c) 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// ---
-// Author: Craig Silverstein.
-//
-// A simple mutex wrapper, supporting locks and read-write locks.
-// You should assume the locks are *not* re-entrant.
-//
-// To use: you should define the following macros in your configure.ac:
-// ACX_PTHREAD
-// AC_RWLOCK
-// The latter is defined in ../autoconf.
-//
-// This class is meant to be internal-only and should be wrapped by an
-// internal namespace. Before you use this module, please give the
-// name of your internal namespace for this module. Or, if you want
-// to expose it, you'll want to move it to the Google namespace. We
-// cannot put this class in global namespace because there can be some
-// problems when we have multiple versions of Mutex in each shared object.
-//
-// NOTE: by default, we have #ifdef'ed out the TryLock() method.
-// This is for two reasons:
-// 1) TryLock() under Windows is a bit annoying (it requires a
-// #define to be defined very early).
-// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
-// mode.
-// If you need TryLock(), and either these two caveats are not a
-// problem for you, or you're willing to work around them, then
-// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
-// in the code below.
-//
-// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
-// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
-// Because of that, we might as well use windows locks for
-// cygwin. They seem to be more reliable than the cygwin pthreads layer.
-//
-// TRICKY IMPLEMENTATION NOTE:
-// This class is designed to be safe to use during
-// dynamic-initialization -- that is, by global constructors that are
-// run before main() starts. The issue in this case is that
-// dynamic-initialization happens in an unpredictable order, and it
-// could be that someone else's dynamic initializer could call a
-// function that tries to acquire this mutex -- but that all happens
-// before this mutex's constructor has run. (This can happen even if
-// the mutex and the function that uses the mutex are in the same .cc
-// file.) Basically, because Mutex does non-trivial work in its
-// constructor, it's not, in the naive implementation, safe to use
-// before dynamic initialization has run on it.
-//
-// The solution used here is to pair the actual mutex primitive with a
-// bool that is set to true when the mutex is dynamically initialized.
-// (Before that it's false.) Then we modify all mutex routines to
-// look at the bool, and not try to lock/unlock until the bool makes
-// it to true (which happens after the Mutex constructor has run.)
-//
-// This works because before main() starts -- particularly, during
-// dynamic initialization -- there are no threads, so a) it's ok that
-// the mutex operations are a no-op, since we don't need locking then
-// anyway; and b) we can be quite confident our bool won't change
-// state between a call to Lock() and a call to Unlock() (that would
-// require a global constructor in one translation unit to call Lock()
-// and another global constructor in another translation unit to call
-// Unlock() later, which is pretty perverse).
-//
-// That said, it's tricky, and can conceivably fail; it's safest to
-// avoid trying to acquire a mutex in a global constructor, if you
-// can. One way it can fail is that a really smart compiler might
-// initialize the bool to true at static-initialization time (too
-// early) rather than at dynamic-initialization time. To discourage
-// that, we set is_safe_ to true in code (not the constructor
-// colon-initializer) and set it to true via a function that always
-// evaluates to true, but that the compiler can't know always
-// evaluates to true. This should be good enough.
-
-#ifndef GOOGLE_MUTEX_H_
-#define GOOGLE_MUTEX_H_
-
-#include "../config.h" // to figure out pthreads support
-
-#if defined(NO_THREADS)
- typedef int MutexType; // to keep a lock-count
-#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN // We only need minimal includes
-# endif
-# ifdef GMUTEX_TRYLOCK
- // We need Windows NT or later for TryEnterCriticalSection(). If you
- // don't need that functionality, you can remove these _WIN32_WINNT
- // lines, and change TryLock() to assert(0) or something.
-# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0400
-# endif
-# endif
-// To avoid macro definition of ERROR.
-# ifndef NOGDI
-# define NOGDI
-# endif
-// To avoid macro definition of min/max.
-# ifndef NOMINMAX
-# define NOMINMAX
-# endif
-# include <windows.h>
- typedef CRITICAL_SECTION MutexType;
-#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
- // Needed for pthread_rwlock_*. If it causes problems, you could take it
- // out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
- // *does* cause problems for FreeBSD, or MacOSX, but isn't needed
- // for locking there.)
-# ifdef __linux__
-# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
-# endif
-# include <pthread.h>
- typedef pthread_rwlock_t MutexType;
-#elif defined(HAVE_PTHREAD)
-# include <pthread.h>
- typedef pthread_mutex_t MutexType;
-#else
-# error Need to implement mutex.h for your architecture, or #define NO_THREADS
-#endif
-
-// We need to include these header files after defining _XOPEN_SOURCE
-// as they may define the _XOPEN_SOURCE macro.
-#include <assert.h>
-#include <stdlib.h> // for abort()
-
-#define MUTEX_NAMESPACE glog_internal_namespace_
-
-namespace MUTEX_NAMESPACE {
-
-class Mutex {
- public:
- // Create a Mutex that is not held by anybody. This constructor is
- // typically used for Mutexes allocated on the heap or the stack.
- // See below for a recommendation for constructing global Mutex
- // objects.
- inline Mutex();
-
- // Destructor
- inline ~Mutex();
-
- inline void Lock(); // Block if needed until free then acquire exclusively
- inline void Unlock(); // Release a lock acquired via Lock()
-#ifdef GMUTEX_TRYLOCK
- inline bool TryLock(); // If free, Lock() and return true, else return false
-#endif
- // Note that on systems that don't support read-write locks, these may
- // be implemented as synonyms to Lock() and Unlock(). So you can use
- // these for efficiency, but don't use them anyplace where being able
- // to do shared reads is necessary to avoid deadlock.
- inline void ReaderLock(); // Block until free or shared then acquire a share
- inline void ReaderUnlock(); // Release a read share of this Mutex
- inline void WriterLock() { Lock(); } // Acquire an exclusive lock
- inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
-
- // TODO(hamaji): Do nothing, implement correctly.
- inline void AssertHeld() {}
-
- private:
- MutexType mutex_;
- // We want to make sure that the compiler sets is_safe_ to true only
- // when we tell it to, and never makes assumptions is_safe_ is
- // always true. volatile is the most reliable way to do that.
- volatile bool is_safe_;
-
- inline void SetIsSafe() { is_safe_ = true; }
-
- // Catch the error of writing Mutex when intending MutexLock.
- Mutex(Mutex* /*ignored*/) {}
- // Disallow "evil" constructors
- Mutex(const Mutex&);
- void operator=(const Mutex&);
-};
-
-// Now the implementation of Mutex for various systems
-#if defined(NO_THREADS)
-
-// When we don't have threads, we can be either reading or writing,
-// but not both. We can have lots of readers at once (in no-threads
-// mode, that's most likely to happen in recursive function calls),
-// but only one writer. We represent this by having mutex_ be -1 when
-// writing and a number > 0 when reading (and 0 when no lock is held).
-//
-// In debug mode, we assert these invariants, while in non-debug mode
-// we do nothing, for efficiency. That's why everything is in an
-// assert.
-
-Mutex::Mutex() : mutex_(0) { }
-Mutex::~Mutex() { assert(mutex_ == 0); }
-void Mutex::Lock() { assert(--mutex_ == -1); }
-void Mutex::Unlock() { assert(mutex_++ == -1); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
-#endif
-void Mutex::ReaderLock() { assert(++mutex_ > 0); }
-void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
-
-#elif defined(_WIN32) || defined(__CYGWIN32__) || defined(__CYGWIN64__)
-
-Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
-Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
-void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
-void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- TryEnterCriticalSection(&mutex_) != 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
-void Mutex::ReaderUnlock() { Unlock(); }
-
-#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
-
-#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() {
- SetIsSafe();
- if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
-void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
-void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_rwlock_trywrlock(&mutex_) == 0 :
- true; }
-#endif
-void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
-void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
-#undef SAFE_PTHREAD
-
-#elif defined(HAVE_PTHREAD)
-
-#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
- if (is_safe_ && fncall(&mutex_) != 0) abort(); \
-} while (0)
-
-Mutex::Mutex() {
- SetIsSafe();
- if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
-}
-Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
-void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
-void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
-#ifdef GMUTEX_TRYLOCK
-bool Mutex::TryLock() { return is_safe_ ?
- pthread_mutex_trylock(&mutex_) == 0 : true; }
-#endif
-void Mutex::ReaderLock() { Lock(); }
-void Mutex::ReaderUnlock() { Unlock(); }
-#undef SAFE_PTHREAD
-
-#endif
-
-// --------------------------------------------------------------------------
-// Some helper classes
-
-// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
-class MutexLock {
- public:
- explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
- ~MutexLock() { mu_->Unlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- MutexLock(const MutexLock&);
- void operator=(const MutexLock&);
-};
-
-// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
-class ReaderMutexLock {
- public:
- explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
- ~ReaderMutexLock() { mu_->ReaderUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- ReaderMutexLock(const ReaderMutexLock&);
- void operator=(const ReaderMutexLock&);
-};
-
-class WriterMutexLock {
- public:
- explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
- ~WriterMutexLock() { mu_->WriterUnlock(); }
- private:
- Mutex * const mu_;
- // Disallow "evil" constructors
- WriterMutexLock(const WriterMutexLock&);
- void operator=(const WriterMutexLock&);
-};
-
-// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
-#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
-#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
-#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
-
-} // namespace MUTEX_NAMESPACE
-
-using namespace MUTEX_NAMESPACE;
-
-#undef MUTEX_NAMESPACE
-
-#endif /* #define GOOGLE_MUTEX_H__ */
diff --git a/extern/libmv/third_party/glog/src/config_freebsd.h b/extern/libmv/third_party/glog/src/config_freebsd.h
deleted file mode 100644
index a1fe76fe806..00000000000
--- a/extern/libmv/third_party/glog/src/config_freebsd.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* src/config.h. Generated from config.h.in by configure. */
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* Namespace for Google classes */
-#define GOOGLE_NAMESPACE google
-
-/* Define if you have the `dladdr' function */
-/* #undef HAVE_DLADDR */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if you have the <execinfo.h> header file. */
-#undef HAVE_EXECINFO_H
-
-/* Define if you have the `fcntl' function */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <glob.h> header file. */
-#define HAVE_GLOB_H 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `pthread' library (-lpthread). */
-#define HAVE_LIBPTHREAD 1
-
-/* Define to 1 if you have the <libunwind.h> header file. */
-/* #undef HAVE_LIBUNWIND_H */
-
-/* define if you have google gflags library */
-#define HAVE_LIB_GFLAGS 1
-
-/* define if you have google gmock library */
-/* #undef HAVE_LIB_GMOCK */
-
-/* define if you have google gtest library */
-/* #undef HAVE_LIB_GTEST */
-
-/* define if you have libunwind */
-/* #undef HAVE_LIB_UNWIND */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* define if the compiler implements namespaces */
-#define HAVE_NAMESPACES 1
-
-/* Define if you have the 'pread' function */
-#define HAVE_PREAD 1
-
-/* Define if you have POSIX threads libraries and header files. */
-#define HAVE_PTHREAD 1
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define if you have the 'pwrite' function */
-#define HAVE_PWRITE 1
-
-/* define if the compiler implements pthread_rwlock_* */
-#define HAVE_RWLOCK 1
-
-/* Define if you have the `sigaltstack' function */
-#define HAVE_SIGALTSTACK 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <syscall.h> header file. */
-/* #undef HAVE_SYSCALL_H */
-
-/* Define to 1 if you have the <syslog.h> header file. */
-#define HAVE_SYSLOG_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/syscall.h> header file. */
-#define HAVE_SYS_SYSCALL_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/ucontext.h> header file. */
-#define HAVE_SYS_UCONTEXT_H 1
-
-/* Define to 1 if you have the <sys/utsname.h> header file. */
-#define HAVE_SYS_UTSNAME_H 1
-
-/* Define to 1 if you have the <ucontext.h> header file. */
-#define HAVE_UCONTEXT_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* define if the compiler supports using expression for operator */
-#define HAVE_USING_OPERATOR 1
-
-/* define if your compiler has __attribute__ */
-#define HAVE___ATTRIBUTE__ 1
-
-/* define if your compiler has __builtin_expect */
-#define HAVE___BUILTIN_EXPECT 1
-
-/* define if your compiler has __sync_val_compare_and_swap */
-/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */
-
-/* Name of package */
-#define PACKAGE "glog"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "opensource@google.com"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "glog"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "glog 0.3.2"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "glog"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.3.2"
-
-/* How to access the PC from a struct ucontext */
-/* #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP] */
-
-/* Define to necessary symbol if this constant uses a non-standard name on
- your system. */
-/* #undef PTHREAD_CREATE_JOINABLE */
-
-/* The size of `void *', as computed by sizeof. */
-#define SIZEOF_VOID_P 8
-
-/* Define to 1 if you have the ANSI C header files. */
-/* #undef STDC_HEADERS */
-
-#define STDC_HEADERS 1
-/* the namespace where STL code like vector<> is defined */
-#define STL_NAMESPACE std
-
-/* location of source code */
-#define TEST_SRC_DIR "."
-
-/* Version number of package */
-#define VERSION "0.3.2"
-
-/* Stops putting the code inside the Google namespace */
-#define _END_GOOGLE_NAMESPACE_ }
-
-/* Puts following code inside the Google namespace */
-#define _START_GOOGLE_NAMESPACE_ namespace google {
-
-/* isn't getting defined by configure script when clang compilers are used
- and cuases compilation errors in stactrace/unwind modules */
-#ifdef __clang__
-# define NO_FRAME_POINTER
-#endif
diff --git a/extern/libmv/third_party/glog/src/config_hurd.h b/extern/libmv/third_party/glog/src/config_hurd.h
deleted file mode 100644
index 81e8ed7bac3..00000000000
--- a/extern/libmv/third_party/glog/src/config_hurd.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* src/config.h. Generated from config.h.in by configure. */
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* Namespace for Google classes */
-#define GOOGLE_NAMESPACE google
-
-/* Define if you have the `dladdr' function */
-/* #undef HAVE_DLADDR */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if you have the <execinfo.h> header file. */
-#define HAVE_EXECINFO_H 1
-
-/* Define if you have the `fcntl' function */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <glob.h> header file. */
-#define HAVE_GLOB_H 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `pthread' library (-lpthread). */
-#define HAVE_LIBPTHREAD 1
-
-/* Define to 1 if you have the <libunwind.h> header file. */
-/* #undef HAVE_LIBUNWIND_H */
-
-/* define if you have google gflags library */
-#define HAVE_LIB_GFLAGS 1
-
-/* define if you have google gmock library */
-/* #undef HAVE_LIB_GMOCK */
-
-/* define if you have google gtest library */
-/* #undef HAVE_LIB_GTEST */
-
-/* define if you have libunwind */
-/* #undef HAVE_LIB_UNWIND */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* define if the compiler implements namespaces */
-#define HAVE_NAMESPACES 1
-
-/* Define if you have the 'pread' function */
-#define HAVE_PREAD 1
-
-/* Define if you have POSIX threads libraries and header files. */
-#define HAVE_PTHREAD 1
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define if you have the 'pwrite' function */
-#define HAVE_PWRITE 1
-
-/* define if the compiler implements pthread_rwlock_* */
-#define HAVE_RWLOCK 1
-
-/* Define if you have the `sigaltstack' function */
-#define HAVE_SIGALTSTACK 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <syscall.h> header file. */
-/* #undef HAVE_SYSCALL_H */
-
-/* Define to 1 if you have the <syslog.h> header file. */
-#define HAVE_SYSLOG_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/syscall.h> header file. */
-/* #undef HAVE_SYS_SYSCALL_H */
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/ucontext.h> header file. */
-#define HAVE_SYS_UCONTEXT_H 1
-
-/* Define to 1 if you have the <sys/utsname.h> header file. */
-#define HAVE_SYS_UTSNAME_H 1
-
-/* Define to 1 if you have the <ucontext.h> header file. */
-#define HAVE_UCONTEXT_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* define if the compiler supports using expression for operator */
-#define HAVE_USING_OPERATOR 1
-
-/* define if your compiler has __attribute__ */
-#define HAVE___ATTRIBUTE__ 1
-
-/* define if your compiler has __builtin_expect */
-#define HAVE___BUILTIN_EXPECT 1
-
-/* define if your compiler has __sync_val_compare_and_swap */
-/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */
-
-/* Name of package */
-#define PACKAGE "glog"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "opensource@google.com"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "glog"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "glog 0.3.1"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "glog"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.3.1"
-
-/* How to access the PC from a struct ucontext */
-#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
- #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
-#elif defined(_M_IX86) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
- #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
-#else
- #undef PC_FROM_UCONTEXT
-#endif
-
-/* Define to necessary symbol if this constant uses a non-standard name on
- your system. */
-/* #undef PTHREAD_CREATE_JOINABLE */
-
-/* The size of `void *', as computed by sizeof. */
-#define SIZEOF_VOID_P 4
-
-/* Define to 1 if you have the ANSI C header files. */
-/* #undef STDC_HEADERS */
-
-#define STDC_HEADERS 1
-/* the namespace where STL code like vector<> is defined */
-#define STL_NAMESPACE std
-
-/* location of source code */
-#define TEST_SRC_DIR "."
-
-/* Version number of package */
-#define VERSION "0.3.1"
-
-/* Stops putting the code inside the Google namespace */
-#define _END_GOOGLE_NAMESPACE_ }
-
-/* Puts following code inside the Google namespace */
-#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/extern/libmv/third_party/glog/src/config_linux.h b/extern/libmv/third_party/glog/src/config_linux.h
deleted file mode 100644
index 7741ddebb63..00000000000
--- a/extern/libmv/third_party/glog/src/config_linux.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/* src/config.h. Generated from config.h.in by configure. */
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* Namespace for Google classes */
-#define GOOGLE_NAMESPACE google
-
-/* Define if you have the `dladdr' function */
-/* #undef HAVE_DLADDR */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if you have the <execinfo.h> header file. */
-#define HAVE_EXECINFO_H 1
-
-/* Define if you have the `fcntl' function */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <glob.h> header file. */
-#define HAVE_GLOB_H 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `pthread' library (-lpthread). */
-#define HAVE_LIBPTHREAD 1
-
-/* Define to 1 if you have the <libunwind.h> header file. */
-/* #undef HAVE_LIBUNWIND_H */
-
-/* define if you have google gflags library */
-#define HAVE_LIB_GFLAGS 1
-
-/* define if you have google gmock library */
-/* #undef HAVE_LIB_GMOCK */
-
-/* define if you have google gtest library */
-/* #undef HAVE_LIB_GTEST */
-
-/* define if you have libunwind */
-/* #undef HAVE_LIB_UNWIND */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* define if the compiler implements namespaces */
-#define HAVE_NAMESPACES 1
-
-/* Define if you have the 'pread' function */
-#define HAVE_PREAD 1
-
-/* Define if you have POSIX threads libraries and header files. */
-#define HAVE_PTHREAD 1
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define if you have the 'pwrite' function */
-#define HAVE_PWRITE 1
-
-/* define if the compiler implements pthread_rwlock_* */
-#define HAVE_RWLOCK 1
-
-/* Define if you have the `sigaltstack' function */
-#define HAVE_SIGALTSTACK 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <syscall.h> header file. */
-#define HAVE_SYSCALL_H 1
-
-/* Define to 1 if you have the <syslog.h> header file. */
-#define HAVE_SYSLOG_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/syscall.h> header file. */
-#define HAVE_SYS_SYSCALL_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/ucontext.h> header file. */
-#define HAVE_SYS_UCONTEXT_H 1
-
-/* Define to 1 if you have the <sys/utsname.h> header file. */
-#define HAVE_SYS_UTSNAME_H 1
-
-/* Define to 1 if you have the <ucontext.h> header file. */
-#define HAVE_UCONTEXT_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* define if the compiler supports using expression for operator */
-#define HAVE_USING_OPERATOR 1
-
-/* define if your compiler has __attribute__ */
-#define HAVE___ATTRIBUTE__ 1
-
-/* define if your compiler has __builtin_expect */
-#define HAVE___BUILTIN_EXPECT 1
-
-/* define if your compiler has __sync_val_compare_and_swap */
-/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
-#define LT_OBJDIR ".libs/"
-
-/* Name of package */
-#define PACKAGE "glog"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "opensource@google.com"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "glog"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "glog 0.3.2"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "glog"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.3.2"
-
-/* How to access the PC from a struct ucontext */
-#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
- #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
-#elif defined(_M_IX86) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
- #define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
-#else
- #undef PC_FROM_UCONTEXT
-#endif
-
-/* Define to necessary symbol if this constant uses a non-standard name on
- your system. */
-/* #undef PTHREAD_CREATE_JOINABLE */
-
-/* The size of `void *', as computed by sizeof. */
-#define SIZEOF_VOID_P 8
-
-/* Define to 1 if you have the ANSI C header files. */
-/* #undef STDC_HEADERS */
-
-#define STDC_HEADERS 1
-/* the namespace where STL code like vector<> is defined */
-#define STL_NAMESPACE std
-
-/* location of source code */
-#define TEST_SRC_DIR "."
-
-/* Version number of package */
-#define VERSION "0.3.2"
-
-/* Stops putting the code inside the Google namespace */
-#define _END_GOOGLE_NAMESPACE_ }
-
-/* Puts following code inside the Google namespace */
-#define _START_GOOGLE_NAMESPACE_ namespace google {
-
-/* isn't getting defined by configure script when clang compilers are used
- and cuases compilation errors in stactrace/unwind modules */
-#ifdef __clang__
-# define NO_FRAME_POINTER
-#endif
diff --git a/extern/libmv/third_party/glog/src/config_mac.h b/extern/libmv/third_party/glog/src/config_mac.h
deleted file mode 100644
index 1695472f031..00000000000
--- a/extern/libmv/third_party/glog/src/config_mac.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* src/config.h. Generated from config.h.in by configure. */
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* Namespace for Google classes */
-#define GOOGLE_NAMESPACE google
-
-/* Define if you have the `dladdr' function */
-#define HAVE_DLADDR 1
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if you have the <execinfo.h> header file. */
-#define HAVE_EXECINFO_H 1
-
-/* Define if you have the `fcntl' function */
-#define HAVE_FCNTL 1
-
-/* Define to 1 if you have the <glob.h> header file. */
-#define HAVE_GLOB_H 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `pthread' library (-lpthread). */
-#define HAVE_LIBPTHREAD 1
-
-/* Define to 1 if you have the <libunwind.h> header file. */
-#define HAVE_LIBUNWIND_H 1
-
-/* define if you have google gflags library */
-#define HAVE_LIB_GFLAGS 1
-
-/* define if you have google gmock library */
-/* #undef HAVE_LIB_GMOCK */
-
-/* define if you have google gtest library */
-//#define HAVE_LIB_GTEST 1
-
-/* define if you have libunwind */
-/* #undef HAVE_LIB_UNWIND */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* define if the compiler implements namespaces */
-#define HAVE_NAMESPACES 1
-
-/* Define if you have the 'pread' function */
-#define HAVE_PREAD 1
-
-/* Define if you have POSIX threads libraries and header files. */
-#define HAVE_PTHREAD 1
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define if you have the 'pwrite' function */
-#define HAVE_PWRITE 1
-
-/* define if the compiler implements pthread_rwlock_* */
-#define HAVE_RWLOCK 1
-
-/* Define if you have the `sigaltstack' function */
-#define HAVE_SIGALTSTACK 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the <syscall.h> header file. */
-/* #undef HAVE_SYSCALL_H */
-
-/* Define to 1 if you have the <syslog.h> header file. */
-#define HAVE_SYSLOG_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/syscall.h> header file. */
-#define HAVE_SYS_SYSCALL_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/ucontext.h> header file. */
-#define HAVE_SYS_UCONTEXT_H 1
-
-/* Define to 1 if you have the <sys/utsname.h> header file. */
-#define HAVE_SYS_UTSNAME_H 1
-
-/* Define to 1 if you have the <ucontext.h> header file. */
-/* #undef HAVE_UCONTEXT_H */
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* define if the compiler supports using expression for operator */
-#define HAVE_USING_OPERATOR 1
-
-/* define if your compiler has __attribute__ */
-#define HAVE___ATTRIBUTE__ 1
-
-/* define if your compiler has __builtin_expect */
-#define HAVE___BUILTIN_EXPECT 1
-
-/* define if your compiler has __sync_val_compare_and_swap */
-/* #undef HAVE___SYNC_VAL_COMPARE_AND_SWAP */
-
-/* Name of package */
-#define PACKAGE "glog"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "opensource@google.com"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "glog"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "glog 0.3.2"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "glog"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.3.2"
-
-/* How to access the PC from a struct ucontext */
-#undef PC_FROM_UCONTEXT
-
-/* Define to necessary symbol if this constant uses a non-standard name on
- your system. */
-/* #undef PTHREAD_CREATE_JOINABLE */
-
-/* The size of `void *', as computed by sizeof. */
-#define SIZEOF_VOID_P 8
-
-/* Define to 1 if you have the ANSI C header files. */
-/* #undef STDC_HEADERS */
-
-/* the namespace where STL code like vector<> is defined */
-#define STL_NAMESPACE std
-
-/* location of source code */
-#define TEST_SRC_DIR "."
-
-/* Version number of package */
-#define VERSION "0.3.2"
-
-/* Stops putting the code inside the Google namespace */
-#define _END_GOOGLE_NAMESPACE_ }
-
-/* Puts following code inside the Google namespace */
-#define _START_GOOGLE_NAMESPACE_ namespace google {
-
-/* isn't getting defined by configure script when clang compilers are used
- and cuases compilation errors in stactrace/unwind modules */
-#ifdef __clang__
-# define NO_FRAME_POINTER
-#endif
diff --git a/extern/libmv/third_party/glog/src/demangle.h b/extern/libmv/third_party/glog/src/demangle.h
deleted file mode 100644
index 9c7591527c0..00000000000
--- a/extern/libmv/third_party/glog/src/demangle.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-//
-// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
-// (aka G++ V3 ABI).
-
-// The demangler is implemented to be used in async signal handlers to
-// symbolize stack traces. We cannot use libstdc++'s
-// abi::__cxa_demangle() in such signal handlers since it's not async
-// signal safe (it uses malloc() internally).
-//
-// Note that this demangler doesn't support full demangling. More
-// specifically, it doesn't print types of function parameters and
-// types of template arguments. It just skips them. However, it's
-// still very useful to extract basic information such as class,
-// function, constructor, destructor, and operator names.
-//
-// See the implementation note in demangle.cc if you are interested.
-//
-// Example:
-//
-// | Mangled Name | The Demangler | abi::__cxa_demangle()
-// |---------------|---------------|-----------------------
-// | _Z1fv | f() | f()
-// | _Z1fi | f() | f(int)
-// | _Z3foo3bar | foo() | foo(bar)
-// | _Z1fIiEvi | f<>() | void f<int>(int)
-// | _ZN1N1fE | N::f | N::f
-// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
-// | _Zrm1XS_" | operator%() | operator%(X, X)
-// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
-// | _Z1fSs | f() | f(std::basic_string<char,
-// | | | std::char_traits<char>,
-// | | | std::allocator<char> >)
-//
-// See the unit test for more examples.
-//
-// Note: we might want to write demanglers for ABIs other than Itanium
-// C++ ABI in the future.
-//
-
-#ifndef BASE_DEMANGLE_H_
-#define BASE_DEMANGLE_H_
-
-#include "config.h"
-
-_START_GOOGLE_NAMESPACE_
-
-// Demangle "mangled". On success, return true and write the
-// demangled symbol name to "out". Otherwise, return false.
-// "out" is modified even if demangling is unsuccessful.
-bool Demangle(const char *mangled, char *out, int out_size);
-
-_END_GOOGLE_NAMESPACE_
-
-#endif // BASE_DEMANGLE_H_
diff --git a/extern/libmv/third_party/glog/src/glog/logging.h b/extern/libmv/third_party/glog/src/glog/logging.h
deleted file mode 100644
index 247c0467b6a..00000000000
--- a/extern/libmv/third_party/glog/src/glog/logging.h
+++ /dev/null
@@ -1,1609 +0,0 @@
-// Copyright (c) 1999, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Ray Sidney
-//
-// This file contains #include information about logging-related stuff.
-// Pretty much everybody needs to #include this file so that they can
-// log various happenings.
-//
-#ifdef WIN32
-# include "windows/glog/logging.h"
-#else // WIN32
-
-#ifndef _LOGGING_H_
-#define _LOGGING_H_
-
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <iosfwd>
-#include <ostream>
-#include <sstream>
-#include <string>
-#if 1
-# include <unistd.h>
-#endif
-#include <vector>
-
-// Annoying stuff for windows -- makes sure clients can import these functions
-#ifndef GOOGLE_GLOG_DLL_DECL
-# if defined(_WIN32) && !defined(__CYGWIN__)
-# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
-# else
-# define GOOGLE_GLOG_DLL_DECL
-# endif
-#endif
-#if defined(_MSC_VER)
-#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
- __pragma(warning(disable:n))
-#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
-#else
-#define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
-#define GLOG_MSVC_POP_WARNING()
-#endif
-
-// We care a lot about number of bits things take up. Unfortunately,
-// systems define their bit-specific ints in a lot of different ways.
-// We use our own way, and have a typedef to get there.
-// Note: these commands below may look like "#if 1" or "#if 0", but
-// that's because they were constructed that way at ./configure time.
-// Look at logging.h.in to see how they're calculated (based on your config).
-#if 1
-#include <stdint.h> // the normal place uint16_t is defined
-#endif
-#if 1
-#include <sys/types.h> // the normal place u_int16_t is defined
-#endif
-#if 1
-#include <inttypes.h> // a third place for uint16_t or u_int16_t
-#endif
-
-#if 1
-#include <gflags/gflags.h>
-#endif
-
-namespace google {
-
-#if 1 // the C99 format
-typedef int32_t int32;
-typedef uint32_t uint32;
-typedef int64_t int64;
-typedef uint64_t uint64;
-#elif 1 // the BSD format
-typedef int32_t int32;
-typedef u_int32_t uint32;
-typedef int64_t int64;
-typedef u_int64_t uint64;
-#elif 0 // the windows (vc7) format
-typedef __int32 int32;
-typedef unsigned __int32 uint32;
-typedef __int64 int64;
-typedef unsigned __int64 uint64;
-#else
-#error Do not know how to define a 32-bit integer quantity on your system
-#endif
-
-}
-
-// The global value of GOOGLE_STRIP_LOG. All the messages logged to
-// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.
-// If it can be determined at compile time that the message will not be
-// printed, the statement will be compiled out.
-//
-// Example: to strip out all INFO and WARNING messages, use the value
-// of 2 below. To make an exception for WARNING messages from a single
-// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
-// base/logging.h
-#ifndef GOOGLE_STRIP_LOG
-#define GOOGLE_STRIP_LOG 0
-#endif
-
-// GCC can be told that a certain branch is not likely to be taken (for
-// instance, a CHECK failure), and use that information in static analysis.
-// Giving it this information can help it optimize for the common case in
-// the absence of better information (ie. -fprofile-arcs).
-//
-#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
-#if 1
-#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
-#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
-#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-#else
-#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
-#define GOOGLE_PREDICT_FALSE(x) x
-#define GOOGLE_PREDICT_TRUE(x) x
-#endif
-#endif
-
-// Make a bunch of macros for logging. The way to log things is to stream
-// things to LOG(<a particular severity level>). E.g.,
-//
-// LOG(INFO) << "Found " << num_cookies << " cookies";
-//
-// You can capture log messages in a string, rather than reporting them
-// immediately:
-//
-// vector<string> errors;
-// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num;
-//
-// This pushes back the new error onto 'errors'; if given a NULL pointer,
-// it reports the error via LOG(ERROR).
-//
-// You can also do conditional logging:
-//
-// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
-//
-// You can also do occasional logging (log every n'th occurrence of an
-// event):
-//
-// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
-//
-// The above will cause log messages to be output on the 1st, 11th, 21st, ...
-// times it is executed. Note that the special google::COUNTER value is used
-// to identify which repetition is happening.
-//
-// You can also do occasional conditional logging (log every n'th
-// occurrence of an event, when condition is satisfied):
-//
-// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
-// << "th big cookie";
-//
-// You can log messages the first N times your code executes a line. E.g.
-//
-// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
-//
-// Outputs log messages for the first 20 times it is executed.
-//
-// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.
-// These log to syslog as well as to the normal logs. If you use these at
-// all, you need to be aware that syslog can drastically reduce performance,
-// especially if it is configured for remote logging! Don't use these
-// unless you fully understand this and have a concrete need to use them.
-// Even then, try to minimize your use of them.
-//
-// There are also "debug mode" logging macros like the ones above:
-//
-// DLOG(INFO) << "Found cookies";
-//
-// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
-//
-// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
-//
-// All "debug mode" logging is compiled away to nothing for non-debug mode
-// compiles.
-//
-// We also have
-//
-// LOG_ASSERT(assertion);
-// DLOG_ASSERT(assertion);
-//
-// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
-//
-// There are "verbose level" logging macros. They look like
-//
-// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
-// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
-//
-// These always log at the INFO log level (when they log at all).
-// The verbose logging can also be turned on module-by-module. For instance,
-// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0
-// will cause:
-// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}
-// b. VLOG(1) and lower messages to be printed from file.{h,cc}
-// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs"
-// d. VLOG(0) and lower messages to be printed from elsewhere
-//
-// The wildcarding functionality shown by (c) supports both '*' (match
-// 0 or more characters) and '?' (match any single character) wildcards.
-//
-// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
-//
-// if (VLOG_IS_ON(2)) {
-// // do some logging preparation and logging
-// // that can't be accomplished with just VLOG(2) << ...;
-// }
-//
-// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level"
-// condition macros for sample cases, when some extra computation and
-// preparation for logs is not needed.
-// VLOG_IF(1, (size > 1024))
-// << "I'm printed when size is more than 1024 and when you run the "
-// "program with --v=1 or more";
-// VLOG_EVERY_N(1, 10)
-// << "I'm printed every 10th occurrence, and when you run the program "
-// "with --v=1 or more. Present occurence is " << google::COUNTER;
-// VLOG_IF_EVERY_N(1, (size > 1024), 10)
-// << "I'm printed on every 10th occurence of case when size is more "
-// " than 1024, when you run the program with --v=1 or more. ";
-// "Present occurence is " << google::COUNTER;
-//
-// The supported severity levels for macros that allow you to specify one
-// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
-// Note that messages of a given severity are logged not only in the
-// logfile for that severity, but also in all logfiles of lower severity.
-// E.g., a message of severity FATAL will be logged to the logfiles of
-// severity FATAL, ERROR, WARNING, and INFO.
-//
-// There is also the special severity of DFATAL, which logs FATAL in
-// debug mode, ERROR in normal mode.
-//
-// Very important: logging a message at the FATAL severity level causes
-// the program to terminate (after the message is logged).
-//
-// Unless otherwise specified, logs will be written to the filename
-// "<program name>.<hostname>.<user name>.log.<severity level>.", followed
-// by the date, time, and pid (you can't prevent the date, time, and pid
-// from being in the filename).
-//
-// The logging code takes two flags:
-// --v=# set the verbose level
-// --logtostderr log all the messages to stderr instead of to logfiles
-
-// LOG LINE PREFIX FORMAT
-//
-// Log lines have this form:
-//
-// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
-//
-// where the fields are defined as follows:
-//
-// L A single character, representing the log level
-// (eg 'I' for INFO)
-// mm The month (zero padded; ie May is '05')
-// dd The day (zero padded)
-// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
-// threadid The space-padded thread ID as returned by GetTID()
-// (this matches the PID on Linux)
-// file The file name
-// line The line number
-// msg The user-supplied message
-//
-// Example:
-//
-// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
-// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
-//
-// NOTE: although the microseconds are useful for comparing events on
-// a single machine, clocks on different machines may not be well
-// synchronized. Hence, use caution when comparing the low bits of
-// timestamps from different machines.
-
-#ifndef DECLARE_VARIABLE
-#define MUST_UNDEF_GFLAGS_DECLARE_MACROS
-#define DECLARE_VARIABLE(type, shorttype, name, tn) \
- namespace fL##shorttype { \
- extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
- } \
- using fL##shorttype::FLAGS_##name
-
-// bool specialization
-#define DECLARE_bool(name) \
- DECLARE_VARIABLE(bool, B, name, bool)
-
-// int32 specialization
-#define DECLARE_int32(name) \
- DECLARE_VARIABLE(google::int32, I, name, int32)
-
-// Special case for string, because we have to specify the namespace
-// std::string, which doesn't play nicely with our FLAG__namespace hackery.
-#define DECLARE_string(name) \
- namespace fLS { \
- extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \
- } \
- using fLS::FLAGS_##name
-#endif
-
-// Set whether log messages go to stderr instead of logfiles
-DECLARE_bool(logtostderr);
-
-// Set whether log messages go to stderr in addition to logfiles.
-DECLARE_bool(alsologtostderr);
-
-// Set color messages logged to stderr (if supported by terminal).
-DECLARE_bool(colorlogtostderr);
-
-// Log messages at a level >= this flag are automatically sent to
-// stderr in addition to log files.
-DECLARE_int32(stderrthreshold);
-
-// Set whether the log prefix should be prepended to each line of output.
-DECLARE_bool(log_prefix);
-
-// Log messages at a level <= this flag are buffered.
-// Log messages at a higher level are flushed immediately.
-DECLARE_int32(logbuflevel);
-
-// Sets the maximum number of seconds which logs may be buffered for.
-DECLARE_int32(logbufsecs);
-
-// Log suppression level: messages logged at a lower level than this
-// are suppressed.
-DECLARE_int32(minloglevel);
-
-// If specified, logfiles are written into this directory instead of the
-// default logging directory.
-DECLARE_string(log_dir);
-
-// Sets the path of the directory into which to put additional links
-// to the log files.
-DECLARE_string(log_link);
-
-DECLARE_int32(v); // in vlog_is_on.cc
-
-// Sets the maximum log file size (in MB).
-DECLARE_int32(max_log_size);
-
-// Sets whether to avoid logging to the disk if the disk is full.
-DECLARE_bool(stop_logging_if_full_disk);
-
-#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS
-#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS
-#undef DECLARE_VARIABLE
-#undef DECLARE_bool
-#undef DECLARE_int32
-#undef DECLARE_string
-#endif
-
-// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for
-// security reasons. See LOG(severtiy) below.
-
-// A few definitions of macros that don't generate much code. Since
-// LOG(INFO) and its ilk are used all over our code, it's
-// better to have compact code for these operations.
-
-#if GOOGLE_STRIP_LOG == 0
-#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
- __FILE__, __LINE__)
-#define LOG_TO_STRING_INFO(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_INFO, message)
-#else
-#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
-#define LOG_TO_STRING_INFO(message) google::NullStream()
-#endif
-
-#if GOOGLE_STRIP_LOG <= 1
-#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_WARNING)
-#define LOG_TO_STRING_WARNING(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_WARNING, message)
-#else
-#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
-#define LOG_TO_STRING_WARNING(message) google::NullStream()
-#endif
-
-#if GOOGLE_STRIP_LOG <= 2
-#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ERROR)
-#define LOG_TO_STRING_ERROR(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ERROR, message)
-#else
-#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
-#define LOG_TO_STRING_ERROR(message) google::NullStream()
-#endif
-
-#if GOOGLE_STRIP_LOG <= 3
-#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \
- __FILE__, __LINE__)
-#define LOG_TO_STRING_FATAL(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_FATAL, message)
-#else
-#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
-#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
-#endif
-
-// For DFATAL, we want to use LogMessage (as opposed to
-// LogMessageFatal), to be consistent with the original behavior.
-#ifdef NDEBUG
-#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
-#elif GOOGLE_STRIP_LOG <= 3
-#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_FATAL)
-#else
-#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
-#endif
-
-#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog)
-#define SYSLOG_INFO(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_WARNING(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_WARNING(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_ERROR(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_ERROR(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_FATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_FATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_DFATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_DFATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-
-#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
-// A very useful logging macro to log windows errors:
-#define LOG_SYSRESULT(result) \
- if (FAILED(HRESULT_FROM_WIN32(result))) { \
- LPSTR message = NULL; \
- LPSTR msg = reinterpret_cast<LPSTR>(&message); \
- DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
- FORMAT_MESSAGE_FROM_SYSTEM, \
- 0, result, 0, msg, 100, NULL); \
- if (message_length > 0) { \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \
- &google::LogMessage::SendToLog).stream() \
- << reinterpret_cast<const char*>(message); \
- LocalFree(message); \
- } \
- }
-#endif
-
-// We use the preprocessor's merging operator, "##", so that, e.g.,
-// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny
-// subtle difference between ostream member streaming functions (e.g.,
-// ostream::operator<<(int) and ostream non-member streaming functions
-// (e.g., ::operator<<(ostream&, string&): it turns out that it's
-// impossible to stream something like a string directly to an unnamed
-// ostream. We employ a neat hack by calling the stream() member
-// function of LogMessage which seems to avoid the problem.
-#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
-#define SYSLOG(severity) SYSLOG_ ## severity(0).stream()
-
-namespace google {
-
-// They need the definitions of integer types.
-#include "glog/log_severity.h"
-#include "glog/vlog_is_on.h"
-
-// Initialize google's logging library. You will see the program name
-// specified by argv0 in log outputs.
-GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0);
-
-// Shutdown google's logging library.
-GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging();
-
-// Install a function which will be called after LOG(FATAL).
-GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)());
-
-class LogSink; // defined below
-
-// If a non-NULL sink pointer is given, we push this message to that sink.
-// For LOG_TO_SINK we then do normal LOG(severity) logging as well.
-// This is useful for capturing messages and passing/storing them
-// somewhere more specific than the global log of the process.
-// Argument types:
-// LogSink* sink;
-// LogSeverity severity;
-// The cast is to disambiguate NULL arguments.
-#define LOG_TO_SINK(sink, severity) \
- google::LogMessage( \
- __FILE__, __LINE__, \
- google::GLOG_ ## severity, \
- static_cast<google::LogSink*>(sink), true).stream()
-#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \
- google::LogMessage( \
- __FILE__, __LINE__, \
- google::GLOG_ ## severity, \
- static_cast<google::LogSink*>(sink), false).stream()
-
-// If a non-NULL string pointer is given, we write this message to that string.
-// We then do normal LOG(severity) logging as well.
-// This is useful for capturing messages and storing them somewhere more
-// specific than the global log of the process.
-// Argument types:
-// string* message;
-// LogSeverity severity;
-// The cast is to disambiguate NULL arguments.
-// NOTE: LOG(severity) expands to LogMessage().stream() for the specified
-// severity.
-#define LOG_TO_STRING(severity, message) \
- LOG_TO_STRING_##severity(static_cast<string*>(message)).stream()
-
-// If a non-NULL pointer is given, we push the message onto the end
-// of a vector of strings; otherwise, we report it with LOG(severity).
-// This is handy for capturing messages and perhaps passing them back
-// to the caller, rather than reporting them immediately.
-// Argument types:
-// LogSeverity severity;
-// vector<string> *outvec;
-// The cast is to disambiguate NULL arguments.
-#define LOG_STRING(severity, outvec) \
- LOG_TO_STRING_##severity(static_cast<vector<string>*>(outvec)).stream()
-
-#define LOG_IF(severity, condition) \
- !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-#define SYSLOG_IF(severity, condition) \
- !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
-
-#define LOG_ASSERT(condition) \
- LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
-#define SYSLOG_ASSERT(condition) \
- SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
-
-// CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
-// compilation mode. Therefore, it is safe to do things like:
-// CHECK(fp->Write(x) == 4)
-#define CHECK(condition) \
- LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
- << "Check failed: " #condition " "
-
-// A container for a string pointer which can be evaluated to a bool -
-// true iff the pointer is NULL.
-struct CheckOpString {
- CheckOpString(std::string* str) : str_(str) { }
- // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
- // so there's no point in cleaning up str_.
- operator bool() const {
- return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL);
- }
- std::string* str_;
-};
-
-// Function is overloaded for integral types to allow static const
-// integrals declared in classes and not defined to be used as arguments to
-// CHECK* macros. It's not encouraged though.
-template <class T>
-inline const T& GetReferenceableValue(const T& t) { return t; }
-inline char GetReferenceableValue(char t) { return t; }
-inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
-inline signed char GetReferenceableValue(signed char t) { return t; }
-inline short GetReferenceableValue(short t) { return t; }
-inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
-inline int GetReferenceableValue(int t) { return t; }
-inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
-inline long GetReferenceableValue(long t) { return t; }
-inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
-inline long long GetReferenceableValue(long long t) { return t; }
-inline unsigned long long GetReferenceableValue(unsigned long long t) {
- return t;
-}
-
-// This is a dummy class to define the following operator.
-struct DummyClassToDefineOperator {};
-
-}
-
-// Define global operator<< to declare using ::operator<<.
-// This declaration will allow use to use CHECK macros for user
-// defined classes which have operator<< (e.g., stl_logging.h).
-inline std::ostream& operator<<(
- std::ostream& out, const google::DummyClassToDefineOperator&) {
- return out;
-}
-
-namespace google {
-
-// This formats a value for a failing CHECK_XX statement. Ordinarily,
-// it uses the definition for operator<<, with a few special cases below.
-template <typename T>
-inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
- (*os) << v;
-}
-
-// Overrides for char types provide readable values for unprintable
-// characters.
-template <> GOOGLE_GLOG_DLL_DECL
-void MakeCheckOpValueString(std::ostream* os, const char& v);
-template <> GOOGLE_GLOG_DLL_DECL
-void MakeCheckOpValueString(std::ostream* os, const signed char& v);
-template <> GOOGLE_GLOG_DLL_DECL
-void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
-
-// Build the error message string. Specify no inlining for code size.
-template <typename T1, typename T2>
-std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
- __attribute__ ((noinline));
-
-namespace base {
-namespace internal {
-
-// If "s" is less than base_logging::INFO, returns base_logging::INFO.
-// If "s" is greater than base_logging::FATAL, returns
-// base_logging::ERROR. Otherwise, returns "s".
-LogSeverity NormalizeSeverity(LogSeverity s);
-
-} // namespace internal
-
-// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
-// statement. See MakeCheckOpString for sample usage. Other
-// approaches were considered: use of a template method (e.g.,
-// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
-// base::Print<T2>, &v2), however this approach has complications
-// related to volatile arguments and function-pointer arguments).
-class GOOGLE_GLOG_DLL_DECL CheckOpMessageBuilder {
- public:
- // Inserts "exprtext" and " (" to the stream.
- explicit CheckOpMessageBuilder(const char *exprtext);
- // Deletes "stream_".
- ~CheckOpMessageBuilder();
- // For inserting the first variable.
- std::ostream* ForVar1() { return stream_; }
- // For inserting the second variable (adds an intermediate " vs. ").
- std::ostream* ForVar2();
- // Get the result (inserts the closing ")").
- std::string* NewString();
-
- private:
- std::ostringstream *stream_;
-};
-
-} // namespace base
-
-template <typename T1, typename T2>
-std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
- base::CheckOpMessageBuilder comb(exprtext);
- MakeCheckOpValueString(comb.ForVar1(), v1);
- MakeCheckOpValueString(comb.ForVar2(), v2);
- return comb.NewString();
-}
-
-// Helper functions for CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-#define DEFINE_CHECK_OP_IMPL(name, op) \
- template <typename T1, typename T2> \
- inline std::string* name##Impl(const T1& v1, const T2& v2, \
- const char* exprtext) { \
- if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
- else return MakeCheckOpString(v1, v2, exprtext); \
- } \
- inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
- return name##Impl<int, int>(v1, v2, exprtext); \
- }
-
-// We use the full name Check_EQ, Check_NE, etc. in case the file including
-// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
-// This happens if, for example, those are used as token names in a
-// yacc grammar.
-DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)?
-DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead.
-DEFINE_CHECK_OP_IMPL(Check_LE, <=)
-DEFINE_CHECK_OP_IMPL(Check_LT, < )
-DEFINE_CHECK_OP_IMPL(Check_GE, >=)
-DEFINE_CHECK_OP_IMPL(Check_GT, > )
-#undef DEFINE_CHECK_OP_IMPL
-
-// Helper macro for binary operators.
-// Don't use this macro directly in your code, use CHECK_EQ et al below.
-
-#if defined(STATIC_ANALYSIS)
-// Only for static analysis tool to know that it is equivalent to assert
-#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
-#elif !defined(NDEBUG)
-// In debug mode, avoid constructing CheckOpStrings if possible,
-// to reduce the overhead of CHECK statments by 2x.
-// Real DCHECK-heavy tests have seen 1.5x speedups.
-
-// The meaning of "string" might be different between now and
-// when this macro gets invoked (e.g., if someone is experimenting
-// with other string implementations that get defined after this
-// file is included). Save the current meaning now and use it
-// in the macro.
-typedef std::string _Check_string;
-#define CHECK_OP_LOG(name, op, val1, val2, log) \
- while (google::_Check_string* _result = \
- google::Check##name##Impl( \
- google::GetReferenceableValue(val1), \
- google::GetReferenceableValue(val2), \
- #val1 " " #op " " #val2)) \
- log(__FILE__, __LINE__, \
- google::CheckOpString(_result)).stream()
-#else
-// In optimized mode, use CheckOpString to hint to compiler that
-// the while condition is unlikely.
-#define CHECK_OP_LOG(name, op, val1, val2, log) \
- while (google::CheckOpString _result = \
- google::Check##name##Impl( \
- google::GetReferenceableValue(val1), \
- google::GetReferenceableValue(val2), \
- #val1 " " #op " " #val2)) \
- log(__FILE__, __LINE__, _result).stream()
-#endif // STATIC_ANALYSIS, !NDEBUG
-
-#if GOOGLE_STRIP_LOG <= 3
-#define CHECK_OP(name, op, val1, val2) \
- CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
-#else
-#define CHECK_OP(name, op, val1, val2) \
- CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
-#endif // STRIP_LOG <= 3
-
-// Equality/Inequality checks - compare two values, and log a FATAL message
-// including the two values when the result is not as expected. The values
-// must have operator<<(ostream, ...) defined.
-//
-// You may append to the error message like so:
-// CHECK_NE(1, 2) << ": The world must be ending!";
-//
-// We are very careful to ensure that each argument is evaluated exactly
-// once, and that anything which is legal to pass as a function argument is
-// legal here. In particular, the arguments may be temporary expressions
-// which will end up being destroyed at the end of the apparent statement,
-// for example:
-// CHECK_EQ(string("abc")[1], 'b');
-//
-// WARNING: These don't compile correctly if one of the arguments is a pointer
-// and the other is NULL. To work around this, simply static_cast NULL to the
-// type of the desired pointer.
-
-#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
-#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
-#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
-#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
-#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
-#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
-
-// Check that the input is non NULL. This very useful in constructor
-// initializer lists.
-
-#define CHECK_NOTNULL(val) \
- google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
-
-// Helper functions for string comparisons.
-// To avoid bloat, the definitions are in logging.cc.
-#define DECLARE_CHECK_STROP_IMPL(func, expected) \
- GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \
- const char* s1, const char* s2, const char* names);
-DECLARE_CHECK_STROP_IMPL(strcmp, true)
-DECLARE_CHECK_STROP_IMPL(strcmp, false)
-DECLARE_CHECK_STROP_IMPL(strcasecmp, true)
-DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
-#undef DECLARE_CHECK_STROP_IMPL
-
-// Helper macro for string comparisons.
-// Don't use this macro directly in your code, use CHECK_STREQ et al below.
-#define CHECK_STROP(func, op, expected, s1, s2) \
- while (google::CheckOpString _result = \
- google::Check##func##expected##Impl((s1), (s2), \
- #s1 " " #op " " #s2)) \
- LOG(FATAL) << *_result.str_
-
-
-// String (char*) equality/inequality checks.
-// CASE versions are case-insensitive.
-//
-// Note that "s1" and "s2" may be temporary strings which are destroyed
-// by the compiler at the end of the current "full expression"
-// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
-
-#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
-#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
-#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)
-#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)
-
-#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
-#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
-
-#define CHECK_DOUBLE_EQ(val1, val2) \
- do { \
- CHECK_LE((val1), (val2)+0.000000000000001L); \
- CHECK_GE((val1), (val2)-0.000000000000001L); \
- } while (0)
-
-#define CHECK_NEAR(val1, val2, margin) \
- do { \
- CHECK_LE((val1), (val2)+(margin)); \
- CHECK_GE((val1), (val2)-(margin)); \
- } while (0)
-
-// perror()..googly style!
-//
-// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and
-// CHECK equivalents with the addition that they postpend a description
-// of the current state of errno to their output lines.
-
-#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()
-
-#define GOOGLE_PLOG(severity, counter) \
- google::ErrnoLogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, counter, \
- &google::LogMessage::SendToLog)
-
-#define PLOG_IF(severity, condition) \
- !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
-
-// A CHECK() macro that postpends errno if the condition is false. E.g.
-//
-// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }
-#define PCHECK(condition) \
- PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
- << "Check failed: " #condition " "
-
-// A CHECK() macro that lets you assert the success of a function that
-// returns -1 and sets errno in case of an error. E.g.
-//
-// CHECK_ERR(mkdir(path, 0700));
-//
-// or
-//
-// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename;
-#define CHECK_ERR(invocation) \
-PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \
- << #invocation
-
-// Use macro expansion to create, for each use of LOG_EVERY_N(), static
-// variables with the __LINE__ expansion as part of the variable name.
-#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
-#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line
-
-#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
-#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
-
-#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \
- static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
- ++LOG_OCCURRENCES; \
- if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
- if (LOG_OCCURRENCES_MOD_N == 1) \
- google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \
- static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
- ++LOG_OCCURRENCES; \
- if (condition && \
- ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \
- google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \
- static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
- ++LOG_OCCURRENCES; \
- if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
- if (LOG_OCCURRENCES_MOD_N == 1) \
- google::ErrnoLogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \
- static int LOG_OCCURRENCES = 0; \
- if (LOG_OCCURRENCES <= n) \
- ++LOG_OCCURRENCES; \
- if (LOG_OCCURRENCES <= n) \
- google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-namespace glog_internal_namespace_ {
-template <bool>
-struct CompileAssert {
-};
-struct CrashReason;
-} // namespace glog_internal_namespace_
-
-#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
- typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
-#define LOG_EVERY_N(severity, n) \
- GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \
- google::NUM_SEVERITIES, \
- INVALID_REQUESTED_LOG_SEVERITY); \
- SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
-
-#define SYSLOG_EVERY_N(severity, n) \
- SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog)
-
-#define PLOG_EVERY_N(severity, n) \
- SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
-
-#define LOG_FIRST_N(severity, n) \
- SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)
-
-#define LOG_IF_EVERY_N(severity, condition, n) \
- SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog)
-
-// We want the special COUNTER value available for LOG_EVERY_X()'ed messages
-enum PRIVATE_Counter {COUNTER};
-
-#ifdef GLOG_NO_ABBREVIATED_SEVERITIES
-// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
-// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
-// to keep using this syntax, we define this macro to do the same thing
-// as COMPACT_GOOGLE_LOG_ERROR.
-#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
-#define SYSLOG_0 SYSLOG_ERROR
-#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR
-// Needed for LOG_IS_ON(ERROR).
-const LogSeverity GLOG_0 = GLOG_ERROR;
-#else
-// Users may include windows.h after logging.h without
-// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.
-// For this case, we cannot detect if ERROR is defined before users
-// actually use ERROR. Let's make an undefined symbol to warn users.
-# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail
-# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG
-# define SYSLOG_0 GLOG_ERROR_MSG
-# define LOG_TO_STRING_0 GLOG_ERROR_MSG
-# define GLOG_0 GLOG_ERROR_MSG
-#endif
-
-// Plus some debug-logging macros that get compiled to nothing for production
-
-#ifndef NDEBUG
-
-#define DLOG(severity) LOG(severity)
-#define DVLOG(verboselevel) VLOG(verboselevel)
-#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
-#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
-#define DLOG_IF_EVERY_N(severity, condition, n) \
- LOG_IF_EVERY_N(severity, condition, n)
-#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
-
-// debug-only checking. not executed in NDEBUG mode.
-#define DCHECK(condition) CHECK(condition)
-#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
-#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
-#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
-#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
-#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
-#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
-#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
-#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
-#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
-#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
-#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
-
-#else // NDEBUG
-
-#define DLOG(severity) \
- true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DVLOG(verboselevel) \
- (true || !VLOG_IS_ON(verboselevel)) ?\
- (void) 0 : google::LogMessageVoidify() & LOG(INFO)
-
-#define DLOG_IF(severity, condition) \
- (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DLOG_EVERY_N(severity, n) \
- true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DLOG_IF_EVERY_N(severity, condition, n) \
- (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DLOG_ASSERT(condition) \
- true ? (void) 0 : LOG_ASSERT(condition)
-
-// MSVC warning C4127: conditional expression is constant
-#define DCHECK(condition) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK(condition)
-
-#define DCHECK_EQ(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)
-
-#define DCHECK_NE(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)
-
-#define DCHECK_LE(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)
-
-#define DCHECK_LT(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)
-
-#define DCHECK_GE(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)
-
-#define DCHECK_GT(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)
-
-// You may see warnings in release mode if you don't use the return
-// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.
-#define DCHECK_NOTNULL(val) (val)
-
-#define DCHECK_STREQ(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)
-
-#define DCHECK_STRCASEEQ(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)
-
-#define DCHECK_STRNE(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)
-
-#define DCHECK_STRCASENE(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
-
-#endif // NDEBUG
-
-// Log only in verbose mode.
-
-#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
-
-#define VLOG_IF(verboselevel, condition) \
- LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
-
-#define VLOG_EVERY_N(verboselevel, n) \
- LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)
-
-#define VLOG_IF_EVERY_N(verboselevel, condition, n) \
- LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
-
-namespace base_logging {
-
-// LogMessage::LogStream is a std::ostream backed by this streambuf.
-// This class ignores overflow and leaves two bytes at the end of the
-// buffer to allow for a '\n' and '\0'.
-class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf {
- public:
- // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
- LogStreamBuf(char *buf, int len) {
- setp(buf, buf + len - 2);
- }
- // This effectively ignores overflow.
- virtual int_type overflow(int_type ch) {
- return ch;
- }
-
- // Legacy public ostrstream method.
- size_t pcount() const { return pptr() - pbase(); }
- char* pbase() const { return std::streambuf::pbase(); }
-};
-
-} // namespace base_logging
-
-//
-// This class more or less represents a particular log message. You
-// create an instance of LogMessage and then stream stuff to it.
-// When you finish streaming to it, ~LogMessage is called and the
-// full message gets streamed to the appropriate destination.
-//
-// You shouldn't actually use LogMessage's constructor to log things,
-// though. You should use the LOG() macro (and variants thereof)
-// above.
-class GOOGLE_GLOG_DLL_DECL LogMessage {
-public:
- enum {
- // Passing kNoLogPrefix for the line number disables the
- // log-message prefix. Useful for using the LogMessage
- // infrastructure as a printing utility. See also the --log_prefix
- // flag for controlling the log-message prefix on an
- // application-wide basis.
- kNoLogPrefix = -1
- };
-
- // LogStream inherit from non-DLL-exported class (std::ostrstream)
- // and VC++ produces a warning for this situation.
- // However, MSDN says "C4275 can be ignored in Microsoft Visual C++
- // 2005 if you are deriving from a type in the Standard C++ Library"
- // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
- // Let's just ignore the warning.
-#ifdef _MSC_VER
-# pragma warning(disable: 4275)
-#endif
- class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
-#ifdef _MSC_VER
-# pragma warning(default: 4275)
-#endif
- public:
- LogStream(char *buf, int len, int ctr)
- : std::ostream(NULL),
- streambuf_(buf, len),
- ctr_(ctr),
- self_(this) {
- rdbuf(&streambuf_);
- }
-
- int ctr() const { return ctr_; }
- void set_ctr(int ctr) { ctr_ = ctr; }
- LogStream* self() const { return self_; }
-
- // Legacy std::streambuf methods.
- size_t pcount() const { return streambuf_.pcount(); }
- char* pbase() const { return streambuf_.pbase(); }
- char* str() const { return pbase(); }
-
- private:
- base_logging::LogStreamBuf streambuf_;
- int ctr_; // Counter hack (for the LOG_EVERY_X() macro)
- LogStream *self_; // Consistency check hack
- };
-
-public:
- // icc 8 requires this typedef to avoid an internal compiler error.
- typedef void (LogMessage::*SendMethod)();
-
- LogMessage(const char* file, int line, LogSeverity severity, int ctr,
- SendMethod send_method);
-
- // Two special constructors that generate reduced amounts of code at
- // LOG call sites for common cases.
-
- // Used for LOG(INFO): Implied are:
- // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.
- //
- // Using this constructor instead of the more complex constructor above
- // saves 19 bytes per call site.
- LogMessage(const char* file, int line);
-
- // Used for LOG(severity) where severity != INFO. Implied
- // are: ctr = 0, send_method = &LogMessage::SendToLog
- //
- // Using this constructor instead of the more complex constructor above
- // saves 17 bytes per call site.
- LogMessage(const char* file, int line, LogSeverity severity);
-
- // Constructor to log this message to a specified sink (if not NULL).
- // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if
- // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.
- LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,
- bool also_send_to_log);
-
- // Constructor where we also give a vector<string> pointer
- // for storing the messages (if the pointer is not NULL).
- // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.
- LogMessage(const char* file, int line, LogSeverity severity,
- std::vector<std::string>* outvec);
-
- // Constructor where we also give a string pointer for storing the
- // message (if the pointer is not NULL). Implied are: ctr = 0,
- // send_method = &LogMessage::WriteToStringAndLog.
- LogMessage(const char* file, int line, LogSeverity severity,
- std::string* message);
-
- // A special constructor used for check failures
- LogMessage(const char* file, int line, const CheckOpString& result);
-
- ~LogMessage();
-
- // Flush a buffered message to the sink set in the constructor. Always
- // called by the destructor, it may also be called from elsewhere if
- // needed. Only the first call is actioned; any later ones are ignored.
- void Flush();
-
- // An arbitrary limit on the length of a single log message. This
- // is so that streaming can be done more efficiently.
- static const size_t kMaxLogMessageLen;
-
- // Theses should not be called directly outside of logging.*,
- // only passed as SendMethod arguments to other LogMessage methods:
- void SendToLog(); // Actually dispatch to the logs
- void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
-
- // Call abort() or similar to perform LOG(FATAL) crash.
- static void Fail() __attribute__ ((noreturn));
-
- std::ostream& stream();
-
- int preserved_errno() const;
-
- // Must be called without the log_mutex held. (L < log_mutex)
- static int64 num_messages(int severity);
-
- struct LogMessageData;
-
-private:
- // Fully internal SendMethod cases:
- void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs
- void SendToSink(); // Send to sink if provided, do nothing otherwise.
-
- // Write to string if provided and dispatch to the logs.
- void WriteToStringAndLog();
-
- void SaveOrSendToLog(); // Save to stringvec if provided, else to logs
-
- void Init(const char* file, int line, LogSeverity severity,
- void (LogMessage::*send_method)());
-
- // Used to fill in crash information during LOG(FATAL) failures.
- void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
-
- // Counts of messages sent at each priority:
- static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex
-
- // We keep the data in a separate struct so that each instance of
- // LogMessage uses less stack space.
- LogMessageData* allocated_;
- LogMessageData* data_;
-
- friend class LogDestination;
-
- LogMessage(const LogMessage&);
- void operator=(const LogMessage&);
-};
-
-// This class happens to be thread-hostile because all instances share
-// a single data buffer, but since it can only be created just before
-// the process dies, we don't worry so much.
-class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
- public:
- LogMessageFatal(const char* file, int line);
- LogMessageFatal(const char* file, int line, const CheckOpString& result);
- ~LogMessageFatal() __attribute__ ((noreturn));
-};
-
-// A non-macro interface to the log facility; (useful
-// when the logging level is not a compile-time constant).
-inline void LogAtLevel(int const severity, std::string const &msg) {
- LogMessage(__FILE__, __LINE__, severity).stream() << msg;
-}
-
-// A macro alternative of LogAtLevel. New code may want to use this
-// version since there are two advantages: 1. this version outputs the
-// file name and the line number where this macro is put like other
-// LOG macros, 2. this macro can be used as C++ stream.
-#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
-
-// A small helper for CHECK_NOTNULL().
-template <typename T>
-T* CheckNotNull(const char *file, int line, const char *names, T* t) {
- if (t == NULL) {
- LogMessageFatal(file, line, new std::string(names));
- }
- return t;
-}
-
-// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
-// only works if ostream is a LogStream. If the ostream is not a
-// LogStream you'll get an assert saying as much at runtime.
-GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os,
- const PRIVATE_Counter&);
-
-
-// Derived class for PLOG*() above.
-class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage {
- public:
-
- ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr,
- void (LogMessage::*send_method)());
-
- // Postpends ": strerror(errno) [errno]".
- ~ErrnoLogMessage();
-
- private:
- ErrnoLogMessage(const ErrnoLogMessage&);
- void operator=(const ErrnoLogMessage&);
-};
-
-
-// This class is used to explicitly ignore values in the conditional
-// logging macros. This avoids compiler warnings like "value computed
-// is not used" and "statement has no effect".
-
-class GOOGLE_GLOG_DLL_DECL LogMessageVoidify {
- public:
- LogMessageVoidify() { }
- // This has to be an operator with a precedence lower than << but
- // higher than ?:
- void operator&(std::ostream&) { }
-};
-
-
-// Flushes all log files that contains messages that are at least of
-// the specified severity level. Thread-safe.
-GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity);
-
-// Flushes all log files that contains messages that are at least of
-// the specified severity level. Thread-hostile because it ignores
-// locking -- used for catastrophic failures.
-GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity);
-
-//
-// Set the destination to which a particular severity level of log
-// messages is sent. If base_filename is "", it means "don't log this
-// severity". Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity,
- const char* base_filename);
-
-//
-// Set the basename of the symlink to the latest log file at a given
-// severity. If symlink_basename is empty, do not make a symlink. If
-// you don't call this function, the symlink basename is the
-// invocation name of the program. Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity,
- const char* symlink_basename);
-
-//
-// Used to send logs to some other kind of destination
-// Users should subclass LogSink and override send to do whatever they want.
-// Implementations must be thread-safe because a shared instance will
-// be called from whichever thread ran the LOG(XXX) line.
-class GOOGLE_GLOG_DLL_DECL LogSink {
- public:
- virtual ~LogSink();
-
- // Sink's logging logic (message_len is such as to exclude '\n' at the end).
- // This method can't use LOG() or CHECK() as logging system mutex(s) are held
- // during this call.
- virtual void send(LogSeverity severity, const char* full_filename,
- const char* base_filename, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len) = 0;
-
- // Redefine this to implement waiting for
- // the sink's logging logic to complete.
- // It will be called after each send() returns,
- // but before that LogMessage exits or crashes.
- // By default this function does nothing.
- // Using this function one can implement complex logic for send()
- // that itself involves logging; and do all this w/o causing deadlocks and
- // inconsistent rearrangement of log messages.
- // E.g. if a LogSink has thread-specific actions, the send() method
- // can simply add the message to a queue and wake up another thread that
- // handles real logging while itself making some LOG() calls;
- // WaitTillSent() can be implemented to wait for that logic to complete.
- // See our unittest for an example.
- virtual void WaitTillSent();
-
- // Returns the normal text output of the log message.
- // Can be useful to implement send().
- static std::string ToString(LogSeverity severity, const char* file, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len);
-};
-
-// Add or remove a LogSink as a consumer of logging data. Thread-safe.
-GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination);
-GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);
-
-//
-// Specify an "extension" added to the filename specified via
-// SetLogDestination. This applies to all severity levels. It's
-// often used to append the port we're listening on to the logfile
-// name. Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(
- const char* filename_extension);
-
-//
-// Make it so that all log messages of at least a particular severity
-// are logged to stderr (in addition to logging to the usual log
-// file(s)). Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);
-
-//
-// Make it so that all log messages go only to stderr. Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void LogToStderr();
-
-//
-// Make it so that all log messages of at least a particular severity are
-// logged via email to a list of addresses (in addition to logging to the
-// usual log file(s)). The list of addresses is just a string containing
-// the email addresses to send to (separated by spaces, say). Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,
- const char* addresses);
-
-// A simple function that sends email. dest is a commma-separated
-// list of addressess. Thread-safe.
-GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,
- const char *subject, const char *body);
-
-GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();
-
-// For tests only: Clear the internal [cached] list of logging directories to
-// force a refresh the next time GetLoggingDirectories is called.
-// Thread-hostile.
-void TestOnly_ClearLoggingDirectoriesList();
-
-// Returns a set of existing temporary directories, which will be a
-// subset of the directories returned by GetLogginDirectories().
-// Thread-safe.
-GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(
- std::vector<std::string>* list);
-
-// Print any fatal message again -- useful to call from signal handler
-// so that the last thing in the output is the fatal message.
-// Thread-hostile, but a race is unlikely.
-GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();
-
-// Truncate a log file that may be the append-only output of multiple
-// processes and hence can't simply be renamed/reopened (typically a
-// stdout/stderr). If the file "path" is > "limit" bytes, copy the
-// last "keep" bytes to offset 0 and truncate the rest. Since we could
-// be racing with other writers, this approach has the potential to
-// lose very small amounts of data. For security, only follow symlinks
-// if the path is /proc/self/fd/*
-GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,
- int64 limit, int64 keep);
-
-// Truncate stdout and stderr if they are over the value specified by
-// --max_log_size; keep the final 1MB. This function has the same
-// race condition as TruncateLogFile.
-GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();
-
-// Return the string representation of the provided LogSeverity level.
-// Thread-safe.
-GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
-
-// ---------------------------------------------------------------------
-// Implementation details that are not useful to most clients
-// ---------------------------------------------------------------------
-
-// A Logger is the interface used by logging modules to emit entries
-// to a log. A typical implementation will dump formatted data to a
-// sequence of files. We also provide interfaces that will forward
-// the data to another thread so that the invoker never blocks.
-// Implementations should be thread-safe since the logging system
-// will write to them from multiple threads.
-
-namespace base {
-
-class GOOGLE_GLOG_DLL_DECL Logger {
- public:
- virtual ~Logger();
-
- // Writes "message[0,message_len-1]" corresponding to an event that
- // occurred at "timestamp". If "force_flush" is true, the log file
- // is flushed immediately.
- //
- // The input message has already been formatted as deemed
- // appropriate by the higher level logging facility. For example,
- // textual log messages already contain timestamps, and the
- // file:linenumber header.
- virtual void Write(bool force_flush,
- time_t timestamp,
- const char* message,
- int message_len) = 0;
-
- // Flush any buffered messages
- virtual void Flush() = 0;
-
- // Get the current LOG file size.
- // The returned value is approximate since some
- // logged data may not have been flushed to disk yet.
- virtual uint32 LogSize() = 0;
-};
-
-// Get the logger for the specified severity level. The logger
-// remains the property of the logging module and should not be
-// deleted by the caller. Thread-safe.
-extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level);
-
-// Set the logger for the specified severity level. The logger
-// becomes the property of the logging module and should not
-// be deleted by the caller. Thread-safe.
-extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger);
-
-}
-
-// glibc has traditionally implemented two incompatible versions of
-// strerror_r(). There is a poorly defined convention for picking the
-// version that we want, but it is not clear whether it even works with
-// all versions of glibc.
-// So, instead, we provide this wrapper that automatically detects the
-// version that is in use, and then implements POSIX semantics.
-// N.B. In addition to what POSIX says, we also guarantee that "buf" will
-// be set to an empty string, if this function failed. This means, in most
-// cases, you do not need to check the error code and you can directly
-// use the value of "buf". It will never have an undefined value.
-// DEPRECATED: Use StrError(int) instead.
-GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len);
-
-// A thread-safe replacement for strerror(). Returns a string describing the
-// given POSIX error code.
-GOOGLE_GLOG_DLL_DECL std::string StrError(int err);
-
-// A class for which we define operator<<, which does nothing.
-class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream {
- public:
- // Initialize the LogStream so the messages can be written somewhere
- // (they'll never be actually displayed). This will be needed if a
- // NullStream& is implicitly converted to LogStream&, in which case
- // the overloaded NullStream::operator<< will not be invoked.
- NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { }
- NullStream(const char* /*file*/, int /*line*/,
- const CheckOpString& /*result*/) :
- LogMessage::LogStream(message_buffer_, 1, 0) { }
- NullStream &stream() { return *this; }
- private:
- // A very short buffer for messages (which we discard anyway). This
- // will be needed if NullStream& converted to LogStream& (e.g. as a
- // result of a conditional expression).
- char message_buffer_[2];
-};
-
-// Do nothing. This operator is inline, allowing the message to be
-// compiled away. The message will not be compiled away if we do
-// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when
-// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly
-// converted to LogStream and the message will be computed and then
-// quietly discarded.
-template<class T>
-inline NullStream& operator<<(NullStream &str, const T &) { return str; }
-
-// Similar to NullStream, but aborts the program (without stack
-// trace), like LogMessageFatal.
-class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
- public:
- NullStreamFatal() { }
- NullStreamFatal(const char* file, int line, const CheckOpString& result) :
- NullStream(file, line, result) { }
- __attribute__ ((noreturn)) ~NullStreamFatal() { _exit(1); }
-};
-
-// Install a signal handler that will dump signal information and a stack
-// trace when the program crashes on certain signals. We'll install the
-// signal handler for the following signals.
-//
-// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.
-//
-// By default, the signal handler will write the failure dump to the
-// standard error. You can customize the destination by installing your
-// own writer function by InstallFailureWriter() below.
-//
-// Note on threading:
-//
-// The function should be called before threads are created, if you want
-// to use the failure signal handler for all threads. The stack trace
-// will be shown only for the thread that receives the signal. In other
-// words, stack traces of other threads won't be shown.
-GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler();
-
-// Installs a function that is used for writing the failure dump. "data"
-// is the pointer to the beginning of a message to be written, and "size"
-// is the size of the message. You should not expect the data is
-// terminated with '\0'.
-GOOGLE_GLOG_DLL_DECL void InstallFailureWriter(
- void (*writer)(const char* data, int size));
-
-}
-
-#endif // _LOGGING_H_
-
-#endif // WIN32
diff --git a/extern/libmv/third_party/glog/src/glog/raw_logging.h b/extern/libmv/third_party/glog/src/glog/raw_logging.h
deleted file mode 100644
index b030f7f736d..00000000000
--- a/extern/libmv/third_party/glog/src/glog/raw_logging.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Maxim Lifantsev
-//
-// Thread-safe logging routines that do not allocate any memory or
-// acquire any locks, and can therefore be used by low-level memory
-// allocation and synchronization code.
-
-#ifdef WIN32
-# include "windows/glog/raw_logging.h"
-#else // WIN32
-
-#ifndef BASE_RAW_LOGGING_H_
-#define BASE_RAW_LOGGING_H_
-
-#include <time.h>
-
-namespace google {
-
-#include "glog/log_severity.h"
-#include "glog/vlog_is_on.h"
-
-// Annoying stuff for windows -- makes sure clients can import these functions
-#ifndef GOOGLE_GLOG_DLL_DECL
-# if defined(_WIN32) && !defined(__CYGWIN__)
-# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
-# else
-# define GOOGLE_GLOG_DLL_DECL
-# endif
-#endif
-
-// This is similar to LOG(severity) << format... and VLOG(level) << format..,
-// but
-// * it is to be used ONLY by low-level modules that can't use normal LOG()
-// * it is desiged to be a low-level logger that does not allocate any
-// memory and does not need any locks, hence:
-// * it logs straight and ONLY to STDERR w/o buffering
-// * it uses an explicit format and arguments list
-// * it will silently chop off really long message strings
-// Usage example:
-// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
-// RAW_VLOG(3, "status is %i", status);
-// These will print an almost standard log lines like this to stderr only:
-// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
-// I0821 211317 file.cc:142] RAW: status is 20
-#define RAW_LOG(severity, ...) \
- do { \
- switch (google::GLOG_ ## severity) { \
- case 0: \
- RAW_LOG_INFO(__VA_ARGS__); \
- break; \
- case 1: \
- RAW_LOG_WARNING(__VA_ARGS__); \
- break; \
- case 2: \
- RAW_LOG_ERROR(__VA_ARGS__); \
- break; \
- case 3: \
- RAW_LOG_FATAL(__VA_ARGS__); \
- break; \
- default: \
- break; \
- } \
- } while (0)
-
-// The following STRIP_LOG testing is performed in the header file so that it's
-// possible to completely compile out the logging code and the log messages.
-#if STRIP_LOG == 0
-#define RAW_VLOG(verboselevel, ...) \
- do { \
- if (VLOG_IS_ON(verboselevel)) { \
- RAW_LOG_INFO(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
-#endif // STRIP_LOG == 0
-
-#if STRIP_LOG == 0
-#define RAW_LOG_INFO(...) google::RawLog__(google::GLOG_INFO, \
- __FILE__, __LINE__, __VA_ARGS__)
-#else
-#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
-#endif // STRIP_LOG == 0
-
-#if STRIP_LOG <= 1
-#define RAW_LOG_WARNING(...) google::RawLog__(google::GLOG_WARNING, \
- __FILE__, __LINE__, __VA_ARGS__)
-#else
-#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
-#endif // STRIP_LOG <= 1
-
-#if STRIP_LOG <= 2
-#define RAW_LOG_ERROR(...) google::RawLog__(google::GLOG_ERROR, \
- __FILE__, __LINE__, __VA_ARGS__)
-#else
-#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
-#endif // STRIP_LOG <= 2
-
-#if STRIP_LOG <= 3
-#define RAW_LOG_FATAL(...) google::RawLog__(google::GLOG_FATAL, \
- __FILE__, __LINE__, __VA_ARGS__)
-#else
-#define RAW_LOG_FATAL(...) \
- do { \
- google::RawLogStub__(0, __VA_ARGS__); \
- exit(1); \
- } while (0)
-#endif // STRIP_LOG <= 3
-
-// Similar to CHECK(condition) << message,
-// but for low-level modules: we use only RAW_LOG that does not allocate memory.
-// We do not want to provide args list here to encourage this usage:
-// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
-// so that the args are not computed when not needed.
-#define RAW_CHECK(condition, message) \
- do { \
- if (!(condition)) { \
- RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
- } \
- } while (0)
-
-// Debug versions of RAW_LOG and RAW_CHECK
-#ifndef NDEBUG
-
-#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
-#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
-
-#else // NDEBUG
-
-#define RAW_DLOG(severity, ...) \
- while (false) \
- RAW_LOG(severity, __VA_ARGS__)
-#define RAW_DCHECK(condition, message) \
- while (false) \
- RAW_CHECK(condition, message)
-
-#endif // NDEBUG
-
-// Stub log function used to work around for unused variable warnings when
-// building with STRIP_LOG > 0.
-static inline void RawLogStub__(int /* ignored */, ...) {
-}
-
-// Helper function to implement RAW_LOG and RAW_VLOG
-// Logs format... at "severity" level, reporting it
-// as called from file:line.
-// This does not allocate memory or acquire locks.
-GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
- const char* file,
- int line,
- const char* format, ...)
- __attribute__((__format__ (__printf__, 4, 5)));
-
-// Hack to propagate time information into this module so that
-// this module does not have to directly call localtime_r(),
-// which could allocate memory.
-GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs);
-
-}
-
-#endif // BASE_RAW_LOGGING_H_
-
-#endif // WIN32
diff --git a/extern/libmv/third_party/glog/src/logging.cc b/extern/libmv/third_party/glog/src/logging.cc
deleted file mode 100644
index 75047353535..00000000000
--- a/extern/libmv/third_party/glog/src/logging.cc
+++ /dev/null
@@ -1,2083 +0,0 @@
-// Copyright (c) 1999, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#define _GNU_SOURCE 1 // needed for O_NOFOLLOW and pread()/pwrite()
-
-#include "utilities.h"
-
-#include <algorithm>
-#include <assert.h>
-#include <iomanip>
-#include <string>
-#include <algorithm>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h> // For _exit.
-#endif
-#include <climits>
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_SYS_UTSNAME_H
-# include <sys/utsname.h> // For uname.
-#endif
-#include <fcntl.h>
-#include <cstdio>
-#include <iostream>
-#include <stdarg.h>
-#include <stdlib.h>
-#ifdef HAVE_PWD_H
-# include <pwd.h>
-#endif
-#ifdef HAVE_SYSLOG_H
-# include <syslog.h>
-#endif
-#include <vector>
-#include <errno.h> // for errno
-#include <sstream>
-#include "base/commandlineflags.h" // to get the program name
-#include "glog/logging.h"
-#include "glog/raw_logging.h"
-#include "base/googleinit.h"
-
-#ifdef HAVE_STACKTRACE
-# include "stacktrace.h"
-#endif
-
-using std::string;
-using std::vector;
-using std::setw;
-using std::setfill;
-using std::hex;
-using std::dec;
-using std::min;
-using std::ostream;
-using std::ostringstream;
-
-using std::FILE;
-using std::fwrite;
-using std::fclose;
-using std::fflush;
-using std::fprintf;
-using std::perror;
-
-#ifdef __QNX__
-using std::fdopen;
-#endif
-
-// There is no thread annotation support.
-#define EXCLUSIVE_LOCKS_REQUIRED(mu)
-
-static bool BoolFromEnv(const char *varname, bool defval) {
- const char* const valstr = getenv(varname);
- if (!valstr) {
- return defval;
- }
- return memchr("tTyY1\0", valstr[0], 6) != NULL;
-}
-
-GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
- "log messages go to stderr instead of logfiles");
-GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
- "log messages go to stderr in addition to logfiles");
-GLOG_DEFINE_bool(colorlogtostderr, false,
- "color messages logged to stderr (if supported by terminal)");
-#ifdef OS_LINUX
-GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
- "Logs can grow very quickly and they are rarely read before they "
- "need to be evicted from memory. Instead, drop them from memory "
- "as soon as they are flushed to disk.");
-_START_GOOGLE_NAMESPACE_
-namespace logging {
-static const int64 kPageSize = getpagesize();
-}
-_END_GOOGLE_NAMESPACE_
-#endif
-
-// By default, errors (including fatal errors) get logged to stderr as
-// well as the file.
-//
-// The default is ERROR instead of FATAL so that users can see problems
-// when they run a program without having to look in another file.
-DEFINE_int32(stderrthreshold,
- GOOGLE_NAMESPACE::GLOG_ERROR,
- "log messages at or above this level are copied to stderr in "
- "addition to logfiles. This flag obsoletes --alsologtostderr.");
-
-GLOG_DEFINE_string(alsologtoemail, "",
- "log messages go to these email addresses "
- "in addition to logfiles");
-GLOG_DEFINE_bool(log_prefix, true,
- "Prepend the log prefix to the start of each log line");
-GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
- "actually get logged anywhere");
-GLOG_DEFINE_int32(logbuflevel, 0,
- "Buffer log messages logged at this level or lower"
- " (-1 means don't buffer; 0 means buffer INFO only;"
- " ...)");
-GLOG_DEFINE_int32(logbufsecs, 30,
- "Buffer log messages for at most this many seconds");
-GLOG_DEFINE_int32(logemaillevel, 999,
- "Email log messages logged at this level or higher"
- " (0 means email all; 3 means email FATAL only;"
- " ...)");
-GLOG_DEFINE_string(logmailer, "/bin/mail",
- "Mailer used to send logging email");
-
-// Compute the default value for --log_dir
-static const char* DefaultLogDir() {
- const char* env;
- env = getenv("GOOGLE_LOG_DIR");
- if (env != NULL && env[0] != '\0') {
- return env;
- }
- env = getenv("TEST_TMPDIR");
- if (env != NULL && env[0] != '\0') {
- return env;
- }
- return "";
-}
-
-GLOG_DEFINE_string(log_dir, DefaultLogDir(),
- "If specified, logfiles are written into this directory instead "
- "of the default logging directory.");
-GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
- "files in this directory");
-
-GLOG_DEFINE_int32(max_log_size, 1800,
- "approx. maximum log file size (in MB). A value of 0 will "
- "be silently overridden to 1.");
-
-GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
- "Stop attempting to log to disk if the disk is full.");
-
-GLOG_DEFINE_string(log_backtrace_at, "",
- "Emit a backtrace when logging at file:linenum.");
-
-// TODO(hamaji): consider windows
-#define PATH_SEPARATOR '/'
-
-#ifndef HAVE_PREAD
-#if defined(OS_WINDOWS)
-#include <BaseTsd.h>
-#define ssize_t SSIZE_T
-#endif
-static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
- off_t orig_offset = lseek(fd, 0, SEEK_CUR);
- if (orig_offset == (off_t)-1)
- return -1;
- if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
- return -1;
- ssize_t len = read(fd, buf, count);
- if (len < 0)
- return len;
- if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
- return -1;
- return len;
-}
-#endif // !HAVE_PREAD
-
-#ifndef HAVE_PWRITE
-static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
- off_t orig_offset = lseek(fd, 0, SEEK_CUR);
- if (orig_offset == (off_t)-1)
- return -1;
- if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
- return -1;
- ssize_t len = write(fd, buf, count);
- if (len < 0)
- return len;
- if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
- return -1;
- return len;
-}
-#endif // !HAVE_PWRITE
-
-static void GetHostName(string* hostname) {
-#if defined(HAVE_SYS_UTSNAME_H)
- struct utsname buf;
- if (0 != uname(&buf)) {
- // ensure null termination on failure
- *buf.nodename = '\0';
- }
- *hostname = buf.nodename;
-#elif defined(OS_WINDOWS)
- char buf[MAX_COMPUTERNAME_LENGTH + 1];
- DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
- if (GetComputerNameA(buf, &len)) {
- *hostname = buf;
- } else {
- hostname->clear();
- }
-#else
-# warning There is no way to retrieve the host name.
- *hostname = "(unknown)";
-#endif
-}
-
-// Returns true iff terminal supports using colors in output.
-static bool TerminalSupportsColor() {
- bool term_supports_color = false;
-#ifdef OS_WINDOWS
- // on Windows TERM variable is usually not set, but the console does
- // support colors.
- term_supports_color = true;
-#else
- // On non-Windows platforms, we rely on the TERM variable.
- const char* const term = getenv("TERM");
- if (term != NULL && term[0] != '\0') {
- term_supports_color =
- !strcmp(term, "xterm") ||
- !strcmp(term, "xterm-color") ||
- !strcmp(term, "xterm-256color") ||
- !strcmp(term, "screen") ||
- !strcmp(term, "linux") ||
- !strcmp(term, "cygwin");
- }
-#endif
- return term_supports_color;
-}
-
-_START_GOOGLE_NAMESPACE_
-
-enum GLogColor {
- COLOR_DEFAULT,
- COLOR_RED,
- COLOR_GREEN,
- COLOR_YELLOW
-};
-
-static GLogColor SeverityToColor(LogSeverity severity) {
- assert(severity >= 0 && severity < NUM_SEVERITIES);
- GLogColor color = COLOR_DEFAULT;
- switch (severity) {
- case GLOG_INFO:
- color = COLOR_DEFAULT;
- break;
- case GLOG_WARNING:
- color = COLOR_YELLOW;
- break;
- case GLOG_ERROR:
- case GLOG_FATAL:
- color = COLOR_RED;
- break;
- default:
- // should never get here.
- assert(false);
- }
- return color;
-}
-
-#ifdef OS_WINDOWS
-
-// Returns the character attribute for the given color.
-WORD GetColorAttribute(GLogColor color) {
- switch (color) {
- case COLOR_RED: return FOREGROUND_RED;
- case COLOR_GREEN: return FOREGROUND_GREEN;
- case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
- default: return 0;
- }
-}
-
-#else
-
-// Returns the ANSI color code for the given color.
-static const char* GetAnsiColorCode(GLogColor color) {
- switch (color) {
- case COLOR_RED: return "1";
- case COLOR_GREEN: return "2";
- case COLOR_YELLOW: return "3";
- case COLOR_DEFAULT: return "";
- };
- return NULL; // stop warning about return type.
-}
-
-#endif // OS_WINDOWS
-
-// Safely get max_log_size, overriding to 1 if it somehow gets defined as 0
-static int32 MaxLogSize() {
- return (FLAGS_max_log_size > 0 ? FLAGS_max_log_size : 1);
-}
-
-// An arbitrary limit on the length of a single log message. This
-// is so that streaming can be done more efficiently.
-const size_t LogMessage::kMaxLogMessageLen = 30000;
-
-struct LogMessage::LogMessageData {
- LogMessageData();
-
- int preserved_errno_; // preserved errno
- // Buffer space; contains complete message text.
- char message_text_[LogMessage::kMaxLogMessageLen+1];
- LogStream stream_;
- char severity_; // What level is this LogMessage logged at?
- int line_; // line number where logging call is.
- void (LogMessage::*send_method_)(); // Call this in destructor to send
- union { // At most one of these is used: union to keep the size low.
- LogSink* sink_; // NULL or sink to send message to
- std::vector<std::string>* outvec_; // NULL or vector to push message onto
- std::string* message_; // NULL or string to write message into
- };
- time_t timestamp_; // Time of creation of LogMessage
- struct ::tm tm_time_; // Time of creation of LogMessage
- size_t num_prefix_chars_; // # of chars of prefix in this message
- size_t num_chars_to_log_; // # of chars of msg to send to log
- size_t num_chars_to_syslog_; // # of chars of msg to send to syslog
- const char* basename_; // basename of file that called LOG
- const char* fullname_; // fullname of file that called LOG
- bool has_been_flushed_; // false => data has not been flushed
- bool first_fatal_; // true => this was first fatal msg
-
- private:
- LogMessageData(const LogMessageData&);
- void operator=(const LogMessageData&);
-};
-
-// A mutex that allows only one thread to log at a time, to keep things from
-// getting jumbled. Some other very uncommon logging operations (like
-// changing the destination file for log messages of a given severity) also
-// lock this mutex. Please be sure that anybody who might possibly need to
-// lock it does so.
-static Mutex log_mutex;
-
-// Number of messages sent at each severity. Under log_mutex.
-int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
-
-// Globally disable log writing (if disk is full)
-static bool stop_writing = false;
-
-const char*const LogSeverityNames[NUM_SEVERITIES] = {
- "INFO", "WARNING", "ERROR", "FATAL"
-};
-
-// Has the user called SetExitOnDFatal(true)?
-static bool exit_on_dfatal = true;
-
-const char* GetLogSeverityName(LogSeverity severity) {
- return LogSeverityNames[severity];
-}
-
-static bool SendEmailInternal(const char*dest, const char *subject,
- const char*body, bool use_logging);
-
-base::Logger::~Logger() {
-}
-
-namespace {
-
-// Encapsulates all file-system related state
-class LogFileObject : public base::Logger {
- public:
- LogFileObject(LogSeverity severity, const char* base_filename);
- ~LogFileObject();
-
- virtual void Write(bool force_flush, // Should we force a flush here?
- time_t timestamp, // Timestamp for this entry
- const char* message,
- int message_len);
-
- // Configuration options
- void SetBasename(const char* basename);
- void SetExtension(const char* ext);
- void SetSymlinkBasename(const char* symlink_basename);
-
- // Normal flushing routine
- virtual void Flush();
-
- // It is the actual file length for the system loggers,
- // i.e., INFO, ERROR, etc.
- virtual uint32 LogSize() {
- MutexLock l(&lock_);
- return file_length_;
- }
-
- // Internal flush routine. Exposed so that FlushLogFilesUnsafe()
- // can avoid grabbing a lock. Usually Flush() calls it after
- // acquiring lock_.
- void FlushUnlocked();
-
- private:
- static const uint32 kRolloverAttemptFrequency = 0x20;
-
- Mutex lock_;
- bool base_filename_selected_;
- string base_filename_;
- string symlink_basename_;
- string filename_extension_; // option users can specify (eg to add port#)
- FILE* file_;
- LogSeverity severity_;
- uint32 bytes_since_flush_;
- uint32 file_length_;
- unsigned int rollover_attempt_;
- int64 next_flush_time_; // cycle count at which to flush log
-
- // Actually create a logfile using the value of base_filename_ and the
- // supplied argument time_pid_string
- // REQUIRES: lock_ is held
- bool CreateLogfile(const string& time_pid_string);
-};
-
-} // namespace
-
-class LogDestination {
- public:
- friend class LogMessage;
- friend void ReprintFatalMessage();
- friend base::Logger* base::GetLogger(LogSeverity);
- friend void base::SetLogger(LogSeverity, base::Logger*);
-
- // These methods are just forwarded to by their global versions.
- static void SetLogDestination(LogSeverity severity,
- const char* base_filename);
- static void SetLogSymlink(LogSeverity severity,
- const char* symlink_basename);
- static void AddLogSink(LogSink *destination);
- static void RemoveLogSink(LogSink *destination);
- static void SetLogFilenameExtension(const char* filename_extension);
- static void SetStderrLogging(LogSeverity min_severity);
- static void SetEmailLogging(LogSeverity min_severity, const char* addresses);
- static void LogToStderr();
- // Flush all log files that are at least at the given severity level
- static void FlushLogFiles(int min_severity);
- static void FlushLogFilesUnsafe(int min_severity);
-
- // we set the maximum size of our packet to be 1400, the logic being
- // to prevent fragmentation.
- // Really this number is arbitrary.
- static const int kNetworkBytes = 1400;
-
- static const string& hostname();
- static const bool& terminal_supports_color() {
- return terminal_supports_color_;
- }
-
- static void DeleteLogDestinations();
-
- private:
- LogDestination(LogSeverity severity, const char* base_filename);
- ~LogDestination() { }
-
- // Take a log message of a particular severity and log it to stderr
- // iff it's of a high enough severity to deserve it.
- static void MaybeLogToStderr(LogSeverity severity, const char* message,
- size_t len);
-
- // Take a log message of a particular severity and log it to email
- // iff it's of a high enough severity to deserve it.
- static void MaybeLogToEmail(LogSeverity severity, const char* message,
- size_t len);
- // Take a log message of a particular severity and log it to a file
- // iff the base filename is not "" (which means "don't log to me")
- static void MaybeLogToLogfile(LogSeverity severity,
- time_t timestamp,
- const char* message, size_t len);
- // Take a log message of a particular severity and log it to the file
- // for that severity and also for all files with severity less than
- // this severity.
- static void LogToAllLogfiles(LogSeverity severity,
- time_t timestamp,
- const char* message, size_t len);
-
- // Send logging info to all registered sinks.
- static void LogToSinks(LogSeverity severity,
- const char *full_filename,
- const char *base_filename,
- int line,
- const struct ::tm* tm_time,
- const char* message,
- size_t message_len);
-
- // Wait for all registered sinks via WaitTillSent
- // including the optional one in "data".
- static void WaitForSinks(LogMessage::LogMessageData* data);
-
- static LogDestination* log_destination(LogSeverity severity);
-
- LogFileObject fileobject_;
- base::Logger* logger_; // Either &fileobject_, or wrapper around it
-
- static LogDestination* log_destinations_[NUM_SEVERITIES];
- static LogSeverity email_logging_severity_;
- static string addresses_;
- static string hostname_;
- static bool terminal_supports_color_;
-
- // arbitrary global logging destinations.
- static vector<LogSink*>* sinks_;
-
- // Protects the vector sinks_,
- // but not the LogSink objects its elements reference.
- static Mutex sink_mutex_;
-
- // Disallow
- LogDestination(const LogDestination&);
- LogDestination& operator=(const LogDestination&);
-};
-
-// Errors do not get logged to email by default.
-LogSeverity LogDestination::email_logging_severity_ = 99999;
-
-string LogDestination::addresses_;
-string LogDestination::hostname_;
-
-vector<LogSink*>* LogDestination::sinks_ = NULL;
-Mutex LogDestination::sink_mutex_;
-bool LogDestination::terminal_supports_color_ = TerminalSupportsColor();
-
-/* static */
-const string& LogDestination::hostname() {
- if (hostname_.empty()) {
- GetHostName(&hostname_);
- if (hostname_.empty()) {
- hostname_ = "(unknown)";
- }
- }
- return hostname_;
-}
-
-LogDestination::LogDestination(LogSeverity severity,
- const char* base_filename)
- : fileobject_(severity, base_filename),
- logger_(&fileobject_) {
-}
-
-inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
- // assume we have the log_mutex or we simply don't care
- // about it
- for (int i = min_severity; i < NUM_SEVERITIES; i++) {
- LogDestination* log = log_destination(i);
- if (log != NULL) {
- // Flush the base fileobject_ logger directly instead of going
- // through any wrappers to reduce chance of deadlock.
- log->fileobject_.FlushUnlocked();
- }
- }
-}
-
-inline void LogDestination::FlushLogFiles(int min_severity) {
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&log_mutex);
- for (int i = min_severity; i < NUM_SEVERITIES; i++) {
- LogDestination* log = log_destination(i);
- if (log != NULL) {
- log->logger_->Flush();
- }
- }
-}
-
-inline void LogDestination::SetLogDestination(LogSeverity severity,
- const char* base_filename) {
- assert(severity >= 0 && severity < NUM_SEVERITIES);
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&log_mutex);
- log_destination(severity)->fileobject_.SetBasename(base_filename);
-}
-
-inline void LogDestination::SetLogSymlink(LogSeverity severity,
- const char* symlink_basename) {
- CHECK_GE(severity, 0);
- CHECK_LT(severity, NUM_SEVERITIES);
- MutexLock l(&log_mutex);
- log_destination(severity)->fileobject_.SetSymlinkBasename(symlink_basename);
-}
-
-inline void LogDestination::AddLogSink(LogSink *destination) {
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&sink_mutex_);
- if (!sinks_) sinks_ = new vector<LogSink*>;
- sinks_->push_back(destination);
-}
-
-inline void LogDestination::RemoveLogSink(LogSink *destination) {
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&sink_mutex_);
- // This doesn't keep the sinks in order, but who cares?
- if (sinks_) {
- for (int i = sinks_->size() - 1; i >= 0; i--) {
- if ((*sinks_)[i] == destination) {
- (*sinks_)[i] = (*sinks_)[sinks_->size() - 1];
- sinks_->pop_back();
- break;
- }
- }
- }
-}
-
-inline void LogDestination::SetLogFilenameExtension(const char* ext) {
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&log_mutex);
- for ( int severity = 0; severity < NUM_SEVERITIES; ++severity ) {
- log_destination(severity)->fileobject_.SetExtension(ext);
- }
-}
-
-inline void LogDestination::SetStderrLogging(LogSeverity min_severity) {
- assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&log_mutex);
- FLAGS_stderrthreshold = min_severity;
-}
-
-inline void LogDestination::LogToStderr() {
- // *Don't* put this stuff in a mutex lock, since SetStderrLogging &
- // SetLogDestination already do the locking!
- SetStderrLogging(0); // thus everything is "also" logged to stderr
- for ( int i = 0; i < NUM_SEVERITIES; ++i ) {
- SetLogDestination(i, ""); // "" turns off logging to a logfile
- }
-}
-
-inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
- const char* addresses) {
- assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // all this stuff.
- MutexLock l(&log_mutex);
- LogDestination::email_logging_severity_ = min_severity;
- LogDestination::addresses_ = addresses;
-}
-
-static void ColoredWriteToStderr(LogSeverity severity,
- const char* message, size_t len) {
- const GLogColor color =
- (LogDestination::terminal_supports_color() && FLAGS_colorlogtostderr) ?
- SeverityToColor(severity) : COLOR_DEFAULT;
-
- // Avoid using cerr from this module since we may get called during
- // exit code, and cerr may be partially or fully destroyed by then.
- if (COLOR_DEFAULT == color) {
- fwrite(message, len, 1, stderr);
- return;
- }
-#ifdef OS_WINDOWS
- const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
-
- // Gets the current text color.
- CONSOLE_SCREEN_BUFFER_INFO buffer_info;
- GetConsoleScreenBufferInfo(stderr_handle, &buffer_info);
- const WORD old_color_attrs = buffer_info.wAttributes;
-
- // We need to flush the stream buffers into the console before each
- // SetConsoleTextAttribute call lest it affect the text that is already
- // printed but has not yet reached the console.
- fflush(stderr);
- SetConsoleTextAttribute(stderr_handle,
- GetColorAttribute(color) | FOREGROUND_INTENSITY);
- fwrite(message, len, 1, stderr);
- fflush(stderr);
- // Restores the text color.
- SetConsoleTextAttribute(stderr_handle, old_color_attrs);
-#else
- fprintf(stderr, "\033[0;3%sm", GetAnsiColorCode(color));
- fwrite(message, len, 1, stderr);
- fprintf(stderr, "\033[m"); // Resets the terminal to default.
-#endif // OS_WINDOWS
-}
-
-static void WriteToStderr(const char* message, size_t len) {
- // Avoid using cerr from this module since we may get called during
- // exit code, and cerr may be partially or fully destroyed by then.
- fwrite(message, len, 1, stderr);
-}
-
-inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
- const char* message, size_t len) {
- if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
- ColoredWriteToStderr(severity, message, len);
-#ifdef OS_WINDOWS
- // On Windows, also output to the debugger
- ::OutputDebugStringA(string(message,len).c_str());
-#endif
- }
-}
-
-
-inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
- const char* message, size_t len) {
- if (severity >= email_logging_severity_ ||
- severity >= FLAGS_logemaillevel) {
- string to(FLAGS_alsologtoemail);
- if (!addresses_.empty()) {
- if (!to.empty()) {
- to += ",";
- }
- to += addresses_;
- }
- const string subject(string("[LOG] ") + LogSeverityNames[severity] + ": " +
- glog_internal_namespace_::ProgramInvocationShortName());
- string body(hostname());
- body += "\n\n";
- body.append(message, len);
-
- // should NOT use SendEmail(). The caller of this function holds the
- // log_mutex and SendEmail() calls LOG/VLOG which will block trying to
- // acquire the log_mutex object. Use SendEmailInternal() and set
- // use_logging to false.
- SendEmailInternal(to.c_str(), subject.c_str(), body.c_str(), false);
- }
-}
-
-
-inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
- time_t timestamp,
- const char* message,
- size_t len) {
- const bool should_flush = severity > FLAGS_logbuflevel;
- LogDestination* destination = log_destination(severity);
- destination->logger_->Write(should_flush, timestamp, message, len);
-}
-
-inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
- time_t timestamp,
- const char* message,
- size_t len) {
-
- if ( FLAGS_logtostderr ) { // global flag: never log to file
- ColoredWriteToStderr(severity, message, len);
- } else {
- for (int i = severity; i >= 0; --i)
- LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
- }
-}
-
-inline void LogDestination::LogToSinks(LogSeverity severity,
- const char *full_filename,
- const char *base_filename,
- int line,
- const struct ::tm* tm_time,
- const char* message,
- size_t message_len) {
- ReaderMutexLock l(&sink_mutex_);
- if (sinks_) {
- for (int i = sinks_->size() - 1; i >= 0; i--) {
- (*sinks_)[i]->send(severity, full_filename, base_filename,
- line, tm_time, message, message_len);
- }
- }
-}
-
-inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
- ReaderMutexLock l(&sink_mutex_);
- if (sinks_) {
- for (int i = sinks_->size() - 1; i >= 0; i--) {
- (*sinks_)[i]->WaitTillSent();
- }
- }
- const bool send_to_sink =
- (data->send_method_ == &LogMessage::SendToSink) ||
- (data->send_method_ == &LogMessage::SendToSinkAndLog);
- if (send_to_sink && data->sink_ != NULL) {
- data->sink_->WaitTillSent();
- }
-}
-
-LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
-
-inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
- assert(severity >=0 && severity < NUM_SEVERITIES);
- if (!log_destinations_[severity]) {
- log_destinations_[severity] = new LogDestination(severity, NULL);
- }
- return log_destinations_[severity];
-}
-
-void LogDestination::DeleteLogDestinations() {
- for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
- delete log_destinations_[severity];
- log_destinations_[severity] = NULL;
- }
-}
-
-namespace {
-
-LogFileObject::LogFileObject(LogSeverity severity,
- const char* base_filename)
- : base_filename_selected_(base_filename != NULL),
- base_filename_((base_filename != NULL) ? base_filename : ""),
- symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),
- filename_extension_(),
- file_(NULL),
- severity_(severity),
- bytes_since_flush_(0),
- file_length_(0),
- rollover_attempt_(kRolloverAttemptFrequency-1),
- next_flush_time_(0) {
- assert(severity >= 0);
- assert(severity < NUM_SEVERITIES);
-}
-
-LogFileObject::~LogFileObject() {
- MutexLock l(&lock_);
- if (file_ != NULL) {
- fclose(file_);
- file_ = NULL;
- }
-}
-
-void LogFileObject::SetBasename(const char* basename) {
- MutexLock l(&lock_);
- base_filename_selected_ = true;
- if (base_filename_ != basename) {
- // Get rid of old log file since we are changing names
- if (file_ != NULL) {
- fclose(file_);
- file_ = NULL;
- rollover_attempt_ = kRolloverAttemptFrequency-1;
- }
- base_filename_ = basename;
- }
-}
-
-void LogFileObject::SetExtension(const char* ext) {
- MutexLock l(&lock_);
- if (filename_extension_ != ext) {
- // Get rid of old log file since we are changing names
- if (file_ != NULL) {
- fclose(file_);
- file_ = NULL;
- rollover_attempt_ = kRolloverAttemptFrequency-1;
- }
- filename_extension_ = ext;
- }
-}
-
-void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
- MutexLock l(&lock_);
- symlink_basename_ = symlink_basename;
-}
-
-void LogFileObject::Flush() {
- MutexLock l(&lock_);
- FlushUnlocked();
-}
-
-void LogFileObject::FlushUnlocked(){
- if (file_ != NULL) {
- fflush(file_);
- bytes_since_flush_ = 0;
- }
- // Figure out when we are due for another flush.
- const int64 next = (FLAGS_logbufsecs
- * static_cast<int64>(1000000)); // in usec
- next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
-}
-
-bool LogFileObject::CreateLogfile(const string& time_pid_string) {
- string string_filename = base_filename_+filename_extension_+
- time_pid_string;
- const char* filename = string_filename.c_str();
- int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0664);
- if (fd == -1) return false;
-#ifdef HAVE_FCNTL
- // Mark the file close-on-exec. We don't really care if this fails
- fcntl(fd, F_SETFD, FD_CLOEXEC);
-#endif
-
- file_ = fdopen(fd, "a"); // Make a FILE*.
- if (file_ == NULL) { // Man, we're screwed!
- close(fd);
- unlink(filename); // Erase the half-baked evidence: an unusable log file
- return false;
- }
-
- // We try to create a symlink called <program_name>.<severity>,
- // which is easier to use. (Every time we create a new logfile,
- // we destroy the old symlink and create a new one, so it always
- // points to the latest logfile.) If it fails, we're sad but it's
- // no error.
- if (!symlink_basename_.empty()) {
- // take directory from filename
- const char* slash = strrchr(filename, PATH_SEPARATOR);
- const string linkname =
- symlink_basename_ + '.' + LogSeverityNames[severity_];
- string linkpath;
- if ( slash ) linkpath = string(filename, slash-filename+1); // get dirname
- linkpath += linkname;
- unlink(linkpath.c_str()); // delete old one if it exists
-
-#if defined(OS_WINDOWS)
- // TODO(hamaji): Create lnk file on Windows?
-#elif defined(HAVE_UNISTD_H)
- // We must have unistd.h.
- // Make the symlink be relative (in the same dir) so that if the
- // entire log directory gets relocated the link is still valid.
- const char *linkdest = slash ? (slash + 1) : filename;
- if (symlink(linkdest, linkpath.c_str()) != 0) {
- // silently ignore failures
- }
-
- // Make an additional link to the log file in a place specified by
- // FLAGS_log_link, if indicated
- if (!FLAGS_log_link.empty()) {
- linkpath = FLAGS_log_link + "/" + linkname;
- unlink(linkpath.c_str()); // delete old one if it exists
- if (symlink(filename, linkpath.c_str()) != 0) {
- // silently ignore failures
- }
- }
-#endif
- }
-
- return true; // Everything worked
-}
-
-void LogFileObject::Write(bool force_flush,
- time_t timestamp,
- const char* message,
- int message_len) {
- MutexLock l(&lock_);
-
- // We don't log if the base_name_ is "" (which means "don't write")
- if (base_filename_selected_ && base_filename_.empty()) {
- return;
- }
-
- if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
- PidHasChanged()) {
- if (file_ != NULL) fclose(file_);
- file_ = NULL;
- file_length_ = bytes_since_flush_ = 0;
- rollover_attempt_ = kRolloverAttemptFrequency-1;
- }
-
- // If there's no destination file, make one before outputting
- if (file_ == NULL) {
- // Try to rollover the log file every 32 log messages. The only time
- // this could matter would be when we have trouble creating the log
- // file. If that happens, we'll lose lots of log messages, of course!
- if (++rollover_attempt_ != kRolloverAttemptFrequency) return;
- rollover_attempt_ = 0;
-
- struct ::tm tm_time;
- localtime_r(&timestamp, &tm_time);
-
- // The logfile's filename will have the date/time & pid in it
- ostringstream time_pid_stream;
- time_pid_stream.fill('0');
- time_pid_stream << 1900+tm_time.tm_year
- << setw(2) << 1+tm_time.tm_mon
- << setw(2) << tm_time.tm_mday
- << '-'
- << setw(2) << tm_time.tm_hour
- << setw(2) << tm_time.tm_min
- << setw(2) << tm_time.tm_sec
- << '.'
- << GetMainThreadPid();
- const string& time_pid_string = time_pid_stream.str();
-
- if (base_filename_selected_) {
- if (!CreateLogfile(time_pid_string)) {
- perror("Could not create log file");
- fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
- time_pid_string.c_str());
- return;
- }
- } else {
- // If no base filename for logs of this severity has been set, use a
- // default base filename of
- // "<program name>.<hostname>.<user name>.log.<severity level>.". So
- // logfiles will have names like
- // webserver.examplehost.root.log.INFO.19990817-150000.4354, where
- // 19990817 is a date (1999 August 17), 150000 is a time (15:00:00),
- // and 4354 is the pid of the logging process. The date & time reflect
- // when the file was created for output.
- //
- // Where does the file get put? Successively try the directories
- // "/tmp", and "."
- string stripped_filename(
- glog_internal_namespace_::ProgramInvocationShortName());
- string hostname;
- GetHostName(&hostname);
-
- string uidname = MyUserName();
- // We should not call CHECK() here because this function can be
- // called after holding on to log_mutex. We don't want to
- // attempt to hold on to the same mutex, and get into a
- // deadlock. Simply use a name like invalid-user.
- if (uidname.empty()) uidname = "invalid-user";
-
- stripped_filename = stripped_filename+'.'+hostname+'.'
- +uidname+".log."
- +LogSeverityNames[severity_]+'.';
- // We're going to (potentially) try to put logs in several different dirs
- const vector<string> & log_dirs = GetLoggingDirectories();
-
- // Go through the list of dirs, and try to create the log file in each
- // until we succeed or run out of options
- bool success = false;
- for (vector<string>::const_iterator dir = log_dirs.begin();
- dir != log_dirs.end();
- ++dir) {
- base_filename_ = *dir + "/" + stripped_filename;
- if ( CreateLogfile(time_pid_string) ) {
- success = true;
- break;
- }
- }
- // If we never succeeded, we have to give up
- if ( success == false ) {
- perror("Could not create logging file");
- fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
- time_pid_string.c_str());
- return;
- }
- }
-
- // Write a header message into the log file
- ostringstream file_header_stream;
- file_header_stream.fill('0');
- file_header_stream << "Log file created at: "
- << 1900+tm_time.tm_year << '/'
- << setw(2) << 1+tm_time.tm_mon << '/'
- << setw(2) << tm_time.tm_mday
- << ' '
- << setw(2) << tm_time.tm_hour << ':'
- << setw(2) << tm_time.tm_min << ':'
- << setw(2) << tm_time.tm_sec << '\n'
- << "Running on machine: "
- << LogDestination::hostname() << '\n'
- << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
- << "threadid file:line] msg" << '\n';
- const string& file_header_string = file_header_stream.str();
-
- const int header_len = file_header_string.size();
- fwrite(file_header_string.data(), 1, header_len, file_);
- file_length_ += header_len;
- bytes_since_flush_ += header_len;
- }
-
- // Write to LOG file
- if ( !stop_writing ) {
- // fwrite() doesn't return an error when the disk is full, for
- // messages that are less than 4096 bytes. When the disk is full,
- // it returns the message length for messages that are less than
- // 4096 bytes. fwrite() returns 4096 for message lengths that are
- // greater than 4096, thereby indicating an error.
- errno = 0;
- fwrite(message, 1, message_len, file_);
- if ( FLAGS_stop_logging_if_full_disk &&
- errno == ENOSPC ) { // disk full, stop writing to disk
- stop_writing = true; // until the disk is
- return;
- } else {
- file_length_ += message_len;
- bytes_since_flush_ += message_len;
- }
- } else {
- if ( CycleClock_Now() >= next_flush_time_ )
- stop_writing = false; // check to see if disk has free space.
- return; // no need to flush
- }
-
- // See important msgs *now*. Also, flush logs at least every 10^6 chars,
- // or every "FLAGS_logbufsecs" seconds.
- if ( force_flush ||
- (bytes_since_flush_ >= 1000000) ||
- (CycleClock_Now() >= next_flush_time_) ) {
- FlushUnlocked();
-#ifdef OS_LINUX
- if (FLAGS_drop_log_memory) {
- if (file_length_ >= logging::kPageSize) {
- // don't evict the most recent page
- uint32 len = file_length_ & ~(logging::kPageSize - 1);
- posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED);
- }
- }
-#endif
- }
-}
-
-} // namespace
-
-
-// Static log data space to avoid alloc failures in a LOG(FATAL)
-//
-// Since multiple threads may call LOG(FATAL), and we want to preserve
-// the data from the first call, we allocate two sets of space. One
-// for exclusive use by the first thread, and one for shared use by
-// all other threads.
-static Mutex fatal_msg_lock;
-static CrashReason crash_reason;
-static bool fatal_msg_exclusive = true;
-static LogMessage::LogMessageData fatal_msg_data_exclusive;
-static LogMessage::LogMessageData fatal_msg_data_shared;
-
-LogMessage::LogMessageData::LogMessageData()
- : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
-}
-
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
- int ctr, void (LogMessage::*send_method)())
- : allocated_(NULL) {
- Init(file, line, severity, send_method);
- data_->stream_.set_ctr(ctr);
-}
-
-LogMessage::LogMessage(const char* file, int line,
- const CheckOpString& result)
- : allocated_(NULL) {
- Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);
- stream() << "Check failed: " << (*result.str_) << " ";
-}
-
-LogMessage::LogMessage(const char* file, int line)
- : allocated_(NULL) {
- Init(file, line, GLOG_INFO, &LogMessage::SendToLog);
-}
-
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
- : allocated_(NULL) {
- Init(file, line, severity, &LogMessage::SendToLog);
-}
-
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
- LogSink* sink, bool also_send_to_log)
- : allocated_(NULL) {
- Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog :
- &LogMessage::SendToSink);
- data_->sink_ = sink; // override Init()'s setting to NULL
-}
-
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
- vector<string> *outvec)
- : allocated_(NULL) {
- Init(file, line, severity, &LogMessage::SaveOrSendToLog);
- data_->outvec_ = outvec; // override Init()'s setting to NULL
-}
-
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
- string *message)
- : allocated_(NULL) {
- Init(file, line, severity, &LogMessage::WriteToStringAndLog);
- data_->message_ = message; // override Init()'s setting to NULL
-}
-
-void LogMessage::Init(const char* file,
- int line,
- LogSeverity severity,
- void (LogMessage::*send_method)()) {
- allocated_ = NULL;
- if (severity != GLOG_FATAL || !exit_on_dfatal) {
- allocated_ = new LogMessageData();
- data_ = allocated_;
- data_->first_fatal_ = false;
- } else {
- MutexLock l(&fatal_msg_lock);
- if (fatal_msg_exclusive) {
- fatal_msg_exclusive = false;
- data_ = &fatal_msg_data_exclusive;
- data_->first_fatal_ = true;
- } else {
- data_ = &fatal_msg_data_shared;
- data_->first_fatal_ = false;
- }
- }
-
- stream().fill('0');
- data_->preserved_errno_ = errno;
- data_->severity_ = severity;
- data_->line_ = line;
- data_->send_method_ = send_method;
- data_->sink_ = NULL;
- data_->outvec_ = NULL;
- WallTime now = WallTime_Now();
- data_->timestamp_ = static_cast<time_t>(now);
- localtime_r(&data_->timestamp_, &data_->tm_time_);
- int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
- RawLog__SetLastTime(data_->tm_time_, usecs);
-
- data_->num_chars_to_log_ = 0;
- data_->num_chars_to_syslog_ = 0;
- data_->basename_ = const_basename(file);
- data_->fullname_ = file;
- data_->has_been_flushed_ = false;
-
- // If specified, prepend a prefix to each line. For example:
- // I1018 160715 f5d4fbb0 logging.cc:1153]
- // (log level, GMT month, date, time, thread_id, file basename, line)
- // We exclude the thread_id for the default thread.
- if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
- stream() << LogSeverityNames[severity][0]
- << setw(2) << 1+data_->tm_time_.tm_mon
- << setw(2) << data_->tm_time_.tm_mday
- << ' '
- << setw(2) << data_->tm_time_.tm_hour << ':'
- << setw(2) << data_->tm_time_.tm_min << ':'
- << setw(2) << data_->tm_time_.tm_sec << "."
- << setw(6) << usecs
- << ' '
- << setfill(' ') << setw(5)
- << static_cast<unsigned int>(GetTID()) << setfill('0')
- << ' '
- << data_->basename_ << ':' << data_->line_ << "] ";
- }
- data_->num_prefix_chars_ = data_->stream_.pcount();
-
- if (!FLAGS_log_backtrace_at.empty()) {
- char fileline[128];
- snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
-#ifdef HAVE_STACKTRACE
- if (!strcmp(FLAGS_log_backtrace_at.c_str(), fileline)) {
- string stacktrace;
- DumpStackTraceToString(&stacktrace);
- stream() << " (stacktrace:\n" << stacktrace << ") ";
- }
-#endif
- }
-}
-
-LogMessage::~LogMessage() {
- Flush();
- delete allocated_;
-}
-
-int LogMessage::preserved_errno() const {
- return data_->preserved_errno_;
-}
-
-ostream& LogMessage::stream() {
- return data_->stream_;
-}
-
-// Flush buffered message, called by the destructor, or any other function
-// that needs to synchronize the log.
-void LogMessage::Flush() {
- if (data_->has_been_flushed_ || data_->severity_ < FLAGS_minloglevel)
- return;
-
- data_->num_chars_to_log_ = data_->stream_.pcount();
- data_->num_chars_to_syslog_ =
- data_->num_chars_to_log_ - data_->num_prefix_chars_;
-
- // Do we need to add a \n to the end of this message?
- bool append_newline =
- (data_->message_text_[data_->num_chars_to_log_-1] != '\n');
- char original_final_char = '\0';
-
- // If we do need to add a \n, we'll do it by violating the memory of the
- // ostrstream buffer. This is quick, and we'll make sure to undo our
- // modification before anything else is done with the ostrstream. It
- // would be preferable not to do things this way, but it seems to be
- // the best way to deal with this.
- if (append_newline) {
- original_final_char = data_->message_text_[data_->num_chars_to_log_];
- data_->message_text_[data_->num_chars_to_log_++] = '\n';
- }
-
- // Prevent any subtle race conditions by wrapping a mutex lock around
- // the actual logging action per se.
- {
- MutexLock l(&log_mutex);
- (this->*(data_->send_method_))();
- ++num_messages_[static_cast<int>(data_->severity_)];
- }
- LogDestination::WaitForSinks(data_);
-
- if (append_newline) {
- // Fix the ostrstream back how it was before we screwed with it.
- // It's 99.44% certain that we don't need to worry about doing this.
- data_->message_text_[data_->num_chars_to_log_-1] = original_final_char;
- }
-
- // If errno was already set before we enter the logging call, we'll
- // set it back to that value when we return from the logging call.
- // It happens often that we log an error message after a syscall
- // failure, which can potentially set the errno to some other
- // values. We would like to preserve the original errno.
- if (data_->preserved_errno_ != 0) {
- errno = data_->preserved_errno_;
- }
-
- // Note that this message is now safely logged. If we're asked to flush
- // again, as a result of destruction, say, we'll do nothing on future calls.
- data_->has_been_flushed_ = true;
-}
-
-// Copy of first FATAL log message so that we can print it out again
-// after all the stack traces. To preserve legacy behavior, we don't
-// use fatal_msg_data_exclusive.
-static time_t fatal_time;
-static char fatal_message[256];
-
-void ReprintFatalMessage() {
- if (fatal_message[0]) {
- const int n = strlen(fatal_message);
- if (!FLAGS_logtostderr) {
- // Also write to stderr (don't color to avoid terminal checks)
- WriteToStderr(fatal_message, n);
- }
- LogDestination::LogToAllLogfiles(GLOG_ERROR, fatal_time, fatal_message, n);
- }
-}
-
-// L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
- static bool already_warned_before_initgoogle = false;
-
- log_mutex.AssertHeld();
-
- RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
- data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
-
- // Messages of a given severity get logged to lower severity logs, too
-
- if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {
- const char w[] = "WARNING: Logging before InitGoogleLogging() is "
- "written to STDERR\n";
- WriteToStderr(w, strlen(w));
- already_warned_before_initgoogle = true;
- }
-
- // global flag: never log to file if set. Also -- don't log to a
- // file if we haven't parsed the command line flags to get the
- // program name.
- if (FLAGS_logtostderr || !IsGoogleLoggingInitialized()) {
- ColoredWriteToStderr(data_->severity_,
- data_->message_text_, data_->num_chars_to_log_);
-
- // this could be protected by a flag if necessary.
- LogDestination::LogToSinks(data_->severity_,
- data_->fullname_, data_->basename_,
- data_->line_, &data_->tm_time_,
- data_->message_text_ + data_->num_prefix_chars_,
- (data_->num_chars_to_log_ -
- data_->num_prefix_chars_ - 1));
- } else {
-
- // log this message to all log files of severity <= severity_
- LogDestination::LogToAllLogfiles(data_->severity_, data_->timestamp_,
- data_->message_text_,
- data_->num_chars_to_log_);
-
- LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,
- data_->num_chars_to_log_);
- LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
- data_->num_chars_to_log_);
- LogDestination::LogToSinks(data_->severity_,
- data_->fullname_, data_->basename_,
- data_->line_, &data_->tm_time_,
- data_->message_text_ + data_->num_prefix_chars_,
- (data_->num_chars_to_log_
- - data_->num_prefix_chars_ - 1));
- // NOTE: -1 removes trailing \n
- }
-
- // If we log a FATAL message, flush all the log destinations, then toss
- // a signal for others to catch. We leave the logs in a state that
- // someone else can use them (as long as they flush afterwards)
- if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {
- if (data_->first_fatal_) {
- // Store crash information so that it is accessible from within signal
- // handlers that may be invoked later.
- RecordCrashReason(&crash_reason);
- SetCrashReason(&crash_reason);
-
- // Store shortened fatal message for other logs and GWQ status
- const int copy = min<int>(data_->num_chars_to_log_,
- sizeof(fatal_message)-1);
- memcpy(fatal_message, data_->message_text_, copy);
- fatal_message[copy] = '\0';
- fatal_time = data_->timestamp_;
- }
-
- if (!FLAGS_logtostderr) {
- for (int i = 0; i < NUM_SEVERITIES; ++i) {
- if ( LogDestination::log_destinations_[i] )
- LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
- }
- }
-
- // release the lock that our caller (directly or indirectly)
- // LogMessage::~LogMessage() grabbed so that signal handlers
- // can use the logging facility. Alternately, we could add
- // an entire unsafe logging interface to bypass locking
- // for signal handlers but this seems simpler.
- log_mutex.Unlock();
- LogDestination::WaitForSinks(data_);
-
- const char* message = "*** Check failure stack trace: ***\n";
- if (write(STDERR_FILENO, message, strlen(message)) < 0) {
- // Ignore errors.
- }
- Fail();
- }
-}
-
-void LogMessage::RecordCrashReason(
- glog_internal_namespace_::CrashReason* reason) {
- reason->filename = fatal_msg_data_exclusive.fullname_;
- reason->line_number = fatal_msg_data_exclusive.line_;
- reason->message = fatal_msg_data_exclusive.message_text_ +
- fatal_msg_data_exclusive.num_prefix_chars_;
-#ifdef HAVE_STACKTRACE
- // Retrieve the stack trace, omitting the logging frames that got us here.
- reason->depth = GetStackTrace(reason->stack, ARRAYSIZE(reason->stack), 4);
-#else
- reason->depth = 0;
-#endif
-}
-
-#ifdef HAVE___ATTRIBUTE__
-# define ATTRIBUTE_NORETURN __attribute__((noreturn))
-#else
-# define ATTRIBUTE_NORETURN
-#endif
-
-static void logging_fail() ATTRIBUTE_NORETURN;
-
-static void logging_fail() {
-#if defined(_DEBUG) && defined(_MSC_VER)
- // When debugging on windows, avoid the obnoxious dialog and make
- // it possible to continue past a LOG(FATAL) in the debugger
- __debugbreak();
-#else
- abort();
-#endif
-}
-
-typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
-
-GOOGLE_GLOG_DLL_DECL
-logging_fail_func_t g_logging_fail_func = &logging_fail;
-
-void InstallFailureFunction(void (*fail_func)()) {
- g_logging_fail_func = (logging_fail_func_t)fail_func;
-}
-
-void LogMessage::Fail() {
- g_logging_fail_func();
-}
-
-// L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
- if (data_->sink_ != NULL) {
- RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
- data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
- data_->sink_->send(data_->severity_, data_->fullname_, data_->basename_,
- data_->line_, &data_->tm_time_,
- data_->message_text_ + data_->num_prefix_chars_,
- (data_->num_chars_to_log_ -
- data_->num_prefix_chars_ - 1));
- }
-}
-
-// L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
- SendToSink();
- SendToLog();
-}
-
-// L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
- if (data_->outvec_ != NULL) {
- RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
- data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
- // Omit prefix of message and trailing newline when recording in outvec_.
- const char *start = data_->message_text_ + data_->num_prefix_chars_;
- int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
- data_->outvec_->push_back(string(start, len));
- } else {
- SendToLog();
- }
-}
-
-void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
- if (data_->message_ != NULL) {
- RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
- data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
- // Omit prefix of message and trailing newline when writing to message_.
- const char *start = data_->message_text_ + data_->num_prefix_chars_;
- int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
- data_->message_->assign(start, len);
- }
- SendToLog();
-}
-
-// L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SendToSyslogAndLog() {
-#ifdef HAVE_SYSLOG_H
- // Before any calls to syslog(), make a single call to openlog()
- static bool openlog_already_called = false;
- if (!openlog_already_called) {
- openlog(glog_internal_namespace_::ProgramInvocationShortName(),
- LOG_CONS | LOG_NDELAY | LOG_PID,
- LOG_USER);
- openlog_already_called = true;
- }
-
- // This array maps Google severity levels to syslog levels
- const int SEVERITY_TO_LEVEL[] = { LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG };
- syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)], "%.*s",
- int(data_->num_chars_to_syslog_),
- data_->message_text_ + data_->num_prefix_chars_);
- SendToLog();
-#else
- LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
-#endif
-}
-
-base::Logger* base::GetLogger(LogSeverity severity) {
- MutexLock l(&log_mutex);
- return LogDestination::log_destination(severity)->logger_;
-}
-
-void base::SetLogger(LogSeverity severity, base::Logger* logger) {
- MutexLock l(&log_mutex);
- LogDestination::log_destination(severity)->logger_ = logger;
-}
-
-// L < log_mutex. Acquires and releases mutex_.
-int64 LogMessage::num_messages(int severity) {
- MutexLock l(&log_mutex);
- return num_messages_[severity];
-}
-
-// Output the COUNTER value. This is only valid if ostream is a
-// LogStream.
-ostream& operator<<(ostream &os, const PRIVATE_Counter&) {
-#ifdef DISABLE_RTTI
- LogMessage::LogStream *log = static_cast<LogMessage::LogStream*>(&os);
-#else
- LogMessage::LogStream *log = dynamic_cast<LogMessage::LogStream*>(&os);
-#endif
- CHECK(log && log == log->self())
- << "You must not use COUNTER with non-glog ostream";
- os << log->ctr();
- return os;
-}
-
-ErrnoLogMessage::ErrnoLogMessage(const char* file, int line,
- LogSeverity severity, int ctr,
- void (LogMessage::*send_method)())
- : LogMessage(file, line, severity, ctr, send_method) {
-}
-
-ErrnoLogMessage::~ErrnoLogMessage() {
- // Don't access errno directly because it may have been altered
- // while streaming the message.
- stream() << ": " << StrError(preserved_errno()) << " ["
- << preserved_errno() << "]";
-}
-
-void FlushLogFiles(LogSeverity min_severity) {
- LogDestination::FlushLogFiles(min_severity);
-}
-
-void FlushLogFilesUnsafe(LogSeverity min_severity) {
- LogDestination::FlushLogFilesUnsafe(min_severity);
-}
-
-void SetLogDestination(LogSeverity severity, const char* base_filename) {
- LogDestination::SetLogDestination(severity, base_filename);
-}
-
-void SetLogSymlink(LogSeverity severity, const char* symlink_basename) {
- LogDestination::SetLogSymlink(severity, symlink_basename);
-}
-
-LogSink::~LogSink() {
-}
-
-void LogSink::WaitTillSent() {
- // noop default
-}
-
-string LogSink::ToString(LogSeverity severity, const char* file, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len) {
- ostringstream stream(string(message, message_len));
- stream.fill('0');
-
- // FIXME(jrvb): Updating this to use the correct value for usecs
- // requires changing the signature for both this method and
- // LogSink::send(). This change needs to be done in a separate CL
- // so subclasses of LogSink can be updated at the same time.
- int usecs = 0;
-
- stream << LogSeverityNames[severity][0]
- << setw(2) << 1+tm_time->tm_mon
- << setw(2) << tm_time->tm_mday
- << ' '
- << setw(2) << tm_time->tm_hour << ':'
- << setw(2) << tm_time->tm_min << ':'
- << setw(2) << tm_time->tm_sec << '.'
- << setw(6) << usecs
- << ' '
- << setfill(' ') << setw(5) << GetTID() << setfill('0')
- << ' '
- << file << ':' << line << "] ";
-
- stream << string(message, message_len);
- return stream.str();
-}
-
-void AddLogSink(LogSink *destination) {
- LogDestination::AddLogSink(destination);
-}
-
-void RemoveLogSink(LogSink *destination) {
- LogDestination::RemoveLogSink(destination);
-}
-
-void SetLogFilenameExtension(const char* ext) {
- LogDestination::SetLogFilenameExtension(ext);
-}
-
-void SetStderrLogging(LogSeverity min_severity) {
- LogDestination::SetStderrLogging(min_severity);
-}
-
-void SetEmailLogging(LogSeverity min_severity, const char* addresses) {
- LogDestination::SetEmailLogging(min_severity, addresses);
-}
-
-void LogToStderr() {
- LogDestination::LogToStderr();
-}
-
-namespace base {
-namespace internal {
-
-namespace {
-
-bool GetExitOnDFatal() {
- MutexLock l(&log_mutex);
- return exit_on_dfatal;
-}
-
-// Determines whether we exit the program for a LOG(DFATAL) message in
-// debug mode. It does this by skipping the call to Fail/FailQuietly.
-// This is intended for testing only.
-//
-// This can have some effects on LOG(FATAL) as well. Failure messages
-// are always allocated (rather than sharing a buffer), the crash
-// reason is not recorded, the "gwq" status message is not updated,
-// and the stack trace is not recorded. The LOG(FATAL) *will* still
-// exit the program. Since this function is used only in testing,
-// these differences are acceptable.
-void SetExitOnDFatal(bool value) {
- MutexLock l(&log_mutex);
- exit_on_dfatal = value;
-}
-
-} // namespace
-
-} // namespace internal
-} // namespace base
-
-// use_logging controls whether the logging functions LOG/VLOG are used
-// to log errors. It should be set to false when the caller holds the
-// log_mutex.
-static bool SendEmailInternal(const char*dest, const char *subject,
- const char*body, bool use_logging) {
- if (dest && *dest) {
- if ( use_logging ) {
- VLOG(1) << "Trying to send TITLE:" << subject
- << " BODY:" << body << " to " << dest;
- } else {
- fprintf(stderr, "Trying to send TITLE: %s BODY: %s to %s\n",
- subject, body, dest);
- }
-
- string cmd =
- FLAGS_logmailer + " -s\"" + subject + "\" " + dest;
- FILE* pipe = popen(cmd.c_str(), "w");
- if (pipe != NULL) {
- // Add the body if we have one
- if (body)
- fwrite(body, sizeof(char), strlen(body), pipe);
- bool ok = pclose(pipe) != -1;
- if ( !ok ) {
- if ( use_logging ) {
- LOG(ERROR) << "Problems sending mail to " << dest << ": "
- << StrError(errno);
- } else {
- fprintf(stderr, "Problems sending mail to %s: %s\n",
- dest, StrError(errno).c_str());
- }
- }
- return ok;
- } else {
- if ( use_logging ) {
- LOG(ERROR) << "Unable to send mail to " << dest;
- } else {
- fprintf(stderr, "Unable to send mail to %s\n", dest);
- }
- }
- }
- return false;
-}
-
-bool SendEmail(const char*dest, const char *subject, const char*body){
- return SendEmailInternal(dest, subject, body, true);
-}
-
-static void GetTempDirectories(vector<string>* list) {
- list->clear();
-#ifdef OS_WINDOWS
- // On windows we'll try to find a directory in this order:
- // C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)
- // C:/TMP/
- // C:/TEMP/
- // C:/WINDOWS/ or C:/WINNT/
- // .
- char tmp[MAX_PATH];
- if (GetTempPathA(MAX_PATH, tmp))
- list->push_back(tmp);
- list->push_back("C:\\tmp\\");
- list->push_back("C:\\temp\\");
-#else
- // Directories, in order of preference. If we find a dir that
- // exists, we stop adding other less-preferred dirs
- const char * candidates[] = {
- // Non-null only during unittest/regtest
- getenv("TEST_TMPDIR"),
-
- // Explicitly-supplied temp dirs
- getenv("TMPDIR"), getenv("TMP"),
-
- // If all else fails
- "/tmp",
- };
-
- for (size_t i = 0; i < ARRAYSIZE(candidates); i++) {
- const char *d = candidates[i];
- if (!d) continue; // Empty env var
-
- // Make sure we don't surprise anyone who's expecting a '/'
- string dstr = d;
- if (dstr[dstr.size() - 1] != '/') {
- dstr += "/";
- }
- list->push_back(dstr);
-
- struct stat statbuf;
- if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {
- // We found a dir that exists - we're done.
- return;
- }
- }
-
-#endif
-}
-
-static vector<string>* logging_directories_list;
-
-const vector<string>& GetLoggingDirectories() {
- // Not strictly thread-safe but we're called early in InitGoogle().
- if (logging_directories_list == NULL) {
- logging_directories_list = new vector<string>;
-
- if ( !FLAGS_log_dir.empty() ) {
- // A dir was specified, we should use it
- logging_directories_list->push_back(FLAGS_log_dir.c_str());
- } else {
- GetTempDirectories(logging_directories_list);
-#ifdef OS_WINDOWS
- char tmp[MAX_PATH];
- if (GetWindowsDirectoryA(tmp, MAX_PATH))
- logging_directories_list->push_back(tmp);
- logging_directories_list->push_back(".\\");
-#else
- logging_directories_list->push_back("./");
-#endif
- }
- }
- return *logging_directories_list;
-}
-
-void TestOnly_ClearLoggingDirectoriesList() {
- fprintf(stderr, "TestOnly_ClearLoggingDirectoriesList should only be "
- "called from test code.\n");
- delete logging_directories_list;
- logging_directories_list = NULL;
-}
-
-void GetExistingTempDirectories(vector<string>* list) {
- GetTempDirectories(list);
- vector<string>::iterator i_dir = list->begin();
- while( i_dir != list->end() ) {
- // zero arg to access means test for existence; no constant
- // defined on windows
- if ( access(i_dir->c_str(), 0) ) {
- i_dir = list->erase(i_dir);
- } else {
- ++i_dir;
- }
- }
-}
-
-void TruncateLogFile(const char *path, int64 limit, int64 keep) {
-#ifdef HAVE_UNISTD_H
- struct stat statbuf;
- const int kCopyBlockSize = 8 << 10;
- char copybuf[kCopyBlockSize];
- int64 read_offset, write_offset;
- // Don't follow symlinks unless they're our own fd symlinks in /proc
- int flags = O_RDWR;
- // TODO(hamaji): Support other environments.
-#ifdef OS_LINUX
- const char *procfd_prefix = "/proc/self/fd/";
- if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;
-#endif
-
- int fd = open(path, flags);
- if (fd == -1) {
- if (errno == EFBIG) {
- // The log file in question has got too big for us to open. The
- // real fix for this would be to compile logging.cc (or probably
- // all of base/...) with -D_FILE_OFFSET_BITS=64 but that's
- // rather scary.
- // Instead just truncate the file to something we can manage
- if (truncate(path, 0) == -1) {
- PLOG(ERROR) << "Unable to truncate " << path;
- } else {
- LOG(ERROR) << "Truncated " << path << " due to EFBIG error";
- }
- } else {
- PLOG(ERROR) << "Unable to open " << path;
- }
- return;
- }
-
- if (fstat(fd, &statbuf) == -1) {
- PLOG(ERROR) << "Unable to fstat()";
- goto out_close_fd;
- }
-
- // See if the path refers to a regular file bigger than the
- // specified limit
- if (!S_ISREG(statbuf.st_mode)) goto out_close_fd;
- if (statbuf.st_size <= limit) goto out_close_fd;
- if (statbuf.st_size <= keep) goto out_close_fd;
-
- // This log file is too large - we need to truncate it
- LOG(INFO) << "Truncating " << path << " to " << keep << " bytes";
-
- // Copy the last "keep" bytes of the file to the beginning of the file
- read_offset = statbuf.st_size - keep;
- write_offset = 0;
- int bytesin, bytesout;
- while ((bytesin = pread(fd, copybuf, sizeof(copybuf), read_offset)) > 0) {
- bytesout = pwrite(fd, copybuf, bytesin, write_offset);
- if (bytesout == -1) {
- PLOG(ERROR) << "Unable to write to " << path;
- break;
- } else if (bytesout != bytesin) {
- LOG(ERROR) << "Expected to write " << bytesin << ", wrote " << bytesout;
- }
- read_offset += bytesin;
- write_offset += bytesout;
- }
- if (bytesin == -1) PLOG(ERROR) << "Unable to read from " << path;
-
- // Truncate the remainder of the file. If someone else writes to the
- // end of the file after our last read() above, we lose their latest
- // data. Too bad ...
- if (ftruncate(fd, write_offset) == -1) {
- PLOG(ERROR) << "Unable to truncate " << path;
- }
-
- out_close_fd:
- close(fd);
-#else
- LOG(ERROR) << "No log truncation support.";
-#endif
-}
-
-void TruncateStdoutStderr() {
-#ifdef HAVE_UNISTD_H
- int64 limit = MaxLogSize() << 20;
- int64 keep = 1 << 20;
- TruncateLogFile("/proc/self/fd/1", limit, keep);
- TruncateLogFile("/proc/self/fd/2", limit, keep);
-#else
- LOG(ERROR) << "No log truncation support.";
-#endif
-}
-
-
-// Helper functions for string comparisons.
-#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
- string* Check##func##expected##Impl(const char* s1, const char* s2, \
- const char* names) { \
- bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
- if (equal == expected) return NULL; \
- else { \
- ostringstream ss; \
- if (!s1) s1 = ""; \
- if (!s2) s2 = ""; \
- ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
- return new string(ss.str()); \
- } \
- }
-DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
-DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
-DEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true)
-DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)
-#undef DEFINE_CHECK_STROP_IMPL
-
-int posix_strerror_r(int err, char *buf, size_t len) {
- // Sanity check input parameters
- if (buf == NULL || len <= 0) {
- errno = EINVAL;
- return -1;
- }
-
- // Reset buf and errno, and try calling whatever version of strerror_r()
- // is implemented by glibc
- buf[0] = '\000';
- int old_errno = errno;
- errno = 0;
- char *rc = reinterpret_cast<char *>(strerror_r(err, buf, len));
-
- // Both versions set errno on failure
- if (errno) {
- // Should already be there, but better safe than sorry
- buf[0] = '\000';
- return -1;
- }
- errno = old_errno;
-
- // POSIX is vague about whether the string will be terminated, although
- // is indirectly implies that typically ERANGE will be returned, instead
- // of truncating the string. This is different from the GNU implementation.
- // We play it safe by always terminating the string explicitly.
- buf[len-1] = '\000';
-
- // If the function succeeded, we can use its exit code to determine the
- // semantics implemented by glibc
- if (!rc) {
- return 0;
- } else {
- // GNU semantics detected
- if (rc == buf) {
- return 0;
- } else {
- buf[0] = '\000';
-#if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
- if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
- // This means an error on MacOSX or FreeBSD.
- return -1;
- }
-#endif
- strncat(buf, rc, len-1);
- return 0;
- }
- }
-}
-
-string StrError(int err) {
- char buf[100];
- int rc = posix_strerror_r(err, buf, sizeof(buf));
- if ((rc < 0) || (buf[0] == '\000')) {
- snprintf(buf, sizeof(buf), "Error number %d", err);
- }
- return buf;
-}
-
-LogMessageFatal::LogMessageFatal(const char* file, int line) :
- LogMessage(file, line, GLOG_FATAL) {}
-
-LogMessageFatal::LogMessageFatal(const char* file, int line,
- const CheckOpString& result) :
- LogMessage(file, line, result) {}
-
-LogMessageFatal::~LogMessageFatal() {
- Flush();
- LogMessage::Fail();
-}
-
-namespace base {
-
-CheckOpMessageBuilder::CheckOpMessageBuilder(const char *exprtext)
- : stream_(new ostringstream) {
- *stream_ << exprtext << " (";
-}
-
-CheckOpMessageBuilder::~CheckOpMessageBuilder() {
- delete stream_;
-}
-
-ostream* CheckOpMessageBuilder::ForVar2() {
- *stream_ << " vs. ";
- return stream_;
-}
-
-string* CheckOpMessageBuilder::NewString() {
- *stream_ << ")";
- return new string(stream_->str());
-}
-
-} // namespace base
-
-template <>
-void MakeCheckOpValueString(std::ostream* os, const char& v) {
- if (v >= 32 && v <= 126) {
- (*os) << "'" << v << "'";
- } else {
- (*os) << "char value " << (short)v;
- }
-}
-
-template <>
-void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
- if (v >= 32 && v <= 126) {
- (*os) << "'" << v << "'";
- } else {
- (*os) << "signed char value " << (short)v;
- }
-}
-
-template <>
-void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
- if (v >= 32 && v <= 126) {
- (*os) << "'" << v << "'";
- } else {
- (*os) << "unsigned char value " << (unsigned short)v;
- }
-}
-
-void InitGoogleLogging(const char* argv0) {
- glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
-}
-
-void ShutdownGoogleLogging() {
- glog_internal_namespace_::ShutdownGoogleLoggingUtilities();
- LogDestination::DeleteLogDestinations();
- delete logging_directories_list;
- logging_directories_list = NULL;
-}
-
-_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/signalhandler.cc b/extern/libmv/third_party/glog/src/signalhandler.cc
deleted file mode 100644
index cccd800d769..00000000000
--- a/extern/libmv/third_party/glog/src/signalhandler.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-//
-// Implementation of InstallFailureSignalHandler().
-
-#include "utilities.h"
-#include "stacktrace.h"
-#include "symbolize.h"
-#include "glog/logging.h"
-
-#include <signal.h>
-#include <time.h>
-#ifdef HAVE_UCONTEXT_H
-# include <ucontext.h>
-#endif
-#ifdef HAVE_SYS_UCONTEXT_H
-# include <sys/ucontext.h>
-#endif
-#include <algorithm>
-
-_START_GOOGLE_NAMESPACE_
-
-// TOOD(hamaji): Use signal instead of sigaction?
-#ifdef HAVE_SIGACTION
-
-namespace {
-
-// We'll install the failure signal handler for these signals. We could
-// use strsignal() to get signal names, but we don't use it to avoid
-// introducing yet another #ifdef complication.
-//
-// The list should be synced with the comment in signalhandler.h.
-const struct {
- int number;
- const char *name;
-} kFailureSignals[] = {
- { SIGSEGV, "SIGSEGV" },
- { SIGILL, "SIGILL" },
- { SIGFPE, "SIGFPE" },
- { SIGABRT, "SIGABRT" },
- { SIGBUS, "SIGBUS" },
- { SIGTERM, "SIGTERM" },
-};
-
-// Returns the program counter from signal context, NULL if unknown.
-void* GetPC(void* ucontext_in_void) {
-#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
- if (ucontext_in_void != NULL) {
- ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
- return (void*)context->PC_FROM_UCONTEXT;
- }
-#endif
- return NULL;
-}
-
-// The class is used for formatting error messages. We don't use printf()
-// as it's not async signal safe.
-class MinimalFormatter {
- public:
- MinimalFormatter(char *buffer, int size)
- : buffer_(buffer),
- cursor_(buffer),
- end_(buffer + size) {
- }
-
- // Returns the number of bytes written in the buffer.
- int num_bytes_written() const { return cursor_ - buffer_; }
-
- // Appends string from "str" and updates the internal cursor.
- void AppendString(const char* str) {
- int i = 0;
- while (str[i] != '\0' && cursor_ + i < end_) {
- cursor_[i] = str[i];
- ++i;
- }
- cursor_ += i;
- }
-
- // Formats "number" in "radix" and updates the internal cursor.
- // Lowercase letters are used for 'a' - 'z'.
- void AppendUint64(uint64 number, int radix) {
- int i = 0;
- while (cursor_ + i < end_) {
- const int tmp = number % radix;
- number /= radix;
- cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
- ++i;
- if (number == 0) {
- break;
- }
- }
- // Reverse the bytes written.
- std::reverse(cursor_, cursor_ + i);
- cursor_ += i;
- }
-
- // Formats "number" as hexadecimal number, and updates the internal
- // cursor. Padding will be added in front if needed.
- void AppendHexWithPadding(uint64 number, int width) {
- char* start = cursor_;
- AppendString("0x");
- AppendUint64(number, 16);
- // Move to right and add padding in front if needed.
- if (cursor_ < start + width) {
- const int64 delta = start + width - cursor_;
- std::copy(start, cursor_, start + delta);
- std::fill(start, start + delta, ' ');
- cursor_ = start + width;
- }
- }
-
- private:
- char *buffer_;
- char *cursor_;
- const char * const end_;
-};
-
-// Writes the given data with the size to the standard error.
-void WriteToStderr(const char* data, int size) {
- if (write(STDERR_FILENO, data, size) < 0) {
- // Ignore errors.
- }
-}
-
-// The writer function can be changed by InstallFailureWriter().
-void (*g_failure_writer)(const char* data, int size) = WriteToStderr;
-
-// Dumps time information. We don't dump human-readable time information
-// as localtime() is not guaranteed to be async signal safe.
-void DumpTimeInfo() {
- time_t time_in_sec = time(NULL);
- char buf[256]; // Big enough for time info.
- MinimalFormatter formatter(buf, sizeof(buf));
- formatter.AppendString("*** Aborted at ");
- formatter.AppendUint64(time_in_sec, 10);
- formatter.AppendString(" (unix time)");
- formatter.AppendString(" try \"date -d @");
- formatter.AppendUint64(time_in_sec, 10);
- formatter.AppendString("\" if you are using GNU date ***\n");
- g_failure_writer(buf, formatter.num_bytes_written());
-}
-
-// Dumps information about the signal to STDERR.
-void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
- // Get the signal name.
- const char* signal_name = NULL;
- for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
- if (signal_number == kFailureSignals[i].number) {
- signal_name = kFailureSignals[i].name;
- }
- }
-
- char buf[256]; // Big enough for signal info.
- MinimalFormatter formatter(buf, sizeof(buf));
-
- formatter.AppendString("*** ");
- if (signal_name) {
- formatter.AppendString(signal_name);
- } else {
- // Use the signal number if the name is unknown. The signal name
- // should be known, but just in case.
- formatter.AppendString("Signal ");
- formatter.AppendUint64(signal_number, 10);
- }
- formatter.AppendString(" (@0x");
- formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
- formatter.AppendString(")");
- formatter.AppendString(" received by PID ");
- formatter.AppendUint64(getpid(), 10);
- formatter.AppendString(" (TID 0x");
- // We assume pthread_t is an integral number or a pointer, rather
- // than a complex struct. In some environments, pthread_self()
- // returns an uint64 but in some other environments pthread_self()
- // returns a pointer. Hence we use C-style cast here, rather than
- // reinterpret/static_cast, to support both types of environments.
- formatter.AppendUint64((uintptr_t)pthread_self(), 16);
- formatter.AppendString(") ");
- // Only linux has the PID of the signal sender in si_pid.
-#ifdef OS_LINUX
- formatter.AppendString("from PID ");
- formatter.AppendUint64(siginfo->si_pid, 10);
- formatter.AppendString("; ");
-#endif
- formatter.AppendString("stack trace: ***\n");
- g_failure_writer(buf, formatter.num_bytes_written());
-}
-
-// Dumps information about the stack frame to STDERR.
-void DumpStackFrameInfo(const char* prefix, void* pc) {
- // Get the symbol name.
- const char *symbol = "(unknown)";
- char symbolized[1024]; // Big enough for a sane symbol.
- // Symbolizes the previous address of pc because pc may be in the
- // next function.
- if (Symbolize(reinterpret_cast<char *>(pc) - 1,
- symbolized, sizeof(symbolized))) {
- symbol = symbolized;
- }
-
- char buf[1024]; // Big enough for stack frame info.
- MinimalFormatter formatter(buf, sizeof(buf));
-
- formatter.AppendString(prefix);
- formatter.AppendString("@ ");
- const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
- formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
- formatter.AppendString(" ");
- formatter.AppendString(symbol);
- formatter.AppendString("\n");
- g_failure_writer(buf, formatter.num_bytes_written());
-}
-
-// Invoke the default signal handler.
-void InvokeDefaultSignalHandler(int signal_number) {
- struct sigaction sig_action;
- memset(&sig_action, 0, sizeof(sig_action));
- sigemptyset(&sig_action.sa_mask);
- sig_action.sa_handler = SIG_DFL;
- sigaction(signal_number, &sig_action, NULL);
- kill(getpid(), signal_number);
-}
-
-// This variable is used for protecting FailureSignalHandler() from
-// dumping stuff while another thread is doing it. Our policy is to let
-// the first thread dump stuff and let other threads wait.
-// See also comments in FailureSignalHandler().
-static pthread_t* g_entered_thread_id_pointer = NULL;
-
-// Dumps signal and stack frame information, and invokes the default
-// signal handler once our job is done.
-void FailureSignalHandler(int signal_number,
- siginfo_t *signal_info,
- void *ucontext) {
- // First check if we've already entered the function. We use an atomic
- // compare and swap operation for platforms that support it. For other
- // platforms, we use a naive method that could lead to a subtle race.
-
- // We assume pthread_self() is async signal safe, though it's not
- // officially guaranteed.
- pthread_t my_thread_id = pthread_self();
- // NOTE: We could simply use pthread_t rather than pthread_t* for this,
- // if pthread_self() is guaranteed to return non-zero value for thread
- // ids, but there is no such guarantee. We need to distinguish if the
- // old value (value returned from __sync_val_compare_and_swap) is
- // different from the original value (in this case NULL).
- pthread_t* old_thread_id_pointer =
- glog_internal_namespace_::sync_val_compare_and_swap(
- &g_entered_thread_id_pointer,
- static_cast<pthread_t*>(NULL),
- &my_thread_id);
- if (old_thread_id_pointer != NULL) {
- // We've already entered the signal handler. What should we do?
- if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
- // It looks the current thread is reentering the signal handler.
- // Something must be going wrong (maybe we are reentering by another
- // type of signal?). Kill ourself by the default signal handler.
- InvokeDefaultSignalHandler(signal_number);
- }
- // Another thread is dumping stuff. Let's wait until that thread
- // finishes the job and kills the process.
- while (true) {
- sleep(1);
- }
- }
- // This is the first time we enter the signal handler. We are going to
- // do some interesting stuff from here.
- // TODO(satorux): We might want to set timeout here using alarm(), but
- // mixing alarm() and sleep() can be a bad idea.
-
- // First dump time info.
- DumpTimeInfo();
-
- // Get the program counter from ucontext.
- void *pc = GetPC(ucontext);
- DumpStackFrameInfo("PC: ", pc);
-
-#ifdef HAVE_STACKTRACE
- // Get the stack traces.
- void *stack[32];
- // +1 to exclude this function.
- const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
- DumpSignalInfo(signal_number, signal_info);
- // Dump the stack traces.
- for (int i = 0; i < depth; ++i) {
- DumpStackFrameInfo(" ", stack[i]);
- }
-#endif
-
- // *** TRANSITION ***
- //
- // BEFORE this point, all code must be async-termination-safe!
- // (See WARNING above.)
- //
- // AFTER this point, we do unsafe things, like using LOG()!
- // The process could be terminated or hung at any time. We try to
- // do more useful things first and riskier things later.
-
- // Flush the logs before we do anything in case 'anything'
- // causes problems.
- FlushLogFilesUnsafe(0);
-
- // Kill ourself by the default signal handler.
- InvokeDefaultSignalHandler(signal_number);
-}
-
-} // namespace
-
-#endif // HAVE_SIGACTION
-
-void InstallFailureSignalHandler() {
-#ifdef HAVE_SIGACTION
- // Build the sigaction struct.
- struct sigaction sig_action;
- memset(&sig_action, 0, sizeof(sig_action));
- sigemptyset(&sig_action.sa_mask);
- sig_action.sa_flags |= SA_SIGINFO;
- sig_action.sa_sigaction = &FailureSignalHandler;
-
- for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
- CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
- }
-#endif // HAVE_SIGACTION
-}
-
-void InstallFailureWriter(void (*writer)(const char* data, int size)) {
-#ifdef HAVE_SIGACTION
- g_failure_writer = writer;
-#endif // HAVE_SIGACTION
-}
-
-_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/symbolize.cc b/extern/libmv/third_party/glog/src/symbolize.cc
deleted file mode 100644
index b25f7479d0d..00000000000
--- a/extern/libmv/third_party/glog/src/symbolize.cc
+++ /dev/null
@@ -1,848 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Satoru Takabayashi
-// Stack-footprint reduction work done by Raksit Ashok
-//
-// Implementation note:
-//
-// We don't use heaps but only use stacks. We want to reduce the
-// stack consumption so that the symbolizer can run on small stacks.
-//
-// Here are some numbers collected with GCC 4.1.0 on x86:
-// - sizeof(Elf32_Sym) = 16
-// - sizeof(Elf32_Shdr) = 40
-// - sizeof(Elf64_Sym) = 24
-// - sizeof(Elf64_Shdr) = 64
-//
-// This implementation is intended to be async-signal-safe but uses
-// some functions which are not guaranteed to be so, such as memchr()
-// and memmove(). We assume they are async-signal-safe.
-//
-// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
-// macro to add platform specific defines (e.g. OS_OPENBSD).
-
-#ifdef GLOG_BUILD_CONFIG_INCLUDE
-#include GLOG_BUILD_CONFIG_INCLUDE
-#endif // GLOG_BUILD_CONFIG_INCLUDE
-
-#include "utilities.h"
-
-#if defined(HAVE_SYMBOLIZE)
-
-#include <limits>
-
-#include "symbolize.h"
-#include "demangle.h"
-
-_START_GOOGLE_NAMESPACE_
-
-// We don't use assert() since it's not guaranteed to be
-// async-signal-safe. Instead we define a minimal assertion
-// macro. So far, we don't need pretty printing for __FILE__, etc.
-
-// A wrapper for abort() to make it callable in ? :.
-static int AssertFail() {
- abort();
- return 0; // Should not reach.
-}
-
-#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
-
-static SymbolizeCallback g_symbolize_callback = NULL;
-void InstallSymbolizeCallback(SymbolizeCallback callback) {
- g_symbolize_callback = callback;
-}
-
-static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
- NULL;
-void InstallSymbolizeOpenObjectFileCallback(
- SymbolizeOpenObjectFileCallback callback) {
- g_symbolize_open_object_file_callback = callback;
-}
-
-// This function wraps the Demangle function to provide an interface
-// where the input symbol is demangled in-place.
-// To keep stack consumption low, we would like this function to not
-// get inlined.
-static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
- char demangled[256]; // Big enough for sane demangled symbols.
- if (Demangle(out, demangled, sizeof(demangled))) {
- // Demangling succeeded. Copy to out if the space allows.
- size_t len = strlen(demangled);
- if (len + 1 <= (size_t)out_size) { // +1 for '\0'.
- SAFE_ASSERT(len < sizeof(demangled));
- memmove(out, demangled, len + 1);
- }
- }
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#if defined(__ELF__)
-
-#include <dlfcn.h>
-#if defined(OS_OPENBSD)
-#include <sys/exec_elf.h>
-#else
-#include <elf.h>
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "symbolize.h"
-#include "config.h"
-#include "glog/raw_logging.h"
-
-// Re-runs fn until it doesn't cause EINTR.
-#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
-
-_START_GOOGLE_NAMESPACE_
-
-// Read up to "count" bytes from file descriptor "fd" into the buffer
-// starting at "buf" while handling short reads and EINTR. On
-// success, return the number of bytes read. Otherwise, return -1.
-static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
- SAFE_ASSERT(fd >= 0);
- SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
- char *buf0 = reinterpret_cast<char *>(buf);
- ssize_t num_bytes = 0;
- while (num_bytes < count) {
- ssize_t len;
- NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
- if (len < 0) { // There was an error other than EINTR.
- return -1;
- }
- if (len == 0) { // Reached EOF.
- break;
- }
- num_bytes += len;
- }
- SAFE_ASSERT(num_bytes <= count);
- return num_bytes;
-}
-
-// Read up to "count" bytes from "offset" in the file pointed by file
-// descriptor "fd" into the buffer starting at "buf". On success,
-// return the number of bytes read. Otherwise, return -1.
-static ssize_t ReadFromOffset(const int fd, void *buf,
- const size_t count, const off_t offset) {
- off_t off = lseek(fd, offset, SEEK_SET);
- if (off == (off_t)-1) {
- return -1;
- }
- return ReadPersistent(fd, buf, count);
-}
-
-// Try reading exactly "count" bytes from "offset" bytes in a file
-// pointed by "fd" into the buffer starting at "buf" while handling
-// short reads and EINTR. On success, return true. Otherwise, return
-// false.
-static bool ReadFromOffsetExact(const int fd, void *buf,
- const size_t count, const off_t offset) {
- ssize_t len = ReadFromOffset(fd, buf, count, offset);
- return len == count;
-}
-
-// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
-static int FileGetElfType(const int fd) {
- ElfW(Ehdr) elf_header;
- if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
- return -1;
- }
- if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
- return -1;
- }
- return elf_header.e_type;
-}
-
-// Read the section headers in the given ELF binary, and if a section
-// of the specified type is found, set the output to this section header
-// and return true. Otherwise, return false.
-// To keep stack consumption low, we would like this function to not get
-// inlined.
-static ATTRIBUTE_NOINLINE bool
-GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
- ElfW(Word) type, ElfW(Shdr) *out) {
- // Read at most 16 section headers at a time to save read calls.
- ElfW(Shdr) buf[16];
- for (int i = 0; i < sh_num;) {
- const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
- const ssize_t num_bytes_to_read =
- (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
- const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
- sh_offset + i * sizeof(buf[0]));
- SAFE_ASSERT(len % sizeof(buf[0]) == 0);
- const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
- SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
- for (int j = 0; j < num_headers_in_buf; ++j) {
- if (buf[j].sh_type == type) {
- *out = buf[j];
- return true;
- }
- }
- i += num_headers_in_buf;
- }
- return false;
-}
-
-// There is no particular reason to limit section name to 63 characters,
-// but there has (as yet) been no need for anything longer either.
-const int kMaxSectionNameLen = 64;
-
-// name_len should include terminating '\0'.
-bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
- ElfW(Shdr) *out) {
- ElfW(Ehdr) elf_header;
- if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
- return false;
- }
-
- ElfW(Shdr) shstrtab;
- off_t shstrtab_offset = (elf_header.e_shoff +
- elf_header.e_shentsize * elf_header.e_shstrndx);
- if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
- return false;
- }
-
- for (int i = 0; i < elf_header.e_shnum; ++i) {
- off_t section_header_offset = (elf_header.e_shoff +
- elf_header.e_shentsize * i);
- if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
- return false;
- }
- char header_name[kMaxSectionNameLen];
- if (sizeof(header_name) < name_len) {
- RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
- "section will not be found (even if present).", name, name_len);
- // No point in even trying.
- return false;
- }
- off_t name_offset = shstrtab.sh_offset + out->sh_name;
- ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
- if (n_read == -1) {
- return false;
- } else if (n_read != name_len) {
- // Short read -- name could be at end of file.
- continue;
- }
- if (memcmp(header_name, name, name_len) == 0) {
- return true;
- }
- }
- return false;
-}
-
-// Read a symbol table and look for the symbol containing the
-// pc. Iterate over symbols in a symbol table and look for the symbol
-// containing "pc". On success, return true and write the symbol name
-// to out. Otherwise, return false.
-// To keep stack consumption low, we would like this function to not get
-// inlined.
-static ATTRIBUTE_NOINLINE bool
-FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
- uint64_t symbol_offset, const ElfW(Shdr) *strtab,
- const ElfW(Shdr) *symtab) {
- if (symtab == NULL) {
- return false;
- }
- const int num_symbols = symtab->sh_size / symtab->sh_entsize;
- for (int i = 0; i < num_symbols;) {
- off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
-
- // If we are reading Elf64_Sym's, we want to limit this array to
- // 32 elements (to keep stack consumption low), otherwise we can
- // have a 64 element Elf32_Sym array.
-#if __WORDSIZE == 64
-#define NUM_SYMBOLS 32
-#else
-#define NUM_SYMBOLS 64
-#endif
-
- // Read at most NUM_SYMBOLS symbols at once to save read() calls.
- ElfW(Sym) buf[NUM_SYMBOLS];
- const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
- SAFE_ASSERT(len % sizeof(buf[0]) == 0);
- const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
- SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
- for (int j = 0; j < num_symbols_in_buf; ++j) {
- const ElfW(Sym)& symbol = buf[j];
- uint64_t start_address = symbol.st_value;
- start_address += symbol_offset;
- uint64_t end_address = start_address + symbol.st_size;
- if (symbol.st_value != 0 && // Skip null value symbols.
- symbol.st_shndx != 0 && // Skip undefined symbols.
- start_address <= pc && pc < end_address) {
- ssize_t len1 = ReadFromOffset(fd, out, out_size,
- strtab->sh_offset + symbol.st_name);
- if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
- return false;
- }
- return true; // Obtained the symbol name.
- }
- }
- i += num_symbols_in_buf;
- }
- return false;
-}
-
-// Get the symbol name of "pc" from the file pointed by "fd". Process
-// both regular and dynamic symbol tables if necessary. On success,
-// write the symbol name to "out" and return true. Otherwise, return
-// false.
-static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
- char *out, int out_size,
- uint64_t map_start_address) {
- // Read the ELF header.
- ElfW(Ehdr) elf_header;
- if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
- return false;
- }
-
- uint64_t symbol_offset = 0;
- if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment.
- symbol_offset = map_start_address;
- }
-
- ElfW(Shdr) symtab, strtab;
-
- // Consult a regular symbol table first.
- if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
- SHT_SYMTAB, &symtab)) {
- if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
- symtab.sh_link * sizeof(symtab))) {
- return false;
- }
- if (FindSymbol(pc, fd, out, out_size, symbol_offset,
- &strtab, &symtab)) {
- return true; // Found the symbol in a regular symbol table.
- }
- }
-
- // If the symbol is not found, then consult a dynamic symbol table.
- if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
- SHT_DYNSYM, &symtab)) {
- if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
- symtab.sh_link * sizeof(symtab))) {
- return false;
- }
- if (FindSymbol(pc, fd, out, out_size, symbol_offset,
- &strtab, &symtab)) {
- return true; // Found the symbol in a dynamic symbol table.
- }
- }
-
- return false;
-}
-
-namespace {
-// Thin wrapper around a file descriptor so that the file descriptor
-// gets closed for sure.
-struct FileDescriptor {
- const int fd_;
- explicit FileDescriptor(int fd) : fd_(fd) {}
- ~FileDescriptor() {
- if (fd_ >= 0) {
- NO_INTR(close(fd_));
- }
- }
- int get() { return fd_; }
-
- private:
- explicit FileDescriptor(const FileDescriptor&);
- void operator=(const FileDescriptor&);
-};
-
-// Helper class for reading lines from file.
-//
-// Note: we don't use ProcMapsIterator since the object is big (it has
-// a 5k array member) and uses async-unsafe functions such as sscanf()
-// and snprintf().
-class LineReader {
- public:
- explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
- buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
- }
-
- // Read '\n'-terminated line from file. On success, modify "bol"
- // and "eol", then return true. Otherwise, return false.
- //
- // Note: if the last line doesn't end with '\n', the line will be
- // dropped. It's an intentional behavior to make the code simple.
- bool ReadLine(const char **bol, const char **eol) {
- if (BufferIsEmpty()) { // First time.
- const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
- if (num_bytes <= 0) { // EOF or error.
- return false;
- }
- eod_ = buf_ + num_bytes;
- bol_ = buf_;
- } else {
- bol_ = eol_ + 1; // Advance to the next line in the buffer.
- SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
- if (!HasCompleteLine()) {
- const int incomplete_line_length = eod_ - bol_;
- // Move the trailing incomplete line to the beginning.
- memmove(buf_, bol_, incomplete_line_length);
- // Read text from file and append it.
- char * const append_pos = buf_ + incomplete_line_length;
- const int capacity_left = buf_len_ - incomplete_line_length;
- const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
- capacity_left);
- if (num_bytes <= 0) { // EOF or error.
- return false;
- }
- eod_ = append_pos + num_bytes;
- bol_ = buf_;
- }
- }
- eol_ = FindLineFeed();
- if (eol_ == NULL) { // '\n' not found. Malformed line.
- return false;
- }
- *eol_ = '\0'; // Replace '\n' with '\0'.
-
- *bol = bol_;
- *eol = eol_;
- return true;
- }
-
- // Beginning of line.
- const char *bol() {
- return bol_;
- }
-
- // End of line.
- const char *eol() {
- return eol_;
- }
-
- private:
- explicit LineReader(const LineReader&);
- void operator=(const LineReader&);
-
- char *FindLineFeed() {
- return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
- }
-
- bool BufferIsEmpty() {
- return buf_ == eod_;
- }
-
- bool HasCompleteLine() {
- return !BufferIsEmpty() && FindLineFeed() != NULL;
- }
-
- const int fd_;
- char * const buf_;
- const int buf_len_;
- char *bol_;
- char *eol_;
- const char *eod_; // End of data in "buf_".
-};
-} // namespace
-
-// Place the hex number read from "start" into "*hex". The pointer to
-// the first non-hex character or "end" is returned.
-static char *GetHex(const char *start, const char *end, uint64_t *hex) {
- *hex = 0;
- const char *p;
- for (p = start; p < end; ++p) {
- int ch = *p;
- if ((ch >= '0' && ch <= '9') ||
- (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
- *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
- } else { // Encountered the first non-hex character.
- break;
- }
- }
- SAFE_ASSERT(p <= end);
- return const_cast<char *>(p);
-}
-
-// Searches for the object file (from /proc/self/maps) that contains
-// the specified pc. If found, sets |start_address| to the start address
-// of where this object file is mapped in memory, sets the module base
-// address into |base_address|, copies the object file name into
-// |out_file_name|, and attempts to open the object file. If the object
-// file is opened successfully, returns the file descriptor. Otherwise,
-// returns -1. |out_file_name_size| is the size of the file name buffer
-// (including the null-terminator).
-static ATTRIBUTE_NOINLINE int
-OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
- uint64_t &start_address,
- uint64_t &base_address,
- char *out_file_name,
- int out_file_name_size) {
- int object_fd;
-
- // Open /proc/self/maps.
- int maps_fd;
- NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
- FileDescriptor wrapped_maps_fd(maps_fd);
- if (wrapped_maps_fd.get() < 0) {
- return -1;
- }
-
- // Iterate over maps and look for the map containing the pc. Then
- // look into the symbol tables inside.
- char buf[1024]; // Big enough for line of sane /proc/self/maps
- int num_maps = 0;
- LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
- while (true) {
- num_maps++;
- const char *cursor;
- const char *eol;
- if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
- return -1;
- }
-
- // Start parsing line in /proc/self/maps. Here is an example:
- //
- // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
- //
- // We want start address (08048000), end address (0804c000), flags
- // (r-xp) and file name (/bin/cat).
-
- // Read start address.
- cursor = GetHex(cursor, eol, &start_address);
- if (cursor == eol || *cursor != '-') {
- return -1; // Malformed line.
- }
- ++cursor; // Skip '-'.
-
- // Read end address.
- uint64_t end_address;
- cursor = GetHex(cursor, eol, &end_address);
- if (cursor == eol || *cursor != ' ') {
- return -1; // Malformed line.
- }
- ++cursor; // Skip ' '.
-
- // Check start and end addresses.
- if (!(start_address <= pc && pc < end_address)) {
- continue; // We skip this map. PC isn't in this map.
- }
-
- // Read flags. Skip flags until we encounter a space or eol.
- const char * const flags_start = cursor;
- while (cursor < eol && *cursor != ' ') {
- ++cursor;
- }
- // We expect at least four letters for flags (ex. "r-xp").
- if (cursor == eol || cursor < flags_start + 4) {
- return -1; // Malformed line.
- }
-
- // Check flags. We are only interested in "r-x" maps.
- if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
- continue; // We skip this map.
- }
- ++cursor; // Skip ' '.
-
- // Read file offset.
- uint64_t file_offset;
- cursor = GetHex(cursor, eol, &file_offset);
- if (cursor == eol || *cursor != ' ') {
- return -1; // Malformed line.
- }
- ++cursor; // Skip ' '.
-
- // Don't subtract 'start_address' from the first entry:
- // * If a binary is compiled w/o -pie, then the first entry in
- // process maps is likely the binary itself (all dynamic libs
- // are mapped higher in address space). For such a binary,
- // instruction offset in binary coincides with the actual
- // instruction address in virtual memory (as code section
- // is mapped to a fixed memory range).
- // * If a binary is compiled with -pie, all the modules are
- // mapped high at address space (in particular, higher than
- // shadow memory of the tool), so the module can't be the
- // first entry.
- base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
-
- // Skip to file name. "cursor" now points to dev. We need to
- // skip at least two spaces for dev and inode.
- int num_spaces = 0;
- while (cursor < eol) {
- if (*cursor == ' ') {
- ++num_spaces;
- } else if (num_spaces >= 2) {
- // The first non-space character after skipping two spaces
- // is the beginning of the file name.
- break;
- }
- ++cursor;
- }
- if (cursor == eol) {
- return -1; // Malformed line.
- }
-
- // Finally, "cursor" now points to file name of our interest.
- NO_INTR(object_fd = open(cursor, O_RDONLY));
- if (object_fd < 0) {
- // Failed to open object file. Copy the object file name to
- // |out_file_name|.
- strncpy(out_file_name, cursor, out_file_name_size);
- // Making sure |out_file_name| is always null-terminated.
- out_file_name[out_file_name_size - 1] = '\0';
- return -1;
- }
- return object_fd;
- }
-}
-
-// POSIX doesn't define any async-signal safe function for converting
-// an integer to ASCII. We'll have to define our own version.
-// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
-// conversion was successful or NULL otherwise. It never writes more than "sz"
-// bytes. Output will be truncated as needed, and a NUL character is always
-// appended.
-// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
-char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
- // Make sure we can write at least one NUL byte.
- size_t n = 1;
- if (n > sz)
- return NULL;
-
- if (base < 2 || base > 16) {
- buf[0] = '\000';
- return NULL;
- }
-
- char *start = buf;
-
- uintptr_t j = i;
-
- // Handle negative numbers (only for base 10).
- if (i < 0 && base == 10) {
- j = -i;
-
- // Make sure we can write the '-' character.
- if (++n > sz) {
- buf[0] = '\000';
- return NULL;
- }
- *start++ = '-';
- }
-
- // Loop until we have converted the entire number. Output at least one
- // character (i.e. '0').
- char *ptr = start;
- do {
- // Make sure there is still enough space left in our output buffer.
- if (++n > sz) {
- buf[0] = '\000';
- return NULL;
- }
-
- // Output the next digit.
- *ptr++ = "0123456789abcdef"[j % base];
- j /= base;
-
- if (padding > 0)
- padding--;
- } while (j > 0 || padding > 0);
-
- // Terminate the output with a NUL character.
- *ptr = '\000';
-
- // Conversion to ASCII actually resulted in the digits being in reverse
- // order. We can't easily generate them in forward order, as we can't tell
- // the number of characters needed until we are done converting.
- // So, now, we reverse the string (except for the possible "-" sign).
- while (--ptr > start) {
- char ch = *ptr;
- *ptr = *start;
- *start++ = ch;
- }
- return buf;
-}
-
-// Safely appends string |source| to string |dest|. Never writes past the
-// buffer size |dest_size| and guarantees that |dest| is null-terminated.
-void SafeAppendString(const char* source, char* dest, int dest_size) {
- int dest_string_length = strlen(dest);
- SAFE_ASSERT(dest_string_length < dest_size);
- dest += dest_string_length;
- dest_size -= dest_string_length;
- strncpy(dest, source, dest_size);
- // Making sure |dest| is always null-terminated.
- dest[dest_size - 1] = '\0';
-}
-
-// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
-// Never writes past the buffer size |dest_size| and guarantees that |dest| is
-// null-terminated.
-void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
- // 64-bit numbers in hex can have up to 16 digits.
- char buf[17] = {'\0'};
- SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
-}
-
-// The implementation of our symbolization routine. If it
-// successfully finds the symbol containing "pc" and obtains the
-// symbol name, returns true and write the symbol name to "out".
-// Otherwise, returns false. If Callback function is installed via
-// InstallSymbolizeCallback(), the function is also called in this function,
-// and "out" is used as its output.
-// To keep stack consumption low, we would like this function to not
-// get inlined.
-static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
- int out_size) {
- uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
- uint64_t start_address = 0;
- uint64_t base_address = 0;
- int object_fd = -1;
-
- if (out_size < 1) {
- return false;
- }
- out[0] = '\0';
- SafeAppendString("(", out, out_size);
-
- if (g_symbolize_open_object_file_callback) {
- object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
- base_address, out + 1,
- out_size - 1);
- } else {
- object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
- base_address,
- out + 1,
- out_size - 1);
- }
-
- // Check whether a file name was returned.
- if (object_fd < 0) {
- if (out[1]) {
- // The object file containing PC was determined successfully however the
- // object file was not opened successfully. This is still considered
- // success because the object file name and offset are known and tools
- // like asan_symbolize.py can be used for the symbolization.
- out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
- SafeAppendString("+0x", out, out_size);
- SafeAppendHexNumber(pc0 - base_address, out, out_size);
- SafeAppendString(")", out, out_size);
- return true;
- }
- // Failed to determine the object file containing PC. Bail out.
- return false;
- }
- FileDescriptor wrapped_object_fd(object_fd);
- int elf_type = FileGetElfType(wrapped_object_fd.get());
- if (elf_type == -1) {
- return false;
- }
- if (g_symbolize_callback) {
- // Run the call back if it's installed.
- // Note: relocation (and much of the rest of this code) will be
- // wrong for prelinked shared libraries and PIE executables.
- uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
- int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
- pc, out, out_size,
- relocation);
- if (num_bytes_written > 0) {
- out += num_bytes_written;
- out_size -= num_bytes_written;
- }
- }
- if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
- out, out_size, start_address)) {
- return false;
- }
-
- // Symbolization succeeded. Now we try to demangle the symbol.
- DemangleInplace(out, out_size);
- return true;
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
-
-#include <dlfcn.h>
-#include <string.h>
-
-_START_GOOGLE_NAMESPACE_
-
-static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
- int out_size) {
- Dl_info info;
- if (dladdr(pc, &info)) {
- if ((int)strlen(info.dli_sname) < out_size) {
- strcpy(out, info.dli_sname);
- // Symbolization succeeded. Now we try to demangle the symbol.
- DemangleInplace(out, out_size);
- return true;
- }
- }
- return false;
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#else
-# error BUG: HAVE_SYMBOLIZE was wrongly set
-#endif
-
-_START_GOOGLE_NAMESPACE_
-
-bool Symbolize(void *pc, char *out, int out_size) {
- SAFE_ASSERT(out_size >= 0);
- return SymbolizeAndDemangle(pc, out, out_size);
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#else /* HAVE_SYMBOLIZE */
-
-#include <assert.h>
-
-#include "config.h"
-
-_START_GOOGLE_NAMESPACE_
-
-// TODO: Support other environments.
-bool Symbolize(void *pc, char *out, int out_size) {
- assert(0);
- return false;
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#endif
diff --git a/extern/libmv/third_party/glog/src/utilities.cc b/extern/libmv/third_party/glog/src/utilities.cc
deleted file mode 100644
index 1e8836d243f..00000000000
--- a/extern/libmv/third_party/glog/src/utilities.cc
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright (c) 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Shinichiro Hamaji
-
-#include "utilities.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <signal.h>
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#include <time.h>
-#if defined(HAVE_SYSCALL_H)
-#include <syscall.h> // for syscall()
-#elif defined(HAVE_SYS_SYSCALL_H)
-#include <sys/syscall.h> // for syscall()
-#endif
-#ifdef HAVE_SYSLOG_H
-# include <syslog.h>
-#endif
-
-#include "base/googleinit.h"
-
-using std::string;
-
-_START_GOOGLE_NAMESPACE_
-
-static const char* g_program_invocation_short_name = NULL;
-static pthread_t g_main_thread_id;
-
-_END_GOOGLE_NAMESPACE_
-
-// The following APIs are all internal.
-#ifdef HAVE_STACKTRACE
-
-#include "stacktrace.h"
-#include "symbolize.h"
-#include "base/commandlineflags.h"
-
-GLOG_DEFINE_bool(symbolize_stacktrace, true,
- "Symbolize the stack trace in the tombstone");
-
-_START_GOOGLE_NAMESPACE_
-
-typedef void DebugWriter(const char*, void*);
-
-// The %p field width for printf() functions is two characters per byte.
-// For some environments, add two extra bytes for the leading "0x".
-static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
-
-static void DebugWriteToStderr(const char* data, void *) {
- // This one is signal-safe.
- if (write(STDERR_FILENO, data, strlen(data)) < 0) {
- // Ignore errors.
- }
-}
-
-static void DebugWriteToString(const char* data, void *arg) {
- reinterpret_cast<string*>(arg)->append(data);
-}
-
-#ifdef HAVE_SYMBOLIZE
-// Print a program counter and its symbol name.
-static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
- const char * const prefix) {
- char tmp[1024];
- const char *symbol = "(unknown)";
- // Symbolizes the previous address of pc because pc may be in the
- // next function. The overrun happens when the function ends with
- // a call to a function annotated noreturn (e.g. CHECK).
- if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
- symbol = tmp;
- }
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
- prefix, kPrintfPointerFieldWidth, pc, symbol);
- writerfn(buf, arg);
-}
-#endif
-
-static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
- const char * const prefix) {
- char buf[100];
- snprintf(buf, sizeof(buf), "%s@ %*p\n",
- prefix, kPrintfPointerFieldWidth, pc);
- writerfn(buf, arg);
-}
-
-// Dump current stack trace as directed by writerfn
-static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
- // Print stack trace
- void* stack[32];
- int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
- for (int i = 0; i < depth; i++) {
-#if defined(HAVE_SYMBOLIZE)
- if (FLAGS_symbolize_stacktrace) {
- DumpPCAndSymbol(writerfn, arg, stack[i], " ");
- } else {
- DumpPC(writerfn, arg, stack[i], " ");
- }
-#else
- DumpPC(writerfn, arg, stack[i], " ");
-#endif
- }
-}
-
-static void DumpStackTraceAndExit() {
- DumpStackTrace(1, DebugWriteToStderr, NULL);
-
- // TOOD(hamaji): Use signal instead of sigaction?
-#ifdef HAVE_SIGACTION
- // Set the default signal handler for SIGABRT, to avoid invoking our
- // own signal handler installed by InstallFailedSignalHandler().
- struct sigaction sig_action;
- memset(&sig_action, 0, sizeof(sig_action));
- sigemptyset(&sig_action.sa_mask);
- sig_action.sa_handler = SIG_DFL;
- sigaction(SIGABRT, &sig_action, NULL);
-#endif // HAVE_SIGACTION
-
- abort();
-}
-
-_END_GOOGLE_NAMESPACE_
-
-#endif // HAVE_STACKTRACE
-
-_START_GOOGLE_NAMESPACE_
-
-namespace glog_internal_namespace_ {
-
-const char* ProgramInvocationShortName() {
- if (g_program_invocation_short_name != NULL) {
- return g_program_invocation_short_name;
- } else {
- // TODO(hamaji): Use /proc/self/cmdline and so?
- return "UNKNOWN";
- }
-}
-
-bool IsGoogleLoggingInitialized() {
- return g_program_invocation_short_name != NULL;
-}
-
-bool is_default_thread() {
- if (g_program_invocation_short_name == NULL) {
- // InitGoogleLogging() not yet called, so unlikely to be in a different
- // thread
- return true;
- } else {
- return pthread_equal(pthread_self(), g_main_thread_id);
- }
-}
-
-#ifdef OS_WINDOWS
-struct timeval {
- long tv_sec, tv_usec;
-};
-
-// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
-// See COPYING for copyright information.
-static int gettimeofday(struct timeval *tv, void* tz) {
-#define EPOCHFILETIME (116444736000000000ULL)
- FILETIME ft;
- LARGE_INTEGER li;
- uint64 tt;
-
- GetSystemTimeAsFileTime(&ft);
- li.LowPart = ft.dwLowDateTime;
- li.HighPart = ft.dwHighDateTime;
- tt = (li.QuadPart - EPOCHFILETIME) / 10;
- tv->tv_sec = tt / 1000000;
- tv->tv_usec = tt % 1000000;
-
- return 0;
-}
-#endif
-
-int64 CycleClock_Now() {
- // TODO(hamaji): temporary impementation - it might be too slow.
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
-}
-
-int64 UsecToCycles(int64 usec) {
- return usec;
-}
-
-WallTime WallTime_Now() {
- // Now, cycle clock is retuning microseconds since the epoch.
- return CycleClock_Now() * 0.000001;
-}
-
-static int32 g_main_thread_pid = getpid();
-int32 GetMainThreadPid() {
- return g_main_thread_pid;
-}
-
-bool PidHasChanged() {
- int32 pid = getpid();
- if (g_main_thread_pid == pid) {
- return false;
- }
- g_main_thread_pid = pid;
- return true;
-}
-
-pid_t GetTID() {
- // On Linux and MacOSX, we try to use gettid().
-#if defined OS_LINUX || defined OS_MACOSX
-#ifndef __NR_gettid
-#ifdef OS_MACOSX
-#define __NR_gettid SYS_gettid
-#elif ! defined __i386__
-#error "Must define __NR_gettid for non-x86 platforms"
-#else
-#define __NR_gettid 224
-#endif
-#endif
- static bool lacks_gettid = false;
- if (!lacks_gettid) {
- pid_t tid = syscall(__NR_gettid);
- if (tid != -1) {
- return tid;
- }
- // Technically, this variable has to be volatile, but there is a small
- // performance penalty in accessing volatile variables and there should
- // not be any serious adverse effect if a thread does not immediately see
- // the value change to "true".
- lacks_gettid = true;
- }
-#endif // OS_LINUX || OS_MACOSX
-
- // If gettid() could not be used, we use one of the following.
-#if defined OS_LINUX
- return getpid(); // Linux: getpid returns thread ID when gettid is absent
-#elif defined OS_WINDOWS || defined OS_CYGWIN
- return GetCurrentThreadId();
-#else
- // If none of the techniques above worked, we use pthread_self().
- return (pid_t)(uintptr_t)pthread_self();
-#endif
-}
-
-const char* const_basename(const char* filepath) {
- const char* base = strrchr(filepath, '/');
-#ifdef OS_WINDOWS // Look for either path separator in Windows
- if (!base)
- base = strrchr(filepath, '\\');
-#endif
- return base ? (base+1) : filepath;
-}
-
-static string g_my_user_name;
-const string& MyUserName() {
- return g_my_user_name;
-}
-static void MyUserNameInitializer() {
- // TODO(hamaji): Probably this is not portable.
-#if defined(OS_WINDOWS)
- const char* user = getenv("USERNAME");
-#else
- const char* user = getenv("USER");
-#endif
- if (user != NULL) {
- g_my_user_name = user;
- } else {
- g_my_user_name = "invalid-user";
- }
-}
-REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
-
-#ifdef HAVE_STACKTRACE
-void DumpStackTraceToString(string* stacktrace) {
- DumpStackTrace(1, DebugWriteToString, stacktrace);
-}
-#endif
-
-// We use an atomic operation to prevent problems with calling CrashReason
-// from inside the Mutex implementation (potentially through RAW_CHECK).
-static const CrashReason* g_reason = 0;
-
-void SetCrashReason(const CrashReason* r) {
- sync_val_compare_and_swap(&g_reason,
- reinterpret_cast<const CrashReason*>(0),
- r);
-}
-
-void InitGoogleLoggingUtilities(const char* argv0) {
- CHECK(!IsGoogleLoggingInitialized())
- << "You called InitGoogleLogging() twice!";
- const char* slash = strrchr(argv0, '/');
-#ifdef OS_WINDOWS
- if (!slash) slash = strrchr(argv0, '\\');
-#endif
- g_program_invocation_short_name = slash ? slash + 1 : argv0;
- g_main_thread_id = pthread_self();
-
-#ifdef HAVE_STACKTRACE
- InstallFailureFunction(&DumpStackTraceAndExit);
-#endif
-}
-
-void ShutdownGoogleLoggingUtilities() {
- CHECK(IsGoogleLoggingInitialized())
- << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
- g_program_invocation_short_name = NULL;
-#ifdef HAVE_SYSLOG_H
- closelog();
-#endif
-}
-
-} // namespace glog_internal_namespace_
-
-_END_GOOGLE_NAMESPACE_
-
-// Make an implementation of stacktrace compiled.
-#ifdef STACKTRACE_H
-# include STACKTRACE_H
-#endif
diff --git a/extern/libmv/third_party/glog/src/vlog_is_on.cc b/extern/libmv/third_party/glog/src/vlog_is_on.cc
deleted file mode 100644
index cd7fc19bca8..00000000000
--- a/extern/libmv/third_party/glog/src/vlog_is_on.cc
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright (c) 1999, 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Ray Sidney and many others
-//
-// Broken out from logging.cc by Soren Lassen
-// logging_unittest.cc covers the functionality herein
-
-#include "utilities.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <cstdio>
-#include <string>
-#include "base/commandlineflags.h"
-#include "glog/logging.h"
-#include "glog/raw_logging.h"
-#include "base/googleinit.h"
-
-// glog doesn't have annotation
-#define ANNOTATE_BENIGN_RACE(address, description)
-
-using std::string;
-
-GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
-" Overridable by --vmodule.");
-
-GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
-" Argument is a comma-separated list of <module name>=<log level>."
-" <module name> is a glob pattern, matched against the filename base"
-" (that is, name ignoring .cc/.h./-inl.h)."
-" <log level> overrides any value given by --v.");
-
-_START_GOOGLE_NAMESPACE_
-
-namespace glog_internal_namespace_ {
-
-namespace {
-
-// Implementation of fnmatch that does not need 0-termination
-// of arguments and does not allocate any memory,
-// but we only support "*" and "?" wildcards, not the "[...]" patterns.
-// It's not a static function for the unittest.
-GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
- size_t patt_len,
- const char* str,
- size_t str_len) {
- size_t p = 0;
- size_t s = 0;
- while (1) {
- if (p == patt_len && s == str_len) return true;
- if (p == patt_len) return false;
- if (s == str_len) return p+1 == patt_len && pattern[p] == '*';
- if (pattern[p] == str[s] || pattern[p] == '?') {
- p += 1;
- s += 1;
- continue;
- }
- if (pattern[p] == '*') {
- if (p+1 == patt_len) return true;
- do {
- if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
- return true;
- }
- s += 1;
- } while (s != str_len);
- return false;
- }
- return false;
- }
-}
-
-} // namespace
-
-} // namespace glog_internal_namespace_
-
-using glog_internal_namespace_::SafeFNMatch_;
-
-int32 kLogSiteUninitialized = 1000;
-
-// List of per-module log levels from FLAGS_vmodule.
-// Once created each element is never deleted/modified
-// except for the vlog_level: other threads will read VModuleInfo blobs
-// w/o locks and we'll store pointers to vlog_level at VLOG locations
-// that will never go away.
-// We can't use an STL struct here as we wouldn't know
-// when it's safe to delete/update it: other threads need to use it w/o locks.
-struct VModuleInfo {
- string module_pattern;
- mutable int32 vlog_level; // Conceptually this is an AtomicWord, but it's
- // too much work to use AtomicWord type here
- // w/o much actual benefit.
- const VModuleInfo* next;
-};
-
-// This protects the following global variables.
-static Mutex vmodule_lock;
-// Pointer to head of the VModuleInfo list.
-// It's a map from module pattern to logging level for those module(s).
-static VModuleInfo* vmodule_list = 0;
-// Boolean initialization flag.
-static bool inited_vmodule = false;
-
-// L >= vmodule_lock.
-static void VLOG2Initializer() {
- vmodule_lock.AssertHeld();
- // Can now parse --vmodule flag and initialize mapping of module-specific
- // logging levels.
- inited_vmodule = false;
- const char* vmodule = FLAGS_vmodule.c_str();
- const char* sep;
- VModuleInfo* head = NULL;
- VModuleInfo* tail = NULL;
- while ((sep = strchr(vmodule, '=')) != NULL) {
- string pattern(vmodule, sep - vmodule);
- int module_level;
- if (sscanf(sep, "=%d", &module_level) == 1) {
- VModuleInfo* info = new VModuleInfo;
- info->module_pattern = pattern;
- info->vlog_level = module_level;
- if (head) tail->next = info;
- else head = info;
- tail = info;
- }
- // Skip past this entry
- vmodule = strchr(sep, ',');
- if (vmodule == NULL) break;
- vmodule++; // Skip past ","
- }
- if (head) { // Put them into the list at the head:
- tail->next = vmodule_list;
- vmodule_list = head;
- }
- inited_vmodule = true;
-}
-
-// This can be called very early, so we use SpinLock and RAW_VLOG here.
-int SetVLOGLevel(const char* module_pattern, int log_level) {
- int result = FLAGS_v;
- int const pattern_len = strlen(module_pattern);
- bool found = false;
- MutexLock l(&vmodule_lock); // protect whole read-modify-write
- for (const VModuleInfo* info = vmodule_list;
- info != NULL; info = info->next) {
- if (info->module_pattern == module_pattern) {
- if (!found) {
- result = info->vlog_level;
- found = true;
- }
- info->vlog_level = log_level;
- } else if (!found &&
- SafeFNMatch_(info->module_pattern.c_str(),
- info->module_pattern.size(),
- module_pattern, pattern_len)) {
- result = info->vlog_level;
- found = true;
- }
- }
- if (!found) {
- VModuleInfo* info = new VModuleInfo;
- info->module_pattern = module_pattern;
- info->vlog_level = log_level;
- info->next = vmodule_list;
- vmodule_list = info;
- }
- RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
- return result;
-}
-
-// NOTE: Individual VLOG statements cache the integer log level pointers.
-// NOTE: This function must not allocate memory or require any locks.
-bool InitVLOG3__(int32** site_flag, int32* site_default,
- const char* fname, int32 verbose_level) {
- MutexLock l(&vmodule_lock);
- bool read_vmodule_flag = inited_vmodule;
- if (!read_vmodule_flag) {
- VLOG2Initializer();
- }
-
- // protect the errno global in case someone writes:
- // VLOG(..) << "The last error was " << strerror(errno)
- int old_errno = errno;
-
- // site_default normally points to FLAGS_v
- int32* site_flag_value = site_default;
-
- // Get basename for file
- const char* base = strrchr(fname, '/');
- base = base ? (base+1) : fname;
- const char* base_end = strchr(base, '.');
- size_t base_length = base_end ? size_t(base_end - base) : strlen(base);
-
- // Trim out trailing "-inl" if any
- if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
- base_length -= 4;
- }
-
- // TODO: Trim out _unittest suffix? Perhaps it is better to have
- // the extra control and just leave it there.
-
- // find target in vector of modules, replace site_flag_value with
- // a module-specific verbose level, if any.
- for (const VModuleInfo* info = vmodule_list;
- info != NULL; info = info->next) {
- if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
- base, base_length)) {
- site_flag_value = &info->vlog_level;
- // value at info->vlog_level is now what controls
- // the VLOG at the caller site forever
- break;
- }
- }
-
- // Cache the vlog value pointer if --vmodule flag has been parsed.
- ANNOTATE_BENIGN_RACE(site_flag,
- "*site_flag may be written by several threads,"
- " but the value will be the same");
- if (read_vmodule_flag) *site_flag = site_flag_value;
-
- // restore the errno in case something recoverable went wrong during
- // the initialization of the VLOG mechanism (see above note "protect the..")
- errno = old_errno;
- return *site_flag_value >= verbose_level;
-}
-
-_END_GOOGLE_NAMESPACE_
diff --git a/extern/libmv/third_party/glog/src/windows/config.h b/extern/libmv/third_party/glog/src/windows/config.h
deleted file mode 100644
index 9fb3cc564d5..00000000000
--- a/extern/libmv/third_party/glog/src/windows/config.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* src/config.h.in. Generated from configure.ac by autoheader. */
-
-/* define if you have google gflags library */
-#define HAVE_LIB_GFLAGS 1
-
-/* Namespace for Google classes */
-#define GOOGLE_NAMESPACE google
-
-/* Stops putting the code inside the Google namespace */
-#define _END_GOOGLE_NAMESPACE_ }
-
-/* Puts following code inside the Google namespace */
-#define _START_GOOGLE_NAMESPACE_ namespace google {
-
-/* Always the empty-string on non-windows systems. On windows, should be
- "__declspec(dllexport)". This way, when we compile the dll, we export our
- functions/classes. It's safe to define this here because config.h is only
- used internally, to compile the DLL, and every DLL source file #includes
- "config.h" before anything else. */
-#ifndef GOOGLE_GLOG_DLL_DECL
-# define GOOGLE_GLOG_IS_A_DLL 1 /* not set if you're statically linking */
-# define GOOGLE_GLOG_DLL_DECL __declspec(dllexport)
-# define GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS __declspec(dllimport)
-#endif
diff --git a/extern/libmv/third_party/glog/src/windows/glog/logging.h b/extern/libmv/third_party/glog/src/windows/glog/logging.h
deleted file mode 100644
index 6e9c9224f92..00000000000
--- a/extern/libmv/third_party/glog/src/windows/glog/logging.h
+++ /dev/null
@@ -1,1616 +0,0 @@
-// This file is automatically generated from src/glog/logging.h.in
-// using src/windows/preprocess.sh.
-// DO NOT EDIT!
-
-// Copyright (c) 1999, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: Ray Sidney
-//
-// This file contains #include information about logging-related stuff.
-// Pretty much everybody needs to #include this file so that they can
-// log various happenings.
-//
-#ifndef _LOGGING_H_
-#define _LOGGING_H_
-
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <iosfwd>
-#include <ostream>
-#include <sstream>
-#include <string>
-#if 0
-# include <unistd.h>
-#endif
-#include <vector>
-
-// Annoying stuff for windows -- makes sure clients can import these functions
-#ifndef GOOGLE_GLOG_DLL_DECL
-# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
-# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
-# else
-# define GOOGLE_GLOG_DLL_DECL
-# endif
-#endif
-#if defined(_MSC_VER)
-#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
- __pragma(warning(disable:n))
-#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
-#else
-#define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
-#define GLOG_MSVC_POP_WARNING()
-#endif
-
-// We care a lot about number of bits things take up. Unfortunately,
-// systems define their bit-specific ints in a lot of different ways.
-// We use our own way, and have a typedef to get there.
-// Note: these commands below may look like "#if 1" or "#if 0", but
-// that's because they were constructed that way at ./configure time.
-// Look at logging.h.in to see how they're calculated (based on your config).
-#if 0
-#include <stdint.h> // the normal place uint16_t is defined
-#endif
-#if 0
-#include <sys/types.h> // the normal place u_int16_t is defined
-#endif
-#if 0
-#include <inttypes.h> // a third place for uint16_t or u_int16_t
-#endif
-
-#if 1
-#include <gflags/gflags.h>
-#endif
-
-#ifdef __MINGW32__
-# include <stdlib.h>
-# include <unistd.h>
-# include <stdint.h> // the normal place uint16_t is defined
-# include <sys/types.h> // the normal place u_int16_t is defined
-# include <inttypes.h> // a third place for uint16_t or u_int16_t
-# define _exit(x) exit(x)
-#endif
-
-namespace google {
-
-#if defined(__MINGW32__) // the C99 format
-typedef int32_t int32;
-typedef uint32_t uint32;
-typedef int64_t int64;
-typedef uint64_t uint64;
-#elif 0 // the BSD format
-typedef int32_t int32;
-typedef u_int32_t uint32;
-typedef int64_t int64;
-typedef u_int64_t uint64;
-#elif defined(_MSC_VER) // the windows (vc7) format
-typedef __int32 int32;
-typedef unsigned __int32 uint32;
-typedef __int64 int64;
-typedef unsigned __int64 uint64;
-#else
-#error Do not know how to define a 32-bit integer quantity on your system
-#endif
-
-}
-
-// The global value of GOOGLE_STRIP_LOG. All the messages logged to
-// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed.
-// If it can be determined at compile time that the message will not be
-// printed, the statement will be compiled out.
-//
-// Example: to strip out all INFO and WARNING messages, use the value
-// of 2 below. To make an exception for WARNING messages from a single
-// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including
-// base/logging.h
-#ifndef GOOGLE_STRIP_LOG
-#define GOOGLE_STRIP_LOG 0
-#endif
-
-// GCC can be told that a certain branch is not likely to be taken (for
-// instance, a CHECK failure), and use that information in static analysis.
-// Giving it this information can help it optimize for the common case in
-// the absence of better information (ie. -fprofile-arcs).
-//
-#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN
-#if 0
-#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0))
-#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0))
-#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
-#else
-#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x
-#define GOOGLE_PREDICT_FALSE(x) x
-#define GOOGLE_PREDICT_TRUE(x) x
-#endif
-#endif
-
-// Make a bunch of macros for logging. The way to log things is to stream
-// things to LOG(<a particular severity level>). E.g.,
-//
-// LOG(INFO) << "Found " << num_cookies << " cookies";
-//
-// You can capture log messages in a string, rather than reporting them
-// immediately:
-//
-// vector<string> errors;
-// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num;
-//
-// This pushes back the new error onto 'errors'; if given a NULL pointer,
-// it reports the error via LOG(ERROR).
-//
-// You can also do conditional logging:
-//
-// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
-//
-// You can also do occasional logging (log every n'th occurrence of an
-// event):
-//
-// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
-//
-// The above will cause log messages to be output on the 1st, 11th, 21st, ...
-// times it is executed. Note that the special google::COUNTER value is used
-// to identify which repetition is happening.
-//
-// You can also do occasional conditional logging (log every n'th
-// occurrence of an event, when condition is satisfied):
-//
-// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
-// << "th big cookie";
-//
-// You can log messages the first N times your code executes a line. E.g.
-//
-// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
-//
-// Outputs log messages for the first 20 times it is executed.
-//
-// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available.
-// These log to syslog as well as to the normal logs. If you use these at
-// all, you need to be aware that syslog can drastically reduce performance,
-// especially if it is configured for remote logging! Don't use these
-// unless you fully understand this and have a concrete need to use them.
-// Even then, try to minimize your use of them.
-//
-// There are also "debug mode" logging macros like the ones above:
-//
-// DLOG(INFO) << "Found cookies";
-//
-// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
-//
-// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
-//
-// All "debug mode" logging is compiled away to nothing for non-debug mode
-// compiles.
-//
-// We also have
-//
-// LOG_ASSERT(assertion);
-// DLOG_ASSERT(assertion);
-//
-// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
-//
-// There are "verbose level" logging macros. They look like
-//
-// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
-// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
-//
-// These always log at the INFO log level (when they log at all).
-// The verbose logging can also be turned on module-by-module. For instance,
-// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0
-// will cause:
-// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc}
-// b. VLOG(1) and lower messages to be printed from file.{h,cc}
-// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs"
-// d. VLOG(0) and lower messages to be printed from elsewhere
-//
-// The wildcarding functionality shown by (c) supports both '*' (match
-// 0 or more characters) and '?' (match any single character) wildcards.
-//
-// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
-//
-// if (VLOG_IS_ON(2)) {
-// // do some logging preparation and logging
-// // that can't be accomplished with just VLOG(2) << ...;
-// }
-//
-// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level"
-// condition macros for sample cases, when some extra computation and
-// preparation for logs is not needed.
-// VLOG_IF(1, (size > 1024))
-// << "I'm printed when size is more than 1024 and when you run the "
-// "program with --v=1 or more";
-// VLOG_EVERY_N(1, 10)
-// << "I'm printed every 10th occurrence, and when you run the program "
-// "with --v=1 or more. Present occurence is " << google::COUNTER;
-// VLOG_IF_EVERY_N(1, (size > 1024), 10)
-// << "I'm printed on every 10th occurence of case when size is more "
-// " than 1024, when you run the program with --v=1 or more. ";
-// "Present occurence is " << google::COUNTER;
-//
-// The supported severity levels for macros that allow you to specify one
-// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
-// Note that messages of a given severity are logged not only in the
-// logfile for that severity, but also in all logfiles of lower severity.
-// E.g., a message of severity FATAL will be logged to the logfiles of
-// severity FATAL, ERROR, WARNING, and INFO.
-//
-// There is also the special severity of DFATAL, which logs FATAL in
-// debug mode, ERROR in normal mode.
-//
-// Very important: logging a message at the FATAL severity level causes
-// the program to terminate (after the message is logged).
-//
-// Unless otherwise specified, logs will be written to the filename
-// "<program name>.<hostname>.<user name>.log.<severity level>.", followed
-// by the date, time, and pid (you can't prevent the date, time, and pid
-// from being in the filename).
-//
-// The logging code takes two flags:
-// --v=# set the verbose level
-// --logtostderr log all the messages to stderr instead of to logfiles
-
-// LOG LINE PREFIX FORMAT
-//
-// Log lines have this form:
-//
-// Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
-//
-// where the fields are defined as follows:
-//
-// L A single character, representing the log level
-// (eg 'I' for INFO)
-// mm The month (zero padded; ie May is '05')
-// dd The day (zero padded)
-// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
-// threadid The space-padded thread ID as returned by GetTID()
-// (this matches the PID on Linux)
-// file The file name
-// line The line number
-// msg The user-supplied message
-//
-// Example:
-//
-// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
-// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
-//
-// NOTE: although the microseconds are useful for comparing events on
-// a single machine, clocks on different machines may not be well
-// synchronized. Hence, use caution when comparing the low bits of
-// timestamps from different machines.
-
-#ifndef DECLARE_VARIABLE
-#define MUST_UNDEF_GFLAGS_DECLARE_MACROS
-#define DECLARE_VARIABLE(type, shorttype, name, tn) \
- namespace fL##shorttype { \
- extern GOOGLE_GLOG_DLL_DECL type FLAGS_##name; \
- } \
- using fL##shorttype::FLAGS_##name
-
-// bool specialization
-#define DECLARE_bool(name) \
- DECLARE_VARIABLE(bool, B, name, bool)
-
-// int32 specialization
-#define DECLARE_int32(name) \
- DECLARE_VARIABLE(google::int32, I, name, int32)
-
-// Special case for string, because we have to specify the namespace
-// std::string, which doesn't play nicely with our FLAG__namespace hackery.
-#define DECLARE_string(name) \
- namespace fLS { \
- extern GOOGLE_GLOG_DLL_DECL std::string& FLAGS_##name; \
- } \
- using fLS::FLAGS_##name
-#endif
-
-// Set whether log messages go to stderr instead of logfiles
-DECLARE_bool(logtostderr);
-
-// Set whether log messages go to stderr in addition to logfiles.
-DECLARE_bool(alsologtostderr);
-
-// Set color messages logged to stderr (if supported by terminal).
-DECLARE_bool(colorlogtostderr);
-
-// Log messages at a level >= this flag are automatically sent to
-// stderr in addition to log files.
-DECLARE_int32(stderrthreshold);
-
-// Set whether the log prefix should be prepended to each line of output.
-DECLARE_bool(log_prefix);
-
-// Log messages at a level <= this flag are buffered.
-// Log messages at a higher level are flushed immediately.
-DECLARE_int32(logbuflevel);
-
-// Sets the maximum number of seconds which logs may be buffered for.
-DECLARE_int32(logbufsecs);
-
-// Log suppression level: messages logged at a lower level than this
-// are suppressed.
-DECLARE_int32(minloglevel);
-
-// If specified, logfiles are written into this directory instead of the
-// default logging directory.
-DECLARE_string(log_dir);
-
-// Sets the path of the directory into which to put additional links
-// to the log files.
-DECLARE_string(log_link);
-
-DECLARE_int32(v); // in vlog_is_on.cc
-
-// Sets the maximum log file size (in MB).
-DECLARE_int32(max_log_size);
-
-// Sets whether to avoid logging to the disk if the disk is full.
-DECLARE_bool(stop_logging_if_full_disk);
-
-#ifdef MUST_UNDEF_GFLAGS_DECLARE_MACROS
-#undef MUST_UNDEF_GFLAGS_DECLARE_MACROS
-#undef DECLARE_VARIABLE
-#undef DECLARE_bool
-#undef DECLARE_int32
-#undef DECLARE_string
-#endif
-
-// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for
-// security reasons. See LOG(severtiy) below.
-
-// A few definitions of macros that don't generate much code. Since
-// LOG(INFO) and its ilk are used all over our code, it's
-// better to have compact code for these operations.
-
-#if GOOGLE_STRIP_LOG == 0
-#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \
- __FILE__, __LINE__)
-#define LOG_TO_STRING_INFO(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_INFO, message)
-#else
-#define COMPACT_GOOGLE_LOG_INFO google::NullStream()
-#define LOG_TO_STRING_INFO(message) google::NullStream()
-#endif
-
-#if GOOGLE_STRIP_LOG <= 1
-#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_WARNING)
-#define LOG_TO_STRING_WARNING(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_WARNING, message)
-#else
-#define COMPACT_GOOGLE_LOG_WARNING google::NullStream()
-#define LOG_TO_STRING_WARNING(message) google::NullStream()
-#endif
-
-#if GOOGLE_STRIP_LOG <= 2
-#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ERROR)
-#define LOG_TO_STRING_ERROR(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ERROR, message)
-#else
-#define COMPACT_GOOGLE_LOG_ERROR google::NullStream()
-#define LOG_TO_STRING_ERROR(message) google::NullStream()
-#endif
-
-#if GOOGLE_STRIP_LOG <= 3
-#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \
- __FILE__, __LINE__)
-#define LOG_TO_STRING_FATAL(message) google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_FATAL, message)
-#else
-#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal()
-#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal()
-#endif
-
-// For DFATAL, we want to use LogMessage (as opposed to
-// LogMessageFatal), to be consistent with the original behavior.
-#ifdef NDEBUG
-#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
-#elif GOOGLE_STRIP_LOG <= 3
-#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_FATAL)
-#else
-#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal()
-#endif
-
-#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog)
-#define SYSLOG_INFO(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_WARNING(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_WARNING(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_ERROR(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_ERROR(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_FATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_FATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-#define GOOGLE_LOG_DFATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
- &google::LogMessage::SendToLog)
-#define SYSLOG_DFATAL(counter) \
- google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \
- &google::LogMessage::SendToSyslogAndLog)
-
-#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
-// A very useful logging macro to log windows errors:
-#define LOG_SYSRESULT(result) \
- if (FAILED(HRESULT_FROM_WIN32(result))) { \
- LPSTR message = NULL; \
- LPSTR msg = reinterpret_cast<LPSTR>(&message); \
- DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \
- FORMAT_MESSAGE_FROM_SYSTEM, \
- 0, result, 0, msg, 100, NULL); \
- if (message_length > 0) { \
- google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \
- &google::LogMessage::SendToLog).stream() \
- << reinterpret_cast<const char*>(message); \
- LocalFree(message); \
- } \
- }
-#endif
-
-// We use the preprocessor's merging operator, "##", so that, e.g.,
-// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny
-// subtle difference between ostream member streaming functions (e.g.,
-// ostream::operator<<(int) and ostream non-member streaming functions
-// (e.g., ::operator<<(ostream&, string&): it turns out that it's
-// impossible to stream something like a string directly to an unnamed
-// ostream. We employ a neat hack by calling the stream() member
-// function of LogMessage which seems to avoid the problem.
-#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
-#define SYSLOG(severity) SYSLOG_ ## severity(0).stream()
-
-namespace google {
-
-// They need the definitions of integer types.
-#include "glog/log_severity.h"
-#include "glog/vlog_is_on.h"
-
-// Initialize google's logging library. You will see the program name
-// specified by argv0 in log outputs.
-GOOGLE_GLOG_DLL_DECL void InitGoogleLogging(const char* argv0);
-
-// Shutdown google's logging library.
-GOOGLE_GLOG_DLL_DECL void ShutdownGoogleLogging();
-
-// Install a function which will be called after LOG(FATAL).
-GOOGLE_GLOG_DLL_DECL void InstallFailureFunction(void (*fail_func)());
-
-class LogSink; // defined below
-
-// If a non-NULL sink pointer is given, we push this message to that sink.
-// For LOG_TO_SINK we then do normal LOG(severity) logging as well.
-// This is useful for capturing messages and passing/storing them
-// somewhere more specific than the global log of the process.
-// Argument types:
-// LogSink* sink;
-// LogSeverity severity;
-// The cast is to disambiguate NULL arguments.
-#define LOG_TO_SINK(sink, severity) \
- google::LogMessage( \
- __FILE__, __LINE__, \
- google::GLOG_ ## severity, \
- static_cast<google::LogSink*>(sink), true).stream()
-#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \
- google::LogMessage( \
- __FILE__, __LINE__, \
- google::GLOG_ ## severity, \
- static_cast<google::LogSink*>(sink), false).stream()
-
-// If a non-NULL string pointer is given, we write this message to that string.
-// We then do normal LOG(severity) logging as well.
-// This is useful for capturing messages and storing them somewhere more
-// specific than the global log of the process.
-// Argument types:
-// string* message;
-// LogSeverity severity;
-// The cast is to disambiguate NULL arguments.
-// NOTE: LOG(severity) expands to LogMessage().stream() for the specified
-// severity.
-#define LOG_TO_STRING(severity, message) \
- LOG_TO_STRING_##severity(static_cast<string*>(message)).stream()
-
-// If a non-NULL pointer is given, we push the message onto the end
-// of a vector of strings; otherwise, we report it with LOG(severity).
-// This is handy for capturing messages and perhaps passing them back
-// to the caller, rather than reporting them immediately.
-// Argument types:
-// LogSeverity severity;
-// vector<string> *outvec;
-// The cast is to disambiguate NULL arguments.
-#define LOG_STRING(severity, outvec) \
- LOG_TO_STRING_##severity(static_cast<vector<string>*>(outvec)).stream()
-
-#define LOG_IF(severity, condition) \
- !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-#define SYSLOG_IF(severity, condition) \
- !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity)
-
-#define LOG_ASSERT(condition) \
- LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
-#define SYSLOG_ASSERT(condition) \
- SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
-
-// CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
-// compilation mode. Therefore, it is safe to do things like:
-// CHECK(fp->Write(x) == 4)
-#define CHECK(condition) \
- LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
- << "Check failed: " #condition " "
-
-// A container for a string pointer which can be evaluated to a bool -
-// true iff the pointer is NULL.
-struct CheckOpString {
- CheckOpString(std::string* str) : str_(str) { }
- // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
- // so there's no point in cleaning up str_.
- operator bool() const {
- return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL);
- }
- std::string* str_;
-};
-
-// Function is overloaded for integral types to allow static const
-// integrals declared in classes and not defined to be used as arguments to
-// CHECK* macros. It's not encouraged though.
-template <class T>
-inline const T& GetReferenceableValue(const T& t) { return t; }
-inline char GetReferenceableValue(char t) { return t; }
-inline unsigned char GetReferenceableValue(unsigned char t) { return t; }
-inline signed char GetReferenceableValue(signed char t) { return t; }
-inline short GetReferenceableValue(short t) { return t; }
-inline unsigned short GetReferenceableValue(unsigned short t) { return t; }
-inline int GetReferenceableValue(int t) { return t; }
-inline unsigned int GetReferenceableValue(unsigned int t) { return t; }
-inline long GetReferenceableValue(long t) { return t; }
-inline unsigned long GetReferenceableValue(unsigned long t) { return t; }
-inline long long GetReferenceableValue(long long t) { return t; }
-inline unsigned long long GetReferenceableValue(unsigned long long t) {
- return t;
-}
-
-// This is a dummy class to define the following operator.
-struct DummyClassToDefineOperator {};
-
-}
-
-// Define global operator<< to declare using ::operator<<.
-// This declaration will allow use to use CHECK macros for user
-// defined classes which have operator<< (e.g., stl_logging.h).
-inline std::ostream& operator<<(
- std::ostream& out, const google::DummyClassToDefineOperator&) {
- return out;
-}
-
-namespace google {
-
-// This formats a value for a failing CHECK_XX statement. Ordinarily,
-// it uses the definition for operator<<, with a few special cases below.
-template <typename T>
-inline void MakeCheckOpValueString(std::ostream* os, const T& v) {
- (*os) << v;
-}
-
-// Overrides for char types provide readable values for unprintable
-// characters.
-template <> GOOGLE_GLOG_DLL_DECL
-void MakeCheckOpValueString(std::ostream* os, const char& v);
-template <> GOOGLE_GLOG_DLL_DECL
-void MakeCheckOpValueString(std::ostream* os, const signed char& v);
-template <> GOOGLE_GLOG_DLL_DECL
-void MakeCheckOpValueString(std::ostream* os, const unsigned char& v);
-
-// Build the error message string. Specify no inlining for code size.
-template <typename T1, typename T2>
-std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext)
- ;
-
-namespace base {
-namespace internal {
-
-// If "s" is less than base_logging::INFO, returns base_logging::INFO.
-// If "s" is greater than base_logging::FATAL, returns
-// base_logging::ERROR. Otherwise, returns "s".
-LogSeverity NormalizeSeverity(LogSeverity s);
-
-} // namespace internal
-
-// A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX
-// statement. See MakeCheckOpString for sample usage. Other
-// approaches were considered: use of a template method (e.g.,
-// base::BuildCheckOpString(exprtext, base::Print<T1>, &v1,
-// base::Print<T2>, &v2), however this approach has complications
-// related to volatile arguments and function-pointer arguments).
-class GOOGLE_GLOG_DLL_DECL CheckOpMessageBuilder {
- public:
- // Inserts "exprtext" and " (" to the stream.
- explicit CheckOpMessageBuilder(const char *exprtext);
- // Deletes "stream_".
- ~CheckOpMessageBuilder();
- // For inserting the first variable.
- std::ostream* ForVar1() { return stream_; }
- // For inserting the second variable (adds an intermediate " vs. ").
- std::ostream* ForVar2();
- // Get the result (inserts the closing ")").
- std::string* NewString();
-
- private:
- std::ostringstream *stream_;
-};
-
-} // namespace base
-
-template <typename T1, typename T2>
-std::string* MakeCheckOpString(const T1& v1, const T2& v2, const char* exprtext) {
- base::CheckOpMessageBuilder comb(exprtext);
- MakeCheckOpValueString(comb.ForVar1(), v1);
- MakeCheckOpValueString(comb.ForVar2(), v2);
- return comb.NewString();
-}
-
-// Helper functions for CHECK_OP macro.
-// The (int, int) specialization works around the issue that the compiler
-// will not instantiate the template version of the function on values of
-// unnamed enum type - see comment below.
-#define DEFINE_CHECK_OP_IMPL(name, op) \
- template <typename T1, typename T2> \
- inline std::string* name##Impl(const T1& v1, const T2& v2, \
- const char* exprtext) { \
- if (GOOGLE_PREDICT_TRUE(v1 op v2)) return NULL; \
- else return MakeCheckOpString(v1, v2, exprtext); \
- } \
- inline std::string* name##Impl(int v1, int v2, const char* exprtext) { \
- return name##Impl<int, int>(v1, v2, exprtext); \
- }
-
-// We use the full name Check_EQ, Check_NE, etc. in case the file including
-// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
-// This happens if, for example, those are used as token names in a
-// yacc grammar.
-DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)?
-DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead.
-DEFINE_CHECK_OP_IMPL(Check_LE, <=)
-DEFINE_CHECK_OP_IMPL(Check_LT, < )
-DEFINE_CHECK_OP_IMPL(Check_GE, >=)
-DEFINE_CHECK_OP_IMPL(Check_GT, > )
-#undef DEFINE_CHECK_OP_IMPL
-
-// Helper macro for binary operators.
-// Don't use this macro directly in your code, use CHECK_EQ et al below.
-
-#if defined(STATIC_ANALYSIS)
-// Only for static analysis tool to know that it is equivalent to assert
-#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
-#elif !defined(NDEBUG)
-// In debug mode, avoid constructing CheckOpStrings if possible,
-// to reduce the overhead of CHECK statments by 2x.
-// Real DCHECK-heavy tests have seen 1.5x speedups.
-
-// The meaning of "string" might be different between now and
-// when this macro gets invoked (e.g., if someone is experimenting
-// with other string implementations that get defined after this
-// file is included). Save the current meaning now and use it
-// in the macro.
-typedef std::string _Check_string;
-#define CHECK_OP_LOG(name, op, val1, val2, log) \
- while (google::_Check_string* _result = \
- google::Check##name##Impl( \
- google::GetReferenceableValue(val1), \
- google::GetReferenceableValue(val2), \
- #val1 " " #op " " #val2)) \
- log(__FILE__, __LINE__, \
- google::CheckOpString(_result)).stream()
-#else
-// In optimized mode, use CheckOpString to hint to compiler that
-// the while condition is unlikely.
-#define CHECK_OP_LOG(name, op, val1, val2, log) \
- while (google::CheckOpString _result = \
- google::Check##name##Impl( \
- google::GetReferenceableValue(val1), \
- google::GetReferenceableValue(val2), \
- #val1 " " #op " " #val2)) \
- log(__FILE__, __LINE__, _result).stream()
-#endif // STATIC_ANALYSIS, !NDEBUG
-
-#if GOOGLE_STRIP_LOG <= 3
-#define CHECK_OP(name, op, val1, val2) \
- CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal)
-#else
-#define CHECK_OP(name, op, val1, val2) \
- CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal)
-#endif // STRIP_LOG <= 3
-
-// Equality/Inequality checks - compare two values, and log a FATAL message
-// including the two values when the result is not as expected. The values
-// must have operator<<(ostream, ...) defined.
-//
-// You may append to the error message like so:
-// CHECK_NE(1, 2) << ": The world must be ending!";
-//
-// We are very careful to ensure that each argument is evaluated exactly
-// once, and that anything which is legal to pass as a function argument is
-// legal here. In particular, the arguments may be temporary expressions
-// which will end up being destroyed at the end of the apparent statement,
-// for example:
-// CHECK_EQ(string("abc")[1], 'b');
-//
-// WARNING: These don't compile correctly if one of the arguments is a pointer
-// and the other is NULL. To work around this, simply static_cast NULL to the
-// type of the desired pointer.
-
-#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
-#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
-#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
-#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
-#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
-#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
-
-// Check that the input is non NULL. This very useful in constructor
-// initializer lists.
-
-#define CHECK_NOTNULL(val) \
- google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
-
-// Helper functions for string comparisons.
-// To avoid bloat, the definitions are in logging.cc.
-#define DECLARE_CHECK_STROP_IMPL(func, expected) \
- GOOGLE_GLOG_DLL_DECL std::string* Check##func##expected##Impl( \
- const char* s1, const char* s2, const char* names);
-DECLARE_CHECK_STROP_IMPL(strcmp, true)
-DECLARE_CHECK_STROP_IMPL(strcmp, false)
-DECLARE_CHECK_STROP_IMPL(strcasecmp, true)
-DECLARE_CHECK_STROP_IMPL(strcasecmp, false)
-#undef DECLARE_CHECK_STROP_IMPL
-
-// Helper macro for string comparisons.
-// Don't use this macro directly in your code, use CHECK_STREQ et al below.
-#define CHECK_STROP(func, op, expected, s1, s2) \
- while (google::CheckOpString _result = \
- google::Check##func##expected##Impl((s1), (s2), \
- #s1 " " #op " " #s2)) \
- LOG(FATAL) << *_result.str_
-
-
-// String (char*) equality/inequality checks.
-// CASE versions are case-insensitive.
-//
-// Note that "s1" and "s2" may be temporary strings which are destroyed
-// by the compiler at the end of the current "full expression"
-// (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())).
-
-#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2)
-#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2)
-#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2)
-#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2)
-
-#define CHECK_INDEX(I,A) CHECK(I < (sizeof(A)/sizeof(A[0])))
-#define CHECK_BOUND(B,A) CHECK(B <= (sizeof(A)/sizeof(A[0])))
-
-#define CHECK_DOUBLE_EQ(val1, val2) \
- do { \
- CHECK_LE((val1), (val2)+0.000000000000001L); \
- CHECK_GE((val1), (val2)-0.000000000000001L); \
- } while (0)
-
-#define CHECK_NEAR(val1, val2, margin) \
- do { \
- CHECK_LE((val1), (val2)+(margin)); \
- CHECK_GE((val1), (val2)-(margin)); \
- } while (0)
-
-// perror()..googly style!
-//
-// PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and
-// CHECK equivalents with the addition that they postpend a description
-// of the current state of errno to their output lines.
-
-#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream()
-
-#define GOOGLE_PLOG(severity, counter) \
- google::ErrnoLogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, counter, \
- &google::LogMessage::SendToLog)
-
-#define PLOG_IF(severity, condition) \
- !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity)
-
-// A CHECK() macro that postpends errno if the condition is false. E.g.
-//
-// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... }
-#define PCHECK(condition) \
- PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \
- << "Check failed: " #condition " "
-
-// A CHECK() macro that lets you assert the success of a function that
-// returns -1 and sets errno in case of an error. E.g.
-//
-// CHECK_ERR(mkdir(path, 0700));
-//
-// or
-//
-// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename;
-#define CHECK_ERR(invocation) \
-PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \
- << #invocation
-
-// Use macro expansion to create, for each use of LOG_EVERY_N(), static
-// variables with the __LINE__ expansion as part of the variable name.
-#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
-#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base ## line
-
-#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
-#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
-
-#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \
- static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
- ++LOG_OCCURRENCES; \
- if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
- if (LOG_OCCURRENCES_MOD_N == 1) \
- google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \
- static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
- ++LOG_OCCURRENCES; \
- if (condition && \
- ((LOG_OCCURRENCES_MOD_N=(LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \
- google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \
- static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
- ++LOG_OCCURRENCES; \
- if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
- if (LOG_OCCURRENCES_MOD_N == 1) \
- google::ErrnoLogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \
- static int LOG_OCCURRENCES = 0; \
- if (LOG_OCCURRENCES <= n) \
- ++LOG_OCCURRENCES; \
- if (LOG_OCCURRENCES <= n) \
- google::LogMessage( \
- __FILE__, __LINE__, google::GLOG_ ## severity, LOG_OCCURRENCES, \
- &what_to_do).stream()
-
-namespace glog_internal_namespace_ {
-template <bool>
-struct CompileAssert {
-};
-struct CrashReason;
-} // namespace glog_internal_namespace_
-
-#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \
- typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
-#define LOG_EVERY_N(severity, n) \
- GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \
- google::NUM_SEVERITIES, \
- INVALID_REQUESTED_LOG_SEVERITY); \
- SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
-
-#define SYSLOG_EVERY_N(severity, n) \
- SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog)
-
-#define PLOG_EVERY_N(severity, n) \
- SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
-
-#define LOG_FIRST_N(severity, n) \
- SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog)
-
-#define LOG_IF_EVERY_N(severity, condition, n) \
- SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog)
-
-// We want the special COUNTER value available for LOG_EVERY_X()'ed messages
-enum PRIVATE_Counter {COUNTER};
-
-#ifdef GLOG_NO_ABBREVIATED_SEVERITIES
-// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
-// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
-// to keep using this syntax, we define this macro to do the same thing
-// as COMPACT_GOOGLE_LOG_ERROR.
-#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
-#define SYSLOG_0 SYSLOG_ERROR
-#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR
-// Needed for LOG_IS_ON(ERROR).
-const LogSeverity GLOG_0 = GLOG_ERROR;
-#else
-// Users may include windows.h after logging.h without
-// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN.
-// For this case, we cannot detect if ERROR is defined before users
-// actually use ERROR. Let's make an undefined symbol to warn users.
-# define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail
-# define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG
-# define SYSLOG_0 GLOG_ERROR_MSG
-# define LOG_TO_STRING_0 GLOG_ERROR_MSG
-# define GLOG_0 GLOG_ERROR_MSG
-#endif
-
-// Plus some debug-logging macros that get compiled to nothing for production
-
-#ifndef NDEBUG
-
-#define DLOG(severity) LOG(severity)
-#define DVLOG(verboselevel) VLOG(verboselevel)
-#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
-#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
-#define DLOG_IF_EVERY_N(severity, condition, n) \
- LOG_IF_EVERY_N(severity, condition, n)
-#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
-
-// debug-only checking. not executed in NDEBUG mode.
-#define DCHECK(condition) CHECK(condition)
-#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
-#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
-#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
-#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
-#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
-#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
-#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val)
-#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2)
-#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2)
-#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
-#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
-
-#else // NDEBUG
-
-#define DLOG(severity) \
- true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DVLOG(verboselevel) \
- (true || !VLOG_IS_ON(verboselevel)) ?\
- (void) 0 : google::LogMessageVoidify() & LOG(INFO)
-
-#define DLOG_IF(severity, condition) \
- (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DLOG_EVERY_N(severity, n) \
- true ? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DLOG_IF_EVERY_N(severity, condition, n) \
- (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity)
-
-#define DLOG_ASSERT(condition) \
- true ? (void) 0 : LOG_ASSERT(condition)
-
-// MSVC warning C4127: conditional expression is constant
-#define DCHECK(condition) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK(condition)
-
-#define DCHECK_EQ(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_EQ(val1, val2)
-
-#define DCHECK_NE(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_NE(val1, val2)
-
-#define DCHECK_LE(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_LE(val1, val2)
-
-#define DCHECK_LT(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_LT(val1, val2)
-
-#define DCHECK_GE(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_GE(val1, val2)
-
-#define DCHECK_GT(val1, val2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_GT(val1, val2)
-
-// You may see warnings in release mode if you don't use the return
-// value of DCHECK_NOTNULL. Please just use DCHECK for such cases.
-#define DCHECK_NOTNULL(val) (val)
-
-#define DCHECK_STREQ(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STREQ(str1, str2)
-
-#define DCHECK_STRCASEEQ(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STRCASEEQ(str1, str2)
-
-#define DCHECK_STRNE(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STRNE(str1, str2)
-
-#define DCHECK_STRCASENE(str1, str2) \
- GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \
- while (false) \
- GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
-
-#endif // NDEBUG
-
-// Log only in verbose mode.
-
-#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel))
-
-#define VLOG_IF(verboselevel, condition) \
- LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel))
-
-#define VLOG_EVERY_N(verboselevel, n) \
- LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n)
-
-#define VLOG_IF_EVERY_N(verboselevel, condition, n) \
- LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n)
-
-namespace base_logging {
-
-// LogMessage::LogStream is a std::ostream backed by this streambuf.
-// This class ignores overflow and leaves two bytes at the end of the
-// buffer to allow for a '\n' and '\0'.
-class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf {
- public:
- // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'.
- LogStreamBuf(char *buf, int len) {
- setp(buf, buf + len - 2);
- }
- // This effectively ignores overflow.
- virtual int_type overflow(int_type ch) {
- return ch;
- }
-
- // Legacy public ostrstream method.
- size_t pcount() const { return pptr() - pbase(); }
- char* pbase() const { return std::streambuf::pbase(); }
-};
-
-} // namespace base_logging
-
-//
-// This class more or less represents a particular log message. You
-// create an instance of LogMessage and then stream stuff to it.
-// When you finish streaming to it, ~LogMessage is called and the
-// full message gets streamed to the appropriate destination.
-//
-// You shouldn't actually use LogMessage's constructor to log things,
-// though. You should use the LOG() macro (and variants thereof)
-// above.
-class GOOGLE_GLOG_DLL_DECL LogMessage {
-public:
- enum {
- // Passing kNoLogPrefix for the line number disables the
- // log-message prefix. Useful for using the LogMessage
- // infrastructure as a printing utility. See also the --log_prefix
- // flag for controlling the log-message prefix on an
- // application-wide basis.
- kNoLogPrefix = -1
- };
-
- // LogStream inherit from non-DLL-exported class (std::ostrstream)
- // and VC++ produces a warning for this situation.
- // However, MSDN says "C4275 can be ignored in Microsoft Visual C++
- // 2005 if you are deriving from a type in the Standard C++ Library"
- // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
- // Let's just ignore the warning.
-#ifdef _MSC_VER
-# pragma warning(disable: 4275)
-#endif
- class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {
-#ifdef _MSC_VER
-# pragma warning(default: 4275)
-#endif
- public:
- LogStream(char *buf, int len, int ctr)
- : std::ostream(NULL),
- streambuf_(buf, len),
- ctr_(ctr),
- self_(this) {
- rdbuf(&streambuf_);
- }
-
- int ctr() const { return ctr_; }
- void set_ctr(int ctr) { ctr_ = ctr; }
- LogStream* self() const { return self_; }
-
- // Legacy std::streambuf methods.
- size_t pcount() const { return streambuf_.pcount(); }
- char* pbase() const { return streambuf_.pbase(); }
- char* str() const { return pbase(); }
-
- private:
- base_logging::LogStreamBuf streambuf_;
- int ctr_; // Counter hack (for the LOG_EVERY_X() macro)
- LogStream *self_; // Consistency check hack
- };
-
-public:
- // icc 8 requires this typedef to avoid an internal compiler error.
- typedef void (LogMessage::*SendMethod)();
-
- LogMessage(const char* file, int line, LogSeverity severity, int ctr,
- SendMethod send_method);
-
- // Two special constructors that generate reduced amounts of code at
- // LOG call sites for common cases.
-
- // Used for LOG(INFO): Implied are:
- // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog.
- //
- // Using this constructor instead of the more complex constructor above
- // saves 19 bytes per call site.
- LogMessage(const char* file, int line);
-
- // Used for LOG(severity) where severity != INFO. Implied
- // are: ctr = 0, send_method = &LogMessage::SendToLog
- //
- // Using this constructor instead of the more complex constructor above
- // saves 17 bytes per call site.
- LogMessage(const char* file, int line, LogSeverity severity);
-
- // Constructor to log this message to a specified sink (if not NULL).
- // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if
- // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise.
- LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink,
- bool also_send_to_log);
-
- // Constructor where we also give a vector<string> pointer
- // for storing the messages (if the pointer is not NULL).
- // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog.
- LogMessage(const char* file, int line, LogSeverity severity,
- std::vector<std::string>* outvec);
-
- // Constructor where we also give a string pointer for storing the
- // message (if the pointer is not NULL). Implied are: ctr = 0,
- // send_method = &LogMessage::WriteToStringAndLog.
- LogMessage(const char* file, int line, LogSeverity severity,
- std::string* message);
-
- // A special constructor used for check failures
- LogMessage(const char* file, int line, const CheckOpString& result);
-
- ~LogMessage();
-
- // Flush a buffered message to the sink set in the constructor. Always
- // called by the destructor, it may also be called from elsewhere if
- // needed. Only the first call is actioned; any later ones are ignored.
- void Flush();
-
- // An arbitrary limit on the length of a single log message. This
- // is so that streaming can be done more efficiently.
- static const size_t kMaxLogMessageLen;
-
- // Theses should not be called directly outside of logging.*,
- // only passed as SendMethod arguments to other LogMessage methods:
- void SendToLog(); // Actually dispatch to the logs
- void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs
-
- // Call abort() or similar to perform LOG(FATAL) crash.
- static void Fail() ;
-
- std::ostream& stream();
-
- int preserved_errno() const;
-
- // Must be called without the log_mutex held. (L < log_mutex)
- static int64 num_messages(int severity);
-
- struct LogMessageData;
-
-private:
- // Fully internal SendMethod cases:
- void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs
- void SendToSink(); // Send to sink if provided, do nothing otherwise.
-
- // Write to string if provided and dispatch to the logs.
- void WriteToStringAndLog();
-
- void SaveOrSendToLog(); // Save to stringvec if provided, else to logs
-
- void Init(const char* file, int line, LogSeverity severity,
- void (LogMessage::*send_method)());
-
- // Used to fill in crash information during LOG(FATAL) failures.
- void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
-
- // Counts of messages sent at each priority:
- static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex
-
- // We keep the data in a separate struct so that each instance of
- // LogMessage uses less stack space.
- LogMessageData* allocated_;
- LogMessageData* data_;
-
- friend class LogDestination;
-
- LogMessage(const LogMessage&);
- void operator=(const LogMessage&);
-};
-
-// This class happens to be thread-hostile because all instances share
-// a single data buffer, but since it can only be created just before
-// the process dies, we don't worry so much.
-class GOOGLE_GLOG_DLL_DECL LogMessageFatal : public LogMessage {
- public:
- LogMessageFatal(const char* file, int line);
- LogMessageFatal(const char* file, int line, const CheckOpString& result);
- ~LogMessageFatal() ;
-};
-
-// A non-macro interface to the log facility; (useful
-// when the logging level is not a compile-time constant).
-inline void LogAtLevel(int const severity, std::string const &msg) {
- LogMessage(__FILE__, __LINE__, severity).stream() << msg;
-}
-
-// A macro alternative of LogAtLevel. New code may want to use this
-// version since there are two advantages: 1. this version outputs the
-// file name and the line number where this macro is put like other
-// LOG macros, 2. this macro can be used as C++ stream.
-#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream()
-
-// A small helper for CHECK_NOTNULL().
-template <typename T>
-T* CheckNotNull(const char *file, int line, const char *names, T* t) {
- if (t == NULL) {
- LogMessageFatal(file, line, new std::string(names));
- }
- return t;
-}
-
-// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
-// only works if ostream is a LogStream. If the ostream is not a
-// LogStream you'll get an assert saying as much at runtime.
-GOOGLE_GLOG_DLL_DECL std::ostream& operator<<(std::ostream &os,
- const PRIVATE_Counter&);
-
-
-// Derived class for PLOG*() above.
-class GOOGLE_GLOG_DLL_DECL ErrnoLogMessage : public LogMessage {
- public:
-
- ErrnoLogMessage(const char* file, int line, LogSeverity severity, int ctr,
- void (LogMessage::*send_method)());
-
- // Postpends ": strerror(errno) [errno]".
- ~ErrnoLogMessage();
-
- private:
- ErrnoLogMessage(const ErrnoLogMessage&);
- void operator=(const ErrnoLogMessage&);
-};
-
-
-// This class is used to explicitly ignore values in the conditional
-// logging macros. This avoids compiler warnings like "value computed
-// is not used" and "statement has no effect".
-
-class GOOGLE_GLOG_DLL_DECL LogMessageVoidify {
- public:
- LogMessageVoidify() { }
- // This has to be an operator with a precedence lower than << but
- // higher than ?:
- void operator&(std::ostream&) { }
-};
-
-
-// Flushes all log files that contains messages that are at least of
-// the specified severity level. Thread-safe.
-GOOGLE_GLOG_DLL_DECL void FlushLogFiles(LogSeverity min_severity);
-
-// Flushes all log files that contains messages that are at least of
-// the specified severity level. Thread-hostile because it ignores
-// locking -- used for catastrophic failures.
-GOOGLE_GLOG_DLL_DECL void FlushLogFilesUnsafe(LogSeverity min_severity);
-
-//
-// Set the destination to which a particular severity level of log
-// messages is sent. If base_filename is "", it means "don't log this
-// severity". Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetLogDestination(LogSeverity severity,
- const char* base_filename);
-
-//
-// Set the basename of the symlink to the latest log file at a given
-// severity. If symlink_basename is empty, do not make a symlink. If
-// you don't call this function, the symlink basename is the
-// invocation name of the program. Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetLogSymlink(LogSeverity severity,
- const char* symlink_basename);
-
-//
-// Used to send logs to some other kind of destination
-// Users should subclass LogSink and override send to do whatever they want.
-// Implementations must be thread-safe because a shared instance will
-// be called from whichever thread ran the LOG(XXX) line.
-class GOOGLE_GLOG_DLL_DECL LogSink {
- public:
- virtual ~LogSink();
-
- // Sink's logging logic (message_len is such as to exclude '\n' at the end).
- // This method can't use LOG() or CHECK() as logging system mutex(s) are held
- // during this call.
- virtual void send(LogSeverity severity, const char* full_filename,
- const char* base_filename, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len) = 0;
-
- // Redefine this to implement waiting for
- // the sink's logging logic to complete.
- // It will be called after each send() returns,
- // but before that LogMessage exits or crashes.
- // By default this function does nothing.
- // Using this function one can implement complex logic for send()
- // that itself involves logging; and do all this w/o causing deadlocks and
- // inconsistent rearrangement of log messages.
- // E.g. if a LogSink has thread-specific actions, the send() method
- // can simply add the message to a queue and wake up another thread that
- // handles real logging while itself making some LOG() calls;
- // WaitTillSent() can be implemented to wait for that logic to complete.
- // See our unittest for an example.
- virtual void WaitTillSent();
-
- // Returns the normal text output of the log message.
- // Can be useful to implement send().
- static std::string ToString(LogSeverity severity, const char* file, int line,
- const struct ::tm* tm_time,
- const char* message, size_t message_len);
-};
-
-// Add or remove a LogSink as a consumer of logging data. Thread-safe.
-GOOGLE_GLOG_DLL_DECL void AddLogSink(LogSink *destination);
-GOOGLE_GLOG_DLL_DECL void RemoveLogSink(LogSink *destination);
-
-//
-// Specify an "extension" added to the filename specified via
-// SetLogDestination. This applies to all severity levels. It's
-// often used to append the port we're listening on to the logfile
-// name. Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetLogFilenameExtension(
- const char* filename_extension);
-
-//
-// Make it so that all log messages of at least a particular severity
-// are logged to stderr (in addition to logging to the usual log
-// file(s)). Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetStderrLogging(LogSeverity min_severity);
-
-//
-// Make it so that all log messages go only to stderr. Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void LogToStderr();
-
-//
-// Make it so that all log messages of at least a particular severity are
-// logged via email to a list of addresses (in addition to logging to the
-// usual log file(s)). The list of addresses is just a string containing
-// the email addresses to send to (separated by spaces, say). Thread-safe.
-//
-GOOGLE_GLOG_DLL_DECL void SetEmailLogging(LogSeverity min_severity,
- const char* addresses);
-
-// A simple function that sends email. dest is a commma-separated
-// list of addressess. Thread-safe.
-GOOGLE_GLOG_DLL_DECL bool SendEmail(const char *dest,
- const char *subject, const char *body);
-
-GOOGLE_GLOG_DLL_DECL const std::vector<std::string>& GetLoggingDirectories();
-
-// For tests only: Clear the internal [cached] list of logging directories to
-// force a refresh the next time GetLoggingDirectories is called.
-// Thread-hostile.
-void TestOnly_ClearLoggingDirectoriesList();
-
-// Returns a set of existing temporary directories, which will be a
-// subset of the directories returned by GetLogginDirectories().
-// Thread-safe.
-GOOGLE_GLOG_DLL_DECL void GetExistingTempDirectories(
- std::vector<std::string>* list);
-
-// Print any fatal message again -- useful to call from signal handler
-// so that the last thing in the output is the fatal message.
-// Thread-hostile, but a race is unlikely.
-GOOGLE_GLOG_DLL_DECL void ReprintFatalMessage();
-
-// Truncate a log file that may be the append-only output of multiple
-// processes and hence can't simply be renamed/reopened (typically a
-// stdout/stderr). If the file "path" is > "limit" bytes, copy the
-// last "keep" bytes to offset 0 and truncate the rest. Since we could
-// be racing with other writers, this approach has the potential to
-// lose very small amounts of data. For security, only follow symlinks
-// if the path is /proc/self/fd/*
-GOOGLE_GLOG_DLL_DECL void TruncateLogFile(const char *path,
- int64 limit, int64 keep);
-
-// Truncate stdout and stderr if they are over the value specified by
-// --max_log_size; keep the final 1MB. This function has the same
-// race condition as TruncateLogFile.
-GOOGLE_GLOG_DLL_DECL void TruncateStdoutStderr();
-
-// Return the string representation of the provided LogSeverity level.
-// Thread-safe.
-GOOGLE_GLOG_DLL_DECL const char* GetLogSeverityName(LogSeverity severity);
-
-// ---------------------------------------------------------------------
-// Implementation details that are not useful to most clients
-// ---------------------------------------------------------------------
-
-// A Logger is the interface used by logging modules to emit entries
-// to a log. A typical implementation will dump formatted data to a
-// sequence of files. We also provide interfaces that will forward
-// the data to another thread so that the invoker never blocks.
-// Implementations should be thread-safe since the logging system
-// will write to them from multiple threads.
-
-namespace base {
-
-class GOOGLE_GLOG_DLL_DECL Logger {
- public:
- virtual ~Logger();
-
- // Writes "message[0,message_len-1]" corresponding to an event that
- // occurred at "timestamp". If "force_flush" is true, the log file
- // is flushed immediately.
- //
- // The input message has already been formatted as deemed
- // appropriate by the higher level logging facility. For example,
- // textual log messages already contain timestamps, and the
- // file:linenumber header.
- virtual void Write(bool force_flush,
- time_t timestamp,
- const char* message,
- int message_len) = 0;
-
- // Flush any buffered messages
- virtual void Flush() = 0;
-
- // Get the current LOG file size.
- // The returned value is approximate since some
- // logged data may not have been flushed to disk yet.
- virtual uint32 LogSize() = 0;
-};
-
-// Get the logger for the specified severity level. The logger
-// remains the property of the logging module and should not be
-// deleted by the caller. Thread-safe.
-extern GOOGLE_GLOG_DLL_DECL Logger* GetLogger(LogSeverity level);
-
-// Set the logger for the specified severity level. The logger
-// becomes the property of the logging module and should not
-// be deleted by the caller. Thread-safe.
-extern GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger* logger);
-
-}
-
-// glibc has traditionally implemented two incompatible versions of
-// strerror_r(). There is a poorly defined convention for picking the
-// version that we want, but it is not clear whether it even works with
-// all versions of glibc.
-// So, instead, we provide this wrapper that automatically detects the
-// version that is in use, and then implements POSIX semantics.
-// N.B. In addition to what POSIX says, we also guarantee that "buf" will
-// be set to an empty string, if this function failed. This means, in most
-// cases, you do not need to check the error code and you can directly
-// use the value of "buf". It will never have an undefined value.
-// DEPRECATED: Use StrError(int) instead.
-GOOGLE_GLOG_DLL_DECL int posix_strerror_r(int err, char *buf, size_t len);
-
-// A thread-safe replacement for strerror(). Returns a string describing the
-// given POSIX error code.
-GOOGLE_GLOG_DLL_DECL std::string StrError(int err);
-
-// A class for which we define operator<<, which does nothing.
-class GOOGLE_GLOG_DLL_DECL NullStream : public LogMessage::LogStream {
- public:
- // Initialize the LogStream so the messages can be written somewhere
- // (they'll never be actually displayed). This will be needed if a
- // NullStream& is implicitly converted to LogStream&, in which case
- // the overloaded NullStream::operator<< will not be invoked.
- NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) { }
- NullStream(const char* /*file*/, int /*line*/,
- const CheckOpString& /*result*/) :
- LogMessage::LogStream(message_buffer_, 1, 0) { }
- NullStream &stream() { return *this; }
- private:
- // A very short buffer for messages (which we discard anyway). This
- // will be needed if NullStream& converted to LogStream& (e.g. as a
- // result of a conditional expression).
- char message_buffer_[2];
-};
-
-// Do nothing. This operator is inline, allowing the message to be
-// compiled away. The message will not be compiled away if we do
-// something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when
-// SKIP_LOG=WARNING. In those cases, NullStream will be implicitly
-// converted to LogStream and the message will be computed and then
-// quietly discarded.
-template<class T>
-inline NullStream& operator<<(NullStream &str, const T &) { return str; }
-
-// Similar to NullStream, but aborts the program (without stack
-// trace), like LogMessageFatal.
-class GOOGLE_GLOG_DLL_DECL NullStreamFatal : public NullStream {
- public:
- NullStreamFatal() { }
- NullStreamFatal(const char* file, int line, const CheckOpString& result) :
- NullStream(file, line, result) { }
- ~NullStreamFatal() { _exit(1); }
-};
-
-// Install a signal handler that will dump signal information and a stack
-// trace when the program crashes on certain signals. We'll install the
-// signal handler for the following signals.
-//
-// SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM.
-//
-// By default, the signal handler will write the failure dump to the
-// standard error. You can customize the destination by installing your
-// own writer function by InstallFailureWriter() below.
-//
-// Note on threading:
-//
-// The function should be called before threads are created, if you want
-// to use the failure signal handler for all threads. The stack trace
-// will be shown only for the thread that receives the signal. In other
-// words, stack traces of other threads won't be shown.
-GOOGLE_GLOG_DLL_DECL void InstallFailureSignalHandler();
-
-// Installs a function that is used for writing the failure dump. "data"
-// is the pointer to the beginning of a message to be written, and "size"
-// is the size of the message. You should not expect the data is
-// terminated with '\0'.
-GOOGLE_GLOG_DLL_DECL void InstallFailureWriter(
- void (*writer)(const char* data, int size));
-
-}
-
-#endif // _LOGGING_H_
diff --git a/extern/libmv/third_party/glog/src/windows/port.cc b/extern/libmv/third_party/glog/src/windows/port.cc
deleted file mode 100644
index c16111a4b6d..00000000000
--- a/extern/libmv/third_party/glog/src/windows/port.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Copyright (c) 2008, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ---
- * Author: Craig Silverstein
- * Copied from google-perftools and modified by Shinichiro Hamaji
- */
-
-#ifndef _WIN32
-# error You should only be including windows/port.cc in a windows environment!
-#endif
-
-#include "config.h"
-#include <stdarg.h> // for va_list, va_start, va_end
-#include <string.h> // for strstr()
-#include <assert.h>
-#include <string>
-#include <vector>
-#include "port.h"
-
-using std::string;
-using std::vector;
-
-// These call the windows _vsnprintf, but always NUL-terminate.
-int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
- if (size == 0) // not even room for a \0?
- return -1; // not what C99 says to do, but what windows does
- str[size-1] = '\0';
- return _vsnprintf(str, size-1, format, ap);
-}
-
-#ifndef __MINGW64__
-int snprintf(char *str, size_t size, const char *format, ...) {
- va_list ap;
- va_start(ap, format);
- const int r = vsnprintf(str, size, format, ap);
- va_end(ap);
- return r;
-}
-#endif
diff --git a/extern/libmv/third_party/glog/src/windows/port.h b/extern/libmv/third_party/glog/src/windows/port.h
deleted file mode 100644
index 4879cbf5f92..00000000000
--- a/extern/libmv/third_party/glog/src/windows/port.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* Copyright (c) 2008, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ---
- * Author: Craig Silverstein
- * Copied from google-perftools and modified by Shinichiro Hamaji
- *
- * These are some portability typedefs and defines to make it a bit
- * easier to compile this code under VC++.
- *
- * Several of these are taken from glib:
- * http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
- */
-
-#ifndef CTEMPLATE_WINDOWS_PORT_H_
-#define CTEMPLATE_WINDOWS_PORT_H_
-
-#include "config.h"
-
-#ifdef _WIN32
-
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
-#endif
-
-#include <windows.h>
-#include <winsock.h> /* for gethostname */
-#include <io.h> /* because we so often use open/close/etc */
-#include <direct.h> /* for _getcwd() */
-#include <process.h> /* for _getpid() */
-#include <stdio.h> /* read in vsnprintf decl. before redifining it */
-#include <stdarg.h> /* template_dictionary.cc uses va_copy */
-#include <string.h> /* for _strnicmp(), strerror_s() */
-#include <time.h> /* for localtime_s() */
-/* Note: the C++ #includes are all together at the bottom. This file is
- * used by both C and C++ code, so we put all the C++ together.
- */
-
-#ifdef _MSC_VER
-
-/* 4244: otherwise we get problems when substracting two size_t's to an int
- * 4251: it's complaining about a private struct I've chosen not to dllexport
- * 4355: we use this in a constructor, but we do it safely
- * 4715: for some reason VC++ stopped realizing you can't return after abort()
- * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
- * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
- */
-#pragma warning(disable:4244 4251 4355 4715 4800 4996)
-
-/* file I/O */
-#define PATH_MAX 1024
-#define access _access
-#define getcwd _getcwd
-#define open _open
-#define read _read
-#define write _write
-#define lseek _lseek
-#define close _close
-#define popen _popen
-#define pclose _pclose
-#define R_OK 04 /* read-only (for access()) */
-#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
-#ifndef __MINGW32__
-enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
-#endif
-#define S_IRUSR S_IREAD
-#define S_IWUSR S_IWRITE
-
-/* Not quite as lightweight as a hard-link, but more than good enough for us. */
-#define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
-
-#define strcasecmp _stricmp
-#define strncasecmp _strnicmp
-
-/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
-/* VC11 provides std::hash */
-#if defined(_MSC_VER) && (_MSC_VER < 1700)
-#define hash hash_compare
-#endif
-
-/* Sleep is in ms, on windows */
-#define sleep(secs) Sleep((secs) * 1000)
-
-/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
- * because they don't always NUL-terminate. :-( We also can't use the
- * name vsnprintf, since windows defines that (but not snprintf (!)).
- */
-extern int snprintf(char *str, size_t size,
- const char *format, ...);
-extern int safe_vsnprintf(char *str, size_t size,
- const char *format, va_list ap);
-#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
-#define va_copy(dst, src) (dst) = (src)
-
-/* Windows doesn't support specifying the number of buckets as a
- * hash_map constructor arg, so we leave this blank.
- */
-#define CTEMPLATE_SMALL_HASHTABLE
-
-#define DEFAULT_TEMPLATE_ROOTDIR ".."
-
-// ----------------------------------- SYSTEM/PROCESS
-typedef int pid_t;
-#define getpid _getpid
-
-#include <BaseTsd.h>
-typedef SSIZE_T ssize_t;
-
-#endif // _MSC_VER
-
-// ----------------------------------- THREADS
-typedef DWORD pthread_t;
-typedef DWORD pthread_key_t;
-typedef LONG pthread_once_t;
-enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
-#define pthread_self GetCurrentThreadId
-#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
-
-inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
-#if __MINGW32__
- struct tm *local_result;
- local_result = localtime (timep);
-
- if (local_result == NULL || result == NULL)
- return NULL;
-
- memcpy (result, local_result, sizeof (result));
-
- return result;
-#else
- localtime_s(result, timep);
- return result;
-#endif
-}
-
-inline char* strerror_r(int errnum, char* buf, size_t buflen) {
-#if __MINGW32__
- strncpy(buf, "Not implemented yet", buflen);
- return buf;
-#else
- strerror_s(buf, buflen, errnum);
- return buf;
-#endif
-}
-
-#ifndef __cplusplus
-/* I don't see how to get inlining for C code in MSVC. Ah well. */
-#define inline
-#endif
-
-#endif /* _WIN32 */
-
-#endif /* CTEMPLATE_WINDOWS_PORT_H_ */
diff --git a/extern/libmv/third_party/glog/src/windows/preprocess.sh b/extern/libmv/third_party/glog/src/windows/preprocess.sh
deleted file mode 100755
index ea4352e8e3a..00000000000
--- a/extern/libmv/third_party/glog/src/windows/preprocess.sh
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/bin/sh
-
-# Copyright (c) 2008, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# ---
-# Author: Craig Silverstein
-# Copied from google-perftools and modified by Shinichiro Hamaji
-#
-# This script is meant to be run at distribution-generation time, for
-# instance by autogen.sh. It does some of the work configure would
-# normally do, for windows systems. In particular, it expands all the
-# @...@ variables found in .in files, and puts them here, in the windows
-# directory.
-#
-# This script should be run before any new release.
-
-if [ -z "$1" ]; then
- echo "USAGE: $0 <src/ directory>"
- exit 1
-fi
-
-DLLDEF_MACRO_NAME="GLOG_DLL_DECL"
-
-# The text we put in every .h files we create. As a courtesy, we'll
-# include a helpful comment for windows users as to how to use
-# GLOG_DLL_DECL. Apparently sed expands \n into a newline. Good!
-DLLDEF_DEFINES="\
-// NOTE: if you are statically linking the template library into your binary\n\
-// (rather than using the template .dll), set '/D $DLLDEF_MACRO_NAME='\n\
-// as a compiler flag in your project file to turn off the dllimports.\n\
-#ifndef $DLLDEF_MACRO_NAME\n\
-# define $DLLDEF_MACRO_NAME __declspec(dllimport)\n\
-#endif"
-
-# Read all the windows config info into variables
-# In order for the 'set' to take, this requires putting all in a subshell.
-(
- while read define varname value; do
- [ "$define" != "#define" ] && continue
- eval "$varname='$value'"
- done
-
- # Process all the .in files in the "glog" subdirectory
- mkdir -p "$1/windows/glog"
- for file in `echo "$1"/glog/*.in`; do
- echo "Processing $file"
- outfile="$1/windows/glog/`basename $file .in`"
-
- echo "\
-// This file is automatically generated from $file
-// using src/windows/preprocess.sh.
-// DO NOT EDIT!
-" > "$outfile"
- # Besides replacing @...@, we also need to turn on dllimport
- # We also need to replace hash by hash_compare (annoying we hard-code :-( )
- sed -e "s!@ac_windows_dllexport@!$DLLDEF_MACRO_NAME!g" \
- -e "s!@ac_windows_dllexport_defines@!$DLLDEF_DEFINES!g" \
- -e "s!@ac_cv_cxx_hash_map@!$HASH_MAP_H!g" \
- -e "s!@ac_cv_cxx_hash_namespace@!$HASH_NAMESPACE!g" \
- -e "s!@ac_cv_cxx_hash_set@!$HASH_SET_H!g" \
- -e "s!@ac_cv_have_stdint_h@!0!g" \
- -e "s!@ac_cv_have_systypes_h@!0!g" \
- -e "s!@ac_cv_have_inttypes_h@!0!g" \
- -e "s!@ac_cv_have_unistd_h@!0!g" \
- -e "s!@ac_cv_have_uint16_t@!0!g" \
- -e "s!@ac_cv_have_u_int16_t@!0!g" \
- -e "s!@ac_cv_have___uint16@!1!g" \
- -e "s!@ac_cv_have_libgflags@!0!g" \
- -e "s!@ac_cv_have___builtin_expect@!0!g" \
- -e "s!@ac_cv_cxx_using_operator@!1!g" \
- -e "s!@ac_cv___attribute___noreturn@!!g" \
- -e "s!@ac_cv___attribute___printf_4_5@!!g" \
- -e "s!@ac_google_attribute@!${HAVE___ATTRIBUTE__:-0}!g" \
- -e "s!@ac_google_end_namespace@!$_END_GOOGLE_NAMESPACE_!g" \
- -e "s!@ac_google_namespace@!$GOOGLE_NAMESPACE!g" \
- -e "s!@ac_google_start_namespace@!$_START_GOOGLE_NAMESPACE_!g" \
- -e "s!@ac_htmlparser_namespace@!$HTMLPARSER_NAMESPACE!g" \
- -e "s!\\bhash\\b!hash_compare!g" \
- "$file" >> "$outfile"
- done
-) < "$1/windows/config.h"
-
-# log_severity.h isn't a .in file.
-echo "\
-// This file is automatically generated from $1/glog/log_severity.h
-// using src/windows/preprocess.sh.
-// DO NOT EDIT!
-" > "$1/windows/glog/log_severity.h"
-cat "$1/glog/log_severity.h" >> "$1/windows/glog/log_severity.h"
-
-echo "DONE"
diff --git a/extern/libopenjpeg/SConscript b/extern/libopenjpeg/SConscript
deleted file mode 100644
index 178875ddec3..00000000000
--- a/extern/libopenjpeg/SConscript
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/python
-
-import sys
-
-Import('env')
-
-sources = env.Glob('*.c')
-
-incs = '.'
-flags = []
-defs = []
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- flags = []
- defs.append('OPJ_STATIC')
-elif env['OURPLATFORM'] == 'darwin':
- flags = ['-Wall', '-O3', '-ffast-math', '-std=c99'] + env['CCFLAGS'] # to supply SDK_FLAGS here
-else:
- flags = ['-Wall', '-O3', '-ffast-math', '-std=c99']
-
-oj_env = env.Clone()
-if not env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- oj_env.Replace(CCFLAGS = '')
- oj_env.Replace(BF_DEBUG_FLAGS = '')
-
-oj_env.BlenderLib ( libname='extern_openjpeg',
- sources=sources, includes=Split(incs),
- defines=defs,
- libtype=['extern','player'],
- priority=[10,185], compileflags = flags)
diff --git a/extern/libopenjpeg/bio.c b/extern/libopenjpeg/bio.c
index 4c02f464d8d..f04f3e503fb 100644
--- a/extern/libopenjpeg/bio.c
+++ b/extern/libopenjpeg/bio.c
@@ -42,7 +42,7 @@ Write a bit
@param bio BIO handle
@param b Bit to write (0 or 1)
*/
-static void bio_putbit(opj_bio_t *bio, int b);
+static void bio_putbit(opj_bio_t *bio, unsigned int b);
/**
Read a bit
@param bio BIO handle
@@ -78,7 +78,7 @@ static int bio_byteout(opj_bio_t *bio) {
if (bio->bp >= bio->end) {
return 1;
}
- *bio->bp++ = bio->buf >> 8;
+ *bio->bp++ = (unsigned char)(bio->buf >> 8);
return 0;
}
@@ -92,7 +92,7 @@ static int bio_bytein(opj_bio_t *bio) {
return 0;
}
-static void bio_putbit(opj_bio_t *bio, int b) {
+static void bio_putbit(opj_bio_t *bio, unsigned int b) {
if (bio->ct == 0) {
bio_byteout(bio);
}
@@ -126,7 +126,7 @@ void bio_destroy(opj_bio_t *bio) {
}
int bio_numbytes(opj_bio_t *bio) {
- return (bio->bp - bio->start);
+ return (int)(bio->bp - bio->start);
}
void bio_init_enc(opj_bio_t *bio, unsigned char *bp, int len) {
diff --git a/extern/libopenjpeg/cidx_manager.c b/extern/libopenjpeg/cidx_manager.c
index 6131b938ea6..f3b251ffa09 100644
--- a/extern/libopenjpeg/cidx_manager.c
+++ b/extern/libopenjpeg/cidx_manager.c
@@ -29,8 +29,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdio.h>
-#include <stdlib.h>
#include "opj_includes.h"
diff --git a/extern/libopenjpeg/cio.c b/extern/libopenjpeg/cio.c
index b8a7ecf8a87..97cccea6dee 100644
--- a/extern/libopenjpeg/cio.c
+++ b/extern/libopenjpeg/cio.c
@@ -30,6 +30,7 @@
*/
#include "opj_includes.h"
+#include <assert.h>
/* ----------------------------------------------------------------------- */
@@ -106,6 +107,7 @@ int OPJ_CALLCONV cio_tell(opj_cio_t *cio) {
* pos : position, in number of bytes, from the beginning of the stream
*/
void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) {
+ assert((cio->start + pos) <= cio->end);
cio->bp = cio->start + pos;
}
@@ -113,6 +115,7 @@ void OPJ_CALLCONV cio_seek(opj_cio_t *cio, int pos) {
* Number of bytes left before the end of the stream.
*/
int cio_numbytesleft(opj_cio_t *cio) {
+ assert((cio->end - cio->bp) >= 0);
return cio->end - cio->bp;
}
@@ -139,6 +142,7 @@ opj_bool cio_byteout(opj_cio_t *cio, unsigned char v) {
* Read a byte.
*/
unsigned char cio_bytein(opj_cio_t *cio) {
+ assert(cio->bp >= cio->start);
if (cio->bp >= cio->end) {
opj_event_msg(cio->cinfo, EVT_ERROR, "read error: passed the end of the codestream (start = %d, current = %d, end = %d\n", cio->start, cio->bp, cio->end);
return 0;
@@ -152,7 +156,7 @@ unsigned char cio_bytein(opj_cio_t *cio) {
* v : value to write
* n : number of bytes to write
*/
-unsigned int cio_write(opj_cio_t *cio, unsigned long long int v, int n) {
+unsigned int cio_write(opj_cio_t *cio, unsigned int64 v, int n) {
int i;
for (i = n - 1; i >= 0; i--) {
if( !cio_byteout(cio, (unsigned char) ((v >> (i << 3)) & 0xff)) )
@@ -173,7 +177,7 @@ unsigned int cio_read(opj_cio_t *cio, int n) {
unsigned int v;
v = 0;
for (i = n - 1; i >= 0; i--) {
- v += cio_bytein(cio) << (i << 3);
+ v += (unsigned int)cio_bytein(cio) << (i << 3);
}
return v;
}
@@ -184,6 +188,10 @@ unsigned int cio_read(opj_cio_t *cio, int n) {
* n : number of bytes to skip
*/
void cio_skip(opj_cio_t *cio, int n) {
+ assert((cio->bp + n) >= cio->bp);
+ if (((cio->bp + n) < cio->start) || ((cio->bp + n) > cio->end)) {
+ assert(0);
+ }
cio->bp += n;
}
diff --git a/extern/libopenjpeg/cio.h b/extern/libopenjpeg/cio.h
index ce1a13ecb3a..e62743141ca 100644
--- a/extern/libopenjpeg/cio.h
+++ b/extern/libopenjpeg/cio.h
@@ -31,6 +31,13 @@
#ifndef __CIO_H
#define __CIO_H
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define int64 __int64
+#else
+#define int64 long long
+#endif
+
/**
@file cio.h
@brief Implementation of a byte input-output process (CIO)
@@ -63,7 +70,7 @@ Write some bytes
@param n Number of bytes to write
@return Returns the number of bytes written or 0 if an error occured
*/
-unsigned int cio_write(opj_cio_t *cio, unsigned long long int v, int n);
+unsigned int cio_write(opj_cio_t *cio, unsigned int64 v, int n);
/**
Read some bytes
@param cio CIO handle
diff --git a/extern/libopenjpeg/event.c b/extern/libopenjpeg/event.c
index 0dc22f12549..38db33a9432 100644
--- a/extern/libopenjpeg/event.c
+++ b/extern/libopenjpeg/event.c
@@ -103,18 +103,17 @@ opj_bool opj_event_msg(opj_common_ptr cinfo, int event_type, const char *fmt, ..
va_list arg;
int str_length/*, i, j*/; /* UniPG */
char message[MSG_SIZE];
- memset(message, 0, MSG_SIZE);
/* initialize the optional parameter list */
va_start(arg, fmt);
- /* check the length of the format string */
- str_length = (strlen(fmt) > MSG_SIZE) ? MSG_SIZE : strlen(fmt);
/* parse the format string and put the result in 'message' */
- vsprintf(message, fmt, arg); /* UniPG */
+ str_length = vsnprintf(message, MSG_SIZE, fmt, arg); /* UniPG */
/* deinitialize the optional parameter list */
va_end(arg);
/* output the message to the user program */
- msg_handler(message, cinfo->client_data);
+ if( str_length > -1 && str_length < MSG_SIZE )
+ msg_handler(message, cinfo->client_data);
+ else return OPJ_FALSE;
}
return OPJ_TRUE;
diff --git a/extern/libopenjpeg/image.c b/extern/libopenjpeg/image.c
index 7c1e7f7faa2..579fd73d718 100644
--- a/extern/libopenjpeg/image.c
+++ b/extern/libopenjpeg/image.c
@@ -40,7 +40,7 @@ opj_image_t* OPJ_CALLCONV opj_image_create(int numcmpts, opj_image_cmptparm_t *c
image->color_space = clrspc;
image->numcomps = numcmpts;
/* allocate memory for the per-component information */
- image->comps = (opj_image_comp_t*)opj_malloc(image->numcomps * sizeof(opj_image_comp_t));
+ image->comps = (opj_image_comp_t*)opj_calloc(1,image->numcomps * sizeof(opj_image_comp_t));
if(!image->comps) {
fprintf(stderr,"Unable to allocate memory for image.\n");
opj_image_destroy(image);
@@ -86,3 +86,4 @@ void OPJ_CALLCONV opj_image_destroy(opj_image_t *image) {
opj_free(image);
}
}
+
diff --git a/extern/libopenjpeg/j2k.c b/extern/libopenjpeg/j2k.c
index d34c75faa7b..93e5c9eb80a 100644
--- a/extern/libopenjpeg/j2k.c
+++ b/extern/libopenjpeg/j2k.c
@@ -32,6 +32,7 @@
*/
#include "opj_includes.h"
+#include <assert.h>
/** @defgroup J2K J2K - JPEG-2000 codestream reader/writer */
/*@{*/
@@ -404,6 +405,7 @@ static void j2k_write_siz(opj_j2k_t *j2k) {
static void j2k_read_siz(opj_j2k_t *j2k) {
int len, i;
+ int n_comps;
opj_cio_t *cio = j2k->cio;
opj_image_t *image = j2k->image;
@@ -422,12 +424,33 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
if ((image->x0<0)||(image->x1<0)||(image->y0<0)||(image->y1<0)) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
- "%s: invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n",
+ "invalid image size (x0:%d, x1:%d, y0:%d, y1:%d)\n",
image->x0,image->x1,image->y0,image->y1);
return;
}
+ n_comps = (len - 36 - 2 ) / 3;
+ assert( (len - 36 - 2 ) % 3 == 0 );
image->numcomps = cio_read(cio, 2); /* Csiz */
+ assert( n_comps == image->numcomps );
+ (void)n_comps;
+
+ /* testcase 4035.pdf.SIGSEGV.d8b.3375 */
+ if (image->x0 > image->x1 || image->y0 > image->y1) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Error with SIZ marker: negative image size (%d x %d)\n", image->x1 - image->x0, image->y1 - image->y0);
+ return;
+ }
+ /* testcase 2539.pdf.SIGFPE.706.1712 (also 3622.pdf.SIGFPE.706.2916 and 4008.pdf.SIGFPE.706.3345 and maybe more) */
+ if (!(cp->tdx * cp->tdy)) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Error with SIZ marker: invalid tile size (tdx: %d, tdy: %d)\n", cp->tdx, cp->tdy);
+ return;
+ }
+
+ /* testcase 1610.pdf.SIGSEGV.59c.681 */
+ if (((int64)image->x1) * ((int64)image->y1) != (image->x1 * image->y1)) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Prevent buffer overflow (x1: %d, y1: %d)\n", image->x1, image->y1);
+ return;
+ }
#ifdef USE_JPWL
if (j2k->cp->correct) {
@@ -466,11 +489,19 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
/* update components number in the jpwl_exp_comps filed */
cp->exp_comps = image->numcomps;
}
+#else
+ (void)len;
#endif /* USE_JPWL */
+ /* prevent division by zero */
+ if (!(cp->tdx * cp->tdy)) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "invalid tile size (tdx: %d, tdy: %d)\n", cp->tdx, cp->tdy);
+ return;
+ }
+
image->comps = (opj_image_comp_t*) opj_calloc(image->numcomps, sizeof(opj_image_comp_t));
for (i = 0; i < image->numcomps; i++) {
- int tmp, w, h;
+ int tmp;
tmp = cio_read(cio, 1); /* Ssiz_i */
image->comps[i].prec = (tmp & 0x7f) + 1;
image->comps[i].sgnd = tmp >> 7;
@@ -506,9 +537,11 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
}
#endif /* USE_JPWL */
- /* TODO: unused ? */
- w = int_ceildiv(image->x1 - image->x0, image->comps[i].dx);
- h = int_ceildiv(image->y1 - image->y0, image->comps[i].dy);
+ /* prevent division by zero */
+ if (!(image->comps[i].dx * image->comps[i].dy)) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "JPWL: invalid component size (dx: %d, dy: %d)\n", image->comps[i].dx, image->comps[i].dy);
+ return;
+ }
image->comps[i].resno_decoded = 0; /* number of resolution decoded */
image->comps[i].factor = cp->reduce; /* reducing factor per component */
@@ -517,6 +550,15 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
cp->tw = int_ceildiv(image->x1 - cp->tx0, cp->tdx);
cp->th = int_ceildiv(image->y1 - cp->ty0, cp->tdy);
+ /* gdal_fuzzer_check_number_of_tiles.jp2 */
+ if (cp->tw == 0 || cp->th == 0 || cp->tw > 65535 / cp->th) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "Invalid number of tiles : %u x %u (maximum fixed by jpeg2000 norm is 65535 tiles)\n",
+ cp->tw, cp->th);
+ return;
+ }
+
+
#ifdef USE_JPWL
if (j2k->cp->correct) {
/* if JPWL is on, we check whether TX errors have damaged
@@ -558,7 +600,17 @@ static void j2k_read_siz(opj_j2k_t *j2k) {
#endif /* USE_JPWL */
cp->tcps = (opj_tcp_t*) opj_calloc(cp->tw * cp->th, sizeof(opj_tcp_t));
+ if (cp->tcps == NULL)
+ {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Out of memory\n");
+ return;
+ }
cp->tileno = (int*) opj_malloc(cp->tw * cp->th * sizeof(int));
+ if (cp->tileno == NULL)
+ {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Out of memory\n");
+ return;
+ }
cp->tileno_size = 0;
#ifdef USE_JPWL
@@ -684,6 +736,12 @@ static void j2k_read_cox(opj_j2k_t *j2k, int compno) {
"of resolutions of this component\nModify the cp_reduce parameter.\n\n", compno);
j2k->state |= J2K_STATE_ERR;
}
+ if( tccp->numresolutions > J2K_MAXRLVLS ) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Error decoding component %d.\nThe number of resolutions is too big: %d vs max= %d. Truncating.\n\n",
+ compno, tccp->numresolutions, J2K_MAXRLVLS);
+ j2k->state |= J2K_STATE_ERR;
+ tccp->numresolutions = J2K_MAXRLVLS;
+ }
tccp->cblkw = cio_read(cio, 1) + 2; /* SPcox (E) */
tccp->cblkh = cio_read(cio, 1) + 2; /* SPcox (F) */
@@ -753,6 +811,7 @@ static void j2k_read_cod(opj_j2k_t *j2k) {
opj_image_t *image = j2k->image;
len = cio_read(cio, 2); /* Lcod */
+ (void)len;
tcp->csty = cio_read(cio, 1); /* Scod */
tcp->prg = (OPJ_PROG_ORDER)cio_read(cio, 1); /* SGcod (A) */
tcp->numlayers = cio_read(cio, 2); /* SGcod (B) */
@@ -806,7 +865,14 @@ static void j2k_read_coc(opj_j2k_t *j2k) {
opj_cio_t *cio = j2k->cio;
len = cio_read(cio, 2); /* Lcoc */
+ (void)len;
compno = cio_read(cio, image->numcomps <= 256 ? 1 : 2); /* Ccoc */
+ if (compno >= image->numcomps) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "bad component number in COC (%d out of a maximum of %d)\n",
+ compno, image->numcomps);
+ return;
+ }
tcp->tccps[compno].csty = cio_read(cio, 1); /* Scoc */
j2k_read_cox(j2k, compno);
}
@@ -877,6 +943,8 @@ static void j2k_read_qcx(opj_j2k_t *j2k, int compno, int len) {
opj_event_msg(j2k->cinfo, EVT_WARNING ,
"bad number of subbands in Sqcx (%d) regarding to J2K_MAXBANDS (%d) \n"
"- limiting number of bands to J2K_MAXBANDS and try to move to the next markers\n", numbands, J2K_MAXBANDS);
+ /* edf_c2_1013627.jp2 */
+ numbands = 1;
}
#endif /* USE_JPWL */
@@ -988,9 +1056,16 @@ static void j2k_read_qcc(opj_j2k_t *j2k) {
/* keep your private count of tiles */
backup_compno++;
- };
+ }
#endif /* USE_JPWL */
+ if ((compno < 0) || (compno >= numcomp)) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "bad component number in QCC (%d out of a maximum of %d)\n",
+ compno, j2k->image->numcomps);
+ return;
+ }
+
j2k_read_qcx(j2k, compno, len - 2 - (numcomp <= 256 ? 1 : 2));
}
@@ -1036,6 +1111,15 @@ static void j2k_read_poc(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lpoc */
numpchgs = (len - 2) / (5 + 2 * (numcomps <= 256 ? 1 : 2));
+ if( numpchgs >= 32 )
+ {
+ /* edf_c2_1103421.jp2 */
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "bad number of POCS (%d out of a maximum of %d)\n",
+ numpchgs, 32);
+ numpchgs = 0;
+ }
+
for (i = old_poc; i < numpchgs + old_poc; i++) {
opj_poc_t *poc;
poc = &tcp->pocs[i];
@@ -1058,9 +1142,12 @@ static void j2k_read_crg(opj_j2k_t *j2k) {
int numcomps = j2k->image->numcomps;
len = cio_read(cio, 2); /* Lcrg */
+ (void)len;
for (i = 0; i < numcomps; i++) {
Xcrg_i = cio_read(cio, 2); /* Xcrg_i */
+ (void)Xcrg_i;
Ycrg_i = cio_read(cio, 2); /* Ycrg_i */
+ (void)Ycrg_i;
}
}
@@ -1072,13 +1159,16 @@ static void j2k_read_tlm(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Ltlm */
Ztlm = cio_read(cio, 1); /* Ztlm */
+ (void)Ztlm;
Stlm = cio_read(cio, 1); /* Stlm */
ST = ((Stlm >> 4) & 0x01) + ((Stlm >> 4) & 0x02);
SP = (Stlm >> 6) & 0x01;
tile_tlm = (len - 4) / ((SP + 1) * 2 + ST);
for (i = 0; i < tile_tlm; i++) {
Ttlm_i = cio_read(cio, ST); /* Ttlm_i */
+ (void)Ttlm_i;
Ptlm_i = cio_read(cio, SP ? 4 : 2); /* Ptlm_i */
+ (void)Ptlm_i;
}
}
@@ -1089,6 +1179,7 @@ static void j2k_read_plm(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lplm */
Zplm = cio_read(cio, 1); /* Zplm */
+ (void)Zplm;
len -= 3;
while (len > 0) {
Nplm = cio_read(cio, 4); /* Nplm */
@@ -1114,6 +1205,7 @@ static void j2k_read_plt(opj_j2k_t *j2k) {
len = cio_read(cio, 2); /* Lplt */
Zplt = cio_read(cio, 1); /* Zplt */
+ (void)Zplt;
for (i = len - 3; i > 0; i--) {
add = cio_read(cio, 1);
packet_len = (packet_len << 7) + add; /* Iplt_i */
@@ -1261,6 +1353,7 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
opj_cio_t *cio = j2k->cio;
len = cio_read(cio, 2);
+ (void)len;
tileno = cio_read(cio, 2);
#ifdef USE_JPWL
@@ -1269,7 +1362,7 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
static int backup_tileno = 0;
/* tileno is negative or larger than the number of tiles!!! */
- if ((tileno < 0) || (tileno > (cp->tw * cp->th))) {
+ if ((tileno < 0) || (tileno >= (cp->tw * cp->th))) {
opj_event_msg(j2k->cinfo, EVT_ERROR,
"JPWL: bad tile number (%d out of a maximum of %d)\n",
tileno, (cp->tw * cp->th));
@@ -1286,8 +1379,18 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
/* keep your private count of tiles */
backup_tileno++;
- };
+ }
+ else
#endif /* USE_JPWL */
+ {
+ /* tileno is negative or larger than the number of tiles!!! */
+ if ((tileno < 0) || (tileno >= (cp->tw * cp->th))) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "JPWL: bad tile number (%d out of a maximum of %d)\n",
+ tileno, (cp->tw * cp->th));
+ return;
+ }
+ }
if (cp->tileno_size == 0) {
cp->tileno[cp->tileno_size] = tileno;
@@ -1325,8 +1428,18 @@ static void j2k_read_sot(opj_j2k_t *j2k) {
totlen);
}
- };
+ }
+ else
#endif /* USE_JPWL */
+ {
+ /* totlen is negative or larger than the bytes left!!! */
+ if ((totlen < 0) || (totlen > (cio_numbytesleft(cio) + 8))) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "JPWL: bad tile byte size (%d bytes against %d bytes left)\n",
+ totlen, cio_numbytesleft(cio) + 8);
+ return;
+ }
+ }
if (!totlen)
totlen = cio_numbytesleft(cio) + 8;
@@ -1478,7 +1591,13 @@ static void j2k_read_sod(opj_j2k_t *j2k) {
}
data = j2k->tile_data[curtileno];
+ data_ptr = data; /* store in case of failure */
data = (unsigned char*) opj_realloc(data, (j2k->tile_len[curtileno] + len) * sizeof(unsigned char));
+ if( data == NULL ) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR, "Could not reallocated\n" );
+ opj_free( data_ptr );
+ return;
+ }
data_ptr = data + j2k->tile_len[curtileno];
for (i = 0; i < len; i++) {
@@ -1518,8 +1637,10 @@ static void j2k_read_rgn(opj_j2k_t *j2k) {
int numcomps = j2k->image->numcomps;
len = cio_read(cio, 2); /* Lrgn */
+ (void)len;
compno = cio_read(cio, numcomps <= 256 ? 1 : 2); /* Crgn */
roisty = cio_read(cio, 1); /* Srgn */
+ (void)roisty;
#ifdef USE_JPWL
if (j2k->cp->correct) {
@@ -1536,6 +1657,13 @@ static void j2k_read_rgn(opj_j2k_t *j2k) {
};
#endif /* USE_JPWL */
+ if (compno >= numcomps) {
+ opj_event_msg(j2k->cinfo, EVT_ERROR,
+ "bad component number in RGN (%d out of a maximum of %d)\n",
+ compno, j2k->image->numcomps);
+ return;
+ }
+
tcp->tccps[compno].roishift = cio_read(cio, 1); /* SPrgn */
}
@@ -1554,7 +1682,7 @@ static void j2k_write_eoc(opj_j2k_t *j2k) {
static void j2k_read_eoc(opj_j2k_t *j2k) {
int i, tileno;
- opj_bool success;
+ opj_bool success = OPJ_FALSE;
/* if packets should be decoded */
if (j2k->cp->limit_decoding != DECODE_ALL_BUT_PACKETS) {
@@ -1562,11 +1690,17 @@ static void j2k_read_eoc(opj_j2k_t *j2k) {
tcd_malloc_decode(tcd, j2k->image, j2k->cp);
for (i = 0; i < j2k->cp->tileno_size; i++) {
tcd_malloc_decode_tile(tcd, j2k->image, j2k->cp, i, j2k->cstr_info);
- tileno = j2k->cp->tileno[i];
- success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info);
- opj_free(j2k->tile_data[tileno]);
- j2k->tile_data[tileno] = NULL;
- tcd_free_decode_tile(tcd, i);
+ if (j2k->cp->tileno[i] != -1)
+ {
+ tileno = j2k->cp->tileno[i];
+ success = tcd_decode_tile(tcd, j2k->tile_data[tileno], j2k->tile_len[tileno], tileno, j2k->cstr_info);
+ assert( tileno != -1 );
+ opj_free(j2k->tile_data[tileno]);
+ j2k->tile_data[tileno] = NULL;
+ tcd_free_decode_tile(tcd, i);
+ }
+ else
+ success = OPJ_FALSE;
if (success == OPJ_FALSE) {
j2k->state |= J2K_STATE_ERR;
break;
@@ -1737,6 +1871,17 @@ void j2k_destroy_decompress(opj_j2k_t *j2k) {
opj_free(j2k->tile_len);
}
if(j2k->tile_data != NULL) {
+ if(j2k->cp != NULL) {
+ for (i = 0; i < j2k->cp->tileno_size; i++) {
+ int tileno = j2k->cp->tileno[i];
+ if( tileno != -1 )
+ {
+ opj_free(j2k->tile_data[tileno]);
+ j2k->tile_data[tileno] = NULL;
+ }
+ }
+ }
+
opj_free(j2k->tile_data);
}
if(j2k->default_tcp != NULL) {
@@ -1856,9 +2001,15 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
#endif /* USE_JPWL */
if (id >> 8 != 0xff) {
- opj_image_destroy(image);
- opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
- return 0;
+ if(cio_numbytesleft(cio) != 0) /* not end of file reached and no EOC */
+ {
+ opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
+ opj_image_destroy(image);
+ return 0;
+ }
+ opj_event_msg(cinfo, EVT_WARNING, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
+ j2k->state = J2K_STATE_NEOC;
+ break;
}
e = j2k_dec_mstab_lookup(id);
/* Check if the marker is known*/
@@ -1877,7 +2028,10 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
(*e->handler)(j2k);
}
if (j2k->state & J2K_STATE_ERR)
+ {
+ opj_image_destroy(image);
return NULL;
+ }
if (j2k->state == J2K_STATE_MT) {
break;
@@ -1888,6 +2042,11 @@ opj_image_t* j2k_decode(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestream_info_t *c
}
if (j2k->state == J2K_STATE_NEOC) {
j2k_read_eoc(j2k);
+ /* Check one last time for errors during decoding before returning */
+ if (j2k->state & J2K_STATE_ERR) {
+ opj_image_destroy(image);
+ return NULL;
+ }
}
if (j2k->state != J2K_STATE_MT) {
@@ -1949,9 +2108,15 @@ opj_image_t* j2k_decode_jpt_stream(opj_j2k_t *j2k, opj_cio_t *cio, opj_codestre
id = cio_read(cio, 2);
if (id >> 8 != 0xff) {
- opj_image_destroy(image);
- opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
- return 0;
+ if(cio_numbytesleft(cio) != 0) /* no end of file reached and no EOC */
+ {
+ opj_event_msg(cinfo, EVT_ERROR, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
+ opj_image_destroy(image);
+ return 0;
+ }
+ opj_event_msg(cinfo, EVT_WARNING, "%.8x: expected a marker instead of %x\n", cio_tell(cio) - 2, id);
+ j2k->state = J2K_STATE_NEOC;
+ break;
}
e = j2k_dec_mstab_lookup(id);
if (!(j2k->state & e->states)) {
diff --git a/extern/libopenjpeg/jp2.c b/extern/libopenjpeg/jp2.c
index 5ae114c33b9..d3322603c8b 100644
--- a/extern/libopenjpeg/jp2.c
+++ b/extern/libopenjpeg/jp2.c
@@ -30,6 +30,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "opj_includes.h"
+#include <assert.h>
/** @defgroup JP2 JP2 - JPEG-2000 file format reader/writer */
/*@{*/
@@ -172,6 +173,9 @@ static opj_bool jp2_read_boxhdr(opj_common_ptr cinfo, opj_cio_t *cio, opj_jp2_bo
}
else if (box->length == 0) {
box->length = cio_numbytesleft(cio) + 8;
+ } else if (box->length < 0) {
+ opj_event_msg(cinfo, EVT_ERROR, "Integer overflow in box->length\n");
+ return OPJ_FALSE; /* TODO: actually check jp2_read_boxhdr's return value */
}
return OPJ_TRUE;
@@ -206,7 +210,10 @@ static opj_bool jp2_read_ihdr(opj_jp2_t *jp2, opj_cio_t *cio) {
opj_common_ptr cinfo = jp2->cinfo;
- jp2_read_boxhdr(cinfo, cio, &box);
+ if(jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) {
+ opj_event_msg(cinfo, EVT_ERROR, "Failed to read boxhdr\n");
+ return OPJ_FALSE;
+ }
if (JP2_IHDR != box.type) {
opj_event_msg(cinfo, EVT_ERROR, "Expected IHDR Marker\n");
return OPJ_FALSE;
@@ -279,7 +286,10 @@ static opj_bool jp2_read_bpcc(opj_jp2_t *jp2, opj_cio_t *cio) {
opj_common_ptr cinfo = jp2->cinfo;
- jp2_read_boxhdr(cinfo, cio, &box);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) {
+ opj_event_msg(cinfo, EVT_ERROR, "Failed to read boxhdr\n");
+ return OPJ_FALSE;
+ }
if (JP2_BPCC != box.type) {
opj_event_msg(cinfo, EVT_ERROR, "Expected BPCC Marker\n");
return OPJ_FALSE;
@@ -469,7 +479,7 @@ static opj_bool jp2_read_pclr(opj_jp2_t *jp2, opj_cio_t *cio,
for(i = 0; i < nr_channels; ++i)
{
/* Cji */
- *entries++ = cio_read(cio, channel_size[i]>>3);
+ *entries++ = cio_read(cio, (channel_size[i]+7)>>3);
}
}
@@ -512,10 +522,8 @@ static opj_bool jp2_read_cmap(opj_jp2_t *jp2, opj_cio_t *cio,
static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color)
{
opj_jp2_cdef_info_t *info;
- int color_space;
unsigned short i, n, cn, typ, asoc, acn;
- color_space = image->color_space;
info = color->jp2_cdef->info;
n = color->jp2_cdef->n;
@@ -525,6 +533,7 @@ static void jp2_apply_cdef(opj_image_t *image, opj_jp2_color_t *color)
if((asoc = info[i].asoc) == 0) continue;
cn = info[i].cn; typ = info[i].typ; acn = asoc - 1;
+ (void)typ;
if(cn != acn)
{
@@ -639,90 +648,173 @@ opj_bool jp2_read_jp2h(opj_jp2_t *jp2, opj_cio_t *cio, opj_jp2_color_t *color)
opj_common_ptr cinfo = jp2->cinfo;
- jp2_read_boxhdr(cinfo, cio, &box);
- do
- {
- if (JP2_JP2H != box.type)
- {
- if (box.type == JP2_JP2C)
- {
- opj_event_msg(cinfo, EVT_ERROR, "Expected JP2H Marker\n");
- return OPJ_FALSE;
- }
- cio_skip(cio, box.length - 8);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
+ do {
+ if (JP2_JP2H != box.type)
+ {
+ if (box.type == JP2_JP2C)
+ {
+ opj_event_msg(cinfo, EVT_ERROR, "Expected JP2H Marker\n");
+ return OPJ_FALSE;
+ }
+ if (box.length <= 8) return OPJ_FALSE;
+ cio_skip(cio, box.length - 8);
- if(cio->bp >= cio->end) return OPJ_FALSE;
+ if(cio->bp >= cio->end) return OPJ_FALSE;
- jp2_read_boxhdr(cinfo, cio, &box);
- }
- } while(JP2_JP2H != box.type);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
+ }
+ } while(JP2_JP2H != box.type);
if (!jp2_read_ihdr(jp2, cio))
return OPJ_FALSE;
jp2h_end = box.init_pos + box.length;
- if (jp2->bpc == 255)
- {
- if (!jp2_read_bpcc(jp2, cio))
- return OPJ_FALSE;
- }
- jp2_read_boxhdr(cinfo, cio, &box);
+ if (jp2->bpc == 255)
+ {
+ if (!jp2_read_bpcc(jp2, cio))
+ return OPJ_FALSE;
+ }
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
- while(cio_tell(cio) < jp2h_end)
- {
- if(box.type == JP2_COLR)
- {
- if( !jp2_read_colr(jp2, cio, &box, color))
- {
- cio_seek(cio, box.init_pos + 8);
- cio_skip(cio, box.length - 8);
- }
- jp2_read_boxhdr(cinfo, cio, &box);
- continue;
- }
+ while(cio_tell(cio) < jp2h_end)
+ {
+ if(box.type == JP2_COLR)
+ {
+ if( !jp2_read_colr(jp2, cio, &box, color))
+ {
+ if (box.length <= 8) return OPJ_FALSE;
+ cio_seek(cio, box.init_pos + 8);
+ cio_skip(cio, box.length - 8);
+ }
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
+ continue;
+ }
if(box.type == JP2_CDEF && !jp2->ignore_pclr_cmap_cdef)
- {
- if( !jp2_read_cdef(jp2, cio, &box, color))
- {
- cio_seek(cio, box.init_pos + 8);
- cio_skip(cio, box.length - 8);
- }
- jp2_read_boxhdr(cinfo, cio, &box);
- continue;
- }
+ {
+ if( !jp2_read_cdef(jp2, cio, &box, color))
+ {
+ if (box.length <= 8) return OPJ_FALSE;
+ cio_seek(cio, box.init_pos + 8);
+ cio_skip(cio, box.length - 8);
+ }
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
+ continue;
+ }
if(box.type == JP2_PCLR && !jp2->ignore_pclr_cmap_cdef)
- {
- if( !jp2_read_pclr(jp2, cio, &box, color))
- {
- cio_seek(cio, box.init_pos + 8);
- cio_skip(cio, box.length - 8);
- }
- jp2_read_boxhdr(cinfo, cio, &box);
- continue;
- }
+ {
+ if( !jp2_read_pclr(jp2, cio, &box, color))
+ {
+ if (box.length <= 8) return OPJ_FALSE;
+ cio_seek(cio, box.init_pos + 8);
+ cio_skip(cio, box.length - 8);
+ }
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
+ continue;
+ }
if(box.type == JP2_CMAP && !jp2->ignore_pclr_cmap_cdef)
- {
- if( !jp2_read_cmap(jp2, cio, &box, color))
- {
+ {
+ if( !jp2_read_cmap(jp2, cio, &box, color))
+ {
+ if (box.length <= 8) return OPJ_FALSE;
+ cio_seek(cio, box.init_pos + 8);
+ cio_skip(cio, box.length - 8);
+ }
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
+ continue;
+ }
+ if (box.length <= 8) return OPJ_FALSE;
cio_seek(cio, box.init_pos + 8);
cio_skip(cio, box.length - 8);
- }
- jp2_read_boxhdr(cinfo, cio, &box);
- continue;
- }
- cio_seek(cio, box.init_pos + 8);
- cio_skip(cio, box.length - 8);
- jp2_read_boxhdr(cinfo, cio, &box);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
- }/* while(cio_tell(cio) < box_end) */
+ }/* while(cio_tell(cio) < box_end) */
- cio_seek(cio, jp2h_end);
+ cio_seek(cio, jp2h_end);
-/* Part 1, I.5.3.3 : 'must contain at least one' */
- return (color->jp2_has_colr == 1);
+ /* Part 1, I.5.3.3 : 'must contain at least one' */
+ return (color->jp2_has_colr == 1);
}/* jp2_read_jp2h() */
+static opj_bool opj_jp2_check_color(opj_image_t *image, opj_jp2_color_t *color, opj_common_ptr cinfo)
+{
+ int i;
+
+ /* testcase 4149.pdf.SIGSEGV.cf7.3501 */
+ if (color->jp2_cdef) {
+ opj_jp2_cdef_info_t *info = color->jp2_cdef->info;
+ int n = color->jp2_cdef->n;
+
+ for (i = 0; i < n; i++) {
+ if (info[i].cn >= image->numcomps) {
+ opj_event_msg(cinfo, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].cn, image->numcomps);
+ return OPJ_FALSE;
+ }
+ if (info[i].asoc > 0 && (info[i].asoc - 1) >= image->numcomps) {
+ opj_event_msg(cinfo, EVT_ERROR, "Invalid component index %d (>= %d).\n", info[i].asoc - 1, image->numcomps);
+ return OPJ_FALSE;
+ }
+ }
+ }
+
+ /* testcases 451.pdf.SIGSEGV.f4c.3723, 451.pdf.SIGSEGV.5b5.3723 and
+ 66ea31acbb0f23a2bbc91f64d69a03f5_signal_sigsegv_13937c0_7030_5725.pdf */
+ if (color->jp2_pclr && color->jp2_pclr->cmap) {
+ int nr_channels = color->jp2_pclr->nr_channels;
+ opj_jp2_cmap_comp_t *cmap = color->jp2_pclr->cmap;
+ opj_bool *pcol_usage, is_sane = OPJ_TRUE;
+
+ /* verify that all original components match an existing one */
+ for (i = 0; i < nr_channels; i++) {
+ if (cmap[i].cmp >= image->numcomps) {
+ opj_event_msg(cinfo, EVT_ERROR, "Invalid component index %d (>= %d).\n", cmap[i].cmp, image->numcomps);
+ is_sane = OPJ_FALSE;
+ }
+ }
+
+ pcol_usage = opj_calloc(nr_channels, sizeof(opj_bool));
+ if (!pcol_usage) {
+ opj_event_msg(cinfo, EVT_ERROR, "Unexpected OOM.\n");
+ return OPJ_FALSE;
+ }
+ /* verify that no component is targeted more than once */
+ for (i = 0; i < nr_channels; i++) {
+ int pcol = cmap[i].pcol;
+ assert(cmap[i].mtyp == 0 || cmap[i].mtyp == 1);
+ if (pcol >= nr_channels) {
+ opj_event_msg(cinfo, EVT_ERROR, "Invalid component/palette index for direct mapping %d.\n", pcol);
+ is_sane = OPJ_FALSE;
+ }
+ else if (pcol_usage[pcol] && cmap[i].mtyp == 1) {
+ opj_event_msg(cinfo, EVT_ERROR, "Component %d is mapped twice.\n", pcol);
+ is_sane = OPJ_FALSE;
+ }
+ else if (cmap[i].mtyp == 0 && cmap[i].pcol != 0) {
+ /* I.5.3.5 PCOL: If the value of the MTYP field for this channel is 0, then
+ * the value of this field shall be 0. */
+ opj_event_msg(cinfo, EVT_ERROR, "Direct use at #%d however pcol=%d.\n", i, pcol);
+ is_sane = OPJ_FALSE;
+ }
+ else
+ pcol_usage[pcol] = OPJ_TRUE;
+ }
+ /* verify that all components are targeted at least once */
+ for (i = 0; i < nr_channels; i++) {
+ if (!pcol_usage[i] && cmap[i].mtyp != 0) {
+ opj_event_msg(cinfo, EVT_ERROR, "Component %d doesn't have a mapping.\n", i);
+ is_sane = OPJ_FALSE;
+ }
+ }
+ opj_free(pcol_usage);
+ if (!is_sane) {
+ return OPJ_FALSE;
+ }
+ }
+
+ return OPJ_TRUE;
+}
+
opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio,
opj_codestream_info_t *cstr_info)
{
@@ -756,6 +848,10 @@ opj_image_t* opj_jp2_decode(opj_jp2_t *jp2, opj_cio_t *cio,
}
if (!jp2->ignore_pclr_cmap_cdef){
+ if (!opj_jp2_check_color(image, &color, cinfo)) {
+ opj_event_msg(cinfo, EVT_ERROR, "Failed to decode PCRL box\n");
+ return NULL;
+ }
/* Set Image Color Space */
if (jp2->enumcs == 16)
@@ -839,8 +935,10 @@ static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) {
opj_common_ptr cinfo = jp2->cinfo;
- jp2_read_boxhdr(cinfo, cio, &box);
-
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) {
+ opj_event_msg(cinfo, EVT_ERROR, "Failed to read boxhdr\n");
+ return OPJ_FALSE;
+ }
if (JP2_FTYP != box.type) {
opj_event_msg(cinfo, EVT_ERROR, "Expected FTYP Marker\n");
return OPJ_FALSE;
@@ -849,6 +947,14 @@ static opj_bool jp2_read_ftyp(opj_jp2_t *jp2, opj_cio_t *cio) {
jp2->brand = cio_read(cio, 4); /* BR */
jp2->minversion = cio_read(cio, 4); /* MinV */
jp2->numcl = (box.length - 16) / 4;
+
+ /* edf_c2_1673169.jp2 */
+ if (cio_numbytesleft(cio) < ((int)jp2->numcl * 4)) {
+ opj_event_msg(cinfo, EVT_ERROR, "Not enough bytes in FTYP Box "
+ "(expected %d, but only %d left)\n",
+ ((int)jp2->numcl * 4), cio_numbytesleft(cio));
+ return OPJ_FALSE;
+ }
jp2->cl = (unsigned int *) opj_malloc(jp2->numcl * sizeof(unsigned int));
for (i = 0; i < (int)jp2->numcl; i++) {
@@ -897,15 +1003,20 @@ static opj_bool jp2_read_jp2c(opj_jp2_t *jp2, opj_cio_t *cio, unsigned int *j2k_
opj_common_ptr cinfo = jp2->cinfo;
- jp2_read_boxhdr(cinfo, cio, &box);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) {
+ opj_event_msg(cinfo, EVT_ERROR, "Failed to read boxhdr\n");
+ return OPJ_FALSE;
+ }
do {
if(JP2_JP2C != box.type) {
+ if (box.length <= 8) return OPJ_FALSE;
cio_skip(cio, box.length - 8);
- jp2_read_boxhdr(cinfo, cio, &box);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) return OPJ_FALSE;
}
} while(JP2_JP2C != box.type);
*j2k_codestream_offset = cio_tell(cio);
+ if (box.length <= 8) return OPJ_FALSE;
*j2k_codestream_length = box.length - 8;
return OPJ_TRUE;
@@ -930,7 +1041,10 @@ static opj_bool jp2_read_jp(opj_jp2_t *jp2, opj_cio_t *cio) {
opj_common_ptr cinfo = jp2->cinfo;
- jp2_read_boxhdr(cinfo, cio, &box);
+ if( jp2_read_boxhdr(cinfo, cio, &box) == OPJ_FALSE ) {
+ opj_event_msg(cinfo, EVT_ERROR, "Failed to read boxhdr\n");
+ return OPJ_FALSE;
+ }
if (JP2_JP != box.type) {
opj_event_msg(cinfo, EVT_ERROR, "Expected JP Marker\n");
return OPJ_FALSE;
@@ -1070,6 +1184,7 @@ void jp2_setup_decoder(opj_jp2_t *jp2, opj_dparameters_t *parameters) {
opj_jp2_t* jp2_create_compress(opj_common_ptr cinfo) {
opj_jp2_t *jp2 = (opj_jp2_t*)opj_malloc(sizeof(opj_jp2_t));
if(jp2) {
+ memset(jp2, 0, sizeof(opj_jp2_t));
jp2->cinfo = cinfo;
/* create the J2K codec */
jp2->j2k = j2k_create_compress(cinfo);
diff --git a/extern/libopenjpeg/openjpeg.h b/extern/libopenjpeg/openjpeg.h
index 53e9fac0438..59147c8b3d1 100644
--- a/extern/libopenjpeg/openjpeg.h
+++ b/extern/libopenjpeg/openjpeg.h
@@ -135,6 +135,10 @@ typedef enum COLOR_SPACE {
CLRSPC_SYCC = 3 /**< YUV */
} OPJ_COLOR_SPACE;
+#define ENUMCS_SRGB 16
+#define ENUMCS_GRAY 17
+#define ENUMCS_SYCC 18
+
/**
Supported codec
*/
diff --git a/extern/libopenjpeg/opj_config.h b/extern/libopenjpeg/opj_config.h
index 82e12be03a9..5d0a877b840 100644
--- a/extern/libopenjpeg/opj_config.h
+++ b/extern/libopenjpeg/opj_config.h
@@ -3,7 +3,7 @@
* the endian check is a blender define */
/* create config.h for CMake */
-#define PACKAGE_VERSION "1.5.0"
+#define PACKAGE_VERSION "1.5.2"
#define HAVE_INTTYPES_H
#define HAVE_MEMORY_H
@@ -23,6 +23,7 @@
/* #undef HAVE_LIBLCMS2 */
/* #undef HAVE_LCMS1_H */
/* #undef HAVE_LCMS2_H */
+/* #undef USE_SYSTEM_GETOPT */
/* Byte order. */
/* All compilers that support Mac OS X define either __BIG_ENDIAN__ or
diff --git a/extern/libopenjpeg/opj_includes.h b/extern/libopenjpeg/opj_includes.h
index 2b5866a9990..e9194fd9886 100644
--- a/extern/libopenjpeg/opj_includes.h
+++ b/extern/libopenjpeg/opj_includes.h
@@ -89,18 +89,17 @@ Most compilers implement their own version of this keyword ...
/* MSVC and Borland C do not have lrintf */
#if defined(_MSC_VER) || defined(__BORLANDC__)
static INLINE long lrintf(float f){
-#ifdef _M_X64
- return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f));
-#else
- int i;
+#ifdef _M_IX86
+ long int i;
_asm{
fld f
fistp i
};
-
return i;
-#endif
+#else
+ return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f));
+#endif /* _M_IX86 */
}
#endif
diff --git a/extern/libopenjpeg/opj_malloc.h b/extern/libopenjpeg/opj_malloc.h
index 87493f497c7..aef2ee3b8c9 100644
--- a/extern/libopenjpeg/opj_malloc.h
+++ b/extern/libopenjpeg/opj_malloc.h
@@ -83,8 +83,10 @@ Allocate memory aligned to a 16 byte boundry
#else /* Not _WIN32 */
#if defined(__sun)
#define HAVE_MEMALIGN
+ #elif defined(__FreeBSD__)
+ #define HAVE_POSIX_MEMALIGN
/* Linux x86_64 and OSX always align allocations to 16 bytes */
- #elif !defined(__amd64__) && !defined(__APPLE__)
+ #elif !defined(__amd64__) && !defined(__APPLE__) && !defined(_AIX)
#define HAVE_MEMALIGN
#include <malloc.h>
#endif
diff --git a/extern/libopenjpeg/patches/fbsd.patch b/extern/libopenjpeg/patches/fbsd.patch
deleted file mode 100644
index 90e77600941..00000000000
--- a/extern/libopenjpeg/patches/fbsd.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-Index: extern/libopenjpeg/opj_malloc.h
-===================================================================
---- extern/libopenjpeg/opj_malloc.h (revision 27736)
-+++ extern/libopenjpeg/opj_malloc.h (working copy)
-@@ -76,7 +76,7 @@
- #if defined(__sun)
- #define HAVE_MEMALIGN
- #elif defined(__GNUC__)
-- #ifndef __APPLE__
-+ #if !defined(__APPLE__) && !defined(__FreeBSD__)
- #define HAVE_MEMALIGN
- #include <malloc.h>
- #endif
diff --git a/extern/libopenjpeg/patches/osx.patch b/extern/libopenjpeg/patches/osx.patch
deleted file mode 100644
index c518978eed6..00000000000
--- a/extern/libopenjpeg/patches/osx.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-Index: opj_malloc.h
-===================================================================
---- opj_malloc.h (revision 15089)
-+++ opj_malloc.h (working copy)
-@@ -76,8 +76,10 @@
- #if defined(__sun)
- #define HAVE_MEMALIGN
- #elif defined(__GNUC__)
-- #define HAVE_MEMALIGN
-- #include <malloc.h>
-+ #ifndef __APPLE__
-+ #define HAVE_MEMALIGN
-+ #include <malloc.h>
-+ #endif
- /* Linux x86_64 and OSX always align allocations to 16 bytes */
- #elif !defined(__amd64__) && !defined(__APPLE__)
- /* FIXME: Yes, this is a big assumption */
diff --git a/extern/libopenjpeg/t1.c b/extern/libopenjpeg/t1.c
index 477720412aa..ed9cdc3fea6 100644
--- a/extern/libopenjpeg/t1.c
+++ b/extern/libopenjpeg/t1.c
@@ -1577,6 +1577,7 @@ void t1_decode_cblks(
opj_free(cblk->segs);
} /* cblkno */
opj_free(precinct->cblks.dec);
+ precinct->cblks.dec = NULL;
} /* precno */
} /* bandno */
} /* resno */
diff --git a/extern/libopenjpeg/t2.c b/extern/libopenjpeg/t2.c
index 232a5437329..2585c3d56a6 100644
--- a/extern/libopenjpeg/t2.c
+++ b/extern/libopenjpeg/t2.c
@@ -30,6 +30,7 @@
*/
#include "opj_includes.h"
+#include <assert.h>
/** @defgroup T2 T2 - Implementation of a tier-2 coding */
/*@{*/
@@ -64,7 +65,7 @@ static int t2_encode_packet(opj_tcd_tile_t *tile, opj_tcp_t *tcp, opj_pi_iterato
@param cblksty
@param first
*/
-static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first);
+static opj_bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first);
/**
Decode a packet of a tile from a source buffer
@param t2 T2 handle
@@ -296,9 +297,17 @@ static int t2_encode_packet(opj_tcd_tile_t * tile, opj_tcp_t * tcp, opj_pi_itera
return (c - dest);
}
-static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) {
+static opj_bool t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int first) {
opj_tcd_seg_t* seg;
- cblk->segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t));
+ opj_tcd_seg_t* segs;
+ segs = (opj_tcd_seg_t*) opj_realloc(cblk->segs, (index + 1) * sizeof(opj_tcd_seg_t));
+
+ if (segs == NULL)
+ {
+ return OPJ_FALSE;
+ }
+ cblk->segs = segs;
+
seg = &cblk->segs[index];
seg->data = NULL;
seg->dataindex = 0;
@@ -316,6 +325,8 @@ static void t2_init_seg(opj_tcd_cblk_dec_t* cblk, int index, int cblksty, int fi
} else {
seg->maxpasses = 109;
}
+
+ return OPJ_TRUE;
}
static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_tile_t *tile,
@@ -330,13 +341,15 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
int precno = pi->precno; /* precinct value */
int layno = pi->layno; /* quality layer value */
- opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno];
-
unsigned char *hd = NULL;
int present;
opj_bio_t *bio = NULL; /* BIO component */
-
+
+ opj_tcd_resolution_t* res;
+ assert(&tile->comps[compno] != NULL);
+ res = &tile->comps[compno].resolutions[resno];
+
if (layno == 0) {
for (bandno = 0; bandno < res->numbands; bandno++) {
opj_tcd_band_t *band = &res->bands[bandno];
@@ -462,12 +475,22 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
cblk->numlenbits += increment;
segno = 0;
if (!cblk->numsegs) {
- t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1);
+ if (!t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 1))
+ {
+ opj_event_msg(t2->cinfo, EVT_ERROR, "Out of memory\n");
+ bio_destroy(bio);
+ return -999;
+ }
} else {
segno = cblk->numsegs - 1;
if (cblk->segs[segno].numpasses == cblk->segs[segno].maxpasses) {
++segno;
- t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0);
+ if (!t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0))
+ {
+ opj_event_msg(t2->cinfo, EVT_ERROR, "Out of memory\n");
+ bio_destroy(bio);
+ return -999;
+ }
}
}
n = cblk->numnewpasses;
@@ -478,7 +501,12 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
n -= cblk->segs[segno].numnewpasses;
if (n > 0) {
++segno;
- t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0);
+ if (!t2_init_seg(cblk, segno, tcp->tccps[compno].cblksty, 0))
+ {
+ opj_event_msg(t2->cinfo, EVT_ERROR, "Out of memory\n");
+ bio_destroy(bio);
+ return -999;
+ }
}
} while (n > 0);
}
@@ -714,7 +742,11 @@ int t2_decode_packets(opj_t2_t *t2, unsigned char *src, int len, int tileno, opj
} else {
e = 0;
}
- if(e == -999) return -999;
+ if(e == -999)
+ {
+ pi_destroy(pi, cp, tileno);
+ return -999;
+ }
/* progression in resolution */
image->comps[pi[pino].compno].resno_decoded =
(e > 0) ?
diff --git a/extern/libopenjpeg/tcd.c b/extern/libopenjpeg/tcd.c
index 18cdbc786bc..62904eb2c65 100644
--- a/extern/libopenjpeg/tcd.c
+++ b/extern/libopenjpeg/tcd.c
@@ -30,7 +30,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define _ISOC99_SOURCE /* lrintf is C99 */
#include "opj_includes.h"
+#include <assert.h>
void tcd_dump(FILE *fd, opj_tcd_t *tcd, opj_tcd_image_t * img) {
int tileno, compno, resno, bandno, precno;/*, cblkno;*/
@@ -249,7 +251,9 @@ void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int c
cbgwidthexpn = pdx - 1;
cbgheightexpn = pdy - 1;
}
-
+ (void)brcbgyend;
+ (void)brcbgxend;
+
cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn);
cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn);
@@ -333,8 +337,10 @@ void tcd_malloc_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int c
cblk->y0 = int_max(cblkystart, prc->y0);
cblk->x1 = int_min(cblkxend, prc->x1);
cblk->y1 = int_min(cblkyend, prc->y1);
- cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char));
+ cblk->data = (unsigned char*) opj_calloc(9728+2, sizeof(unsigned char));
/* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */
+ cblk->data[0] = 0;
+ cblk->data[1] = 0;
cblk->data += 2;
cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t));
cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t));
@@ -509,6 +515,8 @@ void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int cur
cbgwidthexpn = pdx - 1;
cbgheightexpn = pdy - 1;
}
+ (void)brcbgyend;
+ (void)brcbgxend;
cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn);
cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn);
@@ -594,6 +602,8 @@ void tcd_init_encode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp, int cur
cblk->y1 = int_min(cblkyend, prc->y1);
cblk->data = (unsigned char*) opj_calloc(8192+2, sizeof(unsigned char));
/* FIXME: mqc_init_enc and mqc_byteout underrun the buffer if we don't do this. Why? */
+ cblk->data[0] = 0;
+ cblk->data[1] = 0;
cblk->data += 2;
cblk->layers = (opj_tcd_layer_t*) opj_calloc(100, sizeof(opj_tcd_layer_t));
cblk->passes = (opj_tcd_pass_t*) opj_calloc(100, sizeof(opj_tcd_pass_t));
@@ -614,7 +624,7 @@ void tcd_malloc_decode(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp) {
tcd->image = image;
tcd->tcd_image->tw = cp->tw;
tcd->tcd_image->th = cp->th;
- tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_malloc(cp->tw * cp->th * sizeof(opj_tcd_tile_t));
+ tcd->tcd_image->tiles = (opj_tcd_tile_t *) opj_calloc(cp->tw * cp->th, sizeof(opj_tcd_tile_t));
/*
Allocate place to store the decoded data = final image
@@ -690,6 +700,12 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
opj_tccp_t *tccp = &tcp->tccps[compno];
opj_tcd_tilecomp_t *tilec = &tile->comps[compno];
+ if (tccp->numresolutions <= 0)
+ {
+ cp->tileno[tileno] = -1;
+ return;
+ }
+
/* border of each tile component (global) */
tilec->x0 = int_ceildiv(tile->x0, image->comps[compno].dx);
tilec->y0 = int_ceildiv(tile->y0, image->comps[compno].dy);
@@ -749,6 +765,8 @@ void tcd_malloc_decode_tile(opj_tcd_t *tcd, opj_image_t * image, opj_cp_t * cp,
cbgwidthexpn = pdx - 1;
cbgheightexpn = pdy - 1;
}
+ (void)brcbgyend;
+ (void)brcbgxend;
cblkwidthexpn = int_min(tccp->cblkw, cbgwidthexpn);
cblkheightexpn = int_min(tccp->cblkh, cbgheightexpn);
@@ -1370,16 +1388,31 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
if (l == -999) {
eof = 1;
opj_event_msg(tcd->cinfo, EVT_ERROR, "tcd_decode: incomplete bistream\n");
+ return OPJ_FALSE;
}
/*------------------TIER1-----------------*/
t1_time = opj_clock(); /* time needed to decode a tile */
t1 = t1_create(tcd->cinfo);
+ if (t1 == NULL)
+ {
+ opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
+ t1_destroy(t1);
+ return OPJ_FALSE;
+ }
+
for (compno = 0; compno < tile->numcomps; ++compno) {
opj_tcd_tilecomp_t* tilec = &tile->comps[compno];
/* The +3 is headroom required by the vectorized DWT */
tilec->data = (int*) opj_aligned_malloc((((tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0))+3) * sizeof(int));
+ if (tilec->data == NULL)
+ {
+ opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
+ t1_destroy(t1);
+ return OPJ_FALSE;
+ }
+
t1_decode_cblks(t1, tilec, &tcd->tcp->tccps[compno]);
}
t1_destroy(t1);
@@ -1394,13 +1427,15 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
int numres2decode;
if (tcd->cp->reduce != 0) {
- tcd->image->comps[compno].resno_decoded =
- tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
- if (tcd->image->comps[compno].resno_decoded < 0) {
+ if ( tile->comps[compno].numresolutions < ( tcd->cp->reduce - 1 ) ) {
opj_event_msg(tcd->cinfo, EVT_ERROR, "Error decoding tile. The number of resolutions to remove [%d+1] is higher than the number "
" of resolutions in the original codestream [%d]\nModify the cp_reduce parameter.\n", tcd->cp->reduce, tile->comps[compno].numresolutions);
return OPJ_FALSE;
}
+ else {
+ tcd->image->comps[compno].resno_decoded =
+ tile->comps[compno].numresolutions - tcd->cp->reduce - 1;
+ }
}
numres2decode = tcd->image->comps[compno].resno_decoded + 1;
@@ -1421,6 +1456,13 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
int n = (tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0);
if (tile->numcomps >= 3 ){
+ /* testcase 1336.pdf.asan.47.376 */
+ if ((tile->comps[0].x1 - tile->comps[0].x0) * (tile->comps[0].y1 - tile->comps[0].y0) < n ||
+ ( tile->comps[1].x1 - tile->comps[1].x0) * (tile->comps[1].y1 - tile->comps[1].y0) < n ||
+ ( tile->comps[2].x1 - tile->comps[2].x0) * (tile->comps[2].y1 - tile->comps[2].y0) < n) {
+ opj_event_msg(tcd->cinfo, EVT_ERROR, "Tiles don't all have the same dimension. Skip the MCT step.\n");
+ return OPJ_FALSE;
+ }
if (tcd->tcp->tccps[0].qmfbid == 1) {
mct_decode(
tile->comps[0].data,
@@ -1452,18 +1494,33 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
int tw = tilec->x1 - tilec->x0;
int w = imagec->w;
+ int i, j;
int offset_x = int_ceildivpow2(imagec->x0, imagec->factor);
int offset_y = int_ceildivpow2(imagec->y0, imagec->factor);
+ /* NR-DEC-2977.pdf.asan.67.2198.jp2-52-decode */
+ if( res->x0 - offset_x < 0 || res->x1 - offset_x < 0
+ || res->y0 - offset_y < 0 || res->y1 - offset_y < 0 )
+ {
+ opj_event_msg(tcd->cinfo, EVT_ERROR, "Impossible offsets %d / %d\n", offset_x, offset_y);
+ return OPJ_FALSE;
+ }
+ assert( 0 <= res->x0 - offset_x && 0 <= res->x1 - offset_x );
+ assert( 0 <= res->y0 - offset_y && 0 <= res->y1 - offset_y );
- int i, j;
if(!imagec->data){
imagec->data = (int*) opj_malloc(imagec->w * imagec->h * sizeof(int));
}
+ if (!imagec->data)
+ {
+ opj_event_msg(tcd->cinfo, EVT_ERROR, "Out of memory\n");
+ return OPJ_FALSE;
+ }
if(tcd->tcp->tccps[compno].qmfbid == 1) {
for(j = res->y0; j < res->y1; ++j) {
for(i = res->x0; i < res->x1; ++i) {
int v = tilec->data[i - res->x0 + (j - res->y0) * tw];
v += adjust;
+ /*assert( (i - offset_x) + (j - offset_y) * w >= 0 );*/
imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max);
}
}
@@ -1473,6 +1530,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw];
int v = lrintf(tmp);
v += adjust;
+ /*assert( (i - offset_x) + (j - offset_y) * w >= 0 );*/
imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max);
}
}
@@ -1492,32 +1550,51 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
void tcd_free_decode(opj_tcd_t *tcd) {
opj_tcd_image_t *tcd_image = tcd->tcd_image;
+ int i = 0;
+ for (i = 0; i < tcd_image->tw * tcd_image->th; i++)
+ {
+ tcd_free_decode_tile(tcd, i);
+ }
+
opj_free(tcd_image->tiles);
}
void tcd_free_decode_tile(opj_tcd_t *tcd, int tileno) {
- int compno,resno,bandno,precno;
+ int compno,resno,bandno,precno,cblkno;
opj_tcd_image_t *tcd_image = tcd->tcd_image;
opj_tcd_tile_t *tile = &tcd_image->tiles[tileno];
- for (compno = 0; compno < tile->numcomps; compno++) {
- opj_tcd_tilecomp_t *tilec = &tile->comps[compno];
- for (resno = 0; resno < tilec->numresolutions; resno++) {
- opj_tcd_resolution_t *res = &tilec->resolutions[resno];
- for (bandno = 0; bandno < res->numbands; bandno++) {
- opj_tcd_band_t *band = &res->bands[bandno];
- for (precno = 0; precno < res->ph * res->pw; precno++) {
- opj_tcd_precinct_t *prec = &band->precincts[precno];
- if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree);
- if (prec->incltree != NULL) tgt_destroy(prec->incltree);
+ if (tile->comps != NULL) {
+ for (compno = 0; compno < tile->numcomps; compno++) {
+ opj_tcd_tilecomp_t *tilec = &tile->comps[compno];
+ for (resno = 0; resno < tilec->numresolutions; resno++) {
+ opj_tcd_resolution_t *res = &tilec->resolutions[resno];
+ for (bandno = 0; bandno < res->numbands; bandno++) {
+ opj_tcd_band_t *band = &res->bands[bandno];
+ for (precno = 0; precno < res->ph * res->pw; precno++) {
+ opj_tcd_precinct_t *prec = &band->precincts[precno];
+ if (prec->cblks.dec != NULL) {
+ for (cblkno = 0; cblkno < prec->cw * prec->ch; ++cblkno) {
+ opj_tcd_cblk_dec_t* cblk = &prec->cblks.dec[cblkno];
+ opj_free(cblk->data);
+ opj_free(cblk->segs);
+ }
+ opj_free(prec->cblks.dec);
+ }
+ if (prec->imsbtree != NULL) tgt_destroy(prec->imsbtree);
+ if (prec->incltree != NULL) tgt_destroy(prec->incltree);
+
+
+ }
+ opj_free(band->precincts);
}
- opj_free(band->precincts);
}
+ opj_free(tilec->resolutions);
}
- opj_free(tilec->resolutions);
+ opj_free(tile->comps);
+ tile->comps = NULL;
}
- opj_free(tile->comps);
}
diff --git a/extern/libredcode/AUTHOR b/extern/libredcode/AUTHOR
deleted file mode 100644
index b3d20a4eb7a..00000000000
--- a/extern/libredcode/AUTHOR
+++ /dev/null
@@ -1 +0,0 @@
-Peter Schlaile * peter at schlaile dot de
diff --git a/extern/libredcode/CMakeLists.txt b/extern/libredcode/CMakeLists.txt
deleted file mode 100644
index c75523741ea..00000000000
--- a/extern/libredcode/CMakeLists.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Jacques Beaurain.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- .
-)
-
-set(INC_SYS
- ../libopenjpeg
-)
-
-set(SRC
- codec.c
- debayer.c
- format.c
-
- codec.h
- debayer.h
- format.h
-)
-
-add_definitions(${OPENJPEG_DEFINES})
-
-blender_add_lib(extern_redcode "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/libredcode/LICENSE b/extern/libredcode/LICENSE
deleted file mode 100644
index 14db8fc79db..00000000000
--- a/extern/libredcode/LICENSE
+++ /dev/null
@@ -1,340 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/extern/libredcode/NOTES b/extern/libredcode/NOTES
deleted file mode 100644
index 39101e0bd63..00000000000
--- a/extern/libredcode/NOTES
+++ /dev/null
@@ -1,23 +0,0 @@
-This is a redcode decoder written solely by looking at some
-R3D files that are floating around on the web.
-
-This decoder works with the files I tested, but I don't give
-any guarantee (especially, if RED decides to change the
-file format).
-
-That said: I found it a really nice idea of them, to make
-such a clear and comprehensible file layout.
-
-Choosing JPEG2000 as an encoding format and the way, they
-did YCbCr encoding of the sensor data is simply brilliant.
-
-My approach of decoding the sensor data is probably not
-so brilliant, but seems to work rather nicely (and sharply!).
-
-If someone finds a better way and/or RED decides to release
-specification, just go ahead and feel free to change it!
-
-Until that happens: simply enjoy opening RED footage within Blender!
-
--- Peter Schlaile, June 2008
-
diff --git a/extern/libredcode/SConscript b/extern/libredcode/SConscript
deleted file mode 100644
index 3fb78dbea0f..00000000000
--- a/extern/libredcode/SConscript
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/python
-
-import sys
-import os
-import shutil
-
-Import('env')
-
-sources = env.Glob('*.c')
-incs = '. ../libopenjpeg'
-
-env.BlenderLib ( libname='extern_redcode',
- sources=sources, includes=Split(incs),
- defines=[],
- libtype=['core','intern'],
- priority=[5, 5], compileflags = [])
diff --git a/extern/libredcode/codec.c b/extern/libredcode/codec.c
deleted file mode 100644
index 70c875ca991..00000000000
--- a/extern/libredcode/codec.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/* ***** BEGIN GPL LICENSE BLOCK *****
- *
- * Copyright 2008 Peter Schlaile
- *
- * This file is part of libredcode.
- *
- * Libredcode is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Libredcode is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with libredcode; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****/
-
-#include "codec.h"
-#include "format.h"
-#include "debayer.h"
-
-#include <openjpeg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-static void error_callback(const char *msg, void *client_data)
-{
- FILE *stream = (FILE*)client_data;
- fprintf(stream, "[R3D ERR] %s", msg);
-}
-
-static void warning_callback(const char *msg, void *client_data)
-{
- FILE *stream = (FILE*)client_data;
- fprintf(stream, "[R3D WARN] %s", msg);
-}
-
-static void info_callback(const char *msg, void *client_data)
-{
- (void)client_data;
- fprintf(stdout, "[R3D INFO] %s", msg);
-}
-
-#define J2K_CFMT 0
-#define JP2_CFMT 1
-#define JPT_CFMT 2
-
-struct redcode_frame_raw * redcode_decode_video_raw(
- struct redcode_frame * frame, int scale)
-{
- struct redcode_frame_raw * rv = NULL;
- opj_dparameters_t parameters; /* decompression parameters */
- opj_event_mgr_t event_mgr; /* event manager */
- opj_image_t *image = NULL;
- opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */
- opj_cio_t *cio = NULL;
-
- memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
- event_mgr.error_handler = error_callback;
- event_mgr.warning_handler = warning_callback;
- event_mgr.info_handler = info_callback;
-
- opj_set_default_decoder_parameters(&parameters);
-
- parameters.decod_format = JP2_CFMT;
-
- if (scale == 2) {
- parameters.cp_reduce = 1;
- } else if (scale == 4) {
- parameters.cp_reduce = 2;
- } else if (scale == 8) {
- parameters.cp_reduce = 3;
- }
-
- /* JPEG 2000 compressed image data */
-
- /* get a decoder handle */
- dinfo = opj_create_decompress(CODEC_JP2);
-
- /* catch events using our callbacks and give a local context */
- opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);
-
- /* setup the decoder decoding parameters using the current image
- and user parameters */
- opj_setup_decoder(dinfo, &parameters);
-
- /* open a byte stream */
- cio = opj_cio_open((opj_common_ptr)dinfo,
- frame->data + frame->offset, frame->length);
-
- image = opj_decode(dinfo, cio);
-
- if(!image) {
- fprintf(stderr,
- "ERROR -> j2k_to_image: failed to decode image!\n");
- opj_destroy_decompress(dinfo);
- opj_cio_close(cio);
- return 0;
- }
-
- /* close the byte stream */
- opj_cio_close(cio);
-
- /* free remaining structures */
- if(dinfo) {
- opj_destroy_decompress(dinfo);
- }
-
- if((image->numcomps * image->x1 * image->y1) == 0) {
- opj_image_destroy(image);
- return 0;
- }
-
- rv = (struct redcode_frame_raw *) calloc(
- 1, sizeof(struct redcode_frame_raw));
-
- rv->data = image;
- rv->width = image->comps[0].w;
- rv->height = image->comps[0].h;
-
- return rv;
-}
-
-int redcode_decode_video_float(struct redcode_frame_raw * frame,
- float * out, int scale)
-{
- int* planes[4];
- int i;
- opj_image_t *image = (opj_image_t*) frame->data;
-
- if (image->numcomps != 4) {
- fprintf(stderr, "R3D: need 4 planes, but got: %d\n",
- image->numcomps);
- return 0;
- }
-
- for (i = 0; i < 4; i++) {
- planes[i] = image->comps[i].data;
- }
-
- if (scale == 1) {
- redcode_ycbcr2rgb_fullscale(
- planes, frame->width, frame->height, out);
- } else if (scale == 2) {
- redcode_ycbcr2rgb_halfscale(
- planes, frame->width, frame->height, out);
- } else if (scale == 4) {
- redcode_ycbcr2rgb_quarterscale(
- planes, frame->width, frame->height, out);
- }
-
- opj_image_destroy(image);
-
- free(frame);
-
- return 1;
-}
-
-
-
diff --git a/extern/libredcode/codec.h b/extern/libredcode/codec.h
deleted file mode 100644
index 6f7092672ee..00000000000
--- a/extern/libredcode/codec.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* ***** BEGIN GPL LICENSE BLOCK *****
- *
- * Copyright 2008 Peter Schlaile
- *
- * This file is part of libredcode.
- *
- * Libredcode is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Libredcode is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Libredcode; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****/
-
-#ifndef __CODEC_H__
-#define __CODEC_H__
-
-struct redcode_frame;
-
-struct redcode_frame_raw {
- void * data;
- int width;
- int height;
-};
-
-/* do the JPEG2000 decompression into YCbCrY planes */
-struct redcode_frame_raw * redcode_decode_video_raw(
- struct redcode_frame * frame, int scale);
-
-/* finally decode RAW frame into out-buffer (which has to be allocated
- in advance)
-
- Keep in mind: frame_raw-width + height is half sized.
- (one pixel contains 2x2 bayer-sensor data)
-
- output-buffer should have room for
-
- scale = 1 : width * height * 4 * 4 * sizeof(float)
- scale = 2 : width * height * 4 * sizeof(float)
- scale = 4 : width * height * sizeof(float)
-
-*/
-
-int redcode_decode_video_float(struct redcode_frame_raw * frame,
- float * out, int scale);
-
-
-#endif
diff --git a/extern/libredcode/debayer.c b/extern/libredcode/debayer.c
deleted file mode 100644
index a236fed1749..00000000000
--- a/extern/libredcode/debayer.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/* ***** BEGIN GPL LICENSE BLOCK *****
- *
- * Copyright 2008 Peter Schlaile
- *
- * This file is part of libredcode.
- *
- * Libredcode is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Libredcode is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Libredcode; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****/
-
-#include "debayer.h"
-
-/* pretty simple but astonishingly very effective "debayer" function
- */
-
-void redcode_ycbcr2rgb_fullscale(
- int ** planes, int width, int height, float * out)
-{
- int x,y;
- int pix_max = 4096;
- int mask = pix_max - 1;
- float *o;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- int i = x + y*width;
- int i_p = (y > 0) ? i-width : i;
- int i_n = (y < (height-1)) ? i + width : i;
- float y1n = planes[0][i_n] & mask;
- float y1 = planes[0][i] & mask;
- float cb = (planes[1][i] & mask) - pix_max/2;
- float cr = (planes[2][i] & mask) - pix_max/2;
- float y2 = (planes[3][i] & mask);
- float y2p = (planes[3][i_p] & mask);
-
- float b_ = cb /(pix_max/2);
- float r_ = cr /(pix_max/2);
- float g_ = 0.0;
-
- float y_[4] = {y1 / pix_max,
- (y2 + y2p)/2 / pix_max,
- (y1 + y1n)/2 / pix_max,
- y2 / pix_max};
-
- int j;
- int yc = 0;
-
- o = out + (2*height-1-2*y)*2*4*width
- + x*2*4;
-
- for (j = 0; j < 8; j += 4) {
- o[j+0] = r_ + y_[yc];
- o[j+1] = g_ + y_[yc];
- o[j+2] = b_ + y_[yc];
- o[j+3] = 1.0;
- yc++;
- }
-
- o = out + (2*height-1-2*y)*2*4*width
- + x*2*4 - 2*4*width;
-
- for (j = 0; j < 8; j += 4) {
- o[j+0] = r_ + y_[yc];
- o[j+1] = g_ + y_[yc];
- o[j+2] = b_ + y_[yc];
- o[j+3] = 1.0;
- yc++;
- }
- }
- }
-}
-
-void redcode_ycbcr2rgb_halfscale(
- int ** planes, int width, int height, float * out)
-{
- int x,y;
- int pix_max = 4096;
- int mask = pix_max - 1;
-
- for (y = 0; y < height; y++) {
- float *o = out + width * (height - y - 1);
- for (x = 0; x < width; x++) {
- int i = y*height + x;
- float y1 = (planes[0][i] & mask);
- float cb = (planes[1][i] & mask) - pix_max/2;
- float cr = (planes[2][i] & mask) - pix_max/2;
- float y2 = (planes[3][i] & mask);
-
- float b_ = cb /(pix_max/2);
- float r_ = cr /(pix_max/2);
- float g_ = 0.0;
-
- float y = (y1 + y2)/2 / pix_max;
-
- *o++ = r_ + y;
- *o++ = g_ + y;
- *o++ = b_ + y;
- *o++ = 1.0;
- }
- }
-}
-
-
-void redcode_ycbcr2rgb_quarterscale(
- int ** planes, int width, int height, float * out)
-{
- int x,y;
- int pix_max = 4096;
- int mask = pix_max - 1;
-
- for (y = 0; y < height; y += 2) {
- float *o = out + (width/2) * (height/2 - y/2 - 1);
- for (x = 0; x < width; x += 2) {
- int i = y * width + x;
- float y1 = planes[0][i] & mask;
- float cb = (planes[1][i] & mask) - pix_max/2;
- float cr = (planes[2][i] & mask) - pix_max/2;
- float y2 = planes[3][i] & mask;
-
- float b_ = cb /(pix_max/2);
- float r_ = cr /(pix_max/2);
- float g_ = 0.0;
-
- float y = (y1 + y2)/2 / pix_max;
-
- *o++ = r_ + y;
- *o++ = g_ + y;
- *o++ = b_ + y;
- *o++ = 1.0;
- }
- }
-}
-
diff --git a/extern/libredcode/debayer.h b/extern/libredcode/debayer.h
deleted file mode 100644
index 31f3dd01fea..00000000000
--- a/extern/libredcode/debayer.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* ***** BEGIN GPL LICENSE BLOCK *****
- *
- * Copyright 2008 Peter Schlaile
- *
- * This file is part of libredcode.
- *
- * Libredcode is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Libredcode is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Libredcode; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****/
-
-#ifndef __DEBAYER_H__
-#define __DEBAYER_H__
-
-void redcode_ycbcr2rgb_fullscale(
- int ** planes, int width, int height, float * out);
-void redcode_ycbcr2rgb_halfscale(
- int ** planes, int width, int height, float * out);
-void redcode_ycbcr2rgb_quarterscale(
- int ** planes, int width, int height, float * out);
-
-#endif
diff --git a/extern/libredcode/format.c b/extern/libredcode/format.c
deleted file mode 100644
index 9a3023fa2c0..00000000000
--- a/extern/libredcode/format.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/* ***** BEGIN GPL LICENSE BLOCK *****
- *
- * Copyright 2008 Peter Schlaile
- *
- * This file is part of libredcode.
- *
- * Libredcode is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Libredcode is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Libredcode; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "format.h"
-
-struct red_reob {
- unsigned int len;
- unsigned int head;
-
- unsigned int rdvo;
- unsigned int rdvs;
- unsigned int rdao;
- unsigned int rdas;
-
- unsigned int unknown1;
- unsigned int unknown2;
- unsigned int totlen;
-
- unsigned int avgv;
- unsigned int avgs;
-
- unsigned int unknown3;
- unsigned int unknown4;
- unsigned int unknown5;
-};
-
-struct redcode_handle {
- FILE * fp;
- struct red_reob * reob;
- unsigned int * rdvo;
- unsigned int * rdvs;
- unsigned int * rdao;
- unsigned int * rdas;
- long cfra;
- long length;
-};
-
-unsigned int read_be32(unsigned int val)
-{
- unsigned char * v = (unsigned char*) & val;
-
- return (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
-}
-
-static unsigned char* read_packet(FILE * fp, char * expect)
-{
- unsigned int len;
- char head[5];
- unsigned char * rv;
-
- fread(&len, 4, 1, fp);
- fread(&head, 4, 1, fp);
-
- head[4] = 0;
-
- len = read_be32(len);
-
- if (strcmp(expect, head) != 0) {
- /* fprintf(stderr, "Read: %s, expect: %s\n", head, expect); */
- return NULL;
- }
-
- rv = (unsigned char*) malloc(len + 8);
-
- memcpy(rv, &len, 4);
- memcpy(rv + 4, &head, 4);
-
- fread(rv + 8, len, 1, fp);
-
- return rv;
-}
-
-static unsigned int * read_index_packet(FILE * fp, char * expect)
-{
- unsigned int * rv = (unsigned int*) read_packet(fp, expect);
- int i;
-
- if (!rv) {
- return NULL;
- }
-
- for (i = 2; i < rv[0]/4; i++) {
- rv[i] = read_be32(rv[i]);
- }
- return rv;
-}
-
-static struct red_reob * read_reob(FILE * fp)
-{
- fseek(fp, -0x38, SEEK_END);
-
- return (struct red_reob *) read_index_packet(fp, "REOB");
-}
-
-static unsigned int * read_index(FILE * fp, unsigned int i, char * expect)
-{
- fseek(fp, i, SEEK_SET);
-
- return (unsigned int*) read_index_packet(fp, expect);
-}
-
-static unsigned char * read_data(FILE * fp, unsigned int i, char * expect)
-{
- fseek(fp, i, SEEK_SET);
-
- return read_packet(fp, expect);
-}
-
-struct redcode_handle * redcode_open(const char * fname)
-{
- struct redcode_handle * rv = NULL;
- struct red_reob * reob = NULL;
- int i;
-
- FILE * fp = fopen(fname, "rb");
-
- if (!fp) {
- return NULL;
- }
-
- reob = read_reob(fp);
- if (!reob) {
- fclose(fp);
- return NULL;
- }
-
- rv = (struct redcode_handle*) calloc(1, sizeof(struct redcode_handle));
-
- rv->fp = fp;
- rv->reob = reob;
- rv->rdvo = read_index(fp, reob->rdvo, "RDVO");
- rv->rdvs = read_index(fp, reob->rdvs, "RDVS");
- rv->rdao = read_index(fp, reob->rdao, "RDAO");
- rv->rdas = read_index(fp, reob->rdas, "RDAS");
-
- if (!rv->rdvo || !rv->rdvs || !rv->rdao || !rv->rdas) {
- redcode_close(rv);
- return NULL;
- }
-
- for (i = 0; i < (rv->rdvo[0] - 8)/4; i++) {
- if (rv->rdvo[i + 2]) {
- rv->length = i;
- }
- }
-
- return rv;
-}
-
-void redcode_close(struct redcode_handle * handle)
-{
- if (handle->reob) {
- free(handle->reob);
- }
- if (handle->rdvo) {
- free(handle->rdvo);
- }
- if (handle->rdvs) {
- free(handle->rdvs);
- }
- if (handle->rdao) {
- free(handle->rdao);
- }
- if (handle->rdas) {
- free(handle->rdas);
- }
- fclose(handle->fp);
- free(handle);
-}
-
-long redcode_get_length(struct redcode_handle * handle)
-{
- return handle->length;
-}
-
-struct redcode_frame * redcode_read_video_frame(
- struct redcode_handle * handle, long frame)
-{
- struct redcode_frame * rv;
- unsigned char * data;
-
- if (frame > handle->rdvo[0]/4 || handle->rdvo[frame + 2] == 0) {
- return NULL;
- }
- data = read_data(handle->fp, handle->rdvo[frame + 2], "REDV");
- if (!data) {
- return NULL;
- }
-
- rv = (struct redcode_frame*) calloc(1, sizeof(struct redcode_frame));
-
- rv->offset = 12+8;
- rv->length = *(unsigned int*)data - rv->offset;
- rv->data = data;
-
- return rv;
-}
-
-struct redcode_frame * redcode_read_audio_frame(
- struct redcode_handle * handle, long frame)
-{
- struct redcode_frame * rv;
- unsigned char * data;
-
- if (frame > handle->rdao[0]/4 || handle->rdao[frame + 2] == 0) {
- return NULL;
- }
- data = read_data(handle->fp, handle->rdao[frame+2], "REDA");
- if (!data) {
- return NULL;
- }
-
- rv = (struct redcode_frame*) calloc(1, sizeof(struct redcode_frame));
-
- rv->offset = 24+8;
- rv->length = *(unsigned int*)data - rv->offset;
- rv->data = data;
-
- return rv;
-}
-
-void redcode_free_frame(struct redcode_frame * frame)
-{
- free(frame->data);
- free(frame);
-}
diff --git a/extern/libredcode/format.h b/extern/libredcode/format.h
deleted file mode 100644
index 473a2b1a8d9..00000000000
--- a/extern/libredcode/format.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ***** BEGIN GPL LICENSE BLOCK *****
- *
- * Copyright 2008 Peter Schlaile
- *
- * This file is part of libredcode.
- *
- * Libredcode is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Libredcode is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Libredcode; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * ***** END GPL LICENSE BLOCK *****/
-
-#ifndef __FORMAT_H__
-#define __FORMAT_H__
-
-struct redcode_handle;
-struct redcode_frame {
- unsigned int length;
- unsigned int offset;
- unsigned char * data;
-};
-
-struct redcode_handle * redcode_open(const char * fname);
-void redcode_close(struct redcode_handle * handle);
-
-long redcode_get_length(struct redcode_handle * handle);
-
-struct redcode_frame * redcode_read_video_frame(
- struct redcode_handle * handle, long frame);
-struct redcode_frame * redcode_read_audio_frame(
- struct redcode_handle * handle, long frame);
-
-void redcode_free_frame(struct redcode_frame * frame);
-
-
-#endif
diff --git a/extern/lzma/SConscript b/extern/lzma/SConscript
deleted file mode 100644
index d0cfed87cb6..00000000000
--- a/extern/lzma/SConscript
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/python
-Import ('env')
-
-sources = env.Glob('./*.c')
-
-defs = ''
-incs = ' . '
-
-env.BlenderLib ('extern_lzma', sources, Split(incs), Split(defs), libtype=['intern'], priority=[40] )
diff --git a/extern/lzo/SConscript b/extern/lzo/SConscript
deleted file mode 100644
index a87034d197a..00000000000
--- a/extern/lzo/SConscript
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/python
-Import ('env')
-
-sources = env.Glob('minilzo/*.c')
-
-defs = ''
-incs = ' include '
-
-env.BlenderLib ('extern_minilzo', sources, Split(incs), Split(defs), libtype=['intern'], priority=[40] )
diff --git a/extern/rangetree/SConscript b/extern/rangetree/SConscript
deleted file mode 100644
index 787decd599e..00000000000
--- a/extern/rangetree/SConscript
+++ /dev/null
@@ -1,9 +0,0 @@
-2#!/usr/bin/python
-Import ('env')
-
-sources = env.Glob('*.cc')
-
-incs = '.'
-defs = ''
-
-env.BlenderLib ('extern_rangetree', sources, Split(incs), Split(defs), libtype=['extern'], priority=[100] )
diff --git a/extern/recastnavigation/Recast/Include/Recast.h b/extern/recastnavigation/Recast/Include/Recast.h
index 4e20b0f0fff..6f18247d527 100644
--- a/extern/recastnavigation/Recast/Include/Recast.h
+++ b/extern/recastnavigation/Recast/Include/Recast.h
@@ -15,7 +15,7 @@
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
-
+
#ifndef RECAST_H
#define RECAST_H
@@ -27,8 +27,8 @@ static const float RC_PI = 3.14159265f;
enum rcLogCategory
{
RC_LOG_PROGRESS = 1, ///< A progress log entry.
- RC_LOG_WARNING, ///< A warning log entry.
- RC_LOG_ERROR, ///< An error log entry.
+ RC_LOG_WARNING, ///< A warning log entry.
+ RC_LOG_ERROR, ///< An error log entry.
};
/// Recast performance timer categories.
@@ -86,7 +86,7 @@ enum rcTimerLabel
/// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone)
RC_TIMER_BUILD_REGIONS_FILTER,
/// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers)
- RC_TIMER_BUILD_LAYERS,
+ RC_TIMER_BUILD_LAYERS,
/// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail)
RC_TIMER_BUILD_POLYMESHDETAIL,
/// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails)
@@ -95,7 +95,7 @@ enum rcTimerLabel
RC_MAX_TIMERS
};
-/// Provides an interface for optional logging and performance tracking of the Recast
+/// Provides an interface for optional logging and performance tracking of the Recast
/// build process.
/// @ingroup recast
class rcContext
@@ -103,39 +103,39 @@ class rcContext
public:
/// Contructor.
- /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true]
+ /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true]
inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {}
virtual ~rcContext() {}
/// Enables or disables logging.
- /// @param[in] state TRUE if logging should be enabled.
+ /// @param[in] state TRUE if logging should be enabled.
inline void enableLog(bool state) { m_logEnabled = state; }
/// Clears all log entries.
inline void resetLog() { if (m_logEnabled) doResetLog(); }
/// Logs a message.
- /// @param[in] category The category of the message.
- /// @param[in] format The message.
+ /// @param[in] category The category of the message.
+ /// @param[in] format The message.
void log(const rcLogCategory category, const char* format, ...);
/// Enables or disables the performance timers.
- /// @param[in] state TRUE if timers should be enabled.
+ /// @param[in] state TRUE if timers should be enabled.
inline void enableTimer(bool state) { m_timerEnabled = state; }
/// Clears all peformance timers. (Resets all to unused.)
inline void resetTimers() { if (m_timerEnabled) doResetTimers(); }
/// Starts the specified performance timer.
- /// @param label The category of timer.
+ /// @param label The category of the timer.
inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); }
/// Stops the specified performance timer.
- /// @param label The category of the timer.
+ /// @param label The category of the timer.
inline void stopTimer(const rcTimerLabel label) { if (m_timerEnabled) doStopTimer(label); }
/// Returns the total accumulated time of the specified performance timer.
- /// @param label The category of the timer.
+ /// @param label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; }
@@ -145,27 +145,27 @@ protected:
virtual void doResetLog() {}
/// Logs a message.
- /// @param[in] category The category of the message.
- /// @param[in] msg The formatted message.
- /// @param[in] len The length of the formatted message.
+ /// @param[in] category The category of the message.
+ /// @param[in] msg The formatted message.
+ /// @param[in] len The length of the formatted message.
virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {}
/// Clears all timers. (Resets all to unused.)
virtual void doResetTimers() {}
/// Starts the specified performance timer.
- /// @param[in] label The category of timer.
+ /// @param[in] label The category of timer.
virtual void doStartTimer(const rcTimerLabel /*label*/) {}
/// Stops the specified performance timer.
- /// @param[in] label The category of the timer.
+ /// @param[in] label The category of the timer.
virtual void doStopTimer(const rcTimerLabel /*label*/) {}
/// Returns the total accumulated time of the specified performance timer.
- /// @param[in] label The category of the timer.
+ /// @param[in] label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; }
-
+
/// True if logging is enabled.
bool m_logEnabled;
@@ -173,6 +173,26 @@ protected:
bool m_timerEnabled;
};
+/// A helper to first start a timer and then stop it when this helper goes out of scope.
+/// @see rcContext
+class rcScopedTimer
+{
+public:
+ /// Constructs an instance and starts the timer.
+ /// @param[in] ctx The context to use.
+ /// @param[in] label The category of the timer.
+ inline rcScopedTimer(rcContext* ctx, const rcTimerLabel label) : m_ctx(ctx), m_label(label) { m_ctx->startTimer(m_label); }
+ inline ~rcScopedTimer() { m_ctx->stopTimer(m_label); }
+
+private:
+ // Explicitly disabled copy constructor and copy assignment operator.
+ rcScopedTimer(const rcScopedTimer&);
+ rcScopedTimer& operator=(const rcScopedTimer&);
+
+ rcContext* const m_ctx;
+ const rcTimerLabel m_label;
+};
+
/// Specifies a configuration to use when performing Recast builds.
/// @ingroup recast
struct rcConfig
@@ -181,71 +201,71 @@ struct rcConfig
int width;
/// The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
- int height;
-
+ int height;
+
/// The width/height size of tile's on the xz-plane. [Limit: >= 0] [Units: vx]
- int tileSize;
-
+ int tileSize;
+
/// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx]
int borderSize;
- /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu]
+ /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu]
float cs;
/// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu]
float ch;
/// The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
- float bmin[3];
+ float bmin[3];
/// The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
float bmax[3];
- /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees]
+ /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees]
float walkableSlopeAngle;
- /// Minimum floor to 'ceiling' height that will still allow the floor area to
- /// be considered walkable. [Limit: >= 3] [Units: vx]
- int walkableHeight;
-
- /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx]
- int walkableClimb;
-
- /// The distance to erode/shrink the walkable area of the heightfield away from
- /// obstructions. [Limit: >=0] [Units: vx]
- int walkableRadius;
-
- /// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx]
- int maxEdgeLen;
-
- /// The maximum distance a simplfied contour's border edges should deviate
- /// the original raw contour. [Limit: >=0] [Units: wu]
- float maxSimplificationError;
-
- /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx]
- int minRegionArea;
-
- /// Any regions with a span count smaller than this value will, if possible,
- /// be merged with larger regions. [Limit: >=0] [Units: vx]
- int mergeRegionArea;
-
- /// The maximum number of vertices allowed for polygons generated during the
- /// contour to polygon conversion process. [Limit: >= 3]
+ /// Minimum floor to 'ceiling' height that will still allow the floor area to
+ /// be considered walkable. [Limit: >= 3] [Units: vx]
+ int walkableHeight;
+
+ /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx]
+ int walkableClimb;
+
+ /// The distance to erode/shrink the walkable area of the heightfield away from
+ /// obstructions. [Limit: >=0] [Units: vx]
+ int walkableRadius;
+
+ /// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx]
+ int maxEdgeLen;
+
+ /// The maximum distance a simplfied contour's border edges should deviate
+ /// the original raw contour. [Limit: >=0] [Units: vx]
+ float maxSimplificationError;
+
+ /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx]
+ int minRegionArea;
+
+ /// Any regions with a span count smaller than this value will, if possible,
+ /// be merged with larger regions. [Limit: >=0] [Units: vx]
+ int mergeRegionArea;
+
+ /// The maximum number of vertices allowed for polygons generated during the
+ /// contour to polygon conversion process. [Limit: >= 3]
int maxVertsPerPoly;
-
+
/// Sets the sampling distance to use when generating the detail mesh.
- /// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu]
+ /// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu]
float detailSampleDist;
-
+
/// The maximum distance the detail mesh surface should deviate from heightfield
- /// data. (For height detail only.) [Limit: >=0] [Units: wu]
+ /// data. (For height detail only.) [Limit: >=0] [Units: wu]
float detailSampleMaxError;
};
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
static const int RC_SPAN_HEIGHT_BITS = 13;
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
-static const int RC_SPAN_MAX_HEIGHT = (1<<RC_SPAN_HEIGHT_BITS)-1;
+static const int RC_SPAN_MAX_HEIGHT = (1 << RC_SPAN_HEIGHT_BITS) - 1;
/// The number of spans allocated per span spool.
/// @see rcSpanPool
@@ -255,10 +275,10 @@ static const int RC_SPANS_PER_POOL = 2048;
/// @see rcHeightfield
struct rcSpan
{
- unsigned int smin : 13; ///< The lower limit of the span. [Limit: < #smax]
- unsigned int smax : 13; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
- unsigned int area : 6; ///< The area id assigned to the span.
- rcSpan* next; ///< The next span higher up in column.
+ unsigned int smin : RC_SPAN_HEIGHT_BITS; ///< The lower limit of the span. [Limit: < #smax]
+ unsigned int smax : RC_SPAN_HEIGHT_BITS; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
+ unsigned int area : 6; ///< The area id assigned to the span.
+ rcSpan* next; ///< The next span higher up in column.
};
/// A memory pool used for quick allocation of spans within a heightfield.
@@ -273,18 +293,18 @@ struct rcSpanPool
/// @ingroup recast
struct rcHeightfield
{
- int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
+ int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
int height; ///< The height of the heightfield. (Along the z-axis in cell units.)
float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)]
- float cs; ///< The size of each cell. (On the xz-plane.)
+ float cs; ///< The size of each cell. (On the xz-plane.)
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
rcSpan** spans; ///< Heightfield of spans (width*height).
rcSpanPool* pools; ///< Linked list of span pools.
rcSpan* freelist; ///< The next free span.
};
-/// Provides information on the content of a cell column in a compact heightfield.
+/// Provides information on the content of a cell column in a compact heightfield.
struct rcCompactCell
{
unsigned int index : 24; ///< Index to the first span in the column.
@@ -295,7 +315,7 @@ struct rcCompactCell
struct rcCompactSpan
{
unsigned short y; ///< The lower extent of the span. (Measured from the heightfield's base.)
- unsigned short reg; ///< The id of the region the span belongs to. (Or zero if not in a region.)
+ unsigned short reg; ///< The id of the region the span belongs to. (Or zero if not in a region.)
unsigned int con : 24; ///< Packed neighbor connection data.
unsigned int h : 8; ///< The height of the span. (Measured from #y.)
};
@@ -304,17 +324,17 @@ struct rcCompactSpan
/// @ingroup recast
struct rcCompactHeightfield
{
- int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
+ int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
int height; ///< The height of the heightfield. (Along the z-axis in cell units.)
int spanCount; ///< The number of spans in the heightfield.
- int walkableHeight; ///< The walkable height used during the build of the field. (See: rcConfig::walkableHeight)
+ int walkableHeight; ///< The walkable height used during the build of the field. (See: rcConfig::walkableHeight)
int walkableClimb; ///< The walkable climb used during the build of the field. (See: rcConfig::walkableClimb)
int borderSize; ///< The AABB border size used during the build of the field. (See: rcConfig::borderSize)
- unsigned short maxDistance; ///< The maximum distance value of any span within the field.
- unsigned short maxRegions; ///< The maximum region id of any span within the field.
- float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
+ unsigned short maxDistance; ///< The maximum distance value of any span within the field.
+ unsigned short maxRegions; ///< The maximum region id of any span within the field.
+ float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)]
- float cs; ///< The size of each cell. (On the xz-plane.)
+ float cs; ///< The size of each cell. (On the xz-plane.)
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
rcCompactCell* cells; ///< Array of cells. [Size: #width*#height]
rcCompactSpan* spans; ///< Array of spans. [Size: #spanCount]
@@ -326,26 +346,26 @@ struct rcCompactHeightfield
/// @see rcHeightfieldLayerSet
struct rcHeightfieldLayer
{
- float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
+ float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)]
- float cs; ///< The size of each cell. (On the xz-plane.)
+ float cs; ///< The size of each cell. (On the xz-plane.)
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
- int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
+ int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
int height; ///< The height of the heightfield. (Along the z-axis in cell units.)
- int minx; ///< The minimum x-bounds of usable data.
- int maxx; ///< The maximum x-bounds of usable data.
- int miny; ///< The minimum y-bounds of usable data. (Along the z-axis.)
+ int minx; ///< The minimum x-bounds of usable data.
+ int maxx; ///< The maximum x-bounds of usable data.
+ int miny; ///< The minimum y-bounds of usable data. (Along the z-axis.)
int maxy; ///< The maximum y-bounds of usable data. (Along the z-axis.)
- int hmin; ///< The minimum height bounds of usable data. (Along the y-axis.)
+ int hmin; ///< The minimum height bounds of usable data. (Along the y-axis.)
int hmax; ///< The maximum height bounds of usable data. (Along the y-axis.)
- unsigned char* heights; ///< The heightfield. [Size: (width - borderSize*2) * (h - borderSize*2)]
+ unsigned char* heights; ///< The heightfield. [Size: width * height]
unsigned char* areas; ///< Area ids. [Size: Same as #heights]
unsigned char* cons; ///< Packed neighbor connection information. [Size: Same as #heights]
};
/// Represents a set of heightfield layers.
/// @ingroup recast
-/// @see rcAllocHeightfieldLayerSet, rcFreeHeightfieldLayerSet
+/// @see rcAllocHeightfieldLayerSet, rcFreeHeightfieldLayerSet
struct rcHeightfieldLayerSet
{
rcHeightfieldLayer* layers; ///< The layers in the set. [Size: #nlayers]
@@ -356,9 +376,9 @@ struct rcHeightfieldLayerSet
struct rcContour
{
int* verts; ///< Simplified contour vertex and connection data. [Size: 4 * #nverts]
- int nverts; ///< The number of vertices in the simplified contour.
+ int nverts; ///< The number of vertices in the simplified contour.
int* rverts; ///< Raw contour vertex and connection data. [Size: 4 * #nrverts]
- int nrverts; ///< The number of vertices in the raw contour.
+ int nrverts; ///< The number of vertices in the raw contour.
unsigned short reg; ///< The region id of the contour.
unsigned char area; ///< The area id of the contour.
};
@@ -371,17 +391,18 @@ struct rcContourSet
int nconts; ///< The number of contours in the set.
float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)]
- float cs; ///< The size of each cell. (On the xz-plane.)
+ float cs; ///< The size of each cell. (On the xz-plane.)
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
- int width; ///< The width of the set. (Along the x-axis in cell units.)
- int height; ///< The height of the set. (Along the z-axis in cell units.)
+ int width; ///< The width of the set. (Along the x-axis in cell units.)
+ int height; ///< The height of the set. (Along the z-axis in cell units.)
int borderSize; ///< The AABB border size used to generate the source data from which the contours were derived.
+ float maxError; ///< The max edge error that this contour set was simplified with.
};
-/// Represents a polygon mesh suitable for use in building a navigation mesh.
+/// Represents a polygon mesh suitable for use in building a navigation mesh.
/// @ingroup recast
struct rcPolyMesh
-{
+{
unsigned short* verts; ///< The mesh vertices. [Form: (x, y, z) * #nverts]
unsigned short* polys; ///< Polygon and neighbor data. [Length: #maxpolys * 2 * #nvp]
unsigned short* regs; ///< The region id assigned to each polygon. [Length: #maxpolys]
@@ -391,24 +412,25 @@ struct rcPolyMesh
int npolys; ///< The number of polygons.
int maxpolys; ///< The number of allocated polygons.
int nvp; ///< The maximum number of vertices per polygon.
- float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
- float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)]
- float cs; ///< The size of each cell. (On the xz-plane.)
+ float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
+ float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)]
+ float cs; ///< The size of each cell. (On the xz-plane.)
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
int borderSize; ///< The AABB border size used to generate the source data from which the mesh was derived.
+ float maxEdgeError; ///< The max error of the polygon edges in the mesh.
};
-/// Contains triangle meshes that represent detailed height data associated
+/// Contains triangle meshes that represent detailed height data associated
/// with the polygons in its associated polygon mesh object.
/// @ingroup recast
struct rcPolyMeshDetail
{
- unsigned int* meshes; ///< The sub-mesh data. [Size: 4*#nmeshes]
- float* verts; ///< The mesh vertices. [Size: 3*#nverts]
- unsigned char* tris; ///< The mesh triangles. [Size: 4*#ntris]
- int nmeshes; ///< The number of sub-meshes defined by #meshes.
- int nverts; ///< The number of vertices in #verts.
- int ntris; ///< The number of triangles in #tris.
+ unsigned int* meshes; ///< The sub-mesh data. [Size: 4*#nmeshes]
+ float* verts; ///< The mesh vertices. [Size: 3*#nverts]
+ unsigned char* tris; ///< The mesh triangles. [Size: 4*#ntris]
+ int nmeshes; ///< The number of sub-meshes defined by #meshes.
+ int nverts; ///< The number of vertices in #verts.
+ int ntris; ///< The number of triangles in #tris.
};
/// @name Allocation Functions
@@ -423,7 +445,7 @@ struct rcPolyMeshDetail
rcHeightfield* rcAllocHeightfield();
/// Frees the specified heightfield object using the Recast allocator.
-/// @param[in] hf A heightfield allocated using #rcAllocHeightfield
+/// @param[in] hf A heightfield allocated using #rcAllocHeightfield
/// @ingroup recast
/// @see rcAllocHeightfield
void rcFreeHeightField(rcHeightfield* hf);
@@ -435,7 +457,7 @@ void rcFreeHeightField(rcHeightfield* hf);
rcCompactHeightfield* rcAllocCompactHeightfield();
/// Frees the specified compact heightfield object using the Recast allocator.
-/// @param[in] chf A compact heightfield allocated using #rcAllocCompactHeightfield
+/// @param[in] chf A compact heightfield allocated using #rcAllocCompactHeightfield
/// @ingroup recast
/// @see rcAllocCompactHeightfield
void rcFreeCompactHeightfield(rcCompactHeightfield* chf);
@@ -447,7 +469,7 @@ void rcFreeCompactHeightfield(rcCompactHeightfield* chf);
rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet();
/// Frees the specified heightfield layer set using the Recast allocator.
-/// @param[in] lset A heightfield layer set allocated using #rcAllocHeightfieldLayerSet
+/// @param[in] lset A heightfield layer set allocated using #rcAllocHeightfieldLayerSet
/// @ingroup recast
/// @see rcAllocHeightfieldLayerSet
void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset);
@@ -459,7 +481,7 @@ void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset);
rcContourSet* rcAllocContourSet();
/// Frees the specified contour set using the Recast allocator.
-/// @param[in] cset A contour set allocated using #rcAllocContourSet
+/// @param[in] cset A contour set allocated using #rcAllocContourSet
/// @ingroup recast
/// @see rcAllocContourSet
void rcFreeContourSet(rcContourSet* cset);
@@ -471,7 +493,7 @@ void rcFreeContourSet(rcContourSet* cset);
rcPolyMesh* rcAllocPolyMesh();
/// Frees the specified polygon mesh using the Recast allocator.
-/// @param[in] pmesh A polygon mesh allocated using #rcAllocPolyMesh
+/// @param[in] pmesh A polygon mesh allocated using #rcAllocPolyMesh
/// @ingroup recast
/// @see rcAllocPolyMesh
void rcFreePolyMesh(rcPolyMesh* pmesh);
@@ -483,7 +505,7 @@ void rcFreePolyMesh(rcPolyMesh* pmesh);
rcPolyMeshDetail* rcAllocPolyMeshDetail();
/// Frees the specified detail mesh using the Recast allocator.
-/// @param[in] dmesh A detail mesh allocated using #rcAllocPolyMeshDetail
+/// @param[in] dmesh A detail mesh allocated using #rcAllocPolyMeshDetail
/// @ingroup recast
/// @see rcAllocPolyMeshDetail
void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh);
@@ -491,16 +513,24 @@ void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh);
/// @}
/// Heighfield border flag.
-/// If a heightfield region ID has this bit set, then the region is a border
+/// If a heightfield region ID has this bit set, then the region is a border
/// region and its spans are considered unwalkable.
/// (Used during the region and contour build process.)
/// @see rcCompactSpan::reg
static const unsigned short RC_BORDER_REG = 0x8000;
+/// Polygon touches multiple regions.
+/// If a polygon has this region ID it was merged with or created
+/// from polygons of different regions during the polymesh
+/// build step that removes redundant border vertices.
+/// (Used during the polymesh and detail polymesh build processes)
+/// @see rcPolyMesh::regs
+static const unsigned short RC_MULTIPLE_REGS = 0;
+
/// Border vertex flag.
/// If a region ID has this bit set, then the associated element lies on
-/// a tile border. If a contour vertex's region ID has this bit set, the
-/// vertex will later be removed in order to match the segments and vertices
+/// a tile border. If a contour vertex's region ID has this bit set, the
+/// vertex will later be removed in order to match the segments and vertices
/// at tile boundaries.
/// (Used during the build process.)
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
@@ -533,13 +563,13 @@ static const int RC_CONTOUR_REG_MASK = 0xffff;
static const unsigned short RC_MESH_NULL_IDX = 0xffff;
/// Represents the null area.
-/// When a data element is given this value it is considered to no longer be
+/// When a data element is given this value it is considered to no longer be
/// assigned to a usable area. (E.g. It is unwalkable.)
static const unsigned char RC_NULL_AREA = 0;
-/// The default area id used to indicate a walkable polygon.
-/// This is also the maximum allowed area id, and the only non-null area id
-/// recognized by some steps in the build process.
+/// The default area id used to indicate a walkable polygon.
+/// This is also the maximum allowed area id, and the only non-null area id
+/// recognized by some steps in the build process.
static const unsigned char RC_WALKABLE_AREA = 63;
/// The value returned by #rcGetCon if the specified direction is not connected
@@ -549,58 +579,58 @@ static const int RC_NOT_CONNECTED = 0x3f;
/// @name General helper functions
/// @{
+/// Used to ignore a function parameter. VS complains about unused parameters
+/// and this silences the warning.
+/// @param [in] _ Unused parameter
+template<class T> void rcIgnoreUnused(const T&) { }
+
/// Swaps the values of the two parameters.
-/// @param[in,out] a Value A
-/// @param[in,out] b Value B
+/// @param[in,out] a Value A
+/// @param[in,out] b Value B
template<class T> inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; }
/// Returns the minimum of two values.
-/// @param[in] a Value A
-/// @param[in] b Value B
+/// @param[in] a Value A
+/// @param[in] b Value B
/// @return The minimum of the two values.
template<class T> inline T rcMin(T a, T b) { return a < b ? a : b; }
/// Returns the maximum of two values.
-/// @param[in] a Value A
-/// @param[in] b Value B
+/// @param[in] a Value A
+/// @param[in] b Value B
/// @return The maximum of the two values.
template<class T> inline T rcMax(T a, T b) { return a > b ? a : b; }
/// Returns the absolute value.
-/// @param[in] a The value.
+/// @param[in] a The value.
/// @return The absolute value of the specified value.
template<class T> inline T rcAbs(T a) { return a < 0 ? -a : a; }
-/// Return the square of a value.
-/// @param[in] a The value.
+/// Returns the square of the value.
+/// @param[in] a The value.
/// @return The square of the value.
template<class T> inline T rcSqr(T a) { return a*a; }
/// Clamps the value to the specified range.
-/// @param[in] v The value to clamp.
-/// @param[in] mn The minimum permitted return value.
-/// @param[in] mx The maximum permitted return value.
+/// @param[in] v The value to clamp.
+/// @param[in] mn The minimum permitted return value.
+/// @param[in] mx The maximum permitted return value.
/// @return The value, clamped to the specified range.
template<class T> inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
/// Returns the square root of the value.
-/// @param[in] x The value.
+/// @param[in] x The value.
/// @return The square root of the vlaue.
float rcSqrt(float x);
-/// Not documented. Internal use only.
-/// @param[in] x Not documented.
-/// @return Not documented.
-inline int rcAlign4(int x) { return (x+3) & ~3; }
-
/// @}
/// @name Vector helper functions.
/// @{
-/// Derives the cross product of two vectors. (v1 x v2)
-/// @param[out] dest The cross product. [(x, y, z)]
-/// @param[in] v1 A Vector [(x, y, z)]
-/// @param[in] v2 A vector [(x, y, z)]
+/// Derives the cross product of two vectors. (@p v1 x @p v2)
+/// @param[out] dest The cross product. [(x, y, z)]
+/// @param[in] v1 A Vector [(x, y, z)]
+/// @param[in] v2 A vector [(x, y, z)]
inline void rcVcross(float* dest, const float* v1, const float* v2)
{
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
@@ -608,20 +638,20 @@ inline void rcVcross(float* dest, const float* v1, const float* v2)
dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
-/// Derives the dot product of two vectors. (v1 . v2)
-/// @param[in] v1 A Vector [(x, y, z)]
-/// @param[in] v2 A vector [(x, y, z)]
-/// @return The dot product.
+/// Derives the dot product of two vectors. (@p v1 . @p v2)
+/// @param[in] v1 A Vector [(x, y, z)]
+/// @param[in] v2 A vector [(x, y, z)]
+/// @return The dot product.
inline float rcVdot(const float* v1, const float* v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
-/// Performs a scaled vector addition. (v1 + (v2 * s))
-/// @param[out] dest The result vector. [(x, y, z)]
-/// @param[in] v1 The base vector [(x, y, z)]
-/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
-/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
+/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
+/// @param[out] dest The result vector. [(x, y, z)]
+/// @param[in] v1 The base vector. [(x, y, z)]
+/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
+/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
inline void rcVmad(float* dest, const float* v1, const float* v2, const float s)
{
dest[0] = v1[0]+v2[0]*s;
@@ -630,9 +660,9 @@ inline void rcVmad(float* dest, const float* v1, const float* v2, const float s)
}
/// Performs a vector addition. (@p v1 + @p v2)
-/// @param[out] dest The result vector. [(x, y, z)]
-/// @param[in] v1 The base vector [(x, y, z)]
-/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
+/// @param[out] dest The result vector. [(x, y, z)]
+/// @param[in] v1 The base vector. [(x, y, z)]
+/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
inline void rcVadd(float* dest, const float* v1, const float* v2)
{
dest[0] = v1[0]+v2[0];
@@ -641,9 +671,9 @@ inline void rcVadd(float* dest, const float* v1, const float* v2)
}
/// Performs a vector subtraction. (@p v1 - @p v2)
-/// @param[out] dest The result vector. [(x, y, z)]
-/// @param[in] v1 The base vector [(x, y, z)]
-/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
+/// @param[out] dest The result vector. [(x, y, z)]
+/// @param[in] v1 The base vector. [(x, y, z)]
+/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
inline void rcVsub(float* dest, const float* v1, const float* v2)
{
dest[0] = v1[0]-v2[0];
@@ -652,8 +682,8 @@ inline void rcVsub(float* dest, const float* v1, const float* v2)
}
/// Selects the minimum value of each element from the specified vectors.
-/// @param[in, out] mn A vector. (Will be updated with the result.) [(x, y, z)]
-/// @param[in] v A vector. [(x, y, z)]
+/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
+/// @param[in] v A vector. [(x, y, z)]
inline void rcVmin(float* mn, const float* v)
{
mn[0] = rcMin(mn[0], v[0]);
@@ -662,8 +692,8 @@ inline void rcVmin(float* mn, const float* v)
}
/// Selects the maximum value of each element from the specified vectors.
-/// @param[in, out] mx A vector. (Will be updated with the result.) [(x, y, z)]
-/// @param[in] v A vector. [(x, y, z)]
+/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
+/// @param[in] v A vector. [(x, y, z)]
inline void rcVmax(float* mx, const float* v)
{
mx[0] = rcMax(mx[0], v[0]);
@@ -672,8 +702,8 @@ inline void rcVmax(float* mx, const float* v)
}
/// Performs a vector copy.
-/// @param[out] dest The result. [(x, y, z)]
-/// @param[in] v The vector to copy [(x, y, z)]
+/// @param[out] dest The result. [(x, y, z)]
+/// @param[in] v The vector to copy. [(x, y, z)]
inline void rcVcopy(float* dest, const float* v)
{
dest[0] = v[0];
@@ -682,9 +712,9 @@ inline void rcVcopy(float* dest, const float* v)
}
/// Returns the distance between two points.
-/// @param[in] v1 A point. [(x, y, z)]
-/// @param[in] v2 A point. [(x, y, z)]
-/// @return The distance between the two points.
+/// @param[in] v1 A point. [(x, y, z)]
+/// @param[in] v2 A point. [(x, y, z)]
+/// @return The distance between the two points.
inline float rcVdist(const float* v1, const float* v2)
{
float dx = v2[0] - v1[0];
@@ -694,9 +724,9 @@ inline float rcVdist(const float* v1, const float* v2)
}
/// Returns the square of the distance between two points.
-/// @param[in] v1 A point. [(x, y, z)]
-/// @param[in] v2 A point. [(x, y, z)]
-/// @return The square of the distance between the two points.
+/// @param[in] v1 A point. [(x, y, z)]
+/// @param[in] v2 A point. [(x, y, z)]
+/// @return The square of the distance between the two points.
inline float rcVdistSqr(const float* v1, const float* v2)
{
float dx = v2[0] - v1[0];
@@ -706,7 +736,7 @@ inline float rcVdistSqr(const float* v1, const float* v2)
}
/// Normalizes the vector.
-/// @param[in,out] v The vector to normalize. [(x, y, z)]
+/// @param[in,out] v The vector to normalize. [(x, y, z)]
inline void rcVnormalize(float* v)
{
float d = 1.0f / rcSqrt(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2]));
@@ -715,17 +745,6 @@ inline void rcVnormalize(float* v)
v[2] *= d;
}
-/// Not documented. Internal use only.
-/// @param[in] p0 Not documented.
-/// @param[in] p1 Not documented.
-/// @return Not documented.
-inline bool rcVequal(const float* p0, const float* p1)
-{
- static const float thr = rcSqr(1.0f/16384.0f);
- const float d = rcVdistSqr(p0, p1);
- return d < thr;
-}
-
/// @}
/// @name Heightfield Functions
/// @see rcHeightfield
@@ -733,31 +752,32 @@ inline bool rcVequal(const float* p0, const float* p1)
/// Calculates the bounding box of an array of vertices.
/// @ingroup recast
-/// @param[in] verts An array of vertices. [(x, y, z) * @p nv]
-/// @param[in] nv The number of vertices in the @p verts array.
-/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
-/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[in] verts An array of vertices. [(x, y, z) * @p nv]
+/// @param[in] nv The number of vertices in the @p verts array.
+/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax);
/// Calculates the grid size based on the bounding box and grid cell size.
/// @ingroup recast
-/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
-/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
-/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu]
-/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx]
-/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx]
+/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu]
+/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx]
+/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx]
void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h);
/// Initializes a new heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in,out] hf The allocated heightfield to initialize.
-/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx]
-/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
-/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
-/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
-/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu]
-/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu]
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] hf The allocated heightfield to initialize.
+/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx]
+/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
+/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
+/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
+/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu]
+/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu]
+/// @returns True if the operation completed successfully.
bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
const float* bmin, const float* bmax,
float cs, float ch);
@@ -765,133 +785,138 @@ bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int heigh
/// Sets the area id of all triangles with a slope below the specified value
/// to #RC_WALKABLE_AREA.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. [Limits: 0 <= value < 90]
-/// [Units: Degrees]
-/// @param[in] verts The vertices. [(x, y, z) * @p nv]
-/// @param[in] nv The number of vertices.
-/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
-/// @param[in] nt The number of triangles.
-/// @param[out] areas The triangle area ids. [Length: >= @p nt]
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable.
+/// [Limits: 0 <= value < 90] [Units: Degrees]
+/// @param[in] verts The vertices. [(x, y, z) * @p nv]
+/// @param[in] nv The number of vertices.
+/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] nt The number of triangles.
+/// @param[out] areas The triangle area ids. [Length: >= @p nt]
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
- const int* tris, int nt, unsigned char* areas);
+ const int* tris, int nt, unsigned char* areas);
/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. [Limits: 0 <= value < 90]
-/// [Units: Degrees]
-/// @param[in] verts The vertices. [(x, y, z) * @p nv]
-/// @param[in] nv The number of vertices.
-/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
-/// @param[in] nt The number of triangles.
-/// @param[out] areas The triangle area ids. [Length: >= @p nt]
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable.
+/// [Limits: 0 <= value < 90] [Units: Degrees]
+/// @param[in] verts The vertices. [(x, y, z) * @p nv]
+/// @param[in] nv The number of vertices.
+/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] nt The number of triangles.
+/// @param[out] areas The triangle area ids. [Length: >= @p nt]
void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
- const int* tris, int nt, unsigned char* areas);
+ const int* tris, int nt, unsigned char* areas);
/// Adds a span to the specified heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in,out] hf An initialized heightfield.
-/// @param[in] x The width index where the span is to be added.
-/// [Limits: 0 <= value < rcHeightfield::width]
-/// @param[in] y The height index where the span is to be added.
-/// [Limits: 0 <= value < rcHeightfield::height]
-/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx]
-/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx]
-/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA)
-/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx]
-void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] hf An initialized heightfield.
+/// @param[in] x The width index where the span is to be added.
+/// [Limits: 0 <= value < rcHeightfield::width]
+/// @param[in] y The height index where the span is to be added.
+/// [Limits: 0 <= value < rcHeightfield::height]
+/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx]
+/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx]
+/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA)
+/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
const unsigned short smin, const unsigned short smax,
const unsigned char area, const int flagMergeThr);
/// Rasterizes a triangle into the specified heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] v0 Triangle vertex 0 [(x, y, z)]
-/// @param[in] v1 Triangle vertex 1 [(x, y, z)]
-/// @param[in] v2 Triangle vertex 2 [(x, y, z)]
-/// @param[in] area The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA]
-/// @param[in, out] solid An initialized heightfield.
-/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
-/// [Limit: >= 0] [Units: vx]
-void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] v0 Triangle vertex 0 [(x, y, z)]
+/// @param[in] v1 Triangle vertex 1 [(x, y, z)]
+/// @param[in] v2 Triangle vertex 2 [(x, y, z)]
+/// @param[in] area The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA]
+/// @param[in,out] solid An initialized heightfield.
+/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& solid,
const int flagMergeThr = 1);
/// Rasterizes an indexed triangle mesh into the specified heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] verts The vertices. [(x, y, z) * @p nv]
-/// @param[in] nv The number of vertices.
-/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
-/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
-/// @param[in] nt The number of triangles.
-/// @param[in, out] solid An initialized heightfield.
-/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
-/// [Limit: >= 0] [Units: vx]
-void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] verts The vertices. [(x, y, z) * @p nv]
+/// @param[in] nv The number of vertices.
+/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
+/// @param[in] nt The number of triangles.
+/// @param[in,out] solid An initialized heightfield.
+/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
const int* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr = 1);
/// Rasterizes an indexed triangle mesh into the specified heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] verts The vertices. [(x, y, z) * @p nv]
-/// @param[in] nv The number of vertices.
-/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
-/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
-/// @param[in] nt The number of triangles.
-/// @param[in, out] solid An initialized heightfield.
-/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
-/// [Limit: >= 0] [Units: vx]
-void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] verts The vertices. [(x, y, z) * @p nv]
+/// @param[in] nv The number of vertices.
+/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
+/// @param[in] nt The number of triangles.
+/// @param[in,out] solid An initialized heightfield.
+/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
const unsigned short* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr = 1);
/// Rasterizes triangles into the specified heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt]
-/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
-/// @param[in] nt The number of triangles.
-/// @param[in, out] solid An initialized heightfield.
-/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
-/// [Limit: >= 0] [Units: vx]
-void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt]
+/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
+/// @param[in] nt The number of triangles.
+/// @param[in,out] solid An initialized heightfield.
+/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr = 1);
-/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor.
+/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
-/// [Limit: >=0] [Units: vx]
-/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
+/// [Limit: >=0] [Units: vx]
+/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid);
-/// Marks spans that are ledges as not-walkable.
+/// Marks spans that are ledges as not-walkable.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
-/// be considered walkable. [Limit: >= 3] [Units: vx]
-/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
-/// [Limit: >=0] [Units: vx]
-/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
+/// be considered walkable. [Limit: >= 3] [Units: vx]
+/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
+/// [Limit: >=0] [Units: vx]
+/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight,
const int walkableClimb, rcHeightfield& solid);
-/// Marks walkable spans as not walkable if the clearence above the span is less than the specified height.
+/// Marks walkable spans as not walkable if the clearence above the span is less than the specified height.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
-/// be considered walkable. [Limit: >= 3] [Units: vx]
-/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
+/// be considered walkable. [Limit: >= 3] [Units: vx]
+/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid);
/// Returns the number of spans contained in the specified heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] hf An initialized heightfield.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] hf An initialized heightfield.
/// @returns The number of spans in the heightfield.
int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf);
@@ -902,105 +927,128 @@ int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf);
/// Builds a compact heightfield representing open space, from a heightfield representing solid space.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
-/// to be considered walkable. [Limit: >= 3] [Units: vx]
-/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
-/// [Limit: >=0] [Units: vx]
-/// @param[in] hf The heightfield to be compacted.
-/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
+/// to be considered walkable. [Limit: >= 3] [Units: vx]
+/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
+/// [Limit: >=0] [Units: vx]
+/// @param[in] hf The heightfield to be compacted.
+/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
rcHeightfield& hf, rcCompactHeightfield& chf);
-/// Erodes the walkable area within the heightfield by the specified radius.
+/// Erodes the walkable area within the heightfield by the specified radius.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx]
-/// @param[in,out] chf The populated compact heightfield to erode.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx]
+/// @param[in,out] chf The populated compact heightfield to erode.
/// @returns True if the operation completed successfully.
bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf);
/// Applies a median filter to walkable area types (based on area id), removing noise.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in,out] chf A populated compact heightfield.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] chf A populated compact heightfield.
/// @returns True if the operation completed successfully.
bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf);
-/// Applies an area id to all spans within the specified bounding box. (AABB)
+/// Applies an area id to all spans within the specified bounding box. (AABB)
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] bmin The minimum of the bounding box. [(x, y, z)]
-/// @param[in] bmax The maximum of the bounding box. [(x, y, z)]
-/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
-/// @param[in,out] chf A populated compact heightfield.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] bmin The minimum of the bounding box. [(x, y, z)]
+/// @param[in] bmax The maximum of the bounding box. [(x, y, z)]
+/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
+/// @param[in,out] chf A populated compact heightfield.
void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId,
rcCompactHeightfield& chf);
-/// Applies the area id to the all spans within the specified convex polygon.
+/// Applies the area id to the all spans within the specified convex polygon.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] verts The vertices of the polygon [Fomr: (x, y, z) * @p nverts]
-/// @param[in] nverts The number of vertices in the polygon.
-/// @param[in] hmin The height of the base of the polygon.
-/// @param[in] hmax The height of the top of the polygon.
-/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
-/// @param[in,out] chf A populated compact heightfield.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] verts The vertices of the polygon [Fomr: (x, y, z) * @p nverts]
+/// @param[in] nverts The number of vertices in the polygon.
+/// @param[in] hmin The height of the base of the polygon.
+/// @param[in] hmax The height of the top of the polygon.
+/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
+/// @param[in,out] chf A populated compact heightfield.
void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
const float hmin, const float hmax, unsigned char areaId,
rcCompactHeightfield& chf);
+/// Helper function to offset voncex polygons for rcMarkConvexPolyArea.
+/// @ingroup recast
+/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts]
+/// @param[in] nverts The number of vertices in the polygon.
+/// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value]
+/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts.
+/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts.
+int rcOffsetPoly(const float* verts, const int nverts, const float offset,
+ float* outVerts, const int maxOutVerts);
+
/// Applies the area id to all spans within the specified cylinder.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)]
-/// @param[in] r The radius of the cylinder.
-/// @param[in] h The height of the cylinder.
-/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
-/// @param[in,out] chf A populated compact heightfield.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)]
+/// @param[in] r The radius of the cylinder.
+/// @param[in] h The height of the cylinder.
+/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
+/// @param[in,out] chf A populated compact heightfield.
void rcMarkCylinderArea(rcContext* ctx, const float* pos,
const float r, const float h, unsigned char areaId,
rcCompactHeightfield& chf);
-/// Builds the distance field for the specified compact heightfield.
+/// Builds the distance field for the specified compact heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in,out] chf A populated compact heightfield.
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] chf A populated compact heightfield.
/// @returns True if the operation completed successfully.
bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf);
-/// Builds region data for the heightfield using watershed partitioning.
+/// Builds region data for the heightfield using watershed partitioning.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in,out] chf A populated compact heightfield.
-/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx]
-/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. [Limit: >=0]
-/// [Units: vx].
-/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible,
-/// be merged with larger regions. [Limit: >=0] [Units: vx]
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] chf A populated compact heightfield.
+/// @param[in] borderSize The size of the non-navigable border around the heightfield.
+/// [Limit: >=0] [Units: vx]
+/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas.
+/// [Limit: >=0] [Units: vx].
+/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible,
+/// be merged with larger regions. [Limit: >=0] [Units: vx]
/// @returns True if the operation completed successfully.
bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int minRegionArea, const int mergeRegionArea);
+/// Builds region data for the heightfield by partitioning the heightfield in non-overlapping layers.
+/// @ingroup recast
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] chf A populated compact heightfield.
+/// @param[in] borderSize The size of the non-navigable border around the heightfield.
+/// [Limit: >=0] [Units: vx]
+/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas.
+/// [Limit: >=0] [Units: vx].
+/// @returns True if the operation completed successfully.
+bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
+ const int borderSize, const int minRegionArea);
+
/// Builds region data for the heightfield using simple monotone partitioning.
-/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in,out] chf A populated compact heightfield.
-/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx]
-/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. [Limit: >=0]
-/// [Units: vx].
-/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible,
-/// be merged with larger regions. [Limit: >=0] [Units: vx]
+/// @ingroup recast
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in,out] chf A populated compact heightfield.
+/// @param[in] borderSize The size of the non-navigable border around the heightfield.
+/// [Limit: >=0] [Units: vx]
+/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas.
+/// [Limit: >=0] [Units: vx].
+/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible,
+/// be merged with larger regions. [Limit: >=0] [Units: vx]
/// @returns True if the operation completed successfully.
bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int minRegionArea, const int mergeRegionArea);
-
/// Sets the neighbor connection data for the specified direction.
-/// @param[in] s The span to update.
-/// @param[in] dir The direction to set. [Limits: 0 <= value < 4]
-/// @param[in] i The index of the neighbor span.
+/// @param[in] s The span to update.
+/// @param[in] dir The direction to set. [Limits: 0 <= value < 4]
+/// @param[in] i The index of the neighbor span.
inline void rcSetCon(rcCompactSpan& s, int dir, int i)
{
const unsigned int shift = (unsigned int)dir*6;
@@ -1009,10 +1057,10 @@ inline void rcSetCon(rcCompactSpan& s, int dir, int i)
}
/// Gets neighbor connection data for the specified direction.
-/// @param[in] s The span to check.
-/// @param[in] dir The direction to check. [Limits: 0 <= value < 4]
+/// @param[in] s The span to check.
+/// @param[in] dir The direction to check. [Limits: 0 <= value < 4]
/// @return The neighbor connection data for the specified direction,
-/// or #RC_NOT_CONNECTED if there is no connection.
+/// or #RC_NOT_CONNECTED if there is no connection.
inline int rcGetCon(const rcCompactSpan& s, int dir)
{
const unsigned int shift = (unsigned int)dir*6;
@@ -1020,25 +1068,35 @@ inline int rcGetCon(const rcCompactSpan& s, int dir)
}
/// Gets the standard width (x-axis) offset for the specified direction.
-/// @param[in] dir The direction. [Limits: 0 <= value < 4]
+/// @param[in] dir The direction. [Limits: 0 <= value < 4]
/// @return The width offset to apply to the current cell position to move
-/// in the direction.
+/// in the direction.
inline int rcGetDirOffsetX(int dir)
{
- const int offset[4] = { -1, 0, 1, 0, };
+ static const int offset[4] = { -1, 0, 1, 0, };
return offset[dir&0x03];
}
/// Gets the standard height (z-axis) offset for the specified direction.
-/// @param[in] dir The direction. [Limits: 0 <= value < 4]
+/// @param[in] dir The direction. [Limits: 0 <= value < 4]
/// @return The height offset to apply to the current cell position to move
-/// in the direction.
+/// in the direction.
inline int rcGetDirOffsetY(int dir)
{
- const int offset[4] = { 0, 1, 0, -1 };
+ static const int offset[4] = { 0, 1, 0, -1 };
return offset[dir&0x03];
}
+/// Gets the direction for the specified offset. One of x and y should be 0.
+/// @param[in] x The x offset. [Limits: -1 <= value <= 1]
+/// @param[in] y The y offset. [Limits: -1 <= value <= 1]
+/// @return The direction that represents the offset.
+inline int rcGetDirForOffset(int x, int y)
+{
+ static const int dirs[5] = { 3, 0, -1, 2, 1 };
+ return dirs[((y+1)<<1)+x];
+}
+
/// @}
/// @name Layer, Contour, Polymesh, and Detail Mesh Functions
/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail
@@ -1046,72 +1104,80 @@ inline int rcGetDirOffsetY(int dir)
/// Builds a layer set from the specified compact heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] chf A fully built compact heightfield.
-/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0]
-/// [Units: vx]
-/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
-/// to be considered walkable. [Limit: >= 3] [Units: vx]
-/// @param[out] lset The resulting layer set. (Must be pre-allocated.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] chf A fully built compact heightfield.
+/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0]
+/// [Units: vx]
+/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
+/// to be considered walkable. [Limit: >= 3] [Units: vx]
+/// @param[out] lset The resulting layer set. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
-bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
+bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int walkableHeight,
rcHeightfieldLayerSet& lset);
/// Builds a contour set from the region outlines in the provided compact heightfield.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] chf A fully built compact heightfield.
-/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate
-/// the original raw contour. [Limit: >=0] [Units: wu]
-/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh.
-/// [Limit: >=0] [Units: vx]
-/// @param[out] cset The resulting contour set. (Must be pre-allocated.)
-/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] chf A fully built compact heightfield.
+/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate
+/// the original raw contour. [Limit: >=0] [Units: wu]
+/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh.
+/// [Limit: >=0] [Units: vx]
+/// @param[out] cset The resulting contour set. (Must be pre-allocated.)
+/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags)
/// @returns True if the operation completed successfully.
bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
const float maxError, const int maxEdgeLen,
- rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES);
+ rcContourSet& cset, const int buildFlags = RC_CONTOUR_TESS_WALL_EDGES);
/// Builds a polygon mesh from the provided contours.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] cset A fully built contour set.
-/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the
-/// contour to polygon conversion process. [Limit: >= 3]
-/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] cset A fully built contour set.
+/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the
+/// contour to polygon conversion process. [Limit: >= 3]
+/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.)
/// @returns True if the operation completed successfully.
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh);
/// Merges multiple polygon meshes into a single mesh.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes]
-/// @param[in] nmeshes The number of polygon meshes in the meshes array.
-/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes]
+/// @param[in] nmeshes The number of polygon meshes in the meshes array.
+/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh);
/// Builds a detail mesh from the provided polygon mesh.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] mesh A fully built polygon mesh.
-/// @param[in] chf The compact heightfield used to build the polygon mesh.
-/// @param[in] sampleDist Sets the distance to use when samping the heightfield. [Limit: >=0] [Units: wu]
-/// @param[in] sampleMaxError The maximum distance the detail mesh surface should deviate from
-/// heightfield data. [Limit: >=0] [Units: wu]
-/// @param[out] dmesh The resulting detail mesh. (Must be pre-allocated.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] mesh A fully built polygon mesh.
+/// @param[in] chf The compact heightfield used to build the polygon mesh.
+/// @param[in] sampleDist Sets the distance to use when samping the heightfield. [Limit: >=0] [Units: wu]
+/// @param[in] sampleMaxError The maximum distance the detail mesh surface should deviate from
+/// heightfield data. [Limit: >=0] [Units: wu]
+/// @param[out] dmesh The resulting detail mesh. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
const float sampleDist, const float sampleMaxError,
rcPolyMeshDetail& dmesh);
+/// Copies the poly mesh data from src to dst.
+/// @ingroup recast
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] src The source mesh to copy from.
+/// @param[out] dst The resulting detail mesh. (Must be pre-allocated, must be empty mesh.)
+/// @returns True if the operation completed successfully.
+bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst);
+
/// Merges multiple detail meshes into a single detail mesh.
/// @ingroup recast
-/// @param[in,out] ctx The build context to use during the operation.
-/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes]
-/// @param[in] nmeshes The number of detail meshes in the meshes array.
-/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.)
+/// @param[in,out] ctx The build context to use during the operation.
+/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes]
+/// @param[in] nmeshes The number of detail meshes in the meshes array.
+/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh);
@@ -1123,6 +1189,6 @@ bool buildMeshAdjacency(unsigned short* polys, const int npolys, const int nvert
///////////////////////////////////////////////////////////////////////////
-// Due to the large amount of detail documentation for this file,
+// Due to the large amount of detail documentation for this file,
// the content normally located at the end of the header file has been separated
// out to a file in /Docs/Extern.
diff --git a/extern/recastnavigation/Recast/Include/RecastAlloc.h b/extern/recastnavigation/Recast/Include/RecastAlloc.h
index 0038c1a5c54..f1608fb5537 100644
--- a/extern/recastnavigation/Recast/Include/RecastAlloc.h
+++ b/extern/recastnavigation/Recast/Include/RecastAlloc.h
@@ -19,6 +19,8 @@
#ifndef RECASTALLOC_H
#define RECASTALLOC_H
+#include <stddef.h>
+
/// Provides hint values to the memory allocator on how long the
/// memory is expected to be used.
enum rcAllocHint
@@ -28,30 +30,32 @@ enum rcAllocHint
};
/// A memory allocation function.
-// @param[in] size The size, in bytes of memory, to allocate.
-// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
+// @param[in] size The size, in bytes of memory, to allocate.
+// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use.
// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
/// @see rcAllocSetCustom
-typedef void* (rcAllocFunc)(int size, rcAllocHint hint);
+typedef void* (rcAllocFunc)(size_t size, rcAllocHint hint);
/// A memory deallocation function.
+/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc.
/// @see rcAllocSetCustom
-// @param[in] ptr
typedef void (rcFreeFunc)(void* ptr);
/// Sets the base custom allocation functions to be used by Recast.
-/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc
-/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree
+/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc
+/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);
/// Allocates a memory block.
-/// @param[in] size The size, in bytes of memory, to allocate.
-/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
+/// @param[in] size The size, in bytes of memory, to allocate.
+/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
-void* rcAlloc(int size, rcAllocHint hint);
+/// @see rcFree
+void* rcAlloc(size_t size, rcAllocHint hint);
/// Deallocates a memory block.
-/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
+/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
+/// @see rcAlloc
void rcFree(void* ptr);
@@ -60,42 +64,58 @@ class rcIntArray
{
int* m_data;
int m_size, m_cap;
- inline rcIntArray(const rcIntArray&);
- inline rcIntArray& operator=(const rcIntArray&);
-public:
+ void doResize(int n);
+
+ // Explicitly disabled copy constructor and copy assignment operator.
+ rcIntArray(const rcIntArray&);
+ rcIntArray& operator=(const rcIntArray&);
+
+public:
/// Constructs an instance with an initial array size of zero.
- inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
+ rcIntArray() : m_data(0), m_size(0), m_cap(0) {}
/// Constructs an instance initialized to the specified size.
- /// @param[in] n The initial size of the integer array.
- inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
- inline ~rcIntArray() { rcFree(m_data); }
+ /// @param[in] n The initial size of the integer array.
+ rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); }
+ ~rcIntArray() { rcFree(m_data); }
/// Specifies the new size of the integer array.
- /// @param[in] n The new size of the integer array.
- void resize(int n);
+ /// @param[in] n The new size of the integer array.
+ void resize(int n)
+ {
+ if (n > m_cap)
+ doResize(n);
+
+ m_size = n;
+ }
/// Push the specified integer onto the end of the array and increases the size by one.
- /// @param[in] item The new value.
- inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
+ /// @param[in] item The new value.
+ void push(int item) { resize(m_size+1); m_data[m_size-1] = item; }
/// Returns the value at the end of the array and reduces the size by one.
/// @return The value at the end of the array.
- inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; }
+ int pop()
+ {
+ if (m_size > 0)
+ m_size--;
+
+ return m_data[m_size];
+ }
/// The value at the specified array index.
/// @warning Does not provide overflow protection.
- /// @param[in] i The index of the value.
- inline const int& operator[](int i) const { return m_data[i]; }
+ /// @param[in] i The index of the value.
+ const int& operator[](int i) const { return m_data[i]; }
/// The value at the specified array index.
/// @warning Does not provide overflow protection.
- /// @param[in] i The index of the value.
- inline int& operator[](int i) { return m_data[i]; }
+ /// @param[in] i The index of the value.
+ int& operator[](int i) { return m_data[i]; }
/// The current size of the integer array.
- inline int size() const { return m_size; }
+ int size() const { return m_size; }
};
/// A simple helper class used to delete an array when it goes out of scope.
@@ -110,13 +130,18 @@ public:
inline rcScopedDelete() : ptr(0) {}
/// Constructs an instance with the specified pointer.
- /// @param[in] p An pointer to an allocated array.
+ /// @param[in] p An pointer to an allocated array.
inline rcScopedDelete(T* p) : ptr(p) {}
inline ~rcScopedDelete() { rcFree(ptr); }
/// The root array pointer.
/// @return The root array pointer.
inline operator T*() { return ptr; }
+
+private:
+ // Explicitly disabled copy constructor and copy assignment operator.
+ rcScopedDelete(const rcScopedDelete&);
+ rcScopedDelete& operator=(const rcScopedDelete&);
};
#endif
diff --git a/extern/recastnavigation/Recast/Include/RecastAssert.h b/extern/recastnavigation/Recast/Include/RecastAssert.h
index 45cb01fb595..2aca0d9a14f 100644
--- a/extern/recastnavigation/Recast/Include/RecastAssert.h
+++ b/extern/recastnavigation/Recast/Include/RecastAssert.h
@@ -24,7 +24,7 @@
#ifdef NDEBUG
// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
-# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__ == -1), false)
+# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
#else
# include <assert.h>
# define rcAssert assert
diff --git a/extern/recastnavigation/Recast/Include/RecastLog.h b/extern/recastnavigation/Recast/Include/RecastLog.h
deleted file mode 100644
index 026ef73a3aa..00000000000
--- a/extern/recastnavigation/Recast/Include/RecastLog.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright (c) 2009 Mikko Mononen memon@inside.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 RECAST_LOG_H
-#define RECAST_LOG_H
-
-enum rcLogCategory
-{
- RC_LOG_PROGRESS = 1,
- RC_LOG_WARNING,
- RC_LOG_ERROR,
-};
-
-class rcLog
-{
-public:
- rcLog();
- ~rcLog();
-
- void log(rcLogCategory category, const char* format, ...);
- inline void clear() { m_messageCount = 0; m_textPoolSize = 0; }
- inline int getMessageCount() const { return m_messageCount; }
- inline char getMessageType(int i) const { return *m_messages[i]; }
- inline const char* getMessageText(int i) const { return m_messages[i]+1; }
-
-private:
- static const int MAX_MESSAGES = 1000;
- const char* m_messages[MAX_MESSAGES];
- int m_messageCount;
- static const int TEXT_POOL_SIZE = 8000;
- char m_textPool[TEXT_POOL_SIZE];
- int m_textPoolSize;
-};
-
-struct rcBuildTimes
-{
- int rasterizeTriangles;
- int buildCompact;
- int buildContours;
- int buildContoursTrace;
- int buildContoursSimplify;
- int filterBorder;
- int filterWalkable;
- int filterMarkReachable;
- int buildPolymesh;
- int buildDistanceField;
- int buildDistanceFieldDist;
- int buildDistanceFieldBlur;
- int buildRegions;
- int buildRegionsReg;
- int buildRegionsExp;
- int buildRegionsFlood;
- int buildRegionsFilter;
- int buildDetailMesh;
- int mergePolyMesh;
- int mergePolyMeshDetail;
-};
-
-void rcSetLog(rcLog* log);
-rcLog* rcGetLog();
-
-void rcSetBuildTimes(rcBuildTimes* btimes);
-rcBuildTimes* rcGetBuildTimes();
-
-#endif // RECAST_LOG_H
diff --git a/extern/recastnavigation/Recast/Include/RecastTimer.h b/extern/recastnavigation/Recast/Include/RecastTimer.h
deleted file mode 100644
index d4f21e58776..00000000000
--- a/extern/recastnavigation/Recast/Include/RecastTimer.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (c) 2009 Mikko Mononen memon@inside.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 RECAST_TIMER_H
-#define RECAST_TIMER_H
-
-#ifdef __GNUC__
-#include <stdint.h>
-typedef int64_t rcTimeVal;
-#else
-typedef __int64 rcTimeVal;
-#endif
-
-rcTimeVal rcGetPerformanceTimer();
-int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end);
-
-#endif // RECAST_TIMER_H
diff --git a/extern/recastnavigation/Recast/Source/Recast.cpp b/extern/recastnavigation/Recast/Source/Recast.cpp
index 283cf0c128b..46bc8b7810d 100644
--- a/extern/recastnavigation/Recast/Source/Recast.cpp
+++ b/extern/recastnavigation/Recast/Source/Recast.cpp
@@ -208,12 +208,11 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int*
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocHeightfield, rcHeightfield
-bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height,
+bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
const float* bmin, const float* bmax,
float cs, float ch)
{
- // TODO: VC complains about unref formal variable, figure out a way to handle this better.
-// rcAssert(ctx);
+ rcIgnoreUnused(ctx);
hf.width = width;
hf.height = height;
@@ -239,19 +238,18 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
/// @par
///
-/// Only sets the aread id's for the walkable triangles. Does not alter the
+/// Only sets the area id's for the walkable triangles. Does not alter the
/// area id's for unwalkable triangles.
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
-void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
+void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
const float* verts, int /*nv*/,
const int* tris, int nt,
unsigned char* areas)
{
- // TODO: VC complains about unref formal variable, figure out a way to handle this better.
-// rcAssert(ctx);
+ rcIgnoreUnused(ctx);
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
@@ -269,19 +267,18 @@ void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
/// @par
///
-/// Only sets the aread id's for the unwalkable triangles. Does not alter the
+/// Only sets the area id's for the unwalkable triangles. Does not alter the
/// area id's for walkable triangles.
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
-void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
+void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
const float* verts, int /*nv*/,
const int* tris, int nt,
unsigned char* areas)
{
- // TODO: VC complains about unref formal variable, figure out a way to handle this better.
-// rcAssert(ctx);
+ rcIgnoreUnused(ctx);
const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
@@ -297,10 +294,9 @@ void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAng
}
}
-int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
+int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf)
{
- // TODO: VC complains about unref formal variable, figure out a way to handle this better.
-// rcAssert(ctx);
+ rcIgnoreUnused(ctx);
const int w = hf.width;
const int h = hf.height;
@@ -322,7 +318,7 @@ int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
/// @par
///
/// This is just the beginning of the process of fully building a compact heightfield.
-/// Various filters may be applied applied, then the distance field and regions built.
+/// Various filters may be applied, then the distance field and regions built.
/// E.g: #rcBuildDistanceField and #rcBuildRegions
///
/// See the #rcConfig documentation for more information on the configuration parameters.
@@ -333,7 +329,7 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
const int w = hf.width;
const int h = hf.height;
@@ -439,13 +435,13 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
{
// Mark direction as walkable.
- const int idx = k - (int)nc.index;
- if (idx < 0 || idx > MAX_LAYERS)
+ const int lidx = k - (int)nc.index;
+ if (lidx < 0 || lidx > MAX_LAYERS)
{
- tooHighNeighbour = rcMax(tooHighNeighbour, idx);
+ tooHighNeighbour = rcMax(tooHighNeighbour, lidx);
continue;
}
- rcSetCon(s, dir, idx);
+ rcSetCon(s, dir, lidx);
break;
}
}
@@ -460,8 +456,6 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
tooHighNeighbour, MAX_LAYERS);
}
-
- ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
return true;
}
@@ -490,4 +484,4 @@ static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
size += sizeof(rcCompactCell) * chf.width * chf.height;
return size;
}
-*/ \ No newline at end of file
+*/
diff --git a/extern/recastnavigation/Recast/Source/RecastAlloc.cpp b/extern/recastnavigation/Recast/Source/RecastAlloc.cpp
index b5ec1516146..ee1039f2f4f 100644
--- a/extern/recastnavigation/Recast/Source/RecastAlloc.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastAlloc.cpp
@@ -20,7 +20,7 @@
#include <string.h>
#include "RecastAlloc.h"
-static void *rcAllocDefault(int size, rcAllocHint)
+static void *rcAllocDefault(size_t size, rcAllocHint)
{
return malloc(size);
}
@@ -41,7 +41,7 @@ void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc)
}
/// @see rcAllocSetCustom
-void* rcAlloc(int size, rcAllocHint hint)
+void* rcAlloc(size_t size, rcAllocHint hint)
{
return sRecastAllocFunc(size, hint);
}
@@ -72,17 +72,13 @@ void rcFree(void* ptr)
/// Using this method ensures the array is at least large enough to hold
/// the specified number of elements. This can improve performance by
/// avoiding auto-resizing during use.
-void rcIntArray::resize(int n)
+void rcIntArray::doResize(int n)
{
- if (n > m_cap)
- {
- if (!m_cap) m_cap = n;
- while (m_cap < n) m_cap *= 2;
- int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP);
- if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int));
- rcFree(m_data);
- m_data = newData;
- }
- m_size = n;
+ if (!m_cap) m_cap = n;
+ while (m_cap < n) m_cap *= 2;
+ int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP);
+ if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int));
+ rcFree(m_data);
+ m_data = newData;
}
diff --git a/extern/recastnavigation/Recast/Source/RecastArea.cpp b/extern/recastnavigation/Recast/Source/RecastArea.cpp
index a59acc53eb6..97139cf996a 100644
--- a/extern/recastnavigation/Recast/Source/RecastArea.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastArea.cpp
@@ -41,7 +41,7 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
const int w = chf.width;
const int h = chf.height;
- ctx->startTimer(RC_TIMER_ERODE_AREA);
+ rcScopedTimer timer(ctx, RC_TIMER_ERODE_AREA);
unsigned char* dist = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
if (!dist)
@@ -75,8 +75,8 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
{
const int nx = x + rcGetDirOffsetX(dir);
const int ny = y + rcGetDirOffsetY(dir);
- const int ni = (int)chf.cells[nx+ny*w].index + rcGetCon(s, dir);
- if (chf.areas[ni] != RC_NULL_AREA)
+ const int nidx = (int)chf.cells[nx+ny*w].index + rcGetCon(s, dir);
+ if (chf.areas[nidx] != RC_NULL_AREA)
{
nc++;
}
@@ -215,8 +215,6 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf)
rcFree(dist);
- ctx->stopTimer(RC_TIMER_ERODE_AREA);
-
return true;
}
@@ -245,7 +243,7 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
const int w = chf.width;
const int h = chf.height;
- ctx->startTimer(RC_TIMER_MEDIAN_AREA);
+ rcScopedTimer timer(ctx, RC_TIMER_MEDIAN_AREA);
unsigned char* areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
if (!areas)
@@ -306,8 +304,6 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf)
memcpy(chf.areas, areas, sizeof(unsigned char)*chf.spanCount);
rcFree(areas);
-
- ctx->stopTimer(RC_TIMER_MEDIAN_AREA);
return true;
}
@@ -322,7 +318,7 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_MARK_BOX_AREA);
+ rcScopedTimer timer(ctx, RC_TIMER_MARK_BOX_AREA);
int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs);
int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch);
@@ -357,9 +353,6 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne
}
}
}
-
- ctx->stopTimer(RC_TIMER_MARK_BOX_AREA);
-
}
@@ -391,7 +384,7 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_MARK_CONVEXPOLY_AREA);
+ rcScopedTimer timer(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA);
float bmin[3], bmax[3];
rcVcopy(bmin, verts);
@@ -448,10 +441,86 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
}
}
}
+}
+
+int rcOffsetPoly(const float* verts, const int nverts, const float offset,
+ float* outVerts, const int maxOutVerts)
+{
+ const float MITER_LIMIT = 1.20f;
+
+ int n = 0;
+
+ for (int i = 0; i < nverts; i++)
+ {
+ const int a = (i+nverts-1) % nverts;
+ const int b = i;
+ const int c = (i+1) % nverts;
+ const float* va = &verts[a*3];
+ const float* vb = &verts[b*3];
+ const float* vc = &verts[c*3];
+ float dx0 = vb[0] - va[0];
+ float dy0 = vb[2] - va[2];
+ float d0 = dx0*dx0 + dy0*dy0;
+ if (d0 > 1e-6f)
+ {
+ d0 = 1.0f/rcSqrt(d0);
+ dx0 *= d0;
+ dy0 *= d0;
+ }
+ float dx1 = vc[0] - vb[0];
+ float dy1 = vc[2] - vb[2];
+ float d1 = dx1*dx1 + dy1*dy1;
+ if (d1 > 1e-6f)
+ {
+ d1 = 1.0f/rcSqrt(d1);
+ dx1 *= d1;
+ dy1 *= d1;
+ }
+ const float dlx0 = -dy0;
+ const float dly0 = dx0;
+ const float dlx1 = -dy1;
+ const float dly1 = dx1;
+ float cross = dx1*dy0 - dx0*dy1;
+ float dmx = (dlx0 + dlx1) * 0.5f;
+ float dmy = (dly0 + dly1) * 0.5f;
+ float dmr2 = dmx*dmx + dmy*dmy;
+ bool bevel = dmr2 * MITER_LIMIT*MITER_LIMIT < 1.0f;
+ if (dmr2 > 1e-6f)
+ {
+ const float scale = 1.0f / dmr2;
+ dmx *= scale;
+ dmy *= scale;
+ }
- ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA);
+ if (bevel && cross < 0.0f)
+ {
+ if (n+2 >= maxOutVerts)
+ return 0;
+ float d = (1.0f - (dx0*dx1 + dy0*dy1))*0.5f;
+ outVerts[n*3+0] = vb[0] + (-dlx0+dx0*d)*offset;
+ outVerts[n*3+1] = vb[1];
+ outVerts[n*3+2] = vb[2] + (-dly0+dy0*d)*offset;
+ n++;
+ outVerts[n*3+0] = vb[0] + (-dlx1-dx1*d)*offset;
+ outVerts[n*3+1] = vb[1];
+ outVerts[n*3+2] = vb[2] + (-dly1-dy1*d)*offset;
+ n++;
+ }
+ else
+ {
+ if (n+1 >= maxOutVerts)
+ return 0;
+ outVerts[n*3+0] = vb[0] - dmx*offset;
+ outVerts[n*3+1] = vb[1];
+ outVerts[n*3+2] = vb[2] - dmy*offset;
+ n++;
+ }
+ }
+
+ return n;
}
+
/// @par
///
/// The value of spacial parameters are in world units.
@@ -463,7 +532,7 @@ void rcMarkCylinderArea(rcContext* ctx, const float* pos,
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_MARK_CYLINDER_AREA);
+ rcScopedTimer timer(ctx, RC_TIMER_MARK_CYLINDER_AREA);
float bmin[3], bmax[3];
bmin[0] = pos[0] - r;
@@ -519,6 +588,4 @@ void rcMarkCylinderArea(rcContext* ctx, const float* pos,
}
}
}
-
- ctx->stopTimer(RC_TIMER_MARK_CYLINDER_AREA);
}
diff --git a/extern/recastnavigation/Recast/Source/RecastContour.cpp b/extern/recastnavigation/Recast/Source/RecastContour.cpp
index df943838ffb..277ab015018 100644
--- a/extern/recastnavigation/Recast/Source/RecastContour.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastContour.cpp
@@ -20,6 +20,7 @@
#include <math.h>
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include "Recast.h"
#include "RecastAlloc.h"
#include "RecastAssert.h"
@@ -36,7 +37,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
unsigned int regs[4] = {0,0,0,0};
// Combine region and area codes in order to prevent
- // border vertices which are in between two areas to be removed.
+ // border vertices which are in between two areas to be removed.
regs[0] = chf.spans[i].reg | (chf.areas[i] << 16);
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
@@ -187,27 +188,6 @@ static float distancePtSeg(const int x, const int z,
const int px, const int pz,
const int qx, const int qz)
{
-/* float pqx = (float)(qx - px);
- float pqy = (float)(qy - py);
- float pqz = (float)(qz - pz);
- float dx = (float)(x - px);
- float dy = (float)(y - py);
- float dz = (float)(z - pz);
- float d = pqx*pqx + pqy*pqy + pqz*pqz;
- float t = pqx*dx + pqy*dy + pqz*dz;
- if (d > 0)
- t /= d;
- if (t < 0)
- t = 0;
- else if (t > 1)
- t = 1;
-
- dx = px + t*pqx - x;
- dy = py + t*pqy - y;
- dz = pz + t*pqz - z;
-
- return dx*dx + dy*dy + dz*dz;*/
-
float pqx = (float)(qx - px);
float pqz = (float)(qz - pz);
float dx = (float)(x - px);
@@ -257,13 +237,13 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
simplified.push(points[i*4+2]);
simplified.push(i);
}
- }
+ }
}
if (simplified.size() == 0)
{
// If there is no connections at all,
- // create some initial points for the simplification process.
+ // create some initial points for the simplification process.
// Find lower-left and upper-right vertices of the contour.
int llx = points[0];
int lly = points[1];
@@ -311,19 +291,19 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
{
int ii = (i+1) % (simplified.size()/4);
- const int ax = simplified[i*4+0];
- const int az = simplified[i*4+2];
- const int ai = simplified[i*4+3];
-
- const int bx = simplified[ii*4+0];
- const int bz = simplified[ii*4+2];
- const int bi = simplified[ii*4+3];
+ int ax = simplified[i*4+0];
+ int az = simplified[i*4+2];
+ int ai = simplified[i*4+3];
+
+ int bx = simplified[ii*4+0];
+ int bz = simplified[ii*4+2];
+ int bi = simplified[ii*4+3];
// Find maximum deviation from the segment.
float maxd = 0;
- int i_max = -1;
+ int maxi = -1;
int ci, cinc, endi;
-
+
// Traverse the segment in lexilogical order so that the
// max deviation is calculated similarly when traversing
// opposite segments.
@@ -338,6 +318,8 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
cinc = pn-1;
ci = (bi+cinc) % pn;
endi = ai;
+ rcSwap(ax, bx);
+ rcSwap(az, bz);
}
// Tessellate only outer edges or edges between areas.
@@ -350,7 +332,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
if (d > maxd)
{
maxd = d;
- i_max = ci;
+ maxi = ci;
}
ci = (ci+cinc) % pn;
}
@@ -359,7 +341,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
// If the max deviation is larger than accepted error,
// add new point, else continue to next segment.
- if (i_max != -1 && maxd > (maxError*maxError))
+ if (maxi != -1 && maxd > (maxError*maxError))
{
// Add space for the new point.
simplified.resize(simplified.size()+4);
@@ -372,10 +354,10 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
simplified[j*4+3] = simplified[(j-1)*4+3];
}
// Add the point.
- simplified[(i+1)*4+0] = points[i_max*4+0];
- simplified[(i+1)*4+1] = points[i_max*4+1];
- simplified[(i+1)*4+2] = points[i_max*4+2];
- simplified[(i+1)*4+3] = i_max;
+ simplified[(i+1)*4+0] = points[maxi*4+0];
+ simplified[(i+1)*4+1] = points[maxi*4+1];
+ simplified[(i+1)*4+2] = points[maxi*4+2];
+ simplified[(i+1)*4+3] = maxi;
}
else
{
@@ -397,11 +379,11 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
const int bx = simplified[ii*4+0];
const int bz = simplified[ii*4+2];
const int bi = simplified[ii*4+3];
-
+
// Find maximum deviation from the segment.
- int i_max = -1;
+ int maxi = -1;
int ci = (ai+1) % pn;
-
+
// Tessellate only outer edges or edges between areas.
bool tess = false;
// Wall edges.
@@ -420,22 +402,20 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
// Round based on the segments in lexilogical order so that the
// max tesselation is consistent regardles in which direction
// segments are traversed.
- if (bx > ax || (bx == ax && bz > az))
+ const int n = bi < ai ? (bi+pn - ai) : (bi - ai);
+ if (n > 1)
{
- const int n = bi < ai ? (bi+pn - ai) : (bi - ai);
- i_max = (ai + n/2) % pn;
- }
- else
- {
- const int n = bi < ai ? (bi+pn - ai) : (bi - ai);
- i_max = (ai + (n+1)/2) % pn;
+ if (bx > ax || (bx == ax && bz > az))
+ maxi = (ai + n/2) % pn;
+ else
+ maxi = (ai + (n+1)/2) % pn;
}
}
}
// If the max deviation is larger than accepted error,
// add new point, else continue to next segment.
- if (i_max != -1)
+ if (maxi != -1)
{
// Add space for the new point.
simplified.resize(simplified.size()+4);
@@ -448,10 +428,10 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
simplified[j*4+3] = simplified[(j-1)*4+3];
}
// Add the point.
- simplified[(i+1)*4+0] = points[i_max*4+0];
- simplified[(i+1)*4+1] = points[i_max*4+1];
- simplified[(i+1)*4+2] = points[i_max*4+2];
- simplified[(i+1)*4+3] = i_max;
+ simplified[(i+1)*4+0] = points[maxi*4+0];
+ simplified[(i+1)*4+1] = points[maxi*4+1];
+ simplified[(i+1)*4+2] = points[maxi*4+2];
+ simplified[(i+1)*4+3] = maxi;
}
else
{
@@ -466,37 +446,11 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified,
// and the neighbour region is take from the next raw point.
const int ai = (simplified[i*4+3]+1) % pn;
const int bi = simplified[i*4+3];
- simplified[i*4+3] = (points[ai*4+3] & RC_CONTOUR_REG_MASK) | (points[bi*4+3] & RC_BORDER_VERTEX);
+ simplified[i*4+3] = (points[ai*4+3] & (RC_CONTOUR_REG_MASK|RC_AREA_BORDER)) | (points[bi*4+3] & RC_BORDER_VERTEX);
}
}
-static void removeDegenerateSegments(rcIntArray& simplified)
-{
- // Remove adjacent vertices which are equal on xz-plane,
- // or else the triangulator will get confused.
- for (int i = 0; i < simplified.size()/4; ++i)
- {
- int ni = i+1;
- if (ni >= (simplified.size()/4))
- ni = 0;
-
- if (simplified[i*4+0] == simplified[ni*4+0] &&
- simplified[i*4+2] == simplified[ni*4+2])
- {
- // Degenerate segment, remove.
- for (int j = i; j < simplified.size()/4-1; ++j)
- {
- simplified[j*4+0] = simplified[(j+1)*4+0];
- simplified[j*4+1] = simplified[(j+1)*4+1];
- simplified[j*4+2] = simplified[(j+1)*4+2];
- simplified[j*4+3] = simplified[(j+1)*4+3];
- }
- simplified.resize(simplified.size()-4);
- }
- }
-}
-
static int calcAreaOfPolygon2D(const int* verts, const int nverts)
{
int area = 0;
@@ -509,54 +463,155 @@ static int calcAreaOfPolygon2D(const int* verts, const int nverts)
return (area+1) / 2;
}
-inline bool ileft(const int* a, const int* b, const int* c)
+// TODO: these are the same as in RecastMesh.cpp, consider using the same.
+// Last time I checked the if version got compiled using cmov, which was a lot faster than module (with idiv).
+inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; }
+inline int next(int i, int n) { return i+1 < n ? i+1 : 0; }
+
+inline int area2(const int* a, const int* b, const int* c)
+{
+ return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
+}
+
+// Exclusive or: true iff exactly one argument is true.
+// The arguments are negated to ensure that they are 0/1
+// values. Then the bitwise Xor operator may apply.
+// (This idea is due to Michael Baldwin.)
+inline bool xorb(bool x, bool y)
{
- return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]) <= 0;
+ return !x ^ !y;
}
-static void getClosestIndices(const int* vertsa, const int nvertsa,
- const int* vertsb, const int nvertsb,
- int& ia, int& ib)
+// Returns true iff c is strictly to the left of the directed
+// line through a to b.
+inline bool left(const int* a, const int* b, const int* c)
{
- int closestDist = 0xfffffff;
- ia = -1, ib = -1;
- for (int i = 0; i < nvertsa; ++i)
+ return area2(a, b, c) < 0;
+}
+
+inline bool leftOn(const int* a, const int* b, const int* c)
+{
+ return area2(a, b, c) <= 0;
+}
+
+inline bool collinear(const int* a, const int* b, const int* c)
+{
+ return area2(a, b, c) == 0;
+}
+
+// Returns true iff ab properly intersects cd: they share
+// a point interior to both segments. The properness of the
+// intersection is ensured by using strict leftness.
+static bool intersectProp(const int* a, const int* b, const int* c, const int* d)
+{
+ // Eliminate improper cases.
+ if (collinear(a,b,c) || collinear(a,b,d) ||
+ collinear(c,d,a) || collinear(c,d,b))
+ return false;
+
+ return xorb(left(a,b,c), left(a,b,d)) && xorb(left(c,d,a), left(c,d,b));
+}
+
+// Returns T iff (a,b,c) are collinear and point c lies
+// on the closed segement ab.
+static bool between(const int* a, const int* b, const int* c)
+{
+ if (!collinear(a, b, c))
+ return false;
+ // If ab not vertical, check betweenness on x; else on y.
+ if (a[0] != b[0])
+ return ((a[0] <= c[0]) && (c[0] <= b[0])) || ((a[0] >= c[0]) && (c[0] >= b[0]));
+ else
+ return ((a[2] <= c[2]) && (c[2] <= b[2])) || ((a[2] >= c[2]) && (c[2] >= b[2]));
+}
+
+// Returns true iff segments ab and cd intersect, properly or improperly.
+static bool intersect(const int* a, const int* b, const int* c, const int* d)
+{
+ if (intersectProp(a, b, c, d))
+ return true;
+ else if (between(a, b, c) || between(a, b, d) ||
+ between(c, d, a) || between(c, d, b))
+ return true;
+ else
+ return false;
+}
+
+static bool vequal(const int* a, const int* b)
+{
+ return a[0] == b[0] && a[2] == b[2];
+}
+
+static bool intersectSegCountour(const int* d0, const int* d1, int i, int n, const int* verts)
+{
+ // For each edge (k,k+1) of P
+ for (int k = 0; k < n; k++)
+ {
+ int k1 = next(k, n);
+ // Skip edges incident to i.
+ if (i == k || i == k1)
+ continue;
+ const int* p0 = &verts[k * 4];
+ const int* p1 = &verts[k1 * 4];
+ if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
+ continue;
+
+ if (intersect(d0, d1, p0, p1))
+ return true;
+ }
+ return false;
+}
+
+static bool inCone(int i, int n, const int* verts, const int* pj)
+{
+ const int* pi = &verts[i * 4];
+ const int* pi1 = &verts[next(i, n) * 4];
+ const int* pin1 = &verts[prev(i, n) * 4];
+
+ // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
+ if (leftOn(pin1, pi, pi1))
+ return left(pi, pj, pin1) && left(pj, pi, pi1);
+ // Assume (i-1,i,i+1) not collinear.
+ // else P[i] is reflex.
+ return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
+}
+
+
+static void removeDegenerateSegments(rcIntArray& simplified)
+{
+ // Remove adjacent vertices which are equal on xz-plane,
+ // or else the triangulator will get confused.
+ int npts = simplified.size()/4;
+ for (int i = 0; i < npts; ++i)
{
- const int in = (i+1) % nvertsa;
- const int ip = (i+nvertsa-1) % nvertsa;
- const int* va = &vertsa[i*4];
- const int* van = &vertsa[in*4];
- const int* vap = &vertsa[ip*4];
+ int ni = next(i, npts);
- for (int j = 0; j < nvertsb; ++j)
+ if (vequal(&simplified[i*4], &simplified[ni*4]))
{
- const int* vb = &vertsb[j*4];
- // vb must be "infront" of va.
- if (ileft(vap,va,vb) && ileft(va,van,vb))
+ // Degenerate segment, remove.
+ for (int j = i; j < simplified.size()/4-1; ++j)
{
- const int dx = vb[0] - va[0];
- const int dz = vb[2] - va[2];
- const int d = dx*dx + dz*dz;
- if (d < closestDist)
- {
- ia = i;
- ib = j;
- closestDist = d;
- }
+ simplified[j*4+0] = simplified[(j+1)*4+0];
+ simplified[j*4+1] = simplified[(j+1)*4+1];
+ simplified[j*4+2] = simplified[(j+1)*4+2];
+ simplified[j*4+3] = simplified[(j+1)*4+3];
}
+ simplified.resize(simplified.size()-4);
+ npts--;
}
}
}
+
static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
{
const int maxVerts = ca.nverts + cb.nverts + 2;
int* verts = (int*)rcAlloc(sizeof(int)*maxVerts*4, RC_ALLOC_PERM);
if (!verts)
return false;
-
+
int nv = 0;
-
+
// Copy contour A.
for (int i = 0; i <= ca.nverts; ++i)
{
@@ -584,7 +639,7 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
rcFree(ca.verts);
ca.verts = verts;
ca.nverts = nv;
-
+
rcFree(cb.verts);
cb.verts = 0;
cb.nverts = 0;
@@ -592,18 +647,179 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib)
return true;
}
+struct rcContourHole
+{
+ rcContour* contour;
+ int minx, minz, leftmost;
+};
+
+struct rcContourRegion
+{
+ rcContour* outline;
+ rcContourHole* holes;
+ int nholes;
+};
+
+struct rcPotentialDiagonal
+{
+ int vert;
+ int dist;
+};
+
+// Finds the lowest leftmost vertex of a contour.
+static void findLeftMostVertex(rcContour* contour, int* minx, int* minz, int* leftmost)
+{
+ *minx = contour->verts[0];
+ *minz = contour->verts[2];
+ *leftmost = 0;
+ for (int i = 1; i < contour->nverts; i++)
+ {
+ const int x = contour->verts[i*4+0];
+ const int z = contour->verts[i*4+2];
+ if (x < *minx || (x == *minx && z < *minz))
+ {
+ *minx = x;
+ *minz = z;
+ *leftmost = i;
+ }
+ }
+}
+
+static int compareHoles(const void* va, const void* vb)
+{
+ const rcContourHole* a = (const rcContourHole*)va;
+ const rcContourHole* b = (const rcContourHole*)vb;
+ if (a->minx == b->minx)
+ {
+ if (a->minz < b->minz)
+ return -1;
+ if (a->minz > b->minz)
+ return 1;
+ }
+ else
+ {
+ if (a->minx < b->minx)
+ return -1;
+ if (a->minx > b->minx)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int compareDiagDist(const void* va, const void* vb)
+{
+ const rcPotentialDiagonal* a = (const rcPotentialDiagonal*)va;
+ const rcPotentialDiagonal* b = (const rcPotentialDiagonal*)vb;
+ if (a->dist < b->dist)
+ return -1;
+ if (a->dist > b->dist)
+ return 1;
+ return 0;
+}
+
+
+static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
+{
+ // Sort holes from left to right.
+ for (int i = 0; i < region.nholes; i++)
+ findLeftMostVertex(region.holes[i].contour, &region.holes[i].minx, &region.holes[i].minz, &region.holes[i].leftmost);
+
+ qsort(region.holes, region.nholes, sizeof(rcContourHole), compareHoles);
+
+ int maxVerts = region.outline->nverts;
+ for (int i = 0; i < region.nholes; i++)
+ maxVerts += region.holes[i].contour->nverts;
+
+ rcScopedDelete<rcPotentialDiagonal> diags((rcPotentialDiagonal*)rcAlloc(sizeof(rcPotentialDiagonal)*maxVerts, RC_ALLOC_TEMP));
+ if (!diags)
+ {
+ ctx->log(RC_LOG_WARNING, "mergeRegionHoles: Failed to allocated diags %d.", maxVerts);
+ return;
+ }
+
+ rcContour* outline = region.outline;
+
+ // Merge holes into the outline one by one.
+ for (int i = 0; i < region.nholes; i++)
+ {
+ rcContour* hole = region.holes[i].contour;
+
+ int index = -1;
+ int bestVertex = region.holes[i].leftmost;
+ for (int iter = 0; iter < hole->nverts; iter++)
+ {
+ // Find potential diagonals.
+ // The 'best' vertex must be in the cone described by 3 cosequtive vertices of the outline.
+ // ..o j-1
+ // |
+ // | * best
+ // |
+ // j o-----o j+1
+ // :
+ int ndiags = 0;
+ const int* corner = &hole->verts[bestVertex*4];
+ for (int j = 0; j < outline->nverts; j++)
+ {
+ if (inCone(j, outline->nverts, outline->verts, corner))
+ {
+ int dx = outline->verts[j*4+0] - corner[0];
+ int dz = outline->verts[j*4+2] - corner[2];
+ diags[ndiags].vert = j;
+ diags[ndiags].dist = dx*dx + dz*dz;
+ ndiags++;
+ }
+ }
+ // Sort potential diagonals by distance, we want to make the connection as short as possible.
+ qsort(diags, ndiags, sizeof(rcPotentialDiagonal), compareDiagDist);
+
+ // Find a diagonal that is not intersecting the outline not the remaining holes.
+ index = -1;
+ for (int j = 0; j < ndiags; j++)
+ {
+ const int* pt = &outline->verts[diags[j].vert*4];
+ bool intersect = intersectSegCountour(pt, corner, diags[i].vert, outline->nverts, outline->verts);
+ for (int k = i; k < region.nholes && !intersect; k++)
+ intersect |= intersectSegCountour(pt, corner, -1, region.holes[k].contour->nverts, region.holes[k].contour->verts);
+ if (!intersect)
+ {
+ index = diags[j].vert;
+ break;
+ }
+ }
+ // If found non-intersecting diagonal, stop looking.
+ if (index != -1)
+ break;
+ // All the potential diagonals for the current vertex were intersecting, try next vertex.
+ bestVertex = (bestVertex + 1) % hole->nverts;
+ }
+
+ if (index == -1)
+ {
+ ctx->log(RC_LOG_WARNING, "mergeHoles: Failed to find merge points for %p and %p.", region.outline, hole);
+ continue;
+ }
+ if (!mergeContours(*region.outline, *hole, index, bestVertex))
+ {
+ ctx->log(RC_LOG_WARNING, "mergeHoles: Failed to merge contours %p and %p.", region.outline, hole);
+ continue;
+ }
+ }
+}
+
+
/// @par
///
/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen
/// parameters control how closely the simplified contours will match the raw contours.
///
-/// Simplified contours are generated such that the vertices for portals between areas match up.
+/// Simplified contours are generated such that the vertices for portals between areas match up.
/// (They are considered mandatory vertices.)
///
/// Setting @p maxEdgeLength to zero will disabled the edge length feature.
-///
+///
/// See the #rcConfig documentation for more information on the configuration parameters.
-///
+///
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
const float maxError, const int maxEdgeLen,
@@ -615,7 +831,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
const int h = chf.height;
const int borderSize = chf.borderSize;
- ctx->startTimer(RC_TIMER_BUILD_CONTOURS);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_CONTOURS);
rcVcopy(cset.bmin, chf.bmin);
rcVcopy(cset.bmax, chf.bmax);
@@ -633,6 +849,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
cset.width = chf.width - chf.borderSize*2;
cset.height = chf.height - chf.borderSize*2;
cset.borderSize = chf.borderSize;
+ cset.maxError = maxError;
int maxContours = rcMax((int)chf.maxRegions, 8);
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
@@ -640,7 +857,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
return false;
cset.nconts = 0;
- rcScopedDelete<unsigned char> flags = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned char> flags((unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP));
if (!flags)
{
ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount);
@@ -706,17 +923,17 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
verts.resize(0);
simplified.resize(0);
-
+
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
walkContour(x, y, i, chf, flags, verts);
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
-
+
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
removeDegenerateSegments(simplified);
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
-
+
// Store region->contour remap info.
// Create contour.
if (simplified.size()/4 >= 3)
@@ -724,7 +941,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
if (cset.nconts >= maxContours)
{
// Allocate more contours.
- // This can happen when there are tiny holes in the heightfield.
+ // This happens when a region has holes.
const int oldMax = maxContours;
maxContours *= 2;
rcContour* newConts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
@@ -737,10 +954,10 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
}
rcFree(cset.conts);
cset.conts = newConts;
-
+
ctx->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours);
}
-
+
rcContour* cont = &cset.conts[cset.nconts++];
cont->nverts = simplified.size()/4;
@@ -754,9 +971,9 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
if (borderSize > 0)
{
// If the heightfield was build with bordersize, remove the offset.
- for (int i = 0; i < cont->nverts; ++i)
+ for (int j = 0; j < cont->nverts; ++j)
{
- int* v = &cont->verts[i*4];
+ int* v = &cont->verts[j*4];
v[0] -= borderSize;
v[2] -= borderSize;
}
@@ -773,25 +990,14 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
if (borderSize > 0)
{
// If the heightfield was build with bordersize, remove the offset.
- for (int i = 0; i < cont->nrverts; ++i)
+ for (int j = 0; j < cont->nrverts; ++j)
{
- int* v = &cont->rverts[i*4];
+ int* v = &cont->rverts[j*4];
v[0] -= borderSize;
v[2] -= borderSize;
}
}
-/* cont->cx = cont->cy = cont->cz = 0;
- for (int i = 0; i < cont->nverts; ++i)
- {
- cont->cx += cont->verts[i*4+0];
- cont->cy += cont->verts[i*4+1];
- cont->cz += cont->verts[i*4+2];
- }
- cont->cx /= cont->nverts;
- cont->cy /= cont->nverts;
- cont->cz /= cont->nverts;*/
-
cont->reg = reg;
cont->area = area;
}
@@ -799,55 +1005,101 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
}
}
- // Check and merge droppings.
- // Sometimes the previous algorithms can fail and create several contours
- // per area. This pass will try to merge the holes into the main region.
- for (int i = 0; i < cset.nconts; ++i)
+ // Merge holes if needed.
+ if (cset.nconts > 0)
{
- rcContour& cont = cset.conts[i];
- // Check if the contour is would backwards.
- if (calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0)
+ // Calculate winding of all polygons.
+ rcScopedDelete<char> winding((char*)rcAlloc(sizeof(char)*cset.nconts, RC_ALLOC_TEMP));
+ if (!winding)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'hole' (%d).", cset.nconts);
+ return false;
+ }
+ int nholes = 0;
+ for (int i = 0; i < cset.nconts; ++i)
+ {
+ rcContour& cont = cset.conts[i];
+ // If the contour is wound backwards, it is a hole.
+ winding[i] = calcAreaOfPolygon2D(cont.verts, cont.nverts) < 0 ? -1 : 1;
+ if (winding[i] < 0)
+ nholes++;
+ }
+
+ if (nholes > 0)
{
- // Find another contour which has the same region ID.
- int mergeIdx = -1;
- for (int j = 0; j < cset.nconts; ++j)
+ // Collect outline contour and holes contours per region.
+ // We assume that there is one outline and multiple holes.
+ const int nregions = chf.maxRegions+1;
+ rcScopedDelete<rcContourRegion> regions((rcContourRegion*)rcAlloc(sizeof(rcContourRegion)*nregions, RC_ALLOC_TEMP));
+ if (!regions)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'regions' (%d).", nregions);
+ return false;
+ }
+ memset(regions, 0, sizeof(rcContourRegion)*nregions);
+
+ rcScopedDelete<rcContourHole> holes((rcContourHole*)rcAlloc(sizeof(rcContourHole)*cset.nconts, RC_ALLOC_TEMP));
+ if (!holes)
{
- if (i == j) continue;
- if (cset.conts[j].nverts && cset.conts[j].reg == cont.reg)
+ ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'holes' (%d).", cset.nconts);
+ return false;
+ }
+ memset(holes, 0, sizeof(rcContourHole)*cset.nconts);
+
+ for (int i = 0; i < cset.nconts; ++i)
+ {
+ rcContour& cont = cset.conts[i];
+ // Positively would contours are outlines, negative holes.
+ if (winding[i] > 0)
{
- // Make sure the polygon is correctly oriented.
- if (calcAreaOfPolygon2D(cset.conts[j].verts, cset.conts[j].nverts))
- {
- mergeIdx = j;
- break;
- }
+ if (regions[cont.reg].outline)
+ ctx->log(RC_LOG_ERROR, "rcBuildContours: Multiple outlines for region %d.", cont.reg);
+ regions[cont.reg].outline = &cont;
+ }
+ else
+ {
+ regions[cont.reg].nholes++;
+ }
+ }
+ int index = 0;
+ for (int i = 0; i < nregions; i++)
+ {
+ if (regions[i].nholes > 0)
+ {
+ regions[i].holes = &holes[index];
+ index += regions[i].nholes;
+ regions[i].nholes = 0;
}
}
- if (mergeIdx == -1)
+ for (int i = 0; i < cset.nconts; ++i)
{
- ctx->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i);
+ rcContour& cont = cset.conts[i];
+ rcContourRegion& reg = regions[cont.reg];
+ if (winding[i] < 0)
+ reg.holes[reg.nholes++].contour = &cont;
}
- else
+
+ // Finally merge each regions holes into the outline.
+ for (int i = 0; i < nregions; i++)
{
- rcContour& mcont = cset.conts[mergeIdx];
- // Merge by closest points.
- int ia = 0, ib = 0;
- getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib);
- if (ia == -1 || ib == -1)
+ rcContourRegion& reg = regions[i];
+ if (!reg.nholes) continue;
+
+ if (reg.outline)
{
- ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to find merge points for %d and %d.", i, mergeIdx);
- continue;
+ mergeRegionHoles(ctx, reg);
}
- if (!mergeContours(mcont, cont, ia, ib))
+ else
{
- ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx);
- continue;
+ // The region does not have an outline.
+ // This can happen if the contour becaomes selfoverlapping because of
+ // too aggressive simplification settings.
+ ctx->log(RC_LOG_ERROR, "rcBuildContours: Bad outline for region %d, contour simplification is likely too aggressive.", i);
}
}
}
+
}
- ctx->stopTimer(RC_TIMER_BUILD_CONTOURS);
-
return true;
}
diff --git a/extern/recastnavigation/Recast/Source/RecastFilter.cpp b/extern/recastnavigation/Recast/Source/RecastFilter.cpp
index 9df71ea3fbf..9d3e63c4820 100644
--- a/extern/recastnavigation/Recast/Source/RecastFilter.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastFilter.cpp
@@ -37,7 +37,7 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
+ rcScopedTimer timer(ctx, RC_TIMER_FILTER_LOW_OBSTACLES);
const int w = solid.width;
const int h = solid.height;
@@ -67,8 +67,6 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb
}
}
}
-
- ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES);
}
/// @par
@@ -86,7 +84,7 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_FILTER_BORDER);
+ rcScopedTimer timer(ctx, RC_TIMER_FILTER_BORDER);
const int w = solid.width;
const int h = solid.height;
@@ -128,7 +126,7 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
rcSpan* ns = solid.spans[dx + dy*w];
int nbot = -walkableClimb;
int ntop = ns ? (int)ns->smin : MAX_HEIGHT;
- // Skip neighbor if the gap between the spans is too small.
+ // Skip neightbour if the gap between the spans is too small.
if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight)
minh = rcMin(minh, nbot - bot);
@@ -137,7 +135,7 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
{
nbot = (int)ns->smax;
ntop = ns->next ? (int)ns->next->smin : MAX_HEIGHT;
- // Skip neighbor if the gap between the spans is too small.
+ // Skip neightbour if the gap between the spans is too small.
if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight)
{
minh = rcMin(minh, nbot - bot);
@@ -156,20 +154,19 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk
// The current span is close to a ledge if the drop to any
// neighbour span is less than the walkableClimb.
if (minh < -walkableClimb)
+ {
s->area = RC_NULL_AREA;
-
+ }
// If the difference between all neighbours is too large,
// we are at steep slope, mark the span as ledge.
- if ((asmax - asmin) > walkableClimb)
+ else if ((asmax - asmin) > walkableClimb)
{
s->area = RC_NULL_AREA;
}
}
}
}
-
- ctx->stopTimer(RC_TIMER_FILTER_BORDER);
-}
+}
/// @par
///
@@ -181,7 +178,7 @@ void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeight
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_FILTER_WALKABLE);
+ rcScopedTimer timer(ctx, RC_TIMER_FILTER_WALKABLE);
const int w = solid.width;
const int h = solid.height;
@@ -202,6 +199,4 @@ void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeight
}
}
}
-
- ctx->stopTimer(RC_TIMER_FILTER_WALKABLE);
}
diff --git a/extern/recastnavigation/Recast/Source/RecastLayers.cpp b/extern/recastnavigation/Recast/Source/RecastLayers.cpp
index 2d9658b2bed..22a357effa1 100644
--- a/extern/recastnavigation/Recast/Source/RecastLayers.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastLayers.cpp
@@ -38,7 +38,7 @@ struct rcLayerRegion
unsigned char layerId; // Layer ID
unsigned char nlayers; // Layer count
unsigned char nneis; // Neighbour count
- unsigned char base; // Flag indicating if the region is hte base of merged regions.
+ unsigned char base; // Flag indicating if the region is the base of merged regions.
};
@@ -87,12 +87,12 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_LAYERS);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_LAYERS);
const int w = chf.width;
const int h = chf.height;
- rcScopedDelete<unsigned char> srcReg = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned char> srcReg((unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP));
if (!srcReg)
{
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'srcReg' (%d).", chf.spanCount);
@@ -101,7 +101,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
memset(srcReg,0xff,sizeof(unsigned char)*chf.spanCount);
const int nsweeps = chf.width;
- rcScopedDelete<rcLayerSweepSpan> sweeps = (rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP);
+ rcScopedDelete<rcLayerSweepSpan> sweeps((rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP));
if (!sweeps)
{
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps);
@@ -212,7 +212,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
// Allocate and init layer regions.
const int nregs = (int)regId;
- rcScopedDelete<rcLayerRegion> regs = (rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP);
+ rcScopedDelete<rcLayerRegion> regs((rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP));
if (!regs)
{
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'regs' (%d).", nregs);
@@ -258,7 +258,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
const int ay = y + rcGetDirOffsetY(dir);
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
const unsigned char rai = srcReg[ai];
- if (rai != 0xff && rai != ri)
+ if (rai != 0xff && rai != ri && regs[ri].nneis < RC_MAX_NEIS)
addUnique(regs[ri].neis, regs[ri].nneis, rai);
}
}
@@ -293,7 +293,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
for (int i = 0; i < nregs; ++i)
{
rcLayerRegion& root = regs[i];
- // Skip alreadu visited.
+ // Skip already visited.
if (root.layerId != 0xff)
continue;
@@ -325,7 +325,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
continue;
// Skip if the height range would become too large.
const int ymin = rcMin(root.ymin, regn.ymin);
- const int ymax = rcMin(root.ymax, regn.ymax);
+ const int ymax = rcMax(root.ymax, regn.ymax);
if ((ymax - ymin) >= 255)
continue;
@@ -373,11 +373,11 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
continue;
// Skip if the height range would become too large.
const int ymin = rcMin(ri.ymin, rj.ymin);
- const int ymax = rcMin(ri.ymax, rj.ymax);
+ const int ymax = rcMax(ri.ymax, rj.ymax);
if ((ymax - ymin) >= 255)
continue;
- // Make sure that there is no overlap when mergin 'ri' and 'rj'.
+ // Make sure that there is no overlap when merging 'ri' and 'rj'.
bool overlap = false;
// Iterate over all regions which have the same layerId as 'rj'
for (int k = 0; k < nregs; ++k)
@@ -417,7 +417,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
// Add overlaid layers from 'rj' to 'ri'.
for (int k = 0; k < rj.nlayers; ++k)
addUnique(ri.layers, ri.nlayers, rj.layers[k]);
- // Update heigh bounds.
+ // Update height bounds.
ri.ymin = rcMin(ri.ymin, rj.ymin);
ri.ymax = rcMax(ri.ymax, rj.ymax);
}
@@ -446,10 +446,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
// No layers, return empty.
if (layerId == 0)
- {
- ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
return true;
- }
// Create layers.
rcAssert(lset.layers == 0);
@@ -481,10 +478,8 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
for (int i = 0; i < lset.nlayers; ++i)
{
unsigned char curId = (unsigned char)i;
-
- // Allocate memory for the current layer.
+
rcHeightfieldLayer* layer = &lset.layers[i];
- memset(layer, 0, sizeof(rcHeightfieldLayer));
const int gridSize = sizeof(unsigned char)*lw*lh;
@@ -528,7 +523,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
layer->cs = chf.cs;
layer->ch = chf.ch;
- // Adjust the bbox to fit the heighfield.
+ // Adjust the bbox to fit the heightfield.
rcVcopy(layer->bmin, bmin);
rcVcopy(layer->bmax, bmax);
layer->bmin[1] = bmin[1] + hmin*chf.ch;
@@ -542,7 +537,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
layer->miny = layer->height;
layer->maxy = 0;
- // Copy height and area from compact heighfield.
+ // Copy height and area from compact heightfield.
for (int y = 0; y < lh; ++y)
{
for (int x = 0; x < lw; ++x)
@@ -550,14 +545,14 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
const int cx = borderSize+x;
const int cy = borderSize+y;
const rcCompactCell& c = chf.cells[cx+cy*w];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ for (int j = (int)c.index, nj = (int)(c.index+c.count); j < nj; ++j)
{
- const rcCompactSpan& s = chf.spans[i];
+ const rcCompactSpan& s = chf.spans[j];
// Skip unassigned regions.
- if (srcReg[i] == 0xff)
+ if (srcReg[j] == 0xff)
continue;
// Skip of does nto belong to current layer.
- unsigned char lid = regs[srcReg[i]].layerId;
+ unsigned char lid = regs[srcReg[j]].layerId;
if (lid != curId)
continue;
@@ -570,7 +565,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
// Store height and area type.
const int idx = x+y*lw;
layer->heights[idx] = (unsigned char)(s.y - hmin);
- layer->areas[idx] = chf.areas[i];
+ layer->areas[idx] = chf.areas[j];
// Check connection.
unsigned char portal = 0;
@@ -614,7 +609,5 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
layer->miny = layer->maxy = 0;
}
- ctx->stopTimer(RC_TIMER_BUILD_LAYERS);
-
return true;
}
diff --git a/extern/recastnavigation/Recast/Source/RecastLog.cpp b/extern/recastnavigation/Recast/Source/RecastLog.cpp
deleted file mode 100644
index 27868042a1c..00000000000
--- a/extern/recastnavigation/Recast/Source/RecastLog.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// Copyright (c) 2009 Mikko Mononen memon@inside.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 "RecastLog.h"
-#include <stdio.h>
-#include <stdarg.h>
-
-static rcLog* g_log = 0;
-static rcBuildTimes* g_btimes = 0;
-
-rcLog::rcLog() :
- m_messageCount(0),
- m_textPoolSize(0)
-{
-}
-
-rcLog::~rcLog()
-{
- if (g_log == this)
- g_log = 0;
-}
-
-void rcLog::log(rcLogCategory category, const char* format, ...)
-{
- if (m_messageCount >= MAX_MESSAGES)
- return;
- char* dst = &m_textPool[m_textPoolSize];
- int n = TEXT_POOL_SIZE - m_textPoolSize;
- if (n < 2)
- return;
- // Store category
- *dst = (char)category;
- n--;
- // Store message
- va_list ap;
- va_start(ap, format);
- int ret = vsnprintf(dst+1, n-1, format, ap);
- va_end(ap);
- if (ret > 0)
- m_textPoolSize += ret+2;
- m_messages[m_messageCount++] = dst;
-}
-
-void rcSetLog(rcLog* log)
-{
- g_log = log;
-}
-
-rcLog* rcGetLog()
-{
- return g_log;
-}
-
-void rcSetBuildTimes(rcBuildTimes* btimes)
-{
- g_btimes = btimes;
-}
-
-rcBuildTimes* rcGetBuildTimes()
-{
- return g_btimes;
-}
diff --git a/extern/recastnavigation/Recast/Source/RecastMesh.cpp b/extern/recastnavigation/Recast/Source/RecastMesh.cpp
index e6d89eed3a8..e762318431f 100644
--- a/extern/recastnavigation/Recast/Source/RecastMesh.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastMesh.cpp
@@ -160,6 +160,7 @@ static unsigned short addVertex(unsigned short x, unsigned short y, unsigned sho
return (unsigned short)i;
}
+// Last time I checked the if version got compiled using cmov, which was a lot faster than module (with idiv).
inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; }
inline int next(int i, int n) { return i+1 < n ? i+1 : 0; }
@@ -288,6 +289,53 @@ static bool diagonal(int i, int j, int n, const int* verts, int* indices)
return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices);
}
+
+static bool diagonalieLoose(int i, int j, int n, const int* verts, int* indices)
+{
+ const int* d0 = &verts[(indices[i] & 0x0fffffff) * 4];
+ const int* d1 = &verts[(indices[j] & 0x0fffffff) * 4];
+
+ // For each edge (k,k+1) of P
+ for (int k = 0; k < n; k++)
+ {
+ int k1 = next(k, n);
+ // Skip edges incident to i or j
+ if (!((k == i) || (k1 == i) || (k == j) || (k1 == j)))
+ {
+ const int* p0 = &verts[(indices[k] & 0x0fffffff) * 4];
+ const int* p1 = &verts[(indices[k1] & 0x0fffffff) * 4];
+
+ if (vequal(d0, p0) || vequal(d1, p0) || vequal(d0, p1) || vequal(d1, p1))
+ continue;
+
+ if (intersectProp(d0, d1, p0, p1))
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool inConeLoose(int i, int j, int n, const int* verts, int* indices)
+{
+ const int* pi = &verts[(indices[i] & 0x0fffffff) * 4];
+ const int* pj = &verts[(indices[j] & 0x0fffffff) * 4];
+ const int* pi1 = &verts[(indices[next(i, n)] & 0x0fffffff) * 4];
+ const int* pin1 = &verts[(indices[prev(i, n)] & 0x0fffffff) * 4];
+
+ // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
+ if (leftOn(pin1, pi, pi1))
+ return leftOn(pi, pj, pin1) && leftOn(pj, pi, pi1);
+ // Assume (i-1,i,i+1) not collinear.
+ // else P[i] is reflex.
+ return !(leftOn(pi, pj, pi1) && leftOn(pj, pi, pin1));
+}
+
+static bool diagonalLoose(int i, int j, int n, const int* verts, int* indices)
+{
+ return inConeLoose(i, j, n, verts, indices) && diagonalieLoose(i, j, n, verts, indices);
+}
+
+
static int triangulate(int n, const int* verts, int* indices, int* tris)
{
int ntris = 0;
@@ -305,7 +353,7 @@ static int triangulate(int n, const int* verts, int* indices, int* tris)
while (n > 3)
{
int minLen = -1;
- int i_min = -1;
+ int mini = -1;
for (int i = 0; i < n; i++)
{
int i1 = next(i, n);
@@ -321,24 +369,51 @@ static int triangulate(int n, const int* verts, int* indices, int* tris)
if (minLen < 0 || len < minLen)
{
minLen = len;
- i_min = i;
+ mini = i;
}
}
}
- if (i_min == -1)
+ if (mini == -1)
{
- // Should not happen.
-/* printf("mini == -1 ntris=%d n=%d\n", ntris, n);
+ // We might get here because the contour has overlapping segments, like this:
+ //
+ // A o-o=====o---o B
+ // / |C D| \
+ // o o o o
+ // : : : :
+ // We'll try to recover by loosing up the inCone test a bit so that a diagonal
+ // like A-B or C-D can be found and we can continue.
+ minLen = -1;
+ mini = -1;
for (int i = 0; i < n; i++)
{
- printf("%d ", indices[i] & 0x0fffffff);
+ int i1 = next(i, n);
+ int i2 = next(i1, n);
+ if (diagonalLoose(i, i2, n, verts, indices))
+ {
+ const int* p0 = &verts[(indices[i] & 0x0fffffff) * 4];
+ const int* p2 = &verts[(indices[next(i2, n)] & 0x0fffffff) * 4];
+ int dx = p2[0] - p0[0];
+ int dy = p2[2] - p0[2];
+ int len = dx*dx + dy*dy;
+
+ if (minLen < 0 || len < minLen)
+ {
+ minLen = len;
+ mini = i;
+ }
+ }
+ }
+ if (mini == -1)
+ {
+ // The contour is messed up. This sometimes happens
+ // if the contour simplification is too aggressive.
+ return -ntris;
}
- printf("\n");*/
- return -ntris;
}
- int i = i_min;
+ int i = mini;
int i1 = next(i, n);
int i2 = next(i1, n);
@@ -453,8 +528,8 @@ static int getPolyMergeValue(unsigned short* pa, unsigned short* pb,
return dx*dx + dy*dy;
}
-static void mergePolys(unsigned short* pa, unsigned short* pb, int ea, int eb,
- unsigned short* tmp, const int nvp)
+static void mergePolyVerts(unsigned short* pa, unsigned short* pb, int ea, int eb,
+ unsigned short* tmp, const int nvp)
{
const int na = countPolyVerts(pa, nvp);
const int nb = countPolyVerts(pb, nvp);
@@ -526,7 +601,7 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho
// Find edges which share the removed vertex.
const int maxEdges = numTouchedVerts*2;
int nedges = 0;
- rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP);
+ rcScopedDelete<int> edges((int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP));
if (!edges)
{
ctx->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3);
@@ -550,9 +625,9 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho
// Check if the edge exists
bool exists = false;
- for (int k = 0; k < nedges; ++k)
+ for (int m = 0; m < nedges; ++m)
{
- int* e = &edges[k*3];
+ int* e = &edges[m*3];
if (e[1] == b)
{
// Exists, increment vertex share count.
@@ -606,7 +681,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
int nedges = 0;
- rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP);
+ rcScopedDelete<int> edges((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP));
if (!edges)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4);
@@ -614,15 +689,15 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
int nhole = 0;
- rcScopedDelete<int> hole = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
+ rcScopedDelete<int> hole((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP));
if (!hole)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp);
return false;
}
-
+
int nhreg = 0;
- rcScopedDelete<int> hreg = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
+ rcScopedDelete<int> hreg((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP));
if (!hreg)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp);
@@ -630,7 +705,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
int nharea = 0;
- rcScopedDelete<int> harea = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP);
+ rcScopedDelete<int> harea((int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP));
if (!harea)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp);
@@ -661,7 +736,8 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
// Remove the polygon.
unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2];
- memcpy(p,p2,sizeof(unsigned short)*nvp);
+ if (p != p2)
+ memcpy(p,p2,sizeof(unsigned short)*nvp);
memset(p+nvp,0xff,sizeof(unsigned short)*nvp);
mesh.regs[i] = mesh.regs[mesh.npolys-1];
mesh.areas[i] = mesh.areas[mesh.npolys-1];
@@ -671,7 +747,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
// Remove vertex.
- for (int i = (int)rem; i < mesh.nverts; ++i)
+ for (int i = (int)rem; i < mesh.nverts - 1; ++i)
{
mesh.verts[i*3+0] = mesh.verts[(i+1)*3+0];
mesh.verts[i*3+1] = mesh.verts[(i+1)*3+1];
@@ -746,22 +822,22 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
break;
}
- rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP);
+ rcScopedDelete<int> tris((int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP));
if (!tris)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3);
return false;
}
- rcScopedDelete<int> tverts = (int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP);
+ rcScopedDelete<int> tverts((int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP));
if (!tverts)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4);
return false;
}
- rcScopedDelete<int> thole = (int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP);
- if (!tverts)
+ rcScopedDelete<int> thole((int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP));
+ if (!thole)
{
ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole);
return false;
@@ -787,20 +863,20 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
// Merge the hole triangles back to polygons.
- rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned short> polys((unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP));
if (!polys)
{
ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp);
return false;
}
- rcScopedDelete<unsigned short> pregs = (unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned short> pregs((unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP));
if (!pregs)
{
ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris);
return false;
}
- rcScopedDelete<unsigned char> pareas = (unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP);
- if (!pregs)
+ rcScopedDelete<unsigned char> pareas((unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP));
+ if (!pareas)
{
ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris);
return false;
@@ -819,7 +895,14 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
polys[npolys*nvp+0] = (unsigned short)hole[t[0]];
polys[npolys*nvp+1] = (unsigned short)hole[t[1]];
polys[npolys*nvp+2] = (unsigned short)hole[t[2]];
- pregs[npolys] = (unsigned short)hreg[t[0]];
+
+ // If this polygon covers multiple region types then
+ // mark it as such
+ if (hreg[t[0]] != hreg[t[1]] || hreg[t[1]] != hreg[t[2]])
+ pregs[npolys] = RC_MULTIPLE_REGS;
+ else
+ pregs[npolys] = (unsigned short)hreg[t[0]];
+
pareas[npolys] = (unsigned char)harea[t[0]];
npolys++;
}
@@ -860,8 +943,13 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
// Found best, merge.
unsigned short* pa = &polys[bestPa*nvp];
unsigned short* pb = &polys[bestPb*nvp];
- mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
- memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp);
+ mergePolyVerts(pa, pb, bestEa, bestEb, tmpPoly, nvp);
+ if (pregs[bestPa] != pregs[bestPb])
+ pregs[bestPa] = RC_MULTIPLE_REGS;
+
+ unsigned short* last = &polys[(npolys-1)*nvp];
+ if (pb != last)
+ memcpy(pb, last, sizeof(unsigned short)*nvp);
pregs[bestPb] = pregs[npolys-1];
pareas[bestPb] = pareas[npolys-1];
npolys--;
@@ -905,13 +993,14 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_POLYMESH);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_POLYMESH);
rcVcopy(mesh.bmin, cset.bmin);
rcVcopy(mesh.bmax, cset.bmax);
mesh.cs = cset.cs;
mesh.ch = cset.ch;
mesh.borderSize = cset.borderSize;
+ mesh.maxEdgeError = cset.maxError;
int maxVertices = 0;
int maxTris = 0;
@@ -931,10 +1020,10 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
return false;
}
- rcScopedDelete<unsigned char> vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned char> vflags((unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP));
if (!vflags)
{
- ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
+ ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'vflags' (%d).", maxVertices);
return false;
}
memset(vflags, 0, maxVertices);
@@ -974,7 +1063,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
memset(mesh.regs, 0, sizeof(unsigned short)*maxTris);
memset(mesh.areas, 0, sizeof(unsigned char)*maxTris);
- rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP);
+ rcScopedDelete<int> nextVert((int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP));
if (!nextVert)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices);
@@ -982,7 +1071,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
}
memset(nextVert, 0, sizeof(int)*maxVertices);
- rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP);
+ rcScopedDelete<int> firstVert((int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP));
if (!firstVert)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
@@ -991,19 +1080,19 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
firstVert[i] = -1;
- rcScopedDelete<int> indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP);
+ rcScopedDelete<int> indices((int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP));
if (!indices)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont);
return false;
}
- rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP);
+ rcScopedDelete<int> tris((int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP));
if (!tris)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3);
return false;
}
- rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned short> polys((unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP));
if (!polys)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp);
@@ -1053,7 +1142,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
vflags[indices[j]] = 1;
}
}
-
+
// Build initial polygons.
int npolys = 0;
memset(polys, 0xff, maxVertsPerCont*nvp*sizeof(unsigned short));
@@ -1104,8 +1193,10 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
// Found best, merge.
unsigned short* pa = &polys[bestPa*nvp];
unsigned short* pb = &polys[bestPb*nvp];
- mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp);
- memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp);
+ mergePolyVerts(pa, pb, bestEa, bestEb, tmpPoly, nvp);
+ unsigned short* lastPoly = &polys[(npolys-1)*nvp];
+ if (pb != lastPoly)
+ memcpy(pb, lastPoly, sizeof(unsigned short)*nvp);
npolys--;
}
else
@@ -1150,6 +1241,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
}
// Remove vertex
// Note: mesh.nverts is already decremented inside removeVertex()!
+ // Fixup vertex flags
for (int j = i; j < mesh.nverts; ++j)
vflags[j] = vflags[j+1];
--i;
@@ -1212,8 +1304,6 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
}
- ctx->stopTimer(RC_TIMER_BUILD_POLYMESH);
-
return true;
}
@@ -1225,7 +1315,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
if (!nmeshes || !meshes)
return true;
- ctx->startTimer(RC_TIMER_MERGE_POLYMESH);
+ rcScopedTimer timer(ctx, RC_TIMER_MERGE_POLYMESH);
mesh.nvp = meshes[0]->nvp;
mesh.cs = meshes[0]->cs;
@@ -1286,7 +1376,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
}
memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys);
- rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP);
+ rcScopedDelete<int> nextVert((int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP));
if (!nextVert)
{
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts);
@@ -1294,7 +1384,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
}
memset(nextVert, 0, sizeof(int)*maxVerts);
- rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP);
+ rcScopedDelete<int> firstVert((int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP));
if (!firstVert)
{
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT);
@@ -1303,13 +1393,13 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i)
firstVert[i] = -1;
- rcScopedDelete<unsigned short> vremap = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM);
+ rcScopedDelete<unsigned short> vremap((unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM));
if (!vremap)
{
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh);
return false;
}
- memset(nextVert, 0, sizeof(int)*maxVerts);
+ memset(vremap, 0, sizeof(unsigned short)*maxVertsPerMesh);
for (int i = 0; i < nmeshes; ++i)
{
@@ -1318,6 +1408,12 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
const unsigned short ox = (unsigned short)floorf((pmesh->bmin[0]-mesh.bmin[0])/mesh.cs+0.5f);
const unsigned short oz = (unsigned short)floorf((pmesh->bmin[2]-mesh.bmin[2])/mesh.cs+0.5f);
+ bool isMinX = (ox == 0);
+ bool isMinZ = (oz == 0);
+ bool isMaxX = ((unsigned short)floorf((mesh.bmax[0] - pmesh->bmax[0]) / mesh.cs + 0.5f)) == 0;
+ bool isMaxZ = ((unsigned short)floorf((mesh.bmax[2] - pmesh->bmax[2]) / mesh.cs + 0.5f)) == 0;
+ bool isOnBorder = (isMinX || isMinZ || isMaxX || isMaxZ);
+
for (int j = 0; j < pmesh->nverts; ++j)
{
unsigned short* v = &pmesh->verts[j*3];
@@ -1338,6 +1434,36 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
if (src[k] == RC_MESH_NULL_IDX) break;
tgt[k] = vremap[src[k]];
}
+
+ if (isOnBorder)
+ {
+ for (int k = mesh.nvp; k < mesh.nvp * 2; ++k)
+ {
+ if (src[k] & 0x8000 && src[k] != 0xffff)
+ {
+ unsigned short dir = src[k] & 0xf;
+ switch (dir)
+ {
+ case 0: // Portal x-
+ if (isMinX)
+ tgt[k] = src[k];
+ break;
+ case 1: // Portal z+
+ if (isMaxZ)
+ tgt[k] = src[k];
+ break;
+ case 2: // Portal x+
+ if (isMaxX)
+ tgt[k] = src[k];
+ break;
+ case 3: // Portal z-
+ if (isMinZ)
+ tgt[k] = src[k];
+ break;
+ }
+ }
+ }
+ }
}
}
@@ -1357,7 +1483,70 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r
ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff);
}
- ctx->stopTimer(RC_TIMER_MERGE_POLYMESH);
+ return true;
+}
+
+bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst)
+{
+ rcAssert(ctx);
+
+ // Destination must be empty.
+ rcAssert(dst.verts == 0);
+ rcAssert(dst.polys == 0);
+ rcAssert(dst.regs == 0);
+ rcAssert(dst.areas == 0);
+ rcAssert(dst.flags == 0);
+
+ dst.nverts = src.nverts;
+ dst.npolys = src.npolys;
+ dst.maxpolys = src.npolys;
+ dst.nvp = src.nvp;
+ rcVcopy(dst.bmin, src.bmin);
+ rcVcopy(dst.bmax, src.bmax);
+ dst.cs = src.cs;
+ dst.ch = src.ch;
+ dst.borderSize = src.borderSize;
+ dst.maxEdgeError = src.maxEdgeError;
+
+ dst.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.nverts*3, RC_ALLOC_PERM);
+ if (!dst.verts)
+ {
+ ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.verts' (%d).", src.nverts*3);
+ return false;
+ }
+ memcpy(dst.verts, src.verts, sizeof(unsigned short)*src.nverts*3);
+
+ dst.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys*2*src.nvp, RC_ALLOC_PERM);
+ if (!dst.polys)
+ {
+ ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.polys' (%d).", src.npolys*2*src.nvp);
+ return false;
+ }
+ memcpy(dst.polys, src.polys, sizeof(unsigned short)*src.npolys*2*src.nvp);
+
+ dst.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM);
+ if (!dst.regs)
+ {
+ ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.regs' (%d).", src.npolys);
+ return false;
+ }
+ memcpy(dst.regs, src.regs, sizeof(unsigned short)*src.npolys);
+
+ dst.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*src.npolys, RC_ALLOC_PERM);
+ if (!dst.areas)
+ {
+ ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.areas' (%d).", src.npolys);
+ return false;
+ }
+ memcpy(dst.areas, src.areas, sizeof(unsigned char)*src.npolys);
+
+ dst.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM);
+ if (!dst.flags)
+ {
+ ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.flags' (%d).", src.npolys);
+ return false;
+ }
+ memcpy(dst.flags, src.flags, sizeof(unsigned short)*src.npolys);
return true;
}
diff --git a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp
index b52da597675..f1270cf2027 100644
--- a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp
@@ -37,11 +37,12 @@ struct rcHeightPatch
int xmin, ymin, width, height;
};
+
inline float vdot2(const float* a, const float* b)
{
return a[0]*b[0] + a[2]*b[2];
}
-
+
inline float vdistSq2(const float* p, const float* q)
{
const float dx = q[0] - p[0];
@@ -55,7 +56,7 @@ inline float vdist2(const float* p, const float* q)
}
inline float vcross2(const float* p1, const float* p2, const float* p3)
-{
+{
const float u1 = p2[0] - p1[0];
const float v1 = p2[2] - p1[2];
const float u2 = p3[0] - p1[0];
@@ -67,21 +68,27 @@ static bool circumCircle(const float* p1, const float* p2, const float* p3,
float* c, float& r)
{
static const float EPS = 1e-6f;
+ // Calculate the circle relative to p1, to avoid some precision issues.
+ const float v1[3] = {0,0,0};
+ float v2[3], v3[3];
+ rcVsub(v2, p2,p1);
+ rcVsub(v3, p3,p1);
- const float cp = vcross2(p1, p2, p3);
+ const float cp = vcross2(v1, v2, v3);
if (fabsf(cp) > EPS)
{
- const float p1Sq = vdot2(p1,p1);
- const float p2Sq = vdot2(p2,p2);
- const float p3Sq = vdot2(p3,p3);
- c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp);
- c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp);
- r = vdist2(c, p1);
+ const float v1Sq = vdot2(v1,v1);
+ const float v2Sq = vdot2(v2,v2);
+ const float v3Sq = vdot2(v3,v3);
+ c[0] = (v1Sq*(v2[2]-v3[2]) + v2Sq*(v3[2]-v1[2]) + v3Sq*(v1[2]-v2[2])) / (2*cp);
+ c[1] = 0;
+ c[2] = (v1Sq*(v3[0]-v2[0]) + v2Sq*(v1[0]-v3[0]) + v3Sq*(v2[0]-v1[0])) / (2*cp);
+ r = vdist2(c, v1);
+ rcVadd(c, c, p1);
return true;
}
-
- c[0] = p1[0];
- c[2] = p1[2];
+
+ rcVcopy(c, p1);
r = 0;
return false;
}
@@ -92,7 +99,7 @@ static float distPtTri(const float* p, const float* a, const float* b, const flo
rcVsub(v0, c,a);
rcVsub(v1, b,a);
rcVsub(v2, p,a);
-
+
const float dot00 = vdot2(v0, v0);
const float dot01 = vdot2(v0, v1);
const float dot02 = vdot2(v0, v2);
@@ -177,7 +184,7 @@ static float distToTriMesh(const float* p, const float* verts, const int /*nvert
static float distToPoly(int nvert, const float* verts, const float* p)
{
-
+
float dmin = FLT_MAX;
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++)
@@ -195,42 +202,79 @@ static float distToPoly(int nvert, const float* verts, const float* p)
static unsigned short getHeight(const float fx, const float fy, const float fz,
const float /*cs*/, const float ics, const float ch,
- const rcHeightPatch& hp)
+ const int radius, const rcHeightPatch& hp)
{
int ix = (int)floorf(fx*ics + 0.01f);
int iz = (int)floorf(fz*ics + 0.01f);
- ix = rcClamp(ix-hp.xmin, 0, hp.width);
- iz = rcClamp(iz-hp.ymin, 0, hp.height);
+ ix = rcClamp(ix-hp.xmin, 0, hp.width - 1);
+ iz = rcClamp(iz-hp.ymin, 0, hp.height - 1);
unsigned short h = hp.data[ix+iz*hp.width];
if (h == RC_UNSET_HEIGHT)
{
// Special case when data might be bad.
- // Find nearest neighbour pixel which has valid height.
- const int off[8*2] = { -1,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1};
+ // Walk adjacent cells in a spiral up to 'radius', and look
+ // for a pixel which has a valid height.
+ int x = 1, z = 0, dx = 1, dz = 0;
+ int maxSize = radius * 2 + 1;
+ int maxIter = maxSize * maxSize - 1;
+
+ int nextRingIterStart = 8;
+ int nextRingIters = 16;
+
float dmin = FLT_MAX;
- for (int i = 0; i < 8; ++i)
+ for (int i = 0; i < maxIter; i++)
{
- const int nx = ix+off[i*2+0];
- const int nz = iz+off[i*2+1];
- if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue;
- const unsigned short nh = hp.data[nx+nz*hp.width];
- if (nh == RC_UNSET_HEIGHT) continue;
+ const int nx = ix + x;
+ const int nz = iz + z;
+
+ if (nx >= 0 && nz >= 0 && nx < hp.width && nz < hp.height)
+ {
+ const unsigned short nh = hp.data[nx + nz*hp.width];
+ if (nh != RC_UNSET_HEIGHT)
+ {
+ const float d = fabsf(nh*ch - fy);
+ if (d < dmin)
+ {
+ h = nh;
+ dmin = d;
+ }
+ }
+ }
- const float d = fabsf(nh*ch - fy);
- if (d < dmin)
+ // We are searching in a grid which looks approximately like this:
+ // __________
+ // |2 ______ 2|
+ // | |1 __ 1| |
+ // | | |__| | |
+ // | |______| |
+ // |__________|
+ // We want to find the best height as close to the center cell as possible. This means that
+ // if we find a height in one of the neighbor cells to the center, we don't want to
+ // expand further out than the 8 neighbors - we want to limit our search to the closest
+ // of these "rings", but the best height in the ring.
+ // For example, the center is just 1 cell. We checked that at the entrance to the function.
+ // The next "ring" contains 8 cells (marked 1 above). Those are all the neighbors to the center cell.
+ // The next one again contains 16 cells (marked 2). In general each ring has 8 additional cells, which
+ // can be thought of as adding 2 cells around the "center" of each side when we expand the ring.
+ // Here we detect if we are about to enter the next ring, and if we are and we have found
+ // a height, we abort the search.
+ if (i + 1 == nextRingIterStart)
{
- h = nh;
- dmin = d;
+ if (h != RC_UNSET_HEIGHT)
+ break;
+
+ nextRingIterStart += nextRingIters;
+ nextRingIters += 8;
}
-
-/* const float dx = (nx+0.5f)*cs - fx;
- const float dz = (nz+0.5f)*cs - fz;
- const float d = dx*dx+dz*dz;
- if (d < dmin)
+
+ if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z)))
{
- h = nh;
- dmin = d;
- } */
+ int tmp = dx;
+ dx = -dz;
+ dz = tmp;
+ }
+ x += dx;
+ z += dz;
}
}
return h;
@@ -239,8 +283,8 @@ static unsigned short getHeight(const float fx, const float fy, const float fz,
enum EdgeValues
{
- UNDEF = -1,
- HULL = -2,
+ EV_UNDEF = -1,
+ EV_HULL = -2,
};
static int findEdge(const int* edges, int nedges, int s, int t)
@@ -251,7 +295,7 @@ static int findEdge(const int* edges, int nedges, int s, int t)
if ((e[0] == s && e[1] == t) || (e[0] == t && e[1] == s))
return i;
}
- return UNDEF;
+ return EV_UNDEF;
}
static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges, int s, int t, int l, int r)
@@ -259,33 +303,33 @@ static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges,
if (nedges >= maxEdges)
{
ctx->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges);
- return UNDEF;
+ return EV_UNDEF;
}
- // Add edge if not already in the triangulation.
+ // Add edge if not already in the triangulation.
int e = findEdge(edges, nedges, s, t);
- if (e == UNDEF)
+ if (e == EV_UNDEF)
{
- int* e = &edges[nedges*4];
- e[0] = s;
- e[1] = t;
- e[2] = l;
- e[3] = r;
+ int* edge = &edges[nedges*4];
+ edge[0] = s;
+ edge[1] = t;
+ edge[2] = l;
+ edge[3] = r;
return nedges++;
}
else
{
- return UNDEF;
+ return EV_UNDEF;
}
}
static void updateLeftFace(int* e, int s, int t, int f)
{
- if (e[0] == s && e[1] == t && e[2] == UNDEF)
+ if (e[0] == s && e[1] == t && e[2] == EV_UNDEF)
e[2] = f;
- else if (e[1] == s && e[0] == t && e[3] == UNDEF)
+ else if (e[1] == s && e[0] == t && e[3] == EV_UNDEF)
e[3] = f;
-}
+}
static int overlapSegSeg2d(const float* a, const float* b, const float* c, const float* d)
{
@@ -297,7 +341,7 @@ static int overlapSegSeg2d(const float* a, const float* b, const float* c, const
float a4 = a3 + a2 - a1;
if (a3 * a4 < 0.0f)
return 1;
- }
+ }
return 0;
}
@@ -319,28 +363,28 @@ static bool overlapEdges(const float* pts, const int* edges, int nedges, int s1,
static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e)
{
static const float EPS = 1e-5f;
-
+
int* edge = &edges[e*4];
// Cache s and t.
int s,t;
- if (edge[2] == UNDEF)
+ if (edge[2] == EV_UNDEF)
{
s = edge[0];
t = edge[1];
}
- else if (edge[3] == UNDEF)
+ else if (edge[3] == EV_UNDEF)
{
s = edge[1];
t = edge[0];
}
else
{
- // Edge already completed.
+ // Edge already completed.
return;
}
- // Find best point on left of edge.
+ // Find best point on left of edge.
int pt = npts;
float c[3] = {0,0,0};
float r = -1;
@@ -384,23 +428,23 @@ static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges
}
}
- // Add new triangle or update edge info if s-t is on hull.
+ // Add new triangle or update edge info if s-t is on hull.
if (pt < npts)
{
- // Update face information of edge being completed.
+ // Update face information of edge being completed.
updateLeftFace(&edges[e*4], s, t, nfaces);
- // Add new edge or update face info of old edge.
+ // Add new edge or update face info of old edge.
e = findEdge(edges, nedges, pt, s);
- if (e == UNDEF)
- addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF);
+ if (e == EV_UNDEF)
+ addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, EV_UNDEF);
else
updateLeftFace(&edges[e*4], pt, s, nfaces);
- // Add new edge or update face info of old edge.
+ // Add new edge or update face info of old edge.
e = findEdge(edges, nedges, t, pt);
- if (e == UNDEF)
- addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF);
+ if (e == EV_UNDEF)
+ addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, EV_UNDEF);
else
updateLeftFace(&edges[e*4], t, pt, nfaces);
@@ -408,7 +452,7 @@ static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges
}
else
{
- updateLeftFace(&edges[e*4], s, t, HULL);
+ updateLeftFace(&edges[e*4], s, t, EV_HULL);
}
}
@@ -422,18 +466,18 @@ static void delaunayHull(rcContext* ctx, const int npts, const float* pts,
edges.resize(maxEdges*4);
for (int i = 0, j = nhull-1; i < nhull; j=i++)
- addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], HULL, UNDEF);
+ addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], EV_HULL, EV_UNDEF);
int currentEdge = 0;
while (currentEdge < nedges)
{
- if (edges[currentEdge*4+2] == UNDEF)
+ if (edges[currentEdge*4+2] == EV_UNDEF)
completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
- if (edges[currentEdge*4+3] == UNDEF)
+ if (edges[currentEdge*4+3] == EV_UNDEF)
completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
currentEdge++;
}
-
+
// Create tris
tris.resize(nfaces*4);
for (int i = 0; i < nfaces*4; ++i)
@@ -488,6 +532,97 @@ static void delaunayHull(rcContext* ctx, const int npts, const float* pts,
}
}
+// Calculate minimum extend of the polygon.
+static float polyMinExtent(const float* verts, const int nverts)
+{
+ float minDist = FLT_MAX;
+ for (int i = 0; i < nverts; i++)
+ {
+ const int ni = (i+1) % nverts;
+ const float* p1 = &verts[i*3];
+ const float* p2 = &verts[ni*3];
+ float maxEdgeDist = 0;
+ for (int j = 0; j < nverts; j++)
+ {
+ if (j == i || j == ni) continue;
+ float d = distancePtSeg2d(&verts[j*3], p1,p2);
+ maxEdgeDist = rcMax(maxEdgeDist, d);
+ }
+ minDist = rcMin(minDist, maxEdgeDist);
+ }
+ return rcSqrt(minDist);
+}
+
+// Last time I checked the if version got compiled using cmov, which was a lot faster than module (with idiv).
+inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; }
+inline int next(int i, int n) { return i+1 < n ? i+1 : 0; }
+
+static void triangulateHull(const int /*nverts*/, const float* verts, const int nhull, const int* hull, rcIntArray& tris)
+{
+ int start = 0, left = 1, right = nhull-1;
+
+ // Start from an ear with shortest perimeter.
+ // This tends to favor well formed triangles as starting point.
+ float dmin = 0;
+ for (int i = 0; i < nhull; i++)
+ {
+ int pi = prev(i, nhull);
+ int ni = next(i, nhull);
+ const float* pv = &verts[hull[pi]*3];
+ const float* cv = &verts[hull[i]*3];
+ const float* nv = &verts[hull[ni]*3];
+ const float d = vdist2(pv,cv) + vdist2(cv,nv) + vdist2(nv,pv);
+ if (d < dmin)
+ {
+ start = i;
+ left = ni;
+ right = pi;
+ dmin = d;
+ }
+ }
+
+ // Add first triangle
+ tris.push(hull[start]);
+ tris.push(hull[left]);
+ tris.push(hull[right]);
+ tris.push(0);
+
+ // Triangulate the polygon by moving left or right,
+ // depending on which triangle has shorter perimeter.
+ // This heuristic was chose emprically, since it seems
+ // handle tesselated straight edges well.
+ while (next(left, nhull) != right)
+ {
+ // Check to see if se should advance left or right.
+ int nleft = next(left, nhull);
+ int nright = prev(right, nhull);
+
+ const float* cvleft = &verts[hull[left]*3];
+ const float* nvleft = &verts[hull[nleft]*3];
+ const float* cvright = &verts[hull[right]*3];
+ const float* nvright = &verts[hull[nright]*3];
+ const float dleft = vdist2(cvleft, nvleft) + vdist2(nvleft, cvright);
+ const float dright = vdist2(cvright, nvright) + vdist2(cvleft, nvright);
+
+ if (dleft < dright)
+ {
+ tris.push(hull[left]);
+ tris.push(hull[nleft]);
+ tris.push(hull[right]);
+ tris.push(0);
+ left = nleft;
+ }
+ else
+ {
+ tris.push(hull[left]);
+ tris.push(hull[nright]);
+ tris.push(hull[right]);
+ tris.push(0);
+ right = nright;
+ }
+ }
+}
+
inline float getJitterX(const int i)
{
@@ -501,9 +636,9 @@ inline float getJitterY(const int i)
static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
const float sampleDist, const float sampleMaxError,
- const rcCompactHeightfield& chf, const rcHeightPatch& hp,
- float* verts, int& nverts, rcIntArray& tris,
- rcIntArray& edges, rcIntArray& samples)
+ const int heightSearchRadius, const rcCompactHeightfield& chf,
+ const rcHeightPatch& hp, float* verts, int& nverts,
+ rcIntArray& tris, rcIntArray& edges, rcIntArray& samples)
{
static const int MAX_VERTS = 127;
static const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
@@ -511,16 +646,22 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
float edge[(MAX_VERTS_PER_EDGE+1)*3];
int hull[MAX_VERTS];
int nhull = 0;
-
+
nverts = 0;
-
+
for (int i = 0; i < nin; ++i)
rcVcopy(&verts[i*3], &in[i*3]);
nverts = nin;
+ edges.resize(0);
+ tris.resize(0);
+
const float cs = chf.cs;
const float ics = 1.0f/cs;
+ // Calculate minimum extents of the polygon based on input data.
+ float minExtent = polyMinExtent(verts, nverts);
+
// Tessellate outlines.
// This is done in separate pass in order to ensure
// seamless height values across the ply boundaries.
@@ -566,7 +707,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
pos[0] = vj[0] + dx*u;
pos[1] = vj[1] + dy*u;
pos[2] = vj[2] + dz*u;
- pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, hp)*chf.ch;
+ pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, heightSearchRadius, hp)*chf.ch;
}
// Simplify samples.
int idx[MAX_VERTS_PER_EDGE] = {0,nn};
@@ -579,23 +720,23 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
const float* vb = &edge[b*3];
// Find maximum deviation along the segment.
float maxd = 0;
- int i_max = -1;
+ int maxi = -1;
for (int m = a+1; m < b; ++m)
{
- float d = distancePtSeg(&edge[m*3],va,vb);
- if (d > maxd)
+ float dev = distancePtSeg(&edge[m*3],va,vb);
+ if (dev > maxd)
{
- maxd = d;
- i_max = m;
+ maxd = dev;
+ maxi = m;
}
}
// If the max deviation is larger than accepted error,
// add new point, else continue to next segment.
- if (i_max != -1 && maxd > rcSqr(sampleMaxError))
+ if (maxi != -1 && maxd > rcSqr(sampleMaxError))
{
for (int m = nidx; m > k; --m)
idx[m] = idx[m-1];
- idx[k+1] = i_max;
+ idx[k+1] = maxi;
nidx++;
}
else
@@ -627,27 +768,26 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
}
}
-
+ // If the polygon minimum extent is small (sliver or small triangle), do not try to add internal points.
+ if (minExtent < sampleDist*2)
+ {
+ triangulateHull(nverts, verts, nhull, hull, tris);
+ return true;
+ }
+
// Tessellate the base mesh.
- edges.resize(0);
- tris.resize(0);
-
- delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
+ // We're using the triangulateHull instead of delaunayHull as it tends to
+ // create a bit better triangulation for long thing triangles when there
+ // are no internal points.
+ triangulateHull(nverts, verts, nhull, hull, tris);
if (tris.size() == 0)
{
// Could not triangulate the poly, make sure there is some valid data there.
- ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data.");
- for (int i = 2; i < nverts; ++i)
- {
- tris.push(0);
- tris.push(i-1);
- tris.push(i);
- tris.push(0);
- }
+ ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon (%d verts).", nverts);
return true;
}
-
+
if (sampleDist > 0)
{
// Create sample locations in a grid.
@@ -675,12 +815,12 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
// Make sure the samples are not too close to the edges.
if (distToPoly(nin,in,pt) > -sampleDist/2) continue;
samples.push(x);
- samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, hp));
+ samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, heightSearchRadius, hp));
samples.push(z);
samples.push(0); // Not added
}
}
-
+
// Add the samples starting from the one that has the most
// error. The procedure stops when all samples are added
// or when the max error is within treshold.
@@ -689,7 +829,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
{
if (nverts >= MAX_VERTS)
break;
-
+
// Find sample with most error.
float bestpt[3] = {0,0,0};
float bestd = 0;
@@ -727,45 +867,38 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
edges.resize(0);
tris.resize(0);
delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
- }
+ }
}
-
+
const int ntris = tris.size()/4;
if (ntris > MAX_TRIS)
{
tris.resize(MAX_TRIS*4);
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS);
}
-
+
return true;
}
-static void getHeightData(const rcCompactHeightfield& chf,
- const unsigned short* poly, const int npoly,
- const unsigned short* verts, const int bs,
- rcHeightPatch& hp, rcIntArray& stack)
+static void seedArrayWithPolyCenter(rcContext* ctx, const rcCompactHeightfield& chf,
+ const unsigned short* poly, const int npoly,
+ const unsigned short* verts, const int bs,
+ rcHeightPatch& hp, rcIntArray& array)
{
- // Floodfill the heightfield to get 2D height data,
- // starting at vertex locations as seeds.
-
// Note: Reads to the compact heightfield are offset by border size (bs)
// since border size offset is already removed from the polymesh vertices.
- memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
-
- stack.resize(0);
-
static const int offset[9*2] =
{
0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0,
};
- // Use poly vertices as seed points for the flood fill.
- for (int j = 0; j < npoly; ++j)
+ // Find cell closest to a poly vertex
+ int startCellX = 0, startCellY = 0, startSpanIndex = -1;
+ int dmin = RC_UNSET_HEIGHT;
+ for (int j = 0; j < npoly && dmin > 0; ++j)
{
- int cx = 0, cz = 0, ci =-1;
- int dmin = RC_UNSET_HEIGHT;
- for (int k = 0; k < 9; ++k)
+ for (int k = 0; k < 9 && dmin > 0; ++k)
{
const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0];
const int ay = (int)verts[poly[j]*3+1];
@@ -775,118 +908,210 @@ static void getHeightData(const rcCompactHeightfield& chf,
continue;
const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni && dmin > 0; ++i)
{
const rcCompactSpan& s = chf.spans[i];
int d = rcAbs(ay - (int)s.y);
if (d < dmin)
{
- cx = ax;
- cz = az;
- ci = i;
+ startCellX = ax;
+ startCellY = az;
+ startSpanIndex = i;
dmin = d;
}
}
}
- if (ci != -1)
- {
- stack.push(cx);
- stack.push(cz);
- stack.push(ci);
- }
}
- // Find center of the polygon using flood fill.
- int pcx = 0, pcz = 0;
+ rcAssert(startSpanIndex != -1);
+ // Find center of the polygon
+ int pcx = 0, pcy = 0;
for (int j = 0; j < npoly; ++j)
{
pcx += (int)verts[poly[j]*3+0];
- pcz += (int)verts[poly[j]*3+2];
+ pcy += (int)verts[poly[j]*3+2];
}
pcx /= npoly;
- pcz /= npoly;
-
- for (int i = 0; i < stack.size(); i += 3)
- {
- int cx = stack[i+0];
- int cy = stack[i+1];
- int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
- hp.data[idx] = 1;
- }
+ pcy /= npoly;
- while (stack.size() > 0)
+ // Use seeds array as a stack for DFS
+ array.resize(0);
+ array.push(startCellX);
+ array.push(startCellY);
+ array.push(startSpanIndex);
+
+ int dirs[] = { 0, 1, 2, 3 };
+ memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
+ // DFS to move to the center. Note that we need a DFS here and can not just move
+ // directly towards the center without recording intermediate nodes, even though the polygons
+ // are convex. In very rare we can get stuck due to contour simplification if we do not
+ // record nodes.
+ int cx = -1, cy = -1, ci = -1;
+ while (true)
{
- int ci = stack.pop();
- int cy = stack.pop();
- int cx = stack.pop();
-
- // Check if close to center of the polygon.
- if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1)
+ if (array.size() < 3)
{
- stack.resize(0);
- stack.push(cx);
- stack.push(cy);
- stack.push(ci);
+ ctx->log(RC_LOG_WARNING, "Walk towards polygon center failed to reach center");
break;
}
-
+
+ ci = array.pop();
+ cy = array.pop();
+ cx = array.pop();
+
+ if (cx == pcx && cy == pcy)
+ break;
+
+ // If we are already at the correct X-position, prefer direction
+ // directly towards the center in the Y-axis; otherwise prefer
+ // direction in the X-axis
+ int directDir;
+ if (cx == pcx)
+ directDir = rcGetDirForOffset(0, pcy > cy ? 1 : -1);
+ else
+ directDir = rcGetDirForOffset(pcx > cx ? 1 : -1, 0);
+
+ // Push the direct dir last so we start with this on next iteration
+ rcSwap(dirs[directDir], dirs[3]);
+
const rcCompactSpan& cs = chf.spans[ci];
-
- for (int dir = 0; dir < 4; ++dir)
+ for (int i = 0; i < 4; i++)
{
- if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
-
- const int ax = cx + rcGetDirOffsetX(dir);
- const int ay = cy + rcGetDirOffsetY(dir);
-
- if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
- ay < hp.ymin || ay >= (hp.ymin+hp.height))
+ int dir = dirs[i];
+ if (rcGetCon(cs, dir) == RC_NOT_CONNECTED)
continue;
-
- if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
+
+ int newX = cx + rcGetDirOffsetX(dir);
+ int newY = cy + rcGetDirOffsetY(dir);
+
+ int hpx = newX - hp.xmin;
+ int hpy = newY - hp.ymin;
+ if (hpx < 0 || hpx >= hp.width || hpy < 0 || hpy >= hp.height)
continue;
-
- const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
- int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
- hp.data[idx] = 1;
-
- stack.push(ax);
- stack.push(ay);
- stack.push(ai);
+ if (hp.data[hpx+hpy*hp.width] != 0)
+ continue;
+
+ hp.data[hpx+hpy*hp.width] = 1;
+ array.push(newX);
+ array.push(newY);
+ array.push((int)chf.cells[(newX+bs)+(newY+bs)*chf.width].index + rcGetCon(cs, dir));
}
+
+ rcSwap(dirs[directDir], dirs[3]);
}
+ array.resize(0);
+ // getHeightData seeds are given in coordinates with borders
+ array.push(cx+bs);
+ array.push(cy+bs);
+ array.push(ci);
+
memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
+ const rcCompactSpan& cs = chf.spans[ci];
+ hp.data[cx-hp.xmin+(cy-hp.ymin)*hp.width] = cs.y;
+}
+
- // Mark start locations.
- for (int i = 0; i < stack.size(); i += 3)
+static void push3(rcIntArray& queue, int v1, int v2, int v3)
+{
+ queue.resize(queue.size() + 3);
+ queue[queue.size() - 3] = v1;
+ queue[queue.size() - 2] = v2;
+ queue[queue.size() - 1] = v3;
+}
+
+static void getHeightData(rcContext* ctx, const rcCompactHeightfield& chf,
+ const unsigned short* poly, const int npoly,
+ const unsigned short* verts, const int bs,
+ rcHeightPatch& hp, rcIntArray& queue,
+ int region)
+{
+ // Note: Reads to the compact heightfield are offset by border size (bs)
+ // since border size offset is already removed from the polymesh vertices.
+
+ queue.resize(0);
+ // Set all heights to RC_UNSET_HEIGHT.
+ memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
+
+ bool empty = true;
+
+ // We cannot sample from this poly if it was created from polys
+ // of different regions. If it was then it could potentially be overlapping
+ // with polys of that region and the heights sampled here could be wrong.
+ if (region != RC_MULTIPLE_REGS)
{
- int cx = stack[i+0];
- int cy = stack[i+1];
- int ci = stack[i+2];
- int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
- const rcCompactSpan& cs = chf.spans[ci];
- hp.data[idx] = cs.y;
+ // Copy the height from the same region, and mark region borders
+ // as seed points to fill the rest.
+ for (int hy = 0; hy < hp.height; hy++)
+ {
+ int y = hp.ymin + hy + bs;
+ for (int hx = 0; hx < hp.width; hx++)
+ {
+ int x = hp.xmin + hx + bs;
+ const rcCompactCell& c = chf.cells[x + y*chf.width];
+ for (int i = (int)c.index, ni = (int)(c.index + c.count); i < ni; ++i)
+ {
+ const rcCompactSpan& s = chf.spans[i];
+ if (s.reg == region)
+ {
+ // Store height
+ hp.data[hx + hy*hp.width] = s.y;
+ empty = false;
+
+ // If any of the neighbours is not in same region,
+ // add the current location as flood fill start
+ bool border = false;
+ for (int dir = 0; dir < 4; ++dir)
+ {
+ if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
+ {
+ const int ax = x + rcGetDirOffsetX(dir);
+ const int ay = y + rcGetDirOffsetY(dir);
+ const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(s, dir);
+ const rcCompactSpan& as = chf.spans[ai];
+ if (as.reg != region)
+ {
+ border = true;
+ break;
+ }
+ }
+ }
+ if (border)
+ push3(queue, x, y, i);
+ break;
+ }
+ }
+ }
+ }
}
+ // if the polygon does not contain any points from the current region (rare, but happens)
+ // or if it could potentially be overlapping polygons of the same region,
+ // then use the center as the seed point.
+ if (empty)
+ seedArrayWithPolyCenter(ctx, chf, poly, npoly, verts, bs, hp, queue);
+
static const int RETRACT_SIZE = 256;
int head = 0;
- while (head*3 < stack.size())
+ // We assume the seed is centered in the polygon, so a BFS to collect
+ // height data will ensure we do not move onto overlapping polygons and
+ // sample wrong heights.
+ while (head*3 < queue.size())
{
- int cx = stack[head*3+0];
- int cy = stack[head*3+1];
- int ci = stack[head*3+2];
+ int cx = queue[head*3+0];
+ int cy = queue[head*3+1];
+ int ci = queue[head*3+2];
head++;
if (head >= RETRACT_SIZE)
{
head = 0;
- if (stack.size() > RETRACT_SIZE*3)
- memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3));
- stack.resize(stack.size()-RETRACT_SIZE*3);
+ if (queue.size() > RETRACT_SIZE*3)
+ memmove(&queue[0], &queue[RETRACT_SIZE*3], sizeof(int)*(queue.size()-RETRACT_SIZE*3));
+ queue.resize(queue.size()-RETRACT_SIZE*3);
}
-
+
const rcCompactSpan& cs = chf.spans[ci];
for (int dir = 0; dir < 4; ++dir)
{
@@ -894,26 +1119,23 @@ static void getHeightData(const rcCompactHeightfield& chf,
const int ax = cx + rcGetDirOffsetX(dir);
const int ay = cy + rcGetDirOffsetY(dir);
+ const int hx = ax - hp.xmin - bs;
+ const int hy = ay - hp.ymin - bs;
- if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
- ay < hp.ymin || ay >= (hp.ymin+hp.height))
+ if ((unsigned int)hx >= (unsigned int)hp.width || (unsigned int)hy >= (unsigned int)hp.height)
continue;
- if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != RC_UNSET_HEIGHT)
+ if (hp.data[hx + hy*hp.width] != RC_UNSET_HEIGHT)
continue;
- const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
-
+ const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir);
const rcCompactSpan& as = chf.spans[ai];
- int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
- hp.data[idx] = as.y;
-
- stack.push(ax);
- stack.push(ay);
- stack.push(ai);
+
+ hp.data[hx + hy*hp.width] = as.y;
+
+ push3(queue, ax, ay, ai);
}
}
-
}
static unsigned char getEdgeFlags(const float* va, const float* vb,
@@ -923,7 +1145,7 @@ static unsigned char getEdgeFlags(const float* va, const float* vb,
static const float thrSqr = rcSqr(0.001f);
for (int i = 0, j = npoly-1; i < npoly; j=i++)
{
- if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
+ if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
distancePtSeg2d(vb, &vpoly[j*3], &vpoly[i*3]) < thrSqr)
return 1;
}
@@ -951,8 +1173,8 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
-
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_POLYMESHDETAIL);
+
if (mesh.nverts == 0 || mesh.npolys == 0)
return true;
@@ -961,23 +1183,24 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
const float ch = mesh.ch;
const float* orig = mesh.bmin;
const int borderSize = mesh.borderSize;
+ const int heightSearchRadius = rcMax(1, (int)ceilf(mesh.maxEdgeError));
rcIntArray edges(64);
rcIntArray tris(512);
- rcIntArray stack(512);
+ rcIntArray arr(512);
rcIntArray samples(512);
float verts[256*3];
rcHeightPatch hp;
int nPolyVerts = 0;
int maxhw = 0, maxhh = 0;
- rcScopedDelete<int> bounds = (int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP);
+ rcScopedDelete<int> bounds((int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP));
if (!bounds)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4);
return false;
}
- rcScopedDelete<float> poly = (float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP);
+ rcScopedDelete<float> poly((float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP));
if (!poly)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3);
@@ -1015,7 +1238,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
maxhh = rcMax(maxhh, ymax-ymin);
}
- hp.data = (unsigned short *)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP);
+ hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP);
if (!hp.data)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh);
@@ -1031,10 +1254,10 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4);
return false;
}
-
+
int vcap = nPolyVerts+nPolyVerts/2;
int tcap = vcap*2;
-
+
dmesh.nverts = 0;
dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
if (!dmesh.verts)
@@ -1043,7 +1266,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
return false;
}
dmesh.ntris = 0;
- dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM);
+ dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM);
if (!dmesh.tris)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
@@ -1071,18 +1294,19 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
hp.ymin = bounds[i*4+2];
hp.width = bounds[i*4+1]-bounds[i*4+0];
hp.height = bounds[i*4+3]-bounds[i*4+2];
- getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack);
+ getHeightData(ctx, chf, p, npoly, mesh.verts, borderSize, hp, arr, mesh.regs[i]);
// Build detail mesh.
int nverts = 0;
if (!buildPolyDetail(ctx, poly, npoly,
sampleDist, sampleMaxError,
- chf, hp, verts, nverts, tris,
+ heightSearchRadius, chf, hp,
+ verts, nverts, tris,
edges, samples))
{
return false;
}
-
+
// Move detail verts to world space.
for (int j = 0; j < nverts; ++j)
{
@@ -1097,21 +1321,21 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
poly[j*3+1] += orig[1];
poly[j*3+2] += orig[2];
}
-
+
// Store detail submesh.
const int ntris = tris.size()/4;
-
+
dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts;
dmesh.meshes[i*4+1] = (unsigned int)nverts;
dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris;
- dmesh.meshes[i*4+3] = (unsigned int)ntris;
+ dmesh.meshes[i*4+3] = (unsigned int)ntris;
// Store vertices, allocate more memory if necessary.
if (dmesh.nverts+nverts > vcap)
{
while (dmesh.nverts+nverts > vcap)
vcap += 256;
-
+
float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
if (!newv)
{
@@ -1157,9 +1381,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
dmesh.ntris++;
}
}
-
- ctx->stopTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
-
+
return true;
}
@@ -1168,12 +1390,12 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
-
+ rcScopedTimer timer(ctx, RC_TIMER_MERGE_POLYMESHDETAIL);
+
int maxVerts = 0;
int maxTris = 0;
int maxMeshes = 0;
-
+
for (int i = 0; i < nmeshes; ++i)
{
if (!meshes[i]) continue;
@@ -1181,7 +1403,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
maxTris += meshes[i]->ntris;
maxMeshes += meshes[i]->nmeshes;
}
-
+
mesh.nmeshes = 0;
mesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*maxMeshes*4, RC_ALLOC_PERM);
if (!mesh.meshes)
@@ -1189,7 +1411,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4);
return false;
}
-
+
mesh.ntris = 0;
mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM);
if (!mesh.tris)
@@ -1197,7 +1419,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4);
return false;
}
-
+
mesh.nverts = 0;
mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM);
if (!mesh.verts)
@@ -1221,7 +1443,7 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
dst[3] = src[3];
mesh.nmeshes++;
}
-
+
for (int k = 0; k < dm->nverts; ++k)
{
rcVcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]);
@@ -1236,9 +1458,6 @@ bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int
mesh.ntris++;
}
}
-
- ctx->stopTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
return true;
}
-
diff --git a/extern/recastnavigation/Recast/Source/RecastRasterization.cpp b/extern/recastnavigation/Recast/Source/RecastRasterization.cpp
index d2bb7c98f18..a4cef749098 100644
--- a/extern/recastnavigation/Recast/Source/RecastRasterization.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastRasterization.cpp
@@ -50,7 +50,7 @@ static rcSpan* allocSpan(rcHeightfield& hf)
// Allocate memory for the new pool.
rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
if (!pool) return 0;
- pool->next = 0;
+
// Add the pool into the list of pools.
pool->next = hf.pools;
hf.pools = pool;
@@ -82,7 +82,7 @@ static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
hf.freelist = ptr;
}
-static void addSpan(rcHeightfield& hf, const int x, const int y,
+static bool addSpan(rcHeightfield& hf, const int x, const int y,
const unsigned short smin, const unsigned short smax,
const unsigned char area, const int flagMergeThr)
{
@@ -90,16 +90,18 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
int idx = x + y*hf.width;
rcSpan* s = allocSpan(hf);
+ if (!s)
+ return false;
s->smin = smin;
s->smax = smax;
s->area = area;
s->next = 0;
- // Empty cell, add he first span.
+ // Empty cell, add the first span.
if (!hf.spans[idx])
{
hf.spans[idx] = s;
- return;
+ return true;
}
rcSpan* prev = 0;
rcSpan* cur = hf.spans[idx];
@@ -152,6 +154,8 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
s->next = hf.spans[idx];
hf.spans[idx] = s;
}
+
+ return true;
}
/// @par
@@ -161,45 +165,80 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
/// from the existing span, the span flags are merged.
///
/// @see rcHeightfield, rcSpan.
-void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
+bool rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
const unsigned short smin, const unsigned short smax,
const unsigned char area, const int flagMergeThr)
{
-// rcAssert(ctx);
- addSpan(hf, x,y, smin, smax, area, flagMergeThr);
+ rcAssert(ctx);
+
+ if (!addSpan(hf, x, y, smin, smax, area, flagMergeThr))
+ {
+ ctx->log(RC_LOG_ERROR, "rcAddSpan: Out of memory.");
+ return false;
+ }
+
+ return true;
}
-static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
+// divides a convex polygons into two convex polygons on both sides of a line
+static void dividePoly(const float* in, int nin,
+ float* out1, int* nout1,
+ float* out2, int* nout2,
+ float x, int axis)
{
float d[12];
- for (int i = 0; i < n; ++i)
- d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
-
- int m = 0;
- for (int i = 0, j = n-1; i < n; j=i, ++i)
+ for (int i = 0; i < nin; ++i)
+ d[i] = x - in[i*3+axis];
+
+ int m = 0, n = 0;
+ for (int i = 0, j = nin-1; i < nin; j=i, ++i)
{
bool ina = d[j] >= 0;
bool inb = d[i] >= 0;
if (ina != inb)
{
float s = d[j] / (d[j] - d[i]);
- out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
- out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
- out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
+ out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
+ out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
+ out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
+ rcVcopy(out2 + n*3, out1 + m*3);
m++;
+ n++;
+ // add the i'th point to the right polygon. Do NOT add points that are on the dividing line
+ // since these were already added above
+ if (d[i] > 0)
+ {
+ rcVcopy(out1 + m*3, in + i*3);
+ m++;
+ }
+ else if (d[i] < 0)
+ {
+ rcVcopy(out2 + n*3, in + i*3);
+ n++;
+ }
}
- if (inb)
+ else // same side
{
- out[m*3+0] = in[i*3+0];
- out[m*3+1] = in[i*3+1];
- out[m*3+2] = in[i*3+2];
- m++;
+ // add the i'th point to the right polygon. Addition is done even for points on the dividing line
+ if (d[i] >= 0)
+ {
+ rcVcopy(out1 + m*3, in + i*3);
+ m++;
+ if (d[i] != 0)
+ continue;
+ }
+ rcVcopy(out2 + n*3, in + i*3);
+ n++;
}
}
- return m;
+
+ *nout1 = m;
+ *nout2 = n;
}
-static void rasterizeTri(const float* v0, const float* v1, const float* v2,
+
+
+static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& hf,
const float* bmin, const float* bmax,
const float cs, const float ics, const float ich,
@@ -220,50 +259,59 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
if (!overlapBounds(bmin, bmax, tmin, tmax))
- return;
+ return true;
- // Calculate the footpring of the triangle on the grid.
- int x0 = (int)((tmin[0] - bmin[0])*ics);
+ // Calculate the footprint of the triangle on the grid's y-axis
int y0 = (int)((tmin[2] - bmin[2])*ics);
- int x1 = (int)((tmax[0] - bmin[0])*ics);
int y1 = (int)((tmax[2] - bmin[2])*ics);
- x0 = rcClamp(x0, 0, w-1);
y0 = rcClamp(y0, 0, h-1);
- x1 = rcClamp(x1, 0, w-1);
y1 = rcClamp(y1, 0, h-1);
// Clip the triangle into all grid cells it touches.
- float in[7*3], out[7*3], inrow[7*3];
+ float buf[7*3*4];
+ float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
+
+ rcVcopy(&in[0], v0);
+ rcVcopy(&in[1*3], v1);
+ rcVcopy(&in[2*3], v2);
+ int nvrow, nvIn = 3;
for (int y = y0; y <= y1; ++y)
{
- // Clip polygon to row.
- rcVcopy(&in[0], v0);
- rcVcopy(&in[1*3], v1);
- rcVcopy(&in[2*3], v2);
- int nvrow = 3;
+ // Clip polygon to row. Store the remaining polygon as well
const float cz = bmin[2] + y*cs;
- nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
- if (nvrow < 3) continue;
- nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
+ dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
+ rcSwap(in, p1);
if (nvrow < 3) continue;
+ // find the horizontal bounds in the row
+ float minX = inrow[0], maxX = inrow[0];
+ for (int i=1; i<nvrow; ++i)
+ {
+ if (minX > inrow[i*3]) minX = inrow[i*3];
+ if (maxX < inrow[i*3]) maxX = inrow[i*3];
+ }
+ int x0 = (int)((minX - bmin[0])*ics);
+ int x1 = (int)((maxX - bmin[0])*ics);
+ x0 = rcClamp(x0, 0, w-1);
+ x1 = rcClamp(x1, 0, w-1);
+
+ int nv, nv2 = nvrow;
+
for (int x = x0; x <= x1; ++x)
{
- // Clip polygon to column.
- int nv = nvrow;
+ // Clip polygon to column. store the remaining polygon as well
const float cx = bmin[0] + x*cs;
- nv = clipPoly(inrow, nv, out, 1, 0, -cx);
- if (nv < 3) continue;
- nv = clipPoly(out, nv, in, -1, 0, cx+cs);
+ dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
+ rcSwap(inrow, p2);
if (nv < 3) continue;
// Calculate min and max of the span.
- float smin = in[1], smax = in[1];
+ float smin = p1[1], smax = p1[1];
for (int i = 1; i < nv; ++i)
{
- smin = rcMin(smin, in[i*3+1]);
- smax = rcMax(smax, in[i*3+1]);
+ smin = rcMin(smin, p1[i*3+1]);
+ smax = rcMax(smax, p1[i*3+1]);
}
smin -= bmin[1];
smax -= bmin[1];
@@ -278,9 +326,12 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
- addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
+ if (!addSpan(hf, x, y, ismin, ismax, area, flagMergeThr))
+ return false;
}
}
+
+ return true;
}
/// @par
@@ -288,19 +339,23 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
/// No spans will be added if the triangle does not overlap the heightfield grid.
///
/// @see rcHeightfield
-void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
+bool rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
const unsigned char area, rcHeightfield& solid,
const int flagMergeThr)
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+ rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
- rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
+ if (!rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ {
+ ctx->log(RC_LOG_ERROR, "rcRasterizeTriangle: Out of memory.");
+ return false;
+ }
- ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+ return true;
}
/// @par
@@ -308,13 +363,13 @@ void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
-void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
+bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
const int* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr)
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+ rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
@@ -325,10 +380,14 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
const float* v1 = &verts[tris[i*3+1]*3];
const float* v2 = &verts[tris[i*3+2]*3];
// Rasterize.
- rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
+ if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ {
+ ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
+ return false;
+ }
}
-
- ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+
+ return true;
}
/// @par
@@ -336,13 +395,13 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
-void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
+bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
const unsigned short* tris, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr)
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+ rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
@@ -353,10 +412,14 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
const float* v1 = &verts[tris[i*3+1]*3];
const float* v2 = &verts[tris[i*3+2]*3];
// Rasterize.
- rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
+ if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ {
+ ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
+ return false;
+ }
}
-
- ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+
+ return true;
}
/// @par
@@ -364,12 +427,12 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
-void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
+bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
rcHeightfield& solid, const int flagMergeThr)
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+ rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
const float ics = 1.0f/solid.cs;
const float ich = 1.0f/solid.ch;
@@ -380,8 +443,12 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned cha
const float* v1 = &verts[(i*3+1)*3];
const float* v2 = &verts[(i*3+2)*3];
// Rasterize.
- rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
+ if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ {
+ ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
+ return false;
+ }
}
-
- ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
+
+ return true;
}
diff --git a/extern/recastnavigation/Recast/Source/RecastRegion.cpp b/extern/recastnavigation/Recast/Source/RecastRegion.cpp
index 4290972ed24..54acf4b736b 100644
--- a/extern/recastnavigation/Recast/Source/RecastRegion.cpp
+++ b/extern/recastnavigation/Recast/Source/RecastRegion.cpp
@@ -286,7 +286,10 @@ static bool floodRegion(int x, int y, int i,
if (nr & RC_BORDER_REG) // Do not take borders into account.
continue;
if (nr != 0 && nr != r)
+ {
ar = nr;
+ break;
+ }
const rcCompactSpan& as = chf.spans[ai];
@@ -298,9 +301,12 @@ static bool floodRegion(int x, int y, int i,
const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
if (chf.areas[ai2] != area)
continue;
- unsigned short nr = srcReg[ai2];
- if (nr != 0 && nr != r)
- ar = nr;
+ unsigned short nr2 = srcReg[ai2];
+ if (nr2 != 0 && nr2 != r)
+ {
+ ar = nr2;
+ break;
+ }
}
}
}
@@ -309,6 +315,7 @@ static bool floodRegion(int x, int y, int i,
srcReg[ci] = 0;
continue;
}
+
count++;
// Expand neighbours.
@@ -340,30 +347,44 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
rcCompactHeightfield& chf,
unsigned short* srcReg, unsigned short* srcDist,
unsigned short* dstReg, unsigned short* dstDist,
- rcIntArray& stack)
+ rcIntArray& stack,
+ bool fillStack)
{
const int w = chf.width;
const int h = chf.height;
- // Find cells revealed by the raised level.
- stack.resize(0);
- for (int y = 0; y < h; ++y)
+ if (fillStack)
{
- for (int x = 0; x < w; ++x)
+ // Find cells revealed by the raised level.
+ stack.resize(0);
+ for (int y = 0; y < h; ++y)
{
- const rcCompactCell& c = chf.cells[x+y*w];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ for (int x = 0; x < w; ++x)
{
- if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
+ const rcCompactCell& c = chf.cells[x+y*w];
+ for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
{
- stack.push(x);
- stack.push(y);
- stack.push(i);
+ if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
+ {
+ stack.push(x);
+ stack.push(y);
+ stack.push(i);
+ }
}
}
}
}
-
+ else // use cells in the input stack
+ {
+ // mark all cells which already have a region
+ for (int j=0; j<stack.size(); j+=3)
+ {
+ int i = stack[j+2];
+ if (srcReg[i] != 0)
+ stack[j+2] = -1;
+ }
+ }
+
int iter = 0;
while (stack.size() > 0)
{
@@ -434,6 +455,61 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
}
+
+static void sortCellsByLevel(unsigned short startLevel,
+ rcCompactHeightfield& chf,
+ unsigned short* srcReg,
+ unsigned int nbStacks, rcIntArray* stacks,
+ unsigned short loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
+{
+ const int w = chf.width;
+ const int h = chf.height;
+ startLevel = startLevel >> loglevelsPerStack;
+
+ for (unsigned int j=0; j<nbStacks; ++j)
+ stacks[j].resize(0);
+
+ // put all cells in the level range into the appropriate stacks
+ for (int y = 0; y < h; ++y)
+ {
+ for (int x = 0; x < w; ++x)
+ {
+ const rcCompactCell& c = chf.cells[x+y*w];
+ for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ {
+ if (chf.areas[i] == RC_NULL_AREA || srcReg[i] != 0)
+ continue;
+
+ int level = chf.dist[i] >> loglevelsPerStack;
+ int sId = startLevel - level;
+ if (sId >= (int)nbStacks)
+ continue;
+ if (sId < 0)
+ sId = 0;
+
+ stacks[sId].push(x);
+ stacks[sId].push(y);
+ stacks[sId].push(i);
+ }
+ }
+ }
+}
+
+
+static void appendStacks(rcIntArray& srcStack, rcIntArray& dstStack,
+ unsigned short* srcReg)
+{
+ for (int j=0; j<srcStack.size(); j+=3)
+ {
+ int i = srcStack[j+2];
+ if ((i < 0) || (srcReg[i] != 0))
+ continue;
+ dstStack.push(srcStack[j]);
+ dstStack.push(srcStack[j+1]);
+ dstStack.push(srcStack[j+2]);
+ }
+}
+
struct rcRegion
{
inline rcRegion(unsigned short i) :
@@ -441,7 +517,11 @@ struct rcRegion
id(i),
areaType(0),
remap(false),
- visited(false)
+ visited(false),
+ overlap(false),
+ connectsToBorder(false),
+ ymin(0xffff),
+ ymax(0)
{}
int spanCount; // Number of spans belonging to this region
@@ -449,6 +529,9 @@ struct rcRegion
unsigned char areaType; // Are type.
bool remap;
bool visited;
+ bool overlap;
+ bool connectsToBorder;
+ unsigned short ymin, ymax;
rcIntArray connections;
rcIntArray floors;
};
@@ -678,25 +761,26 @@ static void walkContour(int x, int y, int i, int dir,
// Remove adjacent duplicates.
if (cont.size() > 1)
{
- for (int i = 0; i < cont.size(); )
+ for (int j = 0; j < cont.size(); )
{
- int ni = (i+1) % cont.size();
- if (cont[i] == cont[ni])
+ int nj = (j+1) % cont.size();
+ if (cont[j] == cont[nj])
{
- for (int j = i; j < cont.size()-1; ++j)
- cont[j] = cont[j+1];
+ for (int k = j; k < cont.size()-1; ++k)
+ cont[k] = cont[k+1];
cont.pop();
}
else
- ++i;
+ ++j;
}
}
}
-static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize,
- unsigned short& maxRegionId,
- rcCompactHeightfield& chf,
- unsigned short* srcReg)
+
+static bool mergeAndFilterRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize,
+ unsigned short& maxRegionId,
+ rcCompactHeightfield& chf,
+ unsigned short* srcReg, rcIntArray& overlaps)
{
const int w = chf.width;
const int h = chf.height;
@@ -705,7 +789,7 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
if (!regions)
{
- ctx->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg);
+ ctx->log(RC_LOG_ERROR, "mergeAndFilterRegions: Out of memory 'regions' (%d).", nreg);
return false;
}
@@ -728,7 +812,6 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
rcRegion& reg = regions[r];
reg.spanCount++;
-
// Update floors.
for (int j = (int)c.index; j < ni; ++j)
{
@@ -736,6 +819,8 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
unsigned short floorId = srcReg[j];
if (floorId == 0 || floorId >= nreg)
continue;
+ if (floorId == r)
+ reg.overlap = true;
addUniqueFloorRegion(reg, floorId);
}
@@ -806,14 +891,14 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
connectsToBorder = true;
continue;
}
- rcRegion& nreg = regions[creg.connections[j]];
- if (nreg.visited)
+ rcRegion& neireg = regions[creg.connections[j]];
+ if (neireg.visited)
continue;
- if (nreg.id == 0 || (nreg.id & RC_BORDER_REG))
+ if (neireg.id == 0 || (neireg.id & RC_BORDER_REG))
continue;
// Visit
- stack.push(nreg.id);
- nreg.visited = true;
+ stack.push(neireg.id);
+ neireg.visited = true;
}
}
@@ -831,7 +916,7 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
}
}
}
-
+
// Merge too small regions to neighbour regions.
int mergeCount = 0 ;
do
@@ -841,7 +926,9 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
{
rcRegion& reg = regions[i];
if (reg.id == 0 || (reg.id & RC_BORDER_REG))
- continue;
+ continue;
+ if (reg.overlap)
+ continue;
if (reg.spanCount == 0)
continue;
@@ -858,7 +945,7 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
{
if (reg.connections[j] & RC_BORDER_REG) continue;
rcRegion& mreg = regions[reg.connections[j]];
- if (mreg.id == 0 || (mreg.id & RC_BORDER_REG)) continue;
+ if (mreg.id == 0 || (mreg.id & RC_BORDER_REG) || mreg.overlap) continue;
if (mreg.spanCount < smallest &&
canMergeWithRegion(reg, mreg) &&
canMergeWithRegion(mreg, reg))
@@ -928,6 +1015,224 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
if ((srcReg[i] & RC_BORDER_REG) == 0)
srcReg[i] = regions[srcReg[i]].id;
}
+
+ // Return regions that we found to be overlapping.
+ for (int i = 0; i < nreg; ++i)
+ if (regions[i].overlap)
+ overlaps.push(regions[i].id);
+
+ for (int i = 0; i < nreg; ++i)
+ regions[i].~rcRegion();
+ rcFree(regions);
+
+
+ return true;
+}
+
+
+static void addUniqueConnection(rcRegion& reg, int n)
+{
+ for (int i = 0; i < reg.connections.size(); ++i)
+ if (reg.connections[i] == n)
+ return;
+ reg.connections.push(n);
+}
+
+static bool mergeAndFilterLayerRegions(rcContext* ctx, int minRegionArea,
+ unsigned short& maxRegionId,
+ rcCompactHeightfield& chf,
+ unsigned short* srcReg, rcIntArray& /*overlaps*/)
+{
+ const int w = chf.width;
+ const int h = chf.height;
+
+ const int nreg = maxRegionId+1;
+ rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
+ if (!regions)
+ {
+ ctx->log(RC_LOG_ERROR, "mergeAndFilterLayerRegions: Out of memory 'regions' (%d).", nreg);
+ return false;
+ }
+
+ // Construct regions
+ for (int i = 0; i < nreg; ++i)
+ new(&regions[i]) rcRegion((unsigned short)i);
+
+ // Find region neighbours and overlapping regions.
+ rcIntArray lregs(32);
+ for (int y = 0; y < h; ++y)
+ {
+ for (int x = 0; x < w; ++x)
+ {
+ const rcCompactCell& c = chf.cells[x+y*w];
+
+ lregs.resize(0);
+
+ for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ {
+ const rcCompactSpan& s = chf.spans[i];
+ const unsigned short ri = srcReg[i];
+ if (ri == 0 || ri >= nreg) continue;
+ rcRegion& reg = regions[ri];
+
+ reg.spanCount++;
+
+ reg.ymin = rcMin(reg.ymin, s.y);
+ reg.ymax = rcMax(reg.ymax, s.y);
+
+ // Collect all region layers.
+ lregs.push(ri);
+
+ // Update neighbours
+ for (int dir = 0; dir < 4; ++dir)
+ {
+ if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
+ {
+ const int ax = x + rcGetDirOffsetX(dir);
+ const int ay = y + rcGetDirOffsetY(dir);
+ const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
+ const unsigned short rai = srcReg[ai];
+ if (rai > 0 && rai < nreg && rai != ri)
+ addUniqueConnection(reg, rai);
+ if (rai & RC_BORDER_REG)
+ reg.connectsToBorder = true;
+ }
+ }
+
+ }
+
+ // Update overlapping regions.
+ for (int i = 0; i < lregs.size()-1; ++i)
+ {
+ for (int j = i+1; j < lregs.size(); ++j)
+ {
+ if (lregs[i] != lregs[j])
+ {
+ rcRegion& ri = regions[lregs[i]];
+ rcRegion& rj = regions[lregs[j]];
+ addUniqueFloorRegion(ri, lregs[j]);
+ addUniqueFloorRegion(rj, lregs[i]);
+ }
+ }
+ }
+
+ }
+ }
+
+ // Create 2D layers from regions.
+ unsigned short layerId = 1;
+
+ for (int i = 0; i < nreg; ++i)
+ regions[i].id = 0;
+
+ // Merge montone regions to create non-overlapping areas.
+ rcIntArray stack(32);
+ for (int i = 1; i < nreg; ++i)
+ {
+ rcRegion& root = regions[i];
+ // Skip already visited.
+ if (root.id != 0)
+ continue;
+
+ // Start search.
+ root.id = layerId;
+
+ stack.resize(0);
+ stack.push(i);
+
+ while (stack.size() > 0)
+ {
+ // Pop front
+ rcRegion& reg = regions[stack[0]];
+ for (int j = 0; j < stack.size()-1; ++j)
+ stack[j] = stack[j+1];
+ stack.resize(stack.size()-1);
+
+ const int ncons = (int)reg.connections.size();
+ for (int j = 0; j < ncons; ++j)
+ {
+ const int nei = reg.connections[j];
+ rcRegion& regn = regions[nei];
+ // Skip already visited.
+ if (regn.id != 0)
+ continue;
+ // Skip if the neighbour is overlapping root region.
+ bool overlap = false;
+ for (int k = 0; k < root.floors.size(); k++)
+ {
+ if (root.floors[k] == nei)
+ {
+ overlap = true;
+ break;
+ }
+ }
+ if (overlap)
+ continue;
+
+ // Deepen
+ stack.push(nei);
+
+ // Mark layer id
+ regn.id = layerId;
+ // Merge current layers to root.
+ for (int k = 0; k < regn.floors.size(); ++k)
+ addUniqueFloorRegion(root, regn.floors[k]);
+ root.ymin = rcMin(root.ymin, regn.ymin);
+ root.ymax = rcMax(root.ymax, regn.ymax);
+ root.spanCount += regn.spanCount;
+ regn.spanCount = 0;
+ root.connectsToBorder = root.connectsToBorder || regn.connectsToBorder;
+ }
+ }
+
+ layerId++;
+ }
+
+ // Remove small regions
+ for (int i = 0; i < nreg; ++i)
+ {
+ if (regions[i].spanCount > 0 && regions[i].spanCount < minRegionArea && !regions[i].connectsToBorder)
+ {
+ unsigned short reg = regions[i].id;
+ for (int j = 0; j < nreg; ++j)
+ if (regions[j].id == reg)
+ regions[j].id = 0;
+ }
+ }
+
+ // Compress region Ids.
+ for (int i = 0; i < nreg; ++i)
+ {
+ regions[i].remap = false;
+ if (regions[i].id == 0) continue; // Skip nil regions.
+ if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
+ regions[i].remap = true;
+ }
+
+ unsigned short regIdGen = 0;
+ for (int i = 0; i < nreg; ++i)
+ {
+ if (!regions[i].remap)
+ continue;
+ unsigned short oldId = regions[i].id;
+ unsigned short newId = ++regIdGen;
+ for (int j = i; j < nreg; ++j)
+ {
+ if (regions[j].id == oldId)
+ {
+ regions[j].id = newId;
+ regions[j].remap = false;
+ }
+ }
+ }
+ maxRegionId = regIdGen;
+
+ // Remap regions.
+ for (int i = 0; i < chf.spanCount; ++i)
+ {
+ if ((srcReg[i] & RC_BORDER_REG) == 0)
+ srcReg[i] = regions[srcReg[i]].id;
+ }
for (int i = 0; i < nreg; ++i)
regions[i].~rcRegion();
@@ -936,6 +1241,8 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio
return true;
}
+
+
/// @par
///
/// This is usually the second to the last step in creating a fully built
@@ -950,7 +1257,7 @@ bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_DISTANCEFIELD);
if (chf.dist)
{
@@ -974,25 +1281,23 @@ bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
unsigned short maxDist = 0;
- ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST);
-
- calculateDistanceField(chf, src, maxDist);
- chf.maxDistance = maxDist;
-
- ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST);
-
- ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
-
- // Blur
- if (boxBlur(chf, 1, src, dst) != src)
- rcSwap(src, dst);
-
- // Store distance.
- chf.dist = src;
-
- ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
+ {
+ rcScopedTimer timerDist(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST);
- ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD);
+ calculateDistanceField(chf, src, maxDist);
+ chf.maxDistance = maxDist;
+ }
+
+ {
+ rcScopedTimer timerBlur(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
+
+ // Blur
+ if (boxBlur(chf, 1, src, dst) != src)
+ rcSwap(src, dst);
+
+ // Store distance.
+ chf.dist = src;
+ }
rcFree(dst);
@@ -1052,13 +1357,13 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_REGIONS);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
const int w = chf.width;
const int h = chf.height;
unsigned short id = 1;
- rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned short> srcReg((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP));
if (!srcReg)
{
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
@@ -1067,7 +1372,7 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
const int nsweeps = rcMax(chf.width,chf.height);
- rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP);
+ rcScopedDelete<rcSweepSpan> sweeps((rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP));
if (!sweeps)
{
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
@@ -1181,20 +1486,22 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
}
}
- ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
- // Filter out small regions.
- chf.maxRegions = id;
- if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg))
- return false;
+ {
+ rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
- ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
+ // Merge regions and filter out small regions.
+ rcIntArray overlaps;
+ chf.maxRegions = id;
+ if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
+ return false;
+
+ // Monotone partitioning does not generate overlapping regions.
+ }
// Store the result out.
for (int i = 0; i < chf.spanCount; ++i)
chf.spans[i].reg = srcReg[i];
-
- ctx->stopTimer(RC_TIMER_BUILD_REGIONS);
return true;
}
@@ -1223,12 +1530,12 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
{
rcAssert(ctx);
- ctx->startTimer(RC_TIMER_BUILD_REGIONS);
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
const int w = chf.width;
const int h = chf.height;
- rcScopedDelete<unsigned short> buf = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP);
+ rcScopedDelete<unsigned short> buf((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP));
if (!buf)
{
ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4);
@@ -1236,7 +1543,13 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
}
ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
-
+
+ const int LOG_NB_STACKS = 3;
+ const int NB_STACKS = 1 << LOG_NB_STACKS;
+ rcIntArray lvlStacks[NB_STACKS];
+ for (int i=0; i<NB_STACKS; ++i)
+ lvlStacks[i].resize(1024);
+
rcIntArray stack(1024);
rcIntArray visited(1024);
@@ -1262,6 +1575,13 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
// Make sure border will not overflow.
const int bw = rcMin(w, borderSize);
const int bh = rcMin(h, borderSize);
+
+ if (regionId > 0xFFFB)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildRegions: Region ID overflow");
+ return false;
+ }
+
// Paint regions
paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
@@ -1271,44 +1591,60 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
chf.borderSize = borderSize;
}
+ int sId = -1;
while (level > 0)
{
level = level >= 2 ? level-2 : 0;
-
- ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
-
- // Expand current regions until no empty connected cells found.
- if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
+ sId = (sId+1) & (NB_STACKS-1);
+
+// ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
+
+ if (sId == 0)
+ sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
+ else
+ appendStacks(lvlStacks[sId-1], lvlStacks[sId], srcReg); // copy left overs from last level
+
+// ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
+
{
- rcSwap(srcReg, dstReg);
- rcSwap(srcDist, dstDist);
+ rcScopedTimer timerExpand(ctx, RC_TIMER_BUILD_REGIONS_EXPAND);
+
+ // Expand current regions until no empty connected cells found.
+ if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, lvlStacks[sId], false) != srcReg)
+ {
+ rcSwap(srcReg, dstReg);
+ rcSwap(srcDist, dstDist);
+ }
}
- ctx->stopTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
-
- ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
-
- // Mark new regions with IDs.
- for (int y = 0; y < h; ++y)
{
- for (int x = 0; x < w; ++x)
+ rcScopedTimer timerFloor(ctx, RC_TIMER_BUILD_REGIONS_FLOOD);
+
+ // Mark new regions with IDs.
+ for (int j = 0; j<lvlStacks[sId].size(); j += 3)
{
- const rcCompactCell& c = chf.cells[x+y*w];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ int x = lvlStacks[sId][j];
+ int y = lvlStacks[sId][j+1];
+ int i = lvlStacks[sId][j+2];
+ if (i >= 0 && srcReg[i] == 0)
{
- if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA)
- continue;
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
+ {
+ if (regionId == 0xFFFF)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildRegions: Region ID overflow");
+ return false;
+ }
+
regionId++;
+ }
}
}
}
-
- ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
}
// Expand current regions until no empty connected cells found.
- if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
+ if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack, true) != srcReg)
{
rcSwap(srcReg, dstReg);
rcSwap(srcDist, dstDist);
@@ -1316,22 +1652,179 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
- ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
-
- // Filter out small regions.
- chf.maxRegions = regionId;
- if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg))
- return false;
-
- ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
+ {
+ rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
+
+ // Merge regions and filter out smalle regions.
+ rcIntArray overlaps;
+ chf.maxRegions = regionId;
+ if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
+ return false;
+
+ // If overlapping regions were found during merging, split those regions.
+ if (overlaps.size() > 0)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildRegions: %d overlapping regions.", overlaps.size());
+ }
+ }
// Write the result out.
for (int i = 0; i < chf.spanCount; ++i)
chf.spans[i].reg = srcReg[i];
- ctx->stopTimer(RC_TIMER_BUILD_REGIONS);
-
return true;
}
+bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
+ const int borderSize, const int minRegionArea)
+{
+ rcAssert(ctx);
+
+ rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
+
+ const int w = chf.width;
+ const int h = chf.height;
+ unsigned short id = 1;
+
+ rcScopedDelete<unsigned short> srcReg((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP));
+ if (!srcReg)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
+ return false;
+ }
+ memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
+
+ const int nsweeps = rcMax(chf.width,chf.height);
+ rcScopedDelete<rcSweepSpan> sweeps((rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP));
+ if (!sweeps)
+ {
+ ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
+ return false;
+ }
+
+
+ // Mark border regions.
+ if (borderSize > 0)
+ {
+ // Make sure border will not overflow.
+ const int bw = rcMin(w, borderSize);
+ const int bh = rcMin(h, borderSize);
+ // Paint regions
+ paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
+ paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
+ paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
+ paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
+
+ chf.borderSize = borderSize;
+ }
+
+ rcIntArray prev(256);
+
+ // Sweep one line at a time.
+ for (int y = borderSize; y < h-borderSize; ++y)
+ {
+ // Collect spans from this row.
+ prev.resize(id+1);
+ memset(&prev[0],0,sizeof(int)*id);
+ unsigned short rid = 1;
+
+ for (int x = borderSize; x < w-borderSize; ++x)
+ {
+ const rcCompactCell& c = chf.cells[x+y*w];
+
+ for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ {
+ const rcCompactSpan& s = chf.spans[i];
+ if (chf.areas[i] == RC_NULL_AREA) continue;
+
+ // -x
+ unsigned short previd = 0;
+ if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
+ {
+ const int ax = x + rcGetDirOffsetX(0);
+ const int ay = y + rcGetDirOffsetY(0);
+ const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
+ if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
+ previd = srcReg[ai];
+ }
+
+ if (!previd)
+ {
+ previd = rid++;
+ sweeps[previd].rid = previd;
+ sweeps[previd].ns = 0;
+ sweeps[previd].nei = 0;
+ }
+
+ // -y
+ if (rcGetCon(s,3) != RC_NOT_CONNECTED)
+ {
+ const int ax = x + rcGetDirOffsetX(3);
+ const int ay = y + rcGetDirOffsetY(3);
+ const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
+ if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
+ {
+ unsigned short nr = srcReg[ai];
+ if (!sweeps[previd].nei || sweeps[previd].nei == nr)
+ {
+ sweeps[previd].nei = nr;
+ sweeps[previd].ns++;
+ prev[nr]++;
+ }
+ else
+ {
+ sweeps[previd].nei = RC_NULL_NEI;
+ }
+ }
+ }
+
+ srcReg[i] = previd;
+ }
+ }
+
+ // Create unique ID.
+ for (int i = 1; i < rid; ++i)
+ {
+ if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
+ prev[sweeps[i].nei] == (int)sweeps[i].ns)
+ {
+ sweeps[i].id = sweeps[i].nei;
+ }
+ else
+ {
+ sweeps[i].id = id++;
+ }
+ }
+
+ // Remap IDs
+ for (int x = borderSize; x < w-borderSize; ++x)
+ {
+ const rcCompactCell& c = chf.cells[x+y*w];
+
+ for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ {
+ if (srcReg[i] > 0 && srcReg[i] < rid)
+ srcReg[i] = sweeps[srcReg[i]].id;
+ }
+ }
+ }
+
+
+ {
+ rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
+
+ // Merge monotone regions to layers and remove small regions.
+ rcIntArray overlaps;
+ chf.maxRegions = id;
+ if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg, overlaps))
+ return false;
+ }
+
+
+ // Store the result out.
+ for (int i = 0; i < chf.spanCount; ++i)
+ chf.spans[i].reg = srcReg[i];
+
+ return true;
+}
diff --git a/extern/recastnavigation/Recast/Source/RecastTimer.cpp b/extern/recastnavigation/Recast/Source/RecastTimer.cpp
deleted file mode 100644
index 51ffb7d3160..00000000000
--- a/extern/recastnavigation/Recast/Source/RecastTimer.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "RecastTimer.h"
-
-#if defined(WIN32)
-
-// Win32
-#include <windows.h>
-
-rcTimeVal rcGetPerformanceTimer()
-{
- __int64 count;
- QueryPerformanceCounter((LARGE_INTEGER*)&count);
- return count;
-}
-
-int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
-{
- static __int64 freq = 0;
- if (freq == 0)
- QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
- __int64 elapsed = end - start;
- return (int)(elapsed*1000000 / freq);
-}
-
-#elif defined(__MACH__)
-
-// OSX
-#include <mach/mach_time.h>
-
-rcTimeVal rcGetPerformanceTimer()
-{
- return mach_absolute_time();
-}
-
-int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
-{
- static mach_timebase_info_data_t timebaseInfo;
- if (timebaseInfo.denom == 0)
- mach_timebase_info(&timebaseInfo);
- uint64_t elapsed = end - start;
- uint64_t nanosec = elapsed * timebaseInfo.numer / timebaseInfo.denom;
- return (int)(nanosec / 1000);
-}
-
-#else
-
-// TODO: Linux, etc
-
-rcTimeVal rcGetPerformanceTimer()
-{
- return 0;
-}
-
-int rcGetDeltaTimeUsec(rcTimeVal start, rcTimeVal end)
-{
- return 0;
-}
-
-#endif \ No newline at end of file
diff --git a/extern/recastnavigation/SConscript b/extern/recastnavigation/SConscript
deleted file mode 100644
index 2c15e518eb1..00000000000
--- a/extern/recastnavigation/SConscript
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/python
-
-Import('env')
-
-sources = env.Glob('Recast/Source/*.cpp') + env.Glob('Detour/Source/*.cpp')
-sources += ['recast-capi.cpp']
-
-incs = 'Recast/Include Detour/Include'
-
-env.BlenderLib ( 'extern_recastnavigation', sources, Split(incs), [],
- libtype=['extern','player'],
- priority=[10,185])
diff --git a/extern/recastnavigation/readme-blender.txt b/extern/recastnavigation/readme-blender.txt
new file mode 100644
index 00000000000..2a1b2882ce2
--- /dev/null
+++ b/extern/recastnavigation/readme-blender.txt
@@ -0,0 +1,22 @@
+The version of Recast is 1.5.0, from:
+https://github.com/recastnavigation/recastnavigation
+Changes made:
+ * Recast/Source/RecastMesh.cpp: made buildMeshAdjacency() non-static so it can be used with recast-capi
+ * Recast/Include/Recast.h: Added forward declaration for buildMeshAdjacency()
+
+The following additional files were added:
+ * recast-capi.cpp
+ * recast-capi.h
+These expose a C interface to the Recast library, which has only C++ headers.
+
+The version of Detour is 1.4, from:
+https://code.google.com/archive/p/recastnavigation/downloads
+Changes made:
+ * DetourStatNavMesh.h: use more portable definition of DT_STAT_NAVMESH_MAGIC
+ * DetourStatNavMesh.cpp: comment out some unused variables to avoid compiler warnings
+ * DetourStatNavMeshBuilder.h: add forward declaration for createBVTree
+ * DetourStatNavMeshBuilder.cpp: made createBVTree non-static for use with recast-capi
+
+The CMakeLists.txt file has been added, since the original software does not include build files for the libraries.
+
+~rdb
diff --git a/extern/recastnavigation/recast-capi.cpp b/extern/recastnavigation/recast-capi.cpp
index 38c14118156..1163265722b 100644
--- a/extern/recastnavigation/recast-capi.cpp
+++ b/extern/recastnavigation/recast-capi.cpp
@@ -68,17 +68,41 @@ int recast_createHeightfield(struct recast_heightfield *hf, int width, int heigh
}
void recast_markWalkableTriangles(const float walkableSlopeAngle,const float *verts, int nv,
- const int *tris, int nt, unsigned char *flags)
+ const int *tris, int nt, unsigned char *areas)
{
INIT_SCTX();
- rcMarkWalkableTriangles(sctx, walkableSlopeAngle, verts, nv, tris, nt, flags);
+ rcMarkWalkableTriangles(sctx, walkableSlopeAngle, verts, nv, tris, nt, areas);
}
-void recast_rasterizeTriangles(const float *verts, int nv, const int *tris,
- const unsigned char *flags, int nt, struct recast_heightfield *solid)
+void recast_clearUnwalkableTriangles(const float walkableSlopeAngle, const float* verts, int nv,
+ const int* tris, int nt, unsigned char* areas)
{
INIT_SCTX();
- rcRasterizeTriangles(sctx, verts, nv, tris, flags, nt, *(rcHeightfield *) solid);
+ rcClearUnwalkableTriangles(sctx, walkableSlopeAngle, verts, nv, tris, nt, areas);
+}
+
+int recast_addSpan(struct recast_heightfield *hf, const int x, const int y,
+ const unsigned short smin, const unsigned short smax,
+ const unsigned char area, const int flagMergeThr)
+{
+ INIT_SCTX();
+ return rcAddSpan(sctx, *(rcHeightfield *) hf, x, y, smin, smax, area, flagMergeThr);
+}
+
+int recast_rasterizeTriangle(const float *v0, const float *v1, const float *v2,
+ const unsigned char area, struct recast_heightfield *solid,
+ const int flagMergeThr)
+{
+ INIT_SCTX();
+ return rcRasterizeTriangle(sctx, v0, v1, v2, area, *(rcHeightfield *) solid, flagMergeThr);
+}
+
+int recast_rasterizeTriangles(const float *verts, const int nv, const int *tris,
+ const unsigned char *areas, const int nt, struct recast_heightfield *solid,
+ const int flagMergeThr)
+{
+ INIT_SCTX();
+ return rcRasterizeTriangles(sctx, verts, nv, tris, areas, nt, *(rcHeightfield *) solid, flagMergeThr);
}
void recast_filterLedgeSpans(const int walkableHeight, const int walkableClimb,
@@ -100,6 +124,22 @@ void recast_filterLowHangingWalkableObstacles(const int walkableClimb, struct re
rcFilterLowHangingWalkableObstacles(sctx, walkableClimb, *(rcHeightfield *) solid);
}
+int recast_getHeightFieldSpanCount(struct recast_heightfield *hf)
+{
+ INIT_SCTX();
+ return rcGetHeightFieldSpanCount(sctx, *(rcHeightfield *) hf);
+}
+
+struct recast_heightfieldLayerSet *recast_newHeightfieldLayerSet(void)
+{
+ return (struct recast_heightfieldLayerSet *) rcAllocHeightfieldLayerSet();
+}
+
+void recast_destroyHeightfieldLayerSet(struct recast_heightfieldLayerSet *lset)
+{
+ rcFreeHeightfieldLayerSet( (rcHeightfieldLayerSet *) lset);
+}
+
struct recast_compactHeightfield *recast_newCompactHeightfield(void)
{
return (struct recast_compactHeightfield *) rcAllocCompactHeightfield();
@@ -124,18 +164,68 @@ int recast_erodeWalkableArea(int radius, struct recast_compactHeightfield *chf)
return rcErodeWalkableArea(sctx, radius, *(rcCompactHeightfield *) chf);
}
+int recast_medianFilterWalkableArea(struct recast_compactHeightfield *chf)
+{
+ INIT_SCTX();
+ return rcMedianFilterWalkableArea(sctx, *(rcCompactHeightfield *) chf);
+}
+
+void recast_markBoxArea(const float *bmin, const float *bmax, unsigned char areaId,
+ struct recast_compactHeightfield *chf)
+{
+ INIT_SCTX();
+ rcMarkBoxArea(sctx, bmin, bmax, areaId, *(rcCompactHeightfield *) chf);
+}
+
+void recast_markConvexPolyArea(const float* verts, const int nverts,
+ const float hmin, const float hmax, unsigned char areaId,
+ struct recast_compactHeightfield *chf)
+{
+ INIT_SCTX();
+ rcMarkConvexPolyArea(sctx, verts, nverts, hmin, hmax, areaId, *(rcCompactHeightfield *) chf);
+}
+
+int recast_offsetPoly(const float* verts, const int nverts,
+ const float offset, float *outVerts, const int maxOutVerts)
+{
+ return rcOffsetPoly(verts, nverts, offset, outVerts, maxOutVerts);
+}
+
+void recast_markCylinderArea(const float* pos, const float r, const float h,
+ unsigned char areaId, struct recast_compactHeightfield *chf)
+{
+ INIT_SCTX();
+ rcMarkCylinderArea(sctx, pos, r, h, areaId, *(rcCompactHeightfield *) chf);
+}
+
int recast_buildDistanceField(struct recast_compactHeightfield *chf)
{
INIT_SCTX();
return rcBuildDistanceField(sctx, *(rcCompactHeightfield *) chf);
}
-int recast_buildRegions(struct recast_compactHeightfield *chf, int borderSize,
- int minRegionSize, int mergeRegionSize)
+int recast_buildRegions(struct recast_compactHeightfield *chf,
+ const int borderSize, const int minRegionArea, const int mergeRegionArea)
{
INIT_SCTX();
return rcBuildRegions(sctx, *(rcCompactHeightfield *) chf, borderSize,
- minRegionSize, mergeRegionSize);
+ minRegionArea, mergeRegionArea);
+}
+
+int recast_buildLayerRegions(struct recast_compactHeightfield *chf,
+ const int borderSize, const int minRegionArea)
+{
+ INIT_SCTX();
+ return rcBuildLayerRegions(sctx, *(rcCompactHeightfield *) chf, borderSize,
+ minRegionArea);
+}
+
+int recast_buildRegionsMonotone(struct recast_compactHeightfield *chf,
+ const int borderSize, const int minRegionArea, const int mergeRegionArea)
+{
+ INIT_SCTX();
+ return rcBuildRegionsMonotone(sctx, *(rcCompactHeightfield *) chf, borderSize,
+ minRegionArea, mergeRegionArea);
}
struct recast_contourSet *recast_newContourSet(void)
@@ -149,10 +239,11 @@ void recast_destroyContourSet(struct recast_contourSet *contourSet)
}
int recast_buildContours(struct recast_compactHeightfield *chf,
- const float maxError, const int maxEdgeLen, struct recast_contourSet *cset)
+ const float maxError, const int maxEdgeLen, struct recast_contourSet *cset,
+ const int buildFlags)
{
INIT_SCTX();
- return rcBuildContours(sctx, *(rcCompactHeightfield *) chf, maxError, maxEdgeLen, *(rcContourSet *) cset);
+ return rcBuildContours(sctx, *(rcCompactHeightfield *) chf, maxError, maxEdgeLen, *(rcContourSet *) cset, buildFlags);
}
struct recast_polyMesh *recast_newPolyMesh(void)
@@ -165,10 +256,22 @@ void recast_destroyPolyMesh(struct recast_polyMesh *polyMesh)
rcFreePolyMesh((rcPolyMesh *) polyMesh);
}
-int recast_buildPolyMesh(struct recast_contourSet *cset, int nvp, struct recast_polyMesh *mesh)
+int recast_buildPolyMesh(struct recast_contourSet *cset, const int nvp, struct recast_polyMesh *mesh)
+{
+ INIT_SCTX();
+ return rcBuildPolyMesh(sctx, *(rcContourSet *) cset, nvp, *(rcPolyMesh *) mesh);
+}
+
+int recast_mergePolyMeshes(struct recast_polyMesh **meshes, const int nmeshes, struct recast_polyMesh *mesh)
{
INIT_SCTX();
- return rcBuildPolyMesh(sctx, *(rcContourSet *) cset, nvp, * (rcPolyMesh *) mesh);
+ return rcMergePolyMeshes(sctx, (rcPolyMesh **) meshes, nmeshes, *(rcPolyMesh *) mesh);
+}
+
+int recast_copyPolyMesh(const struct recast_polyMesh *src, struct recast_polyMesh *dst)
+{
+ INIT_SCTX();
+ return rcCopyPolyMesh(sctx, *(const rcPolyMesh *) src, *(rcPolyMesh *) dst);
}
unsigned short *recast_polyMeshGetVerts(struct recast_polyMesh *mesh, int *nverts)
@@ -240,6 +343,12 @@ int recast_buildPolyMeshDetail(const struct recast_polyMesh *mesh, const struct
sampleDist, sampleMaxError, *(rcPolyMeshDetail *) dmesh);
}
+int recast_mergePolyMeshDetails(struct recast_polyMeshDetail **meshes, const int nmeshes, struct recast_polyMeshDetail *mesh)
+{
+ INIT_SCTX();
+ return rcMergePolyMeshDetails(sctx, (rcPolyMeshDetail **) meshes, nmeshes, *(rcPolyMeshDetail *) mesh);
+}
+
float *recast_polyMeshDetailGetVerts(struct recast_polyMeshDetail *mesh, int *nverts)
{
rcPolyMeshDetail *dmesh = (rcPolyMeshDetail *)mesh;
diff --git a/extern/recastnavigation/recast-capi.h b/extern/recastnavigation/recast-capi.h
index 54bf84931c4..306bf79c167 100644
--- a/extern/recastnavigation/recast-capi.h
+++ b/extern/recastnavigation/recast-capi.h
@@ -38,12 +38,13 @@ struct recast_polyMesh;
struct recast_polyMeshDetail;
struct recast_heightfield;
struct recast_compactHeightfield;
+struct recast_heightfieldLayerSet;
struct recast_contourSet;
-enum recast_SpanFlags
+enum recast_BuildContoursFlags
{
- RECAST_WALKABLE = 0x01,
- RECAST_REACHABLE = 0x02
+ RECAST_CONTOUR_TESS_WALL_EDGES = 0x01,
+ RECAST_CONTOUR_TESS_AREA_EDGES = 0x02,
};
int recast_buildMeshAdjacency(unsigned short* polys, const int npolys,
@@ -61,10 +62,22 @@ int recast_createHeightfield(struct recast_heightfield *hf, int width, int heigh
const float *bmin, const float* bmax, float cs, float ch);
void recast_markWalkableTriangles(const float walkableSlopeAngle,const float *verts, int nv,
- const int *tris, int nt, unsigned char *flags);
+ const int *tris, int nt, unsigned char *areas);
-void recast_rasterizeTriangles(const float *verts, int nv, const int *tris,
- const unsigned char *flags, int nt, struct recast_heightfield *solid);
+void recast_clearUnwalkableTriangles(const float walkableSlopeAngle, const float* verts, int nv,
+ const int* tris, int nt, unsigned char* areas);
+
+int recast_addSpan(struct recast_heightfield *hf, const int x, const int y,
+ const unsigned short smin, const unsigned short smax,
+ const unsigned char area, const int flagMergeThr);
+
+int recast_rasterizeTriangle(const float* v0, const float* v1, const float* v2,
+ const unsigned char area, struct recast_heightfield *solid,
+ const int flagMergeThr);
+
+int recast_rasterizeTriangles(const float *verts, const int nv, const int *tris,
+ const unsigned char *areas, const int nt, struct recast_heightfield *solid,
+ const int flagMergeThr);
void recast_filterLedgeSpans(const int walkableHeight, const int walkableClimb,
struct recast_heightfield *solid);
@@ -73,6 +86,12 @@ void recast_filterWalkableLowHeightSpans(int walkableHeight, struct recast_heigh
void recast_filterLowHangingWalkableObstacles(const int walkableClimb, struct recast_heightfield *solid);
+int recast_getHeightFieldSpanCount(struct recast_heightfield *hf);
+
+struct recast_heightfieldLayerSet *recast_newHeightfieldLayerSet(void);
+
+void recast_destroyHeightfieldLayerSet(struct recast_heightfieldLayerSet *lset);
+
struct recast_compactHeightfield *recast_newCompactHeightfield(void);
void recast_destroyCompactHeightfield(struct recast_compactHeightfield *compactHeightfield);
@@ -82,10 +101,31 @@ int recast_buildCompactHeightfield(const int walkableHeight, const int walkableC
int recast_erodeWalkableArea(int radius, struct recast_compactHeightfield *chf);
+int recast_medianFilterWalkableArea(struct recast_compactHeightfield *chf);
+
+void recast_markBoxArea(const float *bmin, const float *bmax, unsigned char areaId,
+ struct recast_compactHeightfield *chf);
+
+void recast_markConvexPolyArea(const float* verts, const int nverts,
+ const float hmin, const float hmax, unsigned char areaId,
+ struct recast_compactHeightfield *chf);
+
+int recast_offsetPoly(const float* verts, const int nverts,
+ const float offset, float *outVerts, const int maxOutVerts);
+
+void recast_markCylinderArea(const float* pos, const float r, const float h,
+ unsigned char areaId, struct recast_compactHeightfield *chf);
+
int recast_buildDistanceField(struct recast_compactHeightfield *chf);
-int recast_buildRegions(struct recast_compactHeightfield *chf, int borderSize,
- int minRegionSize, int mergeRegionSize);
+int recast_buildRegions(struct recast_compactHeightfield *chf,
+ const int borderSize, const int minRegionArea, const int mergeRegionArea);
+
+int recast_buildLayerRegions(struct recast_compactHeightfield *chf,
+ const int borderSize, const int minRegionArea);
+
+int recast_buildRegionsMonotone(struct recast_compactHeightfield *chf,
+ const int borderSize, const int minRegionArea, const int mergeRegionArea);
/* Contour set */
@@ -94,7 +134,8 @@ struct recast_contourSet *recast_newContourSet(void);
void recast_destroyContourSet(struct recast_contourSet *contourSet);
int recast_buildContours(struct recast_compactHeightfield *chf,
- const float maxError, const int maxEdgeLen, struct recast_contourSet *cset);
+ const float maxError, const int maxEdgeLen, struct recast_contourSet *cset,
+ const int buildFlags);
/* Poly mesh */
@@ -102,7 +143,11 @@ struct recast_polyMesh *recast_newPolyMesh(void);
void recast_destroyPolyMesh(struct recast_polyMesh *polyMesh);
-int recast_buildPolyMesh(struct recast_contourSet *cset, int nvp, struct recast_polyMesh *mesh);
+int recast_buildPolyMesh(struct recast_contourSet *cset, const int nvp, struct recast_polyMesh *mesh);
+
+int recast_mergePolyMeshes(struct recast_polyMesh **meshes, const int nmeshes, struct recast_polyMesh *mesh);
+
+int recast_copyPolyMesh(const struct recast_polyMesh *src, struct recast_polyMesh *dst);
unsigned short *recast_polyMeshGetVerts(struct recast_polyMesh *mesh, int *nverts);
@@ -121,6 +166,8 @@ void recast_destroyPolyMeshDetail(struct recast_polyMeshDetail *polyMeshDetail);
int recast_buildPolyMeshDetail(const struct recast_polyMesh *mesh, const struct recast_compactHeightfield *chf,
const float sampleDist, const float sampleMaxError, struct recast_polyMeshDetail *dmesh);
+int recast_mergePolyMeshDetails(struct recast_polyMeshDetail **meshes, const int nmeshes, struct recast_polyMeshDetail *mesh);
+
float *recast_polyMeshDetailGetVerts(struct recast_polyMeshDetail *mesh, int *nverts);
unsigned char *recast_polyMeshDetailGetTris(struct recast_polyMeshDetail *mesh, int *ntris);
diff --git a/extern/sdlew/SConscript b/extern/sdlew/SConscript
deleted file mode 100644
index 287f9c09ec8..00000000000
--- a/extern/sdlew/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2014, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Sergey Sharybin.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('src/sdlew.c')
-
-incs = 'include'
-defs = []
-
-env.BlenderLib ('extern_sdlew', sources, Split(incs), defines=defs, libtype=['extern'], priority = [999])
diff --git a/extern/sdlew/auto/sdlew_gen.sh b/extern/sdlew/auto/sdlew_gen.sh
deleted file mode 100755
index 36a2d939d20..00000000000
--- a/extern/sdlew/auto/sdlew_gen.sh
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/bin/bash
-
-SDL="SDL2"
-INCLUDE_DIR="/usr/include/${SDL}"
-SCRIPT=`realpath -s $0`
-DIR=`dirname $SCRIPT`
-DIR=`dirname $DIR`
-
-mkdir -p $DIR/include/${SDL}
-mkdir -p $DIR/src
-
-rm -rf $DIR/include/${SDL}/*.h
-rm -rf $DIR/src/sdlew.c
-
-echo "Generating sdlew headers..."
-
-UNSUPPORTED="SDL_MemoryBarrierRelease SDL_MemoryBarrierAcquire SDL_AtomicCAS SDL_AtomicCASPtr \
- SDL_iPhoneSetAnimationCallback SDL_iPhoneSetEventPump SDL_AndroidGetJNIEnv SDL_AndroidGetActivity \
- SDL_AndroidGetActivity SDL_AndroidGetInternalStoragePath SDL_AndroidGetExternalStorageState \
- SDL_AndroidGetExternalStoragePath SDL_CreateShapedWindow SDL_IsShapedWindow tSDL_SetWindowShape \
- SDL_GetShapedWindowMode"
-
-for header in $INCLUDE_DIR/*; do
- filename=`basename $header`
- cat $header \
- | sed -r 's/extern DECLSPEC ((const )?[a-z0-9_]+(\s\*)?)\s?SDLCALL /typedef \1 SDLCALL t/i' \
- > $DIR/include/${SDL}/$filename
-
- line_num=`cat $DIR/include/${SDL}/$filename | grep -n "Ends C function" | cut -d : -f 1`
- if [ ! -z "$line_num" ]; then
- functions=`grep -E 'typedef [A-Za-z0-9_ \*]+ SDLCALL' $DIR/include/${SDL}/$filename \
- | sed -r 's/typedef [A-Za-z0-9_ \*]+ SDLCALL t([a-z0-9_]+).*/extern t\1 *\1;/i'`
- functions=`echo "${functions}" | sed -e 's/[\/&]/\\\&/g'`
- echo "$functions" | while read function; do
- if [ -z "$function" ]; then
- continue;
- fi
- func_name=`echo $function | cut -d '*' -f 2 | sed -r 's/;//'`
- if [ ! -z "`echo "$UNSUPPORTED" | grep $func_name`" ]; then
- continue;
- fi
- if [ "$func_name" == "SDL_memcpy" ]; then
- line_num=`cat $DIR/include/${SDL}/$filename | grep -n "SDL_memcpy4" | cut -d : -f 1`
- sed -ri "${line_num}s/(.*)/${function}\n\1/" $DIR/include/${SDL}/$filename
- else
- sed -ri "${line_num}s/(.*)/${function}\n\1/" $DIR/include/${SDL}/$filename
- fi
- line_num=`cat $DIR/include/${SDL}/$filename | grep -n "Ends C function" | cut -d : -f 1`
- done
- line_num=`cat $DIR/include/${SDL}/$filename | grep -n "Ends C function" | cut -d : -f 1`
- sed -ri "${line_num}s/(.*)/\n\1/" $DIR/include/${SDL}/$filename
- fi
-
- if [ $filename == "SDL_stdinc.h" ]; then
- cat $header | grep -E '#if(def)? (defined\()?HAVE_' | sed -r 's/#if(def)? //' | while read check; do
- func_names=`cat $DIR/include/${SDL}/$filename \
- | grep -A 8 "$check\$" \
- | grep -v struct \
- | grep 'typedef' \
- | sed -r 's/typedef [a-z0-9_ \*]+ SDLCALL ([a-z0-9_]+).*/\1/i'`
- full_check=`echo "${check}" | sed -e 's/[\/&]/\\\&/g'`
- if [ ! -z "`echo $full_check | grep defined`" ]; then
- full_check="#if !($full_check)"
- else
- full_check="#ifndef $full_check"
- fi
- for func_name in $func_names; do
- line_num=`grep -n "extern ${func_name} \*" $DIR/include/${SDL}/$filename | cut -d : -f 1`
- let prev_num=line_num-1
- if [ -z "`cat $DIR/include/${SDL}/$filename | head -n $prev_num | tail -n 1 | grep '#if'`" ]; then
- sed -ri "${line_num}s/(.*)/$full_check \/* GEN_CHECK_MARKER *\/\n\1\n#endif \/* GEN_CHECK_MARKER *\//" $DIR/include/${SDL}/$filename
- fi
- done
- done
- fi
-done
-
-cat << EOF > $DIR/include/sdlew.h
-/*
- * Copyright 2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-#ifndef __SDL_EW_H__
-#define __SDL_EW_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum {
- SDLEW_SUCCESS = 0,
- SDLEW_ERROR_OPEN_FAILED = -1,
- SDLEW_ERROR_ATEXIT_FAILED = -2,
- SDLEW_ERROR_VERSION = -3,
-};
-
-int sdlewInit(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SDL_EW_H__ */
-EOF
-
-echo "Generating sdlew sources..."
-
-cat << EOF > $DIR/src/sdlew.c
-/*
- * Copyright 2014 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-#ifdef _MSC_VER
-# define snprintf _snprintf
-# define popen _popen
-# define pclose _pclose
-# define _CRT_SECURE_NO_WARNINGS
-#endif
-
-#include "sdlew.h"
-
-#include "${SDL}/SDL.h"
-#include "${SDL}/SDL_syswm.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#ifdef _WIN32
-# define WIN32_LEAN_AND_MEAN
-# define VC_EXTRALEAN
-# include <windows.h>
-
-/* Utility macros. */
-
-typedef HMODULE DynamicLibrary;
-
-# define dynamic_library_open(path) LoadLibrary(path)
-# define dynamic_library_close(lib) FreeLibrary(lib)
-# define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol)
-#else
-# include <dlfcn.h>
-
-typedef void* DynamicLibrary;
-
-# define dynamic_library_open(path) dlopen(path, RTLD_NOW)
-# define dynamic_library_close(lib) dlclose(lib)
-# define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
-#endif
-
-#define SDL_LIBRARY_FIND_CHECKED(name) \
- name = (t##name *)dynamic_library_find(lib, #name); \
- assert(name);
-
-#define SDL_LIBRARY_FIND(name) \
- name = (t##name *)dynamic_library_find(lib, #name);
-
-static DynamicLibrary lib;
-
-EOF
-
-content=`grep --no-filename -ER "extern tSDL|GEN_CHECK_MARKER" $DIR/include/${SDL}/`
-
-echo "$content" | sed -r 's/extern t([a-z0-9_]+).*/t\1 *\1;/gi' >> $DIR/src/sdlew.c
-
-cat << EOF >> $DIR/src/sdlew.c
-
-static void sdlewExit(void) {
- if(lib != NULL) {
- /* Ignore errors. */
- dynamic_library_close(lib);
- lib = NULL;
- }
-}
-
-/* Implementation function. */
-int sdlewInit(void) {
- /* Library paths. */
-#ifdef _WIN32
- /* Expected in c:/windows/system or similar, no path needed. */
- const char *path = "SDL2.dll";
-#elif defined(__APPLE__)
- /* Default installation path. */
- const char *path = "/usr/local/cuda/lib/libSDL2.dylib";
-#else
- const char *path = "libSDL2.so";
-#endif
- static int initialized = 0;
- static int result = 0;
- int error;
-
- if (initialized) {
- return result;
- }
-
- initialized = 1;
-
- error = atexit(sdlewExit);
- if (error) {
- result = SDLEW_ERROR_ATEXIT_FAILED;
- return result;
- }
-
- /* Load library. */
- lib = dynamic_library_open(path);
-
- if (lib == NULL) {
- result = SDLEW_ERROR_OPEN_FAILED;
- return result;
- }
-
-EOF
-
-echo "$content" | sed -r 's/extern t([a-z0-9_]+).*/ SDL_LIBRARY_FIND(\1);/gi' >> $DIR/src/sdlew.c
-
-cat << EOF >> $DIR/src/sdlew.c
-
- result = SDLEW_SUCCESS;
-
- return result;
-}
-EOF
-
-sed -i 's/\s\/\* GEN_CHECK_MARKER \*\///g' $DIR/src/sdlew.c
-sed -i 's/\s\/\* GEN_CHECK_MARKER \*\///g' $DIR/include/${SDL}/SDL_stdinc.h
diff --git a/extern/sdlew/auto/strip_comments.sh b/extern/sdlew/auto/strip_comments.sh
deleted file mode 100755
index c89224c3d56..00000000000
--- a/extern/sdlew/auto/strip_comments.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-SDL="SDL2"
-INCLUDE_DIR="/usr/include/${SDL}"
-SCRIPT=`realpath -s $0`
-DIR=`dirname $SCRIPT`
-DIR=`dirname $DIR`
-
-for f in $DIR/include/${SDL}/*.h; do
- file_name=`basename $f`
- echo "Striping $file_name..."
- sed -r ':a; s%(.*)/\*.*\*/%\1%; ta; /\/\*/ !b; N; ba' -i $f
- sed 's/[ \t]*$//' -i $f
- sed '/^$/N;/^\n$/D' -i $f
-done
diff --git a/extern/wcwidth/SConscript b/extern/wcwidth/SConscript
deleted file mode 100644
index 14fdaf3f738..00000000000
--- a/extern/wcwidth/SConscript
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/python
-
-Import('env')
-
-sources = env.Glob('*.c')
-
-incs = '.'
-
-env.BlenderLib ( 'extern_wcwidth', sources, Split(incs), [], libtype=['extern','player'], priority=[10, 185])
diff --git a/extern/wcwidth/wcwidth.c b/extern/wcwidth/wcwidth.c
index 61e822ad679..8cab81e32cd 100644
--- a/extern/wcwidth/wcwidth.c
+++ b/extern/wcwidth/wcwidth.c
@@ -61,6 +61,8 @@
#include <wchar.h>
+#include "wcwidth.h"
+
struct interval {
int first;
int last;
diff --git a/extern/xdnd/SConscript b/extern/xdnd/SConscript
deleted file mode 100644
index 6f1fe72cc28..00000000000
--- a/extern/xdnd/SConscript
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/python
-
-Import('env')
-
-defs = ['HAVE_SYS_TIME_H']
-sources = env.Glob('*.c')
-
-incs = '.'
-
-env.BlenderLib ( 'extern_xdnd', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185])
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index 4ee3dff7695..43e5b6bff3e 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -27,11 +27,12 @@
add_subdirectory(string)
add_subdirectory(ghost)
add_subdirectory(guardedalloc)
+add_subdirectory(libmv)
add_subdirectory(memutil)
add_subdirectory(opencolorio)
add_subdirectory(mikktspace)
-add_subdirectory(raskter)
add_subdirectory(glew-mx)
+add_subdirectory(eigen)
if(WITH_AUDASPACE)
add_subdirectory(audaspace)
@@ -73,10 +74,6 @@ if(WITH_BULLET)
add_subdirectory(rigidbody)
endif()
-if(WITH_OPENNL)
- add_subdirectory(opennl)
-endif()
-
if(WITH_OPENSUBDIV)
add_subdirectory(opensubdiv)
endif()
@@ -85,3 +82,7 @@ endif()
if(WIN32)
add_subdirectory(utfconv)
endif()
+
+if(WITH_OPENVDB)
+ add_subdirectory(openvdb)
+endif()
diff --git a/intern/SConscript b/intern/SConscript
deleted file mode 100644
index 124afd4bbb9..00000000000
--- a/intern/SConscript
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-SConscript(['string/SConscript',
- 'ghost/SConscript',
- 'glew-mx/SConscript',
- 'guardedalloc/SConscript',
- 'moto/SConscript',
- 'memutil/SConscript/',
- 'iksolver/SConscript',
- 'itasc/SConscript',
- 'opencolorio/SConscript',
- 'opennl/SConscript',
- 'mikktspace/SConscript',
- 'smoke/SConscript',
- 'raskter/SConscript'])
-
-# currently only contains headers
-# SConscript('container/SConscript')
-
-if env['WITH_BF_AUDASPACE']:
- SConscript(['audaspace/SConscript'])
-
-if env ['WITH_BF_REMESH']:
- SConscript(['dualcon/SConscript'])
-
-if env['WITH_BF_FLUID']:
- SConscript(['elbeem/SConscript'])
-
-if env['WITH_BF_CYCLES']:
- SConscript(['cycles/SConscript'])
-
-if env['WITH_BF_INTERNATIONAL']:
- SConscript(['locale/SConscript'])
-
-if env['WITH_BF_BULLET']:
- SConscript (['rigidbody/SConscript'])
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'):
- SConscript(['utfconv/SConscript'])
-
-if env['WITH_BF_OPENSUBDIV']:
- SConscript (['opensubdiv/SConscript'])
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index d8161d10401..dc06a51f859 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -90,6 +90,8 @@ ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
+ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b);
+
ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new);
@@ -378,6 +380,30 @@ atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new)
#endif
/******************************************************************************/
+/* 8-bit operations. */
+#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+ATOMIC_INLINE uint8_t
+atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b)
+{
+ return __sync_fetch_and_and(p, b);
+}
+#elif (defined(_MSC_VER))
+#include <intrin.h>
+#pragma intrinsic(_InterlockedAnd8)
+ATOMIC_INLINE uint8_t
+atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b)
+{
+#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
+ return InterlockedAnd8((char *)p, (char)b);
+#else
+ return _InterlockedAnd8((char *)p, (char)b);
+#endif
+}
+#else
+# error "Missing implementation for 8-bit atomic operations"
+#endif
+
+/******************************************************************************/
/* size_t operations. */
ATOMIC_INLINE size_t
atomic_add_z(size_t *p, size_t x)
diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt
index b3682a77875..2d415296dac 100644
--- a/intern/audaspace/CMakeLists.txt
+++ b/intern/audaspace/CMakeLists.txt
@@ -21,6 +21,10 @@
remove_extra_strict_flags()
+if(CMAKE_COMPILER_IS_GNUCC)
+ remove_cc_flag("-Wunused-macros")
+endif()
+
if(WITH_SYSTEM_AUDASPACE)
set(INC
diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp
index dc019c1f245..300fd55e23b 100644
--- a/intern/audaspace/Python/AUD_PyAPI.cpp
+++ b/intern/audaspace/Python/AUD_PyAPI.cpp
@@ -128,7 +128,7 @@ Factory_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(M_aud_Factory_sine_doc,
- "sine(frequency, rate=44100)\n\n"
+ "sine(frequency, rate=48000)\n\n"
"Creates a sine factory which plays a sine wave.\n\n"
":arg frequency: The frequency of the sine wave in Hz.\n"
":type frequency: float\n"
@@ -142,7 +142,7 @@ static PyObject *
Factory_sine(PyTypeObject* type, PyObject *args)
{
float frequency;
- double rate = 44100;
+ double rate = 48000;
if(!PyArg_ParseTuple(args, "f|d:sine", &frequency, &rate))
return NULL;
@@ -2115,7 +2115,7 @@ Device_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static const char *kwlist[] = {"type", "rate", "channels", "format", "buffer_size", "name", NULL};
int device;
- double rate = AUD_RATE_44100;
+ double rate = AUD_RATE_48000;
int channels = AUD_CHANNELS_STEREO;
int format = AUD_FORMAT_FLOAT32;
int buffersize = AUD_DEFAULT_BUFFER_SIZE;
diff --git a/intern/audaspace/SConscript b/intern/audaspace/SConscript
deleted file mode 100644
index 8dfaa861ce2..00000000000
--- a/intern/audaspace/SConscript
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN LGPL LICENSE BLOCK *****
-#
-# Copyright 2009 Jrg Hermann Mller
-#
-# This file is part of AudaSpace.
-#
-# AudaSpace is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# AudaSpace is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
-#
-# ***** END LGPL LICENSE BLOCK *****
-
-from os import path
-Import ('env')
-
-sources = env.Glob('intern/*.cpp') + env.Glob('FX/*.cpp')
-
-# AUD_PyInit is for external audaspace only
-sources.remove(path.join('intern', 'AUD_PyInit.cpp'))
-
-
-incs = '. intern FX ' + env['BF_PTHREADS_INC'] + ' ' + env['BF_BOOST_INC']
-defs = []
-
-if env['WITH_BF_FFMPEG']:
- sources += env.Glob('ffmpeg/*.cpp')
- incs += ' ffmpeg #/intern/ffmpeg ' + env['BF_FFMPEG_INC']
- defs.append('WITH_FFMPEG')
-
-if env['WITH_BF_SDL']:
- sources += env.Glob('SDL/*.cpp')
- incs += ' SDL ' + env['BF_SDL_INC']
- defs.append('WITH_SDL')
-
-if env['WITH_BF_OPENAL']:
- sources += env.Glob('OpenAL/*.cpp')
- incs += ' OpenAL ' + env['BF_OPENAL_INC']
- defs.append('WITH_OPENAL')
-
-if env['WITH_BF_JACK']:
- sources += env.Glob('jack/*.cpp')
- incs += ' jack ' + env['BF_JACK_INC']
- defs.append('WITH_JACK')
- if env['WITH_BF_JACK_DYNLOAD']:
- defs.append('WITH_JACK_DYNLOAD')
-
-if env['WITH_BF_SNDFILE']:
- sources += env.Glob('sndfile/*.cpp')
- incs += ' sndfile ' + env['BF_SNDFILE_INC']
- defs.append('WITH_SNDFILE')
-
-#if env['WITH_BF_FFTW3']:
-# sources += env.Glob('fftw/*.cpp')
-# incs += ' fftw ' + env['BF_FFTW3_INC']
-# defs.append('WITH_FFTW3')
-
-if env['WITH_BF_PYTHON']:
- sources += env.Glob('Python/*.cpp')
- incs += ' Python ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ('bf_intern_audaspace', sources, Split(incs), defs, libtype=['intern','player'], priority = [25,215] )
diff --git a/intern/audaspace/SDL/AUD_SDLDevice.cpp b/intern/audaspace/SDL/AUD_SDLDevice.cpp
index 0be8db91d28..23729a7a171 100644
--- a/intern/audaspace/SDL/AUD_SDLDevice.cpp
+++ b/intern/audaspace/SDL/AUD_SDLDevice.cpp
@@ -48,7 +48,7 @@ AUD_SDLDevice::AUD_SDLDevice(AUD_DeviceSpecs specs, int buffersize)
if(specs.format == AUD_FORMAT_INVALID)
specs.format = AUD_FORMAT_S16;
if(specs.rate == AUD_RATE_INVALID)
- specs.rate = AUD_RATE_44100;
+ specs.rate = AUD_RATE_48000;
m_specs = specs;
diff --git a/intern/audaspace/SDL/AUD_SDLDevice.h b/intern/audaspace/SDL/AUD_SDLDevice.h
index 266edd0dfcc..c4ff9e80aa9 100644
--- a/intern/audaspace/SDL/AUD_SDLDevice.h
+++ b/intern/audaspace/SDL/AUD_SDLDevice.h
@@ -32,7 +32,18 @@
#include "AUD_SoftwareDevice.h"
+/* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings
+ * because we pass those defines via command line as well. For until there's
+ * proper ifndef added to SDL headers we ignore the redefinition warning.
+ */
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4005)
+#endif
#include <SDL.h>
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
/**
* This device plays back through SDL, the simple direct media layer.
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
index ba961f0cb78..e9eea195208 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
@@ -58,9 +58,9 @@ int AUD_FFMPEGReader::decode(AVPacket& packet, AUD_Buffer& buffer)
got_frame = 0;
if(!frame)
- frame = avcodec_alloc_frame();
+ frame = av_frame_alloc();
else
- avcodec_get_frame_defaults(frame);
+ av_frame_unref(frame);
read_length = avcodec_decode_audio4(m_codecCtx, frame, &got_frame, &packet);
if(read_length < 0)
@@ -389,9 +389,7 @@ void AUD_FFMPEGReader::seek(int position)
int length = AUD_DEFAULT_BUFFER_SIZE;
AUD_Buffer buffer(length * AUD_SAMPLE_SIZE(m_specs));
bool eos;
- for(int len = position - m_position;
- length == AUD_DEFAULT_BUFFER_SIZE;
- len -= AUD_DEFAULT_BUFFER_SIZE)
+ for(int len = position - m_position; len > 0; len -= AUD_DEFAULT_BUFFER_SIZE)
{
if(len < AUD_DEFAULT_BUFFER_SIZE)
length = len;
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
index 4ee99c723aa..3f95ac7a4da 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
@@ -202,7 +202,7 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
m_frame = av_frame_alloc();
if (!m_frame)
AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
- avcodec_get_frame_defaults(m_frame);
+ av_frame_unref(m_frame);
m_frame->linesize[0] = m_input_size * samplesize;
m_frame->format = m_codecCtx->sample_fmt;
m_frame->nb_samples = m_input_size;
@@ -224,7 +224,9 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_FLAG_WRITE))
AUD_THROW(AUD_ERROR_FILE, file_error);
- avformat_write_header(m_formatCtx, NULL);
+ if(avformat_write_header(m_formatCtx, NULL) < 0) {
+ throw;
+ }
}
catch(AUD_Exception&)
{
diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp
index 341f1cd3f6b..b326c9f4281 100644
--- a/intern/audaspace/intern/AUD_C-API.cpp
+++ b/intern/audaspace/intern/AUD_C-API.cpp
@@ -75,7 +75,6 @@
#include "AUD_MutexLock.h"
#ifdef WITH_SDL
-#include <SDL.h>
#include "AUD_SDLDevice.h"
#endif
@@ -918,7 +917,7 @@ AUD_Sound *AUD_Sequence_create(float fps, int muted)
// specs are changed at a later point!
AUD_Specs specs;
specs.channels = AUD_CHANNELS_STEREO;
- specs.rate = AUD_RATE_44100;
+ specs.rate = AUD_RATE_48000;
AUD_Sound *sequencer = new AUD_Sound(boost::shared_ptr<AUD_SequencerFactory>(new AUD_SequencerFactory(specs, fps, muted)));
return sequencer;
}
@@ -1292,9 +1291,11 @@ AUD_Device *AUD_openMixdownDevice(AUD_DeviceSpecs specs, AUD_Sound *sequencer, f
device->setQuality(true);
device->setVolume(volume);
- dynamic_cast<AUD_SequencerFactory *>(sequencer->get())->setSpecs(specs.specs);
+ AUD_SequencerFactory *f = dynamic_cast<AUD_SequencerFactory *>(sequencer->get());
- AUD_Handle handle = device->play(*sequencer);
+ f->setSpecs(specs.specs);
+
+ AUD_Handle handle = device->play(f->createQualityReader());
if (handle.get()) {
handle->seek(start);
}
diff --git a/intern/audaspace/intern/AUD_SilenceReader.cpp b/intern/audaspace/intern/AUD_SilenceReader.cpp
index 948868508fc..5d7e83f7f09 100644
--- a/intern/audaspace/intern/AUD_SilenceReader.cpp
+++ b/intern/audaspace/intern/AUD_SilenceReader.cpp
@@ -59,7 +59,7 @@ int AUD_SilenceReader::getPosition() const
AUD_Specs AUD_SilenceReader::getSpecs() const
{
AUD_Specs specs;
- specs.rate = AUD_RATE_44100;
+ specs.rate = AUD_RATE_48000;
specs.channels = AUD_CHANNELS_MONO;
return specs;
}
diff --git a/intern/audaspace/intern/AUD_SinusFactory.h b/intern/audaspace/intern/AUD_SinusFactory.h
index d1909dedb66..c8d409a4aff 100644
--- a/intern/audaspace/intern/AUD_SinusFactory.h
+++ b/intern/audaspace/intern/AUD_SinusFactory.h
@@ -59,7 +59,7 @@ public:
* \param sampleRate The target sample rate for playback.
*/
AUD_SinusFactory(float frequency,
- AUD_SampleRate sampleRate = AUD_RATE_44100);
+ AUD_SampleRate sampleRate = AUD_RATE_48000);
/**
* Returns the frequency of the sine wave.
diff --git a/intern/audaspace/intern/AUD_Space.h b/intern/audaspace/intern/AUD_Space.h
index ec2c06900ac..26bbdc5a8f7 100644
--- a/intern/audaspace/intern/AUD_Space.h
+++ b/intern/audaspace/intern/AUD_Space.h
@@ -50,9 +50,9 @@
/// Returns the bigger of the two values.
#define AUD_MAX(a, b) (((a) > (b)) ? (a) : (b))
-// 5 sec * 44100 samples/sec * 4 bytes/sample * 6 channels
+// 5 sec * 48000 samples/sec * 4 bytes/sample * 6 channels
/// The size by which a buffer should be resized if the final extent is unknown.
-#define AUD_BUFFER_RESIZE_BYTES 5292000
+#define AUD_BUFFER_RESIZE_BYTES 5760000
/// The default playback buffer size of a device.
#define AUD_DEFAULT_BUFFER_SIZE 1024
diff --git a/intern/container/SConscript b/intern/container/SConscript
deleted file mode 100644
index 1f943157d6a..00000000000
--- a/intern/container/SConscript
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-incs = '. #intern/guardedalloc'
-
-env.BlenderLib ('bf_intern_ctr', sources, Split(incs) , [], libtype='intern', priority = 10 )
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index c252a613cef..3b6c25c370e 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -11,15 +11,18 @@ endif()
include(cmake/external_libs.cmake)
# Build Flags
-# todo: refactor this code to match scons
+# todo: this code could be refactored a bit to avoid duplication
# note: CXX_HAS_SSE is needed in case passing SSE flags fails altogether (gcc-arm)
-if(WITH_CYCLES_WERROR)
- ADD_CHECK_C_COMPILER_FLAG(CMAKE_C_FLAGS C_WERROR -Werror)
- ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS C_WERROR -Werror)
-endif()
-
-if(NOT WITH_CPU_SSE)
+if(WITH_CYCLES_NATIVE_ONLY)
+ set(CXX_HAS_SSE FALSE)
+ set(CXX_HAS_AVX FALSE)
+ set(CXX_HAS_AVX2 FALSE)
+ add_definitions(
+ -DWITH_KERNEL_NATIVE
+ )
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
+elseif(NOT WITH_CPU_SSE)
set(CXX_HAS_SSE FALSE)
set(CXX_HAS_AVX FALSE)
set(CXX_HAS_AVX2 FALSE)
@@ -126,10 +129,6 @@ add_definitions(
-DCCL_NAMESPACE_END=}
)
-if(WITH_CYCLES_NETWORK)
- add_definitions(-DWITH_NETWORK)
-endif()
-
if(WITH_CYCLES_STANDALONE_GUI)
add_definitions(-DWITH_CYCLES_STANDALONE_GUI)
endif()
@@ -138,10 +137,6 @@ if(WITH_CYCLES_PTEX)
add_definitions(-DWITH_PTEX)
endif()
-if(WITH_CYCLES_OPENSUBDIV)
- add_definitions(-DWITH_OPENSUBDIV)
-endif()
-
if(WITH_CYCLES_OSL)
add_definitions(-DWITH_OSL)
add_definitions(-DOSL_STATIC_LIBRARY)
@@ -151,13 +146,13 @@ if(WITH_CYCLES_OSL)
)
endif()
-add_definitions(
- -DWITH_OPENCL
- -DWITH_CUDA
- -DWITH_MULTI
-)
+set(WITH_CYCLES_DEVICE_OPENCL TRUE)
+set(WITH_CYCLES_DEVICE_CUDA TRUE)
+set(WITH_CYCLES_DEVICE_MULTI TRUE)
-TEST_UNORDERED_MAP_SUPPORT()
+if(CYCLES_STANDALONE_REPOSITORY)
+ TEST_UNORDERED_MAP_SUPPORT()
+endif()
if(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DCYCLES_STD_UNORDERED_MAP)
@@ -215,17 +210,24 @@ endif()
if(CMAKE_COMPILER_IS_GNUCXX)
ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_cxxflag_float_conversion "-Werror=float-conversion")
ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_cxxflag_double_promotion "-Werror=double-promotion")
+ ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_no_error_unused_macros "-Wno-error=unused-macros")
unset(_has_cxxflag_float_conversion)
unset(_has_cxxflag_double_promotion)
+ unset(_has_no_error_unused_macros)
endif()
# Subdirectories
if(WITH_CYCLES_BLENDER)
+ add_definitions(-DWITH_BLENDER_GUARDEDALLOC)
add_subdirectory(blender)
endif()
+if(WITH_CYCLES_NETWORK)
+ add_definitions(-DWITH_NETWORK)
+endif()
+
if(WITH_CYCLES_STANDALONE OR WITH_CYCLES_NETWORK)
add_subdirectory(app)
endif()
@@ -238,6 +240,11 @@ add_subdirectory(render)
add_subdirectory(subd)
add_subdirectory(util)
+# TODO(sergey): Make this to work with standalone repository.
+if(WITH_GTESTS)
+ add_subdirectory(test)
+endif()
+
if(NOT WITH_BLENDER AND WITH_CYCLES_STANDALONE)
delayed_do_install(${CMAKE_BINARY_DIR}/bin)
endif()
diff --git a/intern/cycles/SConscript b/intern/cycles/SConscript
deleted file mode 100644
index 99df8c299fc..00000000000
--- a/intern/cycles/SConscript
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-from os import path
-Import('env')
-
-cycles = env.Clone()
-
-cycles.Depends('../../source/blender/makesrna/intern/RNA_blender_cpp.h', 'makesrna')
-
-sources = cycles.Glob('bvh/*.cpp') + cycles.Glob('device/*.cpp') + cycles.Glob('kernel/*.cpp') + cycles.Glob('render/*.cpp') + cycles.Glob('subd/*.cpp') + cycles.Glob('util/*.cpp') + cycles.Glob('blender/*.cpp')
-
-sources.append(path.join('kernel', 'kernels', 'cpu', 'kernel.cpp'))
-sources.remove(path.join('util', 'util_view.cpp'))
-
-incs = []
-defs = []
-cxxflags = Split(env['CXXFLAGS'])
-
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_UNORDERED_MAP_SUPPORT']:
- if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
- if env['UNORDERED_MAP_NAMESPACE'] == 'std':
- defs.append('CYCLES_STD_UNORDERED_MAP')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CYCLES_TR1_UNORDERED_MAP')
-else:
- print("-- Replacing unordered_map/set with map/set (warning: slower!)")
- defs.append('CYCLES_NO_UNORDERED_MAP')
-
-defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
-defs.append('CCL_NAMESPACE_END=}')
-
-defs.append('WITH_OPENCL')
-defs.append('WITH_MULTI')
-defs.append('WITH_CUDA')
-
-if env['WITH_BF_CYCLES_OSL']:
- defs.append('WITH_OSL')
- defs.append('OSL_STATIC_LIBRARY')
- incs.append(cycles['BF_OSL_INC'])
-
-if env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-if env['WITH_BF_CYCLES_LOGGING']:
- defs.append('WITH_CYCLES_LOGGING')
- defs.append('GOOGLE_GLOG_DLL_DECL=')
- defs.append('CYCLES_GFLAGS_NAMESPACE=gflags')
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append('#extern/libmv/third_party/glog/src/windows')
- incs.append('#extern/libmv/third_party/gflags')
- else:
- incs.append('#extern/libmv/third_party/glog/src')
- incs.append('#extern/libmv/third_party/gflags')
-
-incs.extend('. bvh render device kernel kernel/osl kernel/svm util subd'.split())
-incs.extend('#intern/guardedalloc #source/blender/makesrna #source/blender/makesdna #source/blender/blenlib'.split())
-incs.extend('#source/blender/blenloader ../../source/blender/makesrna/intern'.split())
-
-incs.append(env['BF_GLEW_INC'])
-incs.append('#/intern/glew-mx')
-incs.append('#/intern/atomic')
-incs.append('#intern/mikktspace')
-incs.extend('#extern/glew/include #extern/clew/include #extern/cuew/include #intern/mikktspace'.split())
-
-incs.append(cycles['BF_OIIO_INC'])
-incs.append(cycles['BF_BOOST_INC'])
-incs.append(cycles['BF_OPENEXR_INC'].split())
-incs.extend(cycles['BF_PYTHON_INC'].split())
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- cxxflags.append('-D_CRT_SECURE_NO_WARNINGS /fp:fast /EHsc'.split())
-else:
- cxxflags.append('-ffast-math'.split())
-
-# Warnings
-# XXX Not supported by gcc < 4.9, since we do not have any 'supported flags' test as in cmake,
-# simpler to comment for now.
-#if env['C_COMPILER_ID'] == 'gcc':
-# cxxflags.append(['-Werror=float-conversion'])
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-# optimized kernel. we compile the kernel multiple times with different
-# optimization flags, at runtime it will choose the optimal kernel
-kernel_flags = {}
-
-if env['OURPLATFORM'] == 'win32-vc':
- # there is no /arch:SSE3, but intrinsics are available anyway
- kernel_flags['sse2'] = '/arch:SSE /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /GS-'
- kernel_flags['sse3'] = kernel_flags['sse2']
-
-elif env['OURPLATFORM'] == 'win64-vc':
- # /arch:AVX only available from visual studio 2012
- kernel_flags['sse2'] = '-D_CRT_SECURE_NO_WARNINGS /fp:fast /Ox /GS-'
- kernel_flags['sse3'] = kernel_flags['sse2']
-
- if env['MSVC_VERSION'] >= '12.0':
- kernel_flags['sse41'] = kernel_flags['sse3']
- kernel_flags['avx'] = kernel_flags['sse41'] + ' /arch:AVX'
- kernel_flags['avx2'] = kernel_flags['sse41'] + ' /arch:AVX /arch:AVX2'
-else:
- # -mavx only available with relatively new gcc/clang
- kernel_flags['sse2'] = '-ffast-math -msse -msse2 -mfpmath=sse'
- kernel_flags['sse3'] = kernel_flags['sse2'] + ' -msse3 -mssse3'
- kernel_flags['sse41'] = kernel_flags['sse3'] + ' -msse4.1'
-
- if (env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6') or (env['C_COMPILER_ID'] == 'clang' and env['CCVERSION'] >= '3.1'):
- kernel_flags['avx'] = kernel_flags['sse41'] + ' -mavx'
- kernel_flags['avx2'] = kernel_flags['avx'] + ' -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c'
-
-for kernel_type in kernel_flags.keys():
- defs.append('WITH_KERNEL_' + kernel_type.upper())
-
-for kernel_type in kernel_flags.keys():
- kernel_source = path.join('kernel', 'kernels', 'cpu', 'kernel_' + kernel_type + '.cpp')
- kernel_cxxflags = Split(env['CXXFLAGS'])
- kernel_cxxflags.append(kernel_flags[kernel_type].split())
- kernel_defs = defs[:]
- kernel_env = cycles.Clone()
-
- if env['OURPLATFORM'] == 'darwin' and env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6':
- # use Apple assembler for avx , gnu-compilers do not support it ( gnu gcc-4.6 or higher case )
- kernel_env.BlenderLib('bf_intern_cycles_' + kernel_type, [kernel_source], incs, kernel_defs,
- libtype=['intern'], priority=[10], cxx_compileflags=kernel_cxxflags,
- cc_compilerchange='/usr/bin/clang', cxx_compilerchange='/usr/bin/clang++')
- else:
- kernel_env.BlenderLib('bf_intern_cycles_' + kernel_type, [kernel_source], incs, kernel_defs,
- libtype=['intern'], priority=[10], cxx_compileflags=kernel_cxxflags)
-
-cycles.BlenderLib('bf_intern_cycles', sources, incs, defs, libtype=['intern'], priority=[0], cxx_compileflags=cxxflags)
-
-# OSL shaders
-if env['WITH_BF_CYCLES_OSL']:
- oso_files = SConscript(['kernel/shaders/SConscript'])
- cycles.Depends("kernel/osl/osl_shader.o", oso_files)
-
- SConscript(['kernel/osl/SConscript'])
-
-# cuda kernel binaries
-if env['WITH_BF_CYCLES_CUDA_BINARIES']:
- kernel_binaries = SConscript(['kernel/SConscript'])
- cycles.Depends("device/device_cuda.o", kernel_binaries)
-
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index b000266cac2..d40a1a14f72 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -29,9 +29,14 @@ set(LIBRARIES
${TIFF_LIBRARY}
${PTHREADS_LIBRARIES}
extern_clew
- extern_cuew
)
+if(WITH_CUDA_DYNLOAD)
+ list(APPEND LIBRARIES extern_cuew)
+else()
+ list(APPEND LIBRARIES ${CUDA_CUDA_LIBRARY})
+endif()
+
if(WITH_CYCLES_OSL)
list(APPEND LIBRARIES cycles_kernel_osl)
endif()
@@ -44,9 +49,9 @@ if(CYCLES_STANDALONE_REPOSITORY)
)
endif()
else()
- list(APPEND LIBRARIES bf_intern_glew_mx)
+ list(APPEND LIBRARIES bf_intern_glew_mx bf_intern_guardedalloc)
if(WITH_CYCLES_LOGGING)
- list(APPEND LIBRARIES extern_glog)
+ list(APPEND LIBRARIES extern_glog extern_gflags)
endif()
endif()
@@ -79,18 +84,12 @@ include_directories(SYSTEM ${INC_SYS})
macro(cycles_target_link_libraries target)
target_link_libraries(${target} ${LIBRARIES})
if(WITH_CYCLES_OSL)
- target_link_libraries_decoupled(${target} OSL_LIBRARIES)
- if(MSVC)
- target_link_libraries_debug(${target} "${LLVM_LIBRARIES_DEBUG}")
- target_link_libraries_optimized(${target} "${LLVM_LIBRARIES}")
- else()
- target_link_libraries(${target} ${LLVM_LIBRARIES})
- endif()
+ target_link_libraries(${target} ${OSL_LIBRARIES} ${LLVM_LIBRARIES})
endif()
- target_link_libraries_decoupled(${target} OPENIMAGEIO_LIBRARIES)
- target_link_libraries_decoupled(${target} OPENEXR_LIBRARIES)
target_link_libraries(
${target}
+ ${OPENIMAGEIO_LIBRARIES}
+ ${OPENEXR_LIBRARIES}
${PUGIXML_LIBRARIES}
${BOOST_LIBRARIES}
${CMAKE_DL_LIBS}
diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp
index b0d49d6ee72..726e9a51744 100644
--- a/intern/cycles/app/cycles_standalone.cpp
+++ b/intern/cycles/app/cycles_standalone.cpp
@@ -32,6 +32,7 @@
#include "util_string.h"
#include "util_time.h"
#include "util_transform.h"
+#include "util_version.h"
#ifdef WITH_CYCLES_STANDALONE_GUI
#include "util_view.h"
@@ -358,7 +359,7 @@ static void options_parse(int argc, const char **argv)
/* parse options */
ArgParse ap;
- bool help = false, debug = false;
+ bool help = false, debug = false, version = false;
int verbosity = 1;
ap.options ("Usage: cycles [options] file.xml",
@@ -380,6 +381,7 @@ static void options_parse(int argc, const char **argv)
"--verbose %d", &verbosity, "Set verbosity of the logger",
#endif
"--help", &help, "Print help message",
+ "--version", &version, "Print version number",
NULL);
if(ap.parse(argc, argv) < 0) {
@@ -406,6 +408,10 @@ static void options_parse(int argc, const char **argv)
exit(EXIT_SUCCESS);
}
+ else if(version) {
+ printf("%s\n", CYCLES_VERSION_STRING);
+ exit(EXIT_SUCCESS);
+ }
else if(help || options.filepath == "") {
ap.usage();
exit(EXIT_SUCCESS);
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index edea8cd0ec4..c845f28ff90 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -359,6 +359,10 @@ static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
xml_read_float(&cam->fisheye_fov, node, "fisheye_fov");
xml_read_float(&cam->fisheye_lens, node, "fisheye_lens");
+ xml_read_bool(&cam->use_spherical_stereo, node, "use_spherical_stereo");
+ xml_read_float(&cam->interocular_distance, node, "interocular_distance");
+ xml_read_float(&cam->convergence_distance, node, "convergence_distance");
+
xml_read_float(&cam->sensorwidth, node, "sensorwidth");
xml_read_float(&cam->sensorheight, node, "sensorheight");
@@ -513,6 +517,7 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
else if(string_iequals(node.name(), "wave_texture")) {
WaveTextureNode *wave = new WaveTextureNode();
xml_read_enum(&wave->type, WaveTextureNode::type_enum, node, "type");
+ xml_read_enum(&wave->profile, WaveTextureNode::profile_enum, node, "profile");
snode = wave;
}
else if(string_iequals(node.name(), "normal")) {
@@ -595,8 +600,10 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
xml_read_string(&falloff, node, "falloff");
if(falloff == "cubic")
sss->closure = CLOSURE_BSSRDF_CUBIC_ID;
- else
+ else if(falloff == "gaussian")
sss->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+ else /*if(falloff == "burley")*/
+ sss->closure = CLOSURE_BSSRDF_BURLEY_ID;
snode = sss;
}
@@ -1001,6 +1008,8 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
fdata[2] = make_float3(UV[v2*2], UV[v2*2+1], 0.0);
fdata += 3;
}
+
+ index_offset += nverts[i];
}
}
}
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index c6a2b919486..a8cc4907cbf 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -52,6 +52,10 @@ set(ADDON_FILES
add_definitions(${GL_DEFINITIONS})
+if(WITH_CYCLES_NETWORK)
+ add_definitions(-DWITH_NETWORK)
+endif()
+
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}")
# avoid link failure with clang 3.4 debug
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 0783c1c4cba..29388317873 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -19,11 +19,11 @@
bl_info = {
"name": "Cycles Render Engine",
"author": "",
- "blender": (2, 70, 0),
+ "blender": (2, 76, 0),
"location": "Info header, render engine menu",
"description": "Cycles Render Engine integration",
"warning": "",
- "wiki_url": "http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles",
+ "wiki_url": "https://www.blender.org/manual/render/cycles/index.html",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Render"}
@@ -43,6 +43,7 @@ class CyclesRender(bpy.types.RenderEngine):
bl_use_preview = True
bl_use_exclude_layers = True
bl_use_save_buffers = True
+ bl_use_spherical_stereo = True
def __init__(self):
self.session = None
@@ -67,8 +68,8 @@ class CyclesRender(bpy.types.RenderEngine):
def render(self, scene):
engine.render(self)
- def bake(self, scene, obj, pass_type, object_id, pixel_array, num_pixels, depth, result):
- engine.bake(self, obj, pass_type, object_id, pixel_array, num_pixels, depth, result)
+ def bake(self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
+ engine.bake(self, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result)
# viewport render
def view_update(self, context):
@@ -88,10 +89,19 @@ class CyclesRender(bpy.types.RenderEngine):
self.report({'ERROR'}, "OSL support disabled in this build.")
+def engine_exit():
+ engine.exit()
+
+
def register():
from . import ui
from . import properties
from . import presets
+ import atexit
+
+ # Make sure we only registered the callback once.
+ atexit.unregister(engine_exit)
+ atexit.register(engine_exit)
engine.init()
@@ -107,6 +117,7 @@ def unregister():
from . import ui
from . import properties
from . import presets
+ import atexit
bpy.app.handlers.version_update.remove(version_update.do_versions)
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 030f0dbbf14..d4b7535b9ee 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -50,10 +50,39 @@ def _workaround_buggy_drivers():
_cycles.opencl_disable()
+def _parse_command_line():
+ import sys
+
+ argv = sys.argv
+ if "--" not in argv:
+ return
+
+ argv = argv[argv.index("--") + 1:]
+
+ num_resumable_chunks = None
+ current_resumable_chunk = None
+
+ # TODO(sergey): Add some nice error ptins if argument is not used properly.
+ idx = 0
+ while idx < len(argv) - 1:
+ arg = argv[idx]
+ if arg == '--cycles-resumable-num-chunks':
+ num_resumable_chunks = int(argv[idx + 1])
+ elif arg == '--cycles-resumable-current-chunk':
+ current_resumable_chunk = int(argv[idx + 1])
+ idx += 1
+
+ if num_resumable_chunks is not None and current_resumable_chunk is not None:
+ import _cycles
+ _cycles.set_resumable_chunks(num_resumable_chunks,
+ current_resumable_chunk)
+
+
def init():
import bpy
import _cycles
import os.path
+ import sys
# Workaround possibly buggy legacy drivers which crashes on the OpenCL
# device enumeration.
@@ -72,7 +101,11 @@ def init():
user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', '')))
_cycles.init(path, user_path, bpy.app.background)
+ _parse_command_line()
+def exit():
+ import _cycles
+ _cycles.exit()
def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False):
import bpy
@@ -88,6 +121,11 @@ def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=Fa
if rv3d:
rv3d = rv3d.as_pointer()
+ if bpy.app.debug_value == 256:
+ _cycles.debug_flags_update(scene)
+ else:
+ _cycles.debug_flags_reset()
+
engine.session = _cycles.create(engine.as_pointer(), userpref, data, scene, region, v3d, rv3d, preview_osl)
@@ -105,11 +143,11 @@ def render(engine):
_cycles.render(engine.session)
-def bake(engine, obj, pass_type, object_id, pixel_array, num_pixels, depth, result):
+def bake(engine, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result):
import _cycles
session = getattr(engine, "session", None)
if session is not None:
- _cycles.bake(engine.session, obj.as_pointer(), pass_type, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
+ _cycles.bake(engine.session, obj.as_pointer(), pass_type, pass_filter, object_id, pixel_array.as_pointer(), num_pixels, depth, result.as_pointer())
def reset(engine, data, scene):
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 23d0d850cde..a5887bb9e2d 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -46,6 +46,12 @@ enum_displacement_methods = (
('BOTH', "Both", "Combination of displacement and bump mapping"),
)
+enum_subdivision_types = (
+ ('NONE', "None", "No subdivision"),
+ ('LINEAR', "Linear", "Use linear subdivision"),
+ ('CATMULL_CLARK', "Catmull–Clark", "Use Catmull-Clark subdivision"),
+ )
+
enum_bvh_types = (
('DYNAMIC_BVH', "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
('STATIC_BVH', "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"),
@@ -54,6 +60,7 @@ enum_bvh_types = (
enum_filter_types = (
('BOX', "Box", "Box filter"),
('GAUSSIAN', "Gaussian", "Gaussian filter"),
+ ('BLACKMAN_HARRIS', "Blackman-Harris", "Blackman-Harris filter"),
)
enum_aperture_types = (
@@ -91,6 +98,7 @@ enum_tile_order = (
('LEFT_TO_RIGHT', "Left to Right", "Render from left to right"),
('TOP_TO_BOTTOM', "Top to Bottom", "Render from top to bottom"),
('BOTTOM_TO_TOP', "Bottom to Top", "Render from bottom to top"),
+ ('HILBERT_SPIRAL', "Hilbert Spiral", "Render in a Hilbert Spiral"),
)
enum_use_layer_samples = (
@@ -163,13 +171,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
name="Samples",
description="Number of samples to render for each pixel",
min=1, max=2147483647,
- default=10,
+ default=128,
)
cls.preview_samples = IntProperty(
name="Preview Samples",
description="Number of samples to render in the viewport, unlimited if 0",
min=0, max=2147483647,
- default=10,
+ default=32,
)
cls.preview_pause = BoolProperty(
name="Pause Preview",
@@ -236,7 +244,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
name="Volume Samples",
description="Number of volume scattering samples to render for each AA sample",
min=1, max=10000,
- default=0,
+ default=1,
)
cls.sampling_pattern = EnumProperty(
@@ -362,6 +370,26 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=2, max=65536
)
+ cls.dicing_rate = FloatProperty(
+ name="Dicing Rate",
+ description="Size of a micropolygon in pixels",
+ min=0.1, max=1000.0,
+ default=1.0,
+ )
+ cls.preview_dicing_rate = FloatProperty(
+ name="Preview Dicing Rate",
+ description="Size of a micropolygon in pixels during preview render",
+ min=0.1, max=1000.0,
+ default=8.0,
+ )
+
+ cls.max_subdivisions = IntProperty(
+ name="Max Subdivisions",
+ description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation",
+ min=0, max=16,
+ default=12,
+ )
+
cls.film_exposure = FloatProperty(
name="Exposure",
description="Image brightness scale",
@@ -374,12 +402,24 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
default=False,
)
+ # Really annoyingly, we have to keep it around for a few releases,
+ # otherwise forward compatibility breaks in really bad manner: CRASH!
+ #
+ # TODO(sergey): Remove this during 2.8x series of Blender.
cls.filter_type = EnumProperty(
name="Filter Type",
description="Pixel filter type",
items=enum_filter_types,
- default='GAUSSIAN',
+ default='BLACKMAN_HARRIS',
)
+
+ cls.pixel_filter_type = EnumProperty(
+ name="Filter Type",
+ description="Pixel filter type",
+ items=enum_filter_types,
+ default='BLACKMAN_HARRIS',
+ )
+
cls.filter_width = FloatProperty(
name="Filter Width",
description="Pixel filter width",
@@ -463,16 +503,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use BVH spatial splits: longer builder time, faster render",
default=False,
)
- cls.use_cache = BoolProperty(
- name="Cache BVH",
- description="Cache last built BVH to disk for faster re-render if no geometry changed",
- default=False,
- )
cls.tile_order = EnumProperty(
name="Tile Order",
description="Tile order for rendering",
items=enum_tile_order,
- default='CENTER',
+ default='HILBERT_SPIRAL',
options=set(), # Not animatable!
)
cls.use_progressive_refine = BoolProperty(
@@ -496,18 +531,10 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
('UV', "UV", ""),
('EMIT', "Emit", ""),
('ENVIRONMENT', "Environment", ""),
- ('DIFFUSE_DIRECT', "Diffuse Direct", ""),
- ('DIFFUSE_INDIRECT', "Diffuse Indirect", ""),
- ('DIFFUSE_COLOR', "Diffuse Color", ""),
- ('GLOSSY_DIRECT', "Glossy Direct", ""),
- ('GLOSSY_INDIRECT', "Glossy Indirect", ""),
- ('GLOSSY_COLOR', "Glossy Color", ""),
- ('TRANSMISSION_DIRECT', "Transmission Direct", ""),
- ('TRANSMISSION_INDIRECT', "Transmission Indirect", ""),
- ('TRANSMISSION_COLOR', "Transmission Color", ""),
- ('SUBSURFACE_DIRECT', "Subsurface Direct", ""),
- ('SUBSURFACE_INDIRECT', "Subsurface Indirect", ""),
- ('SUBSURFACE_COLOR', "Subsurface Color", ""),
+ ('DIFFUSE', "Diffuse", ""),
+ ('GLOSSY', "Glossy", ""),
+ ('TRANSMISSION', "Transmission", ""),
+ ('SUBSURFACE', "Subsurface", ""),
),
)
@@ -524,6 +551,76 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
min=0.0, max=5.0
)
+ cls.motion_blur_position = EnumProperty(
+ name="Motion Blur Position",
+ default='CENTER',
+ description="Offset for the shutter's time interval, allows to change the motion blur trails",
+ items=(
+ ('START', "Start on Frame", "The shutter opens at the current frame"),
+ ('CENTER', "Center on Frame", "The shutter is open during the current frame"),
+ ('END', "End on Frame", "The shutter closes at the current frame"),
+ ),
+ )
+
+ cls.rolling_shutter_type = EnumProperty(
+ name="Shutter Type",
+ default='NONE',
+ description="Type of rolling shutter effect matching CMOS-based cameras",
+ items=(
+ ('NONE', "None", "No rolling shutter effect used"),
+ ('TOP', "Top-Bottom", "Sensor is being scanned from top to bottom")
+ # TODO(seergey): Are there real cameras with different scanning direction?
+ ),
+ )
+
+ cls.rolling_shutter_duration = FloatProperty(
+ name="Rolling Shutter Duration",
+ description="Scanline \"exposure\" time for the rolling shutter effect",
+ default=0.1,
+ min=0.0, max=1.0,
+ )
+
+ # Various fine-tuning debug flags
+
+ def devices_update_callback(self, context):
+ import _cycles
+ scene = context.scene.as_pointer()
+ return _cycles.debug_flags_update(scene)
+
+ cls.debug_use_cpu_avx2 = BoolProperty(name="AVX2", default=True)
+ cls.debug_use_cpu_avx = BoolProperty(name="AVX", default=True)
+ cls.debug_use_cpu_sse41 = BoolProperty(name="SSE41", default=True)
+ cls.debug_use_cpu_sse3 = BoolProperty(name="SSE3", default=True)
+ cls.debug_use_cpu_sse2 = BoolProperty(name="SSE2", default=True)
+ cls.debug_use_qbvh = BoolProperty(name="QBVH", default=True)
+
+ cls.debug_opencl_kernel_type = EnumProperty(
+ name="OpenCL Kernel Type",
+ default='DEFAULT',
+ items=(
+ ('DEFAULT', "Default", ""),
+ ('MEGA', "Mega", ""),
+ ('SPLIT', "Split", ""),
+ ),
+ update=devices_update_callback
+ )
+
+ cls.debug_opencl_device_type = EnumProperty(
+ name="OpenCL Device Type",
+ default='ALL',
+ items=(
+ ('NONE', "None", ""),
+ ('ALL', "All", ""),
+ ('DEFAULT', "Default", ""),
+ ('CPU', "CPU", ""),
+ ('GPU', "GPU", ""),
+ ('ACCELERATOR', "Accelerator", ""),
+ ),
+ update=devices_update_callback
+ )
+
+ cls.debug_use_opencl_debug = BoolProperty(name="Debug OpenCL", default=False)
+
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles
@@ -667,7 +764,7 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
name="Volume Sampling",
description="Sampling method to use for volumes",
items=enum_volume_sampling,
- default='DISTANCE',
+ default='MULTIPLE_IMPORTANCE',
)
cls.volume_interpolation = EnumProperty(
@@ -711,7 +808,7 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
name="Multiple Importance Sample",
description="Use multiple importance sampling for the lamp, "
"reduces noise for area lamps and sharp glossy materials",
- default=False,
+ default=True,
)
cls.is_portal = BoolProperty(
name="Is Portal",
@@ -737,20 +834,20 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
name="Multiple Importance Sample",
description="Use multiple importance sampling for the environment, "
"enabling for non-solid colors is recommended",
- default=False,
+ default=True,
)
cls.sample_map_resolution = IntProperty(
name="Map Resolution",
description="Importance map size is resolution x resolution; "
"higher values potentially produce less noise, at the cost of memory and speed",
min=4, max=8192,
- default=256,
+ default=1024,
)
cls.samples = IntProperty(
name="Samples",
description="Number of light samples to render for each AA sample",
min=1, max=10000,
- default=4,
+ default=1,
)
cls.max_bounces = IntProperty(
name="Max Bounces",
@@ -860,15 +957,16 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
items=enum_displacement_methods,
default='BUMP',
)
- cls.use_subdivision = BoolProperty(
- name="Use Subdivision",
- description="Subdivide mesh for rendering",
- default=False,
+ cls.subdivision_type = EnumProperty(
+ name="Subdivision Type",
+ description="Type of subdivision to use",
+ items=enum_subdivision_types,
+ default='NONE',
)
cls.dicing_rate = FloatProperty(
name="Dicing Rate",
- description="",
- min=0.001, max=1000.0,
+ description="Multiplier for scene dicing rate",
+ min=0.1, max=1000.0,
default=1.0,
)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index b4a061424b2..a4e6809390d 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -60,6 +60,20 @@ def use_cpu(context):
return (device_type == 'NONE' or cscene.device == 'CPU')
+def use_opencl(context):
+ cscene = context.scene.cycles
+ device_type = context.user_preferences.system.compute_device_type
+
+ return (device_type == 'OPENCL' and cscene.device == 'GPU')
+
+
+def use_cuda(context):
+ cscene = context.scene.cycles
+ device_type = context.user_preferences.system.compute_device_type
+
+ return (device_type == 'CUDA' and cscene.device == 'GPU')
+
+
def use_branched_path(context):
cscene = context.scene.cycles
device_type = context.user_preferences.system.compute_device_type
@@ -67,6 +81,12 @@ def use_branched_path(context):
return (cscene.progressive == 'BRANCHED_PATH' and device_type != 'OPENCL')
+def use_sample_all_lights(context):
+ cscene = context.scene.cycles
+
+ return cscene.sample_all_lights_direct or cscene.sample_all_lights_indirect
+
+
def draw_samples_info(layout, context):
cscene = context.scene.cycles
integrator = cscene.progressive
@@ -131,7 +151,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
row = layout.row()
sub = row.row()
- sub.active = device_type != 'OPENCL'
+ sub.active = device_type != 'OPENCL' or use_cpu(context)
sub.prop(cscene, "progressive", text="")
row.prop(cscene, "use_square_samples")
@@ -148,7 +168,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
sub.prop(cscene, "sample_clamp_direct")
sub.prop(cscene, "sample_clamp_indirect")
- if cscene.progressive == 'PATH' or use_branched_path(context) == False:
+ if cscene.progressive == 'PATH' or use_branched_path(context) is False:
col = split.column()
sub = col.column(align=True)
sub.label(text="Samples:")
@@ -169,11 +189,15 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
sub.prop(cscene, "glossy_samples", text="Glossy")
sub.prop(cscene, "transmission_samples", text="Transmission")
sub.prop(cscene, "ao_samples", text="AO")
- sub.prop(cscene, "mesh_light_samples", text="Mesh Light")
+
+ subsub = sub.row(align=True)
+ subsub.active = use_sample_all_lights(context)
+ subsub.prop(cscene, "mesh_light_samples", text="Mesh Light")
+
sub.prop(cscene, "subsurface_samples", text="Subsurface")
sub.prop(cscene, "volume_samples", text="Volume")
- if use_cpu(context) or cscene.feature_set == 'EXPERIMENTAL':
+ if not (use_opencl(context) and cscene.feature_set != 'EXPERIMENTAL'):
layout.row().prop(cscene, "sampling_pattern", text="Pattern")
for rl in scene.render.layers:
@@ -185,8 +209,8 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
draw_samples_info(layout, context)
-class CyclesRender_PT_volume_sampling(CyclesButtonsPanel, Panel):
- bl_label = "Volume Sampling"
+class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel):
+ bl_label = "Geometry"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
@@ -195,11 +219,30 @@ class CyclesRender_PT_volume_sampling(CyclesButtonsPanel, Panel):
scene = context.scene
cscene = scene.cycles
- row = layout.row()
- row.label("Heterogeneous:")
- row = layout.row()
- row.prop(cscene, "volume_step_size")
- row.prop(cscene, "volume_max_steps")
+ if cscene.feature_set == 'EXPERIMENTAL':
+ split = layout.split()
+
+ col = split.column()
+
+ sub = col.column(align=True)
+ sub.label("Volume Sampling:")
+ sub.prop(cscene, "volume_step_size")
+ sub.prop(cscene, "volume_max_steps")
+
+ col = split.column()
+
+ sub = col.column(align=True)
+ sub.label("Subdivision Rate:")
+ sub.prop(cscene, "dicing_rate", text="Render")
+ sub.prop(cscene, "preview_dicing_rate", text="Preview")
+ sub.separator()
+ sub.prop(cscene, "max_subdivisions")
+ else:
+ row = layout.row()
+ row.label("Volume Sampling:")
+ row = layout.row()
+ row.prop(cscene, "volume_step_size")
+ row.prop(cscene, "volume_max_steps")
class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
@@ -259,11 +302,33 @@ class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
- rd = context.scene.render
+ scene = context.scene
+ cscene = scene.cycles
+ rd = scene.render
layout.active = rd.use_motion_blur
- row = layout.row()
- row.prop(rd, "motion_blur_shutter")
+ col = layout.column()
+ col.prop(cscene, "motion_blur_position", text="Position")
+ col.prop(rd, "motion_blur_shutter")
+
+ col = layout.column()
+ col.label("Shutter curve:")
+ col.template_curve_mapping(rd, "motion_blur_shutter_curve")
+
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.operator("render.shutter_curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
+ row.operator("render.shutter_curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
+ row.operator("render.shutter_curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
+ row.operator("render.shutter_curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
+ row.operator("render.shutter_curve_preset", icon='LINCURVE', text="").shape = 'LINE'
+ row.operator("render.shutter_curve_preset", icon='NOCURVE', text="").shape = 'MAX'
+
+ col = layout.column()
+ col.prop(cscene, "rolling_shutter_type")
+ row = col.row()
+ row.active = cscene.rolling_shutter_type != 'NONE'
+ row.prop(cscene, "rolling_shutter_duration")
class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
@@ -283,8 +348,8 @@ class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
col = split.column()
sub = col.column(align=True)
- sub.prop(cscene, "filter_type", text="")
- if cscene.filter_type != 'BOX':
+ sub.prop(cscene, "pixel_filter_type", text="")
+ if cscene.pixel_filter_type != 'BOX':
sub.prop(cscene, "filter_width", text="Width")
@@ -332,7 +397,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
col.separator()
col.label(text="Final Render:")
- col.prop(cscene, "use_cache")
col.prop(rd, "use_persistent_data", text="Persistent Images")
col.separator()
@@ -372,6 +436,7 @@ class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
col = split.column()
col.prop(rl, "use_sky", "Use Environment")
+ col.prop(rl, "use_ao", "Use AO")
col.prop(rl, "use_solid", "Use Surfaces")
col.prop(rl, "use_strand", "Use Hair")
@@ -564,9 +629,9 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
ob = context.object
slot = context.material_slot
space = context.space_data
- is_sortable = len(ob.material_slots) > 1
if ob:
+ is_sortable = len(ob.material_slots) > 1
rows = 1
if (is_sortable):
rows = 4
@@ -635,10 +700,20 @@ class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
elif mball:
cdata = mball.cycles
- layout.prop(cdata, "displacement_method", text="Method")
- layout.prop(cdata, "use_subdivision")
- layout.prop(cdata, "dicing_rate")
+ split = layout.split()
+
+ col = split.column()
+ sub = col.column(align=True)
+ sub.label(text="Displacment:")
+ sub.prop(cdata, "displacement_method", text="")
+
+ col = split.column()
+ sub = col.column(align=True)
+ sub.label(text="Subdivision:")
+ sub.prop(cdata, "subdivision_type", text="")
+ if cdata.subdivision_type != 'NONE':
+ sub.prop(cdata, "dicing_rate")
class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
bl_label = "Motion Blur"
@@ -841,7 +916,9 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
if not (lamp.type == 'AREA' and clamp.is_portal):
sub = col.column(align=True)
if use_branched_path(context):
- sub.prop(clamp, "samples")
+ subsub = sub.row(align=True)
+ subsub.active = use_sample_all_lights(context)
+ subsub.prop(clamp, "samples")
sub.prop(clamp, "max_bounces")
col = split.column()
@@ -1050,7 +1127,9 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel):
sub.active = cworld.sample_as_light
sub.prop(cworld, "sample_map_resolution")
if use_branched_path(context):
- sub.prop(cworld, "samples")
+ subsub = sub.row(align=True)
+ subsub.active = use_sample_all_lights(context)
+ subsub.prop(cworld, "samples")
sub.prop(cworld, "max_bounces")
col = split.column()
@@ -1391,7 +1470,43 @@ class CyclesRender_PT_bake(CyclesButtonsPanel, Panel):
col = layout.column()
col.prop(cscene, "bake_type")
- col.separator()
+
+ col = layout.column()
+
+ if cscene.bake_type == 'NORMAL':
+ col.prop(cbk, "normal_space", text="Space")
+
+ row = col.row(align=True)
+ row.label(text="Swizzle:")
+ row.prop(cbk, "normal_r", text="")
+ row.prop(cbk, "normal_g", text="")
+ row.prop(cbk, "normal_b", text="")
+
+ elif cscene.bake_type == 'COMBINED':
+ row = col.row(align=True)
+ row.prop(cbk, "use_pass_direct", toggle=True)
+ row.prop(cbk, "use_pass_indirect", toggle=True)
+
+ split = col.split()
+ split.active = cbk.use_pass_direct or cbk.use_pass_indirect
+
+ col = split.column()
+ col.prop(cbk, "use_pass_diffuse")
+ col.prop(cbk, "use_pass_glossy")
+ col.prop(cbk, "use_pass_transmission")
+
+ col = split.column()
+ col.prop(cbk, "use_pass_subsurface")
+ col.prop(cbk, "use_pass_ambient_occlusion")
+ col.prop(cbk, "use_pass_emit")
+
+ elif cscene.bake_type in {'DIFFUSE', 'GLOSSY', 'TRANSMISSION', 'SUBSURFACE'}:
+ row = col.row(align=True)
+ row.prop(cbk, "use_pass_direct", toggle=True)
+ row.prop(cbk, "use_pass_indirect", toggle=True)
+ row.prop(cbk, "use_pass_color", toggle=True)
+
+ layout.separator()
split = layout.split()
@@ -1410,17 +1525,39 @@ class CyclesRender_PT_bake(CyclesButtonsPanel, Panel):
else:
sub.prop(cbk, "cage_extrusion", text="Ray Distance")
- if cscene.bake_type == 'NORMAL':
- layout.separator()
- box = layout.box()
- box.label(text="Normal Settings:")
- box.prop(cbk, "normal_space", text="Space")
- row = box.row(align=True)
- row.label(text="Swizzle:")
- row.prop(cbk, "normal_r", text="")
- row.prop(cbk, "normal_g", text="")
- row.prop(cbk, "normal_b", text="")
+class CyclesRender_PT_debug(CyclesButtonsPanel, Panel):
+ bl_label = "Debug"
+ bl_context = "render"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'CYCLES'}
+
+ @classmethod
+ def poll(cls, context):
+ return CyclesButtonsPanel.poll(context) and bpy.app.debug_value == 256
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ cscene = scene.cycles
+
+ col = layout.column()
+
+ col.label('CPU Flags:')
+ row = col.row(align=True)
+ row.prop(cscene, "debug_use_cpu_sse2", toggle=True)
+ row.prop(cscene, "debug_use_cpu_sse3", toggle=True)
+ row.prop(cscene, "debug_use_cpu_sse41", toggle=True)
+ row.prop(cscene, "debug_use_cpu_avx", toggle=True)
+ row.prop(cscene, "debug_use_cpu_avx2", toggle=True)
+ col.prop(cscene, "debug_use_qbvh")
+
+ col = layout.column()
+ col.label('OpenCL Flags:')
+ col.prop(cscene, "debug_opencl_kernel_type", text="Kernel")
+ col.prop(cscene, "debug_opencl_device_type", text="Device")
+ col.prop(cscene, "debug_use_opencl_debug", text="Debug")
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 2fbb01ba5b8..221b1437128 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -100,6 +100,77 @@ def mapping_node_order_flip(node):
node.rotation = quat.to_euler('XYZ')
+def vector_curve_node_remap(node):
+ """
+ Remap values of vector curve node from normalized to absolute values
+ """
+ from mathutils import Vector
+ if node.bl_idname == 'ShaderNodeVectorCurve':
+ node.mapping.use_clip = False
+ for curve in node.mapping.curves:
+ for point in curve.points:
+ point.location.x = (point.location.x * 2.0) - 1.0
+ point.location.y = (point.location.y - 0.5) * 2.0
+ node.mapping.update()
+
+
+def custom_bake_remap(scene):
+ """
+ Remap bake types into the new types and set the flags accordingly
+ """
+ bake_lookup = (
+ 'COMBINED',
+ 'AO',
+ 'SHADOW',
+ 'NORMAL',
+ 'UV',
+ 'EMIT',
+ 'ENVIRONMENT',
+ 'DIFFUSE_DIRECT',
+ 'DIFFUSE_INDIRECT',
+ 'DIFFUSE_COLOR',
+ 'GLOSSY_DIRECT',
+ 'GLOSSY_INDIRECT',
+ 'GLOSSY_COLOR',
+ 'TRANSMISSION_DIRECT',
+ 'TRANSMISSION_INDIRECT',
+ 'TRANSMISSION_COLOR',
+ 'SUBSURFACE_DIRECT',
+ 'SUBSURFACE_INDIRECT',
+ 'SUBSURFACE_COLOR')
+
+ diffuse_direct_idx = bake_lookup.index('DIFFUSE_DIRECT')
+
+ cscene = scene.cycles
+
+ # Old bake type
+ bake_type_idx = cscene.get("bake_type")
+
+ if bake_type_idx is None:
+ cscene.bake_type = 'COMBINED'
+ return
+
+ # File doesn't need versioning
+ if bake_type_idx < diffuse_direct_idx:
+ return
+
+ # File needs versioning
+ bake_type = bake_lookup[bake_type_idx]
+ cscene.bake_type, end = bake_type.split('_')
+
+ if end == 'DIRECT':
+ scene.render.bake.use_pass_indirect = False
+ scene.render.bake.use_pass_color = False
+
+ elif end == 'INDIRECT':
+ scene.render.bake.use_pass_direct = False
+ scene.render.bake.use_pass_color = False
+
+ elif end == 'COLOR':
+ scene.render.bake.use_pass_direct = False
+ scene.render.bake.use_pass_indirect = False
+
+
@persistent
def do_versions(self):
# We don't modify startup file because it assumes to
@@ -140,3 +211,71 @@ def do_versions(self):
# Euler order was ZYX in previous versions.
if bpy.data.version <= (2, 73, 4):
foreach_cycles_node(mapping_node_order_flip)
+
+ if bpy.data.version <= (2, 76, 5):
+ foreach_cycles_node(vector_curve_node_remap)
+
+ # Baking types changed
+ if bpy.data.version <= (2, 76, 6):
+ for scene in bpy.data.scenes:
+ custom_bake_remap(scene)
+
+ # Several default changes for 2.77
+ if bpy.data.version <= (2, 76, 8):
+ for scene in bpy.data.scenes:
+ cscene = scene.cycles
+
+ # Samples
+ if not cscene.is_property_set("samples"):
+ cscene.samples = 10
+
+ # Preview Samples
+ if not cscene.is_property_set("preview_samples"):
+ cscene.preview_samples = 10
+
+ # Filter
+ if not cscene.is_property_set("filter_type"):
+ cscene.pixel_filter_type = 'GAUSSIAN'
+
+ # Tile Order
+ if not cscene.is_property_set("tile_order"):
+ cscene.tile_order = 'CENTER'
+
+ for lamp in bpy.data.lamps:
+ clamp = lamp.cycles
+
+ # MIS
+ if not clamp.is_property_set("use_multiple_importance_sampling"):
+ clamp.use_multiple_importance_sampling = False
+
+ for mat in bpy.data.materials:
+ cmat = mat.cycles
+
+ # Volume Sampling
+ if not cmat.is_property_set("volume_sampling"):
+ cmat.volume_sampling = 'DISTANCE'
+
+ if bpy.data.version <= (2, 76, 9):
+ for world in bpy.data.worlds:
+ cworld = world.cycles
+
+ # World MIS
+ if not cworld.is_property_set("sample_as_light"):
+ cworld.sample_as_light = False
+
+ # World MIS Samples
+ if not cworld.is_property_set("samples"):
+ cworld.samples = 4
+
+ # World MIS Resolution
+ if not cworld.is_property_set("sample_map_resolution"):
+ cworld.sample_map_resolution = 256
+
+ if bpy.data.version <= (2, 76, 10):
+ for scene in bpy.data.scenes:
+ cscene = scene.cycles
+ if cscene.is_property_set("filter_type"):
+ if not cscene.is_property_set("pixel_filter_type"):
+ cscene.pixel_filter_type = cscene.filter_type
+ if cscene.filter_type == 'BLACKMAN_HARRIS':
+ cscene.filter_type = 'GAUSSIAN'
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 1cc601ce148..6b459ae575f 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -36,6 +36,11 @@ struct BlenderCamera {
float lens;
float shuttertime;
+ Camera::MotionPosition motion_position;
+ float shutter_curve[RAMP_TABLE_SIZE];
+
+ Camera::RollingShutterType rolling_shutter_type;
+ float rolling_shutter_duration;
float aperturesize;
uint apertureblades;
@@ -57,6 +62,9 @@ struct BlenderCamera {
float latitude_max;
float longitude_min;
float longitude_max;
+ bool use_spherical_stereo;
+ float interocular_distance;
+ float convergence_distance;
enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
float sensor_width;
@@ -72,7 +80,8 @@ struct BlenderCamera {
Transform matrix;
};
-static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render)
+static void blender_camera_init(BlenderCamera *bcam,
+ BL::RenderSettings& b_render)
{
memset(bcam, 0, sizeof(BlenderCamera));
@@ -83,6 +92,9 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render
bcam->sensor_height = 18.0f;
bcam->sensor_fit = BlenderCamera::AUTO;
bcam->shuttertime = 1.0f;
+ bcam->motion_position = Camera::MOTION_POSITION_CENTER;
+ bcam->rolling_shutter_type = Camera::ROLLING_SHUTTER_NONE;
+ bcam->rolling_shutter_duration = 0.1f;
bcam->border.right = 1.0f;
bcam->border.top = 1.0f;
bcam->pano_viewplane.right = 1.0f;
@@ -93,9 +105,16 @@ static void blender_camera_init(BlenderCamera *bcam, BL::RenderSettings b_render
/* render resolution */
bcam->full_width = render_resolution_x(b_render);
bcam->full_height = render_resolution_y(b_render);
+
+ /* pixel aspect */
+ bcam->pixelaspect.x = b_render.pixel_aspect_x();
+ bcam->pixelaspect.y = b_render.pixel_aspect_y();
}
-static float blender_camera_focal_distance(BL::RenderEngine b_engine, BL::Object b_ob, BL::Camera b_camera)
+static float blender_camera_focal_distance(BL::RenderEngine& b_engine,
+ BL::Object& b_ob,
+ BL::Camera& b_camera,
+ BlenderCamera *bcam)
{
BL::Object b_dof_object = b_camera.dof_object();
@@ -104,15 +123,18 @@ static float blender_camera_focal_distance(BL::RenderEngine b_engine, BL::Object
/* for dof object, return distance along camera Z direction */
BL::Array<float, 16> b_ob_matrix;
- b_engine.camera_model_matrix(b_ob, b_ob_matrix);
- Transform obmat = get_transform(b_ob_matrix);
+ b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
+ Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
Transform dofmat = get_transform(b_dof_object.matrix_world());
float3 view_dir = normalize(transform_get_column(&obmat, 2));
float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
return fabsf(dot(view_dir, dof_dir));
}
-static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Object b_ob, bool skip_panorama = false)
+static void blender_camera_from_object(BlenderCamera *bcam,
+ BL::RenderEngine& b_engine,
+ BL::Object& b_ob,
+ bool skip_panorama = false)
{
BL::ID b_ob_data = b_ob.data();
@@ -138,24 +160,12 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_e
default:
bcam->type = CAMERA_PERSPECTIVE;
break;
- }
+ }
- switch(RNA_enum_get(&ccamera, "panorama_type"))
- {
- case 1:
- bcam->panorama_type = PANORAMA_FISHEYE_EQUIDISTANT;
- break;
- case 2:
- bcam->panorama_type = PANORAMA_FISHEYE_EQUISOLID;
- break;
- case 3:
- bcam->panorama_type = PANORAMA_MIRRORBALL;
- break;
- case 0:
- default:
- bcam->panorama_type = PANORAMA_EQUIRECTANGULAR;
- break;
- }
+ bcam->panorama_type = (PanoramaType)get_enum(ccamera,
+ "panorama_type",
+ PANORAMA_NUM_TYPES,
+ PANORAMA_EQUIRECTANGULAR);
bcam->fisheye_fov = RNA_float_get(&ccamera, "fisheye_fov");
bcam->fisheye_lens = RNA_float_get(&ccamera, "fisheye_lens");
@@ -164,13 +174,22 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_e
bcam->longitude_min = RNA_float_get(&ccamera, "longitude_min");
bcam->longitude_max = RNA_float_get(&ccamera, "longitude_max");
+ bcam->interocular_distance = b_camera.stereo().interocular_distance();
+ if(b_camera.stereo().convergence_mode() == BL::CameraStereoData::convergence_mode_PARALLEL) {
+ bcam->convergence_distance = FLT_MAX;
+ }
+ else {
+ bcam->convergence_distance = b_camera.stereo().convergence_distance();
+ }
+ bcam->use_spherical_stereo = b_engine.use_spherical_stereo(b_ob);
+
bcam->ortho_scale = b_camera.ortho_scale();
bcam->lens = b_camera.lens();
/* allow f/stop number to change aperture_size but still
* give manual control over aperture radius */
- int aperture_type = RNA_enum_get(&ccamera, "aperture_type");
+ int aperture_type = get_enum(ccamera, "aperture_type");
if(aperture_type == 1) {
float fstop = RNA_float_get(&ccamera, "aperture_fstop");
@@ -186,10 +205,10 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_e
bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
- bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera);
+ bcam->focaldistance = blender_camera_focal_distance(b_engine, b_ob, b_camera, bcam);
bcam->aperture_ratio = RNA_float_get(&ccamera, "aperture_ratio");
- bcam->shift.x = b_engine.camera_shift_x(b_ob);
+ bcam->shift.x = b_engine.camera_shift_x(b_ob, bcam->use_spherical_stereo);
bcam->shift.y = b_camera.shift_y();
bcam->sensor_width = b_camera.sensor_width();
@@ -331,7 +350,7 @@ static void blender_camera_viewplane(BlenderCamera *bcam,
}
}
-static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
+static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height, const char *viewname)
{
/* copy camera to compare later */
Camera prevcam = *cam;
@@ -341,6 +360,12 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
blender_camera_viewplane(bcam, width, height,
&cam->viewplane, &aspectratio, &sensor_size);
+ cam->width = bcam->full_width;
+ cam->height = bcam->full_height;
+
+ cam->full_width = width;
+ cam->full_height = height;
+
/* panorama sensor */
if(bcam->type == CAMERA_PANORAMA && bcam->panorama_type == PANORAMA_FISHEYE_EQUISOLID) {
float fit_xratio = (float)bcam->full_width*bcam->pixelaspect.x;
@@ -388,6 +413,20 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
cam->longitude_min = bcam->longitude_min;
cam->longitude_max = bcam->longitude_max;
+ /* panorama stereo */
+ cam->interocular_distance = bcam->interocular_distance;
+ cam->convergence_distance = bcam->convergence_distance;
+ cam->use_spherical_stereo = bcam->use_spherical_stereo;
+
+ if(cam->use_spherical_stereo) {
+ if(strcmp(viewname, "left") == 0)
+ cam->stereo_eye = Camera::STEREO_LEFT;
+ else if(strcmp(viewname, "right") == 0)
+ cam->stereo_eye = Camera::STEREO_RIGHT;
+ else
+ cam->stereo_eye = Camera::STEREO_NONE;
+ }
+
/* anamorphic lens bokeh */
cam->aperture_ratio = bcam->aperture_ratio;
@@ -409,6 +448,12 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
cam->shuttertime = bcam->shuttertime;
cam->fov_pre = cam->fov;
cam->fov_post = cam->fov;
+ cam->motion_position = bcam->motion_position;
+
+ cam->rolling_shutter_type = bcam->rolling_shutter_type;
+ cam->rolling_shutter_duration = bcam->rolling_shutter_duration;
+
+ memcpy(cam->shutter_curve, bcam->shutter_curve, sizeof(cam->shutter_curve));
/* border */
cam->border = bcam->border;
@@ -421,7 +466,10 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
/* Sync Render Camera */
-void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override, int width, int height)
+void BlenderSync::sync_camera(BL::RenderSettings& b_render,
+ BL::Object& b_override,
+ int width, int height,
+ const char *viewname)
{
BlenderCamera bcam;
blender_camera_init(&bcam, b_render);
@@ -431,6 +479,22 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
bcam.pixelaspect.y = b_render.pixel_aspect_y();
bcam.shuttertime = b_render.motion_blur_shutter();
+ BL::CurveMapping b_shutter_curve(b_render.motion_blur_shutter_curve());
+ curvemapping_to_array(b_shutter_curve, bcam.shutter_curve, RAMP_TABLE_SIZE);
+
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ bcam.motion_position =
+ (Camera::MotionPosition)get_enum(cscene,
+ "motion_blur_position",
+ Camera::MOTION_NUM_POSITIONS,
+ Camera::MOTION_POSITION_CENTER);
+ bcam.rolling_shutter_type =
+ (Camera::RollingShutterType)get_enum(cscene,
+ "rolling_shutter_type",
+ Camera::ROLLING_SHUTTER_NUM_TYPES,
+ Camera::ROLLING_SHUTTER_NONE);
+ bcam.rolling_shutter_duration = RNA_float_get(&cscene, "rolling_shutter_duration");
+
/* border */
if(b_render.use_border()) {
bcam.border.left = b_render.border_min_x();
@@ -448,17 +512,17 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
if(b_ob) {
BL::Array<float, 16> b_ob_matrix;
blender_camera_from_object(&bcam, b_engine, b_ob);
- b_engine.camera_model_matrix(b_ob, b_ob_matrix);
+ b_engine.camera_model_matrix(b_ob, bcam.use_spherical_stereo, b_ob_matrix);
bcam.matrix = get_transform(b_ob_matrix);
}
/* sync */
Camera *cam = scene->camera;
- blender_camera_sync(cam, &bcam, width, height);
+ blender_camera_sync(cam, &bcam, width, height, viewname);
}
-void BlenderSync::sync_camera_motion(BL::RenderSettings b_render,
- BL::Object b_ob,
+void BlenderSync::sync_camera_motion(BL::RenderSettings& b_render,
+ BL::Object& b_ob,
int width, int height,
float motion_time)
{
@@ -467,7 +531,7 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings b_render,
Camera *cam = scene->camera;
BL::Array<float, 16> b_ob_matrix;
- b_engine.camera_model_matrix(b_ob, b_ob_matrix);
+ b_engine.camera_model_matrix(b_ob, cam->use_spherical_stereo, b_ob_matrix);
Transform tfm = get_transform(b_ob_matrix);
tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
@@ -487,6 +551,7 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings b_render,
BlenderCamera bcam;
float aspectratio, sensor_size;
blender_camera_init(&bcam, b_render);
+
blender_camera_from_object(&bcam, b_engine, b_ob);
blender_camera_viewplane(&bcam,
width, height,
@@ -511,10 +576,23 @@ void BlenderSync::sync_camera_motion(BL::RenderSettings b_render,
/* Sync 3D View Camera */
-static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
- BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box);
-
-static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false)
+static void blender_camera_view_subset(BL::RenderEngine& b_engine,
+ BL::RenderSettings& b_render,
+ BL::Scene& b_scene,
+ BL::Object& b_ob,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height,
+ BoundBox2D *view_box,
+ BoundBox2D *cam_box);
+
+static void blender_camera_from_view(BlenderCamera *bcam,
+ BL::RenderEngine& b_engine,
+ BL::Scene& b_scene,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height,
+ bool skip_panorama = false)
{
/* 3d view parameters */
bcam->nearclip = b_v3d.clip_start();
@@ -522,6 +600,9 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine b_eng
bcam->lens = b_v3d.lens();
bcam->shuttertime = b_scene.render().motion_blur_shutter();
+ BL::CurveMapping b_shutter_curve(b_scene.render().motion_blur_shutter_curve());
+ curvemapping_to_array(b_shutter_curve, bcam->shutter_curve, RAMP_TABLE_SIZE);
+
if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
/* camera view */
BL::Object b_ob = (b_v3d.lock_camera_and_layers())? b_scene.camera(): b_v3d.camera();
@@ -533,8 +614,16 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine b_eng
/* in panorama camera view, we map viewplane to camera border */
BoundBox2D view_box, cam_box;
- blender_camera_view_subset(b_engine, b_scene.render(), b_scene, b_ob, b_v3d, b_rv3d, width, height,
- &view_box, &cam_box);
+ BL::RenderSettings b_render_settings(b_scene.render());
+ blender_camera_view_subset(b_engine,
+ b_render_settings,
+ b_scene,
+ b_ob,
+ b_v3d,
+ b_rv3d,
+ width, height,
+ &view_box,
+ &cam_box);
bcam->pano_viewplane = view_box.make_relative_to(cam_box);
}
@@ -571,8 +660,15 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::RenderEngine b_eng
bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
}
-static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d,
- BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box)
+static void blender_camera_view_subset(BL::RenderEngine& b_engine,
+ BL::RenderSettings& b_render,
+ BL::Scene& b_scene,
+ BL::Object& b_ob,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height,
+ BoundBox2D *view_box,
+ BoundBox2D *cam_box)
{
BoundBox2D cam, view;
float view_aspect, cam_aspect, sensor_size;
@@ -598,12 +694,12 @@ static void blender_camera_view_subset(BL::RenderEngine b_engine, BL::RenderSett
*cam_box = cam * (1.0f/cam_aspect);
}
-static void blender_camera_border_subset(BL::RenderEngine b_engine,
- BL::RenderSettings b_render,
- BL::Scene b_scene,
- BL::SpaceView3D b_v3d,
- BL::RegionView3D b_rv3d,
- BL::Object b_ob,
+static void blender_camera_border_subset(BL::RenderEngine& b_engine,
+ BL::RenderSettings& b_render,
+ BL::Scene& b_scene,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ BL::Object& b_ob,
int width, int height,
const BoundBox2D &border,
BoundBox2D *result)
@@ -618,8 +714,13 @@ static void blender_camera_border_subset(BL::RenderEngine b_engine,
*result = cam_box.subset(border);
}
-static void blender_camera_border(BlenderCamera *bcam, BL::RenderEngine b_engine, BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d,
- BL::RegionView3D b_rv3d, int width, int height)
+static void blender_camera_border(BlenderCamera *bcam,
+ BL::RenderEngine& b_engine,
+ BL::RenderSettings& b_render,
+ BL::Scene& b_scene,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height)
{
bool is_camera_view;
@@ -676,20 +777,37 @@ static void blender_camera_border(BlenderCamera *bcam, BL::RenderEngine b_engine
width, height,
bcam->border,
&bcam->border);
- bcam->border.clamp();
+ bcam->border = bcam->border.clamp();
}
-void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
+void BlenderSync::sync_view(BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height)
{
BlenderCamera bcam;
- blender_camera_init(&bcam, b_scene.render());
- blender_camera_from_view(&bcam, b_engine, b_scene, b_v3d, b_rv3d, width, height);
- blender_camera_border(&bcam, b_engine, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
-
- blender_camera_sync(scene->camera, &bcam, width, height);
+ BL::RenderSettings b_render_settings(b_scene.render());
+ blender_camera_init(&bcam, b_render_settings);
+ blender_camera_from_view(&bcam,
+ b_engine,
+ b_scene,
+ b_v3d,
+ b_rv3d,
+ width, height);
+ blender_camera_border(&bcam,
+ b_engine,
+ b_render_settings,
+ b_scene,
+ b_v3d,
+ b_rv3d,
+ width, height);
+ blender_camera_sync(scene->camera, &bcam, width, height, "");
}
-BufferParams BlenderSync::get_buffer_params(BL::RenderSettings b_render, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height)
+BufferParams BlenderSync::get_buffer_params(BL::RenderSettings& b_render,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ Camera *cam,
+ int width, int height)
{
BufferParams params;
bool use_border = false;
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 6a119081bfd..0178bfbe8d9 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -795,8 +795,16 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->minimum_width = get_float(csscene, "minimum_width");
curve_system_manager->maximum_width = get_float(csscene, "maximum_width");
- curve_system_manager->primitive = get_enum(csscene, "primitive");
- curve_system_manager->curve_shape = get_enum(csscene, "shape");
+ curve_system_manager->primitive =
+ (CurvePrimitiveType)get_enum(csscene,
+ "primitive",
+ CURVE_NUM_PRIMITIVE_TYPES,
+ CURVE_LINE_SEGMENTS);
+ curve_system_manager->curve_shape =
+ (CurveShapeType)get_enum(csscene,
+ "shape",
+ CURVE_NUM_SHAPE_TYPES,
+ CURVE_THICK);
curve_system_manager->resolution = get_int(csscene, "resolution");
curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
curve_system_manager->use_backfacing = !get_boolean(csscene, "cull_backfacing");
@@ -856,7 +864,11 @@ void BlenderSync::sync_curve_settings()
curve_system_manager->tag_update(scene);
}
-void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index)
+void BlenderSync::sync_curves(Mesh *mesh,
+ BL::Mesh& b_mesh,
+ BL::Object& b_ob,
+ bool motion,
+ int time_index)
{
if(!motion) {
/* Clear stored curve data */
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 7135e938afb..1f0aa5eef34 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -18,6 +18,7 @@
#include "mesh.h"
#include "object.h"
#include "scene.h"
+#include "camera.h"
#include "blender_sync.h"
#include "blender_session.h"
@@ -35,10 +36,54 @@
CCL_NAMESPACE_BEGIN
+/* Per-face bit flags. */
+enum {
+ /* Face has no special flags. */
+ FACE_FLAG_NONE = (0 << 0),
+ /* Quad face was split using 1-3 diagonal. */
+ FACE_FLAG_DIVIDE_13 = (1 << 0),
+ /* Quad face was split using 2-4 diagonal. */
+ FACE_FLAG_DIVIDE_24 = (1 << 1),
+};
+
+/* Get vertex indices to create triangles from a given face.
+ *
+ * Two triangles has vertex indices in the original Blender-side face.
+ * If face is already a quad tri_b will not be initialized.
+ */
+inline void face_split_tri_indices(const int num_verts,
+ const int face_flag,
+ int tri_a[3],
+ int tri_b[3])
+{
+ if(face_flag & FACE_FLAG_DIVIDE_24) {
+ tri_a[0] = 0;
+ tri_a[1] = 1;
+ tri_a[2] = 3;
+ if(num_verts == 4) {
+ tri_b[0] = 2;
+ tri_b[1] = 3;
+ tri_b[2] = 1;
+ }
+ }
+ else /*if(face_flag & FACE_FLAG_DIVIDE_13)*/ {
+ tri_a[0] = 0;
+ tri_a[1] = 1;
+ tri_a[2] = 2;
+ if(num_verts == 4) {
+ tri_b[0] = 0;
+ tri_b[1] = 2;
+ tri_b[2] = 3;
+ }
+ }
+}
+
/* Tangent Space */
struct MikkUserData {
- MikkUserData(const BL::Mesh mesh_, BL::MeshTextureFaceLayer *layer_, int num_faces_)
+ MikkUserData(const BL::Mesh& mesh_,
+ BL::MeshTextureFaceLayer *layer_,
+ int num_faces_)
: mesh(mesh_), layer(layer_), num_faces(num_faces_)
{
tangent.resize(num_faces*4);
@@ -85,7 +130,7 @@ static void mikk_get_texture_coordinate(const SMikkTSpaceContext *context, float
BL::MeshTextureFace tf = userdata->layer->data[face_num];
float3 tfuv;
- switch (vert_num) {
+ switch(vert_num) {
case 0:
tfuv = get_float3(tf.uv1());
break;
@@ -140,7 +185,13 @@ static void mikk_set_tangent_space(const SMikkTSpaceContext *context, const floa
userdata->tangent[face*4 + vert] = make_float4(T[0], T[1], T[2], sign);
}
-static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_layer, Mesh *mesh, const vector<int>& nverts, bool need_sign, bool active_render)
+static void mikk_compute_tangents(BL::Mesh& b_mesh,
+ BL::MeshTextureFaceLayer *b_layer,
+ Mesh *mesh,
+ const vector<int>& nverts,
+ const vector<int>& face_flags,
+ bool need_sign,
+ bool active_render)
{
/* setup userdata */
MikkUserData userdata(b_mesh, b_layer, nverts.size());
@@ -199,28 +250,31 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_l
}
for(int i = 0; i < nverts.size(); i++) {
- tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]);
- tangent[1] = float4_to_float3(userdata.tangent[i*4 + 1]);
- tangent[2] = float4_to_float3(userdata.tangent[i*4 + 2]);
+ int tri_a[3], tri_b[3];
+ face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+
+ tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_a[0]]);
+ tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_a[1]]);
+ tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_a[2]]);
tangent += 3;
if(tangent_sign) {
- tangent_sign[0] = userdata.tangent[i*4 + 0].w;
- tangent_sign[1] = userdata.tangent[i*4 + 1].w;
- tangent_sign[2] = userdata.tangent[i*4 + 2].w;
+ tangent_sign[0] = userdata.tangent[i*4 + tri_a[0]].w;
+ tangent_sign[1] = userdata.tangent[i*4 + tri_a[1]].w;
+ tangent_sign[2] = userdata.tangent[i*4 + tri_a[2]].w;
tangent_sign += 3;
}
if(nverts[i] == 4) {
- tangent[0] = float4_to_float3(userdata.tangent[i*4 + 0]);
- tangent[1] = float4_to_float3(userdata.tangent[i*4 + 2]);
- tangent[2] = float4_to_float3(userdata.tangent[i*4 + 3]);
+ tangent[0] = float4_to_float3(userdata.tangent[i*4 + tri_b[0]]);
+ tangent[1] = float4_to_float3(userdata.tangent[i*4 + tri_b[1]]);
+ tangent[2] = float4_to_float3(userdata.tangent[i*4 + tri_b[2]]);
tangent += 3;
if(tangent_sign) {
- tangent_sign[0] = userdata.tangent[i*4 + 0].w;
- tangent_sign[1] = userdata.tangent[i*4 + 2].w;
- tangent_sign[2] = userdata.tangent[i*4 + 3].w;
+ tangent_sign[0] = userdata.tangent[i*4 + tri_b[0]].w;
+ tangent_sign[1] = userdata.tangent[i*4 + tri_b[1]].w;
+ tangent_sign[2] = userdata.tangent[i*4 + tri_b[2]].w;
tangent_sign += 3;
}
}
@@ -229,7 +283,11 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_l
/* Create Volume Attribute */
-static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
+static void create_mesh_volume_attribute(BL::Object& b_ob,
+ Mesh *mesh,
+ ImageManager *image_manager,
+ AttributeStandard std,
+ float frame)
{
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
@@ -250,11 +308,14 @@ static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManag
is_float,
is_linear,
INTERPOLATION_LINEAR,
- EXTENSION_REPEAT,
+ EXTENSION_CLIP,
true);
}
-static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame)
+static void create_mesh_volume_attributes(Scene *scene,
+ BL::Object& b_ob,
+ Mesh *mesh,
+ float frame)
{
/* for smoke volume rendering */
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
@@ -272,8 +333,9 @@ static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *m
/* Create vertex color attributes. */
static void attr_create_vertex_color(Scene *scene,
Mesh *mesh,
- BL::Mesh b_mesh,
- const vector<int>& nverts)
+ BL::Mesh& b_mesh,
+ const vector<int>& nverts,
+ const vector<int>& face_flags)
{
BL::Mesh::tessface_vertex_colors_iterator l;
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
@@ -288,14 +350,25 @@ static void attr_create_vertex_color(Scene *scene,
size_t i = 0;
for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
- cdata[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1())));
- cdata[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2())));
- cdata[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
+ int tri_a[3], tri_b[3];
+ face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+ uchar4 colors[4];
+ colors[0] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color1())));
+ colors[1] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color2())));
+ colors[2] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color3())));
if(nverts[i] == 4) {
- cdata[3] = cdata[0];
- cdata[4] = cdata[2];
- cdata[5] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
+ colors[3] = color_float_to_byte(color_srgb_to_scene_linear(get_float3(c->color4())));
+ }
+
+ cdata[0] = colors[tri_a[0]];
+ cdata[1] = colors[tri_a[1]];
+ cdata[2] = colors[tri_a[2]];
+
+ if(nverts[i] == 4) {
+ cdata[3] = colors[tri_b[0]];
+ cdata[4] = colors[tri_b[1]];
+ cdata[5] = colors[tri_b[2]];
cdata += 6;
}
else
@@ -307,8 +380,9 @@ static void attr_create_vertex_color(Scene *scene,
/* Create uv map attributes. */
static void attr_create_uv_map(Scene *scene,
Mesh *mesh,
- BL::Mesh b_mesh,
- const vector<int>& nverts)
+ BL::Mesh& b_mesh,
+ const vector<int>& nverts,
+ const vector<int>& face_flags)
{
if(b_mesh.tessface_uv_textures.length() != 0) {
BL::Mesh::tessface_uv_textures_iterator l;
@@ -332,15 +406,26 @@ static void attr_create_uv_map(Scene *scene,
size_t i = 0;
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
- fdata[0] = get_float3(t->uv1());
- fdata[1] = get_float3(t->uv2());
- fdata[2] = get_float3(t->uv3());
+ int tri_a[3], tri_b[3];
+ face_split_tri_indices(nverts[i], face_flags[i], tri_a, tri_b);
+
+ float3 uvs[4];
+ uvs[0] = get_float3(t->uv1());
+ uvs[1] = get_float3(t->uv2());
+ uvs[2] = get_float3(t->uv3());
+ if(nverts[i] == 4) {
+ uvs[3] = get_float3(t->uv4());
+ }
+
+ fdata[0] = uvs[tri_a[0]];
+ fdata[1] = uvs[tri_a[1]];
+ fdata[2] = uvs[tri_a[2]];
fdata += 3;
if(nverts[i] == 4) {
- fdata[0] = get_float3(t->uv1());
- fdata[1] = get_float3(t->uv3());
- fdata[2] = get_float3(t->uv4());
+ fdata[0] = uvs[tri_b[0]];
+ fdata[1] = uvs[tri_b[1]];
+ fdata[2] = uvs[tri_b[2]];
fdata += 3;
}
}
@@ -355,20 +440,32 @@ static void attr_create_uv_map(Scene *scene,
name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std));
- mikk_compute_tangents(b_mesh, &(*l), mesh, nverts, need_sign, active_render);
+ mikk_compute_tangents(b_mesh,
+ &(*l),
+ mesh,
+ nverts,
+ face_flags,
+ need_sign,
+ active_render);
}
}
}
else if(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)) {
bool need_sign = mesh->need_attribute(scene, ATTR_STD_UV_TANGENT_SIGN);
- mikk_compute_tangents(b_mesh, NULL, mesh, nverts, need_sign, true);
+ mikk_compute_tangents(b_mesh,
+ NULL,
+ mesh,
+ nverts,
+ face_flags,
+ need_sign,
+ true);
}
}
/* Create vertex pointiness attributes. */
static void attr_create_pointiness(Scene *scene,
Mesh *mesh,
- BL::Mesh b_mesh)
+ BL::Mesh& b_mesh)
{
if(mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
const int numverts = b_mesh.vertices.length();
@@ -432,7 +529,10 @@ static void attr_create_pointiness(Scene *scene,
/* Create Mesh */
-static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
+static void create_mesh(Scene *scene,
+ Mesh *mesh,
+ BL::Mesh& b_mesh,
+ const vector<uint>& used_shaders)
{
/* count vertices and faces */
int numverts = b_mesh.vertices.length();
@@ -482,6 +582,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* create faces */
vector<int> nverts(numfaces);
+ vector<int> face_flags(numfaces, FACE_FLAG_NONE);
int fi = 0, ti = 0;
for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
@@ -517,16 +618,19 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
{
- mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
- mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
+ // TODO(mai): order here is probably wrong
+ mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth, true);
+ mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth, true);
+ face_flags[fi] |= FACE_FLAG_DIVIDE_24;
}
else {
- mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
- mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth);
+ mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, true);
+ mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth, true);
+ face_flags[fi] |= FACE_FLAG_DIVIDE_13;
}
}
else
- mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
+ mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth, false);
nverts[fi] = n;
}
@@ -534,8 +638,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
/* Create all needed attributes.
* The calculate functions will check whether they're needed or not.
*/
- attr_create_vertex_color(scene, mesh, b_mesh, nverts);
- attr_create_uv_map(scene, mesh, b_mesh, nverts);
+ attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags);
+ attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags);
/* for volume objects, create a matrix to transform from object space to
* mesh texture space. this does not work with deformations but that can
@@ -551,51 +655,36 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
}
}
-static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
+static void create_subd_mesh(Scene *scene,
+ Mesh *mesh,
+ BL::Object b_ob,
+ BL::Mesh& b_mesh,
+ PointerRNA *cmesh,
+ const vector<uint>& used_shaders,
+ float dicing_rate,
+ int max_subdivisions)
{
- /* create subd mesh */
- SubdMesh sdmesh;
-
- /* create vertices */
- BL::Mesh::vertices_iterator v;
+ Mesh basemesh;
+ create_mesh(scene, &basemesh, b_mesh, used_shaders);
- for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
- sdmesh.add_vert(get_float3(v->co()));
-
- /* create faces */
- BL::Mesh::tessfaces_iterator f;
+ SubdParams sdparams(mesh, used_shaders[0], true, false);
+ sdparams.dicing_rate = max(0.1f, RNA_float_get(cmesh, "dicing_rate") * dicing_rate);
+ sdparams.max_level = max_subdivisions;
- for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
- int4 vi = get_int4(f->vertices_raw());
- int n = (vi[3] == 0) ? 3: 4;
- //int shader = used_shaders[f->material_index()];
-
- if(n == 4)
- sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
- else
- sdmesh.add_face(vi[0], vi[1], vi[2]);
- }
-
- /* finalize subd mesh */
- sdmesh.finish();
-
- /* parameters */
- bool need_ptex = mesh->need_attribute(scene, ATTR_STD_PTEX_FACE_ID) ||
- mesh->need_attribute(scene, ATTR_STD_PTEX_UV);
-
- SubdParams sdparams(mesh, used_shaders[0], true, need_ptex);
- sdparams.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
- //scene->camera->update();
- //sdparams.camera = scene->camera;
+ scene->camera->update();
+ sdparams.camera = scene->camera;
+ sdparams.objecttoworld = get_transform(b_ob.matrix_world());
/* tesselate */
DiagSplit dsplit(sdparams);
- sdmesh.tessellate(&dsplit);
+ basemesh.tessellate(&dsplit);
}
/* Sync */
-Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
+Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
+ bool object_updated,
+ bool hide_tris)
{
/* When viewport display is not needed during render we can force some
* caches to be releases from blender side in order to reduce peak memory
@@ -615,10 +704,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
BL::Object::material_slots_iterator slot;
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
- if(material_override)
+ if(material_override) {
find_shader(material_override, used_shaders, scene->default_surface);
- else
- find_shader(slot->material(), used_shaders, scene->default_surface);
+ }
+ else {
+ BL::ID b_material(slot->material());
+ find_shader(b_material, used_shaders, scene->default_surface);
+ }
}
if(used_shaders.size() == 0) {
@@ -693,8 +785,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
if(b_mesh) {
if(render_layer.use_surfaces && !hide_tris) {
- if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision"))
- create_subd_mesh(scene, mesh, b_mesh, &cmesh, used_shaders);
+ if(cmesh.data && experimental && RNA_enum_get(&cmesh, "subdivision_type"))
+ create_subd_mesh(scene, mesh, b_ob, b_mesh, &cmesh, used_shaders,
+ dicing_rate, max_subdivisions);
else
create_mesh(scene, mesh, b_mesh, used_shaders);
@@ -716,7 +809,10 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
/* displacement method */
if(cmesh.data) {
- const int method = RNA_enum_get(&cmesh, "displacement_method");
+ const int method = get_enum(cmesh,
+ "displacement_method",
+ Mesh::DISPLACE_NUM_METHODS,
+ Mesh::DISPLACE_BUMP);
if(method == 0 || !experimental)
mesh->displacement_method = Mesh::DISPLACE_BUMP;
@@ -748,7 +844,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tri
return mesh;
}
-void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
+void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
+ Object *object,
+ float motion_time)
{
/* ensure we only sync instanced meshes once */
Mesh *mesh = object->mesh;
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 432c4aaa078..5c0c30f28de 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -36,7 +36,7 @@ CCL_NAMESPACE_BEGIN
/* Utilities */
-bool BlenderSync::BKE_object_is_modified(BL::Object b_ob)
+bool BlenderSync::BKE_object_is_modified(BL::Object& b_ob)
{
/* test if we can instance or if the object is modified */
if(b_ob.type() == BL::Object::type_META) {
@@ -58,7 +58,7 @@ bool BlenderSync::BKE_object_is_modified(BL::Object b_ob)
return false;
}
-bool BlenderSync::object_is_mesh(BL::Object b_ob)
+bool BlenderSync::object_is_mesh(BL::Object& b_ob)
{
BL::ID b_ob_data = b_ob.data();
@@ -66,14 +66,14 @@ bool BlenderSync::object_is_mesh(BL::Object b_ob)
b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
}
-bool BlenderSync::object_is_light(BL::Object b_ob)
+bool BlenderSync::object_is_light(BL::Object& b_ob)
{
BL::ID b_ob_data = b_ob.data();
return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
}
-static uint object_ray_visibility(BL::Object b_ob)
+static uint object_ray_visibility(BL::Object& b_ob)
{
PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
uint flag = 0;
@@ -90,7 +90,11 @@ static uint object_ray_visibility(BL::Object b_ob)
/* Light */
-void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm, bool *use_portal)
+void BlenderSync::sync_light(BL::Object& b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BL::Object& b_ob,
+ Transform& tfm,
+ bool *use_portal)
{
/* test if we need to sync */
Light *light;
@@ -208,8 +212,8 @@ void BlenderSync::sync_background_light(bool use_portal)
ObjectKey key(b_world, 0, b_world);
if(light_map.sync(&light, b_world, b_world, key) ||
- world_recalc ||
- b_world.ptr.data != world_map)
+ world_recalc ||
+ b_world.ptr.data != world_map)
{
light->type = LIGHT_BACKGROUND;
light->map_resolution = get_int(cworld, "sample_map_resolution");
@@ -239,7 +243,7 @@ void BlenderSync::sync_background_light(bool use_portal)
* to reduce number of objects which are wrongly considered visible.
*/
static bool object_boundbox_clip(Scene *scene,
- BL::Object b_ob,
+ BL::Object& b_ob,
Transform& tfm,
float margin)
{
@@ -275,9 +279,9 @@ static bool object_boundbox_clip(Scene *scene,
return true;
}
-Object *BlenderSync::sync_object(BL::Object b_parent,
+Object *BlenderSync::sync_object(BL::Object& b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BL::DupliObject b_dupli_ob,
+ BL::DupliObject& b_dupli_ob,
Transform& tfm,
uint layer_flag,
float motion_time,
@@ -439,7 +443,8 @@ Object *BlenderSync::sync_object(BL::Object b_parent,
return object;
}
-static bool object_render_hide_original(BL::Object::type_enum ob_type, BL::Object::dupli_type_enum dupli_type)
+static bool object_render_hide_original(BL::Object::type_enum ob_type,
+ BL::Object::dupli_type_enum dupli_type)
{
/* metaball exception, they duplicate self */
if(ob_type == BL::Object::type_META)
@@ -450,7 +455,10 @@ static bool object_render_hide_original(BL::Object::type_enum ob_type, BL::Objec
dupli_type == BL::Object::dupli_type_FRAMES);
}
-static bool object_render_hide(BL::Object b_ob, bool top_level, bool parent_hide, bool& hide_triangles)
+static bool object_render_hide(BL::Object& b_ob,
+ bool top_level,
+ bool parent_hide,
+ bool& hide_triangles)
{
/* check if we should render or hide particle emitter */
BL::Object::particle_systems_iterator b_psys;
@@ -507,7 +515,7 @@ static bool object_render_hide(BL::Object b_ob, bool top_level, bool parent_hide
}
}
-static bool object_render_hide_duplis(BL::Object b_ob)
+static bool object_render_hide_duplis(BL::Object& b_ob)
{
BL::Object parent = b_ob.parent();
@@ -516,7 +524,7 @@ static bool object_render_hide_duplis(BL::Object b_ob)
/* Object Loop */
-void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
+void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
{
/* layer data */
uint scene_layer = render_layer.scene_layer;
@@ -558,11 +566,20 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
bool cancel = false;
bool use_portal = false;
+ uint layer_override = get_layer(b_engine.layer_override());
for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
+ /* Render layer's scene_layer is affected by local view already,
+ * which is not a desired behavior here.
+ */
+ uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers());
for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) {
BL::Object b_ob = b_base->object();
bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render();
- uint ob_layer = get_layer(b_base->layers(), b_base->layers_local_view(), render_layer.use_localview, object_is_light(b_ob));
+ uint ob_layer = get_layer(b_base->layers(),
+ b_base->layers_local_view(),
+ render_layer.use_localview,
+ object_is_light(b_ob),
+ scene_layers);
hide = hide || !(ob_layer & scene_layer);
if(!hide) {
@@ -622,9 +639,10 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
if(!object_render_hide(b_ob, true, true, hide_tris)) {
/* object itself */
Transform tfm = get_transform(b_ob.matrix_world());
+ BL::DupliObject b_empty_dupli_ob(PointerRNA_NULL);
sync_object(b_ob,
NULL,
- PointerRNA_NULL,
+ b_empty_dupli_ob,
tfm,
ob_layer,
motion_time,
@@ -659,9 +677,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
mesh_motion_synced.clear();
}
-void BlenderSync::sync_motion(BL::RenderSettings b_render,
- BL::SpaceView3D b_v3d,
- BL::Object b_override,
+void BlenderSync::sync_motion(BL::RenderSettings& b_render,
+ BL::SpaceView3D& b_v3d,
+ BL::Object& b_override,
int width, int height,
void **python_thread_state)
{
@@ -676,6 +694,28 @@ void BlenderSync::sync_motion(BL::RenderSettings b_render,
Camera prevcam = *(scene->camera);
int frame_center = b_scene.frame_current();
+ float frame_center_delta = 0.0f;
+
+ if(scene->need_motion() != Scene::MOTION_PASS &&
+ scene->camera->motion_position != Camera::MOTION_POSITION_CENTER)
+ {
+ float shuttertime = scene->camera->shuttertime;
+ if(scene->camera->motion_position == Camera::MOTION_POSITION_END) {
+ frame_center_delta = -shuttertime * 0.5f;
+ }
+ else {
+ assert(scene->camera->motion_position == Camera::MOTION_POSITION_START);
+ frame_center_delta = shuttertime * 0.5f;
+ }
+ float time = frame_center + frame_center_delta;
+ int frame = (int)floorf(time);
+ float subframe = time - frame;
+ python_thread_state_restore(python_thread_state);
+ b_engine.frame_set(frame, subframe);
+ python_thread_state_save(python_thread_state);
+ sync_camera_motion(b_render, b_cam, width, height, 0.0f);
+ sync_objects(b_v3d, 0.0f);
+ }
/* always sample these times for camera motion */
motion_times.insert(-1.0f);
@@ -695,7 +735,7 @@ void BlenderSync::sync_motion(BL::RenderSettings b_render,
shuttertime = scene->camera->shuttertime;
/* compute frame and subframe time */
- float time = frame_center + relative_time * shuttertime * 0.5f;
+ float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f;
int frame = (int)floorf(time);
float subframe = time - frame;
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
index 6d799e6e10e..d1e702cfdc2 100644
--- a/intern/cycles/blender/blender_particles.cpp
+++ b/intern/cycles/blender/blender_particles.cpp
@@ -27,7 +27,9 @@ CCL_NAMESPACE_BEGIN
/* Utilities */
-bool BlenderSync::sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Object *object)
+bool BlenderSync::sync_dupli_particle(BL::Object& b_ob,
+ BL::DupliObject& b_dup,
+ Object *object)
{
/* test if this dupli was generated from a particle sytem */
BL::ParticleSystem b_psys = b_dup.particle_system();
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 6581d0b997e..ceb9cbf242e 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -37,13 +37,94 @@
CCL_NAMESPACE_BEGIN
-static void *pylong_as_voidptr_typesafe(PyObject *object)
+namespace {
+
+/* Device list stored static (used by compute_device_list()). */
+static ccl::vector<CCLDeviceInfo> device_list;
+static ccl::DeviceType device_type = DEVICE_NONE;
+
+/* Flag describing whether debug flags were synchronized from scene. */
+bool debug_flags_set = false;
+
+void *pylong_as_voidptr_typesafe(PyObject *object)
{
if(object == Py_None)
return NULL;
return PyLong_AsVoidPtr(object);
}
+/* Synchronize debug flags from a given Blender scene.
+ * Return truth when device list needs invalidation.
+ */
+bool debug_flags_sync_from_scene(BL::Scene b_scene)
+{
+ DebugFlagsRef flags = DebugFlags();
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ /* Backup some settings for comparison. */
+ DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
+ DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type;
+ /* Synchronize CPU flags. */
+ flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
+ flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
+ flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
+ flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
+ flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
+ flags.cpu.qbvh = get_boolean(cscene, "debug_use_qbvh");
+ /* Synchronize OpenCL kernel type. */
+ switch(get_enum(cscene, "debug_opencl_kernel_type")) {
+ case 0:
+ flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_DEFAULT;
+ break;
+ case 1:
+ flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_MEGA;
+ break;
+ case 2:
+ flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_SPLIT;
+ break;
+ }
+ /* Synchronize OpenCL device type. */
+ switch(get_enum(cscene, "debug_opencl_device_type")) {
+ case 0:
+ flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
+ break;
+ case 1:
+ flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL;
+ break;
+ case 2:
+ flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
+ break;
+ case 3:
+ flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU;
+ break;
+ case 4:
+ flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU;
+ break;
+ case 5:
+ flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
+ break;
+ }
+ /* Synchronize other OpenCL flags. */
+ flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug");
+ return flags.opencl.device_type != opencl_device_type ||
+ flags.opencl.kernel_type != opencl_kernel_type;
+}
+
+/* Reset debug flags to default values.
+ * Return truth when device list needs invalidation.
+ */
+bool debug_flags_reset()
+{
+ DebugFlagsRef flags = DebugFlags();
+ /* Backup some settings for comparison. */
+ DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
+ DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type;
+ flags.reset();
+ return flags.opencl.device_type != opencl_device_type ||
+ flags.opencl.kernel_type != opencl_kernel_type;
+}
+
+} /* namespace */
+
void python_thread_state_save(void **python_thread_state)
{
*python_thread_state = (void*)PyEval_SaveThread();
@@ -57,19 +138,29 @@ void python_thread_state_restore(void **python_thread_state)
static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
{
-#ifdef WIN32
- /* bug [#31856] oddly enough, Python3.2 --> 3.3 on Windows will throw an
- * exception here this needs to be fixed in python:
- * see: bugs.python.org/issue15859 */
- if(!PyUnicode_Check(py_str)) {
- PyErr_BadArgument();
- return "";
+ const char *result = _PyUnicode_AsString(py_str);
+ if(result) {
+ /* 99% of the time this is enough but we better support non unicode
+ * chars since blender doesnt limit this.
+ */
+ return result;
}
-#endif
- if((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
- return PyBytes_AS_STRING(*coerce);
+ else {
+ PyErr_Clear();
+ if(PyBytes_Check(py_str)) {
+ return PyBytes_AS_STRING(py_str);
+ }
+ else if((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
+ return PyBytes_AS_STRING(*coerce);
+ }
+ else {
+ /* Clear the error, so Cycles can be at leadt used without
+ * GPU and OSL support,
+ */
+ PyErr_Clear();
+ return "";
+ }
}
- return "";
}
static PyObject *init_func(PyObject * /*self*/, PyObject *args)
@@ -89,6 +180,19 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args)
BlenderSession::headless = headless;
+ VLOG(2) << "Debug flags initialized to:\n"
+ << DebugFlags();
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ ShaderManager::free_memory();
+ TaskScheduler::free_memory();
+ Device::free_memory();
+ device_list.free_memory();
Py_RETURN_NONE;
}
@@ -190,9 +294,9 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
PyObject *pysession, *pyobject;
PyObject *pypixel_array, *pyresult;
const char *pass_type;
- int num_pixels, depth, object_id;
+ int num_pixels, depth, object_id, pass_filter;
- if(!PyArg_ParseTuple(args, "OOsiOiiO", &pysession, &pyobject, &pass_type, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
+ if(!PyArg_ParseTuple(args, "OOsiiOiiO", &pysession, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
return NULL;
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
@@ -209,7 +313,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
python_thread_state_save(&session->python_thread_state);
- session->bake(b_object, pass_type, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
+ session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
python_thread_state_restore(&session->python_thread_state);
@@ -491,17 +595,87 @@ static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/)
{
VLOG(2) << "Disabling OpenCL platform.";
-#ifdef WIN32
- putenv("CYCLES_OPENCL_TEST=NONE");
-#else
- setenv("CYCLES_OPENCL_TEST", "NONE", 1);
-#endif
+ DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
Py_RETURN_NONE;
}
#endif
+static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
+{
+ PyObject *pyscene;
+ if(!PyArg_ParseTuple(args, "O", &pyscene)) {
+ return NULL;
+ }
+
+ PointerRNA sceneptr;
+ RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
+ BL::Scene b_scene(sceneptr);
+
+ if(debug_flags_sync_from_scene(b_scene)) {
+ VLOG(2) << "Tagging device list for update.";
+ Device::tag_update();
+ }
+
+ VLOG(2) << "Debug flags set to:\n"
+ << DebugFlags();
+
+ debug_flags_set = true;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
+{
+ if(debug_flags_reset()) {
+ VLOG(2) << "Tagging device list for update.";
+ Device::tag_update();
+ }
+ if(debug_flags_set) {
+ VLOG(2) << "Debug flags reset to:\n"
+ << DebugFlags();
+ debug_flags_set = false;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *set_resumable_chunks_func(PyObject * /*self*/, PyObject *args)
+{
+ int num_resumable_chunks, current_resumable_chunk;
+ if(!PyArg_ParseTuple(args, "ii",
+ &num_resumable_chunks,
+ &current_resumable_chunk)) {
+ Py_RETURN_NONE;
+ }
+
+ if(num_resumable_chunks <= 0) {
+ fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
+ abort();
+ Py_RETURN_NONE;
+ }
+ if(current_resumable_chunk < 1 ||
+ current_resumable_chunk > num_resumable_chunks)
+ {
+ fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n");
+ abort();
+ Py_RETURN_NONE;
+ }
+
+ VLOG(1) << "Initialized resumable render: "
+ << "num_resumable_chunks=" << num_resumable_chunks << ", "
+ << "current_resumable_chunk=" << current_resumable_chunk;
+ BlenderSession::num_resumable_chunks = num_resumable_chunks;
+ BlenderSession::current_resumable_chunk = current_resumable_chunk;
+
+ printf("Cycles: Will render chunk %d of %d\n",
+ current_resumable_chunk,
+ num_resumable_chunks);
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef methods[] = {
{"init", init_func, METH_VARARGS, ""},
+ {"exit", exit_func, METH_VARARGS, ""},
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_O, ""},
{"render", render_func, METH_O, ""},
@@ -518,6 +692,14 @@ static PyMethodDef methods[] = {
#ifdef WITH_OPENCL
{"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
#endif
+
+ /* Debugging routines */
+ {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
+ {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
+
+ /* Resumable render */
+ {"set_resumable_chunks", set_resumable_chunks_func, METH_VARARGS, ""},
+
{NULL, NULL, 0, NULL},
};
@@ -532,10 +714,6 @@ static struct PyModuleDef module = {
static CCLDeviceInfo *compute_device_list(DeviceType type)
{
- /* device list stored static */
- static ccl::vector<CCLDeviceInfo> device_list;
- static ccl::DeviceType device_type = DEVICE_NONE;
-
/* create device list if it's not already done */
if(type != device_type) {
ccl::vector<DeviceInfo>& devices = ccl::Device::available_devices();
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 04d05ee7b3c..7a5243d3234 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -43,11 +43,21 @@
CCL_NAMESPACE_BEGIN
bool BlenderSession::headless = false;
-
-BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
- BL::BlendData b_data_, BL::Scene b_scene_)
-: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_render(b_engine_.render()), b_scene(b_scene_),
- b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL), python_thread_state(NULL)
+int BlenderSession::num_resumable_chunks = 0;
+int BlenderSession::current_resumable_chunk = 0;
+
+BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
+ BL::UserPreferences& b_userpref,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene)
+: b_engine(b_engine),
+ b_userpref(b_userpref),
+ b_data(b_data),
+ b_render(b_engine.render()),
+ b_scene(b_scene),
+ b_v3d(PointerRNA_NULL),
+ b_rv3d(PointerRNA_NULL),
+ python_thread_state(NULL)
{
/* offline render */
@@ -59,16 +69,26 @@ BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b
start_resize_time = 0.0;
}
-BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
- BL::BlendData b_data_, BL::Scene b_scene_,
- BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
-: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_render(b_scene_.render()), b_scene(b_scene_),
- b_v3d(b_v3d_), b_rv3d(b_rv3d_), python_thread_state(NULL)
+BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
+ BL::UserPreferences& b_userpref,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height)
+: b_engine(b_engine),
+ b_userpref(b_userpref),
+ b_data(b_data),
+ b_render(b_scene.render()),
+ b_scene(b_scene),
+ b_v3d(b_v3d),
+ b_rv3d(b_rv3d),
+ width(width),
+ height(height),
+ python_thread_state(NULL)
{
/* 3d view render */
- width = width_;
- height = height_;
background = false;
last_redraw_time = 0.0;
start_resize_time = 0.0;
@@ -117,14 +137,14 @@ void BlenderSession::create_session()
/* create sync */
sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu);
-
+ BL::Object b_camera_override(b_engine.camera_override());
if(b_v3d) {
if(session_pause == false) {
/* full data sync */
sync->sync_view(b_v3d, b_rv3d, width, height);
sync->sync_data(b_render,
b_v3d,
- b_engine.camera_override(),
+ b_camera_override,
width, height,
&python_thread_state,
b_rlay_name.c_str());
@@ -135,7 +155,7 @@ void BlenderSession::create_session()
* do some basic syncing here, no objects or materials for speed */
sync->sync_render_layers(b_v3d, NULL);
sync->sync_integrator();
- sync->sync_camera(b_render, b_engine.camera_override(), width, height);
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
}
/* set buffer parameters */
@@ -143,9 +163,11 @@ void BlenderSession::create_session()
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
+
+ update_resumable_tile_manager(session_params.samples);
}
-void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
+void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_)
{
b_data = b_data_;
b_render = b_engine.render();
@@ -188,11 +210,18 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
/* for final render we will do full data sync per render layer, only
* do some basic syncing here, no objects or materials for speed */
+ BL::Object b_camera_override(b_engine.camera_override());
sync->sync_render_layers(b_v3d, NULL);
sync->sync_integrator();
- sync->sync_camera(b_render, b_engine.camera_override(), width, height);
-
- BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
+
+ BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
+ BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
+ BufferParams buffer_params = BlenderSync::get_buffer_params(b_render,
+ b_null_space_view3d,
+ b_null_region_view3d,
+ scene->camera,
+ width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
@@ -209,7 +238,7 @@ void BlenderSession::free_session()
delete session;
}
-static PassType get_pass_type(BL::RenderPass b_pass)
+static PassType get_pass_type(BL::RenderPass& b_pass)
{
switch(b_pass.type()) {
case BL::RenderPass::type_COMBINED:
@@ -316,22 +345,14 @@ static ShaderEvalType get_shader_type(const string& pass_type)
return SHADER_EVAL_COMBINED;
else if(strcmp(shader_type, "SHADOW")==0)
return SHADER_EVAL_SHADOW;
- else if(strcmp(shader_type, "DIFFUSE_DIRECT")==0)
- return SHADER_EVAL_DIFFUSE_DIRECT;
- else if(strcmp(shader_type, "GLOSSY_DIRECT")==0)
- return SHADER_EVAL_GLOSSY_DIRECT;
- else if(strcmp(shader_type, "TRANSMISSION_DIRECT")==0)
- return SHADER_EVAL_TRANSMISSION_DIRECT;
- else if(strcmp(shader_type, "SUBSURFACE_DIRECT")==0)
- return SHADER_EVAL_SUBSURFACE_DIRECT;
- else if(strcmp(shader_type, "DIFFUSE_INDIRECT")==0)
- return SHADER_EVAL_DIFFUSE_INDIRECT;
- else if(strcmp(shader_type, "GLOSSY_INDIRECT")==0)
- return SHADER_EVAL_GLOSSY_INDIRECT;
- else if(strcmp(shader_type, "TRANSMISSION_INDIRECT")==0)
- return SHADER_EVAL_TRANSMISSION_INDIRECT;
- else if(strcmp(shader_type, "SUBSURFACE_INDIRECT")==0)
- return SHADER_EVAL_SUBSURFACE_INDIRECT;
+ else if(strcmp(shader_type, "DIFFUSE")==0)
+ return SHADER_EVAL_DIFFUSE;
+ else if(strcmp(shader_type, "GLOSSY")==0)
+ return SHADER_EVAL_GLOSSY;
+ else if(strcmp(shader_type, "TRANSMISSION")==0)
+ return SHADER_EVAL_TRANSMISSION;
+ else if(strcmp(shader_type, "SUBSURFACE")==0)
+ return SHADER_EVAL_SUBSURFACE;
/* extra */
else if(strcmp(shader_type, "ENVIRONMENT")==0)
@@ -341,12 +362,19 @@ static ShaderEvalType get_shader_type(const string& pass_type)
return SHADER_EVAL_BAKE;
}
-static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername, const char *viewname)
+static BL::RenderResult begin_render_result(BL::RenderEngine& b_engine,
+ int x, int y,
+ int w, int h,
+ const char *layername,
+ const char *viewname)
{
return b_engine.begin_result(x, y, w, h, layername, viewname);
}
-static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel, bool do_merge_results)
+static void end_render_result(BL::RenderEngine& b_engine,
+ BL::RenderResult& b_rr,
+ bool cancel,
+ bool do_merge_results)
{
b_engine.end_result(b_rr, (int)cancel, (int)do_merge_results);
}
@@ -477,22 +505,30 @@ void BlenderSession::render()
b_engine.active_view_set(b_rview_name.c_str());
/* update scene */
- sync->sync_camera(b_render, b_engine.camera_override(), width, height);
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
sync->sync_data(b_render,
b_v3d,
- b_engine.camera_override(),
+ b_camera_override,
width, height,
&python_thread_state,
b_rlay_name.c_str());
- /* update number of samples per layer */
+ /* Update number of samples per layer. */
int samples = sync->get_layer_samples();
bool bound_samples = sync->get_layer_bound_samples();
+ int effective_layer_samples;
if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
- session->reset(buffer_params, samples);
+ effective_layer_samples = samples;
else
- session->reset(buffer_params, session_params.samples);
+ effective_layer_samples = session_params.samples;
+
+ /* Update tile manager if we're doing resumable render. */
+ update_resumable_tile_manager(effective_layer_samples);
+
+ /* Update session itself. */
+ session->reset(buffer_params, effective_layer_samples);
/* render */
session->start();
@@ -528,7 +564,10 @@ void BlenderSession::render()
sync = NULL;
}
-static void populate_bake_data(BakeData *data, const int object_id, BL::BakePixel pixel_array, const int num_pixels)
+static void populate_bake_data(BakeData *data, const
+ int object_id,
+ BL::BakePixel& pixel_array,
+ const int num_pixels)
{
BL::BakePixel bp = pixel_array;
@@ -543,7 +582,42 @@ static void populate_bake_data(BakeData *data, const int object_id, BL::BakePixe
}
}
-void BlenderSession::bake(BL::Object b_object, const string& pass_type, const int object_id, BL::BakePixel pixel_array, const size_t num_pixels, const int /*depth*/, float result[])
+static int bake_pass_filter_get(const int pass_filter)
+{
+ int flag = BAKE_FILTER_NONE;
+
+ if((pass_filter & BL::BakeSettings::pass_filter_DIRECT) != 0)
+ flag |= BAKE_FILTER_DIRECT;
+ if((pass_filter & BL::BakeSettings::pass_filter_INDIRECT) != 0)
+ flag |= BAKE_FILTER_INDIRECT;
+ if((pass_filter & BL::BakeSettings::pass_filter_COLOR) != 0)
+ flag |= BAKE_FILTER_COLOR;
+
+ if((pass_filter & BL::BakeSettings::pass_filter_DIFFUSE) != 0)
+ flag |= BAKE_FILTER_DIFFUSE;
+ if((pass_filter & BL::BakeSettings::pass_filter_GLOSSY) != 0)
+ flag |= BAKE_FILTER_GLOSSY;
+ if((pass_filter & BL::BakeSettings::pass_filter_TRANSMISSION) != 0)
+ flag |= BAKE_FILTER_TRANSMISSION;
+ if((pass_filter & BL::BakeSettings::pass_filter_SUBSURFACE) != 0)
+ flag |= BAKE_FILTER_SUBSURFACE;
+
+ if((pass_filter & BL::BakeSettings::pass_filter_EMIT) != 0)
+ flag |= BAKE_FILTER_EMISSION;
+ if((pass_filter & BL::BakeSettings::pass_filter_AO) != 0)
+ flag |= BAKE_FILTER_AO;
+
+ return flag;
+}
+
+void BlenderSession::bake(BL::Object& b_object,
+ const string& pass_type,
+ const int pass_filter,
+ const int object_id,
+ BL::BakePixel& pixel_array,
+ const size_t num_pixels,
+ const int /*depth*/,
+ float result[])
{
ShaderEvalType shader_type = get_shader_type(pass_type);
size_t object_index = OBJECT_NONE;
@@ -565,8 +639,11 @@ void BlenderSession::bake(BL::Object b_object, const string& pass_type, const in
Pass::add(PASS_UV, scene->film->passes);
}
- if(BakeManager::is_light_pass(shader_type)) {
- /* force use_light_pass to be true */
+ int bake_pass_filter = bake_pass_filter_get(pass_filter);
+ bake_pass_filter = BakeManager::shader_type_to_pass_filter(shader_type, bake_pass_filter);
+
+ /* force use_light_pass to be true if we bake more than just colors */
+ if(bake_pass_filter & ~BAKE_FILTER_COLOR) {
Pass::add(PASS_LIGHT, scene->film->passes);
}
@@ -575,10 +652,11 @@ void BlenderSession::bake(BL::Object b_object, const string& pass_type, const in
scene->integrator->tag_update(scene);
/* update scene */
- sync->sync_camera(b_render, b_engine.camera_override(), width, height);
+ BL::Object b_camera_override(b_engine.camera_override());
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
sync->sync_data(b_render,
b_v3d,
- b_engine.camera_override(),
+ b_camera_override,
width, height,
&python_thread_state,
b_rlay_name.c_str());
@@ -617,7 +695,7 @@ void BlenderSession::bake(BL::Object b_object, const string& pass_type, const in
session->progress.set_update_callback(function_bind(&BlenderSession::update_bake_progress, this));
- scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_data, result);
+ scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_pass_filter, bake_data, result);
/* free all memory used (host and device), so we wouldn't leave render
* engine with extra memory allocated
@@ -629,7 +707,10 @@ void BlenderSession::bake(BL::Object b_object, const string& pass_type, const in
sync = NULL;
}
-void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only)
+void BlenderSession::do_write_update_render_result(BL::RenderResult& b_rr,
+ BL::RenderLayer& b_rlay,
+ RenderTile& rtile,
+ bool do_update_only)
{
RenderBuffers *buffers = rtile.buffers;
@@ -642,6 +723,13 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
vector<float> pixels(params.width*params.height*4);
+ /* Adjust absolute sample number to the range. */
+ int sample = rtile.sample;
+ const int range_start_sample = session->tile_manager.range_start_sample;
+ if(range_start_sample != -1) {
+ sample -= range_start_sample;
+ }
+
if(!do_update_only) {
/* copy each pass */
BL::RenderLayer::passes_iterator b_iter;
@@ -654,7 +742,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
int components = b_pass.channels();
/* copy pixels */
- if(!buffers->get_pass_rect(pass_type, exposure, rtile.sample, components, &pixels[0]))
+ if(!buffers->get_pass_rect(pass_type, exposure, sample, components, &pixels[0]))
memset(&pixels[0], 0, pixels.size()*sizeof(float));
b_pass.rect(&pixels[0]);
@@ -663,7 +751,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
else {
/* copy combined pass */
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_type(BL::RenderPass::type_COMBINED, b_rview_name.c_str()));
- if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
+ if(buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0]))
b_combined_pass.rect(&pixels[0]);
}
@@ -671,12 +759,16 @@ void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::Re
b_engine.update_result(b_rr);
}
-void BlenderSession::write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
+void BlenderSession::write_render_result(BL::RenderResult& b_rr,
+ BL::RenderLayer& b_rlay,
+ RenderTile& rtile)
{
do_write_update_render_result(b_rr, b_rlay, rtile, false);
}
-void BlenderSession::update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
+void BlenderSession::update_render_result(BL::RenderResult& b_rr,
+ BL::RenderLayer& b_rlay,
+ RenderTile& rtile)
{
do_write_update_render_result(b_rr, b_rlay, rtile, true);
}
@@ -723,9 +815,10 @@ void BlenderSession::synchronize()
}
/* data and camera synchronize */
+ BL::Object b_camera_override(b_engine.camera_override());
sync->sync_data(b_render,
b_v3d,
- b_engine.camera_override(),
+ b_camera_override,
width, height,
&python_thread_state,
b_rlay_name.c_str());
@@ -733,7 +826,7 @@ void BlenderSession::synchronize()
if(b_rv3d)
sync->sync_view(b_v3d, b_rv3d, width, height);
else
- sync->sync_camera(b_render, b_engine.camera_override(), width, height);
+ sync->sync_camera(b_render, b_camera_override, width, height, "");
/* unlock */
session->scene->mutex.unlock();
@@ -834,16 +927,16 @@ void BlenderSession::get_progress(float& progress, double& total_time, double& r
int tile, sample, samples_per_tile;
int tile_total = session->tile_manager.state.num_tiles;
int samples = session->tile_manager.state.sample + 1;
- int total_samples = session->tile_manager.num_samples;
+ int total_samples = session->tile_manager.get_num_effective_samples();
session->progress.get_tile(tile, total_time, render_time, tile_time);
sample = session->progress.get_sample();
- samples_per_tile = session->tile_manager.num_samples;
+ samples_per_tile = session->tile_manager.get_num_effective_samples();
if(background && samples_per_tile && tile_total)
progress = ((float)sample / (float)(tile_total * samples_per_tile));
- else if(!background && samples > 0 && total_samples != USHRT_MAX)
+ else if(!background && samples > 0 && total_samples != INT_MAX)
progress = ((float)samples) / total_samples;
else
progress = 0.0;
@@ -984,8 +1077,8 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti
{
/* empty image */
is_float = false;
- width = 0;
- height = 0;
+ width = 1;
+ height = 1;
depth = 0;
channels = 0;
@@ -1012,25 +1105,37 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti
BL::Object b_ob(b_id);
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
+ is_float = true;
+ depth = 1;
+ channels = 1;
+
if(!b_domain)
return;
if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) ||
- builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME))
+ builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME) ||
+ builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT))
channels = 1;
else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
channels = 4;
+ else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY))
+ channels = 3;
else
return;
int3 resolution = get_int3(b_domain.domain_resolution());
int amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
+ /* Velocity and heat data is always low-resolution. */
+ if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
+ builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT))
+ {
+ amplify = 1;
+ }
+
width = resolution.x * amplify;
height = resolution.y * amplify;
depth = resolution.z * amplify;
-
- is_float = true;
}
else {
/* TODO(sergey): Check we're indeed in shader node tree. */
@@ -1151,6 +1256,13 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
int3 resolution = get_int3(b_domain.domain_resolution());
int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
+ /* Velocity and heat data is always low-resolution. */
+ if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY) ||
+ builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT))
+ {
+ amplify = 1;
+ }
+
int width = resolution.x * amplify;
int height = resolution.y * amplify;
int depth = resolution.z * amplify;
@@ -1158,7 +1270,6 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
-
if(length == num_pixels) {
SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels);
return true;
@@ -1168,7 +1279,6 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
/* this is in range 0..1, and interpreted by the OpenGL smoke viewer
* as 1500..3000 K with the first part faded to zero density */
SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
-
if(length == num_pixels) {
SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
return true;
@@ -1177,12 +1287,32 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
/* the RGB is "premultiplied" by density for better interpolation results */
SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
-
if(length == num_pixels*4) {
SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels);
return true;
}
}
+ else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
+ SmokeDomainSettings_velocity_grid_get_length(&b_domain.ptr, &length);
+ if(length == num_pixels*3) {
+ SmokeDomainSettings_velocity_grid_get(&b_domain.ptr, pixels);
+ return true;
+ }
+ }
+ else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
+ SmokeDomainSettings_heat_grid_get_length(&b_domain.ptr, &length);
+ if(length == num_pixels) {
+ SmokeDomainSettings_heat_grid_get(&b_domain.ptr, pixels);
+ return true;
+ }
+ }
+ else {
+ fprintf(stderr,
+ "Cycles error: unknown volume attribute %s, skipping\n",
+ builtin_name.c_str());
+ pixels[0] = 0.0f;
+ return false;
+ }
fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
}
@@ -1194,12 +1324,34 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
int length;
- b_point_density_node.calc_point_density(b_scene, &length, &pixels);
+ int settings = background ? 1 : 0; /* 1 - render settings, 0 - vewport settings. */
+ b_point_density_node.calc_point_density(b_scene, settings, &length, &pixels);
}
}
return false;
}
-CCL_NAMESPACE_END
+void BlenderSession::update_resumable_tile_manager(int num_samples)
+{
+ const int num_resumable_chunks = BlenderSession::num_resumable_chunks,
+ current_resumable_chunk = BlenderSession::current_resumable_chunk;
+ if(num_resumable_chunks == 0) {
+ return;
+ }
+ int num_samples_per_chunk = (int)ceilf((float)num_samples / num_resumable_chunks);
+ int range_start_sample = num_samples_per_chunk * (current_resumable_chunk - 1);
+ int range_num_samples = num_samples_per_chunk;
+ if(range_start_sample + range_num_samples > num_samples) {
+ range_num_samples = num_samples - range_num_samples;
+ }
+
+ VLOG(1) << "Samples range start is " << range_start_sample << ", "
+ << "number of samples to render is " << range_num_samples;
+
+ session->tile_manager.range_start_sample = range_start_sample;
+ session->tile_manager.range_num_samples = range_num_samples;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index 708776dc8ca..66a6945cbc1 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -33,11 +33,18 @@ class RenderTile;
class BlenderSession {
public:
- BlenderSession(BL::RenderEngine b_engine, BL::UserPreferences b_userpref,
- BL::BlendData b_data, BL::Scene b_scene);
- BlenderSession(BL::RenderEngine b_engine, BL::UserPreferences b_userpref,
- BL::BlendData b_data, BL::Scene b_scene,
- BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
+ BlenderSession(BL::RenderEngine& b_engine,
+ BL::UserPreferences& b_userpref,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene);
+
+ BlenderSession(BL::RenderEngine& b_engine,
+ BL::UserPreferences& b_userpref,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height);
~BlenderSession();
@@ -47,19 +54,31 @@ public:
void create_session();
void free_session();
- void reset_session(BL::BlendData b_data, BL::Scene b_scene);
+ void reset_session(BL::BlendData& b_data,
+ BL::Scene& b_scene);
/* offline render */
void render();
- void bake(BL::Object b_object, const string& pass_type, const int object_id, BL::BakePixel pixel_array, const size_t num_pixels, const int depth, float pixels[]);
-
- void write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile);
+ void bake(BL::Object& b_object,
+ const string& pass_type,
+ const int custom_flag,
+ const int object_id,
+ BL::BakePixel& pixel_array,
+ const size_t num_pixels,
+ const int depth,
+ float pixels[]);
+
+ void write_render_result(BL::RenderResult& b_rr,
+ BL::RenderLayer& b_rlay,
+ RenderTile& rtile);
void write_render_tile(RenderTile& rtile);
/* update functions are used to update display buffer only after sample was rendered
* only needed for better visual feedback */
- void update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile);
+ void update_render_result(BL::RenderResult& b_rr,
+ BL::RenderLayer& b_rlay,
+ RenderTile& rtile);
void update_render_tile(RenderTile& rtile);
/* interactive updates */
@@ -76,7 +95,6 @@ public:
void update_bake_progress();
bool background;
- static bool headless;
Session *session;
Scene *scene;
BlenderSync *sync;
@@ -101,14 +119,38 @@ public:
void *python_thread_state;
+ /* Global state which is common for all render sessions created from Blender.
+ * Usually denotes command line arguments.
+ */
+
+ /* Blender is running from the command line, no windows are shown and some
+ * extra render optimization is possible (possible to free draw-only data and
+ * so on.
+ */
+ static bool headless;
+
+ /* ** Resumable render ** */
+
+ /* Overall number of chunks in which the sample range is to be devided. */
+ static int num_resumable_chunks;
+
+ /* Current resumable chunk index to render. */
+ static int current_resumable_chunk;
+
protected:
- void do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only);
+ void do_write_update_render_result(BL::RenderResult& b_rr,
+ BL::RenderLayer& b_rlay,
+ RenderTile& rtile,
+ bool do_update_only);
void do_write_update_render_tile(RenderTile& rtile, bool do_update_only);
int builtin_image_frame(const string &builtin_name);
void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels);
bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels);
bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels);
+
+ /* Update tile manager to reflect resumable render settings. */
+ void update_resumable_tile_manager(int num_samples);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index 42aab52e294..4f7ca301fb7 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -36,7 +36,9 @@ typedef map<std::string, ProxyNode*> ProxyMap;
/* Find */
-void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader)
+void BlenderSync::find_shader(BL::ID& id,
+ vector<uint>& used_shaders,
+ int default_shader)
{
Shader *shader = (id)? shader_map.find(id): scene->shaders[default_shader];
@@ -49,9 +51,53 @@ void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders, int default
}
}
+/* RNA translation utilities */
+
+static VolumeSampling get_volume_sampling(PointerRNA& ptr)
+{
+ return (VolumeSampling)get_enum(ptr,
+ "volume_sampling",
+ VOLUME_NUM_SAMPLING,
+ VOLUME_SAMPLING_DISTANCE);
+}
+
+static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
+{
+ return (VolumeInterpolation)get_enum(ptr,
+ "volume_interpolation",
+ VOLUME_NUM_INTERPOLATION,
+ VOLUME_INTERPOLATION_LINEAR);
+}
+
+static int validate_enum_value(int value, int num_values, int default_value)
+{
+ if(value >= num_values) {
+ return default_value;
+ }
+ return value;
+}
+
+template<typename NodeType>
+static InterpolationType get_image_interpolation(NodeType& b_node)
+{
+ int value = b_node.interpolation();
+ return (InterpolationType)validate_enum_value(value,
+ INTERPOLATION_NUM_TYPES,
+ INTERPOLATION_LINEAR);
+}
+
+template<typename NodeType>
+static ExtensionType get_image_extension(NodeType& b_node)
+{
+ int value = b_node.extension();
+ return (ExtensionType)validate_enum_value(value,
+ EXTENSION_NUM_TYPES,
+ EXTENSION_REPEAT);
+}
+
/* Graph */
-static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
+static BL::NodeSocket get_node_output(BL::Node& b_node, const string& name)
{
BL::Node::outputs_iterator b_out;
@@ -64,7 +110,7 @@ static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
return *b_out;
}
-static float3 get_node_output_rgba(BL::Node b_node, const string& name)
+static float3 get_node_output_rgba(BL::Node& b_node, const string& name)
{
BL::NodeSocket b_sock = get_node_output(b_node, name);
float value[4];
@@ -72,13 +118,13 @@ static float3 get_node_output_rgba(BL::Node b_node, const string& name)
return make_float3(value[0], value[1], value[2]);
}
-static float get_node_output_value(BL::Node b_node, const string& name)
+static float get_node_output_value(BL::Node& b_node, const string& name)
{
BL::NodeSocket b_sock = get_node_output(b_node, name);
return RNA_float_get(&b_sock.ptr, "default_value");
}
-static float3 get_node_output_vector(BL::Node b_node, const string& name)
+static float3 get_node_output_vector(BL::Node& b_node, const string& name)
{
BL::NodeSocket b_sock = get_node_output(b_node, name);
float value[3];
@@ -86,9 +132,9 @@ static float3 get_node_output_vector(BL::Node b_node, const string& name)
return make_float3(value[0], value[1], value[2]);
}
-static ShaderSocketType convert_socket_type(BL::NodeSocket b_socket)
+static ShaderSocketType convert_socket_type(BL::NodeSocket& b_socket)
{
- switch (b_socket.type()) {
+ switch(b_socket.type()) {
case BL::NodeSocket::type_VALUE:
return SHADER_SOCKET_FLOAT;
case BL::NodeSocket::type_INT:
@@ -107,40 +153,66 @@ static ShaderSocketType convert_socket_type(BL::NodeSocket b_socket)
}
}
-static void set_default_value(ShaderInput *input, BL::NodeSocket b_sock, BL::BlendData b_data, BL::ID b_id)
+#ifdef WITH_OSL
+static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query,
+ BL::NodeSocket& b_socket)
+{
+ ShaderSocketType socket_type = convert_socket_type(b_socket);
+ if(socket_type == SHADER_SOCKET_VECTOR) {
+ /* TODO(sergey): Do we need compatible_name() here? */
+ const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name());
+ assert(param != NULL);
+ if(param != NULL) {
+ if(param->type.vecsemantics == TypeDesc::POINT) {
+ socket_type = SHADER_SOCKET_POINT;
+ }
+ else if(param->type.vecsemantics == TypeDesc::NORMAL) {
+ socket_type = SHADER_SOCKET_NORMAL;
+ }
+ }
+ }
+
+ return socket_type;
+}
+#endif /* WITH_OSL */
+
+static void set_default_value(ShaderInput *input,
+ BL::NodeSocket& b_sock,
+ BL::BlendData& b_data,
+ BL::ID& b_id)
{
/* copy values for non linked inputs */
switch(input->type) {
- case SHADER_SOCKET_FLOAT: {
- input->set(get_float(b_sock.ptr, "default_value"));
- break;
- }
- case SHADER_SOCKET_INT: {
- input->set((float)get_int(b_sock.ptr, "default_value"));
- break;
- }
- case SHADER_SOCKET_COLOR: {
- input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
- break;
- }
- case SHADER_SOCKET_NORMAL:
- case SHADER_SOCKET_POINT:
- case SHADER_SOCKET_VECTOR: {
- input->set(get_float3(b_sock.ptr, "default_value"));
- break;
- }
- case SHADER_SOCKET_STRING: {
- input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
- break;
- }
-
- case SHADER_SOCKET_CLOSURE:
- case SHADER_SOCKET_UNDEFINED:
- break;
+ case SHADER_SOCKET_FLOAT: {
+ input->set(get_float(b_sock.ptr, "default_value"));
+ break;
+ }
+ case SHADER_SOCKET_INT: {
+ input->set((float)get_int(b_sock.ptr, "default_value"));
+ break;
+ }
+ case SHADER_SOCKET_COLOR: {
+ input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
+ break;
+ }
+ case SHADER_SOCKET_NORMAL:
+ case SHADER_SOCKET_POINT:
+ case SHADER_SOCKET_VECTOR: {
+ input->set(get_float3(b_sock.ptr, "default_value"));
+ break;
+ }
+ case SHADER_SOCKET_STRING: {
+ input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
+ break;
+ }
+
+ case SHADER_SOCKET_CLOSURE:
+ case SHADER_SOCKET_UNDEFINED:
+ break;
}
}
-static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
+static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping& b_mapping)
{
if(!b_mapping)
return;
@@ -155,7 +227,8 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
}
-static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping b_mapping)
+static void get_tex_mapping(TextureMapping *mapping,
+ BL::ShaderNodeMapping& b_mapping)
{
if(!b_mapping)
return;
@@ -173,7 +246,7 @@ static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping b_map
mapping->max = get_float3(b_mapping.max());
}
-static bool is_output_node(BL::Node b_node)
+static bool is_output_node(BL::Node& b_node)
{
return (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
|| b_node.is_a(&RNA_ShaderNodeOutputWorld)
@@ -181,33 +254,45 @@ static bool is_output_node(BL::Node b_node)
}
static ShaderNode *add_node(Scene *scene,
- BL::RenderEngine b_engine,
- BL::BlendData b_data,
- BL::Scene b_scene,
+ BL::RenderEngine& b_engine,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ const bool background,
ShaderGraph *graph,
- BL::ShaderNodeTree b_ntree,
- BL::ShaderNode b_node)
+ BL::ShaderNodeTree& b_ntree,
+ BL::ShaderNode& b_node)
{
ShaderNode *node = NULL;
/* existing blender nodes */
if(b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
BL::ShaderNodeRGBCurve b_curve_node(b_node);
+ BL::CurveMapping mapping(b_curve_node.mapping());
RGBCurvesNode *curves = new RGBCurvesNode();
- curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
+ curvemapping_color_to_array(mapping,
+ curves->curves,
+ RAMP_TABLE_SIZE,
+ true);
+ curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x);
node = curves;
}
if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
BL::ShaderNodeVectorCurve b_curve_node(b_node);
+ BL::CurveMapping mapping(b_curve_node.mapping());
VectorCurvesNode *curves = new VectorCurvesNode();
- curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
+ curvemapping_color_to_array(mapping,
+ curves->curves,
+ RAMP_TABLE_SIZE,
+ false);
+ curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x);
node = curves;
}
else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) {
RGBRampNode *ramp = new RGBRampNode();
BL::ShaderNodeValToRGB b_ramp_node(b_node);
- colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
- ramp->interpolate = b_ramp_node.color_ramp().interpolation() != BL::ColorRamp::interpolation_CONSTANT;
+ BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
+ colorramp_to_array(b_color_ramp, ramp->ramp, RAMP_TABLE_SIZE);
+ ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT;
node = ramp;
}
else if(b_node.is_a(&RNA_ShaderNodeRGB)) {
@@ -283,7 +368,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
VectorTransformNode *vtransform = new VectorTransformNode();
- vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.type()];
+ vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.vector_type()];
vtransform->convert_from = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_from()];
vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()];
node = vtransform;
@@ -332,17 +417,16 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();
- switch (b_aniso_node.distribution())
- {
- case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
- aniso->distribution = ustring("Beckmann");
- break;
- case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
- aniso->distribution = ustring("GGX");
- break;
- case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
- aniso->distribution = ustring("Ashikhmin-Shirley");
- break;
+ switch(b_aniso_node.distribution()) {
+ case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
+ aniso->distribution = ustring("Beckmann");
+ break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
+ aniso->distribution = ustring("GGX");
+ break;
+ case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
+ aniso->distribution = ustring("Ashikhmin-Shirley");
+ break;
}
node = aniso;
@@ -356,12 +440,15 @@ static ShaderNode *add_node(Scene *scene,
SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode();
switch(b_subsurface_node.falloff()) {
- case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
- subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
- break;
- case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
- subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
- break;
+ case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
+ subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
+ break;
+ case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
+ subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+ break;
+ case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
+ subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID;
+ break;
}
node = subsurface;
@@ -371,18 +458,18 @@ static ShaderNode *add_node(Scene *scene,
GlossyBsdfNode *glossy = new GlossyBsdfNode();
switch(b_glossy_node.distribution()) {
- case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
- glossy->distribution = ustring("Sharp");
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
- glossy->distribution = ustring("Beckmann");
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_GGX:
- glossy->distribution = ustring("GGX");
- break;
- case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
- glossy->distribution = ustring("Ashikhmin-Shirley");
- break;
+ case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
+ glossy->distribution = ustring("Sharp");
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
+ glossy->distribution = ustring("Beckmann");
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_GGX:
+ glossy->distribution = ustring("GGX");
+ break;
+ case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
+ glossy->distribution = ustring("Ashikhmin-Shirley");
+ break;
}
node = glossy;
}
@@ -390,15 +477,15 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
GlassBsdfNode *glass = new GlassBsdfNode();
switch(b_glass_node.distribution()) {
- case BL::ShaderNodeBsdfGlass::distribution_SHARP:
- glass->distribution = ustring("Sharp");
- break;
- case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
- glass->distribution = ustring("Beckmann");
- break;
- case BL::ShaderNodeBsdfGlass::distribution_GGX:
- glass->distribution = ustring("GGX");
- break;
+ case BL::ShaderNodeBsdfGlass::distribution_SHARP:
+ glass->distribution = ustring("Sharp");
+ break;
+ case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
+ glass->distribution = ustring("Beckmann");
+ break;
+ case BL::ShaderNodeBsdfGlass::distribution_GGX:
+ glass->distribution = ustring("GGX");
+ break;
}
node = glass;
}
@@ -508,6 +595,22 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeScript b_script_node(b_node);
OSLScriptNode *script_node = new OSLScriptNode();
+ OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
+ string bytecode_hash = b_script_node.bytecode_hash();
+
+ /* Gather additional information from the shader, such as
+ * input/output type info needed for proper node construction.
+ */
+ OSL::OSLQuery query;
+
+ if(!bytecode_hash.empty()) {
+ query.open_bytecode(b_script_node.bytecode());
+ }
+ else {
+ OSLShaderManager::osl_query(query, b_script_node.filepath());
+ }
+ /* TODO(sergey): Add proper query info error parsing. */
+
/* Generate inputs/outputs from node sockets
*
* Note: the node sockets are generated from OSL parameters,
@@ -520,7 +623,7 @@ static ShaderNode *add_node(Scene *scene,
for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
script_node->input_names.push_back(ustring(b_input->name()));
ShaderInput *input = script_node->add_input(script_node->input_names.back().c_str(),
- convert_socket_type(*b_input));
+ convert_osl_socket_type(query, *b_input));
set_default_value(input, *b_input, b_data, b_ntree);
}
@@ -529,13 +632,10 @@ static ShaderNode *add_node(Scene *scene,
for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
script_node->output_names.push_back(ustring(b_output->name()));
script_node->add_output(script_node->output_names.back().c_str(),
- convert_socket_type(*b_output));
+ convert_osl_socket_type(query, *b_output));
}
/* load bytecode or filepath */
- OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
- string bytecode_hash = b_script_node.bytecode_hash();
-
if(!bytecode_hash.empty()) {
/* loaded bytecode if not already done */
if(!manager->shader_test_loaded(bytecode_hash))
@@ -558,6 +658,7 @@ static ShaderNode *add_node(Scene *scene,
else if(b_node.is_a(&RNA_ShaderNodeTexImage)) {
BL::ShaderNodeTexImage b_image_node(b_node);
BL::Image b_image(b_image_node.image());
+ BL::ImageUser b_image_user(b_image_node.image_user());
ImageTextureNode *image = new ImageTextureNode();
if(b_image) {
/* builtin images will use callback-based reading because
@@ -576,12 +677,15 @@ static ShaderNode *add_node(Scene *scene,
* builtin names for packed images and movies
*/
int scene_frame = b_scene.frame_current();
- int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
+ int image_frame = image_user_frame_number(b_image_user,
+ scene_frame);
image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
image->builtin_data = b_image.ptr.data;
}
else {
- image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+ image->filename = image_user_file_path(b_image_user,
+ b_image,
+ b_scene.frame_current());
image->builtin_data = NULL;
}
@@ -593,21 +697,23 @@ static ShaderNode *add_node(Scene *scene,
scene->image_manager->tag_reload_image(
image->filename,
image->builtin_data,
- (InterpolationType)b_image_node.interpolation(),
- (ExtensionType)b_image_node.extension());
+ get_image_interpolation(b_image_node),
+ get_image_extension(b_image_node));
}
}
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
- image->interpolation = (InterpolationType)b_image_node.interpolation();
- image->extension = (ExtensionType)b_image_node.extension();
+ image->interpolation = get_image_interpolation(b_image_node);
+ image->extension = get_image_extension(b_image_node);
image->projection_blend = b_image_node.projection_blend();
- get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
+ get_tex_mapping(&image->tex_mapping, b_texture_mapping);
node = image;
}
else if(b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
BL::ShaderNodeTexEnvironment b_env_node(b_node);
BL::Image b_image(b_env_node.image());
+ BL::ImageUser b_image_user(b_env_node.image_user());
EnvironmentTextureNode *env = new EnvironmentTextureNode();
if(b_image) {
bool is_builtin = b_image.packed_file() ||
@@ -617,12 +723,15 @@ static ShaderNode *add_node(Scene *scene,
if(is_builtin) {
int scene_frame = b_scene.frame_current();
- int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
+ int image_frame = image_user_frame_number(b_image_user,
+ scene_frame);
env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
env->builtin_data = b_image.ptr.data;
}
else {
- env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
+ env->filename = image_user_file_path(b_image_user,
+ b_image,
+ b_scene.frame_current());
env->animated = b_env_node.image_user().use_auto_refresh();
env->builtin_data = NULL;
}
@@ -631,49 +740,58 @@ static ShaderNode *add_node(Scene *scene,
/* TODO(sergey): Does not work properly when we change builtin type. */
if(b_image.is_updated()) {
- scene->image_manager->tag_reload_image(env->filename,
- env->builtin_data,
- INTERPOLATION_LINEAR,
- EXTENSION_REPEAT);
+ scene->image_manager->tag_reload_image(
+ env->filename,
+ env->builtin_data,
+ get_image_interpolation(b_env_node),
+ EXTENSION_REPEAT);
}
}
env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+ env->interpolation = get_image_interpolation(b_env_node);
env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
- get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
+ get_tex_mapping(&env->tex_mapping, b_texture_mapping);
node = env;
}
else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
BL::ShaderNodeTexGradient b_gradient_node(b_node);
GradientTextureNode *gradient = new GradientTextureNode();
gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
- get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
+ get_tex_mapping(&gradient->tex_mapping, b_texture_mapping);
node = gradient;
}
else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
- get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
+ get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
node = voronoi;
}
else if(b_node.is_a(&RNA_ShaderNodeTexMagic)) {
BL::ShaderNodeTexMagic b_magic_node(b_node);
MagicTextureNode *magic = new MagicTextureNode();
magic->depth = b_magic_node.turbulence_depth();
- get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
+ get_tex_mapping(&magic->tex_mapping, b_texture_mapping);
node = magic;
}
else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
BL::ShaderNodeTexWave b_wave_node(b_node);
WaveTextureNode *wave = new WaveTextureNode();
wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
- get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
+ wave->profile = WaveTextureNode::profile_enum[(int)b_wave_node.wave_profile()];
+ BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
+ get_tex_mapping(&wave->tex_mapping, b_texture_mapping);
node = wave;
}
else if(b_node.is_a(&RNA_ShaderNodeTexChecker)) {
BL::ShaderNodeTexChecker b_checker_node(b_node);
CheckerTextureNode *checker = new CheckerTextureNode();
- get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
+ get_tex_mapping(&checker->tex_mapping, b_texture_mapping);
node = checker;
}
else if(b_node.is_a(&RNA_ShaderNodeTexBrick)) {
@@ -683,20 +801,23 @@ static ShaderNode *add_node(Scene *scene,
brick->offset_frequency = b_brick_node.offset_frequency();
brick->squash = b_brick_node.squash();
brick->squash_frequency = b_brick_node.squash_frequency();
- get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
+ get_tex_mapping(&brick->tex_mapping, b_texture_mapping);
node = brick;
}
else if(b_node.is_a(&RNA_ShaderNodeTexNoise)) {
BL::ShaderNodeTexNoise b_noise_node(b_node);
NoiseTextureNode *noise = new NoiseTextureNode();
- get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
+ get_tex_mapping(&noise->tex_mapping, b_texture_mapping);
node = noise;
}
else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
- get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
+ get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
node = musgrave;
}
else if(b_node.is_a(&RNA_ShaderNodeTexCoord)) {
@@ -716,7 +837,8 @@ static ShaderNode *add_node(Scene *scene,
sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction()));
sky->turbidity = b_sky_node.turbidity();
sky->ground_albedo = b_sky_node.ground_albedo();
- get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
+ BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
+ get_tex_mapping(&sky->tex_mapping, b_texture_mapping);
node = sky;
}
else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) {
@@ -747,29 +869,40 @@ static ShaderNode *add_node(Scene *scene,
point_density->filename = b_point_density_node.name();
point_density->space =
PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
- point_density->interpolation =
- (InterpolationType)b_point_density_node.interpolation();
+ point_density->interpolation = get_image_interpolation(b_point_density_node);
point_density->builtin_data = b_point_density_node.ptr.data;
- /* Transformation form world space to texture space. */
- BL::Object b_ob(b_point_density_node.object());
- if(b_ob) {
- float3 loc, size;
- point_density_texture_space(b_point_density_node, loc, size);
- point_density->tfm =
- transform_translate(-loc) * transform_scale(size) *
- transform_inverse(get_transform(b_ob.matrix_world()));
- }
+ /* 1 - render settings, 0 - vewport settings. */
+ int settings = background ? 1 : 0;
/* TODO(sergey): Use more proper update flag. */
if(true) {
+ b_point_density_node.cache_point_density(b_scene, settings);
scene->image_manager->tag_reload_image(
point_density->filename,
point_density->builtin_data,
point_density->interpolation,
- EXTENSION_REPEAT);
+ EXTENSION_CLIP);
}
node = point_density;
+
+ /* Transformation form world space to texture space.
+ *
+ * NOTE: Do this after the texture is cached, this is because getting
+ * min/max will need to access this cache.
+ */
+ BL::Object b_ob(b_point_density_node.object());
+ if(b_ob) {
+ float3 loc, size;
+ point_density_texture_space(b_scene,
+ b_point_density_node,
+ settings,
+ loc,
+ size);
+ point_density->tfm =
+ transform_translate(-loc) * transform_scale(size) *
+ transform_inverse(get_transform(b_ob.matrix_world()));
+ }
}
if(node)
@@ -786,7 +919,9 @@ static bool node_use_modified_socket_name(ShaderNode *node)
return true;
}
-static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::Node b_node, BL::NodeSocket b_socket)
+static ShaderInput *node_find_input_by_name(ShaderNode *node,
+ BL::Node& b_node,
+ BL::NodeSocket& b_socket)
{
string name = b_socket.name();
@@ -817,7 +952,9 @@ static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::Node b_node, B
return node->input(name.c_str());
}
-static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::Node b_node, BL::NodeSocket b_socket)
+static ShaderOutput *node_find_output_by_name(ShaderNode *node,
+ BL::Node& b_node,
+ BL::NodeSocket& b_socket)
{
string name = b_socket.name();
@@ -849,11 +986,12 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::Node b_node,
}
static void add_nodes(Scene *scene,
- BL::RenderEngine b_engine,
- BL::BlendData b_data,
- BL::Scene b_scene,
+ BL::RenderEngine& b_engine,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ const bool background,
ShaderGraph *graph,
- BL::ShaderNodeTree b_ntree,
+ BL::ShaderNodeTree& b_ntree,
const ProxyMap &proxy_input_map,
const ProxyMap &proxy_output_map)
{
@@ -890,7 +1028,8 @@ static void add_nodes(Scene *scene,
/* replace muted node with internal links */
BL::Node::internal_links_iterator b_link;
for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
- ProxyNode *proxy = new ProxyNode(convert_socket_type(b_link->to_socket()));
+ BL::NodeSocket to_socket(b_link->to_socket());
+ ProxyNode *proxy = new ProxyNode(convert_socket_type(to_socket));
input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
@@ -937,6 +1076,7 @@ static void add_nodes(Scene *scene,
b_engine,
b_data,
b_scene,
+ background,
graph,
b_group_ntree,
group_proxy_input_map,
@@ -980,13 +1120,15 @@ static void add_nodes(Scene *scene,
}
}
else {
+ BL::ShaderNode b_shader_node(*b_node);
node = add_node(scene,
b_engine,
b_data,
b_scene,
+ background,
graph,
b_ntree,
- BL::ShaderNode(*b_node));
+ b_shader_node);
}
if(node) {
@@ -1043,17 +1185,19 @@ static void add_nodes(Scene *scene,
}
static void add_nodes(Scene *scene,
- BL::RenderEngine b_engine,
- BL::BlendData b_data,
- BL::Scene b_scene,
+ BL::RenderEngine& b_engine,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ const bool background,
ShaderGraph *graph,
- BL::ShaderNodeTree b_ntree)
+ BL::ShaderNodeTree& b_ntree)
{
static const ProxyMap empty_proxy_map;
add_nodes(scene,
b_engine,
b_data,
b_scene,
+ background,
graph,
b_ntree,
empty_proxy_map,
@@ -1083,7 +1227,7 @@ void BlenderSync::sync_materials(bool update_all)
if(b_mat->use_nodes() && b_mat->node_tree()) {
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
}
else {
ShaderNode *closure, *out;
@@ -1100,8 +1244,8 @@ void BlenderSync::sync_materials(bool update_all)
shader->use_mis = get_boolean(cmat, "sample_as_light");
shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow");
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
- shader->volume_sampling_method = (VolumeSampling)RNA_enum_get(&cmat, "volume_sampling");
- shader->volume_interpolation_method = (VolumeInterpolation)RNA_enum_get(&cmat, "volume_interpolation");
+ shader->volume_sampling_method = get_volume_sampling(cmat);
+ shader->volume_interpolation_method = get_volume_interpolation(cmat);
shader->set_graph(graph);
shader->tag_update(scene);
@@ -1126,13 +1270,13 @@ void BlenderSync::sync_world(bool update_all)
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
BL::ShaderNodeTree b_ntree(b_world.node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
/* volume */
PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume");
- shader->volume_sampling_method = (VolumeSampling)RNA_enum_get(&cworld, "volume_sampling");
- shader->volume_interpolation_method = (VolumeInterpolation)RNA_enum_get(&cworld, "volume_interpolation");
+ shader->volume_sampling_method = get_volume_sampling(cworld);
+ shader->volume_interpolation_method = get_volume_interpolation(cworld);
}
else if(b_world) {
ShaderNode *closure, *out;
@@ -1167,6 +1311,10 @@ void BlenderSync::sync_world(bool update_all)
background->visibility = visibility;
}
+ else {
+ background->ao_factor = 0.0f;
+ background->ao_distance = FLT_MAX;
+ }
shader->set_graph(graph);
shader->tag_update(scene);
@@ -1184,7 +1332,8 @@ void BlenderSync::sync_world(bool update_all)
else
background->transparent = b_scene.render().alpha_mode() == BL::RenderSettings::alpha_mode_TRANSPARENT;
- background->use = render_layer.use_background;
+ background->use_shader = render_layer.use_background_shader;
+ background->use_ao = render_layer.use_background_ao;
if(background->modified(prevbackground))
background->tag_update(scene);
@@ -1212,7 +1361,7 @@ void BlenderSync::sync_lamps(bool update_all)
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
- add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
+ add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
}
else {
ShaderNode *closure, *out;
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 8888d219aac..6291b38d462 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -42,22 +42,34 @@ CCL_NAMESPACE_BEGIN
/* Constructor */
-BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_)
-: b_engine(b_engine_),
- b_data(b_data_), b_scene(b_scene_),
- shader_map(&scene_->shaders),
- object_map(&scene_->objects),
- mesh_map(&scene_->meshes),
- light_map(&scene_->lights),
- particle_system_map(&scene_->particle_systems),
+BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ Scene *scene,
+ bool preview,
+ Progress &progress,
+ bool is_cpu)
+: b_engine(b_engine),
+ b_data(b_data),
+ b_scene(b_scene),
+ shader_map(&scene->shaders),
+ object_map(&scene->objects),
+ mesh_map(&scene->meshes),
+ light_map(&scene->lights),
+ particle_system_map(&scene->particle_systems),
world_map(NULL),
world_recalc(false),
+ scene(scene),
+ preview(preview),
experimental(false),
- progress(progress_)
+ is_cpu(is_cpu),
+ dicing_rate(1.0f),
+ max_subdivisions(12),
+ progress(progress)
{
- scene = scene_;
- preview = preview_;
- is_cpu = is_cpu_;
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+ dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate") : RNA_float_get(&cscene, "dicing_rate");
+ max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
}
BlenderSync::~BlenderSync()
@@ -117,19 +129,57 @@ bool BlenderSync::sync_recalc()
}
}
+ bool dicing_prop_changed = false;
+
+ if(experimental) {
+ PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+ float updated_dicing_rate = preview ? RNA_float_get(&cscene, "preview_dicing_rate")
+ : RNA_float_get(&cscene, "dicing_rate");
+
+ if(dicing_rate != updated_dicing_rate) {
+ dicing_rate = updated_dicing_rate;
+ dicing_prop_changed = true;
+ }
+
+ int updated_max_subdivisions = RNA_int_get(&cscene, "max_subdivisions");
+
+ if(max_subdivisions != updated_max_subdivisions) {
+ max_subdivisions = updated_max_subdivisions;
+ dicing_prop_changed = true;
+ }
+ }
+
BL::BlendData::meshes_iterator b_mesh;
- for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
- if(b_mesh->is_updated())
+ for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh) {
+ if(b_mesh->is_updated()) {
mesh_map.set_recalc(*b_mesh);
+ }
+ else if(dicing_prop_changed) {
+ PointerRNA cmesh = RNA_pointer_get(&b_mesh->ptr, "cycles");
+
+ if(RNA_enum_get(&cmesh, "subdivision_type"))
+ mesh_map.set_recalc(*b_mesh);
+ }
+ }
+
BL::BlendData::worlds_iterator b_world;
for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world) {
- if(world_map == b_world->ptr.data &&
- (b_world->is_updated() || (b_world->node_tree() && b_world->node_tree().is_updated())))
- {
- world_recalc = true;
+ if(world_map == b_world->ptr.data) {
+ if(b_world->is_updated() ||
+ (b_world->node_tree() && b_world->node_tree().is_updated()))
+ {
+ world_recalc = true;
+ }
+ else if(b_world->node_tree() && b_world->use_nodes()) {
+ Shader *shader = scene->shaders[scene->default_background];
+ if(has_updated_objects && shader != NULL && shader->has_object_dependency) {
+ world_recalc = true;
+ }
+ }
}
}
@@ -145,9 +195,9 @@ bool BlenderSync::sync_recalc()
return recalc;
}
-void BlenderSync::sync_data(BL::RenderSettings b_render,
- BL::SpaceView3D b_v3d,
- BL::Object b_override,
+void BlenderSync::sync_data(BL::RenderSettings& b_render,
+ BL::SpaceView3D& b_v3d,
+ BL::Object& b_override,
int width, int height,
void **python_thread_state,
const char *layer)
@@ -161,7 +211,12 @@ void BlenderSync::sync_data(BL::RenderSettings b_render,
mesh_synced.clear(); /* use for objects and motion sync */
- sync_objects(b_v3d);
+ if(scene->need_motion() == Scene::MOTION_PASS ||
+ scene->need_motion() == Scene::MOTION_NONE ||
+ scene->camera->motion_position == Camera::MOTION_POSITION_CENTER)
+ {
+ sync_objects(b_v3d);
+ }
sync_motion(b_render,
b_v3d,
b_override,
@@ -180,7 +235,7 @@ void BlenderSync::sync_integrator()
#endif
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
- experimental = (RNA_enum_get(&cscene, "feature_set") != 0);
+ experimental = (get_enum(cscene, "feature_set") != 0);
Integrator *integrator = scene->integrator;
Integrator previntegrator = *integrator;
@@ -208,7 +263,11 @@ void BlenderSync::sync_integrator()
if(get_boolean(cscene, "use_animated_seed"))
integrator->seed = hash_int_2d(b_scene.frame_current(), get_int(cscene, "seed"));
- integrator->sampling_pattern = (SamplingPattern)RNA_enum_get(&cscene, "sampling_pattern");
+ integrator->sampling_pattern = (SamplingPattern)get_enum(
+ cscene,
+ "sampling_pattern",
+ SAMPLING_NUM_PATTERNS,
+ SAMPLING_PATTERN_SOBOL);
integrator->layer_flag = render_layer.layer;
@@ -225,7 +284,10 @@ void BlenderSync::sync_integrator()
}
#endif
- integrator->method = (Integrator::Method)get_enum(cscene, "progressive");
+ integrator->method = (Integrator::Method)get_enum(cscene,
+ "progressive",
+ Integrator::NUM_METHODS,
+ Integrator::PATH);
integrator->sample_all_lights_direct = get_boolean(cscene, "sample_all_lights_direct");
integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect");
@@ -270,12 +332,11 @@ void BlenderSync::sync_film()
Film *film = scene->film;
Film prevfilm = *film;
- /* Clamping */
- Integrator *integrator = scene->integrator;
- film->use_sample_clamp = (integrator->sample_clamp_direct != 0.0f || integrator->sample_clamp_indirect != 0.0f);
-
film->exposure = get_float(cscene, "film_exposure");
- film->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
+ film->filter_type = (FilterType)get_enum(cscene,
+ "pixel_filter_type",
+ FILTER_NUM_TYPES,
+ FILTER_BLACKMAN_HARRIS);
film->filter_width = (film->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
if(b_scene.world()) {
@@ -303,7 +364,7 @@ void BlenderSync::sync_film()
/* Render Layer */
-void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer)
+void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
string layername;
@@ -322,7 +383,8 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer)
render_layer.exclude_layer = 0;
render_layer.holdout_layer = 0;
render_layer.material_override = PointerRNA_NULL;
- render_layer.use_background = true;
+ render_layer.use_background_shader = true;
+ render_layer.use_background_ao = true;
render_layer.use_hair = true;
render_layer.use_surfaces = true;
render_layer.use_viewport_visibility = true;
@@ -335,7 +397,7 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer)
/* render layer */
BL::RenderSettings r = b_scene.render();
BL::RenderSettings::layers_iterator b_rlay;
- int use_layer_samples = RNA_enum_get(&cscene, "use_layer_samples");
+ int use_layer_samples = get_enum(cscene, "use_layer_samples");
bool first_layer = true;
uint layer_override = get_layer(b_engine.layer_override());
uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers());
@@ -354,7 +416,8 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer)
render_layer.layer |= render_layer.holdout_layer;
render_layer.material_override = b_rlay->material_override();
- render_layer.use_background = b_rlay->use_sky();
+ render_layer.use_background_shader = b_rlay->use_sky();
+ render_layer.use_background_ao = b_rlay->use_ao();
render_layer.use_surfaces = b_rlay->use_solid();
render_layer.use_hair = b_rlay->use_strand();
render_layer.use_viewport_visibility = false;
@@ -409,7 +472,9 @@ void BlenderSync::sync_images()
/* Scene Parameters */
-SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bool is_cpu)
+SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
+ bool background,
+ bool is_cpu)
{
BL::RenderSettings r = b_scene.render();
SceneParams params;
@@ -424,10 +489,13 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bo
if(background)
params.bvh_type = SceneParams::BVH_STATIC;
else
- params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
+ params.bvh_type = (SceneParams::BVHType)get_enum(
+ cscene,
+ "debug_bvh_type",
+ SceneParams::BVH_NUM_TYPES,
+ SceneParams::BVH_STATIC);
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
- params.use_bvh_cache = (background)? RNA_boolean_get(&cscene, "use_cache"): false;
if(background && params.shadingsystem != SHADINGSYSTEM_OSL)
params.persistent_data = r.use_persistent_data();
@@ -436,7 +504,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bo
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
if(is_cpu) {
- params.use_qbvh = system_cpu_support_sse2();
+ params.use_qbvh = DebugFlags().cpu.qbvh && system_cpu_support_sse2();
}
else
#endif
@@ -449,22 +517,22 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bo
/* Session Parameters */
-bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
+bool BlenderSync::get_session_pause(BL::Scene& b_scene, bool background)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
return (background)? false: get_boolean(cscene, "preview_pause");
}
-SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine,
- BL::UserPreferences b_userpref,
- BL::Scene b_scene,
+SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
+ BL::UserPreferences& b_userpref,
+ BL::Scene& b_scene,
bool background)
{
SessionParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
/* feature set */
- params.experimental = (RNA_enum_get(&cscene, "feature_set") != 0);
+ params.experimental = (get_enum(cscene, "feature_set") != 0);
/* device type */
vector<DeviceInfo>& devices = Device::available_devices();
@@ -472,13 +540,13 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine,
/* device default CPU */
params.device = devices[0];
- if(RNA_enum_get(&cscene, "device") == 2) {
+ if(get_enum(cscene, "device") == 2) {
/* find network device */
foreach(DeviceInfo& info, devices)
if(info.type == DEVICE_NETWORK)
params.device = info;
}
- else if(RNA_enum_get(&cscene, "device") == 1) {
+ else if(get_enum(cscene, "device") == 1) {
/* find GPU device with given id */
PointerRNA systemptr = b_userpref.system().ptr;
PropertyRNA *deviceprop = RNA_struct_find_property(&systemptr, "compute_device");
@@ -517,7 +585,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine,
else {
params.samples = preview_aa_samples;
if(params.samples == 0)
- params.samples = USHRT_MAX;
+ params.samples = INT_MAX;
}
}
else {
@@ -527,7 +595,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine,
else {
params.samples = preview_samples;
if(params.samples == 0)
- params.samples = USHRT_MAX;
+ params.samples = INT_MAX;
}
}
@@ -548,8 +616,8 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine,
params.tile_size = make_int2(tile_x, tile_y);
}
- if(BlenderSession::headless == false) {
- params.tile_order = (TileOrder)RNA_enum_get(&cscene, "tile_order");
+ if((BlenderSession::headless == false) && background) {
+ params.tile_order = (TileOrder)get_enum(cscene, "tile_order");
}
else {
params.tile_order = TILE_BOTTOM_TO_TOP;
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index efc6ae94542..6ff5326f39f 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -48,41 +48,58 @@ class ShaderNode;
class BlenderSync {
public:
- BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_);
+ BlenderSync(BL::RenderEngine& b_engine,
+ BL::BlendData& b_data,
+ BL::Scene& b_scene,
+ Scene *scene,
+ bool preview,
+ Progress &progress,
+ bool is_cpu);
~BlenderSync();
/* sync */
bool sync_recalc();
- void sync_data(BL::RenderSettings b_render,
- BL::SpaceView3D b_v3d,
- BL::Object b_override,
+ void sync_data(BL::RenderSettings& b_render,
+ BL::SpaceView3D& b_v3d,
+ BL::Object& b_override,
int width, int height,
void **python_thread_state,
const char *layer = 0);
- void sync_render_layers(BL::SpaceView3D b_v3d, const char *layer);
+ void sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer);
void sync_integrator();
- void sync_camera(BL::RenderSettings b_render, BL::Object b_override, int width, int height);
- void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
- int get_layer_samples() { return render_layer.samples; }
- int get_layer_bound_samples() { return render_layer.bound_samples; }
+ void sync_camera(BL::RenderSettings& b_render,
+ BL::Object& b_override,
+ int width, int height,
+ const char *viewname);
+ void sync_view(BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ int width, int height);
+ inline int get_layer_samples() { return render_layer.samples; }
+ inline int get_layer_bound_samples() { return render_layer.bound_samples; }
/* get parameters */
- static SceneParams get_scene_params(BL::Scene b_scene, bool background, bool is_cpu);
- static SessionParams get_session_params(BL::RenderEngine b_engine,
- BL::UserPreferences b_userpref,
- BL::Scene b_scene,
+ static SceneParams get_scene_params(BL::Scene& b_scene,
+ bool background,
+ bool is_cpu);
+ static SessionParams get_session_params(BL::RenderEngine& b_engine,
+ BL::UserPreferences& b_userpref,
+ BL::Scene& b_scene,
bool background);
- static bool get_session_pause(BL::Scene b_scene, bool background);
- static BufferParams get_buffer_params(BL::RenderSettings b_render, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height);
+ static bool get_session_pause(BL::Scene& b_scene, bool background);
+ static BufferParams get_buffer_params(BL::RenderSettings& b_render,
+ BL::SpaceView3D& b_v3d,
+ BL::RegionView3D& b_rv3d,
+ Camera *cam,
+ int width, int height);
private:
/* sync */
void sync_lamps(bool update_all);
void sync_materials(bool update_all);
- void sync_objects(BL::SpaceView3D b_v3d, float motion_time = 0.0f);
- void sync_motion(BL::RenderSettings b_render,
- BL::SpaceView3D b_v3d,
- BL::Object b_override,
+ void sync_objects(BL::SpaceView3D& b_v3d, float motion_time = 0.0f);
+ void sync_motion(BL::RenderSettings& b_render,
+ BL::SpaceView3D& b_v3d,
+ BL::Object& b_override,
int width, int height,
void **python_thread_state);
void sync_film();
@@ -91,12 +108,16 @@ private:
void sync_shaders();
void sync_curve_settings();
- void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
- Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
- void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index = 0);
- Object *sync_object(BL::Object b_parent,
+ void sync_nodes(Shader *shader, BL::ShaderNodeTree& b_ntree);
+ Mesh *sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris);
+ void sync_curves(Mesh *mesh,
+ BL::Mesh& b_mesh,
+ BL::Object& b_ob,
+ bool motion,
+ int time_index = 0);
+ Object *sync_object(BL::Object& b_parent,
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
- BL::DupliObject b_dupli_ob,
+ BL::DupliObject& b_dupli_ob,
Transform& tfm,
uint layer_flag,
float motion_time,
@@ -104,25 +125,31 @@ private:
bool use_camera_cull,
float camera_cull_margin,
bool *use_portal);
- void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm, bool *use_portal);
+ void sync_light(BL::Object& b_parent,
+ int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
+ BL::Object& b_ob,
+ Transform& tfm,
+ bool *use_portal);
void sync_background_light(bool use_portal);
- void sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time);
- void sync_camera_motion(BL::RenderSettings b_render,
- BL::Object b_ob,
+ void sync_mesh_motion(BL::Object& b_ob, Object *object, float motion_time);
+ void sync_camera_motion(BL::RenderSettings& b_render,
+ BL::Object& b_ob,
int width, int height,
float motion_time);
/* particles */
- bool sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Object *object);
+ bool sync_dupli_particle(BL::Object& b_ob,
+ BL::DupliObject& b_dup,
+ Object *object);
/* Images. */
void sync_images();
/* util */
- void find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader);
- bool BKE_object_is_modified(BL::Object b_ob);
- bool object_is_mesh(BL::Object b_ob);
- bool object_is_light(BL::Object b_ob);
+ void find_shader(BL::ID& id, vector<uint>& used_shaders, int default_shader);
+ bool BKE_object_is_modified(BL::Object& b_ob);
+ bool object_is_mesh(BL::Object& b_ob);
+ bool object_is_light(BL::Object& b_ob);
/* variables */
BL::RenderEngine b_engine;
@@ -145,12 +172,16 @@ private:
bool experimental;
bool is_cpu;
+ float dicing_rate;
+ int max_subdivisions;
+
struct RenderLayerInfo {
RenderLayerInfo()
: scene_layer(0), layer(0),
holdout_layer(0), exclude_layer(0),
material_override(PointerRNA_NULL),
- use_background(true),
+ use_background_shader(true),
+ use_background_ao(true),
use_surfaces(true),
use_hair(true),
use_viewport_visibility(false),
@@ -164,7 +195,8 @@ private:
uint holdout_layer;
uint exclude_layer;
BL::Material material_override;
- bool use_background;
+ bool use_background_shader;
+ bool use_background_ao;
bool use_surfaces;
bool use_hair;
bool use_viewport_visibility;
diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp
index cb4dd1792d0..3807e683c7c 100644
--- a/intern/cycles/blender/blender_texture.cpp
+++ b/intern/cycles/blender/blender_texture.cpp
@@ -22,8 +22,8 @@ namespace {
/* Point density helpers. */
-static void density_texture_space_invert(float3& loc,
- float3& size)
+void density_texture_space_invert(float3& loc,
+ float3& size)
{
if(size.x != 0.0f) size.x = 0.5f/size.x;
if(size.y != 0.0f) size.y = 0.5f/size.y;
@@ -32,85 +32,28 @@ static void density_texture_space_invert(float3& loc,
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
}
-static void density_object_texture_space(BL::Object b_ob,
- float radius,
- float3& loc,
- float3& size)
-{
- if(b_ob.type() == BL::Object::type_MESH) {
- BL::Mesh b_mesh(b_ob.data());
- loc = get_float3(b_mesh.texspace_location());
- size = get_float3(b_mesh.texspace_size());
- }
- else {
- /* TODO(sergey): Not supported currently. */
- }
- /* Adjust texture space to include density points on the boundaries. */
- size = size + make_float3(radius, radius, radius);
- density_texture_space_invert(loc, size);
-}
-
-static void density_particle_system_texture_space(
- BL::Object b_ob,
- BL::ParticleSystem b_particle_system,
- float radius,
- float3& loc,
- float3& size)
-{
- if(b_particle_system.settings().type() == BL::ParticleSettings::type_HAIR) {
- /* TODO(sergey): Not supported currently. */
- return;
- }
- Transform tfm = get_transform(b_ob.matrix_world());
- Transform itfm = transform_inverse(tfm);
- float3 min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
- max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
- float3 particle_size = make_float3(radius, radius, radius);
- for(int i = 0; i < b_particle_system.particles.length(); ++i) {
- BL::Particle particle = b_particle_system.particles[i];
- float3 location = get_float3(particle.location());
- location = transform_point(&itfm, location);
- min = ccl::min(min, location - particle_size);
- max = ccl::max(max, location + particle_size);
- }
- /* Calculate texture space from the particle bounds. */
- loc = (min + max) * 0.5f;
- size = (max - min) * 0.5f;
- density_texture_space_invert(loc, size);
-}
-
} /* namespace */
-void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
+void point_density_texture_space(BL::Scene& b_scene,
+ BL::ShaderNodeTexPointDensity& b_point_density_node,
+ int settings,
float3& loc,
float3& size)
{
- /* Fallback values. */
- loc = make_float3(0.0f, 0.0f, 0.0f);
- size = make_float3(0.0f, 0.0f, 0.0f);
BL::Object b_ob(b_point_density_node.object());
if(!b_ob) {
+ loc = make_float3(0.0f, 0.0f, 0.0f);
+ size = make_float3(0.0f, 0.0f, 0.0f);
return;
}
- if(b_point_density_node.point_source() ==
- BL::ShaderNodeTexPointDensity::point_source_PARTICLE_SYSTEM)
- {
- BL::ParticleSystem b_particle_system(
- b_point_density_node.particle_system());
- if(b_particle_system) {
- density_particle_system_texture_space(b_ob,
- b_particle_system,
- b_point_density_node.radius(),
- loc,
- size);
- }
- }
- else {
- density_object_texture_space(b_ob,
- b_point_density_node.radius(),
- loc,
- size);
- }
+ float3 min, max;
+ b_point_density_node.calc_point_density_minmax(b_scene,
+ settings,
+ &min[0],
+ &max[0]);
+ loc = (min + max) * 0.5f;
+ size = (max - min) * 0.5f;
+ density_texture_space_invert(loc, size);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h
index 74fbca02a9e..ad96f9db8ed 100644
--- a/intern/cycles/blender/blender_texture.h
+++ b/intern/cycles/blender/blender_texture.h
@@ -22,7 +22,9 @@
CCL_NAMESPACE_BEGIN
-void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
+void point_density_texture_space(BL::Scene& b_scene,
+ BL::ShaderNodeTexPointDensity& b_point_density_node,
+ const int settings,
float3& loc,
float3& size);
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 165242d0dff..cefc01bfa91 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -40,7 +40,12 @@ CCL_NAMESPACE_BEGIN
void python_thread_state_save(void **python_thread_state);
void python_thread_state_restore(void **python_thread_state);
-static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL::Scene scene, bool apply_modifiers, bool render, bool calc_undeformed)
+static inline BL::Mesh object_to_mesh(BL::BlendData& data,
+ BL::Object& object,
+ BL::Scene& scene,
+ bool apply_modifiers,
+ bool render,
+ bool calc_undeformed)
{
BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
if((bool)me) {
@@ -52,7 +57,9 @@ static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL:
return me;
}
-static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size)
+static inline void colorramp_to_array(BL::ColorRamp& ramp,
+ float4 *data,
+ int size)
{
for(int i = 0; i < size; i++) {
float color[4];
@@ -62,9 +69,64 @@ static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size
}
}
-static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *data, int size, bool rgb_curve)
+static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap& curve,
+ float *min_x,
+ float *max_x)
+{
+ *min_x = min(*min_x, curve.points[0].location()[0]);
+ *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
+}
+
+static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap,
+ bool rgb_curve,
+ float *min_x,
+ float *max_x)
+{
+ /* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */
+ const int num_curves = rgb_curve? 4: 3;
+ *min_x = FLT_MAX;
+ *max_x = -FLT_MAX;
+ for(int i = 0; i < num_curves; ++i) {
+ BL::CurveMap map(cumap.curves[i]);
+ curvemap_minmax_curve(map, min_x, max_x);
+ }
+}
+
+static inline void curvemapping_to_array(BL::CurveMapping& cumap,
+ float *data,
+ int size)
{
cumap.update();
+ BL::CurveMap curve = cumap.curves[0];
+ for(int i = 0; i < size; i++) {
+ float t = (float)i/(float)(size-1);
+ data[i] = curve.evaluate(t);
+ }
+}
+
+static inline void curvemapping_color_to_array(BL::CurveMapping& cumap,
+ float4 *data,
+ int size,
+ bool rgb_curve)
+{
+ float min_x = 0.0f, max_x = 1.0f;
+
+ /* TODO(sergey): There is no easy way to automatically guess what is
+ * the range to be used here for the case when mapping is applied on
+ * top of another mapping (i.e. R curve applied on top of common
+ * one).
+ *
+ * Using largest possible range form all curves works correct for the
+ * cases like vector curves and should be good enough heuristic for
+ * the color curves as well.
+ *
+ * There might be some better estimations here tho.
+ */
+ curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x);
+
+ const float range_x = max_x - min_x;
+
+ cumap.update();
BL::CurveMap mapR = cumap.curves[0];
BL::CurveMap mapG = cumap.curves[1];
@@ -74,7 +136,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d
BL::CurveMap mapI = cumap.curves[3];
for(int i = 0; i < size; i++) {
- float t = (float)i/(float)(size-1);
+ float t = min_x + (float)i/(float)(size-1) * range_x;
data[i][0] = mapR.evaluate(mapI.evaluate(t));
data[i][1] = mapG.evaluate(mapI.evaluate(t));
@@ -83,7 +145,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d
}
else {
for(int i = 0; i < size; i++) {
- float t = (float)i/(float)(size-1);
+ float t = min_x + (float)i/(float)(size-1) * range_x;
data[i][0] = mapR.evaluate(t);
data[i][1] = mapG.evaluate(t);
@@ -92,27 +154,33 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d
}
}
-static inline bool BKE_object_is_modified(BL::Object self, BL::Scene scene, bool preview)
+static inline bool BKE_object_is_modified(BL::Object& self,
+ BL::Scene& scene,
+ bool preview)
{
return self.is_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
}
-static inline bool BKE_object_is_deform_modified(BL::Object self, BL::Scene scene, bool preview)
+static inline bool BKE_object_is_deform_modified(BL::Object& self,
+ BL::Scene& scene,
+ bool preview)
{
return self.is_deform_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
}
-static inline int render_resolution_x(BL::RenderSettings b_render)
+static inline int render_resolution_x(BL::RenderSettings& b_render)
{
return b_render.resolution_x()*b_render.resolution_percentage()/100;
}
-static inline int render_resolution_y(BL::RenderSettings b_render)
+static inline int render_resolution_y(BL::RenderSettings& b_render)
{
return b_render.resolution_y()*b_render.resolution_percentage()/100;
}
-static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, int cfra)
+static inline string image_user_file_path(BL::ImageUser& iuser,
+ BL::Image& ima,
+ int cfra)
{
char filepath[1024];
BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
@@ -120,25 +188,27 @@ static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, in
return string(filepath);
}
-static inline int image_user_frame_number(BL::ImageUser iuser, int cfra)
+static inline int image_user_frame_number(BL::ImageUser& iuser, int cfra)
{
BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
return iuser.frame_current();
}
-static inline unsigned char *image_get_pixels_for_frame(BL::Image image, int frame)
+static inline unsigned char *image_get_pixels_for_frame(BL::Image& image,
+ int frame)
{
return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
}
-static inline float *image_get_float_pixels_for_frame(BL::Image image, int frame)
+static inline float *image_get_float_pixels_for_frame(BL::Image& image,
+ int frame)
{
return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
}
/* Utilities */
-static inline Transform get_transform(BL::Array<float, 16> array)
+static inline Transform get_transform(const BL::Array<float, 16>& array)
{
Transform tfm;
@@ -150,42 +220,42 @@ static inline Transform get_transform(BL::Array<float, 16> array)
return tfm;
}
-static inline float2 get_float2(BL::Array<float, 2> array)
+static inline float2 get_float2(const BL::Array<float, 2>& array)
{
return make_float2(array[0], array[1]);
}
-static inline float3 get_float3(BL::Array<float, 2> array)
+static inline float3 get_float3(const BL::Array<float, 2>& array)
{
return make_float3(array[0], array[1], 0.0f);
}
-static inline float3 get_float3(BL::Array<float, 3> array)
+static inline float3 get_float3(const BL::Array<float, 3>& array)
{
return make_float3(array[0], array[1], array[2]);
}
-static inline float3 get_float3(BL::Array<float, 4> array)
+static inline float3 get_float3(const BL::Array<float, 4>& array)
{
return make_float3(array[0], array[1], array[2]);
}
-static inline float4 get_float4(BL::Array<float, 4> array)
+static inline float4 get_float4(const BL::Array<float, 4>& array)
{
return make_float4(array[0], array[1], array[2], array[3]);
}
-static inline int3 get_int3(BL::Array<int, 3> array)
+static inline int3 get_int3(const BL::Array<int, 3>& array)
{
return make_int3(array[0], array[1], array[2]);
}
-static inline int4 get_int4(BL::Array<int, 4> array)
+static inline int4 get_int4(const BL::Array<int, 4>& array)
{
return make_int4(array[0], array[1], array[2], array[3]);
}
-static inline uint get_layer(BL::Array<int, 20> array)
+static inline uint get_layer(const BL::Array<int, 20>& array)
{
uint layer = 0;
@@ -196,7 +266,11 @@ static inline uint get_layer(BL::Array<int, 20> array)
return layer;
}
-static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_array, bool use_local, bool is_light = false)
+static inline uint get_layer(const BL::Array<int, 20>& array,
+ const BL::Array<int, 8>& local_array,
+ bool use_local,
+ bool is_light = false,
+ uint scene_layers = (1 << 20) - 1)
{
uint layer = 0;
@@ -205,9 +279,13 @@ static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_a
layer |= (1 << i);
if(is_light) {
- /* consider lamps on all local view layers */
- for(uint i = 0; i < 8; i++)
- layer |= (1 << (20+i));
+ /* Consider light is visible if it was visible without layer
+ * override, which matches behavior of Blender Internal.
+ */
+ if(layer & scene_layers) {
+ for(uint i = 0; i < 8; i++)
+ layer |= (1 << (20+i));
+ }
}
else {
for(uint i = 0; i < 8; i++)
@@ -279,9 +357,24 @@ static inline void set_int(PointerRNA& ptr, const char *name, int value)
RNA_int_set(&ptr, name, value);
}
-static inline int get_enum(PointerRNA& ptr, const char *name)
-{
- return RNA_enum_get(&ptr, name);
+/* Get a RNA enum value with sanity check: if the RNA value is above num_values
+ * the function will return a fallback default value.
+ *
+ * NOTE: This function assumes that RNA enum values are a continuous sequence
+ * from 0 to num_values-1. Be careful to use it with enums where some values are
+ * deprecated!
+ */
+static inline int get_enum(PointerRNA& ptr,
+ const char *name,
+ int num_values = -1,
+ int default_value = -1)
+{
+ int value = RNA_enum_get(&ptr, name);
+ if(num_values != -1 && value >= num_values) {
+ assert(default_value != -1);
+ value = default_value;
+ }
+ return value;
}
static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
@@ -302,7 +395,7 @@ static inline void set_enum(PointerRNA& ptr, const char *name, int value)
static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier)
{
- RNA_enum_set_identifier(&ptr, name, identifier.c_str());
+ RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
}
static inline string get_string(PointerRNA& ptr, const char *name)
@@ -323,13 +416,19 @@ static inline void set_string(PointerRNA& ptr, const char *name, const string &v
/* Relative Paths */
-static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
+static inline string blender_absolute_path(BL::BlendData& b_data,
+ BL::ID& b_id,
+ const string& path)
{
if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
string dirname;
- if(b_id.library())
- dirname = blender_absolute_path(b_data, b_id.library(), b_id.library().filepath());
+ if(b_id.library()) {
+ BL::ID b_library_id(b_id.library());
+ dirname = blender_absolute_path(b_data,
+ b_library_id,
+ b_id.library().filepath());
+ }
else
dirname = b_data.filepath();
@@ -341,7 +440,9 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co
/* Texture Space */
-static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size)
+static inline void mesh_texture_space(BL::Mesh& b_mesh,
+ float3& loc,
+ float3& size)
{
loc = get_float3(b_mesh.texspace_location());
size = get_float3(b_mesh.texspace_size());
@@ -354,7 +455,7 @@ static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size
}
/* object used for motion blur */
-static inline bool object_use_motion(BL::Object b_parent, BL::Object b_ob)
+static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
{
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
bool use_motion = get_boolean(cobject, "use_motion_blur");
@@ -372,7 +473,7 @@ static inline bool object_use_motion(BL::Object b_parent, BL::Object b_ob)
}
/* object motion steps */
-static inline uint object_motion_steps(BL::Object b_ob)
+static inline uint object_motion_steps(BL::Object& b_ob)
{
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
uint steps = get_int(cobject, "motion_steps");
@@ -384,7 +485,8 @@ static inline uint object_motion_steps(BL::Object b_ob)
}
/* object uses deformation motion blur */
-static inline bool object_use_deform_motion(BL::Object b_parent, BL::Object b_ob)
+static inline bool object_use_deform_motion(BL::Object& b_parent,
+ BL::Object& b_ob)
{
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
@@ -401,7 +503,7 @@ static inline bool object_use_deform_motion(BL::Object b_parent, BL::Object b_ob
return use_deform_motion;
}
-static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object b_ob)
+static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob)
{
BL::Object::modifiers_iterator b_mod;
@@ -430,7 +532,7 @@ public:
scene_data = scene_data_;
}
- T *find(BL::ID id)
+ T *find(const BL::ID& id)
{
return find(id.ptr.id.data);
}
@@ -445,7 +547,7 @@ public:
return NULL;
}
- void set_recalc(BL::ID id)
+ void set_recalc(const BL::ID& id)
{
b_recalc.insert(id.ptr.data);
}
@@ -460,12 +562,12 @@ public:
used_set.clear();
}
- bool sync(T **r_data, BL::ID id)
+ bool sync(T **r_data, const BL::ID& id)
{
return sync(r_data, id, id, id.ptr.id.data);
}
- bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
+ bool sync(T **r_data, const BL::ID& id, const BL::ID& parent, const K& key)
{
T *data = find(key);
bool recalc;
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index 350ca16f6e2..9e63485c04e 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -25,7 +25,6 @@
#include "bvh_node.h"
#include "bvh_params.h"
-#include "util_cache.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_logging.h"
@@ -70,125 +69,12 @@ BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
return new RegularBVH(params, objects);
}
-/* Cache */
-
-bool BVH::cache_read(CacheData& key)
-{
- key.add(system_cpu_bits());
- key.add(&params, sizeof(params));
-
- foreach(Object *ob, objects) {
- Mesh *mesh = ob->mesh;
-
- key.add(mesh->verts);
- key.add(mesh->triangles);
- key.add(mesh->curve_keys);
- key.add(mesh->curves);
- key.add(&ob->bounds, sizeof(ob->bounds));
- key.add(&ob->visibility, sizeof(ob->visibility));
- key.add(&mesh->transform_applied, sizeof(bool));
-
- if(mesh->use_motion_blur) {
- Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if(attr)
- key.add(attr->buffer);
-
- attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
- if(attr)
- key.add(attr->buffer);
- }
- }
-
- CacheData value;
-
- if(Cache::global.lookup(key, value)) {
- cache_filename = key.get_filename();
-
- if(!(value.read(pack.root_index) &&
- value.read(pack.SAH) &&
- value.read(pack.nodes) &&
- value.read(pack.leaf_nodes) &&
- value.read(pack.object_node) &&
- value.read(pack.tri_woop) &&
- value.read(pack.prim_type) &&
- value.read(pack.prim_visibility) &&
- value.read(pack.prim_index) &&
- value.read(pack.prim_object)))
- {
- /* Clear the pack if load failed. */
- pack.root_index = 0;
- pack.SAH = 0.0f;
- pack.nodes.clear();
- pack.leaf_nodes.clear();
- pack.object_node.clear();
- pack.tri_woop.clear();
- pack.prim_type.clear();
- pack.prim_visibility.clear();
- pack.prim_index.clear();
- pack.prim_object.clear();
- return false;
- }
- return true;
- }
-
- return false;
-}
-
-void BVH::cache_write(CacheData& key)
-{
- CacheData value;
-
- value.add(pack.root_index);
- value.add(pack.SAH);
-
- value.add(pack.nodes);
- value.add(pack.leaf_nodes);
- value.add(pack.object_node);
- value.add(pack.tri_woop);
- value.add(pack.prim_type);
- value.add(pack.prim_visibility);
- value.add(pack.prim_index);
- value.add(pack.prim_object);
-
- Cache::global.insert(key, value);
-
- cache_filename = key.get_filename();
-}
-
-void BVH::clear_cache_except()
-{
- set<string> except;
-
- if(!cache_filename.empty())
- except.insert(cache_filename);
-
- foreach(Object *ob, objects) {
- Mesh *mesh = ob->mesh;
- BVH *bvh = mesh->bvh;
-
- if(bvh && !bvh->cache_filename.empty())
- except.insert(bvh->cache_filename);
- }
-
- Cache::global.clear_except("bvh", except);
-}
-
/* Building */
void BVH::build(Progress& progress)
{
progress.set_substatus("Building BVH");
- /* cache read */
- CacheData key("bvh");
-
- if(params.use_cache) {
- progress.set_substatus("Looking in BVH cache");
-
- if(cache_read(key))
- return;
- }
-
/* build nodes */
BVHBuild bvh_build(objects,
pack.prim_type,
@@ -203,15 +89,6 @@ void BVH::build(Progress& progress)
return;
}
- /* compute SAH */
- if(!params.top_level)
- pack.SAH = root->computeSubtreeSAHCost(params);
-
- if(progress.get_cancel()) {
- root->deleteSubtree();
- return;
- }
-
/* pack triangles */
progress.set_substatus("Packing BVH triangles and strands");
pack_primitives();
@@ -227,18 +104,6 @@ void BVH::build(Progress& progress)
/* free build nodes */
root->deleteSubtree();
-
- if(progress.get_cancel()) return;
-
- /* cache write */
- if(params.use_cache) {
- progress.set_substatus("Writing BVH cache");
- cache_write(key);
-
- /* clear other bvh files from cache */
- if(params.top_level)
- clear_cache_except();
- }
}
/* Refitting */
@@ -256,7 +121,7 @@ void BVH::refit(Progress& progress)
/* Triangles */
-void BVH::pack_triangle(int idx, float4 woop[3])
+void BVH::pack_triangle(int idx, float4 storage[3])
{
int tob = pack.prim_object[idx];
assert(tob >= 0 && tob < objects.size());
@@ -269,36 +134,34 @@ void BVH::pack_triangle(int idx, float4 woop[3])
float3 v1 = vpos[vidx[1]];
float3 v2 = vpos[vidx[2]];
- woop[0] = float3_to_float4(v0);
- woop[1] = float3_to_float4(v1);
- woop[2] = float3_to_float4(v2);
+ storage[0] = float3_to_float4(v0);
+ storage[1] = float3_to_float4(v1);
+ storage[2] = float3_to_float4(v2);
}
-/* Curves*/
-
void BVH::pack_primitives()
{
int nsize = TRI_NODE_SIZE;
size_t tidx_size = pack.prim_index.size();
- pack.tri_woop.clear();
- pack.tri_woop.resize(tidx_size * nsize);
+ pack.tri_storage.clear();
+ pack.tri_storage.resize(tidx_size * nsize);
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
for(unsigned int i = 0; i < tidx_size; i++) {
if(pack.prim_index[i] != -1) {
- float4 woop[3];
+ float4 storage[3];
if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
- pack_triangle(i, woop);
+ pack_triangle(i, storage);
}
else {
/* Avoid use of uninitialized memory. */
- memset(&woop, 0, sizeof(woop));
+ memset(&storage, 0, sizeof(storage));
}
- memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
+ memcpy(&pack.tri_storage[i * nsize], storage, sizeof(float4)*3);
int tob = pack.prim_object[i];
Object *ob = objects[tob];
@@ -308,7 +171,7 @@ void BVH::pack_primitives()
pack.prim_visibility[i] |= PATH_RAY_CURVE;
}
else {
- memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
+ memset(&pack.tri_storage[i * nsize], 0, sizeof(float4)*3);
pack.prim_visibility[i] = 0;
}
}
@@ -345,10 +208,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
/* reserve */
size_t prim_index_size = pack.prim_index.size();
- size_t tri_woop_size = pack.tri_woop.size();
+ size_t tri_storage_size = pack.tri_storage.size();
size_t pack_prim_index_offset = prim_index_size;
- size_t pack_tri_woop_offset = tri_woop_size;
+ size_t pack_tri_storage_offset = tri_storage_size;
size_t pack_nodes_offset = nodes_size;
size_t pack_leaf_nodes_offset = leaf_nodes_size;
size_t object_offset = 0;
@@ -359,10 +222,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
Mesh *mesh = ob->mesh;
BVH *bvh = mesh->bvh;
- if(!mesh->transform_applied) {
+ if(mesh->need_build_bvh()) {
if(mesh_map.find(mesh) == mesh_map.end()) {
prim_index_size += bvh->pack.prim_index.size();
- tri_woop_size += bvh->pack.tri_woop.size();
+ tri_storage_size += bvh->pack.tri_storage.size();
nodes_size += bvh->pack.nodes.size();
leaf_nodes_size += bvh->pack.leaf_nodes.size();
@@ -377,7 +240,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
pack.prim_type.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.resize(prim_index_size);
- pack.tri_woop.resize(tri_woop_size);
+ pack.tri_storage.resize(tri_storage_size);
pack.nodes.resize(nodes_size);
pack.leaf_nodes.resize(leaf_nodes_size);
pack.object_node.resize(objects.size());
@@ -386,7 +249,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
- float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
+ float4 *pack_tri_storage = (pack.tri_storage.size())? &pack.tri_storage[0]: NULL;
int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL;
@@ -394,9 +257,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
foreach(Object *ob, objects) {
Mesh *mesh = ob->mesh;
- /* if mesh transform is applied, that means it's already in the top
- * level BVH, and we don't need to merge it in */
- if(mesh->transform_applied) {
+ /* We assume that if mesh doesn't need own BVH it was already included
+ * into a top-level BVH and no packing here is needed.
+ */
+ if(!mesh->need_build_bvh()) {
pack.object_node[object_offset++] = 0;
continue;
}
@@ -447,10 +311,11 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
}
/* merge triangle intersection data */
- if(bvh->pack.tri_woop.size()) {
- memcpy(pack_tri_woop + pack_tri_woop_offset, &bvh->pack.tri_woop[0],
- bvh->pack.tri_woop.size()*sizeof(float4));
- pack_tri_woop_offset += bvh->pack.tri_woop.size();
+ if(bvh->pack.tri_storage.size()) {
+ memcpy(pack_tri_storage + pack_tri_storage_offset,
+ &bvh->pack.tri_storage[0],
+ bvh->pack.tri_storage.size()*sizeof(float4));
+ pack_tri_storage_offset += bvh->pack.tri_storage.size();
}
/* merge nodes */
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
index 669d2ccdcd5..6076c25ca31 100644
--- a/intern/cycles/bvh/bvh.h
+++ b/intern/cycles/bvh/bvh.h
@@ -20,7 +20,6 @@
#include "bvh_params.h"
-#include "util_string.h"
#include "util_types.h"
#include "util_vector.h"
@@ -30,7 +29,6 @@ class BVHNode;
struct BVHStackEntry;
class BVHParams;
class BoundBox;
-class CacheData;
class LeafNode;
class Object;
class Progress;
@@ -54,8 +52,8 @@ struct PackedBVH {
array<int4> leaf_nodes;
/* object index to BVH node index mapping for instances */
array<int> object_node;
- /* precomputed triangle intersection data, one triangle is 4x float4 */
- array<float4> tri_woop;
+ /* Aligned triangle storage for fatser lookup in the kernel. */
+ array<float4> tri_storage;
/* primitive type - triangle or strand */
array<int> prim_type;
/* visibility visibilitys for primitives */
@@ -69,13 +67,9 @@ struct PackedBVH {
/* index of the root node. */
int root_index;
- /* surface area heuristic, for building top level BVH */
- float SAH;
-
PackedBVH()
{
root_index = 0;
- SAH = 0.0f;
}
};
@@ -87,7 +81,6 @@ public:
PackedBVH pack;
BVHParams params;
vector<Object*> objects;
- string cache_filename;
static BVH *create(const BVHParams& params, const vector<Object*>& objects);
virtual ~BVH() {}
@@ -95,18 +88,12 @@ public:
void build(Progress& progress);
void refit(Progress& progress);
- void clear_cache_except();
-
protected:
BVH(const BVHParams& params, const vector<Object*>& objects);
- /* cache */
- bool cache_read(CacheData& key);
- void cache_write(CacheData& key);
-
/* triangles and strands*/
void pack_primitives();
- void pack_triangle(int idx, float4 woop[3]);
+ void pack_triangle(int idx, float4 storage[3]);
/* merge instance BVH's */
void pack_instances(size_t nodes_size, size_t leaf_nodes_size);
diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp
index 8745e39c21e..b07e870d759 100644
--- a/intern/cycles/bvh/bvh_binning.cpp
+++ b/intern/cycles/bvh/bvh_binning.cpp
@@ -176,7 +176,7 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO
prefetch_L2(&prims[start() + l + 8]);
prefetch_L2(&prims[start() + r - 8]);
- BVHReference prim = prims[start() + l];
+ const BVHReference& prim = prims[start() + l];
float3 center = prim.bounds().center2();
if(get_bin(center)[dim] < pos) {
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
index 45b0aaa2d63..a0b09c780ce 100644
--- a/intern/cycles/bvh/bvh_build.cpp
+++ b/intern/cycles/bvh/bvh_build.cpp
@@ -30,36 +30,59 @@
#include "util_foreach.h"
#include "util_logging.h"
#include "util_progress.h"
+#include "util_stack_allocator.h"
+#include "util_simd.h"
#include "util_time.h"
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_SSE2__)
-/* TODO(sergey): Move to some generic header so all code
- * can use bitscan on non-SSE processors.
- */
-ccl_device_inline int bitscan(int value)
-{
- assert(value != 0);
- int bit = 0;
- while(value >>= 1) {
- ++bit;
- }
- return bit;
-}
-#endif
-
/* BVH Build Task */
class BVHBuildTask : public Task {
public:
- BVHBuildTask(BVHBuild *build, InnerNode *node, int child, BVHObjectBinning& range_, int level)
- : range(range_)
+ BVHBuildTask(BVHBuild *build,
+ InnerNode *node,
+ int child,
+ const BVHObjectBinning& range,
+ int level)
+ : range_(range)
{
- run = function_bind(&BVHBuild::thread_build_node, build, node, child, &range, level);
+ run = function_bind(&BVHBuild::thread_build_node,
+ build,
+ node,
+ child,
+ &range_,
+ level);
}
+private:
+ BVHObjectBinning range_;
+};
- BVHObjectBinning range;
+class BVHSpatialSplitBuildTask : public Task {
+public:
+ BVHSpatialSplitBuildTask(BVHBuild *build,
+ InnerNode *node,
+ int child,
+ const BVHRange& range,
+ const vector<BVHReference>& references,
+ int level)
+ : range_(range),
+ references_(references.begin() + range.start(),
+ references.begin() + range.end())
+ {
+ range_.set_start(0);
+ run = function_bind(&BVHBuild::thread_build_spatial_split_node,
+ build,
+ node,
+ child,
+ &range_,
+ &references_,
+ level,
+ _1);
+ }
+private:
+ BVHRange range_;
+ vector<BVHReference> references_;
};
/* Constructor / Destructor */
@@ -180,7 +203,7 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
- if(ob->mesh->transform_applied) {
+ if(!ob->mesh->is_instanced()) {
num_alloc_references += ob->mesh->triangles.size();
num_alloc_references += count_curve_segments(ob->mesh);
}
@@ -201,7 +224,7 @@ void BVHBuild::add_references(BVHRange& root)
foreach(Object *ob, objects) {
if(params.top_level) {
- if(ob->mesh->transform_applied)
+ if(!ob->mesh->is_instanced())
add_reference_mesh(bounds, center, ob->mesh, i);
else
add_reference_object(bounds, center, ob, i);
@@ -244,8 +267,23 @@ BVHNode* BVHBuild::run()
}
spatial_min_overlap = root.bounds().safe_area() * params.spatial_split_alpha;
- spatial_right_bounds.clear();
- spatial_right_bounds.resize(max(root.size(), (int)BVHParams::NUM_SPATIAL_BINS) - 1);
+ if(params.use_spatial_split) {
+ /* NOTE: The API here tries to be as much ready for multi-threaded build
+ * as possible, but at the same time it tries not to introduce any
+ * changes in behavior for until all refactoring needed for threading is
+ * finished.
+ *
+ * So we currently allocate single storage for now, which is only used by
+ * the only thread working on the spatial BVH build.
+ */
+ spatial_storage.resize(TaskScheduler::num_threads() + 1);
+ size_t num_bins = max(root.size(), (int)BVHParams::NUM_SPATIAL_BINS) - 1;
+ foreach(BVHSpatialStorage &storage, spatial_storage) {
+ storage.right_bounds.clear();
+ }
+ spatial_storage[0].right_bounds.resize(num_bins);
+ }
+ spatial_free_index = 0;
/* init progress updates */
double build_start_time;
@@ -262,11 +300,12 @@ BVHNode* BVHBuild::run()
BVHNode *rootnode;
if(params.use_spatial_split) {
- /* singlethreaded spatial split build */
- rootnode = build_node(root, 0);
+ /* Perform multithreaded spatial split build. */
+ rootnode = build_node(root, &references, 0, 0);
+ task_pool.wait_work();
}
else {
- /* multithreaded binning build */
+ /* Perform multithreaded binning build. */
BVHObjectBinning rootbin(root, (references.size())? &references[0]: NULL);
rootnode = build_node(rootbin, 0);
task_pool.wait_work();
@@ -279,7 +318,7 @@ BVHNode* BVHBuild::run()
rootnode = NULL;
VLOG(1) << "BVH build cancelled.";
}
- else if(!params.use_spatial_split) {
+ else {
/*rotate(rootnode, 4, 5);*/
rootnode->update_visibility();
}
@@ -291,7 +330,11 @@ BVHNode* BVHBuild::run()
<< " Number of inner nodes: "
<< rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT) << "\n"
<< " Number of leaf nodes: "
- << rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT) << "\n";
+ << rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT) << "\n"
+ << " Allocation slop factor: "
+ << ((prim_type.capacity() != 0)
+ ? (float)prim_type.size() / prim_type.capacity()
+ : 1.0f) << "\n";
}
}
@@ -314,7 +357,10 @@ void BVHBuild::progress_update()
progress_start_time = time_dt();
}
-void BVHBuild::thread_build_node(InnerNode *inner, int child, BVHObjectBinning *range, int level)
+void BVHBuild::thread_build_node(InnerNode *inner,
+ int child,
+ BVHObjectBinning *range,
+ int level)
{
if(progress.get_cancel())
return;
@@ -336,20 +382,39 @@ void BVHBuild::thread_build_node(InnerNode *inner, int child, BVHObjectBinning *
}
}
-bool BVHBuild::range_within_max_leaf_size(const BVHRange& range)
+void BVHBuild::thread_build_spatial_split_node(InnerNode *inner,
+ int child,
+ BVHRange *range,
+ vector<BVHReference> *references,
+ int level,
+ int thread_id)
+{
+ if(progress.get_cancel()) {
+ return;
+ }
+
+ /* build nodes */
+ BVHNode *node = build_node(*range, references, level, thread_id);
+
+ /* set child in inner node */
+ inner->children[child] = node;
+}
+
+bool BVHBuild::range_within_max_leaf_size(const BVHRange& range,
+ const vector<BVHReference>& references) const
{
size_t size = range.size();
size_t max_leaf_size = max(params.max_triangle_leaf_size, params.max_curve_leaf_size);
if(size > max_leaf_size)
return false;
-
+
size_t num_triangles = 0;
size_t num_curves = 0;
size_t num_motion_curves = 0;
for(int i = 0; i < size; i++) {
- BVHReference& ref = references[range.start() + i];
+ const BVHReference& ref = references[range.start() + i];
if(ref.prim_type() & PRIMITIVE_CURVE)
num_curves++;
@@ -375,8 +440,11 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
* visibility tests, since object instances do not check visibility flag */
if(!(range.size() > 0 && params.top_level && level == 0)) {
/* make leaf node when threshold reached or SAH tells us */
- if(params.small_enough_for_leaf(size, level) || (range_within_max_leaf_size(range) && leafSAH < splitSAH))
- return create_leaf_node(range);
+ if((params.small_enough_for_leaf(size, level)) ||
+ (range_within_max_leaf_size(range, references) && leafSAH < splitSAH))
+ {
+ return create_leaf_node(range, references);
+ }
}
/* perform split */
@@ -404,48 +472,86 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level)
return inner;
}
-/* single threaded spatial split builder */
-BVHNode* BVHBuild::build_node(const BVHRange& range, int level)
+/* multithreaded spatial split builder */
+BVHNode* BVHBuild::build_node(const BVHRange& range,
+ vector<BVHReference> *references,
+ int level,
+ int thread_id)
{
- /* progress update */
+ /* Update progress.
+ *
+ * TODO(sergey): Currently it matches old behavior, but we can move it to the
+ * task thread (which will mimic non=split builder) and save some CPU ticks
+ * on checking cancel status.
+ */
progress_update();
- if(progress.get_cancel())
+ if(progress.get_cancel()) {
return NULL;
+ }
- /* small enough or too deep => create leaf. */
+ /* Small enough or too deep => create leaf. */
if(!(range.size() > 0 && params.top_level && level == 0)) {
if(params.small_enough_for_leaf(range.size(), level)) {
progress_count += range.size();
- return create_leaf_node(range);
+ return create_leaf_node(range, *references);
}
}
- /* splitting test */
- BVHMixedSplit split(this, range, level);
+ /* Perform splitting test. */
+ BVHSpatialStorage *storage = &spatial_storage[thread_id];
+ BVHMixedSplit split(this, storage, range, references, level);
if(!(range.size() > 0 && params.top_level && level == 0)) {
if(split.no_split) {
progress_count += range.size();
- return create_leaf_node(range);
+ return create_leaf_node(range, *references);
}
}
-
- /* do split */
+
+ /* Do split. */
BVHRange left, right;
split.split(this, left, right, range);
progress_total += left.size() + right.size() - range.size();
- size_t total = progress_total;
- /* left node */
- BVHNode *leftnode = build_node(left, level + 1);
+ /* Create inner node. */
+ InnerNode *inner;
+
+ if(range.size() < THREAD_TASK_SIZE) {
+ /* Local build. */
+
+ /* Build left node. */
+ vector<BVHReference> copy(references->begin() + right.start(),
+ references->begin() + right.end());
+ right.set_start(0);
+
+ BVHNode *leftnode = build_node(left, references, level + 1, thread_id);
- /* right node (modify start for splits) */
- right.set_start(right.start() + progress_total - total);
- BVHNode *rightnode = build_node(right, level + 1);
+ /* Build right node. */
+ BVHNode *rightnode = build_node(right, &copy, level + 1, thread_id);
- /* inner node */
- return new InnerNode(range.bounds(), leftnode, rightnode);
+ inner = new InnerNode(range.bounds(), leftnode, rightnode);
+ }
+ else {
+ /* Threaded build. */
+ inner = new InnerNode(range.bounds());
+ task_pool.push(new BVHSpatialSplitBuildTask(this,
+ inner,
+ 0,
+ left,
+ *references,
+ level + 1),
+ true);
+ task_pool.push(new BVHSpatialSplitBuildTask(this,
+ inner,
+ 1,
+ right,
+ *references,
+ level + 1),
+ true);
+ }
+
+ return inner;
}
/* Create Nodes */
@@ -478,30 +584,32 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
}
}
-BVHNode *BVHBuild::create_primitive_leaf_node(const int *p_type,
- const int *p_index,
- const int *p_object,
- const BoundBox& bounds,
- uint visibility,
- int start,
- int num)
+BVHNode* BVHBuild::create_leaf_node(const BVHRange& range,
+ const vector<BVHReference>& references)
{
- for(int i = 0; i < num; ++i) {
- prim_type[start + i] = p_type[i];
- prim_index[start + i] = p_index[i];
- prim_object[start + i] = p_object[i];
- }
- return new LeafNode(bounds, visibility, start, start + num);
-}
-
-BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
-{
- /* TODO(sergey): Consider writing own allocator which would
- * not do heap allocation if number of elements is relatively small.
+ /* This is a bit overallocating here (considering leaf size into account),
+ * but chunk-based re-allocation in vector makes it difficult to use small
+ * size of stack storage here. Some tweaks are possible tho.
+ *
+ * NOTES:
+ * - If the size is too big, we'll have inefficient stack usage,
+ * and lots of cache misses.
+ * - If the size is too small, then we can run out of memory
+ * allowed to be used by vector.
+ * In practice it wouldn't mean crash, just allocator will fallback
+ * to heap which is slower.
+ * - Optimistic re-allocation in STL could jump us out of stack usage
+ * because re-allocation happens in chunks and size of those chunks we
+ * can not control.
*/
- vector<int> p_type[PRIMITIVE_NUM_TOTAL];
- vector<int> p_index[PRIMITIVE_NUM_TOTAL];
- vector<int> p_object[PRIMITIVE_NUM_TOTAL];
+ typedef StackAllocator<256, int> LeafStackAllocator;
+
+ vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL];
+ vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL];
+ vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL];
+ /* TODO(sergey): In theory we should be able to store references. */
+ vector<BVHReference, LeafStackAllocator> object_references;
+
uint visibility[PRIMITIVE_NUM_TOTAL] = {0};
/* NOTE: Keep initializtion in sync with actual number of primitives. */
BoundBox bounds[PRIMITIVE_NUM_TOTAL] = {BoundBox::empty,
@@ -512,7 +620,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
/* Fill in per-type type/index array. */
for(int i = 0; i < range.size(); i++) {
- BVHReference& ref = references[range.start() + i];
+ const BVHReference& ref = references[range.start() + i];
if(ref.prim_index() != -1) {
int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL);
p_type[type_index].push_back(ref.prim_type());
@@ -523,52 +631,122 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
visibility[type_index] |= objects[ref.prim_object()]->visibility;
}
else {
- if(ob_num < i) {
- references[range.start() + ob_num] = ref;
- }
+ object_references.push_back(ref);
ob_num++;
}
}
- /* Extend an array when needed. */
- if(prim_type.size() < range.end()) {
- assert(params.use_spatial_split);
- prim_type.reserve(references.size());
- prim_index.reserve(references.size());
- prim_object.reserve(references.size());
- prim_type.resize(range.end());
- prim_index.resize(range.end());
- prim_object.resize(range.end());
- }
-
- /* Create leaf nodes for every existing primitive. */
+ /* Create leaf nodes for every existing primitive.
+ *
+ * Here we write primitive types, indices and objects to a temporary array.
+ * This way we keep all the heavy memory allocation code outside of the
+ * thread lock in the case of spatial split building.
+ *
+ * TODO(sergey): With some pointer trickery we can write directly to the
+ * destination buffers for the non-spatial split BVH.
+ */
BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
int num_leaves = 0;
- int start = range.start();
+ size_t start_index = 0;
+ vector<int, LeafStackAllocator> local_prim_type,
+ local_prim_index,
+ local_prim_object;
for(int i = 0; i < PRIMITIVE_NUM_TOTAL; ++i) {
int num = (int)p_type[i].size();
+ local_prim_type.resize(start_index + num);
+ local_prim_index.resize(start_index + num);
+ local_prim_object.resize(start_index + num);
if(num != 0) {
assert(p_type[i].size() == p_index[i].size());
assert(p_type[i].size() == p_object[i].size());
- leaves[num_leaves] = create_primitive_leaf_node(&p_type[i][0],
- &p_index[i][0],
- &p_object[i][0],
- bounds[i],
- visibility[i],
- start,
- num);
- ++num_leaves;
- start += num;
+ for(int j = 0; j < num; ++j) {
+ const int index = start_index + j;
+ local_prim_type[index] = p_type[i][j];
+ local_prim_index[index] = p_index[i][j];
+ local_prim_object[index] = p_object[i][j];
+ }
+ leaves[num_leaves++] = new LeafNode(bounds[i],
+ visibility[i],
+ start_index,
+ start_index + num);
+ start_index += num;
+ }
+ }
+ /* Get size of new data to be copied to the packed arrays. */
+ const int num_new_leaf_data = start_index;
+ const size_t new_leaf_data_size = sizeof(int) * num_new_leaf_data;
+ /* Copy actual data to the packed array. */
+ if(params.use_spatial_split) {
+ spatial_spin_lock.lock();
+ /* We use first free index in the packed arrays and mode pointer to the
+ * end of the current range.
+ *
+ * This doesn't give deterministic packed arrays, but it shouldn't really
+ * matter because order of children in BVH is deterministic.
+ */
+ start_index = spatial_free_index;
+ spatial_free_index += range.size();
+
+ /* Extend an array when needed. */
+ const size_t range_end = start_index + range.size();
+ if(prim_type.size() < range_end) {
+ /* Avoid extra re-allocations by pre-allocating bigger array in an
+ * advance.
+ */
+ if(range_end >= prim_type.capacity()) {
+ float progress = (float)progress_count/(float)progress_total;
+ float factor = (1.0f - progress);
+ const size_t reserve = (size_t)(range_end + (float)range_end*factor);
+ prim_type.reserve(reserve);
+ prim_index.reserve(reserve);
+ prim_object.reserve(reserve);
+ }
+
+ prim_type.resize(range_end);
+ prim_index.resize(range_end);
+ prim_object.resize(range_end);
+ }
+ spatial_spin_lock.unlock();
+
+ /* Perform actual data copy. */
+ if(new_leaf_data_size > 0) {
+ memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
+ memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
+ memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
+ }
+ }
+ else {
+ /* For the regular BVH builder we simply copy new data starting at the
+ * range start. This is totally thread-safe, all threads are living
+ * inside of their own range.
+ */
+ start_index = range.start();
+ if(new_leaf_data_size > 0) {
+ memcpy(&prim_type[start_index], &local_prim_type[0], new_leaf_data_size);
+ memcpy(&prim_index[start_index], &local_prim_index[0], new_leaf_data_size);
+ memcpy(&prim_object[start_index], &local_prim_object[0], new_leaf_data_size);
}
}
+ /* So far leaves were created with the zero-based index in an arrays,
+ * here we modify the indices to correspond to actual packed array start
+ * index.
+ */
+ for(int i = 0; i < num_leaves; ++i) {
+ LeafNode *leaf = (LeafNode *)leaves[i];
+ leaf->m_lo += start_index;
+ leaf->m_hi += start_index;
+ }
+
/* Create leaf node for object. */
if(num_leaves == 0 || ob_num) {
/* Only create object leaf nodes if there are objects or no other
* nodes created.
*/
- const BVHReference *ref = (ob_num)? &references[range.start()]: NULL;
- leaves[num_leaves] = create_object_leaf_nodes(ref, start, ob_num);
+ const BVHReference *ref = (ob_num)? &object_references[0]: NULL;
+ leaves[num_leaves] = create_object_leaf_nodes(ref,
+ start_index + num_new_leaf_data,
+ ob_num);
++num_leaves;
}
@@ -600,6 +778,8 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
}
return inner_c;
}
+
+#undef MAX_ITEMS_PER_LEAF
}
/* Tree Rotations */
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
index eefb7b60f7c..a015b89d72f 100644
--- a/intern/cycles/bvh/bvh_build.h
+++ b/intern/cycles/bvh/bvh_build.h
@@ -30,6 +30,7 @@
CCL_NAMESPACE_BEGIN
class BVHBuildTask;
+class BVHSpatialSplitBuildTask;
class BVHParams;
class InnerNode;
class Mesh;
@@ -57,6 +58,7 @@ protected:
friend class BVHObjectSplit;
friend class BVHSpatialSplit;
friend class BVHBuildTask;
+ friend class BVHSpatialSplitBuildTask;
/* adding references */
void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i);
@@ -64,25 +66,30 @@ protected:
void add_references(BVHRange& root);
/* building */
- BVHNode *build_node(const BVHRange& range, int level);
+ BVHNode *build_node(const BVHRange& range,
+ vector<BVHReference> *references,
+ int level,
+ int thread_id);
BVHNode *build_node(const BVHObjectBinning& range, int level);
- BVHNode *create_leaf_node(const BVHRange& range);
+ BVHNode *create_leaf_node(const BVHRange& range,
+ const vector<BVHReference>& references);
BVHNode *create_object_leaf_nodes(const BVHReference *ref, int start, int num);
- /* Leaf node type splitting. */
- BVHNode *create_primitive_leaf_node(const int *p_type,
- const int *p_index,
- const int *p_object,
- const BoundBox& bounds,
- uint visibility,
- int start,
- int nun);
-
- bool range_within_max_leaf_size(const BVHRange& range);
+ bool range_within_max_leaf_size(const BVHRange& range,
+ const vector<BVHReference>& references) const;
/* threads */
enum { THREAD_TASK_SIZE = 4096 };
- void thread_build_node(InnerNode *node, int child, BVHObjectBinning *range, int level);
+ void thread_build_node(InnerNode *node,
+ int child,
+ BVHObjectBinning *range,
+ int level);
+ void thread_build_spatial_split_node(InnerNode *node,
+ int child,
+ BVHRange *range,
+ vector<BVHReference> *references,
+ int level,
+ int thread_id);
thread_mutex build_mutex;
/* progress */
@@ -114,8 +121,9 @@ protected:
/* spatial splitting */
float spatial_min_overlap;
- vector<BoundBox> spatial_right_bounds;
- BVHSpatialBin spatial_bins[3][BVHParams::NUM_SPATIAL_BINS];
+ vector<BVHSpatialStorage> spatial_storage;
+ size_t spatial_free_index;
+ thread_spin_lock spatial_spin_lock;
/* threads */
TaskPool task_pool;
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
index af8d8eeb3ee..cf683df1b31 100644
--- a/intern/cycles/bvh/bvh_params.h
+++ b/intern/cycles/bvh/bvh_params.h
@@ -43,9 +43,6 @@ public:
/* object or mesh level bvh */
bool top_level;
- /* disk cache */
- bool use_cache;
-
/* QBVH */
bool use_qbvh;
@@ -71,7 +68,6 @@ public:
max_curve_leaf_size = 2;
top_level = false;
- use_cache = false;
use_qbvh = false;
}
@@ -179,6 +175,26 @@ struct BVHSpatialBin
}
};
+/* BVH Spatial Storage
+ *
+ * The idea of this storage is have thread-specific storage for the spatial
+ * splitters. We can pre-allocate this storage in advance and avoid heavy memory
+ * operations during split process.
+ */
+
+struct BVHSpatialStorage {
+ /* Accumulated bounds when sweeping from right to left. */
+ vector<BoundBox> right_bounds;
+
+ /* Bins used for histogram when selecting best split plane. */
+ BVHSpatialBin bins[3][BVHParams::NUM_SPATIAL_BINS];
+
+ /* Temporary storage for the new references. Used by spatial split to store
+ * new references in before they're getting inserted into actual array,
+ */
+ vector<BVHReference> new_references;
+};
+
CCL_NAMESPACE_END
#endif /* __BVH_PARAMS_H__ */
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
index 3140bf23376..c12751979cd 100644
--- a/intern/cycles/bvh/bvh_sort.cpp
+++ b/intern/cycles/bvh/bvh_sort.cpp
@@ -14,22 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+
#include "bvh_build.h"
#include "bvh_sort.h"
#include "util_algorithm.h"
#include "util_debug.h"
+#include "util_task.h"
CCL_NAMESPACE_BEGIN
-/* silly workaround for float extended precision that happens when compiling
+static const int BVH_SORT_THRESHOLD = 4096;
+
+/* Silly workaround for float extended precision that happens when compiling
* on x86, due to one float staying in 80 bit precision register and the other
- * not, which causes the strictly weak ordering to break */
+ * not, which causes the strictly weak ordering to break.
+ */
#if !defined(__i386__)
-#define NO_EXTENDED_PRECISION
+# define NO_EXTENDED_PRECISION
#else
-#define NO_EXTENDED_PRECISION volatile
+# define NO_EXTENDED_PRECISION volatile
#endif
struct BVHReferenceCompare {
@@ -41,28 +45,148 @@ public:
dim = dim_;
}
- bool operator()(const BVHReference& ra, const BVHReference& rb)
+ /* Compare two references.
+ *
+ * Returns value is similar to return value of strcmp().
+ */
+ __forceinline int compare(const BVHReference& ra,
+ const BVHReference& rb) const
{
NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim] + ra.bounds().max[dim];
NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim] + rb.bounds().max[dim];
- if(ca < cb) return true;
- else if(ca > cb) return false;
- else if(ra.prim_object() < rb.prim_object()) return true;
- else if(ra.prim_object() > rb.prim_object()) return false;
- else if(ra.prim_index() < rb.prim_index()) return true;
- else if(ra.prim_index() > rb.prim_index()) return false;
- else if(ra.prim_type() < rb.prim_type()) return true;
- else if(ra.prim_type() > rb.prim_type()) return false;
+ if(ca < cb) return -1;
+ else if(ca > cb) return 1;
+ else if(ra.prim_object() < rb.prim_object()) return -1;
+ else if(ra.prim_object() > rb.prim_object()) return 1;
+ else if(ra.prim_index() < rb.prim_index()) return -1;
+ else if(ra.prim_index() > rb.prim_index()) return 1;
+ else if(ra.prim_type() < rb.prim_type()) return -1;
+ else if(ra.prim_type() > rb.prim_type()) return 1;
+
+ return 0;
+ }
+
+ bool operator()(const BVHReference& ra, const BVHReference& rb)
+ {
+ return (compare(ra, rb) < 0);
+ }
+};
+
+static void bvh_reference_sort_threaded(TaskPool *task_pool,
+ BVHReference *data,
+ const int job_start,
+ const int job_end,
+ const BVHReferenceCompare& compare);
- return false;
+class BVHSortTask : public Task {
+public:
+ BVHSortTask(TaskPool *task_pool,
+ BVHReference *data,
+ const int job_start,
+ const int job_end,
+ const BVHReferenceCompare& compare)
+ {
+ run = function_bind(bvh_reference_sort_threaded,
+ task_pool,
+ data,
+ job_start,
+ job_end,
+ compare);
}
};
+/* Multi-threaded reference sort. */
+static void bvh_reference_sort_threaded(TaskPool *task_pool,
+ BVHReference *data,
+ const int job_start,
+ const int job_end,
+ const BVHReferenceCompare& compare)
+{
+ int start = job_start, end = job_end;
+ bool have_work = (start < end);
+ while(have_work) {
+ const int count = job_end - job_start;
+ if(count < BVH_SORT_THRESHOLD) {
+ /* Number of reference low enough, faster to finish the job
+ * in one thread rather than to spawn more threads.
+ */
+ sort(data+job_start, data+job_end+1, compare);
+ break;
+ }
+ /* Single QSort step.
+ * Use median-of-three method for the pivot point.
+ */
+ int left = start, right = end;
+ int center = (left + right) >> 1;
+ if(compare.compare(data[left], data[center]) > 0) {
+ swap(data[left], data[center]);
+ }
+ if(compare.compare(data[left], data[right]) > 0) {
+ swap(data[left], data[right]);
+ }
+ if (compare.compare(data[center], data[right]) > 0) {
+ swap(data[center], data[right]);
+ }
+ swap(data[center], data[right - 1]);
+ BVHReference median = data[right - 1];
+ do {
+ while(compare.compare(data[left], median) < 0) {
+ ++left;
+ }
+ while(compare.compare(data[right], median) > 0) {
+ --right;
+ }
+ if(left <= right) {
+ swap(data[left], data[right]);
+ ++left;
+ --right;
+ }
+ } while(left <= right);
+ /* We only create one new task here to reduce downside effects of
+ * latency in TaskScheduler.
+ * So generally current thread keeps working on the left part of the
+ * array, and we create new task for the right side.
+ * However, if there's nothing to be done in the left side of the array
+ * we don't create any tasks and make it so current thread works on the
+ * right side.
+ */
+ have_work = false;
+ if(left < end) {
+ if(start < right) {
+ task_pool->push(new BVHSortTask(task_pool,
+ data,
+ left, end,
+ compare), true);
+ }
+ else {
+ start = left;
+ have_work = true;
+ }
+ }
+ if(start < right) {
+ end = right;
+ have_work = true;
+ }
+ }
+}
+
void bvh_reference_sort(int start, int end, BVHReference *data, int dim)
{
+ const int count = end - start;
BVHReferenceCompare compare(dim);
- sort(data+start, data+end, compare);
+ if(count < BVH_SORT_THRESHOLD) {
+ /* It is important to not use any mutex if array is small enough,
+ * otherwise we end up in situation when we're going to sleep far
+ * too often.
+ */
+ sort(data+start, data+end, compare);
+ }
+ else {
+ TaskPool task_pool;
+ bvh_reference_sort_threaded(&task_pool, data, start, end - 1, dim);
+ task_pool.wait_work();
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp
index 534c1aa73b5..9185bd99d10 100644
--- a/intern/cycles/bvh/bvh_split.cpp
+++ b/intern/cycles/bvh/bvh_split.cpp
@@ -28,22 +28,36 @@ CCL_NAMESPACE_BEGIN
/* Object Split */
-BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, const BVHRange& range, float nodeSAH)
-: sah(FLT_MAX), dim(0), num_left(0), left_bounds(BoundBox::empty), right_bounds(BoundBox::empty)
+BVHObjectSplit::BVHObjectSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange& range,
+ vector<BVHReference> *references,
+ float nodeSAH)
+: sah(FLT_MAX),
+ dim(0),
+ num_left(0),
+ left_bounds(BoundBox::empty),
+ right_bounds(BoundBox::empty),
+ storage_(storage),
+ references_(references)
{
- const BVHReference *ref_ptr = &builder->references[range.start()];
+ const BVHReference *ref_ptr = &references_->at(range.start());
float min_sah = FLT_MAX;
for(int dim = 0; dim < 3; dim++) {
- /* sort references */
- bvh_reference_sort(range.start(), range.end(), &builder->references[0], dim);
+ /* Sort references. */
+ bvh_reference_sort(range.start(),
+ range.end(),
+ &references_->at(0),
+ dim);
/* sweep right to left and determine bounds. */
BoundBox right_bounds = BoundBox::empty;
+ storage_->right_bounds.resize(range.size());
for(int i = range.size() - 1; i > 0; i--) {
right_bounds.grow(ref_ptr[i].bounds());
- builder->spatial_right_bounds[i - 1] = right_bounds;
+ storage_->right_bounds[i - 1] = right_bounds;
}
/* sweep left to right and select lowest SAH. */
@@ -51,7 +65,7 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, const BVHRange& range, float n
for(int i = 1; i < range.size(); i++) {
left_bounds.grow(ref_ptr[i - 1].bounds());
- right_bounds = builder->spatial_right_bounds[i - 1];
+ right_bounds = storage_->right_bounds[i - 1];
float sah = nodeSAH +
left_bounds.safe_area() * builder->params.primitive_cost(i) +
@@ -70,10 +84,15 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, const BVHRange& range, float n
}
}
-void BVHObjectSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)
+void BVHObjectSplit::split(BVHRange& left,
+ BVHRange& right,
+ const BVHRange& range)
{
/* sort references according to split */
- bvh_reference_sort(range.start(), range.end(), &builder->references[0], this->dim);
+ bvh_reference_sort(range.start(),
+ range.end(),
+ &references_->at(0),
+ this->dim);
/* split node ranges */
left = BVHRange(this->left_bounds, range.start(), this->num_left);
@@ -83,8 +102,16 @@ void BVHObjectSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, c
/* Spatial Split */
-BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float nodeSAH)
-: sah(FLT_MAX), dim(0), pos(0.0f)
+BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder,
+ BVHSpatialStorage *storage,
+ const BVHRange& range,
+ vector<BVHReference> *references,
+ float nodeSAH)
+: sah(FLT_MAX),
+ dim(0),
+ pos(0.0f),
+ storage_(storage),
+ references_(references)
{
/* initialize bins. */
float3 origin = range.bounds().min;
@@ -93,7 +120,7 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
for(int dim = 0; dim < 3; dim++) {
for(int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
- BVHSpatialBin& bin = builder->spatial_bins[dim][i];
+ BVHSpatialBin& bin = storage_->bins[dim][i];
bin.bounds = BoundBox::empty;
bin.enter = 0;
@@ -103,7 +130,7 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
/* chop references into bins. */
for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) {
- const BVHReference& ref = builder->references[refIdx];
+ const BVHReference& ref = references_->at(refIdx);
float3 firstBinf = (ref.bounds().min - origin) * invBinSize;
float3 lastBinf = (ref.bounds().max - origin) * invBinSize;
int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
@@ -119,13 +146,13 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
BVHReference leftRef, rightRef;
split_reference(builder, leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
- builder->spatial_bins[dim][i].bounds.grow(leftRef.bounds());
+ storage_->bins[dim][i].bounds.grow(leftRef.bounds());
currRef = rightRef;
}
- builder->spatial_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
- builder->spatial_bins[dim][firstBin[dim]].enter++;
- builder->spatial_bins[dim][lastBin[dim]].exit++;
+ storage_->bins[dim][lastBin[dim]].bounds.grow(currRef.bounds());
+ storage_->bins[dim][firstBin[dim]].enter++;
+ storage_->bins[dim][lastBin[dim]].exit++;
}
}
@@ -134,9 +161,10 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
/* sweep right to left and determine bounds. */
BoundBox right_bounds = BoundBox::empty;
+ storage_->right_bounds.resize(BVHParams::NUM_SPATIAL_BINS);
for(int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
- right_bounds.grow(builder->spatial_bins[dim][i].bounds);
- builder->spatial_right_bounds[i - 1] = right_bounds;
+ right_bounds.grow(storage_->bins[dim][i].bounds);
+ storage_->right_bounds[i - 1] = right_bounds;
}
/* sweep left to right and select lowest SAH. */
@@ -145,13 +173,13 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
int rightNum = range.size();
for(int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
- left_bounds.grow(builder->spatial_bins[dim][i - 1].bounds);
- leftNum += builder->spatial_bins[dim][i - 1].enter;
- rightNum -= builder->spatial_bins[dim][i - 1].exit;
+ left_bounds.grow(storage_->bins[dim][i - 1].bounds);
+ leftNum += storage_->bins[dim][i - 1].enter;
+ rightNum -= storage_->bins[dim][i - 1].exit;
float sah = nodeSAH +
- left_bounds.safe_area() * builder->params.primitive_cost(leftNum) +
- builder->spatial_right_bounds[i - 1].safe_area() * builder->params.primitive_cost(rightNum);
+ left_bounds.safe_area() * builder.params.primitive_cost(leftNum) +
+ storage_->right_bounds[i - 1].safe_area() * builder.params.primitive_cost(rightNum);
if(sah < this->sah) {
this->sah = sah;
@@ -162,7 +190,10 @@ BVHSpatialSplit::BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float
}
}
-void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)
+void BVHSpatialSplit::split(BVHBuild *builder,
+ BVHRange& left,
+ BVHRange& right,
+ const BVHRange& range)
{
/* Categorize references and compute bounds.
*
@@ -170,7 +201,7 @@ void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right,
* Uncategorized/split: [left_end, right_start[
* Right-hand side: [right_start, refs.size()[ */
- vector<BVHReference>& refs = builder->references;
+ vector<BVHReference>& refs = *references_;
int left_start = range.start();
int left_end = left_start;
int right_start = range.end();
@@ -196,12 +227,13 @@ void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right,
* Duplication happens into a temporary pre-allocated vector in order to
* reduce number of memmove() calls happening in vector.insert().
*/
- vector<BVHReference> new_refs;
+ vector<BVHReference>& new_refs = storage_->new_references;
+ new_refs.clear();
new_refs.reserve(right_start - left_end);
while(left_end < right_start) {
/* split reference. */
BVHReference lref, rref;
- split_reference(builder, lref, rref, refs[left_end], this->dim, this->pos);
+ split_reference(*builder, lref, rref, refs[left_end], this->dim, this->pos);
/* compute SAH for duplicate/unsplit candidates. */
BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds.
@@ -245,7 +277,7 @@ void BVHSpatialSplit::split(BVHBuild *builder, BVHRange& left, BVHRange& right,
}
/* Insert duplicated references into actual array in one go. */
if(new_refs.size() != 0) {
- refs.insert(refs.begin() + right_end - new_refs.size(),
+ refs.insert(refs.begin() + (right_end - new_refs.size()),
new_refs.begin(),
new_refs.end());
}
@@ -401,7 +433,7 @@ void BVHSpatialSplit::split_object_reference(const Object *object,
}
}
-void BVHSpatialSplit::split_reference(BVHBuild *builder,
+void BVHSpatialSplit::split_reference(const BVHBuild& builder,
BVHReference& left,
BVHReference& right,
const BVHReference& ref,
@@ -413,7 +445,7 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder,
BoundBox right_bounds = BoundBox::empty;
/* loop over vertices/edges. */
- Object *ob = builder->objects[ref.prim_object()];
+ const Object *ob = builder.objects[ref.prim_object()];
const Mesh *mesh = ob->mesh;
if(ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
@@ -452,4 +484,3 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder,
}
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h
index 1e46bb66203..aea8b2565e0 100644
--- a/intern/cycles/bvh/bvh_split.h
+++ b/intern/cycles/bvh/bvh_split.h
@@ -37,9 +37,19 @@ public:
BoundBox right_bounds;
BVHObjectSplit() {}
- BVHObjectSplit(BVHBuild *builder, const BVHRange& range, float nodeSAH);
+ BVHObjectSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange& range,
+ vector<BVHReference> *references,
+ float nodeSAH);
- void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range);
+ void split(BVHRange& left,
+ BVHRange& right,
+ const BVHRange& range);
+
+protected:
+ BVHSpatialStorage *storage_;
+ vector<BVHReference> *references_;
};
/* Spatial Split */
@@ -51,11 +61,23 @@ public:
int dim;
float pos;
- BVHSpatialSplit() : sah(FLT_MAX), dim(0), pos(0.0f) {}
- BVHSpatialSplit(BVHBuild *builder, const BVHRange& range, float nodeSAH);
-
- void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range);
- void split_reference(BVHBuild *builder,
+ BVHSpatialSplit() : sah(FLT_MAX),
+ dim(0),
+ pos(0.0f),
+ storage_(NULL),
+ references_(NULL) {}
+ BVHSpatialSplit(const BVHBuild& builder,
+ BVHSpatialStorage *storage,
+ const BVHRange& range,
+ vector<BVHReference> *references,
+ float nodeSAH);
+
+ void split(BVHBuild *builder,
+ BVHRange& left,
+ BVHRange& right,
+ const BVHRange& range);
+
+ void split_reference(const BVHBuild& builder,
BVHReference& left,
BVHReference& right,
const BVHReference& ref,
@@ -63,6 +85,9 @@ public:
float pos);
protected:
+ BVHSpatialStorage *storage_;
+ vector<BVHReference> *references_;
+
/* Lower-level functions which calculates boundaries of left and right nodes
* needed for spatial split.
*
@@ -123,7 +148,11 @@ public:
bool no_split;
- __forceinline BVHMixedSplit(BVHBuild *builder, const BVHRange& range, int level)
+ __forceinline BVHMixedSplit(BVHBuild *builder,
+ BVHSpatialStorage *storage,
+ const BVHRange& range,
+ vector<BVHReference> *references,
+ int level)
{
/* find split candidates. */
float area = range.bounds().safe_area();
@@ -131,19 +160,25 @@ public:
leafSAH = area * builder->params.primitive_cost(range.size());
nodeSAH = area * builder->params.node_cost(2);
- object = BVHObjectSplit(builder, range, nodeSAH);
+ object = BVHObjectSplit(builder, storage, range, references, nodeSAH);
if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
BoundBox overlap = object.left_bounds;
overlap.intersect(object.right_bounds);
- if(overlap.safe_area() >= builder->spatial_min_overlap)
- spatial = BVHSpatialSplit(builder, range, nodeSAH);
+ if(overlap.safe_area() >= builder->spatial_min_overlap) {
+ spatial = BVHSpatialSplit(*builder,
+ storage,
+ range,
+ references,
+ nodeSAH);
+ }
}
/* leaf SAH is the lowest => create leaf. */
minSAH = min(min(leafSAH, object.sah), spatial.sah);
- no_split = (minSAH == leafSAH && builder->range_within_max_leaf_size(range));
+ no_split = (minSAH == leafSAH &&
+ builder->range_within_max_leaf_size(range, *references));
}
__forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range)
@@ -151,7 +186,7 @@ public:
if(builder->params.use_spatial_split && minSAH == spatial.sah)
spatial.split(builder, left, right, range);
if(!left.size() || !right.size())
- object.split(builder, left, right, range);
+ object.split(left, right, range);
}
};
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index 10a166b6e44..616dd940801 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -37,7 +37,7 @@ endif()
###########################################################################
# CUDA
-if(WITH_CYCLES_CUDA_BINARIES)
+if(WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD)
find_package(CUDA) # Try to auto locate CUDA toolkit
if(CUDA_FOUND)
message(STATUS "CUDA nvcc = ${CUDA_NVCC_EXECUTABLE}")
@@ -132,11 +132,11 @@ if(CYCLES_STANDALONE_REPOSITORY)
unset(_lib_DIR)
else()
if(WIN32)
- set(GLOG_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/libmv/third_party/glog/src/windows)
- set(GFLAGS_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/libmv/third_party/gflags)
+ set(GLOG_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/glog/src/windows)
+ set(GFLAGS_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/gflags/src)
else()
- set(GLOG_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/libmv/third_party/glog/src)
- set(GFLAGS_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/libmv/third_party/gflags)
+ set(GLOG_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/glog/src)
+ set(GFLAGS_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/gflags/src)
endif()
set(GFLAGS_NAMESPACE "gflags")
set(LLVM_LIBRARIES ${LLVM_LIBRARY})
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index b0fa283c1d8..2a9ec0c3818 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -11,10 +11,21 @@ set(INC
set(INC_SYS
${GLEW_INCLUDE_DIR}
- ../../../extern/cuew/include
../../../extern/clew/include
)
+if(WITH_CUDA_DYNLOAD)
+ list(APPEND INC
+ ../../../extern/cuew/include
+ )
+ add_definitions(-DWITH_CUDA_DYNLOAD)
+else()
+ list(APPEND INC_SYS
+ ${CUDA_TOOLKIT_INCLUDE}
+ )
+ add_definitions(-DCYCLES_CUDA_NVCC_EXECUTABLE="${CUDA_NVCC_EXECUTABLE}")
+endif()
+
set(SRC
device.cpp
device_cpu.cpp
@@ -39,6 +50,18 @@ set(SRC_HEADERS
)
add_definitions(${GL_DEFINITIONS})
+if(WITH_CYCLES_NETWORK)
+ add_definitions(-DWITH_NETWORK)
+endif()
+if(WITH_CYCLES_DEVICE_OPENCL)
+ add_definitions(-DWITH_OPENCL)
+endif()
+if(WITH_CYCLES_DEVICE_CUDA)
+ add_definitions(-DWITH_CUDA)
+endif()
+if(WITH_CYCLES_DEVICE_MULTI)
+ add_definitions(-DWITH_MULTI)
+endif()
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index fc9959e0b48..8c01bcb116f 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -28,9 +28,15 @@
#include "util_time.h"
#include "util_types.h"
#include "util_vector.h"
+#include "util_string.h"
CCL_NAMESPACE_BEGIN
+bool Device::need_types_update = true;
+bool Device::need_devices_update = true;
+vector<DeviceType> Device::types;
+vector<DeviceInfo> Device::devices;
+
/* Device Requested Features */
std::ostream& operator <<(std::ostream &os,
@@ -42,15 +48,14 @@ std::ostream& operator <<(std::ostream &os,
os << "Max nodes group: " << requested_features.max_nodes_group << std::endl;
/* TODO(sergey): Decode bitflag into list of names. */
os << "Nodes features: " << requested_features.nodes_features << std::endl;
- /* TODO(sergey): Make it utility function to convert bool to string. */
os << "Use hair: "
- << (requested_features.use_hair ? "True" : "False") << std::endl;
+ << string_from_bool(requested_features.use_hair) << std::endl;
os << "Use object motion: "
- << (requested_features.use_object_motion ? "True" : "False") << std::endl;
+ << string_from_bool(requested_features.use_object_motion) << std::endl;
os << "Use camera motion: "
- << (requested_features.use_camera_motion ? "True" : "False") << std::endl;
+ << string_from_bool(requested_features.use_camera_motion) << std::endl;
os << "Use Baking: "
- << (requested_features.use_baking ? "True" : "False") << std::endl;
+ << string_from_bool(requested_features.use_baking) << std::endl;
return os;
}
@@ -277,10 +282,8 @@ string Device::string_from_type(DeviceType type)
vector<DeviceType>& Device::available_types()
{
- static vector<DeviceType> types;
- static bool types_init = false;
-
- if(!types_init) {
+ if(need_types_update) {
+ types.clear();
types.push_back(DEVICE_CPU);
#ifdef WITH_CUDA
@@ -300,7 +303,7 @@ vector<DeviceType>& Device::available_types()
types.push_back(DEVICE_MULTI);
#endif
- types_init = true;
+ need_types_update = false;
}
return types;
@@ -308,10 +311,8 @@ vector<DeviceType>& Device::available_types()
vector<DeviceInfo>& Device::available_devices()
{
- static vector<DeviceInfo> devices;
- static bool devices_init = false;
-
- if(!devices_init) {
+ if(need_devices_update) {
+ devices.clear();
#ifdef WITH_CUDA
if(device_cuda_init())
device_cuda_info(devices);
@@ -332,7 +333,7 @@ vector<DeviceInfo>& Device::available_devices()
device_network_info(devices);
#endif
- devices_init = true;
+ need_devices_update = false;
}
return devices;
@@ -359,4 +360,18 @@ string Device::device_capabilities()
return capabilities;
}
+void Device::tag_update()
+{
+ need_types_update = true;
+ need_devices_update = true;
+}
+
+void Device::free_memory()
+{
+ need_types_update = true;
+ need_devices_update = true;
+ types.free_memory();
+ devices.free_memory();
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 3c0fb880948..30d0003b940 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -100,6 +100,12 @@ public:
/* Denotes whether baking functionality is needed. */
bool use_baking;
+ /* Use subsurface scattering materials. */
+ bool use_subsurface;
+
+ /* Use branched integrator. */
+ bool use_integrator_branched;
+
DeviceRequestedFeatures()
{
/* TODO(sergey): Find more meaningful defaults. */
@@ -111,6 +117,8 @@ public:
use_object_motion = false;
use_camera_motion = false;
use_baking = false;
+ use_subsurface = false;
+ use_integrator_branched = false;
}
bool modified(const DeviceRequestedFeatures& requested_features)
@@ -122,9 +130,45 @@ public:
use_hair == requested_features.use_hair &&
use_object_motion == requested_features.use_object_motion &&
use_camera_motion == requested_features.use_camera_motion &&
- use_baking == requested_features.use_baking);
+ use_baking == requested_features.use_baking &&
+ use_subsurface == requested_features.use_subsurface &&
+ use_integrator_branched == requested_features.use_integrator_branched);
}
+ /* Convert the requested features structure to a build options,
+ * which could then be passed to compilers.
+ */
+ string get_build_options(void) const
+ {
+ string build_options = "";
+ if(experimental) {
+ build_options += "-D__KERNEL_EXPERIMENTAL__ ";
+ }
+ build_options += "-D__NODES_MAX_GROUP__=" +
+ string_printf("%d", max_nodes_group);
+ build_options += " -D__NODES_FEATURES__=" +
+ string_printf("%d", nodes_features);
+ build_options += string_printf(" -D__MAX_CLOSURE__=%d", max_closure);
+ if(!use_hair) {
+ build_options += " -D__NO_HAIR__";
+ }
+ if(!use_object_motion) {
+ build_options += " -D__NO_OBJECT_MOTION__";
+ }
+ if(!use_camera_motion) {
+ build_options += " -D__NO_CAMERA_MOTION__";
+ }
+ if(!use_baking) {
+ build_options += " -D__NO_BAKING__";
+ }
+ if(!use_subsurface) {
+ build_options += " -D__NO_SUBSURFACE__";
+ }
+ if(!use_integrator_branched) {
+ build_options += " -D__NO_BRANCHED_PATH__";
+ }
+ return build_options;
+ }
};
std::ostream& operator <<(std::ostream &os,
@@ -221,6 +265,16 @@ public:
static vector<DeviceType>& available_types();
static vector<DeviceInfo>& available_devices();
static string device_capabilities();
+
+ /* Tag devices lists for update. */
+ static void tag_update();
+
+ static void free_memory();
+private:
+ /* Indicted whether device types and devices lists were initialized. */
+ static bool need_types_update, need_devices_update;
+ static vector<DeviceType> types;
+ static vector<DeviceInfo> devices;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp
index f06963c146e..676b1279a80 100644
--- a/intern/cycles/device/device_cpu.cpp
+++ b/intern/cycles/device/device_cpu.cpp
@@ -19,15 +19,8 @@
/* So ImathMath is included before our kernel_cpu_compat. */
#ifdef WITH_OSL
-# if defined(_MSC_VER)
-/* Prevent OSL from polluting the context with weird macros from windows.h.
- * TODO(sergey): Ideally it's only enough to have class/struct declarations in
- * the header and skip header include here.
- */
-# define NOGDI
-# define NOMINMAX
-# define WIN32_LEAN_AND_MEAN
-# endif
+/* So no context pollution happens from indirectly included windows.h */
+# include "util_windows.h"
# include <OSL/oslexec.h>
#endif
@@ -78,6 +71,40 @@ public:
system_cpu_support_sse41();
system_cpu_support_avx();
system_cpu_support_avx2();
+
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
+ if(system_cpu_support_avx2()) {
+ VLOG(1) << "Will be using AVX2 kernels.";
+ }
+ else
+#endif
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
+ if(system_cpu_support_avx()) {
+ VLOG(1) << "Will be using AVX kernels.";
+ }
+ else
+#endif
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
+ if(system_cpu_support_sse41()) {
+ VLOG(1) << "Will be using SSE4.1 kernels.";
+ }
+ else
+#endif
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
+ if(system_cpu_support_sse3()) {
+ VLOG(1) << "Will be using SSE3kernels.";
+ }
+ else
+#endif
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
+ if(system_cpu_support_sse2()) {
+ VLOG(1) << "Will be using SSE2 kernels.";
+ }
+ else
+#endif
+ {
+ VLOG(1) << "Will be using regular kernels.";
+ }
}
~CPUDevice()
@@ -197,31 +224,38 @@ public:
void(*path_trace_kernel)(KernelGlobals*, float*, unsigned int*, int, int, int, int, int);
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
- if(system_cpu_support_avx2())
+ if(system_cpu_support_avx2()) {
path_trace_kernel = kernel_cpu_avx2_path_trace;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
- if(system_cpu_support_avx())
+ if(system_cpu_support_avx()) {
path_trace_kernel = kernel_cpu_avx_path_trace;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
- if(system_cpu_support_sse41())
+ if(system_cpu_support_sse41()) {
path_trace_kernel = kernel_cpu_sse41_path_trace;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
- if(system_cpu_support_sse3())
+ if(system_cpu_support_sse3()) {
path_trace_kernel = kernel_cpu_sse3_path_trace;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
- if(system_cpu_support_sse2())
+ if(system_cpu_support_sse2()) {
path_trace_kernel = kernel_cpu_sse2_path_trace;
+ }
else
#endif
+ {
path_trace_kernel = kernel_cpu_path_trace;
+ }
while(task.acquire_tile(this, tile)) {
float *render_buffer = (float*)tile.buffer;
@@ -267,32 +301,38 @@ public:
if(task.rgba_half) {
void(*convert_to_half_float_kernel)(KernelGlobals *, uchar4 *, float *, float, int, int, int, int);
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
- if(system_cpu_support_avx2())
+ if(system_cpu_support_avx2()) {
convert_to_half_float_kernel = kernel_cpu_avx2_convert_to_half_float;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
- if(system_cpu_support_avx())
- for(int y = task.y; y < task.y + task.h; y++)
+ if(system_cpu_support_avx()) {
convert_to_half_float_kernel = kernel_cpu_avx_convert_to_half_float;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
- if(system_cpu_support_sse41())
+ if(system_cpu_support_sse41()) {
convert_to_half_float_kernel = kernel_cpu_sse41_convert_to_half_float;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
- if(system_cpu_support_sse3())
+ if(system_cpu_support_sse3()) {
convert_to_half_float_kernel = kernel_cpu_sse3_convert_to_half_float;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
- if(system_cpu_support_sse2())
+ if(system_cpu_support_sse2()) {
convert_to_half_float_kernel = kernel_cpu_sse2_convert_to_half_float;
+ }
else
#endif
+ {
convert_to_half_float_kernel = kernel_cpu_convert_to_half_float;
+ }
for(int y = task.y; y < task.y + task.h; y++)
for(int x = task.x; x < task.x + task.w; x++)
@@ -302,31 +342,38 @@ public:
else {
void(*convert_to_byte_kernel)(KernelGlobals *, uchar4 *, float *, float, int, int, int, int);
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
- if(system_cpu_support_avx2())
+ if(system_cpu_support_avx2()) {
convert_to_byte_kernel = kernel_cpu_avx2_convert_to_byte;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
- if(system_cpu_support_avx())
+ if(system_cpu_support_avx()) {
convert_to_byte_kernel = kernel_cpu_avx_convert_to_byte;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
- if(system_cpu_support_sse41())
+ if(system_cpu_support_sse41()) {
convert_to_byte_kernel = kernel_cpu_sse41_convert_to_byte;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
- if(system_cpu_support_sse3())
+ if(system_cpu_support_sse3()) {
convert_to_byte_kernel = kernel_cpu_sse3_convert_to_byte;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
- if(system_cpu_support_sse2())
+ if(system_cpu_support_sse2()) {
convert_to_byte_kernel = kernel_cpu_sse2_convert_to_byte;
+ }
else
#endif
+ {
convert_to_byte_kernel = kernel_cpu_convert_to_byte;
+ }
for(int y = task.y; y < task.y + task.h; y++)
for(int x = task.x; x < task.x + task.w; x++)
@@ -343,39 +390,53 @@ public:
#ifdef WITH_OSL
OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
#endif
- void(*shader_kernel)(KernelGlobals*, uint4*, float4*, int, int, int, int);
+ void(*shader_kernel)(KernelGlobals*, uint4*, float4*, float*, int, int, int, int, int);
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
- if(system_cpu_support_avx2())
+ if(system_cpu_support_avx2()) {
shader_kernel = kernel_cpu_avx2_shader;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
- if(system_cpu_support_avx())
+ if(system_cpu_support_avx()) {
shader_kernel = kernel_cpu_avx_shader;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
- if(system_cpu_support_sse41())
+ if(system_cpu_support_sse41()) {
shader_kernel = kernel_cpu_sse41_shader;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
- if(system_cpu_support_sse3())
+ if(system_cpu_support_sse3()) {
shader_kernel = kernel_cpu_sse3_shader;
+ }
else
#endif
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
- if(system_cpu_support_sse2())
+ if(system_cpu_support_sse2()) {
shader_kernel = kernel_cpu_sse2_shader;
+ }
else
#endif
+ {
shader_kernel = kernel_cpu_shader;
+ }
for(int sample = 0; sample < task.num_samples; sample++) {
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++)
- shader_kernel(&kg, (uint4*)task.shader_input, (float4*)task.shader_output,
- task.shader_eval_type, x, task.offset, sample);
+ shader_kernel(&kg,
+ (uint4*)task.shader_input,
+ (float4*)task.shader_output,
+ (float*)task.shader_output_luma,
+ task.shader_eval_type,
+ task.shader_filter,
+ x,
+ task.offset,
+ sample);
if(task.get_cancel() || task_pool.canceled())
break;
diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp
index a47d4edeb56..f1a17d652da 100644
--- a/intern/cycles/device/device_cuda.cpp
+++ b/intern/cycles/device/device_cuda.cpp
@@ -23,10 +23,17 @@
#include "buffers.h"
-#include "cuew.h"
+#ifdef WITH_CUDA_DYNLOAD
+# include "cuew.h"
+#else
+# include "util_opengl.h"
+# include <cuda.h>
+# include <cudaGL.h>
+#endif
#include "util_debug.h"
#include "util_logging.h"
#include "util_map.h"
+#include "util_md5.h"
#include "util_opengl.h"
#include "util_path.h"
#include "util_string.h"
@@ -34,8 +41,47 @@
#include "util_types.h"
#include "util_time.h"
+/* use feature-adaptive kernel compilation.
+ * Requires CUDA toolkit to be installed and currently only works on Linux.
+ */
+/* #define KERNEL_USE_ADAPTIVE */
+
CCL_NAMESPACE_BEGIN
+#ifndef WITH_CUDA_DYNLOAD
+
+/* Transparently implement some functions, so majority of the file does not need
+ * to worry about difference between dynamically loaded and linked CUDA at all.
+ */
+
+namespace {
+
+const char *cuewErrorString(CUresult result)
+{
+ /* We can only give error code here without major code duplication, that
+ * should be enough since dynamic loading is only being disabled by folks
+ * who knows what they're doing anyway.
+ *
+ * NOTE: Avoid call from several threads.
+ */
+ static string error;
+ error = string_printf("%d", result);
+ return error.c_str();
+}
+
+const char *cuewCompilerPath(void)
+{
+ return CYCLES_CUDA_NVCC_EXECUTABLE;
+}
+
+int cuewCompilerVersion(void)
+{
+ return (CUDA_VERSION / 100) + (CUDA_VERSION % 100 / 10);
+}
+
+} /* namespace */
+#endif /* WITH_CUDA_DYNLOAD */
+
class CUDADevice : public Device
{
public:
@@ -185,21 +231,21 @@ public:
cuda_assert(cuCtxDestroy(cuContext));
}
- bool support_device(bool /*experimental*/)
+ bool support_device(const DeviceRequestedFeatures& /*requested_features*/)
{
int major, minor;
cuDeviceComputeCapability(&major, &minor, cuDevId);
-
+
/* We only support sm_20 and above */
if(major < 2) {
cuda_error_message(string_printf("CUDA device supported only with compute capability 2.0 or up, found %d.%d.", major, minor));
return false;
}
-
+
return true;
}
- string compile_kernel(bool experimental)
+ string compile_kernel(const DeviceRequestedFeatures& requested_features)
{
/* compute cubin name */
int major, minor;
@@ -207,10 +253,7 @@ public:
string cubin;
/* attempt to use kernel provided with blender */
- if(experimental)
- cubin = path_get(string_printf("lib/kernel_experimental_sm_%d%d.cubin", major, minor));
- else
- cubin = path_get(string_printf("lib/kernel_sm_%d%d.cubin", major, minor));
+ cubin = path_get(string_printf("lib/kernel_sm_%d%d.cubin", major, minor));
VLOG(1) << "Testing for pre-compiled kernel " << cubin;
if(path_exists(cubin)) {
VLOG(1) << "Using precompiled kernel";
@@ -221,10 +264,18 @@ public:
string kernel_path = path_get("kernel");
string md5 = path_files_md5_hash(kernel_path);
- if(experimental)
- cubin = string_printf("cycles_kernel_experimental_sm%d%d_%s.cubin", major, minor, md5.c_str());
- else
- cubin = string_printf("cycles_kernel_sm%d%d_%s.cubin", major, minor, md5.c_str());
+#ifdef KERNEL_USE_ADAPTIVE
+ string feature_build_options = requested_features.get_build_options();
+ string device_md5 = util_md5_string(feature_build_options);
+ cubin = string_printf("cycles_kernel_%s_sm%d%d_%s.cubin",
+ device_md5.c_str(),
+ major, minor,
+ md5.c_str());
+#else
+ (void)requested_features;
+ cubin = string_printf("cycles_kernel_sm%d%d_%s.cubin", major, minor, md5.c_str());
+#endif
+
cubin = path_user_get(path_join("cache", cubin));
VLOG(1) << "Testing for locally compiled kernel " << cubin;
/* if exists already, use it */
@@ -259,11 +310,11 @@ public:
return "";
}
if(cuda_version < 60) {
- printf("Unsupported CUDA version %d.%d detected, you need CUDA 6.5.\n", cuda_version/10, cuda_version%10);
+ printf("Unsupported CUDA version %d.%d detected, you need CUDA 7.5.\n", cuda_version/10, cuda_version%10);
return "";
}
- else if(cuda_version != 65)
- printf("CUDA version %d.%d detected, build may succeed but only CUDA 6.5 is officially supported.\n", cuda_version/10, cuda_version%10);
+ else if(cuda_version != 75)
+ printf("CUDA version %d.%d detected, build may succeed but only CUDA 7.5 is officially supported.\n", cuda_version/10, cuda_version%10);
/* compile */
string kernel = path_join(kernel_path, path_join("kernels", path_join("cuda", "kernel.cu")));
@@ -279,12 +330,14 @@ public:
"-o \"%s\" --ptxas-options=\"-v\" --use_fast_math -I\"%s\" "
"-DNVCC -D__KERNEL_CUDA_VERSION__=%d",
nvcc, major, minor, machine, kernel.c_str(), cubin.c_str(), include.c_str(), cuda_version);
-
- if(experimental)
- command += " -D__KERNEL_EXPERIMENTAL__";
- if(getenv("CYCLES_CUDA_EXTRA_CFLAGS")) {
- command += string(" ") + getenv("CYCLES_CUDA_EXTRA_CFLAGS");
+#ifdef KERNEL_USE_ADAPTIVE
+ command += " " + feature_build_options;
+#endif
+
+ const char* extra_cflags = getenv("CYCLES_CUDA_EXTRA_CFLAGS");
+ if(extra_cflags) {
+ command += string(" ") + string(extra_cflags);
}
#ifdef WITH_CYCLES_DEBUG
@@ -314,13 +367,13 @@ public:
/* check if cuda init succeeded */
if(cuContext == 0)
return false;
-
+
/* check if GPU is supported */
- if(!support_device(requested_features.experimental))
+ if(!support_device(requested_features))
return false;
/* get kernel */
- string cubin = compile_kernel(requested_features.experimental);
+ string cubin = compile_kernel(requested_features);
if(cubin == "")
return false;
@@ -421,9 +474,20 @@ public:
InterpolationType interpolation,
ExtensionType extension)
{
- /* todo: support 3D textures, only CPU for now */
VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes.";
+ string bind_name = name;
+ if(mem.data_depth > 1) {
+ /* Kernel uses different bind names for 2d and 3d float textures,
+ * so we have to adjust couple of things here.
+ */
+ vector<string> tokens;
+ string_split(tokens, name, "_");
+ bind_name = string_printf("__tex_image_%s3d_%s",
+ tokens[2].c_str(),
+ tokens[3].c_str());
+ }
+
/* determine format */
CUarray_format_enum format;
size_t dsize = datatype_size(mem.data_type);
@@ -443,7 +507,7 @@ public:
CUtexref texref = NULL;
cuda_push_context();
- cuda_assert(cuModuleGetTexRef(&texref, cuModule, name));
+ cuda_assert(cuModuleGetTexRef(&texref, cuModule, bind_name.c_str()));
if(!texref) {
cuda_pop_context();
@@ -452,20 +516,49 @@ public:
if(interpolation != INTERPOLATION_NONE) {
CUarray handle = NULL;
- CUDA_ARRAY_DESCRIPTOR desc;
- desc.Width = mem.data_width;
- desc.Height = mem.data_height;
- desc.Format = format;
- desc.NumChannels = mem.data_elements;
+ if(mem.data_depth > 1) {
+ CUDA_ARRAY3D_DESCRIPTOR desc;
+
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Depth = mem.data_depth;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+ desc.Flags = 0;
+
+ cuda_assert(cuArray3DCreate(&handle, &desc));
+ }
+ else {
+ CUDA_ARRAY_DESCRIPTOR desc;
- cuda_assert(cuArrayCreate(&handle, &desc));
+ desc.Width = mem.data_width;
+ desc.Height = mem.data_height;
+ desc.Format = format;
+ desc.NumChannels = mem.data_elements;
+
+ cuda_assert(cuArrayCreate(&handle, &desc));
+ }
if(!handle) {
cuda_pop_context();
return;
}
+ if(mem.data_depth > 1) {
+ CUDA_MEMCPY3D param;
+ memset(&param, 0, sizeof(param));
+ param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
+ param.dstArray = handle;
+ param.srcMemoryType = CU_MEMORYTYPE_HOST;
+ param.srcHost = (void*)mem.data_pointer;
+ param.srcPitch = mem.data_width*dsize*mem.data_elements;
+ param.WidthInBytes = param.srcPitch;
+ param.Height = mem.data_height;
+ param.Depth = mem.data_depth;
+
+ cuda_assert(cuMemcpy3D(&param));
+ }
if(mem.data_height > 1) {
CUDA_MEMCPY2D param;
memset(&param, 0, sizeof(param));
@@ -513,20 +606,27 @@ public:
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER));
}
+ CUaddress_mode address_mode = CU_TR_ADDRESS_MODE_WRAP;
switch(extension) {
case EXTENSION_REPEAT:
- cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_WRAP));
- cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_WRAP));
+ address_mode = CU_TR_ADDRESS_MODE_WRAP;
break;
case EXTENSION_EXTEND:
- cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_CLAMP));
- cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_CLAMP));
+ address_mode = CU_TR_ADDRESS_MODE_CLAMP;
break;
case EXTENSION_CLIP:
- cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_BORDER));
- cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_BORDER));
+ address_mode = CU_TR_ADDRESS_MODE_BORDER;
+ break;
+ default:
+ assert(0);
break;
}
+ cuda_assert(cuTexRefSetAddressMode(texref, 0, address_mode));
+ cuda_assert(cuTexRefSetAddressMode(texref, 1, address_mode));
+ if(mem.data_depth > 1) {
+ cuda_assert(cuTexRefSetAddressMode(texref, 2, address_mode));
+ }
+
cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements));
cuda_pop_context();
@@ -540,7 +640,7 @@ public:
CUdeviceptr cumem;
size_t cubytes;
- cuda_assert(cuModuleGetGlobal(&cumem, &cubytes, cuModule, name));
+ cuda_assert(cuModuleGetGlobal(&cumem, &cubytes, cuModule, bind_name.c_str()));
if(cubytes == 8) {
/* 64 bit device pointer */
@@ -604,14 +704,14 @@ public:
/* pass in parameters */
void *args[] = {&d_buffer,
- &d_rng_state,
- &sample,
- &rtile.x,
- &rtile.y,
- &rtile.w,
- &rtile.h,
- &rtile.offset,
- &rtile.stride};
+ &d_rng_state,
+ &sample,
+ &rtile.x,
+ &rtile.y,
+ &rtile.w,
+ &rtile.h,
+ &rtile.offset,
+ &rtile.stride};
/* launch kernel */
int threads_per_block;
@@ -631,9 +731,9 @@ public:
cuda_assert(cuFuncSetCacheConfig(cuPathTrace, CU_FUNC_CACHE_PREFER_L1));
cuda_assert(cuLaunchKernel(cuPathTrace,
- xblocks , yblocks, 1, /* blocks */
- xthreads, ythreads, 1, /* threads */
- 0, 0, args, 0));
+ xblocks , yblocks, 1, /* blocks */
+ xthreads, ythreads, 1, /* threads */
+ 0, 0, args, 0));
cuda_assert(cuCtxSynchronize());
@@ -664,14 +764,14 @@ public:
/* pass in parameters */
void *args[] = {&d_rgba,
- &d_buffer,
- &sample_scale,
- &task.x,
- &task.y,
- &task.w,
- &task.h,
- &task.offset,
- &task.stride};
+ &d_buffer,
+ &sample_scale,
+ &task.x,
+ &task.y,
+ &task.w,
+ &task.h,
+ &task.offset,
+ &task.stride};
/* launch kernel */
int threads_per_block;
@@ -685,9 +785,9 @@ public:
cuda_assert(cuFuncSetCacheConfig(cuFilmConvert, CU_FUNC_CACHE_PREFER_L1));
cuda_assert(cuLaunchKernel(cuFilmConvert,
- xblocks , yblocks, 1, /* blocks */
- xthreads, ythreads, 1, /* threads */
- 0, 0, args, 0));
+ xblocks , yblocks, 1, /* blocks */
+ xthreads, ythreads, 1, /* threads */
+ 0, 0, args, 0));
unmap_pixels((rgba_byte)? rgba_byte: rgba_half);
@@ -704,6 +804,7 @@ public:
CUfunction cuShader;
CUdeviceptr d_input = cuda_device_ptr(task.shader_input);
CUdeviceptr d_output = cuda_device_ptr(task.shader_output);
+ CUdeviceptr d_output_luma = cuda_device_ptr(task.shader_output_luma);
/* get kernel function */
if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
@@ -725,13 +826,21 @@ public:
int shader_w = min(shader_chunk_size, end - shader_x);
/* pass in parameters */
- void *args[] = {&d_input,
- &d_output,
- &task.shader_eval_type,
- &shader_x,
- &shader_w,
- &offset,
- &sample};
+ void *args[8];
+ int arg = 0;
+ args[arg++] = &d_input;
+ args[arg++] = &d_output;
+ if(task.shader_eval_type < SHADER_EVAL_BAKE) {
+ args[arg++] = &d_output_luma;
+ }
+ args[arg++] = &task.shader_eval_type;
+ if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
+ args[arg++] = &task.shader_filter;
+ }
+ args[arg++] = &shader_x;
+ args[arg++] = &shader_w;
+ args[arg++] = &offset;
+ args[arg++] = &sample;
/* launch kernel */
int threads_per_block;
@@ -741,9 +850,9 @@ public:
cuda_assert(cuFuncSetCacheConfig(cuShader, CU_FUNC_CACHE_PREFER_L1));
cuda_assert(cuLaunchKernel(cuShader,
- xblocks , 1, 1, /* blocks */
- threads_per_block, 1, 1, /* threads */
- 0, 0, args, 0));
+ xblocks , 1, 1, /* blocks */
+ threads_per_block, 1, 1, /* threads */
+ 0, 0, args, 0));
cuda_assert(cuCtxSynchronize());
@@ -808,7 +917,7 @@ public:
if(mem.data_type == TYPE_HALF)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, pmem.w, pmem.h, 0, GL_RGBA, GL_HALF_FLOAT, NULL);
else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
@@ -907,13 +1016,13 @@ public:
else
offset *= sizeof(uint8_t);
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pmem.cuPBO);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
if(mem.data_type == TYPE_HALF)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, (void*)offset);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glEnable(GL_TEXTURE_2D);
@@ -1072,6 +1181,7 @@ public:
bool device_cuda_init(void)
{
+#ifdef WITH_CUDA_DYNLOAD
static bool initialized = false;
static bool result = false;
@@ -1083,12 +1193,12 @@ bool device_cuda_init(void)
if(cuew_result == CUEW_SUCCESS) {
VLOG(1) << "CUEW initialization succeeded";
if(CUDADevice::have_precompiled_kernels()) {
- VLOG(1) << "Found precompiled kernels";
+ VLOG(1) << "Found precompiled kernels";
result = true;
}
#ifndef _WIN32
else if(cuewCompilerPath() != NULL) {
- VLOG(1) << "Found CUDA compiled " << cuewCompilerPath();
+ VLOG(1) << "Found CUDA compiler " << cuewCompilerPath();
result = true;
}
else {
@@ -1105,6 +1215,9 @@ bool device_cuda_init(void)
}
return result;
+#else /* WITH_CUDA_DYNLOAD */
+ return true;
+#endif /* WITH_CUDA_DYNLOAD */
}
Device *device_cuda_create(DeviceInfo& info, Stats &stats, bool background)
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index ba79f8c88ae..8c32d03135e 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -211,7 +211,10 @@ public:
T *resize(size_t width, size_t height = 0, size_t depth = 0)
{
data_size = width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth);
- data.resize(data_size);
+ if(data.resize(data_size) == NULL) {
+ clear();
+ return NULL;
+ }
data_width = width;
data_height = height;
data_depth = depth;
@@ -226,7 +229,9 @@ public:
T *copy(T *ptr, size_t width, size_t height = 0, size_t depth = 0)
{
T *mem = resize(width, height, depth);
- memcpy(mem, ptr, memory_size());
+ if(mem != NULL) {
+ memcpy(mem, ptr, memory_size());
+ }
return mem;
}
diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp
index 8fb841b2b0d..069305e8a29 100644
--- a/intern/cycles/device/device_multi.cpp
+++ b/intern/cycles/device/device_multi.cpp
@@ -316,6 +316,7 @@ public:
if(task.rgba_half) subtask.rgba_half = sub.ptr_map[task.rgba_half];
if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
+ if(task.shader_output_luma) subtask.shader_output_luma = sub.ptr_map[task.shader_output_luma];
sub.device->task_add(subtask);
}
diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp
index afa35224aba..cf4a05de8fc 100644
--- a/intern/cycles/device/device_network.cpp
+++ b/intern/cycles/device/device_network.cpp
@@ -648,6 +648,9 @@ protected:
if(task.shader_output)
task.shader_output = device_ptr_from_client_pointer(task.shader_output);
+ if(task.shader_output_luma)
+ task.shader_output_luma = device_ptr_from_client_pointer(task.shader_output_luma);
+
task.acquire_tile = function_bind(&DeviceServer::task_acquire_tile, this, _1, _2);
task.release_tile = function_bind(&DeviceServer::task_release_tile, this, _1);
diff --git a/intern/cycles/device/device_network.h b/intern/cycles/device/device_network.h
index 2e751f6697f..60ecc1d0a86 100644
--- a/intern/cycles/device/device_network.h
+++ b/intern/cycles/device/device_network.h
@@ -132,7 +132,7 @@ public:
archive & type & task.x & task.y & task.w & task.h;
archive & task.rgba_byte & task.rgba_half & task.buffer & task.sample & task.num_samples;
archive & task.offset & task.stride;
- archive & task.shader_input & task.shader_output & task.shader_eval_type;
+ archive & task.shader_input & task.shader_output & task.shader_output_luma & task.shader_eval_type;
archive & task.shader_x & task.shader_w;
archive & task.need_finish_queue;
}
@@ -291,7 +291,7 @@ public:
*archive & type & task.x & task.y & task.w & task.h;
*archive & task.rgba_byte & task.rgba_half & task.buffer & task.sample & task.num_samples;
*archive & task.offset & task.stride;
- *archive & task.shader_input & task.shader_output & task.shader_eval_type;
+ *archive & task.shader_input & task.shader_output & task.shader_output_luma & task.shader_eval_type;
*archive & task.shader_x & task.shader_w;
*archive & task.need_finish_queue;
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index c3392d27b2c..1b4e5421b5a 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -27,6 +27,7 @@
#include "buffers.h"
+#include "util_debug.h"
#include "util_foreach.h"
#include "util_logging.h"
#include "util_map.h"
@@ -84,29 +85,28 @@ namespace {
cl_device_type opencl_device_type()
{
- char *device = getenv("CYCLES_OPENCL_TEST");
-
- if(device) {
- if(strcmp(device, "NONE") == 0)
+ switch(DebugFlags().opencl.device_type)
+ {
+ case DebugFlags::OpenCL::DEVICE_NONE:
return 0;
- if(strcmp(device, "ALL") == 0)
+ case DebugFlags::OpenCL::DEVICE_ALL:
return CL_DEVICE_TYPE_ALL;
- else if(strcmp(device, "DEFAULT") == 0)
+ case DebugFlags::OpenCL::DEVICE_DEFAULT:
return CL_DEVICE_TYPE_DEFAULT;
- else if(strcmp(device, "CPU") == 0)
+ case DebugFlags::OpenCL::DEVICE_CPU:
return CL_DEVICE_TYPE_CPU;
- else if(strcmp(device, "GPU") == 0)
+ case DebugFlags::OpenCL::DEVICE_GPU:
return CL_DEVICE_TYPE_GPU;
- else if(strcmp(device, "ACCELERATOR") == 0)
+ case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
return CL_DEVICE_TYPE_ACCELERATOR;
+ default:
+ return CL_DEVICE_TYPE_ALL;
}
-
- return CL_DEVICE_TYPE_ALL;
}
-bool opencl_kernel_use_debug()
+inline bool opencl_kernel_use_debug()
{
- return (getenv("CYCLES_OPENCL_DEBUG") != NULL);
+ return DebugFlags().opencl.debug;
}
bool opencl_kernel_use_advanced_shading(const string& platform)
@@ -129,9 +129,14 @@ bool opencl_kernel_use_advanced_shading(const string& platform)
bool opencl_kernel_use_split(const string& platform_name,
const cl_device_type device_type)
{
- if(getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST") != NULL) {
+ if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_SPLIT) {
+ VLOG(1) << "Forcing split kernel to use.";
return true;
}
+ if(DebugFlags().opencl.kernel_type == DebugFlags::OpenCL::KERNEL_MEGA) {
+ VLOG(1) << "Forcing mega kernel to use.";
+ return false;
+ }
/* TODO(sergey): Replace string lookups with more enum-like API,
* similar to device/vendor checks blender's gpu.
*/
@@ -224,8 +229,7 @@ bool opencl_device_version_check(cl_device_id device,
void opencl_get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices)
{
const bool force_all_platforms =
- (getenv("CYCLES_OPENCL_TEST") != NULL) ||
- (getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST")) != NULL;
+ (DebugFlags().opencl.kernel_type != DebugFlags::OpenCL::KERNEL_DEFAULT);
const cl_device_type device_type = opencl_device_type();
static bool first_time = true;
#define FIRST_VLOG(severity) if(first_time) VLOG(severity)
@@ -313,7 +317,7 @@ void opencl_get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices)
continue;
}
if(!opencl_device_version_check(device_id)) {
- FIRST_VLOG(2) << "Ignoting device " << device_name
+ FIRST_VLOG(2) << "Ignoring device " << device_name
<< " due to old compiler version.";
continue;
}
@@ -327,8 +331,8 @@ void opencl_get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices)
&device_type,
NULL) != CL_SUCCESS)
{
- FIRST_VLOG(2) << "Ignoting device " << device_name
- << ", faield to fetch device type.";
+ FIRST_VLOG(2) << "Ignoring device " << device_name
+ << ", failed to fetch device type.";
continue;
}
FIRST_VLOG(2) << "Adding new device " << device_name << ".";
@@ -339,7 +343,7 @@ void opencl_get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices)
device_name));
}
else {
- FIRST_VLOG(2) << "Ignoting device " << device_name
+ FIRST_VLOG(2) << "Ignoring device " << device_name
<< ", not officially supported yet.";
}
}
@@ -581,7 +585,7 @@ public:
ProgramName program_name,
thread_scoped_lock& slot_locker)
{
- switch (program_name) {
+ switch(program_name) {
case OCL_DEV_BASE_PROGRAM:
store_something<cl_program>(platform,
device,
@@ -990,7 +994,8 @@ public:
if(path_exists(clbin) && load_binary(kernel_path,
clbin,
build_flags,
- &cpProgram)) {
+ &cpProgram))
+ {
/* Kernel loaded from binary, nothing to do. */
VLOG(2) << "Loaded kernel from " << clbin << ".";
}
@@ -1110,7 +1115,7 @@ public:
{
/* this is blocking */
size_t size = mem.memory_size();
- if(size != 0){
+ if(size != 0) {
opencl_assert(clEnqueueWriteBuffer(cqCommandQueue,
CL_MEM_PTR(mem.device_pointer),
CL_TRUE,
@@ -1299,7 +1304,9 @@ public:
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
cl_mem d_input = CL_MEM_PTR(task.shader_input);
cl_mem d_output = CL_MEM_PTR(task.shader_output);
+ cl_mem d_output_luma = CL_MEM_PTR(task.shader_output_luma);
cl_int d_shader_eval_type = task.shader_eval_type;
+ cl_int d_shader_filter = task.shader_filter;
cl_int d_shader_x = task.shader_x;
cl_int d_shader_w = task.shader_w;
cl_int d_offset = task.offset;
@@ -1325,14 +1332,27 @@ public:
d_input,
d_output);
+ if(task.shader_eval_type < SHADER_EVAL_BAKE) {
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_output_luma);
+ }
+
#define KERNEL_TEX(type, ttype, name) \
- set_kernel_arg_mem(kernel, &start_arg_index, #name);
+ set_kernel_arg_mem(kernel, &start_arg_index, #name);
#include "kernel_textures.h"
#undef KERNEL_TEX
start_arg_index += kernel_set_args(kernel,
start_arg_index,
- d_shader_eval_type,
+ d_shader_eval_type);
+ if(task.shader_eval_type >= SHADER_EVAL_BAKE) {
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
+ d_shader_filter);
+ }
+ start_arg_index += kernel_set_args(kernel,
+ start_arg_index,
d_shader_x,
d_shader_w,
d_offset,
@@ -1380,7 +1400,7 @@ public:
protected:
string kernel_build_options(const string *debug_src = NULL)
{
- string build_options = " -cl-fast-relaxed-math ";
+ string build_options = "-cl-fast-relaxed-math ";
if(platform_name == "NVIDIA CUDA") {
build_options += "-D__KERNEL_OPENCL_NVIDIA__ "
@@ -1430,7 +1450,15 @@ protected:
template <typename T>
ArgumentWrapper(T& argument) : size(sizeof(argument)),
pointer(&argument) { }
+ ArgumentWrapper(int argument) : size(sizeof(int)),
+ int_value(argument),
+ pointer(&int_value) { }
+ ArgumentWrapper(float argument) : size(sizeof(float)),
+ float_value(argument),
+ pointer(&float_value) { }
size_t size;
+ int int_value;
+ float float_value;
void *pointer;
};
@@ -1545,34 +1573,6 @@ protected:
}
}
- string build_options_from_requested_features(
- const DeviceRequestedFeatures& requested_features)
- {
- string build_options = "";
- if(requested_features.experimental) {
- build_options += " -D__KERNEL_EXPERIMENTAL__";
- }
- build_options += " -D__NODES_MAX_GROUP__=" +
- string_printf("%d", requested_features.max_nodes_group);
- build_options += " -D__NODES_FEATURES__=" +
- string_printf("%d", requested_features.nodes_features);
- build_options += string_printf(" -D__MAX_CLOSURE__=%d",
- requested_features.max_closure);
- if(!requested_features.use_hair) {
- build_options += " -D__NO_HAIR__";
- }
- if(!requested_features.use_object_motion) {
- build_options += " -D__NO_OBJECT_MOTION__";
- }
- if(!requested_features.use_camera_motion) {
- build_options += " -D__NO_CAMERA_MOTION__";
- }
- if(!requested_features.use_baking) {
- build_options += " -D__NO_BAKING__";
- }
- return build_options;
- }
-
/* ** Those guys are for workign around some compiler-specific bugs ** */
virtual cl_program load_cached_kernel(
@@ -1673,7 +1673,8 @@ public:
clbin,
custom_kernel_build_options,
&path_trace_program,
- debug_src)) {
+ debug_src))
+ {
/* Kernel loaded from binary, nothing to do. */
}
else {
@@ -1909,63 +1910,6 @@ public:
* shadow_blocked kernel.
*/
- /* Global buffers of each member of ShaderData. */
- cl_mem P_sd;
- cl_mem P_sd_DL_shadow;
- cl_mem N_sd;
- cl_mem N_sd_DL_shadow;
- cl_mem Ng_sd;
- cl_mem Ng_sd_DL_shadow;
- cl_mem I_sd;
- cl_mem I_sd_DL_shadow;
- cl_mem shader_sd;
- cl_mem shader_sd_DL_shadow;
- cl_mem flag_sd;
- cl_mem flag_sd_DL_shadow;
- cl_mem prim_sd;
- cl_mem prim_sd_DL_shadow;
- cl_mem type_sd;
- cl_mem type_sd_DL_shadow;
- cl_mem u_sd;
- cl_mem u_sd_DL_shadow;
- cl_mem v_sd;
- cl_mem v_sd_DL_shadow;
- cl_mem object_sd;
- cl_mem object_sd_DL_shadow;
- cl_mem time_sd;
- cl_mem time_sd_DL_shadow;
- cl_mem ray_length_sd;
- cl_mem ray_length_sd_DL_shadow;
- cl_mem ray_depth_sd;
- cl_mem ray_depth_sd_DL_shadow;
- cl_mem transparent_depth_sd;
- cl_mem transparent_depth_sd_DL_shadow;
-
- /* Ray differentials. */
- cl_mem dP_sd, dI_sd;
- cl_mem dP_sd_DL_shadow, dI_sd_DL_shadow;
- cl_mem du_sd, dv_sd;
- cl_mem du_sd_DL_shadow, dv_sd_DL_shadow;
-
- /* Dp/Du */
- cl_mem dPdu_sd, dPdv_sd;
- cl_mem dPdu_sd_DL_shadow, dPdv_sd_DL_shadow;
-
- /* Object motion. */
- cl_mem ob_tfm_sd, ob_itfm_sd;
- cl_mem ob_tfm_sd_DL_shadow, ob_itfm_sd_DL_shadow;
-
- cl_mem closure_sd;
- cl_mem closure_sd_DL_shadow;
- cl_mem num_closure_sd;
- cl_mem num_closure_sd_DL_shadow;
- cl_mem randb_closure_sd;
- cl_mem randb_closure_sd_DL_shadow;
- cl_mem ray_P_sd;
- cl_mem ray_P_sd_DL_shadow;
- cl_mem ray_dP_sd;
- cl_mem ray_dP_sd_DL_shadow;
-
/* Global memory required for shadow blocked and accum_radiance. */
cl_mem BSDFEval_coop;
cl_mem ISLamp_coop;
@@ -1973,8 +1917,7 @@ public:
cl_mem AOAlpha_coop;
cl_mem AOBSDF_coop;
cl_mem AOLightRay_coop;
- cl_mem Intersection_coop_AO;
- cl_mem Intersection_coop_DL;
+ cl_mem Intersection_coop_shadow;
#ifdef WITH_CYCLES_DEBUG
/* DebugData memory */
@@ -2063,70 +2006,6 @@ public:
sd = NULL;
sd_DL_shadow = NULL;
- P_sd = NULL;
- P_sd_DL_shadow = NULL;
- N_sd = NULL;
- N_sd_DL_shadow = NULL;
- Ng_sd = NULL;
- Ng_sd_DL_shadow = NULL;
- I_sd = NULL;
- I_sd_DL_shadow = NULL;
- shader_sd = NULL;
- shader_sd_DL_shadow = NULL;
- flag_sd = NULL;
- flag_sd_DL_shadow = NULL;
- prim_sd = NULL;
- prim_sd_DL_shadow = NULL;
- type_sd = NULL;
- type_sd_DL_shadow = NULL;
- u_sd = NULL;
- u_sd_DL_shadow = NULL;
- v_sd = NULL;
- v_sd_DL_shadow = NULL;
- object_sd = NULL;
- object_sd_DL_shadow = NULL;
- time_sd = NULL;
- time_sd_DL_shadow = NULL;
- ray_length_sd = NULL;
- ray_length_sd_DL_shadow = NULL;
- ray_depth_sd = NULL;
- ray_depth_sd_DL_shadow = NULL;
- transparent_depth_sd = NULL;
- transparent_depth_sd_DL_shadow = NULL;
-
- /* Ray differentials. */
- dP_sd = NULL;
- dI_sd = NULL;
- dP_sd_DL_shadow = NULL;
- dI_sd_DL_shadow = NULL;
- du_sd = NULL;
- dv_sd = NULL;
- du_sd_DL_shadow = NULL;
- dv_sd_DL_shadow = NULL;
-
- /* Dp/Du */
- dPdu_sd = NULL;
- dPdv_sd = NULL;
- dPdu_sd_DL_shadow = NULL;
- dPdv_sd_DL_shadow = NULL;
-
- /* Object motion. */
- ob_tfm_sd = NULL;
- ob_itfm_sd = NULL;
- ob_tfm_sd_DL_shadow = NULL;
- ob_itfm_sd_DL_shadow = NULL;
-
- closure_sd = NULL;
- closure_sd_DL_shadow = NULL;
- num_closure_sd = NULL;
- num_closure_sd_DL_shadow = NULL;
- randb_closure_sd = NULL;
- randb_closure_sd_DL_shadow = NULL;
- ray_P_sd = NULL;
- ray_P_sd_DL_shadow = NULL;
- ray_dP_sd = NULL;
- ray_dP_sd_DL_shadow = NULL;
-
rng_coop = NULL;
throughput_coop = NULL;
L_transparent_coop = NULL;
@@ -2142,8 +2021,7 @@ public:
BSDFEval_coop = NULL;
ISLamp_coop = NULL;
LightRay_coop = NULL;
- Intersection_coop_AO = NULL;
- Intersection_coop_DL = NULL;
+ Intersection_coop_shadow = NULL;
#ifdef WITH_CYCLES_DEBUG
debugdata_coop = NULL;
@@ -2204,7 +2082,8 @@ public:
clbin,
custom_kernel_build_options,
program,
- debug_src)) {
+ debug_src))
+ {
/* Kernel loaded from binary. */
}
else {
@@ -2243,17 +2122,10 @@ public:
return ret_size;
}
- size_t get_shader_closure_size(int max_closure)
+ size_t get_shader_data_size(size_t max_closure)
{
- return (sizeof(ShaderClosure) * max_closure);
- }
-
- size_t get_shader_data_size(size_t shader_closure_size)
- {
- /* ShaderData size without accounting for ShaderClosure array. */
- size_t shader_data_size =
- sizeof(ShaderData) - (sizeof(ShaderClosure) * MAX_CLOSURE);
- return (shader_data_size + shader_closure_size);
+ /* ShaderData size with variable size ShaderClosure array */
+ return sizeof(ShaderData) - (sizeof(ShaderClosure) * (MAX_CLOSURE - max_closure));
}
/* Returns size of KernelGlobals structure associated with OpenCL. */
@@ -2268,25 +2140,13 @@ public:
ccl_global type *name;
#include "kernel_textures.h"
#undef KERNEL_TEX
+ void *sd_input;
+ void *isect_shadow;
} KernelGlobals;
return sizeof(KernelGlobals);
}
- /* Returns size of Structure of arrays implementation of. */
- size_t get_shaderdata_soa_size()
- {
- size_t shader_soa_size = 0;
-
-#define SD_VAR(type, what) shader_soa_size += sizeof(void *);
-#define SD_CLOSURE_VAR(type, what, max_closure) shader_soa_size += sizeof(void *);
- #include "kernel_shaderdata_vars.h"
-#undef SD_VAR
-#undef SD_CLOSURE_VAR
-
- return shader_soa_size;
- }
-
bool load_kernels(const DeviceRequestedFeatures& requested_features)
{
/* Get Shader, bake and film_convert kernels.
@@ -2303,11 +2163,11 @@ public:
string clbin;
string clsrc, *debug_src = NULL;
- string build_options = "-D__SPLIT_KERNEL__";
+ string build_options = "-D__SPLIT_KERNEL__ ";
#ifdef __WORK_STEALING__
- build_options += " -D__WORK_STEALING__";
+ build_options += "-D__WORK_STEALING__ ";
#endif
- build_options += build_options_from_requested_features(requested_features);
+ build_options += requested_features.get_build_options();
/* Set compute device build option. */
cl_device_type device_type;
@@ -2407,70 +2267,6 @@ public:
release_kernel_safe(ckPathTraceKernel_sum_all_radiance);
/* Release global memory */
- release_mem_object_safe(P_sd);
- release_mem_object_safe(P_sd_DL_shadow);
- release_mem_object_safe(N_sd);
- release_mem_object_safe(N_sd_DL_shadow);
- release_mem_object_safe(Ng_sd);
- release_mem_object_safe(Ng_sd_DL_shadow);
- release_mem_object_safe(I_sd);
- release_mem_object_safe(I_sd_DL_shadow);
- release_mem_object_safe(shader_sd);
- release_mem_object_safe(shader_sd_DL_shadow);
- release_mem_object_safe(flag_sd);
- release_mem_object_safe(flag_sd_DL_shadow);
- release_mem_object_safe(prim_sd);
- release_mem_object_safe(prim_sd_DL_shadow);
- release_mem_object_safe(type_sd);
- release_mem_object_safe(type_sd_DL_shadow);
- release_mem_object_safe(u_sd);
- release_mem_object_safe(u_sd_DL_shadow);
- release_mem_object_safe(v_sd);
- release_mem_object_safe(v_sd_DL_shadow);
- release_mem_object_safe(object_sd);
- release_mem_object_safe(object_sd_DL_shadow);
- release_mem_object_safe(time_sd);
- release_mem_object_safe(time_sd_DL_shadow);
- release_mem_object_safe(ray_length_sd);
- release_mem_object_safe(ray_length_sd_DL_shadow);
- release_mem_object_safe(ray_depth_sd);
- release_mem_object_safe(ray_depth_sd_DL_shadow);
- release_mem_object_safe(transparent_depth_sd);
- release_mem_object_safe(transparent_depth_sd_DL_shadow);
-
- /* Ray differentials. */
- release_mem_object_safe(dP_sd);
- release_mem_object_safe(dP_sd_DL_shadow);
- release_mem_object_safe(dI_sd);
- release_mem_object_safe(dI_sd_DL_shadow);
- release_mem_object_safe(du_sd);
- release_mem_object_safe(du_sd_DL_shadow);
- release_mem_object_safe(dv_sd);
- release_mem_object_safe(dv_sd_DL_shadow);
-
- /* Dp/Du */
- release_mem_object_safe(dPdu_sd);
- release_mem_object_safe(dPdu_sd_DL_shadow);
- release_mem_object_safe(dPdv_sd);
- release_mem_object_safe(dPdv_sd_DL_shadow);
-
- /* Object motion. */
- release_mem_object_safe(ob_tfm_sd);
- release_mem_object_safe(ob_itfm_sd);
-
- release_mem_object_safe(ob_tfm_sd_DL_shadow);
- release_mem_object_safe(ob_itfm_sd_DL_shadow);
-
- release_mem_object_safe(closure_sd);
- release_mem_object_safe(closure_sd_DL_shadow);
- release_mem_object_safe(num_closure_sd);
- release_mem_object_safe(num_closure_sd_DL_shadow);
- release_mem_object_safe(randb_closure_sd);
- release_mem_object_safe(randb_closure_sd_DL_shadow);
- release_mem_object_safe(ray_P_sd);
- release_mem_object_safe(ray_P_sd_DL_shadow);
- release_mem_object_safe(ray_dP_sd);
- release_mem_object_safe(ray_dP_sd_DL_shadow);
release_mem_object_safe(rng_coop);
release_mem_object_safe(throughput_coop);
release_mem_object_safe(L_transparent_coop);
@@ -2488,8 +2284,7 @@ public:
release_mem_object_safe(BSDFEval_coop);
release_mem_object_safe(ISLamp_coop);
release_mem_object_safe(LightRay_coop);
- release_mem_object_safe(Intersection_coop_AO);
- release_mem_object_safe(Intersection_coop_DL);
+ release_mem_object_safe(Intersection_coop_shadow);
#ifdef WITH_CYCLES_DEBUG
release_mem_object_safe(debugdata_coop);
#endif
@@ -2586,7 +2381,7 @@ public:
/* TODO(sergey): This will actually over-allocate if
* particular kernel does not support multiclosure.
*/
- size_t ShaderClosure_size = get_shader_closure_size(current_max_closure);
+ size_t shaderdata_size = get_shader_data_size(current_max_closure);
#ifdef __WORK_STEALING__
/* Calculate max groups */
@@ -2607,71 +2402,8 @@ public:
kgbuffer = mem_alloc(get_KernelGlobals_size());
/* Create global buffers for ShaderData. */
- sd = mem_alloc(get_shaderdata_soa_size());
- sd_DL_shadow = mem_alloc(get_shaderdata_soa_size());
- P_sd = mem_alloc(num_global_elements * sizeof(float3));
- P_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
- N_sd = mem_alloc(num_global_elements * sizeof(float3));
- N_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
- Ng_sd = mem_alloc(num_global_elements * sizeof(float3));
- Ng_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
- I_sd = mem_alloc(num_global_elements * sizeof(float3));
- I_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
- shader_sd = mem_alloc(num_global_elements * sizeof(int));
- shader_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- flag_sd = mem_alloc(num_global_elements * sizeof(int));
- flag_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- prim_sd = mem_alloc(num_global_elements * sizeof(int));
- prim_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- type_sd = mem_alloc(num_global_elements * sizeof(int));
- type_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- u_sd = mem_alloc(num_global_elements * sizeof(float));
- u_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
- v_sd = mem_alloc(num_global_elements * sizeof(float));
- v_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
- object_sd = mem_alloc(num_global_elements * sizeof(int));
- object_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- time_sd = mem_alloc(num_global_elements * sizeof(float));
- time_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
- ray_length_sd = mem_alloc(num_global_elements * sizeof(float));
- ray_length_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
- ray_depth_sd = mem_alloc(num_global_elements * sizeof(int));
- ray_depth_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- transparent_depth_sd = mem_alloc(num_global_elements * sizeof(int));
- transparent_depth_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
-
- /* Ray differentials. */
- dP_sd = mem_alloc(num_global_elements * sizeof(differential3));
- dP_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential3));
- dI_sd = mem_alloc(num_global_elements * sizeof(differential3));
- dI_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential3));
- du_sd = mem_alloc(num_global_elements * sizeof(differential));
- du_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential));
- dv_sd = mem_alloc(num_global_elements * sizeof(differential));
- dv_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential));
-
- /* Dp/Du */
- dPdu_sd = mem_alloc(num_global_elements * sizeof(float3));
- dPdu_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
- dPdv_sd = mem_alloc(num_global_elements * sizeof(float3));
- dPdv_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
-
- /* Object motion. */
- ob_tfm_sd = mem_alloc(num_global_elements * sizeof(Transform));
- ob_tfm_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(Transform));
- ob_itfm_sd = mem_alloc(num_global_elements * sizeof(Transform));
- ob_itfm_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(Transform));
-
- closure_sd = mem_alloc(num_global_elements * ShaderClosure_size);
- closure_sd_DL_shadow = mem_alloc(num_global_elements * 2 * ShaderClosure_size);
- num_closure_sd = mem_alloc(num_global_elements * sizeof(int));
- num_closure_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(int));
- randb_closure_sd = mem_alloc(num_global_elements * sizeof(float));
- randb_closure_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float));
- ray_P_sd = mem_alloc(num_global_elements * sizeof(float3));
- ray_P_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(float3));
- ray_dP_sd = mem_alloc(num_global_elements * sizeof(differential3));
- ray_dP_sd_DL_shadow = mem_alloc(num_global_elements * 2 * sizeof(differential3));
+ sd = mem_alloc(num_global_elements * shaderdata_size);
+ sd_DL_shadow = mem_alloc(num_global_elements * 2 * shaderdata_size);
/* Creation of global memory buffers which are shared among
* the kernels.
@@ -2689,8 +2421,7 @@ public:
BSDFEval_coop = mem_alloc(num_global_elements * sizeof(BsdfEval));
ISLamp_coop = mem_alloc(num_global_elements * sizeof(int));
LightRay_coop = mem_alloc(num_global_elements * sizeof(Ray));
- Intersection_coop_AO = mem_alloc(num_global_elements * sizeof(Intersection));
- Intersection_coop_DL = mem_alloc(num_global_elements * sizeof(Intersection));
+ Intersection_coop_shadow = mem_alloc(2 * num_global_elements * sizeof(Intersection));
#ifdef WITH_CYCLES_DEBUG
debugdata_coop = mem_alloc(num_global_elements * sizeof(DebugData));
@@ -2708,89 +2439,12 @@ public:
}
cl_int dQueue_size = global_size[0] * global_size[1];
- cl_int total_num_rays = global_size[0] * global_size[1];
cl_uint start_arg_index =
kernel_set_args(ckPathTraceKernel_data_init,
0,
kgbuffer,
- sd,
sd_DL_shadow,
- P_sd,
- P_sd_DL_shadow,
- N_sd,
- N_sd_DL_shadow,
- Ng_sd,
- Ng_sd_DL_shadow,
- I_sd,
- I_sd_DL_shadow,
- shader_sd,
- shader_sd_DL_shadow,
- flag_sd,
- flag_sd_DL_shadow,
- prim_sd,
- prim_sd_DL_shadow,
- type_sd,
- type_sd_DL_shadow,
- u_sd,
- u_sd_DL_shadow,
- v_sd,
- v_sd_DL_shadow,
- object_sd,
- object_sd_DL_shadow,
- time_sd,
- time_sd_DL_shadow,
- ray_length_sd,
- ray_length_sd_DL_shadow,
- ray_depth_sd,
- ray_depth_sd_DL_shadow,
- transparent_depth_sd,
- transparent_depth_sd_DL_shadow);
-
- /* Ray differentials. */
- start_arg_index +=
- kernel_set_args(ckPathTraceKernel_data_init,
- start_arg_index,
- dP_sd,
- dP_sd_DL_shadow,
- dI_sd,
- dI_sd_DL_shadow,
- du_sd,
- du_sd_DL_shadow,
- dv_sd,
- dv_sd_DL_shadow);
-
- /* Dp/Du */
- start_arg_index +=
- kernel_set_args(ckPathTraceKernel_data_init,
- start_arg_index,
- dPdu_sd,
- dPdu_sd_DL_shadow,
- dPdv_sd,
- dPdv_sd_DL_shadow);
-
- /* Object motion. */
- start_arg_index +=
- kernel_set_args(ckPathTraceKernel_data_init,
- start_arg_index,
- ob_tfm_sd,
- ob_tfm_sd_DL_shadow,
- ob_itfm_sd,
- ob_itfm_sd_DL_shadow);
-
- start_arg_index +=
- kernel_set_args(ckPathTraceKernel_data_init,
- start_arg_index,
- closure_sd,
- closure_sd_DL_shadow,
- num_closure_sd,
- num_closure_sd_DL_shadow,
- randb_closure_sd,
- randb_closure_sd_DL_shadow,
- ray_P_sd,
- ray_P_sd_DL_shadow,
- ray_dP_sd,
- ray_dP_sd_DL_shadow,
d_data,
per_sample_output_buffers,
d_rng_state,
@@ -2800,9 +2454,10 @@ public:
PathRadiance_coop,
Ray_coop,
PathState_coop,
+ Intersection_coop_shadow,
ray_state);
-/* TODO(segrey): Avoid map lookup here. */
+/* TODO(sergey): Avoid map lookup here. */
#define KERNEL_TEX(type, ttype, name) \
set_kernel_arg_mem(ckPathTraceKernel_data_init, &start_arg_index, #name);
#include "kernel_textures.h"
@@ -2859,7 +2514,6 @@ public:
0,
kgbuffer,
d_data,
- sd,
throughput_coop,
PathRadiance_coop,
Ray_coop,
@@ -2885,7 +2539,6 @@ public:
0,
kgbuffer,
d_data,
- sd,
per_sample_output_buffers,
d_rng_state,
rng_coop,
@@ -2967,7 +2620,6 @@ public:
kgbuffer,
d_data,
sd,
- sd_DL_shadow,
rng_coop,
PathState_coop,
ISLamp_coop,
@@ -2982,17 +2634,13 @@ public:
0,
kgbuffer,
d_data,
- sd_DL_shadow,
PathState_coop,
LightRay_coop,
AOLightRay_coop,
- Intersection_coop_AO,
- Intersection_coop_DL,
ray_state,
Queue_data,
Queue_index,
- dQueue_size,
- total_num_rays);
+ dQueue_size);
kernel_set_args(ckPathTraceKernel_next_iteration_setup,
0,
@@ -3162,16 +2810,12 @@ public:
{
size_t total_invariable_mem_allocated = 0;
size_t KernelGlobals_size = 0;
- size_t ShaderData_SOA_size = 0;
KernelGlobals_size = get_KernelGlobals_size();
- ShaderData_SOA_size = get_shaderdata_soa_size();
total_invariable_mem_allocated += KernelGlobals_size; /* KernelGlobals size */
total_invariable_mem_allocated += NUM_QUEUES * sizeof(unsigned int); /* Queue index size */
total_invariable_mem_allocated += sizeof(char); /* use_queues_flag size */
- total_invariable_mem_allocated += ShaderData_SOA_size; /* sd size */
- total_invariable_mem_allocated += ShaderData_SOA_size; /* sd_DL_shadow size */
return total_invariable_mem_allocated;
}
@@ -3238,13 +2882,11 @@ public:
/* Calculate the memory required for one thread in split kernel. */
size_t get_per_thread_memory()
{
- size_t shader_closure_size = 0;
- size_t shaderdata_volume = 0;
- shader_closure_size = get_shader_closure_size(current_max_closure);
+ size_t shaderdata_size = 0;
/* TODO(sergey): This will actually over-allocate if
* particular kernel does not support multiclosure.
*/
- shaderdata_volume = get_shader_data_size(shader_closure_size);
+ shaderdata_size = get_shader_data_size(current_max_closure);
size_t retval = sizeof(RNG)
+ sizeof(float3) /* Throughput size */
+ sizeof(float) /* L transparent size */
@@ -3255,8 +2897,8 @@ public:
+ sizeof(Intersection) /* Overall isect */
+ sizeof(Intersection) /* Instersection_coop_AO */
+ sizeof(Intersection) /* Intersection coop DL */
- + shaderdata_volume /* Overall ShaderData */
- + (shaderdata_volume * 2) /* ShaderData : DL and shadow */
+ + shaderdata_size /* Overall ShaderData */
+ + (shaderdata_size * 2) /* ShaderData : DL and shadow */
+ sizeof(Ray) + sizeof(BsdfEval)
+ sizeof(float3) /* AOAlpha size */
+ sizeof(float3) /* AOBSDF size */
@@ -3580,7 +3222,7 @@ protected:
string build_options_for_base_program(
const DeviceRequestedFeatures& requested_features)
{
- return build_options_from_requested_features(requested_features);
+ return requested_features.get_build_options();
}
};
@@ -3690,7 +3332,7 @@ string device_opencl_capabilities(void)
APPEND_STRING_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what)
vector<cl_device_id> device_ids;
- for (cl_uint platform = 0; platform < num_platforms; ++platform) {
+ for(cl_uint platform = 0; platform < num_platforms; ++platform) {
cl_platform_id platform_id = platform_ids[platform];
result += string_printf("Platform #%u\n", platform);
@@ -3715,7 +3357,7 @@ string device_opencl_capabilities(void)
num_devices,
&device_ids[0],
NULL));
- for (cl_uint device = 0; device < num_devices; ++device) {
+ for(cl_uint device = 0; device < num_devices; ++device) {
cl_device_id device_id = device_ids[device];
result += string_printf("\t\tDevice: #%u\n", device);
diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp
index d527540f300..1f1128a28f8 100644
--- a/intern/cycles/device/device_task.cpp
+++ b/intern/cycles/device/device_task.cpp
@@ -29,8 +29,8 @@ CCL_NAMESPACE_BEGIN
DeviceTask::DeviceTask(Type type_)
: type(type_), x(0), y(0), w(0), h(0), rgba_byte(0), rgba_half(0), buffer(0),
sample(0), num_samples(1),
- shader_input(0), shader_output(0),
- shader_eval_type(0), shader_x(0), shader_w(0)
+ shader_input(0), shader_output(0), shader_output_luma(0),
+ shader_eval_type(0), shader_filter(0), shader_x(0), shader_w(0)
{
last_update_time = time_dt();
}
diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h
index 834ea60988a..d7912f386f5 100644
--- a/intern/cycles/device/device_task.h
+++ b/intern/cycles/device/device_task.h
@@ -46,8 +46,9 @@ public:
int offset, stride;
device_ptr shader_input;
- device_ptr shader_output;
+ device_ptr shader_output, shader_output_luma;
int shader_eval_type;
+ int shader_filter;
int shader_x, shader_w;
DeviceTask(Type type = PATH_TRACE);
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index b44e91751ad..9f3fb66c85a 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -29,7 +29,6 @@ set(SRC
)
set(SRC_HEADERS
- kernel.h
kernel_accumulate.h
kernel_bake.h
kernel_camera.h
@@ -56,7 +55,6 @@ set(SRC_HEADERS
kernel_queues.h
kernel_random.h
kernel_shader.h
- kernel_shaderdata_vars.h
kernel_shadow.h
kernel_subsurface.h
kernel_textures.h
@@ -65,6 +63,12 @@ set(SRC_HEADERS
kernel_work_stealing.h
)
+set(SRC_KERNELS_CPU_HEADERS
+ kernel.h
+ kernels/cpu/kernel_cpu.h
+ kernels/cpu/kernel_cpu_impl.h
+)
+
set(SRC_CLOSURE_HEADERS
closure/bsdf.h
closure/bsdf_ashikhmin_velvet.h
@@ -161,6 +165,7 @@ set(SRC_UTIL_HEADERS
../util/util_math.h
../util/util_math_fast.h
../util/util_transform.h
+ ../util/util_texture.h
../util/util_types.h
)
@@ -182,7 +187,7 @@ set(SRC_SPLIT_HEADERS
if(WITH_CYCLES_CUDA_BINARIES)
# 32 bit or 64 bit
- if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+ if(CUDA_64_BIT_DEVICE_CODE)
set(CUDA_BITS 64)
else()
set(CUDA_BITS 32)
@@ -195,11 +200,11 @@ if(WITH_CYCLES_CUDA_BINARIES)
set(CUDA_VERSION "${CUDA_VERSION_MAJOR}${CUDA_VERSION_MINOR}")
# warn for other versions
- if(CUDA_VERSION MATCHES "65")
+ if(CUDA_VERSION MATCHES "75")
else()
message(WARNING
"CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, "
- "build may succeed but only CUDA 6.5 is officially supported")
+ "build may succeed but only CUDA 7.5 is officially supported")
endif()
# build for each arch
@@ -255,9 +260,6 @@ if(WITH_CYCLES_CUDA_BINARIES)
foreach(arch ${CYCLES_CUDA_BINARIES_ARCH})
# Compile regular kernel
CYCLES_CUDA_KERNEL_ADD(${arch} FALSE)
-
- # Compile experimental kernel
- CYCLES_CUDA_KERNEL_ADD(${arch} TRUE)
endforeach()
add_custom_target(cycles_kernel_cuda ALL DEPENDS ${cuda_cubins})
@@ -301,7 +303,15 @@ if(CXX_HAS_AVX2)
set_source_files_properties(kernels/cpu/kernel_avx2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_KERNEL_FLAGS}")
endif()
-add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS})
+add_library(cycles_kernel
+ ${SRC}
+ ${SRC_HEADERS}
+ ${SRC_KERNELS_CPU_HEADERS}
+ ${SRC_CLOSURE_HEADERS}
+ ${SRC_SVM_HEADERS}
+ ${SRC_GEOM_HEADERS}
+ ${SRC_SPLIT_HEADERS}
+)
if(WITH_CYCLES_CUDA)
add_dependencies(cycles_kernel cycles_kernel_cuda)
diff --git a/intern/cycles/kernel/SConscript b/intern/cycles/kernel/SConscript
deleted file mode 100644
index e8d51013924..00000000000
--- a/intern/cycles/kernel/SConscript
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import re
-import subprocess
-import sys
-import os
-import Blender as B
-import btools
-
-def normpath(path):
- return os.path.abspath(os.path.normpath(path))
-
-Import ('env')
-
-kernel_binaries = []
-
-#Bitness
-if B.bitness == 32:
- bits = 32
-else:
- bits = 64
-
-if env['WITH_BF_CYCLES_CUDA_BINARIES']:
- kernel = env.Clone()
-
- # cuda info
- nvcc = env['BF_CYCLES_CUDA_NVCC']
- cuda_archs = env['BF_CYCLES_CUDA_BINARIES_ARCH']
-
- # build directory
- root_build_dir = normpath(env['BF_BUILDDIR'])
- build_dir = os.path.join(root_build_dir, 'intern/cycles/kernel')
-
- # source directories and files
- kernel_file_rel = os.path.join("kernels", "cuda", "kernel.cu")
- source_dir = Dir('.').srcnode().path
- kernel_file = os.path.join(source_dir, kernel_file_rel)
- util_dir = os.path.join(source_dir, "../util")
- svm_dir = os.path.join(source_dir, "../svm")
- geom_dir = os.path.join(source_dir, "../geom")
- closure_dir = os.path.join(source_dir, "../closure")
-
- # get CUDA version
- output = btools.get_command_output([nvcc, "--version"])
- cuda_major_minor = re.findall(r'release (\d+).(\d+)', output)[0]
- cuda_version = int(cuda_major_minor[0])*10 + int(cuda_major_minor[1])
-
- if cuda_version != 65:
- print("CUDA version %d.%d detected, build may succeed but only CUDA 6.5 is officially supported." % (cuda_version/10, cuda_version%10))
-
- # nvcc flags
- nvcc_flags = "-m%s" % (bits)
- nvcc_flags += " --cubin --ptxas-options=\"-v\" --use_fast_math"
- nvcc_flags += " -D__KERNEL_CUDA_VERSION__=%d" % (cuda_version)
- nvcc_flags += " -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END= -DNVCC"
- nvcc_flags += " -I \"%s\" -I \"%s\" -I \"%s\" -I \"%s\"" % (util_dir, svm_dir, geom_dir, closure_dir)
-
- if env['WITH_BF_CYCLES_DEBUG']:
- nvcc_flags += " -D__KERNEL_DEBUG__"
-
- # dependencies
- dependencies = [kernel_file_rel] + kernel.Glob('*.h') + kernel.Glob('../util/*.h') + kernel.Glob('svm/*.h') + kernel.Glob('geom/*.h') + kernel.Glob('closure/*.h')
- last_cubin_file = None
-
- configs = (("kernel_%s.cubin", ''),
- ("kernel_experimental_%s.cubin", ' -D__KERNEL_EXPERIMENTAL__'))
-
- # add command for each cuda architecture
- for arch in cuda_archs:
- for config in configs:
- # TODO(sergey): Use dict instead ocouple in order to increase readability?
- name = config[0]
- extra_flags = config[1]
-
- cubin_file = os.path.join(build_dir, name % arch)
- current_flags = nvcc_flags + extra_flags
-
- if env['BF_CYCLES_CUDA_ENV']:
- MS_SDK = "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Bin\\SetEnv.cmd"
- command = "\"%s\" & \"%s\" -arch=%s %s \"%s\" -o \"%s\"" % (MS_SDK, nvcc, arch, current_flags, kernel_file, cubin_file)
- else:
- command = "\"%s\" -arch=%s %s \"%s\" -o \"%s\"" % (nvcc, arch, current_flags, kernel_file, cubin_file)
-
- kernel.Command(cubin_file, kernel_file_rel, command)
- kernel.Depends(cubin_file, dependencies)
-
- kernel_binaries.append(cubin_file)
-
- if not env['WITH_BF_CYCLES_CUDA_THREADED_COMPILE']:
- # trick to compile one kernel at a time to reduce memory usage
- if last_cubin_file:
- kernel.Depends(cubin_file, last_cubin_file)
- last_cubin_file = cubin_file
-
-Return('kernel_binaries')
-
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 558aa0dc6a9..f0add804c32 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -27,10 +27,10 @@
#include "../closure/bsdf_toon.h"
#include "../closure/bsdf_hair.h"
#ifdef __SUBSURFACE__
-#include "../closure/bssrdf.h"
+# include "../closure/bssrdf.h"
#endif
#ifdef __VOLUME__
-#include "../closure/volume.h"
+# include "../closure/volume.h"
#endif
CCL_NAMESPACE_BEGIN
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index f817dcd5f2d..c24720cefbe 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -19,25 +19,6 @@
CCL_NAMESPACE_BEGIN
-ccl_device int bssrdf_setup(ShaderClosure *sc, ClosureType type)
-{
- if(sc->data0 < BSSRDF_MIN_RADIUS) {
- /* revert to diffuse BSDF if radius too small */
- sc->data0 = 0.0f;
- sc->data1 = 0.0f;
- int flag = bsdf_diffuse_setup(sc);
- sc->type = CLOSURE_BSDF_BSSRDF_ID;
- return flag;
- }
- else {
- sc->data1 = saturate(sc->data1); /* texture blur */
- sc->T.x = saturate(sc->T.x); /* sharpness */
- sc->type = type;
-
- return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
- }
-}
-
/* Planar Truncated Gaussian
*
* Note how this is different from the typical gaussian, this one integrates
@@ -83,8 +64,8 @@ ccl_device void bssrdf_gaussian_sample(ShaderClosure *sc, float xi, float *r, fl
const float r_squared = -2.0f*v*logf(1.0f - xi*area_truncated);
*r = sqrtf(r_squared);
- /* h^2 + r^2 = Rm^2 */
- *h = sqrtf(Rm*Rm - r_squared);
+ /* h^2 + r^2 = Rm^2 */
+ *h = safe_sqrtf(Rm*Rm - r_squared);
}
/* Planar Cubic BSSRDF falloff
@@ -184,16 +165,134 @@ ccl_device void bssrdf_cubic_sample(ShaderClosure *sc, float xi, float *r, float
r_ = powf(r_, 1.0f + sharpness);
Rm *= (1.0f + sharpness);
}
-
+
r_ *= Rm;
*r = r_;
/* h^2 + r^2 = Rm^2 */
- *h = sqrtf(Rm*Rm - r_*r_);
+ *h = safe_sqrtf(Rm*Rm - r_*r_);
+}
+
+/* Approximate Reflectance Profiles
+ * http://graphics.pixar.com/library/ApproxBSSRDF/paper.pdf
+ */
+
+/* This is a bit arbitrary, just need big enough radius so it matches
+ * the mean free length, but still not too big so sampling is still
+ * effective. Might need some further tweaks.
+ */
+#define BURLEY_TRUNCATE 16.0f
+#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
+
+ccl_device_inline float bssrdf_burley_fitting(float A)
+{
+ /* Diffuse surface transmission, equation (6). */
+ return 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
+}
+
+/* Scale mean free path length so it gives similar looking result
+ * to Cubic and Gaussian models.
+ */
+ccl_device_inline float bssrdf_burley_compatible_mfp(float r)
+{
+ return 0.25f * M_1_PI_F * r;
+}
+
+ccl_device void bssrdf_burley_setup(ShaderClosure *sc)
+{
+ /* Mean free path length. */
+ const float l = bssrdf_burley_compatible_mfp(sc->data0);
+ /* Surface albedo. */
+ const float A = sc->data2;
+ const float s = bssrdf_burley_fitting(A);
+ const float d = l / s;
+
+ sc->custom1 = d;
+}
+
+ccl_device float bssrdf_burley_eval(ShaderClosure *sc, float r)
+{
+ const float d = sc->custom1;
+ const float Rm = BURLEY_TRUNCATE * d;
+
+ if(r >= Rm)
+ return 0.0f;
+
+ /* Burley refletance profile, equation (3).
+ *
+ * NOTES:
+ * - Surface albedo is already included into sc->weight, no need to
+ * multiply by this term here.
+ * - This is normalized diffuse model, so the equation is mutliplied
+ * by 2*pi, which also matches cdf().
+ */
+ float exp_r_3_d = expf(-r / (3.0f * d));
+ float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
+ return (exp_r_d + exp_r_3_d) / (4.0f*d);
+}
+
+ccl_device float bssrdf_burley_pdf(ShaderClosure *sc, float r)
+{
+ return bssrdf_burley_eval(sc, r) * (1.0f/BURLEY_TRUNCATE_CDF);
+}
+
+/* Find the radius for desired CDF value.
+ * Returns scaled radius, meaning the result is to be scaled up by d.
+ * Since there's no closed form solution we do Newton-Raphson method to find it.
+ */
+ccl_device float bssrdf_burley_root_find(float xi)
+{
+ const float tolerance = 1e-6f;
+ const int max_iteration_count = 10;
+ /* Do initial guess based on manual curve fitting, this allows us to reduce
+ * number of iterations to maximum 4 across the [0..1] range. We keep maximum
+ * number of iteration higher just to be sure we didn't miss root in some
+ * corner case.
+ */
+ float r;
+ if(xi <= 0.9f) {
+ r = expf(xi * xi * 2.4f) - 1.0f;
+ }
+ else {
+ /* TODO(sergey): Some nicer curve fit is possible here. */
+ r = 15.0f;
+ }
+ /* Solve against scaled radius. */
+ for(int i = 0; i < max_iteration_count; i++) {
+ float exp_r_3 = expf(-r / 3.0f);
+ float exp_r = exp_r_3 * exp_r_3 * exp_r_3;
+ float f = 1.0f - 0.25f * exp_r - 0.75f * exp_r_3 - xi;
+ float f_ = 0.25f * exp_r + 0.25f * exp_r_3;
+
+ if(fabsf(f) < tolerance || f_ == 0.0f) {
+ break;
+ }
+
+ r = r - f/f_;
+ if(r < 0.0f) {
+ r = 0.0f;
+ }
+ }
+ return r;
+}
+
+ccl_device void bssrdf_burley_sample(ShaderClosure *sc,
+ float xi,
+ float *r,
+ float *h)
+{
+ const float d = sc->custom1;
+ const float Rm = BURLEY_TRUNCATE * d;
+ const float r_ = bssrdf_burley_root_find(xi * BURLEY_TRUNCATE_CDF) * d;
+
+ *r = r_;
+
+ /* h^2 + r^2 = Rm^2 */
+ *h = safe_sqrtf(Rm*Rm - r_*r_);
}
/* None BSSRDF falloff
- *
+ *
* Samples distributed over disk with no falloff, for reference. */
ccl_device float bssrdf_none_eval(ShaderClosure *sc, float r)
@@ -221,25 +320,52 @@ ccl_device void bssrdf_none_sample(ShaderClosure *sc, float xi, float *r, float
*r = r_;
/* h^2 + r^2 = Rm^2 */
- *h = sqrtf(Rm*Rm - r_*r_);
+ *h = safe_sqrtf(Rm*Rm - r_*r_);
}
/* Generic */
+ccl_device int bssrdf_setup(ShaderClosure *sc, ClosureType type)
+{
+ if(sc->data0 < BSSRDF_MIN_RADIUS) {
+ /* revert to diffuse BSDF if radius too small */
+ sc->data0 = 0.0f;
+ sc->data1 = 0.0f;
+ int flag = bsdf_diffuse_setup(sc);
+ sc->type = CLOSURE_BSDF_BSSRDF_ID;
+ return flag;
+ }
+ else {
+ sc->data1 = saturate(sc->data1); /* texture blur */
+ sc->T.x = saturate(sc->T.x); /* sharpness */
+ sc->type = type;
+
+ if(type == CLOSURE_BSSRDF_BURLEY_ID) {
+ bssrdf_burley_setup(sc);
+ }
+
+ return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF;
+ }
+}
+
ccl_device void bssrdf_sample(ShaderClosure *sc, float xi, float *r, float *h)
{
if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
bssrdf_cubic_sample(sc, xi, r, h);
- else
+ else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID)
bssrdf_gaussian_sample(sc, xi, r, h);
+ else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/
+ bssrdf_burley_sample(sc, xi, r, h);
}
ccl_device float bssrdf_pdf(ShaderClosure *sc, float r)
{
if(sc->type == CLOSURE_BSSRDF_CUBIC_ID)
return bssrdf_cubic_pdf(sc, r);
- else
+ else if(sc->type == CLOSURE_BSSRDF_GAUSSIAN_ID)
return bssrdf_gaussian_pdf(sc, r);
+ else /*if(sc->type == CLOSURE_BSSRDF_BURLEY_ID)*/
+ return bssrdf_burley_pdf(sc, r);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h
index 5ab900d47aa..c94a5384d1f 100644
--- a/intern/cycles/kernel/geom/geom.h
+++ b/intern/cycles/kernel/geom/geom.h
@@ -31,9 +31,9 @@
* without sse support on x86, it results in different results for float ops
* that you would otherwise expect to compare correctly */
#if !defined(__i386__) || defined(__SSE__)
-#define NO_EXTENDED_PRECISION
+# define NO_EXTENDED_PRECISION
#else
-#define NO_EXTENDED_PRECISION volatile
+# define NO_EXTENDED_PRECISION volatile
#endif
#include "geom_attribute.h"
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h
index 3d0d406dd0b..9eadc97386c 100644
--- a/intern/cycles/kernel/geom/geom_bvh.h
+++ b/intern/cycles/kernel/geom/geom_bvh.h
@@ -30,9 +30,9 @@ CCL_NAMESPACE_BEGIN
/* Don't inline intersect functions on GPU, this is faster */
#ifdef __KERNEL_GPU__
-#define ccl_device_intersect ccl_device_noinline
+# define ccl_device_intersect ccl_device_noinline
#else
-#define ccl_device_intersect ccl_device_inline
+# define ccl_device_intersect ccl_device_inline
#endif
/* BVH intersection function variations */
@@ -50,7 +50,7 @@ CCL_NAMESPACE_BEGIN
/* Common QBVH functions. */
#ifdef __QBVH__
-#include "geom_qbvh.h"
+# include "geom_qbvh.h"
#endif
/* Regular BVH traversal */
@@ -60,155 +60,113 @@ CCL_NAMESPACE_BEGIN
#include "geom_bvh_traversal.h"
#if defined(__INSTANCING__)
-#define BVH_FUNCTION_NAME bvh_intersect_instancing
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING
-#include "geom_bvh_traversal.h"
+# define BVH_FUNCTION_NAME bvh_intersect_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "geom_bvh_traversal.h"
#endif
#if defined(__HAIR__)
-#define BVH_FUNCTION_NAME bvh_intersect_hair
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
-#include "geom_bvh_traversal.h"
+# define BVH_FUNCTION_NAME bvh_intersect_hair
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
+# include "geom_bvh_traversal.h"
#endif
#if defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-#include "geom_bvh_traversal.h"
+# define BVH_FUNCTION_NAME bvh_intersect_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+# include "geom_bvh_traversal.h"
#endif
#if defined(__HAIR__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_hair_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
-#include "geom_bvh_traversal.h"
+# define BVH_FUNCTION_NAME bvh_intersect_hair_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
+# include "geom_bvh_traversal.h"
#endif
/* Subsurface scattering BVH traversal */
#if defined(__SUBSURFACE__)
-#define BVH_FUNCTION_NAME bvh_intersect_subsurface
-#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_subsurface.h"
-#endif
-
-#if defined(__SUBSURFACE__) && defined(__INSTANCING__)
-#define BVH_FUNCTION_NAME bvh_intersect_subsurface_instancing
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING
-#include "geom_bvh_subsurface.h"
-#endif
-
-#if defined(__SUBSURFACE__) && defined(__HAIR__)
-#define BVH_FUNCTION_NAME bvh_intersect_subsurface_hair
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
-#include "geom_bvh_subsurface.h"
+# define BVH_FUNCTION_NAME bvh_intersect_subsurface
+# define BVH_FUNCTION_FEATURES 0
+# include "geom_bvh_subsurface.h"
#endif
#if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-#include "geom_bvh_subsurface.h"
-#endif
-
-#if defined(__SUBSURFACE__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_subsurface_hair_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
-#include "geom_bvh_subsurface.h"
+# define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion
+# define BVH_FUNCTION_FEATURES BVH_MOTION
+# include "geom_bvh_subsurface.h"
#endif
/* Volume BVH traversal */
#if defined(__VOLUME__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume
-#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_volume.h"
+# define BVH_FUNCTION_NAME bvh_intersect_volume
+# define BVH_FUNCTION_FEATURES 0
+# include "geom_bvh_volume.h"
#endif
#if defined(__VOLUME__) && defined(__INSTANCING__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING
-#include "geom_bvh_volume.h"
-#endif
-
-#if defined(__VOLUME__) && defined(__HAIR__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_hair
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
-#include "geom_bvh_volume.h"
+# define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "geom_bvh_volume.h"
#endif
#if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-#include "geom_bvh_volume.h"
-#endif
-
-#if defined(__VOLUME__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_hair_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
-#include "geom_bvh_volume.h"
+# define BVH_FUNCTION_NAME bvh_intersect_volume_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+# include "geom_bvh_volume.h"
#endif
/* Record all intersections - Shadow BVH traversal */
#if defined(__SHADOW_RECORD_ALL__)
-#define BVH_FUNCTION_NAME bvh_intersect_shadow_all
-#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_shadow.h"
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all
+# define BVH_FUNCTION_FEATURES 0
+# include "geom_bvh_shadow.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__INSTANCING__)
-#define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING
-#include "geom_bvh_shadow.h"
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "geom_bvh_shadow.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__)
-#define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
-#include "geom_bvh_shadow.h"
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR
+# include "geom_bvh_shadow.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-#include "geom_bvh_shadow.h"
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+# include "geom_bvh_shadow.h"
#endif
#if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
-#include "geom_bvh_shadow.h"
+# define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION
+# include "geom_bvh_shadow.h"
#endif
/* Record all intersections - Volume BVH traversal */
#if defined(__VOLUME_RECORD_ALL__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_all
-#define BVH_FUNCTION_FEATURES 0
-#include "geom_bvh_volume_all.h"
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all
+# define BVH_FUNCTION_FEATURES 0
+# include "geom_bvh_volume_all.h"
#endif
#if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING
-#include "geom_bvh_volume_all.h"
-#endif
-
-#if defined(__VOLUME_RECORD_ALL__) && defined(__HAIR__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_all_hair
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
-#include "geom_bvh_volume_all.h"
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING
+# include "geom_bvh_volume_all.h"
#endif
#if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
-#include "geom_bvh_volume_all.h"
-#endif
-
-#if defined(__VOLUME_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
-#define BVH_FUNCTION_NAME bvh_intersect_volume_all_hair_motion
-#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
-#include "geom_bvh_volume_all.h"
+# define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion
+# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+# include "geom_bvh_volume_all.h"
#endif
#undef BVH_FEATURE
@@ -216,182 +174,150 @@ CCL_NAMESPACE_BEGIN
#undef BVH_NAME_EVAL
#undef BVH_FUNCTION_FULL_NAME
-ccl_device_intersect bool scene_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect,
- uint *lcg_state, float difl, float extmax)
+ccl_device_intersect bool scene_intersect(KernelGlobals *kg,
+ const Ray *ray,
+ const uint visibility,
+ Intersection *isect,
+ uint *lcg_state,
+ float difl,
+ float extmax)
{
#ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
-#ifdef __HAIR__
+# ifdef __HAIR__
if(kernel_data.bvh.have_curves)
return bvh_intersect_hair_motion(kg, ray, isect, visibility, lcg_state, difl, extmax);
-#endif /* __HAIR__ */
+# endif /* __HAIR__ */
return bvh_intersect_motion(kg, ray, isect, visibility);
}
#endif /* __OBJECT_MOTION__ */
-#ifdef __HAIR__
+#ifdef __HAIR__
if(kernel_data.bvh.have_curves)
return bvh_intersect_hair(kg, ray, isect, visibility, lcg_state, difl, extmax);
#endif /* __HAIR__ */
#ifdef __KERNEL_CPU__
-#ifdef __INSTANCING__
+# ifdef __INSTANCING__
if(kernel_data.bvh.have_instancing)
return bvh_intersect_instancing(kg, ray, isect, visibility);
-#endif /* __INSTANCING__ */
+# endif /* __INSTANCING__ */
return bvh_intersect(kg, ray, isect, visibility);
#else /* __KERNEL_CPU__ */
-#ifdef __INSTANCING__
+# ifdef __INSTANCING__
return bvh_intersect_instancing(kg, ray, isect, visibility);
-#else
+# else
return bvh_intersect(kg, ray, isect, visibility);
-#endif /* __INSTANCING__ */
+# endif /* __INSTANCING__ */
#endif /* __KERNEL_CPU__ */
}
#ifdef __SUBSURFACE__
-ccl_device_intersect uint scene_intersect_subsurface(KernelGlobals *kg, const Ray *ray, Intersection *isect, int subsurface_object, uint *lcg_state, int max_hits)
+ccl_device_intersect void scene_intersect_subsurface(KernelGlobals *kg,
+ const Ray *ray,
+ SubsurfaceIntersection *ss_isect,
+ int subsurface_object,
+ uint *lcg_state,
+ int max_hits)
{
#ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
-#ifdef __HAIR__
- if(kernel_data.bvh.have_curves)
- return bvh_intersect_subsurface_hair_motion(kg, ray, isect, subsurface_object, lcg_state, max_hits);
-#endif /* __HAIR__ */
-
- return bvh_intersect_subsurface_motion(kg, ray, isect, subsurface_object, lcg_state, max_hits);
+ return bvh_intersect_subsurface_motion(kg,
+ ray,
+ ss_isect,
+ subsurface_object,
+ lcg_state,
+ max_hits);
}
#endif /* __OBJECT_MOTION__ */
-
-#ifdef __HAIR__
- if(kernel_data.bvh.have_curves)
- return bvh_intersect_subsurface_hair(kg, ray, isect, subsurface_object, lcg_state, max_hits);
-#endif /* __HAIR__ */
-
-#ifdef __KERNEL_CPU__
-
-#ifdef __INSTANCING__
- if(kernel_data.bvh.have_instancing)
- return bvh_intersect_subsurface_instancing(kg, ray, isect, subsurface_object, lcg_state, max_hits);
-#endif /* __INSTANCING__ */
-
- return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, lcg_state, max_hits);
-#else /* __KERNEL_CPU__ */
-
-#ifdef __INSTANCING__
- return bvh_intersect_subsurface_instancing(kg, ray, isect, subsurface_object, lcg_state, max_hits);
-#else
- return bvh_intersect_subsurface(kg, ray, isect, subsurface_object, lcg_state, max_hits);
-#endif /* __INSTANCING__ */
-
-#endif /* __KERNEL_CPU__ */
+ return bvh_intersect_subsurface(kg,
+ ray,
+ ss_isect,
+ subsurface_object,
+ lcg_state,
+ max_hits);
}
#endif
#ifdef __SHADOW_RECORD_ALL__
ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals *kg, const Ray *ray, Intersection *isect, uint max_hits, uint *num_hits)
{
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
-#ifdef __HAIR__
+# ifdef __HAIR__
if(kernel_data.bvh.have_curves)
return bvh_intersect_shadow_all_hair_motion(kg, ray, isect, max_hits, num_hits);
-#endif /* __HAIR__ */
+# endif /* __HAIR__ */
return bvh_intersect_shadow_all_motion(kg, ray, isect, max_hits, num_hits);
}
-#endif /* __OBJECT_MOTION__ */
+# endif /* __OBJECT_MOTION__ */
-#ifdef __HAIR__
+# ifdef __HAIR__
if(kernel_data.bvh.have_curves)
return bvh_intersect_shadow_all_hair(kg, ray, isect, max_hits, num_hits);
-#endif /* __HAIR__ */
+# endif /* __HAIR__ */
-#ifdef __INSTANCING__
+# ifdef __INSTANCING__
if(kernel_data.bvh.have_instancing)
return bvh_intersect_shadow_all_instancing(kg, ray, isect, max_hits, num_hits);
-#endif /* __INSTANCING__ */
+# endif /* __INSTANCING__ */
return bvh_intersect_shadow_all(kg, ray, isect, max_hits, num_hits);
}
-#endif
+#endif /* __SHADOW_RECORD_ALL__ */
#ifdef __VOLUME__
ccl_device_intersect bool scene_intersect_volume(KernelGlobals *kg,
- const Ray *ray,
- Intersection *isect)
+ const Ray *ray,
+ Intersection *isect,
+ const uint visibility)
{
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
-#ifdef __HAIR__
- if(kernel_data.bvh.have_curves)
- return bvh_intersect_volume_hair_motion(kg, ray, isect);
-#endif /* __HAIR__ */
-
- return bvh_intersect_volume_motion(kg, ray, isect);
+ return bvh_intersect_volume_motion(kg, ray, isect, visibility);
}
-#endif /* __OBJECT_MOTION__ */
-
-#ifdef __HAIR__
- if(kernel_data.bvh.have_curves)
- return bvh_intersect_volume_hair(kg, ray, isect);
-#endif /* __HAIR__ */
-
-#ifdef __KERNEL_CPU__
-
-#ifdef __INSTANCING__
+# endif /* __OBJECT_MOTION__ */
+# ifdef __KERNEL_CPU__
+# ifdef __INSTANCING__
if(kernel_data.bvh.have_instancing)
- return bvh_intersect_volume_instancing(kg, ray, isect);
-#endif /* __INSTANCING__ */
-
- return bvh_intersect_volume(kg, ray, isect);
-#else /* __KERNEL_CPU__ */
-
-#ifdef __INSTANCING__
- return bvh_intersect_volume_instancing(kg, ray, isect);
-#else
- return bvh_intersect_volume(kg, ray, isect);
-#endif /* __INSTANCING__ */
-
-#endif /* __KERNEL_CPU__ */
+ return bvh_intersect_volume_instancing(kg, ray, isect, visibility);
+# endif /* __INSTANCING__ */
+ return bvh_intersect_volume(kg, ray, isect, visibility);
+# else /* __KERNEL_CPU__ */
+# ifdef __INSTANCING__
+ return bvh_intersect_volume_instancing(kg, ray, isect, visibility);
+# else
+ return bvh_intersect_volume(kg, ray, isect, visibility);
+# endif /* __INSTANCING__ */
+# endif /* __KERNEL_CPU__ */
}
-#endif
+#endif /* __VOLUME__ */
#ifdef __VOLUME_RECORD_ALL__
ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals *kg,
const Ray *ray,
Intersection *isect,
- const uint max_hits)
+ const uint max_hits,
+ const uint visibility)
{
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
if(kernel_data.bvh.have_motion) {
-#ifdef __HAIR__
- if(kernel_data.bvh.have_curves)
- return bvh_intersect_volume_all_hair_motion(kg, ray, isect, max_hits);
-#endif /* __HAIR__ */
-
- return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits);
+ return bvh_intersect_volume_all_motion(kg, ray, isect, max_hits, visibility);
}
-#endif /* __OBJECT_MOTION__ */
-
-#ifdef __HAIR__
- if(kernel_data.bvh.have_curves)
- return bvh_intersect_volume_all_hair(kg, ray, isect, max_hits);
-#endif /* __HAIR__ */
-
-#ifdef __INSTANCING__
+# endif /* __OBJECT_MOTION__ */
+# ifdef __INSTANCING__
if(kernel_data.bvh.have_instancing)
- return bvh_intersect_volume_all_instancing(kg, ray, isect, max_hits);
-#endif /* __INSTANCING__ */
-
- return bvh_intersect_volume_all(kg, ray, isect, max_hits);
+ return bvh_intersect_volume_all_instancing(kg, ray, isect, max_hits, visibility);
+# endif /* __INSTANCING__ */
+ return bvh_intersect_volume_all(kg, ray, isect, max_hits, visibility);
}
-#endif
+#endif /* __VOLUME_RECORD_ALL__ */
/* Ray offset to avoid self intersection.
diff --git a/intern/cycles/kernel/geom/geom_bvh_shadow.h b/intern/cycles/kernel/geom/geom_bvh_shadow.h
index e4cba99dc96..4005489f77d 100644
--- a/intern/cycles/kernel/geom/geom_bvh_shadow.h
+++ b/intern/cycles/kernel/geom/geom_bvh_shadow.h
@@ -18,7 +18,7 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_shadow.h"
+# include "geom_qbvh_shadow.h"
#endif
/* This is a template BVH traversal function, where various features can be
@@ -59,7 +59,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
float isect_t = tmax;
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
#if BVH_FEATURE(BVH_INSTANCING)
@@ -84,7 +84,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ssef tsplat(0.0f, 0.0f, -isect_t, -isect_t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+#endif /* __KERNEL_SSE2__ */
IsectPrecalc isect_precalc;
triangle_intersect_precalc(dir, &isect_precalc);
@@ -127,14 +127,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
/* decide which nodes to traverse next */
-#ifdef __VISIBILITY_FLAG__
+# ifdef __VISIBILITY_FLAG__
/* this visibility test gives a 5% performance hit, how to solve? */
traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW);
traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW);
-#else
+# else
traverseChild0 = (c0max >= c0min);
traverseChild1 = (c1max >= c1min);
-#endif
+# endif
#else // __KERNEL_SSE2__
/* Intersect two child bounding boxes, SSE3 version adapted from Embree */
@@ -154,14 +154,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
/* decide which nodes to traverse next */
-#ifdef __VISIBILITY_FLAG__
+# ifdef __VISIBILITY_FLAG__
/* this visibility test gives a 5% performance hit, how to solve? */
traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW);
traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW);
-#else
+# else
traverseChild0 = (movemask(lrhit) & 1);
traverseChild1 = (movemask(lrhit) & 2);
-#endif
+# endif
#endif // __KERNEL_SSE2__
nodeAddr = __float_as_int(cnodes.x);
@@ -301,24 +301,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* instance push */
object = kernel_tex_fetch(__prim_object, -primAddr-1);
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
num_hits_in_instance = 0;
isect_array->t = isect_t;
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
++stackPtr;
kernel_assert(stackPtr < BVH_STACK_SIZE);
@@ -337,11 +337,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
if(num_hits_in_instance) {
float t_fac;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
+# else
bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
@@ -352,25 +352,25 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
else {
float ignore_t = FLT_MAX;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
}
isect_t = tmax;
isect_array->t = isect_t;
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
object = OBJECT_NONE;
nodeAddr = traversalStack[stackPtr];
diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/geom/geom_bvh_subsurface.h
index a73139f9c88..915e9415c93 100644
--- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h
+++ b/intern/cycles/kernel/geom/geom_bvh_subsurface.h
@@ -18,21 +18,20 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_subsurface.h"
+# include "geom_qbvh_subsurface.h"
#endif
/* This is a template BVH traversal function for subsurface scattering, where
* various features can be enabled/disabled. This way we can compile optimized
* versions for each case without new features slowing things down.
*
- * BVH_INSTANCING: object instancing
* BVH_MOTION: motion blur rendering
*
*/
-ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
+ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const Ray *ray,
- Intersection *isect_array,
+ SubsurfaceIntersection *ss_isect,
int subsurface_object,
uint *lcg_state,
int max_hits)
@@ -41,17 +40,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
* - test if pushing distance on the stack helps (for non shadow rays)
* - separate version for shadow rays
* - likely and unlikely for if() statements
- * - SSE for hair
* - test restrict attribute for pointers
*/
-
+
/* traversal stack in CUDA thread-local memory */
int traversalStack[BVH_STACK_SIZE];
traversalStack[0] = ENTRYPOINT_SENTINEL;
/* traversal variables in registers */
int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
/* ray parameters in registers */
float3 P = ray->P;
@@ -60,16 +58,30 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
int object = OBJECT_NONE;
float isect_t = ray->t;
- uint num_hits = 0;
+ ss_isect->num_hits = 0;
+ const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object);
+ if(!(object_flag & SD_TRANSFORM_APPLIED)) {
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
+ bvh_instance_motion_push(kg,
+ subsurface_object,
+ ray,
+ &P,
+ &dir,
+ &idir,
+ &isect_t,
+ &ob_itfm);
+#else
+ bvh_instance_push(kg, subsurface_object, ray, &P, &dir, &idir, &isect_t);
#endif
+ object = subsurface_object;
+ }
#if defined(__KERNEL_SSE2__)
const shuffle_swap_t shuf_identity = shuffle_swap_identity();
const shuffle_swap_t shuf_swap = shuffle_swap_swap();
-
+
const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
ssef Psplat[3], idirsplat[3];
shuffle_swap_t shufflexyz[3];
@@ -190,124 +202,62 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
-#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
-#endif
- const int primAddr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
-
- /* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
-
- /* primitive intersection */
- switch(type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- /* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* only primitives from the same object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- if(tri_object != subsurface_object)
- continue;
- triangle_intersect_subsurface(kg, &isect_precalc, isect_array, P, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
- }
- break;
+ const int primAddr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
+
+ /* pop */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+
+ /* primitive intersection */
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ /* intersect ray against primitive */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ triangle_intersect_subsurface(kg,
+ &isect_precalc,
+ ss_isect,
+ P,
+ object,
+ primAddr,
+ isect_t,
+ lcg_state,
+ max_hits);
}
+ break;
+ }
#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- /* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* only primitives from the same object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- if(tri_object != subsurface_object)
- continue;
- motion_triangle_intersect_subsurface(kg, isect_array, P, dir, ray->time, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
- }
- break;
- }
-#endif
- default: {
- break;
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ /* intersect ray against primitive */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ motion_triangle_intersect_subsurface(kg,
+ ss_isect,
+ P,
+ dir,
+ ray->time,
+ object,
+ primAddr,
+ isect_t,
+ lcg_state,
+ max_hits);
}
+ break;
}
- }
-#if BVH_FEATURE(BVH_INSTANCING)
- else {
- /* instance push */
- if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
- object = subsurface_object;
-
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
- bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
-#if defined(__KERNEL_SSE2__)
- Psplat[0] = ssef(P.x);
- Psplat[1] = ssef(P.y);
- Psplat[2] = ssef(P.z);
-
- tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
-
- gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
#endif
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_STACK_SIZE);
- traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
-
- nodeAddr = kernel_tex_fetch(__object_node, object);
- }
- else {
- /* pop */
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
+ default: {
+ break;
}
}
}
-#endif /* FEATURE(BVH_INSTANCING) */
} while(nodeAddr != ENTRYPOINT_SENTINEL);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* instance pop */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
-
- triangle_intersect_precalc(dir, &isect_precalc);
-
-#if defined(__KERNEL_SSE2__)
- Psplat[0] = ssef(P.x);
- Psplat[1] = ssef(P.y);
- Psplat[2] = ssef(P.z);
-
- tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
-
- gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
-
- object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr];
- --stackPtr;
- }
-#endif /* FEATURE(BVH_INSTANCING) */
} while(nodeAddr != ENTRYPOINT_SENTINEL);
-
- return num_hits;
}
-ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
+ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg,
const Ray *ray,
- Intersection *isect_array,
+ SubsurfaceIntersection *ss_isect,
int subsurface_object,
uint *lcg_state,
int max_hits)
@@ -316,7 +266,7 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
if(kernel_data.bvh.use_qbvh) {
return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
ray,
- isect_array,
+ ss_isect,
subsurface_object,
lcg_state,
max_hits);
@@ -327,7 +277,7 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
kernel_assert(kernel_data.bvh.use_qbvh == false);
return BVH_FUNCTION_FULL_NAME(BVH)(kg,
ray,
- isect_array,
+ ss_isect,
subsurface_object,
lcg_state,
max_hits);
diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/geom/geom_bvh_traversal.h
index 73d79fd78ee..8560612addc 100644
--- a/intern/cycles/kernel/geom/geom_bvh_traversal.h
+++ b/intern/cycles/kernel/geom/geom_bvh_traversal.h
@@ -18,7 +18,7 @@
*/
#ifdef __QBVH__
-#include "geom_qbvh_traversal.h"
+# include "geom_qbvh_traversal.h"
#endif
/* This is a template BVH traversal function, where various features can be
@@ -65,7 +65,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
int object = OBJECT_NONE;
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
isect->t = ray->t;
@@ -136,7 +136,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
if(difl != 0.0f) {
float hdiff = 1.0f + difl;
float ldiff = 1.0f - difl;
@@ -149,17 +149,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
c1max = min(hdiff * c1max, c1max + extmax);
}
}
-#endif
+# endif
/* decide which nodes to traverse next */
-#ifdef __VISIBILITY_FLAG__
+# ifdef __VISIBILITY_FLAG__
/* this visibility test gives a 5% performance hit, how to solve? */
traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & visibility);
traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & visibility);
-#else
+# else
traverseChild0 = (c0max >= c0min);
traverseChild1 = (c1max >= c1min);
-#endif
+# endif
#else // __KERNEL_SSE2__
/* Intersect two child bounding boxes, SSE3 version adapted from Embree */
@@ -177,7 +177,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
const ssef tminmax = minmax ^ pn;
-#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
+# if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH)
if(difl != 0.0f) {
float4 *tminmaxview = (float4*)&tminmax;
float &c0min = tminmaxview->x, &c1min = tminmaxview->y;
@@ -194,19 +194,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
c1max = min(hdiff * c1max, c1max + extmax);
}
}
-#endif
+# endif
const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
/* decide which nodes to traverse next */
-#ifdef __VISIBILITY_FLAG__
+# ifdef __VISIBILITY_FLAG__
/* this visibility test gives a 5% performance hit, how to solve? */
traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & visibility);
traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & visibility);
-#else
+# else
traverseChild0 = (movemask(lrhit) & 1);
traverseChild1 = (movemask(lrhit) & 2);
-#endif
+# endif
#endif // __KERNEL_SSE2__
nodeAddr = __float_as_int(cnodes.x);
@@ -287,20 +287,20 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
+# if defined(__KERNEL_DEBUG__)
isect->num_traversal_steps++;
-#endif
+# endif
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
/* shadow ray early termination */
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-#else
+# else
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
-#endif
+# endif
}
}
break;
@@ -310,9 +310,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
+# if defined(__KERNEL_DEBUG__)
isect->num_traversal_steps++;
-#endif
+# endif
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
bool hit;
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
@@ -321,14 +321,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax);
if(hit) {
/* shadow ray early termination */
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
-#else
+# else
if(visibility == PATH_RAY_SHADOW_OPAQUE)
return true;
-#endif
+# endif
}
}
break;
@@ -341,14 +341,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* instance push */
object = kernel_tex_fetch(__prim_object, -primAddr-1);
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
@@ -356,7 +356,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
++stackPtr;
kernel_assert(stackPtr < BVH_STACK_SIZE);
@@ -364,9 +364,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
nodeAddr = kernel_tex_fetch(__object_node, object);
-#if defined(__KERNEL_DEBUG__)
+# if defined(__KERNEL_DEBUG__)
isect->num_traversed_instances++;
-#endif
+# endif
}
}
#endif /* FEATURE(BVH_INSTANCING) */
@@ -377,14 +377,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
kernel_assert(object != OBJECT_NONE);
/* instance pop */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
@@ -392,7 +392,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
object = OBJECT_NONE;
nodeAddr = traversalStack[stackPtr];
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/geom/geom_bvh_volume.h
index 41c784869f2..f3edf85d723 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume.h
+++ b/intern/cycles/kernel/geom/geom_bvh_volume.h
@@ -26,14 +26,14 @@
* versions for each case without new features slowing things down.
*
* BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
* BVH_MOTION: motion blur rendering
*
*/
ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const Ray *ray,
- Intersection *isect)
+ Intersection *isect,
+ const uint visibility)
{
/* todo:
* - test if pushing distance on the stack helps (for non shadow rays)
@@ -56,10 +56,8 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
float3 idir = bvh_inverse_direction(dir);
int object = OBJECT_NONE;
- const uint visibility = PATH_RAY_ALL_VISIBILITY;
-
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
isect->t = ray->t;
@@ -233,26 +231,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
break;
}
#endif
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- /* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- }
- break;
- }
-#endif
default: {
break;
}
@@ -266,15 +244,15 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
if(object_flag & SD_OBJECT_HAS_VOLUME) {
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
@@ -282,7 +260,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
++stackPtr;
kernel_assert(stackPtr < BVH_STACK_SIZE);
@@ -306,15 +284,15 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
kernel_assert(object != OBJECT_NONE);
/* instance pop */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
@@ -322,7 +300,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
object = OBJECT_NONE;
nodeAddr = traversalStack[stackPtr];
@@ -336,13 +314,15 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
const Ray *ray,
- Intersection *isect)
+ Intersection *isect,
+ const uint visibility)
{
#ifdef __QBVH__
if(kernel_data.bvh.use_qbvh) {
return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
ray,
- isect);
+ isect,
+ visibility);
}
else
#endif
@@ -350,7 +330,8 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg,
kernel_assert(kernel_data.bvh.use_qbvh == false);
return BVH_FUNCTION_FULL_NAME(BVH)(kg,
ray,
- isect);
+ isect,
+ visibility);
}
}
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume_all.h b/intern/cycles/kernel/geom/geom_bvh_volume_all.h
index b6db36f4b17..ec837212471 100644
--- a/intern/cycles/kernel/geom/geom_bvh_volume_all.h
+++ b/intern/cycles/kernel/geom/geom_bvh_volume_all.h
@@ -26,7 +26,6 @@
* versions for each case without new features slowing things down.
*
* BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
* BVH_MOTION: motion blur rendering
*
*/
@@ -34,7 +33,8 @@
ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
- const uint max_hits)
+ const uint max_hits,
+ const uint visibility)
{
/* todo:
* - test if pushing distance on the stack helps (for non shadow rays)
@@ -59,10 +59,8 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
int object = OBJECT_NONE;
float isect_t = tmax;
- const uint visibility = PATH_RAY_ALL_VISIBILITY;
-
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
#if BVH_FEATURE(BVH_INSTANCING)
@@ -229,12 +227,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
isect_array->t = isect_t;
if(num_hits == max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
-#if BVH_FEATURE(BVH_MOTION)
- float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
-#else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- float t_fac = len(transform_direction(&tfm, 1.0f/idir));
-#endif
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+# else
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+# endif
for(int i = 0; i < num_hits_in_instance; i++) {
(isect_array-i-1)->t *= t_fac;
}
@@ -261,72 +259,29 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
/* Move on to next entry in intersections array. */
isect_array++;
num_hits++;
-#if BVH_FEATURE(BVH_INSTANCING)
- num_hits_in_instance++;
-#endif
- isect_array->t = isect_t;
- if(num_hits == max_hits) {
-#if BVH_FEATURE(BVH_INSTANCING)
-# if BVH_FEATURE(BVH_MOTION)
- float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
-# else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- float t_fac = len(transform_direction(&tfm, 1.0f/idir));
-#endif
- for(int i = 0; i < num_hits_in_instance; i++) {
- (isect_array-i-1)->t *= t_fac;
- }
-#endif /* BVH_FEATURE(BVH_INSTANCING) */
- return num_hits;
- }
- }
- }
- break;
- }
-#endif
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- /* intersect ray against primitive */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* only primitives from volume object */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- hit = bvh_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- if(hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
- num_hits++;
-#if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
-#endif
+# endif
isect_array->t = isect_t;
if(num_hits == max_hits) {
-#if BVH_FEATURE(BVH_INSTANCING)
-# if BVH_FEATURE(BVH_MOTION)
- float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
-# else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- float t_fac = len(transform_direction(&tfm, 1.0f/idir));
-#endif
+# if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+# else
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+# endif
for(int i = 0; i < num_hits_in_instance; i++) {
(isect_array-i-1)->t *= t_fac;
}
-#endif /* BVH_FEATURE(BVH_INSTANCING) */
+# endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
}
}
}
break;
}
-#endif
+#endif /* BVH_MOTION */
default: {
break;
}
@@ -340,17 +295,17 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
if(object_flag & SD_OBJECT_HAS_VOLUME) {
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
num_hits_in_instance = 0;
isect_array->t = isect_t;
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
@@ -358,7 +313,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
++stackPtr;
kernel_assert(stackPtr < BVH_STACK_SIZE);
@@ -383,11 +338,11 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
if(num_hits_in_instance) {
float t_fac;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
+# else
bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
/* Scale isect->t to adjust for instancing. */
for(int i = 0; i < num_hits_in_instance; i++) {
@@ -396,18 +351,18 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
}
else {
float ignore_t = FLT_MAX;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
}
isect_t = tmax;
isect_array->t = isect_t;
-#if defined(__KERNEL_SSE2__)
+# if defined(__KERNEL_SSE2__)
Psplat[0] = ssef(P.x);
Psplat[1] = ssef(P.y);
Psplat[2] = ssef(P.z);
@@ -415,7 +370,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t);
gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
-#endif
+# endif
object = OBJECT_NONE;
nodeAddr = traversalStack[stackPtr];
@@ -430,14 +385,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
- const uint max_hits)
+ const uint max_hits,
+ const uint visibility)
{
#ifdef __QBVH__
if(kernel_data.bvh.use_qbvh) {
return BVH_FUNCTION_FULL_NAME(QBVH)(kg,
ray,
isect_array,
- max_hits);
+ max_hits,
+ visibility);
}
else
#endif
@@ -446,7 +403,8 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg,
return BVH_FUNCTION_FULL_NAME(BVH)(kg,
ray,
isect_array,
- max_hits);
+ max_hits,
+ visibility);
}
}
diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h
index 9653ad8f1bb..8894843997c 100644
--- a/intern/cycles/kernel/geom/geom_curve.h
+++ b/intern/cycles/kernel/geom/geom_curve.h
@@ -626,9 +626,9 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec
{
/* define few macros to minimize code duplication for SSE */
#ifndef __KERNEL_SSE2__
-#define len3_squared(x) len_squared(x)
-#define len3(x) len(x)
-#define dot3(x, y) dot(x, y)
+# define len3_squared(x) len_squared(x)
+# define len3(x) len(x)
+# define dot3(x, y) dot(x, y)
#endif
int segment = PRIMITIVE_UNPACK_SEGMENT(type);
@@ -850,10 +850,10 @@ ccl_device_inline bool bvh_curve_intersect(KernelGlobals *kg, Intersection *isec
return false;
#ifndef __KERNEL_SSE2__
-#undef len3_squared
-#undef len3
-#undef dot3
-#endif
+# undef len3_squared
+# undef len3
+# undef dot3
+# endif
}
ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3)
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
index 86f93f242a1..ffe55529110 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ b/intern/cycles/kernel/geom/geom_motion_triangle.h
@@ -133,11 +133,11 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *s
if(UNLIKELY(t == 0.0f)) {
return P;
}
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_itfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
-#endif
+# endif
P = transform_point(&tfm, P);
D = transform_direction(&tfm, D*t);
@@ -160,11 +160,11 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *s
P = P + D*rt;
if(isect->object != OBJECT_NONE) {
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_tfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
-#endif
+# endif
P = transform_point(&tfm, P);
}
@@ -178,19 +178,24 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *s
/* Same as above, except that isect->t is assumed to be in object space for instancing */
#ifdef __SUBSURFACE__
-ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3])
+# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
+ccl_device_noinline
+# else
+ccl_device_inline
+# endif
+float3 motion_triangle_refine_subsurface(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3])
{
float3 P = ray->P;
float3 D = ray->D;
float t = isect->t;
-#ifdef __INTERSECTION_REFINE__
+# ifdef __INTERSECTION_REFINE__
if(isect->object != OBJECT_NONE) {
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_itfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
-#endif
+# endif
P = transform_point(&tfm, P);
D = transform_direction(&tfm, D);
@@ -212,19 +217,19 @@ ccl_device_inline float3 motion_triangle_refine_subsurface(KernelGlobals *kg, Sh
P = P + D*rt;
if(isect->object != OBJECT_NONE) {
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_tfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
-#endif
+# endif
P = transform_point(&tfm, P);
}
return P;
-#else
+# else
return P + D*t;
-#endif
+# endif
}
#endif
@@ -358,8 +363,17 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, Intersection
* multiple hits we pick a single random primitive as the intersection point. */
#ifdef __SUBSURFACE__
-ccl_device_inline void motion_triangle_intersect_subsurface(KernelGlobals *kg, Intersection *isect_array,
- float3 P, float3 dir, float time, int object, int triAddr, float tmax, uint *num_hits, uint *lcg_state, int max_hits)
+ccl_device_inline void motion_triangle_intersect_subsurface(
+ KernelGlobals *kg,
+ SubsurfaceIntersection *ss_isect,
+ float3 P,
+ float3 dir,
+ float time,
+ int object,
+ int triAddr,
+ float tmax,
+ uint *lcg_state,
+ int max_hits)
{
/* primitive index for vertex location lookup */
int prim = kernel_tex_fetch(__prim_index, triAddr);
@@ -373,30 +387,34 @@ ccl_device_inline void motion_triangle_intersect_subsurface(KernelGlobals *kg, I
float t, u, v;
if(ray_triangle_intersect_uv(P, dir, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) {
- (*num_hits)++;
+ ss_isect->num_hits++;
int hit;
- if(*num_hits <= max_hits) {
- hit = *num_hits - 1;
+ if(ss_isect->num_hits <= max_hits) {
+ hit = ss_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
- hit = lcg_step_uint(lcg_state) % *num_hits;
+ hit = lcg_step_uint(lcg_state) % ss_isect->num_hits;
if(hit >= max_hits)
return;
}
/* record intersection */
- Intersection *isect = &isect_array[hit];
+ Intersection *isect = &ss_isect->hits[hit];
isect->t = t;
isect->u = u;
isect->v = v;
isect->prim = triAddr;
isect->object = object;
isect->type = PRIMITIVE_MOTION_TRIANGLE;
+
+ /* Record geometric normal. */
+ ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0],
+ verts[2] - verts[0]));
}
}
#endif
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index 9d0a008fff1..ffd2f3b778f 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -428,8 +428,8 @@ ccl_device_inline void qbvh_instance_push(KernelGlobals *kg,
ccl_device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t)
{
if(*t != FLT_MAX) {
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- *t *= len(transform_direction(&tfm, 1.0f/(*idir)));
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ *t /= len(transform_direction(&tfm, ray->D));
}
*P = ray->P;
@@ -441,8 +441,8 @@ ccl_device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray
ccl_device_inline void bvh_instance_pop_factor(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t_fac)
{
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- *t_fac = len(transform_direction(&tfm, 1.0f/(*idir)));
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ *t_fac = 1.0f / len(transform_direction(&tfm, ray->D));
*P = ray->P;
*dir = bvh_clamp_direction(ray->D);
@@ -453,15 +453,21 @@ ccl_device_inline void bvh_instance_pop_factor(KernelGlobals *kg, int object, co
#ifdef __OBJECT_MOTION__
/* Transform ray into object space to enter motion blurred object in BVH */
-ccl_device_inline void bvh_instance_motion_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t, Transform *tfm)
+ccl_device_inline void bvh_instance_motion_push(KernelGlobals *kg,
+ int object,
+ const Ray *ray,
+ float3 *P,
+ float3 *dir,
+ float3 *idir,
+ ccl_addr_space float *t,
+ Transform *itfm)
{
- Transform itfm;
- *tfm = object_fetch_transform_motion_test(kg, object, ray->time, &itfm);
+ object_fetch_transform_motion_test(kg, object, ray->time, itfm);
- *P = transform_point(&itfm, ray->P);
+ *P = transform_point(itfm, ray->P);
float len;
- *dir = bvh_clamp_direction(normalize_len(transform_direction(&itfm, ray->D), &len));
+ *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
*idir = bvh_inverse_direction(*dir);
if(*t != FLT_MAX)
@@ -475,18 +481,24 @@ ccl_device_inline void bvh_instance_motion_push(KernelGlobals *kg, int object, c
* TODO(sergey): Investigate if passing NULL instead of t1 gets optimized
* so we can avoid having this duplication.
*/
-ccl_device_inline void qbvh_instance_motion_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t, float *t1, Transform *tfm)
+ccl_device_inline void qbvh_instance_motion_push(KernelGlobals *kg,
+ int object,
+ const Ray *ray,
+ float3 *P,
+ float3 *dir,
+ float3 *idir,
+ float *t,
+ float *t1,
+ Transform *itfm)
{
- Transform itfm;
- *tfm = object_fetch_transform_motion_test(kg, object, ray->time, &itfm);
+ object_fetch_transform_motion_test(kg, object, ray->time, itfm);
- *P = transform_point(&itfm, ray->P);
+ *P = transform_point(itfm, ray->P);
float len;
- *dir = bvh_clamp_direction(normalize_len(transform_direction(&itfm, ray->D), &len));
+ *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
*idir = bvh_inverse_direction(*dir);
-
if(*t != FLT_MAX)
*t *= len;
@@ -497,10 +509,18 @@ ccl_device_inline void qbvh_instance_motion_push(KernelGlobals *kg, int object,
/* Transorm ray to exit motion blurred object in BVH */
-ccl_device_inline void bvh_instance_motion_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t, Transform *tfm)
+ccl_device_inline void bvh_instance_motion_pop(KernelGlobals *kg,
+ int object,
+ const Ray *ray,
+ float3 *P,
+ float3 *dir,
+ float3 *idir,
+ ccl_addr_space float *t,
+ Transform *itfm)
{
- if(*t != FLT_MAX)
- *t *= len(transform_direction(tfm, 1.0f/(*idir)));
+ if(*t != FLT_MAX) {
+ *t /= len(transform_direction(itfm, ray->D));
+ }
*P = ray->P;
*dir = bvh_clamp_direction(ray->D);
@@ -509,10 +529,16 @@ ccl_device_inline void bvh_instance_motion_pop(KernelGlobals *kg, int object, co
/* Same as above, but returns scale factor to apply to multiple intersection distances */
-ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t_fac, Transform *tfm)
+ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals *kg,
+ int object,
+ const Ray *ray,
+ float3 *P,
+ float3 *dir,
+ float3 *idir,
+ float *t_fac,
+ Transform *itfm)
{
- *t_fac = len(transform_direction(tfm, 1.0f/(*idir)));
-
+ *t_fac /= len(transform_direction(itfm, ray->D));
*P = ray->P;
*dir = bvh_clamp_direction(ray->D);
*idir = bvh_inverse_direction(*dir);
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index 30f12d32355..b1b1e919e00 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -109,11 +109,11 @@ ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
{
#ifdef __HAIR__
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)
-#ifdef __DPDU__
+# ifdef __DPDU__
return normalize(ccl_fetch(sd, dPdu));
-#else
+# else
return make_float3(0.0f, 0.0f, 0.0f);
-#endif
+# endif
#endif
/* try to create spherical tangent from generated coordinates */
diff --git a/intern/cycles/kernel/geom/geom_qbvh.h b/intern/cycles/kernel/geom/geom_qbvh.h
index 37deaac0800..2a2d7822eee 100644
--- a/intern/cycles/kernel/geom/geom_qbvh.h
+++ b/intern/cycles/kernel/geom/geom_qbvh.h
@@ -19,7 +19,7 @@ struct QBVHStackItem {
float dist;
};
-/* TOOD(sergey): Investigate if using instrinsics helps for both
+/* TOOD(sergey): Investigate if using intrinsics helps for both
* stack item swap and float comparison.
*/
ccl_device_inline void qbvh_item_swap(QBVHStackItem *__restrict a,
diff --git a/intern/cycles/kernel/geom/geom_qbvh_shadow.h b/intern/cycles/kernel/geom/geom_qbvh_shadow.h
index dc37e6ecfa4..edb5b5c78c3 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_shadow.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_shadow.h
@@ -55,7 +55,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
float isect_t = tmax;
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
*num_hits = 0;
@@ -316,11 +316,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Instance push. */
object = kernel_tex_fetch(__prim_object, -primAddr-1);
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
+# endif
num_hits_in_instance = 0;
isect_array->t = isect_t;
@@ -330,12 +330,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect_t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
++stackPtr;
@@ -356,11 +356,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(num_hits_in_instance) {
float t_fac;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
+# else
bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
-#endif
+# endif
/* scale isect->t to adjust for instancing */
for(int i = 0; i < num_hits_in_instance; i++)
@@ -369,11 +369,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
else {
float ignore_t = FLT_MAX;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
-#endif
+# endif
}
isect_t = tmax;
@@ -384,12 +384,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(tmax);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
object = OBJECT_NONE;
diff --git a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h b/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
index d85e1a4691e..84512a8783c 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_subsurface.h
@@ -21,14 +21,13 @@
* various features can be enabled/disabled. This way we can compile optimized
* versions for each case without new features slowing things down.
*
- * BVH_INSTANCING: object instancing
* BVH_MOTION: motion blur rendering
*
*/
-ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
+ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
- Intersection *isect_array,
+ SubsurfaceIntersection *ss_isect,
int subsurface_object,
uint *lcg_state,
int max_hits)
@@ -47,7 +46,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Traversal variables in registers. */
int stackPtr = 0;
- int nodeAddr = kernel_data.bvh.root;
+ int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object);
/* Ray parameters in registers. */
float3 P = ray->P;
@@ -55,15 +54,30 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
float3 idir = bvh_inverse_direction(dir);
int object = OBJECT_NONE;
float isect_t = ray->t;
- uint num_hits = 0;
+ ss_isect->num_hits = 0;
+
+ const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object);
+ if(!(object_flag & SD_TRANSFORM_APPLIED)) {
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
+ bvh_instance_motion_push(kg,
+ subsurface_object,
+ ray,
+ &P,
+ &dir,
+ &idir,
+ &isect_t,
+ &ob_itfm);
+#else
+ bvh_instance_push(kg, subsurface_object, ray, &P, &dir, &idir, &isect_t);
#endif
+ object = subsurface_object;
+ }
#ifndef __KERNEL_SSE41__
if(!isfinite(P.x)) {
- return 0;
+ return;
}
#endif
@@ -205,122 +219,54 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE);
int primAddr = __float_as_int(leaf.x);
-#if BVH_FEATURE(BVH_INSTANCING)
- if(primAddr >= 0) {
-#endif
- int primAddr2 = __float_as_int(leaf.y);
- const uint type = __float_as_int(leaf.w);
+ int primAddr2 = __float_as_int(leaf.y);
+ const uint type = __float_as_int(leaf.w);
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
+ /* Pop. */
+ nodeAddr = traversalStack[stackPtr].addr;
+ --stackPtr;
- /* Primitive intersection. */
- switch(type & PRIMITIVE_ALL) {
- case PRIMITIVE_TRIANGLE: {
- /* Intersect ray against primitive, */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* Only primitives from the same object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- if(tri_object != subsurface_object) {
- continue;
- }
- triangle_intersect_subsurface(kg, &isect_precalc, isect_array, P, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
- }
- break;
+ /* Primitive intersection. */
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ /* Intersect ray against primitive, */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ triangle_intersect_subsurface(kg,
+ &isect_precalc,
+ ss_isect,
+ P,
+ object,
+ primAddr,
+ isect_t,
+ lcg_state,
+ max_hits);
}
+ break;
+ }
#if BVH_FEATURE(BVH_MOTION)
- case PRIMITIVE_MOTION_TRIANGLE: {
- /* Intersect ray against primitive. */
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* Only primitives from the same object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- if(tri_object != subsurface_object) {
- continue;
- }
- motion_triangle_intersect_subsurface(kg, isect_array, P, dir, ray->time, object, primAddr, isect_t, &num_hits, lcg_state, max_hits);
- }
- break;
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ /* Intersect ray against primitive. */
+ for(; primAddr < primAddr2; primAddr++) {
+ kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
+ motion_triangle_intersect_subsurface(kg,
+ ss_isect,
+ P,
+ dir,
+ ray->time,
+ object,
+ primAddr,
+ isect_t,
+ lcg_state,
+ max_hits);
}
-#endif
- default:
- break;
+ break;
}
- }
-#if BVH_FEATURE(BVH_INSTANCING)
- else {
- /* Instance push. */
- if(subsurface_object == kernel_tex_fetch(__prim_object, -primAddr-1)) {
- object = subsurface_object;
-
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
- bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
#endif
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect_t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- ++stackPtr;
- kernel_assert(stackPtr < BVH_QSTACK_SIZE);
- traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL;
-
- nodeAddr = kernel_tex_fetch(__object_node, object);
- }
- else {
- /* Pop. */
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
- }
-
+ default:
+ break;
}
}
-#endif /* FEATURE(BVH_INSTANCING) */
} while(nodeAddr != ENTRYPOINT_SENTINEL);
-
-#if BVH_FEATURE(BVH_INSTANCING)
- if(stackPtr >= 0) {
- kernel_assert(object != OBJECT_NONE);
-
- /* Instance pop. */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
- bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
-
- if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
- if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
- if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
- tfar = ssef(isect_t);
- idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
- P_idir = P*idir;
- P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
- org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
- triangle_intersect_precalc(dir, &isect_precalc);
-
- object = OBJECT_NONE;
- nodeAddr = traversalStack[stackPtr].addr;
- --stackPtr;
- }
-#endif /* FEATURE(BVH_INSTANCING) */
} while(nodeAddr != ENTRYPOINT_SENTINEL);
-
- return num_hits;
}
diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
index 7e356ea062b..ce3bbbdf957 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_traversal.h
@@ -63,7 +63,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
int object = OBJECT_NONE;
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
#ifndef __KERNEL_SSE41__
@@ -134,11 +134,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
traverseChild = qbvh_node_intersect_robust(kg,
tnear,
tfar,
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir4,
-#else
+# else
org,
-#endif
+# endif
idir4,
near_x, near_y, near_z,
far_x, far_y, far_z,
@@ -147,7 +147,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
&dist);
}
else
-#endif
+#endif /* BVH_HAIR_MINIMUM_WIDTH */
{
traverseChild = qbvh_node_intersect(kg,
tnear,
@@ -311,9 +311,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_MOTION)
case PRIMITIVE_MOTION_TRIANGLE: {
for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
+# if defined(__KERNEL_DEBUG__)
isect->num_traversal_steps++;
-#endif
+# endif
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) {
tfar = ssef(isect->t);
@@ -329,9 +329,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
case PRIMITIVE_CURVE:
case PRIMITIVE_MOTION_CURVE: {
for(; primAddr < primAddr2; primAddr++) {
-#if defined(__KERNEL_DEBUG__)
+# if defined(__KERNEL_DEBUG__)
isect->num_traversal_steps++;
-#endif
+# endif
kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
bool hit;
if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
@@ -355,23 +355,23 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Instance push. */
object = kernel_tex_fetch(__prim_object, -primAddr-1);
-#if BVH_FEATURE(BVH_MOTION)
- qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist, &ob_itfm);
+# else
qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist);
-#endif
+# endif
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect->t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
++stackPtr;
@@ -381,9 +381,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
nodeAddr = kernel_tex_fetch(__object_node, object);
-#if defined(__KERNEL_DEBUG__)
+# if defined(__KERNEL_DEBUG__)
isect->num_traversed_instances++;
-#endif
+# endif
}
}
#endif /* FEATURE(BVH_INSTANCING) */
@@ -394,23 +394,23 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
kernel_assert(object != OBJECT_NONE);
/* Instance pop. */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect->t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
object = OBJECT_NONE;
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume.h b/intern/cycles/kernel/geom/geom_qbvh_volume.h
index d8cfa3a4061..ab2e530dd20 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_volume.h
@@ -22,14 +22,14 @@
* versions for each case without new features slowing things down.
*
* BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
* BVH_MOTION: motion blur rendering
*
*/
ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
- Intersection *isect)
+ Intersection *isect,
+ const uint visibility)
{
/* TODO(sergey):
* - Test if pushing distance on the stack helps.
@@ -51,10 +51,8 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
float3 idir = bvh_inverse_direction(dir);
int object = OBJECT_NONE;
- const uint visibility = PATH_RAY_ALL_VISIBILITY;
-
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
#ifndef __KERNEL_SSE41__
@@ -250,26 +248,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
break;
}
#endif
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- /* Intersect ray against primitive. */
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- }
- break;
- }
-#endif
}
}
#if BVH_FEATURE(BVH_INSTANCING)
@@ -280,23 +258,23 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(object_flag & SD_OBJECT_HAS_VOLUME) {
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect->t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
++stackPtr;
@@ -321,23 +299,23 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
kernel_assert(object != OBJECT_NONE);
/* Instance pop. */
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
-#endif
+# endif
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect->t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
object = OBJECT_NONE;
diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h b/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
index 056ca9a1ad9..5546471b0e3 100644
--- a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
+++ b/intern/cycles/kernel/geom/geom_qbvh_volume_all.h
@@ -22,7 +22,6 @@
* versions for each case without new features slowing things down.
*
* BVH_INSTANCING: object instancing
- * BVH_HAIR: hair curve rendering
* BVH_MOTION: motion blur rendering
*
*/
@@ -30,7 +29,8 @@
ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
const Ray *ray,
Intersection *isect_array,
- const uint max_hits)
+ const uint max_hits,
+ const uint visibility)
{
/* TODO(sergey):
* - Test if pushing distance on the stack helps.
@@ -54,10 +54,8 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
int object = OBJECT_NONE;
float isect_t = tmax;
- const uint visibility = PATH_RAY_ALL_VISIBILITY;
-
#if BVH_FEATURE(BVH_MOTION)
- Transform ob_tfm;
+ Transform ob_itfm;
#endif
uint num_hits = 0;
@@ -246,12 +244,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
isect_array->t = isect_t;
if(num_hits == max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
-#if BVH_FEATURE(BVH_MOTION)
- float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
-#else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- float t_fac = len(transform_direction(&tfm, 1.0f/idir));
-#endif
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+# else
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+# endif
for(int i = 0; i < num_hits_in_instance; i++) {
(isect_array-i-1)->t *= t_fac;
}
@@ -278,65 +276,22 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Move on to next entry in intersections array. */
isect_array++;
num_hits++;
-#if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
-#endif
+# endif
isect_array->t = isect_t;
if(num_hits == max_hits) {
-#if BVH_FEATURE(BVH_INSTANCING)
-# if BVH_FEATURE(BVH_MOTION)
- float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
-# else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- float t_fac = len(transform_direction(&tfm, 1.0f/idir));
-#endif
+# if BVH_FEATURE(BVH_INSTANCING)
+# if BVH_FEATURE(BVH_MOTION)
+ float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
+# else
+ Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ float t_fac = 1.0f / len(transform_direction(&itfm, dir));
+# endif
for(int i = 0; i < num_hits_in_instance; i++) {
(isect_array-i-1)->t *= t_fac;
}
-#endif /* BVH_FEATURE(BVH_INSTANCING) */
- return num_hits;
- }
- }
- }
- break;
- }
-#endif
-#if BVH_FEATURE(BVH_HAIR)
- case PRIMITIVE_CURVE:
- case PRIMITIVE_MOTION_CURVE: {
- for(; primAddr < primAddr2; primAddr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type);
- /* Only primitives from volume object. */
- uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
- if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
- continue;
- }
- /* Intersect ray against primitive. */
- if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
- hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- else
- hit = bvh_curve_intersect(kg, isect_array, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
- if(hit) {
- /* Move on to next entry in intersections array. */
- isect_array++;
- num_hits++;
-#if BVH_FEATURE(BVH_INSTANCING)
- num_hits_in_instance++;
-#endif
- isect_array->t = isect_t;
- if(num_hits == max_hits) {
-#if BVH_FEATURE(BVH_INSTANCING)
-# if BVH_FEATURE(BVH_MOTION)
- float t_fac = len(transform_direction(&ob_tfm, 1.0f/idir));
-# else
- Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
- float t_fac = len(transform_direction(&tfm, 1.0f/idir));
-#endif
- for(int i = 0; i < num_hits_in_instance; i++) {
- (isect_array-i-1)->t *= t_fac;
- }
-#endif /* BVH_FEATURE(BVH_INSTANCING) */
+# endif /* BVH_FEATURE(BVH_INSTANCING) */
return num_hits;
}
}
@@ -354,23 +309,23 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(object_flag & SD_OBJECT_HAS_VOLUME) {
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm);
+# else
bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t);
-#endif
+# endif
if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; }
if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; }
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect_t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
num_hits_in_instance = 0;
isect_array->t = isect_t;
@@ -399,11 +354,11 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
/* Instance pop. */
if(num_hits_in_instance) {
float t_fac;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm);
+# else
bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
/* Scale isect->t to adjust for instancing. */
for(int i = 0; i < num_hits_in_instance; i++) {
@@ -412,11 +367,11 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
}
else {
float ignore_t = FLT_MAX;
-#if BVH_FEATURE(BVH_MOTION)
- bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_tfm);
-#else
+# if BVH_FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &ignore_t, &ob_itfm);
+# else
bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &ignore_t);
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
}
@@ -425,12 +380,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; }
tfar = ssef(isect_t);
idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z));
-#ifdef __KERNEL_AVX2__
+# ifdef __KERNEL_AVX2__
P_idir = P*idir;
P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z);
-#else
+# else
org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z));
-#endif
+# endif
triangle_intersect_precalc(dir, &isect_precalc);
isect_t = tmax;
isect_array->t = isect_t;
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index ba309a1dc53..d2957ad5474 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -49,25 +49,12 @@ typedef struct IsectPrecalc {
float Sx, Sy, Sz;
} IsectPrecalc;
-#if defined(__KERNEL_CUDA__)
-# if (defined(i386) || defined(_M_IX86))
-# if __CUDA_ARCH__ > 500
+#if (defined(__KERNEL_OPENCL_APPLE__)) || \
+ (defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)))
ccl_device_noinline
-# else /* __CUDA_ARCH__ > 500 */
-ccl_device_inline
-# endif /* __CUDA_ARCH__ > 500 */
-# else /* (defined(i386) || defined(_M_IX86)) */
-# if defined(__KERNEL_EXPERIMENTAL__) && (__CUDA_ARCH__ >= 500)
-ccl_device_noinline
-# else
-ccl_device_inline
-# endif
-# endif /* (defined(i386) || defined(_M_IX86)) */
-#elif defined(__KERNEL_OPENCL_APPLE__)
-ccl_device_noinline
-#else /* defined(__KERNEL_OPENCL_APPLE__) */
+#else
ccl_device_inline
-#endif /* defined(__KERNEL_OPENCL_APPLE__) */
+#endif
void triangle_intersect_precalc(float3 dir,
IsectPrecalc *isect_precalc)
{
@@ -119,9 +106,9 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0),
+ tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1),
+ tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2);
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -142,12 +129,8 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
float U = Cx * By - Cy * Bx;
float V = Ax * Cy - Ay * Cx;
float W = Bx * Ay - By * Ax;
- const int sign_mask = (__float_as_int(U) & 0x80000000);
- /* TODO(sergey): Check if multiplication plus sign check is faster
- * or at least same speed (but robust for endian types).
- */
- if(sign_mask != (__float_as_int(V) & 0x80000000) ||
- sign_mask != (__float_as_int(W) & 0x80000000))
+ if((U < 0.0f || V < 0.0f || W < 0.0f) &&
+ (U > 0.0f || V > 0.0f || W > 0.0f))
{
return false;
}
@@ -162,9 +145,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
* the hit distance.
*/
const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz;
- const float sign_T = xor_signmask(T, sign_mask);
+ const int sign_det = (__float_as_int(det) & 0x80000000);
+ const float sign_T = xor_signmask(T, sign_det);
if((sign_T < 0.0f) ||
- (sign_T > isect->t * xor_signmask(det, sign_mask)))
+ (sign_T > isect->t * xor_signmask(det, sign_det)))
{
return false;
}
@@ -207,12 +191,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
ccl_device_inline void triangle_intersect_subsurface(
KernelGlobals *kg,
const IsectPrecalc *isect_precalc,
- Intersection *isect_array,
+ SubsurfaceIntersection *ss_isect,
float3 P,
int object,
int triAddr,
float tmax,
- uint *num_hits,
uint *lcg_state,
int max_hits)
{
@@ -224,9 +207,9 @@ ccl_device_inline void triangle_intersect_subsurface(
const float Sz = isect_precalc->Sz;
/* Calculate vertices relative to ray origin. */
- const float4 tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0),
+ tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1),
+ tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2);
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
@@ -245,13 +228,12 @@ ccl_device_inline void triangle_intersect_subsurface(
/* Calculate scaled barycentric coordinates. */
float U = Cx * By - Cy * Bx;
- int sign_mask = (__float_as_int(U) & 0x80000000);
float V = Ax * Cy - Ay * Cx;
- if(sign_mask != (__float_as_int(V) & 0x80000000)) {
- return;
- }
float W = Bx * Ay - By * Ax;
- if(sign_mask != (__float_as_int(W) & 0x80000000)) {
+
+ if((U < 0.0f || V < 0.0f || W < 0.0f) &&
+ (U > 0.0f || V > 0.0f || W > 0.0f))
+ {
return;
}
@@ -264,10 +246,11 @@ ccl_device_inline void triangle_intersect_subsurface(
/* Calculate scaled z−coordinates of vertices and use them to calculate
* the hit distance.
*/
+ const int sign_det = (__float_as_int(det) & 0x80000000);
const float T = (U * A_kz + V * B_kz + W * C_kz) * Sz;
- const float sign_T = xor_signmask(T, sign_mask);
+ const float sign_T = xor_signmask(T, sign_det);
if((sign_T < 0.0f) ||
- (sign_T > tmax * xor_signmask(det, sign_mask)))
+ (sign_T > tmax * xor_signmask(det, sign_det)))
{
return;
}
@@ -275,29 +258,36 @@ ccl_device_inline void triangle_intersect_subsurface(
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
- (*num_hits)++;
+ ss_isect->num_hits++;
int hit;
- if(*num_hits <= max_hits) {
- hit = *num_hits - 1;
+ if(ss_isect->num_hits <= max_hits) {
+ hit = ss_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
- hit = lcg_step_uint(lcg_state) % *num_hits;
+ hit = lcg_step_uint(lcg_state) % ss_isect->num_hits;
if(hit >= max_hits)
return;
}
/* record intersection */
- Intersection *isect = &isect_array[hit];
+ Intersection *isect = &ss_isect->hits[hit];
isect->prim = triAddr;
isect->object = object;
isect->type = PRIMITIVE_TRIANGLE;
isect->u = U * inv_det;
isect->v = V * inv_det;
isect->t = T * inv_det;
+
+ /* Record geometric normal. */
+ /* TODO(sergey): Use float4_to_float3() on just an edges. */
+ const float3 v0 = float4_to_float3(tri_a);
+ const float3 v1 = float4_to_float3(tri_b);
+ const float3 v2 = float4_to_float3(tri_c);
+ ss_isect->Ng[hit] = normalize(cross(v1 - v0, v2 - v0));
}
#endif
@@ -326,11 +316,11 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
if(UNLIKELY(t == 0.0f)) {
return P;
}
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_itfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
-#endif
+# endif
P = transform_point(&tfm, P);
D = transform_direction(&tfm, D*t);
@@ -339,9 +329,9 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
P = P + D*t;
- const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+ const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0),
+ tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1),
+ tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2);
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
@@ -352,11 +342,11 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
P = P + D*rt;
if(isect->object != OBJECT_NONE) {
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_tfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
-#endif
+# endif
P = transform_point(&tfm, P);
}
@@ -379,7 +369,6 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
float3 D = ray->D;
float t = isect->t;
-#ifdef __INTERSECTION_REFINE__
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
Transform tfm = ccl_fetch(sd, ob_itfm);
@@ -396,9 +385,10 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
P = P + D*t;
- const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0),
- tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1),
- tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
+#ifdef __INTERSECTION_REFINE__
+ const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0),
+ tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1),
+ tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2);
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
@@ -407,6 +397,7 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
float rt = dot(edge2, qvec) / dot(edge1, pvec);
P = P + D*rt;
+#endif /* __INTERSECTION_REFINE__ */
if(isect->object != OBJECT_NONE) {
#ifdef __OBJECT_MOTION__
@@ -421,9 +412,6 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
}
return P;
-#else
- return P + D*t;
-#endif
}
#undef IDX
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index c72afa2a3a4..14b6738b23e 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -29,6 +29,21 @@ CCL_NAMESPACE_BEGIN
/* Return position normalized to 0..1 in mesh bounds */
+#ifdef __KERNEL_GPU__
+ccl_device float4 volume_image_texture_3d(int id, float x, float y, float z)
+{
+ float4 r;
+ switch(id) {
+ case 0: r = kernel_tex_image_interp_3d(__tex_image_float3d_000, x, y, z); break;
+ case 1: r = kernel_tex_image_interp_3d(__tex_image_float3d_001, x, y, z); break;
+ case 2: r = kernel_tex_image_interp_3d(__tex_image_float3d_002, x, y, z); break;
+ case 3: r = kernel_tex_image_interp_3d(__tex_image_float3d_003, x, y, z); break;
+ case 4: r = kernel_tex_image_interp_3d(__tex_image_float3d_004, x, y, z); break;
+ }
+ return r;
+}
+#endif /* __KERNEL_GPU__ */
+
ccl_device float3 volume_normalized_position(KernelGlobals *kg, const ShaderData *sd, float3 P)
{
/* todo: optimize this so it's just a single matrix multiplication when
@@ -50,7 +65,7 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
{
float3 P = volume_normalized_position(kg, sd, sd->P);
#ifdef __KERNEL_GPU__
- float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
#else
float4 r;
if(sd->flag & SD_VOLUME_CUBIC)
@@ -70,7 +85,7 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
{
float3 P = volume_normalized_position(kg, sd, sd->P);
#ifdef __KERNEL_GPU__
- float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
#else
float4 r;
if(sd->flag & SD_VOLUME_CUBIC)
diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h
index b2596d10ee7..9279a94c13a 100644
--- a/intern/cycles/kernel/kernel.h
+++ b/intern/cycles/kernel/kernel.h
@@ -23,6 +23,10 @@
CCL_NAMESPACE_BEGIN
+#define KERNEL_NAME_JOIN(x, y, z) x ## _ ## y ## _ ## z
+#define KERNEL_NAME_EVAL(arch, name) KERNEL_NAME_JOIN(kernel, arch, name)
+#define KERNEL_FUNCTION_FULL_NAME(name) KERNEL_NAME_EVAL(KERNEL_ARCH, name)
+
struct KernelGlobals;
KernelGlobals *kernel_globals_create();
@@ -41,69 +45,33 @@ void kernel_tex_copy(KernelGlobals *kg,
InterpolationType interpolation=INTERPOLATION_LINEAR,
ExtensionType extension = EXTENSION_REPEAT);
-void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
- int sample, int x, int y, int offset, int stride);
-void kernel_cpu_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_shader(KernelGlobals *kg, uint4 *input, float4 *output,
- int type, int i, int offset, int sample);
+#define KERNEL_ARCH cpu
+#include "kernels/cpu/kernel_cpu.h"
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
-void kernel_cpu_sse2_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
- int sample, int x, int y, int offset, int stride);
-void kernel_cpu_sse2_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_sse2_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_sse2_shader(KernelGlobals *kg, uint4 *input, float4 *output,
- int type, int i, int offset, int sample);
-#endif
+# define KERNEL_ARCH cpu_sse2
+# include "kernels/cpu/kernel_cpu.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
-void kernel_cpu_sse3_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
- int sample, int x, int y, int offset, int stride);
-void kernel_cpu_sse3_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_sse3_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_sse3_shader(KernelGlobals *kg, uint4 *input, float4 *output,
- int type, int i, int offset, int sample);
-#endif
+# define KERNEL_ARCH cpu_sse3
+# include "kernels/cpu/kernel_cpu.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
-void kernel_cpu_sse41_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
- int sample, int x, int y, int offset, int stride);
-void kernel_cpu_sse41_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_sse41_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_sse41_shader(KernelGlobals *kg, uint4 *input, float4 *output,
- int type, int i, int offset, int sample);
-#endif
+# define KERNEL_ARCH cpu_sse41
+# include "kernels/cpu/kernel_cpu.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 */
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
-void kernel_cpu_avx_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
- int sample, int x, int y, int offset, int stride);
-void kernel_cpu_avx_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_avx_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_avx_shader(KernelGlobals *kg, uint4 *input, float4 *output,
- int type, int i, int offset, int sample);
-#endif
+# define KERNEL_ARCH cpu_avx
+# include "kernels/cpu/kernel_cpu.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
-void kernel_cpu_avx2_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state,
- int sample, int x, int y, int offset, int stride);
-void kernel_cpu_avx2_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_avx2_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer,
- float sample_scale, int x, int y, int offset, int stride);
-void kernel_cpu_avx2_shader(KernelGlobals *kg, uint4 *input, float4 *output,
- int type, int i, int offset, int sample);
-#endif
+# define KERNEL_ARCH cpu_avx2
+# include "kernels/cpu/kernel_cpu.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index 2dc87fffcbc..5f5a3609ded 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -339,6 +339,23 @@ ccl_device_inline void path_radiance_reset_indirect(PathRadiance *L)
#endif
}
+ccl_device_inline void path_radiance_copy_indirect(PathRadiance *L,
+ const PathRadiance *L_src)
+{
+#ifdef __PASSES__
+ if(L->use_light_pass) {
+ L->path_diffuse = L_src->path_diffuse;
+ L->path_glossy = L_src->path_glossy;
+ L->path_transmission = L_src->path_transmission;
+ L->path_subsurface = L_src->path_subsurface;
+ L->path_scatter = L_src->path_scatter;
+
+ L->direct_emission = L_src->direct_emission;
+ L->indirect = L_src->indirect;
+ }
+#endif
+}
+
ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L)
{
float3 L_sum;
@@ -361,6 +378,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
/* Reject invalid value */
if(!isfinite(sum)) {
+ kernel_assert(!"Non-finite sum in path_radiance_clamp_and_sum!");
L_sum = make_float3(0.0f, 0.0f, 0.0f);
L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
@@ -428,8 +446,10 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
/* Reject invalid value */
float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z);
- if(!isfinite(sum))
+ if(!isfinite(sum)) {
+ kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!");
L_sum = make_float3(0.0f, 0.0f, 0.0f);
+ }
return L_sum;
}
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 2b305e5488d..8e7a2c1b62b 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -16,10 +16,10 @@
CCL_NAMESPACE_BEGIN
-#undef USE_BAKE_JITTER
+#ifndef __NO_BAKING__
ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, RNG rng,
- const bool is_combined, const bool is_ao, const bool is_sss, int sample)
+ int pass_filter, int sample)
{
/* initialize master radiance accumulator */
kernel_assert(kernel_data.film.use_light_pass);
@@ -29,7 +29,6 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
PathState state;
Ray ray;
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
- bool is_sss_sample = is_sss;
ray.P = sd->P + sd->Ng;
ray.D = -sd->Ng;
@@ -46,7 +45,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* evaluate surface shader */
float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* TODO, disable the closures we won't need */
@@ -56,27 +55,56 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
#endif
/* sample ambient occlusion */
- if(is_combined || is_ao) {
+ if(pass_filter & BAKE_FILTER_AO) {
kernel_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
}
+ /* sample emission */
+ if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
+ float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
+ path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
+ }
+
+ bool is_sss_sample = false;
+
#ifdef __SUBSURFACE__
/* sample subsurface scattering */
- if((is_combined || is_sss_sample) && (sd->flag & SD_BSSRDF)) {
+ if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) {
/* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */
- if(kernel_path_subsurface_scatter(kg, sd, &L_sample, &state, &rng, &ray, &throughput))
+ SubsurfaceIndirectRays ss_indirect;
+ kernel_path_subsurface_init_indirect(&ss_indirect);
+ if(kernel_path_subsurface_scatter(kg,
+ sd,
+ &L_sample,
+ &state,
+ &rng,
+ &ray,
+ &throughput,
+ &ss_indirect))
+ {
+ while(ss_indirect.num_rays) {
+ kernel_path_subsurface_setup_indirect(kg,
+ &ss_indirect,
+ &state,
+ &ray,
+ &L_sample,
+ &throughput);
+ kernel_path_indirect(kg,
+ &rng,
+ &ray,
+ throughput,
+ state.num_samples,
+ &state,
+ &L_sample);
+ kernel_path_subsurface_accum_indirect(&ss_indirect, &L_sample);
+ }
is_sss_sample = true;
+ }
}
#endif
/* sample light and BSDF */
- if((!is_sss_sample) && (!is_ao)) {
-
- if(sd->flag & SD_EMISSION) {
- float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
- path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
- }
-
+ if(!is_sss_sample && (pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT))) {
kernel_path_surface_connect_light(kg, &rng, sd, throughput, &state, &L_sample);
if(kernel_path_surface_bounce(kg, &rng, sd, &throughput, &state, &L_sample, &ray)) {
@@ -84,7 +112,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
state.ray_t = 0.0f;
#endif
/* compute indirect light */
- kernel_path_indirect(kg, &rng, ray, throughput, 1, state, &L_sample);
+ kernel_path_indirect(kg, &rng, &ray, throughput, 1, &state, &L_sample);
/* sum and reset indirect light pass variables for the next samples */
path_radiance_sum_indirect(&L_sample);
@@ -97,30 +125,30 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian
/* branched path tracer */
/* sample ambient occlusion */
- if(is_combined || is_ao) {
+ if(pass_filter & BAKE_FILTER_AO) {
kernel_branched_path_ao(kg, sd, &L_sample, &state, &rng, throughput);
}
+ /* sample emission */
+ if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
+ float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
+ path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
+ }
+
#ifdef __SUBSURFACE__
/* sample subsurface scattering */
- if((is_combined || is_sss_sample) && (sd->flag & SD_BSSRDF)) {
+ if((pass_filter & BAKE_FILTER_SUBSURFACE) && (sd->flag & SD_BSSRDF)) {
/* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */
kernel_branched_path_subsurface_scatter(kg, sd, &L_sample, &state, &rng, &ray, throughput);
}
#endif
/* sample light and BSDF */
- if((!is_sss_sample) && (!is_ao)) {
-
- if(sd->flag & SD_EMISSION) {
- float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
- path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
- }
-
+ if(pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT)) {
#if defined(__EMISSION__)
/* direct light */
if(kernel_data.integrator.use_direct_light) {
- bool all = kernel_data.integrator.sample_all_lights_direct;
+ int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_surface_connect_light(kg, &rng,
sd, &state, throughput, 1.0f, &L_sample, all);
}
@@ -148,47 +176,91 @@ ccl_device bool is_aa_pass(ShaderEvalType type)
}
}
-ccl_device bool is_light_pass(ShaderEvalType type)
-{
- switch (type) {
- case SHADER_EVAL_AO:
- case SHADER_EVAL_COMBINED:
- case SHADER_EVAL_SHADOW:
- case SHADER_EVAL_DIFFUSE_DIRECT:
- case SHADER_EVAL_GLOSSY_DIRECT:
- case SHADER_EVAL_TRANSMISSION_DIRECT:
- case SHADER_EVAL_SUBSURFACE_DIRECT:
- case SHADER_EVAL_DIFFUSE_INDIRECT:
- case SHADER_EVAL_GLOSSY_INDIRECT:
- case SHADER_EVAL_TRANSMISSION_INDIRECT:
- case SHADER_EVAL_SUBSURFACE_INDIRECT:
- return true;
- default:
- return false;
- }
-}
-
/* this helps with AA but it's not the real solution as it does not AA the geometry
* but it's better than nothing, thus committed */
-ccl_device_inline float bake_clamp_mirror_repeat(float u)
+ccl_device_inline float bake_clamp_mirror_repeat(float u, float max)
{
/* use mirror repeat (like opengl texture) so that if the barycentric
* coordinate goes past the end of the triangle it is not always clamped
* to the same value, gives ugly patterns */
+ u /= max;
float fu = floorf(u);
u = u - fu;
- return (((int)fu) & 1)? 1.0f - u: u;
+ return ((((int)fu) & 1)? 1.0f - u: u) * max;
+}
+
+ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg,
+ ShaderData *sd,
+ const ShaderEvalType type)
+{
+ switch(type) {
+ case SHADER_EVAL_DIFFUSE:
+ return shader_bsdf_diffuse(kg, sd);
+ case SHADER_EVAL_GLOSSY:
+ return shader_bsdf_glossy(kg, sd);
+ case SHADER_EVAL_TRANSMISSION:
+ return shader_bsdf_transmission(kg, sd);
+#ifdef __SUBSURFACE__
+ case SHADER_EVAL_SUBSURFACE:
+ return shader_bsdf_subsurface(kg, sd);
+#endif
+ default:
+ kernel_assert(!"Unknown bake type passed to BSDF evaluate");
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ float3 direct,
+ float3 indirect,
+ const ShaderEvalType type,
+ const int pass_filter)
+{
+ float3 color;
+ const bool is_color = (pass_filter & BAKE_FILTER_COLOR) != 0;
+ const bool is_direct = (pass_filter & BAKE_FILTER_DIRECT) != 0;
+ const bool is_indirect = (pass_filter & BAKE_FILTER_INDIRECT) != 0;
+ float3 out = make_float3(0.0f, 0.0f, 0.0f);
+
+ if(is_color) {
+ if(is_direct || is_indirect) {
+ /* Leave direct and diffuse channel colored. */
+ color = make_float3(1.0f, 1.0f, 1.0f);
+ }
+ else {
+ /* surface color of the pass only */
+ shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
+ return kernel_bake_shader_bsdf(kg, sd, type);
+ }
+ }
+ else {
+ shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN);
+ color = kernel_bake_shader_bsdf(kg, sd, type);
+ }
+
+ if(is_direct) {
+ out += safe_divide_color(direct, color);
+ }
+
+ if(is_indirect) {
+ out += safe_divide_color(indirect, color);
+ }
+
+ return out;
}
ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, ccl_global float4 *output,
- ShaderEvalType type, int i, int offset, int sample)
+ ShaderEvalType type, int pass_filter, int i, int offset, int sample)
{
ShaderData sd;
+ PathState state = {0};
uint4 in = input[i * 2];
uint4 diff = input[i * 2 + 1];
- float3 out;
+ float3 out = make_float3(0.0f, 0.0f, 0.0f);
int object = in.x;
int prim = in.y;
@@ -209,7 +281,6 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
/* random number generator */
RNG rng = cmj_hash(offset + i, kernel_data.integrator.seed);
-#ifdef USE_BAKE_JITTER
float filter_x, filter_y;
if(sample == 0) {
filter_x = filter_y = 0.5f;
@@ -220,10 +291,9 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
/* subpixel u/v offset */
if(sample > 0) {
- u = bake_clamp_mirror_repeat(u + dudx*(filter_x - 0.5f) + dudy*(filter_y - 0.5f));
- v = bake_clamp_mirror_repeat(v + dvdx*(filter_x - 0.5f) + dvdy*(filter_y - 0.5f));
+ u = bake_clamp_mirror_repeat(u + dudx*(filter_x - 0.5f) + dudy*(filter_y - 0.5f), 1.0f);
+ v = bake_clamp_mirror_repeat(v + dvdx*(filter_x - 0.5f) + dvdy*(filter_y - 0.5f), 1.0f - u);
}
-#endif
/* triangle */
int shader;
@@ -235,13 +305,11 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
float3 I = Ng;
float t = 0.0f;
float time = TIME_INVALID;
- int bounce = 0;
- int transparent_bounce = 0;
/* light passes */
PathRadiance L;
- shader_setup_from_sample(kg, &sd, P, Ng, I, shader, object, prim, u, v, t, time, bounce, transparent_bounce);
+ shader_setup_from_sample(kg, &sd, P, Ng, I, shader, object, prim, u, v, t, time);
sd.I = sd.N;
/* update differentials */
@@ -252,22 +320,16 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
sd.dv.dx = dvdx;
sd.dv.dy = dvdy;
- /* light passes */
- if(is_light_pass(type)) {
- compute_light_pass(kg, &sd, &L, rng,
- (type == SHADER_EVAL_COMBINED),
- (type == SHADER_EVAL_AO),
- (type == SHADER_EVAL_SUBSURFACE_DIRECT ||
- type == SHADER_EVAL_SUBSURFACE_INDIRECT),
- sample);
- }
+ /* light passes if we need more than color */
+ if(pass_filter & ~BAKE_FILTER_COLOR)
+ compute_light_pass(kg, &sd, &L, rng, pass_filter, sample);
- switch (type) {
+ switch(type) {
/* data passes */
case SHADER_EVAL_NORMAL:
{
if((sd.flag & SD_HAS_BUMP)) {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN);
}
/* compression: normal = (2 * color) - 1 */
@@ -279,35 +341,9 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
out = primitive_uv(kg, &sd);
break;
}
- case SHADER_EVAL_DIFFUSE_COLOR:
- {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = shader_bsdf_diffuse(kg, &sd);
- break;
- }
- case SHADER_EVAL_GLOSSY_COLOR:
- {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = shader_bsdf_glossy(kg, &sd);
- break;
- }
- case SHADER_EVAL_TRANSMISSION_COLOR:
- {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = shader_bsdf_transmission(kg, &sd);
- break;
- }
- case SHADER_EVAL_SUBSURFACE_COLOR:
- {
-#ifdef __SUBSURFACE__
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = shader_bsdf_subsurface(kg, &sd);
-#endif
- break;
- }
case SHADER_EVAL_EMISSION:
{
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_EMISSION);
+ shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION);
out = shader_emissive_eval(kg, &sd);
break;
}
@@ -321,7 +357,34 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
}
case SHADER_EVAL_COMBINED:
{
- out = path_radiance_clamp_and_sum(kg, &L);
+ if((pass_filter & BAKE_FILTER_COMBINED) == BAKE_FILTER_COMBINED) {
+ out = path_radiance_clamp_and_sum(kg, &L);
+ break;
+ }
+
+ if((pass_filter & BAKE_FILTER_DIFFUSE_DIRECT) == BAKE_FILTER_DIFFUSE_DIRECT)
+ out += L.direct_diffuse;
+ if((pass_filter & BAKE_FILTER_DIFFUSE_INDIRECT) == BAKE_FILTER_DIFFUSE_INDIRECT)
+ out += L.indirect_diffuse;
+
+ if((pass_filter & BAKE_FILTER_GLOSSY_DIRECT) == BAKE_FILTER_GLOSSY_DIRECT)
+ out += L.direct_glossy;
+ if((pass_filter & BAKE_FILTER_GLOSSY_INDIRECT) == BAKE_FILTER_GLOSSY_INDIRECT)
+ out += L.indirect_glossy;
+
+ if((pass_filter & BAKE_FILTER_TRANSMISSION_DIRECT) == BAKE_FILTER_TRANSMISSION_DIRECT)
+ out += L.direct_transmission;
+ if((pass_filter & BAKE_FILTER_TRANSMISSION_INDIRECT) == BAKE_FILTER_TRANSMISSION_INDIRECT)
+ out += L.indirect_transmission;
+
+ if((pass_filter & BAKE_FILTER_SUBSURFACE_DIRECT) == BAKE_FILTER_SUBSURFACE_DIRECT)
+ out += L.direct_subsurface;
+ if((pass_filter & BAKE_FILTER_SUBSURFACE_INDIRECT) == BAKE_FILTER_SUBSURFACE_INDIRECT)
+ out += L.indirect_subsurface;
+
+ if((pass_filter & BAKE_FILTER_EMISSION) != 0)
+ out += L.emission;
+
break;
}
case SHADER_EVAL_SHADOW:
@@ -329,55 +392,49 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
out = make_float3(L.shadow.x, L.shadow.y, L.shadow.z);
break;
}
- case SHADER_EVAL_DIFFUSE_DIRECT:
+ case SHADER_EVAL_DIFFUSE:
{
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.direct_diffuse, shader_bsdf_diffuse(kg, &sd));
+ out = kernel_bake_evaluate_direct_indirect(kg,
+ &sd,
+ &state,
+ L.direct_diffuse,
+ L.indirect_diffuse,
+ type,
+ pass_filter);
break;
}
- case SHADER_EVAL_GLOSSY_DIRECT:
+ case SHADER_EVAL_GLOSSY:
{
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.direct_glossy, shader_bsdf_glossy(kg, &sd));
+ out = kernel_bake_evaluate_direct_indirect(kg,
+ &sd,
+ &state,
+ L.direct_glossy,
+ L.indirect_glossy,
+ type,
+ pass_filter);
break;
}
- case SHADER_EVAL_TRANSMISSION_DIRECT:
+ case SHADER_EVAL_TRANSMISSION:
{
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.direct_transmission, shader_bsdf_transmission(kg, &sd));
+ out = kernel_bake_evaluate_direct_indirect(kg,
+ &sd,
+ &state,
+ L.direct_transmission,
+ L.indirect_transmission,
+ type,
+ pass_filter);
break;
}
- case SHADER_EVAL_SUBSURFACE_DIRECT:
+ case SHADER_EVAL_SUBSURFACE:
{
#ifdef __SUBSURFACE__
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.direct_subsurface, shader_bsdf_subsurface(kg, &sd));
-#endif
- break;
- }
- case SHADER_EVAL_DIFFUSE_INDIRECT:
- {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.indirect_diffuse, shader_bsdf_diffuse(kg, &sd));
- break;
- }
- case SHADER_EVAL_GLOSSY_INDIRECT:
- {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.indirect_glossy, shader_bsdf_glossy(kg, &sd));
- break;
- }
- case SHADER_EVAL_TRANSMISSION_INDIRECT:
- {
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.indirect_transmission, shader_bsdf_transmission(kg, &sd));
- break;
- }
- case SHADER_EVAL_SUBSURFACE_INDIRECT:
- {
-#ifdef __SUBSURFACE__
- shader_eval_surface(kg, &sd, 0.f, 0, SHADER_CONTEXT_MAIN);
- out = safe_divide_color(L.indirect_subsurface, shader_bsdf_subsurface(kg, &sd));
+ out = kernel_bake_evaluate_direct_indirect(kg,
+ &sd,
+ &state,
+ L.direct_subsurface,
+ L.indirect_subsurface,
+ type,
+ pass_filter);
#endif
break;
}
@@ -402,11 +459,11 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
#endif
/* setup shader data */
- shader_setup_from_background(kg, &sd, &ray, 0, 0);
+ shader_setup_from_background(kg, &sd, &ray);
/* evaluate */
int flag = 0; /* we can't know which type of BSDF this is for */
- out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN);
+ out = shader_eval_background(kg, &sd, &state, flag, SHADER_CONTEXT_MAIN);
break;
}
default:
@@ -426,9 +483,18 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
output[i] += make_float4(out.x, out.y, out.z, 1.0f) * output_fac;
}
-ccl_device void kernel_shader_evaluate(KernelGlobals *kg, ccl_global uint4 *input, ccl_global float4 *output, ShaderEvalType type, int i, int sample)
+#endif /* __NO_BAKING__ */
+
+ccl_device void kernel_shader_evaluate(KernelGlobals *kg,
+ ccl_global uint4 *input,
+ ccl_global float4 *output,
+ ccl_global float *output_luma,
+ ShaderEvalType type,
+ int i,
+ int sample)
{
ShaderData sd;
+ PathState state = {0};
uint4 in = input[i];
float3 out;
@@ -443,7 +509,7 @@ ccl_device void kernel_shader_evaluate(KernelGlobals *kg, ccl_global uint4 *inpu
/* evaluate */
float3 P = sd.P;
- shader_eval_displacement(kg, &sd, SHADER_CONTEXT_MAIN);
+ shader_eval_displacement(kg, &sd, &state, SHADER_CONTEXT_MAIN);
out = sd.P - P;
}
else { // SHADER_EVAL_BACKGROUND
@@ -465,18 +531,30 @@ ccl_device void kernel_shader_evaluate(KernelGlobals *kg, ccl_global uint4 *inpu
#endif
/* setup shader data */
- shader_setup_from_background(kg, &sd, &ray, 0, 0);
+ shader_setup_from_background(kg, &sd, &ray);
/* evaluate */
int flag = 0; /* we can't know which type of BSDF this is for */
- out = shader_eval_background(kg, &sd, flag, SHADER_CONTEXT_MAIN);
+ out = shader_eval_background(kg, &sd, &state, flag, SHADER_CONTEXT_MAIN);
}
/* write output */
- if(sample == 0)
- output[i] = make_float4(out.x, out.y, out.z, 0.0f);
- else
- output[i] += make_float4(out.x, out.y, out.z, 0.0f);
+ if(sample == 0) {
+ if(output != NULL) {
+ output[i] = make_float4(out.x, out.y, out.z, 0.0f);
+ }
+ if(output_luma != NULL) {
+ output_luma[i] = average(out);
+ }
+ }
+ else {
+ if(output != NULL) {
+ output[i] += make_float4(out.x, out.y, out.z, 0.0f);
+ }
+ if(output_luma != NULL) {
+ output_luma[i] += average(out);
+ }
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
index 8d439ceb0d7..f6c103d59dd 100644
--- a/intern/cycles/kernel/kernel_camera.h
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -92,31 +92,45 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
-#ifdef __KERNEL_OPENCL__
+# ifdef __KERNEL_OPENCL__
const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
((const DecompMotionTransform*)&tfm),
ray->time);
-#else
+# else
transform_motion_interpolate(&cameratoworld,
((const DecompMotionTransform*)&kernel_data.cam.motion),
ray->time);
-#endif
+# endif
}
#endif
- ray->P = transform_point(&cameratoworld, ray->P);
- ray->D = transform_direction(&cameratoworld, ray->D);
- ray->D = normalize(ray->D);
+ float3 tP = transform_point(&cameratoworld, ray->P);
+ float3 tD = transform_direction(&cameratoworld, ray->D);
+ ray->P = spherical_stereo_position(kg, tD, tP);
+ ray->D = spherical_stereo_direction(kg, tD, tP, ray->P);
#ifdef __RAY_DIFFERENTIALS__
/* ray differential */
- float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
-
ray->dP = differential3_zero();
- ray->dD.dx = normalize(Ddiff + float4_to_float3(kernel_data.cam.dx)) - normalize(Ddiff);
- ray->dD.dy = normalize(Ddiff + float4_to_float3(kernel_data.cam.dy)) - normalize(Ddiff);
+ float3 tD_diff = transform_direction(&cameratoworld, Pcamera);
+ float3 Pdiff = spherical_stereo_position(kg, tD_diff, Pcamera);
+ float3 Ddiff = spherical_stereo_direction(kg, tD_diff, Pcamera, Pdiff);
+
+ tP = transform_perspective(&rastertocamera,
+ make_float3(raster_x + 1.0f, raster_y, 0.0f));
+ tD = tD_diff + float4_to_float3(kernel_data.cam.dx);
+ Pcamera = spherical_stereo_position(kg, tD, tP);
+ ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
+ ray->dP.dx = Pcamera - Pdiff;
+
+ tP = transform_perspective(&rastertocamera,
+ make_float3(raster_x, raster_y + 1.0f, 0.0f));
+ tD = tD_diff + float4_to_float3(kernel_data.cam.dy);
+ Pcamera = spherical_stereo_position(kg, tD, tP);
+ ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
+ /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */
#endif
#ifdef __CAMERA_CLIPPING__
@@ -162,16 +176,16 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
-#ifdef __KERNEL_OPENCL__
+# ifdef __KERNEL_OPENCL__
const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
(const DecompMotionTransform*)&tfm,
ray->time);
-#else
+# else
transform_motion_interpolate(&cameratoworld,
(const DecompMotionTransform*)&kernel_data.cam.motion,
ray->time);
-#endif
+# endif
}
#endif
@@ -246,35 +260,44 @@ ccl_device void camera_sample_panorama(KernelGlobals *kg, float raster_x, float
#ifdef __CAMERA_MOTION__
if(kernel_data.cam.have_motion) {
-#ifdef __KERNEL_OPENCL__
+# ifdef __KERNEL_OPENCL__
const MotionTransform tfm = kernel_data.cam.motion;
transform_motion_interpolate(&cameratoworld,
(const DecompMotionTransform*)&tfm,
ray->time);
-#else
+# else
transform_motion_interpolate(&cameratoworld,
(const DecompMotionTransform*)&kernel_data.cam.motion,
ray->time);
-#endif
+# endif
}
#endif
- ray->P = transform_point(&cameratoworld, ray->P);
- ray->D = transform_direction(&cameratoworld, ray->D);
- ray->D = normalize(ray->D);
+ float3 tP = transform_point(&cameratoworld, ray->P);
+ float3 tD = transform_direction(&cameratoworld, ray->D);
+ ray->P = spherical_stereo_position(kg, tD, tP);
+ ray->D = spherical_stereo_direction(kg, tD, tP, ray->P);
#ifdef __RAY_DIFFERENTIALS__
/* ray differential */
ray->dP = differential3_zero();
- Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
- float3 Ddiff = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y)));
-
- Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
- ray->dD.dx = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y))) - Ddiff;
-
- Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
- ray->dD.dy = normalize(transform_direction(&cameratoworld, panorama_to_direction(kg, Pcamera.x, Pcamera.y))) - Ddiff;
+ tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+ tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
+ float3 Pdiff = spherical_stereo_position(kg, tD, tP);
+ float3 Ddiff = spherical_stereo_direction(kg, tD, tP, Pdiff);
+
+ tP = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f));
+ tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
+ Pcamera = spherical_stereo_position(kg, tD, tP);
+ ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
+ ray->dP.dx = Pcamera - Pdiff;
+
+ tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f));
+ tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y));
+ Pcamera = spherical_stereo_position(kg, tD, tP);
+ ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff;
+ /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */
#endif
}
@@ -290,10 +313,42 @@ ccl_device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, f
#ifdef __CAMERA_MOTION__
/* motion blur */
- if(kernel_data.cam.shuttertime == -1.0f)
+ if(kernel_data.cam.shuttertime == -1.0f) {
ray->time = TIME_INVALID;
- else
- ray->time = time;
+ }
+ else {
+ /* TODO(sergey): Such lookup is unneeded when there's rolling shutter
+ * effect in use but rolling shutter duration is set to 0.0.
+ */
+ const int shutter_table_offset = kernel_data.cam.shutter_table_offset;
+ ray->time = lookup_table_read(kg, time, shutter_table_offset, SHUTTER_TABLE_SIZE);
+ /* TODO(sergey): Currently single rolling shutter effect type only
+ * where scanlines are acquired from top to bottom and whole scanline
+ * is acquired at once (no delay in acquisition happens between pixels
+ * of single scanline).
+ *
+ * Might want to support more models in the future.
+ */
+ if(kernel_data.cam.rolling_shutter_type) {
+ /* Time corresponding to a fully rolling shutter only effect:
+ * top of the frame is time 0.0, bottom of the frame is time 1.0.
+ */
+ const float time = 1.0f - (float)y / kernel_data.cam.height;
+ const float duration = kernel_data.cam.rolling_shutter_duration;
+ if(duration != 0.0f) {
+ /* This isn't fully physical correct, but lets us to have simple
+ * controls in the interface. The idea here is basically sort of
+ * linear interpolation between how much rolling shutter effect
+ * exist on the frame and how much of it is a motion blur effect.
+ */
+ ray->time = (ray->time - 0.5f) * duration;
+ ray->time += (time - 0.5f) * (1.0f - duration) + 0.5f;
+ }
+ else {
+ ray->time = time;
+ }
+ }
+ }
#endif
/* sample */
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index ed145b4a967..b96a84499b4 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -22,7 +22,7 @@
/* Release kernel has too much false-positive maybe-uninitialized warnings,
* which makes it possible to miss actual warnings.
*/
-#if defined(__GNUC__) && defined(NDEBUG)
+#if (defined(__GNUC__) && !defined(__clang__)) && defined(NDEBUG)
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
# pragma GCC diagnostic ignored "-Wuninitialized"
#endif
@@ -144,7 +144,7 @@ template<typename T> struct texture_image {
iy = wrap_periodic(iy, height);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
/* Fall through. */
@@ -152,6 +152,9 @@ template<typename T> struct texture_image {
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
return read(data[ix + iy*width]);
}
@@ -168,7 +171,7 @@ template<typename T> struct texture_image {
niy = wrap_periodic(iy+1, height);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
/* Fall through. */
@@ -179,6 +182,9 @@ template<typename T> struct texture_image {
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
@@ -208,7 +214,7 @@ template<typename T> struct texture_image {
nniy = wrap_periodic(iy+2, height);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
/* Fall through. */
@@ -225,6 +231,9 @@ template<typename T> struct texture_image {
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
const int xc[4] = {pix, ix, nix, nnix};
@@ -279,7 +288,9 @@ template<typename T> struct texture_image {
iz = wrap_periodic(iz, depth);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ if(x < 0.0f || y < 0.0f || z < 0.0f ||
+ x > 1.0f || y > 1.0f || z > 1.0f)
+ {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
/* Fall through. */
@@ -288,6 +299,9 @@ template<typename T> struct texture_image {
iy = wrap_clamp(iy, height);
iz = wrap_clamp(iz, depth);
break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
return read(data[ix + iy*width + iz*width*height]);
@@ -308,7 +322,9 @@ template<typename T> struct texture_image {
niz = wrap_periodic(iz+1, depth);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ if(x < 0.0f || y < 0.0f || z < 0.0f ||
+ x > 1.0f || y > 1.0f || z > 1.0f)
+ {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
/* Fall through. */
@@ -321,6 +337,9 @@ template<typename T> struct texture_image {
iy = wrap_clamp(iy, height);
iz = wrap_clamp(iz, depth);
break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
float4 r;
@@ -363,7 +382,9 @@ template<typename T> struct texture_image {
nniz = wrap_periodic(iz+2, depth);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ if(x < 0.0f || y < 0.0f || z < 0.0f ||
+ x > 1.0f || y > 1.0f || z > 1.0f)
+ {
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
/* Fall through. */
@@ -384,6 +405,9 @@ template<typename T> struct texture_image {
iy = wrap_clamp(iy, height);
iz = wrap_clamp(iz, depth);
break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
const int xc[4] = {pix, ix, nix, nnix};
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
index 9fdd3abfec3..d10d3255e1b 100644
--- a/intern/cycles/kernel/kernel_compat_cuda.h
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -62,6 +62,7 @@ typedef texture<int, 1> texture_int;
typedef texture<uint4, 1> texture_uint4;
typedef texture<uchar4, 1> texture_uchar4;
typedef texture<float4, 2> texture_image_float4;
+typedef texture<float4, 3> texture_image3d_float4;
typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
/* Macros to handle different memory storage on different devices */
@@ -70,15 +71,16 @@ typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
* of textures. On earlier cards this seems slower, but on Titan it is
* actually slightly faster in tests. */
#if __CUDA_ARCH__ < 300
-#define __KERNEL_CUDA_TEX_STORAGE__
+# define __KERNEL_CUDA_TEX_STORAGE__
#endif
#ifdef __KERNEL_CUDA_TEX_STORAGE__
-#define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
+# define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
#else
-#define kernel_tex_fetch(t, index) t[(index)]
+# define kernel_tex_fetch(t, index) t[(index)]
#endif
#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
+#define kernel_tex_image_interp_3d(t, x, y, z) tex3D(t, x, y, z)
#define kernel_data __data
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
index e8b36d2605d..a5708448e23 100644
--- a/intern/cycles/kernel/kernel_compat_opencl.h
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -25,9 +25,9 @@
#define CCL_NAMESPACE_END
#ifdef __CL_NOINLINE__
-#define ccl_noinline __attribute__((noinline))
+# define ccl_noinline __attribute__((noinline))
#else
-#define ccl_noinline
+# define ccl_noinline
#endif
/* in opencl all functions are device functions, so leave this empty */
@@ -41,9 +41,9 @@
#define ccl_private __private
#ifdef __SPLIT_KERNEL__
-#define ccl_addr_space __global
+# define ccl_addr_space __global
#else
-#define ccl_addr_space
+# define ccl_addr_space
#endif
/* Selective nodes compilation. */
@@ -59,25 +59,25 @@
/* make_type definitions with opencl style element initializers */
#ifdef make_float2
-#undef make_float2
+# undef make_float2
#endif
#ifdef make_float3
-#undef make_float3
+# undef make_float3
#endif
#ifdef make_float4
-#undef make_float4
+# undef make_float4
#endif
#ifdef make_int2
-#undef make_int2
+# undef make_int2
#endif
#ifdef make_int3
-#undef make_int3
+# undef make_int3
#endif
#ifdef make_int4
-#undef make_int4
+# undef make_int4
#endif
#ifdef make_uchar4
-#undef make_uchar4
+# undef make_uchar4
#endif
#define make_float2(x, y) ((float2)(x, y))
@@ -108,19 +108,19 @@
#define fmodf(x, y) fmod((float)(x), (float)(y))
#ifndef __CL_USE_NATIVE__
-#define sinf(x) native_sin(((float)(x)))
-#define cosf(x) native_cos(((float)(x)))
-#define tanf(x) native_tan(((float)(x)))
-#define expf(x) native_exp(((float)(x)))
-#define sqrtf(x) native_sqrt(((float)(x)))
-#define logf(x) native_log(((float)(x)))
+# define sinf(x) native_sin(((float)(x)))
+# define cosf(x) native_cos(((float)(x)))
+# define tanf(x) native_tan(((float)(x)))
+# define expf(x) native_exp(((float)(x)))
+# define sqrtf(x) native_sqrt(((float)(x)))
+# define logf(x) native_log(((float)(x)))
#else
-#define sinf(x) sin(((float)(x)))
-#define cosf(x) cos(((float)(x)))
-#define tanf(x) tan(((float)(x)))
-#define expf(x) exp(((float)(x)))
-#define sqrtf(x) sqrt(((float)(x)))
-#define logf(x) log(((float)(x)))
+# define sinf(x) sin(((float)(x)))
+# define cosf(x) cos(((float)(x)))
+# define tanf(x) tan(((float)(x)))
+# define expf(x) exp(((float)(x)))
+# define sqrtf(x) sqrt(((float)(x)))
+# define logf(x) log(((float)(x)))
#endif
/* data lookup defines */
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index de9e8d77ec8..5cf52f9d176 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -18,15 +18,16 @@ CCL_NAMESPACE_BEGIN
/* Direction Emission */
ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
- LightSample *ls, float3 I, differential3 dI, float t, float time, int bounce, int transparent_bounce
-#ifdef __SPLIT_KERNEL__
- ,ShaderData *sd_input
-#endif
-)
+ LightSample *ls,
+ ccl_addr_space PathState *state,
+ float3 I,
+ differential3 dI,
+ float t,
+ float time)
{
/* setup shading at emitter */
#ifdef __SPLIT_KERNEL__
- ShaderData *sd = sd_input;
+ ShaderData *sd = kg->sd_input;
#else
ShaderData sd_object;
ShaderData *sd = &sd_object;
@@ -39,25 +40,30 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
ray.D = ls->D;
ray.P = ls->P;
ray.t = 1.0f;
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
ray.time = time;
-#endif
+# endif
ray.dP = differential3_zero();
ray.dD = dI;
- shader_setup_from_background(kg, sd, &ray, bounce+1, transparent_bounce);
- eval = shader_eval_background(kg, sd, 0, SHADER_CONTEXT_EMISSION);
+ shader_setup_from_background(kg, sd, &ray);
+
+ path_state_modify_bounce(state, true);
+ eval = shader_eval_background(kg, sd, state, 0, SHADER_CONTEXT_EMISSION);
+ path_state_modify_bounce(state, false);
}
else
#endif
{
- shader_setup_from_sample(kg, sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time, bounce+1, transparent_bounce);
+ shader_setup_from_sample(kg, sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, ls->u, ls->v, t, time);
ls->Ng = ccl_fetch(sd, Ng);
/* no path flag, we're evaluating this for all closures. that's weak but
* we'd have to do multiple evaluations otherwise */
- shader_eval_surface(kg, sd, 0.0f, 0, SHADER_CONTEXT_EMISSION);
+ path_state_modify_bounce(state, true);
+ shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION);
+ path_state_modify_bounce(state, false);
/* evaluate emissive closure */
if(ccl_fetch(sd, flag) & SD_EMISSION)
@@ -71,13 +77,13 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
return eval;
}
-ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
- LightSample *ls, Ray *ray, BsdfEval *eval, bool *is_lamp,
- int bounce, int transparent_bounce
-#ifdef __SPLIT_KERNEL__
- , ShaderData *sd_DL
-#endif
- )
+ccl_device_noinline bool direct_emission(KernelGlobals *kg,
+ ShaderData *sd,
+ LightSample *ls,
+ ccl_addr_space PathState *state,
+ Ray *ray,
+ BsdfEval *eval,
+ bool *is_lamp)
{
if(ls->pdf == 0.0f)
return false;
@@ -87,35 +93,35 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd,
/* evaluate closure */
- float3 light_eval = direct_emissive_eval(kg, ls, -ls->D, dD, ls->t, ccl_fetch(sd, time),
- bounce,
- transparent_bounce
-#ifdef __SPLIT_KERNEL__
- ,sd_DL
-#endif
- );
+ float3 light_eval = direct_emissive_eval(kg,
+ ls,
+ state,
+ -ls->D,
+ dD,
+ ls->t,
+ ccl_fetch(sd, time));
if(is_zero(light_eval))
return false;
/* evaluate BSDF at shading point */
- float bsdf_pdf;
#ifdef __VOLUME__
if(ccl_fetch(sd, prim) != PRIM_NONE)
- shader_bsdf_eval(kg, sd, ls->D, eval, &bsdf_pdf);
- else
+ shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS);
+ else {
+ float bsdf_pdf;
shader_volume_phase_eval(kg, sd, ls->D, eval, &bsdf_pdf);
+ if(ls->shader & SHADER_USE_MIS) {
+ /* Multiple importance sampling. */
+ float mis_weight = power_heuristic(ls->pdf, bsdf_pdf);
+ light_eval *= mis_weight;
+ }
+ }
#else
- shader_bsdf_eval(kg, sd, ls->D, eval, &bsdf_pdf);
+ shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS);
#endif
- if(ls->shader & SHADER_USE_MIS) {
- /* multiple importance sampling */
- float mis_weight = power_heuristic(ls->pdf, bsdf_pdf);
- light_eval *= mis_weight;
- }
-
bsdf_eval_mul(eval, light_eval/ls->pdf);
#ifdef __PASSES__
@@ -191,11 +197,10 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader
/* Indirect Lamp Emission */
-ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *state, Ray *ray, float3 *emission
-#ifdef __SPLIT_KERNEL__
- ,ShaderData *sd
-#endif
- )
+ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
+ ccl_addr_space PathState *state,
+ Ray *ray,
+ float3 *emission)
{
bool hit_lamp = false;
@@ -219,13 +224,13 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *st
}
#endif
- float3 L = direct_emissive_eval(kg, &ls, -ray->D, ray->dD, ls.t, ray->time,
- state->bounce,
- state->transparent_bounce
-#ifdef __SPLIT_KERNEL__
- ,sd
-#endif
- );
+ float3 L = direct_emissive_eval(kg,
+ &ls,
+ state,
+ -ray->D,
+ ray->dD,
+ ls.t,
+ ray->time);
#ifdef __VOLUME__
if(state->volume_stack[0].shader != SHADER_NONE) {
@@ -254,11 +259,9 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg, PathState *st
/* Indirect Background */
-ccl_device_noinline float3 indirect_background(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space Ray *ray
-#ifdef __SPLIT_KERNEL__
- ,ShaderData *sd_global
-#endif
- )
+ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
+ ccl_addr_space PathState *state,
+ ccl_addr_space Ray *ray)
{
#ifdef __BACKGROUND__
int shader = kernel_data.background.surface_shader;
@@ -274,17 +277,22 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg, ccl_addr_space
return make_float3(0.0f, 0.0f, 0.0f);
}
-#ifdef __SPLIT_KERNEL__
/* evaluate background closure */
+# ifdef __SPLIT_KERNEL__
Ray priv_ray = *ray;
- shader_setup_from_background(kg, sd_global, &priv_ray, state->bounce+1, state->transparent_bounce);
- float3 L = shader_eval_background(kg, sd_global, state->flag, SHADER_CONTEXT_EMISSION);
-#else
+ shader_setup_from_background(kg, kg->sd_input, &priv_ray);
+
+ path_state_modify_bounce(state, true);
+ float3 L = shader_eval_background(kg, kg->sd_input, state, state->flag, SHADER_CONTEXT_EMISSION);
+ path_state_modify_bounce(state, false);
+# else
ShaderData sd;
- shader_setup_from_background(kg, &sd, ray, state->bounce+1, state->transparent_bounce);
+ shader_setup_from_background(kg, &sd, ray);
- float3 L = shader_eval_background(kg, &sd, state->flag, SHADER_CONTEXT_EMISSION);
-#endif
+ path_state_modify_bounce(state, true);
+ float3 L = shader_eval_background(kg, &sd, state, state->flag, SHADER_CONTEXT_EMISSION);
+ path_state_modify_bounce(state, false);
+# endif
#ifdef __BACKGROUND_MIS__
/* check if background light exists or if we should skip pdf */
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
index 17fa18909c4..52e718f8efd 100644
--- a/intern/cycles/kernel/kernel_globals.h
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -25,36 +25,36 @@ CCL_NAMESPACE_BEGIN
#ifdef __KERNEL_CPU__
-#ifdef __OSL__
+# ifdef __OSL__
struct OSLGlobals;
struct OSLThreadData;
struct OSLShadingSystem;
-#endif
+# endif
-#define MAX_BYTE_IMAGES 1024
-#define MAX_FLOAT_IMAGES 1024
+# define MAX_BYTE_IMAGES 1024
+# define MAX_FLOAT_IMAGES 1024
typedef struct KernelGlobals {
texture_image_uchar4 texture_byte_images[MAX_BYTE_IMAGES];
texture_image_float4 texture_float_images[MAX_FLOAT_IMAGES];
-#define KERNEL_TEX(type, ttype, name) ttype name;
-#define KERNEL_IMAGE_TEX(type, ttype, name)
-#include "kernel_textures.h"
+# define KERNEL_TEX(type, ttype, name) ttype name;
+# define KERNEL_IMAGE_TEX(type, ttype, name)
+# include "kernel_textures.h"
KernelData __data;
-#ifdef __OSL__
+# ifdef __OSL__
/* On the CPU, we also have the OSL globals here. Most data structures are shared
* with SVM, the difference is in the shaders and object/mesh attributes. */
OSLGlobals *osl;
OSLShadingSystem *osl_ss;
OSLThreadData *osl_tdata;
-#endif
+# endif
} KernelGlobals;
-#endif
+#endif /* __KERNEL_CPU__ */
/* For CUDA, constant memory textures must be globals, so we can't put them
* into a struct. As a result we don't actually use this struct and use actual
@@ -66,15 +66,15 @@ typedef struct KernelGlobals {
__constant__ KernelData __data;
typedef struct KernelGlobals {} KernelGlobals;
-#ifdef __KERNEL_CUDA_TEX_STORAGE__
-#define KERNEL_TEX(type, ttype, name) ttype name;
-#else
-#define KERNEL_TEX(type, ttype, name) const __constant__ __device__ type *name;
-#endif
-#define KERNEL_IMAGE_TEX(type, ttype, name) ttype name;
-#include "kernel_textures.h"
+# ifdef __KERNEL_CUDA_TEX_STORAGE__
+# define KERNEL_TEX(type, ttype, name) ttype name;
+# else
+# define KERNEL_TEX(type, ttype, name) const __constant__ __device__ type *name;
+# endif
+# define KERNEL_IMAGE_TEX(type, ttype, name) ttype name;
+# include "kernel_textures.h"
-#endif
+#endif /* __KERNEL_CUDA__ */
/* OpenCL */
@@ -83,12 +83,17 @@ typedef struct KernelGlobals {} KernelGlobals;
typedef ccl_addr_space struct KernelGlobals {
ccl_constant KernelData *data;
-#define KERNEL_TEX(type, ttype, name) \
+# define KERNEL_TEX(type, ttype, name) \
ccl_global type *name;
-#include "kernel_textures.h"
+# include "kernel_textures.h"
+
+# ifdef __SPLIT_KERNEL__
+ ShaderData *sd_input;
+ Intersection *isect_shadow;
+# endif
} KernelGlobals;
-#endif
+#endif /* __KERNEL_OPENCL__ */
/* Interpolated lookup table access */
diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h
index 9ba41635b9e..a98881b5af3 100644
--- a/intern/cycles/kernel/kernel_jitter.h
+++ b/intern/cycles/kernel/kernel_jitter.h
@@ -26,7 +26,7 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline bool cmj_is_pow2(int i)
{
- return (i & (i - 1)) == 0;
+ return (i > 1) && ((i & (i - 1)) == 0);
}
ccl_device_inline int cmj_fast_mod_pow2(int a, int b)
@@ -34,10 +34,9 @@ ccl_device_inline int cmj_fast_mod_pow2(int a, int b)
return (a & (b - 1));
}
-/* a must be > 0 and b must be > 1 */
+/* b must be > 1 */
ccl_device_inline int cmj_fast_div_pow2(int a, int b)
{
- kernel_assert(a > 0);
kernel_assert(b > 1);
#if defined(__KERNEL_SSE2__)
# ifdef _MSC_VER
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 7590ec2d706..675eacfc5ee 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -262,7 +262,7 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals
*dir = make_float3(data3.y, data3.z, data3.w);
/* Check whether portal is on the right side. */
- if(dot(*dir, P - *lightpos) > 1e-5f)
+ if(dot(*dir, P - *lightpos) > 1e-4f)
return true;
return false;
@@ -276,6 +276,7 @@ ccl_device float background_portal_pdf(KernelGlobals *kg,
{
float portal_pdf = 0.0f;
+ int num_possible = 0;
for(int p = 0; p < kernel_data.integrator.num_portals; p++) {
if(p == ignore_portal)
continue;
@@ -284,13 +285,14 @@ ccl_device float background_portal_pdf(KernelGlobals *kg,
if(!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
continue;
+ /* There's a portal that could be sampled from this position. */
if(is_possible) {
- /* There's a portal that could be sampled from this position. */
*is_possible = true;
}
+ num_possible++;
float t = -(dot(P, dir) - dot(lightpos, dir)) / dot(direction, dir);
- if(t <= 1e-5f) {
+ if(t <= 1e-4f) {
/* Either behind the portal or too close. */
continue;
}
@@ -312,7 +314,12 @@ ccl_device float background_portal_pdf(KernelGlobals *kg,
portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false);
}
- return kernel_data.integrator.num_portals? portal_pdf / kernel_data.integrator.num_portals: 0.0f;
+ if(ignore_portal >= 0) {
+ /* We have skipped a portal that could be sampled as well. */
+ num_possible++;
+ }
+
+ return (num_possible > 0)? portal_pdf / num_possible: 0.0f;
}
ccl_device int background_num_possible_portals(KernelGlobals *kg, float3 P)
@@ -431,38 +438,28 @@ ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direct
/* Probability of sampling portals instead of the map. */
float portal_sampling_pdf = kernel_data.integrator.portal_pdf;
+ float portal_pdf = 0.0f, map_pdf = 0.0f;
if(portal_sampling_pdf > 0.0f) {
+ /* Evaluate PDF of sampling this direction by portal sampling. */
bool is_possible = false;
- float portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible);
- if(portal_pdf == 0.0f) {
- if(portal_sampling_pdf == 1.0f) {
- /* If there are no possible portals at this point,
- * the fallback sampling would have been used.
- * Otherwise, the direction would not be sampled at all => pdf = 0
- */
- return is_possible? 0.0f: kernel_data.integrator.pdf_lights / M_4PI_F;
- }
- else {
- /* We can only sample the map. */
- return background_map_pdf(kg, direction) * kernel_data.integrator.pdf_lights;
- }
- } else {
+ portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible) * portal_sampling_pdf;
+ if(!is_possible) {
+ /* Portal sampling is not possible here because all portals point to the wrong side.
+ * If map sampling is possible, it would be used instead, otherwise fallback sampling is used. */
if(portal_sampling_pdf == 1.0f) {
- /* We can only sample portals. */
- return portal_pdf * kernel_data.integrator.pdf_lights;
+ return kernel_data.integrator.pdf_lights / M_4PI_F;
}
else {
- /* We can sample both, so combine with MIS. */
- return (background_map_pdf(kg, direction) * (1.0f - portal_sampling_pdf)
- + portal_pdf * portal_sampling_pdf) * kernel_data.integrator.pdf_lights;
+ /* Force map sampling. */
+ portal_sampling_pdf = 0.0f;
}
}
}
-
- /* No portals in the scene, so must sample the map.
- * At least one of them is always possible if we have a LIGHT_BACKGROUND.
- */
- return background_map_pdf(kg, direction) * kernel_data.integrator.pdf_lights;
+ if(portal_sampling_pdf < 1.0f) {
+ /* Evaluate PDF of sampling this direction by map sampling. */
+ map_pdf = background_map_pdf(kg, direction) * (1.0f - portal_sampling_pdf);
+ }
+ return (portal_pdf + map_pdf) * kernel_data.integrator.pdf_lights;
}
#endif
@@ -620,12 +617,7 @@ ccl_device void lamp_light_sample(KernelGlobals *kg, int lamp,
}
}
-#if defined(__KERNEL_CUDA__) && (__CUDA_ARCH__ >= 500) && (defined(i386) || defined(_M_IX86))
-ccl_device_noinline
-#else
-ccl_device
-#endif
-bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
+ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
{
float4 data0 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 0);
float4 data1 = kernel_tex_fetch(__light_data, lamp*LIGHT_SIZE + 1);
@@ -693,8 +685,10 @@ bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, L
return false;
if(!ray_aligned_disk_intersect(P, D, t,
- lightP, radius, &ls->P, &ls->t))
+ lightP, radius, &ls->P, &ls->t))
+ {
return false;
+ }
ls->Ng = -D;
ls->D = D;
@@ -736,8 +730,10 @@ bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, L
float3 light_P = make_float3(data0.y, data0.z, data0.w);
if(!ray_quad_intersect(P, D, t,
- light_P, axisu, axisv, &ls->P, &ls->t))
+ light_P, axisu, axisv, &ls->P, &ls->t))
+ {
return false;
+ }
ls->D = D;
ls->Ng = Ng;
@@ -757,12 +753,12 @@ ccl_device void object_transform_light_sample(KernelGlobals *kg, LightSample *ls
#ifdef __INSTANCING__
/* instance transform */
if(object >= 0) {
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
Transform itfm;
Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm);
-#else
+# else
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
-#endif
+# endif
ls->P = transform_point(&tfm, ls->P);
ls->Ng = normalize(transform_direction(&tfm, ls->Ng));
@@ -845,7 +841,14 @@ ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, i
return (bounce > __float_as_int(data4.x));
}
-ccl_device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float time, float3 P, int bounce, LightSample *ls)
+ccl_device_noinline void light_sample(KernelGlobals *kg,
+ float randt,
+ float randu,
+ float randv,
+ float time,
+ float3 P,
+ int bounce,
+ LightSample *ls)
{
/* sample index */
int index = light_distribution_sample(kg, randt);
diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h
index 453f4c8b421..9bee5603474 100644
--- a/intern/cycles/kernel/kernel_math.h
+++ b/intern/cycles/kernel/kernel_math.h
@@ -20,6 +20,7 @@
#include "util_color.h"
#include "util_math.h"
#include "util_math_fast.h"
+#include "util_texture.h"
#include "util_transform.h"
#endif /* __KERNEL_MATH_H__ */
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 9794ad1d180..c136c85df59 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -15,7 +15,7 @@
*/
#ifdef __OSL__
-#include "osl_shader.h"
+# include "osl_shader.h"
#endif
#include "kernel_random.h"
@@ -32,11 +32,11 @@
#include "kernel_passes.h"
#ifdef __SUBSURFACE__
-#include "kernel_subsurface.h"
+# include "kernel_subsurface.h"
#endif
#ifdef __VOLUME__
-#include "kernel_volume.h"
+# include "kernel_volume.h"
#endif
#include "kernel_path_state.h"
@@ -47,52 +47,69 @@
#include "kernel_path_volume.h"
#ifdef __KERNEL_DEBUG__
-#include "kernel_debug.h"
+# include "kernel_debug.h"
#endif
CCL_NAMESPACE_BEGIN
-ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
- float3 throughput, int num_samples, PathState state, PathRadiance *L)
+ccl_device void kernel_path_indirect(KernelGlobals *kg,
+ RNG *rng,
+ Ray *ray,
+ float3 throughput,
+ int num_samples,
+ PathState *state,
+ PathRadiance *L)
{
/* path iteration */
for(;;) {
/* intersect scene */
Intersection isect;
- uint visibility = path_state_ray_visibility(kg, &state);
- bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
+ uint visibility = path_state_ray_visibility(kg, state);
+ bool hit = scene_intersect(kg,
+ ray,
+ visibility,
+ &isect,
+ NULL,
+ 0.0f, 0.0f);
#ifdef __LAMP_MIS__
- if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
+ if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
/* ray starting from previous non-transparent bounce */
Ray light_ray;
- light_ray.P = ray.P - state.ray_t*ray.D;
- state.ray_t += isect.t;
- light_ray.D = ray.D;
- light_ray.t = state.ray_t;
- light_ray.time = ray.time;
- light_ray.dD = ray.dD;
- light_ray.dP = ray.dP;
+ light_ray.P = ray->P - state->ray_t*ray->D;
+ state->ray_t += isect.t;
+ light_ray.D = ray->D;
+ light_ray.t = state->ray_t;
+ light_ray.time = ray->time;
+ light_ray.dD = ray->dD;
+ light_ray.dP = ray->dP;
/* intersect with lamp */
float3 emission;
-
- if(indirect_lamp_emission(kg, &state, &light_ray, &emission))
- path_radiance_accum_emission(L, throughput, emission, state.bounce);
+ if(indirect_lamp_emission(kg, state, &light_ray, &emission)) {
+ path_radiance_accum_emission(L,
+ throughput,
+ emission,
+ state->bounce);
+ }
}
#endif
#ifdef __VOLUME__
/* volume attenuation, emission, scatter */
- if(state.volume_stack[0].shader != SHADER_NONE) {
- Ray volume_ray = ray;
+ if(state->volume_stack[0].shader != SHADER_NONE) {
+ Ray volume_ray = *ray;
volume_ray.t = (hit)? isect.t: FLT_MAX;
- bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
+ bool heterogeneous =
+ volume_stack_is_heterogeneous(kg,
+ state->volume_stack);
-#ifdef __VOLUME_DECOUPLED__
- int sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
+# ifdef __VOLUME_DECOUPLED__
+ int sampling_method =
+ volume_stack_sampling_method(kg,
+ state->volume_stack);
bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, false, sampling_method);
if(decoupled) {
@@ -100,70 +117,117 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
VolumeSegment volume_segment;
ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
- kernel_volume_decoupled_record(kg, &state,
- &volume_ray, &volume_sd, &volume_segment, heterogeneous);
-
+ shader_setup_from_volume(kg,
+ &volume_sd,
+ &volume_ray);
+ kernel_volume_decoupled_record(kg,
+ state,
+ &volume_ray,
+ &volume_sd,
+ &volume_segment,
+ heterogeneous);
+
volume_segment.sampling_method = sampling_method;
/* emission */
- if(volume_segment.closure_flag & SD_EMISSION)
- path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce);
+ if(volume_segment.closure_flag & SD_EMISSION) {
+ path_radiance_accum_emission(L,
+ throughput,
+ volume_segment.accum_emission,
+ state->bounce);
+ }
/* scattering */
VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
if(volume_segment.closure_flag & SD_SCATTER) {
- bool all = kernel_data.integrator.sample_all_lights_indirect;
+ int all = kernel_data.integrator.sample_all_lights_indirect;
/* direct light sampling */
- kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, L, all, &volume_ray, &volume_segment);
+ kernel_branched_path_volume_connect_light(kg,
+ rng,
+ &volume_sd,
+ throughput,
+ state,
+ L,
+ all,
+ &volume_ray,
+ &volume_segment);
/* indirect sample. if we use distance sampling and take just
* one sample for direct and indirect light, we could share
* this computation, but makes code a bit complex */
- float rphase = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_PHASE);
- float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE);
+ float rphase = path_state_rng_1D_for_decision(kg, rng, state, PRNG_PHASE);
+ float rscatter = path_state_rng_1D_for_decision(kg, rng, state, PRNG_SCATTER_DISTANCE);
result = kernel_volume_decoupled_scatter(kg,
- &state, &volume_ray, &volume_sd, &throughput,
- rphase, rscatter, &volume_segment, NULL, true);
+ state,
+ &volume_ray,
+ &volume_sd,
+ &throughput,
+ rphase,
+ rscatter,
+ &volume_segment,
+ NULL,
+ true);
}
/* free cached steps */
kernel_volume_decoupled_free(kg, &volume_segment);
if(result == VOLUME_PATH_SCATTERED) {
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, L, &ray))
+ if(kernel_path_volume_bounce(kg,
+ rng,
+ &volume_sd,
+ &throughput,
+ state,
+ L,
+ ray))
+ {
continue;
- else
+ }
+ else {
break;
+ }
}
else {
throughput *= volume_segment.accum_transmittance;
}
}
else
-#endif
+# endif
{
/* integrate along volume segment with distance sampling */
ShaderData volume_sd;
VolumeIntegrateResult result = kernel_volume_integrate(
- kg, &state, &volume_sd, &volume_ray, L, &throughput, rng, heterogeneous);
+ kg, state, &volume_sd, &volume_ray, L, &throughput, rng, heterogeneous);
-#ifdef __VOLUME_SCATTER__
+# ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* direct lighting */
- kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, L);
+ kernel_path_volume_connect_light(kg,
+ rng,
+ &volume_sd,
+ throughput,
+ state,
+ L);
/* indirect light bounce */
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, L, &ray))
+ if(kernel_path_volume_bounce(kg,
+ rng,
+ &volume_sd,
+ &throughput,
+ state,
+ L,
+ ray))
+ {
continue;
- else
+ }
+ else {
break;
+ }
}
-#endif
+# endif
}
}
#endif
@@ -171,8 +235,11 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
if(!hit) {
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, &state, &ray);
- path_radiance_accum_background(L, throughput, L_background, state.bounce);
+ float3 L_background = indirect_background(kg, state, ray);
+ path_radiance_accum_background(L,
+ throughput,
+ L_background,
+ state->bounce);
#endif
break;
@@ -180,9 +247,12 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
/* setup shading */
ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce);
- float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_INDIRECT);
+ shader_setup_from_ray(kg,
+ &sd,
+ &isect,
+ ray);
+ float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
+ shader_eval_surface(kg, &sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT);
#ifdef __BRANCHED_PATH__
shader_merge_closures(&sd);
#endif
@@ -190,7 +260,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
/* blurring of bsdf after bounces, for rays that have a small likelihood
* of following this particular path (diffuse, rough glossy) */
if(kernel_data.integrator.filter_glossy != FLT_MAX) {
- float blur_pdf = kernel_data.integrator.filter_glossy*state.min_ray_pdf;
+ float blur_pdf = kernel_data.integrator.filter_glossy*state->min_ray_pdf;
if(blur_pdf < 1.0f) {
float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
@@ -201,21 +271,28 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
#ifdef __EMISSION__
/* emission */
if(sd.flag & SD_EMISSION) {
- float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
- path_radiance_accum_emission(L, throughput, emission, state.bounce);
+ float3 emission = indirect_primitive_emission(kg,
+ &sd,
+ isect.t,
+ state->flag,
+ state->ray_pdf);
+ path_radiance_accum_emission(L, throughput, emission, state->bounce);
}
#endif
/* path termination. this is a strange place to put the termination, it's
* mainly due to the mixed in MIS that we use. gives too many unneeded
* shader evaluations, only need emission if we are going to terminate */
- float probability = path_state_terminate_probability(kg, &state, throughput*num_samples);
+ float probability =
+ path_state_terminate_probability(kg,
+ state,
+ throughput*num_samples);
if(probability == 0.0f) {
break;
}
else if(probability != 1.0f) {
- float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE);
+ float terminate = path_state_rng_1D_for_decision(kg, rng, state, PRNG_TERMINATE);
if(terminate >= probability)
break;
@@ -227,7 +304,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
/* ambient occlusion */
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
float bsdf_u, bsdf_v;
- path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
+ path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
float ao_factor = kernel_data.background.ao_factor;
float3 ao_N;
@@ -245,14 +322,20 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
light_ray.P = ray_offset(sd.P, sd.Ng);
light_ray.D = ao_D;
light_ray.t = kernel_data.background.ao_distance;
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
light_ray.time = sd.time;
-#endif
+# endif
light_ray.dP = sd.dP;
light_ray.dD = differential3_zero();
- if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow))
- path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state.bounce);
+ if(!shadow_blocked(kg, state, &light_ray, &ao_shadow)) {
+ path_radiance_accum_ao(L,
+ throughput,
+ ao_alpha,
+ ao_bsdf,
+ ao_shadow,
+ state->bounce);
+ }
}
}
#endif
@@ -269,28 +352,51 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, Ray ray,
/* do bssrdf scatter step if we picked a bssrdf closure */
if(sc) {
- uint lcg_state = lcg_state_init(rng, &state, 0x68bc21eb);
+ uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb);
float bssrdf_u, bssrdf_v;
- path_state_rng_2D(kg, rng, &state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
- subsurface_scatter_step(kg, &sd, state.flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
+ path_state_rng_2D(kg,
+ rng,
+ state,
+ PRNG_BSDF_U,
+ &bssrdf_u, &bssrdf_v);
+ subsurface_scatter_step(kg,
+ &sd,
+ state,
+ state->flag,
+ sc,
+ &lcg_state,
+ bssrdf_u, bssrdf_v,
+ false);
}
}
#endif
#if defined(__EMISSION__) && defined(__BRANCHED_PATH__)
if(kernel_data.integrator.use_direct_light) {
- bool all = kernel_data.integrator.sample_all_lights_indirect;
- kernel_branched_path_surface_connect_light(kg, rng, &sd, &state, throughput, 1.0f, L, all);
+ int all = kernel_data.integrator.sample_all_lights_indirect;
+ kernel_branched_path_surface_connect_light(kg,
+ rng,
+ &sd,
+ state,
+ throughput,
+ 1.0f,
+ L,
+ all);
}
#endif
- if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, &state, L, &ray))
+ if(!kernel_path_surface_bounce(kg, rng, &sd, &throughput, state, L, ray))
break;
}
}
-ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput)
+ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
+ ShaderData *sd,
+ PathRadiance *L,
+ PathState *state,
+ RNG *rng,
+ float3 throughput)
{
/* todo: solve correlation */
float bsdf_u, bsdf_v;
@@ -326,7 +432,15 @@ ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *
#ifdef __SUBSURFACE__
-ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, Ray *ray, float3 *throughput)
+ccl_device bool kernel_path_subsurface_scatter(
+ KernelGlobals *kg,
+ ShaderData *sd,
+ PathRadiance *L,
+ PathState *state,
+ RNG *rng,
+ Ray *ray,
+ float3 *throughput,
+ SubsurfaceIndirectRays *ss_indirect)
{
float bssrdf_probability;
ShaderClosure *sc = subsurface_scatter_pick_closure(kg, sd, &bssrdf_probability);
@@ -336,64 +450,152 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd
/* do bssrdf scatter step if we picked a bssrdf closure */
if(sc) {
+ /* We should never have two consecutive BSSRDF bounces,
+ * the second one should be converted to a diffuse BSDF to
+ * avoid this.
+ */
+ kernel_assert(!ss_indirect->tracing);
+
uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb);
- ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
+ SubsurfaceIntersection ss_isect;
float bssrdf_u, bssrdf_v;
path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
- int num_hits = subsurface_scatter_multi_step(kg, sd, bssrdf_sd, state->flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
-#ifdef __VOLUME__
- Ray volume_ray = *ray;
- bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
- ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
-#endif
+ int num_hits = subsurface_scatter_multi_intersect(kg,
+ &ss_isect,
+ sd,
+ sc,
+ &lcg_state,
+ bssrdf_u, bssrdf_v,
+ false);
+# ifdef __VOLUME__
+ ss_indirect->need_update_volume_stack =
+ kernel_data.integrator.use_volumes &&
+ ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
+# endif
/* compute lighting with the BSDF closure */
for(int hit = 0; hit < num_hits; hit++) {
- float3 tp = *throughput;
- PathState hit_state = *state;
- Ray hit_ray = *ray;
-
- hit_state.rng_offset += PRNG_BOUNCE_NUM;
-
- kernel_path_surface_connect_light(kg, rng, &bssrdf_sd[hit], tp, state, L);
-
- if(kernel_path_surface_bounce(kg, rng, &bssrdf_sd[hit], &tp, &hit_state, L, &hit_ray)) {
-#ifdef __LAMP_MIS__
- hit_state.ray_t = 0.0f;
-#endif
+ /* NOTE: We reuse the existing ShaderData, we assume the path
+ * integration loop stops when this function returns true.
+ */
+ subsurface_scatter_multi_setup(kg,
+ &ss_isect,
+ hit,
+ sd,
+ state,
+ state->flag,
+ sc,
+ false);
+
+ PathState *hit_state = &ss_indirect->state[ss_indirect->num_rays];
+ Ray *hit_ray = &ss_indirect->rays[ss_indirect->num_rays];
+ float3 *hit_tp = &ss_indirect->throughputs[ss_indirect->num_rays];
+ PathRadiance *hit_L = &ss_indirect->L[ss_indirect->num_rays];
+
+ *hit_state = *state;
+ *hit_ray = *ray;
+ *hit_tp = *throughput;
+
+ hit_state->rng_offset += PRNG_BOUNCE_NUM;
+
+ path_radiance_init(hit_L, kernel_data.film.use_light_pass);
+ hit_L->direct_throughput = L->direct_throughput;
+ path_radiance_copy_indirect(hit_L, L);
+
+ kernel_path_surface_connect_light(kg, rng, sd, *hit_tp, state, hit_L);
+
+ if(kernel_path_surface_bounce(kg,
+ rng,
+ sd,
+ hit_tp,
+ hit_state,
+ hit_L,
+ hit_ray))
+ {
+# ifdef __LAMP_MIS__
+ hit_state->ray_t = 0.0f;
+# endif
-#ifdef __VOLUME__
- if(need_update_volume_stack) {
+# ifdef __VOLUME__
+ if(ss_indirect->need_update_volume_stack) {
+ Ray volume_ray = *ray;
/* Setup ray from previous surface point to the new one. */
- volume_ray.D = normalize_len(hit_ray.P - volume_ray.P,
+ volume_ray.D = normalize_len(hit_ray->P - volume_ray.P,
&volume_ray.t);
kernel_volume_stack_update_for_subsurface(
kg,
&volume_ray,
- hit_state.volume_stack);
-
- /* Move volume ray forward. */
- volume_ray.P = hit_ray.P;
+ hit_state->volume_stack);
}
-#endif
-
- kernel_path_indirect(kg, rng, hit_ray, tp, state->num_samples, hit_state, L);
-
- /* for render passes, sum and reset indirect light pass variables
- * for the next samples */
- path_radiance_sum_indirect(L);
+# endif
path_radiance_reset_indirect(L);
+ ss_indirect->num_rays++;
+ }
+ else {
+ path_radiance_accum_sample(L, hit_L, 1);
}
}
return true;
}
return false;
}
-#endif
-ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer)
+ccl_device_inline void kernel_path_subsurface_init_indirect(
+ SubsurfaceIndirectRays *ss_indirect)
+{
+ ss_indirect->tracing = false;
+ ss_indirect->num_rays = 0;
+}
+
+ccl_device void kernel_path_subsurface_accum_indirect(
+ SubsurfaceIndirectRays *ss_indirect,
+ PathRadiance *L)
+{
+ if(ss_indirect->tracing) {
+ path_radiance_sum_indirect(L);
+ path_radiance_accum_sample(&ss_indirect->direct_L, L, 1);
+ if(ss_indirect->num_rays == 0) {
+ *L = ss_indirect->direct_L;
+ }
+ }
+}
+
+ccl_device void kernel_path_subsurface_setup_indirect(
+ KernelGlobals *kg,
+ SubsurfaceIndirectRays *ss_indirect,
+ PathState *state,
+ Ray *ray,
+ PathRadiance *L,
+ float3 *throughput)
+{
+ if(!ss_indirect->tracing) {
+ ss_indirect->direct_L = *L;
+ }
+ ss_indirect->tracing = true;
+
+ /* Setup state, ray and throughput for indirect SSS rays. */
+ ss_indirect->num_rays--;
+
+ Ray *indirect_ray = &ss_indirect->rays[ss_indirect->num_rays];
+ PathRadiance *indirect_L = &ss_indirect->L[ss_indirect->num_rays];
+
+ *state = ss_indirect->state[ss_indirect->num_rays];
+ *ray = *indirect_ray;
+ *L = *indirect_L;
+ *throughput = ss_indirect->throughputs[ss_indirect->num_rays];
+
+ state->rng_offset += ss_indirect->num_rays * PRNG_BOUNCE_NUM;
+}
+
+#endif /* __SUBSURFACE__ */
+
+ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg,
+ RNG *rng,
+ int sample,
+ Ray ray,
+ ccl_global float *buffer)
{
/* initialize */
PathRadiance L;
@@ -410,6 +612,13 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
debug_data_init(&debug_data);
#endif
+#ifdef __SUBSURFACE__
+ SubsurfaceIndirectRays ss_indirect;
+ kernel_path_subsurface_init_indirect(&ss_indirect);
+
+ for(;;) {
+#endif
+
/* path iteration */
for(;;) {
/* intersect scene */
@@ -473,7 +682,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
-#ifdef __VOLUME_DECOUPLED__
+# ifdef __VOLUME_DECOUPLED__
int sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, true, sampling_method);
@@ -482,7 +691,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
VolumeSegment volume_segment;
ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
+ shader_setup_from_volume(kg, &volume_sd, &volume_ray);
kernel_volume_decoupled_record(kg, &state,
&volume_ray, &volume_sd, &volume_segment, heterogeneous);
@@ -496,7 +705,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
if(volume_segment.closure_flag & SD_SCATTER) {
- bool all = false;
+ int all = false;
/* direct light sampling */
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
@@ -526,15 +735,15 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
throughput *= volume_segment.accum_transmittance;
}
}
- else
-#endif
+ else
+# endif
{
/* integrate along volume segment with distance sampling */
ShaderData volume_sd;
VolumeIntegrateResult result = kernel_volume_integrate(
kg, &state, &volume_sd, &volume_ray, &L, &throughput, rng, heterogeneous);
-#ifdef __VOLUME_SCATTER__
+# ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* direct lighting */
kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, &L);
@@ -545,7 +754,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
else
break;
}
-#endif
+# endif
}
}
#endif
@@ -572,9 +781,9 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
/* setup shading */
ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce);
+ shader_setup_from_ray(kg, &sd, &isect, &ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF);
- shader_eval_surface(kg, &sd, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN);
/* holdout */
#ifdef __HOLDOUT__
@@ -647,10 +856,19 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
/* bssrdf scatter to a different location on the same object, replacing
* the closures with a diffuse BSDF */
if(sd.flag & SD_BSSRDF) {
- if(kernel_path_subsurface_scatter(kg, &sd, &L, &state, rng, &ray, &throughput))
+ if(kernel_path_subsurface_scatter(kg,
+ &sd,
+ &L,
+ &state,
+ rng,
+ &ray,
+ &throughput,
+ &ss_indirect))
+ {
break;
+ }
}
-#endif
+#endif /* __SUBSURFACE__ */
/* direct lighting */
kernel_path_surface_connect_light(kg, rng, &sd, throughput, &state, &L);
@@ -660,6 +878,26 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
break;
}
+#ifdef __SUBSURFACE__
+ kernel_path_subsurface_accum_indirect(&ss_indirect, &L);
+
+ /* Trace indirect subsurface rays by restarting the loop. this uses less
+ * stack memory than invoking kernel_path_indirect.
+ */
+ if(ss_indirect.num_rays) {
+ kernel_path_subsurface_setup_indirect(kg,
+ &ss_indirect,
+ &state,
+ &ray,
+ &L,
+ &throughput);
+ }
+ else {
+ break;
+ }
+ }
+#endif /* __SUBSURFACE__ */
+
float3 L_sum = path_radiance_clamp_and_sum(kg, &L);
kernel_write_light_passes(kg, buffer, &L, sample);
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index b6d64985f6a..13ae4cf669b 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -91,10 +91,27 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
float3 tp = throughput;
Ray bsdf_ray;
- if(!kernel_branched_path_surface_bounce(kg, &bsdf_rng, sd, sc, j, num_samples, &tp, &ps, L, &bsdf_ray))
+ if(!kernel_branched_path_surface_bounce(kg,
+ &bsdf_rng,
+ sd,
+ sc,
+ j,
+ num_samples,
+ &tp,
+ &ps,
+ L,
+ &bsdf_ray))
+ {
continue;
+ }
- kernel_path_indirect(kg, rng, bsdf_ray, tp*num_samples_inv, num_samples, ps, L);
+ kernel_path_indirect(kg,
+ rng,
+ &bsdf_ray,
+ tp*num_samples_inv,
+ num_samples,
+ &ps,
+ L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
@@ -128,10 +145,16 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
/* do subsurface scatter step with copy of shader data, this will
* replace the BSSRDF with a diffuse BSDF closure */
for(int j = 0; j < num_samples; j++) {
- ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
+ SubsurfaceIntersection ss_isect;
float bssrdf_u, bssrdf_v;
path_branched_rng_2D(kg, &bssrdf_rng, state, j, num_samples, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
- int num_hits = subsurface_scatter_multi_step(kg, sd, bssrdf_sd, state->flag, sc, &lcg_state, bssrdf_u, bssrdf_v, true);
+ int num_hits = subsurface_scatter_multi_intersect(kg,
+ &ss_isect,
+ sd,
+ sc,
+ &lcg_state,
+ bssrdf_u, bssrdf_v,
+ true);
#ifdef __VOLUME__
Ray volume_ray = *ray;
bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
@@ -140,6 +163,16 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
/* compute lighting with the BSDF closure */
for(int hit = 0; hit < num_hits; hit++) {
+ ShaderData bssrdf_sd = *sd;
+ subsurface_scatter_multi_setup(kg,
+ &ss_isect,
+ hit,
+ &bssrdf_sd,
+ state,
+ state->flag,
+ sc,
+ true);
+
PathState hit_state = *state;
path_state_branch(&hit_state, j, num_samples);
@@ -147,7 +180,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
#ifdef __VOLUME__
if(need_update_volume_stack) {
/* Setup ray from previous surface point to the new one. */
- float3 P = ray_offset(bssrdf_sd[hit].P, -bssrdf_sd[hit].Ng);
+ float3 P = ray_offset(bssrdf_sd.P, -bssrdf_sd.Ng);
volume_ray.D = normalize_len(P - volume_ray.P,
&volume_ray.t);
@@ -155,25 +188,34 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
kg,
&volume_ray,
hit_state.volume_stack);
-
- /* Move volume ray forward. */
- volume_ray.P = P;
}
#endif
#ifdef __EMISSION__
/* direct light */
if(kernel_data.integrator.use_direct_light) {
- bool all = kernel_data.integrator.sample_all_lights_direct;
- kernel_branched_path_surface_connect_light(kg, rng,
- &bssrdf_sd[hit], &hit_state, throughput, num_samples_inv, L, all);
+ int all = kernel_data.integrator.sample_all_lights_direct;
+ kernel_branched_path_surface_connect_light(
+ kg,
+ rng,
+ &bssrdf_sd,
+ &hit_state,
+ throughput,
+ num_samples_inv,
+ L,
+ all);
}
#endif
/* indirect light */
- kernel_branched_path_surface_indirect_light(kg, rng,
- &bssrdf_sd[hit], throughput, num_samples_inv,
- &hit_state, L);
+ kernel_branched_path_surface_indirect_light(
+ kg,
+ rng,
+ &bssrdf_sd,
+ throughput,
+ num_samples_inv,
+ &hit_state,
+ L);
}
}
}
@@ -247,7 +289,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
VolumeSegment volume_segment;
ShaderData volume_sd;
- shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
+ shader_setup_from_volume(kg, &volume_sd, &volume_ray);
kernel_volume_decoupled_record(kg, &state,
&volume_ray, &volume_sd, &volume_segment, heterogeneous);
@@ -255,7 +297,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
if(volume_segment.closure_flag & SD_SCATTER) {
volume_segment.sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
- bool all = kernel_data.integrator.sample_all_lights_direct;
+ int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
throughput, &state, &L, all, &volume_ray, &volume_segment);
@@ -285,12 +327,25 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
&ps, &pray, &volume_sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
-
+
(void)result;
kernel_assert(result == VOLUME_PATH_SCATTERED);
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &tp, &ps, &L, &pray)) {
- kernel_path_indirect(kg, rng, pray, tp*num_samples_inv, num_samples, ps, &L);
+ if(kernel_path_volume_bounce(kg,
+ rng,
+ &volume_sd,
+ &tp,
+ &ps,
+ &L,
+ &pray))
+ {
+ kernel_path_indirect(kg,
+ rng,
+ &pray,
+ tp*num_samples_inv,
+ num_samples,
+ &ps,
+ &L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
@@ -326,15 +381,28 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
VolumeIntegrateResult result = kernel_volume_integrate(
kg, &ps, &volume_sd, &volume_ray, &L, &tp, rng, heterogeneous);
-
+
#ifdef __VOLUME_SCATTER__
if(result == VOLUME_PATH_SCATTERED) {
/* todo: support equiangular, MIS and all light sampling.
* alternatively get decoupled ray marching working on the GPU */
kernel_path_volume_connect_light(kg, rng, &volume_sd, tp, &state, &L);
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &tp, &ps, &L, &pray)) {
- kernel_path_indirect(kg, rng, pray, tp, num_samples, ps, &L);
+ if(kernel_path_volume_bounce(kg,
+ rng,
+ &volume_sd,
+ &tp,
+ &ps,
+ &L,
+ &pray))
+ {
+ kernel_path_indirect(kg,
+ rng,
+ &pray,
+ tp,
+ num_samples,
+ &ps,
+ &L);
/* for render passes, sum and reset indirect light pass variables
* for the next samples */
@@ -373,8 +441,8 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
/* setup shading */
ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce);
- shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
+ shader_setup_from_ray(kg, &sd, &isect, &ray);
+ shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
shader_merge_closures(&sd);
/* holdout */
@@ -449,7 +517,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in
#ifdef __EMISSION__
/* direct light */
if(kernel_data.integrator.use_direct_light) {
- bool all = kernel_data.integrator.sample_all_lights_direct;
+ int all = kernel_data.integrator.sample_all_lights_direct;
kernel_branched_path_surface_connect_light(kg, rng,
&sd, &hit_state, throughput, 1.0f, &L, all);
}
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index 15efb2371de..540f289eae0 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -168,5 +168,15 @@ ccl_device_inline float path_state_terminate_probability(KernelGlobals *kg, ccl_
return average(throughput); /* todo: try using max here */
}
+/* TODO(DingTo): Find more meaningful name for this */
+ccl_device_inline void path_state_modify_bounce(ccl_addr_space PathState *state, bool increase)
+{
+ /* Modify bounce temporarily for shader eval */
+ if(increase)
+ state->bounce += 1;
+ else
+ state->bounce -= 1;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index fe85a6b6e4b..1818c4fd2da 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -19,8 +19,8 @@ CCL_NAMESPACE_BEGIN
#if defined(__BRANCHED_PATH__) || defined(__SUBSURFACE__)
/* branched path tracing: connect path directly to position on one or more lights and add it to L */
-ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RNG *rng,
- ShaderData *sd, PathState *state, float3 throughput, float num_samples_adjust, PathRadiance *L, bool sample_all_lights)
+ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RNG *rng,
+ ShaderData *sd, PathState *state, float3 throughput, float num_samples_adjust, PathRadiance *L, int sample_all_lights)
{
#ifdef __EMISSION__
/* sample illumination from lights to find path contribution */
@@ -31,15 +31,15 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
BsdfEval L_light;
bool is_lamp;
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
light_ray.time = ccl_fetch(sd, time);
-#endif
+# endif
if(sample_all_lights) {
/* lamp sampling */
for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
if(UNLIKELY(light_select_reached_max_bounces(kg, i, state->bounce)))
- continue;
+ continue;
int num_samples = ceil_to_int(num_samples_adjust*light_select_num_samples(kg, i));
float num_samples_inv = num_samples_adjust/(num_samples*kernel_data.integrator.num_all_lights);
@@ -55,7 +55,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
LightSample ls;
lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls);
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -87,7 +87,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
LightSample ls;
light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -109,7 +109,7 @@ ccl_device void kernel_branched_path_surface_connect_light(KernelGlobals *kg, RN
light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
/* sample random light */
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -150,7 +150,7 @@ ccl_device bool kernel_branched_path_surface_bounce(KernelGlobals *kg, RNG *rng,
/* setup ray */
ray->P = ray_offset(ccl_fetch(sd, P), (label & LABEL_TRANSMIT)? -ccl_fetch(sd, Ng): ccl_fetch(sd, Ng));
- ray->D = bsdf_omega_in;
+ ray->D = normalize(bsdf_omega_in);
ray->t = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
ray->dP = ccl_fetch(sd, dP);
@@ -206,7 +206,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_
LightSample ls;
light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls);
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -257,7 +257,7 @@ ccl_device_inline bool kernel_path_surface_bounce(KernelGlobals *kg, ccl_addr_sp
/* setup ray */
ray->P = ray_offset(ccl_fetch(sd, P), (label & LABEL_TRANSMIT)? -ccl_fetch(sd, Ng): ccl_fetch(sd, Ng));
- ray->D = bsdf_omega_in;
+ ray->D = normalize(bsdf_omega_in);
if(state->bounce == 0)
ray->t -= ccl_fetch(sd, ray_length); /* clipping works through transparent */
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index 82dc0f97622..9eb8b240b88 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -36,15 +36,15 @@ ccl_device void kernel_path_volume_connect_light(KernelGlobals *kg, RNG *rng,
bool is_lamp;
/* connect to light from given point where shader has been evaluated */
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
-#endif
+# endif
light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls);
if(ls.pdf == 0.0f)
return;
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -117,9 +117,9 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
BsdfEval L_light;
bool is_lamp;
-#ifdef __OBJECT_MOTION__
+# ifdef __OBJECT_MOTION__
light_ray.time = sd->time;
-#endif
+# endif
if(sample_all_lights) {
/* lamp sampling */
@@ -160,7 +160,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
if(ls.pdf == 0.0f)
continue;
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -211,7 +211,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
if(ls.pdf == 0.0f)
continue;
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
@@ -251,7 +251,7 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG
return;
/* sample random light */
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp, state->bounce, state->transparent_bounce)) {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* trace shadow ray */
float3 shadow;
diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h
index 62922df3286..c1a359e9269 100644
--- a/intern/cycles/kernel/kernel_projection.h
+++ b/intern/cycles/kernel/kernel_projection.h
@@ -47,10 +47,10 @@ ccl_device float2 direction_to_spherical(float3 dir)
ccl_device float3 spherical_to_direction(float theta, float phi)
{
- return make_float3(
- sinf(theta)*cosf(phi),
- sinf(theta)*sinf(phi),
- cosf(theta));
+ float sin_theta = sinf(theta);
+ return make_float3(sin_theta*cosf(phi),
+ sin_theta*sinf(phi),
+ cosf(theta));
}
/* Equirectangular coordinates <-> Cartesian direction */
@@ -67,11 +67,10 @@ ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 ra
{
float phi = range.x*u + range.y;
float theta = range.z*v + range.w;
-
- return make_float3(
- sinf(theta)*cosf(phi),
- sinf(theta)*sinf(phi),
- cosf(theta));
+ float sin_theta = sinf(theta);
+ return make_float3(sin_theta*cosf(phi),
+ sin_theta*sinf(phi),
+ cosf(theta));
}
ccl_device float2 direction_to_equirectangular(float3 dir)
@@ -222,7 +221,48 @@ ccl_device float2 direction_to_panorama(KernelGlobals *kg, float3 dir)
}
}
-CCL_NAMESPACE_END
+ccl_device float3 spherical_stereo_position(KernelGlobals *kg,
+ float3 dir,
+ float3 pos)
+{
+ const float interocular_offset = kernel_data.cam.interocular_offset;
+
+ /* Interocular offset of zero means either non stereo, or stereo without
+ * spherical stereo.
+ */
+ if(interocular_offset == 0.0f) {
+ return pos;
+ }
+
+ float3 up = make_float3(0.0f, 0.0f, 1.0f);
+ float3 side = normalize(cross(dir, up));
-#endif /* __KERNEL_PROJECTION_CL__ */
+ return pos + (side * interocular_offset);
+}
+
+/* NOTE: Ensures direction is normalized. */
+ccl_device float3 spherical_stereo_direction(KernelGlobals *kg,
+ float3 dir,
+ float3 pos,
+ float3 newpos)
+{
+ const float convergence_distance = kernel_data.cam.convergence_distance;
+ const float3 normalized_dir = normalize(dir);
+ /* Interocular offset of zero means either no stereo, or stereo without
+ * spherical stereo.
+ * Convergence distance is FLT_MAX in the case of parallel convergence mode,
+ * no need to mdify direction in this case either.
+ */
+ if(kernel_data.cam.interocular_offset == 0.0f ||
+ convergence_distance == FLT_MAX)
+ {
+ return normalized_dir;
+ }
+
+ float3 screenpos = pos + (normalized_dir * convergence_distance);
+ return normalize(screenpos - newpos);
+}
+
+CCL_NAMESPACE_END
+#endif /* __KERNEL_PROJECTION_CL__ */
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 6b560f5fdb2..a0b56118ab7 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -48,8 +48,10 @@ ccl_device void shader_setup_object_transforms(KernelGlobals *kg, ShaderData *sd
}
#endif
-ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
- const Intersection *isect, const Ray *ray, int bounce, int transparent_bounce)
+ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
+ ShaderData *sd,
+ const Intersection *isect,
+ const Ray *ray)
{
#ifdef __INSTANCING__
ccl_fetch(sd, object) = (isect->object == PRIM_NONE)? kernel_tex_fetch(__prim_object, isect->prim): isect->object;
@@ -66,8 +68,6 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
ccl_fetch(sd, prim) = kernel_tex_fetch(__prim_index, isect->prim);
ccl_fetch(sd, ray_length) = isect->t;
- ccl_fetch(sd, ray_depth) = bounce;
- ccl_fetch(sd, transparent_depth) = transparent_bounce;
#ifdef __UV__
ccl_fetch(sd, u) = isect->u;
@@ -117,10 +117,10 @@ ccl_device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
/* instance transform */
object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N));
object_normal_transform_auto(kg, sd, &ccl_fetch(sd, Ng));
-#ifdef __DPDU__
+# ifdef __DPDU__
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu));
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv));
-#endif
+# endif
}
#endif
@@ -158,10 +158,10 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
sd->type = isect->type;
-#ifdef __UV__
+# ifdef __UV__
sd->u = isect->u;
sd->v = isect->v;
-#endif
+# endif
/* fetch triangle data */
if(sd->type == PRIMITIVE_TRIANGLE) {
@@ -176,10 +176,10 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
if(sd->shader & SHADER_SMOOTH_NORMAL)
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
-#ifdef __DPDU__
+# ifdef __DPDU__
/* dPdu/dPdv */
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
-#endif
+# endif
}
else {
/* motion triangle */
@@ -188,46 +188,51 @@ ccl_device_inline void shader_setup_from_subsurface(KernelGlobals *kg, ShaderDat
sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2);
-#ifdef __INSTANCING__
+# ifdef __INSTANCING__
if(isect->object != OBJECT_NONE) {
/* instance transform */
object_normal_transform(kg, sd, &sd->N);
object_normal_transform(kg, sd, &sd->Ng);
-#ifdef __DPDU__
+# ifdef __DPDU__
object_dir_transform(kg, sd, &sd->dPdu);
object_dir_transform(kg, sd, &sd->dPdv);
-#endif
+# endif
}
-#endif
+# endif
/* backfacing test */
if(backfacing) {
sd->flag |= SD_BACKFACING;
sd->Ng = -sd->Ng;
sd->N = -sd->N;
-#ifdef __DPDU__
+# ifdef __DPDU__
sd->dPdu = -sd->dPdu;
sd->dPdv = -sd->dPdv;
-#endif
+# endif
}
/* should not get used in principle as the shading will only use a diffuse
* BSDF, but the shader might still access it */
sd->I = sd->N;
-#ifdef __RAY_DIFFERENTIALS__
+# ifdef __RAY_DIFFERENTIALS__
/* differentials */
differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
/* don't modify dP and dI */
-#endif
+# endif
}
#endif
/* ShaderData setup from position sampled on mesh */
-ccl_device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
- const float3 P, const float3 Ng, const float3 I,
- int shader, int object, int prim, float u, float v, float t, float time, int bounce, int transparent_bounce)
+ccl_device void shader_setup_from_sample(KernelGlobals *kg,
+ ShaderData *sd,
+ const float3 P,
+ const float3 Ng,
+ const float3 I,
+ int shader, int object, int prim,
+ float u, float v, float t,
+ float time)
{
/* vectors */
ccl_fetch(sd, P) = P;
@@ -248,8 +253,6 @@ ccl_device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
ccl_fetch(sd, v) = v;
#endif
ccl_fetch(sd, ray_length) = t;
- ccl_fetch(sd, ray_depth) = bounce;
- ccl_fetch(sd, transparent_depth) = transparent_bounce;
/* detect instancing, for non-instanced the object index is -object-1 */
#ifdef __INSTANCING__
@@ -293,12 +296,12 @@ ccl_device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
#ifdef __DPDU__
triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv));
-#ifdef __INSTANCING__
+# ifdef __INSTANCING__
if(instanced) {
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu));
object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv));
}
-#endif
+# endif
#endif
}
else {
@@ -347,12 +350,12 @@ ccl_device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
/* watch out: no instance transform currently */
- shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID, 0, 0);
+ shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v, 0.0f, TIME_INVALID);
}
/* ShaderData setup from ray into background */
-ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce, int transparent_bounce)
+ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
{
/* vectors */
ccl_fetch(sd, P) = ray->D;
@@ -365,8 +368,6 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
ccl_fetch(sd, time) = ray->time;
#endif
ccl_fetch(sd, ray_length) = 0.0f;
- ccl_fetch(sd, ray_depth) = bounce;
- ccl_fetch(sd, transparent_depth) = transparent_bounce;
#ifdef __INSTANCING__
ccl_fetch(sd, object) = PRIM_NONE;
@@ -395,7 +396,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
/* ShaderData setup from point inside volume */
#ifdef __VOLUME__
-ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray, int bounce, int transparent_bounce)
+ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
{
/* vectors */
sd->P = ray->P;
@@ -408,8 +409,6 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
sd->time = ray->time;
#endif
sd->ray_length = 0.0f; /* todo: can we set this to some useful value? */
- sd->ray_depth = bounce;
- sd->transparent_depth = transparent_bounce;
#ifdef __INSTANCING__
sd->object = PRIM_NONE; /* todo: fill this for texture coordinates */
@@ -516,12 +515,52 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
*pdf = (sum_sample_weight > 0.0f)? sum_pdf/sum_sample_weight: 0.0f;
}
-ccl_device void shader_bsdf_eval(KernelGlobals *kg, ShaderData *sd,
- const float3 omega_in, BsdfEval *eval, float *pdf)
+#ifdef __BRANCHED_PATH__
+ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
+ const ShaderData *sd,
+ const float3 omega_in,
+ BsdfEval *result_eval,
+ float light_pdf,
+ bool use_mis)
+{
+ for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
+ const ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
+ if(CLOSURE_IS_BSDF(sc->type)) {
+ float bsdf_pdf = 0.0f;
+ float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf);
+ if(bsdf_pdf != 0.0f) {
+ float mis_weight = use_mis? power_heuristic(light_pdf, bsdf_pdf): 1.0f;
+ bsdf_eval_accum(result_eval,
+ sc->type,
+ eval * sc->weight * mis_weight);
+ }
+ }
+ }
+}
+#endif
+
+ccl_device void shader_bsdf_eval(KernelGlobals *kg,
+ ShaderData *sd,
+ const float3 omega_in,
+ BsdfEval *eval,
+ float light_pdf,
+ bool use_mis)
{
bsdf_eval_init(eval, NBUILTIN_CLOSURES, make_float3(0.0f, 0.0f, 0.0f), kernel_data.film.use_light_pass);
- _shader_bsdf_multi_eval(kg, sd, omega_in, pdf, -1, eval, 0.0f, 0.0f);
+#ifdef __BRANCHED_PATH__
+ if(kernel_data.integrator.branched)
+ _shader_bsdf_multi_eval_branched(kg, sd, omega_in, eval, light_pdf, use_mis);
+ else
+#endif
+ {
+ float pdf;
+ _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f);
+ if(use_mis) {
+ float weight = power_heuristic(light_pdf, pdf);
+ bsdf_eval_mul(eval, make_float3(weight, weight, weight));
+ }
+ }
}
ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
@@ -786,19 +825,19 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
/* Surface Evaluation */
ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
- float randb, int path_flag, ShaderContext ctx)
+ ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
ccl_fetch(sd, randb_closure) = randb;
#ifdef __OSL__
if(kg->osl)
- OSLShader::eval_surface(kg, sd, path_flag, ctx);
+ OSLShader::eval_surface(kg, sd, state, path_flag, ctx);
else
#endif
{
#ifdef __SVM__
- svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, path_flag);
+ svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
#else
ccl_fetch_array(sd, closure, 0)->weight = make_float3(0.8f, 0.8f, 0.8f);
ccl_fetch_array(sd, closure, 0)->N = ccl_fetch(sd, N);
@@ -811,21 +850,22 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
/* Background Evaluation */
-ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
+ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd,
+ ccl_addr_space PathState *state, int path_flag, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
ccl_fetch(sd, randb_closure) = 0.0f;
#ifdef __OSL__
if(kg->osl) {
- return OSLShader::eval_background(kg, sd, path_flag, ctx);
+ return OSLShader::eval_background(kg, sd, state, path_flag, ctx);
}
else
#endif
{
#ifdef __SVM__
- svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, path_flag);
+ svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -952,7 +992,7 @@ ccl_device int shader_phase_sample_closure(KernelGlobals *kg, const ShaderData *
/* Volume Evaluation */
ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
- VolumeStack *stack, int path_flag, ShaderContext ctx)
+ PathState *state, VolumeStack *stack, int path_flag, ShaderContext ctx)
{
/* reset closures once at the start, we will be accumulating the closures
* for all volumes in the stack into a single array of closures */
@@ -980,14 +1020,14 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
/* evaluate shader */
#ifdef __SVM__
-#ifdef __OSL__
+# ifdef __OSL__
if(kg->osl) {
- OSLShader::eval_volume(kg, sd, path_flag, ctx);
+ OSLShader::eval_volume(kg, sd, state, path_flag, ctx);
}
else
-#endif
+# endif
{
- svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, path_flag);
+ svm_eval_nodes(kg, sd, state, SHADER_TYPE_VOLUME, path_flag);
}
#endif
@@ -1001,20 +1041,20 @@ ccl_device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
/* Displacement Evaluation */
-ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx)
+ccl_device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ShaderContext ctx)
{
ccl_fetch(sd, num_closure) = 0;
ccl_fetch(sd, randb_closure) = 0.0f;
/* this will modify sd->P */
#ifdef __SVM__
-#ifdef __OSL__
+# ifdef __OSL__
if(kg->osl)
OSLShader::eval_displacement(kg, sd, ctx);
else
-#endif
+# endif
{
- svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0);
+ svm_eval_nodes(kg, sd, state, SHADER_TYPE_DISPLACEMENT, 0);
}
#endif
}
diff --git a/intern/cycles/kernel/kernel_shaderdata_vars.h b/intern/cycles/kernel/kernel_shaderdata_vars.h
deleted file mode 100644
index b157b82e023..00000000000
--- a/intern/cycles/kernel/kernel_shaderdata_vars.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-* Copyright 2011-2015 Blender Foundation
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#ifndef SD_VAR
-#define SD_VAR(type, what)
-#endif
-#ifndef SD_CLOSURE_VAR
-#define SD_CLOSURE_VAR(type, what, max_closure)
-#endif
-
-/* position */
-SD_VAR(float3, P)
-/* smooth normal for shading */
-SD_VAR(float3, N)
-/* true geometric normal */
-SD_VAR(float3, Ng)
-/* view/incoming direction */
-SD_VAR(float3, I)
-/* shader id */
-SD_VAR(int, shader)
-/* booleans describing shader, see ShaderDataFlag */
-SD_VAR(int, flag)
-
-/* primitive id if there is one, ~0 otherwise */
-SD_VAR(int, prim)
-
-/* combined type and curve segment for hair */
-SD_VAR(int, type)
-
-/* parametric coordinates
-* - barycentric weights for triangles */
-SD_VAR(float, u)
-SD_VAR(float, v)
-/* object id if there is one, ~0 otherwise */
-SD_VAR(int, object)
-
-/* motion blur sample time */
-SD_VAR(float, time)
-
-/* length of the ray being shaded */
-SD_VAR(float, ray_length)
-
-/* ray bounce depth */
-SD_VAR(int, ray_depth)
-
-/* ray transparent depth */
-SD_VAR(int, transparent_depth)
-
-#ifdef __RAY_DIFFERENTIALS__
-/* differential of P. these are orthogonal to Ng, not N */
-SD_VAR(differential3, dP)
-/* differential of I */
-SD_VAR(differential3, dI)
-/* differential of u, v */
-SD_VAR(differential, du)
-SD_VAR(differential, dv)
-#endif
-#ifdef __DPDU__
-/* differential of P w.r.t. parametric coordinates. note that dPdu is
-* not readily suitable as a tangent for shading on triangles. */
-SD_VAR(float3, dPdu)
-SD_VAR(float3, dPdv)
-#endif
-
-#ifdef __OBJECT_MOTION__
-/* object <-> world space transformations, cached to avoid
-* re-interpolating them constantly for shading */
-SD_VAR(Transform, ob_tfm)
-SD_VAR(Transform, ob_itfm)
-#endif
-
-/* Closure data, we store a fixed array of closures */
-SD_CLOSURE_VAR(ShaderClosure, closure, MAX_CLOSURE)
-SD_VAR(int, num_closure)
-SD_VAR(float, randb_closure)
-
-/* ray start position, only set for backgrounds */
-SD_VAR(float3, ray_P)
-SD_VAR(differential3, ray_dP)
-
-#ifdef __OSL__
-SD_VAR(struct KernelGlobals *, osl_globals)
-#endif
-
-#undef SD_VAR
-#undef SD_CLOSURE_VAR
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 2811a8348ca..3b1111e5069 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -107,11 +107,14 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
/* setup shader data at surface */
ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, ray, state->bounce+1, bounce);
+ shader_setup_from_ray(kg, &sd, isect, ray);
/* attenuation from transparent surface */
if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
- shader_eval_surface(kg, &sd, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ path_state_modify_bounce(state, true);
+ shader_eval_surface(kg, &sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ path_state_modify_bounce(state, false);
+
throughput *= shader_bsdf_transparency(kg, &sd);
}
@@ -180,11 +183,10 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *
* potentially transparent, and only in that case start marching. this gives
* one extra ray cast for the cases were we do want transparency. */
-ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ccl_addr_space PathState *state, ccl_addr_space Ray *ray_input, float3 *shadow
-#ifdef __SPLIT_KERNEL__
- , ShaderData *sd_mem, Intersection *isect_mem
-#endif
- )
+ccl_device_noinline bool shadow_blocked(KernelGlobals *kg,
+ ccl_addr_space PathState *state,
+ ccl_addr_space Ray *ray_input,
+ float3 *shadow)
{
*shadow = make_float3(1.0f, 1.0f, 1.0f);
@@ -199,7 +201,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ccl_addr_space PathStat
#endif
#ifdef __SPLIT_KERNEL__
- Intersection *isect = isect_mem;
+ Intersection *isect = &kg->isect_shadow[SD_THREAD];
#else
Intersection isect_object;
Intersection *isect = &isect_object;
@@ -248,16 +250,19 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ccl_addr_space PathStat
/* setup shader data at surface */
#ifdef __SPLIT_KERNEL__
- ShaderData *sd = sd_mem;
+ ShaderData *sd = kg->sd_input;
#else
ShaderData sd_object;
ShaderData *sd = &sd_object;
#endif
- shader_setup_from_ray(kg, sd, isect, ray, state->bounce+1, bounce);
+ shader_setup_from_ray(kg, sd, isect, ray);
/* attenuation from transparent surface */
if(!(ccl_fetch(sd, flag) & SD_HAS_ONLY_VOLUME)) {
- shader_eval_surface(kg, sd, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ path_state_modify_bounce(state, true);
+ shader_eval_surface(kg, sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ path_state_modify_bounce(state, false);
+
throughput *= shader_bsdf_transparency(kg, sd);
}
diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h
index 2da060c32a2..705b57ba6ff 100644
--- a/intern/cycles/kernel/kernel_subsurface.h
+++ b/intern/cycles/kernel/kernel_subsurface.h
@@ -16,7 +16,12 @@
CCL_NAMESPACE_BEGIN
-/* NEW BSSRDF: See "BSSRDF Importance Sampling", SIGGRAPH 2013 */
+/* BSSRDF using disk based importance sampling.
+ *
+ * BSSRDF Importance Sampling, SIGGRAPH 2013
+ * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf
+ *
+ */
/* TODO:
* - test using power heuristic for combing bssrdfs
@@ -101,8 +106,6 @@ ccl_device float3 subsurface_scatter_eval(ShaderData *sd, ShaderClosure *sc, flo
float sample_weight_inv = 1.0f/sample_weight_sum;
- //printf("num closures %d\n", sd->num_closure);
-
for(int i = 0; i < sd->num_closure; i++) {
sc = &sd->closure[i];
@@ -179,19 +182,24 @@ ccl_device float3 subsurface_color_pow(float3 color, float exponent)
return color;
}
-ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, ShaderData *out_sd, ShaderData *in_sd, int state_flag, float3 *eval, float3 *N)
+ccl_device void subsurface_color_bump_blur(KernelGlobals *kg,
+ ShaderData *sd,
+ PathState *state,
+ int state_flag,
+ float3 *eval,
+ float3 *N)
{
/* average color and texture blur at outgoing point */
float texture_blur;
- float3 out_color = shader_bssrdf_sum(out_sd, NULL, &texture_blur);
+ float3 out_color = shader_bssrdf_sum(sd, NULL, &texture_blur);
/* do we have bump mapping? */
- bool bump = (out_sd->flag & SD_HAS_BSSRDF_BUMP) != 0;
+ bool bump = (sd->flag & SD_HAS_BSSRDF_BUMP) != 0;
if(bump || texture_blur > 0.0f) {
/* average color and normal at incoming point */
- shader_eval_surface(kg, in_sd, 0.0f, state_flag, SHADER_CONTEXT_SSS);
- float3 in_color = shader_bssrdf_sum(in_sd, (bump)? N: NULL, NULL);
+ shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS);
+ float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL);
/* we simply divide out the average color and multiply with the average
* of the other one. we could try to do this per closure but it's quite
@@ -206,14 +214,23 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, ShaderData *out_sd
}
}
-/* subsurface scattering step, from a point on the surface to other nearby points on the same object */
-ccl_device int subsurface_scatter_multi_step(KernelGlobals *kg, ShaderData *sd, ShaderData bssrdf_sd[BSSRDF_MAX_HITS],
- int state_flag, ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all)
+/* Subsurface scattering step, from a point on the surface to other
+ * nearby points on the same object.
+ */
+ccl_device int subsurface_scatter_multi_intersect(
+ KernelGlobals *kg,
+ SubsurfaceIntersection* ss_isect,
+ ShaderData *sd,
+ ShaderClosure *sc,
+ uint *lcg_state,
+ float disk_u,
+ float disk_v,
+ bool all)
{
/* pick random axis in local frame and point on disk */
float3 disk_N, disk_T, disk_B;
float pick_pdf_N, pick_pdf_T, pick_pdf_B;
-
+
disk_N = sd->Ng;
make_orthonormals(disk_N, &disk_T, &disk_B);
@@ -259,70 +276,110 @@ ccl_device int subsurface_scatter_multi_step(KernelGlobals *kg, ShaderData *sd,
float3 disk_P = (disk_r*cosf(phi)) * disk_T + (disk_r*sinf(phi)) * disk_B;
/* create ray */
- Ray ray;
- ray.P = sd->P + disk_N*disk_height + disk_P;
- ray.D = -disk_N;
- ray.t = 2.0f*disk_height;
- ray.dP = sd->dP;
- ray.dD = differential3_zero();
- ray.time = sd->time;
+ Ray *ray = &ss_isect->ray;
+ ray->P = sd->P + disk_N*disk_height + disk_P;
+ ray->D = -disk_N;
+ ray->t = 2.0f*disk_height;
+ ray->dP = sd->dP;
+ ray->dD = differential3_zero();
+ ray->time = sd->time;
/* intersect with the same object. if multiple intersections are found it
* will use at most BSSRDF_MAX_HITS hits, a random subset of all hits */
- Intersection isect[BSSRDF_MAX_HITS];
- uint num_hits = scene_intersect_subsurface(kg, &ray, isect, sd->object, lcg_state, BSSRDF_MAX_HITS);
-
- /* evaluate bssrdf */
- float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- int num_eval_hits = min(num_hits, BSSRDF_MAX_HITS);
+ scene_intersect_subsurface(kg,
+ ray,
+ ss_isect,
+ sd->object,
+ lcg_state,
+ BSSRDF_MAX_HITS);
+ int num_eval_hits = min(ss_isect->num_hits, BSSRDF_MAX_HITS);
for(int hit = 0; hit < num_eval_hits; hit++) {
- ShaderData *bsd = &bssrdf_sd[hit];
+ /* Quickly retrieve P and Ng without setting up ShaderData. */
+ float3 hit_P;
+ if(ccl_fetch(sd, type) & PRIMITIVE_TRIANGLE) {
+ hit_P = triangle_refine_subsurface(kg,
+ sd,
+ &ss_isect->hits[hit],
+ ray);
+ }
+#ifdef __OBJECT_MOTION__
+ else if(ccl_fetch(sd, type) & PRIMITIVE_MOTION_TRIANGLE) {
+ float3 verts[3];
+ motion_triangle_vertices(
+ kg,
+ ccl_fetch(sd, object),
+ kernel_tex_fetch(__prim_index, ss_isect->hits[hit].prim),
+ ccl_fetch(sd, time),
+ verts);
+ hit_P = motion_triangle_refine_subsurface(kg,
+ sd,
+ &ss_isect->hits[hit],
+ ray,
+ verts);
+ }
+#endif /* __OBJECT_MOTION__ */
- /* setup new shading point */
- *bsd = *sd;
- shader_setup_from_subsurface(kg, bsd, &isect[hit], &ray);
+ float3 hit_Ng = ss_isect->Ng[hit];
+ if(ss_isect->hits[hit].object != OBJECT_NONE) {
+ object_normal_transform(kg, sd, &hit_Ng);
+ }
/* probability densities for local frame axes */
- float pdf_N = pick_pdf_N * fabsf(dot(disk_N, bsd->Ng));
- float pdf_T = pick_pdf_T * fabsf(dot(disk_T, bsd->Ng));
- float pdf_B = pick_pdf_B * fabsf(dot(disk_B, bsd->Ng));
-
+ float pdf_N = pick_pdf_N * fabsf(dot(disk_N, hit_Ng));
+ float pdf_T = pick_pdf_T * fabsf(dot(disk_T, hit_Ng));
+ float pdf_B = pick_pdf_B * fabsf(dot(disk_B, hit_Ng));
+
/* multiple importance sample between 3 axes, power heuristic
* found to be slightly better than balance heuristic */
float mis_weight = power_heuristic_3(pdf_N, pdf_T, pdf_B);
/* real distance to sampled point */
- float r = len(bsd->P - sd->P);
+ float r = len(hit_P - sd->P);
/* evaluate */
float w = mis_weight / pdf_N;
- if(num_hits > BSSRDF_MAX_HITS)
- w *= num_hits/(float)BSSRDF_MAX_HITS;
- eval = subsurface_scatter_eval(bsd, sc, disk_r, r, all) * w;
+ if(ss_isect->num_hits > BSSRDF_MAX_HITS)
+ w *= ss_isect->num_hits/(float)BSSRDF_MAX_HITS;
+ float3 eval = subsurface_scatter_eval(sd, sc, disk_r, r, all) * w;
- /* optionally blur colors and bump mapping */
- float3 N = bsd->N;
- subsurface_color_bump_blur(kg, sd, bsd, state_flag, &eval, &N);
-
- /* setup diffuse bsdf */
- subsurface_scatter_setup_diffuse_bsdf(bsd, eval, true, N);
+ ss_isect->weight[hit] = eval;
}
return num_eval_hits;
}
+ccl_device void subsurface_scatter_multi_setup(KernelGlobals *kg,
+ SubsurfaceIntersection* ss_isect,
+ int hit,
+ ShaderData *sd,
+ PathState *state,
+ int state_flag,
+ ShaderClosure *sc,
+ bool all)
+{
+ /* Setup new shading point. */
+ shader_setup_from_subsurface(kg, sd, &ss_isect->hits[hit], &ss_isect->ray);
+
+ /* Optionally blur colors and bump mapping. */
+ float3 weight = ss_isect->weight[hit];
+ float3 N = sd->N;
+ subsurface_color_bump_blur(kg, sd, state, state_flag, &weight, &N);
+
+ /* Setup diffuse BSDF. */
+ subsurface_scatter_setup_diffuse_bsdf(sd, weight, true, N);
+}
+
/* subsurface scattering step, from a point on the surface to another nearby point on the same object */
-ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd,
+ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd, PathState *state,
int state_flag, ShaderClosure *sc, uint *lcg_state, float disk_u, float disk_v, bool all)
{
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
- uint num_hits = 0;
/* pick random axis in local frame and point on disk */
float3 disk_N, disk_T, disk_B;
float pick_pdf_N, pick_pdf_T, pick_pdf_B;
-
+
disk_N = sd->Ng;
make_orthonormals(disk_N, &disk_T, &disk_B);
@@ -368,21 +425,21 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd,
/* intersect with the same object. if multiple intersections are
* found it will randomly pick one of them */
- Intersection isect;
- num_hits = scene_intersect_subsurface(kg, &ray, &isect, sd->object, lcg_state, 1);
+ SubsurfaceIntersection ss_isect;
+ scene_intersect_subsurface(kg, &ray, &ss_isect, sd->object, lcg_state, 1);
/* evaluate bssrdf */
- if(num_hits > 0) {
+ if(ss_isect.num_hits > 0) {
float3 origP = sd->P;
/* setup new shading point */
- shader_setup_from_subsurface(kg, sd, &isect, &ray);
+ shader_setup_from_subsurface(kg, sd, &ss_isect.hits[0], &ray);
/* probability densities for local frame axes */
float pdf_N = pick_pdf_N * fabsf(dot(disk_N, sd->Ng));
float pdf_T = pick_pdf_T * fabsf(dot(disk_T, sd->Ng));
float pdf_B = pick_pdf_B * fabsf(dot(disk_B, sd->Ng));
-
+
/* multiple importance sample between 3 axes, power heuristic
* found to be slightly better than balance heuristic */
float mis_weight = power_heuristic_3(pdf_N, pdf_T, pdf_B);
@@ -391,16 +448,16 @@ ccl_device void subsurface_scatter_step(KernelGlobals *kg, ShaderData *sd,
float r = len(sd->P - origP);
/* evaluate */
- float w = (mis_weight * num_hits) / pdf_N;
+ float w = (mis_weight * ss_isect.num_hits) / pdf_N;
eval = subsurface_scatter_eval(sd, sc, disk_r, r, all) * w;
}
/* optionally blur colors and bump mapping */
float3 N = sd->N;
- subsurface_color_bump_blur(kg, sd, sd, state_flag, &eval, &N);
+ subsurface_color_bump_blur(kg, sd, state, state_flag, &eval, &N);
/* setup diffuse bsdf */
- subsurface_scatter_setup_diffuse_bsdf(sd, eval, (num_hits > 0), N);
+ subsurface_scatter_setup_diffuse_bsdf(sd, eval, (ss_isect.num_hits > 0), N);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index f545a056cc8..2a048b7e3f2 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -15,17 +15,17 @@
*/
#ifndef KERNEL_TEX
-#define KERNEL_TEX(type, ttype, name)
+# define KERNEL_TEX(type, ttype, name)
#endif
#ifndef KERNEL_IMAGE_TEX
-#define KERNEL_IMAGE_TEX(type, ttype, name)
+# define KERNEL_IMAGE_TEX(type, ttype, name)
#endif
/* bvh */
KERNEL_TEX(float4, texture_float4, __bvh_nodes)
KERNEL_TEX(float4, texture_float4, __bvh_leaf_nodes)
-KERNEL_TEX(float4, texture_float4, __tri_woop)
+KERNEL_TEX(float4, texture_float4, __tri_storage)
KERNEL_TEX(uint, texture_uint, __prim_type)
KERNEL_TEX(uint, texture_uint, __prim_visibility)
KERNEL_TEX(uint, texture_uint, __prim_index)
@@ -79,6 +79,12 @@ KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_002)
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_003)
KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_004)
+KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float3d_000)
+KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float3d_001)
+KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float3d_002)
+KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float3d_003)
+KERNEL_IMAGE_TEX(float4, texture_image3d_float4, __tex_image_float3d_004)
+
/* image */
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_005)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_006)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 740a5f1f5d3..c9a895d9aec 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -21,14 +21,14 @@
#include "svm/svm_types.h"
#ifndef __KERNEL_GPU__
-#define __KERNEL_CPU__
+# define __KERNEL_CPU__
#endif
/* TODO(sergey): This is only to make it possible to include this header
* from outside of the kernel. but this could be done somewhat cleaner?
*/
#ifndef ccl_addr_space
-#define ccl_addr_space
+# define ccl_addr_space
#endif
CCL_NAMESPACE_BEGIN
@@ -37,8 +37,9 @@ CCL_NAMESPACE_BEGIN
#define OBJECT_SIZE 11
#define OBJECT_VECTOR_SIZE 6
#define LIGHT_SIZE 5
-#define FILTER_TABLE_SIZE 256
+#define FILTER_TABLE_SIZE 1024
#define RAMP_TABLE_SIZE 256
+#define SHUTTER_TABLE_SIZE 256
#define PARTICLE_SIZE 5
#define TIME_INVALID FLT_MAX
@@ -47,8 +48,6 @@ CCL_NAMESPACE_BEGIN
#define BECKMANN_TABLE_SIZE 256
-#define TEX_NUM_FLOAT_IMAGES 5
-
#define SHADER_NONE (~0)
#define OBJECT_NONE (~0)
#define PRIM_NONE (~0)
@@ -58,89 +57,84 @@ CCL_NAMESPACE_BEGIN
/* device capabilities */
#ifdef __KERNEL_CPU__
-#ifdef __KERNEL_SSE2__
-# define __QBVH__
-#endif
-#define __KERNEL_SHADING__
-#define __KERNEL_ADV_SHADING__
-#define __BRANCHED_PATH__
-#ifdef WITH_OSL
-#define __OSL__
-#endif
-#define __SUBSURFACE__
-#define __CMJ__
-#define __VOLUME__
-#define __VOLUME_DECOUPLED__
-#define __VOLUME_SCATTER__
-#define __SHADOW_RECORD_ALL__
-#define __VOLUME_RECORD_ALL__
-#endif
+# ifdef __KERNEL_SSE2__
+# define __QBVH__
+# endif
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
+# define __BRANCHED_PATH__
+# ifdef WITH_OSL
+# define __OSL__
+# endif
+# define __SUBSURFACE__
+# define __CMJ__
+# define __VOLUME__
+# define __VOLUME_DECOUPLED__
+# define __VOLUME_SCATTER__
+# define __SHADOW_RECORD_ALL__
+# define __VOLUME_RECORD_ALL__
+#endif /* __KERNEL_CPU__ */
#ifdef __KERNEL_CUDA__
-#define __KERNEL_SHADING__
-#define __KERNEL_ADV_SHADING__
-#define __BRANCHED_PATH__
-#define __VOLUME__
-#define __VOLUME_SCATTER__
-
-/* Experimental on GPU */
-#ifdef __KERNEL_EXPERIMENTAL__
-#define __SUBSURFACE__
-#define __CMJ__
-#endif
-
-#endif
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
+# define __BRANCHED_PATH__
+# define __VOLUME__
+# define __VOLUME_SCATTER__
+# define __SUBSURFACE__
+# define __CMJ__
+#endif /* __KERNEL_CUDA__ */
#ifdef __KERNEL_OPENCL__
/* keep __KERNEL_ADV_SHADING__ in sync with opencl_kernel_use_advanced_shading! */
-#ifdef __KERNEL_OPENCL_NVIDIA__
-# define __KERNEL_SHADING__
-# define __KERNEL_ADV_SHADING__
-# ifdef __KERNEL_EXPERIMENTAL__
-# define __CMJ__
-# endif
-#endif
-
-#ifdef __KERNEL_OPENCL_APPLE__
-# define __KERNEL_SHADING__
-# define __KERNEL_ADV_SHADING__
+# ifdef __KERNEL_OPENCL_NVIDIA__
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
+# ifdef __KERNEL_EXPERIMENTAL__
+# define __CMJ__
+# endif
+# endif /* __KERNEL_OPENCL_NVIDIA__ */
+
+# ifdef __KERNEL_OPENCL_APPLE__
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
/* TODO(sergey): Currently experimental section is ignored here,
* this is because megakernel in device_opencl does not support
* custom cflags depending on the scene features.
*/
-# ifdef __KERNEL_EXPERIMENTAL__
-# define __CMJ__
-# endif
-#endif
-
-#ifdef __KERNEL_OPENCL_AMD__
-# define __CL_USE_NATIVE__
-# define __KERNEL_SHADING__
-# define __MULTI_CLOSURE__
-# define __PASSES__
-# define __BACKGROUND_MIS__
-# define __LAMP_MIS__
-# define __AO__
-# define __CAMERA_MOTION__
-# define __OBJECT_MOTION__
-# define __HAIR__
-# ifdef __KERNEL_EXPERIMENTAL__
-# define __TRANSPARENT_SHADOWS__
-# endif
-#endif
-
-#ifdef __KERNEL_OPENCL_INTEL_CPU__
-# define __CL_USE_NATIVE__
-# define __KERNEL_SHADING__
-# define __KERNEL_ADV_SHADING__
-# ifdef __KERNEL_EXPERIMENTAL__
-# define __CMJ__
-# endif
-#endif
-
-#endif // __KERNEL_OPENCL__
+# ifdef __KERNEL_EXPERIMENTAL__
+# define __CMJ__
+# endif
+# endif /* __KERNEL_OPENCL_NVIDIA__ */
+
+# ifdef __KERNEL_OPENCL_AMD__
+# define __CL_USE_NATIVE__
+# define __KERNEL_SHADING__
+# define __MULTI_CLOSURE__
+# define __PASSES__
+# define __BACKGROUND_MIS__
+# define __LAMP_MIS__
+# define __AO__
+# define __CAMERA_MOTION__
+# define __OBJECT_MOTION__
+# define __HAIR__
+# ifdef __KERNEL_EXPERIMENTAL__
+# define __TRANSPARENT_SHADOWS__
+# endif
+# endif /* __KERNEL_OPENCL_AMD__ */
+
+# ifdef __KERNEL_OPENCL_INTEL_CPU__
+# define __CL_USE_NATIVE__
+# define __KERNEL_SHADING__
+# define __KERNEL_ADV_SHADING__
+# ifdef __KERNEL_EXPERIMENTAL__
+# define __CMJ__
+# endif
+# endif /* __KERNEL_OPENCL_INTEL_CPU__ */
+
+#endif /* __KERNEL_OPENCL__ */
/* kernel features */
#define __SOBOL__
@@ -156,30 +150,30 @@ CCL_NAMESPACE_BEGIN
#define __CLAMP_SAMPLE__
#ifdef __KERNEL_SHADING__
-#define __SVM__
-#define __EMISSION__
-#define __TEXTURES__
-#define __EXTRA_NODES__
-#define __HOLDOUT__
+# define __SVM__
+# define __EMISSION__
+# define __TEXTURES__
+# define __EXTRA_NODES__
+# define __HOLDOUT__
#endif
#ifdef __KERNEL_ADV_SHADING__
-#define __MULTI_CLOSURE__
-#define __TRANSPARENT_SHADOWS__
-#define __PASSES__
-#define __BACKGROUND_MIS__
-#define __LAMP_MIS__
-#define __AO__
-#define __CAMERA_MOTION__
-#define __OBJECT_MOTION__
-#define __HAIR__
+# define __MULTI_CLOSURE__
+# define __TRANSPARENT_SHADOWS__
+# define __PASSES__
+# define __BACKGROUND_MIS__
+# define __LAMP_MIS__
+# define __AO__
+# define __CAMERA_MOTION__
+# define __OBJECT_MOTION__
+# define __HAIR__
#endif
#ifdef WITH_CYCLES_DEBUG
# define __KERNEL_DEBUG__
#endif
-/* Scene-based selective featrues compilation/ */
+/* Scene-based selective featrues compilation. */
#ifdef __NO_CAMERA_MOTION__
# undef __CAMERA_MOTION__
#endif
@@ -189,6 +183,12 @@ CCL_NAMESPACE_BEGIN
#ifdef __NO_HAIR__
# undef __HAIR__
#endif
+#ifdef __NO_SUBSURFACE__
+# undef __SUBSURFACE__
+#endif
+#ifdef __NO_BRANCHED_PATH__
+# undef __BRANCHED_PATH__
+#endif
/* Random Numbers */
@@ -216,14 +216,10 @@ typedef enum ShaderEvalType {
SHADER_EVAL_AO,
SHADER_EVAL_COMBINED,
SHADER_EVAL_SHADOW,
- SHADER_EVAL_DIFFUSE_DIRECT,
- SHADER_EVAL_GLOSSY_DIRECT,
- SHADER_EVAL_TRANSMISSION_DIRECT,
- SHADER_EVAL_SUBSURFACE_DIRECT,
- SHADER_EVAL_DIFFUSE_INDIRECT,
- SHADER_EVAL_GLOSSY_INDIRECT,
- SHADER_EVAL_TRANSMISSION_INDIRECT,
- SHADER_EVAL_SUBSURFACE_INDIRECT,
+ SHADER_EVAL_DIFFUSE,
+ SHADER_EVAL_GLOSSY,
+ SHADER_EVAL_TRANSMISSION,
+ SHADER_EVAL_SUBSURFACE,
/* extra */
SHADER_EVAL_ENVIRONMENT,
@@ -266,7 +262,9 @@ enum PathTraceDimension {
enum SamplingPattern {
SAMPLING_PATTERN_SOBOL = 0,
- SAMPLING_PATTERN_CMJ = 1
+ SAMPLING_PATTERN_CMJ = 1,
+
+ SAMPLING_NUM_PATTERNS,
};
/* these flags values correspond to raytypes in osl.cpp, so keep them in sync!
@@ -353,6 +351,39 @@ typedef enum PassType {
#define PASS_ALL (~0)
+typedef enum BakePassFilter {
+ BAKE_FILTER_NONE = 0,
+ BAKE_FILTER_DIRECT = (1 << 0),
+ BAKE_FILTER_INDIRECT = (1 << 1),
+ BAKE_FILTER_COLOR = (1 << 2),
+ BAKE_FILTER_DIFFUSE = (1 << 3),
+ BAKE_FILTER_GLOSSY = (1 << 4),
+ BAKE_FILTER_TRANSMISSION = (1 << 5),
+ BAKE_FILTER_SUBSURFACE = (1 << 6),
+ BAKE_FILTER_EMISSION = (1 << 7),
+ BAKE_FILTER_AO = (1 << 8),
+} BakePassFilter;
+
+typedef enum BakePassFilterCombos {
+ BAKE_FILTER_COMBINED = (
+ BAKE_FILTER_DIRECT |
+ BAKE_FILTER_INDIRECT |
+ BAKE_FILTER_DIFFUSE |
+ BAKE_FILTER_GLOSSY |
+ BAKE_FILTER_TRANSMISSION |
+ BAKE_FILTER_SUBSURFACE |
+ BAKE_FILTER_EMISSION |
+ BAKE_FILTER_AO),
+ BAKE_FILTER_DIFFUSE_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_DIFFUSE),
+ BAKE_FILTER_GLOSSY_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_GLOSSY),
+ BAKE_FILTER_TRANSMISSION_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_TRANSMISSION),
+ BAKE_FILTER_SUBSURFACE_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_SUBSURFACE),
+ BAKE_FILTER_DIFFUSE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_DIFFUSE),
+ BAKE_FILTER_GLOSSY_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_GLOSSY),
+ BAKE_FILTER_TRANSMISSION_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_TRANSMISSION),
+ BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE),
+} BakePassFilterCombos;
+
#ifdef __PASSES__
typedef ccl_addr_space struct PathRadiance {
@@ -451,10 +482,12 @@ enum CameraType {
/* Panorama Type */
enum PanoramaType {
- PANORAMA_EQUIRECTANGULAR,
- PANORAMA_MIRRORBALL,
- PANORAMA_FISHEYE_EQUIDISTANT,
- PANORAMA_FISHEYE_EQUISOLID
+ PANORAMA_EQUIRECTANGULAR = 0,
+ PANORAMA_FISHEYE_EQUIDISTANT = 1,
+ PANORAMA_FISHEYE_EQUISOLID = 2,
+ PANORAMA_MIRRORBALL = 3,
+
+ PANORAMA_NUM_TYPES,
};
/* Differential */
@@ -593,7 +626,7 @@ typedef enum AttributeStandard {
# define MAX_CLOSURE __MAX_CLOSURE__
# endif
#else
-#define MAX_CLOSURE 1
+# define MAX_CLOSURE 1
#endif
/* This struct is to be 16 bytes aligned, we also keep some extra precautions:
@@ -611,7 +644,14 @@ typedef ccl_addr_space struct ShaderClosure {
float data0;
float data1;
float data2;
- int pad1, pad2, pad3;
+
+ /* Following fields could be used to store pre-calculated
+ * values by various BSDF closures for more effective sampling
+ * and evaluation.
+ */
+ float custom1;
+ float custom2;
+ float custom3;
#ifdef __OSL__
void *prim, *pad4;
@@ -687,22 +727,93 @@ enum ShaderDataFlag {
struct KernelGlobals;
#ifdef __SPLIT_KERNEL__
-#define SD_VAR(type, what) ccl_global type *what;
-#define SD_CLOSURE_VAR(type, what, max_closure) type *what;
-#define TIDX (get_global_id(1) * get_global_size(0) + get_global_id(0))
-#define ccl_fetch(s, t) (s->t[TIDX])
-#define ccl_fetch_array(s, t, index) (&s->t[TIDX * MAX_CLOSURE + index])
+# define SD_THREAD (get_global_id(1) * get_global_size(0) + get_global_id(0))
+# if defined(__SPLIT_KERNEL_AOS__)
+ /* ShaderData is stored as an Array-of-Structures */
+# define ccl_fetch(s, t) (s[SD_THREAD].t)
+# define ccl_fetch_array(s, t, index) (&s[SD_THREAD].t[index])
+# else
+ /* ShaderData is stored as an Structure-of-Arrays */
+# define SD_GLOBAL_SIZE (get_global_size(0) * get_global_size(1))
+# define SD_FIELD_SIZE(t) sizeof(((struct ShaderData*)0)->t)
+# define SD_OFFSETOF(t) ((char*)(&((struct ShaderData*)0)->t) - (char*)0)
+# define ccl_fetch(s, t) (((ShaderData*)((ccl_addr_space char*)s + SD_GLOBAL_SIZE * SD_OFFSETOF(t) + SD_FIELD_SIZE(t) * SD_THREAD - SD_OFFSETOF(t)))->t)
+# define ccl_fetch_array(s, t, index) (&ccl_fetch(s, t)[index])
+# endif
#else
-#define SD_VAR(type, what) type what;
-#define SD_CLOSURE_VAR(type, what, max_closure) type what[max_closure];
-#define ccl_fetch(s, t) (s->t)
-#define ccl_fetch_array(s, t, index) (&s->t[index])
+# define ccl_fetch(s, t) (s->t)
+# define ccl_fetch_array(s, t, index) (&s->t[index])
#endif
typedef ccl_addr_space struct ShaderData {
+ /* position */
+ float3 P;
+ /* smooth normal for shading */
+ float3 N;
+ /* true geometric normal */
+ float3 Ng;
+ /* view/incoming direction */
+ float3 I;
+ /* shader id */
+ int shader;
+ /* booleans describing shader, see ShaderDataFlag */
+ int flag;
-#include "kernel_shaderdata_vars.h"
+ /* primitive id if there is one, ~0 otherwise */
+ int prim;
+
+ /* combined type and curve segment for hair */
+ int type;
+
+ /* parametric coordinates
+ * - barycentric weights for triangles */
+ float u;
+ float v;
+ /* object id if there is one, ~0 otherwise */
+ int object;
+
+ /* motion blur sample time */
+ float time;
+
+ /* length of the ray being shaded */
+ float ray_length;
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differential of P. these are orthogonal to Ng, not N */
+ differential3 dP;
+ /* differential of I */
+ differential3 dI;
+ /* differential of u, v */
+ differential du;
+ differential dv;
+#endif
+#ifdef __DPDU__
+ /* differential of P w.r.t. parametric coordinates. note that dPdu is
+ * not readily suitable as a tangent for shading on triangles. */
+ float3 dPdu;
+ float3 dPdv;
+#endif
+#ifdef __OBJECT_MOTION__
+ /* object <-> world space transformations, cached to avoid
+ * re-interpolating them constantly for shading */
+ Transform ob_tfm;
+ Transform ob_itfm;
+#endif
+
+ /* Closure data, we store a fixed array of closures */
+ struct ShaderClosure closure[MAX_CLOSURE];
+ int num_closure;
+ float randb_closure;
+
+ /* ray start position, only set for backgrounds */
+ float3 ray_P;
+ differential3 ray_dP;
+
+#ifdef __OSL__
+ struct KernelGlobals * osl_globals;
+ struct PathState *osl_path_state;
+#endif
} ShaderData;
/* Path State */
@@ -716,7 +827,7 @@ typedef struct VolumeStack {
typedef struct PathState {
/* see enum PathRayFlag */
- int flag;
+ int flag;
/* random number generator state */
int rng_offset; /* dimension offset */
@@ -745,6 +856,33 @@ typedef struct PathState {
#endif
} PathState;
+/* Subsurface */
+
+/* Struct to gather multiple SSS hits. */
+struct SubsurfaceIntersection
+{
+ Ray ray;
+ float3 weight[BSSRDF_MAX_HITS];
+
+ int num_hits;
+ struct Intersection hits[BSSRDF_MAX_HITS];
+ float3 Ng[BSSRDF_MAX_HITS];
+};
+
+/* Struct to gather SSS indirect rays and delay tracing them. */
+struct SubsurfaceIndirectRays
+{
+ bool need_update_volume_stack;
+ bool tracing;
+ PathState state[BSSRDF_MAX_HITS];
+ struct PathRadiance direct_L;
+
+ int num_rays;
+ struct Ray rays[BSSRDF_MAX_HITS];
+ float3 throughputs[BSSRDF_MAX_HITS];
+ struct PathRadiance L[BSSRDF_MAX_HITS];
+};
+
/* Constant Kernel Data
*
* These structs are passed from CPU to various devices, and the struct layout
@@ -761,6 +899,11 @@ typedef struct KernelCamera {
float fisheye_lens;
float4 equirectangular_range;
+ /* stereo */
+ int pad1, pad2;
+ float interocular_offset;
+ float convergence_distance;
+
/* matrices */
Transform cameratoworld;
Transform rastertocamera;
@@ -813,6 +956,14 @@ typedef struct KernelCamera {
* Used for camera zoom motion blur,
*/
PerspectiveMotionTransform perspective_motion;
+
+ int shutter_table_offset;
+
+ /* Rolling shutter */
+ int rolling_shutter_type;
+ float rolling_shutter_duration;
+
+ int pad;
} KernelCamera;
typedef struct KernelFilm {
@@ -1025,34 +1176,50 @@ typedef ccl_addr_space struct DebugData {
/* Queue names */
enum QueueNumber {
- QUEUE_ACTIVE_AND_REGENERATED_RAYS = 0, /* All active rays and regenerated rays are enqueued here. */
- QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS = 1, /* All
- * 1. Background-hit rays,
- * 2. Rays that has exited path-iteration but needs to update output buffer
- * 3. Rays to be regenerated
- * are enqueued here.
- */
- QUEUE_SHADOW_RAY_CAST_AO_RAYS = 2, /* All rays for which a shadow ray should be cast to determine radiance
- * contribution for AO are enqueued here.
- */
- QUEUE_SHADOW_RAY_CAST_DL_RAYS = 3, /* All rays for which a shadow ray should be cast to determine radiance
- * contributing for direct lighting are enqueued here.
- */
+ /* All active rays and regenerated rays are enqueued here. */
+ QUEUE_ACTIVE_AND_REGENERATED_RAYS = 0,
+
+ /* All
+ * 1. Background-hit rays,
+ * 2. Rays that has exited path-iteration but needs to update output buffer
+ * 3. Rays to be regenerated
+ * are enqueued here.
+ */
+ QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS = 1,
+
+ /* All rays for which a shadow ray should be cast to determine radiance
+ * contribution for AO are enqueued here.
+ */
+ QUEUE_SHADOW_RAY_CAST_AO_RAYS = 2,
+
+ /* All rays for which a shadow ray should be cast to determine radiance
+ * contributing for direct lighting are enqueued here.
+ */
+ QUEUE_SHADOW_RAY_CAST_DL_RAYS = 3,
};
/* We use RAY_STATE_MASK to get ray_state (enums 0 to 5) */
#define RAY_STATE_MASK 0x007
#define RAY_FLAG_MASK 0x0F8
enum RayState {
- RAY_ACTIVE = 0, // Denotes ray is actively involved in path-iteration
- RAY_INACTIVE = 1, // Denotes ray has completed processing all samples and is inactive
- RAY_UPDATE_BUFFER = 2, // Denoted ray has exited path-iteration and needs to update output buffer
- RAY_HIT_BACKGROUND = 3, // Donotes ray has hit background
- RAY_TO_REGENERATE = 4, // Denotes ray has to be regenerated
- RAY_REGENERATED = 5, // Denotes ray has been regenerated
- RAY_SKIP_DL = 6, // Denotes ray should skip direct lighting
- RAY_SHADOW_RAY_CAST_AO = 16, // Flag's ray has to execute shadow blocked function in AO part
- RAY_SHADOW_RAY_CAST_DL = 32 // Flag's ray has to execute shadow blocked function in direct lighting part
+ /* Denotes ray is actively involved in path-iteration. */
+ RAY_ACTIVE = 0,
+ /* Denotes ray has completed processing all samples and is inactive. */
+ RAY_INACTIVE = 1,
+ /* Denoted ray has exited path-iteration and needs to update output buffer. */
+ RAY_UPDATE_BUFFER = 2,
+ /* Donotes ray has hit background */
+ RAY_HIT_BACKGROUND = 3,
+ /* Denotes ray has to be regenerated */
+ RAY_TO_REGENERATE = 4,
+ /* Denotes ray has been regenerated */
+ RAY_REGENERATED = 5,
+ /* Denotes ray should skip direct lighting */
+ RAY_SKIP_DL = 6,
+ /* Flag's ray has to execute shadow blocked function in AO part */
+ RAY_SHADOW_RAY_CAST_AO = 16,
+ /* Flag's ray has to execute shadow blocked function in direct lighting part. */
+ RAY_SHADOW_RAY_CAST_DL = 32,
};
#define ASSIGN_RAY_STATE(ray_state, ray_index, state) (ray_state[ray_index] = ((ray_state[ray_index] & RAY_FLAG_MASK) | state))
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 0a74a9deba9..c499773b980 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -39,7 +39,7 @@ typedef struct VolumeShaderCoefficients {
ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *sd, PathState *state, float3 P, float3 *extinction)
{
sd->P = P;
- shader_eval_volume(kg, sd, state->volume_stack, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
+ shader_eval_volume(kg, sd, state, state->volume_stack, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW);
if(!(sd->flag & (SD_ABSORPTION|SD_SCATTER)))
return false;
@@ -61,7 +61,7 @@ ccl_device bool volume_shader_extinction_sample(KernelGlobals *kg, ShaderData *s
ccl_device bool volume_shader_sample(KernelGlobals *kg, ShaderData *sd, PathState *state, float3 P, VolumeShaderCoefficients *coeff)
{
sd->P = P;
- shader_eval_volume(kg, sd, state->volume_stack, state->flag, SHADER_CONTEXT_VOLUME);
+ shader_eval_volume(kg, sd, state, state->volume_stack, state->flag, SHADER_CONTEXT_VOLUME);
if(!(sd->flag & (SD_ABSORPTION|SD_SCATTER|SD_EMISSION)))
return false;
@@ -222,7 +222,7 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, PathState
ccl_device_noinline void kernel_volume_shadow(KernelGlobals *kg, PathState *state, Ray *ray, float3 *throughput)
{
ShaderData sd;
- shader_setup_from_volume(kg, &sd, ray, state->bounce, state->transparent_bounce);
+ shader_setup_from_volume(kg, &sd, ray);
if(volume_stack_is_heterogeneous(kg, state->volume_stack))
kernel_volume_shadow_heterogeneous(kg, state, ray, &sd, throughput);
@@ -567,7 +567,7 @@ ccl_device_noinline VolumeIntegrateResult kernel_volume_integrate(KernelGlobals
* performance of rendering without volumes */
RNG tmp_rng = cmj_hash(*rng, state->rng_offset);
- shader_setup_from_volume(kg, sd, ray, state->bounce, state->transparent_bounce);
+ shader_setup_from_volume(kg, sd, ray);
if(heterogeneous)
return kernel_volume_integrate_heterogeneous_distance(kg, state, ray, sd, L, throughput, &tmp_rng);
@@ -750,7 +750,7 @@ ccl_device void kernel_volume_decoupled_free(KernelGlobals *kg, VolumeSegment *s
}
/* scattering for homogeneous and heterogeneous volumes, using decoupled ray
- * marching. this function does not do emission or modify throughput.
+ * marching.
*
* function is expected to return VOLUME_PATH_SCATTERED when probalistic_scatter is false */
ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
@@ -994,12 +994,14 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
int stack_index = 0, enclosed_index = 0;
+ const uint visibility = PATH_RAY_ALL_VISIBILITY | kernel_data.integrator.layer_flag;
#ifdef __VOLUME_RECORD_ALL__
Intersection hits[2*VOLUME_STACK_SIZE];
uint num_hits = scene_intersect_volume_all(kg,
&volume_ray,
hits,
- 2*VOLUME_STACK_SIZE);
+ 2*VOLUME_STACK_SIZE,
+ visibility);
if(num_hits > 0) {
int enclosed_volumes[VOLUME_STACK_SIZE];
Intersection *isect = hits;
@@ -1008,19 +1010,25 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray, 0, 0);
+ shader_setup_from_ray(kg, &sd, isect, &volume_ray);
if(sd.flag & SD_BACKFACING) {
- /* If ray exited the volume and never entered to that volume
- * it means that camera is inside such a volume.
- */
- bool is_enclosed = false;
- for(int i = 0; i < enclosed_index; ++i) {
+ bool need_add = true;
+ for(int i = 0; i < enclosed_index && need_add; ++i) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
if(enclosed_volumes[i] == sd.object) {
- is_enclosed = true;
+ need_add = false;
+ }
+ }
+ for(int i = 0; i < stack_index && need_add; ++i) {
+ /* Don't add intersections twice. */
+ if(stack[i].object == sd.object) {
+ need_add = false;
break;
}
}
- if(is_enclosed == false) {
+ if(need_add) {
stack[stack_index].object = sd.object;
stack[stack_index].shader = sd.shader;
++stack_index;
@@ -1043,24 +1051,33 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
step < 2 * VOLUME_STACK_SIZE)
{
Intersection isect;
- if(!scene_intersect_volume(kg, &volume_ray, &isect)) {
+ if(!scene_intersect_volume(kg, &volume_ray, &isect, visibility)) {
break;
}
ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray, 0, 0);
+ shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
if(sd.flag & SD_BACKFACING) {
/* If ray exited the volume and never entered to that volume
* it means that camera is inside such a volume.
*/
- bool is_enclosed = false;
- for(int i = 0; i < enclosed_index; ++i) {
+ bool need_add = true;
+ for(int i = 0; i < enclosed_index && need_add; ++i) {
+ /* If ray exited the volume and never entered to that volume
+ * it means that camera is inside such a volume.
+ */
if(enclosed_volumes[i] == sd.object) {
- is_enclosed = true;
+ need_add = false;
+ }
+ }
+ for(int i = 0; i < stack_index && need_add; ++i) {
+ /* Don't add intersections twice. */
+ if(stack[i].object == sd.object) {
+ need_add = false;
break;
}
}
- if(is_enclosed == false) {
+ if(need_add) {
stack[stack_index].object = sd.object;
stack[stack_index].shader = sd.shader;
++stack_index;
@@ -1149,12 +1166,13 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
Ray volume_ray = *ray;
-#ifdef __VOLUME_RECORD_ALL__
+# ifdef __VOLUME_RECORD_ALL__
Intersection hits[2*VOLUME_STACK_SIZE];
uint num_hits = scene_intersect_volume_all(kg,
&volume_ray,
hits,
- 2*VOLUME_STACK_SIZE);
+ 2*VOLUME_STACK_SIZE,
+ PATH_RAY_ALL_VISIBILITY);
if(num_hits > 0) {
Intersection *isect = hits;
@@ -1162,18 +1180,21 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
for(uint hit = 0; hit < num_hits; ++hit, ++isect) {
ShaderData sd;
- shader_setup_from_ray(kg, &sd, isect, &volume_ray, 0, 0);
+ shader_setup_from_ray(kg, &sd, isect, &volume_ray);
kernel_volume_stack_enter_exit(kg, &sd, stack);
}
}
-#else
+# else
Intersection isect;
int step = 0;
while(step < 2 * VOLUME_STACK_SIZE &&
- scene_intersect_volume(kg, &volume_ray, &isect))
+ scene_intersect_volume(kg,
+ &volume_ray,
+ &isect,
+ PATH_RAY_ALL_VISIBILITY))
{
ShaderData sd;
- shader_setup_from_ray(kg, &sd, &isect, &volume_ray, 0, 0);
+ shader_setup_from_ray(kg, &sd, &isect, &volume_ray);
kernel_volume_stack_enter_exit(kg, &sd, stack);
/* Move ray forward. */
@@ -1181,7 +1202,7 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg,
volume_ray.t -= sd.ray_length;
++step;
}
-#endif
+# endif
}
#endif
diff --git a/intern/cycles/kernel/kernel_work_stealing.h b/intern/cycles/kernel/kernel_work_stealing.h
index 9b83d972e97..7d559b1aa31 100644
--- a/intern/cycles/kernel/kernel_work_stealing.h
+++ b/intern/cycles/kernel/kernel_work_stealing.h
@@ -24,7 +24,7 @@
#ifdef __WORK_STEALING__
#ifdef __KERNEL_OPENCL__
-#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
+# pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
#endif
uint get_group_id_with_ray_index(uint ray_index,
diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp
index 2c8d3503c1a..45091f6f33d 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp
@@ -16,15 +16,47 @@
/* CPU kernel entry points */
-#include "kernel_compat_cpu.h"
+/* On x86-64, we can assume SSE2, so avoid the extra kernel and compile this
+ * one with SSE2 intrinsics.
+ */
+#if defined(__x86_64__) || defined(_M_X64)
+# define __KERNEL_SSE2__
+#endif
+
+/* When building kernel for native machine detect kernel features from the flags
+ * set by compiler.
+ */
+#ifdef WITH_KERNEL_NATIVE
+# ifdef __SSE2__
+# ifndef __KERNEL_SSE2__
+# define __KERNEL_SSE2__
+# endif
+# endif
+# ifdef __SSE3__
+# define __KERNEL_SSE3__
+# endif
+# ifdef __SSSE3__
+# define __KERNEL_SSSE3__
+# endif
+# ifdef __SSE4_1__
+# define __KERNEL_SSE41__
+# endif
+# ifdef __AVX__
+# define __KERNEL_AVX__
+# endif
+# ifdef __AVX2__
+# define __KERNEL_AVX2__
+# endif
+#endif
+
+/* quiet unused define warnings */
+#if defined(__KERNEL_SSE2__)
+ /* do nothing */
+#endif
+
#include "kernel.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_path_branched.h"
-#include "kernel_bake.h"
+#define KERNEL_ARCH cpu
+#include "kernel_cpu_impl.h"
CCL_NAMESPACE_BEGIN
@@ -94,49 +126,4 @@ void kernel_tex_copy(KernelGlobals *kg,
assert(0);
}
-/* On x86-64, we can assume SSE2, so avoid the extra kernel and compile this one with SSE2 intrinsics */
-#if defined(__x86_64__) || defined(_M_X64)
-#define __KERNEL_SSE2__
-#endif
-
-/* quiet unused define warnings */
-#if defined(__KERNEL_SSE2__)
- /* do nothing */
-#endif
-
-/* Path Tracing */
-
-void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride)
-{
-#ifdef __BRANCHED_PATH__
- if(kernel_data.integrator.branched)
- kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
- else
-#endif
- kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
-}
-
-/* Film */
-
-void kernel_cpu_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-void kernel_cpu_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-/* Shader Evaluation */
-
-void kernel_cpu_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i, int offset, int sample)
-{
- if(type >= SHADER_EVAL_BAKE)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, i, offset, sample);
- else
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i, sample);
-}
-
CCL_NAMESPACE_END
-
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
index df77bedc729..533ab46b741 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp
@@ -20,68 +20,17 @@
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
-#define __KERNEL_SSE2__
-#define __KERNEL_SSE3__
-#define __KERNEL_SSSE3__
-#define __KERNEL_SSE41__
-#define __KERNEL_AVX__
+# define __KERNEL_SSE2__
+# define __KERNEL_SSE3__
+# define __KERNEL_SSSE3__
+# define __KERNEL_SSE41__
+# define __KERNEL_AVX__
#endif
-
-#include "util_optimization.h"
-
-#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
-
-#include "kernel_compat_cpu.h"
-#include "kernel.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_path_branched.h"
-#include "kernel_bake.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Path Tracing */
-
-void kernel_cpu_avx_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride)
-{
-#ifdef __BRANCHED_PATH__
- if(kernel_data.integrator.branched)
- kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
- else
-#endif
- kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
-}
-/* Film */
-
-void kernel_cpu_avx_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-void kernel_cpu_avx_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-/* Shader Evaluate */
-
-void kernel_cpu_avx_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i, int offset, int sample)
-{
- if(type >= SHADER_EVAL_BAKE)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, i, offset, sample);
- else
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i, sample);
-}
-
-CCL_NAMESPACE_END
-#else
-
-/* needed for some linkers in combination with scons making empty compilation unit in a library */
-void __dummy_function_cycles_avx(void);
-void __dummy_function_cycles_avx(void) {}
+#include "util_optimization.h"
-#endif
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX
+# include "kernel.h"
+# define KERNEL_ARCH cpu_avx
+# include "kernel_cpu_impl.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
index b3192369794..7351e2bad6b 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_avx2.cpp
@@ -17,72 +17,21 @@
/* Optimized CPU kernel entry points. This file is compiled with AVX2
* optimization flags and nearly all functions inlined, while kernel.cpp
* is compiled without for other CPU's. */
-
+
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
-#define __KERNEL_SSE2__
-#define __KERNEL_SSE3__
-#define __KERNEL_SSSE3__
-#define __KERNEL_SSE41__
-#define __KERNEL_AVX__
-#define __KERNEL_AVX2__
+# define __KERNEL_SSE2__
+# define __KERNEL_SSE3__
+# define __KERNEL_SSSE3__
+# define __KERNEL_SSE41__
+# define __KERNEL_AVX__
+# define __KERNEL_AVX2__
#endif
-
-#include "util_optimization.h"
-
-#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
-
-#include "kernel_compat_cpu.h"
-#include "kernel.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_path_branched.h"
-#include "kernel_bake.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Path Tracing */
-
-void kernel_cpu_avx2_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride)
-{
-#ifdef __BRANCHED_PATH__
- if(kernel_data.integrator.branched)
- kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
- else
-#endif
- kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
-}
-
-/* Film */
-void kernel_cpu_avx2_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-void kernel_cpu_avx2_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-/* Shader Evaluate */
-
-void kernel_cpu_avx2_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i, int offset, int sample)
-{
- if(type >= SHADER_EVAL_BAKE)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, i, offset, sample);
- else
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i, sample);
-}
-
-CCL_NAMESPACE_END
-#else
-
-/* needed for some linkers in combination with scons making empty compilation unit in a library */
-void __dummy_function_cycles_avx2(void);
-void __dummy_function_cycles_avx2(void) {}
+#include "util_optimization.h"
-#endif
+#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
+# include "kernel.h"
+# define KERNEL_ARCH cpu_avx2
+# include "kernel_cpu_impl.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu.h
new file mode 100644
index 00000000000..1a07c705f1c
--- /dev/null
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Templated common declaration part of all CPU kernels. */
+
+void KERNEL_FUNCTION_FULL_NAME(path_trace)(KernelGlobals *kg,
+ float *buffer,
+ unsigned int *rng_state,
+ int sample,
+ int x, int y,
+ int offset,
+ int stride);
+
+void KERNEL_FUNCTION_FULL_NAME(convert_to_byte)(KernelGlobals *kg,
+ uchar4 *rgba,
+ float *buffer,
+ float sample_scale,
+ int x, int y,
+ int offset, int stride);
+
+void KERNEL_FUNCTION_FULL_NAME(convert_to_half_float)(KernelGlobals *kg,
+ uchar4 *rgba,
+ float *buffer,
+ float sample_scale,
+ int x, int y,
+ int offset,
+ int stride);
+
+void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg,
+ uint4 *input,
+ float4 *output,
+ float *output_luma,
+ int type,
+ int filter,
+ int i,
+ int offset,
+ int sample);
+
+#undef KERNEL_ARCH
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
new file mode 100644
index 00000000000..1454f925ab9
--- /dev/null
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Templated common implementation part of all CPU kernels.
+ *
+ * The idea is that particular .cpp files sets needed optimization flags and
+ * simply includes this file without worry of copying actual implementation over.
+ */
+
+#include "kernel_compat_cpu.h"
+#include "kernel_math.h"
+#include "kernel_types.h"
+#include "kernel_globals.h"
+#include "kernel_film.h"
+#include "kernel_path.h"
+#include "kernel_path_branched.h"
+#include "kernel_bake.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Path Tracing */
+
+void KERNEL_FUNCTION_FULL_NAME(path_trace)(KernelGlobals *kg,
+ float *buffer,
+ unsigned int *rng_state,
+ int sample,
+ int x, int y,
+ int offset,
+ int stride)
+{
+#ifdef __BRANCHED_PATH__
+ if(kernel_data.integrator.branched) {
+ kernel_branched_path_trace(kg,
+ buffer,
+ rng_state,
+ sample,
+ x, y,
+ offset,
+ stride);
+ }
+ else
+#endif
+ {
+ kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
+ }
+}
+
+/* Film */
+
+void KERNEL_FUNCTION_FULL_NAME(convert_to_byte)(KernelGlobals *kg,
+ uchar4 *rgba,
+ float *buffer,
+ float sample_scale,
+ int x, int y,
+ int offset,
+ int stride)
+{
+ kernel_film_convert_to_byte(kg,
+ rgba,
+ buffer,
+ sample_scale,
+ x, y,
+ offset,
+ stride);
+}
+
+void KERNEL_FUNCTION_FULL_NAME(convert_to_half_float)(KernelGlobals *kg,
+ uchar4 *rgba,
+ float *buffer,
+ float sample_scale,
+ int x, int y,
+ int offset,
+ int stride)
+{
+ kernel_film_convert_to_half_float(kg,
+ rgba,
+ buffer,
+ sample_scale,
+ x, y,
+ offset,
+ stride);
+}
+
+/* Shader Evaluate */
+
+void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg,
+ uint4 *input,
+ float4 *output,
+ float *output_luma,
+ int type,
+ int filter,
+ int i,
+ int offset,
+ int sample)
+{
+ if(type >= SHADER_EVAL_BAKE) {
+ kernel_assert(output_luma == NULL);
+ kernel_bake_evaluate(kg,
+ input,
+ output,
+ (ShaderEvalType)type,
+ filter,
+ i,
+ offset,
+ sample);
+ }
+ else {
+ kernel_shader_evaluate(kg,
+ input,
+ output,
+ output_luma,
+ (ShaderEvalType)type,
+ i,
+ sample);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp
index f9c5134e442..a5f2d6e7294 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_sse2.cpp
@@ -20,65 +20,13 @@
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
-#define __KERNEL_SSE2__
+# define __KERNEL_SSE2__
#endif
#include "util_optimization.h"
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
-
-#include "kernel_compat_cpu.h"
-#include "kernel.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_path_branched.h"
-#include "kernel_bake.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Path Tracing */
-
-void kernel_cpu_sse2_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride)
-{
-#ifdef __BRANCHED_PATH__
- if(kernel_data.integrator.branched)
- kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
- else
-#endif
- kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
-}
-
-/* Film */
-
-void kernel_cpu_sse2_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-void kernel_cpu_sse2_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-/* Shader Evaluate */
-
-void kernel_cpu_sse2_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i, int offset, int sample)
-{
- if(type >= SHADER_EVAL_BAKE)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, i, offset, sample);
- else
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i, sample);
-}
-
-CCL_NAMESPACE_END
-
-#else
-
-/* needed for some linkers in combination with scons making empty compilation unit in a library */
-void __dummy_function_cycles_sse2(void);
-void __dummy_function_cycles_sse2(void) {}
-
-#endif
+# include "kernel.h"
+# define KERNEL_ARCH cpu_sse2
+# include "kernel_cpu_impl.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE2 */
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp
index 2dbe4b81821..86f9ce991f8 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_sse3.cpp
@@ -20,66 +20,15 @@
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
-#define __KERNEL_SSE2__
-#define __KERNEL_SSE3__
-#define __KERNEL_SSSE3__
+# define __KERNEL_SSE2__
+# define __KERNEL_SSE3__
+# define __KERNEL_SSSE3__
#endif
#include "util_optimization.h"
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
-
-#include "kernel_compat_cpu.h"
-#include "kernel.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_path_branched.h"
-#include "kernel_bake.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Path Tracing */
-
-void kernel_cpu_sse3_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride)
-{
-#ifdef __BRANCHED_PATH__
- if(kernel_data.integrator.branched)
- kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
- else
-#endif
- kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
-}
-
-/* Film */
-
-void kernel_cpu_sse3_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-void kernel_cpu_sse3_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-/* Shader Evaluate */
-
-void kernel_cpu_sse3_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i, int offset, int sample)
-{
- if(type >= SHADER_EVAL_BAKE)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, i, offset, sample);
- else
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i, sample);
-}
-
-CCL_NAMESPACE_END
-#else
-
-/* needed for some linkers in combination with scons making empty compilation unit in a library */
-void __dummy_function_cycles_sse3(void);
-void __dummy_function_cycles_sse3(void) {}
-
-#endif
+# include "kernel.h"
+# define KERNEL_ARCH cpu_sse3
+# include "kernel_cpu_impl.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE3 */
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp b/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp
index 5c57ad01181..c174406047d 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp
+++ b/intern/cycles/kernel/kernels/cpu/kernel_sse41.cpp
@@ -20,67 +20,16 @@
/* SSE optimization disabled for now on 32 bit, see bug #36316 */
#if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
-#define __KERNEL_SSE2__
-#define __KERNEL_SSE3__
-#define __KERNEL_SSSE3__
-#define __KERNEL_SSE41__
+# define __KERNEL_SSE2__
+# define __KERNEL_SSE3__
+# define __KERNEL_SSSE3__
+# define __KERNEL_SSE41__
#endif
#include "util_optimization.h"
#ifdef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
-
-#include "kernel_compat_cpu.h"
-#include "kernel.h"
-#include "kernel_math.h"
-#include "kernel_types.h"
-#include "kernel_globals.h"
-#include "kernel_film.h"
-#include "kernel_path.h"
-#include "kernel_path_branched.h"
-#include "kernel_bake.h"
-
-CCL_NAMESPACE_BEGIN
-
-/* Path Tracing */
-
-void kernel_cpu_sse41_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride)
-{
-#ifdef __BRANCHED_PATH__
- if(kernel_data.integrator.branched)
- kernel_branched_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
- else
-#endif
- kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
-}
-
-/* Film */
-
-void kernel_cpu_sse41_convert_to_byte(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_byte(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-void kernel_cpu_sse41_convert_to_half_float(KernelGlobals *kg, uchar4 *rgba, float *buffer, float sample_scale, int x, int y, int offset, int stride)
-{
- kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
-}
-
-/* Shader Evaluate */
-
-void kernel_cpu_sse41_shader(KernelGlobals *kg, uint4 *input, float4 *output, int type, int i, int offset, int sample)
-{
- if(type >= SHADER_EVAL_BAKE)
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, i, offset, sample);
- else
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, i, sample);
-}
-
-CCL_NAMESPACE_END
-#else
-
-/* needed for some linkers in combination with scons making empty compilation unit in a library */
-void __dummy_function_cycles_sse41(void);
-void __dummy_function_cycles_sse41(void) {}
-
-#endif
+# include "kernel.h"
+# define KERNEL_ARCH cpu_sse41
+# include "kernel_cpu_impl.h"
+#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_SSE41 */
diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu
index bcd55b8c676..259b634f939 100644
--- a/intern/cycles/kernel/kernels/cuda/kernel.cu
+++ b/intern/cycles/kernel/kernels/cuda/kernel.cu
@@ -31,55 +31,67 @@
/* 2.0 and 2.1 */
#if __CUDA_ARCH__ == 200 || __CUDA_ARCH__ == 210
-#define CUDA_MULTIPRESSOR_MAX_REGISTERS 32768
-#define CUDA_MULTIPROCESSOR_MAX_BLOCKS 8
-#define CUDA_BLOCK_MAX_THREADS 1024
-#define CUDA_THREAD_MAX_REGISTERS 63
+# define CUDA_MULTIPRESSOR_MAX_REGISTERS 32768
+# define CUDA_MULTIPROCESSOR_MAX_BLOCKS 8
+# define CUDA_BLOCK_MAX_THREADS 1024
+# define CUDA_THREAD_MAX_REGISTERS 63
/* tunable parameters */
-#define CUDA_THREADS_BLOCK_WIDTH 16
-#define CUDA_KERNEL_MAX_REGISTERS 32
-#define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 40
+# define CUDA_THREADS_BLOCK_WIDTH 16
+# define CUDA_KERNEL_MAX_REGISTERS 32
+# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 40
/* 3.0 and 3.5 */
#elif __CUDA_ARCH__ == 300 || __CUDA_ARCH__ == 350
-#define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536
-#define CUDA_MULTIPROCESSOR_MAX_BLOCKS 16
-#define CUDA_BLOCK_MAX_THREADS 1024
-#define CUDA_THREAD_MAX_REGISTERS 63
+# define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536
+# define CUDA_MULTIPROCESSOR_MAX_BLOCKS 16
+# define CUDA_BLOCK_MAX_THREADS 1024
+# define CUDA_THREAD_MAX_REGISTERS 63
/* tunable parameters */
-#define CUDA_THREADS_BLOCK_WIDTH 16
-#define CUDA_KERNEL_MAX_REGISTERS 63
-#define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
+# define CUDA_THREADS_BLOCK_WIDTH 16
+# define CUDA_KERNEL_MAX_REGISTERS 63
+# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
/* 3.2 */
#elif __CUDA_ARCH__ == 320
-#define CUDA_MULTIPRESSOR_MAX_REGISTERS 32768
-#define CUDA_MULTIPROCESSOR_MAX_BLOCKS 16
-#define CUDA_BLOCK_MAX_THREADS 1024
-#define CUDA_THREAD_MAX_REGISTERS 63
+# define CUDA_MULTIPRESSOR_MAX_REGISTERS 32768
+# define CUDA_MULTIPROCESSOR_MAX_BLOCKS 16
+# define CUDA_BLOCK_MAX_THREADS 1024
+# define CUDA_THREAD_MAX_REGISTERS 63
/* tunable parameters */
-#define CUDA_THREADS_BLOCK_WIDTH 16
-#define CUDA_KERNEL_MAX_REGISTERS 63
-#define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
+# define CUDA_THREADS_BLOCK_WIDTH 16
+# define CUDA_KERNEL_MAX_REGISTERS 63
+# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
-/* 5.0 and 5.2 */
-#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520
-#define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536
-#define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32
-#define CUDA_BLOCK_MAX_THREADS 1024
-#define CUDA_THREAD_MAX_REGISTERS 255
+/* 3.7 */
+#elif __CUDA_ARCH__ == 370
+# define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536
+# define CUDA_MULTIPROCESSOR_MAX_BLOCKS 16
+# define CUDA_BLOCK_MAX_THREADS 1024
+# define CUDA_THREAD_MAX_REGISTERS 255
/* tunable parameters */
-#define CUDA_THREADS_BLOCK_WIDTH 16
-#define CUDA_KERNEL_MAX_REGISTERS 40
-#define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
+# define CUDA_THREADS_BLOCK_WIDTH 16
+# define CUDA_KERNEL_MAX_REGISTERS 63
+# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
+
+/* 5.0, 5.2 and 5.3 */
+#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 || __CUDA_ARCH__ == 530
+# define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536
+# define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32
+# define CUDA_BLOCK_MAX_THREADS 1024
+# define CUDA_THREAD_MAX_REGISTERS 255
+
+/* tunable parameters */
+# define CUDA_THREADS_BLOCK_WIDTH 16
+# define CUDA_KERNEL_MAX_REGISTERS 40
+# define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63
/* unknown architecture */
#else
-#error "Unknown or unsupported CUDA architecture, can't determine launch bounds"
+# error "Unknown or unsupported CUDA architecture, can't determine launch bounds"
#endif
/* compute number of threads per block and minimum blocks per multiprocessor
@@ -94,19 +106,19 @@
/* sanity checks */
#if CUDA_THREADS_BLOCK_WIDTH*CUDA_THREADS_BLOCK_WIDTH > CUDA_BLOCK_MAX_THREADS
-#error "Maximum number of threads per block exceeded"
+# error "Maximum number of threads per block exceeded"
#endif
#if CUDA_MULTIPRESSOR_MAX_REGISTERS/(CUDA_THREADS_BLOCK_WIDTH*CUDA_THREADS_BLOCK_WIDTH*CUDA_KERNEL_MAX_REGISTERS) > CUDA_MULTIPROCESSOR_MAX_BLOCKS
-#error "Maximum number of blocks per multiprocessor exceeded"
+# error "Maximum number of blocks per multiprocessor exceeded"
#endif
#if CUDA_KERNEL_MAX_REGISTERS > CUDA_THREAD_MAX_REGISTERS
-#error "Maximum number of registers per thread exceeded"
+# error "Maximum number of registers per thread exceeded"
#endif
#if CUDA_KERNEL_BRANCHED_MAX_REGISTERS > CUDA_THREAD_MAX_REGISTERS
-#error "Maximum number of registers per thread exceeded"
+# error "Maximum number of registers per thread exceeded"
#endif
/* kernels */
@@ -159,22 +171,36 @@ kernel_cuda_convert_to_half_float(uchar4 *rgba, float *buffer, float sample_scal
extern "C" __global__ void
CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS)
-kernel_cuda_shader(uint4 *input, float4 *output, int type, int sx, int sw, int offset, int sample)
+kernel_cuda_shader(uint4 *input,
+ float4 *output,
+ float *output_luma,
+ int type,
+ int sx,
+ int sw,
+ int offset,
+ int sample)
{
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
- if(x < sx + sw)
- kernel_shader_evaluate(NULL, input, output, (ShaderEvalType)type, x, sample);
+ if(x < sx + sw) {
+ kernel_shader_evaluate(NULL,
+ input,
+ output,
+ output_luma,
+ (ShaderEvalType)type,
+ x,
+ sample);
+ }
}
extern "C" __global__ void
CUDA_LAUNCH_BOUNDS(CUDA_THREADS_BLOCK_WIDTH, CUDA_KERNEL_MAX_REGISTERS)
-kernel_cuda_bake(uint4 *input, float4 *output, int type, int sx, int sw, int offset, int sample)
+kernel_cuda_bake(uint4 *input, float4 *output, int type, int filter, int sx, int sw, int offset, int sample)
{
int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
if(x < sx + sw)
- kernel_bake_evaluate(NULL, input, output, (ShaderEvalType)type, x, offset, sample);
+ kernel_bake_evaluate(NULL, input, output, (ShaderEvalType)type, filter, x, offset, sample);
}
#endif
diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl
index 57db6fd9098..aad06ed5c76 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel.cl
@@ -22,8 +22,25 @@
#include "../../kernel_globals.h"
#include "../../kernel_film.h"
-#include "../../kernel_path.h"
-#include "../../kernel_path_branched.h"
+
+#if defined(__COMPILE_ONLY_MEGAKERNEL__) || !defined(__NO_BAKING__)
+# include "../../kernel_path.h"
+# include "../../kernel_path_branched.h"
+#else /* __COMPILE_ONLY_MEGAKERNEL__ */
+/* Include only actually used headers for the case
+ * when path tracing kernels are not needed.
+ */
+# include "../../kernel_random.h"
+# include "../../kernel_differential.h"
+# include "../../kernel_montecarlo.h"
+# include "../../kernel_projection.h"
+# include "../../geom/geom.h"
+
+# include "../../kernel_accumulate.h"
+# include "../../kernel_camera.h"
+# include "../../kernel_shader.h"
+#endif /* defined(__COMPILE_ONLY_MEGAKERNEL__) || !defined(__NO_BAKING__) */
+
#include "../../kernel_bake.h"
#ifdef __COMPILE_ONLY_MEGAKERNEL__
@@ -55,12 +72,13 @@ __kernel void kernel_ocl_path_trace(
kernel_path_trace(kg, buffer, rng_state, sample, x, y, offset, stride);
}
-#else // __COMPILE_ONLY_MEGAKERNEL__
+#else /* __COMPILE_ONLY_MEGAKERNEL__ */
__kernel void kernel_ocl_shader(
ccl_constant KernelData *data,
ccl_global uint4 *input,
ccl_global float4 *output,
+ ccl_global float *output_luma,
#define KERNEL_TEX(type, ttype, name) \
ccl_global type *name,
@@ -78,8 +96,15 @@ __kernel void kernel_ocl_shader(
int x = sx + get_global_id(0);
- if(x < sx + sw)
- kernel_shader_evaluate(kg, input, output, (ShaderEvalType)type, x, sample);
+ if(x < sx + sw) {
+ kernel_shader_evaluate(kg,
+ input,
+ output,
+ output_luma,
+ (ShaderEvalType)type,
+ x,
+ sample);
+ }
}
__kernel void kernel_ocl_bake(
@@ -91,7 +116,7 @@ __kernel void kernel_ocl_bake(
ccl_global type *name,
#include "../../kernel_textures.h"
- int type, int sx, int sw, int offset, int sample)
+ int type, int filter, int sx, int sw, int offset, int sample)
{
KernelGlobals kglobals, *kg = &kglobals;
@@ -107,7 +132,7 @@ __kernel void kernel_ocl_bake(
#ifdef __NO_BAKING__
output[x] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
#else
- kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, x, offset, sample);
+ kernel_bake_evaluate(kg, input, output, (ShaderEvalType)type, filter, x, offset, sample);
#endif
}
}
@@ -166,4 +191,4 @@ __kernel void kernel_ocl_convert_to_half_float(
kernel_film_convert_to_half_float(kg, rgba, buffer, sample_scale, x, y, offset, stride);
}
-#endif // __COMPILE_ONLY_MEGAKERNEL__ \ No newline at end of file
+#endif /* __COMPILE_ONLY_MEGAKERNEL__ */
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl b/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl
index eff77b89a0a..1914d241eb1 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_background_buffer_update.cl
@@ -17,9 +17,8 @@
#include "split/kernel_background_buffer_update.h"
__kernel void kernel_ocl_path_trace_background_buffer_update(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_data,
ccl_global float *per_sample_output_buffers,
ccl_global uint *rng_state,
ccl_global uint *rng_coop, /* Required for buffer Update */
@@ -83,9 +82,7 @@ __kernel void kernel_ocl_path_trace_background_buffer_update(
if(ray_index != QUEUE_EMPTY_SLOT) {
#endif
enqueue_flag =
- kernel_background_buffer_update(globals,
- data,
- shader_data,
+ kernel_background_buffer_update((KernelGlobals *)kg,
per_sample_output_buffers,
rng_state,
rng_coop,
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl
index c3277676029..18139687eab 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_data_init.cl
@@ -18,96 +18,7 @@
__kernel void kernel_ocl_path_trace_data_init(
ccl_global char *globals,
- ccl_global char *shader_data_sd, /* Arguments related to ShaderData */
- ccl_global char *shader_data_sd_DL_shadow, /* Arguments related to ShaderData */
-
- ccl_global float3 *P_sd,
- ccl_global float3 *P_sd_DL_shadow,
-
- ccl_global float3 *N_sd,
- ccl_global float3 *N_sd_DL_shadow,
-
- ccl_global float3 *Ng_sd,
- ccl_global float3 *Ng_sd_DL_shadow,
-
- ccl_global float3 *I_sd,
- ccl_global float3 *I_sd_DL_shadow,
-
- ccl_global int *shader_sd,
- ccl_global int *shader_sd_DL_shadow,
-
- ccl_global int *flag_sd,
- ccl_global int *flag_sd_DL_shadow,
-
- ccl_global int *prim_sd,
- ccl_global int *prim_sd_DL_shadow,
-
- ccl_global int *type_sd,
- ccl_global int *type_sd_DL_shadow,
-
- ccl_global float *u_sd,
- ccl_global float *u_sd_DL_shadow,
-
- ccl_global float *v_sd,
- ccl_global float *v_sd_DL_shadow,
-
- ccl_global int *object_sd,
- ccl_global int *object_sd_DL_shadow,
-
- ccl_global float *time_sd,
- ccl_global float *time_sd_DL_shadow,
-
- ccl_global float *ray_length_sd,
- ccl_global float *ray_length_sd_DL_shadow,
-
- ccl_global int *ray_depth_sd,
- ccl_global int *ray_depth_sd_DL_shadow,
-
- ccl_global int *transparent_depth_sd,
- ccl_global int *transparent_depth_sd_DL_shadow,
-
- /* Ray differentials. */
- ccl_global differential3 *dP_sd,
- ccl_global differential3 *dP_sd_DL_shadow,
-
- ccl_global differential3 *dI_sd,
- ccl_global differential3 *dI_sd_DL_shadow,
-
- ccl_global differential *du_sd,
- ccl_global differential *du_sd_DL_shadow,
-
- ccl_global differential *dv_sd,
- ccl_global differential *dv_sd_DL_shadow,
-
- /* Dp/Du */
- ccl_global float3 *dPdu_sd,
- ccl_global float3 *dPdu_sd_DL_shadow,
-
- ccl_global float3 *dPdv_sd,
- ccl_global float3 *dPdv_sd_DL_shadow,
-
- /* Object motion. */
- ccl_global Transform *ob_tfm_sd,
- ccl_global Transform *ob_tfm_sd_DL_shadow,
-
- ccl_global Transform *ob_itfm_sd,
- ccl_global Transform *ob_itfm_sd_DL_shadow,
-
- ShaderClosure *closure_sd,
- ShaderClosure *closure_sd_DL_shadow,
-
- ccl_global int *num_closure_sd,
- ccl_global int *num_closure_sd_DL_shadow,
-
- ccl_global float *randb_closure_sd,
- ccl_global float *randb_closure_sd_DL_shadow,
-
- ccl_global float3 *ray_P_sd,
- ccl_global float3 *ray_P_sd_DL_shadow,
-
- ccl_global differential3 *ray_dP_sd,
- ccl_global differential3 *ray_dP_sd_DL_shadow,
-
+ ccl_global char *sd_DL_shadow,
ccl_constant KernelData *data,
ccl_global float *per_sample_output_buffers,
ccl_global uint *rng_state,
@@ -117,6 +28,7 @@ __kernel void kernel_ocl_path_trace_data_init(
PathRadiance *PathRadiance_coop, /* PathRadiance array to store PathRadiance values for all rays */
ccl_global Ray *Ray_coop, /* Ray array to store Ray information for all rays */
ccl_global PathState *PathState_coop, /* PathState array to store PathState information for all rays */
+ Intersection *Intersection_coop_shadow,
ccl_global char *ray_state, /* Stores information on current state of a ray */
#define KERNEL_TEX(type, ttype, name) \
@@ -141,72 +53,8 @@ __kernel void kernel_ocl_path_trace_data_init(
#endif
int parallel_samples) /* Number of samples to be processed in parallel */
{
- kernel_data_init(globals,
- shader_data_sd,
- shader_data_sd_DL_shadow,
- P_sd,
- P_sd_DL_shadow,
- N_sd,
- N_sd_DL_shadow,
- Ng_sd,
- Ng_sd_DL_shadow,
- I_sd,
- I_sd_DL_shadow,
- shader_sd,
- shader_sd_DL_shadow,
- flag_sd,
- flag_sd_DL_shadow,
- prim_sd,
- prim_sd_DL_shadow,
- type_sd,
- type_sd_DL_shadow,
- u_sd,
- u_sd_DL_shadow,
- v_sd,
- v_sd_DL_shadow,
- object_sd,
- object_sd_DL_shadow,
- time_sd,
- time_sd_DL_shadow,
- ray_length_sd,
- ray_length_sd_DL_shadow,
- ray_depth_sd,
- ray_depth_sd_DL_shadow,
- transparent_depth_sd,
- transparent_depth_sd_DL_shadow,
-
- /* Ray differentials. */
- dP_sd,
- dP_sd_DL_shadow,
- dI_sd,
- dI_sd_DL_shadow,
- du_sd,
- du_sd_DL_shadow,
- dv_sd,
- dv_sd_DL_shadow,
-
- /* Dp/Du */
- dPdu_sd,
- dPdu_sd_DL_shadow,
- dPdv_sd,
- dPdv_sd_DL_shadow,
-
- /* Object motion. */
- ob_tfm_sd,
- ob_tfm_sd_DL_shadow,
- ob_itfm_sd,
- ob_itfm_sd_DL_shadow,
-
- closure_sd,
- closure_sd_DL_shadow,
- num_closure_sd,
- num_closure_sd_DL_shadow,
- randb_closure_sd,
- randb_closure_sd_DL_shadow,
- ray_P_sd,
- ray_P_sd_DL_shadow,
- ray_dP_sd,
- ray_dP_sd_DL_shadow,
+ kernel_data_init((KernelGlobals *)globals,
+ (ShaderData *)sd_DL_shadow,
data,
per_sample_output_buffers,
rng_state,
@@ -216,6 +64,7 @@ __kernel void kernel_ocl_path_trace_data_init(
PathRadiance_coop,
Ray_coop,
PathState_coop,
+ Intersection_coop_shadow,
ray_state,
#define KERNEL_TEX(type, ttype, name) name,
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl b/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl
index 6ec75013b3a..c6a2c8d050c 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_direct_lighting.cl
@@ -17,10 +17,9 @@
#include "split/kernel_direct_lighting.h"
__kernel void kernel_ocl_path_trace_direct_lighting(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required for direct lighting */
- ccl_global char *shader_DL, /* Required for direct lighting */
+ ccl_global char *sd, /* Required for direct lighting */
ccl_global uint *rng_coop, /* Required for direct lighting */
ccl_global PathState *PathState_coop, /* Required for direct lighting */
ccl_global int *ISLamp_coop, /* Required for direct lighting */
@@ -61,10 +60,8 @@ __kernel void kernel_ocl_path_trace_direct_lighting(
#ifndef __COMPUTE_DEVICE_GPU__
if(ray_index != QUEUE_EMPTY_SLOT) {
#endif
- enqueue_flag = kernel_direct_lighting(globals,
- data,
- shader_data,
- shader_DL,
+ enqueue_flag = kernel_direct_lighting((KernelGlobals *)kg,
+ (ShaderData *)sd,
rng_coop,
PathState_coop,
ISLamp_coop,
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl b/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl
index ae5f5cd1b3b..e063614da1a 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_holdout_emission_blurring_pathtermination_ao.cl
@@ -17,9 +17,9 @@
#include "split/kernel_holdout_emission_blurring_pathtermination_ao.h"
__kernel void kernel_ocl_path_trace_holdout_emission_blurring_pathtermination_ao(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required throughout the kernel except probabilistic path termination and AO */
+ ccl_global char *sd, /* Required throughout the kernel except probabilistic path termination and AO */
ccl_global float *per_sample_output_buffers,
ccl_global uint *rng_coop, /* Required for "kernel_write_data_passes" and AO */
ccl_global float3 *throughput_coop, /* Required for handling holdout material and AO */
@@ -75,9 +75,8 @@ __kernel void kernel_ocl_path_trace_holdout_emission_blurring_pathtermination_ao
if(ray_index != QUEUE_EMPTY_SLOT) {
#endif
kernel_holdout_emission_blurring_pathtermination_ao(
- globals,
- data,
- shader_data,
+ (KernelGlobals *)kg,
+ (ShaderData *)sd,
per_sample_output_buffers,
rng_coop,
throughput_coop,
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl b/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl
index 1bc7808d834..267bddc2ffc 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_lamp_emission.cl
@@ -17,9 +17,8 @@
#include "split/kernel_lamp_emission.h"
__kernel void kernel_ocl_path_trace_lamp_emission(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required for lamp emission */
ccl_global float3 *throughput_coop, /* Required for lamp emission */
PathRadiance *PathRadiance_coop, /* Required for lamp emission */
ccl_global Ray *Ray_coop, /* Required for lamp emission */
@@ -61,16 +60,14 @@ __kernel void kernel_ocl_path_trace_lamp_emission(
return;
}
} else {
- if(x < (sw * parallel_samples) && y < sh){
+ if(x < (sw * parallel_samples) && y < sh) {
ray_index = x + y * (sw * parallel_samples);
} else {
return;
}
}
- kernel_lamp_emission(globals,
- data,
- shader_data,
+ kernel_lamp_emission((KernelGlobals *)kg,
throughput_coop,
PathRadiance_coop,
Ray_coop,
@@ -79,6 +76,5 @@ __kernel void kernel_ocl_path_trace_lamp_emission(
ray_state,
sw, sh,
use_queues_flag,
- parallel_samples,
ray_index);
}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl b/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl
index dcf4db40411..6d49b6294a8 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_next_iteration_setup.cl
@@ -17,9 +17,9 @@
#include "split/kernel_next_iteration_setup.h"
__kernel void kernel_ocl_path_trace_next_iteration_setup(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required for setting up ray for next iteration */
+ ccl_global char *sd, /* Required for setting up ray for next iteration */
ccl_global uint *rng_coop, /* Required for setting up ray for next iteration */
ccl_global float3 *throughput_coop, /* Required for setting up ray for next iteration */
PathRadiance *PathRadiance_coop, /* Required for setting up ray for next iteration */
@@ -83,9 +83,8 @@ __kernel void kernel_ocl_path_trace_next_iteration_setup(
#ifndef __COMPUTE_DEVICE_GPU__
if(ray_index != QUEUE_EMPTY_SLOT) {
#endif
- enqueue_flag = kernel_next_iteration_setup(globals,
- data,
- shader_data,
+ enqueue_flag = kernel_next_iteration_setup((KernelGlobals *)kg,
+ (ShaderData *)sd,
rng_coop,
throughput_coop,
PathRadiance_coop,
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl b/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl
index e5fad7bce50..7f3f433c7a6 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_scene_intersect.cl
@@ -17,7 +17,7 @@
#include "split/kernel_scene_intersect.h"
__kernel void kernel_ocl_path_trace_scene_intersect(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
ccl_global uint *rng_coop,
ccl_global Ray *Ray_coop, /* Required for scene_intersect */
@@ -58,15 +58,14 @@ __kernel void kernel_ocl_path_trace_scene_intersect(
return;
}
} else {
- if(x < (sw * parallel_samples) && y < sh){
+ if(x < (sw * parallel_samples) && y < sh) {
ray_index = x + y * (sw * parallel_samples);
} else {
return;
}
}
- kernel_scene_intersect(globals,
- data,
+ kernel_scene_intersect((KernelGlobals *)kg,
rng_coop,
Ray_coop,
PathState_coop,
@@ -77,6 +76,5 @@ __kernel void kernel_ocl_path_trace_scene_intersect(
#ifdef __KERNEL_DEBUG__
debugdata_coop,
#endif
- parallel_samples,
ray_index);
}
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl b/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl
index b9f616e6bdf..c37856c8f30 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_shader_eval.cl
@@ -17,9 +17,9 @@
#include "split/kernel_shader_eval.h"
__kernel void kernel_ocl_path_trace_shader_eval(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Output ShaderData structure to be filled */
+ ccl_global char *sd, /* Output ShaderData structure to be filled */
ccl_global uint *rng_coop, /* Required for rbsdf calculation */
ccl_global Ray *Ray_coop, /* Required for setting up shader from ray */
ccl_global PathState *PathState_coop, /* Required for all functions in this kernel */
@@ -57,9 +57,8 @@ __kernel void kernel_ocl_path_trace_shader_eval(
Queue_index);
/* Continue on with shader evaluation. */
- kernel_shader_eval(globals,
- data,
- shader_data,
+ kernel_shader_eval((KernelGlobals *)kg,
+ (ShaderData *)sd,
rng_coop,
Ray_coop,
PathState_coop,
diff --git a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl
index 03886c0a030..edf76fba714 100644
--- a/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl
+++ b/intern/cycles/kernel/kernels/opencl/kernel_shadow_blocked.cl
@@ -17,29 +17,16 @@
#include "split/kernel_shadow_blocked.h"
__kernel void kernel_ocl_path_trace_shadow_blocked(
- ccl_global char *globals,
+ ccl_global char *kg,
ccl_constant KernelData *data,
- ccl_global char *shader_shadow, /* Required for shadow blocked */
ccl_global PathState *PathState_coop, /* Required for shadow blocked */
ccl_global Ray *LightRay_dl_coop, /* Required for direct lighting's shadow blocked */
ccl_global Ray *LightRay_ao_coop, /* Required for AO's shadow blocked */
- Intersection *Intersection_coop_AO,
- Intersection *Intersection_coop_DL,
ccl_global char *ray_state,
ccl_global int *Queue_data, /* Queue memory */
ccl_global int *Queue_index, /* Tracks the number of elements in each queue */
- int queuesize, /* Size (capacity) of each queue */
- int total_num_rays)
+ int queuesize) /* Size (capacity) of each queue */
{
-#if 0
- /* We will make the Queue_index entries '0' in the next kernel. */
- if(get_global_id(0) == 0 && get_global_id(1) == 0) {
- /* We empty this queue here */
- Queue_index[QUEUE_SHADOW_RAY_CAST_AO_RAYS] = 0;
- Queue_index[QUEUE_SHADOW_RAY_CAST_DL_RAYS] = 0;
- }
-#endif
-
int lidx = get_local_id(1) * get_local_id(0) + get_local_id(0);
ccl_local unsigned int ao_queue_length;
@@ -68,16 +55,11 @@ __kernel void kernel_ocl_path_trace_shadow_blocked(
if(ray_index == QUEUE_EMPTY_SLOT)
return;
- kernel_shadow_blocked(globals,
- data,
- shader_shadow,
+ kernel_shadow_blocked((KernelGlobals *)kg,
PathState_coop,
LightRay_dl_coop,
LightRay_ao_coop,
- Intersection_coop_AO,
- Intersection_coop_DL,
ray_state,
- total_num_rays,
shadow_blocked_type,
ray_index);
}
diff --git a/intern/cycles/kernel/osl/SConscript b/intern/cycles/kernel/osl/SConscript
deleted file mode 100644
index 74ba5e1020c..00000000000
--- a/intern/cycles/kernel/osl/SConscript
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-defs = []
-incs = []
-cxxflags = Split(env['CXXFLAGS'])
-
-sources = env.Glob('*.cpp')
-
-incs.extend('. .. ../svm ../../render ../../util ../../device'.split())
-incs.append(env['BF_OIIO_INC'])
-incs.append(env['BF_BOOST_INC'])
-incs.append(env['BF_OSL_INC'])
-incs.append(env['BF_OPENEXR_INC'].split())
-incs.append('#/intern/atomic')
-
-defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
-defs.append('CCL_NAMESPACE_END=}')
-defs.append('WITH_OSL')
-
-if env['WITH_UNORDERED_MAP_SUPPORT']:
- if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
- if env['UNORDERED_MAP_NAMESPACE'] == 'std':
- defs.append('CYCLES_STD_UNORDERED_MAP')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('CYCLES_TR1_UNORDERED_MAP')
-else:
- print("-- Replacing unordered_map/set with map/set (warning: slower!)")
- defs.append('CYCLES_NO_UNORDERED_MAP')
-
-if env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-if env['WITH_BF_CYCLES_LOGGING']:
- defs.append('WITH_CYCLES_LOGGING')
- defs.append('GOOGLE_GLOG_DLL_DECL=')
- defs.append('CYCLES_GFLAGS_NAMESPACE=gflags')
- if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append('#extern/libmv/third_party/glog/src/windows')
- incs.append('#extern/libmv/third_party/gflags')
- else:
- incs.append('#extern/libmv/third_party/glog/src')
- incs.append('#extern/libmv/third_party/gflags')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- cxxflags.append('-DBOOST_NO_RTTI -DBOOST_NO_TYPEID /fp:fast'.split())
- incs.append(env['BF_PTHREADS_INC'])
- defs.append('OSL_STATIC_LIBRARY')
-else:
- cxxflags.append('-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID -ffast-math'.split())
-
-env.BlenderLib ('cycles_kernel_osl', sources, incs, defs, libtype=['intern'], priority=[10], cxx_compileflags=cxxflags)
diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp
index 2facced0914..85fa7b34bcc 100644
--- a/intern/cycles/kernel/osl/background.cpp
+++ b/intern/cycles/kernel/osl/background.cpp
@@ -77,8 +77,8 @@ public:
ClosureParam *closure_background_params()
{
static ClosureParam params[] = {
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(GenericBackgroundClosure)
+ CLOSURE_STRING_KEYPARAM(GenericBackgroundClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(GenericBackgroundClosure)
};
return params;
}
@@ -88,7 +88,7 @@ CCLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure)
ClosureParam *closure_holdout_params()
{
static ClosureParam params[] = {
- CLOSURE_FINISH_PARAM(HoldoutClosure)
+ CLOSURE_FINISH_PARAM(HoldoutClosure)
};
return params;
}
@@ -98,8 +98,8 @@ CCLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure)
ClosureParam *closure_ambient_occlusion_params()
{
static ClosureParam params[] = {
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(AmbientOcclusionClosure)
+ CLOSURE_STRING_KEYPARAM(AmbientOcclusionClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(AmbientOcclusionClosure)
};
return params;
}
diff --git a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
index 43929fbe928..b5c0d76cf37 100644
--- a/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_diffuse_ramp.cpp
@@ -93,8 +93,8 @@ ClosureParam *closure_bsdf_diffuse_ramp_params()
static ClosureParam params[] = {
CLOSURE_FLOAT3_PARAM(DiffuseRampClosure, sc.N),
CLOSURE_COLOR_ARRAY_PARAM(DiffuseRampClosure, colors, 8),
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(DiffuseRampClosure)
+ CLOSURE_STRING_KEYPARAM(DiffuseRampClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(DiffuseRampClosure)
};
return params;
}
diff --git a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
index 497c4f0dc5c..bc73d80cd78 100644
--- a/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
+++ b/intern/cycles/kernel/osl/bsdf_phong_ramp.cpp
@@ -93,8 +93,8 @@ ClosureParam *closure_bsdf_phong_ramp_params()
CLOSURE_FLOAT3_PARAM(PhongRampClosure, sc.N),
CLOSURE_FLOAT_PARAM(PhongRampClosure, sc.data0),
CLOSURE_COLOR_ARRAY_PARAM(PhongRampClosure, colors, 8),
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(PhongRampClosure)
+ CLOSURE_STRING_KEYPARAM(PhongRampClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(PhongRampClosure)
};
return params;
}
diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp
index 02935542c56..f91fd6e015c 100644
--- a/intern/cycles/kernel/osl/emissive.cpp
+++ b/intern/cycles/kernel/osl/emissive.cpp
@@ -77,8 +77,8 @@ public:
ClosureParam *closure_emission_params()
{
static ClosureParam params[] = {
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(GenericEmissiveClosure)
+ CLOSURE_STRING_KEYPARAM(GenericEmissiveClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(GenericEmissiveClosure)
};
return params;
}
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.cpp b/intern/cycles/kernel/osl/osl_bssrdf.cpp
index 88998037751..da4afb138f6 100644
--- a/intern/cycles/kernel/osl/osl_bssrdf.cpp
+++ b/intern/cycles/kernel/osl/osl_bssrdf.cpp
@@ -69,8 +69,8 @@ ClosureParam *closure_bssrdf_cubic_params()
CLOSURE_FLOAT3_PARAM(CubicBSSRDFClosure, radius),
CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, sc.data1),
CLOSURE_FLOAT_PARAM(CubicBSSRDFClosure, sc.T.x),
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(CubicBSSRDFClosure)
+ CLOSURE_STRING_KEYPARAM(CubicBSSRDFClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(CubicBSSRDFClosure)
};
return params;
}
@@ -97,13 +97,42 @@ ClosureParam *closure_bssrdf_gaussian_params()
CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, sc.N),
CLOSURE_FLOAT3_PARAM(GaussianBSSRDFClosure, radius),
CLOSURE_FLOAT_PARAM(GaussianBSSRDFClosure, sc.data1),
- CLOSURE_STRING_KEYPARAM("label"),
- CLOSURE_FINISH_PARAM(GaussianBSSRDFClosure)
+ CLOSURE_STRING_KEYPARAM(GaussianBSSRDFClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(GaussianBSSRDFClosure)
};
return params;
}
CCLOSURE_PREPARE(closure_bssrdf_gaussian_prepare, GaussianBSSRDFClosure)
+/* Burley */
+
+class BurleyBSSRDFClosure : public CBSSRDFClosure {
+public:
+ BurleyBSSRDFClosure()
+ {}
+
+ void setup()
+ {
+ sc.type = CLOSURE_BSSRDF_BURLEY_ID;
+ sc.data0 = fabsf(average(radius));
+ }
+};
+
+ClosureParam *closure_bssrdf_burley_params()
+{
+ static ClosureParam params[] = {
+ CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, sc.N),
+ CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, radius),
+ CLOSURE_FLOAT_PARAM(BurleyBSSRDFClosure, sc.data1),
+ CLOSURE_FLOAT3_PARAM(BurleyBSSRDFClosure, albedo),
+ CLOSURE_STRING_KEYPARAM(BurleyBSSRDFClosure, label, "label"),
+ CLOSURE_FINISH_PARAM(BurleyBSSRDFClosure)
+ };
+ return params;
+}
+
+CCLOSURE_PREPARE(closure_bssrdf_burley_prepare, BurleyBSSRDFClosure)
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_bssrdf.h b/intern/cycles/kernel/osl/osl_bssrdf.h
index 6aee2c28ea8..d81ecade543 100644
--- a/intern/cycles/kernel/osl/osl_bssrdf.h
+++ b/intern/cycles/kernel/osl/osl_bssrdf.h
@@ -49,6 +49,7 @@ class CBSSRDFClosure : public CClosurePrimitive {
public:
ShaderClosure sc;
float3 radius;
+ float3 albedo;
CBSSRDFClosure() : CClosurePrimitive(BSSRDF) { }
int scattering() const { return LABEL_DIFFUSE; }
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 461ce8f7598..95b8cea0922 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -236,6 +236,8 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
closure_bssrdf_cubic_params(), closure_bssrdf_cubic_prepare);
register_closure(ss, "bssrdf_gaussian", id++,
closure_bssrdf_gaussian_params(), closure_bssrdf_gaussian_prepare);
+ register_closure(ss, "bssrdf_burley", id++,
+ closure_bssrdf_burley_params(), closure_bssrdf_burley_prepare);
register_closure(ss, "hair_reflection", id++,
bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index ef67ef52fc0..1578d06cd56 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -50,6 +50,7 @@ OSL::ClosureParam *closure_bsdf_diffuse_ramp_params();
OSL::ClosureParam *closure_bsdf_phong_ramp_params();
OSL::ClosureParam *closure_bssrdf_cubic_params();
OSL::ClosureParam *closure_bssrdf_gaussian_params();
+OSL::ClosureParam *closure_bssrdf_burley_params();
OSL::ClosureParam *closure_henyey_greenstein_volume_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
@@ -60,6 +61,7 @@ void closure_bsdf_diffuse_ramp_prepare(OSL::RendererServices *, int id, void *da
void closure_bsdf_phong_ramp_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data);
void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data);
#define CCLOSURE_PREPARE(name, classname) \
@@ -72,7 +74,7 @@ void name(RendererServices *, int id, void *data) \
#define CCLOSURE_PREPARE_STATIC(name, classname) static CCLOSURE_PREPARE(name, classname)
#define CLOSURE_FLOAT3_PARAM(st, fld) \
- { TypeDesc::TypeVector, reckless_offsetof(st, fld), NULL, sizeof(OSL::Vec3) }
+ { TypeDesc::TypeVector, (int)reckless_offsetof(st, fld), NULL, sizeof(OSL::Vec3) }
#define TO_VEC3(v) OSL::Vec3(v.x, v.y, v.z)
#define TO_COLOR3(v) OSL::Color3(v.x, v.y, v.z)
@@ -97,6 +99,8 @@ public:
virtual void setup() {}
Category category;
+
+ OSL::ustring label;
};
/* BSDF */
@@ -175,8 +179,8 @@ static ClosureParam *bsdf_##lower##_params() \
/* parameters */
#define BSDF_CLOSURE_CLASS_END(Upper, lower) \
- CLOSURE_STRING_KEYPARAM("label"), \
- CLOSURE_FINISH_PARAM(Upper##Closure) \
+ CLOSURE_STRING_KEYPARAM(Upper##Closure, label, "label"), \
+ CLOSURE_FINISH_PARAM(Upper##Closure) \
}; \
return params; \
} \
@@ -223,8 +227,8 @@ static ClosureParam *volume_##lower##_params() \
/* parameters */
#define VOLUME_CLOSURE_CLASS_END(Upper, lower) \
- CLOSURE_STRING_KEYPARAM("label"), \
- CLOSURE_FINISH_PARAM(Upper##Closure) \
+ CLOSURE_STRING_KEYPARAM(Upper##Closure, label, "label"), \
+ CLOSURE_FINISH_PARAM(Upper##Closure) \
}; \
return params; \
} \
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index e349ac676b0..916542ec628 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -51,10 +51,10 @@ struct OSLGlobals {
OSLRenderServices *services;
/* shader states */
- vector<OSL::ShadingAttribStateRef> surface_state;
- vector<OSL::ShadingAttribStateRef> volume_state;
- vector<OSL::ShadingAttribStateRef> displacement_state;
- OSL::ShadingAttribStateRef background_state;
+ vector<OSL::ShaderGroupRef> surface_state;
+ vector<OSL::ShaderGroupRef> volume_state;
+ vector<OSL::ShaderGroupRef> displacement_state;
+ OSL::ShaderGroupRef background_state;
/* attributes */
struct Attribute {
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 3c1955a1e1e..03e7906378a 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -18,7 +18,7 @@
* here, so for now we just put here. In the future it might be better
* to have dedicated file for such tweaks.
*/
-#if defined(__GNUC__) && defined(NDEBUG)
+#if (defined(__GNUC__) && !defined(__clang__)) && defined(NDEBUG)
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
# pragma GCC diagnostic ignored "-Wuninitialized"
#endif
@@ -35,6 +35,7 @@
#include "osl_shader.h"
#include "util_foreach.h"
+#include "util_logging.h"
#include "util_string.h"
#include "kernel_compat_cpu.h"
@@ -52,7 +53,7 @@
#include "kernel_shader.h"
#ifdef WITH_PTEX
-#include <Ptexture.h>
+# include <Ptexture.h>
#endif
CCL_NAMESPACE_BEGIN
@@ -100,6 +101,7 @@ ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
ustring OSLRenderServices::u_path_transparent_depth("path:transparent_depth");
+ustring OSLRenderServices::u_path_transmission_depth("path:transmission_depth");
ustring OSLRenderServices::u_trace("trace");
ustring OSLRenderServices::u_hit("hit");
ustring OSLRenderServices::u_hitdist("hitdist");
@@ -124,6 +126,8 @@ OSLRenderServices::OSLRenderServices()
OSLRenderServices::~OSLRenderServices()
{
+ VLOG(2) << "OSL texture system stats:\n"
+ << osl_ts->getstats();
#ifdef WITH_PTEX
ptex_cache->release();
#endif
@@ -723,12 +727,20 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *
}
else if(name == u_path_ray_depth) {
/* Ray Depth */
- int f = sd->ray_depth;
+ PathState *state = sd->osl_path_state;
+ int f = state->bounce;
return set_attribute_int(f, type, derivatives, val);
}
else if(name == u_path_transparent_depth) {
/* Transparent Ray Depth */
- int f = sd->transparent_depth;
+ PathState *state = sd->osl_path_state;
+ int f = state->transparent_bounce;
+ return set_attribute_int(f, type, derivatives, val);
+ }
+ else if(name == u_path_transmission_depth) {
+ /* Transmission Ray Depth */
+ PathState *state = sd->osl_path_state;
+ int f = state->transmission_bounce;
return set_attribute_int(f, type, derivatives, val);
}
else if(name == u_ndc) {
@@ -840,15 +852,27 @@ bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, OSL::ShaderGlo
return false; /* never called by OSL */
}
-bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
+bool OSLRenderServices::texture(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
+ TextureOpt &options,
OSL::ShaderGlobals *sg,
- float s, float t, float dsdx, float dtdx,
- float dsdy, float dtdy, int nchannels, float *result)
+ float s, float t,
+ float dsdx, float dtdx, float dsdy, float dtdy,
+ int nchannels,
+ float *result,
+ float *dresultds,
+ float *dresultdt)
{
OSL::TextureSystem *ts = osl_ts;
ShaderData *sd = (ShaderData *)(sg->renderstate);
KernelGlobals *kg = sd->osl_globals;
+ if(texture_thread_info == NULL) {
+ OSLThreadData *tdata = kg->osl_tdata;
+ texture_thread_info = tdata->oiio_thread_info;
+ }
+
#ifdef WITH_PTEX
/* todo: this is just a quick hack, only works with particular files and options */
if(string_endswith(filename.string(), ".ptx")) {
@@ -902,20 +926,27 @@ bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
status = true;
}
else {
- OSLThreadData *tdata = kg->osl_tdata;
- OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
-
- OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
-
-#if OIIO_VERSION < 10500
- status = ts->texture(th, thread_info,
- options, s, t, dsdx, dtdx, dsdy, dtdy,
- result);
-#else
- status = ts->texture(th, thread_info,
- options, s, t, dsdx, dtdx, dsdy, dtdy,
- nchannels, result);
-#endif
+ if(texture_handle != NULL) {
+ status = ts->texture(texture_handle,
+ texture_thread_info,
+ options,
+ s, t,
+ dsdx, dtdx,
+ dsdy, dtdy,
+ nchannels,
+ result,
+ dresultds, dresultdt);
+ }
+ else {
+ status = ts->texture(filename,
+ options,
+ s, t,
+ dsdx, dtdx,
+ dsdy, dtdy,
+ nchannels,
+ result,
+ dresultds, dresultdt);
+ }
}
if(!status) {
@@ -927,19 +958,40 @@ bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
if(nchannels == 4)
result[3] = 1.0f;
}
+ /* This might be slow, but prevents error messages leak and
+ * other nasty stuff happening.
+ */
+ string err = ts->geterror();
+ (void)err;
}
return status;
}
-bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
- OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
- const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
- const OSL::Vec3 &dPdz, int nchannels, float *result)
+bool OSLRenderServices::texture3d(ustring filename,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
+ TextureOpt &options,
+ OSL::ShaderGlobals *sg,
+ const OSL::Vec3 &P,
+ const OSL::Vec3 &dPdx,
+ const OSL::Vec3 &dPdy,
+ const OSL::Vec3 &dPdz,
+ int nchannels,
+ float *result,
+ float *dresultds,
+ float *dresultdt,
+ float *dresultdr)
{
OSL::TextureSystem *ts = osl_ts;
ShaderData *sd = (ShaderData *)(sg->renderstate);
KernelGlobals *kg = sd->osl_globals;
+
+ if(texture_thread_info == NULL) {
+ OSLThreadData *tdata = kg->osl_tdata;
+ texture_thread_info = tdata->oiio_thread_info;
+ }
+
bool status;
if(filename[0] == '@') {
int slot = atoi(filename.c_str() + 1);
@@ -955,17 +1007,25 @@ bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
status = true;
}
else {
- OSLThreadData *tdata = kg->osl_tdata;
- OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
- OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
-#if OIIO_VERSION < 10500
- status = ts->texture3d(th, thread_info,
- options, P, dPdx, dPdy, dPdz, result);
-#else
- status = ts->texture3d(th, thread_info,
- options, P, dPdx, dPdy, dPdz,
- nchannels, result);
-#endif
+ if(texture_handle != NULL) {
+ status = ts->texture3d(texture_handle,
+ texture_thread_info,
+ options,
+ P,
+ dPdx, dPdy, dPdz,
+ nchannels,
+ result,
+ dresultds, dresultdt, dresultdr);
+ }
+ else {
+ status = ts->texture3d(filename,
+ options,
+ P,
+ dPdx, dPdy, dPdz,
+ nchannels,
+ result,
+ dresultds, dresultdt, dresultdr);
+ }
}
if(!status) {
@@ -977,7 +1037,11 @@ bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
if(nchannels == 4)
result[3] = 1.0f;
}
-
+ /* This might be slow, but prevents error messages leak and
+ * other nasty stuff happening.
+ */
+ string err = ts->geterror();
+ (void)err;
}
return status;
@@ -996,14 +1060,9 @@ bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
-#if OIIO_VERSION < 10500
- bool status = ts->environment(th, thread_info,
- options, R, dRdx, dRdy, result);
-#else
bool status = ts->environment(th, thread_info,
options, R, dRdx, dRdy,
nchannels, result);
-#endif
if(!status) {
if(nchannels == 3 || nchannels == 4) {
@@ -1115,11 +1174,7 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustri
if(!tracedata->setup) {
/* lazy shader data setup */
- ShaderData *original_sd = (ShaderData *)(sg->renderstate);
- int bounce = original_sd->ray_depth + 1;
- int transparent_bounce = original_sd->transparent_depth;
-
- shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, bounce, transparent_bounce);
+ shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray);
tracedata->setup = true;
}
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index cb6f2311ad8..2701abb483c 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -40,7 +40,6 @@ class Shader;
struct ShaderData;
struct float3;
struct KernelGlobals;
-
class OSLRenderServices : public OSL::RendererServices
{
public:
@@ -94,41 +93,21 @@ public:
bool getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
TypeDesc type, void *val, bool derivatives);
- bool texture(ustring filename, TextureOpt &options,
- OSL::ShaderGlobals *sg,
- float s, float t, float dsdx, float dtdx,
- float dsdy, float dtdy, int nchannels, float *result);
-
- bool texture3d(ustring filename, TextureOpt &options,
- OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
- const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
- const OSL::Vec3 &dPdz, int nchannels, float *result);
-
-#if OSL_LIBRARY_VERSION_CODE >= 10700
bool texture(ustring filename,
- TextureHandle * /*texture_handle*/,
- TexturePerthread * /*texture_thread_info*/,
+ TextureSystem::TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
TextureOpt &options,
OSL::ShaderGlobals *sg,
float s, float t,
float dsdx, float dtdx, float dsdy, float dtdy,
int nchannels,
float *result,
- float * /*dresultds*/,
- float * /*dresultdt*/)
- {
- return texture(filename,
- options,
- sg,
- s, t,
- dsdx, dtdx, dsdy, dtdy,
- nchannels,
- result);
- }
+ float *dresultds,
+ float *dresultdt);
bool texture3d(ustring filename,
- TextureHandle * /*texture_handle*/,
- TexturePerthread * /*texture_thread_info*/,
+ TextureHandle *texture_handle,
+ TexturePerthread *texture_thread_info,
TextureOpt &options,
OSL::ShaderGlobals *sg,
const OSL::Vec3 &P,
@@ -137,19 +116,9 @@ public:
const OSL::Vec3 &dPdz,
int nchannels,
float *result,
- float * /*dresultds*/,
- float * /*dresultdt*/,
- float * /*dresultdr*/)
- {
- return texture3d(filename,
- options,
- sg,
- P,
- dPdx, dPdy, dPdz,
- nchannels,
- result);
- }
-#endif
+ float *dresultds,
+ float *dresultdt,
+ float *dresultdr);
bool environment(ustring filename, TextureOpt &options,
OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
@@ -196,6 +165,7 @@ public:
static ustring u_path_ray_length;
static ustring u_path_ray_depth;
static ustring u_path_transparent_depth;
+ static ustring u_path_transmission_depth;
static ustring u_trace;
static ustring u_hit;
static ustring u_hitdist;
@@ -207,37 +177,6 @@ public:
static ustring u_v;
static ustring u_empty;
- /* Code to make OSL versions transition smooth. */
-
-#if OSL_LIBRARY_VERSION_CODE < 10600
- inline bool texture(ustring filename, TextureOpt &options,
- OSL::ShaderGlobals *sg,
- float s, float t, float dsdx, float dtdx,
- float dsdy, float dtdy, float *result)
- {
- return texture(filename, options, sg, s, t, dsdx, dtdx, dsdy, dtdy,
- options.nchannels, result);
- }
-
- inline bool texture3d(ustring filename, TextureOpt &options,
- OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
- const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
- const OSL::Vec3 &dPdz, float *result)
- {
- return texture3d(filename, options, sg, P, dPdx, dPdy, dPdz,
- options.nchannels, result);
- }
-
- inline bool environment(ustring filename, TextureOpt &options,
- OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
- const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy,
- float *result)
- {
- return environment(filename, options, sg, R, dRdx, dRdy,
- options.nchannels, result);
- }
-#endif
-
private:
KernelGlobals *kernel_globals;
OSL::TextureSystem *osl_ts;
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 8cfe0cbcbd4..f58368e6789 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -92,7 +92,7 @@ void OSLShader::thread_free(KernelGlobals *kg)
/* Globals */
-static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
+static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, PathState *state,
int path_flag, OSLThreadData *tdata)
{
OSL::ShaderGlobals *globals = &tdata->globals;
@@ -136,6 +136,7 @@ static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
/* used by renderservices */
sd->osl_globals = kg;
+ sd->osl_path_state = state;
}
/* Surface */
@@ -146,172 +147,186 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
/* OSL gives us a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */
- if(closure->type == OSL::ClosureColor::COMPONENT) {
- OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
- CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
+ switch(closure->id) {
+ case OSL::ClosureColor::MUL: {
+ OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
+ flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
+ break;
+ }
+ case OSL::ClosureColor::ADD: {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
+ flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
+ flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
+ break;
+ }
+ default: {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
+ CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if(prim) {
- ShaderClosure sc;
+ if(prim) {
+ ShaderClosure sc;
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- weight = weight*TO_FLOAT3(comp->w);
+ weight = weight*TO_FLOAT3(comp->w);
#endif
- sc.weight = weight;
+ sc.weight = weight;
- prim->setup();
+ prim->setup();
- switch (prim->category) {
- case CClosurePrimitive::BSDF: {
- CBSDFClosure *bsdf = (CBSDFClosure *)prim;
- int scattering = bsdf->scattering();
+ switch(prim->category) {
+ case CClosurePrimitive::BSDF: {
+ CBSDFClosure *bsdf = (CBSDFClosure *)prim;
+ int scattering = bsdf->scattering();
- /* caustic options */
- if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
- KernelGlobals *kg = sd->osl_globals;
+ /* caustic options */
+ if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) {
+ KernelGlobals *kg = sd->osl_globals;
- if((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
- (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT))) {
- return;
+ if((!kernel_data.integrator.caustics_reflective && (scattering & LABEL_REFLECT)) ||
+ (!kernel_data.integrator.caustics_refractive && (scattering & LABEL_TRANSMIT)))
+ {
+ return;
+ }
}
- }
- /* sample weight */
- float sample_weight = fabsf(average(weight));
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
- sc.sample_weight = sample_weight;
+ sc.sample_weight = sample_weight;
- sc.type = bsdf->sc.type;
- sc.N = bsdf->sc.N;
- sc.T = bsdf->sc.T;
- sc.data0 = bsdf->sc.data0;
- sc.data1 = bsdf->sc.data1;
- sc.data2 = bsdf->sc.data2;
- sc.prim = bsdf->sc.prim;
+ sc.type = bsdf->sc.type;
+ sc.N = bsdf->sc.N;
+ sc.T = bsdf->sc.T;
+ sc.data0 = bsdf->sc.data0;
+ sc.data1 = bsdf->sc.data1;
+ sc.data2 = bsdf->sc.data2;
+ sc.prim = bsdf->sc.prim;
- /* add */
- if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= bsdf->shaderdata_flag();
- }
- break;
- }
- case CClosurePrimitive::Emissive: {
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = CLOSURE_EMISSION_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.data2 = 0.0f;
- sc.prim = NULL;
-
- /* flag */
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_EMISSION;
- }
- break;
- }
- case CClosurePrimitive::AmbientOcclusion: {
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.data2 = 0.0f;
- sc.prim = NULL;
-
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_AO;
- }
- break;
- }
- case CClosurePrimitive::Holdout: {
- sc.sample_weight = 0.0f;
- sc.type = CLOSURE_HOLDOUT_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.data2 = 0.0f;
- sc.prim = NULL;
-
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_HOLDOUT;
+ /* add */
+ if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
+ sd->closure[sd->num_closure++] = sc;
+ sd->flag |= bsdf->shaderdata_flag();
+ }
+ break;
}
- break;
- }
- case CClosurePrimitive::BSSRDF: {
- CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
- float sample_weight = fabsf(average(weight));
+ case CClosurePrimitive::Emissive: {
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
- if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) {
sc.sample_weight = sample_weight;
-
- sc.type = bssrdf->sc.type;
- sc.N = bssrdf->sc.N;
- sc.data1 = bssrdf->sc.data1;
- sc.T.x = bssrdf->sc.T.x;
+ sc.type = CLOSURE_EMISSION_ID;
+ sc.data0 = 0.0f;
+ sc.data1 = 0.0f;
+ sc.data2 = 0.0f;
sc.prim = NULL;
- /* disable in case of diffuse ancestor, can't see it well then and
- * adds considerably noise due to probabilities of continuing path
- * getting lower and lower */
- if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
- bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f);
-
- /* create one closure for each color channel */
- if(fabsf(weight.x) > 0.0f) {
- sc.weight = make_float3(weight.x, 0.0f, 0.0f);
- sc.data0 = bssrdf->radius.x;
- sc.data1 = 0.0f;
- sd->flag |= bssrdf_setup(&sc, sc.type);
+ /* flag */
+ if(sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
+ sd->flag |= SD_EMISSION;
}
+ break;
+ }
+ case CClosurePrimitive::AmbientOcclusion: {
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
+
+ sc.sample_weight = sample_weight;
+ sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
+ sc.data0 = 0.0f;
+ sc.data1 = 0.0f;
+ sc.data2 = 0.0f;
+ sc.prim = NULL;
- if(fabsf(weight.y) > 0.0f) {
- sc.weight = make_float3(0.0f, weight.y, 0.0f);
- sc.data0 = bssrdf->radius.y;
- sc.data1 = 0.0f;
- sd->flag |= bssrdf_setup(&sc, sc.type);
+ if(sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
+ sd->flag |= SD_AO;
}
+ break;
+ }
+ case CClosurePrimitive::Holdout: {
+ sc.sample_weight = 0.0f;
+ sc.type = CLOSURE_HOLDOUT_ID;
+ sc.data0 = 0.0f;
+ sc.data1 = 0.0f;
+ sc.data2 = 0.0f;
+ sc.prim = NULL;
- if(fabsf(weight.z) > 0.0f) {
- sc.weight = make_float3(0.0f, 0.0f, weight.z);
- sc.data0 = bssrdf->radius.z;
- sc.data1 = 0.0f;
- sd->flag |= bssrdf_setup(&sc, sc.type);
+ if(sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
+ sd->flag |= SD_HOLDOUT;
+ }
+ break;
+ }
+ case CClosurePrimitive::BSSRDF: {
+ CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
+ float sample_weight = fabsf(average(weight));
+
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) {
+ sc.sample_weight = sample_weight;
+
+ sc.type = bssrdf->sc.type;
+ sc.N = bssrdf->sc.N;
+ sc.data1 = bssrdf->sc.data1;
+ sc.T.x = bssrdf->sc.T.x;
+ sc.prim = NULL;
+
+ /* disable in case of diffuse ancestor, can't see it well then and
+ * adds considerably noise due to probabilities of continuing path
+ * getting lower and lower */
+ if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
+ bssrdf->radius = make_float3(0.0f, 0.0f, 0.0f);
+
+ float3 albedo =
+ (bssrdf->sc.type == CLOSURE_BSSRDF_BURLEY_ID)
+ ? bssrdf->albedo
+ : make_float3(0.0f, 0.0f, 0.0f);
+
+ /* create one closure for each color channel */
+ if(fabsf(weight.x) > 0.0f) {
+ sc.weight = make_float3(weight.x, 0.0f, 0.0f);
+ sc.data0 = bssrdf->radius.x;
+ sc.data1 = 0.0f;
+ sc.data2 = albedo.x;
+ sd->flag |= bssrdf_setup(&sc, sc.type);
+ sd->closure[sd->num_closure++] = sc;
+ }
+
+ if(fabsf(weight.y) > 0.0f) {
+ sc.weight = make_float3(0.0f, weight.y, 0.0f);
+ sc.data0 = bssrdf->radius.y;
+ sc.data1 = 0.0f;
+ sc.data2 = albedo.y;
+ sd->flag |= bssrdf_setup(&sc, sc.type);
+ sd->closure[sd->num_closure++] = sc;
+ }
+
+ if(fabsf(weight.z) > 0.0f) {
+ sc.weight = make_float3(0.0f, 0.0f, weight.z);
+ sc.data0 = bssrdf->radius.z;
+ sc.data1 = 0.0f;
+ sc.data2 = albedo.z;
+ sd->flag |= bssrdf_setup(&sc, sc.type);
+ sd->closure[sd->num_closure++] = sc;
+ }
}
+ break;
}
- break;
+ case CClosurePrimitive::Background:
+ case CClosurePrimitive::Volume:
+ break; /* not relevant */
}
- case CClosurePrimitive::Background:
- case CClosurePrimitive::Volume:
- break; /* not relevant */
}
+ break;
}
}
- else if(closure->type == OSL::ClosureColor::MUL) {
- OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
- flatten_surface_closure_tree(sd, path_flag, mul->closure, TO_FLOAT3(mul->weight) * weight);
- }
- else if(closure->type == OSL::ClosureColor::ADD) {
- OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
- flatten_surface_closure_tree(sd, path_flag, add->closureA, weight);
- flatten_surface_closure_tree(sd, path_flag, add->closureB, weight);
- }
}
-void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
+void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx)
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
+ shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
/* execute shader for this point */
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
@@ -319,8 +334,9 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, int path_flag, S
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
- if(kg->osl->surface_state[shader])
- ss->execute(*octx, *(kg->osl->surface_state[shader]), *globals);
+ if(kg->osl->surface_state[shader]) {
+ ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
+ }
/* flatten closure tree */
if(globals->Ci)
@@ -335,45 +351,48 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
* is only one supported closure type at the moment, which has no evaluation
* functions, so we just sum the weights */
- if(closure->type == OSL::ClosureColor::COMPONENT) {
- OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
- CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
+ switch(closure->id) {
+ case OSL::ClosureColor::MUL: {
+ OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
+
+ return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
+ }
+ case OSL::ClosureColor::ADD: {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
+
+ return flatten_background_closure_tree(add->closureA) +
+ flatten_background_closure_tree(add->closureB);
+ }
+ default: {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
+ CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if(prim && prim->category == CClosurePrimitive::Background)
+ if(prim && prim->category == CClosurePrimitive::Background)
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- return TO_FLOAT3(comp->w);
+ return TO_FLOAT3(comp->w);
#else
- return make_float3(1.0f, 1.0f, 1.0f);
+ return make_float3(1.0f, 1.0f, 1.0f);
#endif
- }
- else if(closure->type == OSL::ClosureColor::MUL) {
- OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
-
- return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
- }
- else if(closure->type == OSL::ClosureColor::ADD) {
- OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
-
- return flatten_background_closure_tree(add->closureA) +
- flatten_background_closure_tree(add->closureB);
+ }
}
return make_float3(0.0f, 0.0f, 0.0f);
}
-float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
+float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx)
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
+ shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
/* execute shader for this point */
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSL::ShaderGlobals *globals = &tdata->globals;
OSL::ShadingContext *octx = tdata->context[(int)ctx];
- if(kg->osl->background_state)
- ss->execute(*octx, *(kg->osl->background_state), *globals);
+ if(kg->osl->background_state) {
+ ss->execute(octx, *(kg->osl->background_state), *globals);
+ }
/* return background color immediately */
if(globals->Ci)
@@ -390,83 +409,87 @@ static void flatten_volume_closure_tree(ShaderData *sd,
/* OSL gives us a closure tree, we flatten it into arrays per
* closure type, for evaluation, sampling, etc later on. */
- if(closure->type == OSL::ClosureColor::COMPONENT) {
- OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
- CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
+ switch(closure->id) {
+ case OSL::ClosureColor::MUL: {
+ OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
+ flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
+ break;
+ }
+ case OSL::ClosureColor::ADD: {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
+ flatten_volume_closure_tree(sd, add->closureA, weight);
+ flatten_volume_closure_tree(sd, add->closureB, weight);
+ break;
+ }
+ default: {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent *)closure;
+ CClosurePrimitive *prim = (CClosurePrimitive *)comp->data();
- if(prim) {
- ShaderClosure sc;
+ if(prim) {
+ ShaderClosure sc;
#ifdef OSL_SUPPORTS_WEIGHTED_CLOSURE_COMPONENTS
- weight = weight*TO_FLOAT3(comp->w);
+ weight = weight*TO_FLOAT3(comp->w);
#endif
- sc.weight = weight;
-
- prim->setup();
-
- switch (prim->category) {
- case CClosurePrimitive::Volume: {
- CVolumeClosure *volume = (CVolumeClosure *)prim;
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = volume->sc.type;
- sc.data0 = volume->sc.data0;
- sc.data1 = volume->sc.data1;
-
- /* add */
- if((sc.sample_weight > CLOSURE_WEIGHT_CUTOFF) &&
- (sd->num_closure < MAX_CLOSURE))
- {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= volume->shaderdata_flag();
+ sc.weight = weight;
+
+ prim->setup();
+
+ switch(prim->category) {
+ case CClosurePrimitive::Volume: {
+ CVolumeClosure *volume = (CVolumeClosure *)prim;
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
+
+ sc.sample_weight = sample_weight;
+ sc.type = volume->sc.type;
+ sc.data0 = volume->sc.data0;
+ sc.data1 = volume->sc.data1;
+
+ /* add */
+ if((sc.sample_weight > CLOSURE_WEIGHT_CUTOFF) &&
+ (sd->num_closure < MAX_CLOSURE))
+ {
+ sd->closure[sd->num_closure++] = sc;
+ sd->flag |= volume->shaderdata_flag();
+ }
+ break;
}
- break;
- }
- case CClosurePrimitive::Emissive: {
- /* sample weight */
- float sample_weight = fabsf(average(weight));
-
- sc.sample_weight = sample_weight;
- sc.type = CLOSURE_EMISSION_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.prim = NULL;
-
- /* flag */
- if(sd->num_closure < MAX_CLOSURE) {
- sd->closure[sd->num_closure++] = sc;
- sd->flag |= SD_EMISSION;
+ case CClosurePrimitive::Emissive: {
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
+
+ sc.sample_weight = sample_weight;
+ sc.type = CLOSURE_EMISSION_ID;
+ sc.data0 = 0.0f;
+ sc.data1 = 0.0f;
+ sc.prim = NULL;
+
+ /* flag */
+ if(sd->num_closure < MAX_CLOSURE) {
+ sd->closure[sd->num_closure++] = sc;
+ sd->flag |= SD_EMISSION;
+ }
+ break;
}
- break;
+ case CClosurePrimitive::Holdout:
+ break; /* not implemented */
+ case CClosurePrimitive::Background:
+ case CClosurePrimitive::BSDF:
+ case CClosurePrimitive::BSSRDF:
+ case CClosurePrimitive::AmbientOcclusion:
+ break; /* not relevant */
}
- case CClosurePrimitive::Holdout:
- break; /* not implemented */
- case CClosurePrimitive::Background:
- case CClosurePrimitive::BSDF:
- case CClosurePrimitive::BSSRDF:
- case CClosurePrimitive::AmbientOcclusion:
- break; /* not relevant */
}
}
}
- else if(closure->type == OSL::ClosureColor::MUL) {
- OSL::ClosureMul *mul = (OSL::ClosureMul *)closure;
- flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
- }
- else if(closure->type == OSL::ClosureColor::ADD) {
- OSL::ClosureAdd *add = (OSL::ClosureAdd *)closure;
- flatten_volume_closure_tree(sd, add->closureA, weight);
- flatten_volume_closure_tree(sd, add->closureB, weight);
- }
}
-void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx)
+void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx)
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, path_flag, tdata);
+ shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata);
/* execute shader */
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
@@ -474,8 +497,9 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, int path_flag, Sh
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
- if(kg->osl->volume_state[shader])
- ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
+ if(kg->osl->volume_state[shader]) {
+ ss->execute(octx, *(kg->osl->volume_state[shader]), *globals);
+ }
/* flatten closure tree */
if(globals->Ci)
@@ -488,7 +512,10 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte
{
/* setup shader globals from shader data */
OSLThreadData *tdata = kg->osl_tdata;
- shaderdata_to_shaderglobals(kg, sd, 0, tdata);
+
+ PathState state = {0};
+
+ shaderdata_to_shaderglobals(kg, sd, &state, 0, tdata);
/* execute shader */
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
@@ -496,8 +523,9 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
- if(kg->osl->displacement_state[shader])
- ss->execute(*octx, *(kg->osl->displacement_state[shader]), *globals);
+ if(kg->osl->displacement_state[shader]) {
+ ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals);
+ }
/* get back position */
sd->P = TO_FLOAT3(globals->P);
diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h
index 15dd74f9d38..7d26cd40da5 100644
--- a/intern/cycles/kernel/osl/osl_shader.h
+++ b/intern/cycles/kernel/osl/osl_shader.h
@@ -53,9 +53,9 @@ public:
static void thread_free(KernelGlobals *kg);
/* eval */
- static void eval_surface(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx);
- static float3 eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx);
- static void eval_volume(KernelGlobals *kg, ShaderData *sd, int path_flag, ShaderContext ctx);
+ static void eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
+ static float3 eval_background(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
+ static void eval_volume(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, ShaderContext ctx);
static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx);
/* sample & eval */
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 81931463cad..49030f33c26 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -102,8 +102,8 @@ foreach(_file ${SRC_OSL})
string(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} _OSO_FILE ${_OSO_FILE})
add_custom_command(
OUTPUT ${_OSO_FILE}
- COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" ${_OSL_FILE}
- DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS})
+ COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" -o ${_OSO_FILE} ${_OSL_FILE}
+ DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS} ${OSL_COMPILER})
list(APPEND SRC_OSO
${_OSO_FILE}
)
@@ -112,7 +112,7 @@ foreach(_file ${SRC_OSL})
unset(_OSO_FILE)
endforeach()
-add_custom_target(cycles_osl_shaders ALL DEPENDS ${SRC_OSO} ${SRC_OSL_HEADERS})
+add_custom_target(cycles_osl_shaders ALL DEPENDS ${SRC_OSO} ${SRC_OSL_HEADERS} ${OSL_COMPILER})
# CMAKE_CURRENT_SOURCE_DIR is already included in OSO paths
delayed_install("" "${SRC_OSO}" ${CYCLES_INSTALL_PATH}/shader)
diff --git a/intern/cycles/kernel/shaders/SConscript b/intern/cycles/kernel/shaders/SConscript
deleted file mode 100644
index 8bc1c2206e0..00000000000
--- a/intern/cycles/kernel/shaders/SConscript
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-import os
-import Blender as B
-
-def normpath(path):
- return os.path.abspath(os.path.normpath(path))
-
-Import ('env')
-
-oso_files = []
-
-if env['WITH_BF_CYCLES_OSL']:
- shaders = env.Clone()
-
- # osl compiler
- osl_compiler = File(env.subst(env['BF_OSL_COMPILER'])).abspath
-
- # build directory
- root_build_dir = normpath(env['BF_BUILDDIR'])
- build_dir = os.path.join(root_build_dir, 'intern/cycles/kernel/shaders')
-
- # source directories and files
- source_dir = Dir('.').srcnode().path
-
- # dependencies
- dependencies = shaders.Glob('*.h')
-
- for f in os.listdir(source_dir):
- if f.endswith('.osl'):
- osl_file = os.path.join(source_dir, f)
- oso_file = os.path.join(build_dir, f.replace('.osl', '.oso'))
-
- command = "\"%s\" -q -O2 -I\"%s\" -o \"%s\" \"%s\"" % (osl_compiler, source_dir, oso_file, osl_file)
-
- shaders.Command(oso_file, f, command)
- shaders.Depends(oso_file, [f] + dependencies)
-
- oso_files.append(oso_file)
-
-
-Return('oso_files')
diff --git a/intern/cycles/kernel/shaders/node_environment_texture.osl b/intern/cycles/kernel/shaders/node_environment_texture.osl
index 14f0226a0e5..3a0b782c98e 100644
--- a/intern/cycles/kernel/shaders/node_environment_texture.osl
+++ b/intern/cycles/kernel/shaders/node_environment_texture.osl
@@ -45,6 +45,7 @@ shader node_environment_texture(
vector Vector = P,
string filename = "",
string projection = "Equirectangular",
+ string interpolation = "linear",
string color_space = "sRGB",
int is_float = 1,
int use_alpha = 1,
@@ -64,7 +65,7 @@ shader node_environment_texture(
p = environment_texture_direction_to_mirrorball(p);
/* todo: use environment for better texture filtering of equirectangular */
- Color = (color)texture(filename, p[0], 1.0 - p[1], "wrap", "periodic", "alpha", Alpha);
+ Color = (color)texture(filename, p[0], 1.0 - p[1], "wrap", "periodic", "interp", interpolation, "alpha", Alpha);
if (use_alpha) {
Color = color_unpremultiply(Color, Alpha);
diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/shaders/node_light_path.osl
index 99a92c4f403..a021a40467d 100644
--- a/intern/cycles/kernel/shaders/node_light_path.osl
+++ b/intern/cycles/kernel/shaders/node_light_path.osl
@@ -27,7 +27,8 @@ shader node_light_path(
output float IsVolumeScatterRay = 0.0,
output float RayLength = 0.0,
output float RayDepth = 0.0,
- output float TransparentDepth = 0.0)
+ output float TransparentDepth = 0.0,
+ output float TransmissionDepth = 0.0)
{
IsCameraRay = raytype("camera");
IsShadowRay = raytype("shadow");
@@ -47,5 +48,9 @@ shader node_light_path(
int transparent_depth;
getattribute("path:transparent_depth", transparent_depth);
TransparentDepth = (float)transparent_depth;
+
+ int transmission_depth;
+ getattribute("path:transmission_depth", transmission_depth);
+ TransmissionDepth = (float)transmission_depth;
}
diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl
index c09523f205b..55992e3494c 100644
--- a/intern/cycles/kernel/shaders/node_magic_texture.osl
+++ b/intern/cycles/kernel/shaders/node_magic_texture.osl
@@ -97,6 +97,7 @@ shader node_magic_texture(
float Distortion = 5.0,
float Scale = 5.0,
point Vector = P,
+ output float Fac = 0.0,
output color Color = 0.0)
{
point p = Vector;
@@ -105,5 +106,6 @@ shader node_magic_texture(
p = transform(mapping, p);
Color = magic(p * Scale, Depth, Distortion);
+ Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
}
diff --git a/intern/cycles/kernel/shaders/node_rgb_curves.osl b/intern/cycles/kernel/shaders/node_rgb_curves.osl
index 60cb273ba98..fc93dbd044b 100644
--- a/intern/cycles/kernel/shaders/node_rgb_curves.osl
+++ b/intern/cycles/kernel/shaders/node_rgb_curves.osl
@@ -19,6 +19,21 @@
float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
{
+ if (at < 0.0 || at > 1.0) {
+ float t0, dy;
+ if (at < 0.0) {
+ t0 = ramp[0][component];
+ dy = t0 - ramp[1][component];
+ at = -at;
+ }
+ else {
+ t0 = ramp[RAMP_TABLE_SIZE - 1][component];
+ dy = t0 - ramp[RAMP_TABLE_SIZE - 2][component];
+ at = at - 1.0;
+ }
+ return t0 + dy * at * (RAMP_TABLE_SIZE - 1);
+ }
+
float f = clamp(at, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
/* clamp int as well in case of NaN */
@@ -37,14 +52,18 @@ float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
shader node_rgb_curves(
color ramp[RAMP_TABLE_SIZE] = {0.0},
+ float min_x = 0.0,
+ float max_x = 1.0,
color ColorIn = 0.0,
float Fac = 0.0,
output color ColorOut = 0.0)
{
- ColorOut[0] = ramp_lookup(ramp, ColorIn[0], 0);
- ColorOut[1] = ramp_lookup(ramp, ColorIn[1], 1);
- ColorOut[2] = ramp_lookup(ramp, ColorIn[2], 2);
+ color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x);
+
+ ColorOut[0] = ramp_lookup(ramp, c[0], 0);
+ ColorOut[1] = ramp_lookup(ramp, c[1], 1);
+ ColorOut[2] = ramp_lookup(ramp, c[2], 2);
ColorOut = mix(ColorIn, ColorOut, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
index dbbf657776c..a67333c5d4e 100644
--- a/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
+++ b/intern/cycles/kernel/shaders/node_subsurface_scattering.osl
@@ -27,8 +27,10 @@ shader node_subsurface_scattering(
output closure color BSSRDF = 0)
{
if (Falloff == "Gaussian")
- BSSRDF = Color * bssrdf_gaussian(N, Scale * Radius, TextureBlur);
+ BSSRDF = Color * bssrdf_gaussian(Normal, Scale * Radius, TextureBlur);
+ else if (Falloff == "Cubic")
+ BSSRDF = Color * bssrdf_cubic(Normal, Scale * Radius, TextureBlur, Sharpness);
else
- BSSRDF = Color * bssrdf_cubic(N, Scale * Radius, TextureBlur, Sharpness);
+ BSSRDF = Color * bssrdf_burley(Normal, Scale * Radius, TextureBlur, Color);
}
diff --git a/intern/cycles/kernel/shaders/node_vector_curves.osl b/intern/cycles/kernel/shaders/node_vector_curves.osl
index 7bbf97d95ea..4d4c28b57a2 100644
--- a/intern/cycles/kernel/shaders/node_vector_curves.osl
+++ b/intern/cycles/kernel/shaders/node_vector_curves.osl
@@ -19,7 +19,22 @@
float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
{
- float f = clamp((at + 1.0) * 0.5, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
+ if (at < 0.0 || at > 1.0) {
+ float t0, dy;
+ if (at < 0.0) {
+ t0 = ramp[0][component];
+ dy = t0 - ramp[1][component];
+ at = -at;
+ }
+ else {
+ t0 = ramp[RAMP_TABLE_SIZE - 1][component];
+ dy = t0 - ramp[RAMP_TABLE_SIZE - 2][component];
+ at = at - 1.0;
+ }
+ return t0 + dy * at * (RAMP_TABLE_SIZE - 1);
+ }
+
+ float f = clamp(at, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
/* clamp int as well in case of NaN */
int i = (int)f;
@@ -32,19 +47,23 @@ float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
if (t > 0.0)
result = (1.0 - t) * result + t * ramp[i + 1][component];
- return result * 2.0 - 1.0;
+ return result;
}
shader node_vector_curves(
color ramp[RAMP_TABLE_SIZE] = {0.0},
+ float min_x = 0.0,
+ float max_x = 1.0,
vector VectorIn = vector(0.0, 0.0, 0.0),
float Fac = 0.0,
output vector VectorOut = vector(0.0, 0.0, 0.0))
{
- VectorOut[0] = ramp_lookup(ramp, VectorIn[0], 0);
- VectorOut[1] = ramp_lookup(ramp, VectorIn[1], 1);
- VectorOut[2] = ramp_lookup(ramp, VectorIn[2], 2);
+ vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x);
+
+ VectorOut[0] = ramp_lookup(ramp, c[0], 0);
+ VectorOut[1] = ramp_lookup(ramp, c[1], 1);
+ VectorOut[2] = ramp_lookup(ramp, c[2], 2);
VectorOut = mix(VectorIn, VectorOut, Fac);
}
diff --git a/intern/cycles/kernel/shaders/node_voxel_texture.osl b/intern/cycles/kernel/shaders/node_voxel_texture.osl
index e45af62220f..9253febd64a 100644
--- a/intern/cycles/kernel/shaders/node_voxel_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voxel_texture.osl
@@ -35,8 +35,8 @@ shader node_voxel_texture(
if (getattribute("geom:generated_transform", tfm))
p = transform(tfm, p);
}
- if(p[0] < 0.0 || p[1] < 0.0 || p[2] < 0.0 ||
- p[0] > 1.0 || p[1] > 1.0 || p[2] > 1.0)
+ if (p[0] < 0.0 || p[1] < 0.0 || p[2] < 0.0 ||
+ p[0] > 1.0 || p[1] > 1.0 || p[2] > 1.0)
{
Density = 0;
Color = color(0, 0, 0);
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index 569f284cbac..59f61d3b46a 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -19,7 +19,7 @@
/* Wave */
-float wave(point p, string type, float detail, float distortion, float dscale)
+float wave(point p, string type, string profile, float detail, float distortion, float dscale)
{
float n = 0.0;
@@ -33,13 +33,23 @@ float wave(point p, string type, float detail, float distortion, float dscale)
if (distortion != 0.0) {
n = n + (distortion * noise_turbulence(p * dscale, detail, 0));
}
- return 0.5 + 0.5 * sin(n);
+
+ if (profile == "Sine") {
+ return 0.5 + 0.5 * sin(n);
+ }
+ else {
+ /* Saw profile */
+ n /= M_2PI;
+ n -= (int) n;
+ return (n < 0.0) ? n + 1.0 : n;
+ }
}
shader node_wave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
string Type = "Bands",
+ string Profile = "Sine",
float Scale = 5.0,
float Distortion = 0.0,
float Detail = 2.0,
@@ -53,7 +63,7 @@ shader node_wave_texture(
if (use_mapping)
p = transform(mapping, p);
- Fac = wave(p * Scale, Type, Detail, Distortion, DetailScale);
+ Fac = wave(p * Scale, Type, Profile, Detail, Distortion, DetailScale);
Color = Fac;
}
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index 697a1756119..8d5d3746caf 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -433,6 +433,35 @@ normal step (normal edge, normal x) BUILTIN;
float step (float edge, float x) BUILTIN;
float smoothstep (float edge0, float edge1, float x) BUILTIN;
+float linearstep (float edge0, float edge1, float x) {
+ float result;
+ if (edge0 != edge1) {
+ float xclamped = clamp (x, edge0, edge1);
+ result = (xclamped - edge0) / (edge1 - edge0);
+ } else { // special case: edges coincide
+ result = step (edge0, x);
+ }
+ return result;
+}
+
+float smooth_linearstep (float edge0, float edge1, float x_, float eps_) {
+ float result;
+ if (edge0 != edge1) {
+ float rampup (float x, float r) { return 0.5/r * x*x; }
+ float width_inv = 1.0 / (edge1 - edge0);
+ float eps = eps_ * width_inv;
+ float x = (x_ - edge0) * width_inv;
+ if (x <= -eps) result = 0;
+ else if (x >= eps && x <= 1.0-eps) result = x;
+ else if (x >= 1.0+eps) result = 1;
+ else if (x < eps) result = rampup (x+eps, 2.0*eps);
+ else /* if (x < 1.0+eps) */ result = 1.0 - rampup (1.0+eps - x, 2.0*eps);
+ } else {
+ result = step (edge0, x_);
+ }
+ return result;
+}
+
float aastep (float edge, float s, float dedge, float ds) {
// Box filtered AA step
float width = fabs(dedge) + fabs(ds);
@@ -455,8 +484,9 @@ float aastep (float edge, float s) {
// String functions
-
int strlen (string s) BUILTIN;
+int hash (string s) BUILTIN;
+int getchar (string s, int index) BUILTIN;
int startswith (string s, string prefix) BUILTIN;
int endswith (string s, string suffix) BUILTIN;
string substr (string s, int start, int len) BUILTIN;
@@ -510,6 +540,7 @@ closure color ambient_occlusion() BUILTIN;
// BSSRDF
closure color bssrdf_cubic(normal N, vector radius, float texture_blur, float sharpness) BUILTIN;
closure color bssrdf_gaussian(normal N, vector radius, float texture_blur) BUILTIN;
+closure color bssrdf_burley(normal N, vector radius, float texture_blur, color albedo) BUILTIN;
// Hair
closure color hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
diff --git a/intern/cycles/kernel/split/kernel_background_buffer_update.h b/intern/cycles/kernel/split/kernel_background_buffer_update.h
index 0132ef9c2f2..3d12a3dd993 100644
--- a/intern/cycles/kernel/split/kernel_background_buffer_update.h
+++ b/intern/cycles/kernel/split/kernel_background_buffer_update.h
@@ -43,7 +43,7 @@
* Queue_index (QUEUE_ACTIVE_AND_REGENERATED_RAYS) ------| |--- work_array
* parallel_samples -------------------------------------| |--- PathState_coop
* end_sample -------------------------------------------| |--- throughput_coop
- * kg (globals + data) ----------------------------------| |--- rng_coop
+ * kg (globals) -----------------------------------------| |--- rng_coop
* rng_state --------------------------------------------| |--- Ray
* PathRadiance_coop ------------------------------------| |
* sw ---------------------------------------------------| |
@@ -57,7 +57,7 @@
* work_pool_wgs ----------------------------------------| |
* num_samples ------------------------------------------| |
*
- * note on shader_data : shader_data argument is neither an input nor an output for this kernel. It is just filled and consumed here itself.
+ * note on sd : sd argument is neither an input nor an output for this kernel. It is just filled and consumed here itself.
* Note on Queues :
* This kernel fetches rays from QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue.
*
@@ -70,9 +70,7 @@
* QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be empty
*/
ccl_device char kernel_background_buffer_update(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_data,
+ KernelGlobals *kg,
ccl_global float *per_sample_output_buffers,
ccl_global uint *rng_state,
ccl_global uint *rng_coop, /* Required for buffer Update */
@@ -100,11 +98,6 @@ ccl_device char kernel_background_buffer_update(
int ray_index)
{
char enqueue_flag = 0;
-
- /* Load kernel globals structure and ShaderData strucuture */
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd = (ShaderData *)shader_data;
-
#ifdef __KERNEL_DEBUG__
DebugData *debug_data = &debugdata_coop[ray_index];
#endif
@@ -164,7 +157,7 @@ ccl_device char kernel_background_buffer_update(
if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
#ifdef __BACKGROUND__
/* sample background shader */
- float3 L_background = indirect_background(kg, state, ray, sd);
+ float3 L_background = indirect_background(kg, state, ray);
path_radiance_accum_background(L, (*throughput), L_background, state->bounce);
#endif
ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER);
diff --git a/intern/cycles/kernel/split/kernel_data_init.h b/intern/cycles/kernel/split/kernel_data_init.h
index 4dab79a5c67..9891391a3a3 100644
--- a/intern/cycles/kernel/split/kernel_data_init.h
+++ b/intern/cycles/kernel/split/kernel_data_init.h
@@ -51,97 +51,8 @@
* The number of elements in the queues is initialized to 0;
*/
ccl_device void kernel_data_init(
- ccl_global char *globals,
- ccl_global char *shader_data_sd, /* Arguments related to ShaderData */
- ccl_global char *shader_data_sd_DL_shadow, /* Arguments related to ShaderData */
-
- ccl_global float3 *P_sd,
- ccl_global float3 *P_sd_DL_shadow,
-
- ccl_global float3 *N_sd,
- ccl_global float3 *N_sd_DL_shadow,
-
- ccl_global float3 *Ng_sd,
- ccl_global float3 *Ng_sd_DL_shadow,
-
- ccl_global float3 *I_sd,
- ccl_global float3 *I_sd_DL_shadow,
-
- ccl_global int *shader_sd,
- ccl_global int *shader_sd_DL_shadow,
-
- ccl_global int *flag_sd,
- ccl_global int *flag_sd_DL_shadow,
-
- ccl_global int *prim_sd,
- ccl_global int *prim_sd_DL_shadow,
-
- ccl_global int *type_sd,
- ccl_global int *type_sd_DL_shadow,
-
- ccl_global float *u_sd,
- ccl_global float *u_sd_DL_shadow,
-
- ccl_global float *v_sd,
- ccl_global float *v_sd_DL_shadow,
-
- ccl_global int *object_sd,
- ccl_global int *object_sd_DL_shadow,
-
- ccl_global float *time_sd,
- ccl_global float *time_sd_DL_shadow,
-
- ccl_global float *ray_length_sd,
- ccl_global float *ray_length_sd_DL_shadow,
-
- ccl_global int *ray_depth_sd,
- ccl_global int *ray_depth_sd_DL_shadow,
-
- ccl_global int *transparent_depth_sd,
- ccl_global int *transparent_depth_sd_DL_shadow,
-
- /* Ray differentials. */
- ccl_global differential3 *dP_sd,
- ccl_global differential3 *dP_sd_DL_shadow,
-
- ccl_global differential3 *dI_sd,
- ccl_global differential3 *dI_sd_DL_shadow,
-
- ccl_global differential *du_sd,
- ccl_global differential *du_sd_DL_shadow,
-
- ccl_global differential *dv_sd,
- ccl_global differential *dv_sd_DL_shadow,
-
- /* Dp/Du */
- ccl_global float3 *dPdu_sd,
- ccl_global float3 *dPdu_sd_DL_shadow,
-
- ccl_global float3 *dPdv_sd,
- ccl_global float3 *dPdv_sd_DL_shadow,
-
- /* Object motion. */
- ccl_global Transform *ob_tfm_sd,
- ccl_global Transform *ob_tfm_sd_DL_shadow,
-
- ccl_global Transform *ob_itfm_sd,
- ccl_global Transform *ob_itfm_sd_DL_shadow,
-
- ShaderClosure *closure_sd,
- ShaderClosure *closure_sd_DL_shadow,
-
- ccl_global int *num_closure_sd,
- ccl_global int *num_closure_sd_DL_shadow,
-
- ccl_global float *randb_closure_sd,
- ccl_global float *randb_closure_sd_DL_shadow,
-
- ccl_global float3 *ray_P_sd,
- ccl_global float3 *ray_P_sd_DL_shadow,
-
- ccl_global differential3 *ray_dP_sd,
- ccl_global differential3 *ray_dP_sd_DL_shadow,
-
+ KernelGlobals *kg,
+ ShaderData *sd_DL_shadow,
ccl_constant KernelData *data,
ccl_global float *per_sample_output_buffers,
ccl_global uint *rng_state,
@@ -151,6 +62,7 @@ ccl_device void kernel_data_init(
PathRadiance *PathRadiance_coop, /* PathRadiance array to store PathRadiance values for all rays */
ccl_global Ray *Ray_coop, /* Ray array to store Ray information for all rays */
ccl_global PathState *PathState_coop, /* PathState array to store PathState information for all rays */
+ Intersection *Intersection_coop_shadow,
ccl_global char *ray_state, /* Stores information on current state of a ray */
#define KERNEL_TEX(type, ttype, name) \
@@ -175,108 +87,13 @@ ccl_device void kernel_data_init(
#endif
int parallel_samples) /* Number of samples to be processed in parallel */
{
-
- /* Load kernel globals structure */
- KernelGlobals *kg = (KernelGlobals *)globals;
-
kg->data = data;
+ kg->sd_input = sd_DL_shadow;
+ kg->isect_shadow = Intersection_coop_shadow;
#define KERNEL_TEX(type, ttype, name) \
kg->name = name;
#include "../kernel_textures.h"
- /* Load ShaderData structure */
- ShaderData *sd = (ShaderData *)shader_data_sd;
- ShaderData *sd_DL_shadow = (ShaderData *)shader_data_sd_DL_shadow;
-
- sd->P = P_sd;
- sd_DL_shadow->P = P_sd_DL_shadow;
-
- sd->N = N_sd;
- sd_DL_shadow->N = N_sd_DL_shadow;
-
- sd->Ng = Ng_sd;
- sd_DL_shadow->Ng = Ng_sd_DL_shadow;
-
- sd->I = I_sd;
- sd_DL_shadow->I = I_sd_DL_shadow;
-
- sd->shader = shader_sd;
- sd_DL_shadow->shader = shader_sd_DL_shadow;
-
- sd->flag = flag_sd;
- sd_DL_shadow->flag = flag_sd_DL_shadow;
-
- sd->prim = prim_sd;
- sd_DL_shadow->prim = prim_sd_DL_shadow;
-
- sd->type = type_sd;
- sd_DL_shadow->type = type_sd_DL_shadow;
-
- sd->u = u_sd;
- sd_DL_shadow->u = u_sd_DL_shadow;
-
- sd->v = v_sd;
- sd_DL_shadow->v = v_sd_DL_shadow;
-
- sd->object = object_sd;
- sd_DL_shadow->object = object_sd_DL_shadow;
-
- sd->time = time_sd;
- sd_DL_shadow->time = time_sd_DL_shadow;
-
- sd->ray_length = ray_length_sd;
- sd_DL_shadow->ray_length = ray_length_sd_DL_shadow;
-
- sd->ray_depth = ray_depth_sd;
- sd_DL_shadow->ray_depth = ray_depth_sd_DL_shadow;
-
- sd->transparent_depth = transparent_depth_sd;
- sd_DL_shadow->transparent_depth = transparent_depth_sd_DL_shadow;
-
-#ifdef __RAY_DIFFERENTIALS__
- sd->dP = dP_sd;
- sd_DL_shadow->dP = dP_sd_DL_shadow;
-
- sd->dI = dI_sd;
- sd_DL_shadow->dI = dI_sd_DL_shadow;
-
- sd->du = du_sd;
- sd_DL_shadow->du = du_sd_DL_shadow;
-
- sd->dv = dv_sd;
- sd_DL_shadow->dv = dv_sd_DL_shadow;
-#ifdef __DPDU__
- sd->dPdu = dPdu_sd;
- sd_DL_shadow->dPdu = dPdu_sd_DL_shadow;
-
- sd->dPdv = dPdv_sd;
- sd_DL_shadow->dPdv = dPdv_sd_DL_shadow;
-#endif
-#endif
-
-#ifdef __OBJECT_MOTION__
- sd->ob_tfm = ob_tfm_sd;
- sd_DL_shadow->ob_tfm = ob_tfm_sd_DL_shadow;
-
- sd->ob_itfm = ob_itfm_sd;
- sd_DL_shadow->ob_itfm = ob_itfm_sd_DL_shadow;
-#endif
-
- sd->closure = closure_sd;
- sd_DL_shadow->closure = closure_sd_DL_shadow;
-
- sd->num_closure = num_closure_sd;
- sd_DL_shadow->num_closure = num_closure_sd_DL_shadow;
-
- sd->randb_closure = randb_closure_sd;
- sd_DL_shadow->randb_closure = randb_closure_sd_DL_shadow;
-
- sd->ray_P = ray_P_sd;
- sd_DL_shadow->ray_P = ray_P_sd_DL_shadow;
-
- sd->ray_dP = ray_dP_sd;
- sd_DL_shadow->ray_dP = ray_dP_sd_DL_shadow;
-
int thread_index = get_global_id(1) * get_global_size(0) + get_global_id(0);
#ifdef __WORK_STEALING__
diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h
index 50c83d06140..c7a2aa6426c 100644
--- a/intern/cycles/kernel/split/kernel_direct_lighting.h
+++ b/intern/cycles/kernel/split/kernel_direct_lighting.h
@@ -30,13 +30,12 @@
*
* rng_coop -----------------------------------------|--- kernel_direct_lighting --|--- BSDFEval_coop
* PathState_coop -----------------------------------| |--- ISLamp_coop
- * shader_data --------------------------------------| |--- LightRay_coop
+ * sd -----------------------------------------------| |--- LightRay_coop
* ray_state ----------------------------------------| |--- ray_state
* Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS) ---| |
- * kg (globals + data) ------------------------------| |
+ * kg (globals) -------------------------------------| |
* queuesize ----------------------------------------| |
*
- * note on shader_DL : shader_DL is neither input nor output to this kernel; shader_DL is filled and consumed in this kernel itself.
* Note on Queues :
* This kernel only reads from the QUEUE_ACTIVE_AND_REGENERATED_RAYS queue and processes
* only the rays of state RAY_ACTIVE; If a ray needs to execute the corresponding shadow_blocked
@@ -49,10 +48,8 @@
* kernel call. Before this kernel call the QUEUE_SHADOW_RAY_CAST_DL_RAYS will be empty.
*/
ccl_device char kernel_direct_lighting(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required for direct lighting */
- ccl_global char *shader_DL, /* Required for direct lighting */
+ KernelGlobals *kg,
+ ShaderData *sd, /* Required for direct lighting */
ccl_global uint *rng_coop, /* Required for direct lighting */
ccl_global PathState *PathState_coop, /* Required for direct lighting */
ccl_global int *ISLamp_coop, /* Required for direct lighting */
@@ -63,11 +60,6 @@ ccl_device char kernel_direct_lighting(
{
char enqueue_flag = 0;
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
- /* Load kernel globals structure and ShaderData structure. */
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd = (ShaderData *)shader_data;
- ShaderData *sd_DL = (ShaderData *)shader_DL;
-
ccl_global PathState *state = &PathState_coop[ray_index];
/* direct lighting */
@@ -96,9 +88,7 @@ ccl_device char kernel_direct_lighting(
BsdfEval L_light;
bool is_lamp;
- if(direct_emission(kg, sd, &ls, &light_ray, &L_light, &is_lamp,
- state->bounce, state->transparent_bounce, sd_DL))
- {
+ if(direct_emission(kg, sd, &ls, state, &light_ray, &L_light, &is_lamp)) {
/* Write intermediate data to global memory to access from
* the next kernel.
*/
diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
index a75523a3e53..78dada82d89 100644
--- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
+++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
@@ -36,11 +36,11 @@
* Intersection_coop ------------------------------------| |--- L_transparent_coop
* PathState_coop ---------------------------------------| |--- per_sample_output_buffers
* L_transparent_coop -----------------------------------| |--- PathRadiance_coop
- * shader_data ------------------------------------------| |--- ShaderData
+ * sd ---------------------------------------------------| |--- ShaderData
* ray_state --------------------------------------------| |--- ray_state
* Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS) -------| |--- Queue_data (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
* Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS) ---| |--- AOAlpha_coop
- * kg (globals + data) ----------------------------------| |--- AOBSDF_coop
+ * kg (globals) -----------------------------------------| |--- AOBSDF_coop
* parallel_samples -------------------------------------| |--- AOLightRay_coop
* per_sample_output_buffers ----------------------------| |
* sw ---------------------------------------------------| |
@@ -71,9 +71,8 @@
* QUEUE_SHADOW_RAY_CAST_AO_RAYS will be filled with rays marked with flag RAY_SHADOW_RAY_CAST_AO
*/
ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required throughout the kernel except probabilistic path termination and AO */
+ KernelGlobals *kg,
+ ShaderData *sd, /* Required throughout the kernel except probabilistic path termination and AO */
ccl_global float *per_sample_output_buffers,
ccl_global uint *rng_coop, /* Required for "kernel_write_data_passes" and AO */
ccl_global float3 *throughput_coop, /* Required for handling holdout material and AO */
@@ -95,10 +94,6 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
char *enqueue_flag,
char *enqueue_flag_AO_SHADOW_RAY_CAST)
{
- /* Load kernel globals structure and ShaderData structure */
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd = (ShaderData *)shader_data;
-
#ifdef __WORK_STEALING__
unsigned int my_work;
unsigned int pixel_x;
diff --git a/intern/cycles/kernel/split/kernel_lamp_emission.h b/intern/cycles/kernel/split/kernel_lamp_emission.h
index a8e4b0a06c8..dc3b4b34d4e 100644
--- a/intern/cycles/kernel/split/kernel_lamp_emission.h
+++ b/intern/cycles/kernel/split/kernel_lamp_emission.h
@@ -26,7 +26,7 @@
* Throughput_coop ------------------------------------|--- kernel_lamp_emission --|--- PathRadiance_coop
* Ray_coop -------------------------------------------| |--- Queue_data(QUEUE_ACTIVE_AND_REGENERATED_RAYS)
* PathState_coop -------------------------------------| |--- Queue_index(QUEUE_ACTIVE_AND_REGENERATED_RAYS)
- * kg (globals + data) --------------------------------| |
+ * kg (globals) ---------------------------------------| |
* Intersection_coop ----------------------------------| |
* ray_state ------------------------------------------| |
* Queue_data (QUEUE_ACTIVE_AND_REGENERATED_RAYS) -----| |
@@ -35,14 +35,9 @@
* use_queues_flag ------------------------------------| |
* sw -------------------------------------------------| |
* sh -------------------------------------------------| |
- * parallel_samples -----------------------------------| |
- *
- * note : shader_data is neither input nor output. Its just filled and consumed in the same, kernel_lamp_emission, kernel.
*/
ccl_device void kernel_lamp_emission(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required for lamp emission */
+ KernelGlobals *kg,
ccl_global float3 *throughput_coop, /* Required for lamp emission */
PathRadiance *PathRadiance_coop, /* Required for lamp emission */
ccl_global Ray *Ray_coop, /* Required for lamp emission */
@@ -53,127 +48,36 @@ ccl_device void kernel_lamp_emission(
ccl_global char *use_queues_flag, /* Used to decide if this kernel should use
* queues to fetch ray index
*/
- int parallel_samples, /* Number of samples to be processed in parallel */
int ray_index)
{
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE) ||
IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND))
{
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd = (ShaderData *)shader_data;
PathRadiance *L = &PathRadiance_coop[ray_index];
+ ccl_global PathState *state = &PathState_coop[ray_index];
float3 throughput = throughput_coop[ray_index];
Ray ray = Ray_coop[ray_index];
- PathState state = PathState_coop[ray_index];
#ifdef __LAMP_MIS__
- if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
+ if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
/* ray starting from previous non-transparent bounce */
Ray light_ray;
- light_ray.P = ray.P - state.ray_t*ray.D;
- state.ray_t += Intersection_coop[ray_index].t;
+ light_ray.P = ray.P - state->ray_t*ray.D;
+ state->ray_t += Intersection_coop[ray_index].t;
light_ray.D = ray.D;
- light_ray.t = state.ray_t;
+ light_ray.t = state->ray_t;
light_ray.time = ray.time;
light_ray.dD = ray.dD;
light_ray.dP = ray.dP;
/* intersect with lamp */
float3 emission;
- if(indirect_lamp_emission(kg, &state, &light_ray, &emission, sd)) {
- path_radiance_accum_emission(L, throughput, emission, state.bounce);
+ if(indirect_lamp_emission(kg, state, &light_ray, &emission)) {
+ path_radiance_accum_emission(L, throughput, emission, state->bounce);
}
}
#endif /* __LAMP_MIS__ */
-
- /* __VOLUME__ feature is disabled */
-#if 0
-#ifdef __VOLUME__
- /* volume attenuation, emission, scatter */
- if(state.volume_stack[0].shader != SHADER_NONE) {
- Ray volume_ray = ray;
- volume_ray.t = (hit)? isect.t: FLT_MAX;
-
- bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
-
-#ifdef __VOLUME_DECOUPLED__
- int sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
- bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, true, sampling_method);
-
- if(decoupled) {
- /* cache steps along volume for repeated sampling */
- VolumeSegment volume_segment;
- ShaderData volume_sd;
-
- shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
- kernel_volume_decoupled_record(kg, &state,
- &volume_ray, &volume_sd, &volume_segment, heterogeneous);
-
- volume_segment.sampling_method = sampling_method;
-
- /* emission */
- if(volume_segment.closure_flag & SD_EMISSION)
- path_radiance_accum_emission(&L, throughput, volume_segment.accum_emission, state.bounce);
-
- /* scattering */
- VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
-
- if(volume_segment.closure_flag & SD_SCATTER) {
- bool all = false;
-
- /* direct light sampling */
- kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
- throughput, &state, &L, 1.0f, all, &volume_ray, &volume_segment);
-
- /* indirect sample. if we use distance sampling and take just
- * one sample for direct and indirect light, we could share
- * this computation, but makes code a bit complex */
- float rphase = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_PHASE);
- float rscatter = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_SCATTER_DISTANCE);
-
- result = kernel_volume_decoupled_scatter(kg,
- &state, &volume_ray, &volume_sd, &throughput,
- rphase, rscatter, &volume_segment, NULL, true);
- }
-
- if(result != VOLUME_PATH_SCATTERED)
- throughput *= volume_segment.accum_transmittance;
-
- /* free cached steps */
- kernel_volume_decoupled_free(kg, &volume_segment);
-
- if(result == VOLUME_PATH_SCATTERED) {
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
- continue;
- else
- break;
- }
- }
- else
-#endif /* __VOLUME_DECOUPLED__ */
- {
- /* integrate along volume segment with distance sampling */
- ShaderData volume_sd;
- VolumeIntegrateResult result = kernel_volume_integrate(
- kg, &state, &volume_sd, &volume_ray, &L, &throughput, rng, heterogeneous);
-
-#ifdef __VOLUME_SCATTER__
- if(result == VOLUME_PATH_SCATTERED) {
- /* direct lighting */
- kernel_path_volume_connect_light(kg, rng, &volume_sd, throughput, &state, &L);
-
- /* indirect light bounce */
- if(kernel_path_volume_bounce(kg, rng, &volume_sd, &throughput, &state, &L, &ray))
- continue;
- else
- break;
- }
-#endif /* __VOLUME_SCATTER__ */
- }
- }
-#endif /* __VOLUME__ */
-#endif
}
}
diff --git a/intern/cycles/kernel/split/kernel_next_iteration_setup.h b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
index e1a1577d7ae..74da80b52cc 100644
--- a/intern/cycles/kernel/split/kernel_next_iteration_setup.h
+++ b/intern/cycles/kernel/split/kernel_next_iteration_setup.h
@@ -30,12 +30,12 @@
* throughput_coop --------------------------------------| |--- Queue_data (QUEUE_HITBF_BUFF_UPDATE_TOREGEN_RAYS)
* PathRadiance_coop ------------------------------------| |--- throughput_coop
* PathState_coop ---------------------------------------| |--- PathRadiance_coop
- * shader_data ------------------------------------------| |--- PathState_coop
+ * sd ---------------------------------------------------| |--- PathState_coop
* ray_state --------------------------------------------| |--- ray_state
* Queue_data (QUEUE_ACTIVE_AND_REGENERATD_RAYS) --------| |--- Ray_coop
* Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS) ---| |--- use_queues_flag
* Ray_coop ---------------------------------------------| |
- * kg (globals + data) ----------------------------------| |
+ * kg (globals) -----------------------------------------| |
* LightRay_dl_coop -------------------------------------|
* ISLamp_coop ------------------------------------------|
* BSDFEval_coop ----------------------------------------|
@@ -60,9 +60,8 @@
* QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE and more RAY_UPDATE_BUFFER rays
*/
ccl_device char kernel_next_iteration_setup(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Required for setting up ray for next iteration */
+ KernelGlobals *kg,
+ ShaderData *sd, /* Required for setting up ray for next iteration */
ccl_global uint *rng_coop, /* Required for setting up ray for next iteration */
ccl_global float3 *throughput_coop, /* Required for setting up ray for next iteration */
PathRadiance *PathRadiance_coop, /* Required for setting up ray for next iteration */
@@ -81,16 +80,14 @@ ccl_device char kernel_next_iteration_setup(
{
char enqueue_flag = 0;
- /* Load kernel globals structure and ShaderData structure. */
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd = (ShaderData *)shader_data;
- PathRadiance *L = 0x0;
- ccl_global PathState *state = 0x0;
+ /* Load ShaderData structure. */
+ PathRadiance *L = NULL;
+ ccl_global PathState *state = NULL;
/* Path radiance update for AO/Direct_lighting's shadow blocked. */
if(IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL) ||
IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO))
- {
+ {
state = &PathState_coop[ray_index];
L = &PathRadiance_coop[ray_index];
float3 _throughput = throughput_coop[ray_index];
diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h
index 7eb201ecf32..faa752c360e 100644
--- a/intern/cycles/kernel/split/kernel_scene_intersect.h
+++ b/intern/cycles/kernel/split/kernel_scene_intersect.h
@@ -30,9 +30,8 @@
* PathState_coop ---------------------------------| |--- Intersection
* ray_state --------------------------------------| |--- ray_state
* use_queues_flag --------------------------------| |
- * parallel_samples -------------------------------| |
* QueueData(QUEUE_ACTIVE_AND_REGENERATED_RAYS) ---| |
- * kg (data + globals) ----------------------------| |
+ * kg (globals) -----------------------------------| |
* rng_coop ---------------------------------------| |
* sw ---------------------------------------------| |
* sh ---------------------------------------------| |
@@ -63,8 +62,7 @@
*/
ccl_device void kernel_scene_intersect(
- ccl_global char *globals,
- ccl_constant KernelData *data,
+ KernelGlobals *kg,
ccl_global uint *rng_coop,
ccl_global Ray *Ray_coop, /* Required for scene_intersect */
ccl_global PathState *PathState_coop, /* Required for scene_intersect */
@@ -76,7 +74,6 @@ ccl_device void kernel_scene_intersect(
#ifdef __KERNEL_DEBUG__
DebugData *debugdata_coop,
#endif
- int parallel_samples, /* Number of samples to be processed in parallel */
int ray_index)
{
/* All regenerated rays become active here */
@@ -86,9 +83,6 @@ ccl_device void kernel_scene_intersect(
if(!IS_STATE(ray_state, ray_index, RAY_ACTIVE))
return;
- /* Load kernel globals structure */
- KernelGlobals *kg = (KernelGlobals *)globals;
-
#ifdef __KERNEL_DEBUG__
DebugData *debug_data = &debugdata_coop[ray_index];
#endif
diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h
index e6fdc592586..e816a818915 100644
--- a/intern/cycles/kernel/split/kernel_shader_eval.h
+++ b/intern/cycles/kernel/split/kernel_shader_eval.h
@@ -23,14 +23,14 @@
* the rays of state RAY_TO_REGENERATE and enqueues them in QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS queue.
*
* The input and output of the kernel is as follows,
- * rng_coop -------------------------------------------|--- kernel_shader_eval --|--- shader_data
+ * rng_coop -------------------------------------------|--- kernel_shader_eval --|--- sd
* Ray_coop -------------------------------------------| |--- Queue_data (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
* PathState_coop -------------------------------------| |--- Queue_index (QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)
* Intersection_coop ----------------------------------| |
* Queue_data (QUEUE_ACTIVE_AND_REGENERATD_RAYS)-------| |
* Queue_index(QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS)---| |
* ray_state ------------------------------------------| |
- * kg (globals + data) --------------------------------| |
+ * kg (globals) ---------------------------------------| |
* queuesize ------------------------------------------| |
*
* Note on Queues :
@@ -45,9 +45,8 @@
* QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS will be filled with RAY_TO_REGENERATE rays
*/
ccl_device void kernel_shader_eval(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_data, /* Output ShaderData structure to be filled */
+ KernelGlobals *kg,
+ ShaderData *sd, /* Output ShaderData structure to be filled */
ccl_global uint *rng_coop, /* Required for rbsdf calculation */
ccl_global Ray *Ray_coop, /* Required for setting up shader from ray */
ccl_global PathState *PathState_coop, /* Required for all functions in this kernel */
@@ -56,8 +55,6 @@ ccl_device void kernel_shader_eval(
int ray_index)
{
if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd = (ShaderData *)shader_data;
Intersection *isect = &Intersection_coop[ray_index];
ccl_global uint *rng = &rng_coop[ray_index];
ccl_global PathState *state = &PathState_coop[ray_index];
@@ -66,10 +63,8 @@ ccl_device void kernel_shader_eval(
shader_setup_from_ray(kg,
sd,
isect,
- &ray,
- state->bounce,
- state->transparent_bounce);
+ &ray);
float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF);
- shader_eval_surface(kg, sd, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
+ shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN);
}
}
diff --git a/intern/cycles/kernel/split/kernel_shadow_blocked.h b/intern/cycles/kernel/split/kernel_shadow_blocked.h
index 28351c2b1ae..0c989861eef 100644
--- a/intern/cycles/kernel/split/kernel_shadow_blocked.h
+++ b/intern/cycles/kernel/split/kernel_shadow_blocked.h
@@ -31,10 +31,10 @@
QUEUE_SHADOW_RAY_CAST_DL_RAYS) -------| |
* Queue_index(QUEUE_SHADOW_RAY_CAST_AO_RAYS&
QUEUE_SHADOW_RAY_CAST_DL_RAYS) -------| |
- * kg (globals + data) -----------------------------| |
+ * kg (globals) ------------------------------------| |
* queuesize ---------------------------------------| |
*
- * Note on shader_shadow : shader_shadow is neither input nor output to this kernel. shader_shadow is filled and consumed in this kernel itself.
+ * Note on sd_shadow : sd_shadow is neither input nor output to this kernel. sd_shadow is filled and consumed in this kernel itself.
* Note on queues :
* The kernel fetches from QUEUE_SHADOW_RAY_CAST_AO_RAYS and QUEUE_SHADOW_RAY_CAST_DL_RAYS queues. We will empty
* these queues this kernel.
@@ -46,16 +46,11 @@
* QUEUE_SHADOW_RAY_CAST_AO_RAYS and QUEUE_SHADOW_RAY_CAST_DL_RAYS will be empty at kernel exit.
*/
ccl_device void kernel_shadow_blocked(
- ccl_global char *globals,
- ccl_constant KernelData *data,
- ccl_global char *shader_shadow, /* Required for shadow blocked */
+ KernelGlobals *kg,
ccl_global PathState *PathState_coop, /* Required for shadow blocked */
ccl_global Ray *LightRay_dl_coop, /* Required for direct lighting's shadow blocked */
ccl_global Ray *LightRay_ao_coop, /* Required for AO's shadow blocked */
- Intersection *Intersection_coop_AO,
- Intersection *Intersection_coop_DL,
ccl_global char *ray_state,
- int total_num_rays,
char shadow_blocked_type,
int ray_index)
{
@@ -65,30 +60,20 @@ ccl_device void kernel_shadow_blocked(
if(IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_DL) ||
IS_FLAG(ray_state, ray_index, RAY_SHADOW_RAY_CAST_AO))
{
- /* Load kernel global structure. */
- KernelGlobals *kg = (KernelGlobals *)globals;
- ShaderData *sd_shadow = (ShaderData *)shader_shadow;
-
ccl_global PathState *state = &PathState_coop[ray_index];
ccl_global Ray *light_ray_dl_global = &LightRay_dl_coop[ray_index];
ccl_global Ray *light_ray_ao_global = &LightRay_ao_coop[ray_index];
- Intersection *isect_ao_global = &Intersection_coop_AO[ray_index];
- Intersection *isect_dl_global = &Intersection_coop_DL[ray_index];
ccl_global Ray *light_ray_global =
shadow_blocked_type == RAY_SHADOW_RAY_CAST_AO
- ? light_ray_ao_global
- : light_ray_dl_global;
- Intersection *isect_global =
- RAY_SHADOW_RAY_CAST_AO ? isect_ao_global : isect_dl_global;
+ ? light_ray_ao_global
+ : light_ray_dl_global;
float3 shadow;
update_path_radiance = !(shadow_blocked(kg,
state,
light_ray_global,
- &shadow,
- sd_shadow,
- isect_global));
+ &shadow));
/* We use light_ray_global's P and t to store shadow and
* update_path_radiance.
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 69b98060c62..9865da2e8cd 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -187,7 +187,7 @@ CCL_NAMESPACE_BEGIN
#define NODES_FEATURE(feature) ((__NODES_FEATURES__ & (feature)) != 0)
/* Main Interpreter Loop */
-ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, int path_flag)
+ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_addr_space PathState *state, ShaderType type, int path_flag)
{
float stack[SVM_STACK_SIZE];
int offset = ccl_fetch(sd, shader) & SHADER_MASK;
@@ -335,7 +335,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
svm_node_brightness(sd, stack, node.y, node.z, node.w);
break;
case NODE_LIGHT_PATH:
- svm_node_light_path(sd, stack, node.y, node.z, path_flag);
+ svm_node_light_path(sd, state, stack, node.y, node.z, path_flag);
break;
case NODE_OBJECT_INFO:
svm_node_object_info(kg, sd, stack, node.y, node.z);
@@ -447,11 +447,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
svm_node_blackbody(kg, sd, stack, node.y, node.z);
break;
# endif /* __EXTRA_NODES__ */
-# if NODES_FEATURE(NODE_FEATURE_VOLUME) && !defined(__KERNEL_GPU__)
+# if NODES_FEATURE(NODE_FEATURE_VOLUME)
case NODE_TEX_VOXEL:
svm_node_tex_voxel(kg, sd, stack, node, &offset);
break;
-# endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) && !defined(__KERNEL_GPU__) */
+# endif /* NODES_FEATURE(NODE_FEATURE_VOLUME) */
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_3) */
case NODE_END:
return;
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
index 025ae96f59d..63bbb27d873 100644
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -22,6 +22,8 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
uint4 node, NodeAttributeType *type,
NodeAttributeType *mesh_type, AttributeElement *elem, int *offset, uint *out_offset)
{
+ *out_offset = node.z;
+ *type = (NodeAttributeType)node.w;
if(ccl_fetch(sd, object) != OBJECT_NONE) {
/* find attribute by unique id */
uint id = node.y;
@@ -32,6 +34,12 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
while(attr_map.x != id) {
+ if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
+ *elem = ATTR_ELEMENT_NONE;
+ *offset = 0;
+ *mesh_type = (NodeAttributeType)node.w;
+ return;
+ }
attr_offset += ATTR_PRIM_TYPES;
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
}
@@ -47,9 +55,6 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
*offset = 0;
*mesh_type = (NodeAttributeType)node.w;
}
-
- *out_offset = node.z;
- *type = (NodeAttributeType)node.w;
}
ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
diff --git a/intern/cycles/kernel/svm/svm_checker.h b/intern/cycles/kernel/svm/svm_checker.h
index 186bf7df55f..cea245991de 100644
--- a/intern/cycles/kernel/svm/svm_checker.h
+++ b/intern/cycles/kernel/svm/svm_checker.h
@@ -25,9 +25,9 @@ ccl_device_noinline float svm_checker(float3 p)
p.y = (p.y + 0.000001f)*0.999999f;
p.z = (p.z + 0.000001f)*0.999999f;
- int xi = float_to_int(fabsf(floorf(p.x)));
- int yi = float_to_int(fabsf(floorf(p.y)));
- int zi = float_to_int(fabsf(floorf(p.z)));
+ int xi = abs(float_to_int(floorf(p.x)));
+ int yi = abs(float_to_int(floorf(p.y)));
+ int zi = abs(float_to_int(floorf(p.z)));
return ((xi % 2 == yi % 2) == (zi % 2))? 1.0f: 0.0f;
}
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index c495ebb35bd..88397005b49 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -254,10 +254,13 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
#ifdef __CAUSTICS_TRICKS__
if(!kernel_data.integrator.caustics_reflective &&
- !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) {
+ !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE))
+ {
break;
}
#endif
+ int num_closure = ccl_fetch(sd, num_closure);
+
/* index of refraction */
float eta = fmaxf(param2, 1e-5f);
eta = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta;
@@ -268,7 +271,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
float roughness = param1;
/* reflection */
- ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
+ ShaderClosure *sc = ccl_fetch_array(sd, closure, num_closure);
float3 weight = sc->weight;
float sample_weight = sc->sample_weight;
@@ -289,8 +292,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
#endif
/* refraction */
- if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
- sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
+ if(num_closure + 1 < MAX_CLOSURE) {
+ sc = ccl_fetch_array(sd, closure, num_closure + 1);
sc->weight = weight;
sc->sample_weight = sample_weight;
@@ -411,7 +414,10 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->data1 = param2;
sc->data2 = -stack_load_float(stack, data_node.z);
- if(!(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)) {
+ if(stack_valid(data_node.y)) {
+ sc->T = normalize(stack_load_float3(stack, data_node.y));
+ }
+ else if(!(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE)) {
sc->T = normalize(ccl_fetch(sd, dPdv));
sc->data2 = 0.0f;
}
@@ -432,14 +438,16 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
#endif
#ifdef __SUBSURFACE__
-#ifndef __SPLIT_KERNEL__
-# define sc_next(sc) sc++
+# ifndef __SPLIT_KERNEL__
+# define sc_next(sc) sc++
# else
-# define sc_next(sc) sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure))
+# define sc_next(sc) sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure))
# endif
case CLOSURE_BSSRDF_CUBIC_ID:
- case CLOSURE_BSSRDF_GAUSSIAN_ID: {
+ case CLOSURE_BSSRDF_GAUSSIAN_ID:
+ case CLOSURE_BSSRDF_BURLEY_ID: {
ShaderClosure *sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
+ float3 albedo = sc->weight;
float3 weight = sc->weight * mix_weight;
float sample_weight = fabsf(average(weight));
@@ -463,11 +471,11 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->sample_weight = sample_weight;
sc->data0 = radius.x;
sc->data1 = texture_blur;
- sc->data2 = 0.0f;
+ sc->data2 = albedo.x;
sc->T.x = sharpness;
-#ifdef __OSL__
+# ifdef __OSL__
sc->prim = NULL;
-#endif
+# endif
sc->N = N;
ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
@@ -480,11 +488,11 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->sample_weight = sample_weight;
sc->data0 = radius.y;
sc->data1 = texture_blur;
- sc->data2 = 0.0f;
+ sc->data2 = albedo.y;
sc->T.x = sharpness;
-#ifdef __OSL__
+# ifdef __OSL__
sc->prim = NULL;
-#endif
+# endif
sc->N = N;
ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
@@ -497,11 +505,11 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
sc->sample_weight = sample_weight;
sc->data0 = radius.z;
sc->data1 = texture_blur;
- sc->data2 = 0.0f;
+ sc->data2 = albedo.z;
sc->T.x = sharpness;
-#ifdef __OSL__
+# ifdef __OSL__
sc->prim = NULL;
-#endif
+# endif
sc->N = N;
ccl_fetch(sd, flag) |= bssrdf_setup(sc, (ClosureType)type);
diff --git a/intern/cycles/kernel/svm/svm_gamma.h b/intern/cycles/kernel/svm/svm_gamma.h
index b645ff3f0f9..171945a60bc 100644
--- a/intern/cycles/kernel/svm/svm_gamma.h
+++ b/intern/cycles/kernel/svm/svm_gamma.h
@@ -21,12 +21,7 @@ ccl_device void svm_node_gamma(ShaderData *sd, float *stack, uint in_gamma, uint
float3 color = stack_load_float3(stack, in_color);
float gamma = stack_load_float(stack, in_gamma);
- if(color.x > 0.0f)
- color.x = powf(color.x, gamma);
- if(color.y > 0.0f)
- color.y = powf(color.y, gamma);
- if(color.z > 0.0f)
- color.z = powf(color.z, gamma);
+ color = svm_math_gamma_color(color, gamma);
if(stack_valid(out_color))
stack_store_float3(stack, out_color, color);
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index caf0b37ba35..07ab2f28577 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -16,6 +16,15 @@
CCL_NAMESPACE_BEGIN
+/* Float textures on various devices. */
+#if defined(__KERNEL_CPU__)
+ #define TEX_NUM_FLOAT_IMAGES TEX_NUM_FLOAT_IMAGES_CPU
+#elif defined(__KERNEL_CUDA__)
+ #define TEX_NUM_FLOAT_IMAGES TEX_NUM_FLOAT_IMAGES_CUDA
+#else
+ #define TEX_NUM_FLOAT_IMAGES TEX_NUM_FLOAT_IMAGES_OPENCL
+#endif
+
#ifdef __KERNEL_OPENCL__
/* For OpenCL all images are packed in a single array, and we do manual lookup
@@ -50,12 +59,6 @@ ccl_device_inline float svm_image_texture_frac(float x, int *ix)
ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha)
{
- /* first slots are used by float textures, which are not supported here */
- if(id < TEX_NUM_FLOAT_IMAGES)
- return make_float4(1.0f, 0.0f, 1.0f, 1.0f);
-
- id -= TEX_NUM_FLOAT_IMAGES;
-
uint4 info = kernel_tex_fetch(__tex_image_packed_info, id);
uint width = info.x;
uint height = info.y;
@@ -133,13 +136,13 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha)
{
#ifdef __KERNEL_CPU__
-#ifdef __KERNEL_SSE2__
+# ifdef __KERNEL_SSE2__
ssef r_ssef;
float4 &r = (float4 &)r_ssef;
r = kernel_tex_image_interp(id, x, y);
-#else
+# else
float4 r = kernel_tex_image_interp(id, x, y);
-#endif
+# endif
#else
float4 r;
@@ -246,13 +249,13 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
case 90: r = kernel_tex_image_interp(__tex_image_090, x, y); break;
case 91: r = kernel_tex_image_interp(__tex_image_091, x, y); break;
case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break;
+
+# if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300)
case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break;
case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break;
case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break;
case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break;
case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break;
-
-#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 300)
case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break;
case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
case 100: r = kernel_tex_image_interp(__tex_image_100, x, y); break;
@@ -306,7 +309,7 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
case 148: r = kernel_tex_image_interp(__tex_image_148, x, y); break;
case 149: r = kernel_tex_image_interp(__tex_image_149, x, y); break;
case 150: r = kernel_tex_image_interp(__tex_image_150, x, y); break;
-#endif
+# endif
default:
kernel_assert(0);
diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h
index a235dd35224..f35ea05048b 100644
--- a/intern/cycles/kernel/svm/svm_light_path.h
+++ b/intern/cycles/kernel/svm/svm_light_path.h
@@ -18,7 +18,7 @@ CCL_NAMESPACE_BEGIN
/* Light Path Node */
-ccl_device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint out_offset, int path_flag)
+ccl_device void svm_node_light_path(ShaderData *sd, ccl_addr_space PathState *state, float *stack, uint type, uint out_offset, int path_flag)
{
float info = 0.0f;
@@ -33,8 +33,9 @@ ccl_device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uin
case NODE_LP_volume_scatter: info = (path_flag & PATH_RAY_VOLUME_SCATTER)? 1.0f: 0.0f; break;
case NODE_LP_backfacing: info = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f: 0.0f; break;
case NODE_LP_ray_length: info = ccl_fetch(sd, ray_length); break;
- case NODE_LP_ray_depth: info = (float)ccl_fetch(sd, ray_depth); break;
- case NODE_LP_ray_transparent: info = (float)ccl_fetch(sd, transparent_depth); break;
+ case NODE_LP_ray_depth: info = (float)state->bounce; break;
+ case NODE_LP_ray_transparent: info = (float)state->transparent_bounce; break;
+ case NODE_LP_ray_transmission: info = (float)state->transmission_bounce; break;
}
stack_store_float(stack, out_offset, info);
@@ -61,7 +62,10 @@ ccl_device void svm_node_light_falloff(ShaderData *sd, float *stack, uint4 node)
if(smooth > 0.0f) {
float squared = ccl_fetch(sd, ray_length)*ccl_fetch(sd, ray_length);
- strength *= squared/(smooth + squared);
+ /* Distant lamps set the ray length to FLT_MAX, which causes squared to overflow. */
+ if(isfinite(squared)) {
+ strength *= squared/(smooth + squared);
+ }
}
stack_store_float(stack, out_offset, strength);
diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h
index 645cbd3fc73..3f7d18a02fe 100644
--- a/intern/cycles/kernel/svm/svm_math_util.h
+++ b/intern/cycles/kernel/svm/svm_math_util.h
@@ -166,5 +166,17 @@ ccl_device float3 svm_math_blackbody_color(float t) {
return make_float3(4.70366907f, 0.0f, 0.0f);
}
+ccl_device_inline float3 svm_math_gamma_color(float3 color, float gamma)
+{
+ if(color.x > 0.0f)
+ color.x = powf(color.x, gamma);
+ if(color.y > 0.0f)
+ color.y = powf(color.y, gamma);
+ if(color.z > 0.0f)
+ color.z = powf(color.z, gamma);
+
+ return color;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h
index 6111214acba..7cbda111d81 100644
--- a/intern/cycles/kernel/svm/svm_mix.h
+++ b/intern/cycles/kernel/svm/svm_mix.h
@@ -261,7 +261,7 @@ ccl_device float3 svm_mix_clamp(float3 col)
return outcol;
}
-ccl_device float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
+ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
{
float t = saturate(fac);
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
index c77c2a1c482..3f75ae5c04e 100644
--- a/intern/cycles/kernel/svm/svm_noise.h
+++ b/intern/cycles/kernel/svm/svm_noise.h
@@ -90,8 +90,8 @@ ccl_device uint hash(uint kx, uint ky, uint kz)
#ifdef __KERNEL_SSE2__
ccl_device_inline ssei hash_sse(const ssei& kx, const ssei& ky, const ssei& kz)
{
-#define rot(x,k) (((x)<<(k)) | (srl(x, 32-(k))))
-#define xor_rot(a, b, c) do {a = a^b; a = a - rot(b, c);} while(0)
+# define rot(x,k) (((x)<<(k)) | (srl(x, 32-(k))))
+# define xor_rot(a, b, c) do {a = a^b; a = a - rot(b, c);} while(0)
uint len = 3;
ssei magic = ssei(0xdeadbeef + (len << 2) + 13);
@@ -108,8 +108,8 @@ ccl_device_inline ssei hash_sse(const ssei& kx, const ssei& ky, const ssei& kz)
xor_rot(c, b, 24);
return c;
-#undef rot
-#undef xor_rot
+# undef rot
+# undef xor_rot
}
#endif
diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h
index 062ab013b1f..7e4106e212e 100644
--- a/intern/cycles/kernel/svm/svm_ramp.h
+++ b/intern/cycles/kernel/svm/svm_ramp.h
@@ -19,8 +19,27 @@
CCL_NAMESPACE_BEGIN
-ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg, int offset, float f, bool interpolate)
+ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg,
+ int offset,
+ float f,
+ bool interpolate,
+ bool extrapolate)
{
+ if((f < 0.0f || f > 1.0f) && extrapolate) {
+ float4 t0, dy;
+ if(f < 0.0f) {
+ t0 = fetch_node_float(kg, offset);
+ dy = t0 - fetch_node_float(kg, offset + 1);
+ f = -f;
+ }
+ else {
+ t0 = fetch_node_float(kg, offset + RAMP_TABLE_SIZE - 1);
+ dy = t0 - fetch_node_float(kg, offset + RAMP_TABLE_SIZE - 2);
+ f = f - 1.0f;
+ }
+ return t0 + dy * f * (RAMP_TABLE_SIZE-1);
+ }
+
f = saturate(f)*(RAMP_TABLE_SIZE-1);
/* clamp int as well in case of NaN */
@@ -43,7 +62,7 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac
decode_node_uchar4(node.y, &fac_offset, &color_offset, &alpha_offset, NULL);
float fac = stack_load_float(stack, fac_offset);
- float4 color = rgb_ramp_lookup(kg, *offset, fac, interpolate);
+ float4 color = rgb_ramp_lookup(kg, *offset, fac, interpolate, false);
if(stack_valid(color_offset))
stack_store_float3(stack, color_offset, float4_to_float3(color));
@@ -55,16 +74,24 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac
ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{
- uint fac_offset = node.y;
- uint color_offset = node.z;
- uint out_offset = node.w;
+ uint fac_offset, color_offset, out_offset;
+ decode_node_uchar4(node.y,
+ &fac_offset,
+ &color_offset,
+ &out_offset,
+ NULL);
float fac = stack_load_float(stack, fac_offset);
float3 color = stack_load_float3(stack, color_offset);
- float r = rgb_ramp_lookup(kg, *offset, color.x, true).x;
- float g = rgb_ramp_lookup(kg, *offset, color.y, true).y;
- float b = rgb_ramp_lookup(kg, *offset, color.z, true).z;
+ const float min_x = __int_as_float(node.z),
+ max_x = __int_as_float(node.w);
+ const float range_x = max_x - min_x;
+ color = (color - make_float3(min_x, min_x, min_x)) / range_x;
+
+ float r = rgb_ramp_lookup(kg, *offset, color.x, true, true).x;
+ float g = rgb_ramp_lookup(kg, *offset, color.y, true, true).y;
+ float b = rgb_ramp_lookup(kg, *offset, color.z, true, true).z;
color = (1.0f - fac)*color + fac*make_float3(r, g, b);
stack_store_float3(stack, out_offset, color);
@@ -74,18 +101,26 @@ ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *st
ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{
- uint fac_offset = node.y;
- uint color_offset = node.z;
- uint out_offset = node.w;
+ uint fac_offset, color_offset, out_offset;
+ decode_node_uchar4(node.y,
+ &fac_offset,
+ &color_offset,
+ &out_offset,
+ NULL);
float fac = stack_load_float(stack, fac_offset);
float3 color = stack_load_float3(stack, color_offset);
- float r = rgb_ramp_lookup(kg, *offset, (color.x + 1.0f)*0.5f, true).x;
- float g = rgb_ramp_lookup(kg, *offset, (color.y + 1.0f)*0.5f, true).y;
- float b = rgb_ramp_lookup(kg, *offset, (color.z + 1.0f)*0.5f, true).z;
+ const float min_x = __int_as_float(node.z),
+ max_x = __int_as_float(node.w);
+ const float range_x = max_x - min_x;
+ color = (color - make_float3(min_x, min_x, min_x)) / range_x;
- color = (1.0f - fac)*color + fac*make_float3(r*2.0f - 1.0f, g*2.0f - 1.0f, b*2.0f - 1.0f);
+ float r = rgb_ramp_lookup(kg, *offset, color.x, true, true).x;
+ float g = rgb_ramp_lookup(kg, *offset, color.y, true, true).y;
+ float b = rgb_ramp_lookup(kg, *offset, color.z, true, true).z;
+
+ color = (1.0f - fac)*color + fac*make_float3(r, g, b);
stack_store_float3(stack, out_offset, color);
*offset += RAMP_TABLE_SIZE;
diff --git a/intern/cycles/kernel/svm/svm_sky.h b/intern/cycles/kernel/svm/svm_sky.h
index 4c8e3a32271..854e85fd326 100644
--- a/intern/cycles/kernel/svm/svm_sky.h
+++ b/intern/cycles/kernel/svm/svm_sky.h
@@ -168,14 +168,16 @@ ccl_device void svm_node_tex_sky(KernelGlobals *kg, ShaderData *sd, float *stack
float3 f;
/* Compute Sky */
- if(sky_model == 0)
+ if(sky_model == 0) {
f = sky_radiance_old(kg, dir, sunphi, suntheta,
radiance_x, radiance_y, radiance_z,
config_x, config_y, config_z);
- else
+ }
+ else {
f = sky_radiance_new(kg, dir, sunphi, suntheta,
radiance_x, radiance_y, radiance_z,
config_x, config_y, config_z);
+ }
stack_store_float3(stack, out_offset, f);
}
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index eebd9bee420..27fed89fdf7 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -99,12 +99,12 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg,
stack_store_float3(stack, out_offset, data);
}
-ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
- ShaderData *sd,
- int path_flag,
- float *stack,
- uint4 node,
- int *offset)
+ccl_device_inline void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
+ ShaderData *sd,
+ int path_flag,
+ float *stack,
+ uint4 node,
+ int *offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
@@ -184,12 +184,12 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg,
#endif
}
-ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
- ShaderData *sd,
- int path_flag,
- float *stack,
- uint4 node,
- int *offset)
+ccl_device_inline void svm_node_tex_coord_bump_dy(KernelGlobals *kg,
+ ShaderData *sd,
+ int path_flag,
+ float *stack,
+ uint4 node,
+ int *offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index bf7e067616f..21b0cb15a4f 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -183,7 +183,8 @@ typedef enum NodeLightPath {
NODE_LP_backfacing,
NODE_LP_ray_length,
NODE_LP_ray_depth,
- NODE_LP_ray_transparent
+ NODE_LP_ray_transparent,
+ NODE_LP_ray_transmission,
} NodeLightPath;
typedef enum NodeLightFalloff {
@@ -244,7 +245,7 @@ typedef enum NodeMath {
NODE_MATH_LESS_THAN,
NODE_MATH_GREATER_THAN,
NODE_MATH_MODULO,
- NODE_MATH_ABSOLUTE,
+ NODE_MATH_ABSOLUTE,
NODE_MATH_CLAMP /* used for the clamp UI option */
} NodeMath;
@@ -293,6 +294,11 @@ typedef enum NodeWaveType {
NODE_WAVE_RINGS
} NodeWaveType;
+typedef enum NodeWaveProfiles {
+ NODE_WAVE_PROFILE_SIN,
+ NODE_WAVE_PROFILE_SAW,
+} NodeWaveProfile;
+
typedef enum NodeSkyType {
NODE_SKY_OLD,
NODE_SKY_NEW
@@ -404,6 +410,7 @@ typedef enum ClosureType {
/* BSSRDF */
CLOSURE_BSSRDF_CUBIC_ID,
CLOSURE_BSSRDF_GAUSSIAN_ID,
+ CLOSURE_BSSRDF_BURLEY_ID,
/* Other */
CLOSURE_EMISSION_ID,
@@ -426,8 +433,8 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID)
#define CLOSURE_IS_BSDF_ANISOTROPIC(type) (type >= CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID)
-#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_GAUSSIAN_ID)
-#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_GAUSSIAN_ID)
+#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_BURLEY_ID)
+#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_BURLEY_ID)
#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
index bbb687dfce5..85ba2f906fa 100644
--- a/intern/cycles/kernel/svm/svm_voxel.h
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -16,8 +16,6 @@
CCL_NAMESPACE_BEGIN
-#if !defined(__KERNEL_GPU__)
-
/* TODO(sergey): Think of making it more generic volume-type attribute
* sampler.
*/
@@ -29,6 +27,7 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
{
uint co_offset, density_out_offset, color_out_offset, space;
decode_node_uchar4(node.z, &co_offset, &density_out_offset, &color_out_offset, &space);
+#ifdef __VOLUME__
int id = node.y;
float3 co = stack_load_float3(stack, co_offset);
if(space == NODE_TEX_VOXEL_SPACE_OBJECT) {
@@ -43,22 +42,18 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
tfm.w = read_node_float(kg, offset);
co = transform_point(&tfm, co);
}
- if(co.x < 0.0f || co.y < 0.0f || co.z < 0.0f ||
- co.x > 1.0f || co.y > 1.0f || co.z > 1.0f)
- {
- if (stack_valid(density_out_offset))
- stack_store_float(stack, density_out_offset, 0.0f);
- if (stack_valid(color_out_offset))
- stack_store_float3(stack, color_out_offset, make_float3(0.0f, 0.0f, 0.0f));
- return;
- }
+# if defined(__KERNEL_GPU__)
+ float4 r = volume_image_texture_3d(id, co.x, co.y, co.z);
+# else
float4 r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z);
- if (stack_valid(density_out_offset))
+# endif
+#else
+ float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+#endif
+ if(stack_valid(density_out_offset))
stack_store_float(stack, density_out_offset, r.w);
- if (stack_valid(color_out_offset))
+ if(stack_valid(color_out_offset))
stack_store_float3(stack, color_out_offset, make_float3(r.x, r.y, r.z));
}
-#endif /* !defined(__KERNEL_GPU__) */
-
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h
index 6eaddaf301c..6ce69458a03 100644
--- a/intern/cycles/kernel/svm/svm_wave.h
+++ b/intern/cycles/kernel/svm/svm_wave.h
@@ -18,7 +18,7 @@ CCL_NAMESPACE_BEGIN
/* Wave */
-ccl_device_noinline float svm_wave(NodeWaveType type, float3 p, float detail, float distortion, float dscale)
+ccl_device_noinline float svm_wave(NodeWaveType type, NodeWaveProfile profile, float3 p, float detail, float distortion, float dscale)
{
float n;
@@ -26,11 +26,18 @@ ccl_device_noinline float svm_wave(NodeWaveType type, float3 p, float detail, fl
n = (p.x + p.y + p.z) * 10.0f;
else /* NODE_WAVE_RINGS */
n = len(p) * 20.0f;
-
+
if(distortion != 0.0f)
n += distortion * noise_turbulence(p*dscale, detail, 0);
- return 0.5f + 0.5f * sinf(n);
+ if(profile == NODE_WAVE_PROFILE_SIN) {
+ return 0.5f + 0.5f * sinf(n);
+ }
+ else { /* NODE_WAVE_PROFILE_SAW */
+ n /= M_2PI_F;
+ n -= (int) n;
+ return (n < 0.0f)? n + 1.0f: n;
+ }
}
ccl_device void svm_node_tex_wave(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
@@ -49,7 +56,7 @@ ccl_device void svm_node_tex_wave(KernelGlobals *kg, ShaderData *sd, float *stac
float distortion = stack_load_float_default(stack, distortion_offset, node2.z);
float dscale = stack_load_float_default(stack, dscale_offset, node2.w);
- float f = svm_wave((NodeWaveType)type, co*scale, detail, distortion, dscale);
+ float f = svm_wave((NodeWaveType)type, (NodeWaveProfile)node.w, co*scale, detail, distortion, dscale);
if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f);
if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, make_float3(f, f, f));
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 4e8a1794813..38450a9f762 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -6,6 +6,7 @@ set(INC
../kernel/svm
../kernel/osl
../bvh
+ ../subd
../util
../../glew-mx
)
@@ -35,7 +36,6 @@ set(SRC
scene.cpp
session.cpp
shader.cpp
- sky_model.cpp
sobol.cpp
svm.cpp
tables.cpp
@@ -62,8 +62,6 @@ set(SRC_HEADERS
scene.h
session.h
shader.h
- sky_model.h
- sky_model_data.h
sobol.h
svm.h
tables.h
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index 6e94459da55..b7de83d89c1 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -32,8 +32,9 @@ Attribute::~Attribute()
if(element == ATTR_ELEMENT_VOXEL) {
VoxelAttribute *voxel_data = data_voxel();
- if(voxel_data)
+ if(voxel_data && voxel_data->slot != -1) {
voxel_data->manager->remove_image(voxel_data->slot);
+ }
}
}
diff --git a/intern/cycles/render/background.cpp b/intern/cycles/render/background.cpp
index 5fd7bd8f16f..0cd164dc03e 100644
--- a/intern/cycles/render/background.cpp
+++ b/intern/cycles/render/background.cpp
@@ -33,7 +33,8 @@ Background::Background()
ao_factor = 0.0f;
ao_distance = FLT_MAX;
- use = true;
+ use_shader = true;
+ use_ao = false;
visibility = PATH_RAY_ALL_VISIBILITY;
shader = 0;
@@ -53,7 +54,7 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
device_free(device, dscene);
- if(use)
+ if(use_shader)
shader = scene->default_background;
else
shader = scene->default_empty;
@@ -61,8 +62,14 @@ void Background::device_update(Device *device, DeviceScene *dscene, Scene *scene
/* set shader index and transparent option */
KernelBackground *kbackground = &dscene->data.background;
- kbackground->ao_factor = ao_factor;
- kbackground->ao_distance = ao_distance;
+ if(use_ao) {
+ kbackground->ao_factor = ao_factor;
+ kbackground->ao_distance = ao_distance;
+ }
+ else {
+ kbackground->ao_factor = 0.0f;
+ kbackground->ao_distance = FLT_MAX;
+ }
kbackground->transparent = transparent;
kbackground->surface_shader = scene->shader_manager->get_shader_id(shader);
@@ -100,7 +107,8 @@ void Background::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
bool Background::modified(const Background& background)
{
return !(transparent == background.transparent &&
- use == background.use &&
+ use_shader == background.use_shader &&
+ use_ao == background.use_ao &&
ao_factor == background.ao_factor &&
ao_distance == background.ao_distance &&
visibility == background.visibility);
diff --git a/intern/cycles/render/background.h b/intern/cycles/render/background.h
index 26a727291ee..8bf97f5d6f7 100644
--- a/intern/cycles/render/background.h
+++ b/intern/cycles/render/background.h
@@ -30,7 +30,8 @@ public:
float ao_factor;
float ao_distance;
- bool use;
+ bool use_shader;
+ bool use_ao;
uint visibility;
uint shader;
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 4bbac0f91d1..5bf5e5113ef 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -131,7 +131,7 @@ void BakeManager::set_shader_limit(const size_t x, const size_t y)
m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit)/log(2)));
}
-bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, BakeData *bake_data, float result[])
+bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, const int pass_filter, BakeData *bake_data, float result[])
{
size_t num_pixels = bake_data->size();
@@ -183,6 +183,7 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre
task.shader_input = d_input.device_pointer;
task.shader_output = d_output.device_pointer;
task.shader_eval_type = shader_type;
+ task.shader_filter = pass_filter;
task.shader_x = 0;
task.offset = shader_offset;
task.shader_w = d_output.size();
@@ -254,23 +255,28 @@ bool BakeManager::is_aa_pass(ShaderEvalType type)
}
}
-bool BakeManager::is_light_pass(ShaderEvalType type)
+/* Keep it synced with kernel_bake.h logic */
+int BakeManager::shader_type_to_pass_filter(ShaderEvalType type, const int pass_filter)
{
+ const int component_flags = pass_filter & (BAKE_FILTER_DIRECT | BAKE_FILTER_INDIRECT | BAKE_FILTER_COLOR);
+
switch(type) {
case SHADER_EVAL_AO:
- case SHADER_EVAL_COMBINED:
+ return BAKE_FILTER_AO;
case SHADER_EVAL_SHADOW:
- case SHADER_EVAL_DIFFUSE_DIRECT:
- case SHADER_EVAL_GLOSSY_DIRECT:
- case SHADER_EVAL_TRANSMISSION_DIRECT:
- case SHADER_EVAL_SUBSURFACE_DIRECT:
- case SHADER_EVAL_DIFFUSE_INDIRECT:
- case SHADER_EVAL_GLOSSY_INDIRECT:
- case SHADER_EVAL_TRANSMISSION_INDIRECT:
- case SHADER_EVAL_SUBSURFACE_INDIRECT:
- return true;
+ return BAKE_FILTER_DIRECT;
+ case SHADER_EVAL_DIFFUSE:
+ return BAKE_FILTER_DIFFUSE | component_flags;
+ case SHADER_EVAL_GLOSSY:
+ return BAKE_FILTER_GLOSSY | component_flags;
+ case SHADER_EVAL_TRANSMISSION:
+ return BAKE_FILTER_TRANSMISSION | component_flags;
+ case SHADER_EVAL_SUBSURFACE:
+ return BAKE_FILTER_SUBSURFACE | component_flags;
+ case SHADER_EVAL_COMBINED:
+ return pass_filter;
default:
- return false;
+ return 0;
}
}
diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h
index 14d975a4b4e..8377e387197 100644
--- a/intern/cycles/render/bake.h
+++ b/intern/cycles/render/bake.h
@@ -63,12 +63,12 @@ public:
void set_shader_limit(const size_t x, const size_t y);
- bool bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, BakeData *bake_data, float result[]);
+ bool bake(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress, ShaderEvalType shader_type, const int pass_filter, BakeData *bake_data, float result[]);
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
- static bool is_light_pass(ShaderEvalType type);
+ static int shader_type_to_pass_filter(ShaderEvalType type, const int pass_filter);
static bool is_aa_pass(ShaderEvalType type);
bool need_update;
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index 127d116e556..028916c1b8f 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -18,17 +18,36 @@
#include "mesh.h"
#include "object.h"
#include "scene.h"
+#include "tables.h"
#include "device.h"
#include "util_foreach.h"
+#include "util_function.h"
+#include "util_math_cdf.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
+static float shutter_curve_eval(float x,
+ float shutter_curve[RAMP_TABLE_SIZE])
+{
+ x *= RAMP_TABLE_SIZE;
+ int index = (int)x;
+ float frac = x - index;
+ if(index < RAMP_TABLE_SIZE - 1) {
+ return lerp(shutter_curve[index], shutter_curve[index + 1], frac);
+ }
+ else {
+ return shutter_curve[RAMP_TABLE_SIZE - 1];
+ }
+}
+
Camera::Camera()
{
shuttertime = 1.0f;
+ motion_position = MOTION_POSITION_CENTER;
+ shutter_table_offset = TABLE_OFFSET_INVALID;
aperturesize = 0.0f;
focaldistance = 10.0f;
@@ -54,6 +73,9 @@ Camera::Camera()
longitude_max = M_PI_F;
fov = M_PI_4_F;
fov_pre = fov_post = fov;
+ stereo_eye = STEREO_NONE;
+ interocular_distance = 0.065f;
+ convergence_distance = 30.0f * 0.065f;
sensorwidth = 0.036f;
sensorheight = 0.024f;
@@ -84,6 +106,16 @@ Camera::Camera()
need_device_update = true;
need_flags_update = true;
previous_need_motion = -1;
+
+ /* Initialize shutter curve. */
+ const int num_shutter_points = sizeof(shutter_curve) / sizeof(*shutter_curve);
+ for(int i = 0; i < num_shutter_points; ++i) {
+ shutter_curve[i] = 1.0f;
+ }
+
+ /* Initialize rolling shutter effect. */
+ rolling_shutter_type = ROLLING_SHUTTER_NONE;
+ rolling_shutter_duration = 0.1f;
}
Camera::~Camera()
@@ -125,26 +157,30 @@ void Camera::update()
Transform bordertofull = transform_inverse(fulltoborder);
/* ndc to raster */
- Transform screentocamera;
Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull;
+ Transform full_ndctoraster = transform_scale(full_width, full_height, 1.0f) * bordertofull;
/* raster to screen */
Transform screentondc = fulltoborder * transform_from_viewplane(viewplane);
Transform screentoraster = ndctoraster * screentondc;
Transform rastertoscreen = transform_inverse(screentoraster);
+ Transform full_screentoraster = full_ndctoraster * screentondc;
+ Transform full_rastertoscreen = transform_inverse(full_screentoraster);
/* screen to camera */
+ Transform cameratoscreen;
if(type == CAMERA_PERSPECTIVE)
- screentocamera = transform_inverse(transform_perspective(fov, nearclip, farclip));
+ cameratoscreen = transform_perspective(fov, nearclip, farclip);
else if(type == CAMERA_ORTHOGRAPHIC)
- screentocamera = transform_inverse(transform_orthographic(nearclip, farclip));
+ cameratoscreen = transform_orthographic(nearclip, farclip);
else
- screentocamera = transform_identity();
+ cameratoscreen = transform_identity();
- Transform cameratoscreen = transform_inverse(screentocamera);
+ Transform screentocamera = transform_inverse(cameratoscreen);
rastertocamera = screentocamera * rastertoscreen;
+ Transform full_rastertocamera = screentocamera * full_rastertoscreen;
cameratoraster = screentoraster * cameratoscreen;
cameratoworld = matrix;
@@ -164,12 +200,18 @@ void Camera::update()
if(type == CAMERA_ORTHOGRAPHIC) {
dx = transform_direction(&rastertocamera, make_float3(1, 0, 0));
dy = transform_direction(&rastertocamera, make_float3(0, 1, 0));
+ full_dx = transform_direction(&full_rastertocamera, make_float3(1, 0, 0));
+ full_dy = transform_direction(&full_rastertocamera, make_float3(0, 1, 0));
}
else if(type == CAMERA_PERSPECTIVE) {
dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
transform_perspective(&rastertocamera, make_float3(0, 0, 0));
dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
transform_perspective(&rastertocamera, make_float3(0, 0, 0));
+ full_dx = transform_perspective(&full_rastertocamera, make_float3(1, 0, 0)) -
+ transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
+ full_dy = transform_perspective(&full_rastertocamera, make_float3(0, 1, 0)) -
+ transform_perspective(&full_rastertocamera, make_float3(0, 0, 0));
}
else {
dx = make_float3(0.0f, 0.0f, 0.0f);
@@ -178,6 +220,8 @@ void Camera::update()
dx = transform_direction(&cameratoworld, dx);
dy = transform_direction(&cameratoworld, dy);
+ full_dx = transform_direction(&cameratoworld, full_dx);
+ full_dy = transform_direction(&cameratoworld, full_dy);
/* TODO(sergey): Support other types of camera. */
if(type == CAMERA_PERSPECTIVE) {
@@ -278,6 +322,23 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
/* motion blur */
#ifdef __CAMERA_MOTION__
kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: -1.0f;
+
+ if(need_motion == Scene::MOTION_BLUR) {
+ vector<float> shutter_table;
+ util_cdf_inverted(SHUTTER_TABLE_SIZE,
+ 0.0f,
+ 1.0f,
+ function_bind(shutter_curve_eval, _1, shutter_curve),
+ false,
+ shutter_table);
+ shutter_table_offset = scene->lookup_tables->add_table(dscene,
+ shutter_table);
+ kcam->shutter_table_offset = (int)shutter_table_offset;
+ }
+ else if(shutter_table_offset != TABLE_OFFSET_INVALID) {
+ scene->lookup_tables->remove_table(shutter_table_offset);
+ shutter_table_offset = TABLE_OFFSET_INVALID;
+ }
#else
kcam->shuttertime = -1.0f;
#endif
@@ -295,6 +356,21 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
kcam->equirectangular_range = make_float4(longitude_min - longitude_max, -longitude_min,
latitude_min - latitude_max, -latitude_min + M_PI_2_F);
+ switch(stereo_eye) {
+ case STEREO_LEFT:
+ kcam->interocular_offset = -interocular_distance * 0.5f;
+ break;
+ case STEREO_RIGHT:
+ kcam->interocular_offset = interocular_distance * 0.5f;
+ break;
+ case STEREO_NONE:
+ default:
+ kcam->interocular_offset = 0.0f;
+ break;
+ }
+
+ kcam->convergence_distance = convergence_distance;
+
/* sensor size */
kcam->sensorwidth = sensorwidth;
kcam->sensorheight = sensorheight;
@@ -315,6 +391,10 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
/* Camera in volume. */
kcam->is_inside_volume = 0;
+ /* Rolling shutter effect */
+ kcam->rolling_shutter_type = rolling_shutter_type;
+ kcam->rolling_shutter_duration = rolling_shutter_duration;
+
previous_need_motion = need_motion;
}
@@ -341,9 +421,14 @@ void Camera::device_update_volume(Device * /*device*/,
need_flags_update = false;
}
-void Camera::device_free(Device * /*device*/, DeviceScene * /*dscene*/)
+void Camera::device_free(Device * /*device*/,
+ DeviceScene * /*dscene*/,
+ Scene *scene)
{
- /* nothing to free, only writing to constant memory */
+ if(shutter_table_offset != TABLE_OFFSET_INVALID) {
+ scene->lookup_tables->remove_table(shutter_table_offset);
+ shutter_table_offset = TABLE_OFFSET_INVALID;
+ }
}
bool Camera::modified(const Camera& cam)
@@ -372,7 +457,8 @@ bool Camera::modified(const Camera& cam)
(latitude_min == cam.latitude_min) &&
(latitude_max == cam.latitude_max) &&
(longitude_min == cam.longitude_min) &&
- (longitude_max == cam.longitude_max));
+ (longitude_max == cam.longitude_max) &&
+ (stereo_eye == cam.stereo_eye));
}
bool Camera::motion_modified(const Camera& cam)
@@ -425,9 +511,30 @@ BoundBox Camera::viewplane_bounds_get()
BoundBox bounds = BoundBox::empty;
if(type == CAMERA_PANORAMA) {
- bounds.grow(make_float3(cameratoworld.x.w,
- cameratoworld.y.w,
- cameratoworld.z.w));
+ if(use_spherical_stereo == false) {
+ bounds.grow(make_float3(cameratoworld.x.w,
+ cameratoworld.y.w,
+ cameratoworld.z.w));
+ }
+ else {
+ float half_eye_distance = interocular_distance * 0.5f;
+
+ bounds.grow(make_float3(cameratoworld.x.w + half_eye_distance,
+ cameratoworld.y.w,
+ cameratoworld.z.w));
+
+ bounds.grow(make_float3(cameratoworld.z.w,
+ cameratoworld.y.w + half_eye_distance,
+ cameratoworld.z.w));
+
+ bounds.grow(make_float3(cameratoworld.x.w - half_eye_distance,
+ cameratoworld.y.w,
+ cameratoworld.z.w));
+
+ bounds.grow(make_float3(cameratoworld.x.w,
+ cameratoworld.y.w - half_eye_distance,
+ cameratoworld.z.w));
+ }
}
else {
bounds.grow(transform_raster_to_world(0.0f, 0.0f));
@@ -444,4 +551,32 @@ BoundBox Camera::viewplane_bounds_get()
return bounds;
}
+float Camera::world_to_raster_size(float3 P)
+{
+ if(type == CAMERA_ORTHOGRAPHIC) {
+ return min(len(full_dx), len(full_dy));
+ }
+ else if(type == CAMERA_PERSPECTIVE) {
+ /* Calculate as if point is directly ahead of the camera. */
+ float3 raster = make_float3(0.5f*width, 0.5f*height, 0.0f);
+ float3 Pcamera = transform_perspective(&rastertocamera, raster);
+
+ /* dDdx */
+ float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
+ float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy;
+ float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff);
+
+ /* dPdx */
+ float dist = len(transform_point(&worldtocamera, P));
+ float3 D = normalize(Ddiff);
+ return len(dist*dDdx - dot(dist*dDdx, D)*D);
+ }
+ else {
+ // TODO(mai): implement for CAMERA_PANORAMA
+ assert(!"pixel width calculation for panoramic projection not implemented yet");
+ }
+
+ return 1.0f;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 1bedb051112..684b4458dfc 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -32,12 +32,53 @@ class Scene;
/* Camera
*
* The camera parameters are quite standard, tested to be both compatible with
- * Renderman, and Blender after remapping. */
+ * Renderman, and Blender after remapping.
+ */
class Camera {
public:
+ /* Specifies an offset for the shutter's time interval. */
+ enum MotionPosition {
+ /* Shutter opens at the current frame. */
+ MOTION_POSITION_START = 0,
+ /* Shutter is fully open at the current frame. */
+ MOTION_POSITION_CENTER = 1,
+ /* Shutter closes at the current frame. */
+ MOTION_POSITION_END = 2,
+
+ MOTION_NUM_POSITIONS,
+ };
+
+ /* Specifies rolling shutter effect. */
+ enum RollingShutterType {
+ /* No rolling shutter effect. */
+ ROLLING_SHUTTER_NONE = 0,
+ /* Sensor is being scanned vertically from top to bottom. */
+ ROLLING_SHUTTER_TOP = 1,
+
+ ROLLING_SHUTTER_NUM_TYPES,
+ };
+
+ /* Stereo Type */
+ enum StereoEye {
+ STEREO_NONE,
+ STEREO_LEFT,
+ STEREO_RIGHT,
+ };
+
/* motion blur */
float shuttertime;
+ MotionPosition motion_position;
+ float shutter_curve[RAMP_TABLE_SIZE];
+ size_t shutter_table_offset;
+
+ /* ** Rolling shutter effect. ** */
+ /* Defines rolling shutter effect type. */
+ RollingShutterType rolling_shutter_type;
+ /* Specifies exposure time of scanlines when using
+ * rolling shutter effect.
+ */
+ float rolling_shutter_duration;
/* depth of field */
float focaldistance;
@@ -58,6 +99,12 @@ public:
float longitude_min;
float longitude_max;
+ /* panorama stereo */
+ StereoEye stereo_eye;
+ bool use_spherical_stereo;
+ float interocular_distance;
+ float convergence_distance;
+
/* anamorphic lens bokeh */
float aperture_ratio;
@@ -73,6 +120,8 @@ public:
int width, height;
int resolution;
BoundBox2D viewplane;
+ /* width and height change during preview, so we need these for calculating dice rates. */
+ int full_width, full_height;
/* border */
BoundBox2D border;
@@ -104,6 +153,9 @@ public:
float3 dx;
float3 dy;
+ float3 full_dx;
+ float3 full_dy;
+
/* update */
bool need_update;
bool need_device_update;
@@ -120,7 +172,7 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene);
void device_update_volume(Device *device, DeviceScene *dscene, Scene *scene);
- void device_free(Device *device, DeviceScene *dscene);
+ void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Camera& cam);
bool motion_modified(const Camera& cam);
@@ -129,6 +181,9 @@ public:
/* Public utility functions. */
BoundBox viewplane_bounds_get();
+ /* Calculates the width of a pixel at point in world space. */
+ float world_to_raster_size(float3 P);
+
private:
/* Private utility functions. */
float3 transform_raster_to_world(float raster_x, float raster_y);
diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h
index 22ab5d05f8a..3d9b4e1f347 100644
--- a/intern/cycles/render/curves.h
+++ b/intern/cycles/render/curves.h
@@ -29,28 +29,32 @@ class Scene;
void curvebounds(float *lower, float *upper, float3 *p, int dim);
-typedef enum curve_primitives {
- CURVE_TRIANGLES,
- CURVE_LINE_SEGMENTS,
- CURVE_SEGMENTS,
- CURVE_RIBBONS
-} curve_primitives;
-
-typedef enum curve_shape {
- CURVE_RIBBON,
- CURVE_THICK
-} curve_shape;
-
-typedef enum curve_triangles {
+typedef enum CurvePrimitiveType {
+ CURVE_TRIANGLES = 0,
+ CURVE_LINE_SEGMENTS = 1,
+ CURVE_SEGMENTS = 2,
+ CURVE_RIBBONS = 3,
+
+ CURVE_NUM_PRIMITIVE_TYPES,
+} CurvePrimitiveType;
+
+typedef enum CurveShapeType {
+ CURVE_RIBBON = 0,
+ CURVE_THICK = 1,
+
+ CURVE_NUM_SHAPE_TYPES,
+} CurveShapeType;
+
+typedef enum CurveTriangleMethod {
CURVE_CAMERA_TRIANGLES,
CURVE_TESSELATED_TRIANGLES
-} curve_triangles;
+} CurveTriangleMethod;
-typedef enum curve_lines {
+typedef enum CurveLineMethod {
CURVE_ACCURATE,
CURVE_CORRECTED,
CURVE_UNCORRECTED
-} curve_lines;
+} CurveLineMethod;
class ParticleCurveData {
@@ -83,10 +87,10 @@ public:
class CurveSystemManager {
public:
- int primitive;
- int curve_shape;
- int line_method;
- int triangle_method;
+ CurvePrimitiveType primitive;
+ CurveShapeType curve_shape;
+ CurveLineMethod line_method;
+ CurveTriangleMethod triangle_method;
int resolution;
int subdivisions;
diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp
index 58080289633..abdd1c2cc8a 100644
--- a/intern/cycles/render/film.cpp
+++ b/intern/cycles/render/film.cpp
@@ -26,6 +26,7 @@
#include "util_debug.h"
#include "util_foreach.h"
#include "util_math.h"
+#include "util_math_cdf.h"
CCL_NAMESPACE_BEGIN
@@ -208,17 +209,20 @@ static float filter_func_box(float /*v*/, float /*width*/)
static float filter_func_gaussian(float v, float width)
{
- v *= 2.0f/width;
+ v *= 6.0f/width;
return expf(-2.0f*v*v);
}
+static float filter_func_blackman_harris(float v, float width)
+{
+ v = M_2PI_F * (v / width + 0.5f);
+ return 0.35875f - 0.48829f*cosf(v) + 0.14128f*cosf(2.0f*v) - 0.01168f*cosf(3.0f*v);
+}
+
static vector<float> filter_table(FilterType type, float width)
{
- const int filter_table_size = FILTER_TABLE_SIZE-1;
- vector<float> filter_table_cdf(filter_table_size+1);
- vector<float> filter_table(filter_table_size+1);
+ vector<float> filter_table(FILTER_TABLE_SIZE);
float (*filter_func)(float, float) = NULL;
- int i, half_size = filter_table_size/2;
switch(type) {
case FILTER_BOX:
@@ -226,42 +230,33 @@ static vector<float> filter_table(FilterType type, float width)
break;
case FILTER_GAUSSIAN:
filter_func = filter_func_gaussian;
+ width *= 3.0f;
+ break;
+ case FILTER_BLACKMAN_HARRIS:
+ filter_func = filter_func_blackman_harris;
+ width *= 2.0f;
break;
default:
assert(0);
}
- /* compute cumulative distribution function */
- filter_table_cdf[0] = 0.0f;
-
- for(i = 0; i < filter_table_size; i++) {
- float x = i*width*0.5f/(filter_table_size-1);
- float y = filter_func(x, width);
- filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
- }
-
- for(i = 0; i <= filter_table_size; i++)
- filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
-
- /* create importance sampling table */
- for(i = 0; i <= half_size; i++) {
- float x = i/(float)half_size;
- int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
- float t;
-
- if(index < filter_table_size+1) {
- t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
- }
- else {
- t = 0.0f;
- index = filter_table_size;
- }
-
- float y = ((index + t)/(filter_table_size))*width;
-
- filter_table[half_size+i] = 0.5f*(1.0f + y);
- filter_table[half_size-i] = 0.5f*(1.0f - y);
- }
+ /* Create importance sampling table. */
+
+ /* TODO(sergey): With the even filter table size resolution we can not
+ * really make it nice symmetric importance map without sampling full range
+ * (meaning, we would need to sample full filter range and not use the
+ * make_symmetric argument).
+ *
+ * Current code matches exactly initial filter table code, but we should
+ * consider either making FILTER_TABLE_SIZE odd value or sample full filter.
+ */
+
+ util_cdf_inverted(FILTER_TABLE_SIZE,
+ 0.0f,
+ width * 0.5f,
+ function_bind(filter_func, _1, width),
+ true,
+ filter_table);
return filter_table;
}
diff --git a/intern/cycles/render/film.h b/intern/cycles/render/film.h
index e2cd63cc2ed..966e00a8d1f 100644
--- a/intern/cycles/render/film.h
+++ b/intern/cycles/render/film.h
@@ -30,7 +30,10 @@ class Scene;
typedef enum FilterType {
FILTER_BOX,
- FILTER_GAUSSIAN
+ FILTER_GAUSSIAN,
+ FILTER_BLACKMAN_HARRIS,
+
+ FILTER_NUM_TYPES,
} FilterType;
class Pass {
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index f5ff091623b..4a9b2f1103c 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -22,9 +22,72 @@
#include "util_algorithm.h"
#include "util_debug.h"
#include "util_foreach.h"
+#include "util_queue.h"
CCL_NAMESPACE_BEGIN
+namespace {
+
+bool check_node_inputs_has_links(const ShaderNode *node)
+{
+ foreach(const ShaderInput *in, node->inputs) {
+ if(in->link) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool check_node_inputs_traversed(const ShaderNode *node,
+ const ShaderNodeSet& done)
+{
+ foreach(const ShaderInput *in, node->inputs) {
+ if(in->link) {
+ if(done.find(in->link->parent) == done.end()) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool check_node_inputs_equals(const ShaderNode *node_a,
+ const ShaderNode *node_b)
+{
+ if(node_a->inputs.size() != node_b->inputs.size()) {
+ /* Happens with BSDF closure nodes which are currently sharing the same
+ * name for all the BSDF types, making it impossible to filter out
+ * incompatible nodes.
+ */
+ return false;
+ }
+ for(int i = 0; i < node_a->inputs.size(); ++i) {
+ ShaderInput *input_a = node_a->inputs[i],
+ *input_b = node_b->inputs[i];
+ if(input_a->link == NULL && input_b->link == NULL) {
+ /* Unconnected inputs are expected to have the same value. */
+ if(input_a->value != input_b->value) {
+ return false;
+ }
+ }
+ else if(input_a->link != NULL && input_b->link != NULL) {
+ /* Expect links are to come from the same exact socket. */
+ if(input_a->link != input_b->link) {
+ return false;
+ }
+ }
+ else {
+ /* One socket has a link and another has not, inputs can't be
+ * considered equal.
+ */
+ return false;
+ }
+ }
+ return true;
+}
+
+} /* namespace */
+
/* Input and Output */
ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_)
@@ -68,9 +131,10 @@ ShaderNode::~ShaderNode()
ShaderInput *ShaderNode::input(const char *name)
{
- foreach(ShaderInput *socket, inputs)
+ foreach(ShaderInput *socket, inputs) {
if(strcmp(socket->name, name) == 0)
return socket;
+ }
return NULL;
}
@@ -146,8 +210,7 @@ ShaderGraph::ShaderGraph()
ShaderGraph::~ShaderGraph()
{
- foreach(ShaderNode *node, nodes)
- delete node;
+ clear_nodes();
}
ShaderNode *ShaderGraph::add(ShaderNode *node)
@@ -168,15 +231,15 @@ ShaderGraph *ShaderGraph::copy()
ShaderGraph *newgraph = new ShaderGraph();
/* copy nodes */
- set<ShaderNode*> nodes_all;
+ ShaderNodeSet nodes_all;
foreach(ShaderNode *node, nodes)
nodes_all.insert(node);
- map<ShaderNode*, ShaderNode*> nodes_copy;
+ ShaderNodeMap nodes_copy;
copy_nodes(nodes_all, nodes_copy);
/* add nodes (in same order, so output is still first) */
- newgraph->nodes.clear();
+ newgraph->clear_nodes();
foreach(ShaderNode *node, nodes)
newgraph->add(nodes_copy[node]);
@@ -242,7 +305,10 @@ void ShaderGraph::relink(vector<ShaderInput*> inputs, vector<ShaderInput*> outpu
}
}
-void ShaderGraph::finalize(bool do_bump, bool do_osl)
+void ShaderGraph::finalize(Scene *scene,
+ bool do_bump,
+ bool do_osl,
+ bool do_simplify)
{
/* before compiling, the shader graph may undergo a number of modifications.
* currently we set default geometry shader inputs, and create automatic bump
@@ -250,7 +316,7 @@ void ShaderGraph::finalize(bool do_bump, bool do_osl)
* modified afterwards. */
if(!finalized) {
- clean();
+ clean(scene);
default_inputs(do_osl);
refine_bump_nodes();
@@ -269,14 +335,17 @@ void ShaderGraph::finalize(bool do_bump, bool do_osl)
finalized = true;
}
+ else if(do_simplify) {
+ simplify_settings(scene);
+ }
}
-void ShaderGraph::find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input)
+void ShaderGraph::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
{
/* find all nodes that this input depends on directly and indirectly */
ShaderNode *node = (input->link)? input->link->parent: NULL;
- if(node) {
+ if(node != NULL && dependencies.find(node) == dependencies.end()) {
foreach(ShaderInput *in, node->inputs)
find_dependencies(dependencies, in);
@@ -284,7 +353,15 @@ void ShaderGraph::find_dependencies(set<ShaderNode*>& dependencies, ShaderInput
}
}
-void ShaderGraph::copy_nodes(set<ShaderNode*>& nodes, map<ShaderNode*, ShaderNode*>& nnodemap)
+void ShaderGraph::clear_nodes()
+{
+ foreach(ShaderNode *node, nodes) {
+ delete node;
+ }
+ nodes.clear();
+}
+
+void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
{
/* copy a set of nodes, and the links between them. the assumption is
* made that all nodes that inputs are linked to are in the set too. */
@@ -331,6 +408,13 @@ void ShaderGraph::copy_nodes(set<ShaderNode*>& nodes, map<ShaderNode*, ShaderNod
}
}
+/* Graph simplification */
+/* ******************** */
+
+/* Step 1: Remove unused nodes.
+ * Remove nodes which are not needed in the graph, such as proxies,
+ * mix nodes with a factor of 0 or 1, emission shaders without contribution...
+ */
void ShaderGraph::remove_unneeded_nodes()
{
vector<bool> removed(num_node_ids, false);
@@ -397,7 +481,8 @@ void ShaderGraph::remove_unneeded_nodes()
if(bg->outputs[0]->links.size()) {
/* Black color or zero strength, remove node */
if((!bg->inputs[0]->link && bg->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!bg->inputs[1]->link && bg->inputs[1]->value.x == 0.0f)) {
+ (!bg->inputs[1]->link && bg->inputs[1]->value.x == 0.0f))
+ {
vector<ShaderInput*> inputs = bg->outputs[0]->links;
relink(bg->inputs, inputs, NULL);
@@ -412,7 +497,8 @@ void ShaderGraph::remove_unneeded_nodes()
if(em->outputs[0]->links.size()) {
/* Black color or zero strength, remove node */
if((!em->inputs[0]->link && em->inputs[0]->value == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!em->inputs[1]->link && em->inputs[1]->value.x == 0.0f)) {
+ (!em->inputs[1]->link && em->inputs[1]->value.x == 0.0f))
+ {
vector<ShaderInput*> inputs = em->outputs[0]->links;
relink(em->inputs, inputs, NULL);
@@ -526,6 +612,139 @@ void ShaderGraph::remove_unneeded_nodes()
}
}
+/* Step 2: Constant folding.
+ * Try to constant fold some nodes, and pipe result directly to
+ * the input socket of connected nodes.
+ */
+void ShaderGraph::constant_fold()
+{
+ ShaderNodeSet done, scheduled;
+ queue<ShaderNode*> traverse_queue;
+
+ /* Schedule nodes which doesn't have any dependencies. */
+ foreach(ShaderNode *node, nodes) {
+ if(!check_node_inputs_has_links(node)) {
+ traverse_queue.push(node);
+ scheduled.insert(node);
+ }
+ }
+
+ while(!traverse_queue.empty()) {
+ ShaderNode *node = traverse_queue.front();
+ traverse_queue.pop();
+ done.insert(node);
+ foreach(ShaderOutput *output, node->outputs) {
+ /* Schedule node which was depending on the value,
+ * when possible. Do it before disconnect.
+ */
+ foreach(ShaderInput *input, output->links) {
+ if(scheduled.find(input->parent) != scheduled.end()) {
+ /* Node might not be optimized yet but scheduled already
+ * by other dependencies. No need to re-schedule it.
+ */
+ continue;
+ }
+ /* Schedule node if its inputs are fully done. */
+ if(check_node_inputs_traversed(input->parent, done)) {
+ traverse_queue.push(input->parent);
+ scheduled.insert(input->parent);
+ }
+ }
+ /* Optimize current node. */
+ float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
+ if(node->constant_fold(output, &optimized_value)) {
+ /* Apply optimized value to connected sockets. */
+ vector<ShaderInput*> links(output->links);
+ foreach(ShaderInput *input, links) {
+ /* Assign value and disconnect the optimizedinput. */
+ input->value = optimized_value;
+ disconnect(input);
+ }
+ }
+ }
+ }
+}
+
+/* Step 3: Simplification. */
+void ShaderGraph::simplify_settings(Scene *scene)
+{
+ foreach(ShaderNode *node, nodes) {
+ node->simplify_settings(scene);
+ }
+}
+
+/* Step 4: Deduplicate nodes with same settings. */
+void ShaderGraph::deduplicate_nodes()
+{
+ /* NOTES:
+ * - Deduplication happens for nodes which has same exact settings and same
+ * exact input links configuration (either connected to same output or has
+ * the same exact default value).
+ * - Deduplication happens in the bottom-top manner, so we know for fact that
+ * all traversed nodes are either can not be deduplicated at all or were
+ * already deduplicated.
+ */
+
+ ShaderNodeSet scheduled;
+ map<ustring, ShaderNodeSet> done;
+ queue<ShaderNode*> traverse_queue;
+
+ /* Schedule nodes which doesn't have any dependencies. */
+ foreach(ShaderNode *node, nodes) {
+ if(!check_node_inputs_has_links(node)) {
+ traverse_queue.push(node);
+ scheduled.insert(node);
+ }
+ }
+
+ while(!traverse_queue.empty()) {
+ ShaderNode *node = traverse_queue.front();
+ traverse_queue.pop();
+ done[node->name].insert(node);
+ /* Schedule the nodes which were depending on the current node. */
+ foreach(ShaderOutput *output, node->outputs) {
+ foreach(ShaderInput *input, output->links) {
+ if(scheduled.find(input->parent) != scheduled.end()) {
+ /* Node might not be optimized yet but scheduled already
+ * by other dependencies. No need to re-schedule it.
+ */
+ continue;
+ }
+ /* Schedule node if its inputs are fully done. */
+ if(check_node_inputs_traversed(input->parent, done[input->parent->name])) {
+ traverse_queue.push(input->parent);
+ scheduled.insert(input->parent);
+ }
+ }
+ }
+ /* Try to merge this node with another one. */
+ foreach(ShaderNode *other_node, done[node->name]) {
+ if(node == other_node) {
+ /* Don't merge with self. */
+ continue;
+ }
+ if(node->name != other_node->name) {
+ /* Can only de-duplicate nodes of the same type. */
+ continue;
+ }
+ if(!check_node_inputs_equals(node, other_node)) {
+ /* Node inputs are different, can't merge them, */
+ continue;
+ }
+ if(!node->equals(other_node)) {
+ /* Node settings are different. */
+ continue;
+ }
+ /* TODO(sergey): Consider making it an utility function. */
+ for(int i = 0; i < node->outputs.size(); ++i) {
+ vector<ShaderInput*> inputs = node->outputs[i]->links;
+ relink(node->inputs, inputs, other_node->outputs[i]);
+ }
+ break;
+ }
+ }
+}
+
void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack)
{
visited[node->id] = true;
@@ -550,11 +769,27 @@ void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<b
on_stack[node->id] = false;
}
-void ShaderGraph::clean()
+void ShaderGraph::clean(Scene *scene)
{
- /* remove proxy and unnecessary nodes */
+ /* Graph simplification:
+ * 1: Remove unnecessary nodes
+ * 2: Constant folding
+ * 3: Simplification
+ * 4: De-duplication
+ */
+
+ /* 1: Remove proxy and unnecessary nodes. */
remove_unneeded_nodes();
+ /* 2: Constant folding. */
+ constant_fold();
+
+ /* 3: Simplification. */
+ simplify_settings(scene);
+
+ /* 4: De-duplication. */
+ deduplicate_nodes();
+
/* we do two things here: find cycles and break them, and remove unused
* nodes that don't feed into the output. how cycles are broken is
* undefined, they are invalid input, the important thing is to not crash */
@@ -659,14 +894,14 @@ void ShaderGraph::refine_bump_nodes()
foreach(ShaderNode *node, nodes) {
if(node->name == ustring("bump") && node->input("Height")->link) {
ShaderInput *bump_input = node->input("Height");
- set<ShaderNode*> nodes_bump;
+ ShaderNodeSet nodes_bump;
/* make 2 extra copies of the subgraph defined in Bump input */
- map<ShaderNode*, ShaderNode*> nodes_dx;
- map<ShaderNode*, ShaderNode*> nodes_dy;
+ ShaderNodeMap nodes_dx;
+ ShaderNodeMap nodes_dy;
/* find dependencies for the given input */
- find_dependencies(nodes_bump, bump_input );
+ find_dependencies(nodes_bump, bump_input);
copy_nodes(nodes_bump, nodes_dx);
copy_nodes(nodes_bump, nodes_dy);
@@ -725,13 +960,13 @@ void ShaderGraph::bump_from_displacement()
return;
/* find dependencies for the given input */
- set<ShaderNode*> nodes_displace;
+ ShaderNodeSet nodes_displace;
find_dependencies(nodes_displace, displacement_in);
/* copy nodes for 3 bump samples */
- map<ShaderNode*, ShaderNode*> nodes_center;
- map<ShaderNode*, ShaderNode*> nodes_dx;
- map<ShaderNode*, ShaderNode*> nodes_dy;
+ ShaderNodeMap nodes_center;
+ ShaderNodeMap nodes_dx;
+ ShaderNodeMap nodes_dy;
copy_nodes(nodes_displace, nodes_center);
copy_nodes(nodes_displace, nodes_dx);
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index 9117fd03a95..214199a1c52 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -29,6 +29,7 @@
CCL_NAMESPACE_BEGIN
class AttributeRequestSet;
+class Scene;
class Shader;
class ShaderInput;
class ShaderOutput;
@@ -194,12 +195,22 @@ public:
virtual void compile(SVMCompiler& compiler) = 0;
virtual void compile(OSLCompiler& compiler) = 0;
+ /* ** Node optimization ** */
+ /* Check whether the node can be replaced with single constant. */
+ virtual bool constant_fold(ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
+
+ /* Simplify settings used by artists to the ones which are simpler to
+ * evaluate in the kernel but keep the final result unchanged.
+ */
+ virtual void simplify_settings(Scene * /*scene*/) {};
+
virtual bool has_surface_emission() { return false; }
virtual bool has_surface_transparent() { return false; }
virtual bool has_surface_bssrdf() { return false; }
virtual bool has_bssrdf_bump() { return false; }
virtual bool has_spatial_varying() { return false; }
virtual bool has_object_dependency() { return false; }
+ virtual bool has_integrator_dependency() { return false; }
vector<ShaderInput*> inputs;
vector<ShaderOutput*> outputs;
@@ -227,6 +238,21 @@ public:
* nodes group.
*/
virtual int get_feature() { return bump == SHADER_BUMP_NONE ? 0 : NODE_FEATURE_BUMP; }
+
+ /* Check whether settings of the node equals to another one.
+ *
+ * This is mainly used to check whether two nodes can be merged
+ * together. Meaning, runtime stuff like node id and unbound slots
+ * will be ignored for comparison.
+ *
+ * NOTE: If some node can't be de-duplicated for whatever reason it
+ * is to be handled in the subclass.
+ */
+ virtual bool equals(const ShaderNode *other)
+ {
+ return name == other->name &&
+ bump == other->bump;
+ }
};
@@ -248,6 +274,18 @@ public:
virtual void compile(SVMCompiler& compiler); \
virtual void compile(OSLCompiler& compiler); \
+class ShaderNodeIDComparator
+{
+public:
+ bool operator()(const ShaderNode *n1, const ShaderNode *n2) const
+ {
+ return n1->id < n2->id;
+ }
+};
+
+typedef set<ShaderNode*, ShaderNodeIDComparator> ShaderNodeSet;
+typedef map<ShaderNode*, ShaderNode*, ShaderNodeIDComparator> ShaderNodeMap;
+
/* Graph
*
* Shader graph of nodes. Also does graph manipulations for default inputs,
@@ -272,7 +310,10 @@ public:
void relink(vector<ShaderInput*> inputs, vector<ShaderInput*> outputs, ShaderOutput *output);
void remove_unneeded_nodes();
- void finalize(bool do_bump = false, bool do_osl = false);
+ void finalize(Scene *scene,
+ bool do_bump = false,
+ bool do_osl = false,
+ bool do_simplify = false);
int get_num_closures();
@@ -281,15 +322,21 @@ public:
protected:
typedef pair<ShaderNode* const, ShaderNode*> NodePair;
- void find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input);
- void copy_nodes(set<ShaderNode*>& nodes, map<ShaderNode*, ShaderNode*>& nnodemap);
+ void find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input);
+ void clear_nodes();
+ void copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap);
void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack);
- void clean();
void bump_from_displacement();
void refine_bump_nodes();
void default_inputs(bool do_osl);
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);
+
+ /* Graph simplification routines. */
+ void clean(Scene *scene);
+ void constant_fold();
+ void simplify_settings(Scene *scene);
+ void deduplicate_nodes();
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 7bceb8a8bfa..c0cbf0af968 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -22,6 +22,7 @@
#include "util_image.h"
#include "util_path.h"
#include "util_progress.h"
+#include "util_texture.h"
#ifdef WITH_OSL
#include <OSL/oslexec.h>
@@ -29,16 +30,46 @@
CCL_NAMESPACE_BEGIN
-ImageManager::ImageManager()
+ImageManager::ImageManager(const DeviceInfo& info)
{
need_update = true;
pack_images = false;
osl_texture_system = NULL;
animation_frame = 0;
- tex_num_images = TEX_NUM_IMAGES;
- tex_num_float_images = TEX_NUM_FLOAT_IMAGES;
- tex_image_byte_start = TEX_IMAGE_BYTE_START;
+ /* Set image limits */
+
+ /* CPU */
+ if(info.type == DEVICE_CPU) {
+ tex_num_byte_images = TEX_NUM_BYTE_IMAGES_CPU;
+ tex_num_float_images = TEX_NUM_FLOAT_IMAGES_CPU;
+ tex_image_byte_start = TEX_IMAGE_BYTE_START_CPU;
+ }
+ /* CUDA (Fermi) */
+ else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && !info.extended_images) {
+ tex_num_byte_images = TEX_NUM_BYTE_IMAGES_CUDA;
+ tex_num_float_images = TEX_NUM_FLOAT_IMAGES_CUDA;
+ tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA;
+ }
+ /* CUDA (Kepler and above) */
+ else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.extended_images) {
+ tex_num_byte_images = TEX_NUM_BYTE_IMAGES_CUDA_KEPLER;
+ tex_num_float_images = TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER;
+ tex_image_byte_start = TEX_IMAGE_BYTE_START_CUDA_KELPER;
+ }
+ /* OpenCL */
+ else if(info.pack_images) {
+ tex_num_byte_images = TEX_NUM_BYTE_IMAGES_OPENCL;
+ tex_num_float_images = TEX_NUM_FLOAT_IMAGES_OPENCL;
+ tex_image_byte_start = TEX_IMAGE_BYTE_START_OPENCL;
+ }
+ /* Should never happen */
+ else {
+ tex_num_byte_images = 0;
+ tex_num_float_images = 0;
+ tex_image_byte_start = 0;
+ assert(0);
+ }
}
ImageManager::~ImageManager()
@@ -59,18 +90,6 @@ void ImageManager::set_osl_texture_system(void *texture_system)
osl_texture_system = texture_system;
}
-void ImageManager::set_extended_image_limits(const DeviceInfo& info)
-{
- if(info.type == DEVICE_CPU) {
- tex_num_images = TEX_EXTENDED_NUM_IMAGES_CPU;
- tex_num_float_images = TEX_EXTENDED_NUM_FLOAT_IMAGES;
- tex_image_byte_start = TEX_EXTENDED_IMAGE_BYTE_START;
- }
- else if((info.type == DEVICE_CUDA || info.type == DEVICE_MULTI) && info.extended_images) {
- tex_num_images = TEX_EXTENDED_NUM_IMAGES_GPU;
- }
-}
-
bool ImageManager::set_animation_frame_update(int frame)
{
if(frame != animation_frame) {
@@ -263,9 +282,9 @@ int ImageManager::add_image(const string& filename,
if(slot == images.size()) {
/* max images limit reached */
- if(images.size() == tex_num_images) {
+ if(images.size() == tex_num_byte_images) {
printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n",
- tex_num_images, filename.c_str());
+ tex_num_byte_images, filename.c_str());
return -1;
}
@@ -350,7 +369,8 @@ void ImageManager::remove_image(const string& filename,
filename,
builtin_data,
interpolation,
- extension)) {
+ extension))
+ {
remove_image(slot);
break;
}
@@ -374,7 +394,8 @@ void ImageManager::tag_reload_image(const string& filename,
filename,
builtin_data,
interpolation,
- extension)) {
+ extension))
+ {
images[slot]->need_load = true;
break;
}
@@ -387,7 +408,8 @@ void ImageManager::tag_reload_image(const string& filename,
filename,
builtin_data,
interpolation,
- extension)) {
+ extension))
+ {
float_images[slot]->need_load = true;
break;
}
@@ -447,6 +469,9 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
/* read RGBA pixels */
uchar *pixels = (uchar*)tex_img.resize(width, height, depth);
+ if(pixels == NULL) {
+ return false;
+ }
bool cmyk = false;
if(in) {
@@ -570,6 +595,9 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
/* read RGBA pixels */
float *pixels = (float*)tex_img.resize(width, height, depth);
+ if(pixels == NULL) {
+ return false;
+ }
bool cmyk = false;
if(in) {
diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h
index bcc58ae951b..64798d75638 100644
--- a/intern/cycles/render/image.h
+++ b/intern/cycles/render/image.h
@@ -24,35 +24,15 @@
#include "util_thread.h"
#include "util_vector.h"
-#include "kernel_types.h" /* for TEX_NUM_FLOAT_IMAGES */
-
CCL_NAMESPACE_BEGIN
-/* generic */
-#define TEX_NUM_IMAGES 94
-#define TEX_IMAGE_BYTE_START TEX_NUM_FLOAT_IMAGES
-
-/* extended gpu */
-#define TEX_EXTENDED_NUM_IMAGES_GPU 145
-
-/* extended cpu */
-#define TEX_EXTENDED_NUM_FLOAT_IMAGES 1024
-#define TEX_EXTENDED_NUM_IMAGES_CPU 1024
-#define TEX_EXTENDED_IMAGE_BYTE_START TEX_EXTENDED_NUM_FLOAT_IMAGES
-
-/* color to use when textures are not found */
-#define TEX_IMAGE_MISSING_R 1
-#define TEX_IMAGE_MISSING_G 0
-#define TEX_IMAGE_MISSING_B 1
-#define TEX_IMAGE_MISSING_A 1
-
class Device;
class DeviceScene;
class Progress;
class ImageManager {
public:
- ImageManager();
+ ImageManager(const DeviceInfo& info);
~ImageManager();
int add_image(const string& filename,
@@ -82,7 +62,6 @@ public:
void set_osl_texture_system(void *texture_system);
void set_pack_images(bool pack_images_);
- void set_extended_image_limits(const DeviceInfo& info);
bool set_animation_frame_update(int frame);
bool need_update;
@@ -106,7 +85,7 @@ public:
};
private:
- int tex_num_images;
+ int tex_num_byte_images;
int tex_num_float_images;
int tex_image_byte_start;
thread_mutex device_mutex;
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 9f8d5b50ccd..be8fd552e78 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -16,8 +16,10 @@
#include "device.h"
#include "integrator.h"
+#include "film.h"
#include "light.h"
#include "scene.h"
+#include "shader.h"
#include "sobol.h"
#include "util_foreach.h"
@@ -173,6 +175,14 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
device->tex_alloc("__sobol_directions", dscene->sobol_directions);
+ /* Clamping. */
+ bool use_sample_clamp = (sample_clamp_direct != 0.0f ||
+ sample_clamp_indirect != 0.0f);
+ if(use_sample_clamp != scene->film->use_sample_clamp) {
+ scene->film->use_sample_clamp = use_sample_clamp;
+ scene->film->tag_update(scene);
+ }
+
need_update = false;
}
@@ -217,8 +227,14 @@ bool Integrator::modified(const Integrator& integrator)
sample_all_lights_indirect == integrator.sample_all_lights_indirect);
}
-void Integrator::tag_update(Scene * /*scene*/)
+void Integrator::tag_update(Scene *scene)
{
+ foreach(Shader *shader, scene->shaders) {
+ if(shader->has_integrator_dependency) {
+ scene->shader_manager->need_update = true;
+ break;
+ }
+ }
need_update = true;
}
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index fd2ad14488d..bb4e9c7056f 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -66,7 +66,9 @@ public:
enum Method {
BRANCHED_PATH = 0,
- PATH = 1
+ PATH = 1,
+
+ NUM_METHODS,
};
Method method;
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 4e962616263..1637045ce84 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -131,6 +131,7 @@ Light::Light()
max_bounces = 1024;
is_portal = false;
+ is_enabled = true;
}
void Light::tag_update(Scene *scene)
@@ -161,6 +162,38 @@ LightManager::~LightManager()
{
}
+void LightManager::disable_ineffective_light(Device *device, Scene *scene)
+{
+ /* Make all lights enabled by default, and perform some preliminary checks
+ * needed for finer-tuning of settings (for example, check whether we've
+ * got portals or not).
+ */
+ bool has_portal = false, has_background = false;
+ foreach(Light *light, scene->lights) {
+ light->is_enabled = light->has_contribution(scene);
+ has_portal |= light->is_portal;
+ has_background |= light->type == LIGHT_BACKGROUND;
+ }
+
+ if(has_background) {
+ /* Ignore background light if:
+ * - If unsupported on a device
+ * - If we don't need it (no HDRs etc.)
+ */
+ Shader *shader = scene->shaders[scene->background->shader];
+ bool disable_mis = !(has_portal || shader->has_surface_spatial_varying) ||
+ !(device->info.advanced_shading);
+ if(disable_mis) {
+ VLOG(1) << "Background MIS has been disabled.\n";
+ foreach(Light *light, scene->lights) {
+ if(light->type == LIGHT_BACKGROUND) {
+ light->is_enabled = false;
+ }
+ }
+ }
+ }
+}
+
void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
progress.set_status("Updating Lights", "Computing distribution");
@@ -173,7 +206,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
bool background_mis = false;
foreach(Light *light, scene->lights) {
- if(light->has_contribution(scene))
+ if(light->is_enabled)
num_lights++;
}
@@ -312,7 +345,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
int light_index = 0;
foreach(Light *light, scene->lights) {
- if(!light->has_contribution(scene))
+ if(!light->is_enabled)
continue;
distribution[offset].x = totarea;
@@ -460,7 +493,10 @@ static void background_cdf(int start,
}
}
-void LightManager::device_update_background(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void LightManager::device_update_background(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress)
{
KernelIntegrator *kintegrator = &dscene->data.integrator;
Light *background_light = NULL;
@@ -474,7 +510,7 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,
}
/* no background light found, signal renderer to skip sampling */
- if(!background_light) {
+ if(!background_light || !background_light->is_enabled) {
kintegrator->pdf_background_res = 0;
return;
}
@@ -551,26 +587,19 @@ void LightManager::device_update_background(Device *device, DeviceScene *dscene,
device->tex_alloc("__light_background_conditional_cdf", dscene->light_background_conditional_cdf);
}
-void LightManager::device_update_points(Device *device, DeviceScene *dscene, Scene *scene)
+void LightManager::device_update_points(Device *device,
+ DeviceScene *dscene,
+ Scene *scene)
{
- if(scene->lights.size() == 0)
+ int num_scene_lights = scene->lights.size();
+ if(num_scene_lights == 0)
return;
- /* remove background light? */
- if(!(device->info.advanced_shading)) {
- foreach(Light *light, scene->lights) {
- if(light->type == LIGHT_BACKGROUND) {
- scene->lights.erase(std::remove(scene->lights.begin(), scene->lights.end(), light), scene->lights.end());
- break;
- }
- }
- }
-
- float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);
+ float4 *light_data = dscene->light_data.resize(num_scene_lights*LIGHT_SIZE);
int light_index = 0;
foreach(Light *light, scene->lights) {
- if(!light->has_contribution(scene)) {
+ if(!light->is_enabled) {
continue;
}
@@ -732,8 +761,10 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
light_index++;
}
+ VLOG(1) << "Number of lights sent to the device: " << light_index;
+
VLOG(1) << "Number of lights without contribution: "
- << scene->lights.size() - light_index;
+ << num_scene_lights - light_index;
device->tex_alloc("__light_data", dscene->light_data);
}
@@ -749,6 +780,8 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
use_light_visibility = false;
+ disable_ineffective_light(device, scene);
+
device_update_points(device, dscene, scene);
if(progress.get_cancel()) return;
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index afec3628dda..15038d0a920 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -57,6 +57,7 @@ public:
bool use_scatter;
bool is_portal;
+ bool is_enabled;
int shader;
int samples;
@@ -76,15 +77,32 @@ public:
LightManager();
~LightManager();
- void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+ void device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
protected:
- void device_update_points(Device *device, DeviceScene *dscene, Scene *scene);
- void device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
- void device_update_background(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
+ /* Optimization: disable light which is either unsupported or
+ * which doesn't contribute to the scene or which is only used for MIS
+ * and scene doesn't need MIS.
+ */
+ void disable_ineffective_light(Device *device, Scene *scene);
+
+ void device_update_points(Device *device,
+ DeviceScene *dscene,
+ Scene *scene);
+ void device_update_distribution(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
+ void device_update_background(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress& progress);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 45685fe5927..241a1c44ebf 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -30,12 +30,14 @@
#include "osl_globals.h"
-#include "util_cache.h"
#include "util_foreach.h"
#include "util_logging.h"
#include "util_progress.h"
#include "util_set.h"
+#include "subd_split.h"
+#include "subd_patch.h"
+
CCL_NAMESPACE_BEGIN
/* Triangle */
@@ -98,6 +100,7 @@ Mesh::Mesh()
curve_attributes.curve_mesh = this;
has_volume = false;
+ has_surface_bssrdf = false;
}
Mesh::~Mesh()
@@ -112,6 +115,9 @@ void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys)
triangles.resize(numtris);
shader.resize(numtris);
smooth.resize(numtris);
+
+ forms_quad.resize(numtris);
+
curve_keys.resize(numcurvekeys);
curves.resize(numcurves);
@@ -127,6 +133,8 @@ void Mesh::clear()
shader.clear();
smooth.clear();
+ forms_quad.clear();
+
curve_keys.clear();
curves.clear();
@@ -156,7 +164,7 @@ int Mesh::split_vertex(int vertex)
return verts.size() - 1;
}
-void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_)
+void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
{
Triangle tri;
tri.v[0] = v0;
@@ -166,9 +174,10 @@ void Mesh::set_triangle(int i, int v0, int v1, int v2, int shader_, bool smooth_
triangles[i] = tri;
shader[i] = shader_;
smooth[i] = smooth_;
+ forms_quad[i] = forms_quad_;
}
-void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
+void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_, bool forms_quad_)
{
Triangle tri;
tri.v[0] = v0;
@@ -178,6 +187,7 @@ void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
triangles.push_back(tri);
shader.push_back(shader_);
smooth.push_back(smooth_);
+ forms_quad.push_back(forms_quad_);
}
void Mesh::add_curve_key(float3 co, float radius)
@@ -491,7 +501,7 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
compute_bounds();
- if(!transform_applied) {
+ if(need_build_bvh()) {
string msg = "Updating Mesh BVH ";
if(name == "")
msg += string_printf("%u/%u", (uint)(n+1), (uint)total);
@@ -513,7 +523,6 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total
progress->set_status(msg, "Building BVH");
BVHParams bparams;
- bparams.use_cache = params->use_bvh_cache;
bparams.use_spatial_split = params->use_bvh_spatial_split;
bparams.use_qbvh = params->use_qbvh;
@@ -552,6 +561,21 @@ bool Mesh::has_motion_blur() const
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
}
+bool Mesh::need_build_bvh() const
+{
+ return !transform_applied || has_surface_bssrdf;
+}
+
+bool Mesh::is_instanced() const
+{
+ /* Currently we treat subsurface objects as instanced.
+ *
+ * While it might be not very optimal for ray traversal, it avoids having
+ * duplicated BVH in the memory, saving quite some space.
+ */
+ return !transform_applied || has_surface_bssrdf;
+}
+
/* Mesh Manager */
MeshManager::MeshManager()
@@ -1084,7 +1108,6 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.top_level = true;
bparams.use_qbvh = scene->params.use_qbvh;
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
- bparams.use_cache = scene->params.use_bvh_cache;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
@@ -1109,9 +1132,9 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size());
device->tex_alloc("__object_node", dscene->object_node);
}
- if(pack.tri_woop.size()) {
- dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size());
- device->tex_alloc("__tri_woop", dscene->tri_woop);
+ if(pack.tri_storage.size()) {
+ dscene->tri_storage.reference(&pack.tri_storage[0], pack.tri_storage.size());
+ device->tex_alloc("__tri_storage", dscene->tri_storage);
}
if(pack.prim_type.size()) {
dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size());
@@ -1145,10 +1168,14 @@ void MeshManager::device_update_flags(Device * /*device*/,
/* update flags */
foreach(Mesh *mesh, scene->meshes) {
mesh->has_volume = false;
- foreach(uint shader, mesh->used_shaders) {
- if(scene->shaders[shader]->has_volume) {
+ foreach(uint shader_index, mesh->used_shaders) {
+ const Shader *shader = scene->shaders[shader_index];
+ if(shader->has_volume) {
mesh->has_volume = true;
}
+ if(shader->has_surface_bssrdf) {
+ mesh->has_surface_bssrdf = true;
+ }
}
}
need_flags_update = false;
@@ -1281,7 +1308,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
size_t i = 0, num_bvh = 0;
foreach(Mesh *mesh, scene->meshes)
- if(mesh->need_update && !mesh->transform_applied)
+ if(mesh->need_update && mesh->need_build_bvh())
num_bvh++;
TaskPool pool;
@@ -1294,13 +1321,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
&progress,
i,
num_bvh));
- if(!mesh->transform_applied) {
+ if(mesh->need_build_bvh()) {
i++;
}
}
}
- pool.wait_work();
+ TaskPool::Summary summary;
+ pool.wait_work(&summary);
+ VLOG(2) << "Objects BVH build pool statistics:\n"
+ << summary.full_report();
+
foreach(Shader *shader, scene->shaders)
shader->need_update_attributes = false;
@@ -1338,7 +1369,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
device->tex_free(dscene->bvh_nodes);
device->tex_free(dscene->bvh_leaf_nodes);
device->tex_free(dscene->object_node);
- device->tex_free(dscene->tri_woop);
+ device->tex_free(dscene->tri_storage);
device->tex_free(dscene->prim_type);
device->tex_free(dscene->prim_visibility);
device->tex_free(dscene->prim_index);
@@ -1356,7 +1387,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene)
dscene->bvh_nodes.clear();
dscene->object_node.clear();
- dscene->tri_woop.clear();
+ dscene->tri_storage.clear();
dscene->prim_type.clear();
dscene->prim_visibility.clear();
dscene->prim_index.clear();
@@ -1416,5 +1447,74 @@ bool Mesh::need_attribute(Scene *scene, ustring name)
return false;
}
+void Mesh::tessellate(DiagSplit *split)
+{
+ int num_faces = triangles.size();
+
+ add_face_normals();
+ add_vertex_normals();
+
+ Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
+ float3 *fN = attr_fN->data_float3();
+
+ Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
+ float3 *vN = attr_vN->data_float3();
+
+ for(int f = 0; f < num_faces; f++) {
+ if(!forms_quad[f]) {
+ /* triangle */
+ LinearTrianglePatch patch;
+ float3 *hull = patch.hull;
+ float3 *normals = patch.normals;
+
+ for(int i = 0; i < 3; i++) {
+ hull[i] = verts[triangles[f].v[i]];
+ }
+
+ if(smooth[f]) {
+ for(int i = 0; i < 3; i++) {
+ normals[i] = vN[triangles[f].v[i]];
+ }
+ }
+ else {
+ for(int i = 0; i < 3; i++) {
+ normals[i] = fN[f];
+ }
+ }
+
+ split->split_triangle(&patch);
+ }
+ else {
+ /* quad */
+ LinearQuadPatch patch;
+ float3 *hull = patch.hull;
+ float3 *normals = patch.normals;
+
+ hull[0] = verts[triangles[f ].v[0]];
+ hull[1] = verts[triangles[f ].v[1]];
+ hull[3] = verts[triangles[f ].v[2]];
+ hull[2] = verts[triangles[f+1].v[2]];
+
+ if(smooth[f]) {
+ normals[0] = vN[triangles[f ].v[0]];
+ normals[1] = vN[triangles[f ].v[1]];
+ normals[3] = vN[triangles[f ].v[2]];
+ normals[2] = vN[triangles[f+1].v[2]];
+ }
+ else {
+ for(int i = 0; i < 4; i++) {
+ normals[i] = fN[f];
+ }
+ }
+
+ split->split_quad(&patch);
+
+ // consume second triangle in quad
+ f++;
+ }
+
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index 76c186a3feb..006a4889d50 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -38,6 +38,7 @@ class Progress;
class Scene;
class SceneParams;
class AttributeRequest;
+class DiagSplit;
/* Mesh */
@@ -63,9 +64,11 @@ public:
/* Displacement */
enum DisplacementMethod {
- DISPLACE_BUMP,
- DISPLACE_TRUE,
- DISPLACE_BOTH
+ DISPLACE_BUMP = 0,
+ DISPLACE_TRUE = 1,
+ DISPLACE_BOTH = 2,
+
+ DISPLACE_NUM_METHODS,
};
ustring name;
@@ -83,8 +86,10 @@ public:
vector<Triangle> triangles;
vector<uint> shader;
vector<bool> smooth;
+ vector<bool> forms_quad; /* used to tell if triangle is part of a quad patch */
bool has_volume; /* Set in the device_update_flags(). */
+ bool has_surface_bssrdf; /* Set in the device_update_flags(). */
vector<float4> curve_keys; /* co + radius */
vector<Curve> curves;
@@ -120,8 +125,8 @@ public:
void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys);
void clear();
- void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth);
- void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
+ void set_triangle(int i, int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
+ void add_triangle(int v0, int v1, int v2, int shader, bool smooth, bool forms_quad = false);
void add_curve_key(float3 loc, float radius);
void add_curve(int first_key, int num_keys, int shader);
int split_vertex(int vertex);
@@ -141,6 +146,21 @@ public:
void tag_update(Scene *scene, bool rebuild);
bool has_motion_blur() const;
+
+ /* Check whether the mesh should have own BVH built separately. Briefly,
+ * own BVH is needed for mesh, if:
+ *
+ * - It is instanced multiple times, so each instance object should share the
+ * same BVH tree.
+ * - Special ray intersection is needed, for example to limit subsurface rays
+ * to only the mesh itself.
+ */
+ bool need_build_bvh() const;
+
+ /* Check if the mesh should be treated as instanced. */
+ bool is_instanced() const;
+
+ void tessellate(DiagSplit *split);
};
/* Mesh Manager */
diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp
index 1ba0c7f7291..dccfd74f17a 100644
--- a/intern/cycles/render/mesh_displace.cpp
+++ b/intern/cycles/render/mesh_displace.cpp
@@ -54,9 +54,10 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
}
/* setup input for device task */
- vector<bool> done(mesh->verts.size(), false);
+ const size_t num_verts = mesh->verts.size();
+ vector<bool> done(num_verts, false);
device_vector<uint4> d_input;
- uint4 *d_input_data = d_input.resize(mesh->verts.size());
+ uint4 *d_input_data = d_input.resize(num_verts);
size_t d_input_size = 0;
for(size_t i = 0; i < mesh->triangles.size(); i++) {
@@ -78,7 +79,7 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
int prim = mesh->tri_offset + i;
float u, v;
- switch (j) {
+ switch(j) {
case 0:
u = 1.0f;
v = 0.0f;
@@ -137,11 +138,12 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
/* read result */
done.clear();
- done.resize(mesh->verts.size(), false);
+ done.resize(num_verts, false);
int k = 0;
float4 *offset = (float4*)d_output.data_pointer;
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
for(size_t i = 0; i < mesh->triangles.size(); i++) {
Mesh::Triangle t = mesh->triangles[i];
Shader *shader = scene->shaders[mesh->shader[i]];
@@ -154,6 +156,12 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
done[t.v[j]] = true;
float3 off = float4_to_float3(offset[k++]);
mesh->verts[t.v[j]] += off;
+ if(attr_mP != NULL) {
+ for(int step = 0; step < mesh->motion_steps - 1; step++) {
+ float3 *mP = attr_mP->data_float3() + step*num_verts;
+ mP[t.v[j]] += off;
+ }
+ }
}
}
}
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 7ed07ab6453..57fb1a78f5b 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -15,12 +15,14 @@
*/
#include "image.h"
+#include "integrator.h"
#include "nodes.h"
+#include "scene.h"
#include "svm.h"
#include "svm_math_util.h"
#include "osl.h"
-#include "sky_model.h"
+#include "util_sky_model.h"
#include "util_foreach.h"
#include "util_transform.h"
@@ -182,6 +184,21 @@ static ShaderEnum image_projection_init()
return enm;
}
+static const char* get_osl_interpolation_parameter(InterpolationType interpolation)
+{
+ switch(interpolation) {
+ case INTERPOLATION_CLOSEST:
+ return "closest";
+ case INTERPOLATION_CUBIC:
+ return "cubic";
+ case INTERPOLATION_SMART:
+ return "smart";
+ case INTERPOLATION_LINEAR:
+ default:
+ return "linear";
+ }
+}
+
ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
@@ -362,22 +379,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
compiler.parameter("projection_blend", projection_blend);
compiler.parameter("is_float", is_float);
compiler.parameter("use_alpha", !alpha_out->links.empty());
-
- switch (interpolation) {
- case INTERPOLATION_CLOSEST:
- compiler.parameter("interpolation", "closest");
- break;
- case INTERPOLATION_CUBIC:
- compiler.parameter("interpolation", "cubic");
- break;
- case INTERPOLATION_SMART:
- compiler.parameter("interpolation", "smart");
- break;
- case INTERPOLATION_LINEAR:
- default:
- compiler.parameter("interpolation", "linear");
- break;
- }
+ compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation));
switch(extension) {
case EXTENSION_EXTEND:
@@ -421,6 +423,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
filename = "";
builtin_data = NULL;
color_space = ustring("Color");
+ interpolation = INTERPOLATION_LINEAR;
projection = ustring("Equirectangular");
animated = false;
@@ -434,7 +437,7 @@ EnvironmentTextureNode::~EnvironmentTextureNode()
if(image_manager) {
image_manager->remove_image(filename,
builtin_data,
- INTERPOLATION_LINEAR,
+ interpolation,
EXTENSION_REPEAT);
}
}
@@ -477,7 +480,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
0,
is_float_bool,
is_linear,
- INTERPOLATION_LINEAR,
+ interpolation,
EXTENSION_REPEAT,
use_alpha);
is_float = (int)is_float_bool;
@@ -546,7 +549,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
0,
is_float_bool,
is_linear,
- INTERPOLATION_LINEAR,
+ interpolation,
EXTENSION_REPEAT,
use_alpha);
is_float = (int)is_float_bool;
@@ -564,6 +567,9 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
compiler.parameter("color_space", "Linear");
else
compiler.parameter("color_space", "sRGB");
+
+ compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation));
+
compiler.parameter("is_float", is_float);
compiler.parameter("use_alpha", !alpha_out->links.empty());
compiler.add(this, "node_environment_texture");
@@ -1067,12 +1073,24 @@ static ShaderEnum wave_type_init()
return enm;
}
+static ShaderEnum wave_profile_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Sine", NODE_WAVE_PROFILE_SIN);
+ enm.insert("Saw", NODE_WAVE_PROFILE_SAW);
+
+ return enm;
+}
+
ShaderEnum WaveTextureNode::type_enum = wave_type_init();
+ShaderEnum WaveTextureNode::profile_enum = wave_profile_init();
WaveTextureNode::WaveTextureNode()
: TextureNode("wave_texture")
{
type = ustring("Bands");
+ profile = ustring("Sine");
add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
@@ -1114,7 +1132,8 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_TEX_WAVE,
compiler.encode_uchar4(type_enum[type], color_out->stack_offset, fac_out->stack_offset, dscale_in->stack_offset),
- compiler.encode_uchar4(vector_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset));
+ compiler.encode_uchar4(vector_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset),
+ profile_enum[profile]);
compiler.add_node(
__float_as_int(scale_in->value.x),
@@ -1131,6 +1150,7 @@ void WaveTextureNode::compile(OSLCompiler& compiler)
tex_mapping.compile(compiler);
compiler.parameter("Type", type);
+ compiler.parameter("Profile", profile);
compiler.add(this, "node_wave_texture");
}
@@ -1381,7 +1401,7 @@ PointDensityTextureNode::~PointDensityTextureNode()
image_manager->remove_image(filename,
builtin_data,
interpolation,
- EXTENSION_REPEAT);
+ EXTENSION_CLIP);
}
}
@@ -1413,10 +1433,10 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
image_manager = compiler.image_manager;
- if (use_density || use_color) {
- if (use_density)
+ if(use_density || use_color) {
+ if(use_density)
compiler.stack_assign(density_out);
- if (use_color)
+ if(use_color)
compiler.stack_assign(color_out);
if(slot == -1) {
@@ -1425,7 +1445,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
false, 0,
is_float, is_linear,
interpolation,
- EXTENSION_REPEAT,
+ EXTENSION_CLIP,
true);
}
@@ -1466,14 +1486,14 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
image_manager = compiler.image_manager;
- if (use_density || use_color) {
+ if(use_density || use_color) {
if(slot == -1) {
bool is_float, is_linear;
slot = image_manager->add_image(filename, builtin_data,
false, 0,
is_float, is_linear,
interpolation,
- EXTENSION_REPEAT,
+ EXTENSION_CLIP,
true);
}
@@ -1484,7 +1504,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
compiler.parameter("mapping", transform_transpose(tfm));
compiler.parameter("use_mapping", 1);
}
- switch (interpolation) {
+ switch(interpolation) {
case INTERPOLATION_CLOSEST:
compiler.parameter("interpolation", "closest");
break;
@@ -1615,6 +1635,56 @@ ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool auto
assert(0);
}
+bool ConvertNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+{
+ ShaderInput *in = inputs[0];
+ float3 value = in->value;
+
+ /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
+
+ if(socket == outputs[0] && in->link == NULL) {
+ if(from == SHADER_SOCKET_FLOAT) {
+ if(to == SHADER_SOCKET_INT)
+ /* float to int */
+ return false;
+ else
+ /* float to float3 */
+ *optimized_value = make_float3(value.x, value.x, value.x);
+ }
+ else if(from == SHADER_SOCKET_INT) {
+ if(to == SHADER_SOCKET_FLOAT)
+ /* int to float */
+ return false;
+ else
+ /* int to vector/point/normal */
+ return false;
+ }
+ else if(to == SHADER_SOCKET_FLOAT) {
+ if(from == SHADER_SOCKET_COLOR)
+ /* color to float */
+ optimized_value->x = linear_rgb_to_gray(value);
+ else
+ /* vector/point/normal to float */
+ optimized_value->x = average(value);
+ }
+ else if(to == SHADER_SOCKET_INT) {
+ if(from == SHADER_SOCKET_COLOR)
+ /* color to int */
+ return false;
+ else
+ /* vector/point/normal to int */
+ return false;
+ }
+ else {
+ *optimized_value = value;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
void ConvertNode::compile(SVMCompiler& compiler)
{
ShaderInput *in = inputs[0];
@@ -1675,7 +1745,7 @@ void ConvertNode::compile(SVMCompiler& compiler)
compiler.stack_assign(in);
compiler.stack_assign(out);
- compiler.add_node(NODE_VALUE_V, in->stack_offset);
+ compiler.add_node(NODE_VALUE_V, out->stack_offset);
compiler.add_node(NODE_VALUE_V, in->value);
}
}
@@ -1870,10 +1940,39 @@ GlossyBsdfNode::GlossyBsdfNode()
{
closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
distribution = ustring("GGX");
+ distribution_orig = ustring("");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
}
+void GlossyBsdfNode::simplify_settings(Scene *scene)
+{
+ if(distribution_orig == "") {
+ distribution_orig = distribution;
+ }
+ Integrator *integrator = scene->integrator;
+ if(integrator->filter_glossy == 0.0f) {
+ /* Fallback to Sharp closure for Roughness close to 0.
+ * Note: Keep the epsilon in sync with kernel!
+ */
+ ShaderInput *roughness_input = input("Roughness");
+ if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
+ distribution = ustring("Sharp");
+ }
+ }
+ else {
+ /* Rollback to original distribution when filter glossy is used. */
+ distribution = distribution_orig;
+ }
+ closure = (ClosureType)distribution_enum[distribution];
+}
+
+bool GlossyBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+}
+
void GlossyBsdfNode::compile(SVMCompiler& compiler)
{
closure = (ClosureType)distribution_enum[distribution];
@@ -1909,11 +2008,40 @@ GlassBsdfNode::GlassBsdfNode()
{
closure = CLOSURE_BSDF_SHARP_GLASS_ID;
distribution = ustring("Sharp");
+ distribution_orig = ustring("");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
}
+void GlassBsdfNode::simplify_settings(Scene *scene)
+{
+ if(distribution_orig == "") {
+ distribution_orig = distribution;
+ }
+ Integrator *integrator = scene->integrator;
+ if(integrator->filter_glossy == 0.0f) {
+ /* Fallback to Sharp closure for Roughness close to 0.
+ * Note: Keep the epsilon in sync with kernel!
+ */
+ ShaderInput *roughness_input = input("Roughness");
+ if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
+ distribution = ustring("Sharp");
+ }
+ }
+ else {
+ /* Rollback to original distribution when filter glossy is used. */
+ distribution = distribution_orig;
+ }
+ closure = (ClosureType)distribution_enum[distribution];
+}
+
+bool GlassBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+}
+
void GlassBsdfNode::compile(SVMCompiler& compiler)
{
closure = (ClosureType)distribution_enum[distribution];
@@ -1949,11 +2077,40 @@ RefractionBsdfNode::RefractionBsdfNode()
{
closure = CLOSURE_BSDF_REFRACTION_ID;
distribution = ustring("Sharp");
+ distribution_orig = ustring("");
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
}
+void RefractionBsdfNode::simplify_settings(Scene *scene)
+{
+ if(distribution_orig == "") {
+ distribution_orig = distribution;
+ }
+ Integrator *integrator = scene->integrator;
+ if(integrator->filter_glossy == 0.0f) {
+ /* Fallback to Sharp closure for Roughness close to 0.
+ * Note: Keep the epsilon in sync with kernel!
+ */
+ ShaderInput *roughness_input = input("Roughness");
+ if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
+ distribution = ustring("Sharp");
+ }
+ }
+ else {
+ /* Rollback to original distribution when filter glossy is used. */
+ distribution = distribution_orig;
+ }
+ closure = (ClosureType)distribution_enum[distribution];
+}
+
+bool RefractionBsdfNode::has_integrator_dependency()
+{
+ ShaderInput *roughness_input = input("Roughness");
+ return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+}
+
void RefractionBsdfNode::compile(SVMCompiler& compiler)
{
closure = (ClosureType)distribution_enum[distribution];
@@ -2086,6 +2243,7 @@ static ShaderEnum subsurface_falloff_init()
enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID);
enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
+ enm.insert("Burley", CLOSURE_BSSRDF_BURLEY_ID);
return enm;
}
@@ -2354,6 +2512,7 @@ HairBsdfNode::HairBsdfNode()
add_input("Offset", SHADER_SOCKET_FLOAT);
add_input("RoughnessU", SHADER_SOCKET_FLOAT);
add_input("RoughnessV", SHADER_SOCKET_FLOAT);
+ add_input("Tangent", SHADER_SOCKET_VECTOR);
}
void HairBsdfNode::compile(SVMCompiler& compiler)
@@ -2735,6 +2894,7 @@ LightPathNode::LightPathNode()
add_output("Ray Length", SHADER_SOCKET_FLOAT);
add_output("Ray Depth", SHADER_SOCKET_FLOAT);
add_output("Transparent Depth", SHADER_SOCKET_FLOAT);
+ add_output("Transmission Depth", SHADER_SOCKET_FLOAT);
}
void LightPathNode::compile(SVMCompiler& compiler)
@@ -2807,6 +2967,12 @@ void LightPathNode::compile(SVMCompiler& compiler)
compiler.stack_assign(out);
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, out->stack_offset);
}
+
+ out = output("Transmission Depth");
+ if(!out->links.empty()) {
+ compiler.stack_assign(out);
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, out->stack_offset);
+ }
}
void LightPathNode::compile(OSLCompiler& compiler)
@@ -3083,6 +3249,13 @@ ValueNode::ValueNode()
add_output("Value", SHADER_SOCKET_FLOAT);
}
+bool ValueNode::constant_fold(ShaderOutput * /*socket*/,
+ float3 *optimized_value)
+{
+ *optimized_value = make_float3(value, value, value);
+ return true;
+}
+
void ValueNode::compile(SVMCompiler& compiler)
{
ShaderOutput *val_out = output("Value");
@@ -3107,6 +3280,13 @@ ColorNode::ColorNode()
add_output("Color", SHADER_SOCKET_COLOR);
}
+bool ColorNode::constant_fold(ShaderOutput * /*socket*/,
+ float3 *optimized_value)
+{
+ *optimized_value = value;
+ return true;
+}
+
void ColorNode::compile(SVMCompiler& compiler)
{
ShaderOutput *color_out = output("Color");
@@ -3408,6 +3588,23 @@ GammaNode::GammaNode()
add_output("Color", SHADER_SOCKET_COLOR);
}
+bool GammaNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderInput *gamma_in = input("Gamma");
+
+ if(socket == output("Color")) {
+ if(color_in->link == NULL && gamma_in->link == NULL) {
+ *optimized_value = svm_math_gamma_color(color_in->value,
+ gamma_in->value.x);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
void GammaNode::compile(SVMCompiler& compiler)
{
ShaderInput *color_in = input("Color");
@@ -3861,6 +4058,21 @@ BlackbodyNode::BlackbodyNode()
add_output("Color", SHADER_SOCKET_COLOR);
}
+bool BlackbodyNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+{
+ ShaderInput *temperature_in = input("Temperature");
+
+ if(socket == output("Color")) {
+ if(temperature_in->link == NULL) {
+ *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
void BlackbodyNode::compile(SVMCompiler& compiler)
{
ShaderInput *temperature_in = input("Temperature");
@@ -3868,15 +4080,8 @@ void BlackbodyNode::compile(SVMCompiler& compiler)
compiler.stack_assign(color_out);
- if(temperature_in->link == NULL) {
- float3 color = svm_math_blackbody_color(temperature_in->value.x);
- compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
- compiler.add_node(NODE_VALUE_V, color);
- }
- else {
- compiler.stack_assign(temperature_in);
- compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
- }
+ compiler.stack_assign(temperature_in);
+ compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
}
void BlackbodyNode::compile(OSLCompiler& compiler)
@@ -3960,28 +4165,35 @@ static ShaderEnum math_type_init()
ShaderEnum MathNode::type_enum = math_type_init();
-void MathNode::compile(SVMCompiler& compiler)
+bool MathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
{
ShaderInput *value1_in = input("Value1");
ShaderInput *value2_in = input("Value2");
- ShaderOutput *value_out = output("Value");
- compiler.stack_assign(value_out);
+ if(socket == output("Value")) {
+ if(value1_in->link == NULL && value2_in->link == NULL) {
+ optimized_value->x = svm_math((NodeMath)type_enum[type],
+ value1_in->value.x,
+ value2_in->value.x);
+
+ if(use_clamp) {
+ optimized_value->x = saturate(optimized_value->x);
+ }
- /* Optimize math node without links to a single value node. */
- if(value1_in->link == NULL && value2_in->link == NULL) {
- float optimized_value = svm_math((NodeMath)type_enum[type],
- value1_in->value.x,
- value2_in->value.x);
- if(use_clamp) {
- optimized_value = saturate(optimized_value);
+ return true;
}
- compiler.add_node(NODE_VALUE_F,
- __float_as_int(optimized_value),
- value_out->stack_offset);
- return;
}
+ return false;
+}
+
+void MathNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *value1_in = input("Value1");
+ ShaderInput *value2_in = input("Value2");
+ ShaderOutput *value_out = output("Value");
+
+ compiler.stack_assign(value_out);
compiler.stack_assign(value1_in);
compiler.stack_assign(value2_in);
@@ -4030,35 +4242,44 @@ static ShaderEnum vector_math_type_init()
ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
-void VectorMathNode::compile(SVMCompiler& compiler)
+bool VectorMathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
{
ShaderInput *vector1_in = input("Vector1");
ShaderInput *vector2_in = input("Vector2");
- ShaderOutput *value_out = output("Value");
- ShaderOutput *vector_out = output("Vector");
- compiler.stack_assign(value_out);
- compiler.stack_assign(vector_out);
+ float value;
+ float3 vector;
- /* Optimize vector math node without links to a single value node. */
if(vector1_in->link == NULL && vector2_in->link == NULL) {
- float optimized_value;
- float3 optimized_vector;
- svm_vector_math(&optimized_value,
- &optimized_vector,
+ svm_vector_math(&value,
+ &vector,
(NodeVectorMath)type_enum[type],
vector1_in->value,
vector2_in->value);
- compiler.add_node(NODE_VALUE_F,
- __float_as_int(optimized_value),
- value_out->stack_offset);
-
- compiler.add_node(NODE_VALUE_V, vector_out->stack_offset);
- compiler.add_node(NODE_VALUE_V, optimized_vector);
- return;
+ if(socket == output("Value")) {
+ optimized_value->x = value;
+ return true;
+ }
+ else if(socket == output("Vector")) {
+ *optimized_value = vector;
+ return true;
+ }
}
+ return false;
+}
+
+void VectorMathNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *vector1_in = input("Vector1");
+ ShaderInput *vector2_in = input("Vector2");
+ ShaderOutput *value_out = output("Value");
+ ShaderOutput *vector_out = output("Vector");
+
+ compiler.stack_assign(value_out);
+ compiler.stack_assign(vector_out);
+
compiler.stack_assign(vector1_in);
compiler.stack_assign(vector2_in);
@@ -4196,6 +4417,9 @@ RGBCurvesNode::RGBCurvesNode()
add_input("Fac", SHADER_SOCKET_FLOAT);
add_input("Color", SHADER_SOCKET_COLOR);
add_output("Color", SHADER_SOCKET_COLOR);
+
+ min_x = 0.0f;
+ max_x = 1.0f;
}
void RGBCurvesNode::compile(SVMCompiler& compiler)
@@ -4208,7 +4432,12 @@ void RGBCurvesNode::compile(SVMCompiler& compiler)
compiler.stack_assign(color_in);
compiler.stack_assign(color_out);
- compiler.add_node(NODE_RGB_CURVES, fac_in->stack_offset, color_in->stack_offset, color_out->stack_offset);
+ compiler.add_node(NODE_RGB_CURVES,
+ compiler.encode_uchar4(fac_in->stack_offset,
+ color_in->stack_offset,
+ color_out->stack_offset),
+ __float_as_int(min_x),
+ __float_as_int(max_x));
compiler.add_array(curves, RAMP_TABLE_SIZE);
}
@@ -4223,6 +4452,8 @@ void RGBCurvesNode::compile(OSLCompiler& compiler)
}
compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
+ compiler.parameter("min_x", min_x);
+ compiler.parameter("max_x", max_x);
compiler.add(this, "node_rgb_curves");
}
@@ -4234,6 +4465,9 @@ VectorCurvesNode::VectorCurvesNode()
add_input("Fac", SHADER_SOCKET_FLOAT);
add_input("Vector", SHADER_SOCKET_VECTOR);
add_output("Vector", SHADER_SOCKET_VECTOR);
+
+ min_x = 0.0f;
+ max_x = 1.0f;
}
void VectorCurvesNode::compile(SVMCompiler& compiler)
@@ -4246,7 +4480,12 @@ void VectorCurvesNode::compile(SVMCompiler& compiler)
compiler.stack_assign(vector_in);
compiler.stack_assign(vector_out);
- compiler.add_node(NODE_VECTOR_CURVES, fac_in->stack_offset, vector_in->stack_offset, vector_out->stack_offset);
+ compiler.add_node(NODE_VECTOR_CURVES,
+ compiler.encode_uchar4(fac_in->stack_offset,
+ vector_in->stack_offset,
+ vector_out->stack_offset),
+ __float_as_int(min_x),
+ __float_as_int(max_x));
compiler.add_array(curves, RAMP_TABLE_SIZE);
}
@@ -4261,6 +4500,8 @@ void VectorCurvesNode::compile(OSLCompiler& compiler)
}
compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
+ compiler.parameter("min_x", min_x);
+ compiler.parameter("max_x", max_x);
compiler.add(this, "node_vector_curves");
}
@@ -4358,26 +4599,6 @@ void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
void OSLScriptNode::compile(OSLCompiler& compiler)
{
- /* XXX fix for #36790:
- * point and normal parameters are reflected as generic SOCK_VECTOR sockets
- * on the node. Socket fixed input values need to be copied explicitly here for
- * vector sockets, otherwise OSL will reject the value due to mismatching type.
- */
- foreach(ShaderInput *input, this->inputs) {
- if(!input->link) {
- /* no need for compatible_name here, OSL parameter names are always unique */
- string param_name(input->name);
- switch(input->type) {
- case SHADER_SOCKET_VECTOR:
- compiler.parameter_point(param_name.c_str(), input->value);
- compiler.parameter_normal(param_name.c_str(), input->value);
- break;
- default:
- break;
- }
- }
- }
-
if(!filepath.empty())
compiler.add(this, filepath.c_str(), true);
else
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 5065e68345a..7400770d60a 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -24,6 +24,7 @@
CCL_NAMESPACE_BEGIN
class ImageManager;
+class Scene;
class Shader;
/* Texture Mapping */
@@ -51,6 +52,20 @@ public:
enum Projection { FLAT, CUBE, TUBE, SPHERE };
Projection projection;
+
+ bool equals(const TextureMapping& other) {
+ return translation == other.translation &&
+ rotation == other.rotation &&
+ scale == other.scale &&
+ use_minmax == other.use_minmax &&
+ min == other.min &&
+ max == other.max &&
+ type == other.type &&
+ x_mapping == other.x_mapping &&
+ y_mapping == other.y_mapping &&
+ z_mapping == other.z_mapping &&
+ projection == other.projection;
+ }
};
/* Nodes */
@@ -68,12 +83,22 @@ class TextureNode : public ShaderNode {
public:
TextureNode(const char *name_) : ShaderNode(name_) {}
TextureMapping tex_mapping;
+
+ virtual bool equals(const ShaderNode *other) {
+ return ShaderNode::equals(other) &&
+ tex_mapping.equals(((const TextureNode*)other)->tex_mapping);
+ }
};
class ImageSlotTextureNode : public ImageSlotNode {
public:
ImageSlotTextureNode(const char *name_) : ImageSlotNode(name_) {}
TextureMapping tex_mapping;
+
+ virtual bool equals(const ShaderNode *other) {
+ return ShaderNode::equals(other) &&
+ tex_mapping.equals(((const ImageSlotTextureNode*)other)->tex_mapping);
+ }
};
class ImageTextureNode : public ImageSlotTextureNode {
@@ -98,6 +123,20 @@ public:
static ShaderEnum color_space_enum;
static ShaderEnum projection_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const ImageTextureNode *image_node = (const ImageTextureNode*)other;
+ return ImageSlotTextureNode::equals(other) &&
+ use_alpha == image_node->use_alpha &&
+ filename == image_node->filename &&
+ builtin_data == image_node->builtin_data &&
+ color_space == image_node->color_space &&
+ projection == image_node->projection &&
+ interpolation == image_node->interpolation &&
+ extension == image_node->extension &&
+ projection_blend == image_node->projection_blend &&
+ animated == image_node->animated;
+ }
};
class EnvironmentTextureNode : public ImageSlotTextureNode {
@@ -116,10 +155,23 @@ public:
void *builtin_data;
ustring color_space;
ustring projection;
+ InterpolationType interpolation;
bool animated;
static ShaderEnum color_space_enum;
static ShaderEnum projection_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const EnvironmentTextureNode *env_node = (const EnvironmentTextureNode*)other;
+ return ImageSlotTextureNode::equals(other) &&
+ use_alpha == env_node->use_alpha &&
+ filename == env_node->filename &&
+ builtin_data == env_node->builtin_data &&
+ color_space == env_node->color_space &&
+ projection == env_node->projection &&
+ interpolation == env_node->interpolation &&
+ animated == env_node->animated;
+ }
};
class SkyTextureNode : public TextureNode {
@@ -131,14 +183,26 @@ public:
float3 sun_direction;
float turbidity;
float ground_albedo;
-
+
ustring type;
static ShaderEnum type_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const SkyTextureNode *sky_node = (const SkyTextureNode*)other;
+ return TextureNode::equals(other) &&
+ sun_direction == sky_node->sun_direction &&
+ turbidity == sky_node->turbidity &&
+ ground_albedo == sky_node->ground_albedo &&
+ type == sky_node->type;
+ }
};
class OutputNode : public ShaderNode {
public:
SHADER_NODE_CLASS(OutputNode)
+
+ /* Don't allow output node de-duplication. */
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
};
class GradientTextureNode : public TextureNode {
@@ -149,6 +213,12 @@ public:
ustring type;
static ShaderEnum type_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const GradientTextureNode *gradient_node = (const GradientTextureNode*)other;
+ return TextureNode::equals(other) &&
+ type == gradient_node->type;
+ }
};
class NoiseTextureNode : public TextureNode {
@@ -165,6 +235,12 @@ public:
ustring coloring;
static ShaderEnum coloring_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const VoronoiTextureNode *voronoi_node = (const VoronoiTextureNode*)other;
+ return TextureNode::equals(other) &&
+ coloring == voronoi_node->coloring;
+ }
};
class MusgraveTextureNode : public TextureNode {
@@ -176,6 +252,12 @@ public:
ustring type;
static ShaderEnum type_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const MusgraveTextureNode *musgrave_node = (const MusgraveTextureNode*)other;
+ return TextureNode::equals(other) &&
+ type == musgrave_node->type;
+ }
};
class WaveTextureNode : public TextureNode {
@@ -185,7 +267,16 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
ustring type;
+ ustring profile;
static ShaderEnum type_enum;
+ static ShaderEnum profile_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const WaveTextureNode *wave_node = (const WaveTextureNode*)other;
+ return TextureNode::equals(other) &&
+ type == wave_node->type &&
+ profile == wave_node->profile;
+ }
};
class MagicTextureNode : public TextureNode {
@@ -195,6 +286,12 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
int depth;
+
+ virtual bool equals(const ShaderNode *other) {
+ const MagicTextureNode *magic_node = (const MagicTextureNode*)other;
+ return TextureNode::equals(other) &&
+ depth == magic_node->depth;
+ }
};
class CheckerTextureNode : public TextureNode {
@@ -207,11 +304,20 @@ public:
class BrickTextureNode : public TextureNode {
public:
SHADER_NODE_CLASS(BrickTextureNode)
-
+
float offset, squash;
int offset_frequency, squash_frequency;
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
+
+ virtual bool equals(const ShaderNode *other) {
+ const BrickTextureNode *brick_node = (const BrickTextureNode*)other;
+ return TextureNode::equals(other) &&
+ offset == brick_node->offset &&
+ squash == brick_node->squash &&
+ offset_frequency == brick_node->offset_frequency &&
+ squash_frequency == brick_node->squash_frequency;
+ }
};
class PointDensityTextureNode : public ShaderNode {
@@ -235,6 +341,16 @@ public:
Transform tfm;
static ShaderEnum space_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const PointDensityTextureNode *point_dendity_node = (const PointDensityTextureNode*)other;
+ return ShaderNode::equals(other) &&
+ filename == point_dendity_node->filename &&
+ space == point_dendity_node->space &&
+ builtin_data == point_dendity_node->builtin_data &&
+ interpolation == point_dendity_node->interpolation &&
+ tfm == point_dendity_node->tfm;
+ }
};
class MappingNode : public ShaderNode {
@@ -243,6 +359,12 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
TextureMapping tex_mapping;
+
+ virtual bool equals(const ShaderNode *other) {
+ const MappingNode *mapping_node = (const MappingNode*)other;
+ return ShaderNode::equals(other) &&
+ tex_mapping.equals(mapping_node->tex_mapping);
+ }
};
class ConvertNode : public ShaderNode {
@@ -250,7 +372,17 @@ public:
ConvertNode(ShaderSocketType from, ShaderSocketType to, bool autoconvert = false);
SHADER_NODE_BASE_CLASS(ConvertNode)
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+
ShaderSocketType from, to;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const ConvertNode *convert_node = (const ConvertNode*)other;
+ return ShaderNode::equals(other) &&
+ from == convert_node->from &&
+ to == convert_node->to;
+ }
};
class ProxyNode : public ShaderNode {
@@ -259,6 +391,15 @@ public:
SHADER_NODE_BASE_CLASS(ProxyNode)
ShaderSocketType type;
+
+ virtual bool equals(const ShaderNode * /*other*/)
+ {
+ /* Proxy nodes are created for node groups and can't be duplicated
+ * actually. So in order to make code a bit more robust in obscure cases
+ * lets explicitly forbid de-duplication of proxy nodes for now.
+ */
+ return false;
+ }
};
class BsdfNode : public ShaderNode {
@@ -271,6 +412,12 @@ public:
ClosureType closure;
bool scattering;
+
+ virtual bool equals(const ShaderNode * /*other*/)
+ {
+ /* TODO(sergey): With some care BSDF nodes can be de-duplicated. */
+ return false;
+ }
};
class AnisotropicBsdfNode : public BsdfNode {
@@ -309,7 +456,10 @@ class GlossyBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlossyBsdfNode)
- ustring distribution;
+ void simplify_settings(Scene *scene);
+ bool has_integrator_dependency();
+
+ ustring distribution, distribution_orig;
static ShaderEnum distribution_enum;
};
@@ -317,7 +467,10 @@ class GlassBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlassBsdfNode)
- ustring distribution;
+ void simplify_settings(Scene *scene);
+ bool has_integrator_dependency();
+
+ ustring distribution, distribution_orig;
static ShaderEnum distribution_enum;
};
@@ -325,7 +478,10 @@ class RefractionBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(RefractionBsdfNode)
- ustring distribution;
+ void simplify_settings(Scene *scene);
+ bool has_integrator_dependency();
+
+ ustring distribution, distribution_orig;
static ShaderEnum distribution_enum;
};
@@ -342,7 +498,6 @@ public:
SHADER_NODE_CLASS(SubsurfaceScatteringNode)
bool has_surface_bssrdf() { return true; }
bool has_bssrdf_bump();
- bool has_spatial_varying() { return true; }
static ShaderEnum falloff_enum;
};
@@ -382,6 +537,12 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
ClosureType closure;
+
+ virtual bool equals(const ShaderNode * /*other*/)
+ {
+ /* TODO(sergey): With some care Volume nodes can be de-duplicated. */
+ return false;
+ }
};
class AbsorptionVolumeNode : public VolumeNode {
@@ -420,6 +581,14 @@ public:
bool from_dupli;
bool use_transform;
Transform ob_tfm;
+
+ virtual bool equals(const ShaderNode *other) {
+ const TextureCoordinateNode *texco_node = (const TextureCoordinateNode*)other;
+ return ShaderNode::equals(other) &&
+ from_dupli == texco_node->from_dupli &&
+ use_transform == texco_node->use_transform &&
+ ob_tfm == texco_node->ob_tfm;
+ }
};
class UVMapNode : public ShaderNode {
@@ -431,6 +600,13 @@ public:
ustring attribute;
bool from_dupli;
+
+ virtual bool equals(const ShaderNode *other) {
+ const UVMapNode *uv_map_node = (const UVMapNode*)other;
+ return ShaderNode::equals(other) &&
+ attribute == uv_map_node->attribute &&
+ from_dupli == uv_map_node->from_dupli;
+ }
};
class LightPathNode : public ShaderNode {
@@ -443,6 +619,7 @@ class LightFalloffNode : public ShaderNode {
public:
SHADER_NODE_CLASS(LightFalloffNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
class ObjectInfoNode : public ShaderNode {
@@ -474,14 +651,30 @@ class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+
float value;
+
+ virtual bool equals(const ShaderNode *other) {
+ const ValueNode *value_node = (const ValueNode*)other;
+ return ShaderNode::equals(other) &&
+ value == value_node->value;
+ }
};
class ColorNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ColorNode)
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+
float3 value;
+
+ virtual bool equals(const ShaderNode *other) {
+ const ColorNode *color_node = (const ColorNode*)other;
+ return ShaderNode::equals(other) &&
+ value == color_node->value;
+ }
};
class AddClosureNode : public ShaderNode {
@@ -516,6 +709,14 @@ public:
ustring type;
static ShaderEnum type_enum;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const MixNode *mix_node = (const MixNode*)other;
+ return ShaderNode::equals(other) &&
+ use_clamp == mix_node->use_clamp &&
+ type == mix_node->type;
+ }
};
class CombineRGBNode : public ShaderNode {
@@ -542,6 +743,9 @@ public:
class GammaNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GammaNode)
+
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
+
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
@@ -584,6 +788,12 @@ public:
bool has_spatial_varying() { return true; }
ustring attribute;
+
+ virtual bool equals(const ShaderNode *other) {
+ const AttributeNode *color_node = (const AttributeNode*)other;
+ return ShaderNode::equals(other) &&
+ attribute == color_node->attribute;
+ }
};
class CameraNode : public ShaderNode {
@@ -611,7 +821,7 @@ public:
SHADER_NODE_CLASS(WireframeNode)
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
-
+
bool use_pixel_size;
};
@@ -625,6 +835,7 @@ public:
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
@@ -633,11 +844,20 @@ class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
bool use_clamp;
ustring type;
static ShaderEnum type_enum;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const MathNode *math_node = (const MathNode*)other;
+ return ShaderNode::equals(other) &&
+ use_clamp == math_node->use_clamp &&
+ type == math_node->type;
+ }
};
class NormalNode : public ShaderNode {
@@ -646,15 +866,30 @@ public:
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
float3 direction;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const NormalNode *normal_node = (const NormalNode*)other;
+ return ShaderNode::equals(other) &&
+ direction == normal_node->direction;
+ }
};
class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
ustring type;
static ShaderEnum type_enum;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const MathNode *math_node = (const MathNode*)other;
+ return ShaderNode::equals(other) &&
+ type == math_node->type;
+ }
};
class VectorTransformNode : public ShaderNode {
@@ -666,9 +901,17 @@ public:
ustring type;
ustring convert_from;
ustring convert_to;
-
+
static ShaderEnum type_enum;
static ShaderEnum convert_space_enum;
+
+ virtual bool equals(const ShaderNode *other) {
+ const VectorTransformNode *vector_transform_node = (const VectorTransformNode*)other;
+ return ShaderNode::equals(other) &&
+ type == vector_transform_node->type &&
+ convert_from == vector_transform_node->convert_from &&
+ convert_to == vector_transform_node->convert_to;
+ }
};
class BumpNode : public ShaderNode {
@@ -680,6 +923,12 @@ public:
}
bool invert;
+
+ virtual bool equals(const ShaderNode *other) {
+ const BumpNode *bump_node = (const BumpNode*)other;
+ return ShaderNode::equals(other) &&
+ invert == bump_node->invert;
+ }
};
class RGBCurvesNode : public ShaderNode {
@@ -687,8 +936,10 @@ public:
SHADER_NODE_CLASS(RGBCurvesNode)
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
float4 curves[RAMP_TABLE_SIZE];
+ float min_x, max_x;
};
class VectorCurvesNode : public ShaderNode {
@@ -696,8 +947,10 @@ public:
SHADER_NODE_CLASS(VectorCurvesNode)
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
float4 curves[RAMP_TABLE_SIZE];
+ float min_x, max_x;
};
class RGBRampNode : public ShaderNode {
@@ -706,6 +959,7 @@ public:
float4 ramp[RAMP_TABLE_SIZE];
bool interpolate;
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
};
class SetNormalNode : public ShaderNode {
@@ -722,11 +976,13 @@ public:
string filepath;
string bytecode_hash;
-
+
/* ShaderInput/ShaderOutput only stores a shallow string copy (const char *)!
* The actual socket names have to be stored externally to avoid memory errors. */
vector<ustring> input_names;
vector<ustring> output_names;
+
+ virtual bool equals(const ShaderNode * /*other*/) { return false; }
};
class NormalMapNode : public ShaderNode {
@@ -740,6 +996,14 @@ public:
static ShaderEnum space_enum;
ustring attribute;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const NormalMapNode *normal_map_node = (const NormalMapNode*)other;
+ return ShaderNode::equals(other) &&
+ space == normal_map_node->space &&
+ attribute == normal_map_node->attribute;
+ }
};
class TangentNode : public ShaderNode {
@@ -756,6 +1020,15 @@ public:
static ShaderEnum axis_enum;
ustring attribute;
+
+ virtual bool equals(const ShaderNode *other)
+ {
+ const TangentNode *tangent_node = (const TangentNode*)other;
+ return ShaderNode::equals(other) &&
+ direction_type == tangent_node->direction_type &&
+ axis == tangent_node->axis &&
+ attribute == tangent_node->attribute;
+ }
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index ec85aa8f80b..42bb665cb9f 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -512,7 +512,12 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
/* apply transforms for objects with single user meshes */
foreach(Object *object, scene->objects) {
- if(mesh_users[object->mesh] == 1 &&
+ /* Annoying feedback loop here: we can't use is_instanced() because
+ * it'll use uninitialized transform_applied flag.
+ *
+ * Could be solved by moving reference counter to Mesh.
+ */
+ if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
{
if(!(motion_blur && object->use_motion)) {
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index a02f91ad2cf..e1c5416b024 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -100,7 +100,7 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
compiler.background = (shader == scene->shaders[scene->default_background]);
- compiler.compile(og, shader);
+ compiler.compile(scene, og, shader);
if(shader->use_mis && shader->has_surface_emission)
scene->light_manager->need_update = true;
@@ -125,11 +125,21 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
device_update_common(device, dscene, scene, progress);
- /* greedyjit test
{
+ /* Perform greedyjit optimization.
+ *
+ * This might waste time on optimizing gorups which are never actually
+ * used, but this prevents OSL from allocating data on TLS at render
+ * time.
+ *
+ * This is much better for us because this way we aren't required to
+ * stop task scheduler threads to make sure all TLS is clean and don't
+ * have issues with TLS data free accessing freed memory if task scheduler
+ * is being freed after the Session is freed.
+ */
thread_scoped_lock lock(ss_shared_mutex);
ss->optimize_all_groups();
- }*/
+ }
}
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
@@ -176,6 +186,7 @@ void OSLShaderManager::texture_system_free()
ts_shared_users--;
if(ts_shared_users == 0) {
+ ts_shared->invalidate_all(true);
OSL::TextureSystem::destroy(ts_shared);
ts_shared = NULL;
}
@@ -191,13 +202,26 @@ void OSLShaderManager::shading_system_init()
if(ss_shared_users == 0) {
services_shared = new OSLRenderServices();
+ string shader_path = path_get("shader");
+#ifdef _WIN32
+ /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
+ * operate with file paths with any character. This requires to use wide
+ * char functions, but OSL uses old fashioned ANSI functions which means:
+ *
+ * - We have to convert our paths to ANSI before passing to OSL
+ * - OSL can't be used when there's a multi-byte character in the path
+ * to the shaders folder.
+ */
+ shader_path = string_to_ansi(shader_path);
+#endif
+
ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
ss_shared->attribute("lockgeom", 1);
ss_shared->attribute("commonspace", "world");
- ss_shared->attribute("searchpath:shader", path_get("shader"));
- //ss_shared->attribute("greedyjit", 1);
+ ss_shared->attribute("searchpath:shader", shader_path);
+ ss_shared->attribute("greedyjit", 1);
- VLOG(1) << "Using shader search path: " << path_get("shader");
+ VLOG(1) << "Using shader search path: " << shader_path;
/* our own ray types */
static const char *raytypes[] = {
@@ -253,11 +277,7 @@ void OSLShaderManager::shading_system_free()
bool OSLShaderManager::osl_compile(const string& inputfile, const string& outputfile)
{
-#if OSL_LIBRARY_VERSION_CODE < 10602
- vector<string_view> options;
-#else
vector<string> options;
-#endif
string stdosl_path;
string shader_path = path_get("shader");
@@ -272,7 +292,7 @@ bool OSLShaderManager::osl_compile(const string& inputfile, const string& output
stdosl_path = path_get("shader/stdosl.h");
/* compile */
- OSL::OSLCompiler *compiler = new OSL::OSLCompiler();
+ OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path));
delete compiler;
@@ -555,24 +575,34 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
/* test if we shader contains specific closures */
OSLShaderInfo *info = ((OSLShaderManager*)manager)->shader_loaded_info(name);
- if(info && current_type == SHADER_TYPE_SURFACE) {
- if(info->has_surface_emission)
- current_shader->has_surface_emission = true;
- if(info->has_surface_transparent)
- current_shader->has_surface_transparent = true;
- if(info->has_surface_bssrdf) {
- current_shader->has_surface_bssrdf = true;
- current_shader->has_bssrdf_bump = true; /* can't detect yet */
+ if(current_type == SHADER_TYPE_SURFACE) {
+ if(info) {
+ if(info->has_surface_emission)
+ current_shader->has_surface_emission = true;
+ if(info->has_surface_transparent)
+ current_shader->has_surface_transparent = true;
+ if(info->has_surface_bssrdf) {
+ current_shader->has_surface_bssrdf = true;
+ current_shader->has_bssrdf_bump = true; /* can't detect yet */
+ }
+ }
+
+ if(node->has_spatial_varying()) {
+ current_shader->has_surface_spatial_varying = true;
}
}
else if(current_type == SHADER_TYPE_VOLUME) {
if(node->has_spatial_varying())
- current_shader->has_heterogeneous_volume = true;
+ current_shader->has_volume_spatial_varying = true;
}
if(node->has_object_dependency()) {
current_shader->has_object_dependency = true;
}
+
+ if(node->has_integrator_dependency()) {
+ current_shader->has_integrator_dependency = true;
+ }
}
void OSLCompiler::parameter(const char *name, float f)
@@ -694,11 +724,11 @@ void OSLCompiler::parameter_array(const char *name, const Transform tfm[], int a
ss->Parameter(name, type, (const float *)tfm);
}
-void OSLCompiler::find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input)
+void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
{
ShaderNode *node = (input->link)? input->link->parent: NULL;
- if(node) {
+ if(node != NULL && dependencies.find(node) == dependencies.end()) {
foreach(ShaderInput *in, node->inputs)
if(!node_skip_input(node, in))
find_dependencies(dependencies, in);
@@ -707,9 +737,9 @@ void OSLCompiler::find_dependencies(set<ShaderNode*>& dependencies, ShaderInput
}
}
-void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
+void OSLCompiler::generate_nodes(const ShaderNodeSet& nodes)
{
- set<ShaderNode*> done;
+ ShaderNodeSet done;
bool nodes_done;
do {
@@ -733,6 +763,8 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
current_shader->has_surface_emission = true;
if(node->has_surface_transparent())
current_shader->has_surface_transparent = true;
+ if(node->has_spatial_varying())
+ current_shader->has_surface_spatial_varying = true;
if(node->has_surface_bssrdf()) {
current_shader->has_surface_bssrdf = true;
if(node->has_bssrdf_bump())
@@ -741,7 +773,7 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
}
else if(current_type == SHADER_TYPE_VOLUME) {
if(node->has_spatial_varying())
- current_shader->has_heterogeneous_volume = true;
+ current_shader->has_volume_spatial_varying = true;
}
}
else
@@ -751,16 +783,16 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
} while(!nodes_done);
}
-OSL::ShadingAttribStateRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
+OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
{
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
current_type = type;
- OSL::ShadingAttribStateRef group = ss->ShaderGroupBegin(shader->name.c_str());
+ OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
ShaderNode *output = graph->output();
- set<ShaderNode*> dependencies;
+ ShaderNodeSet dependencies;
if(type == SHADER_TYPE_SURFACE) {
/* generate surface shader */
@@ -788,7 +820,7 @@ OSL::ShadingAttribStateRef OSLCompiler::compile_type(Shader *shader, ShaderGraph
return group;
}
-void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
+void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
{
if(shader->need_update) {
ShaderGraph *graph = shader->graph;
@@ -800,9 +832,16 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->graph_bump = shader->graph->copy();
/* finalize */
- shader->graph->finalize(false, true);
- if(shader->graph_bump)
- shader->graph_bump->finalize(true, true);
+ shader->graph->finalize(scene,
+ false,
+ true,
+ shader->has_integrator_dependency);
+ if(shader->graph_bump) {
+ shader->graph_bump->finalize(scene,
+ true,
+ true,
+ shader->has_integrator_dependency);
+ }
current_shader = shader;
@@ -813,8 +852,10 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_bssrdf_bump = false;
shader->has_volume = false;
shader->has_displacement = false;
- shader->has_heterogeneous_volume = false;
+ shader->has_surface_spatial_varying = false;
+ shader->has_volume_spatial_varying = false;
shader->has_object_dependency = false;
+ shader->has_integrator_dependency = false;
/* generate surface shader */
if(shader->used && graph && output->input("Surface")->link) {
@@ -828,8 +869,8 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_surface = true;
}
else {
- shader->osl_surface_ref = OSL::ShadingAttribStateRef();
- shader->osl_surface_bump_ref = OSL::ShadingAttribStateRef();
+ shader->osl_surface_ref = OSL::ShaderGroupRef();
+ shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
}
/* generate volume shader */
@@ -838,7 +879,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_volume = true;
}
else
- shader->osl_volume_ref = OSL::ShadingAttribStateRef();
+ shader->osl_volume_ref = OSL::ShaderGroupRef();
/* generate displacement shader */
if(shader->used && graph && output->input("Displacement")->link) {
@@ -846,7 +887,7 @@ void OSLCompiler::compile(OSLGlobals *og, Shader *shader)
shader->has_displacement = true;
}
else
- shader->osl_displacement_ref = OSL::ShadingAttribStateRef();
+ shader->osl_displacement_ref = OSL::ShaderGroupRef();
}
/* push state to array for lookup */
diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h
index bc6a9d8fbbd..ac985a84eef 100644
--- a/intern/cycles/render/osl.h
+++ b/intern/cycles/render/osl.h
@@ -21,6 +21,7 @@
#include "util_string.h"
#include "util_thread.h"
+#include "graph.h"
#include "shader.h"
#ifdef WITH_OSL
@@ -113,7 +114,7 @@ protected:
class OSLCompiler {
public:
OSLCompiler(void *manager, void *shadingsys, ImageManager *image_manager);
- void compile(OSLGlobals *og, Shader *shader);
+ void compile(Scene *scene, OSLGlobals *og, Shader *shader);
void add(ShaderNode *node, const char *name, bool isfilepath = false);
@@ -144,13 +145,13 @@ public:
private:
#ifdef WITH_OSL
string id(ShaderNode *node);
- OSL::ShadingAttribStateRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
+ OSL::ShaderGroupRef compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
bool node_skip_input(ShaderNode *node, ShaderInput *input);
string compatible_name(ShaderNode *node, ShaderInput *input);
string compatible_name(ShaderNode *node, ShaderOutput *output);
- void find_dependencies(set<ShaderNode*>& dependencies, ShaderInput *input);
- void generate_nodes(const set<ShaderNode*>& nodes);
+ void find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input);
+ void generate_nodes(const ShaderNodeSet& nodes);
#endif
void *shadingsys;
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index 19d715d834b..29163c53109 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -34,13 +34,10 @@
#include "tables.h"
#include "util_foreach.h"
+#include "util_guarded_allocator.h"
+#include "util_logging.h"
#include "util_progress.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "util_guarded_allocator.h"
-# include "util_logging.h"
-#endif
-
CCL_NAMESPACE_BEGIN
Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
@@ -57,7 +54,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
mesh_manager = new MeshManager();
object_manager = new ObjectManager();
integrator = new Integrator();
- image_manager = new ImageManager();
+ image_manager = new ImageManager(device_info_);
particle_system_manager = new ParticleSystemManager();
curve_system_manager = new CurveSystemManager();
bake_manager = new BakeManager();
@@ -67,9 +64,6 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
shader_manager = ShaderManager::create(this, params.shadingsystem);
else
shader_manager = ShaderManager::create(this, SHADINGSYSTEM_SVM);
-
- /* Extended image limits for CPU and GPUs */
- image_manager->set_extended_image_limits(device_info_);
}
Scene::~Scene()
@@ -97,7 +91,7 @@ void Scene::free_memory(bool final)
particle_systems.clear();
if(device) {
- camera->device_free(device, &dscene);
+ camera->device_free(device, &dscene, this);
film->device_free(device, &dscene, this);
background->device_free(device, &dscene);
integrator->device_free(device, &dscene);
@@ -170,13 +164,13 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Objects");
- object_manager->device_update(device, &dscene, this, progress);
+ progress.set_status("Updating Meshes Flags");
+ mesh_manager->device_update_flags(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Meshes Flags");
- mesh_manager->device_update_flags(device, &dscene, this, progress);
+ progress.set_status("Updating Objects");
+ object_manager->device_update(device, &dscene, this, progress);
if(progress.get_cancel() || device->have_error()) return;
@@ -220,13 +214,13 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Film");
- film->device_update(device, &dscene, this);
+ progress.set_status("Updating Integrator");
+ integrator->device_update(device, &dscene, this);
if(progress.get_cancel() || device->have_error()) return;
- progress.set_status("Updating Integrator");
- integrator->device_update(device, &dscene, this);
+ progress.set_status("Updating Film");
+ film->device_update(device, &dscene, this);
if(progress.get_cancel() || device->have_error()) return;
@@ -245,11 +239,9 @@ void Scene::device_update(Device *device_, Progress& progress)
device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
}
-#ifdef WITH_CYCLES_DEBUG
VLOG(1) << "System memory statistics after full device sync:\n"
<< " Usage: " << util_guarded_get_mem_used() << "\n"
<< " Peak: " << util_guarded_get_mem_peak();
-#endif
}
Scene::MotionType Scene::need_motion(bool advanced_shading)
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 851e5ac0b72..d30a0cb45fe 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -22,11 +22,10 @@
#include "device_memory.h"
-#include "kernel_types.h"
-
#include "util_param.h"
#include "util_string.h"
#include "util_system.h"
+#include "util_texture.h"
#include "util_thread.h"
#include "util_types.h"
#include "util_vector.h"
@@ -64,7 +63,7 @@ public:
device_vector<float4> bvh_nodes;
device_vector<float4> bvh_leaf_nodes;
device_vector<uint> object_node;
- device_vector<float4> tri_woop;
+ device_vector<float4> tri_storage;
device_vector<uint> prim_type;
device_vector<uint> prim_visibility;
device_vector<uint> prim_index;
@@ -110,8 +109,8 @@ public:
device_vector<uint> sobol_directions;
/* cpu images */
- device_vector<uchar4> tex_image[TEX_EXTENDED_NUM_IMAGES_CPU];
- device_vector<float4> tex_float_image[TEX_EXTENDED_NUM_FLOAT_IMAGES];
+ device_vector<uchar4> tex_image[TEX_NUM_BYTE_IMAGES_CPU];
+ device_vector<float4> tex_float_image[TEX_NUM_FLOAT_IMAGES_CPU];
/* opencl images */
device_vector<uchar4> tex_image_packed;
@@ -125,8 +124,12 @@ public:
class SceneParams {
public:
ShadingSystem shadingsystem;
- enum BVHType { BVH_DYNAMIC, BVH_STATIC } bvh_type;
- bool use_bvh_cache;
+ enum BVHType {
+ BVH_DYNAMIC = 0,
+ BVH_STATIC = 1,
+
+ BVH_NUM_TYPES,
+ } bvh_type;
bool use_bvh_spatial_split;
bool use_qbvh;
bool persistent_data;
@@ -135,7 +138,6 @@ public:
{
shadingsystem = SHADINGSYSTEM_SVM;
bvh_type = BVH_DYNAMIC;
- use_bvh_cache = false;
use_bvh_spatial_split = false;
use_qbvh = false;
persistent_data = false;
@@ -144,7 +146,6 @@ public:
bool modified(const SceneParams& params)
{ return !(shadingsystem == params.shadingsystem
&& bvh_type == params.bvh_type
- && use_bvh_cache == params.use_bvh_cache
&& use_bvh_spatial_split == params.use_bvh_spatial_split
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); }
diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp
index 837c2694894..24f48b61349 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -619,8 +619,7 @@ DeviceRequestedFeatures Session::get_requested_device_features()
requested_features.max_closure = get_max_closure_count();
scene->shader_manager->get_requested_features(
scene,
- requested_features.max_nodes_group,
- requested_features.nodes_features);
+ &requested_features);
}
/* This features are not being tweaked as often as shaders,
@@ -640,6 +639,7 @@ DeviceRequestedFeatures Session::get_requested_device_features()
BakeManager *bake_manager = scene->bake_manager;
requested_features.use_baking = bake_manager->get_baking();
+ requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH);
return requested_features;
}
@@ -831,7 +831,8 @@ void Session::update_status_time(bool show_pause, bool show_done)
string status, substatus;
if(!params.progressive) {
- const int progress_sample = progress.get_sample(), num_samples = tile_manager.num_samples;
+ const int progress_sample = progress.get_sample(),
+ num_samples = tile_manager.get_num_effective_samples();
const bool is_gpu = params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL;
const bool is_multidevice = params.device.multi_devices.size() > 1;
const bool is_cpu = params.device.type == DEVICE_CPU;
@@ -870,10 +871,12 @@ void Session::update_status_time(bool show_pause, bool show_done)
substatus += string_printf(", Sample %d/%d", status_sample, num_samples);
}
}
- else if(tile_manager.num_samples == USHRT_MAX)
+ else if(tile_manager.num_samples == INT_MAX)
substatus = string_printf("Path Tracing Sample %d", sample+1);
else
- substatus = string_printf("Path Tracing Sample %d/%d", sample+1, tile_manager.num_samples);
+ substatus = string_printf("Path Tracing Sample %d/%d",
+ sample+1,
+ tile_manager.get_num_effective_samples());
if(show_pause) {
status = "Paused";
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index c669bccd34b..02d97ce9a87 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -72,7 +72,7 @@ public:
progressive = false;
experimental = false;
- samples = USHRT_MAX;
+ samples = INT_MAX;
tile_size = make_int2(64, 64);
start_resolution = INT_MAX;
threads = 0;
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index aba3e7237d2..09a6061abea 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -152,8 +152,10 @@ Shader::Shader()
has_volume = false;
has_displacement = false;
has_bssrdf_bump = false;
- has_heterogeneous_volume = false;
+ has_surface_spatial_varying = false;
+ has_volume_spatial_varying = false;
has_object_dependency = false;
+ has_integrator_dependency = false;
used = false;
@@ -361,7 +363,7 @@ void ShaderManager::device_update_common(Device *device,
*/
flag |= SD_HAS_TRANSPARENT_SHADOW;
}
- if(shader->heterogeneous_volume && shader->has_heterogeneous_volume)
+ if(shader->heterogeneous_volume && shader->has_volume_spatial_varying)
flag |= SD_HETEROGENEOUS_VOLUME;
if(shader->has_bssrdf_bump)
flag |= SD_HAS_BSSRDF_BUMP;
@@ -385,7 +387,7 @@ void ShaderManager::device_update_common(Device *device,
shader_flag[i++] = flag;
shader_flag[i++] = shader->pass_id;
- has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW);
+ has_transparent_shadow |= (flag & SD_HAS_TRANSPARENT_SHADOW) != 0;
}
device->tex_alloc("__shader_flag", dscene->shader_flag);
@@ -489,45 +491,50 @@ void ShaderManager::add_default(Scene *scene)
}
}
-/* NOTE: Expects max_group and features to be initialized in the callee. */
void ShaderManager::get_requested_graph_features(ShaderGraph *graph,
- int& max_group,
- int& features)
+ DeviceRequestedFeatures *requested_features)
{
foreach(ShaderNode *node, graph->nodes) {
- max_group = max(max_group, node->get_group());
- features |= node->get_feature();
+ requested_features->max_nodes_group = max(requested_features->max_nodes_group,
+ node->get_group());
+ requested_features->nodes_features |= node->get_feature();
if(node->special_type == SHADER_SPECIAL_TYPE_CLOSURE) {
BsdfNode *bsdf_node = static_cast<BsdfNode*>(node);
if(CLOSURE_IS_VOLUME(bsdf_node->closure)) {
- features |= NODE_FEATURE_VOLUME;
+ requested_features->nodes_features |= NODE_FEATURE_VOLUME;
}
}
+ if(node->has_surface_bssrdf()) {
+ requested_features->use_subsurface = true;
+ }
}
}
void ShaderManager::get_requested_features(Scene *scene,
- int& max_group,
- int& features)
+ DeviceRequestedFeatures *requested_features)
{
- max_group = NODE_GROUP_LEVEL_0;
- features = 0;
+ requested_features->max_nodes_group = NODE_GROUP_LEVEL_0;
+ requested_features->nodes_features = 0;
for(int i = 0; i < scene->shaders.size(); i++) {
Shader *shader = scene->shaders[i];
/* Gather requested features from all the nodes from the graph nodes. */
- get_requested_graph_features(shader->graph, max_group, features);
+ get_requested_graph_features(shader->graph, requested_features);
/* Gather requested features from the graph itself. */
if(shader->graph_bump) {
get_requested_graph_features(shader->graph_bump,
- max_group,
- features);
+ requested_features);
}
ShaderNode *output_node = shader->graph->output();
if(output_node->input("Displacement")->link != NULL) {
- features |= NODE_FEATURE_BUMP;
+ requested_features->nodes_features |= NODE_FEATURE_BUMP;
}
}
}
+void ShaderManager::free_memory()
+{
+ beckmann_table.free_memory();
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index 64d45635ef1..d7692a2b6f5 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -18,15 +18,8 @@
#define __SHADER_H__
#ifdef WITH_OSL
-# if defined(_MSC_VER)
-/* Prevent OSL from polluting the context with weird macros from windows.h.
- * TODO(sergey): Ideally it's only enough to have class/struct declarations in
- * the header and skip header include here.
- */
-# define NOGDI
-# define NOMINMAX
-# define WIN32_LEAN_AND_MEAN
-# endif
+/* So no context pollution happens from indirectly included windows.h */
+# include "util_windows.h"
# include <OSL/oslexec.h>
#endif
@@ -43,6 +36,7 @@ CCL_NAMESPACE_BEGIN
class Device;
class DeviceScene;
+class DeviceRequestedFeatures;
class Mesh;
class Progress;
class Scene;
@@ -59,11 +53,15 @@ enum VolumeSampling {
VOLUME_SAMPLING_DISTANCE = 0,
VOLUME_SAMPLING_EQUIANGULAR = 1,
VOLUME_SAMPLING_MULTIPLE_IMPORTANCE = 2,
+
+ VOLUME_NUM_SAMPLING,
};
enum VolumeInterpolation {
VOLUME_INTERPOLATION_LINEAR = 0,
VOLUME_INTERPOLATION_CUBIC = 1,
+
+ VOLUME_NUM_INTERPOLATION,
};
/* Shader describing the appearance of a Mesh, Light or Background.
@@ -105,8 +103,10 @@ public:
bool has_displacement;
bool has_surface_bssrdf;
bool has_bssrdf_bump;
- bool has_heterogeneous_volume;
+ bool has_surface_spatial_varying;
+ bool has_volume_spatial_varying;
bool has_object_dependency;
+ bool has_integrator_dependency;
/* requested mesh attributes */
AttributeRequestSet attributes;
@@ -116,10 +116,10 @@ public:
#ifdef WITH_OSL
/* osl shading state references */
- OSL::ShadingAttribStateRef osl_surface_ref;
- OSL::ShadingAttribStateRef osl_surface_bump_ref;
- OSL::ShadingAttribStateRef osl_volume_ref;
- OSL::ShadingAttribStateRef osl_displacement_ref;
+ OSL::ShaderGroupRef osl_surface_ref;
+ OSL::ShaderGroupRef osl_surface_bump_ref;
+ OSL::ShaderGroupRef osl_volume_ref;
+ OSL::ShaderGroupRef osl_displacement_ref;
#endif
Shader();
@@ -167,8 +167,9 @@ public:
/* Selective nodes compilation. */
void get_requested_features(Scene *scene,
- int& max_group,
- int& features);
+ DeviceRequestedFeatures *requested_features);
+
+ static void free_memory();
protected:
ShaderManager();
@@ -182,8 +183,7 @@ protected:
size_t beckmann_table_offset;
void get_requested_graph_features(ShaderGraph *graph,
- int& max_group,
- int& features);
+ DeviceRequestedFeatures *requested_features);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/sky_model.cpp b/intern/cycles/render/sky_model.cpp
deleted file mode 100644
index c8a5dbe55e0..00000000000
--- a/intern/cycles/render/sky_model.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
-This source is published under the following 3-clause BSD license.
-
-Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * None of the names of the contributors may be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
-*/
-
-/* ============================================================================
-
-This file is part of a sample implementation of the analytical skylight and
-solar radiance models presented in the SIGGRAPH 2012 paper
-
-
- "An Analytic Model for Full Spectral Sky-Dome Radiance"
-
-and the 2013 IEEE CG&A paper
-
- "Adding a Solar Radiance Function to the Hosek Skylight Model"
-
- both by
-
- Lukas Hosek and Alexander Wilkie
- Charles University in Prague, Czech Republic
-
-
- Version: 1.4a, February 22nd, 2013
-
-Version history:
-
-1.4a February 22nd, 2013
- Removed unnecessary and counter-intuitive solar radius parameters
- from the interface of the colourspace sky dome initialisation functions.
-
-1.4 February 11th, 2013
- Fixed a bug which caused the relative brightness of the solar disc
- and the sky dome to be off by a factor of about 6. The sun was too
- bright: this affected both normal and alien sun scenarios. The
- coefficients of the solar radiance function were changed to fix this.
-
-1.3 January 21st, 2013 (not released to the public)
- Added support for solar discs that are not exactly the same size as
- the terrestrial sun. Also added support for suns with a different
- emission spectrum ("Alien World" functionality).
-
-1.2a December 18th, 2012
- Fixed a mistake and some inaccuracies in the solar radiance function
- explanations found in ArHosekSkyModel.h. The actual source code is
- unchanged compared to version 1.2.
-
-1.2 December 17th, 2012
- Native RGB data and a solar radiance function that matches the turbidity
- conditions were added.
-
-1.1 September 2012
- The coefficients of the spectral model are now scaled so that the output
- is given in physical units: W / (m^-2 * sr * nm). Also, the output of the
- XYZ model is now no longer scaled to the range [0...1]. Instead, it is
- the result of a simple conversion from spectral data via the CIE 2 degree
- standard observer matching functions. Therefore, after multiplication
- with 683 lm / W, the Y channel now corresponds to luminance in lm.
-
-1.0 May 11th, 2012
- Initial release.
-
-
-Please visit http://cgg.mff.cuni.cz/projects/SkylightModelling/ to check if
-an updated version of this code has been published!
-
-============================================================================ */
-
-/*
-
-All instructions on how to use this code are in the accompanying header file.
-
-*/
-
-#include "sky_model.h"
-#include "sky_model_data.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-CCL_NAMESPACE_BEGIN
-
-// Some macro definitions that occur elsewhere in ART, and that have to be
-// replicated to make this a stand-alone module.
-
-#ifndef MATH_PI
-#define MATH_PI 3.141592653589793
-#endif
-
-#ifndef MATH_DEG_TO_RAD
-#define MATH_DEG_TO_RAD ( MATH_PI / 180.0 )
-#endif
-
-#ifndef DEGREES
-#define DEGREES * MATH_DEG_TO_RAD
-#endif
-
-#ifndef TERRESTRIAL_SOLAR_RADIUS
-#define TERRESTRIAL_SOLAR_RADIUS ( ( 0.51 DEGREES ) / 2.0 )
-#endif
-
-#ifndef ALLOC
-#define ALLOC(_struct) ((_struct *)malloc(sizeof(_struct)))
-#endif
-
-// internal definitions
-
-typedef const double *ArHosekSkyModel_Dataset;
-typedef const double *ArHosekSkyModel_Radiance_Dataset;
-
-// internal functions
-
-static void ArHosekSkyModel_CookConfiguration(
- ArHosekSkyModel_Dataset dataset,
- ArHosekSkyModelConfiguration config,
- double turbidity,
- double albedo,
- double solar_elevation)
-{
- const double * elev_matrix;
-
- int int_turbidity = (int)turbidity;
- double turbidity_rem = turbidity - (double)int_turbidity;
-
- solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
-
- // alb 0 low turb
-
- elev_matrix = dataset + ( 9 * 6 * (int_turbidity-1));
-
- for(unsigned int i = 0; i < 9; ++i) {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] =
- (1.0-albedo) * (1.0 - turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
-
- // alb 1 low turb
- elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity-1));
- for(unsigned int i = 0; i < 9; ++i) {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] +=
- (albedo) * (1.0 - turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
-
- if(int_turbidity == 10)
- return;
-
- // alb 0 high turb
- elev_matrix = dataset + (9*6*(int_turbidity));
- for(unsigned int i = 0; i < 9; ++i) {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] +=
- (1.0-albedo) * (turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
-
- // alb 1 high turb
- elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity));
- for(unsigned int i = 0; i < 9; ++i) {
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- config[i] +=
- (albedo) * (turbidity_rem)
- * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
- 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
- pow(solar_elevation, 5.0) * elev_matrix[i+45]);
- }
-}
-
-static double ArHosekSkyModel_CookRadianceConfiguration(
- ArHosekSkyModel_Radiance_Dataset dataset,
- double turbidity,
- double albedo,
- double solar_elevation)
-{
- const double* elev_matrix;
-
- int int_turbidity = (int)turbidity;
- double turbidity_rem = turbidity - (double)int_turbidity;
- double res;
- solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
-
- // alb 0 low turb
- elev_matrix = dataset + (6*(int_turbidity-1));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res = (1.0-albedo) * (1.0 - turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
-
- // alb 1 low turb
- elev_matrix = dataset + (6*10 + 6*(int_turbidity-1));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res += (albedo) * (1.0 - turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
- if(int_turbidity == 10)
- return res;
-
- // alb 0 high turb
- elev_matrix = dataset + (6*(int_turbidity));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res += (1.0-albedo) * (turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
-
- // alb 1 high turb
- elev_matrix = dataset + (6*10 + 6*(int_turbidity));
- //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
- res += (albedo) * (turbidity_rem) *
- ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
- 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
- 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
- 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
- 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
- pow(solar_elevation, 5.0) * elev_matrix[5]);
- return res;
-}
-
-static double ArHosekSkyModel_GetRadianceInternal(
- ArHosekSkyModelConfiguration configuration,
- double theta,
- double gamma)
-{
- const double expM = exp(configuration[4] * gamma);
- const double rayM = cos(gamma)*cos(gamma);
- const double mieM = (1.0 + cos(gamma)*cos(gamma)) / pow((1.0 + configuration[8]*configuration[8] - 2.0*configuration[8]*cos(gamma)), 1.5);
- const double zenith = sqrt(cos(theta));
-
- return (1.0 + configuration[0] * exp(configuration[1] / (cos(theta) + 0.01))) *
- (configuration[2] + configuration[3] * expM + configuration[5] * rayM + configuration[6] * mieM + configuration[7] * zenith);
-}
-
-void arhosekskymodelstate_free(ArHosekSkyModelState * state)
-{
- free(state);
-}
-
-double arhosekskymodel_radiance(ArHosekSkyModelState *state,
- double theta,
- double gamma,
- double wavelength)
-{
- int low_wl = (int)((wavelength - 320.0) / 40.0);
-
- if(low_wl < 0 || low_wl >= 11)
- return 0.0f;
-
- double interp = fmod((wavelength - 320.0 ) / 40.0, 1.0);
-
- double val_low =
- ArHosekSkyModel_GetRadianceInternal(
- state->configs[low_wl],
- theta,
- gamma)
- * state->radiances[low_wl]
- * state->emission_correction_factor_sky[low_wl];
-
- if(interp < 1e-6)
- return val_low;
-
- double result = ( 1.0 - interp ) * val_low;
-
- if(low_wl+1 < 11) {
- result +=
- interp
- * ArHosekSkyModel_GetRadianceInternal(
- state->configs[low_wl+1],
- theta,
- gamma)
- * state->radiances[low_wl+1]
- * state->emission_correction_factor_sky[low_wl+1];
- }
-
- return result;
-}
-
-
-// xyz and rgb versions
-
-ArHosekSkyModelState * arhosek_xyz_skymodelstate_alloc_init(
- const double turbidity,
- const double albedo,
- const double elevation)
-{
- ArHosekSkyModelState * state = ALLOC(ArHosekSkyModelState);
-
- state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
- state->turbidity = turbidity;
- state->albedo = albedo;
- state->elevation = elevation;
-
- for(unsigned int channel = 0; channel < 3; ++channel) {
- ArHosekSkyModel_CookConfiguration(
- datasetsXYZ[channel],
- state->configs[channel],
- turbidity,
- albedo,
- elevation);
-
- state->radiances[channel] =
- ArHosekSkyModel_CookRadianceConfiguration(
- datasetsXYZRad[channel],
- turbidity,
- albedo,
- elevation);
- }
-
- return state;
-}
-
-CCL_NAMESPACE_END
-
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index d0bd34915df..f3d39c1bd72 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -76,9 +76,14 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
if(shader->use_mis && shader->has_surface_emission)
scene->light_manager->need_update = true;
+ SVMCompiler::Summary summary;
SVMCompiler compiler(scene->shader_manager, scene->image_manager);
compiler.background = ((int)i == scene->default_background);
- compiler.compile(shader, svm_nodes, i);
+ compiler.compile(scene, shader, svm_nodes, i, &summary);
+
+ VLOG(1) << "Compilation summary:\n"
+ << "Shader name: " << shader->name << "\n"
+ << summary.full_report();
}
dscene->svm_nodes.copy((uint4*)&svm_nodes[0], svm_nodes.size());
@@ -121,7 +126,7 @@ int SVMCompiler::stack_size(ShaderSocketType type)
{
int size = 0;
- switch (type) {
+ switch(type) {
case SHADER_SOCKET_FLOAT:
case SHADER_SOCKET_INT:
size = 1;
@@ -180,7 +185,7 @@ void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset)
active_stack.users[offset + i]--;
}
-void SVMCompiler::stack_backup(StackBackup& backup, set<ShaderNode*>& done)
+void SVMCompiler::stack_backup(StackBackup& backup, ShaderNodeSet& done)
{
backup.done = done;
backup.stack = active_stack;
@@ -193,7 +198,7 @@ void SVMCompiler::stack_backup(StackBackup& backup, set<ShaderNode*>& done)
}
}
-void SVMCompiler::stack_restore(StackBackup& backup, set<ShaderNode*>& done)
+void SVMCompiler::stack_restore(StackBackup& backup, ShaderNodeSet& done)
{
int i = 0;
@@ -263,7 +268,7 @@ void SVMCompiler::stack_link(ShaderInput *input, ShaderOutput *output)
}
}
-void SVMCompiler::stack_clear_users(ShaderNode *node, set<ShaderNode*>& done)
+void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done)
{
/* optimization we should add:
* find and lower user counts for outputs for which all inputs are done.
@@ -366,14 +371,18 @@ bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
return false;
}
-void SVMCompiler::find_dependencies(set<ShaderNode*>& dependencies,
- const set<ShaderNode*>& done,
+void SVMCompiler::find_dependencies(ShaderNodeSet& dependencies,
+ const ShaderNodeSet& done,
ShaderInput *input,
ShaderNode *skip_node)
{
ShaderNode *node = (input->link)? input->link->parent: NULL;
- if(node && done.find(node) == done.end() && node != skip_node) {
+ if(node != NULL &&
+ done.find(node) == done.end() &&
+ node != skip_node &&
+ dependencies.find(node) == dependencies.end())
+ {
foreach(ShaderInput *in, node->inputs)
if(!node_skip_input(node, in))
find_dependencies(dependencies, done, in, skip_node);
@@ -382,41 +391,53 @@ void SVMCompiler::find_dependencies(set<ShaderNode*>& dependencies,
}
}
-void SVMCompiler::generate_node(ShaderNode *node, set<ShaderNode*>& done)
+void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done)
{
node->compile(*this);
stack_clear_users(node, done);
stack_clear_temporary(node);
- if(current_type == SHADER_TYPE_VOLUME) {
+ if(current_type == SHADER_TYPE_SURFACE) {
if(node->has_spatial_varying())
- current_shader->has_heterogeneous_volume = true;
+ current_shader->has_surface_spatial_varying = true;
+ }
+ else if(current_type == SHADER_TYPE_VOLUME) {
+ if(node->has_spatial_varying())
+ current_shader->has_volume_spatial_varying = true;
}
if(node->has_object_dependency()) {
current_shader->has_object_dependency = true;
}
+
+ if(node->has_integrator_dependency()) {
+ current_shader->has_integrator_dependency = true;
+ }
}
-void SVMCompiler::generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done)
+void SVMCompiler::generate_svm_nodes(const ShaderNodeSet& nodes,
+ CompilerState *state)
{
- bool nodes_done;
+ ShaderNodeSet& done = state->nodes_done;
+ vector<bool>& done_flag = state->nodes_done_flag;
+ bool nodes_done;
do {
nodes_done = true;
foreach(ShaderNode *node, nodes) {
- if(done.find(node) == done.end()) {
+ if(!done_flag[node->id]) {
bool inputs_done = true;
foreach(ShaderInput *input, node->inputs)
if(!node_skip_input(node, input))
- if(input->link && done.find(input->link->parent) == done.end())
+ if(input->link && !done_flag[input->link->parent->id])
inputs_done = false;
if(inputs_done) {
generate_node(node, done);
done.insert(node);
+ done_flag[node->id] = true;
}
else
nodes_done = false;
@@ -425,14 +446,15 @@ void SVMCompiler::generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNo
} while(!nodes_done);
}
-void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done)
+void SVMCompiler::generate_closure_node(ShaderNode *node,
+ CompilerState *state)
{
/* execute dependencies for closure */
foreach(ShaderInput *in, node->inputs) {
if(!node_skip_input(node, in) && in->link) {
- set<ShaderNode*> dependencies;
- find_dependencies(dependencies, done, in);
- generate_svm_nodes(dependencies, done);
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, in);
+ generate_svm_nodes(dependencies, state);
}
}
@@ -448,7 +470,7 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done
mix_weight_offset = SVM_STACK_INVALID;
/* compile closure itself */
- generate_node(node, done);
+ generate_node(node, state->nodes_done);
mix_weight_offset = SVM_STACK_INVALID;
@@ -467,32 +489,32 @@ void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done
void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
ShaderNode *node,
- set<ShaderNode*>& done,
- set<ShaderNode*>& closure_done,
- const set<ShaderNode*>& shared)
+ CompilerState *state,
+ const ShaderNodeSet& shared)
{
if(shared.find(node) != shared.end()) {
- generate_multi_closure(root_node, node, done, closure_done);
+ generate_multi_closure(root_node, node, state);
}
else {
foreach(ShaderInput *in, node->inputs) {
if(in->type == SHADER_SOCKET_CLOSURE && in->link)
- generated_shared_closure_nodes(root_node, in->link->parent,
- done, closure_done, shared);
+ generated_shared_closure_nodes(root_node,
+ in->link->parent,
+ state,
+ shared);
}
}
}
void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
ShaderNode *node,
- set<ShaderNode*>& done,
- set<ShaderNode*>& closure_done)
+ CompilerState *state)
{
/* only generate once */
- if(closure_done.find(node) != closure_done.end())
+ if(state->closure_done.find(node) != state->closure_done.end())
return;
- closure_done.insert(node);
+ state->closure_done.insert(node);
if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) {
/* weighting is already taken care of in ShaderGraph::transform_multi_closure */
@@ -506,23 +528,25 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
if(facin && facin->link) {
/* mix closure: generate instructions to compute mix weight */
- set<ShaderNode*> dependencies;
- find_dependencies(dependencies, done, facin);
- generate_svm_nodes(dependencies, done);
+ ShaderNodeSet dependencies;
+ find_dependencies(dependencies, state->nodes_done, facin);
+ generate_svm_nodes(dependencies, state);
stack_assign(facin);
/* execute shared dependencies. this is needed to allow skipping
* of zero weight closures and their dependencies later, so we
* ensure that they only skip dependencies that are unique to them */
- set<ShaderNode*> cl1deps, cl2deps, shareddeps;
+ ShaderNodeSet cl1deps, cl2deps, shareddeps;
- find_dependencies(cl1deps, done, cl1in);
- find_dependencies(cl2deps, done, cl2in);
+ find_dependencies(cl1deps, state->nodes_done, cl1in);
+ find_dependencies(cl2deps, state->nodes_done, cl2in);
+ ShaderNodeIDComparator node_id_comp;
set_intersection(cl1deps.begin(), cl1deps.end(),
cl2deps.begin(), cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()));
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
/* it's possible some nodes are not shared between this mix node
* inputs, but still needed to be always executed, this mainly
@@ -530,28 +554,34 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
* node or so */
if(root_node != node) {
foreach(ShaderInput *in, root_node->inputs) {
- set<ShaderNode*> rootdeps;
- find_dependencies(rootdeps, done, in, node);
+ ShaderNodeSet rootdeps;
+ find_dependencies(rootdeps, state->nodes_done, in, node);
set_intersection(rootdeps.begin(), rootdeps.end(),
cl1deps.begin(), cl1deps.end(),
- std::inserter(shareddeps, shareddeps.begin()));
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
set_intersection(rootdeps.begin(), rootdeps.end(),
cl2deps.begin(), cl2deps.end(),
- std::inserter(shareddeps, shareddeps.begin()));
+ std::inserter(shareddeps, shareddeps.begin()),
+ node_id_comp);
}
}
if(!shareddeps.empty()) {
if(cl1in->link) {
- generated_shared_closure_nodes(root_node, cl1in->link->parent,
- done, closure_done, shareddeps);
+ generated_shared_closure_nodes(root_node,
+ cl1in->link->parent,
+ state,
+ shareddeps);
}
if(cl2in->link) {
- generated_shared_closure_nodes(root_node, cl2in->link->parent,
- done, closure_done, shareddeps);
+ generated_shared_closure_nodes(root_node,
+ cl2in->link->parent,
+ state,
+ shareddeps);
}
- generate_svm_nodes(shareddeps, done);
+ generate_svm_nodes(shareddeps, state);
}
/* generate instructions for input closure 1 */
@@ -560,7 +590,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE, 0, facin->stack_offset, 0));
int node_jump_skip_index = svm_nodes.size() - 1;
- generate_multi_closure(root_node, cl1in->link->parent, done, closure_done);
+ generate_multi_closure(root_node, cl1in->link->parent, state);
/* fill in jump instruction location to be after closure */
svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1;
@@ -572,7 +602,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO, 0, facin->stack_offset, 0));
int node_jump_skip_index = svm_nodes.size() - 1;
- generate_multi_closure(root_node, cl2in->link->parent, done, closure_done);
+ generate_multi_closure(root_node, cl2in->link->parent, state);
/* fill in jump instruction location to be after closure */
svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1;
@@ -586,16 +616,17 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
* to skip closures here because was already optimized due to
* fixed weight or add closure that always needs both */
if(cl1in->link)
- generate_multi_closure(root_node, cl1in->link->parent, done, closure_done);
+ generate_multi_closure(root_node, cl1in->link->parent, state);
if(cl2in->link)
- generate_multi_closure(root_node, cl2in->link->parent, done, closure_done);
+ generate_multi_closure(root_node, cl2in->link->parent, state);
}
}
else {
- generate_closure_node(node, done);
+ generate_closure_node(node, state);
}
- done.insert(node);
+ state->nodes_done.insert(node);
+ state->nodes_done_flag[node->id] = true;
}
@@ -624,7 +655,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
ShaderNode *node = graph->output();
ShaderInput *clin = NULL;
- switch (type) {
+ switch(type) {
case SHADER_TYPE_SURFACE:
clin = node->input("Surface");
break;
@@ -654,7 +685,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
if(clin->link) {
bool generate = false;
- switch (type) {
+ switch(type) {
case SHADER_TYPE_SURFACE: /* generate surface shader */
generate = true;
shader->has_surface = true;
@@ -672,9 +703,10 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
}
if(generate) {
- set<ShaderNode*> done, closure_done;
- generate_multi_closure(clin->link->parent, clin->link->parent,
- done, closure_done);
+ CompilerState state(graph);
+ generate_multi_closure(clin->link->parent,
+ clin->link->parent,
+ &state);
}
}
@@ -691,19 +723,38 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
add_node(NODE_END, 0, 0, 0);
}
-void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int index)
+void SVMCompiler::compile(Scene *scene,
+ Shader *shader,
+ vector<int4>& global_svm_nodes,
+ int index,
+ Summary *summary)
{
/* copy graph for shader with bump mapping */
ShaderNode *node = shader->graph->output();
+ int start_num_svm_nodes = global_svm_nodes.size();
+
+ const double time_start = time_dt();
if(node->input("Surface")->link && node->input("Displacement")->link)
if(!shader->graph_bump)
shader->graph_bump = shader->graph->copy();
/* finalize */
- shader->graph->finalize(false, false);
- if(shader->graph_bump)
- shader->graph_bump->finalize(true, false);
+ {
+ scoped_timer timer((summary != NULL)? &summary->time_finalize: NULL);
+ shader->graph->finalize(scene,
+ false,
+ false,
+ shader->has_integrator_dependency);
+ }
+
+ if(shader->graph_bump) {
+ scoped_timer timer((summary != NULL)? &summary->time_finalize_bump: NULL);
+ shader->graph_bump->finalize(scene,
+ true,
+ false,
+ shader->has_integrator_dependency);
+ }
current_shader = shader;
@@ -714,32 +765,101 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in
shader->has_bssrdf_bump = false;
shader->has_volume = false;
shader->has_displacement = false;
- shader->has_heterogeneous_volume = false;
+ shader->has_surface_spatial_varying = false;
+ shader->has_volume_spatial_varying = false;
shader->has_object_dependency = false;
+ shader->has_integrator_dependency = false;
/* generate surface shader */
- compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- global_svm_nodes[index*2 + 0].y = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
+ global_svm_nodes[index*2 + 0].y = global_svm_nodes.size();
+ global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
+ global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ }
if(shader->graph_bump) {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
}
/* generate volume shader */
- compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
- global_svm_nodes[index*2 + 0].z = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].z = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
+ global_svm_nodes[index*2 + 0].z = global_svm_nodes.size();
+ global_svm_nodes[index*2 + 1].z = global_svm_nodes.size();
+ global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ }
/* generate displacement shader */
- compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
- global_svm_nodes[index*2 + 0].w = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].w = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL);
+ compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
+ global_svm_nodes[index*2 + 0].w = global_svm_nodes.size();
+ global_svm_nodes[index*2 + 1].w = global_svm_nodes.size();
+ global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ }
+
+ /* Fill in summary information. */
+ if(summary != NULL) {
+ summary->time_total = time_dt() - time_start;
+ summary->peak_stack_usage = max_stack_use;
+ summary->num_svm_nodes = global_svm_nodes.size() - start_num_svm_nodes;
+ }
+}
+
+/* Compiler summary implementation. */
+
+SVMCompiler::Summary::Summary()
+ : num_svm_nodes(0),
+ peak_stack_usage(0),
+ time_finalize(0.0),
+ time_finalize_bump(0.0),
+ time_generate_surface(0.0),
+ time_generate_bump(0.0),
+ time_generate_volume(0.0),
+ time_generate_displacement(0.0),
+ time_total(0.0)
+{
+}
+
+string SVMCompiler::Summary::full_report() const
+{
+ string report = "";
+ report += string_printf("Number of SVM nodes: %d\n", num_svm_nodes);
+ report += string_printf("Peak stack usage: %d\n", peak_stack_usage);
+
+ report += string_printf("Time (in seconds):\n");
+ report += string_printf(" Finalize: %f\n", time_finalize);
+ report += string_printf(" Bump finalize: %f\n", time_finalize_bump);
+ report += string_printf("Finalize: %f\n", time_finalize +
+ time_finalize_bump);
+ report += string_printf(" Surface: %f\n", time_generate_surface);
+ report += string_printf(" Bump: %f\n", time_generate_bump);
+ report += string_printf(" Volume: %f\n", time_generate_volume);
+ report += string_printf(" Displacement: %f\n", time_generate_displacement);
+ report += string_printf("Generate: %f\n", time_generate_surface +
+ time_generate_bump +
+ time_generate_volume +
+ time_generate_displacement);
+ report += string_printf("Total: %f\n", time_total);
+
+ return report;
+}
+
+/* Global state of the compiler. */
+
+SVMCompiler::CompilerState::CompilerState(ShaderGraph *graph)
+{
+ int max_id = 0;
+ foreach(ShaderNode *node, graph->nodes) {
+ max_id = max(node->id, max_id);
+ }
+ nodes_done_flag.resize(max_id + 1, false);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index 4b390fb88f9..b86a00bf8ea 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -52,8 +52,48 @@ public:
class SVMCompiler {
public:
+ struct Summary {
+ Summary();
+
+ /* Number of SVM nodes shader was compiled into. */
+ int num_svm_nodes;
+
+ /* Peak stack usage during shader evaluation. */
+ int peak_stack_usage;
+
+ /* Time spent on surface graph finalization. */
+ double time_finalize;
+
+ /* Time spent on bump graph finalization. */
+ double time_finalize_bump;
+
+ /* Time spent on generating SVM nodes for surface shader. */
+ double time_generate_surface;
+
+ /* Time spent on generating SVM nodes for bump shader. */
+ double time_generate_bump;
+
+ /* Time spent on generating SVM nodes for volume shader. */
+ double time_generate_volume;
+
+ /* Time spent on generating SVM nodes for displacement shader. */
+ double time_generate_displacement;
+
+ /* Total time spent on all routines. */
+ double time_total;
+
+ /* A full multiline description of the state of the compiler after
+ * compilation.
+ */
+ string full_report() const;
+ };
+
SVMCompiler(ShaderManager *shader_manager, ImageManager *image_manager);
- void compile(Shader *shader, vector<int4>& svm_nodes, int index);
+ void compile(Scene *scene,
+ Shader *shader,
+ vector<int4>& svm_nodes,
+ int index,
+ Summary *summary = NULL);
void stack_assign(ShaderOutput *output);
void stack_assign(ShaderInput *input);
@@ -109,35 +149,60 @@ protected:
struct StackBackup {
Stack stack;
vector<int> offsets;
- set<ShaderNode*> done;
+ ShaderNodeSet done;
+ };
+
+ /* Global state of the compiler accessible from the compilation routines. */
+ struct CompilerState {
+ CompilerState(ShaderGraph *graph);
+
+ /* ** Global state, used by various compilation steps. ** */
+
+ /* Set of nodes which were already compiled. */
+ ShaderNodeSet nodes_done;
+
+ /* Set of closures which were already compiled. */
+ ShaderNodeSet closure_done;
+
+ /* ** SVM nodes generation state ** */
+
+ /* Flag whether the node with corresponding ID was already compiled or
+ * not. Array element with index i corresponds to a node with such if.
+ *
+ * TODO(sergey): This is actually a copy of nodes_done just in another
+ * notation. We can de-duplicate this storage actually after switching
+ * all areas to use this flags array.
+ */
+ vector<bool> nodes_done_flag;
};
- void stack_backup(StackBackup& backup, set<ShaderNode*>& done);
- void stack_restore(StackBackup& backup, set<ShaderNode*>& done);
+ void stack_backup(StackBackup& backup, ShaderNodeSet& done);
+ void stack_restore(StackBackup& backup, ShaderNodeSet& done);
void stack_clear_temporary(ShaderNode *node);
int stack_size(ShaderSocketType type);
- void stack_clear_users(ShaderNode *node, set<ShaderNode*>& done);
+ void stack_clear_users(ShaderNode *node, ShaderNodeSet& done);
bool node_skip_input(ShaderNode *node, ShaderInput *input);
/* single closure */
- void find_dependencies(set<ShaderNode*>& dependencies,
- const set<ShaderNode*>& done,
+ void find_dependencies(ShaderNodeSet& dependencies,
+ const ShaderNodeSet& done,
ShaderInput *input,
ShaderNode *skip_node = NULL);
- void generate_node(ShaderNode *node, set<ShaderNode*>& done);
- void generate_closure_node(ShaderNode *node, set<ShaderNode*>& done);
- void generated_shared_closure_nodes(ShaderNode *root_node, ShaderNode *node,
- set<ShaderNode*>& done,
- set<ShaderNode*>& closure_done, const set<ShaderNode*>& shared);
- void generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done);
+ void generate_node(ShaderNode *node, ShaderNodeSet& done);
+ void generate_closure_node(ShaderNode *node, CompilerState *state);
+ void generated_shared_closure_nodes(ShaderNode *root_node,
+ ShaderNode *node,
+ CompilerState *state,
+ const ShaderNodeSet& shared);
+ void generate_svm_nodes(const ShaderNodeSet& nodes,
+ CompilerState *state);
/* multi closure */
void generate_multi_closure(ShaderNode *root_node,
ShaderNode *node,
- set<ShaderNode*>& done,
- set<ShaderNode*>& closure_done);
+ CompilerState *state);
/* compile */
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 7e68ce84d94..3a6dfea11a7 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -21,6 +21,70 @@
CCL_NAMESPACE_BEGIN
+namespace {
+
+class TileComparator {
+public:
+ TileComparator(TileOrder order, int2 center)
+ : order_(order),
+ center_(center)
+ {}
+
+ bool operator()(Tile &a, Tile &b)
+ {
+ switch(order_) {
+ case TILE_CENTER:
+ {
+ float2 dist_a = make_float2(center_.x - (a.x + a.w/2),
+ center_.y - (a.y + a.h/2));
+ float2 dist_b = make_float2(center_.x - (b.x + b.w/2),
+ center_.y - (b.y + b.h/2));
+ return dot(dist_a, dist_a) < dot(dist_b, dist_b);
+ }
+ case TILE_LEFT_TO_RIGHT:
+ return (a.x == b.x)? (a.y < b.y): (a.x < b.x);
+ case TILE_RIGHT_TO_LEFT:
+ return (a.x == b.x)? (a.y < b.y): (a.x > b.x);
+ case TILE_TOP_TO_BOTTOM:
+ return (a.y == b.y)? (a.x < b.x): (a.y > b.y);
+ case TILE_BOTTOM_TO_TOP:
+ default:
+ return (a.y == b.y)? (a.x < b.x): (a.y < b.y);
+ }
+ }
+
+protected:
+ TileOrder order_;
+ int2 center_;
+};
+
+inline int2 hilbert_index_to_pos(int n, int d)
+{
+ int2 r, xy = make_int2(0, 0);
+ for(int s = 1; s < n; s *= 2) {
+ r.x = (d >> 1) & 1;
+ r.y = (d ^ r.x) & 1;
+ if(!r.y) {
+ if(r.x) {
+ xy = make_int2(s-1, s-1) - xy;
+ }
+ swap(xy.x, xy.y);
+ }
+ xy += r*make_int2(s, s);
+ d >>= 2;
+ }
+ return xy;
+}
+
+enum SpiralDirection {
+ DIRECTION_UP,
+ DIRECTION_LEFT,
+ DIRECTION_DOWN,
+ DIRECTION_RIGHT,
+};
+
+} /* namespace */
+
TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int start_resolution_,
bool preserve_tile_device_, bool background_, TileOrder tile_order_, int num_devices_)
{
@@ -33,6 +97,9 @@ TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, i
preserve_tile_device = preserve_tile_device_;
background = background_;
+ range_start_sample = 0;
+ range_num_samples = -1;
+
BufferParams buffer_params;
reset(buffer_params, 0);
}
@@ -50,8 +117,8 @@ void TileManager::reset(BufferParams& params_, int num_samples_)
if(start_resolution != INT_MAX) {
while(w*h > start_resolution*start_resolution) {
- w = max(1, w/2);
- h = max(1, h/2);
+ w = max(1, w/2);
+ h = max(1, h/2);
divider *= 2;
}
@@ -60,7 +127,7 @@ void TileManager::reset(BufferParams& params_, int num_samples_)
num_samples = num_samples_;
state.buffer = BufferParams();
- state.sample = -1;
+ state.sample = range_start_sample - 1;
state.num_tiles = 0;
state.num_rendered_tiles = 0;
state.num_samples = 0;
@@ -73,74 +140,160 @@ void TileManager::set_samples(int num_samples_)
num_samples = num_samples_;
}
-/* splits image into tiles and assigns equal amount of tiles to every render device */
-void TileManager::gen_tiles_global()
+/* If sliced is false, splits image into tiles and assigns equal amount of tiles to every render device.
+ * If sliced is true, slice image into as much pieces as how many devices are rendering this image. */
+int TileManager::gen_tiles(bool sliced)
{
int resolution = state.resolution_divider;
int image_w = max(1, params.width/resolution);
int image_h = max(1, params.height/resolution);
+ int2 center = make_int2(image_w/2, image_h/2);
state.tiles.clear();
- int tile_w = (tile_size.x >= image_w)? 1: (image_w + tile_size.x - 1)/tile_size.x;
- int tile_h = (tile_size.y >= image_h)? 1: (image_h + tile_size.y - 1)/tile_size.y;
-
int num_logical_devices = preserve_tile_device? num_devices: 1;
int num = min(image_h, num_logical_devices);
+ int slice_num = sliced? num: 1;
int tile_index = 0;
- int tiles_per_device = (tile_w * tile_h + num - 1) / num;
- int cur_device = 0, cur_tiles = 0;
+ state.tiles.clear();
+ state.tiles.resize(num);
+ vector<list<Tile> >::iterator tile_list = state.tiles.begin();
- for(int tile_y = 0; tile_y < tile_h; tile_y++) {
- for(int tile_x = 0; tile_x < tile_w; tile_x++, tile_index++) {
- int x = tile_x * tile_size.x;
- int y = tile_y * tile_size.y;
- int w = (tile_x == tile_w-1)? image_w - x: tile_size.x;
- int h = (tile_y == tile_h-1)? image_h - y: tile_size.y;
+ if(tile_order == TILE_HILBERT_SPIRAL) {
+ assert(!sliced);
- state.tiles.push_back(Tile(tile_index, x, y, w, h, cur_device));
- cur_tiles++;
+ /* Size of blocks in tiles, must be a power of 2 */
+ const int hilbert_size = (max(tile_size.x, tile_size.y) <= 12)? 8: 4;
- if(cur_tiles == tiles_per_device) {
- cur_tiles = 0;
- cur_device++;
+ int tile_w = (tile_size.x >= image_w)? 1: (image_w + tile_size.x - 1)/tile_size.x;
+ int tile_h = (tile_size.y >= image_h)? 1: (image_h + tile_size.y - 1)/tile_size.y;
+ int tiles_per_device = (tile_w * tile_h + num - 1) / num;
+ int cur_device = 0, cur_tiles = 0;
+
+ int2 block_size = tile_size * make_int2(hilbert_size, hilbert_size);
+ /* Number of blocks to fill the image */
+ int blocks_x = (block_size.x >= image_w)? 1: (image_w + block_size.x - 1)/block_size.x;
+ int blocks_y = (block_size.y >= image_h)? 1: (image_h + block_size.y - 1)/block_size.y;
+ int n = max(blocks_x, blocks_y) | 0x1; /* Side length of the spiral (must be odd) */
+ /* Offset of spiral (to keep it centered) */
+ int2 offset = make_int2((image_w - n*block_size.x)/2, (image_h - n*block_size.y)/2);
+ offset = (offset / tile_size) * tile_size; /* Round to tile border. */
+
+ int2 block = make_int2(0, 0); /* Current block */
+ SpiralDirection prev_dir = DIRECTION_UP, dir = DIRECTION_UP;
+ for(int i = 0;;) {
+ /* Generate the tiles in the current block. */
+ for(int hilbert_index = 0; hilbert_index < hilbert_size*hilbert_size; hilbert_index++) {
+ int2 tile, hilbert_pos = hilbert_index_to_pos(hilbert_size, hilbert_index);
+ /* Rotate block according to spiral direction. */
+ if(prev_dir == DIRECTION_UP && dir == DIRECTION_UP) {
+ tile = make_int2(hilbert_pos.y, hilbert_pos.x);
+ }
+ else if(dir == DIRECTION_LEFT || prev_dir == DIRECTION_LEFT) {
+ tile = hilbert_pos;
+ }
+ else if(dir == DIRECTION_DOWN) {
+ tile = make_int2(hilbert_size-1-hilbert_pos.y, hilbert_size-1-hilbert_pos.x);
+ }
+ else {
+ tile = make_int2(hilbert_size-1-hilbert_pos.x, hilbert_size-1-hilbert_pos.y);
+ }
+
+ int2 pos = block*block_size + tile*tile_size + offset;
+ /* Only add tiles which are in the image (tiles outside of the image can be generated since the spiral is always square). */
+ if(pos.x >= 0 && pos.y >= 0 && pos.x < image_w && pos.y < image_h) {
+ int w = min(tile_size.x, image_w - pos.x);
+ int h = min(tile_size.y, image_h - pos.y);
+ tile_list->push_front(Tile(tile_index, pos.x, pos.y, w, h, cur_device));
+ cur_tiles++;
+ tile_index++;
+
+ if(cur_tiles == tiles_per_device) {
+ tile_list++;
+ cur_tiles = 0;
+ cur_device++;
+ }
+ }
+ }
+
+ /* Stop as soon as the spiral has reached the center block. */
+ if(block.x == (n-1)/2 && block.y == (n-1)/2)
+ break;
+
+ /* Advance to next block. */
+ prev_dir = dir;
+ switch(dir) {
+ case DIRECTION_UP:
+ block.y++;
+ if(block.y == (n-i-1)) {
+ dir = DIRECTION_LEFT;
+ }
+ break;
+ case DIRECTION_LEFT:
+ block.x++;
+ if(block.x == (n-i-1)) {
+ dir = DIRECTION_DOWN;
+ }
+ break;
+ case DIRECTION_DOWN:
+ block.y--;
+ if(block.y == i) {
+ dir = DIRECTION_RIGHT;
+ }
+ break;
+ case DIRECTION_RIGHT:
+ block.x--;
+ if(block.x == i+1) {
+ dir = DIRECTION_UP;
+ i++;
+ }
+ break;
}
}
+ return tile_index;
}
-}
-
-/* slices image into as much pieces as how many devices are rendering this image */
-void TileManager::gen_tiles_sliced()
-{
- int resolution = state.resolution_divider;
- int image_w = max(1, params.width/resolution);
- int image_h = max(1, params.height/resolution);
- state.tiles.clear();
-
- int num_logical_devices = preserve_tile_device? num_devices: 1;
- int num = min(image_h, num_logical_devices);
- int tile_index = 0;
-
- for(int device = 0; device < num; device++) {
- int device_y = (image_h/num)*device;
- int device_h = (device == num-1)? image_h - device*(image_h/num): image_h/num;
+ for(int slice = 0; slice < slice_num; slice++) {
+ int slice_y = (image_h/slice_num)*slice;
+ int slice_h = (slice == slice_num-1)? image_h - slice*(image_h/slice_num): image_h/slice_num;
int tile_w = (tile_size.x >= image_w)? 1: (image_w + tile_size.x - 1)/tile_size.x;
- int tile_h = (tile_size.y >= device_h)? 1: (device_h + tile_size.y - 1)/tile_size.y;
+ int tile_h = (tile_size.y >= slice_h)? 1: (slice_h + tile_size.y - 1)/tile_size.y;
+
+ int tiles_per_device = (tile_w * tile_h + num - 1) / num;
+ int cur_device = 0, cur_tiles = 0;
for(int tile_y = 0; tile_y < tile_h; tile_y++) {
for(int tile_x = 0; tile_x < tile_w; tile_x++, tile_index++) {
int x = tile_x * tile_size.x;
int y = tile_y * tile_size.y;
int w = (tile_x == tile_w-1)? image_w - x: tile_size.x;
- int h = (tile_y == tile_h-1)? device_h - y: tile_size.y;
-
- state.tiles.push_back(Tile(tile_index, x, y + device_y, w, h, device));
+ int h = (tile_y == tile_h-1)? slice_h - y: tile_size.y;
+
+ tile_list->push_back(Tile(tile_index, x, y + slice_y, w, h, sliced? slice: cur_device));
+
+ if(!sliced) {
+ cur_tiles++;
+
+ if(cur_tiles == tiles_per_device) {
+ /* Tiles are already generated in Bottom-to-Top order, so no sort is necessary in that case. */
+ if(tile_order != TILE_BOTTOM_TO_TOP) {
+ tile_list->sort(TileComparator(tile_order, center));
+ }
+ tile_list++;
+ cur_tiles = 0;
+ cur_device++;
+ }
+ }
}
}
+ if(sliced) {
+ tile_list++;
+ }
}
+
+ return tile_index;
}
void TileManager::set_tiles()
@@ -149,12 +302,7 @@ void TileManager::set_tiles()
int image_w = max(1, params.width/resolution);
int image_h = max(1, params.height/resolution);
- if(background)
- gen_tiles_global();
- else
- gen_tiles_sliced();
-
- state.num_tiles = state.tiles.size();
+ state.num_tiles = gen_tiles(!background);
state.buffer.width = image_w;
state.buffer.height = image_h;
@@ -165,95 +313,26 @@ void TileManager::set_tiles()
state.buffer.full_height = max(1, params.full_height/resolution);
}
-list<Tile>::iterator TileManager::next_viewport_tile(int device)
-{
- list<Tile>::iterator iter;
-
- int logical_device = preserve_tile_device? device: 0;
-
- for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) {
- if(iter->device == logical_device && iter->rendering == false)
- return iter;
- }
-
- return state.tiles.end();
-}
-
-list<Tile>::iterator TileManager::next_background_tile(int device, TileOrder tile_order)
+bool TileManager::next_tile(Tile& tile, int device)
{
- list<Tile>::iterator iter, best = state.tiles.end();
-
- int resolution = state.resolution_divider;
int logical_device = preserve_tile_device? device: 0;
- int64_t cordx = max(1, params.width/resolution);
- int64_t cordy = max(1, params.height/resolution);
- int64_t mindist = INT_MAX;
-
- int64_t centx = cordx / 2, centy = cordy / 2;
-
- for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) {
- if(iter->device == logical_device && iter->rendering == false) {
- Tile &cur_tile = *iter;
-
- int64_t distx = cordx;
- int64_t disty = cordy;
-
- switch (tile_order) {
- case TILE_CENTER:
- distx = centx - (cur_tile.x + (cur_tile.w / 2));
- disty = centy - (cur_tile.y + (cur_tile.h / 2));
- distx = (int64_t)sqrt((double)(distx * distx + disty * disty));
- break;
- case TILE_RIGHT_TO_LEFT:
- distx = cordx - cur_tile.x;
- break;
- case TILE_LEFT_TO_RIGHT:
- distx = cordx + cur_tile.x;
- break;
- case TILE_TOP_TO_BOTTOM:
- distx = cordx - cur_tile.y;
- break;
- case TILE_BOTTOM_TO_TOP:
- distx = cordx + cur_tile.y;
- break;
- default:
- break;
- }
-
- if(distx < mindist) {
- best = iter;
- mindist = distx;
- }
- }
- }
-
- return best;
-}
-
-bool TileManager::next_tile(Tile& tile, int device)
-{
- list<Tile>::iterator tile_it;
-
- if(background)
- tile_it = next_background_tile(device, tile_order);
- else
- tile_it = next_viewport_tile(device);
-
- if(tile_it != state.tiles.end()) {
- tile_it->rendering = true;
- tile = *tile_it;
- state.num_rendered_tiles++;
-
- return true;
- }
+ if((logical_device >= state.tiles.size()) || state.tiles[logical_device].empty())
+ return false;
- return false;
+ tile = Tile(state.tiles[logical_device].front());
+ state.tiles[logical_device].pop_front();
+ state.num_rendered_tiles++;
+ return true;
}
bool TileManager::done()
{
- return (state.sample+state.num_samples >= num_samples && state.resolution_divider == 1);
+ int end_sample = (range_num_samples == -1)
+ ? num_samples
+ : range_start_sample + range_num_samples;
+ return (state.resolution_divider == 1) &&
+ (state.sample+state.num_samples >= end_sample);
}
bool TileManager::next()
@@ -272,8 +351,10 @@ bool TileManager::next()
if(progressive)
state.num_samples = 1;
- else
+ else if(range_num_samples == -1)
state.num_samples = num_samples;
+ else
+ state.num_samples = range_num_samples;
state.resolution_divider = 1;
set_tiles();
@@ -282,5 +363,11 @@ bool TileManager::next()
return true;
}
+int TileManager::get_num_effective_samples()
+{
+ return (range_num_samples == -1) ? num_samples
+ : range_num_samples;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h
index c9bdc86f029..af1b1ed8b0f 100644
--- a/intern/cycles/render/tile.h
+++ b/intern/cycles/render/tile.h
@@ -31,13 +31,12 @@ public:
int index;
int x, y, w, h;
int device;
- bool rendering;
Tile()
{}
Tile(int index_, int x_, int y_, int w_, int h_, int device_)
- : index(index_), x(x_), y(y_), w(w_), h(h_), device(device_), rendering(false) {}
+ : index(index_), x(x_), y(y_), w(w_), h(h_), device(device_) {}
};
/* Tile order */
@@ -48,7 +47,8 @@ enum TileOrder {
TILE_RIGHT_TO_LEFT = 1,
TILE_LEFT_TO_RIGHT = 2,
TILE_TOP_TO_BOTTOM = 3,
- TILE_BOTTOM_TO_TOP = 4
+ TILE_BOTTOM_TO_TOP = 4,
+ TILE_HILBERT_SPIRAL = 5,
};
/* Tile Manager */
@@ -64,7 +64,9 @@ public:
int resolution_divider;
int num_tiles;
int num_rendered_tiles;
- list<Tile> tiles;
+ /* This vector contains a list of tiles for every logical device in the session.
+ * In each list, the tiles are sorted according to the tile order setting. */
+ vector<list<Tile> > tiles;
} state;
int num_samples;
@@ -78,8 +80,19 @@ public:
bool next();
bool next_tile(Tile& tile, int device = 0);
bool done();
-
+
void set_tile_order(TileOrder tile_order_) { tile_order = tile_order_; }
+
+ /* ** Sample range rendering. ** */
+
+ /* Start sample in the range. */
+ int range_start_sample;
+
+ /* Number to samples in the rendering range. */
+ int range_num_samples;
+
+ /* get number of actual samples to render. */
+ int get_num_effective_samples();
protected:
void set_tiles();
@@ -109,17 +122,8 @@ protected:
*/
bool background;
- /* splits image into tiles and assigns equal amount of tiles to every render device */
- void gen_tiles_global();
-
- /* slices image into as much pieces as how many devices are rendering this image */
- void gen_tiles_sliced();
-
- /* returns tiles for background render */
- list<Tile>::iterator next_background_tile(int device, TileOrder tile_order);
-
- /* returns first unhandled tile for viewport render */
- list<Tile>::iterator next_viewport_tile(int device);
+ /* Generate tile list, return number of tiles. */
+ int gen_tiles(bool sliced);
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/subd/CMakeLists.txt b/intern/cycles/subd/CMakeLists.txt
index 2641f6d9c0c..1ccf80d9457 100644
--- a/intern/cycles/subd/CMakeLists.txt
+++ b/intern/cycles/subd/CMakeLists.txt
@@ -25,6 +25,10 @@ set(SRC_HEADERS
subd_split.h
)
+if(WITH_CYCLES_OPENSUBDIV)
+ add_definitions(-DWITH_OPENSUBDIV)
+endif()
+
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index 44bab066dde..a5dfcd21ceb 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -58,10 +58,9 @@ void EdgeDice::reserve(int num_verts, int num_tris)
int EdgeDice::add_vert(Patch *patch, float2 uv)
{
- float3 P, N, dPdu, dPdv;
+ float3 P, N;
- patch->eval(&P, &dPdu, &dPdv, uv.x, uv.y);
- N = normalize(cross(dPdu, dPdv));
+ patch->eval(&P, NULL, NULL, &N, uv.x, uv.y);
assert(vert_offset < params.mesh->verts.size());
@@ -81,7 +80,7 @@ int EdgeDice::add_vert(Patch *patch, float2 uv)
void EdgeDice::add_triangle(Patch *patch, int v0, int v1, int v2)
{
- params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth);
+ params.mesh->add_triangle(v0, v1, v2, params.shader, params.smooth, false);
if(params.ptex) {
Attribute *attr_ptex_face_id = params.mesh->attributes.add(ATTR_STD_PTEX_FACE_ID);
@@ -159,7 +158,7 @@ float3 QuadDice::eval_projected(SubPatch& sub, float u, float v)
float2 uv = map_uv(sub, u, v);
float3 P;
- sub.patch->eval(&P, NULL, NULL, uv.x, uv.y);
+ sub.patch->eval(&P, NULL, NULL, NULL, uv.x, uv.y);
if(params.camera)
P = transform_perspective(&params.camera->worldtoraster, P);
@@ -260,17 +259,10 @@ float QuadDice::scale_factor(SubPatch& sub, EdgeFactors& ef, int Mu, int Mv)
void QuadDice::add_corners(SubPatch& sub)
{
/* add verts for patch corners */
- if(sub.patch->is_triangle()) {
- add_vert(sub, 0.0f, 0.0f);
- add_vert(sub, 1.0f, 0.0f);
- add_vert(sub, 0.0f, 1.0f);
- }
- else {
- add_vert(sub, 0.0f, 0.0f);
- add_vert(sub, 1.0f, 0.0f);
- add_vert(sub, 0.0f, 1.0f);
- add_vert(sub, 1.0f, 1.0f);
- }
+ add_vert(sub, 0.0f, 0.0f);
+ add_vert(sub, 1.0f, 0.0f);
+ add_vert(sub, 0.0f, 1.0f);
+ add_vert(sub, 1.0f, 1.0f);
}
void QuadDice::add_grid(SubPatch& sub, int Mu, int Mv, int offset)
@@ -305,7 +297,12 @@ void QuadDice::dice(SubPatch& sub, EdgeFactors& ef)
int Mu = max(ef.tu0, ef.tu1);
int Mv = max(ef.tv0, ef.tv1);
+#if 0 /* Doesnt work very well, especially at grazing angles. */
float S = scale_factor(sub, ef, Mu, Mv);
+#else
+ float S = 1.0f;
+#endif
+
Mu = max((int)ceil(S*Mu), 2); // XXX handle 0 & 1?
Mv = max((int)ceil(S*Mv), 2); // XXX handle 0 & 1?
@@ -454,15 +451,21 @@ void TriangleDice::add_grid(SubPatch& sub, EdgeFactors& ef, int M)
add_triangle(sub.patch, outer_w[0], outer_u[0], outer_v[0]);
}
else {
- /* center vertex + 6 triangles */
+ /* center vertex + up to 6 triangles */
int center = add_vert(sub, make_float2(1.0f/3.0f, 1.0f/3.0f));
add_triangle(sub.patch, outer_w[0], outer_w[1], center);
- add_triangle(sub.patch, outer_w[1], outer_w[2], center);
+ /* if this is false then there is only one triangle on this side */
+ if(outer_w.size() > 2)
+ add_triangle(sub.patch, outer_w[1], outer_w[2], center);
+
add_triangle(sub.patch, outer_u[0], outer_u[1], center);
- add_triangle(sub.patch, outer_u[1], outer_u[2], center);
+ if(outer_u.size() > 2)
+ add_triangle(sub.patch, outer_u[1], outer_u[2], center);
+
add_triangle(sub.patch, outer_v[0], outer_v[1], center);
- add_triangle(sub.patch, outer_v[1], outer_v[2], center);
+ if(outer_v.size() > 2)
+ add_triangle(sub.patch, outer_v[1], outer_v[2], center);
}
}
@@ -471,6 +474,16 @@ void TriangleDice::dice(SubPatch& sub, EdgeFactors& ef)
/* todo: handle 2 1 1 resolution */
int M = max(ef.tu, max(ef.tv, ef.tw));
+ /* Due to the "slant" of the edges of a triangle compared to a quad, the internal
+ * triangles end up smaller, causing over-tessellation. This is to correct for this
+ * difference in area. Technically its only correct for equilateral triangles, but
+ * its better than how it was.
+ *
+ * (2*cos(radians(30))/3)**0.5
+ */
+ float S = 0.7598356856515927f;
+ M = max((int)ceil(S*M), 1);
+
reserve(ef, M);
add_grid(sub, ef, M);
diff --git a/intern/cycles/subd/subd_dice.h b/intern/cycles/subd/subd_dice.h
index b7e61748779..8450a43129e 100644
--- a/intern/cycles/subd/subd_dice.h
+++ b/intern/cycles/subd/subd_dice.h
@@ -40,7 +40,9 @@ struct SubdParams {
int test_steps;
int split_threshold;
float dicing_rate;
+ int max_level;
Camera *camera;
+ Transform objecttoworld;
SubdParams(Mesh *mesh_, int shader_, bool smooth_ = true, bool ptex_ = false)
{
@@ -52,6 +54,7 @@ struct SubdParams {
test_steps = 3;
split_threshold = 1;
dicing_rate = 0.1f;
+ max_level = 12;
camera = NULL;
}
diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp
index 17a730e5efe..d7cb7b921ee 100644
--- a/intern/cycles/subd/subd_mesh.cpp
+++ b/intern/cycles/subd/subd_mesh.cpp
@@ -196,17 +196,18 @@ void OpenSubdMesh::add_face(int *index, int num)
OsdHbrHalfEdge *opposite = destination->GetEdge(origin);
if(origin==NULL || destination==NULL)
- assert("An edge was specified that connected a nonexistent vertex\n");
+ assert(!"An edge was specified that connected a nonexistent vertex\n");
if(origin == destination)
- assert("An edge was specified that connected a vertex to itself\n");
+ assert(!"An edge was specified that connected a vertex to itself\n");
if(opposite && opposite->GetOpposite())
- assert("A non-manifold edge incident to more than 2 faces was found\n");
+ assert(!"A non-manifold edge incident to more than 2 faces was found\n");
- if(origin->GetEdge(destination))
- assert("An edge connecting two vertices was specified more than once."
- "It's likely that an incident face was flipped\n");
+ if(origin->GetEdge(destination)) {
+ assert(!"An edge connecting two vertices was specified more than once."
+ "It's likely that an incident face was flipped\n");
+ }
}
#endif
diff --git a/intern/cycles/subd/subd_patch.cpp b/intern/cycles/subd/subd_patch.cpp
index 0db46ec492d..60a78016054 100644
--- a/intern/cycles/subd/subd_patch.cpp
+++ b/intern/cycles/subd/subd_patch.cpp
@@ -57,7 +57,7 @@ static void decasteljau_bicubic(float3 *P, float3 *du, float3 *dv, const float3
/* Linear Quad Patch */
-void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
+void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
{
float3 d0 = interp(hull[0], hull[1], u);
float3 d1 = interp(hull[2], hull[3], u);
@@ -68,6 +68,10 @@ void LinearQuadPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float
*dPdu = interp(hull[1] - hull[0], hull[3] - hull[2], v);
*dPdv = interp(hull[2] - hull[0], hull[3] - hull[1], u);
}
+
+ if(N) {
+ *N = normalize(interp(interp(normals[0], normals[1], u), interp(normals[2], normals[3], u), v));
+ }
}
BoundBox LinearQuadPatch::bound()
@@ -82,7 +86,7 @@ BoundBox LinearQuadPatch::bound()
/* Linear Triangle Patch */
-void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
+void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
{
*P = u*hull[0] + v*hull[1] + (1.0f - u - v)*hull[2];
@@ -90,6 +94,10 @@ void LinearTrianglePatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, f
*dPdu = hull[0] - hull[2];
*dPdv = hull[1] - hull[2];
}
+
+ if(N) {
+ *N = normalize(u*normals[0] + v*normals[1] + (1.0f - u - v)*normals[2]);
+ }
}
BoundBox LinearTrianglePatch::bound()
@@ -104,9 +112,22 @@ BoundBox LinearTrianglePatch::bound()
/* Bicubic Patch */
-void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v)
+void BicubicPatch::eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
{
- decasteljau_bicubic(P, dPdu, dPdv, hull, u, v);
+ if(N) {
+ float3 dPdu_, dPdv_;
+ decasteljau_bicubic(P, &dPdu_, &dPdv_, hull, u, v);
+
+ if(dPdu && dPdv) {
+ *dPdu = dPdu_;
+ *dPdv = dPdv_;
+ }
+
+ *N = normalize(cross(dPdu_, dPdv_));
+ }
+ else {
+ decasteljau_bicubic(P, dPdu, dPdv, hull, u, v);
+ }
}
BoundBox BicubicPatch::bound()
diff --git a/intern/cycles/subd/subd_patch.h b/intern/cycles/subd/subd_patch.h
index 9be4606c248..bfa04412c66 100644
--- a/intern/cycles/subd/subd_patch.h
+++ b/intern/cycles/subd/subd_patch.h
@@ -25,7 +25,7 @@ CCL_NAMESPACE_BEGIN
class Patch {
public:
virtual ~Patch() {}
- virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v) = 0;
+ virtual void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) = 0;
virtual bool is_triangle() { return false; }
virtual BoundBox bound() = 0;
virtual int ptex_face_id() { return -1; }
@@ -36,8 +36,9 @@ public:
class LinearQuadPatch : public Patch {
public:
float3 hull[4];
+ float3 normals[4];
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v);
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
bool is_triangle() { return false; }
BoundBox bound();
};
@@ -47,8 +48,9 @@ public:
class LinearTrianglePatch : public Patch {
public:
float3 hull[3];
+ float3 normals[3];
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v);
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
bool is_triangle() { return true; }
BoundBox bound();
};
@@ -59,7 +61,7 @@ class BicubicPatch : public Patch {
public:
float3 hull[16];
- void eval(float3 *P, float3 *dPdu, float3 *dPdv, float u, float v);
+ void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v);
bool is_triangle() { return false; }
BoundBox bound();
};
diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp
index df4d451e8eb..c4af8cc8c43 100644
--- a/intern/cycles/subd/subd_split.cpp
+++ b/intern/cycles/subd/subd_split.cpp
@@ -46,13 +46,13 @@ void DiagSplit::dispatch(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors&
edgefactors_triangle.push_back(ef);
}
-float3 DiagSplit::project(Patch *patch, float2 uv)
+float3 DiagSplit::to_world(Patch *patch, float2 uv)
{
float3 P;
- patch->eval(&P, NULL, NULL, uv.x, uv.y);
+ patch->eval(&P, NULL, NULL, NULL, uv.x, uv.y);
if(params.camera)
- P = transform_perspective(&params.camera->worldtoraster, P);
+ P = transform_point(&params.objecttoworld, P);
return P;
}
@@ -66,10 +66,21 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend)
for(int i = 0; i < params.test_steps; i++) {
float t = i/(float)(params.test_steps-1);
- float3 P = project(patch, Pstart + t*(Pend - Pstart));
+ float3 P = to_world(patch, Pstart + t*(Pend - Pstart));
if(i > 0) {
- float L = len(P - Plast);
+ float L;
+
+ if(!params.camera) {
+ L = len(P - Plast);
+ }
+ else {
+ Camera* cam = params.camera;
+
+ float pixel_width = cam->world_to_raster_size((P + Plast) * 0.5f);
+ L = len(P - Plast) / pixel_width;
+ }
+
Lsum += L;
Lmax = max(L, Lmax);
}
@@ -101,93 +112,158 @@ void DiagSplit::partition_edge(Patch *patch, float2 *P, int *t0, int *t1, float2
}
}
-void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth)
+static float2 right_to_equilateral(float2 P)
{
- assert(ef.tu == T(sub.patch, sub.Pv, sub.Pw));
- assert(ef.tv == T(sub.patch, sub.Pw, sub.Pu));
- assert(ef.tw == T(sub.patch, sub.Pu, sub.Pv));
+ static const float2 A = make_float2(1.0f, 0.5f);
+ static const float2 B = make_float2(0.0f, sinf(M_PI_F/3.0f));
+ return make_float2(dot(P, A), dot(P, B));
+}
- if(depth == 0) {
- dispatch(sub, ef);
- return;
+static void limit_edge_factors(const TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int max_t)
+{
+ float2 Pu = sub.Pu;
+ float2 Pv = sub.Pv;
+ float2 Pw = sub.Pw;
+
+ if(sub.patch->is_triangle()) {
+ Pu = right_to_equilateral(Pu);
+ Pv = right_to_equilateral(Pv);
+ Pw = right_to_equilateral(Pw);
}
- if(ef.tu == DSPLIT_NON_UNIFORM) {
- /* partition edges */
- TriangleDice::EdgeFactors ef0, ef1;
- float2 Psplit;
+ int tu = int(max_t * len(Pw - Pv));
+ int tv = int(max_t * len(Pw - Pu));
+ int tw = int(max_t * len(Pv - Pu));
- partition_edge(sub.patch,
- &Psplit, &ef1.tu, &ef0.tu, sub.Pv, sub.Pw, ef.tu);
+ ef.tu = tu <= 1 ? 1 : min(ef.tu, tu);
+ ef.tv = tv <= 1 ? 1 : min(ef.tv, tv);
+ ef.tw = tw <= 1 ? 1 : min(ef.tw, tw);
+}
- /* split */
- int tsplit = T(sub.patch, sub.Pu, Psplit);
- ef0.tv = ef.tv;
- ef0.tw = tsplit;
+static void limit_edge_factors(const QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int max_t)
+{
+ float2 P00 = sub.P00;
+ float2 P01 = sub.P01;
+ float2 P10 = sub.P10;
+ float2 P11 = sub.P11;
+
+ if(sub.patch->is_triangle()) {
+ P00 = right_to_equilateral(P00);
+ P01 = right_to_equilateral(P01);
+ P10 = right_to_equilateral(P10);
+ P11 = right_to_equilateral(P11);
+ }
- ef1.tv = tsplit;
- ef1.tw = ef.tw;
+ int tu0 = int(max_t * len(P10 - P00));
+ int tu1 = int(max_t * len(P11 - P01));
+ int tv0 = int(max_t * len(P01 - P00));
+ int tv1 = int(max_t * len(P11 - P10));
- /* create subpatches */
- TriangleDice::SubPatch sub0 = {sub.patch, sub.Pu, Psplit, sub.Pw};
- TriangleDice::SubPatch sub1 = {sub.patch, sub.Pu, sub.Pv, Psplit};
+ ef.tu0 = tu0 <= 1 ? 1 : min(ef.tu0, tu0);
+ ef.tu1 = tu1 <= 1 ? 1 : min(ef.tu1, tu1);
+ ef.tv0 = tv0 <= 1 ? 1 : min(ef.tv0, tv0);
+ ef.tv1 = tv1 <= 1 ? 1 : min(ef.tv1, tv1);
+}
- split(sub0, ef0, depth+1);
- split(sub1, ef1, depth+1);
+void DiagSplit::split(TriangleDice::SubPatch& sub, TriangleDice::EdgeFactors& ef, int depth)
+{
+ if(depth > 32) {
+ /* We should never get here, but just in case end recursion safely. */
+ ef.tu = 1;
+ ef.tv = 1;
+ ef.tw = 1;
+
+ dispatch(sub, ef);
+ return;
}
- else if(ef.tv == DSPLIT_NON_UNIFORM) {
- /* partition edges */
- TriangleDice::EdgeFactors ef0, ef1;
- float2 Psplit;
- partition_edge(sub.patch,
- &Psplit, &ef1.tu, &ef0.tu, sub.Pw, sub.Pu, ef.tv);
+ assert(ef.tu == T(sub.patch, sub.Pv, sub.Pw));
+ assert(ef.tv == T(sub.patch, sub.Pw, sub.Pu));
+ assert(ef.tw == T(sub.patch, sub.Pu, sub.Pv));
- /* split */
- int tsplit = T(sub.patch, sub.Pv, Psplit);
- ef0.tv = ef.tw;
- ef0.tw = tsplit;
+ int non_uniform_count = int(ef.tu == DSPLIT_NON_UNIFORM) +
+ int(ef.tv == DSPLIT_NON_UNIFORM) +
+ int(ef.tw == DSPLIT_NON_UNIFORM);
- ef1.tv = tsplit;
- ef1.tw = ef.tu;
+ switch(non_uniform_count) {
+ case 1: {
+ /* TODO(mai): one edge is non-uniform, split into two triangles */
+ // fallthru
+ }
+ case 2: {
+ /* TODO(mai): two edges are non-uniform, split into triangle and quad */
+ // fallthru
+ }
+ case 3: {
+ /* all three edges are non-uniform, split into three quads */
- /* create subpatches */
- TriangleDice::SubPatch sub0 = {sub.patch, sub.Pv, Psplit, sub.Pu};
- TriangleDice::SubPatch sub1 = {sub.patch, sub.Pv, sub.Pw, Psplit};
+ /* partition edges */
+ QuadDice::EdgeFactors ef0, ef1, ef2;
+ float2 Pu, Pv, Pw, Pcenter;
- split(sub0, ef0, depth+1);
- split(sub1, ef1, depth+1);
- }
- else if(ef.tw == DSPLIT_NON_UNIFORM) {
- /* partition edges */
- TriangleDice::EdgeFactors ef0, ef1;
- float2 Psplit;
+ partition_edge(sub.patch, &Pu, &ef1.tv0, &ef2.tu0, sub.Pw, sub.Pv, ef.tu);
+ partition_edge(sub.patch, &Pv, &ef0.tv0, &ef1.tu0, sub.Pu, sub.Pw, ef.tv);
+ partition_edge(sub.patch, &Pw, &ef2.tv0, &ef0.tu0, sub.Pv, sub.Pu, ef.tw);
+ Pcenter = (Pu + Pv + Pw) * (1.0f / 3.0f);
- partition_edge(sub.patch,
- &Psplit, &ef1.tu, &ef0.tu, sub.Pu, sub.Pv, ef.tw);
+ /* split */
+ int tsplit01 = T(sub.patch, Pv, Pcenter);
+ int tsplit12 = T(sub.patch, Pu, Pcenter);
+ int tsplit20 = T(sub.patch, Pw, Pcenter);
- /* split */
- int tsplit = T(sub.patch, sub.Pw, Psplit);
- ef0.tv = ef.tu;
- ef0.tw = tsplit;
+ ef0.tu1 = tsplit01;
+ ef0.tv1 = tsplit20;
- ef1.tv = tsplit;
- ef1.tw = ef.tv;
+ ef1.tu1 = tsplit12;
+ ef1.tv1 = tsplit01;
- /* create subpatches */
- TriangleDice::SubPatch sub0 = {sub.patch, sub.Pw, Psplit, sub.Pv};
- TriangleDice::SubPatch sub1 = {sub.patch, sub.Pw, sub.Pu, Psplit};
+ ef2.tu1 = tsplit20;
+ ef2.tv1 = tsplit12;
- split(sub0, ef0, depth+1);
- split(sub1, ef1, depth+1);
+ /* create subpatches */
+ QuadDice::SubPatch sub0 = {sub.patch, sub.Pu, Pw, Pv, Pcenter};
+ QuadDice::SubPatch sub1 = {sub.patch, sub.Pw, Pv, Pu, Pcenter};
+ QuadDice::SubPatch sub2 = {sub.patch, sub.Pv, Pu, Pw, Pcenter};
+
+ limit_edge_factors(sub0, ef0, 1 << params.max_level);
+ limit_edge_factors(sub1, ef1, 1 << params.max_level);
+ limit_edge_factors(sub2, ef2, 1 << params.max_level);
+
+ split(sub0, ef0, depth+1);
+ split(sub1, ef1, depth+1);
+ split(sub2, ef2, depth+1);
+
+ break;
+ }
+ default: {
+ /* all edges uniform, no splitting needed */
+ dispatch(sub, ef);
+ break;
+ }
}
- else
- dispatch(sub, ef);
}
void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int depth)
{
- if((ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM)) {
+ if(depth > 32) {
+ /* We should never get here, but just in case end recursion safely. */
+ ef.tu0 = 1;
+ ef.tu1 = 1;
+ ef.tv0 = 1;
+ ef.tv1 = 1;
+
+ dispatch(sub, ef);
+ return;
+ }
+
+ bool split_u = (ef.tu0 == DSPLIT_NON_UNIFORM || ef.tu1 == DSPLIT_NON_UNIFORM);
+ bool split_v = (ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM);
+
+ if(split_u && split_v) {
+ split_u = depth % 2;
+ }
+
+ if(split_u) {
/* partition edges */
QuadDice::EdgeFactors ef0, ef1;
float2 Pu0, Pu1;
@@ -209,10 +285,13 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
QuadDice::SubPatch sub0 = {sub.patch, sub.P00, Pu0, sub.P01, Pu1};
QuadDice::SubPatch sub1 = {sub.patch, Pu0, sub.P10, Pu1, sub.P11};
+ limit_edge_factors(sub0, ef0, 1 << params.max_level);
+ limit_edge_factors(sub1, ef1, 1 << params.max_level);
+
split(sub0, ef0, depth+1);
split(sub1, ef1, depth+1);
}
- else if(ef.tv0 == DSPLIT_NON_UNIFORM || ef.tv1 == DSPLIT_NON_UNIFORM) {
+ else if(split_v) {
/* partition edges */
QuadDice::EdgeFactors ef0, ef1;
float2 Pv0, Pv1;
@@ -234,11 +313,15 @@ void DiagSplit::split(QuadDice::SubPatch& sub, QuadDice::EdgeFactors& ef, int de
QuadDice::SubPatch sub0 = {sub.patch, sub.P00, sub.P10, Pv0, Pv1};
QuadDice::SubPatch sub1 = {sub.patch, Pv0, Pv1, sub.P01, sub.P11};
+ limit_edge_factors(sub0, ef0, 1 << params.max_level);
+ limit_edge_factors(sub1, ef1, 1 << params.max_level);
+
split(sub0, ef0, depth+1);
split(sub1, ef1, depth+1);
}
- else
+ else {
dispatch(sub, ef);
+ }
}
void DiagSplit::split_triangle(Patch *patch)
@@ -255,6 +338,8 @@ void DiagSplit::split_triangle(Patch *patch)
ef_split.tv = T(patch, sub_split.Pw, sub_split.Pu);
ef_split.tw = T(patch, sub_split.Pu, sub_split.Pv);
+ limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
+
split(sub_split, ef_split);
TriangleDice dice(params);
@@ -263,10 +348,6 @@ void DiagSplit::split_triangle(Patch *patch)
TriangleDice::SubPatch& sub = subpatches_triangle[i];
TriangleDice::EdgeFactors& ef = edgefactors_triangle[i];
- ef.tu = 4;
- ef.tv = 4;
- ef.tw = 4;
-
ef.tu = max(ef.tu, 1);
ef.tv = max(ef.tv, 1);
ef.tw = max(ef.tw, 1);
@@ -276,6 +357,24 @@ void DiagSplit::split_triangle(Patch *patch)
subpatches_triangle.clear();
edgefactors_triangle.clear();
+
+ /* triangle might be split into quads so dice quad subpatches as well */
+ QuadDice qdice(params);
+
+ for(size_t i = 0; i < subpatches_quad.size(); i++) {
+ QuadDice::SubPatch& sub = subpatches_quad[i];
+ QuadDice::EdgeFactors& ef = edgefactors_quad[i];
+
+ ef.tu0 = max(ef.tu0, 1);
+ ef.tu1 = max(ef.tu1, 1);
+ ef.tv0 = max(ef.tv0, 1);
+ ef.tv1 = max(ef.tv1, 1);
+
+ qdice.dice(sub, ef);
+ }
+
+ subpatches_quad.clear();
+ edgefactors_quad.clear();
}
void DiagSplit::split_quad(Patch *patch)
@@ -294,6 +393,8 @@ void DiagSplit::split_quad(Patch *patch)
ef_split.tv0 = T(patch, sub_split.P00, sub_split.P01);
ef_split.tv1 = T(patch, sub_split.P10, sub_split.P11);
+ limit_edge_factors(sub_split, ef_split, 1 << params.max_level);
+
split(sub_split, ef_split);
QuadDice dice(params);
diff --git a/intern/cycles/subd/subd_split.h b/intern/cycles/subd/subd_split.h
index df4935ee624..f04c51dedfe 100644
--- a/intern/cycles/subd/subd_split.h
+++ b/intern/cycles/subd/subd_split.h
@@ -45,7 +45,7 @@ public:
DiagSplit(const SubdParams& params);
- float3 project(Patch *patch, float2 uv);
+ float3 to_world(Patch *patch, float2 uv);
int T(Patch *patch, float2 Pstart, float2 Pend);
void partition_edge(Patch *patch, float2 *P, int *t0, int *t1,
float2 Pstart, float2 Pend, int t);
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt
new file mode 100644
index 00000000000..2f3a4d0b1df
--- /dev/null
+++ b/intern/cycles/test/CMakeLists.txt
@@ -0,0 +1,31 @@
+if(WITH_GTESTS)
+ Include(GTestTesting)
+
+ # Otherwise we get warnings here that we cant fix in external projects
+ remove_strict_flags()
+endif()
+
+macro(CYCLES_TEST SRC EXTRA_LIBS)
+ if(WITH_GTESTS)
+ BLENDER_SRC_GTEST("cycles_${SRC}" "${SRC}_test.cpp" "${EXTRA_LIBS}")
+ endif()
+endmacro()
+
+set(INC
+ .
+ ..
+ ../util
+)
+
+include_directories(${INC})
+
+link_directories(${BOOST_LIBPATH})
+link_directories(${OPENIMAGEIO_LIBPATH})
+
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
+set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
+
+CYCLES_TEST(util_aligned_malloc "cycles_util")
+CYCLES_TEST(util_path "cycles_util;${BOOST_LIBRARIES};${OPENIMAGEIO_LIBRARIES}")
+CYCLES_TEST(util_string "cycles_util;${BOOST_LIBRARIES}")
+CYCLES_TEST(util_task "cycles_util;${BOOST_LIBRARIES}")
diff --git a/intern/cycles/test/util_aligned_malloc_test.cpp b/intern/cycles/test/util_aligned_malloc_test.cpp
new file mode 100644
index 00000000000..479070f0513
--- /dev/null
+++ b/intern/cycles/test/util_aligned_malloc_test.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testing/testing.h"
+
+#include "util/util_aligned_malloc.h"
+
+#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ(0, (size_t)ptr % align)
+
+CCL_NAMESPACE_BEGIN
+
+TEST(util_aligned_malloc, aligned_malloc_16)
+{
+ int *mem = (int*)util_aligned_malloc(sizeof(int), 16);
+ CHECK_ALIGNMENT(mem, 16);
+ util_aligned_free(mem);
+}
+
+/* On Apple we currently only support 16 bytes alignment. */
+#ifndef __APPLE__
+TEST(util_aligned_malloc, aligned_malloc_32)
+{
+ int *mem = (int*)util_aligned_malloc(sizeof(int), 32);
+ CHECK_ALIGNMENT(mem, 32);
+ util_aligned_free(mem);
+}
+#endif /* __APPLE__ */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/test/util_path_test.cpp b/intern/cycles/test/util_path_test.cpp
new file mode 100644
index 00000000000..92be1dd4cbe
--- /dev/null
+++ b/intern/cycles/test/util_path_test.cpp
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testing/testing.h"
+
+#include "util/util_path.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* ******** Tests for path_filename() ******** */
+
+#ifndef _WIN32
+TEST(util_path_filename, simple_unix)
+{
+ string str = path_filename("/tmp/foo.txt");
+ EXPECT_EQ("foo.txt", str);
+}
+
+TEST(util_path_filename, root_unix)
+{
+ string str = path_filename("/");
+ EXPECT_EQ("/", str);
+}
+
+TEST(util_path_filename, last_slash_unix)
+{
+ string str = path_filename("/tmp/foo.txt/");
+ EXPECT_EQ(".", str);
+}
+
+TEST(util_path_filename, alternate_slash_unix)
+{
+ string str = path_filename("/tmp\\foo.txt");
+ EXPECT_EQ("tmp\\foo.txt", str);
+}
+#endif /* !_WIN32 */
+
+TEST(util_path_filename, file_only)
+{
+ string str = path_filename("foo.txt");
+ EXPECT_EQ("foo.txt", str);
+}
+
+TEST(util_path_filename, empty)
+{
+ string str = path_filename("");
+ EXPECT_EQ("", str);
+}
+
+#ifdef _WIN32
+TEST(util_path_filename, simple_windows)
+{
+ string str = path_filename("C:\\tmp\\foo.txt");
+ EXPECT_EQ("foo.txt", str);
+}
+
+TEST(util_path_filename, root_windows)
+{
+ string str = path_filename("C:\\");
+ EXPECT_EQ("\\", str);
+}
+
+TEST(util_path_filename, last_slash_windows)
+{
+ string str = path_filename("C:\\tmp\\foo.txt\\");
+ EXPECT_EQ(".", str);
+}
+
+TEST(util_path_filename, alternate_slash_windows)
+{
+ string str = path_filename("C:\\tmp/foo.txt");
+ EXPECT_EQ("foo.txt", str);
+}
+#endif /* _WIN32 */
+
+/* ******** Tests for path_dirname() ******** */
+
+#ifndef _WIN32
+TEST(util_path_dirname, simple_unix)
+{
+ string str = path_dirname("/tmp/foo.txt");
+ EXPECT_EQ("/tmp", str);
+}
+
+TEST(util_path_dirname, root_unix)
+{
+ string str = path_dirname("/");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_path_dirname, last_slash_unix)
+{
+ string str = path_dirname("/tmp/foo.txt/");
+ EXPECT_EQ("/tmp/foo.txt", str);
+}
+
+TEST(util_path_dirname, alternate_slash_unix)
+{
+ string str = path_dirname("/tmp\\foo.txt");
+ EXPECT_EQ("/", str);
+}
+#endif /* !_WIN32 */
+
+TEST(util_path_dirname, file_only)
+{
+ string str = path_dirname("foo.txt");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_path_dirname, empty)
+{
+ string str = path_dirname("");
+ EXPECT_EQ("", str);
+}
+
+#ifdef _WIN32
+TEST(util_path_dirname, simple_windows)
+{
+ string str = path_dirname("C:\\tmp\\foo.txt");
+ EXPECT_EQ("C:\\tmp", str);
+}
+
+TEST(util_path_dirname, root_windows)
+{
+ string str = path_dirname("C:\\");
+ EXPECT_EQ("C:", str);
+}
+
+TEST(util_path_dirname, last_slash_windows)
+{
+ string str = path_dirname("C:\\tmp\\foo.txt\\");
+ EXPECT_EQ("C:\\tmp\\foo.txt", str);
+}
+
+TEST(util_path_dirname, alternate_slash_windows)
+{
+ string str = path_dirname("C:\\tmp/foo.txt");
+ EXPECT_EQ("C:\\tmp", str);
+}
+#endif /* _WIN32 */
+
+/* ******** Tests for path_join() ******** */
+
+TEST(util_path_join, empty_both)
+{
+ string str = path_join("", "");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_path_join, empty_directory)
+{
+ string str = path_join("", "foo.txt");
+ EXPECT_EQ("foo.txt", str);
+}
+
+TEST(util_path_join, empty_filename)
+{
+ string str = path_join("foo", "");
+ EXPECT_EQ("foo", str);
+}
+
+#ifndef _WIN32
+TEST(util_path_join, simple_unix)
+{
+ string str = path_join("foo", "bar");
+ EXPECT_EQ("foo/bar", str);
+}
+
+TEST(util_path_join, directory_slash_unix)
+{
+ string str = path_join("foo/", "bar");
+ EXPECT_EQ("foo/bar", str);
+}
+
+TEST(util_path_join, filename_slash_unix)
+{
+ string str = path_join("foo", "/bar");
+ EXPECT_EQ("foo/bar", str);
+}
+
+TEST(util_path_join, both_slash_unix)
+{
+ string str = path_join("foo/", "/bar");
+ EXPECT_EQ("foo//bar", str);
+}
+
+TEST(util_path_join, directory_alternate_slash_unix)
+{
+ string str = path_join("foo\\", "bar");
+ EXPECT_EQ("foo\\/bar", str);
+}
+
+TEST(util_path_join, filename_alternate_slash_unix)
+{
+ string str = path_join("foo", "\\bar");
+ EXPECT_EQ("foo/\\bar", str);
+}
+
+TEST(util_path_join, both_alternate_slash_unix)
+{
+ string str = path_join("foo", "\\bar");
+ EXPECT_EQ("foo/\\bar", str);
+}
+
+TEST(util_path_join, empty_dir_filename_slash_unix)
+{
+ string str = path_join("", "/foo.txt");
+ EXPECT_EQ("/foo.txt", str);
+}
+
+TEST(util_path_join, empty_dir_filename_alternate_slash_unix)
+{
+ string str = path_join("", "\\foo.txt");
+ EXPECT_EQ("\\foo.txt", str);
+}
+
+TEST(util_path_join, empty_filename_dir_slash_unix)
+{
+ string str = path_join("foo/", "");
+ EXPECT_EQ("foo/", str);
+}
+
+TEST(util_path_join, empty_filename_dir_alternate_slash_unix)
+{
+ string str = path_join("foo\\", "");
+ EXPECT_EQ("foo\\", str);
+}
+#else /* !_WIN32 */
+TEST(util_path_join, simple_windows)
+{
+ string str = path_join("foo", "bar");
+ EXPECT_EQ("foo\\bar", str);
+}
+
+TEST(util_path_join, directory_slash_windows)
+{
+ string str = path_join("foo\\", "bar");
+ EXPECT_EQ("foo\\bar", str);
+}
+
+TEST(util_path_join, filename_slash_windows)
+{
+ string str = path_join("foo", "\\bar");
+ EXPECT_EQ("foo\\bar", str);
+}
+
+TEST(util_path_join, both_slash_windows)
+{
+ string str = path_join("foo\\", "\\bar");
+ EXPECT_EQ("foo\\\\bar", str);
+}
+
+TEST(util_path_join, directory_alternate_slash_windows)
+{
+ string str = path_join("foo/", "bar");
+ EXPECT_EQ("foo/bar", str);
+}
+
+TEST(util_path_join, filename_alternate_slash_windows)
+{
+ string str = path_join("foo", "/bar");
+ EXPECT_EQ("foo/bar", str);
+}
+
+TEST(util_path_join, both_alternate_slash_windows)
+{
+ string str = path_join("foo/", "/bar");
+ EXPECT_EQ("foo//bar", str);
+}
+
+TEST(util_path_join, empty_dir_filename_slash_windows)
+{
+ string str = path_join("", "\\foo.txt");
+ EXPECT_EQ("\\foo.txt", str);
+}
+
+TEST(util_path_join, empty_dir_filename_alternate_slash_windows)
+{
+ string str = path_join("", "/foo.txt");
+ EXPECT_EQ("/foo.txt", str);
+}
+
+TEST(util_path_join, empty_filename_dir_slash_windows)
+{
+ string str = path_join("foo\\", "");
+ EXPECT_EQ("foo\\", str);
+}
+
+TEST(util_path_join, empty_filename_dir_alternate_slash_windows)
+{
+ string str = path_join("foo/", "");
+ EXPECT_EQ("foo/", str);
+}
+#endif /* !_WIN32 */
+
+/* ******** Tests for path_escape() ******** */
+
+TEST(util_path_escape, no_escape_chars)
+{
+ string str = path_escape("/tmp/foo/bar");
+ EXPECT_EQ("/tmp/foo/bar", str);
+}
+
+TEST(util_path_escape, simple)
+{
+ string str = path_escape("/tmp/foo bar");
+ EXPECT_EQ("/tmp/foo\\ bar", str);
+}
+
+TEST(util_path_escape, simple_end)
+{
+ string str = path_escape("/tmp/foo/bar ");
+ EXPECT_EQ("/tmp/foo/bar\\ ", str);
+}
+
+TEST(util_path_escape, multiple)
+{
+ string str = path_escape("/tmp/foo bar");
+ EXPECT_EQ("/tmp/foo\\ \\ bar", str);
+}
+
+TEST(util_path_escape, simple_multiple_end)
+{
+ string str = path_escape("/tmp/foo/bar ");
+ EXPECT_EQ("/tmp/foo/bar\\ \\ ", str);
+}
+
+/* ******** Tests for path_is_relative() ******** */
+
+TEST(util_path_is_relative, filename)
+{
+ bool is_relative = path_is_relative("foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+
+#ifndef _WIN32
+TEST(util_path_is_relative, absolute_unix)
+{
+ bool is_relative = path_is_relative("/tmp/foo.txt");
+ EXPECT_FALSE(is_relative);
+}
+
+TEST(util_path_is_relative, relative_dir_unix)
+{
+ bool is_relative = path_is_relative("tmp/foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+
+TEST(util_path_is_relative, absolute_windir_on_unix)
+{
+ bool is_relative = path_is_relative("C:\\tmp\\foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+
+TEST(util_path_is_relative, relative_windir_on_unix)
+{
+ bool is_relative = path_is_relative("tmp\\foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+TEST(util_path_is_relative, absolute_windows)
+{
+ bool is_relative = path_is_relative("C:\\tmp\\foo.txt");
+ EXPECT_FALSE(is_relative);
+}
+
+TEST(util_path_is_relative, relative_dir_windows)
+{
+ bool is_relative = path_is_relative("tmp\\foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+
+TEST(util_path_is_relative, absolute_unixdir_on_windows)
+{
+ bool is_relative = path_is_relative("/tmp/foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+
+TEST(util_path_is_relative, relative_unixdir_on_windows)
+{
+ bool is_relative = path_is_relative("tmp/foo.txt");
+ EXPECT_TRUE(is_relative);
+}
+#endif /* _WIN32 */
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/test/util_string_test.cpp b/intern/cycles/test/util_string_test.cpp
new file mode 100644
index 00000000000..e502a35704b
--- /dev/null
+++ b/intern/cycles/test/util_string_test.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testing/testing.h"
+
+#include "util/util_string.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* ******** Tests for string_printf() ******** */
+
+TEST(util_string_printf, no_format)
+{
+ string str = string_printf("foo bar");
+ EXPECT_EQ(str, "foo bar");
+}
+
+TEST(util_string_printf, int_number)
+{
+ string str = string_printf("foo %d bar", 314);
+ EXPECT_EQ(str, "foo 314 bar");
+}
+
+TEST(util_string_printf, float_number_default_precision)
+{
+ string str = string_printf("foo %f bar", 3.1415);
+ EXPECT_EQ(str, "foo 3.141500 bar");
+}
+
+TEST(util_string_printf, float_number_custom_precision)
+{
+ string str = string_printf("foo %.1f bar", 3.1415);
+ EXPECT_EQ(str, "foo 3.1 bar");
+}
+
+/* ******** Tests for string_printf() ******** */
+
+TEST(util_string_iequals, empty_a)
+{
+ bool equals = string_iequals("", "foo");
+ EXPECT_FALSE(equals);
+}
+
+TEST(util_string_iequals, empty_b)
+{
+ bool equals = string_iequals("foo", "");
+ EXPECT_FALSE(equals);
+}
+
+TEST(util_string_iequals, same_register)
+{
+ bool equals = string_iequals("foo", "foo");
+ EXPECT_TRUE(equals);
+}
+
+TEST(util_string_iequals, different_register)
+{
+ bool equals = string_iequals("XFoo", "XfoO");
+ EXPECT_TRUE(equals);
+}
+
+/* ******** Tests for string_split() ******** */
+
+TEST(util_string_split, empty)
+{
+ vector<string> tokens;
+ string_split(tokens, "");
+ EXPECT_EQ(0, tokens.size());
+}
+
+TEST(util_string_split, only_spaces)
+{
+ vector<string> tokens;
+ string_split(tokens, " \t\t \t");
+ EXPECT_EQ(0, tokens.size());
+}
+
+TEST(util_string_split, single)
+{
+ vector<string> tokens;
+ string_split(tokens, "foo");
+ EXPECT_EQ(1, tokens.size());
+ EXPECT_EQ("foo", tokens[0]);
+}
+
+TEST(util_string_split, simple)
+{
+ vector<string> tokens;
+ string_split(tokens, "foo a bar b");
+ EXPECT_EQ(4, tokens.size());
+ EXPECT_EQ("foo", tokens[0]);
+ EXPECT_EQ("a", tokens[1]);
+ EXPECT_EQ("bar", tokens[2]);
+ EXPECT_EQ("b", tokens[3]);
+}
+
+TEST(util_string_split, multiple_spaces)
+{
+ vector<string> tokens;
+ string_split(tokens, " \t foo \ta bar b\t ");
+ EXPECT_EQ(4, tokens.size());
+ EXPECT_EQ("foo", tokens[0]);
+ EXPECT_EQ("a", tokens[1]);
+ EXPECT_EQ("bar", tokens[2]);
+ EXPECT_EQ("b", tokens[3]);
+}
+
+/* ******** Tests for string_replace() ******** */
+
+TEST(util_string_replace, empty_haystack_and_other)
+{
+ string str = "";
+ string_replace(str, "x", "");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_string_replace, empty_haystack)
+{
+ string str = "";
+ string_replace(str, "x", "y");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_string_replace, empty_other)
+{
+ string str = "x";
+ string_replace(str, "x", "");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_string_replace, long_haystack_empty_other)
+{
+ string str = "a x b xxc";
+ string_replace(str, "x", "");
+ EXPECT_EQ("a b c", str);
+}
+
+TEST(util_string_replace, long_haystack)
+{
+ string str = "a x b xxc";
+ string_replace(str, "x", "FOO");
+ EXPECT_EQ("a FOO b FOOFOOc", str);
+}
+
+/* ******** Tests for string_endswith() ******** */
+
+TEST(util_string_endswith, empty_both)
+{
+ bool endswith = string_endswith("", "");
+ EXPECT_TRUE(endswith);
+}
+
+TEST(util_string_endswith, empty_string)
+{
+ bool endswith = string_endswith("", "foo");
+ EXPECT_FALSE(endswith);
+}
+
+TEST(util_string_endswith, empty_end)
+{
+ bool endswith = string_endswith("foo", "");
+ EXPECT_TRUE(endswith);
+}
+
+TEST(util_string_endswith, simple_true)
+{
+ bool endswith = string_endswith("foo bar", "bar");
+ EXPECT_TRUE(endswith);
+}
+
+TEST(util_string_endswith, simple_false)
+{
+ bool endswith = string_endswith("foo bar", "foo");
+ EXPECT_FALSE(endswith);
+}
+
+/* ******** Tests for string_strip() ******** */
+
+TEST(util_string_strip, empty)
+{
+ string str = string_strip("");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_string_strip, only_spaces)
+{
+ string str = string_strip(" ");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_string_strip, no_spaces)
+{
+ string str = string_strip("foo bar");
+ EXPECT_EQ("foo bar", str);
+}
+
+TEST(util_string_strip, with_spaces)
+{
+ string str = string_strip(" foo bar ");
+ EXPECT_EQ("foo bar", str);
+}
+
+/* ******** Tests for string_remove_trademark() ******** */
+
+TEST(util_string_remove_trademark, empty)
+{
+ string str = string_remove_trademark("");
+ EXPECT_EQ("", str);
+}
+
+TEST(util_string_remove_trademark, no_trademark)
+{
+ string str = string_remove_trademark("foo bar");
+ EXPECT_EQ("foo bar", str);
+}
+
+TEST(util_string_remove_trademark, only_tm)
+{
+ string str = string_remove_trademark("foo bar(TM) zzz");
+ EXPECT_EQ("foo bar zzz", str);
+}
+
+TEST(util_string_remove_trademark, only_r)
+{
+ string str = string_remove_trademark("foo bar(R) zzz");
+ EXPECT_EQ("foo bar zzz", str);
+}
+
+TEST(util_string_remove_trademark, both)
+{
+ string str = string_remove_trademark("foo bar(TM)(R) zzz");
+ EXPECT_EQ("foo bar zzz", str);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/test/util_task_test.cpp b/intern/cycles/test/util_task_test.cpp
new file mode 100644
index 00000000000..2268206b214
--- /dev/null
+++ b/intern/cycles/test/util_task_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testing/testing.h"
+
+#include "util/util_task.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace {
+
+void task_run() {
+}
+
+} // namespace
+
+TEST(util_task, basic) {
+ TaskScheduler::init(0);
+ TaskPool pool;
+ for(int i = 0; i < 100; ++i) {
+ pool.push(function_bind(task_run));
+ }
+ TaskPool::Summary summary;
+ pool.wait_work(&summary);
+ TaskScheduler::exit();
+ EXPECT_EQ(summary.num_tasks_handled, 100);
+}
+
+TEST(util_task, multiple_times) {
+ for(int N = 0; N < 1000; ++N) {
+ TaskScheduler::init(0);
+ TaskPool pool;
+ for(int i = 0; i < 100; ++i) {
+ pool.push(function_bind(task_run));
+ }
+ TaskPool::Summary summary;
+ pool.wait_work(&summary);
+ TaskScheduler::exit();
+ EXPECT_EQ(summary.num_tasks_handled, 100);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt
index 0acb9e9304c..cceec8d444c 100644
--- a/intern/cycles/util/CMakeLists.txt
+++ b/intern/cycles/util/CMakeLists.txt
@@ -10,8 +10,9 @@ set(INC_SYS
set(SRC
util_aligned_malloc.cpp
- util_cache.cpp
+ util_debug.cpp
util_logging.cpp
+ util_math_cdf.cpp
util_md5.cpp
util_path.cpp
util_string.cpp
@@ -38,10 +39,11 @@ set(SRC_HEADERS
util_args.h
util_atomic.h
util_boundbox.h
- util_cache.h
util_debug.h
+ util_guarded_allocator.cpp
util_foreach.h
util_function.h
+ util_guarded_allocator.h
util_half.h
util_hash.h
util_image.h
@@ -49,6 +51,7 @@ set(SRC_HEADERS
util_logging.h
util_map.h
util_math.h
+ util_math_cdf.h
util_math_fast.h
util_md5.h
util_opengl.h
@@ -56,33 +59,32 @@ set(SRC_HEADERS
util_param.h
util_path.h
util_progress.h
+ util_queue.h
util_set.h
util_simd.h
+ util_sky_model.cpp
+ util_sky_model.h
+ util_sky_model_data.h
util_sseb.h
util_ssef.h
util_ssei.h
+ util_stack_allocator.h
util_stats.h
util_string.h
util_system.h
util_task.h
+ util_texture.h
util_thread.h
util_time.h
util_transform.h
util_types.h
util_vector.h
+ util_version.h
util_view.h
+ util_windows.h
util_xml.h
)
-if(WITH_CYCLES_DEBUG)
- list(APPEND SRC
- util_guarded_allocator.cpp
- )
- list(APPEND SRC_HEADERS
- util_guarded_allocator.h
- )
-endif()
-
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})
diff --git a/intern/cycles/util/util_aligned_malloc.cpp b/intern/cycles/util/util_aligned_malloc.cpp
index b161a55c15e..15d2eb3271b 100644
--- a/intern/cycles/util/util_aligned_malloc.cpp
+++ b/intern/cycles/util/util_aligned_malloc.cpp
@@ -44,8 +44,7 @@ void *util_aligned_malloc(size_t size, int alignment)
{
#ifdef WITH_BLENDER_GUARDEDALLOC
return MEM_mallocN_aligned(size, alignment, "Cycles Aligned Alloc");
-#endif
-#ifdef _WIN32
+#elif defined(_WIN32)
return _aligned_malloc(size, alignment);
#elif defined(__APPLE__)
/* On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
diff --git a/intern/cycles/util/util_cache.cpp b/intern/cycles/util/util_cache.cpp
deleted file mode 100644
index 5eebfb18155..00000000000
--- a/intern/cycles/util/util_cache.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-
-#include "util_cache.h"
-#include "util_debug.h"
-#include "util_foreach.h"
-#include "util_map.h"
-#include "util_md5.h"
-#include "util_path.h"
-#include "util_types.h"
-
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
-
-CCL_NAMESPACE_BEGIN
-
-/* CacheData */
-
-CacheData::CacheData(const string& name_)
-{
- name = name_;
- f = NULL;
- have_filename = false;
-}
-
-CacheData::~CacheData()
-{
- if(f)
- fclose(f);
-}
-
-const string& CacheData::get_filename()
-{
- if(!have_filename) {
- MD5Hash hash;
-
- foreach(const CacheBuffer& buffer, buffers)
- if(buffer.size)
- hash.append((uint8_t*)buffer.data, buffer.size);
-
- filename = name + "_" + hash.get_hex();
- have_filename = true;
- }
-
- return filename;
-}
-
-/* Cache */
-
-Cache Cache::global;
-
-string Cache::data_filename(CacheData& key)
-{
- return path_user_get(path_join("cache", key.get_filename()));
-}
-
-void Cache::insert(CacheData& key, CacheData& value)
-{
- string filename = data_filename(key);
- path_create_directories(filename);
- FILE *f = path_fopen(filename, "wb");
-
- if(!f) {
- fprintf(stderr, "Failed to open file %s for writing.\n", filename.c_str());
- return;
- }
-
- foreach(CacheBuffer& buffer, value.buffers) {
- if(!fwrite(&buffer.size, sizeof(buffer.size), 1, f))
- fprintf(stderr, "Failed to write to file %s.\n", filename.c_str());
- if(buffer.size)
- if(!fwrite(buffer.data, buffer.size, 1, f))
- fprintf(stderr, "Failed to write to file %s.\n", filename.c_str());
- }
-
- fclose(f);
-}
-
-bool Cache::lookup(CacheData& key, CacheData& value)
-{
- string filename = data_filename(key);
- FILE *f = path_fopen(filename, "rb");
-
- if(!f)
- return false;
-
- value.name = key.name;
- value.f = f;
-
- return true;
-}
-
-void Cache::clear_except(const string& name, const set<string>& except)
-{
- path_cache_clear_except(name, except);
-}
-
-CCL_NAMESPACE_END
-
diff --git a/intern/cycles/util/util_cache.h b/intern/cycles/util/util_cache.h
deleted file mode 100644
index 343fa36817d..00000000000
--- a/intern/cycles/util/util_cache.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2011-2013 Blender Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __UTIL_CACHE_H__
-#define __UTIL_CACHE_H__
-
-/* Disk Cache based on Hashing
- *
- * To be used to cache expensive computations. The hash key is created from an
- * arbitrary number of bytes, by hashing the bytes using MD5, which then gives
- * the file name containing the data. This data then is read from the file
- * again into the appropriate data structures.
- *
- * This way we do not need to accurately track changes, compare dates and
- * invalidate cache entries, at the cost of extra computation. If everything
- * is stored in a global cache, computations can perhaps even be shared between
- * different scenes where it may be hard to detect duplicate work.
- */
-
-#include "util_set.h"
-#include "util_string.h"
-#include "util_vector.h"
-
-CCL_NAMESPACE_BEGIN
-
-class CacheBuffer {
-public:
- const void *data;
- size_t size;
-
- CacheBuffer(const void *data_, size_t size_)
- { data = data_; size = size_; }
-};
-
-class CacheData {
-public:
- vector<CacheBuffer> buffers;
- string name;
- string filename;
- bool have_filename;
- FILE *f;
-
- CacheData(const string& name = "");
- ~CacheData();
-
- const string& get_filename();
-
- template<typename T> void add(const vector<T>& data)
- {
- CacheBuffer buffer(data.size()? &data[0]: NULL, data.size()*sizeof(T));
- buffers.push_back(buffer);
- }
-
- template<typename T> void add(const array<T>& data)
- {
- CacheBuffer buffer(data.size()? &data[0]: NULL, data.size()*sizeof(T));
- buffers.push_back(buffer);
- }
-
- void add(const void *data, size_t size)
- {
- if(size) {
- CacheBuffer buffer(data, size);
- buffers.push_back(buffer);
- }
- }
-
- void add(const int& data)
- {
- CacheBuffer buffer(&data, sizeof(int));
- buffers.push_back(buffer);
- }
-
- void add(const float& data)
- {
- CacheBuffer buffer(&data, sizeof(float));
- buffers.push_back(buffer);
- }
-
- void add(const size_t& data)
- {
- CacheBuffer buffer(&data, sizeof(size_t));
- buffers.push_back(buffer);
- }
-
- template<typename T> bool read(array<T>& data)
- {
- size_t size;
-
- if(!fread(&size, sizeof(size), 1, f)) {
- fprintf(stderr, "Failed to read vector size from cache.\n");
- return false;
- }
-
- if((size == 0) || (size % sizeof(T)) != 0)
- return false;
-
- data.resize(size/sizeof(T));
-
- if(!fread(&data[0], size, 1, f)) {
- fprintf(stderr, "Failed to read vector data from cache (%lu).\n", (unsigned long)size);
- return false;
- }
- return true;
- }
-
- bool read(int& data)
- {
- size_t size;
-
- if(!fread(&size, sizeof(size), 1, f)) {
- fprintf(stderr, "Failed to read int size from cache.\n");
- return false;
- }
- if(!fread(&data, sizeof(data), 1, f)) {
- fprintf(stderr, "Failed to read int from cache.\n");
- return false;
- }
- return true;
- }
-
- bool read(float& data)
- {
- size_t size;
-
- if(!fread(&size, sizeof(size), 1, f)) {
- fprintf(stderr, "Failed to read float size from cache.\n");
- return false;
- }
- if(!fread(&data, sizeof(data), 1, f)) {
- fprintf(stderr, "Failed to read float from cache.\n");
- return false;
- }
- return true;
- }
-
- bool read(size_t& data)
- {
- size_t size;
-
- if(!fread(&size, sizeof(size), 1, f)) {
- fprintf(stderr, "Failed to read size_t size from cache.\n");
- return false;
- }
- if(!fread(&data, sizeof(data), 1, f)) {
- fprintf(stderr, "Failed to read size_t from cache.\n");
- return false;
- }
- return true;
- }
-};
-
-class Cache {
-public:
- static Cache global;
-
- void insert(CacheData& key, CacheData& value);
- bool lookup(CacheData& key, CacheData& value);
-
- void clear_except(const string& name, const set<string>& except);
-
-protected:
- string data_filename(CacheData& key);
-};
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_CACHE_H__ */
-
diff --git a/intern/cycles/util/util_debug.cpp b/intern/cycles/util/util_debug.cpp
new file mode 100644
index 00000000000..448c6223765
--- /dev/null
+++ b/intern/cycles/util/util_debug.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_debug.h"
+
+#include <stdlib.h>
+
+#include "util_logging.h"
+#include "util_string.h"
+
+CCL_NAMESPACE_BEGIN
+
+DebugFlags::CPU::CPU()
+ : avx2(true),
+ avx(true),
+ sse41(true),
+ sse3(true),
+ sse2(true),
+ qbvh(true)
+{
+ reset();
+}
+
+void DebugFlags::CPU::reset()
+{
+#define STRINGIFY(x) #x
+#define CHECK_CPU_FLAGS(flag, env) \
+ do { \
+ flag = (getenv(env) == NULL); \
+ if(!flag) { \
+ VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
+ } \
+ } while(0)
+
+ CHECK_CPU_FLAGS(avx2, "CYCLES_CPU_NO_AVX2");
+ CHECK_CPU_FLAGS(avx, "CYCLES_CPU_NO_AVX");
+ CHECK_CPU_FLAGS(sse41, "CYCLES_CPU_NO_SSE41");
+ CHECK_CPU_FLAGS(sse3, "CYCLES_CPU_NO_SSE3");
+ CHECK_CPU_FLAGS(sse2, "CYCLES_CPU_NO_SSE2");
+
+#undef STRINGIFY
+#undef CHECK_CPU_FLAGS
+
+ qbvh = true;
+}
+
+DebugFlags::OpenCL::OpenCL()
+ : device_type(DebugFlags::OpenCL::DEVICE_ALL),
+ kernel_type(DebugFlags::OpenCL::KERNEL_DEFAULT),
+ debug(false)
+{
+ reset();
+}
+
+void DebugFlags::OpenCL::reset()
+{
+ /* Initialize device type from environment variables. */
+ device_type = DebugFlags::OpenCL::DEVICE_ALL;
+ char *device = getenv("CYCLES_OPENCL_TEST");
+ if(device) {
+ if(strcmp(device, "NONE") == 0) {
+ device_type = DebugFlags::OpenCL::DEVICE_NONE;
+ }
+ else if(strcmp(device, "ALL") == 0) {
+ device_type = DebugFlags::OpenCL::DEVICE_ALL;
+ }
+ else if(strcmp(device, "DEFAULT") == 0) {
+ device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
+ }
+ else if(strcmp(device, "CPU") == 0) {
+ device_type = DebugFlags::OpenCL::DEVICE_CPU;
+ }
+ else if(strcmp(device, "GPU") == 0) {
+ device_type = DebugFlags::OpenCL::DEVICE_GPU;
+ }
+ else if(strcmp(device, "ACCELERATOR") == 0) {
+ device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
+ }
+ }
+ /* Initialize kernel type from environment variables. */
+ kernel_type = DebugFlags::OpenCL::KERNEL_DEFAULT;
+ if(getenv("CYCLES_OPENCL_MEGA_KERNEL_TEST") != NULL) {
+ kernel_type = DebugFlags::OpenCL::KERNEL_MEGA;
+ }
+ else if(getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST") != NULL) {
+ kernel_type = DebugFlags::OpenCL::KERNEL_SPLIT;
+ }
+ /* Initialize other flags from environment variables. */
+ debug = (getenv("CYCLES_OPENCL_DEBUG") != NULL);
+}
+
+DebugFlags::DebugFlags()
+{
+ /* Nothing for now. */
+}
+
+void DebugFlags::reset()
+{
+ cpu.reset();
+ opencl.reset();
+}
+
+std::ostream& operator <<(std::ostream &os,
+ DebugFlagsConstRef debug_flags)
+{
+ os << "CPU flags:\n"
+ << " AVX2 : " << string_from_bool(debug_flags.cpu.avx2) << "\n"
+ << " AVX : " << string_from_bool(debug_flags.cpu.avx) << "\n"
+ << " SSE4.1 : " << string_from_bool(debug_flags.cpu.sse41) << "\n"
+ << " SSE3 : " << string_from_bool(debug_flags.cpu.sse3) << "\n"
+ << " SSE2 : " << string_from_bool(debug_flags.cpu.sse2) << "\n";
+
+ const char *opencl_device_type,
+ *opencl_kernel_type;
+ switch(debug_flags.opencl.device_type) {
+ case DebugFlags::OpenCL::DEVICE_NONE:
+ opencl_device_type = "NONE";
+ break;
+ case DebugFlags::OpenCL::DEVICE_ALL:
+ opencl_device_type = "ALL";
+ break;
+ case DebugFlags::OpenCL::DEVICE_DEFAULT:
+ opencl_device_type = "DEFAULT";
+ break;
+ case DebugFlags::OpenCL::DEVICE_CPU:
+ opencl_device_type = "CPU";
+ break;
+ case DebugFlags::OpenCL::DEVICE_GPU:
+ opencl_device_type = "GPU";
+ break;
+ case DebugFlags::OpenCL::DEVICE_ACCELERATOR:
+ opencl_device_type = "ACCELERATOR";
+ break;
+ }
+ switch(debug_flags.opencl.kernel_type) {
+ case DebugFlags::OpenCL::KERNEL_DEFAULT:
+ opencl_kernel_type = "DEFAULT";
+ break;
+ case DebugFlags::OpenCL::KERNEL_MEGA:
+ opencl_kernel_type = "MEGA";
+ break;
+ case DebugFlags::OpenCL::KERNEL_SPLIT:
+ opencl_kernel_type = "SPLIT";
+ break;
+ }
+ os << "OpenCL flags:\n"
+ << " Device type : " << opencl_device_type << "\n"
+ << " Kernel type : " << opencl_kernel_type << "\n"
+ << " Debug : " << string_from_bool(debug_flags.opencl.debug)
+ << "\n";
+ return os;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_debug.h b/intern/cycles/util/util_debug.h
index 6b61a49fcc3..6ec5188049d 100644
--- a/intern/cycles/util/util_debug.h
+++ b/intern/cycles/util/util_debug.h
@@ -17,7 +17,123 @@
#ifndef __UTIL_DEBUG_H__
#define __UTIL_DEBUG_H__
-#include <assert.h>
+#include <cassert>
+#include <iostream>
-#endif /* __UTIL_DEBUG_H__ */
+CCL_NAMESPACE_BEGIN
+
+/* Global storage for all sort of flags used to fine-tune behavior of particular
+ * areas for the development purposes, without officially exposing settings to
+ * the interface.
+ */
+class DebugFlags {
+public:
+ /* Descriptor of CPU feature-set to be used. */
+ struct CPU {
+ CPU();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Flags describing which instructions sets are allowed for use. */
+ bool avx2;
+ bool avx;
+ bool sse41;
+ bool sse3;
+ bool sse2;
+
+ /* Whether QBVH usage is allowed or not. */
+ bool qbvh;
+ };
+
+ /* Descriptor of OpenCL feature-set to be used. */
+ struct OpenCL {
+ OpenCL();
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Available device types.
+ * Only gives a hint which devices to let user to choose from, does not
+ * try to use any sort of optimal device or so.
+ */
+ enum DeviceType {
+ /* None of OpenCL devices will be used. */
+ DEVICE_NONE,
+ /* All OpenCL devices will be used. */
+ DEVICE_ALL,
+ /* Default system OpenCL device will be used. */
+ DEVICE_DEFAULT,
+ /* Host processor will be used. */
+ DEVICE_CPU,
+ /* GPU devices will be used. */
+ DEVICE_GPU,
+ /* Dedicated OpenCL accelerator device will be used. */
+ DEVICE_ACCELERATOR,
+ };
+
+ /* Available kernel types. */
+ enum KernelType {
+ /* Do automated guess which kernel to use, based on the officially
+ * supported GPUs and such.
+ */
+ KERNEL_DEFAULT,
+ /* Force mega kernel to be used. */
+ KERNEL_MEGA,
+ /* Force split kernel to be used. */
+ KERNEL_SPLIT,
+ };
+
+ /* Requested device type. */
+ DeviceType device_type;
+
+ /* Requested kernel type. */
+ KernelType kernel_type;
+ /* Use debug version of the kernel. */
+ bool debug;
+ };
+
+ /* Get instance of debug flags registry. */
+ static DebugFlags& get()
+ {
+ static DebugFlags instance;
+ return instance;
+ }
+
+ /* Reset flags to their defaults. */
+ void reset();
+
+ /* Requested CPU flags. */
+ CPU cpu;
+
+ /* Requested OpenCL flags. */
+ OpenCL opencl;
+
+private:
+ DebugFlags();
+
+#if (__cplusplus > 199711L)
+public:
+ DebugFlags(DebugFlags const& /*other*/) = delete;
+ void operator=(DebugFlags const& /*other*/) = delete;
+#else
+private:
+ DebugFlags(DebugFlags const& /*other*/);
+ void operator=(DebugFlags const& /*other*/);
+#endif
+};
+
+typedef DebugFlags& DebugFlagsRef;
+typedef const DebugFlags& DebugFlagsConstRef;
+
+inline DebugFlags& DebugFlags() {
+ return DebugFlags::get();
+}
+
+std::ostream& operator <<(std::ostream &os,
+ DebugFlagsConstRef debug_flags);
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_DEBUG_H__ */
diff --git a/intern/cycles/util/util_guarded_allocator.h b/intern/cycles/util/util_guarded_allocator.h
index 2df717253e3..f6004749a13 100644
--- a/intern/cycles/util/util_guarded_allocator.h
+++ b/intern/cycles/util/util_guarded_allocator.h
@@ -17,17 +17,10 @@
#ifndef __UTIL_GUARDED_ALLOCATOR_H__
#define __UTIL_GUARDED_ALLOCATOR_H__
-/* Define this in order to use Blender's guarded allocator to keep
- * track of allocated buffers, their sizes and peak memory usage.
- *
- * This is usually a bad level call, but it's really handy to keep
- * track of overall peak memory consumption during the scene
- * synchronization step.
- */
-#undef WITH_BLENDER_GUARDEDALLOC
-
+#include <cstddef>
#include <memory>
+#include "util_debug.h"
#include "util_types.h"
#ifdef WITH_BLENDER_GUARDEDALLOC
@@ -42,39 +35,122 @@ void util_guarded_mem_free(size_t n);
/* Guarded allocator for the use with STL. */
template <typename T>
-class GuardedAllocator : public std::allocator<T> {
+class GuardedAllocator {
public:
- template<typename _Tp1>
- struct rebind {
- typedef GuardedAllocator<_Tp1> other;
- };
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T *pointer;
+ typedef const T *const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ GuardedAllocator() {}
+ GuardedAllocator(const GuardedAllocator&) {}
T *allocate(size_t n, const void *hint = 0)
{
- util_guarded_mem_alloc(n * sizeof(T));
-#ifdef WITH_BLENDER_GUARDEDALLOC
+ size_t size = n * sizeof(T);
+ util_guarded_mem_alloc(size);
(void)hint;
- return (T*)MEM_mallocN_aligned(n * sizeof(T), 16, "Cycles Alloc");
+#ifdef WITH_BLENDER_GUARDEDALLOC
+ if(n == 0) {
+ return NULL;
+ }
+ /* C++ standard requires allocation functions to allocate memory suitably
+ * aligned for any standard type. This is 16 bytes for 64 bit platform as
+ * far as i concerned. We might over-align on 32bit here, but that should
+ * be all safe actually.
+ */
+ return (T*)MEM_mallocN_aligned(size, 16, "Cycles Alloc");
#else
- return std::allocator<T>::allocate(n, hint);
+ return (T*)malloc(size);
#endif
}
void deallocate(T *p, size_t n)
{
util_guarded_mem_free(n * sizeof(T));
+ if(p != NULL) {
#ifdef WITH_BLENDER_GUARDEDALLOC
- MEM_freeN((void*)p);
+ MEM_freeN(p);
#else
- std::allocator<T>::deallocate(p, n);
+ free(p);
#endif
+ }
+ }
+
+ T *address(T& x) const
+ {
+ return &x;
+ }
+
+ const T *address(const T& x) const
+ {
+ return &x;
+ }
+
+ GuardedAllocator<T>& operator=(const GuardedAllocator&)
+ {
+ return *this;
+ }
+
+ void construct(T *p, const T& val)
+ {
+ new ((T *)p) T(val);
}
- GuardedAllocator() : std::allocator<T>() { }
- GuardedAllocator(const GuardedAllocator &a) : std::allocator<T>(a) { }
+ void destroy(T *p)
+ {
+ p->~T();
+ }
+
+ size_t max_size() const
+ {
+ return size_t(-1);
+ }
+
+ template <class U>
+ struct rebind {
+ typedef GuardedAllocator<U> other;
+ };
+
template <class U>
- GuardedAllocator(const GuardedAllocator<U> &a) : std::allocator<T>(a) { }
- ~GuardedAllocator() { }
+ GuardedAllocator(const GuardedAllocator<U>&) {}
+
+ template <class U>
+ GuardedAllocator& operator=(const GuardedAllocator<U>&) { return *this; }
+
+ inline bool operator==(GuardedAllocator const& /*other*/) const { return true; }
+ inline bool operator!=(GuardedAllocator const& other) const { return !operator==(other); }
+
+#ifdef _MSC_VER
+ /* Welcome to the black magic here.
+ *
+ * The issue is that MSVC C++ allocates container proxy on any
+ * vector initialization, including static vectors which don't
+ * have any data yet. This leads to several issues:
+ *
+ * - Static objects initialization fiasco (global_stats from
+ * util_stats.h might not be initialized yet).
+ * - If main() function changes allocator type (for example,
+ * this might happen with `blender --debug-memory`) nobody
+ * will know how to convert already allocated memory to a new
+ * guarded allocator.
+ *
+ * Here we work this around by making it so container proxy does
+ * not use guarded allocation. A bit fragile, unfortunately.
+ */
+ template<>
+ struct rebind<std::_Container_proxy> {
+ typedef std::allocator<std::_Container_proxy> other;
+ };
+
+ operator std::allocator<std::_Container_proxy>() const
+ {
+ return std::allocator<std::_Container_proxy>();
+ }
+#endif
};
/* Get memory usage and peak from the guarded STL allocator. */
diff --git a/intern/cycles/util/util_logging.h b/intern/cycles/util/util_logging.h
index 7fc42ac355a..2aa9c25b1a0 100644
--- a/intern/cycles/util/util_logging.h
+++ b/intern/cycles/util/util_logging.h
@@ -43,6 +43,8 @@ public:
#endif
+#define VLOG_ONCE(level, flag) if(!flag) flag = true, VLOG(level)
+
struct float3;
void util_logging_init(const char *argv0);
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 7d6dfd34e0e..32924f9a8c2 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -24,10 +24,6 @@
#ifndef __KERNEL_OPENCL__
-#ifdef _MSC_VER
-# define _USE_MATH_DEFINES
-#endif
-
#include <float.h>
#include <math.h>
#include <stdio.h>
@@ -101,6 +97,11 @@ ccl_device_inline float fminf(float a, float b)
#ifndef __KERNEL_GPU__
+ccl_device_inline int abs(int x)
+{
+ return (x > 0)? x: -x;
+}
+
ccl_device_inline int max(int a, int b)
{
return (a > b)? a: b;
@@ -351,7 +352,7 @@ ccl_device_inline float2 normalize_len(const float2 a, float *t)
ccl_device_inline float2 safe_normalize(const float2 a)
{
float t = len(a);
- return (t)? a/t: a;
+ return (t != 0.0f)? a/t: a;
}
ccl_device_inline bool operator==(const float2 a, const float2 b)
@@ -553,7 +554,7 @@ ccl_device_inline float3 normalize_len(const float3 a, float *t)
ccl_device_inline float3 safe_normalize(const float3 a)
{
float t = len(a);
- return (t)? a/t: a;
+ return (t != 0.0f)? a/t: a;
}
#ifndef __KERNEL_OPENCL__
@@ -866,7 +867,7 @@ ccl_device_inline float4 normalize(const float4 a)
ccl_device_inline float4 safe_normalize(const float4 a)
{
float t = len(a);
- return (t)? a/t: a;
+ return (t != 0.0f)? a/t: a;
}
ccl_device_inline float4 min(float4 a, float4 b)
@@ -939,6 +940,37 @@ ccl_device_inline void print_float4(const char *label, const float4& a)
#endif
+/* Int2 */
+
+#ifndef __KERNEL_OPENCL__
+
+ccl_device_inline int2 operator+(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x + b.x, a.y + b.y);
+}
+
+ccl_device_inline int2 operator+=(int2 &a, const int2 &b)
+{
+ return a = a + b;
+}
+
+ccl_device_inline int2 operator-(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x - b.x, a.y - b.y);
+}
+
+ccl_device_inline int2 operator*(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x * b.x, a.y * b.y);
+}
+
+ccl_device_inline int2 operator/(const int2 &a, const int2 &b)
+{
+ return make_int2(a.x / b.x, a.y / b.y);
+}
+
+#endif
+
/* Int3 */
#ifndef __KERNEL_OPENCL__
diff --git a/intern/cycles/util/util_math_cdf.cpp b/intern/cycles/util/util_math_cdf.cpp
new file mode 100644
index 00000000000..ec78ca15d88
--- /dev/null
+++ b/intern/cycles/util/util_math_cdf.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util_math_cdf.h"
+
+#include "util_algorithm.h"
+#include "util_math.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Invert pre-calculated CDF function. */
+void util_cdf_invert(const int resolution,
+ const float from,
+ const float to,
+ const vector<float> &cdf,
+ const bool make_symmetric,
+ vector<float> &inv_cdf) {
+ const float inv_resolution = 1.0f / (float)resolution;
+ const float range = to - from;
+ inv_cdf.resize(resolution);
+ if(make_symmetric) {
+ const int half_size = (resolution - 1) / 2;
+ for(int i = 0; i <= half_size; i++) {
+ float x = i / (float)half_size;
+ int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
+ float t;
+ if(index < cdf.size() - 1) {
+ t = (x - cdf[index])/(cdf[index+1] - cdf[index]);
+ } else {
+ t = 0.0f;
+ index = cdf.size() - 1;
+ }
+ float y = ((index + t) / (resolution - 1)) * (2.0f * range);
+ inv_cdf[half_size+i] = 0.5f*(1.0f + y);
+ inv_cdf[half_size-i] = 0.5f*(1.0f - y);
+ }
+ }
+ else {
+ for(int i = 0; i < resolution; i++) {
+ float x = from + range * (float)i * inv_resolution;
+ int index = upper_bound(cdf.begin(), cdf.end(), x) - cdf.begin();
+ float t;
+ if(index < cdf.size() - 1) {
+ t = (x - cdf[index])/(cdf[index+1] - cdf[index]);
+ } else {
+ t = 0.0f;
+ index = resolution;
+ }
+ inv_cdf[i] = (index + t) * inv_resolution;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_math_cdf.h b/intern/cycles/util/util_math_cdf.h
new file mode 100644
index 00000000000..47dfb68ba44
--- /dev/null
+++ b/intern/cycles/util/util_math_cdf.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_MATH_CDF_H__
+#define __UTIL_MATH_CDF_H__
+
+#include "util_algorithm.h"
+#include "util_math.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Evaluate CDF of a given functor with given range and resolution. */
+template <typename Functor>
+void util_cdf_evaluate(const int resolution,
+ const float from,
+ const float to,
+ Functor functor,
+ vector<float> &cdf)
+{
+ const int cdf_count = resolution + 1;
+ const float range = to - from;
+ cdf.resize(cdf_count);
+ cdf[0] = 0.0f;
+ /* Actual CDF evaluation. */
+ for(int i = 0; i < resolution; ++i) {
+ float x = from + range * (float)i / (resolution - 1);
+ float y = functor(x);
+ cdf[i + 1] = cdf[i] + fabsf(y);
+ }
+ /* Normalize the CDF. */
+ for(int i = 0; i <= resolution; i++) {
+ cdf[i] /= cdf[resolution];
+ }
+}
+
+/* Invert pre-calculated CDF function. */
+void util_cdf_invert(const int resolution,
+ const float from,
+ const float to,
+ const vector<float> &cdf,
+ const bool make_symmetric,
+ vector<float> &inv_cdf);
+
+/* Evaluate inverted CDF of a given functor with given range and resolution. */
+template <typename Functor>
+void util_cdf_inverted(const int resolution,
+ const float from,
+ const float to,
+ Functor functor,
+ const bool make_symmetric,
+ vector<float> &inv_cdf)
+{
+ vector<float> cdf;
+ /* There is no much smartness going around lower resolution for the CDF table,
+ * this just to match the old code from pixel filter so it all stays exactly
+ * the same and no regression tests are failed.
+ */
+ util_cdf_evaluate(resolution - 1, from, to, functor, cdf);
+ util_cdf_invert(resolution, from, to, cdf, make_symmetric, inv_cdf);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_MATH_H_CDF__ */
diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h
index c1a1be603f4..deb2013daae 100644
--- a/intern/cycles/util/util_math_fast.h
+++ b/intern/cycles/util/util_math_fast.h
@@ -47,7 +47,6 @@
CCL_NAMESPACE_BEGIN
-/* TODO(sergey): Make sure it does not conflict with SSE intrinsics. */
ccl_device_inline float madd(const float a, const float b, const float c)
{
/* NOTE: In the future we may want to explicitly ask for a fused
@@ -248,7 +247,7 @@ ccl_device float fast_sinpif(float x)
* The basic idea of this approximation starts with the coarse approximation:
* sin(pi*x) ~= f(x) = 4 * (x - x * abs(x))
*
- * This approximation always _over_ estimates the target. On the otherhand,
+ * This approximation always _over_ estimates the target. On the other hand,
* the curve:
* sin(pi*x) ~= f(x) * abs(f(x)) / 4
*
@@ -314,8 +313,7 @@ ccl_device float fast_atanf(float x)
float r = s * madd(0.43157974f, t, 1.0f) /
madd(madd(0.05831938f, t, 0.76443945f), t, 1.0f);
if(a > 1.0f) {
- /* TODO(sergey): Is it M_PI_2_F? */
- r = 1.570796326794896557998982f - r;
+ r = M_PI_2_F - r;
}
return copysignf(r, x);
}
@@ -341,8 +339,7 @@ ccl_device float fast_atan2f(float y, float x)
if(b > a) {
/* Account for arg reduction. */
- /* TODO(sergey): Is it M_PI_2_F? */
- r = 1.570796326794896557998982f - r;
+ r = M_PI_2_F - r;
}
/* Test sign bit of x. */
if(__float_as_uint(x) & 0x80000000u) {
@@ -536,7 +533,7 @@ ccl_device float fast_safe_powf(float x, float y)
}
/* TODO(sergey): Check speed with our erf functions implementation from
- * bsdf_microfaset.h.
+ * bsdf_microfacet.h.
*/
ccl_device_inline float fast_erff(float x)
diff --git a/intern/cycles/util/util_md5.cpp b/intern/cycles/util/util_md5.cpp
index b2a32c45287..19168135f01 100644
--- a/intern/cycles/util/util_md5.cpp
+++ b/intern/cycles/util/util_md5.cpp
@@ -141,7 +141,7 @@ void MD5Hash::process(const uint8_t *data /*[64]*/)
X = xbuf; /* (dynamic only) */
for(i = 0; i < 16; ++i, xp += 4)
- xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
}
}
@@ -373,5 +373,12 @@ string MD5Hash::get_hex()
return string(buf);
}
+string util_md5_string(const string& str)
+{
+ MD5Hash md5;
+ md5.append((uint8_t*)str.c_str(), str.size());
+ return md5.get_hex();
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_md5.h b/intern/cycles/util/util_md5.h
index aab177d9fe6..d0af9fdb004 100644
--- a/intern/cycles/util/util_md5.h
+++ b/intern/cycles/util/util_md5.h
@@ -53,6 +53,8 @@ protected:
uint8_t buf[64]; /* accumulate block */
};
+string util_md5_string(const string& str);
+
CCL_NAMESPACE_END
#endif /* __UTIL_MD5_H__ */
diff --git a/intern/cycles/util/util_optimization.h b/intern/cycles/util/util_optimization.h
index c951c35fc76..adc141a7b28 100644
--- a/intern/cycles/util/util_optimization.h
+++ b/intern/cycles/util/util_optimization.h
@@ -23,7 +23,9 @@
#if defined(__KERNEL_SSE2__) || \
defined(__KERNEL_SSE3__) || \
defined(__KERNEL_SSSE3__) || \
- defined(__KERNEL_SSE41__)
+ defined(__KERNEL_SSE41__) || \
+ defined(__KERNEL_AVX__) || \
+ defined(__KERNEL_AVX2__)
/* do nothing */
#endif
@@ -33,43 +35,43 @@
#if defined(i386) || defined(_M_IX86)
-#ifdef WITH_KERNEL_SSE2
-#define WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
-#endif
+# ifdef WITH_KERNEL_SSE2
+# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
+# endif
-#ifdef WITH_KERNEL_SSE3
-#define WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
-#endif
+# ifdef WITH_KERNEL_SSE3
+# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
+# endif
-#endif
+#endif /* defined(i386) || defined(_M_IX86) */
/* x86-64
*
- * Compile a regular (includes SSE2), SSE3 and SSE 4.1 kernel. */
+ * Compile a regular (includes SSE2), SSE3, SSE 4.1, AVX and AVX2 kernel. */
#if defined(__x86_64__) || defined(_M_X64)
/* SSE2 is always available on x86-64 CPUs, so auto enable */
-#define __KERNEL_SSE2__
+# define __KERNEL_SSE2__
/* no SSE2 kernel on x86-64, part of regular kernel */
-#ifdef WITH_KERNEL_SSE3
-#define WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
-#endif
+# ifdef WITH_KERNEL_SSE3
+# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE3
+# endif
-#ifdef WITH_KERNEL_SSE41
-#define WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
-#endif
+# ifdef WITH_KERNEL_SSE41
+# define WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
+# endif
-#ifdef WITH_KERNEL_AVX
-#define WITH_CYCLES_OPTIMIZED_KERNEL_AVX
-#endif
+# ifdef WITH_KERNEL_AVX
+# define WITH_CYCLES_OPTIMIZED_KERNEL_AVX
+# endif
-#ifdef WITH_KERNEL_AVX2
-#define WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
-#endif
+# ifdef WITH_KERNEL_AVX2
+# define WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
+# endif
-#endif
+#endif /* defined(__x86_64__) || defined(_M_X64) */
/* SSE Experiment
*
@@ -77,19 +79,19 @@
* such as float3 and float4. Currently this gives an overall slowdown. */
#if 0
-#define __KERNEL_SSE__
-#ifndef __KERNEL_SSE2__
-#define __KERNEL_SSE2__
-#endif
-#ifndef __KERNEL_SSE3__
-#define __KERNEL_SSE3__
-#endif
-#ifndef __KERNEL_SSSE3__
-#define __KERNEL_SSSE3__
-#endif
-#ifndef __KERNEL_SSE4__
-#define __KERNEL_SSE4__
-#endif
+# define __KERNEL_SSE__
+# ifndef __KERNEL_SSE2__
+# define __KERNEL_SSE2__
+# endif
+# ifndef __KERNEL_SSE3__
+# define __KERNEL_SSE3__
+# endif
+# ifndef __KERNEL_SSSE3__
+# define __KERNEL_SSSE3__
+# endif
+# ifndef __KERNEL_SSE4__
+# define __KERNEL_SSE4__
+# endif
#endif
/* SSE Intrinsics includes
@@ -100,19 +102,16 @@
#ifndef FREE_WINDOWS64
#ifdef _MSC_VER
-#include <intrin.h>
-#else
-#include <x86intrin.h>
+# include <intrin.h>
+#elif (defined(__x86_64__) || defined(__i386__))
+# include <x86intrin.h>
#endif
#else
/* MinGW64 has conflicting declarations for these SSE headers in <windows.h>.
* Since we can't avoid including <windows.h>, better only include that */
-#define NOGDI
-#define NOMINMAX
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
+#include "util_windows.h"
#endif
diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp
index e8f1ec81763..83754728dbe 100644
--- a/intern/cycles/util/util_path.cpp
+++ b/intern/cycles/util/util_path.cpp
@@ -19,30 +19,299 @@
#include "util_path.h"
#include "util_string.h"
+#include <OpenImageIO/filesystem.h>
#include <OpenImageIO/strutil.h>
#include <OpenImageIO/sysutil.h>
+
OIIO_NAMESPACE_USING
#include <stdio.h>
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+# define DIR_SEP '\\'
+# define DIR_SEP_ALT '/'
+# include <direct.h>
+#else
+# define DIR_SEP '/'
+# include <dirent.h>
+#endif
+
+#ifdef HAVE_SHLWAPI_H
+# include <shlwapi.h>
+#endif
+
+#include "util_windows.h"
CCL_NAMESPACE_BEGIN
+#ifdef _WIN32
+# if defined(_MSC_VER) || defined(__MINGW64__)
+typedef struct _stat64 path_stat_t;
+# elif defined(__MINGW32__)
+typedef struct _stati64 path_stat_t;
+# else
+typedef struct _stat path_stat_t;
+# endif
+# ifndef S_ISDIR
+# define S_ISDIR(x) (((x) & _S_IFDIR) == _S_IFDIR)
+# endif
+#else
+typedef struct stat path_stat_t;
+#endif
+
static string cached_path = "";
static string cached_user_path = "";
-static boost::filesystem::path to_boost(const string& path)
-{
- return boost::filesystem::path(path.c_str());
-}
+namespace {
+
+#ifdef _WIN32
+class directory_iterator {
+public:
+ class path_info {
+ public:
+ path_info(const string& path,
+ const WIN32_FIND_DATAW& find_data)
+ : path_(path),
+ find_data_(find_data)
+ {
+ }
-static string from_boost(const boost::filesystem::path& path)
+ string path() {
+ return path_join(path_, string_from_wstring(find_data_.cFileName));
+ }
+ protected:
+ const string& path_;
+ const WIN32_FIND_DATAW& find_data_;
+ };
+
+ directory_iterator()
+ : path_info_("", find_data_),
+ h_find_(INVALID_HANDLE_VALUE)
+ {
+ }
+
+ directory_iterator(const string& path)
+ : path_(path),
+ path_info_(path, find_data_)
+ {
+ string wildcard = path;
+ if(wildcard[wildcard.size() - 1] != DIR_SEP) {
+ wildcard += DIR_SEP;
+ }
+ wildcard += "*";
+ h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(),
+ &find_data_);
+ if(h_find_ != INVALID_HANDLE_VALUE) {
+ skip_dots();
+ }
+ }
+
+ ~directory_iterator()
+ {
+ if(h_find_ != INVALID_HANDLE_VALUE) {
+ FindClose(h_find_);
+ }
+ }
+
+ directory_iterator& operator++()
+ {
+ step();
+ return *this;
+ }
+
+ path_info* operator-> ()
+ {
+ return &path_info_;
+ }
+
+ bool operator!=(const directory_iterator& other)
+ {
+ return h_find_ != other.h_find_;
+ }
+
+protected:
+ bool step()
+ {
+ if(do_step()) {
+ return skip_dots();
+ }
+ return false;
+ }
+
+ bool do_step()
+ {
+ if(h_find_ != INVALID_HANDLE_VALUE) {
+ bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
+ if(!result) {
+ FindClose(h_find_);
+ h_find_ = INVALID_HANDLE_VALUE;
+ }
+ return result;
+ }
+ return false;
+ }
+
+ bool skip_dots()
+ {
+ while(wcscmp(find_data_.cFileName, L".") == 0 ||
+ wcscmp(find_data_.cFileName, L"..") == 0)
+ {
+ if(!do_step()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ string path_;
+ path_info path_info_;
+ WIN32_FIND_DATAW find_data_;
+ HANDLE h_find_;
+};
+#else /* _WIN32 */
+
+class directory_iterator {
+public:
+ class path_info {
+ public:
+ path_info(const string& path)
+ : path_(path),
+ entry_(NULL)
+ {
+ }
+
+ string path() {
+ return path_join(path_, entry_->d_name);
+ }
+
+ void current_entry_set(const struct dirent *entry)
+ {
+ entry_ = entry;
+ }
+ protected:
+ const string& path_;
+ const struct dirent *entry_;
+ };
+
+ directory_iterator()
+ : path_info_(""),
+ name_list_(NULL),
+ num_entries_(-1),
+ cur_entry_(-1)
+ {
+ }
+
+ directory_iterator(const string& path)
+ : path_(path),
+ path_info_(path_),
+ cur_entry_(0)
+ {
+ num_entries_ = scandir(path.c_str(),
+ &name_list_,
+ NULL,
+ alphasort);
+ if(num_entries_ < 0) {
+ perror("scandir");
+ }
+ else {
+ skip_dots();
+ }
+ }
+
+ ~directory_iterator()
+ {
+ destroy_name_list();
+ }
+
+ directory_iterator& operator++()
+ {
+ step();
+ return *this;
+ }
+
+ path_info* operator-> ()
+ {
+ path_info_.current_entry_set(name_list_[cur_entry_]);
+ return &path_info_;
+ }
+
+ bool operator!=(const directory_iterator& other)
+ {
+ return name_list_ != other.name_list_;
+ }
+
+protected:
+ bool step()
+ {
+ if(do_step()) {
+ return skip_dots();
+ }
+ return false;
+ }
+
+ bool do_step()
+ {
+ ++cur_entry_;
+ if(cur_entry_ >= num_entries_) {
+ destroy_name_list();
+ return false;
+ }
+ return true;
+ }
+
+ /* Skip . and .. folders. */
+ bool skip_dots()
+ {
+ while(strcmp(name_list_[cur_entry_]->d_name, ".") == 0 ||
+ strcmp(name_list_[cur_entry_]->d_name, "..") == 0)
+ {
+ if(!step()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void destroy_name_list()
+ {
+ if(name_list_ == NULL) {
+ return;
+ }
+ for(int i = 0; i < num_entries_; ++i) {
+ free(name_list_[i]);
+ }
+ free(name_list_);
+ name_list_ = NULL;
+ }
+
+ string path_;
+ path_info path_info_;
+ struct dirent **name_list_;
+ int num_entries_, cur_entry_;
+};
+
+#endif /* _WIN32 */
+
+size_t find_last_slash(const string& path)
{
- return path.string().c_str();
+ for(size_t i = 0; i < path.size(); ++i) {
+ size_t index = path.size() - 1 - i;
+#ifdef _WIN32
+ if(path[index] == DIR_SEP || path[index] == DIR_SEP_ALT)
+#else
+ if(path[index] == DIR_SEP)
+#endif
+ {
+ return index;
+ }
+ }
+ return string::npos;
}
+} /* namespace */
+
static char *path_specials(const string& sub)
{
static bool env_init = false;
@@ -68,8 +337,10 @@ void path_init(const string& path, const string& user_path)
cached_user_path = user_path;
#ifdef _MSC_VER
- // fix for https://svn.boost.org/trac/boost/ticket/6320
- boost::filesystem::path::imbue( std::locale( "" ) );
+ // workaround for https://svn.boost.org/trac/boost/ticket/6320
+ // indirectly init boost codec here since it's not thread safe, and can
+ // cause crashes when it happens in multithreaded image load
+ OIIO::Filesystem::exists(path);
#endif
}
@@ -95,49 +366,237 @@ string path_user_get(const string& sub)
string path_filename(const string& path)
{
- return from_boost(to_boost(path).filename());
+ size_t index = find_last_slash(path);
+ if(index != string::npos) {
+ /* Corner cases to match boost behavior. */
+#ifndef _WIN32
+ if(index == 0 && path.size() == 1) {
+ return path;
+ }
+#endif
+ if(index == path.size() - 1) {
+#ifdef _WIN32
+ if(index == 2) {
+ return string(1, DIR_SEP);
+ }
+#endif
+ return ".";
+ }
+ return path.substr(index + 1, path.size() - index - 1);
+ }
+ return path;
}
string path_dirname(const string& path)
{
- return from_boost(to_boost(path).parent_path());
+ size_t index = find_last_slash(path);
+ if(index != string::npos) {
+#ifndef _WIN32
+ if(index == 0 && path.size() > 1) {
+ return string(1, DIR_SEP);
+ }
+#endif
+ return path.substr(0, index);
+ }
+ return "";
}
string path_join(const string& dir, const string& file)
{
- return from_boost((to_boost(dir) / to_boost(file)));
+ if(dir.size() == 0) {
+ return file;
+ }
+ if(file.size() == 0) {
+ return dir;
+ }
+ string result = dir;
+#ifndef _WIN32
+ if(result[result.size() - 1] != DIR_SEP &&
+ file[0] != DIR_SEP)
+#else
+ if(result[result.size() - 1] != DIR_SEP &&
+ result[result.size() - 1] != DIR_SEP_ALT &&
+ file[0] != DIR_SEP &&
+ file[0] != DIR_SEP_ALT)
+#endif
+ {
+ result += DIR_SEP;
+ }
+ result += file;
+ return result;
}
string path_escape(const string& path)
{
string result = path;
- boost::replace_all(result, " ", "\\ ");
+ string_replace(result, " ", "\\ ");
return result;
}
bool path_is_relative(const string& path)
{
- return to_boost(path).is_relative();
+#ifdef _WIN32
+# ifdef HAVE_SHLWAPI_H
+ return PathIsRelative(path.c_str());
+# else /* HAVE_SHLWAPI_H */
+ if(path.size() >= 3) {
+ return !(((path[0] >= 'a' && path[0] <= 'z') ||
+ (path[0] >= 'A' && path[0] <= 'Z')) &&
+ path[1] == ':' && path[2] == DIR_SEP);
+ }
+ return true;
+# endif /* HAVE_SHLWAPI_H */
+#else /* _WIN32 */
+ if(path.size() == 0) {
+ return 1;
+ }
+ return path[0] != DIR_SEP;
+#endif /* _WIN32 */
+}
+
+#ifdef _WIN32
+/* Add a slash if the UNC path points to a share. */
+static string path_unc_add_slash_to_share(const string& path)
+{
+ size_t slash_after_server = path.find(DIR_SEP, 2);
+ if(slash_after_server != string::npos) {
+ size_t slash_after_share = path.find(DIR_SEP,
+ slash_after_server + 1);
+ if(slash_after_share == string::npos) {
+ return path + DIR_SEP;
+ }
+ }
+ return path;
+}
+
+/* Convert:
+ * \\?\UNC\server\share\folder\... to \\server\share\folder\...
+ * \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
+ */
+static string path_unc_to_short(const string& path)
+{
+ size_t len = path.size();
+ if((len > 3) &&
+ (path[0] == DIR_SEP) &&
+ (path[1] == DIR_SEP) &&
+ (path[2] == '?') &&
+ ((path[3] == DIR_SEP) || (path[3] == DIR_SEP_ALT)))
+ {
+ if((len > 5) && (path[5] == ':')) {
+ return path.substr(4, len - 4);
+ }
+ else if((len > 7) &&
+ (path.substr(4, 3) == "UNC") &&
+ ((path[7] == DIR_SEP) || (path[7] == DIR_SEP_ALT)))
+ {
+ return "\\\\" + path.substr(8, len - 8);
+ }
+ }
+ return path;
+}
+
+static string path_cleanup_unc(const string& path)
+{
+ string result = path_unc_to_short(path);
+ if(path.size() > 2) {
+ /* It's possible path is now a non-UNC. */
+ if(result[0] == DIR_SEP && result[1] == DIR_SEP) {
+ return path_unc_add_slash_to_share(result);
+ }
+ }
+ return result;
+}
+
+/* Make path compatible for stat() functions. */
+static string path_make_compatible(const string& path)
+{
+ string result = path;
+ /* In Windows stat() doesn't recognize dir ending on a slash. */
+ if(result.size() > 3 && result[result.size() - 1] == DIR_SEP) {
+ result.resize(result.size() - 1);
+ }
+ /* Clean up UNC path. */
+ if((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) {
+ result = path_cleanup_unc(result);
+ }
+ /* Make sure volume-only path ends up wit ha directory separator. */
+ if(result.size() == 2 && result[1] == ':') {
+ result += DIR_SEP;
+ }
+ return result;
+}
+
+static int path_wstat(const wstring& path_wc, path_stat_t *st)
+{
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ return _wstat64(path_wc.c_str(), st);
+#elif defined(__MINGW32__)
+ return _wstati64(path_wc.c_str(), st);
+#else
+ return _wstat(path_wc.c_str(), st);
+#endif
+}
+
+static int path_stat(const string& path, path_stat_t *st)
+{
+ wstring path_wc = string_to_wstring(path);
+ return path_wstat(path_wc, st);
+}
+#else /* _WIN32 */
+static int path_stat(const string& path, path_stat_t *st)
+{
+ return stat(path.c_str(), st);
+}
+#endif /* _WIN32 */
+
+size_t path_file_size(const string& path)
+{
+ path_stat_t st;
+ if(path_stat(path, &st) != 0) {
+ return -1;
+ }
+ return st.st_size;
}
bool path_exists(const string& path)
{
- return boost::filesystem::exists(to_boost(path));
+#ifdef _WIN32
+ string fixed_path = path_make_compatible(path);
+ wstring path_wc = string_to_wstring(fixed_path);
+ path_stat_t st;
+ if(path_wstat(path_wc, &st) != 0) {
+ return false;
+ }
+ return st.st_mode != 0;
+#else /* _WIN32 */
+ struct stat st;
+ if(stat(path.c_str(), &st) != 0) {
+ return 0;
+ }
+ return st.st_mode != 0;
+#endif /* _WIN32 */
}
-static void path_files_md5_hash_recursive(MD5Hash& hash, const string& dir)
+bool path_is_directory(const string& path)
{
- boost::filesystem::path dirpath = to_boost(dir);
+ path_stat_t st;
+ if(path_stat(path, &st) != 0) {
+ return false;
+ }
+ return S_ISDIR(st.st_mode);
+}
- if(boost::filesystem::exists(dirpath)) {
- boost::filesystem::directory_iterator it(dirpath), it_end;
+static void path_files_md5_hash_recursive(MD5Hash& hash, const string& dir)
+{
+ if(path_exists(dir)) {
+ directory_iterator it(dir), it_end;
- for(; it != it_end; it++) {
- if(boost::filesystem::is_directory(it->status())) {
- path_files_md5_hash_recursive(hash, from_boost(it->path()));
+ for(; it != it_end; ++it) {
+ if(path_is_directory(it->path())) {
+ path_files_md5_hash_recursive(hash, it->path());
}
else {
- string filepath = from_boost(it->path());
+ string filepath = it->path();
hash.append((const uint8_t*)filepath.c_str(), filepath.size());
hash.append_file(filepath);
@@ -156,9 +615,36 @@ string path_files_md5_hash(const string& dir)
return hash.get_hex();
}
-void path_create_directories(const string& path)
+static bool create_directories_recursivey(const string& path)
+{
+ if(path_is_directory(path)) {
+ /* Directory already exists, nothing to do. */
+ return true;
+ }
+ if(path_exists(path)) {
+ /* File exists and it's not a directory. */
+ return false;
+ }
+
+ string parent = path_dirname(path);
+ if(parent.size() > 0 && parent != path) {
+ if(!create_directories_recursivey(parent)) {
+ return false;
+ }
+ }
+
+#ifdef _WIN32
+ wstring path_wc = string_to_wstring(path);
+ return _wmkdir(path_wc.c_str()) == 0;
+#else
+ return mkdir(path.c_str(), 0777) == 0;
+#endif
+}
+
+void path_create_directories(const string& filepath)
{
- boost::filesystem::create_directories(to_boost(path_dirname(path)));
+ string path = path_dirname(filepath);
+ create_directories_recursivey(path);
}
bool path_write_binary(const string& path, const vector<uint8_t>& binary)
@@ -189,13 +675,15 @@ bool path_write_text(const string& path, string& text)
bool path_read_binary(const string& path, vector<uint8_t>& binary)
{
- binary.resize(boost::filesystem::file_size(to_boost(path)));
-
/* read binary file into memory */
FILE *f = path_fopen(path, "rb");
- if(!f)
+ if(!f) {
+ binary.resize(0);
return false;
+ }
+
+ binary.resize(path_file_size(path));
if(binary.size() == 0) {
fclose(f);
@@ -228,57 +716,84 @@ bool path_read_text(const string& path, string& text)
uint64_t path_modified_time(const string& path)
{
- if(boost::filesystem::exists(to_boost(path)))
- return (uint64_t)boost::filesystem::last_write_time(to_boost(path));
-
+ path_stat_t st;
+ if(path_stat(path, &st) != 0) {
+ return st.st_mtime;
+ }
return 0;
}
-string path_source_replace_includes(const string& source_, const string& path)
+bool path_remove(const string& path)
{
- /* our own little c preprocessor that replaces #includes with the file
- * contents, to work around issue of opencl drivers not supporting
- * include paths with spaces in them */
- string source = source_;
- const string include = "#include \"";
- size_t n, pos = 0;
-
- while((n = source.find(include, pos)) != string::npos) {
- size_t n_start = n + include.size();
- size_t n_end = source.find("\"", n_start);
- string filename = source.substr(n_start, n_end - n_start);
-
- string text, filepath = path_join(path, filename);
+ return remove(path.c_str()) == 0;
+}
- if(path_read_text(filepath, text)) {
- text = path_source_replace_includes(text, path_dirname(filepath));
- source.replace(n, n_end + 1 - n, "\n" + text + "\n");
+string path_source_replace_includes(const string& source, const string& path)
+{
+ /* Our own little c preprocessor that replaces #includes with the file
+ * contents, to work around issue of opencl drivers not supporting
+ * include paths with spaces in them.
+ */
+
+ string result = "";
+ vector<string> lines;
+ string_split(lines, source, "\n");
+
+ for(size_t i = 0; i < lines.size(); ++i) {
+ string line = lines[i];
+ if(line[0] == '#') {
+ string token = string_strip(line.substr(1, line.size() - 1));
+ if(string_startswith(token, "include")) {
+ token = string_strip(token.substr(7, token.size() - 7));
+ if(token[0] == '"') {
+ size_t n_start = 1;
+ size_t n_end = token.find("\"", n_start);
+ string filename = token.substr(n_start, n_end - n_start);
+ string text, filepath = path_join(path, filename);
+ if(path_read_text(filepath, text)) {
+ /* Replace include directories with both current path
+ * and path extracted from the include file.
+ * Not totally robust, but works fine for Cycles kernel
+ * and avoids having list of include directories.x
+ */
+ text = path_source_replace_includes(
+ text, path_dirname(filepath));
+ text = path_source_replace_includes(text, path);
+ line = token.replace(0, n_end + 1, "\n" + text + "\n");
+ }
+ }
+ }
}
- else
- pos = n_end;
+ result += line + "\n";
}
- return source;
+ return result;
}
FILE *path_fopen(const string& path, const string& mode)
{
+#ifdef _WIN32
+ wstring path_wc = string_to_wstring(path);
+ wstring mode_wc = string_to_wstring(mode);
+ return _wfopen(path_wc.c_str(), mode_wc.c_str());
+#else
return fopen(path.c_str(), mode.c_str());
+#endif
}
void path_cache_clear_except(const string& name, const set<string>& except)
{
string dir = path_user_get("cache");
- if(boost::filesystem::exists(dir)) {
- boost::filesystem::directory_iterator it(dir), it_end;
+ if(path_exists(dir)) {
+ directory_iterator it(dir), it_end;
- for(; it != it_end; it++) {
- string filename = from_boost(it->path().filename().string());
+ for(; it != it_end; ++it) {
+ string filename = path_filename(it->path());
- if(boost::starts_with(filename, name))
+ if(string_startswith(filename, name.c_str()))
if(except.find(filename) == except.end())
- boost::filesystem::remove(to_boost(filename));
+ path_remove(it->path());
}
}
diff --git a/intern/cycles/util/util_path.h b/intern/cycles/util/util_path.h
index b81d71d1c0f..c80247f3837 100644
--- a/intern/cycles/util/util_path.h
+++ b/intern/cycles/util/util_path.h
@@ -44,7 +44,9 @@ string path_escape(const string& path);
bool path_is_relative(const string& path);
/* file info */
+size_t path_file_size(const string& path);
bool path_exists(const string& path);
+bool path_is_directory(const string& path);
string path_files_md5_hash(const string& dir);
uint64_t path_modified_time(const string& path);
@@ -59,6 +61,9 @@ bool path_write_text(const string& path, string& text);
bool path_read_binary(const string& path, vector<uint8_t>& binary);
bool path_read_text(const string& path, string& text);
+/* File manipulation. */
+bool path_remove(const string& path);
+
/* source code utility */
string path_source_replace_includes(const string& source, const string& path);
diff --git a/intern/cycles/util/util_queue.h b/intern/cycles/util/util_queue.h
new file mode 100644
index 00000000000..f4c802785f9
--- /dev/null
+++ b/intern/cycles/util/util_queue.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2011-2015 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_QUEUE_H__
+#define __UTIL_QUEUE_H__
+
+#include <queue>
+
+CCL_NAMESPACE_BEGIN
+
+using std::queue;
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_LIST_H__ */
+
diff --git a/intern/cycles/util/util_set.h b/intern/cycles/util/util_set.h
index b3cb8dd8af5..c19fa071b37 100644
--- a/intern/cycles/util/util_set.h
+++ b/intern/cycles/util/util_set.h
@@ -21,15 +21,41 @@
#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
# include <unordered_set>
#else
-# include <boost/tr1/unordered_set.hpp>
+# if defined(CYCLES_TR1_UNORDERED_MAP)
+# include <tr1/unordered_set>
+# endif
+# if defined(CYCLES_STD_UNORDERED_MAP) || \
+ defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_set>
+# endif
+# if !defined(CYCLES_NO_UNORDERED_MAP) && \
+ !defined(CYCLES_TR1_UNORDERED_MAP) && \
+ !defined(CYCLES_STD_UNORDERED_MAP) && \
+ !defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# error One of: CYCLES_NO_UNORDERED_MAP, CYCLES_TR1_UNORDERED_MAP,\
+ CYCLES_STD_UNORDERED_MAP, CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+# endif
#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+# include <iterator>
+#endif
+
CCL_NAMESPACE_BEGIN
using std::set;
#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
using std::unordered_set;
#else
+# if defined(CYCLES_NO_UNORDERED_MAP)
+typedef std::set unordered_set;
+# endif
+# if defined(CYCLES_TR1_UNORDERED_MAP) || defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
using std::tr1::unordered_set;
+# endif
+# if defined(CYCLES_STD_UNORDERED_MAP)
+using std::unordered_set;
+# endif
#endif
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_simd.cpp b/intern/cycles/util/util_simd.cpp
index eb9e32800e1..de2df612578 100644
--- a/intern/cycles/util/util_simd.cpp
+++ b/intern/cycles/util/util_simd.cpp
@@ -15,7 +15,8 @@
* limitations under the License.
*/
-#ifdef WITH_KERNEL_SSE2
+#if (defined(WITH_KERNEL_SSE2)) || \
+ (defined(WITH_KERNEL_NATIVE) && defined(__SSE2__))
#define __KERNEL_SSE2__
#include "util_simd.h"
diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h
index a1c35b7174d..36da1550a94 100644
--- a/intern/cycles/util/util_simd.h
+++ b/intern/cycles/util/util_simd.h
@@ -430,6 +430,23 @@ __forceinline __int64 _mm_extract_epi64( __m128i input, const int index ) {
#endif
+#else /* __KERNEL_SSE2__ */
+
+/* This section is for utility functions which operates on non-register data
+ * which might be used from a non-vectorized code.
+ */
+
+ccl_device_inline int bitscan(int value)
+{
+ assert(value != 0);
+ int bit = 0;
+ while(value >>= 1) {
+ ++bit;
+ }
+ return bit;
+}
+
+
#endif /* __KERNEL_SSE2__ */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_sky_model.cpp b/intern/cycles/util/util_sky_model.cpp
new file mode 100644
index 00000000000..a53c2ce1bb6
--- /dev/null
+++ b/intern/cycles/util/util_sky_model.cpp
@@ -0,0 +1,370 @@
+/*
+This source is published under the following 3-clause BSD license.
+
+Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * None of the names of the contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
+*/
+
+/* ============================================================================
+
+This file is part of a sample implementation of the analytical skylight and
+solar radiance models presented in the SIGGRAPH 2012 paper
+
+
+ "An Analytic Model for Full Spectral Sky-Dome Radiance"
+
+and the 2013 IEEE CG&A paper
+
+ "Adding a Solar Radiance Function to the Hosek Skylight Model"
+
+ both by
+
+ Lukas Hosek and Alexander Wilkie
+ Charles University in Prague, Czech Republic
+
+
+ Version: 1.4a, February 22nd, 2013
+
+Version history:
+
+1.4a February 22nd, 2013
+ Removed unnecessary and counter-intuitive solar radius parameters
+ from the interface of the colourspace sky dome initialisation functions.
+
+1.4 February 11th, 2013
+ Fixed a bug which caused the relative brightness of the solar disc
+ and the sky dome to be off by a factor of about 6. The sun was too
+ bright: this affected both normal and alien sun scenarios. The
+ coefficients of the solar radiance function were changed to fix this.
+
+1.3 January 21st, 2013 (not released to the public)
+ Added support for solar discs that are not exactly the same size as
+ the terrestrial sun. Also added support for suns with a different
+ emission spectrum ("Alien World" functionality).
+
+1.2a December 18th, 2012
+ Fixed a mistake and some inaccuracies in the solar radiance function
+ explanations found in ArHosekSkyModel.h. The actual source code is
+ unchanged compared to version 1.2.
+
+1.2 December 17th, 2012
+ Native RGB data and a solar radiance function that matches the turbidity
+ conditions were added.
+
+1.1 September 2012
+ The coefficients of the spectral model are now scaled so that the output
+ is given in physical units: W / (m^-2 * sr * nm). Also, the output of the
+ XYZ model is now no longer scaled to the range [0...1]. Instead, it is
+ the result of a simple conversion from spectral data via the CIE 2 degree
+ standard observer matching functions. Therefore, after multiplication
+ with 683 lm / W, the Y channel now corresponds to luminance in lm.
+
+1.0 May 11th, 2012
+ Initial release.
+
+
+Please visit http://cgg.mff.cuni.cz/projects/SkylightModelling/ to check if
+an updated version of this code has been published!
+
+============================================================================ */
+
+/*
+
+All instructions on how to use this code are in the accompanying header file.
+
+*/
+
+#include "util_sky_model.h"
+#include "util_sky_model_data.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+CCL_NAMESPACE_BEGIN
+
+// Some macro definitions that occur elsewhere in ART, and that have to be
+// replicated to make this a stand-alone module.
+
+#ifndef MATH_PI
+#define MATH_PI 3.141592653589793
+#endif
+
+#ifndef MATH_DEG_TO_RAD
+#define MATH_DEG_TO_RAD ( MATH_PI / 180.0 )
+#endif
+
+#ifndef DEGREES
+#define DEGREES * MATH_DEG_TO_RAD
+#endif
+
+#ifndef TERRESTRIAL_SOLAR_RADIUS
+#define TERRESTRIAL_SOLAR_RADIUS ( ( 0.51 DEGREES ) / 2.0 )
+#endif
+
+#ifndef ALLOC
+#define ALLOC(_struct) ((_struct *)malloc(sizeof(_struct)))
+#endif
+
+// internal definitions
+
+typedef const double *ArHosekSkyModel_Dataset;
+typedef const double *ArHosekSkyModel_Radiance_Dataset;
+
+// internal functions
+
+static void ArHosekSkyModel_CookConfiguration(
+ ArHosekSkyModel_Dataset dataset,
+ ArHosekSkyModelConfiguration config,
+ double turbidity,
+ double albedo,
+ double solar_elevation)
+{
+ const double * elev_matrix;
+
+ int int_turbidity = (int)turbidity;
+ double turbidity_rem = turbidity - (double)int_turbidity;
+
+ solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
+
+ // alb 0 low turb
+
+ elev_matrix = dataset + ( 9 * 6 * (int_turbidity-1));
+
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] =
+ (1.0-albedo) * (1.0 - turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
+
+ // alb 1 low turb
+ elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity-1));
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] +=
+ (albedo) * (1.0 - turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
+
+ if(int_turbidity == 10)
+ return;
+
+ // alb 0 high turb
+ elev_matrix = dataset + (9*6*(int_turbidity));
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] +=
+ (1.0-albedo) * (turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
+
+ // alb 1 high turb
+ elev_matrix = dataset + (9*6*10 + 9*6*(int_turbidity));
+ for(unsigned int i = 0; i < 9; ++i) {
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ config[i] +=
+ (albedo) * (turbidity_rem)
+ * ( pow(1.0-solar_elevation, 5.0) * elev_matrix[i] +
+ 5.0 * pow(1.0-solar_elevation, 4.0) * solar_elevation * elev_matrix[i+9] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[i+18] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[i+27] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[i+36] +
+ pow(solar_elevation, 5.0) * elev_matrix[i+45]);
+ }
+}
+
+static double ArHosekSkyModel_CookRadianceConfiguration(
+ ArHosekSkyModel_Radiance_Dataset dataset,
+ double turbidity,
+ double albedo,
+ double solar_elevation)
+{
+ const double* elev_matrix;
+
+ int int_turbidity = (int)turbidity;
+ double turbidity_rem = turbidity - (double)int_turbidity;
+ double res;
+ solar_elevation = pow(solar_elevation / (MATH_PI / 2.0), (1.0 / 3.0));
+
+ // alb 0 low turb
+ elev_matrix = dataset + (6*(int_turbidity-1));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res = (1.0-albedo) * (1.0 - turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+
+ // alb 1 low turb
+ elev_matrix = dataset + (6*10 + 6*(int_turbidity-1));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res += (albedo) * (1.0 - turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+ if(int_turbidity == 10)
+ return res;
+
+ // alb 0 high turb
+ elev_matrix = dataset + (6*(int_turbidity));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res += (1.0-albedo) * (turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+
+ // alb 1 high turb
+ elev_matrix = dataset + (6*10 + 6*(int_turbidity));
+ //(1-t).^3* A1 + 3*(1-t).^2.*t * A2 + 3*(1-t) .* t .^ 2 * A3 + t.^3 * A4;
+ res += (albedo) * (turbidity_rem) *
+ ( pow(1.0-solar_elevation, 5.0) * elev_matrix[0] +
+ 5.0*pow(1.0-solar_elevation, 4.0)*solar_elevation * elev_matrix[1] +
+ 10.0*pow(1.0-solar_elevation, 3.0)*pow(solar_elevation, 2.0) * elev_matrix[2] +
+ 10.0*pow(1.0-solar_elevation, 2.0)*pow(solar_elevation, 3.0) * elev_matrix[3] +
+ 5.0*(1.0-solar_elevation)*pow(solar_elevation, 4.0) * elev_matrix[4] +
+ pow(solar_elevation, 5.0) * elev_matrix[5]);
+ return res;
+}
+
+static double ArHosekSkyModel_GetRadianceInternal(
+ ArHosekSkyModelConfiguration configuration,
+ double theta,
+ double gamma)
+{
+ const double expM = exp(configuration[4] * gamma);
+ const double rayM = cos(gamma)*cos(gamma);
+ const double mieM = (1.0 + cos(gamma)*cos(gamma)) / pow((1.0 + configuration[8]*configuration[8] - 2.0*configuration[8]*cos(gamma)), 1.5);
+ const double zenith = sqrt(cos(theta));
+
+ return (1.0 + configuration[0] * exp(configuration[1] / (cos(theta) + 0.01))) *
+ (configuration[2] + configuration[3] * expM + configuration[5] * rayM + configuration[6] * mieM + configuration[7] * zenith);
+}
+
+void arhosekskymodelstate_free(ArHosekSkyModelState * state)
+{
+ free(state);
+}
+
+double arhosekskymodel_radiance(ArHosekSkyModelState *state,
+ double theta,
+ double gamma,
+ double wavelength)
+{
+ int low_wl = (int)((wavelength - 320.0) / 40.0);
+
+ if(low_wl < 0 || low_wl >= 11)
+ return 0.0f;
+
+ double interp = fmod((wavelength - 320.0 ) / 40.0, 1.0);
+
+ double val_low =
+ ArHosekSkyModel_GetRadianceInternal(
+ state->configs[low_wl],
+ theta,
+ gamma)
+ * state->radiances[low_wl]
+ * state->emission_correction_factor_sky[low_wl];
+
+ if(interp < 1e-6)
+ return val_low;
+
+ double result = ( 1.0 - interp ) * val_low;
+
+ if(low_wl+1 < 11) {
+ result +=
+ interp
+ * ArHosekSkyModel_GetRadianceInternal(
+ state->configs[low_wl+1],
+ theta,
+ gamma)
+ * state->radiances[low_wl+1]
+ * state->emission_correction_factor_sky[low_wl+1];
+ }
+
+ return result;
+}
+
+
+// xyz and rgb versions
+
+ArHosekSkyModelState * arhosek_xyz_skymodelstate_alloc_init(
+ const double turbidity,
+ const double albedo,
+ const double elevation)
+{
+ ArHosekSkyModelState * state = ALLOC(ArHosekSkyModelState);
+
+ state->solar_radius = TERRESTRIAL_SOLAR_RADIUS;
+ state->turbidity = turbidity;
+ state->albedo = albedo;
+ state->elevation = elevation;
+
+ for(unsigned int channel = 0; channel < 3; ++channel) {
+ ArHosekSkyModel_CookConfiguration(
+ datasetsXYZ[channel],
+ state->configs[channel],
+ turbidity,
+ albedo,
+ elevation);
+
+ state->radiances[channel] =
+ ArHosekSkyModel_CookRadianceConfiguration(
+ datasetsXYZRad[channel],
+ turbidity,
+ albedo,
+ elevation);
+ }
+
+ return state;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/render/sky_model.h b/intern/cycles/util/util_sky_model.h
index 237e4e61bf5..237e4e61bf5 100644
--- a/intern/cycles/render/sky_model.h
+++ b/intern/cycles/util/util_sky_model.h
diff --git a/intern/cycles/render/sky_model_data.h b/intern/cycles/util/util_sky_model_data.h
index e6f3f761532..e6f3f761532 100644
--- a/intern/cycles/render/sky_model_data.h
+++ b/intern/cycles/util/util_sky_model_data.h
diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h
index e625fa63568..2f5295b5463 100644
--- a/intern/cycles/util/util_ssef.h
+++ b/intern/cycles/util/util_ssef.h
@@ -558,7 +558,7 @@ ccl_device_inline const ssef shuffle_swap(const ssef& a, shuffle_swap_t shuf)
#ifdef __KERNEL_SSE41__
ccl_device_inline void gen_idirsplat_swap(const ssef &pn, const shuffle_swap_t &shuf_identity, const shuffle_swap_t &shuf_swap,
- const float3& idir, ssef idirsplat[3], shuffle_swap_t shufflexyz[3])
+ const float3& idir, ssef idirsplat[3], shuffle_swap_t shufflexyz[3])
{
const __m128 idirsplat_raw[] = { _mm_set_ps1(idir.x), _mm_set_ps1(idir.y), _mm_set_ps1(idir.z) };
idirsplat[0] = _mm_xor_ps(idirsplat_raw[0], pn);
@@ -577,7 +577,7 @@ ccl_device_inline void gen_idirsplat_swap(const ssef &pn, const shuffle_swap_t &
#else
ccl_device_inline void gen_idirsplat_swap(const ssef &pn, const shuffle_swap_t &shuf_identity, const shuffle_swap_t &shuf_swap,
- const float3& idir, ssef idirsplat[3], shuffle_swap_t shufflexyz[3])
+ const float3& idir, ssef idirsplat[3], shuffle_swap_t shufflexyz[3])
{
idirsplat[0] = ssef(idir.x) ^ pn;
idirsplat[1] = ssef(idir.y) ^ pn;
diff --git a/intern/cycles/util/util_stack_allocator.h b/intern/cycles/util/util_stack_allocator.h
new file mode 100644
index 00000000000..29260888eef
--- /dev/null
+++ b/intern/cycles/util/util_stack_allocator.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_STACK_ALLOCATOR_H__
+#define __UTIL_STACK_ALLOCATOR_H__
+
+#include <cstddef>
+#include <memory>
+
+#include "util_debug.h"
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Stack allocator for the use with STL. */
+template <int SIZE, typename T>
+class ccl_try_align(16) StackAllocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T *pointer;
+ typedef const T *const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ /* Allocator construction/destruction. */
+
+ StackAllocator()
+ : pointer_(0) {}
+
+ StackAllocator(const StackAllocator&)
+ : pointer_(0) {}
+
+ template <class U>
+ StackAllocator(const StackAllocator<SIZE, U>&)
+ : pointer_(0) {}
+
+ /* Memory allocation/deallocation. */
+
+ T *allocate(size_t n, const void *hint = 0)
+ {
+ (void)hint;
+ if(n == 0) {
+ return NULL;
+ }
+ if(pointer_ + n >= SIZE) {
+ size_t size = n * sizeof(T);
+ util_guarded_mem_alloc(size);
+#ifdef WITH_BLENDER_GUARDEDALLOC
+ return (T*)MEM_mallocN_aligned(size, 16, "Cycles Alloc");
+#else
+ return (T*)malloc(size);
+#endif
+ }
+ T *mem = &data_[pointer_];
+ pointer_ += n;
+ return mem;
+ }
+
+ void deallocate(T *p, size_t n)
+ {
+ if(p == NULL) {
+ return;
+ }
+ if(p < data_ || p >= data_ + SIZE) {
+ util_guarded_mem_free(n * sizeof(T));
+#ifdef WITH_BLENDER_GUARDEDALLOC
+ MEM_freeN(p);
+#else
+ free(p);
+#endif
+ return;
+ }
+ /* We don't support memory free for the stack allocator. */
+ }
+
+ /* Address of an reference. */
+
+ T *address(T& x) const
+ {
+ return &x;
+ }
+
+ const T *address(const T& x) const
+ {
+ return &x;
+ }
+
+ /* Object construction/destruction. */
+
+ void construct(T *p, const T& val)
+ {
+ new ((T *)p) T(val);
+ }
+
+ void destroy(T *p)
+ {
+ p->~T();
+ }
+
+ /* Maximum allocation size. */
+
+ size_t max_size() const
+ {
+ return size_t(-1);
+ }
+
+ /* Rebind to other ype of allocator. */
+
+ template <class U>
+ struct rebind {
+ typedef StackAllocator<SIZE, U> other;
+ };
+
+ /* Operators */
+
+ template <class U>
+ inline StackAllocator& operator=(const StackAllocator<SIZE, U>&)
+ {
+ return *this;
+ }
+
+ StackAllocator<SIZE, T>& operator=(const StackAllocator&)
+ {
+ return *this;
+ }
+
+ inline bool operator==(StackAllocator const& /*other*/) const
+ {
+ return true;
+ }
+
+ inline bool operator!=(StackAllocator const& other) const
+ {
+ return !operator==(other);
+ }
+
+private:
+ int pointer_;
+ T data_[SIZE];
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_GUARDED_ALLOCATOR_H__ */
diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp
index 66856dd8331..b3a8c6d7c2e 100644
--- a/intern/cycles/util/util_string.cpp
+++ b/intern/cycles/util/util_string.cpp
@@ -17,16 +17,15 @@
#include <stdarg.h>
#include <stdio.h>
-#include <boost/algorithm/string.hpp>
-
#include "util_foreach.h"
#include "util_string.h"
+#include "util_windows.h"
#ifdef _WIN32
-#ifndef vsnprintf
-#define vsnprintf _vsnprintf
-#endif
-#endif
+# ifndef vsnprintf
+# define vsnprintf _vsnprintf
+# endif
+#endif /* _WIN32 */
CCL_NAMESPACE_BEGIN
@@ -77,13 +76,42 @@ bool string_iequals(const string& a, const string& b)
void string_split(vector<string>& tokens, const string& str, const string& separators)
{
- vector<string> split;
+ size_t token_start = 0, token_length = 0;
+ for(size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ if(separators.find(ch) == string::npos) {
+ /* Current character is not a separator,
+ * append it to token by increasing token length.
+ */
+ ++token_length;
+ }
+ else {
+ /* Current character is a separator,
+ * append current token to the list (if token is not empty).
+ */
+ if(token_length > 0) {
+ string token = str.substr(token_start, token_length);
+ tokens.push_back(token);
+ }
+ token_start = i + 1;
+ token_length = 0;
+ }
+ }
+ /* Append token from the tail of the string if exists. */
+ if(token_length) {
+ string token = str.substr(token_start, token_length);
+ tokens.push_back(token);
+ }
+}
- boost::split(split, str, boost::is_any_of(separators), boost::token_compress_on);
+bool string_startswith(const string& s, const char *start)
+{
+ size_t len = strlen(start);
- foreach(const string& token, split)
- if(token != "")
- tokens.push_back(token);
+ if(len > s.size())
+ return 0;
+ else
+ return strncmp(s.c_str(), start, len) == 0;
}
bool string_endswith(const string& s, const char *end)
@@ -107,10 +135,11 @@ string string_strip(const string& s)
void string_replace(string& haystack, const string& needle, const string& other)
{
- size_t i;
-
- while((i = haystack.find(needle)) != string::npos)
- haystack.replace(i, needle.length(), other);
+ size_t i = 0, index;
+ while((index = haystack.find(needle, i)) != string::npos) {
+ haystack.replace(index, needle.size(), other);
+ i = index + other.size();
+ }
}
string string_remove_trademark(const string &s)
@@ -122,5 +151,93 @@ string string_remove_trademark(const string &s)
return string_strip(result);
}
+string string_from_bool(bool var)
+{
+ if(var)
+ return "True";
+ else
+ return "False";
+}
+
+/* Wide char strings helpers for Windows. */
+
+#ifdef _WIN32
+
+wstring string_to_wstring(const string& str)
+{
+ const int length_wc = MultiByteToWideChar(CP_UTF8,
+ 0,
+ str.c_str(),
+ str.length(),
+ NULL,
+ 0);
+ wstring str_wc(length_wc, 0);
+ MultiByteToWideChar(CP_UTF8,
+ 0,
+ str.c_str(),
+ str.length(),
+ &str_wc[0],
+ length_wc);
+ return str_wc;
+}
+
+string string_from_wstring(const wstring& str)
+{
+ int length_mb = WideCharToMultiByte(CP_UTF8,
+ 0,
+ str.c_str(),
+ str.size(),
+ NULL,
+ 0,
+ NULL, NULL);
+ string str_mb(length_mb, 0);
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ str.c_str(),
+ str.size(),
+ &str_mb[0],
+ length_mb,
+ NULL, NULL);
+ return str_mb;
+}
+
+string string_to_ansi(const string& str)
+{
+ const int length_wc = MultiByteToWideChar(CP_UTF8,
+ 0,
+ str.c_str(),
+ str.length(),
+ NULL,
+ 0);
+ wstring str_wc(length_wc, 0);
+ MultiByteToWideChar(CP_UTF8,
+ 0,
+ str.c_str(),
+ str.length(),
+ &str_wc[0],
+ length_wc);
+
+ int length_mb = WideCharToMultiByte(CP_ACP,
+ 0,
+ str_wc.c_str(),
+ str_wc.size(),
+ NULL,
+ 0,
+ NULL, NULL);
+
+ string str_mb(length_mb, 0);
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ str_wc.c_str(),
+ str_wc.size(),
+ &str_mb[0],
+ length_mb,
+ NULL, NULL);
+
+ return str_mb;
+}
+
+#endif /* _WIN32 */
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h
index 6cb8d8df1e1..c4b51bda432 100644
--- a/intern/cycles/util/util_string.h
+++ b/intern/cycles/util/util_string.h
@@ -41,9 +41,26 @@ string string_printf(const char *format, ...) PRINTF_ATTRIBUTE;
bool string_iequals(const string& a, const string& b);
void string_split(vector<string>& tokens, const string& str, const string& separators = "\t ");
void string_replace(string& haystack, const string& needle, const string& other);
+bool string_startswith(const string& s, const char *start);
bool string_endswith(const string& s, const char *end);
string string_strip(const string& s);
string string_remove_trademark(const string& s);
+string string_from_bool(const bool var);
+
+/* Wide char strings are only used on Windows to deal with non-ascii
+ * characters in file names and such. No reason to use such strings
+ * for something else at this moment.
+ *
+ * Please note that strings are expected to be in UTF-8 codepage, and
+ * if ANSI is needed then explicit conversion required.
+ *
+ */
+#ifdef _WIN32
+using std::wstring;
+wstring string_to_wstring(const string& path);
+string string_from_wstring(const wstring& path);
+string string_to_ansi(const string& str);
+#endif
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp
index cc88320b68e..4ff0ee91d73 100644
--- a/intern/cycles/util/util_system.cpp
+++ b/intern/cycles/util/util_system.cpp
@@ -15,19 +15,20 @@
*/
#include "util_system.h"
+#include "util_debug.h"
#include "util_types.h"
#include "util_string.h"
#ifdef _WIN32
-#if(!defined(FREE_WINDOWS))
-#include <intrin.h>
-#endif
-#include <windows.h>
+# if(!defined(FREE_WINDOWS))
+# include <intrin.h>
+# endif
+# include "util_windows.h"
#elif defined(__APPLE__)
-#include <sys/sysctl.h>
-#include <sys/types.h>
+# include <sys/sysctl.h>
+# include <sys/types.h>
#else
-#include <unistd.h>
+# include <unistd.h>
#endif
CCL_NAMESPACE_BEGIN
@@ -126,29 +127,6 @@ struct CPUCapabilities {
bool bmi2;
};
-static void system_cpu_capabilities_override(CPUCapabilities *caps)
-{
- /* Only capabilities which affects on cycles kernel. */
- if(getenv("CYCLES_CPU_NO_AVX2")) {
- caps->avx2 = false;
- }
- if(getenv("CYCLES_CPU_NO_AVX")) {
- caps->avx = false;
- }
- if(getenv("CYCLES_CPU_NO_SSE41")) {
- caps->sse41 = false;
- }
- if(getenv("CYCLES_CPU_NO_SSE3")) {
- caps->sse3 = false;
- }
- if(getenv("CYCLES_CPU_NO_SSE2")) {
- caps->sse2 = false;
- }
- if(getenv("CYCLES_CPU_NO_SSE")) {
- caps->sse = false;
- }
-}
-
static CPUCapabilities& system_cpu_capabilities()
{
static CPUCapabilities caps;
@@ -201,8 +179,6 @@ static CPUCapabilities& system_cpu_capabilities()
caps.avx2 = (result[1] & ((int)1 << 5)) != 0;
}
- system_cpu_capabilities_override(&caps);
-
caps_init = true;
}
@@ -212,30 +188,35 @@ static CPUCapabilities& system_cpu_capabilities()
bool system_cpu_support_sse2()
{
CPUCapabilities& caps = system_cpu_capabilities();
- return caps.sse && caps.sse2;
+ return DebugFlags().cpu.sse2 && caps.sse && caps.sse2;
}
bool system_cpu_support_sse3()
{
CPUCapabilities& caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3;
+ return DebugFlags().cpu.sse3 &&
+ caps.sse && caps.sse2 && caps.sse3 && caps.ssse3;
}
bool system_cpu_support_sse41()
{
CPUCapabilities& caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41;
+ return DebugFlags().cpu.sse41 &&
+ caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41;
}
bool system_cpu_support_avx()
{
CPUCapabilities& caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx;
+ return DebugFlags().cpu.avx &&
+ caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx;
}
+
bool system_cpu_support_avx2()
{
CPUCapabilities& caps = system_cpu_capabilities();
- return caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.f16c && caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
+ return DebugFlags().cpu.avx2 &&
+ caps.sse && caps.sse2 && caps.sse3 && caps.ssse3 && caps.sse41 && caps.avx && caps.f16c && caps.avx2 && caps.fma3 && caps.bmi1 && caps.bmi2;
}
#else
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp
index d56553d1d4a..d86aa8a4a46 100644
--- a/intern/cycles/util/util_task.cpp
+++ b/intern/cycles/util/util_task.cpp
@@ -18,6 +18,7 @@
#include "util_foreach.h"
#include "util_system.h"
#include "util_task.h"
+#include "util_time.h"
//#define THREADING_DEBUG_ENABLED
@@ -34,6 +35,7 @@ CCL_NAMESPACE_BEGIN
TaskPool::TaskPool()
{
+ num_tasks_handled = 0;
num = 0;
do_cancel = false;
}
@@ -58,7 +60,7 @@ void TaskPool::push(const TaskRunFunction& run, bool front)
push(new Task(run), front);
}
-void TaskPool::wait_work()
+void TaskPool::wait_work(Summary *stats)
{
thread_scoped_lock num_lock(num_mutex);
@@ -89,7 +91,7 @@ void TaskPool::wait_work()
/* if found task, do it, otherwise wait until other tasks are done */
if(found_entry) {
/* run task */
- work_entry.task->run();
+ work_entry.task->run(0);
/* delete task */
delete work_entry.task;
@@ -108,6 +110,11 @@ void TaskPool::wait_work()
THREADING_DEBUG("num==%d, condition wait done in TaskPool::wait_work !found_entry\n", num);
}
}
+
+ if(stats != NULL) {
+ stats->time_total = time_dt() - start_time;
+ stats->num_tasks_handled = num_tasks_handled;
+ }
}
void TaskPool::cancel()
@@ -158,7 +165,11 @@ void TaskPool::num_decrease(int done)
void TaskPool::num_increase()
{
thread_scoped_lock num_lock(num_mutex);
+ if(num_tasks_handled == 0) {
+ start_time = time_dt();
+ }
num++;
+ num_tasks_handled++;
THREADING_DEBUG("num==%d, notifying all in TaskPool::num_increase\n", num);
num_cond.notify_all();
}
@@ -192,7 +203,7 @@ void TaskScheduler::init(int num_threads)
threads.resize(num_threads);
for(size_t i = 0; i < threads.size(); i++)
- threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i));
+ threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i + 1));
}
users++;
@@ -206,8 +217,10 @@ void TaskScheduler::exit()
if(users == 0) {
/* stop all waiting threads */
+ TaskScheduler::queue_mutex.lock();
do_exit = true;
TaskScheduler::queue_cond.notify_all();
+ TaskScheduler::queue_mutex.unlock();
/* delete threads */
foreach(thread *t, threads) {
@@ -219,6 +232,12 @@ void TaskScheduler::exit()
}
}
+void TaskScheduler::free_memory()
+{
+ assert(users == 0);
+ threads.free_memory();
+}
+
bool TaskScheduler::thread_wait_pop(Entry& entry)
{
thread_scoped_lock queue_lock(queue_mutex);
@@ -237,7 +256,7 @@ bool TaskScheduler::thread_wait_pop(Entry& entry)
return true;
}
-void TaskScheduler::thread_run(int /*thread_id*/)
+void TaskScheduler::thread_run(int thread_id)
{
Entry entry;
@@ -246,7 +265,7 @@ void TaskScheduler::thread_run(int /*thread_id*/)
/* keep popping off tasks */
while(thread_wait_pop(entry)) {
/* run task */
- entry.task->run();
+ entry.task->run(thread_id);
/* delete task */
delete entry.task;
@@ -413,7 +432,7 @@ void DedicatedTaskPool::thread_run()
/* keep popping off tasks */
while(thread_wait_pop(task)) {
/* run task */
- task->run();
+ task->run(0);
/* delete task */
delete task;
@@ -444,5 +463,13 @@ void DedicatedTaskPool::clear()
num_decrease(done);
}
+string TaskPool::Summary::full_report() const
+{
+ string report = "";
+ report += string_printf("Total time: %f\n", time_total);
+ report += string_printf("Tasks handled: %d\n", num_tasks_handled);
+ return report;
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h
index debcff3b776..d697ebf35a4 100644
--- a/intern/cycles/util/util_task.h
+++ b/intern/cycles/util/util_task.h
@@ -18,6 +18,7 @@
#define __UTIL_TASK_H__
#include "util_list.h"
+#include "util_string.h"
#include "util_thread.h"
#include "util_vector.h"
@@ -27,7 +28,21 @@ class Task;
class TaskPool;
class TaskScheduler;
-typedef function<void(void)> TaskRunFunction;
+/* Notes on Thread ID
+ *
+ * Thread ID argument reports the 0-based ID of a working thread from which
+ * the run() callback is being invoked. Thread ID of 0 denotes the thread from
+ * which wait_work() was called.
+ *
+ * DO NOT use this ID to control execution flaw, use it only for things like
+ * emulating TLS which does not affect on scheduling. Don't use this ID to make
+ * any decisions.
+ *
+ * It is to be noted here that dedicated task pool will always report thread ID
+ * of 0.
+ */
+
+typedef function<void(int thread_id)> TaskRunFunction;
/* Task
*
@@ -56,13 +71,26 @@ public:
class TaskPool
{
public:
+ struct Summary {
+ /* Time spent to handle all tasks. */
+ double time_total;
+
+ /* Number of all tasks handled by this pool. */
+ int num_tasks_handled;
+
+ /* A full multiline description of the state of the pool after
+ * all work is done.
+ */
+ string full_report() const;
+ };
+
TaskPool();
~TaskPool();
void push(Task *task, bool front = false);
void push(const TaskRunFunction& run, bool front = false);
- void wait_work(); /* work and wait until all tasks are done */
+ void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
void cancel(); /* cancel all tasks, keep worker threads running */
void stop(); /* stop all worker threads */
@@ -79,6 +107,14 @@ protected:
int num;
bool do_cancel;
+
+ /* ** Statistics ** */
+
+ /* Time time stamp of first task pushed. */
+ double start_time;
+
+ /* Number of all tasks handled by this pool. */
+ int num_tasks_handled;
};
/* Task Scheduler
@@ -91,6 +127,7 @@ class TaskScheduler
public:
static void init(int num_threads = 0);
static void exit();
+ static void free_memory();
/* number of threads that can work on task */
static int num_threads() { return threads.size(); }
diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h
new file mode 100644
index 00000000000..2b6b8e743fb
--- /dev/null
+++ b/intern/cycles/util/util_texture.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_TEXTURE_H__
+#define __UTIL_TEXTURE_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* Texture limits on various devices. */
+
+/* CPU */
+#define TEX_NUM_BYTE_IMAGES_CPU 1024
+#define TEX_NUM_FLOAT_IMAGES_CPU 1024
+#define TEX_IMAGE_BYTE_START_CPU TEX_NUM_FLOAT_IMAGES_CPU
+
+/* CUDA (Fermi) */
+#define TEX_NUM_BYTE_IMAGES_CUDA 88
+#define TEX_NUM_FLOAT_IMAGES_CUDA 5
+#define TEX_IMAGE_BYTE_START_CUDA TEX_NUM_FLOAT_IMAGES_CUDA
+
+/* CUDA (KEPLER and above) */
+#define TEX_NUM_BYTE_IMAGES_CUDA_KEPLER 145
+#define TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER 5
+#define TEX_IMAGE_BYTE_START_CUDA_KELPER TEX_NUM_FLOAT_IMAGES_CUDA_KEPLER
+
+/* OpenCL */
+#define TEX_NUM_BYTE_IMAGES_OPENCL 1024
+#define TEX_NUM_FLOAT_IMAGES_OPENCL 0
+#define TEX_IMAGE_BYTE_START_OPENCL TEX_NUM_FLOAT_IMAGES_OPENCL
+
+
+/* Color to use when textures are not found. */
+#define TEX_IMAGE_MISSING_R 1
+#define TEX_IMAGE_MISSING_G 0
+#define TEX_IMAGE_MISSING_B 1
+#define TEX_IMAGE_MISSING_A 1
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_TEXTURE_H__ */
diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h
index 9c19235d41d..59575f31c13 100644
--- a/intern/cycles/util/util_thread.h
+++ b/intern/cycles/util/util_thread.h
@@ -28,6 +28,10 @@
#include <pthread.h>
#include <queue>
+#ifdef __APPLE__
+# include <libkern/OSAtomic.h>
+#endif
+
#include "util_function.h"
CCL_NAMESPACE_BEGIN
@@ -81,6 +85,47 @@ protected:
bool joined;
};
+/* Own wrapper around pthread's spin lock to make it's use easier. */
+
+class thread_spin_lock {
+public:
+#ifdef __APPLE__
+ inline thread_spin_lock() {
+ spin_ = OS_SPINLOCK_INIT;
+ }
+
+ inline void lock() {
+ OSSpinLockLock(&spin_);
+ }
+
+ inline void unlock() {
+ OSSpinLockUnlock(&spin_);
+ }
+#else /* __APPLE__ */
+ inline thread_spin_lock() {
+ pthread_spin_init(&spin_, 0);
+ }
+
+ inline ~thread_spin_lock() {
+ pthread_spin_destroy(&spin_);
+ }
+
+ inline void lock() {
+ pthread_spin_lock(&spin_);
+ }
+
+ inline void unlock() {
+ pthread_spin_unlock(&spin_);
+ }
+#endif /* __APPLE__ */
+protected:
+#ifdef __APPLE__
+ OSSpinLock spin_;
+#else
+ pthread_spinlock_t spin_;
+#endif
+};
+
CCL_NAMESPACE_END
#endif /* __UTIL_THREAD_H__ */
diff --git a/intern/cycles/util/util_time.cpp b/intern/cycles/util/util_time.cpp
index 964f9f1a7af..59c963cfafb 100644
--- a/intern/cycles/util/util_time.cpp
+++ b/intern/cycles/util/util_time.cpp
@@ -17,11 +17,10 @@
#include <stdlib.h>
#include "util_time.h"
+#include "util_windows.h"
#ifdef _WIN32
-#include <windows.h>
-
CCL_NAMESPACE_BEGIN
double time_dt()
diff --git a/intern/cycles/util/util_time.h b/intern/cycles/util/util_time.h
index 14ffea7f3da..9cd52d5f11a 100644
--- a/intern/cycles/util/util_time.h
+++ b/intern/cycles/util/util_time.h
@@ -27,6 +27,24 @@ double time_dt();
void time_sleep(double t);
+class scoped_timer {
+public:
+ scoped_timer(double *value) : value_(value)
+ {
+ time_start_ = time_dt();
+ }
+
+ ~scoped_timer()
+ {
+ if(value_ != NULL) {
+ *value_ = time_dt() - time_start_;
+ }
+ }
+protected:
+ double *value_;
+ double time_start_;
+};
+
CCL_NAMESPACE_END
#endif
diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp
index acaca69464c..79e1137d238 100644
--- a/intern/cycles/util/util_transform.cpp
+++ b/intern/cycles/util/util_transform.cpp
@@ -236,7 +236,7 @@ static void transform_decompose(Transform *decomp, const Transform *tfm)
} while(iteration < 100 && norm > 1e-4f);
if(transform_negative_scale(R))
- R = R * transform_scale(-1.0f, -1.0f, -1.0f); /* todo: test scale */
+ R = R * transform_scale(-1.0f, -1.0f, -1.0f);
decomp->x = transform_to_quat(R);
diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h
index ba8d04b5c16..f01db64a79b 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -347,7 +347,12 @@ ccl_device_inline Transform transform_quick_inverse(Transform M)
* scale can be inverted but what about shearing? */
Transform R;
float det = M.x.x*(M.z.z*M.y.y - M.z.y*M.y.z) - M.y.x*(M.z.z*M.x.y - M.z.y*M.x.z) + M.z.x*(M.y.z*M.x.y - M.y.y*M.x.z);
-
+ if(det == 0.0f) {
+ M.x.x += 1e-8f;
+ M.y.y += 1e-8f;
+ M.z.z += 1e-8f;
+ det = M.x.x*(M.z.z*M.y.y - M.z.y*M.y.z) - M.y.x*(M.z.z*M.x.y - M.z.y*M.x.z) + M.z.x*(M.y.z*M.x.y - M.y.y*M.x.z);
+ }
det = (det != 0.0f)? 1.0f/det: 0.0f;
float3 Rx = det*make_float3(M.z.z*M.y.y - M.z.y*M.y.z, M.z.y*M.x.z - M.z.z*M.x.y, M.y.z*M.x.y - M.y.y*M.x.z);
diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h
index 6f474f873a6..972befa185b 100644
--- a/intern/cycles/util/util_types.h
+++ b/intern/cycles/util/util_types.h
@@ -468,6 +468,8 @@ enum InterpolationType {
INTERPOLATION_CLOSEST = 1,
INTERPOLATION_CUBIC = 2,
INTERPOLATION_SMART = 3,
+
+ INTERPOLATION_NUM_TYPES,
};
/* Extension types for textures.
@@ -481,6 +483,8 @@ enum ExtensionType {
EXTENSION_EXTEND = 1,
/* Clip to image size and set exterior pixels as transparent. */
EXTENSION_CLIP = 2,
+
+ EXTENSION_NUM_TYPES,
};
/* macros */
diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h
index ee1f997721d..4eb0dde8308 100644
--- a/intern/cycles/util/util_vector.h
+++ b/intern/cycles/util/util_vector.h
@@ -24,30 +24,21 @@
#include <vector>
#include "util_aligned_malloc.h"
+#include "util_guarded_allocator.h"
#include "util_types.h"
-#ifdef WITH_CYCLES_DEBUG
-# include "util_guarded_allocator.h"
-#endif
-
CCL_NAMESPACE_BEGIN
/* Vector
*
* Own subclass-ed vestion of std::vector. Subclass is needed because:
*
- * - When building with WITH_CYCLES_DEBUG we need to use own allocator which
- * keeps track of used/peak memory.
+ * - Use own allocator which keeps track of used/peak memory.
*
* - Have method to ensure capacity is re-set to 0.
*/
template<typename value_type,
-#ifdef WITH_CYCLES_DEBUG
- typename allocator_type = GuardedAllocator<value_type>
-#else
- typename allocator_type = std::allocator<value_type>
-#endif
- >
+ typename allocator_type = GuardedAllocator<value_type> >
class vector : public std::vector<value_type, allocator_type>
{
public:
@@ -84,7 +75,7 @@ public:
/* Some external API might demand working with std::vector. */
operator std::vector<value_type>()
{
- return std::vector<value_type>(*this);
+ return std::vector<value_type>(this->begin(), this->end());
}
};
@@ -102,23 +93,22 @@ class array
{
public:
array()
- {
- data = NULL;
- datasize = 0;
- capacity = 0;
- }
+ : data_(NULL),
+ datasize_(0),
+ capacity_(0)
+ {}
array(size_t newsize)
{
if(newsize == 0) {
- data = NULL;
- datasize = 0;
- capacity = 0;
+ data_ = NULL;
+ datasize_ = 0;
+ capacity_ = 0;
}
else {
- data = (T*)util_aligned_malloc(sizeof(T)*newsize, alignment);
- datasize = newsize;
- capacity = datasize;
+ data_ = mem_allocate(newsize);
+ datasize_ = newsize;
+ capacity_ = datasize_;
}
}
@@ -130,15 +120,15 @@ public:
array& operator=(const array& from)
{
if(from.datasize == 0) {
- data = NULL;
- datasize = 0;
- capacity = 0;
+ data_ = NULL;
+ datasize_ = 0;
+ capacity_ = 0;
}
else {
- data = (T*)util_aligned_malloc(sizeof(T)*from.datasize, alignment);
- memcpy(data, from.data, from.datasize*sizeof(T));
- datasize = from.datasize;
- capacity = datasize;
+ data_ = mem_allocate(from.datasize);
+ memcpy(data_, from.data, from.datasize*sizeof(T));
+ datasize_ = from.datasize_;
+ capacity_ = datasize_;
}
return *this;
@@ -146,13 +136,13 @@ public:
array& operator=(const vector<T>& from)
{
- datasize = from.size();
- capacity = datasize;
- data = NULL;
+ datasize_ = from.size();
+ capacity_ = datasize_;
+ data_ = NULL;
- if(datasize > 0) {
- data = (T*)util_aligned_malloc(sizeof(T)*datasize, alignment);
- memcpy(data, &from[0], datasize*sizeof(T));
+ if(datasize_ > 0) {
+ data_ = mem_allocate(datasize_);
+ memcpy(data_, &from[0], datasize_*sizeof(T));
}
return *this;
@@ -160,63 +150,92 @@ public:
~array()
{
- util_aligned_free(data);
+ mem_free(data_, capacity_);
}
- void resize(size_t newsize)
+ T* resize(size_t newsize)
{
if(newsize == 0) {
clear();
}
- else if(newsize != datasize) {
- if(newsize > capacity) {
- T *newdata = (T*)util_aligned_malloc(sizeof(T)*newsize, alignment);
- if(data) {
- memcpy(newdata, data, ((datasize < newsize)? datasize: newsize)*sizeof(T));
- util_aligned_free(data);
+ else if(newsize != datasize_) {
+ if(newsize > capacity_) {
+ T *newdata = mem_allocate(newsize);
+ if(newdata == NULL) {
+ /* Allocation failed, likely out of memory. */
+ clear();
+ return NULL;
+ }
+ else if(data_ != NULL) {
+ memcpy(newdata, data_, ((datasize_ < newsize)? datasize_: newsize)*sizeof(T));
+ mem_free(data_, capacity_);
}
- data = newdata;
- capacity = newsize;
+ data_ = newdata;
+ capacity_ = newsize;
}
- datasize = newsize;
+ datasize_ = newsize;
}
+ return data_;
}
void clear()
{
- util_aligned_free(data);
- data = NULL;
- datasize = 0;
- capacity = 0;
+ if(data_ != NULL) {
+ mem_free(data_, capacity_);
+ data_ = NULL;
+ }
+ datasize_ = 0;
+ capacity_ = 0;
}
size_t size() const
{
- return datasize;
+ return datasize_;
}
T& operator[](size_t i) const
{
- assert(i < datasize);
- return data[i];
+ assert(i < datasize_);
+ return data_[i];
}
void reserve(size_t newcapacity) {
- if(newcapacity > capacity) {
- T *newdata = (T*)util_aligned_malloc(sizeof(T)*newcapacity, alignment);
- if(data) {
- memcpy(newdata, data, ((datasize < newcapacity)? datasize: newcapacity)*sizeof(T));
- util_aligned_free(data);
+ if(newcapacity > capacity_) {
+ T *newdata = mem_allocate(newcapacity);
+ if(data_ != NULL) {
+ memcpy(newdata, data_, ((datasize_ < newcapacity)? datasize_: newcapacity)*sizeof(T));
+ mem_free(data_, capacity_);
}
- data = newdata;
- capacity = newcapacity;
+ data_ = newdata;
+ capacity_ = newcapacity;
}
}
+ size_t capacity() const {
+ return capacity_;
+ }
+
protected:
- T *data;
- size_t datasize;
- size_t capacity;
+ inline T* mem_allocate(size_t N)
+ {
+ T *mem = (T*)util_aligned_malloc(sizeof(T)*N, alignment);
+ if(mem != NULL) {
+ util_guarded_mem_alloc(sizeof(T)*N);
+ }
+ return mem;
+ }
+
+ inline void mem_free(T *mem, size_t N)
+ {
+ if(mem != NULL) {
+ util_guarded_mem_free(sizeof(T)*N);
+ util_aligned_free(mem);
+ }
+ }
+
+ T *data_;
+ size_t datasize_;
+ size_t capacity_;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_version.h b/intern/cycles/util/util_version.h
new file mode 100644
index 00000000000..186a177d9d3
--- /dev/null
+++ b/intern/cycles/util/util_version.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_VERSION_H__
+#define __UTIL_VERSION_H__
+
+/* Cycles version number */
+
+CCL_NAMESPACE_BEGIN
+
+#define CYCLES_VERSION_MAJOR 1
+#define CYCLES_VERSION_MINOR 7
+#define CYCLES_VERSION_PATCH 0
+
+#define CYCLES_MAKE_VERSION_STRING2(a,b,c) #a "." #b "." #c
+#define CYCLES_MAKE_VERSION_STRING(a,b,c) CYCLES_MAKE_VERSION_STRING2(a,b,c)
+#define CYCLES_VERSION_STRING \
+ CYCLES_MAKE_VERSION_STRING(CYCLES_VERSION_MAJOR, \
+ CYCLES_VERSION_MINOR, \
+ CYCLES_VERSION_PATCH)
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_VERSION_H__ */
diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp
index 9b5cd22fb4a..4d2adf33a7a 100644
--- a/intern/cycles/util/util_view.cpp
+++ b/intern/cycles/util/util_view.cpp
@@ -16,10 +16,11 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include "util_opengl.h"
+#include "util_string.h"
#include "util_time.h"
+#include "util_version.h"
#include "util_view.h"
#ifdef __APPLE__
@@ -97,8 +98,10 @@ void view_display_help()
glColor3f(0.8f, 0.8f, 0.8f);
- view_display_text(x1+20, y2-20, "Cycles Renderer");
- view_display_text(x1+20, y2-40, "(C) 2011-2015 Blender Foundation");
+ string info = string("Cycles Renderer ") + CYCLES_VERSION_STRING;
+
+ view_display_text(x1+20, y2-20, info.c_str());
+ view_display_text(x1+20, y2-40, "(C) 2011-2016 Blender Foundation");
view_display_text(x1+20, y2-80, "Controls:");
view_display_text(x1+20, y2-100, "h: Info/Help");
view_display_text(x1+20, y2-120, "r: Reset");
diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h
new file mode 100644
index 00000000000..f67e34d0f31
--- /dev/null
+++ b/intern/cycles/util/util_windows.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_WINDOWS_H__
+#define __UTIL_WINDOWS_H__
+
+#ifdef _WIN32
+
+#ifndef NOGDI
+# define NOGDI
+#endif
+#ifndef NOMINMAX
+# define NOMINMAX
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+
+#endif /* WIN32 */
+
+#endif /* __UTIL_WINDOWS_H__ */
+
diff --git a/intern/dualcon/SConscript b/intern/dualcon/SConscript
deleted file mode 100644
index 34df21a74c3..00000000000
--- a/intern/dualcon/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = '. ../../extern/Eigen3'
-defs = ''
-
-env.BlenderLib ('bf_intern_dualcon', sources, Split(incs), Split(defs), libtype=['intern'], priority=[100] )
diff --git a/intern/dualcon/intern/Projections.h b/intern/dualcon/intern/Projections.h
index a5086ddca39..2d1eca55997 100644
--- a/intern/dualcon/intern/Projections.h
+++ b/intern/dualcon/intern/Projections.h
@@ -29,7 +29,7 @@
#define CONTAINS_INDEX
#define GRID_DIMENSION 20
-#if defined(_WIN32) && !defined(__MINGW32__)
+#if defined(_WIN32) && !defined(__MINGW32__) && !(_MSC_VER >= 1900)
#define isnan(n) _isnan(n)
#define LONG __int64
#define int64_t __int64
diff --git a/intern/eigen/CMakeLists.txt b/intern/eigen/CMakeLists.txt
new file mode 100644
index 00000000000..5811b71de94
--- /dev/null
+++ b/intern/eigen/CMakeLists.txt
@@ -0,0 +1,46 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2015, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Bastien Montagne.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+)
+
+set(INC_SYS
+ ${EIGEN3_INCLUDE_DIRS}
+)
+
+set(SRC
+ eigen_capi.h
+
+ intern/eigenvalues.cc
+ intern/linear_solver.cc
+ intern/svd.cc
+
+ intern/eigenvalues.h
+ intern/linear_solver.h
+ intern/svd.h
+)
+
+blender_add_lib(bf_intern_eigen "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/eigen/eigen_capi.h b/intern/eigen/eigen_capi.h
new file mode 100644
index 00000000000..be42e340274
--- /dev/null
+++ b/intern/eigen/eigen_capi.h
@@ -0,0 +1,34 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __EIGEN_C_API_H__
+#define __EIGEN_C_API_H__
+
+#include "intern/eigenvalues.h"
+#include "intern/linear_solver.h"
+#include "intern/svd.h"
+
+#endif /* __EIGEN_C_API_H__ */
diff --git a/intern/eigen/intern/eigenvalues.cc b/intern/eigen/intern/eigenvalues.cc
new file mode 100644
index 00000000000..57942a4dc55
--- /dev/null
+++ b/intern/eigen/intern/eigenvalues.cc
@@ -0,0 +1,70 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __EIGEN3_EIGENVALUES_C_API_CC__
+#define __EIGEN3_EIGENVALUES_C_API_CC__
+
+/* Eigen gives annoying huge amount of warnings here, silence them! */
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+
+#include <Eigen/Core>
+#include <Eigen/Eigenvalues>
+
+#include "eigenvalues.h"
+
+using Eigen::SelfAdjointEigenSolver;
+
+using Eigen::MatrixXf;
+using Eigen::VectorXf;
+using Eigen::Map;
+
+using Eigen::Success;
+
+bool EIG_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors)
+{
+ SelfAdjointEigenSolver<MatrixXf> eigen_solver;
+
+ /* Blender and Eigen matrices are both column-major. */
+ eigen_solver.compute(Map<MatrixXf>((float *)matrix, size, size));
+
+ if (eigen_solver.info() != Success) {
+ return false;
+ }
+
+ if (r_eigen_values) {
+ Map<VectorXf>(r_eigen_values, size) = eigen_solver.eigenvalues().transpose();
+ }
+
+ if (r_eigen_vectors) {
+ Map<MatrixXf>(r_eigen_vectors, size, size) = eigen_solver.eigenvectors();
+ }
+
+ return true;
+}
+
+#endif /* __EIGEN3_EIGENVALUES_C_API_CC__ */
diff --git a/intern/eigen/intern/eigenvalues.h b/intern/eigen/intern/eigenvalues.h
new file mode 100644
index 00000000000..5c08ab5be39
--- /dev/null
+++ b/intern/eigen/intern/eigenvalues.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __EIGEN3_EIGENVALUES_C_API_H__
+#define __EIGEN3_EIGENVALUES_C_API_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool EIG_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EIGEN3_EIGENVALUES_C_API_H__ */
diff --git a/intern/eigen/intern/linear_solver.cc b/intern/eigen/intern/linear_solver.cc
new file mode 100644
index 00000000000..0fc4d39309b
--- /dev/null
+++ b/intern/eigen/intern/linear_solver.cc
@@ -0,0 +1,366 @@
+/*
+ * Sparse linear solver.
+ * Copyright (C) 2004 Bruno Levy
+ * Copyright (C) 2005-2015 Blender Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+
+#include "linear_solver.h"
+
+#include <Eigen/Sparse>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <iostream>
+#include <vector>
+
+/* Eigen data structures */
+
+typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix;
+typedef Eigen::SparseLU<EigenSparseMatrix> EigenSparseLU;
+typedef Eigen::VectorXd EigenVectorX;
+typedef Eigen::Triplet<double> EigenTriplet;
+
+/* Linear Solver data structure */
+
+struct LinearSolver
+{
+ struct Coeff
+ {
+ Coeff()
+ {
+ index = 0;
+ value = 0.0;
+ }
+
+ int index;
+ double value;
+ };
+
+ struct Variable
+ {
+ Variable()
+ {
+ memset(value, 0, sizeof(value));
+ locked = false;
+ index = 0;
+ }
+
+ double value[4];
+ bool locked;
+ int index;
+ std::vector<Coeff> a;
+ };
+
+ enum State
+ {
+ STATE_VARIABLES_CONSTRUCT,
+ STATE_MATRIX_CONSTRUCT,
+ STATE_MATRIX_SOLVED
+ };
+
+ LinearSolver(int num_rows_, int num_variables_, int num_rhs_, bool lsq_)
+ {
+ assert(num_variables_ > 0);
+ assert(num_rhs_ <= 4);
+
+ state = STATE_VARIABLES_CONSTRUCT;
+ m = 0;
+ n = 0;
+ sparseLU = NULL;
+ num_variables = num_variables_;
+ num_rhs = num_rhs_;
+ num_rows = num_rows_;
+ least_squares = lsq_;
+
+ variable.resize(num_variables);
+ }
+
+ ~LinearSolver()
+ {
+ delete sparseLU;
+ }
+
+ State state;
+
+ int n;
+ int m;
+
+ std::vector<EigenTriplet> Mtriplets;
+ EigenSparseMatrix M;
+ EigenSparseMatrix MtM;
+ std::vector<EigenVectorX> b;
+ std::vector<EigenVectorX> x;
+
+ EigenSparseLU *sparseLU;
+
+ int num_variables;
+ std::vector<Variable> variable;
+
+ int num_rows;
+ int num_rhs;
+
+ bool least_squares;
+};
+
+LinearSolver *EIG_linear_solver_new(int num_rows, int num_columns, int num_rhs)
+{
+ return new LinearSolver(num_rows, num_columns, num_rhs, false);
+}
+
+LinearSolver *EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_rhs)
+{
+ return new LinearSolver(num_rows, num_columns, num_rhs, true);
+}
+
+void EIG_linear_solver_delete(LinearSolver *solver)
+{
+ delete solver;
+}
+
+/* Variables */
+
+void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value)
+{
+ solver->variable[index].value[rhs] = value;
+}
+
+double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index)
+{
+ return solver->variable[index].value[rhs];
+}
+
+void EIG_linear_solver_variable_lock(LinearSolver *solver, int index)
+{
+ if (!solver->variable[index].locked) {
+ assert(solver->state == LinearSolver::STATE_VARIABLES_CONSTRUCT);
+ solver->variable[index].locked = true;
+ }
+}
+
+void EIG_linear_solver_variable_unlock(LinearSolver *solver, int index)
+{
+ if (solver->variable[index].locked) {
+ assert(solver->state == LinearSolver::STATE_VARIABLES_CONSTRUCT);
+ solver->variable[index].locked = false;
+ }
+}
+
+static void linear_solver_variables_to_vector(LinearSolver *solver)
+{
+ int num_rhs = solver->num_rhs;
+
+ for (int i = 0; i < solver->num_variables; i++) {
+ LinearSolver::Variable* v = &solver->variable[i];
+ if (!v->locked) {
+ for (int j = 0; j < num_rhs; j++)
+ solver->x[j][v->index] = v->value[j];
+ }
+ }
+}
+
+static void linear_solver_vector_to_variables(LinearSolver *solver)
+{
+ int num_rhs = solver->num_rhs;
+
+ for (int i = 0; i < solver->num_variables; i++) {
+ LinearSolver::Variable* v = &solver->variable[i];
+ if (!v->locked) {
+ for (int j = 0; j < num_rhs; j++)
+ v->value[j] = solver->x[j][v->index];
+ }
+ }
+}
+
+/* Matrix */
+
+static void linear_solver_ensure_matrix_construct(LinearSolver *solver)
+{
+ /* transition to matrix construction if necessary */
+ if (solver->state == LinearSolver::STATE_VARIABLES_CONSTRUCT) {
+ int n = 0;
+
+ for (int i = 0; i < solver->num_variables; i++) {
+ if (solver->variable[i].locked)
+ solver->variable[i].index = ~0;
+ else
+ solver->variable[i].index = n++;
+ }
+
+ int m = (solver->num_rows == 0)? n: solver->num_rows;
+
+ solver->m = m;
+ solver->n = n;
+
+ assert(solver->least_squares || m == n);
+
+ /* reserve reasonable estimate */
+ solver->Mtriplets.clear();
+ solver->Mtriplets.reserve(std::max(m, n)*3);
+
+ solver->b.resize(solver->num_rhs);
+ solver->x.resize(solver->num_rhs);
+
+ for (int i = 0; i < solver->num_rhs; i++) {
+ solver->b[i].setZero(m);
+ solver->x[i].setZero(n);
+ }
+
+ linear_solver_variables_to_vector(solver);
+
+ solver->state = LinearSolver::STATE_MATRIX_CONSTRUCT;
+ }
+}
+
+void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value)
+{
+ if (solver->state == LinearSolver::STATE_MATRIX_SOLVED)
+ return;
+
+ linear_solver_ensure_matrix_construct(solver);
+
+ if (!solver->least_squares && solver->variable[row].locked);
+ else if (solver->variable[col].locked) {
+ if (!solver->least_squares)
+ row = solver->variable[row].index;
+
+ LinearSolver::Coeff coeff;
+ coeff.index = row;
+ coeff.value = value;
+ solver->variable[col].a.push_back(coeff);
+ }
+ else {
+ if (!solver->least_squares)
+ row = solver->variable[row].index;
+ col = solver->variable[col].index;
+
+ /* direct insert into matrix is too slow, so use triplets */
+ EigenTriplet triplet(row, col, value);
+ solver->Mtriplets.push_back(triplet);
+ }
+}
+
+/* Right hand side */
+
+void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value)
+{
+ linear_solver_ensure_matrix_construct(solver);
+
+ if (solver->least_squares) {
+ solver->b[rhs][index] += value;
+ }
+ else if (!solver->variable[index].locked) {
+ index = solver->variable[index].index;
+ solver->b[rhs][index] += value;
+ }
+}
+
+/* Solve */
+
+bool EIG_linear_solver_solve(LinearSolver *solver)
+{
+ /* nothing to solve, perhaps all variables were locked */
+ if (solver->m == 0 || solver->n == 0)
+ return true;
+
+ bool result = true;
+
+ assert(solver->state != LinearSolver::STATE_VARIABLES_CONSTRUCT);
+
+ if (solver->state == LinearSolver::STATE_MATRIX_CONSTRUCT) {
+ /* create matrix from triplets */
+ solver->M.resize(solver->m, solver->n);
+ solver->M.setFromTriplets(solver->Mtriplets.begin(), solver->Mtriplets.end());
+ solver->Mtriplets.clear();
+
+ /* create least squares matrix */
+ if (solver->least_squares)
+ solver->MtM = solver->M.transpose() * solver->M;
+
+ /* convert M to compressed column format */
+ EigenSparseMatrix& M = (solver->least_squares)? solver->MtM: solver->M;
+ M.makeCompressed();
+
+ /* perform sparse LU factorization */
+ EigenSparseLU *sparseLU = new EigenSparseLU();
+ solver->sparseLU = sparseLU;
+
+ sparseLU->compute(M);
+ result = (sparseLU->info() == Eigen::Success);
+
+ solver->state = LinearSolver::STATE_MATRIX_SOLVED;
+ }
+
+ if (result) {
+ /* solve for each right hand side */
+ for (int rhs = 0; rhs < solver->num_rhs; rhs++) {
+ /* modify for locked variables */
+ EigenVectorX& b = solver->b[rhs];
+
+ for (int i = 0; i < solver->num_variables; i++) {
+ LinearSolver::Variable *variable = &solver->variable[i];
+
+ if (variable->locked) {
+ std::vector<LinearSolver::Coeff>& a = variable->a;
+
+ for (int j = 0; j < a.size(); j++)
+ b[a[j].index] -= a[j].value*variable->value[rhs];
+ }
+ }
+
+ /* solve */
+ if (solver->least_squares) {
+ EigenVectorX Mtb = solver->M.transpose() * b;
+ solver->x[rhs] = solver->sparseLU->solve(Mtb);
+ }
+ else {
+ EigenVectorX& b = solver->b[rhs];
+ solver->x[rhs] = solver->sparseLU->solve(b);
+ }
+
+ if (solver->sparseLU->info() != Eigen::Success)
+ result = false;
+ }
+
+ if (result)
+ linear_solver_vector_to_variables(solver);
+ }
+
+ /* clear for next solve */
+ for (int rhs = 0; rhs < solver->num_rhs; rhs++)
+ solver->b[rhs].setZero(solver->m);
+
+ return result;
+}
+
+/* Debugging */
+
+void EIG_linear_solver_print_matrix(LinearSolver *solver)
+{
+ std::cout << "A:" << solver->M << std::endl;
+
+ for (int rhs = 0; rhs < solver->num_rhs; rhs++)
+ std::cout << "b " << rhs << ":" << solver->b[rhs] << std::endl;
+
+ if (solver->MtM.rows() && solver->MtM.cols())
+ std::cout << "AtA:" << solver->MtM << std::endl;
+}
+
diff --git a/intern/eigen/intern/linear_solver.h b/intern/eigen/intern/linear_solver.h
new file mode 100644
index 00000000000..8f07e24e9a6
--- /dev/null
+++ b/intern/eigen/intern/linear_solver.h
@@ -0,0 +1,72 @@
+/*
+ * Sparse linear solver.
+ * Copyright (C) 2004 Bruno Levy
+ * Copyright (C) 2005-2015 Blender Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * If you modify this software, you should include a notice giving the
+ * name of the person performing the modification, the date of modification,
+ * and the reason for such modification.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Solvers for Ax = b and AtAx = Atb */
+
+typedef struct LinearSolver LinearSolver;
+
+LinearSolver *EIG_linear_solver_new(
+ int num_rows,
+ int num_columns,
+ int num_right_hand_sides);
+
+LinearSolver *EIG_linear_least_squares_solver_new(
+ int num_rows,
+ int num_columns,
+ int num_right_hand_sides);
+
+void EIG_linear_solver_delete(LinearSolver *solver);
+
+/* Variables (x). Any locking must be done before matrix construction. */
+
+void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value);
+double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index);
+void EIG_linear_solver_variable_lock(LinearSolver *solver, int index);
+void EIG_linear_solver_variable_unlock(LinearSolver *solver, int index);
+
+/* Matrix (A) and right hand side (b) */
+
+void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value);
+void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value);
+
+/* Solve. Repeated solves are supported, by changing b between solves. */
+
+bool EIG_linear_solver_solve(LinearSolver *solver);
+
+/* Debugging */
+
+void EIG_linear_solver_print_matrix(LinearSolver *solver);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/intern/eigen/intern/svd.cc b/intern/eigen/intern/svd.cc
new file mode 100644
index 00000000000..04929cff798
--- /dev/null
+++ b/intern/eigen/intern/svd.cc
@@ -0,0 +1,75 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __EIGEN3_SVD_C_API_CC__
+#define __EIGEN3_SVD_C_API_CC__
+
+/* Eigen gives annoying huge amount of warnings here, silence them! */
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+
+#ifdef __EIGEN3_SVD_C_API_CC__ /* quiet warning */
+#endif
+
+#include <Eigen/Core>
+#include <Eigen/SVD>
+
+#include "svd.h"
+
+using Eigen::JacobiSVD;
+
+using Eigen::NoQRPreconditioner;
+
+using Eigen::ComputeThinU;
+using Eigen::ComputeThinV;
+
+using Eigen::MatrixXf;
+using Eigen::VectorXf;
+using Eigen::Map;
+
+void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V)
+{
+ /* Since our matrix is squared, we can use thinU/V. */
+ unsigned int flags = (r_U ? ComputeThinU : 0) | (r_V ? ComputeThinV : 0);
+
+ /* Blender and Eigen matrices are both column-major. */
+ JacobiSVD<MatrixXf, NoQRPreconditioner> svd(Map<MatrixXf>((float *)matrix, size, size), flags);
+
+ if (r_U) {
+ Map<MatrixXf>(r_U, size, size) = svd.matrixU();
+ }
+
+ if (r_S) {
+ Map<VectorXf>(r_S, size) = svd.singularValues();
+ }
+
+ if (r_V) {
+ Map<MatrixXf>(r_V, size, size) = svd.matrixV();
+ }
+}
+
+#endif /* __EIGEN3_SVD_C_API_CC__ */
diff --git a/intern/eigen/intern/svd.h b/intern/eigen/intern/svd.h
new file mode 100644
index 00000000000..feadcc3520a
--- /dev/null
+++ b/intern/eigen/intern/svd.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __EIGEN3_SVD_C_API_H__
+#define __EIGEN3_SVD_C_API_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EIGEN3_SVD_C_API_H__ */
diff --git a/intern/elbeem/SConscript b/intern/elbeem/SConscript
deleted file mode 100644
index e3a20cf9d45..00000000000
--- a/intern/elbeem/SConscript
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-import os
-Import('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = ''
-defs = 'NOGUI ELBEEM_BLENDER=1'
-
-if env['WITH_BF_OPENMP']:
- if env['OURPLATFORM'] == 'linuxcross':
- incs += ' ' + env['BF_OPENMP_INC']
-
- defs += ' PARALLEL'
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- defs += ' USE_MSVC6FIXES'
-incs += ' ' + env['BF_PNG_INC'] + ' ' + env['BF_ZLIB_INC']
-incs += ' extern ../../guardedalloc'
-
-env.BlenderLib ('bf_intern_elbeem', sources, Split(incs), Split(defs), libtype='intern', priority=0 )
diff --git a/intern/elbeem/intern/simulation_object.cpp b/intern/elbeem/intern/simulation_object.cpp
index 99c3b170634..f2f928f07dc 100644
--- a/intern/elbeem/intern/simulation_object.cpp
+++ b/intern/elbeem/intern/simulation_object.cpp
@@ -172,7 +172,7 @@ int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
mpLbm->setParticleTracer( mpParts );
if(mpElbeemSettings) {
// set further settings from API struct init
- if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath);
+ this->mOutFilename = string(mpElbeemSettings->outputPath);
mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo );
mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing);
mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs);
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index ac4da5b6133..bcfa24b06a8 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -446,4 +446,230 @@ AVRational av_get_r_frame_rate_compat(const AVStream *stream)
# define FFMPEG_HAVE_DEPRECATED_FLAGS2
#endif
+/* Since FFmpeg-1.1 this constant have AV_ prefix. */
+#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 3, 100)
+# define AV_PIX_FMT_BGR32 PIX_FMT_BGR32
+# define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
+# define AV_PIX_FMT_BGRA PIX_FMT_BGRA
+# define AV_PIX_FMT_ARGB PIX_FMT_ARGB
+# define AV_PIX_FMT_RGBA PIX_FMT_RGBA
+#endif
+
+/* New API from FFmpeg-2.0 which soon became recommended one. */
+#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 38, 100)
+# define av_frame_alloc avcodec_alloc_frame
+# define av_frame_free avcodec_free_frame
+# define av_frame_unref avcodec_get_frame_defaults
+#endif
+
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 102)
+
+/* NOTE: The code in this block are from FFmpeg 2.6.4, which is licensed by LGPL. */
+
+#define MAX_NEG_CROP 1024
+
+#define times4(x) x, x, x, x
+#define times256(x) times4(times4(times4(times4(times4(x)))))
+
+static const uint8_t ff_compat_crop_tab[256 + 2 * MAX_NEG_CROP] = {
+times256(0x00),
+0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
+times256(0xFF)
+};
+
+#undef times4
+#undef times256
+
+/* filter parameters: [-1 4 2 4 -1] // 8 */
+FFMPEG_INLINE
+void deinterlace_line(uint8_t *dst,
+ const uint8_t *lum_m4, const uint8_t *lum_m3,
+ const uint8_t *lum_m2, const uint8_t *lum_m1,
+ const uint8_t *lum,
+ int size)
+{
+ const uint8_t *cm = ff_compat_crop_tab + MAX_NEG_CROP;
+ int sum;
+
+ for(;size > 0;size--) {
+ sum = -lum_m4[0];
+ sum += lum_m3[0] << 2;
+ sum += lum_m2[0] << 1;
+ sum += lum_m1[0] << 2;
+ sum += -lum[0];
+ dst[0] = cm[(sum + 4) >> 3];
+ lum_m4++;
+ lum_m3++;
+ lum_m2++;
+ lum_m1++;
+ lum++;
+ dst++;
+ }
+}
+
+FFMPEG_INLINE
+void deinterlace_line_inplace(uint8_t *lum_m4, uint8_t *lum_m3,
+ uint8_t *lum_m2, uint8_t *lum_m1,
+ uint8_t *lum, int size)
+{
+ const uint8_t *cm = ff_compat_crop_tab + MAX_NEG_CROP;
+ int sum;
+
+ for(;size > 0;size--) {
+ sum = -lum_m4[0];
+ sum += lum_m3[0] << 2;
+ sum += lum_m2[0] << 1;
+ lum_m4[0]=lum_m2[0];
+ sum += lum_m1[0] << 2;
+ sum += -lum[0];
+ lum_m2[0] = cm[(sum + 4) >> 3];
+ lum_m4++;
+ lum_m3++;
+ lum_m2++;
+ lum_m1++;
+ lum++;
+ }
+}
+
+/* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
+ top field is copied as is, but the bottom field is deinterlaced
+ against the top field. */
+FFMPEG_INLINE
+void deinterlace_bottom_field(uint8_t *dst, int dst_wrap,
+ const uint8_t *src1, int src_wrap,
+ int width, int height)
+{
+ const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
+ int y;
+
+ src_m2 = src1;
+ src_m1 = src1;
+ src_0=&src_m1[src_wrap];
+ src_p1=&src_0[src_wrap];
+ src_p2=&src_p1[src_wrap];
+ for(y=0;y<(height-2);y+=2) {
+ memcpy(dst,src_m1,width);
+ dst += dst_wrap;
+ deinterlace_line(dst,src_m2,src_m1,src_0,src_p1,src_p2,width);
+ src_m2 = src_0;
+ src_m1 = src_p1;
+ src_0 = src_p2;
+ src_p1 += 2*src_wrap;
+ src_p2 += 2*src_wrap;
+ dst += dst_wrap;
+ }
+ memcpy(dst,src_m1,width);
+ dst += dst_wrap;
+ /* do last line */
+ deinterlace_line(dst,src_m2,src_m1,src_0,src_0,src_0,width);
+}
+
+FFMPEG_INLINE
+int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap,
+ int width, int height)
+{
+ uint8_t *src_m1, *src_0, *src_p1, *src_p2;
+ int y;
+ uint8_t *buf = (uint8_t *)av_malloc(width);
+ if (!buf)
+ return AVERROR(ENOMEM);
+
+ src_m1 = src1;
+ memcpy(buf,src_m1,width);
+ src_0=&src_m1[src_wrap];
+ src_p1=&src_0[src_wrap];
+ src_p2=&src_p1[src_wrap];
+ for(y=0;y<(height-2);y+=2) {
+ deinterlace_line_inplace(buf,src_m1,src_0,src_p1,src_p2,width);
+ src_m1 = src_p1;
+ src_0 = src_p2;
+ src_p1 += 2*src_wrap;
+ src_p2 += 2*src_wrap;
+ }
+ /* do last line */
+ deinterlace_line_inplace(buf,src_m1,src_0,src_0,src_0,width);
+ av_free(buf);
+ return 0;
+}
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+FFMPEG_INLINE
+int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
+ enum AVPixelFormat pix_fmt, int width, int height)
+{
+ int i, ret;
+
+ if (pix_fmt != AV_PIX_FMT_YUV420P &&
+ pix_fmt != AV_PIX_FMT_YUVJ420P &&
+ pix_fmt != AV_PIX_FMT_YUV422P &&
+ pix_fmt != AV_PIX_FMT_YUVJ422P &&
+ pix_fmt != AV_PIX_FMT_YUV444P &&
+ pix_fmt != AV_PIX_FMT_YUV411P &&
+ pix_fmt != AV_PIX_FMT_GRAY8)
+ return -1;
+ if ((width & 3) != 0 || (height & 3) != 0)
+ return -1;
+
+ for(i=0;i<3;i++) {
+ if (i == 1) {
+ switch(pix_fmt) {
+ case AV_PIX_FMT_YUVJ420P:
+ case AV_PIX_FMT_YUV420P:
+ width >>= 1;
+ height >>= 1;
+ break;
+ case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUVJ422P:
+ width >>= 1;
+ break;
+ case AV_PIX_FMT_YUV411P:
+ width >>= 2;
+ break;
+ default:
+ break;
+ }
+ if (pix_fmt == AV_PIX_FMT_GRAY8) {
+ break;
+ }
+ }
+ if (src == dst) {
+ ret = deinterlace_bottom_field_inplace(dst->data[i],
+ dst->linesize[i],
+ width, height);
+ if (ret < 0)
+ return ret;
+ } else {
+ deinterlace_bottom_field(dst->data[i],dst->linesize[i],
+ src->data[i], src->linesize[i],
+ width, height);
+ }
+ }
+ return 0;
+}
+
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#endif
+
#endif
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 761bcb4dd27..d31e9472168 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -166,11 +166,6 @@ elseif(APPLE AND NOT WITH_X11)
intern/GHOST_NDOFManagerCocoa.h
)
-
- list(APPEND SRC_NDOF3DCONNEXION
- intern/GHOST_NDOFManager3Dconnexion.c
- intern/GHOST_NDOFManager3Dconnexion.h
- )
endif()
if(WITH_CODEC_QUICKTIME)
@@ -230,9 +225,9 @@ elseif(WITH_X11)
if(WITH_INPUT_NDOF)
list(APPEND SRC
- intern/GHOST_NDOFManagerX11.cpp
+ intern/GHOST_NDOFManagerUnix.cpp
- intern/GHOST_NDOFManagerX11.h
+ intern/GHOST_NDOFManagerUnix.h
)
endif()
@@ -315,8 +310,8 @@ if(APPLE)
elseif(UNIX)
list(APPEND SRC
- intern/GHOST_SystemPathsX11.cpp
- intern/GHOST_SystemPathsX11.h
+ intern/GHOST_SystemPathsUnix.cpp
+ intern/GHOST_SystemPathsUnix.h
)
if(NOT WITH_INSTALL_PORTABLE)
@@ -338,8 +333,3 @@ endif()
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_intern_ghost "${SRC}" "${INC}" "${INC_SYS}")
-
-# workaround for apple clang mangling extern "C" symbols
-if(WITH_INPUT_NDOF AND APPLE)
- blender_add_lib(bf_intern_ghostndof3dconnexion "${SRC_NDOF3DCONNEXION}" "${INC}" "${INC_SYS}")
-endif()
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ff0dc575005..f1484a298d3 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -263,9 +263,8 @@ extern int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent
/**
* Retrieves events from the queue and send them to the event consumers.
* \param systemhandle The handle to the system
- * \return Indication of the presence of events.
*/
-extern int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle);
+extern void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle);
/**
* Adds the given event consumer to our list.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 6825e8a0384..4c48473c7b8 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -319,9 +319,8 @@ public:
/**
* Retrieves events from the queue and send them to the event consumers.
- * \return Indication of the presence of events.
*/
- virtual bool dispatchEvents() = 0;
+ virtual void dispatchEvents() = 0;
/**
* Adds the given event consumer to our list.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 7a73af3f249..29508a83733 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -57,8 +57,7 @@ typedef struct {
typedef enum {
GHOST_glStereoVisual = (1 << 0),
- GHOST_glWarnSupport = (1 << 1),
- GHOST_glDebugContext = (1 << 2),
+ GHOST_glDebugContext = (1 << 1)
} GHOST_GLFlags;
diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript
deleted file mode 100644
index 78566210047..00000000000
--- a/intern/ghost/SConscript
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-import os
-
-Import ('env')
-
-window_system = env['OURPLATFORM']
-
-sources = env.Glob('intern/*.cpp')
-sources2 = env.Glob('intern/GHOST_NDOFManager3Dconnexion.c')
-if window_system == 'darwin':
- sources += env.Glob('intern/*.mm')
- #remove, will be readded below if needed.
- sources.remove('intern' + os.sep + 'GHOST_ContextCGL.mm')
-
-if not env['WITH_BF_GL_EGL']:
- sources.remove('intern' + os.sep + 'GHOST_ContextEGL.cpp')
-
-# seems cleaner to remove these now then add back the one that is needed
-sources.remove('intern' + os.sep + 'GHOST_ContextGLX.cpp')
-sources.remove('intern' + os.sep + 'GHOST_ContextWGL.cpp')
-
-pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget', 'GHOST_NDOFManager', 'GHOST_Context']
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_GL_EGL']:
- defs.append('WITH_EGL')
-
-incs = [
- '.',
- env['BF_GLEW_INC'],
- '../glew-mx',
- '#source/blender/imbuf',
- '#source/blender/makesdna',
- '../string',
- ]
-incs = ' '.join(incs)
-
-if env['WITH_GHOST_SDL']:
- for f in pf:
- try:
- sources.remove('intern' + os.sep + f + 'Win32.cpp')
- sources.remove('intern' + os.sep + f + 'X11.cpp')
- except ValueError:
- pass
- incs += ' ' + env['BF_SDL_INC']
- defs += ['WITH_GHOST_SDL']
-elif window_system in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'aix4', 'aix5'):
- for f in pf:
- try:
- sources.remove('intern' + os.sep + f + 'Win32.cpp')
- except ValueError:
- pass
-
- try:
- sources.remove('intern' + os.sep + f + 'SDL.cpp')
- except ValueError:
- pass
-
- defs += ['WITH_X11']
-
- ## removing because scons does not support system installation
- ## if this is used for blender.org builds it means our distrobution
- ## will find any locally installed blender and double up its script path.
- ## So until this is supported properly as with CMake,
- ## just dont use the PREFIX.
- # defs += ['PREFIX=\\"/usr/local/\\"'] # XXX, make an option
- if env['WITH_X11_XINPUT']:
- defs += ['WITH_X11_XINPUT']
-
- if env['WITH_X11_XF86VMODE']:
- #incs += env['X11_xf86vmode_INCLUDE_PATH']
- defs += ['WITH_X11_XF86VMODE']
-
- # freebsd doesn't seem to support XDND protocol
- if env['WITH_GHOST_XDND'] and window_system not in ('freebsd7', 'freebsd8', 'freebsd9'):
- incs += ' #/extern/xdnd'
- defs += ['WITH_XDND']
- else:
- sources.remove('intern' + os.sep + 'GHOST_DropTargetX11.cpp')
-
- if not env['WITH_BF_GL_EGL']:
- sources.append('intern' + os.sep + 'GHOST_ContextGLX.cpp')
-
-elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc', 'win64-mingw'):
- for f in pf:
- try:
- sources.remove('intern' + os.sep + f + 'X11.cpp')
- except ValueError:
- pass
-
- try:
- sources.remove('intern' + os.sep + f + 'SDL.cpp')
- except ValueError:
- pass
-
- if not env['WITH_BF_GL_EGL']:
- sources.append('intern' + os.sep + 'GHOST_ContextWGL.cpp')
-
-elif window_system == 'darwin':
- if env['WITH_BF_QUICKTIME']:
- defs.append('WITH_QUICKTIME')
- for f in pf:
- try:
- sources.remove('intern' + os.sep + f + 'Win32.cpp')
- except ValueError:
- pass
-
- try:
- sources.remove('intern' + os.sep + f + 'X11.cpp')
- except ValueError:
- pass
- try:
- sources.remove('intern' + os.sep + f + 'SDL.cpp')
- except ValueError:
- pass
-
- if not env['WITH_BF_GL_EGL']:
- sources.append('intern' + os.sep + 'GHOST_ContextCGL.mm')
-
-else:
- print "Unknown window system specified."
- Exit()
-
-if env['BF_GHOST_DEBUG']:
- defs.append('WITH_GHOST_DEBUG')
-else:
- sources.remove('intern' + os.sep + 'GHOST_EventPrinter.cpp')
-
-if env['WITH_BF_IME'] and window_system in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
- defs.append('WITH_INPUT_IME')
-elif env['WITH_BF_IME']:
- print "IME input is only supported on Windows! Please disable WITH_BF_IME!"
- Exit()
-else:
- sources.remove('intern' + os.sep + 'GHOST_ImeWin32.cpp')
-
-if env['WITH_BF_3DMOUSE']:
- defs.append('WITH_INPUT_NDOF')
-
- if env['OURPLATFORM'] in ('linux','darwin'):
- incs += ' ' + env['BF_3DMOUSE_INC']
-else:
- sources.remove('intern' + os.sep + 'GHOST_NDOFManager.cpp')
- try:
- if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc', 'win64-mingw'):
- sources.remove('intern' + os.sep + 'GHOST_NDOFManagerWin32.cpp')
- elif window_system=='darwin':
- sources.remove('intern' + os.sep + 'GHOST_NDOFManagerCocoa.mm')
- else:
- sources.remove('intern' + os.sep + 'GHOST_NDOFManagerX11.cpp')
- except ValueError:
- pass
-
-if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs = env['BF_WINTAB_INC'] + ' ' + incs
- incs += ' ../utfconv'
-
-if window_system in ('win32-vc', 'win64-vc'):
- env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15]) #, cc_compileflags=env['CCFLAGS'].append('/WX') )
-
-elif window_system == 'darwin' and env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6': # always use default-Apple-gcc for objC language, for gnu-compilers do not support it fully yet
- env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15], cc_compilerchange='/usr/bin/gcc', cxx_compilerchange='/usr/bin/g++' )
- print "GHOST COCOA WILL BE COMPILED WITH APPLE GCC"
-
-else:
- env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15] )
-
-if window_system == 'darwin' and env['WITH_BF_3DMOUSE']: # build seperate to circumvent extern "C" linkage issues
- env.BlenderLib ('bf_intern_ghostndof3dconnexion', sources2, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15] )
-
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index af992bf5a3c..ccd7f57f9a4 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -230,11 +230,11 @@ int GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, int waitForEvent)
-int GHOST_DispatchEvents(GHOST_SystemHandle systemhandle)
+void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
- return (int) system->dispatchEvents();
+ system->dispatchEvents();
}
@@ -358,27 +358,20 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
int bounds[4], const int mouse_ungrab_xy[2])
{
GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
- GHOST_Rect bounds_rect, bounds_win;
- GHOST_TInt32 mouse_ungrab_xy_global[2];
+ GHOST_Rect bounds_rect;
+ GHOST_TInt32 mouse_xy[2];
if (bounds) {
- /* if this is X11 specific we need a function that converts */
- window->getClientBounds(bounds_win);
- window->clientToScreen(bounds[0], bounds_win.getHeight() - bounds[1], bounds_rect.m_l, bounds_rect.m_t);
- window->clientToScreen(bounds[2], bounds_win.getHeight() - bounds[3], bounds_rect.m_r, bounds_rect.m_b);
-
+ bounds_rect = GHOST_Rect(bounds[0], bounds[1], bounds[2], bounds[3]);
}
-
if (mouse_ungrab_xy) {
- if (bounds == NULL)
- window->getClientBounds(bounds_win);
- window->clientToScreen(mouse_ungrab_xy[0], bounds_win.getHeight() - mouse_ungrab_xy[1],
- mouse_ungrab_xy_global[0], mouse_ungrab_xy_global[1]);
+ mouse_xy[0] = mouse_ungrab_xy[0];
+ mouse_xy[1] = mouse_ungrab_xy[1];
}
return window->setCursorGrab(mode,
bounds ? &bounds_rect : NULL,
- mouse_ungrab_xy ? mouse_ungrab_xy_global : NULL);
+ mouse_ungrab_xy ? mouse_xy : NULL);
}
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index 92fdbfc53de..953235669a8 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -128,18 +128,9 @@ public:
private:
//void initContextCGLEW()
- /** The window containing the OpenGL view */
- NSWindow *m_window;
-
/** The openGL view */
NSOpenGLView *m_openGLView;
- const int m_contextProfileMask;
- const int m_contextMajorVersion;
- const int m_contextMinorVersion;
- const int m_contextFlags;
- const int m_contextResetNotificationStrategy;
-
/** The OpenGL drawing context */
NSOpenGLContext *m_openGLContext;
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 51895e5fa1a..e09de4be143 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -58,16 +58,9 @@ GHOST_ContextCGL::GHOST_ContextCGL(
int contextFlags,
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual, numOfAASamples),
- m_window(window),
m_openGLView(openGLView),
- m_contextProfileMask(contextProfileMask),
- m_contextMajorVersion(contextMajorVersion),
- m_contextMinorVersion(contextMinorVersion),
- m_contextFlags(contextFlags),
- m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_openGLContext(nil)
{
- assert(window != nil);
assert(openGLView != nil);
}
@@ -184,10 +177,6 @@ static void makeAttribList(
// Pixel Format Attributes for the windowed NSOpenGLContext
attribs.push_back(NSOpenGLPFADoubleBuffer);
- // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object's flushBuffer
- // needed for 'Draw Overlap' drawing method
- attribs.push_back(NSOpenGLPFABackingStore);
-
// Force software OpenGL, for debugging
/* XXX jwilkins: fixed this to work on Intel macs? useful feature for Windows and Linux too?
* Maybe a command line flag is better... */
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index 02b43abec6c..90d810b7986 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -40,6 +40,13 @@
#include <cstdio>
#include <cstring>
+/* needed for intel drivers (works w/ mesa-swrast & nvidia) */
+#define USE_GLXEW_INIT_WORKAROUND
+
+#ifdef USE_GLXEW_INIT_WORKAROUND
+static GLuint _glewStrLen(const GLubyte *s);
+static GLboolean _glewSearchExtension(const char *name, const GLubyte *start, const GLubyte *end);
+#endif
#ifdef WITH_GLEW_MX
GLXEWContext *glxewContext = NULL;
@@ -87,7 +94,7 @@ GHOST_ContextGLX::~GHOST_ContextGLX()
if (m_context != None) {
if (m_window != 0 && m_context == ::glXGetCurrentContext())
- ::glXMakeCurrent(m_display, m_window, NULL);
+ ::glXMakeCurrent(m_display, None, NULL);
if (m_context != s_sharedContext || s_sharedCount == 1) {
assert(s_sharedCount > 0);
@@ -154,10 +161,54 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
#endif
- /* needed so 'GLXEW_ARB_create_context' is valid */
- mxIgnoreNoVersion(1);
- initContextGLXEW();
- mxIgnoreNoVersion(0);
+
+
+ /* -------------------------------------------------------------------- */
+ /* Begin Inline Glew */
+
+#ifdef USE_GLXEW_INIT_WORKAROUND
+ const GLubyte *extStart = (GLubyte *)"";
+ const GLubyte *extEnd;
+ if (glXQueryExtension(m_display, NULL, NULL)) {
+ extStart = (const GLubyte *)glXGetClientString(m_display, GLX_EXTENSIONS);
+ if ((extStart == NULL) ||
+ (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB(
+ (const GLubyte *)"glXChooseFBConfig")) == NULL ||
+ (glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB(
+ (const GLubyte *)"glXCreateContextAttribsARB")) == NULL)
+ {
+ extStart = (GLubyte *)"";
+ }
+ }
+ extEnd = extStart + _glewStrLen(extStart);
+
+#undef GLXEW_ARB_create_context
+ const bool GLXEW_ARB_create_context =
+ _glewSearchExtension("GLX_ARB_create_context", extStart, extEnd);
+#undef GLXEW_ARB_create_context_profile
+ const bool GLXEW_ARB_create_context_profile =
+ _glewSearchExtension("GLX_ARB_create_context_profile", extStart, extEnd);
+#undef GLXEW_ARB_create_context_robustness
+const bool GLXEW_ARB_create_context_robustness =
+ _glewSearchExtension("GLX_ARB_create_context_robustness", extStart, extEnd);
+#ifdef WITH_GLEW_ES
+#undef GLXEW_EXT_create_context_es_profile
+ const bool GLXEW_EXT_create_context_es_profile =
+ _glewSearchExtension("GLX_EXT_create_context_es_profile", extStart, extEnd);
+#undef GLXEW_EXT_create_context_es2_profile
+ const bool GLXEW_EXT_create_context_es2_profile =
+ _glewSearchExtension("GLX_EXT_create_context_es2_profile", extStart, extEnd);
+#endif /* WITH_GLEW_ES */
+
+ /* End Inline Glew */
+ /* -------------------------------------------------------------------- */
+#else
+ /* important to initialize only glxew (_not_ glew),
+ * since this breaks w/ Mesa's `swrast`, see: T46431 */
+ glxewInit();
+#endif /* USE_GLXEW_INIT_WORKAROUND */
+
+
if (GLXEW_ARB_create_context) {
int profileBitCore = m_contextProfileMask & GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
@@ -257,6 +308,8 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
GHOST_TSuccess success;
if (m_context != NULL) {
+ const unsigned char *version;
+
if (!s_sharedContext)
s_sharedContext = m_context;
@@ -264,13 +317,26 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
glXMakeCurrent(m_display, m_window, m_context);
+ // Seems that this has to be called after MakeCurrent,
+ // which means we cannot use glX extensions until after we create a context
+ initContextGLXEW();
+
initClearGL();
::glXSwapBuffers(m_display, m_window);
/* re initialize to get the extensions properly */
initContextGLXEW();
- success = GHOST_kSuccess;
+ version = glGetString(GL_VERSION);
+
+ if (!version || version[0] < '2' || ((version[0] == '2') && (version[2] < '1'))) {
+ fprintf(stderr, "Error! Blender requires OpenGL 2.1 to run. Try updating your drivers.\n");
+ fflush(stderr);
+ /* ugly, but we get crashes unless a whole bunch of systems are patched. */
+ exit(0);
+ }
+ else
+ success = GHOST_kSuccess;
}
else {
/* freeing well clean up the context initialized above */
@@ -409,3 +475,45 @@ int GHOST_X11_GL_GetAttributes(
return i;
}
+
+
+/* excuse inlining part of glew */
+#ifdef USE_GLXEW_INIT_WORKAROUND
+static GLuint _glewStrLen(const GLubyte *s)
+{
+ GLuint i = 0;
+ if (s == NULL) return 0;
+ while (s[i] != '\0') i++;
+ return i;
+}
+
+static GLuint _glewStrCLen(const GLubyte *s, GLubyte c)
+{
+ GLuint i = 0;
+ if (s == NULL) return 0;
+ while (s[i] != '\0' && s[i] != c) i++;
+ return (s[i] == '\0' || s[i] == c) ? i : 0;
+}
+
+static GLboolean _glewStrSame(const GLubyte *a, const GLubyte *b, GLuint n)
+{
+ GLuint i = 0;
+ if (a == NULL || b == NULL)
+ return (a == NULL && b == NULL && n == 0) ? GL_TRUE : GL_FALSE;
+ while (i < n && a[i] != '\0' && b[i] != '\0' && a[i] == b[i]) i++;
+ return i == n ? GL_TRUE : GL_FALSE;
+}
+
+static GLboolean _glewSearchExtension(const char *name, const GLubyte *start, const GLubyte *end)
+{
+ const GLubyte *p;
+ GLuint len = _glewStrLen((const GLubyte *)name);
+ p = start;
+ while (p < end) {
+ GLuint n = _glewStrCLen(p, ' ');
+ if (len == n && _glewStrSame((const GLubyte *)name, p, n)) return GL_TRUE;
+ p += n + 1;
+ }
+ return GL_FALSE;
+}
+#endif /* USE_GLXEW_INIT_WORKAROUND */
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index d2a9eed95d9..cb580f60bd7 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -48,7 +48,6 @@ HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
int GHOST_ContextWGL::s_sharedCount = 0;
bool GHOST_ContextWGL::s_singleContextMode = false;
-bool GHOST_ContextWGL::s_warn_old = false;
/* Intel video-cards don't work fine with multiple contexts and
@@ -918,27 +917,27 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
reportContextString("Version", m_dummyVersion, version);
#endif
- if (!s_warn_old) {
- if ((strcmp(vendor, "Microsoft Corporation") == 0 ||
- strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1')
- {
- MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n"
- "Such systems can cause stability problems in Blender and they are unsupported.\n\n"
- "This may be caused by:\n"
- "* A missing or faulty graphics driver installation.\n"
- " Blender needs a graphics card driver to work correctly.\n"
- "* Accessing Blender through a remote connection.\n"
- "* Using Blender through a virtual machine.\n\n"
- "Disable this message in <User Preferences - Interface - Warn On Deprecated OpenGL>",
- "Blender - Can't detect 3D hardware accelerated Driver!", MB_OK | MB_ICONWARNING);
- }
- else if (version[0] == '1' && version[2] < '4') {
- MessageBox(m_hWnd, "The OpenGL version provided by your graphics driver version is too low\n"
- "Blender requires version 1.4 and may not work correctly\n\n"
- "Disable this message in <User Preferences - Interface - Warn On Deprecated OpenGL>",
- "Blender - Unsupported Graphics Driver!", MB_OK | MB_ICONWARNING);
- }
- s_warn_old = true;
+ if ((strcmp(vendor, "Microsoft Corporation") == 0 ||
+ strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1')
+ {
+ MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n"
+ "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
+ "This may be caused by:\n"
+ "* A missing or faulty graphics driver installation.\n"
+ " Blender needs a graphics card driver to work correctly.\n"
+ "* Accessing Blender through a remote connection.\n"
+ "* Using Blender through a virtual machine.\n\n"
+ "The program will now close.",
+ "Blender - Can't detect 3D hardware accelerated Driver!",
+ MB_OK | MB_ICONERROR);
+ exit(0);
+ }
+ else if (version[0] < '2' || (version[0] == '2' && version[2] < '1')) {
+ MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
+ "The program will now close.",
+ "Blender - Unsupported Graphics Driver!",
+ MB_OK | MB_ICONERROR);
+ exit(0);
}
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h
index c457ddab2f7..3b04a33b662 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.h
+++ b/intern/ghost/intern/GHOST_ContextWGL.h
@@ -118,8 +118,6 @@ public:
*/
GHOST_TSuccess getSwapInterval(int &intervalOut);
- static void unSetWarningOld(){s_warn_old = true;}
-
protected:
inline void activateWGLEW() const {
#ifdef WITH_GLEW_MX
@@ -184,7 +182,6 @@ private:
static int s_sharedCount;
static bool s_singleContextMode;
- static bool s_warn_old;
};
#endif // __GHOST_CONTEXTWGL_H__
diff --git a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
index 65d5e650251..252ea775329 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerWin32.cpp
@@ -34,6 +34,7 @@
#include "GHOST_DisplayManagerWin32.h"
#include "GHOST_Debug.h"
+#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501 // require Windows XP or newer
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/intern/ghost/intern/GHOST_EventManager.cpp b/intern/ghost/intern/GHOST_EventManager.cpp
index 7dc8b8a19bf..bc531bd515b 100644
--- a/intern/ghost/intern/GHOST_EventManager.cpp
+++ b/intern/ghost/intern/GHOST_EventManager.cpp
@@ -78,16 +78,6 @@ GHOST_TUns32 GHOST_EventManager::getNumEvents(GHOST_TEventType type)
}
-GHOST_IEvent *GHOST_EventManager::peekEvent()
-{
- GHOST_IEvent *event = NULL;
- if (m_events.empty() == false) {
- event = m_events.back();
- }
- return event;
-}
-
-
GHOST_TSuccess GHOST_EventManager::pushEvent(GHOST_IEvent *event)
{
GHOST_TSuccess success;
@@ -103,52 +93,33 @@ GHOST_TSuccess GHOST_EventManager::pushEvent(GHOST_IEvent *event)
}
-bool GHOST_EventManager::dispatchEvent(GHOST_IEvent *event)
+void GHOST_EventManager::dispatchEvent(GHOST_IEvent *event)
{
- bool handled;
- if (event) {
- handled = true;
- TConsumerVector::iterator iter;
- for (iter = m_consumers.begin(); iter != m_consumers.end(); ++iter) {
- if ((*iter)->processEvent(event)) {
- handled = false;
- }
- }
- }
- else {
- handled = false;
+ TConsumerVector::iterator iter;
+
+ for (iter = m_consumers.begin(); iter != m_consumers.end(); ++iter) {
+ (*iter)->processEvent(event);
}
- return handled;
}
-bool GHOST_EventManager::dispatchEvent()
+void GHOST_EventManager::dispatchEvent()
{
- GHOST_IEvent *event = popEvent();
- bool handled = false;
- if (event) {
- handled = dispatchEvent(event);
- delete event;
- }
- return handled;
+ GHOST_IEvent *event = m_events.back();
+ m_events.pop_back();
+ m_handled_events.push_back(event);
+
+ dispatchEvent(event);
}
-bool GHOST_EventManager::dispatchEvents()
+void GHOST_EventManager::dispatchEvents()
{
- bool handled;
- if (getNumEvents()) {
- handled = true;
- while (getNumEvents()) {
- if (!dispatchEvent()) {
- handled = false;
- }
- }
- }
- else {
- handled = false;
+ while (!m_events.empty()) {
+ dispatchEvent();
}
- return handled;
+
+ disposeEvents();
}
@@ -241,18 +212,14 @@ void GHOST_EventManager::removeTypeEvents(GHOST_TEventType type, GHOST_IWindow *
}
-GHOST_IEvent *GHOST_EventManager::popEvent()
+void GHOST_EventManager::disposeEvents()
{
- GHOST_IEvent *event = peekEvent();
- if (event) {
- m_events.pop_back();
+ while (m_handled_events.empty() == false) {
+ GHOST_ASSERT(m_handled_events[0], "invalid event");
+ delete m_handled_events[0];
+ m_handled_events.pop_front();
}
- return event;
-}
-
-void GHOST_EventManager::disposeEvents()
-{
while (m_events.empty() == false) {
GHOST_ASSERT(m_events[0], "invalid event");
delete m_events[0];
diff --git a/intern/ghost/intern/GHOST_EventManager.h b/intern/ghost/intern/GHOST_EventManager.h
index c8b5d1debe5..ae2971ea1a8 100644
--- a/intern/ghost/intern/GHOST_EventManager.h
+++ b/intern/ghost/intern/GHOST_EventManager.h
@@ -74,13 +74,6 @@ public:
GHOST_TUns32 getNumEvents(GHOST_TEventType type);
/**
- * Return the event at the top of the stack without removal.
- * Do not delete the event!
- * \return The event at the top of the stack.
- */
- GHOST_IEvent *peekEvent();
-
- /**
* Pushes an event on the stack.
* To dispatch it, call dispatchEvent() or dispatchEvents().
* Do not delete the event!
@@ -90,23 +83,20 @@ public:
/**
* Dispatches the given event directly, bypassing the event stack.
- * \return Indication as to whether any of the consumers handled the event.
*/
- bool dispatchEvent(GHOST_IEvent *event);
+ void dispatchEvent(GHOST_IEvent *event);
/**
* Dispatches the event at the back of the stack.
* The event will be removed from the stack.
- * \return Indication as to whether any of the consumers handled the event.
*/
- bool dispatchEvent();
+ void dispatchEvent();
/**
* Dispatches all the events on the stack.
* The event stack will be empty afterwards.
- * \return Indication as to whether any of the consumers handled the events.
*/
- bool dispatchEvents();
+ void dispatchEvents();
/**
* Adds a consumer to the list of event consumers.
@@ -145,12 +135,6 @@ public:
);
protected:
- /**
- * Returns the event at the top of the stack and removes it.
- * Delete the event after use!
- * \return The event at the top of the stack.
- */
- GHOST_IEvent *popEvent();
/**
* Removes all events from the stack.
@@ -162,6 +146,7 @@ protected:
/** The event stack. */
std::deque<GHOST_IEvent *> m_events;
+ std::deque<GHOST_IEvent *> m_handled_events;
/** A vector with event consumers. */
typedef std::vector<GHOST_IEventConsumer *> TConsumerVector;
diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp
index 581467fb666..6ebcb37ba06 100644
--- a/intern/ghost/intern/GHOST_ISystemPaths.cpp
+++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp
@@ -44,7 +44,7 @@
# ifdef __APPLE__
# include "GHOST_SystemPathsCocoa.h"
# else
-# include "GHOST_SystemPathsX11.h"
+# include "GHOST_SystemPathsUnix.h"
# endif
#endif
@@ -62,7 +62,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create()
# ifdef __APPLE__
m_systemPaths = new GHOST_SystemPathsCocoa();
# else
- m_systemPaths = new GHOST_SystemPathsX11();
+ m_systemPaths = new GHOST_SystemPathsUnix();
# endif
#endif
success = m_systemPaths != 0 ? GHOST_kSuccess : GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index 48a4881afb1..ba82f37bb2a 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -107,10 +107,13 @@ typedef enum {
class GHOST_NDOFManager
{
public:
- GHOST_NDOFManager(GHOST_System &);
-
+ GHOST_NDOFManager(GHOST_System&);
virtual ~GHOST_NDOFManager() {}
+ // whether multi-axis functionality is available (via the OS or driver)
+ // does not imply that a device is plugged in or being used
+ virtual bool available() = 0;
+
// each platform's device detection should call this
// use standard USB/HID identifiers
bool setDevice(unsigned short vendor_id, unsigned short product_id);
diff --git a/intern/ghost/intern/GHOST_NDOFManager3Dconnexion.c b/intern/ghost/intern/GHOST_NDOFManager3Dconnexion.c
deleted file mode 100644
index 01e301f927e..00000000000
--- a/intern/ghost/intern/GHOST_NDOFManager3Dconnexion.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s):
- * Jake Kauth on 9/12/13.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifdef WITH_INPUT_NDOF
-
-#include <ConnexionClientAPI.h>
-#include <stdio.h>
-
-#include "GHOST_NDOFManager3Dconnexion.h"
-
-/* It is to be noted that these implementations are linked in as
- * 'extern "C"' calls from GHOST_NDOFManagerCocoa.
- *
- * This is done in order to
- * preserve weak linking capability (which as of clang-3.3 and xcode5
- * breaks weak linking when there is name mangling of c++ libraries.)
- *
- * We need to have the weak linked file as pure C. Therefore we build a
- * compiled bridge from the real weak linked calls and the calls within C++
- *
- */
-
-OSErr GHOST_NDOFManager3Dconnexion_available(void)
-{
- // extern unsigned int InstallConnexionHandlers() __attribute__((weak_import));
- // Make the linker happy for the framework check (see link below for more info)
- // http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
- return InstallConnexionHandlers != 0;
- // this means that the driver is installed and dynamically linked to blender
-}
-
-OSErr GHOST_NDOFManager3Dconnexion_oldDRV()
-{
- //extern unsigned int SetConnexionClientButtonMask() __attribute__((weak_import));
- // Make the linker happy for the framework check (see link below for more info)
- // http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
- return SetConnexionClientButtonMask != 0;
- // this means that the driver has this symbol
-}
-
-UInt16 GHOST_NDOFManager3Dconnexion_RegisterConnexionClient(UInt32 signature, UInt8 *name, UInt16 mode, UInt32 mask)
-{
- return RegisterConnexionClient(signature, name, mode, mask);
-}
-
-void GHOST_NDOFManager3Dconnexion_SetConnexionClientButtonMask(UInt16 clientID, UInt32 buttonMask)
-{
- return SetConnexionClientButtonMask( clientID, buttonMask);
-}
-
-void GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(UInt16 clientID)
-{
- return UnregisterConnexionClient( clientID);
-}
-
-OSErr GHOST_NDOFManager3Dconnexion_InstallConnexionHandlers(
- ConnexionMessageHandlerProc messageHandler,
- ConnexionAddedHandlerProc addedHandler,
- ConnexionRemovedHandlerProc removedHandler)
-{
- return InstallConnexionHandlers( messageHandler, addedHandler, removedHandler);
-}
-
-void GHOST_NDOFManager3Dconnexion_CleanupConnexionHandlers(void)
-{
- return CleanupConnexionHandlers();
-}
-
-OSErr GHOST_NDOFManager3Dconnexion_ConnexionControl(UInt32 message, SInt32 param, SInt32 *result)
-{
- return ConnexionControl( message, param, result);
-}
-
-#endif // WITH_INPUT_NDOF
diff --git a/intern/ghost/intern/GHOST_NDOFManager3Dconnexion.h b/intern/ghost/intern/GHOST_NDOFManager3Dconnexion.h
deleted file mode 100644
index 9a84c14b4ac..00000000000
--- a/intern/ghost/intern/GHOST_NDOFManager3Dconnexion.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s):
- * Jake Kauth on 9/12/13.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __GHOST_NDOFMANAGER3DCONNEXION_H__
-#define __GHOST_NDOFMANAGER3DCONNEXION_H__
-
-#ifdef WITH_INPUT_NDOF
-#include <ConnexionClientAPI.h>
-
-
-OSErr GHOST_NDOFManager3Dconnexion_available(void);
-OSErr GHOST_NDOFManager3Dconnexion_oldDRV(void);
-OSErr GHOST_NDOFManager3Dconnexion_InstallConnexionHandlers(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler);
-void GHOST_NDOFManager3Dconnexion_CleanupConnexionHandlers(void);
-UInt16 GHOST_NDOFManager3Dconnexion_RegisterConnexionClient(UInt32 signature, UInt8 *name, UInt16 mode, UInt32 mask);
-void GHOST_NDOFManager3Dconnexion_SetConnexionClientButtonMask(UInt16 clientID, UInt32 buttonMask);
-void GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(UInt16 clientID);
-OSErr GHOST_NDOFManager3Dconnexion_ConnexionControl(UInt32 message, SInt32 param, SInt32 *result);
-
-extern OSErr InstallConnexionHandlers(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler) __attribute__((weak_import));
-extern void CleanupConnexionHandlers(void) __attribute__((weak_import));
-extern UInt16 RegisterConnexionClient(UInt32 signature, UInt8 *name, UInt16 mode, UInt32 mask) __attribute__((weak_import));
-extern void SetConnexionClientButtonMask(UInt16 clientID, UInt32 buttonMask) __attribute__((weak_import));
-extern void UnregisterConnexionClient(UInt16 clientID) __attribute__((weak_import));
-extern OSErr ConnexionControl(UInt32 message, SInt32 param, SInt32 *result) __attribute__((weak_import));
-
-
-#endif // WITH_INPUT_NDOF
-
-#endif // #include guard
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
index 2a1b492dd96..464ba48145e 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
@@ -26,22 +26,7 @@
#ifdef WITH_INPUT_NDOF
-
-extern "C" {
-#include <ConnexionClientAPI.h>
-#include <stdio.h>
-}
-
-
#include "GHOST_NDOFManager.h"
-extern "C" OSErr GHOST_NDOFManager3Dconnexion_available(void);
-extern "C" OSErr GHOST_NDOFManager3Dconnexion_oldDRV(void);
-extern "C" OSErr GHOST_NDOFManager3Dconnexion_InstallConnexionHandlers(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler);
-extern "C" void GHOST_NDOFManager3Dconnexion_CleanupConnexionHandlers(void);
-extern "C" UInt16 GHOST_NDOFManager3Dconnexion_RegisterConnexionClient(UInt32 signature, UInt8 *name, UInt16 mode, UInt32 mask);
-extern "C" void GHOST_NDOFManager3Dconnexion_SetConnexionClientButtonMask(UInt16 clientID, UInt32 buttonMask);
-extern "C" void GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(UInt16 clientID);
-extern "C" OSErr GHOST_NDOFManager3Dconnexion_ConnexionControl(UInt32 message, SInt32 param, SInt32 *result);
// Event capture is handled within the NDOF manager on Macintosh,
// so there's no need for SystemCocoa to look for them.
@@ -50,14 +35,9 @@ class GHOST_NDOFManagerCocoa : public GHOST_NDOFManager
{
public:
GHOST_NDOFManagerCocoa(GHOST_System&);
-
~GHOST_NDOFManagerCocoa();
- // whether multi-axis functionality is available (via the OS or driver)
- // does not imply that a device is plugged in or being used
-
-private:
- unsigned short m_clientID;
+ bool available();
};
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
index 6eedaafb2d1..6fee39dcb82 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
@@ -23,59 +23,178 @@
#ifdef WITH_INPUT_NDOF
+#define DEBUG_NDOF_DRIVER false
+
#include "GHOST_NDOFManagerCocoa.h"
-#include "GHOST_NDOFManager3Dconnexion.h"
#include "GHOST_SystemCocoa.h"
-extern "C" {
- #include <ConnexionClientAPI.h>
- #include <stdio.h>
-}
+#include <stdint.h>
+#include <dlfcn.h>
+#if DEBUG_NDOF_DRIVER
+ #include <cstdio>
+#endif
-// static functions need to talk to these objects:
+// static callback functions need to talk to these objects:
static GHOST_SystemCocoa* ghost_system = NULL;
static GHOST_NDOFManager* ndof_manager = NULL;
-// 3Dconnexion drivers before 10.x are "old"
-// not all buttons will work
-static bool has_old_driver = true;
+static uint16_t clientID = 0;
+
+static bool driver_loaded = false;
+static bool has_old_driver = false; // 3Dconnexion drivers before 10 beta 4 are "old", not all buttons will work
+static bool has_new_driver = false; // drivers >= 10.2.2 are "new", and can process events on a separate thread
+
+// replicate just enough of the 3Dx API for our uses, not everything the driver provides
+
+#define kConnexionClientModeTakeOver 1
+#define kConnexionMaskAll 0x3fff
+#define kConnexionMaskAllButtons 0xffffffff
+#define kConnexionCmdHandleButtons 2
+#define kConnexionCmdHandleAxis 3
+#define kConnexionCmdAppSpecific 10
+#define kConnexionMsgDeviceState '3dSR'
+#define kConnexionCtlGetDeviceID '3did'
+
+#pragma pack(push,2) // just this struct
+struct ConnexionDeviceState {
+ uint16_t version;
+ uint16_t client;
+ uint16_t command;
+ int16_t param;
+ int32_t value;
+ uint64_t time;
+ uint8_t report[8];
+ uint16_t buttons8; // obsolete! (pre-10.x drivers)
+ int16_t axis[6]; // tx, ty, tz, rx, ry, rz
+ uint16_t address;
+ uint32_t buttons;
+};
+#pragma pack(pop)
+
+// callback functions:
+typedef void (*AddedHandler)(uint32_t);
+typedef void (*RemovedHandler)(uint32_t);
+typedef void (*MessageHandler)(uint32_t, uint32_t msg_type, void* msg_arg);
-static void NDOF_DeviceAdded(io_connect_t connection)
+// driver functions:
+typedef int16_t (*SetConnexionHandlers_ptr)(MessageHandler, AddedHandler, RemovedHandler, bool);
+typedef int16_t (*InstallConnexionHandlers_ptr)(MessageHandler, AddedHandler, RemovedHandler);
+typedef void (*CleanupConnexionHandlers_ptr)();
+typedef uint16_t (*RegisterConnexionClient_ptr)(uint32_t signature, const char* name, uint16_t mode, uint32_t mask);
+typedef void (*SetConnexionClientButtonMask_ptr)(uint16_t clientID, uint32_t buttonMask);
+typedef void (*UnregisterConnexionClient_ptr)(uint16_t clientID);
+typedef int16_t (*ConnexionClientControl_ptr)(uint16_t clientID, uint32_t message, int32_t param, int32_t* result);
+
+#define DECLARE_FUNC(name) name##_ptr name = NULL
+
+DECLARE_FUNC(SetConnexionHandlers);
+DECLARE_FUNC(InstallConnexionHandlers);
+DECLARE_FUNC(CleanupConnexionHandlers);
+DECLARE_FUNC(RegisterConnexionClient);
+DECLARE_FUNC(SetConnexionClientButtonMask);
+DECLARE_FUNC(UnregisterConnexionClient);
+DECLARE_FUNC(ConnexionClientControl);
+
+
+static void* load_func(void* module, const char* func_name)
{
- printf("ndof: device added\n"); // change these: printf --> informational reports
+ void* func = dlsym(module, func_name);
-#if 0 // device preferences will be useful some day
- ConnexionDevicePrefs p;
- ConnexionGetCurrentDevicePrefs(kDevID_AnyDevice, &p);
+#if DEBUG_NDOF_DRIVER
+ if (func) {
+ printf("'%s' loaded :D\n", func_name);
+ }
+ else {
+ printf("<!> %s\n", dlerror());
+ }
+#endif
+
+ return func;
+}
+
+#define LOAD_FUNC(name) name = (name##_ptr) load_func(module, #name)
+
+static bool load_driver_functions()
+{
+ if (driver_loaded) {
+ return true;
+ }
+
+ void* module = dlopen("3DconnexionClient.framework/3DconnexionClient", RTLD_LAZY | RTLD_LOCAL);
+
+ if (module) {
+ LOAD_FUNC(SetConnexionHandlers);
+
+ if (SetConnexionHandlers != NULL) {
+ driver_loaded = true;
+ has_new_driver = true;
+ }
+ else {
+ LOAD_FUNC(InstallConnexionHandlers);
+
+ driver_loaded = (InstallConnexionHandlers != NULL);
+ }
+
+ if (driver_loaded) {
+ LOAD_FUNC(CleanupConnexionHandlers);
+ LOAD_FUNC(RegisterConnexionClient);
+ LOAD_FUNC(SetConnexionClientButtonMask);
+ LOAD_FUNC(UnregisterConnexionClient);
+ LOAD_FUNC(ConnexionClientControl);
+
+ has_old_driver = (SetConnexionClientButtonMask == NULL);
+ }
+
+ dlclose(module); // functions will remain loaded
+ }
+#if DEBUG_NDOF_DRIVER
+ else {
+ printf("<!> %s\n", dlerror());
+ }
+
+ printf("loaded: %s\n", driver_loaded ? "YES" : "NO");
+ printf("old: %s\n", has_old_driver ? "YES" : "NO");
+ printf("new: %s\n", has_new_driver ? "YES" : "NO");
+#endif
+
+ return driver_loaded;
+ }
+
+
+static void DeviceAdded(uint32_t unused)
+{
+#if DEBUG_NDOF_DRIVER
+ printf("ndof: device added\n");
#endif
// determine exactly which device is plugged in
- SInt32 result = 0;
- GHOST_NDOFManager3Dconnexion_ConnexionControl(kConnexionCtlGetDeviceID, 0, &result);
- unsigned short vendorID = result >> 16;
- unsigned short productID = result & 0xffff;
+ int32_t result;
+ ConnexionClientControl(clientID, kConnexionCtlGetDeviceID, 0, &result);
+ int16_t vendorID = result >> 16;
+ int16_t productID = result & 0xffff;
ndof_manager->setDevice(vendorID, productID);
}
-static void NDOF_DeviceRemoved(io_connect_t connection)
+static void DeviceRemoved(uint32_t unused)
{
+#if DEBUG_NDOF_DRIVER
printf("ndof: device removed\n");
+#endif
}
-static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, void* messageArgument)
+static void DeviceEvent(uint32_t unused, uint32_t msg_type, void* msg_arg)
{
- switch (messageType)
- {
- case kConnexionMsgDeviceState:
- {
- ConnexionDeviceState* s = (ConnexionDeviceState*)messageArgument;
+ if (msg_type == kConnexionMsgDeviceState) {
+ ConnexionDeviceState* s = (ConnexionDeviceState*)msg_arg;
+ // device state is broadcast to all clients; only react if sent to us
+ if (s->client == clientID) {
+ // TODO: is s->time compatible with GHOST timestamps? if so use that instead.
GHOST_TUns64 now = ghost_system->getMilliSeconds();
- switch (s->command)
- {
+ switch (s->command) {
case kConnexionCmdHandleAxis:
{
// convert to blender view coordinates
@@ -91,82 +210,71 @@ static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, voi
case kConnexionCmdHandleButtons:
{
int button_bits = has_old_driver ? s->buttons8 : s->buttons;
+ printf("button bits: 0x%08x\n", button_bits);
ndof_manager->updateButtons(button_bits, now);
ghost_system->notifyExternalEventProcessed();
break;
}
+#if DEBUG_NDOF_DRIVER
case kConnexionCmdAppSpecific:
printf("ndof: app-specific command, param = %hd, value = %d\n", s->param, s->value);
break;
default:
printf("ndof: mystery device command %d\n", s->command);
+#endif
}
- break;
}
- case kConnexionMsgPrefsChanged:
- // printf("ndof: prefs changed\n"); // this includes app switches
- // TODO: look through updated prefs for things blender cares about
- break;
- case kConnexionMsgCalibrateDevice:
- printf("ndof: calibrate\n"); // but what should blender do?
- break;
- case kConnexionMsgDoMapping:
- // printf("ndof: driver did something\n");
- // sent when the driver itself consumes an NDOF event
- // and performs whatever action is set in user prefs
- // 3Dx header file says to ignore these
- break;
- default:
- printf("ndof: mystery event %d\n", messageType);
}
}
GHOST_NDOFManagerCocoa::GHOST_NDOFManagerCocoa(GHOST_System& sys)
: GHOST_NDOFManager(sys)
{
- if (GHOST_NDOFManager3Dconnexion_available())
- {
+ if (load_driver_functions()) {
// give static functions something to talk to:
ghost_system = dynamic_cast<GHOST_SystemCocoa*>(&sys);
ndof_manager = this;
- OSErr error = GHOST_NDOFManager3Dconnexion_InstallConnexionHandlers(NDOF_DeviceEvent, NDOF_DeviceAdded, NDOF_DeviceRemoved);
+ uint16_t error;
+ if (has_new_driver) {
+ const bool separate_thread = false; // TODO: rework Mac event handler to allow this
+ error = SetConnexionHandlers(DeviceEvent, DeviceAdded, DeviceRemoved, separate_thread);
+ }
+ else {
+ error = InstallConnexionHandlers(DeviceEvent, DeviceAdded, DeviceRemoved);
+ }
+
if (error) {
- printf("ndof: error %d while installing handlers\n", error);
+#if DEBUG_NDOF_DRIVER
+ printf("ndof: error %d while setting up handlers\n", error);
+#endif
return;
}
// Pascal string *and* a four-letter constant. How old-skool.
- m_clientID = GHOST_NDOFManager3Dconnexion_RegisterConnexionClient('blnd', (UInt8*) "\007blender",
- kConnexionClientModeTakeOver, kConnexionMaskAll);
-
- // printf("ndof: client id = %d\n", m_clientID);
+ clientID = RegisterConnexionClient('blnd', "\007blender", kConnexionClientModeTakeOver, kConnexionMaskAll);
- if (GHOST_NDOFManager3Dconnexion_oldDRV()) {
- has_old_driver = false;
- GHOST_NDOFManager3Dconnexion_SetConnexionClientButtonMask(m_clientID, kConnexionMaskAllButtons);
- }
- else {
- printf("ndof: old 3Dx driver installed, some buttons may not work\n");
+ if (!has_old_driver) {
+ SetConnexionClientButtonMask(clientID, kConnexionMaskAllButtons);
}
}
- else {
- printf("ndof: 3Dx driver not found\n");
- // This isn't a hard error, just means the user doesn't have a 3D mouse.
- }
}
GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
{
- if (GHOST_NDOFManager3Dconnexion_available())
- {
- GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(m_clientID);
- GHOST_NDOFManager3Dconnexion_UnregisterConnexionClient(m_clientID);
+ if (driver_loaded) {
+ UnregisterConnexionClient(clientID);
+ CleanupConnexionHandlers();
- GHOST_NDOFManager3Dconnexion_CleanupConnexionHandlers();
ghost_system = NULL;
ndof_manager = NULL;
}
}
+
+bool GHOST_NDOFManagerCocoa::available()
+{
+ return driver_loaded;
+}
+
#endif // WITH_INPUT_NDOF
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
new file mode 100644
index 00000000000..df516357c9e
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
@@ -0,0 +1,146 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_INPUT_NDOF
+
+#include "GHOST_NDOFManagerUnix.h"
+#include "GHOST_System.h"
+
+#include <spnav.h>
+#include <stdio.h>
+
+
+GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System& sys)
+ : GHOST_NDOFManager(sys),
+ m_available(false)
+{
+ if (spnav_open() != -1) {
+ m_available = true;
+
+ /* determine exactly which device (if any) is plugged in */
+
+#define MAX_LINE_LENGTH 100
+
+ /* look for USB devices with Logitech or 3Dconnexion's vendor ID */
+ FILE *command_output = popen("lsusb | grep '046d:\\|256f:'", "r");
+ if (command_output) {
+ char line[MAX_LINE_LENGTH] = {0};
+ while (fgets(line, MAX_LINE_LENGTH, command_output)) {
+ unsigned short vendor_id = 0, product_id = 0;
+ if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
+ if (setDevice(vendor_id, product_id)) {
+ break; /* stop looking once the first 3D mouse is found */
+ }
+ }
+ pclose(command_output);
+ }
+ }
+ else {
+#ifdef DEBUG
+ /* annoying for official builds, just adds noise and most people don't own these */
+ puts("ndof: spacenavd not found");
+ /* This isn't a hard error, just means the user doesn't have a 3D mouse. */
+#endif
+ }
+}
+
+GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix()
+{
+ if (m_available)
+ spnav_close();
+}
+
+bool GHOST_NDOFManagerUnix::available()
+{
+ return m_available;
+}
+
+/*
+ * Workaround for a problem where we don't enter the 'GHOST_kFinished' state,
+ * this causes any proceeding event to have a very high 'dt' (time delta),
+ * many seconds for eg, causing the view to jump.
+ *
+ * this workaround expects continuous events, if we miss a motion event,
+ * immediately send a dummy event with no motion to ensure the finished state is reached.
+ */
+#define USE_FINISH_GLITCH_WORKAROUND
+/* TODO: make this available on all platforms */
+
+#ifdef USE_FINISH_GLITCH_WORKAROUND
+static bool motion_test_prev = false;
+#endif
+
+bool GHOST_NDOFManagerUnix::processEvents()
+{
+ bool anyProcessed = false;
+
+ if (m_available) {
+ spnav_event e;
+
+#ifdef USE_FINISH_GLITCH_WORKAROUND
+ bool motion_test = false;
+#endif
+
+ while (spnav_poll_event(&e)) {
+ switch (e.type) {
+ case SPNAV_EVENT_MOTION:
+ {
+ /* convert to blender view coords */
+ GHOST_TUns64 now = m_system.getMilliSeconds();
+ const short t[3] = {(short)e.motion.x, (short)e.motion.y, (short)-e.motion.z};
+ const short r[3] = {(short)-e.motion.rx, (short)-e.motion.ry, (short)e.motion.rz};
+
+ updateTranslation(t, now);
+ updateRotation(r, now);
+#ifdef USE_FINISH_GLITCH_WORKAROUND
+ motion_test = true;
+#endif
+ break;
+ }
+ case SPNAV_EVENT_BUTTON:
+ GHOST_TUns64 now = m_system.getMilliSeconds();
+ updateButton(e.button.bnum, e.button.press, now);
+ break;
+ }
+ anyProcessed = true;
+ }
+
+#ifdef USE_FINISH_GLITCH_WORKAROUND
+ if (motion_test_prev == true && motion_test == false) {
+ GHOST_TUns64 now = m_system.getMilliSeconds();
+ const short v[3] = {0, 0, 0};
+
+ updateTranslation(v, now);
+ updateRotation(v, now);
+
+ anyProcessed = true;
+ }
+ motion_test_prev = motion_test;
+#endif
+
+ }
+
+ return anyProcessed;
+}
+
+#endif /* WITH_INPUT_NDOF */
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.h b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
new file mode 100644
index 00000000000..278a8cb6fe0
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.h
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GHOST_NDOFMANAGERUNIX_H__
+#define __GHOST_NDOFMANAGERUNIX_H__
+
+#ifdef WITH_INPUT_NDOF
+
+#include "GHOST_NDOFManager.h"
+
+/* Event capture is handled within the NDOF manager on Linux,
+ * so there's no need for SystemX11 to look for them. */
+
+class GHOST_NDOFManagerUnix : public GHOST_NDOFManager
+{
+public:
+ GHOST_NDOFManagerUnix(GHOST_System&);
+ ~GHOST_NDOFManagerUnix();
+ bool available();
+ bool processEvents();
+
+private:
+ bool m_available;
+};
+
+#endif /* WITH_INPUT_NDOF */
+#endif /* __GHOST_NDOFMANAGERUNIX_H__ */
diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp b/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
deleted file mode 100644
index 753321be58e..00000000000
--- a/intern/ghost/intern/GHOST_NDOFManagerX11.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s):
- * Mike Erwin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifdef WITH_INPUT_NDOF
-
-#include "GHOST_NDOFManagerX11.h"
-#include "GHOST_SystemX11.h"
-#include <spnav.h>
-#include <stdio.h>
-
-
-GHOST_NDOFManagerX11::GHOST_NDOFManagerX11(GHOST_System& sys)
- : GHOST_NDOFManager(sys),
- m_available(false)
-{
- if (spnav_open() != -1) {
- m_available = true;
-
- /* determine exactly which device (if any) is plugged in */
-
-#define MAX_LINE_LENGTH 100
-
- /* look for USB devices with Logitech or 3Dconnexion's vendor ID */
- FILE *command_output = popen("lsusb | grep '046d:\\|256f:'", "r");
- if (command_output) {
- char line[MAX_LINE_LENGTH] = {0};
- while (fgets(line, MAX_LINE_LENGTH, command_output)) {
- unsigned short vendor_id = 0, product_id = 0;
- if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
- if (setDevice(vendor_id, product_id)) {
- break; /* stop looking once the first 3D mouse is found */
- }
- }
- pclose(command_output);
- }
- }
- else {
-#ifdef DEBUG
- /* annoying for official builds, just adds noise and most people don't own these */
- puts("ndof: spacenavd not found");
- /* This isn't a hard error, just means the user doesn't have a 3D mouse. */
-#endif
- }
-}
-
-GHOST_NDOFManagerX11::~GHOST_NDOFManagerX11()
-{
- if (m_available)
- spnav_close();
-}
-
-bool GHOST_NDOFManagerX11::available()
-{
- return m_available;
-}
-
-/*
- * Workaround for a problem where we don't enter the 'GHOST_kFinished' state,
- * this causes any proceeding event to have a very high 'dt' (time delta),
- * many seconds for eg, causing the view to jump.
- *
- * this workaround expects continuous events, if we miss a motion event,
- * immediately send a dummy event with no motion to ensure the finished state is reached.
- */
-#define USE_FINISH_GLITCH_WORKAROUND
-/* TODO: make this available on all platforms */
-
-#ifdef USE_FINISH_GLITCH_WORKAROUND
-static bool motion_test_prev = false;
-#endif
-
-bool GHOST_NDOFManagerX11::processEvents()
-{
- bool anyProcessed = false;
-
- if (m_available) {
- spnav_event e;
-
-#ifdef USE_FINISH_GLITCH_WORKAROUND
- bool motion_test = false;
-#endif
-
- while (spnav_poll_event(&e)) {
- switch (e.type) {
- case SPNAV_EVENT_MOTION:
- {
- /* convert to blender view coords */
- GHOST_TUns64 now = m_system.getMilliSeconds();
- const short t[3] = {(short)e.motion.x, (short)e.motion.y, (short)-e.motion.z};
- const short r[3] = {(short)-e.motion.rx, (short)-e.motion.ry, (short)e.motion.rz};
-
- updateTranslation(t, now);
- updateRotation(r, now);
-#ifdef USE_FINISH_GLITCH_WORKAROUND
- motion_test = true;
-#endif
- break;
- }
- case SPNAV_EVENT_BUTTON:
- GHOST_TUns64 now = m_system.getMilliSeconds();
- updateButton(e.button.bnum, e.button.press, now);
- break;
- }
- anyProcessed = true;
- }
-
-#ifdef USE_FINISH_GLITCH_WORKAROUND
- if (motion_test_prev == true && motion_test == false) {
- GHOST_TUns64 now = m_system.getMilliSeconds();
- const short v[3] = {0, 0, 0};
-
- updateTranslation(v, now);
- updateRotation(v, now);
-
- anyProcessed = true;
- }
- motion_test_prev = motion_test;
-#endif
-
- }
-
- return anyProcessed;
-}
-
-#endif /* WITH_INPUT_NDOF */
diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.h b/intern/ghost/intern/GHOST_NDOFManagerX11.h
deleted file mode 100644
index 4629baeb0de..00000000000
--- a/intern/ghost/intern/GHOST_NDOFManagerX11.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s):
- * Mike Erwin
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __GHOST_NDOFMANAGERX11_H__
-#define __GHOST_NDOFMANAGERX11_H__
-
-#ifdef WITH_INPUT_NDOF
-
-#include "GHOST_NDOFManager.h"
-
-/* Event capture is handled within the NDOF manager on Linux,
- * so there's no need for SystemX11 to look for them. */
-
-class GHOST_NDOFManagerX11 : public GHOST_NDOFManager
-{
-public:
- GHOST_NDOFManagerX11(GHOST_System&);
- ~GHOST_NDOFManagerX11();
- bool available();
- bool processEvents();
-
-private:
- bool m_available;
-};
-
-#endif /* WITH_INPUT_NDOF */
-#endif /* #include guard */
-
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 1698d2f0f31..0f5c822f4b6 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -214,23 +214,20 @@ bool GHOST_System::getFullScreen(void)
}
-bool GHOST_System::dispatchEvents()
+void GHOST_System::dispatchEvents()
{
- bool handled = false;
-
#ifdef WITH_INPUT_NDOF
// NDOF Motion event is sent only once per dispatch, so do it now:
if (m_ndofManager) {
- handled |= m_ndofManager->sendMotionEvent();
+ m_ndofManager->sendMotionEvent();
}
#endif
if (m_eventManager) {
- handled |= m_eventManager->dispatchEvents();
+ m_eventManager->dispatchEvents();
}
m_timerManager->fireTimers(getMilliSeconds());
- return handled;
}
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 9dcba11527c..c4951adb4fd 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -190,9 +190,8 @@ public:
/**
* Dispatches all the events on the stack.
* The event stack will be empty afterwards.
- * \return Indication as to whether any of the consumers handled the events.
*/
- bool dispatchEvents();
+ void dispatchEvents();
/**
* Adds the given event consumer to our list.
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 3d6b40ee541..b142c2f7194 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -297,9 +297,10 @@ protected:
*/
GHOST_TInt32 m_cursorDelta_x, m_cursorDelta_y;
- /** Multitouch trackpad availability */
- bool m_hasMultiTouchTrackpad;
-
+ /** Temporarily ignore momentum scroll events */
+ bool m_ignoreMomentumScroll;
+ /** Is the scroll wheel event generated by a multitouch trackpad or mouse? */
+ bool m_multiTouchScroll;
};
#endif // __GHOST_SYSTEMCOCOA_H__
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index b9686e5af9b..4db945d31f7 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -50,9 +50,9 @@
#include "GHOST_TimerTask.h"
#include "GHOST_WindowManager.h"
#include "GHOST_WindowCocoa.h"
+
#ifdef WITH_INPUT_NDOF
-#include "GHOST_NDOFManagerCocoa.h"
-#include "GHOST_NDOFManager3Dconnexion.h"
+ #include "GHOST_NDOFManagerCocoa.h"
#endif
#include "AssertMacros.h"
@@ -284,7 +284,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
* CocoaAppDelegate
* ObjC object to capture applicationShouldTerminate, and send quit event
**/
-@interface CocoaAppDelegate : NSObject {
+@interface CocoaAppDelegate : NSObject <NSFileManagerDelegate> {
GHOST_SystemCocoa *systemCocoa;
}
- (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
@@ -370,12 +370,12 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
rstring = (char*)malloc( len );
sysctl( mib, 2, rstring, &len, NULL, 0 );
- m_hasMultiTouchTrackpad = false;
-
free( rstring );
rstring = NULL;
m_ignoreWindowSizedMessages = false;
+ m_ignoreMomentumScroll = false;
+ m_multiTouchScroll = false;
}
GHOST_SystemCocoa::~GHOST_SystemCocoa()
@@ -443,10 +443,8 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
[windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 // make it build with 10.6 deployment target, but as it is not available in 10.6, it will get weaklinked
menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f" ];
[menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
-#endif
menuItem = [windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
[menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
@@ -1223,10 +1221,10 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
NSEvent *event = (NSEvent *)eventPtr;
switch ([event subtype]) {
- case NX_SUBTYPE_TABLET_POINT:
+ case NSTabletPointEventSubtype:
handleTabletEvent(eventPtr, NSTabletPoint);
return true;
- case NX_SUBTYPE_TABLET_PROXIMITY:
+ case NSTabletProximityEventSubtype:
handleTabletEvent(eventPtr, NSTabletProximity);
return true;
default:
@@ -1317,6 +1315,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
GHOST_TInt32 x_warp, y_warp, x_accum, y_accum, x, y;
window->getCursorGrabInitPos(x_warp, y_warp);
+ window->screenToClientIntern(x_warp, y_warp, x_warp, y_warp);
window->getCursorGrabAccum(x_accum, y_accum);
x_accum += [event deltaX];
@@ -1368,6 +1367,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
//Post event
window->getCursorGrabInitPos(x_cur, y_cur);
+ window->screenToClientIntern(x_cur, y_cur, x_cur, y_cur);
window->clientToScreenIntern(x_cur + x_accum, y_cur + y_accum, x, y);
pushEvent(new GHOST_EventCursor([event timestamp] * 1000, GHOST_kEventCursorMove, window, x, y));
break;
@@ -1388,25 +1388,39 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
}
}
break;
-
- /* these events only happen on swiping trackpads or tablets */
- /* warning: using tablet + trackpad at same time frustrates this static variable */
- case NSEventTypeBeginGesture:
- m_hasMultiTouchTrackpad = 1;
- break;
- case NSEventTypeEndGesture:
- m_hasMultiTouchTrackpad = 0;
- break;
-
+
case NSScrollWheel:
{
- int *momentum = NULL;
+ NSEventPhase momentumPhase = NSEventPhaseNone;
+ NSEventPhase phase = NSEventPhaseNone;
if ([event respondsToSelector:@selector(momentumPhase)])
- momentum = (int *)[event momentumPhase];
+ momentumPhase = [event momentumPhase];
+ if ([event respondsToSelector:@selector(phase)])
+ phase = [event phase];
+
+ /* when pressing a key while momentum scrolling continues after
+ * lifting fingers off the trackpad, the action can unexpectedly
+ * change from e.g. scrolling to zooming. this works around the
+ * issue by ignoring momentum scroll after a key press */
+ if (momentumPhase) {
+ if (m_ignoreMomentumScroll)
+ break;
+ }
+ else {
+ m_ignoreMomentumScroll = false;
+ }
+
+ /* we assume phases are only set for gestures from trackpad or magic
+ * mouse events. note that using tablet at the same time may not work
+ * since this is a static variable */
+ if (phase == NSEventPhaseBegan)
+ m_multiTouchScroll = true;
+ else if (phase == NSEventPhaseEnded)
+ m_multiTouchScroll = false;
/* standard scrollwheel case, if no swiping happened, and no momentum (kinetic scroll) works */
- if (!m_hasMultiTouchTrackpad && momentum == NULL) {
+ if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) {
GHOST_TInt32 delta;
double deltaF = [event deltaY];
@@ -1422,16 +1436,14 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
GHOST_TInt32 x, y;
double dx;
double dy;
-
+
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
- int phase = [event phase];
-
/* with 10.7 nice scrolling deltas are supported */
dx = [event scrollingDeltaX];
dy = [event scrollingDeltaY];
/* however, wacom tablet (intuos5) needs old deltas, it then has momentum and phase at zero */
- if (phase == 0 && momentum==NULL) {
+ if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
dx = [event deltaX];
dy = [event deltaY];
}
@@ -1536,11 +1548,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
for (int x = 0; x < [convertedCharacters length]; x++) {
utf8_buf[x] = ((char*)[convertedCharacters bytes])[x];
}
-
- /* ascii is a subset of unicode */
- if ([convertedCharacters length] == 1) {
- ascii = utf8_buf[0];
- }
}
/* arrow keys should not have utf8 */
@@ -1558,6 +1565,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
break; //Cmd-Q is directly handled by Cocoa
+ /* ascii is a subset of unicode */
+ if (utf8_buf[0] && !utf8_buf[1]) {
+ ascii = utf8_buf[0];
+ }
+
if ([event type] == NSKeyDown) {
pushEvent( new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyDown, window, keyCode, ascii, utf8_buf) );
//printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii, utf8_buf);
@@ -1566,6 +1578,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
pushEvent( new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL) );
//printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",[event keyCode],[charsIgnoringModifiers length]>0?[charsIgnoringModifiers characterAtIndex:0]:' ',keyCode,ascii,ascii, utf8_buf);
}
+ m_ignoreMomentumScroll = true;
break;
case NSFlagsChanged:
@@ -1585,6 +1598,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
}
m_modifierMask = modifiers;
+ m_ignoreMomentumScroll = true;
break;
default:
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
new file mode 100644
index 00000000000..8738b8dd0fe
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
@@ -0,0 +1,127 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/intern/GHOST_SystemPathsUnix.cpp
+ * \ingroup GHOST
+ */
+
+#include "GHOST_SystemPathsUnix.h"
+
+#include "GHOST_Debug.h"
+
+// For timing
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <stdio.h> /* for fprintf only */
+#include <cstdlib> /* for exit */
+
+#include <pwd.h> /* for get home without use getenv() */
+#include <string>
+
+using std::string;
+
+#ifdef PREFIX
+static const char *static_path = PREFIX "/share";
+#else
+static const char *static_path = NULL;
+#endif
+
+GHOST_SystemPathsUnix::GHOST_SystemPathsUnix()
+{
+}
+
+GHOST_SystemPathsUnix::~GHOST_SystemPathsUnix()
+{
+}
+
+const GHOST_TUns8 *GHOST_SystemPathsUnix::getSystemDir(int, const char *versionstr) const
+{
+ /* no prefix assumes a portable build which only uses bundled scripts */
+ if (static_path) {
+ static string system_path = string(static_path) + "/blender/" + versionstr;
+ return (GHOST_TUns8 *)system_path.c_str();
+ }
+
+ return NULL;
+}
+
+const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserDir(int version, const char *versionstr) const
+{
+ static string user_path = "";
+ static int last_version = 0;
+
+ /* in blender 2.64, we migrate to XDG. to ensure the copy previous settings
+ * operator works we give a different path depending on the requested version */
+ if (version < 264) {
+ if (user_path.empty() || last_version != version) {
+ const char *home = getenv("HOME");
+
+ last_version = version;
+
+ if (home) {
+ user_path = string(home) + "/.blender/" + versionstr;
+ }
+ else {
+ return NULL;
+ }
+ }
+ return (GHOST_TUns8 *)user_path.c_str();
+ }
+ else {
+ if (user_path.empty() || last_version != version) {
+ const char *home = getenv("XDG_CONFIG_HOME");
+
+ last_version = version;
+
+ if (home) {
+ user_path = string(home) + "/blender/" + versionstr;
+ }
+ else {
+ home = getenv("HOME");
+
+ if (home == NULL)
+ home = getpwuid(getuid())->pw_dir;
+
+ user_path = string(home) + "/.config/blender/" + versionstr;
+ }
+ }
+
+ return (const GHOST_TUns8 *)user_path.c_str();
+ }
+}
+
+const GHOST_TUns8 *GHOST_SystemPathsUnix::getBinaryDir() const
+{
+ return NULL;
+}
+
+void GHOST_SystemPathsUnix::addToSystemRecentFiles(const char * /*filename*/) const
+{
+ /* XXXXX TODO: Implementation for X11 if possible */
+
+}
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.h b/intern/ghost/intern/GHOST_SystemPathsUnix.h
new file mode 100644
index 00000000000..1502160c8d6
--- /dev/null
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.h
@@ -0,0 +1,79 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ghost/intern/GHOST_SystemPathsUnix.h
+ * \ingroup GHOST
+ */
+
+
+#ifndef __GHOST_SYSTEMPATHSUNIX_H__
+#define __GHOST_SYSTEMPATHSUNIX_H__
+
+#include "GHOST_SystemPaths.h"
+#include "../GHOST_Types.h"
+
+
+class GHOST_SystemPathsUnix : public GHOST_SystemPaths {
+public:
+
+ /**
+ * Constructor
+ * this class should only be instanciated by GHOST_ISystem.
+ */
+ GHOST_SystemPathsUnix();
+
+ /**
+ * Destructor.
+ */
+ ~GHOST_SystemPathsUnix();
+
+ /**
+ * Determine the base dir in which shared resources are located. It will first try to use
+ * "unpack and run" path, then look for properly installed path, including versioning.
+ * \return Unsigned char string pointing to system dir (eg `/usr/share/blender/`).
+ */
+ const GHOST_TUns8 *getSystemDir(int version, const char *versionstr) const;
+
+ /**
+ * Determine the base dir in which user configuration is stored, including versioning.
+ * If needed, it will create the base directory.
+ * \return Unsigned char string pointing to user dir (eg `~/.config/.blender/`).
+ */
+ const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
+
+ /**
+ * Determine the directory of the current binary
+ * \return Unsigned char string pointing to the binary dir
+ */
+ const GHOST_TUns8 *getBinaryDir() const;
+
+ /**
+ * Add the file to the operating system most recently used files
+ */
+ void addToSystemRecentFiles(const char *filename) const;
+};
+
+#endif /* __GHOST_SYSTEMPATHSUNIX_H__ */
diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.h b/intern/ghost/intern/GHOST_SystemPathsWin32.h
index b63d20bfcbd..5685a57eba8 100644
--- a/intern/ghost/intern/GHOST_SystemPathsWin32.h
+++ b/intern/ghost/intern/GHOST_SystemPathsWin32.h
@@ -37,6 +37,7 @@
#error WIN32 only!
#endif // WIN32
+#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501 // require Windows XP or newer
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/intern/ghost/intern/GHOST_SystemPathsX11.cpp b/intern/ghost/intern/GHOST_SystemPathsX11.cpp
deleted file mode 100644
index 5473e404593..00000000000
--- a/intern/ghost/intern/GHOST_SystemPathsX11.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2010 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file ghost/intern/GHOST_SystemPathsX11.cpp
- * \ingroup GHOST
- */
-
-
-#include "GHOST_SystemPathsX11.h"
-
-#include "GHOST_Debug.h"
-
-// For timing
-
-#include <sys/time.h>
-#include <unistd.h>
-
-#include <stdio.h> /* for fprintf only */
-#include <cstdlib> /* for exit */
-
-#include <pwd.h> /* for get home without use getenv() */
-#include <string>
-
-using std::string;
-
-#ifdef PREFIX
-static const char *static_path = PREFIX "/share";
-#else
-static const char *static_path = NULL;
-#endif
-
-GHOST_SystemPathsX11::GHOST_SystemPathsX11()
-{
-}
-
-GHOST_SystemPathsX11::~GHOST_SystemPathsX11()
-{
-}
-
-const GHOST_TUns8 *GHOST_SystemPathsX11::getSystemDir(int, const char *versionstr) const
-{
- /* no prefix assumes a portable build which only uses bundled scripts */
- if (static_path) {
- static string system_path = string(static_path) + "/blender/" + versionstr;
- return (GHOST_TUns8 *)system_path.c_str();
- }
-
- return NULL;
-}
-
-const GHOST_TUns8 *GHOST_SystemPathsX11::getUserDir(int version, const char *versionstr) const
-{
- static string user_path = "";
- static int last_version = 0;
-
- /* in blender 2.64, we migrate to XDG. to ensure the copy previous settings
- * operator works we give a different path depending on the requested version */
- if (version < 264) {
- if (user_path.empty() || last_version != version) {
- const char *home = getenv("HOME");
-
- last_version = version;
-
- if (home) {
- user_path = string(home) + "/.blender/" + versionstr;
- }
- else {
- return NULL;
- }
- }
- return (GHOST_TUns8 *)user_path.c_str();
- }
- else {
- if (user_path.empty() || last_version != version) {
- const char *home = getenv("XDG_CONFIG_HOME");
-
- last_version = version;
-
- if (home) {
- user_path = string(home) + "/blender/" + versionstr;
- }
- else {
- home = getenv("HOME");
-
- if (home == NULL)
- home = getpwuid(getuid())->pw_dir;
-
- user_path = string(home) + "/.config/blender/" + versionstr;
- }
- }
-
- return (const GHOST_TUns8 *)user_path.c_str();
- }
-}
-
-const GHOST_TUns8 *GHOST_SystemPathsX11::getBinaryDir() const
-{
- return NULL;
-}
-
-void GHOST_SystemPathsX11::addToSystemRecentFiles(const char * /*filename*/) const
-{
- /* XXXXX TODO: Implementation for X11 if possible */
-
-}
diff --git a/intern/ghost/intern/GHOST_SystemPathsX11.h b/intern/ghost/intern/GHOST_SystemPathsX11.h
deleted file mode 100644
index 23cc2e4b104..00000000000
--- a/intern/ghost/intern/GHOST_SystemPathsX11.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2010 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file ghost/intern/GHOST_SystemPathsX11.h
- * \ingroup GHOST
- */
-
-
-#ifndef __GHOST_SYSTEMPATHSX11_H__
-#define __GHOST_SYSTEMPATHSX11_H__
-
-#include "GHOST_SystemPaths.h"
-#include "../GHOST_Types.h"
-
-
-class GHOST_SystemPathsX11 : public GHOST_SystemPaths {
-public:
-
- /**
- * Constructor
- * this class should only be instanciated by GHOST_ISystem.
- */
- GHOST_SystemPathsX11();
-
- /**
- * Destructor.
- */
- ~GHOST_SystemPathsX11();
-
- /**
- * Determine the base dir in which shared resources are located. It will first try to use
- * "unpack and run" path, then look for properly installed path, including versioning.
- * \return Unsigned char string pointing to system dir (eg /usr/share/blender/).
- */
- const GHOST_TUns8 *getSystemDir(int version, const char *versionstr) const;
-
- /**
- * Determine the base dir in which user configuration is stored, including versioning.
- * If needed, it will create the base directory.
- * \return Unsigned char string pointing to user dir (eg ~/.blender/).
- */
- const GHOST_TUns8 *getUserDir(int version, const char *versionstr) const;
-
- /**
- * Determine the directory of the current binary
- * \return Unsigned char string pointing to the binary dir
- */
- const GHOST_TUns8 *getBinaryDir() const;
-
- /**
- * Add the file to the operating system most recently used files
- */
- void addToSystemRecentFiles(const char *filename) const;
-};
-
-#endif
-
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 4f3b1127a18..d8ec827a946 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -241,7 +241,6 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(
state,
type,
((glSettings.flags & GHOST_glStereoVisual) != 0),
- ((glSettings.flags & GHOST_glWarnSupport) != 0),
glSettings.numOfAASamples,
parentWindow,
((glSettings.flags & GHOST_glDebugContext) != 0));
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 0a8837294db..3085fde610b 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -38,7 +38,8 @@
#endif // WIN32
#ifndef __MINGW64__
-#define _WIN32_WINNT 0x501 // require Windows XP or newer
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x501 // require Windows XP or newer
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 325cba0c631..3e1dbd18119 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -48,7 +48,7 @@
#include "GHOST_DisplayManagerX11.h"
#include "GHOST_EventDragnDrop.h"
#ifdef WITH_INPUT_NDOF
-# include "GHOST_NDOFManagerX11.h"
+# include "GHOST_NDOFManagerUnix.h"
#endif
#ifdef WITH_XDND
@@ -76,6 +76,10 @@
/* see [#34039] Fix Alt key glitch on Unity desktop */
#define USE_UNITY_WORKAROUND
+/* Fix 'shortcut' part of keyboard reading code only ever using first defined keymap instead of active one.
+ * See T47228 and D1746 */
+#define USE_NON_LATIN_KB_WORKAROUND
+
static GHOST_TKey convertXKey(KeySym key);
/* these are for copy and select copy */
@@ -202,7 +206,7 @@ init()
if (success) {
#ifdef WITH_INPUT_NDOF
- m_ndofManager = new GHOST_NDOFManagerX11(*this);
+ m_ndofManager = new GHOST_NDOFManagerUnix(*this);
#endif
m_displayManager = new GHOST_DisplayManagerX11(this);
@@ -589,7 +593,7 @@ processEvents(
}
#ifdef WITH_INPUT_NDOF
- if (static_cast<GHOST_NDOFManagerX11 *>(m_ndofManager)->processEvents()) {
+ if (static_cast<GHOST_NDOFManagerUnix *>(m_ndofManager)->processEvents()) {
anyProcessed = true;
}
#endif
@@ -762,6 +766,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
{
XKeyEvent *xke = &(xe->xkey);
KeySym key_sym;
+ KeySym key_sym_str;
char ascii;
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* utf8_array[] is initial buffer used for Xutf8LookupString().
@@ -777,8 +782,50 @@ GHOST_SystemX11::processEvent(XEvent *xe)
char *utf8_buf = NULL;
#endif
+ GHOST_TEventType type = (xke->type == KeyPress) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
+
GHOST_TKey gkey;
+#ifdef USE_NON_LATIN_KB_WORKAROUND
+ /* XXX Code below is kinda awfully convoluted... Issues are:
+ *
+ * - In keyboards like latin ones, numbers need a 'Shift' to be accessed but key_sym
+ * is unmodified (or anyone swapping the keys with xmodmap).
+ *
+ * - XLookupKeysym seems to always use first defined keymap (see T47228), which generates
+ * keycodes unusable by convertXKey for non-latin-compatible keymaps.
+ *
+ * To address this, we:
+ *
+ * - Try to get a 'number' key_sym using XLookupKeysym (with or without shift modifier).
+ * - Fallback to XLookupString to get a key_sym from active user-defined keymap.
+ *
+ * Note that this enforces users to use an ascii-compatible keymap with Blender - but at least it gives
+ * predictable and consistent results.
+ *
+ * Also, note that nothing in XLib sources [1] makes it obvious why those two functions give different
+ * key_sym results...
+ *
+ * [1] http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/KeyBind.c
+ */
+ if ((xke->keycode >= 10 && xke->keycode < 20)) {
+ key_sym = XLookupKeysym(xke, ShiftMask);
+ if (!((key_sym >= XK_0) && (key_sym <= XK_9))) {
+ key_sym = XLookupKeysym(xke, 0);
+ }
+ }
+ else {
+ key_sym = XLookupKeysym(xke, 0);
+ }
+
+ if (!XLookupString(xke, &ascii, 1, &key_sym_str, NULL)) {
+ ascii = '\0';
+ }
+
+ if ((gkey = convertXKey(key_sym)) == GHOST_kKeyUnknown) {
+ gkey = convertXKey(key_sym_str);
+ }
+#else
/* In keyboards like latin ones,
* numbers needs a 'Shift' to be accessed but key_sym
* is unmodified (or anyone swapping the keys with xmodmap).
@@ -799,14 +846,12 @@ GHOST_SystemX11::processEvent(XEvent *xe)
}
gkey = convertXKey(key_sym);
-
- GHOST_TEventType type = (xke->type == KeyPress) ?
- GHOST_kEventKeyDown : GHOST_kEventKeyUp;
if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
ascii = '\0';
}
-
+#endif
+
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* getting unicode on key-up events gives XLookupNone status */
XIC xic = window->getX11_XIC();
@@ -1340,8 +1385,8 @@ GHOST_TSuccess
GHOST_SystemX11::
setCursorPosition(
GHOST_TInt32 x,
- GHOST_TInt32 y
- ) {
+ GHOST_TInt32 y)
+{
/* This is a brute force move in screen coordinates
* XWarpPointer does relative moves so first determine the
diff --git a/intern/ghost/intern/GHOST_TaskbarWin32.h b/intern/ghost/intern/GHOST_TaskbarWin32.h
index 04196701fe9..6fcff297237 100644
--- a/intern/ghost/intern/GHOST_TaskbarWin32.h
+++ b/intern/ghost/intern/GHOST_TaskbarWin32.h
@@ -9,7 +9,8 @@
#endif // WIN32
#ifndef __MINGW64__
-#define _WIN32_WINNT 0x501 // require Windows XP or newer
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x501 // require Windows XP or newer
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 9c7b5c3fee7..b3fc8efbab1 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -41,11 +41,6 @@
#include <Cocoa/Cocoa.h>
-#if MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
- //Use of the SetSystemUIMode function (64bit compatible)
-# include <Carbon/Carbon.h>
-#endif
-
#include <sys/sysctl.h>
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
@@ -132,14 +127,10 @@ enum {
- (void)windowDidResize:(NSNotification *)notification
{
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
//if (![[notification object] inLiveResize]) {
//Send event only once, at end of resize operation (when user has released mouse button)
-#endif
systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow);
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
//}
-#endif
/* Live resize, send event, gets handled in wm_window.c. Needed because live resize runs in a modal loop, not letting main loop run */
if ([[notification object] inLiveResize]) {
systemCocoa->dispatchEvents();
@@ -393,16 +384,6 @@ enum {
systemCocoa->handleMouseEvent(event);
}
-- (void)beginGestureWithEvent:(NSEvent *)event
-{
- systemCocoa->handleMouseEvent(event);
-}
-
-- (void)endGestureWithEvent:(NSEvent *)event
-{
- systemCocoa->handleMouseEvent(event);
-}
-
- (void)tabletPoint:(NSEvent *)event
{
systemCocoa->handleTabletEvent(event,[event type]);
@@ -618,19 +599,15 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
[m_window setAcceptsMouseMovedEvents:YES];
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
NSView *view = [m_window contentView];
[view setAcceptsTouchEvents:YES];
-#endif
[m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
NSStringPboardType, NSTIFFPboardType, nil]];
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
if (state != GHOST_kWindowStateFullScreen) {
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
}
-#endif
if (state == GHOST_kWindowStateFullScreen)
setState(GHOST_kWindowStateFullScreen);
@@ -869,7 +846,6 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GHOST_TWindowState state;
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
NSUInteger masks = [m_window styleMask];
if (masks & NSFullScreenWindowMask) {
@@ -881,9 +857,7 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const
state = GHOST_kWindowStateNormal;
}
}
- else
-#endif
- if (m_fullScreen) {
+ else if (m_fullScreen) {
state = GHOST_kWindowStateFullScreen;
}
else if ([m_window isMiniaturized]) {
@@ -998,7 +972,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
case GHOST_kWindowStateFullScreen:
{
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
NSUInteger masks = [m_window styleMask];
if (!m_fullScreen && !(masks & NSFullScreenWindowMask)) {
@@ -1006,9 +979,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
[m_window toggleFullScreen:nil];
break;
}
-#else
- if (!m_fullScreen) {
-#endif
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* This status change needs to be done before Cocoa call to enter fullscreen mode
@@ -1016,12 +986,9 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
* doesn't know view/window difference. */
m_fullScreen = true;
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
/* Disable toggle for Lion style fullscreen */
[m_window setCollectionBehavior:NSWindowCollectionBehaviorDefault];
-#endif
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
//10.6 provides Cocoa functions to autoshow menu bar, and to change a window style
//Hide menu & dock if on primary screen. else only menu
if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) {
@@ -1031,38 +998,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
[m_window setStyleMask:NSBorderlessWindowMask];
[m_window setFrame:[[m_window screen] frame] display:YES];
[m_window makeFirstResponder:m_openGLView];
-#else
- //With 10.5, we need to create a new window to change its style to borderless
- //Hide menu & dock if needed
- if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) {
- //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO];
- //One of the very few 64bit compatible Carbon function
- SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar);
- }
- //Create a fullscreen borderless window
- CocoaWindow *tmpWindow = [[CocoaWindow alloc]
- initWithContentRect:[[m_window screen] frame]
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:YES];
- //Copy current window parameters
- [tmpWindow setTitle:[m_window title]];
- [tmpWindow setRepresentedFilename:[m_window representedFilename]];
- [tmpWindow setAcceptsMouseMovedEvents:YES];
- [tmpWindow setDelegate:[m_window delegate]];
- [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this];
- [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
- NSStringPboardType, NSTIFFPboardType, nil]];
-
- //Assign the openGL view to the new window
- [tmpWindow setContentView:m_openGLView];
-
- //Show the new window
- [tmpWindow makeKeyAndOrderFront:m_openGLView];
- //Close and release old window
- [m_window close];
- m_window = tmpWindow;
-#endif
//Tell WM of view new size
m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
@@ -1074,25 +1009,19 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
case GHOST_kWindowStateNormal:
default:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
NSUInteger masks = [m_window styleMask];
if (masks & NSFullScreenWindowMask) {
// Lion style fullscreen
[m_window toggleFullScreen:nil];
}
- else
-#endif
- if (m_fullScreen) {
+ else if (m_fullScreen) {
m_fullScreen = false;
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
/* Enable toggle for into Lion style fullscreen */
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
-#endif
//Exit fullscreen
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
//Show again menu & dock if needed
if ([[m_window screen] isEqual:[NSScreen mainScreen]]) {
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
@@ -1102,39 +1031,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
[m_window setFrame:[[m_window screen] visibleFrame] display:YES];
//TODO for 10.6 only : window title is forgotten after the style change
[m_window makeFirstResponder:m_openGLView];
-#else
- //With 10.5, we need to create a new window to change its style to borderless
- //Show menu & dock if needed
- if ([[m_window screen] isEqual:[NSScreen mainScreen]]) {
- //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES];
- SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function
- }
- //Create a fullscreen borderless window
- CocoaWindow *tmpWindow = [[CocoaWindow alloc]
- initWithContentRect:[[m_window screen] frame]
- styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
- backing:NSBackingStoreBuffered
- defer:YES];
- //Copy current window parameters
- [tmpWindow setTitle:[m_window title]];
- [tmpWindow setRepresentedFilename:[m_window representedFilename]];
- [tmpWindow setAcceptsMouseMovedEvents:YES];
- [tmpWindow setDelegate:[m_window delegate]];
- [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this];
- [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
- NSStringPboardType, NSTIFFPboardType, nil]];
- //Forbid to resize the window below the blender defined minimum one
- [tmpWindow setContentMinSize:NSMakeSize(320, 240)];
-
- //Assign the openGL view to the new window
- [tmpWindow setContentView:m_openGLView];
-
- //Show the new window
- [tmpWindow makeKeyAndOrderFront:nil];
- //Close and release old window
- [m_window close];
- m_window = tmpWindow;
-#endif
//Tell WM of view new size
m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this);
@@ -1463,12 +1359,9 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
if (mode != GHOST_kGrabDisable) {
//No need to perform grab without warp as it is always on in OS X
if (mode != GHOST_kGrabNormal) {
- GHOST_TInt32 x_old,y_old;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- m_systemCocoa->getCursorPosition(x_old,y_old);
- screenToClientIntern(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
- //Warp position is stored in client (window base) coordinates
+ m_systemCocoa->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
setCursorGrabAccum(0, 0);
if (mode == GHOST_kGrabHide) {
@@ -1486,7 +1379,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
}
else {
if (m_cursorGrab==GHOST_kGrabHide) {
- //No need to set again cursor position, as it has not changed for Cocoa
+ m_systemCocoa->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
setWindowCursorVisibility(true);
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 54689a96b66..7247753c655 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -70,7 +70,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
- bool wantStereoVisual, bool warnOld,
+ bool wantStereoVisual,
GHOST_TUns16 wantNumOfAASamples,
GHOST_TEmbedderWindowID parentwindowhwnd,
bool is_debug)
@@ -98,13 +98,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-#if !defined(WITH_GL_EGL)
- if (!warnOld)
- GHOST_ContextWGL::unSetWarningOld();
-#else
- (void)(warnOld);
-#endif
-
if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
@@ -633,7 +626,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
- WGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
+ WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
3, 2,
GHOST_OPENGL_WGL_CONTEXT_FLAGS,
GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
@@ -653,8 +646,14 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
+#if 1
0, // profile bit
- 0, 0,
+ 2, 1, // GL version requested
+#else
+ // switch to this for Blender 2.8 development
+ WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+ 3, 2,
+#endif
GHOST_OPENGL_WGL_CONTEXT_FLAGS,
GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
#else
@@ -691,8 +690,14 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
m_wantNumOfAASamples,
m_hWnd,
m_hDC,
+#if 1
0, // profile bit
- 0, 0,
+ 2, 1, // GL version requested
+#else
+ // switch to this for Blender 2.8 development
+ EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
+ 3, 2,
+#endif
GHOST_OPENGL_EGL_CONTEXT_FLAGS,
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 3666fa753f3..b508c2f37df 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -89,7 +89,6 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
bool wantStereoVisual = false,
- bool warnOld = false,
GHOST_TUns16 wantNumOfAASamples = 0,
GHOST_TEmbedderWindowID parentWindowHwnd = 0,
bool is_debug = false);
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index fe99a8bee1e..e68e0901dab 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -105,8 +105,12 @@ typedef struct {
* print(", ".join([str(p) for p in px]), end=",\n")
*/
-/* See the python script above to regenerate the 48x48 icon within blender */
-static long BLENDER_ICON_48x48x32[] = {
+/**
+ * See the python script above to regenerate the 48x48 icon within blender
+ *
+ * \note Using 'unsigned' to avoid `-Wnarrowing` warning.
+ */
+static const unsigned long BLENDER_ICON_48x48x32[] = {
48,48,
4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303, 4671303,
@@ -355,22 +359,17 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
#endif
if (state == GHOST_kWindowStateMaximized || state == GHOST_kWindowStateFullScreen) {
- Atom _NET_WM_STATE = XInternAtom(m_display, "_NET_WM_STATE", False);
- Atom _NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
- Atom _NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
- Atom _NET_WM_STATE_FULLSCREEN = XInternAtom(m_display, "_NET_WM_STATE_FULLSCREEN", False);
Atom atoms[2];
int count = 0;
-
if (state == GHOST_kWindowStateMaximized) {
- atoms[count++] = _NET_WM_STATE_MAXIMIZED_VERT;
- atoms[count++] = _NET_WM_STATE_MAXIMIZED_HORZ;
+ atoms[count++] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT;
+ atoms[count++] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ;
}
else {
- atoms[count++] = _NET_WM_STATE_FULLSCREEN;
+ atoms[count++] = m_system->m_atom._NET_WM_STATE_FULLSCREEN;
}
- XChangeProperty(m_display, m_window, _NET_WM_STATE, XA_ATOM, 32,
+ XChangeProperty(m_display, m_window, m_system->m_atom._NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char *)atoms, count);
m_post_init = False;
}
@@ -787,16 +786,16 @@ void GHOST_WindowX11::icccmSetState(int state)
int GHOST_WindowX11::icccmGetState(void) const
{
- unsigned char *prop_ret;
+ Atom *prop_ret;
unsigned long bytes_after, num_ret;
Atom type_ret;
int format_ret, st;
prop_ret = NULL;
- st = XGetWindowProperty(m_display, m_window, m_system->m_atom.WM_STATE, 0,
- 0x7fffffff, False, m_system->m_atom.WM_STATE, &type_ret,
- &format_ret, &num_ret, &bytes_after, &prop_ret);
-
+ st = XGetWindowProperty(
+ m_display, m_window, m_system->m_atom.WM_STATE, 0, 2,
+ False, m_system->m_atom.WM_STATE, &type_ret,
+ &format_ret, &num_ret, &bytes_after, ((unsigned char **)&prop_ret));
if ((st == Success) && (prop_ret) && (num_ret == 2))
st = prop_ret[0];
else
@@ -833,7 +832,7 @@ void GHOST_WindowX11::netwmMaximized(bool set)
bool GHOST_WindowX11::netwmIsMaximized(void) const
{
- unsigned char *prop_ret;
+ Atom *prop_ret;
unsigned long bytes_after, num_ret, i;
Atom type_ret;
bool st;
@@ -841,16 +840,19 @@ bool GHOST_WindowX11::netwmIsMaximized(void) const
prop_ret = NULL;
st = False;
- ret = XGetWindowProperty(m_display, m_window, m_system->m_atom._NET_WM_STATE, 0,
- 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret,
- &num_ret, &bytes_after, &prop_ret);
+ ret = XGetWindowProperty(
+ m_display, m_window, m_system->m_atom._NET_WM_STATE, 0, INT_MAX,
+ False, XA_ATOM, &type_ret, &format_ret,
+ &num_ret, &bytes_after, (unsigned char **)&prop_ret);
if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
count = 0;
for (i = 0; i < num_ret; i++) {
- if (((unsigned long *) prop_ret)[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ)
+ if (prop_ret[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ) {
count++;
- if (((unsigned long *) prop_ret)[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT)
+ }
+ if (prop_ret[i] == m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT) {
count++;
+ }
if (count == 2) {
st = True;
break;
@@ -889,7 +891,7 @@ void GHOST_WindowX11::netwmFullScreen(bool set)
bool GHOST_WindowX11::netwmIsFullScreen(void) const
{
- unsigned char *prop_ret;
+ Atom *prop_ret;
unsigned long bytes_after, num_ret, i;
Atom type_ret;
bool st;
@@ -897,12 +899,13 @@ bool GHOST_WindowX11::netwmIsFullScreen(void) const
prop_ret = NULL;
st = False;
- ret = XGetWindowProperty(m_display, m_window, m_system->m_atom._NET_WM_STATE, 0,
- 0x7fffffff, False, XA_ATOM, &type_ret, &format_ret,
- &num_ret, &bytes_after, &prop_ret);
+ ret = XGetWindowProperty(
+ m_display, m_window, m_system->m_atom._NET_WM_STATE, 0, INT_MAX,
+ False, XA_ATOM, &type_ret, &format_ret,
+ &num_ret, &bytes_after, (unsigned char **)&prop_ret);
if ((ret == Success) && (prop_ret) && (format_ret == 32)) {
for (i = 0; i < num_ret; i++) {
- if (((unsigned long *) prop_ret)[i] == m_system->m_atom._NET_WM_STATE_FULLSCREEN) {
+ if (prop_ret[i] == m_system->m_atom._NET_WM_STATE_FULLSCREEN) {
st = True;
break;
}
@@ -931,23 +934,22 @@ void GHOST_WindowX11::motifFullScreen(bool set)
bool GHOST_WindowX11::motifIsFullScreen(void) const
{
- unsigned char *prop_ret;
+ MotifWmHints *prop_ret;
unsigned long bytes_after, num_ret;
- MotifWmHints *hints;
Atom type_ret;
bool state;
int format_ret, st;
prop_ret = NULL;
state = False;
- st = XGetWindowProperty(m_display, m_window, m_system->m_atom._MOTIF_WM_HINTS, 0,
- 0x7fffffff, False, m_system->m_atom._MOTIF_WM_HINTS,
- &type_ret, &format_ret, &num_ret,
- &bytes_after, &prop_ret);
- if ((st == Success) && (prop_ret)) {
- hints = (MotifWmHints *) prop_ret;
- if (hints->flags & MWM_HINTS_DECORATIONS) {
- if (!hints->decorations)
+ st = XGetWindowProperty(
+ m_display, m_window, m_system->m_atom._MOTIF_WM_HINTS, 0, INT_MAX,
+ False, m_system->m_atom._MOTIF_WM_HINTS,
+ &type_ret, &format_ret, &num_ret,
+ &bytes_after, (unsigned char **)&prop_ret);
+ if ((st == Success) && prop_ret) {
+ if (prop_ret->flags & MWM_HINTS_DECORATIONS) {
+ if (!prop_ret->decorations)
state = True;
}
}
@@ -1102,7 +1104,7 @@ setOrder(
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;
- root = RootWindow(m_display, m_visualInfo->screen),
+ root = RootWindow(m_display, m_visualInfo->screen);
eventmask = SubstructureRedirectMask | SubstructureNotifyMask;
XSendEvent(m_display, root, False, eventmask, &xev);
diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt
index e1475966d47..fb9ef621ecf 100644
--- a/intern/ghost/test/CMakeLists.txt
+++ b/intern/ghost/test/CMakeLists.txt
@@ -79,6 +79,8 @@ if(UNIX AND NOT APPLE)
endif()
# for now... default to this
add_definitions(-DWITH_GL_PROFILE_COMPAT)
+# BLF needs this to ignore GPU library
+add_definitions(-DBLF_STANDALONE)
# ghost
include(${CMAKE_SOURCE_DIR}/../CMakeLists.txt)
diff --git a/intern/glew-mx/SConscript b/intern/glew-mx/SConscript
deleted file mode 100644
index 546470d020c..00000000000
--- a/intern/glew-mx/SConscript
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/python
-import sys
-import os
-
-Import('env')
-
-sources = ['intern/glew-mx.c']
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-incs = [
- '.',
- env['BF_GLEW_INC'],
- ]
-
-env.BlenderLib('intern_glew_mx', sources, incs, defs, libtype=['intern','player'], priority=[50, 185])
diff --git a/intern/glew-mx/glew-mx.h b/intern/glew-mx/glew-mx.h
index 92450d67812..ed17ea4a0e6 100644
--- a/intern/glew-mx/glew-mx.h
+++ b/intern/glew-mx/glew-mx.h
@@ -95,8 +95,6 @@ MXContext *mxGetCurrentContext (void);
void mxMakeCurrentContext(MXContext *ctx);
void mxDestroyContext (MXContext *ctx);
-void mxIgnoreNoVersion(int ignore);
-
GLenum glew_chk(GLenum error, const char *file, int line, const char *text);
#ifndef NDEBUG
diff --git a/intern/glew-mx/intern/glew-mx.c b/intern/glew-mx/intern/glew-mx.c
index 78920670f68..6fbb1a7a2e2 100644
--- a/intern/glew-mx/intern/glew-mx.c
+++ b/intern/glew-mx/intern/glew-mx.c
@@ -34,8 +34,6 @@
#include <stdio.h>
#include <stdlib.h>
-static int ignore_version = 0;
-
#define CASE_CODE_RETURN_STR(code) case code: return #code;
static const char *get_glew_error_enum_string(GLenum error)
@@ -63,7 +61,7 @@ GLenum glew_chk(GLenum error, const char *file, int line, const char *text)
const char *code = get_glew_error_enum_string(error);
const char *msg = (const char *)glewGetErrorString(error);
- if (error == GLEW_ERROR_NO_GL_VERSION && ignore_version)
+ if (error == GLEW_ERROR_NO_GL_VERSION)
return GLEW_OK;
#ifndef NDEBUG
@@ -144,8 +142,3 @@ void mxDestroyContext(MXContext *ctx)
(void)ctx;
#endif
}
-
-void mxIgnoreNoVersion(int ignore)
-{
- ignore_version = ignore;
-}
diff --git a/intern/guardedalloc/SConscript b/intern/guardedalloc/SConscript
deleted file mode 100644
index 3bae808cc94..00000000000
--- a/intern/guardedalloc/SConscript
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-defs = []
-
-sources = [
- 'intern/mallocn.c',
- 'intern/mallocn_guarded_impl.c',
- 'intern/mallocn_lockfree_impl.c',
- 'intern/mmap_win.c'
-]
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- sources.append('cpp/mallocn.cpp')
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-incs = '. ../atomic'
-
-env.BlenderLib ('bf_intern_guardedalloc', sources, Split(incs), defs, libtype=['intern','player'], priority = [5,150] )
diff --git a/intern/iksolver/CMakeLists.txt b/intern/iksolver/CMakeLists.txt
index 9476e0379e9..52e331653ac 100644
--- a/intern/iksolver/CMakeLists.txt
+++ b/intern/iksolver/CMakeLists.txt
@@ -29,7 +29,7 @@ set(INC
)
set(INC_SYS
- ../moto/include
+ ${EIGEN3_INCLUDE_DIRS}
)
set(SRC
@@ -38,38 +38,13 @@ set(SRC
intern/IK_QSegment.cpp
intern/IK_QTask.cpp
intern/IK_Solver.cpp
- intern/MT_ExpMap.cpp
extern/IK_solver.h
+ intern/IK_Math.h
intern/IK_QJacobian.h
intern/IK_QJacobianSolver.h
intern/IK_QSegment.h
intern/IK_QTask.h
- intern/MT_ExpMap.h
- intern/TNT/cholesky.h
- intern/TNT/cmat.h
- intern/TNT/fcscmat.h
- intern/TNT/fmat.h
- intern/TNT/fortran.h
- intern/TNT/fspvec.h
- intern/TNT/index.h
- intern/TNT/lapack.h
- intern/TNT/lu.h
- intern/TNT/qr.h
- intern/TNT/region1d.h
- intern/TNT/region2d.h
- intern/TNT/stopwatch.h
- intern/TNT/subscript.h
- intern/TNT/svd.h
- intern/TNT/tnt.h
- intern/TNT/tntmath.h
- intern/TNT/tntreqs.h
- intern/TNT/transv.h
- intern/TNT/triang.h
- intern/TNT/trisolve.h
- intern/TNT/vec.h
- intern/TNT/vecadaptor.h
- intern/TNT/version.h
)
blender_add_lib(bf_intern_iksolver "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/iksolver/SConscript b/intern/iksolver/SConscript
deleted file mode 100644
index ba973ad5fd5..00000000000
--- a/intern/iksolver/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = 'intern ../moto/include ../memutil'
-
-env.BlenderLib ('bf_intern_iksolver', sources, Split(incs), [], libtype=['intern','player'], priority=[100,90] )
-
diff --git a/intern/iksolver/intern/IK_Math.h b/intern/iksolver/intern/IK_Math.h
new file mode 100644
index 00000000000..78d99837c43
--- /dev/null
+++ b/intern/iksolver/intern/IK_Math.h
@@ -0,0 +1,261 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Original author: Laurence
+ * Contributor(s): Brecht
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#pragma once
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <cmath>
+
+using Eigen::Affine3d;
+using Eigen::Matrix3d;
+using Eigen::MatrixXd;
+using Eigen::Vector3d;
+using Eigen::VectorXd;
+
+static const double IK_EPSILON = 1e-20;
+
+static inline bool FuzzyZero(double x)
+{
+ return fabs(x) < IK_EPSILON;
+}
+
+static inline double Clamp(const double x, const double min, const double max)
+{
+ return (x < min) ? min : (x > max) ? max : x;
+}
+
+static inline Eigen::Matrix3d CreateMatrix(double xx, double xy, double xz,
+ double yx, double yy, double yz,
+ double zx, double zy, double zz)
+{
+ Eigen::Matrix3d M;
+ M(0, 0) = xx; M(0, 1) = xy; M(0, 2) = xz;
+ M(1, 0) = yx; M(1, 1) = yy; M(1, 2) = yz;
+ M(2, 0) = zx; M(2, 1) = zy; M(2, 2) = zz;
+ return M;
+}
+
+static inline Eigen::Matrix3d RotationMatrix(double sine, double cosine, int axis)
+{
+ if (axis == 0)
+ return CreateMatrix(1.0, 0.0, 0.0,
+ 0.0, cosine, -sine,
+ 0.0, sine, cosine);
+ else if (axis == 1)
+ return CreateMatrix(cosine, 0.0, sine,
+ 0.0, 1.0, 0.0,
+ -sine, 0.0, cosine);
+ else
+ return CreateMatrix(cosine, -sine, 0.0,
+ sine, cosine, 0.0,
+ 0.0, 0.0, 1.0);
+}
+
+static inline Eigen::Matrix3d RotationMatrix(double angle, int axis)
+{
+ return RotationMatrix(sin(angle), cos(angle), axis);
+}
+
+
+static inline double EulerAngleFromMatrix(const Eigen::Matrix3d& R, int axis)
+{
+ double t = sqrt(R(0, 0) * R(0, 0) + R(0, 1) * R(0, 1));
+
+ if (t > 16.0 * IK_EPSILON) {
+ if (axis == 0) return -atan2(R(1, 2), R(2, 2));
+ else if (axis == 1) return atan2(-R(0, 2), t);
+ else return -atan2(R(0, 1), R(0, 0));
+ }
+ else {
+ if (axis == 0) return -atan2(-R(2, 1), R(1, 1));
+ else if (axis == 1) return atan2(-R(0, 2), t);
+ else return 0.0f;
+ }
+}
+
+static inline double safe_acos(double f)
+{
+ // acos that does not return NaN with rounding errors
+ if (f <= -1.0)
+ return M_PI;
+ else if (f >= 1.0)
+ return 0.0;
+ else
+ return acos(f);
+}
+
+static inline Eigen::Vector3d normalize(const Eigen::Vector3d& v)
+{
+ // a sane normalize function that doesn't give (1, 0, 0) in case
+ // of a zero length vector
+ double len = v.norm();
+ return FuzzyZero(len) ? Eigen::Vector3d(0, 0, 0) : Eigen::Vector3d(v / len);
+}
+
+static inline double angle(const Eigen::Vector3d& v1, const Eigen::Vector3d& v2)
+{
+ return safe_acos(v1.dot(v2));
+}
+
+static inline double ComputeTwist(const Eigen::Matrix3d& R)
+{
+ // qy and qw are the y and w components of the quaternion from R
+ double qy = R(0, 2) - R(2, 0);
+ double qw = R(0, 0) + R(1, 1) + R(2, 2) + 1;
+
+ double tau = 2.0 * atan2(qy, qw);
+
+ return tau;
+}
+
+static inline Eigen::Matrix3d ComputeTwistMatrix(double tau)
+{
+ return RotationMatrix(tau, 1);
+}
+
+static inline void RemoveTwist(Eigen::Matrix3d& R)
+{
+ // compute twist parameter
+ double tau = ComputeTwist(R);
+
+ // compute twist matrix
+ Eigen::Matrix3d T = ComputeTwistMatrix(tau);
+
+ // remove twist
+ R = R * T.transpose();
+}
+
+static inline Eigen::Vector3d SphericalRangeParameters(const Eigen::Matrix3d& R)
+{
+ // compute twist parameter
+ double tau = ComputeTwist(R);
+
+ // compute swing parameters
+ double num = 2.0 * (1.0 + R(1, 1));
+
+ // singularity at pi
+ if (fabs(num) < IK_EPSILON)
+ // TODO: this does now rotation of size pi over z axis, but could
+ // be any axis, how to deal with this i'm not sure, maybe don't
+ // enforce limits at all then
+ return Eigen::Vector3d(0.0, tau, 1.0);
+
+ num = 1.0 / sqrt(num);
+ double ax = -R(2, 1) * num;
+ double az = R(0, 1) * num;
+
+ return Eigen::Vector3d(ax, tau, az);
+}
+
+static inline Eigen::Matrix3d ComputeSwingMatrix(double ax, double az)
+{
+ // length of (ax, 0, az) = sin(theta/2)
+ double sine2 = ax * ax + az * az;
+ double cosine2 = sqrt((sine2 >= 1.0) ? 0.0 : 1.0 - sine2);
+
+ // compute swing matrix
+ Eigen::Matrix3d S(Eigen::Quaterniond(-cosine2, ax, 0.0, az));
+
+ return S;
+}
+
+static inline Eigen::Vector3d MatrixToAxisAngle(const Eigen::Matrix3d& R)
+{
+ Eigen::Vector3d delta = Eigen::Vector3d(R(2, 1) - R(1, 2),
+ R(0, 2) - R(2, 0),
+ R(1, 0) - R(0, 1));
+
+ double c = safe_acos((R(0, 0) + R(1, 1) + R(2, 2) - 1) / 2);
+ double l = delta.norm();
+
+ if (!FuzzyZero(l))
+ delta *= c / l;
+
+ return delta;
+}
+
+static inline bool EllipseClamp(double& ax, double& az, double *amin, double *amax)
+{
+ double xlim, zlim, x, z;
+
+ if (ax < 0.0) {
+ x = -ax;
+ xlim = -amin[0];
+ }
+ else {
+ x = ax;
+ xlim = amax[0];
+ }
+
+ if (az < 0.0) {
+ z = -az;
+ zlim = -amin[1];
+ }
+ else {
+ z = az;
+ zlim = amax[1];
+ }
+
+ if (FuzzyZero(xlim) || FuzzyZero(zlim)) {
+ if (x <= xlim && z <= zlim)
+ return false;
+
+ if (x > xlim)
+ x = xlim;
+ if (z > zlim)
+ z = zlim;
+ }
+ else {
+ double invx = 1.0 / (xlim * xlim);
+ double invz = 1.0 / (zlim * zlim);
+
+ if ((x * x * invx + z * z * invz) <= 1.0)
+ return false;
+
+ if (FuzzyZero(x)) {
+ x = 0.0;
+ z = zlim;
+ }
+ else {
+ double rico = z / x;
+ double old_x = x;
+ x = sqrt(1.0 / (invx + invz * rico * rico));
+ if (old_x < 0.0)
+ x = -x;
+ z = rico * x;
+ }
+ }
+
+ ax = (ax < 0.0) ? -x : x;
+ az = (az < 0.0) ? -z : z;
+
+ return true;
+}
+
diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp
index bb7b7c5c0b8..2925cadf435 100644
--- a/intern/iksolver/intern/IK_QJacobian.cpp
+++ b/intern/iksolver/intern/IK_QJacobian.cpp
@@ -32,7 +32,6 @@
#include "IK_QJacobian.h"
-#include "TNT/svd.h"
IK_QJacobian::IK_QJacobian()
: m_sdls(true), m_min_damp(1.0)
@@ -48,74 +47,66 @@ void IK_QJacobian::ArmMatrices(int dof, int task_size)
m_dof = dof;
m_task_size = task_size;
- m_jacobian.newsize(task_size, dof);
- m_jacobian = 0;
+ m_jacobian.resize(task_size, dof);
+ m_jacobian.setZero();
- m_alpha.newsize(dof);
- m_alpha = 0;
+ m_alpha.resize(dof);
+ m_alpha.setZero();
- m_null.newsize(dof, dof);
+ m_nullspace.resize(dof, dof);
- m_d_theta.newsize(dof);
- m_d_theta_tmp.newsize(dof);
- m_d_norm_weight.newsize(dof);
+ m_d_theta.resize(dof);
+ m_d_theta_tmp.resize(dof);
+ m_d_norm_weight.resize(dof);
- m_norm.newsize(dof);
- m_norm = 0.0;
+ m_norm.resize(dof);
+ m_norm.setZero();
- m_beta.newsize(task_size);
+ m_beta.resize(task_size);
- m_weight.newsize(dof);
- m_weight_sqrt.newsize(dof);
- m_weight = 1.0;
- m_weight_sqrt = 1.0;
+ m_weight.resize(dof);
+ m_weight_sqrt.resize(dof);
+ m_weight.setOnes();
+ m_weight_sqrt.setOnes();
if (task_size >= dof) {
m_transpose = false;
- m_jacobian_tmp.newsize(task_size, dof);
+ m_jacobian_tmp.resize(task_size, dof);
- m_svd_u.newsize(task_size, dof);
- m_svd_v.newsize(dof, dof);
- m_svd_w.newsize(dof);
+ m_svd_u.resize(task_size, dof);
+ m_svd_v.resize(dof, dof);
+ m_svd_w.resize(dof);
- m_work1.newsize(task_size);
- m_work2.newsize(dof);
-
- m_svd_u_t.newsize(dof, task_size);
- m_svd_u_beta.newsize(dof);
+ m_svd_u_beta.resize(dof);
}
else {
// use the SVD of the transpose jacobian, it works just as well
// as the original, and often allows using smaller matrices.
m_transpose = true;
- m_jacobian_tmp.newsize(dof, task_size);
-
- m_svd_u.newsize(task_size, task_size);
- m_svd_v.newsize(dof, task_size);
- m_svd_w.newsize(task_size);
+ m_jacobian_tmp.resize(dof, task_size);
- m_work1.newsize(dof);
- m_work2.newsize(task_size);
+ m_svd_u.resize(task_size, task_size);
+ m_svd_v.resize(dof, task_size);
+ m_svd_w.resize(task_size);
- m_svd_u_t.newsize(task_size, task_size);
- m_svd_u_beta.newsize(task_size);
+ m_svd_u_beta.resize(task_size);
}
}
-void IK_QJacobian::SetBetas(int id, int, const MT_Vector3& v)
+void IK_QJacobian::SetBetas(int id, int, const Vector3d& v)
{
m_beta[id + 0] = v.x();
m_beta[id + 1] = v.y();
m_beta[id + 2] = v.z();
}
-void IK_QJacobian::SetDerivatives(int id, int dof_id, const MT_Vector3& v, MT_Scalar norm_weight)
+void IK_QJacobian::SetDerivatives(int id, int dof_id, const Vector3d& v, double norm_weight)
{
- m_jacobian[id + 0][dof_id] = v.x() * m_weight_sqrt[dof_id];
- m_jacobian[id + 1][dof_id] = v.y() * m_weight_sqrt[dof_id];
- m_jacobian[id + 2][dof_id] = v.z() * m_weight_sqrt[dof_id];
+ m_jacobian(id + 0, dof_id) = v.x() * m_weight_sqrt[dof_id];
+ m_jacobian(id + 1, dof_id) = v.y() * m_weight_sqrt[dof_id];
+ m_jacobian(id + 2, dof_id) = v.z() * m_weight_sqrt[dof_id];
m_d_norm_weight[dof_id] = norm_weight;
}
@@ -125,14 +116,18 @@ void IK_QJacobian::Invert()
if (m_transpose) {
// SVD will decompose Jt into V*W*Ut with U,V orthogonal and W diagonal,
// so J = U*W*Vt and Jinv = V*Winv*Ut
- TNT::transpose(m_jacobian, m_jacobian_tmp);
- TNT::SVD(m_jacobian_tmp, m_svd_v, m_svd_w, m_svd_u, m_work1, m_work2);
+ Eigen::JacobiSVD<MatrixXd> svd(m_jacobian.transpose(), Eigen::ComputeThinU | Eigen::ComputeThinV);
+ m_svd_u = svd.matrixV();
+ m_svd_w = svd.singularValues();
+ m_svd_v = svd.matrixU();
}
else {
// SVD will decompose J into U*W*Vt with U,V orthogonal and W diagonal,
// so Jinv = V*Winv*Ut
- m_jacobian_tmp = m_jacobian;
- TNT::SVD(m_jacobian_tmp, m_svd_u, m_svd_w, m_svd_v, m_work1, m_work2);
+ Eigen::JacobiSVD<MatrixXd> svd(m_jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV);
+ m_svd_u = svd.matrixU();
+ m_svd_w = svd.singularValues();
+ m_svd_v = svd.matrixV();
}
if (m_sdls)
@@ -143,7 +138,7 @@ void IK_QJacobian::Invert()
bool IK_QJacobian::ComputeNullProjection()
{
- MT_Scalar epsilon = 1e-10;
+ double epsilon = 1e-10;
// compute null space projection based on V
int i, j, rank = 0;
@@ -154,26 +149,24 @@ bool IK_QJacobian::ComputeNullProjection()
if (rank < m_task_size)
return false;
- TMatrix basis(m_svd_v.num_rows(), rank);
- TMatrix basis_t(rank, m_svd_v.num_rows());
+ MatrixXd basis(m_svd_v.rows(), rank);
int b = 0;
for (i = 0; i < m_svd_w.size(); i++)
if (m_svd_w[i] > epsilon) {
- for (j = 0; j < m_svd_v.num_rows(); j++)
- basis[j][b] = m_svd_v[j][i];
+ for (j = 0; j < m_svd_v.rows(); j++)
+ basis(j, b) = m_svd_v(j, i);
b++;
}
- TNT::transpose(basis, basis_t);
- TNT::matmult(m_null, basis, basis_t);
+ m_nullspace = basis * basis.transpose();
- for (i = 0; i < m_null.num_rows(); i++)
- for (j = 0; j < m_null.num_cols(); j++)
+ for (i = 0; i < m_nullspace.rows(); i++)
+ for (j = 0; j < m_nullspace.cols(); j++)
if (i == j)
- m_null[i][j] = 1.0 - m_null[i][j];
+ m_nullspace(i, j) = 1.0 - m_nullspace(i, j);
else
- m_null[i][j] = -m_null[i][j];
+ m_nullspace(i, j) = -m_nullspace(i, j);
return true;
}
@@ -184,7 +177,7 @@ void IK_QJacobian::SubTask(IK_QJacobian& jacobian)
return;
// restrict lower priority jacobian
- jacobian.Restrict(m_d_theta, m_null);
+ jacobian.Restrict(m_d_theta, m_nullspace);
// add angle update from lower priority
jacobian.Invert();
@@ -197,19 +190,15 @@ void IK_QJacobian::SubTask(IK_QJacobian& jacobian)
m_d_theta[i] = m_d_theta[i] + /*m_min_damp * */ jacobian.AngleUpdate(i);
}
-void IK_QJacobian::Restrict(TVector& d_theta, TMatrix& null)
+void IK_QJacobian::Restrict(VectorXd& d_theta, MatrixXd& nullspace)
{
// subtract part already moved by higher task from beta
- TVector beta_sub(m_beta.size());
-
- TNT::matmult(beta_sub, m_jacobian, d_theta);
- m_beta = m_beta - beta_sub;
+ m_beta = m_beta - m_jacobian * d_theta;
// note: should we be using the norm of the unrestricted jacobian for SDLS?
// project jacobian on to null space of higher priority task
- TMatrix jacobian_copy(m_jacobian);
- TNT::matmult(m_jacobian, jacobian_copy, null);
+ m_jacobian = m_jacobian * nullspace;
}
void IK_QJacobian::InvertSDLS()
@@ -230,20 +219,20 @@ void IK_QJacobian::InvertSDLS()
// DLS. The SDLS damps individual singular values, instead of using a single
// damping term.
- MT_Scalar max_angle_change = MT_PI / 4.0;
- MT_Scalar epsilon = 1e-10;
+ double max_angle_change = M_PI / 4.0;
+ double epsilon = 1e-10;
int i, j;
- m_d_theta = 0;
+ m_d_theta.setZero();
m_min_damp = 1.0;
for (i = 0; i < m_dof; i++) {
m_norm[i] = 0.0;
for (j = 0; j < m_task_size; j += 3) {
- MT_Scalar n = 0.0;
- n += m_jacobian[j][i] * m_jacobian[j][i];
- n += m_jacobian[j + 1][i] * m_jacobian[j + 1][i];
- n += m_jacobian[j + 2][i] * m_jacobian[j + 2][i];
+ double n = 0.0;
+ n += m_jacobian(j, i) * m_jacobian(j, i);
+ n += m_jacobian(j + 1, i) * m_jacobian(j + 1, i);
+ n += m_jacobian(j + 2, i) * m_jacobian(j + 2, i);
m_norm[i] += sqrt(n);
}
}
@@ -252,40 +241,40 @@ void IK_QJacobian::InvertSDLS()
if (m_svd_w[i] <= epsilon)
continue;
- MT_Scalar wInv = 1.0 / m_svd_w[i];
- MT_Scalar alpha = 0.0;
- MT_Scalar N = 0.0;
+ double wInv = 1.0 / m_svd_w[i];
+ double alpha = 0.0;
+ double N = 0.0;
// compute alpha and N
- for (j = 0; j < m_svd_u.num_rows(); j += 3) {
- alpha += m_svd_u[j][i] * m_beta[j];
- alpha += m_svd_u[j + 1][i] * m_beta[j + 1];
- alpha += m_svd_u[j + 2][i] * m_beta[j + 2];
+ for (j = 0; j < m_svd_u.rows(); j += 3) {
+ alpha += m_svd_u(j, i) * m_beta[j];
+ alpha += m_svd_u(j + 1, i) * m_beta[j + 1];
+ alpha += m_svd_u(j + 2, i) * m_beta[j + 2];
// note: for 1 end effector, N will always be 1, since U is
// orthogonal, .. so could be optimized
- MT_Scalar tmp;
- tmp = m_svd_u[j][i] * m_svd_u[j][i];
- tmp += m_svd_u[j + 1][i] * m_svd_u[j + 1][i];
- tmp += m_svd_u[j + 2][i] * m_svd_u[j + 2][i];
+ double tmp;
+ tmp = m_svd_u(j, i) * m_svd_u(j, i);
+ tmp += m_svd_u(j + 1, i) * m_svd_u(j + 1, i);
+ tmp += m_svd_u(j + 2, i) * m_svd_u(j + 2, i);
N += sqrt(tmp);
}
alpha *= wInv;
// compute M, dTheta and max_dtheta
- MT_Scalar M = 0.0;
- MT_Scalar max_dtheta = 0.0, abs_dtheta;
+ double M = 0.0;
+ double max_dtheta = 0.0, abs_dtheta;
for (j = 0; j < m_d_theta.size(); j++) {
- MT_Scalar v = m_svd_v[j][i];
- M += MT_abs(v) * m_norm[j];
+ double v = m_svd_v(j, i);
+ M += fabs(v) * m_norm[j];
// compute tmporary dTheta's
m_d_theta_tmp[j] = v * alpha;
// find largest absolute dTheta
// multiply with weight to prevent unnecessary damping
- abs_dtheta = MT_abs(m_d_theta_tmp[j]) * m_weight_sqrt[j];
+ abs_dtheta = fabs(m_d_theta_tmp[j]) * m_weight_sqrt[j];
if (abs_dtheta > max_dtheta)
max_dtheta = abs_dtheta;
}
@@ -293,18 +282,18 @@ void IK_QJacobian::InvertSDLS()
M *= wInv;
// compute damping term and damp the dTheta's
- MT_Scalar gamma = max_angle_change;
+ double gamma = max_angle_change;
if (N < M)
gamma *= N / M;
- MT_Scalar damp = (gamma < max_dtheta) ? gamma / max_dtheta : 1.0;
+ double damp = (gamma < max_dtheta) ? gamma / max_dtheta : 1.0;
for (j = 0; j < m_d_theta.size(); j++) {
// slight hack: we do 0.80*, so that if there is some oscillation,
// the system can still converge (for joint limits). also, it's
// better to go a little to slow than to far
- MT_Scalar dofdamp = damp / m_weight[j];
+ double dofdamp = damp / m_weight[j];
if (dofdamp > 1.0) dofdamp = 1.0;
m_d_theta[j] += 0.80 * dofdamp * m_d_theta_tmp[j];
@@ -315,19 +304,19 @@ void IK_QJacobian::InvertSDLS()
}
// weight + prevent from doing angle updates with angles > max_angle_change
- MT_Scalar max_angle = 0.0, abs_angle;
+ double max_angle = 0.0, abs_angle;
for (j = 0; j < m_dof; j++) {
m_d_theta[j] *= m_weight[j];
- abs_angle = MT_abs(m_d_theta[j]);
+ abs_angle = fabs(m_d_theta[j]);
if (abs_angle > max_angle)
max_angle = abs_angle;
}
if (max_angle > max_angle_change) {
- MT_Scalar damp = (max_angle_change) / (max_angle_change + max_angle);
+ double damp = (max_angle_change) / (max_angle_change + max_angle);
for (j = 0; j < m_dof; j++)
m_d_theta[j] *= damp;
@@ -353,12 +342,12 @@ void IK_QJacobian::InvertDLS()
// find the smallest non-zero W value, anything below epsilon is
// treated as zero
- MT_Scalar epsilon = 1e-10;
- MT_Scalar max_angle_change = 0.1;
- MT_Scalar x_length = sqrt(TNT::dot_prod(m_beta, m_beta));
+ double epsilon = 1e-10;
+ double max_angle_change = 0.1;
+ double x_length = sqrt(m_beta.dot(m_beta));
int i, j;
- MT_Scalar w_min = MT_INFINITY;
+ double w_min = std::numeric_limits<double>::max();
for (i = 0; i < m_svd_w.size(); i++) {
if (m_svd_w[i] > epsilon && m_svd_w[i] < w_min)
@@ -367,8 +356,8 @@ void IK_QJacobian::InvertDLS()
// compute lambda damping term
- MT_Scalar d = x_length / max_angle_change;
- MT_Scalar lambda;
+ double d = x_length / max_angle_change;
+ double lambda;
if (w_min <= d / 2)
lambda = d / 2;
@@ -386,20 +375,19 @@ void IK_QJacobian::InvertDLS()
// rather than matrix*matrix products
// compute Ut*Beta
- TNT::transpose(m_svd_u, m_svd_u_t);
- TNT::matmult(m_svd_u_beta, m_svd_u_t, m_beta);
+ m_svd_u_beta = m_svd_u.transpose() * m_beta;
- m_d_theta = 0.0;
+ m_d_theta.setZero();
for (i = 0; i < m_svd_w.size(); i++) {
if (m_svd_w[i] > epsilon) {
- MT_Scalar wInv = m_svd_w[i] / (m_svd_w[i] * m_svd_w[i] + lambda);
+ double wInv = m_svd_w[i] / (m_svd_w[i] * m_svd_w[i] + lambda);
// compute V*Winv*Ut*Beta
m_svd_u_beta[i] *= wInv;
for (j = 0; j < m_d_theta.size(); j++)
- m_d_theta[j] += m_svd_v[j][i] * m_svd_u_beta[i];
+ m_d_theta[j] += m_svd_v(j, i) * m_svd_u_beta[i];
}
}
@@ -407,31 +395,31 @@ void IK_QJacobian::InvertDLS()
m_d_theta[j] *= m_weight[j];
}
-void IK_QJacobian::Lock(int dof_id, MT_Scalar delta)
+void IK_QJacobian::Lock(int dof_id, double delta)
{
int i;
for (i = 0; i < m_task_size; i++) {
- m_beta[i] -= m_jacobian[i][dof_id] * delta;
- m_jacobian[i][dof_id] = 0.0;
+ m_beta[i] -= m_jacobian(i, dof_id) * delta;
+ m_jacobian(i, dof_id) = 0.0;
}
m_norm[dof_id] = 0.0; // unneeded
m_d_theta[dof_id] = 0.0;
}
-MT_Scalar IK_QJacobian::AngleUpdate(int dof_id) const
+double IK_QJacobian::AngleUpdate(int dof_id) const
{
return m_d_theta[dof_id];
}
-MT_Scalar IK_QJacobian::AngleUpdateNorm() const
+double IK_QJacobian::AngleUpdateNorm() const
{
int i;
- MT_Scalar mx = 0.0, dtheta_abs;
+ double mx = 0.0, dtheta_abs;
for (i = 0; i < m_d_theta.size(); i++) {
- dtheta_abs = MT_abs(m_d_theta[i] * m_d_norm_weight[i]);
+ dtheta_abs = fabs(m_d_theta[i] * m_d_norm_weight[i]);
if (dtheta_abs > mx)
mx = dtheta_abs;
}
@@ -439,7 +427,7 @@ MT_Scalar IK_QJacobian::AngleUpdateNorm() const
return mx;
}
-void IK_QJacobian::SetDoFWeight(int dof, MT_Scalar weight)
+void IK_QJacobian::SetDoFWeight(int dof, double weight)
{
m_weight[dof] = weight;
m_weight_sqrt[dof] = sqrt(weight);
diff --git a/intern/iksolver/intern/IK_QJacobian.h b/intern/iksolver/intern/IK_QJacobian.h
index b4b5a0402e6..f541866c6a7 100644
--- a/intern/iksolver/intern/IK_QJacobian.h
+++ b/intern/iksolver/intern/IK_QJacobian.h
@@ -31,44 +31,36 @@
* \ingroup iksolver
*/
+#pragma once
-#ifndef __IK_QJACOBIAN_H__
-
-#define __IK_QJACOBIAN_H__
-
-#include "TNT/cmat.h"
-#include <vector>
-#include "MT_Vector3.h"
+#include "IK_Math.h"
class IK_QJacobian
{
public:
- typedef TNT::Matrix<MT_Scalar> TMatrix;
- typedef TNT::Vector<MT_Scalar> TVector;
-
IK_QJacobian();
~IK_QJacobian();
// Call once to initialize
void ArmMatrices(int dof, int task_size);
- void SetDoFWeight(int dof, MT_Scalar weight);
+ void SetDoFWeight(int dof, double weight);
// Iteratively called
- void SetBetas(int id, int size, const MT_Vector3& v);
- void SetDerivatives(int id, int dof_id, const MT_Vector3& v, MT_Scalar norm_weight);
+ void SetBetas(int id, int size, const Vector3d& v);
+ void SetDerivatives(int id, int dof_id, const Vector3d& v, double norm_weight);
void Invert();
- MT_Scalar AngleUpdate(int dof_id) const;
- MT_Scalar AngleUpdateNorm() const;
+ double AngleUpdate(int dof_id) const;
+ double AngleUpdateNorm() const;
// DoF locking for inner clamping loop
- void Lock(int dof_id, MT_Scalar delta);
+ void Lock(int dof_id, double delta);
// Secondary task
bool ComputeNullProjection();
- void Restrict(TVector& d_theta, TMatrix& null);
+ void Restrict(VectorXd& d_theta, MatrixXd& nullspace);
void SubTask(IK_QJacobian& jacobian);
private:
@@ -80,41 +72,35 @@ private:
bool m_transpose;
// the jacobian matrix and it's null space projector
- TMatrix m_jacobian, m_jacobian_tmp;
- TMatrix m_null;
+ MatrixXd m_jacobian, m_jacobian_tmp;
+ MatrixXd m_nullspace;
/// the vector of intermediate betas
- TVector m_beta;
+ VectorXd m_beta;
/// the vector of computed angle changes
- TVector m_d_theta;
- TVector m_d_norm_weight;
+ VectorXd m_d_theta;
+ VectorXd m_d_norm_weight;
/// space required for SVD computation
+ VectorXd m_svd_w;
+ MatrixXd m_svd_v;
+ MatrixXd m_svd_u;
- TVector m_svd_w;
- TMatrix m_svd_v;
- TMatrix m_svd_u;
- TVector m_work1;
- TVector m_work2;
-
- TMatrix m_svd_u_t;
- TVector m_svd_u_beta;
+ VectorXd m_svd_u_beta;
// space required for SDLS
bool m_sdls;
- TVector m_norm;
- TVector m_d_theta_tmp;
- MT_Scalar m_min_damp;
+ VectorXd m_norm;
+ VectorXd m_d_theta_tmp;
+ double m_min_damp;
// null space task vector
- TVector m_alpha;
+ VectorXd m_alpha;
// dof weighting
- TVector m_weight;
- TVector m_weight_sqrt;
+ VectorXd m_weight;
+ VectorXd m_weight_sqrt;
};
-#endif
-
diff --git a/intern/iksolver/intern/IK_QJacobianSolver.cpp b/intern/iksolver/intern/IK_QJacobianSolver.cpp
index 75f51f566c9..b78270eb87f 100644
--- a/intern/iksolver/intern/IK_QJacobianSolver.cpp
+++ b/intern/iksolver/intern/IK_QJacobianSolver.cpp
@@ -32,8 +32,8 @@
#include <stdio.h>
+
#include "IK_QJacobianSolver.h"
-#include "MT_Quaternion.h"
//#include "analyze.h"
IK_QJacobianSolver::IK_QJacobianSolver()
@@ -43,10 +43,10 @@ IK_QJacobianSolver::IK_QJacobianSolver()
m_rootmatrix.setIdentity();
}
-MT_Scalar IK_QJacobianSolver::ComputeScale()
+double IK_QJacobianSolver::ComputeScale()
{
std::vector<IK_QSegment *>::iterator seg;
- MT_Scalar length = 0.0f;
+ double length = 0.0f;
for (seg = m_segments.begin(); seg != m_segments.end(); seg++)
length += (*seg)->MaxExtension();
@@ -57,7 +57,7 @@ MT_Scalar IK_QJacobianSolver::ComputeScale()
return 1.0 / length;
}
-void IK_QJacobianSolver::Scale(MT_Scalar scale, std::list<IK_QTask *>& tasks)
+void IK_QJacobianSolver::Scale(double scale, std::list<IK_QTask *>& tasks)
{
std::list<IK_QTask *>::iterator task;
std::vector<IK_QSegment *>::iterator seg;
@@ -68,7 +68,7 @@ void IK_QJacobianSolver::Scale(MT_Scalar scale, std::list<IK_QTask *>& tasks)
for (seg = m_segments.begin(); seg != m_segments.end(); seg++)
(*seg)->Scale(scale);
- m_rootmatrix.getOrigin() *= scale;
+ m_rootmatrix.translation() *= scale;
m_goal *= scale;
m_polegoal *= scale;
}
@@ -102,7 +102,7 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *>& tasks)
// compute task id's and assing weights to task
int primary_size = 0, primary = 0;
int secondary_size = 0, secondary = 0;
- MT_Scalar primary_weight = 0.0, secondary_weight = 0.0;
+ double primary_weight = 0.0, secondary_weight = 0.0;
std::list<IK_QTask *>::iterator task;
for (task = tasks.begin(); task != tasks.end(); task++) {
@@ -122,15 +122,15 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *>& tasks)
}
}
- if (primary_size == 0 || MT_fuzzyZero(primary_weight))
+ if (primary_size == 0 || FuzzyZero(primary_weight))
return false;
m_secondary_enabled = (secondary > 0);
// rescale weights of tasks to sum up to 1
- MT_Scalar primary_rescale = 1.0 / primary_weight;
- MT_Scalar secondary_rescale;
- if (MT_fuzzyZero(secondary_weight))
+ double primary_rescale = 1.0 / primary_weight;
+ double secondary_rescale;
+ if (FuzzyZero(secondary_weight))
secondary_rescale = 0.0;
else
secondary_rescale = 1.0 / secondary_weight;
@@ -159,7 +159,7 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *>& tasks)
return true;
}
-void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, MT_Vector3& polegoal, float poleangle, bool getangle)
+void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, Vector3d& goal, Vector3d& polegoal, float poleangle, bool getangle)
{
m_poleconstraint = true;
m_poletip = tip;
@@ -169,27 +169,6 @@ void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& g
m_getpoleangle = getangle;
}
-static MT_Scalar safe_acos(MT_Scalar f)
-{
- // acos that does not return NaN with rounding errors
- if (f <= -1.0) return MT_PI;
- else if (f >= 1.0) return 0.0;
- else return acos(f);
-}
-
-static MT_Vector3 normalize(const MT_Vector3& v)
-{
- // a sane normalize function that doesn't give (1, 0, 0) in case
- // of a zero length vector, like MT_Vector3.normalize
- MT_Scalar len = v.length();
- return MT_fuzzyZero(len) ? MT_Vector3(0, 0, 0) : v / len;
-}
-
-static float angle(const MT_Vector3& v1, const MT_Vector3& v2)
-{
- return safe_acos(v1.dot(v2));
-}
-
void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask *>& tasks)
{
// this function will be called before and after solving. calling it before
@@ -215,37 +194,38 @@ void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTa
// get positions and rotations
root->UpdateTransform(m_rootmatrix);
- const MT_Vector3 rootpos = root->GlobalStart();
- const MT_Vector3 endpos = m_poletip->GlobalEnd();
- const MT_Matrix3x3& rootbasis = root->GlobalTransform().getBasis();
+ const Vector3d rootpos = root->GlobalStart();
+ const Vector3d endpos = m_poletip->GlobalEnd();
+ const Matrix3d& rootbasis = root->GlobalTransform().linear();
// construct "lookat" matrices (like gluLookAt), based on a direction and
// an up vector, with the direction going from the root to the end effector
// and the up vector going from the root to the pole constraint position.
- MT_Vector3 dir = normalize(endpos - rootpos);
- MT_Vector3 rootx = rootbasis.getColumn(0);
- MT_Vector3 rootz = rootbasis.getColumn(2);
- MT_Vector3 up = rootx * cos(m_poleangle) + rootz *sin(m_poleangle);
+ Vector3d dir = normalize(endpos - rootpos);
+ Vector3d rootx = rootbasis.col(0);
+ Vector3d rootz = rootbasis.col(2);
+ Vector3d up = rootx * cos(m_poleangle) + rootz *sin(m_poleangle);
// in post, don't rotate towards the goal but only correct the pole up
- MT_Vector3 poledir = (m_getpoleangle) ? dir : normalize(m_goal - rootpos);
- MT_Vector3 poleup = normalize(m_polegoal - rootpos);
+ Vector3d poledir = (m_getpoleangle) ? dir : normalize(m_goal - rootpos);
+ Vector3d poleup = normalize(m_polegoal - rootpos);
- MT_Matrix3x3 mat, polemat;
+ Matrix3d mat, polemat;
- mat[0] = normalize(MT_cross(dir, up));
- mat[1] = MT_cross(mat[0], dir);
- mat[2] = -dir;
+ mat.row(0) = normalize(dir.cross(up));
+ mat.row(1) = mat.row(0).cross(dir);
+ mat.row(2) = -dir;
- polemat[0] = normalize(MT_cross(poledir, poleup));
- polemat[1] = MT_cross(polemat[0], poledir);
- polemat[2] = -poledir;
+ polemat.row(0) = normalize(poledir.cross(poleup));
+ polemat.row(1) = polemat.row(0).cross(poledir);
+ polemat.row(2) = -poledir;
if (m_getpoleangle) {
// we compute the pole angle that to rotate towards the target
- m_poleangle = angle(mat[1], polemat[1]);
+ m_poleangle = angle(mat.row(1), polemat.row(1));
- if (rootz.dot(mat[1] * cos(m_poleangle) + mat[0] * sin(m_poleangle)) > 0.0)
+ double dt = rootz.dot(mat.row(1) * cos(m_poleangle) + mat.row(0) * sin(m_poleangle));
+ if (dt > 0.0)
m_poleangle = -m_poleangle;
// solve again, with the pole angle we just computed
@@ -257,18 +237,20 @@ void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTa
// desired rotation based on the pole vector constraint. we use
// transpose instead of inverse because we have orthogonal matrices
// anyway, and in case of a singular matrix we don't get NaN's.
- MT_Transform trans(MT_Point3(0, 0, 0), polemat.transposed() * mat);
+ Affine3d trans;
+ trans.linear() = polemat.transpose() * mat;
+ trans.translation() = Vector3d(0, 0, 0);
m_rootmatrix = trans * m_rootmatrix;
}
}
-bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm)
+bool IK_QJacobianSolver::UpdateAngles(double& norm)
{
// assing each segment a unique id for the jacobian
std::vector<IK_QSegment *>::iterator seg;
IK_QSegment *qseg, *minseg = NULL;
- MT_Scalar minabsdelta = 1e10, absdelta;
- MT_Vector3 delta, mindelta;
+ double minabsdelta = 1e10, absdelta;
+ Vector3d delta, mindelta;
bool locked = false, clamp[3];
int i, mindof = 0;
@@ -280,9 +262,9 @@ bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm)
if (qseg->UpdateAngle(m_jacobian, delta, clamp)) {
for (i = 0; i < qseg->NumberOfDoF(); i++) {
if (clamp[i] && !qseg->Locked(i)) {
- absdelta = MT_abs(delta[i]);
+ absdelta = fabs(delta[i]);
- if (absdelta < MT_EPSILON) {
+ if (absdelta < IK_EPSILON) {
qseg->Lock(i, m_jacobian, delta);
locked = true;
}
@@ -320,7 +302,7 @@ bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm)
bool IK_QJacobianSolver::Solve(
IK_QSegment *root,
std::list<IK_QTask *> tasks,
- const MT_Scalar,
+ const double,
const int max_iterations
)
{
@@ -349,7 +331,7 @@ bool IK_QJacobianSolver::Solve(
(*task)->ComputeJacobian(m_jacobian_sub);
}
- MT_Scalar norm = 0.0;
+ double norm = 0.0;
do {
// invert jacobian
@@ -372,7 +354,7 @@ bool IK_QJacobianSolver::Solve(
(*seg)->UnLock();
// compute angle update norm
- MT_Scalar maxnorm = m_jacobian.AngleUpdateNorm();
+ double maxnorm = m_jacobian.AngleUpdateNorm();
if (maxnorm > norm)
norm = maxnorm;
@@ -384,7 +366,7 @@ bool IK_QJacobianSolver::Solve(
}
if (m_poleconstraint)
- root->PrependBasis(m_rootmatrix.getBasis());
+ root->PrependBasis(m_rootmatrix.linear());
Scale(1.0f / scale, tasks);
diff --git a/intern/iksolver/intern/IK_QJacobianSolver.h b/intern/iksolver/intern/IK_QJacobianSolver.h
index 646f952b9ff..545ef91c710 100644
--- a/intern/iksolver/intern/IK_QJacobianSolver.h
+++ b/intern/iksolver/intern/IK_QJacobianSolver.h
@@ -30,10 +30,7 @@
* \ingroup iksolver
*/
-
-#ifndef __IK_QJACOBIANSOLVER_H__
-
-#define __IK_QJACOBIANSOLVER_H__
+#pragma once
/**
* @author Laurence Bourn
@@ -43,8 +40,7 @@
#include <vector>
#include <list>
-#include "MT_Vector3.h"
-#include "MT_Transform.h"
+#include "IK_Math.h"
#include "IK_QJacobian.h"
#include "IK_QSegment.h"
#include "IK_QTask.h"
@@ -56,8 +52,8 @@ public:
~IK_QJacobianSolver() {}
// setup pole vector constraint
- void SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal,
- MT_Vector3& polegoal, float poleangle, bool getangle);
+ void SetPoleVectorConstraint(IK_QSegment *tip, Vector3d& goal,
+ Vector3d& polegoal, float poleangle, bool getangle);
float GetPoleAngle() { return m_poleangle; }
// call setup once before solving, if it fails don't solve
@@ -67,17 +63,17 @@ public:
bool Solve(
IK_QSegment *root,
std::list<IK_QTask*> tasks,
- const MT_Scalar tolerance,
+ const double tolerance,
const int max_iterations
);
private:
void AddSegmentList(IK_QSegment *seg);
- bool UpdateAngles(MT_Scalar& norm);
+ bool UpdateAngles(double& norm);
void ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask*>& tasks);
- MT_Scalar ComputeScale();
- void Scale(MT_Scalar scale, std::list<IK_QTask*>& tasks);
+ double ComputeScale();
+ void Scale(double scale, std::list<IK_QTask*>& tasks);
private:
@@ -88,15 +84,13 @@ private:
std::vector<IK_QSegment*> m_segments;
- MT_Transform m_rootmatrix;
+ Affine3d m_rootmatrix;
bool m_poleconstraint;
bool m_getpoleangle;
- MT_Vector3 m_goal;
- MT_Vector3 m_polegoal;
+ Vector3d m_goal;
+ Vector3d m_polegoal;
float m_poleangle;
IK_QSegment *m_poletip;
};
-#endif
-
diff --git a/intern/iksolver/intern/IK_QSegment.cpp b/intern/iksolver/intern/IK_QSegment.cpp
index e511d8233a2..23b094db279 100644
--- a/intern/iksolver/intern/IK_QSegment.cpp
+++ b/intern/iksolver/intern/IK_QSegment.cpp
@@ -32,192 +32,6 @@
#include "IK_QSegment.h"
-#include <cmath>
-
-// Utility functions
-
-static MT_Matrix3x3 RotationMatrix(MT_Scalar sine, MT_Scalar cosine, int axis)
-{
- if (axis == 0)
- return MT_Matrix3x3(1.0, 0.0, 0.0,
- 0.0, cosine, -sine,
- 0.0, sine, cosine);
- else if (axis == 1)
- return MT_Matrix3x3(cosine, 0.0, sine,
- 0.0, 1.0, 0.0,
- -sine, 0.0, cosine);
- else
- return MT_Matrix3x3(cosine, -sine, 0.0,
- sine, cosine, 0.0,
- 0.0, 0.0, 1.0);
-}
-
-static MT_Matrix3x3 RotationMatrix(MT_Scalar angle, int axis)
-{
- return RotationMatrix(sin(angle), cos(angle), axis);
-}
-
-
-static MT_Scalar EulerAngleFromMatrix(const MT_Matrix3x3& R, int axis)
-{
- MT_Scalar t = sqrt(R[0][0] * R[0][0] + R[0][1] * R[0][1]);
-
- if (t > 16.0 * MT_EPSILON) {
- if (axis == 0) return -atan2(R[1][2], R[2][2]);
- else if (axis == 1) return atan2(-R[0][2], t);
- else return -atan2(R[0][1], R[0][0]);
- }
- else {
- if (axis == 0) return -atan2(-R[2][1], R[1][1]);
- else if (axis == 1) return atan2(-R[0][2], t);
- else return 0.0f;
- }
-}
-
-static MT_Scalar safe_acos(MT_Scalar f)
-{
- if (f <= -1.0)
- return MT_PI;
- else if (f >= 1.0)
- return 0.0;
- else
- return acos(f);
-}
-
-static MT_Scalar ComputeTwist(const MT_Matrix3x3& R)
-{
- // qy and qw are the y and w components of the quaternion from R
- MT_Scalar qy = R[0][2] - R[2][0];
- MT_Scalar qw = R[0][0] + R[1][1] + R[2][2] + 1;
-
- MT_Scalar tau = 2.0 * atan2(qy, qw);
-
- return tau;
-}
-
-static MT_Matrix3x3 ComputeTwistMatrix(MT_Scalar tau)
-{
- return RotationMatrix(tau, 1);
-}
-
-static void RemoveTwist(MT_Matrix3x3& R)
-{
- // compute twist parameter
- MT_Scalar tau = ComputeTwist(R);
-
- // compute twist matrix
- MT_Matrix3x3 T = ComputeTwistMatrix(tau);
-
- // remove twist
- R = R * T.transposed();
-}
-
-static MT_Vector3 SphericalRangeParameters(const MT_Matrix3x3& R)
-{
- // compute twist parameter
- MT_Scalar tau = ComputeTwist(R);
-
- // compute swing parameters
- MT_Scalar num = 2.0 * (1.0 + R[1][1]);
-
- // singularity at pi
- if (MT_abs(num) < MT_EPSILON)
- // TODO: this does now rotation of size pi over z axis, but could
- // be any axis, how to deal with this i'm not sure, maybe don't
- // enforce limits at all then
- return MT_Vector3(0.0, tau, 1.0);
-
- num = 1.0 / sqrt(num);
- MT_Scalar ax = -R[2][1] * num;
- MT_Scalar az = R[0][1] * num;
-
- return MT_Vector3(ax, tau, az);
-}
-
-static MT_Matrix3x3 ComputeSwingMatrix(MT_Scalar ax, MT_Scalar az)
-{
- // length of (ax, 0, az) = sin(theta/2)
- MT_Scalar sine2 = ax * ax + az * az;
- MT_Scalar cosine2 = sqrt((sine2 >= 1.0) ? 0.0 : 1.0 - sine2);
-
- // compute swing matrix
- MT_Matrix3x3 S(MT_Quaternion(ax, 0.0, az, -cosine2));
-
- return S;
-}
-
-static MT_Vector3 MatrixToAxisAngle(const MT_Matrix3x3& R)
-{
- MT_Vector3 delta = MT_Vector3(R[2][1] - R[1][2],
- R[0][2] - R[2][0],
- R[1][0] - R[0][1]);
-
- MT_Scalar c = safe_acos((R[0][0] + R[1][1] + R[2][2] - 1) / 2);
- MT_Scalar l = delta.length();
-
- if (!MT_fuzzyZero(l))
- delta *= c / l;
-
- return delta;
-}
-
-static bool EllipseClamp(MT_Scalar& ax, MT_Scalar& az, MT_Scalar *amin, MT_Scalar *amax)
-{
- MT_Scalar xlim, zlim, x, z;
-
- if (ax < 0.0) {
- x = -ax;
- xlim = -amin[0];
- }
- else {
- x = ax;
- xlim = amax[0];
- }
-
- if (az < 0.0) {
- z = -az;
- zlim = -amin[1];
- }
- else {
- z = az;
- zlim = amax[1];
- }
-
- if (MT_fuzzyZero(xlim) || MT_fuzzyZero(zlim)) {
- if (x <= xlim && z <= zlim)
- return false;
-
- if (x > xlim)
- x = xlim;
- if (z > zlim)
- z = zlim;
- }
- else {
- MT_Scalar invx = 1.0 / (xlim * xlim);
- MT_Scalar invz = 1.0 / (zlim * zlim);
-
- if ((x * x * invx + z * z * invz) <= 1.0)
- return false;
-
- if (MT_fuzzyZero(x)) {
- x = 0.0;
- z = zlim;
- }
- else {
- MT_Scalar rico = z / x;
- MT_Scalar old_x = x;
- x = sqrt(1.0 / (invx + invz * rico * rico));
- if (old_x < 0.0)
- x = -x;
- z = rico * x;
- }
- }
-
- ax = (ax < 0.0) ? -x : x;
- az = (az < 0.0) ? -z : z;
-
- return true;
-}
// IK_QSegment
@@ -230,10 +44,10 @@ IK_QSegment::IK_QSegment(int num_DoF, bool translational)
m_max_extension = 0.0;
- m_start = MT_Vector3(0, 0, 0);
+ m_start = Vector3d(0, 0, 0);
m_rest_basis.setIdentity();
m_basis.setIdentity();
- m_translation = MT_Vector3(0, 0, 0);
+ m_translation = Vector3d(0, 0, 0);
m_orig_basis = m_basis;
m_orig_translation = m_translation;
@@ -252,13 +66,13 @@ void IK_QSegment::Reset()
}
void IK_QSegment::SetTransform(
- const MT_Vector3& start,
- const MT_Matrix3x3& rest_basis,
- const MT_Matrix3x3& basis,
- const MT_Scalar length
+ const Vector3d& start,
+ const Matrix3d& rest_basis,
+ const Matrix3d& basis,
+ const double length
)
{
- m_max_extension = start.length() + length;
+ m_max_extension = start.norm() + length;
m_start = start;
m_rest_basis = rest_basis;
@@ -266,16 +80,16 @@ void IK_QSegment::SetTransform(
m_orig_basis = basis;
SetBasis(basis);
- m_translation = MT_Vector3(0, length, 0);
+ m_translation = Vector3d(0, length, 0);
m_orig_translation = m_translation;
}
-MT_Matrix3x3 IK_QSegment::BasisChange() const
+Matrix3d IK_QSegment::BasisChange() const
{
- return m_orig_basis.transposed() * m_basis;
+ return m_orig_basis.transpose() * m_basis;
}
-MT_Vector3 IK_QSegment::TranslationChange() const
+Vector3d IK_QSegment::TranslationChange() const
{
return m_translation - m_orig_translation;
}
@@ -327,13 +141,13 @@ void IK_QSegment::RemoveChild(IK_QSegment *child)
}
}
-void IK_QSegment::UpdateTransform(const MT_Transform& global)
+void IK_QSegment::UpdateTransform(const Affine3d& global)
{
// compute the global transform at the end of the segment
- m_global_start = global.getOrigin() + global.getBasis() * m_start;
+ m_global_start = global.translation() + global.linear() * m_start;
- m_global_transform.setOrigin(m_global_start);
- m_global_transform.setBasis(global.getBasis() * m_rest_basis * m_basis);
+ m_global_transform.translation() = m_global_start;
+ m_global_transform.linear() = global.linear() * m_rest_basis * m_basis;
m_global_transform.translate(m_translation);
// update child transforms
@@ -341,18 +155,18 @@ void IK_QSegment::UpdateTransform(const MT_Transform& global)
seg->UpdateTransform(m_global_transform);
}
-void IK_QSegment::PrependBasis(const MT_Matrix3x3& mat)
+void IK_QSegment::PrependBasis(const Matrix3d& mat)
{
m_basis = m_rest_basis.inverse() * mat * m_rest_basis * m_basis;
}
-void IK_QSegment::Scale(MT_Scalar scale)
+void IK_QSegment::Scale(double scale)
{
m_start *= scale;
m_translation *= scale;
m_orig_translation *= scale;
m_global_start *= scale;
- m_global_transform.getOrigin() *= scale;
+ m_global_transform.translation() *= scale;
m_max_extension *= scale;
}
@@ -363,19 +177,19 @@ IK_QSphericalSegment::IK_QSphericalSegment()
{
}
-MT_Vector3 IK_QSphericalSegment::Axis(int dof) const
+Vector3d IK_QSphericalSegment::Axis(int dof) const
{
- return m_global_transform.getBasis().getColumn(dof);
+ return m_global_transform.linear().col(dof);
}
-void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
+void IK_QSphericalSegment::SetLimit(int axis, double lmin, double lmax)
{
if (lmin > lmax)
return;
if (axis == 1) {
- lmin = MT_clamp(lmin, -MT_PI, MT_PI);
- lmax = MT_clamp(lmax, -MT_PI, MT_PI);
+ lmin = Clamp(lmin, -M_PI, M_PI);
+ lmax = Clamp(lmax, -M_PI, M_PI);
m_min_y = lmin;
m_max_y = lmax;
@@ -384,8 +198,8 @@ void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
}
else {
// clamp and convert to axis angle parameters
- lmin = MT_clamp(lmin, -MT_PI, MT_PI);
- lmax = MT_clamp(lmax, -MT_PI, MT_PI);
+ lmin = Clamp(lmin, -M_PI, M_PI);
+ lmax = Clamp(lmax, -M_PI, M_PI);
lmin = sin(lmin * 0.5);
lmax = sin(lmax * 0.5);
@@ -403,17 +217,17 @@ void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
}
}
-void IK_QSphericalSegment::SetWeight(int axis, MT_Scalar weight)
+void IK_QSphericalSegment::SetWeight(int axis, double weight)
{
m_weight[axis] = weight;
}
-bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
+bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp)
{
if (m_locked[0] && m_locked[1] && m_locked[2])
return false;
- MT_Vector3 dq;
+ Vector3d dq;
dq.x() = jacobian.AngleUpdate(m_DoF_id);
dq.y() = jacobian.AngleUpdate(m_DoF_id + 1);
dq.z() = jacobian.AngleUpdate(m_DoF_id + 2);
@@ -421,27 +235,27 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
// Directly update the rotation matrix, with Rodrigues' rotation formula,
// to avoid singularities and allow smooth integration.
- MT_Scalar theta = dq.length();
+ double theta = dq.norm();
- if (!MT_fuzzyZero(theta)) {
- MT_Vector3 w = dq * (1.0 / theta);
+ if (!FuzzyZero(theta)) {
+ Vector3d w = dq * (1.0 / theta);
- MT_Scalar sine = sin(theta);
- MT_Scalar cosine = cos(theta);
- MT_Scalar cosineInv = 1 - cosine;
+ double sine = sin(theta);
+ double cosine = cos(theta);
+ double cosineInv = 1 - cosine;
- MT_Scalar xsine = w.x() * sine;
- MT_Scalar ysine = w.y() * sine;
- MT_Scalar zsine = w.z() * sine;
+ double xsine = w.x() * sine;
+ double ysine = w.y() * sine;
+ double zsine = w.z() * sine;
- MT_Scalar xxcosine = w.x() * w.x() * cosineInv;
- MT_Scalar xycosine = w.x() * w.y() * cosineInv;
- MT_Scalar xzcosine = w.x() * w.z() * cosineInv;
- MT_Scalar yycosine = w.y() * w.y() * cosineInv;
- MT_Scalar yzcosine = w.y() * w.z() * cosineInv;
- MT_Scalar zzcosine = w.z() * w.z() * cosineInv;
+ double xxcosine = w.x() * w.x() * cosineInv;
+ double xycosine = w.x() * w.y() * cosineInv;
+ double xzcosine = w.x() * w.z() * cosineInv;
+ double yycosine = w.y() * w.y() * cosineInv;
+ double yzcosine = w.y() * w.z() * cosineInv;
+ double zzcosine = w.z() * w.z() * cosineInv;
- MT_Matrix3x3 M(
+ Matrix3d M = CreateMatrix(
cosine + xxcosine, -zsine + xycosine, ysine + xzcosine,
zsine + xycosine, cosine + yycosine, -xsine + yzcosine,
-ysine + xzcosine, xsine + yzcosine, cosine + zzcosine);
@@ -455,7 +269,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
if (m_limit_y == false && m_limit_x == false && m_limit_z == false)
return false;
- MT_Vector3 a = SphericalRangeParameters(m_new_basis);
+ Vector3d a = SphericalRangeParameters(m_new_basis);
if (m_locked[0])
a.x() = m_locked_ax;
@@ -464,7 +278,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
if (m_locked[2])
a.z() = m_locked_az;
- MT_Scalar ax = a.x(), ay = a.y(), az = a.z();
+ double ax = a.x(), ay = a.y(), az = a.z();
clamp[0] = clamp[1] = clamp[2] = false;
@@ -512,7 +326,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
m_new_basis = ComputeSwingMatrix(ax, az) * ComputeTwistMatrix(ay);
- delta = MatrixToAxisAngle(m_basis.transposed() * m_new_basis);
+ delta = MatrixToAxisAngle(m_basis.transpose() * m_new_basis);
if (!(m_locked[0] || m_locked[2]) && (clamp[0] || clamp[2])) {
m_locked_ax = ax;
@@ -525,7 +339,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
return true;
}
-void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
+void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta)
{
if (dof == 1) {
m_locked[1] = true;
@@ -557,7 +371,7 @@ IK_QRevoluteSegment::IK_QRevoluteSegment(int axis)
{
}
-void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis)
+void IK_QRevoluteSegment::SetBasis(const Matrix3d& basis)
{
if (m_axis == 1) {
m_angle = ComputeTwist(basis);
@@ -569,12 +383,12 @@ void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis)
}
}
-MT_Vector3 IK_QRevoluteSegment::Axis(int) const
+Vector3d IK_QRevoluteSegment::Axis(int) const
{
- return m_global_transform.getBasis().getColumn(m_axis);
+ return m_global_transform.linear().col(m_axis);
}
-bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
+bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp)
{
if (m_locked[0])
return false;
@@ -599,7 +413,7 @@ bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3&
return true;
}
-void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta)
+void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, Vector3d& delta)
{
m_locked[0] = true;
jacobian.Lock(m_DoF_id, delta[0]);
@@ -611,14 +425,14 @@ void IK_QRevoluteSegment::UpdateAngleApply()
m_basis = RotationMatrix(m_angle, m_axis);
}
-void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
+void IK_QRevoluteSegment::SetLimit(int axis, double lmin, double lmax)
{
if (lmin > lmax || m_axis != axis)
return;
// clamp and convert to axis angle parameters
- lmin = MT_clamp(lmin, -MT_PI, MT_PI);
- lmax = MT_clamp(lmax, -MT_PI, MT_PI);
+ lmin = Clamp(lmin, -M_PI, M_PI);
+ lmax = Clamp(lmax, -M_PI, M_PI);
m_min = lmin;
m_max = lmax;
@@ -626,7 +440,7 @@ void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
m_limit = true;
}
-void IK_QRevoluteSegment::SetWeight(int axis, MT_Scalar weight)
+void IK_QRevoluteSegment::SetWeight(int axis, double weight)
{
if (axis == m_axis)
m_weight[0] = weight;
@@ -639,23 +453,23 @@ IK_QSwingSegment::IK_QSwingSegment()
{
}
-void IK_QSwingSegment::SetBasis(const MT_Matrix3x3& basis)
+void IK_QSwingSegment::SetBasis(const Matrix3d& basis)
{
m_basis = basis;
RemoveTwist(m_basis);
}
-MT_Vector3 IK_QSwingSegment::Axis(int dof) const
+Vector3d IK_QSwingSegment::Axis(int dof) const
{
- return m_global_transform.getBasis().getColumn((dof == 0) ? 0 : 2);
+ return m_global_transform.linear().col((dof == 0) ? 0 : 2);
}
-bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
+bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp)
{
if (m_locked[0] && m_locked[1])
return false;
- MT_Vector3 dq;
+ Vector3d dq;
dq.x() = jacobian.AngleUpdate(m_DoF_id);
dq.y() = 0.0;
dq.z() = jacobian.AngleUpdate(m_DoF_id + 1);
@@ -663,23 +477,23 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del
// Directly update the rotation matrix, with Rodrigues' rotation formula,
// to avoid singularities and allow smooth integration.
- MT_Scalar theta = dq.length();
+ double theta = dq.norm();
- if (!MT_fuzzyZero(theta)) {
- MT_Vector3 w = dq * (1.0 / theta);
+ if (!FuzzyZero(theta)) {
+ Vector3d w = dq * (1.0 / theta);
- MT_Scalar sine = sin(theta);
- MT_Scalar cosine = cos(theta);
- MT_Scalar cosineInv = 1 - cosine;
+ double sine = sin(theta);
+ double cosine = cos(theta);
+ double cosineInv = 1 - cosine;
- MT_Scalar xsine = w.x() * sine;
- MT_Scalar zsine = w.z() * sine;
+ double xsine = w.x() * sine;
+ double zsine = w.z() * sine;
- MT_Scalar xxcosine = w.x() * w.x() * cosineInv;
- MT_Scalar xzcosine = w.x() * w.z() * cosineInv;
- MT_Scalar zzcosine = w.z() * w.z() * cosineInv;
+ double xxcosine = w.x() * w.x() * cosineInv;
+ double xzcosine = w.x() * w.z() * cosineInv;
+ double zzcosine = w.z() * w.z() * cosineInv;
- MT_Matrix3x3 M(
+ Matrix3d M = CreateMatrix(
cosine + xxcosine, -zsine, xzcosine,
zsine, cosine, -xsine,
xzcosine, xsine, cosine + zzcosine);
@@ -694,8 +508,8 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del
if (m_limit_x == false && m_limit_z == false)
return false;
- MT_Vector3 a = SphericalRangeParameters(m_new_basis);
- MT_Scalar ax = 0, az = 0;
+ Vector3d a = SphericalRangeParameters(m_new_basis);
+ double ax = 0, az = 0;
clamp[0] = clamp[1] = false;
@@ -732,13 +546,13 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del
m_new_basis = ComputeSwingMatrix(ax, az);
- delta = MatrixToAxisAngle(m_basis.transposed() * m_new_basis);
+ delta = MatrixToAxisAngle(m_basis.transpose() * m_new_basis);
delta[1] = delta[2]; delta[2] = 0.0;
return true;
}
-void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta)
+void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, Vector3d& delta)
{
m_locked[0] = m_locked[1] = true;
jacobian.Lock(m_DoF_id, delta[0]);
@@ -750,20 +564,20 @@ void IK_QSwingSegment::UpdateAngleApply()
m_basis = m_new_basis;
}
-void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
+void IK_QSwingSegment::SetLimit(int axis, double lmin, double lmax)
{
if (lmin > lmax)
return;
// clamp and convert to axis angle parameters
- lmin = MT_clamp(lmin, -MT_PI, MT_PI);
- lmax = MT_clamp(lmax, -MT_PI, MT_PI);
+ lmin = Clamp(lmin, -M_PI, M_PI);
+ lmax = Clamp(lmax, -M_PI, M_PI);
lmin = sin(lmin * 0.5);
lmax = sin(lmax * 0.5);
// put center of ellispe in the middle between min and max
- MT_Scalar offset = 0.5 * (lmin + lmax);
+ double offset = 0.5 * (lmin + lmax);
//lmax = lmax - offset;
if (axis == 0) {
@@ -784,7 +598,7 @@ void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
}
}
-void IK_QSwingSegment::SetWeight(int axis, MT_Scalar weight)
+void IK_QSwingSegment::SetWeight(int axis, double weight)
{
if (axis == 0)
m_weight[0] = weight;
@@ -800,7 +614,7 @@ IK_QElbowSegment::IK_QElbowSegment(int axis)
{
}
-void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis)
+void IK_QElbowSegment::SetBasis(const Matrix3d& basis)
{
m_basis = basis;
@@ -811,22 +625,22 @@ void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis)
m_basis = RotationMatrix(m_angle, m_axis) * ComputeTwistMatrix(m_twist);
}
-MT_Vector3 IK_QElbowSegment::Axis(int dof) const
+Vector3d IK_QElbowSegment::Axis(int dof) const
{
if (dof == 0) {
- MT_Vector3 v;
+ Vector3d v;
if (m_axis == 0)
- v = MT_Vector3(m_cos_twist, 0, m_sin_twist);
+ v = Vector3d(m_cos_twist, 0, m_sin_twist);
else
- v = MT_Vector3(-m_sin_twist, 0, m_cos_twist);
+ v = Vector3d(-m_sin_twist, 0, m_cos_twist);
- return m_global_transform.getBasis() * v;
+ return m_global_transform.linear() * v;
}
else
- return m_global_transform.getBasis().getColumn(1);
+ return m_global_transform.linear().col(1);
}
-bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
+bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp)
{
if (m_locked[0] && m_locked[1])
return false;
@@ -870,7 +684,7 @@ bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del
return (clamp[0] || clamp[1]);
}
-void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
+void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta)
{
if (dof == 0) {
m_locked[0] = true;
@@ -890,20 +704,20 @@ void IK_QElbowSegment::UpdateAngleApply()
m_sin_twist = sin(m_twist);
m_cos_twist = cos(m_twist);
- MT_Matrix3x3 A = RotationMatrix(m_angle, m_axis);
- MT_Matrix3x3 T = RotationMatrix(m_sin_twist, m_cos_twist, 1);
+ Matrix3d A = RotationMatrix(m_angle, m_axis);
+ Matrix3d T = RotationMatrix(m_sin_twist, m_cos_twist, 1);
m_basis = A * T;
}
-void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
+void IK_QElbowSegment::SetLimit(int axis, double lmin, double lmax)
{
if (lmin > lmax)
return;
// clamp and convert to axis angle parameters
- lmin = MT_clamp(lmin, -MT_PI, MT_PI);
- lmax = MT_clamp(lmax, -MT_PI, MT_PI);
+ lmin = Clamp(lmin, -M_PI, M_PI);
+ lmax = Clamp(lmax, -M_PI, M_PI);
if (axis == 1) {
m_min_twist = lmin;
@@ -917,7 +731,7 @@ void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
}
}
-void IK_QElbowSegment::SetWeight(int axis, MT_Scalar weight)
+void IK_QElbowSegment::SetWeight(int axis, double weight)
{
if (axis == m_axis)
m_weight[0] = weight;
@@ -963,16 +777,16 @@ IK_QTranslateSegment::IK_QTranslateSegment()
m_limit[0] = m_limit[1] = m_limit[2] = false;
}
-MT_Vector3 IK_QTranslateSegment::Axis(int dof) const
+Vector3d IK_QTranslateSegment::Axis(int dof) const
{
- return m_global_transform.getBasis().getColumn(m_axis[dof]);
+ return m_global_transform.linear().col(m_axis[dof]);
}
-bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp)
+bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp)
{
int dof_id = m_DoF_id, dof = 0, i, clamped = false;
- MT_Vector3 dx(0.0, 0.0, 0.0);
+ Vector3d dx(0.0, 0.0, 0.0);
for (i = 0; i < 3; i++) {
if (!m_axis_enabled[i]) {
@@ -1011,13 +825,13 @@ void IK_QTranslateSegment::UpdateAngleApply()
m_translation = m_new_translation;
}
-void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta)
+void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta)
{
m_locked[dof] = true;
jacobian.Lock(m_DoF_id + dof, delta[dof]);
}
-void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight)
+void IK_QTranslateSegment::SetWeight(int axis, double weight)
{
int i;
@@ -1026,7 +840,7 @@ void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight)
m_weight[i] = weight;
}
-void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
+void IK_QTranslateSegment::SetLimit(int axis, double lmin, double lmax)
{
if (lmax < lmin)
return;
@@ -1036,7 +850,7 @@ void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax)
m_limit[axis] = true;
}
-void IK_QTranslateSegment::Scale(MT_Scalar scale)
+void IK_QTranslateSegment::Scale(double scale)
{
int i;
diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h
index b40bf3739ff..74f157aa763 100644
--- a/intern/iksolver/intern/IK_QSegment.h
+++ b/intern/iksolver/intern/IK_QSegment.h
@@ -30,13 +30,9 @@
* \ingroup iksolver
*/
+#pragma once
-#ifndef __IK_QSEGMENT_H__
-#define __IK_QSEGMENT_H__
-
-#include "MT_Vector3.h"
-#include "MT_Transform.h"
-#include "MT_Matrix4x4.h"
+#include "IK_Math.h"
#include "IK_QJacobian.h"
#include <vector>
@@ -50,8 +46,7 @@
* Here we define the local coordinates of a joint as
* local_transform =
* translate(tr1) * rotation(A) * rotation(q) * translate(0,length,0)
- * We use the standard moto column ordered matrices. You can read
- * this as:
+ * You can read this as:
* - first translate by (0,length,0)
* - multiply by the rotation matrix derived from the current
* angle parameterization q.
@@ -73,10 +68,10 @@ public:
// length: length of this segment
void SetTransform(
- const MT_Vector3& start,
- const MT_Matrix3x3& rest_basis,
- const MT_Matrix3x3& basis,
- const MT_Scalar length
+ const Vector3d& start,
+ const Matrix3d& rest_basis,
+ const Matrix3d& basis,
+ const double length
);
// tree structure access
@@ -109,22 +104,22 @@ public:
{ m_DoF_id = dof_id; }
// the max distance of the end of this bone from the local origin.
- const MT_Scalar MaxExtension() const
+ const double MaxExtension() const
{ return m_max_extension; }
// the change in rotation and translation w.r.t. the rest pose
- MT_Matrix3x3 BasisChange() const;
- MT_Vector3 TranslationChange() const;
+ Matrix3d BasisChange() const;
+ Vector3d TranslationChange() const;
// the start and end of the segment
- const MT_Point3 &GlobalStart() const
+ const Vector3d GlobalStart() const
{ return m_global_start; }
- const MT_Point3 &GlobalEnd() const
- { return m_global_transform.getOrigin(); }
+ const Vector3d GlobalEnd() const
+ { return m_global_transform.translation(); }
// the global transformation at the end of the segment
- const MT_Transform &GlobalTransform() const
+ const Affine3d &GlobalTransform() const
{ return m_global_transform; }
// is a translational segment?
@@ -139,38 +134,38 @@ public:
{ m_locked[0] = m_locked[1] = m_locked[2] = false; }
// per dof joint weighting
- MT_Scalar Weight(int dof) const
+ double Weight(int dof) const
{ return m_weight[dof]; }
- void ScaleWeight(int dof, MT_Scalar scale)
+ void ScaleWeight(int dof, double scale)
{ m_weight[dof] *= scale; }
// recursively update the global coordinates of this segment, 'global'
// is the global transformation from the parent segment
- void UpdateTransform(const MT_Transform &global);
+ void UpdateTransform(const Affine3d &global);
// get axis from rotation matrix for derivative computation
- virtual MT_Vector3 Axis(int dof) const=0;
+ virtual Vector3d Axis(int dof) const=0;
// update the angles using the dTheta's computed using the jacobian matrix
- virtual bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*)=0;
- virtual void Lock(int, IK_QJacobian&, MT_Vector3&) {}
+ virtual bool UpdateAngle(const IK_QJacobian&, Vector3d&, bool*)=0;
+ virtual void Lock(int, IK_QJacobian&, Vector3d&) {}
virtual void UpdateAngleApply()=0;
// set joint limits
- virtual void SetLimit(int, MT_Scalar, MT_Scalar) {}
+ virtual void SetLimit(int, double, double) {}
// set joint weights (per axis)
- virtual void SetWeight(int, MT_Scalar) {}
+ virtual void SetWeight(int, double) {}
- virtual void SetBasis(const MT_Matrix3x3& basis) { m_basis = basis; }
+ virtual void SetBasis(const Matrix3d& basis) { m_basis = basis; }
// functions needed for pole vector constraint
- void PrependBasis(const MT_Matrix3x3& mat);
+ void PrependBasis(const Matrix3d& mat);
void Reset();
// scale
- virtual void Scale(MT_Scalar scale);
+ virtual void Scale(double scale);
protected:
@@ -188,28 +183,28 @@ protected:
// full transform =
// start * rest_basis * basis * translation
- MT_Vector3 m_start;
- MT_Matrix3x3 m_rest_basis;
- MT_Matrix3x3 m_basis;
- MT_Vector3 m_translation;
+ Vector3d m_start;
+ Matrix3d m_rest_basis;
+ Matrix3d m_basis;
+ Vector3d m_translation;
// original basis
- MT_Matrix3x3 m_orig_basis;
- MT_Vector3 m_orig_translation;
+ Matrix3d m_orig_basis;
+ Vector3d m_orig_translation;
// maximum extension of this segment
- MT_Scalar m_max_extension;
+ double m_max_extension;
// accumulated transformations starting from root
- MT_Point3 m_global_start;
- MT_Transform m_global_transform;
+ Vector3d m_global_start;
+ Affine3d m_global_transform;
// number degrees of freedom, (first) id of this segments DOF's
int m_num_DoF, m_DoF_id;
bool m_locked[3];
bool m_translational;
- MT_Scalar m_weight[3];
+ double m_weight[3];
};
class IK_QSphericalSegment : public IK_QSegment
@@ -217,23 +212,23 @@ class IK_QSphericalSegment : public IK_QSegment
public:
IK_QSphericalSegment();
- MT_Vector3 Axis(int dof) const;
+ Vector3d Axis(int dof) const;
- bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp);
- void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta);
+ bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp);
+ void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta);
void UpdateAngleApply();
- bool ComputeClampRotation(MT_Vector3& clamp);
+ bool ComputeClampRotation(Vector3d& clamp);
- void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax);
- void SetWeight(int axis, MT_Scalar weight);
+ void SetLimit(int axis, double lmin, double lmax);
+ void SetWeight(int axis, double weight);
private:
- MT_Matrix3x3 m_new_basis;
+ Matrix3d m_new_basis;
bool m_limit_x, m_limit_y, m_limit_z;
- MT_Scalar m_min[2], m_max[2];
- MT_Scalar m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z;
- MT_Scalar m_locked_ax, m_locked_ay, m_locked_az;
+ double m_min[2], m_max[2];
+ double m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z;
+ double m_locked_ax, m_locked_ay, m_locked_az;
};
class IK_QNullSegment : public IK_QSegment
@@ -241,11 +236,11 @@ class IK_QNullSegment : public IK_QSegment
public:
IK_QNullSegment();
- bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*) { return false; }
+ bool UpdateAngle(const IK_QJacobian&, Vector3d&, bool*) { return false; }
void UpdateAngleApply() {}
- MT_Vector3 Axis(int) const { return MT_Vector3(0, 0, 0); }
- void SetBasis(const MT_Matrix3x3&) { m_basis.setIdentity(); }
+ Vector3d Axis(int) const { return Vector3d(0, 0, 0); }
+ void SetBasis(const Matrix3d&) { m_basis.setIdentity(); }
};
class IK_QRevoluteSegment : public IK_QSegment
@@ -254,21 +249,21 @@ public:
// axis: the axis of the DoF, in range 0..2
IK_QRevoluteSegment(int axis);
- MT_Vector3 Axis(int dof) const;
+ Vector3d Axis(int dof) const;
- bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp);
- void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta);
+ bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp);
+ void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta);
void UpdateAngleApply();
- void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax);
- void SetWeight(int axis, MT_Scalar weight);
- void SetBasis(const MT_Matrix3x3& basis);
+ void SetLimit(int axis, double lmin, double lmax);
+ void SetWeight(int axis, double weight);
+ void SetBasis(const Matrix3d& basis);
private:
int m_axis;
- MT_Scalar m_angle, m_new_angle;
+ double m_angle, m_new_angle;
bool m_limit;
- MT_Scalar m_min, m_max;
+ double m_min, m_max;
};
class IK_QSwingSegment : public IK_QSegment
@@ -277,21 +272,21 @@ public:
// XZ DOF, uses one direct rotation
IK_QSwingSegment();
- MT_Vector3 Axis(int dof) const;
+ Vector3d Axis(int dof) const;
- bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp);
- void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta);
+ bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp);
+ void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta);
void UpdateAngleApply();
- void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax);
- void SetWeight(int axis, MT_Scalar weight);
- void SetBasis(const MT_Matrix3x3& basis);
+ void SetLimit(int axis, double lmin, double lmax);
+ void SetWeight(int axis, double weight);
+ void SetBasis(const Matrix3d& basis);
private:
- MT_Matrix3x3 m_new_basis;
+ Matrix3d m_new_basis;
bool m_limit_x, m_limit_z;
- MT_Scalar m_min[2], m_max[2];
- MT_Scalar m_max_x, m_max_z, m_offset_x, m_offset_z;
+ double m_min[2], m_max[2];
+ double m_max_x, m_max_z, m_offset_x, m_offset_z;
};
class IK_QElbowSegment : public IK_QSegment
@@ -301,24 +296,24 @@ public:
// X or Z, then rotate around Y (twist)
IK_QElbowSegment(int axis);
- MT_Vector3 Axis(int dof) const;
+ Vector3d Axis(int dof) const;
- bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp);
- void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta);
+ bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp);
+ void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta);
void UpdateAngleApply();
- void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax);
- void SetWeight(int axis, MT_Scalar weight);
- void SetBasis(const MT_Matrix3x3& basis);
+ void SetLimit(int axis, double lmin, double lmax);
+ void SetWeight(int axis, double weight);
+ void SetBasis(const Matrix3d& basis);
private:
int m_axis;
- MT_Scalar m_twist, m_angle, m_new_twist, m_new_angle;
- MT_Scalar m_cos_twist, m_sin_twist;
+ double m_twist, m_angle, m_new_twist, m_new_angle;
+ double m_cos_twist, m_sin_twist;
bool m_limit, m_limit_twist;
- MT_Scalar m_min, m_max, m_min_twist, m_max_twist;
+ double m_min, m_max, m_min_twist, m_max_twist;
};
class IK_QTranslateSegment : public IK_QSegment
@@ -329,23 +324,21 @@ public:
IK_QTranslateSegment(int axis1, int axis2);
IK_QTranslateSegment();
- MT_Vector3 Axis(int dof) const;
+ Vector3d Axis(int dof) const;
- bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp);
- void Lock(int, IK_QJacobian&, MT_Vector3&);
+ bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp);
+ void Lock(int, IK_QJacobian&, Vector3d&);
void UpdateAngleApply();
- void SetWeight(int axis, MT_Scalar weight);
- void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax);
+ void SetWeight(int axis, double weight);
+ void SetLimit(int axis, double lmin, double lmax);
- void Scale(MT_Scalar scale);
+ void Scale(double scale);
private:
int m_axis[3];
bool m_axis_enabled[3], m_limit[3];
- MT_Vector3 m_new_translation;
- MT_Scalar m_min[3], m_max[3];
+ Vector3d m_new_translation;
+ double m_min[3], m_max[3];
};
-#endif
-
diff --git a/intern/iksolver/intern/IK_QTask.cpp b/intern/iksolver/intern/IK_QTask.cpp
index 0ba716ff59d..d7c73865789 100644
--- a/intern/iksolver/intern/IK_QTask.cpp
+++ b/intern/iksolver/intern/IK_QTask.cpp
@@ -51,7 +51,7 @@ IK_QTask::IK_QTask(
IK_QPositionTask::IK_QPositionTask(
bool primary,
const IK_QSegment *segment,
- const MT_Vector3& goal
+ const Vector3d& goal
) :
IK_QTask(3, primary, true, segment), m_goal(goal)
{
@@ -73,10 +73,10 @@ IK_QPositionTask::IK_QPositionTask(
void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian)
{
// compute beta
- const MT_Vector3& pos = m_segment->GlobalEnd();
+ const Vector3d& pos = m_segment->GlobalEnd();
- MT_Vector3 d_pos = m_goal - pos;
- MT_Scalar length = d_pos.length();
+ Vector3d d_pos = m_goal - pos;
+ double length = d_pos.norm();
if (length > m_clamp_length)
d_pos = (m_clamp_length / length) * d_pos;
@@ -88,26 +88,26 @@ void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian)
const IK_QSegment *seg;
for (seg = m_segment; seg; seg = seg->Parent()) {
- MT_Vector3 p = seg->GlobalStart() - pos;
+ Vector3d p = seg->GlobalStart() - pos;
for (i = 0; i < seg->NumberOfDoF(); i++) {
- MT_Vector3 axis = seg->Axis(i) * m_weight;
+ Vector3d axis = seg->Axis(i) * m_weight;
if (seg->Translational())
jacobian.SetDerivatives(m_id, seg->DoFId() + i, axis, 1e2);
else {
- MT_Vector3 pa = p.cross(axis);
+ Vector3d pa = p.cross(axis);
jacobian.SetDerivatives(m_id, seg->DoFId() + i, pa, 1e0);
}
}
}
}
-MT_Scalar IK_QPositionTask::Distance() const
+double IK_QPositionTask::Distance() const
{
- const MT_Vector3& pos = m_segment->GlobalEnd();
- MT_Vector3 d_pos = m_goal - pos;
- return d_pos.length();
+ const Vector3d& pos = m_segment->GlobalEnd();
+ Vector3d d_pos = m_goal - pos;
+ return d_pos.norm();
}
// IK_QOrientationTask
@@ -115,7 +115,7 @@ MT_Scalar IK_QPositionTask::Distance() const
IK_QOrientationTask::IK_QOrientationTask(
bool primary,
const IK_QSegment *segment,
- const MT_Matrix3x3& goal
+ const Matrix3d& goal
) :
IK_QTask(3, primary, true, segment), m_goal(goal), m_distance(0.0)
{
@@ -124,17 +124,16 @@ IK_QOrientationTask::IK_QOrientationTask(
void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian)
{
// compute betas
- const MT_Matrix3x3& rot = m_segment->GlobalTransform().getBasis();
+ const Matrix3d& rot = m_segment->GlobalTransform().linear();
- MT_Matrix3x3 d_rotm = m_goal * rot.transposed();
- d_rotm.transpose();
+ Matrix3d d_rotm = (m_goal * rot.transpose()).transpose();
- MT_Vector3 d_rot;
- d_rot = -0.5 * MT_Vector3(d_rotm[2][1] - d_rotm[1][2],
- d_rotm[0][2] - d_rotm[2][0],
- d_rotm[1][0] - d_rotm[0][1]);
+ Vector3d d_rot;
+ d_rot = -0.5 * Vector3d(d_rotm(2, 1) - d_rotm(1, 2),
+ d_rotm(0, 2) - d_rotm(2, 0),
+ d_rotm(1, 0) - d_rotm(0, 1));
- m_distance = d_rot.length();
+ m_distance = d_rot.norm();
jacobian.SetBetas(m_id, m_size, m_weight * d_rot);
@@ -146,9 +145,9 @@ void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian)
for (i = 0; i < seg->NumberOfDoF(); i++) {
if (seg->Translational())
- jacobian.SetDerivatives(m_id, seg->DoFId() + i, MT_Vector3(0, 0, 0), 1e2);
+ jacobian.SetDerivatives(m_id, seg->DoFId() + i, Vector3d(0, 0, 0), 1e2);
else {
- MT_Vector3 axis = seg->Axis(i) * m_weight;
+ Vector3d axis = seg->Axis(i) * m_weight;
jacobian.SetDerivatives(m_id, seg->DoFId() + i, axis, 1e0);
}
}
@@ -160,18 +159,18 @@ void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian)
IK_QCenterOfMassTask::IK_QCenterOfMassTask(
bool primary,
const IK_QSegment *segment,
- const MT_Vector3& goal_center
+ const Vector3d& goal_center
) :
IK_QTask(3, primary, true, segment), m_goal_center(goal_center)
{
m_total_mass_inv = ComputeTotalMass(m_segment);
- if (!MT_fuzzyZero(m_total_mass_inv))
+ if (!FuzzyZero(m_total_mass_inv))
m_total_mass_inv = 1.0 / m_total_mass_inv;
}
-MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment)
+double IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment)
{
- MT_Scalar mass = /*seg->Mass()*/ 1.0;
+ double mass = /*seg->Mass()*/ 1.0;
const IK_QSegment *seg;
for (seg = segment->Child(); seg; seg = seg->Sibling())
@@ -180,9 +179,9 @@ MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment)
return mass;
}
-MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment)
+Vector3d IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment)
{
- MT_Vector3 center = /*seg->Mass()**/ segment->GlobalStart();
+ Vector3d center = /*seg->Mass()**/ segment->GlobalStart();
const IK_QSegment *seg;
for (seg = segment->Child(); seg; seg = seg->Sibling())
@@ -191,19 +190,19 @@ MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment)
return center;
}
-void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment)
+void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, Vector3d& center, const IK_QSegment *segment)
{
int i;
- MT_Vector3 p = center - segment->GlobalStart();
+ Vector3d p = center - segment->GlobalStart();
for (i = 0; i < segment->NumberOfDoF(); i++) {
- MT_Vector3 axis = segment->Axis(i) * m_weight;
+ Vector3d axis = segment->Axis(i) * m_weight;
axis *= /*segment->Mass()**/ m_total_mass_inv;
if (segment->Translational())
jacobian.SetDerivatives(m_id, segment->DoFId() + i, axis, 1e2);
else {
- MT_Vector3 pa = axis.cross(p);
+ Vector3d pa = axis.cross(p);
jacobian.SetDerivatives(m_id, segment->DoFId() + i, pa, 1e0);
}
}
@@ -215,12 +214,12 @@ void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& c
void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian)
{
- MT_Vector3 center = ComputeCenter(m_segment) * m_total_mass_inv;
+ Vector3d center = ComputeCenter(m_segment) * m_total_mass_inv;
// compute beta
- MT_Vector3 d_pos = m_goal_center - center;
+ Vector3d d_pos = m_goal_center - center;
- m_distance = d_pos.length();
+ m_distance = d_pos.norm();
#if 0
if (m_distance > m_clamp_length)
@@ -233,7 +232,7 @@ void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian)
JacobianSegment(jacobian, center, m_segment);
}
-MT_Scalar IK_QCenterOfMassTask::Distance() const
+double IK_QCenterOfMassTask::Distance() const
{
return m_distance;
}
diff --git a/intern/iksolver/intern/IK_QTask.h b/intern/iksolver/intern/IK_QTask.h
index baf1c346d62..141e6d41b47 100644
--- a/intern/iksolver/intern/IK_QTask.h
+++ b/intern/iksolver/intern/IK_QTask.h
@@ -30,13 +30,9 @@
* \ingroup iksolver
*/
+#pragma once
-#ifndef __IK_QTASK_H__
-#define __IK_QTASK_H__
-
-#include "MT_Vector3.h"
-#include "MT_Transform.h"
-#include "MT_Matrix4x4.h"
+#include "IK_Math.h"
#include "IK_QJacobian.h"
#include "IK_QSegment.h"
@@ -66,19 +62,19 @@ public:
bool Active() const
{ return m_active; }
- MT_Scalar Weight() const
+ double Weight() const
{ return m_weight*m_weight; }
- void SetWeight(MT_Scalar weight)
+ void SetWeight(double weight)
{ m_weight = sqrt(weight); }
virtual void ComputeJacobian(IK_QJacobian& jacobian)=0;
- virtual MT_Scalar Distance() const=0;
+ virtual double Distance() const=0;
virtual bool PositionTask() const { return false; }
- virtual void Scale(MT_Scalar) {}
+ virtual void Scale(double) {}
protected:
int m_id;
@@ -86,7 +82,7 @@ protected:
bool m_primary;
bool m_active;
const IK_QSegment *m_segment;
- MT_Scalar m_weight;
+ double m_weight;
};
class IK_QPositionTask : public IK_QTask
@@ -95,19 +91,19 @@ public:
IK_QPositionTask(
bool primary,
const IK_QSegment *segment,
- const MT_Vector3& goal
+ const Vector3d& goal
);
void ComputeJacobian(IK_QJacobian& jacobian);
- MT_Scalar Distance() const;
+ double Distance() const;
bool PositionTask() const { return true; }
- void Scale(MT_Scalar scale) { m_goal *= scale; m_clamp_length *= scale; }
+ void Scale(double scale) { m_goal *= scale; m_clamp_length *= scale; }
private:
- MT_Vector3 m_goal;
- MT_Scalar m_clamp_length;
+ Vector3d m_goal;
+ double m_clamp_length;
};
class IK_QOrientationTask : public IK_QTask
@@ -116,15 +112,15 @@ public:
IK_QOrientationTask(
bool primary,
const IK_QSegment *segment,
- const MT_Matrix3x3& goal
+ const Matrix3d& goal
);
- MT_Scalar Distance() const { return m_distance; }
+ double Distance() const { return m_distance; }
void ComputeJacobian(IK_QJacobian& jacobian);
private:
- MT_Matrix3x3 m_goal;
- MT_Scalar m_distance;
+ Matrix3d m_goal;
+ double m_distance;
};
@@ -134,24 +130,22 @@ public:
IK_QCenterOfMassTask(
bool primary,
const IK_QSegment *segment,
- const MT_Vector3& center
+ const Vector3d& center
);
void ComputeJacobian(IK_QJacobian& jacobian);
- MT_Scalar Distance() const;
+ double Distance() const;
- void Scale(MT_Scalar scale) { m_goal_center *= scale; m_distance *= scale; }
+ void Scale(double scale) { m_goal_center *= scale; m_distance *= scale; }
private:
- MT_Scalar ComputeTotalMass(const IK_QSegment *segment);
- MT_Vector3 ComputeCenter(const IK_QSegment *segment);
- void JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment);
+ double ComputeTotalMass(const IK_QSegment *segment);
+ Vector3d ComputeCenter(const IK_QSegment *segment);
+ void JacobianSegment(IK_QJacobian& jacobian, Vector3d& center, const IK_QSegment *segment);
- MT_Vector3 m_goal_center;
- MT_Scalar m_total_mass_inv;
- MT_Scalar m_distance;
+ Vector3d m_goal_center;
+ double m_total_mass_inv;
+ double m_distance;
};
-#endif
-
diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp
index eb18cde3356..cefb8c7ed7b 100644
--- a/intern/iksolver/intern/IK_Solver.cpp
+++ b/intern/iksolver/intern/IK_Solver.cpp
@@ -154,19 +154,19 @@ void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float bas
{
IK_QSegment *qseg = (IK_QSegment *)seg;
- MT_Vector3 mstart(start);
- // convert from blender column major to moto row major
- MT_Matrix3x3 mbasis(basis[0][0], basis[1][0], basis[2][0],
- basis[0][1], basis[1][1], basis[2][1],
- basis[0][2], basis[1][2], basis[2][2]);
- MT_Matrix3x3 mrest(rest[0][0], rest[1][0], rest[2][0],
- rest[0][1], rest[1][1], rest[2][1],
- rest[0][2], rest[1][2], rest[2][2]);
- MT_Scalar mlength(length);
+ Vector3d mstart(start[0], start[1], start[2]);
+ // convert from blender column major
+ Matrix3d mbasis = CreateMatrix(basis[0][0], basis[1][0], basis[2][0],
+ basis[0][1], basis[1][1], basis[2][1],
+ basis[0][2], basis[1][2], basis[2][2]);
+ Matrix3d mrest = CreateMatrix(rest[0][0], rest[1][0], rest[2][0],
+ rest[0][1], rest[1][1], rest[2][1],
+ rest[0][2], rest[1][2], rest[2][2]);
+ double mlength(length);
if (qseg->Composite()) {
- MT_Vector3 cstart(0, 0, 0);
- MT_Matrix3x3 cbasis;
+ Vector3d cstart(0, 0, 0);
+ Matrix3d cbasis;
cbasis.setIdentity();
qseg->SetTransform(mstart, mrest, mbasis, 0.0);
@@ -205,7 +205,7 @@ void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness)
stiffness = (1.0 - IK_STRETCH_STIFF_EPS);
IK_QSegment *qseg = (IK_QSegment *)seg;
- MT_Scalar weight = 1.0f - stiffness;
+ double weight = 1.0f - stiffness;
if (axis >= IK_TRANS_X) {
if (!qseg->Translational()) {
@@ -230,18 +230,18 @@ void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3])
if (qseg->Translational() && qseg->Composite())
qseg = qseg->Composite();
- const MT_Matrix3x3& change = qseg->BasisChange();
-
- // convert from moto row major to blender column major
- basis_change[0][0] = (float)change[0][0];
- basis_change[1][0] = (float)change[0][1];
- basis_change[2][0] = (float)change[0][2];
- basis_change[0][1] = (float)change[1][0];
- basis_change[1][1] = (float)change[1][1];
- basis_change[2][1] = (float)change[1][2];
- basis_change[0][2] = (float)change[2][0];
- basis_change[1][2] = (float)change[2][1];
- basis_change[2][2] = (float)change[2][2];
+ const Matrix3d& change = qseg->BasisChange();
+
+ // convert to blender column major
+ basis_change[0][0] = (float)change(0, 0);
+ basis_change[1][0] = (float)change(0, 1);
+ basis_change[2][0] = (float)change(0, 2);
+ basis_change[0][1] = (float)change(1, 0);
+ basis_change[1][1] = (float)change(1, 1);
+ basis_change[2][1] = (float)change(1, 2);
+ basis_change[0][2] = (float)change(2, 0);
+ basis_change[1][2] = (float)change(2, 1);
+ basis_change[2][2] = (float)change(2, 2);
}
void IK_GetTranslationChange(IK_Segment *seg, float *translation_change)
@@ -251,7 +251,7 @@ void IK_GetTranslationChange(IK_Segment *seg, float *translation_change)
if (!qseg->Translational() && qseg->Composite())
qseg = qseg->Composite();
- const MT_Vector3& change = qseg->TranslationChange();
+ const Vector3d& change = qseg->TranslationChange();
translation_change[0] = (float)change[0];
translation_change[1] = (float)change[1];
@@ -296,7 +296,7 @@ void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float w
if (qtip->Composite())
qtip = qtip->Composite();
- MT_Vector3 pos(goal);
+ Vector3d pos(goal[0], goal[1], goal[2]);
IK_QTask *ee = new IK_QPositionTask(true, qtip, pos);
ee->SetWeight(weight);
@@ -315,10 +315,10 @@ void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[
if (qtip->Composite())
qtip = qtip->Composite();
- // convert from blender column major to moto row major
- MT_Matrix3x3 rot(goal[0][0], goal[1][0], goal[2][0],
- goal[0][1], goal[1][1], goal[2][1],
- goal[0][2], goal[1][2], goal[2][2]);
+ // convert from blender column major
+ Matrix3d rot = CreateMatrix(goal[0][0], goal[1][0], goal[2][0],
+ goal[0][1], goal[1][1], goal[2][1],
+ goal[0][2], goal[1][2], goal[2][2]);
IK_QTask *orient = new IK_QOrientationTask(true, qtip, rot);
orient->SetWeight(weight);
@@ -337,8 +337,8 @@ void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float
if (qtip->Composite())
qtip = qtip->Composite();
- MT_Vector3 qgoal(goal);
- MT_Vector3 qpolegoal(polegoal);
+ Vector3d qgoal(goal[0], goal[1], goal[2]);
+ Vector3d qpolegoal(polegoal[0], polegoal[1], polegoal[2]);
qsolver->solver.SetPoleVectorConstraint(
qtip, qgoal, qpolegoal, poleangle, getangle);
@@ -363,8 +363,8 @@ static void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float
IK_QSolver *qsolver = (IK_QSolver *)solver;
IK_QSegment *qroot = (IK_QSegment *)root;
- // convert from blender column major to moto row major
- MT_Vector3 center(goal);
+ // convert from blender column major
+ Vector3d center(goal);
IK_QTask *com = new IK_QCenterOfMassTask(true, qroot, center);
com->SetWeight(weight);
@@ -382,7 +382,7 @@ int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations)
IK_QSegment *root = qsolver->root;
IK_QJacobianSolver& jacobian = qsolver->solver;
std::list<IK_QTask *>& tasks = qsolver->tasks;
- MT_Scalar tol = tolerance;
+ double tol = tolerance;
if (!jacobian.Setup(root, tasks))
return 0;
diff --git a/intern/iksolver/intern/MT_ExpMap.cpp b/intern/iksolver/intern/MT_ExpMap.cpp
deleted file mode 100644
index b2b13acebeb..00000000000
--- a/intern/iksolver/intern/MT_ExpMap.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Original Author: Laurence
- * Contributor(s): Brecht
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file iksolver/intern/MT_ExpMap.cpp
- * \ingroup iksolver
- */
-
-
-#include "MT_ExpMap.h"
-
-/**
- * Set the exponential map from a quaternion. The quaternion must be non-zero.
- */
-
-void
-MT_ExpMap::
-setRotation(
- const MT_Quaternion &q)
-{
- // ok first normalize the quaternion
- // then compute theta the axis-angle and the normalized axis v
- // scale v by theta and that's it hopefully!
-
- m_q = q.normalized();
- m_v = MT_Vector3(m_q.x(), m_q.y(), m_q.z());
-
- MT_Scalar cosp = m_q.w();
- m_sinp = m_v.length();
- m_v /= m_sinp;
-
- m_theta = atan2(double(m_sinp), double(cosp));
- m_v *= m_theta;
-}
-
-/**
- * Convert from an exponential map to a quaternion
- * representation
- */
-
-const MT_Quaternion&
-MT_ExpMap::
-getRotation() const
-{
- return m_q;
-}
-
-/**
- * Convert the exponential map to a 3x3 matrix
- */
-
-MT_Matrix3x3
-MT_ExpMap::
-getMatrix() const
-{
- return MT_Matrix3x3(m_q);
-}
-
-/**
- * Update & reparameterizate the exponential map
- */
-
-void
-MT_ExpMap::
-update(
- const MT_Vector3& dv)
-{
- m_v += dv;
-
- angleUpdated();
-}
-
-/**
- * Compute the partial derivatives of the exponential
- * map (dR/de - where R is a 3x3 rotation matrix formed
- * from the map) and return them as a 3x3 matrix
- */
-
-void
-MT_ExpMap::
-partialDerivatives(
- MT_Matrix3x3& dRdx,
- MT_Matrix3x3& dRdy,
- MT_Matrix3x3& dRdz) const
-{
- MT_Quaternion dQdx[3];
-
- compute_dQdVi(dQdx);
-
- compute_dRdVi(dQdx[0], dRdx);
- compute_dRdVi(dQdx[1], dRdy);
- compute_dRdVi(dQdx[2], dRdz);
-}
-
-void
-MT_ExpMap::
-compute_dRdVi(
- const MT_Quaternion &dQdvi,
- MT_Matrix3x3 & dRdvi) const
-{
- MT_Scalar prod[9];
-
- /* This efficient formulation is arrived at by writing out the
- * entire chain rule product dRdq * dqdv in terms of 'q' and
- * noticing that all the entries are formed from sums of just
- * nine products of 'q' and 'dqdv' */
-
- prod[0] = -MT_Scalar(4) * m_q.x() * dQdvi.x();
- prod[1] = -MT_Scalar(4) * m_q.y() * dQdvi.y();
- prod[2] = -MT_Scalar(4) * m_q.z() * dQdvi.z();
- prod[3] = MT_Scalar(2) * (m_q.y() * dQdvi.x() + m_q.x() * dQdvi.y());
- prod[4] = MT_Scalar(2) * (m_q.w() * dQdvi.z() + m_q.z() * dQdvi.w());
- prod[5] = MT_Scalar(2) * (m_q.z() * dQdvi.x() + m_q.x() * dQdvi.z());
- prod[6] = MT_Scalar(2) * (m_q.w() * dQdvi.y() + m_q.y() * dQdvi.w());
- prod[7] = MT_Scalar(2) * (m_q.z() * dQdvi.y() + m_q.y() * dQdvi.z());
- prod[8] = MT_Scalar(2) * (m_q.w() * dQdvi.x() + m_q.x() * dQdvi.w());
-
- /* first row, followed by second and third */
- dRdvi[0][0] = prod[1] + prod[2];
- dRdvi[0][1] = prod[3] - prod[4];
- dRdvi[0][2] = prod[5] + prod[6];
-
- dRdvi[1][0] = prod[3] + prod[4];
- dRdvi[1][1] = prod[0] + prod[2];
- dRdvi[1][2] = prod[7] - prod[8];
-
- dRdvi[2][0] = prod[5] - prod[6];
- dRdvi[2][1] = prod[7] + prod[8];
- dRdvi[2][2] = prod[0] + prod[1];
-}
-
-// compute partial derivatives dQ/dVi
-
-void
-MT_ExpMap::
-compute_dQdVi(
- MT_Quaternion *dQdX) const
-{
- /* This is an efficient implementation of the derivatives given
- * in Appendix A of the paper with common subexpressions factored out */
-
- MT_Scalar sinc, termCoeff;
-
- if (m_theta < MT_EXPMAP_MINANGLE) {
- sinc = 0.5 - m_theta * m_theta / 48.0;
- termCoeff = (m_theta * m_theta / 40.0 - 1.0) / 24.0;
- }
- else {
- MT_Scalar cosp = m_q.w();
- MT_Scalar ang = 1.0 / m_theta;
-
- sinc = m_sinp * ang;
- termCoeff = ang * ang * (0.5 * cosp - sinc);
- }
-
- for (int i = 0; i < 3; i++) {
- MT_Quaternion& dQdx = dQdX[i];
- int i2 = (i + 1) % 3;
- int i3 = (i + 2) % 3;
-
- MT_Scalar term = m_v[i] * termCoeff;
-
- dQdx[i] = term * m_v[i] + sinc;
- dQdx[i2] = term * m_v[i2];
- dQdx[i3] = term * m_v[i3];
- dQdx.w() = -0.5 * m_v[i] * sinc;
- }
-}
-
-// reParametize away from singularity, updating
-// m_v and m_theta
-
-void
-MT_ExpMap::
-reParametrize()
-{
- if (m_theta > MT_PI) {
- MT_Scalar scl = m_theta;
- if (m_theta > MT_2_PI) { /* first get theta into range 0..2PI */
- m_theta = MT_Scalar(fmod(m_theta, MT_2_PI));
- scl = m_theta / scl;
- m_v *= scl;
- }
- if (m_theta > MT_PI) {
- scl = m_theta;
- m_theta = MT_2_PI - m_theta;
- scl = MT_Scalar(1.0) - MT_2_PI / scl;
- m_v *= scl;
- }
- }
-}
-
-// compute cached variables
-
-void
-MT_ExpMap::
-angleUpdated()
-{
- m_theta = m_v.length();
-
- reParametrize();
-
- // compute quaternion, sinp and cosp
-
- if (m_theta < MT_EXPMAP_MINANGLE) {
- m_sinp = MT_Scalar(0.0);
-
- /* Taylor Series for sinc */
- MT_Vector3 temp = m_v * MT_Scalar(MT_Scalar(.5) - m_theta * m_theta / MT_Scalar(48.0));
- m_q.x() = temp.x();
- m_q.y() = temp.y();
- m_q.z() = temp.z();
- m_q.w() = MT_Scalar(1.0);
- }
- else {
- m_sinp = MT_Scalar(sin(.5 * m_theta));
-
- /* Taylor Series for sinc */
- MT_Vector3 temp = m_v * (m_sinp / m_theta);
- m_q.x() = temp.x();
- m_q.y() = temp.y();
- m_q.z() = temp.z();
- m_q.w() = MT_Scalar(cos(0.5 * m_theta));
- }
-}
-
diff --git a/intern/iksolver/intern/MT_ExpMap.h b/intern/iksolver/intern/MT_ExpMap.h
deleted file mode 100644
index 65bbe4d4ad5..00000000000
--- a/intern/iksolver/intern/MT_ExpMap.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Original author: Laurence
- * Contributor(s): Brecht
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file iksolver/intern/MT_ExpMap.h
- * \ingroup iksolver
- */
-
-
-#ifndef MT_ExpMap_H
-#define MT_ExpMap_H
-
-#include <MT_assert.h>
-
-#include "MT_Vector3.h"
-#include "MT_Quaternion.h"
-#include "MT_Matrix4x4.h"
-
-const MT_Scalar MT_EXPMAP_MINANGLE (1e-7);
-
-/**
- * MT_ExpMap an exponential map parameterization of rotations
- * in 3D. This implementation is derived from the paper
- * "F. Sebastian Grassia. Practical parameterization of
- * rotations using the exponential map. Journal of Graphics Tools,
- * 3(3):29-48, 1998" Please go to http://www.acm.org/jgt/papers/Grassia98/
- * for a thorough description of the theory and sample code used
- * to derive this class.
- *
- * Basic overview of why this class is used.
- * In an IK system we need to paramterize the joint angles in some
- * way. Typically 2 parameterizations are used.
- * - Euler Angles
- * These suffer from singularities in the parameterization known
- * as gimbal lock. They also do not interpolate well. For every
- * set of euler angles there is exactly 1 corresponding 3d rotation.
- * - Quaternions.
- * Great for interpolating. Only unit quaternions are valid rotations
- * means that in a differential ik solver we often stray outside of
- * this manifold into invalid rotations. Means we have to do a lot
- * of nasty normalizations all the time. Does not suffer from
- * gimbal lock problems. More expensive to compute partial derivatives
- * as there are 4 of them.
- *
- * So exponential map is similar to a quaternion axis/angle
- * representation but we store the angle as the length of the
- * axis. So require only 3 parameters. Means that all exponential
- * maps are valid rotations. Suffers from gimbal lock. But it's
- * possible to detect when gimbal lock is near and reparameterize
- * away from it. Also nice for interpolating.
- * Exponential maps are share some of the useful properties of
- * euler and quaternion parameterizations. And are very useful
- * for differential IK solvers.
- */
-
-class MT_ExpMap {
-public:
-
- /**
- * Default constructor
- * @warning there is no initialization in the
- * default constructor
- */
-
- MT_ExpMap() {}
- MT_ExpMap(const MT_Vector3& v) : m_v(v) { angleUpdated(); }
-
- MT_ExpMap(const float v[3]) : m_v(v) { angleUpdated(); }
- MT_ExpMap(const double v[3]) : m_v(v) { angleUpdated(); }
-
- MT_ExpMap(MT_Scalar x, MT_Scalar y, MT_Scalar z) :
- m_v(x, y, z) { angleUpdated(); }
-
- /**
- * Construct an exponential map from a quaternion
- */
-
- MT_ExpMap(
- const MT_Quaternion &q
- ) {
- setRotation(q);
- }
-
- /**
- * Accessors
- * Decided not to inherit from MT_Vector3 but rather
- * this class contains an MT_Vector3. This is because
- * it is very dangerous to use MT_Vector3 functions
- * on this class and some of them have no direct meaning.
- */
-
- const
- MT_Vector3 &
- vector(
- ) const {
- return m_v;
- }
-
- /**
- * Set the exponential map from a quaternion
- */
-
- void
- setRotation(
- const MT_Quaternion &q
- );
-
- /**
- * Convert from an exponential map to a quaternion
- * representation
- */
-
- const MT_Quaternion&
- getRotation(
- ) const;
-
- /**
- * Convert the exponential map to a 3x3 matrix
- */
-
- MT_Matrix3x3
- getMatrix(
- ) const;
-
- /**
- * Update (and reparameterize) the expontial map
- * @param dv delta update values.
- */
-
- void
- update(
- const MT_Vector3& dv
- );
-
- /**
- * Compute the partial derivatives of the exponential
- * map (dR/de - where R is a 4x4 matrix formed
- * from the map) and return them as a 4x4 matrix
- */
-
- void
- partialDerivatives(
- MT_Matrix3x3& dRdx,
- MT_Matrix3x3& dRdy,
- MT_Matrix3x3& dRdz
- ) const ;
-
-private :
-
- // m_v contains the exponential map, the other variables are
- // cached for efficiency
-
- MT_Vector3 m_v;
- MT_Scalar m_theta, m_sinp;
- MT_Quaternion m_q;
-
- // private methods
-
- // Compute partial derivatives dR (3x3 rotation matrix) / dVi (EM vector)
- // given the partial derivative dQ (Quaternion) / dVi (ith element of EM vector)
-
- void
- compute_dRdVi(
- const MT_Quaternion &dQdV,
- MT_Matrix3x3 & dRdVi
- ) const;
-
- // compute partial derivatives dQ/dVi
-
- void
- compute_dQdVi(
- MT_Quaternion *dQdX
- ) const ;
-
- // reparametrize away from singularity
-
- void
- reParametrize(
- );
-
- // (re-)compute cached variables
-
- void
- angleUpdated(
- );
-};
-
-#endif
-
diff --git a/intern/iksolver/intern/TNT/cholesky.h b/intern/iksolver/intern/TNT/cholesky.h
deleted file mode 100644
index 89c7dc64d5b..00000000000
--- a/intern/iksolver/intern/TNT/cholesky.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- */
-
-/*
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-#ifndef CHOLESKY_H
-#define CHOLESKY_H
-
-#include <cmath>
-
-// index method
-
-namespace TNT
-{
-
-
-//
-// Only upper part of A is used. Cholesky factor is returned in
-// lower part of L. Returns 0 if successful, 1 otherwise.
-//
-template <class SPDMatrix, class SymmMatrix>
-int Cholesky_upper_factorization(SPDMatrix &A, SymmMatrix &L)
-{
- Subscript M = A.dim(1);
- Subscript N = A.dim(2);
-
- assert(M == N); // make sure A is square
-
- // readjust size of L, if necessary
-
- if (M != L.dim(1) || N != L.dim(2))
- L = SymmMatrix(N,N);
-
- Subscript i,j,k;
-
-
- typename SPDMatrix::element_type dot=0;
-
-
- for (j=1; j<=N; j++) // form column j of L
- {
- dot= 0;
-
- for (i=1; i<j; i++) // for k= 1 TO j-1
- dot = dot + L(j,i)*L(j,i);
-
- L(j,j) = A(j,j) - dot;
-
- for (i=j+1; i<=N; i++)
- {
- dot = 0;
- for (k=1; k<j; k++)
- dot = dot + L(i,k)*L(j,k);
- L(i,j) = A(j,i) - dot;
- }
-
- if (L(j,j) <= 0.0) return 1;
-
- L(j,j) = sqrt( L(j,j) );
-
- for (i=j+1; i<=N; i++)
- L(i,j) = L(i,j) / L(j,j);
-
- }
-
- return 0;
-}
-
-
-
-
-}
-// namespace TNT
-
-#endif
-// CHOLESKY_H
-
diff --git a/intern/iksolver/intern/TNT/cmat.h b/intern/iksolver/intern/TNT/cmat.h
deleted file mode 100644
index fd3a1851262..00000000000
--- a/intern/iksolver/intern/TNT/cmat.h
+++ /dev/null
@@ -1,614 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing
-//
-
-#ifndef CMAT_H
-#define CMAT_H
-
-#include "subscript.h"
-#include "vec.h"
-#include <stdlib.h>
-#include <assert.h>
-#include <iostream>
-#ifdef TNT_USE_REGIONS
-#include "region2d.h"
-#endif
-
-namespace TNT
-{
-
-template <class T>
-class Matrix
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- Subscript m_;
- Subscript n_;
- Subscript mn_; // total size
- T* v_;
- T** row_;
- T* vm1_ ; // these point to the same data, but are 1-based
- T** rowm1_;
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript M, Subscript N)
- {
- mn_ = M*N;
- m_ = M;
- n_ = N;
-
- v_ = new T[mn_];
- row_ = new T*[M];
- rowm1_ = new T*[M];
-
- assert(v_ != NULL);
- assert(row_ != NULL);
- assert(rowm1_ != NULL);
-
- T* p = v_;
- vm1_ = v_ - 1;
- for (Subscript i=0; i<M; i++)
- {
- row_[i] = p;
- rowm1_[i] = p-1;
- p += N ;
-
- }
-
- rowm1_ -- ; // compensate for 1-based offset
- }
-
- void copy(const T* v)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- if (v_ != NULL) delete [] (v_);
- if (row_ != NULL) delete [] (row_);
-
- /* return rowm1_ back to original value */
- rowm1_ ++;
- if (rowm1_ != NULL ) delete [] (rowm1_);
- }
-
-
- public:
-
- operator T**(){ return row_; }
- operator T**() const { return row_; }
-
-
- Subscript size() const { return mn_; }
-
- // constructors
-
- Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {}
-
- Matrix(const Matrix<T> &A)
- {
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- Matrix(Subscript M, Subscript N, const T& value = T())
- {
- initialize(M,N);
- set(value);
- }
-
- Matrix(Subscript M, Subscript N, const T* v)
- {
- initialize(M,N);
- copy(v);
- }
-
-
- // destructor
- //
- ~Matrix()
- {
- destroy();
- }
-
-
- // reallocating
- //
- Matrix<T>& newsize(Subscript M, Subscript N)
- {
- if (num_rows() == M && num_cols() == N)
- return *this;
-
- destroy();
- initialize(M,N);
-
- return *this;
- }
-
- void
- diagonal(Vector<T> &diag)
- {
- int sz = diag.dim();
- newsize(sz,sz);
- set(0);
-
- Subscript i;
- for (i = 0; i < sz; i++) {
- row_[i][i] = diag[i];
- }
- }
-
-
-
- // assignments
- //
- Matrix<T>& operator=(const Matrix<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Matrix<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
-
- Subscript dim(Subscript d) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( d >= 1);
- assert( d <= 2);
-#endif
- return (d==1) ? m_ : ((d==2) ? n_ : 0);
- }
-
- Subscript num_rows() const { return m_; }
- Subscript num_cols() const { return n_; }
-
-
-
-
- inline T* operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < m_) ;
-#endif
- return row_[i];
- }
-
- inline const T* operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < m_) ;
-#endif
- return row_[i];
- }
-
- inline reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= mn_) ;
-#endif
- return vm1_[i];
- }
-
- inline const_reference operator()(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= mn_) ;
-#endif
- return vm1_[i];
- }
-
-
-
- inline reference operator()(Subscript i, Subscript j)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return rowm1_[i][j];
- }
-
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return rowm1_[i][j];
- }
-
-
-
-#ifdef TNT_USE_REGIONS
-
- typedef Region2D<Matrix<T> > Region;
-
-
- Region operator()(const Index1D &I, const Index1D &J)
- {
- return Region(*this, I,J);
- }
-
-
- typedef const_Region2D< Matrix<T> > const_Region;
- const_Region operator()(const Index1D &I, const Index1D &J) const
- {
- return const_Region(*this, I,J);
- }
-
-#endif
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Matrix<T> &A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << "\n";
-
- for (Subscript i=0; i<M; i++)
- {
- for (Subscript j=0; j<N; j++)
- {
- s << A[i][j] << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Matrix<T> &A)
-{
-
- Subscript M, N;
-
- s >> M >> N;
-
- if ( !(M == A.num_rows() && N == A.num_cols() ))
- {
- A.newsize(M,N);
- }
-
-
- for (Subscript i=0; i<M; i++)
- for (Subscript j=0; j<N; j++)
- {
- s >> A[i][j];
- }
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-template <class T>
-Matrix<T> operator+(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] + B[i][j];
-
- return tmp;
-}
-
-template <class T>
-Matrix<T> operator-(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] - B[i][j];
-
- return tmp;
-}
-
-template <class T>
-Matrix<T> mult_element(const Matrix<T> &A,
- const Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- tmp[i][j] = A[i][j] * B[i][j];
-
- return tmp;
-}
-
-template <class T>
-void transpose(const Matrix<T> &A, Matrix<T> &S)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==S.num_cols());
- assert(N==S.num_rows());
-
- Subscript i, j;
-
- for (i=0; i<M; i++)
- for (j=0; j<N; j++)
- S[j][i] = A[i][j];
-
-}
-
-
-template <class T>
-inline void matmult(Matrix<T>& C, const Matrix<T> &A,
- const Matrix<T> &B)
-{
-
- assert(A.num_cols() == B.num_rows());
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- C.newsize(M,K);
-
- T sum;
-
- const T* row_i;
- const T* col_k;
-
- for (Subscript i=0; i<M; i++)
- for (Subscript k=0; k<K; k++)
- {
- row_i = &(A[i][0]);
- col_k = &(B[0][k]);
- sum = 0;
- for (Subscript j=0; j<N; j++)
- {
- sum += *row_i * *col_k;
- row_i++;
- col_k += K;
- }
- C[i][k] = sum;
- }
-
-}
-
-template <class T>
-void matmult(Vector<T> &y, const Matrix<T> &A, const Vector<T> &x)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == x.dim());
- assert(A.num_rows() == y.dim());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- T sum;
-
- for (Subscript i=0; i<M; i++)
- {
- sum = 0;
- const T* rowi = A[i];
- for (Subscript j=0; j<N; j++)
- sum = sum + rowi[j] * x[j];
-
- y[i] = sum;
- }
-}
-
-template <class T>
-inline void matmultdiag(
- Matrix<T>& C,
- const Matrix<T> &A,
- const Vector<T> &diag
-){
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() ==A.num_rows()== diag.dim());
-#endif
-
- Subscript M = A.num_rows();
- Subscript K = diag.dim();
-
- C.newsize(M,K);
-
- const T* row_i;
- const T* col_k;
-
- for (Subscript i=0; i<M; i++) {
- for (Subscript k=0; k<K; k++)
- {
- C[i][k] = A[i][k] * diag[k];
- }
- }
-}
-
-
-template <class T>
-inline void matmultdiag(
- Matrix<T>& C,
- const Vector<T> &diag,
- const Matrix<T> &A
-){
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() ==A.num_rows()== diag.dim());
-#endif
-
- Subscript M = A.num_rows();
- Subscript K = diag.dim();
-
- C.newsize(M,K);
-
- for (Subscript i=0; i<M; i++) {
-
- const T diag_element = diag[i];
-
- for (Subscript k=0; k<K; k++)
- {
- C[i][k] = A[i][k] * diag_element;
- }
- }
-}
-
-} // namespace TNT
-
-#endif // CMAT_H
-
diff --git a/intern/iksolver/intern/TNT/fcscmat.h b/intern/iksolver/intern/TNT/fcscmat.h
deleted file mode 100644
index 8865dc7a039..00000000000
--- a/intern/iksolver/intern/TNT/fcscmat.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Templated compressed sparse column matrix (Fortran conventions).
-// uses 1-based offsets in storing row indices.
-// Used primarily to interface with Fortran sparse matrix libaries.
-// (CANNOT BE USED AS AN STL CONTAINER.)
-
-
-#ifndef FCSCMAT_H
-#define FCSCMAT_H
-
-#include <iostream>
-#include <cassert>
-#include "tnt.h"
-#include "vec.h"
-
-using namespace std;
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Sparse_Col_Matrix
-{
-
- protected:
-
- Vector<T> val_; // data values (nz_ elements)
- Vector<Subscript> rowind_; // row_ind (nz_ elements)
- Vector<Subscript> colptr_; // col_ptr (n_+1 elements)
-
- int nz_; // number of nonzeros
- Subscript m_; // global dimensions
- Subscript n_;
-
- public:
-
-
- Fortran_Sparse_Col_Matrix(void);
- Fortran_Sparse_Col_Matrix(const Fortran_Sparse_Col_Matrix<T> &S)
- : val_(S.val_), rowind_(S.rowind_), colptr_(S.colptr_), nz_(S.nz_),
- m_(S.m_), n_(S.n_) {};
- Fortran_Sparse_Col_Matrix(Subscript M, Subscript N,
- Subscript nz, const T *val, const Subscript *r,
- const Subscript *c) : val_(nz, val), rowind_(nz, r),
- colptr_(N+1, c), nz_(nz), m_(M), n_(N) {};
-
- Fortran_Sparse_Col_Matrix(Subscript M, Subscript N,
- Subscript nz, char *val, char *r,
- char *c) : val_(nz, val), rowind_(nz, r),
- colptr_(N+1, c), nz_(nz), m_(M), n_(N) {};
-
- Fortran_Sparse_Col_Matrix(Subscript M, Subscript N,
- Subscript nz, const T *val, Subscript *r, Subscript *c)
- : val_(nz, val), rowind_(nz, r), colptr_(N+1, c), nz_(nz),
- m_(M), n_(N) {};
-
- ~Fortran_Sparse_Col_Matrix() {};
-
-
- T & val(Subscript i) { return val_(i); }
- const T & val(Subscript i) const { return val_(i); }
-
- Subscript & row_ind(Subscript i) { return rowind_(i); }
- const Subscript & row_ind(Subscript i) const { return rowind_(i); }
-
- Subscript col_ptr(Subscript i) { return colptr_(i);}
- const Subscript col_ptr(Subscript i) const { return colptr_(i);}
-
-
- Subscript num_cols() const { return m_;}
- Subscript num_rows() const { return n_; }
-
- Subscript dim(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( 1 <= i );
- assert( i <= 2 );
-#endif
- if (i==1) return m_;
- else if (i==2) return m_;
- else return 0;
- }
-
- Subscript num_nonzeros() const {return nz_;};
- Subscript lbound() const {return 1;}
-
-
-
- Fortran_Sparse_Col_Matrix& operator=(const
- Fortran_Sparse_Col_Matrix &C)
- {
- val_ = C.val_;
- rowind_ = C.rowind_;
- colptr_ = C.colptr_;
- nz_ = C.nz_;
- m_ = C.m_;
- n_ = C.n_;
-
- return *this;
- }
-
- Fortran_Sparse_Col_Matrix& newsize(Subscript M, Subscript N,
- Subscript nz)
- {
- val_.newsize(nz);
- rowind_.newsize(nz);
- colptr_.newsize(N+1);
- return *this;
- }
-};
-
-template <class T>
-ostream& operator<<(ostream &s, const Fortran_Sparse_Col_Matrix<T> &A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << " " << A.num_nonzeros() << endl;
-
-
- for (Subscript k=1; k<=N; k++)
- {
- Subscript start = A.col_ptr(k);
- Subscript end = A.col_ptr(k+1);
-
- for (Subscript i= start; i<end; i++)
- {
- s << A.row_ind(i) << " " << k << " " << A.val(i) << endl;
- }
- }
-
- return s;
-}
-
-
-} // namespace TNT
-
-#endif /* FCSCMAT_H */
-
diff --git a/intern/iksolver/intern/TNT/fmat.h b/intern/iksolver/intern/TNT/fmat.h
deleted file mode 100644
index edb64003143..00000000000
--- a/intern/iksolver/intern/TNT/fmat.h
+++ /dev/null
@@ -1,569 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Fortran-compatible matrix: column oriented, 1-based (i,j) indexing
-
-#ifndef FMAT_H
-#define FMAT_H
-
-#include "subscript.h"
-#include "vec.h"
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-#ifdef TNT_USE_REGIONS
-#include "region2d.h"
-#endif
-
-// simple 1-based, column oriented Matrix class
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Matrix
-{
-
-
- public:
-
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- T* v_; // these are adjusted to simulate 1-offset
- Subscript m_;
- Subscript n_;
- T** col_; // these are adjusted to simulate 1-offset
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript M, Subscript N)
- {
- // adjust col_[] pointers so that they are 1-offset:
- // col_[j][i] is really col_[j-1][i-1];
- //
- // v_[] is the internal contiguous array, it is still 0-offset
- //
- v_ = new T[M*N];
- col_ = new T*[N];
-
- assert(v_ != NULL);
- assert(col_ != NULL);
-
-
- m_ = M;
- n_ = N;
- T* p = v_ - 1;
- for (Subscript i=0; i<N; i++)
- {
- col_[i] = p;
- p += M ;
-
- }
- col_ --;
- }
-
- void copy(const T* v)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = m_ * n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- delete [] (v_);
- col_ ++; // changed back to 0-offset
- delete [] (col_);
- }
-
-
- public:
-
- T* begin() { return v_; }
- const T* begin() const { return v_;}
-
- T* end() { return v_ + m_*n_; }
- const T* end() const { return v_ + m_*n_; }
-
-
- // constructors
-
- Fortran_Matrix() : v_(0), m_(0), n_(0), col_(0) {};
- Fortran_Matrix(const Fortran_Matrix<T> &A)
- {
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- Fortran_Matrix(Subscript M, Subscript N, const T& value = T())
- {
- initialize(M,N);
- set(value);
- }
-
- Fortran_Matrix(Subscript M, Subscript N, const T* v)
- {
- initialize(M,N);
- copy(v);
- }
-
-
- // destructor
- ~Fortran_Matrix()
- {
- destroy();
- }
-
-
- // assignments
- //
- Fortran_Matrix<T>& operator=(const Fortran_Matrix<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.m_, A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Fortran_Matrix<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
-
- Subscript dim(Subscript d) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( d >= 1);
- assert( d <= 2);
-#endif
- return (d==1) ? m_ : ((d==2) ? n_ : 0);
- }
-
- Subscript num_rows() const { return m_; }
- Subscript num_cols() const { return n_; }
-
- Fortran_Matrix<T>& newsize(Subscript M, Subscript N)
- {
- if (num_rows() == M && num_cols() == N)
- return *this;
-
- destroy();
- initialize(M,N);
-
- return *this;
- }
-
-
-
- // 1-based element access
- //
- inline reference operator()(Subscript i, Subscript j)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return col_[j][i];
- }
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= m_) ;
- assert(1<=j);
- assert(j <= n_);
-#endif
- return col_[j][i];
- }
-
-
-#ifdef TNT_USE_REGIONS
-
- typedef Region2D<Fortran_Matrix<T> > Region;
- typedef const_Region2D< Fortran_Matrix<T> > const_Region;
-
- Region operator()(const Index1D &I, const Index1D &J)
- {
- return Region(*this, I,J);
- }
-
- const_Region operator()(const Index1D &I, const Index1D &J) const
- {
- return const_Region(*this, I,J);
- }
-
-#endif
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Fortran_Matrix<T> &A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << "\n";
-
- for (Subscript i=1; i<=M; i++)
- {
- for (Subscript j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class T>
-std::istream& operator>>(std::istream &s, Fortran_Matrix<T> &A)
-{
-
- Subscript M, N;
-
- s >> M >> N;
-
- if ( !(M == A.num_rows() && N == A.num_cols()))
- {
- A.newsize(M,N);
- }
-
-
- for (Subscript i=1; i<=M; i++)
- for (Subscript j=1; j<=N; j++)
- {
- s >> A(i,j);
- }
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-
-template <class T>
-Fortran_Matrix<T> operator+(const Fortran_Matrix<T> &A,
- const Fortran_Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Fortran_Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=1; i<=M; i++)
- for (j=1; j<=N; j++)
- tmp(i,j) = A(i,j) + B(i,j);
-
- return tmp;
-}
-
-template <class T>
-Fortran_Matrix<T> operator-(const Fortran_Matrix<T> &A,
- const Fortran_Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Fortran_Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=1; i<=M; i++)
- for (j=1; j<=N; j++)
- tmp(i,j) = A(i,j) - B(i,j);
-
- return tmp;
-}
-
-// element-wise multiplication (use matmult() below for matrix
-// multiplication in the linear algebra sense.)
-//
-//
-template <class T>
-Fortran_Matrix<T> mult_element(const Fortran_Matrix<T> &A,
- const Fortran_Matrix<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M==B.num_rows());
- assert(N==B.num_cols());
-
- Fortran_Matrix<T> tmp(M,N);
- Subscript i,j;
-
- for (i=1; i<=M; i++)
- for (j=1; j<=N; j++)
- tmp(i,j) = A(i,j) * B(i,j);
-
- return tmp;
-}
-
-
-template <class T>
-Fortran_Matrix<T> transpose(const Fortran_Matrix<T> &A)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Fortran_Matrix<T> S(N,M);
- Subscript i, j;
-
- for (i=1; i<=M; i++)
- for (j=1; j<=N; j++)
- S(j,i) = A(i,j);
-
- return S;
-}
-
-
-
-template <class T>
-inline Fortran_Matrix<T> matmult(const Fortran_Matrix<T> &A,
- const Fortran_Matrix<T> &B)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == B.num_rows());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- Fortran_Matrix<T> tmp(M,K);
- T sum;
-
- for (Subscript i=1; i<=M; i++)
- for (Subscript k=1; k<=K; k++)
- {
- sum = 0;
- for (Subscript j=1; j<=N; j++)
- sum = sum + A(i,j) * B(j,k);
-
- tmp(i,k) = sum;
- }
-
- return tmp;
-}
-
-template <class T>
-inline Fortran_Matrix<T> operator*(const Fortran_Matrix<T> &A,
- const Fortran_Matrix<T> &B)
-{
- return matmult(A,B);
-}
-
-template <class T>
-inline int matmult(Fortran_Matrix<T>& C, const Fortran_Matrix<T> &A,
- const Fortran_Matrix<T> &B)
-{
-
- assert(A.num_cols() == B.num_rows());
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
- Subscript K = B.num_cols();
-
- C.newsize(M,K); // adjust shape of C, if necessary
-
-
- T sum;
-
- const T* row_i;
- const T* col_k;
-
- for (Subscript i=1; i<=M; i++)
- {
- for (Subscript k=1; k<=K; k++)
- {
- row_i = &A(i,1);
- col_k = &B(1,k);
- sum = 0;
- for (Subscript j=1; j<=N; j++)
- {
- sum += *row_i * *col_k;
- row_i += M;
- col_k ++;
- }
-
- C(i,k) = sum;
- }
-
- }
-
- return 0;
-}
-
-
-template <class T>
-Vector<T> matmult(const Fortran_Matrix<T> &A, const Vector<T> &x)
-{
-
-#ifdef TNT_BOUNDS_CHECK
- assert(A.num_cols() == x.dim());
-#endif
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Vector<T> tmp(M);
- T sum;
-
- for (Subscript i=1; i<=M; i++)
- {
- sum = 0;
- for (Subscript j=1; j<=N; j++)
- sum = sum + A(i,j) * x(j);
-
- tmp(i) = sum;
- }
-
- return tmp;
-}
-
-template <class T>
-inline Vector<T> operator*(const Fortran_Matrix<T> &A, const Vector<T> &x)
-{
- return matmult(A,x);
-}
-
-template <class T>
-inline Fortran_Matrix<T> operator*(const Fortran_Matrix<T> &A, const T &x)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- Subscript MN = M*N;
-
- Fortran_Matrix<T> res(M,N);
- const T* a = A.begin();
- T* t = res.begin();
- T* tend = res.end();
-
- for (t=res.begin(); t < tend; t++, a++)
- *t = *a * x;
-
- return res;
-}
-
-} // namespace TNT
-
-#endif // FMAT_H
-
diff --git a/intern/iksolver/intern/TNT/fortran.h b/intern/iksolver/intern/TNT/fortran.h
deleted file mode 100644
index c58a859741b..00000000000
--- a/intern/iksolver/intern/TNT/fortran.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Header file to define C/Fortran conventions (Platform specific)
-
-#ifndef FORTRAN_H
-#define FORTRAN_H
-
-// help map between C/C++ data types and Fortran types
-
-typedef int Fortran_integer;
-typedef float Fortran_float;
-typedef double Fortran_double;
-
-
-typedef Fortran_double *fda_; // (in/out) double precision array
-typedef const Fortran_double *cfda_; // (in) double precsion array
-
-typedef Fortran_double *fd_; // (in/out) single double precision
-typedef const Fortran_double *cfd_; // (in) single double precision
-
-typedef Fortran_float *ffa_; // (in/out) float precision array
-typedef const Fortran_float *cffa_; // (in) float precsion array
-
-typedef Fortran_float *ff_; // (in/out) single float precision
-typedef const Fortran_float *cff_; // (in) single float precision
-
-typedef Fortran_integer *fia_; // (in/out) single integer array
-typedef const Fortran_integer *cfia_; // (in) single integer array
-
-typedef Fortran_integer *fi_; // (in/out) single integer
-typedef const Fortran_integer *cfi_; // (in) single integer
-
-typedef char *fch_; // (in/out) single character
-typedef char *cfch_; // (in) single character
-
-
-#ifndef TNT_SUBSCRIPT_TYPE
-#define TNT_SUBSCRIPT_TYPE TNT::Fortran_integer
-#endif
-
-#endif // FORTRAN_H
-
diff --git a/intern/iksolver/intern/TNT/fspvec.h b/intern/iksolver/intern/TNT/fspvec.h
deleted file mode 100644
index 8b14fa89216..00000000000
--- a/intern/iksolver/intern/TNT/fspvec.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-// Templated sparse vector (Fortran conventions).
-// Used primarily to interface with Fortran sparse matrix libaries.
-// (CANNOT BE USED AS AN STL CONTAINER.)
-
-#ifndef FSPVEC_H
-#define FSPVEC_H
-
-#include "tnt.h"
-#include "vec.h"
-#include <cstdlib>
-#include <cassert>
-#include <iostream>
-
-using namespace std;
-
-namespace TNT
-{
-
-template <class T>
-class Fortran_Sparse_Vector
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- Vector<T> val_;
- Vector<Subscript> index_;
- Subscript dim_; // prescribed dimension
-
-
- public:
-
- // size and shape information
-
- Subscript dim() const { return dim_; }
- Subscript num_nonzeros() const { return val_.dim(); }
-
- // access
-
- T& val(Subscript i) { return val_(i); }
- const T& val(Subscript i) const { return val_(i); }
-
- Subscript &index(Subscript i) { return index_(i); }
- const Subscript &index(Subscript i) const { return index_(i); }
-
- // constructors
-
- Fortran_Sparse_Vector() : val_(), index_(), dim_(0) {};
- Fortran_Sparse_Vector(Subscript N, Subscript nz) : val_(nz),
- index_(nz), dim_(N) {};
- Fortran_Sparse_Vector(Subscript N, Subscript nz, const T *values,
- const Subscript *indices): val_(nz, values), index_(nz, indices),
- dim_(N) {}
-
- Fortran_Sparse_Vector(const Fortran_Sparse_Vector<T> &S):
- val_(S.val_), index_(S.index_), dim_(S.dim_) {}
-
- // initialize from string, e.g.
- //
- // Fortran_Sparse_Vector<T> A(N, 2, "1.0 2.1", "1 3");
- //
- Fortran_Sparse_Vector(Subscript N, Subscript nz, char *v,
- char *ind) : val_(nz, v), index_(nz, ind), dim_(N) {}
-
- // assignments
-
- Fortran_Sparse_Vector<T> & newsize(Subscript N, Subscript nz)
- {
- val_.newsize(nz);
- index_.newsize(nz);
- dim_ = N;
- return *this;
- }
-
- Fortran_Sparse_Vector<T> & operator=( const Fortran_Sparse_Vector<T> &A)
- {
- val_ = A.val_;
- index_ = A.index_;
- dim_ = A.dim_;
-
- return *this;
- }
-
- // methods
-
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-ostream& operator<<(ostream &s, const Fortran_Sparse_Vector<T> &A)
-{
- // output format is : N nz val1 ind1 val2 ind2 ...
- Subscript nz=A.num_nonzeros();
-
- s << A.dim() << " " << nz << endl;
-
- for (Subscript i=1; i<=nz; i++)
- s << A.val(i) << " " << A.index(i) << endl;
- s << endl;
-
- return s;
-}
-
-
-template <class T>
-istream& operator>>(istream &s, Fortran_Sparse_Vector<T> &A)
-{
- // output format is : N nz val1 ind1 val2 ind2 ...
-
- Subscript N;
- Subscript nz;
-
- s >> N >> nz;
-
- A.newsize(N, nz);
-
- for (Subscript i=1; i<=nz; i++)
- s >> A.val(i) >> A.index(i);
-
-
- return s;
-}
-
-} // namespace TNT
-
-#endif // FSPVEC_H
-
diff --git a/intern/iksolver/intern/TNT/index.h b/intern/iksolver/intern/TNT/index.h
deleted file mode 100644
index 1abe20ba729..00000000000
--- a/intern/iksolver/intern/TNT/index.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Vector/Matrix/Array Index Module
-
-#ifndef INDEX_H
-#define INDEX_H
-
-#include "subscript.h"
-
-namespace TNT
-{
-
-class Index1D
-{
- Subscript lbound_;
- Subscript ubound_;
-
- public:
-
- Subscript lbound() const { return lbound_; }
- Subscript ubound() const { return ubound_; }
-
- Index1D(const Index1D &D) : lbound_(D.lbound_), ubound_(D.ubound_) {}
- Index1D(Subscript i1, Subscript i2) : lbound_(i1), ubound_(i2) {}
-
- Index1D & operator=(const Index1D &D)
- {
- lbound_ = D.lbound_;
- ubound_ = D.ubound_;
- return *this;
- }
-
-};
-
-inline Index1D operator+(const Index1D &D, Subscript i)
-{
- return Index1D(i+D.lbound(), i+D.ubound());
-}
-
-inline Index1D operator+(Subscript i, const Index1D &D)
-{
- return Index1D(i+D.lbound(), i+D.ubound());
-}
-
-
-
-inline Index1D operator-(Index1D &D, Subscript i)
-{
- return Index1D(D.lbound()-i, D.ubound()-i);
-}
-
-inline Index1D operator-(Subscript i, Index1D &D)
-{
- return Index1D(i-D.lbound(), i-D.ubound());
-}
-
-} // namespace TNT
-
-#endif
-
diff --git a/intern/iksolver/intern/TNT/lapack.h b/intern/iksolver/intern/TNT/lapack.h
deleted file mode 100644
index e015fa9b617..00000000000
--- a/intern/iksolver/intern/TNT/lapack.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Header file for Fortran Lapack
-
-#ifndef LAPACK_H
-#define LAPACK_H
-
-// This file incomplete and included here to only demonstrate the
-// basic framework for linking with the Fortran Lapack routines.
-
-#include "fortran.h"
-#include "vec.h"
-#include "fmat.h"
-
-
-#define F77_DGESV dgesv_
-#define F77_DGELS dgels_
-#define F77_DSYEV dsyev_
-#define F77_DGEEV dgeev_
-
-extern "C"
-{
-
- // linear equations (general) using LU factorizaiton
- //
- void F77_DGESV(cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda,
- fia_ ipiv, fda_ b, cfi_ ldb, fi_ info);
-
- // solve linear least squares using QR or LU factorization
- //
- void F77_DGELS(cfch_ trans, cfi_ M,
- cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, fda_ B, cfi_ ldb, fda_ work,
- cfi_ lwork, fi_ info);
-
- // solve symmetric eigenvalues
- //
- void F77_DSYEV( cfch_ jobz, cfch_ uplo, cfi_ N, fda_ A, cfi_ lda,
- fda_ W, fda_ work, cfi_ lwork, fi_ info);
-
- // solve unsymmetric eigenvalues
- //
- void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda,
- fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr,
- cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info);
-
-}
-
-// solve linear equations using LU factorization
-
-using namespace TNT;
-
-Vector<double> Lapack_LU_linear_solve(const Fortran_Matrix<double> &A,
- const Vector<double> &b)
-{
- const Fortran_integer one=1;
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- Fortran_Matrix<double> Tmp(A);
- Vector<double> x(b);
- Vector<Fortran_integer> index(M);
- Fortran_integer info = 0;
-
- F77_DGESV(&N, &one, &Tmp(1,1), &M, &index(1), &x(1), &M, &info);
-
- if (info != 0) return Vector<double>(0);
- else
- return x;
-}
-
-// solve linear least squares problem using QR factorization
-//
-Vector<double> Lapack_LLS_QR_linear_solve(const Fortran_Matrix<double> &A,
- const Vector<double> &b)
-{
- const Fortran_integer one=1;
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- Fortran_Matrix<double> Tmp(A);
- Vector<double> x(b);
- Fortran_integer info = 0;
-
- char transp = 'N';
- Fortran_integer lwork = 5 * (M+N); // temporary work space
- Vector<double> work(lwork);
-
- F77_DGELS(&transp, &M, &N, &one, &Tmp(1,1), &M, &x(1), &M, &work(1),
- &lwork, &info);
-
- if (info != 0) return Vector<double>(0);
- else
- return x;
-}
-
-// *********************** Eigenvalue problems *******************
-
-// solve symmetric eigenvalue problem (eigenvalues only)
-//
-Vector<double> Upper_symmetric_eigenvalue_solve(const Fortran_Matrix<double> &A)
-{
- char jobz = 'N';
- char uplo = 'U';
- Subscript N = A.num_rows();
-
- assert(N == A.num_cols());
-
- Vector<double> eigvals(N);
- Fortran_integer worksize = 3*N;
- Fortran_integer info = 0;
- Vector<double> work(worksize);
- Fortran_Matrix<double> Tmp = A;
-
- F77_DSYEV(&jobz, &uplo, &N, &Tmp(1,1), &N, eigvals.begin(), work.begin(),
- &worksize, &info);
-
- if (info != 0) return Vector<double>();
- else
- return eigvals;
-}
-
-
-// solve unsymmetric eigenvalue problems
-//
-int eigenvalue_solve(const Fortran_Matrix<double> &A,
- Vector<double> &wr, Vector<double> &wi)
-{
- char jobvl = 'N';
- char jobvr = 'N';
-
- Fortran_integer N = A.num_rows();
-
-
- assert(N == A.num_cols());
-
- if (N<1) return 1;
-
- Fortran_Matrix<double> vl(1,N); /* should be NxN ? **** */
- Fortran_Matrix<double> vr(1,N);
- Fortran_integer one = 1;
-
- Fortran_integer worksize = 5*N;
- Fortran_integer info = 0;
- Vector<double> work(worksize, 0.0);
- Fortran_Matrix<double> Tmp = A;
-
- wr.newsize(N);
- wi.newsize(N);
-
-// void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda,
-// fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr,
-// cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info);
-
- F77_DGEEV(&jobvl, &jobvr, &N, &Tmp(1,1), &N, &(wr(1)),
- &(wi(1)), &(vl(1,1)), &one, &(vr(1,1)), &one,
- &(work(1)), &worksize, &info);
-
- return (info==0 ? 0: 1);
-}
-
-#endif // LAPACK_H
-
diff --git a/intern/iksolver/intern/TNT/lu.h b/intern/iksolver/intern/TNT/lu.h
deleted file mode 100644
index f64172bd31f..00000000000
--- a/intern/iksolver/intern/TNT/lu.h
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-#ifndef LU_H
-#define LU_H
-
-// Solve system of linear equations Ax = b.
-//
-// Typical usage:
-//
-// Matrix(double) A;
-// Vector(Subscript) ipiv;
-// Vector(double) b;
-//
-// 1) LU_Factor(A,ipiv);
-// 2) LU_Solve(A,ipiv,b);
-//
-// Now b has the solution x. Note that both A and b
-// are overwritten. If these values need to be preserved,
-// one can make temporary copies, as in
-//
-// O) Matrix(double) T = A;
-// 1) LU_Factor(T,ipiv);
-// 1a) Vector(double) x=b;
-// 2) LU_Solve(T,ipiv,x);
-//
-// See details below.
-//
-
-
-// for fabs()
-//
-#include <cmath>
-
-// right-looking LU factorization algorithm (unblocked)
-//
-// Factors matrix A into lower and upper triangular matrices
-// (L and U respectively) in solving the linear equation Ax=b.
-//
-//
-// Args:
-//
-// A (input/output) Matrix(1:n, 1:n) In input, matrix to be
-// factored. On output, overwritten with lower and
-// upper triangular factors.
-//
-// indx (output) Vector(1:n) Pivot vector. Describes how
-// the rows of A were reordered to increase
-// numerical stability.
-//
-// Return value:
-//
-// int (0 if successful, 1 otherwise)
-//
-//
-
-
-namespace TNT
-{
-
-template <class MaTRiX, class VecToRSubscript>
-int LU_factor( MaTRiX &A, VecToRSubscript &indx)
-{
- assert(A.lbound() == 1); // currently for 1-offset
- assert(indx.lbound() == 1); // vectors and matrices
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- if (M == 0 || N==0) return 0;
- if (indx.dim() != M)
- indx.newsize(M);
-
- Subscript i=0,j=0,k=0;
- Subscript jp=0;
-
- typename MaTRiX::element_type t;
-
- Subscript minMN = (M < N ? M : N) ; // min(M,N);
-
- for (j=1; j<= minMN; j++)
- {
-
- // find pivot in column j and test for singularity.
-
- jp = j;
- t = fabs(A(j,j));
- for (i=j+1; i<=M; i++)
- if ( fabs(A(i,j)) > t)
- {
- jp = i;
- t = fabs(A(i,j));
- }
-
- indx(j) = jp;
-
- // jp now has the index of maximum element
- // of column j, below the diagonal
-
- if ( A(jp,j) == 0 )
- return 1; // factorization failed because of zero pivot
-
-
- if (jp != j) // swap rows j and jp
- for (k=1; k<=N; k++)
- {
- t = A(j,k);
- A(j,k) = A(jp,k);
- A(jp,k) =t;
- }
-
- if (j<M) // compute elements j+1:M of jth column
- {
- // note A(j,j), was A(jp,p) previously which was
- // guarranteed not to be zero (Label #1)
- //
- typename MaTRiX::element_type recp = 1.0 / A(j,j);
-
- for (k=j+1; k<=M; k++)
- A(k,j) *= recp;
- }
-
-
- if (j < minMN)
- {
- // rank-1 update to trailing submatrix: E = E - x*y;
- //
- // E is the region A(j+1:M, j+1:N)
- // x is the column vector A(j+1:M,j)
- // y is row vector A(j,j+1:N)
-
- Subscript ii,jj;
-
- for (ii=j+1; ii<=M; ii++)
- for (jj=j+1; jj<=N; jj++)
- A(ii,jj) -= A(ii,j)*A(j,jj);
- }
- }
-
- return 0;
-}
-
-
-
-
-template <class MaTRiX, class VecToR, class VecToRSubscripts>
-int LU_solve(const MaTRiX &A, const VecToRSubscripts &indx, VecToR &b)
-{
- assert(A.lbound() == 1); // currently for 1-offset
- assert(indx.lbound() == 1); // vectors and matrices
- assert(b.lbound() == 1);
-
- Subscript i,ii=0,ip,j;
- Subscript n = b.dim();
- typename MaTRiX::element_type sum = 0.0;
-
- for (i=1;i<=n;i++)
- {
- ip=indx(i);
- sum=b(ip);
- b(ip)=b(i);
- if (ii)
- for (j=ii;j<=i-1;j++)
- sum -= A(i,j)*b(j);
- else if (sum) ii=i;
- b(i)=sum;
- }
- for (i=n;i>=1;i--)
- {
- sum=b(i);
- for (j=i+1;j<=n;j++)
- sum -= A(i,j)*b(j);
- b(i)=sum/A(i,i);
- }
-
- return 0;
-}
-
-} // namespace TNT
-
-#endif // LU_H
-
diff --git a/intern/iksolver/intern/TNT/qr.h b/intern/iksolver/intern/TNT/qr.h
deleted file mode 100644
index 9df34e2d7cc..00000000000
--- a/intern/iksolver/intern/TNT/qr.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-#ifndef QR_H
-#define QR_H
-
-// Classical QR factorization example, based on Stewart[1973].
-//
-//
-// This algorithm computes the factorization of a matrix A
-// into a product of an orthognal matrix (Q) and an upper triangular
-// matrix (R), such that QR = A.
-//
-// Parameters:
-//
-// A (in): Matrix(1:N, 1:N)
-//
-// Q (output): Matrix(1:N, 1:N), collection of Householder
-// column vectors Q1, Q2, ... QN
-//
-// R (output): upper triangular Matrix(1:N, 1:N)
-//
-// Returns:
-//
-// 0 if successful, 1 if A is detected to be singular
-//
-
-
-#include <cmath> //for sqrt() & fabs()
-#include "tntmath.h" // for sign()
-
-// Classical QR factorization, based on Stewart[1973].
-//
-//
-// This algorithm computes the factorization of a matrix A
-// into a product of an orthognal matrix (Q) and an upper triangular
-// matrix (R), such that QR = A.
-//
-// Parameters:
-//
-// A (in/out): On input, A is square, Matrix(1:N, 1:N), that represents
-// the matrix to be factored.
-//
-// On output, Q and R is encoded in the same Matrix(1:N,1:N)
-// in the following manner:
-//
-// R is contained in the upper triangular section of A,
-// except that R's main diagonal is in D. The lower
-// triangular section of A represents Q, where each
-// column j is the vector Qj = I - uj*uj'/pi_j.
-//
-// C (output): vector of Pi[j]
-// D (output): main diagonal of R, i.e. D(i) is R(i,i)
-//
-// Returns:
-//
-// 0 if successful, 1 if A is detected to be singular
-//
-
-namespace TNT
-{
-
-template <class MaTRiX, class Vector>
-int QR_factor(MaTRiX &A, Vector& C, Vector &D)
-{
- assert(A.lbound() == 1); // ensure these are all
- assert(C.lbound() == 1); // 1-based arrays and vectors
- assert(D.lbound() == 1);
-
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(M == N); // make sure A is square
-
- Subscript i,j,k;
- typename MaTRiX::element_type eta, sigma, sum;
-
- // adjust the shape of C and D, if needed...
-
- if (N != C.size()) C.newsize(N);
- if (N != D.size()) D.newsize(N);
-
- for (k=1; k<N; k++)
- {
- // eta = max |M(i,k)|, for k <= i <= n
- //
- eta = 0;
- for (i=k; i<=N; i++)
- {
- double absA = fabs(A(i,k));
- eta = ( absA > eta ? absA : eta );
- }
-
- if (eta == 0) // matrix is singular
- {
- cerr << "QR: k=" << k << "\n";
- return 1;
- }
-
- // form Qk and premiltiply M by it
- //
- for(i=k; i<=N; i++)
- A(i,k) = A(i,k) / eta;
-
- sum = 0;
- for (i=k; i<=N; i++)
- sum = sum + A(i,k)*A(i,k);
- sigma = sign(A(k,k)) * sqrt(sum);
-
-
- A(k,k) = A(k,k) + sigma;
- C(k) = sigma * A(k,k);
- D(k) = -eta * sigma;
-
- for (j=k+1; j<=N; j++)
- {
- sum = 0;
- for (i=k; i<=N; i++)
- sum = sum + A(i,k)*A(i,j);
- sum = sum / C(k);
-
- for (i=k; i<=N; i++)
- A(i,j) = A(i,j) - sum * A(i,k);
- }
-
- D(N) = A(N,N);
- }
-
- return 0;
-}
-
-// modified form of upper triangular solve, except that the main diagonal
-// of R (upper portion of A) is in D.
-//
-template <class MaTRiX, class Vector>
-int R_solve(const MaTRiX &A, /*const*/ Vector &D, Vector &b)
-{
- assert(A.lbound() == 1); // ensure these are all
- assert(D.lbound() == 1); // 1-based arrays and vectors
- assert(b.lbound() == 1);
-
- Subscript i,j;
- Subscript N = A.num_rows();
-
- assert(N == A.num_cols());
- assert(N == D.dim());
- assert(N == b.dim());
-
- typename MaTRiX::element_type sum;
-
- if (D(N) == 0)
- return 1;
-
- b(N) = b(N) /
- D(N);
-
- for (i=N-1; i>=1; i--)
- {
- if (D(i) == 0)
- return 1;
- sum = 0;
- for (j=i+1; j<=N; j++)
- sum = sum + A(i,j)*b(j);
- b(i) = ( b(i) - sum ) /
- D(i);
- }
-
- return 0;
-}
-
-
-template <class MaTRiX, class Vector>
-int QR_solve(const MaTRiX &A, const Vector &c, /*const*/ Vector &d,
- Vector &b)
-{
- assert(A.lbound() == 1); // ensure these are all
- assert(c.lbound() == 1); // 1-based arrays and vectors
- assert(d.lbound() == 1);
-
- Subscript N=A.num_rows();
-
- assert(N == A.num_cols());
- assert(N == c.dim());
- assert(N == d.dim());
- assert(N == b.dim());
-
- Subscript i,j;
- typename MaTRiX::element_type sum, tau;
-
- for (j=1; j<N; j++)
- {
- // form Q'*b
- sum = 0;
- for (i=j; i<=N; i++)
- sum = sum + A(i,j)*b(i);
- if (c(j) == 0)
- return 1;
- tau = sum / c(j);
- for (i=j; i<=N; i++)
- b(i) = b(i) - tau * A(i,j);
- }
- return R_solve(A, d, b); // solve Rx = Q'b
-}
-
-} // namespace TNT
-
-#endif // QR_H
-
diff --git a/intern/iksolver/intern/TNT/region1d.h b/intern/iksolver/intern/TNT/region1d.h
deleted file mode 100644
index 8acaac3ae23..00000000000
--- a/intern/iksolver/intern/TNT/region1d.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-
-#ifndef REGION1D_H
-#define REGION1D_H
-
-
-#include "subscript.h"
-#include "index.h"
-#include <iostream>
-#include <cassert>
-
-namespace TNT
-{
-
-template <class Array1D>
-class const_Region1D;
-
-template <class Array1D>
-class Region1D
-{
- protected:
-
- Array1D & A_;
- Subscript offset_; // 0-based
- Subscript dim_;
-
- typedef typename Array1D::element_type T;
-
- public:
- const Array1D & array() const { return A_; }
-
- Subscript offset() const { return offset_;}
- Subscript dim() const { return dim_; }
-
- Subscript offset(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(i==TNT_BASE_OFFSET);
-#endif
- return offset_;
- }
-
- Subscript dim(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(i== TNT_BASE_OFFSET);
-#endif
- return offset_;
- }
-
-
- Region1D(Array1D &A, Subscript i1, Subscript i2) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i1 );
- assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1));
- assert(i1 <= i2);
-#endif
- offset_ = i1 - TNT_BASE_OFFSET;
- dim_ = i2-i1 + 1;
- }
-
- Region1D(Array1D &A, const Index1D &I) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <=I.lbound());
- assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1));
- assert(I.lbound() <= I.ubound());
-#endif
- offset_ = I.lbound() - TNT_BASE_OFFSET;
- dim_ = I.ubound() - I.lbound() + 1;
- }
-
- Region1D(Region1D<Array1D> &A, Subscript i1, Subscript i2) :
- A_(A.A_)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i1 );
- assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1));
- assert(i1 <= i2);
-#endif
- // (old-offset) (new-offset)
- //
- offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_;
- dim_ = i2-i1 + 1;
- }
-
- Region1D<Array1D> operator()(Subscript i1, Subscript i2)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i1);
- assert(i2 <= dim() + (TNT_BASE_OFFSET -1));
- assert(i1 <= i2);
-#endif
- // offset_ is 0-based, so no need for
- // ( - TNT_BASE_OFFSET)
- //
- return Region1D<Array1D>(A_, i1+offset_,
- offset_ + i2);
- }
-
-
- Region1D<Array1D> operator()(const Index1D &I)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET<=I.lbound());
- assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1));
- assert(I.lbound() <= I.ubound());
-#endif
- return Region1D<Array1D>(A_, I.lbound()+offset_,
- offset_ + I.ubound());
- }
-
-
-
-
- T & operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i);
- assert(i <= dim() + (TNT_BASE_OFFSET-1));
-#endif
- return A_(i+offset_);
- }
-
- const T & operator() (Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i);
- assert(i <= dim() + (TNT_BASE_OFFSET-1));
-#endif
- return A_(i+offset_);
- }
-
-
- Region1D<Array1D> & operator=(const Region1D<Array1D> &R)
- {
- // make sure both sides conform
- assert(dim() == R.dim());
-
- Subscript N = dim();
- Subscript i;
- Subscript istart = TNT_BASE_OFFSET;
- Subscript iend = istart + N-1;
-
- for (i=istart; i<=iend; i++)
- (*this)(i) = R(i);
-
- return *this;
- }
-
-
-
- Region1D<Array1D> & operator=(const const_Region1D<Array1D> &R)
- {
- // make sure both sides conform
- assert(dim() == R.dim());
-
- Subscript N = dim();
- Subscript i;
- Subscript istart = TNT_BASE_OFFSET;
- Subscript iend = istart + N-1;
-
- for (i=istart; i<=iend; i++)
- (*this)(i) = R(i);
-
- return *this;
-
- }
-
-
- Region1D<Array1D> & operator=(const T& t)
- {
- Subscript N=dim();
- Subscript i;
- Subscript istart = TNT_BASE_OFFSET;
- Subscript iend = istart + N-1;
-
- for (i=istart; i<= iend; i++)
- (*this)(i) = t;
-
- return *this;
-
- }
-
-
- Region1D<Array1D> & operator=(const Array1D &R)
- {
- // make sure both sides conform
- Subscript N = dim();
- assert(dim() == R.dim());
-
- Subscript i;
- Subscript istart = TNT_BASE_OFFSET;
- Subscript iend = istart + N-1;
-
- for (i=istart; i<=iend; i++)
- (*this)(i) = R(i);
-
- return *this;
-
- }
-
-};
-
-template <class Array1D>
-std::ostream& operator<<(std::ostream &s, Region1D<Array1D> &A)
-{
- Subscript N=A.dim();
- Subscript istart = TNT_BASE_OFFSET;
- Subscript iend = N - 1 + TNT_BASE_OFFSET;
-
- for (Subscript i=istart; i<=iend; i++)
- s << A(i) << endl;
-
- return s;
-}
-
-
-/* --------- class const_Region1D ------------ */
-
-template <class Array1D>
-class const_Region1D
-{
- protected:
-
- const Array1D & A_;
- Subscript offset_; // 0-based
- Subscript dim_;
- typedef typename Array1D::element_type T;
-
- public:
- const Array1D & array() const { return A_; }
-
- Subscript offset() const { return offset_;}
- Subscript dim() const { return dim_; }
-
- Subscript offset(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(i==TNT_BASE_OFFSET);
-#endif
- return offset_;
- }
-
- Subscript dim(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(i== TNT_BASE_OFFSET);
-#endif
- return offset_;
- }
-
-
- const_Region1D(const Array1D &A, Subscript i1, Subscript i2) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i1 );
- assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1));
- assert(i1 <= i2);
-#endif
- offset_ = i1 - TNT_BASE_OFFSET;
- dim_ = i2-i1 + 1;
- }
-
- const_Region1D(const Array1D &A, const Index1D &I) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <=I.lbound());
- assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1));
- assert(I.lbound() <= I.ubound());
-#endif
- offset_ = I.lbound() - TNT_BASE_OFFSET;
- dim_ = I.ubound() - I.lbound() + 1;
- }
-
- const_Region1D(const_Region1D<Array1D> &A, Subscript i1, Subscript i2) :
- A_(A.A_)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i1 );
- assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1));
- assert(i1 <= i2);
-#endif
- // (old-offset) (new-offset)
- //
- offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_;
- dim_ = i2-i1 + 1;
- }
-
- const_Region1D<Array1D> operator()(Subscript i1, Subscript i2)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i1);
- assert(i2 <= dim() + (TNT_BASE_OFFSET -1));
- assert(i1 <= i2);
-#endif
- // offset_ is 0-based, so no need for
- // ( - TNT_BASE_OFFSET)
- //
- return const_Region1D<Array1D>(A_, i1+offset_,
- offset_ + i2);
- }
-
-
- const_Region1D<Array1D> operator()(const Index1D &I)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET<=I.lbound());
- assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1));
- assert(I.lbound() <= I.ubound());
-#endif
- return const_Region1D<Array1D>(A_, I.lbound()+offset_,
- offset_ + I.ubound());
- }
-
-
- const T & operator() (Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(TNT_BASE_OFFSET <= i);
- assert(i <= dim() + (TNT_BASE_OFFSET-1));
-#endif
- return A_(i+offset_);
- }
-
-
-
-
-};
-
-template <class Array1D>
-std::ostream& operator<<(std::ostream &s, const_Region1D<Array1D> &A)
-{
- Subscript N=A.dim();
-
- for (Subscript i=1; i<=N; i++)
- s << A(i) << endl;
-
- return s;
-}
-
-
-} // namespace TNT
-
-#endif // const_Region1D_H
-
diff --git a/intern/iksolver/intern/TNT/region2d.h b/intern/iksolver/intern/TNT/region2d.h
deleted file mode 100644
index 6af50262382..00000000000
--- a/intern/iksolver/intern/TNT/region2d.h
+++ /dev/null
@@ -1,471 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-// 2D Regions for arrays and matrices
-
-#ifndef REGION2D_H
-#define REGION2D_H
-
-#include "index.h"
-#include <iostream>
-#include <cassert>
-
-namespace TNT
-{
-
-template <class Array2D>
-class const_Region2D;
-
-
-template <class Array2D>
-class Region2D
-{
- protected:
-
- Array2D & A_;
- Subscript offset_[2]; // 0-offset internally
- Subscript dim_[2];
-
- public:
- typedef typename Array2D::value_type T;
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Array2D & array() { return A_; }
- const Array2D & array() const { return A_; }
- Subscript lbound() const { return A_.lbound(); }
- Subscript num_rows() const { return dim_[0]; }
- Subscript num_cols() const { return dim_[1]; }
- Subscript offset(Subscript i) const // 1-offset
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( A_.lbound() <= i);
- assert( i<= dim_[0] + A_.lbound()-1);
-#endif
- return offset_[i-A_.lbound()];
- }
-
- Subscript dim(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( A_.lbound() <= i);
- assert( i<= dim_[0] + A_.lbound()-1);
-#endif
- return dim_[i-A_.lbound()];
- }
-
-
-
- Region2D(Array2D &A, Subscript i1, Subscript i2, Subscript j1,
- Subscript j2) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( i1 <= i2 );
- assert( j1 <= j2);
- assert( A.lbound() <= i1);
- assert( i2<= A.dim(A.lbound()) + A.lbound()-1);
- assert( A.lbound() <= j1);
- assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 );
-#endif
-
-
- offset_[0] = i1-A.lbound();
- offset_[1] = j1-A.lbound();
- dim_[0] = i2-i1+1;
- dim_[1] = j2-j1+1;
- }
-
- Region2D(Array2D &A, const Index1D &I, const Index1D &J) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( I.lbound() <= I.ubound() );
- assert( J.lbound() <= J.ubound() );
- assert( A.lbound() <= I.lbound());
- assert( I.ubound()<= A.dim(A.lbound()) + A.lbound()-1);
- assert( A.lbound() <= J.lbound());
- assert( J.ubound() <= A.dim(A.lbound()+1) + A.lbound()-1 );
-#endif
-
- offset_[0] = I.lbound()-A.lbound();
- offset_[1] = J.lbound()-A.lbound();
- dim_[0] = I.ubound() - I.lbound() + 1;
- dim_[1] = J.ubound() - J.lbound() + 1;
- }
-
- Region2D(Region2D<Array2D> &A, Subscript i1, Subscript i2,
- Subscript j1, Subscript j2) : A_(A.A_)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( i1 <= i2 );
- assert( j1 <= j2);
- assert( A.lbound() <= i1);
- assert( i2<= A.dim(A.lbound()) + A.lbound()-1);
- assert( A.lbound() <= j1);
- assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 );
-#endif
- offset_[0] = (i1 - A.lbound()) + A.offset_[0];
- offset_[1] = (j1 - A.lbound()) + A.offset_[1];
- dim_[0] = i2-i1 + 1;
- dim_[1] = j2-j1+1;
- }
-
- Region2D<Array2D> operator()(Subscript i1, Subscript i2,
- Subscript j1, Subscript j2)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( i1 <= i2 );
- assert( j1 <= j2);
- assert( A_.lbound() <= i1);
- assert( i2<= dim_[0] + A_.lbound()-1);
- assert( A_.lbound() <= j1);
- assert( j2<= dim_[1] + A_.lbound()-1 );
-#endif
- return Region2D<Array2D>(A_,
- i1+offset_[0], offset_[0] + i2,
- j1+offset_[1], offset_[1] + j2);
- }
-
-
- Region2D<Array2D> operator()(const Index1D &I,
- const Index1D &J)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( I.lbound() <= I.ubound() );
- assert( J.lbound() <= J.ubound() );
- assert( A_.lbound() <= I.lbound());
- assert( I.ubound()<= dim_[0] + A_.lbound()-1);
- assert( A_.lbound() <= J.lbound());
- assert( J.ubound() <= dim_[1] + A_.lbound()-1 );
-#endif
-
- return Region2D<Array2D>(A_, I.lbound()+offset_[0],
- offset_[0] + I.ubound(), offset_[1]+J.lbound(),
- offset_[1] + J.ubound());
- }
-
- inline T & operator()(Subscript i, Subscript j)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( A_.lbound() <= i);
- assert( i<= dim_[0] + A_.lbound()-1);
- assert( A_.lbound() <= j);
- assert( j<= dim_[1] + A_.lbound()-1 );
-#endif
- return A_(i+offset_[0], j+offset_[1]);
- }
-
- inline const T & operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( A_.lbound() <= i);
- assert( i<= dim_[0] + A_.lbound()-1);
- assert( A_.lbound() <= j);
- assert( j<= dim_[1] + A_.lbound()-1 );
-#endif
- return A_(i+offset_[0], j+offset_[1]);
- }
-
-
- Region2D<Array2D> & operator=(const Region2D<Array2D> &R)
- {
- Subscript M = num_rows();
- Subscript N = num_cols();
-
- // make sure both sides conform
- assert(M == R.num_rows());
- assert(N == R.num_cols());
-
-
- Subscript start = R.lbound();
- Subscript Mend = start + M - 1;
- Subscript Nend = start + N - 1;
- for (Subscript i=start; i<=Mend; i++)
- for (Subscript j=start; j<=Nend; j++)
- (*this)(i,j) = R(i,j);
-
- return *this;
- }
-
- Region2D<Array2D> & operator=(const const_Region2D<Array2D> &R)
- {
- Subscript M = num_rows();
- Subscript N = num_cols();
-
- // make sure both sides conform
- assert(M == R.num_rows());
- assert(N == R.num_cols());
-
-
- Subscript start = R.lbound();
- Subscript Mend = start + M - 1;
- Subscript Nend = start + N - 1;
- for (Subscript i=start; i<=Mend; i++)
- for (Subscript j=start; j<=Nend; j++)
- (*this)(i,j) = R(i,j);
-
- return *this;
- }
-
- Region2D<Array2D> & operator=(const Array2D &R)
- {
- Subscript M = num_rows();
- Subscript N = num_cols();
-
- // make sure both sides conform
- assert(M == R.num_rows());
- assert(N == R.num_cols());
-
-
- Subscript start = R.lbound();
- Subscript Mend = start + M - 1;
- Subscript Nend = start + N - 1;
- for (Subscript i=start; i<=Mend; i++)
- for (Subscript j=start; j<=Nend; j++)
- (*this)(i,j) = R(i,j);
-
- return *this;
- }
-
- Region2D<Array2D> & operator=(const T &scalar)
- {
- Subscript start = lbound();
- Subscript Mend = lbound() + num_rows() - 1;
- Subscript Nend = lbound() + num_cols() - 1;
-
-
- for (Subscript i=start; i<=Mend; i++)
- for (Subscript j=start; j<=Nend; j++)
- (*this)(i,j) = scalar;
-
- return *this;
- }
-
-};
-
-//************************
-
-template <class Array2D>
-class const_Region2D
-{
- protected:
-
- const Array2D & A_;
- Subscript offset_[2]; // 0-offset internally
- Subscript dim_[2];
-
- public:
- typedef typename Array2D::value_type T;
- typedef T value_type;
- typedef T element_type;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- const Array2D & array() const { return A_; }
- Subscript lbound() const { return A_.lbound(); }
- Subscript num_rows() const { return dim_[0]; }
- Subscript num_cols() const { return dim_[1]; }
- Subscript offset(Subscript i) const // 1-offset
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( TNT_BASE_OFFSET <= i);
- assert( i<= dim_[0] + TNT_BASE_OFFSET-1);
-#endif
- return offset_[i-TNT_BASE_OFFSET];
- }
-
- Subscript dim(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( TNT_BASE_OFFSET <= i);
- assert( i<= dim_[0] + TNT_BASE_OFFSET-1);
-#endif
- return dim_[i-TNT_BASE_OFFSET];
- }
-
-
- const_Region2D(const Array2D &A, Subscript i1, Subscript i2,
- Subscript j1, Subscript j2) : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( i1 <= i2 );
- assert( j1 <= j2);
- assert( TNT_BASE_OFFSET <= i1);
- assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1);
- assert( TNT_BASE_OFFSET <= j1);
- assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 );
-#endif
-
- offset_[0] = i1-TNT_BASE_OFFSET;
- offset_[1] = j1-TNT_BASE_OFFSET;
- dim_[0] = i2-i1+1;
- dim_[1] = j2-j1+1;
- }
-
- const_Region2D(const Array2D &A, const Index1D &I, const Index1D &J)
- : A_(A)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( I.lbound() <= I.ubound() );
- assert( J.lbound() <= J.ubound() );
- assert( TNT_BASE_OFFSET <= I.lbound());
- assert( I.ubound()<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1);
- assert( TNT_BASE_OFFSET <= J.lbound());
- assert( J.ubound() <= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 );
-#endif
-
- offset_[0] = I.lbound()-TNT_BASE_OFFSET;
- offset_[1] = J.lbound()-TNT_BASE_OFFSET;
- dim_[0] = I.ubound() - I.lbound() + 1;
- dim_[1] = J.ubound() - J.lbound() + 1;
- }
-
-
- const_Region2D(const_Region2D<Array2D> &A, Subscript i1,
- Subscript i2,
- Subscript j1, Subscript j2) : A_(A.A_)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( i1 <= i2 );
- assert( j1 <= j2);
- assert( TNT_BASE_OFFSET <= i1);
- assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1);
- assert( TNT_BASE_OFFSET <= j1);
- assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 );
-#endif
- offset_[0] = (i1 - TNT_BASE_OFFSET) + A.offset_[0];
- offset_[1] = (j1 - TNT_BASE_OFFSET) + A.offset_[1];
- dim_[0] = i2-i1 + 1;
- dim_[1] = j2-j1+1;
- }
-
- const_Region2D<Array2D> operator()(Subscript i1, Subscript i2,
- Subscript j1, Subscript j2)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( i1 <= i2 );
- assert( j1 <= j2);
- assert( TNT_BASE_OFFSET <= i1);
- assert( i2<= dim_[0] + TNT_BASE_OFFSET-1);
- assert( TNT_BASE_OFFSET <= j1);
- assert( j2<= dim_[0] + TNT_BASE_OFFSET-1 );
-#endif
- return const_Region2D<Array2D>(A_,
- i1+offset_[0], offset_[0] + i2,
- j1+offset_[1], offset_[1] + j2);
- }
-
-
- const_Region2D<Array2D> operator()(const Index1D &I,
- const Index1D &J)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( I.lbound() <= I.ubound() );
- assert( J.lbound() <= J.ubound() );
- assert( TNT_BASE_OFFSET <= I.lbound());
- assert( I.ubound()<= dim_[0] + TNT_BASE_OFFSET-1);
- assert( TNT_BASE_OFFSET <= J.lbound());
- assert( J.ubound() <= dim_[1] + TNT_BASE_OFFSET-1 );
-#endif
-
- return const_Region2D<Array2D>(A_, I.lbound()+offset_[0],
- offset_[0] + I.ubound(), offset_[1]+J.lbound(),
- offset_[1] + J.ubound());
- }
-
-
- inline const T & operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( TNT_BASE_OFFSET <= i);
- assert( i<= dim_[0] + TNT_BASE_OFFSET-1);
- assert( TNT_BASE_OFFSET <= j);
- assert( j<= dim_[1] + TNT_BASE_OFFSET-1 );
-#endif
- return A_(i+offset_[0], j+offset_[1]);
- }
-
-};
-
-
-// ************** std::ostream algorithms *******************************
-
-template <class Array2D>
-std::ostream& operator<<(std::ostream &s, const const_Region2D<Array2D> &A)
-{
- Subscript start = A.lbound();
- Subscript Mend=A.lbound()+ A.num_rows() - 1;
- Subscript Nend=A.lbound() + A.num_cols() - 1;
-
-
- s << A.num_rows() << " " << A.num_cols() << "\n";
- for (Subscript i=start; i<=Mend; i++)
- {
- for (Subscript j=start; j<=Nend; j++)
- {
- s << A(i,j) << " ";
- }
- s << "\n";
- }
-
-
- return s;
-}
-
-template <class Array2D>
-std::ostream& operator<<(std::ostream &s, const Region2D<Array2D> &A)
-{
- Subscript start = A.lbound();
- Subscript Mend=A.lbound()+ A.num_rows() - 1;
- Subscript Nend=A.lbound() + A.num_cols() - 1;
-
-
- s << A.num_rows() << " " << A.num_cols() << "\n";
- for (Subscript i=start; i<=Mend; i++)
- {
- for (Subscript j=start; j<=Nend; j++)
- {
- s << A(i,j) << " ";
- }
- s << "\n";
- }
-
-
- return s;
-
-}
-
-} // namespace TNT
-
-#endif // REGION2D_H
-
diff --git a/intern/iksolver/intern/TNT/stopwatch.h b/intern/iksolver/intern/TNT/stopwatch.h
deleted file mode 100644
index 55cd532d6a4..00000000000
--- a/intern/iksolver/intern/TNT/stopwatch.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-#ifndef STPWATCH_H
-#define STPWATCH_H
-
-// for clock() and CLOCKS_PER_SEC
-#include <ctime>
-
-namespace TNT
-{
-
-/* Simple stopwatch object:
-
- void start() : start timing
- double stop() : stop timing
- void reset() : set elapsed time to 0.0
- double read() : read elapsed time (in seconds)
-
-*/
-
-inline double seconds(void)
-{
- static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
- return ( (double) clock() ) * secs_per_tick;
-}
-
-
-class stopwatch {
- private:
- int running;
- double last_time;
- double total;
-
- public:
- stopwatch() : running(0), last_time(0.0), total(0.0) {}
- void reset() { running = 0; last_time = 0.0; total=0.0; }
- void start() { if (!running) { last_time = seconds(); running = 1;}}
- double stop() { if (running)
- {
- total += seconds() - last_time;
- running = 0;
- }
- return total;
- }
- double read() { if (running)
- {
- total+= seconds() - last_time;
- last_time = seconds();
- }
- return total;
- }
-
-};
-
-} // namespace TNT
-
-#endif
-
diff --git a/intern/iksolver/intern/TNT/subscript.h b/intern/iksolver/intern/TNT/subscript.h
deleted file mode 100644
index 75555e1c0b6..00000000000
--- a/intern/iksolver/intern/TNT/subscript.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-#ifndef SUBSCRPT_H
-#define SUBSCRPT_H
-
-
-//---------------------------------------------------------------------
-// This definition describes the default TNT data type used for
-// indexing into TNT matrices and vectors. The data type should
-// be wide enough to index into large arrays. It defaults to an
-// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE,
-// e.g.
-//
-// g++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ...
-//
-//---------------------------------------------------------------------
-//
-
-#ifndef TNT_SUBSCRIPT_TYPE
-#define TNT_SUBSCRIPT_TYPE int
-#endif
-
-namespace TNT
-{
- typedef TNT_SUBSCRIPT_TYPE Subscript;
-}
-
-
-// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the
-// first elements. This offset is left as a macro for future
-// purposes, but should not be changed in the current release.
-//
-//
-#define TNT_BASE_OFFSET (1)
-
-#endif
-
diff --git a/intern/iksolver/intern/TNT/svd.h b/intern/iksolver/intern/TNT/svd.h
deleted file mode 100644
index cfff73caa3f..00000000000
--- a/intern/iksolver/intern/TNT/svd.h
+++ /dev/null
@@ -1,435 +0,0 @@
-/**
- */
-
-#ifndef SVD_H
-
-#define SVD_H
-
-// Compute the Single Value Decomposition of an arbitrary matrix A
-// That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
-// ,W a diagonal matrix and V an orthogonal square matrix s.t.
-// A = U.W.Vt. From this decomposition it is trivial to compute the
-// inverse of A as Ainv = V.Winv.tranpose(U).
-//
-// s = diagonal elements of W
-// work1 = workspace, length must be A.num_rows
-// work2 = workspace, length must be A.num_cols
-
-#include "tntmath.h"
-
-#define SVD_MAX_ITER 200
-
-namespace TNT
-{
-
-template <class MaTRiX, class VecToR >
-void SVD(MaTRiX &A, MaTRiX &U, VecToR &s, MaTRiX &V, VecToR &work1, VecToR &work2, int maxiter=SVD_MAX_ITER) {
-
- int m = A.num_rows();
- int n = A.num_cols();
- int nu = min(m,n);
-
- VecToR& work = work1;
- VecToR& e = work2;
-
- U = 0;
- s = 0;
-
- int i=0, j=0, k=0;
-
- // Reduce A to bidiagonal form, storing the diagonal elements
- // in s and the super-diagonal elements in e.
-
- int nct = min(m-1,n);
- int nrt = max(0,min(n-2,m));
- for (k = 0; k < max(nct,nrt); k++) {
- if (k < nct) {
-
- // Compute the transformation for the k-th column and
- // place the k-th diagonal in s[k].
- // Compute 2-norm of k-th column without under/overflow.
- s[k] = 0;
- for (i = k; i < m; i++) {
- s[k] = hypot(s[k],A[i][k]);
- }
- if (s[k] != 0.0) {
- if (A[k][k] < 0.0) {
- s[k] = -s[k];
- }
- for (i = k; i < m; i++) {
- A[i][k] /= s[k];
- }
- A[k][k] += 1.0;
- }
- s[k] = -s[k];
- }
- for (j = k+1; j < n; j++) {
- if ((k < nct) && (s[k] != 0.0)) {
-
- // Apply the transformation.
-
- typename MaTRiX::value_type t = 0;
- for (i = k; i < m; i++) {
- t += A[i][k]*A[i][j];
- }
- t = -t/A[k][k];
- for (i = k; i < m; i++) {
- A[i][j] += t*A[i][k];
- }
- }
-
- // Place the k-th row of A into e for the
- // subsequent calculation of the row transformation.
-
- e[j] = A[k][j];
- }
- if (k < nct) {
-
- // Place the transformation in U for subsequent back
- // multiplication.
-
- for (i = k; i < m; i++)
- U[i][k] = A[i][k];
- }
- if (k < nrt) {
-
- // Compute the k-th row transformation and place the
- // k-th super-diagonal in e[k].
- // Compute 2-norm without under/overflow.
- e[k] = 0;
- for (i = k+1; i < n; i++) {
- e[k] = hypot(e[k],e[i]);
- }
- if (e[k] != 0.0) {
- if (e[k+1] < 0.0) {
- e[k] = -e[k];
- }
- for (i = k+1; i < n; i++) {
- e[i] /= e[k];
- }
- e[k+1] += 1.0;
- }
- e[k] = -e[k];
- if ((k+1 < m) & (e[k] != 0.0)) {
-
- // Apply the transformation.
-
- for (i = k+1; i < m; i++) {
- work[i] = 0.0;
- }
- for (j = k+1; j < n; j++) {
- for (i = k+1; i < m; i++) {
- work[i] += e[j]*A[i][j];
- }
- }
- for (j = k+1; j < n; j++) {
- typename MaTRiX::value_type t = -e[j]/e[k+1];
- for (i = k+1; i < m; i++) {
- A[i][j] += t*work[i];
- }
- }
- }
-
- // Place the transformation in V for subsequent
- // back multiplication.
-
- for (i = k+1; i < n; i++)
- V[i][k] = e[i];
- }
- }
-
- // Set up the final bidiagonal matrix or order p.
-
- int p = min(n,m+1);
- if (nct < n) {
- s[nct] = A[nct][nct];
- }
- if (m < p) {
- s[p-1] = 0.0;
- }
- if (nrt+1 < p) {
- e[nrt] = A[nrt][p-1];
- }
- e[p-1] = 0.0;
-
- // If required, generate U.
-
- for (j = nct; j < nu; j++) {
- for (i = 0; i < m; i++) {
- U[i][j] = 0.0;
- }
- U[j][j] = 1.0;
- }
- for (k = nct-1; k >= 0; k--) {
- if (s[k] != 0.0) {
- for (j = k+1; j < nu; j++) {
- typename MaTRiX::value_type t = 0;
- for (i = k; i < m; i++) {
- t += U[i][k]*U[i][j];
- }
- t = -t/U[k][k];
- for (i = k; i < m; i++) {
- U[i][j] += t*U[i][k];
- }
- }
- for (i = k; i < m; i++ ) {
- U[i][k] = -U[i][k];
- }
- U[k][k] = 1.0 + U[k][k];
- for (i = 0; i < k-1; i++) {
- U[i][k] = 0.0;
- }
- } else {
- for (i = 0; i < m; i++) {
- U[i][k] = 0.0;
- }
- U[k][k] = 1.0;
- }
- }
-
- // If required, generate V.
-
- for (k = n-1; k >= 0; k--) {
- if ((k < nrt) & (e[k] != 0.0)) {
- for (j = k+1; j < nu; j++) {
- typename MaTRiX::value_type t = 0;
- for (i = k+1; i < n; i++) {
- t += V[i][k]*V[i][j];
- }
- t = -t/V[k+1][k];
- for (i = k+1; i < n; i++) {
- V[i][j] += t*V[i][k];
- }
- }
- }
- for (i = 0; i < n; i++) {
- V[i][k] = 0.0;
- }
- V[k][k] = 1.0;
- }
-
- // Main iteration loop for the singular values.
-
- int pp = p-1;
- int iter = 0;
- typename MaTRiX::value_type eps = pow(2.0,-52.0);
- while (p > 0) {
- int kase=0;
- k=0;
-
- // Test for maximum iterations to avoid infinite loop
- if(maxiter == 0)
- break;
- maxiter--;
-
- // This section of the program inspects for
- // negligible elements in the s and e arrays. On
- // completion the variables kase and k are set as follows.
-
- // kase = 1 if s(p) and e[k-1] are negligible and k<p
- // kase = 2 if s(k) is negligible and k<p
- // kase = 3 if e[k-1] is negligible, k<p, and
- // s(k), ..., s(p) are not negligible (qr step).
- // kase = 4 if e(p-1) is negligible (convergence).
-
- for (k = p-2; k >= -1; k--) {
- if (k == -1) {
- break;
- }
- if (TNT::abs(e[k]) <= eps*(TNT::abs(s[k]) + TNT::abs(s[k+1]))) {
- e[k] = 0.0;
- break;
- }
- }
- if (k == p-2) {
- kase = 4;
- } else {
- int ks;
- for (ks = p-1; ks >= k; ks--) {
- if (ks == k) {
- break;
- }
- typename MaTRiX::value_type t = (ks != p ? TNT::abs(e[ks]) : 0.) +
- (ks != k+1 ? TNT::abs(e[ks-1]) : 0.);
- if (TNT::abs(s[ks]) <= eps*t) {
- s[ks] = 0.0;
- break;
- }
- }
- if (ks == k) {
- kase = 3;
- } else if (ks == p-1) {
- kase = 1;
- } else {
- kase = 2;
- k = ks;
- }
- }
- k++;
-
- // Perform the task indicated by kase.
-
- switch (kase) {
-
- // Deflate negligible s(p).
-
- case 1: {
- typename MaTRiX::value_type f = e[p-2];
- e[p-2] = 0.0;
- for (j = p-2; j >= k; j--) {
- typename MaTRiX::value_type t = hypot(s[j],f);
- typename MaTRiX::value_type cs = s[j]/t;
- typename MaTRiX::value_type sn = f/t;
- s[j] = t;
- if (j != k) {
- f = -sn*e[j-1];
- e[j-1] = cs*e[j-1];
- }
-
- for (i = 0; i < n; i++) {
- t = cs*V[i][j] + sn*V[i][p-1];
- V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
- V[i][j] = t;
- }
- }
- }
- break;
-
- // Split at negligible s(k).
-
- case 2: {
- typename MaTRiX::value_type f = e[k-1];
- e[k-1] = 0.0;
- for (j = k; j < p; j++) {
- typename MaTRiX::value_type t = hypot(s[j],f);
- typename MaTRiX::value_type cs = s[j]/t;
- typename MaTRiX::value_type sn = f/t;
- s[j] = t;
- f = -sn*e[j];
- e[j] = cs*e[j];
-
- for (i = 0; i < m; i++) {
- t = cs*U[i][j] + sn*U[i][k-1];
- U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
- U[i][j] = t;
- }
- }
- }
- break;
-
- // Perform one qr step.
-
- case 3: {
-
- // Calculate the shift.
-
- typename MaTRiX::value_type scale = max(max(max(max(
- TNT::abs(s[p-1]),TNT::abs(s[p-2])),TNT::abs(e[p-2])),
- TNT::abs(s[k])),TNT::abs(e[k]));
- typename MaTRiX::value_type sp = s[p-1]/scale;
- typename MaTRiX::value_type spm1 = s[p-2]/scale;
- typename MaTRiX::value_type epm1 = e[p-2]/scale;
- typename MaTRiX::value_type sk = s[k]/scale;
- typename MaTRiX::value_type ek = e[k]/scale;
- typename MaTRiX::value_type b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
- typename MaTRiX::value_type c = (sp*epm1)*(sp*epm1);
- typename MaTRiX::value_type shift = 0.0;
- if ((b != 0.0) || (c != 0.0)) {
- shift = sqrt(b*b + c);
- if (b < 0.0) {
- shift = -shift;
- }
- shift = c/(b + shift);
- }
- typename MaTRiX::value_type f = (sk + sp)*(sk - sp) + shift;
- typename MaTRiX::value_type g = sk*ek;
-
- // Chase zeros.
-
- for (j = k; j < p-1; j++) {
- typename MaTRiX::value_type t = hypot(f,g);
- /* division by zero checks added to avoid NaN (brecht) */
- typename MaTRiX::value_type cs = (t == 0.0f)? 0.0f: f/t;
- typename MaTRiX::value_type sn = (t == 0.0f)? 0.0f: g/t;
- if (j != k) {
- e[j-1] = t;
- }
- f = cs*s[j] + sn*e[j];
- e[j] = cs*e[j] - sn*s[j];
- g = sn*s[j+1];
- s[j+1] = cs*s[j+1];
-
- for (i = 0; i < n; i++) {
- t = cs*V[i][j] + sn*V[i][j+1];
- V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
- V[i][j] = t;
- }
-
- t = hypot(f,g);
- /* division by zero checks added to avoid NaN (brecht) */
- cs = (t == 0.0f)? 0.0f: f/t;
- sn = (t == 0.0f)? 0.0f: g/t;
- s[j] = t;
- f = cs*e[j] + sn*s[j+1];
- s[j+1] = -sn*e[j] + cs*s[j+1];
- g = sn*e[j+1];
- e[j+1] = cs*e[j+1];
- if (j < m-1) {
- for (i = 0; i < m; i++) {
- t = cs*U[i][j] + sn*U[i][j+1];
- U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
- U[i][j] = t;
- }
- }
- }
- e[p-2] = f;
- iter = iter + 1;
- }
- break;
-
- // Convergence.
-
- case 4: {
-
- // Make the singular values positive.
-
- if (s[k] <= 0.0) {
- s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
-
- for (i = 0; i <= pp; i++)
- V[i][k] = -V[i][k];
- }
-
- // Order the singular values.
-
- while (k < pp) {
- if (s[k] >= s[k+1]) {
- break;
- }
- typename MaTRiX::value_type t = s[k];
- s[k] = s[k+1];
- s[k+1] = t;
- if (k < n-1) {
- for (i = 0; i < n; i++) {
- t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
- }
- }
- if (k < m-1) {
- for (i = 0; i < m; i++) {
- t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
- }
- }
- k++;
- }
- iter = 0;
- p--;
- }
- break;
- }
- }
-}
-
-}
-
-#endif
-
diff --git a/intern/iksolver/intern/TNT/tnt.h b/intern/iksolver/intern/TNT/tnt.h
deleted file mode 100644
index c15ae27c547..00000000000
--- a/intern/iksolver/intern/TNT/tnt.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-#ifndef TNT_H
-#define TNT_H
-
-//---------------------------------------------------------------------
-// tnt.h TNT general header file. Defines default types
-// and conventions.
-//---------------------------------------------------------------------
-
-//---------------------------------------------------------------------
-// Include current version
-//---------------------------------------------------------------------
-#include "version.h"
-
-//---------------------------------------------------------------------
-// Define the data type used for matrix and vector Subscripts.
-// This will default to "int", but it can be overriden at compile time,
-// e.g.
-//
-// g++ -DTNT_SUBSCRIPT_TYPE='unsinged long' ...
-//
-// See subscript.h for details.
-//---------------------------------------------------------------------
-
-#include "subscript.h"
-
-
-
-//---------------------------------------------------------------------
-// Define this macro if you want TNT to ensure all refernces
-// are within the bounds of the array. This encurs a run-time
-// overhead, of course, but is recommended while developing
-// code. It can be turned off for production runs.
-//
-// #define TNT_BOUNDS_CHECK
-//---------------------------------------------------------------------
-//
-#define TNT_BOUNDS_CHECK
-#ifdef TNT_NO_BOUNDS_CHECK
-#undef TNT_BOUNDS_CHECK
-#endif
-
-//---------------------------------------------------------------------
-// Define this macro if you want to utilize matrix and vector
-// regions. This is typically on, but you can save some
-// compilation time by turning it off. If you do this and
-// attempt to use regions you will get an error message.
-//
-// #define TNT_USE_REGIONS
-//---------------------------------------------------------------------
-//
-#define TNT_USE_REGIONS
-
-//---------------------------------------------------------------------
-//
-//---------------------------------------------------------------------
-// if your system doesn't have abs() min(), and max() uncoment the following
-//---------------------------------------------------------------------
-//
-//
-//#define __NEED_ABS_MIN_MAX_
-
-#include "tntmath.h"
-
-#endif // TNT_H
-
diff --git a/intern/iksolver/intern/TNT/tntmath.h b/intern/iksolver/intern/TNT/tntmath.h
deleted file mode 100644
index be72796da59..00000000000
--- a/intern/iksolver/intern/TNT/tntmath.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Header file for scalar math functions
-
-#ifndef TNTMATH_H
-#define TNTMATH_H
-
-// conventional functions required by several matrix algorithms
-
-#if defined(_MSC_VER) && (_MSC_VER < 1800)
-#define hypot _hypot
-#endif
-
-namespace TNT
-{
-
-struct TNTException {
- int i;
-};
-
-
-inline double abs(double t)
-{
- return ( t > 0 ? t : -t);
-}
-
-inline double min(double a, double b)
-{
- return (a < b ? a : b);
-}
-
-inline double max(double a, double b)
-{
- return (a > b ? a : b);
-}
-
-inline float abs(float t)
-{
- return ( t > 0 ? t : -t);
-}
-
-inline float min(float a, float b)
-{
- return (a < b ? a : b);
-}
-
-inline int min(int a, int b)
-{
- return (a < b ? a : b);
-}
-
-inline int max(int a, int b)
-{
- return (a > b ? a : b);
-}
-
-inline float max(float a, float b)
-{
- return (a > b ? a : b);
-}
-
-inline double sign(double a)
-{
- return (a > 0 ? 1.0 : -1.0);
-}
-
-inline double sign(double a,double b) {
- return (b >= 0.0 ? TNT::abs(a) : -TNT::abs(a));
-}
-
-inline float sign(float a,float b) {
- return (b >= 0.0f ? TNT::abs(a) : -TNT::abs(a));
-}
-
-inline float sign(float a)
-{
- return (a > 0.0 ? 1.0f : -1.0f);
-}
-
-inline float pythag(float a, float b)
-{
- float absa,absb;
- absa = abs(a);
- absb = abs(b);
-
- if (absa > absb) {
- float sqr = absb/absa;
- sqr *= sqr;
- return absa * float(sqrt(1 + sqr));
- } else {
- if (absb > float(0)) {
- float sqr = absa/absb;
- sqr *= sqr;
- return absb * float(sqrt(1 + sqr));
- } else {
- return float(0);
- }
- }
-}
-
-inline double pythag(double a, double b)
-{
- double absa,absb;
- absa = abs(a);
- absb = abs(b);
-
- if (absa > absb) {
- double sqr = absb/absa;
- sqr *= sqr;
- return absa * double(sqrt(1 + sqr));
- } else {
-
- if (absb > double(0)) {
- double sqr = absa/absb;
- sqr *= sqr;
- return absb * double(sqrt(1 + sqr));
- } else {
- return double(0);
- }
- }
-}
-
-
-} /* namespace TNT */
-
-#endif /* TNTMATH_H */
-
diff --git a/intern/iksolver/intern/TNT/tntreqs.h b/intern/iksolver/intern/TNT/tntreqs.h
deleted file mode 100644
index 2ee124d5940..00000000000
--- a/intern/iksolver/intern/TNT/tntreqs.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-// The requirements for a bare-bones vector class:
-//
-//
-// o) must have 0-based [] indexing for const and
-// non-const objects (i.e. operator[] defined)
-//
-// o) must have size() method to denote the number of
-// elements
-// o) must clean up after itself when destructed
-// (i.e. no memory leaks)
-//
-// -) must have begin() and end() methods (The begin()
-// method is necessary, because relying on
-// &v_[0] may not work on a empty vector (i.e. v_ is NULL.)
-//
-// o) must be templated
-// o) must have X::value_type defined to be the types of elements
-// o) must have X::X(const &x) copy constructor (by *value*)
-// o) must have X::X(int N) constructor to N-length vector
-// (NOTE: this constructor need *NOT* initalize elements)
-//
-// -) must have X::X(int N, T scalar) constructor to initalize
-// elements to value of "scalar".
-//
-// ( removed, because valarray<> class uses (scalar, N) rather
-// than (N, scalar) )
-// -) must have X::X(int N, const T* scalars) constructor to copy from
-// any C linear array
-//
-// ( removed, because of same reverse order of valarray<> )
-//
-// o) must have assignment A=B, by value
-//
-// NOTE: this class is *NOT* meant to be derived from,
-// so its methods (particularly indexing) need not be
-// declared virtual.
-//
-//
-// Some things it *DOES NOT* need to do are
-//
-// o) bounds checking
-// o) array referencing (e.g. reference counting)
-// o) support () indexing
-// o) I/O
-//
-
diff --git a/intern/iksolver/intern/TNT/transv.h b/intern/iksolver/intern/TNT/transv.h
deleted file mode 100644
index 5500cecff40..00000000000
--- a/intern/iksolver/intern/TNT/transv.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Matrix Transpose Views
-
-#ifndef TRANSV_H
-#define TRANSV_H
-
-#include <iostream>
-#include <cassert>
-#include "vec.h"
-
-namespace TNT
-{
-
-template <class Array2D>
-class Transpose_View
-{
- protected:
-
- const Array2D & A_;
-
- public:
-
- typedef typename Array2D::element_type T;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
-
- const Array2D & array() const { return A_; }
- Subscript num_rows() const { return A_.num_cols();}
- Subscript num_cols() const { return A_.num_rows();}
- Subscript lbound() const { return A_.lbound(); }
- Subscript dim(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert( A_.lbound() <= i);
- assert( i<= A_.lbound()+1);
-#endif
- if (i== A_.lbound())
- return num_rows();
- else
- return num_cols();
- }
-
-
- Transpose_View(const Transpose_View<Array2D> &A) : A_(A.A_) {};
- Transpose_View(const Array2D &A) : A_(A) {};
-
-
- inline const typename Array2D::element_type & operator()(
- Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(lbound()<=i);
- assert(i<=A_.num_cols() + lbound() - 1);
- assert(lbound()<=j);
- assert(j<=A_.num_rows() + lbound() - 1);
-#endif
-
- return A_(j,i);
- }
-
-
-};
-
-template <class Matrix>
-Transpose_View<Matrix> Transpose_view(const Matrix &A)
-{
- return Transpose_View<Matrix>(A);
-}
-
-template <class Matrix, class T>
-Vector<T> matmult(
- const Transpose_View<Matrix> & A,
- const Vector<T> &B)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(B.dim() == N);
-
- Vector<T> x(N);
-
- Subscript i, j;
- T tmp = 0;
-
- for (i=1; i<=M; i++)
- {
- tmp = 0;
- for (j=1; j<=N; j++)
- tmp += A(i,j) * B(j);
- x(i) = tmp;
- }
-
- return x;
-}
-
-template <class Matrix, class T>
-inline Vector<T> operator*(const Transpose_View<Matrix> & A, const Vector<T> &B)
-{
- return matmult(A,B);
-}
-
-
-template <class Matrix>
-std::ostream& operator<<(std::ostream &s, const Transpose_View<Matrix> &A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- Subscript start = A.lbound();
- Subscript Mend = M + A.lbound() - 1;
- Subscript Nend = N + A.lbound() - 1;
-
- s << M << " " << N << endl;
- for (Subscript i=start; i<=Mend; i++)
- {
- for (Subscript j=start; j<=Nend; j++)
- {
- s << A(i,j) << " ";
- }
- s << endl;
- }
-
-
- return s;
-}
-
-} // namespace TNT
-
-#endif // TRANSV_H
-
diff --git a/intern/iksolver/intern/TNT/triang.h b/intern/iksolver/intern/TNT/triang.h
deleted file mode 100644
index 10ec2cb18c3..00000000000
--- a/intern/iksolver/intern/TNT/triang.h
+++ /dev/null
@@ -1,637 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Triangular Matrices (Views and Adpators)
-
-#ifndef TRIANG_H
-#define TRIANG_H
-
-// default to use lower-triangular portions of arrays
-// for symmetric matrices.
-
-namespace TNT
-{
-
-template <class MaTRiX>
-class LowerTriangularView
-{
- protected:
-
-
- const MaTRiX &A_;
- const typename MaTRiX::element_type zero_;
-
- public:
-
-
- typedef typename MaTRiX::const_reference const_reference;
- typedef const typename MaTRiX::element_type element_type;
- typedef const typename MaTRiX::element_type value_type;
- typedef element_type T;
-
- Subscript dim(Subscript d) const { return A_.dim(d); }
- Subscript lbound() const { return A_.lbound(); }
- Subscript num_rows() const { return A_.num_rows(); }
- Subscript num_cols() const { return A_.num_cols(); }
-
-
- // constructors
-
- LowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {}
-
-
- inline const_reference get(Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(lbound()<=i);
- assert(i<=A_.num_rows() + lbound() - 1);
- assert(lbound()<=j);
- assert(j<=A_.num_cols() + lbound() - 1);
-#endif
- if (i<j)
- return zero_;
- else
- return A_(i,j);
- }
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(lbound()<=i);
- assert(i<=A_.num_rows() + lbound() - 1);
- assert(lbound()<=j);
- assert(j<=A_.num_cols() + lbound() - 1);
-#endif
- if (i<j)
- return zero_;
- else
- return A_(i,j);
- }
-
-#ifdef TNT_USE_REGIONS
-
- typedef const_Region2D< LowerTriangularView<MaTRiX> >
- const_Region;
-
- const_Region operator()(/*const*/ Index1D &I,
- /*const*/ Index1D &J) const
- {
- return const_Region(*this, I, J);
- }
-
- const_Region operator()(Subscript i1, Subscript i2,
- Subscript j1, Subscript j2) const
- {
- return const_Region(*this, i1, i2, j1, j2);
- }
-
-
-
-#endif
-// TNT_USE_REGIONS
-
-};
-
-
-/* *********** Lower_triangular_view() algorithms ****************** */
-
-template <class MaTRiX, class VecToR>
-VecToR matmult(/*const*/ LowerTriangularView<MaTRiX> &A, VecToR &x)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(N == x.dim());
-
- Subscript i, j;
- typename MaTRiX::element_type sum=0.0;
- VecToR result(M);
-
- Subscript start = A.lbound();
- Subscript Mend = M + A.lbound() -1 ;
-
- for (i=start; i<=Mend; i++)
- {
- sum = 0.0;
- for (j=start; j<=i; j++)
- sum = sum + A(i,j)*x(j);
- result(i) = sum;
- }
-
- return result;
-}
-
-template <class MaTRiX, class VecToR>
-inline VecToR operator*(/*const*/ LowerTriangularView<MaTRiX> &A, VecToR &x)
-{
- return matmult(A,x);
-}
-
-template <class MaTRiX>
-class UnitLowerTriangularView
-{
- protected:
-
- const MaTRiX &A_;
- const typename MaTRiX::element_type zero;
- const typename MaTRiX::element_type one;
-
- public:
-
- typedef typename MaTRiX::const_reference const_reference;
- typedef typename MaTRiX::element_type element_type;
- typedef typename MaTRiX::element_type value_type;
- typedef element_type T;
-
- Subscript lbound() const { return 1; }
- Subscript dim(Subscript d) const { return A_.dim(d); }
- Subscript num_rows() const { return A_.num_rows(); }
- Subscript num_cols() const { return A_.num_cols(); }
-
-
- // constructors
-
- UnitLowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {}
-
-
- inline const_reference get(Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i<=A_.dim(1));
- assert(1<=j);
- assert(j<=A_.dim(2));
- assert(0<=i && i<A_.dim(0) && 0<=j && j<A_.dim(1));
-#endif
- if (i>j)
- return A_(i,j);
- else if (i==j)
- return one;
- else
- return zero;
- }
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i<=A_.dim(1));
- assert(1<=j);
- assert(j<=A_.dim(2));
-#endif
- if (i>j)
- return A_(i,j);
- else if (i==j)
- return one;
- else
- return zero;
- }
-
-
-#ifdef TNT_USE_REGIONS
- // These are the "index-aware" features
-
- typedef const_Region2D< UnitLowerTriangularView<MaTRiX> >
- const_Region;
-
- const_Region operator()(/*const*/ Index1D &I,
- /*const*/ Index1D &J) const
- {
- return const_Region(*this, I, J);
- }
-
- const_Region operator()(Subscript i1, Subscript i2,
- Subscript j1, Subscript j2) const
- {
- return const_Region(*this, i1, i2, j1, j2);
- }
-#endif
-// TNT_USE_REGIONS
-};
-
-template <class MaTRiX>
-LowerTriangularView<MaTRiX> Lower_triangular_view(
- /*const*/ MaTRiX &A)
-{
- return LowerTriangularView<MaTRiX>(A);
-}
-
-
-template <class MaTRiX>
-UnitLowerTriangularView<MaTRiX> Unit_lower_triangular_view(
- /*const*/ MaTRiX &A)
-{
- return UnitLowerTriangularView<MaTRiX>(A);
-}
-
-template <class MaTRiX, class VecToR>
-VecToR matmult(/*const*/ UnitLowerTriangularView<MaTRiX> &A, VecToR &x)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(N == x.dim());
-
- Subscript i, j;
- typename MaTRiX::element_type sum=0.0;
- VecToR result(M);
-
- Subscript start = A.lbound();
- Subscript Mend = M + A.lbound() -1 ;
-
- for (i=start; i<=Mend; i++)
- {
- sum = 0.0;
- for (j=start; j<i; j++)
- sum = sum + A(i,j)*x(j);
- result(i) = sum + x(i);
- }
-
- return result;
-}
-
-template <class MaTRiX, class VecToR>
-inline VecToR operator*(/*const*/ UnitLowerTriangularView<MaTRiX> &A, VecToR &x)
-{
- return matmult(A,x);
-}
-
-
-//********************** Algorithms *************************************
-
-
-
-template <class MaTRiX>
-std::ostream& operator<<(std::ostream &s, const LowerTriangularView<MaTRiX>&A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << endl;
-
- for (Subscript i=1; i<=M; i++)
- {
- for (Subscript j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << endl;
- }
-
-
- return s;
-}
-
-template <class MaTRiX>
-std::ostream& operator<<(std::ostream &s,
- const UnitLowerTriangularView<MaTRiX>&A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << endl;
-
- for (Subscript i=1; i<=M; i++)
- {
- for (Subscript j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << endl;
- }
-
-
- return s;
-}
-
-
-
-// ******************* Upper Triangular Section **************************
-
-template <class MaTRiX>
-class UpperTriangularView
-{
- protected:
-
-
- /*const*/ MaTRiX &A_;
- /*const*/ typename MaTRiX::element_type zero_;
-
- public:
-
-
- typedef typename MaTRiX::const_reference const_reference;
- typedef /*const*/ typename MaTRiX::element_type element_type;
- typedef /*const*/ typename MaTRiX::element_type value_type;
- typedef element_type T;
-
- Subscript dim(Subscript d) const { return A_.dim(d); }
- Subscript lbound() const { return A_.lbound(); }
- Subscript num_rows() const { return A_.num_rows(); }
- Subscript num_cols() const { return A_.num_cols(); }
-
-
- // constructors
-
- UpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {}
-
-
- inline const_reference get(Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(lbound()<=i);
- assert(i<=A_.num_rows() + lbound() - 1);
- assert(lbound()<=j);
- assert(j<=A_.num_cols() + lbound() - 1);
-#endif
- if (i>j)
- return zero_;
- else
- return A_(i,j);
- }
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(lbound()<=i);
- assert(i<=A_.num_rows() + lbound() - 1);
- assert(lbound()<=j);
- assert(j<=A_.num_cols() + lbound() - 1);
-#endif
- if (i>j)
- return zero_;
- else
- return A_(i,j);
- }
-
-#ifdef TNT_USE_REGIONS
-
- typedef const_Region2D< UpperTriangularView<MaTRiX> >
- const_Region;
-
- const_Region operator()(const Index1D &I,
- const Index1D &J) const
- {
- return const_Region(*this, I, J);
- }
-
- const_Region operator()(Subscript i1, Subscript i2,
- Subscript j1, Subscript j2) const
- {
- return const_Region(*this, i1, i2, j1, j2);
- }
-
-
-
-#endif
-// TNT_USE_REGIONS
-
-};
-
-
-/* *********** Upper_triangular_view() algorithms ****************** */
-
-template <class MaTRiX, class VecToR>
-VecToR matmult(/*const*/ UpperTriangularView<MaTRiX> &A, VecToR &x)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(N == x.dim());
-
- Subscript i, j;
- typename VecToR::element_type sum=0.0;
- VecToR result(M);
-
- Subscript start = A.lbound();
- Subscript Mend = M + A.lbound() -1 ;
-
- for (i=start; i<=Mend; i++)
- {
- sum = 0.0;
- for (j=i; j<=N; j++)
- sum = sum + A(i,j)*x(j);
- result(i) = sum;
- }
-
- return result;
-}
-
-template <class MaTRiX, class VecToR>
-inline VecToR operator*(/*const*/ UpperTriangularView<MaTRiX> &A, VecToR &x)
-{
- return matmult(A,x);
-}
-
-template <class MaTRiX>
-class UnitUpperTriangularView
-{
- protected:
-
- const MaTRiX &A_;
- const typename MaTRiX::element_type zero;
- const typename MaTRiX::element_type one;
-
- public:
-
- typedef typename MaTRiX::const_reference const_reference;
- typedef typename MaTRiX::element_type element_type;
- typedef typename MaTRiX::element_type value_type;
- typedef element_type T;
-
- Subscript lbound() const { return 1; }
- Subscript dim(Subscript d) const { return A_.dim(d); }
- Subscript num_rows() const { return A_.num_rows(); }
- Subscript num_cols() const { return A_.num_cols(); }
-
-
- // constructors
-
- UnitUpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {}
-
-
- inline const_reference get(Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i<=A_.dim(1));
- assert(1<=j);
- assert(j<=A_.dim(2));
- assert(0<=i && i<A_.dim(0) && 0<=j && j<A_.dim(1));
-#endif
- if (i<j)
- return A_(i,j);
- else if (i==j)
- return one;
- else
- return zero;
- }
-
-
- inline const_reference operator() (Subscript i, Subscript j) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i<=A_.dim(1));
- assert(1<=j);
- assert(j<=A_.dim(2));
-#endif
- if (i<j)
- return A_(i,j);
- else if (i==j)
- return one;
- else
- return zero;
- }
-
-
-#ifdef TNT_USE_REGIONS
- // These are the "index-aware" features
-
- typedef const_Region2D< UnitUpperTriangularView<MaTRiX> >
- const_Region;
-
- const_Region operator()(const Index1D &I,
- const Index1D &J) const
- {
- return const_Region(*this, I, J);
- }
-
- const_Region operator()(Subscript i1, Subscript i2,
- Subscript j1, Subscript j2) const
- {
- return const_Region(*this, i1, i2, j1, j2);
- }
-#endif
-// TNT_USE_REGIONS
-};
-
-template <class MaTRiX>
-UpperTriangularView<MaTRiX> Upper_triangular_view(
- /*const*/ MaTRiX &A)
-{
- return UpperTriangularView<MaTRiX>(A);
-}
-
-
-template <class MaTRiX>
-UnitUpperTriangularView<MaTRiX> Unit_upper_triangular_view(
- /*const*/ MaTRiX &A)
-{
- return UnitUpperTriangularView<MaTRiX>(A);
-}
-
-template <class MaTRiX, class VecToR>
-VecToR matmult(/*const*/ UnitUpperTriangularView<MaTRiX> &A, VecToR &x)
-{
- Subscript M = A.num_rows();
- Subscript N = A.num_cols();
-
- assert(N == x.dim());
-
- Subscript i, j;
- typename VecToR::element_type sum=0.0;
- VecToR result(M);
-
- Subscript start = A.lbound();
- Subscript Mend = M + A.lbound() -1 ;
-
- for (i=start; i<=Mend; i++)
- {
- sum = x(i);
- for (j=i+1; j<=N; j++)
- sum = sum + A(i,j)*x(j);
- result(i) = sum + x(i);
- }
-
- return result;
-}
-
-template <class MaTRiX, class VecToR>
-inline VecToR operator*(/*const*/ UnitUpperTriangularView<MaTRiX> &A, VecToR &x)
-{
- return matmult(A,x);
-}
-
-
-//********************** Algorithms *************************************
-
-
-
-template <class MaTRiX>
-std::ostream& operator<<(std::ostream &s,
- /*const*/ UpperTriangularView<MaTRiX>&A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << endl;
-
- for (Subscript i=1; i<=M; i++)
- {
- for (Subscript j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << endl;
- }
-
-
- return s;
-}
-
-template <class MaTRiX>
-std::ostream& operator<<(std::ostream &s,
- /*const*/ UnitUpperTriangularView<MaTRiX>&A)
-{
- Subscript M=A.num_rows();
- Subscript N=A.num_cols();
-
- s << M << " " << N << endl;
-
- for (Subscript i=1; i<=M; i++)
- {
- for (Subscript j=1; j<=N; j++)
- {
- s << A(i,j) << " ";
- }
- s << endl;
- }
-
-
- return s;
-}
-
-} // namespace TNT
-
-#endif //TRIANG_H
-
diff --git a/intern/iksolver/intern/TNT/trisolve.h b/intern/iksolver/intern/TNT/trisolve.h
deleted file mode 100644
index e6e2a0afe3a..00000000000
--- a/intern/iksolver/intern/TNT/trisolve.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-// Triangular Solves
-
-#ifndef TRISLV_H
-#define TRISLV_H
-
-
-#include "triang.h"
-
-namespace TNT
-{
-
-template <class MaTriX, class VecToR>
-VecToR Lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b)
-{
- Subscript N = A.num_rows();
-
- // make sure matrix sizes agree; A must be square
-
- assert(A.num_cols() == N);
- assert(b.dim() == N);
-
- VecToR x(N);
-
- Subscript i;
- for (i=1; i<=N; i++)
- {
- typename MaTriX::element_type tmp=0;
-
- for (Subscript j=1; j<i; j++)
- tmp = tmp + A(i,j)*x(j);
-
- x(i) = (b(i) - tmp)/ A(i,i);
- }
-
- return x;
-}
-
-
-template <class MaTriX, class VecToR>
-VecToR Unit_lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b)
-{
- Subscript N = A.num_rows();
-
- // make sure matrix sizes agree; A must be square
-
- assert(A.num_cols() == N);
- assert(b.dim() == N);
-
- VecToR x(N);
-
- Subscript i;
- for (i=1; i<=N; i++)
- {
-
- typename MaTriX::element_type tmp=0;
-
- for (Subscript j=1; j<i; j++)
- tmp = tmp + A(i,j)*x(j);
-
- x(i) = b(i) - tmp;
- }
-
- return x;
-}
-
-
-template <class MaTriX, class VecToR>
-VecToR linear_solve(/*const*/ LowerTriangularView<MaTriX> &A,
- /*const*/ VecToR &b)
-{
- return Lower_triangular_solve(A, b);
-}
-
-template <class MaTriX, class VecToR>
-VecToR linear_solve(/*const*/ UnitLowerTriangularView<MaTriX> &A,
- /*const*/ VecToR &b)
-{
- return Unit_lower_triangular_solve(A, b);
-}
-
-
-
-//********************** Upper triangular section ****************
-
-template <class MaTriX, class VecToR>
-VecToR Upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b)
-{
- Subscript N = A.num_rows();
-
- // make sure matrix sizes agree; A must be square
-
- assert(A.num_cols() == N);
- assert(b.dim() == N);
-
- VecToR x(N);
-
- Subscript i;
- for (i=N; i>=1; i--)
- {
-
- typename MaTriX::element_type tmp=0;
-
- for (Subscript j=i+1; j<=N; j++)
- tmp = tmp + A(i,j)*x(j);
-
- x(i) = (b(i) - tmp)/ A(i,i);
- }
-
- return x;
-}
-
-
-template <class MaTriX, class VecToR>
-VecToR Unit_upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b)
-{
- Subscript N = A.num_rows();
-
- // make sure matrix sizes agree; A must be square
-
- assert(A.num_cols() == N);
- assert(b.dim() == N);
-
- VecToR x(N);
-
- Subscript i;
- for (i=N; i>=1; i--)
- {
-
- typename MaTriX::element_type tmp=0;
-
- for (Subscript j=i+1; j<i; j++)
- tmp = tmp + A(i,j)*x(j);
-
- x(i) = b(i) - tmp;
- }
-
- return x;
-}
-
-
-template <class MaTriX, class VecToR>
-VecToR linear_solve(/*const*/ UpperTriangularView<MaTriX> &A,
- /*const*/ VecToR &b)
-{
- return Upper_triangular_solve(A, b);
-}
-
-template <class MaTriX, class VecToR>
-VecToR linear_solve(/*const*/ UnitUpperTriangularView<MaTriX> &A,
- /*const*/ VecToR &b)
-{
- return Unit_upper_triangular_solve(A, b);
-}
-
-
-} // namespace TNT
-
-#endif // TRISLV_H
-
diff --git a/intern/iksolver/intern/TNT/vec.h b/intern/iksolver/intern/TNT/vec.h
deleted file mode 100644
index 5d4ef14bf73..00000000000
--- a/intern/iksolver/intern/TNT/vec.h
+++ /dev/null
@@ -1,491 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-// Basic TNT numerical vector (0-based [i] AND 1-based (i) indexing )
-//
-
-#ifndef VEC_H
-#define VEC_H
-
-#include "subscript.h"
-#include <stdlib.h>
-#include <assert.h>
-#include <iostream>
-
-namespace TNT
-{
-
-template <class T>
-class Vector
-{
-
-
- public:
-
- typedef Subscript size_type;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1;}
-
- protected:
- T* v_;
- T* vm1_; // pointer adjustment for optimzied 1-offset indexing
- Subscript n_;
-
- // internal helper function to create the array
- // of row pointers
-
- void initialize(Subscript N)
- {
- // adjust pointers so that they are 1-offset:
- // v_[] is the internal contiguous array, it is still 0-offset
- //
- assert(v_ == NULL);
- v_ = new T[N];
- assert(v_ != NULL);
- vm1_ = v_-1;
- n_ = N;
- }
-
- void copy(const T* v)
- {
- Subscript N = n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = v[i];
- v_[i+1] = v[i+1];
- v_[i+2] = v[i+2];
- v_[i+3] = v[i+3];
- }
-
- for (i=N4; i< N; i++)
- v_[i] = v[i];
-#else
-
- for (i=0; i< N; i++)
- v_[i] = v[i];
-#endif
- }
-
- void set(const T& val)
- {
- Subscript N = n_;
- Subscript i;
-
-#ifdef TNT_UNROLL_LOOPS
- Subscript Nmod4 = N & 3;
- Subscript N4 = N - Nmod4;
-
- for (i=0; i<N4; i+=4)
- {
- v_[i] = val;
- v_[i+1] = val;
- v_[i+2] = val;
- v_[i+3] = val;
- }
-
- for (i=N4; i< N; i++)
- v_[i] = val;
-#else
-
- for (i=0; i< N; i++)
- v_[i] = val;
-
-#endif
- }
-
-
-
- void destroy()
- {
- /* do nothing, if no memory has been previously allocated */
- if (v_ == NULL) return ;
-
- /* if we are here, then matrix was previously allocated */
- delete [] (v_);
-
- v_ = NULL;
- vm1_ = NULL;
- }
-
-
- public:
-
- // access
-
- iterator begin() { return v_;}
- iterator end() { return v_ + n_; }
- const iterator begin() const { return v_;}
- const iterator end() const { return v_ + n_; }
-
- // destructor
-
- ~Vector()
- {
- destroy();
- }
-
- // constructors
-
- Vector() : v_(0), vm1_(0), n_(0) {}
-
- Vector(const Vector<T> &A) : v_(0), vm1_(0), n_(0)
- {
- initialize(A.n_);
- copy(A.v_);
- }
-
- Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- set(value);
- }
-
- Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0)
- {
- initialize(N);
- copy(v);
- }
-
-
- // methods
- //
- Vector<T>& newsize(Subscript N)
- {
- if (n_ == N) return *this;
-
- destroy();
- initialize(N);
-
- return *this;
- }
-
-
- // assignments
- //
- Vector<T>& operator=(const Vector<T> &A)
- {
- if (v_ == A.v_)
- return *this;
-
- if (n_ == A.n_) // no need to re-alloc
- copy(A.v_);
-
- else
- {
- destroy();
- initialize(A.n_);
- copy(A.v_);
- }
-
- return *this;
- }
-
- Vector<T>& operator=(const T& scalar)
- {
- set(scalar);
- return *this;
- }
-
- inline Subscript dim() const
- {
- return n_;
- }
-
- inline Subscript size() const
- {
- return n_;
- }
-
-
- inline reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= n_) ;
-#endif
- return vm1_[i];
- }
-
- inline const_reference operator() (Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i <= n_) ;
-#endif
- return vm1_[i];
- }
-
- inline reference operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i < n_) ;
-#endif
- return v_[i];
- }
-
- inline const_reference operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i) ;
- assert(i < n_) ;
-#endif
- return v_[i];
- }
-
-
-
-};
-
-
-/* *************************** I/O ********************************/
-
-template <class T>
-std::ostream& operator<<(std::ostream &s, const Vector<T> &A)
-{
- Subscript N=A.dim();
-
- s << N << std::endl;
-
- for (Subscript i=0; i<N; i++)
- s << A[i] << " " << std::endl;
- s << std::endl;
-
- return s;
-}
-
-template <class T>
-std::istream & operator>>(std::istream &s, Vector<T> &A)
-{
-
- Subscript N;
-
- s >> N;
-
- if ( !(N == A.size() ))
- {
- A.newsize(N);
- }
-
-
- for (Subscript i=0; i<N; i++)
- s >> A[i];
-
-
- return s;
-}
-
-// *******************[ basic matrix algorithms ]***************************
-
-
-template <class T>
-Vector<T> operator+(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] + B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator-(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] - B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator*(const Vector<T> &A,
- const Vector<T> &B)
-{
- Subscript N = A.dim();
-
- assert(N==B.dim());
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] * B[i];
-
- return tmp;
-}
-
-template <class T>
-Vector<T> operator*(const Vector<T> &A,
- const T &B)
-{
- Subscript N = A.dim();
-
- Vector<T> tmp(N);
- Subscript i;
-
- for (i=0; i<N; i++)
- tmp[i] = A[i] * B;
-
- return tmp;
-}
-
-
-template <class T>
-T dot_prod(const Vector<T> &A, const Vector<T> &B)
-{
- Subscript N = A.dim();
- assert(N == B.dim());
-
- Subscript i;
- T sum = 0;
-
- for (i=0; i<N; i++)
- sum += A[i] * B[i];
-
- return sum;
-}
-
-// inplace versions of the above template functions
-
-// A = A + B
-
-template <class T>
-void vectoradd(
- Vector<T> &A,
- const Vector<T> &B)
-{
- const Subscript N = A.dim();
- assert(N==B.dim());
- Subscript i;
-
- for (i=0; i<N; i++)
- A[i] += B[i];
-}
-
-// same with separate output vector
-
-template <class T>
-void vectoradd(
- Vector<T> &C,
- const Vector<T> &A,
- const Vector<T> &B)
-{
- const Subscript N = A.dim();
- assert(N==B.dim());
- Subscript i;
-
- for (i=0; i<N; i++)
- C[i] = A[i] + B[i];
-}
-
-// A = A - B
-
-template <class T>
-void vectorsub(
- Vector<T> &A,
- const Vector<T> &B)
-{
- const Subscript N = A.dim();
- assert(N==B.dim());
- Subscript i;
-
- for (i=0; i<N; i++)
- A[i] -= B[i];
-}
-
-template <class T>
-void vectorsub(
- Vector<T> &C,
- const Vector<T> &A,
- const Vector<T> &B)
-{
- const Subscript N = A.dim();
- assert(N==B.dim());
- Subscript i;
-
- for (i=0; i<N; i++)
- C[i] = A[i] - B[i];
-}
-
-template <class T>
-void vectorscale(
- Vector<T> &C,
- const Vector<T> &A,
- const T &B)
-{
- const Subscript N = A.dim();
- Subscript i;
-
- for (i=0; i<N; i++)
- C[i] = A[i] * B;
-}
-
-template <class T>
-void vectorscale(
- Vector<T> &A,
- const T &B)
-{
- const Subscript N = A.dim();
- Subscript i;
-
- for (i=0; i<N; i++)
- A[i] *= B;
-}
-
-} /* namespace TNT */
-
-#endif // VEC_H
-
diff --git a/intern/iksolver/intern/TNT/vecadaptor.h b/intern/iksolver/intern/TNT/vecadaptor.h
deleted file mode 100644
index 77d4e2c05a4..00000000000
--- a/intern/iksolver/intern/TNT/vecadaptor.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/**
- */
-
-/*
-
-*
-* Template Numerical Toolkit (TNT): Linear Algebra Module
-*
-* Mathematical and Computational Sciences Division
-* National Institute of Technology,
-* Gaithersburg, MD USA
-*
-*
-* This software was developed at the National Institute of Standards and
-* Technology (NIST) by employees of the Federal Government in the course
-* of their official duties. Pursuant to title 17 Section 105 of the
-* United States Code, this software is not subject to copyright protection
-* and is in the public domain. The Template Numerical Toolkit (TNT) is
-* an experimental system. NIST assumes no responsibility whatsoever for
-* its use by other parties, and makes no guarantees, expressed or implied,
-* about its quality, reliability, or any other characteristic.
-*
-* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-* see http://math.nist.gov/tnt for latest updates.
-*
-*/
-
-
-
-#ifndef VECADAPTOR_H
-#define VECADAPTOR_H
-
-#include <cstdlib>
-#include <iostream>
-#include <cassert>
-
-#include "subscript.h"
-
-#ifdef TNT_USE_REGIONS
-#include "region1d.h"
-#endif
-
-namespace TNT
-{
-
-// see "tntreq.h" for TNT requirements for underlying vector
-// class. This need NOT be the STL vector<> class, but a subset
-// that provides minimal services.
-//
-// This is a container adaptor that provides the following services.
-//
-// o) adds 1-offset operator() access ([] is always 0 offset)
-// o) adds TNT_BOUNDS_CHECK to () and []
-// o) adds initialization from strings, e.g. "1.0 2.0 3.0";
-// o) adds newsize(N) function (does not preserve previous values)
-// o) adds dim() and dim(1)
-// o) adds free() function to release memory used by vector
-// o) adds regions, e.g. A(Index(1,10)) = ...
-// o) add getVector() method to return adapted container
-// o) adds simple I/O for ostreams
-
-template <class BBVec>
-class Vector_Adaptor
-{
-
- public:
- typedef typename BBVec::value_type T;
- typedef T value_type;
- typedef T element_type;
- typedef T* pointer;
- typedef T* iterator;
- typedef T& reference;
- typedef const T* const_iterator;
- typedef const T& const_reference;
-
- Subscript lbound() const { return 1; }
-
- protected:
- BBVec v_;
- T* vm1_;
-
- public:
-
- Subscript size() const { return v_.size(); }
-
- // These were removed so that the ANSI C++ valarray class
- // would work as a possible storage container.
- //
- //
- //iterator begin() { return v_.begin();}
- //iterator begin() { return &v_[0];}
- //
- //iterator end() { return v_.end(); }
- //iterator end() { return &v_[0] + v_.size(); }
- //
- //const_iterator begin() const { return v_.begin();}
- //const_iterator begin() const { return &v_[0];}
- //
- //const_iterator end() const { return v_.end(); }
- //const_iterator end() const { return &v_[0] + v_.size(); }
-
- BBVec& getVector() { return v_; }
- Subscript dim() const { return v_.size(); }
- Subscript dim(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(i==TNT_BASE_OFFSET);
-#endif
- return (i==TNT_BASE_OFFSET ? v_.size() : 0 );
- }
- Vector_Adaptor() : v_() {};
- Vector_Adaptor(const Vector_Adaptor<BBVec> &A) : v_(A.v_)
- {
- vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL);
-
- }
-
- Vector_Adaptor(Subscript N, const T& value = T()) : v_(N)
- {
- for (Subscript i=0; i<N; i++)
- v_[i] = value;
-
- vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL);
- }
-
- Vector_Adaptor(Subscript N, const T* values) : v_(N)
- {
- for (Subscript i=0; i<N; i++)
- v_[i] = values[i];
- vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL);
- }
- Vector_Adaptor(const BBVec & A) : v_(A)
- {
- vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL);
- }
-
- // NOTE: this assumes that BBVec(0) constructor creates an
- // null vector that does not take up space... It would be
- // great to require that BBVec have a corresponding free()
- // function, but in particular STL vectors do not.
- //
- Vector_Adaptor<BBVec>& free()
- {
- return *this = Vector_Adaptor<BBVec>(0);
- }
-
- Vector_Adaptor<BBVec>& operator=(const Vector_Adaptor<BBVec> &A)
- {
- v_ = A.v_ ;
- vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL);
- return *this;
- }
-
- Vector_Adaptor<BBVec>& newsize(Subscript N)
- {
- // NOTE: this is not as efficient as it could be
- // but to retain compatiblity with STL interface
- // we cannot assume underlying implementation
- // has a newsize() function.
-
- return *this = Vector_Adaptor<BBVec>(N);
-
- }
-
- Vector_Adaptor<BBVec>& operator=(const T &a)
- {
- Subscript i;
- Subscript N = v_.size();
- for (i=0; i<N; i++)
- v_[i] = a;
-
- return *this;
- }
-
- Vector_Adaptor<BBVec>& resize(Subscript N)
- {
- if (N == size()) return *this;
-
- Vector_Adaptor<BBVec> tmp(N);
- Subscript n = (N < size() ? N : size()); // min(N, size());
- Subscript i;
-
- for (i=0; i<n; i++)
- tmp[i] = v_[i];
-
-
- return (*this = tmp);
-
- }
-
-
- reference operator()(Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i<=dim());
-#endif
- return vm1_[i];
- }
-
- const_reference operator()(Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(1<=i);
- assert(i<=dim());
-#endif
- return vm1_[i];
- }
-
- reference operator[](Subscript i)
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i<dim());
-#endif
- return v_[i];
- }
-
- const_reference operator[](Subscript i) const
- {
-#ifdef TNT_BOUNDS_CHECK
- assert(0<=i);
- assert(i<dim());
-#endif
- return v_[i];
- }
-
-
-#ifdef TNT_USE_REGIONS
- // "index-aware" features, all of these are 1-based offsets
-
- typedef Region1D<Vector_Adaptor<BBVec> > Region;
-
- typedef const_Region1D< Vector_Adaptor<BBVec> > const_Region;
-
- Region operator()(const Index1D &I)
- { return Region(*this, I); }
-
- Region operator()(const Subscript i1, Subscript i2)
- { return Region(*this, i1, i2); }
-
- const_Region operator()(const Index1D &I) const
- { return const_Region(*this, I); }
-
- const_Region operator()(const Subscript i1, Subscript i2) const
- { return const_Region(*this, i1, i2); }
-#endif
-// TNT_USE_REGIONS
-
-
-};
-
-#include <iostream>
-
-template <class BBVec>
-std::ostream& operator<<(std::ostream &s, const Vector_Adaptor<BBVec> &A)
-{
- Subscript M=A.size();
-
- s << M << endl;
- for (Subscript i=1; i<=M; i++)
- s << A(i) << endl;
- return s;
-}
-
-template <class BBVec>
-std::istream& operator>>(std::istream &s, Vector_Adaptor<BBVec> &A)
-{
- Subscript N;
-
- s >> N;
-
- A.resize(N);
-
- for (Subscript i=1; i<=N; i++)
- s >> A(i);
-
- return s;
-}
-
-} // namespace TNT
-
-#endif
-
diff --git a/intern/iksolver/intern/TNT/version.h b/intern/iksolver/intern/TNT/version.h
deleted file mode 100644
index 58017dd80f9..00000000000
--- a/intern/iksolver/intern/TNT/version.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- */
-
-// Template Numerical Toolkit (TNT) for Linear Algebra
-
-//
-// BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
-// Please see http://math.nist.gov/tnt for updates
-//
-// R. Pozo
-// Mathematical and Computational Sciences Division
-// National Institute of Standards and Technology
-
-
-#ifndef TNT_VERSION_H
-#define TNT_VERSION_H
-
-
-#define TNT_MAJOR_VERSION '0'
-#define TNT_MINOR_VERSION '9'
-#define TNT_SUBMINOR_VERSION '4'
-#define TNT_VERSION_STRING "0.9.4"
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp
deleted file mode 100644
index b138dd18725..00000000000
--- a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "GlutDrawer.h"
-
-#include "MT_assert.h"
-
-MEM_SmartPtr<GlutDrawManager> GlutDrawManager::m_s_instance = MEM_SmartPtr<GlutDrawManager>();
-
- GlutDrawManager *
-GlutDrawManager::
-Instance(
-){
- if (m_s_instance == NULL) {
- m_s_instance = new GlutDrawManager();
- }
-
- return m_s_instance;
-}
-
-
-// this is the function you should pass to glut
-
- void
-GlutDrawManager::
-Draw(
-){
- GlutDrawManager *manager = GlutDrawManager::Instance();
-
- if (manager->m_drawer != NULL) {
- manager->m_drawer->Draw();
- }
-}
-
- void
-GlutDrawManager::
-InstallDrawer(
- GlutDrawer * drawer
-){
-
- MT_assert(m_drawer == NULL);
- m_drawer = drawer;
-}
-
- void
-GlutDrawManager::
-ReleaseDrawer(
-){
- m_drawer = NULL;
-}
-
-
-GlutDrawManager::
-~GlutDrawManager(
-){
-
- delete(m_drawer);
-}
-
-
-
-
-
-
-
-
-
diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h
deleted file mode 100644
index 05d2424dfea..00000000000
--- a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __GLUTDRAWER_H__
-#define __GLUTDRAWER_H__
-
-#include "MEM_NonCopyable.h"
-#include "MEM_SmartPtr.h"
-
-// So pissed off with Glut callback stuff
-// that is impossible to call objects unless they are global
-
-// inherit from GlutDrawer and installl the drawer in the singleton
-// class GlutDrawManager.
-
-class GlutDrawer {
-public :
-
- virtual
- void
- Draw(
- )= 0;
-
- virtual
- ~GlutDrawer(
- ){};
-};
-
-class GlutDrawManager : public MEM_NonCopyable{
-
-public :
-
- static
- GlutDrawManager *
- Instance(
- );
-
- // this is the function you should pass to glut
-
- static
- void
- Draw(
- );
-
- void
- InstallDrawer(
- GlutDrawer *
- );
-
- void
- ReleaseDrawer(
- );
-
- ~GlutDrawManager(
- );
-
-private :
-
- GlutDrawManager (
- ) :
- m_drawer (0)
- {
- };
-
- GlutDrawer * m_drawer;
-
- static MEM_SmartPtr<GlutDrawManager> m_s_instance;
-};
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp
deleted file mode 100644
index 0b7a16b032b..00000000000
--- a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "GlutKeyboardManager.h"
-#include "MT_assert.h"
-
-MEM_SmartPtr<GlutKeyboardManager> GlutKeyboardManager::m_s_instance = MEM_SmartPtr<GlutKeyboardManager>();
-
- GlutKeyboardManager *
-GlutKeyboardManager::
-Instance(
-){
- if (m_s_instance == NULL) {
- m_s_instance = new GlutKeyboardManager();
- }
-
- return m_s_instance;
-}
-
-
-// this is the function you should pass to glut
-
- void
-GlutKeyboardManager::
-HandleKeyboard(
- unsigned char key,
- int x,
- int y
-){
- GlutKeyboardManager *manager = GlutKeyboardManager::Instance();
-
- if (manager->m_handler != NULL) {
- manager->m_handler->HandleKeyboard(key,x,y);
- }
-}
-
- void
-GlutKeyboardManager::
-InstallHandler(
- GlutKeyboardHandler * handler
-){
-
- MT_assert(m_handler == NULL);
- m_handler = handler;
-}
-
- void
-GlutKeyboardManager::
-ReleaseHandler(
-){
- m_handler = NULL;
-}
-
-
-GlutKeyboardManager::
-~GlutKeyboardManager(
-){
-
- delete(m_handler);
-}
diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h
deleted file mode 100644
index ea39b6835f6..00000000000
--- a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __GLUTKEYBOARDMANAGER_H__
-#define __GLUTKEYBOARDMANAGER_H__
-
-#include "MEM_NonCopyable.h"
-#include "MEM_SmartPtr.h"
-
-// So pissed off with Glut callback stuff
-// that is impossible to call objects unless they are global
-
-// inherit from GlutKeyboardHandler and installl the drawer in the singleton
-// class GlutKeyboardManager.
-
-class GlutKeyboardHandler : public MEM_NonCopyable {
-public :
-
- virtual
- void
- HandleKeyboard(
- unsigned char key,
- int x,
- int y
- )= 0;
-
- virtual
- ~GlutKeyboardHandler(
- ){};
-};
-
-class GlutKeyboardManager : public MEM_NonCopyable{
-
-public :
-
- static
- GlutKeyboardManager *
- Instance(
- );
-
- // this is the function you should pass to glut
-
- static
- void
- HandleKeyboard(
- unsigned char key,
- int x,
- int y
- );
-
- void
- InstallHandler(
- GlutKeyboardHandler *
- );
-
- void
- ReleaseHandler(
- );
-
- ~GlutKeyboardManager(
- );
-
-private :
-
- GlutKeyboardManager (
- ) :
- m_handler (0)
- {
- };
-
- GlutKeyboardHandler * m_handler;
-
- static MEM_SmartPtr<GlutKeyboardManager> m_s_instance;
-};
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp
deleted file mode 100644
index c426f933e67..00000000000
--- a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "GlutMouseManager.h"
-#include "MT_assert.h"
-
-MEM_SmartPtr<GlutMouseManager> GlutMouseManager::m_s_instance = MEM_SmartPtr<GlutMouseManager>();
-
-
- GlutMouseManager *
-GlutMouseManager::
-Instance(
-){
- if (m_s_instance == NULL) {
- m_s_instance = new GlutMouseManager();
- }
-
- return m_s_instance;
-}
-
-// these are the functions you should pass to GLUT
-
- void
-GlutMouseManager::
-Mouse(
- int button,
- int state,
- int x,
- int y
-){
- GlutMouseManager *manager = GlutMouseManager::Instance();
-
- if (manager->m_handler != NULL) {
- manager->m_handler->Mouse(button,state,x,y);
- }
-}
-
- void
-GlutMouseManager::
-Motion(
- int x,
- int y
-){
- GlutMouseManager *manager = GlutMouseManager::Instance();
-
- if (manager->m_handler != NULL) {
- manager->m_handler->Motion(x,y);
- }
-}
-
- void
-GlutMouseManager::
-InstallHandler(
- GlutMouseHandler *handler
-){
-
- MT_assert(m_handler == NULL);
- m_handler = handler;
-}
-
- void
-GlutMouseManager::
-ReleaseHandler(
-){
- m_handler = NULL;
-}
-
-GlutMouseManager::
-~GlutMouseManager(
-){
-
- delete(m_handler);
-}
-
-
diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h
deleted file mode 100644
index 4a2344b7c74..00000000000
--- a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __GLUTMOUSEMANAGER_H__
-#define __GLUTMOUSEMANAGER_H__
-
-#include "MEM_NonCopyable.h"
-#include "MEM_SmartPtr.h"
-
-class GlutMouseHandler {
-public :
-
- virtual
- void
- Mouse(
- int button,
- int state,
- int x,
- int y
- ) = 0;
-
- virtual
- void
- Motion(
- int x,
- int y
- ) = 0;
-
- virtual
- ~GlutMouseHandler(
- ){};
-};
-
-class GlutMouseManager : public MEM_NonCopyable{
-
-public :
-
- static
- GlutMouseManager *
- Instance(
- );
-
- // these are the functions you should pass to GLUT
-
- static
- void
- Mouse(
- int button,
- int state,
- int x,
- int y
- );
-
- static
- void
- Motion(
- int x,
- int y
- );
-
- void
- InstallHandler(
- GlutMouseHandler *
- );
-
- void
- ReleaseHandler(
- );
-
- ~GlutMouseManager(
- );
-
-private :
-
- GlutMouseManager (
- ) :
- m_handler (0)
- {
- };
-
- GlutMouseHandler * m_handler;
-
- static MEM_SmartPtr<GlutMouseManager> m_s_instance;
-};
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h b/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h
deleted file mode 100644
index f2863806112..00000000000
--- a/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __CHAINDRAWER_H__
-#define __CHAINDRAWER_H__
-
-#include "../common/GlutDrawer.h"
-#include "MyGlutMouseHandler.h"
-#include "MyGlutKeyHandler.h"
-#include "MT_Transform.h"
-# include "IK_Qsolver.h"
-# include "../intern/IK_QChain.h"
-# include "../intern/IK_QSolver_Class.h"
-#include <GL/glut.h>
-
-class ChainDrawer : public GlutDrawer
-{
-public :
- static
- ChainDrawer *
- New(
- ) {
- return new ChainDrawer();
- }
-
- void
- SetMouseHandler(
- MyGlutMouseHandler *mouse_handler
- ) {
- m_mouse_handler = mouse_handler;
- }
-
- void
- SetKeyHandler (
- MyGlutKeyHandler *key_handler
- ) {
- m_key_handler = key_handler;
- }
-
- void
- SetChain(
- IK_Chain_ExternPtr *chains,int chain_num
- ) {
- m_chain_num = chain_num;
- m_chains = chains;
- }
-
-
- // inherited from GlutDrawer
- void
- Draw(
- ) {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glPopMatrix();
- glPushMatrix();
- glRotatef(m_mouse_handler->AngleX(), 0.0, 1.0, 0.0);
- glRotatef(m_mouse_handler->AngleY(), 1.0, 0.0, 0.0);
-
- DrawScene();
- glutSwapBuffers();
-
- }
-
- ~ChainDrawer(
- ){
- // nothing to do
- };
-
-private :
-
- void
- DrawScene(
- ){
-
- // draw a little cross at the position of the key handler
- // coordinates
-
- MT_Vector3 line_x(4,0,0);
- MT_Vector3 line_y(0.0,4,0);
- MT_Vector3 line_z(0.0,0.0,4);
-
- MT_Vector3 cross_origin = m_mouse_handler->Position();
- MT_Vector3 temp;
-
- glDisable(GL_LIGHTING);
-
-
- glBegin(GL_LINES);
-
- glColor3f (1.0f,1.0f,1.0f);
-
- temp = cross_origin - line_x;
- glVertex3f(temp[0],temp[1],temp[2]);
- temp = cross_origin + line_x;
- glVertex3f(temp[0],temp[1],temp[2]);
-
- temp = cross_origin - line_y;
- glVertex3f(temp[0],temp[1],temp[2]);
- temp = cross_origin + line_y;
- glVertex3f(temp[0],temp[1],temp[2]);
-
- temp = cross_origin - line_z;
- glVertex3f(temp[0],temp[1],temp[2]);
- temp = cross_origin + line_z;
- glVertex3f(temp[0],temp[1],temp[2]);
-
- glEnd();
- glEnable(GL_LIGHTING);
-
-
- IK_Chain_ExternPtr chain;
-
- int chain_num;
- for (chain_num = 0; chain_num < m_chain_num; chain_num++) {
- chain = m_chains[chain_num];
-
-
- IK_Segment_ExternPtr segs = chain->segments;
- IK_Segment_ExternPtr seg_start = segs;
- const IK_Segment_ExternPtr seg_end = segs + chain->num_segments;
- float ogl_matrix[16];
-
- glColor3f (0.0f,1.0f,0.0f);
-
- MT_Vector3 previous_origin(0,0,0);
-
- MT_Transform global_transform;
- global_transform.setIdentity();
-
- for (; seg_start != seg_end; ++seg_start) {
-
- glPushMatrix();
-
- // fill ogl_matrix with zeros
-
- std::fill(ogl_matrix,ogl_matrix + 16,float(0));
-
- // we have to do a bit of work here to compute the chain's
- // bone values
-
- // first compute all the matrices we need
-
- MT_Transform translation;
- translation.setIdentity();
- translation.translate(MT_Vector3(0,seg_start->length,0));
-
- MT_Matrix3x3 seg_rot(
- seg_start->basis_change[0],seg_start->basis_change[1],seg_start->basis_change[2],
- seg_start->basis_change[3],seg_start->basis_change[4],seg_start->basis_change[5],
- seg_start->basis_change[6],seg_start->basis_change[7],seg_start->basis_change[8]
- );
-
- seg_rot.transpose();
-
- MT_Matrix3x3 seg_pre_rot(
- seg_start->basis[0],seg_start->basis[1],seg_start->basis[2],
- seg_start->basis[3],seg_start->basis[4],seg_start->basis[5],
- seg_start->basis[6],seg_start->basis[7],seg_start->basis[8]
- );
-
-
- MT_Transform seg_t_pre_rot(
- MT_Point3(
- seg_start->seg_start[0],
- seg_start->seg_start[1],
- seg_start->seg_start[2]
- ),
- seg_pre_rot
- );
- // start of the bone is just the current global transform
- // multiplied by the seg_start vector
-
-
-
- MT_Transform seg_t_rot(MT_Point3(0,0,0),seg_rot);
- MT_Transform seg_local = seg_t_pre_rot * seg_t_rot * translation;
-
- MT_Vector3 bone_start = global_transform *
- MT_Point3(
- seg_start->seg_start[0],
- seg_start->seg_start[1],
- seg_start->seg_start[2]
- );
-
-
- global_transform = global_transform * seg_local;
-
- global_transform.getValue(ogl_matrix);
- MT_Vector3 bone_end = global_transform.getOrigin();
-
- glMultMatrixf(ogl_matrix);
-// glutSolidSphere(0.5,5,5);
-
- glPopMatrix();
-
- glDisable(GL_LIGHTING);
-
- glBegin(GL_LINES);
-
- // draw lines of the principle axis of the local transform
-
- MT_Vector3 x_axis(1,0,0);
- MT_Vector3 y_axis(0,1,0);
- MT_Vector3 z_axis(0,0,1);
-
- x_axis = global_transform.getBasis() * x_axis * 5;
- y_axis = global_transform.getBasis() * y_axis * 5;
- z_axis = global_transform.getBasis() * z_axis * 5;
-
-
- x_axis = x_axis + bone_start;
- y_axis = y_axis + bone_start;
- z_axis = z_axis + bone_start;
-
- glColor3f(1,0,0);
-
- glVertex3f(x_axis.x(),x_axis.y(),x_axis.z());
- glVertex3f(
- bone_start.x(),
- bone_start.y(),
- bone_start.z()
- );
-
- glColor3f(0,1,0);
-
- glVertex3f(y_axis.x(),y_axis.y(),y_axis.z());
- glVertex3f(
- bone_start.x(),
- bone_start.y(),
- bone_start.z()
- );
-
- glColor3f(0,1,1);
-
- glVertex3f(z_axis.x(),z_axis.y(),z_axis.z());
- glVertex3f(
- bone_start.x(),
- bone_start.y(),
- bone_start.z()
- );
-
- glColor3f(0,0,1);
-
- glVertex3f(
- bone_start.x(),
- bone_start.y(),
- bone_start.z()
- );
- glVertex3f(bone_end[0],bone_end[1],bone_end[2]);
-
- glEnd();
- glEnable(GL_LIGHTING);
- }
-#if 0
- // draw jacobian column vectors
-
- // hack access to internals
-
- IK_Solver_Class * internals = static_cast<IK_Solver_Class *>(chain->intern);
-
- glDisable(GL_LIGHTING);
-
- glBegin(GL_LINES);
-
- const TNT::Matrix<MT_Scalar> & jac = internals->Chain().TransposedJacobian();
-
- int i = 0;
- for (i=0; i < jac.num_rows(); i++) {
- glColor3f(1,1,1);
-
- previous_origin = internals->Chain().Segments()[i/3].GlobalSegmentStart();
-
- glVertex3f(previous_origin[0],previous_origin[1],previous_origin[2]);
- glVertex3f(jac[i][0] + previous_origin[0],jac[i][1] + previous_origin[1],jac[i][2] + previous_origin[2]);
-
-
- }
- glEnd();
- glEnable(GL_LIGHTING);
-#endif
-
- }
-
- glColor3f(1.0,1.0,1.0);
-
- glDisable(GL_LIGHTING);
- glBegin(GL_LINES);
-
- MT_Scalar cube_size = 50;
- glVertex3f(cube_size,cube_size,cube_size);
- glVertex3f(-cube_size,cube_size,cube_size);
-
- glVertex3f(cube_size,-cube_size,cube_size);
- glVertex3f(-cube_size,-cube_size,cube_size);
-
- glVertex3f(cube_size,cube_size,-cube_size);
- glVertex3f(-cube_size,cube_size,-cube_size);
-
- glVertex3f(cube_size,-cube_size,-cube_size);
- glVertex3f(-cube_size,-cube_size,-cube_size);
-
-
- glVertex3f(-cube_size,cube_size,cube_size);
- glVertex3f(-cube_size,-cube_size,cube_size);
-
- glVertex3f(cube_size,cube_size,-cube_size);
- glVertex3f(cube_size,-cube_size,-cube_size);
-
- glVertex3f(cube_size,cube_size,cube_size);
- glVertex3f(cube_size,-cube_size,cube_size);
-
- glVertex3f(-cube_size,cube_size,-cube_size);
- glVertex3f(-cube_size,-cube_size,-cube_size);
-
-
- glVertex3f(cube_size,cube_size,cube_size);
- glVertex3f(cube_size,cube_size,-cube_size);
-
- glVertex3f(cube_size,-cube_size,cube_size);
- glVertex3f(cube_size,-cube_size,-cube_size);
-
- glVertex3f(-cube_size,cube_size,cube_size);
- glVertex3f(-cube_size,cube_size,-cube_size);
-
- glVertex3f(-cube_size,-cube_size,cube_size);
- glVertex3f(-cube_size,-cube_size,-cube_size);
- glEnd();
- glEnable(GL_LIGHTING);
-
- };
-
-
-
-private :
-
- MyGlutMouseHandler * m_mouse_handler;
- MyGlutKeyHandler *m_key_handler;
- IK_Chain_ExternPtr *m_chains;
-
- int m_chain_num;
- ChainDrawer (
- ) : m_chains (NULL),
- m_mouse_handler (NULL),
- m_chain_num (0)
- {
- };
-
-};
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h
deleted file mode 100644
index 621e0d32869..00000000000
--- a/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __MYGLUTKEYHANDLER_H__
-#define __MYGLUTKEYHANDLER_H__
-
-#include "../common/GlutKeyboardManager.h"
-
-class MyGlutKeyHandler : public GlutKeyboardHandler
-{
-public :
- static
- MyGlutKeyHandler *
- New(
- ) {
- MEM_SmartPtr<MyGlutKeyHandler> output = new MyGlutKeyHandler();
-
- if (output == NULL
- ) {
- return NULL;
- }
- return output.Release();
-
- }
-
- void
- HandleKeyboard(
- unsigned char key,
- int x,
- int y
- ){
-
- switch (key) {
-
- case 27 :
-
- exit(0);
- }
- }
-
- ~MyGlutKeyHandler(
- )
- {
- };
-
-private :
-
- MyGlutKeyHandler(
- )
- {
- }
-
-};
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h
deleted file mode 100644
index 205ce38ac23..00000000000
--- a/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __MYGLUTMOUSEHANDLER_H__
-#define __MYGLUTMOUSEHANDLER_H__
-
-#include "../common/GlutMouseManager.h"
-#include <GL/glut.h>
-#include "IK_solver.h"
-
-class MyGlutMouseHandler : public GlutMouseHandler
-{
-
-public :
-
- static
- MyGlutMouseHandler *
- New(
- ) {
- MEM_SmartPtr<MyGlutMouseHandler> output = new MyGlutMouseHandler();
- if (output == NULL
- ) {
- return NULL;
- }
- return output.Release();
-
- }
-
- void
- SetChain(
- IK_Chain_ExternPtr *chains, int num_chains
- ){
- m_chains = chains;
- m_num_chains = num_chains;
- }
-
- void
- Mouse(
- int button,
- int state,
- int x,
- int y
- ){
- if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
- m_moving = true;
- m_begin_x = x;
- m_begin_y = y;
- }
- if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
- m_moving = false;
- }
-
- if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
- m_tracking = true;
- }
- if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP) {
- m_tracking = false;
- }
-
- if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) {
- m_cg_on = true;
- }
- if (button == GLUT_MIDDLE_BUTTON && state == GLUT_UP) {
- m_cg_on = false;
- }
-
- }
-
-
- void
- Motion(
- int x,
- int y
- ){
- if (m_moving) {
- m_angle_x = m_angle_x + (x - m_begin_x);
- m_begin_x = x;
-
- m_angle_y = m_angle_y + (y - m_begin_y);
- m_begin_y = y;
-
- glutPostRedisplay();
- }
- if (m_tracking) {
-
- int w_h = glutGet((GLenum)GLUT_WINDOW_HEIGHT);
-
- y = w_h - y;
-
- double mvmatrix[16];
- double projmatrix[16];
- GLint viewport[4];
-
- double px, py, pz,sz;
-
- /* Get the matrices needed for gluUnProject */
- glGetIntegerv(GL_VIEWPORT, viewport);
- glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
- glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
-
- // work out the position of the end effector in screen space
-
- GLdouble ex,ey,ez;
- ex = m_pos.x();
- ey = m_pos.y();
- ez = m_pos.z();
-
- gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz);
- gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz);
-
- m_pos = MT_Vector3(px,py,pz);
-
- }
- if (m_tracking || m_cg_on) {
- float temp[3];
- m_pos.getValue(temp);
-
- IK_SolveChain(m_chains[0],temp,0.01,200,0.1,m_chains[1]->segments);
- IK_LoadChain(m_chains[0],m_chains[0]->segments,m_chains[0]->num_segments);
-
- glutPostRedisplay();
- }
-
-
- }
-
- const
- float
- AngleX(
- ) const {
- return m_angle_x;
- }
-
- const
- float
- AngleY(
- ) const {
- return m_angle_y;
- }
-
- const
- MT_Vector3
- Position(
- ) const {
- return m_pos;
- }
-
-
-private :
-
- MyGlutMouseHandler (
- ) :
- m_angle_x(0),
- m_angle_y(0),
- m_begin_x(0),
- m_begin_y(0),
- m_moving (false),
- m_tracking (false),
- m_pos(0,0,0),
- m_cg_on (false),
- m_chains(NULL),
- m_num_chains(0)
- {
- };
-
- float m_angle_x;
- float m_angle_y;
- float m_begin_x;
- float m_begin_y;
-
- bool m_moving;
- bool m_tracking;
- bool m_cg_on;
- MT_Vector3 m_pos;
-
- IK_Chain_ExternPtr *m_chains;
- int m_num_chains;
-
-};
-
-#endif
-
diff --git a/intern/iksolver/test/ik_glut_test/intern/main.cpp b/intern/iksolver/test/ik_glut_test/intern/main.cpp
deleted file mode 100644
index bfb9d8fa1a0..00000000000
--- a/intern/iksolver/test/ik_glut_test/intern/main.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "MEM_SmartPtr.h"
-
-#ifdef USE_QUATERNIONS
-#include "IK_Qsolver.h"
-#else
-#include "IK_solver.h"
-#endif
-
-#include <GL/glut.h>
-#include "MT_Vector3.h"
-#include "MT_Quaternion.h"
-#include "MT_Matrix3x3.h"
-#include "MyGlutMouseHandler.h"
-#include "MyGlutKeyHandler.h"
-#include "ChainDrawer.h"
-
-void init(MT_Vector3 min,MT_Vector3 max)
-{
- GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 1.0}; /* Red diffuse light. */
- GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */
-
- GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 1.0}; /* Red diffuse light. */
- GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */
-
- /* Enable a single OpenGL light. */
- glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0);
- glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
-
- glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
- glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
-
- glEnable(GL_LIGHT0);
- glEnable(GL_LIGHT1);
- glEnable(GL_LIGHTING);
-
- /* Use depth buffering for hidden surface elimination. */
- glEnable(GL_DEPTH_TEST);
-
- /* Setup the view of the cube. */
- glMatrixMode(GL_PROJECTION);
-
- // center of the box + 3* depth of box
-
- MT_Vector3 center = (min + max) * 0.5;
- MT_Vector3 diag = max - min;
-
- float depth = diag.length();
- float distance = 2;
-
- gluPerspective(/* field of view in degree */ 40.0,
- /* aspect ratio */ 1.0,
- /* Z near */ 1.0,
- /* Z far */ distance * depth * 2
- );
- glMatrixMode(GL_MODELVIEW);
-
-
- gluLookAt(center.x(), center.y(), center.z() + distance*depth, /* eye is at (0,0,5) */
- center.x(), center.y(), center.z(), /* center is at (0,0,0) */
- 0.0, 1.0, 0.); /* up is in positive Y direction */
-
- glPushMatrix();
-
-
-}
-
-int main(int argc, char **argv)
-{
-
-
- const int seg_num = 5;
- const MT_Scalar seg_length = 15;
-
- const float seg_startA[3] = {0,0,0};
- const float seg_startB[3] = {0,-20,0};
-
- // create some segments to solve with
-
- // First chain
- //////////////
-
-
- IK_Segment_ExternPtr const segmentsA = new IK_Segment_Extern[seg_num];
- IK_Segment_ExternPtr const segmentsB = new IK_Segment_Extern[seg_num];
-
- IK_Segment_ExternPtr seg_it = segmentsA;
- IK_Segment_ExternPtr seg_itB = segmentsB;
-
-
- {
-
-// MT_Quaternion qmat(MT_Vector3(0,0,1),-3.141/2);
- MT_Quaternion qmat(MT_Vector3(0,0,1),0);
- MT_Matrix3x3 mat(qmat);
-
- seg_it->seg_start[0] = seg_startA[0];
- seg_it->seg_start[1] = seg_startA[1];
- seg_it->seg_start[2] = seg_startA[2];
-
- float temp[12];
- mat.getValue(temp);
-
- seg_it->basis[0] = temp[0];
- seg_it->basis[1] = temp[1];
- seg_it->basis[2] = temp[2];
-
- seg_it->basis[3] = temp[4];
- seg_it->basis[4] = temp[5];
- seg_it->basis[5] = temp[6];
-
- seg_it->basis[6] = temp[8];
- seg_it->basis[7] = temp[9];
- seg_it->basis[8] = temp[10];
-
- seg_it->length = seg_length;
-
- MT_Quaternion q;
- q.setEuler(0,0,0);
-
-
- MT_Matrix3x3 qrot(q);
-
- seg_it->basis_change[0] = 1;
- seg_it->basis_change[1] = 0;
- seg_it->basis_change[2] = 0;
- seg_it->basis_change[3] = 0;
- seg_it->basis_change[4] = 1;
- seg_it->basis_change[5] = 0;
- seg_it->basis_change[6] = 0;
- seg_it->basis_change[7] = 0;
- seg_it->basis_change[8] = 1;
-
-
- seg_it ++;
-
- seg_itB->seg_start[0] = seg_startA[0];
- seg_itB->seg_start[1] = seg_startA[1];
- seg_itB->seg_start[2] = seg_startA[2];
-
- seg_itB->basis[0] = temp[0];
- seg_itB->basis[1] = temp[1];
- seg_itB->basis[2] = temp[2];
-
- seg_itB->basis[3] = temp[4];
- seg_itB->basis[4] = temp[5];
- seg_itB->basis[5] = temp[6];
-
- seg_itB->basis[6] = temp[8];
- seg_itB->basis[7] = temp[9];
- seg_itB->basis[8] = temp[10];
-
- seg_itB->length = seg_length;
-
- seg_itB->basis_change[0] = 1;
- seg_itB->basis_change[1] = 0;
- seg_itB->basis_change[2] = 0;
- seg_itB->basis_change[3] = 0;
- seg_itB->basis_change[4] = 1;
- seg_itB->basis_change[5] = 0;
- seg_itB->basis_change[6] = 0;
- seg_itB->basis_change[7] = 0;
- seg_itB->basis_change[8] = 1;
-
-
- seg_itB ++;
-
-
- }
-
-
- int i;
- for (i=1; i < seg_num; ++i, ++seg_it,++seg_itB) {
-
- MT_Quaternion qmat(MT_Vector3(0,0,1),0.3);
- MT_Matrix3x3 mat(qmat);
-
- seg_it->seg_start[0] = 0;
- seg_it->seg_start[1] = 0;
- seg_it->seg_start[2] = 0;
-
- float temp[12];
- mat.getValue(temp);
-
- seg_it->basis[0] = temp[0];
- seg_it->basis[1] = temp[1];
- seg_it->basis[2] = temp[2];
-
- seg_it->basis[3] = temp[4];
- seg_it->basis[4] = temp[5];
- seg_it->basis[5] = temp[6];
-
- seg_it->basis[6] = temp[8];
- seg_it->basis[7] = temp[9];
- seg_it->basis[8] = temp[10];
-
- seg_it->length = seg_length;
-
- MT_Quaternion q;
- q.setEuler(0,0,0);
-
-
- MT_Matrix3x3 qrot(q);
-
- seg_it->basis_change[0] = 1;
- seg_it->basis_change[1] = 0;
- seg_it->basis_change[2] = 0;
- seg_it->basis_change[3] = 0;
- seg_it->basis_change[4] = 1;
- seg_it->basis_change[5] = 0;
- seg_it->basis_change[6] = 0;
- seg_it->basis_change[7] = 0;
- seg_it->basis_change[8] = 1;
-
-
- ///////////////////////////////
-
- seg_itB->seg_start[0] = 0;
- seg_itB->seg_start[1] = 0;
- seg_itB->seg_start[2] = 0;
-
- seg_itB->basis[0] = temp[0];
- seg_itB->basis[1] = temp[1];
- seg_itB->basis[2] = temp[2];
-
- seg_itB->basis[3] = temp[4];
- seg_itB->basis[4] = temp[5];
- seg_itB->basis[5] = temp[6];
-
- seg_itB->basis[6] = temp[8];
- seg_itB->basis[7] = temp[9];
- seg_itB->basis[8] = temp[10];
-
- seg_itB->length = seg_length;
-
- seg_itB->basis_change[0] = 1;
- seg_itB->basis_change[1] = 0;
- seg_itB->basis_change[2] = 0;
- seg_itB->basis_change[3] = 0;
- seg_itB->basis_change[4] = 1;
- seg_itB->basis_change[5] = 0;
- seg_itB->basis_change[6] = 0;
- seg_itB->basis_change[7] = 0;
- seg_itB->basis_change[8] = 1;
-
-
-
- }
-
- // create the chains
-
- const int num_chains = 2;
-
- IK_Chain_ExternPtr chains[num_chains];
-
- chains[0] = IK_CreateChain();
- chains[1] = IK_CreateChain();
-
- // load segments into chain
-
- IK_LoadChain(chains[0],segmentsA,seg_num);
- IK_LoadChain(chains[1],segmentsB,seg_num);
-
- // make and install a mouse handler
-
- MEM_SmartPtr<MyGlutMouseHandler> mouse_handler (MyGlutMouseHandler::New());
- GlutMouseManager::Instance()->InstallHandler(mouse_handler);
-
- mouse_handler->SetChain(chains,num_chains);
-
- // make and install a keyhandler
- MEM_SmartPtr<MyGlutKeyHandler> key_handler (MyGlutKeyHandler::New());
- GlutKeyboardManager::Instance()->InstallHandler(key_handler);
-
- // instantiate the drawing class
-
- MEM_SmartPtr<ChainDrawer> drawer (ChainDrawer::New());
- GlutDrawManager::Instance()->InstallDrawer(drawer);
-
- drawer->SetMouseHandler(mouse_handler);
- drawer->SetChain(chains,num_chains);
- drawer->SetKeyHandler(key_handler);
-
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
- glutCreateWindow("ik");
- glutDisplayFunc(GlutDrawManager::Draw);
- glutMouseFunc(GlutMouseManager::Mouse);
- glutMotionFunc(GlutMouseManager::Motion);
- glutKeyboardFunc(GlutKeyboardManager::HandleKeyboard);
-
- init(MT_Vector3(-50,-50,-50),MT_Vector3(50,50,50));
- glutMainLoop();
- return 0; /* ANSI C requires main to return int. */
-}
diff --git a/intern/itasc/SConscript b/intern/itasc/SConscript
deleted file mode 100644
index bd20368f001..00000000000
--- a/intern/itasc/SConscript
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-sources += env.Glob('kdl/*.cpp')
-sources += env.Glob('kdl/utilities/*.cpp')
-
-incs = '. ../../extern/Eigen3'
-
-defs = []
-
-env.BlenderLib ('bf_intern_itasc', sources, Split(incs), defs, libtype=['intern','player'], priority=[20,100])
diff --git a/intern/itasc/kdl/chain.hpp b/intern/itasc/kdl/chain.hpp
index 1776737fc7d..81c606b73c0 100644
--- a/intern/itasc/kdl/chain.hpp
+++ b/intern/itasc/kdl/chain.hpp
@@ -35,17 +35,8 @@ namespace KDL {
*/
class Chain {
private:
-#if defined(__APPLE__)
-# if MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
- std::vector<Segment> segments;
-# else
// Eigen allocator is needed for alignment of Eigen data types
std::vector<Segment, Eigen::aligned_allocator<Segment> > segments;
-# endif /* MAC_OS_X_VERSION_MIN_REQUIRED */
-#else
- // Eigen allocator is needed for alignment of Eigen data types
- std::vector<Segment, Eigen::aligned_allocator<Segment> > segments;
-#endif
unsigned int nrOfJoints;
unsigned int nrOfSegments;
public:
diff --git a/intern/itasc/kdl/tree.hpp b/intern/itasc/kdl/tree.hpp
index 8f971200969..c8a253fc901 100644
--- a/intern/itasc/kdl/tree.hpp
+++ b/intern/itasc/kdl/tree.hpp
@@ -27,26 +27,14 @@
#include <string>
#include <map>
-#if defined(__APPLE__)
-# if MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
- //no include
-# else
-# include <Eigen/Core>
-# endif /* MAC_OS_X_VERSION_MIN_REQUIRED */
-#else
-# include <Eigen/Core>
-#endif
+#include <Eigen/Core>
namespace KDL
{
//Forward declaration
class TreeElement;
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
- typedef std::map<std::string,TreeElement> SegmentMap;
-#else
// Eigen allocator is needed for alignment of Eigen data types
typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap;
-#endif
class TreeElement
{
diff --git a/intern/libmv/CMakeLists.txt b/intern/libmv/CMakeLists.txt
new file mode 100644
index 00000000000..cd89f1d84b5
--- /dev/null
+++ b/intern/libmv/CMakeLists.txt
@@ -0,0 +1,238 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# NOTE: This file is automatically generated by bundle.sh script
+# If you're doing changes in this file, please update template
+# in that script too
+
+set(INC
+ .
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ libmv-capi.h
+)
+
+if(WITH_LIBMV)
+ add_definitions(${GFLAGS_DEFINES})
+ add_definitions(${GLOG_DEFINES})
+ add_definitions(${CERES_DEFINES})
+
+ list(APPEND INC
+ ../../extern/gflags/src
+ ../../extern/glog/src
+ ../../extern/ceres/include
+ ../../extern/ceres/config
+ ../guardedalloc
+ )
+
+ list(APPEND INC_SYS
+ ${EIGEN3_INCLUDE_DIRS}
+ ${PNG_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+ )
+
+ add_definitions(
+ -DWITH_LIBMV_GUARDED_ALLOC
+ -DLIBMV_NO_FAST_DETECTOR=
+ )
+
+ list(APPEND SRC
+ intern/autotrack.cc
+ intern/camera_intrinsics.cc
+ intern/detector.cc
+ intern/frame_accessor.cc
+ intern/homography.cc
+ intern/image.cc
+ intern/logging.cc
+ intern/reconstruction.cc
+ intern/track_region.cc
+ intern/tracks.cc
+ intern/tracksN.cc
+ libmv/autotrack/autotrack.cc
+ libmv/autotrack/predict_tracks.cc
+ libmv/autotrack/tracks.cc
+ libmv/base/aligned_malloc.cc
+ libmv/image/array_nd.cc
+ libmv/image/convolve.cc
+ libmv/multiview/conditioning.cc
+ libmv/multiview/euclidean_resection.cc
+ libmv/multiview/fundamental.cc
+ libmv/multiview/homography.cc
+ libmv/multiview/panography.cc
+ libmv/multiview/panography_kernel.cc
+ libmv/multiview/projection.cc
+ libmv/multiview/triangulation.cc
+ libmv/numeric/numeric.cc
+ libmv/numeric/poly.cc
+ libmv/simple_pipeline/bundle.cc
+ libmv/simple_pipeline/camera_intrinsics.cc
+ libmv/simple_pipeline/detect.cc
+ libmv/simple_pipeline/distortion_models.cc
+ libmv/simple_pipeline/initialize_reconstruction.cc
+ libmv/simple_pipeline/intersect.cc
+ libmv/simple_pipeline/keyframe_selection.cc
+ libmv/simple_pipeline/modal_solver.cc
+ libmv/simple_pipeline/pipeline.cc
+ libmv/simple_pipeline/reconstruction.cc
+ libmv/simple_pipeline/reconstruction_scale.cc
+ libmv/simple_pipeline/resect.cc
+ libmv/simple_pipeline/tracks.cc
+ libmv/tracking/brute_region_tracker.cc
+ libmv/tracking/hybrid_region_tracker.cc
+ libmv/tracking/klt_region_tracker.cc
+ libmv/tracking/pyramid_region_tracker.cc
+ libmv/tracking/retrack_region_tracker.cc
+ libmv/tracking/track_region.cc
+ libmv/tracking/trklt_region_tracker.cc
+
+
+ intern/autotrack.h
+ intern/camera_intrinsics.h
+ intern/detector.h
+ intern/frame_accessor.h
+ intern/homography.h
+ intern/image.h
+ intern/logging.h
+ intern/reconstruction.h
+ intern/track_region.h
+ intern/tracks.h
+ intern/tracksN.h
+ libmv/autotrack/autotrack.h
+ libmv/autotrack/callbacks.h
+ libmv/autotrack/frame_accessor.h
+ libmv/autotrack/marker.h
+ libmv/autotrack/model.h
+ libmv/autotrack/predict_tracks.h
+ libmv/autotrack/quad.h
+ libmv/autotrack/reconstruction.h
+ libmv/autotrack/region.h
+ libmv/autotrack/tracks.h
+ libmv/base/aligned_malloc.h
+ libmv/base/id_generator.h
+ libmv/base/scoped_ptr.h
+ libmv/base/vector.h
+ libmv/base/vector_utils.h
+ libmv/image/array_nd.h
+ libmv/image/convolve.h
+ libmv/image/correlation.h
+ libmv/image/image_converter.h
+ libmv/image/image_drawing.h
+ libmv/image/image.h
+ libmv/image/sample.h
+ libmv/image/tuple.h
+ libmv/logging/logging.h
+ libmv/multiview/conditioning.h
+ libmv/multiview/euclidean_resection.h
+ libmv/multiview/fundamental.h
+ libmv/multiview/homography_error.h
+ libmv/multiview/homography.h
+ libmv/multiview/homography_parameterization.h
+ libmv/multiview/nviewtriangulation.h
+ libmv/multiview/panography.h
+ libmv/multiview/panography_kernel.h
+ libmv/multiview/projection.h
+ libmv/multiview/resection.h
+ libmv/multiview/triangulation.h
+ libmv/multiview/two_view_kernel.h
+ libmv/numeric/dogleg.h
+ libmv/numeric/function_derivative.h
+ libmv/numeric/levenberg_marquardt.h
+ libmv/numeric/numeric.h
+ libmv/numeric/poly.h
+ libmv/simple_pipeline/bundle.h
+ libmv/simple_pipeline/callbacks.h
+ libmv/simple_pipeline/camera_intrinsics.h
+ libmv/simple_pipeline/camera_intrinsics_impl.h
+ libmv/simple_pipeline/detect.h
+ libmv/simple_pipeline/distortion_models.h
+ libmv/simple_pipeline/initialize_reconstruction.h
+ libmv/simple_pipeline/intersect.h
+ libmv/simple_pipeline/keyframe_selection.h
+ libmv/simple_pipeline/modal_solver.h
+ libmv/simple_pipeline/pipeline.h
+ libmv/simple_pipeline/reconstruction.h
+ libmv/simple_pipeline/reconstruction_scale.h
+ libmv/simple_pipeline/resect.h
+ libmv/simple_pipeline/tracks.h
+ libmv/tracking/brute_region_tracker.h
+ libmv/tracking/hybrid_region_tracker.h
+ libmv/tracking/kalman_filter.h
+ libmv/tracking/klt_region_tracker.h
+ libmv/tracking/pyramid_region_tracker.h
+ libmv/tracking/region_tracker.h
+ libmv/tracking/retrack_region_tracker.h
+ libmv/tracking/track_region.h
+ libmv/tracking/trklt_region_tracker.h
+
+ third_party/msinttypes/inttypes.h
+ third_party/msinttypes/stdint.h
+ )
+
+
+ if(WITH_GTESTS)
+ blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "" "")
+
+ BLENDER_SRC_GTEST("libmv_predict_tracks" "./libmv/autotrack/predict_tracks_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_tracks" "./libmv/autotrack/tracks_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_vector" "./libmv/base/vector_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_array_nd" "./libmv/image/array_nd_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_convolve" "./libmv/image/convolve_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_image" "./libmv/image/image_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_sample" "./libmv/image/sample_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_tuple" "./libmv/image/tuple_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_homography" "./libmv/multiview/homography_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_panography" "./libmv/multiview/panography_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_projection" "./libmv/multiview/projection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_resection" "./libmv/multiview/resection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_numeric" "./libmv/numeric/numeric_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_poly" "./libmv/numeric/poly_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ BLENDER_SRC_GTEST("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "libmv_test_dataset;bf_intern_libmv;extern_ceres")
+ endif()
+else()
+ list(APPEND SRC
+ intern/stub.cc
+ )
+endif()
+
+blender_add_lib(bf_intern_libmv "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/libmv/ChangeLog b/intern/libmv/ChangeLog
new file mode 100644
index 00000000000..45be9c25afa
--- /dev/null
+++ b/intern/libmv/ChangeLog
@@ -0,0 +1,603 @@
+commit 7a676106720fb126a27ff010abdd8bb65d7e0d9a
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Jan 4 18:30:12 2016 +0500
+
+ Fix strict compiler warnings
+
+commit d3537e3709fe11f42312e82cb1c9837c9e742385
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sun Jan 3 14:17:10 2016 +0500
+
+ GLog/GFlags: Reduce difference between upstream and bundled versions
+
+ Several things here:
+
+ - Re-bundled sources using own fork with pull-requests applied on the sources.
+
+ - Got rid of changes around include "config.h", it was needed by Blender to
+ make it's include directories configuration to work. This could be addressed
+ differently from Blender side.
+
+ - Moved some customization to defines set by CMakeLists.
+
+commit 1ec37bba2cfbbf0d6568429fa3035ee2164c23e6
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sat Jan 2 12:42:55 2016 +0500
+
+ GFlags linking errors fix for MSVC
+
+commit df7642b270e8e43685e9ffb404b59d7b226a9f60
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 31 17:56:12 2015 +0500
+
+ Alternative fix for missing prototype for a couple of functions
+
+commit 08f685797b7d776cdaa579136c82b15ddc6ffb30
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 31 17:33:05 2015 +0500
+
+ Update GFlags to the latest upstream version
+
+ Makes it easier to synchronize some compiler/warning fixes.
+
+commit e0ef5b09203e3906a555e6c2010f25cb667da9cd
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 31 16:15:59 2015 +0500
+
+ GLog: Solve some compilation warnings
+
+ Those are actually sent to a pull-request, see
+
+ https://github.com/google/glog/pull/81
+
+commit 2072b213d4d3a55d099a063ed1e7331cc773454e
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 31 16:13:53 2015 +0500
+
+ Add Martijn Berger to the AUTHORS file
+
+commit 4dd0770d98d67896e4f936356e281f63d927410e
+Author: Martijn Berger <martijn.berger@gmail.com>
+Date: Thu Dec 31 16:13:08 2015 +0500
+
+ Fix compilation error of Glog and Gflags with MSVC2015
+
+commit 2712f42be2ad79e7d3a6c9905f6d8d1e3b7133ac
+Author: Brecht Van Lommel <brechtvanlommel@gmail.com>
+Date: Thu Dec 31 14:00:58 2015 +0500
+
+ Fix OS X (with 10.11 SDK) glog build errors due to using deprecated code.
+
+ Some values are now restored to the ones from before the upgrade today.
+
+commit d249280fdf7c937fd6ebbc465508843a70aafd4c
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 30 16:59:28 2015 +0500
+
+ Tweaks to Glog to support building on all platforms
+
+ This makes it possible to compile Libmv on all platforms,
+ amount of hacks is lower, which could bring some warnings
+ up, but those are better be addressed via upstream which
+ is now rather active.
+
+commit 86c57750ddb857643fb5dd2c83b4953da83dd57d
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 30 16:15:47 2015 +0500
+
+ Enable explicit Schur complement matrix by default
+
+ Gives up to 2x speed up of camera solving process in average scene.
+ In the really huge one it might be slower, but that we need to investigate.
+
+commit d6c52a70b5a0664b7c74bda68f59a895fe8aa235
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 30 16:13:03 2015 +0500
+
+ Fix one frame memory leak when tracking last frame
+
+commit 6e2ac41d25d5923b2a62c96d27d919a36eff9b48
+Author: Brecht Van Lommel <brechtvanlommel@gmail.com>
+Date: Wed Dec 30 16:11:24 2015 +0500
+
+ Motion tracking not workig with Xcode 7 on OS X.
+
+ Caused by use of the uninitialized shape_ variable in Resize().
+
+commit fc72ae06fb4ae559ac37d14d1b34d6669505cc86
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 30 15:56:40 2015 +0500
+
+ Update GLog to latest upstream
+
+ Should fix issues building with MSVC2015.
+
+commit d4b2d15bd3d195074b074331354de96a1b51042f
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 30 16:01:10 2015 +0500
+
+ Fix wrong README file reference
+
+commit 2b4aa0b7720cae9a408284834559bea9960157ee
+Author: Keir Mierle <mierle@gmail.com>
+Date: Mon May 11 02:16:53 2015 -0700
+
+ Make README more informative for GitHub viewers
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D1295
+
+commit 514e4491aea655d20be047ed87f002fb7854d5c9
+Author: Keir Mierle <mierle@gmail.com>
+Date: Mon May 11 01:54:09 2015 -0700
+
+ Simplify the modal solver Ceres cost function
+
+ Fix test by flipping the quaternion.
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Projects: #libmv
+
+ Differential Revision: https://developer.blender.org/D756
+
+commit e55fafd31f7d53d42af7c6b7df2eebe3c2568da9
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 31 19:05:51 2014 +0500
+
+ Synchronize MSVC compilation fixes from Blender
+
+commit 7d6020d2ec42c6cb2749bc891186b4880d26d40b
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Dec 31 15:32:07 2014 +0500
+
+ Update GLog to latest upstream revision 143
+
+ Mainly to solve compilation error with demangle.cc.
+
+commit 5dc746700eaf85cb674f0fb73ff3c1b49a7f6315
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Dec 12 14:59:55 2014 +0500
+
+ Update GFlags to latest release 2.1.1
+
+ Main purpose of this (andsome of upcoming) update is to check if the
+ upstream sources are useable without any modifications for us. And if
+ not, then we'll need to consider moving some changes into upstream.
+
+ This commit contains an one-to-one copy of the upstream GFlags library
+ and also changes namespace usage since it's changed in the upstream.
+
+commit 6fe6d75f7e90e161b44643b953f058a3829a5247
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sat Nov 1 02:53:36 2014 +0500
+
+ Libmv: Code cleanup, mixed class/struct in declaration/definition
+
+commit d2a5f7953812d2d09765431b59c6c4ac72faf35b
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Oct 30 23:13:53 2014 +0500
+
+ Libmv: Support disabled color channels in tracking settings
+
+ This was never ported to a new tracking pipeline and now it's done using
+ FrameAccessor::Transform routines. Quite striaghtforward, but i've changed
+ order of grayscale conversion in blender side with call of transform callback.
+
+ This way it's much easier to perform rescaling in libmv side.
+
+commit d976e034cdf74b34860e0632d7b29713f47c5756
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sat Aug 23 00:38:01 2014 -0700
+
+ Minor keyframe selection cleanups
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D757
+
+commit bc99ca55dadfca89fde0f93764397c2fe028943d
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sat Aug 23 01:55:32 2014 +0600
+
+ implement backward prediction
+
+ The title actually says it all, just extend current implementation
+ of PredictMarkerPosition() to cases when tracking happens in the reverse
+ order (from the end frame to start).
+
+ it's still doesn't solve all the ambiguity happening in the function
+ in cases when one tracks the feature and then re-tracks it in order
+ to refine the sliding. This is considered a separate TODO for now and
+ will likely be solved by passing tracking direction to the prediction
+ function.
+
+ Reviewers: keir
+
+ Reviewed By: keir
+
+ Differential Revision: https://developer.blender.org/D663
+
+commit 5b87682d98df65ade02638bc6482d824cf0dd0b3
+Author: Keir Mierle <mierle@gmail.com>
+Date: Thu Aug 21 22:45:22 2014 -0700
+
+ Make libmv compile on Ubuntu 14.04
+
+ Reviewers: fsiddi
+
+ Reviewed By: fsiddi
+
+ Subscribers: sergey
+
+ Differential Revision: https://developer.blender.org/D755
+
+commit 0a81db623c458e0384b4f7060d1bcff8993fb469
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Jul 23 00:42:00 2014 +0600
+
+ Fix wrong residual blocks counter
+
+ This happened in cases when having zero-weighted tracks
+ and could lead to some assert failures on marking parameter
+ block constant.
+
+commit 2824dbac54cacf74828678be7a5c9fd960ce83e2
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Jul 18 12:52:03 2014 +0600
+
+ Fix search area sliding issue
+
+ The only way to do this is to store search region in floats
+ and round when we need to sample it. Otherwise you'll always
+ have sliding effect caused by rounding the issues, especially
+ when doing incremental offset (thing which happens in the
+ prediction code).
+
+ Pretty much straightforward change apart from stuff to be kept
+ in mind: offset calculation int should happen relative to the
+ rounded search region. This is because tracker works in the space
+ of the search window image which get's rounded on the frame access,
+
+ This makes API a bit creepy because frame accessor uses the same
+ Region struct as the search window in Marker and ideally we would
+ need to have either IntRegion or Region<int> in order to make
+ Libmv fully track on what's getting rounded and when.
+
+ Reviewers: keir
+
+ Reviewed By: keir
+
+ Differential Revision: https://developer.blender.org/D616
+
+commit 04862c479332308be47a0f27361402444ace8880
+Author: Keir Mierle <mierle@gmail.com>
+Date: Fri May 9 23:00:03 2014 +0200
+
+ Start the automatic 2D tracking code
+
+ This starts the 2D automatic tracking code. It is totally unfinished.
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D523
+
+commit be679f67d807a2139c1f7d7e2ca45141940b30d5
+Author: Keir Mierle <mierle@gmail.com>
+Date: Fri May 9 14:36:04 2014 +0200
+
+ Also shift the search window
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D520
+
+commit 66b8f5eef2633ebcde32a388fc14c60171011821
+Author: Keir Mierle <mierle@gmail.com>
+Date: Fri May 9 13:06:28 2014 +0200
+
+ Change the search region to absolute frame coordinates
+
+ Smarter Eigen usage
+
+ Better error logging
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D519
+
+commit a08193319ae409fad8f08887eae1f79f02e91eaa
+Author: Keir Mierle <mierle@gmail.com>
+Date: Fri May 9 12:02:47 2014 +0200
+
+ First cut at predictive tracing
+
+ This adds a Kalman filter-based approach to predict where a marker
+ will go in the next frame to track. Hopefully this will make the
+ tracker work faster by avoiding lengthy searches. This code
+ compiles, but is otherwise untested, and likely does not work.
+
+ Fix else branch
+
+ Add some tests
+
+ Update patch coordinates as well (and test)
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D518
+
+commit 607ffb2f62b56e34a841abbb952d83e19cd1e23c
+Author: Keir Mierle <mierle@gmail.com>
+Date: Thu May 8 16:05:28 2014 +0200
+
+ Add constructor to AutoTrack
+
+commit c39e20a0c27da3733804c3848454b5d4c4f0e66b
+Author: Keir Mierle <mierle@gmail.com>
+Date: Thu May 8 16:04:20 2014 +0200
+
+ Fix GetMarker compilation issue
+
+commit 8dd93e431b6e44439c803bfd26ec2669b656177e
+Author: Keir Mierle <mierle@gmail.com>
+Date: Thu May 8 15:50:26 2014 +0200
+
+ Expose GetMarker() in AutoTrack
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D516
+
+commit 4405dff60ea08d454b64da1a7c0595d9328cf8a3
+Author: Keir Mierle <mierle@gmail.com>
+Date: Thu May 8 15:38:14 2014 +0200
+
+ Add public SetMarkers to AutoTrack
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D515
+
+commit c90837f6db276a3b1f610eaad509155f6a43b24f
+Author: Keir Mierle <mierle@gmail.com>
+Date: Thu May 8 15:17:48 2014 +0200
+
+ Make autotrack skeleton compile
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D514
+
+commit be01baa2e82e36f63e548f073157e68d2ff870c0
+Author: Keir Mierle <mierle@gmail.com>
+Date: Wed May 7 18:48:55 2014 +0200
+
+ Add preliminary TrackMarkerToFrame in autotrack
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D509
+
+commit 0cab028d591b3d08672ca86eb6c6e4ac1aacf1d0
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed May 7 17:59:11 2014 +0200
+
+ Remove assert from ArrayND Resize
+
+ That assert broke initialization of arrays which doesn't
+ own the data since constructor uses Resize to set shape
+ and strides.
+
+ Strides are still to be fixed, but that's for later.
+
+commit 64f9c118029a9351e9023e96527c120e1d724d5b
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed May 7 17:42:21 2014 +0200
+
+ Fix ArrayND freeing the data it doesn't own
+
+ Can't really guarantee it works fully correct now,
+ but at least this check is needed anyway and compilation
+ works just fine.
+
+ Reviewers: keir
+
+ Reviewed By: keir
+
+ Differential Revision: https://developer.blender.org/D508
+
+commit 0618f1c8e88dfc738cdde55784da80b889905e7c
+Author: Keir Mierle <mierle@gmail.com>
+Date: Wed May 7 12:03:32 2014 +0200
+
+ Minor changes
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D505
+
+commit 5c34335e1bb90c4ed701ee830c718ed4e20dbffa
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed May 7 11:12:23 2014 +0200
+
+ Fix compilation error in frame accessor
+
+ - int64 is not a standard type, we've got int64_t defined in
+ std int. We also have an msvc port of this header, so should
+ not be an issue.
+
+ - Fixed inconsistency in usage of CacheKey and Key, used Key.
+
+ - Some functions weren't marked as virtual.
+
+ Additional change: added self to authors.
+
+ Reviewers: keir
+
+ Reviewed By: keir
+
+ Differential Revision: https://developer.blender.org/D504
+
+commit 06bc207614e262cd688e2c3ed820ade7c77bdb66
+Author: Keir Mierle <mierle@gmail.com>
+Date: Tue May 6 22:30:59 2014 +0200
+
+ Start new Tracks implementation
+
+ This adds the new Tracks implementation, as well as a
+ trivial test to show it compiles.
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D502
+
+commit 25ce061e6da69881460ba7718bb0d660a2380a02
+Author: Keir Mierle <mierle@gmail.com>
+Date: Tue May 6 19:10:51 2014 +0200
+
+ Add Reconstruction class for new API
+
+ This starts the new Reconstruction class (with support for e.g. planes). This
+ also starts the new namespace "mv" which will eventually have all the symbols
+ we wish to export.
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D501
+
+commit 0a6af3e29016048978aea607673340500e050339
+Author: Keir Mierle <mierle@gmail.com>
+Date: Tue May 6 17:52:53 2014 +0200
+
+ Add a new Tracks implementation
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D500
+
+commit 887b68d29c2b198f4939f9ab5153881aa2c1806e
+Author: Keir Mierle <mierle@gmail.com>
+Date: Tue May 6 17:01:39 2014 +0200
+
+ Initial commit of unfinished AutoTrack API
+
+ This starts the creating the new AutoTrack API. The new API will
+ make it possible for libmv to do full autotracking, including
+ predictive tracking and also support multiple motion models (3D
+ planes etc).
+
+ The first goal (not in this patch) is to convert Blender to use
+ the new API without adding any new functionality.
+
+ Note: This does not add any of the API to the build system!
+ It likely does not compile.
+
+ Reviewers: sergey
+
+ Reviewed By: sergey
+
+ Differential Revision: https://developer.blender.org/D499
+
+commit 08cc227d431d257d27f300fbb8e6991e663302da
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue May 6 13:09:22 2014 +0200
+
+ Fix homography test failure
+
+ It was caused by assuming that reconstructed homography matrix
+ should look exactly the same as the matrix used to generate a
+ test case.
+
+ It's not actually valid assumption because different-looking
+ matrices could correspond to the same exact transform.
+
+ In this change we make it so actual "re-projected" vectors
+ are being checked, not the values in matrix. This makes it
+ more predictable verification.
+
+ Reviewers: keir
+
+ Reviewed By: keir
+
+ Differential Revision: https://developer.blender.org/D488
+
+commit 0b7d83dc9627447dc7df64d7e3a468aefe9ddc13
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Apr 23 19:14:55 2014 +0600
+
+ Fix compilation on OSX after previous commit
+
+ EXPECT_EQ wasn't defined in the scope.
+
+commit d14049e00dabf8fdf49056779f0a3718fbb39e8f
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Wed Apr 23 15:08:16 2014 +0600
+
+ Move aligned malloc implementation into own file
+
+ It was rather stupid having it in brute region tracker,
+ now it is in own file in base library (which was also
+ added in this commit, before this it consist of header
+ files only).
+
+ Reviewers: keir
+
+ Reviewed By: keir
+
+ Differential Revision: https://developer.blender.org/D479
+
+commit 0ddf3851bfcb8de43660b119a25a77a25674200d
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Apr 21 14:14:03 2014 +0600
+
+ Optimization of PearsonProductMomentCorrelation
+
+ Pass the arrays by reference rather than by value,
+ should give some percent of speedup.
+
+ Also don't pass the dimensions to the function but
+ get them from the images themselves.
+
+ Hopefully this will give some %% of tracker speedup.
+
+commit f68fdbe5896a6c5bd8b500caeec61b876c5e44c6
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Apr 21 14:10:43 2014 +0600
+
+ Fix wrong assert in ResizeImage()
+
+ The assert didn't make any sense because ComputeBoundingBox()
+ is intended to return bounding box in the following way:
+ (xmin, xmax, ymin, ymax).
diff --git a/intern/libmv/bundle.sh b/intern/libmv/bundle.sh
new file mode 100755
index 00000000000..b1a4be84e53
--- /dev/null
+++ b/intern/libmv/bundle.sh
@@ -0,0 +1,187 @@
+#!/bin/sh
+
+if [ "x$1" = "x--i-really-know-what-im-doing" ] ; then
+ echo Proceeding as requested by command line ...
+else
+ echo "*** Please run again with --i-really-know-what-im-doing ..."
+ exit 1
+fi
+
+BRANCH="master"
+
+repo="git://git.blender.org/libmv.git"
+tmp=`mktemp -d`
+
+git clone -b $BRANCH $repo $tmp/libmv
+
+git --git-dir $tmp/libmv/.git --work-tree $tmp/libmv log -n 50 > ChangeLog
+
+find libmv -type f -exec rm -rf {} \;
+find third_party -type f -exec rm -rf {} \;
+
+cat "files.txt" | while read f; do
+ mkdir -p `dirname $f`
+ cp $tmp/libmv/src/$f $f
+done
+
+rm -rf $tmp
+
+sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v _test.cc | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d`
+headers=`find ./libmv -type f -iname '*.h' | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d`
+
+third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t\t/' | sort -d`
+third_headers=`find ./third_party -type f -iname '*.h' | sed -r 's/^\.\//\t\t/' | sort -d`
+
+tests=`find ./libmv -type f -iname '*_test.cc' | sort -d | awk ' { name=gensub(".*/([A-Za-z_]+)_test.cc", "\\\\1", $1); printf("\t\tBLENDER_SRC_GTEST(\"libmv_%s\" \"%s\" \"libmv_test_dataset;bf_intern_libmv;extern_ceres\")\n", name, $1) } '`
+
+src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
+src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
+src=""
+win_src=""
+for x in $src_dir $src_third_dir; do
+ t=""
+
+ if stat $x/*.cpp > /dev/null 2>&1; then
+ t=" src += env.Glob('`echo $x'/*.cpp'`')"
+ fi
+
+ if stat $x/*.c > /dev/null 2>&1; then
+ if [ -z "$t" ]; then
+ t=" src += env.Glob('`echo $x'/*.c'`')"
+ else
+ t="$t + env.Glob('`echo $x'/*.c'`')"
+ fi
+ fi
+
+ if stat $x/*.cc > /dev/null 2>&1; then
+ if [ -z "$t" ]; then
+ t=" src += env.Glob('`echo $x'/*.cc'`')"
+ else
+ t="$t + env.Glob('`echo $x'/*.cc'`')"
+ fi
+ fi
+
+ if test `echo $x | grep -c "windows\|gflags" ` -eq 0; then
+ if [ -z "$src" ]; then
+ src=$t
+ else
+ src=`echo "$src\n$t"`
+ fi
+ else
+ if [ -z "$win_src" ]; then
+ win_src=`echo " $t"`
+ else
+ win_src=`echo "$win_src\n $t"`
+ fi
+ fi
+done
+
+cat > CMakeLists.txt << EOF
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# Contributor(s): Blender Foundation,
+# Sergey Sharybin
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# NOTE: This file is automatically generated by bundle.sh script
+# If you're doing changes in this file, please update template
+# in that script too
+
+set(INC
+ .
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ libmv-capi.h
+)
+
+if(WITH_LIBMV)
+ add_definitions(\${GFLAGS_DEFINES})
+ add_definitions(\${GLOG_DEFINES})
+ add_definitions(\${CERES_DEFINES})
+
+ list(APPEND INC
+ ../../extern/gflags/src
+ ../../extern/glog/src
+ ../../extern/ceres/include
+ ../../extern/ceres/config
+ ../guardedalloc
+ )
+
+ list(APPEND INC_SYS
+ \${EIGEN3_INCLUDE_DIRS}
+ \${PNG_INCLUDE_DIRS}
+ \${ZLIB_INCLUDE_DIRS}
+ )
+
+ add_definitions(
+ -DWITH_LIBMV_GUARDED_ALLOC
+ -DLIBMV_NO_FAST_DETECTOR=
+ )
+
+ list(APPEND SRC
+ intern/autotrack.cc
+ intern/camera_intrinsics.cc
+ intern/detector.cc
+ intern/frame_accessor.cc
+ intern/homography.cc
+ intern/image.cc
+ intern/logging.cc
+ intern/reconstruction.cc
+ intern/track_region.cc
+ intern/tracks.cc
+ intern/tracksN.cc
+${sources}
+${third_sources}
+
+ intern/autotrack.h
+ intern/camera_intrinsics.h
+ intern/detector.h
+ intern/frame_accessor.h
+ intern/homography.h
+ intern/image.h
+ intern/logging.h
+ intern/reconstruction.h
+ intern/track_region.h
+ intern/tracks.h
+ intern/tracksN.h
+${headers}
+
+${third_headers}
+ )
+
+
+ if(WITH_GTESTS)
+ blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "${INC}" "${INC_SYS}")
+
+${tests}
+ endif()
+else()
+ list(APPEND SRC
+ intern/stub.cc
+ )
+endif()
+
+blender_add_lib(bf_intern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
+EOF
diff --git a/intern/libmv/files.txt b/intern/libmv/files.txt
new file mode 100644
index 00000000000..223066bb02f
--- /dev/null
+++ b/intern/libmv/files.txt
@@ -0,0 +1,138 @@
+libmv/autotrack/autotrack.cc
+libmv/autotrack/autotrack.h
+libmv/autotrack/callbacks.h
+libmv/autotrack/frame_accessor.h
+libmv/autotrack/marker.h
+libmv/autotrack/model.h
+libmv/autotrack/predict_tracks.cc
+libmv/autotrack/predict_tracks.h
+libmv/autotrack/predict_tracks_test.cc
+libmv/autotrack/quad.h
+libmv/autotrack/reconstruction.h
+libmv/autotrack/region.h
+libmv/autotrack/tracks.cc
+libmv/autotrack/tracks.h
+libmv/autotrack/tracks_test.cc
+libmv/base/aligned_malloc.cc
+libmv/base/aligned_malloc.h
+libmv/base/id_generator.h
+libmv/base/scoped_ptr.h
+libmv/base/scoped_ptr_test.cc
+libmv/base/vector.h
+libmv/base/vector_test.cc
+libmv/base/vector_utils.h
+libmv/image/array_nd.cc
+libmv/image/array_nd.h
+libmv/image/array_nd_test.cc
+libmv/image/convolve.cc
+libmv/image/convolve.h
+libmv/image/convolve_test.cc
+libmv/image/correlation.h
+libmv/image/image_converter.h
+libmv/image/image_drawing.h
+libmv/image/image.h
+libmv/image/image_test.cc
+libmv/image/sample.h
+libmv/image/sample_test.cc
+libmv/image/tuple.h
+libmv/image/tuple_test.cc
+libmv/logging/logging.h
+libmv/multiview/conditioning.cc
+libmv/multiview/conditioning.h
+libmv/multiview/euclidean_resection.cc
+libmv/multiview/euclidean_resection.h
+libmv/multiview/euclidean_resection_test.cc
+libmv/multiview/fundamental.cc
+libmv/multiview/fundamental.h
+libmv/multiview/fundamental_test.cc
+libmv/multiview/homography.cc
+libmv/multiview/homography_error.h
+libmv/multiview/homography.h
+libmv/multiview/homography_parameterization.h
+libmv/multiview/homography_test.cc
+libmv/multiview/nviewtriangulation.h
+libmv/multiview/nviewtriangulation_test.cc
+libmv/multiview/panography.cc
+libmv/multiview/panography.h
+libmv/multiview/panography_kernel.cc
+libmv/multiview/panography_kernel.h
+libmv/multiview/panography_test.cc
+libmv/multiview/projection.cc
+libmv/multiview/projection.h
+libmv/multiview/projection_test.cc
+libmv/multiview/resection.h
+libmv/multiview/resection_test.cc
+libmv/multiview/test_data_sets.cc
+libmv/multiview/test_data_sets.h
+libmv/multiview/triangulation.cc
+libmv/multiview/triangulation.h
+libmv/multiview/triangulation_test.cc
+libmv/multiview/two_view_kernel.h
+libmv/numeric/dogleg.h
+libmv/numeric/dogleg_test.cc
+libmv/numeric/function_derivative.h
+libmv/numeric/function_derivative_test.cc
+libmv/numeric/levenberg_marquardt.h
+libmv/numeric/levenberg_marquardt_test.cc
+libmv/numeric/numeric.cc
+libmv/numeric/numeric.h
+libmv/numeric/numeric_test.cc
+libmv/numeric/poly.cc
+libmv/numeric/poly.h
+libmv/numeric/poly_test.cc
+libmv/simple_pipeline/bundle.cc
+libmv/simple_pipeline/bundle.h
+libmv/simple_pipeline/callbacks.h
+libmv/simple_pipeline/camera_intrinsics.cc
+libmv/simple_pipeline/camera_intrinsics.h
+libmv/simple_pipeline/camera_intrinsics_impl.h
+libmv/simple_pipeline/camera_intrinsics_test.cc
+libmv/simple_pipeline/detect.cc
+libmv/simple_pipeline/detect.h
+libmv/simple_pipeline/detect_test.cc
+libmv/simple_pipeline/distortion_models.cc
+libmv/simple_pipeline/distortion_models.h
+libmv/simple_pipeline/initialize_reconstruction.cc
+libmv/simple_pipeline/initialize_reconstruction.h
+libmv/simple_pipeline/intersect.cc
+libmv/simple_pipeline/intersect.h
+libmv/simple_pipeline/intersect_test.cc
+libmv/simple_pipeline/keyframe_selection.cc
+libmv/simple_pipeline/keyframe_selection.h
+libmv/simple_pipeline/keyframe_selection_test.cc
+libmv/simple_pipeline/modal_solver.cc
+libmv/simple_pipeline/modal_solver.h
+libmv/simple_pipeline/modal_solver_test.cc
+libmv/simple_pipeline/pipeline.cc
+libmv/simple_pipeline/pipeline.h
+libmv/simple_pipeline/reconstruction.cc
+libmv/simple_pipeline/reconstruction.h
+libmv/simple_pipeline/reconstruction_scale.cc
+libmv/simple_pipeline/reconstruction_scale.h
+libmv/simple_pipeline/resect.cc
+libmv/simple_pipeline/resect.h
+libmv/simple_pipeline/resect_test.cc
+libmv/simple_pipeline/tracks.cc
+libmv/simple_pipeline/tracks.h
+libmv/tracking/brute_region_tracker.cc
+libmv/tracking/brute_region_tracker.h
+libmv/tracking/brute_region_tracker_test.cc
+libmv/tracking/hybrid_region_tracker.cc
+libmv/tracking/hybrid_region_tracker.h
+libmv/tracking/kalman_filter.h
+libmv/tracking/klt_region_tracker.cc
+libmv/tracking/klt_region_tracker.h
+libmv/tracking/klt_region_tracker_test.cc
+libmv/tracking/pyramid_region_tracker.cc
+libmv/tracking/pyramid_region_tracker.h
+libmv/tracking/pyramid_region_tracker_test.cc
+libmv/tracking/region_tracker.h
+libmv/tracking/retrack_region_tracker.cc
+libmv/tracking/retrack_region_tracker.h
+libmv/tracking/track_region.cc
+libmv/tracking/track_region.h
+libmv/tracking/trklt_region_tracker.cc
+libmv/tracking/trklt_region_tracker.h
+third_party/msinttypes/inttypes.h
+third_party/msinttypes/README.libmv
+third_party/msinttypes/stdint.h
diff --git a/extern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc
index f0cbc68f11e..f0cbc68f11e 100644
--- a/extern/libmv/intern/autotrack.cc
+++ b/intern/libmv/intern/autotrack.cc
diff --git a/extern/libmv/intern/autotrack.h b/intern/libmv/intern/autotrack.h
index 2a4a8f3c97f..2a4a8f3c97f 100644
--- a/extern/libmv/intern/autotrack.h
+++ b/intern/libmv/intern/autotrack.h
diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc
new file mode 100644
index 00000000000..24a34ae40bb
--- /dev/null
+++ b/intern/libmv/intern/camera_intrinsics.cc
@@ -0,0 +1,345 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "intern/camera_intrinsics.h"
+#include "intern/utildefines.h"
+#include "libmv/simple_pipeline/camera_intrinsics.h"
+
+using libmv::CameraIntrinsics;
+using libmv::DivisionCameraIntrinsics;
+using libmv::PolynomialCameraIntrinsics;
+
+libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
+ const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) {
+ CameraIntrinsics *camera_intrinsics =
+ libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options);
+ return (libmv_CameraIntrinsics *) camera_intrinsics;
+}
+
+libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
+ const libmv_CameraIntrinsics* libmv_intrinsics) {
+ const CameraIntrinsics *orig_intrinsics =
+ (const CameraIntrinsics *) libmv_intrinsics;
+
+ CameraIntrinsics *new_intrinsics = NULL;
+ switch (orig_intrinsics->GetDistortionModelType()) {
+ case libmv::DISTORTION_MODEL_POLYNOMIAL:
+ {
+ const PolynomialCameraIntrinsics *polynomial_intrinsics =
+ static_cast<const PolynomialCameraIntrinsics*>(orig_intrinsics);
+ new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics,
+ *polynomial_intrinsics);
+ break;
+ }
+ case libmv::DISTORTION_MODEL_DIVISION:
+ {
+ const DivisionCameraIntrinsics *division_intrinsics =
+ static_cast<const DivisionCameraIntrinsics*>(orig_intrinsics);
+ new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics,
+ *division_intrinsics);
+ break;
+ }
+ default:
+ assert(!"Unknown distortion model");
+ }
+ return (libmv_CameraIntrinsics *) new_intrinsics;
+}
+
+void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) {
+ LIBMV_OBJECT_DELETE(libmv_intrinsics, CameraIntrinsics);
+}
+
+void libmv_cameraIntrinsicsUpdate(
+ const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
+ libmv_CameraIntrinsics* libmv_intrinsics) {
+ CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+
+ double focal_length = libmv_camera_intrinsics_options->focal_length;
+ double principal_x = libmv_camera_intrinsics_options->principal_point_x;
+ double principal_y = libmv_camera_intrinsics_options->principal_point_y;
+ int image_width = libmv_camera_intrinsics_options->image_width;
+ int image_height = libmv_camera_intrinsics_options->image_height;
+
+ /* Try avoid unnecessary updates, so pre-computed distortion grids
+ * are not freed.
+ */
+
+ if (camera_intrinsics->focal_length() != focal_length) {
+ camera_intrinsics->SetFocalLength(focal_length, focal_length);
+ }
+
+ if (camera_intrinsics->principal_point_x() != principal_x ||
+ camera_intrinsics->principal_point_y() != principal_y) {
+ camera_intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ }
+
+ if (camera_intrinsics->image_width() != image_width ||
+ camera_intrinsics->image_height() != image_height) {
+ camera_intrinsics->SetImageSize(image_width, image_height);
+ }
+
+ switch (libmv_camera_intrinsics_options->distortion_model) {
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+ {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_POLYNOMIAL);
+
+ PolynomialCameraIntrinsics *polynomial_intrinsics =
+ (PolynomialCameraIntrinsics *) camera_intrinsics;
+
+ double k1 = libmv_camera_intrinsics_options->polynomial_k1;
+ double k2 = libmv_camera_intrinsics_options->polynomial_k2;
+ double k3 = libmv_camera_intrinsics_options->polynomial_k3;
+
+ if (polynomial_intrinsics->k1() != k1 ||
+ polynomial_intrinsics->k2() != k2 ||
+ polynomial_intrinsics->k3() != k3) {
+ polynomial_intrinsics->SetRadialDistortion(k1, k2, k3);
+ }
+ break;
+ }
+
+ case LIBMV_DISTORTION_MODEL_DIVISION:
+ {
+ assert(camera_intrinsics->GetDistortionModelType() ==
+ libmv::DISTORTION_MODEL_DIVISION);
+
+ DivisionCameraIntrinsics *division_intrinsics =
+ (DivisionCameraIntrinsics *) camera_intrinsics;
+
+ double k1 = libmv_camera_intrinsics_options->division_k1;
+ double k2 = libmv_camera_intrinsics_options->division_k2;
+
+ if (division_intrinsics->k1() != k1 ||
+ division_intrinsics->k2() != k2) {
+ division_intrinsics->SetDistortion(k1, k2);
+ }
+
+ break;
+ }
+
+ default:
+ assert(!"Unknown distortion model");
+ }
+}
+
+void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics,
+ int threads) {
+ CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ camera_intrinsics->SetThreads(threads);
+}
+
+void libmv_cameraIntrinsicsExtractOptions(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
+ const CameraIntrinsics *camera_intrinsics =
+ (const CameraIntrinsics *) libmv_intrinsics;
+
+ // Fill in options which are common for all distortion models.
+ camera_intrinsics_options->focal_length = camera_intrinsics->focal_length();
+ camera_intrinsics_options->principal_point_x =
+ camera_intrinsics->principal_point_x();
+ camera_intrinsics_options->principal_point_y =
+ camera_intrinsics->principal_point_y();
+
+ camera_intrinsics_options->image_width = camera_intrinsics->image_width();
+ camera_intrinsics_options->image_height = camera_intrinsics->image_height();
+
+ switch (camera_intrinsics->GetDistortionModelType()) {
+ case libmv::DISTORTION_MODEL_POLYNOMIAL:
+ {
+ const PolynomialCameraIntrinsics *polynomial_intrinsics =
+ static_cast<const PolynomialCameraIntrinsics *>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
+ LIBMV_DISTORTION_MODEL_POLYNOMIAL;
+ camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1();
+ camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2();
+ camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3();
+ camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1();
+ camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p2();
+ break;
+ }
+
+ case libmv::DISTORTION_MODEL_DIVISION:
+ {
+ const DivisionCameraIntrinsics *division_intrinsics =
+ static_cast<const DivisionCameraIntrinsics *>(camera_intrinsics);
+ camera_intrinsics_options->distortion_model =
+ LIBMV_DISTORTION_MODEL_DIVISION;
+ camera_intrinsics_options->division_k1 = division_intrinsics->k1();
+ camera_intrinsics_options->division_k2 = division_intrinsics->k2();
+ break;
+ }
+
+ default:
+ assert(!"Uknown distortion model");
+ }
+}
+
+void libmv_cameraIntrinsicsUndistortByte(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ const unsigned char *source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ unsigned char* destination_image) {
+ CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ camera_intrinsics->UndistortBuffer(source_image,
+ width, height,
+ overscan,
+ channels,
+ destination_image);
+}
+
+void libmv_cameraIntrinsicsUndistortFloat(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ const float* source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ float* destination_image) {
+ CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ intrinsics->UndistortBuffer(source_image,
+ width, height,
+ overscan,
+ channels,
+ destination_image);
+}
+
+void libmv_cameraIntrinsicsDistortByte(
+ const struct libmv_CameraIntrinsics* libmv_intrinsics,
+ const unsigned char *source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ unsigned char *destination_image) {
+ CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ intrinsics->DistortBuffer(source_image,
+ width, height,
+ overscan,
+ channels,
+ destination_image);
+}
+
+void libmv_cameraIntrinsicsDistortFloat(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ float* source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ float* destination_image) {
+ CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ intrinsics->DistortBuffer(source_image,
+ width, height,
+ overscan,
+ channels,
+ destination_image);
+}
+
+void libmv_cameraIntrinsicsApply(
+ const struct libmv_CameraIntrinsics* libmv_intrinsics,
+ double x,
+ double y,
+ double* x1,
+ double* y1) {
+ CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ intrinsics->ApplyIntrinsics(x, y, x1, y1);
+}
+
+void libmv_cameraIntrinsicsInvert(
+ const struct libmv_CameraIntrinsics* libmv_intrinsics,
+ double x,
+ double y,
+ double* x1,
+ double* y1) {
+ CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics;
+ intrinsics->InvertIntrinsics(x, y, x1, y1);
+}
+
+static void libmv_cameraIntrinsicsFillFromOptions(
+ const libmv_CameraIntrinsicsOptions* camera_intrinsics_options,
+ CameraIntrinsics* camera_intrinsics) {
+ camera_intrinsics->SetFocalLength(camera_intrinsics_options->focal_length,
+ camera_intrinsics_options->focal_length);
+
+ camera_intrinsics->SetPrincipalPoint(
+ camera_intrinsics_options->principal_point_x,
+ camera_intrinsics_options->principal_point_y);
+
+ camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width,
+ camera_intrinsics_options->image_height);
+
+ switch (camera_intrinsics_options->distortion_model) {
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+ {
+ PolynomialCameraIntrinsics *polynomial_intrinsics =
+ static_cast<PolynomialCameraIntrinsics*>(camera_intrinsics);
+
+ polynomial_intrinsics->SetRadialDistortion(
+ camera_intrinsics_options->polynomial_k1,
+ camera_intrinsics_options->polynomial_k2,
+ camera_intrinsics_options->polynomial_k3);
+
+ break;
+ }
+
+ case LIBMV_DISTORTION_MODEL_DIVISION:
+ {
+ DivisionCameraIntrinsics *division_intrinsics =
+ static_cast<DivisionCameraIntrinsics*>(camera_intrinsics);
+
+ division_intrinsics->SetDistortion(
+ camera_intrinsics_options->division_k1,
+ camera_intrinsics_options->division_k2);
+ break;
+ }
+
+ default:
+ assert(!"Unknown distortion model");
+ }
+}
+
+CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
+ const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) {
+ CameraIntrinsics *camera_intrinsics = NULL;
+ switch (camera_intrinsics_options->distortion_model) {
+ case LIBMV_DISTORTION_MODEL_POLYNOMIAL:
+ camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics);
+ break;
+ case LIBMV_DISTORTION_MODEL_DIVISION:
+ camera_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics);
+ break;
+ default:
+ assert(!"Unknown distortion model");
+ }
+ libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options,
+ camera_intrinsics);
+ return camera_intrinsics;
+}
diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h
new file mode 100644
index 00000000000..50a0073437b
--- /dev/null
+++ b/intern/libmv/intern/camera_intrinsics.h
@@ -0,0 +1,138 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef LIBMV_C_API_CAMERA_INTRINSICS_H_
+#define LIBMV_C_API_CAMERA_INTRINSICS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct libmv_CameraIntrinsics libmv_CameraIntrinsics;
+
+enum {
+ LIBMV_DISTORTION_MODEL_POLYNOMIAL = 0,
+ LIBMV_DISTORTION_MODEL_DIVISION = 1,
+};
+
+typedef struct libmv_CameraIntrinsicsOptions {
+ // Common settings of all distortion models.
+ int distortion_model;
+ int image_width, image_height;
+ double focal_length;
+ double principal_point_x, principal_point_y;
+
+ // Radial distortion model.
+ double polynomial_k1, polynomial_k2, polynomial_k3;
+ double polynomial_p1, polynomial_p2;
+
+ // Division distortion model.
+ double division_k1, division_k2;
+} libmv_CameraIntrinsicsOptions;
+
+libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
+ const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options);
+
+libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
+ const libmv_CameraIntrinsics* libmv_intrinsics);
+
+void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics);
+void libmv_cameraIntrinsicsUpdate(
+ const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options,
+ libmv_CameraIntrinsics* libmv_intrinsics);
+
+void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics,
+ int threads);
+
+void libmv_cameraIntrinsicsExtractOptions(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ libmv_CameraIntrinsicsOptions* camera_intrinsics_options);
+
+void libmv_cameraIntrinsicsUndistortByte(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ const unsigned char *source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ unsigned char* destination_image);
+
+void libmv_cameraIntrinsicsUndistortFloat(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ const float* source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ float* destination_image);
+
+void libmv_cameraIntrinsicsDistortByte(
+ const struct libmv_CameraIntrinsics* libmv_intrinsics,
+ const unsigned char *source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ unsigned char *destination_image);
+
+void libmv_cameraIntrinsicsDistortFloat(
+ const libmv_CameraIntrinsics* libmv_intrinsics,
+ float* source_image,
+ int width,
+ int height,
+ float overscan,
+ int channels,
+ float* destination_image);
+
+void libmv_cameraIntrinsicsApply(
+ const struct libmv_CameraIntrinsics* libmv_intrinsics,
+ double x,
+ double y,
+ double* x1,
+ double* y1);
+
+void libmv_cameraIntrinsicsInvert(
+ const struct libmv_CameraIntrinsics* libmv_intrinsics,
+ double x,
+ double y,
+ double* x1,
+ double* y1);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+namespace libmv {
+ class CameraIntrinsics;
+}
+
+libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions(
+ const libmv_CameraIntrinsicsOptions* camera_intrinsics_options);
+#endif
+
+#endif // LIBMV_C_API_CAMERA_INTRINSICS_H_
diff --git a/extern/libmv/intern/detector.cc b/intern/libmv/intern/detector.cc
index 8abc9014115..8abc9014115 100644
--- a/extern/libmv/intern/detector.cc
+++ b/intern/libmv/intern/detector.cc
diff --git a/extern/libmv/intern/detector.h b/intern/libmv/intern/detector.h
index f72b0dd8d6e..f72b0dd8d6e 100644
--- a/extern/libmv/intern/detector.h
+++ b/intern/libmv/intern/detector.h
diff --git a/intern/libmv/intern/frame_accessor.cc b/intern/libmv/intern/frame_accessor.cc
new file mode 100644
index 00000000000..9213cc311b3
--- /dev/null
+++ b/intern/libmv/intern/frame_accessor.cc
@@ -0,0 +1,164 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "intern/frame_accessor.h"
+#include "intern/image.h"
+#include "intern/utildefines.h"
+#include "libmv/autotrack/frame_accessor.h"
+#include "libmv/autotrack/region.h"
+#include "libmv/image/image.h"
+
+namespace {
+
+using libmv::FloatImage;
+using mv::FrameAccessor;
+using mv::Region;
+
+struct LibmvFrameAccessor : public FrameAccessor {
+ LibmvFrameAccessor(libmv_FrameAccessorUserData* user_data,
+ libmv_GetImageCallback get_image_callback,
+ libmv_ReleaseImageCallback release_image_callback)
+ : user_data_(user_data),
+ get_image_callback_(get_image_callback),
+ release_image_callback_(release_image_callback) { }
+
+ libmv_InputMode get_libmv_input_mode(InputMode input_mode) {
+ switch (input_mode) {
+#define CHECK_INPUT_MODE(mode) \
+ case mode: \
+ return LIBMV_IMAGE_MODE_ ## mode;
+ CHECK_INPUT_MODE(MONO)
+ CHECK_INPUT_MODE(RGBA)
+#undef CHECK_INPUT_MODE
+ }
+ assert(!"unknown input mode passed from Libmv.");
+ // TODO(sergey): Proper error handling here in the future.
+ return LIBMV_IMAGE_MODE_MONO;
+ }
+
+ void get_libmv_region(const Region& region,
+ libmv_Region* libmv_region) {
+ libmv_region->min[0] = region.min(0);
+ libmv_region->min[1] = region.min(1);
+ libmv_region->max[0] = region.max(0);
+ libmv_region->max[1] = region.max(1);
+ }
+
+ Key GetImage(int clip,
+ int frame,
+ InputMode input_mode,
+ int downscale,
+ const Region* region,
+ const Transform* transform,
+ FloatImage* destination) {
+ float *float_buffer;
+ int width, height, channels;
+ libmv_Region libmv_region;
+ if (region) {
+ get_libmv_region(*region, &libmv_region);
+ }
+ Key cache_key = get_image_callback_(user_data_,
+ clip,
+ frame,
+ get_libmv_input_mode(input_mode),
+ downscale,
+ region != NULL ? &libmv_region : NULL,
+ (libmv_FrameTransform*) transform,
+ &float_buffer,
+ &width,
+ &height,
+ &channels);
+
+ // TODO(sergey): Dumb code for until we can set data directly.
+ FloatImage temp_image(float_buffer,
+ height,
+ width,
+ channels);
+ destination->CopyFrom(temp_image);
+
+ return cache_key;
+ }
+
+ void ReleaseImage(Key cache_key) {
+ release_image_callback_(cache_key);
+ }
+
+ bool GetClipDimensions(int /*clip*/, int * /*width*/, int * /*height*/) {
+ return false;
+ }
+
+ int NumClips() {
+ return 1;
+ }
+
+ int NumFrames(int /*clip*/) {
+ return 0;
+ }
+
+ libmv_FrameAccessorUserData* user_data_;
+ libmv_GetImageCallback get_image_callback_;
+ libmv_ReleaseImageCallback release_image_callback_;
+};
+
+} // namespace
+
+libmv_FrameAccessor* libmv_FrameAccessorNew(
+ libmv_FrameAccessorUserData* user_data,
+ libmv_GetImageCallback get_image_callback,
+ libmv_ReleaseImageCallback release_image_callback) {
+ return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor,
+ user_data,
+ get_image_callback,
+ release_image_callback);
+}
+
+void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) {
+ LIBMV_OBJECT_DELETE(frame_accessor, LibmvFrameAccessor);
+}
+
+int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform) {
+ return ((FrameAccessor::Transform*) transform)->key();
+}
+
+void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform,
+ const libmv_FloatImage *input_image,
+ libmv_FloatImage *output_image) {
+ const FloatImage input(input_image->buffer,
+ input_image->height,
+ input_image->width,
+ input_image->channels);
+
+ FloatImage output;
+ ((FrameAccessor::Transform*) transform)->run(input,
+ &output);
+
+ int num_pixels = output.Width() *output.Height() * output.Depth();
+ output_image->buffer = new float[num_pixels];
+ memcpy(output_image->buffer, output.Data(), num_pixels * sizeof(float));
+ output_image->width = output.Width();
+ output_image->height = output.Height();
+ output_image->channels = output.Depth();
+}
diff --git a/extern/libmv/intern/frame_accessor.h b/intern/libmv/intern/frame_accessor.h
index 3e813fe7581..3e813fe7581 100644
--- a/extern/libmv/intern/frame_accessor.h
+++ b/intern/libmv/intern/frame_accessor.h
diff --git a/extern/libmv/intern/homography.cc b/intern/libmv/intern/homography.cc
index 6b61bd9ab42..6b61bd9ab42 100644
--- a/extern/libmv/intern/homography.cc
+++ b/intern/libmv/intern/homography.cc
diff --git a/extern/libmv/intern/homography.h b/intern/libmv/intern/homography.h
index 175108e8171..175108e8171 100644
--- a/extern/libmv/intern/homography.h
+++ b/intern/libmv/intern/homography.h
diff --git a/extern/libmv/intern/image.cc b/intern/libmv/intern/image.cc
index 5018caef5b1..5018caef5b1 100644
--- a/extern/libmv/intern/image.cc
+++ b/intern/libmv/intern/image.cc
diff --git a/extern/libmv/intern/image.h b/intern/libmv/intern/image.h
index 1213943aac4..1213943aac4 100644
--- a/extern/libmv/intern/image.h
+++ b/intern/libmv/intern/image.h
diff --git a/extern/libmv/intern/logging.cc b/intern/libmv/intern/logging.cc
index 77b56ef4df3..77b56ef4df3 100644
--- a/extern/libmv/intern/logging.cc
+++ b/intern/libmv/intern/logging.cc
diff --git a/extern/libmv/intern/logging.h b/intern/libmv/intern/logging.h
index 479ed3d6288..479ed3d6288 100644
--- a/extern/libmv/intern/logging.h
+++ b/intern/libmv/intern/logging.h
diff --git a/extern/libmv/intern/reconstruction.cc b/intern/libmv/intern/reconstruction.cc
index 046671e467f..046671e467f 100644
--- a/extern/libmv/intern/reconstruction.cc
+++ b/intern/libmv/intern/reconstruction.cc
diff --git a/extern/libmv/intern/reconstruction.h b/intern/libmv/intern/reconstruction.h
index 8b6b34a6142..8b6b34a6142 100644
--- a/extern/libmv/intern/reconstruction.h
+++ b/intern/libmv/intern/reconstruction.h
diff --git a/extern/libmv/intern/region.h b/intern/libmv/intern/region.h
index 9f114bbad3b..9f114bbad3b 100644
--- a/extern/libmv/intern/region.h
+++ b/intern/libmv/intern/region.h
diff --git a/intern/libmv/intern/stub.cc b/intern/libmv/intern/stub.cc
new file mode 100644
index 00000000000..47e1915e072
--- /dev/null
+++ b/intern/libmv/intern/stub.cc
@@ -0,0 +1,398 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "libmv-capi.h"
+
+#include <cstdlib>
+#include <cstring>
+
+/* ************ Logging ************ */
+
+void libmv_initLogging(const char * /*argv0*/) {
+}
+
+void libmv_startDebugLogging(void) {
+}
+
+void libmv_setLoggingVerbosity(int /*verbosity*/) {
+}
+
+/* ************ Planar tracker ************ */
+
+/* TrackRegion (new planar tracker) */
+int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/,
+ const float * /*image1*/,
+ int /*image1_width*/,
+ int /*image1_height*/,
+ const float * /*image2*/,
+ int /*image2_width*/,
+ int /*image2_height*/,
+ const double *x1,
+ const double *y1,
+ libmv_TrackRegionResult *result,
+ double *x2,
+ double *y2) {
+ /* Convert to doubles for the libmv api. The four corners and the center. */
+ for (int i = 0; i < 5; ++i) {
+ x2[i] = x1[i];
+ y2[i] = y1[i];
+ }
+
+ result->termination = -1;
+ result->termination_reason = "Built without libmv support";
+ result->correlation = 0.0;
+
+ return false;
+}
+
+void libmv_samplePlanarPatchFloat(const float * /*image*/,
+ int /*width*/,
+ int /*height*/,
+ int /*channels*/,
+ const double * /*xs*/,
+ const double * /*ys*/,
+ int /*num_samples_x*/,
+ int /*num_samples_y*/,
+ const float * /*mask*/,
+ float * /*patch*/,
+ double * /*warped_position_x*/,
+ double * /*warped_position_y*/) {
+ /* TODO(sergey): implement */
+}
+
+void libmv_samplePlanarPatchByte(const unsigned char * /*image*/,
+ int /*width*/,
+ int /*height*/,
+ int /*channels*/,
+ const double * /*xs*/,
+ const double * /*ys*/,
+ int /*num_samples_x*/, int /*num_samples_y*/,
+ const float * /*mask*/,
+ unsigned char * /*patch*/,
+ double * /*warped_position_x*/,
+ double * /*warped_position_y*/) {
+ /* TODO(sergey): implement */
+}
+
+void libmv_floatImageDestroy(libmv_FloatImage* /*image*/)
+{
+}
+
+/* ************ Tracks ************ */
+
+libmv_Tracks *libmv_tracksNew(void) {
+ return NULL;
+}
+
+void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/,
+ int /*image*/,
+ int /*track*/,
+ double /*x*/,
+ double /*y*/,
+ double /*weight*/) {
+}
+
+void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) {
+}
+
+/* ************ Reconstruction solver ************ */
+
+libmv_Reconstruction *libmv_solveReconstruction(
+ const libmv_Tracks * /*libmv_tracks*/,
+ const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
+ libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
+ reconstruct_progress_update_cb /*progress_update_callback*/,
+ void * /*callback_customdata*/) {
+ return NULL;
+}
+
+libmv_Reconstruction *libmv_solveModal(
+ const libmv_Tracks * /*libmv_tracks*/,
+ const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
+ const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
+ reconstruct_progress_update_cb /*progress_update_callback*/,
+ void * /*callback_customdata*/) {
+ return NULL;
+}
+
+int libmv_reconstructionIsValid(libmv_Reconstruction * /*libmv_reconstruction*/) {
+ return 0;
+}
+
+int libmv_reprojectionPointForTrack(
+ const libmv_Reconstruction * /*libmv_reconstruction*/,
+ int /*track*/,
+ double /*pos*/[3]) {
+ return 0;
+}
+
+double libmv_reprojectionErrorForTrack(
+ const libmv_Reconstruction * /*libmv_reconstruction*/,
+ int /*track*/) {
+ return 0.0;
+}
+
+double libmv_reprojectionErrorForImage(
+ const libmv_Reconstruction * /*libmv_reconstruction*/,
+ int /*image*/) {
+ return 0.0;
+}
+
+int libmv_reprojectionCameraForImage(
+ const libmv_Reconstruction * /*libmv_reconstruction*/,
+ int /*image*/,
+ double /*mat*/[4][4]) {
+ return 0;
+}
+
+double libmv_reprojectionError(
+ const libmv_Reconstruction * /*libmv_reconstruction*/) {
+ return 0.0;
+}
+
+void libmv_reconstructionDestroy(
+ struct libmv_Reconstruction * /*libmv_reconstruction*/) {
+}
+
+/* ************ Feature detector ************ */
+
+libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/,
+ int /*width*/,
+ int /*height*/,
+ int /*channels*/,
+ libmv_DetectOptions * /*options*/) {
+ return NULL;
+}
+
+struct libmv_Features *libmv_detectFeaturesFloat(
+ const float * /*image_buffer*/,
+ int /*width*/,
+ int /*height*/,
+ int /*channels*/,
+ libmv_DetectOptions * /*options*/) {
+ return NULL;
+}
+
+int libmv_countFeatures(const libmv_Features * /*libmv_features*/) {
+ return 0;
+}
+
+void libmv_getFeature(const libmv_Features * /*libmv_features*/,
+ int /*number*/,
+ double *x,
+ double *y,
+ double *score,
+ double *size) {
+ *x = 0.0;
+ *y = 0.0;
+ *score = 0.0;
+ *size = 0.0;
+}
+
+void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) {
+}
+
+/* ************ Camera intrinsics ************ */
+
+libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
+ libmv_Reconstruction * /*libmv_reconstruction*/) {
+ return NULL;
+}
+
+libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew(
+ const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) {
+ return NULL;
+}
+
+libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy(
+ const libmv_CameraIntrinsics * /*libmvIntrinsics*/) {
+ return NULL;
+}
+
+void libmv_cameraIntrinsicsDestroy(
+ libmv_CameraIntrinsics * /*libmvIntrinsics*/) {
+}
+
+void libmv_cameraIntrinsicsUpdate(
+ const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
+ libmv_CameraIntrinsics * /*libmv_intrinsics*/) {
+}
+
+void libmv_cameraIntrinsicsSetThreads(
+ libmv_CameraIntrinsics * /*libmv_intrinsics*/,
+ int /*threads*/) {
+}
+
+void libmv_cameraIntrinsicsExtractOptions(
+ const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
+ libmv_CameraIntrinsicsOptions *camera_intrinsics_options) {
+ memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions));
+ camera_intrinsics_options->focal_length = 1.0;
+}
+
+void libmv_cameraIntrinsicsUndistortByte(
+ const libmv_CameraIntrinsics * /*libmv_intrinsics*/,
+ const unsigned char *source_image,
+ int width, int height,
+ float /*overscan*/,
+ int channels,
+ unsigned char *destination_image) {
+ memcpy(destination_image, source_image,
+ channels * width * height * sizeof(unsigned char));
+}
+
+void libmv_cameraIntrinsicsUndistortFloat(
+ const libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ const float* source_image,
+ int width,
+ int height,
+ float /*overscan*/,
+ int channels,
+ float* destination_image) {
+ memcpy(destination_image, source_image,
+ channels * width * height * sizeof(float));
+}
+
+void libmv_cameraIntrinsicsDistortByte(
+ const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ const unsigned char *source_image,
+ int width,
+ int height,
+ float /*overscan*/,
+ int channels,
+ unsigned char *destination_image) {
+ memcpy(destination_image, source_image,
+ channels * width * height * sizeof(unsigned char));
+}
+
+void libmv_cameraIntrinsicsDistortFloat(
+ const libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ float* source_image,
+ int width,
+ int height,
+ float /*overscan*/,
+ int channels,
+ float* destination_image) {
+ memcpy(destination_image, source_image,
+ channels * width * height * sizeof(float));
+}
+
+/* ************ utils ************ */
+
+void libmv_cameraIntrinsicsApply(
+ const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ double /*x*/,
+ double /*y*/,
+ double* x1,
+ double* y1) {
+ *x1 = 0.0;
+ *y1 = 0.0;
+}
+
+void libmv_cameraIntrinsicsInvert(
+ const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/,
+ double /*x*/,
+ double /*y*/,
+ double* x1,
+ double* y1) {
+ *x1 = 0.0;
+ *y1 = 0.0;
+}
+
+void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2],
+ /* const */ double (* /*x2*/)[2],
+ int /*num_points*/,
+ double H[3][3]) {
+ memset(H, 0, sizeof(double[3][3]));
+ H[0][0] = 1.0f;
+ H[1][1] = 1.0f;
+ H[2][2] = 1.0f;
+}
+
+/* ************ autotrack ************ */
+
+libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/)
+{
+ return NULL;
+}
+
+void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/)
+{
+}
+
+void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/,
+ const libmv_AutoTrackOptions* /*options*/)
+{
+}
+
+int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/,
+ const libmv_TrackRegionOptions* /*libmv_options*/,
+ libmv_Marker * /*libmv_tracker_marker*/,
+ libmv_TrackRegionResult* /*libmv_result*/)
+{
+ return 0;
+}
+
+void libmv_autoTrackAddMarker(libmv_AutoTrack* /*libmv_autotrack*/,
+ const libmv_Marker* /*libmv_marker*/)
+{
+}
+
+int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/,
+ int /*clip*/,
+ int /*frame*/,
+ int /*track*/,
+ libmv_Marker* /*libmv_marker*/)
+{
+ return 0;
+}
+
+/* ************ frame accessor ************ */
+
+libmv_FrameAccessor* libmv_FrameAccessorNew(
+ libmv_FrameAccessorUserData* /*user_data**/,
+ libmv_GetImageCallback /*get_image_callback*/,
+ libmv_ReleaseImageCallback /*release_image_callback*/)
+{
+ return NULL;
+}
+
+void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/)
+{
+}
+
+int64_t libmv_frameAccessorgetTransformKey(
+ const libmv_FrameTransform * /*transform*/)
+{
+ return 0;
+}
+
+void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* /*transform*/,
+ const libmv_FloatImage* /*input_image*/,
+ libmv_FloatImage* /*output_image*/)
+{
+}
+
diff --git a/intern/libmv/intern/track_region.cc b/intern/libmv/intern/track_region.cc
new file mode 100644
index 00000000000..8989897e09f
--- /dev/null
+++ b/intern/libmv/intern/track_region.cc
@@ -0,0 +1,177 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "intern/track_region.h"
+#include "intern/image.h"
+#include "intern/utildefines.h"
+#include "libmv/image/image.h"
+#include "libmv/tracking/track_region.h"
+
+/* define this to generate PNG images with content of search areas
+ tracking between which failed */
+#undef DUMP_FAILURE
+
+/* define this to generate PNG images with content of search areas
+ on every itteration of tracking */
+#undef DUMP_ALWAYS
+
+using libmv::FloatImage;
+using libmv::TrackRegionOptions;
+using libmv::TrackRegionResult;
+using libmv::TrackRegion;
+
+void libmv_configureTrackRegionOptions(
+ const libmv_TrackRegionOptions& options,
+ TrackRegionOptions* track_region_options) {
+ switch (options.motion_model) {
+#define LIBMV_CONVERT(the_model) \
+ case TrackRegionOptions::the_model: \
+ track_region_options->mode = TrackRegionOptions::the_model; \
+ break;
+ LIBMV_CONVERT(TRANSLATION)
+ LIBMV_CONVERT(TRANSLATION_ROTATION)
+ LIBMV_CONVERT(TRANSLATION_SCALE)
+ LIBMV_CONVERT(TRANSLATION_ROTATION_SCALE)
+ LIBMV_CONVERT(AFFINE)
+ LIBMV_CONVERT(HOMOGRAPHY)
+#undef LIBMV_CONVERT
+ }
+
+ track_region_options->minimum_correlation = options.minimum_correlation;
+ track_region_options->max_iterations = options.num_iterations;
+ track_region_options->sigma = options.sigma;
+ track_region_options->num_extra_points = 1;
+ track_region_options->image1_mask = NULL;
+ track_region_options->use_brute_initialization = options.use_brute;
+ /* TODO(keir): This will make some cases better, but may be a regression until
+ * the motion model is in. Since this is on trunk, enable it for now.
+ *
+ * TODO(sergey): This gives much worse results on mango footage (see 04_2e)
+ * so disabling for now for until proper prediction model is landed.
+ *
+ * The thing is, currently blender sends input coordinates as the guess to
+ * region tracker and in case of fast motion such an early out ruins the track.
+ */
+ track_region_options->attempt_refine_before_brute = false;
+ track_region_options->use_normalized_intensities = options.use_normalization;
+}
+
+void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result,
+ libmv_TrackRegionResult* result) {
+ result->termination = (int) track_region_result.termination;
+ result->termination_reason = "";
+ result->correlation = track_region_result.correlation;
+}
+
+int libmv_trackRegion(const libmv_TrackRegionOptions* options,
+ const float* image1,
+ int image1_width,
+ int image1_height,
+ const float* image2,
+ int image2_width,
+ int image2_height,
+ const double* x1,
+ const double* y1,
+ libmv_TrackRegionResult* /*result*/,
+ double* x2,
+ double* y2) {
+ double xx1[5], yy1[5];
+ double xx2[5], yy2[5];
+ bool tracking_result = false;
+
+ // Convert to doubles for the libmv api. The four corners and the center.
+ for (int i = 0; i < 5; ++i) {
+ xx1[i] = x1[i];
+ yy1[i] = y1[i];
+ xx2[i] = x2[i];
+ yy2[i] = y2[i];
+ }
+
+ TrackRegionOptions track_region_options;
+ FloatImage image1_mask;
+
+ libmv_configureTrackRegionOptions(*options, &track_region_options);
+ if (options->image1_mask) {
+ libmv_floatBufferToFloatImage(options->image1_mask,
+ image1_width,
+ image1_height,
+ 1,
+ &image1_mask);
+
+ track_region_options.image1_mask = &image1_mask;
+ }
+
+ // Convert from raw float buffers to libmv's FloatImage.
+ FloatImage old_patch, new_patch;
+ libmv_floatBufferToFloatImage(image1,
+ image1_width,
+ image1_height,
+ 1,
+ &old_patch);
+ libmv_floatBufferToFloatImage(image2,
+ image2_width,
+ image2_height,
+ 1,
+ &new_patch);
+
+ TrackRegionResult track_region_result;
+ TrackRegion(old_patch, new_patch,
+ xx1, yy1,
+ track_region_options,
+ xx2, yy2,
+ &track_region_result);
+
+ // Convert to floats for the blender api.
+ for (int i = 0; i < 5; ++i) {
+ x2[i] = xx2[i];
+ y2[i] = yy2[i];
+ }
+
+ // TODO(keir): Update the termination string with failure details.
+ if (track_region_result.termination == TrackRegionResult::CONVERGENCE ||
+ track_region_result.termination == TrackRegionResult::NO_CONVERGENCE) {
+ tracking_result = true;
+ }
+
+ // Debug dump of patches.
+#if defined(DUMP_FAILURE) || defined(DUMP_ALWAYS)
+ bool need_dump = !tracking_result;
+
+# ifdef DUMP_ALWAYS
+ need_dump = true;
+# endif
+
+ if (need_dump) {
+ libmv_saveImage(old_patch, "old_patch", x1[4], y1[4]);
+ libmv_saveImage(new_patch, "new_patch", x2[4], y2[4]);
+ if (options->image1_mask) {
+ libmv_saveImage(image1_mask, "mask", x2[4], y2[4]);
+ }
+ }
+#endif
+
+ return tracking_result;
+}
diff --git a/extern/libmv/intern/track_region.h b/intern/libmv/intern/track_region.h
index 7ed3e443e40..7ed3e443e40 100644
--- a/extern/libmv/intern/track_region.h
+++ b/intern/libmv/intern/track_region.h
diff --git a/extern/libmv/intern/tracks.cc b/intern/libmv/intern/tracks.cc
index 9b032b0760a..9b032b0760a 100644
--- a/extern/libmv/intern/tracks.cc
+++ b/intern/libmv/intern/tracks.cc
diff --git a/extern/libmv/intern/tracks.h b/intern/libmv/intern/tracks.h
index 79f6cc99579..79f6cc99579 100644
--- a/extern/libmv/intern/tracks.h
+++ b/intern/libmv/intern/tracks.h
diff --git a/extern/libmv/intern/tracksN.cc b/intern/libmv/intern/tracksN.cc
index 9e1da88ef10..9e1da88ef10 100644
--- a/extern/libmv/intern/tracksN.cc
+++ b/intern/libmv/intern/tracksN.cc
diff --git a/extern/libmv/intern/tracksN.h b/intern/libmv/intern/tracksN.h
index d0cb54e40bc..d0cb54e40bc 100644
--- a/extern/libmv/intern/tracksN.h
+++ b/intern/libmv/intern/tracksN.h
diff --git a/intern/libmv/intern/utildefines.h b/intern/libmv/intern/utildefines.h
new file mode 100644
index 00000000000..b1f11d6091e
--- /dev/null
+++ b/intern/libmv/intern/utildefines.h
@@ -0,0 +1,62 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef LIBMV_C_API_UTILDEFINES_H_
+#define LIBMV_C_API_UTILDEFINES_H_
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+# define __func__ __FUNCTION__
+# define snprintf _snprintf
+#endif
+
+#ifdef WITH_LIBMV_GUARDED_ALLOC
+# include "MEM_guardedalloc.h"
+# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW
+# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
+# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
+# define LIBMV_STRUCT_NEW(type, count) \
+ (type*)MEM_mallocN(sizeof(type) * count, __func__)
+# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what)
+#else
+// Need this to keep libmv-capi potentially standalone.
+# if defined __GNUC__ || defined __sun
+# define LIBMV_OBJECT_NEW(type, args ...) \
+ new(malloc(sizeof(type))) type(args)
+# else
+# define LIBMV_OBJECT_NEW(type, ...) \
+ new(malloc(sizeof(type))) type(__VA_ARGS__)
+#endif
+# define LIBMV_OBJECT_DELETE(what, type) \
+ { \
+ if (what) { \
+ ((type*)(what))->~type(); \
+ free(what); \
+ } \
+ } (void)0
+# define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count)
+# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0
+#endif
+
+#endif // LIBMV_C_API_UTILDEFINES_H_
diff --git a/extern/libmv/libmv-capi.h b/intern/libmv/libmv-capi.h
index 92e206a19b2..92e206a19b2 100644
--- a/extern/libmv/libmv-capi.h
+++ b/intern/libmv/libmv-capi.h
diff --git a/extern/libmv/libmv/autotrack/autotrack.cc b/intern/libmv/libmv/autotrack/autotrack.cc
index 4c7bdf1fde8..4c7bdf1fde8 100644
--- a/extern/libmv/libmv/autotrack/autotrack.cc
+++ b/intern/libmv/libmv/autotrack/autotrack.cc
diff --git a/extern/libmv/libmv/autotrack/autotrack.h b/intern/libmv/libmv/autotrack/autotrack.h
index 1d7422f54e7..1d7422f54e7 100644
--- a/extern/libmv/libmv/autotrack/autotrack.h
+++ b/intern/libmv/libmv/autotrack/autotrack.h
diff --git a/extern/libmv/libmv/autotrack/callbacks.h b/intern/libmv/libmv/autotrack/callbacks.h
index e65841de3ce..e65841de3ce 100644
--- a/extern/libmv/libmv/autotrack/callbacks.h
+++ b/intern/libmv/libmv/autotrack/callbacks.h
diff --git a/extern/libmv/libmv/autotrack/frame_accessor.h b/intern/libmv/libmv/autotrack/frame_accessor.h
index 8de5d865cd7..8de5d865cd7 100644
--- a/extern/libmv/libmv/autotrack/frame_accessor.h
+++ b/intern/libmv/libmv/autotrack/frame_accessor.h
diff --git a/extern/libmv/libmv/autotrack/marker.h b/intern/libmv/libmv/autotrack/marker.h
index bb803313af8..bb803313af8 100644
--- a/extern/libmv/libmv/autotrack/marker.h
+++ b/intern/libmv/libmv/autotrack/marker.h
diff --git a/extern/libmv/libmv/autotrack/model.h b/intern/libmv/libmv/autotrack/model.h
index 1165281cdac..1165281cdac 100644
--- a/extern/libmv/libmv/autotrack/model.h
+++ b/intern/libmv/libmv/autotrack/model.h
diff --git a/extern/libmv/libmv/autotrack/predict_tracks.cc b/intern/libmv/libmv/autotrack/predict_tracks.cc
index adc986a0033..adc986a0033 100644
--- a/extern/libmv/libmv/autotrack/predict_tracks.cc
+++ b/intern/libmv/libmv/autotrack/predict_tracks.cc
diff --git a/extern/libmv/libmv/autotrack/predict_tracks.h b/intern/libmv/libmv/autotrack/predict_tracks.h
index 0a176d08378..0a176d08378 100644
--- a/extern/libmv/libmv/autotrack/predict_tracks.h
+++ b/intern/libmv/libmv/autotrack/predict_tracks.h
diff --git a/intern/libmv/libmv/autotrack/predict_tracks_test.cc b/intern/libmv/libmv/autotrack/predict_tracks_test.cc
new file mode 100644
index 00000000000..f7c2c68d750
--- /dev/null
+++ b/intern/libmv/libmv/autotrack/predict_tracks_test.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2014 libmv authors.
+//
+// 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.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+
+#include "libmv/autotrack/predict_tracks.h"
+
+#include "libmv/autotrack/marker.h"
+#include "libmv/autotrack/tracks.h"
+#include "libmv/logging/logging.h"
+#include "testing/testing.h"
+
+namespace mv {
+
+static void AddMarker(int frame, float x, float y, Tracks* tracks) {
+ Marker marker;
+ marker.clip = marker.track = 0;
+ marker.frame = frame;
+ marker.center.x() = x;
+ marker.center.y() = y;
+ marker.patch.coordinates << x - 1, y - 1,
+ x + 1, y - 1,
+ x + 1, y + 1,
+ x - 1, y + 1;
+ tracks->AddMarker(marker);
+}
+
+TEST(PredictMarkerPosition, EasyLinearMotion) {
+ Tracks tracks;
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(2, 3.0, 10.0, &tracks);
+ AddMarker(3, 4.0, 15.0, &tracks);
+ AddMarker(4, 5.0, 20.0, &tracks);
+ AddMarker(5, 6.0, 25.0, &tracks);
+ AddMarker(6, 7.0, 30.0, &tracks);
+ AddMarker(7, 8.0, 35.0, &tracks);
+
+ Marker predicted;
+ predicted.clip = 0;
+ predicted.track = 0;
+ predicted.frame = 8;
+
+ PredictMarkerPosition(tracks, &predicted);
+ double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
+ LG << "Got error: " << error;
+ EXPECT_LT(error, 0.1);
+
+ // Check the patch coordinates as well.
+ double x = 9, y = 40.0;
+ Quad2Df expected_patch;
+ expected_patch.coordinates << x - 1, y - 1,
+ x + 1, y - 1,
+ x + 1, y + 1,
+ x - 1, y + 1;
+
+ error = (expected_patch.coordinates - predicted.patch.coordinates).norm();
+ LG << "Patch error: " << error;
+ EXPECT_LT(error, 0.1);
+}
+
+TEST(PredictMarkerPosition, EasyBackwardLinearMotion) {
+ Tracks tracks;
+ AddMarker(8, 1.0, 0.0, &tracks);
+ AddMarker(7, 2.0, 5.0, &tracks);
+ AddMarker(6, 3.0, 10.0, &tracks);
+ AddMarker(5, 4.0, 15.0, &tracks);
+ AddMarker(4, 5.0, 20.0, &tracks);
+ AddMarker(3, 6.0, 25.0, &tracks);
+ AddMarker(2, 7.0, 30.0, &tracks);
+ AddMarker(1, 8.0, 35.0, &tracks);
+
+ Marker predicted;
+ predicted.clip = 0;
+ predicted.track = 0;
+ predicted.frame = 0;
+
+ PredictMarkerPosition(tracks, &predicted);
+ LG << predicted;
+ double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
+ LG << "Got error: " << error;
+ EXPECT_LT(error, 0.1);
+
+ // Check the patch coordinates as well.
+ double x = 9.0, y = 40.0;
+ Quad2Df expected_patch;
+ expected_patch.coordinates << x - 1, y - 1,
+ x + 1, y - 1,
+ x + 1, y + 1,
+ x - 1, y + 1;
+
+ error = (expected_patch.coordinates - predicted.patch.coordinates).norm();
+ LG << "Patch error: " << error;
+ EXPECT_LT(error, 0.1);
+}
+
+TEST(PredictMarkerPosition, TwoFrameGap) {
+ Tracks tracks;
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(2, 3.0, 10.0, &tracks);
+ AddMarker(3, 4.0, 15.0, &tracks);
+ AddMarker(4, 5.0, 20.0, &tracks);
+ AddMarker(5, 6.0, 25.0, &tracks);
+ AddMarker(6, 7.0, 30.0, &tracks);
+ // Missing frame 7!
+
+ Marker predicted;
+ predicted.clip = 0;
+ predicted.track = 0;
+ predicted.frame = 8;
+
+ PredictMarkerPosition(tracks, &predicted);
+ double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
+ LG << "Got error: " << error;
+ EXPECT_LT(error, 0.1);
+}
+
+TEST(PredictMarkerPosition, FourFrameGap) {
+ Tracks tracks;
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(2, 3.0, 10.0, &tracks);
+ AddMarker(3, 4.0, 15.0, &tracks);
+ // Missing frames 4, 5, 6, 7.
+
+ Marker predicted;
+ predicted.clip = 0;
+ predicted.track = 0;
+ predicted.frame = 8;
+
+ PredictMarkerPosition(tracks, &predicted);
+ double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
+ LG << "Got error: " << error;
+ EXPECT_LT(error, 2.0); // Generous error due to larger prediction window.
+}
+
+TEST(PredictMarkerPosition, MultipleGaps) {
+ Tracks tracks;
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
+ AddMarker(2, 3.0, 10.0, &tracks);
+ // AddMarker(3, 4.0, 15.0, &tracks); // Note the 3-frame gap.
+ // AddMarker(4, 5.0, 20.0, &tracks);
+ // AddMarker(5, 6.0, 25.0, &tracks);
+ AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement.
+ // AddMarker(7, 8.0, 35.0, &tracks);
+
+ Marker predicted;
+ predicted.clip = 0;
+ predicted.track = 0;
+ predicted.frame = 8;
+
+ PredictMarkerPosition(tracks, &predicted);
+ double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
+ LG << "Got error: " << error;
+ EXPECT_LT(error, 1.0); // Generous error due to larger prediction window.
+}
+
+TEST(PredictMarkerPosition, MarkersInRandomOrder) {
+ Tracks tracks;
+
+ // This is the same as the easy, except that the tracks are randomly ordered.
+ AddMarker(0, 1.0, 0.0, &tracks);
+ AddMarker(2, 3.0, 10.0, &tracks);
+ AddMarker(7, 8.0, 35.0, &tracks);
+ AddMarker(5, 6.0, 25.0, &tracks);
+ AddMarker(4, 5.0, 20.0, &tracks);
+ AddMarker(3, 4.0, 15.0, &tracks);
+ AddMarker(6, 7.0, 30.0, &tracks);
+ AddMarker(1, 2.0, 5.0, &tracks);
+
+ Marker predicted;
+ predicted.clip = 0;
+ predicted.track = 0;
+ predicted.frame = 8;
+
+ PredictMarkerPosition(tracks, &predicted);
+ double error = (libmv::Vec2f(9.0, 40.0) - predicted.center).norm();
+ LG << "Got error: " << error;
+ EXPECT_LT(error, 0.1);
+}
+
+} // namespace mv
diff --git a/extern/libmv/libmv/autotrack/quad.h b/intern/libmv/libmv/autotrack/quad.h
index 0c70f9882da..0c70f9882da 100644
--- a/extern/libmv/libmv/autotrack/quad.h
+++ b/intern/libmv/libmv/autotrack/quad.h
diff --git a/extern/libmv/libmv/autotrack/reconstruction.h b/intern/libmv/libmv/autotrack/reconstruction.h
index e1d4e882cbd..e1d4e882cbd 100644
--- a/extern/libmv/libmv/autotrack/reconstruction.h
+++ b/intern/libmv/libmv/autotrack/reconstruction.h
diff --git a/extern/libmv/libmv/autotrack/region.h b/intern/libmv/libmv/autotrack/region.h
index b35d99eb60d..b35d99eb60d 100644
--- a/extern/libmv/libmv/autotrack/region.h
+++ b/intern/libmv/libmv/autotrack/region.h
diff --git a/extern/libmv/libmv/autotrack/tracks.cc b/intern/libmv/libmv/autotrack/tracks.cc
index 174f264f3f2..174f264f3f2 100644
--- a/extern/libmv/libmv/autotrack/tracks.cc
+++ b/intern/libmv/libmv/autotrack/tracks.cc
diff --git a/extern/libmv/libmv/autotrack/tracks.h b/intern/libmv/libmv/autotrack/tracks.h
index 0b7de91d211..0b7de91d211 100644
--- a/extern/libmv/libmv/autotrack/tracks.h
+++ b/intern/libmv/libmv/autotrack/tracks.h
diff --git a/extern/libmv/libmv/autotrack/tracks_test.cc b/intern/libmv/libmv/autotrack/tracks_test.cc
index 028b4a10913..028b4a10913 100644
--- a/extern/libmv/libmv/autotrack/tracks_test.cc
+++ b/intern/libmv/libmv/autotrack/tracks_test.cc
diff --git a/intern/libmv/libmv/base/aligned_malloc.cc b/intern/libmv/libmv/base/aligned_malloc.cc
new file mode 100644
index 00000000000..cc0a5fbbba7
--- /dev/null
+++ b/intern/libmv/libmv/base/aligned_malloc.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2014 libmv authors.
+//
+// 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.
+
+#include "libmv/base/aligned_malloc.h"
+#include "libmv/logging/logging.h"
+
+#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+// Needed for memalign on Linux and _aligned_alloc on Windows.
+# ifdef FREE_WINDOWS
+/* make sure _aligned_malloc is included */
+# ifdef __MSVCRT_VERSION__
+# undef __MSVCRT_VERSION__
+# endif
+
+# define __MSVCRT_VERSION__ 0x0700
+# endif // FREE_WINDOWS
+
+# include <malloc.h>
+#else
+// Apple's malloc is 16-byte aligned, and does not have malloc.h, so include
+// stdilb instead.
+# include <cstdlib>
+#endif
+
+namespace libmv {
+
+void *aligned_malloc(int size, int alignment) {
+#ifdef _WIN32
+ return _aligned_malloc(size, alignment);
+#elif defined(__APPLE__)
+ // On Mac OS X, both the heap and the stack are guaranteed 16-byte aligned so
+ // they work natively with SSE types with no further work.
+ CHECK_EQ(alignment, 16);
+ return malloc(size);
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
+ void *result;
+
+ if (posix_memalign(&result, alignment, size)) {
+ // non-zero means allocation error
+ // either no allocation or bad alignment value
+ return NULL;
+ }
+ return result;
+#else // This is for Linux.
+ return memalign(alignment, size);
+#endif
+}
+
+void aligned_free(void *ptr) {
+#ifdef _WIN32
+ _aligned_free(ptr);
+#else
+ free(ptr);
+#endif
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/base/aligned_malloc.h b/intern/libmv/libmv/base/aligned_malloc.h
index 096ff6e2d7c..096ff6e2d7c 100644
--- a/extern/libmv/libmv/base/aligned_malloc.h
+++ b/intern/libmv/libmv/base/aligned_malloc.h
diff --git a/extern/libmv/libmv/base/id_generator.h b/intern/libmv/libmv/base/id_generator.h
index bf1eafd218e..bf1eafd218e 100644
--- a/extern/libmv/libmv/base/id_generator.h
+++ b/intern/libmv/libmv/base/id_generator.h
diff --git a/extern/libmv/libmv/base/scoped_ptr.h b/intern/libmv/libmv/base/scoped_ptr.h
index b9cd4854213..b9cd4854213 100644
--- a/extern/libmv/libmv/base/scoped_ptr.h
+++ b/intern/libmv/libmv/base/scoped_ptr.h
diff --git a/extern/libmv/libmv/base/scoped_ptr_test.cc b/intern/libmv/libmv/base/scoped_ptr_test.cc
index ce1d56b500a..ce1d56b500a 100644
--- a/extern/libmv/libmv/base/scoped_ptr_test.cc
+++ b/intern/libmv/libmv/base/scoped_ptr_test.cc
diff --git a/extern/libmv/libmv/base/vector.h b/intern/libmv/libmv/base/vector.h
index 1931fb0b1f9..1931fb0b1f9 100644
--- a/extern/libmv/libmv/base/vector.h
+++ b/intern/libmv/libmv/base/vector.h
diff --git a/extern/libmv/libmv/base/vector_test.cc b/intern/libmv/libmv/base/vector_test.cc
index f17718c3926..f17718c3926 100644
--- a/extern/libmv/libmv/base/vector_test.cc
+++ b/intern/libmv/libmv/base/vector_test.cc
diff --git a/extern/libmv/libmv/base/vector_utils.h b/intern/libmv/libmv/base/vector_utils.h
index c71e1bea951..c71e1bea951 100644
--- a/extern/libmv/libmv/base/vector_utils.h
+++ b/intern/libmv/libmv/base/vector_utils.h
diff --git a/extern/libmv/libmv/image/array_nd.cc b/intern/libmv/libmv/image/array_nd.cc
index 469a19aabf1..469a19aabf1 100644
--- a/extern/libmv/libmv/image/array_nd.cc
+++ b/intern/libmv/libmv/image/array_nd.cc
diff --git a/intern/libmv/libmv/image/array_nd.h b/intern/libmv/libmv/image/array_nd.h
new file mode 100644
index 00000000000..e95e66aa2b3
--- /dev/null
+++ b/intern/libmv/libmv/image/array_nd.h
@@ -0,0 +1,497 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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.
+
+#ifndef LIBMV_IMAGE_ARRAY_ND_H
+#define LIBMV_IMAGE_ARRAY_ND_H
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+
+#include "libmv/image/tuple.h"
+
+namespace libmv {
+
+class BaseArray {};
+
+/// A multidimensional array class.
+template <typename T, int N>
+class ArrayND : public BaseArray {
+ public:
+ typedef T Scalar;
+
+ /// Type for the multidimensional indices.
+ typedef Tuple<int, N> Index;
+
+ /// Create an empty array.
+ ArrayND() : data_(NULL), own_data_(true) { Resize(Index(0)); }
+
+ /// Create an array with the specified shape.
+ ArrayND(const Index &shape) : data_(NULL), own_data_(true) { Resize(shape); }
+
+ /// Create an array with the specified shape.
+ ArrayND(int *shape) : data_(NULL), own_data_(true) { Resize(shape); }
+
+ /// Copy constructor.
+ ArrayND(const ArrayND<T, N> &b) : data_(NULL), own_data_(true) {
+ ResizeLike(b);
+ std::memcpy(Data(), b.Data(), sizeof(T) * Size());
+ }
+
+ ArrayND(int s0) : data_(NULL), own_data_(true) { Resize(s0); }
+ ArrayND(int s0, int s1) : data_(NULL), own_data_(true) { Resize(s0, s1); }
+ ArrayND(int s0, int s1, int s2) : data_(NULL), own_data_(true) {
+ Resize(s0, s1, s2);
+ }
+
+ ArrayND(T* data, int s0, int s1, int s2)
+ : shape_(0), strides_(0), data_(data), own_data_(false) {
+ Resize(s0, s1, s2);
+ }
+
+ /// Destructor deletes pixel data.
+ ~ArrayND() {
+ if (own_data_) {
+ delete [] data_;
+ }
+ }
+
+ /// Assignation copies pixel data.
+ ArrayND &operator=(const ArrayND<T, N> &b) {
+ assert(this != &b);
+ ResizeLike(b);
+ std::memcpy(Data(), b.Data(), sizeof(T) * Size());
+ return *this;
+ }
+
+ const Index &Shapes() const {
+ return shape_;
+ }
+
+ const Index &Strides() const {
+ return strides_;
+ }
+
+ /// Create an array of shape s.
+ void Resize(const Index &new_shape) {
+ if (data_ != NULL && shape_ == new_shape) {
+ // Don't bother realloacting if the shapes match.
+ return;
+ }
+ shape_.Reset(new_shape);
+ strides_(N - 1) = 1;
+ for (int i = N - 1; i > 0; --i) {
+ strides_(i - 1) = strides_(i) * shape_(i);
+ }
+ if (own_data_) {
+ delete [] data_;
+ data_ = NULL;
+ if (Size() > 0) {
+ data_ = new T[Size()];
+ }
+ }
+ }
+
+ template<typename D>
+ void ResizeLike(const ArrayND<D, N> &other) {
+ Resize(other.Shape());
+ }
+
+ /// Resizes the array to shape s. All data is lost.
+ void Resize(const int *new_shape_array) {
+ Resize(Index(new_shape_array));
+ }
+
+ /// Resize a 1D array to length s0.
+ void Resize(int s0) {
+ assert(N == 1);
+ int shape[] = {s0};
+ Resize(shape);
+ }
+
+ /// Resize a 2D array to shape (s0,s1).
+ void Resize(int s0, int s1) {
+ int shape[N] = {s0, s1};
+ for (int i = 2; i < N; ++i) {
+ shape[i] = 1;
+ }
+ Resize(shape);
+ }
+
+ // Match Eigen2's API.
+ void resize(int rows, int cols) {
+ Resize(rows, cols);
+ }
+
+ /// Resize a 3D array to shape (s0,s1,s2).
+ void Resize(int s0, int s1, int s2) {
+ assert(N == 3);
+ int shape[] = {s0, s1, s2};
+ Resize(shape);
+ }
+
+ template<typename D>
+ void CopyFrom(const ArrayND<D, N> &other) {
+ ResizeLike(other);
+ T *data = Data();
+ const D *other_data = other.Data();
+ for (int i = 0; i < Size(); ++i) {
+ data[i] = T(other_data[i]);
+ }
+ }
+
+ void Fill(T value) {
+ for (int i = 0; i < Size(); ++i) {
+ Data()[i] = value;
+ }
+ }
+
+ // Match Eigen's API.
+ void fill(T value) {
+ for (int i = 0; i < Size(); ++i) {
+ Data()[i] = value;
+ }
+ }
+
+ /// Return a tuple containing the length of each axis.
+ const Index &Shape() const {
+ return shape_;
+ }
+
+ /// Return the length of an axis.
+ int Shape(int axis) const {
+ return shape_(axis);
+ }
+
+ /// Return the distance between neighboring elements along axis.
+ int Stride(int axis) const {
+ return strides_(axis);
+ }
+
+ /// Return the number of elements of the array.
+ int Size() const {
+ int size = 1;
+ for (int i = 0; i < N; ++i)
+ size *= Shape(i);
+ return size;
+ }
+
+ /// Return the total amount of memory used by the array.
+ int MemorySizeInBytes() const {
+ return sizeof(*this) + Size() * sizeof(T);
+ }
+
+ /// Pointer to the first element of the array.
+ T *Data() { return data_; }
+
+ /// Constant pointer to the first element of the array.
+ const T *Data() const { return data_; }
+
+ /// Distance between the first element and the element at position index.
+ int Offset(const Index &index) const {
+ int offset = 0;
+ for (int i = 0; i < N; ++i)
+ offset += index(i) * Stride(i);
+ return offset;
+ }
+
+ /// 1D specialization.
+ int Offset(int i0) const {
+ assert(N == 1);
+ return i0 * Stride(0);
+ }
+
+ /// 2D specialization.
+ int Offset(int i0, int i1) const {
+ assert(N == 2);
+ return i0 * Stride(0) + i1 * Stride(1);
+ }
+
+ /// 3D specialization.
+ int Offset(int i0, int i1, int i2) const {
+ assert(N == 3);
+ return i0 * Stride(0) + i1 * Stride(1) + i2 * Stride(2);
+ }
+
+ /// Return a reference to the element at position index.
+ T &operator()(const Index &index) {
+ // TODO(pau) Boundary checking in debug mode.
+ return *( Data() + Offset(index) );
+ }
+
+ /// 1D specialization.
+ T &operator()(int i0) {
+ return *( Data() + Offset(i0) );
+ }
+
+ /// 2D specialization.
+ T &operator()(int i0, int i1) {
+ assert(0 <= i0 && i0 < Shape(0));
+ assert(0 <= i1 && i1 < Shape(1));
+ return *(Data() + Offset(i0, i1));
+ }
+
+ /// 3D specialization.
+ T &operator()(int i0, int i1, int i2) {
+ assert(0 <= i0 && i0 < Shape(0));
+ assert(0 <= i1 && i1 < Shape(1));
+ assert(0 <= i2 && i2 < Shape(2));
+ return *(Data() + Offset(i0, i1, i2));
+ }
+
+ /// Return a constant reference to the element at position index.
+ const T &operator()(const Index &index) const {
+ return *(Data() + Offset(index));
+ }
+
+ /// 1D specialization.
+ const T &operator()(int i0) const {
+ return *(Data() + Offset(i0));
+ }
+
+ /// 2D specialization.
+ const T &operator()(int i0, int i1) const {
+ assert(0 <= i0 && i0 < Shape(0));
+ assert(0 <= i1 && i1 < Shape(1));
+ return *(Data() + Offset(i0, i1));
+ }
+
+ /// 3D specialization.
+ const T &operator()(int i0, int i1, int i2) const {
+ return *(Data() + Offset(i0, i1, i2));
+ }
+
+ /// True if index is inside array.
+ bool Contains(const Index &index) const {
+ for (int i = 0; i < N; ++i)
+ if (index(i) < 0 || index(i) >= Shape(i))
+ return false;
+ return true;
+ }
+
+ /// 1D specialization.
+ bool Contains(int i0) const {
+ return 0 <= i0 && i0 < Shape(0);
+ }
+
+ /// 2D specialization.
+ bool Contains(int i0, int i1) const {
+ return 0 <= i0 && i0 < Shape(0)
+ && 0 <= i1 && i1 < Shape(1);
+ }
+
+ /// 3D specialization.
+ bool Contains(int i0, int i1, int i2) const {
+ return 0 <= i0 && i0 < Shape(0)
+ && 0 <= i1 && i1 < Shape(1)
+ && 0 <= i2 && i2 < Shape(2);
+ }
+
+ bool operator==(const ArrayND<T, N> &other) const {
+ if (shape_ != other.shape_) return false;
+ if (strides_ != other.strides_) return false;
+ for (int i = 0; i < Size(); ++i) {
+ if (this->Data()[i] != other.Data()[i])
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=(const ArrayND<T, N> &other) const {
+ return !(*this == other);
+ }
+
+ ArrayND<T, N> operator*(const ArrayND<T, N> &other) const {
+ assert(Shape() = other.Shape());
+ ArrayND<T, N> res;
+ res.ResizeLike(*this);
+ for (int i = 0; i < res.Size(); ++i) {
+ res.Data()[i] = Data()[i] * other.Data()[i];
+ }
+ return res;
+ }
+
+ protected:
+ /// The number of element in each dimension.
+ Index shape_;
+
+ /// How to jump to neighbors in each dimension.
+ Index strides_;
+
+ /// Pointer to the first element of the array.
+ T *data_;
+
+ /// Flag if this Array either own or reference the data
+ bool own_data_;
+};
+
+/// 3D array (row, column, channel).
+template <typename T>
+class Array3D : public ArrayND<T, 3> {
+ typedef ArrayND<T, 3> Base;
+ public:
+ Array3D()
+ : Base() {
+ }
+ Array3D(int height, int width, int depth = 1)
+ : Base(height, width, depth) {
+ }
+ Array3D(T* data, int height, int width, int depth = 1)
+ : Base(data, height, width, depth) {
+ }
+
+ void Resize(int height, int width, int depth = 1) {
+ Base::Resize(height, width, depth);
+ }
+
+ int Height() const {
+ return Base::Shape(0);
+ }
+ int Width() const {
+ return Base::Shape(1);
+ }
+ int Depth() const {
+ return Base::Shape(2);
+ }
+
+ // Match Eigen2's API so that Array3D's and Mat*'s can work together via
+ // template magic.
+ int rows() const { return Height(); }
+ int cols() const { return Width(); }
+ int depth() const { return Depth(); }
+
+ int Get_Step() const { return Width()*Depth(); }
+
+ /// Enable accessing with 2 indices for grayscale images.
+ T &operator()(int i0, int i1, int i2 = 0) {
+ assert(0 <= i0 && i0 < Height());
+ assert(0 <= i1 && i1 < Width());
+ return Base::operator()(i0, i1, i2);
+ }
+ const T &operator()(int i0, int i1, int i2 = 0) const {
+ assert(0 <= i0 && i0 < Height());
+ assert(0 <= i1 && i1 < Width());
+ return Base::operator()(i0, i1, i2);
+ }
+};
+
+typedef Array3D<unsigned char> Array3Du;
+typedef Array3D<unsigned int> Array3Dui;
+typedef Array3D<int> Array3Di;
+typedef Array3D<float> Array3Df;
+typedef Array3D<short> Array3Ds;
+
+void SplitChannels(const Array3Df &input,
+ Array3Df *channel0,
+ Array3Df *channel1,
+ Array3Df *channel2);
+
+void PrintArray(const Array3Df &array);
+
+/** Convert a float array into a byte array by scaling values by 255* (max-min).
+ * where max and min are automatically detected
+ * (if automatic_range_detection = true)
+ * \note and TODO this automatic detection only works when the image contains
+ * at least one pixel of both bounds.
+ **/
+void FloatArrayToScaledByteArray(const Array3Df &float_array,
+ Array3Du *byte_array,
+ bool automatic_range_detection = false);
+
+//! Convert a byte array into a float array by dividing values by 255.
+void ByteArrayToScaledFloatArray(const Array3Du &byte_array,
+ Array3Df *float_array);
+
+template <typename AArrayType, typename BArrayType, typename CArrayType>
+void MultiplyElements(const AArrayType &a,
+ const BArrayType &b,
+ CArrayType *c) {
+ // This function does an element-wise multiply between
+ // the two Arrays A and B, and stores the result in C.
+ // A and B must have the same dimensions.
+ assert(a.Shape() == b.Shape());
+ c->ResizeLike(a);
+
+ // To perform the multiplcation, a "current" index into the N-dimensions of
+ // the A and B matrix specifies which elements are being multiplied.
+ typename CArrayType::Index index;
+
+ // The index starts at the maximum value for each dimension
+ const typename CArrayType::Index& cShape = c->Shape();
+ for ( int i = 0; i < CArrayType::Index::SIZE; ++i )
+ index(i) = cShape(i) - 1;
+
+ // After each multiplication, the highest-dimensional index is reduced.
+ // if this reduces it less than zero, it resets to its maximum value
+ // and decrements the index of the next lower dimension.
+ // This ripple-action continues until the entire new array has been
+ // calculated, indicated by dimension zero having a negative index.
+ while ( index(0) >= 0 ) {
+ (*c)(index) = a(index) * b(index);
+
+ int dimension = CArrayType::Index::SIZE - 1;
+ index(dimension) = index(dimension) - 1;
+ while ( dimension > 0 && index(dimension) < 0 ) {
+ index(dimension) = cShape(dimension) - 1;
+ index(dimension - 1) = index(dimension - 1) - 1;
+ --dimension;
+ }
+ }
+}
+
+template <typename TA, typename TB, typename TC>
+void MultiplyElements(const ArrayND<TA, 3> &a,
+ const ArrayND<TB, 3> &b,
+ ArrayND<TC, 3> *c) {
+ // Specialization for N==3
+ c->ResizeLike(a);
+ assert(a.Shape(0) == b.Shape(0));
+ assert(a.Shape(1) == b.Shape(1));
+ assert(a.Shape(2) == b.Shape(2));
+ for (int i = 0; i < a.Shape(0); ++i) {
+ for (int j = 0; j < a.Shape(1); ++j) {
+ for (int k = 0; k < a.Shape(2); ++k) {
+ (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k));
+ }
+ }
+ }
+}
+
+template <typename TA, typename TB, typename TC>
+void MultiplyElements(const Array3D<TA> &a,
+ const Array3D<TB> &b,
+ Array3D<TC> *c) {
+ // Specialization for N==3
+ c->ResizeLike(a);
+ assert(a.Shape(0) == b.Shape(0));
+ assert(a.Shape(1) == b.Shape(1));
+ assert(a.Shape(2) == b.Shape(2));
+ for (int i = 0; i < a.Shape(0); ++i) {
+ for (int j = 0; j < a.Shape(1); ++j) {
+ for (int k = 0; k < a.Shape(2); ++k) {
+ (*c)(i, j, k) = TC(a(i, j, k) * b(i, j, k));
+ }
+ }
+ }
+}
+
+} // namespace libmv
+
+#endif // LIBMV_IMAGE_ARRAY_ND_H
diff --git a/extern/libmv/libmv/image/array_nd_test.cc b/intern/libmv/libmv/image/array_nd_test.cc
index 313f21b60e9..313f21b60e9 100644
--- a/extern/libmv/libmv/image/array_nd_test.cc
+++ b/intern/libmv/libmv/image/array_nd_test.cc
diff --git a/extern/libmv/libmv/image/convolve.cc b/intern/libmv/libmv/image/convolve.cc
index 464043581d2..464043581d2 100644
--- a/extern/libmv/libmv/image/convolve.cc
+++ b/intern/libmv/libmv/image/convolve.cc
diff --git a/extern/libmv/libmv/image/convolve.h b/intern/libmv/libmv/image/convolve.h
index d3b6da9794b..d3b6da9794b 100644
--- a/extern/libmv/libmv/image/convolve.h
+++ b/intern/libmv/libmv/image/convolve.h
diff --git a/extern/libmv/libmv/image/convolve_test.cc b/intern/libmv/libmv/image/convolve_test.cc
index 0cdef8e1e72..0cdef8e1e72 100644
--- a/extern/libmv/libmv/image/convolve_test.cc
+++ b/intern/libmv/libmv/image/convolve_test.cc
diff --git a/extern/libmv/libmv/image/correlation.h b/intern/libmv/libmv/image/correlation.h
index c354f7e891e..c354f7e891e 100644
--- a/extern/libmv/libmv/image/correlation.h
+++ b/intern/libmv/libmv/image/correlation.h
diff --git a/extern/libmv/libmv/image/image.h b/intern/libmv/libmv/image/image.h
index e0f200a4c93..e0f200a4c93 100644
--- a/extern/libmv/libmv/image/image.h
+++ b/intern/libmv/libmv/image/image.h
diff --git a/extern/libmv/libmv/image/image_converter.h b/intern/libmv/libmv/image/image_converter.h
index b3a3fa2bf8c..b3a3fa2bf8c 100644
--- a/extern/libmv/libmv/image/image_converter.h
+++ b/intern/libmv/libmv/image/image_converter.h
diff --git a/extern/libmv/libmv/image/image_drawing.h b/intern/libmv/libmv/image/image_drawing.h
index f50e48b75a3..f50e48b75a3 100644
--- a/extern/libmv/libmv/image/image_drawing.h
+++ b/intern/libmv/libmv/image/image_drawing.h
diff --git a/extern/libmv/libmv/image/image_test.cc b/intern/libmv/libmv/image/image_test.cc
index 241f49f2244..241f49f2244 100644
--- a/extern/libmv/libmv/image/image_test.cc
+++ b/intern/libmv/libmv/image/image_test.cc
diff --git a/extern/libmv/libmv/image/sample.h b/intern/libmv/libmv/image/sample.h
index 24eb9ccd57d..24eb9ccd57d 100644
--- a/extern/libmv/libmv/image/sample.h
+++ b/intern/libmv/libmv/image/sample.h
diff --git a/extern/libmv/libmv/image/sample_test.cc b/intern/libmv/libmv/image/sample_test.cc
index c8a0ce470c2..c8a0ce470c2 100644
--- a/extern/libmv/libmv/image/sample_test.cc
+++ b/intern/libmv/libmv/image/sample_test.cc
diff --git a/extern/libmv/libmv/image/tuple.h b/intern/libmv/libmv/image/tuple.h
index c8dc36f2e18..c8dc36f2e18 100644
--- a/extern/libmv/libmv/image/tuple.h
+++ b/intern/libmv/libmv/image/tuple.h
diff --git a/extern/libmv/libmv/image/tuple_test.cc b/intern/libmv/libmv/image/tuple_test.cc
index df44e5638b5..df44e5638b5 100644
--- a/extern/libmv/libmv/image/tuple_test.cc
+++ b/intern/libmv/libmv/image/tuple_test.cc
diff --git a/extern/libmv/libmv/logging/logging.h b/intern/libmv/libmv/logging/logging.h
index 776d9d52f7a..776d9d52f7a 100644
--- a/extern/libmv/libmv/logging/logging.h
+++ b/intern/libmv/libmv/logging/logging.h
diff --git a/extern/libmv/libmv/multiview/conditioning.cc b/intern/libmv/libmv/multiview/conditioning.cc
index 0afbf119ea3..0afbf119ea3 100644
--- a/extern/libmv/libmv/multiview/conditioning.cc
+++ b/intern/libmv/libmv/multiview/conditioning.cc
diff --git a/extern/libmv/libmv/multiview/conditioning.h b/intern/libmv/libmv/multiview/conditioning.h
index 8f3e3a76070..8f3e3a76070 100644
--- a/extern/libmv/libmv/multiview/conditioning.h
+++ b/intern/libmv/libmv/multiview/conditioning.h
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/intern/libmv/libmv/multiview/euclidean_resection.cc
index 245b027fb7c..245b027fb7c 100644
--- a/extern/libmv/libmv/multiview/euclidean_resection.cc
+++ b/intern/libmv/libmv/multiview/euclidean_resection.cc
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.h b/intern/libmv/libmv/multiview/euclidean_resection.h
index 28eae92611c..28eae92611c 100644
--- a/extern/libmv/libmv/multiview/euclidean_resection.h
+++ b/intern/libmv/libmv/multiview/euclidean_resection.h
diff --git a/intern/libmv/libmv/multiview/euclidean_resection_test.cc b/intern/libmv/libmv/multiview/euclidean_resection_test.cc
new file mode 100644
index 00000000000..378837d3d2d
--- /dev/null
+++ b/intern/libmv/libmv/multiview/euclidean_resection_test.cc
@@ -0,0 +1,237 @@
+// Copyright (c) 2009 libmv authors.
+//
+// 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.
+
+#include "libmv/multiview/euclidean_resection.h"
+#include "libmv/numeric/numeric.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/projection.h"
+#include "testing/testing.h"
+
+using namespace libmv::euclidean_resection;
+using namespace libmv;
+
+// Generates all necessary inputs and expected outputs for EuclideanResection.
+static void CreateCameraSystem(const Mat3& KK,
+ const Mat3X& x_image,
+ const Vec& X_distances,
+ const Mat3& R_input,
+ const Vec3& T_input,
+ Mat2X *x_camera,
+ Mat3X *X_world,
+ Mat3 *R_expected,
+ Vec3 *T_expected) {
+ int num_points = x_image.cols();
+
+ Mat3X x_unit_cam(3, num_points);
+ x_unit_cam = KK.inverse() * x_image;
+
+ // Create normalized camera coordinates to be used as an input to the PnP
+ // function, instead of using NormalizeColumnVectors(&x_unit_cam).
+ *x_camera = x_unit_cam.block(0, 0, 2, num_points);
+ for (int i = 0; i < num_points; ++i) {
+ x_unit_cam.col(i).normalize();
+ }
+
+ // Create the 3D points in the camera system.
+ Mat X_camera(3, num_points);
+ for (int i = 0; i < num_points; ++i) {
+ X_camera.col(i) = X_distances(i) * x_unit_cam.col(i);
+ }
+
+ // Apply the transformation to the camera 3D points
+ Mat translation_matrix(3, num_points);
+ translation_matrix.row(0).setConstant(T_input(0));
+ translation_matrix.row(1).setConstant(T_input(1));
+ translation_matrix.row(2).setConstant(T_input(2));
+
+ *X_world = R_input * X_camera + translation_matrix;
+
+ // Create the expected result for comparison.
+ *R_expected = R_input.transpose();
+ *T_expected = *R_expected * (-T_input);
+};
+
+TEST(AbsoluteOrientation, QuaternionSolution) {
+ int num_points = 4;
+ Mat X;
+ Mat Xp;
+ X = 100 * Mat::Random(3, num_points);
+
+ // Create a random translation and rotation.
+ Mat3 R_input;
+ R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
+ * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
+ * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
+
+ Vec3 t_input;
+ t_input.setRandom();
+ t_input = 100 * t_input;
+
+ Mat translation_matrix(3, num_points);
+ translation_matrix.row(0).setConstant(t_input(0));
+ translation_matrix.row(1).setConstant(t_input(1));
+ translation_matrix.row(2).setConstant(t_input(2));
+
+ // Create the transformed 3D points Xp as Xp = R * X + t.
+ Xp = R_input * X + translation_matrix;
+
+ // Output variables.
+ Mat3 R;
+ Vec3 t;
+
+ AbsoluteOrientation(X, Xp, &R, &t);
+
+ EXPECT_MATRIX_NEAR(t, t_input, 1e-6);
+ EXPECT_MATRIX_NEAR(R, R_input, 1e-8);
+}
+
+TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
+ // In this test only the translation and rotation are random. The image
+ // points are selected from a real case and are well conditioned.
+ Vec2i image_dimensions;
+ image_dimensions << 1600, 1200;
+
+ Mat3 KK;
+ KK << 2796, 0, 804,
+ 0 , 2796, 641,
+ 0, 0, 1;
+
+ // The real image points.
+ int num_points = 4;
+ Mat3X x_image(3, num_points);
+ x_image << 1164.06, 734.948, 749.599, 430.727,
+ 681.386, 844.59, 496.315, 580.775,
+ 1, 1, 1, 1;
+
+
+ // A vector of the 4 distances to the 3D points.
+ Vec X_distances = 100 * Vec::Random(num_points).array().abs();
+
+ // Create the random camera motion R and t that resection should recover.
+ Mat3 R_input;
+ R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
+ * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
+ * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
+
+ Vec3 T_input;
+ T_input.setRandom();
+ T_input = 100 * T_input;
+
+ // Create the camera system, also getting the expected result of the
+ // transformation.
+ Mat3 R_expected;
+ Vec3 T_expected;
+ Mat3X X_world;
+ Mat2X x_camera;
+ CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
+ &x_camera, &X_world, &R_expected, &T_expected);
+
+ // Finally, run the code under test.
+ Mat3 R_output;
+ Vec3 T_output;
+ EuclideanResection(x_camera, X_world,
+ &R_output, &T_output,
+ RESECTION_ANSAR_DANIILIDIS);
+
+ EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
+ EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
+
+ // For now, the EPnP doesn't have a non-linear optimization step and so is
+ // not precise enough with only 4 points.
+ //
+ // TODO(jmichot): Reenable this test when there is nonlinear refinement.
+#if 0
+ R_output.setIdentity();
+ T_output.setZero();
+
+ EuclideanResection(x_camera, X_world,
+ &R_output, &T_output,
+ RESECTION_EPNP);
+
+ EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
+ EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/
+#endif
+}
+
+// TODO(jmichot): Reduce the code duplication here with the code above.
+TEST(EuclideanResection, Points6AllRandomInput) {
+ Mat3 KK;
+ KK << 2796, 0, 804,
+ 0 , 2796, 641,
+ 0, 0, 1;
+
+ // Create random image points for a 1600x1200 image.
+ int w = 1600;
+ int h = 1200;
+ int num_points = 6;
+ Mat3X x_image(3, num_points);
+ x_image.row(0) = w * Vec::Random(num_points).array().abs();
+ x_image.row(1) = h * Vec::Random(num_points).array().abs();
+ x_image.row(2).setOnes();
+
+ // Normalized camera coordinates to be used as an input to the PnP function.
+ Mat2X x_camera;
+ Vec X_distances = 100 * Vec::Random(num_points).array().abs();
+
+ // Create the random camera motion R and t that resection should recover.
+ Mat3 R_input;
+ R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
+ * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
+ * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
+
+ Vec3 T_input;
+ T_input.setRandom();
+ T_input = 100 * T_input;
+
+ // Create the camera system.
+ Mat3 R_expected;
+ Vec3 T_expected;
+ Mat3X X_world;
+ CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
+ &x_camera, &X_world, &R_expected, &T_expected);
+
+ // Test each of the resection methods.
+ {
+ Mat3 R_output;
+ Vec3 T_output;
+ EuclideanResection(x_camera, X_world,
+ &R_output, &T_output,
+ RESECTION_ANSAR_DANIILIDIS);
+ EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
+ EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
+ }
+ {
+ Mat3 R_output;
+ Vec3 T_output;
+ EuclideanResection(x_camera, X_world,
+ &R_output, &T_output,
+ RESECTION_EPNP);
+ EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
+ EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
+ }
+ {
+ Mat3 R_output;
+ Vec3 T_output;
+ EuclideanResection(x_image, X_world, KK,
+ &R_output, &T_output);
+ EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
+ EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
+ }
+}
diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/intern/libmv/libmv/multiview/fundamental.cc
index ea8594c8cc0..ea8594c8cc0 100644
--- a/extern/libmv/libmv/multiview/fundamental.cc
+++ b/intern/libmv/libmv/multiview/fundamental.cc
diff --git a/intern/libmv/libmv/multiview/fundamental.h b/intern/libmv/libmv/multiview/fundamental.h
new file mode 100644
index 00000000000..a6c7a6802fe
--- /dev/null
+++ b/intern/libmv/libmv/multiview/fundamental.h
@@ -0,0 +1,180 @@
+// Copyright (c) 2007, 2008, 2011 libmv authors.
+//
+// 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.
+
+#ifndef LIBMV_MULTIVIEW_FUNDAMENTAL_H_
+#define LIBMV_MULTIVIEW_FUNDAMENTAL_H_
+
+#include <vector>
+
+#include "libmv/numeric/numeric.h"
+
+namespace libmv {
+
+void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2);
+void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F);
+
+/**
+ * 7 points (minimal case, points coordinates must be normalized before):
+ */
+double FundamentalFrom7CorrespondencesLinear(const Mat &x1,
+ const Mat &x2,
+ std::vector<Mat3> *F);
+
+/**
+ * 7 points (points coordinates must be in image space):
+ */
+double FundamentalFromCorrespondences7Point(const Mat &x1,
+ const Mat &x2,
+ std::vector<Mat3> *F);
+
+/**
+ * 8 points (points coordinates must be in image space):
+ */
+double NormalizedEightPointSolver(const Mat &x1,
+ const Mat &x2,
+ Mat3 *F);
+
+/**
+ * Fundamental matrix utility function:
+ */
+void EnforceFundamentalRank2Constraint(Mat3 *F);
+
+void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized);
+
+/**
+ * Approximate squared reprojection errror.
+ *
+ * See page 287 of HZ equation 11.9. This avoids triangulating the point,
+ * relying only on the entries in F.
+ */
+double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+
+/**
+ * Calculates the sum of the distances from the points to the epipolar lines.
+ *
+ * See page 288 of HZ equation 11.10.
+ */
+double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2);
+
+/**
+ * Compute the relative camera motion between two cameras.
+ *
+ * Given the motion parameters of two cameras, computes the motion parameters
+ * of the second one assuming the first one to be at the origin.
+ * If T1 and T2 are the camera motions, the computed relative motion is
+ * T = T2 T1^{-1}
+ */
+void RelativeCameraMotion(const Mat3 &R1,
+ const Vec3 &t1,
+ const Mat3 &R2,
+ const Vec3 &t2,
+ Mat3 *R,
+ Vec3 *t);
+
+void EssentialFromFundamental(const Mat3 &F,
+ const Mat3 &K1,
+ const Mat3 &K2,
+ Mat3 *E);
+
+void FundamentalFromEssential(const Mat3 &E,
+ const Mat3 &K1,
+ const Mat3 &K2,
+ Mat3 *F);
+
+void EssentialFromRt(const Mat3 &R1,
+ const Vec3 &t1,
+ const Mat3 &R2,
+ const Vec3 &t2,
+ Mat3 *E);
+
+void MotionFromEssential(const Mat3 &E,
+ std::vector<Mat3> *Rs,
+ std::vector<Vec3> *ts);
+
+/**
+ * Choose one of the four possible motion solutions from an essential matrix.
+ *
+ * Decides the right solution by checking that the triangulation of a match
+ * x1--x2 lies in front of the cameras. See HZ 9.6 pag 259 (9.6.3 Geometrical
+ * interpretation of the 4 solutions)
+ *
+ * \return index of the right solution or -1 if no solution.
+ */
+int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs,
+ const std::vector<Vec3> &ts,
+ const Mat3 &K1,
+ const Vec2 &x1,
+ const Mat3 &K2,
+ const Vec2 &x2);
+
+bool MotionFromEssentialAndCorrespondence(const Mat3 &E,
+ const Mat3 &K1,
+ const Vec2 &x1,
+ const Mat3 &K2,
+ const Vec2 &x2,
+ Mat3 *R,
+ Vec3 *t);
+
+/**
+ * Find closest essential matrix E to fundamental F
+ */
+void FundamentalToEssential(const Mat3 &F, Mat3 *E);
+
+/**
+ * This structure contains options that controls how the fundamental
+ * estimation operates.
+ *
+ * Defaults should be suitable for a wide range of use cases, but
+ * better performance and accuracy might require tweaking/
+ */
+struct EstimateFundamentalOptions {
+ // Default constructor which sets up a options for generic usage.
+ EstimateFundamentalOptions(void);
+
+ // Maximal number of iterations for refinement step.
+ int max_num_iterations;
+
+ // Expected average of symmetric epipolar distance between
+ // actual destination points and original ones transformed by
+ // estimated fundamental matrix.
+ //
+ // Refinement will finish as soon as average of symmetric
+ // epipolar distance is less or equal to this value.
+ //
+ // This distance is measured in the same units as input points are.
+ double expected_average_symmetric_distance;
+};
+
+/**
+ * Fundamental transformation estimation.
+ *
+ * This function estimates the fundamental transformation from a list of 2D
+ * correspondences by doing algebraic estimation first followed with result
+ * refinement.
+ */
+bool EstimateFundamentalFromCorrespondences(
+ const Mat &x1,
+ const Mat &x2,
+ const EstimateFundamentalOptions &options,
+ Mat3 *F);
+
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_FUNDAMENTAL_H_
diff --git a/extern/libmv/libmv/multiview/fundamental_test.cc b/intern/libmv/libmv/multiview/fundamental_test.cc
index da0eb449b8f..da0eb449b8f 100644
--- a/extern/libmv/libmv/multiview/fundamental_test.cc
+++ b/intern/libmv/libmv/multiview/fundamental_test.cc
diff --git a/intern/libmv/libmv/multiview/homography.cc b/intern/libmv/libmv/multiview/homography.cc
new file mode 100644
index 00000000000..ce533a3ead2
--- /dev/null
+++ b/intern/libmv/libmv/multiview/homography.cc
@@ -0,0 +1,465 @@
+// Copyright (c) 2008, 2009 libmv authors.
+//
+// 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.
+
+#include "libmv/multiview/homography.h"
+
+#include "ceres/ceres.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/conditioning.h"
+#include "libmv/multiview/homography_parameterization.h"
+
+namespace libmv {
+/** 2D Homography transformation estimation in the case that points are in
+ * euclidean coordinates.
+ *
+ * x = H y
+ * x and y vector must have the same direction, we could write
+ * crossproduct(|x|, * H * |y| ) = |0|
+ *
+ * | 0 -1 x2| |a b c| |y1| |0|
+ * | 1 0 -x1| * |d e f| * |y2| = |0|
+ * |-x2 x1 0| |g h 1| |1 | |0|
+ *
+ * That gives :
+ *
+ * (-d+x2*g)*y1 + (-e+x2*h)*y2 + -f+x2 |0|
+ * (a-x1*g)*y1 + (b-x1*h)*y2 + c-x1 = |0|
+ * (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0|
+ */
+static bool Homography2DFromCorrespondencesLinearEuc(
+ const Mat &x1,
+ const Mat &x2,
+ Mat3 *H,
+ double expected_precision) {
+ assert(2 == x1.rows());
+ assert(4 <= x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ int n = x1.cols();
+ MatX8 L = Mat::Zero(n * 3, 8);
+ Mat b = Mat::Zero(n * 3, 1);
+ for (int i = 0; i < n; ++i) {
+ int j = 3 * i;
+ L(j, 0) = x1(0, i); // a
+ L(j, 1) = x1(1, i); // b
+ L(j, 2) = 1.0; // c
+ L(j, 6) = -x2(0, i) * x1(0, i); // g
+ L(j, 7) = -x2(0, i) * x1(1, i); // h
+ b(j, 0) = x2(0, i); // i
+
+ ++j;
+ L(j, 3) = x1(0, i); // d
+ L(j, 4) = x1(1, i); // e
+ L(j, 5) = 1.0; // f
+ L(j, 6) = -x2(1, i) * x1(0, i); // g
+ L(j, 7) = -x2(1, i) * x1(1, i); // h
+ b(j, 0) = x2(1, i); // i
+
+ // This ensures better stability
+ // TODO(julien) make a lite version without this 3rd set
+ ++j;
+ L(j, 0) = x2(1, i) * x1(0, i); // a
+ L(j, 1) = x2(1, i) * x1(1, i); // b
+ L(j, 2) = x2(1, i); // c
+ L(j, 3) = -x2(0, i) * x1(0, i); // d
+ L(j, 4) = -x2(0, i) * x1(1, i); // e
+ L(j, 5) = -x2(0, i); // f
+ }
+ // Solve Lx=B
+ Vec h = L.fullPivLu().solve(b);
+ Homography2DNormalizedParameterization<double>::To(h, H);
+ if ((L * h).isApprox(b, expected_precision)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/** 2D Homography transformation estimation in the case that points are in
+ * homogeneous coordinates.
+ *
+ * | 0 -x3 x2| |a b c| |y1| -x3*d+x2*g -x3*e+x2*h -x3*f+x2*1 |y1| (-x3*d+x2*g)*y1 (-x3*e+x2*h)*y2 (-x3*f+x2*1)*y3 |0|
+ * | x3 0 -x1| * |d e f| * |y2| = x3*a-x1*g x3*b-x1*h x3*c-x1*1 * |y2| = (x3*a-x1*g)*y1 (x3*b-x1*h)*y2 (x3*c-x1*1)*y3 = |0|
+ * |-x2 x1 0| |g h 1| |y3| -x2*a+x1*d -x2*b+x1*e -x2*c+x1*f |y3| (-x2*a+x1*d)*y1 (-x2*b+x1*e)*y2 (-x2*c+x1*f)*y3 |0|
+ * X = |a b c d e f g h|^t
+ */
+bool Homography2DFromCorrespondencesLinear(const Mat &x1,
+ const Mat &x2,
+ Mat3 *H,
+ double expected_precision) {
+ if (x1.rows() == 2) {
+ return Homography2DFromCorrespondencesLinearEuc(x1, x2, H,
+ expected_precision);
+ }
+ assert(3 == x1.rows());
+ assert(4 <= x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ const int x = 0;
+ const int y = 1;
+ const int w = 2;
+ int n = x1.cols();
+ MatX8 L = Mat::Zero(n * 3, 8);
+ Mat b = Mat::Zero(n * 3, 1);
+ for (int i = 0; i < n; ++i) {
+ int j = 3 * i;
+ L(j, 0) = x2(w, i) * x1(x, i); // a
+ L(j, 1) = x2(w, i) * x1(y, i); // b
+ L(j, 2) = x2(w, i) * x1(w, i); // c
+ L(j, 6) = -x2(x, i) * x1(x, i); // g
+ L(j, 7) = -x2(x, i) * x1(y, i); // h
+ b(j, 0) = x2(x, i) * x1(w, i);
+
+ ++j;
+ L(j, 3) = x2(w, i) * x1(x, i); // d
+ L(j, 4) = x2(w, i) * x1(y, i); // e
+ L(j, 5) = x2(w, i) * x1(w, i); // f
+ L(j, 6) = -x2(y, i) * x1(x, i); // g
+ L(j, 7) = -x2(y, i) * x1(y, i); // h
+ b(j, 0) = x2(y, i) * x1(w, i);
+
+ // This ensures better stability
+ ++j;
+ L(j, 0) = x2(y, i) * x1(x, i); // a
+ L(j, 1) = x2(y, i) * x1(y, i); // b
+ L(j, 2) = x2(y, i) * x1(w, i); // c
+ L(j, 3) = -x2(x, i) * x1(x, i); // d
+ L(j, 4) = -x2(x, i) * x1(y, i); // e
+ L(j, 5) = -x2(x, i) * x1(w, i); // f
+ }
+ // Solve Lx=B
+ Vec h = L.fullPivLu().solve(b);
+ if ((L * h).isApprox(b, expected_precision)) {
+ Homography2DNormalizedParameterization<double>::To(h, H);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Default settings for homography estimation which should be suitable
+// for a wide range of use cases.
+EstimateHomographyOptions::EstimateHomographyOptions(void) :
+ use_normalization(true),
+ max_num_iterations(50),
+ expected_average_symmetric_distance(1e-16) {
+}
+
+namespace {
+void GetNormalizedPoints(const Mat &original_points,
+ Mat *normalized_points,
+ Mat3 *normalization_matrix) {
+ IsotropicPreconditionerFromPoints(original_points, normalization_matrix);
+ ApplyTransformationToPoints(original_points,
+ *normalization_matrix,
+ normalized_points);
+}
+
+// Cost functor which computes symmetric geometric distance
+// used for homography matrix refinement.
+class HomographySymmetricGeometricCostFunctor {
+ public:
+ HomographySymmetricGeometricCostFunctor(const Vec2 &x,
+ const Vec2 &y)
+ : x_(x), y_(y) { }
+
+ template<typename T>
+ bool operator()(const T *homography_parameters, T *residuals) const {
+ typedef Eigen::Matrix<T, 3, 3> Mat3;
+ typedef Eigen::Matrix<T, 3, 1> Vec3;
+
+ Mat3 H(homography_parameters);
+
+ Vec3 x(T(x_(0)), T(x_(1)), T(1.0));
+ Vec3 y(T(y_(0)), T(y_(1)), T(1.0));
+
+ Vec3 H_x = H * x;
+ Vec3 Hinv_y = H.inverse() * y;
+
+ H_x /= H_x(2);
+ Hinv_y /= Hinv_y(2);
+
+ // This is a forward error.
+ residuals[0] = H_x(0) - T(y_(0));
+ residuals[1] = H_x(1) - T(y_(1));
+
+ // This is a backward error.
+ residuals[2] = Hinv_y(0) - T(x_(0));
+ residuals[3] = Hinv_y(1) - T(x_(1));
+
+ return true;
+ }
+
+ const Vec2 x_;
+ const Vec2 y_;
+};
+
+// Termination checking callback used for homography estimation.
+// It finished the minimization as soon as actual average of
+// symmetric geometric distance is less or equal to the expected
+// average value.
+class TerminationCheckingCallback : public ceres::IterationCallback {
+ public:
+ TerminationCheckingCallback(const Mat &x1, const Mat &x2,
+ const EstimateHomographyOptions &options,
+ Mat3 *H)
+ : options_(options), x1_(x1), x2_(x2), H_(H) {}
+
+ virtual ceres::CallbackReturnType operator()(
+ const ceres::IterationSummary& summary) {
+ // If the step wasn't successful, there's nothing to do.
+ if (!summary.step_is_successful) {
+ return ceres::SOLVER_CONTINUE;
+ }
+
+ // Calculate average of symmetric geometric distance.
+ double average_distance = 0.0;
+ for (int i = 0; i < x1_.cols(); i++) {
+ average_distance = SymmetricGeometricDistance(*H_,
+ x1_.col(i),
+ x2_.col(i));
+ }
+ average_distance /= x1_.cols();
+
+ if (average_distance <= options_.expected_average_symmetric_distance) {
+ return ceres::SOLVER_TERMINATE_SUCCESSFULLY;
+ }
+
+ return ceres::SOLVER_CONTINUE;
+ }
+
+ private:
+ const EstimateHomographyOptions &options_;
+ const Mat &x1_;
+ const Mat &x2_;
+ Mat3 *H_;
+};
+} // namespace
+
+/** 2D Homography transformation estimation in the case that points are in
+ * euclidean coordinates.
+ */
+bool EstimateHomography2DFromCorrespondences(
+ const Mat &x1,
+ const Mat &x2,
+ const EstimateHomographyOptions &options,
+ Mat3 *H) {
+ // TODO(sergey): Support homogenous coordinates, not just euclidean.
+
+ assert(2 == x1.rows());
+ assert(4 <= x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ Mat3 T1 = Mat3::Identity(),
+ T2 = Mat3::Identity();
+
+ // Step 1: Algebraic homography estimation.
+ Mat x1_normalized, x2_normalized;
+
+ if (options.use_normalization) {
+ LG << "Estimating homography using normalization.";
+ GetNormalizedPoints(x1, &x1_normalized, &T1);
+ GetNormalizedPoints(x2, &x2_normalized, &T2);
+ } else {
+ x1_normalized = x1;
+ x2_normalized = x2;
+ }
+
+ // Assume algebraic estiation always suceeds,
+ Homography2DFromCorrespondencesLinear(x1_normalized, x2_normalized, H);
+
+ // Denormalize the homography matrix.
+ if (options.use_normalization) {
+ *H = T2.inverse() * (*H) * T1;
+ }
+
+ LG << "Estimated matrix after algebraic estimation:\n" << *H;
+
+ // Step 2: Refine matrix using Ceres minimizer.
+ ceres::Problem problem;
+ for (int i = 0; i < x1.cols(); i++) {
+ HomographySymmetricGeometricCostFunctor
+ *homography_symmetric_geometric_cost_function =
+ new HomographySymmetricGeometricCostFunctor(x1.col(i),
+ x2.col(i));
+
+ problem.AddResidualBlock(
+ new ceres::AutoDiffCostFunction<
+ HomographySymmetricGeometricCostFunctor,
+ 4, // num_residuals
+ 9>(homography_symmetric_geometric_cost_function),
+ NULL,
+ H->data());
+ }
+
+ // Configure the solve.
+ ceres::Solver::Options solver_options;
+ solver_options.linear_solver_type = ceres::DENSE_QR;
+ solver_options.max_num_iterations = options.max_num_iterations;
+ solver_options.update_state_every_iteration = true;
+
+ // Terminate if the average symmetric distance is good enough.
+ TerminationCheckingCallback callback(x1, x2, options, H);
+ solver_options.callbacks.push_back(&callback);
+
+ // Run the solve.
+ ceres::Solver::Summary summary;
+ ceres::Solve(solver_options, &problem, &summary);
+
+ VLOG(1) << "Summary:\n" << summary.FullReport();
+
+ LG << "Final refined matrix:\n" << *H;
+
+ return summary.IsSolutionUsable();
+}
+
+/**
+ * x2 ~ A * x1
+ * x2^t * Hi * A *x1 = 0
+ * H1 = H2 = H3 =
+ * | 0 0 0 1| |-x2w| |0 0 0 0| | 0 | | 0 0 1 0| |-x2z|
+ * | 0 0 0 0| -> | 0 | |0 0 1 0| -> |-x2z| | 0 0 0 0| -> | 0 |
+ * | 0 0 0 0| | 0 | |0-1 0 0| | x2y| |-1 0 0 0| | x2x|
+ * |-1 0 0 0| | x2x| |0 0 0 0| | 0 | | 0 0 0 0| | 0 |
+ * H4 = H5 = H6 =
+ * |0 0 0 0| | 0 | | 0 1 0 0| |-x2y| |0 0 0 0| | 0 |
+ * |0 0 0 1| -> |-x2w| |-1 0 0 0| -> | x2x| |0 0 0 0| -> | 0 |
+ * |0 0 0 0| | 0 | | 0 0 0 0| | 0 | |0 0 0 1| |-x2w|
+ * |0-1 0 0| | x2y| | 0 0 0 0| | 0 | |0 0-1 0| | x2z|
+ * |a b c d|
+ * A = |e f g h|
+ * |i j k l|
+ * |m n o 1|
+ *
+ * x2^t * H1 * A *x1 = (-x2w*a +x2x*m )*x1x + (-x2w*b +x2x*n )*x1y + (-x2w*c +x2x*o )*x1z + (-x2w*d +x2x*1 )*x1w = 0
+ * x2^t * H2 * A *x1 = (-x2z*e +x2y*i )*x1x + (-x2z*f +x2y*j )*x1y + (-x2z*g +x2y*k )*x1z + (-x2z*h +x2y*l )*x1w = 0
+ * x2^t * H3 * A *x1 = (-x2z*a +x2x*i )*x1x + (-x2z*b +x2x*j )*x1y + (-x2z*c +x2x*k )*x1z + (-x2z*d +x2x*l )*x1w = 0
+ * x2^t * H4 * A *x1 = (-x2w*e +x2y*m )*x1x + (-x2w*f +x2y*n )*x1y + (-x2w*g +x2y*o )*x1z + (-x2w*h +x2y*1 )*x1w = 0
+ * x2^t * H5 * A *x1 = (-x2y*a +x2x*e )*x1x + (-x2y*b +x2x*f )*x1y + (-x2y*c +x2x*g )*x1z + (-x2y*d +x2x*h )*x1w = 0
+ * x2^t * H6 * A *x1 = (-x2w*i +x2z*m )*x1x + (-x2w*j +x2z*n )*x1y + (-x2w*k +x2z*o )*x1z + (-x2w*l +x2z*1 )*x1w = 0
+ *
+ * X = |a b c d e f g h i j k l m n o|^t
+*/
+bool Homography3DFromCorrespondencesLinear(const Mat &x1,
+ const Mat &x2,
+ Mat4 *H,
+ double expected_precision) {
+ assert(4 == x1.rows());
+ assert(5 <= x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+ const int x = 0;
+ const int y = 1;
+ const int z = 2;
+ const int w = 3;
+ int n = x1.cols();
+ MatX15 L = Mat::Zero(n * 6, 15);
+ Mat b = Mat::Zero(n * 6, 1);
+ for (int i = 0; i < n; ++i) {
+ int j = 6 * i;
+ L(j, 0) = -x2(w, i) * x1(x, i); // a
+ L(j, 1) = -x2(w, i) * x1(y, i); // b
+ L(j, 2) = -x2(w, i) * x1(z, i); // c
+ L(j, 3) = -x2(w, i) * x1(w, i); // d
+ L(j, 12) = x2(x, i) * x1(x, i); // m
+ L(j, 13) = x2(x, i) * x1(y, i); // n
+ L(j, 14) = x2(x, i) * x1(z, i); // o
+ b(j, 0) = -x2(x, i) * x1(w, i);
+
+ ++j;
+ L(j, 4) = -x2(z, i) * x1(x, i); // e
+ L(j, 5) = -x2(z, i) * x1(y, i); // f
+ L(j, 6) = -x2(z, i) * x1(z, i); // g
+ L(j, 7) = -x2(z, i) * x1(w, i); // h
+ L(j, 8) = x2(y, i) * x1(x, i); // i
+ L(j, 9) = x2(y, i) * x1(y, i); // j
+ L(j, 10) = x2(y, i) * x1(z, i); // k
+ L(j, 11) = x2(y, i) * x1(w, i); // l
+
+ ++j;
+ L(j, 0) = -x2(z, i) * x1(x, i); // a
+ L(j, 1) = -x2(z, i) * x1(y, i); // b
+ L(j, 2) = -x2(z, i) * x1(z, i); // c
+ L(j, 3) = -x2(z, i) * x1(w, i); // d
+ L(j, 8) = x2(x, i) * x1(x, i); // i
+ L(j, 9) = x2(x, i) * x1(y, i); // j
+ L(j, 10) = x2(x, i) * x1(z, i); // k
+ L(j, 11) = x2(x, i) * x1(w, i); // l
+
+ ++j;
+ L(j, 4) = -x2(w, i) * x1(x, i); // e
+ L(j, 5) = -x2(w, i) * x1(y, i); // f
+ L(j, 6) = -x2(w, i) * x1(z, i); // g
+ L(j, 7) = -x2(w, i) * x1(w, i); // h
+ L(j, 12) = x2(y, i) * x1(x, i); // m
+ L(j, 13) = x2(y, i) * x1(y, i); // n
+ L(j, 14) = x2(y, i) * x1(z, i); // o
+ b(j, 0) = -x2(y, i) * x1(w, i);
+
+ ++j;
+ L(j, 0) = -x2(y, i) * x1(x, i); // a
+ L(j, 1) = -x2(y, i) * x1(y, i); // b
+ L(j, 2) = -x2(y, i) * x1(z, i); // c
+ L(j, 3) = -x2(y, i) * x1(w, i); // d
+ L(j, 4) = x2(x, i) * x1(x, i); // e
+ L(j, 5) = x2(x, i) * x1(y, i); // f
+ L(j, 6) = x2(x, i) * x1(z, i); // g
+ L(j, 7) = x2(x, i) * x1(w, i); // h
+
+ ++j;
+ L(j, 8) = -x2(w, i) * x1(x, i); // i
+ L(j, 9) = -x2(w, i) * x1(y, i); // j
+ L(j, 10) = -x2(w, i) * x1(z, i); // k
+ L(j, 11) = -x2(w, i) * x1(w, i); // l
+ L(j, 12) = x2(z, i) * x1(x, i); // m
+ L(j, 13) = x2(z, i) * x1(y, i); // n
+ L(j, 14) = x2(z, i) * x1(z, i); // o
+ b(j, 0) = -x2(z, i) * x1(w, i);
+ }
+ // Solve Lx=B
+ Vec h = L.fullPivLu().solve(b);
+ if ((L * h).isApprox(b, expected_precision)) {
+ Homography3DNormalizedParameterization<double>::To(h, H);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+double SymmetricGeometricDistance(const Mat3 &H,
+ const Vec2 &x1,
+ const Vec2 &x2) {
+ Vec3 x(x1(0), x1(1), 1.0);
+ Vec3 y(x2(0), x2(1), 1.0);
+
+ Vec3 H_x = H * x;
+ Vec3 Hinv_y = H.inverse() * y;
+
+ H_x /= H_x(2);
+ Hinv_y /= Hinv_y(2);
+
+ return (H_x.head<2>() - y.head<2>()).squaredNorm() +
+ (Hinv_y.head<2>() - x.head<2>()).squaredNorm();
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/multiview/homography.h b/intern/libmv/libmv/multiview/homography.h
index 6d810c845ed..6d810c845ed 100644
--- a/extern/libmv/libmv/multiview/homography.h
+++ b/intern/libmv/libmv/multiview/homography.h
diff --git a/extern/libmv/libmv/multiview/homography_error.h b/intern/libmv/libmv/multiview/homography_error.h
index f8b9d45e73c..f8b9d45e73c 100644
--- a/extern/libmv/libmv/multiview/homography_error.h
+++ b/intern/libmv/libmv/multiview/homography_error.h
diff --git a/extern/libmv/libmv/multiview/homography_parameterization.h b/intern/libmv/libmv/multiview/homography_parameterization.h
index ca8fbd8066e..ca8fbd8066e 100644
--- a/extern/libmv/libmv/multiview/homography_parameterization.h
+++ b/intern/libmv/libmv/multiview/homography_parameterization.h
diff --git a/extern/libmv/libmv/multiview/homography_test.cc b/intern/libmv/libmv/multiview/homography_test.cc
index 8d7266e3d11..8d7266e3d11 100644
--- a/extern/libmv/libmv/multiview/homography_test.cc
+++ b/intern/libmv/libmv/multiview/homography_test.cc
diff --git a/extern/libmv/libmv/multiview/nviewtriangulation.h b/intern/libmv/libmv/multiview/nviewtriangulation.h
index f4614ab1a5c..f4614ab1a5c 100644
--- a/extern/libmv/libmv/multiview/nviewtriangulation.h
+++ b/intern/libmv/libmv/multiview/nviewtriangulation.h
diff --git a/extern/libmv/libmv/multiview/nviewtriangulation_test.cc b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc
index 5a4d8499753..5a4d8499753 100644
--- a/extern/libmv/libmv/multiview/nviewtriangulation_test.cc
+++ b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc
diff --git a/extern/libmv/libmv/multiview/panography.cc b/intern/libmv/libmv/multiview/panography.cc
index b62802948c4..b62802948c4 100644
--- a/extern/libmv/libmv/multiview/panography.cc
+++ b/intern/libmv/libmv/multiview/panography.cc
diff --git a/extern/libmv/libmv/multiview/panography.h b/intern/libmv/libmv/multiview/panography.h
index 6e87bd71304..6e87bd71304 100644
--- a/extern/libmv/libmv/multiview/panography.h
+++ b/intern/libmv/libmv/multiview/panography.h
diff --git a/extern/libmv/libmv/multiview/panography_kernel.cc b/intern/libmv/libmv/multiview/panography_kernel.cc
index 8fdc9e79aed..8fdc9e79aed 100644
--- a/extern/libmv/libmv/multiview/panography_kernel.cc
+++ b/intern/libmv/libmv/multiview/panography_kernel.cc
diff --git a/extern/libmv/libmv/multiview/panography_kernel.h b/intern/libmv/libmv/multiview/panography_kernel.h
index a6adbd54b20..a6adbd54b20 100644
--- a/extern/libmv/libmv/multiview/panography_kernel.h
+++ b/intern/libmv/libmv/multiview/panography_kernel.h
diff --git a/extern/libmv/libmv/multiview/panography_test.cc b/intern/libmv/libmv/multiview/panography_test.cc
index f6faf0f6022..f6faf0f6022 100644
--- a/extern/libmv/libmv/multiview/panography_test.cc
+++ b/intern/libmv/libmv/multiview/panography_test.cc
diff --git a/extern/libmv/libmv/multiview/projection.cc b/intern/libmv/libmv/multiview/projection.cc
index f8bece3de68..f8bece3de68 100644
--- a/extern/libmv/libmv/multiview/projection.cc
+++ b/intern/libmv/libmv/multiview/projection.cc
diff --git a/extern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h
index 3220bc2dbbc..3220bc2dbbc 100644
--- a/extern/libmv/libmv/multiview/projection.h
+++ b/intern/libmv/libmv/multiview/projection.h
diff --git a/intern/libmv/libmv/multiview/projection_test.cc b/intern/libmv/libmv/multiview/projection_test.cc
new file mode 100644
index 00000000000..460a186e7c4
--- /dev/null
+++ b/intern/libmv/libmv/multiview/projection_test.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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.
+
+#include <iostream>
+
+#include "libmv/multiview/projection.h"
+#include "libmv/numeric/numeric.h"
+#include "testing/testing.h"
+
+namespace {
+using namespace libmv;
+
+TEST(Projection, P_From_KRt) {
+ Mat3 K, Kp;
+ K << 10, 1, 30,
+ 0, 20, 40,
+ 0, 0, 1;
+
+ Mat3 R, Rp;
+ R << 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1;
+
+ Vec3 t, tp;
+ t << 1, 2, 3;
+
+ Mat34 P;
+ P_From_KRt(K, R, t, &P);
+ KRt_From_P(P, &Kp, &Rp, &tp);
+
+ EXPECT_MATRIX_NEAR(K, Kp, 1e-8);
+ EXPECT_MATRIX_NEAR(R, Rp, 1e-8);
+ EXPECT_MATRIX_NEAR(t, tp, 1e-8);
+
+ // TODO(keir): Change the code to ensure det(R) == 1, which is not currently
+ // the case. Also add a test for that here.
+}
+
+Vec4 GetRandomPoint() {
+ Vec4 X;
+ X.setRandom();
+ X(3) = 1;
+ return X;
+}
+
+TEST(Projection, isInFrontOfCamera) {
+ Mat34 P;
+ P << 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0;
+
+ Vec4 X_front = GetRandomPoint();
+ Vec4 X_back = GetRandomPoint();
+ X_front(2) = 10; // Any point in the positive Z direction
+ // where Z > 1 is infront of the camera.
+ X_back(2) = -10; // Any point int he negative Z dirstaion
+ // is behind the camera.
+
+ bool res_front = isInFrontOfCamera(P, X_front);
+ bool res_back = isInFrontOfCamera(P, X_back);
+
+ EXPECT_TRUE(res_front);
+ EXPECT_FALSE(res_back);
+}
+
+TEST(AutoCalibration, ProjectionShiftPrincipalPoint) {
+ Mat34 P1, P2;
+ P1 << 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0;
+ P2 << 1, 0, 3, 0,
+ 0, 1, 4, 0,
+ 0, 0, 1, 0;
+ Mat34 P1_computed, P2_computed;
+ ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed);
+ ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed);
+
+ EXPECT_MATRIX_EQ(P1, P1_computed);
+ EXPECT_MATRIX_EQ(P2, P2_computed);
+}
+
+TEST(AutoCalibration, ProjectionChangeAspectRatio) {
+ Mat34 P1, P2;
+ P1 << 1, 0, 3, 0,
+ 0, 1, 4, 0,
+ 0, 0, 1, 0;
+ P2 << 1, 0, 3, 0,
+ 0, 2, 4, 0,
+ 0, 0, 1, 0;
+ Mat34 P1_computed, P2_computed;
+ ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed);
+ ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed);
+
+ EXPECT_MATRIX_EQ(P1, P1_computed);
+ EXPECT_MATRIX_EQ(P2, P2_computed);
+}
+
+} // namespace
diff --git a/extern/libmv/libmv/multiview/resection.h b/intern/libmv/libmv/multiview/resection.h
index c142d6deeb2..c142d6deeb2 100644
--- a/extern/libmv/libmv/multiview/resection.h
+++ b/intern/libmv/libmv/multiview/resection.h
diff --git a/extern/libmv/libmv/multiview/resection_test.cc b/intern/libmv/libmv/multiview/resection_test.cc
index 368e2281cfa..368e2281cfa 100644
--- a/extern/libmv/libmv/multiview/resection_test.cc
+++ b/intern/libmv/libmv/multiview/resection_test.cc
diff --git a/extern/libmv/libmv/multiview/test_data_sets.cc b/intern/libmv/libmv/multiview/test_data_sets.cc
index 110bde6f762..110bde6f762 100644
--- a/extern/libmv/libmv/multiview/test_data_sets.cc
+++ b/intern/libmv/libmv/multiview/test_data_sets.cc
diff --git a/extern/libmv/libmv/multiview/test_data_sets.h b/intern/libmv/libmv/multiview/test_data_sets.h
index cf01663ca02..cf01663ca02 100644
--- a/extern/libmv/libmv/multiview/test_data_sets.h
+++ b/intern/libmv/libmv/multiview/test_data_sets.h
diff --git a/extern/libmv/libmv/multiview/triangulation.cc b/intern/libmv/libmv/multiview/triangulation.cc
index 4d146c8f21b..4d146c8f21b 100644
--- a/extern/libmv/libmv/multiview/triangulation.cc
+++ b/intern/libmv/libmv/multiview/triangulation.cc
diff --git a/extern/libmv/libmv/multiview/triangulation.h b/intern/libmv/libmv/multiview/triangulation.h
index be878890242..be878890242 100644
--- a/extern/libmv/libmv/multiview/triangulation.h
+++ b/intern/libmv/libmv/multiview/triangulation.h
diff --git a/extern/libmv/libmv/multiview/triangulation_test.cc b/intern/libmv/libmv/multiview/triangulation_test.cc
index 66d1ee25a62..66d1ee25a62 100644
--- a/extern/libmv/libmv/multiview/triangulation_test.cc
+++ b/intern/libmv/libmv/multiview/triangulation_test.cc
diff --git a/extern/libmv/libmv/multiview/two_view_kernel.h b/intern/libmv/libmv/multiview/two_view_kernel.h
index 7af0ed5ddab..7af0ed5ddab 100644
--- a/extern/libmv/libmv/multiview/two_view_kernel.h
+++ b/intern/libmv/libmv/multiview/two_view_kernel.h
diff --git a/extern/libmv/libmv/numeric/dogleg.h b/intern/libmv/libmv/numeric/dogleg.h
index bf6f996ddaf..bf6f996ddaf 100644
--- a/extern/libmv/libmv/numeric/dogleg.h
+++ b/intern/libmv/libmv/numeric/dogleg.h
diff --git a/extern/libmv/libmv/numeric/dogleg_test.cc b/intern/libmv/libmv/numeric/dogleg_test.cc
index 90c46c31672..90c46c31672 100644
--- a/extern/libmv/libmv/numeric/dogleg_test.cc
+++ b/intern/libmv/libmv/numeric/dogleg_test.cc
diff --git a/extern/libmv/libmv/numeric/function_derivative.h b/intern/libmv/libmv/numeric/function_derivative.h
index 9820885f04e..9820885f04e 100644
--- a/extern/libmv/libmv/numeric/function_derivative.h
+++ b/intern/libmv/libmv/numeric/function_derivative.h
diff --git a/extern/libmv/libmv/numeric/function_derivative_test.cc b/intern/libmv/libmv/numeric/function_derivative_test.cc
index 8d976d3e9a0..8d976d3e9a0 100644
--- a/extern/libmv/libmv/numeric/function_derivative_test.cc
+++ b/intern/libmv/libmv/numeric/function_derivative_test.cc
diff --git a/extern/libmv/libmv/numeric/levenberg_marquardt.h b/intern/libmv/libmv/numeric/levenberg_marquardt.h
index 2af9a62cf7b..2af9a62cf7b 100644
--- a/extern/libmv/libmv/numeric/levenberg_marquardt.h
+++ b/intern/libmv/libmv/numeric/levenberg_marquardt.h
diff --git a/extern/libmv/libmv/numeric/levenberg_marquardt_test.cc b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc
index fc3f9ebbb29..fc3f9ebbb29 100644
--- a/extern/libmv/libmv/numeric/levenberg_marquardt_test.cc
+++ b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc
diff --git a/extern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc
index 9007663c8e2..9007663c8e2 100644
--- a/extern/libmv/libmv/numeric/numeric.cc
+++ b/intern/libmv/libmv/numeric/numeric.cc
diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h
new file mode 100644
index 00000000000..20a4a29e5ba
--- /dev/null
+++ b/intern/libmv/libmv/numeric/numeric.h
@@ -0,0 +1,502 @@
+// Copyright (c) 2007, 2008_WIN32 libmv authors.
+//
+// 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.
+//
+// Matrix and vector classes, based on Eigen2.
+//
+// Avoid using Eigen2 classes directly; instead typedef them here.
+
+#ifndef LIBMV_NUMERIC_NUMERIC_H
+#define LIBMV_NUMERIC_NUMERIC_H
+
+#include <Eigen/Cholesky>
+#include <Eigen/Core>
+#include <Eigen/Eigenvalues>
+#include <Eigen/Geometry>
+#include <Eigen/LU>
+#include <Eigen/QR>
+#include <Eigen/SVD>
+
+#if !defined(__MINGW64__)
+# if defined(_WIN32) || defined(__APPLE__) || \
+ defined(__FreeBSD__) || defined(__NetBSD__)
+static void sincos(double x, double *sinx, double *cosx) {
+ *sinx = sin(x);
+ *cosx = cos(x);
+}
+# endif
+#endif // !__MINGW64__
+
+#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__)
+inline long lround(double d) {
+ return (long)(d>0 ? d+0.5 : ceil(d-0.5));
+}
+# if _MSC_VER < 1800
+inline int round(double d) {
+ return (d>0) ? int(d+0.5) : int(d-0.5);
+}
+# endif // _MSC_VER < 1800
+typedef unsigned int uint;
+#endif // _WIN32
+
+namespace libmv {
+
+typedef Eigen::MatrixXd Mat;
+typedef Eigen::VectorXd Vec;
+
+typedef Eigen::MatrixXf Matf;
+typedef Eigen::VectorXf Vecf;
+
+typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic> Matu;
+typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> Vecu;
+typedef Eigen::Matrix<unsigned int, 2, 1> Vec2u;
+
+typedef Eigen::Matrix<double, 2, 2> Mat2;
+typedef Eigen::Matrix<double, 2, 3> Mat23;
+typedef Eigen::Matrix<double, 3, 3> Mat3;
+typedef Eigen::Matrix<double, 3, 4> Mat34;
+typedef Eigen::Matrix<double, 3, 5> Mat35;
+typedef Eigen::Matrix<double, 4, 1> Mat41;
+typedef Eigen::Matrix<double, 4, 3> Mat43;
+typedef Eigen::Matrix<double, 4, 4> Mat4;
+typedef Eigen::Matrix<double, 4, 6> Mat46;
+typedef Eigen::Matrix<float, 2, 2> Mat2f;
+typedef Eigen::Matrix<float, 2, 3> Mat23f;
+typedef Eigen::Matrix<float, 3, 3> Mat3f;
+typedef Eigen::Matrix<float, 3, 4> Mat34f;
+typedef Eigen::Matrix<float, 3, 5> Mat35f;
+typedef Eigen::Matrix<float, 4, 3> Mat43f;
+typedef Eigen::Matrix<float, 4, 4> Mat4f;
+typedef Eigen::Matrix<float, 4, 6> Mat46f;
+
+typedef Eigen::Matrix<double, 3, 3, Eigen::RowMajor> RMat3;
+typedef Eigen::Matrix<double, 4, 4, Eigen::RowMajor> RMat4;
+
+typedef Eigen::Matrix<double, 2, Eigen::Dynamic> Mat2X;
+typedef Eigen::Matrix<double, 3, Eigen::Dynamic> Mat3X;
+typedef Eigen::Matrix<double, 4, Eigen::Dynamic> Mat4X;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 15> MatX15;
+typedef Eigen::Matrix<double, Eigen::Dynamic, 16> MatX16;
+
+typedef Eigen::Vector2d Vec2;
+typedef Eigen::Vector3d Vec3;
+typedef Eigen::Vector4d Vec4;
+typedef Eigen::Matrix<double, 5, 1> Vec5;
+typedef Eigen::Matrix<double, 6, 1> Vec6;
+typedef Eigen::Matrix<double, 7, 1> Vec7;
+typedef Eigen::Matrix<double, 8, 1> Vec8;
+typedef Eigen::Matrix<double, 9, 1> Vec9;
+typedef Eigen::Matrix<double, 10, 1> Vec10;
+typedef Eigen::Matrix<double, 11, 1> Vec11;
+typedef Eigen::Matrix<double, 12, 1> Vec12;
+typedef Eigen::Matrix<double, 13, 1> Vec13;
+typedef Eigen::Matrix<double, 14, 1> Vec14;
+typedef Eigen::Matrix<double, 15, 1> Vec15;
+typedef Eigen::Matrix<double, 16, 1> Vec16;
+typedef Eigen::Matrix<double, 17, 1> Vec17;
+typedef Eigen::Matrix<double, 18, 1> Vec18;
+typedef Eigen::Matrix<double, 19, 1> Vec19;
+typedef Eigen::Matrix<double, 20, 1> Vec20;
+
+typedef Eigen::Vector2f Vec2f;
+typedef Eigen::Vector3f Vec3f;
+typedef Eigen::Vector4f Vec4f;
+
+typedef Eigen::VectorXi VecXi;
+
+typedef Eigen::Vector2i Vec2i;
+typedef Eigen::Vector3i Vec3i;
+typedef Eigen::Vector4i Vec4i;
+
+typedef Eigen::Matrix<float,
+ Eigen::Dynamic,
+ Eigen::Dynamic,
+ Eigen::RowMajor> RMatf;
+
+typedef Eigen::NumTraits<double> EigenDouble;
+
+using Eigen::Map;
+using Eigen::Dynamic;
+using Eigen::Matrix;
+
+// Find U, s, and VT such that
+//
+// A = U * diag(s) * VT
+//
+template <typename TMat, typename TVec>
+inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) {
+ assert(0);
+}
+
+// Solve the linear system Ax = 0 via SVD. Store the solution in x, such that
+// ||x|| = 1.0. Return the singluar value corresponding to the solution.
+// Destroys A and resizes x if necessary.
+// TODO(maclean): Take the SVD of the transpose instead of this zero padding.
+template <typename TMat, typename TVec>
+double Nullspace(TMat *A, TVec *nullspace) {
+ Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
+ (*nullspace) = svd.matrixV().col(A->cols()-1);
+ if (A->rows() >= A->cols())
+ return svd.singularValues()(A->cols()-1);
+ else
+ return 0.0;
+}
+
+// Solve the linear system Ax = 0 via SVD. Finds two solutions, x1 and x2, such
+// that x1 is the best solution and x2 is the next best solution (in the L2
+// norm sense). Store the solution in x1 and x2, such that ||x|| = 1.0. Return
+// the singluar value corresponding to the solution x1. Destroys A and resizes
+// x if necessary.
+template <typename TMat, typename TVec1, typename TVec2>
+double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) {
+ Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV);
+ *x1 = svd.matrixV().col(A->cols() - 1);
+ *x2 = svd.matrixV().col(A->cols() - 2);
+ if (A->rows() >= A->cols())
+ return svd.singularValues()(A->cols()-1);
+ else
+ return 0.0;
+}
+
+// In place transpose for square matrices.
+template<class TA>
+inline void TransposeInPlace(TA *A) {
+ *A = A->transpose().eval();
+}
+
+template<typename TVec>
+inline double NormL1(const TVec &x) {
+ return x.array().abs().sum();
+}
+
+template<typename TVec>
+inline double NormL2(const TVec &x) {
+ return x.norm();
+}
+
+template<typename TVec>
+inline double NormLInfinity(const TVec &x) {
+ return x.array().abs().maxCoeff();
+}
+
+template<typename TVec>
+inline double DistanceL1(const TVec &x, const TVec &y) {
+ return (x - y).array().abs().sum();
+}
+
+template<typename TVec>
+inline double DistanceL2(const TVec &x, const TVec &y) {
+ return (x - y).norm();
+}
+template<typename TVec>
+inline double DistanceLInfinity(const TVec &x, const TVec &y) {
+ return (x - y).array().abs().maxCoeff();
+}
+
+// Normalize a vector with the L1 norm, and return the norm before it was
+// normalized.
+template<typename TVec>
+inline double NormalizeL1(TVec *x) {
+ double norm = NormL1(*x);
+ *x /= norm;
+ return norm;
+}
+
+// Normalize a vector with the L2 norm, and return the norm before it was
+// normalized.
+template<typename TVec>
+inline double NormalizeL2(TVec *x) {
+ double norm = NormL2(*x);
+ *x /= norm;
+ return norm;
+}
+
+// Normalize a vector with the L^Infinity norm, and return the norm before it
+// was normalized.
+template<typename TVec>
+inline double NormalizeLInfinity(TVec *x) {
+ double norm = NormLInfinity(*x);
+ *x /= norm;
+ return norm;
+}
+
+// Return the square of a number.
+template<typename T>
+inline T Square(T x) {
+ return x * x;
+}
+
+Mat3 RotationAroundX(double angle);
+Mat3 RotationAroundY(double angle);
+Mat3 RotationAroundZ(double angle);
+
+// Returns the rotation matrix of a rotation of angle |axis| around axis.
+// This is computed using the Rodrigues formula, see:
+// http://mathworld.wolfram.com/RodriguesRotationFormula.html
+Mat3 RotationRodrigues(const Vec3 &axis);
+
+// Make a rotation matrix such that center becomes the direction of the
+// positive z-axis, and y is oriented close to up.
+Mat3 LookAt(Vec3 center);
+
+// Return a diagonal matrix from a vector containg the diagonal values.
+template <typename TVec>
+inline Mat Diag(const TVec &x) {
+ return x.asDiagonal();
+}
+
+template<typename TMat>
+inline double FrobeniusNorm(const TMat &A) {
+ return sqrt(A.array().abs2().sum());
+}
+
+template<typename TMat>
+inline double FrobeniusDistance(const TMat &A, const TMat &B) {
+ return FrobeniusNorm(A - B);
+}
+
+inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) {
+ return x.cross(y);
+}
+
+Mat3 CrossProductMatrix(const Vec3 &x);
+
+void MeanAndVarianceAlongRows(const Mat &A,
+ Vec *mean_pointer,
+ Vec *variance_pointer);
+
+#if defined(_WIN32)
+ // TODO(bomboze): un-#if this for both platforms once tested under Windows
+ /* This solution was extensively discussed here
+ http://forum.kde.org/viewtopic.php?f=74&t=61940 */
+ #define SUM_OR_DYNAMIC(x, y) (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x+y)
+
+ template<typename Derived1, typename Derived2>
+ struct hstack_return {
+ typedef typename Derived1::Scalar Scalar;
+ enum {
+ RowsAtCompileTime = Derived1::RowsAtCompileTime,
+ ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime,
+ Derived2::ColsAtCompileTime),
+ Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
+ MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime,
+ Derived2::MaxColsAtCompileTime)
+ };
+ typedef Eigen::Matrix<Scalar,
+ RowsAtCompileTime,
+ ColsAtCompileTime,
+ Options,
+ MaxRowsAtCompileTime,
+ MaxColsAtCompileTime> type;
+ };
+
+ template<typename Derived1, typename Derived2>
+ typename hstack_return<Derived1, Derived2>::type
+ HStack(const Eigen::MatrixBase<Derived1>& lhs,
+ const Eigen::MatrixBase<Derived2>& rhs) {
+ typename hstack_return<Derived1, Derived2>::type res;
+ res.resize(lhs.rows(), lhs.cols()+rhs.cols());
+ res << lhs, rhs;
+ return res;
+ };
+
+
+ template<typename Derived1, typename Derived2>
+ struct vstack_return {
+ typedef typename Derived1::Scalar Scalar;
+ enum {
+ RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime,
+ Derived2::RowsAtCompileTime),
+ ColsAtCompileTime = Derived1::ColsAtCompileTime,
+ Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0,
+ MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime,
+ Derived2::MaxRowsAtCompileTime),
+ MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime
+ };
+ typedef Eigen::Matrix<Scalar,
+ RowsAtCompileTime,
+ ColsAtCompileTime,
+ Options,
+ MaxRowsAtCompileTime,
+ MaxColsAtCompileTime> type;
+ };
+
+ template<typename Derived1, typename Derived2>
+ typename vstack_return<Derived1, Derived2>::type
+ VStack(const Eigen::MatrixBase<Derived1>& lhs,
+ const Eigen::MatrixBase<Derived2>& rhs) {
+ typename vstack_return<Derived1, Derived2>::type res;
+ res.resize(lhs.rows()+rhs.rows(), lhs.cols());
+ res << lhs, rhs;
+ return res;
+ };
+
+
+#else // _WIN32
+
+ // Since it is not possible to typedef privately here, use a macro.
+ // Always take dynamic columns if either side is dynamic.
+ #define COLS \
+ ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \
+ ? Eigen::Dynamic : (ColsLeft + ColsRight))
+
+ // Same as above, except that prefer fixed size if either is fixed.
+ #define ROWS \
+ ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \
+ ? Eigen::Dynamic \
+ : ((RowsLeft == Eigen::Dynamic) \
+ ? RowsRight \
+ : RowsLeft \
+ ) \
+ )
+
+ // TODO(keir): Add a static assert if both rows are at compiletime.
+ template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+ Eigen::Matrix<T, ROWS, COLS>
+ HStack(const Eigen::Matrix<T, RowsLeft, ColsLeft> &left,
+ const Eigen::Matrix<T, RowsRight, ColsRight> &right) {
+ assert(left.rows() == right.rows());
+ int n = left.rows();
+ int m1 = left.cols();
+ int m2 = right.cols();
+
+ Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2);
+ stacked.block(0, 0, n, m1) = left;
+ stacked.block(0, m1, n, m2) = right;
+ return stacked;
+ }
+
+ // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but
+ // the duplication is worse.
+ // TODO(keir): Add a static assert if both rows are at compiletime.
+ // TODO(keir): Mail eigen list about making this work for general expressions
+ // rather than only matrix types.
+ template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight>
+ Eigen::Matrix<T, COLS, ROWS>
+ VStack(const Eigen::Matrix<T, ColsLeft, RowsLeft> &top,
+ const Eigen::Matrix<T, ColsRight, RowsRight> &bottom) {
+ assert(top.cols() == bottom.cols());
+ int n1 = top.rows();
+ int n2 = bottom.rows();
+ int m = top.cols();
+
+ Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m);
+ stacked.block(0, 0, n1, m) = top;
+ stacked.block(n1, 0, n2, m) = bottom;
+ return stacked;
+ }
+ #undef COLS
+ #undef ROWS
+#endif // _WIN32
+
+
+
+void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked);
+
+template<typename TTop, typename TBot, typename TStacked>
+void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) {
+ assert(top.cols() == bottom.cols());
+ int n1 = top.rows();
+ int n2 = bottom.rows();
+ int m = top.cols();
+
+ stacked->resize(n1 + n2, m);
+ stacked->block(0, 0, n1, m) = top;
+ stacked->block(n1, 0, n2, m) = bottom;
+}
+
+void MatrixColumn(const Mat &A, int i, Vec2 *v);
+void MatrixColumn(const Mat &A, int i, Vec3 *v);
+void MatrixColumn(const Mat &A, int i, Vec4 *v);
+
+template <typename TMat, typename TCols>
+TMat ExtractColumns(const TMat &A, const TCols &columns) {
+ TMat compressed(A.rows(), columns.size());
+ for (int i = 0; i < columns.size(); ++i) {
+ compressed.col(i) = A.col(columns[i]);
+ }
+ return compressed;
+}
+
+template <typename TMat, typename TDest>
+void reshape(const TMat &a, int rows, int cols, TDest *b) {
+ assert(a.rows()*a.cols() == rows*cols);
+ b->resize(rows, cols);
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ (*b)(i, j) = a[cols*i + j];
+ }
+ }
+}
+
+inline bool isnan(double i) {
+#ifdef WIN32
+ return _isnan(i) > 0;
+#else
+ return std::isnan(i);
+#endif
+}
+
+/// Ceil function that has the same behaviour for positive
+/// and negative values
+template <typename FloatType>
+FloatType ceil0(const FloatType& value) {
+ FloatType result = std::ceil(std::fabs(value));
+ return (value < 0.0) ? -result : result;
+}
+
+/// Returns the skew anti-symmetric matrix of a vector
+inline Mat3 SkewMat(const Vec3 &x) {
+ Mat3 skew;
+ skew << 0 , -x(2), x(1),
+ x(2), 0 , -x(0),
+ -x(1), x(0), 0;
+ return skew;
+}
+/// Returns the skew anti-symmetric matrix of a vector with only
+/// the first two (independent) lines
+inline Mat23 SkewMatMinimal(const Vec2 &x) {
+ Mat23 skew;
+ skew << 0, -1, x(1),
+ 1, 0, -x(0);
+ return skew;
+}
+
+/// Returns the rotaiton matrix built from given vector of euler angles
+inline Mat3 RotationFromEulerVector(Vec3 euler_vector) {
+ double theta = euler_vector.norm();
+ if (theta == 0.0) {
+ return Mat3::Identity();
+ }
+ Vec3 w = euler_vector / theta;
+ Mat3 w_hat = CrossProductMatrix(w);
+ return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta));
+}
+} // namespace libmv
+
+#endif // LIBMV_NUMERIC_NUMERIC_H
diff --git a/extern/libmv/libmv/numeric/numeric_test.cc b/intern/libmv/libmv/numeric/numeric_test.cc
index 0cdfaf33ab2..0cdfaf33ab2 100644
--- a/extern/libmv/libmv/numeric/numeric_test.cc
+++ b/intern/libmv/libmv/numeric/numeric_test.cc
diff --git a/extern/libmv/libmv/numeric/poly.cc b/intern/libmv/libmv/numeric/poly.cc
index 376403616c3..376403616c3 100644
--- a/extern/libmv/libmv/numeric/poly.cc
+++ b/intern/libmv/libmv/numeric/poly.cc
diff --git a/extern/libmv/libmv/numeric/poly.h b/intern/libmv/libmv/numeric/poly.h
index 76ba062d475..76ba062d475 100644
--- a/extern/libmv/libmv/numeric/poly.h
+++ b/intern/libmv/libmv/numeric/poly.h
diff --git a/intern/libmv/libmv/numeric/poly_test.cc b/intern/libmv/libmv/numeric/poly_test.cc
new file mode 100644
index 00000000000..69f887b416c
--- /dev/null
+++ b/intern/libmv/libmv/numeric/poly_test.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2007, 2008 libmv authors.
+//
+// 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.
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/poly.h"
+#include "testing/testing.h"
+
+using namespace libmv;
+
+namespace {
+
+// Find the polynomial coefficients of x in the equation
+//
+// (x - a)(x - b)(x - c) == 0
+//
+// by expanding to
+//
+// x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0.
+// = p = q = r
+void CoeffsForCubicZeros(double a, double b, double c,
+ double *p, double *q, double *r) {
+ *p = -(c + b + a);
+ *q = (a * b + (b + a) * c);
+ *r = -a * b * c;
+}
+
+TEST(Poly, SolveCubicPolynomial) {
+ double a, b, c, aa, bb, cc;
+ double p, q, r;
+
+ a = 1; b = 2; c = 3;
+ CoeffsForCubicZeros(a, b, c, &p, &q, &r);
+ ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
+ EXPECT_NEAR(a, aa, 1e-10);
+ EXPECT_NEAR(b, bb, 1e-10);
+ EXPECT_NEAR(c, cc, 1e-10);
+
+ a = 0; b = 1; c = 3;
+ CoeffsForCubicZeros(a, b, c, &p, &q, &r);
+ ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
+ EXPECT_NEAR(a, aa, 1e-10);
+ EXPECT_NEAR(b, bb, 1e-10);
+ EXPECT_NEAR(c, cc, 1e-10);
+
+ a = -10; b = 0; c = 1;
+ CoeffsForCubicZeros(a, b, c, &p, &q, &r);
+ ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
+ EXPECT_NEAR(a, aa, 1e-10);
+ EXPECT_NEAR(b, bb, 1e-10);
+ EXPECT_NEAR(c, cc, 1e-10);
+
+ a = -8; b = 1; c = 3;
+ CoeffsForCubicZeros(a, b, c, &p, &q, &r);
+ ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
+ EXPECT_NEAR(a, aa, 1e-10);
+ EXPECT_NEAR(b, bb, 1e-10);
+ EXPECT_NEAR(c, cc, 1e-10);
+
+ a = 28; b = 28; c = 105;
+ CoeffsForCubicZeros(a, b, c, &p, &q, &r);
+ ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
+ EXPECT_NEAR(a, aa, 1e-10);
+ EXPECT_NEAR(b, bb, 1e-10);
+ EXPECT_NEAR(c, cc, 1e-10);
+}
+} // namespace
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc
index e61650fb371..e61650fb371 100644
--- a/extern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.h b/intern/libmv/libmv/simple_pipeline/bundle.h
index 781bd8476fe..781bd8476fe 100644
--- a/extern/libmv/libmv/simple_pipeline/bundle.h
+++ b/intern/libmv/libmv/simple_pipeline/bundle.h
diff --git a/extern/libmv/libmv/simple_pipeline/callbacks.h b/intern/libmv/libmv/simple_pipeline/callbacks.h
index 58f7b0d3cc9..58f7b0d3cc9 100644
--- a/extern/libmv/libmv/simple_pipeline/callbacks.h
+++ b/intern/libmv/libmv/simple_pipeline/callbacks.h
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
index 5e4e07b3c4c..5e4e07b3c4c 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
index 6a3ade81089..6a3ade81089 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h
index 97abee7ab01..97abee7ab01 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
index 96d35a29ef8..96d35a29ef8 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
diff --git a/extern/libmv/libmv/simple_pipeline/detect.cc b/intern/libmv/libmv/simple_pipeline/detect.cc
index 46599a4c49e..46599a4c49e 100644
--- a/extern/libmv/libmv/simple_pipeline/detect.cc
+++ b/intern/libmv/libmv/simple_pipeline/detect.cc
diff --git a/extern/libmv/libmv/simple_pipeline/detect.h b/intern/libmv/libmv/simple_pipeline/detect.h
index 1035287bcf2..1035287bcf2 100644
--- a/extern/libmv/libmv/simple_pipeline/detect.h
+++ b/intern/libmv/libmv/simple_pipeline/detect.h
diff --git a/intern/libmv/libmv/simple_pipeline/detect_test.cc b/intern/libmv/libmv/simple_pipeline/detect_test.cc
new file mode 100644
index 00000000000..b226ad96595
--- /dev/null
+++ b/intern/libmv/libmv/simple_pipeline/detect_test.cc
@@ -0,0 +1,232 @@
+// Copyright (c) 2014 libmv authors.
+//
+// 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.
+
+#include "libmv/simple_pipeline/detect.h"
+
+#include "testing/testing.h"
+#include "libmv/logging/logging.h"
+
+namespace libmv {
+
+namespace {
+
+void PreformSinglePointTest(const DetectOptions &options) {
+ // Prepare the image.
+ FloatImage image(15, 15);
+ image.fill(1.0);
+ image(7, 7) = 0.0;
+
+ // Run the detector.
+ vector<Feature> detected_features;
+ Detect(image, options, &detected_features);
+
+ // Check detected features matches our expectations.
+ EXPECT_EQ(1, detected_features.size());
+ if (detected_features.size() == 1) {
+ Feature &feature = detected_features[0];
+ EXPECT_EQ(7, feature.x);
+ EXPECT_EQ(7, feature.y);
+ }
+}
+
+#if 0
+void PreformCheckerBoardTest(const DetectOptions &options) {
+ // Prepare the image.
+ FloatImage image(30, 30);
+ for (int y = 0; y < image.Height(); ++y) {
+ for (int x = 0; x < image.Width(); ++x) {
+ image(y, x) = (x / 10 + y / 10) % 2 ? 1.0 : 0.0;
+ }
+ }
+
+ // Run the detector.
+ vector<Feature> detected_features;
+ Detect(image, options, &detected_features);
+
+ // Check detected features matches our expectations.
+
+ // We expect here only corners of a center square to be
+ // considered a feature points.
+ EXPECT_EQ(4, detected_features.size());
+
+ // We don't know which side of the corner detector will choose,
+ // so what we're checking here is that detected feature is from
+ // any side of the corner.
+ //
+ // This doesn't check whether there're multiple features which
+ // are placed on different sides of the same corner. The way we
+ // deal with this is requiring min_distance to be greater than 2px.
+ for (int i = 0; i < detected_features.size(); ++i) {
+ Feature &feature = detected_features[i];
+ int rounded_x = ((feature.x + 1) / 10) * 10,
+ rounded_y = ((feature.y + 1) / 10) * 10;
+ EXPECT_LE(1, std::abs(feature.x - rounded_x));
+ EXPECT_LE(1, std::abs(feature.y - rounded_y));
+ }
+}
+#endif
+
+void CheckExpectedFeatures(const vector<Feature> &detected_features,
+ const vector<Feature> &expected_features) {
+ EXPECT_EQ(expected_features.size(), detected_features.size());
+
+ // That's unsafe to iterate over vectors when their lengths
+ // doesn't match. And it doesn't make any sense actually since
+ // the test will already be considered failed here.
+ if (expected_features.size() != detected_features.size()) {
+ return;
+ }
+
+ for (int i = 0; i < expected_features.size(); ++i) {
+ const Feature &extected_feature = expected_features[i];
+ bool found = false;
+ for (int j = 0; j < detected_features.size(); ++j) {
+ const Feature &detected_feature = detected_features[j];
+ if (extected_feature.x == detected_feature.x &&
+ extected_feature.y == detected_feature.y) {
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+ }
+}
+
+void PreformSingleTriangleTest(const DetectOptions &options) {
+ // Prepare the image.
+ FloatImage image(15, 21);
+ image.fill(1.0);
+
+ int vertex_x = 10, vertex_y = 5;
+ for (int i = 0; i < 6; ++i) {
+ int current_x = vertex_x - i,
+ current_y = vertex_y + i;
+ for (int j = 0; j < i * 2 + 1; ++j, ++current_x) {
+ image(current_y, current_x) = 0.0;
+ }
+ }
+
+ // Run the detector.
+ vector<Feature> detected_features;
+ Detect(image, options, &detected_features);
+
+ // Check detected features matches our expectations.
+ vector<Feature> expected_features;
+ expected_features.push_back(Feature(6, 10));
+ expected_features.push_back(Feature(14, 10));
+ expected_features.push_back(Feature(10, 6));
+
+ CheckExpectedFeatures(detected_features, expected_features);
+}
+
+} // namespace
+
+#ifndef LIBMV_NO_FAST_DETECTOR
+TEST(Detect, FASTSinglePointTest) {
+ DetectOptions options;
+ options.type = DetectOptions::FAST;
+ options.min_distance = 0;
+ options.fast_min_trackness = 1;
+
+ PreformSinglePointTest(options);
+}
+#endif // LIBMV_NO_FAST_DETECTOR
+
+#if 0
+// TODO(sergey): FAST doesn't detect checker board corners, but should it?
+TEST(Detect, FASTCheckerBoardTest) {
+ DetectOptions options;
+ options.type = DetectOptions::FAST;
+ options.min_distance = 0;
+ options.fast_min_trackness = 1;
+
+ PreformCheckerBoardTest(options);
+}
+#endif
+
+#if 0
+// TODO(sergey): FAST doesn't detect triangle corners!
+TEST(Detect, FASTSingleTriangleTest) {
+ DetectOptions options;
+ options.type = DetectOptions::FAST;
+ options.margin = 3;
+ options.min_distance = 0;
+ options.fast_min_trackness = 2;
+
+ PreformSingleTriangleTest(options);
+}
+#endif
+
+#if 0
+// TODO(sergey): This doesn't actually detect single point,
+// but should it or it's expected that Moravec wouldn't consider
+// single point as feature?
+//
+// Uncomment this or remove as soon as we know answer for the
+// question.
+TEST(Detect, MoravecSinglePointTest) {
+ DetectOptions options;
+ options.type = DetectOptions::MORAVEC;
+ options.min_distance = 0;
+ options.moravec_max_count = 10;
+
+ PreformSinglePointTest(options);
+}
+
+// TODO(sergey): Moravec doesn't detect checker board corners, but should it?
+TEST(Detect, MoravecCheckerBoardTest) {
+ DetectOptions options;
+ options.type = DetectOptions::MORAVEC;
+ options.min_distance = 0;
+ options.moravec_max_count = 10;
+
+ PreformCheckerBoardTest(options);
+}
+#endif
+
+TEST(Detect, HarrisSinglePointTest) {
+ DetectOptions options;
+ options.type = DetectOptions::HARRIS;
+
+ // Set this to non-zero so image corners are not considered
+ // a feature points and avoid center point neighbors to be
+ // considered a features as well.
+ options.margin = 3;
+ options.min_distance = 3;
+
+ PreformSinglePointTest(options);
+}
+
+TEST(Detect, HarrisSingleTriangleTest) {
+ DetectOptions options;
+ options.type = DetectOptions::HARRIS;
+
+ options.margin = 3;
+ options.min_distance = 2;
+ options.harris_threshold = 1e-3;
+
+ PreformSingleTriangleTest(options);
+}
+
+// TODO(sergey): Add tests for margin option.
+
+// TODO(sergey): Add tests for min_distance option.
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
index 9b6dca2678a..9b6dca2678a 100644
--- a/extern/libmv/libmv/simple_pipeline/distortion_models.cc
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc
diff --git a/extern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h
index 4f8e2295a0e..4f8e2295a0e 100644
--- a/extern/libmv/libmv/simple_pipeline/distortion_models.h
+++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h
diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
index 7a086c375d5..7a086c375d5 100644
--- a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
+++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc
diff --git a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
index 744436246b0..744436246b0 100644
--- a/extern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
+++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h
diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/intern/libmv/libmv/simple_pipeline/intersect.cc
index ddb713684a4..ddb713684a4 100644
--- a/extern/libmv/libmv/simple_pipeline/intersect.cc
+++ b/intern/libmv/libmv/simple_pipeline/intersect.cc
diff --git a/extern/libmv/libmv/simple_pipeline/intersect.h b/intern/libmv/libmv/simple_pipeline/intersect.h
index 3a0ffa7418b..3a0ffa7418b 100644
--- a/extern/libmv/libmv/simple_pipeline/intersect.h
+++ b/intern/libmv/libmv/simple_pipeline/intersect.h
diff --git a/extern/libmv/libmv/simple_pipeline/intersect_test.cc b/intern/libmv/libmv/simple_pipeline/intersect_test.cc
index dd4fdc789af..dd4fdc789af 100644
--- a/extern/libmv/libmv/simple_pipeline/intersect_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/intersect_test.cc
diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc
index 241b5600505..241b5600505 100644
--- a/extern/libmv/libmv/simple_pipeline/keyframe_selection.cc
+++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc
diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection.h b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h
index aa3eeaf193d..aa3eeaf193d 100644
--- a/extern/libmv/libmv/simple_pipeline/keyframe_selection.h
+++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h
diff --git a/extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
index 9d88362cc88..9d88362cc88 100644
--- a/extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.cc b/intern/libmv/libmv/simple_pipeline/modal_solver.cc
new file mode 100644
index 00000000000..15e185eeda7
--- /dev/null
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver.cc
@@ -0,0 +1,251 @@
+// Copyright (c) 2015 libmv authors.
+//
+// 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.
+
+#include "libmv/simple_pipeline/modal_solver.h"
+
+#include <cstdio>
+
+#include "ceres/ceres.h"
+#include "ceres/rotation.h"
+#include "libmv/logging/logging.h"
+#include "libmv/multiview/panography.h"
+
+#ifdef _MSC_VER
+# define snprintf _snprintf
+#endif
+
+namespace libmv {
+
+namespace {
+void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) {
+ X(0) = marker.x;
+ X(1) = marker.y;
+ X(2) = 1.0;
+
+ X *= 5.0 / X.norm();
+}
+
+void ModalSolverLogProress(ProgressUpdateCallback *update_callback,
+ double progress) {
+ if (update_callback) {
+ char message[256];
+
+ snprintf(message, sizeof(message), "Solving progress %d%%",
+ (int)(progress * 100));
+
+ update_callback->invoke(progress, message);
+ }
+}
+
+struct ModalReprojectionError {
+ ModalReprojectionError(double observed_x,
+ double observed_y,
+ const double weight,
+ const Vec3 &bundle)
+ : observed_x_(observed_x), observed_y_(observed_y),
+ weight_(weight), bundle_(bundle) { }
+
+ // TODO(keir): This should support bundling focal length as well.
+ template <typename T>
+ bool operator()(const T* quaternion, T* residuals) const {
+ // Convert bundle position from double to T.
+ T X[3] = { T(bundle_(0)), T(bundle_(1)), T(bundle_(2)) };
+
+ // Compute the point position in camera coordinates: x = RX.
+ T x[3];
+
+ // This flips the sense of the quaternion, to adhere to Blender conventions.
+ T quaternion_inverse[4] = {
+ quaternion[0],
+ -quaternion[1],
+ -quaternion[2],
+ -quaternion[3],
+ };
+ ceres::QuaternionRotatePoint(quaternion_inverse, X, x);
+
+ // Compute normalized coordinates by dividing out the depth.
+ T xn = x[0] / x[2];
+ T yn = x[1] / x[2];
+
+ // The error is the difference between reprojected and observed marker
+ // positions, weighted by the passed in weight.
+ residuals[0] = T(weight_) * (xn - T(observed_x_));
+ residuals[1] = T(weight_) * (yn - T(observed_y_));
+
+ return true;
+ }
+
+ double observed_x_;
+ double observed_y_;
+ double weight_;
+ Vec3 bundle_;
+};
+} // namespace
+
+void ModalSolver(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction,
+ ProgressUpdateCallback *update_callback) {
+ int max_image = tracks.MaxImage();
+ int max_track = tracks.MaxTrack();
+
+ LG << "Max image: " << max_image;
+ LG << "Max track: " << max_track;
+
+ // For minimization we're using quaternions.
+ Vec3 zero_rotation = Vec3::Zero();
+ Vec4 quaternion;
+ ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0));
+
+ for (int image = 0; image <= max_image; ++image) {
+ vector<Marker> all_markers = tracks.MarkersInImage(image);
+
+ ModalSolverLogProress(update_callback, (float) image / max_image);
+
+ // Skip empty images without doing anything.
+ if (all_markers.size() == 0) {
+ LG << "Skipping image: " << image;
+ continue;
+ }
+
+ // STEP 1: Estimate rotation analytically.
+ Mat3 current_R;
+ ceres::QuaternionToRotation(&quaternion(0), &current_R(0, 0));
+
+ // Construct point cloud for current and previous images,
+ // using markers appear at current image for which we know
+ // 3D positions.
+ Mat x1, x2;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ Marker &marker = all_markers[i];
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ if (point) {
+ Vec3 X;
+ ProjectMarkerOnSphere(marker, X);
+
+ int last_column = x1.cols();
+ x1.conservativeResize(3, last_column + 1);
+ x2.conservativeResize(3, last_column + 1);
+
+ x1.col(last_column) = current_R * point->X;
+ x2.col(last_column) = X;
+ }
+ }
+
+ if (x1.cols() >= 2) {
+ Mat3 delta_R;
+
+ // Compute delta rotation matrix for two point clouds.
+ // Could be a bit confusing at first glance, but order
+ // of clouds is indeed so.
+ GetR_FixedCameraCenter(x2, x1, 1.0, &delta_R);
+
+ // Convert delta rotation form matrix to final image
+ // rotation stored in a quaternion
+ Vec3 delta_angle_axis;
+ ceres::RotationMatrixToAngleAxis(&delta_R(0, 0), &delta_angle_axis(0));
+
+ Vec3 current_angle_axis;
+ ceres::QuaternionToAngleAxis(&quaternion(0), &current_angle_axis(0));
+
+ Vec3 angle_axis = current_angle_axis + delta_angle_axis;
+
+ ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0));
+
+ LG << "Analytically computed quaternion "
+ << quaternion.transpose();
+ }
+
+ // STEP 2: Refine rotation with Ceres.
+ ceres::Problem problem;
+
+ ceres::LocalParameterization* quaternion_parameterization =
+ new ceres::QuaternionParameterization;
+
+ int num_residuals = 0;
+ for (int i = 0; i < all_markers.size(); ++i) {
+ Marker &marker = all_markers[i];
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+
+ if (point && marker.weight != 0.0) {
+ problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
+ ModalReprojectionError,
+ 2, /* num_residuals */
+ 4>(new ModalReprojectionError(marker.x,
+ marker.y,
+ marker.weight,
+ point->X)),
+ NULL,
+ &quaternion(0));
+ num_residuals++;
+
+ problem.SetParameterization(&quaternion(0),
+ quaternion_parameterization);
+ }
+ }
+
+ LG << "Number of residuals: " << num_residuals;
+
+ if (num_residuals) {
+ // Configure the solve.
+ ceres::Solver::Options solver_options;
+ solver_options.linear_solver_type = ceres::DENSE_QR;
+ solver_options.max_num_iterations = 50;
+ solver_options.update_state_every_iteration = true;
+ solver_options.gradient_tolerance = 1e-36;
+ solver_options.parameter_tolerance = 1e-36;
+ solver_options.function_tolerance = 1e-36;
+
+ // Run the solve.
+ ceres::Solver::Summary summary;
+ ceres::Solve(solver_options, &problem, &summary);
+
+ LG << "Summary:\n" << summary.FullReport();
+ LG << "Refined quaternion " << quaternion.transpose();
+ }
+
+ // Convert quaternion to rotation matrix.
+ Mat3 R;
+ ceres::QuaternionToRotation(&quaternion(0), &R(0, 0));
+ reconstruction->InsertCamera(image, R, Vec3::Zero());
+
+ // STEP 3: reproject all new markers appeared at image
+
+ // Check if there're new markers appeared on current image
+ // and reproject them on sphere to obtain 3D position/
+ for (int track = 0; track <= max_track; ++track) {
+ if (!reconstruction->PointForTrack(track)) {
+ Marker marker = tracks.MarkerInImageForTrack(image, track);
+
+ if (marker.image == image) {
+ // New track appeared on this image,
+ // project it's position onto sphere.
+
+ LG << "Projecting track " << track << " at image " << image;
+
+ Vec3 X;
+ ProjectMarkerOnSphere(marker, X);
+ reconstruction->InsertPoint(track, R.inverse() * X);
+ }
+ }
+ }
+ }
+}
+
+} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.h b/intern/libmv/libmv/simple_pipeline/modal_solver.h
index 9801fd21d81..9801fd21d81 100644
--- a/extern/libmv/libmv/simple_pipeline/modal_solver.h
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver.h
diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver_test.cc b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc
index 8b87acd95bb..8b87acd95bb 100644
--- a/extern/libmv/libmv/simple_pipeline/modal_solver_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc
diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/intern/libmv/libmv/simple_pipeline/pipeline.cc
index 6c8592baa00..6c8592baa00 100644
--- a/extern/libmv/libmv/simple_pipeline/pipeline.cc
+++ b/intern/libmv/libmv/simple_pipeline/pipeline.cc
diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.h b/intern/libmv/libmv/simple_pipeline/pipeline.h
index 4d1bd00c51f..4d1bd00c51f 100644
--- a/extern/libmv/libmv/simple_pipeline/pipeline.h
+++ b/intern/libmv/libmv/simple_pipeline/pipeline.h
diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.cc b/intern/libmv/libmv/simple_pipeline/reconstruction.cc
index 65e5dd27d5d..65e5dd27d5d 100644
--- a/extern/libmv/libmv/simple_pipeline/reconstruction.cc
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction.cc
diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction.h b/intern/libmv/libmv/simple_pipeline/reconstruction.h
index 947a0636476..947a0636476 100644
--- a/extern/libmv/libmv/simple_pipeline/reconstruction.h
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction.h
diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
index 40ac23be7a2..40ac23be7a2 100644
--- a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc
diff --git a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.h b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h
index f2349ff5146..f2349ff5146 100644
--- a/extern/libmv/libmv/simple_pipeline/reconstruction_scale.h
+++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h
diff --git a/extern/libmv/libmv/simple_pipeline/resect.cc b/intern/libmv/libmv/simple_pipeline/resect.cc
index e73fc44df2a..e73fc44df2a 100644
--- a/extern/libmv/libmv/simple_pipeline/resect.cc
+++ b/intern/libmv/libmv/simple_pipeline/resect.cc
diff --git a/extern/libmv/libmv/simple_pipeline/resect.h b/intern/libmv/libmv/simple_pipeline/resect.h
index 7ca3237437e..7ca3237437e 100644
--- a/extern/libmv/libmv/simple_pipeline/resect.h
+++ b/intern/libmv/libmv/simple_pipeline/resect.h
diff --git a/extern/libmv/libmv/simple_pipeline/resect_test.cc b/intern/libmv/libmv/simple_pipeline/resect_test.cc
index 811edd282d8..811edd282d8 100644
--- a/extern/libmv/libmv/simple_pipeline/resect_test.cc
+++ b/intern/libmv/libmv/simple_pipeline/resect_test.cc
diff --git a/extern/libmv/libmv/simple_pipeline/tracks.cc b/intern/libmv/libmv/simple_pipeline/tracks.cc
index d5d009708ba..d5d009708ba 100644
--- a/extern/libmv/libmv/simple_pipeline/tracks.cc
+++ b/intern/libmv/libmv/simple_pipeline/tracks.cc
diff --git a/extern/libmv/libmv/simple_pipeline/tracks.h b/intern/libmv/libmv/simple_pipeline/tracks.h
index a54a43659b7..a54a43659b7 100644
--- a/extern/libmv/libmv/simple_pipeline/tracks.h
+++ b/intern/libmv/libmv/simple_pipeline/tracks.h
diff --git a/extern/libmv/libmv/tracking/brute_region_tracker.cc b/intern/libmv/libmv/tracking/brute_region_tracker.cc
index 4a2aef63a96..4a2aef63a96 100644
--- a/extern/libmv/libmv/tracking/brute_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/brute_region_tracker.cc
diff --git a/extern/libmv/libmv/tracking/brute_region_tracker.h b/intern/libmv/libmv/tracking/brute_region_tracker.h
index a699c42ee92..a699c42ee92 100644
--- a/extern/libmv/libmv/tracking/brute_region_tracker.h
+++ b/intern/libmv/libmv/tracking/brute_region_tracker.h
diff --git a/extern/libmv/libmv/tracking/brute_region_tracker_test.cc b/intern/libmv/libmv/tracking/brute_region_tracker_test.cc
index 9014797c7cf..9014797c7cf 100644
--- a/extern/libmv/libmv/tracking/brute_region_tracker_test.cc
+++ b/intern/libmv/libmv/tracking/brute_region_tracker_test.cc
diff --git a/extern/libmv/libmv/tracking/hybrid_region_tracker.cc b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc
index ea3b0f5bfc0..ea3b0f5bfc0 100644
--- a/extern/libmv/libmv/tracking/hybrid_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc
diff --git a/extern/libmv/libmv/tracking/hybrid_region_tracker.h b/intern/libmv/libmv/tracking/hybrid_region_tracker.h
index 967d2afd1e5..967d2afd1e5 100644
--- a/extern/libmv/libmv/tracking/hybrid_region_tracker.h
+++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.h
diff --git a/extern/libmv/libmv/tracking/kalman_filter.h b/intern/libmv/libmv/tracking/kalman_filter.h
index 9841f0e912c..9841f0e912c 100644
--- a/extern/libmv/libmv/tracking/kalman_filter.h
+++ b/intern/libmv/libmv/tracking/kalman_filter.h
diff --git a/extern/libmv/libmv/tracking/klt_region_tracker.cc b/intern/libmv/libmv/tracking/klt_region_tracker.cc
index dbbf9f0b996..dbbf9f0b996 100644
--- a/extern/libmv/libmv/tracking/klt_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/klt_region_tracker.cc
diff --git a/extern/libmv/libmv/tracking/klt_region_tracker.h b/intern/libmv/libmv/tracking/klt_region_tracker.h
index 43977757084..43977757084 100644
--- a/extern/libmv/libmv/tracking/klt_region_tracker.h
+++ b/intern/libmv/libmv/tracking/klt_region_tracker.h
diff --git a/extern/libmv/libmv/tracking/klt_region_tracker_test.cc b/intern/libmv/libmv/tracking/klt_region_tracker_test.cc
index 07d5d6500e3..07d5d6500e3 100644
--- a/extern/libmv/libmv/tracking/klt_region_tracker_test.cc
+++ b/intern/libmv/libmv/tracking/klt_region_tracker_test.cc
diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc
index 4db501050f3..4db501050f3 100644
--- a/extern/libmv/libmv/tracking/pyramid_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc
diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker.h b/intern/libmv/libmv/tracking/pyramid_region_tracker.h
index 1f9675469f4..1f9675469f4 100644
--- a/extern/libmv/libmv/tracking/pyramid_region_tracker.h
+++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.h
diff --git a/extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
index d90a1012237..d90a1012237 100644
--- a/extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
+++ b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
diff --git a/extern/libmv/libmv/tracking/region_tracker.h b/intern/libmv/libmv/tracking/region_tracker.h
index 4f7574df1a3..4f7574df1a3 100644
--- a/extern/libmv/libmv/tracking/region_tracker.h
+++ b/intern/libmv/libmv/tracking/region_tracker.h
diff --git a/extern/libmv/libmv/tracking/retrack_region_tracker.cc b/intern/libmv/libmv/tracking/retrack_region_tracker.cc
index 4d230086d28..4d230086d28 100644
--- a/extern/libmv/libmv/tracking/retrack_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/retrack_region_tracker.cc
diff --git a/extern/libmv/libmv/tracking/retrack_region_tracker.h b/intern/libmv/libmv/tracking/retrack_region_tracker.h
index ab05f320834..ab05f320834 100644
--- a/extern/libmv/libmv/tracking/retrack_region_tracker.h
+++ b/intern/libmv/libmv/tracking/retrack_region_tracker.h
diff --git a/extern/libmv/libmv/tracking/track_region.cc b/intern/libmv/libmv/tracking/track_region.cc
index ef6dac65236..ef6dac65236 100644
--- a/extern/libmv/libmv/tracking/track_region.cc
+++ b/intern/libmv/libmv/tracking/track_region.cc
diff --git a/extern/libmv/libmv/tracking/track_region.h b/intern/libmv/libmv/tracking/track_region.h
index be1d8ef3e03..be1d8ef3e03 100644
--- a/extern/libmv/libmv/tracking/track_region.h
+++ b/intern/libmv/libmv/tracking/track_region.h
diff --git a/extern/libmv/libmv/tracking/trklt_region_tracker.cc b/intern/libmv/libmv/tracking/trklt_region_tracker.cc
index 05ef3d1d272..05ef3d1d272 100644
--- a/extern/libmv/libmv/tracking/trklt_region_tracker.cc
+++ b/intern/libmv/libmv/tracking/trklt_region_tracker.cc
diff --git a/extern/libmv/libmv/tracking/trklt_region_tracker.h b/intern/libmv/libmv/tracking/trklt_region_tracker.h
index 26d0621aa02..26d0621aa02 100644
--- a/extern/libmv/libmv/tracking/trklt_region_tracker.h
+++ b/intern/libmv/libmv/tracking/trklt_region_tracker.h
diff --git a/intern/libmv/mkfiles.sh b/intern/libmv/mkfiles.sh
new file mode 100755
index 00000000000..618070f0a81
--- /dev/null
+++ b/intern/libmv/mkfiles.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+find ./libmv/ -type f | sed -r 's/^\.\///' | sort > files.txt
+find ./third_party/ -mindepth 2 -type f | \
+ grep -v third_party/ceres | \
+ sed -r 's/^\.\///' | sort >> files.txt
diff --git a/extern/libmv/third_party/msinttypes/README.libmv b/intern/libmv/third_party/msinttypes/README.libmv
index 423f599b4ad..423f599b4ad 100644
--- a/extern/libmv/third_party/msinttypes/README.libmv
+++ b/intern/libmv/third_party/msinttypes/README.libmv
diff --git a/extern/libmv/third_party/msinttypes/inttypes.h b/intern/libmv/third_party/msinttypes/inttypes.h
index 0e8af69cb07..0e8af69cb07 100644
--- a/extern/libmv/third_party/msinttypes/inttypes.h
+++ b/intern/libmv/third_party/msinttypes/inttypes.h
diff --git a/extern/libmv/third_party/msinttypes/stdint.h b/intern/libmv/third_party/msinttypes/stdint.h
index 189ee34571c..189ee34571c 100644
--- a/extern/libmv/third_party/msinttypes/stdint.h
+++ b/intern/libmv/third_party/msinttypes/stdint.h
diff --git a/intern/locale/SConscript b/intern/locale/SConscript
deleted file mode 100644
index 02b4d6cda1b..00000000000
--- a/intern/locale/SConscript
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2012, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Bastien Montagne.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-sources = env.Glob('*.cpp')
-
-if env['OURPLATFORM'] in ['darwin']:
- # Cocoa code to read user locale on OSX
- sources.append('osx_user_locale.mm')
-
-incs = '.'
-defs = []
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
- incs += ' ' + env['BF_BOOST_INC']
-
-env.BlenderLib( 'bf_intern_locale', sources, Split(incs), defs, libtype=['intern','player'], priority=[10, 185])
-
-if env['WITH_BF_INTERNATIONAL']:
- import os
- from os.path import dirname
-
- def normpath(path):
- return os.path.abspath(os.path.normpath(path))
-
- # build directory
- source_dir = Dir('.').srcnode().path
- root_build_dir = normpath(env['BF_BUILDDIR'])
- root_source_dir = dirname(dirname(normpath(source_dir)))
- po_dir = os.path.join(root_source_dir, "release", "datafiles", "locale", "po")
- build_dir = os.path.join(root_build_dir, 'locale')
-
- if os.path.exists(po_dir):
- # create directory if needed
- if not os.path.exists(build_dir):
- os.makedirs(build_dir)
-
- msgfmt_tool = env.Clone()
- msgfmt_tool.Append(LINKFLAGS = env['PLATFORM_LINKFLAGS'])
-
- targetpath = root_build_dir + '/msgfmt'
-
- msgfmt_target = msgfmt_tool.Program(target = targetpath, source = ['msgfmt.cc'])
-
- locale = env.Clone()
-
- # dependencies
- dependencies = [msgfmt_target]
-
- # add command for each locale
- all_mo_files = []
- for f in os.listdir(po_dir):
- if not f.endswith(".po"):
- continue
-
- po_file = os.path.join(po_dir, f)
- mo_file = os.path.join(build_dir, os.path.splitext(f)[0] + ".mo")
-
- command = "\"%s\" \"%s\" \"%s\"" % (targetpath, po_file, mo_file)
-
- locale.Command(mo_file, po_file, command)
- locale.Depends(mo_file, dependencies)
-
- all_mo_files.append(mo_file)
-
- env.Depends("boost_locale_wrapper.cpp", all_mo_files)
diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index 5eb2f7fe9d9..0707c0dd3e3 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -114,10 +114,12 @@ const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
}
catch(std::bad_cast const &e) { /* if std::has_facet<char_message_facet>(l) == false, LC_ALL = "C" case */
// std::cout << "bl_locale_pgettext(" << msgid << "): " << e.what() << " \n";
+ (void)e;
return msgid;
}
catch(std::exception const &e) {
// std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n";
+ (void)e;
return msgid;
}
}
diff --git a/intern/memutil/CMakeLists.txt b/intern/memutil/CMakeLists.txt
index 3f9f8d6fe25..82e968853f4 100644
--- a/intern/memutil/CMakeLists.txt
+++ b/intern/memutil/CMakeLists.txt
@@ -39,11 +39,8 @@ set(SRC
MEM_Allocator.h
MEM_CacheLimiter.h
MEM_CacheLimiterC-Api.h
- MEM_NonCopyable.h
- MEM_RefCountPtr.h
MEM_RefCounted.h
MEM_RefCountedC-Api.h
- MEM_SmartPtr.h
)
blender_add_lib(bf_intern_memutil "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/memutil/MEM_NonCopyable.h b/intern/memutil/MEM_NonCopyable.h
deleted file mode 100644
index 9378ea7b69d..00000000000
--- a/intern/memutil/MEM_NonCopyable.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file memutil/MEM_NonCopyable.h
- * \ingroup memutil
- */
-
-/**
- * @file MEM_NonCopyable.h
- * Declaration of MEM_NonCopyable class.
- */
-
-#ifndef __MEM_NONCOPYABLE_H__
-#define __MEM_NONCOPYABLE_H__
-
-/**
- * Simple class that makes sure sub classes cannot
- * generate standard copy constructors.
- * If you want to make sure that your class does
- * not have any of these cheesy hidden constructors
- * inherit from this class.
- */
-
-class MEM_NonCopyable {
-protected :
-
- MEM_NonCopyable(
- ) {
- };
-
-private :
-
- MEM_NonCopyable (const MEM_NonCopyable *);
- MEM_NonCopyable (const MEM_NonCopyable &);
-};
-
-#endif
-
diff --git a/intern/memutil/MEM_RefCountPtr.h b/intern/memutil/MEM_RefCountPtr.h
deleted file mode 100644
index ea865eadd47..00000000000
--- a/intern/memutil/MEM_RefCountPtr.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file memutil/MEM_RefCountPtr.h
- * \ingroup memutil
- */
-
-/**
- * \file MEM_RefCountPtr.h
- * Declaration of MEM_RefCounted and MEM_RefCountable classes.
- * \author Laurence
- */
-
-#ifndef __MEM_REFCOUNTPTR_H__
-#define __MEM_REFCOUNTPTR_H__
-
-#include <stdlib.h> // for NULL !
-
-/**
- * \section MEM_RefCountable
- * This is a base class for reference countable objects.
- * If you want an object to be shared using a reference
- * counted system derrivce from this class. All subclasses
- * should insist that they are created on the heap, this
- * can be done by makeing all constructors private and
- * defining a static New() method that returns a ref counted
- * ptr to a new()ly allocated instance.
- *
- * \section Example subclass
- *
- * \code{.cpp}
- * class MySharedObject : public MEM_RefCountable {
- *
- * private :
- * MySharedObject() : MEM_RefCountable() { //class specific initialization};
- * MySharedObject(const MySharedObject &other) // not implemented
- * public :
- * static
- * MEM_RefCountPtr<MySharedObject>
- * New(
- * ) {
- * return MEM_RefCountPtr<MySharedObject>( new MySharedObject());
- * }
- *
- * // other member functions
- * };
- * \endcode
- *
- * Alternitively you may first wish to define a fully functional
- * class and then define a reference counting wrapper for this class.
- * This is useful when the base type can be used without reference
- * counting.
- *
- * E.g.
- *
- * \code{.cpp}
- * class UsefullClass {
- * private :
- * ...
- * public :
- *
- * UsefullClass()
- * UsefullMethod(...)
- * AnotherUsefullMethod(...)
- * };
- *
- * class RcUsefullClass : public UsefullClass, public MEM_RefCountable
- * {
- * private :
- * // Override base class public constructor --- forces
- * // use of New(...)
- * RcUsefullClass(...)
- * public :
- *
- * // Override each public constructor of UsefullClass with
- * // an equivalent static New method returning a MEM_RefCountPtr
- *
- * static
- * MEM_RefCountPtr<RcUsefullClass>
- * New(...) {
- * return MEM_RefCountPtr<RcUsefullClass> output(
- * new UsefullClass(...)
- * );
- * }
- *
- * // warning never call destructor directly allow ref counting
- * // mechanism to handle object lifetime.
- * ~RcUsefullClass();
- * };
- * \endcode
- *
- */
-
-class MEM_RefCountable {
-private :
-
- /**
- * The reference count!
- * We use mutable here because we would like to
- * share references of const objects!
- * Maybe should think about having decRef()
- * another value because we should not be deleting
- * non-const objects
- */
-
- mutable int m_count;
-
-protected :
-
- /**
- * Protected constructors
- * This class is not for direct instantiation. Sub classes
- * should only be allocated on the heap.
- */
-
- MEM_RefCountable (
- ) :
- m_count (0)
- {
- };
-
- MEM_RefCountable (
- const MEM_RefCountable &
- ) :
- m_count (0)
- {
- }
-
-public :
-
- void
- IncRef(
- ) const {
- m_count++;
- }
-
- int
- DecRef(
- ) {
- return (--m_count);
- }
-
- ~MEM_RefCountable(
- ) {
- //nothing to do
- }
-};
-
-/**
- * \section MEM_RefCountPtr
- */
-
-template
- < class T >
-class MEM_RefCountPtr {
-
-public :
-
- /**
- * Construction from reference - share ownership with
- * the right hand side.
- */
-
- MEM_RefCountPtr(
- const MEM_RefCountPtr &rhs
- ) : m_val (NULL) {
- ShareOwnership(rhs.m_val);
- }
-
- /**
- * Construction from ptr - this class shares
- * ownership of object val.
- */
-
- MEM_RefCountPtr(
- const T* val
- ) :
- m_val (NULL)
- {
- ShareOwnership(val);
- }
-
- /**
- * Default constructor
- */
-
- MEM_RefCountPtr(
- ) :
- m_val (NULL)
- {
- }
-
- /**
- * Type conversion from this class to the type
- * of a pointer to the template parameter.
- * This means you can pass an instance of this class
- * to a function expecting a ptr of type T.
- */
-
- operator T * () const {
- return m_val;
- }
-
-
- MEM_RefCountPtr & operator=(
- const MEM_RefCountPtr &rhs
- ) {
- if (this->m_val != rhs.m_val) {
- ReleaseOwnership();
- ShareOwnership(rhs.m_val);
- }
- return *this;
- }
-
- /**
- * Overload the operator -> so that it's possible to access
- * all the normal methods of the internal ptr.
- */
-
- T * operator->() const {
- return m_val;
- }
-
- /**
- * Returrn a reference to the shared object.
- */
-
- T&
- Ref(
- ) {
- return *m_val;
- }
-
-
- /**
- * Destructor - deletes object if it's ref count is zero.
- */
-
- ~MEM_RefCountPtr(
- ) {
- ReleaseOwnership();
- }
-
-private :
-
- /// The ptr owned by this class.
- T * m_val;
-
- void
- ShareOwnership(
- const T * val
- ) {
- if (val != NULL) {
- val->IncRef();
- }
- m_val = const_cast<T *>(val);
- }
-
- void
- ReleaseOwnership(
- ) {
- if (m_val) {
- if (m_val->DecRef() == 0) {
- delete(m_val);
- m_val = NULL;
- }
- }
- }
-
-};
-
-#endif
-
diff --git a/intern/memutil/MEM_SmartPtr.h b/intern/memutil/MEM_SmartPtr.h
deleted file mode 100644
index e0d7b81290f..00000000000
--- a/intern/memutil/MEM_SmartPtr.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file memutil/MEM_SmartPtr.h
- * \ingroup memutil
- */
-
-/**
- * @file MEM_SmartPtr.h
- * Declaration of MEM_RefCounted and MEM_RefCountable classes.
- * @author Laurence
- */
-
-#ifndef __MEM_SMARTPTR_H__
-#define __MEM_SMARTPTR_H__
-
-
-#include <stdlib.h> // for NULL !
-
-
-/**
- * \section MEM_SmartPtr
- * This class defines a smart pointer similar to that defined in
- * the Standard Template Library but without the painful get()
- * semantics to access the internal c style pointer.
- *
- * It is often useful to explicitly declare ownership of memory
- * allocated on the heap within class or function scope. This
- * class helps you to encapsulate this ownership within a value
- * type. When an instance of this class goes out of scope it
- * makes sure that any memory associated with it's internal pointer
- * is deleted. It can help to inform users of an aggregate class
- * that it owns instances of it's members and these instances
- * should not be shared. This is not reliably enforceable in C++
- * but this class attempts to make the 1-1 relationship clear.
- *
- * \section Example usage
- *
- * \code{.cpp}
- * class foo {
- * ...constructors accessors etc.
- * int x[1000];
- * }
- *
- * class bar {
- * public :
- * static
- * bar *
- * New(
- * ) {
- * MEM_SmartPtr<foo> afoo = new foo();
- * MEM_SmartPtr<bar> that = new bar();
- *
- * if (foo == NULL || that == NULL) return NULL;
- *
- * that->m_foo = afoo.Release();
- * return that.Release();
- * }
- *
- * ~bar() {
- * // smart ptr takes care of deletion
- * }
- * private :
- * MEM_SmartPtr<foo> m_foo;
- * }
- * \endcode
- *
- * You may also safely construct vectors of MEM_SmartPtrs and
- * have the vector own stuff you put into it.
- *
- * e.g.
- * \code{.cpp}
- * {
- * std::vector<MEM_SmartPtr<foo> > foo_vector;
- * foo_vector.push_back( new foo());
- * foo_vector.push_back( new foo());
- *
- * foo_vector[0]->bla();
- * } // foo_vector out of scope => heap memory freed for both foos
- * \endcode
- *
- * @warning this class should only be used for objects created
- * on the heap via the new function. It will not behave correctly
- * if you pass ptrs to objects created with new[] nor with
- * objects declared on the stack. Doing this is likely to crash
- * the program or lead to memory leaks.
- */
-
-template
- < class T >
-class MEM_SmartPtr {
-
-public :
-
- /**
- * Construction from reference - this class
- * always assumes ownership from the rhs.
- */
-
- MEM_SmartPtr(
- const MEM_SmartPtr &rhs
- ) {
- m_val = rhs.Release();
- }
-
- /**
- * Construction from ptr - this class always
- * assumes that it now owns the memory associated with the
- * ptr.
- */
-
- MEM_SmartPtr(
- T* val
- ) :
- m_val (val)
- {
- }
-
- /**
- * Defalut constructor
- */
-
- MEM_SmartPtr(
- ) :
- m_val (NULL)
- {
- }
-
- /**
- * Type conversion from this class to the type
- * of a pointer to the template parameter.
- * This means you can pass an instance of this class
- * to a function expecting a ptr of type T.
- */
-
- operator T * () const {
- return m_val;
- }
-
- /**
- * Return a reference to the internal ptr class.
- * Use with care when you now that the internal ptr
- * is not NULL!
- */
-
- T &
- Ref(
- ) const {
- return *m_val;
- }
-
- /**
- * Assignment operator - ownership is transferred from rhs to lhs.
- * There is an intenional side-effect of function of transferring
- * ownership from the const parameter rhs. This is to insure
- * the 1-1 relationship.
- * The object associated with this instance is deleted if it
- * is not the same as that contained in the rhs.
- */
-
- MEM_SmartPtr & operator=(
- const MEM_SmartPtr &rhs
- ) {
- if (this->m_val != rhs.m_val) {
- delete this->m_val;
- }
-
- this->m_val = rhs.Release();
- return *this;
- }
-
- /**
- * Overload the operator -> so that it's possible to access
- * all the normal methods of the internal ptr.
- */
-
- T * operator->() const {
- return m_val;
- }
-
- /**
- * Caller takes ownership of the object - the object will not
- * be deleted when the ptr goes out of scope.
- */
-
- T *
- Release(
- ) const {
- T* temp = m_val;
- (const_cast<MEM_SmartPtr *>(this))->m_val = NULL;
- return temp;
- }
-
- /**
- * Force destruction of the internal object.
- */
-
- void
- Delete(
- ) {
- delete (m_val);
- m_val = NULL;
- }
-
- /**
- * Destructor - deletes object if it exists
- */
-
- ~MEM_SmartPtr(
- ) {
- delete (m_val);
- }
-
-private :
-
- /// The ptr owned by this class.
- T * m_val;
-};
-
-#endif
-
diff --git a/intern/memutil/SConscript b/intern/memutil/SConscript
deleted file mode 100644
index 95fa39eb9c5..00000000000
--- a/intern/memutil/SConscript
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = '. ..'
-
-env.BlenderLib ('bf_intern_memutil', sources, Split(incs), [], libtype=['intern','player'], priority = [0,155] )
diff --git a/intern/mikktspace/CMakeLists.txt b/intern/mikktspace/CMakeLists.txt
index e48b0240f98..8abd9559358 100644
--- a/intern/mikktspace/CMakeLists.txt
+++ b/intern/mikktspace/CMakeLists.txt
@@ -23,6 +23,13 @@
#
# ***** END GPL LICENSE BLOCK *****
+if(CMAKE_COMPILER_IS_GNUCC)
+ remove_cc_flag(
+ "-Wshadow"
+ "-Werror=shadow"
+ )
+endif()
+
set(INC
.
)
diff --git a/intern/mikktspace/SConscript b/intern/mikktspace/SConscript
deleted file mode 100644
index fcb257a4ea0..00000000000
--- a/intern/mikktspace/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Daniel Genrich
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = ['mikktspace.c']
-
-incs = ''
-defs = ''
-
-env.BlenderLib ('bf_intern_mikktspace', sources, Split(incs), Split(defs), libtype=['intern'], priority=[100] )
diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c
index 822e5fbc44e..7e5861ea9ed 100644
--- a/intern/mikktspace/mikktspace.c
+++ b/intern/mikktspace/mikktspace.c
@@ -477,12 +477,14 @@ static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SM
if (vDim.y>vDim.x && vDim.y>vDim.z)
{
iChannel=1;
- fMin = vMin.y, fMax=vMax.y;
+ fMin = vMin.y;
+ fMax = vMax.y;
}
else if (vDim.z>vDim.x)
{
iChannel=2;
- fMin = vMin.z, fMax=vMax.z;
+ fMin = vMin.z;
+ fMax = vMax.z;
}
// make allocations
@@ -1660,7 +1662,8 @@ static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int
uSeed=uSeed+t+3;
// Random end
- iL=iLeft, iR=iRight;
+ iL = iLeft;
+ iR = iRight;
n = (iR-iL)+1;
assert(n>=0);
index = (int) (uSeed%n);
diff --git a/intern/moto/CMakeLists.txt b/intern/moto/CMakeLists.txt
index 8075c66b847..d17181c6809 100644
--- a/intern/moto/CMakeLists.txt
+++ b/intern/moto/CMakeLists.txt
@@ -36,7 +36,6 @@ set(SRC
intern/MT_CmMatrix4x4.cpp
intern/MT_Matrix3x3.cpp
intern/MT_Matrix4x4.cpp
- intern/MT_Plane3.cpp
intern/MT_Point3.cpp
intern/MT_Quaternion.cpp
intern/MT_Transform.cpp
@@ -45,14 +44,11 @@ set(SRC
intern/MT_Vector4.cpp
intern/MT_random.cpp
- include/GEN_List.h
- include/GEN_Map.h
include/MT_CmMatrix4x4.h
include/MT_Matrix3x3.h
include/MT_Matrix4x4.h
include/MT_MinMax.h
include/MT_Optimize.h
- include/MT_Plane3.h
include/MT_Point2.h
include/MT_Point3.h
include/MT_Quaternion.h
@@ -67,11 +63,9 @@ set(SRC
include/MT_Vector4.h
include/MT_assert.h
include/MT_random.h
- include/NM_Scalar.h
include/MT_Matrix3x3.inl
include/MT_Matrix4x4.inl
- include/MT_Plane3.inl
include/MT_Point2.inl
include/MT_Point3.inl
include/MT_Quaternion.inl
diff --git a/intern/moto/SConscript b/intern/moto/SConscript
deleted file mode 100644
index 34a0afe27f8..00000000000
--- a/intern/moto/SConscript
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = 'include'
-
-env.BlenderLib ('bf_intern_moto', sources, Split(incs), [], libtype=['intern','player'], priority = [130,95] )
diff --git a/intern/moto/include/GEN_List.h b/intern/moto/include/GEN_List.h
deleted file mode 100644
index 3aefe5e060c..00000000000
--- a/intern/moto/include/GEN_List.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file moto/include/GEN_List.h
- * \ingroup moto
- */
-
-
-#ifndef GEN_LIST_H
-#define GEN_LIST_H
-
-class GEN_Link {
-public:
- GEN_Link() : m_next(0), m_prev(0) {}
- GEN_Link(GEN_Link *next, GEN_Link *prev) : m_next(next), m_prev(prev) {}
-
- GEN_Link *getNext() const { return m_next; }
- GEN_Link *getPrev() const { return m_prev; }
-
- bool isHead() const { return m_prev == 0; }
- bool isTail() const { return m_next == 0; }
-
- void insertBefore(GEN_Link *link) {
- m_next = link;
- m_prev = link->m_prev;
- m_next->m_prev = this;
- m_prev->m_next = this;
- }
-
- void insertAfter(GEN_Link *link) {
- m_next = link->m_next;
- m_prev = link;
- m_next->m_prev = this;
- m_prev->m_next = this;
- }
-
- void remove() {
- m_next->m_prev = m_prev;
- m_prev->m_next = m_next;
- }
-
-private:
- GEN_Link *m_next;
- GEN_Link *m_prev;
-};
-
-class GEN_List {
-public:
- GEN_List() : m_head(&m_tail, 0), m_tail(0, &m_head) {}
-
- GEN_Link *getHead() const { return m_head.getNext(); }
- GEN_Link *getTail() const { return m_tail.getPrev(); }
-
- void addHead(GEN_Link *link) { link->insertAfter(&m_head); }
- void addTail(GEN_Link *link) { link->insertBefore(&m_tail); }
-
-private:
- GEN_Link m_head;
- GEN_Link m_tail;
-};
-
-#endif
-
diff --git a/intern/moto/include/GEN_Map.h b/intern/moto/include/GEN_Map.h
deleted file mode 100644
index 526bfdc8caf..00000000000
--- a/intern/moto/include/GEN_Map.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file moto/include/GEN_Map.h
- * \ingroup moto
- */
-
-
-#ifndef GEN_MAP_H
-#define GEN_MAP_H
-
-template <class Key, class Value>
-class GEN_Map {
-private:
- struct Entry {
- Entry (Entry *next, Key key, Value value) :
- m_next(next),
- m_key(key),
- m_value(value) {}
-
- Entry *m_next;
- Key m_key;
- Value m_value;
- };
-
-public:
- GEN_Map(int num_buckets = 100) : m_num_buckets(num_buckets) {
- m_buckets = new Entry *[num_buckets];
- for (int i = 0; i < num_buckets; ++i) {
- m_buckets[i] = 0;
- }
- }
-
- GEN_Map(const GEN_Map& map)
- {
- m_num_buckets = map.m_num_buckets;
- m_buckets = new Entry *[m_num_buckets];
-
- for (int i = 0; i < m_num_buckets; ++i) {
- m_buckets[i] = 0;
-
- for(Entry *entry = map.m_buckets[i]; entry; entry=entry->m_next)
- insert(entry->m_key, entry->m_value);
- }
- }
-
- int size() {
- int count=0;
- for (int i=0;i<m_num_buckets;i++)
- {
- Entry* bucket = m_buckets[i];
- while(bucket)
- {
- bucket = bucket->m_next;
- count++;
- }
- }
- return count;
- }
-
- Value* at(int index) {
- int count=0;
- for (int i=0;i<m_num_buckets;i++)
- {
- Entry* bucket = m_buckets[i];
- while(bucket)
- {
- if (count==index)
- {
- return &bucket->m_value;
- }
- bucket = bucket->m_next;
- count++;
- }
- }
- return 0;
- }
-
- Key* getKey(int index) {
- int count=0;
- for (int i=0;i<m_num_buckets;i++)
- {
- Entry* bucket = m_buckets[i];
- while(bucket)
- {
- if (count==index)
- {
- return &bucket->m_key;
- }
- bucket = bucket->m_next;
- count++;
- }
- }
- return 0;
- }
-
- void clear() {
- for (int i = 0; i < m_num_buckets; ++i) {
- Entry *entry_ptr = m_buckets[i];
-
- while (entry_ptr != 0) {
- Entry *tmp_ptr = entry_ptr->m_next;
- delete entry_ptr;
- entry_ptr = tmp_ptr;
- }
- m_buckets[i] = 0;
- }
- }
-
- ~GEN_Map() {
- clear();
- delete [] m_buckets;
- }
-
- void insert(const Key& key, const Value& value) {
- Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets];
- while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) {
- entry_ptr = entry_ptr->m_next;
- }
-
- if (entry_ptr != 0) {
- entry_ptr->m_value = value;
- }
- else {
- Entry **bucket = &m_buckets[key.hash() % m_num_buckets];
- *bucket = new Entry(*bucket, key, value);
- }
- }
-
- void remove(const Key& key) {
- Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets];
- while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) {
- entry_ptr = &(*entry_ptr)->m_next;
- }
-
- if (*entry_ptr != 0) {
- Entry *tmp_ptr = (*entry_ptr)->m_next;
- delete *entry_ptr;
- *entry_ptr = tmp_ptr;
- }
- }
-
- Value *operator[](Key key) {
- Entry *bucket = m_buckets[key.hash() % m_num_buckets];
- while ((bucket != 0) && !(key == bucket->m_key)) {
- bucket = bucket->m_next;
- }
- return bucket != 0 ? &bucket->m_value : 0;
- }
-
-private:
- int m_num_buckets;
- Entry **m_buckets;
-};
-
-#endif
-
diff --git a/intern/moto/include/MT_CmMatrix4x4.h b/intern/moto/include/MT_CmMatrix4x4.h
index 2b710c66888..53fdd41fb28 100644
--- a/intern/moto/include/MT_CmMatrix4x4.h
+++ b/intern/moto/include/MT_CmMatrix4x4.h
@@ -55,7 +55,7 @@ class MT_CmMatrix4x4
public :
MT_CmMatrix4x4(
- const float value[4][4]
+ const MT_Scalar value[4][4]
);
MT_CmMatrix4x4(
@@ -63,7 +63,7 @@ public :
MT_CmMatrix4x4(
- const double value[16]
+ const MT_Scalar value[16]
);
MT_CmMatrix4x4(
@@ -85,19 +85,19 @@ public :
const MT_CmMatrix4x4 & other
);
- double*
+ MT_Scalar*
getPointer(
);
const
- double*
+ MT_Scalar*
getPointer(
) const;
void
setElem(
int pos,
- double newvalue
+ MT_Scalar newvalue
);
MT_Vector3
@@ -121,7 +121,7 @@ public :
const MT_Vector3 & v
);
- double&
+ MT_Scalar&
operator (
) (int row,int col) { return m_V[col][row]; }
@@ -139,8 +139,8 @@ public :
protected:
union
{
- double m_V[4][4];
- double m_Vflat[16];
+ MT_Scalar m_V[4][4];
+ MT_Scalar m_Vflat[16];
};
};
diff --git a/intern/moto/include/MT_Matrix3x3.h b/intern/moto/include/MT_Matrix3x3.h
index 17dd5335217..6f965f59069 100644
--- a/intern/moto/include/MT_Matrix3x3.h
+++ b/intern/moto/include/MT_Matrix3x3.h
@@ -132,14 +132,14 @@ public:
void setRotation(const MT_Quaternion& q) {
MT_Scalar d = q.length2();
MT_assert(!MT_fuzzyZero2(d));
- MT_Scalar s = MT_Scalar(2.0) / d;
+ MT_Scalar s = MT_Scalar(2.0f) / d;
MT_Scalar xs = q[0] * s, ys = q[1] * s, zs = q[2] * s;
MT_Scalar wx = q[3] * xs, wy = q[3] * ys, wz = q[3] * zs;
MT_Scalar xx = q[0] * xs, xy = q[0] * ys, xz = q[0] * zs;
MT_Scalar yy = q[1] * ys, yz = q[1] * zs, zz = q[2] * zs;
- setValue(MT_Scalar(1.0) - (yy + zz), xy - wz , xz + wy,
- xy + wz , MT_Scalar(1.0) - (xx + zz), yz - wx,
- xz - wy , yz + wx, MT_Scalar(1.0) - (xx + yy));
+ setValue(MT_Scalar(1.0f) - (yy + zz), xy - wz , xz + wy,
+ xy + wz , MT_Scalar(1.0f) - (xx + zz), yz - wx,
+ xz - wy , yz + wx, MT_Scalar(1.0f) - (xx + yy));
}
/**
@@ -151,12 +151,12 @@ public:
**/
void setEuler(const MT_Vector3& euler) {
- MT_Scalar ci = cos(euler[0]);
- MT_Scalar cj = cos(euler[1]);
- MT_Scalar ch = cos(euler[2]);
- MT_Scalar si = sin(euler[0]);
- MT_Scalar sj = sin(euler[1]);
- MT_Scalar sh = sin(euler[2]);
+ MT_Scalar ci = cosf(euler[0]);
+ MT_Scalar cj = cosf(euler[1]);
+ MT_Scalar ch = cosf(euler[2]);
+ MT_Scalar si = sinf(euler[0]);
+ MT_Scalar sj = sinf(euler[1]);
+ MT_Scalar sh = sinf(euler[2]);
MT_Scalar cc = ci * ch;
MT_Scalar cs = ci * sh;
MT_Scalar sc = si * ch;
@@ -169,20 +169,20 @@ public:
void getEuler(MT_Scalar& yaw, MT_Scalar& pitch, MT_Scalar& roll) const
{
- if (m_el[2][0] != -1.0 && m_el[2][0] != 1.0) {
- pitch = MT_Scalar(-asin(m_el[2][0]));
- yaw = MT_Scalar(atan2(m_el[2][1] / cos(pitch), m_el[2][2] / cos(pitch)));
- roll = MT_Scalar(atan2(m_el[1][0] / cos(pitch), m_el[0][0] / cos(pitch)));
+ if (m_el[2][0] != -1.0f && m_el[2][0] != 1.0f) {
+ pitch = MT_Scalar(-asinf(m_el[2][0]));
+ yaw = MT_Scalar(atan2f(m_el[2][1] / cosf(pitch), m_el[2][2] / cosf(pitch)));
+ roll = MT_Scalar(atan2f(m_el[1][0] / cosf(pitch), m_el[0][0] / cosf(pitch)));
}
else {
roll = MT_Scalar(0);
- if (m_el[2][0] == -1.0) {
- pitch = MT_PI / 2.0;
- yaw = MT_Scalar(atan2(m_el[0][1], m_el[0][2]));
+ if (m_el[2][0] == -1.0f) {
+ pitch = (float)MT_PI / 2.0f;
+ yaw = MT_Scalar(atan2f(m_el[0][1], m_el[0][2]));
}
else {
- pitch = - MT_PI / 2.0;
- yaw = MT_Scalar(atan2(m_el[0][1], m_el[0][2]));
+ pitch = (float)-MT_PI / 2.0f;
+ yaw = MT_Scalar(atan2f(m_el[0][1], m_el[0][2]));
}
}
}
@@ -200,15 +200,15 @@ public:
}
void setIdentity() {
- setValue(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0),
- MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0),
- MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0));
+ setValue(MT_Scalar(1.0f), MT_Scalar(0.0f), MT_Scalar(0.0f),
+ MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f),
+ MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f));
}
void getValue(float *m) const {
- *m++ = (float) m_el[0][0]; *m++ = (float) m_el[1][0]; *m++ = (float) m_el[2][0]; *m++ = (float) 0.0;
- *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) 0.0;
- *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m = (float) 0.0;
+ *m++ = (float) m_el[0][0]; *m++ = (float) m_el[1][0]; *m++ = (float) m_el[2][0]; *m++ = (float) 0.0f;
+ *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) 0.0f;
+ *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m = (float) 0.0f;
}
void getValue(double *m) const {
diff --git a/intern/moto/include/MT_Matrix3x3.inl b/intern/moto/include/MT_Matrix3x3.inl
index c581640ebfe..614e4f93a81 100644
--- a/intern/moto/include/MT_Matrix3x3.inl
+++ b/intern/moto/include/MT_Matrix3x3.inl
@@ -7,11 +7,11 @@ GEN_INLINE MT_Quaternion MT_Matrix3x3::getRotation() const {
MT_Scalar trace = m_el[0][0] + m_el[1][1] + m_el[2][2];
- if (trace > 0.0)
+ if (trace > 0.0f)
{
- MT_Scalar s = sqrt(trace + MT_Scalar(1.0));
- result[3] = s * MT_Scalar(0.5);
- s = MT_Scalar(0.5) / s;
+ MT_Scalar s = sqrtf(trace + MT_Scalar(1.0f));
+ result[3] = s * MT_Scalar(0.5f);
+ s = MT_Scalar(0.5f) / s;
result[0] = (m_el[2][1] - m_el[1][2]) * s;
result[1] = (m_el[0][2] - m_el[2][0]) * s;
@@ -28,11 +28,11 @@ GEN_INLINE MT_Quaternion MT_Matrix3x3::getRotation() const {
int j = next[i];
int k = next[j];
- MT_Scalar s = sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + MT_Scalar(1.0));
+ MT_Scalar s = sqrtf(m_el[i][i] - m_el[j][j] - m_el[k][k] + MT_Scalar(1.0f));
- result[i] = s * MT_Scalar(0.5);
+ result[i] = s * MT_Scalar(0.5f);
- s = MT_Scalar(0.5) / s;
+ s = MT_Scalar(0.5f) / s;
result[3] = (m_el[k][j] - m_el[j][k]) * s;
result[j] = (m_el[j][i] + m_el[i][j]) * s;
@@ -80,7 +80,7 @@ GEN_INLINE MT_Matrix3x3 MT_Matrix3x3::inverse() const {
MT_Vector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1));
MT_Scalar det = MT_dot((*this)[0], co);
MT_assert(!MT_fuzzyZero2(det));
- MT_Scalar s = MT_Scalar(1.0) / det;
+ MT_Scalar s = MT_Scalar(1.0f) / det;
return
MT_Matrix3x3(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s,
co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s,
diff --git a/intern/moto/include/MT_Matrix4x4.h b/intern/moto/include/MT_Matrix4x4.h
index de2ea995401..045cc3b8361 100644
--- a/intern/moto/include/MT_Matrix4x4.h
+++ b/intern/moto/include/MT_Matrix4x4.h
@@ -86,7 +86,7 @@ public:
basis[0][0],basis[0][1],basis[0][2],origin[0],
basis[1][0],basis[1][1],basis[1][2],origin[1],
basis[2][0],basis[2][1],basis[2][2],origin[2],
- MT_Scalar(0),MT_Scalar(0),MT_Scalar(0),MT_Scalar(1)
+ MT_Scalar(0.0f),MT_Scalar(0.0f),MT_Scalar(0.0f),MT_Scalar(1.0f)
);
}
@@ -157,10 +157,10 @@ public:
* Set this matrix to I.
*/
void setIdentity() {
- setValue(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0),
- MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0),
- MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0),
- MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0));
+ setValue(MT_Scalar(1.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(0.0f),
+ MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f), MT_Scalar(0.0f),
+ MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f),
+ MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f));
}
/**
diff --git a/intern/moto/include/MT_Matrix4x4.inl b/intern/moto/include/MT_Matrix4x4.inl
index 074bd6e4b05..fb72af1f9bf 100644
--- a/intern/moto/include/MT_Matrix4x4.inl
+++ b/intern/moto/include/MT_Matrix4x4.inl
@@ -11,14 +11,14 @@ GEN_INLINE void MT_Matrix4x4::invert() {
for (i=1; i < 4; i++) m_el[0][i] /= m_el[0][0];
for (i=1; i < 4; i++) {
for (j=i; j < 4; j++) { // do a column of L
- MT_Scalar sum = 0.0;
+ MT_Scalar sum = 0.0f;
for (k = 0; k < i; k++)
sum += m_el[j][k] * m_el[k][i];
m_el[j][i] -= sum;
}
if (i == 3) continue;
for (j=i+1; j < 4; j++) { // do a row of U
- MT_Scalar sum = 0.0;
+ MT_Scalar sum = 0.0f;
for (k = 0; k < i; k++)
sum += m_el[i][k]*m_el[k][j];
m_el[i][j] =
@@ -27,9 +27,9 @@ GEN_INLINE void MT_Matrix4x4::invert() {
}
for (i = 0; i < 4; i++ ) // invert L
for (j = i; j < 4; j++ ) {
- MT_Scalar x = 1.0;
+ MT_Scalar x = 1.0f;
if ( i != j ) {
- x = 0.0;
+ x = 0.0f;
for (k = i; k < j; k++ )
x -= m_el[j][k]*m_el[k][i];
}
@@ -38,16 +38,16 @@ GEN_INLINE void MT_Matrix4x4::invert() {
for (i = 0; i < 4; i++ ) // invert U
for (j = i; j < 4; j++ ) {
if ( i == j ) continue;
- MT_Scalar sum = 0.0;
+ MT_Scalar sum = 0.0f;
for (k = i; k < j; k++ )
- sum += m_el[k][j]*( (i==k) ? 1.0 : m_el[i][k] );
+ sum += m_el[k][j]*( (i==k) ? 1.0f : m_el[i][k] );
m_el[i][j] = -sum;
}
for (i = 0; i < 4; i++ ) // final inversion
for (j = 0; j < 4; j++ ) {
- MT_Scalar sum = 0.0;
+ MT_Scalar sum = 0.0f;
for (k = ((i>j)?i:j); k < 4; k++ )
- sum += ((j==k)?1.0:m_el[j][k])*m_el[k][i];
+ sum += ((j==k)?1.0f:m_el[j][k])*m_el[k][i];
m_el[j][i] = sum;
}
}
diff --git a/intern/moto/include/MT_Plane3.h b/intern/moto/include/MT_Plane3.h
deleted file mode 100644
index f208b377a81..00000000000
--- a/intern/moto/include/MT_Plane3.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file moto/include/MT_Plane3.h
- * \ingroup moto
- */
-
-
-#ifndef MT_PLANE3
-#define MT_PLANE3
-
-#include "MT_Tuple4.h"
-#include "MT_Point3.h"
-
-/**
- * A simple 3d plane class.
- *
- * This class represents a plane in 3d. The internal parameterization used
- * is n.x + d =0 where n is a unit vector and d is a scalar.
- *
- * It inherits data from MT_Tuple4 please see this class for low level
- * access to the internal representation.
- *
- */
-
-class MT_Plane3 : public MT_Tuple4
-{
-public :
- /**
- * Constructor from 3 points
- */
-
- MT_Plane3(
- const MT_Vector3 &a,
- const MT_Vector3 &b,
- const MT_Vector3 &c
- );
- /**
- * Construction from vector and a point.
- */
-
- MT_Plane3(
- const MT_Vector3 &n,
- const MT_Vector3 &p
- );
-
- /**
- * Default constructor
- */
- MT_Plane3(
- );
-
- /**
- * Default constructor
- */
-
- MT_Plane3(
- const MT_Plane3 & p
- ):
- MT_Tuple4(p)
- {
- }
-
- /**
- * Return plane normal
- */
-
- MT_Vector3
- Normal(
- ) const;
-
- /**
- * Return plane scalar i.e the d from n.x + d = 0
- */
-
- MT_Scalar
- Scalar(
- ) const ;
-
- /**
- * Invert the plane - just swaps direction of normal.
- */
- void
- Invert(
- );
-
- /**
- * Assignment operator
- */
-
- MT_Plane3 &
- operator = (
- const MT_Plane3 & rhs
- );
-
- /**
- * Return the signed perpendicular distance from a point to the plane
- */
-
- MT_Scalar
- signedDistance(
- const MT_Vector3 &
- ) const;
-
-
-};
-
-#ifdef GEN_INLINED
-#include "MT_Plane3.inl"
-#endif
-
-#endif
-
diff --git a/intern/moto/include/MT_Plane3.inl b/intern/moto/include/MT_Plane3.inl
deleted file mode 100644
index 77db9b35e1d..00000000000
--- a/intern/moto/include/MT_Plane3.inl
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "MT_Optimize.h"
-
-
-GEN_INLINE
-MT_Plane3::
-MT_Plane3(
- const MT_Vector3 &a,
- const MT_Vector3 &b,
- const MT_Vector3 &c
-){
- MT_Vector3 l1 = b-a;
- MT_Vector3 l2 = c-b;
-
- MT_Vector3 n = l1.cross(l2);
- n = n.safe_normalized();
- MT_Scalar d = n.dot(a);
-
- m_co[0] = n.x();
- m_co[1] = n.y();
- m_co[2] = n.z();
- m_co[3] = -d;
-}
-
-/**
- * Construction from vector and a point.
- */
-GEN_INLINE
-MT_Plane3::
-MT_Plane3(
- const MT_Vector3 &n,
- const MT_Vector3 &p
-){
-
- MT_Vector3 mn = n.safe_normalized();
- MT_Scalar md = mn.dot(p);
-
- m_co[0] = mn.x();
- m_co[1] = mn.y();
- m_co[2] = mn.z();
- m_co[3] = -md;
-}
-
-
-/**
- * Default constructor
- */
-GEN_INLINE
-MT_Plane3::
-MT_Plane3(
-):
- MT_Tuple4()
-{
- m_co[0] = MT_Scalar(1);
- m_co[1] = MT_Scalar(0);
- m_co[2] = MT_Scalar(0);
- m_co[3] = MT_Scalar(0);
-}
-
-/**
- * Return plane normal
- */
-
-GEN_INLINE
- MT_Vector3
-MT_Plane3::
-Normal(
-) const {
- return MT_Vector3(m_co[0],m_co[1],m_co[2]);
-}
-
-/**
- * Return plane scalar i.e the d from n.x + d = 0
- */
-
-GEN_INLINE
- MT_Scalar
-MT_Plane3::
-Scalar(
-) const {
- return m_co[3];
-}
-
-GEN_INLINE
- void
-MT_Plane3::
-Invert(
-) {
- m_co[0] = -m_co[0];
- m_co[1] = -m_co[1];
- m_co[2] = -m_co[2];
- m_co[3] = -m_co[3];
-}
-
-
-/**
- * Assignment operator
- */
-
-GEN_INLINE
- MT_Plane3 &
-MT_Plane3::
-operator = (
- const MT_Plane3 & rhs
-) {
- m_co[0] = rhs.m_co[0];
- m_co[1] = rhs.m_co[1];
- m_co[2] = rhs.m_co[2];
- m_co[3] = rhs.m_co[3];
- return *this;
-}
-
-/**
- * Return the distance from a point to the plane
- */
-
-GEN_INLINE
- MT_Scalar
-MT_Plane3::
-signedDistance(
- const MT_Vector3 &v
-) const {
- return Normal().dot(v) + m_co[3];
-}
-
-
-
-
-
diff --git a/intern/moto/include/MT_Quaternion.h b/intern/moto/include/MT_Quaternion.h
index 407d291348b..6aabb1f2ed4 100644
--- a/intern/moto/include/MT_Quaternion.h
+++ b/intern/moto/include/MT_Quaternion.h
@@ -70,18 +70,18 @@ public:
void setRotation(const MT_Vector3& axis, MT_Scalar mt_angle) {
MT_Scalar d = axis.length();
MT_assert(!MT_fuzzyZero(d));
- MT_Scalar s = sin(mt_angle * MT_Scalar(0.5)) / d;
+ MT_Scalar s = sinf(mt_angle * MT_Scalar(0.5f)) / d;
setValue(axis[0] * s, axis[1] * s, axis[2] * s,
- cos(mt_angle * MT_Scalar(0.5)));
+ cosf(mt_angle * MT_Scalar(0.5f)));
}
void setEuler(MT_Scalar yaw, MT_Scalar pitch, MT_Scalar roll) {
- MT_Scalar cosYaw = cos(yaw * MT_Scalar(0.5));
- MT_Scalar sinYaw = sin(yaw * MT_Scalar(0.5));
- MT_Scalar cosPitch = cos(pitch * MT_Scalar(0.5));
- MT_Scalar sinPitch = sin(pitch * MT_Scalar(0.5));
- MT_Scalar cosRoll = cos(roll * MT_Scalar(0.5));
- MT_Scalar sinRoll = sin(roll * MT_Scalar(0.5));
+ MT_Scalar cosYaw = cosf(yaw * MT_Scalar(0.5f));
+ MT_Scalar sinYaw = sinf(yaw * MT_Scalar(0.5f));
+ MT_Scalar cosPitch = cosf(pitch * MT_Scalar(0.5f));
+ MT_Scalar sinPitch = sinf(pitch * MT_Scalar(0.5f));
+ MT_Scalar cosRoll = cosf(roll * MT_Scalar(0.5f));
+ MT_Scalar sinRoll = sinf(roll * MT_Scalar(0.5f));
setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw,
sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,
diff --git a/intern/moto/include/MT_Quaternion.inl b/intern/moto/include/MT_Quaternion.inl
index ec747c453d3..8fe71b7b214 100644
--- a/intern/moto/include/MT_Quaternion.inl
+++ b/intern/moto/include/MT_Quaternion.inl
@@ -29,10 +29,10 @@ GEN_INLINE MT_Quaternion MT_Quaternion::inverse() const {
// pg. 124-132
GEN_INLINE MT_Quaternion MT_Quaternion::random() {
MT_Scalar x0 = MT_random();
- MT_Scalar r1 = sqrt(MT_Scalar(1.0) - x0), r2 = sqrt(x0);
- MT_Scalar t1 = MT_2_PI * MT_random(), t2 = MT_2_PI * MT_random();
- MT_Scalar c1 = cos(t1), s1 = sin(t1);
- MT_Scalar c2 = cos(t2), s2 = sin(t2);
+ MT_Scalar r1 = sqrtf(MT_Scalar(1.0f) - x0), r2 = sqrtf(x0);
+ MT_Scalar t1 = (float)MT_2_PI * MT_random(), t2 = (float)MT_2_PI * MT_random();
+ MT_Scalar c1 = cosf(t1), s1 = sinf(t1);
+ MT_Scalar c2 = cosf(t2), s2 = sinf(t2);
return MT_Quaternion(s1 * r1, c1 * r1, s2 * r2, c2 * r2);
}
@@ -62,35 +62,35 @@ GEN_INLINE MT_Quaternion operator*(const MT_Vector3& w, const MT_Quaternion& q)
GEN_INLINE MT_Scalar MT_Quaternion::angle(const MT_Quaternion& q) const
{
- MT_Scalar s = sqrt(length2() * q.length2());
- assert(s != MT_Scalar(0.0));
+ MT_Scalar s = sqrtf(length2() * q.length2());
+ assert(s != MT_Scalar(0.0f));
s = dot(q) / s;
- s = MT_clamp(s, -1.0, 1.0);
+ s = MT_clamp(s, -1.0f, 1.0f);
- return acos(s);
+ return acosf(s);
}
GEN_INLINE MT_Quaternion MT_Quaternion::slerp(const MT_Quaternion& q, const MT_Scalar& t) const
{
MT_Scalar d, s0, s1;
MT_Scalar s = dot(q);
- bool neg = (s < 0.0);
+ bool neg = (s < 0.0f);
if (neg)
s = -s;
- if ((1.0 - s) > 0.0001)
+ if ((1.0f - s) > 0.0001f)
{
- MT_Scalar theta = acos(s);
- d = MT_Scalar(1.0) / sin(theta);
- s0 = sin((MT_Scalar(1.0) - t) * theta);
- s1 = sin(t * theta);
+ MT_Scalar theta = acosf(s);
+ d = MT_Scalar(1.0f) / sinf(theta);
+ s0 = sinf((MT_Scalar(1.0f) - t) * theta);
+ s1 = sinf(t * theta);
}
else
{
- d = MT_Scalar(1.0);
- s0 = MT_Scalar(1.0) - t;
+ d = MT_Scalar(1.0f);
+ s0 = MT_Scalar(1.0f) - t;
s1 = t;
}
if (neg)
diff --git a/intern/moto/include/MT_Scalar.h b/intern/moto/include/MT_Scalar.h
index 5c4a5c2a44a..94723f4d7ec 100644
--- a/intern/moto/include/MT_Scalar.h
+++ b/intern/moto/include/MT_Scalar.h
@@ -51,9 +51,8 @@
#include <float.h>
#include "MT_random.h"
-#include "NM_Scalar.h"
-typedef double MT_Scalar; //this should be float !
+typedef float MT_Scalar;
const MT_Scalar MT_DEGS_PER_RAD(57.29577951308232286465);
@@ -62,23 +61,23 @@ const MT_Scalar MT_PI(3.14159265358979323846);
const MT_Scalar MT_2_PI(6.28318530717958623200);
const MT_Scalar MT_EPSILON(1.0e-10);
const MT_Scalar MT_EPSILON2(1.0e-20);
-const MT_Scalar MT_INFINITY(1.0e50);
+const MT_Scalar MT_INFINITY(1.0e38);
inline int MT_sign(MT_Scalar x) {
- return x < 0.0 ? -1 : x > 0.0 ? 1 : 0;
+ return x < 0.0f ? -1 : x > 0.0f ? 1 : 0;
}
inline MT_Scalar MT_abs(MT_Scalar x) { return fabs(x); }
-inline bool MT_fuzzyZero(MT_Scalar x) { return MT_abs(x) < MT_EPSILON; }
-inline bool MT_fuzzyZero2(MT_Scalar x) { return MT_abs(x) < MT_EPSILON2; }
+inline bool MT_fuzzyZero(MT_Scalar x) { return MT_abs(x) < (float)MT_EPSILON; }
+inline bool MT_fuzzyZero2(MT_Scalar x) { return MT_abs(x) < (float)MT_EPSILON2; }
inline MT_Scalar MT_radians(MT_Scalar x) {
- return x * MT_RADS_PER_DEG;
+ return x * (float)MT_RADS_PER_DEG;
}
inline MT_Scalar MT_degrees(MT_Scalar x) {
- return x * MT_DEGS_PER_RAD;
+ return x * (float)MT_DEGS_PER_RAD;
}
inline MT_Scalar MT_random() {
diff --git a/intern/moto/include/MT_Vector2.inl b/intern/moto/include/MT_Vector2.inl
index 860f9bad830..ed16025e733 100644
--- a/intern/moto/include/MT_Vector2.inl
+++ b/intern/moto/include/MT_Vector2.inl
@@ -17,7 +17,7 @@ GEN_INLINE MT_Vector2& MT_Vector2::operator*=(MT_Scalar s) {
GEN_INLINE MT_Vector2& MT_Vector2::operator/=(MT_Scalar s) {
MT_assert(!MT_fuzzyZero(s));
- return *this *= 1.0 / s;
+ return *this *= 1.0f / s;
}
GEN_INLINE MT_Vector2 operator+(const MT_Vector2& v1, const MT_Vector2& v2) {
@@ -40,7 +40,7 @@ GEN_INLINE MT_Vector2 operator*(MT_Scalar s, const MT_Vector2& v) { return v * s
GEN_INLINE MT_Vector2 operator/(const MT_Vector2& v, MT_Scalar s) {
MT_assert(!MT_fuzzyZero(s));
- return v * (1.0 / s);
+ return v * (1.0f / s);
}
GEN_INLINE MT_Scalar MT_Vector2::dot(const MT_Vector2& vv) const {
@@ -48,7 +48,7 @@ GEN_INLINE MT_Scalar MT_Vector2::dot(const MT_Vector2& vv) const {
}
GEN_INLINE MT_Scalar MT_Vector2::length2() const { return dot(*this); }
-GEN_INLINE MT_Scalar MT_Vector2::length() const { return sqrt(length2()); }
+GEN_INLINE MT_Scalar MT_Vector2::length() const { return sqrtf(length2()); }
GEN_INLINE MT_Vector2 MT_Vector2::absolute() const {
return MT_Vector2(MT_abs(m_co[0]), MT_abs(m_co[1]));
@@ -68,9 +68,9 @@ GEN_INLINE MT_Vector2 MT_Vector2::scaled(MT_Scalar xx, MT_Scalar yy) const {
}
GEN_INLINE MT_Scalar MT_Vector2::angle(const MT_Vector2& vv) const {
- MT_Scalar s = sqrt(length2() * vv.length2());
+ MT_Scalar s = sqrtf(length2() * vv.length2());
MT_assert(!MT_fuzzyZero(s));
- return acos(dot(vv) / s);
+ return acosf(dot(vv) / s);
}
diff --git a/intern/moto/include/MT_Vector3.h b/intern/moto/include/MT_Vector3.h
index b06f345bdaf..545ca1fad0b 100644
--- a/intern/moto/include/MT_Vector3.h
+++ b/intern/moto/include/MT_Vector3.h
@@ -52,7 +52,6 @@
class MT_Vector3 : public MT_Tuple3 {
public:
- virtual ~MT_Vector3() {}
MT_Vector3() {}
MT_Vector3(const float *v) : MT_Tuple3(v) {}
MT_Vector3(const double *v) : MT_Tuple3(v) {}
diff --git a/intern/moto/include/MT_Vector3.inl b/intern/moto/include/MT_Vector3.inl
index 09c92c6ab54..7994bf7c55c 100644
--- a/intern/moto/include/MT_Vector3.inl
+++ b/intern/moto/include/MT_Vector3.inl
@@ -17,7 +17,7 @@ GEN_INLINE MT_Vector3& MT_Vector3::operator*=(MT_Scalar s) {
GEN_INLINE MT_Vector3& MT_Vector3::operator/=(MT_Scalar s) {
MT_assert(!MT_fuzzyZero(s));
- return *this *= MT_Scalar(1.0) / s;
+ return *this *= MT_Scalar(1.0f) / s;
}
GEN_INLINE MT_Vector3 operator+(const MT_Vector3& v1, const MT_Vector3& v2) {
@@ -40,7 +40,7 @@ GEN_INLINE MT_Vector3 operator*(MT_Scalar s, const MT_Vector3& v) { return v * s
GEN_INLINE MT_Vector3 operator/(const MT_Vector3& v, MT_Scalar s) {
MT_assert(!MT_fuzzyZero(s));
- return v * (MT_Scalar(1.0) / s);
+ return v * (MT_Scalar(1.0f) / s);
}
GEN_INLINE MT_Vector3 operator*(const MT_Vector3& v1, const MT_Vector3& v2) {
@@ -52,7 +52,7 @@ GEN_INLINE MT_Scalar MT_Vector3::dot(const MT_Vector3& v) const {
}
GEN_INLINE MT_Scalar MT_Vector3::length2() const { return dot(*this); }
-GEN_INLINE MT_Scalar MT_Vector3::length() const { return sqrt(length2()); }
+GEN_INLINE MT_Scalar MT_Vector3::length() const { return sqrtf(length2()); }
GEN_INLINE MT_Vector3 MT_Vector3::absolute() const {
return MT_Vector3(MT_abs(m_co[0]), MT_abs(m_co[1]), MT_abs(m_co[2]));
@@ -64,7 +64,7 @@ GEN_INLINE bool MT_Vector3::fuzzyZero() const {
GEN_INLINE void MT_Vector3::noiseGate(MT_Scalar threshold) {
if (length2() < threshold) {
- setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+ setValue(MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(0.0f));
}
}
@@ -73,7 +73,7 @@ GEN_INLINE MT_Vector3 MT_Vector3::normalized() const { return *this / length();
GEN_INLINE MT_Vector3 MT_Vector3::safe_normalized() const {
MT_Scalar len = length();
return MT_fuzzyZero(len) ?
- MT_Vector3(MT_Scalar(1.0), MT_Scalar(0.0), MT_Scalar(0.0)) :
+ MT_Vector3(MT_Scalar(1.0f), MT_Scalar(0.0f), MT_Scalar(0.0f)) :
*this / len;
}
@@ -93,9 +93,9 @@ GEN_INLINE MT_Vector3 MT_Vector3::scaled(MT_Scalar xx, MT_Scalar yy, MT_Scalar z
}
GEN_INLINE MT_Scalar MT_Vector3::angle(const MT_Vector3& v) const {
- MT_Scalar s = sqrt(length2() * v.length2());
+ MT_Scalar s = sqrtf(length2() * v.length2());
MT_assert(!MT_fuzzyZero(s));
- return acos(dot(v) / s);
+ return acosf(dot(v) / s);
}
GEN_INLINE MT_Vector3 MT_Vector3::cross(const MT_Vector3& v) const {
@@ -116,10 +116,10 @@ GEN_INLINE int MT_Vector3::closestAxis() const {
}
GEN_INLINE MT_Vector3 MT_Vector3::random() {
- MT_Scalar z = MT_Scalar(2.0) * MT_random() - MT_Scalar(1.0);
- MT_Scalar r = sqrt(MT_Scalar(1.0) - z * z);
- MT_Scalar t = MT_2_PI * MT_random();
- return MT_Vector3(r * cos(t), r * sin(t), z);
+ MT_Scalar z = MT_Scalar(2.0f) * MT_random() - MT_Scalar(1.0f);
+ MT_Scalar r = sqrtf(MT_Scalar(1.0f) - z * z);
+ MT_Scalar t = (float)MT_2_PI * MT_random();
+ return MT_Vector3(r * cosf(t), r * sinf(t), z);
}
GEN_INLINE MT_Scalar MT_dot(const MT_Vector3& v1, const MT_Vector3& v2) {
diff --git a/intern/moto/include/MT_Vector4.h b/intern/moto/include/MT_Vector4.h
index d157cefa946..440bf9b84f1 100644
--- a/intern/moto/include/MT_Vector4.h
+++ b/intern/moto/include/MT_Vector4.h
@@ -53,7 +53,6 @@
class MT_Vector4 : public MT_Tuple4 {
public:
- virtual ~MT_Vector4() {}
MT_Vector4() {}
MT_Vector4(const float *v) : MT_Tuple4(v) {}
MT_Vector4(const double *v) : MT_Tuple4(v) {}
diff --git a/intern/moto/include/MT_Vector4.inl b/intern/moto/include/MT_Vector4.inl
index 9b4126093c1..5b6e6766416 100644
--- a/intern/moto/include/MT_Vector4.inl
+++ b/intern/moto/include/MT_Vector4.inl
@@ -17,7 +17,7 @@ GEN_INLINE MT_Vector4& MT_Vector4::operator*=(MT_Scalar s) {
GEN_INLINE MT_Vector4& MT_Vector4::operator/=(MT_Scalar s) {
MT_assert(!MT_fuzzyZero(s));
- return *this *= MT_Scalar(1.0) / s;
+ return *this *= MT_Scalar(1.0f) / s;
}
GEN_INLINE MT_Vector4 operator+(const MT_Vector4& v1, const MT_Vector4& v2) {
@@ -40,7 +40,7 @@ GEN_INLINE MT_Vector4 operator*(MT_Scalar s, const MT_Vector4& v) { return v * s
GEN_INLINE MT_Vector4 operator/(const MT_Vector4& v, MT_Scalar s) {
MT_assert(!MT_fuzzyZero(s));
- return v * (MT_Scalar(1.0) / s);
+ return v * (MT_Scalar(1.0f) / s);
}
GEN_INLINE MT_Scalar MT_Vector4::dot(const MT_Vector4& v) const {
@@ -48,7 +48,7 @@ GEN_INLINE MT_Scalar MT_Vector4::dot(const MT_Vector4& v) const {
}
GEN_INLINE MT_Scalar MT_Vector4::length2() const { return MT_dot(*this, *this); }
-GEN_INLINE MT_Scalar MT_Vector4::length() const { return sqrt(length2()); }
+GEN_INLINE MT_Scalar MT_Vector4::length() const { return sqrtf(length2()); }
GEN_INLINE MT_Vector4 MT_Vector4::absolute() const {
return MT_Vector4(MT_abs(m_co[0]), MT_abs(m_co[1]), MT_abs(m_co[2]), MT_abs(m_co[3]));
diff --git a/intern/moto/include/NM_Scalar.h b/intern/moto/include/NM_Scalar.h
deleted file mode 100644
index 0e33979c521..00000000000
--- a/intern/moto/include/NM_Scalar.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file moto/include/NM_Scalar.h
- * \ingroup moto
- */
-
-
-#include <math.h>
-#include <iostream>
-
-template <class T>
-class NM_Scalar {
-public:
- NM_Scalar() {}
- explicit NM_Scalar(T value, T error = 0.0) :
- m_value(value), m_error(error) {}
-
- T getValue() const { return m_value; }
- T getError() const { return m_error; }
-
- operator T() const { return m_value; }
-
- NM_Scalar operator-() const {
- return NM_Scalar<T>(-m_value, m_error);
- }
-
- NM_Scalar& operator=(T value) {
- m_value = value;
- m_error = 0.0;
- return *this;
- }
-
- NM_Scalar& operator+=(const NM_Scalar& x) {
- m_value += x.m_value;
- m_error = (fabs(m_value) * (m_error + 1.0) +
- fabs(x.m_value) * (x.m_error + 1.0)) /
- fabs(m_value + x.m_value);
- return *this;
- }
-
- NM_Scalar& operator-=(const NM_Scalar& x) {
- m_value -= x.m_value;
- m_error = (fabs(m_value) * (m_error + 1.0) +
- fabs(x.m_value) * (x.m_error + 1.0)) /
- fabs(m_value - x.m_value);
- return *this;
- }
-
- NM_Scalar& operator*=(const NM_Scalar& x) {
- m_value *= x.m_value;
- m_error += x.m_error + 1.0;
- return *this;
- }
-
- NM_Scalar& operator/=(const NM_Scalar& x) {
- m_value /= x.m_value;
- m_error += x.m_error + 1.0;
- return *this;
- }
-
-private:
- T m_value;
- T m_error;
-};
-
-template <class T>
-inline NM_Scalar<T> operator+(const NM_Scalar<T>& x, const NM_Scalar<T>& y) {
- return x.getValue() == 0.0 && y.getValue() == 0.0 ?
- NM_Scalar<T>(0.0, 0.0) :
- NM_Scalar<T>(x.getValue() + y.getValue(),
- (fabs(x.getValue()) * (x.getError() + 1.0) +
- fabs(y.getValue()) * (y.getError() + 1.0)) /
- fabs(x.getValue() + y.getValue()));
-}
-
-template <class T>
-inline NM_Scalar<T> operator-(const NM_Scalar<T>& x, const NM_Scalar<T>& y) {
- return x.getValue() == 0.0 && y.getValue() == 0.0 ?
- NM_Scalar<T>(0.0, 0.0) :
- NM_Scalar<T>(x.getValue() - y.getValue(),
- (fabs(x.getValue()) * (x.getError() + 1.0) +
- fabs(y.getValue()) * (y.getError() + 1.0)) /
- fabs(x.getValue() - y.getValue()));
-}
-
-template <class T>
-inline NM_Scalar<T> operator*(const NM_Scalar<T>& x, const NM_Scalar<T>& y) {
- return NM_Scalar<T>(x.getValue() * y.getValue(),
- x.getError() + y.getError() + 1.0);
-}
-
-template <class T>
-inline NM_Scalar<T> operator/(const NM_Scalar<T>& x, const NM_Scalar<T>& y) {
- return NM_Scalar<T>(x.getValue() / y.getValue(),
- x.getError() + y.getError() + 1.0);
-}
-
-template <class T>
-inline std::ostream& operator<<(std::ostream& os, const NM_Scalar<T>& x) {
- return os << x.getValue() << '[' << x.getError() << ']';
-}
-
-template <class T>
-inline NM_Scalar<T> sqrt(const NM_Scalar<T>& x) {
- return NM_Scalar<T>(sqrt(x.getValue()),
- 0.5 * x.getError() + 1.0);
-}
-
-template <class T>
-inline NM_Scalar<T> acos(const NM_Scalar<T>& x) {
- return NM_Scalar<T>(acos(x.getValue()), x.getError() + 1.0);
-}
-
-template <class T>
-inline NM_Scalar<T> cos(const NM_Scalar<T>& x) {
- return NM_Scalar<T>(cos(x.getValue()), x.getError() + 1.0);
-}
-
-template <class T>
-inline NM_Scalar<T> sin(const NM_Scalar<T>& x) {
- return NM_Scalar<T>(sin(x.getValue()), x.getError() + 1.0);
-}
-
-template <class T>
-inline NM_Scalar<T> fabs(const NM_Scalar<T>& x) {
- return NM_Scalar<T>(fabs(x.getValue()), x.getError());
-}
-
-template <class T>
-inline NM_Scalar<T> pow(const NM_Scalar<T>& x, const NM_Scalar<T>& y) {
- return NM_Scalar<T>(pow(x.getValue(), y.getValue()),
- fabs(y.getValue()) * x.getError() + 1.0);
-}
-
diff --git a/intern/moto/intern/MT_CmMatrix4x4.cpp b/intern/moto/intern/MT_CmMatrix4x4.cpp
index 7a04864e48d..38c93b92761 100644
--- a/intern/moto/intern/MT_CmMatrix4x4.cpp
+++ b/intern/moto/intern/MT_CmMatrix4x4.cpp
@@ -42,7 +42,7 @@ MT_CmMatrix4x4::MT_CmMatrix4x4()
-MT_CmMatrix4x4::MT_CmMatrix4x4(const float value[4][4])
+MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Scalar value[4][4])
{
for (int i=0;i<4;i++)
{
@@ -53,7 +53,7 @@ MT_CmMatrix4x4::MT_CmMatrix4x4(const float value[4][4])
-MT_CmMatrix4x4::MT_CmMatrix4x4(const double value[16])
+MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Scalar value[16])
{
for (int i=0;i<16;i++)
m_Vflat[i] = value[i];
@@ -148,21 +148,21 @@ void MT_CmMatrix4x4::SetMatrix(const MT_CmMatrix4x4& other)
-double* MT_CmMatrix4x4::getPointer()
+MT_Scalar* MT_CmMatrix4x4::getPointer()
{
return &m_V[0][0];
}
-const double* MT_CmMatrix4x4::getPointer() const
+const MT_Scalar* MT_CmMatrix4x4::getPointer() const
{
return &m_V[0][0];
}
-void MT_CmMatrix4x4::setElem(int pos,double newvalue)
+void MT_CmMatrix4x4::setElem(int pos,MT_Scalar newvalue)
{
m_Vflat[pos] = newvalue;
}
@@ -179,28 +179,28 @@ MT_CmMatrix4x4 MT_CmMatrix4x4::Perspective(
MT_CmMatrix4x4 mat;
// Column 0
- mat(0, 0) = -(2.0*inNear) / (inRight-inLeft);
- mat(1, 0) = 0;
- mat(2, 0) = 0;
- mat(3, 0) = 0;
+ mat(0, 0) = -(2.0f*inNear) / (inRight-inLeft);
+ mat(1, 0) = 0.0f;
+ mat(2, 0) = 0.0f;
+ mat(3, 0) = 0.0f;
// Column 1
- mat(0, 1) = 0;
- mat(1, 1) = (2.0*inNear) / (inTop-inBottom);
- mat(2, 1) = 0;
- mat(3, 1) = 0;
+ mat(0, 1) = 0.0f;
+ mat(1, 1) = (2.0f*inNear) / (inTop-inBottom);
+ mat(2, 1) = 0.0f;
+ mat(3, 1) = 0.0f;
// Column 2
mat(0, 2) = (inRight+inLeft) / (inRight-inLeft);
mat(1, 2) = (inTop+inBottom) / (inTop-inBottom);
mat(2, 2) = -(inFar+inNear) / (inFar-inNear);
- mat(3, 2) = -1;
+ mat(3, 2) = -1.0f;
// Column 3
- mat(0, 3) = 0;
- mat(1, 3) = 0;
- mat(2, 3) = -(2.0*inFar*inNear) / (inFar-inNear);
- mat(3, 3) = 0;
+ mat(0, 3) = 0.0f;
+ mat(1, 3) = 0.0f;
+ mat(2, 3) = -(2.0f*inFar*inNear) / (inFar-inNear);
+ mat(3, 3) = 0.0f;
return mat;
}
diff --git a/intern/moto/intern/MT_Plane3.cpp b/intern/moto/intern/MT_Plane3.cpp
deleted file mode 100644
index 22f7cfdbded..00000000000
--- a/intern/moto/intern/MT_Plane3.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file moto/intern/MT_Plane3.cpp
- * \ingroup moto
- */
-
-
-#ifndef GEN_INLINED
-#include "MT_Plane3.h"
-#include "MT_Plane3.inl"
-#endif
-
diff --git a/intern/moto/intern/MT_Transform.cpp b/intern/moto/intern/MT_Transform.cpp
index 13dd31b7667..49a75b78e46 100644
--- a/intern/moto/intern/MT_Transform.cpp
+++ b/intern/moto/intern/MT_Transform.cpp
@@ -68,7 +68,7 @@ void MT_Transform::setValue(const double *m) {
void MT_Transform::getValue(float *m) const {
m_basis.getValue(m);
m_origin.getValue(&m[12]);
- m[15] = 1.0;
+ m[15] = 1.0f;
}
void MT_Transform::getValue(double *m) const {
@@ -101,7 +101,7 @@ void MT_Transform::scale(MT_Scalar x, MT_Scalar y, MT_Scalar z) {
void MT_Transform::setIdentity() {
m_basis.setIdentity();
- m_origin.setValue(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(0.0));
+ m_origin.setValue(MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(0.0f));
m_type = IDENTITY;
}
diff --git a/intern/opencolorio/SConscript b/intern/opencolorio/SConscript
deleted file mode 100644
index 6be6a5ed90c..00000000000
--- a/intern/opencolorio/SConscript
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2012, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Sergey Sharybin.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-sources = env.Glob('*.cc')
-
-incs = '. ../guardedalloc ../../source/blender/blenlib'
-defs = []
-
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_OCIO']:
- defs.append('WITH_OCIO')
- incs += ' ' + env['BF_OCIO_INC']
- incs += ' ' + env['BF_GLEW_INC']
- incs += ' ' + '#/intern/glew-mx'
-
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- incs += ' ' + env['BF_BOOST_INC']
-
- # generated data files
- import os
- sources.extend((
- os.path.join(env['DATA_SOURCES'], "gpu_shader_display_transform.glsl.c"),
- ))
-
-else:
- sources.remove('ocio_impl.cc')
- sources.remove('ocio_impl_glsl.cc')
-
-env.BlenderLib( 'bf_intern_opencolorio', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185])
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index bf5590077ef..82536a74159 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -29,7 +29,14 @@
#include <sstream>
#include <string.h>
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4251 4275)
+#endif
#include <OpenColorIO/OpenColorIO.h>
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
using namespace OCIO_NAMESPACE;
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index de89ea72f3c..bf91ea143da 100644
--- a/intern/opencolorio/ocio_impl_glsl.cc
+++ b/intern/opencolorio/ocio_impl_glsl.cc
@@ -39,7 +39,15 @@
#include "glew-mx.h"
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4251 4275)
+#endif
#include <OpenColorIO/OpenColorIO.h>
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
using namespace OCIO_NAMESPACE;
@@ -221,8 +229,8 @@ static bool ensureCurveMappingAllocated(OCIO_GLSLDrawState *state, OCIO_CurveMap
/* Detect if we can support GLSL drawing */
bool OCIOImpl::supportGLSLDraw()
{
- /* GLSL and GL_RGB16F_ARB */
- return GLEW_VERSION_2_0 && (GLEW_VERSION_3_0 || GLEW_ARB_texture_float);
+ /* uses GL_RGB16F_ARB */
+ return GLEW_VERSION_3_0 || GLEW_ARB_texture_float;
}
static bool supportGLSL13()
diff --git a/intern/opennl/CMakeLists.txt b/intern/opennl/CMakeLists.txt
deleted file mode 100644
index af8fde8572b..00000000000
--- a/intern/opennl/CMakeLists.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Jacques Beaurain.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# External project, better not fix warnings.
-remove_strict_flags()
-
-# remove debug flag here since this is not a blender maintained library
-# and debug gives a lot of prints on UV unwrapping. developers can enable if they need to.
-if(MSVC)
- remove_definitions(-DDEBUG)
-else()
- add_definitions(-UDEBUG)
-endif()
-
-
-# quiet compiler warnings about undefined defines
-add_definitions(
- -DDEBUGlevel=0
- -DPRNTlevel=0
-)
-
-set(INC
- extern
- superlu
-)
-
-set(INC_SYS
- ../../extern/colamd/Include
-)
-
-set(SRC
- intern/opennl.c
- superlu/get_perm_c.c
- superlu/heap_relax_snode.c
- superlu/lsame.c
- superlu/memory.c
- superlu/mmd.c
- superlu/relax_snode.c
- superlu/scolumn_bmod.c
- superlu/scolumn_dfs.c
- superlu/scopy_to_ucol.c
- superlu/sgssv.c
- superlu/sgstrf.c
- superlu/sgstrs.c
- superlu/smemory.c
- superlu/smyblas2.c
- superlu/sp_coletree.c
- superlu/sp_ienv.c
- superlu/sp_preorder.c
- superlu/spanel_bmod.c
- superlu/spanel_dfs.c
- superlu/spivotL.c
- superlu/spruneL.c
- superlu/ssnode_bmod.c
- superlu/ssnode_dfs.c
- superlu/ssp_blas2.c
- superlu/ssp_blas3.c
- superlu/strsv.c
- superlu/superlu_timer.c
- superlu/sutil.c
- superlu/util.c
- superlu/xerbla.c
-
- extern/ONL_opennl.h
- superlu/Cnames.h
- superlu/ssp_defs.h
- superlu/supermatrix.h
- superlu/util.h
-)
-
-blender_add_lib(bf_intern_opennl "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/opennl/SConscript b/intern/opennl/SConscript
deleted file mode 100644
index f47dd560779..00000000000
--- a/intern/opennl/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c') + env.Glob('superlu/*.c')
-
-incs = 'extern superlu ../../extern/colamd/Include'
-
-env.BlenderLib ('bf_intern_opennl', sources, Split(incs), [], libtype=['intern','player'], priority=[100,90] )
-
diff --git a/intern/opennl/doc/OpenNL_License.txt b/intern/opennl/doc/OpenNL_License.txt
deleted file mode 100644
index 4e8d97fd526..00000000000
--- a/intern/opennl/doc/OpenNL_License.txt
+++ /dev/null
@@ -1,341 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-
- END OF TERMS AND CONDITIONS
-
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
-
diff --git a/intern/opennl/doc/OpenNL_Readme.txt b/intern/opennl/doc/OpenNL_Readme.txt
deleted file mode 100644
index e6aea3c0286..00000000000
--- a/intern/opennl/doc/OpenNL_Readme.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-
-This is OpenNL, a library to easily construct and solve sparse linear systems.
-* OpenNL is supplied with a set of iterative solvers (Conjugate gradient,
- BICGSTAB, GMRes) and preconditioners (Jacobi, SSOR).
-* OpenNL can also use other solvers (SuperLU 3.0 supported as an OpenNL
- extension)
-
-Note that to be compatible with OpenNL, SuperLU 3.0 needs to be compiled with
-the following flag (see make.inc in SuperLU3.0):
-CDEFS = -DAdd_ (the default is -DAdd__, just remove the second underscore)
-
-OpenNL was modified for Blender to be used only as a wrapper for SuperLU.
-
diff --git a/intern/opennl/doc/SuperLU_License.txt b/intern/opennl/doc/SuperLU_License.txt
deleted file mode 100644
index f31a01782e2..00000000000
--- a/intern/opennl/doc/SuperLU_License.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-Copyright (c) 2003, The Regents of the University of California, through
-Lawrence Berkeley National Laboratory (subject to receipt of any required
-approvals from U.S. Dept. of Energy)
-
-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) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of
-Energy nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/intern/opennl/doc/SuperLU_Readme.txt b/intern/opennl/doc/SuperLU_Readme.txt
deleted file mode 100644
index c1cedd09893..00000000000
--- a/intern/opennl/doc/SuperLU_Readme.txt
+++ /dev/null
@@ -1,52 +0,0 @@
- SuperLU (Version 3.0)
- =====================
-
-Copyright (c) 2003, The Regents of the University of California, through
-Lawrence Berkeley National Laboratory (subject to receipt of any required
-approvals from U.S. Dept. of Energy)
-
-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) Neither the name of Lawrence Berkeley National Laboratory, U.S. Dept. of
-Energy nor the names of its contributors may be used to endorse or promote
-products derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-SuperLU contains a set of subroutines to solve a sparse linear system
-A*X=B. It uses Gaussian elimination with partial pivoting (GEPP).
-The columns of A may be preordered before factorization; the
-preordering for sparsity is completely separate from the factorization.
-
-SuperLU is implemented in ANSI C, and must be compiled with standard
-ANSI C compilers. It provides functionality for both real and complex
-matrices, in both single and double precision. The file names for the
-single-precision real version start with letter "s" (such as sgstrf.c);
-the file names for the double-precision real version start with letter "d"
-(such as dgstrf.c); the file names for the single-precision complex
-version start with letter "c" (such as cgstrf.c); the file names
-for the double-precision complex version start with letter "z"
-(such as zgstrf.c).
-
-SuperLU was modified for Blender to only include single-precision
-functionality.
-
diff --git a/intern/opennl/extern/ONL_opennl.h b/intern/opennl/extern/ONL_opennl.h
deleted file mode 100644
index c89a4aaf1f4..00000000000
--- a/intern/opennl/extern/ONL_opennl.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/** \file opennl/extern/ONL_opennl.h
- * \ingroup opennlextern
- */
-/*
- * OpenNL: Numerical Library
- * Copyright (C) 2004 Bruno Levy
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * If you modify this software, you should include a notice giving the
- * name of the person performing the modification, the date of modification,
- * and the reason for such modification.
- *
- * Contact: Bruno Levy
- *
- * levy@loria.fr
- *
- * ISA Project
- * LORIA, INRIA Lorraine,
- * Campus Scientifique, BP 239
- * 54506 VANDOEUVRE LES NANCY CEDEX
- * FRANCE
- *
- * Note that the GNU General Public License does not permit incorporating
- * the Software into proprietary programs.
- */
-
-/*
-#define NL_DEBUG
-#define NL_PARANOID
-*/
-
-#define NL_USE_SUPERLU
-
-#ifndef nlOPENNL_H
-#define nlOPENNL_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define NL_VERSION_0_0 1
-
-/* Datatypes */
-
-typedef unsigned int NLenum;
-typedef unsigned char NLboolean;
-typedef unsigned int NLbitfield;
-typedef void NLvoid;
-typedef signed char NLbyte; /* 1-byte signed */
-typedef short NLshort; /* 2-byte signed */
-typedef int NLint; /* 4-byte signed */
-typedef unsigned char NLubyte; /* 1-byte unsigned */
-typedef unsigned short NLushort; /* 2-byte unsigned */
-typedef unsigned int NLuint; /* 4-byte unsigned */
-typedef int NLsizei; /* 4-byte signed */
-typedef float NLfloat; /* single precision float */
-typedef double NLdouble; /* double precision float */
-
-typedef void* NLContext;
-
-/* Constants */
-
-#define NL_FALSE 0x0
-#define NL_TRUE 0x1
-
-/* Primitives */
-
-#define NL_SYSTEM 0x0
-#define NL_MATRIX 0x1
-
-/* Solver Parameters */
-
-#define NL_SOLVER 0x100
-#define NL_NB_VARIABLES 0x101
-#define NL_LEAST_SQUARES 0x102
-#define NL_SYMMETRIC 0x106
-#define NL_ERROR 0x108
-#define NL_NB_ROWS 0x110
-#define NL_NB_RIGHT_HAND_SIDES 0x112 /* 4 max */
-
-/* Contexts */
-
-NLContext nlNewContext(void);
-void nlDeleteContext(NLContext context);
-void nlMakeCurrent(NLContext context);
-NLContext nlGetCurrent(void);
-
-/* State get/set */
-
-void nlSolverParameterf(NLenum pname, NLdouble param);
-void nlSolverParameteri(NLenum pname, NLint param);
-
-void nlGetBooleanv(NLenum pname, NLboolean* params);
-void nlGetFloatv(NLenum pname, NLdouble* params);
-void nlGetIntergerv(NLenum pname, NLint* params);
-
-void nlEnable(NLenum pname);
-void nlDisable(NLenum pname);
-NLboolean nlIsEnabled(NLenum pname);
-
-/* Variables */
-
-void nlSetVariable(NLuint rhsindex, NLuint index, NLdouble value);
-NLdouble nlGetVariable(NLuint rhsindex, NLuint index);
-void nlLockVariable(NLuint index);
-void nlUnlockVariable(NLuint index);
-NLboolean nlVariableIsLocked(NLuint index);
-
-/* Begin/End */
-
-void nlBegin(NLenum primitive);
-void nlEnd(NLenum primitive);
-
-/* Setting elements in matrix/vector */
-
-void nlMatrixAdd(NLuint row, NLuint col, NLdouble value);
-void nlRightHandSideAdd(NLuint rhsindex, NLuint index, NLdouble value);
-void nlRightHandSideSet(NLuint rhsindex, NLuint index, NLdouble value);
-
-/* Solve */
-
-void nlPrintMatrix(void);
-NLboolean nlSolve(void);
-NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/intern/opennl/intern/opennl.c b/intern/opennl/intern/opennl.c
deleted file mode 100644
index 8cf4bf1327b..00000000000
--- a/intern/opennl/intern/opennl.c
+++ /dev/null
@@ -1,1270 +0,0 @@
-/** \file opennl/intern/opennl.c
- * \ingroup opennlintern
- */
-/*
- *
- * OpenNL: Numerical Library
- * Copyright (C) 2004 Bruno Levy
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * If you modify this software, you should include a notice giving the
- * name of the person performing the modification, the date of modification,
- * and the reason for such modification.
- *
- * Contact: Bruno Levy
- *
- * levy@loria.fr
- *
- * ISA Project
- * LORIA, INRIA Lorraine,
- * Campus Scientifique, BP 239
- * 54506 VANDOEUVRE LES NANCY CEDEX
- * FRANCE
- *
- * Note that the GNU General Public License does not permit incorporating
- * the Software into proprietary programs.
- */
-
-#include "ONL_opennl.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#ifdef NL_PARANOID
-#ifndef NL_DEBUG
-#define NL_DEBUG
-#endif
-#endif
-
-/* SuperLU includes */
-#include <ssp_defs.h>
-#include <util.h>
-
-/************************************************************************************/
-/* Assertions */
-
-
-static void __nl_assertion_failed(char* cond, char* file, int line) {
- fprintf(
- stderr,
- "OpenNL assertion failed: %s, file:%s, line:%d\n",
- cond,file,line
- );
- abort();
-}
-
-static void __nl_range_assertion_failed(
- double x, double min_val, double max_val, char* file, int line
-) {
- fprintf(
- stderr,
- "OpenNL range assertion failed: %f in [ %f ... %f ], file:%s, line:%d\n",
- x, min_val, max_val, file,line
- );
- abort();
-}
-
-static void __nl_should_not_have_reached(char* file, int line) {
- fprintf(
- stderr,
- "OpenNL should not have reached this point: file:%s, line:%d\n",
- file,line
- );
- abort();
-}
-
-
-#define __nl_assert(x) { \
- if(!(x)) { \
- __nl_assertion_failed(#x,__FILE__, __LINE__); \
- } \
-}
-
-#define __nl_range_assert(x,min_val,max_val) { \
- if(((x) < (min_val)) || ((x) > (max_val))) { \
- __nl_range_assertion_failed(x, min_val, max_val, \
- __FILE__, __LINE__ \
- ); \
- } \
-}
-
-#define __nl_assert_not_reached { \
- __nl_should_not_have_reached(__FILE__, __LINE__); \
-}
-
-#ifdef NL_DEBUG
-#define __nl_debug_assert(x) __nl_assert(x)
-#define __nl_debug_range_assert(x,min_val,max_val) __nl_range_assert(x,min_val,max_val)
-#else
-#define __nl_debug_assert(x)
-#define __nl_debug_range_assert(x,min_val,max_val)
-#endif
-
-#ifdef NL_PARANOID
-#define __nl_parano_assert(x) __nl_assert(x)
-#define __nl_parano_range_assert(x,min_val,max_val) __nl_range_assert(x,min_val,max_val)
-#else
-#define __nl_parano_assert(x)
-#define __nl_parano_range_assert(x,min_val,max_val)
-#endif
-
-/************************************************************************************/
-/* classic macros */
-
-#ifndef MIN
-#define MIN(x,y) (((x) < (y)) ? (x) : (y))
-#endif
-
-#ifndef MAX
-#define MAX(x,y) (((x) > (y)) ? (x) : (y))
-#endif
-
-/************************************************************************************/
-/* memory management */
-
-#define __NL_NEW(T) (T*)(calloc(1, sizeof(T)))
-#define __NL_NEW_ARRAY(T,NB) (T*)(calloc(MAX(NB, 1),sizeof(T)))
-#define __NL_RENEW_ARRAY(T,x,NB) (T*)(realloc(x,(NB)*sizeof(T)))
-#define __NL_DELETE(x) if(x) free(x); x = NULL
-#define __NL_DELETE_ARRAY(x) if(x) free(x); x = NULL
-
-#define __NL_CLEAR(T, x) memset(x, 0, sizeof(T))
-#define __NL_CLEAR_ARRAY(T,x,NB) if(NB) memset(x, 0, (NB)*sizeof(T))
-
-/************************************************************************************/
-/* Dynamic arrays for sparse row/columns */
-
-typedef struct {
- NLuint index;
- NLdouble value;
-} __NLCoeff;
-
-typedef struct {
- NLuint size;
- NLuint capacity;
- __NLCoeff* coeff;
-} __NLRowColumn;
-
-static void __nlRowColumnConstruct(__NLRowColumn* c) {
- c->size = 0;
- c->capacity = 0;
- c->coeff = NULL;
-}
-
-static void __nlRowColumnDestroy(__NLRowColumn* c) {
- __NL_DELETE_ARRAY(c->coeff);
-#ifdef NL_PARANOID
- __NL_CLEAR(__NLRowColumn, c);
-#endif
-}
-
-static void __nlRowColumnGrow(__NLRowColumn* c) {
- if(c->capacity != 0) {
- c->capacity = 2 * c->capacity;
- c->coeff = __NL_RENEW_ARRAY(__NLCoeff, c->coeff, c->capacity);
- } else {
- c->capacity = 4;
- c->coeff = __NL_NEW_ARRAY(__NLCoeff, c->capacity);
- }
-}
-
-static void __nlRowColumnAdd(__NLRowColumn* c, NLint index, NLdouble value) {
- NLuint i;
- for(i=0; i<c->size; i++) {
- if(c->coeff[i].index == (NLuint)index) {
- c->coeff[i].value += value;
- return;
- }
- }
- if(c->size == c->capacity) {
- __nlRowColumnGrow(c);
- }
- c->coeff[c->size].index = index;
- c->coeff[c->size].value = value;
- c->size++;
-}
-
-/* Does not check whether the index already exists */
-static void __nlRowColumnAppend(__NLRowColumn* c, NLint index, NLdouble value) {
- if(c->size == c->capacity) {
- __nlRowColumnGrow(c);
- }
- c->coeff[c->size].index = index;
- c->coeff[c->size].value = value;
- c->size++;
-}
-
-static void __nlRowColumnClear(__NLRowColumn* c) {
- c->size = 0;
- c->capacity = 0;
- __NL_DELETE_ARRAY(c->coeff);
-}
-
-/************************************************************************************/
-/* SparseMatrix data structure */
-
-#define __NL_ROWS 1
-#define __NL_COLUMNS 2
-#define __NL_SYMMETRIC 4
-
-typedef struct {
- NLuint m;
- NLuint n;
- NLuint diag_size;
- NLenum storage;
- __NLRowColumn* row;
- __NLRowColumn* column;
- NLdouble* diag;
-} __NLSparseMatrix;
-
-
-static void __nlSparseMatrixConstruct(
- __NLSparseMatrix* M, NLuint m, NLuint n, NLenum storage
-) {
- NLuint i;
- M->m = m;
- M->n = n;
- M->storage = storage;
- if(storage & __NL_ROWS) {
- M->row = __NL_NEW_ARRAY(__NLRowColumn, m);
- for(i=0; i<m; i++) {
- __nlRowColumnConstruct(&(M->row[i]));
- }
- } else {
- M->row = NULL;
- }
-
- if(storage & __NL_COLUMNS) {
- M->column = __NL_NEW_ARRAY(__NLRowColumn, n);
- for(i=0; i<n; i++) {
- __nlRowColumnConstruct(&(M->column[i]));
- }
- } else {
- M->column = NULL;
- }
-
- M->diag_size = MIN(m,n);
- M->diag = __NL_NEW_ARRAY(NLdouble, M->diag_size);
-}
-
-static void __nlSparseMatrixDestroy(__NLSparseMatrix* M) {
- NLuint i;
- __NL_DELETE_ARRAY(M->diag);
- if(M->storage & __NL_ROWS) {
- for(i=0; i<M->m; i++) {
- __nlRowColumnDestroy(&(M->row[i]));
- }
- __NL_DELETE_ARRAY(M->row);
- }
- if(M->storage & __NL_COLUMNS) {
- for(i=0; i<M->n; i++) {
- __nlRowColumnDestroy(&(M->column[i]));
- }
- __NL_DELETE_ARRAY(M->column);
- }
-#ifdef NL_PARANOID
- __NL_CLEAR(__NLSparseMatrix,M);
-#endif
-}
-
-static void __nlSparseMatrixAdd(
- __NLSparseMatrix* M, NLuint i, NLuint j, NLdouble value
-) {
- __nl_parano_range_assert(i, 0, M->m - 1);
- __nl_parano_range_assert(j, 0, M->n - 1);
- if((M->storage & __NL_SYMMETRIC) && (j > i)) {
- return;
- }
- if(i == j) {
- M->diag[i] += value;
- }
- if(M->storage & __NL_ROWS) {
- __nlRowColumnAdd(&(M->row[i]), j, value);
- }
- if(M->storage & __NL_COLUMNS) {
- __nlRowColumnAdd(&(M->column[j]), i, value);
- }
-}
-
-static void __nlSparseMatrixClear( __NLSparseMatrix* M) {
- NLuint i;
- if(M->storage & __NL_ROWS) {
- for(i=0; i<M->m; i++) {
- __nlRowColumnClear(&(M->row[i]));
- }
- }
- if(M->storage & __NL_COLUMNS) {
- for(i=0; i<M->n; i++) {
- __nlRowColumnClear(&(M->column[i]));
- }
- }
- __NL_CLEAR_ARRAY(NLdouble, M->diag, M->diag_size);
-}
-
-/* Returns the number of non-zero coefficients */
-static NLuint __nlSparseMatrixNNZ( __NLSparseMatrix* M) {
- NLuint nnz = 0;
- NLuint i;
- if(M->storage & __NL_ROWS) {
- for(i = 0; i<M->m; i++) {
- nnz += M->row[i].size;
- }
- } else if (M->storage & __NL_COLUMNS) {
- for(i = 0; i<M->n; i++) {
- nnz += M->column[i].size;
- }
- } else {
- __nl_assert_not_reached;
- }
- return nnz;
-}
-
-/************************************************************************************/
-/* SparseMatrix x Vector routines, internal helper routines */
-
-static void __nlSparseMatrix_mult_rows_symmetric(
- __NLSparseMatrix* A, NLdouble* x, NLdouble* y
-) {
- NLuint m = A->m;
- NLuint i,ij;
- __NLRowColumn* Ri = NULL;
- __NLCoeff* c = NULL;
- for(i=0; i<m; i++) {
- y[i] = 0;
- Ri = &(A->row[i]);
- for(ij=0; ij<Ri->size; ij++) {
- c = &(Ri->coeff[ij]);
- y[i] += c->value * x[c->index];
- if(i != c->index) {
- y[c->index] += c->value * x[i];
- }
- }
- }
-}
-
-static void __nlSparseMatrix_mult_rows(
- __NLSparseMatrix* A, NLdouble* x, NLdouble* y
-) {
- NLuint m = A->m;
- NLuint i,ij;
- __NLRowColumn* Ri = NULL;
- __NLCoeff* c = NULL;
- for(i=0; i<m; i++) {
- y[i] = 0;
- Ri = &(A->row[i]);
- for(ij=0; ij<Ri->size; ij++) {
- c = &(Ri->coeff[ij]);
- y[i] += c->value * x[c->index];
- }
- }
-}
-
-static void __nlSparseMatrix_mult_cols_symmetric(
- __NLSparseMatrix* A, NLdouble* x, NLdouble* y
-) {
- NLuint n = A->n;
- NLuint j,ii;
- __NLRowColumn* Cj = NULL;
- __NLCoeff* c = NULL;
- for(j=0; j<n; j++) {
- y[j] = 0;
- Cj = &(A->column[j]);
- for(ii=0; ii<Cj->size; ii++) {
- c = &(Cj->coeff[ii]);
- y[c->index] += c->value * x[j];
- if(j != c->index) {
- y[j] += c->value * x[c->index];
- }
- }
- }
-}
-
-static void __nlSparseMatrix_mult_cols(
- __NLSparseMatrix* A, NLdouble* x, NLdouble* y
-) {
- NLuint n = A->n;
- NLuint j,ii;
- __NLRowColumn* Cj = NULL;
- __NLCoeff* c = NULL;
- __NL_CLEAR_ARRAY(NLdouble, y, A->m);
- for(j=0; j<n; j++) {
- Cj = &(A->column[j]);
- for(ii=0; ii<Cj->size; ii++) {
- c = &(Cj->coeff[ii]);
- y[c->index] += c->value * x[j];
- }
- }
-}
-
-/************************************************************************************/
-/* SparseMatrix x Vector routines, main driver routine */
-
-static void __nlSparseMatrixMult(__NLSparseMatrix* A, NLdouble* x, NLdouble* y) {
- if(A->storage & __NL_ROWS) {
- if(A->storage & __NL_SYMMETRIC) {
- __nlSparseMatrix_mult_rows_symmetric(A, x, y);
- } else {
- __nlSparseMatrix_mult_rows(A, x, y);
- }
- } else {
- if(A->storage & __NL_SYMMETRIC) {
- __nlSparseMatrix_mult_cols_symmetric(A, x, y);
- } else {
- __nlSparseMatrix_mult_cols(A, x, y);
- }
- }
-}
-
-/* ****************** Routines for least squares ******************* */
-
-static void __nlSparseMatrix_square(
- __NLSparseMatrix* AtA, __NLSparseMatrix *A
-) {
- NLuint m = A->m;
- NLuint n = A->n;
- NLuint i, j0, j1;
- __NLRowColumn *Ri = NULL;
- __NLCoeff *c0 = NULL, *c1 = NULL;
- double value;
-
- __nlSparseMatrixConstruct(AtA, n, n, A->storage);
-
- for(i=0; i<m; i++) {
- Ri = &(A->row[i]);
-
- for(j0=0; j0<Ri->size; j0++) {
- c0 = &(Ri->coeff[j0]);
- for(j1=0; j1<Ri->size; j1++) {
- c1 = &(Ri->coeff[j1]);
-
- value = c0->value*c1->value;
- __nlSparseMatrixAdd(AtA, c0->index, c1->index, value);
- }
- }
- }
-}
-
-static void __nlSparseMatrix_transpose_mult_rows(
- __NLSparseMatrix* A, NLdouble* x, NLdouble* y
-) {
- NLuint m = A->m;
- NLuint n = A->n;
- NLuint i,ij;
- __NLRowColumn* Ri = NULL;
- __NLCoeff* c = NULL;
-
- __NL_CLEAR_ARRAY(NLdouble, y, n);
-
- for(i=0; i<m; i++) {
- Ri = &(A->row[i]);
- for(ij=0; ij<Ri->size; ij++) {
- c = &(Ri->coeff[ij]);
- y[c->index] += c->value * x[i];
- }
- }
-}
-
-/************************************************************************************/
-/* NLContext data structure */
-
-typedef void(*__NLMatrixFunc)(double* x, double* y);
-
-typedef struct {
- NLdouble value[4];
- NLboolean locked;
- NLuint index;
- __NLRowColumn *a;
-} __NLVariable;
-
-#define __NL_STATE_INITIAL 0
-#define __NL_STATE_SYSTEM 1
-#define __NL_STATE_MATRIX 2
-#define __NL_STATE_MATRIX_CONSTRUCTED 3
-#define __NL_STATE_SYSTEM_CONSTRUCTED 4
-#define __NL_STATE_SYSTEM_SOLVED 5
-
-typedef struct {
- NLenum state;
- NLuint n;
- NLuint m;
- __NLVariable* variable;
- NLdouble* b;
- NLdouble* Mtb;
- __NLSparseMatrix M;
- __NLSparseMatrix MtM;
- NLdouble* x;
- NLuint nb_variables;
- NLuint nb_rows;
- NLboolean least_squares;
- NLboolean symmetric;
- NLuint nb_rhs;
- NLboolean solve_again;
- NLboolean alloc_M;
- NLboolean alloc_MtM;
- NLboolean alloc_variable;
- NLboolean alloc_x;
- NLboolean alloc_b;
- NLboolean alloc_Mtb;
- NLdouble error;
- __NLMatrixFunc matrix_vector_prod;
-
- struct __NLSuperLUContext {
- NLboolean alloc_slu;
- SuperMatrix L, U;
- NLint *perm_c, *perm_r;
- SuperLUStat_t stat;
- } slu;
-} __NLContext;
-
-static __NLContext* __nlCurrentContext = NULL;
-
-static void __nlMatrixVectorProd_default(NLdouble* x, NLdouble* y) {
- __nlSparseMatrixMult(&(__nlCurrentContext->M), x, y);
-}
-
-
-NLContext nlNewContext(void) {
- __NLContext* result = __NL_NEW(__NLContext);
- result->state = __NL_STATE_INITIAL;
- result->matrix_vector_prod = __nlMatrixVectorProd_default;
- result->nb_rhs = 1;
- nlMakeCurrent(result);
- return result;
-}
-
-static void __nlFree_SUPERLU(__NLContext *context);
-
-void nlDeleteContext(NLContext context_in) {
- __NLContext* context = (__NLContext*)(context_in);
- int i;
-
- if(__nlCurrentContext == context) {
- __nlCurrentContext = NULL;
- }
- if(context->alloc_M) {
- __nlSparseMatrixDestroy(&context->M);
- }
- if(context->alloc_MtM) {
- __nlSparseMatrixDestroy(&context->MtM);
- }
- if(context->alloc_variable) {
- for(i=0; i<context->nb_variables; i++) {
- if(context->variable[i].a) {
- __nlRowColumnDestroy(context->variable[i].a);
- __NL_DELETE(context->variable[i].a);
- }
- }
-
- __NL_DELETE_ARRAY(context->variable);
- }
- if(context->alloc_b) {
- __NL_DELETE_ARRAY(context->b);
- }
- if(context->alloc_Mtb) {
- __NL_DELETE_ARRAY(context->Mtb);
- }
- if(context->alloc_x) {
- __NL_DELETE_ARRAY(context->x);
- }
- if (context->slu.alloc_slu) {
- __nlFree_SUPERLU(context);
- }
-
-#ifdef NL_PARANOID
- __NL_CLEAR(__NLContext, context);
-#endif
- __NL_DELETE(context);
-}
-
-void nlMakeCurrent(NLContext context) {
- __nlCurrentContext = (__NLContext*)(context);
-}
-
-NLContext nlGetCurrent(void) {
- return __nlCurrentContext;
-}
-
-static void __nlCheckState(NLenum state) {
- __nl_assert(__nlCurrentContext->state == state);
-}
-
-static void __nlTransition(NLenum from_state, NLenum to_state) {
- __nlCheckState(from_state);
- __nlCurrentContext->state = to_state;
-}
-
-/************************************************************************************/
-/* Get/Set parameters */
-
-void nlSolverParameterf(NLenum pname, NLdouble param) {
- __nlCheckState(__NL_STATE_INITIAL);
- switch(pname) {
- case NL_NB_VARIABLES: {
- __nl_assert(param > 0);
- __nlCurrentContext->nb_variables = (NLuint)param;
- } break;
- case NL_NB_ROWS: {
- __nl_assert(param > 0);
- __nlCurrentContext->nb_rows = (NLuint)param;
- } break;
- case NL_LEAST_SQUARES: {
- __nlCurrentContext->least_squares = (NLboolean)param;
- } break;
- case NL_SYMMETRIC: {
- __nlCurrentContext->symmetric = (NLboolean)param;
- } break;
- case NL_NB_RIGHT_HAND_SIDES: {
- __nlCurrentContext->nb_rhs = (NLuint)param;
- } break;
- default: {
- __nl_assert_not_reached;
- } break;
- }
-}
-
-void nlSolverParameteri(NLenum pname, NLint param) {
- __nlCheckState(__NL_STATE_INITIAL);
- switch(pname) {
- case NL_NB_VARIABLES: {
- __nl_assert(param > 0);
- __nlCurrentContext->nb_variables = (NLuint)param;
- } break;
- case NL_NB_ROWS: {
- __nl_assert(param > 0);
- __nlCurrentContext->nb_rows = (NLuint)param;
- } break;
- case NL_LEAST_SQUARES: {
- __nlCurrentContext->least_squares = (NLboolean)param;
- } break;
- case NL_SYMMETRIC: {
- __nlCurrentContext->symmetric = (NLboolean)param;
- } break;
- case NL_NB_RIGHT_HAND_SIDES: {
- __nlCurrentContext->nb_rhs = (NLuint)param;
- } break;
- default: {
- __nl_assert_not_reached;
- } break;
- }
-}
-
-void nlGetBooleanv(NLenum pname, NLboolean* params) {
- switch(pname) {
- case NL_LEAST_SQUARES: {
- *params = __nlCurrentContext->least_squares;
- } break;
- case NL_SYMMETRIC: {
- *params = __nlCurrentContext->symmetric;
- } break;
- default: {
- __nl_assert_not_reached;
- } break;
- }
-}
-
-void nlGetFloatv(NLenum pname, NLdouble* params) {
- switch(pname) {
- case NL_NB_VARIABLES: {
- *params = (NLdouble)(__nlCurrentContext->nb_variables);
- } break;
- case NL_NB_ROWS: {
- *params = (NLdouble)(__nlCurrentContext->nb_rows);
- } break;
- case NL_LEAST_SQUARES: {
- *params = (NLdouble)(__nlCurrentContext->least_squares);
- } break;
- case NL_SYMMETRIC: {
- *params = (NLdouble)(__nlCurrentContext->symmetric);
- } break;
- case NL_ERROR: {
- *params = (NLdouble)(__nlCurrentContext->error);
- } break;
- default: {
- __nl_assert_not_reached;
- } break;
- }
-}
-
-void nlGetIntergerv(NLenum pname, NLint* params) {
- switch(pname) {
- case NL_NB_VARIABLES: {
- *params = (NLint)(__nlCurrentContext->nb_variables);
- } break;
- case NL_NB_ROWS: {
- *params = (NLint)(__nlCurrentContext->nb_rows);
- } break;
- case NL_LEAST_SQUARES: {
- *params = (NLint)(__nlCurrentContext->least_squares);
- } break;
- case NL_SYMMETRIC: {
- *params = (NLint)(__nlCurrentContext->symmetric);
- } break;
- default: {
- __nl_assert_not_reached;
- } break;
- }
-}
-
-/************************************************************************************/
-/* Enable / Disable */
-
-void nlEnable(NLenum pname) {
- switch(pname) {
- default: {
- __nl_assert_not_reached;
- }
- }
-}
-
-void nlDisable(NLenum pname) {
- switch(pname) {
- default: {
- __nl_assert_not_reached;
- }
- }
-}
-
-NLboolean nlIsEnabled(NLenum pname) {
- switch(pname) {
- default: {
- __nl_assert_not_reached;
- }
- }
- return NL_FALSE;
-}
-
-/************************************************************************************/
-/* Get/Set Lock/Unlock variables */
-
-void nlSetVariable(NLuint rhsindex, NLuint index, NLdouble value) {
- __nlCheckState(__NL_STATE_SYSTEM);
- __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1);
- __nlCurrentContext->variable[index].value[rhsindex] = value;
-}
-
-NLdouble nlGetVariable(NLuint rhsindex, NLuint index) {
- __nl_assert(__nlCurrentContext->state != __NL_STATE_INITIAL);
- __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1);
- return __nlCurrentContext->variable[index].value[rhsindex];
-}
-
-void nlLockVariable(NLuint index) {
- __nlCheckState(__NL_STATE_SYSTEM);
- __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1);
- __nlCurrentContext->variable[index].locked = NL_TRUE;
-}
-
-void nlUnlockVariable(NLuint index) {
- __nlCheckState(__NL_STATE_SYSTEM);
- __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1);
- __nlCurrentContext->variable[index].locked = NL_FALSE;
-}
-
-NLboolean nlVariableIsLocked(NLuint index) {
- __nl_assert(__nlCurrentContext->state != __NL_STATE_INITIAL);
- __nl_parano_range_assert(index, 0, __nlCurrentContext->nb_variables - 1);
- return __nlCurrentContext->variable[index].locked;
-}
-
-/************************************************************************************/
-/* System construction */
-
-static void __nlVariablesToVector() {
- __NLContext *context = __nlCurrentContext;
- NLuint i, j, nb_rhs;
-
- __nl_assert(context->alloc_x);
- __nl_assert(context->alloc_variable);
-
- nb_rhs= context->nb_rhs;
-
- for(i=0; i<context->nb_variables; i++) {
- __NLVariable* v = &(context->variable[i]);
- if(!v->locked) {
- __nl_assert(v->index < context->n);
-
- for(j=0; j<nb_rhs; j++)
- context->x[context->n*j + v->index] = v->value[j];
- }
- }
-}
-
-static void __nlVectorToVariables() {
- __NLContext *context = __nlCurrentContext;
- NLuint i, j, nb_rhs;
-
- __nl_assert(context->alloc_x);
- __nl_assert(context->alloc_variable);
-
- nb_rhs= context->nb_rhs;
-
- for(i=0; i<context->nb_variables; i++) {
- __NLVariable* v = &(context->variable[i]);
- if(!v->locked) {
- __nl_assert(v->index < context->n);
-
- for(j=0; j<nb_rhs; j++)
- v->value[j] = context->x[context->n*j + v->index];
- }
- }
-}
-
-static void __nlBeginSystem() {
- __nl_assert(__nlCurrentContext->nb_variables > 0);
-
- if (__nlCurrentContext->solve_again)
- __nlTransition(__NL_STATE_SYSTEM_SOLVED, __NL_STATE_SYSTEM);
- else {
- __nlTransition(__NL_STATE_INITIAL, __NL_STATE_SYSTEM);
-
- __nlCurrentContext->variable = __NL_NEW_ARRAY(
- __NLVariable, __nlCurrentContext->nb_variables);
-
- __nlCurrentContext->alloc_variable = NL_TRUE;
- }
-}
-
-static void __nlEndSystem() {
- __nlTransition(__NL_STATE_MATRIX_CONSTRUCTED, __NL_STATE_SYSTEM_CONSTRUCTED);
-}
-
-static void __nlBeginMatrix() {
- NLuint i;
- NLuint m = 0, n = 0;
- NLenum storage = __NL_ROWS;
- __NLContext *context = __nlCurrentContext;
-
- __nlTransition(__NL_STATE_SYSTEM, __NL_STATE_MATRIX);
-
- if (!context->solve_again) {
- for(i=0; i<context->nb_variables; i++) {
- if(context->variable[i].locked) {
- context->variable[i].index = ~0;
- context->variable[i].a = __NL_NEW(__NLRowColumn);
- __nlRowColumnConstruct(context->variable[i].a);
- }
- else
- context->variable[i].index = n++;
- }
-
- m = (context->nb_rows == 0)? n: context->nb_rows;
-
- context->m = m;
- context->n = n;
-
- __nlSparseMatrixConstruct(&context->M, m, n, storage);
- context->alloc_M = NL_TRUE;
-
- context->b = __NL_NEW_ARRAY(NLdouble, m*context->nb_rhs);
- context->alloc_b = NL_TRUE;
-
- context->x = __NL_NEW_ARRAY(NLdouble, n*context->nb_rhs);
- context->alloc_x = NL_TRUE;
- }
- else {
- /* need to recompute b only, A is not constructed anymore */
- __NL_CLEAR_ARRAY(NLdouble, context->b, context->m*context->nb_rhs);
- }
-
- __nlVariablesToVector();
-}
-
-static void __nlEndMatrixRHS(NLuint rhs) {
- __NLContext *context = __nlCurrentContext;
- __NLVariable *variable;
- __NLRowColumn *a;
- NLdouble *b, *Mtb;
- NLuint i, j;
-
- b = context->b + context->m*rhs;
- Mtb = context->Mtb + context->n*rhs;
-
- for(i=0; i<__nlCurrentContext->nb_variables; i++) {
- variable = &(context->variable[i]);
-
- if(variable->locked) {
- a = variable->a;
-
- for(j=0; j<a->size; j++) {
- b[a->coeff[j].index] -= a->coeff[j].value*variable->value[rhs];
- }
- }
- }
-
- if(context->least_squares)
- __nlSparseMatrix_transpose_mult_rows(&context->M, b, Mtb);
-}
-
-static void __nlEndMatrix() {
- __NLContext *context = __nlCurrentContext;
- NLuint i;
-
- __nlTransition(__NL_STATE_MATRIX, __NL_STATE_MATRIX_CONSTRUCTED);
-
- if(context->least_squares) {
- if(!__nlCurrentContext->solve_again) {
- __nlSparseMatrix_square(&context->MtM, &context->M);
- context->alloc_MtM = NL_TRUE;
-
- context->Mtb =
- __NL_NEW_ARRAY(NLdouble, context->n*context->nb_rhs);
- context->alloc_Mtb = NL_TRUE;
- }
- }
-
- for(i=0; i<context->nb_rhs; i++)
- __nlEndMatrixRHS(i);
-}
-
-void nlMatrixAdd(NLuint row, NLuint col, NLdouble value)
-{
- __NLContext *context = __nlCurrentContext;
-
- __nlCheckState(__NL_STATE_MATRIX);
-
- if(context->solve_again)
- return;
-
- if (!context->least_squares && context->variable[row].locked);
- else if (context->variable[col].locked) {
- if(!context->least_squares)
- row = context->variable[row].index;
- __nlRowColumnAppend(context->variable[col].a, row, value);
- }
- else {
- __NLSparseMatrix* M = &context->M;
-
- if(!context->least_squares)
- row = context->variable[row].index;
- col = context->variable[col].index;
-
- __nl_range_assert(row, 0, context->m - 1);
- __nl_range_assert(col, 0, context->n - 1);
-
- __nlSparseMatrixAdd(M, row, col, value);
- }
-}
-
-void nlRightHandSideAdd(NLuint rhsindex, NLuint index, NLdouble value)
-{
- __NLContext *context = __nlCurrentContext;
- NLdouble* b = context->b;
-
- __nlCheckState(__NL_STATE_MATRIX);
-
- if(context->least_squares) {
- __nl_range_assert(index, 0, context->m - 1);
- b[rhsindex*context->m + index] += value;
- }
- else {
- if(!context->variable[index].locked) {
- index = context->variable[index].index;
- __nl_range_assert(index, 0, context->m - 1);
-
- b[rhsindex*context->m + index] += value;
- }
- }
-}
-
-void nlRightHandSideSet(NLuint rhsindex, NLuint index, NLdouble value)
-{
- __NLContext *context = __nlCurrentContext;
- NLdouble* b = context->b;
-
- __nlCheckState(__NL_STATE_MATRIX);
-
- if(context->least_squares) {
- __nl_range_assert(index, 0, context->m - 1);
- b[rhsindex*context->m + index] = value;
- }
- else {
- if(!context->variable[index].locked) {
- index = context->variable[index].index;
- __nl_range_assert(index, 0, context->m - 1);
-
- b[rhsindex*context->m + index] = value;
- }
- }
-}
-
-void nlBegin(NLenum prim) {
- switch(prim) {
- case NL_SYSTEM: {
- __nlBeginSystem();
- } break;
- case NL_MATRIX: {
- __nlBeginMatrix();
- } break;
- default: {
- __nl_assert_not_reached;
- }
- }
-}
-
-void nlEnd(NLenum prim) {
- switch(prim) {
- case NL_SYSTEM: {
- __nlEndSystem();
- } break;
- case NL_MATRIX: {
- __nlEndMatrix();
- } break;
- default: {
- __nl_assert_not_reached;
- }
- }
-}
-
-/************************************************************************/
-/* SuperLU wrapper */
-
-/* Note: SuperLU is difficult to call, but it is worth it. */
-/* Here is a driver inspired by A. Sheffer's "cow flattener". */
-static NLboolean __nlFactorize_SUPERLU(__NLContext *context, NLint *permutation) {
-
- /* OpenNL Context */
- __NLSparseMatrix* M = (context->least_squares)? &context->MtM: &context->M;
- NLuint n = context->n;
- NLuint nnz = __nlSparseMatrixNNZ(M); /* number of non-zero coeffs */
-
- /*if(n > 10)
- n = 10;*/
-
- /* Compressed Row Storage matrix representation */
- NLint *xa = __NL_NEW_ARRAY(NLint, n+1);
- NLdouble *rhs = __NL_NEW_ARRAY(NLdouble, n);
- NLdouble *a = __NL_NEW_ARRAY(NLdouble, nnz);
- NLint *asub = __NL_NEW_ARRAY(NLint, nnz);
- NLint *etree = __NL_NEW_ARRAY(NLint, n);
-
- /* SuperLU variables */
- SuperMatrix At, AtP;
- NLint info, panel_size, relax;
- superlu_options_t options;
-
- /* Temporary variables */
- NLuint i, jj, count;
-
- __nl_assert(!(M->storage & __NL_SYMMETRIC));
- __nl_assert(M->storage & __NL_ROWS);
- __nl_assert(M->m == M->n);
-
- /* Convert M to compressed column format */
- for(i=0, count=0; i<n; i++) {
- __NLRowColumn *Ri = M->row + i;
- xa[i] = count;
-
- for(jj=0; jj<Ri->size; jj++, count++) {
- a[count] = Ri->coeff[jj].value;
- asub[count] = Ri->coeff[jj].index;
- }
- }
- xa[n] = nnz;
-
- /* Free M, don't need it anymore at this point */
- __nlSparseMatrixClear(M);
-
- /* Create superlu A matrix transposed */
- sCreate_CompCol_Matrix(
- &At, n, n, nnz, a, asub, xa,
- SLU_NC, /* Colum wise, no supernode */
- SLU_S, /* doubles */
- SLU_GE /* general storage */
- );
-
- /* Set superlu options */
- set_default_options(&options);
- options.ColPerm = MY_PERMC;
- options.Fact = DOFACT;
-
- StatInit(&(context->slu.stat));
-
- panel_size = sp_ienv(1); /* sp_ienv give us the defaults */
- relax = sp_ienv(2);
-
- /* Compute permutation and permuted matrix */
- context->slu.perm_r = __NL_NEW_ARRAY(NLint, n);
- context->slu.perm_c = __NL_NEW_ARRAY(NLint, n);
-
- if ((permutation == NULL) || (*permutation == -1)) {
- get_perm_c(3, &At, context->slu.perm_c);
-
- if (permutation)
- memcpy(permutation, context->slu.perm_c, sizeof(NLint)*n);
- }
- else
- memcpy(context->slu.perm_c, permutation, sizeof(NLint)*n);
-
- sp_preorder(&options, &At, context->slu.perm_c, etree, &AtP);
-
- /* Decompose into L and U */
- sgstrf(&options, &AtP, relax, panel_size,
- etree, NULL, 0, context->slu.perm_c, context->slu.perm_r,
- &(context->slu.L), &(context->slu.U), &(context->slu.stat), &info);
-
- /* Cleanup */
-
- Destroy_SuperMatrix_Store(&At);
- Destroy_CompCol_Permuted(&AtP);
-
- __NL_DELETE_ARRAY(etree);
- __NL_DELETE_ARRAY(xa);
- __NL_DELETE_ARRAY(rhs);
- __NL_DELETE_ARRAY(a);
- __NL_DELETE_ARRAY(asub);
-
- context->slu.alloc_slu = NL_TRUE;
-
- return (info == 0);
-}
-
-static NLboolean __nlInvert_SUPERLU(__NLContext *context) {
-
- /* OpenNL Context */
- NLdouble* b = (context->least_squares)? context->Mtb: context->b;
- NLdouble* x = context->x;
- NLuint n = context->n, j;
-
- /* SuperLU variables */
- SuperMatrix B;
- NLint info = 0;
-
- for(j=0; j<context->nb_rhs; j++, b+=n, x+=n) {
- /* Create superlu array for B */
- sCreate_Dense_Matrix(
- &B, n, 1, b, n,
- SLU_DN, /* Fortran-type column-wise storage */
- SLU_S, /* doubles */
- SLU_GE /* general */
- );
-
- /* Forward/Back substitution to compute x */
- sgstrs(TRANS, &(context->slu.L), &(context->slu.U),
- context->slu.perm_c, context->slu.perm_r, &B,
- &(context->slu.stat), &info);
-
- if(info == 0)
- memcpy(x, ((DNformat*)B.Store)->nzval, sizeof(*x)*n);
-
- Destroy_SuperMatrix_Store(&B);
- }
-
- return (info == 0);
-}
-
-static void __nlFree_SUPERLU(__NLContext *context) {
-
- Destroy_SuperNode_Matrix(&(context->slu.L));
- Destroy_CompCol_Matrix(&(context->slu.U));
-
- StatFree(&(context->slu.stat));
-
- __NL_DELETE_ARRAY(context->slu.perm_r);
- __NL_DELETE_ARRAY(context->slu.perm_c);
-
- context->slu.alloc_slu = NL_FALSE;
-}
-
-void nlPrintMatrix(void) {
- __NLContext *context = __nlCurrentContext;
- __NLSparseMatrix* M = &(context->M);
- __NLSparseMatrix* MtM = &(context->MtM);
- double *b = context->b;
- NLuint i, jj, k;
- NLuint m = context->m;
- NLuint n = context->n;
- __NLRowColumn* Ri = NULL;
- double *value = malloc(sizeof(*value)*(n+m));
-
- printf("A:\n");
- for(i=0; i<m; i++) {
- Ri = &(M->row[i]);
-
- memset(value, 0.0, sizeof(*value)*n);
- for(jj=0; jj<Ri->size; jj++)
- value[Ri->coeff[jj].index] = Ri->coeff[jj].value;
-
- for (k = 0; k<n; k++)
- printf("%.3f ", value[k]);
- printf("\n");
- }
-
- for(k=0; k<context->nb_rhs; k++) {
- printf("b (%d):\n", k);
- for(i=0; i<n; i++)
- printf("%f ", b[context->n*k + i]);
- printf("\n");
- }
-
- if(context->alloc_MtM) {
- printf("AtA:\n");
- for(i=0; i<n; i++) {
- Ri = &(MtM->row[i]);
-
- memset(value, 0.0, sizeof(*value)*m);
- for(jj=0; jj<Ri->size; jj++)
- value[Ri->coeff[jj].index] = Ri->coeff[jj].value;
-
- for (k = 0; k<n; k++)
- printf("%.3f ", value[k]);
- printf("\n");
- }
-
- for(k=0; k<context->nb_rhs; k++) {
- printf("Mtb (%d):\n", k);
- for(i=0; i<n; i++)
- printf("%f ", context->Mtb[context->n*k + i]);
- printf("\n");
- }
- printf("\n");
- }
-
- free(value);
-}
-
-/************************************************************************/
-/* nlSolve() driver routine */
-
-NLboolean nlSolveAdvanced(NLint *permutation, NLboolean solveAgain) {
- NLboolean result = NL_TRUE;
-
- __nlCheckState(__NL_STATE_SYSTEM_CONSTRUCTED);
-
- if (!__nlCurrentContext->solve_again)
- result = __nlFactorize_SUPERLU(__nlCurrentContext, permutation);
-
- if (result) {
- result = __nlInvert_SUPERLU(__nlCurrentContext);
-
- if (result) {
- __nlVectorToVariables();
-
- if (solveAgain)
- __nlCurrentContext->solve_again = NL_TRUE;
-
- __nlTransition(__NL_STATE_SYSTEM_CONSTRUCTED, __NL_STATE_SYSTEM_SOLVED);
- }
- }
-
- return result;
-}
-
-NLboolean nlSolve() {
- return nlSolveAdvanced(NULL, NL_FALSE);
-}
-
diff --git a/intern/opennl/superlu/Cnames.h b/intern/opennl/superlu/Cnames.h
deleted file mode 100644
index 1be2aa8962a..00000000000
--- a/intern/opennl/superlu/Cnames.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/** \file opennl/superlu/Cnames.h
- * \ingroup opennl
- */
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 1, 1997
- *
- */
-#ifndef __SUPERLU_CNAMES /* allow multiple inclusions */
-#define __SUPERLU_CNAMES
-
-/* We want this flag, safer than putting in build system */
-#define Add_
-
-/*
- * These macros define how C routines will be called. ADD_ assumes that
- * they will be called by fortran, which expects C routines to have an
- * underscore postfixed to the name (Suns, and the Intel expect this).
- * NOCHANGE indicates that fortran will be calling, and that it expects
- * the name called by fortran to be identical to that compiled by the C
- * (RS6K's do this). UPCASE says it expects C routines called by fortran
- * to be in all upcase (CRAY wants this).
- */
-
-#define ADD_ 0
-#define ADD__ 1
-#define NOCHANGE 2
-#define UPCASE 3
-#define C_CALL 4
-
-#ifdef UpCase
-#define F77_CALL_C UPCASE
-#endif
-
-#ifdef NoChange
-#define F77_CALL_C NOCHANGE
-#endif
-
-#ifdef Add_
-#define F77_CALL_C ADD_
-#endif
-
-#ifdef Add__
-#define F77_CALL_C ADD__
-#endif
-
-/* Default */
-#ifndef F77_CALL_C
-#define F77_CALL_C ADD_
-#endif
-
-
-#if (F77_CALL_C == ADD_)
-/*
- * These defines set up the naming scheme required to have a fortran 77
- * routine call a C routine
- * No redefinition necessary to have following Fortran to C interface:
- * FORTRAN CALL C DECLARATION
- * call dgemm(...) void dgemm_(...)
- *
- * This is the default.
- */
-
-#endif
-
-#if (F77_CALL_C == ADD__)
-/*
- * These defines set up the naming scheme required to have a fortran 77
- * routine call a C routine
- * for following Fortran to C interface:
- * FORTRAN CALL C DECLARATION
- * call dgemm(...) void dgemm__(...)
- */
-#define sasum_ sasum__
-#define isamax_ isamax__
-#define scopy_ scopy__
-#define sscal_ sscal__
-#define sger_ sger__
-#define snrm2_ snrm2__
-#define ssymv_ ssymv__
-#define sdot_ sdot__
-#define saxpy_ saxpy__
-#define ssyr2_ ssyr2__
-#define srot_ srot__
-#define sgemv_ sgemv__
-#define strsv_ strsv__
-#define sgemm_ sgemm__
-#define strsm_ strsm__
-
-#define dasum_ dasum__
-#define idamax_ idamax__
-#define dcopy_ dcopy__
-#define dscal_ dscal__
-#define dger_ dger__
-#define dnrm2_ dnrm2__
-#define dsymv_ dsymv__
-#define ddot_ ddot__
-#define daxpy_ daxpy__
-#define dsyr2_ dsyr2__
-#define drot_ drot__
-#define dgemv_ dgemv__
-#define dtrsv_ dtrsv__
-#define dgemm_ dgemm__
-#define dtrsm_ dtrsm__
-
-#define scasum_ scasum__
-#define icamax_ icamax__
-#define ccopy_ ccopy__
-#define cscal_ cscal__
-#define scnrm2_ scnrm2__
-#define caxpy_ caxpy__
-#define cgemv_ cgemv__
-#define ctrsv_ ctrsv__
-#define cgemm_ cgemm__
-#define ctrsm_ ctrsm__
-#define cgerc_ cgerc__
-#define chemv_ chemv__
-#define cher2_ cher2__
-
-#define dzasum_ dzasum__
-#define izamax_ izamax__
-#define zcopy_ zcopy__
-#define zscal_ zscal__
-#define dznrm2_ dznrm2__
-#define zaxpy_ zaxpy__
-#define zgemv_ zgemv__
-#define ztrsv_ ztrsv__
-#define zgemm_ zgemm__
-#define ztrsm_ ztrsm__
-#define zgerc_ zgerc__
-#define zhemv_ zhemv__
-#define zher2_ zher2__
-
-#define c_bridge_dgssv_ c_bridge_dgssv__
-#define c_fortran_dgssv_ c_fortran_dgssv__
-#endif
-
-#if (F77_CALL_C == UPCASE)
-/*
- * These defines set up the naming scheme required to have a fortran 77
- * routine call a C routine
- * following Fortran to C interface:
- * FORTRAN CALL C DECLARATION
- * call dgemm(...) void DGEMM(...)
- */
-#define sasum_ SASUM
-#define isamax_ ISAMAX
-#define scopy_ SCOPY
-#define sscal_ SSCAL
-#define sger_ SGER
-#define snrm2_ SNRM2
-#define ssymv_ SSYMV
-#define sdot_ SDOT
-#define saxpy_ SAXPY
-#define ssyr2_ SSYR2
-#define srot_ SROT
-#define sgemv_ SGEMV
-#define strsv_ STRSV
-#define sgemm_ SGEMM
-#define strsm_ STRSM
-
-#define dasum_ SASUM
-#define idamax_ ISAMAX
-#define dcopy_ SCOPY
-#define dscal_ SSCAL
-#define dger_ SGER
-#define dnrm2_ SNRM2
-#define dsymv_ SSYMV
-#define ddot_ SDOT
-#define daxpy_ SAXPY
-#define dsyr2_ SSYR2
-#define drot_ SROT
-#define dgemv_ SGEMV
-#define dtrsv_ STRSV
-#define dgemm_ SGEMM
-#define dtrsm_ STRSM
-
-#define scasum_ SCASUM
-#define icamax_ ICAMAX
-#define ccopy_ CCOPY
-#define cscal_ CSCAL
-#define scnrm2_ SCNRM2
-#define caxpy_ CAXPY
-#define cgemv_ CGEMV
-#define ctrsv_ CTRSV
-#define cgemm_ CGEMM
-#define ctrsm_ CTRSM
-#define cgerc_ CGERC
-#define chemv_ CHEMV
-#define cher2_ CHER2
-
-#define dzasum_ SCASUM
-#define izamax_ ICAMAX
-#define zcopy_ CCOPY
-#define zscal_ CSCAL
-#define dznrm2_ SCNRM2
-#define zaxpy_ CAXPY
-#define zgemv_ CGEMV
-#define ztrsv_ CTRSV
-#define zgemm_ CGEMM
-#define ztrsm_ CTRSM
-#define zgerc_ CGERC
-#define zhemv_ CHEMV
-#define zher2_ CHER2
-
-#define c_bridge_dgssv_ C_BRIDGE_DGSSV
-#define c_fortran_dgssv_ C_FORTRAN_DGSSV
-#endif
-
-#if (F77_CALL_C == NOCHANGE)
-/*
- * These defines set up the naming scheme required to have a fortran 77
- * routine call a C routine
- * for following Fortran to C interface:
- * FORTRAN CALL C DECLARATION
- * call dgemm(...) void dgemm(...)
- */
-#define sasum_ sasum
-#define isamax_ isamax
-#define scopy_ scopy
-#define sscal_ sscal
-#define sger_ sger
-#define snrm2_ snrm2
-#define ssymv_ ssymv
-#define sdot_ sdot
-#define saxpy_ saxpy
-#define ssyr2_ ssyr2
-#define srot_ srot
-#define sgemv_ sgemv
-#define strsv_ strsv
-#define sgemm_ sgemm
-#define strsm_ strsm
-
-#define dasum_ dasum
-#define idamax_ idamax
-#define dcopy_ dcopy
-#define dscal_ dscal
-#define dger_ dger
-#define dnrm2_ dnrm2
-#define dsymv_ dsymv
-#define ddot_ ddot
-#define daxpy_ daxpy
-#define dsyr2_ dsyr2
-#define drot_ drot
-#define dgemv_ dgemv
-#define dtrsv_ dtrsv
-#define dgemm_ dgemm
-#define dtrsm_ dtrsm
-
-#define scasum_ scasum
-#define icamax_ icamax
-#define ccopy_ ccopy
-#define cscal_ cscal
-#define scnrm2_ scnrm2
-#define caxpy_ caxpy
-#define cgemv_ cgemv
-#define ctrsv_ ctrsv
-#define cgemm_ cgemm
-#define ctrsm_ ctrsm
-#define cgerc_ cgerc
-#define chemv_ chemv
-#define cher2_ cher2
-
-#define dzasum_ dzasum
-#define izamax_ izamax
-#define zcopy_ zcopy
-#define zscal_ zscal
-#define dznrm2_ dznrm2
-#define zaxpy_ zaxpy
-#define zgemv_ zgemv
-#define ztrsv_ ztrsv
-#define zgemm_ zgemm
-#define ztrsm_ ztrsm
-#define zgerc_ zgerc
-#define zhemv_ zhemv
-#define zher2_ zher2
-
-#define c_bridge_dgssv_ c_bridge_dgssv
-#define c_fortran_dgssv_ c_fortran_dgssv
-#endif
-
-#endif /* __SUPERLU_CNAMES */
diff --git a/intern/opennl/superlu/get_perm_c.c b/intern/opennl/superlu/get_perm_c.c
deleted file mode 100644
index 59889645988..00000000000
--- a/intern/opennl/superlu/get_perm_c.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/** \file opennl/superlu/get_perm_c.c
- * \ingroup opennl
- */
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-
-#include "ssp_defs.h"
-#include "colamd.h"
-
-extern int genmmd_(int *, int *, int *, int *, int *, int *, int *,
- int *, int *, int *, int *, int *);
-
-static void
-get_colamd(
- const int m, /* number of rows in matrix A. */
- const int n, /* number of columns in matrix A. */
- const int nnz,/* number of nonzeros in matrix A. */
- int *colptr, /* column pointer of size n+1 for matrix A. */
- int *rowind, /* row indices of size nz for matrix A. */
- int *perm_c /* out - the column permutation vector. */
- )
-{
- int Alen, *A, i, info, *p;
- double *knobs;
- int stats[COLAMD_STATS];
-
- Alen = colamd_recommended(nnz, m, n);
-
- if ( !(knobs = (double *) SUPERLU_MALLOC(COLAMD_KNOBS * sizeof(double))) )
- ABORT("Malloc fails for knobs");
- colamd_set_defaults(knobs);
-
- if (!(A = (int *) SUPERLU_MALLOC(Alen * sizeof(int))) )
- ABORT("Malloc fails for A[]");
- if (!(p = (int *) SUPERLU_MALLOC((n+1) * sizeof(int))) )
- ABORT("Malloc fails for p[]");
- for (i = 0; i <= n; ++i) p[i] = colptr[i];
- for (i = 0; i < nnz; ++i) A[i] = rowind[i];
- info = colamd(m, n, Alen, A, p, knobs, stats);
- if ( info == FALSE ) ABORT("COLAMD failed");
-
- for (i = 0; i < n; ++i) perm_c[p[i]] = i;
-
- SUPERLU_FREE(knobs);
- SUPERLU_FREE(A);
- SUPERLU_FREE(p);
-}
-
-static void
-getata(
- const int m, /* number of rows in matrix A. */
- const int n, /* number of columns in matrix A. */
- const int nz, /* number of nonzeros in matrix A */
- int *colptr, /* column pointer of size n+1 for matrix A. */
- int *rowind, /* row indices of size nz for matrix A. */
- int *atanz, /* out - on exit, returns the actual number of
- nonzeros in matrix A'*A. */
- int **ata_colptr, /* out - size n+1 */
- int **ata_rowind /* out - size *atanz */
- )
-/*
- * Purpose
- * =======
- *
- * Form the structure of A'*A. A is an m-by-n matrix in column oriented
- * format represented by (colptr, rowind). The output A'*A is in column
- * oriented format (symmetrically, also row oriented), represented by
- * (ata_colptr, ata_rowind).
- *
- * This routine is modified from GETATA routine by Tim Davis.
- * The complexity of this algorithm is: SUM_{i=1,m} r(i)^2,
- * i.e., the sum of the square of the row counts.
- *
- * Questions
- * =========
- * o Do I need to withhold the *dense* rows?
- * o How do I know the number of nonzeros in A'*A?
- *
- */
-{
- register int i, j, k, col, num_nz, ti, trow;
- int *marker, *b_colptr, *b_rowind;
- int *t_colptr, *t_rowind; /* a column oriented form of T = A' */
-
- if ( !(marker = (int*) SUPERLU_MALLOC((SUPERLU_MAX(m,n)+1)*sizeof(int))) )
- ABORT("SUPERLU_MALLOC fails for marker[]");
- if ( !(t_colptr = (int*) SUPERLU_MALLOC((m+1) * sizeof(int))) )
- ABORT("SUPERLU_MALLOC t_colptr[]");
- if ( !(t_rowind = (int*) SUPERLU_MALLOC(nz * sizeof(int))) )
- ABORT("SUPERLU_MALLOC fails for t_rowind[]");
-
-
- /* Get counts of each column of T, and set up column pointers */
- for (i = 0; i < m; ++i) marker[i] = 0;
- for (j = 0; j < n; ++j) {
- for (i = colptr[j]; i < colptr[j+1]; ++i)
- ++marker[rowind[i]];
- }
- t_colptr[0] = 0;
- for (i = 0; i < m; ++i) {
- t_colptr[i+1] = t_colptr[i] + marker[i];
- marker[i] = t_colptr[i];
- }
-
- /* Transpose the matrix from A to T */
- for (j = 0; j < n; ++j)
- for (i = colptr[j]; i < colptr[j+1]; ++i) {
- col = rowind[i];
- t_rowind[marker[col]] = j;
- ++marker[col];
- }
-
-
- /* ----------------------------------------------------------------
- compute B = T * A, where column j of B is:
-
- Struct (B_*j) = UNION ( Struct (T_*k) )
- A_kj != 0
-
- do not include the diagonal entry
-
- ( Partition A as: A = (A_*1, ..., A_*n)
- Then B = T * A = (T * A_*1, ..., T * A_*n), where
- T * A_*j = (T_*1, ..., T_*m) * A_*j. )
- ---------------------------------------------------------------- */
-
- /* Zero the diagonal flag */
- for (i = 0; i < n; ++i) marker[i] = -1;
-
- /* First pass determines number of nonzeros in B */
- num_nz = 0;
- for (j = 0; j < n; ++j) {
- /* Flag the diagonal so it's not included in the B matrix */
- marker[j] = j;
-
- for (i = colptr[j]; i < colptr[j+1]; ++i) {
- /* A_kj is nonzero, add pattern of column T_*k to B_*j */
- k = rowind[i];
- for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) {
- trow = t_rowind[ti];
- if ( marker[trow] != j ) {
- marker[trow] = j;
- num_nz++;
- }
- }
- }
- }
- *atanz = num_nz;
-
- /* Allocate storage for A'*A */
- if ( !(*ata_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails for ata_colptr[]");
- if ( *atanz ) {
- if ( !(*ata_rowind = (int*) SUPERLU_MALLOC( *atanz * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails for ata_rowind[]");
- }
- b_colptr = *ata_colptr; /* aliasing */
- b_rowind = *ata_rowind;
-
- /* Zero the diagonal flag */
- for (i = 0; i < n; ++i) marker[i] = -1;
-
- /* Compute each column of B, one at a time */
- num_nz = 0;
- for (j = 0; j < n; ++j) {
- b_colptr[j] = num_nz;
-
- /* Flag the diagonal so it's not included in the B matrix */
- marker[j] = j;
-
- if ( *atanz ) {
- for (i = colptr[j]; i < colptr[j+1]; ++i) {
- /* A_kj is nonzero, add pattern of column T_*k to B_*j */
- k = rowind[i];
- for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) {
- trow = t_rowind[ti];
- if ( marker[trow] != j ) {
- marker[trow] = j;
- b_rowind[num_nz++] = trow;
- }
- }
- }
- }
- }
- b_colptr[n] = num_nz;
-
- SUPERLU_FREE(marker);
- SUPERLU_FREE(t_colptr);
- SUPERLU_FREE(t_rowind);
-}
-
-
-static void
-at_plus_a(
- const int n, /* number of columns in matrix A. */
- const int nz, /* number of nonzeros in matrix A */
- int *colptr, /* column pointer of size n+1 for matrix A. */
- int *rowind, /* row indices of size nz for matrix A. */
- int *bnz, /* out - on exit, returns the actual number of
- nonzeros in matrix A'*A. */
- int **b_colptr, /* out - size n+1 */
- int **b_rowind /* out - size *bnz */
- )
-{
-/*
- * Purpose
- * =======
- *
- * Form the structure of A'+A. A is an n-by-n matrix in column oriented
- * format represented by (colptr, rowind). The output A'+A is in column
- * oriented format (symmetrically, also row oriented), represented by
- * (b_colptr, b_rowind).
- *
- */
- register int i, j, k, col, num_nz;
- int *t_colptr, *t_rowind; /* a column oriented form of T = A' */
- int *marker;
-
- if ( !(marker = (int*) SUPERLU_MALLOC( n * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails for marker[]");
- if ( !(t_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails for t_colptr[]");
- if ( !(t_rowind = (int*) SUPERLU_MALLOC( nz * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails t_rowind[]");
-
-
- /* Get counts of each column of T, and set up column pointers */
- for (i = 0; i < n; ++i) marker[i] = 0;
- for (j = 0; j < n; ++j) {
- for (i = colptr[j]; i < colptr[j+1]; ++i)
- ++marker[rowind[i]];
- }
- t_colptr[0] = 0;
- for (i = 0; i < n; ++i) {
- t_colptr[i+1] = t_colptr[i] + marker[i];
- marker[i] = t_colptr[i];
- }
-
- /* Transpose the matrix from A to T */
- for (j = 0; j < n; ++j)
- for (i = colptr[j]; i < colptr[j+1]; ++i) {
- col = rowind[i];
- t_rowind[marker[col]] = j;
- ++marker[col];
- }
-
-
- /* ----------------------------------------------------------------
- compute B = A + T, where column j of B is:
-
- Struct (B_*j) = Struct (A_*k) UNION Struct (T_*k)
-
- do not include the diagonal entry
- ---------------------------------------------------------------- */
-
- /* Zero the diagonal flag */
- for (i = 0; i < n; ++i) marker[i] = -1;
-
- /* First pass determines number of nonzeros in B */
- num_nz = 0;
- for (j = 0; j < n; ++j) {
- /* Flag the diagonal so it's not included in the B matrix */
- marker[j] = j;
-
- /* Add pattern of column A_*k to B_*j */
- for (i = colptr[j]; i < colptr[j+1]; ++i) {
- k = rowind[i];
- if ( marker[k] != j ) {
- marker[k] = j;
- ++num_nz;
- }
- }
-
- /* Add pattern of column T_*k to B_*j */
- for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) {
- k = t_rowind[i];
- if ( marker[k] != j ) {
- marker[k] = j;
- ++num_nz;
- }
- }
- }
- *bnz = num_nz;
-
- /* Allocate storage for A+A' */
- if ( !(*b_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails for b_colptr[]");
- if ( *bnz) {
- if ( !(*b_rowind = (int*) SUPERLU_MALLOC( *bnz * sizeof(int)) ) )
- ABORT("SUPERLU_MALLOC fails for b_rowind[]");
- }
-
- /* Zero the diagonal flag */
- for (i = 0; i < n; ++i) marker[i] = -1;
-
- /* Compute each column of B, one at a time */
- num_nz = 0;
- for (j = 0; j < n; ++j) {
- (*b_colptr)[j] = num_nz;
-
- /* Flag the diagonal so it's not included in the B matrix */
- marker[j] = j;
-
- /* Add pattern of column A_*k to B_*j */
- if (*bnz) {
- for (i = colptr[j]; i < colptr[j+1]; ++i) {
- k = rowind[i];
- if ( marker[k] != j ) {
- marker[k] = j;
- (*b_rowind)[num_nz++] = k;
- }
- }
-
- /* Add pattern of column T_*k to B_*j */
- for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) {
- k = t_rowind[i];
- if ( marker[k] != j ) {
- marker[k] = j;
- (*b_rowind)[num_nz++] = k;
- }
- }
- }
- }
- (*b_colptr)[n] = num_nz;
-
- SUPERLU_FREE(marker);
- SUPERLU_FREE(t_colptr);
- SUPERLU_FREE(t_rowind);
-}
-
-void
-get_perm_c(int ispec, SuperMatrix *A, int *perm_c)
-/*
- * Purpose
- * =======
- *
- * GET_PERM_C obtains a permutation matrix Pc, by applying the multiple
- * minimum degree ordering code by Joseph Liu to matrix A'*A or A+A'.
- * or using approximate minimum degree column ordering by Davis et. al.
- * The LU factorization of A*Pc tends to have less fill than the LU
- * factorization of A.
- *
- * Arguments
- * =========
- *
- * ispec (input) int
- * Specifies the type of column ordering to reduce fill:
- * = 1: minimum degree on the structure of A^T * A
- * = 2: minimum degree on the structure of A^T + A
- * = 3: approximate minimum degree for unsymmetric matrices
- * If ispec == 0, the natural ordering (i.e., Pc = I) is returned.
- *
- * A (input) SuperMatrix*
- * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
- * of the linear equations is A->nrow. Currently, the type of A
- * can be: Stype = NC; Dtype = _D; Mtype = GE. In the future,
- * more general A can be handled.
- *
- * perm_c (output) int*
- * Column permutation vector of size A->ncol, which defines the
- * permutation matrix Pc; perm_c[i] = j means column i of A is
- * in position j in A*Pc.
- *
- */
-{
- NCformat *Astore = A->Store;
- int m, n, bnz, *b_colptr, i;
- int delta, maxint, nofsub, *invp;
- int *b_rowind, *dhead, *qsize, *llist, *marker;
- /* double t, SuperLU_timer_(); */
-
- /* make gcc happy */
- b_rowind=NULL;
- b_colptr=NULL;
-
- m = A->nrow;
- n = A->ncol;
-
- /* t = SuperLU_timer_(); */
- switch ( ispec ) {
- case 0: /* Natural ordering */
- for (i = 0; i < n; ++i) perm_c[i] = i;
-#if ( PRNTlevel>=1 )
- printf("Use natural column ordering.\n");
-#endif
- return;
- case 1: /* Minimum degree ordering on A'*A */
- getata(m, n, Astore->nnz, Astore->colptr, Astore->rowind,
- &bnz, &b_colptr, &b_rowind);
-#if ( PRNTlevel>=1 )
- printf("Use minimum degree ordering on A'*A.\n");
-#endif
- /*t = SuperLU_timer_() - t;
- printf("Form A'*A time = %8.3f\n", t);*/
- break;
- case 2: /* Minimum degree ordering on A'+A */
- if ( m != n ) ABORT("Matrix is not square");
- at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind,
- &bnz, &b_colptr, &b_rowind);
-#if ( PRNTlevel>=1 )
- printf("Use minimum degree ordering on A'+A.\n");
-#endif
- /*t = SuperLU_timer_() - t;
- printf("Form A'+A time = %8.3f\n", t);*/
- break;
- case 3: /* Approximate minimum degree column ordering. */
- get_colamd(m, n, Astore->nnz, Astore->colptr, Astore->rowind,
- perm_c);
-#if ( PRNTlevel>=1 )
- printf(".. Use approximate minimum degree column ordering.\n");
-#endif
- return;
- default:
- ABORT("Invalid ISPEC");
- return;
- }
-
- if ( bnz != 0 ) {
- /* t = SuperLU_timer_(); */
-
- /* Initialize and allocate storage for GENMMD. */
- delta = 1; /* DELTA is a parameter to allow the choice of nodes
- whose degree <= min-degree + DELTA. */
- maxint = 2147483647; /* 2**31 - 1 */
- invp = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int));
- if ( !invp ) ABORT("SUPERLU_MALLOC fails for invp.");
- dhead = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int));
- if ( !dhead ) ABORT("SUPERLU_MALLOC fails for dhead.");
- qsize = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int));
- if ( !qsize ) ABORT("SUPERLU_MALLOC fails for qsize.");
- llist = (int *) SUPERLU_MALLOC(n*sizeof(int));
- if ( !llist ) ABORT("SUPERLU_MALLOC fails for llist.");
- marker = (int *) SUPERLU_MALLOC(n*sizeof(int));
- if ( !marker ) ABORT("SUPERLU_MALLOC fails for marker.");
-
- /* Transform adjacency list into 1-based indexing required by GENMMD.*/
- for (i = 0; i <= n; ++i) ++b_colptr[i];
- for (i = 0; i < bnz; ++i) ++b_rowind[i];
-
- genmmd_(&n, b_colptr, b_rowind, perm_c, invp, &delta, dhead,
- qsize, llist, marker, &maxint, &nofsub);
-
- /* Transform perm_c into 0-based indexing. */
- for (i = 0; i < n; ++i) --perm_c[i];
-
- SUPERLU_FREE(b_colptr);
- SUPERLU_FREE(b_rowind);
- SUPERLU_FREE(invp);
- SUPERLU_FREE(dhead);
- SUPERLU_FREE(qsize);
- SUPERLU_FREE(llist);
- SUPERLU_FREE(marker);
-
- /* t = SuperLU_timer_() - t;
- printf("call GENMMD time = %8.3f\n", t);*/
-
- } else { /* Empty adjacency structure */
- for (i = 0; i < n; ++i) perm_c[i] = i;
- }
-
-}
diff --git a/intern/opennl/superlu/heap_relax_snode.c b/intern/opennl/superlu/heap_relax_snode.c
deleted file mode 100644
index cd88179bbb7..00000000000
--- a/intern/opennl/superlu/heap_relax_snode.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/** \file opennl/superlu/heap_relax_snode.c
- * \ingroup opennl
- */
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-
-void
-heap_relax_snode (
- const int n,
- int *et, /* column elimination tree */
- const int relax_columns, /* max no of columns allowed in a
- relaxed snode */
- int *descendants, /* no of descendants of each node
- in the etree */
- int *relax_end /* last column in a supernode */
- )
-{
-/*
- * Purpose
- * =======
- * relax_snode() - Identify the initial relaxed supernodes, assuming that
- * the matrix has been reordered according to the postorder of the etree.
- *
- */
- register int i, j, k, l, parent;
- register int snode_start; /* beginning of a snode */
- int *et_save, *post, *inv_post, *iwork;
- int nsuper_et = 0, nsuper_et_post = 0;
-
- /* The etree may not be postordered, but is heap ordered. */
-
- iwork = (int*) intMalloc(3*n+2);
- if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]");
- inv_post = iwork + n+1;
- et_save = inv_post + n+1;
-
- /* Post order etree */
- post = (int *) TreePostorder(n, et);
- for (i = 0; i < n+1; ++i) inv_post[post[i]] = i;
-
- /* Renumber etree in postorder */
- for (i = 0; i < n; ++i) {
- iwork[post[i]] = post[et[i]];
- et_save[i] = et[i]; /* Save the original etree */
- }
- for (i = 0; i < n; ++i) et[i] = iwork[i];
-
- /* Compute the number of descendants of each node in the etree */
- ifill (relax_end, n, EMPTY);
- for (j = 0; j < n; j++) descendants[j] = 0;
- for (j = 0; j < n; j++) {
- parent = et[j];
- if ( parent != n ) /* not the dummy root */
- descendants[parent] += descendants[j] + 1;
- }
-
- /* Identify the relaxed supernodes by postorder traversal of the etree. */
- for (j = 0; j < n; ) {
- parent = et[j];
- snode_start = j;
- while ( parent != n && descendants[parent] < relax_columns ) {
- j = parent;
- parent = et[j];
- }
- /* Found a supernode in postordered etree; j is the last column. */
- ++nsuper_et_post;
- k = n;
- for (i = snode_start; i <= j; ++i)
- k = SUPERLU_MIN(k, inv_post[i]);
- l = inv_post[j];
- if ( (l - k) == (j - snode_start) ) {
- /* It's also a supernode in the original etree */
- relax_end[k] = l; /* Last column is recorded */
- ++nsuper_et;
- } else {
- for (i = snode_start; i <= j; ++i) {
- l = inv_post[i];
- if ( descendants[i] == 0 ) relax_end[l] = l;
- }
- }
- j++;
- /* Search for a new leaf */
- while ( j < n && descendants[j] != 0 ) j++;
- }
-
-#if ( PRNTlevel>=1 )
- printf(".. heap_snode_relax:\n"
- "\tNo of relaxed snodes in postordered etree:\t%d\n"
- "\tNo of relaxed snodes in original etree:\t%d\n",
- nsuper_et_post, nsuper_et);
-#endif
-
- /* Recover the original etree */
- for (i = 0; i < n; ++i) et[i] = et_save[i];
-
- SUPERLU_FREE(post);
- SUPERLU_FREE(iwork);
-}
-
-
diff --git a/intern/opennl/superlu/lsame.c b/intern/opennl/superlu/lsame.c
deleted file mode 100644
index 2f2337d5001..00000000000
--- a/intern/opennl/superlu/lsame.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/** \file opennl/superlu/lsame.c
- * \ingroup opennl
- */
-int lsame_(char *, char *);
-
-
-int lsame_(char *ca, char *cb)
-{
-/* -- LAPACK auxiliary routine (version 2.0) --
- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
- Courant Institute, Argonne National Lab, and Rice University
- September 30, 1994
-
- Purpose
- =======
-
- LSAME returns .TRUE. if CA is the same letter as CB regardless of case.
-
- Arguments
- =========
-
- CA (input) CHARACTER*1
- CB (input) CHARACTER*1
- CA and CB specify the single characters to be compared.
-
- =====================================================================
-*/
-
- /* System generated locals */
- int ret_val;
-
- /* Local variables */
- int inta, intb, zcode;
-
- ret_val = *(unsigned char *)ca == *(unsigned char *)cb;
- if (ret_val) {
- return ret_val;
- }
-
- /* Now test for equivalence if both characters are alphabetic. */
-
- zcode = 'Z';
-
- /* Use 'Z' rather than 'A' so that ASCII can be detected on Prime
- machines, on which ICHAR returns a value with bit 8 set.
- ICHAR('A') on Prime machines returns 193 which is the same as
- ICHAR('A') on an EBCDIC machine. */
-
- inta = *(unsigned char *)ca;
- intb = *(unsigned char *)cb;
-
- if (zcode == 90 || zcode == 122) {
- /* ASCII is assumed - ZCODE is the ASCII code of either lower or
- upper case 'Z'. */
- if (inta >= 97 && inta <= 122) inta += -32;
- if (intb >= 97 && intb <= 122) intb += -32;
-
- } else if (zcode == 233 || zcode == 169) {
- /* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or
- upper case 'Z'. */
- if ((inta >= 129 && inta <= 137) || (inta >= 145 && inta <= 153) || (inta
- >= 162 && inta <= 169))
- inta += 64;
- if ((intb >= 129 && intb <= 137) || (intb >= 145 && intb <= 153) || (intb
- >= 162 && intb <= 169))
- intb += 64;
- } else if (zcode == 218 || zcode == 250) {
- /* ASCII is assumed, on Prime machines - ZCODE is the ASCII code
- plus 128 of either lower or upper case 'Z'. */
- if (inta >= 225 && inta <= 250) inta += -32;
- if (intb >= 225 && intb <= 250) intb += -32;
- }
- ret_val = inta == intb;
- return ret_val;
-
-} /* lsame_ */
diff --git a/intern/opennl/superlu/memory.c b/intern/opennl/superlu/memory.c
deleted file mode 100644
index a239f685424..00000000000
--- a/intern/opennl/superlu/memory.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/** \file opennl/superlu/memory.c
- * \ingroup opennl
- */
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/** Precision-independent memory-related routines.
- (Shared by [sdcz]memory.c) **/
-
-#include "ssp_defs.h"
-
-/* prototypes --------------------------------- */
-void copy_mem_int(int, void *, void *);
-void user_bcopy(char *, char *, int);
-
-
-#if ( DEBUGlevel>=1 ) /* Debug malloc/free. */
-int superlu_malloc_total = 0;
-
-#define PAD_FACTOR 2
-#define DWORD (sizeof(double)) /* Be sure it's no smaller than double. */
-
-void *superlu_malloc(size_t size)
-{
- char *buf;
-
- buf = (char *) malloc(size + DWORD);
- if ( !buf ) {
- printf("superlu_malloc fails: malloc_total %.0f MB, size %d\n",
- superlu_malloc_total*1e-6, size);
- ABORT("superlu_malloc: out of memory");
- }
-
- ((int_t *) buf)[0] = size;
-#if 0
- superlu_malloc_total += size + DWORD;
-#else
- superlu_malloc_total += size;
-#endif
- return (void *) (buf + DWORD);
-}
-
-void superlu_free(void *addr)
-{
- char *p = ((char *) addr) - DWORD;
-
- if ( !addr )
- ABORT("superlu_free: tried to free NULL pointer");
-
- if ( !p )
- ABORT("superlu_free: tried to free NULL+DWORD pointer");
-
- {
- int_t n = ((int_t *) p)[0];
-
- if ( !n )
- ABORT("superlu_free: tried to free a freed pointer");
- *((int_t *) p) = 0; /* Set to zero to detect duplicate free's. */
-#if 0
- superlu_malloc_total -= (n + DWORD);
-#else
- superlu_malloc_total -= n;
-#endif
-
- if ( superlu_malloc_total < 0 )
- ABORT("superlu_malloc_total went negative!");
-
- /*free (addr);*/
- free (p);
- }
-
-}
-
-#else /* production mode */
-
-void *superlu_malloc(size_t size)
-{
- void *buf;
- buf = (void *) malloc(size);
- return (buf);
-}
-
-void superlu_free(void *addr)
-{
- free (addr);
-}
-
-#endif
-
-
-/*
- * Set up pointers for integer working arrays.
- */
-void
-SetIWork(int m, int n, int panel_size, int *iworkptr, int **segrep,
- int **parent, int **xplore, int **repfnz, int **panel_lsub,
- int **xprune, int **marker)
-{
- *segrep = iworkptr;
- *parent = iworkptr + m;
- *xplore = *parent + m;
- *repfnz = *xplore + m;
- *panel_lsub = *repfnz + panel_size * m;
- *xprune = *panel_lsub + panel_size * m;
- *marker = *xprune + n;
- ifill (*repfnz, m * panel_size, EMPTY);
- ifill (*panel_lsub, m * panel_size, EMPTY);
-}
-
-
-void
-copy_mem_int(int howmany, void *old, void *new)
-{
- register int i;
- int *iold = old;
- int *inew = new;
- for (i = 0; i < howmany; i++) inew[i] = iold[i];
-}
-
-
-void
-user_bcopy(char *src, char *dest, int bytes)
-{
- char *s_ptr, *d_ptr;
-
- s_ptr = src + bytes - 1;
- d_ptr = dest + bytes - 1;
- for (; d_ptr >= dest; --s_ptr, --d_ptr ) *d_ptr = *s_ptr;
-}
-
-
-
-int *intMalloc(int n)
-{
- int *buf;
- buf = (int *) SUPERLU_MALLOC(n * sizeof(int));
- if ( !buf ) {
- ABORT("SUPERLU_MALLOC fails for buf in intMalloc()");
- }
- return (buf);
-}
-
-int *intCalloc(int n)
-{
- int *buf;
- register int i;
- buf = (int *) SUPERLU_MALLOC(n * sizeof(int));
- if ( !buf ) {
- ABORT("SUPERLU_MALLOC fails for buf in intCalloc()");
- }
- for (i = 0; i < n; ++i) buf[i] = 0;
- return (buf);
-}
-
-
-
-#if 0
-check_expanders()
-{
- int p;
- printf("Check expanders:\n");
- for (p = 0; p < NO_MEMTYPE; p++) {
- printf("type %d, size %d, mem %d\n",
- p, expanders[p].size, (int)expanders[p].mem);
- }
-
- return 0;
-}
-
-
-StackInfo()
-{
- printf("Stack: size %d, used %d, top1 %d, top2 %d\n",
- stack.size, stack.used, stack.top1, stack.top2);
- return 0;
-}
-
-
-
-PrintStack(char *msg, GlobalLU_t *Glu)
-{
- int i;
- int *xlsub, *lsub, *xusub, *usub;
-
- xlsub = Glu->xlsub;
- lsub = Glu->lsub;
- xusub = Glu->xusub;
- usub = Glu->usub;
-
- printf("%s\n", msg);
-
-/* printf("\nUCOL: ");
- for (i = 0; i < xusub[ndim]; ++i)
- printf("%f ", ucol[i]);
-
- printf("\nLSUB: ");
- for (i = 0; i < xlsub[ndim]; ++i)
- printf("%d ", lsub[i]);
-
- printf("\nUSUB: ");
- for (i = 0; i < xusub[ndim]; ++i)
- printf("%d ", usub[i]);
-
- printf("\n");*/
- return 0;
-}
-#endif
-
-
-
diff --git a/intern/opennl/superlu/mmd.c b/intern/opennl/superlu/mmd.c
deleted file mode 100644
index a9c20fd9e81..00000000000
--- a/intern/opennl/superlu/mmd.c
+++ /dev/null
@@ -1,1028 +0,0 @@
-/** \file opennl/superlu/mmd.c
- * \ingroup opennl
- */
-
-typedef int shortint;
-
-
-/* prototypes -------------------- */
-int genmmd_(int *, int *, int *, int *, int *, int *, int *,
- int *, int *, int *, int *, int *);
-int mmdint_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *,
- shortint *, shortint *);
-int mmdelm_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *,
- shortint *, shortint *, int *, int *);
-int mmdupd_(int *, int *, int *, shortint *, int *, int *, shortint *,
- shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *);
-int mmdnum_(int *, shortint *, shortint *, shortint *);
-
-
-/* *************************************************************** */
-/* *************************************************************** */
-/* **** GENMMD ..... MULTIPLE MINIMUM EXTERNAL DEGREE **** */
-/* *************************************************************** */
-/* *************************************************************** */
-
-/* AUTHOR - JOSEPH W.H. LIU */
-/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */
-
-/* PURPOSE - THIS ROUTINE IMPLEMENTS THE MINIMUM DEGREE */
-/* ALGORITHM. IT MAKES USE OF THE IMPLICIT REPRESENTATION */
-/* OF ELIMINATION GRAPHS BY QUOTIENT GRAPHS, AND THE */
-/* NOTION OF INDISTINGUISHABLE NODES. IT ALSO IMPLEMENTS */
-/* THE MODIFICATIONS BY MULTIPLE ELIMINATION AND MINIMUM */
-/* EXTERNAL DEGREE. */
-/* --------------------------------------------- */
-/* CAUTION - THE ADJACENCY VECTOR ADJNCY WILL BE */
-/* DESTROYED. */
-/* --------------------------------------------- */
-
-/* INPUT PARAMETERS - */
-/* NEQNS - NUMBER OF EQUATIONS. */
-/* (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. */
-/* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */
-/* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) INTEGER */
-/* (ANY SMALLER ESTIMATE WILL DO) FOR MARKING */
-/* NODES. */
-
-/* OUTPUT PARAMETERS - */
-/* PERM - THE MINIMUM DEGREE ORDERING. */
-/* INVP - THE INVERSE OF PERM. */
-/* NOFSUB - AN UPPER BOUND ON THE NUMBER OF NONZERO */
-/* SUBSCRIPTS FOR THE COMPRESSED STORAGE SCHEME. */
-
-/* WORKING PARAMETERS - */
-/* DHEAD - VECTOR FOR HEAD OF DEGREE LISTS. */
-/* INVP - USED TEMPORARILY FOR DEGREE FORWARD LINK. */
-/* PERM - USED TEMPORARILY FOR DEGREE BACKWARD LINK. */
-/* QSIZE - VECTOR FOR SIZE OF SUPERNODES. */
-/* LLIST - VECTOR FOR TEMPORARY LINKED LISTS. */
-/* MARKER - A TEMPORARY MARKER VECTOR. */
-
-/* PROGRAM SUBROUTINES - */
-/* MMDELM, MMDINT, MMDNUM, MMDUPD. */
-
-/* *************************************************************** */
-
-/* Subroutine */ int genmmd_(int *neqns, int *xadj, shortint *adjncy,
- shortint *invp, shortint *perm, int *delta, shortint *dhead,
- shortint *qsize, shortint *llist, shortint *marker, int *maxint,
- int *nofsub)
-{
- /* System generated locals */
- int i__1;
-
- /* Local variables */
- static int mdeg, ehead, i, mdlmt, mdnode;
- extern /* Subroutine */ int mmdelm_(int *, int *, shortint *,
- shortint *, shortint *, shortint *, shortint *, shortint *,
- shortint *, int *, int *), mmdupd_(int *, int *,
- int *, shortint *, int *, int *, shortint *, shortint
- *, shortint *, shortint *, shortint *, shortint *, int *,
- int *), mmdint_(int *, int *, shortint *, shortint *,
- shortint *, shortint *, shortint *, shortint *, shortint *),
- mmdnum_(int *, shortint *, shortint *, shortint *);
- static int nextmd, tag, num;
-
-
-/* *************************************************************** */
-
-
-/* *************************************************************** */
-
- /* Parameter adjustments */
- --marker;
- --llist;
- --qsize;
- --dhead;
- --perm;
- --invp;
- --adjncy;
- --xadj;
-
- /* Function Body */
- if (*neqns <= 0) {
- return 0;
- }
-
-/* ------------------------------------------------ */
-/* INITIALIZATION FOR THE MINIMUM DEGREE ALGORITHM. */
-/* ------------------------------------------------ */
- *nofsub = 0;
- mmdint_(neqns, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], &
- qsize[1], &llist[1], &marker[1]);
-
-/* ---------------------------------------------- */
-/* NUM COUNTS THE NUMBER OF ORDERED NODES PLUS 1. */
-/* ---------------------------------------------- */
- num = 1;
-
-/* ----------------------------- */
-/* ELIMINATE ALL ISOLATED NODES. */
-/* ----------------------------- */
- nextmd = dhead[1];
-L100:
- if (nextmd <= 0) {
- goto L200;
- }
- mdnode = nextmd;
- nextmd = invp[mdnode];
- marker[mdnode] = *maxint;
- invp[mdnode] = -num;
- ++num;
- goto L100;
-
-L200:
-/* ---------------------------------------- */
-/* SEARCH FOR NODE OF THE MINIMUM DEGREE. */
-/* MDEG IS THE CURRENT MINIMUM DEGREE; */
-/* TAG IS USED TO FACILITATE MARKING NODES. */
-/* ---------------------------------------- */
- if (num > *neqns) {
- goto L1000;
- }
- tag = 1;
- dhead[1] = 0;
- mdeg = 2;
-L300:
- if (dhead[mdeg] > 0) {
- goto L400;
- }
- ++mdeg;
- goto L300;
-L400:
-/* ------------------------------------------------- */
-/* USE VALUE OF DELTA TO SET UP MDLMT, WHICH GOVERNS */
-/* WHEN A DEGREE UPDATE IS TO BE PERFORMED. */
-/* ------------------------------------------------- */
- mdlmt = mdeg + *delta;
- ehead = 0;
-
-L500:
- mdnode = dhead[mdeg];
- if (mdnode > 0) {
- goto L600;
- }
- ++mdeg;
- if (mdeg > mdlmt) {
- goto L900;
- }
- goto L500;
-L600:
-/* ---------------------------------------- */
-/* REMOVE MDNODE FROM THE DEGREE STRUCTURE. */
-/* ---------------------------------------- */
- nextmd = invp[mdnode];
- dhead[mdeg] = nextmd;
- if (nextmd > 0) {
- perm[nextmd] = -mdeg;
- }
- invp[mdnode] = -num;
- *nofsub = *nofsub + mdeg + qsize[mdnode] - 2;
- if (num + qsize[mdnode] > *neqns) {
- goto L1000;
- }
-/* ---------------------------------------------- */
-/* ELIMINATE MDNODE AND PERFORM QUOTIENT GRAPH */
-/* TRANSFORMATION. RESET TAG VALUE IF NECESSARY. */
-/* ---------------------------------------------- */
- ++tag;
- if (tag < *maxint) {
- goto L800;
- }
- tag = 1;
- i__1 = *neqns;
- for (i = 1; i <= i__1; ++i) {
- if (marker[i] < *maxint) {
- marker[i] = 0;
- }
-/* L700: */
- }
-L800:
- mmdelm_(&mdnode, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], &
- qsize[1], &llist[1], &marker[1], maxint, &tag);
- num += qsize[mdnode];
- llist[mdnode] = ehead;
- ehead = mdnode;
- if (*delta >= 0) {
- goto L500;
- }
-L900:
-/* ------------------------------------------- */
-/* UPDATE DEGREES OF THE NODES INVOLVED IN THE */
-/* MINIMUM DEGREE NODES ELIMINATION. */
-/* ------------------------------------------- */
- if (num > *neqns) {
- goto L1000;
- }
- mmdupd_(&ehead, neqns, &xadj[1], &adjncy[1], delta, &mdeg, &dhead[1], &
- invp[1], &perm[1], &qsize[1], &llist[1], &marker[1], maxint, &tag)
- ;
- goto L300;
-
-L1000:
- mmdnum_(neqns, &perm[1], &invp[1], &qsize[1]);
- return 0;
-
-} /* genmmd_ */
-
-/* *************************************************************** */
-/* *************************************************************** */
-/* *** MMDINT ..... MULT MINIMUM DEGREE INITIALIZATION *** */
-/* *************************************************************** */
-/* *************************************************************** */
-
-/* AUTHOR - JOSEPH W.H. LIU */
-/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */
-
-/* PURPOSE - THIS ROUTINE PERFORMS INITIALIZATION FOR THE */
-/* MULTIPLE ELIMINATION VERSION OF THE MINIMUM DEGREE */
-/* ALGORITHM. */
-
-/* INPUT PARAMETERS - */
-/* NEQNS - NUMBER OF EQUATIONS. */
-/* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */
-
-/* OUTPUT PARAMETERS - */
-/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */
-/* QSIZE - SIZE OF SUPERNODE (INITIALIZED TO ONE). */
-/* LLIST - LINKED LIST. */
-/* MARKER - MARKER VECTOR. */
-
-/* *************************************************************** */
-
-/* Subroutine */ int mmdint_(int *neqns, int *xadj, shortint *adjncy,
- shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize,
- shortint *llist, shortint *marker)
-{
- /* System generated locals */
- int i__1;
-
- /* Local variables */
- static int ndeg, node, fnode;
-
-
-/* *************************************************************** */
-
-
-/* *************************************************************** */
-
- /* Parameter adjustments */
- --marker;
- --llist;
- --qsize;
- --dbakw;
- --dforw;
- --dhead;
- --adjncy;
- --xadj;
-
- /* Function Body */
- i__1 = *neqns;
- for (node = 1; node <= i__1; ++node) {
- dhead[node] = 0;
- qsize[node] = 1;
- marker[node] = 0;
- llist[node] = 0;
-/* L100: */
- }
-/* ------------------------------------------ */
-/* INITIALIZE THE DEGREE DOUBLY LINKED LISTS. */
-/* ------------------------------------------ */
- i__1 = *neqns;
- for (node = 1; node <= i__1; ++node) {
- ndeg = xadj[node + 1] - xadj[node] + 1;
- fnode = dhead[ndeg];
- dforw[node] = fnode;
- dhead[ndeg] = node;
- if (fnode > 0) {
- dbakw[fnode] = node;
- }
- dbakw[node] = -ndeg;
-/* L200: */
- }
- return 0;
-
-} /* mmdint_ */
-
-/* *************************************************************** */
-/* *************************************************************** */
-/* ** MMDELM ..... MULTIPLE MINIMUM DEGREE ELIMINATION *** */
-/* *************************************************************** */
-/* *************************************************************** */
-
-/* AUTHOR - JOSEPH W.H. LIU */
-/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */
-
-/* PURPOSE - THIS ROUTINE ELIMINATES THE NODE MDNODE OF */
-/* MINIMUM DEGREE FROM THE ADJACENCY STRUCTURE, WHICH */
-/* IS STORED IN THE QUOTIENT GRAPH FORMAT. IT ALSO */
-/* TRANSFORMS THE QUOTIENT GRAPH REPRESENTATION OF THE */
-/* ELIMINATION GRAPH. */
-
-/* INPUT PARAMETERS - */
-/* MDNODE - NODE OF MINIMUM DEGREE. */
-/* MAXINT - ESTIMATE OF MAXIMUM REPRESENTABLE (SHORT) */
-/* INT. */
-/* TAG - TAG VALUE. */
-
-/* UPDATED PARAMETERS - */
-/* (XADJ,ADJNCY) - UPDATED ADJACENCY STRUCTURE. */
-/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */
-/* QSIZE - SIZE OF SUPERNODE. */
-/* MARKER - MARKER VECTOR. */
-/* LLIST - TEMPORARY LINKED LIST OF ELIMINATED NABORS. */
-
-/* *************************************************************** */
-
-/* Subroutine */ int mmdelm_(int *mdnode, int *xadj, shortint *adjncy,
- shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize,
- shortint *llist, shortint *marker, int *maxint, int *tag)
-{
- /* System generated locals */
- int i__1, i__2;
-
- /* Local variables */
- static int node, link, rloc, rlmt, i, j, nabor, rnode, elmnt, xqnbr,
- istop, jstop, istrt, jstrt, nxnode, pvnode, nqnbrs, npv;
-
-
-/* *************************************************************** */
-
-
-/* *************************************************************** */
-
-/* ----------------------------------------------- */
-/* FIND REACHABLE SET AND PLACE IN DATA STRUCTURE. */
-/* ----------------------------------------------- */
- /* Parameter adjustments */
- --marker;
- --llist;
- --qsize;
- --dbakw;
- --dforw;
- --dhead;
- --adjncy;
- --xadj;
-
- /* Function Body */
- marker[*mdnode] = *tag;
- istrt = xadj[*mdnode];
- istop = xadj[*mdnode + 1] - 1;
-/* ------------------------------------------------------- */
-/* ELMNT POINTS TO THE BEGINNING OF THE LIST OF ELIMINATED */
-/* NABORS OF MDNODE, AND RLOC GIVES THE STORAGE LOCATION */
-/* FOR THE NEXT REACHABLE NODE. */
-/* ------------------------------------------------------- */
- elmnt = 0;
- rloc = istrt;
- rlmt = istop;
- i__1 = istop;
- for (i = istrt; i <= i__1; ++i) {
- nabor = adjncy[i];
- if (nabor == 0) {
- goto L300;
- }
- if (marker[nabor] >= *tag) {
- goto L200;
- }
- marker[nabor] = *tag;
- if (dforw[nabor] < 0) {
- goto L100;
- }
- adjncy[rloc] = nabor;
- ++rloc;
- goto L200;
-L100:
- llist[nabor] = elmnt;
- elmnt = nabor;
-L200:
- ;
- }
-L300:
-/* ----------------------------------------------------- */
-/* MERGE WITH REACHABLE NODES FROM GENERALIZED ELEMENTS. */
-/* ----------------------------------------------------- */
- if (elmnt <= 0) {
- goto L1000;
- }
- adjncy[rlmt] = -elmnt;
- link = elmnt;
-L400:
- jstrt = xadj[link];
- jstop = xadj[link + 1] - 1;
- i__1 = jstop;
- for (j = jstrt; j <= i__1; ++j) {
- node = adjncy[j];
- link = -node;
- if (node < 0) {
- goto L400;
- } else if (node == 0) {
- goto L900;
- } else {
- goto L500;
- }
-L500:
- if (marker[node] >= *tag || dforw[node] < 0) {
- goto L800;
- }
- marker[node] = *tag;
-/* --------------------------------- */
-/* USE STORAGE FROM ELIMINATED NODES */
-/* IF NECESSARY. */
-/* --------------------------------- */
-L600:
- if (rloc < rlmt) {
- goto L700;
- }
- link = -adjncy[rlmt];
- rloc = xadj[link];
- rlmt = xadj[link + 1] - 1;
- goto L600;
-L700:
- adjncy[rloc] = node;
- ++rloc;
-L800:
- ;
- }
-L900:
- elmnt = llist[elmnt];
- goto L300;
-L1000:
- if (rloc <= rlmt) {
- adjncy[rloc] = 0;
- }
-/* -------------------------------------------------------- */
-/* FOR EACH NODE IN THE REACHABLE SET, DO THE FOLLOWING ... */
-/* -------------------------------------------------------- */
- link = *mdnode;
-L1100:
- istrt = xadj[link];
- istop = xadj[link + 1] - 1;
- i__1 = istop;
- for (i = istrt; i <= i__1; ++i) {
- rnode = adjncy[i];
- link = -rnode;
- if (rnode < 0) {
- goto L1100;
- } else if (rnode == 0) {
- goto L1800;
- } else {
- goto L1200;
- }
-L1200:
-/* -------------------------------------------- */
-/* IF RNODE IS IN THE DEGREE LIST STRUCTURE ... */
-/* -------------------------------------------- */
- pvnode = dbakw[rnode];
- if (pvnode == 0 || pvnode == -(*maxint)) {
- goto L1300;
- }
-/* ------------------------------------- */
-/* THEN REMOVE RNODE FROM THE STRUCTURE. */
-/* ------------------------------------- */
- nxnode = dforw[rnode];
- if (nxnode > 0) {
- dbakw[nxnode] = pvnode;
- }
- if (pvnode > 0) {
- dforw[pvnode] = nxnode;
- }
- npv = -pvnode;
- if (pvnode < 0) {
- dhead[npv] = nxnode;
- }
-L1300:
-/* ---------------------------------------- */
-/* PURGE INACTIVE QUOTIENT NABORS OF RNODE. */
-/* ---------------------------------------- */
- jstrt = xadj[rnode];
- jstop = xadj[rnode + 1] - 1;
- xqnbr = jstrt;
- i__2 = jstop;
- for (j = jstrt; j <= i__2; ++j) {
- nabor = adjncy[j];
- if (nabor == 0) {
- goto L1500;
- }
- if (marker[nabor] >= *tag) {
- goto L1400;
- }
- adjncy[xqnbr] = nabor;
- ++xqnbr;
-L1400:
- ;
- }
-L1500:
-/* ---------------------------------------- */
-/* IF NO ACTIVE NABOR AFTER THE PURGING ... */
-/* ---------------------------------------- */
- nqnbrs = xqnbr - jstrt;
- if (nqnbrs > 0) {
- goto L1600;
- }
-/* ----------------------------- */
-/* THEN MERGE RNODE WITH MDNODE. */
-/* ----------------------------- */
- qsize[*mdnode] += qsize[rnode];
- qsize[rnode] = 0;
- marker[rnode] = *maxint;
- dforw[rnode] = -(*mdnode);
- dbakw[rnode] = -(*maxint);
- goto L1700;
-L1600:
-/* -------------------------------------- */
-/* ELSE FLAG RNODE FOR DEGREE UPDATE, AND */
-/* ADD MDNODE AS A NABOR OF RNODE. */
-/* -------------------------------------- */
- dforw[rnode] = nqnbrs + 1;
- dbakw[rnode] = 0;
- adjncy[xqnbr] = *mdnode;
- ++xqnbr;
- if (xqnbr <= jstop) {
- adjncy[xqnbr] = 0;
- }
-
-L1700:
- ;
- }
-L1800:
- return 0;
-
-} /* mmdelm_ */
-
-/* *************************************************************** */
-/* *************************************************************** */
-/* ***** MMDUPD ..... MULTIPLE MINIMUM DEGREE UPDATE ***** */
-/* *************************************************************** */
-/* *************************************************************** */
-
-/* AUTHOR - JOSEPH W.H. LIU */
-/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */
-
-/* PURPOSE - THIS ROUTINE UPDATES THE DEGREES OF NODES */
-/* AFTER A MULTIPLE ELIMINATION STEP. */
-
-/* INPUT PARAMETERS - */
-/* EHEAD - THE BEGINNING OF THE LIST OF ELIMINATED */
-/* NODES (I.E., NEWLY FORMED ELEMENTS). */
-/* NEQNS - NUMBER OF EQUATIONS. */
-/* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */
-/* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */
-/* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) */
-/* INTEGER. */
-
-/* UPDATED PARAMETERS - */
-/* MDEG - NEW MINIMUM DEGREE AFTER DEGREE UPDATE. */
-/* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */
-/* QSIZE - SIZE OF SUPERNODE. */
-/* LLIST - WORKING LINKED LIST. */
-/* MARKER - MARKER VECTOR FOR DEGREE UPDATE. */
-/* TAG - TAG VALUE. */
-
-/* *************************************************************** */
-
-/* Subroutine */ int mmdupd_(int *ehead, int *neqns, int *xadj,
- shortint *adjncy, int *delta, int *mdeg, shortint *dhead,
- shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist,
- shortint *marker, int *maxint, int *tag)
-{
- /* System generated locals */
- int i__1, i__2;
-
- /* Local variables */
- static int node, mtag, link, mdeg0, i, j, enode, fnode, nabor, elmnt,
- istop, jstop, q2head, istrt, jstrt, qxhead, iq2, deg, deg0;
-
-
-/* *************************************************************** */
-
-
-/* *************************************************************** */
-
- /* Parameter adjustments */
- --marker;
- --llist;
- --qsize;
- --dbakw;
- --dforw;
- --dhead;
- --adjncy;
- --xadj;
-
- /* Function Body */
- mdeg0 = *mdeg + *delta;
- elmnt = *ehead;
-L100:
-/* ------------------------------------------------------- */
-/* FOR EACH OF THE NEWLY FORMED ELEMENT, DO THE FOLLOWING. */
-/* (RESET TAG VALUE IF NECESSARY.) */
-/* ------------------------------------------------------- */
- if (elmnt <= 0) {
- return 0;
- }
- mtag = *tag + mdeg0;
- if (mtag < *maxint) {
- goto L300;
- }
- *tag = 1;
- i__1 = *neqns;
- for (i = 1; i <= i__1; ++i) {
- if (marker[i] < *maxint) {
- marker[i] = 0;
- }
-/* L200: */
- }
- mtag = *tag + mdeg0;
-L300:
-/* --------------------------------------------- */
-/* CREATE TWO LINKED LISTS FROM NODES ASSOCIATED */
-/* WITH ELMNT: ONE WITH TWO NABORS (Q2HEAD) IN */
-/* ADJACENCY STRUCTURE, AND THE OTHER WITH MORE */
-/* THAN TWO NABORS (QXHEAD). ALSO COMPUTE DEG0, */
-/* NUMBER OF NODES IN THIS ELEMENT. */
-/* --------------------------------------------- */
- q2head = 0;
- qxhead = 0;
- deg0 = 0;
- link = elmnt;
-L400:
- istrt = xadj[link];
- istop = xadj[link + 1] - 1;
- i__1 = istop;
- for (i = istrt; i <= i__1; ++i) {
- enode = adjncy[i];
- link = -enode;
- if (enode < 0) {
- goto L400;
- } else if (enode == 0) {
- goto L800;
- } else {
- goto L500;
- }
-
-L500:
- if (qsize[enode] == 0) {
- goto L700;
- }
- deg0 += qsize[enode];
- marker[enode] = mtag;
-/* ---------------------------------- */
-/* IF ENODE REQUIRES A DEGREE UPDATE, */
-/* THEN DO THE FOLLOWING. */
-/* ---------------------------------- */
- if (dbakw[enode] != 0) {
- goto L700;
- }
-/* ---------------------------------------
-*/
-/* PLACE EITHER IN QXHEAD OR Q2HEAD LISTS.
-*/
-/* ---------------------------------------
-*/
- if (dforw[enode] == 2) {
- goto L600;
- }
- llist[enode] = qxhead;
- qxhead = enode;
- goto L700;
-L600:
- llist[enode] = q2head;
- q2head = enode;
-L700:
- ;
- }
-L800:
-/* -------------------------------------------- */
-/* FOR EACH ENODE IN Q2 LIST, DO THE FOLLOWING. */
-/* -------------------------------------------- */
- enode = q2head;
- iq2 = 1;
-L900:
- if (enode <= 0) {
- goto L1500;
- }
- if (dbakw[enode] != 0) {
- goto L2200;
- }
- ++(*tag);
- deg = deg0;
-/* ------------------------------------------ */
-/* IDENTIFY THE OTHER ADJACENT ELEMENT NABOR. */
-/* ------------------------------------------ */
- istrt = xadj[enode];
- nabor = adjncy[istrt];
- if (nabor == elmnt) {
- nabor = adjncy[istrt + 1];
- }
-/* ------------------------------------------------ */
-/* IF NABOR IS UNELIMINATED, INCREASE DEGREE COUNT. */
-/* ------------------------------------------------ */
- link = nabor;
- if (dforw[nabor] < 0) {
- goto L1000;
- }
- deg += qsize[nabor];
- goto L2100;
-L1000:
-/* -------------------------------------------- */
-/* OTHERWISE, FOR EACH NODE IN THE 2ND ELEMENT, */
-/* DO THE FOLLOWING. */
-/* -------------------------------------------- */
- istrt = xadj[link];
- istop = xadj[link + 1] - 1;
- i__1 = istop;
- for (i = istrt; i <= i__1; ++i) {
- node = adjncy[i];
- link = -node;
- if (node == enode) {
- goto L1400;
- }
- if (node < 0) {
- goto L1000;
- } else if (node == 0) {
- goto L2100;
- } else {
- goto L1100;
- }
-
-L1100:
- if (qsize[node] == 0) {
- goto L1400;
- }
- if (marker[node] >= *tag) {
- goto L1200;
- }
-/* -----------------------------------
--- */
-/* CASE WHEN NODE IS NOT YET CONSIDERED
-. */
-/* -----------------------------------
--- */
- marker[node] = *tag;
- deg += qsize[node];
- goto L1400;
-L1200:
-/* ----------------------------------------
- */
-/* CASE WHEN NODE IS INDISTINGUISHABLE FROM
- */
-/* ENODE. MERGE THEM INTO A NEW SUPERNODE.
- */
-/* ----------------------------------------
- */
- if (dbakw[node] != 0) {
- goto L1400;
- }
- if (dforw[node] != 2) {
- goto L1300;
- }
- qsize[enode] += qsize[node];
- qsize[node] = 0;
- marker[node] = *maxint;
- dforw[node] = -enode;
- dbakw[node] = -(*maxint);
- goto L1400;
-L1300:
-/* --------------------------------------
-*/
-/* CASE WHEN NODE IS OUTMATCHED BY ENODE.
-*/
-/* --------------------------------------
-*/
- if (dbakw[node] == 0) {
- dbakw[node] = -(*maxint);
- }
-L1400:
- ;
- }
- goto L2100;
-L1500:
-/* ------------------------------------------------ */
-/* FOR EACH ENODE IN THE QX LIST, DO THE FOLLOWING. */
-/* ------------------------------------------------ */
- enode = qxhead;
- iq2 = 0;
-L1600:
- if (enode <= 0) {
- goto L2300;
- }
- if (dbakw[enode] != 0) {
- goto L2200;
- }
- ++(*tag);
- deg = deg0;
-/* --------------------------------- */
-/* FOR EACH UNMARKED NABOR OF ENODE, */
-/* DO THE FOLLOWING. */
-/* --------------------------------- */
- istrt = xadj[enode];
- istop = xadj[enode + 1] - 1;
- i__1 = istop;
- for (i = istrt; i <= i__1; ++i) {
- nabor = adjncy[i];
- if (nabor == 0) {
- goto L2100;
- }
- if (marker[nabor] >= *tag) {
- goto L2000;
- }
- marker[nabor] = *tag;
- link = nabor;
-/* ------------------------------ */
-/* IF UNELIMINATED, INCLUDE IT IN */
-/* DEG COUNT. */
-/* ------------------------------ */
- if (dforw[nabor] < 0) {
- goto L1700;
- }
- deg += qsize[nabor];
- goto L2000;
-L1700:
-/* -------------------------------
-*/
-/* IF ELIMINATED, INCLUDE UNMARKED
-*/
-/* NODES IN THIS ELEMENT INTO THE
-*/
-/* DEGREE COUNT. */
-/* -------------------------------
-*/
- jstrt = xadj[link];
- jstop = xadj[link + 1] - 1;
- i__2 = jstop;
- for (j = jstrt; j <= i__2; ++j) {
- node = adjncy[j];
- link = -node;
- if (node < 0) {
- goto L1700;
- } else if (node == 0) {
- goto L2000;
- } else {
- goto L1800;
- }
-
-L1800:
- if (marker[node] >= *tag) {
- goto L1900;
- }
- marker[node] = *tag;
- deg += qsize[node];
-L1900:
- ;
- }
-L2000:
- ;
- }
-L2100:
-/* ------------------------------------------- */
-/* UPDATE EXTERNAL DEGREE OF ENODE IN DEGREE */
-/* STRUCTURE, AND MDEG (MIN DEG) IF NECESSARY. */
-/* ------------------------------------------- */
- deg = deg - qsize[enode] + 1;
- fnode = dhead[deg];
- dforw[enode] = fnode;
- dbakw[enode] = -deg;
- if (fnode > 0) {
- dbakw[fnode] = enode;
- }
- dhead[deg] = enode;
- if (deg < *mdeg) {
- *mdeg = deg;
- }
-L2200:
-/* ---------------------------------- */
-/* GET NEXT ENODE IN CURRENT ELEMENT. */
-/* ---------------------------------- */
- enode = llist[enode];
- if (iq2 == 1) {
- goto L900;
- }
- goto L1600;
-L2300:
-/* ----------------------------- */
-/* GET NEXT ELEMENT IN THE LIST. */
-/* ----------------------------- */
- *tag = mtag;
- elmnt = llist[elmnt];
- goto L100;
-
-} /* mmdupd_ */
-
-/* *************************************************************** */
-/* *************************************************************** */
-/* ***** MMDNUM ..... MULTI MINIMUM DEGREE NUMBERING ***** */
-/* *************************************************************** */
-/* *************************************************************** */
-
-/* AUTHOR - JOSEPH W.H. LIU */
-/* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */
-
-/* PURPOSE - THIS ROUTINE PERFORMS THE FINAL STEP IN */
-/* PRODUCING THE PERMUTATION AND INVERSE PERMUTATION */
-/* VECTORS IN THE MULTIPLE ELIMINATION VERSION OF THE */
-/* MINIMUM DEGREE ORDERING ALGORITHM. */
-
-/* INPUT PARAMETERS - */
-/* NEQNS - NUMBER OF EQUATIONS. */
-/* QSIZE - SIZE OF SUPERNODES AT ELIMINATION. */
-
-/* UPDATED PARAMETERS - */
-/* INVP - INVERSE PERMUTATION VECTOR. ON INPUT, */
-/* IF QSIZE(NODE)=0, THEN NODE HAS BEEN MERGED */
-/* INTO THE NODE -INVP(NODE); OTHERWISE, */
-/* -INVP(NODE) IS ITS INVERSE LABELLING. */
-
-/* OUTPUT PARAMETERS - */
-/* PERM - THE PERMUTATION VECTOR. */
-
-/* *************************************************************** */
-
-/* Subroutine */ int mmdnum_(int *neqns, shortint *perm, shortint *invp,
- shortint *qsize)
-{
- /* System generated locals */
- int i__1;
-
- /* Local variables */
- static int node, root, nextf, father, nqsize, num;
-
-
-/* *************************************************************** */
-
-
-/* *************************************************************** */
-
- /* Parameter adjustments */
- --qsize;
- --invp;
- --perm;
-
- /* Function Body */
- i__1 = *neqns;
- for (node = 1; node <= i__1; ++node) {
- nqsize = qsize[node];
- if (nqsize <= 0) {
- perm[node] = invp[node];
- }
- if (nqsize > 0) {
- perm[node] = -invp[node];
- }
-/* L100: */
- }
-/* ------------------------------------------------------ */
-/* FOR EACH NODE WHICH HAS BEEN MERGED, DO THE FOLLOWING. */
-/* ------------------------------------------------------ */
- i__1 = *neqns;
- for (node = 1; node <= i__1; ++node) {
- if (perm[node] > 0) {
- goto L500;
- }
-/* ----------------------------------------- */
-/* TRACE THE MERGED TREE UNTIL ONE WHICH HAS */
-/* NOT BEEN MERGED, CALL IT ROOT. */
-/* ----------------------------------------- */
- father = node;
-L200:
- if (perm[father] > 0) {
- goto L300;
- }
- father = -perm[father];
- goto L200;
-L300:
-/* ----------------------- */
-/* NUMBER NODE AFTER ROOT. */
-/* ----------------------- */
- root = father;
- num = perm[root] + 1;
- invp[node] = -num;
- perm[root] = num;
-/* ------------------------ */
-/* SHORTEN THE MERGED TREE. */
-/* ------------------------ */
- father = node;
-L400:
- nextf = -perm[father];
- if (nextf <= 0) {
- goto L500;
- }
- perm[father] = -root;
- father = nextf;
- goto L400;
-L500:
- ;
- }
-/* ---------------------- */
-/* READY TO COMPUTE PERM. */
-/* ---------------------- */
- i__1 = *neqns;
- for (node = 1; node <= i__1; ++node) {
- num = -invp[node];
- invp[node] = num;
- perm[num] = node;
-/* L600: */
- }
- return 0;
-
-} /* mmdnum_ */
-
diff --git a/intern/opennl/superlu/relax_snode.c b/intern/opennl/superlu/relax_snode.c
deleted file mode 100644
index 4a9265e0fde..00000000000
--- a/intern/opennl/superlu/relax_snode.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/** \file opennl/superlu/relax_snode.c
- * \ingroup opennl
- */
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-
-void
-relax_snode (
- const int n,
- int *et, /* column elimination tree */
- const int relax_columns, /* max no of columns allowed in a
- relaxed snode */
- int *descendants, /* no of descendants of each node
- in the etree */
- int *relax_end /* last column in a supernode */
- )
-{
-/*
- * Purpose
- * =======
- * relax_snode() - Identify the initial relaxed supernodes, assuming that
- * the matrix has been reordered according to the postorder of the etree.
- *
- */
- register int j, parent;
- register int snode_start; /* beginning of a snode */
-
- ifill (relax_end, n, EMPTY);
- for (j = 0; j < n; j++) descendants[j] = 0;
-
- /* Compute the number of descendants of each node in the etree */
- for (j = 0; j < n; j++) {
- parent = et[j];
- if ( parent != n ) /* not the dummy root */
- descendants[parent] += descendants[j] + 1;
- }
-
- /* Identify the relaxed supernodes by postorder traversal of the etree. */
- for (j = 0; j < n; ) {
- parent = et[j];
- snode_start = j;
- while ( parent != n && descendants[parent] < relax_columns ) {
- j = parent;
- parent = et[j];
- }
- /* Found a supernode with j being the last column. */
- relax_end[snode_start] = j; /* Last column is recorded */
- j++;
- /* Search for a new leaf */
- while ( j < n && descendants[j] != 0 ) j++;
- }
-
- /*printf("No of relaxed snodes: %d; relaxed columns: %d\n",
- nsuper, no_relaxed_col); */
-}
diff --git a/intern/opennl/superlu/scolumn_bmod.c b/intern/opennl/superlu/scolumn_bmod.c
deleted file mode 100644
index 9854115b894..00000000000
--- a/intern/opennl/superlu/scolumn_bmod.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/** \file opennl/superlu/scolumn_bmod.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "ssp_defs.h"
-
-/*
- * Function prototypes
- */
-void susolve(int, int, double*, double*);
-void slsolve(int, int, double*, double*);
-void smatvec(int, int, int, double*, double*, double*);
-
-
-
-/* Return value: 0 - successful return
- * > 0 - number of bytes allocated when run out of space
- */
-int
-scolumn_bmod (
- const int jcol, /* in */
- const int nseg, /* in */
- double *dense, /* in */
- double *tempv, /* working array */
- int *segrep, /* in */
- int *repfnz, /* in */
- int fpanelc, /* in -- first column in the current panel */
- GlobalLU_t *Glu, /* modified */
- SuperLUStat_t *stat /* output */
- )
-{
-/*
- * Purpose:
- * ========
- * Performs numeric block updates (sup-col) in topological order.
- * It features: col-col, 2cols-col, 3cols-col, and sup-col updates.
- * Special processing on the supernodal portion of L\U[*,j]
- *
- */
-#ifdef _CRAY
- _fcd ftcs1 = _cptofcd("L", strlen("L")),
- ftcs2 = _cptofcd("N", strlen("N")),
- ftcs3 = _cptofcd("U", strlen("U"));
-#endif
-
-#ifdef USE_VENDOR_BLAS
- int incx = 1, incy = 1;
- double alpha, beta;
-#endif
-
- /* krep = representative of current k-th supernode
- * fsupc = first supernodal column
- * nsupc = no of columns in supernode
- * nsupr = no of rows in supernode (used as leading dimension)
- * luptr = location of supernodal LU-block in storage
- * kfnz = first nonz in the k-th supernodal segment
- * no_zeros = no of leading zeros in a supernodal U-segment
- */
- double ukj, ukj1, ukj2;
- int luptr, luptr1, luptr2;
- int fsupc, nsupc, nsupr, segsze;
- int nrow; /* No of rows in the matrix of matrix-vector */
- int jcolp1, jsupno, k, ksub, krep, krep_ind, ksupno;
- register int lptr, kfnz, isub, irow, i;
- register int no_zeros, new_next;
- int ufirst, nextlu;
- int fst_col; /* First column within small LU update */
- int d_fsupc; /* Distance between the first column of the current
- panel and the first column of the current snode. */
- int *xsup, *supno;
- int *lsub, *xlsub;
- double *lusup;
- int *xlusup;
- int nzlumax;
- double *tempv1;
- double zero = 0.0;
-#ifdef USE_VENDOR_BLAS
- double one = 1.0;
- double none = -1.0;
-#endif
- int mem_error;
- flops_t *ops = stat->ops;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- lusup = Glu->lusup;
- xlusup = Glu->xlusup;
- nzlumax = Glu->nzlumax;
- jcolp1 = jcol + 1;
- jsupno = supno[jcol];
-
- /*
- * For each nonz supernode segment of U[*,j] in topological order
- */
- k = nseg - 1;
- for (ksub = 0; ksub < nseg; ksub++) {
-
- krep = segrep[k];
- k--;
- ksupno = supno[krep];
- if ( jsupno != ksupno ) { /* Outside the rectangular supernode */
-
- fsupc = xsup[ksupno];
- fst_col = SUPERLU_MAX ( fsupc, fpanelc );
-
- /* Distance from the current supernode to the current panel;
- d_fsupc=0 if fsupc > fpanelc. */
- d_fsupc = fst_col - fsupc;
-
- luptr = xlusup[fst_col] + d_fsupc;
- lptr = xlsub[fsupc] + d_fsupc;
-
- kfnz = repfnz[krep];
- kfnz = SUPERLU_MAX ( kfnz, fpanelc );
-
- segsze = krep - kfnz + 1;
- nsupc = krep - fst_col + 1;
- nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */
- nrow = nsupr - d_fsupc - nsupc;
- krep_ind = lptr + nsupc - 1;
-
- ops[TRSV] += segsze * (segsze - 1);
- ops[GEMV] += 2 * nrow * segsze;
-
-
- /*
- * Case 1: Update U-segment of size 1 -- col-col update
- */
- if ( segsze == 1 ) {
- ukj = dense[lsub[krep_ind]];
- luptr += nsupr*(nsupc-1) + nsupc;
-
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- dense[irow] -= ukj*lusup[luptr];
- luptr++;
- }
-
- } else if ( segsze <= 3 ) {
- ukj = dense[lsub[krep_ind]];
- luptr += nsupr*(nsupc-1) + nsupc-1;
- ukj1 = dense[lsub[krep_ind - 1]];
- luptr1 = luptr - nsupr;
-
- if ( segsze == 2 ) { /* Case 2: 2cols-col update */
- ukj -= ukj1 * lusup[luptr1];
- dense[lsub[krep_ind]] = ukj;
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- luptr++;
- luptr1++;
- dense[irow] -= ( ukj*lusup[luptr]
- + ukj1*lusup[luptr1] );
- }
- } else { /* Case 3: 3cols-col update */
- ukj2 = dense[lsub[krep_ind - 2]];
- luptr2 = luptr1 - nsupr;
- ukj1 -= ukj2 * lusup[luptr2-1];
- ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2];
- dense[lsub[krep_ind]] = ukj;
- dense[lsub[krep_ind-1]] = ukj1;
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- luptr++;
- luptr1++;
- luptr2++;
- dense[irow] -= ( ukj*lusup[luptr]
- + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] );
- }
- }
-
-
-
- } else {
- /*
- * Case: sup-col update
- * Perform a triangular solve and block update,
- * then scatter the result of sup-col update to dense
- */
-
- no_zeros = kfnz - fst_col;
-
- /* Copy U[*,j] segment from dense[*] to tempv[*] */
- isub = lptr + no_zeros;
- for (i = 0; i < segsze; i++) {
- irow = lsub[isub];
- tempv[i] = dense[irow];
- ++isub;
- }
-
- /* Dense triangular solve -- start effective triangle */
- luptr += nsupr * no_zeros + no_zeros;
-
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr],
- &nsupr, tempv, &incx );
-#else
- strsv_( "L", "N", "U", &segsze, &lusup[luptr],
- &nsupr, tempv, &incx );
-#endif
- luptr += segsze; /* Dense matrix-vector */
- tempv1 = &tempv[segsze];
- alpha = one;
- beta = zero;
-#ifdef _CRAY
- SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr],
- &nsupr, tempv, &incx, &beta, tempv1, &incy );
-#else
- sgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr],
- &nsupr, tempv, &incx, &beta, tempv1, &incy );
-#endif
-#else
- slsolve ( nsupr, segsze, &lusup[luptr], tempv );
-
- luptr += segsze; /* Dense matrix-vector */
- tempv1 = &tempv[segsze];
- smatvec (nsupr, nrow , segsze, &lusup[luptr], tempv, tempv1);
-#endif
-
-
- /* Scatter tempv[] into SPA dense[] as a temporary storage */
- isub = lptr + no_zeros;
- for (i = 0; i < segsze; i++) {
- irow = lsub[isub];
- dense[irow] = tempv[i];
- tempv[i] = zero;
- ++isub;
- }
-
- /* Scatter tempv1[] into SPA dense[] */
- for (i = 0; i < nrow; i++) {
- irow = lsub[isub];
- dense[irow] -= tempv1[i];
- tempv1[i] = zero;
- ++isub;
- }
- }
-
- } /* if jsupno ... */
-
- } /* for each segment... */
-
- /*
- * Process the supernodal portion of L\U[*,j]
- */
- nextlu = xlusup[jcol];
- fsupc = xsup[jsupno];
-
- /* Copy the SPA dense into L\U[*,j] */
- new_next = nextlu + xlsub[fsupc+1] - xlsub[fsupc];
- while ( new_next > nzlumax ) {
- if ((mem_error = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, Glu)))
- return (mem_error);
- lusup = Glu->lusup;
- lsub = Glu->lsub;
- }
-
- for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) {
- irow = lsub[isub];
- lusup[nextlu] = dense[irow];
- dense[irow] = zero;
- ++nextlu;
- }
-
- xlusup[jcolp1] = nextlu; /* Close L\U[*,jcol] */
-
- /* For more updates within the panel (also within the current supernode),
- * should start from the first column of the panel, or the first column
- * of the supernode, whichever is bigger. There are 2 cases:
- * 1) fsupc < fpanelc, then fst_col := fpanelc
- * 2) fsupc >= fpanelc, then fst_col := fsupc
- */
- fst_col = SUPERLU_MAX ( fsupc, fpanelc );
-
- if ( fst_col < jcol ) {
-
- /* Distance between the current supernode and the current panel.
- d_fsupc=0 if fsupc >= fpanelc. */
- d_fsupc = fst_col - fsupc;
-
- luptr = xlusup[fst_col] + d_fsupc;
- nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */
- nsupc = jcol - fst_col; /* Excluding jcol */
- nrow = nsupr - d_fsupc - nsupc;
-
- /* Points to the beginning of jcol in snode L\U(jsupno) */
- ufirst = xlusup[jcol] + d_fsupc;
-
- ops[TRSV] += nsupc * (nsupc - 1);
- ops[GEMV] += 2 * nrow * nsupc;
-
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr],
- &nsupr, &lusup[ufirst], &incx );
-#else
- strsv_( "L", "N", "U", &nsupc, &lusup[luptr],
- &nsupr, &lusup[ufirst], &incx );
-#endif
-
- alpha = none; beta = one; /* y := beta*y + alpha*A*x */
-
-#ifdef _CRAY
- SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr,
- &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy );
-#else
- sgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr,
- &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy );
-#endif
-#else
- slsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] );
-
- smatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc],
- &lusup[ufirst], tempv );
-
- /* Copy updates from tempv[*] into lusup[*] */
- isub = ufirst + nsupc;
- for (i = 0; i < nrow; i++) {
- lusup[isub] -= tempv[i];
- tempv[i] = 0.0;
- ++isub;
- }
-
-#endif
-
-
- } /* if fst_col < jcol ... */
-
- return 0;
-}
diff --git a/intern/opennl/superlu/scolumn_dfs.c b/intern/opennl/superlu/scolumn_dfs.c
deleted file mode 100644
index 8f7da485a86..00000000000
--- a/intern/opennl/superlu/scolumn_dfs.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/** \file opennl/superlu/scolumn_dfs.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-
-/* What type of supernodes we want */
-#define T2_SUPER
-
-int
-scolumn_dfs(
- const int m, /* in - number of rows in the matrix */
- const int jcol, /* in */
- int *perm_r, /* in */
- int *nseg, /* modified - with new segments appended */
- int *lsub_col, /* in - defines the RHS vector to start the dfs */
- int *segrep, /* modified - with new segments appended */
- int *repfnz, /* modified */
- int *xprune, /* modified */
- int *marker, /* modified */
- int *parent, /* working array */
- int *xplore, /* working array */
- GlobalLU_t *Glu /* modified */
- )
-{
-/*
- * Purpose
- * =======
- * "column_dfs" performs a symbolic factorization on column jcol, and
- * decide the supernode boundary.
- *
- * This routine does not use numeric values, but only use the RHS
- * row indices to start the dfs.
- *
- * A supernode representative is the last column of a supernode.
- * The nonzeros in U[*,j] are segments that end at supernodal
- * representatives. The routine returns a list of such supernodal
- * representatives in topological order of the dfs that generates them.
- * The location of the first nonzero in each such supernodal segment
- * (supernodal entry location) is also returned.
- *
- * Local parameters
- * ================
- * nseg: no of segments in current U[*,j]
- * jsuper: jsuper=EMPTY if column j does not belong to the same
- * supernode as j-1. Otherwise, jsuper=nsuper.
- *
- * marker2: A-row --> A-row/col (0/1)
- * repfnz: SuperA-col --> PA-row
- * parent: SuperA-col --> SuperA-col
- * xplore: SuperA-col --> index to L-structure
- *
- * Return value
- * ============
- * 0 success;
- * > 0 number of bytes allocated when run out of space.
- *
- */
- int jcolp1, jcolm1, jsuper, nsuper, nextl;
- int k, krep, krow, kmark, kperm;
- int *marker2; /* Used for small panel LU */
- int fsupc; /* First column of a snode */
- int myfnz; /* First nonz column of a U-segment */
- int chperm, chmark, chrep, kchild;
- int xdfs, maxdfs, kpar, oldrep;
- int jptr, jm1ptr;
- int ito, ifrom, istop; /* Used to compress row subscripts */
- int mem_error;
- int *xsup, *supno, *lsub, *xlsub;
- int nzlmax;
- static int first = 1, maxsuper;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- nzlmax = Glu->nzlmax;
-
- if ( first ) {
- maxsuper = sp_ienv(3);
- first = 0;
- }
- jcolp1 = jcol + 1;
- jcolm1 = jcol - 1;
- nsuper = supno[jcol];
- jsuper = nsuper;
- nextl = xlsub[jcol];
- marker2 = &marker[2*m];
-
-
- /* For each nonzero in A[*,jcol] do dfs */
- for (k = 0; lsub_col[k] != EMPTY; k++) {
-
- krow = lsub_col[k];
- lsub_col[k] = EMPTY;
- kmark = marker2[krow];
-
- /* krow was visited before, go to the next nonz */
- if ( kmark == jcol ) continue;
-
- /* For each unmarked nbr krow of jcol
- * krow is in L: place it in structure of L[*,jcol]
- */
- marker2[krow] = jcol;
- kperm = perm_r[krow];
-
- if ( kperm == EMPTY ) {
- lsub[nextl++] = krow; /* krow is indexed into A */
- if ( nextl >= nzlmax ) {
- if ((mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)))
- return (mem_error);
- lsub = Glu->lsub;
- }
- if ( kmark != jcolm1 ) jsuper = EMPTY;/* Row index subset testing */
- } else {
- /* krow is in U: if its supernode-rep krep
- * has been explored, update repfnz[*]
- */
- krep = xsup[supno[kperm]+1] - 1;
- myfnz = repfnz[krep];
-
- if ( myfnz != EMPTY ) { /* Visited before */
- if ( myfnz > kperm ) repfnz[krep] = kperm;
- /* continue; */
- }
- else {
- /* Otherwise, perform dfs starting at krep */
- oldrep = EMPTY;
- parent[krep] = oldrep;
- repfnz[krep] = kperm;
- xdfs = xlsub[krep];
- maxdfs = xprune[krep];
-
- do {
- /*
- * For each unmarked kchild of krep
- */
- while ( xdfs < maxdfs ) {
-
- kchild = lsub[xdfs];
- xdfs++;
- chmark = marker2[kchild];
-
- if ( chmark != jcol ) { /* Not reached yet */
- marker2[kchild] = jcol;
- chperm = perm_r[kchild];
-
- /* Case kchild is in L: place it in L[*,k] */
- if ( chperm == EMPTY ) {
- lsub[nextl++] = kchild;
- if ( nextl >= nzlmax ) {
- if ((mem_error =
- sLUMemXpand(jcol,nextl,LSUB,&nzlmax,Glu)))
- return (mem_error);
- lsub = Glu->lsub;
- }
- if ( chmark != jcolm1 ) jsuper = EMPTY;
- } else {
- /* Case kchild is in U:
- * chrep = its supernode-rep. If its rep has
- * been explored, update its repfnz[*]
- */
- chrep = xsup[supno[chperm]+1] - 1;
- myfnz = repfnz[chrep];
- if ( myfnz != EMPTY ) { /* Visited before */
- if ( myfnz > chperm )
- repfnz[chrep] = chperm;
- } else {
- /* Continue dfs at super-rep of kchild */
- xplore[krep] = xdfs;
- oldrep = krep;
- krep = chrep; /* Go deeper down G(L^t) */
- parent[krep] = oldrep;
- repfnz[krep] = chperm;
- xdfs = xlsub[krep];
- maxdfs = xprune[krep];
- } /* else */
-
- } /* else */
-
- } /* if */
-
- } /* while */
-
- /* krow has no more unexplored nbrs;
- * place supernode-rep krep in postorder DFS.
- * backtrack dfs to its parent
- */
- segrep[*nseg] = krep;
- ++(*nseg);
- kpar = parent[krep]; /* Pop from stack, mimic recursion */
- if ( kpar == EMPTY ) break; /* dfs done */
- krep = kpar;
- xdfs = xplore[krep];
- maxdfs = xprune[krep];
-
- } while ( kpar != EMPTY ); /* Until empty stack */
-
- } /* else */
-
- } /* else */
-
- } /* for each nonzero ... */
-
- /* Check to see if j belongs in the same supernode as j-1 */
- if ( jcol == 0 ) { /* Do nothing for column 0 */
- nsuper = supno[0] = 0;
- } else {
- fsupc = xsup[nsuper];
- jptr = xlsub[jcol]; /* Not compressed yet */
- jm1ptr = xlsub[jcolm1];
-
-#ifdef T2_SUPER
- if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = EMPTY;
-#endif
- /* Make sure the number of columns in a supernode doesn't
- exceed threshold. */
- if ( jcol - fsupc >= maxsuper ) jsuper = EMPTY;
-
- /* If jcol starts a new supernode, reclaim storage space in
- * lsub from the previous supernode. Note we only store
- * the subscript set of the first and last columns of
- * a supernode. (first for num values, last for pruning)
- */
- if ( jsuper == EMPTY ) { /* starts a new supernode */
- if ( (fsupc < jcolm1-1) ) { /* >= 3 columns in nsuper */
-#ifdef CHK_COMPRESS
- printf(" Compress lsub[] at super %d-%d\n", fsupc, jcolm1);
-#endif
- ito = xlsub[fsupc+1];
- xlsub[jcolm1] = ito;
- istop = ito + jptr - jm1ptr;
- xprune[jcolm1] = istop; /* Initialize xprune[jcol-1] */
- xlsub[jcol] = istop;
- for (ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito)
- lsub[ito] = lsub[ifrom];
- nextl = ito; /* = istop + length(jcol) */
- }
- nsuper++;
- supno[jcol] = nsuper;
- } /* if a new supernode */
-
- } /* else: jcol > 0 */
-
- /* Tidy up the pointers before exit */
- xsup[nsuper+1] = jcolp1;
- supno[jcolp1] = nsuper;
- xprune[jcol] = nextl; /* Initialize upper bound for pruning */
- xlsub[jcolp1] = nextl;
-
- return 0;
-}
diff --git a/intern/opennl/superlu/scopy_to_ucol.c b/intern/opennl/superlu/scopy_to_ucol.c
deleted file mode 100644
index 4cf7d64a349..00000000000
--- a/intern/opennl/superlu/scopy_to_ucol.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/** \file opennl/superlu/scopy_to_ucol.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-#include "util.h"
-
-int
-scopy_to_ucol(
- int jcol, /* in */
- int nseg, /* in */
- int *segrep, /* in */
- int *repfnz, /* in */
- int *perm_r, /* in */
- double *dense, /* modified - reset to zero on return */
- GlobalLU_t *Glu /* modified */
- )
-{
-/*
- * Gather from SPA dense[*] to global ucol[*].
- */
- int ksub, krep, ksupno;
- int i, k, kfnz, segsze;
- int fsupc, isub, irow;
- int jsupno, nextu;
- int new_next, mem_error;
- int *xsup, *supno;
- int *lsub, *xlsub;
- double *ucol;
- int *usub, *xusub;
- int nzumax;
-
- double zero = 0.0;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- ucol = Glu->ucol;
- usub = Glu->usub;
- xusub = Glu->xusub;
- nzumax = Glu->nzumax;
-
- jsupno = supno[jcol];
- nextu = xusub[jcol];
- k = nseg - 1;
- for (ksub = 0; ksub < nseg; ksub++) {
- krep = segrep[k--];
- ksupno = supno[krep];
-
- if ( ksupno != jsupno ) { /* Should go into ucol[] */
- kfnz = repfnz[krep];
- if ( kfnz != EMPTY ) { /* Nonzero U-segment */
-
- fsupc = xsup[ksupno];
- isub = xlsub[fsupc] + kfnz - fsupc;
- segsze = krep - kfnz + 1;
-
- new_next = nextu + segsze;
- while ( new_next > nzumax ) {
- if ((mem_error = sLUMemXpand(jcol, nextu, UCOL, &nzumax, Glu)))
- return (mem_error);
- ucol = Glu->ucol;
- if ((mem_error = sLUMemXpand(jcol, nextu, USUB, &nzumax, Glu)))
- return (mem_error);
- usub = Glu->usub;
- lsub = Glu->lsub;
- }
-
- for (i = 0; i < segsze; i++) {
- irow = lsub[isub];
- usub[nextu] = perm_r[irow];
- ucol[nextu] = dense[irow];
- dense[irow] = zero;
- nextu++;
- isub++;
- }
-
- }
-
- }
-
- } /* for each segment... */
-
- xusub[jcol + 1] = nextu; /* Close U[*,jcol] */
- return 0;
-}
diff --git a/intern/opennl/superlu/sgssv.c b/intern/opennl/superlu/sgssv.c
deleted file mode 100644
index b2a9848e597..00000000000
--- a/intern/opennl/superlu/sgssv.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/** \file opennl/superlu/sgssv.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-#include "ssp_defs.h"
-
-void
-sgssv(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r,
- SuperMatrix *L, SuperMatrix *U, SuperMatrix *B,
- SuperLUStat_t *stat, int *info )
-{
-/*
- * Purpose
- * =======
- *
- * SGSSV solves the system of linear equations A*X=B, using the
- * LU factorization from SGSTRF. It performs the following steps:
- *
- * 1. If A is stored column-wise (A->Stype = SLU_NC):
- *
- * 1.1. Permute the columns of A, forming A*Pc, where Pc
- * is a permutation matrix. For more details of this step,
- * see sp_preorder.c.
- *
- * 1.2. Factor A as Pr*A*Pc=L*U with the permutation Pr determined
- * by Gaussian elimination with partial pivoting.
- * L is unit lower triangular with offdiagonal entries
- * bounded by 1 in magnitude, and U is upper triangular.
- *
- * 1.3. Solve the system of equations A*X=B using the factored
- * form of A.
- *
- * 2. If A is stored row-wise (A->Stype = SLU_NR), apply the
- * above algorithm to the transpose of A:
- *
- * 2.1. Permute columns of transpose(A) (rows of A),
- * forming transpose(A)*Pc, where Pc is a permutation matrix.
- * For more details of this step, see sp_preorder.c.
- *
- * 2.2. Factor A as Pr*transpose(A)*Pc=L*U with the permutation Pr
- * determined by Gaussian elimination with partial pivoting.
- * L is unit lower triangular with offdiagonal entries
- * bounded by 1 in magnitude, and U is upper triangular.
- *
- * 2.3. Solve the system of equations A*X=B using the factored
- * form of A.
- *
- * See supermatrix.h for the definition of 'SuperMatrix' structure.
- *
- * Arguments
- * =========
- *
- * options (input) superlu_options_t*
- * The structure defines the input parameters to control
- * how the LU decomposition will be performed and how the
- * system will be solved.
- *
- * A (input) SuperMatrix*
- * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
- * of linear equations is A->nrow. Currently, the type of A can be:
- * Stype = SLU_NC or SLU_NR; Dtype = SLU_S; Mtype = SLU_GE.
- * In the future, more general A may be handled.
- *
- * perm_c (input/output) int*
- * If A->Stype = SLU_NC, column permutation vector of size A->ncol
- * which defines the permutation matrix Pc; perm_c[i] = j means
- * column i of A is in position j in A*Pc.
- * If A->Stype = SLU_NR, column permutation vector of size A->nrow
- * which describes permutation of columns of transpose(A)
- * (rows of A) as described above.
- *
- * If options->ColPerm = MY_PERMC or options->Fact = SamePattern or
- * options->Fact = SamePattern_SameRowPerm, it is an input argument.
- * On exit, perm_c may be overwritten by the product of the input
- * perm_c and a permutation that postorders the elimination tree
- * of Pc'*A'*A*Pc; perm_c is not changed if the elimination tree
- * is already in postorder.
- * Otherwise, it is an output argument.
- *
- * perm_r (input/output) int*
- * If A->Stype = SLU_NC, row permutation vector of size A->nrow,
- * which defines the permutation matrix Pr, and is determined
- * by partial pivoting. perm_r[i] = j means row i of A is in
- * position j in Pr*A.
- * If A->Stype = SLU_NR, permutation vector of size A->ncol, which
- * determines permutation of rows of transpose(A)
- * (columns of A) as described above.
- *
- * If options->RowPerm = MY_PERMR or
- * options->Fact = SamePattern_SameRowPerm, perm_r is an
- * input argument.
- * otherwise it is an output argument.
- *
- * L (output) SuperMatrix*
- * The factor L from the factorization
- * Pr*A*Pc=L*U (if A->Stype = SLU_NC) or
- * Pr*transpose(A)*Pc=L*U (if A->Stype = SLU_NR).
- * Uses compressed row subscripts storage for supernodes, i.e.,
- * L has types: Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU.
- *
- * U (output) SuperMatrix*
- * The factor U from the factorization
- * Pr*A*Pc=L*U (if A->Stype = SLU_NC) or
- * Pr*transpose(A)*Pc=L*U (if A->Stype = SLU_NR).
- * Uses column-wise storage scheme, i.e., U has types:
- * Stype = SLU_NC, Dtype = SLU_S, Mtype = SLU_TRU.
- *
- * B (input/output) SuperMatrix*
- * B has types: Stype = SLU_DN, Dtype = SLU_S, Mtype = SLU_GE.
- * On entry, the right hand side matrix.
- * On exit, the solution matrix if info = 0;
- *
- * stat (output) SuperLUStat_t*
- * Record the statistics on runtime and doubleing-point operation count.
- * See util.h for the definition of 'SuperLUStat_t'.
- *
- * info (output) int*
- * = 0: successful exit
- * > 0: if info = i, and i is
- * <= A->ncol: U(i,i) is exactly zero. The factorization has
- * been completed, but the factor U is exactly singular,
- * so the solution could not be computed.
- * > A->ncol: number of bytes allocated when memory allocation
- * failure occurred, plus A->ncol.
- *
- */
- DNformat *Bstore;
- SuperMatrix *AA = NULL;/* A in SLU_NC format used by the factorization routine.*/
- SuperMatrix AC; /* Matrix postmultiplied by Pc */
- int lwork = 0, *etree, i;
-
- /* Set default values for some parameters */
- int panel_size; /* panel size */
- int relax; /* no of columns in a relaxed snodes */
- int permc_spec;
- trans_t trans = NOTRANS;
- double *utime;
- double t; /* Temporary time */
-
- /* Test the input parameters ... */
- *info = 0;
- Bstore = B->Store;
- if ( options->Fact != DOFACT ) *info = -1;
- else if ( A->nrow != A->ncol || A->nrow < 0 ||
- (A->Stype != SLU_NC && A->Stype != SLU_NR) ||
- A->Dtype != SLU_S || A->Mtype != SLU_GE )
- *info = -2;
- else if ( B->ncol < 0 || Bstore->lda < SUPERLU_MAX(0, A->nrow) ||
- B->Stype != SLU_DN || B->Dtype != SLU_S || B->Mtype != SLU_GE )
- *info = -7;
- if ( *info != 0 ) {
- i = -(*info);
- xerbla_("sgssv", &i);
- return;
- }
-
- utime = stat->utime;
-
- /* Convert A to SLU_NC format when necessary. */
- if ( A->Stype == SLU_NR ) {
- NRformat *Astore = A->Store;
- AA = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) );
- sCreate_CompCol_Matrix(AA, A->ncol, A->nrow, Astore->nnz,
- Astore->nzval, Astore->colind, Astore->rowptr,
- SLU_NC, A->Dtype, A->Mtype);
- trans = TRANS;
- } else {
- if ( A->Stype == SLU_NC ) AA = A;
- }
-
- t = SuperLU_timer_();
- /*
- * Get column permutation vector perm_c[], according to permc_spec:
- * permc_spec = NATURAL: natural ordering
- * permc_spec = MMD_AT_PLUS_A: minimum degree on structure of A'+A
- * permc_spec = MMD_ATA: minimum degree on structure of A'*A
- * permc_spec = COLAMD: approximate minimum degree column ordering
- * permc_spec = MY_PERMC: the ordering already supplied in perm_c[]
- */
- permc_spec = options->ColPerm;
- if ( permc_spec != MY_PERMC && options->Fact == DOFACT )
- get_perm_c(permc_spec, AA, perm_c);
- utime[COLPERM] = SuperLU_timer_() - t;
-
- etree = intMalloc(A->ncol);
-
- t = SuperLU_timer_();
- sp_preorder(options, AA, perm_c, etree, &AC);
- utime[ETREE] = SuperLU_timer_() - t;
-
- panel_size = sp_ienv(1);
- relax = sp_ienv(2);
-
- /*printf("Factor PA = LU ... relax %d\tw %d\tmaxsuper %d\trowblk %d\n",
- relax, panel_size, sp_ienv(3), sp_ienv(4));*/
- t = SuperLU_timer_();
- /* Compute the LU factorization of A. */
- sgstrf(options, &AC, relax, panel_size,
- etree, NULL, lwork, perm_c, perm_r, L, U, stat, info);
- utime[FACT] = SuperLU_timer_() - t;
-
- t = SuperLU_timer_();
- if ( *info == 0 ) {
- /* Solve the system A*X=B, overwriting B with X. */
- sgstrs (trans, L, U, perm_c, perm_r, B, stat, info);
- }
- utime[SOLVE] = SuperLU_timer_() - t;
-
- SUPERLU_FREE (etree);
- Destroy_CompCol_Permuted(&AC);
- if ( A->Stype == SLU_NR ) {
- Destroy_SuperMatrix_Store(AA);
- SUPERLU_FREE(AA);
- }
-
-}
diff --git a/intern/opennl/superlu/sgstrf.c b/intern/opennl/superlu/sgstrf.c
deleted file mode 100644
index 78b1ba21865..00000000000
--- a/intern/opennl/superlu/sgstrf.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/** \file opennl/superlu/sgstrf.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-
-void
-sgstrf (superlu_options_t *options, SuperMatrix *A,
- int relax, int panel_size, int *etree, void *work, int lwork,
- int *perm_c, int *perm_r, SuperMatrix *L, SuperMatrix *U,
- SuperLUStat_t *stat, int *info)
-{
-/*
- * Purpose
- * =======
- *
- * SGSTRF computes an LU factorization of a general sparse m-by-n
- * matrix A using partial pivoting with row interchanges.
- * The factorization has the form
- * Pr * A = L * U
- * where Pr is a row permutation matrix, L is lower triangular with unit
- * diagonal elements (lower trapezoidal if A->nrow > A->ncol), and U is upper
- * triangular (upper trapezoidal if A->nrow < A->ncol).
- *
- * See supermatrix.h for the definition of 'SuperMatrix' structure.
- *
- * Arguments
- * =========
- *
- * options (input) superlu_options_t*
- * The structure defines the input parameters to control
- * how the LU decomposition will be performed.
- *
- * A (input) SuperMatrix*
- * Original matrix A, permuted by columns, of dimension
- * (A->nrow, A->ncol). The type of A can be:
- * Stype = SLU_NCP; Dtype = SLU_S; Mtype = SLU_GE.
- *
- * drop_tol (input) double (NOT IMPLEMENTED)
- * Drop tolerance parameter. At step j of the Gaussian elimination,
- * if abs(A_ij)/(max_i abs(A_ij)) < drop_tol, drop entry A_ij.
- * 0 <= drop_tol <= 1. The default value of drop_tol is 0.
- *
- * relax (input) int
- * To control degree of relaxing supernodes. If the number
- * of nodes (columns) in a subtree of the elimination tree is less
- * than relax, this subtree is considered as one supernode,
- * regardless of the row structures of those columns.
- *
- * panel_size (input) int
- * A panel consists of at most panel_size consecutive columns.
- *
- * etree (input) int*, dimension (A->ncol)
- * Elimination tree of A'*A.
- * Note: etree is a vector of parent pointers for a forest whose
- * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol.
- * On input, the columns of A should be permuted so that the
- * etree is in a certain postorder.
- *
- * work (input/output) void*, size (lwork) (in bytes)
- * User-supplied work space and space for the output data structures.
- * Not referenced if lwork = 0;
- *
- * lwork (input) int
- * Specifies the size of work array in bytes.
- * = 0: allocate space internally by system malloc;
- * > 0: use user-supplied work array of length lwork in bytes,
- * returns error if space runs out.
- * = -1: the routine guesses the amount of space needed without
- * performing the factorization, and returns it in
- * *info; no other side effects.
- *
- * perm_c (input) int*, dimension (A->ncol)
- * Column permutation vector, which defines the
- * permutation matrix Pc; perm_c[i] = j means column i of A is
- * in position j in A*Pc.
- * When searching for diagonal, perm_c[*] is applied to the
- * row subscripts of A, so that diagonal threshold pivoting
- * can find the diagonal of A, rather than that of A*Pc.
- *
- * perm_r (input/output) int*, dimension (A->nrow)
- * Row permutation vector which defines the permutation matrix Pr,
- * perm_r[i] = j means row i of A is in position j in Pr*A.
- * If options->Fact = SamePattern_SameRowPerm, the pivoting routine
- * will try to use the input perm_r, unless a certain threshold
- * criterion is violated. In that case, perm_r is overwritten by
- * a new permutation determined by partial pivoting or diagonal
- * threshold pivoting.
- * Otherwise, perm_r is output argument;
- *
- * L (output) SuperMatrix*
- * The factor L from the factorization Pr*A=L*U; use compressed row
- * subscripts storage for supernodes, i.e., L has type:
- * Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU.
- *
- * U (output) SuperMatrix*
- * The factor U from the factorization Pr*A*Pc=L*U. Use column-wise
- * storage scheme, i.e., U has types: Stype = SLU_NC,
- * Dtype = SLU_S, Mtype = SLU_TRU.
- *
- * stat (output) SuperLUStat_t*
- * Record the statistics on runtime and doubleing-point operation count.
- * See util.h for the definition of 'SuperLUStat_t'.
- *
- * info (output) int*
- * = 0: successful exit
- * < 0: if info = -i, the i-th argument had an illegal value
- * > 0: if info = i, and i is
- * <= A->ncol: U(i,i) is exactly zero. The factorization has
- * been completed, but the factor U is exactly singular,
- * and division by zero will occur if it is used to solve a
- * system of equations.
- * > A->ncol: number of bytes allocated when memory allocation
- * failure occurred, plus A->ncol. If lwork = -1, it is
- * the estimated amount of space needed, plus A->ncol.
- *
- * ======================================================================
- *
- * Local Working Arrays:
- * ======================
- * m = number of rows in the matrix
- * n = number of columns in the matrix
- *
- * xprune[0:n-1]: xprune[*] points to locations in subscript
- * vector lsub[*]. For column i, xprune[i] denotes the point where
- * structural pruning begins. I.e. only xlsub[i],..,xprune[i]-1 need
- * to be traversed for symbolic factorization.
- *
- * marker[0:3*m-1]: marker[i] = j means that node i has been
- * reached when working on column j.
- * Storage: relative to original row subscripts
- * NOTE: There are 3 of them: marker/marker1 are used for panel dfs,
- * see spanel_dfs.c; marker2 is used for inner-factorization,
- * see scolumn_dfs.c.
- *
- * parent[0:m-1]: parent vector used during dfs
- * Storage: relative to new row subscripts
- *
- * xplore[0:m-1]: xplore[i] gives the location of the next (dfs)
- * unexplored neighbor of i in lsub[*]
- *
- * segrep[0:nseg-1]: contains the list of supernodal representatives
- * in topological order of the dfs. A supernode representative is the
- * last column of a supernode.
- * The maximum size of segrep[] is n.
- *
- * repfnz[0:W*m-1]: for a nonzero segment U[*,j] that ends at a
- * supernodal representative r, repfnz[r] is the location of the first
- * nonzero in this segment. It is also used during the dfs: repfnz[r]>0
- * indicates the supernode r has been explored.
- * NOTE: There are W of them, each used for one column of a panel.
- *
- * panel_lsub[0:W*m-1]: temporary for the nonzeros row indices below
- * the panel diagonal. These are filled in during spanel_dfs(), and are
- * used later in the inner LU factorization within the panel.
- * panel_lsub[]/dense[] pair forms the SPA data structure.
- * NOTE: There are W of them.
- *
- * dense[0:W*m-1]: sparse accumulating (SPA) vector for intermediate values;
- * NOTE: there are W of them.
- *
- * tempv[0:*]: real temporary used for dense numeric kernels;
- * The size of this array is defined by NUM_TEMPV() in ssp_defs.h.
- *
- */
- /* Local working arrays */
- NCPformat *Astore;
- int *iperm_r = NULL; /* inverse of perm_r;
- used when options->Fact == SamePattern_SameRowPerm */
- int *iperm_c; /* inverse of perm_c */
- int *iwork;
- double *swork;
- int *segrep, *repfnz, *parent, *xplore;
- int *panel_lsub; /* dense[]/panel_lsub[] pair forms a w-wide SPA */
- int *xprune;
- int *marker;
- double *dense, *tempv;
- int *relax_end;
- double *a;
- int *asub;
- int *xa_begin, *xa_end;
- int *xsup, *supno;
- int *xlsub, *xlusup, *xusub;
- int nzlumax;
- static GlobalLU_t Glu; /* persistent to facilitate multiple factors. */
-
- /* Local scalars */
- fact_t fact = options->Fact;
- double diag_pivot_thresh = options->DiagPivotThresh;
- int pivrow; /* pivotal row number in the original matrix A */
- int nseg1; /* no of segments in U-column above panel row jcol */
- int nseg; /* no of segments in each U-column */
- register int jcol;
- register int kcol; /* end column of a relaxed snode */
- register int icol;
- register int i, k, jj, new_next, iinfo;
- int m, n, min_mn, jsupno, fsupc, nextlu, nextu;
- int w_def; /* upper bound on panel width */
- int usepr, iperm_r_allocated = 0;
- int nnzL, nnzU;
- int *panel_histo = stat->panel_histo;
- flops_t *ops = stat->ops;
-
- iinfo = 0;
- m = A->nrow;
- n = A->ncol;
- min_mn = SUPERLU_MIN(m, n);
- Astore = A->Store;
- a = Astore->nzval;
- asub = Astore->rowind;
- xa_begin = Astore->colbeg;
- xa_end = Astore->colend;
-
- /* Allocate storage common to the factor routines */
- *info = sLUMemInit(fact, work, lwork, m, n, Astore->nnz,
- panel_size, L, U, &Glu, &iwork, &swork);
- if ( *info ) return;
-
- xsup = Glu.xsup;
- supno = Glu.supno;
- xlsub = Glu.xlsub;
- xlusup = Glu.xlusup;
- xusub = Glu.xusub;
-
- SetIWork(m, n, panel_size, iwork, &segrep, &parent, &xplore,
- &repfnz, &panel_lsub, &xprune, &marker);
- sSetRWork(m, panel_size, swork, &dense, &tempv);
-
- usepr = (fact == SamePattern_SameRowPerm);
- if ( usepr ) {
- /* Compute the inverse of perm_r */
- iperm_r = (int *) intMalloc(m);
- for (k = 0; k < m; ++k) iperm_r[perm_r[k]] = k;
- iperm_r_allocated = 1;
- }
- iperm_c = (int *) intMalloc(n);
- for (k = 0; k < n; ++k) iperm_c[perm_c[k]] = k;
-
- /* Identify relaxed snodes */
- relax_end = (int *) intMalloc(n);
- if ( options->SymmetricMode == YES ) {
- heap_relax_snode(n, etree, relax, marker, relax_end);
- } else {
- relax_snode(n, etree, relax, marker, relax_end);
- }
-
- ifill (perm_r, m, EMPTY);
- ifill (marker, m * NO_MARKER, EMPTY);
- supno[0] = -1;
- xsup[0] = xlsub[0] = xusub[0] = xlusup[0] = 0;
- w_def = panel_size;
-
- /*
- * Work on one "panel" at a time. A panel is one of the following:
- * (a) a relaxed supernode at the bottom of the etree, or
- * (b) panel_size contiguous columns, defined by the user
- */
- for (jcol = 0; jcol < min_mn; ) {
-
- if ( relax_end[jcol] != EMPTY ) { /* start of a relaxed snode */
- kcol = relax_end[jcol]; /* end of the relaxed snode */
- panel_histo[kcol-jcol+1]++;
-
- /* --------------------------------------
- * Factorize the relaxed supernode(jcol:kcol)
- * -------------------------------------- */
- /* Determine the union of the row structure of the snode */
- if ( (*info = ssnode_dfs(jcol, kcol, asub, xa_begin, xa_end,
- xprune, marker, &Glu)) != 0 ) {
- if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
- SUPERLU_FREE (iperm_c);
- SUPERLU_FREE (relax_end);
- return;
- }
-
- nextu = xusub[jcol];
- nextlu = xlusup[jcol];
- jsupno = supno[jcol];
- fsupc = xsup[jsupno];
- new_next = nextlu + (xlsub[fsupc+1]-xlsub[fsupc])*(kcol-jcol+1);
- nzlumax = Glu.nzlumax;
- while ( new_next > nzlumax ) {
- if ( (*info = sLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, &Glu)) ) {
- if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
- SUPERLU_FREE (iperm_c);
- SUPERLU_FREE (relax_end);
- return;
- }
- }
-
- for (icol = jcol; icol<= kcol; icol++) {
- xusub[icol+1] = nextu;
-
- /* Scatter into SPA dense[*] */
- for (k = xa_begin[icol]; k < xa_end[icol]; k++)
- dense[asub[k]] = a[k];
-
- /* Numeric update within the snode */
- ssnode_bmod(icol, fsupc, dense, tempv, &Glu, stat);
-
- if ( (*info = spivotL(icol, diag_pivot_thresh, &usepr, perm_r,
- iperm_r, iperm_c, &pivrow, &Glu, stat)) )
- if ( iinfo == 0 ) iinfo = *info;
-
-#ifdef DEBUG
- sprint_lu_col("[1]: ", icol, pivrow, xprune, &Glu);
-#endif
-
- }
-
- jcol = icol;
-
- } else { /* Work on one panel of panel_size columns */
-
- /* Adjust panel_size so that a panel won't overlap with the next
- * relaxed snode.
- */
- panel_size = w_def;
- for (k = jcol + 1; k < SUPERLU_MIN(jcol+panel_size, min_mn); k++)
- if ( relax_end[k] != EMPTY ) {
- panel_size = k - jcol;
- break;
- }
- if ( k == min_mn ) panel_size = min_mn - jcol;
- panel_histo[panel_size]++;
-
- /* symbolic factor on a panel of columns */
- spanel_dfs(m, panel_size, jcol, A, perm_r, &nseg1,
- dense, panel_lsub, segrep, repfnz, xprune,
- marker, parent, xplore, &Glu);
-
- /* numeric sup-panel updates in topological order */
- spanel_bmod(m, panel_size, jcol, nseg1, dense,
- tempv, segrep, repfnz, &Glu, stat);
-
- /* Sparse LU within the panel, and below panel diagonal */
- for ( jj = jcol; jj < jcol + panel_size; jj++) {
- k = (jj - jcol) * m; /* column index for w-wide arrays */
-
- nseg = nseg1; /* Begin after all the panel segments */
-
- if ((*info = scolumn_dfs(m, jj, perm_r, &nseg, &panel_lsub[k],
- segrep, &repfnz[k], xprune, marker,
- parent, xplore, &Glu)) != 0) {
- if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
- SUPERLU_FREE (iperm_c);
- SUPERLU_FREE (relax_end);
- return;
- }
-
- /* Numeric updates */
- if ((*info = scolumn_bmod(jj, (nseg - nseg1), &dense[k],
- tempv, &segrep[nseg1], &repfnz[k],
- jcol, &Glu, stat)) != 0) {
- if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
- SUPERLU_FREE (iperm_c);
- SUPERLU_FREE (relax_end);
- return;
- }
-
- /* Copy the U-segments to ucol[*] */
- if ((*info = scopy_to_ucol(jj, nseg, segrep, &repfnz[k],
- perm_r, &dense[k], &Glu)) != 0) {
- if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
- SUPERLU_FREE (iperm_c);
- SUPERLU_FREE (relax_end);
- return;
- }
-
- if ( (*info = spivotL(jj, diag_pivot_thresh, &usepr, perm_r,
- iperm_r, iperm_c, &pivrow, &Glu, stat)) )
- if ( iinfo == 0 ) iinfo = *info;
-
- /* Prune columns (0:jj-1) using column jj */
- spruneL(jj, perm_r, pivrow, nseg, segrep,
- &repfnz[k], xprune, &Glu);
-
- /* Reset repfnz[] for this column */
- resetrep_col (nseg, segrep, &repfnz[k]);
-
-#ifdef DEBUG
- sprint_lu_col("[2]: ", jj, pivrow, xprune, &Glu);
-#endif
-
- }
-
- jcol += panel_size; /* Move to the next panel */
-
- } /* else */
-
- } /* for */
-
- *info = iinfo;
-
- if ( m > n ) {
- k = 0;
- for (i = 0; i < m; ++i)
- if ( perm_r[i] == EMPTY ) {
- perm_r[i] = n + k;
- ++k;
- }
- }
-
- countnz(min_mn, xprune, &nnzL, &nnzU, &Glu);
- fixupL(min_mn, perm_r, &Glu);
-
- sLUWorkFree(iwork, swork, &Glu); /* Free work space and compress storage */
-
- if ( fact == SamePattern_SameRowPerm ) {
- /* L and U structures may have changed due to possibly different
- pivoting, even though the storage is available.
- There could also be memory expansions, so the array locations
- may have changed, */
- ((SCformat *)L->Store)->nnz = nnzL;
- ((SCformat *)L->Store)->nsuper = Glu.supno[n];
- ((SCformat *)L->Store)->nzval = Glu.lusup;
- ((SCformat *)L->Store)->nzval_colptr = Glu.xlusup;
- ((SCformat *)L->Store)->rowind = Glu.lsub;
- ((SCformat *)L->Store)->rowind_colptr = Glu.xlsub;
- ((NCformat *)U->Store)->nnz = nnzU;
- ((NCformat *)U->Store)->nzval = Glu.ucol;
- ((NCformat *)U->Store)->rowind = Glu.usub;
- ((NCformat *)U->Store)->colptr = Glu.xusub;
- } else {
- sCreate_SuperNode_Matrix(L, A->nrow, A->ncol, nnzL, Glu.lusup,
- Glu.xlusup, Glu.lsub, Glu.xlsub, Glu.supno,
- Glu.xsup, SLU_SC, SLU_S, SLU_TRLU);
- sCreate_CompCol_Matrix(U, min_mn, min_mn, nnzU, Glu.ucol,
- Glu.usub, Glu.xusub, SLU_NC, SLU_S, SLU_TRU);
- }
-
- ops[FACT] += ops[TRSV] + ops[GEMV];
-
- if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r);
- SUPERLU_FREE (iperm_c);
- SUPERLU_FREE (relax_end);
-}
diff --git a/intern/opennl/superlu/sgstrs.c b/intern/opennl/superlu/sgstrs.c
deleted file mode 100644
index 5387e319d99..00000000000
--- a/intern/opennl/superlu/sgstrs.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/** \file opennl/superlu/sgstrs.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-
-
-/*
- * Function prototypes
- */
-void susolve(int, int, double*, double*);
-void slsolve(int, int, double*, double*);
-void smatvec(int, int, int, double*, double*, double*);
-void sprint_soln(int , double *);
-
-void
-sgstrs (trans_t trans, SuperMatrix *L, SuperMatrix *U,
- int *perm_c, int *perm_r, SuperMatrix *B,
- SuperLUStat_t *stat, int *info)
-{
-/*
- * Purpose
- * =======
- *
- * SGSTRS solves a system of linear equations A*X=B or A'*X=B
- * with A sparse and B dense, using the LU factorization computed by
- * SGSTRF.
- *
- * See supermatrix.h for the definition of 'SuperMatrix' structure.
- *
- * Arguments
- * =========
- *
- * trans (input) trans_t
- * Specifies the form of the system of equations:
- * = NOTRANS: A * X = B (No transpose)
- * = TRANS: A'* X = B (Transpose)
- * = CONJ: A**H * X = B (Conjugate transpose)
- *
- * L (input) SuperMatrix*
- * The factor L from the factorization Pr*A*Pc=L*U as computed by
- * sgstrf(). Use compressed row subscripts storage for supernodes,
- * i.e., L has types: Stype = SLU_SC, Dtype = SLU_S, Mtype = SLU_TRLU.
- *
- * U (input) SuperMatrix*
- * The factor U from the factorization Pr*A*Pc=L*U as computed by
- * sgstrf(). Use column-wise storage scheme, i.e., U has types:
- * Stype = SLU_NC, Dtype = SLU_S, Mtype = SLU_TRU.
- *
- * perm_c (input) int*, dimension (L->ncol)
- * Column permutation vector, which defines the
- * permutation matrix Pc; perm_c[i] = j means column i of A is
- * in position j in A*Pc.
- *
- * perm_r (input) int*, dimension (L->nrow)
- * Row permutation vector, which defines the permutation matrix Pr;
- * perm_r[i] = j means row i of A is in position j in Pr*A.
- *
- * B (input/output) SuperMatrix*
- * B has types: Stype = SLU_DN, Dtype = SLU_S, Mtype = SLU_GE.
- * On entry, the right hand side matrix.
- * On exit, the solution matrix if info = 0;
- *
- * stat (output) SuperLUStat_t*
- * Record the statistics on runtime and doubleing-point operation count.
- * See util.h for the definition of 'SuperLUStat_t'.
- *
- * info (output) int*
- * = 0: successful exit
- * < 0: if info = -i, the i-th argument had an illegal value
- *
- */
-#ifdef _CRAY
- _fcd ftcs1, ftcs2, ftcs3, ftcs4;
-#endif
-#ifdef USE_VENDOR_BLAS
- double alpha = 1.0, beta = 1.0;
- double *work_col;
-#endif
- DNformat *Bstore;
- double *Bmat;
- SCformat *Lstore;
- NCformat *Ustore;
- double *Lval, *Uval;
- int fsupc, nrow, nsupr, nsupc, luptr, istart, irow;
- int i, j, k, iptr, jcol, n, ldb, nrhs;
- double *work, *rhs_work, *soln;
- flops_t solve_ops;
- void sprint_soln();
-
- /* Test input parameters ... */
- *info = 0;
- Bstore = B->Store;
- ldb = Bstore->lda;
- nrhs = B->ncol;
- if ( trans != NOTRANS && trans != TRANS && trans != CONJ ) *info = -1;
- else if ( L->nrow != L->ncol || L->nrow < 0 ||
- L->Stype != SLU_SC || L->Dtype != SLU_S || L->Mtype != SLU_TRLU )
- *info = -2;
- else if ( U->nrow != U->ncol || U->nrow < 0 ||
- U->Stype != SLU_NC || U->Dtype != SLU_S || U->Mtype != SLU_TRU )
- *info = -3;
- else if ( ldb < SUPERLU_MAX(0, L->nrow) ||
- B->Stype != SLU_DN || B->Dtype != SLU_S || B->Mtype != SLU_GE )
- *info = -6;
- if ( *info ) {
- i = -(*info);
- xerbla_("sgstrs", &i);
- return;
- }
-
- n = L->nrow;
- work = doubleCalloc(n * nrhs);
- if ( !work ) ABORT("Malloc fails for local work[].");
- soln = doubleMalloc(n);
- if ( !soln ) ABORT("Malloc fails for local soln[].");
-
- Bmat = Bstore->nzval;
- Lstore = L->Store;
- Lval = Lstore->nzval;
- Ustore = U->Store;
- Uval = Ustore->nzval;
- solve_ops = 0;
-
- if ( trans == NOTRANS ) {
- /* Permute right hand sides to form Pr*B */
- for (i = 0; i < nrhs; i++) {
- rhs_work = &Bmat[i*ldb];
- for (k = 0; k < n; k++) soln[perm_r[k]] = rhs_work[k];
- for (k = 0; k < n; k++) rhs_work[k] = soln[k];
- }
-
- /* Forward solve PLy=Pb. */
- for (k = 0; k <= Lstore->nsuper; k++) {
- fsupc = L_FST_SUPC(k);
- istart = L_SUB_START(fsupc);
- nsupr = L_SUB_START(fsupc+1) - istart;
- nsupc = L_FST_SUPC(k+1) - fsupc;
- nrow = nsupr - nsupc;
-
- solve_ops += nsupc * (nsupc - 1) * nrhs;
- solve_ops += 2 * nrow * nsupc * nrhs;
-
- if ( nsupc == 1 ) {
- for (j = 0; j < nrhs; j++) {
- rhs_work = &Bmat[j*ldb];
- luptr = L_NZ_START(fsupc);
- for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); iptr++){
- irow = L_SUB(iptr);
- ++luptr;
- rhs_work[irow] -= rhs_work[fsupc] * Lval[luptr];
- }
- }
- } else {
- luptr = L_NZ_START(fsupc);
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- ftcs1 = _cptofcd("L", strlen("L"));
- ftcs2 = _cptofcd("N", strlen("N"));
- ftcs3 = _cptofcd("U", strlen("U"));
- STRSM( ftcs1, ftcs1, ftcs2, ftcs3, &nsupc, &nrhs, &alpha,
- &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb);
-
- SGEMM( ftcs2, ftcs2, &nrow, &nrhs, &nsupc, &alpha,
- &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb,
- &beta, &work[0], &n );
-#else
- strsm_("L", "L", "N", "U", &nsupc, &nrhs, &alpha,
- &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb);
-
- sgemm_( "N", "N", &nrow, &nrhs, &nsupc, &alpha,
- &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb,
- &beta, &work[0], &n );
-#endif
- for (j = 0; j < nrhs; j++) {
- rhs_work = &Bmat[j*ldb];
- work_col = &work[j*n];
- iptr = istart + nsupc;
- for (i = 0; i < nrow; i++) {
- irow = L_SUB(iptr);
- rhs_work[irow] -= work_col[i]; /* Scatter */
- work_col[i] = 0.0;
- iptr++;
- }
- }
-#else
- for (j = 0; j < nrhs; j++) {
- rhs_work = &Bmat[j*ldb];
- slsolve (nsupr, nsupc, &Lval[luptr], &rhs_work[fsupc]);
- smatvec (nsupr, nrow, nsupc, &Lval[luptr+nsupc],
- &rhs_work[fsupc], &work[0] );
-
- iptr = istart + nsupc;
- for (i = 0; i < nrow; i++) {
- irow = L_SUB(iptr);
- rhs_work[irow] -= work[i];
- work[i] = 0.0;
- iptr++;
- }
- }
-#endif
- } /* else ... */
- } /* for L-solve */
-
-#ifdef DEBUG
- printf("After L-solve: y=\n");
- sprint_soln(n, Bmat);
-#endif
-
- /*
- * Back solve Ux=y.
- */
- for (k = Lstore->nsuper; k >= 0; k--) {
- fsupc = L_FST_SUPC(k);
- istart = L_SUB_START(fsupc);
- nsupr = L_SUB_START(fsupc+1) - istart;
- nsupc = L_FST_SUPC(k+1) - fsupc;
- luptr = L_NZ_START(fsupc);
-
- solve_ops += nsupc * (nsupc + 1) * nrhs;
-
- if ( nsupc == 1 ) {
- rhs_work = &Bmat[0];
- for (j = 0; j < nrhs; j++) {
- rhs_work[fsupc] /= Lval[luptr];
- rhs_work += ldb;
- }
- } else {
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- ftcs1 = _cptofcd("L", strlen("L"));
- ftcs2 = _cptofcd("U", strlen("U"));
- ftcs3 = _cptofcd("N", strlen("N"));
- STRSM( ftcs1, ftcs2, ftcs3, ftcs3, &nsupc, &nrhs, &alpha,
- &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb);
-#else
- strsm_("L", "U", "N", "N", &nsupc, &nrhs, &alpha,
- &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb);
-#endif
-#else
- for (j = 0; j < nrhs; j++)
- susolve ( nsupr, nsupc, &Lval[luptr], &Bmat[fsupc+j*ldb] );
-#endif
- }
-
- for (j = 0; j < nrhs; ++j) {
- rhs_work = &Bmat[j*ldb];
- for (jcol = fsupc; jcol < fsupc + nsupc; jcol++) {
- solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol));
- for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++ ){
- irow = U_SUB(i);
- rhs_work[irow] -= rhs_work[jcol] * Uval[i];
- }
- }
- }
-
- } /* for U-solve */
-
-#ifdef DEBUG
- printf("After U-solve: x=\n");
- sprint_soln(n, Bmat);
-#endif
-
- /* Compute the final solution X := Pc*X. */
- for (i = 0; i < nrhs; i++) {
- rhs_work = &Bmat[i*ldb];
- for (k = 0; k < n; k++) soln[k] = rhs_work[perm_c[k]];
- for (k = 0; k < n; k++) rhs_work[k] = soln[k];
- }
-
- stat->ops[SOLVE] = solve_ops;
-
- } else { /* Solve A'*X=B or CONJ(A)*X=B */
- /* Permute right hand sides to form Pc'*B. */
- for (i = 0; i < nrhs; i++) {
- rhs_work = &Bmat[i*ldb];
- for (k = 0; k < n; k++) soln[perm_c[k]] = rhs_work[k];
- for (k = 0; k < n; k++) rhs_work[k] = soln[k];
- }
-
- stat->ops[SOLVE] = 0;
- for (k = 0; k < nrhs; ++k) {
-
- /* Multiply by inv(U'). */
- sp_strsv("U", "T", "N", L, U, &Bmat[k*ldb], stat, info);
-
- /* Multiply by inv(L'). */
- sp_strsv("L", "T", "U", L, U, &Bmat[k*ldb], stat, info);
-
- }
- /* Compute the final solution X := Pr'*X (=inv(Pr)*X) */
- for (i = 0; i < nrhs; i++) {
- rhs_work = &Bmat[i*ldb];
- for (k = 0; k < n; k++) soln[k] = rhs_work[perm_r[k]];
- for (k = 0; k < n; k++) rhs_work[k] = soln[k];
- }
-
- }
-
- SUPERLU_FREE(work);
- SUPERLU_FREE(soln);
-}
-
-/*
- * Diagnostic print of the solution vector
- */
-void
-sprint_soln(int n, double *soln)
-{
- int i;
-
- for (i = 0; i < n; i++)
- printf("\t%d: %.4f\n", i, soln[i]);
-}
diff --git a/intern/opennl/superlu/smemory.c b/intern/opennl/superlu/smemory.c
deleted file mode 100644
index c3b28a90e62..00000000000
--- a/intern/opennl/superlu/smemory.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/** \file smemory.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-#include "ssp_defs.h"
-
-
-/* blender only: needed for int_ptr, no other BLI used here */
-#include "../../../source/blender/blenlib/BLI_sys_types.h"
-
-/* Constants */
-#define NO_MEMTYPE 4 /* 0: lusup;
- 1: ucol;
- 2: lsub;
- 3: usub */
-#define GluIntArray(n) (5 * (n) + 5)
-
-/* Internal prototypes */
-void *sexpand (int *, MemType,int, int, GlobalLU_t *);
-int sLUWorkInit (int, int, int, int **, double **, LU_space_t);
-void copy_mem_double (int, void *, void *);
-void sStackCompress (GlobalLU_t *);
-void sSetupSpace (void *, int, LU_space_t *);
-void *suser_malloc (int, int);
-void suser_free (int, int);
-
-/* External prototypes (in memory.c - prec-indep) */
-extern void copy_mem_int (int, void *, void *);
-extern void user_bcopy (char *, char *, int);
-
-/* Headers for 4 types of dynamatically managed memory */
-typedef struct e_node {
- int size; /* length of the memory that has been used */
- void *mem; /* pointer to the new malloc'd store */
-} ExpHeader;
-
-typedef struct {
- int size;
- int used;
- int top1; /* grow upward, relative to &array[0] */
- int top2; /* grow downward */
- void *array;
-} LU_stack_t;
-
-/* Variables local to this file */
-static ExpHeader *expanders = 0; /* Array of pointers to 4 types of memory */
-static LU_stack_t stack;
-static int no_expand;
-
-/* Macros to manipulate stack */
-#define StackFull(x) ( x + stack.used >= stack.size )
-#define NotDoubleAlign(addr) ( (intptr_t)addr & 7 )
-#define DoubleAlign(addr) ( ((intptr_t)addr + 7) & ~7L )
-#define TempSpace(m, w) ( (2*w + 4 + NO_MARKER) * m * sizeof(int) + \
- (w + 1) * m * sizeof(double) )
-#define Reduce(alpha) ((alpha + 1) / 2) /* i.e. (alpha-1)/2 + 1 */
-
-
-
-
-/*
- * Setup the memory model to be used for factorization.
- * lwork = 0: use system malloc;
- * lwork > 0: use user-supplied work[] space.
- */
-void sSetupSpace(void *work, int lwork, LU_space_t *MemModel)
-{
- if ( lwork == 0 ) {
- *MemModel = SYSTEM; /* malloc/free */
- } else if ( lwork > 0 ) {
- *MemModel = USER; /* user provided space */
- stack.used = 0;
- stack.top1 = 0;
- stack.top2 = (lwork/4)*4; /* must be word addressable */
- stack.size = stack.top2;
- stack.array = (void *) work;
- }
-}
-
-
-
-void *suser_malloc(int bytes, int which_end)
-{
- void *buf;
-
- if ( StackFull(bytes) ) return (NULL);
-
- if ( which_end == HEAD ) {
- buf = (char*) stack.array + stack.top1;
- stack.top1 += bytes;
- } else {
- stack.top2 -= bytes;
- buf = (char*) stack.array + stack.top2;
- }
-
- stack.used += bytes;
- return buf;
-}
-
-
-void suser_free(int bytes, int which_end)
-{
- if ( which_end == HEAD ) {
- stack.top1 -= bytes;
- } else {
- stack.top2 += bytes;
- }
- stack.used -= bytes;
-}
-
-
-
-/*
- * mem_usage consists of the following fields:
- * - for_lu (double)
- * The amount of space used in bytes for the L\U data structures.
- * - total_needed (double)
- * The amount of space needed in bytes to perform factorization.
- * - expansions (int)
- * Number of memory expansions during the LU factorization.
- */
-int sQuerySpace(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage)
-{
- SCformat *Lstore;
- NCformat *Ustore;
- register int n, iword, dword, panel_size = sp_ienv(1);
-
- Lstore = L->Store;
- Ustore = U->Store;
- n = L->ncol;
- iword = sizeof(int);
- dword = sizeof(double);
-
- /* For LU factors */
- mem_usage->for_lu = (double)( (4*n + 3) * iword + Lstore->nzval_colptr[n] *
- dword + Lstore->rowind_colptr[n] * iword );
- mem_usage->for_lu += (double)( (n + 1) * iword +
- Ustore->colptr[n] * (dword + iword) );
-
- /* Working storage to support factorization */
- mem_usage->total_needed = mem_usage->for_lu +
- (double)( (2 * panel_size + 4 + NO_MARKER) * n * iword +
- (panel_size + 1) * n * dword );
-
- mem_usage->expansions = --no_expand;
-
- return 0;
-} /* sQuerySpace */
-
-/*
- * Allocate storage for the data structures common to all factor routines.
- * For those unpredictable size, make a guess as FILL * nnz(A).
- * Return value:
- * If lwork = -1, return the estimated amount of space required, plus n;
- * otherwise, return the amount of space actually allocated when
- * memory allocation failure occurred.
- */
-int
-sLUMemInit(fact_t fact, void *work, int lwork, int m, int n, int annz,
- int panel_size, SuperMatrix *L, SuperMatrix *U, GlobalLU_t *Glu,
- int **iwork, double **dwork)
-{
- int info, iword, dword;
- SCformat *Lstore;
- NCformat *Ustore;
- int *xsup, *supno;
- int *lsub, *xlsub;
- double *lusup;
- int *xlusup;
- double *ucol;
- int *usub, *xusub;
- int nzlmax, nzumax, nzlumax;
- int FILL = sp_ienv(6);
-
- Glu->n = n;
- no_expand = 0;
- iword = sizeof(int);
- dword = sizeof(double);
-
- if ( !expanders )
- expanders = (ExpHeader*)SUPERLU_MALLOC(NO_MEMTYPE * sizeof(ExpHeader));
- if ( !expanders ) ABORT("SUPERLU_MALLOC fails for expanders");
-
- if ( fact != SamePattern_SameRowPerm ) {
- /* Guess for L\U factors */
- nzumax = nzlumax = FILL * annz;
- nzlmax = SUPERLU_MAX(1, FILL/4.) * annz;
-
- if ( lwork == -1 ) {
- return ( GluIntArray(n) * iword + TempSpace(m, panel_size)
- + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n );
- } else {
- sSetupSpace(work, lwork, &Glu->MemModel);
- }
-
-#ifdef DEBUG
- printf("sLUMemInit() called: annz %d, MemModel %d\n",
- annz, Glu->MemModel);
-#endif
-
- /* Integer pointers for L\U factors */
- if ( Glu->MemModel == SYSTEM ) {
- xsup = intMalloc(n+1);
- supno = intMalloc(n+1);
- xlsub = intMalloc(n+1);
- xlusup = intMalloc(n+1);
- xusub = intMalloc(n+1);
- } else {
- xsup = (int *)suser_malloc((n+1) * iword, HEAD);
- supno = (int *)suser_malloc((n+1) * iword, HEAD);
- xlsub = (int *)suser_malloc((n+1) * iword, HEAD);
- xlusup = (int *)suser_malloc((n+1) * iword, HEAD);
- xusub = (int *)suser_malloc((n+1) * iword, HEAD);
- }
-
- lusup = (double *) sexpand( &nzlumax, LUSUP, 0, 0, Glu );
- ucol = (double *) sexpand( &nzumax, UCOL, 0, 0, Glu );
- lsub = (int *) sexpand( &nzlmax, LSUB, 0, 0, Glu );
- usub = (int *) sexpand( &nzumax, USUB, 0, 1, Glu );
-
- while ( !lusup || !ucol || !lsub || !usub ) {
- if ( Glu->MemModel == SYSTEM ) {
- SUPERLU_FREE(lusup);
- SUPERLU_FREE(ucol);
- SUPERLU_FREE(lsub);
- SUPERLU_FREE(usub);
- } else {
- suser_free((nzlumax+nzumax)*dword+(nzlmax+nzumax)*iword, HEAD);
- }
- nzlumax /= 2;
- nzumax /= 2;
- nzlmax /= 2;
- if ( nzlumax < annz ) {
- printf("Not enough memory to perform factorization.\n");
- return (smemory_usage(nzlmax, nzumax, nzlumax, n) + n);
- }
- lusup = (double *) sexpand( &nzlumax, LUSUP, 0, 0, Glu );
- ucol = (double *) sexpand( &nzumax, UCOL, 0, 0, Glu );
- lsub = (int *) sexpand( &nzlmax, LSUB, 0, 0, Glu );
- usub = (int *) sexpand( &nzumax, USUB, 0, 1, Glu );
- }
-
- } else {
- /* fact == SamePattern_SameRowPerm */
- Lstore = L->Store;
- Ustore = U->Store;
- xsup = Lstore->sup_to_col;
- supno = Lstore->col_to_sup;
- xlsub = Lstore->rowind_colptr;
- xlusup = Lstore->nzval_colptr;
- xusub = Ustore->colptr;
- nzlmax = Glu->nzlmax; /* max from previous factorization */
- nzumax = Glu->nzumax;
- nzlumax = Glu->nzlumax;
-
- if ( lwork == -1 ) {
- return ( GluIntArray(n) * iword + TempSpace(m, panel_size)
- + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n );
- } else if ( lwork == 0 ) {
- Glu->MemModel = SYSTEM;
- } else {
- Glu->MemModel = USER;
- stack.top2 = (lwork/4)*4; /* must be word-addressable */
- stack.size = stack.top2;
- }
-
- lsub = expanders[LSUB].mem = Lstore->rowind;
- lusup = expanders[LUSUP].mem = Lstore->nzval;
- usub = expanders[USUB].mem = Ustore->rowind;
- ucol = expanders[UCOL].mem = Ustore->nzval;;
- expanders[LSUB].size = nzlmax;
- expanders[LUSUP].size = nzlumax;
- expanders[USUB].size = nzumax;
- expanders[UCOL].size = nzumax;
- }
-
- Glu->xsup = xsup;
- Glu->supno = supno;
- Glu->lsub = lsub;
- Glu->xlsub = xlsub;
- Glu->lusup = lusup;
- Glu->xlusup = xlusup;
- Glu->ucol = ucol;
- Glu->usub = usub;
- Glu->xusub = xusub;
- Glu->nzlmax = nzlmax;
- Glu->nzumax = nzumax;
- Glu->nzlumax = nzlumax;
-
- info = sLUWorkInit(m, n, panel_size, iwork, dwork, Glu->MemModel);
- if ( info )
- return ( info + smemory_usage(nzlmax, nzumax, nzlumax, n) + n);
-
- ++no_expand;
- return 0;
-
-} /* sLUMemInit */
-
-/* Allocate known working storage. Returns 0 if success, otherwise
- returns the number of bytes allocated so far when failure occurred. */
-int
-sLUWorkInit(int m, int n, int panel_size, int **iworkptr,
- double **dworkptr, LU_space_t MemModel)
-{
- int isize, dsize, extra;
- double *old_ptr;
- int maxsuper = sp_ienv(3),
- rowblk = sp_ienv(4);
-
- isize = ( (2 * panel_size + 3 + NO_MARKER ) * m + n ) * sizeof(int);
- dsize = (m * panel_size +
- NUM_TEMPV(m,panel_size,maxsuper,rowblk)) * sizeof(double);
-
- if ( MemModel == SYSTEM )
- *iworkptr = (int *) intCalloc(isize/sizeof(int));
- else
- *iworkptr = (int *) suser_malloc(isize, TAIL);
- if ( ! *iworkptr ) {
- fprintf(stderr, "sLUWorkInit: malloc fails for local iworkptr[]\n");
- return (isize + n);
- }
-
- if ( MemModel == SYSTEM )
- *dworkptr = (double *) SUPERLU_MALLOC(dsize);
- else {
- *dworkptr = (double *) suser_malloc(dsize, TAIL);
- if ( NotDoubleAlign(*dworkptr) ) {
- old_ptr = *dworkptr;
- *dworkptr = (double*) DoubleAlign(*dworkptr);
- *dworkptr = (double*) ((double*)*dworkptr - 1);
- extra = (char*)old_ptr - (char*)*dworkptr;
-#ifdef DEBUG
- printf("sLUWorkInit: not aligned, extra %d\n", extra);
-#endif
- stack.top2 -= extra;
- stack.used += extra;
- }
- }
- if ( ! *dworkptr ) {
- fprintf(stderr, "malloc fails for local dworkptr[].");
- return (isize + dsize + n);
- }
-
- return 0;
-}
-
-
-/*
- * Set up pointers for real working arrays.
- */
-void
-sSetRWork(int m, int panel_size, double *dworkptr,
- double **dense, double **tempv)
-{
- double zero = 0.0;
-
- int maxsuper = sp_ienv(3),
- rowblk = sp_ienv(4);
- *dense = dworkptr;
- *tempv = *dense + panel_size*m;
- sfill (*dense, m * panel_size, zero);
- sfill (*tempv, NUM_TEMPV(m,panel_size,maxsuper,rowblk), zero);
-}
-
-/*
- * Free the working storage used by factor routines.
- */
-void sLUWorkFree(int *iwork, double *dwork, GlobalLU_t *Glu)
-{
- if ( Glu->MemModel == SYSTEM ) {
- SUPERLU_FREE (iwork);
- SUPERLU_FREE (dwork);
- } else {
- stack.used -= (stack.size - stack.top2);
- stack.top2 = stack.size;
-/* sStackCompress(Glu); */
- }
-
- SUPERLU_FREE (expanders);
- expanders = 0;
-}
-
-/* Expand the data structures for L and U during the factorization.
- * Return value: 0 - successful return
- * > 0 - number of bytes allocated when run out of space
- */
-int
-sLUMemXpand(int jcol,
- int next, /* number of elements currently in the factors */
- MemType mem_type, /* which type of memory to expand */
- int *maxlen, /* modified - maximum length of a data structure */
- GlobalLU_t *Glu /* modified - global LU data structures */
- )
-{
- void *new_mem;
-
-#ifdef DEBUG
- printf("sLUMemXpand(): jcol %d, next %d, maxlen %d, MemType %d\n",
- jcol, next, *maxlen, mem_type);
-#endif
-
- if (mem_type == USUB)
- new_mem = sexpand(maxlen, mem_type, next, 1, Glu);
- else
- new_mem = sexpand(maxlen, mem_type, next, 0, Glu);
-
- if ( !new_mem ) {
- int nzlmax = Glu->nzlmax;
- int nzumax = Glu->nzumax;
- int nzlumax = Glu->nzlumax;
- fprintf(stderr, "Can't expand MemType %d: jcol %d\n", mem_type, jcol);
- return (smemory_usage(nzlmax, nzumax, nzlumax, Glu->n) + Glu->n);
- }
-
- switch ( mem_type ) {
- case LUSUP:
- Glu->lusup = (double *) new_mem;
- Glu->nzlumax = *maxlen;
- break;
- case UCOL:
- Glu->ucol = (double *) new_mem;
- Glu->nzumax = *maxlen;
- break;
- case LSUB:
- Glu->lsub = (int *) new_mem;
- Glu->nzlmax = *maxlen;
- break;
- case USUB:
- Glu->usub = (int *) new_mem;
- Glu->nzumax = *maxlen;
- break;
- }
-
- return 0;
-
-}
-
-
-
-void
-copy_mem_double(int howmany, void *old, void *new)
-{
- register int i;
- double *dold = old;
- double *dnew = new;
- for (i = 0; i < howmany; i++) dnew[i] = dold[i];
-}
-
-/*
- * Expand the existing storage to accommodate more fill-ins.
- */
-void
-*sexpand (
- int *prev_len, /* length used from previous call */
- MemType type, /* which part of the memory to expand */
- int len_to_copy, /* size of the memory to be copied to new store */
- int keep_prev, /* = 1: use prev_len;
- = 0: compute new_len to expand */
- GlobalLU_t *Glu /* modified - global LU data structures */
- )
-{
- double EXPAND = 1.5;
- double alpha;
- void *new_mem, *old_mem;
- int new_len, tries, lword, extra, bytes_to_copy;
-
- alpha = EXPAND;
-
- if ( no_expand == 0 || keep_prev ) /* First time allocate requested */
- new_len = *prev_len;
- else {
- new_len = alpha * *prev_len;
- }
-
- if ( type == LSUB || type == USUB ) lword = sizeof(int);
- else lword = sizeof(double);
-
- if ( Glu->MemModel == SYSTEM ) {
- new_mem = (void *) SUPERLU_MALLOC((size_t)new_len * (size_t)lword);
-/* new_mem = (void *) calloc(new_len, lword); */
- if ( no_expand != 0 ) {
- tries = 0;
- if ( keep_prev ) {
- if ( !new_mem ) return (NULL);
- } else {
- while ( !new_mem ) {
- if ( ++tries > 10 ) return (NULL);
- alpha = Reduce(alpha);
- new_len = alpha * *prev_len;
- new_mem = (void *) SUPERLU_MALLOC((size_t)new_len * (size_t)lword);
-/* new_mem = (void *) calloc(new_len, lword); */
- }
- }
- if ( type == LSUB || type == USUB ) {
- copy_mem_int(len_to_copy, expanders[type].mem, new_mem);
- } else {
- copy_mem_double(len_to_copy, expanders[type].mem, new_mem);
- }
- SUPERLU_FREE (expanders[type].mem);
- }
- expanders[type].mem = (void *) new_mem;
-
- } else { /* MemModel == USER */
- if ( no_expand == 0 ) {
- new_mem = suser_malloc((size_t)new_len * (size_t)lword, HEAD);
- if ( NotDoubleAlign(new_mem) &&
- (type == LUSUP || type == UCOL) ) {
- old_mem = new_mem;
- new_mem = (void *)DoubleAlign(new_mem);
- extra = (char*)new_mem - (char*)old_mem;
-#ifdef DEBUG
- printf("expand(): not aligned, extra %d\n", extra);
-#endif
- stack.top1 += extra;
- stack.used += extra;
- }
- expanders[type].mem = (void *) new_mem;
- }
- else {
- tries = 0;
- extra = (new_len - *prev_len) * lword;
- if ( keep_prev ) {
- if ( StackFull(extra) ) return (NULL);
- } else {
- while ( StackFull(extra) ) {
- if ( ++tries > 10 ) return (NULL);
- alpha = Reduce(alpha);
- new_len = alpha * *prev_len;
- extra = (new_len - *prev_len) * lword;
- }
- }
-
- if ( type != USUB ) {
- new_mem = (void*)((char*)expanders[type + 1].mem + extra);
- bytes_to_copy = (char*)stack.array + stack.top1
- - (char*)expanders[type + 1].mem;
- user_bcopy(expanders[type+1].mem, new_mem, bytes_to_copy);
-
- if ( type < USUB ) {
- Glu->usub = expanders[USUB].mem =
- (void*)((char*)expanders[USUB].mem + extra);
- }
- if ( type < LSUB ) {
- Glu->lsub = expanders[LSUB].mem =
- (void*)((char*)expanders[LSUB].mem + extra);
- }
- if ( type < UCOL ) {
- Glu->ucol = expanders[UCOL].mem =
- (void*)((char*)expanders[UCOL].mem + extra);
- }
- stack.top1 += extra;
- stack.used += extra;
- if ( type == UCOL ) {
- stack.top1 += extra; /* Add same amount for USUB */
- stack.used += extra;
- }
-
- } /* if ... */
-
- } /* else ... */
- }
-
- expanders[type].size = new_len;
- *prev_len = new_len;
- if ( no_expand ) ++no_expand;
-
- return (void *) expanders[type].mem;
-
-} /* sexpand */
-
-
-/*
- * Compress the work[] array to remove fragmentation.
- */
-void
-sStackCompress(GlobalLU_t *Glu)
-{
- register int iword, dword, ndim;
- char *last, *fragment;
- int *ifrom, *ito;
- double *dfrom, *dto;
- int *xlsub, *lsub, *xusub, *usub, *xlusup;
- double *ucol, *lusup;
-
- iword = sizeof(int);
- dword = sizeof(double);
- ndim = Glu->n;
-
- xlsub = Glu->xlsub;
- lsub = Glu->lsub;
- xusub = Glu->xusub;
- usub = Glu->usub;
- xlusup = Glu->xlusup;
- ucol = Glu->ucol;
- lusup = Glu->lusup;
-
- dfrom = ucol;
- dto = (double *)((char*)lusup + xlusup[ndim] * dword);
- copy_mem_double(xusub[ndim], dfrom, dto);
- ucol = dto;
-
- ifrom = lsub;
- ito = (int *) ((char*)ucol + xusub[ndim] * iword);
- copy_mem_int(xlsub[ndim], ifrom, ito);
- lsub = ito;
-
- ifrom = usub;
- ito = (int *) ((char*)lsub + xlsub[ndim] * iword);
- copy_mem_int(xusub[ndim], ifrom, ito);
- usub = ito;
-
- last = (char*)usub + xusub[ndim] * iword;
- fragment = (char*) (((char*)stack.array + stack.top1) - last);
- stack.used -= (intptr_t) fragment;
- stack.top1 -= (intptr_t) fragment;
-
- Glu->ucol = ucol;
- Glu->lsub = lsub;
- Glu->usub = usub;
-
-#ifdef DEBUG
- printf("sStackCompress: fragment %d\n", (int)*fragment);
- /* for (last = 0; last < ndim; ++last)
- print_lu_col("After compress:", last, 0);*/
-#endif
-
-}
-
-/*
- * Allocate storage for original matrix A
- */
-void
-sallocateA(int n, int nnz, double **a, int **asub, int **xa)
-{
- *a = (double *) doubleMalloc(nnz);
- *asub = (int *) intMalloc(nnz);
- *xa = (int *) intMalloc(n+1);
-}
-
-
-double *doubleMalloc(int n)
-{
- double *buf;
- buf = (double *) SUPERLU_MALLOC(n * sizeof(double));
- if ( !buf ) {
- ABORT("SUPERLU_MALLOC failed for buf in doubleMalloc()\n");
- }
- return (buf);
-}
-
-double *doubleCalloc(int n)
-{
- double *buf;
- register int i;
- double zero = 0.0;
- buf = (double *) SUPERLU_MALLOC(n * sizeof(double));
- if ( !buf ) {
- ABORT("SUPERLU_MALLOC failed for buf in doubleCalloc()\n");
- }
- for (i = 0; i < n; ++i) buf[i] = zero;
- return (buf);
-}
-
-
-int smemory_usage(const int nzlmax, const int nzumax,
- const int nzlumax, const int n)
-{
- register int iword, dword;
-
- iword = sizeof(int);
- dword = sizeof(double);
-
- return (10 * n * iword +
- nzlmax * iword + nzumax * (iword + dword) + nzlumax * dword);
-
-}
diff --git a/intern/opennl/superlu/smyblas2.c b/intern/opennl/superlu/smyblas2.c
deleted file mode 100644
index 11e3b4b4761..00000000000
--- a/intern/opennl/superlu/smyblas2.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/** \file opennl/superlu/smyblas2.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- * File name: smyblas2.c
- * Purpose:
- * Level 2 BLAS operations: solves and matvec, written in C.
- * Note:
- * This is only used when the system lacks an efficient BLAS library.
- */
-
-/*
- * Solves a dense UNIT lower triangular system. The unit lower
- * triangular matrix is stored in a 2D array M(1:nrow,1:ncol).
- * The solution will be returned in the rhs vector.
- */
-
-/* local prototypes*/
-void slsolve ( int, int, double *, double *);
-void susolve ( int, int, double *, double *);
-void smatvec ( int, int, int, double *, double *, double *);
-
-
-void slsolve ( int ldm, int ncol, double *M, double *rhs )
-{
- int k;
- double x0, x1, x2, x3, x4, x5, x6, x7;
- double *M0;
- register double *Mki0, *Mki1, *Mki2, *Mki3, *Mki4, *Mki5, *Mki6, *Mki7;
- register int firstcol = 0;
-
- M0 = &M[0];
-
- while ( firstcol < ncol - 7 ) { /* Do 8 columns */
- Mki0 = M0 + 1;
- Mki1 = Mki0 + ldm + 1;
- Mki2 = Mki1 + ldm + 1;
- Mki3 = Mki2 + ldm + 1;
- Mki4 = Mki3 + ldm + 1;
- Mki5 = Mki4 + ldm + 1;
- Mki6 = Mki5 + ldm + 1;
- Mki7 = Mki6 + ldm + 1;
-
- x0 = rhs[firstcol];
- x1 = rhs[firstcol+1] - x0 * *Mki0++;
- x2 = rhs[firstcol+2] - x0 * *Mki0++ - x1 * *Mki1++;
- x3 = rhs[firstcol+3] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++;
- x4 = rhs[firstcol+4] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++
- - x3 * *Mki3++;
- x5 = rhs[firstcol+5] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++
- - x3 * *Mki3++ - x4 * *Mki4++;
- x6 = rhs[firstcol+6] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++
- - x3 * *Mki3++ - x4 * *Mki4++ - x5 * *Mki5++;
- x7 = rhs[firstcol+7] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++
- - x3 * *Mki3++ - x4 * *Mki4++ - x5 * *Mki5++
- - x6 * *Mki6++;
-
- rhs[++firstcol] = x1;
- rhs[++firstcol] = x2;
- rhs[++firstcol] = x3;
- rhs[++firstcol] = x4;
- rhs[++firstcol] = x5;
- rhs[++firstcol] = x6;
- rhs[++firstcol] = x7;
- ++firstcol;
-
- for (k = firstcol; k < ncol; k++)
- rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++
- - x2 * *Mki2++ - x3 * *Mki3++
- - x4 * *Mki4++ - x5 * *Mki5++
- - x6 * *Mki6++ - x7 * *Mki7++;
-
- M0 += 8 * ldm + 8;
- }
-
- while ( firstcol < ncol - 3 ) { /* Do 4 columns */
- Mki0 = M0 + 1;
- Mki1 = Mki0 + ldm + 1;
- Mki2 = Mki1 + ldm + 1;
- Mki3 = Mki2 + ldm + 1;
-
- x0 = rhs[firstcol];
- x1 = rhs[firstcol+1] - x0 * *Mki0++;
- x2 = rhs[firstcol+2] - x0 * *Mki0++ - x1 * *Mki1++;
- x3 = rhs[firstcol+3] - x0 * *Mki0++ - x1 * *Mki1++ - x2 * *Mki2++;
-
- rhs[++firstcol] = x1;
- rhs[++firstcol] = x2;
- rhs[++firstcol] = x3;
- ++firstcol;
-
- for (k = firstcol; k < ncol; k++)
- rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++
- - x2 * *Mki2++ - x3 * *Mki3++;
-
- M0 += 4 * ldm + 4;
- }
-
- if ( firstcol < ncol - 1 ) { /* Do 2 columns */
- Mki0 = M0 + 1;
- Mki1 = Mki0 + ldm + 1;
-
- x0 = rhs[firstcol];
- x1 = rhs[firstcol+1] - x0 * *Mki0++;
-
- rhs[++firstcol] = x1;
- ++firstcol;
-
- for (k = firstcol; k < ncol; k++)
- rhs[k] = rhs[k] - x0 * *Mki0++ - x1 * *Mki1++;
-
- }
-
-}
-
-/*
- * Solves a dense upper triangular system. The upper triangular matrix is
- * stored in a 2-dim array M(1:ldm,1:ncol). The solution will be returned
- * in the rhs vector.
- */
-void
-susolve ( ldm, ncol, M, rhs )
-int ldm; /* in */
-int ncol; /* in */
-double *M; /* in */
-double *rhs; /* modified */
-{
- double xj;
- int jcol, j, irow;
-
- jcol = ncol - 1;
-
- for (j = 0; j < ncol; j++) {
-
- xj = rhs[jcol] / M[jcol + jcol*ldm]; /* M(jcol, jcol) */
- rhs[jcol] = xj;
-
- for (irow = 0; irow < jcol; irow++)
- rhs[irow] -= xj * M[irow + jcol*ldm]; /* M(irow, jcol) */
-
- jcol--;
-
- }
-}
-
-
-/*
- * Performs a dense matrix-vector multiply: Mxvec = Mxvec + M * vec.
- * The input matrix is M(1:nrow,1:ncol); The product is returned in Mxvec[].
- */
-void smatvec ( ldm, nrow, ncol, M, vec, Mxvec )
-
-int ldm; /* in -- leading dimension of M */
-int nrow; /* in */
-int ncol; /* in */
-double *M; /* in */
-double *vec; /* in */
-double *Mxvec; /* in/out */
-
-{
- double vi0, vi1, vi2, vi3, vi4, vi5, vi6, vi7;
- double *M0;
- register double *Mki0, *Mki1, *Mki2, *Mki3, *Mki4, *Mki5, *Mki6, *Mki7;
- register int firstcol = 0;
- int k;
-
- M0 = &M[0];
- while ( firstcol < ncol - 7 ) { /* Do 8 columns */
-
- Mki0 = M0;
- Mki1 = Mki0 + ldm;
- Mki2 = Mki1 + ldm;
- Mki3 = Mki2 + ldm;
- Mki4 = Mki3 + ldm;
- Mki5 = Mki4 + ldm;
- Mki6 = Mki5 + ldm;
- Mki7 = Mki6 + ldm;
-
- vi0 = vec[firstcol++];
- vi1 = vec[firstcol++];
- vi2 = vec[firstcol++];
- vi3 = vec[firstcol++];
- vi4 = vec[firstcol++];
- vi5 = vec[firstcol++];
- vi6 = vec[firstcol++];
- vi7 = vec[firstcol++];
-
- for (k = 0; k < nrow; k++)
- Mxvec[k] += vi0 * *Mki0++ + vi1 * *Mki1++
- + vi2 * *Mki2++ + vi3 * *Mki3++
- + vi4 * *Mki4++ + vi5 * *Mki5++
- + vi6 * *Mki6++ + vi7 * *Mki7++;
-
- M0 += 8 * ldm;
- }
-
- while ( firstcol < ncol - 3 ) { /* Do 4 columns */
-
- Mki0 = M0;
- Mki1 = Mki0 + ldm;
- Mki2 = Mki1 + ldm;
- Mki3 = Mki2 + ldm;
-
- vi0 = vec[firstcol++];
- vi1 = vec[firstcol++];
- vi2 = vec[firstcol++];
- vi3 = vec[firstcol++];
- for (k = 0; k < nrow; k++)
- Mxvec[k] += vi0 * *Mki0++ + vi1 * *Mki1++
- + vi2 * *Mki2++ + vi3 * *Mki3++ ;
-
- M0 += 4 * ldm;
- }
-
- while ( firstcol < ncol ) { /* Do 1 column */
-
- Mki0 = M0;
- vi0 = vec[firstcol++];
- for (k = 0; k < nrow; k++)
- Mxvec[k] += vi0 * *Mki0++;
-
- M0 += ldm;
- }
-
-}
-
diff --git a/intern/opennl/superlu/sp_coletree.c b/intern/opennl/superlu/sp_coletree.c
deleted file mode 100644
index 7e7187ae8b0..00000000000
--- a/intern/opennl/superlu/sp_coletree.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/** \file opennl/superlu/sp_coletree.c
- * \ingroup opennl
- */
-
-/* Elimination tree computation and layout routines */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "ssp_defs.h"
-
-/*
- * Implementation of disjoint set union routines.
- * Elements are integers in 0..n-1, and the
- * names of the sets themselves are of type int.
- *
- * Calls are:
- * initialize_disjoint_sets (n) initial call.
- * s = make_set (i) returns a set containing only i.
- * s = link (t, u) returns s = t union u, destroying t and u.
- * s = find (i) return name of set containing i.
- * finalize_disjoint_sets final call.
- *
- * This implementation uses path compression but not weighted union.
- * See Tarjan's book for details.
- * John Gilbert, CMI, 1987.
- *
- * Implemented path-halving by XSL 07/05/95.
- */
-
-static int *pp; /* parent array for sets */
-
-static
-int *mxCallocInt(int n)
-{
- register int i;
- int *buf;
-
- buf = (int *) SUPERLU_MALLOC( n * sizeof(int) );
- if ( !buf ) {
- ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()");
- }
- for (i = 0; i < n; i++) buf[i] = 0;
- return (buf);
-}
-
-static
-void initialize_disjoint_sets (
- int n
- )
-{
- pp = mxCallocInt(n);
-}
-
-
-static
-int make_set (
- int i
- )
-{
- pp[i] = i;
- return i;
-}
-
-
-static
-int link (
- int s,
- int t
- )
-{
- pp[s] = t;
- return t;
-}
-
-
-/* PATH HALVING */
-static
-int find (int i)
-{
- register int p, gp;
-
- p = pp[i];
- gp = pp[p];
- while (gp != p) {
- pp[i] = gp;
- i = gp;
- p = pp[i];
- gp = pp[p];
- }
- return (p);
-}
-
-#if 0
-/* PATH COMPRESSION */
-static
-int find (
- int i
- )
-{
- if (pp[i] != i)
- pp[i] = find (pp[i]);
- return pp[i];
-}
-#endif
-
-static
-void finalize_disjoint_sets (
- void
- )
-{
- SUPERLU_FREE(pp);
-}
-
-
-/*
- * Find the elimination tree for A'*A.
- * This uses something similar to Liu's algorithm.
- * It runs in time O(nz(A)*log n) and does not form A'*A.
- *
- * Input:
- * Sparse matrix A. Numeric values are ignored, so any
- * explicit zeros are treated as nonzero.
- * Output:
- * Integer array of parents representing the elimination
- * tree of the symbolic product A'*A. Each vertex is a
- * column of A, and nc means a root of the elimination forest.
- *
- * John R. Gilbert, Xerox, 10 Dec 1990
- * Based on code by JRG dated 1987, 1988, and 1990.
- */
-
-/*
- * Nonsymmetric elimination tree
- */
-int
-sp_coletree(
- int *acolst, int *acolend, /* column start and end past 1 */
- int *arow, /* row indices of A */
- int nr, int nc, /* dimension of A */
- int *parent /* parent in elim tree */
- )
-{
- int *root; /* root of subtee of etree */
- int *firstcol; /* first nonzero col in each row*/
- int rset, cset;
- int row, col;
- int rroot;
- int p;
-
- root = mxCallocInt (nc);
- initialize_disjoint_sets (nc);
-
- /* Compute firstcol[row] = first nonzero column in row */
-
- firstcol = mxCallocInt (nr);
- for (row = 0; row < nr; firstcol[row++] = nc);
- for (col = 0; col < nc; col++)
- for (p = acolst[col]; p < acolend[col]; p++) {
- row = arow[p];
- firstcol[row] = SUPERLU_MIN(firstcol[row], col);
- }
-
- /* Compute etree by Liu's algorithm for symmetric matrices,
- except use (firstcol[r],c) in place of an edge (r,c) of A.
- Thus each row clique in A'*A is replaced by a star
- centered at its first vertex, which has the same fill. */
-
- for (col = 0; col < nc; col++) {
- cset = make_set (col);
- root[cset] = col;
- parent[col] = nc; /* Matlab */
- for (p = acolst[col]; p < acolend[col]; p++) {
- row = firstcol[arow[p]];
- if (row >= col) continue;
- rset = find (row);
- rroot = root[rset];
- if (rroot != col) {
- parent[rroot] = col;
- cset = link (cset, rset);
- root[cset] = col;
- }
- }
- }
-
- SUPERLU_FREE (root);
- SUPERLU_FREE (firstcol);
- finalize_disjoint_sets ();
- return 0;
-}
-
-/*
- * q = TreePostorder (n, p);
- *
- * Postorder a tree.
- * Input:
- * p is a vector of parent pointers for a forest whose
- * vertices are the integers 0 to n-1; p[root]==n.
- * Output:
- * q is a vector indexed by 0..n-1 such that q[i] is the
- * i-th vertex in a postorder numbering of the tree.
- *
- * ( 2/7/95 modified by X.Li:
- * q is a vector indexed by 0:n-1 such that vertex i is the
- * q[i]-th vertex in a postorder numbering of the tree.
- * That is, this is the inverse of the previous q. )
- *
- * In the child structure, lower-numbered children are represented
- * first, so that a tree which is already numbered in postorder
- * will not have its order changed.
- *
- * Written by John Gilbert, Xerox, 10 Dec 1990.
- * Based on code written by John Gilbert at CMI in 1987.
- */
-
-static int *first_kid, *next_kid; /* Linked list of children. */
-static int *post, postnum;
-
-static
-/*
- * Depth-first search from vertex v.
- */
-void etdfs (
- int v
- )
-{
- int w;
-
- for (w = first_kid[v]; w != -1; w = next_kid[w]) {
- etdfs (w);
- }
- /* post[postnum++] = v; in Matlab */
- post[v] = postnum++; /* Modified by X.Li on 2/14/95 */
-}
-
-
-/*
- * Post order a tree
- */
-int *TreePostorder(
- int n,
- int *parent
-)
-{
- int v, dad;
-
- /* Allocate storage for working arrays and results */
- first_kid = mxCallocInt (n+1);
- next_kid = mxCallocInt (n+1);
- post = mxCallocInt (n+1);
-
- /* Set up structure describing children */
- for (v = 0; v <= n; first_kid[v++] = -1);
- for (v = n-1; v >= 0; v--) {
- dad = parent[v];
- next_kid[v] = first_kid[dad];
- first_kid[dad] = v;
- }
-
- /* Depth-first search from dummy root vertex #n */
- postnum = 0;
- etdfs (n);
-
- SUPERLU_FREE (first_kid);
- SUPERLU_FREE (next_kid);
- return post;
-}
-
-
-/*
- * p = spsymetree (A);
- *
- * Find the elimination tree for symmetric matrix A.
- * This uses Liu's algorithm, and runs in time O(nz*log n).
- *
- * Input:
- * Square sparse matrix A. No check is made for symmetry;
- * elements below and on the diagonal are ignored.
- * Numeric values are ignored, so any explicit zeros are
- * treated as nonzero.
- * Output:
- * Integer array of parents representing the etree, with n
- * meaning a root of the elimination forest.
- * Note:
- * This routine uses only the upper triangle, while sparse
- * Cholesky (as in spchol.c) uses only the lower. Matlab's
- * dense Cholesky uses only the upper. This routine could
- * be modified to use the lower triangle either by transposing
- * the matrix or by traversing it by rows with auxiliary
- * pointer and link arrays.
- *
- * John R. Gilbert, Xerox, 10 Dec 1990
- * Based on code by JRG dated 1987, 1988, and 1990.
- * Modified by X.S. Li, November 1999.
- */
-
-/*
- * Symmetric elimination tree
- */
-int
-sp_symetree(
- int *acolst, int *acolend, /* column starts and ends past 1 */
- int *arow, /* row indices of A */
- int n, /* dimension of A */
- int *parent /* parent in elim tree */
- )
-{
- int *root; /* root of subtree of etree */
- int rset, cset;
- int row, col;
- int rroot;
- int p;
-
- root = mxCallocInt (n);
- initialize_disjoint_sets (n);
-
- for (col = 0; col < n; col++) {
- cset = make_set (col);
- root[cset] = col;
- parent[col] = n; /* Matlab */
- for (p = acolst[col]; p < acolend[col]; p++) {
- row = arow[p];
- if (row >= col) continue;
- rset = find (row);
- rroot = root[rset];
- if (rroot != col) {
- parent[rroot] = col;
- cset = link (cset, rset);
- root[cset] = col;
- }
- }
- }
- SUPERLU_FREE (root);
- finalize_disjoint_sets ();
- return 0;
-} /* SP_SYMETREE */
diff --git a/intern/opennl/superlu/sp_ienv.c b/intern/opennl/superlu/sp_ienv.c
deleted file mode 100644
index e0f9693ae71..00000000000
--- a/intern/opennl/superlu/sp_ienv.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/** \file opennl/superlu/sp_ienv.c
- * \ingroup opennl
- */
-/*
- * File name: sp_ienv.c
- * History: Modified from lapack routine ILAENV
- */
-
-#include "ssp_defs.h"
-#include "util.h"
-
-int
-sp_ienv(int ispec)
-{
-/*
- Purpose
- =======
-
- sp_ienv() is inquired to choose machine-dependent parameters for the
- local environment. See ISPEC for a description of the parameters.
-
- This version provides a set of parameters which should give good,
- but not optimal, performance on many of the currently available
- computers. Users are encouraged to modify this subroutine to set
- the tuning parameters for their particular machine using the option
- and problem size information in the arguments.
-
- Arguments
- =========
-
- ISPEC (input) int
- Specifies the parameter to be returned as the value of SP_IENV.
- = 1: the panel size w; a panel consists of w consecutive
- columns of matrix A in the process of Gaussian elimination.
- The best value depends on machine's cache characters.
- = 2: the relaxation parameter relax; if the number of
- nodes (columns) in a subtree of the elimination tree is less
- than relax, this subtree is considered as one supernode,
- regardless of their row structures.
- = 3: the maximum size for a supernode;
- = 4: the minimum row dimension for 2-D blocking to be used;
- = 5: the minimum column dimension for 2-D blocking to be used;
- = 6: the estimated fills factor for L and U, compared with A;
-
- (SP_IENV) (output) int
- >= 0: the value of the parameter specified by ISPEC
- < 0: if SP_IENV = -k, the k-th argument had an illegal value.
-
- =====================================================================
-*/
- int i;
-
- switch (ispec) {
- case 1: return (10);
- case 2: return (5);
- case 3: return (100);
- case 4: return (200);
- case 5: return (40);
- case 6: return (20);
- }
-
- /* Invalid value for ISPEC */
- i = 1;
- xerbla_("sp_ienv", &i);
- return 0;
-
-} /* sp_ienv_ */
-
diff --git a/intern/opennl/superlu/sp_preorder.c b/intern/opennl/superlu/sp_preorder.c
deleted file mode 100644
index 9504669726e..00000000000
--- a/intern/opennl/superlu/sp_preorder.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/** \file opennl/superlu/sp_preorder.c
- * \ingroup opennl
- */
-#include "ssp_defs.h"
-
-int check_perm(char *, int , int *);
-
-
-void
-sp_preorder(superlu_options_t *options, SuperMatrix *A, int *perm_c,
- int *etree, SuperMatrix *AC)
-{
-/*
- * Purpose
- * =======
- *
- * sp_preorder() permutes the columns of the original matrix. It performs
- * the following steps:
- *
- * 1. Apply column permutation perm_c[] to A's column pointers to form AC;
- *
- * 2. If options->Fact = DOFACT, then
- * (1) Compute column elimination tree etree[] of AC'AC;
- * (2) Post order etree[] to get a postordered elimination tree etree[],
- * and a postorder permutation post[];
- * (3) Apply post[] permutation to columns of AC;
- * (4) Overwrite perm_c[] with the product perm_c * post.
- *
- * Arguments
- * =========
- *
- * options (input) superlu_options_t*
- * Specifies whether or not the elimination tree will be re-used.
- * If options->Fact == DOFACT, this means first time factor A,
- * etree is computed, postered, and output.
- * Otherwise, re-factor A, etree is input, unchanged on exit.
- *
- * A (input) SuperMatrix*
- * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
- * of the linear equations is A->nrow. Currently, the type of A can be:
- * Stype = NC or SLU_NCP; Mtype = SLU_GE.
- * In the future, more general A may be handled.
- *
- * perm_c (input/output) int*
- * Column permutation vector of size A->ncol, which defines the
- * permutation matrix Pc; perm_c[i] = j means column i of A is
- * in position j in A*Pc.
- * If options->Fact == DOFACT, perm_c is both input and output.
- * On output, it is changed according to a postorder of etree.
- * Otherwise, perm_c is input.
- *
- * etree (input/output) int*
- * Elimination tree of Pc'*A'*A*Pc, dimension A->ncol.
- * If options->Fact == DOFACT, etree is an output argument,
- * otherwise it is an input argument.
- * Note: etree is a vector of parent pointers for a forest whose
- * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol.
- *
- * AC (output) SuperMatrix*
- * The resulting matrix after applied the column permutation
- * perm_c[] to matrix A. The type of AC can be:
- * Stype = SLU_NCP; Dtype = A->Dtype; Mtype = SLU_GE.
- *
- */
-
- NCformat *Astore;
- NCPformat *ACstore;
- int *iwork, *post;
- register int n, i;
-
- n = A->ncol;
-
- /* Apply column permutation perm_c to A's column pointers so to
- obtain NCP format in AC = A*Pc. */
- AC->Stype = SLU_NCP;
- AC->Dtype = A->Dtype;
- AC->Mtype = A->Mtype;
- AC->nrow = A->nrow;
- AC->ncol = A->ncol;
- Astore = A->Store;
- ACstore = AC->Store = (void *) SUPERLU_MALLOC( sizeof(NCPformat) );
- if ( !ACstore ) ABORT("SUPERLU_MALLOC fails for ACstore");
- ACstore->nnz = Astore->nnz;
- ACstore->nzval = Astore->nzval;
- ACstore->rowind = Astore->rowind;
- ACstore->colbeg = (int*) SUPERLU_MALLOC(n*sizeof(int));
- if ( !(ACstore->colbeg) ) ABORT("SUPERLU_MALLOC fails for ACstore->colbeg");
- ACstore->colend = (int*) SUPERLU_MALLOC(n*sizeof(int));
- if ( !(ACstore->colend) ) ABORT("SUPERLU_MALLOC fails for ACstore->colend");
-
-#ifdef DEBUG
- print_int_vec("pre_order:", n, perm_c);
- check_perm("Initial perm_c", n, perm_c);
-#endif
-
- for (i = 0; i < n; i++) {
- ACstore->colbeg[perm_c[i]] = Astore->colptr[i];
- ACstore->colend[perm_c[i]] = Astore->colptr[i+1];
- }
-
- if ( options->Fact == DOFACT ) {
-#undef ETREE_ATplusA
-#ifdef ETREE_ATplusA
- /*--------------------------------------------
- COMPUTE THE ETREE OF Pc*(A'+A)*Pc'.
- --------------------------------------------*/
- int *b_colptr, *b_rowind, bnz, j;
- int *c_colbeg, *c_colend;
-
- /*printf("Use etree(A'+A)\n");*/
-
- /* Form B = A + A'. */
- at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind,
- &bnz, &b_colptr, &b_rowind);
-
- /* Form C = Pc*B*Pc'. */
- c_colbeg = (int*) SUPERLU_MALLOC(2*n*sizeof(int));
- c_colend = c_colbeg + n;
- if (!c_colbeg ) ABORT("SUPERLU_MALLOC fails for c_colbeg/c_colend");
- for (i = 0; i < n; i++) {
- c_colbeg[perm_c[i]] = b_colptr[i];
- c_colend[perm_c[i]] = b_colptr[i+1];
- }
- for (j = 0; j < n; ++j) {
- for (i = c_colbeg[j]; i < c_colend[j]; ++i) {
- b_rowind[i] = perm_c[b_rowind[i]];
- }
- }
-
- /* Compute etree of C. */
- sp_symetree(c_colbeg, c_colend, b_rowind, n, etree);
-
- SUPERLU_FREE(b_colptr);
- if ( bnz ) SUPERLU_FREE(b_rowind);
- SUPERLU_FREE(c_colbeg);
-
-#else
- /*--------------------------------------------
- COMPUTE THE COLUMN ELIMINATION TREE.
- --------------------------------------------*/
- sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind,
- A->nrow, A->ncol, etree);
-#endif
-#ifdef DEBUG
- print_int_vec("etree:", n, etree);
-#endif
-
- /* In symmetric mode, do not do postorder here. */
- if ( options->SymmetricMode == NO ) {
- /* Post order etree */
- post = (int *) TreePostorder(n, etree);
- /* for (i = 0; i < n+1; ++i) inv_post[post[i]] = i;
- iwork = post; */
-
-#ifdef DEBUG
- print_int_vec("post:", n+1, post);
- check_perm("post", n, post);
-#endif
- iwork = (int*) SUPERLU_MALLOC((n+1)*sizeof(int));
- if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]");
-
- /* Renumber etree in postorder */
- for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]];
- for (i = 0; i < n; ++i) etree[i] = iwork[i];
-
-#ifdef DEBUG
- print_int_vec("postorder etree:", n, etree);
-#endif
-
- /* Postmultiply A*Pc by post[] */
- for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i];
- for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i];
- for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i];
- for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i];
-
- for (i = 0; i < n; ++i)
- iwork[i] = post[perm_c[i]]; /* product of perm_c and post */
- for (i = 0; i < n; ++i) perm_c[i] = iwork[i];
-
-#ifdef DEBUG
- print_int_vec("Pc*post:", n, perm_c);
- check_perm("final perm_c", n, perm_c);
-#endif
- SUPERLU_FREE (post);
- SUPERLU_FREE (iwork);
- } /* end postordering */
-
- } /* if options->Fact == DOFACT ... */
-
-}
-
-int check_perm(char *what, int n, int *perm)
-{
- register int i;
- int *marker;
- marker = (int *) calloc(n, sizeof(int));
-
- for (i = 0; i < n; ++i) {
- if ( marker[perm[i]] == 1 || perm[i] >= n ) {
- printf("%s: Not a valid PERM[%d] = %d\n", what, i, perm[i]);
- ABORT("check_perm");
- } else {
- marker[perm[i]] = 1;
- }
- }
-
- SUPERLU_FREE(marker);
- return 0;
-}
diff --git a/intern/opennl/superlu/spanel_bmod.c b/intern/opennl/superlu/spanel_bmod.c
deleted file mode 100644
index 5f150e640fd..00000000000
--- a/intern/opennl/superlu/spanel_bmod.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/** \file opennl/superlu/spanel_bmod.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "ssp_defs.h"
-
-/*
- * Function prototypes
- */
-void slsolve(int, int, double *, double *);
-void smatvec(int, int, int, double *, double *, double *);
-extern void scheck_tempv();
-
-void
-spanel_bmod (
- const int m, /* in - number of rows in the matrix */
- const int w, /* in */
- const int jcol, /* in */
- const int nseg, /* in */
- double *dense, /* out, of size n by w */
- double *tempv, /* working array */
- int *segrep, /* in */
- int *repfnz, /* in, of size n by w */
- GlobalLU_t *Glu, /* modified */
- SuperLUStat_t *stat /* output */
- )
-{
-/*
- * Purpose
- * =======
- *
- * Performs numeric block updates (sup-panel) in topological order.
- * It features: col-col, 2cols-col, 3cols-col, and sup-col updates.
- * Special processing on the supernodal portion of L\U[*,j]
- *
- * Before entering this routine, the original nonzeros in the panel
- * were already copied into the spa[m,w].
- *
- * Updated/Output parameters-
- * dense[0:m-1,w]: L[*,j:j+w-1] and U[*,j:j+w-1] are returned
- * collectively in the m-by-w vector dense[*].
- *
- */
-
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- _fcd ftcs1 = _cptofcd("L", strlen("L")),
- ftcs2 = _cptofcd("N", strlen("N")),
- ftcs3 = _cptofcd("U", strlen("U"));
-#endif
- int incx = 1, incy = 1;
- double alpha, beta;
-#endif
-
- register int k, ksub;
- int fsupc, nsupc, nsupr, nrow;
- int krep, krep_ind;
- double ukj, ukj1, ukj2;
- int luptr, luptr1, luptr2;
- int segsze;
- int block_nrow; /* no of rows in a block row */
- register int lptr; /* Points to the row subscripts of a supernode */
- int kfnz, irow, no_zeros;
- register int isub, isub1, i;
- register int jj; /* Index through each column in the panel */
- int *xsup, *supno;
- int *lsub, *xlsub;
- double *lusup;
- int *xlusup;
- int *repfnz_col; /* repfnz[] for a column in the panel */
- double *dense_col; /* dense[] for a column in the panel */
- double *tempv1; /* Used in 1-D update */
- double *TriTmp, *MatvecTmp; /* used in 2-D update */
- double zero = 0.0;
- register int ldaTmp;
- register int r_ind, r_hi;
- static int first = 1, maxsuper, rowblk, colblk;
- flops_t *ops = stat->ops;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- lusup = Glu->lusup;
- xlusup = Glu->xlusup;
-
- if ( first ) {
- maxsuper = sp_ienv(3);
- rowblk = sp_ienv(4);
- colblk = sp_ienv(5);
- first = 0;
- }
- ldaTmp = maxsuper + rowblk;
-
- /*
- * For each nonz supernode segment of U[*,j] in topological order
- */
- k = nseg - 1;
- for (ksub = 0; ksub < nseg; ksub++) { /* for each updating supernode */
-
- /* krep = representative of current k-th supernode
- * fsupc = first supernodal column
- * nsupc = no of columns in a supernode
- * nsupr = no of rows in a supernode
- */
- krep = segrep[k--];
- fsupc = xsup[supno[krep]];
- nsupc = krep - fsupc + 1;
- nsupr = xlsub[fsupc+1] - xlsub[fsupc];
- nrow = nsupr - nsupc;
- lptr = xlsub[fsupc];
- krep_ind = lptr + nsupc - 1;
-
- repfnz_col = repfnz;
- dense_col = dense;
-
- if ( nsupc >= colblk && nrow > rowblk ) { /* 2-D block update */
-
- TriTmp = tempv;
-
- /* Sequence through each column in panel -- triangular solves */
- for (jj = jcol; jj < jcol + w; jj++,
- repfnz_col += m, dense_col += m, TriTmp += ldaTmp ) {
-
- kfnz = repfnz_col[krep];
- if ( kfnz == EMPTY ) continue; /* Skip any zero segment */
-
- segsze = krep - kfnz + 1;
- luptr = xlusup[fsupc];
-
- ops[TRSV] += segsze * (segsze - 1);
- ops[GEMV] += 2 * nrow * segsze;
-
- /* Case 1: Update U-segment of size 1 -- col-col update */
- if ( segsze == 1 ) {
- ukj = dense_col[lsub[krep_ind]];
- luptr += nsupr*(nsupc-1) + nsupc;
-
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) {
- irow = lsub[i];
- dense_col[irow] -= ukj * lusup[luptr];
- ++luptr;
- }
-
- } else if ( segsze <= 3 ) {
- ukj = dense_col[lsub[krep_ind]];
- ukj1 = dense_col[lsub[krep_ind - 1]];
- luptr += nsupr*(nsupc-1) + nsupc-1;
- luptr1 = luptr - nsupr;
-
- if ( segsze == 2 ) {
- ukj -= ukj1 * lusup[luptr1];
- dense_col[lsub[krep_ind]] = ukj;
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- luptr++; luptr1++;
- dense_col[irow] -= (ukj*lusup[luptr]
- + ukj1*lusup[luptr1]);
- }
- } else {
- ukj2 = dense_col[lsub[krep_ind - 2]];
- luptr2 = luptr1 - nsupr;
- ukj1 -= ukj2 * lusup[luptr2-1];
- ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2];
- dense_col[lsub[krep_ind]] = ukj;
- dense_col[lsub[krep_ind-1]] = ukj1;
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- luptr++; luptr1++; luptr2++;
- dense_col[irow] -= ( ukj*lusup[luptr]
- + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] );
- }
- }
-
- } else { /* segsze >= 4 */
-
- /* Copy U[*,j] segment from dense[*] to TriTmp[*], which
- holds the result of triangular solves. */
- no_zeros = kfnz - fsupc;
- isub = lptr + no_zeros;
- for (i = 0; i < segsze; ++i) {
- irow = lsub[isub];
- TriTmp[i] = dense_col[irow]; /* Gather */
- ++isub;
- }
-
- /* start effective triangle */
- luptr += nsupr * no_zeros + no_zeros;
-
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr],
- &nsupr, TriTmp, &incx );
-#else
- strsv_( "L", "N", "U", &segsze, &lusup[luptr],
- &nsupr, TriTmp, &incx );
-#endif
-#else
- slsolve ( nsupr, segsze, &lusup[luptr], TriTmp );
-#endif
-
-
- } /* else ... */
-
- } /* for jj ... end tri-solves */
-
- /* Block row updates; push all the way into dense[*] block */
- for ( r_ind = 0; r_ind < nrow; r_ind += rowblk ) {
-
- r_hi = SUPERLU_MIN(nrow, r_ind + rowblk);
- block_nrow = SUPERLU_MIN(rowblk, r_hi - r_ind);
- luptr = xlusup[fsupc] + nsupc + r_ind;
- isub1 = lptr + nsupc + r_ind;
-
- repfnz_col = repfnz;
- TriTmp = tempv;
- dense_col = dense;
-
- /* Sequence through each column in panel -- matrix-vector */
- for (jj = jcol; jj < jcol + w; jj++,
- repfnz_col += m, dense_col += m, TriTmp += ldaTmp) {
-
- kfnz = repfnz_col[krep];
- if ( kfnz == EMPTY ) continue; /* Skip any zero segment */
-
- segsze = krep - kfnz + 1;
- if ( segsze <= 3 ) continue; /* skip unrolled cases */
-
- /* Perform a block update, and scatter the result of
- matrix-vector to dense[]. */
- no_zeros = kfnz - fsupc;
- luptr1 = luptr + nsupr * no_zeros;
- MatvecTmp = &TriTmp[maxsuper];
-
-#ifdef USE_VENDOR_BLAS
- alpha = one;
- beta = zero;
-#ifdef _CRAY
- SGEMV(ftcs2, &block_nrow, &segsze, &alpha, &lusup[luptr1],
- &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy);
-#else
- sgemv_("N", &block_nrow, &segsze, &alpha, &lusup[luptr1],
- &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy);
-#endif
-#else
- smatvec(nsupr, block_nrow, segsze, &lusup[luptr1],
- TriTmp, MatvecTmp);
-#endif
-
- /* Scatter MatvecTmp[*] into SPA dense[*] temporarily
- * such that MatvecTmp[*] can be re-used for the
- * the next blok row update. dense[] will be copied into
- * global store after the whole panel has been finished.
- */
- isub = isub1;
- for (i = 0; i < block_nrow; i++) {
- irow = lsub[isub];
- dense_col[irow] -= MatvecTmp[i];
- MatvecTmp[i] = zero;
- ++isub;
- }
-
- } /* for jj ... */
-
- } /* for each block row ... */
-
- /* Scatter the triangular solves into SPA dense[*] */
- repfnz_col = repfnz;
- TriTmp = tempv;
- dense_col = dense;
-
- for (jj = jcol; jj < jcol + w; jj++,
- repfnz_col += m, dense_col += m, TriTmp += ldaTmp) {
- kfnz = repfnz_col[krep];
- if ( kfnz == EMPTY ) continue; /* Skip any zero segment */
-
- segsze = krep - kfnz + 1;
- if ( segsze <= 3 ) continue; /* skip unrolled cases */
-
- no_zeros = kfnz - fsupc;
- isub = lptr + no_zeros;
- for (i = 0; i < segsze; i++) {
- irow = lsub[isub];
- dense_col[irow] = TriTmp[i];
- TriTmp[i] = zero;
- ++isub;
- }
-
- } /* for jj ... */
-
- } else { /* 1-D block modification */
-
-
- /* Sequence through each column in the panel */
- for (jj = jcol; jj < jcol + w; jj++,
- repfnz_col += m, dense_col += m) {
-
- kfnz = repfnz_col[krep];
- if ( kfnz == EMPTY ) continue; /* Skip any zero segment */
-
- segsze = krep - kfnz + 1;
- luptr = xlusup[fsupc];
-
- ops[TRSV] += segsze * (segsze - 1);
- ops[GEMV] += 2 * nrow * segsze;
-
- /* Case 1: Update U-segment of size 1 -- col-col update */
- if ( segsze == 1 ) {
- ukj = dense_col[lsub[krep_ind]];
- luptr += nsupr*(nsupc-1) + nsupc;
-
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) {
- irow = lsub[i];
- dense_col[irow] -= ukj * lusup[luptr];
- ++luptr;
- }
-
- } else if ( segsze <= 3 ) {
- ukj = dense_col[lsub[krep_ind]];
- luptr += nsupr*(nsupc-1) + nsupc-1;
- ukj1 = dense_col[lsub[krep_ind - 1]];
- luptr1 = luptr - nsupr;
-
- if ( segsze == 2 ) {
- ukj -= ukj1 * lusup[luptr1];
- dense_col[lsub[krep_ind]] = ukj;
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- ++luptr; ++luptr1;
- dense_col[irow] -= (ukj*lusup[luptr]
- + ukj1*lusup[luptr1]);
- }
- } else {
- ukj2 = dense_col[lsub[krep_ind - 2]];
- luptr2 = luptr1 - nsupr;
- ukj1 -= ukj2 * lusup[luptr2-1];
- ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2];
- dense_col[lsub[krep_ind]] = ukj;
- dense_col[lsub[krep_ind-1]] = ukj1;
- for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) {
- irow = lsub[i];
- ++luptr; ++luptr1; ++luptr2;
- dense_col[irow] -= ( ukj*lusup[luptr]
- + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] );
- }
- }
-
- } else { /* segsze >= 4 */
- /*
- * Perform a triangular solve and block update,
- * then scatter the result of sup-col update to dense[].
- */
- no_zeros = kfnz - fsupc;
-
- /* Copy U[*,j] segment from dense[*] to tempv[*]:
- * The result of triangular solve is in tempv[*];
- * The result of matrix vector update is in dense_col[*]
- */
- isub = lptr + no_zeros;
- for (i = 0; i < segsze; ++i) {
- irow = lsub[isub];
- tempv[i] = dense_col[irow]; /* Gather */
- ++isub;
- }
-
- /* start effective triangle */
- luptr += nsupr * no_zeros + no_zeros;
-
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr],
- &nsupr, tempv, &incx );
-#else
- strsv_( "L", "N", "U", &segsze, &lusup[luptr],
- &nsupr, tempv, &incx );
-#endif
-
- luptr += segsze; /* Dense matrix-vector */
- tempv1 = &tempv[segsze];
- alpha = one;
- beta = zero;
-#ifdef _CRAY
- SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr],
- &nsupr, tempv, &incx, &beta, tempv1, &incy );
-#else
- sgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr],
- &nsupr, tempv, &incx, &beta, tempv1, &incy );
-#endif
-#else
- slsolve ( nsupr, segsze, &lusup[luptr], tempv );
-
- luptr += segsze; /* Dense matrix-vector */
- tempv1 = &tempv[segsze];
- smatvec (nsupr, nrow, segsze, &lusup[luptr], tempv, tempv1);
-#endif
-
- /* Scatter tempv[*] into SPA dense[*] temporarily, such
- * that tempv[*] can be used for the triangular solve of
- * the next column of the panel. They will be copied into
- * ucol[*] after the whole panel has been finished.
- */
- isub = lptr + no_zeros;
- for (i = 0; i < segsze; i++) {
- irow = lsub[isub];
- dense_col[irow] = tempv[i];
- tempv[i] = zero;
- isub++;
- }
-
- /* Scatter the update from tempv1[*] into SPA dense[*] */
- /* Start dense rectangular L */
- for (i = 0; i < nrow; i++) {
- irow = lsub[isub];
- dense_col[irow] -= tempv1[i];
- tempv1[i] = zero;
- ++isub;
- }
-
- } /* else segsze>=4 ... */
-
- } /* for each column in the panel... */
-
- } /* else 1-D update ... */
-
- } /* for each updating supernode ... */
-
-}
-
-
-
diff --git a/intern/opennl/superlu/spanel_dfs.c b/intern/opennl/superlu/spanel_dfs.c
deleted file mode 100644
index 80e6814dde9..00000000000
--- a/intern/opennl/superlu/spanel_dfs.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/** \file opennl/superlu/spanel_dfs.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-#include "util.h"
-
-void
-spanel_dfs (
- const int m, /* in - number of rows in the matrix */
- const int w, /* in */
- const int jcol, /* in */
- SuperMatrix *A, /* in - original matrix */
- int *perm_r, /* in */
- int *nseg, /* out */
- double *dense, /* out */
- int *panel_lsub, /* out */
- int *segrep, /* out */
- int *repfnz, /* out */
- int *xprune, /* out */
- int *marker, /* out */
- int *parent, /* working array */
- int *xplore, /* working array */
- GlobalLU_t *Glu /* modified */
- )
-{
-/*
- * Purpose
- * =======
- *
- * Performs a symbolic factorization on a panel of columns [jcol, jcol+w).
- *
- * A supernode representative is the last column of a supernode.
- * The nonzeros in U[*,j] are segments that end at supernodal
- * representatives.
- *
- * The routine returns one list of the supernodal representatives
- * in topological order of the dfs that generates them. This list is
- * a superset of the topological order of each individual column within
- * the panel.
- * The location of the first nonzero in each supernodal segment
- * (supernodal entry location) is also returned. Each column has a
- * separate list for this purpose.
- *
- * Two marker arrays are used for dfs:
- * marker[i] == jj, if i was visited during dfs of current column jj;
- * marker1[i] >= jcol, if i was visited by earlier columns in this panel;
- *
- * marker: A-row --> A-row/col (0/1)
- * repfnz: SuperA-col --> PA-row
- * parent: SuperA-col --> SuperA-col
- * xplore: SuperA-col --> index to L-structure
- *
- */
- NCPformat *Astore;
- double *a;
- int *asub;
- int *xa_begin, *xa_end;
- int krep, chperm, chmark, chrep, oldrep, kchild, myfnz;
- int k, krow, kmark, kperm;
- int xdfs, maxdfs, kpar;
- int jj; /* index through each column in the panel */
- int *marker1; /* marker1[jj] >= jcol if vertex jj was visited
- by a previous column within this panel. */
- int *repfnz_col; /* start of each column in the panel */
- double *dense_col; /* start of each column in the panel */
- int nextl_col; /* next available position in panel_lsub[*,jj] */
- int *xsup, *supno;
- int *lsub, *xlsub;
-
- /* Initialize pointers */
- Astore = A->Store;
- a = Astore->nzval;
- asub = Astore->rowind;
- xa_begin = Astore->colbeg;
- xa_end = Astore->colend;
- marker1 = marker + m;
- repfnz_col = repfnz;
- dense_col = dense;
- *nseg = 0;
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
-
- /* For each column in the panel */
- for (jj = jcol; jj < jcol + w; jj++) {
- nextl_col = (jj - jcol) * m;
-
-#ifdef CHK_DFS
- printf("\npanel col %d: ", jj);
-#endif
-
- /* For each nonz in A[*,jj] do dfs */
- for (k = xa_begin[jj]; k < xa_end[jj]; k++) {
- krow = asub[k];
- dense_col[krow] = a[k];
- kmark = marker[krow];
- if ( kmark == jj )
- continue; /* krow visited before, go to the next nonzero */
-
- /* For each unmarked nbr krow of jj
- * krow is in L: place it in structure of L[*,jj]
- */
- marker[krow] = jj;
- kperm = perm_r[krow];
-
- if ( kperm == EMPTY ) {
- panel_lsub[nextl_col++] = krow; /* krow is indexed into A */
- }
- /*
- * krow is in U: if its supernode-rep krep
- * has been explored, update repfnz[*]
- */
- else {
-
- krep = xsup[supno[kperm]+1] - 1;
- myfnz = repfnz_col[krep];
-
-#ifdef CHK_DFS
- printf("krep %d, myfnz %d, perm_r[%d] %d\n", krep, myfnz, krow, kperm);
-#endif
- if ( myfnz != EMPTY ) { /* Representative visited before */
- if ( myfnz > kperm ) repfnz_col[krep] = kperm;
- /* continue; */
- }
- else {
- /* Otherwise, perform dfs starting at krep */
- oldrep = EMPTY;
- parent[krep] = oldrep;
- repfnz_col[krep] = kperm;
- xdfs = xlsub[krep];
- maxdfs = xprune[krep];
-
-#ifdef CHK_DFS
- printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs);
- for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]);
- printf("\n");
-#endif
- do {
- /*
- * For each unmarked kchild of krep
- */
- while ( xdfs < maxdfs ) {
-
- kchild = lsub[xdfs];
- xdfs++;
- chmark = marker[kchild];
-
- if ( chmark != jj ) { /* Not reached yet */
- marker[kchild] = jj;
- chperm = perm_r[kchild];
-
- /* Case kchild is in L: place it in L[*,j] */
- if ( chperm == EMPTY ) {
- panel_lsub[nextl_col++] = kchild;
- }
- /* Case kchild is in U:
- * chrep = its supernode-rep. If its rep has
- * been explored, update its repfnz[*]
- */
- else {
-
- chrep = xsup[supno[chperm]+1] - 1;
- myfnz = repfnz_col[chrep];
-#ifdef CHK_DFS
- printf("chrep %d,myfnz %d,perm_r[%d] %d\n",chrep,myfnz,kchild,chperm);
-#endif
- if ( myfnz != EMPTY ) { /* Visited before */
- if ( myfnz > chperm )
- repfnz_col[chrep] = chperm;
- }
- else {
- /* Cont. dfs at snode-rep of kchild */
- xplore[krep] = xdfs;
- oldrep = krep;
- krep = chrep; /* Go deeper down G(L) */
- parent[krep] = oldrep;
- repfnz_col[krep] = chperm;
- xdfs = xlsub[krep];
- maxdfs = xprune[krep];
-#ifdef CHK_DFS
- printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs);
- for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]);
- printf("\n");
-#endif
- } /* else */
-
- } /* else */
-
- } /* if... */
-
- } /* while xdfs < maxdfs */
-
- /* krow has no more unexplored nbrs:
- * Place snode-rep krep in postorder DFS, if this
- * segment is seen for the first time. (Note that
- * "repfnz[krep]" may change later.)
- * Backtrack dfs to its parent.
- */
- if ( marker1[krep] < jcol ) {
- segrep[*nseg] = krep;
- ++(*nseg);
- marker1[krep] = jj;
- }
-
- kpar = parent[krep]; /* Pop stack, mimic recursion */
- if ( kpar == EMPTY ) break; /* dfs done */
- krep = kpar;
- xdfs = xplore[krep];
- maxdfs = xprune[krep];
-
-#ifdef CHK_DFS
- printf(" pop stack: krep %d,xdfs %d,maxdfs %d: ", krep,xdfs,maxdfs);
- for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]);
- printf("\n");
-#endif
- } while ( kpar != EMPTY ); /* do-while - until empty stack */
-
- } /* else */
-
- } /* else */
-
- } /* for each nonz in A[*,jj] */
-
- repfnz_col += m; /* Move to next column */
- dense_col += m;
-
- } /* for jj ... */
-
-}
diff --git a/intern/opennl/superlu/spivotL.c b/intern/opennl/superlu/spivotL.c
deleted file mode 100644
index 1a0302d0101..00000000000
--- a/intern/opennl/superlu/spivotL.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/** \file opennl/superlu/spivotL.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include <math.h>
-#include <stdlib.h>
-#include "ssp_defs.h"
-
-#undef DEBUG
-
-int
-spivotL(
- const int jcol, /* in */
- const double u, /* in - diagonal pivoting threshold */
- int *usepr, /* re-use the pivot sequence given by perm_r/iperm_r */
- int *perm_r, /* may be modified */
- int *iperm_r, /* in - inverse of perm_r */
- int *iperm_c, /* in - used to find diagonal of Pc*A*Pc' */
- int *pivrow, /* out */
- GlobalLU_t *Glu, /* modified - global LU data structures */
- SuperLUStat_t *stat /* output */
- )
-{
-/*
- * Purpose
- * =======
- * Performs the numerical pivoting on the current column of L,
- * and the CDIV operation.
- *
- * Pivot policy:
- * (1) Compute thresh = u * max_(i>=j) abs(A_ij);
- * (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN
- * pivot row = k;
- * ELSE IF abs(A_jj) >= thresh THEN
- * pivot row = j;
- * ELSE
- * pivot row = m;
- *
- * Note: If you absolutely want to use a given pivot order, then set u=0.0.
- *
- * Return value: 0 success;
- * i > 0 U(i,i) is exactly zero.
- *
- */
- int fsupc; /* first column in the supernode */
- int nsupc; /* no of columns in the supernode */
- int nsupr; /* no of rows in the supernode */
- int lptr; /* points to the starting subscript of the supernode */
- int pivptr, old_pivptr, diag, diagind;
- double pivmax, rtemp, thresh;
- double temp;
- double *lu_sup_ptr;
- double *lu_col_ptr;
- int *lsub_ptr;
- int isub, icol, k, itemp;
- int *lsub, *xlsub;
- double *lusup;
- int *xlusup;
- flops_t *ops = stat->ops;
-
- /* Initialize pointers */
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- lusup = Glu->lusup;
- xlusup = Glu->xlusup;
- fsupc = (Glu->xsup)[(Glu->supno)[jcol]];
- nsupc = jcol - fsupc; /* excluding jcol; nsupc >= 0 */
- lptr = xlsub[fsupc];
- nsupr = xlsub[fsupc+1] - lptr;
- lu_sup_ptr = &lusup[xlusup[fsupc]]; /* start of the current supernode */
- lu_col_ptr = &lusup[xlusup[jcol]]; /* start of jcol in the supernode */
- lsub_ptr = &lsub[lptr]; /* start of row indices of the supernode */
-
-#ifdef DEBUG
-if ( jcol == MIN_COL ) {
- printf("Before cdiv: col %d\n", jcol);
- for (k = nsupc; k < nsupr; k++)
- printf(" lu[%d] %f\n", lsub_ptr[k], lu_col_ptr[k]);
-}
-#endif
-
- /* Determine the largest abs numerical value for partial pivoting;
- Also search for user-specified pivot, and diagonal element. */
- if ( *usepr ) *pivrow = iperm_r[jcol];
- diagind = iperm_c[jcol];
- pivmax = 0.0;
- pivptr = nsupc;
- diag = EMPTY;
- old_pivptr = nsupc;
- for (isub = nsupc; isub < nsupr; ++isub) {
- rtemp = fabs (lu_col_ptr[isub]);
- if ( rtemp > pivmax ) {
- pivmax = rtemp;
- pivptr = isub;
- }
- if ( *usepr && lsub_ptr[isub] == *pivrow ) old_pivptr = isub;
- if ( lsub_ptr[isub] == diagind ) diag = isub;
- }
-
- /* Test for singularity */
- if ( pivmax == 0.0 ) {
- *pivrow = lsub_ptr[pivptr];
- perm_r[*pivrow] = jcol;
- *usepr = 0;
- return (jcol+1);
- }
-
- thresh = u * pivmax;
-
- /* Choose appropriate pivotal element by our policy. */
- if ( *usepr ) {
- rtemp = fabs (lu_col_ptr[old_pivptr]);
- if ( rtemp != 0.0 && rtemp >= thresh )
- pivptr = old_pivptr;
- else
- *usepr = 0;
- }
- if ( *usepr == 0 ) {
- /* Use diagonal pivot? */
- if ( diag >= 0 ) { /* diagonal exists */
- rtemp = fabs (lu_col_ptr[diag]);
- if ( rtemp != 0.0 && rtemp >= thresh ) pivptr = diag;
- }
- *pivrow = lsub_ptr[pivptr];
- }
-
- /* Record pivot row */
- perm_r[*pivrow] = jcol;
-
- /* Interchange row subscripts */
- if ( pivptr != nsupc ) {
- itemp = lsub_ptr[pivptr];
- lsub_ptr[pivptr] = lsub_ptr[nsupc];
- lsub_ptr[nsupc] = itemp;
-
- /* Interchange numerical values as well, for the whole snode, such
- * that L is indexed the same way as A.
- */
- for (icol = 0; icol <= nsupc; icol++) {
- itemp = pivptr + icol * nsupr;
- temp = lu_sup_ptr[itemp];
- lu_sup_ptr[itemp] = lu_sup_ptr[nsupc + icol*nsupr];
- lu_sup_ptr[nsupc + icol*nsupr] = temp;
- }
- } /* if */
-
- /* cdiv operation */
- ops[FACT] += nsupr - nsupc;
-
- temp = 1.0 / lu_col_ptr[nsupc];
- for (k = nsupc+1; k < nsupr; k++)
- lu_col_ptr[k] *= temp;
-
- return 0;
-}
-
diff --git a/intern/opennl/superlu/spruneL.c b/intern/opennl/superlu/spruneL.c
deleted file mode 100644
index 3cf29658596..00000000000
--- a/intern/opennl/superlu/spruneL.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/** \file opennl/superlu/spruneL.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-#include "util.h"
-
-void
-spruneL(
- const int jcol, /* in */
- const int *perm_r, /* in */
- const int pivrow, /* in */
- const int nseg, /* in */
- const int *segrep, /* in */
- const int *repfnz, /* in */
- int *xprune, /* out */
- GlobalLU_t *Glu /* modified - global LU data structures */
- )
-{
-/*
- * Purpose
- * =======
- * Prunes the L-structure of supernodes whose L-structure
- * contains the current pivot row "pivrow"
- *
- */
- double utemp;
- int jsupno, irep, irep1, kmin, kmax, krow, movnum;
- int i, ktemp, minloc, maxloc;
- int do_prune; /* logical variable */
- int *xsup, *supno;
- int *lsub, *xlsub;
- double *lusup;
- int *xlusup;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- lusup = Glu->lusup;
- xlusup = Glu->xlusup;
-
- /*
- * For each supernode-rep irep in U[*,j]
- */
- jsupno = supno[jcol];
- for (i = 0; i < nseg; i++) {
-
- irep = segrep[i];
- irep1 = irep + 1;
- do_prune = FALSE;
-
- /* Don't prune with a zero U-segment */
- if ( repfnz[irep] == EMPTY )
- continue;
-
- /* If a snode overlaps with the next panel, then the U-segment
- * is fragmented into two parts -- irep and irep1. We should let
- * pruning occur at the rep-column in irep1's snode.
- */
- if ( supno[irep] == supno[irep1] ) /* Don't prune */
- continue;
-
- /*
- * If it has not been pruned & it has a nonz in row L[pivrow,i]
- */
- if ( supno[irep] != jsupno ) {
- if ( xprune[irep] >= xlsub[irep1] ) {
- kmin = xlsub[irep];
- kmax = xlsub[irep1] - 1;
- for (krow = kmin; krow <= kmax; krow++)
- if ( lsub[krow] == pivrow ) {
- do_prune = TRUE;
- break;
- }
- }
-
- if ( do_prune ) {
-
- /* Do a quicksort-type partition
- * movnum=TRUE means that the num values have to be exchanged.
- */
- movnum = FALSE;
- if ( irep == xsup[supno[irep]] ) /* Snode of size 1 */
- movnum = TRUE;
-
- while ( kmin <= kmax ) {
-
- if ( perm_r[lsub[kmax]] == EMPTY )
- kmax--;
- else if ( perm_r[lsub[kmin]] != EMPTY )
- kmin++;
- else { /* kmin below pivrow, and kmax above pivrow:
- * interchange the two subscripts
- */
- ktemp = lsub[kmin];
- lsub[kmin] = lsub[kmax];
- lsub[kmax] = ktemp;
-
- /* If the supernode has only one column, then we
- * only keep one set of subscripts. For any subscript
- * interchange performed, similar interchange must be
- * done on the numerical values.
- */
- if ( movnum ) {
- minloc = xlusup[irep] + (kmin - xlsub[irep]);
- maxloc = xlusup[irep] + (kmax - xlsub[irep]);
- utemp = lusup[minloc];
- lusup[minloc] = lusup[maxloc];
- lusup[maxloc] = utemp;
- }
-
- kmin++;
- kmax--;
-
- }
-
- } /* while */
-
- xprune[irep] = kmin; /* Pruning */
-
-#ifdef CHK_PRUNE
- printf(" After spruneL(),using col %d: xprune[%d] = %d\n",
- jcol, irep, kmin);
-#endif
- } /* if do_prune */
-
- } /* if */
-
- } /* for each U-segment... */
-}
diff --git a/intern/opennl/superlu/ssnode_bmod.c b/intern/opennl/superlu/ssnode_bmod.c
deleted file mode 100644
index 9533373f212..00000000000
--- a/intern/opennl/superlu/ssnode_bmod.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/** \file opennl/superlu/ssnode_bmod.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-
-void slsolve(int, int, double*, double*);
-void smatvec(int, int, int, double*, double*, double*);
-
-/*
- * Performs numeric block updates within the relaxed snode.
- */
-int
-ssnode_bmod (
- const int jcol, /* in */
- const int fsupc, /* in */
- double *dense, /* in */
- double *tempv, /* working array */
- GlobalLU_t *Glu, /* modified */
- SuperLUStat_t *stat /* output */
- )
-{
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- _fcd ftcs1 = _cptofcd("L", strlen("L")),
- ftcs2 = _cptofcd("N", strlen("N")),
- ftcs3 = _cptofcd("U", strlen("U"));
-#endif
- int incx = 1, incy = 1;
- double alpha = -1.0, beta = 1.0;
-#endif
-
- int luptr, nsupc, nsupr, nrow;
- int isub, irow, i, iptr;
- register int ufirst, nextlu;
- int *lsub, *xlsub;
- double *lusup;
- int *xlusup;
- flops_t *ops = stat->ops;
-
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- lusup = Glu->lusup;
- xlusup = Glu->xlusup;
-
- nextlu = xlusup[jcol];
-
- /*
- * Process the supernodal portion of L\U[*,j]
- */
- for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) {
- irow = lsub[isub];
- lusup[nextlu] = dense[irow];
- dense[irow] = 0;
- ++nextlu;
- }
-
- xlusup[jcol + 1] = nextlu; /* Initialize xlusup for next column */
-
- if ( fsupc < jcol ) {
-
- luptr = xlusup[fsupc];
- nsupr = xlsub[fsupc+1] - xlsub[fsupc];
- nsupc = jcol - fsupc; /* Excluding jcol */
- ufirst = xlusup[jcol]; /* Points to the beginning of column
- jcol in supernode L\U(jsupno). */
- nrow = nsupr - nsupc;
-
- ops[TRSV] += nsupc * (nsupc - 1);
- ops[GEMV] += 2 * nrow * nsupc;
-
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], &nsupr,
- &lusup[ufirst], &incx );
- SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr,
- &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy );
-#else
- strsv_( "L", "N", "U", &nsupc, &lusup[luptr], &nsupr,
- &lusup[ufirst], &incx );
- sgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr,
- &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy );
-#endif
-#else
- slsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] );
- smatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc],
- &lusup[ufirst], &tempv[0] );
-
- /* Scatter tempv[*] into lusup[*] */
- iptr = ufirst + nsupc;
- for (i = 0; i < nrow; i++) {
- lusup[iptr++] -= tempv[i];
- tempv[i] = 0.0;
- }
-#endif
-
- }
-
- return 0;
-}
diff --git a/intern/opennl/superlu/ssnode_dfs.c b/intern/opennl/superlu/ssnode_dfs.c
deleted file mode 100644
index 0dfc8d86d82..00000000000
--- a/intern/opennl/superlu/ssnode_dfs.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/** \file opennl/superlu/ssnode_dfs.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include "ssp_defs.h"
-#include "util.h"
-
-int
-ssnode_dfs (
- const int jcol, /* in - start of the supernode */
- const int kcol, /* in - end of the supernode */
- const int *asub, /* in */
- const int *xa_begin, /* in */
- const int *xa_end, /* in */
- int *xprune, /* out */
- int *marker, /* modified */
- GlobalLU_t *Glu /* modified */
- )
-{
-/* Purpose
- * =======
- * ssnode_dfs() - Determine the union of the row structures of those
- * columns within the relaxed snode.
- * Note: The relaxed snodes are leaves of the supernodal etree, therefore,
- * the portion outside the rectangular supernode must be zero.
- *
- * Return value
- * ============
- * 0 success;
- * >0 number of bytes allocated when run out of memory.
- *
- */
- register int i, k, ifrom, ito, nextl, new_next;
- int nsuper, krow, kmark, mem_error;
- int *xsup, *supno;
- int *lsub, *xlsub;
- int nzlmax;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- nzlmax = Glu->nzlmax;
-
- nsuper = ++supno[jcol]; /* Next available supernode number */
- nextl = xlsub[jcol];
-
- for (i = jcol; i <= kcol; i++) {
- /* For each nonzero in A[*,i] */
- for (k = xa_begin[i]; k < xa_end[i]; k++) {
- krow = asub[k];
- kmark = marker[krow];
- if ( kmark != kcol ) { /* First time visit krow */
- marker[krow] = kcol;
- lsub[nextl++] = krow;
- if ( nextl >= nzlmax ) {
- if ( (mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)) )
- return (mem_error);
- lsub = Glu->lsub;
- }
- }
- }
- supno[i] = nsuper;
- }
-
- /* Supernode > 1, then make a copy of the subscripts for pruning */
- if ( jcol < kcol ) {
- new_next = nextl + (nextl - xlsub[jcol]);
- while ( new_next > nzlmax ) {
- if ( (mem_error = sLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu)) )
- return (mem_error);
- lsub = Glu->lsub;
- }
- ito = nextl;
- for (ifrom = xlsub[jcol]; ifrom < nextl; )
- lsub[ito++] = lsub[ifrom++];
- for (i = jcol+1; i <= kcol; i++) xlsub[i] = nextl;
- nextl = ito;
- }
-
- xsup[nsuper+1] = kcol + 1;
- supno[kcol+1] = nsuper;
- xprune[kcol] = nextl;
- xlsub[kcol+1] = nextl;
-
- return 0;
-}
-
diff --git a/intern/opennl/superlu/ssp_blas2.c b/intern/opennl/superlu/ssp_blas2.c
deleted file mode 100644
index 9215d48dc09..00000000000
--- a/intern/opennl/superlu/ssp_blas2.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/** \file opennl/superlu/ssp_blas2.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- * File name: ssp_blas2.c
- * Purpose: Sparse BLAS 2, using some dense BLAS 2 operations.
- */
-
-#include "ssp_defs.h"
-
-/*
- * Function prototypes
- */
-void susolve(int, int, double*, double*);
-void slsolve(int, int, double*, double*);
-void smatvec(int, int, int, double*, double*, double*);
-int strsv_(char*, char*, char*, int*, double*, int*, double*, int*);
-
-int
-sp_strsv(char *uplo, char *trans, char *diag, SuperMatrix *L,
- SuperMatrix *U, double *x, SuperLUStat_t *stat, int *info)
-{
-/*
- * Purpose
- * =======
- *
- * sp_strsv() solves one of the systems of equations
- * A*x = b, or A'*x = b,
- * where b and x are n element vectors and A is a sparse unit , or
- * non-unit, upper or lower triangular matrix.
- * No test for singularity or near-singularity is included in this
- * routine. Such tests must be performed before calling this routine.
- *
- * Parameters
- * ==========
- *
- * uplo - (input) char*
- * On entry, uplo specifies whether the matrix is an upper or
- * lower triangular matrix as follows:
- * uplo = 'U' or 'u' A is an upper triangular matrix.
- * uplo = 'L' or 'l' A is a lower triangular matrix.
- *
- * trans - (input) char*
- * On entry, trans specifies the equations to be solved as
- * follows:
- * trans = 'N' or 'n' A*x = b.
- * trans = 'T' or 't' A'*x = b.
- * trans = 'C' or 'c' A'*x = b.
- *
- * diag - (input) char*
- * On entry, diag specifies whether or not A is unit
- * triangular as follows:
- * diag = 'U' or 'u' A is assumed to be unit triangular.
- * diag = 'N' or 'n' A is not assumed to be unit
- * triangular.
- *
- * L - (input) SuperMatrix*
- * The factor L from the factorization Pr*A*Pc=L*U. Use
- * compressed row subscripts storage for supernodes,
- * i.e., L has types: Stype = SC, Dtype = SLU_S, Mtype = TRLU.
- *
- * U - (input) SuperMatrix*
- * The factor U from the factorization Pr*A*Pc=L*U.
- * U has types: Stype = NC, Dtype = SLU_S, Mtype = TRU.
- *
- * x - (input/output) double*
- * Before entry, the incremented array X must contain the n
- * element right-hand side vector b. On exit, X is overwritten
- * with the solution vector x.
- *
- * info - (output) int*
- * If *info = -i, the i-th argument had an illegal value.
- *
- */
-#ifdef _CRAY
- _fcd ftcs1 = _cptofcd("L", strlen("L")),
- ftcs2 = _cptofcd("N", strlen("N")),
- ftcs3 = _cptofcd("U", strlen("U"));
-#endif
- SCformat *Lstore;
- NCformat *Ustore;
- double *Lval, *Uval;
- int incx = 1;
- int nrow;
- int fsupc, nsupr, nsupc, luptr, istart, irow;
- int i, k, iptr, jcol;
- double *work;
- flops_t solve_ops;
-
- /* Test the input parameters */
- *info = 0;
- if ( !lsame_(uplo,"L") && !lsame_(uplo, "U") ) *info = -1;
- else if ( !lsame_(trans, "N") && !lsame_(trans, "T") &&
- !lsame_(trans, "C")) *info = -2;
- else if ( !lsame_(diag, "U") && !lsame_(diag, "N") ) *info = -3;
- else if ( L->nrow != L->ncol || L->nrow < 0 ) *info = -4;
- else if ( U->nrow != U->ncol || U->nrow < 0 ) *info = -5;
- if ( *info ) {
- i = -(*info);
- xerbla_("sp_strsv", &i);
- return 0;
- }
-
- Lstore = L->Store;
- Lval = Lstore->nzval;
- Ustore = U->Store;
- Uval = Ustore->nzval;
- solve_ops = 0;
-
- if ( !(work = doubleCalloc(L->nrow)) )
- ABORT("Malloc fails for work in sp_strsv().");
-
- if ( lsame_(trans, "N") ) { /* Form x := inv(A)*x. */
-
- if ( lsame_(uplo, "L") ) {
- /* Form x := inv(L)*x */
- if ( L->nrow == 0 ) {
- SUPERLU_FREE(work);
- return 0; /* Quick return */
- }
-
- for (k = 0; k <= Lstore->nsuper; k++) {
- fsupc = L_FST_SUPC(k);
- istart = L_SUB_START(fsupc);
- nsupr = L_SUB_START(fsupc+1) - istart;
- nsupc = L_FST_SUPC(k+1) - fsupc;
- luptr = L_NZ_START(fsupc);
- nrow = nsupr - nsupc;
-
- solve_ops += nsupc * (nsupc - 1);
- solve_ops += 2 * nrow * nsupc;
-
- if ( nsupc == 1 ) {
- for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); ++iptr) {
- irow = L_SUB(iptr);
- ++luptr;
- x[irow] -= x[fsupc] * Lval[luptr];
- }
- } else {
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-
- SGEMV(ftcs2, &nrow, &nsupc, &alpha, &Lval[luptr+nsupc],
- &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy);
-#else
- strsv_("L", "N", "U", &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-
- sgemv_("N", &nrow, &nsupc, &alpha, &Lval[luptr+nsupc],
- &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy);
-#endif
-#else
- slsolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc]);
-
- smatvec ( nsupr, nsupr-nsupc, nsupc, &Lval[luptr+nsupc],
- &x[fsupc], &work[0] );
-#endif
-
- iptr = istart + nsupc;
- for (i = 0; i < nrow; ++i, ++iptr) {
- irow = L_SUB(iptr);
- x[irow] -= work[i]; /* Scatter */
- work[i] = 0.0;
-
- }
- }
- } /* for k ... */
-
- } else {
- /* Form x := inv(U)*x */
-
- if ( U->nrow == 0 ) return 0; /* Quick return */
-
- for (k = Lstore->nsuper; k >= 0; k--) {
- fsupc = L_FST_SUPC(k);
- nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc);
- nsupc = L_FST_SUPC(k+1) - fsupc;
- luptr = L_NZ_START(fsupc);
-
- solve_ops += nsupc * (nsupc + 1);
-
- if ( nsupc == 1 ) {
- x[fsupc] /= Lval[luptr];
- for (i = U_NZ_START(fsupc); i < U_NZ_START(fsupc+1); ++i) {
- irow = U_SUB(i);
- x[irow] -= x[fsupc] * Uval[i];
- }
- } else {
-#ifdef USE_VENDOR_BLAS
-#ifdef _CRAY
- STRSV(ftcs3, ftcs2, ftcs2, &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-#else
- strsv_("U", "N", "N", &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-#endif
-#else
- susolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc] );
-#endif
-
- for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) {
- solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol));
- for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1);
- i++) {
- irow = U_SUB(i);
- x[irow] -= x[jcol] * Uval[i];
- }
- }
- }
- } /* for k ... */
-
- }
- } else { /* Form x := inv(A')*x */
-
- if ( lsame_(uplo, "L") ) {
- /* Form x := inv(L')*x */
- if ( L->nrow == 0 ) return 0; /* Quick return */
-
- for (k = Lstore->nsuper; k >= 0; --k) {
- fsupc = L_FST_SUPC(k);
- istart = L_SUB_START(fsupc);
- nsupr = L_SUB_START(fsupc+1) - istart;
- nsupc = L_FST_SUPC(k+1) - fsupc;
- luptr = L_NZ_START(fsupc);
-
- solve_ops += 2 * (nsupr - nsupc) * nsupc;
-
- for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) {
- iptr = istart + nsupc;
- for (i = L_NZ_START(jcol) + nsupc;
- i < L_NZ_START(jcol+1); i++) {
- irow = L_SUB(iptr);
- x[jcol] -= x[irow] * Lval[i];
- iptr++;
- }
- }
-
- if ( nsupc > 1 ) {
- solve_ops += nsupc * (nsupc - 1);
-#ifdef _CRAY
- ftcs1 = _cptofcd("L", strlen("L"));
- ftcs2 = _cptofcd("T", strlen("T"));
- ftcs3 = _cptofcd("U", strlen("U"));
- STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-#else
- strsv_("L", "T", "U", &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-#endif
- }
- }
- } else {
- /* Form x := inv(U')*x */
- if ( U->nrow == 0 ) return 0; /* Quick return */
-
- for (k = 0; k <= Lstore->nsuper; k++) {
- fsupc = L_FST_SUPC(k);
- nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc);
- nsupc = L_FST_SUPC(k+1) - fsupc;
- luptr = L_NZ_START(fsupc);
-
- for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) {
- solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol));
- for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++) {
- irow = U_SUB(i);
- x[jcol] -= x[irow] * Uval[i];
- }
- }
-
- solve_ops += nsupc * (nsupc + 1);
-
- if ( nsupc == 1 ) {
- x[fsupc] /= Lval[luptr];
- } else {
-#ifdef _CRAY
- ftcs1 = _cptofcd("U", strlen("U"));
- ftcs2 = _cptofcd("T", strlen("T"));
- ftcs3 = _cptofcd("N", strlen("N"));
- STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-#else
- strsv_("U", "T", "N", &nsupc, &Lval[luptr], &nsupr,
- &x[fsupc], &incx);
-#endif
- }
- } /* for k ... */
- }
- }
-
- stat->ops[SOLVE] += solve_ops;
- SUPERLU_FREE(work);
- return 0;
-}
-
-
-
-
-int
-sp_sgemv(char *trans, double alpha, SuperMatrix *A, double *x,
- int incx, double beta, double *y, int incy)
-{
-/* Purpose
- =======
-
- sp_sgemv() performs one of the matrix-vector operations
- y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y,
- where alpha and beta are scalars, x and y are vectors and A is a
- sparse A->nrow by A->ncol matrix.
-
- Parameters
- ==========
-
- TRANS - (input) char*
- On entry, TRANS specifies the operation to be performed as
- follows:
- TRANS = 'N' or 'n' y := alpha*A*x + beta*y.
- TRANS = 'T' or 't' y := alpha*A'*x + beta*y.
- TRANS = 'C' or 'c' y := alpha*A'*x + beta*y.
-
- ALPHA - (input) double
- On entry, ALPHA specifies the scalar alpha.
-
- A - (input) SuperMatrix*
- Matrix A with a sparse format, of dimension (A->nrow, A->ncol).
- Currently, the type of A can be:
- Stype = NC or NCP; Dtype = SLU_S; Mtype = GE.
- In the future, more general A can be handled.
-
- X - (input) double*, array of DIMENSION at least
- ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n'
- and at least
- ( 1 + ( m - 1 )*abs( INCX ) ) otherwise.
- Before entry, the incremented array X must contain the
- vector x.
-
- INCX - (input) int
- On entry, INCX specifies the increment for the elements of
- X. INCX must not be zero.
-
- BETA - (input) double
- On entry, BETA specifies the scalar beta. When BETA is
- supplied as zero then Y need not be set on input.
-
- Y - (output) double*, array of DIMENSION at least
- ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'
- and at least
- ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.
- Before entry with BETA non-zero, the incremented array Y
- must contain the vector y. On exit, Y is overwritten by the
- updated vector y.
-
- INCY - (input) int
- On entry, INCY specifies the increment for the elements of
- Y. INCY must not be zero.
-
- ==== Sparse Level 2 Blas routine.
-*/
-
- /* Local variables */
- NCformat *Astore;
- double *Aval;
- int info;
- double temp;
- int lenx, leny, i, j, irow;
- int iy, jx, jy, kx, ky;
- int notran;
-
- notran = lsame_(trans, "N");
- Astore = A->Store;
- Aval = Astore->nzval;
-
- /* Test the input parameters */
- info = 0;
- if ( !notran && !lsame_(trans, "T") && !lsame_(trans, "C")) info = 1;
- else if ( A->nrow < 0 || A->ncol < 0 ) info = 3;
- else if (incx == 0) info = 5;
- else if (incy == 0) info = 8;
- if (info != 0) {
- xerbla_("sp_sgemv ", &info);
- return 0;
- }
-
- /* Quick return if possible. */
- if (A->nrow == 0 || A->ncol == 0 || (alpha == 0. && beta == 1.))
- return 0;
-
- /* Set LENX and LENY, the lengths of the vectors x and y, and set
- up the start points in X and Y. */
- if (lsame_(trans, "N")) {
- lenx = A->ncol;
- leny = A->nrow;
- } else {
- lenx = A->nrow;
- leny = A->ncol;
- }
- if (incx > 0) kx = 0;
- else kx = - (lenx - 1) * incx;
- if (incy > 0) ky = 0;
- else ky = - (leny - 1) * incy;
-
- /* Start the operations. In this version the elements of A are
- accessed sequentially with one pass through A. */
- /* First form y := beta*y. */
- if (beta != 1.) {
- if (incy == 1) {
- if (beta == 0.)
- for (i = 0; i < leny; ++i) y[i] = 0.;
- else
- for (i = 0; i < leny; ++i) y[i] = beta * y[i];
- } else {
- iy = ky;
- if (beta == 0.)
- for (i = 0; i < leny; ++i) {
- y[iy] = 0.;
- iy += incy;
- }
- else
- for (i = 0; i < leny; ++i) {
- y[iy] = beta * y[iy];
- iy += incy;
- }
- }
- }
-
- if (alpha == 0.) return 0;
-
- if ( notran ) {
- /* Form y := alpha*A*x + y. */
- jx = kx;
- if (incy == 1) {
- for (j = 0; j < A->ncol; ++j) {
- if (x[jx] != 0.) {
- temp = alpha * x[jx];
- for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) {
- irow = Astore->rowind[i];
- y[irow] += temp * Aval[i];
- }
- }
- jx += incx;
- }
- } else {
- ABORT("Not implemented.");
- }
- } else {
- /* Form y := alpha*A'*x + y. */
- jy = ky;
- if (incx == 1) {
- for (j = 0; j < A->ncol; ++j) {
- temp = 0.;
- for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) {
- irow = Astore->rowind[i];
- temp += Aval[i] * x[irow];
- }
- y[jy] += alpha * temp;
- jy += incy;
- }
- } else {
- ABORT("Not implemented.");
- }
- }
- return 0;
-} /* sp_sgemv */
-
-
-
diff --git a/intern/opennl/superlu/ssp_blas3.c b/intern/opennl/superlu/ssp_blas3.c
deleted file mode 100644
index aeb51b0c1ca..00000000000
--- a/intern/opennl/superlu/ssp_blas3.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/** \file opennl/superlu/ssp_blas3.c
- * \ingroup opennl
- */
-
-
-/*
- * -- SuperLU routine (version 2.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * November 15, 1997
- *
- */
-/*
- * File name: sp_blas3.c
- * Purpose: Sparse BLAS3, using some dense BLAS3 operations.
- */
-
-#include "ssp_defs.h"
-#include "util.h"
-
-int
-sp_sgemm(char *transa, int n,
- double alpha, SuperMatrix *A, double *b, int ldb,
- double beta, double *c, int ldc)
-{
-/* Purpose
- =======
-
- sp_s performs one of the matrix-matrix operations
-
- C := alpha*op( A )*op( B ) + beta*C,
-
- where op( X ) is one of
-
- op( X ) = X or op( X ) = X' or op( X ) = conjg( X' ),
-
- alpha and beta are scalars, and A, B and C are matrices, with op( A )
- an m by k matrix, op( B ) a k by n matrix and C an m by n matrix.
-
-
- Parameters
- ==========
-
- TRANSA - (input) char*
- On entry, TRANSA specifies the form of op( A ) to be used in
- the matrix multiplication as follows:
- TRANSA = 'N' or 'n', op( A ) = A.
- TRANSA = 'T' or 't', op( A ) = A'.
- TRANSA = 'C' or 'c', op( A ) = conjg( A' ).
- Unchanged on exit.
-
- TRANSB - (input) char*
- On entry, TRANSB specifies the form of op( B ) to be used in
- the matrix multiplication as follows:
- TRANSB = 'N' or 'n', op( B ) = B.
- TRANSB = 'T' or 't', op( B ) = B'.
- TRANSB = 'C' or 'c', op( B ) = conjg( B' ).
- Unchanged on exit.
-
- M - (input) int
- On entry, M specifies the number of rows of the matrix
- op( A ) and of the matrix C. M must be at least zero.
- Unchanged on exit.
-
- N - (input) int
- On entry, N specifies the number of columns of the matrix
- op( B ) and the number of columns of the matrix C. N must be
- at least zero.
- Unchanged on exit.
-
- K - (input) int
- On entry, K specifies the number of columns of the matrix
- op( A ) and the number of rows of the matrix op( B ). K must
- be at least zero.
- Unchanged on exit.
-
- ALPHA - (input) double
- On entry, ALPHA specifies the scalar alpha.
-
- A - (input) SuperMatrix*
- Matrix A with a sparse format, of dimension (A->nrow, A->ncol).
- Currently, the type of A can be:
- Stype = NC or NCP; Dtype = SLU_S; Mtype = GE.
- In the future, more general A can be handled.
-
- B - FLOAT PRECISION array of DIMENSION ( LDB, kb ), where kb is
- n when TRANSB = 'N' or 'n', and is k otherwise.
- Before entry with TRANSB = 'N' or 'n', the leading k by n
- part of the array B must contain the matrix B, otherwise
- the leading n by k part of the array B must contain the
- matrix B.
- Unchanged on exit.
-
- LDB - (input) int
- On entry, LDB specifies the first dimension of B as declared
- in the calling (sub) program. LDB must be at least max( 1, n ).
- Unchanged on exit.
-
- BETA - (input) double
- On entry, BETA specifies the scalar beta. When BETA is
- supplied as zero then C need not be set on input.
-
- C - FLOAT PRECISION array of DIMENSION ( LDC, n ).
- Before entry, the leading m by n part of the array C must
- contain the matrix C, except when beta is zero, in which
- case C need not be set on entry.
- On exit, the array C is overwritten by the m by n matrix
- ( alpha*op( A )*B + beta*C ).
-
- LDC - (input) int
- On entry, LDC specifies the first dimension of C as declared
- in the calling (sub)program. LDC must be at least max(1,m).
- Unchanged on exit.
-
- ==== Sparse Level 3 Blas routine.
-*/
- int incx = 1, incy = 1;
- int j;
-
- for (j = 0; j < n; ++j) {
- sp_sgemv(transa, alpha, A, &b[ldb*j], incx, beta, &c[ldc*j], incy);
- }
- return 0;
-}
diff --git a/intern/opennl/superlu/ssp_defs.h b/intern/opennl/superlu/ssp_defs.h
deleted file mode 100644
index 5110fc5ad69..00000000000
--- a/intern/opennl/superlu/ssp_defs.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/** \file opennl/superlu/ssp_defs.h
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-#ifndef __SUPERLU_sSP_DEFS /* allow multiple inclusions */
-#define __SUPERLU_sSP_DEFS
-
-/*
- * File name: ssp_defs.h
- * Purpose: Sparse matrix types and function prototypes
- * History:
- */
-
-#ifdef _CRAY
-#include <fortran.h>
-#include <string.h>
-#endif
-
-/* Define my integer type int_t */
-typedef int int_t; /* default */
-
-#include "Cnames.h"
-#include "supermatrix.h"
-#include "util.h"
-
-
-/*
- * Global data structures used in LU factorization -
- *
- * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper].
- * (xsup,supno): supno[i] is the supernode no to which i belongs;
- * xsup(s) points to the beginning of the s-th supernode.
- * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12)
- * xsup 0 1 2 4 7 12
- * Note: dfs will be performed on supernode rep. relative to the new
- * row pivoting ordering
- *
- * (xlsub,lsub): lsub[*] contains the compressed subscript of
- * rectangular supernodes; xlsub[j] points to the starting
- * location of the j-th column in lsub[*]. Note that xlsub
- * is indexed by column.
- * Storage: original row subscripts
- *
- * During the course of sparse LU factorization, we also use
- * (xlsub,lsub) for the purpose of symmetric pruning. For each
- * supernode {s,s+1,...,t=s+r} with first column s and last
- * column t, the subscript set
- * lsub[j], j=xlsub[s], .., xlsub[s+1]-1
- * is the structure of column s (i.e. structure of this supernode).
- * It is used for the storage of numerical values.
- * Furthermore,
- * lsub[j], j=xlsub[t], .., xlsub[t+1]-1
- * is the structure of the last column t of this supernode.
- * It is for the purpose of symmetric pruning. Therefore, the
- * structural subscripts can be rearranged without making physical
- * interchanges among the numerical values.
- *
- * However, if the supernode has only one column, then we
- * only keep one set of subscripts. For any subscript interchange
- * performed, similar interchange must be done on the numerical
- * values.
- *
- * The last column structures (for pruning) will be removed
- * after the numercial LU factorization phase.
- *
- * (xlusup,lusup): lusup[*] contains the numerical values of the
- * rectangular supernodes; xlusup[j] points to the starting
- * location of the j-th column in storage vector lusup[*]
- * Note: xlusup is indexed by column.
- * Each rectangular supernode is stored by column-major
- * scheme, consistent with Fortran 2-dim array storage.
- *
- * (xusub,ucol,usub): ucol[*] stores the numerical values of
- * U-columns outside the rectangular supernodes. The row
- * subscript of nonzero ucol[k] is stored in usub[k].
- * xusub[i] points to the starting location of column i in ucol.
- * Storage: new row subscripts; that is subscripts of PA.
- */
-typedef struct {
- int *xsup; /* supernode and column mapping */
- int *supno;
- int *lsub; /* compressed L subscripts */
- int *xlsub;
- double *lusup; /* L supernodes */
- int *xlusup;
- double *ucol; /* U columns */
- int *usub;
- int *xusub;
- int nzlmax; /* current max size of lsub */
- int nzumax; /* " " " ucol */
- int nzlumax; /* " " " lusup */
- int n; /* number of columns in the matrix */
- LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */
-} GlobalLU_t;
-
-typedef struct {
- double for_lu;
- double total_needed;
- int expansions;
-} mem_usage_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Driver routines */
-extern void
-sgssv(superlu_options_t *, SuperMatrix *, int *, int *, SuperMatrix *,
- SuperMatrix *, SuperMatrix *, SuperLUStat_t *, int *);
-extern void
-sgssvx(superlu_options_t *, SuperMatrix *, int *, int *, int *,
- char *, double *, double *, SuperMatrix *, SuperMatrix *,
- void *, int, SuperMatrix *, SuperMatrix *,
- double *, double *, double *, double *,
- mem_usage_t *, SuperLUStat_t *, int *);
-
-/* Supernodal LU factor related */
-extern void
-sCreate_CompCol_Matrix(SuperMatrix *, int, int, int, double *,
- int *, int *, Stype_t, Dtype_t, Mtype_t);
-extern void
-sCreate_CompRow_Matrix(SuperMatrix *, int, int, int, double *,
- int *, int *, Stype_t, Dtype_t, Mtype_t);
-extern void
-sCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *);
-extern void
-sCreate_Dense_Matrix(SuperMatrix *, int, int, double *, int,
- Stype_t, Dtype_t, Mtype_t);
-extern void
-sCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, double *,
- int *, int *, int *, int *, int *,
- Stype_t, Dtype_t, Mtype_t);
-extern void
-sCopy_Dense_Matrix(int, int, double *, int, double *, int);
-
-extern void countnz (const int, int *, int *, int *, GlobalLU_t *);
-extern void fixupL (const int, const int *, GlobalLU_t *);
-
-extern void sallocateA (int, int, double **, int **, int **);
-extern void sgstrf (superlu_options_t*, SuperMatrix*,
- int, int, int*, void *, int, int *, int *,
- SuperMatrix *, SuperMatrix *, SuperLUStat_t*, int *);
-extern int ssnode_dfs (const int, const int, const int *, const int *,
- const int *, int *, int *, GlobalLU_t *);
-extern int ssnode_bmod (const int, const int, double *,
- double *, GlobalLU_t *, SuperLUStat_t*);
-extern void spanel_dfs (const int, const int, const int, SuperMatrix *,
- int *, int *, double *, int *, int *, int *,
- int *, int *, int *, int *, GlobalLU_t *);
-extern void spanel_bmod (const int, const int, const int, const int,
- double *, double *, int *, int *,
- GlobalLU_t *, SuperLUStat_t*);
-extern int scolumn_dfs (const int, const int, int *, int *, int *, int *,
- int *, int *, int *, int *, int *, GlobalLU_t *);
-extern int scolumn_bmod (const int, const int, double *,
- double *, int *, int *, int,
- GlobalLU_t *, SuperLUStat_t*);
-extern int scopy_to_ucol (int, int, int *, int *, int *,
- double *, GlobalLU_t *);
-extern int spivotL (const int, const double, int *, int *,
- int *, int *, int *, GlobalLU_t *, SuperLUStat_t*);
-extern void spruneL (const int, const int *, const int, const int,
- const int *, const int *, int *, GlobalLU_t *);
-extern void sreadmt (int *, int *, int *, double **, int **, int **);
-extern void sGenXtrue (int, int, double *, int);
-extern void sFillRHS (trans_t, int, double *, int, SuperMatrix *,
- SuperMatrix *);
-extern void sgstrs (trans_t, SuperMatrix *, SuperMatrix *, int *, int *,
- SuperMatrix *, SuperLUStat_t*, int *);
-
-
-/* Driver related */
-
-extern void sgsequ (SuperMatrix *, double *, double *, double *,
- double *, double *, int *);
-extern void slaqgs (SuperMatrix *, double *, double *, double,
- double, double, char *);
-extern void sgscon (char *, SuperMatrix *, SuperMatrix *,
- double, double *, SuperLUStat_t*, int *);
-extern double sPivotGrowth(int, SuperMatrix *, int *,
- SuperMatrix *, SuperMatrix *);
-extern void sgsrfs (trans_t, SuperMatrix *, SuperMatrix *,
- SuperMatrix *, int *, int *, char *, double *,
- double *, SuperMatrix *, SuperMatrix *,
- double *, double *, SuperLUStat_t*, int *);
-
-extern int sp_strsv (char *, char *, char *, SuperMatrix *,
- SuperMatrix *, double *, SuperLUStat_t*, int *);
-extern int sp_sgemv (char *, double, SuperMatrix *, double *,
- int, double, double *, int);
-
-extern int sp_sgemm (char *, int, double,
- SuperMatrix *, double *, int, double,
- double *, int);
-
-/* Memory-related */
-extern int sLUMemInit (fact_t, void *, int, int, int, int, int,
- SuperMatrix *, SuperMatrix *,
- GlobalLU_t *, int **, double **);
-extern void sSetRWork (int, int, double *, double **, double **);
-extern void sLUWorkFree (int *, double *, GlobalLU_t *);
-extern int sLUMemXpand (int, int, MemType, int *, GlobalLU_t *);
-
-extern double *doubleMalloc(int);
-extern double *doubleCalloc(int);
-extern int smemory_usage(const int, const int, const int, const int);
-extern int sQuerySpace (SuperMatrix *, SuperMatrix *, mem_usage_t *);
-
-/* Auxiliary routines */
-extern void sreadhb(int *, int *, int *, double **, int **, int **);
-extern void sCompRow_to_CompCol(int, int, int, double*, int*, int*,
- double **, int **, int **);
-extern void sfill (double *, int, double);
-extern void sinf_norm_error (int, SuperMatrix *, double *);
-extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *,
- double, double, double *, double *, char *);
-
-/* Routines for debugging */
-extern void sPrint_CompCol_Matrix(char *, SuperMatrix *);
-extern void sPrint_SuperNode_Matrix(char *, SuperMatrix *);
-extern void sPrint_Dense_Matrix(char *, SuperMatrix *);
-extern void print_lu_col(char *, int, int, int *, GlobalLU_t *);
-extern void check_tempv(int, double *);
-extern int print_int_vec(char *what, int n, int *vec);
-
-extern int sp_symetree(int *acolst, int *acolend, int *arow, int n, int *parent);
-extern void sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu); // added to build with debug for blender - campbell
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* __SUPERLU_sSP_DEFS */
-
diff --git a/intern/opennl/superlu/strsv.c b/intern/opennl/superlu/strsv.c
deleted file mode 100644
index a34f5fb38a1..00000000000
--- a/intern/opennl/superlu/strsv.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/** \file opennl/superlu/strsv.c
- * \ingroup opennl
- */
-int strsv_(char *, char *, char *, int *, double *, int *, double *, int *);
-
-
-/* Subroutine */ int strsv_(char *uplo, char *trans, char *diag, int *n,
- double *a, int *lda, double *x, int *incx)
-{
-
-
- /* Local variables */
- static int info;
- static double temp;
- static int i, j;
- extern int lsame_(char *, char *);
- static int ix, jx, kx;
- extern /* Subroutine */ int xerbla_(char *, int *);
- static int nounit;
-
-
-/* Purpose
- =======
-
- STRSV solves one of the systems of equations
-
- A*x = b, or A'*x = b,
-
- where b and x are n element vectors and A is an n by n unit, or
- non-unit, upper or lower triangular matrix.
-
- No test for singularity or near-singularity is included in this
- routine. Such tests must be performed before calling this routine.
-
- Parameters
- ==========
-
- UPLO - CHARACTER*1.
- On entry, UPLO specifies whether the matrix is an upper or
- lower triangular matrix as follows:
-
- UPLO = 'U' or 'u' A is an upper triangular matrix.
-
- UPLO = 'L' or 'l' A is a lower triangular matrix.
-
- Unchanged on exit.
-
- TRANS - CHARACTER*1.
- On entry, TRANS specifies the equations to be solved as
- follows:
-
- TRANS = 'N' or 'n' A*x = b.
-
- TRANS = 'T' or 't' A'*x = b.
-
- TRANS = 'C' or 'c' A'*x = b.
-
- Unchanged on exit.
-
- DIAG - CHARACTER*1.
- On entry, DIAG specifies whether or not A is unit
- triangular as follows:
-
- DIAG = 'U' or 'u' A is assumed to be unit triangular.
-
- DIAG = 'N' or 'n' A is not assumed to be unit
- triangular.
-
- Unchanged on exit.
-
- N - INTEGER.
- On entry, N specifies the order of the matrix A.
- N must be at least zero.
- Unchanged on exit.
-
- A - REAL array of DIMENSION ( LDA, n ).
- Before entry with UPLO = 'U' or 'u', the leading n by n
- upper triangular part of the array A must contain the upper
-
- triangular matrix and the strictly lower triangular part of
-
- A is not referenced.
- Before entry with UPLO = 'L' or 'l', the leading n by n
- lower triangular part of the array A must contain the lower
-
- triangular matrix and the strictly upper triangular part of
-
- A is not referenced.
- Note that when DIAG = 'U' or 'u', the diagonal elements of
-
- A are not referenced either, but are assumed to be unity.
- Unchanged on exit.
-
- LDA - INTEGER.
- On entry, LDA specifies the first dimension of A as declared
-
- in the calling (sub) program. LDA must be at least
- max( 1, n ).
- Unchanged on exit.
-
- X - REAL array of dimension at least
- ( 1 + ( n - 1 )*abs( INCX ) ).
- Before entry, the incremented array X must contain the n
- element right-hand side vector b. On exit, X is overwritten
-
- with the solution vector x.
-
- INCX - INTEGER.
- On entry, INCX specifies the increment for the elements of
- X. INCX must not be zero.
- Unchanged on exit.
-
-
- Level 2 Blas routine.
-
- -- Written on 22-October-1986.
- Jack Dongarra, Argonne National Lab.
- Jeremy Du Croz, Nag Central Office.
- Sven Hammarling, Nag Central Office.
- Richard Hanson, Sandia National Labs.
-
-
-
- Test the input parameters.
-
-
- Parameter adjustments
- Function Body */
-#define X(I) x[(I)-1]
-
-#define A(I,J) a[(I)-1 + ((J)-1)* ( *lda)]
-
- info = 0;
- if (! lsame_(uplo, "U") && ! lsame_(uplo, "L")) {
- info = 1;
- } else if (! lsame_(trans, "N") && ! lsame_(trans, "T") &&
- ! lsame_(trans, "C")) {
- info = 2;
- } else if (! lsame_(diag, "U") && ! lsame_(diag, "N")) {
- info = 3;
- } else if (*n < 0) {
- info = 4;
- } else if (*lda < ((1 > *n)? 1: *n)) {
- info = 6;
- } else if (*incx == 0) {
- info = 8;
- }
- if (info != 0) {
- xerbla_("STRSV ", &info);
- return 0;
- }
-
-/* Quick return if possible. */
-
- if (*n == 0) {
- return 0;
- }
-
- nounit = lsame_(diag, "N");
-
-/* Set up the start point in X if the increment is not unity. This
- will be ( N - 1 )*INCX too small for descending loops. */
-
- if (*incx <= 0) {
- kx = 1 - (*n - 1) * *incx;
- } else if (*incx != 1) {
- kx = 1;
- }
-
-/* Start the operations. In this version the elements of A are
- accessed sequentially with one pass through A. */
-
- if (lsame_(trans, "N")) {
-
-/* Form x := inv( A )*x. */
-
- if (lsame_(uplo, "U")) {
- if (*incx == 1) {
- for (j = *n; j >= 1; --j) {
- if (X(j) != 0.f) {
- if (nounit) {
- X(j) /= A(j,j);
- }
- temp = X(j);
- for (i = j - 1; i >= 1; --i) {
- X(i) -= temp * A(i,j);
-/* L10: */
- }
- }
-/* L20: */
- }
- } else {
- jx = kx + (*n - 1) * *incx;
- for (j = *n; j >= 1; --j) {
- if (X(jx) != 0.f) {
- if (nounit) {
- X(jx) /= A(j,j);
- }
- temp = X(jx);
- ix = jx;
- for (i = j - 1; i >= 1; --i) {
- ix -= *incx;
- X(ix) -= temp * A(i,j);
-/* L30: */
- }
- }
- jx -= *incx;
-/* L40: */
- }
- }
- } else {
- if (*incx == 1) {
- for (j = 1; j <= *n; ++j) {
- if (X(j) != 0.f) {
- if (nounit) {
- X(j) /= A(j,j);
- }
- temp = X(j);
- for (i = j + 1; i <= *n; ++i) {
- X(i) -= temp * A(i,j);
-/* L50: */
- }
- }
-/* L60: */
- }
- } else {
- jx = kx;
- for (j = 1; j <= *n; ++j) {
- if (X(jx) != 0.f) {
- if (nounit) {
- X(jx) /= A(j,j);
- }
- temp = X(jx);
- ix = jx;
- for (i = j + 1; i <= *n; ++i) {
- ix += *incx;
- X(ix) -= temp * A(i,j);
-/* L70: */
- }
- }
- jx += *incx;
-/* L80: */
- }
- }
- }
- } else {
-
-/* Form x := inv( A' )*x. */
-
- if (lsame_(uplo, "U")) {
- if (*incx == 1) {
- for (j = 1; j <= *n; ++j) {
- temp = X(j);
- for (i = 1; i <= j-1; ++i) {
- temp -= A(i,j) * X(i);
-/* L90: */
- }
- if (nounit) {
- temp /= A(j,j);
- }
- X(j) = temp;
-/* L100: */
- }
- } else {
- jx = kx;
- for (j = 1; j <= *n; ++j) {
- temp = X(jx);
- ix = kx;
- for (i = 1; i <= j-1; ++i) {
- temp -= A(i,j) * X(ix);
- ix += *incx;
-/* L110: */
- }
- if (nounit) {
- temp /= A(j,j);
- }
- X(jx) = temp;
- jx += *incx;
-/* L120: */
- }
- }
- } else {
- if (*incx == 1) {
- for (j = *n; j >= 1; --j) {
- temp = X(j);
- for (i = *n; i >= j+1; --i) {
- temp -= A(i,j) * X(i);
-/* L130: */
- }
- if (nounit) {
- temp /= A(j,j);
- }
- X(j) = temp;
-/* L140: */
- }
- } else {
- kx += (*n - 1) * *incx;
- jx = kx;
- for (j = *n; j >= 1; --j) {
- temp = X(jx);
- ix = kx;
- for (i = *n; i >= j+1; --i) {
- temp -= A(i,j) * X(ix);
- ix -= *incx;
-/* L150: */
- }
- if (nounit) {
- temp /= A(j,j);
- }
- X(jx) = temp;
- jx -= *incx;
-/* L160: */
- }
- }
- }
- }
-
- return 0;
-
-/* End of STRSV . */
-
-} /* strsv_ */
-
diff --git a/intern/opennl/superlu/superlu_timer.c b/intern/opennl/superlu/superlu_timer.c
deleted file mode 100644
index abcafe8fa1f..00000000000
--- a/intern/opennl/superlu/superlu_timer.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/** \file opennl/superlu/superlu_timer.c
- * \ingroup opennl
- */
-/*
- * Purpose
- * =======
- * Returns the time in seconds used by the process.
- *
- * Note: the timer function call is machine dependent. Use conditional
- * compilation to choose the appropriate function.
- *
- */
-
-/* We want this flag, safer than putting in build system */
-#define NO_TIMER
-
-double SuperLU_timer_ ();
-
-#ifdef SUN
-/*
- * It uses the system call gethrtime(3C), which is accurate to
- * nanoseconds.
-*/
-#include <sys/time.h>
-
-double SuperLU_timer_() {
- return ( (double)gethrtime() / 1e9 );
-}
-
-#else
-
-#ifndef NO_TIMER
-#include <sys/types.h>
-#include <sys/times.h>
-#include <time.h>
-#include <sys/time.h>
-#endif
-
-#ifndef CLK_TCK
-#define CLK_TCK 60
-#endif
-double SuperLU_timer_(void);
-
-double SuperLU_timer_(void)
-{
-#ifdef NO_TIMER
- /* no sys/times.h on WIN32 */
- double tmp;
- tmp = 0.0;
-#else
- struct tms use;
- double tmp;
- times(&use);
- tmp = use.tms_utime;
- tmp += use.tms_stime;
-#endif
- return (double)(tmp) / CLK_TCK;
-}
-
-#endif
-
diff --git a/intern/opennl/superlu/supermatrix.h b/intern/opennl/superlu/supermatrix.h
deleted file mode 100644
index 74dfde4df7c..00000000000
--- a/intern/opennl/superlu/supermatrix.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/** \file opennl/superlu/supermatrix.h
- * \ingroup opennl
- */
-#ifndef __SUPERLU_SUPERMATRIX /* allow multiple inclusions */
-#define __SUPERLU_SUPERMATRIX
-
-/********************************************
- * The matrix types are defined as follows. *
- ********************************************/
-typedef enum {
- SLU_NC, /* column-wise, no supernode */
- SLU_NR, /* row-wize, no supernode */
- SLU_SC, /* column-wise, supernode */
- SLU_SR, /* row-wise, supernode */
- SLU_NCP, /* column-wise, column-permuted, no supernode
- (The consecutive columns of nonzeros, after permutation,
- may not be stored contiguously.) */
- SLU_DN /* Fortran style column-wise storage for dense matrix */
-} Stype_t;
-
-typedef enum {
- SLU_S, /* single */
- SLU_D, /* double */
- SLU_C, /* single complex */
- SLU_Z /* double complex */
-} Dtype_t;
-
-typedef enum {
- SLU_GE, /* general */
- SLU_TRLU, /* lower triangular, unit diagonal */
- SLU_TRUU, /* upper triangular, unit diagonal */
- SLU_TRL, /* lower triangular */
- SLU_TRU, /* upper triangular */
- SLU_SYL, /* symmetric, store lower half */
- SLU_SYU, /* symmetric, store upper half */
- SLU_HEL, /* Hermitian, store lower half */
- SLU_HEU /* Hermitian, store upper half */
-} Mtype_t;
-
-typedef struct {
- Stype_t Stype; /* Storage type: interprets the storage structure
- pointed to by *Store. */
- Dtype_t Dtype; /* Data type. */
- Mtype_t Mtype; /* Matrix type: describes the mathematical property of
- the matrix. */
- int_t nrow; /* number of rows */
- int_t ncol; /* number of columns */
- void *Store; /* pointer to the actual storage of the matrix */
-} SuperMatrix;
-
-/***********************************************
- * The storage schemes are defined as follows. *
- ***********************************************/
-
-/* Stype == NC (Also known as Harwell-Boeing sparse matrix format) */
-typedef struct {
- int_t nnz; /* number of nonzeros in the matrix */
- void *nzval; /* pointer to array of nonzero values, packed by column */
- int_t *rowind; /* pointer to array of row indices of the nonzeros */
- int_t *colptr; /* pointer to array of beginning of columns in nzval[]
- and rowind[] */
- /* Note:
- Zero-based indexing is used;
- colptr[] has ncol+1 entries, the last one pointing
- beyond the last column, so that colptr[ncol] = nnz. */
-} NCformat;
-
-/* Stype == NR (Also known as row compressed storage (RCS). */
-typedef struct {
- int_t nnz; /* number of nonzeros in the matrix */
- void *nzval; /* pointer to array of nonzero values, packed by row */
- int_t *colind; /* pointer to array of column indices of the nonzeros */
- int_t *rowptr; /* pointer to array of beginning of rows in nzval[]
- and colind[] */
- /* Note:
- Zero-based indexing is used;
- nzval[] and colind[] are of the same length, nnz;
- rowptr[] has nrow+1 entries, the last one pointing
- beyond the last column, so that rowptr[nrow] = nnz. */
-} NRformat;
-
-/* Stype == SC */
-typedef struct {
- int_t nnz; /* number of nonzeros in the matrix */
- int_t nsuper; /* number of supernodes, minus 1 */
- void *nzval; /* pointer to array of nonzero values, packed by column */
- int_t *nzval_colptr;/* pointer to array of beginning of columns in nzval[] */
- int_t *rowind; /* pointer to array of compressed row indices of
- rectangular supernodes */
- int_t *rowind_colptr;/* pointer to array of beginning of columns in rowind[] */
- int_t *col_to_sup; /* col_to_sup[j] is the supernode number to which column
- j belongs; mapping from column to supernode number. */
- int_t *sup_to_col; /* sup_to_col[s] points to the start of the s-th
- supernode; mapping from supernode number to column.
- e.g.: col_to_sup: 0 1 2 2 3 3 3 4 4 4 4 4 4 (ncol=12)
- sup_to_col: 0 1 2 4 7 12 (nsuper=4) */
- /* Note:
- Zero-based indexing is used;
- nzval_colptr[], rowind_colptr[], col_to_sup and
- sup_to_col[] have ncol+1 entries, the last one
- pointing beyond the last column.
- For col_to_sup[], only the first ncol entries are
- defined. For sup_to_col[], only the first nsuper+2
- entries are defined. */
-} SCformat;
-
-/* Stype == NCP */
-typedef struct {
- int_t nnz; /* number of nonzeros in the matrix */
- void *nzval; /* pointer to array of nonzero values, packed by column */
- int_t *rowind;/* pointer to array of row indices of the nonzeros */
- /* Note: nzval[]/rowind[] always have the same length */
- int_t *colbeg;/* colbeg[j] points to the beginning of column j in nzval[]
- and rowind[] */
- int_t *colend;/* colend[j] points to one past the last element of column
- j in nzval[] and rowind[] */
- /* Note:
- Zero-based indexing is used;
- The consecutive columns of the nonzeros may not be
- contiguous in storage, because the matrix has been
- postmultiplied by a column permutation matrix. */
-} NCPformat;
-
-/* Stype == DN */
-typedef struct {
- int_t lda; /* leading dimension */
- void *nzval; /* array of size lda*ncol to represent a dense matrix */
-} DNformat;
-
-
-
-/*********************************************************
- * Macros used for easy access of sparse matrix entries. *
- *********************************************************/
-#define L_SUB_START(col) ( Lstore->rowind_colptr[col] )
-#define L_SUB(ptr) ( Lstore->rowind[ptr] )
-#define L_NZ_START(col) ( Lstore->nzval_colptr[col] )
-#define L_FST_SUPC(superno) ( Lstore->sup_to_col[superno] )
-#define U_NZ_START(col) ( Ustore->colptr[col] )
-#define U_SUB(ptr) ( Ustore->rowind[ptr] )
-
-
-#endif /* __SUPERLU_SUPERMATRIX */
diff --git a/intern/opennl/superlu/sutil.c b/intern/opennl/superlu/sutil.c
deleted file mode 100644
index 52728e47f56..00000000000
--- a/intern/opennl/superlu/sutil.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/** \file opennl/superlu/sutil.c
- * \ingroup opennl
- */
-
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include <math.h>
-#include "ssp_defs.h"
-
-/* prototypes */
-void sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu);
-void scheck_tempv(int n, double *tempv);
-void sPrintPerf(SuperMatrix *, SuperMatrix *, mem_usage_t *,double , double ,
- double *, double *, char *, SuperLUStat_t *);
-int print_double_vec(char *what, int n, double *vec);
-/* ********** */
-
-void
-sCreate_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz,
- double *nzval, int *rowind, int *colptr,
- Stype_t stype, Dtype_t dtype, Mtype_t mtype)
-{
- NCformat *Astore;
-
- A->Stype = stype;
- A->Dtype = dtype;
- A->Mtype = mtype;
- A->nrow = m;
- A->ncol = n;
- A->Store = (void *) SUPERLU_MALLOC( sizeof(NCformat) );
- if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store");
- Astore = A->Store;
- Astore->nnz = nnz;
- Astore->nzval = nzval;
- Astore->rowind = rowind;
- Astore->colptr = colptr;
-}
-
-void
-sCreate_CompRow_Matrix(SuperMatrix *A, int m, int n, int nnz,
- double *nzval, int *colind, int *rowptr,
- Stype_t stype, Dtype_t dtype, Mtype_t mtype)
-{
- NRformat *Astore;
-
- A->Stype = stype;
- A->Dtype = dtype;
- A->Mtype = mtype;
- A->nrow = m;
- A->ncol = n;
- A->Store = (void *) SUPERLU_MALLOC( sizeof(NRformat) );
- if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store");
- Astore = A->Store;
- Astore->nnz = nnz;
- Astore->nzval = nzval;
- Astore->colind = colind;
- Astore->rowptr = rowptr;
-}
-
-/* Copy matrix A into matrix B. */
-void
-sCopy_CompCol_Matrix(SuperMatrix *A, SuperMatrix *B)
-{
- NCformat *Astore, *Bstore;
- int ncol, nnz, i;
-
- B->Stype = A->Stype;
- B->Dtype = A->Dtype;
- B->Mtype = A->Mtype;
- B->nrow = A->nrow;;
- B->ncol = ncol = A->ncol;
- Astore = (NCformat *) A->Store;
- Bstore = (NCformat *) B->Store;
- Bstore->nnz = nnz = Astore->nnz;
- for (i = 0; i < nnz; ++i)
- ((double *)Bstore->nzval)[i] = ((double *)Astore->nzval)[i];
- for (i = 0; i < nnz; ++i) Bstore->rowind[i] = Astore->rowind[i];
- for (i = 0; i <= ncol; ++i) Bstore->colptr[i] = Astore->colptr[i];
-}
-
-
-void
-sCreate_Dense_Matrix(SuperMatrix *X, int m, int n, double *x, int ldx,
- Stype_t stype, Dtype_t dtype, Mtype_t mtype)
-{
- DNformat *Xstore;
-
- X->Stype = stype;
- X->Dtype = dtype;
- X->Mtype = mtype;
- X->nrow = m;
- X->ncol = n;
- X->Store = (void *) SUPERLU_MALLOC( sizeof(DNformat) );
- if ( !(X->Store) ) ABORT("SUPERLU_MALLOC fails for X->Store");
- Xstore = (DNformat *) X->Store;
- Xstore->lda = ldx;
- Xstore->nzval = (double *) x;
-}
-
-void
-sCopy_Dense_Matrix(int M, int N, double *X, int ldx,
- double *Y, int ldy)
-{
-/*
- *
- * Purpose
- * =======
- *
- * Copies a two-dimensional matrix X to another matrix Y.
- */
- int i, j;
-
- for (j = 0; j < N; ++j)
- for (i = 0; i < M; ++i)
- Y[i + j*ldy] = X[i + j*ldx];
-}
-
-void
-sCreate_SuperNode_Matrix(SuperMatrix *L, int m, int n, int nnz,
- double *nzval, int *nzval_colptr, int *rowind,
- int *rowind_colptr, int *col_to_sup, int *sup_to_col,
- Stype_t stype, Dtype_t dtype, Mtype_t mtype)
-{
- SCformat *Lstore;
-
- L->Stype = stype;
- L->Dtype = dtype;
- L->Mtype = mtype;
- L->nrow = m;
- L->ncol = n;
- L->Store = (void *) SUPERLU_MALLOC( sizeof(SCformat) );
- if ( !(L->Store) ) ABORT("SUPERLU_MALLOC fails for L->Store");
- Lstore = L->Store;
- Lstore->nnz = nnz;
- Lstore->nsuper = col_to_sup[n];
- Lstore->nzval = nzval;
- Lstore->nzval_colptr = nzval_colptr;
- Lstore->rowind = rowind;
- Lstore->rowind_colptr = rowind_colptr;
- Lstore->col_to_sup = col_to_sup;
- Lstore->sup_to_col = sup_to_col;
-
-}
-
-
-/*
- * Convert a row compressed storage into a column compressed storage.
- */
-void
-sCompRow_to_CompCol(int m, int n, int nnz,
- double *a, int *colind, int *rowptr,
- double **at, int **rowind, int **colptr)
-{
- register int i, j, col, relpos;
- int *marker;
-
- /* Allocate storage for another copy of the matrix. */
- *at = (double *) doubleMalloc(nnz);
- *rowind = (int *) intMalloc(nnz);
- *colptr = (int *) intMalloc(n+1);
- marker = (int *) intCalloc(n);
-
- /* Get counts of each column of A, and set up column pointers */
- for (i = 0; i < m; ++i)
- for (j = rowptr[i]; j < rowptr[i+1]; ++j) ++marker[colind[j]];
- (*colptr)[0] = 0;
- for (j = 0; j < n; ++j) {
- (*colptr)[j+1] = (*colptr)[j] + marker[j];
- marker[j] = (*colptr)[j];
- }
-
- /* Transfer the matrix into the compressed column storage. */
- for (i = 0; i < m; ++i) {
- for (j = rowptr[i]; j < rowptr[i+1]; ++j) {
- col = colind[j];
- relpos = marker[col];
- (*rowind)[relpos] = i;
- (*at)[relpos] = a[j];
- ++marker[col];
- }
- }
-
- SUPERLU_FREE(marker);
-}
-
-
-void
-sPrint_CompCol_Matrix(char *what, SuperMatrix *A)
-{
- NCformat *Astore;
- register int i,n;
- double *dp;
-
- printf("\nCompCol matrix %s:\n", what);
- printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype);
- n = A->ncol;
- Astore = (NCformat *) A->Store;
- dp = (double *) Astore->nzval;
- printf("nrow %d, ncol %d, nnz %d\n", A->nrow,A->ncol,Astore->nnz);
- printf("nzval: ");
- for (i = 0; i < Astore->colptr[n]; ++i) printf("%f ", dp[i]);
- printf("\nrowind: ");
- for (i = 0; i < Astore->colptr[n]; ++i) printf("%d ", Astore->rowind[i]);
- printf("\ncolptr: ");
- for (i = 0; i <= n; ++i) printf("%d ", Astore->colptr[i]);
- printf("\n");
- fflush(stdout);
-}
-
-void
-sPrint_SuperNode_Matrix(char *what, SuperMatrix *A)
-{
- SCformat *Astore;
- register int i, j, k, c, d, n, nsup;
- double *dp;
- int *col_to_sup, *sup_to_col, *rowind, *rowind_colptr;
-
- printf("\nSuperNode matrix %s:\n", what);
- printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype);
- n = A->ncol;
- Astore = (SCformat *) A->Store;
- dp = (double *) Astore->nzval;
- col_to_sup = Astore->col_to_sup;
- sup_to_col = Astore->sup_to_col;
- rowind_colptr = Astore->rowind_colptr;
- rowind = Astore->rowind;
- printf("nrow %d, ncol %d, nnz %d, nsuper %d\n",
- A->nrow,A->ncol,Astore->nnz,Astore->nsuper);
- printf("nzval:\n");
- for (k = 0; k <= Astore->nsuper; ++k) {
- c = sup_to_col[k];
- nsup = sup_to_col[k+1] - c;
- for (j = c; j < c + nsup; ++j) {
- d = Astore->nzval_colptr[j];
- for (i = rowind_colptr[c]; i < rowind_colptr[c+1]; ++i) {
- printf("%d\t%d\t%e\n", rowind[i], j, dp[d++]);
- }
- }
- }
-#if 0
- for (i = 0; i < Astore->nzval_colptr[n]; ++i) printf("%f ", dp[i]);
-#endif
- printf("\nnzval_colptr: ");
- for (i = 0; i <= n; ++i) printf("%d ", Astore->nzval_colptr[i]);
- printf("\nrowind: ");
- for (i = 0; i < Astore->rowind_colptr[n]; ++i)
- printf("%d ", Astore->rowind[i]);
- printf("\nrowind_colptr: ");
- for (i = 0; i <= n; ++i) printf("%d ", Astore->rowind_colptr[i]);
- printf("\ncol_to_sup: ");
- for (i = 0; i < n; ++i) printf("%d ", col_to_sup[i]);
- printf("\nsup_to_col: ");
- for (i = 0; i <= Astore->nsuper+1; ++i)
- printf("%d ", sup_to_col[i]);
- printf("\n");
- fflush(stdout);
-}
-
-void
-sPrint_Dense_Matrix(char *what, SuperMatrix *A)
-{
- DNformat *Astore;
- register int i;
- double *dp;
-
- printf("\nDense matrix %s:\n", what);
- printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype);
- Astore = (DNformat *) A->Store;
- dp = (double *) Astore->nzval;
- printf("nrow %d, ncol %d, lda %d\n", A->nrow,A->ncol,Astore->lda);
- printf("\nnzval: ");
- for (i = 0; i < A->nrow; ++i) printf("%f ", dp[i]);
- printf("\n");
- fflush(stdout);
-}
-
-/*
- * Diagnostic print of column "jcol" in the U/L factor.
- */
-void
-sprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu)
-{
- int i, k, fsupc;
- int *xsup, *supno;
- int *xlsub, *lsub;
- double *lusup;
- int *xlusup;
- double *ucol;
- int *usub, *xusub;
-
- xsup = Glu->xsup;
- supno = Glu->supno;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- lusup = Glu->lusup;
- xlusup = Glu->xlusup;
- ucol = Glu->ucol;
- usub = Glu->usub;
- xusub = Glu->xusub;
-
- printf("%s", msg);
- printf("col %d: pivrow %d, supno %d, xprune %d\n",
- jcol, pivrow, supno[jcol], xprune[jcol]);
-
- printf("\tU-col:\n");
- for (i = xusub[jcol]; i < xusub[jcol+1]; i++)
- printf("\t%d%10.4f\n", usub[i], ucol[i]);
- printf("\tL-col in rectangular snode:\n");
- fsupc = xsup[supno[jcol]]; /* first col of the snode */
- i = xlsub[fsupc];
- k = xlusup[jcol];
- while ( i < xlsub[fsupc+1] && k < xlusup[jcol+1] ) {
- printf("\t%d\t%10.4f\n", lsub[i], lusup[k]);
- i++; k++;
- }
- fflush(stdout);
-}
-
-
-/*
- * Check whether tempv[] == 0. This should be true before and after
- * calling any numeric routines, i.e., "panel_bmod" and "column_bmod".
- */
-void scheck_tempv(int n, double *tempv)
-{
- int i;
-
- for (i = 0; i < n; i++) {
- if (tempv[i] != 0.0)
- {
- fprintf(stderr,"tempv[%d] = %f\n", i,tempv[i]);
- ABORT("scheck_tempv");
- }
- }
-}
-
-
-void
-sGenXtrue(int n, int nrhs, double *x, int ldx)
-{
- int i, j;
- for (j = 0; j < nrhs; ++j)
- for (i = 0; i < n; ++i) {
- x[i + j*ldx] = 1.0;/* + (double)(i+1.)/n;*/
- }
-}
-
-/*
- * Let rhs[i] = sum of i-th row of A, so the solution vector is all 1's
- */
-void
-sFillRHS(trans_t trans, int nrhs, double *x, int ldx,
- SuperMatrix *A, SuperMatrix *B)
-{
- DNformat *Bstore;
- double *rhs;
- double one = 1.0;
- double zero = 0.0;
- int ldc;
- char transc[1];
-
- Bstore = B->Store;
- rhs = Bstore->nzval;
- ldc = Bstore->lda;
-
- if ( trans == NOTRANS ) *(unsigned char *)transc = 'N';
- else *(unsigned char *)transc = 'T';
-
- sp_sgemm(transc, nrhs, one, A,
- x, ldx, zero, rhs, ldc);
-
-}
-
-/*
- * Fills a double precision array with a given value.
- */
-void
-sfill(double *a, int alen, double dval)
-{
- register int i;
- for (i = 0; i < alen; i++) a[i] = dval;
-}
-
-
-
-/*
- * Check the inf-norm of the error vector
- */
-void sinf_norm_error(int nrhs, SuperMatrix *X, double *xtrue)
-{
- DNformat *Xstore;
- double err, xnorm;
- double *Xmat, *soln_work;
- int i, j;
-
- Xstore = X->Store;
- Xmat = Xstore->nzval;
-
- for (j = 0; j < nrhs; j++) {
- soln_work = &Xmat[j*Xstore->lda];
- err = xnorm = 0.0;
- for (i = 0; i < X->nrow; i++) {
- err = SUPERLU_MAX(err, fabs(soln_work[i] - xtrue[i]));
- xnorm = SUPERLU_MAX(xnorm, fabs(soln_work[i]));
- }
- err = err / xnorm;
- printf("||X - Xtrue||/||X|| = %e\n", err);
- }
-}
-
-
-
-/* Print performance of the code. */
-void
-sPrintPerf(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage,
- double rpg, double rcond, double *ferr,
- double *berr, char *equed, SuperLUStat_t *stat)
-{
- SCformat *Lstore;
- NCformat *Ustore;
- double *utime;
- flops_t *ops;
-
- utime = stat->utime;
- ops = stat->ops;
-
- if ( utime[FACT] != 0. )
- printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT],
- ops[FACT]*1e-6/utime[FACT]);
- printf("Identify relaxed snodes = %8.2f\n", utime[RELAX]);
- if ( utime[SOLVE] != 0. )
- printf("Solve flops = %.0f, Mflops = %8.2f\n", ops[SOLVE],
- ops[SOLVE]*1e-6/utime[SOLVE]);
-
- Lstore = (SCformat *) L->Store;
- Ustore = (NCformat *) U->Store;
- printf("\tNo of nonzeros in factor L = %d\n", Lstore->nnz);
- printf("\tNo of nonzeros in factor U = %d\n", Ustore->nnz);
- printf("\tNo of nonzeros in L+U = %d\n", Lstore->nnz + Ustore->nnz);
-
- printf("L\\U MB %.3f\ttotal MB needed %.3f\texpansions %d\n",
- mem_usage->for_lu/1e6, mem_usage->total_needed/1e6,
- mem_usage->expansions);
-
- printf("\tFactor\tMflops\tSolve\tMflops\tEtree\tEquil\tRcond\tRefine\n");
- printf("PERF:%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f\n",
- utime[FACT], ops[FACT]*1e-6/utime[FACT],
- utime[SOLVE], ops[SOLVE]*1e-6/utime[SOLVE],
- utime[ETREE], utime[EQUIL], utime[RCOND], utime[REFINE]);
-
- printf("\tRpg\t\tRcond\t\tFerr\t\tBerr\t\tEquil?\n");
- printf("NUM:\t%e\t%e\t%e\t%e\t%s\n",
- rpg, rcond, ferr[0], berr[0], equed);
-
-}
-
-
-
-
-int print_double_vec(char *what, int n, double *vec)
-{
- int i;
- printf("%s: n %d\n", what, n);
- for (i = 0; i < n; ++i) printf("%d\t%f\n", i, vec[i]);
- return 0;
-}
-
diff --git a/intern/opennl/superlu/util.c b/intern/opennl/superlu/util.c
deleted file mode 100644
index 96f404d886b..00000000000
--- a/intern/opennl/superlu/util.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/** \file opennl/superlu/util.c
- * \ingroup opennl
- */
-/*
- * -- SuperLU routine (version 3.0) --
- * Univ. of California Berkeley, Xerox Palo Alto Research Center,
- * and Lawrence Berkeley National Lab.
- * October 15, 2003
- *
- */
-/*
- Copyright (c) 1994 by Xerox Corporation. All rights reserved.
-
- THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
- EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-
- Permission is hereby granted to use or copy this program for any
- purpose, provided the above notices are retained on all copies.
- Permission to modify the code and to distribute modified code is
- granted, provided the above notices are retained, and a notice that
- the code was modified is included with the above copyright notice.
-*/
-
-#include <math.h>
-#include "ssp_defs.h"
-#include "util.h"
-
-/* prototypes */
-flops_t LUFactFlops(SuperLUStat_t *stat);
-flops_t LUSolveFlops(SuperLUStat_t *stat);
-double SpaSize(int n, int np, double sum_npw);
-double DenseSize(int n, double sum_nw);
-
-/*
- * Global statistics variale
- */
-
-void superlu_abort_and_exit(char* msg)
-{
- fprintf(stderr, "%s", msg);
- exit (-1);
-}
-
-/*
- * Set the default values for the options argument.
- */
-void set_default_options(superlu_options_t *options)
-{
- options->Fact = DOFACT;
- options->Equil = YES;
- options->ColPerm = COLAMD;
- options->DiagPivotThresh = 1.0;
- options->Trans = NOTRANS;
- options->IterRefine = NOREFINE;
- options->SymmetricMode = NO;
- options->PivotGrowth = NO;
- options->ConditionNumber = NO;
- options->PrintStat = YES;
-}
-
-/* Deallocate the structure pointing to the actual storage of the matrix. */
-void
-Destroy_SuperMatrix_Store(SuperMatrix *A)
-{
- SUPERLU_FREE ( A->Store );
-}
-
-void
-Destroy_CompCol_Matrix(SuperMatrix *A)
-{
- SUPERLU_FREE( ((NCformat *)A->Store)->rowind );
- SUPERLU_FREE( ((NCformat *)A->Store)->colptr );
- SUPERLU_FREE( ((NCformat *)A->Store)->nzval );
- SUPERLU_FREE( A->Store );
-}
-
-void
-Destroy_CompRow_Matrix(SuperMatrix *A)
-{
- SUPERLU_FREE( ((NRformat *)A->Store)->colind );
- SUPERLU_FREE( ((NRformat *)A->Store)->rowptr );
- SUPERLU_FREE( ((NRformat *)A->Store)->nzval );
- SUPERLU_FREE( A->Store );
-}
-
-void
-Destroy_SuperNode_Matrix(SuperMatrix *A)
-{
- SUPERLU_FREE ( ((SCformat *)A->Store)->rowind );
- SUPERLU_FREE ( ((SCformat *)A->Store)->rowind_colptr );
- SUPERLU_FREE ( ((SCformat *)A->Store)->nzval );
- SUPERLU_FREE ( ((SCformat *)A->Store)->nzval_colptr );
- SUPERLU_FREE ( ((SCformat *)A->Store)->col_to_sup );
- SUPERLU_FREE ( ((SCformat *)A->Store)->sup_to_col );
- SUPERLU_FREE ( A->Store );
-}
-
-/* A is of type Stype==NCP */
-void
-Destroy_CompCol_Permuted(SuperMatrix *A)
-{
- SUPERLU_FREE ( ((NCPformat *)A->Store)->colbeg );
- SUPERLU_FREE ( ((NCPformat *)A->Store)->colend );
- SUPERLU_FREE ( A->Store );
-}
-
-/* A is of type Stype==DN */
-void
-Destroy_Dense_Matrix(SuperMatrix *A)
-{
- DNformat* Astore = A->Store;
- SUPERLU_FREE (Astore->nzval);
- SUPERLU_FREE ( A->Store );
-}
-
-/*
- * Reset repfnz[] for the current column
- */
-void
-resetrep_col (const int nseg, const int *segrep, int *repfnz)
-{
- int i, irep;
-
- for (i = 0; i < nseg; i++) {
- irep = segrep[i];
- repfnz[irep] = EMPTY;
- }
-}
-
-
-/*
- * Count the total number of nonzeros in factors L and U, and in the
- * symmetrically reduced L.
- */
-void
-countnz(const int n, int *xprune, int *nnzL, int *nnzU, GlobalLU_t *Glu)
-{
- int nsuper, fsupc, i, j;
- int nnzL0, jlen, irep;
- int *xsup, *xlsub;
-
- xsup = Glu->xsup;
- xlsub = Glu->xlsub;
- *nnzL = 0;
- *nnzU = (Glu->xusub)[n];
- nnzL0 = 0;
- nsuper = (Glu->supno)[n];
-
- if ( n <= 0 ) return;
-
- /*
- * For each supernode
- */
- for (i = 0; i <= nsuper; i++) {
- fsupc = xsup[i];
- jlen = xlsub[fsupc+1] - xlsub[fsupc];
-
- for (j = fsupc; j < xsup[i+1]; j++) {
- *nnzL += jlen;
- *nnzU += j - fsupc + 1;
- jlen--;
- }
- irep = xsup[i+1] - 1;
- nnzL0 += xprune[irep] - xlsub[irep];
- }
-
- /* printf("\tNo of nonzeros in symm-reduced L = %d\n", nnzL0);*/
-}
-
-
-
-/*
- * Fix up the data storage lsub for L-subscripts. It removes the subscript
- * sets for structural pruning, and applies permuation to the remaining
- * subscripts.
- */
-void
-fixupL(const int n, const int *perm_r, GlobalLU_t *Glu)
-{
- register int nsuper, fsupc, nextl, i, j, k, jstrt;
- int *xsup, *lsub, *xlsub;
-
- if ( n <= 1 ) return;
-
- xsup = Glu->xsup;
- lsub = Glu->lsub;
- xlsub = Glu->xlsub;
- nextl = 0;
- nsuper = (Glu->supno)[n];
-
- /*
- * For each supernode ...
- */
- for (i = 0; i <= nsuper; i++) {
- fsupc = xsup[i];
- jstrt = xlsub[fsupc];
- xlsub[fsupc] = nextl;
- for (j = jstrt; j < xlsub[fsupc+1]; j++) {
- lsub[nextl] = perm_r[lsub[j]]; /* Now indexed into P*A */
- nextl++;
- }
- for (k = fsupc+1; k < xsup[i+1]; k++)
- xlsub[k] = nextl; /* Other columns in supernode i */
-
- }
-
- xlsub[n] = nextl;
-}
-
-
-/*
- * Diagnostic print of segment info after panel_dfs().
- */
-void print_panel_seg(int n, int w, int jcol, int nseg,
- int *segrep, int *repfnz)
-{
- int j, k;
-
- for (j = jcol; j < jcol+w; j++) {
- printf("\tcol %d:\n", j);
- for (k = 0; k < nseg; k++)
- printf("\t\tseg %d, segrep %d, repfnz %d\n", k,
- segrep[k], repfnz[(j-jcol)*n + segrep[k]]);
- }
-
-}
-
-
-void
-StatInit(SuperLUStat_t *stat)
-{
- register int i, w, panel_size, relax;
-
- panel_size = sp_ienv(1);
- relax = sp_ienv(2);
- w = SUPERLU_MAX(panel_size, relax);
- stat->panel_histo = intCalloc(w+1);
- stat->utime = (double *) SUPERLU_MALLOC(NPHASES * sizeof(double));
- if (!stat->utime) ABORT("SUPERLU_MALLOC fails for stat->utime");
- stat->ops = (flops_t *) SUPERLU_MALLOC(NPHASES * sizeof(flops_t));
- if (!stat->ops) ABORT("SUPERLU_MALLOC fails for stat->ops");
- for (i = 0; i < NPHASES; ++i) {
- stat->utime[i] = 0.;
- stat->ops[i] = 0.;
- }
-}
-
-
-void
-StatPrint(SuperLUStat_t *stat)
-{
- double *utime;
- flops_t *ops;
-
- utime = stat->utime;
- ops = stat->ops;
- printf("Factor time = %8.2f\n", utime[FACT]);
- if ( utime[FACT] != 0.0 )
- printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT],
- ops[FACT]*1e-6/utime[FACT]);
-
- printf("Solve time = %8.2f\n", utime[SOLVE]);
- if ( utime[SOLVE] != 0.0 )
- printf("Solve flops = %e\tMflops = %8.2f\n", ops[SOLVE],
- ops[SOLVE]*1e-6/utime[SOLVE]);
-
-}
-
-
-void
-StatFree(SuperLUStat_t *stat)
-{
- SUPERLU_FREE(stat->panel_histo);
- SUPERLU_FREE(stat->utime);
- SUPERLU_FREE(stat->ops);
-}
-
-
-flops_t
-LUFactFlops(SuperLUStat_t *stat)
-{
- return (stat->ops[FACT]);
-}
-
-flops_t
-LUSolveFlops(SuperLUStat_t *stat)
-{
- return (stat->ops[SOLVE]);
-}
-
-
-
-
-
-/*
- * Fills an integer array with a given value.
- */
-void ifill(int *a, int alen, int ival)
-{
- register int i;
- for (i = 0; i < alen; i++) a[i] = ival;
-}
-
-
-
-/*
- * Get the statistics of the supernodes
- */
-#define NBUCKS 10
-static int max_sup_size;
-
-void super_stats(int nsuper, int *xsup)
-{
- register int nsup1 = 0;
- int i, isize, whichb, bl, bh;
- int bucket[NBUCKS];
-
- max_sup_size = 0;
-
- for (i = 0; i <= nsuper; i++) {
- isize = xsup[i+1] - xsup[i];
- if ( isize == 1 ) nsup1++;
- if ( max_sup_size < isize ) max_sup_size = isize;
- }
-
- printf(" Supernode statistics:\n\tno of super = %d\n", nsuper+1);
- printf("\tmax supernode size = %d\n", max_sup_size);
- printf("\tno of size 1 supernodes = %d\n", nsup1);
-
- /* Histogram of the supernode sizes */
- ifill (bucket, NBUCKS, 0);
-
- for (i = 0; i <= nsuper; i++) {
- isize = xsup[i+1] - xsup[i];
- whichb = (double) isize / max_sup_size * NBUCKS;
- if (whichb >= NBUCKS) whichb = NBUCKS - 1;
- bucket[whichb]++;
- }
-
- printf("\tHistogram of supernode sizes:\n");
- for (i = 0; i < NBUCKS; i++) {
- bl = (double) i * max_sup_size / NBUCKS;
- bh = (double) (i+1) * max_sup_size / NBUCKS;
- printf("\tsnode: %d-%d\t\t%d\n", bl+1, bh, bucket[i]);
- }
-
-}
-
-
-double SpaSize(int n, int np, double sum_npw)
-{
- return (sum_npw*8 + np*8 + n*4)/1024.;
-}
-
-double DenseSize(int n, double sum_nw)
-{
- return (sum_nw*8 + n*8)/1024.;;
-}
-
-
-
-/*
- * Check whether repfnz[] == EMPTY after reset.
- */
-void check_repfnz(int n, int w, int jcol, int *repfnz)
-{
- int jj, k;
-
- for (jj = jcol; jj < jcol+w; jj++)
- for (k = 0; k < n; k++)
- if ( repfnz[(jj-jcol)*n + k] != EMPTY ) {
- fprintf(stderr, "col %d, repfnz_col[%d] = %d\n", jj,
- k, repfnz[(jj-jcol)*n + k]);
- ABORT("check_repfnz");
- }
-}
-
-
-/* Print a summary of the testing results. */
-void
-PrintSumm(char *type, int nfail, int nrun, int nerrs)
-{
- if ( nfail > 0 )
- printf("%3s driver: %d out of %d tests failed to pass the threshold\n",
- type, nfail, nrun);
- else
- printf("All tests for %3s driver passed the threshold (%6d tests run)\n", type, nrun);
-
- if ( nerrs > 0 )
- printf("%6d error messages recorded\n", nerrs);
-}
-
-
-int print_int_vec(char *what, int n, int *vec)
-{
- int i;
- printf("%s\n", what);
- for (i = 0; i < n; ++i) printf("%d\t%d\n", i, vec[i]);
- return 0;
-}
diff --git a/intern/opennl/superlu/util.h b/intern/opennl/superlu/util.h
deleted file mode 100644
index da9a8dbe4e3..00000000000
--- a/intern/opennl/superlu/util.h
+++ /dev/null
@@ -1,271 +0,0 @@
-/** \file opennl/superlu/util.h
- * \ingroup opennl
- */
-#ifndef __SUPERLU_UTIL /* allow multiple inclusions */
-#define __SUPERLU_UTIL
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-/*
-#ifndef __STDC__
-#include <malloc.h>
-#endif
-*/
-#include <assert.h>
-
-/***********************************************************************
- * Macros
- ***********************************************************************/
-#define FIRSTCOL_OF_SNODE(i) (xsup[i])
-/* No of marker arrays used in the symbolic factorization,
- each of size n */
-#define NO_MARKER 3
-#define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) )
-
-#ifndef USER_ABORT
-#define USER_ABORT(msg) \
- { fprintf(stderr, "%s", msg); exit (-1); }
-#endif
-
-#define ABORT(err_msg) \
- { char msg[256];\
- sprintf(msg,"%s at line %d in file %s\n",err_msg,__LINE__, __FILE__);\
- USER_ABORT(msg); }
-
-
-#ifndef USER_MALLOC
-#if 1
-#define USER_MALLOC(size) superlu_malloc(size)
-#else
-/* The following may check out some uninitialized data */
-#define USER_MALLOC(size) memset (superlu_malloc(size), '\x0F', size)
-#endif
-#endif
-
-#define SUPERLU_MALLOC(size) USER_MALLOC(size)
-
-#ifndef USER_FREE
-#define USER_FREE(addr) superlu_free(addr)
-#endif
-
-#define SUPERLU_FREE(addr) USER_FREE(addr)
-
-#define CHECK_MALLOC(where) { \
- extern int superlu_malloc_total; \
- printf("%s: malloc_total %d Bytes\n", \
- where, superlu_malloc_total); \
-}
-
-#define SUPERLU_MAX(x, y) ( (x) > (y) ? (x) : (y) )
-#define SUPERLU_MIN(x, y) ( (x) < (y) ? (x) : (y) )
-
-/***********************************************************************
- * Constants
- ***********************************************************************/
-#define EMPTY (-1)
-/*#define NO (-1)*/
-#define FALSE 0
-#define TRUE 1
-
-/***********************************************************************
- * Enumerate types
- ***********************************************************************/
-typedef enum {NO, YES} yes_no_t;
-typedef enum {DOFACT, SamePattern, SamePattern_SameRowPerm, FACTORED} fact_t;
-typedef enum {NOROWPERM, LargeDiag, MY_PERMR} rowperm_t;
-typedef enum {NATURAL, MMD_ATA, MMD_AT_PLUS_A, COLAMD, MY_PERMC}colperm_t;
-typedef enum {NOTRANS, TRANS, CONJ} trans_t;
-typedef enum {NOEQUIL, ROW, COL, BOTH} DiagScale_t;
-typedef enum {NOREFINE, SINGLE=1, SLU_DOUBLE, EXTRA} IterRefine_t;
-typedef enum {LUSUP, UCOL, LSUB, USUB} MemType;
-typedef enum {HEAD, TAIL} stack_end_t;
-typedef enum {SYSTEM, USER} LU_space_t;
-
-/*
- * The following enumerate type is used by the statistics variable
- * to keep track of flop count and time spent at various stages.
- *
- * Note that not all of the fields are disjoint.
- */
-typedef enum {
- COLPERM, /* find a column ordering that minimizes fills */
- RELAX, /* find artificial supernodes */
- ETREE, /* compute column etree */
- EQUIL, /* equilibrate the original matrix */
- FACT, /* perform LU factorization */
- RCOND, /* estimate reciprocal condition number */
- SOLVE, /* forward and back solves */
- REFINE, /* perform iterative refinement */
- SLU_FLOAT, /* time spent in doubleing-point operations */
- TRSV, /* fraction of FACT spent in xTRSV */
- GEMV, /* fraction of FACT spent in xGEMV */
- FERR, /* estimate error bounds after iterative refinement */
- NPHASES /* total number of phases */
-} PhaseType;
-
-
-/***********************************************************************
- * Type definitions
- ***********************************************************************/
-typedef double flops_t;
-typedef unsigned char Logical;
-
-/*
- *-- This contains the options used to control the solve process.
- *
- * Fact (fact_t)
- * Specifies whether or not the factored form of the matrix
- * A is supplied on entry, and if not, how the matrix A should
- * be factorizaed.
- * = DOFACT: The matrix A will be factorized from scratch, and the
- * factors will be stored in L and U.
- * = SamePattern: The matrix A will be factorized assuming
- * that a factorization of a matrix with the same sparsity
- * pattern was performed prior to this one. Therefore, this
- * factorization will reuse column permutation vector
- * ScalePermstruct->perm_c and the column elimination tree
- * LUstruct->etree.
- * = SamePattern_SameRowPerm: The matrix A will be factorized
- * assuming that a factorization of a matrix with the same
- * sparsity pattern and similar numerical values was performed
- * prior to this one. Therefore, this factorization will reuse
- * both row and column scaling factors R and C, and the
- * both row and column permutation vectors perm_r and perm_c,
- * distributed data structure set up from the previous symbolic
- * factorization.
- * = FACTORED: On entry, L, U, perm_r and perm_c contain the
- * factored form of A. If DiagScale is not NOEQUIL, the matrix
- * A has been equilibrated with scaling factors R and C.
- *
- * Equil (yes_no_t)
- * Specifies whether to equilibrate the system (scale A's row and
- * columns to have unit norm).
- *
- * ColPerm (colperm_t)
- * Specifies what type of column permutation to use to reduce fill.
- * = NATURAL: use the natural ordering
- * = MMD_ATA: use minimum degree ordering on structure of A'*A
- * = MMD_AT_PLUS_A: use minimum degree ordering on structure of A'+A
- * = COLAMD: use approximate minimum degree column ordering
- * = MY_PERMC: use the ordering specified in ScalePermstruct->perm_c[]
- *
- * Trans (trans_t)
- * Specifies the form of the system of equations:
- * = NOTRANS: A * X = B (No transpose)
- * = TRANS: A**T * X = B (Transpose)
- * = CONJ: A**H * X = B (Transpose)
- *
- * IterRefine (IterRefine_t)
- * Specifies whether to perform iterative refinement.
- * = NO: no iterative refinement
- * = WorkingPrec: perform iterative refinement in working precision
- * = ExtraPrec: perform iterative refinement in extra precision
- *
- * PrintStat (yes_no_t)
- * Specifies whether to print the solver's statistics.
- *
- * DiagPivotThresh (double, in [0.0, 1.0]) (only for sequential SuperLU)
- * Specifies the threshold used for a diagonal entry to be an
- * acceptable pivot.
- *
- * PivotGrowth (yes_no_t)
- * Specifies whether to compute the reciprocal pivot growth.
- *
- * ConditionNumber (ues_no_t)
- * Specifies whether to compute the reciprocal condition number.
- *
- * RowPerm (rowperm_t) (only for SuperLU_DIST)
- * Specifies whether to permute rows of the original matrix.
- * = NO: not to permute the rows
- * = LargeDiag: make the diagonal large relative to the off-diagonal
- * = MY_PERMR: use the permutation given in ScalePermstruct->perm_r[]
- *
- * ReplaceTinyPivot (yes_no_t) (only for SuperLU_DIST)
- * Specifies whether to replace the tiny diagonals by
- * sqrt(epsilon)*||A|| during LU factorization.
- *
- * SolveInitialized (yes_no_t) (only for SuperLU_DIST)
- * Specifies whether the initialization has been performed to the
- * triangular solve.
- *
- * RefineInitialized (yes_no_t) (only for SuperLU_DIST)
- * Specifies whether the initialization has been performed to the
- * sparse matrix-vector multiplication routine needed in iterative
- * refinement.
- */
-typedef struct {
- fact_t Fact;
- yes_no_t Equil;
- colperm_t ColPerm;
- trans_t Trans;
- IterRefine_t IterRefine;
- yes_no_t PrintStat;
- yes_no_t SymmetricMode;
- double DiagPivotThresh;
- yes_no_t PivotGrowth;
- yes_no_t ConditionNumber;
- rowperm_t RowPerm;
- yes_no_t ReplaceTinyPivot;
- yes_no_t SolveInitialized;
- yes_no_t RefineInitialized;
-} superlu_options_t;
-
-typedef struct {
- int *panel_histo; /* histogram of panel size distribution */
- double *utime; /* running time at various phases */
- flops_t *ops; /* operation count at various phases */
- int TinyPivots; /* number of tiny pivots */
- int RefineSteps; /* number of iterative refinement steps */
-} SuperLUStat_t;
-
-
-/***********************************************************************
- * Prototypes
- ***********************************************************************/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern void Destroy_SuperMatrix_Store(SuperMatrix *);
-extern void Destroy_CompCol_Matrix(SuperMatrix *);
-extern void Destroy_CompRow_Matrix(SuperMatrix *);
-extern void Destroy_SuperNode_Matrix(SuperMatrix *);
-extern void Destroy_CompCol_Permuted(SuperMatrix *);
-extern void Destroy_Dense_Matrix(SuperMatrix *);
-extern void get_perm_c(int, SuperMatrix *, int *);
-extern void set_default_options(superlu_options_t *options);
-extern void sp_preorder (superlu_options_t *, SuperMatrix*, int*, int*,
- SuperMatrix*);
-extern void superlu_abort_and_exit(char*);
-extern void *superlu_malloc (size_t);
-extern int *intMalloc (int);
-extern int *intCalloc (int);
-extern void superlu_free (void*);
-extern void SetIWork (int, int, int, int *, int **, int **, int **,
- int **, int **, int **, int **);
-extern int sp_coletree (int *, int *, int *, int, int, int *);
-extern void relax_snode (const int, int *, const int, int *, int *);
-extern void heap_relax_snode (const int, int *, const int, int *, int *);
-extern void resetrep_col (const int, const int *, int *);
-extern int spcoletree (int *, int *, int *, int, int, int *);
-extern int *TreePostorder (int, int *);
-extern double SuperLU_timer_ (void);
-extern int sp_ienv (int);
-extern int lsame_ (char *, char *);
-extern int xerbla_ (char *, int *);
-extern void ifill (int *, int, int);
-extern void snode_profile (int, int *);
-extern void super_stats (int, int *);
-extern void PrintSumm (char *, int, int, int);
-extern void StatInit(SuperLUStat_t *);
-extern void StatPrint (SuperLUStat_t *);
-extern void StatFree(SuperLUStat_t *);
-extern void print_panel_seg(int, int, int, int, int *, int *);
-extern void check_repfnz(int, int, int, int *);
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif /* __SUPERLU_UTIL */
diff --git a/intern/opennl/superlu/xerbla.c b/intern/opennl/superlu/xerbla.c
deleted file mode 100644
index 31baaecf3b0..00000000000
--- a/intern/opennl/superlu/xerbla.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/** \file opennl/superlu/xerbla.c
- * \ingroup opennl
- */
-
-#include <stdio.h>
-int xerbla_(char *, int *);
-
-/* Subroutine */ int xerbla_(char *srname, int *info)
-{
-/* -- LAPACK auxiliary routine (version 2.0) --
- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
- Courant Institute, Argonne National Lab, and Rice University
- September 30, 1994
-
-
- Purpose
- =======
-
- XERBLA is an error handler for the LAPACK routines.
- It is called by an LAPACK routine if an input parameter has an
- invalid value. A message is printed and execution stops.
-
- Installers may consider modifying the STOP statement in order to
- call system-specific exception-handling facilities.
-
- Arguments
- =========
-
- SRNAME (input) CHARACTER*6
- The name of the routine which called XERBLA.
-
- INFO (input) INT
- The position of the invalid parameter in the parameter list
-
- of the calling routine.
-
- =====================================================================
-*/
-
- printf("** On entry to %6s, parameter number %2d had an illegal value\n",
- srname, *info);
-
-/* End of XERBLA */
-
- return 0;
-} /* xerbla_ */
-
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index a4dfe339728..311b89b97cf 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -49,11 +49,6 @@ set(SRC
opensubdiv_intern.h
)
-if(WITH_SUBSURF_WERROR)
- ADD_CHECK_C_COMPILER_FLAG(CMAKE_C_FLAGS C_WERROR -Werror)
- ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS C_WERROR -Werror)
-endif()
-
macro(OPENSUBDIV_DEFINE_COMPONENT component)
if(${${component}})
add_definitions(-D${component})
diff --git a/intern/opensubdiv/SConscript b/intern/opensubdiv/SConscript
deleted file mode 100644
index 0532bae1c29..00000000000
--- a/intern/opensubdiv/SConscript
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2013, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Sergey Sharybin.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import os
-
-Import('env')
-
-sources = env.Glob('*.cc')
-
-defs = [ 'GLEW_STATIC' ]
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- defs += [ 'NOMINMAX' ]
-
-incs = '. ../guardedalloc #extern/clew/include/'
-incs += ' ' + env['BF_OPENSUBDIV_INC']
-incs += ' #/extern/glew/include'
-
-def checkOpenSubdivHeaderDefine(header, define):
- include_path = Dir(env.subst(env['BF_OPENSUBDIV_INC'])).abspath
- header_path = os.path.join(include_path, 'opensubdiv', 'osd', header)
- if os.path.exists(header_path):
- defs.append(define)
- return True
- return False
-
-checkOpenSubdivHeaderDefine("tbbEvaluator.h", 'OPENSUBDIV_HAS_TBB')
-#if checkOpenSubdivHeaderDefine("clEvaluator.h", 'OPENSUBDIV_HAS_OPENCL'):
-# defs += ['OPENSUBDIV_HAS_CLEW']
-# incs += ' #/extern/clew/include'
-#if checkOpenSubdivHeaderDefine("cudaEvaluator.h", 'OPENSUBDIV_HAS_CUDA'):
-# defs += ['OPENSUBDIV_HAS_CUEW']
-# incs += ' #/extern/cuew/include'
-checkOpenSubdivHeaderDefine("glXFBEvaluator.h", 'OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK')
-checkOpenSubdivHeaderDefine("glComputeEvaluator.h", 'OPENSUBDIV_HAS_GLSL_COMPUTE')
-
-if env['WITH_BF_LIBMV']:
- defs += ['OPENSUBDIV_HAS_OPENMP']
-
-# generated data files
-sources.extend((
- os.path.join(env['DATA_SOURCES'], "gpu_shader_opensubd_display.glsl.c"),
-))
-
-env.BlenderLib('bf_intern_opensubdiv', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185])
diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
index e2574b5989e..51e8ed46c34 100644
--- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl
+++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
@@ -23,20 +23,13 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/* ***** Vertex shader ***** */
-
-#extension GL_EXT_geometry_shader4 : enable
-#extension GL_ARB_gpu_shader5 : enable
-#extension GL_ARB_explicit_attrib_location : require
-#extension GL_ARB_uniform_buffer_object : require
-
struct VertexData {
vec4 position;
vec3 normal;
vec2 uv;
};
-#ifdef VERTEX_SHADER
+#ifdef VERTEX_SHADER // ---------------------
in vec3 normal;
in vec4 position;
@@ -52,24 +45,33 @@ void main()
{
outpt.v.position = modelViewMatrix * position;
outpt.v.normal = normalize(normalMatrix * normal);
+
+#if __VERSION__ < 140
/* Some compilers expects gl_Position to be written.
* It's not needed once we explicitly switch to GLSL 1.40 or above.
*/
gl_Position = outpt.v.position;
+#endif
}
-#endif /* VERTEX_SHADER */
+#elif defined GEOMETRY_SHADER // ---------------------
-/* ***** geometry shader ***** */
-#ifdef GEOMETRY_SHADER
-
-#ifndef GLSL_COMPAT_WORKAROUND
-layout(lines_adjacency) in;
-#ifndef WIREFRAME
-layout(triangle_strip, max_vertices = 4) out;
+#if __VERSION__ >= 150
+ layout(lines_adjacency) in;
+ #ifdef WIREFRAME
+ layout(line_strip, max_vertices = 8) out;
+ #else
+ layout(triangle_strip, max_vertices = 4) out;
+ #endif
#else
-layout(line_strip, max_vertices = 8) out;
+ #extension GL_EXT_geometry_shader4: require
+ /* application provides input/output layout info */
#endif
+
+#if __VERSION__ < 140
+ #extension GL_ARB_uniform_buffer_object: require
+ #extension GL_ARB_texture_buffer_object: enable
+ #extension GL_EXT_texture_buffer_object: enable
#endif
uniform mat4 modelViewMatrix;
@@ -80,7 +82,7 @@ uniform int osd_active_uv_offset;
in block {
VertexData v;
-} inpt[4];
+} inpt[];
#define INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord) \
{ \
@@ -188,10 +190,7 @@ void main()
EndPrimitive();
}
-#endif /* GEOMETRY_SHADER */
-
-/* ***** Fragment shader ***** */
-#ifdef FRAGMENT_SHADER
+#elif defined FRAGMENT_SHADER // ---------------------
#define MAX_LIGHTS 8
#define NUM_SOLID_LIGHTS 3
@@ -330,4 +329,4 @@ void main()
#endif
}
-#endif // FRAGMENT_SHADER
+#endif // ---------------------
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
index 66598948daf..9b9f4baa39e 100644
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ b/intern/opensubdiv/opensubdiv_capi.cc
@@ -295,29 +295,10 @@ const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefine
int openSubdiv_supportGPUDisplay(void)
{
- {
- /* Currently Intel GPUs has hard time working on Windows.
- *
- * For until we've got access to a hardware which demonstrates
- * the issue we disable OpenSubdiv on Intel GPUs.
- */
- static bool vendor_checked = false;
- static bool is_intel = false;
- if (!vendor_checked) {
- vendor_checked = true;
- const char *vendor = (const char *)glGetString(GL_VENDOR);
- if (vendor != NULL && strstr(vendor, "Intel")) {
- if(getenv("OPENSUBDIV_ALLOW_INTEL") == NULL) {
- is_intel = true;
- }
- }
- }
- if (is_intel) {
- return false;
- }
- }
-
- return GLEW_EXT_geometry_shader4 &&
- GLEW_ARB_gpu_shader5 &&
- GLEW_ARB_uniform_buffer_object;
+ // TODO: simplify extension check once Blender adopts GL 3.2
+ return openSubdiv_gpu_legacy_support() &&
+ (GLEW_VERSION_3_2 ||
+ (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) ||
+ (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
+ /* also ARB_explicit_attrib_location? */
}
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index 8010c39647d..b40505b197d 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -141,8 +141,9 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
/* ** Utility functions ** */
int openSubdiv_supportGPUDisplay(void);
int openSubdiv_getAvailableEvaluators(void);
-void openSubdiv_init(void);
+void openSubdiv_init(bool gpu_legacy_support);
void openSubdiv_cleanup(void);
+bool openSubdiv_gpu_legacy_support(void);
#ifdef __cplusplus
}
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
index 5d43cafd1f3..3fadde68d32 100644
--- a/intern/opensubdiv/opensubdiv_converter.cc
+++ b/intern/opensubdiv/opensubdiv_converter.cc
@@ -467,6 +467,14 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags(
break;
}
}
+ if (vert_edges.size() == 2) {
+ int edge0 = vert_edges[0],
+ edge1 = vert_edges[1];
+ float sharpness0 = conv.get_edge_sharpness(&conv, edge0),
+ sharpness1 = conv.get_edge_sharpness(&conv, edge1);
+ float sharpness = std::min(sharpness0, sharpness1);
+ setBaseVertexSharpness(refiner, vert, sharpness);
+ }
}
return true;
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index ac1e8301a42..1f09fa074d8 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -93,7 +93,7 @@ OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
void openSubdiv_deleteTopologyRefinerDescr(
OpenSubdiv_TopologyRefinerDescr *topology_refiner);
-/* TODO(sergey): Those calls are not strictly related on conversion.
+/* TODO(sergey): Those calls are not strictly related to conversion.
* needs some dedicated file perhaps.
*/
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index 31996a1bab8..698fdfee00f 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -23,11 +23,6 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/* Do some compatibility hacks in order to make
- * the code working with GPU_material pipeline.
- */
-#define GLSL_COMPAT_WORKAROUND
-
#include "opensubdiv_capi.h"
#ifdef _MSC_VER
@@ -191,18 +186,21 @@ void transpose_m3(float mat[3][3])
GLuint compileShader(GLenum shaderType,
const char *section,
+ const char *version,
const char *define)
{
- const char *sources[3];
char sdefine[64];
- sprintf(sdefine, "#define %s\n#define GLSL_COMPAT_WORKAROUND\n", section);
+ sprintf(sdefine, "#define %s\n", section);
- sources[0] = define;
- sources[1] = sdefine;
- sources[2] = datatoc_gpu_shader_opensubd_display_glsl;
+ const char *sources[] = {
+ version,
+ define,
+ sdefine,
+ datatoc_gpu_shader_opensubd_display_glsl
+ };
GLuint shader = glCreateShader(shaderType);
- glShaderSource(shader, 3, sources, NULL);
+ glShaderSource(shader, 4, sources, NULL);
glCompileShader(shader);
GLint status;
@@ -210,32 +208,35 @@ GLuint compileShader(GLenum shaderType,
if (status == GL_FALSE) {
GLchar emsg[1024];
glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
- fprintf(stderr, "Error compiling GLSL shader (%s): %s\n", section, emsg);
- fprintf(stderr, "Section: %s\n", sdefine);
+ fprintf(stderr, "Error compiling GLSL %s: %s\n", section, emsg);
+ fprintf(stderr, "Version: %s\n", version);
fprintf(stderr, "Defines: %s\n", define);
- fprintf(stderr, "Source: %s\n", sources[2]);
+ fprintf(stderr, "Source: %s\n", datatoc_gpu_shader_opensubd_display_glsl);
return 0;
}
return shader;
}
-GLuint linkProgram(const char *define)
+GLuint linkProgram(const char *version, const char *define)
{
GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
"VERTEX_SHADER",
+ version,
define);
if (vertexShader == 0) {
return 0;
}
GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
"GEOMETRY_SHADER",
+ version,
define);
if (geometryShader == 0) {
return 0;
}
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
"FRAGMENT_SHADER",
+ version,
define);
if (fragmentShader == 0) {
return 0;
@@ -250,30 +251,23 @@ GLuint linkProgram(const char *define)
glBindAttribLocation(program, 0, "position");
glBindAttribLocation(program, 1, "normal");
-#ifdef GLSL_COMPAT_WORKAROUND
- glProgramParameteriEXT(program,
- GL_GEOMETRY_INPUT_TYPE_EXT,
- GL_LINES_ADJACENCY_EXT);
- if (strstr(define, "WIREFRAME") == NULL) {
+ if (!GLEW_VERSION_3_2) {
+ /* provide input/output layout info */
glProgramParameteriEXT(program,
- GL_GEOMETRY_OUTPUT_TYPE_EXT,
- GL_TRIANGLE_STRIP);
+ GL_GEOMETRY_INPUT_TYPE_EXT,
+ GL_LINES_ADJACENCY_EXT);
+
+ bool wireframe = strstr(define, "WIREFRAME") != NULL;
- glProgramParameteriEXT(program,
- GL_GEOMETRY_VERTICES_OUT_EXT,
- 4);
- }
- else {
glProgramParameteriEXT(program,
GL_GEOMETRY_OUTPUT_TYPE_EXT,
- GL_LINE_STRIP);
+ wireframe ? GL_LINE_STRIP : GL_TRIANGLE_STRIP);
glProgramParameteriEXT(program,
GL_GEOMETRY_VERTICES_OUT_EXT,
8);
}
-#endif
glLinkProgram(program);
@@ -312,7 +306,7 @@ void bindProgram(GLMeshInterface * /*mesh*/,
{
glUseProgram(program);
- /* Matricies */
+ /* Matrices */
glUniformMatrix4fv(glGetUniformLocation(program, "modelViewMatrix"),
1, false,
g_transform.model_view_matrix);
@@ -323,7 +317,7 @@ void bindProgram(GLMeshInterface * /*mesh*/,
1, false,
g_transform.normal_matrix);
- /* Ligthing */
+ /* Lighting */
glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
glBufferSubData(GL_UNIFORM_BUFFER,
0, sizeof(g_lighting_data), &g_lighting_data);
@@ -378,11 +372,29 @@ bool openSubdiv_osdGLDisplayInit(void)
static bool need_init = true;
static bool init_success = false;
if (need_init) {
- g_flat_fill_solid_program = linkProgram("#define FLAT_SHADING\n");
- g_flat_fill_texture2d_program = linkProgram("#define USE_TEXTURE_2D\n#define FLAT_SHADING\n");
- g_smooth_fill_solid_program = linkProgram("#define SMOOTH_SHADING\n");
- g_smooth_fill_texture2d_program = linkProgram("#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n");
- g_wireframe_program = linkProgram("#define WIREFRAME\n");
+
+ if (!openSubdiv_supportGPUDisplay()) {
+ return false;
+ }
+
+ const char *version = "";
+ if (GLEW_VERSION_3_2) {
+ version = "#version 150 compatibility\n";
+ }
+ else if (GLEW_VERSION_3_1) {
+ version = "#version 140\n"
+ "#extension GL_ARB_compatibility: enable\n";
+ }
+ else {
+ version = "#version 130\n";
+ /* minimum supported for OpenSubdiv */
+ }
+
+ g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n");
+ g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n");
+ g_wireframe_program = linkProgram(version, "#define WIREFRAME\n");
glGenBuffers(1, &g_lighting_ub);
glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
@@ -427,7 +439,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
g_use_osd_glsl = use_osd_glsl != 0;
g_active_uv_index = active_uv_index;
- /* Update transformation matricies. */
+ /* Update transformation matrices. */
glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix);
@@ -482,7 +494,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
}
}
-static GLuint preapre_patchDraw(GLMeshInterface *mesh,
+static GLuint prepare_patchDraw(GLMeshInterface *mesh,
bool fill_quads)
{
GLint program = 0;
@@ -657,7 +669,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
}
/* Setup GLSL/OpenGL to draw patches in current context. */
- GLuint program = preapre_patchDraw(mesh, fill_quads != 0);
+ GLuint program = prepare_patchDraw(mesh, fill_quads != 0);
if (start_patch != -1) {
draw_partition_patches_range(mesh,
diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc
index a945484ba61..ae5592367dd 100644
--- a/intern/opensubdiv/opensubdiv_utils_capi.cc
+++ b/intern/opensubdiv/opensubdiv_utils_capi.cc
@@ -41,6 +41,8 @@
# include "opensubdiv_device_context_cuda.h"
#endif /* OPENSUBDIV_HAS_CUDA */
+static bool gpu_legacy_support_global = false;
+
int openSubdiv_getAvailableEvaluators(void)
{
if (!openSubdiv_supportGPUDisplay()) {
@@ -66,31 +68,13 @@ int openSubdiv_getAvailableEvaluators(void)
#endif /* OPENSUBDIV_HAS_OPENCL */
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
- if (GLEW_ARB_texture_buffer_object) {
+ if (GLEW_VERSION_4_1) {
flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK;
}
#endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
- static bool vendor_checked = false;
- static bool disable_glsl_compute = false;
- /* Force disable GLSL Compute on AMD hardware because it has really
- * hard time evaluating required shaders.
- */
- if (!vendor_checked) {
- vendor_checked = true;
- const char *vendor = (const char *)glGetString(GL_VENDOR);
- const char *renderer = (const char *)glGetString(GL_RENDERER);
- if (vendor != NULL && renderer != NULL) {
- if (strstr(vendor, "ATI") ||
- strstr(renderer, "Mesa DRI R") ||
- (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")))
- {
- disable_glsl_compute = true;
- }
- }
- }
- if (!disable_glsl_compute) {
+ if (GLEW_VERSION_4_3 || GLEW_ARB_compute_shader) {
flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
}
#endif /* OPENSUBDIV_HAS_GLSL_COMPUTE */
@@ -98,13 +82,19 @@ int openSubdiv_getAvailableEvaluators(void)
return flags;
}
-void openSubdiv_init(void)
+void openSubdiv_init(bool gpu_legacy_support)
{
/* Ensure all OpenGL strings are cached. */
(void)openSubdiv_getAvailableEvaluators();
+ gpu_legacy_support_global = gpu_legacy_support;
}
void openSubdiv_cleanup(void)
{
openSubdiv_osdGLDisplayDeinit();
}
+
+bool openSubdiv_gpu_legacy_support(void)
+{
+ return gpu_legacy_support_global;
+}
diff --git a/intern/openvdb/CMakeLists.txt b/intern/openvdb/CMakeLists.txt
new file mode 100644
index 00000000000..e0ecdb52929
--- /dev/null
+++ b/intern/openvdb/CMakeLists.txt
@@ -0,0 +1,70 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2015, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Kevin Dietrich.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ openvdb_capi.h
+)
+
+if(WITH_OPENVDB)
+ add_definitions(
+ -DWITH_OPENVDB
+ )
+
+ list(APPEND INC_SYS
+ ${BOOST_INCLUDE_DIR}
+ ${TBB_INCLUDE_DIRS}
+ ${OPENEXR_INCLUDE_DIRS}
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+
+ list(APPEND SRC
+ intern/openvdb_dense_convert.cc
+ intern/openvdb_reader.cc
+ intern/openvdb_writer.cc
+ openvdb_capi.cc
+ openvdb_util.cc
+
+ intern/openvdb_dense_convert.h
+ intern/openvdb_reader.h
+ intern/openvdb_writer.h
+ openvdb_util.h
+ )
+
+ if(WITH_OPENVDB_BLOSC)
+ add_definitions(
+ -DWITH_OPENVDB_BLOSC
+ )
+ endif()
+endif()
+
+blender_add_lib(bf_intern_openvdb "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/openvdb/intern/openvdb_dense_convert.cc b/intern/openvdb/intern/openvdb_dense_convert.cc
new file mode 100644
index 00000000000..d4f62776988
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_dense_convert.cc
@@ -0,0 +1,167 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_dense_convert.h"
+
+#include <openvdb/tools/ValueTransformer.h> /* for tools::foreach */
+
+namespace internal {
+
+openvdb::Mat4R convertMatrix(const float mat[4][4])
+{
+ return openvdb::Mat4R(
+ mat[0][0], mat[0][1], mat[0][2], mat[0][3],
+ mat[1][0], mat[1][1], mat[1][2], mat[1][3],
+ mat[2][0], mat[2][1], mat[2][2], mat[2][3],
+ mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
+}
+
+
+class MergeScalarGrids {
+ typedef openvdb::FloatTree ScalarTree;
+
+ openvdb::tree::ValueAccessor<const ScalarTree> m_acc_x, m_acc_y, m_acc_z;
+
+public:
+ MergeScalarGrids(const ScalarTree *x_tree, const ScalarTree *y_tree, const ScalarTree *z_tree)
+ : m_acc_x(*x_tree)
+ , m_acc_y(*y_tree)
+ , m_acc_z(*z_tree)
+ {}
+
+ MergeScalarGrids(const MergeScalarGrids &other)
+ : m_acc_x(other.m_acc_x)
+ , m_acc_y(other.m_acc_y)
+ , m_acc_z(other.m_acc_z)
+ {}
+
+ void operator()(const openvdb::Vec3STree::ValueOnIter &it) const
+ {
+ using namespace openvdb;
+
+ const math::Coord xyz = it.getCoord();
+ float x = m_acc_x.getValue(xyz);
+ float y = m_acc_y.getValue(xyz);
+ float z = m_acc_z.getValue(xyz);
+
+ it.setValue(math::Vec3s(x, y, z));
+ }
+};
+
+openvdb::GridBase *OpenVDB_export_vector_grid(
+ OpenVDBWriter *writer,
+ const openvdb::Name &name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3],
+ float fluid_mat[4][4],
+ openvdb::VecType vec_type,
+ const bool is_color,
+ const openvdb::FloatGrid *mask)
+{
+ using namespace openvdb;
+
+ math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
+ Mat4R mat = convertMatrix(fluid_mat);
+ math::Transform::Ptr transform = math::Transform::createLinearTransform(mat);
+
+ FloatGrid::Ptr grid[3];
+
+ grid[0] = FloatGrid::create(0.0f);
+ tools::Dense<const float, tools::LayoutXYZ> dense_grid_x(bbox, data_x);
+ tools::copyFromDense(dense_grid_x, grid[0]->tree(), TOLERANCE);
+
+ grid[1] = FloatGrid::create(0.0f);
+ tools::Dense<const float, tools::LayoutXYZ> dense_grid_y(bbox, data_y);
+ tools::copyFromDense(dense_grid_y, grid[1]->tree(), TOLERANCE);
+
+ grid[2] = FloatGrid::create(0.0f);
+ tools::Dense<const float, tools::LayoutXYZ> dense_grid_z(bbox, data_z);
+ tools::copyFromDense(dense_grid_z, grid[2]->tree(), TOLERANCE);
+
+ Vec3SGrid::Ptr vecgrid = Vec3SGrid::create(Vec3s(0.0f));
+
+ /* Activate voxels in the vector grid based on the scalar grids to ensure
+ * thread safety later on */
+ for (int i = 0; i < 3; ++i) {
+ vecgrid->tree().topologyUnion(grid[i]->tree());
+ }
+
+ MergeScalarGrids op(&(grid[0]->tree()), &(grid[1]->tree()), &(grid[2]->tree()));
+ tools::foreach(vecgrid->beginValueOn(), op, true, false);
+
+ vecgrid->setTransform(transform);
+
+ if (mask) {
+ vecgrid = tools::clip(*vecgrid, *mask);
+ }
+
+ vecgrid->setName(name);
+ vecgrid->setIsInWorldSpace(false);
+ vecgrid->setVectorType(vec_type);
+ vecgrid->insertMeta("is_color", BoolMetadata(is_color));
+ vecgrid->setGridClass(GRID_STAGGERED);
+
+ writer->insert(vecgrid);
+
+ return vecgrid.get();
+}
+
+void OpenVDB_import_grid_vector(
+ OpenVDBReader *reader,
+ const openvdb::Name &name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3])
+{
+ using namespace openvdb;
+
+ if (!reader->hasGrid(name)) {
+ std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str());
+ memset(*data_x, 0, sizeof(float) * res[0] * res[1] * res[2]);
+ memset(*data_y, 0, sizeof(float) * res[0] * res[1] * res[2]);
+ memset(*data_z, 0, sizeof(float) * res[0] * res[1] * res[2]);
+ return;
+ }
+
+ Vec3SGrid::Ptr vgrid = gridPtrCast<Vec3SGrid>(reader->getGrid(name));
+ Vec3SGrid::ConstAccessor acc = vgrid->getConstAccessor();
+ math::Coord xyz;
+ int &x = xyz[0], &y = xyz[1], &z = xyz[2];
+
+ size_t index = 0;
+ for (z = 0; z < res[2]; ++z) {
+ for (y = 0; y < res[1]; ++y) {
+ for (x = 0; x < res[0]; ++x, ++index) {
+ math::Vec3s value = acc.getValue(xyz);
+ (*data_x)[index] = value.x();
+ (*data_y)[index] = value.y();
+ (*data_z)[index] = value.z();
+ }
+ }
+ }
+}
+
+} /* namespace internal */
diff --git a/intern/openvdb/intern/openvdb_dense_convert.h b/intern/openvdb/intern/openvdb_dense_convert.h
new file mode 100644
index 00000000000..fd10334c4ad
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_dense_convert.h
@@ -0,0 +1,130 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_DENSE_CONVERT_H__
+#define __OPENVDB_DENSE_CONVERT_H__
+
+#include "openvdb_reader.h"
+#include "openvdb_writer.h"
+
+#include <openvdb/tools/Clip.h>
+#include <openvdb/tools/Dense.h>
+
+#include <cstdio>
+
+#define TOLERANCE 1e-3f
+
+namespace internal {
+
+openvdb::Mat4R convertMatrix(const float mat[4][4]);
+
+template <typename GridType, typename T>
+GridType *OpenVDB_export_grid(
+ OpenVDBWriter *writer,
+ const openvdb::Name &name,
+ const T *data,
+ const int res[3],
+ float fluid_mat[4][4],
+ const openvdb::FloatGrid *mask)
+{
+ using namespace openvdb;
+
+ math::CoordBBox bbox(Coord(0), Coord(res[0] - 1, res[1] - 1, res[2] - 1));
+ Mat4R mat = convertMatrix(fluid_mat);
+ math::Transform::Ptr transform = math::Transform::createLinearTransform(mat);
+
+ typename GridType::Ptr grid = GridType::create(T(0));
+
+ tools::Dense<const T, openvdb::tools::LayoutXYZ> dense_grid(bbox, data);
+ tools::copyFromDense(dense_grid, grid->tree(), (T)TOLERANCE);
+
+ grid->setTransform(transform);
+
+ if (mask) {
+ grid = tools::clip(*grid, *mask);
+ }
+
+ grid->setName(name);
+ grid->setIsInWorldSpace(false);
+ grid->setVectorType(openvdb::VEC_INVARIANT);
+
+ writer->insert(grid);
+
+ return grid.get();
+}
+
+template <typename GridType, typename T>
+void OpenVDB_import_grid(
+ OpenVDBReader *reader,
+ const openvdb::Name &name,
+ T **data,
+ const int res[3])
+{
+ using namespace openvdb;
+
+ if (!reader->hasGrid(name)) {
+ std::fprintf(stderr, "OpenVDB grid %s not found in file!\n", name.c_str());
+ memset(*data, 0, sizeof(T) * res[0] * res[1] * res[2]);
+ return;
+ }
+
+ typename GridType::Ptr grid = gridPtrCast<GridType>(reader->getGrid(name));
+ typename GridType::ConstAccessor acc = grid->getConstAccessor();
+
+ math::Coord xyz;
+ int &x = xyz[0], &y = xyz[1], &z = xyz[2];
+
+ size_t index = 0;
+ for (z = 0; z < res[2]; ++z) {
+ for (y = 0; y < res[1]; ++y) {
+ for (x = 0; x < res[0]; ++x, ++index) {
+ (*data)[index] = acc.getValue(xyz);
+ }
+ }
+ }
+}
+
+openvdb::GridBase *OpenVDB_export_vector_grid(
+ OpenVDBWriter *writer,
+ const openvdb::Name &name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3],
+ float fluid_mat[4][4],
+ openvdb::VecType vec_type,
+ const bool is_color,
+ const openvdb::FloatGrid *mask);
+
+
+void OpenVDB_import_grid_vector(
+ OpenVDBReader *reader,
+ const openvdb::Name &name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3]);
+
+} /* namespace internal */
+
+#endif /* __OPENVDB_DENSE_CONVERT_H__ */
diff --git a/intern/openvdb/intern/openvdb_reader.cc b/intern/openvdb/intern/openvdb_reader.cc
new file mode 100644
index 00000000000..8b15b81710d
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_reader.cc
@@ -0,0 +1,136 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_reader.h"
+#include "openvdb_util.h"
+
+OpenVDBReader::OpenVDBReader()
+ : m_meta_map(new openvdb::MetaMap)
+ , m_file(NULL)
+{
+ /* Although it is safe, it may not be good to have this here, could be done
+ * once instead of everytime we read a file. */
+ openvdb::initialize();
+}
+
+OpenVDBReader::~OpenVDBReader()
+{
+ cleanupFile();
+}
+
+void OpenVDBReader::open(const openvdb::Name &filename)
+{
+ cleanupFile();
+
+ try {
+ m_file = new openvdb::io::File(filename);
+ m_file->setCopyMaxBytes(0);
+ m_file->open();
+
+ m_meta_map = m_file->getMetadata();
+ }
+ /* Mostly to catch exceptions related to Blosc not being supported. */
+ catch (const openvdb::IoError &e) {
+ std::cerr << e.what() << '\n';
+ cleanupFile();
+ }
+}
+
+void OpenVDBReader::floatMeta(const openvdb::Name &name, float &value) const
+{
+ try {
+ value = m_meta_map->metaValue<float>(name);
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBReader::intMeta(const openvdb::Name &name, int &value) const
+{
+ try {
+ value = m_meta_map->metaValue<int>(name);
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBReader::vec3sMeta(const openvdb::Name &name, float value[3]) const
+{
+ try {
+ openvdb::Vec3s meta_val = m_meta_map->metaValue<openvdb::Vec3s>(name);
+
+ value[0] = meta_val.x();
+ value[1] = meta_val.y();
+ value[2] = meta_val.z();
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBReader::vec3IMeta(const openvdb::Name &name, int value[3]) const
+{
+ try {
+ openvdb::Vec3i meta_val = m_meta_map->metaValue<openvdb::Vec3i>(name);
+
+ value[0] = meta_val.x();
+ value[1] = meta_val.y();
+ value[2] = meta_val.z();
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBReader::mat4sMeta(const openvdb::Name &name, float value[4][4]) const
+{
+ try {
+ openvdb::Mat4s meta_val = m_meta_map->metaValue<openvdb::Mat4s>(name);
+
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ value[i][j] = meta_val[i][j];
+ }
+ }
+ }
+ CATCH_KEYERROR;
+}
+
+bool OpenVDBReader::hasGrid(const openvdb::Name &name) const
+{
+ return m_file->hasGrid(name);
+}
+
+openvdb::GridBase::Ptr OpenVDBReader::getGrid(const openvdb::Name &name) const
+{
+ return m_file->readGrid(name);
+}
+
+size_t OpenVDBReader::numGrids() const
+{
+ return m_file->getGrids()->size();
+}
+
+void OpenVDBReader::cleanupFile()
+{
+ if (m_file) {
+ m_file->close();
+ delete m_file;
+ }
+}
diff --git a/intern/openvdb/intern/openvdb_reader.h b/intern/openvdb/intern/openvdb_reader.h
new file mode 100644
index 00000000000..07f77130ff9
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_reader.h
@@ -0,0 +1,55 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_READER_H__
+#define __OPENVDB_READER_H__
+
+#include <openvdb/openvdb.h>
+
+struct OpenVDBReader {
+private:
+ openvdb::MetaMap::Ptr m_meta_map;
+ openvdb::io::File *m_file;
+
+ void cleanupFile();
+
+public:
+ OpenVDBReader();
+ ~OpenVDBReader();
+
+ void open(const openvdb::Name &filename);
+
+ void floatMeta(const openvdb::Name &name, float &value) const;
+ void intMeta(const openvdb::Name &name, int &value) const;
+ void vec3sMeta(const openvdb::Name &name, float value[3]) const;
+ void vec3IMeta(const openvdb::Name &name, int value[3]) const;
+ void mat4sMeta(const openvdb::Name &name, float value[4][4]) const;
+
+ bool hasGrid(const openvdb::Name &name) const;
+ openvdb::GridBase::Ptr getGrid(const openvdb::Name &name) const;
+ size_t numGrids() const;
+};
+
+#endif /* __OPENVDB_READER_H__ */
diff --git a/intern/openvdb/intern/openvdb_writer.cc b/intern/openvdb/intern/openvdb_writer.cc
new file mode 100644
index 00000000000..923752909d9
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_writer.cc
@@ -0,0 +1,118 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_writer.h"
+#include "openvdb_util.h"
+
+OpenVDBWriter::OpenVDBWriter()
+ : m_grids(new openvdb::GridPtrVec())
+ , m_meta_map(new openvdb::MetaMap())
+ , m_save_as_half(false)
+{
+ m_meta_map->insertMeta("creator", openvdb::StringMetadata("Blender/Smoke"));
+}
+
+OpenVDBWriter::~OpenVDBWriter()
+{}
+
+void OpenVDBWriter::insert(const openvdb::GridBase::Ptr &grid)
+{
+ grid->setSaveFloatAsHalf(m_save_as_half);
+ m_grids->push_back(grid);
+}
+
+void OpenVDBWriter::insert(const openvdb::GridBase &grid)
+{
+ m_grids->push_back(grid.copyGrid());
+}
+
+void OpenVDBWriter::insertFloatMeta(const openvdb::Name &name, const float value)
+{
+ try {
+ m_meta_map->insertMeta(name, openvdb::FloatMetadata(value));
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBWriter::insertIntMeta(const openvdb::Name &name, const int value)
+{
+ try {
+ m_meta_map->insertMeta(name, openvdb::Int32Metadata(value));
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBWriter::insertVec3sMeta(const openvdb::Name &name, const openvdb::Vec3s &value)
+{
+ try {
+ m_meta_map->insertMeta(name, openvdb::Vec3SMetadata(value));
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBWriter::insertVec3IMeta(const openvdb::Name &name, const openvdb::Vec3I &value)
+{
+ try {
+ m_meta_map->insertMeta(name, openvdb::Vec3IMetadata(value));
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBWriter::insertMat4sMeta(const openvdb::Name &name, const float value[4][4])
+{
+ openvdb::Mat4s mat = openvdb::Mat4s(
+ value[0][0], value[0][1], value[0][2], value[0][3],
+ value[1][0], value[1][1], value[1][2], value[1][3],
+ value[2][0], value[2][1], value[2][2], value[2][3],
+ value[3][0], value[3][1], value[3][2], value[3][3]);
+
+ try {
+ m_meta_map->insertMeta(name, openvdb::Mat4SMetadata(mat));
+ }
+ CATCH_KEYERROR;
+}
+
+void OpenVDBWriter::setFlags(const int compression, const bool save_as_half)
+{
+ m_compression_flags = compression;
+ m_save_as_half = save_as_half;
+}
+
+void OpenVDBWriter::write(const openvdb::Name &filename) const
+{
+ try {
+ openvdb::io::File file(filename);
+ file.setCompression(m_compression_flags);
+ file.write(*m_grids, *m_meta_map);
+ file.close();
+
+ /* Should perhaps be an option at some point */
+ m_grids->clear();
+ }
+ /* Mostly to catch exceptions related to Blosc not being supported. */
+ catch (const openvdb::IoError &e) {
+ std::cerr << e.what() << '\n';
+ }
+}
diff --git a/intern/openvdb/intern/openvdb_writer.h b/intern/openvdb/intern/openvdb_writer.h
new file mode 100644
index 00000000000..69f42473975
--- /dev/null
+++ b/intern/openvdb/intern/openvdb_writer.h
@@ -0,0 +1,57 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_WRITER_H__
+#define __OPENVDB_WRITER_H__
+
+#include <openvdb/openvdb.h>
+
+struct OpenVDBWriter {
+private:
+ openvdb::GridPtrVecPtr m_grids;
+ openvdb::MetaMap::Ptr m_meta_map;
+
+ int m_compression_flags;
+ bool m_save_as_half;
+
+public:
+ OpenVDBWriter();
+ ~OpenVDBWriter();
+
+ void insert(const openvdb::GridBase::Ptr &grid);
+ void insert(const openvdb::GridBase &grid);
+
+ void insertFloatMeta(const openvdb::Name &name, const float value);
+ void insertIntMeta(const openvdb::Name &name, const int value);
+ void insertVec3sMeta(const openvdb::Name &name, const openvdb::Vec3s &value);
+ void insertVec3IMeta(const openvdb::Name &name, const openvdb::Vec3I &value);
+ void insertMat4sMeta(const openvdb::Name &name, const float value[4][4]);
+
+ void setFlags(const int compression, const bool save_as_half);
+
+ void write(const openvdb::Name &filename) const;
+};
+
+#endif /* __OPENVDB_WRITER_H__ */
diff --git a/intern/openvdb/openvdb_capi.cc b/intern/openvdb/openvdb_capi.cc
new file mode 100644
index 00000000000..ef4f8c8820f
--- /dev/null
+++ b/intern/openvdb/openvdb_capi.cc
@@ -0,0 +1,240 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_capi.h"
+#include "openvdb_dense_convert.h"
+#include "openvdb_util.h"
+
+struct OpenVDBFloatGrid { int unused; };
+struct OpenVDBIntGrid { int unused; };
+struct OpenVDBVectorGrid { int unused; };
+
+int OpenVDB_getVersionHex()
+{
+ return openvdb::OPENVDB_LIBRARY_VERSION;
+}
+
+OpenVDBFloatGrid *OpenVDB_export_grid_fl(
+ OpenVDBWriter *writer,
+ const char *name, float *data,
+ const int res[3], float matrix[4][4],
+ OpenVDBFloatGrid *mask)
+{
+ Timer(__func__);
+
+ using openvdb::FloatGrid;
+
+ FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask);
+ FloatGrid *grid = internal::OpenVDB_export_grid<FloatGrid>(
+ writer,
+ name,
+ data,
+ res,
+ matrix,
+ mask_grid);
+
+ return reinterpret_cast<OpenVDBFloatGrid *>(grid);
+}
+
+OpenVDBIntGrid *OpenVDB_export_grid_ch(
+ OpenVDBWriter *writer,
+ const char *name, unsigned char *data,
+ const int res[3], float matrix[4][4],
+ OpenVDBFloatGrid *mask)
+{
+ Timer(__func__);
+
+ using openvdb::FloatGrid;
+ using openvdb::Int32Grid;
+
+ FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask);
+ Int32Grid *grid = internal::OpenVDB_export_grid<Int32Grid>(
+ writer,
+ name,
+ data,
+ res,
+ matrix,
+ mask_grid);
+
+ return reinterpret_cast<OpenVDBIntGrid *>(grid);
+}
+
+OpenVDBVectorGrid *OpenVDB_export_grid_vec(
+ struct OpenVDBWriter *writer,
+ const char *name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3], float matrix[4][4], short vec_type,
+ const bool is_color, OpenVDBFloatGrid *mask)
+{
+ Timer(__func__);
+
+ using openvdb::GridBase;
+ using openvdb::FloatGrid;
+ using openvdb::VecType;
+
+ FloatGrid *mask_grid = reinterpret_cast<FloatGrid *>(mask);
+ GridBase *grid = internal::OpenVDB_export_vector_grid(
+ writer,
+ name,
+ data_x,
+ data_y,
+ data_z,
+ res,
+ matrix,
+ static_cast<VecType>(vec_type),
+ is_color,
+ mask_grid);
+
+ return reinterpret_cast<OpenVDBVectorGrid *>(grid);
+}
+
+void OpenVDB_import_grid_fl(
+ OpenVDBReader *reader,
+ const char *name, float **data,
+ const int res[3])
+{
+ Timer(__func__);
+
+ internal::OpenVDB_import_grid<openvdb::FloatGrid>(reader, name, data, res);
+}
+
+void OpenVDB_import_grid_ch(
+ OpenVDBReader *reader,
+ const char *name, unsigned char **data,
+ const int res[3])
+{
+ internal::OpenVDB_import_grid<openvdb::Int32Grid>(reader, name, data, res);
+}
+
+void OpenVDB_import_grid_vec(
+ struct OpenVDBReader *reader,
+ const char *name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3])
+{
+ Timer(__func__);
+
+ internal::OpenVDB_import_grid_vector(reader, name, data_x, data_y, data_z, res);
+}
+
+OpenVDBWriter *OpenVDBWriter_create()
+{
+ return new OpenVDBWriter();
+}
+
+void OpenVDBWriter_free(OpenVDBWriter *writer)
+{
+ delete writer;
+}
+
+void OpenVDBWriter_set_flags(OpenVDBWriter *writer, const int flag, const bool half)
+{
+ int compression_flags = openvdb::io::COMPRESS_ACTIVE_MASK;
+
+#ifdef WITH_OPENVDB_BLOSC
+ if (flag == 0) {
+ compression_flags |= openvdb::io::COMPRESS_BLOSC;
+ }
+ else
+#endif
+ if (flag == 1) {
+ compression_flags |= openvdb::io::COMPRESS_ZIP;
+ }
+ else {
+ compression_flags = openvdb::io::COMPRESS_NONE;
+ }
+
+ writer->setFlags(compression_flags, half);
+}
+
+void OpenVDBWriter_add_meta_fl(OpenVDBWriter *writer, const char *name, const float value)
+{
+ writer->insertFloatMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_int(OpenVDBWriter *writer, const char *name, const int value)
+{
+ writer->insertIntMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_v3(OpenVDBWriter *writer, const char *name, const float value[3])
+{
+ writer->insertVec3sMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_v3_int(OpenVDBWriter *writer, const char *name, const int value[3])
+{
+ writer->insertVec3IMeta(name, value);
+}
+
+void OpenVDBWriter_add_meta_mat4(OpenVDBWriter *writer, const char *name, float value[4][4])
+{
+ writer->insertMat4sMeta(name, value);
+}
+
+void OpenVDBWriter_write(OpenVDBWriter *writer, const char *filename)
+{
+ writer->write(filename);
+}
+
+OpenVDBReader *OpenVDBReader_create()
+{
+ return new OpenVDBReader();
+}
+
+void OpenVDBReader_free(OpenVDBReader *reader)
+{
+ delete reader;
+}
+
+void OpenVDBReader_open(OpenVDBReader *reader, const char *filename)
+{
+ reader->open(filename);
+}
+
+void OpenVDBReader_get_meta_fl(OpenVDBReader *reader, const char *name, float *value)
+{
+ reader->floatMeta(name, *value);
+}
+
+void OpenVDBReader_get_meta_int(OpenVDBReader *reader, const char *name, int *value)
+{
+ reader->intMeta(name, *value);
+}
+
+void OpenVDBReader_get_meta_v3(OpenVDBReader *reader, const char *name, float value[3])
+{
+ reader->vec3sMeta(name, value);
+}
+
+void OpenVDBReader_get_meta_v3_int(OpenVDBReader *reader, const char *name, int value[3])
+{
+ reader->vec3IMeta(name, value);
+}
+
+void OpenVDBReader_get_meta_mat4(OpenVDBReader *reader, const char *name, float value[4][4])
+{
+ reader->mat4sMeta(name, value);
+}
diff --git a/intern/openvdb/openvdb_capi.h b/intern/openvdb/openvdb_capi.h
new file mode 100644
index 00000000000..2d2feeadcf1
--- /dev/null
+++ b/intern/openvdb/openvdb_capi.h
@@ -0,0 +1,108 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_CAPI_H__
+#define __OPENVDB_CAPI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct OpenVDBReader;
+struct OpenVDBWriter;
+struct OpenVDBFloatGrid;
+struct OpenVDBIntGrid;
+struct OpenVDBVectorGrid;
+
+int OpenVDB_getVersionHex(void);
+
+enum {
+ VEC_INVARIANT = 0,
+ VEC_COVARIANT = 1,
+ VEC_COVARIANT_NORMALIZE = 2,
+ VEC_CONTRAVARIANT_RELATIVE = 3,
+ VEC_CONTRAVARIANT_ABSOLUTE = 4,
+};
+
+struct OpenVDBFloatGrid *OpenVDB_export_grid_fl(
+ struct OpenVDBWriter *writer,
+ const char *name, float *data,
+ const int res[3], float matrix[4][4],
+ struct OpenVDBFloatGrid *mask);
+
+struct OpenVDBIntGrid *OpenVDB_export_grid_ch(
+ struct OpenVDBWriter *writer,
+ const char *name, unsigned char *data,
+ const int res[3], float matrix[4][4],
+ struct OpenVDBFloatGrid *mask);
+
+struct OpenVDBVectorGrid *OpenVDB_export_grid_vec(
+ struct OpenVDBWriter *writer,
+ const char *name,
+ const float *data_x, const float *data_y, const float *data_z,
+ const int res[3], float matrix[4][4], short vec_type,
+ const bool is_color,
+ struct OpenVDBFloatGrid *mask);
+
+void OpenVDB_import_grid_fl(
+ struct OpenVDBReader *reader,
+ const char *name, float **data,
+ const int res[3]);
+
+void OpenVDB_import_grid_ch(
+ struct OpenVDBReader *reader,
+ const char *name, unsigned char **data,
+ const int res[3]);
+
+void OpenVDB_import_grid_vec(
+ struct OpenVDBReader *reader,
+ const char *name,
+ float **data_x, float **data_y, float **data_z,
+ const int res[3]);
+
+struct OpenVDBWriter *OpenVDBWriter_create(void);
+void OpenVDBWriter_free(struct OpenVDBWriter *writer);
+void OpenVDBWriter_set_flags(struct OpenVDBWriter *writer, const int flag, const bool half);
+void OpenVDBWriter_add_meta_fl(struct OpenVDBWriter *writer, const char *name, const float value);
+void OpenVDBWriter_add_meta_int(struct OpenVDBWriter *writer, const char *name, const int value);
+void OpenVDBWriter_add_meta_v3(struct OpenVDBWriter *writer, const char *name, const float value[3]);
+void OpenVDBWriter_add_meta_v3_int(struct OpenVDBWriter *writer, const char *name, const int value[3]);
+void OpenVDBWriter_add_meta_mat4(struct OpenVDBWriter *writer, const char *name, float value[4][4]);
+void OpenVDBWriter_write(struct OpenVDBWriter *writer, const char *filename);
+
+struct OpenVDBReader *OpenVDBReader_create(void);
+void OpenVDBReader_free(struct OpenVDBReader *reader);
+void OpenVDBReader_open(struct OpenVDBReader *reader, const char *filename);
+void OpenVDBReader_get_meta_fl(struct OpenVDBReader *reader, const char *name, float *value);
+void OpenVDBReader_get_meta_int(struct OpenVDBReader *reader, const char *name, int *value);
+void OpenVDBReader_get_meta_v3(struct OpenVDBReader *reader, const char *name, float value[3]);
+void OpenVDBReader_get_meta_v3_int(struct OpenVDBReader *reader, const char *name, int value[3]);
+void OpenVDBReader_get_meta_mat4(struct OpenVDBReader *reader, const char *name, float value[4][4]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OPENVDB_CAPI_H__ */
diff --git a/intern/openvdb/openvdb_util.cc b/intern/openvdb/openvdb_util.cc
new file mode 100644
index 00000000000..d187f55970d
--- /dev/null
+++ b/intern/openvdb/openvdb_util.cc
@@ -0,0 +1,38 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "openvdb_util.h"
+
+#include <cstdio>
+
+ScopeTimer::ScopeTimer(const std::string &message)
+ : m_message(message)
+ , m_timer()
+{}
+
+ScopeTimer::~ScopeTimer()
+{
+ std::printf("%s: %fms\n", m_message.c_str(), m_timer.delta());
+}
diff --git a/intern/openvdb/openvdb_util.h b/intern/openvdb/openvdb_util.h
new file mode 100644
index 00000000000..8e14ed54345
--- /dev/null
+++ b/intern/openvdb/openvdb_util.h
@@ -0,0 +1,57 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENVDB_UTIL_H__
+#define __OPENVDB_UTIL_H__
+
+#include <openvdb/openvdb.h>
+#include <openvdb/util/CpuTimer.h>
+
+#define CATCH_KEYERROR \
+ catch (const openvdb::KeyError &e) { \
+ std::cerr << e.what() << '\n'; \
+ }
+
+//#define DEBUG_TIME
+
+/* A utility class which prints the time elapsed during its lifetime, useful for
+ * e.g. timing the overall execution time of a function */
+class ScopeTimer {
+ std::string m_message;
+ openvdb::util::CpuTimer m_timer;
+
+public:
+ ScopeTimer(const std::string &message);
+ ~ScopeTimer();
+};
+
+#ifdef DEBUG_TIME
+# define Timer(x) \
+ ScopeTimer prof(x);
+#else
+# define Timer(x)
+#endif
+
+#endif /* __OPENVDB_UTIL_H__ */
diff --git a/intern/raskter/CMakeLists.txt b/intern/raskter/CMakeLists.txt
deleted file mode 100644
index 3e1368d8eb0..00000000000
--- a/intern/raskter/CMakeLists.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2012, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Peter Larabell
-#
-# ***** END GPL LICENSE BLOCK *****
-
-set(INC
- .
-)
-
-set(INC_SYS
-
-)
-
-set(SRC
- raskter.c
-
- raskter.h
-)
-
-blender_add_lib(bf_intern_raskter "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/intern/raskter/SConscript b/intern/raskter/SConscript
deleted file mode 100644
index c7bf647b0e2..00000000000
--- a/intern/raskter/SConscript
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2012, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Peter Larabell
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = ['raskter.c']
-
-incs = ''
-defs = ''
-
-env.BlenderLib ('bf_intern_raskter', sources, Split(incs), Split(defs), libtype=['intern'], priority=[100] )
diff --git a/intern/raskter/raskter.c b/intern/raskter/raskter.c
deleted file mode 100644
index 4f65f877316..00000000000
--- a/intern/raskter/raskter.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2012 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Peter Larabell.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file raskter.c
- * \ingroup RASKTER
- */
-
-#include <stdlib.h>
-#include "raskter.h"
-
-/* from BLI_utildefines.h */
-#define MIN2(x, y) ( (x) < (y) ? (x) : (y) )
-#define MAX2(x, y) ( (x) > (y) ? (x) : (y) )
-
-struct PolyVert {
- int x;
- int y;
-};
-
-struct e_Status {
- int x;
- int ybeg;
- int xshift;
- int xdir;
- int drift;
- int drift_inc;
- int drift_dec;
- int num;
- struct e_Status *e_next;
-};
-
-struct r_BufferStats {
- float *buf;
- int sizex;
- int sizey;
- int ymin;
- int ymax;
- int xmin;
- int xmax;
-};
-
-struct r_FillContext {
- struct e_Status *all_edges, *possible_edges;
- struct r_BufferStats rb;
-};
-
-/*
- * Sort all the edges of the input polygon by Y, then by X, of the "first" vertex encountered.
- * This will ensure we can scan convert the entire poly in one pass.
- *
- * Really the poly should be clipped to the frame buffer's dimensions here for speed of drawing
- * just the poly. Since the DEM code could end up being coupled with this, we'll keep it separate
- * for now.
- */
-static void preprocess_all_edges(struct r_FillContext *ctx,
- struct PolyVert *verts, int num_verts, struct e_Status *open_edge)
-{
- int i;
- int xbeg;
- int ybeg;
- int xend;
- int yend;
- int dx;
- int dy;
- int temp_pos;
- int xdist;
- struct e_Status *e_new;
- struct e_Status *next_edge;
- struct e_Status **next_edge_ref;
- struct PolyVert *v;
- /* set up pointers */
- v = verts;
- ctx->all_edges = NULL;
- /* initialize some boundaries */
- ctx->rb.xmax = v[0].x;
- ctx->rb.xmin = v[0].x;
- ctx->rb.ymax = v[0].y;
- ctx->rb.ymin = v[0].y;
- /* loop all verts */
- for (i = 0; i < num_verts; i++) {
- /* determine beginnings and endings of edges, linking last vertex to first vertex */
- xbeg = v[i].x;
- ybeg = v[i].y;
- /* keep track of our x and y bounds */
- if (xbeg >= ctx->rb.xmax) {
- ctx->rb.xmax = xbeg;
- }
- else if (xbeg <= ctx->rb.xmin) {
- ctx->rb.xmin = xbeg;
- }
- if (ybeg >= ctx->rb.ymax) {
- ctx->rb.ymax = ybeg;
- }
- else if (ybeg <= ctx->rb.ymin) {
- ctx->rb.ymin=ybeg;
- }
- if (i) {
- /* we're not at the last vert, so end of the edge is the previous vertex */
- xend = v[i - 1].x;
- yend = v[i - 1].y;
- }
- else {
- /* we're at the first vertex, so the "end" of this edge is the last vertex */
- xend = v[num_verts - 1].x;
- yend = v[num_verts - 1].y;
- }
- /* make sure our edges are facing the correct direction */
- if (ybeg > yend) {
- /* flip the Xs */
- temp_pos = xbeg;
- xbeg = xend;
- xend = temp_pos;
- /* flip the Ys */
- temp_pos = ybeg;
- ybeg = yend;
- yend = temp_pos;
- }
-
- /* calculate y delta */
- dy = yend - ybeg;
- /* dont draw horizontal lines directly, they are scanned as part of the edges they connect, so skip em. :) */
- if (dy) {
- /* create the edge and determine it's slope (for incremental line drawing) */
- e_new = open_edge++;
-
- /* calculate x delta */
- dx = xend - xbeg;
- if (dx > 0) {
- e_new->xdir = 1;
- xdist = dx;
- }
- else {
- e_new->xdir = -1;
- xdist = -dx;
- }
-
- e_new->x = xbeg;
- e_new->ybeg = ybeg;
- e_new->num = dy;
- e_new->drift_dec = dy;
-
- /* calculate deltas for incremental drawing */
- if (dx >= 0) {
- e_new->drift = 0;
- }
- else {
- e_new->drift = -dy + 1;
- }
- if (dy >= xdist) {
- e_new->drift_inc = xdist;
- e_new->xshift = 0;
- }
- else {
- e_new->drift_inc = xdist % dy;
- e_new->xshift = (xdist / dy) * e_new->xdir;
- }
- next_edge_ref = &ctx->all_edges;
- /* link in all the edges, in sorted order */
- for (;;) {
- next_edge = *next_edge_ref;
- if (!next_edge || (next_edge->ybeg > ybeg) || ((next_edge->ybeg == ybeg) && (next_edge->x >= xbeg))) {
- e_new->e_next = next_edge;
- *next_edge_ref = e_new;
- break;
- }
- next_edge_ref = &next_edge->e_next;
- }
- }
- }
-}
-
-/*
- * This function clips drawing to the frame buffer. That clipping will likely be moved into the preprocessor
- * for speed, but waiting on final design choices for curve-data before eliminating data the DEM code will need
- * if it ends up being coupled with this function.
- */
-static int rast_scan_fill(struct r_FillContext *ctx, struct PolyVert *verts, int num_verts, float intensity)
-{
- int x_curr; /* current pixel position in X */
- int y_curr; /* current scan line being drawn */
- int yp; /* y-pixel's position in frame buffer */
- int swixd = 0; /* whether or not edges switched position in X */
- float *cpxl; /* pixel pointers... */
- float *mpxl;
- float *spxl;
- struct e_Status *e_curr; /* edge pointers... */
- struct e_Status *e_temp;
- struct e_Status *edgbuf;
- struct e_Status **edgec;
-
-
- /*
- * If the number of verts specified to render as a polygon is less than 3,
- * return immediately. Obviously we cant render a poly with sides < 3. The
- * return for this we set to 1, simply so it can be distinguished from the
- * next place we could return, /home/guest/blender-svn/soc-2011-tomato/intern/raskter/raskter.
- * which is a failure to allocate memory.
- */
- if (num_verts < 3) {
- return(1);
- }
-
- /*
- * Try to allocate an edge buffer in memory. needs to be the size of the edge tracking data
- * multiplied by the number of edges, which is always equal to the number of verts in
- * a 2D polygon. Here we return 0 to indicate a memory allocation failure, as opposed to a 1 for
- * the preceeding error, which was a rasterization request on a 2D poly with less than
- * 3 sides.
- */
- if ((edgbuf = (struct e_Status *)(malloc(sizeof(struct e_Status) * num_verts))) == NULL) {
- return(0);
- }
-
- /*
- * Do some preprocessing on all edges. This constructs a table structure in memory of all
- * the edge properties and can "flip" some edges so sorting works correctly.
- */
- preprocess_all_edges(ctx, verts, num_verts, edgbuf);
-
- /* can happen with a zero area mask */
- if (ctx->all_edges == NULL) {
- free(edgbuf);
- return(1);
- }
- /*
- * Set the pointer for tracking the edges currently in processing to NULL to make sure
- * we don't get some crazy value after initialization.
- */
- ctx->possible_edges = NULL;
-
- /*
- * Loop through all scan lines to be drawn. Since we sorted by Y values during
- * preprocess_all_edges(), we can already exact values for the lowest and
- * highest Y values we could possibly need by induction. The preprocessing sorted
- * out edges by Y position, we can cycle the current edge being processed once
- * it runs out of Y pixels. When we have no more edges, meaning the current edge
- * is NULL after setting the "current" edge to be the previous current edge's
- * "next" edge in the Y sorted edge connection chain, we can stop looping Y values,
- * since we can't possibly have more scan lines if we ran out of edges. :)
- *
- * TODO: This clips Y to the frame buffer, which should be done in the preprocessor, but for now is done here.
- * Will get changed once DEM code gets in.
- */
- for (y_curr = ctx->all_edges->ybeg; (ctx->all_edges || ctx->possible_edges); y_curr++) {
-
- /*
- * Link any edges that start on the current scan line into the list of
- * edges currently needed to draw at least this, if not several, scan lines.
- */
-
- /*
- * Set the current edge to the beginning of the list of edges to be rasterized
- * into this scan line.
- *
- * We could have lots of edge here, so iterate over all the edges needed. The
- * preprocess_all_edges() function sorted edges by X within each chunk of Y sorting
- * so we safely cycle edges to thier own "next" edges in order.
- *
- * At each iteration, make sure we still have a non-NULL edge.
- */
- for (edgec = &ctx->possible_edges; ctx->all_edges && (ctx->all_edges->ybeg == y_curr);) {
- x_curr = ctx->all_edges->x; /* Set current X position. */
- for (;;) { /* Start looping edges. Will break when edges run out. */
- e_curr = *edgec; /* Set up a current edge pointer. */
- if (!e_curr || (e_curr->x >= x_curr)) { /* If we have an no edge, or we need to skip some X-span, */
- e_temp = ctx->all_edges->e_next; /* set a temp "next" edge to test. */
- *edgec = ctx->all_edges; /* Add this edge to the list to be scanned. */
- ctx->all_edges->e_next = e_curr; /* Set up the next edge. */
- edgec = &ctx->all_edges->e_next; /* Set our list to the next edge's location in memory. */
- ctx->all_edges = e_temp; /* Skip the NULL or bad X edge, set pointer to next edge. */
- break; /* Stop looping edges (since we ran out or hit empty X span. */
- }
- else {
- edgec = &e_curr->e_next; /* Set the pointer to the edge list the "next" edge. */
- }
- }
- }
-
- /*
- * Determine the current scan line's offset in the pixel buffer based on its Y position.
- * Basically we just multiply the current scan line's Y value by the number of pixels in each line.
- */
- yp = y_curr * ctx->rb.sizex;
- /*
- * Set a "scan line pointer" in memory. The location of the buffer plus the row offset.
- */
- spxl = ctx->rb.buf + (yp);
- /*
- * Set up the current edge to the first (in X) edge. The edges which could possibly be in this
- * list were determined in the preceeding edge loop above. They were already sorted in X by the
- * initial processing function.
- *
- * At each iteration, test for a NULL edge. Since we'll keep cycling edge's to their own "next" edge
- * we will eventually hit a NULL when the list runs out.
- */
- for (e_curr = ctx->possible_edges; e_curr; e_curr = e_curr->e_next) {
- /*
- * Calculate a span of pixels to fill on the current scan line.
- *
- * Set the current pixel pointer by adding the X offset to the scan line's start offset.
- * Cycle the current edge the next edge.
- * Set the max X value to draw to be one less than the next edge's first pixel. This way we are
- * sure not to ever get into a situation where we have overdraw. (drawing the same pixel more than
- * one time because it's on a vertex connecting two edges)
- *
- * Then blast through all the pixels in the span, advancing the pointer and setting the color to white.
- *
- * TODO: Here we clip to the scan line, this is not efficient, and should be done in the preprocessor,
- * but for now it is done here until the DEM code comes in.
- */
-
- /* set up xmin and xmax bounds on this scan line */
- cpxl = spxl + MAX2(e_curr->x, 0);
- e_curr = e_curr->e_next;
- mpxl = spxl + MIN2(e_curr->x, ctx->rb.sizex) - 1;
-
- if ((y_curr >= 0) && (y_curr < ctx->rb.sizey)) {
- /* draw the pixels. */
- for (; cpxl <= mpxl; *cpxl++ += intensity) {}
- }
- }
-
- /*
- * Loop through all edges of polygon that could be hit by this scan line,
- * and figure out their x-intersections with the next scan line.
- *
- * Either A.) we wont have any more edges to test, or B.) we just add on the
- * slope delta computed in preprocessing step. Since this draws non-antialiased
- * polygons, we dont have fractional positions, so we only move in x-direction
- * when needed to get all the way to the next pixel over...
- */
- for (edgec = &ctx->possible_edges; (e_curr = *edgec);) {
- if (!(--(e_curr->num))) {
- *edgec = e_curr->e_next;
- }
- else {
- e_curr->x += e_curr->xshift;
- if ((e_curr->drift += e_curr->drift_inc) > 0) {
- e_curr->x += e_curr->xdir;
- e_curr->drift -= e_curr->drift_dec;
- }
- edgec = &e_curr->e_next;
- }
- }
- /*
- * It's possible that some edges may have crossed during the last step, so we'll be sure
- * that we ALWAYS intersect scan lines in order by shuffling if needed to make all edges
- * sorted by x-intersection coordinate. We'll always scan through at least once to see if
- * edges crossed, and if so, we set the 'swixd' flag. If 'swixd' gets set on the initial
- * pass, then we know we need to sort by x, so then cycle through edges again and perform
- * the sort.-
- */
- if (ctx->possible_edges) {
- for (edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
- /* if the current edge hits scan line at greater X than the next edge, we need to exchange the edges */
- if (e_curr->x > e_curr->e_next->x) {
- *edgec = e_curr->e_next;
- /* exchange the pointers */
- e_temp = e_curr->e_next->e_next;
- e_curr->e_next->e_next = e_curr;
- e_curr->e_next = e_temp;
- /* set flag that we had at least one switch */
- swixd = 1;
- }
- }
- /* if we did have a switch, look for more (there will more if there was one) */
- for (;;) {
- /* reset exchange flag so it's only set if we encounter another one */
- swixd = 0;
- for (edgec = &ctx->possible_edges; (e_curr = *edgec)->e_next; edgec = &(*edgec)->e_next) {
- /* again, if current edge hits scan line at higher X than next edge, exchange the edges and set flag */
- if (e_curr->x > e_curr->e_next->x) {
- *edgec = e_curr->e_next;
- /* exchange the pointers */
- e_temp = e_curr->e_next->e_next;
- e_curr->e_next->e_next = e_curr;
- e_curr->e_next = e_temp;
- /* flip the exchanged flag */
- swixd = 1;
- }
- }
- /* if we had no exchanges, we're done reshuffling the pointers */
- if (!swixd) {
- break;
- }
- }
- }
- }
-
- free(edgbuf);
- return 1;
-}
-
-int PLX_raskterize(float(*base_verts)[2], int num_base_verts,
- float *buf, int buf_x, int buf_y)
-{
- int i; /* i: Loop counter. */
- struct PolyVert *ply; /* ply: Pointer to a list of integer buffer-space vertex coordinates. */
- struct r_FillContext ctx = {NULL};
- const float buf_x_f = (float)(buf_x);
- const float buf_y_f = (float)(buf_y);
- /*
- * Allocate enough memory for our PolyVert list. It'll be the size of the PolyVert
- * data structure multiplied by the number of base_verts.
- *
- * In the event of a failure to allocate the memory, return 0, so this error can
- * be distinguished as a memory allocation error.
- */
- if ((ply = (struct PolyVert *)(malloc(sizeof(struct PolyVert) * num_base_verts))) == NULL) {
- return(0);
- }
-
- ctx.rb.buf = buf; /* Set the output buffer pointer. */
- ctx.rb.sizex = buf_x; /* Set the output buffer size in X. (width) */
- ctx.rb.sizey = buf_y; /* Set the output buffer size in Y. (height) */
- /*
- * Loop over all verts passed in to be rasterized. Each vertex's X and Y coordinates are
- * then converted from normalized screen space (0.0 <= POS <= 1.0) to integer coordinates
- * in the buffer-space coordinates passed in inside buf_x and buf_y.
- *
- * It's worth noting that this function ONLY outputs fully white pixels in a mask. Every pixel
- * drawn will be 1.0f in value, there is no anti-aliasing.
- */
-
- for (i = 0; i < num_base_verts; i++) { /* Loop over all base_verts. */
- ply[i].x = (int)((base_verts[i][0] * buf_x_f) + 0.5f); /* Range expand normalized X to integer buffer-space X. */
- ply[i].y = (int)((base_verts[i][1] * buf_y_f) + 0.5f); /* Range expand normalized Y to integer buffer-space Y. */
- }
-
- i = rast_scan_fill(&ctx, ply, num_base_verts,1.0f); /* Call our rasterizer, passing in the integer coords for each vert. */
-
- free(ply); /* Free the memory allocated for the integer coordinate table. */
- return(i); /* Return the value returned by the rasterizer. */
-}
diff --git a/intern/raskter/raskter.h b/intern/raskter/raskter.h
deleted file mode 100644
index cf691a9784b..00000000000
--- a/intern/raskter/raskter.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2012 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Peter Larabell.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-/** \file raskter.h
- * \ingroup RASKTER
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int PLX_raskterize(float (*base_verts)[2], int num_base_verts,
- float *buf, int buf_x, int buf_y);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/intern/rigidbody/SConscript b/intern/rigidbody/SConscript
deleted file mode 100644
index 977281f8eef..00000000000
--- a/intern/rigidbody/SConscript
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/python
-# $Id: SConscript $
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# The Original Code is Copyright (C) 2010, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Joshua Leung
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-# XXX: we need a contingency plan for when not compiling with Bullet,
-# since this module will always get included...
-# This problem will also apply to other engines at a later date too...
-sources = env.Glob('*.cpp')
-
-incs = [
- '.',
- '../../extern/bullet2/src',
- ]
-
-env.BlenderLib('bf_intern_rigidbody', sources=sources,
- includes=incs, defines=[],
- libtype=['core', 'player'], priority=[180, 30])
diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt
index 8cda0fd140f..57678ecf2f8 100644
--- a/intern/smoke/CMakeLists.txt
+++ b/intern/smoke/CMakeLists.txt
@@ -40,7 +40,6 @@ set(SRC
intern/FLUID_3D_SOLVERS.cpp
intern/FLUID_3D_STATIC.cpp
intern/LU_HELPER.cpp
- intern/spectrum.cpp
intern/SPHERE.cpp
intern/WTURBULENCE.cpp
intern/smoke_API.cpp
@@ -54,7 +53,6 @@ set(SRC
intern/LU_HELPER.h
intern/MERSENNETWISTER.h
intern/OBSTACLE.h
- intern/spectrum.h
intern/SPHERE.h
intern/VEC3.h
intern/WAVELET_NOISE.h
diff --git a/intern/smoke/SConscript b/intern/smoke/SConscript
deleted file mode 100644
index c4a579b22b3..00000000000
--- a/intern/smoke/SConscript
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Daniel Genrich
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = ''
-defs = ''
-
-if env['WITH_BF_OPENMP']:
- if env['OURPLATFORM'] == 'linuxcross':
- incs += ' ' + env['BF_OPENMP_INC']
-
- defs += ' PARALLEL=1'
-
-incs += ' ' + env['BF_PNG_INC'] + ' ' + env['BF_ZLIB_INC']
-incs += ' intern ../../extern/bullet2/src ../memutil ../guardealloc '
-
-if env['WITH_BF_FFTW3']:
- defs += ' WITH_FFTW3'
- incs += env['BF_FFTW3_INC']
-
-env.BlenderLib ('bf_intern_smoke', sources, Split(incs), Split(defs), libtype=['intern'], priority=[40] )
diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h
index 08dbded176e..a68a587590f 100644
--- a/intern/smoke/extern/smoke_API.h
+++ b/intern/smoke/extern/smoke_API.h
@@ -99,9 +99,6 @@ void smoke_export(struct FLUID_3D *fluid, float *dt, float *dx, float **dens, fl
void smoke_turbulence_export(struct WTURBULENCE *wt, float **dens, float **react, float **flame, float **fuel,
float **r, float **g, float **b, float **tcu, float **tcv, float **tcw);
-/* flame spectrum */
-void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2);
-
/* data fields */
int smoke_has_heat(struct FLUID_3D *fluid);
int smoke_has_fuel(struct FLUID_3D *fluid);
diff --git a/intern/smoke/intern/MERSENNETWISTER.h b/intern/smoke/intern/MERSENNETWISTER.h
index 5a9ccf88ae7..42b3fe19686 100644
--- a/intern/smoke/intern/MERSENNETWISTER.h
+++ b/intern/smoke/intern/MERSENNETWISTER.h
@@ -187,7 +187,7 @@ inline MTRand::uint32 MTRand::randInt()
if( left == 0 ) reload();
--left;
- register uint32 s1;
+ uint32 s1;
s1 = *pNext++;
s1 ^= (s1 >> 11);
s1 ^= (s1 << 7) & 0x9d2c5680UL;
@@ -232,9 +232,9 @@ inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
// in each element are discarded.
// Just call seed() if you want to get array from /dev/urandom
initialize(19650218UL);
- register int i = 1;
- register uint32 j = 0;
- register int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
+ int i = 1;
+ uint32 j = 0;
+ int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
for( ; k; --k )
{
state[i] =
@@ -273,9 +273,9 @@ inline void MTRand::seed()
if( urandom )
{
uint32 bigSeed[N];
- register uint32 *s = bigSeed;
- register int i = N;
- register bool success = true;
+ uint32 *s = bigSeed;
+ int i = N;
+ bool success = true;
while( success && i-- )
success = fread( s++, sizeof(uint32), 1, urandom );
fclose(urandom);
@@ -294,9 +294,9 @@ inline void MTRand::initialize( const uint32 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.
- register uint32 *s = state;
- register uint32 *r = state;
- register int i = 1;
+ uint32 *s = state;
+ uint32 *r = state;
+ int i = 1;
*s++ = seed & 0xffffffffUL;
for( ; i < N; ++i )
{
@@ -310,8 +310,8 @@ inline void MTRand::reload()
{
// Generate N new values in state
// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
- register uint32 *p = state;
- register int i;
+ uint32 *p = state;
+ int i;
for( i = N - M; i--; ++p )
*p = twist( p[M], p[0], p[1] );
for( i = M; --i; ++p )
@@ -350,9 +350,9 @@ inline MTRand::uint32 MTRand::hash( time_t t, clock_t c )
inline void MTRand::save( uint32* saveArray ) const
{
- register uint32 *sa = saveArray;
- register const uint32 *s = state;
- register int i = N;
+ uint32 *sa = saveArray;
+ const uint32 *s = state;
+ int i = N;
for( ; i--; *sa++ = *s++ ) {}
*sa = left;
}
@@ -360,9 +360,9 @@ inline void MTRand::save( uint32* saveArray ) const
inline void MTRand::load( uint32 *const loadArray )
{
- register uint32 *s = state;
- register uint32 *la = loadArray;
- register int i = N;
+ uint32 *s = state;
+ uint32 *la = loadArray;
+ int i = N;
for( ; i--; *s++ = *la++ ) {}
left = *la;
pNext = &state[N-left];
@@ -371,8 +371,8 @@ inline void MTRand::load( uint32 *const loadArray )
inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
{
- register const MTRand::uint32 *s = mtrand.state;
- register int i = mtrand.N;
+ const MTRand::uint32 *s = mtrand.state;
+ int i = mtrand.N;
for( ; i--; os << *s++ << "\t" ) {}
return os << mtrand.left;
}
@@ -380,8 +380,8 @@ inline std::ostream& operator<<( std::ostream& os, const MTRand& mtrand )
inline std::istream& operator>>( std::istream& is, MTRand& mtrand )
{
- register MTRand::uint32 *s = mtrand.state;
- register int i = mtrand.N;
+ MTRand::uint32 *s = mtrand.state;
+ int i = mtrand.N;
for( ; i--; is >> *s++ ) {}
is >> mtrand.left;
mtrand.pNext = &mtrand.state[mtrand.N-mtrand.left];
diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp
index d79aaf76d56..5cab0b30637 100644
--- a/intern/smoke/intern/smoke_API.cpp
+++ b/intern/smoke/intern/smoke_API.cpp
@@ -30,7 +30,6 @@
#include "FLUID_3D.h"
#include "WTURBULENCE.h"
-#include "spectrum.h"
#include <stdio.h>
#include <stdlib.h>
@@ -449,11 +448,6 @@ extern "C" void smoke_turbulence_set_noise(WTURBULENCE *wt, int type, const char
wt->setNoise(type, noisefile_path);
}
-extern "C" void flame_get_spectrum(unsigned char *spec, int width, float t1, float t2)
-{
- spectrum(t1, t2, width, spec);
-}
-
extern "C" int smoke_has_heat(FLUID_3D *fluid)
{
return (fluid->_heat) ? 1 : 0;
diff --git a/intern/smoke/intern/spectrum.cpp b/intern/smoke/intern/spectrum.cpp
deleted file mode 100644
index 15e4d0cf2e5..00000000000
--- a/intern/smoke/intern/spectrum.cpp
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- Colour Rendering of Spectra
-
- by John Walker
- http://www.fourmilab.ch/
-
- Last updated: March 9, 2003
-
- This program is in the public domain.
-
- For complete information about the techniques employed in
- this program, see the World-Wide Web document:
-
- http://www.fourmilab.ch/documents/specrend/
-
- The xyz_to_rgb() function, which was wrong in the original
- version of this program, was corrected by:
-
- Andrew J. S. Hamilton 21 May 1999
- Andrew.Hamilton@Colorado.EDU
- http://casa.colorado.edu/~ajsh/
-
- who also added the gamma correction facilities and
- modified constrain_rgb() to work by desaturating the
- colour by adding white.
-
- A program which uses these functions to plot CIE
- "tongue" diagrams called "ppmcie" is included in
- the Netpbm graphics toolkit:
- http://netpbm.sourceforge.net/
- (The program was called cietoppm in earlier
- versions of Netpbm.)
-
-*/
-
-#include <stdio.h>
-#include <math.h>
-#include "spectrum.h"
-
-/* A colour system is defined by the CIE x and y coordinates of
- its three primary illuminants and the x and y coordinates of
- the white point. */
-
-struct colourSystem {
- const char *name; /* Colour system name */
- double xRed, yRed, /* Red x, y */
- xGreen, yGreen, /* Green x, y */
- xBlue, yBlue, /* Blue x, y */
- xWhite, yWhite, /* White point x, y */
- gamma; /* Gamma correction for system */
-};
-
-/* White point chromaticities. */
-
-#if 0
-#define IlluminantC 0.3101, 0.3162 /* For NTSC television */
-#define IlluminantD65 0.3127, 0.3291 /* For EBU and SMPTE */
-#endif
-#define IlluminantE 0.33333333, 0.33333333 /* CIE equal-energy illuminant */
-
-/* Gamma of nonlinear correction.
-
- See Charles Poynton's ColorFAQ Item 45 and GammaFAQ Item 6 at:
-
- http://www.poynton.com/ColorFAQ.html
- http://www.poynton.com/GammaFAQ.html
-
-*/
-
-#define GAMMA_REC709 0 /* Rec. 709 */
-
-static struct colourSystem
- /* Name xRed yRed xGreen yGreen xBlue yBlue White point Gamma */
-#if 0 /* UNUSED */
- NTSCsystem = { "NTSC", 0.67, 0.33, 0.21, 0.71, 0.14, 0.08, IlluminantC, GAMMA_REC709 },
- EBUsystem = { "EBU (PAL/SECAM)", 0.64, 0.33, 0.29, 0.60, 0.15, 0.06, IlluminantD65, GAMMA_REC709 },
- SMPTEsystem = { "SMPTE", 0.630, 0.340, 0.310, 0.595, 0.155, 0.070, IlluminantD65, GAMMA_REC709 },
- HDTVsystem = { "HDTV", 0.670, 0.330, 0.210, 0.710, 0.150, 0.060, IlluminantD65, GAMMA_REC709 },
-#endif
-
- CIEsystem = { "CIE", 0.7355, 0.2645, 0.2658, 0.7243, 0.1669, 0.0085, IlluminantE, GAMMA_REC709 };
-
-#if 0 /* UNUSED */
- Rec709system = { "CIE REC 709", 0.64, 0.33, 0.30, 0.60, 0.15, 0.06, IlluminantD65, GAMMA_REC709 };
-#endif
-
-/* UPVP_TO_XY
-
- Given 1976 coordinates u', v', determine 1931 chromaticities x, y
-
-*/
-
-#if 0 /* UNUSED */
-static void upvp_to_xy(double up, double vp, double *xc, double *yc)
-{
- *xc = (9 * up) / ((6 * up) - (16 * vp) + 12);
- *yc = (4 * vp) / ((6 * up) - (16 * vp) + 12);
-}
-#endif
-
-/* XY_TO_UPVP
-
- Given 1931 chromaticities x, y, determine 1976 coordinates u', v'
-
-*/
-
-#if 0 /* UNUSED */
-static void xy_to_upvp(double xc, double yc, double *up, double *vp)
-{
- *up = (4 * xc) / ((-2 * xc) + (12 * yc) + 3);
- *vp = (9 * yc) / ((-2 * xc) + (12 * yc) + 3);
-}
-#endif
-
-/* XYZ_TO_RGB
-
- Given an additive tricolour system CS, defined by the CIE x
- and y chromaticities of its three primaries (z is derived
- trivially as 1-(x+y)), and a desired chromaticity (XC, YC,
- ZC) in CIE space, determine the contribution of each
- primary in a linear combination which sums to the desired
- chromaticity. If the requested chromaticity falls outside
- the Maxwell triangle (colour gamut) formed by the three
- primaries, one of the r, g, or b weights will be negative.
-
- Caller can use constrain_rgb() to desaturate an
- outside-gamut colour to the closest representation within
- the available gamut and/or norm_rgb to normalise the RGB
- components so the largest nonzero component has value 1.
-
-*/
-
-static void xyz_to_rgb(struct colourSystem *cs,
- double xc, double yc, double zc,
- double *r, double *g, double *b)
-{
- double xr, yr, zr, xg, yg, zg, xb, yb, zb;
- double xw, yw, zw;
- double rx, ry, rz, gx, gy, gz, bx, by, bz;
- double rw, gw, bw;
-
- xr = cs->xRed; yr = cs->yRed; zr = 1 - (xr + yr);
- xg = cs->xGreen; yg = cs->yGreen; zg = 1 - (xg + yg);
- xb = cs->xBlue; yb = cs->yBlue; zb = 1 - (xb + yb);
-
- xw = cs->xWhite; yw = cs->yWhite; zw = 1 - (xw + yw);
-
- /* xyz -> rgb matrix, before scaling to white. */
-
- rx = (yg * zb) - (yb * zg); ry = (xb * zg) - (xg * zb); rz = (xg * yb) - (xb * yg);
- gx = (yb * zr) - (yr * zb); gy = (xr * zb) - (xb * zr); gz = (xb * yr) - (xr * yb);
- bx = (yr * zg) - (yg * zr); by = (xg * zr) - (xr * zg); bz = (xr * yg) - (xg * yr);
-
- /* White scaling factors.
- Dividing by yw scales the white luminance to unity, as conventional. */
-
- rw = ((rx * xw) + (ry * yw) + (rz * zw)) / yw;
- gw = ((gx * xw) + (gy * yw) + (gz * zw)) / yw;
- bw = ((bx * xw) + (by * yw) + (bz * zw)) / yw;
-
- /* xyz -> rgb matrix, correctly scaled to white. */
-
- rx = rx / rw; ry = ry / rw; rz = rz / rw;
- gx = gx / gw; gy = gy / gw; gz = gz / gw;
- bx = bx / bw; by = by / bw; bz = bz / bw;
-
- /* rgb of the desired point */
-
- *r = (rx * xc) + (ry * yc) + (rz * zc);
- *g = (gx * xc) + (gy * yc) + (gz * zc);
- *b = (bx * xc) + (by * yc) + (bz * zc);
-}
-
-/* INSIDE_GAMUT
-
- Test whether a requested colour is within the gamut
- achievable with the primaries of the current colour
- system. This amounts simply to testing whether all the
- primary weights are non-negative. */
-
-#if 0 /* UNUSED */
-static int inside_gamut(double r, double g, double b)
-{
- return (r >= 0) && (g >= 0) && (b >= 0);
-}
-#endif
-
-/* CONSTRAIN_RGB
-
- If the requested RGB shade contains a negative weight for
- one of the primaries, it lies outside the colour gamut
- accessible from the given triple of primaries. Desaturate
- it by adding white, equal quantities of R, G, and B, enough
- to make RGB all positive. The function returns 1 if the
- components were modified, zero otherwise.
-
-*/
-
-static int constrain_rgb(double *r, double *g, double *b)
-{
- double w;
-
- /* Amount of white needed is w = - min(0, *r, *g, *b) */
-
- w = (0 < *r) ? 0 : *r;
- w = (w < *g) ? w : *g;
- w = (w < *b) ? w : *b;
- w = -w;
-
- /* Add just enough white to make r, g, b all positive. */
-
- if (w > 0) {
- *r += w; *g += w; *b += w;
- return 1; /* Colour modified to fit RGB gamut */
- }
-
- return 0; /* Colour within RGB gamut */
-}
-
-/* GAMMA_CORRECT_RGB
-
- Transform linear RGB values to nonlinear RGB values. Rec.
- 709 is ITU-R Recommendation BT. 709 (1990) ``Basic
- Parameter Values for the HDTV Standard for the Studio and
- for International Programme Exchange'', formerly CCIR Rec.
- 709. For details see
-
- http://www.poynton.com/ColorFAQ.html
- http://www.poynton.com/GammaFAQ.html
-*/
-
-#if 0 /* UNUSED */
-static void gamma_correct(const struct colourSystem *cs, double *c)
-{
- double gamma;
-
- gamma = cs->gamma;
-
- if (gamma == GAMMA_REC709) {
- /* Rec. 709 gamma correction. */
- double cc = 0.018;
-
- if (*c < cc) {
- *c *= ((1.099 * pow(cc, 0.45)) - 0.099) / cc;
- } else {
- *c = (1.099 * pow(*c, 0.45)) - 0.099;
- }
- } else {
- /* Nonlinear colour = (Linear colour)^(1/gamma) */
- *c = pow(*c, 1.0 / gamma);
- }
-}
-
-static void gamma_correct_rgb(const struct colourSystem *cs, double *r, double *g, double *b)
-{
- gamma_correct(cs, r);
- gamma_correct(cs, g);
- gamma_correct(cs, b);
-}
-#endif
-
-/* NORM_RGB
-
- Normalise RGB components so the most intense (unless all
- are zero) has a value of 1.
-
-*/
-
-static void norm_rgb(double *r, double *g, double *b)
-{
-#define Max(a, b) (((a) > (b)) ? (a) : (b))
- double greatest = Max(*r, Max(*g, *b));
-
- if (greatest > 0) {
- *r /= greatest;
- *g /= greatest;
- *b /= greatest;
- }
-#undef Max
-}
-
-/* SPECTRUM_TO_XYZ
-
- Calculate the CIE X, Y, and Z coordinates corresponding to
- a light source with spectral distribution given by the
- function SPEC_INTENS, which is called with a series of
- wavelengths between 380 and 780 nm (the argument is
- expressed in meters), which returns emittance at that
- wavelength in arbitrary units. The chromaticity
- coordinates of the spectrum are returned in the x, y, and z
- arguments which respect the identity:
-
- x + y + z = 1.
-*/
-
-static void spectrum_to_xyz(double (*spec_intens)(double wavelength),
- double *x, double *y, double *z)
-{
- int i;
- double lambda, X = 0, Y = 0, Z = 0, XYZ;
-
- /* CIE colour matching functions xBar, yBar, and zBar for
- wavelengths from 380 through 780 nanometers, every 5
- nanometers. For a wavelength lambda in this range:
-
- cie_colour_match[(lambda - 380) / 5][0] = xBar
- cie_colour_match[(lambda - 380) / 5][1] = yBar
- cie_colour_match[(lambda - 380) / 5][2] = zBar
-
- To save memory, this table can be declared as floats
- rather than doubles; (IEEE) float has enough
- significant bits to represent the values. It's declared
- as a double here to avoid warnings about "conversion
- between floating-point types" from certain persnickety
- compilers. */
-
- static double cie_colour_match[81][3] = {
- {0.0014,0.0000,0.0065}, {0.0022,0.0001,0.0105}, {0.0042,0.0001,0.0201},
- {0.0076,0.0002,0.0362}, {0.0143,0.0004,0.0679}, {0.0232,0.0006,0.1102},
- {0.0435,0.0012,0.2074}, {0.0776,0.0022,0.3713}, {0.1344,0.0040,0.6456},
- {0.2148,0.0073,1.0391}, {0.2839,0.0116,1.3856}, {0.3285,0.0168,1.6230},
- {0.3483,0.0230,1.7471}, {0.3481,0.0298,1.7826}, {0.3362,0.0380,1.7721},
- {0.3187,0.0480,1.7441}, {0.2908,0.0600,1.6692}, {0.2511,0.0739,1.5281},
- {0.1954,0.0910,1.2876}, {0.1421,0.1126,1.0419}, {0.0956,0.1390,0.8130},
- {0.0580,0.1693,0.6162}, {0.0320,0.2080,0.4652}, {0.0147,0.2586,0.3533},
- {0.0049,0.3230,0.2720}, {0.0024,0.4073,0.2123}, {0.0093,0.5030,0.1582},
- {0.0291,0.6082,0.1117}, {0.0633,0.7100,0.0782}, {0.1096,0.7932,0.0573},
- {0.1655,0.8620,0.0422}, {0.2257,0.9149,0.0298}, {0.2904,0.9540,0.0203},
- {0.3597,0.9803,0.0134}, {0.4334,0.9950,0.0087}, {0.5121,1.0000,0.0057},
- {0.5945,0.9950,0.0039}, {0.6784,0.9786,0.0027}, {0.7621,0.9520,0.0021},
- {0.8425,0.9154,0.0018}, {0.9163,0.8700,0.0017}, {0.9786,0.8163,0.0014},
- {1.0263,0.7570,0.0011}, {1.0567,0.6949,0.0010}, {1.0622,0.6310,0.0008},
- {1.0456,0.5668,0.0006}, {1.0026,0.5030,0.0003}, {0.9384,0.4412,0.0002},
- {0.8544,0.3810,0.0002}, {0.7514,0.3210,0.0001}, {0.6424,0.2650,0.0000},
- {0.5419,0.2170,0.0000}, {0.4479,0.1750,0.0000}, {0.3608,0.1382,0.0000},
- {0.2835,0.1070,0.0000}, {0.2187,0.0816,0.0000}, {0.1649,0.0610,0.0000},
- {0.1212,0.0446,0.0000}, {0.0874,0.0320,0.0000}, {0.0636,0.0232,0.0000},
- {0.0468,0.0170,0.0000}, {0.0329,0.0119,0.0000}, {0.0227,0.0082,0.0000},
- {0.0158,0.0057,0.0000}, {0.0114,0.0041,0.0000}, {0.0081,0.0029,0.0000},
- {0.0058,0.0021,0.0000}, {0.0041,0.0015,0.0000}, {0.0029,0.0010,0.0000},
- {0.0020,0.0007,0.0000}, {0.0014,0.0005,0.0000}, {0.0010,0.0004,0.0000},
- {0.0007,0.0002,0.0000}, {0.0005,0.0002,0.0000}, {0.0003,0.0001,0.0000},
- {0.0002,0.0001,0.0000}, {0.0002,0.0001,0.0000}, {0.0001,0.0000,0.0000},
- {0.0001,0.0000,0.0000}, {0.0001,0.0000,0.0000}, {0.0000,0.0000,0.0000}
- };
-
- for (i = 0, lambda = 380; lambda < 780.1; i++, lambda += 5) {
- double Me;
-
- Me = (*spec_intens)(lambda);
- X += Me * cie_colour_match[i][0];
- Y += Me * cie_colour_match[i][1];
- Z += Me * cie_colour_match[i][2];
- }
- XYZ = (X + Y + Z);
- *x = X / XYZ;
- *y = Y / XYZ;
- *z = Z / XYZ;
-}
-
-/* BB_SPECTRUM
-
- Calculate, by Planck's radiation law, the emittance of a black body
- of temperature bbTemp at the given wavelength (in metres). */
-
-static double bbTemp = 5000; /* Hidden temperature argument
- to BB_SPECTRUM. */
-static double bb_spectrum(double wavelength)
-{
- double wlm = wavelength * 1e-9; /* Wavelength in meters */
-
- return (3.74183e-16 * pow(wlm, -5.0)) /
- (exp(1.4388e-2 / (wlm * bbTemp)) - 1.0);
-}
-
-static void xyz_to_lms(double x, double y, double z, double* l, double* m, double* s)
-{
- *l = 0.3897*x + 0.6890*y - 0.0787*z;
- *m = -0.2298*x + 1.1834*y + 0.0464*z;
- *s = z;
-}
-
-static void lms_to_xyz(double l, double m, double s, double* x, double *y, double* z)
-{
- *x = 1.9102*l - 1.1121*m + 0.2019*s;
- *y = 0.3709*l + 0.6290*m + 0.0000*s;
- *z = s;
-}
-
-void spectrum(double t1, double t2, int N, unsigned char *d)
-{
- int i,j,dj;
- double X,Y,Z,R,G,B,L,M,S, Lw, Mw, Sw;
- struct colourSystem *cs = &CIEsystem;
-
- j = 0; dj = 1;
- if (t1<t2) {
- double t = t1;
- t1 = t2;
- t2 = t;
- j = N-1; dj=-1;
- }
-
- for (i=0; i<N; i++) {
- bbTemp = t1 + (t2-t1)/N*i;
-
- // integrate blackbody radiation spectrum to XYZ
- spectrum_to_xyz(bb_spectrum, &X, &Y, &Z);
-
- // normalize highest temperature to white (in LMS system)
- xyz_to_lms(X,Y,Z,&L,&M,&S);
- if (i==0) {
- Lw=1/L; Mw=1/M; Sw=1/S;
- }
- L *= Lw; M *= Mw; S *= Sw;
- lms_to_xyz(L,M,S,&X,&Y,&Z);
-
- // convert to RGB
- xyz_to_rgb(cs, X, Y, Z, &R, &G, &B);
- constrain_rgb(&R, &G, &B);
- norm_rgb(&R, &G, &B);
- d[(j<<2)] = (unsigned char) ((double)R*255);
- d[(j<<2)+1] = (unsigned char) ((double)G*255);
- d[(j<<2)+2] = (unsigned char) ((double)B*255);
- d[(j<<2)+3] = (B>0.1)? B*255 : 0;
- j += dj;
- }
-}
diff --git a/intern/smoke/intern/spectrum.h b/intern/smoke/intern/spectrum.h
deleted file mode 100644
index 3ffd41f9517..00000000000
--- a/intern/smoke/intern/spectrum.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPECTRUM_H
-#define __SPECTRUM_H
-
-void spectrum(double t1, double t2, int n, unsigned char *d);
-
-#endif
diff --git a/intern/string/SConscript b/intern/string/SConscript
deleted file mode 100644
index 8e14605b15d..00000000000
--- a/intern/string/SConscript
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-incs = '.'
-
-defs = []
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
- incs += ' #intern/guardedalloc'
-
-env.BlenderLib ('bf_intern_string', sources, Split(incs), defs, libtype=['intern','player'], priority = [50,10] )
diff --git a/intern/utfconv/SConscript b/intern/utfconv/SConscript
deleted file mode 100644
index 875f6154d55..00000000000
--- a/intern/utfconv/SConscript
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = ['utfconv.c']
-
-incs = '.'
-defs = ''
-
-# This is odd but leave it for now...
-# Why have win32 check here? - this is only used for windows.
-# ... because one day we might want to use it on other platforms.
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'):
- sources += ['utf_winfunc.c']
-
-env.BlenderLib('bf_utfconv', sources, Split(incs), Split(defs), libtype=['intern','player'], priority=[0,0])
diff --git a/make.bat b/make.bat
new file mode 100644
index 00000000000..b4cbe8c11e9
--- /dev/null
+++ b/make.bat
@@ -0,0 +1,171 @@
+@echo off
+REM This batch file does an out-of-source CMake build in ../build_windows
+REM This is for users who like to configure & build Blender with a single command.
+
+setlocal ENABLEEXTENSIONS
+set BLENDER_DIR=%~dp0
+set BUILD_DIR=%BLENDER_DIR%..\build_windows
+set BUILD_TYPE=Release
+set BUILD_CMAKE_ARGS=
+
+REM Detect MSVC Installation
+if DEFINED VisualStudioVersion goto msvc_detect_finally
+set VALUE_NAME=ProductDir
+REM Check 64 bits
+set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0\Setup\VC"
+for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C
+if DEFINED MSVC_VC_DIR goto msvc_detect_finally
+REM Check 32 bits
+set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\12.0\Setup\VC"
+for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C
+if DEFINED MSVC_VC_DIR goto msvc_detect_finally
+:msvc_detect_finally
+if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat"
+
+
+REM Sanity Checks
+where /Q msbuild
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: "MSBuild" command not in the PATH.
+ echo You must have MSVC installed and run this from the "Developer Command Prompt"
+ echo ^(available from Visual Studio's Start menu entry^), aborting!
+ goto EOF
+)
+where /Q cmake
+if %ERRORLEVEL% NEQ 0 (
+ echo Error: "CMake" command not in the PATH.
+ echo You must have CMake installed and added to your PATH, aborting!
+ goto EOF
+)
+if NOT EXIST %BLENDER_DIR%..\lib\nul (
+ echo Error: Path to libraries not found "%BLENDER_DIR%..\lib\"
+ echo This is needed for building, aborting!
+ goto EOF
+)
+
+
+:argv_loop
+if NOT "%1" == "" (
+
+ REM Help Message
+ if "%1" == "help" (
+ echo.
+ echo Convenience targets
+ echo - debug
+ echo - full
+ echo - lite
+ echo - headless
+ echo - cycles
+ echo - bpy
+ echo.
+ echo Utilities ^(not associated with building^)
+ echo - clean
+ echo - update
+ goto EOF
+ )
+
+ REM Build Types
+ if "%1" == "debug" (
+ set BUILD_DIR=%BUILD_DIR%_debug
+ set BUILD_TYPE=Debug
+
+ REM Build Configurations
+ ) else if "%1" == "full" (
+ set BUILD_DIR=%BUILD_DIR%_full
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
+ -C"%BLENDER_DIR%\build_files\cmake\config\blender_full.cmake"
+ ) else if "%1" == "lite" (
+ set BUILD_DIR=%BUILD_DIR%_lite
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
+ -C"%BLENDER_DIR%\build_files\cmake\config\blender_lite.cmake"
+ ) else if "%1" == "cycles" (
+ set BUILD_DIR=%BUILD_DIR%_cycles
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
+ -C"%BLENDER_DIR%\build_files\cmake\config\cycles_standalone.cmake"
+ ) else if "%1" == "headless" (
+ set BUILD_DIR=%BUILD_DIR%_headless
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
+ -C"%BLENDER_DIR%\build_files\cmake\config\blender_headless.cmake"
+ ) else if "%1" == "bpy" (
+ set BUILD_DIR=%BUILD_DIR%_bpy
+ set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^
+ -C"%BLENDER_DIR%\build_files\cmake\config\bpy_module.cmake"
+
+ REM Non-Build Commands
+ ) else if "%1" == "update" (
+ svn up ../lib/*
+ git pull --rebase
+ git submodule foreach git pull --rebase origin master
+ goto EOF
+ ) else if "%1" == "clean" (
+ msbuild ^
+ %BUILD_DIR%\Blender.sln ^
+ /target:clean ^
+ /property:Configuration=%BUILD_TYPE% ^
+ /verbosity:minimal
+ if %ERRORLEVEL% NEQ 0 (
+ echo Cleaned "%BUILD_DIR%"
+ )
+ goto EOF
+ ) else (
+ echo Command "%1" unknown, aborting!
+ goto EOF
+ )
+
+ shift /1
+ goto argv_loop
+)
+
+if "%PROCESSOR_ARCHITECTURE%" == "AMD64" (
+ set WINDOWS_ARCH=Win64
+) else if "%PROCESSOR_ARCHITEW6432%" == "AMD64" (
+ set WINDOWS_ARCH=Win64
+) else (
+ set WINDOWS_ARCH=
+)
+
+set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio 12 2013 %WINDOWS_ARCH%"
+if NOT EXIST %BUILD_DIR%\nul (
+ mkdir %BUILD_DIR%
+)
+
+REM Only configure on first run
+if NOT EXIST %BUILD_DIR%\Blender.sln (
+ cmake ^
+ %BUILD_CMAKE_ARGS% ^
+ -H%BLENDER_DIR% ^
+ -B%BUILD_DIR% ^
+ %BUILD_CMAKE_ARGS%
+
+ if %ERRORLEVEL% NEQ 0 (
+ echo "Configuration Failed"
+ goto EOF
+ )
+)
+
+msbuild ^
+ %BUILD_DIR%\Blender.sln ^
+ /target:build ^
+ /property:Configuration=%BUILD_TYPE% ^
+ /maxcpucount ^
+ /verbosity:minimal
+
+if %ERRORLEVEL% NEQ 0 (
+ echo "Build Failed"
+ goto EOF
+)
+
+msbuild ^
+ %BUILD_DIR%\INSTALL.vcxproj ^
+ /property:Configuration=%BUILD_TYPE% ^
+ /verbosity:minimal
+
+echo.
+echo At any point you can optionally modify your build configuration by editing:
+echo "%BUILD_DIR%\CMakeCache.txt", then run "make" again to build with the changes applied.
+echo.
+echo Blender successfully built, run from: "%BUILD_DIR%\bin\%BUILD_TYPE%"
+echo.
+
+:EOF
+
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index 1923b93577a..40b974661fa 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -30937,6 +30937,26 @@
fx="139"
fy="137.5"
r="7" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient1610"
+ id="linearGradient31208"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-41,98)"
+ x1="-170.25"
+ y1="65.5"
+ x2="-181.375"
+ y2="65.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient319"
+ id="linearGradient31210"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2857143,0,0,0.787037,-92.714287,177.80092)"
+ x1="-101"
+ y1="-16"
+ x2="-93.75"
+ y2="-16.264704" />
</defs>
<sodipodi:namedview
id="base"
@@ -91924,6 +91944,36 @@
</g>
</g>
</g>
+ <g
+ style="display:inline;enable-background:new"
+ id="ICON_MESH_CAPSULE"
+ transform="matrix(0.86967262,0,0,0.81949894,414.30767,262.03112)">
+ <rect
+ y="155"
+ x="-228"
+ height="16"
+ width="16"
+ id="rect41297-1"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cccsccc"
+ id="path41299-4"
+ d="m -220,154.54901 c -3.036,0 -5.49999,3.07099 -5.49999,4.45099 l -1e-5,9 c 0,1.38 2.46399,4.41118 5.49999,4.41118 3.036,0 5.5,-3.03118 5.5,-4.41118 l 1e-5,-9 c 0,-1.38 -2.464,-4.45099 -5.5,-4.45099 z"
+ style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient31208);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;marker:none;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m -220,154.19066 c -3.49999,0 -5.36123,3.42934 -5.36123,4.80934 l -1e-5,8.5 c 0,2 2.32523,5.30934 5.36123,5.30934 3.036,0 5.36125,-3.30934 5.36125,-5.30934 l 0,-8.5 c 0,-1.38 -1.86123,-4.80934 -5.36124,-4.80934 z"
+ id="path41305-2"
+ sodipodi:nodetypes="cccsccc"
+ inkscape:connector-curvature="0" />
+ <path
+ style="display:inline;overflow:visible;visibility:visible;fill:none;stroke:url(#linearGradient31210);stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m -224.5,160.5 0,6.5 c 0,0.9838 0.60816,4.76952 4.46531,4.76952 3.85714,0 4.53469,-3.78572 4.53469,-4.76952 l 0,-6.5 c 0,0 0.43828,-5.18967 -4.47408,-5.25396 C -224.88644,155.18174 -224.5,160.5 -224.5,160.5 Z"
+ id="path41307-2"
+ sodipodi:nodetypes="ccsccsc"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
<g
inkscape:groupmode="layer"
diff --git a/release/datafiles/blender_icons16/icon16_mesh_capsule.dat b/release/datafiles/blender_icons16/icon16_mesh_capsule.dat
new file mode 100644
index 00000000000..031cac70eea
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_mesh_capsule.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_mesh_capsule.dat b/release/datafiles/blender_icons32/icon32_mesh_capsule.dat
new file mode 100644
index 00000000000..213ef4281e1
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_mesh_capsule.dat
Binary files differ
diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio
index 1cf9a3bb36e..c2bfd3bca10 100644
--- a/release/datafiles/colormanagement/config.ocio
+++ b/release/datafiles/colormanagement/config.ocio
@@ -1,6 +1,8 @@
# OpenColorIO configuration file for Blender
#
# Based on aces, nuke-default and spi configurations from OpenColorIO-Config
+#
+# See ocio-license.txt for details.
ocio_profile_version: 1
diff --git a/release/datafiles/datatoc.py b/release/datafiles/datatoc.py
deleted file mode 100755
index 0caef70c912..00000000000
--- a/release/datafiles/datatoc.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2009 Blender Foundation.
-# All rights reserved.
-#
-# Contributor(s): Jörg Müller
-#
-# ***** END GPL LICENCE BLOCK *****
-
-# <pep8 compliant>
-
-import sys
-import os
-
-if len(sys.argv) < 2:
- sys.stdout.write("Usage: datatoc <data_file>\n")
- sys.exit(1)
-
-filename = sys.argv[1]
-
-try:
- fpin = open(filename, "rb")
-except:
- sys.stdout.write("Unable to open input %s\n" % sys.argv[1])
- sys.exit(1)
-
-fpin.seek(0, os.SEEK_END)
-size = fpin.tell()
-fpin.seek(0)
-
-if filename[0:2] == "." + os.sep:
- filename = filename[2:]
-
-cname = filename + ".c"
-sys.stdout.write("Making C file <%s>\n" % cname)
-
-filename = filename.split("/")[-1].split("\\")[-1]
-filename = filename.replace(".", "_")
-sys.stdout.write("%d\n" % size)
-
-try:
- fpout = open(cname, "w")
-except:
- sys.stdout.write("Unable to open output %s\n" % cname)
- sys.exit(1)
-
-fpout.write("/* DataToC output of file <%s> */\n\n" % filename)
-fpout.write("int datatoc_%s_size = %d;\n" % (filename, size))
-
-fpout.write("char datatoc_%s[] = {\n" % filename)
-
-while size > 0:
- size -= 1
- if size % 32 == 31:
- fpout.write("\n")
-
- fpout.write("%3d," % ord(fpin.read(1)))
-
-fpout.write("\n 0};\n\n")
-
-fpin.close()
-fpout.close()
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject de6c83e12e75ffaac90eddbd3cb7451b57c2e0c
+Subproject 9628dc1922be2fb6281bc66f5f7512c2a57c294
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index f84f092d5f8..fa893b4be0d 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png
index f4c611c8cc1..f8dd2bbeaf3 100644
--- a/release/datafiles/splash_2x.png
+++ b/release/datafiles/splash_2x.png
Binary files differ
diff --git a/release/environment-macosx b/release/environment-macosx
deleted file mode 100644
index d41d5ec485f..00000000000
--- a/release/environment-macosx
+++ /dev/null
@@ -1,18 +0,0 @@
-# This is a Blender Environment Variable config file.
-#
-# Comment lines start with "#", other lines will be split at the "="
-# and the part before will be used as env var name and the part after
-# as env var value. The value can make reference to previous or
-# prelaunch variables with "${}" and the content will be replaced.
-# Once set, values of variables will not be overwritten.
-#
-# BLENDER_SHARE should be /Library/Application Support/Blender for typical installs.
-# BLENDER_VERSION will be set by the program before processing this file.
-BLENDER_USER_BASE=${HOME}/Library/Application Support/Blender/${BLENDER_VERSION}
-BLENDER_SYSTEM_BASE=${BLENDER_SHARE}/${BLENDER_VERSION}
-BLENDER_USER_DATAFILES=${HOME}/Library/Application Support/Blender/${BLENDER_VERSION}/datafiles
-BLENDER_SYSTEM_DATAFILES=${BLENDER_SHARE}/${BLENDER_VERSION}/datafiles
-BLENDER_USER_PY=${HOME}/Library/Application Support/Blender/${BLENDER_VERSION}/py
-BLENDER_SYSTEM_PY=${BLENDER_SHARE}/${BLENDER_VERSION}/py
-BLENDER_USER_PLUGINS=${HOME}/Library/Application Support/Blender/${BLENDER_VERSION}/plugins
-BLENDER_SYSTEM_PLUGINS=${BLENDER_SHARE}/${BLENDER_VERSION}/plugins
diff --git a/release/environment-mswindows b/release/environment-mswindows
deleted file mode 100644
index 41308533e0b..00000000000
--- a/release/environment-mswindows
+++ /dev/null
@@ -1,18 +0,0 @@
-# This is a Blender Environment Variable config file.
-#
-# Comment lines start with "#", other lines will be split at the "="
-# and the part before will be used as env var name and the part after
-# as env var value. The value can make reference to previous or
-# prelaunch variables with "%%" and the content will be replaced.
-# Once set, values of variables will not be overwritten.
-#
-# BLENDER_SHARE should be COMMON_APPDATA\\Blender Foundation\\Blender for typical installs.
-# BLENDER_VERSION will be set by the program before processing this file.
-BLENDER_USER_BASE=%USERPROFILE%\\Blender Foundation\\Blender\\%BLENDER_VERSION%
-BLENDER_SYSTEM_BASE=%BLENDER_SHARE%\\%BLENDER_VERSION%
-BLENDER_USER_DATAFILES=%USERPROFILE%\\Blender Foundation\\%BLENDER_VERSION%\\datafiles
-BLENDER_SYSTEM_DATAFILES=%BLENDER_SHARE%\\%BLENDER_VERSION%\\datafiles
-BLENDER_USER_PY=%USERPROFILE%\\Blender Foundation\\%BLENDER_VERSION%\\py
-BLENDER_SYSTEM_PY=%BLENDER_SHARE%\\%BLENDER_VERSION%\\py
-BLENDER_USER_PLUGINS=%USERPROFILE%\\Blender Foundation\\%BLENDER_VERSION%\\plugins
-BLENDER_SYSTEM_PLUGINS=%BLENDER_SHARE%\\%BLENDER_VERSION%\\plugins
diff --git a/release/environment-unix b/release/environment-unix
deleted file mode 100644
index 8a13c288306..00000000000
--- a/release/environment-unix
+++ /dev/null
@@ -1,18 +0,0 @@
-# This is a Blender Environment Variable config file.
-#
-# Comment lines start with "#", other lines will be split at the "="
-# and the part before will be used as env var name and the part after
-# as env var value. The value can make reference to previous or
-# prelaunch variables with "${}" and the content will be replaced.
-# Once set, values of variables will not be overwritten.
-#
-# BLENDER_SHARE should be /usr/share/blender for typical distro installs.
-# BLENDER_VERSION will be set by the program before processing this file.
-BLENDER_USER_BASE=${HOME}/.blender/${BLENDER_VERSION}
-BLENDER_SYSTEM_BASE=${BLENDER_SHARE}/${BLENDER_VERSION}
-BLENDER_USER_DATAFILES=${HOME}/.blender/${BLENDER_VERSION}/datafiles
-BLENDER_SYSTEM_DATAFILES=${BLENDER_SHARE}/${BLENDER_VERSION}/datafiles
-BLENDER_USER_PY=${HOME}/.blender/${BLENDER_VERSION}/py
-BLENDER_SYSTEM_PY=${BLENDER_SHARE}/${BLENDER_VERSION}/py
-BLENDER_USER_PLUGINS=${HOME}/.blender/${BLENDER_VERSION}/plugins
-BLENDER_SYSTEM_PLUGINS=${BLENDER_SHARE}/${BLENDER_VERSION}/plugins
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 94c9c4ee3370d1feb42fc978a1f0d2db07cb943
+Subproject 407d0ea752b3af73d3f13ba072671bd09eefecb
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject e31cec5bf243f00441c7dad7a775ec4722f829d
+Subproject 9f29e18707917ec5be262431d2e09dbb85332f4
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index fe6c6f641ac..082ce139a59 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -1406,10 +1406,11 @@ def process(layer_name, lineset_name):
shaders_list.append(ColorDistanceFromCameraShader(
m.blend, m.influence, m.color_ramp,
m.range_min, m.range_max))
- elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None:
- shaders_list.append(ColorDistanceFromObjectShader(
- m.blend, m.influence, m.color_ramp, m.target,
- m.range_min, m.range_max))
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ if m.target is not None:
+ shaders_list.append(ColorDistanceFromObjectShader(
+ m.blend, m.influence, m.color_ramp, m.target,
+ m.range_min, m.range_max))
elif m.type == 'MATERIAL':
shaders_list.append(ColorMaterialShader(
m.blend, m.influence, m.color_ramp, m.material_attribute,
@@ -1439,10 +1440,11 @@ def process(layer_name, lineset_name):
shaders_list.append(AlphaDistanceFromCameraShader(
m.blend, m.influence, m.mapping, m.invert, m.curve,
m.range_min, m.range_max))
- elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None:
- shaders_list.append(AlphaDistanceFromObjectShader(
- m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
- m.range_min, m.range_max))
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ if m.target is not None:
+ shaders_list.append(AlphaDistanceFromObjectShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+ m.range_min, m.range_max))
elif m.type == 'MATERIAL':
shaders_list.append(AlphaMaterialShader(
m.blend, m.influence, m.mapping, m.invert, m.curve,
@@ -1475,11 +1477,12 @@ def process(layer_name, lineset_name):
thickness_position, linestyle.thickness_ratio,
m.blend, m.influence, m.mapping, m.invert, m.curve,
m.range_min, m.range_max, m.value_min, m.value_max))
- elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None:
- shaders_list.append(ThicknessDistanceFromObjectShader(
- thickness_position, linestyle.thickness_ratio,
- m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
- m.range_min, m.range_max, m.value_min, m.value_max))
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ if m.target is not None:
+ shaders_list.append(ThicknessDistanceFromObjectShader(
+ thickness_position, linestyle.thickness_ratio,
+ m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+ m.range_min, m.range_max, m.value_min, m.value_max))
elif m.type == 'MATERIAL':
shaders_list.append(ThicknessMaterialShader(
thickness_position, linestyle.thickness_ratio,
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 123b3cb953c..95c0e5f187d 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -193,7 +193,7 @@ def modules_refresh(module_cache=addons_fake_modules):
del modules_stale
-def modules(module_cache=addons_fake_modules, refresh=True):
+def modules(module_cache=addons_fake_modules, *, refresh=True):
if refresh or ((module_cache is addons_fake_modules) and modules._is_first):
modules_refresh(module_cache)
modules._is_first = False
@@ -255,12 +255,18 @@ def _addon_remove(module_name):
addons.remove(addon)
-def enable(module_name, default_set=False, persistent=False, handle_error=None):
+def enable(module_name, *, default_set=False, persistent=False, handle_error=None):
"""
Enables an addon by name.
- :arg module_name: The name of the addon and module.
+ :arg module_name: the name of the addon and module.
:type module_name: string
+ :arg default_set: Set the user-preference.
+ :type default_set: bool
+ :arg persistent: Ensure the addon is enabled for the entire session (after loading new files).
+ :type persistent: bool
+ :arg handle_error: Called in the case of an error, taking an exception argument.
+ :type handle_error: function
:return: the loaded module or None on failure.
:rtype: module
"""
@@ -270,7 +276,7 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
from bpy_restrict_state import RestrictBlend
if handle_error is None:
- def handle_error():
+ def handle_error(ex):
import traceback
traceback.print_exc()
@@ -286,10 +292,10 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
# in most cases the caller should 'check()' first.
try:
mod.unregister()
- except:
+ except Exception as ex:
print("Exception in module unregister(): %r" %
getattr(mod, "__file__", module_name))
- handle_error()
+ handle_error(ex)
return None
mod.__addon_enabled__ = False
@@ -301,8 +307,8 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
try:
importlib.reload(mod)
- except:
- handle_error()
+ except Exception as ex:
+ handle_error(ex)
del sys.modules[module_name]
return None
mod.__addon_enabled__ = False
@@ -329,7 +335,7 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
if type(ex) is ImportError and ex.name == module_name:
print("addon not found: %r" % module_name)
else:
- handle_error()
+ handle_error(ex)
if default_set:
_addon_remove(module_name)
@@ -341,10 +347,10 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
# 3) try run the modules register function
try:
mod.register()
- except:
+ except Exception as ex:
print("Exception in module register(): %r" %
getattr(mod, "__file__", module_name))
- handle_error()
+ handle_error(ex)
del sys.modules[module_name]
if default_set:
_addon_remove(module_name)
@@ -360,17 +366,21 @@ def enable(module_name, default_set=False, persistent=False, handle_error=None):
return mod
-def disable(module_name, default_set=False, handle_error=None):
+def disable(module_name, *, default_set=False, handle_error=None):
"""
Disables an addon by name.
:arg module_name: The name of the addon and module.
:type module_name: string
+ :arg default_set: Set the user-preference.
+ :type default_set: bool
+ :arg handle_error: Called in the case of an error, taking an exception argument.
+ :type handle_error: function
"""
import sys
if handle_error is None:
- def handle_error():
+ def handle_error(ex):
import traceback
traceback.print_exc()
@@ -385,10 +395,10 @@ def disable(module_name, default_set=False, handle_error=None):
try:
mod.unregister()
- except:
+ except Exception as ex:
print("Exception in module unregister(): %r" %
getattr(mod, "__file__", module_name))
- handle_error()
+ handle_error(ex)
else:
print("addon_utils.disable: %s not %s." %
(module_name, "disabled" if mod is None else "loaded"))
@@ -401,7 +411,7 @@ def disable(module_name, default_set=False, handle_error=None):
print("\taddon_utils.disable", module_name)
-def reset_all(reload_scripts=False):
+def reset_all(*, reload_scripts=False):
"""
Sets the addon state based on the user preferences.
"""
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 43a09a1acbd..5a3eda567be 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -304,7 +304,8 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
else:
bl_rna_base_props = set()
- for prop in bl_rna.properties:
+ props = sorted(bl_rna.properties, key=lambda p: p.identifier)
+ for prop in props:
# Only write this property if our parent hasn't got it.
if prop in bl_rna_base_props:
continue
@@ -321,8 +322,20 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
process_msg(msgs, default_context, prop.description, msgsrc, reports, check_ctxt_rna_tip, settings)
if isinstance(prop, bpy.types.EnumProperty):
+ done_items = set()
for item in prop.enum_items:
msgsrc = "bpy.types.{}.{}:'{}'".format(bl_rna.identifier, prop.identifier, item.identifier)
+ done_items.add(item.identifier)
+ if item.name and item.name != item.identifier:
+ process_msg(msgs, msgctxt, item.name, msgsrc, reports, check_ctxt_rna, settings)
+ if item.description:
+ process_msg(msgs, default_context, item.description, msgsrc, reports, check_ctxt_rna_tip,
+ settings)
+ for item in prop.enum_items_static:
+ if item.identifier in done_items:
+ continue
+ msgsrc = "bpy.types.{}.{}:'{}'".format(bl_rna.identifier, prop.identifier, item.identifier)
+ done_items.add(item.identifier)
if item.name and item.name != item.identifier:
process_msg(msgs, msgctxt, item.name, msgsrc, reports, check_ctxt_rna, settings)
if item.description:
@@ -456,7 +469,7 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
def extract_strings_split(node):
"""
- Returns a list args as returned by 'extract_strings()', But split into groups based on separate_nodes, this way
+ Returns a list args as returned by 'extract_strings()', but split into groups based on separate_nodes, this way
expressions like ("A" if test else "B") wont be merged but "A" + "B" will.
"""
estr_ls = []
@@ -492,7 +505,11 @@ def dump_py_messages_from_files(msgs, reports, files, settings):
return i18n_contexts.default
def _op_to_ctxt(node):
- opname, _ = extract_strings(node)
+ # Some smart coders like things like:
+ # >>> row.operator("wm.addon_disable" if is_enabled else "wm.addon_enable", ...)
+ # We only take first arg into account here!
+ bag = extract_strings_split(node)
+ opname, _ = bag[0]
if not opname:
return i18n_contexts.default
op = bpy.ops
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 49dbfbe62af..dd6b79f6686 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -89,6 +89,7 @@ LANGUAGES = (
(39, "Uzbek Cyrillic (Ўзбек)", "uz_UZ@cyrillic"),
(40, "Hindi (मानक हिन्दी)", "hi_IN"),
(41, "Vietnamese (tiếng Việt)", "vi_VN"),
+ (42, "Basque (Euskara)", "eu_EU"),
)
# Default context, in py!
@@ -337,6 +338,8 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"image path can't be written to",
"in memory to enable editing!",
"jumps over",
+ "left",
+ "right",
"the lazy dog",
"unable to load movie clip",
"unable to load text",
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index b1aa4e02cee..df014e8262b 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -123,6 +123,7 @@ class SpellChecker:
"mixdown",
"multi",
"multifractal",
+ "multipaint",
"multires", "multiresolution",
"multisampling",
"multitexture",
@@ -158,6 +159,7 @@ class SpellChecker:
"ringnoise",
"rolloff",
"runtime",
+ "scanline",
"screencast", "screenshot", "screenshots",
"selfcollision",
"shadowbuffer", "shadowbuffers",
@@ -240,6 +242,7 @@ class SpellChecker:
"aero",
"amb",
"anim",
+ "app",
"bool",
"calc",
"config", "configs",
@@ -359,6 +362,7 @@ class SpellChecker:
"collada",
"compositing",
"crossfade",
+ "cuda",
"deinterlace",
"dropoff",
"dv",
@@ -408,6 +412,7 @@ class SpellChecker:
# Blender terms
"audaspace",
"bbone",
+ "bmesh",
"breakdowner",
"bspline",
"bweight",
@@ -500,6 +505,7 @@ class SpellChecker:
"asc", "cdl",
"ascii",
"atrac",
+ "avx",
"bsdf",
"bssrdf",
"bw",
@@ -589,6 +595,7 @@ class SpellChecker:
"eps",
"exr",
"fbx",
+ "fbxnode",
"ffmpeg",
"flac",
"gzip",
diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
index 627a6ab2d3d..674c1c00ab1 100644
--- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py
+++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
@@ -26,7 +26,7 @@ import os
import sys
import bpy
-from mathutils import Vector, Euler
+from mathutils import Vector, Euler, Matrix
INTERN_PREVIEW_TYPES = {'MATERIAL', 'LAMP', 'WORLD', 'TEXTURE', 'IMAGE'}
@@ -246,13 +246,14 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
return 'CYCLES'
return 'BLENDER_RENDER'
- def object_bbox_merge(bbox, ob, ob_space):
+ def object_bbox_merge(bbox, ob, ob_space, offset_matrix):
if ob.bound_box:
ob_bbox = ob.bound_box
else:
ob_bbox = ((-ob.scale.x, -ob.scale.y, -ob.scale.z), (ob.scale.x, ob.scale.y, ob.scale.z))
- for v in ob.bound_box:
- v = ob_space.matrix_world.inverted() * ob.matrix_world * Vector(v)
+ for v in ob_bbox:
+ v = offset_matrix * Vector(v) if offset_matrix is not None else Vector(v)
+ v = ob_space.matrix_world.inverted() * ob.matrix_world * v
if bbox[0].x > v.x:
bbox[0].x = v.x
if bbox[0].y > v.y:
@@ -266,11 +267,11 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
if bbox[1].z < v.z:
bbox[1].z = v.z
- def objects_bbox_calc(camera, objects):
+ def objects_bbox_calc(camera, objects, offset_matrix):
bbox = (Vector((1e9, 1e9, 1e9)), Vector((-1e9, -1e9, -1e9)))
for obname in objects:
ob = bpy.data.objects[obname, None]
- object_bbox_merge(bbox, ob, camera)
+ object_bbox_merge(bbox, ob, camera, offset_matrix)
# Our bbox has been generated in camera local space, bring it back in world one
bbox[0][:] = camera.matrix_world * bbox[0]
bbox[1][:] = camera.matrix_world * bbox[1]
@@ -286,12 +287,12 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
)
return cos
- def preview_render_do(render_context, item_container, item_name, objects):
+ def preview_render_do(render_context, item_container, item_name, objects, offset_matrix=None):
scene = bpy.data.scenes[render_context.scene, None]
if objects is not None:
camera = bpy.data.objects[render_context.camera, None]
lamp = bpy.data.objects[render_context.lamp, None] if render_context.lamp is not None else None
- cos = objects_bbox_calc(camera, objects)
+ cos = objects_bbox_calc(camera, objects, offset_matrix)
loc, ortho_scale = camera.camera_fit_coords(scene, cos)
camera.location = loc
if lamp:
@@ -322,7 +323,7 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
prev_scenename = bpy.context.screen.scene.name
if do_objects:
- prev_shown = tuple(ob.hide_render for ob in ids_nolib(bpy.data.objects))
+ prev_shown = {ob.name: ob.hide_render for ob in ids_nolib(bpy.data.objects)}
for ob in ids_nolib(bpy.data.objects):
if ob in objects_ignored:
continue
@@ -368,8 +369,10 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
scene.objects.unlink(ob)
ob.hide_render = True
- for ob, is_rendered in zip(tuple(ids_nolib(bpy.data.objects)), prev_shown):
- ob.hide_render = is_rendered
+ for ob in ids_nolib(bpy.data.objects):
+ is_rendered = prev_shown.get(ob.name, ...)
+ if is_rendered is not ...:
+ ob.hide_render = is_rendered
if do_groups:
for grp in ids_nolib(bpy.data.groups):
@@ -391,7 +394,9 @@ def do_previews(do_objects, do_groups, do_scenes, do_data_intern):
grp_obname = grp_ob.name
scene.update()
- preview_render_do(render_context, 'groups', grp.name, objects)
+ offset_matrix = Matrix.Translation(grp.dupli_offset).inverted()
+
+ preview_render_do(render_context, 'groups', grp.name, objects, offset_matrix)
scene = bpy.data.scenes[render_context.scene, None]
scene.objects.unlink(bpy.data.objects[grp_obname, None])
@@ -466,14 +471,26 @@ def main():
argv = sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []
parser = argparse.ArgumentParser(description="Use Blender to generate previews for currently open Blender file's items.")
- parser.add_argument('--clear', default=False, action="store_true", help="Clear previews instead of generating them.")
- parser.add_argument('--no_scenes', default=True, action="store_false", help="Do not generate/clear previews for scene IDs.")
- parser.add_argument('--no_groups', default=True, action="store_false", help="Do not generate/clear previews for group IDs.")
- parser.add_argument('--no_objects', default=True, action="store_false", help="Do not generate/clear previews for object IDs.")
+ parser.add_argument('--clear', default=False, action="store_true",
+ help="Clear previews instead of generating them.")
+ parser.add_argument('--no_backups', default=False, action="store_true",
+ help="Do not generate a backup .blend1 file when saving processed ones.")
+ parser.add_argument('--no_scenes', default=True, action="store_false",
+ help="Do not generate/clear previews for scene IDs.")
+ parser.add_argument('--no_groups', default=True, action="store_false",
+ help="Do not generate/clear previews for group IDs.")
+ parser.add_argument('--no_objects', default=True, action="store_false",
+ help="Do not generate/clear previews for object IDs.")
parser.add_argument('--no_data_intern', default=True, action="store_false",
help="Do not generate/clear previews for mat/tex/image/etc. IDs (those handled by core Blender code).")
args = parser.parse_args(argv)
+ orig_save_version = bpy.context.user_preferences.filepaths.save_version
+ if args.no_backups:
+ bpy.context.user_preferences.filepaths.save_version = 0
+ elif orig_save_version < 1:
+ bpy.context.user_preferences.filepaths.save_version = 1
+
if args.clear:
print("clear!")
do_clear_previews(do_objects=args.no_objects, do_groups=args.no_groups, do_scenes=args.no_scenes,
@@ -483,6 +500,9 @@ def main():
do_previews(do_objects=args.no_objects, do_groups=args.no_groups, do_scenes=args.no_scenes,
do_data_intern=args.no_data_intern)
+ # Not really necessary, but better be consistent.
+ bpy.context.user_preferences.filepaths.save_version = orig_save_version
+
if __name__ == "__main__":
print("\n\n *** Running {} *** \n".format(__file__))
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index b0d2233b380..f012c1317d4 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -56,22 +56,16 @@ def main():
# fake module to allow:
# from bpy.types import Panel
- sys.modules["bpy.app"] = app
- sys.modules["bpy.app.handlers"] = app.handlers
- sys.modules["bpy.app.translations"] = app.translations
- sys.modules["bpy.types"] = types
-
- #~ if "-d" in sys.argv: # Enable this to measure start up speed
- if 0:
- import cProfile
- cProfile.run("import bpy; bpy.utils.load_scripts()", "blender.prof")
-
- import pstats
- p = pstats.Stats("blender.prof")
- p.sort_stats("cumulative").print_stats(100)
-
- else:
- utils.load_scripts()
+ sys.modules.update({
+ "bpy.app": app,
+ "bpy.app.handlers": app.handlers,
+ "bpy.app.translations": app.translations,
+ "bpy.types": types,
+ })
+
+ # Initializes Python classes.
+ # (good place to run a profiler or trace).
+ utils.load_scripts()
main()
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index d7c6101115d..30f6c8eebed 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -35,6 +35,7 @@ __all__ = (
"extensions_audio",
"is_subdir",
"module_names",
+ "native_pathsep",
"reduce_dirs",
"relpath",
"resolve_ncase",
@@ -69,19 +70,23 @@ def abspath(path, start=None, library=None):
if isinstance(path, bytes):
if path.startswith(b"//"):
if library:
- start = _os.path.dirname(abspath(_getattr_bytes(library, "filepath")))
- return _os.path.join(_os.path.dirname(_getattr_bytes(_bpy.data, "filepath"))
- if start is None else start,
- path[2:],
- )
+ start = _os.path.dirname(
+ abspath(_getattr_bytes(library, "filepath")))
+ return _os.path.join(
+ _os.path.dirname(_getattr_bytes(_bpy.data, "filepath"))
+ if start is None else start,
+ path[2:],
+ )
else:
if path.startswith("//"):
if library:
- start = _os.path.dirname(abspath(library.filepath))
- return _os.path.join(_os.path.dirname(_bpy.data.filepath)
- if start is None else start,
- path[2:],
- )
+ start = _os.path.dirname(
+ abspath(library.filepath))
+ return _os.path.join(
+ _os.path.dirname(_bpy.data.filepath)
+ if start is None else start,
+ path[2:],
+ )
return path
@@ -118,13 +123,13 @@ def is_subdir(path, directory):
:arg path: An absolute path.
:type path: string or bytes
"""
- from os.path import normpath, normcase
+ from os.path import normpath, normcase, sep
path = normpath(normcase(path))
directory = normpath(normcase(directory))
if len(path) > len(directory):
- if path.startswith(directory):
- sep = ord(_os.sep) if isinstance(directory, bytes) else _os.sep
- return (path[len(directory)] == sep)
+ sep = sep.encode('ascii') if isinstance(directory, bytes) else sep
+ if path.startswith(directory.rstrip(sep) + sep):
+ return True
return False
@@ -345,6 +350,28 @@ def basename(path):
return _os.path.basename(path[2:] if path[:2] in {"//", b"//"} else path)
+def native_pathsep(path):
+ """
+ Replace the path separator with the systems native ``os.sep``.
+ """
+ if type(path) is str:
+ if _os.sep == "/":
+ return path.replace("\\", "/")
+ else:
+ if path.startswith("//"):
+ return "//" + path[2:].replace("/", "\\")
+ else:
+ return path.replace("/", "\\")
+ else: # bytes
+ if _os.sep == "/":
+ return path.replace(b"\\", b"/")
+ else:
+ if path.startswith(b"//"):
+ return b"//" + path[2:].replace(b"/", b"\\")
+ else:
+ return path.replace(b"/", b"\\")
+
+
def reduce_dirs(dirs):
"""
Given a sequence of directories, remove duplicates and
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py
index 481db4659af..986d8b9f45c 100644
--- a/release/scripts/modules/bpy/utils/__init__.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -251,7 +251,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
_initialize()
del _addon_utils._initialize
else:
- _addon_utils.reset_all(reload_scripts)
+ _addon_utils.reset_all(reload_scripts=reload_scripts)
del _initialize
# run the active integration preset
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
index 965971139e4..c67c523ea72 100644
--- a/release/scripts/modules/bpy/utils/previews.py
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -86,7 +86,7 @@ class ImagePreviewCollection(dict):
def new(self, name):
if name in self:
- raise KeyException("key %r already exists")
+ raise KeyError("key %r already exists" % name)
p = self[name] = _utils_previews.new(
self._gen_key(name))
return p
@@ -94,7 +94,7 @@ class ImagePreviewCollection(dict):
def load(self, name, path, path_type, force_reload=False):
if name in self:
- raise KeyException("key %r already exists")
+ raise KeyError("key %r already exists" % name)
p = self[name] = _utils_previews.load(
self._gen_key(name), path, path_type, force_reload)
return p
diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py
index ff6d23badb6..f772aab2b14 100644
--- a/release/scripts/modules/bpy_extras/image_utils.py
+++ b/release/scripts/modules/bpy_extras/image_utils.py
@@ -32,6 +32,8 @@ def load_image(imagepath,
convert_callback=None,
verbose=False,
relpath=None,
+ check_existing=False,
+ force_reload=False,
):
"""
Return an image from the file path with options to search multiple paths
@@ -60,6 +62,14 @@ def load_image(imagepath,
:type convert_callback: function
:arg relpath: If not None, make the file relative to this path.
:type relpath: None or string
+ :arg check_existing: If true,
+ returns already loaded image datablock if possible
+ (based on file path).
+ :type check_existing: bool
+ :arg force_reload: If true,
+ force reloading of image (only useful when `check_existing`
+ is also enabled).
+ :type force_reload: bool
:return: an image or None
:rtype: :class:`bpy.types.Image`
"""
@@ -70,9 +80,12 @@ def load_image(imagepath,
# Utility Functions
def _image_load_placeholder(path):
- name = bpy.path.basename(path)
- if type(name) == bytes:
- name = name.decode("utf-8", "replace")
+ name = path
+ if type(path) is str:
+ name = name.encode("utf-8", "replace")
+ name = name.decode("utf-8", "replace")
+ name = os.path.basename(name)
+
image = bpy.data.images.new(name, 128, 128)
# allow the path to be resolved later
image.filepath = path
@@ -85,8 +98,12 @@ def load_image(imagepath,
if convert_callback:
path = convert_callback(path)
+ # Ensure we're not relying on the 'CWD' to resolve the path.
+ if not os.path.isabs(path):
+ path = os.path.abspath(path)
+
try:
- image = bpy.data.images.load(path)
+ image = bpy.data.images.load(path, check_existing)
except RuntimeError:
image = None
@@ -102,6 +119,8 @@ def load_image(imagepath,
image = _image_load_placeholder(path)
if image:
+ if force_reload:
+ image.reload()
if relpath is not None:
# make relative
from bpy.path import relpath as relpath_fn
@@ -131,6 +150,8 @@ def load_image(imagepath,
# -------------------------------------------------------------------------
+ imagepath = bpy.path.native_pathsep(imagepath)
+
if verbose:
print("load_image('%s', '%s', ...)" % (imagepath, dirname))
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 65ccc3f8dc3..a7ecd0b80c0 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -137,7 +137,8 @@ def orientation_helper_factory(name, axis_forward='Y', axis_up='Z'):
def _update_axis_forward(self, context):
if self.axis_forward[-1] == self.axis_up[-1]:
- self.axis_up = self.axis_up[0:-1] + 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3]
+ self.axis_up = (self.axis_up[0:-1] +
+ 'XYZ'[('XYZ'.index(self.axis_up[-1]) + 1) % 3])
members['axis_forward'] = EnumProperty(
name="Forward",
@@ -154,7 +155,8 @@ def orientation_helper_factory(name, axis_forward='Y', axis_up='Z'):
def _update_axis_up(self, context):
if self.axis_up[-1] == self.axis_forward[-1]:
- self.axis_forward = self.axis_forward[0:-1] + 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3]
+ self.axis_forward = (self.axis_forward[0:-1] +
+ 'XYZ'[('XYZ'.index(self.axis_forward[-1]) + 1) % 3])
members['axis_up'] = EnumProperty(
name="Up",
diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py
index 7e4c9e885e7..6246e4489e1 100644
--- a/release/scripts/modules/bpy_extras/keyconfig_utils.py
+++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py
@@ -27,14 +27,14 @@ KM_HIERARCHY = [
('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit
('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot
('Screen Editing', 'EMPTY', 'WINDOW', []), # re-sizing, action corners
+ ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
]),
('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region)
('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
- ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
- ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
- ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
+ ('User Interface', 'EMPTY', 'WINDOW', [
+ ('Eyedropper Modal Map', 'EMPTY', 'WINDOW', []),
]),
('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
@@ -73,10 +73,6 @@ KM_HIERARCHY = [
('3D View Generic', 'VIEW_3D', 'WINDOW', []), # toolbar and properties
]),
- ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
- ('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
- ('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region)
- ('Animation Channels', 'EMPTY', 'WINDOW', []),
('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', []),
]),
@@ -85,15 +81,15 @@ KM_HIERARCHY = [
('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
('NLA Generic', 'NLA_EDITOR', 'WINDOW', []),
]),
+ ('Timeline', 'TIMELINE', 'WINDOW', []),
('Image', 'IMAGE_EDITOR', 'WINDOW', [
- ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
+ ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image)
('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
('UV Sculpt', 'EMPTY', 'WINDOW', []),
('Image Generic', 'IMAGE_EDITOR', 'WINDOW', []),
]),
- ('Timeline', 'TIMELINE', 'WINDOW', []),
('Outliner', 'OUTLINER', 'WINDOW', []),
('Node Editor', 'NODE_EDITOR', 'WINDOW', [
@@ -122,9 +118,17 @@ KM_HIERARCHY = [
('Clip Editor', 'CLIP_EDITOR', 'WINDOW', []),
('Clip Graph Editor', 'CLIP_EDITOR', 'WINDOW', []),
('Clip Dopesheet Editor', 'CLIP_EDITOR', 'WINDOW', []),
- ('Mask Editing', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
]),
+ ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
+ ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
+ ]),
+ ('Mask Editing', 'EMPTY', 'WINDOW', []),
+ ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
+ ('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
+ ('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region)
+ ('Animation Channels', 'EMPTY', 'WINDOW', []),
+
('View3D Gesture Circle', 'EMPTY', 'WINDOW', []),
('Gesture Straight Line', 'EMPTY', 'WINDOW', []),
('Gesture Zoom Border', 'EMPTY', 'WINDOW', []),
@@ -163,13 +167,12 @@ def _export_properties(prefix, properties, kmi_id, lines=None):
def string_value(value):
if isinstance(value, str) or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int):
- result = repr(value)
+ return repr(value)
elif getattr(value, '__len__', False):
return repr(list(value))
- else:
- print("Export key configuration: can't write ", value)
- return result
+ print("Export key configuration: can't write ", value)
+ return ""
for pname in properties.bl_rna.properties.keys():
if pname != "rna_type":
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 78fb6aa8fa2..c2c306e5145 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -33,6 +33,7 @@ import bpy
from bpy.props import (
BoolProperty,
+ BoolVectorProperty,
FloatVectorProperty,
)
@@ -136,16 +137,22 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name=
if context.space_data and context.space_data.type == 'VIEW_3D':
v3d = context.space_data
- if use_active_layer:
- if v3d and v3d.local_view:
- base.layers_from_view(context.space_data)
- base.layers[scene.active_layer] = True
- else:
- base.layers = [True if i == scene.active_layer
- else False for i in range(len(scene.layers))]
+ if operator is not None and any(operator.layers):
+ base.layers = operator.layers
else:
- if v3d:
- base.layers_from_view(context.space_data)
+ if use_active_layer:
+ if v3d and v3d.local_view:
+ base.layers_from_view(context.space_data)
+ base.layers[scene.active_layer] = True
+ else:
+ base.layers = [True if i == scene.active_layer
+ else False for i in range(len(scene.layers))]
+ else:
+ if v3d:
+ base.layers_from_view(context.space_data)
+
+ if operator is not None:
+ operator.layers = base.layers
obj_new.matrix_world = add_object_align_init(context, operator)
@@ -209,6 +216,12 @@ class AddObjectHelper:
name="Rotation",
subtype='EULER',
)
+ layers = BoolVectorProperty(
+ name="Layers",
+ size=20,
+ subtype='LAYER',
+ options={'HIDDEN', 'SKIP_SAVE'},
+ )
@classmethod
def poll(self, context):
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 92dbd2dbd0e..c1a37d10961 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -21,11 +21,13 @@
from _bpy import types as bpy_types
import _bpy
-StructRNA = bpy_types.Struct.__bases__[0]
-StructMetaPropGroup = _bpy.StructMetaPropGroup
+StructRNA = bpy_types.bpy_struct
+StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop
# StructRNA = bpy_types.Struct
bpy_types.BlendDataLibraries.load = _bpy._library_load
+bpy_types.BlendDataLibraries.write = _bpy._library_write
+bpy_types.BlendData.user_map = _bpy._rna_id_collection_user_map
class Context(StructRNA):
@@ -34,8 +36,10 @@ class Context(StructRNA):
def copy(self):
from types import BuiltinMethodType
new_context = {}
- generic_attrs = (list(StructRNA.__dict__.keys()) +
- ["bl_rna", "rna_type", "copy"])
+ generic_attrs = (
+ *StructRNA.__dict__.keys(),
+ "bl_rna", "rna_type", "copy",
+ )
for attr in dir(self):
if not (attr.startswith("_") or attr in generic_attrs):
value = getattr(self, attr)
@@ -205,7 +209,7 @@ class _GenericBone:
@property
def basename(self):
"""The name of this bone before any '.' character"""
- #return self.name.rsplit(".", 1)[0]
+ # return self.name.rsplit(".", 1)[0]
return self.name.split(".")[0]
@property
@@ -405,28 +409,24 @@ class Mesh(bpy_types.ID):
:type faces: iterable object
"""
+ from itertools import chain, islice, accumulate
+
+ face_lengths = tuple(map(len, faces))
+
self.vertices.add(len(vertices))
self.edges.add(len(edges))
- self.loops.add(sum((len(f) for f in faces)))
+ self.loops.add(sum(face_lengths))
self.polygons.add(len(faces))
- vertices_flat = [f for v in vertices for f in v]
- self.vertices.foreach_set("co", vertices_flat)
- del vertices_flat
-
- edges_flat = [i for e in edges for i in e]
- self.edges.foreach_set("vertices", edges_flat)
- del edges_flat
-
- # this is different in bmesh
- loop_index = 0
- for i, p in enumerate(self.polygons):
- f = faces[i]
- loop_len = len(f)
- p.loop_start = loop_index
- p.loop_total = loop_len
- p.vertices = f
- loop_index += loop_len
+ self.vertices.foreach_set("co", tuple(chain.from_iterable(vertices)))
+ self.edges.foreach_set("vertices", tuple(chain.from_iterable(edges)))
+
+ vertex_indices = tuple(chain.from_iterable(faces))
+ loop_starts = tuple(islice(chain([0], accumulate(face_lengths)), len(faces)))
+
+ self.polygons.foreach_set("loop_total", face_lengths)
+ self.polygons.foreach_set("loop_start", loop_starts)
+ self.polygons.foreach_set("vertices", vertex_indices)
# if no edges - calculate them
if faces and (not edges):
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
index 59e4f2314d8..64bb002d6a1 100644
--- a/release/scripts/modules/console_python.py
+++ b/release/scripts/modules/console_python.py
@@ -136,33 +136,40 @@ def execute(context, is_interactive):
console, stdout, stderr = get_console(hash(context.region))
- # redirect output
- sys.stdout = stdout
- sys.stderr = stderr
-
- # don't allow the stdin to be used, can lock blender.
- stdin_backup = sys.stdin
- sys.stdin = None
-
if _BPY_MAIN_OWN:
main_mod_back = sys.modules["__main__"]
sys.modules["__main__"] = console._bpy_main_mod
- # in case exception happens
- line = "" # in case of encoding error
- is_multiline = False
+ # redirect output
+ from contextlib import (
+ redirect_stdout,
+ redirect_stderr,
+ )
+
+ # not included with Python
+ class redirect_stdin(redirect_stdout.__base__):
+ _stream = "stdin"
- try:
- line = line_object.body
+ # don't allow the stdin to be used, can lock blender.
+ with redirect_stdout(stdout), \
+ redirect_stderr(stderr), \
+ redirect_stdin(None):
- # run the console, "\n" executes a multi line statement
- line_exec = line if line.strip() else "\n"
+ # in case exception happens
+ line = "" # in case of encoding error
+ is_multiline = False
- is_multiline = console.push(line_exec)
- except:
- # unlikely, but this can happen with unicode errors for example.
- import traceback
- stderr.write(traceback.format_exc())
+ try:
+ line = line_object.body
+
+ # run the console, "\n" executes a multi line statement
+ line_exec = line if line.strip() else "\n"
+
+ is_multiline = console.push(line_exec)
+ except:
+ # unlikely, but this can happen with unicode errors for example.
+ import traceback
+ stderr.write(traceback.format_exc())
if _BPY_MAIN_OWN:
sys.modules["__main__"] = main_mod_back
@@ -174,8 +181,6 @@ def execute(context, is_interactive):
output_err = stderr.read()
# cleanup
- sys.stdout = sys.__stdout__
- sys.stderr = sys.__stderr__
sys.last_traceback = None
# So we can reuse, clear all data
@@ -213,9 +218,6 @@ def execute(context, is_interactive):
if output_err:
add_scrollback(output_err, 'ERROR')
- # restore the stdin
- sys.stdin = stdin_backup
-
# execute any hooks
for func, args in execute.hooks:
func(*args)
diff --git a/release/scripts/modules/progress_report.py b/release/scripts/modules/progress_report.py
index 578eb967fec..fc77a3e998e 100644
--- a/release/scripts/modules/progress_report.py
+++ b/release/scripts/modules/progress_report.py
@@ -99,7 +99,7 @@ class ProgressReport:
def enter_substeps(self, nbr, msg=""):
if msg:
self.update(msg)
- self.steps.append(self.steps[-1] / nbr)
+ self.steps.append(self.steps[-1] / max(nbr, 1))
self.curr_step.append(0)
self.start_time.append(time.time())
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index 21d1959a037..2ca7a7997a5 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -70,7 +70,7 @@ def draw_km(display_keymaps, kc, km, children, layout, level):
col = _indented_layout(layout, level)
- row = col.row()
+ row = col.row(align=True)
row.prop(km, "show_expanded_children", text="", emboss=False)
row.label(text=km.name, text_ctxt=i18n_contexts.id_windowmanager)
@@ -89,7 +89,7 @@ def draw_km(display_keymaps, kc, km, children, layout, level):
# Put the Parent key map's entries in a 'global' sub-category
# equal in hierarchy to the other children categories
subcol = _indented_layout(col, level + 1)
- subrow = subcol.row()
+ subrow = subcol.row(align=True)
subrow.prop(km, "show_expanded_items", text="", emboss=False)
subrow.label(text=iface_("%s (Global)") % km.name, translate=False)
else:
@@ -97,25 +97,25 @@ def draw_km(display_keymaps, kc, km, children, layout, level):
# Key Map items
if km.show_expanded_items:
+ kmi_level = level + 3 if children else level + 1
for kmi in km.keymap_items:
- draw_kmi(display_keymaps, kc, km, kmi, col, level + 1)
+ draw_kmi(display_keymaps, kc, km, kmi, col, kmi_level)
# "Add New" at end of keymap item list
- col = _indented_layout(col, level + 1)
- subcol = col.split(percentage=0.2).column()
+ subcol = _indented_layout(col, kmi_level)
+ subcol = subcol.split(percentage=0.2).column()
subcol.operator("wm.keyitem_add", text="Add New", text_ctxt=i18n_contexts.id_windowmanager,
icon='ZOOMIN')
- col.separator()
+ col.separator()
# Child key maps
if children:
- subcol = col.column()
- row = subcol.row()
-
for entry in children:
draw_entry(display_keymaps, entry, col, level + 1)
+ col.separator()
+
def draw_kmi(display_keymaps, kc, km, kmi, layout, level):
map_type = kmi.map_type
@@ -128,7 +128,7 @@ def draw_kmi(display_keymaps, kc, km, kmi, layout, level):
else:
box = col.column()
- split = box.split(percentage=0.05)
+ split = box.split(percentage=0.01)
# header bar
row = split.row()
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 195b5767189..c0d92c331b7 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -41,7 +41,8 @@ def rna_idprop_ui_del(item):
def rna_idprop_ui_prop_update(item, prop):
prop_rna = item.path_resolve("[\"%s\"]" % prop.replace("\"", "\\\""), False)
- prop_rna.update()
+ if isinstance(prop_rna, bpy.types.bpy_prop):
+ prop_rna.update()
def rna_idprop_ui_prop_get(item, prop, create=True):
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
index 8ca3014a31e..49395dd48f0 100644
--- a/release/scripts/modules/sys_info.py
+++ b/release/scripts/modules/sys_info.py
@@ -20,22 +20,15 @@
# classes for extracting info from blenders internal classes
-import bpy
-import bgl
-import sys
+def write_sysinfo(filepath):
+ import sys
-
-def write_sysinfo(op):
import textwrap
+ import subprocess
- output_filename = "system-info.txt"
-
- output = bpy.data.texts.get(output_filename)
- if output:
- output.clear()
- else:
- output = bpy.data.texts.new(name=output_filename)
+ import bpy
+ import bgl
# pretty repr
def prepr(v):
@@ -47,17 +40,19 @@ def write_sysinfo(op):
r = r[1:-1]
return r
+ output = open(filepath, 'w', encoding="utf-8")
header = "= Blender %s System Information =\n" % bpy.app.version_string
- lilies = "%s\n\n" % (len(header) * "=")
- firstlilies = "%s\n" % (len(header) * "=")
- output.write(firstlilies)
+ lilies = "%s\n\n" % ((len(header) - 1) * "=")
+ output.write(lilies[:-1])
output.write(header)
output.write(lilies)
+ def title(text):
+ return "\n%s:\n%s" % (text, lilies)
+
# build info
- output.write("\nBlender:\n")
- output.write(lilies)
+ output.write(title("Blender"))
output.write("version: %s, branch: %s, commit date: %s %s, hash: %s, type: %s\n" %
(bpy.app.version_string,
prepr(bpy.app.build_branch),
@@ -76,16 +71,28 @@ def write_sysinfo(op):
output.write("build system: %s\n" % prepr(bpy.app.build_system))
# python info
- output.write("\nPython:\n")
- output.write(lilies)
+ output.write(title("Python"))
output.write("version: %s\n" % (sys.version))
output.write("paths:\n")
for p in sys.path:
- output.write("\t%r\n" % (p))
-
- output.write("\nDirectories:\n")
- output.write(lilies)
- output.write("scripts: %r\n" % (bpy.utils.script_paths()))
+ output.write("\t%r\n" % p)
+
+ output.write(title("Python (External Binary)"))
+ output.write("binary path: %s\n" % prepr(bpy.app.binary_path_python))
+ try:
+ py_ver = prepr(subprocess.check_output([
+ bpy.app.binary_path_python,
+ "--version",
+ ]).strip())
+ except Exception as e:
+ py_ver = str(e)
+ output.write("version: %s\n" % py_ver)
+ del py_ver
+
+ output.write(title("Directories"))
+ output.write("scripts:\n")
+ for p in bpy.utils.script_paths():
+ output.write("\t%r\n" % p)
output.write("user scripts: %r\n" % (bpy.utils.script_path_user()))
output.write("pref scripts: %r\n" % (bpy.utils.script_path_pref()))
output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES')))
@@ -94,8 +101,7 @@ def write_sysinfo(op):
output.write("autosave: %r\n" % (bpy.utils.user_resource('AUTOSAVE')))
output.write("tempdir: %r\n" % (bpy.app.tempdir))
- output.write("\nFFmpeg:\n")
- output.write(lilies)
+ output.write(title("FFmpeg"))
ffmpeg = bpy.app.ffmpeg
if ffmpeg.supported:
for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"):
@@ -105,8 +111,7 @@ def write_sysinfo(op):
output.write("Blender was built without FFmpeg support\n")
if bpy.app.build_options.sdl:
- output.write("\nSDL\n")
- output.write(lilies)
+ output.write(title("SDL"))
output.write("Version: %s\n" % bpy.app.sdl.version_string)
output.write("Loading method: ")
if bpy.app.build_options.sdl_dynload:
@@ -116,8 +121,7 @@ def write_sysinfo(op):
if not bpy.app.sdl.available:
output.write("WARNING: Blender could not load SDL library\n")
- output.write("\nOther Libraries:\n")
- output.write(lilies)
+ output.write(title("Other Libraries"))
ocio = bpy.app.ocio
output.write("OpenColorIO: ")
if ocio.supported:
@@ -146,54 +150,59 @@ def write_sysinfo(op):
else:
output.write("Blender was built without Cycles support\n")
+ openvdb = bpy.app.openvdb
+ output.write("OpenVDB: ")
+ if openvdb.supported:
+ output.write("%s\n" % openvdb.version_string)
+ else:
+ output.write("Blender was built without OpenVDB support\n")
+
if not bpy.app.build_options.sdl:
output.write("SDL: Blender was built without SDL support\n")
if bpy.app.background:
output.write("\nOpenGL: missing, background mode\n")
else:
- output.write("\nOpenGL\n")
- output.write(lilies)
+ output.write(title("OpenGL"))
version = bgl.glGetString(bgl.GL_RENDERER)
output.write("renderer:\t%r\n" % version)
output.write("vendor:\t\t%r\n" % (bgl.glGetString(bgl.GL_VENDOR)))
output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION)))
output.write("extensions:\n")
- glext = bgl.glGetString(bgl.GL_EXTENSIONS)
- glext = textwrap.wrap(glext, 70)
+ glext = sorted(bgl.glGetString(bgl.GL_EXTENSIONS).split())
for l in glext:
output.write("\t%s\n" % l)
- output.write("\nImplementation Dependent OpenGL Limits:\n")
- output.write(lilies)
+ output.write(title("Implementation Dependent OpenGL Limits"))
limit = bgl.Buffer(bgl.GL_INT, 1)
bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit)
output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit)
+ output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit)
+ output.write("Maximum DrawElements Indices:\t%d\n" % limit[0])
output.write("\nGLSL:\n")
- if version[0] > '1':
- bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit)
- output.write("Maximum Varying Floats:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit)
- output.write("Maximum Vertex Attributes:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit)
- output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit)
- output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit)
- output.write("Maximum Vertex Image Units:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit)
- output.write("Maximum Fragment Image Units:\t%d\n" % limit[0])
- bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit)
- output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit)
+ output.write("Maximum Varying Floats:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit)
+ output.write("Maximum Vertex Attributes:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit)
+ output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit)
+ output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit)
+ output.write("Maximum Vertex Image Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit)
+ output.write("Maximum Fragment Image Units:\t%d\n" % limit[0])
+ bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit)
+ output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0])
if bpy.app.build_options.cycles:
import cycles
- output.write("\nCycles\n")
- output.write(lilies)
+ output.write(title("Cycles"))
output.write(cycles.engine.system_info())
- output.current_line_index = 0
+ output.close()
- op.report({'INFO'}, "System information generated in 'system-info.txt'")
diff --git a/release/scripts/presets/interface_theme/back_to_black.xml b/release/scripts/presets/interface_theme/back_to_black.xml
index 05613e79411..3b2b9b99ed2 100644
--- a/release/scripts/presets/interface_theme/back_to_black.xml
+++ b/release/scripts/presets/interface_theme/back_to_black.xml
@@ -300,6 +300,8 @@
camera_path="#5a5a5a"
skin_root="#000000"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#2f5f23"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#202020"
title="#5d5d5d"
diff --git a/release/scripts/presets/interface_theme/blender_24x.xml b/release/scripts/presets/interface_theme/blender_24x.xml
index 1ea335c7d73..445c23b4c4e 100644
--- a/release/scripts/presets/interface_theme/blender_24x.xml
+++ b/release/scripts/presets/interface_theme/blender_24x.xml
@@ -217,7 +217,7 @@
<ThemeWidgetColors outline="#000000"
inner="#00000000"
inner_sel="#7f7f7fff"
- item="#000000ff"
+ item="#5a5a5aff"
text="#000000"
text_sel="#ffffff"
show_shaded="FALSE"
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#b44d4d"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#60c040"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#949494"
title="#000000"
diff --git a/release/scripts/presets/interface_theme/elsyiun.xml b/release/scripts/presets/interface_theme/elsyiun.xml
index 5cb7af1ccc2..20c88363aa9 100644
--- a/release/scripts/presets/interface_theme/elsyiun.xml
+++ b/release/scripts/presets/interface_theme/elsyiun.xml
@@ -217,9 +217,9 @@
<ThemeWidgetColors outline="#000000"
inner="#00000000"
inner_sel="#a9753777"
- item="#000000ff"
+ item="#5a5a5aff"
text="#e0e0e0"
- text_sel="#000000"
+ text_sel="#ffffff"
show_shaded="TRUE"
shadetop="0"
shadedown="-10">
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#000000"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -367,7 +369,7 @@
text="#ffffff"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3bff"
button_title="#8b8b8b"
@@ -459,7 +461,7 @@
text="#ffffff"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3bff"
button_title="#000000"
@@ -517,7 +519,7 @@
text="#ffffff"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#aaaaaaff"
button_title="#000000"
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -590,7 +594,7 @@
text="#8b8b8b"
text_hi="#ffffff"
header="#303030"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#303030ff"
button_title="#8b8b8b"
@@ -625,17 +629,20 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#60c040"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#636363"
title="#8b8b8b"
text="#ffffff"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3b42"
button_title="#000000"
@@ -664,7 +671,7 @@
text="#b8b8b8"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#727272ff"
button_title="#b8b8b8"
@@ -703,7 +710,7 @@
text="#cfbfad"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3bff"
button_title="#8b8b8b"
@@ -735,7 +742,7 @@
text="#b8b8b8"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#727272ff"
button_title="#000000"
@@ -790,7 +797,7 @@
text="#dbdbdb"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3b2f"
button_title="#8b8b8b"
@@ -826,7 +833,7 @@
text="#000000"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3bff"
button_title="#8b8b8b"
@@ -856,7 +863,7 @@
text="#cacaca"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#727272ff"
button_title="#000000"
@@ -894,7 +901,7 @@
text="#000000"
text_hi="#000000"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#000000"
button="#3b3b3bff"
button_title="#000000"
@@ -923,7 +930,7 @@
text="#b8b8b8"
text_hi="#ffffff"
header="#3b3b3b"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#727272ff"
button_title="#000000"
@@ -957,7 +964,7 @@
text="#000000"
text_hi="#ffffff"
header="#303030"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3bff"
button_title="#000000"
@@ -1010,7 +1017,7 @@
text="#000000"
text_hi="#ffffff"
header="#313131"
- header_text="#000000"
+ header_text="#b8b8b8"
header_text_hi="#ffffff"
button="#3b3b3bff"
button_title="#000000"
diff --git a/release/scripts/presets/interface_theme/flatty_light.xml b/release/scripts/presets/interface_theme/flatty_light.xml
index deb1101302a..f9fed2d97da 100644
--- a/release/scripts/presets/interface_theme/flatty_light.xml
+++ b/release/scripts/presets/interface_theme/flatty_light.xml
@@ -217,7 +217,7 @@
<ThemeWidgetColors outline="#e6e6e6"
inner="#00000000"
inner_sel="#5680c2ff"
- item="#cccccc80"
+ item="#80b1ffff"
text="#1a1a1a"
text_sel="#ffffff"
show_shaded="FALSE"
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#b44d4d"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#60c040"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#747474"
title="#000000"
diff --git a/release/scripts/presets/interface_theme/graph.xml b/release/scripts/presets/interface_theme/graph.xml
index 063524a9187..4943bf3b4d5 100644
--- a/release/scripts/presets/interface_theme/graph.xml
+++ b/release/scripts/presets/interface_theme/graph.xml
@@ -217,7 +217,7 @@
<ThemeWidgetColors outline="#3b3b3b"
inner="#3f3f3f00"
inner_sel="#607f9eff"
- item="#ffffffff"
+ item="#414141ff"
text="#b8b8b8"
text_sel="#ffffff"
show_shaded="TRUE"
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#000000"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#ffffff"
transition_strip="#726d70"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#4291dc"
keyframe="#ff8500"
draw_action="#607f9e"
- preview_back="#3b3b3b">
+ preview_back="#3b3b3b"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#5d5d5d"
title="#e4e4e4"
diff --git a/release/scripts/presets/interface_theme/hexagon.xml b/release/scripts/presets/interface_theme/hexagon.xml
index 74adb9f9d27..1db4db0cb47 100644
--- a/release/scripts/presets/interface_theme/hexagon.xml
+++ b/release/scripts/presets/interface_theme/hexagon.xml
@@ -217,7 +217,7 @@
<ThemeWidgetColors outline="#000000"
inner="#00000000"
inner_sel="#50c8ff62"
- item="#000000ff"
+ item="#5a5a5aff"
text="#000000"
text_sel="#ffffff"
show_shaded="FALSE"
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#000000"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#60c040"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#90929c"
title="#000000"
diff --git a/release/scripts/presets/interface_theme/rtheme.xml b/release/scripts/presets/interface_theme/rtheme.xml
index c25806729b9..1f187695909 100644
--- a/release/scripts/presets/interface_theme/rtheme.xml
+++ b/release/scripts/presets/interface_theme/rtheme.xml
@@ -217,9 +217,9 @@
<ThemeWidgetColors outline="#222222"
inner="#00000000"
inner_sel="#0abeffff"
- item="#ffffffff"
+ item="#5a5a5aff"
text="#000000"
- text_sel="#000000"
+ text_sel="#ffffff"
show_shaded="FALSE"
shadetop="0"
shadedown="0">
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#b44d4d"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#60c040"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#9098a0"
title="#000000"
diff --git a/release/scripts/presets/interface_theme/science_lab.xml b/release/scripts/presets/interface_theme/science_lab.xml
index b767e4a837b..7ebaa68b5a6 100644
--- a/release/scripts/presets/interface_theme/science_lab.xml
+++ b/release/scripts/presets/interface_theme/science_lab.xml
@@ -217,9 +217,9 @@
<ThemeWidgetColors outline="#485c6f"
inner="#00000000"
inner_sel="#678db2ff"
- item="#000000ff"
+ item="#597384ff"
text="#e5e5e5"
- text_sel="#000000"
+ text_sel="#ffffff"
show_shaded="FALSE"
shadetop="0"
shadedown="0">
@@ -300,6 +300,8 @@
camera_path="#9f5500"
skin_root="#f1b66e"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#60c040"
keyframe="#ff8500"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#666666"
title="#000000"
diff --git a/release/scripts/presets/interface_theme/softimage.xml b/release/scripts/presets/interface_theme/softimage.xml
index 5b63a775680..619af7c5e52 100644
--- a/release/scripts/presets/interface_theme/softimage.xml
+++ b/release/scripts/presets/interface_theme/softimage.xml
@@ -217,9 +217,9 @@
<ThemeWidgetColors outline="#aca8a7"
inner="#f1e59333"
inner_sel="#fff29c9a"
- item="#ffffffff"
+ item="#4849ceff"
text="#000000"
- text_sel="#000000"
+ text_sel="#ffffff"
show_shaded="FALSE"
shadetop="0"
shadedown="0">
@@ -300,6 +300,8 @@
camera_path="#000000"
skin_root="#000000"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#be8c76"
transition_strip="#d9777a"
meta_strip="#91918d"
+ text_strip="#a29700"
frame_current="#a3ff96"
keyframe="#ffeb89"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#aca8a7"
title="#000000"
diff --git a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
index d1c8b0a23ff..a319b0be5c0 100644
--- a/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
+++ b/release/scripts/presets/interface_theme/ubuntu_ambiance.xml
@@ -217,7 +217,7 @@
<ThemeWidgetColors outline="#0d0d0d"
inner="#00000000"
inner_sel="#6a3859ff"
- item="#cbc3bbff"
+ item="#6a3859ff"
text="#cbc3bb"
text_sel="#ffffff"
show_shaded="FALSE"
@@ -300,6 +300,8 @@
camera_path="#7dbd00"
skin_root="#000000"
clipping_border_3d="#313131ff"
+ text_keyframe="#ddd700"
+ text_grease_pencil="#b5e61d"
paint_curve_handle="#7fff7f7f"
paint_curve_pivot="#ff7f7f7f">
<space>
@@ -571,6 +573,8 @@
uv_shadow="#707070ff"
uv_others="#606060ff"
frame_current="#60c040"
+ metadatabg="#000000"
+ metadatatext="#ffffff"
handle_free="#000000"
handle_auto="#909000"
handle_align="#803060"
@@ -625,10 +629,13 @@
effect_strip="#a9547c"
transition_strip="#a25f6f"
meta_strip="#6d9183"
+ text_strip="#a29700"
frame_current="#c06e11"
keyframe="#f47421"
draw_action="#50c8ff"
- preview_back="#000000">
+ preview_back="#000000"
+ metadatabg="#000000"
+ metadatatext="#ffffff">
<space>
<ThemeSpaceGeneric back="#191919"
title="#acacac"
diff --git a/release/scripts/presets/units_length/centimeters.py b/release/scripts/presets/units_length/centimeters.py
new file mode 100644
index 00000000000..80d5c3e8890
--- /dev/null
+++ b/release/scripts/presets/units_length/centimeters.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'METRIC'
+scene.unit_settings.scale_length = 0.01
diff --git a/release/scripts/presets/units_length/feet.py b/release/scripts/presets/units_length/feet.py
new file mode 100644
index 00000000000..015cb810c4d
--- /dev/null
+++ b/release/scripts/presets/units_length/feet.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'IMPERIAL'
+scene.unit_settings.scale_length = 0.3048
diff --git a/release/scripts/presets/units_length/inches.py b/release/scripts/presets/units_length/inches.py
new file mode 100644
index 00000000000..7bdc96329ec
--- /dev/null
+++ b/release/scripts/presets/units_length/inches.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'IMPERIAL'
+scene.unit_settings.scale_length = 0.0254
diff --git a/release/scripts/presets/units_length/kilometers.py b/release/scripts/presets/units_length/kilometers.py
new file mode 100644
index 00000000000..d2a80e56aaa
--- /dev/null
+++ b/release/scripts/presets/units_length/kilometers.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'METRIC'
+scene.unit_settings.scale_length = 1000.0
diff --git a/release/scripts/presets/units_length/meters.py b/release/scripts/presets/units_length/meters.py
new file mode 100644
index 00000000000..831f1f26071
--- /dev/null
+++ b/release/scripts/presets/units_length/meters.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'METRIC'
+scene.unit_settings.scale_length = 1.0
diff --git a/release/scripts/presets/units_length/miles.py b/release/scripts/presets/units_length/miles.py
new file mode 100644
index 00000000000..59c1e2b36a9
--- /dev/null
+++ b/release/scripts/presets/units_length/miles.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'IMPERIAL'
+scene.unit_settings.scale_length = 1609.344
diff --git a/release/scripts/presets/units_length/millimeters.py b/release/scripts/presets/units_length/millimeters.py
new file mode 100644
index 00000000000..b89918f8b1b
--- /dev/null
+++ b/release/scripts/presets/units_length/millimeters.py
@@ -0,0 +1,5 @@
+import bpy
+scene = bpy.context.scene
+
+scene.unit_settings.system = 'METRIC'
+scene.unit_settings.scale_length = 0.001
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 35c7a55b6da..a696410ca1c 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -18,11 +18,13 @@
# <pep8 compliant>
+# support reloading sub-modules
if "bpy" in locals():
from importlib import reload
- for val in _modules_loaded.values():
+ for val in _modules_loaded:
reload(val)
del reload
+
_modules = [
"add_mesh_torus",
"anim",
@@ -47,15 +49,16 @@ _modules = [
"vertexpaint_dirt",
"view3d",
"wm",
-]
+ ]
import bpy
if bpy.app.build_options.freestyle:
_modules.append("freestyle")
+
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules if name != "bpy"}
+_modules_loaded = [_namespace[name] for name in _modules]
del _namespace
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index f3575f26890..05817216a54 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -108,10 +108,40 @@ class ANIM_OT_keying_set_export(Operator):
- id.bl_rna.name gives a name suitable for UI,
with a capitalised first letter, but we need
the plural form that's all lower case
+ - special handling is needed for "nested" ID-blocks
+ (e.g. nodetree in Material)
"""
-
- idtype_list = ksp.id.bl_rna.name.lower() + "s"
- id_bpy_path = "bpy.data.%s[\"%s\"]" % (idtype_list, ksp.id.name)
+ if ksp.id.bl_rna.identifier.startswith("ShaderNodeTree"):
+ # Find material or lamp using this node tree...
+ id_bpy_path = "bpy.data.nodes[\"%s\"]"
+ found = False
+
+ for mat in bpy.data.materials:
+ if mat.node_tree == ksp.id:
+ id_bpy_path = "bpy.data.materials[\"%s\"].node_tree" % (mat.name)
+ found = True
+ break;
+
+ if not found:
+ for lamp in bpy.data.lamps:
+ if lamp.node_tree == ksp.id:
+ id_bpy_path = "bpy.data.lamps[\"%s\"].node_tree" % (lamp.name)
+ found = True
+ break;
+
+ if not found:
+ self.report({'WARN'}, "Could not find material or lamp using Shader Node Tree - %s" % (ksp.id))
+ elif ksp.id.bl_rna.identifier.startswith("CompositorNodeTree"):
+ # Find compositor nodetree using this node tree...
+ for scene in bpy.data.scenes:
+ if scene.node_tree == ksp.id:
+ id_bpy_path = "bpy.data.scenes[\"%s\"].node_tree" % (scene.name)
+ break;
+ else:
+ self.report({'WARN'}, "Could not find scene using Compositor Node Tree - %s" % (ksp.id))
+ else:
+ idtype_list = ksp.id.bl_rna.name.lower() + "s"
+ id_bpy_path = "bpy.data.%s[\"%s\"]" % (idtype_list, ksp.id.name)
# shorthand ID for the ID-block (as used in the script)
short_id = "id_%d" % len(id_to_paths_cache)
diff --git a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
new file mode 100644
index 00000000000..77e590fd8ce
--- /dev/null
+++ b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
@@ -0,0 +1,350 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# Utilities to detect the next matching element (vert/edge/face)
+# based on an existing pair of elements.
+
+import bmesh
+
+__all__ = (
+ "select_prev",
+ "select_next",
+ )
+
+
+def other_edges_over_face(e):
+ # Can yield same edge multiple times, its fine.
+ for l in e.link_loops:
+ yield l.link_loop_next.edge
+ yield l.link_loop_prev.edge
+
+
+def other_edges_over_edge(e):
+ # Can yield same edge multiple times, its fine.
+ for v in e.verts:
+ for e_other in v.link_edges:
+ if e_other is not e:
+ if not e.is_wire:
+ yield e_other
+
+
+def verts_from_elem(ele):
+ ele_type = type(ele)
+ if ele_type is bmesh.types.BMFace:
+ return [l.vert for l in ele.loops]
+ elif ele_type is bmesh.types.BMEdge:
+ return [v for v in ele.verts]
+ elif ele_type is bmesh.types.BMVert:
+ return [ele]
+ else:
+ raise TypeError("wrong type")
+
+
+def edges_from_elem(ele):
+ ele_type = type(ele)
+ if ele_type is bmesh.types.BMFace:
+ return [l.edge for l in ele.loops]
+ elif ele_type is bmesh.types.BMEdge:
+ return [ele]
+ elif ele_type is bmesh.types.BMVert:
+ return [e for e in ele.link_edges]
+ else:
+ raise TypeError("wrong type")
+
+
+def elems_depth_search(ele_init, depths, other_edges_over_cb, results_init=None):
+ """
+ List of depths -> List of elems that match those depths.
+ """
+
+ depth_max = max(depths)
+ depth_min = min(depths)
+ depths_sorted = tuple(sorted(depths))
+
+ stack_old = edges_from_elem(ele_init)
+ stack_new = []
+
+ stack_visit = set(stack_old)
+
+ vert_depths = {}
+ vert_depths_setdefault = vert_depths.setdefault
+
+ depth = 0
+ while stack_old and depth <= depth_max:
+ for ele in stack_old:
+ for v in verts_from_elem(ele):
+ vert_depths_setdefault(v, depth)
+ for ele_other in other_edges_over_cb(ele):
+ stack_visit_len = len(stack_visit)
+ stack_visit.add(ele_other)
+ if stack_visit_len != len(stack_visit):
+ stack_new.append(ele_other)
+ stack_new, stack_old = stack_old, stack_new
+ stack_new[:] = []
+ depth += 1
+
+ # now we have many verts in vert_depths which are attached to elements
+ # which are candidates for matching with depths
+ if type(ele_init) is bmesh.types.BMFace:
+ test_ele = {
+ l.face for v, depth in vert_depths.items()
+ if depth >= depth_min for l in v.link_loops}
+ elif type(ele_init) is bmesh.types.BMEdge:
+ test_ele = {
+ e for v, depth in vert_depths.items()
+ if depth >= depth_min for e in v.link_edges if not e.is_wire}
+ else:
+ test_ele = {
+ v for v, depth in vert_depths.items()
+ if depth >= depth_min for e in v.link_edges if not e.is_wire}
+
+ result_ele = set()
+
+ vert_depths_get = vert_depths.get
+ # re-used each time, will always be the same length
+ depths_test = [None] * len(depths)
+
+ for ele in test_ele:
+ verts_test = verts_from_elem(ele)
+ if len(verts_test) != len(depths):
+ continue
+ if results_init is not None and ele not in results_init:
+ continue
+ if ele in result_ele:
+ continue
+
+ ok = True
+ for i, v in enumerate(verts_test):
+ depth = vert_depths_get(v)
+ if depth is not None:
+ depths_test[i] = depth
+ else:
+ ok = False
+ break
+
+ if ok:
+ if depths_sorted == tuple(sorted(depths_test)):
+ # Note, its possible the order of sorted items moves the values out-of-order.
+ # for this we could do a circular list comparison,
+ # however - this is such a rare case that we're ignoring it.
+ result_ele.add(ele)
+
+ return result_ele
+
+
+def elems_depth_measure(ele_dst, ele_src, other_edges_over_cb):
+ """
+ Returns·ele_dst vert depths from ele_src, aligned with ele_dst verts.
+ """
+
+ stack_old = edges_from_elem(ele_src)
+ stack_new = []
+
+ stack_visit = set(stack_old)
+
+ # continue until we've reached all verts in the destination
+ ele_dst_verts = verts_from_elem(ele_dst)
+ all_dst = set(ele_dst_verts)
+ all_dst_discard = all_dst.discard
+
+ vert_depths = {}
+
+ depth = 0
+ while stack_old and all_dst:
+ for ele in stack_old:
+ for v in verts_from_elem(ele):
+ len_prev = len(all_dst)
+ all_dst_discard(v)
+ if len_prev != len(all_dst):
+ vert_depths[v] = depth
+
+ for ele_other in other_edges_over_cb(ele):
+ stack_visit_len = len(stack_visit)
+ stack_visit.add(ele_other)
+ if stack_visit_len != len(stack_visit):
+ stack_new.append(ele_other)
+ stack_new, stack_old = stack_old, stack_new
+ stack_new[:] = []
+ depth += 1
+
+ if not all_dst:
+ return [vert_depths[v] for v in ele_dst_verts]
+ else:
+ return None
+
+
+def find_next(ele_dst, ele_src):
+ depth_src_a = elems_depth_measure(ele_dst, ele_src, other_edges_over_edge)
+ depth_src_b = elems_depth_measure(ele_dst, ele_src, other_edges_over_face)
+
+ # path not found
+ if depth_src_a is None or depth_src_b is None:
+ return []
+
+ depth_src = tuple(zip(depth_src_a, depth_src_b))
+
+ candidates = elems_depth_search(ele_dst, depth_src_a, other_edges_over_edge)
+ candidates = elems_depth_search(ele_dst, depth_src_b, other_edges_over_face, candidates)
+ candidates.discard(ele_src)
+ if not candidates:
+ return []
+
+ # Now we have to pick which is the best next-element,
+ # do this by calculating the element with the largest
+ # variation in depth from the relationship to the source.
+ # ... So we have the highest chance of stepping onto the opposite element.
+ diff_best = 0
+ ele_best = None
+ ele_best_tot = 0
+ ele_best_ls = []
+ for ele_test in candidates:
+ depth_test_a = elems_depth_measure(ele_dst, ele_test, other_edges_over_edge)
+ depth_test_b = elems_depth_measure(ele_dst, ele_test, other_edges_over_face)
+ depth_test = tuple(zip(depth_test_a, depth_test_b))
+ # square so a few high values win over many small ones
+ diff_test = sum((abs(a[0] - b[0]) ** 2) +
+ (abs(a[1] - b[1]) ** 2) for a, b in zip(depth_src, depth_test))
+ if diff_test > diff_best:
+ diff_best = diff_test
+ ele_best = ele_test
+ ele_best_tot = 1
+ ele_best_ls[:] = [ele_best]
+ elif diff_test == diff_best:
+ if ele_best is None:
+ ele_best = ele_test
+ ele_best_tot += 1
+ ele_best_ls.append(ele_test)
+
+ if len(ele_best_ls) > 1:
+ ele_best_ls_init = ele_best_ls
+ ele_best_ls = []
+ depth_accum_max = -1
+ for ele_test in ele_best_ls_init:
+ depth_accum_test = (
+ sum(elems_depth_measure(ele_src, ele_test, other_edges_over_edge)) +
+ sum(elems_depth_measure(ele_src, ele_test, other_edges_over_face)))
+
+ if depth_accum_test > depth_accum_max:
+ depth_accum_max = depth_accum_test
+ ele_best = ele_test
+ ele_best_ls[:] = [ele_best]
+ elif depth_accum_test == depth_accum_max:
+ # we have multiple bests, don't return any
+ ele_best_ls.append(ele_test)
+
+ return ele_best_ls
+
+
+# expose for operators
+def select_next(bm, report):
+ import bmesh
+ ele_pair = [None, None]
+ for i, ele in enumerate(reversed(bm.select_history)):
+ ele_pair[i] = ele
+ if i == 1:
+ break
+
+ if ele_pair[-1] is None:
+ report({'INFO'}, "Selection pair not found")
+ return False
+
+ ele_pair_next = find_next(*ele_pair)
+
+ if len(ele_pair_next) > 1:
+ # We have multiple options,
+ # check topology around the element and find the closest match
+ # (allow for sloppy comparison if exact checks fail).
+
+ def ele_uuid(ele):
+ ele_type = type(ele)
+ if ele_type is bmesh.types.BMFace:
+ ret = [len(f.verts) for l in ele.loops for f in l.edge.link_faces if f is not ele]
+ elif ele_type is bmesh.types.BMEdge:
+ ret = [len(l.face.verts) for l in ele.link_loops]
+ elif ele_type is bmesh.types.BMVert:
+ ret = [len(l.face.verts) for l in ele.link_loops]
+ else:
+ raise TypeError("wrong type")
+ return tuple(sorted(ret))
+
+ def ele_uuid_filter():
+
+ def pass_fn(seq):
+ return seq
+
+ def sum_set(seq):
+ return sum(set(seq))
+
+ uuid_cmp = ele_uuid(ele_pair[0])
+ ele_pair_next_uuid = [(ele, ele_uuid(ele)) for ele in ele_pair_next]
+
+ # Attempt to find the closest match,
+ # start specific, use increasingly more approximate comparisons.
+ for fn in (pass_fn, set, sum_set, len):
+ uuid_cmp_test = fn(uuid_cmp)
+ ele_pair_next_uuid_test = [
+ (ele, uuid) for (ele, uuid) in ele_pair_next_uuid
+ if uuid_cmp_test == fn(uuid)]
+ if len(ele_pair_next_uuid_test) > 1:
+ ele_pair_next_uuid = ele_pair_next_uuid_test
+ elif len(ele_pair_next_uuid_test) == 1:
+ return [ele for (ele, uuid) in ele_pair_next_uuid_test]
+ return []
+
+ ele_pair_next[:] = ele_uuid_filter()
+
+ del ele_uuid, ele_uuid_filter
+
+ if len(ele_pair_next) != 1:
+ report({'INFO'}, "No single next item found")
+ return False
+
+ ele = ele_pair_next[0]
+ if ele.hide:
+ report({'INFO'}, "Next element is hidden")
+ return False
+
+ ele.select_set(False)
+ ele.select_set(True)
+ bm.select_history.discard(ele)
+ bm.select_history.add(ele)
+ if type(ele) is bmesh.types.BMFace:
+ bm.faces.active = ele
+ return True
+
+
+def select_prev(bm, report):
+ import bmesh
+ for ele in reversed(bm.select_history):
+ break
+ else:
+ report({'INFO'}, "Last selected not found")
+ return False
+
+ ele.select_set(False)
+
+ for i, ele in enumerate(reversed(bm.select_history)):
+ if i == 1:
+ if type(ele) is bmesh.types.BMFace:
+ bm.faces.active = ele
+ break
+
+ return True
+
diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py
index efcc7d5c65e..64cc0aeddb3 100644
--- a/release/scripts/startup/bl_operators/file.py
+++ b/release/scripts/startup/bl_operators/file.py
@@ -86,6 +86,11 @@ class WM_OT_previews_batch_generate(Operator):
name="Trusted Blend Files",
description="Enable python evaluation for selected files",
)
+ use_backups = BoolProperty(
+ default=True,
+ name="Save Backups",
+ description="Keep a backup (.blend1) version of the files when saving with generated previews",
+ )
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
@@ -126,6 +131,8 @@ class WM_OT_previews_batch_generate(Operator):
cmd.append('--no_objects')
if not self.use_intern_data:
cmd.append('--no_data_intern')
+ if not self.use_backups:
+ cmd.append("--no_backups")
if subprocess.call(cmd):
self.report({'ERROR'}, "Previews generation process failed for file '%s'!" % blen_path)
context.window_manager.progress_end()
@@ -192,6 +199,11 @@ class WM_OT_previews_batch_clear(Operator):
name="Trusted Blend Files",
description="Enable python evaluation for selected files",
)
+ use_backups = BoolProperty(
+ default=True,
+ name="Save Backups",
+ description="Keep a backup (.blend1) version of the files when saving with cleared previews",
+ )
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
@@ -233,6 +245,8 @@ class WM_OT_previews_batch_clear(Operator):
cmd.append('--no_objects')
if not self.use_intern_data:
cmd.append('--no_data_intern')
+ if not self.use_backups:
+ cmd.append("--no_backups")
if subprocess.call(cmd):
self.report({'ERROR'}, "Previews clear process failed for file '%s'!" % blen_path)
context.window_manager.progress_end()
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index ea504d48448..be74f8dbc0e 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -148,3 +148,53 @@ class MeshMirrorUV(Operator):
double_warn)
return {'FINISHED'}
+
+
+class MeshSelectNext(Operator):
+ """Select the next element (using selection order)"""
+ bl_idname = "mesh.select_next_item"
+ bl_label = "Select Next Element"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.mode == 'EDIT_MESH')
+
+ def execute(self, context):
+ import bmesh
+ from .bmesh import find_adjacent
+
+ obj = context.active_object
+ me = obj.data
+ bm = bmesh.from_edit_mesh(me)
+
+ if find_adjacent.select_next(bm, self.report):
+ bm.select_flush_mode()
+ bmesh.update_edit_mesh(me, False)
+
+ return {'FINISHED'}
+
+
+class MeshSelectPrev(Operator):
+ """Select the next element (using selection order)"""
+ bl_idname = "mesh.select_prev_item"
+ bl_label = "Select Previous Element"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.mode == 'EDIT_MESH')
+
+ def execute(self, context):
+ import bmesh
+ from .bmesh import find_adjacent
+
+ obj = context.active_object
+ me = obj.data
+ bm = bmesh.from_edit_mesh(me)
+
+ if find_adjacent.select_prev(bm, self.report):
+ bm.select_flush_mode()
+ bmesh.update_edit_mesh(me, False)
+
+ return {'FINISHED'}
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index d6aeab5c02b..acff259e503 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -36,7 +36,8 @@ from bpy.props import (
class NodeSetting(PropertyGroup):
value = StringProperty(
name="Value",
- description="Python expression to be evaluated as the initial node setting",
+ description="Python expression to be evaluated "
+ "as the initial node setting",
default="",
)
@@ -68,12 +69,15 @@ class NodeAddOperator:
# convert mouse position to the View2D for later node placement
if context.region.type == 'WINDOW':
# convert mouse position to the View2D for later node placement
- space.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y)
+ space.cursor_location_from_region(
+ event.mouse_region_x, event.mouse_region_y)
else:
space.cursor_location = tree.view_center
- # XXX explicit node_type argument is usually not necessary, but required to make search operator work:
- # add_search has to override the 'type' property since it's hardcoded in bpy_operator_wrap.c ...
+ # XXX explicit node_type argument is usually not necessary,
+ # but required to make search operator work:
+ # add_search has to override the 'type' property
+ # since it's hardcoded in bpy_operator_wrap.c ...
def create_node(self, context, node_type=None):
space = context.space_data
tree = space.edit_tree
@@ -94,7 +98,9 @@ class NodeAddOperator:
try:
setattr(node, setting.name, value)
except AttributeError as e:
- self.report({'ERROR_INVALID_INPUT'}, "Node has no attribute " + setting.name)
+ self.report(
+ {'ERROR_INVALID_INPUT'},
+ "Node has no attribute " + setting.name)
print(str(e))
# Continue despite invalid attribute
@@ -107,7 +113,8 @@ class NodeAddOperator:
def poll(cls, context):
space = context.space_data
# needs active node editor and a tree to add nodes to
- return (space.type == 'NODE_EDITOR' and space.edit_tree and not space.edit_tree.library)
+ return ((space.type == 'NODE_EDITOR') and
+ space.edit_tree and not space.edit_tree.library)
# Default execute simply adds a node
def execute(self, context):
@@ -187,7 +194,12 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
if isinstance(item, nodeitems_utils.NodeItem):
nodetype = getattr(bpy.types, item.nodetype, None)
if nodetype:
- enum_items.append((str(index), item.label, nodetype.bl_rna.description, index))
+ enum_items.append(
+ (str(index),
+ item.label,
+ nodetype.bl_rna.description,
+ index,
+ ))
return enum_items
# Look up the item based on index
@@ -220,7 +232,8 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
self.create_node(context, item.nodetype)
if self.use_transform:
- bpy.ops.node.translate_attach_remove_on_cancel('INVOKE_DEFAULT')
+ bpy.ops.node.translate_attach_remove_on_cancel(
+ 'INVOKE_DEFAULT')
return {'FINISHED'}
else:
@@ -243,7 +256,8 @@ class NODE_OT_collapse_hide_unused_toggle(Operator):
def poll(cls, context):
space = context.space_data
# needs active node editor and a tree
- return (space.type == 'NODE_EDITOR' and space.edit_tree and not space.edit_tree.library)
+ return ((space.type == 'NODE_EDITOR') and
+ (space.edit_tree and not space.edit_tree.library))
def execute(self, context):
space = context.space_data
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index 3c84e5dc553..5c3d95e113c 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -125,7 +125,10 @@ def align_objects(context,
relative_to,
bb_quality):
- cursor = context.scene.cursor_location
+ scene = context.scene
+ space = context.space_data
+
+ cursor = (space if space and space.type == 'VIEW_3D' else scene).cursor_location
Left_Front_Up_SEL = [0.0, 0.0, 0.0]
Right_Back_Down_SEL = [0.0, 0.0, 0.0]
@@ -136,7 +139,7 @@ def align_objects(context,
for obj in context.selected_objects:
matrix_world = obj.matrix_world.copy()
- bb_world = [matrix_world * Vector(v[:]) for v in obj.bound_box]
+ bb_world = [matrix_world * Vector(v) for v in obj.bound_box]
objects.append((obj, bb_world))
if not objects:
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 63c1945d2d2..e01e509b292 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -169,14 +169,16 @@ class AddPresetBase:
if not filepath:
return {'CANCELLED'}
- if hasattr(self, "remove"):
- self.remove(context, filepath)
- else:
- try:
+ try:
+ if hasattr(self, "remove"):
+ self.remove(context, filepath)
+ else:
os.remove(filepath)
- except:
- import traceback
- traceback.print_exc()
+ except Exception as e:
+ self.report({'ERROR'}, "Unable to remove preset: %r" % e)
+ import traceback
+ traceback.print_exc()
+ return {'CANCELLED'}
# XXX, stupid!
preset_menu_class.bl_label = "Presets"
@@ -660,3 +662,21 @@ class WM_MT_operator_presets(Menu):
return AddPresetOperator.operator_path(self.operator)
preset_operator = "script.execute_preset"
+
+
+class AddPresetUnitsLength(AddPresetBase, Operator):
+ """Add or remove length units preset"""
+ bl_idname = "scene.units_length_preset_add"
+ bl_label = "Add Length Units Preset"
+ preset_menu = "SCENE_MT_units_length_presets"
+
+ preset_defines = [
+ "scene = bpy.context.scene"
+ ]
+
+ preset_values = [
+ "scene.unit_settings.system",
+ "scene.unit_settings.scale_length",
+ ]
+
+ preset_subdir = "units_length"
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 237c2d55672..750a5b0bf0f 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -163,7 +163,7 @@ class BakeToKeyframes(Operator):
elif rot_mode == 'AXIS_ANGLE':
# this is a little roundabout but there's no better way right now
aa = mat.to_quaternion().to_axis_angle()
- obj.rotation_axis_angle = (aa[1], ) + aa[0][:]
+ obj.rotation_axis_angle = (aa[1], *aa[0])
else: # euler
# make sure euler rotation is compatible to previous frame
# NOTE: assume that on first frame, the starting rotation is appropriate
diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
index 73e6bcd9b0c..52e7b0e0ae4 100644
--- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py
+++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py
@@ -23,7 +23,11 @@ import bpy
from bpy.types import Operator
DEG_TO_RAD = 0.017453292519943295 # pi/180.0
-SMALL_NUM = 0.00000001 # see bug [#31598] why we dont have smaller values
+# see bugs:
+# - T31598 (when too small).
+# - T48086 (when too big).
+SMALL_NUM = 1e-12
+
global USER_FILL_HOLES
global USER_FILL_HOLES_QUALITY
@@ -708,7 +712,8 @@ def main(context,
island_margin,
projection_limit,
user_area_weight,
- use_aspect
+ use_aspect,
+ stretch_to_bounds,
):
global USER_FILL_HOLES
global USER_FILL_HOLES_QUALITY
@@ -733,7 +738,7 @@ def main(context,
USER_PROJECTION_LIMIT = projection_limit
USER_ONLY_SELECTED_FACES = True
USER_SHARE_SPACE = 1 # Only for hole filling.
- USER_STRETCH_ASPECT = 1 # Only for hole filling.
+ USER_STRETCH_ASPECT = stretch_to_bounds
USER_ISLAND_MARGIN = island_margin # Only for hole filling.
USER_FILL_HOLES = 0
USER_FILL_HOLES_QUALITY = 50 # Only for hole filling.
@@ -812,9 +817,6 @@ def main(context,
else:
meshFaces = [thickface(f, uv_layer, me_verts) for i, f in enumerate(me.polygons)]
- if not meshFaces:
- continue
-
#XXX Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces)))
# =======
@@ -834,6 +836,9 @@ def main(context,
uv.zero()
meshFaces.pop()
+ if not meshFaces:
+ continue
+
# Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data.
# Generate Projection Vecs
@@ -1031,8 +1036,7 @@ def main(context,
'',\
'UV Layout',\
('Share Tex Space', USER_SHARE_SPACE, 'Objects Share texture space, map all objects into 1 uvmap.'),\
- ('Stretch to bounds', USER_STRETCH_ASPECT, 'Stretch the final output to texture bounds.'),\
-* ('Island Margin:', USER_ISLAND_MARGIN, 0.0, 0.5, ''),\
+ ('Island Margin:', USER_ISLAND_MARGIN, 0.0, 0.5, ''),\
'Fill in empty areas',\
('Fill Holes', USER_FILL_HOLES, 'Fill in empty areas reduced texture waistage (slow).'),\
('Fill Quality:', USER_FILL_HOLES_QUALITY, 1, 100, 'Depends on fill holes, how tightly to fill UV holes, (higher is slower)'),\
@@ -1073,6 +1077,11 @@ class SmartProject(Operator):
description="Map UVs taking image aspect ratio into account",
default=True
)
+ stretch_to_bounds = BoolProperty(
+ name="Stretch to UV Bounds",
+ description="Stretch the final output to texture bounds",
+ default=True,
+ )
@classmethod
def poll(cls, context):
@@ -1083,7 +1092,8 @@ class SmartProject(Operator):
self.island_margin,
self.angle_limit,
self.user_area_weight,
- self.use_aspect
+ self.use_aspect,
+ self.stretch_to_bounds
)
return {'FINISHED'}
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index c228e33965f..76d41d91b78 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -43,6 +43,12 @@ rna_reverse_prop = BoolProperty(
default=False,
)
+rna_wrap_prop = BoolProperty(
+ name="Wrap",
+ description="Wrap back to the first/last values",
+ default=False,
+ )
+
rna_relative_prop = BoolProperty(
name="Relative",
description="Apply relative to the current value (delta)",
@@ -399,6 +405,7 @@ class WM_OT_context_cycle_int(Operator):
data_path = rna_path_prop
reverse = rna_reverse_prop
+ wrap = rna_wrap_prop
def execute(self, context):
data_path = self.data_path
@@ -413,14 +420,15 @@ class WM_OT_context_cycle_int(Operator):
exec("context.%s = value" % data_path)
- if value != eval("context.%s" % data_path):
- # relies on rna clamping integers out of the range
- if self.reverse:
- value = (1 << 31) - 1
- else:
- value = -1 << 31
+ if self.wrap:
+ if value != eval("context.%s" % data_path):
+ # relies on rna clamping integers out of the range
+ if self.reverse:
+ value = (1 << 31) - 1
+ else:
+ value = -1 << 31
- exec("context.%s = value" % data_path)
+ exec("context.%s = value" % data_path)
return operator_path_undo_return(context, data_path)
@@ -433,6 +441,7 @@ class WM_OT_context_cycle_enum(Operator):
data_path = rna_path_prop
reverse = rna_reverse_prop
+ wrap = rna_wrap_prop
def execute(self, context):
data_path = self.data_path
@@ -460,15 +469,18 @@ class WM_OT_context_cycle_enum(Operator):
enums = rna_struct.properties[rna_prop_str].enum_items.keys()
orig_index = enums.index(orig_value)
- # Have the info we need, advance to the next item
+ # Have the info we need, advance to the next item.
+ #
+ # When wrap's disabled we may set the value to its self,
+ # this is done to ensure update callbacks run.
if self.reverse:
if orig_index == 0:
- advance_enum = enums[-1]
+ advance_enum = enums[-1] if self.wrap else enums[0]
else:
advance_enum = enums[orig_index - 1]
else:
if orig_index == len(enums) - 1:
- advance_enum = enums[0]
+ advance_enum = enums[0] if self.wrap else enums[-1]
else:
advance_enum = enums[orig_index + 1]
@@ -1115,6 +1127,10 @@ rna_max = FloatProperty(
precision=3,
)
+rna_use_soft_limits = BoolProperty(
+ name="Use Soft Limits",
+ )
+
class WM_OT_properties_edit(Operator):
bl_idname = "wm.properties_edit"
@@ -1127,10 +1143,21 @@ class WM_OT_properties_edit(Operator):
value = rna_value
min = rna_min
max = rna_max
+ use_soft_limits = rna_use_soft_limits
+ soft_min = rna_min
+ soft_max = rna_max
description = StringProperty(
name="Tooltip",
)
+ def _cmp_props_get(self):
+ # Changing these properties will refresh the UI
+ return {
+ "use_soft_limits": self.use_soft_limits,
+ "soft_range": (self.soft_min, self.soft_max),
+ "hard_range": (self.min, self.max),
+ }
+
def execute(self, context):
from rna_prop_ui import (
rna_idprop_ui_prop_get,
@@ -1178,8 +1205,15 @@ class WM_OT_properties_edit(Operator):
prop_ui = rna_idprop_ui_prop_get(item, prop)
if prop_type in {float, int}:
- prop_ui["soft_min"] = prop_ui["min"] = prop_type(self.min)
- prop_ui["soft_max"] = prop_ui["max"] = prop_type(self.max)
+ prop_ui["min"] = prop_type(self.min)
+ prop_ui["max"] = prop_type(self.max)
+
+ if self.use_soft_limits:
+ prop_ui["soft_min"] = prop_type(self.soft_min)
+ prop_ui["soft_max"] = prop_type(self.soft_max)
+ else:
+ prop_ui["soft_min"] = prop_type(self.min)
+ prop_ui["soft_max"] = prop_type(self.max)
prop_ui["description"] = self.description
@@ -1240,9 +1274,62 @@ class WM_OT_properties_edit(Operator):
self.max = prop_ui.get("max", 1000000000)
self.description = prop_ui.get("description", "")
+ self.soft_min = prop_ui.get("soft_min", self.min)
+ self.soft_max = prop_ui.get("soft_max", self.max)
+ self.use_soft_limits = (
+ self.min != self.soft_min or
+ self.max != self.soft_max)
+
+ # store for comparison
+ self._cmp_props = self._cmp_props_get()
+
wm = context.window_manager
return wm.invoke_props_dialog(self)
+ def check(self, context):
+ cmp_props = self._cmp_props_get()
+ changed = False
+ if self._cmp_props != cmp_props:
+ if cmp_props["use_soft_limits"]:
+ if cmp_props["soft_range"] != self._cmp_props["soft_range"]:
+ self.min = min(self.min, self.soft_min)
+ self.max = max(self.max, self.soft_max)
+ changed = True
+ if cmp_props["hard_range"] != self._cmp_props["hard_range"]:
+ self.soft_min = max(self.min, self.soft_min)
+ self.soft_max = min(self.max, self.soft_max)
+ changed = True
+ else:
+ if cmp_props["soft_range"] != cmp_props["hard_range"]:
+ self.soft_min = self.min
+ self.soft_max = self.max
+ changed = True
+
+ changed |= (cmp_props["use_soft_limits"] != self._cmp_props["use_soft_limits"])
+
+ if changed:
+ cmp_props = self._cmp_props_get()
+
+ self._cmp_props = cmp_props
+
+ return changed
+
+ def draw(self, context):
+ layout = self.layout
+ layout.prop(self, "property")
+ layout.prop(self, "value")
+ row = layout.row(align=True)
+ row.prop(self, "min")
+ row.prop(self, "max")
+
+ layout.prop(self, "use_soft_limits")
+
+ row = layout.row(align=True)
+ row.enabled = self.use_soft_limits
+ row.prop(self, "soft_min", text="Soft Min")
+ row.prop(self, "soft_max", text="Soft Max")
+ layout.prop(self, "description")
+
class WM_OT_properties_add(Operator):
bl_idname = "wm.properties_add"
@@ -1376,15 +1463,32 @@ class WM_OT_appconfig_activate(Operator):
class WM_OT_sysinfo(Operator):
- """Generate System Info"""
+ """Generate system information, saved into a text file"""
+
bl_idname = "wm.sysinfo"
- bl_label = "System Info"
+ bl_label = "Save System Info"
+
+ filepath = StringProperty(
+ subtype='FILE_PATH',
+ options={'SKIP_SAVE'},
+ )
def execute(self, context):
import sys_info
- sys_info.write_sysinfo(self)
+ sys_info.write_sysinfo(self.filepath)
return {'FINISHED'}
+ def invoke(self, context, event):
+ import os
+
+ if not self.filepath:
+ self.filepath = os.path.join(
+ os.path.expanduser("~"), "system-info.txt")
+
+ wm = context.window_manager
+ wm.fileselect_add(self)
+ return {'RUNNING_MODAL'}
+
class WM_OT_copy_prev_settings(Operator):
"""Copy settings from previous version"""
@@ -1402,7 +1506,7 @@ class WM_OT_copy_prev_settings(Operator):
if os.path.isdir(path_dst):
self.report({'ERROR'}, "Target path %r exists" % path_dst)
elif not os.path.isdir(path_src):
- self.report({'ERROR'}, "Source path %r exists" % path_src)
+ self.report({'ERROR'}, "Source path %r does not exist" % path_src)
else:
shutil.copytree(path_src, path_dst, symlinks=True)
@@ -1736,16 +1840,16 @@ class WM_OT_operator_cheat_sheet(Operator):
# -----------------------------------------------------------------------------
-# Addon Operators
+# Add-on Operators
class WM_OT_addon_enable(Operator):
- "Enable an addon"
+ "Enable an add-on"
bl_idname = "wm.addon_enable"
- bl_label = "Enable Addon"
+ bl_label = "Enable Add-on"
module = StringProperty(
name="Module",
- description="Module name of the addon to enable",
+ description="Module name of the add-on to enable",
)
def execute(self, context):
@@ -1753,7 +1857,7 @@ class WM_OT_addon_enable(Operator):
err_str = ""
- def err_cb():
+ def err_cb(ex):
import traceback
nonlocal err_str
err_str = traceback.format_exc()
@@ -1783,13 +1887,13 @@ class WM_OT_addon_enable(Operator):
class WM_OT_addon_disable(Operator):
- "Disable an addon"
+ "Disable an add-on"
bl_idname = "wm.addon_disable"
- bl_label = "Disable Addon"
+ bl_label = "Disable Add-on"
module = StringProperty(
name="Module",
- description="Module name of the addon to disable",
+ description="Module name of the add-on to disable",
)
def execute(self, context):
@@ -1797,7 +1901,7 @@ class WM_OT_addon_disable(Operator):
err_str = ""
- def err_cb():
+ def err_cb(ex):
import traceback
nonlocal err_str
err_str = traceback.format_exc()
@@ -1871,7 +1975,7 @@ class WM_OT_theme_install(Operator):
class WM_OT_addon_refresh(Operator):
- "Scan addon directories for new modules"
+ "Scan add-on directories for new modules"
bl_idname = "wm.addon_refresh"
bl_label = "Refresh"
@@ -1884,13 +1988,13 @@ class WM_OT_addon_refresh(Operator):
class WM_OT_addon_install(Operator):
- "Install an addon"
+ "Install an add-on"
bl_idname = "wm.addon_install"
bl_label = "Install from File..."
overwrite = BoolProperty(
name="Overwrite",
- description="Remove existing addons with the same ID",
+ description="Remove existing add-ons with the same ID",
default=True,
)
target = EnumProperty(
@@ -1949,7 +2053,7 @@ class WM_OT_addon_install(Operator):
path_addons = os.path.join(path_addons, "addons")
if not path_addons:
- self.report({'ERROR'}, "Failed to get addons path")
+ self.report({'ERROR'}, "Failed to get add-ons path")
return {'CANCELLED'}
if not os.path.isdir(path_addons):
@@ -1965,7 +2069,7 @@ class WM_OT_addon_install(Operator):
pyfile_dir = os.path.dirname(pyfile)
for addon_path in addon_utils.paths():
if os.path.samefile(pyfile_dir, addon_path):
- self.report({'ERROR'}, "Source file is in the addon search path: %r" % addon_path)
+ self.report({'ERROR'}, "Source file is in the add-on search path: %r" % addon_path)
return {'CANCELLED'}
del addon_path
del pyfile_dir
@@ -2049,13 +2153,13 @@ class WM_OT_addon_install(Operator):
class WM_OT_addon_remove(Operator):
- "Delete the addon from the file system"
+ "Delete the add-on from the file system"
bl_idname = "wm.addon_remove"
- bl_label = "Remove Addon"
+ bl_label = "Remove Add-on"
module = StringProperty(
name="Module",
- description="Module name of the addon to remove",
+ description="Module name of the add-on to remove",
)
@staticmethod
@@ -2079,7 +2183,7 @@ class WM_OT_addon_remove(Operator):
path, isdir = WM_OT_addon_remove.path_from_addon(self.module)
if path is None:
- self.report({'WARNING'}, "Addon path %r could not be found" % path)
+ self.report({'WARNING'}, "Add-on path %r could not be found" % path)
return {'CANCELLED'}
# in case its enabled
@@ -2098,7 +2202,7 @@ class WM_OT_addon_remove(Operator):
# lame confirmation check
def draw(self, context):
- self.layout.label(text="Remove Addon: %r?" % self.module)
+ self.layout.label(text="Remove Add-on: %r?" % self.module)
path, isdir = WM_OT_addon_remove.path_from_addon(self.module)
self.layout.label(text="Path: %r" % path)
@@ -2108,14 +2212,14 @@ class WM_OT_addon_remove(Operator):
class WM_OT_addon_expand(Operator):
- "Display more information on this addon"
+ "Display information and preferences for this add-on"
bl_idname = "wm.addon_expand"
bl_label = ""
bl_options = {'INTERNAL'}
module = StringProperty(
name="Module",
- description="Module name of the addon to expand",
+ description="Module name of the add-on to expand",
)
def execute(self, context):
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index c110b429aad..6fc668e67f5 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -20,11 +20,13 @@
# note, properties_animviz is a helper module only.
+# support reloading sub-modules
if "bpy" in locals():
from importlib import reload
- for val in _modules_loaded.values():
+ for val in _modules_loaded:
reload(val)
del reload
+
_modules = [
"properties_animviz",
"properties_constraint",
@@ -78,15 +80,16 @@ _modules = [
"space_userpref",
"space_view3d",
"space_view3d_toolbar",
-]
+ ]
import bpy
if bpy.app.build_options.freestyle:
_modules.append("properties_freestyle")
+
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules if name != "bpy"}
+_modules_loaded = [_namespace[name] for name in _modules]
del _namespace
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 7ade444d7ae..ef0fc9c7c9f 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -440,7 +440,7 @@ class ConstraintButtonsPanel:
self.space_template(layout, con)
- #def SCRIPT(self, context, layout, con):
+ # def SCRIPT(self, context, layout, con):
def ACTION(self, context, layout, con):
self.target_template(layout, con)
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index a14e34580c5..690c22c1440 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -220,7 +220,7 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
col = split.column()
col.prop(bone, "hide", text="Hide")
sub = col.column()
- sub.active = bool(pchan.custom_shape)
+ sub.active = bool(pchan and pchan.custom_shape)
sub.prop(bone, "show_wire", text="Wireframe")
if pchan:
@@ -229,6 +229,8 @@ class BONE_PT_display(BoneButtonsPanel, Panel):
col.label(text="Custom Shape:")
col.prop(pchan, "custom_shape", text="")
if pchan.custom_shape:
+ col.prop(pchan, "use_custom_shape_bone_size", text="Bone Size")
+ col.prop(pchan, "custom_shape_scale", text="Scale")
col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 108e8bdfc74..58a4820e27a 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -147,8 +147,12 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
- # render = context.scene.render
+ render = context.scene.render
st = context.camera.stereo
+ cam = context.camera
+
+ is_spherical_stereo = cam.type != 'ORTHO' and render.use_spherical_stereo
+ use_spherical_stereo = is_spherical_stereo and st.use_spherical_stereo
col = layout.column()
col.row().prop(st, "convergence_mode", expand=True)
@@ -159,8 +163,14 @@ class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
col.prop(st, "interocular_distance")
+ if is_spherical_stereo:
+ col.separator()
+ col.prop(st, "use_spherical_stereo")
+
col.label(text="Pivot:")
- col.row().prop(st, "pivot", expand=True)
+ row = col.row()
+ row.active = not use_spherical_stereo
+ row.prop(st, "pivot", expand=True)
class DATA_PT_camera(CameraButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index f83dea996e6..81ecd2e8db5 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -188,7 +188,10 @@ class DATA_PT_geometry_curve(CurveButtonsPanelCurve, Panel):
row.label(text="Bevel Factor:")
col = layout.column()
- col.active = (curve.bevel_depth > 0 or curve.bevel_object is not None)
+ col.active = (
+ (curve.bevel_depth > 0.0) or
+ (curve.extrude > 0.0) or
+ (curve.bevel_object is not None))
row = col.row(align=True)
row.prop(curve, "bevel_factor_mapping_start", text="")
row.prop(curve, "bevel_factor_start", text="Start")
diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py
index 0121ad46c86..30cd39d2e2f 100644
--- a/release/scripts/startup/bl_ui/properties_data_lamp.py
+++ b/release/scripts/startup/bl_ui/properties_data_lamp.py
@@ -103,6 +103,13 @@ class DATA_PT_lamp(DataButtonsPanel, Panel):
sub.prop(lamp, "linear_attenuation", slider=True, text="Linear")
sub.prop(lamp, "quadratic_attenuation", slider=True, text="Quadratic")
+ elif lamp.falloff_type == 'INVERSE_COEFFICIENTS':
+ col.label(text="Inverse Coefficients:")
+ sub = col.column(align=True)
+ sub.prop(lamp, "constant_coefficient", text="Constant")
+ sub.prop(lamp, "linear_coefficient", text="Linear")
+ sub.prop(lamp, "quadratic_coefficient", text="Quadratic")
+
col.prop(lamp, "use_sphere")
if lamp.type == 'AREA':
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index de8617ecc52..cf939719ba3 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -156,6 +156,17 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.label(text="Object:")
col.prop(md, "object", text="")
+ """
+ layout.prop(md, "use_bmesh")
+ if md.use_bmesh:
+ box = layout.box()
+ box.label("BMesh Options:")
+ box.prop(md, "use_bmesh_separate")
+ box.prop(md, "use_bmesh_dissolve")
+ box.prop(md, "use_bmesh_connect_regions")
+ box.prop(md, "threshold")
+ """
+
def BUILD(self, layout, ob, md):
split = layout.split()
@@ -281,6 +292,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
row.prop(md, "vertex_group_factor")
col.prop(md, "use_collapse_triangulate")
+ row = col.split(percentage=0.75)
+ row.prop(md, "use_symmetry")
+ row.prop(md, "symmetry_axis", text="")
elif decimate_type == 'UNSUBDIV':
layout.prop(md, "iterations")
@@ -724,7 +738,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "target", text="")
col = split.column()
col.label(text="Vertex Group:")
- col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
split = layout.split()
@@ -772,12 +788,14 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.label(text="Vertex Group:")
- col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row = col.row(align=True)
+ row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
+ row.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
split = layout.split()
col = split.column()
- col.label(text="Origin:")
+ col.label(text="Axis, Origin:")
col.prop(md, "origin", text="")
if md.deform_method in {'TAPER', 'STRETCH', 'TWIST'}:
@@ -1276,14 +1294,14 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = layout.column(align=True)
split = col.split(0.333, align=True)
sub = split.column(align=True)
- sub.prop(md, "data_types_verts_vgroup")
- row = split.row(align=True)
+ sub.prop(md, "data_types_verts")
+ sub = split.column(align=True)
+ row = sub.row(align=True)
row.prop(md, "layers_vgroup_select_src", text="")
- row.label(icon='RIGHTARROW_THIN')
+ row.label(icon='RIGHTARROW')
row.prop(md, "layers_vgroup_select_dst", text="")
- split = col.split(0.333, align=True)
- sub = split.column(align=True)
- sub.prop(md, "data_types_verts")
+ row = sub.row(align=True)
+ row.label("", icon='NONE')
layout.separator()
@@ -1312,17 +1330,14 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
split = col.split(0.333, align=True)
sub = split.column(align=True)
sub.prop(md, "data_types_loops")
- split = col.split(0.333, align=True)
sub = split.column(align=True)
- sub.prop(md, "data_types_loops_vcol")
- row = split.row(align=True)
+ row = sub.row(align=True)
+ row.label("", icon='NONE')
+ row = sub.row(align=True)
row.prop(md, "layers_vcol_select_src", text="")
row.label(icon='RIGHTARROW')
row.prop(md, "layers_vcol_select_dst", text="")
- split = col.split(0.333, align=True)
- sub = split.column(align=True)
- sub.prop(md, "data_types_loops_uv")
- row = split.row(align=True)
+ row = sub.row(align=True)
row.prop(md, "layers_uv_select_src", text="")
row.label(icon='RIGHTARROW')
row.prop(md, "layers_uv_select_dst", text="")
diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py
index 56cd4d0f491..8baad4ea0f2 100644
--- a/release/scripts/startup/bl_ui/properties_game.py
+++ b/release/scripts/startup/bl_ui/properties_game.py
@@ -55,6 +55,7 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
layout.prop(game, "step_height", slider=True)
layout.prop(game, "jump_speed")
layout.prop(game, "fall_speed")
+ layout.prop(game, "jump_max")
elif physics_type in {'DYNAMIC', 'RIGID_BODY'}:
split = layout.split()
@@ -509,7 +510,11 @@ class SCENE_PT_game_navmesh(SceneButtonsPanel, Panel):
col.label(text="Region:")
row = col.row()
row.prop(rd, "region_min_size")
- row.prop(rd, "region_merge_size")
+ if rd.partitioning != 'LAYERS':
+ row.prop(rd, "region_merge_size")
+
+ col = layout.column()
+ col.prop(rd, "partitioning")
col = layout.column()
col.label(text="Polygonization:")
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 91a986d8e50..013f4e64854 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -22,23 +22,34 @@
from bpy.types import Menu, UIList
-def gpencil_stroke_placement_settings(context, layout, gpd):
+def gpencil_stroke_placement_settings(context, layout):
+ if context.space_data.type == 'VIEW_3D':
+ propname = "gpencil_stroke_placement_view3d"
+ elif context.space_data.type == 'SEQUENCE_EDITOR':
+ propname = "gpencil_stroke_placement_sequencer_preview"
+ elif context.space_data.type == 'IMAGE_EDITOR':
+ propname = "gpencil_stroke_placement_image_editor"
+ else:
+ propname = "gpencil_stroke_placement_view2d"
+
+ ts = context.tool_settings
+
col = layout.column(align=True)
col.label(text="Stroke Placement:")
row = col.row(align=True)
- row.prop_enum(gpd, "draw_mode", 'VIEW')
- row.prop_enum(gpd, "draw_mode", 'CURSOR')
+ row.prop_enum(ts, propname, 'VIEW')
+ row.prop_enum(ts, propname, 'CURSOR')
if context.space_data.type == 'VIEW_3D':
row = col.row(align=True)
- row.prop_enum(gpd, "draw_mode", 'SURFACE')
- row.prop_enum(gpd, "draw_mode", 'STROKE')
+ row.prop_enum(ts, propname, 'SURFACE')
+ row.prop_enum(ts, propname, 'STROKE')
row = col.row(align=False)
- row.active = gpd.draw_mode in {'SURFACE', 'STROKE'}
- row.prop(gpd, "use_stroke_endpoints")
+ row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'}
+ row.prop(ts, "use_gpencil_stroke_endpoints")
class GreasePencilDrawingToolsPanel:
@@ -56,15 +67,19 @@ class GreasePencilDrawingToolsPanel:
col.label(text="Draw:")
row = col.row(align=True)
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ row.operator("gpencil.draw", icon='GREASEPENCIL', text="Draw").mode = 'DRAW'
+ row.operator("gpencil.draw", icon='FORCE_CURVE', text="Erase").mode = 'ERASER' # XXX: Needs a dedicated icon
row = col.row(align=True)
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Poly").mode = 'DRAW_POLY'
+ row.operator("gpencil.draw", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT'
+ row.operator("gpencil.draw", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY'
- row = col.row(align=True)
- row.prop(context.tool_settings, "use_grease_pencil_sessions", text="Continuous Drawing")
+ sub = col.column(align=True)
+ sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
+ sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
+
+ col.separator()
+ col.separator()
if context.space_data.type in {'VIEW_3D', 'CLIP_EDITOR'}:
col.separator()
@@ -75,10 +90,19 @@ class GreasePencilDrawingToolsPanel:
elif context.space_data.type == 'CLIP_EDITOR':
row.prop(context.space_data, "grease_pencil_source", expand=True)
+ col.separator()
+ col.separator()
+
+ gpencil_stroke_placement_settings(context, col)
+
gpd = context.gpencil_data
+
if gpd:
- col.separator()
- gpencil_stroke_placement_settings(context, col, gpd)
+ layout.separator()
+ layout.separator()
+
+ col = layout.column(align=True)
+ col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
if context.space_data.type == 'VIEW_3D':
col.separator()
@@ -95,67 +119,110 @@ class GreasePencilStrokeEditPanel:
bl_label = "Edit Strokes"
bl_category = "Grease Pencil"
bl_region_type = 'TOOLS'
+ bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
- return (context.gpencil_data is not None)
+ if context.gpencil_data is None:
+ return False
+
+ gpd = context.gpencil_data
+ return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
@staticmethod
def draw(self, context):
layout = self.layout
- gpd = context.gpencil_data
- edit_ok = bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
+ layout.label(text="Select:")
+ col = layout.column(align=True)
+ col.operator("gpencil.select_all", text="Select All")
+ col.operator("gpencil.select_border")
+ col.operator("gpencil.select_circle")
+
+ layout.separator()
col = layout.column(align=True)
- col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
+ col.operator("gpencil.select_linked")
+ col.operator("gpencil.select_more")
+ col.operator("gpencil.select_less")
- col.separator()
+ layout.separator()
- col.label(text="Select:")
- subcol = col.column(align=True)
- subcol.active = edit_ok
- subcol.operator("gpencil.select_all", text="Select All")
- subcol.operator("gpencil.select_border")
- subcol.operator("gpencil.select_circle")
+ layout.label(text="Edit:")
+ row = layout.row(align=True)
+ row.operator("gpencil.copy", text="Copy")
+ row.operator("gpencil.paste", text="Paste")
- col.separator()
+ col = layout.column(align=True)
+ col.operator("gpencil.delete", text="Delete")
+ col.operator("gpencil.duplicate_move", text="Duplicate")
+ col.operator("transform.mirror", text="Mirror")
- subcol = col.column(align=True)
- subcol.active = edit_ok
- subcol.operator("gpencil.select_linked")
- subcol.operator("gpencil.select_more")
- subcol.operator("gpencil.select_less")
+ layout.separator()
- col.separator()
+ col = layout.column(align=True)
+ col.operator("transform.translate") # icon='MAN_TRANS'
+ col.operator("transform.rotate") # icon='MAN_ROT'
+ col.operator("transform.resize", text="Scale") # icon='MAN_SCALE'
- col.label(text="Edit:")
- row = col.row(align=True)
- row.active = edit_ok
- row.operator("gpencil.copy", text="Copy")
- row.operator("gpencil.paste", text="Paste")
+ layout.separator()
- subcol = col.column(align=True)
- subcol.active = edit_ok
- subcol.operator("gpencil.delete", text="Delete")
- subcol.operator("gpencil.duplicate_move", text="Duplicate")
- subcol.operator("transform.mirror", text="Mirror").gpencil_strokes = True
+ col = layout.column(align=True)
+ col.operator("transform.bend", text="Bend")
+ col.operator("transform.shear", text="Shear")
+ col.operator("transform.tosphere", text="To Sphere")
- col.separator()
- subcol = col.column(align=True)
- subcol.active = edit_ok
- subcol.operator("transform.translate").gpencil_strokes = True # icon='MAN_TRANS'
- subcol.operator("transform.rotate").gpencil_strokes = True # icon='MAN_ROT'
- subcol.operator("transform.resize", text="Scale").gpencil_strokes = True # icon='MAN_SCALE'
+class GreasePencilStrokeSculptPanel:
+ # subclass must set
+ # bl_space_type = 'IMAGE_EDITOR'
+ bl_label = "Sculpt Strokes"
+ bl_category = "Grease Pencil"
+ bl_region_type = 'TOOLS'
- col.separator()
+ @classmethod
+ def poll(cls, context):
+ if context.gpencil_data is None:
+ return False
- subcol = col.column(align=True)
- subcol.active = edit_ok
- subcol.operator("transform.bend", text="Bend").gpencil_strokes = True
- subcol.operator("transform.shear", text="Shear").gpencil_strokes = True
- subcol.operator("transform.tosphere", text="To Sphere").gpencil_strokes = True
+ gpd = context.gpencil_data
+ return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
+
+ @staticmethod
+ def draw(self, context):
+ layout = self.layout
+
+ settings = context.tool_settings.gpencil_sculpt
+ tool = settings.tool
+ brush = settings.brush
+
+ layout.column().prop(settings, "tool", expand=True)
+
+ col = layout.column()
+ col.prop(brush, "size", slider=True)
+ row = col.row(align=True)
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_pressure_strength", text="")
+ col.prop(brush, "use_falloff")
+
+ layout.separator()
+
+ if settings.tool == 'THICKNESS':
+ layout.row().prop(brush, "direction", expand=True)
+ elif settings.tool == 'PINCH':
+ row = layout.row(align=True)
+ row.prop_enum(brush, "direction", 'ADD', text="Pinch")
+ row.prop_enum(brush, "direction", 'SUBTRACT', text="Inflate")
+ elif settings.tool == 'TWIST':
+ row = layout.row(align=True)
+ row.prop_enum(brush, "direction", 'SUBTRACT', text="CW")
+ row.prop_enum(brush, "direction", 'ADD', text="CCW")
+
+ layout.separator()
+ layout.prop(settings, "use_select_mask")
+
+ if settings.tool == 'SMOOTH':
+ layout.prop(brush, "affect_pressure")
###############################
@@ -190,14 +257,14 @@ class GPENCIL_PIE_tool_palette(Menu):
if gpd:
if gpd.use_stroke_edit_mode and context.editable_gpencil_strokes:
# S - Exit Edit Mode
- pie.prop(gpd, "use_stroke_edit_mode", text="Exit Edit Mode", icon='EDIT')
+ pie.operator("gpencil.editmode_toggle", text="Exit Edit Mode", icon='EDIT')
# N - Transforms
col = pie.column()
row = col.row(align=True)
- row.operator("transform.translate", icon='MAN_TRANS').gpencil_strokes = True
- row.operator("transform.rotate", icon='MAN_ROT').gpencil_strokes = True
- row.operator("transform.resize", text="Scale", icon='MAN_SCALE').gpencil_strokes = True
+ row.operator("transform.translate", icon='MAN_TRANS')
+ row.operator("transform.rotate", icon='MAN_ROT')
+ row.operator("transform.resize", text="Scale", icon='MAN_SCALE')
row = col.row(align=True)
row.label("Proportional Edit:")
row.prop(context.tool_settings, "proportional_edit", text="", icon_only=True)
@@ -224,7 +291,7 @@ class GPENCIL_PIE_tool_palette(Menu):
pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_PIE_tools_more"
else:
# Toggle Edit Mode
- pie.prop(gpd, "use_stroke_edit_mode", text="Enable Stroke Editing", icon='EDIT')
+ pie.operator("gpencil.editmode_toggle", text="Enable Stroke Editing", icon='EDIT')
class GPENCIL_PIE_settings_palette(Menu):
@@ -261,11 +328,15 @@ class GPENCIL_PIE_settings_palette(Menu):
col.prop(gpl, "use_onion_skinning")
# N - Active Layer
- # XXX: this should show an operator to change the active layer instead
col = pie.column()
col.label("Active Layer: ")
- col.prop(gpl, "info", text="")
- # col.prop(gpd, "layers")
+
+ row = col.row()
+ row.operator_context = 'EXEC_REGION_WIN'
+ row.operator_menu_enum("gpencil.layer_change", "layer", text="", icon='GREASEPENCIL')
+ row.prop(gpl, "info", text="")
+ row.operator("gpencil.layer_remove", text="", icon='X')
+
row = col.row()
row.prop(gpl, "lock")
row.prop(gpl, "hide")
@@ -294,17 +365,82 @@ class GPENCIL_PIE_tools_more(Menu):
col.operator("gpencil.select_more", icon='ZOOMIN')
col.operator("gpencil.select_less", icon='ZOOMOUT')
- pie.operator("transform.mirror", icon='MOD_MIRROR').gpencil_strokes = True
- pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM').gpencil_strokes = True
- pie.operator("transform.shear", icon='MOD_TRIANGULATE').gpencil_strokes = True
- pie.operator("transform.tosphere", icon='MOD_MULTIRES').gpencil_strokes = True
+ pie.operator("transform.mirror", icon='MOD_MIRROR')
+ pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM')
+ pie.operator("transform.shear", icon='MOD_TRIANGULATE')
+ pie.operator("transform.tosphere", icon='MOD_MULTIRES')
pie.operator("gpencil.convert", icon='OUTLINER_OB_CURVE', text="Convert...")
pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_PIE_tool_palette"
+class GPENCIL_PIE_sculpt(Menu):
+ """A pie menu for accessing Grease Pencil stroke sculpting settings"""
+ bl_label = "Grease Pencil Sculpt"
+
+ @classmethod
+ def poll(cls, context):
+ gpd = context.gpencil_data
+ return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
+
+ def draw(self, context):
+ layout = self.layout
+
+ pie = layout.menu_pie()
+
+ settings = context.tool_settings.gpencil_sculpt
+ brush = settings.brush
+
+ # W - Launch Sculpt Mode
+ col = pie.column()
+ # col.label("Tool:")
+ col.prop(settings, "tool", text="")
+ col.operator("gpencil.brush_paint", text="Sculpt", icon='SCULPTMODE_HLT')
+
+ # E - Common Settings
+ col = pie.column(align=True)
+ col.prop(brush, "size", slider=True)
+ row = col.row(align=True)
+ row.prop(brush, "strength", slider=True)
+ # row.prop(brush, "use_pressure_strength", text="", icon_only=True)
+ col.prop(brush, "use_falloff")
+
+ # S - Change Brush Type Shortcuts
+ row = pie.row()
+ row.prop_enum(settings, "tool", value='GRAB')
+ row.prop_enum(settings, "tool", value='PUSH')
+ row.prop_enum(settings, "tool", value='CLONE')
+
+ # N - Change Brush Type Shortcuts
+ row = pie.row()
+ row.prop_enum(settings, "tool", value='SMOOTH')
+ row.prop_enum(settings, "tool", value='THICKNESS')
+ row.prop_enum(settings, "tool", value='RANDOMIZE')
+
+
+###############################
+
+
+class GPENCIL_MT_snap(Menu):
+ bl_label = "Snap"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.snap_to_grid", text="Selection to Grid")
+ layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor").use_offset = False
+ layout.operator("gpencil.snap_to_cursor", text="Selection to Cursor (Offset)").use_offset = True
+
+ layout.separator()
+
+ layout.operator("gpencil.snap_cursor_to_selected", text="Cursor to Selected")
+ layout.operator("view3d.snap_cursor_to_center", text="Cursor to Center")
+ layout.operator("view3d.snap_cursor_to_grid", text="Cursor to Grid")
+
+
###############################
+
class GPENCIL_UL_layer(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# assert(isinstance(item, bpy.types.GPencilLayer)
@@ -328,6 +464,25 @@ class GPENCIL_UL_layer(UIList):
layout.label(text="", icon_value=icon)
+class GPENCIL_MT_layer_specials(Menu):
+ bl_label = "Layer"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon
+
+ layout.separator()
+
+ layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
+ layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
+
+ layout.separator()
+
+ layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
+ layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
+
+
class GreasePencilDataPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@@ -379,7 +534,7 @@ class GreasePencilDataPanel:
gpl = context.active_gpencil_layer
if gpl:
- sub.operator("gpencil.layer_duplicate", icon='COPY_ID', text="") # XXX: needs a dedicated icon
+ sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
if len(gpd.layers) > 1:
col.separator()
@@ -388,6 +543,12 @@ class GreasePencilDataPanel:
sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
+ col.separator()
+
+ sub = col.column(align=True)
+ sub.operator("gpencil.layer_isolate", icon='SOLO_OFF', text="").affect_visibility = False
+ sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
+
if gpl:
self.draw_layer(layout, gpl)
@@ -461,6 +622,13 @@ class GreasePencilDataPanel:
row.prop(gpl, "after_color", text="")
sub.prop(gpl, "ghost_after_range", text="After")
+ # Smooth and subdivide new strokes
+ layout.separator()
+ col = layout.column(align=True)
+ col.label(text="New Stroke Quality:")
+ col.prop(gpl, "pen_smooth_factor")
+ col.prop(gpl, "pen_subdivision_steps")
+
class GreasePencilToolsPanel:
# subclass must set
@@ -492,4 +660,4 @@ class GreasePencilToolsPanel:
layout.separator()
layout.separator()
- gpencil_stroke_placement_settings(context, layout, gpd)
+ gpencil_stroke_placement_settings(context, layout)
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index e294f5487a6..08290f20a69 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -218,9 +218,13 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
row.prop(part, "hair_step")
if psys is not None and psys.is_edited:
if psys.is_global_hair:
- layout.operator("particle.connect_hair")
+ row = layout.row(align=True)
+ row.operator("particle.connect_hair").all = False
+ row.operator("particle.connect_hair", text="Connect All").all = True
else:
- layout.operator("particle.disconnect_hair")
+ row = layout.row(align=True)
+ row.operator("particle.disconnect_hair").all = False
+ row.operator("particle.disconnect_hair", text="Disconnect All").all = True
elif psys is not None and part.type == 'REACTOR':
split.enabled = particle_panel_enabled(context, psys)
split.prop(psys, "reactor_target_object")
@@ -253,7 +257,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, Panel):
layout.enabled = particle_panel_enabled(context, psys) and (psys is None or not psys.has_multiple_caches)
row = layout.row()
- row.active = part.distribution != 'GRID'
+ row.active = part.emit_from == 'VERT' or part.distribution != 'GRID'
row.prop(part, "count")
if part.type == 'HAIR':
diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py
index 85d3c1d7dc4..ef7d25e0a42 100644
--- a/release/scripts/startup/bl_ui/properties_physics_smoke.py
+++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py
@@ -304,12 +304,26 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
- md = context.smoke.domain_settings
- cache = md.point_cache
+ domain = context.smoke.domain_settings
+ cache_file_format = domain.cache_file_format
+
+ layout.prop(domain, "cache_file_format")
+
+ if cache_file_format == 'POINTCACHE':
+ layout.label(text="Compression:")
+ layout.prop(domain, "point_cache_compress_type", expand=True)
+ elif cache_file_format == 'OPENVDB':
+ if not bpy.app.build_options.openvdb:
+ layout.label("Built without OpenVDB support")
+ return
- layout.label(text="Compression:")
- layout.prop(md, "point_cache_compress_type", expand=True)
+ layout.label(text="Compression:")
+ layout.prop(domain, "openvdb_cache_compress_type", expand=True)
+ row = layout.row()
+ row.label("Data Depth:")
+ row.prop(domain, "data_depth", expand=True, text="Data Depth")
+ cache = domain.point_cache
point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 1f1802aa373..6c4904939bf 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -284,7 +284,6 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel):
sub = col.column()
sub.active = rd.use_compositing
sub.prop(rd, "use_free_image_textures")
- sub.prop(rd, "use_free_unused_nodes")
sub = col.column()
sub.active = rd.use_raytrace
sub.label(text="Acceleration structure:")
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index bbf11abe6d9..d6253ec7fbc 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -18,7 +18,12 @@
# <pep8 compliant>
import bpy
-from bpy.types import Panel, UIList
+from bpy.types import (
+ Menu,
+ Panel,
+ UIList,
+ )
+
from rna_prop_ui import PropertyPanel
from bl_ui.properties_physics_common import (
@@ -27,6 +32,14 @@ from bl_ui.properties_physics_common import (
)
+class SCENE_MT_units_length_presets(Menu):
+ """Unit of measure for properties that use length values"""
+ bl_label = "Unit Presets"
+ preset_subdir = "units_length"
+ preset_operator = "script.execute_preset"
+ draw = Menu.draw_preset
+
+
class SCENE_UL_keying_set_paths(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
# assert(isinstance(item, bpy.types.KeyingSetPath)
@@ -75,14 +88,28 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
unit = context.scene.unit_settings
- col = layout.column()
- col.row().prop(unit, "system", expand=True)
- col.row().prop(unit, "system_rotation", expand=True)
+ row = layout.row(align=True)
+ row.menu("SCENE_MT_units_length_presets", text=SCENE_MT_units_length_presets.bl_label)
+ row.operator("scene.units_length_preset_add", text="", icon='ZOOMIN')
+ row.operator("scene.units_length_preset_add", text="", icon='ZOOMOUT').remove_active = True
- if unit.system != 'NONE':
- row = layout.row()
- row.prop(unit, "scale_length", text="Scale")
- row.prop(unit, "use_separate")
+ layout.separator()
+
+ split = layout.split(percentage=0.35)
+ split.label("Length:")
+ split.prop(unit, "system", text="")
+ split = layout.split(percentage=0.35)
+ split.label("Angle:")
+ split.prop(unit, "system_rotation", text="")
+
+ col = layout.column()
+ col.enabled = unit.system != 'NONE'
+ split = col.split(percentage=0.35)
+ split.label("Unit Scale:")
+ split.prop(unit, "scale_length", text="")
+ split = col.split(percentage=0.35)
+ split.row()
+ split.prop(unit, "use_separate")
class SceneKeyingSetsPanel:
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 78ea4fa6c3f..caf19a9e469 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -242,7 +242,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
else:
layout.template_preview(tex, slot=slot)
- #Show Alpha Button for Brush Textures, see #29502
+ # Show Alpha Button for Brush Textures, see #29502
if context.space_data.texture_context == 'BRUSH':
layout.prop(tex, "use_preview_alpha")
@@ -498,7 +498,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel):
col = split.column()
- #Only for Material based textures, not for Lamp/World...
+ # Only for Material based textures, not for Lamp/World...
if slot and isinstance(idblock, Material):
col.prop(tex, "use_normal_map")
row = col.row()
@@ -533,7 +533,7 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel):
col = split.column()
- #Only for Material based textures, not for Lamp/World...
+ # Only for Material based textures, not for Lamp/World...
if slot and isinstance(idblock, Material):
col.prop(tex, "use_normal_map")
row = col.row()
@@ -590,7 +590,7 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, Panel):
split = layout.split()
col = split.column(align=True)
- #col.prop(tex, "crop_rectangle")
+ # col.prop(tex, "crop_rectangle")
col.label(text="Crop Minimum:")
col.prop(tex, "crop_min_x", text="X")
col.prop(tex, "crop_min_y", text="Y")
@@ -777,7 +777,7 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel, Panel):
elif vd.file_format == 'IMAGE_SEQUENCE':
layout.template_ID(tex, "image", open="image.open")
layout.template_image(tex, "image", tex.image_user, compact=True)
- #layout.prop(vd, "frame_duration")
+ # layout.prop(vd, "frame_duration")
if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}:
layout.prop(vd, "use_still_frame")
@@ -830,12 +830,21 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel):
col.separator()
+ col.label(text="Color Source:")
if pd.point_source == 'PARTICLE_SYSTEM':
- col.label(text="Color Source:")
- col.prop(pd, "color_source", text="")
- if pd.color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}:
+ col.prop(pd, "particle_color_source", text="")
+ if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}:
col.prop(pd, "speed_scale")
- if pd.color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}:
+ if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}:
+ layout.template_color_ramp(pd, "color_ramp", expand=True)
+ else:
+ col.prop(pd, "vertex_color_source", text="")
+ if pd.vertex_color_source == 'VERTEX_COLOR':
+ if pd.object and pd.object.data:
+ col.prop_search(pd, "vertex_attribute_name", pd.object.data, "vertex_colors", text="")
+ if pd.vertex_color_source == 'VERTEX_WEIGHT':
+ if pd.object:
+ col.prop_search(pd, "vertex_attribute_name", pd.object, "vertex_groups", text="")
layout.template_color_ramp(pd, "color_ramp", expand=True)
col = split.column()
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index ed4a78420d8..e809ef9ffde 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -24,6 +24,7 @@ from bpy.app.translations import pgettext_iface as iface_
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
+ GreasePencilStrokeSculptPanel,
GreasePencilDataPanel
)
@@ -520,6 +521,7 @@ class CLIP_PT_tools_object(CLIP_PT_reconstruction_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
bl_label = "Object"
+ bl_category = "Solve"
@classmethod
def poll(cls, context):
@@ -1134,6 +1136,11 @@ class CLIP_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
+# Grease Pencil stroke sculpting tools
+class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
+ bl_space_type = 'CLIP_EDITOR'
+
+
class CLIP_MT_view(Menu):
bl_label = "View"
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 7fd9719a6e3..af40f1f070c 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -51,11 +51,13 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False):
row.prop(dopesheet, "show_only_matching_fcurves", text="")
if dopesheet.show_only_matching_fcurves:
row.prop(dopesheet, "filter_fcurve_name", text="")
+ row.prop(dopesheet, "use_multi_word_filter", text="")
else:
row = layout.row(align=True)
row.prop(dopesheet, "use_filter_text", text="")
if dopesheet.use_filter_text:
row.prop(dopesheet, "filter_text", text="")
+ row.prop(dopesheet, "use_multi_word_filter", text="")
if not genericFiltersOnly:
row = layout.row(align=True)
@@ -138,6 +140,20 @@ class DOPESHEET_HT_header(Header):
# 'genericFiltersOnly' limits the options to only the relevant 'generic' subset of
# filters which will work here and are useful (especially for character animation)
dopesheet_filter(layout, context, genericFiltersOnly=True)
+ elif st.mode == 'GPENCIL':
+ row = layout.row(align=True)
+ row.prop(st.dopesheet, "show_gpencil_3d_only", text="Active Only")
+
+ if st.dopesheet.show_gpencil_3d_only:
+ row = layout.row(align=True)
+ row.prop(st.dopesheet, "show_only_selected", text="")
+ row.prop(st.dopesheet, "show_hidden", text="")
+
+ row = layout.row(align=True)
+ row.prop(st.dopesheet, "use_filter_text", text="")
+ if st.dopesheet.use_filter_text:
+ row.prop(st.dopesheet, "filter_text", text="")
+ row.prop(st.dopesheet, "use_multi_word_filter", text="")
row = layout.row(align=True)
row.prop(toolsettings, "use_proportional_action",
@@ -153,7 +169,8 @@ class DOPESHEET_HT_header(Header):
row = layout.row(align=True)
row.operator("action.copy", text="", icon='COPYDOWN')
row.operator("action.paste", text="", icon='PASTEDOWN')
- row.operator("action.paste", text="", icon='PASTEFLIPDOWN').flipped = True
+ if st.mode not in ('GPENCIL', 'MASK'):
+ row.operator("action.paste", text="", icon='PASTEFLIPDOWN').flipped = True
class DOPESHEET_MT_editor_menus(Menu):
@@ -338,7 +355,7 @@ class DOPESHEET_MT_key(Menu):
layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
layout.separator()
- layout.operator("action.clean")
+ layout.operator("action.clean").channels = False
layout.operator("action.clean", text="Clean Channels").channels = True
layout.operator("action.sample")
@@ -421,7 +438,7 @@ class DOPESHEET_MT_delete(Menu):
layout.separator()
- layout.operator("action.clean")
+ layout.operator("action.clean").channels = False
layout.operator("action.clean", text="Clean Channels").channels = True
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index ca695208a67..d7b93dc36f0 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -56,7 +56,7 @@ class FILEBROWSER_HT_header(Header):
layout.prop(params, "display_type", expand=True, text="")
- layout.prop(params, "thumbnail_size", text="")
+ layout.prop(params, "display_size", text="")
layout.prop(params, "sort_method", expand=True, text="")
@@ -229,6 +229,11 @@ class FILEBROWSER_PT_advanced_filter(Panel):
bl_category = "Filter"
bl_label = "Advanced Filter"
+ @classmethod
+ def poll(cls, context):
+ # only useful in append/link (library) context currently...
+ return context.space_data.params.use_library_browsing
+
def draw(self, context):
layout = self.layout
space = context.space_data
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 104fd14797e..82497f11bb1 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -257,7 +257,7 @@ class GRAPH_MT_key(Menu):
layout.operator_menu_enum("graph.easing_type", "type", text="Easing Type")
layout.separator()
- layout.operator("graph.clean")
+ layout.operator("graph.clean").channels = False
layout.operator("graph.clean", text="Clean Channels").channels = True
layout.operator("graph.smooth")
layout.operator("graph.sample")
@@ -293,7 +293,7 @@ class GRAPH_MT_delete(Menu):
layout.separator()
- layout.operator("graph.clean")
+ layout.operator("graph.clean").channels = False
layout.operator("graph.clean", text="Clean Channels").channels = True
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index c3024b25282..fbea07a317e 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -28,6 +28,7 @@ from bl_ui.properties_paint_common import (
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
+ GreasePencilStrokeSculptPanel,
GreasePencilDataPanel,
)
from bpy.app.translations import pgettext_iface as iface_
@@ -87,7 +88,7 @@ class IMAGE_MT_view(Menu):
layout.prop(uv, "show_metadata")
if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'):
layout.prop(uv, "show_texpaint")
- layout.prop(toolsettings, "show_uv_local_view", text="Show same material")
+ layout.prop(toolsettings, "show_uv_local_view", text="Show Same Material")
layout.separator()
@@ -112,6 +113,11 @@ class IMAGE_MT_view(Menu):
layout.separator()
if show_render:
+ layout.operator("image.render_border")
+ layout.operator("image.clear_render_border")
+
+ layout.separator()
+
layout.operator("image.cycle_render_slot", text="Render Slot Cycle Next")
layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True
layout.separator()
@@ -207,19 +213,18 @@ class IMAGE_MT_image(Menu):
layout.menu("IMAGE_MT_image_invert")
if not show_render:
- layout.separator()
-
if not ima.packed_file:
+ layout.separator()
layout.operator("image.pack")
# only for dirty && specific image types, perhaps
# this could be done in operator poll too
if ima.is_dirty:
if ima.source in {'FILE', 'GENERATED'} and ima.type != 'OPEN_EXR_MULTILAYER':
+ if ima.packed_file:
+ layout.separator()
layout.operator("image.pack", text="Pack As PNG").as_png = True
- layout.separator()
-
class IMAGE_MT_image_invert(Menu):
bl_label = "Invert"
@@ -727,6 +732,7 @@ class IMAGE_PT_paint(Panel, ImagePaintPanel):
toolsettings = context.tool_settings.image_paint
return sima.show_paint
+
class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel):
bl_label = "Overlay"
bl_options = {'DEFAULT_CLOSED'}
@@ -1192,5 +1198,10 @@ class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
+# Grease Pencil stroke sculpting tools
+class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index d295cc19fb7..198845792b3 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -262,8 +262,9 @@ class INFO_MT_opengl_render(Menu):
layout = self.layout
rd = context.scene.render
-
layout.prop(rd, "use_antialiasing")
+ layout.prop(rd, "use_full_sample")
+
layout.prop_menu_enum(rd, "antialiasing_samples")
layout.prop_menu_enum(rd, "alpha_mode")
@@ -304,7 +305,7 @@ class INFO_MT_help(Menu):
layout.separator()
layout.operator("wm.url_open", text="Blender Website", icon='URL').url = "http://www.blender.org"
- layout.operator("wm.url_open", text="Blender e-Shop", icon='URL').url = "http://www.blender.org/e-shop"
+ layout.operator("wm.url_open", text="Blender Store", icon='URL').url = "https://store.blender.org"
layout.operator("wm.url_open", text="Developer Community", icon='URL').url = "http://www.blender.org/get-involved/"
layout.operator("wm.url_open", text="User Community", icon='URL').url = "http://www.blender.org/community/user-community"
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index c083907f017..64d3b427260 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -86,6 +86,7 @@ class NLA_MT_view(Menu):
layout.separator()
layout.operator("nla.view_all")
layout.operator("nla.view_selected")
+ layout.operator("nla.view_frame")
layout.separator()
layout.operator("screen.area_dupli")
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 3941e618b5b..986edc7405b 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -24,6 +24,7 @@ from bpy.app.translations import pgettext_iface as iface_
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
+ GreasePencilStrokeSculptPanel,
GreasePencilDataPanel,
GreasePencilToolsPanel,
)
@@ -99,7 +100,6 @@ class NODE_HT_header(Header):
elif snode.tree_type == 'CompositorNodeTree':
if snode_id:
layout.prop(snode_id, "use_nodes")
- layout.prop(snode_id.render, "use_free_unused_nodes", text="Free Unused")
layout.prop(snode, "show_backdrop")
if snode.show_backdrop:
row = layout.row(align=True)
@@ -488,6 +488,12 @@ class NODE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
+
+# Grease Pencil stroke sculpting tools
+class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'TOOLS'
+
# -----------------------------
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 5bf095dc6b5..233145819e7 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -180,6 +180,7 @@ class SEQUENCER_MT_view(Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("sequencer.view_all", text="View all Sequences")
layout.operator("sequencer.view_selected")
+ layout.operator("sequencer.view_frame")
layout.operator_context = 'INVOKE_DEFAULT'
if is_preview:
layout.operator_context = 'INVOKE_REGION_PREVIEW'
@@ -267,12 +268,23 @@ class SEQUENCER_MT_change(Menu):
def draw(self, context):
layout = self.layout
+ strip = act_strip(context)
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator_menu_enum("sequencer.change_effect_input", "swap")
layout.operator_menu_enum("sequencer.change_effect_type", "type")
- layout.operator("sequencer.change_path", text="Path/Files")
+ prop = layout.operator("sequencer.change_path", text="Path/Files")
+
+ if strip:
+ stype = strip.type
+
+ if stype == 'IMAGE':
+ prop.filter_image = True
+ elif stype == 'MOVIE':
+ prop.filter_movie = True
+ elif stype == 'SOUND':
+ prop.filter_sound = True
class SEQUENCER_MT_frame(Menu):
@@ -284,6 +296,24 @@ class SEQUENCER_MT_frame(Menu):
layout.operator("anim.previewrange_clear")
layout.operator("anim.previewrange_set")
+ layout.separator()
+
+ props = layout.operator("sequencer.strip_jump", text="Jump to Previous Strip")
+ props.next = False
+ props.center = False
+ props = layout.operator("sequencer.strip_jump", text="Jump to Next Strip")
+ props.next = True
+ props.center = False
+
+ layout.separator()
+
+ props = layout.operator("sequencer.strip_jump", text="Jump to Previous Strip (Center)")
+ props.next = False
+ props.center = True
+ props = layout.operator("sequencer.strip_jump", text="Jump to Next Strip (Center)")
+ props.next = True
+ props.center = True
+
class SEQUENCER_MT_add(Menu):
bl_label = "Add"
@@ -551,6 +581,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
if strip.input_count > 0:
col = layout.column()
+ col.enabled = False
col.prop(strip, "input_1")
if strip.input_count > 1:
col.prop(strip, "input_2")
@@ -654,7 +685,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel):
elif strip.type == 'GAUSSIAN_BLUR':
col.prop(strip, "size_x")
col.prop(strip, "size_y")
-
+
class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
bl_label = "Strip Input"
@@ -699,7 +730,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel):
layout.prop(strip.colorspace_settings, "name")
layout.prop(strip, "alpha_mode")
- layout.operator("sequencer.change_path")
+ layout.operator("sequencer.change_path").filter_image = True
elif seq_type == 'MOVIE':
split = layout.split(percentage=0.2)
@@ -771,13 +802,10 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
strip = act_strip(context)
sound = strip.sound
- # TODO: add support to handle SOUND datablock in sequencer soundstrips... For now, hide this useless thing!
- # layout.template_ID(strip, "sound", open="sound.open")
-
- # layout.separator()
- layout.prop(strip, "filepath", text="")
-
+ layout.template_ID(strip, "sound", open="sound.open")
if sound is not None:
+ layout.prop(sound, "filepath", text="")
+
row = layout.row()
if sound.packed_file:
row.operator("sound.unpack", icon='PACKAGE', text="Unpack")
@@ -786,6 +814,8 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel):
row.prop(sound, "use_memory_cache")
+ layout.prop(sound, "use_mono")
+
if st.waveform_draw_type == 'DEFAULT_WAVEFORMS':
layout.prop(strip, "show_waveform")
@@ -826,15 +856,25 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel):
layout.template_ID(strip, "scene")
scene = strip.scene
+ layout.prop(strip, "use_sequence")
- layout.label(text="Camera Override")
- layout.template_ID(strip, "scene_camera")
+ if not strip.use_sequence:
+ layout.label(text="Camera Override")
+ layout.template_ID(strip, "scene_camera")
- layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil")
+ layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil")
if scene:
layout.prop(scene, "audio_volume", text="Audio Volume")
+ if not strip.use_sequence:
+ if scene:
+ # Warning, this is not a good convention to follow.
+ # Expose here because setting the alpha from the 'Render' menu is very inconvenient.
+ layout.label("Preview")
+ layout.prop(scene.render, "alpha_mode")
+
+ if scene:
sta = scene.frame_start
end = scene.frame_end
layout.label(text=iface_("Original frame range: %d-%d (%d)") % (sta, end, end - sta + 1), translate=False)
@@ -965,11 +1005,11 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
if proxy.use_proxy_custom_file:
flow.prop(proxy, "filepath")
- row = layout.row()
- row.prop(strip.proxy, "build_25")
- row.prop(strip.proxy, "build_50")
- row.prop(strip.proxy, "build_75")
- row.prop(strip.proxy, "build_100")
+ row = layout.row(align=True)
+ row.prop(strip.proxy, "build_25", toggle=True)
+ row.prop(strip.proxy, "build_50", toggle=True)
+ row.prop(strip.proxy, "build_75", toggle=True)
+ row.prop(strip.proxy, "build_100", toggle=True)
layout.prop(proxy, "use_overwrite")
@@ -999,7 +1039,7 @@ class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, Panel):
render = context.scene.render
col = layout.column()
- col.prop(render, "use_sequencer_gl_preview", text="Open GL Preview")
+ col.prop(render, "use_sequencer_gl_preview", text="OpenGL Preview")
col = layout.column()
#col.active = render.use_sequencer_gl_preview
col.prop(render, "sequencer_gl_preview", text="")
@@ -1099,6 +1139,8 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
box.prop_search(mod, "input_mask_strip", sequences_object, "sequences", text="Mask")
else:
box.prop(mod, "input_mask_id")
+ row = box.row()
+ row.prop(mod, "mask_time", expand=True)
if mod.type == 'COLOR_BALANCE':
box.prop(mod, "color_multiply")
@@ -1111,6 +1153,21 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
col = box.column()
col.prop(mod, "bright")
col.prop(mod, "contrast")
+ elif mod.type == 'WHITE_BALANCE':
+ col = box.column()
+ col.prop(mod, "white_value")
+ elif mod.type == 'TONEMAP':
+ col = box.column()
+ col.prop(mod, "tonemap_type")
+ if mod.tonemap_type == 'RD_PHOTORECEPTOR':
+ col.prop(mod, "intensity")
+ col.prop(mod, "contrast")
+ col.prop(mod, "adaptation")
+ col.prop(mod, "correction")
+ elif mod.tonemap_type == 'RH_SIMPLE':
+ col.prop(mod, "key")
+ col.prop(mod, "offset")
+ col.prop(mod, "gamma")
class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Output, Panel):
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 817c28c6359..5b0075b4147 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -87,6 +87,8 @@ class TIME_HT_header(Header):
subsub = row.row(align=True)
subsub.prop(toolsettings, "use_record_with_nla", toggle=True)
+ layout.prop(toolsettings, "keyframe_type", text="", icon_only=True)
+
row = layout.row(align=True)
row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="")
row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
@@ -128,7 +130,6 @@ class TIME_MT_view(Menu):
layout.prop(st, "show_seconds")
layout.prop(st, "show_locked_time")
- layout.operator("time.view_all")
layout.separator()
@@ -141,6 +142,11 @@ class TIME_MT_view(Menu):
layout.separator()
+ layout.operator("time.view_all")
+ layout.operator("time.view_frame")
+
+ layout.separator()
+
layout.operator("marker.camera_bind")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 1259e743152..dc46aed08c0 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -24,7 +24,7 @@ from bpy.app.translations import contexts as i18n_contexts
def opengl_lamp_buttons(column, lamp):
- split = column.split(percentage=0.1)
+ split = column.row()
split.prop(lamp, "use", text="", icon='OUTLINER_OB_LAMP' if lamp.use else 'LAMP_DATA')
@@ -63,7 +63,7 @@ class USERPREF_HT_header(Header):
elif userpref.active_section == 'ADDONS':
layout.operator("wm.addon_install", icon='FILESEL')
layout.operator("wm.addon_refresh", icon='FILE_REFRESH')
- layout.menu("USERPREF_MT_addons_dev_guides")
+ layout.menu("USERPREF_MT_addons_online_resources")
elif userpref.active_section == 'THEMES':
layout.operator("ui.reset_default_theme")
layout.operator("wm.theme_install")
@@ -174,7 +174,6 @@ class USERPREF_PT_interface(Panel):
if sys.platform[:3] == "win":
col.label("Warnings")
col.prop(view, "use_quit_dialog")
- col.prop(view, "use_gl_warn_support")
row.separator()
row.separator()
@@ -301,10 +300,10 @@ class USERPREF_PT_edit(Panel):
col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
col.separator()
- col.prop(edit, "use_grease_pencil_smooth_stroke", text="Smooth Stroke")
+ col.prop(edit, "grease_pencil_default_color", text="Default Color")
+ col.separator()
col.prop(edit, "use_grease_pencil_simplify_stroke", text="Simplify Stroke")
col.separator()
- col.prop(edit, "grease_pencil_default_color", text="Default Color")
col.separator()
col.separator()
col.separator()
@@ -452,16 +451,14 @@ class USERPREF_PT_system(Panel):
col.prop(system, "use_gpu_mipmap")
col.prop(system, "use_16bit_textures")
- if system.is_occlusion_query_supported():
- col.separator()
- col.label(text="Selection")
- col.prop(system, "select_method", text="")
+ col.separator()
+ col.label(text="Selection")
+ col.prop(system, "select_method", text="")
col.separator()
col.label(text="Anisotropic Filtering")
col.prop(system, "anisotropic_filter", text="")
- col.prop(system, "use_vertex_buffer_objects")
col.separator()
@@ -530,6 +527,7 @@ class USERPREF_PT_system(Panel):
column.separator()
column.prop(system, "font_path_ui")
+ column.prop(system, "font_path_ui_mono")
if bpy.app.build_options.international:
column.prop(system, "use_international_fonts")
@@ -561,8 +559,33 @@ class USERPREF_PT_theme(Panel):
bl_region_type = 'WINDOW'
bl_options = {'HIDE_HEADER'}
+ # not essential, hard-coded UI delimiters for the theme layout
+ ui_delimiters = {
+ 'VIEW_3D': {
+ "text_grease_pencil",
+ "text_keyframe",
+ "speaker",
+ "freestyle_face_mark",
+ "split_normal",
+ "bone_solid",
+ "paint_curve_pivot",
+ },
+ 'GRAPH_EDITOR': {
+ "handle_vertex_select",
+ },
+ 'IMAGE_EDITOR': {
+ "paint_curve_pivot",
+ },
+ 'NODE_EDITOR': {
+ "layout_node",
+ },
+ 'CLIP_EDITOR': {
+ "handle_vertex_select",
+ }
+ }
+
@staticmethod
- def _theme_generic(split, themedata):
+ def _theme_generic(split, themedata, theme_area):
col = split.column()
@@ -589,13 +612,30 @@ class USERPREF_PT_theme(Panel):
props_type.setdefault((prop.type, prop.subtype), []).append(prop)
+ th_delimiters = USERPREF_PT_theme.ui_delimiters.get(theme_area)
for props_type, props_ls in sorted(props_type.items()):
if props_type[0] == 'POINTER':
for i, prop in enumerate(props_ls):
theme_generic_recurse(getattr(data, prop.identifier))
else:
- for i, prop in enumerate(props_ls):
- colsub_pair[i % 2].row().prop(data, prop.identifier)
+ if th_delimiters is None:
+ # simple, no delimiters
+ for i, prop in enumerate(props_ls):
+ colsub_pair[i % 2].row().prop(data, prop.identifier)
+ else:
+ # add hard coded delimiters
+ i = 0
+ for prop in props_ls:
+ colsub = colsub_pair[i]
+ colsub.row().prop(data, prop.identifier)
+ i = (i + 1) % 2
+ if prop.identifier in th_delimiters:
+ if i:
+ colsub = colsub_pair[1]
+ colsub.row().label("")
+ colsub_pair[0].row().label("")
+ colsub_pair[1].row().label("")
+ i = 0
theme_generic_recurse(themedata)
@@ -866,7 +906,7 @@ class USERPREF_PT_theme(Panel):
col.label(text="Widget Label:")
self._ui_font_style(col, style.widget_label)
else:
- self._theme_generic(split, getattr(theme, theme.theme_area.lower()))
+ self._theme_generic(split, getattr(theme, theme.theme_area.lower()), theme.theme_area)
class USERPREF_PT_file(Panel):
@@ -1173,16 +1213,30 @@ class USERPREF_PT_input(Panel):
#print("runtime", time.time() - start)
-class USERPREF_MT_addons_dev_guides(Menu):
- bl_label = "Development Guides"
+class USERPREF_MT_addons_online_resources(Menu):
+ bl_label = "Online Resources"
# menu to open web-pages with addons development guides
def draw(self, context):
layout = self.layout
- layout.operator("wm.url_open", text="API Concepts", icon='URL').url = bpy.types.WM_OT_doc_view._prefix + "/info_quickstart.html"
- layout.operator("wm.url_open", text="Addon Guidelines", icon='URL').url = "http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons"
- layout.operator("wm.url_open", text="How to share your addon", icon='URL').url = "http://wiki.blender.org/index.php/Dev:Py/Sharing"
+ layout.operator(
+ "wm.url_open", text="Add-ons Catalog", icon='URL',
+ ).url = "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts"
+
+ layout.separator()
+
+ layout.operator(
+ "wm.url_open", text="How to share your add-on", icon='URL',
+ ).url = "http://wiki.blender.org/index.php/Dev:Py/Sharing"
+ layout.operator(
+ "wm.url_open", text="Add-on Guidelines", icon='URL',
+ ).url = "http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons"
+ layout.operator(
+ "wm.url_open", text="API Concepts", icon='URL',
+ ).url = bpy.types.WM_OT_doc_view._prefix + "/info_quickstart.html"
+ layout.operator("wm.url_open", text="Add-on Tutorial", icon='URL',
+ ).url = "http://www.blender.org/api/blender_python_api_current/info_tutorial_addon.html"
class USERPREF_PT_addons(Panel):
@@ -1302,9 +1356,19 @@ class USERPREF_PT_addons(Panel):
col_box = col.column()
box = col_box.box()
colsub = box.column()
- row = colsub.row()
+ row = colsub.row(align=True)
+
+ row.operator(
+ "wm.addon_expand",
+ icon='TRIA_DOWN' if info["show_expanded"] else 'TRIA_RIGHT',
+ emboss=False,
+ ).module = module_name
- row.operator("wm.addon_expand", icon='TRIA_DOWN' if info["show_expanded"] else 'TRIA_RIGHT', emboss=False).module = module_name
+ row.operator(
+ "wm.addon_disable" if is_enabled else "wm.addon_enable",
+ icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', text="",
+ emboss=False,
+ ).module = module_name
sub = row.row()
sub.active = is_enabled
@@ -1315,11 +1379,6 @@ class USERPREF_PT_addons(Panel):
# icon showing support level.
sub.label(icon=self._support_icon_mapping.get(info["support"], 'QUESTION'))
- if is_enabled:
- row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
- else:
- row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name
-
# Expanded UI (only if additional info is available)
if info["show_expanded"]:
if info["description"]:
@@ -1397,12 +1456,15 @@ class USERPREF_PT_addons(Panel):
# Addon UI Code
box = col.column().box()
colsub = box.column()
- row = colsub.row()
+ row = colsub.row(align=True)
- row.label(text=module_name, translate=False, icon='ERROR')
+ row.label(text="", icon='ERROR')
if is_enabled:
row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
+ row.label(text=module_name, translate=False)
+
+
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index bb0ad001c34..8db6f81ea51 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -118,6 +118,18 @@ class VIEW3D_HT_header(Header):
row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False
row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True
+ # GPencil
+ if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
+ row = layout.row(align=True)
+ row.operator("gpencil.copy", text="", icon='COPYDOWN')
+ row.operator("gpencil.paste", text="", icon='PASTEDOWN')
+
+ layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH') # XXX: icon
+
+ layout.prop(context.tool_settings.gpencil_sculpt, "use_select_mask")
+
+
+
class VIEW3D_MT_editor_menus(Menu):
bl_space_type = 'VIEW3D_MT_editor_menus'
@@ -131,11 +143,14 @@ class VIEW3D_MT_editor_menus(Menu):
obj = context.active_object
mode_string = context.mode
edit_object = context.edit_object
+ gp_edit = context.gpencil_data and context.gpencil_data.use_stroke_edit_mode
layout.menu("VIEW3D_MT_view")
# Select Menu
- if mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
+ if gp_edit:
+ layout.menu("VIEW3D_MT_select_gpencil")
+ elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
mesh = obj.data
if mesh.use_paint_mask:
layout.menu("VIEW3D_MT_select_paint_mask")
@@ -144,7 +159,9 @@ class VIEW3D_MT_editor_menus(Menu):
elif mode_string != 'SCULPT':
layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
- if mode_string == 'OBJECT':
+ if gp_edit:
+ pass
+ elif mode_string == 'OBJECT':
layout.menu("INFO_MT_add", text="Add")
elif mode_string == 'EDIT_MESH':
layout.menu("INFO_MT_mesh_add", text="Add")
@@ -157,7 +174,9 @@ class VIEW3D_MT_editor_menus(Menu):
elif mode_string == 'EDIT_ARMATURE':
layout.menu("INFO_MT_edit_armature_add", text="Add")
- if edit_object:
+ if gp_edit:
+ layout.menu("VIEW3D_MT_edit_gpencil")
+ elif edit_object:
layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
elif obj:
if mode_string != 'PAINT_TEXTURE':
@@ -419,6 +438,7 @@ class VIEW3D_MT_view(Menu):
layout.operator("view3d.clip_border", text="Clipping Border...")
layout.operator("view3d.zoom_border", text="Zoom Border...")
layout.operator("view3d.render_border", text="Render Border...").camera_only = False
+ layout.operator("view3d.clear_render_border")
layout.separator()
@@ -456,8 +476,8 @@ class VIEW3D_MT_view_navigation(Menu):
layout.separator()
- layout.operator("view3d.view_roll", text="Roll Left").angle = pi / -12.0
- layout.operator("view3d.view_roll", text="Roll Right").angle = pi / 12.0
+ layout.operator("view3d.view_roll", text="Roll Left").type = 'LEFT'
+ layout.operator("view3d.view_roll", text="Roll Right").type = 'RIGHT'
layout.separator()
@@ -537,8 +557,40 @@ class VIEW3D_MT_view_cameras(Menu):
layout.operator("view3d.object_as_camera")
layout.operator("view3d.viewnumpad", text="Active Camera").type = 'CAMERA'
+
# ********** Select menus, suffix from context.mode **********
+class VIEW3D_MT_select_object_more_less(Menu):
+ bl_label = "Select More/Less"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout = self.layout
+
+ layout.operator("object.select_more", text="More")
+ layout.operator("object.select_less", text="Less")
+
+ layout.separator()
+
+ props = layout.operator("object.select_hierarchy", text="Parent")
+ props.extend = False
+ props.direction = 'PARENT'
+
+ props = layout.operator("object.select_hierarchy", text="Child")
+ props.extend = False
+ props.direction = 'CHILD'
+
+ layout.separator()
+
+ props = layout.operator("object.select_hierarchy", text="Extend Parent")
+ props.extend = True
+ props.direction = 'PARENT'
+
+ props = layout.operator("object.select_hierarchy", text="Extend Child")
+ props.extend = True
+ props.direction = 'CHILD'
+
class VIEW3D_MT_select_object(Menu):
bl_label = "Select"
@@ -561,29 +613,22 @@ class VIEW3D_MT_select_object(Menu):
layout.separator()
+ layout.menu("VIEW3D_MT_select_object_more_less")
+
+ layout.separator()
+
layout.operator_menu_enum("object.select_grouped", "type", text="Grouped")
layout.operator_menu_enum("object.select_linked", "type", text="Linked")
layout.operator("object.select_pattern", text="Select Pattern...")
-class VIEW3D_MT_select_pose(Menu):
- bl_label = "Select"
+class VIEW3D_MT_select_pose_more_less(Menu):
+ bl_label = "Select More/Less"
def draw(self, context):
layout = self.layout
- layout.operator("view3d.select_border")
- layout.operator("view3d.select_circle")
-
- layout.separator()
-
- layout.operator("pose.select_all").action = 'TOGGLE'
- layout.operator("pose.select_all", text="Inverse").action = 'INVERT'
- layout.operator("pose.select_mirror", text="Flip Active")
- layout.operator("pose.select_constraint_target", text="Constraint Target")
- layout.operator("pose.select_linked", text="Linked")
-
- layout.separator()
+ layout = self.layout
props = layout.operator("pose.select_hierarchy", text="Parent")
props.extend = False
@@ -603,6 +648,28 @@ class VIEW3D_MT_select_pose(Menu):
props.extend = True
props.direction = 'CHILD'
+
+class VIEW3D_MT_select_pose(Menu):
+ bl_label = "Select"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
+
+ layout.separator()
+
+ layout.operator("pose.select_all").action = 'TOGGLE'
+ layout.operator("pose.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("pose.select_mirror", text="Flip Active")
+ layout.operator("pose.select_constraint_target", text="Constraint Target")
+ layout.operator("pose.select_linked", text="Linked")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_select_pose_more_less")
+
layout.separator()
layout.operator_menu_enum("pose.select_grouped", "type", text="Grouped")
@@ -651,6 +718,37 @@ class VIEW3D_MT_edit_mesh_select_similar(Menu):
layout.operator("mesh.select_similar_region", text="Face Regions")
+class VIEW3D_MT_edit_mesh_select_by_trait(Menu):
+ bl_label = "Select All by Trait"
+
+ def draw(self, context):
+ layout = self.layout
+ if context.scene.tool_settings.mesh_select_mode[2] is False:
+ layout.operator("mesh.select_non_manifold", text="Non Manifold")
+ layout.operator("mesh.select_loose", text="Loose Geometry")
+ layout.operator("mesh.select_interior_faces", text="Interior Faces")
+ layout.operator("mesh.select_face_by_sides")
+
+ layout.separator()
+
+ layout.operator("mesh.select_ungrouped", text="Ungrouped Verts")
+
+
+class VIEW3D_MT_edit_mesh_select_more_less(Menu):
+ bl_label = "Select More/Less"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("mesh.select_more", text="More")
+ layout.operator("mesh.select_less", text="Less")
+
+ layout.separator()
+
+ layout.operator("mesh.select_next_item", text="Next Active")
+ layout.operator("mesh.select_prev_item", text="Previous Active")
+
+
class VIEW3D_MT_select_edit_mesh(Menu):
bl_label = "Select"
@@ -680,23 +778,16 @@ class VIEW3D_MT_select_edit_mesh(Menu):
layout.separator()
- # topology
- layout.operator("mesh.select_loose", text="Loose Geometry")
- if context.scene.tool_settings.mesh_select_mode[2] is False:
- layout.operator("mesh.select_non_manifold", text="Non Manifold")
- layout.operator("mesh.select_interior_faces", text="Interior Faces")
- layout.operator("mesh.select_face_by_sides")
+ # other ...
+ layout.menu("VIEW3D_MT_edit_mesh_select_similar")
layout.separator()
- # other ...
- layout.menu("VIEW3D_MT_edit_mesh_select_similar")
- layout.operator("mesh.select_ungrouped", text="Ungrouped Verts")
+ layout.menu("VIEW3D_MT_edit_mesh_select_by_trait")
layout.separator()
- layout.operator("mesh.select_more", text="More")
- layout.operator("mesh.select_less", text="Less")
+ layout.menu("VIEW3D_MT_edit_mesh_select_more_less")
layout.separator()
@@ -788,7 +879,6 @@ class VIEW3D_MT_select_edit_text(Menu):
layout.separator()
layout.operator("font.text_paste_from_file")
- layout.operator("font.text_paste_from_clipboard")
layout.separator()
@@ -883,6 +973,29 @@ class VIEW3D_MT_select_edit_armature(Menu):
layout.operator("object.select_pattern", text="Select Pattern...")
+class VIEW3D_MT_select_gpencil(Menu):
+ bl_label = "Select"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("gpencil.select_border")
+ layout.operator("gpencil.select_circle")
+
+ layout.separator()
+
+ layout.operator("gpencil.select_all", text="(De)select All").action = 'TOGGLE'
+ layout.operator("gpencil.select_all", text="Inverse").action = 'INVERT'
+ layout.operator("gpencil.select_linked", text="Linked")
+ #layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
+ layout.operator("gpencil.select_grouped", text="Grouped")
+
+ layout.separator()
+
+ layout.operator("gpencil.select_more")
+ layout.operator("gpencil.select_less")
+
+
class VIEW3D_MT_select_paint_mask(Menu):
bl_label = "Select"
@@ -1114,6 +1227,8 @@ class VIEW3D_MT_object(Menu):
def draw(self, context):
layout = self.layout
+ view = context.space_data
+ is_local_view = (view.local_view is not None)
layout.operator("ed.undo")
layout.operator("ed.redo")
@@ -1165,7 +1280,13 @@ class VIEW3D_MT_object(Menu):
layout.separator()
- layout.operator("object.move_to_layer", text="Move to Layer...")
+ if is_local_view:
+ layout.operator_context = 'EXEC_REGION_WIN'
+ layout.operator("object.move_to_layer", text="Move out of Local View")
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ else:
+ layout.operator("object.move_to_layer", text="Move to Layer...")
+
layout.menu("VIEW3D_MT_object_showhide")
layout.operator_menu_enum("object.convert", "target")
@@ -2380,6 +2501,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.operator("mesh.bevel").vertex_only = False
layout.operator("mesh.solidify")
layout.operator("mesh.intersect")
+ layout.operator("mesh.intersect_boolean")
layout.operator("mesh.wireframe")
layout.separator()
@@ -2806,6 +2928,7 @@ class VIEW3D_MT_edit_armature_roll(Menu):
layout.separator()
layout.operator("transform.transform", text="Set Roll").mode = 'BONE_ROLL'
+ layout.operator("armature.roll_clear")
class VIEW3D_MT_edit_armature_delete(Menu):
@@ -2821,6 +2944,81 @@ class VIEW3D_MT_edit_armature_delete(Menu):
layout.operator("armature.dissolve", text="Dissolve")
+# ********** GPencil Stroke Edit menu **********
+
+
+class VIEW3D_MT_edit_gpencil(Menu):
+ bl_label = "GPencil"
+
+ def draw(self, context):
+ toolsettings = context.tool_settings
+
+ layout = self.layout
+
+ layout.operator("ed.undo")
+ layout.operator("ed.redo")
+ layout.operator("ed.undo_history")
+
+ layout.separator()
+
+ layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True
+ layout.prop_menu_enum(toolsettings.gpencil_sculpt, "tool", text="Sculpt Brush")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_edit_gpencil_transform")
+ layout.operator("transform.mirror", text="Mirror")
+ layout.menu("GPENCIL_MT_snap")
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access...
+
+ layout.separator()
+
+ layout.menu("VIEW3D_MT_edit_gpencil_delete")
+ layout.operator("gpencil.duplicate_move", text="Duplicate")
+
+ layout.separator()
+
+ layout.operator("gpencil.copy", text="Copy")
+ layout.operator("gpencil.paste", text="Paste")
+
+ layout.separator()
+
+ layout.prop_menu_enum(toolsettings, "proportional_edit")
+ layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+
+ layout.separator()
+
+ layout.operator("gpencil.reveal")
+ layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True
+ layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
+
+ layout.separator()
+
+ layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
+ layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
+
+
+class VIEW3D_MT_edit_gpencil_transform(Menu):
+ bl_label = "Transform"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("transform.translate")
+ layout.operator("transform.rotate")
+ layout.operator("transform.resize", text="Scale")
+
+ layout.separator()
+
+ layout.operator("transform.bend", text="Bend")
+ layout.operator("transform.shear", text="Shear")
+ layout.operator("transform.tosphere", text="To Sphere")
+ layout.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN'
+
+
# ********** Panel **********
@@ -3046,7 +3244,7 @@ class VIEW3D_PT_view3d_shading(Panel):
col.prop(view, "use_matcap")
if view.use_matcap:
col.template_icon_view(view, "matcap_icon")
- elif view.viewport_shade == 'TEXTURED':
+ if view.viewport_shade == 'TEXTURED' or context.mode == 'PAINT_TEXTURE':
if scene.render.use_shading_nodes or gs.material_mode != 'GLSL':
col.prop(view, "show_textured_shadeless")
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index a24dc494c30..7748618a0aa 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -21,7 +21,8 @@ import bpy
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
- GreasePencilStrokeEditPanel
+ GreasePencilStrokeEditPanel,
+ GreasePencilStrokeSculptPanel
)
from bl_ui.properties_paint_common import (
UnifiedPaintPanel,
@@ -135,6 +136,7 @@ class VIEW3D_PT_tools_add_object(View3DPanel, Panel):
@staticmethod
def draw_add_curve(layout, label=False):
+
if label:
layout.label(text="Bezier:")
layout.operator("curve.primitive_bezier_curve_add", text="Bezier", icon='CURVE_BEZCURVE')
@@ -148,6 +150,10 @@ class VIEW3D_PT_tools_add_object(View3DPanel, Panel):
layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
+ layout.separator()
+
+ layout.operator("curve.draw", icon='LINE_DATA')
+
@staticmethod
def draw_add_surface(layout):
layout.operator("surface.primitive_nurbs_surface_curve_add", text="Nurbs Curve", icon='SURFACE_NCURVE')
@@ -241,13 +247,19 @@ class VIEW3D_PT_tools_animation(View3DPanel, Panel):
def draw(self, context):
layout = self.layout
+ ob = context.active_object
+ mpath = ob.motion_path if ob else None
+
draw_keyframing_tools(context, layout)
col = layout.column(align=True)
col.label(text="Motion Paths:")
- row = col.row(align=True)
- row.operator("object.paths_calculate", text="Calculate")
- row.operator("object.paths_clear", text="Clear")
+ if mpath:
+ row = col.row(align=True)
+ row.operator("object.paths_update", text="Update")
+ row.operator("object.paths_clear", text="", icon='X')
+ else:
+ col.operator("object.paths_calculate", text="Calculate")
col.separator()
@@ -539,8 +551,59 @@ class VIEW3D_PT_tools_add_curve_edit(View3DPanel, Panel):
VIEW3D_PT_tools_add_object.draw_add_curve(col, label=True)
-# ********** default tools for editmode_surface ****************
+class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
+ bl_category = "Options"
+ bl_context = "curve_edit"
+ bl_label = "Curve Stroke"
+
+ def draw(self, context):
+ layout = self.layout
+
+ tool_settings = context.tool_settings
+ cps = tool_settings.curve_paint_settings
+
+ col = layout.column()
+
+ col.prop(cps, "curve_type")
+
+ if cps.curve_type == 'BEZIER':
+ col.label("Bezier Options:")
+ col.prop(cps, "error_threshold")
+ col.prop(cps, "use_corners_detect")
+
+ col = layout.column()
+ col.active = cps.use_corners_detect
+ col.prop(cps, "corner_angle")
+
+ col.label("Pressure Radius:")
+ row = layout.row(align=True)
+ rowsub = row.row(align=True)
+ rowsub.prop(cps, "radius_min", text="Min")
+ rowsub.prop(cps, "radius_max", text="Max")
+
+ row.prop(cps, "use_pressure_radius", text="", icon_only=True)
+
+ col = layout.column()
+ col.label("Taper Radius:")
+ row = layout.row(align=True)
+ row.prop(cps, "radius_taper_start", text="Start")
+ row.prop(cps, "radius_taper_end", text="End")
+
+ col = layout.column()
+ col.label("Projection Depth:")
+ row = layout.row(align=True)
+ row.prop(cps, "depth_mode", expand=True)
+
+ col = layout.column()
+ if cps.depth_mode == 'SURFACE':
+ col.prop(cps, "radius_offset")
+ col.prop(cps, "use_stroke_endpoints")
+ if cps.use_stroke_endpoints:
+ colsub = layout.column(align=True)
+ colsub.prop(cps, "surface_plane", expand=True)
+
+# ********** default tools for editmode_surface ****************
class VIEW3D_PT_tools_transform_surface(View3DPanel, Panel):
bl_category = "Tools"
@@ -769,11 +832,17 @@ class VIEW3D_PT_tools_posemode(View3DPanel, Panel):
draw_keyframing_tools(context, layout)
+ pchan = context.active_pose_bone
+ mpath = pchan.motion_path if pchan else None
+
col = layout.column(align=True)
col.label(text="Motion Paths:")
- row = col.row(align=True)
- row.operator("pose.paths_calculate", text="Calculate")
- row.operator("pose.paths_clear", text="Clear")
+ if mpath:
+ row = col.row(align=True)
+ row.operator("pose.paths_update", text="Update")
+ row.operator("pose.paths_clear", text="", icon='X')
+ else:
+ col.operator("pose.paths_calculate", text="Calculate")
class VIEW3D_PT_tools_posemode_options(View3DPanel, Panel):
@@ -950,6 +1019,12 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
row = col.row(align=True)
row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
+ # rake_factor
+ if capabilities.has_rake_factor:
+ col.separator()
+ row = col.row(align=True)
+ row.prop(brush, "rake_factor", slider=True)
+
# use_original_normal and sculpt_plane
if capabilities.has_sculpt_plane:
col.separator()
@@ -1036,6 +1111,10 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
col.prop(brush, "vertex_tool", text="Blend")
+ if brush.vertex_tool == 'BLUR':
+ col.prop(brush, "use_accumulate")
+ col.separator()
+
col = layout.column()
col.prop(toolsettings, "use_auto_normalize", text="Auto Normalize")
col.prop(toolsettings, "use_multipaint", text="Multi-Paint")
@@ -1569,7 +1648,7 @@ class VIEW3D_PT_tools_brush_appearance(Panel, View3DPaintPanel):
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
- return settings
+ return (settings is not None) and (not isinstance(settings, bpy.types.ParticleEdit))
def draw(self, context):
layout = self.layout
@@ -1653,7 +1732,6 @@ class VIEW3D_PT_tools_weightpaint_options(Panel, View3DPaintPanel):
col.label("Show Zero Weights:")
sub = col.row()
- sub.active = (not tool_settings.use_multipaint)
sub.prop(tool_settings, "vertex_group_user", expand=True)
self.unified_paint_settings(col, context)
@@ -1875,6 +1953,11 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'VIEW_3D'
+# Grease Pencil stroke sculpting tools
+class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
+ bl_space_type = 'VIEW_3D'
+
+
# Note: moved here so that it's always in last position in 'Tools' panels!
class VIEW3D_PT_tools_history(View3DPanel, Panel):
bl_category = "Tools"
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index c3def14787d..780662148e0 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -118,7 +118,7 @@ def line_style_shader_nodes_poll(context):
def world_shader_nodes_poll(context):
snode = context.space_data
return (snode.tree_type == 'ShaderNodeTree' and
- snode.shader_type == 'WORLD')
+ snode.shader_type == 'WORLD')
# only show nodes working in object node trees
@@ -159,6 +159,7 @@ shader_node_categories = [
NodeItem("ShaderNodeNormal"),
NodeItem("ShaderNodeMapping"),
NodeItem("ShaderNodeVectorCurve"),
+ NodeItem("ShaderNodeVectorTransform"),
]),
ShaderOldNodeCategory("SH_CONVERTOR", "Converter", items=[
NodeItem("ShaderNodeValToRGB"),
diff --git a/release/scripts/templates_py/background_job.py b/release/scripts/templates_py/background_job.py
index 11b51e5a9b5..2911740abf9 100644
--- a/release/scripts/templates_py/background_job.py
+++ b/release/scripts/templates_py/background_job.py
@@ -11,7 +11,7 @@
#
# Notice:
# '--factory-startup' is used to avoid the user default settings from
-# interfearing with automated scene generation.
+# interfering with automated scene generation.
#
# '--' causes blender to ignore all following arguments so python can use them.
#
@@ -51,18 +51,7 @@ def example_function(text, save_path, render_path):
lamp_ob.location = 2.0, 2.0, 5.0
if save_path:
- try:
- f = open(save_path, 'w')
- f.close()
- ok = True
- except:
- print("Cannot save to path %r" % save_path)
-
- import traceback
- traceback.print_exc()
-
- if ok:
- bpy.ops.wm.save_as_mainfile(filepath=save_path)
+ bpy.ops.wm.save_as_mainfile(filepath=save_path)
if render_path:
render = scene.render
@@ -85,9 +74,10 @@ def main():
argv = argv[argv.index("--") + 1:] # get all args after "--"
# When --help or no args are given, print this help
- usage_text = \
- "Run blender in background mode with this script:"
- " blender --background --python " + __file__ + " -- [options]"
+ usage_text = (
+ "Run blender in background mode with this script:"
+ " blender --background --python " + __file__ + " -- [options]"
+ )
parser = argparse.ArgumentParser(description=usage_text)
diff --git a/release/scripts/templates_py/operator_file_export.py b/release/scripts/templates_py/operator_file_export.py
index 9511cb163bc..38c88069845 100644
--- a/release/scripts/templates_py/operator_file_export.py
+++ b/release/scripts/templates_py/operator_file_export.py
@@ -28,6 +28,7 @@ class ExportSomeData(Operator, ExportHelper):
filter_glob = StringProperty(
default="*.txt",
options={'HIDDEN'},
+ maxlen=255, # Max internal buffer length, longer would be clamped.
)
# List of operator properties, the attributes will be assigned
diff --git a/release/scripts/templates_py/operator_file_import.py b/release/scripts/templates_py/operator_file_import.py
index 9940a1b98eb..0ec57544f3d 100644
--- a/release/scripts/templates_py/operator_file_import.py
+++ b/release/scripts/templates_py/operator_file_import.py
@@ -31,6 +31,7 @@ class ImportSomeData(Operator, ImportHelper):
filter_glob = StringProperty(
default="*.txt",
options={'HIDDEN'},
+ maxlen=255, # Max internal buffer length, longer would be clamped.
)
# List of operator properties, the attributes will be assigned
diff --git a/release/scripts/templates_py/operator_mesh_add.py b/release/scripts/templates_py/operator_mesh_add.py
index 5fabaaf3f7f..2590d53e49a 100644
--- a/release/scripts/templates_py/operator_mesh_add.py
+++ b/release/scripts/templates_py/operator_mesh_add.py
@@ -33,7 +33,12 @@ def add_box(width, height, depth):
return verts, faces
-from bpy.props import FloatProperty, BoolProperty, FloatVectorProperty
+from bpy.props import (
+ BoolProperty,
+ BoolVectorProperty,
+ FloatProperty,
+ FloatVectorProperty,
+ )
class AddBox(bpy.types.Operator):
@@ -60,6 +65,12 @@ class AddBox(bpy.types.Operator):
min=0.01, max=100.0,
default=1.0,
)
+ layers = BoolVectorProperty(
+ name="Layers",
+ description="Object Layers",
+ size=20,
+ options={'HIDDEN', 'SKIP_SAVE'},
+ )
# generic transform props
view_align = BoolProperty(
diff --git a/release/scripts/templates_py/operator_modal_view3d_raycast.py b/release/scripts/templates_py/operator_modal_view3d_raycast.py
index b72b2f76750..c4d661b4c1f 100644
--- a/release/scripts/templates_py/operator_modal_view3d_raycast.py
+++ b/release/scripts/templates_py/operator_modal_view3d_raycast.py
@@ -2,7 +2,7 @@ import bpy
from bpy_extras import view3d_utils
-def main(context, event, ray_max=1000.0):
+def main(context, event):
"""Run this function on left mouse, execute the ray cast"""
# get the context arguments
scene = context.scene
@@ -14,7 +14,7 @@ def main(context, event, ray_max=1000.0):
view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
- ray_target = ray_origin + (view_vector * ray_max)
+ ray_target = ray_origin + view_vector
def visible_objects_and_duplis():
"""Loop over (object, matrix) pairs (mesh only)"""
@@ -39,17 +39,18 @@ def main(context, event, ray_max=1000.0):
matrix_inv = matrix.inverted()
ray_origin_obj = matrix_inv * ray_origin
ray_target_obj = matrix_inv * ray_target
+ ray_direction_obj = ray_target_obj - ray_origin_obj
# cast the ray
- hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj)
+ success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
- if face_index != -1:
- return hit, normal, face_index
+ if success:
+ return location, normal, face_index
else:
return None, None, None
# cast rays and find the closest object
- best_length_squared = ray_max * ray_max
+ best_length_squared = -1.0
best_obj = None
for obj, matrix in visible_objects_and_duplis():
@@ -59,7 +60,7 @@ def main(context, event, ray_max=1000.0):
hit_world = matrix * hit
scene.cursor_location = hit_world
length_squared = (hit_world - ray_origin).length_squared
- if length_squared < best_length_squared:
+ if best_obj is None or length_squared < best_length_squared:
best_length_squared = length_squared
best_obj = obj
diff --git a/release/text/ocio-license.txt b/release/text/ocio-license.txt
new file mode 100644
index 00000000000..3dfcc78df9e
--- /dev/null
+++ b/release/text/ocio-license.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
+All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of Sony Pictures Imageworks nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/source/icons/blender.exe.manifest b/release/windows/icons/blender.exe.manifest
index a43d11b21a0..a43d11b21a0 100644
--- a/source/icons/blender.exe.manifest
+++ b/release/windows/icons/blender.exe.manifest
diff --git a/source/icons/winblender.ico b/release/windows/icons/winblender.ico
index e6b368c562b..e6b368c562b 100644
--- a/source/icons/winblender.ico
+++ b/release/windows/icons/winblender.ico
Binary files differ
diff --git a/source/icons/winblender.rc b/release/windows/icons/winblender.rc
index 244c2cb2e2c..244c2cb2e2c 100644
--- a/source/icons/winblender.rc
+++ b/release/windows/icons/winblender.rc
diff --git a/source/icons/winblenderfile.ico b/release/windows/icons/winblenderfile.ico
index 254480b6ed5..254480b6ed5 100644
--- a/source/icons/winblenderfile.ico
+++ b/release/windows/icons/winblenderfile.ico
Binary files differ
diff --git a/scons b/scons
deleted file mode 160000
-Subproject 625d446ae8996ff1b3d660c44e2827fc832cf12
diff --git a/source/SConscript b/source/SConscript
deleted file mode 100644
index 432cfb31c7d..00000000000
--- a/source/SConscript
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-SConscript(['blender/SConscript'])
-
-if env['WITH_BF_GAMEENGINE']:
- SConscript (['gameengine/SConscript'])
-
-if env['WITH_BF_PLAYER']:
- SConscript (['blenderplayer/bad_level_call_stubs/SConscript'])
-
-if env['OURPLATFORM'] in ('win64-vc', 'win32-vc', 'win32-mingw', 'linuxcross', 'win64-mingw'):
- SConscript (['icons/SConscript'])
diff --git a/source/blender/SConscript b/source/blender/SConscript
deleted file mode 100644
index c6f4994bb4f..00000000000
--- a/source/blender/SConscript
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-import sys
-
-SConscript(['avi/SConscript',
- 'bmesh/SConscript',
- 'blenkernel/SConscript',
- 'blenlib/SConscript',
- 'blenloader/SConscript',
- 'blentranslation/SConscript',
- 'depsgraph/SConscript',
- 'gpu/SConscript',
- 'editors/SConscript',
- 'imbuf/SConscript',
- 'makesdna/SConscript',
- 'render/SConscript',
- 'nodes/SConscript',
- 'modifiers/SConscript',
- 'ikplugin/SConscript',
- 'physics/SConscript',
- 'windowmanager/SConscript',
- 'blenfont/SConscript'])
-
-makesrna = SConscript('makesrna/SConscript')
-
-if env['WITH_BF_PYTHON']:
- SConscript(['python/SConscript'])
-
-if env['WITH_BF_OIIO']:
- SConscript (['imbuf/intern/oiio/SConscript'])
-
-if env['WITH_BF_DDS']:
- SConscript (['imbuf/intern/dds/SConscript'])
-
-if env['WITH_BF_CINEON']:
- SConscript (['imbuf/intern/cineon/SConscript'])
-
-if env['WITH_BF_OPENEXR']:
- SConscript (['imbuf/intern/openexr/SConscript'])
-
-if env['WITH_BF_QUICKTIME']:
- SConscript (['quicktime/SConscript'])
-
-if env['WITH_BF_COLLADA']:
- SConscript (['collada/SConscript'])
-
-if env['WITH_BF_COMPOSITOR']:
- SConscript (['compositor/SConscript'])
-
-if env['WITH_BF_FREESTYLE']:
- SConscript (['freestyle/SConscript'])
diff --git a/source/blender/avi/SConscript b/source/blender/avi/SConscript
deleted file mode 100644
index 6caeada0e05..00000000000
--- a/source/blender/avi/SConscript
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- '#/intern/guardedalloc',
- '../blenlib',
- env['BF_JPEG_INC'],
- ]
-
-defs = []
-
-env.BlenderLib ('bf_avi', sources, incs, defs, libtype=['core','player'], priority = [190,120] )
diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c
index 6ea94d3b2f3..9601d6e5002 100644
--- a/source/blender/avi/intern/avi.c
+++ b/source/blender/avi/intern/avi.c
@@ -1063,6 +1063,11 @@ AviError AVI_close_compress(AviMovie *movie)
{
int temp, movi_size, i;
+ if (movie->fp == NULL) {
+ /* none of the allocations below were done if the file failed to open */
+ return AVI_ERROR_FOUND;
+ }
+
fseek(movie->fp, 0L, SEEK_END);
movi_size = (int)ftell(movie->fp);
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 9527c4edcf0..e565ffe3cc1 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -73,7 +73,7 @@ void BLF_size(int fontid, int size, int dpi);
* | m[3] m[7] m[11] m[15] |
*
*/
-void BLF_matrix(int fontid, const double m[16]);
+void BLF_matrix(int fontid, const float m[16]);
/* Draw the string using the default font, size and dpi. */
void BLF_draw_default(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();
diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript
deleted file mode 100644
index 6c3b5748011..00000000000
--- a/source/blender/blenfont/SConscript
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- 'intern',
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../blenkernel',
- '../blenlib',
- '../blentranslation',
- '../editors/include',
- '../gpu',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- ]
-
-incs.extend(Split(env['BF_FREETYPE_INC']))
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if sys.platform == 'win32' or env['OURPLATFORM'] == 'linuxcross':
- defs.append('_WIN32')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
- incs.append('../python')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-env.BlenderLib('bf_blenfont', sources, incs, defines=defs, libtype=['core', 'player'], priority=[210, 210])
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index a97187657b8..977fa771014 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -55,6 +55,10 @@
#include "IMB_colormanagement.h"
+#ifndef BLF_STANDALONE
+#include "GPU_basic_shader.h"
+#endif
+
#include "blf_internal_types.h"
#include "blf_internal.h"
@@ -176,9 +180,6 @@ int BLF_load(const char *name)
char *filename;
int i;
- if (!name)
- return -1;
-
/* check if we already load this font. */
i = blf_search(name);
if (i >= 0) {
@@ -216,9 +217,6 @@ int BLF_load_unique(const char *name)
char *filename;
int i;
- if (!name)
- return -1;
-
/* Don't search in the cache!! make a new
* object font, this is for keep fonts threads safe.
*/
@@ -260,9 +258,6 @@ int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size)
FontBLF *font;
int i;
- if (!name)
- return -1;
-
i = blf_search(name);
if (i >= 0) {
/*font = global_font[i];*/ /*UNUSED*/
@@ -275,7 +270,7 @@ int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size)
return -1;
}
- if (!mem || !mem_size) {
+ if (!mem_size) {
printf("Can't load font: %s from memory!!\n", name);
return -1;
}
@@ -295,9 +290,6 @@ int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size
FontBLF *font;
int i;
- if (!name)
- return -1;
-
/*
* Don't search in the cache, make a new object font!
* this is to keep the font thread safe.
@@ -308,7 +300,7 @@ int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size
return -1;
}
- if (!mem || !mem_size) {
+ if (!mem_size) {
printf("Can't load font: %s from memory!!\n", name);
return -1;
}
@@ -394,7 +386,7 @@ void BLF_aspect(int fontid, float x, float y, float z)
}
}
-void BLF_matrix(int fontid, const double m[16])
+void BLF_matrix(int fontid, const float m[16])
{
FontBLF *font = blf_get(fontid);
@@ -498,7 +490,7 @@ void BLF_rotation_default(float angle)
}
}
-static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param)
+static void blf_draw_gl__start(FontBLF *font, GLint *mode)
{
/*
* The pixmap alignment hack is handle
@@ -506,9 +498,12 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param)
*/
glEnable(GL_BLEND);
- glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#ifndef BLF_STANDALONE
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
+#endif
+
/* Save the current matrix mode. */
glGetIntegerv(GL_MATRIX_MODE, mode);
@@ -520,7 +515,7 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param)
glPushMatrix();
if (font->flags & BLF_MATRIX)
- glMultMatrixd((GLdouble *)&font->m);
+ glMultMatrixf(font->m);
glTranslate3fv(font->pos);
@@ -535,19 +530,10 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param)
/* always bind the texture for the first glyph */
font->tex_bind_state = -1;
-
- /* Save the current parameter to restore it later. */
- glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
- if (*param != GL_MODULATE)
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
-static void blf_draw_gl__end(GLint mode, GLint param)
+static void blf_draw_gl__end(GLint mode)
{
- /* and restore the original value. */
- if (param != GL_MODULATE)
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
-
glMatrixMode(GL_TEXTURE);
glPopMatrix();
@@ -557,8 +543,10 @@ static void blf_draw_gl__end(GLint mode, GLint param)
if (mode != GL_MODELVIEW)
glMatrixMode(mode);
+#ifndef BLF_STANDALONE
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+#endif
glDisable(GL_BLEND);
- glDisable(GL_TEXTURE_2D);
}
void BLF_draw_ex(
@@ -566,19 +554,19 @@ void BLF_draw_ex(
struct ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
- GLint mode, param;
+ GLint mode;
BLF_RESULT_CHECK_INIT(r_info);
if (font && font->glyph_cache) {
- blf_draw_gl__start(font, &mode, &param);
+ blf_draw_gl__start(font, &mode);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw__wrap(font, str, len, r_info);
}
else {
blf_font_draw(font, str, len, r_info);
}
- blf_draw_gl__end(mode, param);
+ blf_draw_gl__end(mode);
}
}
void BLF_draw(int fontid, const char *str, size_t len)
@@ -591,12 +579,12 @@ void BLF_draw_ascii_ex(
struct ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
- GLint mode, param;
+ GLint mode;
BLF_RESULT_CHECK_INIT(r_info);
if (font && font->glyph_cache) {
- blf_draw_gl__start(font, &mode, &param);
+ blf_draw_gl__start(font, &mode);
if (font->flags & BLF_WORD_WRAP) {
/* use non-ascii draw function for word-wrap */
blf_font_draw__wrap(font, str, len, r_info);
@@ -604,7 +592,7 @@ void BLF_draw_ascii_ex(
else {
blf_font_draw_ascii(font, str, len, r_info);
}
- blf_draw_gl__end(mode, param);
+ blf_draw_gl__end(mode);
}
}
void BLF_draw_ascii(int fontid, const char *str, size_t len)
@@ -615,13 +603,13 @@ void BLF_draw_ascii(int fontid, const char *str, size_t len)
int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth)
{
FontBLF *font = blf_get(fontid);
- GLint mode, param;
+ GLint mode;
int columns = 0;
if (font && font->glyph_cache) {
- blf_draw_gl__start(font, &mode, &param);
+ blf_draw_gl__start(font, &mode);
columns = blf_font_draw_mono(font, str, len, cwidth);
- blf_draw_gl__end(mode, param);
+ blf_draw_gl__end(mode);
}
return columns;
@@ -908,7 +896,7 @@ void BLF_buffer_col(int fontid, float r, float g, float b, float a)
}
-static void blf_draw_buffer__start(FontBLF *font)
+void blf_draw_buffer__start(FontBLF *font)
{
FontBufInfoBLF *buf_info = &font->buf_info;
@@ -925,7 +913,7 @@ static void blf_draw_buffer__start(FontBLF *font)
srgb_to_linearrgb_v4(buf_info->col_float, buf_info->col_init);
}
}
-static void blf_draw_buffer__end(void) {}
+void blf_draw_buffer__end(void) {}
void BLF_draw_buffer_ex(
int fontid, const char *str, size_t len,
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 3f3ca78b6cd..7c6bef57aa4 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -306,7 +306,6 @@ static void blf_font_draw_buffer_ex(
const unsigned char *b_col_char = buf_info->col_char;
int chx, chy;
int y, x;
- float a;
BLF_KERNING_VARS(font, has_kerning, kern_mode);
@@ -356,26 +355,27 @@ static void blf_font_draw_buffer_ex(
int yb = yb_start;
for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
- a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
-
- if (a > 0.0f) {
+ const char a_byte = *(g->bitmap + x + (yb * g->pitch));
+ if (a_byte) {
+ const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (
((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
(size_t)buf_info->ch);
float *fbuf = buf_info->fbuf + buf_ofs;
- float alphatest;
if (a >= 1.0f) {
fbuf[0] = b_col_float[0];
fbuf[1] = b_col_float[1];
fbuf[2] = b_col_float[2];
- fbuf[3] = (alphatest = (fbuf[3] + (b_col_float[3]))) < 1.0f ? alphatest : 1.0f;
+ fbuf[3] = 1.0f;
}
else {
+ float alphatest;
fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a));
fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a));
fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a));
- fbuf[3] = (alphatest = (fbuf[3] + (b_col_float[3] * a))) < 1.0f ? alphatest : 1.0f;
+ fbuf[3] = (alphatest = (fbuf[3] + a)) < 1.0f ?
+ alphatest : 1.0f;
}
}
}
@@ -391,40 +391,28 @@ static void blf_font_draw_buffer_ex(
int yb = yb_start;
for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
- a = *(g->bitmap + x + (yb * g->pitch)) / 255.0f;
+ const char a_byte = *(g->bitmap + x + (yb * g->pitch));
- if (a > 0.0f) {
+ if (a_byte) {
+ const float a = (a_byte / 255.0f) * b_col_float[3];
const size_t buf_ofs = (
((size_t)(chx + x) + ((size_t)(pen_y + y) * (size_t)buf_info->w)) *
(size_t)buf_info->ch);
unsigned char *cbuf = buf_info->cbuf + buf_ofs;
- int alphatest;
if (a >= 1.0f) {
cbuf[0] = b_col_char[0];
cbuf[1] = b_col_char[1];
cbuf[2] = b_col_char[2];
-
- alphatest = (int)cbuf[3] + (int)b_col_char[3];
- if (alphatest < 255) {
- cbuf[3] = (unsigned char)(alphatest);
- }
- else {
- cbuf[3] = 255;
- }
+ cbuf[3] = 255;
}
else {
+ int alphatest;
cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
-
- alphatest = ((int)cbuf[3] + (int)((b_col_float[3] * a) * 255.0f));
- if (alphatest < 255) {
- cbuf[3] = (unsigned char)(alphatest);
- }
- else {
- cbuf[3] = 255;
- }
+ cbuf[3] = (unsigned char)((alphatest = ((int)cbuf[3] + (int)(a * 255)) < 255) ?
+ alphatest : 255);
}
}
}
@@ -467,7 +455,10 @@ size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, floa
blf_font_ensure_ascii_table(font);
- while ((i_prev = i), (width_new = pen_x), ((i < len) && str[i])) {
+ while ((void)(i_prev = i),
+ (void)(width_new = pen_x),
+ ((i < len) && str[i]))
+ {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
if (UNLIKELY(c == BLI_UTF8_ERR))
@@ -721,11 +712,13 @@ static void blf_font_wrap_apply(
}
else if (UNLIKELY(g->c != ' ' && (g_prev ? g_prev->c == ' ' : false))) {
wrap.last[0] = i_curr;
- wrap.last[1] = i;
+ wrap.last[1] = i_curr;
}
if (UNLIKELY(do_draw)) {
- // printf("(%d..%d) `%.*s`\n", wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]);
+ // printf("(%03d..%03d) `%.*s`\n",
+ // wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]);
+
callback(font, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
wrap.start = wrap.last[0];
i = wrap.last[1];
@@ -740,7 +733,7 @@ static void blf_font_wrap_apply(
g_prev = g;
}
- // printf("done! %d lines\n", lines);
+ // printf("done! lines: %d, width, %d\n", lines, pen_x_next);
if (r_info) {
r_info->lines = lines;
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 215d2484c18..41726e41176 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -113,6 +113,10 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
gc->max_glyph_height = (int)(((float)font->face->size->metrics.height) / 64.0f);
}
+ /* can happen with size 1 fonts */
+ CLAMP_MIN(gc->max_glyph_width, 1);
+ CLAMP_MIN(gc->max_glyph_height, 1);
+
gc->p2_width = 0;
gc->p2_height = 0;
@@ -170,12 +174,12 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
glGenTextures(1, &gc->textures[gc->cur_tex]);
glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->cur_tex]));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL);
}
GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c)
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 55bc61e0e43..d9d758ce548 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -47,6 +47,9 @@ char *blf_dir_metrics_search(const char *filename);
int blf_font_init(void);
void blf_font_exit(void);
+void blf_draw_buffer__start(struct FontBLF *font);
+void blf_draw_buffer__end(void);
+
struct FontBLF *blf_font_new(const char *name, const char *filename);
struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size);
void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index f17401a9991..0fac576a8cc 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -194,7 +194,7 @@ typedef struct FontBLF {
/* Multiplied this matrix with the current one before
* draw the text! see blf_draw__start.
*/
- double m[16];
+ float m[16];
/* clipping rectangle. */
rctf clip_rec;
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 76479593b54..133168fccf2 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -89,6 +89,8 @@ void BLF_thumb_preview(
font_size_curr = font_size;
+ blf_draw_buffer__start(font);
+
for (i = 0; i < draw_str_lines; i++) {
const char *draw_str_i18n = BLT_translate_do(BLT_I18NCONTEXT_DEFAULT, draw_str[i]);
const size_t draw_str_i18n_len = strlen(draw_str_i18n);
@@ -110,12 +112,13 @@ void BLF_thumb_preview(
if (blf_font_count_missing_chars(
font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) > (draw_str_i18n_nbr / 2))
{
- blf_font_draw_buffer(font, draw_str[i], (size_t)draw_str_i18n_nbr, NULL);
+ blf_font_draw_buffer(font, draw_str[i], strlen(draw_str[i]), NULL);
}
else {
blf_font_draw_buffer(font, draw_str_i18n, draw_str_i18n_len, NULL);
}
}
+ blf_draw_buffer__end();
blf_font_free(font);
}
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index ea0479340ad..bdb1d448c77 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -152,7 +152,8 @@ typedef enum DMDrawFlag {
DM_DRAW_USE_TEXPAINT_UV = (1 << 3),
DM_DRAW_SKIP_HIDDEN = (1 << 4),
DM_DRAW_SKIP_SELECT = (1 << 5),
- DM_DRAW_SELECT_USE_EDITMODE = (1 << 6)
+ DM_DRAW_SELECT_USE_EDITMODE = (1 << 6),
+ DM_DRAW_NEED_NORMALS = (1 << 7)
} DMDrawFlag;
typedef enum DMForeachFlag {
@@ -410,7 +411,7 @@ struct DerivedMesh {
void (*drawFacesTex)(DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag uvflag);
+ void *userData, DMDrawFlag flag);
/** Draw all faces with GLSL materials
* o setMaterial is called for every different material nr
@@ -444,7 +445,7 @@ struct DerivedMesh {
void (*drawMappedFacesTex)(DerivedMesh *dm,
DMSetDrawOptionsMappedTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag uvflag);
+ void *userData, DMDrawFlag flag);
/** Draw mapped faces with GLSL materials
* - setMaterial is called for every different material nr
@@ -499,6 +500,11 @@ void DM_init(
DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
int numFaces, int numLoops, int numPolys);
+void DM_from_template_ex(
+ DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
+ int numVerts, int numEdges, int numTessFaces,
+ int numLoops, int numPolys,
+ CustomDataMask mask);
void DM_from_template(
DerivedMesh *dm, DerivedMesh *source,
DerivedMeshType type,
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index a521dcbca9b..ce0e866195c 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -34,6 +34,7 @@
*/
struct Bone;
+struct GHash;
struct Main;
struct bArmature;
struct bPoseChannel;
@@ -72,6 +73,7 @@ extern "C" {
struct bArmature *BKE_armature_add(struct Main *bmain, const char *name);
struct bArmature *BKE_armature_from_object(struct Object *ob);
+int BKE_armature_bonelist_count(struct ListBase *lb);
void BKE_armature_bonelist_free(struct ListBase *lb);
void BKE_armature_free(struct bArmature *arm);
void BKE_armature_make_local(struct bArmature *arm);
@@ -84,7 +86,8 @@ bool BKE_pose_minmax(struct Object *ob, float r_min[3], float r_max[3], bool use
int bone_autoside_name(char name[64], int strip_number, short axis, float head, float tail);
-struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name);
+struct Bone *BKE_armature_find_bone_name(struct bArmature *arm, const char *name);
+struct GHash *BKE_armature_bone_from_name_map(struct bArmature *arm);
bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 327ae898686..fdb34743f36 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -41,17 +41,17 @@ extern "C" {
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 276
-#define BLENDER_SUBVERSION 1
+#define BLENDER_VERSION 277
+#define BLENDER_SUBVERSION 0
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
-#define BLENDER_MINSUBVERSION 5
+#define BLENDER_MINSUBVERSION 6
/* used by packaging tools */
/* can be left blank, otherwise a,b,c... etc with no quotes */
#define BLENDER_VERSION_CHAR
/* alpha/beta/rc/release, docs use this */
-#define BLENDER_VERSION_CYCLE rc
+#define BLENDER_VERSION_CYCLE alpha
extern char versionstr[]; /* from blender.c */
@@ -103,11 +103,19 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active);
extern bool BKE_undo_save_file(const char *filename);
extern struct Main *BKE_undo_get_main(struct Scene **r_scene);
-/* copybuffer */
-void BKE_copybuffer_begin(struct Main *bmain);
+/* partial blend file writing */
+void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
+void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
+bool BKE_blendfile_write_partial(
+ struct Main *bmain_src, const char *filepath, const int write_flags, struct ReportList *reports);
+void BKE_blendfile_write_partial_end(struct Main *bmain_src);
+
+
+/* copybuffer (wrapper for BKE_blendfile_write_partial) */
+void BKE_copybuffer_begin(struct Main *bmain_src);
void BKE_copybuffer_tag_ID(struct ID *id);
-int BKE_copybuffer_save(const char *filename, struct ReportList *reports);
-int BKE_copybuffer_paste(struct bContext *C, const char *libname, struct ReportList *reports);
+bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports);
+bool BKE_copybuffer_paste(struct bContext *C, const char *libname, const short flag, struct ReportList *reports);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index aff3fb08df6..c663458963c 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -32,6 +32,7 @@ struct ImBuf;
struct ImagePool;
struct Main;
struct Scene;
+struct UnifiedPaintSettings;
// enum CurveMappingPreset;
@@ -40,10 +41,12 @@ void BKE_brush_system_init(void);
void BKE_brush_system_exit(void);
/* datablock functions */
+void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
struct Brush *BKE_brush_copy(struct Brush *brush);
void BKE_brush_make_local(struct Brush *brush);
+void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
@@ -58,8 +61,9 @@ int BKE_brush_clone_image_set_nr(struct Brush *brush, int nr);
int BKE_brush_clone_image_delete(struct Brush *brush);
/* jitter */
-void BKE_brush_jitter_pos(const struct Scene *scene, struct Brush *brush,
- const float pos[2], float jitterpos[2]);
+void BKE_brush_jitter_pos(
+ const struct Scene *scene, struct Brush *brush,
+ const float pos[2], float jitterpos[2]);
void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool mask);
/* brush curve */
@@ -68,10 +72,12 @@ float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float le
float BKE_brush_curve_strength(struct Brush *br, float p, const float len);
/* sampling */
-float BKE_brush_sample_tex_3D(const Scene *scene, struct Brush *br, const float point[3],
- float rgba[4], const int thread, struct ImagePool *pool);
-float BKE_brush_sample_masktex(const Scene *scene, struct Brush *br, const float point[2],
- const int thread, struct ImagePool *pool);
+float BKE_brush_sample_tex_3D(
+ const struct Scene *scene, struct Brush *br, const float point[3],
+ float rgba[4], const int thread, struct ImagePool *pool);
+float BKE_brush_sample_masktex(
+ const struct Scene *scene, struct Brush *br, const float point[2],
+ const int thread, struct ImagePool *pool);
/* texture */
unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
@@ -92,9 +98,9 @@ float BKE_brush_unprojected_radius_get(const struct Scene *scene, const struct B
void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float value);
float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush);
-void BKE_brush_alpha_set(Scene *scene, struct Brush *brush, float alpha);
-float BKE_brush_weight_get(const Scene *scene, const struct Brush *brush);
-void BKE_brush_weight_set(const Scene *scene, struct Brush *brush, float value);
+void BKE_brush_alpha_set(struct Scene *scene, struct Brush *brush, float alpha);
+float BKE_brush_weight_get(const struct Scene *scene, const struct Brush *brush);
+void BKE_brush_weight_set(const struct Scene *scene, struct Brush *brush, float value);
int BKE_brush_use_locked_size(const struct Scene *scene, const struct Brush *brush);
int BKE_brush_use_alpha_pressure(const struct Scene *scene, const struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 18eda63bcf1..08c0fcc0f3c 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -51,6 +51,7 @@ typedef struct BVHTreeFromMesh {
/* default callbacks to bvh nearest and raycast */
BVHTree_NearestPointCallback nearest_callback;
BVHTree_RayCastCallback raycast_callback;
+ BVHTree_NearestToRayCallback nearest_to_ray_callback;
/* Vertex array, so that callbacks have instante access to data */
const struct MVert *vert;
@@ -68,7 +69,8 @@ typedef struct BVHTreeFromMesh {
float sphere_radius;
/* Private data */
- void *em_evil; /* var only for snapping */
+ void *em_evil;
+ bool em_evil_all; /* ignore selection/hidden state, adding all loops to the tree */
bool cached;
} BVHTreeFromMesh;
@@ -141,8 +143,13 @@ enum {
BVHTREE_FROM_VERTS = 0,
BVHTREE_FROM_EDGES = 1,
BVHTREE_FROM_FACES = 2,
- BVHTREE_FROM_FACES_EDITMESH = 3,
- BVHTREE_FROM_LOOPTRI = 4,
+ BVHTREE_FROM_LOOPTRI = 3,
+ /* all faces */
+ BVHTREE_FROM_FACES_EDITMESH_ALL = 4,
+ /* visible unselected, only used for transform snapping */
+ BVHTREE_FROM_FACES_EDITMESH_SNAP = 5,
+ // BVHTREE_FROM_EDGES_EDITMESH_SNAP = 6,
+ BVHTREE_FROM_VERTS_EDITMESH_SNAP = 7,
};
typedef struct LinkNode *BVHCache;
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index aacb7a4066b..d13a711c589 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -50,6 +50,7 @@ struct GPUFXSettings;
/* Camera Datablock */
+void BKE_camera_init(struct Camera *cam);
void *BKE_camera_add(struct Main *bmain, const char *name);
struct Camera *BKE_camera_copy(struct Camera *cam);
void BKE_camera_make_local(struct Camera *cam);
@@ -143,6 +144,7 @@ void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Ob
void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
+bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, struct Object *camera);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index c7ad6419560..9948f21ba90 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -84,9 +84,15 @@ struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm);
* given DerivedMesh and containing the requested numbers of elements.
* elements are initialized to all zeros
*/
-struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source,
- int numVerts, int numEdges, int numFaces,
- int numLoops, int numPolys);
+struct DerivedMesh *CDDM_from_template_ex(
+ struct DerivedMesh *source,
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys,
+ CustomDataMask mask);
+struct DerivedMesh *CDDM_from_template(
+ struct DerivedMesh *source,
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys);
/* converts mfaces to mpolys. note things may break if there are not valid
* medges surrounding each mface.
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
index 74a327c3808..e5d348031e9 100644
--- a/source/blender/blenkernel/BKE_colortools.h
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -51,8 +51,12 @@ struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
void curvemapping_set_black_white_ex(const float black[3], const float white[3], float r_bwmul[3]);
void curvemapping_set_black_white(struct CurveMapping *cumap, const float black[3], const float white[3]);
-#define CURVEMAP_SLOPE_NEGATIVE 0
-#define CURVEMAP_SLOPE_POSITIVE 1
+enum {
+ CURVEMAP_SLOPE_NEGATIVE = 0,
+ CURVEMAP_SLOPE_POSITIVE = 1,
+ CURVEMAP_SLOPE_POS_NEG = 2,
+};
+
void curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope);
void curvemap_remove(struct CurveMap *cuma, const short flag);
bool curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index f7af3a7f8ec..65a68a4387c 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -246,6 +246,9 @@ void CTX_data_scene_set(bContext *C, struct Scene *bmain);
int CTX_data_selected_editable_objects(const bContext *C, ListBase *list);
int CTX_data_selected_editable_bases(const bContext *C, ListBase *list);
+int CTX_data_editable_objects(const bContext *C, ListBase *list);
+int CTX_data_editable_bases(const bContext *C, ListBase *list);
+
int CTX_data_selected_objects(const bContext *C, ListBase *list);
int CTX_data_selected_bases(const bContext *C, ListBase *list);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 14d4198a1a7..5cbe70cd404 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -69,6 +69,7 @@ typedef struct CurveCache {
void BKE_curve_unlink(struct Curve *cu);
void BKE_curve_free(struct Curve *cu);
void BKE_curve_editfont_free(struct Curve *cu);
+void BKE_curve_init(struct Curve *cu);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
struct Curve *BKE_curve_copy(struct Curve *cu);
void BKE_curve_make_local(struct Curve *cu);
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 3e784752f10..17ad51a7a16 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -258,7 +258,9 @@ void CustomData_bmesh_interp(
/* swaps the data in the element corners, to new corners with indices as
* specified in corner_indices. for edges this is an array of length 2, for
* faces an array of length 4 */
-void CustomData_swap(struct CustomData *data, int index, const int *corner_indices);
+void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices);
+
+void CustomData_swap(struct CustomData *data, const int index_a, const int index_b);
/* gets a pointer to the data element at index from the first layer of type
* returns NULL if there is no layer of type
@@ -472,6 +474,8 @@ typedef struct CustomDataTransferLayerMap {
size_t data_offset; /* Offset of actual data we transfer (in element contained in data_src/dst). */
uint64_t data_flag; /* For bitflag transfer, flag(s) to affect in transfered data. */
+ void *interp_data; /* Opaque pointer, to be used by specific interp callback (e.g. transformspace for normals). */
+
cd_datatransfer_interp interp;
} CustomDataTransferLayerMap;
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index a45893b00fa..8756f73df72 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -68,25 +68,40 @@ void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *s
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup);
float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup);
+float BKE_defvert_multipaint_collective_weight(
+ const struct MDeformVert *dv, int defbase_tot,
+ const bool *defbase_sel, int defbase_tot_sel, bool do_autonormalize);
+
void defvert_copy(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src);
-void defvert_copy_subset(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
- const bool *vgroup_subset, const int vgroup_tot);
-void defvert_copy_index(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const int defgroup);
+void defvert_copy_subset(
+ struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
+ const bool *vgroup_subset, const int vgroup_tot);
+void defvert_mirror_subset(
+ struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
+ const bool *vgroup_subset, const int vgroup_tot,
+ const int *flip_map, const int flip_map_len);
+void defvert_copy_index(
+ struct MDeformVert *dvert_dst, const int defgroup_dst,
+ const struct MDeformVert *dvert_src, const int defgroup_src);
void defvert_sync(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src, const bool use_verify);
-void defvert_sync_mapped(struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
- const int *flip_map, const int flip_map_len, const bool use_verify);
+void defvert_sync_mapped(
+ struct MDeformVert *dvert_dst, const struct MDeformVert *dvert_src,
+ const int *flip_map, const int flip_map_len, const bool use_verify);
void defvert_remap(struct MDeformVert *dvert, int *map, const int map_len);
void defvert_flip(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void defvert_flip_merged(struct MDeformVert *dvert, const int *flip_map, const int flip_map_len);
void defvert_normalize(struct MDeformVert *dvert);
-void defvert_normalize_subset(struct MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot);
-void defvert_normalize_lock_single(struct MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot,
- const int def_nr_lock);
-void defvert_normalize_lock_map(struct MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot,
- const bool *lock_flags, const int defbase_tot);
+void defvert_normalize_subset(
+ struct MDeformVert *dvert,
+ const bool *vgroup_subset, const int vgroup_tot);
+void defvert_normalize_lock_single(
+ struct MDeformVert *dvert,
+ const bool *vgroup_subset, const int vgroup_tot,
+ const int def_nr_lock);
+void defvert_normalize_lock_map(
+ struct MDeformVert *dvert,
+ const bool *vgroup_subset, const int vgroup_tot,
+ const bool *lock_flags, const int defbase_tot);
/* Utilities to 'extract' a given vgroup into a simple float array, for verts, but also edges/polys/loops. */
void BKE_defvert_extract_vgroup_to_vertweights(
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index b21c5db2118..fe21eba429a 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -68,6 +68,7 @@ struct BMFace *BKE_bmbvh_ray_cast_filter(
/* find a vert closest to co in a sphere of radius dist_max */
struct BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *tree, const float co[3], const float dist_max);
+struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *tree, const float co[3], const float dist_max);
struct BVHTreeOverlap *BKE_bmbvh_overlap(const BMBVHTree *bmtree_a, const BMBVHTree *bmtree_b, unsigned int *r_overlap_tot);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 443a03a475a..2022d11d508 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -93,11 +93,21 @@ void bezt_add_to_cfra_elem(ListBase *lb, struct BezTriple *bezt);
void fcurve_free_driver(struct FCurve *fcu);
struct ChannelDriver *fcurve_copy_driver(struct ChannelDriver *driver);
-void driver_free_variable(struct ChannelDriver *driver, struct DriverVar *dvar);
+void driver_variables_copy(struct ListBase *dst_list, const struct ListBase *src_list);
+
+void driver_free_variable(struct ListBase *variables, struct DriverVar *dvar);
+void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dvar);
+
void driver_change_variable_type(struct DriverVar *dvar, int type);
+void driver_variable_name_validate(struct DriverVar *dvar);
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
float driver_get_variable_value(struct ChannelDriver *driver, struct DriverVar *dvar);
+bool driver_get_variable_property(
+ struct ChannelDriver *driver, struct DriverTarget *dtar,
+ struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
+
+float evaluate_driver(struct ChannelDriver *driver, const float evaltime);
/* ************** F-Curve Modifiers *************** */
@@ -224,11 +234,14 @@ struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, c
int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/* Find an f-curve based on an rna property. */
-struct FCurve *rna_get_fcurve(struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex,
- struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special);
+struct FCurve *rna_get_fcurve(
+ struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex,
+ struct AnimData **r_adt, struct bAction **r_action,
+ bool *r_driven, bool *r_special);
/* Same as above, but takes a context data, temp hack needed for complex paths like texture ones. */
-struct FCurve *rna_get_fcurve_context_ui(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
- int rnaindex, struct AnimData **adt, struct bAction **action, bool *r_driven, bool *r_special);
+struct FCurve *rna_get_fcurve_context_ui(
+ struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex,
+ struct AnimData **r_adt, struct bAction **r_action, bool *r_driven, bool *r_special);
/* Binary search algorithm for finding where to 'insert' BezTriple with given frame number.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index 137670215cc..0711c423d1c 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -56,9 +56,6 @@ typedef struct EditFontSelBox {
} EditFontSelBox;
typedef struct EditFont {
- wchar_t *copybuf;
- struct CharInfo *copybufinfo;
-
wchar_t *textbuf;
struct CharInfo *textbufinfo;
@@ -79,8 +76,11 @@ void BKE_vfont_builtin_register(void *mem, int size);
void BKE_vfont_free_data(struct VFont *vfont);
void BKE_vfont_free(struct VFont *sc);
+void BKE_vfont_init(struct VFont *vfont);
struct VFont *BKE_vfont_builtin_get(void);
-struct VFont *BKE_vfont_load(struct Main *bmain, const char *name);
+struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath);
+struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
+struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath);
bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode,
struct ListBase *r_nubase,
@@ -93,6 +93,12 @@ bool BKE_vfont_to_curve(struct Main *bmain, struct Object *ob, int mode);
int BKE_vfont_select_get(struct Object *ob, int *r_start, int *r_end);
void BKE_vfont_select_clamp(struct Object *ob);
+void BKE_vfont_clipboard_free(void);
+void BKE_vfont_clipboard_set(const wchar_t *text_buf, const struct CharInfo *info_buf, const size_t len);
+void BKE_vfont_clipboard_get(
+ wchar_t **r_text_buf, struct CharInfo **r_info_buf,
+ size_t *r_len_utf8, size_t *r_len_wchar);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 865f621e82d..26a40597ca8 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -127,7 +127,7 @@ enum {
G_DEBUG_DEPSGRAPH = (1 << 8), /* depsgraph messages */
G_DEBUG_SIMDATA = (1 << 9), /* sim debug data display */
G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */
- G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* sinle threaded depsgraph */
+ G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* single threaded depsgraph */
G_DEBUG_GPU = (1 << 12), /* gpu debug */
};
@@ -176,7 +176,7 @@ enum {
#define G_FILE_HISTORY (1 << 25)
/* BMesh option to save as older mesh format */
#define G_FILE_MESH_COMPAT (1 << 26)
-/* On wrote, restore paths after editing them (G_FILE_RELATIVE_REMAP) */
+/* On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */
#define G_FILE_SAVE_COPY (1 << 27)
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY)
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 084c5527f21..24e330d927f 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -47,7 +47,8 @@ void BKE_gpencil_free(struct bGPdata *gpd);
void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
-struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, int setactive);
+struct bGPDframe *gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
+struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPdata *gpencil_data_addnew(const char name[]);
struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
@@ -56,9 +57,29 @@ struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd, bool internal_copy);
void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+/* Stroke and Fill - Alpha Visibility Threshold */
+#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
+
+bool gpencil_layer_is_editable(const struct bGPDlayer *gpl);
+
+/* How gpencil_layer_getframe() should behave when there
+ * is no existing GP-Frame on the frame requested.
+ */
+typedef enum eGP_GetFrame_Mode {
+ /* Use the preceeding gp-frame (i.e. don't add anything) */
+ GP_GETFRAME_USE_PREV = 0,
+
+ /* Add a new empty/blank frame */
+ GP_GETFRAME_ADD_NEW = 1,
+ /* Make a copy of the active frame */
+ GP_GETFRAME_ADD_COPY = 2
+} eGP_GetFrame_Mode;
+
+struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe);
-struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, short addnew);
bool gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index d856e90a340..9056e48cf50 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -41,7 +41,7 @@ struct Object;
struct Scene;
void BKE_group_free(struct Group *group);
-void BKE_group_unlink(struct Group *group);
+void BKE_group_unlink(struct Main *bmain, struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
struct Group *BKE_group_copy(struct Group *group);
bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
diff --git a/source/blender/blenkernel/BKE_idcode.h b/source/blender/blenkernel/BKE_idcode.h
index ebad0d42232..6de0efe2709 100644
--- a/source/blender/blenkernel/BKE_idcode.h
+++ b/source/blender/blenkernel/BKE_idcode.h
@@ -32,15 +32,15 @@
* \ingroup bke
*/
-const char *BKE_idcode_to_name(int code);
-const char *BKE_idcode_to_name_plural(int code);
-const char *BKE_idcode_to_translation_context(int code);
-int BKE_idcode_from_name(const char *name);
-bool BKE_idcode_is_linkable(int code);
-bool BKE_idcode_is_valid(int code);
+const char *BKE_idcode_to_name(short idcode);
+const char *BKE_idcode_to_name_plural(short idcode);
+const char *BKE_idcode_to_translation_context(short idcode);
+short BKE_idcode_from_name(const char *name);
+bool BKE_idcode_is_linkable(short idcode);
+bool BKE_idcode_is_valid(short idcode);
-int BKE_idcode_to_idfilter(const int idcode);
-int BKE_idcode_from_idfilter(const int idfilter);
+int BKE_idcode_to_idfilter(const short idcode);
+short BKE_idcode_from_idfilter(const int idfilter);
/**
* Return an ID code and steps the index forward 1.
@@ -48,6 +48,6 @@ int BKE_idcode_from_idfilter(const int idfilter);
* \param index start as 0.
* \return the code, 0 when all codes have been returned.
*/
-int BKE_idcode_iter_step(int *index);
+short BKE_idcode_iter_step(int *index);
#endif
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 94afc8a16ea..894ccae0dc8 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -67,11 +67,15 @@ void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera,
void BKE_imbuf_stamp_info(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip);
-void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels);
+void BKE_image_stamp_buf(
+ struct Scene *scene, struct Object *camera, const struct StampData *stamp_data_template,
+ unsigned char *rect, float *rectf, int width, int height, int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
-int BKE_imbuf_write_stamp(struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
-void BKE_imbuf_write_prepare(struct ImBuf *ibuf, struct ImageFormatData *imf);
-int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
+int BKE_imbuf_write_stamp(
+ struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, const char *name,
+ const struct ImageFormatData *imf);
+void BKE_imbuf_write_prepare(struct ImBuf *ibuf, const struct ImageFormatData *imf);
+int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageFormatData *imf);
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy);
void BKE_image_path_from_imformat(
char *string, const char *base, const char *relbase, int frame,
@@ -181,7 +185,8 @@ struct Image *BKE_image_load_exists(const char *filepath);
/* adds image, adds ibuf, generates color or pattern */
struct Image *BKE_image_add_generated(
- struct Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
+ struct Main *bmain, unsigned int width, unsigned int height, const char *name,
+ int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d);
/* adds image from imbuf, owns imbuf */
struct Image *BKE_image_add_from_imbuf(struct ImBuf *ibuf, const char *name);
@@ -212,6 +217,8 @@ void BKE_image_multiview_index(struct Image *ima, struct ImageUser *iuser);
/* for multilayer images as well as for render-viewer */
bool BKE_image_is_multilayer(struct Image *ima);
+bool BKE_image_is_multiview(struct Image *ima);
+bool BKE_image_is_stereo(struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
@@ -219,7 +226,7 @@ void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
bool BKE_image_is_openexr(struct Image *ima);
/* for multiple slot render, call this before render */
-void BKE_image_backup_render(struct Scene *scene, struct Image *ima);
+void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot);
/* for singlelayer openexr saving */
bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags);
@@ -252,6 +259,9 @@ bool BKE_image_scale(struct Image *image, int width, int height);
/* check if texture has alpha (depth=32) */
bool BKE_image_has_alpha(struct Image *image);
+/* check if texture has gpu texture code */
+bool BKE_image_has_bindcode(struct Image *ima);
+
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *width, int *height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float size[2]);
void BKE_image_get_aspect(struct Image *image, float *aspx, float *aspy);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index abe12282a1b..1edbb455ca4 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -65,6 +65,8 @@ float *BKE_key_evaluate_object_ex(
float *BKE_key_evaluate_object(
struct Object *ob, int *r_totelem);
+struct Key **BKE_key_from_id_p(struct ID *id);
+struct Key *BKE_key_from_id(struct ID *id);
struct Key **BKE_key_from_object_p(struct Object *ob);
struct Key *BKE_key_from_object(struct Object *ob);
struct KeyBlock *BKE_keyblock_from_object(struct Object *ob);
@@ -101,6 +103,8 @@ void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, st
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+void BKE_keyblock_mesh_calc_normals(
+ struct KeyBlock *kb, struct Mesh *mesh, float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3]);
void BKE_keyblock_update_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
void BKE_keyblock_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index fb2c4da91ea..d830c19651f 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -42,6 +42,7 @@ struct Lamp;
struct Main;
struct Scene;
+void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 07e39684778..51eeb16438e 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -45,6 +45,7 @@ struct BPoint;
struct MDeformVert;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
+void BKE_lattice_init(struct Lattice *lt);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
struct Lattice *BKE_lattice_copy(struct Lattice *lt);
void BKE_lattice_free(struct Lattice *lt);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 5b12858fc7d..21585a160dd 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -49,18 +49,35 @@ struct bContext;
struct PointerRNA;
struct PropertyRNA;
+void *BKE_libblock_alloc_notest(short type);
void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BKE_libblock_init_empty(struct ID *id);
void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL();
void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action);
+void BKE_libblock_relink(struct ID *id);
+void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL();
+void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL();
+
+void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
+void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL();
+void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
+void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
+
+struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id);
void id_lib_extern(struct ID *id);
void BKE_library_filepath_set(struct Library *lib, const char *filepath);
void id_us_ensure_real(struct ID *id);
+void id_us_clear_real(struct ID *id);
+void id_us_plus_no_lib(struct ID *id);
void id_us_plus(struct ID *id);
void id_us_min(struct ID *id);
+void id_fake_user_set(struct ID *id);
+void id_fake_user_clear(struct ID *id);
bool id_make_local(struct ID *id, bool test);
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
@@ -70,18 +87,13 @@ void id_sort_by_name(struct ListBase *lb, struct ID *id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
+void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, bool id_in_mainlist);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 35
+#define MAX_LIBARRAY 34
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
-void BKE_libblock_free(struct Main *bmain, void *idv);
-void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user);
-void BKE_libblock_free_us(struct Main *bmain, void *idv);
-void BKE_libblock_free_data(struct Main *bmain, struct ID *id);
-
-
/* Main API */
struct Main *BKE_main_new(void);
void BKE_main_free(struct Main *mainvar);
@@ -93,34 +105,34 @@ struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct
struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
void BKE_main_thumbnail_create(struct Main *bmain);
-void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const bool tag);
-void BKE_main_id_tag_listbase(struct ListBase *lb, const bool tag);
-void BKE_main_id_tag_all(struct Main *mainvar, const bool tag);
+void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value);
+void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
+void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
-void BKE_main_id_flag_listbase(ListBase *lb, const short flag, const bool value);
-void BKE_main_id_flag_all(struct Main *bmain, const short flag, const bool value);
+void BKE_main_id_flag_listbase(struct ListBase *lb, const int flag, const bool value);
+void BKE_main_id_flag_all(struct Main *bmain, const int flag, const bool value);
void BKE_main_id_clear_newpoins(struct Main *bmain);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
-void rename_id(struct ID *id, const char *name);
-void name_uiprefix_id(char *name, const struct ID *id);
-void test_idbutton(char *name);
+/* (MAX_ID_NAME - 2) + 3 */
+void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
-void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only);
+void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only, bool set_fake);
-struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *);
+typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
+typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *);
-void BKE_library_callback_free_window_manager_set(void (*func)(struct bContext *, struct wmWindowManager *));
-void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *));
-void BKE_library_callback_free_editor_id_reference_set(void (*func)(const struct ID *));
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func);
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
+void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
-#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT))
+#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 50958f8ee80..2e73be576f9 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -38,20 +38,41 @@ enum {
IDWALK_NOP = 0,
IDWALK_NEVER_NULL = (1 << 0),
IDWALK_NEVER_SELF = (1 << 1),
+
+ /**
+ * Adjusts #ID.us reference-count.
+ * \note keep in sync with 'newlibadr_us' use in readfile.c
+ */
+ IDWALK_USER = (1 << 8),
+ /**
+ * Ensure #ID.us is at least 1 on use.
+ */
+ IDWALK_USER_ONE = (1 << 9),
};
-/* Call a callback for each ID link which the given ID uses.
+enum {
+ IDWALK_RET_NOP = 0,
+ IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */
+ IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */
+};
+
+/**
+ * Call a callback for each ID link which the given ID uses.
*
- * Return 'false' if you want to stop iteration.
+ * \return a set of flags to control further iteration (0 to keep going).
*/
-typedef bool (*LibraryIDLinkCallback) (void *user_data, struct ID **id_pointer, int cd_flag);
+typedef int (*LibraryIDLinkCallback) (void *user_data, struct ID *id_self, struct ID **id_pointer, int cd_flag);
/* Flags for the foreach function itself. */
enum {
IDWALK_READONLY = (1 << 0),
+ IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
};
/* Loop over all of the ID's this datablock links to. */
void BKE_library_foreach_ID_link(struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag);
+void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int cd_flag);
+
+int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used);
#endif /* __BKE_LIBRARY_QUERY_H__ */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index e77b4f5e8fe..e3eead4102c 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -49,6 +49,7 @@ struct Object;
struct ColorBand;
struct bContext;
+void BKE_linestyle_init(struct FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 6a00961fbb3..44e4da4e0a3 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -85,7 +85,6 @@ typedef struct Main {
ListBase key;
ListBase world;
ListBase screen;
- ListBase script;
ListBase vfont;
ListBase text;
ListBase speaker;
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index a3c61f44ff2..852564c8d90 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -45,12 +45,13 @@ struct Scene;
/* materials */
void init_def_material(void);
-void BKE_material_free(struct Material *sc);
+void BKE_material_free(struct Material *ma);
void BKE_material_free_ex(struct Material *ma, bool do_id_user);
void test_object_materials(struct Main *bmain, struct ID *id);
void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user);
-void init_material(struct Material *ma);
+void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
+void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
struct Material *BKE_material_copy(struct Material *ma);
struct Material *localize_material(struct Material *ma);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 638a04dac25..401cc2479e9 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -40,6 +40,7 @@ struct MetaElem;
void BKE_mball_unlink(struct MetaBall *mb);
void BKE_mball_free(struct MetaBall *mb);
+void BKE_mball_init(struct MetaBall *mb);
struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
struct MetaBall *BKE_mball_copy(struct MetaBall *mb);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index a27688c1c61..a8f20a4ebc5 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -48,6 +48,7 @@ struct MFace;
struct MEdge;
struct MVert;
struct MDeformVert;
+struct MDisps;
struct Object;
struct CustomData;
struct DerivedMesh;
@@ -82,6 +83,7 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
void BKE_mesh_unlink(struct Mesh *me);
void BKE_mesh_free(struct Mesh *me, int unlink);
+void BKE_mesh_init(struct Mesh *me);
struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name);
struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me);
struct Mesh *BKE_mesh_copy(struct Mesh *me);
@@ -170,7 +172,7 @@ void BKE_mesh_calc_normals_mapping_ex(
const struct MFace *mfaces, int numFaces, const int *origIndexFace, float (*r_faceNors)[3],
const bool only_face_normals);
void BKE_mesh_calc_normals_poly(
- struct MVert *mverts, int numVerts,
+ struct MVert *mverts, float (*r_vertnors)[3], int numVerts,
const struct MLoop *mloop, const struct MPoly *mpolys,
int numLoops, int numPolys, float (*r_polyNors)[3],
const bool only_face_normals);
@@ -316,6 +318,14 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
int *r_totloop, int *r_totpoly,
struct MLoop **r_mloop, struct MPoly **r_mpoly);
+void BKE_mesh_mdisp_flip(struct MDisps *md, const bool use_loop_mdisp_flip);
+
+void BKE_mesh_polygon_flip_ex(
+ struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata,
+ struct MDisps *mdisp, const bool use_loop_mdisp_flip);
+void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
+void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
+
/* flush flags */
void BKE_mesh_flush_hidden_from_verts_ex(
const struct MVert *mvert,
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index c8a17008f5d..d7dd9ed3ac5 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -69,7 +69,7 @@ typedef struct UvElement {
/* general use flag */
unsigned char flag;
/* If generating element map with island sorting, this stores the island index */
- unsigned short island;
+ unsigned int island;
} UvElement;
@@ -90,9 +90,7 @@ typedef struct UvElementMap {
int *islandIndices;
} UvElementMap;
-/* invalid island index is max short. If any one has the patience
- * to make that many islands, he can bite me :p */
-#define INVALID_ISLAND 0xFFFF
+#define INVALID_ISLAND ((unsigned int)-1)
/* Connectivity data */
typedef struct MeshElemMap {
@@ -119,6 +117,9 @@ void BKE_mesh_vert_loop_map_create(
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
+void BKE_mesh_vert_edge_vert_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MEdge *medge, int totvert, int totedge);
void BKE_mesh_edge_poly_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, const int totedge,
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index ded6e13e003..455912ab819 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -104,8 +104,9 @@ typedef enum {
eModifierTypeFlag_UsesPreview = (1 << 9)
} ModifierTypeFlag;
-typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin);
-typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin);
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void (*ObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cd_flag);
+typedef void (*IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cd_flag);
typedef void (*TexWalkFunc)(void *userData, struct Object *ob, struct ModifierData *md, const char *propname);
typedef enum ModifierApplyFlag {
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index 7d7675270de..afca326c727 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -43,6 +43,8 @@ void BKE_movieclip_free(struct MovieClip *clip);
void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip);
struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name);
+struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists);
+struct MovieClip *BKE_movieclip_file_add_exists(struct Main *bmain, const char *name);
void BKE_movieclip_reload(struct MovieClip *clip);
void BKE_movieclip_clear_cache(struct MovieClip *clip);
void BKE_movieclip_clear_proxy_cache(struct MovieClip *clip);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index b97bf203a7c..2ece0f7a028 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -172,7 +172,10 @@ typedef struct bNodeType {
/* Additional drawing on backdrop */
void (*draw_backdrop)(struct SpaceNode *snode, struct ImBuf *backdrop, struct bNode *node, int x, int y);
- /// Optional custom label function for the node header.
+ /**
+ * Optional custom label function for the node header.
+ * \note Used as a fallback when #bNode.label isn't set.
+ */
void (*labelfunc)(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
/// Optional custom resize handle polling.
int (*resize_area_func)(struct bNode *node, int x, int y);
@@ -203,6 +206,8 @@ typedef struct bNodeType {
/* can this node be added to a node tree */
int (*poll_instance)(struct bNode *node, struct bNodeTree *nodetree);
+ /* optional handling of link insertion */
+ void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
/* Update the internal links list, for muting and disconnect operators. */
void (*update_internal_links)(struct bNodeTree *, struct bNode *node);
@@ -217,18 +222,6 @@ typedef struct bNodeType {
ExtensionRNA ext;
} bNodeType;
-/* node->exec, now in use for composites (#define for break is same as ready yes) */
-#define NODE_PROCESSING 1
-#define NODE_READY 2
-#define NODE_BREAK 2
-#define NODE_FINISHED 4
-#define NODE_FREEBUFS 8
-#define NODE_SKIPPED 16
-
-/* sim_exec return value */
-#define NODE_EXEC_FINISHED 0
-#define NODE_EXEC_SUSPEND 1
-
/* nodetype->nclass, for add-menu and themes */
#define NODE_CLASS_INPUT 0
#define NODE_CLASS_OUTPUT 1
@@ -236,22 +229,22 @@ typedef struct bNodeType {
#define NODE_CLASS_OP_VECTOR 4
#define NODE_CLASS_OP_FILTER 5
#define NODE_CLASS_GROUP 6
-#define NODE_CLASS_FILE 7
+// #define NODE_CLASS_FILE 7
#define NODE_CLASS_CONVERTOR 8
#define NODE_CLASS_MATTE 9
#define NODE_CLASS_DISTORT 10
-#define NODE_CLASS_OP_DYNAMIC 11 /* deprecated */
+// #define NODE_CLASS_OP_DYNAMIC 11 /* deprecated */
#define NODE_CLASS_PATTERN 12
#define NODE_CLASS_TEXTURE 13
-#define NODE_CLASS_EXECUTION 14
-#define NODE_CLASS_GETDATA 15
-#define NODE_CLASS_SETDATA 16
-#define NODE_CLASS_MATH 17
-#define NODE_CLASS_MATH_VECTOR 18
-#define NODE_CLASS_MATH_ROTATION 19
-#define NODE_CLASS_PARTICLES 25
-#define NODE_CLASS_TRANSFORM 30
-#define NODE_CLASS_COMBINE 31
+// #define NODE_CLASS_EXECUTION 14
+// #define NODE_CLASS_GETDATA 15
+// #define NODE_CLASS_SETDATA 16
+// #define NODE_CLASS_MATH 17
+// #define NODE_CLASS_MATH_VECTOR 18
+// #define NODE_CLASS_MATH_ROTATION 19
+// #define NODE_CLASS_PARTICLES 25
+// #define NODE_CLASS_TRANSFORM 30
+// #define NODE_CLASS_COMBINE 31
#define NODE_CLASS_SCRIPT 32
#define NODE_CLASS_INTERFACE 33
#define NODE_CLASS_SHADER 40
@@ -337,6 +330,7 @@ struct GHashIterator *ntreeTypeGetIterator(void);
void ntreeSetTypes(const struct bContext *C, struct bNodeTree *ntree);
+void ntreeInitDefault(struct bNodeTree *ntree);
struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname);
/* copy/free funcs, need to manage ID users */
@@ -353,7 +347,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(struct ID *id);
-void ntreeMakeLocal(struct bNodeTree *ntree);
+void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist);
bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
@@ -620,8 +614,8 @@ bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node
#define NODE_UNDEFINED -2 /* node type is not registered */
#define NODE_CUSTOM -1 /* for dynamically registered custom types */
#define NODE_GROUP 2
-#define __NODE_FORLOOP 3 /* deprecated */
-#define __NODE_WHILELOOP 4 /* deprecated */
+// #define NODE_FORLOOP 3 /* deprecated */
+// #define NODE_WHILELOOP 4 /* deprecated */
#define NODE_FRAME 5
#define NODE_REROUTE 6
#define NODE_GROUP_INPUT 7
@@ -798,15 +792,6 @@ struct ShadeResult;
#define SH_NODE_MAT_DIFF 1
#define SH_NODE_MAT_SPEC 2
#define SH_NODE_MAT_NEG 4
-/* custom defines: states for Script node. These are bit indices */
-#define NODE_DYNAMIC_READY 0 /* 1 */
-#define NODE_DYNAMIC_LOADED 1 /* 2 */
-#define NODE_DYNAMIC_NEW 2 /* 4 */
-#define NODE_DYNAMIC_UPDATED 3 /* 8 */
-#define NODE_DYNAMIC_ADDEXIST 4 /* 16 */
-#define NODE_DYNAMIC_ERROR 5 /* 32 */
-#define NODE_DYNAMIC_REPARSE 6 /* 64 */
-#define NODE_DYNAMIC_SET 15 /* sign */
/* API */
@@ -902,7 +887,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_CHANNEL_MATTE 238
#define CMP_NODE_FLIP 239
#define CMP_NODE_SPLITVIEWER 240
-#define CMP_NODE_INDEX_MASK 241
+// #define CMP_NODE_INDEX_MASK 241
#define CMP_NODE_MAP_UV 242
#define CMP_NODE_ID_MASK 243
#define CMP_NODE_DEFOCUS 244
@@ -957,9 +942,6 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
/* channel toggles */
#define CMP_CHAN_RGB 1
#define CMP_CHAN_A 2
-#define CMP_CHAN_R 4
-#define CMP_CHAN_G 8
-#define CMP_CHAN_B 16
/* filter types */
#define CMP_FILT_SOFT 0
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 2df666e0763..062bbde893d 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -79,12 +79,13 @@ void BKE_object_free_modifiers(struct Object *ob);
void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
-void BKE_object_unlink(struct Object *ob);
+void BKE_object_unlink(struct Main *bmain, struct Object *ob);
bool BKE_object_exists_check(struct Object *obtest);
bool BKE_object_is_in_editmode(struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(struct Object *ob);
+void BKE_object_init(struct Object *ob);
struct Object *BKE_object_add_only_object(
struct Main *bmain,
int type, const char *name)
@@ -143,6 +144,7 @@ bool BKE_boundbox_ray_hit_check(
void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]);
void BKE_boundbox_minmax(const struct BoundBox *bb, float obmat[4][4], float r_min[3], float r_max[3]);
+void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale);
struct BoundBox *BKE_boundbox_ensure_minimum_dimensions(
struct BoundBox *bb, struct BoundBox *bb_temp, const float epsilon);
@@ -236,6 +238,7 @@ int BKE_object_is_modified(struct Scene *scene, struct Object *ob);
int BKE_object_is_deform_modified(struct Scene *scene, struct Object *ob);
void BKE_object_relink(struct Object *ob);
+void BKE_object_data_relink(struct Object *ob);
struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default);
@@ -265,6 +268,10 @@ struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
+bool BKE_object_modifier_update_subframe(struct Scene *scene, struct Object *ob, bool update_mesh,
+ int parent_recursion, float frame,
+ int type);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h
index e956815d6f7..a0a885c2a04 100644
--- a/source/blender/blenkernel/BKE_object_deform.h
+++ b/source/blender/blenkernel/BKE_object_deform.h
@@ -68,6 +68,10 @@ bool *BKE_object_defgroup_lock_flags_get(struct Object *ob, const int defbase_to
bool *BKE_object_defgroup_validmap_get(struct Object *ob, const int defbase_tot);
bool *BKE_object_defgroup_selected_get(struct Object *ob, int defbase_tot, int *r_dg_flags_sel_tot);
+void BKE_object_defgroup_mirror_selection(
+ struct Object *ob, int defbase_tot, const bool *selection,
+ bool *dg_flags_sel, int *r_dg_flags_sel_tot);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 9b1b937febf..7a4c7d67040 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -69,11 +69,6 @@ typedef struct OceanCache {
int baked;
} OceanCache;
-
-#define OCEAN_NOT_CACHED 0
-#define OCEAN_CACHING 1
-#define OCEAN_CACHED 2
-
struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index a40a56e7476..169d6cee3a4 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -101,7 +101,7 @@ typedef struct SPHData {
/* Integrator callbacks. This allows different SPH implementations. */
void (*force_cb) (void *sphdata_v, ParticleKey *state, float *force, float *impulse);
- void (*density_cb) (void *rangedata_v, int index, float squared_dist);
+ void (*density_cb) (void *rangedata_v, int index, const float co[3], float squared_dist);
} SPHData;
typedef struct ParticleTexture {
@@ -156,6 +156,9 @@ typedef struct ParticleThreadContext {
float *vg_length, *vg_clump, *vg_kink;
float *vg_rough1, *vg_rough2, *vg_roughe;
float *vg_effector;
+
+ struct CurveMapping *clumpcurve;
+ struct CurveMapping *roughcurve;
} ParticleThreadContext;
typedef struct ParticleTask {
@@ -378,6 +381,11 @@ void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleDa
void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
+/* Callback format for performing operations on ID-pointers for particle systems */
+typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag);
+
+void BKE_particlesystem_id_loop(struct ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata);
+
/* ----------- functions needed only inside particlesystem ------------ */
/* particle.c */
void psys_disable_all(struct Object *ob);
@@ -408,15 +416,15 @@ void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], floa
/* BLI_bvhtree_ray_cast callback */
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
-void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_dmcache,
+void psys_particle_on_dm(struct DerivedMesh *dm_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3]);
/* particle_system.c */
void distribute_particles(struct ParticleSimulationData *sim, int from);
void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
-void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys);
-int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, const float fw[4], struct LinkNode *node);
+void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, struct ParticleSystem *psys);
+int psys_particle_dm_face_lookup(struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, int findex, const float fw[4], struct LinkNode **poly_nodes);
void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 5dc5ebbbd4c..927303f8b3c 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -98,7 +98,7 @@ void BKE_pbvh_raycast(
bool original);
bool BKE_pbvh_node_raycast(
- PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco,
+ PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
const float ray_start[3], const float ray_normal[3],
float *dist);
@@ -210,7 +210,7 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
-void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface);
+void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface);
void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems,
void **gridfaces,
struct DMFlagMat *flagmats, unsigned int **grid_hidden);
@@ -349,6 +349,8 @@ void BKE_pbvh_node_get_bm_orco_data(
PBVHNode *node,
int (**r_orco_tris)[3], int *r_orco_tris_num, float (**r_orco_coords)[3]);
+bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
+
//void BKE_pbvh_node_BB_reset(PBVHNode *node);
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index a3ffad1f66b..8238ea64242 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -94,6 +94,9 @@ struct SmokeModifierData;
struct SoftBody;
struct RigidBodyWorld;
+struct OpenVDBReader;
+struct OpenVDBWriter;
+
/* temp structure for read/write */
typedef struct PTCacheData {
unsigned int index;
@@ -119,13 +122,18 @@ typedef struct PTCacheFile {
#define PTCACHE_VEL_PER_SEC 1
+enum {
+ PTCACHE_FILE_PTCACHE = 0,
+ PTCACHE_FILE_OPENVDB = 1,
+};
+
typedef struct PTCacheID {
struct PTCacheID *next, *prev;
struct Scene *scene;
struct Object *ob;
void *calldata;
- unsigned int type;
+ unsigned int type, file_type;
unsigned int stack_index;
unsigned int flag;
@@ -147,6 +155,11 @@ typedef struct PTCacheID {
/* copies cache cata to point data */
int (*read_stream)(PTCacheFile *pf, void *calldata);
+ /* copies point data to cache data */
+ int (*write_openvdb_stream)(struct OpenVDBWriter *writer, void *calldata);
+ /* copies cache cata to point data */
+ int (*read_openvdb_stream)(struct OpenVDBReader *reader, void *calldata);
+
/* copies custom extradata to cache data */
void (*write_extra_data)(void *calldata, struct PTCacheMem *pm, int cfra);
/* copies custom extradata to cache data */
@@ -177,12 +190,10 @@ typedef struct PTCacheBaker {
int render;
int anim_init;
int quick_step;
- struct PTCacheID *pid;
- int (*break_test)(void *data);
- void *break_data;
- void (*progressbar)(void *data, int num);
- void (*progressend)(void *data);
- void *progresscontext;
+ struct PTCacheID pid;
+
+ void (*update_progress)(void *data, float progress, int *cancel);
+ void *bake_job;
} PTCacheBaker;
/* PTCacheEditKey->flag */
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index 2acfeca233e..70feff17151 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -66,6 +66,8 @@ Report *BKE_reports_last_displayable(ReportList *reports);
bool BKE_reports_contain(ReportList *reports, ReportType level);
+const char *BKE_report_type_str(ReportType type);
+
bool BKE_report_write_file_fp(FILE *fp, ReportList *reports, const char *header);
bool BKE_report_write_file(const char *filepath, ReportList *reports, const char *header);
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index a30ce6cda79..272abc42899 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -53,6 +53,11 @@ struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob);
struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob);
void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc);
+/* Callback format for performing operations on ID-pointers for rigidbody world. */
+typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cd_flag);
+
+void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata);
+
/* -------------- */
/* Setup */
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
index ebdd159b40c..fa448aa97b8 100644
--- a/source/blender/blenkernel/BKE_sca.h
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -73,6 +73,16 @@ void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_u
void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up);
void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up);
+/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */
+typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cd_flag);
+typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cd_flag);
+
+void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata);
+void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata);
+void BKE_sca_actuators_id_loop(struct ListBase *atclist, SCAActuatorIDFunc func, void *userdata);
+
+
const char *sca_state_name_get(Object *ob, short bit);
#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 027bdbbbe58..a4c44b9934e 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -67,6 +67,7 @@ void free_avicodecdata(struct AviCodecData *acd);
void free_qtcodecdata(struct QuicktimeCodecData *acd);
void BKE_scene_free(struct Scene *sce);
+void BKE_scene_init(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
/* base functions */
@@ -134,6 +135,7 @@ float get_render_aosss_error(const struct RenderData *r, float error);
bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
+bool BKE_scene_use_spherical_stereo(struct Scene *scene);
bool BKE_scene_uses_blender_internal(const struct Scene *scene);
bool BKE_scene_uses_blender_game(const struct Scene *scene);
@@ -152,17 +154,17 @@ bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd);
bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv);
bool BKE_scene_multiview_is_render_view_first(const struct RenderData *rd, const char *viewname);
bool BKE_scene_multiview_is_render_view_last(const struct RenderData *rd, const char *viewname);
-size_t BKE_scene_multiview_num_views_get(const struct RenderData *rd);
+int BKE_scene_multiview_num_views_get(const struct RenderData *rd);
struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct RenderData *rd, const int view_id);
const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, const int view_id);
-size_t BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
+int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv, const char *filepath, char *r_filepath);
void BKE_scene_multiview_view_filepath_get(const struct RenderData *rd, const char *filepath, const char *view, char *r_filepath);
const char *BKE_scene_multiview_view_suffix_get(const struct RenderData *rd, const char *viewname);
-const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const size_t view_id);
+const char *BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, const int view_id);
void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char *name, char *rprefix, const char **rext);
void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
-size_t BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
+int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 48616418e67..d05df3470b5 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -35,6 +35,7 @@
struct ARegion;
struct Header;
+struct ID;
struct ListBase;
struct Menu;
struct Panel;
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index f73548373ef..30bb6954019 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -35,6 +35,8 @@ struct EvaluationContext;
struct StripColorBalance;
struct Editing;
struct GSet;
+struct GPUOffScreen;
+struct GPUFX;
struct ImBuf;
struct Main;
struct Mask;
@@ -100,7 +102,13 @@ typedef struct SeqRenderData {
float motion_blur_shutter;
bool skip_cache;
bool is_proxy_render;
- size_t view_id;
+ int view_id;
+
+ /* special case for OpenGL render */
+ struct GPUOffScreen *gpu_offscreen;
+ struct GPUFX *gpu_fx;
+ int gpu_samples;
+ bool gpu_full_samples;
} SeqRenderData;
void BKE_sequencer_new_render_data(
@@ -108,6 +116,8 @@ void BKE_sequencer_new_render_data(
int rectx, int recty, int preview_render_size,
SeqRenderData *r_context);
+int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b);
+
/* Wipe effect */
enum {
DO_SINGLE_WIPE,
@@ -227,6 +237,7 @@ void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, str
void BKE_sequence_free(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_free_anim(struct Sequence *seq);
const char *BKE_sequence_give_name(struct Sequence *seq);
+ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset);
void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_calc_disp(struct Scene *scene, struct Sequence *seq);
void BKE_sequence_reload_new_file(struct Scene *scene, struct Sequence *seq, const bool lock_range);
@@ -304,6 +315,7 @@ void BKE_sequence_tx_set_final_left(struct Sequence *seq, int val);
void BKE_sequence_tx_set_final_right(struct Sequence *seq, int val);
void BKE_sequence_tx_handle_xlimits(struct Sequence *seq, int leftflag, int rightflag);
bool BKE_sequence_tx_test(struct Sequence *seq);
+bool BKE_sequence_tx_fullupdate_test(struct Sequence *seq);
bool BKE_sequence_single_check(struct Sequence *seq);
void BKE_sequence_single_fix(struct Sequence *seq);
bool BKE_sequence_test_overlap(struct ListBase *seqbasep, struct Sequence *test);
@@ -374,6 +386,8 @@ typedef struct SeqLoadInfo {
#define SEQ_LOAD_FRAME_ADVANCE (1 << 1)
#define SEQ_LOAD_MOVIE_SOUND (1 << 2)
#define SEQ_LOAD_SOUND_CACHE (1 << 3)
+#define SEQ_LOAD_SYNC_FPS (1 << 4)
+#define SEQ_LOAD_SOUND_MONO (1 << 5)
/* seq_dupli' flags */
@@ -406,7 +420,11 @@ struct Sequence *BKE_sequencer_add_sound_strip(struct bContext *C, ListBase *seq
struct Sequence *BKE_sequencer_add_movie_strip(struct bContext *C, ListBase *seqbasep, struct SeqLoadInfo *seq_load);
/* view3d draw callback, run when not in background view */
-typedef struct ImBuf *(*SequencerDrawView)(struct Scene *, struct Object *, int, int, unsigned int, int, bool, bool, bool, int, const char *, char[256]);
+typedef struct ImBuf *(*SequencerDrawView)(
+ struct Scene *, struct Object *, int, int,
+ unsigned int, int, bool, bool, bool,
+ int, int, bool, const char *,
+ struct GPUFX *, struct GPUOffScreen *, char[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 070f5c762db..d2ab4f3164c 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -67,6 +67,7 @@ typedef struct ShrinkwrapCalcData {
struct MDeformVert *dvert; //Pointer to mdeform array
int vgroup; //Vertex group num
+ bool invert_vgroup; /* invert vertex group influence */
struct DerivedMesh *target; //mesh we are shrinking to
struct SpaceTransform local2target; //transform to move between local and target space
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
index 07d156cfa02..20366f00df6 100644
--- a/source/blender/blenkernel/BKE_smoke.h
+++ b/source/blender/blenkernel/BKE_smoke.h
@@ -35,7 +35,7 @@
typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, bool for_render);
+struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index e68be701b61..67db2537c8f 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -61,7 +61,9 @@ void BKE_sound_exit(void);
void BKE_sound_force_device(const char *device);
-struct bSound *BKE_sound_new_file(struct Main *main, const char *filename);
+struct bSound *BKE_sound_new_file(struct Main *main, const char *filepath);
+struct bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
+struct bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath);
// XXX unused currently
#if 0
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index 5d93b9844ab..5f30df1d6e3 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -29,7 +29,9 @@
*/
struct Main;
+struct Speaker;
+void BKE_speaker_init(struct Speaker *spk);
void *BKE_speaker_add(struct Main *bmain, const char *name);
struct Speaker *BKE_speaker_copy(struct Speaker *spk);
void BKE_speaker_make_local(struct Speaker *spk);
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 161ab2f2fbd..f52bb2ab9cb 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -140,5 +140,11 @@ typedef struct CCGDerivedMesh {
struct EdgeHash *ehash;
} CCGDerivedMesh;
+#ifdef WITH_OPENSUBDIV
+/* TODO(sergey): Not really ideal place, but we don't currently have better one. */
+void BKE_subsurf_osd_init(void);
+void BKE_subsurf_free_unused_buffers(void);
+void BKE_subsurf_osd_cleanup(void);
#endif
+#endif
diff --git a/source/blender/blenkernel/BKE_suggestions.h b/source/blender/blenkernel/BKE_suggestions.h
index c36a2d61968..9d2aab063ab 100644
--- a/source/blender/blenkernel/BKE_suggestions.h
+++ b/source/blender/blenkernel/BKE_suggestions.h
@@ -54,8 +54,8 @@ struct Text;
typedef struct SuggItem {
struct SuggItem *prev, *next;
- char *name;
char type;
+ char name[0];
} SuggItem;
typedef struct SuggList {
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index a5a59d14c92..b14593f5a56 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -41,9 +41,11 @@ struct Main;
struct Text;
struct TextLine;
+void BKE_text_free_lines (struct Text *text);
void BKE_text_free (struct Text *text);
void txt_set_undostate (int u);
int txt_get_undostate (void);
+void BKE_text_init(struct Text *ta);
struct Text *BKE_text_add (struct Main *bmain, const char *name);
int txt_extended_ascii_as_utf8(char **str);
bool BKE_text_reload(struct Text *text);
@@ -107,6 +109,9 @@ int txt_setcurr_tab_spaces(struct Text *text, int space);
bool txt_cursor_is_line_start(struct Text *text);
bool txt_cursor_is_line_end(struct Text *text);
+int txt_calc_tab_left(struct TextLine *line, int ch);
+int txt_calc_tab_right(struct TextLine *line, int ch);
+
#if 0
void txt_print_undo (struct Text *text);
#endif
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 264bf2bd8fa..2ca88425c29 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -200,6 +200,12 @@ void BKE_tracking_distortion_set_threads(struct MovieDistortion *distortion, int
struct MovieDistortion *BKE_tracking_distortion_copy(struct MovieDistortion *distortion);
struct ImBuf *BKE_tracking_distortion_exec(struct MovieDistortion *distortion, struct MovieTracking *tracking,
struct ImBuf *ibuf, int width, int height, float overscan, bool undistort);
+void BKE_tracking_distortion_distort_v2(struct MovieDistortion *distortion,
+ const float co[2],
+ float r_co[2]);
+void BKE_tracking_distortion_undistort_v2(struct MovieDistortion *distortion,
+ const float co[2],
+ float r_co[2]);
void BKE_tracking_distortion_free(struct MovieDistortion *distortion);
void BKE_tracking_distort_v2(struct MovieTracking *tracking, const float co[2], float r_co[2]);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index 7f4ba6c615e..8d7ab230919 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -38,6 +38,7 @@ struct World;
void BKE_world_free(struct World *sc);
void BKE_world_free_ex(struct World *sc, bool do_id_user);
+void BKE_world_init(struct World *wrld);
struct World *add_world(struct Main *bmian, const char *name);
struct World *BKE_world_copy(struct World *wrld);
struct World *localize_world(struct World *wrld);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 0865efb5ba7..7311f330962 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -46,10 +46,9 @@ set(INC
../../../intern/iksolver/extern
../../../intern/memutil
../../../intern/mikktspace
- ../../../intern/raskter
../../../intern/smoke/extern
../../../intern/atomic
- ../../../extern/libmv
+ ../../../intern/libmv
# XXX - BAD LEVEL CALL WM_api.h
../windowmanager
@@ -413,6 +412,13 @@ if(WITH_PYTHON)
if(WITH_PYTHON_SECURITY)
add_definitions(-DWITH_PYTHON_SECURITY)
endif()
+
+
+ if (PYTHON_EXECUTABLE)
+ get_filename_component(_python_exe_name ${PYTHON_EXECUTABLE} NAME)
+ add_definitions(-DPYTHON_EXECUTABLE_NAME=${_python_exe_name})
+ unset(_python_exe_name)
+ endif()
endif()
if(WITH_MOD_FLUID)
@@ -471,20 +477,6 @@ if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
-if(WITH_LIBMV_WERROR)
- if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
- set_source_files_properties(intern/tracking.c
- intern/tracking_auto.c
- intern/tracking_detect.c
- intern/tracking_plane_tracker.c
- intern/tracking_region_tracker.c
- intern/tracking_solver.c
- intern/tracking_stabilize.c
- intern/tracking_util.c
- PROPERTIES COMPILE_FLAGS -Werror)
- endif()
-endif()
-
if(WITH_FFTW3)
list(APPEND INC_SYS
${FFTW3_INCLUDE_DIRS}
@@ -506,15 +498,18 @@ if(WITH_OPENSUBDIV)
../../../intern/opensubdiv
${OPENSUBDIV_INCLUDE_DIRS}
)
- if(WITH_SUBSURF_WERROR)
- if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
- set_source_files_properties(intern/CCGSubSurf.c
- intern/CCGSubSurf_legacy.c
- intern/CCGSubSurf_opensubdiv.c
- intern/CCGSubSurf_opensubdiv_converter.c
- intern/CCGSubSurf_util.c
- PROPERTIES COMPILE_FLAGS -Werror)
- endif()
+endif()
+
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB)
+ list(APPEND INC
+ ../../../intern/openvdb
+ )
+
+ if(WITH_OPENVDB_BLOSC)
+ add_definitions(
+ -DWITH_OPENVDB_BLOSC
+ )
endif()
endif()
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
deleted file mode 100644
index edb2852d9ac..00000000000
--- a/source/blender/blenkernel/SConscript
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-import os
-
-sources = env.Glob('intern/*.c')
-sources.remove('intern' + os.sep + 'mask_rasterize.c')
-sources.remove('intern' + os.sep + 'mask_evaluate.c')
-sources.remove('intern' + os.sep + 'mask.c')
-
-sources_mask = env.Glob('intern/mask*.c')
-
-incs = [
- '.',
- '#/extern/libmv',
- '#/intern/ffmpeg',
- '#/intern/guardedalloc',
- '#/intern/memutil',
- '#/intern/mikktspace',
- '#/intern/raskter',
- '#/intern/rigidbody',
- '#/extern/bullet2/src',
- env['BF_GLEW_INC'],
- '#/intern/ghost',
- '#/intern/glew-mx',
- '#/intern/elbeem/extern',
- '#/intern/iksolver/extern',
- '#/intern/smoke/extern',
- '#/intern/atomic',
- '../avi',
- '../blenfont',
- '../blenlib',
- '../blenloader',
- '../blentranslation',
- '../bmesh',
- '../depsgraph',
- '../gpu',
- '../ikplugin',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../modifiers',
- '../nodes',
- '../physics',
- '../render/extern/include',
- '../windowmanager',
- env['BF_ZLIB_INC'],
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_SMOKE']:
- defs.append('WITH_SMOKE')
-
-if env['WITH_BF_FRAMESERVER']:
- defs.append('WITH_FRAMESERVER')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ../python'
- defs.append('WITH_PYTHON')
- if env['BF_DEBUG']:
- defs.append('DEBUG')
-
-'''
-if env['WITH_BF_ELTOPO']:
- incs += ' #/extern/eltopo'
- incs += ' #/extern/eltopo/eltopo3d'
- defs.append('WITH_ELTOPO')
-'''
-if env['WITH_BF_QUICKTIME']:
- incs += ' ../quicktime'
-
-if env['WITH_BF_SDL']:
- incs += ' ' + env['BF_SDL_INC']
- defs.append('WITH_SDL')
-
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
-
-if env['WITH_BF_DDS']:
- defs.append('WITH_DDS')
-
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-
-if env['WITH_BF_HDR']:
- defs.append('WITH_HDR')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_JACK']:
- defs.append('WITH_JACK')
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
- incs += ' ' + env['BF_FFMPEG_INC']
-
-if env['WITH_BF_QUICKTIME']:
- defs.append('WITH_QUICKTIME')
- incs += ' ' + env['BF_QUICKTIME_INC']
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-if env['WITH_BF_FLUID']:
- defs.append('WITH_MOD_FLUID')
-
-if env['WITH_BF_OCEANSIM']:
- defs.append('WITH_OCEANSIM')
-
-if env['WITH_BF_LZO']:
- incs += ' #/extern/lzo/minilzo'
- defs.append('WITH_LZO')
-
-if env['WITH_BF_LZMA']:
- incs += ' #/extern/lzma'
- defs.append('WITH_LZMA')
-
-if env['WITH_BF_GAMEENGINE']:
- incs += ' #/extern/recastnavigation'
- defs.append('WITH_GAMEENGINE')
-else:
- sources.remove('intern' + os.sep + 'navmesh_conversion.c')
-
-if env['WITH_BF_LIBMV']:
- defs.append('WITH_LIBMV')
-
-if env['WITH_BF_FFTW3']:
- defs.append('FFTW3=1')
- incs += ' ' + env['BF_FFTW3_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-if env['WITH_BF_OPENSUBDIV']:
- defs.append('WITH_OPENSUBDIV')
- incs += ' #intern/opensubdiv'
- incs += ' ' + env['BF_OPENSUBDIV_INC']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
- incs += ' ../../../intern/utfconv'
-
-if env['WITH_BF_BINRELOC']:
- incs += ' #extern/binreloc/include'
- defs.append('WITH_BINRELOC')
-
-if env['WITH_BF_LEGACY_DEPSGRAPH']:
- defs.append('WITH_LEGACY_DEPSGRAPH')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') )
-else:
- env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player', 'player2'], priority = [166,25,0] )
-
-env.BlenderLib ( libname = 'bf_blenkernel_mask', sources = sources_mask, includes = Split(incs), defines = defs, libtype=['core','player', 'player2'], priority = [200,25,0] )
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
index 0ab633701c1..7b3199efb41 100644
--- a/source/blender/blenkernel/depsgraph_private.h
+++ b/source/blender/blenkernel/depsgraph_private.h
@@ -130,6 +130,7 @@ typedef struct DagForest {
bool is_acyclic;
int time; /* for flushing/tagging, compare with node->lasttime */
bool ugly_hack_sorry; /* prevent type check */
+ bool need_update;
} DagForest;
// queue operations
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 95ddb9d5498..828a6bb16ac 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -334,11 +334,10 @@ void ccgSubSurf_free(CCGSubSurf *ss)
openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
}
if (ss->osd_mesh != NULL) {
- /* TODO(sergey): Make sure free happens form the main thread! */
- openSubdiv_deleteOsdGLMesh(ss->osd_mesh);
+ ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
}
if (ss->osd_vao != 0) {
- glDeleteVertexArrays(1, &ss->osd_vao);
+ ccgSubSurf__delete_vertex_array(ss->osd_vao);
}
if (ss->osd_coarse_coords != NULL) {
MEM_freeN(ss->osd_coarse_coords);
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index e2b42065382..7ec9f329444 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -303,6 +303,16 @@ void ccgSubSurf__sync_legacy(CCGSubSurf *ss);
void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss);
+/* Delayed free routines. Will do actual free if called from
+ * main thread and schedule free for later free otherwise.
+ */
+
+#ifdef WITH_OPENSUBDIV
+void ccgSubSurf__delete_osdGLMesh(struct OpenSubdiv_GLMesh *osd_mesh);
+void ccgSubSurf__delete_vertex_array(unsigned int vao);
+void ccgSubSurf__delete_pending(void);
+#endif
+
/* * CCGSubSurf_opensubdiv_converter.c * */
struct OpenSubdiv_Converter;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
index 6adef1ca729..e9002af19b1 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_legacy.c
@@ -322,15 +322,16 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
}
}
-static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
- CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
- int numEffectedV, int numEffectedE, int numEffectedF, int curLvl)
+static void ccgSubSurf__calcSubdivLevel(
+ CCGSubSurf *ss,
+ CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
+ const int numEffectedV, const int numEffectedE, const int numEffectedF, const int curLvl)
{
- int subdivLevels = ss->subdivLevels;
+ const int subdivLevels = ss->subdivLevels;
+ const int nextLvl = curLvl + 1;
int edgeSize = ccg_edgesize(curLvl);
int gridSize = ccg_gridsize(curLvl);
- int nextLvl = curLvl + 1;
- int ptrIdx, cornerIdx, i;
+ int ptrIdx, i;
int vertDataSize = ss->meshIFC.vertDataSize;
float *q = ss->q, *r = ss->r;
@@ -524,7 +525,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
VertDataAdd(nCo, r, ss);
}
else {
- int cornerIdx = (1 + (1 << (curLvl))) - 2;
+ const int cornerIdx = (1 + (1 << (curLvl))) - 2;
int numEdges = 0, numFaces = 0;
VertDataZero(q, ss);
@@ -683,12 +684,12 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
#pragma omp parallel private(ptrIdx) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
{
- float *q, *r;
+ float *q_thread, *r_thread;
#pragma omp critical
{
- q = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q");
- r = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r");
+ q_thread = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf q");
+ r_thread = MEM_mallocN(ss->meshIFC.vertDataSize, "CCGSubsurf r");
}
#pragma omp for schedule(static)
@@ -701,20 +702,20 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
* - old interior edge points
* - new interior face midpoints
*/
- VertDataZero(q, ss);
+ VertDataZero(q_thread, ss);
for (S = 0; S < f->numVerts; S++) {
- VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
+ VertDataAdd(q_thread, FACE_getIFCo(f, nextLvl, S, 1, 1), ss);
}
- VertDataMulN(q, 1.0f / f->numVerts, ss);
- VertDataZero(r, ss);
+ VertDataMulN(q_thread, 1.0f / f->numVerts, ss);
+ VertDataZero(r_thread, ss);
for (S = 0; S < f->numVerts; S++) {
- VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1), ss);
+ VertDataAdd(r_thread, FACE_getIECo(f, curLvl, S, 1), ss);
}
- VertDataMulN(r, 1.0f / f->numVerts, ss);
+ VertDataMulN(r_thread, 1.0f / f->numVerts, ss);
VertDataMulN((float *)FACE_getCenterData(f), f->numVerts - 2.0f, ss);
- VertDataAdd((float *)FACE_getCenterData(f), q, ss);
- VertDataAdd((float *)FACE_getCenterData(f), r, ss);
+ VertDataAdd((float *)FACE_getCenterData(f), q_thread, ss);
+ VertDataAdd((float *)FACE_getCenterData(f), r_thread, ss);
VertDataMulN((float *)FACE_getCenterData(f), 1.0f / f->numVerts, ss);
for (S = 0; S < f->numVerts; S++) {
@@ -730,14 +731,14 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
const float *co = FACE_getIFCo(f, curLvl, S, x, y);
float *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
- VertDataAvg4(q,
+ VertDataAvg4(q_thread,
FACE_getIFCo(f, nextLvl, S, fx - 1, fy - 1),
FACE_getIFCo(f, nextLvl, S, fx + 1, fy - 1),
FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 1),
FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 1),
ss);
- VertDataAvg4(r,
+ VertDataAvg4(r_thread,
FACE_getIFCo(f, nextLvl, S, fx - 1, fy + 0),
FACE_getIFCo(f, nextLvl, S, fx + 1, fy + 0),
FACE_getIFCo(f, nextLvl, S, fx + 0, fy - 1),
@@ -745,9 +746,9 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
ss);
VertDataCopy(nCo, co, ss);
- VertDataSub(nCo, q, ss);
+ VertDataSub(nCo, q_thread, ss);
VertDataMulN(nCo, 0.25f, ss);
- VertDataAdd(nCo, r, ss);
+ VertDataAdd(nCo, r_thread, ss);
}
}
@@ -761,13 +762,13 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
const float *co = FACE_getIECo(f, curLvl, S, x);
float *nCo = FACE_getIECo(f, nextLvl, S, fx);
- VertDataAvg4(q,
+ VertDataAvg4(q_thread,
FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx - 1),
FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx + 1),
FACE_getIFCo(f, nextLvl, S, fx + 1, +1),
FACE_getIFCo(f, nextLvl, S, fx - 1, +1), ss);
- VertDataAvg4(r,
+ VertDataAvg4(r_thread,
FACE_getIECo(f, nextLvl, S, fx - 1),
FACE_getIECo(f, nextLvl, S, fx + 1),
FACE_getIFCo(f, nextLvl, (S + 1) % f->numVerts, 1, fx),
@@ -775,24 +776,24 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
ss);
VertDataCopy(nCo, co, ss);
- VertDataSub(nCo, q, ss);
+ VertDataSub(nCo, q_thread, ss);
VertDataMulN(nCo, 0.25f, ss);
- VertDataAdd(nCo, r, ss);
+ VertDataAdd(nCo, r_thread, ss);
}
}
}
#pragma omp critical
{
- MEM_freeN(q);
- MEM_freeN(r);
+ MEM_freeN(q_thread);
+ MEM_freeN(r_thread);
}
}
/* copy down */
edgeSize = ccg_edgesize(nextLvl);
gridSize = ccg_gridsize(nextLvl);
- cornerIdx = gridSize - 1;
+ const int cornerIdx = gridSize - 1;
#pragma omp parallel for private(i) if (numEffectedF * edgeSize * edgeSize * 4 >= CCG_OMP_LIMIT)
for (i = 0; i < numEffectedE; i++) {
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 006cebf4573..2bb55c2d1ed 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -28,12 +28,15 @@
#include "BLI_sys_types.h" // for intptr_t support
#include "BLI_utildefines.h" /* for BLI_assert */
+#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_threads.h"
#include "CCGSubSurf.h"
#include "CCGSubSurf_intern.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_subsurf.h"
#include "DNA_userdef_types.h"
@@ -41,6 +44,7 @@
#include "opensubdiv_converter_capi.h"
#include "GL/glew.h"
+#include "GPU_extensions.h"
#define OSD_LOG if (false) printf
@@ -236,7 +240,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
if (ss->osd_mesh_invalid) {
if (ss->osd_mesh != NULL) {
- openSubdiv_deleteOsdGLMesh(ss->osd_mesh);
+ ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
ss->osd_mesh = NULL;
}
ss->osd_mesh_invalid = false;
@@ -314,9 +318,12 @@ int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
if (ss->osd_topology_refiner != NULL) {
topology_refiner = ss->osd_topology_refiner;
}
- else {
+ else if (ss->osd_mesh != NULL) {
topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
}
+ else {
+ return 0;
+ }
return openSubdiv_topologyRefinerGetNumFaces(topology_refiner);
}
@@ -327,9 +334,12 @@ int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
if (ss->osd_topology_refiner != NULL) {
topology_refiner = ss->osd_topology_refiner;
}
- else {
+ else if (ss->osd_mesh != NULL) {
topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
}
+ else {
+ return 0;
+ }
return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face);
}
@@ -891,8 +901,7 @@ void ccgSubSurf__sync_opensubdiv(CCGSubSurf *ss)
void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss)
{
if (ss->osd_mesh != NULL) {
- /* TODO(sergey): Make sure free happens form the main thread! */
- openSubdiv_deleteOsdGLMesh(ss->osd_mesh);
+ ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
ss->osd_mesh = NULL;
}
if (ss->osd_vao != 0) {
@@ -905,10 +914,94 @@ void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3])
{
int i;
BLI_assert(ss->skip_grids == true);
+ if (ss->osd_num_coarse_coords == 0) {
+ zero_v3(r_min);
+ zero_v3(r_max);
+ }
for (i = 0; i < ss->osd_num_coarse_coords; i++) {
/* Coarse coordinates has normals interleaved into the array. */
DO_MINMAX(ss->osd_coarse_coords[2 * i], r_min, r_max);
}
}
+/* ** Delayed delete routines ** */
+
+typedef struct OsdDeletePendingItem {
+ struct OsdDeletePendingItem *next, *prev;
+ OpenSubdiv_GLMesh *osd_mesh;
+ unsigned int vao;
+} OsdDeletePendingItem;
+
+static SpinLock delete_spin;
+static ListBase delete_pool = {NULL, NULL};
+
+static void delete_pending_push(OpenSubdiv_GLMesh *osd_mesh,
+ unsigned int vao)
+{
+ OsdDeletePendingItem *new_entry = MEM_mallocN(sizeof(OsdDeletePendingItem),
+ "opensubdiv delete entry");
+ new_entry->osd_mesh = osd_mesh;
+ new_entry->vao = vao;
+ BLI_spin_lock(&delete_spin);
+ BLI_addtail(&delete_pool, new_entry);
+ BLI_spin_unlock(&delete_spin);
+}
+
+void ccgSubSurf__delete_osdGLMesh(OpenSubdiv_GLMesh *osd_mesh)
+{
+ if (BLI_thread_is_main()) {
+ openSubdiv_deleteOsdGLMesh(osd_mesh);
+ }
+ else {
+ delete_pending_push(osd_mesh, 0);
+ }
+}
+
+void ccgSubSurf__delete_vertex_array(unsigned int vao)
+{
+ if (BLI_thread_is_main()) {
+ glDeleteVertexArrays(1, &vao);
+ }
+ else {
+ delete_pending_push(NULL, vao);
+ }
+}
+
+void ccgSubSurf__delete_pending(void)
+{
+ OsdDeletePendingItem *entry;
+ BLI_assert(BLI_thread_is_main());
+ BLI_spin_lock(&delete_spin);
+ for (entry = delete_pool.first; entry != NULL; entry = entry->next) {
+ if (entry->osd_mesh != NULL) {
+ openSubdiv_deleteOsdGLMesh(entry->osd_mesh);
+ }
+ if (entry->vao != 0) {
+ glDeleteVertexArrays(1, &entry->vao);
+ }
+ }
+ BLI_freelistN(&delete_pool);
+ BLI_spin_unlock(&delete_spin);
+}
+
+/* ** Public API ** */
+
+void BKE_subsurf_osd_init(void)
+{
+ openSubdiv_init(GPU_legacy_support());
+ BLI_spin_init(&delete_spin);
+}
+
+void BKE_subsurf_free_unused_buffers(void)
+{
+ ccgSubSurf__delete_pending();
+}
+
+void BKE_subsurf_osd_cleanup(void)
+{
+ openSubdiv_cleanup();
+ ccgSubSurf__delete_pending();
+ BLI_spin_end(&delete_spin);
+}
+
#endif /* WITH_OPENSUBDIV */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 65de8da941b..411d6ee4452 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -43,6 +43,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_array.h"
#include "BLI_blenlib.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
@@ -53,6 +54,7 @@
#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
+#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
@@ -74,8 +76,8 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "BLI_sys_types.h" /* for intptr_t support */
#include "GPU_buffers.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
+#include "GPU_shader.h"
#ifdef WITH_OPENSUBDIV
# include "DNA_userdef_types.h"
@@ -329,21 +331,17 @@ void DM_init(
* Utility function to initialize a DerivedMesh for the desired number
* of vertices, edges and faces, with a layer setup copied from source
*/
-void DM_from_template(
+void DM_from_template_ex(
DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
int numVerts, int numEdges, int numTessFaces,
- int numLoops, int numPolys)
+ int numLoops, int numPolys,
+ CustomDataMask mask)
{
- CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, numVerts);
- CustomData_copy(&source->edgeData, &dm->edgeData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, numEdges);
- CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, numTessFaces);
- CustomData_copy(&source->loopData, &dm->loopData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, numLoops);
- CustomData_copy(&source->polyData, &dm->polyData, CD_MASK_DERIVEDMESH,
- CD_CALLOC, numPolys);
+ CustomData_copy(&source->vertData, &dm->vertData, mask, CD_CALLOC, numVerts);
+ CustomData_copy(&source->edgeData, &dm->edgeData, mask, CD_CALLOC, numEdges);
+ CustomData_copy(&source->faceData, &dm->faceData, mask, CD_CALLOC, numTessFaces);
+ CustomData_copy(&source->loopData, &dm->loopData, mask, CD_CALLOC, numLoops);
+ CustomData_copy(&source->polyData, &dm->polyData, mask, CD_CALLOC, numPolys);
dm->cd_flag = source->cd_flag;
@@ -359,6 +357,17 @@ void DM_from_template(
dm->needsFree = 1;
dm->dirty = 0;
}
+void DM_from_template(
+ DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
+ int numVerts, int numEdges, int numTessFaces,
+ int numLoops, int numPolys)
+{
+ DM_from_template_ex(
+ dm, source, type,
+ numVerts, numEdges, numTessFaces,
+ numLoops, numPolys,
+ CD_MASK_DERIVEDMESH);
+}
int DM_release(DerivedMesh *dm)
{
@@ -557,8 +566,8 @@ void DM_update_tessface_data(DerivedMesh *dm)
}
}
- /* NOTE: quad detection issue - forth vertidx vs forth loopidx:
- * Here, our tfaces' forth vertex index is never 0 for a quad. However, we know our forth loop index may be
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
* 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
* So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
*/
@@ -575,7 +584,6 @@ void DM_update_tessface_data(DerivedMesh *dm)
void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
{
- int i;
MFace *mf, *mface = dm->getTessFaceArray(dm);
MPoly *mp = dm->getPolyArray(dm);
MLoop *ml = dm->getLoopArray(dm);
@@ -595,9 +603,10 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
return;
if (generate) {
- for (i = 0; i < ldata->totlayer; i++) {
- if (ldata->layers[i].type == CD_TANGENT)
+ for (int i = 0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_TANGENT) {
CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[i].name);
+ }
}
CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
}
@@ -622,8 +631,8 @@ void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
}
}
- /* NOTE: quad detection issue - forth vertidx vs forth loopidx:
- * Here, our tfaces' forth vertex index is never 0 for a quad. However, we know our forth loop index may be
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
* 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
* So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
*/
@@ -791,18 +800,21 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
/* ok, this should now use new CD shapekey data,
* which should be fed through the modifier
- * stack*/
+ * stack */
if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
- if (tmp.key) tmp.key->id.us--;
+ if (tmp.key)
+ id_us_min(&tmp.key->id);
tmp.key = NULL;
}
/* Clear selection history */
- tmp.mselect = NULL;
+ MEM_SAFE_FREE(tmp.mselect);
tmp.totselect = 0;
- if (me->mselect) {
- MEM_freeN(me->mselect);
+ BLI_assert(ELEM(tmp.bb, NULL, me->bb));
+ if (me->bb) {
+ MEM_freeN(me->bb);
+ tmp.bb = NULL;
}
/* skip the listbase */
@@ -1071,7 +1083,7 @@ void DM_interp_tessface_data(
void DM_swap_tessface_data(DerivedMesh *dm, int index, const int *corner_indices)
{
- CustomData_swap(&dm->faceData, index, corner_indices);
+ CustomData_swap_corners(&dm->faceData, index, corner_indices);
}
void DM_interp_loop_data(
@@ -1313,7 +1325,8 @@ enum {
CALC_WP_GROUP_USER_ALL = (1 << 2),
CALC_WP_MULTIPAINT = (1 << 3),
- CALC_WP_AUTO_NORMALIZE = (1 << 4)
+ CALC_WP_AUTO_NORMALIZE = (1 << 4),
+ CALC_WP_MIRROR_X = (1 << 5),
};
typedef struct DMWeightColorInfo {
@@ -1322,12 +1335,13 @@ typedef struct DMWeightColorInfo {
} DMWeightColorInfo;
-static int dm_drawflag_calc(const ToolSettings *ts)
+static int dm_drawflag_calc(const ToolSettings *ts, const Mesh *me)
{
- return ((ts->multipaint ? CALC_WP_MULTIPAINT :
- /* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL*/
- (1 << ts->weightuser)) |
- (ts->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0));
+ return ((ts->multipaint ? CALC_WP_MULTIPAINT : 0) |
+ /* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL */
+ (1 << ts->weightuser) |
+ (ts->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0) |
+ ((me->editflag & ME_EDIT_MIRROR_X) ? CALC_WP_MIRROR_X : 0));
}
static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcinfo, const float input)
@@ -1364,30 +1378,13 @@ static void calc_weightpaint_vert_color(
if ((defbase_sel_tot > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
/* Multi-Paint feature */
- bool was_a_nonzero = false;
- unsigned int i;
-
- const MDeformWeight *dw = dv->dw;
- for (i = dv->totweight; i != 0; i--, dw++) {
- /* in multipaint, get the average if auto normalize is inactive
- * get the sum if it is active */
- if (dw->def_nr < defbase_tot) {
- if (defbase_sel[dw->def_nr]) {
- if (dw->weight) {
- input += dw->weight;
- was_a_nonzero = true;
- }
- }
- }
- }
+ input = BKE_defvert_multipaint_collective_weight(
+ dv, defbase_tot, defbase_sel, defbase_sel_tot, (draw_flag & CALC_WP_AUTO_NORMALIZE) != 0);
/* make it black if the selected groups have no weight on a vertex */
- if (was_a_nonzero == false) {
+ if (input == 0.0f) {
show_alert_color = true;
}
- else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == false) {
- input /= defbase_sel_tot; /* get the average */
- }
}
else {
/* default, non tricky behavior */
@@ -1437,7 +1434,7 @@ static void calc_weightpaint_vert_array(
MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
int numVerts = dm->getNumVerts(dm);
- if (dv) {
+ if (dv && (ob->actdef != 0)) {
unsigned char (*wc)[4] = r_wtcol_v;
unsigned int i;
@@ -1450,6 +1447,10 @@ static void calc_weightpaint_vert_array(
if (draw_flag & CALC_WP_MULTIPAINT) {
defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_sel_tot);
+
+ if (defbase_sel_tot > 1 && (draw_flag & CALC_WP_MIRROR_X)) {
+ BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_sel_tot);
+ }
}
for (i = numVerts; i != 0; i--, wc++, dv++) {
@@ -1462,7 +1463,11 @@ static void calc_weightpaint_vert_array(
}
else {
unsigned char col[4];
- if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) {
+ if ((ob->actdef == 0) && !BLI_listbase_is_empty(&ob->defbase)) {
+ /* color-code for missing data (full brightness isn't easy on the eye). */
+ ARRAY_SET_ITEMS(col, 0xa0, 0, 0xa0, 0xff);
+ }
+ else if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) {
copy_v3_v3_char((char *)col, dm_wcinfo->alert_color);
col[3] = 255;
}
@@ -1543,8 +1548,8 @@ void DM_update_weight_mcol(
int l_index;
int j;
- /* now add to loops, so the data can be passed through the modifier stack */
- /* If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
+ /* now add to loops, so the data can be passed through the modifier stack
+ * If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
if (!wtcol_l) {
wtcol_l = MEM_mallocN(sizeof(*wtcol_l) * dm_totloop, __func__);
CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, dm_totloop);
@@ -1555,8 +1560,8 @@ void DM_update_weight_mcol(
ml = mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++, l_index++) {
- copy_v4_v4_char((char *)&wtcol_l[l_index],
- (char *)&wtcol_v[ml->v]);
+ copy_v4_v4_uchar(&wtcol_l[l_index][0],
+ &wtcol_v[ml->v][0]);
}
}
MEM_freeN(wtcol_v);
@@ -1747,7 +1752,7 @@ static void mesh_init_modifier_context(ModifierEvalContext *ctx,
ctx->deform_app_flags = ctx->app_flags
| (useDeform ? MOD_APPLY_USECACHE : 0);
- ctx->draw_flag = dm_drawflag_calc(scene->toolsettings);
+ ctx->draw_flag = dm_drawflag_calc(scene->toolsettings, me);
ctx->required_mode = useRenderParams ? eModifierMode_Render : eModifierMode_Realtime;
ctx->need_mapping = need_mapping;
@@ -1995,11 +2000,11 @@ static DerivedMesh *mesh_calc_create_input_dm(Object *ob, const ModifierEvalCont
}
/* set the DerivedMesh to only copy needed data */
- /* needMapping check here fixes bug [#28112], otherwise its
- * possible that it wont be copied */
+ /* needMapping check here fixes bug [#28112], otherwise it's
+ * possible that it won't be copied */
DM_set_only_copy(dm, mask | append_mask | (ctx->need_mapping ? CD_MASK_ORIGINDEX : 0));
- /* add cloth rest shape key if need */
+ /* add cloth rest shape key if needed */
if ((mask | append_mask) & CD_MASK_CLOTH_ORCO)
add_orco_dm(ob, NULL, dm, clothorcodm, CD_CLOTH_ORCO);
@@ -2394,7 +2399,7 @@ static void editbmesh_calc_modifiers(
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
CDMaskLink *datamasks, *curr;
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- int draw_flag = dm_drawflag_calc(scene->toolsettings);
+ int draw_flag = dm_drawflag_calc(scene->toolsettings, ob->data);
// const bool do_mod_mcol = true; // (ob->mode == OB_MODE_OBJECT);
#if 0 /* XXX Will re-enable this when we have global mod stack options. */
@@ -2753,13 +2758,13 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *
{
Object *actob = scene->basact ? scene->basact->object : NULL;
CustomDataMask mask = ob->customdata_mask;
- bool editing = BKE_paint_select_face_test(ob);
if (r_need_mapping) {
*r_need_mapping = false;
}
if (ob == actob) {
+ bool editing = BKE_paint_select_face_test(ob);
/* weight paint and face select need original indices because of selection buffer drawing */
if (r_need_mapping) {
@@ -3154,6 +3159,12 @@ void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int
/* ******************* GLSL ******************** */
+/** \name Tangent Space Calculation
+ * \{ */
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
typedef struct {
float (*precomputedFaceNormals)[3];
float (*precomputedLoopNormals)[3];
@@ -3166,83 +3177,212 @@ typedef struct {
float (*tangent)[4]; /* destination */
int numTessFaces;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
} SGLSLMeshToTangent;
/* interface */
#include "mikktspace.h"
-static int GetNumFaces(const SMikkTSpaceContext *pContext)
+static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
{
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
return pMesh->numTessFaces;
+#endif
}
-static int GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
{
- //SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
UNUSED_VARS(pContext, face_num);
return 3;
+#endif
}
-static void GetPosition(const SMikkTSpaceContext *pContext, float r_co[3], const int face_num, const int vert_index)
+static void dm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
{
//assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt = &pMesh->looptri[face_num];
- const float *co = pMesh->mvert[pMesh->mloop[lt->tri[vert_index]].v].co;
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ int loop_index;
+ const float *co;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = mp->loopstart + vert_index;
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
copy_v3_v3(r_co, co);
}
-static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float r_uv[2], const int face_num, const int vert_index)
+static void dm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
{
//assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt = &pMesh->looptri[face_num];
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ int loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = mp->loopstart + vert_index;
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+finally:
if (pMesh->mloopuv != NULL) {
- const float *uv = pMesh->mloopuv[lt->tri[vert_index]].uv;
+ const float *uv = pMesh->mloopuv[loop_index].uv;
copy_v2_v2(r_uv, uv);
}
else {
- const float *orco = pMesh->orco[pMesh->mloop[lt->tri[vert_index]].v];
+ const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
}
}
-static void GetNormal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_num, const int vert_index)
+static void dm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
{
//assert(vert_index >= 0 && vert_index < 4);
SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt = &pMesh->looptri[face_num];
- const bool smoothnormal = (pMesh->mpoly[lt->poly].flag & ME_SMOOTH) != 0;
+ const MLoopTri *lt;
+ int loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = mp->loopstart + vert_index;
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+finally:
if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[lt->tri[vert_index]]);
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
}
- else if (!smoothnormal) { // flat
+ else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
if (pMesh->precomputedFaceNormals) {
copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
}
else {
- const float *p0 = pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co;
- const float *p1 = pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co;
- const float *p2 = pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co;
-
- normal_tri_v3(r_no, p0, p1, p2);
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ normal_quad_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
+ }
+ else
+#endif
+ {
+ normal_tri_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
+ }
}
}
else {
- const short *no = pMesh->mvert[pMesh->mloop[lt->tri[0]].v].no;
+ const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
normal_short_to_float_v3(r_no, no);
}
}
-static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign, const int face_num, const int vert_index)
+static void dm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
{
//assert(vert_index >= 0 && vert_index < 4);
SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt = &pMesh->looptri[face_num];
- float *pRes = pMesh->tangent[lt->tri[vert_index]];
+ const MLoopTri *lt;
+ int loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = mp->loopstart + vert_index;
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[loop_index];
copy_v3_v3(pRes, fvTangent);
pRes[3] = fSign;
}
@@ -3289,6 +3429,31 @@ void DM_calc_loop_tangents(DerivedMesh *dm)
DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (totface != dm->getNumPolys(dm)) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (mpoly[looptri[j].poly].totloop == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
+#endif
+
/* new computation method */
{
SGLSLMeshToTangent mesh2tangent = {NULL};
@@ -3306,20 +3471,35 @@ void DM_calc_loop_tangents(DerivedMesh *dm)
mesh2tangent.tangent = tangent;
mesh2tangent.numTessFaces = totface;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent.face_as_quad_map = face_as_quad_map;
+ mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
+#endif
+
sContext.m_pUserData = &mesh2tangent;
sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = GetNumFaces;
- sInterface.m_getNumVerticesOfFace = GetNumVertsOfFace;
- sInterface.m_getPosition = GetPosition;
- sInterface.m_getTexCoord = GetTextureCoordinate;
- sInterface.m_getNormal = GetNormal;
- sInterface.m_setTSpaceBasic = SetTSpace;
+ sInterface.m_getNumFaces = dm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dm_ts_GetPosition;
+ sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
/* 0 if failed */
genTangSpaceDefault(&sContext);
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+#endif
}
}
+/** \} */
+
+
void DM_calc_auto_bump_scale(DerivedMesh *dm)
{
/* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
@@ -3599,7 +3779,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
if (attribs->orco.gl_texco)
glTexCoord3fv(orco);
else
- glVertexAttrib3fvARB(attribs->orco.gl_index, orco);
+ glVertexAttrib3fv(attribs->orco.gl_index, orco);
}
/* uv texture coordinates */
@@ -3617,7 +3797,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
if (attribs->tface[b].gl_texco)
glTexCoord2fv(uv);
else
- glVertexAttrib2fvARB(attribs->tface[b].gl_index, uv);
+ glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
}
/* vertex colors */
@@ -3626,20 +3806,20 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
if (attribs->mcol[b].array) {
const MLoopCol *cp = &attribs->mcol[b].array[loop];
- copy_v4_v4_char((char *)col, &cp->r);
+ copy_v4_v4_uchar(col, &cp->r);
}
else {
col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
}
- glVertexAttrib4ubvARB(attribs->mcol[b].gl_index, col);
+ glVertexAttrib4ubv(attribs->mcol[b].gl_index, col);
}
/* tangent for normal mapping */
if (attribs->tottang) {
/*const*/ float (*array)[4] = attribs->tang.array;
const float *tang = (array) ? array[loop] : zero;
- glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
+ glVertexAttrib4fv(attribs->tang.gl_index, tang);
}
}
@@ -3655,6 +3835,8 @@ void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
BKE_boundbox_init_from_minmax(ob->bb, min, max);
+
+ ob->bb->flag &= ~BOUNDBOX_DIRTY;
}
/* --- NAVMESH (begin) --- */
@@ -3697,14 +3879,10 @@ static void navmesh_drawColored(DerivedMesh *dm)
#if 0
//UI_ThemeColor(TH_WIRE);
- glDisable(GL_LIGHTING);
glLineWidth(2.0);
dm->drawEdges(dm, 0, 1);
- glLineWidth(1.0);
- glEnable(GL_LIGHTING);
#endif
- glDisable(GL_LIGHTING);
/* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
{
DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
@@ -3734,7 +3912,6 @@ static void navmesh_drawColored(DerivedMesh *dm)
}
glEnd();
}
- glEnable(GL_LIGHTING);
}
static void navmesh_DM_drawFacesTex(
@@ -3840,26 +4017,73 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
void DM_init_origspace(DerivedMesh *dm)
{
- static float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
+ const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
- OrigSpaceLoop *lof;
const int numpoly = dm->getNumPolys(dm);
// const int numloop = dm->getNumLoops(dm);
+ MVert *mv = dm->getVertArray(dm);
+ MLoop *ml = dm->getLoopArray(dm);
MPoly *mp = dm->getPolyArray(dm);
- int i, j;
+ int i, j, k;
+
+ float (*vcos_2d)[2] = NULL;
+ BLI_array_staticdeclare(vcos_2d, 64);
for (i = 0; i < numpoly; i++, mp++) {
- /* only quads/tri's for now */
+ OrigSpaceLoop *lof = lof_array + mp->loopstart;
+
if (mp->totloop == 3 || mp->totloop == 4) {
- lof = lof_array + mp->loopstart;
for (j = 0; j < mp->totloop; j++, lof++) {
copy_v2_v2(lof->uv, default_osf[j]);
}
}
+ else {
+ MLoop *l = &ml[mp->loopstart];
+ float p_nor[3], co[3];
+ float mat[3][3];
+
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {FLT_MIN, FLT_MIN};
+ float translate[2], scale[2];
+
+ BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
+ axis_dominant_v3_to_m3(mat, p_nor);
+
+ BLI_array_empty(vcos_2d);
+ BLI_array_reserve(vcos_2d, mp->totloop);
+ for (j = 0; j < mp->totloop; j++, l++) {
+ mul_v3_m3v3(co, mat, mv[l->v].co);
+ copy_v2_v2(vcos_2d[j], co);
+
+ for (k = 0; k < 2; k++) {
+ if (co[k] > max[k])
+ max[k] = co[k];
+ else if (co[k] < min[k])
+ min[k] = co[k];
+ }
+ }
+
+ /* Brings min to (0, 0). */
+ negate_v2_v2(translate, min);
+
+ /* Scale will bring max to (1, 1). */
+ sub_v2_v2v2(scale, max, min);
+ if (scale[0] == 0.0f)
+ scale[0] = 1e-9f;
+ if (scale[1] == 0.0f)
+ scale[1] = 1e-9f;
+ invert_v2(scale);
+
+ /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assing them as origspace. */
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ add_v2_v2v2(lof->uv, vcos_2d[j], translate);
+ mul_v2_v2(lof->uv, scale);
+ }
+ }
}
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BLI_array_free(vcos_2d);
}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 5b1a6ea7a51..3e1cf6a74a4 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -485,6 +485,9 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel");
BLI_strncpy(chan->name, name, sizeof(chan->name));
+
+ chan->custom_scale = 1.0f;
+
/* init vars to prevent math errors */
unit_qt(chan->quat);
unit_axis_angle(chan->rotAxis, &chan->rotAngle);
@@ -919,6 +922,8 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
if (pchan->custom) {
id_us_plus(&pchan->custom->id);
}
+
+ pchan->custom_scale = pchan_from->custom_scale;
}
diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c
index 811461b84c1..0ef12397fe7 100644
--- a/source/blender/blenkernel/intern/addon.c
+++ b/source/blender/blenkernel/intern/addon.c
@@ -53,7 +53,7 @@ bAddonPrefType *BKE_addon_pref_type_find(const char *idname, bool quiet)
}
else {
if (!quiet) {
- printf("search for empty addon-pref");
+ printf("search for empty addon-pref\n");
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 8010d3450cb..41950c59a22 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -229,10 +229,10 @@ void BKE_animdata_free(ID *id)
if (adt) {
/* unlink action (don't free, as it's in its own list) */
if (adt->action)
- adt->action->id.us--;
+ id_us_min(&adt->action->id);
/* same goes for the temporarily displaced action */
if (adt->tmpact)
- adt->tmpact->id.us--;
+ id_us_min(&adt->tmpact->id);
/* free nla data */
free_nladata(&adt->nla_tracks);
@@ -1596,8 +1596,8 @@ static bool animsys_write_rna_setting(PointerRNA *ptr, char *path, int array_ind
/* for cases like duplifarmes it's only a temporary so don't
* notify anyone of updates */
- if (!(id->flag & LIB_ANIM_NO_RECALC)) {
- id->flag |= LIB_ID_RECALC;
+ if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
+ id->tag |= LIB_TAG_ID_RECALC;
DAG_id_type_tag(G.main, GS(id->name));
}
}
@@ -2562,8 +2562,8 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
*/
if (ptr->id.data != NULL) {
ID *id = ptr->id.data;
- if (!(id->flag & LIB_ANIM_NO_RECALC)) {
- id->flag |= LIB_ID_RECALC;
+ if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) {
+ id->tag |= LIB_TAG_ID_RECALC;
DAG_id_type_tag(G.main, GS(id->name));
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index ee6710e1130..de21d9105e2 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -548,15 +548,7 @@ static void where_am_i(char *fullname, const size_t maxlen, const char *name)
BLI_strncpy(fullname, name, maxlen);
if (name[0] == '.') {
- char wdir[FILE_MAX] = "";
- BLI_current_working_dir(wdir, sizeof(wdir)); /* backup cwd to restore after */
-
- // not needed but avoids annoying /./ in name
- if (name[1] == SEP)
- BLI_join_dirfile(fullname, maxlen, wdir, name + 2);
- else
- BLI_join_dirfile(fullname, maxlen, wdir, name);
-
+ BLI_path_cwd(fullname, maxlen);
#ifdef _WIN32
BLI_path_program_extensions_add_win32(fullname, maxlen);
#endif
@@ -605,10 +597,20 @@ bool BKE_appdir_program_python_search(
char *fullpath, const size_t fullpath_len,
const int version_major, const int version_minor)
{
+#ifdef PYTHON_EXECUTABLE_NAME
+ /* passed in from the build-systems 'PYTHON_EXECUTABLE' */
+ const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME);
+#endif
const char *basename = "python";
char python_ver[16];
/* check both possible names */
- const char *python_names[] = {basename, python_ver};
+ const char *python_names[] = {
+#ifdef PYTHON_EXECUTABLE_NAME
+ python_build_def,
+#endif
+ python_ver,
+ basename,
+ };
int i;
bool is_found = false;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 29f2ad0d512..54fe98940aa 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -38,7 +38,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -91,6 +93,16 @@ bArmature *BKE_armature_from_object(Object *ob)
return NULL;
}
+int BKE_armature_bonelist_count(ListBase *lb)
+{
+ int i = 0;
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ i += 1 + BKE_armature_bonelist_count(&bone->childbase);
+ }
+
+ return i;
+}
+
void BKE_armature_bonelist_free(ListBase *lb)
{
Bone *bone;
@@ -169,8 +181,8 @@ void BKE_armature_make_local(bArmature *arm)
if (ob->data == arm) {
if (ob->id.lib == NULL) {
ob->data = arm_new;
- arm_new->id.us++;
- arm->id.us--;
+ id_us_plus(&arm_new->id);
+ id_us_min(&arm->id);
}
}
}
@@ -229,15 +241,15 @@ bArmature *BKE_armature_copy(bArmature *arm)
return newArm;
}
-static Bone *get_named_bone_bonechildren(Bone *bone, const char *name)
+static Bone *get_named_bone_bonechildren(ListBase *lb, const char *name)
{
Bone *curBone, *rbone;
- if (STREQ(bone->name, name))
- return bone;
+ for (curBone = lb->first; curBone; curBone = curBone->next) {
+ if (STREQ(curBone->name, name))
+ return curBone;
- for (curBone = bone->childbase.first; curBone; curBone = curBone->next) {
- rbone = get_named_bone_bonechildren(curBone, name);
+ rbone = get_named_bone_bonechildren(&curBone->childbase, name);
if (rbone)
return rbone;
}
@@ -246,21 +258,38 @@ static Bone *get_named_bone_bonechildren(Bone *bone, const char *name)
}
-/* Walk the list until the bone is found */
+/**
+ * Walk the list until the bone is found (slow!),
+ * use #BKE_armature_bone_from_name_map for multiple lookups.
+ */
Bone *BKE_armature_find_bone_name(bArmature *arm, const char *name)
{
- Bone *bone = NULL, *curBone;
-
if (!arm)
return NULL;
- for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) {
- bone = get_named_bone_bonechildren(curBone, name);
- if (bone)
- return bone;
+ return get_named_bone_bonechildren(&arm->bonebase, name);
+}
+
+static void armature_bone_from_name_insert_recursive(GHash *bone_hash, ListBase *lb)
+{
+ for (Bone *bone = lb->first; bone; bone = bone->next) {
+ BLI_ghash_insert(bone_hash, bone->name, bone);
+ armature_bone_from_name_insert_recursive(bone_hash, &bone->childbase);
}
+}
- return bone;
+/**
+ * Create a (name -> bone) map.
+ *
+ * \note typically #bPose.chanhash us used via #BKE_pose_channel_find_name
+ * this is for the cases we can't use pose channels.
+ */
+GHash *BKE_armature_bone_from_name_map(bArmature *arm)
+{
+ const int bones_count = BKE_armature_bonelist_count(&arm->bonebase);
+ GHash *bone_hash = BLI_ghash_str_new_ex(__func__, bones_count);
+ armature_bone_from_name_insert_recursive(bone_hash, &arm->bonebase);
+ return bone_hash;
}
bool BKE_armature_bone_flag_test_recursive(const Bone *bone, int flag)
@@ -1325,18 +1354,20 @@ void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inm
/* same as BKE_object_mat3_to_rot() */
void BKE_pchan_mat3_to_rot(bPoseChannel *pchan, float mat[3][3], bool use_compat)
{
+ BLI_ASSERT_UNIT_M3(mat);
+
switch (pchan->rotmode) {
case ROT_MODE_QUAT:
- mat3_to_quat(pchan->quat, mat);
+ mat3_normalized_to_quat(pchan->quat, mat);
break;
case ROT_MODE_AXISANGLE:
- mat3_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, mat);
+ mat3_normalized_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, mat);
break;
default: /* euler */
if (use_compat)
- mat3_to_compatible_eulO(pchan->eul, pchan->eul, pchan->rotmode, mat);
+ mat3_normalized_to_compatible_eulO(pchan->eul, pchan->eul, pchan->rotmode, mat);
else
- mat3_to_eulO(pchan->eul, pchan->rotmode, mat);
+ mat3_normalized_to_eulO(pchan->eul, pchan->rotmode, mat);
break;
}
}
@@ -2189,8 +2220,9 @@ static void boundbox_armature(Object *ob)
BoundBox *bb;
float min[3], max[3];
- if (ob->bb == NULL)
- ob->bb = MEM_mallocN(sizeof(BoundBox), "Armature boundbox");
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "Armature boundbox");
+ }
bb = ob->bb;
INIT_MINMAX(min, max);
@@ -2200,6 +2232,8 @@ static void boundbox_armature(Object *ob)
}
BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
BoundBox *BKE_armature_boundbox_get(Object *ob)
@@ -2229,7 +2263,7 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden
BKE_object_boundbox_get(pchan->custom) : NULL;
if (bb_custom) {
float mat[4][4], smat[4][4];
- scale_m4_fl(smat, pchan->bone->length);
+ scale_m4_fl(smat, PCHAN_CUSTOM_DRAW_SIZE(pchan));
mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat);
BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 0923ac7e743..baf93ffd824 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -52,6 +52,7 @@
#include "DNA_userdef_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_blenlib.h"
@@ -121,7 +122,7 @@ void free_blender(void)
DAG_exit();
BKE_brush_system_exit();
- RE_exit_texture_rng();
+ RE_texture_rng_exit();
BLI_callback_global_finalize();
@@ -196,17 +197,21 @@ static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
return false;
}
-/* context matching */
-/* handle no-ui case */
-
-/* note, this is called on Undo so any slow conversion functions here
- * should be avoided or check (mode!='u') */
-
-static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath)
+/**
+ * Context matching, handle no-ui case
+ *
+ * \note this is called on Undo so any slow conversion functions here
+ * should be avoided or check (mode != LOAD_UNDO).
+ *
+ * \param bfd: Blend file data, freed by this function on exit.
+ * \param filepath: File path or identifier.
+ */
+static void setup_app_data(
+ bContext *C, BlendFileData *bfd,
+ const char *filepath, ReportList *reports)
{
- bScreen *curscreen = NULL;
Scene *curscene = NULL;
- int recover;
+ const bool recover = (G.fileflags & G_FILE_RECOVER) != 0;
enum {
LOAD_UI = 1,
LOAD_UI_OFF,
@@ -223,7 +228,13 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
mode = LOAD_UI;
}
- recover = (G.fileflags & G_FILE_RECOVER);
+ if (mode != LOAD_UNDO) {
+ /* may happen with library files */
+ if (ELEM(NULL, bfd->curscreen, bfd->curscene)) {
+ BKE_report(reports, RPT_WARNING, "Library file, loading empty scene");
+ mode = LOAD_UI_OFF;
+ }
+ }
/* Free all render results, without this stale data gets displayed after loading files */
if (mode != LOAD_UNDO) {
@@ -251,12 +262,12 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
* (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
* see: T43424
*/
+ bScreen *curscreen = NULL;
bool track_undo_scene;
/* comes from readfile.c */
SWAP(ListBase, G.main->wm, bfd->main->wm);
SWAP(ListBase, G.main->screen, bfd->main->screen);
- SWAP(ListBase, G.main->script, bfd->main->script);
/* we re-use current screen */
curscreen = CTX_wm_screen(C);
@@ -265,9 +276,13 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
- if (curscene == NULL) curscene = bfd->main->scene.first;
+ if (curscene == NULL) {
+ curscene = bfd->main->scene.first;
+ }
/* empty file, we add a scene to make Blender work */
- if (curscene == NULL) curscene = BKE_scene_add(bfd->main, "Empty");
+ if (curscene == NULL) {
+ curscene = BKE_scene_add(bfd->main, "Empty");
+ }
if (track_undo_scene) {
/* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
@@ -349,7 +364,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
if (CTX_data_scene(C) == NULL) {
/* in case we don't even have a local scene, add one */
if (!G.main->scene.first)
- BKE_scene_add(G.main, "Scene");
+ BKE_scene_add(G.main, "Empty");
CTX_data_scene_set(C, G.main->scene.first);
CTX_wm_screen(C)->scene = CTX_data_scene(C);
@@ -373,10 +388,6 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
BPY_context_update(C);
#endif
- if (!G.background) {
- //setscreen(G.curscreen);
- }
-
/* FIXME: this version patching should really be part of the file-reading code,
* but we still get too many unrelated data-corruption crashes otherwise... */
if (G.main->versionfile < 250)
@@ -417,6 +428,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
BKE_scene_set_background(G.main, curscene);
if (mode != LOAD_UNDO) {
+ RE_FreeAllPersistentData();
IMB_colormanagement_check_file_config(G.main);
}
@@ -526,8 +538,9 @@ int BKE_read_file(bContext *C, const char *filepath, ReportList *reports)
bfd = NULL;
retval = BKE_READ_FILE_FAIL;
}
- else
- setup_app_data(C, bfd, filepath); // frees BFD
+ else {
+ setup_app_data(C, bfd, filepath, reports);
+ }
}
else
BKE_reports_prependf(reports, "Loading '%s' failed: ", filepath);
@@ -545,7 +558,7 @@ bool BKE_read_file_from_memory(
if (bfd) {
if (update_defaults)
BLO_update_defaults_startup_blend(bfd->main);
- setup_app_data(C, bfd, "<memory2>");
+ setup_app_data(C, bfd, "<memory2>", reports);
}
else {
BKE_reports_prepend(reports, "Loading failed: ");
@@ -569,7 +582,7 @@ bool BKE_read_file_from_memfile(
while (bfd->main->screen.first)
BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true);
- setup_app_data(C, bfd, "<memory1>");
+ setup_app_data(C, bfd, "<memory1>", reports);
}
else {
BKE_reports_prepend(reports, "Loading failed: ");
@@ -638,7 +651,10 @@ int blender_test_break(void)
}
-/* ***************** GLOBAL UNDO *************** */
+/* -------------------------------------------------------------------- */
+
+/** \name Global Undo
+ * \{ */
#define UNDO_DISK 0
@@ -956,98 +972,147 @@ Main *BKE_undo_get_main(Scene **r_scene)
return mainp;
}
-/* ************** copy paste .blend, partial saves ********** */
+/** \} */
+
-/* assumes data is in G.main */
+/* -------------------------------------------------------------------- */
-void BKE_copybuffer_begin(Main *bmain)
+/** \name Partial `.blend` file save.
+ * \{ */
+
+void BKE_blendfile_write_partial_begin(Main *bmain_src)
{
- /* set all id flags to zero; */
- BKE_main_id_flag_all(bmain, LIB_NEED_EXPAND | LIB_DOIT, false);
+ BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
}
-void BKE_copybuffer_tag_ID(ID *id)
+void BKE_blendfile_write_partial_tag_ID(ID *id, bool set)
{
- id->flag |= LIB_NEED_EXPAND | LIB_DOIT;
+ if (set) {
+ id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
+ }
+ else {
+ id->tag &= ~(LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT);
+ }
}
-static void copybuffer_doit(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
+static void blendfile_write_partial_cb(void *UNUSED(handle), Main *UNUSED(bmain), void *vid)
{
if (vid) {
ID *id = vid;
/* only tag for need-expand if not done, prevents eternal loops */
- if ((id->flag & LIB_DOIT) == 0)
- id->flag |= LIB_NEED_EXPAND | LIB_DOIT;
+ if ((id->tag & LIB_TAG_DOIT) == 0)
+ id->tag |= LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT;
}
}
-/* frees main in end */
-int BKE_copybuffer_save(const char *filename, ReportList *reports)
+/**
+ * \return Success.
+ */
+bool BKE_blendfile_write_partial(
+ Main *bmain_src, const char *filepath, const int write_flags, ReportList *reports)
{
- Main *mainb = MEM_callocN(sizeof(Main), "copybuffer");
- ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
+ Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer");
+ ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY];
int a, retval;
-
- /* path backup/restore */
- void *path_list_backup;
+
+ void *path_list_backup = NULL;
const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
- path_list_backup = BKE_bpath_list_backup(G.main, path_list_flag);
+ if (write_flags & G_FILE_RELATIVE_REMAP) {
+ path_list_backup = BKE_bpath_list_backup(bmain_src, path_list_flag);
+ }
+
+ BLO_main_expander(blendfile_write_partial_cb);
+ BLO_expand_main(NULL, bmain_src);
- BLO_main_expander(copybuffer_doit);
- BLO_expand_main(NULL, G.main);
-
/* move over all tagged blocks */
- set_listbasepointers(G.main, fromarray);
- a = set_listbasepointers(mainb, lbarray);
+ set_listbasepointers(bmain_src, lbarray_src);
+ a = set_listbasepointers(bmain_dst, lbarray_dst);
while (a--) {
ID *id, *nextid;
- ListBase *lb1 = lbarray[a], *lb2 = fromarray[a];
+ ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
- for (id = lb2->first; id; id = nextid) {
+ for (id = lb_src->first; id; id = nextid) {
nextid = id->next;
- if (id->flag & LIB_DOIT) {
- BLI_remlink(lb2, id);
- BLI_addtail(lb1, id);
+ if (id->tag & LIB_TAG_DOIT) {
+ BLI_remlink(lb_src, id);
+ BLI_addtail(lb_dst, id);
}
}
}
/* save the buffer */
- retval = BLO_write_file(mainb, filename, G_FILE_RELATIVE_REMAP, reports, NULL);
+ retval = BLO_write_file(bmain_dst, filepath, write_flags, reports, NULL);
/* move back the main, now sorted again */
- set_listbasepointers(G.main, lbarray);
- a = set_listbasepointers(mainb, fromarray);
+ set_listbasepointers(bmain_src, lbarray_dst);
+ a = set_listbasepointers(bmain_dst, lbarray_src);
while (a--) {
ID *id;
- ListBase *lb1 = lbarray[a], *lb2 = fromarray[a];
+ ListBase *lb_dst = lbarray_dst[a], *lb_src = lbarray_src[a];
- while ((id = BLI_pophead(lb2))) {
- BLI_addtail(lb1, id);
- id_sort_by_name(lb1, id);
+ while ((id = BLI_pophead(lb_src))) {
+ BLI_addtail(lb_dst, id);
+ id_sort_by_name(lb_dst, id);
}
}
- MEM_freeN(mainb);
-
- /* set id flag to zero; */
- BKE_main_id_flag_all(G.main, LIB_NEED_EXPAND | LIB_DOIT, false);
+ MEM_freeN(bmain_dst);
if (path_list_backup) {
- BKE_bpath_list_restore(G.main, path_list_flag, path_list_backup);
+ BKE_bpath_list_restore(bmain_src, path_list_flag, path_list_backup);
BKE_bpath_list_free(path_list_backup);
}
return retval;
}
-/* return success (1) */
-int BKE_copybuffer_paste(bContext *C, const char *libname, ReportList *reports)
+void BKE_blendfile_write_partial_end(Main *bmain_src)
+{
+ BKE_main_id_tag_all(bmain_src, LIB_TAG_NEED_EXPAND | LIB_TAG_DOIT, false);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Copy/Paste `.blend`, partial saves.
+ * \{ */
+
+void BKE_copybuffer_begin(Main *bmain_src)
+{
+ BKE_blendfile_write_partial_begin(bmain_src);
+}
+
+void BKE_copybuffer_tag_ID(ID *id)
+{
+ BKE_blendfile_write_partial_tag_ID(id, true);
+}
+
+/**
+ * \return Success.
+ */
+bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports)
+{
+ const int write_flags = G_FILE_RELATIVE_REMAP;
+
+ bool retval = BKE_blendfile_write_partial(bmain_src, filename, write_flags, reports);
+
+ BKE_blendfile_write_partial_end(bmain_src);
+
+ return retval;
+}
+
+/**
+ * \return Success.
+ */
+bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
@@ -1056,7 +1121,7 @@ int BKE_copybuffer_paste(bContext *C, const char *libname, ReportList *reports)
if (bh == NULL) {
/* error reports will have been made by BLO_blendhandle_from_file() */
- return 0;
+ return false;
}
BKE_scene_base_deselect_all(scene);
@@ -1064,15 +1129,15 @@ int BKE_copybuffer_paste(bContext *C, const char *libname, ReportList *reports)
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
*
- * take extra care BKE_main_id_flag_all(bmain, LIB_LINK_TAG, false) is called after! */
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, true);
+ * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* here appending/linking starts */
- mainl = BLO_library_append_begin(bmain, &bh, libname);
+ mainl = BLO_library_link_begin(bmain, &bh, libname);
- BLO_library_append_all(mainl, bh);
+ BLO_library_link_copypaste(mainl, bh);
- BLO_library_append_end(C, mainl, &bh, 0, 0);
+ BLO_library_link_end(mainl, &bh, flag, scene, v3d);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
@@ -1080,11 +1145,11 @@ int BKE_copybuffer_paste(bContext *C, const char *libname, ReportList *reports)
/* append, rather than linking */
lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath));
- BKE_library_make_local(bmain, lib, true);
+ BKE_library_make_local(bmain, lib, true, false);
/* important we unset, otherwise these object wont
* link into other scenes from this blend file */
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
/* recreate dependency graph to include new objects */
DAG_relations_tag_update(bmain);
@@ -1092,5 +1157,7 @@ int BKE_copybuffer_paste(bContext *C, const char *libname, ReportList *reports)
BLO_blendhandle_close(bh);
/* remove library... */
- return 1;
+ return true;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 489e26c5cbe..b4bc83bf94c 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -80,6 +80,9 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
float priority = 0.0f, len = 0.0f;
int ret = 0;
+ int p = 0;
+ efd.index = cur_efd.index = &p;
+
pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
/* first find out goal/predator with highest priority */
@@ -307,6 +310,7 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *
ParticleSystem *epsys = psys_get_target_system(bbd->sim->ob, pt);
if (epsys) {
+ BLI_assert(epsys->tree != NULL);
neighbors = BLI_kdtree_range_search__normal(
epsys->tree, pa->prev_state.co, pa->prev_state.ave,
&ptn, acbr->look_ahead * len_v3(pa->prev_state.vel));
@@ -1006,9 +1010,11 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
case eBoidRulesetType_Random:
{
/* use random rule for each particle (always same for same particle though) */
- rule = BLI_findlink(&state->rules, rand % BLI_listbase_count(&state->rules));
-
- apply_boid_rule(bbd, rule, &val, pa, -1.0);
+ const int n = BLI_listbase_count(&state->rules);
+ if (n) {
+ rule = BLI_findlink(&state->rules, rand % n);
+ apply_boid_rule(bbd, rule, &val, pa, -1.0);
+ }
break;
}
case eBoidRulesetType_Average:
@@ -1500,7 +1506,7 @@ BoidRule *boid_new_rule(int type)
rule->type = type;
rule->flag |= BOIDRULE_IN_AIR|BOIDRULE_ON_LAND;
- BLI_strncpy(rule->name, boidrule_type_items[type-1].name, sizeof(rule->name));
+ BLI_strncpy(rule->name, rna_enum_boidrule_type_items[type-1].name, sizeof(rule->name));
return rule;
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index e0ffd830804..31dac038e43 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -131,22 +131,30 @@ static void brush_defaults(Brush *brush)
/* Datablock add/copy/free/make_local */
-Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
+void BKE_brush_init(Brush *brush)
{
- Brush *brush;
-
- brush = BKE_libblock_alloc(bmain, ID_BR, name);
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(brush, id));
/* enable fake user by default */
- brush->id.flag |= LIB_FAKEUSER;
+ id_fake_user_set(&brush->id);
brush_defaults(brush);
brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
- brush->ob_mode = ob_mode;
/* the default alpha falloff curve */
BKE_brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
+}
+
+Brush *BKE_brush_add(Main *bmain, const char *name, short ob_mode)
+{
+ Brush *brush;
+
+ brush = BKE_libblock_alloc(bmain, ID_BR, name);
+
+ BKE_brush_init(brush);
+
+ brush->ob_mode = ob_mode;
return brush;
}
@@ -185,11 +193,8 @@ Brush *BKE_brush_copy(Brush *brush)
brushn->curve = curvemapping_copy(brush->curve);
/* enable fake user by default */
- if (!(brushn->id.flag & LIB_FAKEUSER)) {
- brushn->id.flag |= LIB_FAKEUSER;
- brushn->id.us++;
- }
-
+ id_fake_user_set(&brush->id);
+
if (brush->id.lib) {
BKE_id_lib_local_paths(G.main, brush->id.lib, &brushn->id);
}
@@ -215,11 +220,27 @@ void BKE_brush_free(Brush *brush)
MEM_freeN(brush->gradient);
}
+/**
+ * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc)
+ * This is only used by RNA, which can remove brushes.
+ */
+void BKE_brush_unlink(Main *bmain, Brush *brush)
+{
+ Brush *brush_iter;
+
+ for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) {
+ if (brush_iter->toggle_brush == brush) {
+ brush_iter->toggle_brush = NULL;
+ }
+ }
+}
+
static void extern_local_brush(Brush *brush)
{
id_lib_extern((ID *)brush->mtex.tex);
id_lib_extern((ID *)brush->mask_mtex.tex);
id_lib_extern((ID *)brush->clone.image);
+ id_lib_extern((ID *)brush->toggle_brush);
id_lib_extern((ID *)brush->paint_curve);
}
@@ -256,15 +277,11 @@ void BKE_brush_make_local(Brush *brush)
extern_local_brush(brush);
/* enable fake user by default */
- if (!(brush->id.flag & LIB_FAKEUSER)) {
- brush->id.flag |= LIB_FAKEUSER;
- brush->id.us++;
- }
+ id_fake_user_set(&brush->id);
}
else if (is_local && is_lib) {
- Brush *brush_new = BKE_brush_copy(brush);
- brush_new->id.us = 1; /* only keep fake user */
- brush_new->id.flag |= LIB_FAKEUSER;
+ Brush *brush_new = BKE_brush_copy(brush); /* Ensures FAKE_USER is set */
+ id_us_min(&brush_new->id); /* Remove user added by standard BKE_libblock_copy(). */
/* Remap paths of new ID using old library as base. */
BKE_id_lib_local_paths(bmain, brush->id.lib, &brush_new->id);
@@ -481,7 +498,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr)
if (idtest == NULL) { /* new tex */
if (id) idtest = (ID *)BKE_texture_copy((Tex *)id);
else idtest = (ID *)BKE_texture_add(G.main, "Tex");
- idtest->us--;
+ id_us_min(idtest);
}
if (idtest != id) {
BKE_brush_texture_delete(brush);
@@ -498,7 +515,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr)
int BKE_brush_texture_delete(Brush *brush)
{
if (brush->mtex.tex)
- brush->mtex.tex->id.us--;
+ id_us_min(&brush->mtex.tex->id);
return 1;
}
@@ -524,7 +541,7 @@ int BKE_brush_clone_image_set_nr(Brush *brush, int nr)
int BKE_brush_clone_image_delete(Brush *brush)
{
if (brush && brush->clone.image) {
- brush->clone.image->id.us--;
+ id_us_min(&brush->clone.image->id);
brush->clone.image = NULL;
return 1;
}
@@ -553,7 +570,7 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
/* Get strength by feeding the vertex
* location directly into a texture */
hasrgb = externtex(mtex, point, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
float rotation = -mtex->rot;
@@ -584,7 +601,7 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
co[2] = 0.0f;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
}
else {
float rotation = -mtex->rot;
@@ -641,7 +658,7 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
co[2] = 0.0f;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
}
intensity += br->texture_sample_bias;
@@ -701,7 +718,7 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
co[2] = 0.0f;
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
}
else {
float rotation = -mtex->rot;
@@ -758,7 +775,7 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
co[2] = 0.0f;
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
}
CLAMP(intensity, 0.0f, 1.0f);
@@ -1031,7 +1048,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
/* This is copied from displace modifier code */
/* TODO(sergey): brush are always cacheing with CM enabled for now. */
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
((char *)texcache)[(iy * side + ix) * 4] =
((char *)texcache)[(iy * side + ix) * 4 + 1] =
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 626be0eaf4e..abba61310a4 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -382,17 +382,40 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r
static BVHTree *bvhtree_from_mesh_verts_create_tree(
float epsilon, int tree_type, int axis,
+ BMEditMesh *em, const int *index_array,
MVert *vert, const int numVerts,
BLI_bitmap *mask, int numVerts_active)
{
BVHTree *tree = NULL;
+ BMVert *eve = NULL;
int i;
-
+ int index = 0;
+ if (em != NULL) {
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ }
if (vert) {
if (mask && numVerts_active < 0) {
numVerts_active = 0;
for (i = 0; i < numVerts; i++) {
if (BLI_BITMAP_TEST_BOOL(mask, i)) {
+ if (em != NULL) {
+ if (index_array) {
+ index = index_array[i];
+ if (index == ORIGINDEX_NONE) {
+ continue;
+ }
+ }
+ else {
+ index = i;
+ }
+
+ eve = BM_vert_at_index(em->bm, index);
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test(eve, BM_ELEM_SELECT))
+ {
+ continue;
+ }
+ }
numVerts_active++;
}
}
@@ -408,6 +431,24 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
if (mask && !BLI_BITMAP_TEST_BOOL(mask, i)) {
continue;
}
+ if (em != NULL) {
+ if (index_array) {
+ index = index_array[i];
+ if (index == ORIGINDEX_NONE) {
+ continue;
+ }
+ }
+ else {
+ index = i;
+ }
+
+ eve = BM_vert_at_index(em->bm, index);
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
+ BM_elem_flag_test(eve, BM_ELEM_SELECT))
+ {
+ continue;
+ }
+ }
BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
@@ -432,6 +473,7 @@ static void bvhtree_from_mesh_verts_setup_data(
* remember the min distance to point is the same as the min distance to BV of point */
data->nearest_callback = NULL;
data->raycast_callback = mesh_verts_spherecast;
+ data->nearest_to_ray_callback = NULL;
data->vert = vert;
data->vert_allocated = vert_allocated;
@@ -449,12 +491,14 @@ static void bvhtree_from_mesh_verts_setup_data(
/* Builds a bvh tree where nodes are the vertices of the given dm */
BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
{
+ BMEditMesh *em = data->em_evil;
+ const int bvhcache_type = em ? BVHTREE_FROM_VERTS_EDITMESH_SNAP : BVHTREE_FROM_VERTS;
BVHTree *tree;
MVert *vert;
bool vert_allocated;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS);
+ tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
BLI_rw_mutex_unlock(&cache_rwlock);
vert = DM_get_vert_array(dm, &vert_allocated);
@@ -462,13 +506,26 @@ BVHTree *bvhtree_from_mesh_verts(BVHTreeFromMesh *data, DerivedMesh *dm, float e
/* Not in cache */
if (tree == NULL) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(&dm->bvhCache, BVHTREE_FROM_VERTS);
+ tree = bvhcache_find(&dm->bvhCache, bvhcache_type);
if (tree == NULL) {
- tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, vert, dm->getNumVerts(dm), NULL, -1);
+ int vert_num, *index_array = NULL;
+ if (em != NULL) {
+ vert_num = em->bm->totvert;
+ index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ }
+ else {
+ vert_num = dm->getNumVerts(dm);
+ BLI_assert(vert_num != 0);
+ }
+ tree = bvhtree_from_mesh_verts_create_tree(
+ epsilon, tree_type, axis,
+ em, index_array,
+ vert, vert_num, NULL, -1);
+
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS);
+ bvhcache_insert(&dm->bvhCache, tree, bvhcache_type);
}
}
BLI_rw_mutex_unlock(&cache_rwlock);
@@ -494,7 +551,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(
BLI_bitmap *mask, int numVerts_active,
float epsilon, int tree_type, int axis)
{
- BVHTree *tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, vert, numVerts, mask, numVerts_active);
+ BVHTree *tree = bvhtree_from_mesh_verts_create_tree(epsilon, tree_type, axis, NULL, NULL, vert, numVerts, mask, numVerts_active);
/* Setup BVHTreeFromMesh */
bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated);
@@ -568,6 +625,7 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
data->nearest_callback = mesh_edges_nearest_point;
data->raycast_callback = mesh_edges_spherecast;
+ data->nearest_to_ray_callback = NULL;
data->vert = vert;
data->vert_allocated = vert_allocated;
@@ -597,7 +655,8 @@ BVHTree *bvhtree_from_mesh_edges(BVHTreeFromMesh *data, DerivedMesh *dm, float e
static BVHTree *bvhtree_from_mesh_faces_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, MVert *vert, MFace *face, const int numFaces,
+ BMEditMesh *em, const bool em_all,
+ MVert *vert, MFace *face, const int numFaces,
BLI_bitmap *mask, int numFaces_active)
{
BVHTree *tree = NULL;
@@ -646,7 +705,10 @@ static BVHTree *bvhtree_from_mesh_faces_create_tree(
insert = insert_prev;
}
else if (insert) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ if (em_all) {
+ /* pass */
+ }
+ else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
/* Don't insert triangles tessellated from faces that are hidden or selected */
insert = false;
}
@@ -719,10 +781,12 @@ static void bvhtree_from_mesh_faces_setup_data(
if (em) {
data->nearest_callback = editmesh_faces_nearest_point;
data->raycast_callback = editmesh_faces_spherecast;
+ data->nearest_to_ray_callback = NULL;
}
else {
data->nearest_callback = mesh_faces_nearest_point;
data->raycast_callback = mesh_faces_spherecast;
+ data->nearest_to_ray_callback = NULL;
data->vert = vert;
data->vert_allocated = vert_allocated;
@@ -746,7 +810,9 @@ static void bvhtree_from_mesh_faces_setup_data(
BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
{
BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_FACES;
+ const int bvhcache_type = em ?
+ (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) :
+ BVHTREE_FROM_FACES;
BVHTree *tree;
MVert *vert = NULL;
MFace *face = NULL;
@@ -781,7 +847,10 @@ BVHTree *bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *dm, float e
BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
}
- tree = bvhtree_from_mesh_faces_create_tree(epsilon, tree_type, axis, em, vert, face, numFaces, NULL, -1);
+ tree = bvhtree_from_mesh_faces_create_tree(
+ epsilon, tree_type, axis,
+ em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL),
+ vert, face, numFaces, NULL, -1);
if (tree) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
@@ -813,7 +882,9 @@ BVHTree *bvhtree_from_mesh_faces_ex(
BLI_bitmap *mask, int numFaces_active, float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhtree_from_mesh_faces_create_tree(
- epsilon, tree_type, axis, NULL, vert, face, numFaces,
+ epsilon, tree_type, axis,
+ NULL, false,
+ vert, face, numFaces,
mask, numFaces_active);
/* Setup BVHTreeFromMesh */
@@ -832,7 +903,8 @@ BVHTree *bvhtree_from_mesh_faces_ex(
static BVHTree *bvhtree_from_mesh_looptri_create_tree(
float epsilon, int tree_type, int axis,
- BMEditMesh *em, const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
+ BMEditMesh *em, const bool em_all,
+ const MVert *vert, const MLoop *mloop, const MLoopTri *looptri, const int looptri_num,
BLI_bitmap *mask, int looptri_num_active)
{
BVHTree *tree = NULL;
@@ -881,7 +953,10 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
insert = insert_prev;
}
else if (insert) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ if (em_all) {
+ /* pass */
+ }
+ else if (BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
/* Don't insert triangles tessellated from faces that are hidden or selected */
insert = false;
}
@@ -953,10 +1028,12 @@ static void bvhtree_from_mesh_looptri_setup_data(
if (em) {
data->nearest_callback = editmesh_faces_nearest_point;
data->raycast_callback = editmesh_faces_spherecast;
+ data->nearest_to_ray_callback = NULL;
}
else {
data->nearest_callback = mesh_looptri_nearest_point;
data->raycast_callback = mesh_looptri_spherecast;
+ data->nearest_to_ray_callback = NULL;
data->vert = vert;
data->vert_allocated = vert_allocated;
@@ -972,6 +1049,9 @@ static void bvhtree_from_mesh_looptri_setup_data(
if (vert_allocated) {
MEM_freeN((void *)vert);
}
+ if (loop_allocated) {
+ MEM_freeN((void *)mloop);
+ }
if (looptri_allocated) {
MEM_freeN((void *)looptri);
}
@@ -986,7 +1066,9 @@ static void bvhtree_from_mesh_looptri_setup_data(
BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis)
{
BMEditMesh *em = data->em_evil;
- const int bvhcache_type = em ? BVHTREE_FROM_FACES_EDITMESH : BVHTREE_FROM_LOOPTRI;
+ const int bvhcache_type = em ?
+ (data->em_evil_all ? BVHTREE_FROM_FACES_EDITMESH_ALL : BVHTREE_FROM_FACES_EDITMESH_SNAP) :
+ BVHTREE_FROM_LOOPTRI;
BVHTree *tree;
MVert *mvert = NULL;
MLoop *mloop = NULL;
@@ -1041,7 +1123,8 @@ BVHTree *bvhtree_from_mesh_looptri(BVHTreeFromMesh *data, DerivedMesh *dm, float
}
tree = bvhtree_from_mesh_looptri_create_tree(
- epsilon, tree_type, axis, em,
+ epsilon, tree_type, axis,
+ em, (bvhcache_type == BVHTREE_FROM_FACES_EDITMESH_ALL),
mvert, mloop, looptri, looptri_num, NULL, -1);
if (tree) {
/* Save on cache for later use */
@@ -1074,7 +1157,9 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
float epsilon, int tree_type, int axis)
{
BVHTree *tree = bvhtree_from_mesh_looptri_create_tree(
- epsilon, tree_type, axis, NULL, vert, mloop, looptri, looptri_num,
+ epsilon, tree_type, axis,
+ NULL, false,
+ vert, mloop, looptri, looptri_num,
mask, looptri_num_active);
/* Setup BVHTreeFromMesh */
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 7e043df2808..6fd756e2788 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -57,11 +57,9 @@
/****************************** Camera Datablock *****************************/
-void *BKE_camera_add(Main *bmain, const char *name)
+void BKE_camera_init(Camera *cam)
{
- Camera *cam;
-
- cam = BKE_libblock_alloc(bmain, ID_CA, name);
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id));
cam->lens = 35.0f;
cam->sensor_x = DEFAULT_SENSOR_WIDTH;
@@ -78,6 +76,15 @@ void *BKE_camera_add(Main *bmain, const char *name)
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
+}
+
+void *BKE_camera_add(Main *bmain, const char *name)
+{
+ Camera *cam;
+
+ cam = BKE_libblock_alloc(bmain, ID_CA, name);
+
+ BKE_camera_init(cam);
return cam;
}
@@ -136,8 +143,8 @@ void BKE_camera_make_local(Camera *cam)
if (ob->data == cam) {
if (ob->id.lib == NULL) {
ob->data = cam_new;
- cam_new->id.us++;
- cam->id.us--;
+ id_us_plus(&cam_new->id);
+ id_us_min(&cam->id);
}
}
}
@@ -838,6 +845,29 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha
normalize_m4(r_modelmat);
}
+bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera)
+{
+ Camera *cam;
+ const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
+
+ if (!is_multiview)
+ return false;
+
+ if (camera->type != OB_CAMERA)
+ return false;
+ else
+ cam = camera->data;
+
+ if ((rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) &&
+ ELEM(cam->type, CAM_PANO, CAM_PERSP) &&
+ ((cam->stereo.flag & CAM_S3D_SPHERICAL) != 0))
+ {
+ return true;
+ }
+
+ return false;
+}
+
static Object *camera_multiview_advanced(Scene *scene, Object *camera, const char *suffix)
{
SceneRenderView *srv;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 8b020226bca..519b7b44637 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -57,8 +57,9 @@
#include "GPU_buffers.h"
#include "GPU_draw.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
+#include "GPU_shader.h"
+#include "GPU_basic_shader.h"
#include "WM_api.h"
@@ -66,8 +67,6 @@
#include <limits.h>
#include <math.h>
-extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
-
typedef struct {
DerivedMesh dm;
@@ -344,8 +343,21 @@ static void cdDM_update_normals_from_pbvh(DerivedMesh *dm)
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
float (*face_nors)[3];
- if (!cddm->pbvh || !cddm->pbvh_draw || !dm->numPolyData)
+ /* Some callbacks do not use optimal PBVH draw, so needs all the
+ * possible data (like normals) to be copied from PBVH back to DM.
+ *
+ * This is safe to do if PBVH and DM are representing the same mesh,
+ * which could be wrong when modifiers are enabled for sculpt.
+ * So here we only doing update when there's no modifiers applied
+ * during sculpt.
+ *
+ * It's safe to do nothing if there are modifiers, because in this
+ * case modifier stack is re-constructed from scratch on every
+ * update.
+ */
+ if (!cddm->pbvh_draw) {
return;
+ }
face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
@@ -446,18 +458,15 @@ static void cdDM_drawFacesSolid(
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
int a;
- if (cddm->pbvh && cddm->pbvh_draw) {
- if (BKE_pbvh_has_faces(cddm->pbvh)) {
- float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
-
- cdDM_update_normals_from_pbvh(dm);
+ if (cddm->pbvh) {
+ if (cddm->pbvh_draw && BKE_pbvh_has_faces(cddm->pbvh)) {
+ float (*face_nors)[3] = CustomData_get_layer(&dm->polyData, CD_NORMAL);
BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
setMaterial, false, false);
glShadeModel(GL_FLAT);
+ return;
}
-
- return;
}
GPU_vertex_setup(dm);
@@ -481,7 +490,7 @@ static void cdDM_drawFacesTex_common(
DMSetDrawOptionsTex drawParams,
DMSetDrawOptionsMappedTex drawParamsMapped,
DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag uvflag)
+ void *userData, DMDrawFlag flag)
{
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
const MPoly *mpoly = cddm->mpoly;
@@ -489,7 +498,8 @@ static void cdDM_drawFacesTex_common(
const MLoopCol *mloopcol;
int i;
int colType, start_element, tot_drawn;
- bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0;
+ const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
+ const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
int totpoly;
int next_actualFace;
int mat_index;
@@ -505,14 +515,18 @@ static void cdDM_drawFacesTex_common(
* textured view, but object itself will be displayed gray
* (the same as it'll display without UV maps in textured view)
*/
- if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (BKE_pbvh_has_faces(cddm->pbvh)) {
- cdDM_update_normals_from_pbvh(dm);
+ if (cddm->pbvh) {
+ if (cddm->pbvh_draw &&
+ BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
+ BKE_pbvh_has_faces(cddm->pbvh))
+ {
GPU_set_tpage(NULL, false, false);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
+ return;
+ }
+ else {
+ cdDM_update_normals_from_pbvh(dm);
}
-
- return;
}
colType = CD_TEXTURE_MLOOPCOL;
@@ -529,7 +543,7 @@ static void cdDM_drawFacesTex_common(
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
- if (uvflag & DM_DRAW_USE_TEXPAINT_UV)
+ if (flag & DM_DRAW_USE_TEXPAINT_UV)
GPU_texpaint_uv_setup(dm);
else
GPU_uv_setup(dm);
@@ -557,7 +571,10 @@ static void cdDM_drawFacesTex_common(
if (i != totpoly - 1)
next_actualFace = bufmat->polys[i + 1];
- if (drawParams) {
+ if (use_hide && (mpoly[actualFace].flag & ME_HIDE)) {
+ draw_option = DM_DRAW_OPTION_SKIP;
+ }
+ else if (drawParams) {
MTexPoly *tp = use_tface && mtexpoly ? &mtexpoly[actualFace] : NULL;
draw_option = drawParams(tp, (mloopcol != NULL), mpoly[actualFace].mat_nr);
}
@@ -621,9 +638,9 @@ static void cdDM_drawFacesTex(
DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag uvflag)
+ void *userData, DMDrawFlag flag)
{
- cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, uvflag);
+ cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
}
static void cdDM_drawMappedFaces(
@@ -636,7 +653,9 @@ static void cdDM_drawMappedFaces(
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
const MPoly *mpoly = cddm->mpoly;
const MLoopCol *mloopcol = NULL;
- int colType, useColors = flag & DM_DRAW_USE_COLORS, useHide = flag & DM_DRAW_SKIP_HIDDEN;
+ const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
+ const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
+ int colType;
int i, j;
int start_element = 0, tot_element, tot_drawn;
int totpoly;
@@ -664,7 +683,7 @@ static void cdDM_drawMappedFaces(
else
me = userData;
- findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int), false);
+ findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int));
fi_map = GPU_buffer_lock(findex_buffer, GPU_BINDING_ARRAY);
if (fi_map) {
@@ -673,7 +692,7 @@ static void cdDM_drawMappedFaces(
const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i;
bool is_hidden;
- if (useHide) {
+ if (use_hide) {
if (flag & DM_DRAW_SELECT_USE_EDITMODE) {
BMFace *efa = BM_face_at_index(bm, orig);
is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0;
@@ -703,7 +722,7 @@ static void cdDM_drawMappedFaces(
else {
GPU_normal_setup(dm);
- if (useColors) {
+ if (use_colors) {
colType = CD_TEXTURE_MLOOPCOL;
mloopcol = DM_get_loop_data_layer(dm, colType);
if (!mloopcol) {
@@ -715,7 +734,7 @@ static void cdDM_drawMappedFaces(
mloopcol = DM_get_loop_data_layer(dm, colType);
}
- if (useColors && mloopcol) {
+ if (use_colors && mloopcol) {
GPU_color_setup(dm, colType);
}
}
@@ -738,7 +757,7 @@ static void cdDM_drawMappedFaces(
GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
int next_actualFace = bufmat->polys[0];
- totpoly = useHide ? bufmat->totvisiblepolys : bufmat->totpolys;
+ totpoly = use_hide ? bufmat->totvisiblepolys : bufmat->totpolys;
tot_element = 0;
start_element = 0;
@@ -748,6 +767,8 @@ static void cdDM_drawMappedFaces(
draw_option = setMaterial(bufmat->mat_nr + 1, NULL);
if (draw_option != DM_DRAW_OPTION_SKIP) {
+ DMDrawOption last_draw_option = DM_DRAW_OPTION_NORMAL;
+
for (i = 0; i < totpoly; i++) {
int actualFace = next_actualFace;
int flush = 0;
@@ -766,17 +787,12 @@ static void cdDM_drawMappedFaces(
}
}
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
- }
-
/* Goal is to draw as long of a contiguous triangle
* array as possible, so draw when we hit either an
* invisible triangle or at the end of the array */
/* flush buffer if current triangle isn't drawable or it's last triangle... */
- flush = (ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE)) || (i == totpoly - 1);
+ flush = (draw_option != last_draw_option) || (i == totpoly - 1);
if (!flush && compareDrawOptions) {
flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
@@ -786,27 +802,42 @@ static void cdDM_drawMappedFaces(
tot_element += tot_tri_verts;
if (flush) {
- if (!ELEM(draw_option, DM_DRAW_OPTION_SKIP, DM_DRAW_OPTION_STIPPLE))
+ if (draw_option != DM_DRAW_OPTION_SKIP) {
tot_drawn += tot_tri_verts;
+ if (last_draw_option != draw_option) {
+ if (draw_option == DM_DRAW_OPTION_STIPPLE) {
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
+ }
+ else {
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
+ }
+ }
+
if (tot_drawn) {
GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
tot_drawn = 0;
}
+ last_draw_option = draw_option;
start_element = tot_element;
-
- if (draw_option == DM_DRAW_OPTION_STIPPLE)
- glDisable(GL_POLYGON_STIPPLE);
}
else {
- tot_drawn += tot_tri_verts;
+ if (draw_option != DM_DRAW_OPTION_SKIP) {
+ tot_drawn += tot_tri_verts;
+ }
+ else {
+ start_element = tot_element;
+ }
}
}
}
}
}
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glShadeModel(GL_FLAT);
GPU_buffers_unbind();
@@ -878,14 +909,18 @@ static void cdDM_drawMappedFacesGLSL(
* will skip using textures (dyntopo currently destroys UV anyway) and
* works fine for matcap
*/
- if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (BKE_pbvh_has_faces(cddm->pbvh)) {
- cdDM_update_normals_from_pbvh(dm);
+ if (cddm->pbvh) {
+ if (cddm->pbvh_draw &&
+ BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
+ BKE_pbvh_has_faces(cddm->pbvh))
+ {
setMaterial(1, &gattribs);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
+ return;
+ }
+ else {
+ cdDM_update_normals_from_pbvh(dm);
}
-
- return;
}
matnr = -1;
@@ -893,10 +928,7 @@ static void cdDM_drawMappedFacesGLSL(
glShadeModel(GL_SMOOTH);
- /* workaround for NVIDIA GPUs on Mac not supporting vertex arrays + interleaved formats, see T43342 */
- if ((GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_MAC, GPU_DRIVER_ANY) && (U.gameflags & USER_DISABLE_VBO)) ||
- setDrawOptions != NULL)
- {
+ if (setDrawOptions != NULL) {
DMVertexAttribs attribs;
DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
memset(&attribs, 0, sizeof(attribs));
@@ -925,7 +957,7 @@ static void cdDM_drawMappedFacesGLSL(
if (!do_draw) {
continue;
}
- else if (setDrawOptions) {
+ else /* if (setDrawOptions) */ {
orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
if (orig == ORIGINDEX_NONE) {
@@ -967,7 +999,7 @@ static void cdDM_drawMappedFacesGLSL(
int *mat_orig_to_new;
int tot_active_mat;
GPUBuffer *buffer = NULL;
- char *varray;
+ unsigned char *varray;
size_t max_element_size = 0;
int tot_loops = 0;
@@ -1032,11 +1064,8 @@ static void cdDM_drawMappedFacesGLSL(
/* part two, generate and fill the arrays with the data */
if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts, false);
+ buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
- if (buffer == NULL) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts, true);
- }
varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
if (varray == NULL) {
GPU_buffers_unbind();
@@ -1072,17 +1101,15 @@ static void cdDM_drawMappedFacesGLSL(
if (matconv[i].attribs.mcol[b].array) {
const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array;
for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4_char((char *)&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r);
+ copy_v4_v4_uchar(&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r);
offset += sizeof(unsigned char) * 4;
}
}
if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
- if (matconv[i].attribs.tface[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
- offset += sizeof(float) * 4;
- }
+ const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array;
+ for (j = 0; j < mpoly->totloop; j++)
+ copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
+ offset += sizeof(float) * 4;
}
}
@@ -1149,14 +1176,18 @@ static void cdDM_drawMappedFacesMat(
* works fine for matcap
*/
- if (cddm->pbvh && cddm->pbvh_draw && BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) {
- if (BKE_pbvh_has_faces(cddm->pbvh)) {
- cdDM_update_normals_from_pbvh(dm);
+ if (cddm->pbvh) {
+ if (cddm->pbvh_draw &&
+ BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
+ BKE_pbvh_has_faces(cddm->pbvh))
+ {
setMaterial(userData, 1, &gattribs);
BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
+ return;
+ }
+ else {
+ cdDM_update_normals_from_pbvh(dm);
}
-
- return;
}
matnr = -1;
@@ -1349,6 +1380,7 @@ static void cdDM_buffer_copy_vertex(
static void cdDM_buffer_copy_normal(
DerivedMesh *dm, short *varray)
{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
int i, j, totpoly;
int start;
@@ -1364,6 +1396,10 @@ static void cdDM_buffer_copy_normal(
mloop = dm->getLoopArray(dm);
totpoly = dm->getNumPolys(dm);
+ /* we are in sculpt mode, disable loop normals (since they won't get updated) */
+ if (cddm->pbvh)
+ lnors = NULL;
+
start = 0;
for (i = 0; i < totpoly; i++, mpoly++) {
const bool smoothnormal = (mpoly->flag & ME_SMOOTH) != 0;
@@ -1464,7 +1500,7 @@ static void cdDM_buffer_copy_uv_texpaint(
}
}
- MEM_freeN(uv_base);
+ MEM_freeN((void *)uv_base);
}
/* treat varray_ as an array of MCol, four MCol's per face */
@@ -1484,7 +1520,7 @@ static void cdDM_buffer_copy_mcol(
for (i = 0; i < totpoly; i++, mpoly++) {
for (j = 0; j < mpoly->totloop; j++) {
- copy_v3_v3_char((char *)&varray[start], &mloopcol[mpoly->loopstart + j].r);
+ copy_v3_v3_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r);
start += 3;
}
}
@@ -2423,10 +2459,11 @@ DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
* relationship between mesh data this needs to be set by the caller. */
-DerivedMesh *CDDM_from_template(
+DerivedMesh *CDDM_from_template_ex(
DerivedMesh *source,
int numVerts, int numEdges, int numTessFaces,
- int numLoops, int numPolys)
+ int numLoops, int numPolys,
+ CustomDataMask mask)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
DerivedMesh *dm = &cddm->dm;
@@ -2438,7 +2475,11 @@ DerivedMesh *CDDM_from_template(
source->getPolyDataArray(source, CD_ORIGINDEX);
/* this does a copy of all non mvert/medge/mface layers */
- DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
+ DM_from_template_ex(
+ dm, source, DM_TYPE_CDDM,
+ numVerts, numEdges, numTessFaces,
+ numLoops, numPolys,
+ mask);
/* now add mvert/medge/mface layers */
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
@@ -2462,6 +2503,16 @@ DerivedMesh *CDDM_from_template(
return dm;
}
+DerivedMesh *CDDM_from_template(
+ DerivedMesh *source,
+ int numVerts, int numEdges, int numTessFaces,
+ int numLoops, int numPolys)
+{
+ return CDDM_from_template_ex(
+ source, numVerts, numEdges, numTessFaces,
+ numLoops, numPolys,
+ CD_MASK_DERIVEDMESH);
+}
void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3])
{
@@ -2534,7 +2585,7 @@ void CDDM_calc_normals_mapping_ex(DerivedMesh *dm, const bool only_face_normals)
/* calculate face normals */
BKE_mesh_calc_normals_poly(
- cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
+ cddm->mvert, NULL, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
dm->numLoopData, dm->numPolyData, face_nors,
only_face_normals);
@@ -2584,7 +2635,7 @@ void CDDM_calc_normals(DerivedMesh *dm)
/* we don't want to overwrite any referenced layers */
cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
- BKE_mesh_calc_normals_poly(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
+ BKE_mesh_calc_normals_poly(cddm->mvert, NULL, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm),
dm->numLoopData, dm->numPolyData, NULL, false);
cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
@@ -2633,7 +2684,7 @@ void CDDM_calc_loop_normals_spacearr(
if (!pnors) {
pnors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
}
- BKE_mesh_calc_normals_poly(mverts, numVerts, mloops, mpolys, numLoops, numPolys, pnors,
+ BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloops, mpolys, numLoops, numPolys, pnors,
(dm->dirty & DM_DIRTY_NORMALS) ? false : true);
dm->dirty &= ~DM_DIRTY_NORMALS;
@@ -2873,6 +2924,8 @@ static bool poly_gset_compare_fn(const void *k1, const void *k2)
* \param vtargetmap The table that maps vertices to target vertices. a value of -1
* indicates a vertex is a target, and is to be kept.
* This array is aligned with 'dm->numVertData'
+ * \warning \a vtergatmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
+ * and will likely generate corrupted geometry.
*
* \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
*
@@ -3181,7 +3234,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
med->v1 = newv[med->v1];
if (newv[med->v2] != -1)
med->v2 = newv[med->v2];
-
+
+ /* Can happen in case vtargetmap contains some double chains, we do not support that. */
+ BLI_assert(med->v1 != med->v2);
+
CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
}
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 7a3cc118eb5..bac59c8c62d 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -293,10 +293,12 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
case CURVE_PRESET_LINE:
cuma->curve[0].x = clipr->xmin;
cuma->curve[0].y = clipr->ymax;
- cuma->curve[0].flag = 0;
cuma->curve[1].x = clipr->xmax;
cuma->curve[1].y = clipr->ymin;
- cuma->curve[1].flag = 0;
+ if (slope == CURVEMAP_SLOPE_POS_NEG) {
+ cuma->curve[0].flag |= CUMA_VECTOR;
+ cuma->curve[1].flag |= CUMA_VECTOR;
+ }
break;
case CURVE_PRESET_SHARP:
cuma->curve[0].x = 0;
@@ -368,7 +370,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
MEM_freeN(cuma->curve);
cuma->curve = newpoints;
}
-
+ else if (slope == CURVEMAP_SLOPE_POS_NEG) {
+ const int num_points = cuma->totpoint * 2 - 1;
+ CurveMapPoint *new_points = MEM_mallocN(num_points * sizeof(CurveMapPoint),
+ "curve symmetric points");
+ int i;
+ for (i = 0; i < cuma->totpoint; i++) {
+ const int src_last_point = cuma->totpoint - i - 1;
+ const int dst_last_point = num_points - i - 1;
+ new_points[i] = cuma->curve[src_last_point];
+ new_points[i].x = (1.0f - cuma->curve[src_last_point].x) * 0.5f;
+ new_points[dst_last_point] = new_points[i];
+ new_points[dst_last_point].x = 0.5f + cuma->curve[src_last_point].x * 0.5f;
+ }
+ cuma->totpoint = num_points;
+ MEM_freeN(cuma->curve);
+ cuma->curve = new_points;
+ }
+
if (cuma->table) {
MEM_freeN(cuma->table);
cuma->table = NULL;
@@ -390,10 +409,19 @@ void curvemap_sethandle(CurveMap *cuma, int type)
/* *********************** Making the tables and display ************** */
-/* reduced copy of garbled calchandleNurb() code in curve.c */
-static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int UNUSED(mode))
+/**
+ * reduced copy of #calchandleNurb_intern code in curve.c
+ */
+static void calchandle_curvemap(
+ BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
{
- float *p1, *p2, *p3, pt[3];
+ /* defines to avoid confusion */
+#define p2_h1 ((p2) - 3)
+#define p2_h2 ((p2) + 3)
+
+ const float *p1, *p3;
+ float *p2;
+ float pt[3];
float len, len_a, len_b;
float dvec_a[2], dvec_b[2];
@@ -442,21 +470,24 @@ static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *nex
if (bezt->h1 == HD_AUTO) {
len_a /= len;
- madd_v2_v2v2fl(p2 - 3, p2, tvec, -len_a);
+ madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
}
if (bezt->h2 == HD_AUTO) {
len_b /= len;
- madd_v2_v2v2fl(p2 + 3, p2, tvec, len_b);
+ madd_v2_v2v2fl(p2_h2, p2, tvec, len_b);
}
}
}
if (bezt->h1 == HD_VECT) { /* vector */
- madd_v2_v2v2fl(p2 - 3, p2, dvec_a, -1.0f / 3.0f);
+ madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
}
if (bezt->h2 == HD_VECT) {
- madd_v2_v2v2fl(p2 + 3, p2, dvec_b, 1.0f / 3.0f);
+ madd_v2_v2v2fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
}
+
+#undef p2_h1
+#undef p2_h2
}
/* in X, out Y.
@@ -518,13 +549,11 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
bezt[a].h1 = bezt[a].h2 = HD_AUTO;
}
+ const BezTriple *bezt_prev = NULL;
for (a = 0; a < cuma->totpoint; a++) {
- if (a == 0)
- calchandle_curvemap(bezt, NULL, bezt + 1, 0);
- else if (a == cuma->totpoint - 1)
- calchandle_curvemap(bezt + a, bezt + a - 1, NULL, 0);
- else
- calchandle_curvemap(bezt + a, bezt + a - 1, bezt + a + 1, 0);
+ const BezTriple *bezt_next = (a != cuma->totpoint - 1) ? &bezt[a + 1] : NULL;
+ calchandle_curvemap(&bezt[a], bezt_prev, bezt_next);
+ bezt_prev = &bezt[a];
}
/* first and last handle need correction, instead of pointing to center of next/prev,
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index ed2e609ae53..dabe606fa55 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -133,7 +133,20 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda
if (ob) {
cob->ob = ob;
cob->type = datatype;
- cob->rotOrder = EULER_ORDER_DEFAULT; // TODO: when objects have rotation order too, use that
+
+ if (cob->ob->rotmode > 0) {
+ /* Should be some kind of Euler order, so use it */
+ /* NOTE: Versions <= 2.76 assumed that "default" order
+ * would always get used, so we may seem some rig
+ * breakage as a result. However, this change here
+ * is needed to fix T46599
+ */
+ cob->rotOrder = ob->rotmode;
+ }
+ else {
+ /* Quats/Axis-Angle, so Eulers should just use default order */
+ cob->rotOrder = EULER_ORDER_DEFAULT;
+ }
copy_m4_m4(cob->matrix, ob->obmat);
}
else
@@ -2717,8 +2730,8 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
float hard = min_ff(bulge, bulge_max);
float range = bulge_max - 1.0f;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
+ float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale_fac) / (float)M_PI_2;
bulge = interpf(soft, hard, data->bulge_smooth);
}
@@ -2729,8 +2742,8 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
float hard = max_ff(bulge, bulge_min);
float range = 1.0f - bulge_min;
- float scale = (range > 0.0f) ? 1.0f / range : 0.0f;
- float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
+ float scale_fac = (range > 0.0f) ? 1.0f / range : 0.0f;
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale_fac) / (float)M_PI_2;
bulge = interpf(soft, hard, data->bulge_smooth);
}
@@ -3465,7 +3478,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
/* TODO should use FLT_MAX.. but normal projection doenst yet supports it */
hit.index = -1;
- hit.dist = (scon->projLimit == 0.0f) ? 100000.0f : scon->projLimit;
+ hit.dist = (scon->projLimit == 0.0f) ? BVH_RAYCAST_DIST_MAX : scon->projLimit;
switch (scon->projAxis) {
case OB_POSX: case OB_POSY: case OB_POSZ:
@@ -3863,7 +3876,7 @@ static void pivotcon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
/* correct the pivot by the rotation axis otherwise the pivot translates when it shouldnt */
- mat3_to_axis_angle(axis, &angle, rotMat);
+ mat3_normalized_to_axis_angle(axis, &angle, rotMat);
if (angle) {
float dvec[3];
sub_v3_v3v3(vec, pivot, cob->matrix[3]);
@@ -4110,7 +4123,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
bvhtree_from_mesh_looptri(&treeData, target, 0.0f, 4, 6);
- hit.dist = FLT_MAX;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
hit.index = -1;
result = BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
@@ -4882,11 +4895,12 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
* since some constraints may not convert the solution back to the input space before blending
* but all are guaranteed to end up in good "worldspace" result
*/
- /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate, or did I miss something? -jahka (r.32105) */
+ /* Note: all kind of stuff here before (caused trouble), much easier to just interpolate,
+ * or did I miss something? -jahka (r.32105) */
if (enf < 1.0f) {
float solution[4][4];
copy_m4_m4(solution, cob->matrix);
- blend_m4_m4m4(cob->matrix, oldmat, solution, enf);
+ interp_m4_m4m4(cob->matrix, oldmat, solution, enf);
}
}
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index d223a3aff9e..5b7698544e0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -987,6 +987,16 @@ int CTX_data_selected_editable_bases(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "selected_editable_bases", list);
}
+int CTX_data_editable_objects(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "editable_objects", list);
+}
+
+int CTX_data_editable_bases(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "editable_bases", list);
+}
+
int CTX_data_selected_objects(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "selected_objects", list);
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index ac39a9f6c13..12aeadc26d3 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -74,27 +74,28 @@ void BKE_curve_unlink(Curve *cu)
int a;
for (a = 0; a < cu->totcol; a++) {
- if (cu->mat[a]) cu->mat[a]->id.us--;
+ if (cu->mat[a])
+ id_us_min(&cu->mat[a]->id);
cu->mat[a] = NULL;
}
if (cu->vfont)
- cu->vfont->id.us--;
+ id_us_min(&cu->vfont->id);
cu->vfont = NULL;
if (cu->vfontb)
- cu->vfontb->id.us--;
+ id_us_min(&cu->vfontb->id);
cu->vfontb = NULL;
if (cu->vfonti)
- cu->vfonti->id.us--;
+ id_us_min(&cu->vfonti->id);
cu->vfonti = NULL;
if (cu->vfontbi)
- cu->vfontbi->id.us--;
+ id_us_min(&cu->vfontbi->id);
cu->vfontbi = NULL;
if (cu->key)
- cu->key->id.us--;
+ id_us_min(&cu->key->id);
cu->key = NULL;
}
@@ -108,10 +109,6 @@ void BKE_curve_editfont_free(Curve *cu)
MEM_freeN(ef->textbuf);
if (ef->textbufinfo)
MEM_freeN(ef->textbufinfo);
- if (ef->copybuf)
- MEM_freeN(ef->copybuf);
- if (ef->copybufinfo)
- MEM_freeN(ef->copybufinfo);
if (ef->selboxes)
MEM_freeN(ef->selboxes);
@@ -161,15 +158,14 @@ void BKE_curve_free(Curve *cu)
MEM_freeN(cu->tb);
}
-Curve *BKE_curve_add(Main *bmain, const char *name, int type)
+void BKE_curve_init(Curve *cu)
{
- Curve *cu;
+ /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cu, id)); */ /* cu->type is already initialized... */
- cu = BKE_libblock_alloc(bmain, ID_CU, name);
copy_v3_fl(cu->size, 1.0f);
cu->flag = CU_FRONT | CU_BACK | CU_DEFORM_BOUNDS_OFF | CU_PATH_RADIUS;
cu->pathlen = 100;
- cu->resolu = cu->resolv = (type == OB_SURF) ? 4 : 12;
+ cu->resolu = cu->resolv = (cu->type == OB_SURF) ? 4 : 12;
cu->width = 1.0;
cu->wordspace = 1.0;
cu->spacing = cu->linedist = 1.0;
@@ -179,7 +175,6 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
cu->smallcaps_scale = 0.75f;
/* XXX: this one seems to be the best one in most cases, at least for curve deform... */
cu->twist_mode = CU_TWIST_MINIMUM;
- cu->type = type;
cu->bevfac1 = 0.0f;
cu->bevfac2 = 1.0f;
cu->bevfac1_mapping = CU_BEVFAC_MAP_RESOLU;
@@ -187,7 +182,7 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
cu->bb = BKE_boundbox_alloc_unit();
- if (type == OB_FONT) {
+ if (cu->type == OB_FONT) {
cu->vfont = cu->vfontb = cu->vfonti = cu->vfontbi = BKE_vfont_builtin_get();
cu->vfont->id.us += 4;
cu->str = MEM_mallocN(12, "str");
@@ -198,6 +193,16 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type)
cu->tb = MEM_callocN(MAXTEXTBOX * sizeof(TextBox), "textbox");
cu->tb[0].w = cu->tb[0].h = 0.0;
}
+}
+
+Curve *BKE_curve_add(Main *bmain, const char *name, int type)
+{
+ Curve *cu;
+
+ cu = BKE_libblock_alloc(bmain, ID_CU, name);
+ cu->type = type;
+
+ BKE_curve_init(cu);
return cu;
}
@@ -297,8 +302,8 @@ void BKE_curve_make_local(Curve *cu)
if (ob->data == cu) {
if (ob->id.lib == NULL) {
ob->data = cu_new;
- cu_new->id.us++;
- cu->id.us--;
+ id_us_plus(&cu_new->id);
+ id_us_min(&cu->id);
}
}
}
@@ -2623,7 +2628,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
BezTriple *bezt, *prevbezt;
BPoint *bp;
BevList *bl, *blnew, *blnext;
- BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
+ BevPoint *bevp2, *bevp1 = NULL, *bevp0;
const float treshold = 0.00001f;
float min, inp;
float *seglen = NULL;
@@ -2672,6 +2677,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
bl->charidx = nu->charidx;
}
else {
+ BevPoint *bevp;
+
if (for_render && cu->resolu_ren != 0)
resolu = cu->resolu_ren;
else
@@ -3003,6 +3010,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
bl = bev->first;
while (bl) {
if (bl->poly > 0) {
+ BevPoint *bevp;
min = 300000.0;
bevp = bl->bevpoints;
@@ -3112,14 +3120,17 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* ****************** HANDLES ************** */
-static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *next,
- bool is_fcurve, bool skip_align)
+static void calchandleNurb_intern(
+ BezTriple *bezt, const BezTriple *prev, const BezTriple *next,
+ bool is_fcurve, bool skip_align)
{
/* defines to avoid confusion */
#define p2_h1 ((p2) - 3)
#define p2_h2 ((p2) + 3)
- float *p1, *p2, *p3, pt[3];
+ const float *p1, *p3;
+ float *p2;
+ float pt[3];
float dvec_a[3], dvec_b[3];
float len, len_a, len_b;
float len_ratio;
@@ -4245,6 +4256,7 @@ void BKE_curve_nurb_active_set(Curve *cu, const Nurb *nu)
cu->actnu = CU_ACT_NONE;
}
else {
+ BLI_assert(!nu->hide);
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
cu->actnu = BLI_findindex(nurbs, nu);
}
@@ -4348,6 +4360,10 @@ void BKE_curve_nurb_vert_active_validate(Curve *cu)
cu->actvert = CU_ACT_NONE;
}
}
+
+ if (nu->hide) {
+ cu->actnu = CU_ACT_NONE;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index ecd809304cd..a12d5434b30 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -61,6 +61,8 @@
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
+#include "data_transfer_intern.h"
+
#include "bmesh.h"
#include <math.h>
@@ -305,13 +307,16 @@ static void layerInterp_normal(
const void **sources, const float *weights,
const float *UNUSED(sub_weights), int count, void *dest)
{
+ /* Note: This is linear interpolation, which is not optimal for vectors.
+ * Unfortunately, spherical interpolation of more than two values is hairy, so for now it will do... */
float no[3] = {0.0f};
while (count--) {
madd_v3_v3fl(no, (const float *)sources[count], weights[count]);
}
- copy_v3_v3((float *)dest, no);
+ /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */
+ normalize_v3_v3((float *)dest, no);
}
static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor)
@@ -904,6 +909,7 @@ static void layerInterp_mloopuv(
const float *sub_weights, int count, void *dest)
{
float uv[2];
+ int flag = 0;
int i;
zero_v2(uv);
@@ -911,9 +917,12 @@ static void layerInterp_mloopuv(
if (sub_weights) {
const float *sub_weight = sub_weights;
for (i = 0; i < count; i++) {
- float weight = weights ? weights[i] : 1.0f;
+ float weight = (weights ? weights[i] : 1.0f) * (*sub_weight);
const MLoopUV *src = sources[i];
- madd_v2_v2fl(uv, src->uv, (*sub_weight) * weight);
+ madd_v2_v2fl(uv, src->uv, weight);
+ if (weight > 0.0f) {
+ flag |= src->flag;
+ }
sub_weight++;
}
}
@@ -922,11 +931,15 @@ static void layerInterp_mloopuv(
float weight = weights ? weights[i] : 1;
const MLoopUV *src = sources[i];
madd_v2_v2fl(uv, src->uv, weight);
+ if (weight > 0.0f) {
+ flag |= src->flag;
+ }
}
}
/* delay writing to the destination incase dest is in sources */
copy_v2_v2(((MLoopUV *)dest)->uv, uv);
+ ((MLoopUV *)dest)->flag = flag;
}
/* origspace is almost exact copy of mloopuv's, keep in sync */
@@ -1297,7 +1310,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask), "GridPaintMask", 1, NULL, layerCopy_grid_paint_mask,
layerFree_grid_paint_mask, NULL, NULL, NULL},
- /* 36: CD_SKIN_NODE */
+ /* 36: CD_MVERT_SKIN */
{sizeof(MVertSkin), "MVertSkin", 1, NULL, NULL, NULL,
layerInterp_mvert_skin, NULL, layerDefault_mvert_skin},
/* 37: CD_FREESTYLE_EDGE */
@@ -1312,7 +1325,6 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
};
-/* note, numbers are from trunk and need updating for bmesh */
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
@@ -1361,9 +1373,16 @@ const CustomDataMask CD_MASK_BMESH =
CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
CD_MASK_CUSTOMLOOPNORMAL;
-const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */
- CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
- CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT;
+/**
+ * cover values copied by #BKE_mesh_loops_to_tessdata
+ */
+const CustomDataMask CD_MASK_FACECORNERS =
+ CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_MCOL | CD_MASK_MLOOPCOL |
+ CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP |
+ CD_MASK_TESSLOOPNORMAL | CD_MASK_NORMAL |
+ CD_MASK_TANGENT | CD_MASK_MLOOPTANGENT;
const CustomDataMask CD_MASK_EVERYTHING =
CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT |
@@ -2314,7 +2333,14 @@ void CustomData_interp(const CustomData *source, CustomData *dest,
if (count > SOURCE_BUF_SIZE) MEM_freeN((void *)sources);
}
-void CustomData_swap(struct CustomData *data, int index, const int *corner_indices)
+/**
+ * Swap data inside each item, for all layers.
+ * This only applies to item types that may store several sub-item data (e.g. corner data [UVs, VCol, ...] of
+ * tessellated faces).
+ *
+ * \param corner_indices A mapping 'new_index -> old_index' of sub-item data.
+ */
+void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
{
const LayerTypeInfo *typeInfo;
int i;
@@ -2330,6 +2356,35 @@ void CustomData_swap(struct CustomData *data, int index, const int *corner_indic
}
}
+/**
+ * Swap two items of given custom data, in all available layers.
+ */
+void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
+{
+ int i;
+ char buff_static[256];
+
+ if (index_a == index_b) {
+ return;
+ }
+
+ for (i = 0; i < data->totlayer; ++i) {
+ const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
+ const size_t size = typeInfo->size;
+ const size_t offset_a = size * index_a;
+ const size_t offset_b = size * index_b;
+
+ void *buff = size <= sizeof(buff_static) ? buff_static : MEM_mallocN(size, __func__);
+ memcpy(buff, POINTER_OFFSET(data->layers[i].data, offset_a), size);
+ memcpy(POINTER_OFFSET(data->layers[i].data, offset_a), POINTER_OFFSET(data->layers[i].data, offset_b), size);
+ memcpy(POINTER_OFFSET(data->layers[i].data, offset_b), buff, size);
+
+ if (buff != buff_static) {
+ MEM_freeN(buff);
+ }
+ }
+}
+
void *CustomData_get(const CustomData *data, int index, int type)
{
int offset;
@@ -3522,6 +3577,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
cdf = cdf_create(CDF_TYPE_MESH);
if (!cdf_read_open(cdf, filename)) {
+ cdf_free(cdf);
fprintf(stderr, "Failed to read %s layer from %s.\n", layerType_getName(layer->type), filename);
return;
}
@@ -3612,6 +3668,7 @@ void CustomData_external_write(CustomData *data, ID *id, CustomDataMask mask, in
if (!cdf_write_open(cdf, filename)) {
fprintf(stderr, "Failed to open %s for writing.\n", filename);
+ cdf_free(cdf);
return;
}
@@ -3638,6 +3695,7 @@ void CustomData_external_write(CustomData *data, ID *id, CustomDataMask mask, in
if (i != data->totlayer) {
fprintf(stderr, "Failed to write data to %s.\n", filename);
+ cdf_write_close(cdf);
cdf_free(cdf);
return;
}
@@ -3905,6 +3963,38 @@ static void customdata_data_transfer_interp_generic(
MEM_freeN(tmp_dst);
}
+/* Normals are special, we need to take care of source & destination spaces... */
+void customdata_data_transfer_interp_normal_normals(
+ const CustomDataTransferLayerMap *laymap, void *data_dst,
+ const void **sources, const float *weights, const int count,
+ const float mix_factor)
+{
+ const int data_type = laymap->data_type;
+ const int mix_mode = laymap->mix_mode;
+
+ SpaceTransform *space_transform = laymap->interp_data;
+
+ const LayerTypeInfo *type_info = layerType_getInfo(data_type);
+ cd_interp interp_cd = type_info->interp;
+
+ float tmp_dst[3];
+
+ BLI_assert(data_type == CD_NORMAL);
+
+ if (!sources) {
+ /* Not supported here, abort. */
+ return;
+ }
+
+ interp_cd(sources, weights, NULL, count, tmp_dst);
+ if (space_transform) {
+ /* tmp_dst is in source space so far, bring it back in destination space. */
+ BLI_space_transform_invert_normal(space_transform, tmp_dst);
+ }
+
+ CustomData_data_mix_value(data_type, tmp_dst, data_dst, mix_mode, mix_factor);
+}
+
void CustomData_data_transfer(const MeshPairRemap *me_remap, const CustomDataTransferLayerMap *laymap)
{
MeshPairRemapItem *mapit = me_remap->items;
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 53b6f4a1019..1dcacc3ae0a 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -42,6 +42,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
@@ -291,7 +292,7 @@ static void data_transfer_dtdata_type_preprocess(
poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst,
+ BKE_mesh_calc_normals_poly(verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
num_loops_dst, num_polys_dst, poly_nors_dst, true);
}
/* Cache loop nors into a temp CDLayer. */
@@ -356,7 +357,6 @@ static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int c
switch (cddata_type) {
case CD_FAKE_UV:
return BKE_mesh_calc_islands_loop_poly_uv;
- break;
default:
break;
}
@@ -428,7 +428,7 @@ void data_transfer_layersmapping_add_item(
ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n,
const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag,
- cd_datatransfer_interp interp)
+ cd_datatransfer_interp interp, void *interp_data)
{
CustomDataTransferLayerMap *item = MEM_mallocN(sizeof(*item), __func__);
@@ -450,17 +450,18 @@ void data_transfer_layersmapping_add_item(
item->data_flag = data_flag;
item->interp = interp;
+ item->interp_data = interp_data;
BLI_addtail(r_map, item);
}
static void data_transfer_layersmapping_add_item_cd(
ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
- void *data_src, void *data_dst)
+ void *data_src, void *data_dst, cd_datatransfer_interp interp, void *interp_data)
{
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst,
- 0, 0, 0, 0, 0, 0, NULL);
+ 0, 0, 0, 0, 0, 0, interp, interp_data);
}
/* Note: All those layer mapping handlers return false *only* if they were given invalid parameters.
@@ -473,7 +474,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
const int num_elem_dst, const bool use_create, const bool use_delete,
CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
- const int tolayers, bool *use_layers_src, const int num_layers_src)
+ const int tolayers, bool *use_layers_src, const int num_layers_src,
+ cd_datatransfer_interp interp, void *interp_data)
{
void *data_src, *data_dst = NULL;
int idx_src = num_layers_src;
@@ -527,7 +529,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_src);
}
data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- data_src, data_dst);
+ data_src, data_dst, interp, interp_data);
}
}
break;
@@ -571,7 +573,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
data_dst = CustomData_get_layer_n(cd_dst, cddata_type, idx_dst);
}
data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- data_src, data_dst);
+ data_src, data_dst, interp, interp_data);
}
}
@@ -599,7 +601,8 @@ static bool data_transfer_layersmapping_cdlayers(
ListBase *r_map, const int cddata_type, const int mix_mode, const float mix_factor, const float *mix_weights,
const int num_elem_dst, const bool use_create, const bool use_delete,
CustomData *cd_src, CustomData *cd_dst, const bool use_dupref_dst,
- const int fromlayers, const int tolayers)
+ const int fromlayers, const int tolayers,
+ cd_datatransfer_interp interp, void *interp_data)
{
int idx_src, idx_dst;
void *data_src, *data_dst = NULL;
@@ -626,7 +629,7 @@ static bool data_transfer_layersmapping_cdlayers(
if (r_map) {
data_transfer_layersmapping_add_item_cd(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- data_src, data_dst);
+ data_src, data_dst, interp, interp_data);
}
}
else if (fromlayers == DT_LAYERS_ACTIVE_SRC || fromlayers >= 0) {
@@ -719,7 +722,7 @@ static bool data_transfer_layersmapping_cdlayers(
if (r_map) {
data_transfer_layersmapping_add_item_cd(
- r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst);
+ r_map, cddata_type, mix_mode, mix_factor, mix_weights, data_src, data_dst, interp, interp_data);
}
}
else if (fromlayers == DT_LAYERS_ALL_SRC) {
@@ -734,7 +737,8 @@ static bool data_transfer_layersmapping_cdlayers(
ret = data_transfer_layersmapping_cdlayers_multisrc_to_dst(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete, cd_src, cd_dst, use_dupref_dst,
- tolayers, use_layers_src, num_src);
+ tolayers, use_layers_src, num_src,
+ interp, interp_data);
if (use_layers_src) {
MEM_freeN(use_layers_src);
@@ -751,10 +755,14 @@ static bool data_transfer_layersmapping_cdlayers(
static bool data_transfer_layersmapping_generate(
ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights,
- const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers)
+ const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers,
+ SpaceTransform *space_transform)
{
CustomData *cd_src, *cd_dst;
+ cd_datatransfer_interp interp = NULL;
+ void *interp_data = NULL;
+
if (elem_type == ME_VERT) {
if (!(cddata_type & CD_FAKE)) {
cd_src = dm_src->getVertDataLayout(dm_src);
@@ -763,7 +771,8 @@ static bool data_transfer_layersmapping_generate(
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
cd_src, cd_dst, dm_dst != NULL,
- fromlayers, tolayers))
+ fromlayers, tolayers,
+ interp, interp_data))
{
/* We handle specific source selection cases here. */
return false;
@@ -795,7 +804,7 @@ static bool data_transfer_layersmapping_generate(
dm_src->getNumVerts(dm_src),
dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert,
elem_size, data_size, data_offset, data_flag,
- data_transfer_interp_char);
+ data_transfer_interp_char, interp_data);
}
return true;
}
@@ -827,7 +836,8 @@ static bool data_transfer_layersmapping_generate(
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
cd_src, cd_dst, dm_dst != NULL,
- fromlayers, tolayers))
+ fromlayers, tolayers,
+ interp, interp_data))
{
/* We handle specific source selection cases here. */
return false;
@@ -859,7 +869,7 @@ static bool data_transfer_layersmapping_generate(
dm_src->getNumEdges(dm_src),
dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
- data_transfer_interp_char);
+ data_transfer_interp_char, interp_data);
}
return true;
}
@@ -888,7 +898,7 @@ static bool data_transfer_layersmapping_generate(
dm_src->getNumEdges(dm_src),
dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
- data_transfer_interp_char);
+ data_transfer_interp_char, interp_data);
}
return true;
}
@@ -904,7 +914,7 @@ static bool data_transfer_layersmapping_generate(
dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
dm_src->getNumEdges(dm_src),
dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
- elem_size, data_size, data_offset, data_flag, NULL);
+ elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
else {
@@ -918,6 +928,8 @@ static bool data_transfer_layersmapping_generate(
else if (cddata_type == CD_FAKE_LNOR) {
/* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */
cddata_type = CD_NORMAL;
+ interp_data = space_transform;
+ interp = customdata_data_transfer_interp_normal_normals;
}
if (!(cddata_type & CD_FAKE)) {
@@ -927,7 +939,8 @@ static bool data_transfer_layersmapping_generate(
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
- fromlayers, tolayers))
+ fromlayers, tolayers,
+ interp, interp_data))
{
/* We handle specific source selection cases here. */
return false;
@@ -950,7 +963,8 @@ static bool data_transfer_layersmapping_generate(
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
- fromlayers, tolayers))
+ fromlayers, tolayers,
+ interp, interp_data))
{
/* We handle specific source selection cases here. */
return false;
@@ -969,7 +983,7 @@ static bool data_transfer_layersmapping_generate(
dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly,
dm_src->getNumPolys(dm_src),
dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly,
- elem_size, data_size, data_offset, data_flag, NULL);
+ elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
else {
@@ -1035,28 +1049,28 @@ void BKE_object_data_transfer_layout(
data_transfer_layersmapping_generate(
NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+ num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
const int num_elem_dst = me_dst->totedge;
data_transfer_layersmapping_generate(
NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+ num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
const int num_elem_dst = me_dst->totloop;
data_transfer_layersmapping_generate(
NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+ num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
const int num_elem_dst = me_dst->totpoly;
data_transfer_layersmapping_generate(
NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
- num_elem_dst, use_create, use_delete, fromlayers, tolayers);
+ num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
}
}
@@ -1122,11 +1136,15 @@ bool BKE_object_data_transfer_dm(
/* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm,
* can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers...
* Issue is, this means we cannot be sure to have requested cd layers in source.
+ *
+ * Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation
+ * of data in it (multi-threaded evaluation of the modifier stack, see T46672).
*/
dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask);
if (!dm_src) {
return changed;
}
+ dm_src = CDDM_copy(dm_src);
if (auto_transform) {
MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
@@ -1176,12 +1194,12 @@ bool BKE_object_data_transfer_dm(
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of vertices, "
"'Topology' mapping cannot be used in this case");
- return changed;
+ continue;
}
if (ELEM(0, num_verts_dst, num_verts_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any vertices, cannot transfer vertex data");
- return changed;
+ continue;
}
BKE_mesh_remap_calc_verts_from_dm(
@@ -1198,7 +1216,7 @@ bool BKE_object_data_transfer_dm(
if (data_transfer_layersmapping_generate(
&lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT,
cddata_type, mix_mode, mix_factor, weights[VDATA],
- num_verts_dst, use_create, use_delete, fromlayers, tolayers))
+ num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
CustomDataTransferLayerMap *lay_mapit;
@@ -1224,12 +1242,12 @@ bool BKE_object_data_transfer_dm(
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of edges, "
"'Topology' mapping cannot be used in this case");
- return changed;
+ continue;
}
if (ELEM(0, num_edges_dst, num_edges_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any edges, cannot transfer edge data");
- return changed;
+ continue;
}
BKE_mesh_remap_calc_edges_from_dm(
@@ -1249,7 +1267,7 @@ bool BKE_object_data_transfer_dm(
if (data_transfer_layersmapping_generate(
&lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE,
cddata_type, mix_mode, mix_factor, weights[EDATA],
- num_edges_dst, use_create, use_delete, fromlayers, tolayers))
+ num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
CustomDataTransferLayerMap *lay_mapit;
@@ -1283,12 +1301,12 @@ bool BKE_object_data_transfer_dm(
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of face corners, "
"'Topology' mapping cannot be used in this case");
- return changed;
+ continue;
}
if (ELEM(0, num_loops_dst, num_loops_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any polygons, cannot transfer loop data");
- return changed;
+ continue;
}
BKE_mesh_remap_calc_loops_from_dm(
@@ -1312,7 +1330,7 @@ bool BKE_object_data_transfer_dm(
if (data_transfer_layersmapping_generate(
&lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP,
cddata_type, mix_mode, mix_factor, weights[LDATA],
- num_loops_dst, use_create, use_delete, fromlayers, tolayers))
+ num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
CustomDataTransferLayerMap *lay_mapit;
@@ -1341,12 +1359,12 @@ bool BKE_object_data_transfer_dm(
BKE_report(reports, RPT_ERROR,
"Source and destination meshes do not have the same amount of faces, "
"'Topology' mapping cannot be used in this case");
- return changed;
+ continue;
}
if (ELEM(0, num_polys_dst, num_polys_src)) {
BKE_report(reports, RPT_ERROR,
"Source or destination meshes do not have any polygons, cannot transfer poly data");
- return changed;
+ continue;
}
BKE_mesh_remap_calc_polys_from_dm(
@@ -1367,7 +1385,7 @@ bool BKE_object_data_transfer_dm(
if (data_transfer_layersmapping_generate(
&lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY,
cddata_type, mix_mode, mix_factor, weights[PDATA],
- num_polys_dst, use_create, use_delete, fromlayers, tolayers))
+ num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
CustomDataTransferLayerMap *lay_mapit;
@@ -1388,6 +1406,7 @@ bool BKE_object_data_transfer_dm(
BKE_mesh_remap_free(&geom_map[i]);
MEM_SAFE_FREE(weights[i]);
}
+ dm_src->release(dm_src);
return changed;
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index 501b749b464..352eedc6ec2 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -45,7 +45,7 @@ void data_transfer_layersmapping_add_item(
const float mix_factor, const float *mix_weights,
const void *data_src, void *data_dst, const int data_src_n, const int data_dst_n,
const size_t elem_size, const size_t data_size, const size_t data_offset, const uint64_t data_flag,
- cd_datatransfer_interp interp);
+ cd_datatransfer_interp interp, void *interp_data);
/* Type-specific. */
@@ -55,4 +55,10 @@ bool data_transfer_layersmapping_vgroups(
struct Object *ob_src, struct Object *ob_dst, struct CustomData *cd_src, struct CustomData *cd_dst,
const bool use_dupref_dst, const int fromlayers, const int tolayers);
+/* Defined in customdata.c */
+void customdata_data_transfer_interp_normal_normals(
+ const CustomDataTransferLayerMap *laymap, void *data_dst,
+ const void **sources, const float *weights, const int count,
+ const float mix_factor);
+
#endif /* __DATA_TRANSFER_INTERN_H__ */
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 6670c3359d7..7052e0a7d25 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -107,17 +107,37 @@ bDeformGroup *defgroup_duplicate(bDeformGroup *ingroup)
return outgroup;
}
-/* overwrite weights filtered by vgroup_subset
+/**
+ * Overwrite weights filtered by vgroup_subset.
* - do nothing if neither are set.
* - add destination weight if needed
*/
-void defvert_copy_subset(MDeformVert *dvert_dst, const MDeformVert *dvert_src,
- const bool *vgroup_subset, const int vgroup_tot)
+void defvert_copy_subset(
+ MDeformVert *dvert_dst, const MDeformVert *dvert_src,
+ const bool *vgroup_subset, const int vgroup_tot)
{
int defgroup;
for (defgroup = 0; defgroup < vgroup_tot; defgroup++) {
if (vgroup_subset[defgroup]) {
- defvert_copy_index(dvert_dst, dvert_src, defgroup);
+ defvert_copy_index(dvert_dst, defgroup, dvert_src, defgroup);
+ }
+ }
+}
+
+/**
+ * Overwrite weights filtered by vgroup_subset and with mirroring specified by the flip map
+ * - do nothing if neither are set.
+ * - add destination weight if needed
+ */
+void defvert_mirror_subset(
+ MDeformVert *dvert_dst, const MDeformVert *dvert_src,
+ const bool *vgroup_subset, const int vgroup_tot,
+ const int *flip_map, const int flip_map_len)
+{
+ int defgroup;
+ for (defgroup = 0; defgroup < vgroup_tot && defgroup < flip_map_len; defgroup++) {
+ if (vgroup_subset[defgroup] && (dvert_dst != dvert_src || flip_map[defgroup] != defgroup)) {
+ defvert_copy_index(dvert_dst, flip_map[defgroup], dvert_src, defgroup);
}
}
}
@@ -141,24 +161,27 @@ void defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
}
}
-/* copy an index from one dvert to another
+/**
+ * Copy an index from one dvert to another.
* - do nothing if neither are set.
* - add destination weight if needed.
*/
-void defvert_copy_index(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const int defgroup)
+void defvert_copy_index(
+ MDeformVert *dvert_dst, const int defgroup_dst,
+ const MDeformVert *dvert_src, const int defgroup_src)
{
MDeformWeight *dw_src, *dw_dst;
- dw_src = defvert_find_index(dvert_src, defgroup);
+ dw_src = defvert_find_index(dvert_src, defgroup_src);
if (dw_src) {
/* source is valid, verify destination */
- dw_dst = defvert_verify_index(dvert_dst, defgroup);
+ dw_dst = defvert_verify_index(dvert_dst, defgroup_dst);
dw_dst->weight = dw_src->weight;
}
else {
/* source was NULL, assign zero, could also remove */
- dw_dst = defvert_find_index(dvert_dst, defgroup);
+ dw_dst = defvert_find_index(dvert_dst, defgroup_dst);
if (dw_dst) {
dw_dst->weight = 0.0f;
@@ -166,7 +189,8 @@ void defvert_copy_index(MDeformVert *dvert_dst, const MDeformVert *dvert_src, co
}
}
-/* only sync over matching weights, don't add or remove groups
+/**
+ * Only sync over matching weights, don't add or remove groups
* warning, loop within loop.
*/
void defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bool use_verify)
@@ -186,9 +210,12 @@ void defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const bo
}
}
-/* be sure all flip_map values are valid */
-void defvert_sync_mapped(MDeformVert *dvert_dst, const MDeformVert *dvert_src,
- const int *flip_map, const int flip_map_len, const bool use_verify)
+/**
+ * be sure all flip_map values are valid
+ */
+void defvert_sync_mapped(
+ MDeformVert *dvert_dst, const MDeformVert *dvert_src,
+ const int *flip_map, const int flip_map_len, const bool use_verify)
{
if (dvert_src->totweight && dvert_dst->totweight) {
int i;
@@ -207,7 +234,9 @@ void defvert_sync_mapped(MDeformVert *dvert_dst, const MDeformVert *dvert_src,
}
}
-/* be sure all flip_map values are valid */
+/**
+ * be sure all flip_map values are valid
+ */
void defvert_remap(MDeformVert *dvert, int *map, const int map_len)
{
MDeformWeight *dw = dvert->dw;
@@ -291,10 +320,13 @@ void defvert_normalize(MDeformVert *dvert)
}
}
-/* Same as defvert_normalize() if the locked vgroup is not a member of the subset */
-void defvert_normalize_lock_single(MDeformVert *dvert,
- const bool *vgroup_subset, const int vgroup_tot,
- const int def_nr_lock)
+/**
+ * Same as defvert_normalize() if the locked vgroup is not a member of the subset
+ */
+void defvert_normalize_lock_single(
+ MDeformVert *dvert,
+ const bool *vgroup_subset, const int vgroup_tot,
+ const int def_nr_lock)
{
if (dvert->totweight == 0) {
/* nothing */
@@ -345,7 +377,9 @@ void defvert_normalize_lock_single(MDeformVert *dvert,
}
}
-/* Same as defvert_normalize() if no locked vgroup is a member of the subset */
+/**
+ * Same as defvert_normalize() if no locked vgroup is a member of the subset
+ */
void defvert_normalize_lock_map(
MDeformVert *dvert,
const bool *vgroup_subset, const int vgroup_tot,
@@ -357,7 +391,7 @@ void defvert_normalize_lock_map(
else if (dvert->totweight == 1) {
MDeformWeight *dw = dvert->dw;
if ((dw->def_nr < vgroup_tot) && vgroup_subset[dw->def_nr]) {
- if (LIKELY(defbase_tot >= 1) && lock_flags[0]) {
+ if ((dw->def_nr < defbase_tot) && (lock_flags[dw->def_nr] == false)) {
dw->weight = 1.0f;
}
}
@@ -449,7 +483,9 @@ int defgroup_name_index(Object *ob, const char *name)
return (name) ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : -1;
}
-/* note, must be freed */
+/**
+ * \note caller must free.
+ */
int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
{
int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
@@ -488,7 +524,9 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default)
}
}
-/* note, must be freed */
+/**
+ * \note caller must free.
+ */
int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_default, int defgroup)
{
int defbase_tot = *flip_map_len = BLI_listbase_count(&ob->defbase);
@@ -573,8 +611,10 @@ static bool is_char_sep(const char c)
return ELEM(c, '.', ' ', '-', '_');
}
-/* based on BLI_split_dirfile() / os.path.splitext(), "a.b.c" -> ("a.b", ".c") */
-
+/**
+ * based on `BLI_split_dirfile()` / `os.path.splitext()`,
+ * `"a.b.c"` -> (`"a.b"`, `".c"`).
+ */
void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME])
{
size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
@@ -593,7 +633,9 @@ void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_V
memcpy(body, string, len + 1);
}
-/* "a.b.c" -> ("a.", "b.c") */
+/**
+ * `"a.b.c"` -> (`"a."`, `"b.c"`)
+ */
void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME])
{
size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
@@ -613,9 +655,13 @@ void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VG
BLI_strncpy(body, string, len);
}
-/* finds the best possible flipped name. For renaming; check for unique names afterwards */
-/* if strip_number: removes number extensions
- * note: don't use sizeof() for 'name' or 'from_name' */
+/**
+ * Finds the best possible flipped name. For renaming; check for unique names afterwards.
+ *
+ * if strip_number: removes number extensions
+ *
+ * \note don't use sizeof() for 'name' or 'from_name'.
+ */
void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME],
const bool strip_number)
{
@@ -745,7 +791,8 @@ float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
return dw ? dw->weight : 0.0f;
}
-/* take care with this the rationale is:
+/**
+ * Take care with this the rationale is:
* - if the object has no vertex group. act like vertex group isn't set and return 1.0,
* - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0
*
@@ -779,8 +826,11 @@ MDeformWeight *defvert_find_index(const MDeformVert *dvert, const int defgroup)
return NULL;
}
-/* Ensures that mv has a deform weight entry for the specified defweight group */
-/* Note this function is mirrored in editmesh_tools.c, for use for editvertices */
+/**
+ * Ensures that mv has a deform weight entry for the specified defweight group.
+ *
+ * \note this function is mirrored in editmesh_tools.c, for use for editvertices.
+ */
MDeformWeight *defvert_verify_index(MDeformVert *dvert, const int defgroup)
{
MDeformWeight *dw_new;
@@ -813,8 +863,11 @@ MDeformWeight *defvert_verify_index(MDeformVert *dvert, const int defgroup)
/* TODO. merge with code above! */
-/* Adds the given vertex to the specified vertex group, with given weight.
- * warning, this does NOT check for existing, assume caller already knows its not there */
+/**
+ * Adds the given vertex to the specified vertex group, with given weight.
+ *
+ * \warning this does NOT check for existing, assume caller already knows its not there.
+ */
void defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
{
MDeformWeight *dw_new;
@@ -838,8 +891,11 @@ void defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weig
}
-/* Removes the given vertex from the vertex group.
- * WARNING: This function frees the given MDeformWeight, do not use it afterward! */
+/**
+ * Removes the given vertex from the vertex group.
+ *
+ * \warning This function frees the given MDeformWeight, do not use it afterward!
+ */
void defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
{
if (dvert && dw) {
@@ -919,8 +975,45 @@ bool defvert_is_weight_zero(const struct MDeformVert *dvert, const int defgroup_
return true;
}
+
+/**
+ * \return The representative weight of a multipaint group, used for
+ * viewport colors and actual painting.
+ *
+ * Result equal to sum of weights with auto normalize, and average otherwise.
+ * Value is not clamped, since painting relies on multiplication being always
+ * commutative with the collective weight function.
+ */
+float BKE_defvert_multipaint_collective_weight(
+ const struct MDeformVert *dv, int defbase_tot,
+ const bool *defbase_sel, int defbase_tot_sel, bool do_autonormalize)
+{
+ int i;
+ float total = 0.0f;
+ const MDeformWeight *dw = dv->dw;
+
+ for (i = dv->totweight; i != 0; i--, dw++) {
+ /* in multipaint, get the average if auto normalize is inactive
+ * get the sum if it is active */
+ if (dw->def_nr < defbase_tot) {
+ if (defbase_sel[dw->def_nr]) {
+ total += dw->weight;
+ }
+ }
+ }
+
+ if (do_autonormalize == false) {
+ total /= defbase_tot_sel;
+ }
+
+ return total;
+}
+
+
/* -------------------------------------------------------------------- */
-/* Defvert Array functions */
+
+/** \name Defvert Array functions
+ * \{ */
void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int copycount)
{
@@ -987,9 +1080,10 @@ void BKE_defvert_extract_vgroup_to_vertweights(
}
}
-/* The following three make basic interpolation, using temp vert_weights array to avoid looking up same weight
- * several times. */
-
+/**
+ * The following three make basic interpolation,
+ * using temp vert_weights array to avoid looking up same weight several times.
+ */
void BKE_defvert_extract_vgroup_to_edgeweights(
MDeformVert *dvert, const int defgroup, const int num_verts, MEdge *edges, const int num_edges,
float *r_weights, const bool invert_vgroup)
@@ -1065,7 +1159,13 @@ void BKE_defvert_extract_vgroup_to_polyweights(
}
}
-/*********** Data Transfer **********/
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Data Transfer
+ * \{ */
static void vgroups_datatransfer_interp(
const CustomDataTransferLayerMap *laymap, void *dest,
@@ -1163,7 +1263,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(
}
data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
data_src, data_dst, idx_src, idx_src,
- elem_size, 0, 0, 0, vgroups_datatransfer_interp);
+ elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
}
}
break;
@@ -1211,7 +1311,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(
data_transfer_layersmapping_add_item(
r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
data_src, data_dst, idx_src, idx_dst,
- elem_size, 0, 0, 0, vgroups_datatransfer_interp);
+ elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
}
}
break;
@@ -1317,7 +1417,7 @@ bool data_transfer_layersmapping_vgroups(
data_transfer_layersmapping_add_item(r_map, CD_FAKE_MDEFORMVERT, mix_mode, mix_factor, mix_weights,
data_src, data_dst, idx_src, idx_dst,
- elem_size, 0, 0, 0, vgroups_datatransfer_interp);
+ elem_size, 0, 0, 0, vgroups_datatransfer_interp, NULL);
}
}
else {
@@ -1353,3 +1453,5 @@ bool data_transfer_layersmapping_vgroups(
return true;
}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 4373e797dfe..a029c8c7748 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -398,13 +398,13 @@ static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *no
static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma)
{
/* Prevent infinite recursion by checking (and tagging the material) as having been visited
- * already (see build_dag()). This assumes ma->id.flag & LIB_DOIT isn't set by anything else
+ * already (see build_dag()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else
* in the meantime... [#32017]
*/
- if (ma->id.flag & LIB_DOIT)
+ if (ma->id.tag & LIB_TAG_DOIT)
return;
- ma->id.flag |= LIB_DOIT;
+ ma->id.tag |= LIB_TAG_DOIT;
/* material itself */
if (ma->adt)
@@ -418,20 +418,20 @@ static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Mat
if (ma->nodetree)
dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree);
- ma->id.flag &= ~LIB_DOIT;
+ ma->id.tag &= ~LIB_TAG_DOIT;
}
/* recursive handling for lamp drivers */
static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la)
{
/* Prevent infinite recursion by checking (and tagging the lamp) as having been visited
- * already (see build_dag()). This assumes la->id.flag & LIB_DOIT isn't set by anything else
+ * already (see build_dag()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else
* in the meantime... [#32017]
*/
- if (la->id.flag & LIB_DOIT)
+ if (la->id.tag & LIB_TAG_DOIT)
return;
- la->id.flag |= LIB_DOIT;
+ la->id.tag |= LIB_TAG_DOIT;
/* lamp itself */
if (la->adt)
@@ -445,7 +445,7 @@ static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *l
if (la->nodetree)
dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree);
- la->id.flag &= ~LIB_DOIT;
+ la->id.tag &= ~LIB_TAG_DOIT;
}
static void check_and_create_collision_relation(DagForest *dag, Object *ob, DagNode *node, Object *ob1, int skip_forcefield, bool no_collision)
@@ -513,7 +513,6 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
}
/* also build a custom data mask for dependencies that need certain layers */
- node->customdata_mask = 0;
if (ob->type == OB_ARMATURE) {
if (ob->pose) {
@@ -765,6 +764,10 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc
ListBase *effectors = NULL;
EffectorCache *eff;
+ if (part->adt) {
+ dag_add_driver_relation(part->adt, dag, node, 1);
+ }
+
dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
if (!psys_check_enabled(ob, psys))
@@ -904,10 +907,10 @@ static void build_dag_group(DagForest *dag, DagNode *scenenode, Main *bmain, Sce
{
GroupObject *go;
- if (group->id.flag & LIB_DOIT)
+ if (group->id.tag & LIB_TAG_DOIT)
return;
- group->id.flag |= LIB_DOIT;
+ group->id.tag |= LIB_TAG_DOIT;
for (go = group->gobject.first; go; go = go->next) {
build_dag_object(dag, scenenode, bmain, scene, go->ob, mask);
@@ -932,11 +935,12 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
dag = dag_init();
sce->theDag = dag;
}
-
- /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */
- BKE_main_id_tag_idcode(bmain, ID_MA, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, false);
- BKE_main_id_tag_idcode(bmain, ID_GR, false);
+ dag->need_update = false;
+
+ /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */
+ BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
/* add base node for scene. scene is always the first node in DAG */
scenenode = dag_add_node(dag, sce);
@@ -952,7 +956,7 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask)
build_dag_group(dag, scenenode, bmain, sce, ob->dup_group, mask);
}
- BKE_main_id_tag_idcode(bmain, ID_GR, false);
+ BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
/* Now all relations were built, but we need to solve 1 exceptional case;
* When objects have multiple "parents" (for example parent + constraint working on same object)
@@ -1140,7 +1144,7 @@ void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel
/* TODO(sergey): Find a better place for this. */
#ifdef WITH_OPENSUBDIV
- if ((rel & DAG_RL_DATA_DATA) != 0) {
+ if ((rel & (DAG_RL_DATA_DATA | DAG_RL_DATA_OB)) != 0) {
if (fob1->type == ID_OB) {
if ((fob1->eval_flags & DAG_EVAL_NEED_CPU) == 0) {
Object *ob2 = fob2->ob;
@@ -1403,15 +1407,15 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
/* test; are group objects all in this scene? */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->id.flag &= ~LIB_DOIT;
+ ob->id.tag &= ~LIB_TAG_DOIT;
ob->id.newid = NULL; /* newid abuse for GroupObject */
}
for (base = sce->base.first; base; base = base->next)
- base->object->id.flag |= LIB_DOIT;
+ base->object->id.tag |= LIB_TAG_DOIT;
for (group = bmain->group.first; group; group = group->id.next) {
for (go = group->gobject.first; go; go = go->next) {
- if ((go->ob->id.flag & LIB_DOIT) == 0)
+ if ((go->ob->id.tag & LIB_TAG_DOIT) == 0)
break;
}
/* this group is entirely in this scene */
@@ -1437,6 +1441,13 @@ static void scene_sort_groups(Main *bmain, Scene *sce)
}
}
+static void dag_scene_tag_rebuild(Scene *sce)
+{
+ if (sce->theDag) {
+ sce->theDag->need_update = true;
+ }
+}
+
/* free the depency graph */
static void dag_scene_free(Scene *sce)
{
@@ -1447,7 +1458,7 @@ static void dag_scene_free(Scene *sce)
}
}
-/* Chech whether object data needs to be evaluated before it
+/* Check whether object data needs to be evaluated before it
* might be used by others.
*
* Means that mesh object needs to have proper derivedFinal,
@@ -1482,7 +1493,7 @@ static bool check_object_tagged_for_update(Object *object)
if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
ID *data_id = object->data;
- return (data_id->flag & (LIB_ID_RECALC_DATA | LIB_ID_RECALC)) != 0;
+ return (data_id->tag & (LIB_TAG_ID_RECALC_DATA | LIB_TAG_ID_RECALC)) != 0;
}
return false;
@@ -1579,7 +1590,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
BLI_listbase_clear(&tempbase);
build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
-
+
dag_check_cycle(sce->theDag);
nqueue = queue_create(DAGQUEUEALLOC);
@@ -1656,10 +1667,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
}
}
- /* temporal...? */
- sce->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */
-
- /* Make sure that new dependencies which came from invisble layers
+ /* Make sure that new dependencies which came from invisible layers
* are tagged for update (if they're needed for objects which were
* tagged for update).
*/
@@ -1672,7 +1680,7 @@ void DAG_relations_tag_update(Main *bmain)
if (DEG_depsgraph_use_legacy()) {
Scene *sce;
for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- dag_scene_free(sce);
+ dag_scene_tag_rebuild(sce);
}
}
else {
@@ -1698,7 +1706,7 @@ void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
void DAG_scene_relations_update(Main *bmain, Scene *sce)
{
if (DEG_depsgraph_use_legacy()) {
- if (!sce->theDag)
+ if (!sce->theDag || sce->theDag->need_update)
dag_scene_build(bmain, sce);
}
else {
@@ -1733,13 +1741,13 @@ void DAG_scene_free(Scene *sce)
static void lib_id_recalc_tag(Main *bmain, ID *id)
{
- id->flag |= LIB_ID_RECALC;
+ id->tag |= LIB_TAG_ID_RECALC;
DAG_id_type_tag(bmain, GS(id->name));
}
static void lib_id_recalc_data_tag(Main *bmain, ID *id)
{
- id->flag |= LIB_ID_RECALC_DATA;
+ id->tag |= LIB_TAG_ID_RECALC_DATA;
DAG_id_type_tag(bmain, GS(id->name));
}
@@ -1975,7 +1983,7 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
return;
}
- if (sce->theDag == NULL) {
+ if (sce->theDag == NULL || sce->theDag->need_update) {
printf("DAG zero... not allowed to happen!\n");
DAG_scene_relations_update(bmain, sce);
}
@@ -2266,10 +2274,10 @@ static void dag_group_update_flags(Main *bmain, Scene *scene, Group *group, cons
{
GroupObject *go;
- if (group->id.flag & LIB_DOIT)
+ if (group->id.tag & LIB_TAG_DOIT)
return;
- group->id.flag |= LIB_DOIT;
+ group->id.tag |= LIB_TAG_DOIT;
for (go = group->gobject.first; go; go = go->next) {
if (do_time)
@@ -2289,7 +2297,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const b
GroupObject *go;
Scene *sce_iter;
- BKE_main_id_tag_idcode(bmain, ID_GR, false);
+ BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
/* set ob flags where animated systems are */
for (SETLOOPER(scene, sce_iter, base)) {
@@ -2305,7 +2313,7 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const b
dag_object_time_update_flags(bmain, sce_iter, ob);
}
- /* recursively tag groups with LIB_DOIT, and update flags for objects */
+ /* recursively tag groups with LIB_TAG_DOIT, and update flags for objects */
if (ob->dup_group)
dag_group_update_flags(bmain, scene, ob->dup_group, do_time);
}
@@ -2328,12 +2336,12 @@ void DAG_scene_update_flags(Main *bmain, Scene *scene, unsigned int lay, const b
/* and store the info in groupobject */
for (group = bmain->group.first; group; group = group->id.next) {
- if (group->id.flag & LIB_DOIT) {
+ if (group->id.tag & LIB_TAG_DOIT) {
for (go = group->gobject.first; go; go = go->next) {
go->recalc = go->ob->recalc;
// printf("ob %s recalc %d\n", go->ob->id.name, go->recalc);
}
- group->id.flag &= ~LIB_DOIT;
+ group->id.tag &= ~LIB_TAG_DOIT;
}
}
@@ -2360,14 +2368,14 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
/* if we have a windowmanager, look into windows */
if ((wm = bmain->wm.first)) {
- BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, 1);
+ BKE_main_id_flag_listbase(&bmain->scene, LIB_TAG_DOIT, 1);
for (win = wm->windows.first; win; win = win->next) {
if (win->screen && win->screen->scene->theDag) {
Scene *scene = win->screen->scene;
DagSceneLayer *dsl;
- if (scene->id.flag & LIB_DOIT) {
+ if (scene->id.tag & LIB_TAG_DOIT) {
dsl = MEM_mallocN(sizeof(DagSceneLayer), "dag scene layer");
BLI_addtail(lb, dsl);
@@ -2375,7 +2383,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
dsl->scene = scene;
dsl->layer = BKE_screen_visible_layers(win->screen, scene);
- scene->id.flag &= ~LIB_DOIT;
+ scene->id.tag &= ~LIB_TAG_DOIT;
}
else {
/* It is possible that multiple windows shares the same scene
@@ -2417,20 +2425,20 @@ static void dag_group_on_visible_update(Scene *scene, Group *group)
{
GroupObject *go;
- if (group->id.flag & LIB_DOIT)
+ if (group->id.tag & LIB_TAG_DOIT)
return;
- group->id.flag |= LIB_DOIT;
+ group->id.tag |= LIB_TAG_DOIT;
for (go = group->gobject.first; go; go = go->next) {
if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
go->ob->recalc |= OB_RECALC_DATA;
- go->ob->id.flag |= LIB_DOIT;
+ go->ob->id.tag |= LIB_TAG_DOIT;
lib_id_recalc_tag(G.main, &go->ob->id);
}
if (go->ob->proxy_from) {
go->ob->recalc |= OB_RECALC_OB;
- go->ob->id.flag |= LIB_DOIT;
+ go->ob->id.tag |= LIB_TAG_DOIT;
lib_id_recalc_tag(G.main, &go->ob->id);
}
@@ -2468,7 +2476,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
dag_scene_flush_layers(sce_iter, lay);
- BKE_main_id_tag_idcode(bmain, ID_GR, false);
+ BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
for (SETLOOPER(scene, sce_iter, base)) {
ob = base->object;
@@ -2499,7 +2507,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
}
}
- BKE_main_id_tag_idcode(bmain, ID_GR, false);
+ BKE_main_id_tag_idcode(bmain, ID_GR, LIB_TAG_DOIT, false);
/* now tag update flags, to ensure deformers get calculated on redraw */
DAG_scene_update_flags(bmain, scene, lay, do_time, true);
@@ -2521,7 +2529,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
}
}
-static void dag_id_flush_update__isDependentTexture(void *userData, Object *UNUSED(ob), ID **idpoin)
+static void dag_id_flush_update__isDependentTexture(
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
{
struct { ID *id; bool is_dependent; } *data = userData;
@@ -2577,7 +2586,18 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
}
}
}
-
+ else if (idtype == ID_VF) {
+ for (obt = bmain->object.first; obt; obt = obt->id.next) {
+ if (obt->type == OB_FONT) {
+ Curve *cu = obt->data;
+ if (ELEM((struct VFont *)id, CURVE_VFONT_ANY(cu))) {
+ obt->recalc |= OB_RECALC_DATA;
+ lib_id_recalc_data_tag(bmain, &obt->id);
+ }
+ }
+ }
+ }
+
/* set flags based on textures - can influence depgraph via modifiers */
if (idtype == ID_TE) {
for (obt = bmain->object.first; obt; obt = obt->id.next) {
@@ -2752,7 +2772,7 @@ void DAG_ids_flush_tagged(Main *bmain)
* looping over all ID's in case there are no tags */
if (id && bmain->id_tag_update[id->name[0]]) {
for (; id; id = id->next) {
- if (id->flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA)) {
+ if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
for (dsl = listbase.first; dsl; dsl = dsl->next)
dag_id_flush_update(bmain, dsl->scene, id);
@@ -2877,13 +2897,13 @@ void DAG_ids_clear_recalc(Main *bmain)
* looping over all ID's in case there are no tags */
if (id && bmain->id_tag_update[id->name[0]]) {
for (; id; id = id->next) {
- if (id->flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA))
- id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ if (id->tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA))
+ id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
/* some ID's contain semi-datablock nodetree */
ntree = ntreeFromID(id);
- if (ntree && (ntree->id.flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA)))
- ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ if (ntree && (ntree->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)))
+ ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
}
}
}
@@ -2944,18 +2964,6 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
}
}
}
- else if (idtype == ID_VF) {
- /* this is weak still, should be done delayed as well */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ob->type == OB_FONT) {
- Curve *cu = ob->data;
-
- if (ELEM((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) {
- ob->recalc |= (flag & OB_RECALC_ALL);
- }
- }
- }
- }
else {
/* disable because this is called on various ID types automatically.
* where printing warning is not useful. for now just ignore */
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index c83050627e9..98cbe47c7f9 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -1521,7 +1521,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
BKE_curve_bevelList_free(&ob->curve_cache->bev);
- /* We only re-evlauate path if evaluation is not happening for orco.
+ /* We only re-evaluate path if evaluation is not happening for orco.
* If the calculation happens for orco, we should never free data which
* was needed before and only not needed for orco calculation.
*/
@@ -1861,6 +1861,8 @@ static void boundbox_displist_object(Object *ob)
INIT_MINMAX(min, max);
BKE_displist_minmax(&ob->curve_cache->disp, min, max);
BKE_boundbox_init_from_minmax(ob->bb, min, max);
+
+ ob->bb->flag &= ~BOUNDBOX_DIRTY;
}
}
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 7557015be8e..dbf095d3832 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -103,8 +103,6 @@ static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* subframe_updateObject() flags */
#define SUBFRAME_RECURSION 5
-#define UPDATE_MESH (1 << 1)
-#define UPDATE_EVERYTHING (UPDATE_MESH) // | UPDATE_PARENTS
/* surface_getBrushFlags() return vals */
#define BRUSH_USES_VELOCITY (1 << 0)
/* brush mesh raycast status */
@@ -484,93 +482,6 @@ static float mixColors(float a_color[3], float a_weight, const float b_color[3],
return (1.0f - factor) * a_weight + factor * b_weight;
}
-/* set "ignore cache" flag for all caches on this object */
-static void object_cacheIgnoreClear(Object *ob, int state)
-{
- ListBase pidlist;
- PTCacheID *pid;
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
-
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache) {
- if (state)
- pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
- else
- pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
- }
- }
-
- BLI_freelistN(&pidlist);
-}
-
-static int subframe_updateObject(Scene *scene, Object *ob, int flags, int parent_recursion, float frame)
-{
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
- bConstraint *con;
-
- /* if other is dynamic paint canvas, don't update */
- if (pmd && pmd->canvas)
- return 1;
-
- /* if object has parents, update them too */
- if (parent_recursion) {
- int recursion = parent_recursion - 1;
- int is_canvas = 0;
- if (ob->parent) is_canvas += subframe_updateObject(scene, ob->parent, 0, recursion, frame);
- if (ob->track) is_canvas += subframe_updateObject(scene, ob->track, 0, recursion, frame);
-
- /* skip subframe if object is parented
- * to vertex of a dynamic paint canvas */
- if (is_canvas && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
- return 0;
-
- /* also update constraint targets */
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- cti->get_constraint_targets(con, &targets);
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar)
- subframe_updateObject(scene, ct->tar, 0, recursion, frame);
- }
- /* free temp targets */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
- if (flags & UPDATE_MESH) {
- /* ignore cache clear during subframe updates
- * to not mess up cache validity */
- object_cacheIgnoreClear(ob, 1);
- BKE_object_handle_update(G.main->eval_ctx, scene, ob);
- object_cacheIgnoreClear(ob, 0);
- }
- else
- BKE_object_where_is_calc_time(scene, ob, frame);
-
- /* for curve following objects, parented curve has to be updated too */
- if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
- }
- /* and armatures... */
- if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
- BKE_pose_where_is(scene, ob);
- }
-
- return 0;
-}
-
static void scene_setSubframe(Scene *scene, float subframe)
{
/* dynamic paint subframes must be done on previous frame */
@@ -1773,8 +1684,8 @@ static DerivedMesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd,
}
else {
col[l_index].r =
- col[l_index].g =
- col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
+ col[l_index].g =
+ col[l_index].b = FTOCHAR(pPoint[v_index].wetness);
col[l_index].a = 255;
}
}
@@ -2278,8 +2189,10 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
tottri = dm->getNumLoopTri(dm);
/* get uv map */
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->uvlayer_name, uvname);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
+ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->uvlayer_name, uvname);
+ mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ }
/* Check for validity */
if (!mloopuv)
@@ -2536,11 +2449,11 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
/* Generate surface adjacency data. */
{
- int i, cursor = 0;
+ int cursor = 0;
/* Create a temporary array of final indexes (before unassigned
* pixels have been dropped) */
- for (i = 0; i < w * h; i++) {
+ for (int i = 0; i < w * h; i++) {
if (tempPoints[i].tri_index != -1) {
final_index[i] = cursor;
cursor++;
@@ -2556,13 +2469,13 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface)
for (ty = 0; ty < h; ty++) {
int tx;
for (tx = 0; tx < w; tx++) {
- int i, index = tx + w * ty;
+ int index = tx + w * ty;
if (tempPoints[index].tri_index != -1) {
ed->n_index[final_index[index]] = n_pos;
ed->n_num[final_index[index]] = 0;
- for (i = 0; i < 8; i++) {
+ for (int i = 0; i < 8; i++) {
/* Try to find a neighboring pixel in defined direction
* If not found, -1 is returned */
@@ -2806,13 +2719,13 @@ static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat,
if (tot) {
bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
for (i = 0; i < tot; i++) {
- bMats->ob_mats[i] = RE_init_sample_material(give_current_material(brushOb, (i + 1)), scene);
+ bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene);
}
}
bMats->tot = tot;
}
else {
- bMats->mat = RE_init_sample_material(ui_mat, scene);
+ bMats->mat = RE_sample_material_init(ui_mat, scene);
}
}
@@ -2823,12 +2736,12 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
if (bMats->ob_mats) {
int i;
for (i = 0; i < bMats->tot; i++) {
- RE_free_sample_material(bMats->ob_mats[i]);
+ RE_sample_material_free(bMats->ob_mats[i]);
}
MEM_freeN(bMats->ob_mats);
}
else if (bMats->mat) {
- RE_free_sample_material(bMats->mat);
+ RE_sample_material_free(bMats->mat);
}
}
@@ -3156,7 +3069,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- subframe_updateObject(scene, ob, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
+ BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_p = CDDM_copy(brush->dm);
numOfVerts_p = dm_p->getNumVerts(dm_p);
mvert_p = dm_p->getVertArray(dm_p);
@@ -3166,7 +3079,7 @@ static void dynamicPaint_brushMeshCalculateVelocity(Scene *scene, Object *ob, Dy
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- subframe_updateObject(scene, ob, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
+ BKE_object_modifier_update_subframe(scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
dm_c = brush->dm;
numOfVerts_c = dm_c->getNumVerts(dm_c);
mvert_c = dm_p->getVertArray(dm_c);
@@ -3216,13 +3129,13 @@ static void dynamicPaint_brushObjectCalculateVelocity(Scene *scene, Object *ob,
/* previous frame dm */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
- subframe_updateObject(scene, ob, 0, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
+ BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
/* current frame dm */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
- subframe_updateObject(scene, ob, 0, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
+ BKE_object_modifier_update_subframe(scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3363,7 +3276,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
add_v3_fl(ray_start, 0.001f);
hit.index = -1;
- hit.dist = 9999;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
nearest.index = -1;
nearest.dist_sq = brush_radius * brush_radius; /* find_nearest uses squared distance */
@@ -3393,7 +3306,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
* point is at least surrounded by two brush faces */
negate_v3(ray_dir);
hit.index = -1;
- hit.dist = 9999;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_dir, 0.0f, &hit, mesh_tris_spherecast_dp, &treeData);
@@ -3628,7 +3541,6 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
float timescale)
{
ParticleSettings *part = psys->part;
- ParticleData *pa = NULL;
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
VolumeGrid *grid = bData->grid;
@@ -3654,7 +3566,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
tree = BLI_kdtree_new(psys->totpart);
/* loop through particles and insert valid ones to the tree */
- for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
+ p = 0;
+ for (ParticleData *pa = psys->particles; p < psys->totpart; p++, pa++) {
/* Proceed only if particle is active */
if (pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN) == 0) continue;
@@ -4947,7 +4860,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- subframe_updateObject(scene, brushObj, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* Prepare materials if required */
if (brush_usesMaterial(brush, scene))
@@ -4981,7 +4894,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- subframe_updateObject(scene, brushObj, UPDATE_EVERYTHING, SUBFRAME_RECURSION, BKE_scene_frame_get(scene));
+ BKE_object_modifier_update_subframe(scene, brushObj, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
/* process special brush effects, like smudge */
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 840935c090b..96bdfe88722 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -55,10 +55,9 @@
#include "MEM_guardedalloc.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
-
-extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
+#include "GPU_shader.h"
+#include "GPU_basic_shader.h"
static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]);
@@ -238,31 +237,71 @@ static void emDM_calcLoopNormalsSpaceArray(
}
+/** \name Tangent Space Calculation
+ * \{ */
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
typedef struct {
const float (*precomputedFaceNormals)[3];
const float (*precomputedLoopNormals)[3];
- BMLoop *(*looptris)[3];
+ const BMLoop *(*looptris)[3];
int cd_loop_uv_offset; /* texture coordinates */
const float (*orco)[3];
float (*tangent)[4]; /* destination */
int numTessFaces;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
} SGLSLEditMeshToTangent;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+/* seems weak but only used on quads */
+static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
+{
+ const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ while (vert_index--) {
+ l = l->next;
+ }
+ return l;
+}
+#endif
+
/* interface */
#include "mikktspace.h"
static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
{
SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
return pMesh->numTessFaces;
+#endif
}
static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
{
- //SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
UNUSED_VARS(pContext, face_num);
return 3;
+#endif
}
static void emdm_ts_GetPosition(
@@ -271,8 +310,30 @@ static void emdm_ts_GetPosition(
{
//assert(vert_index >= 0 && vert_index < 4);
SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- BMLoop **lt = pMesh->looptris[face_num];
- const float *co = lt[vert_index]->v->co;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ const float *co;
+
+finally:
+ co = l->v->co;
copy_v3_v3(r_co, co);
}
@@ -282,14 +343,33 @@ static void emdm_ts_GetTextureCoordinate(
{
//assert(vert_index >= 0 && vert_index < 4);
SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- BMLoop **lt = pMesh->looptris[face_num];
+ const BMLoop **lt;
+ const BMLoop *l;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
if (pMesh->cd_loop_uv_offset != -1) {
- const float *uv = BM_ELEM_CD_GET_VOID_P(lt[vert_index], pMesh->cd_loop_uv_offset);
+ const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
copy_v2_v2(r_uv, uv);
}
else {
- const float *orco = pMesh->orco[BM_elem_index_get(lt[vert_index]->v)];
+ const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
}
}
@@ -300,22 +380,40 @@ static void emdm_ts_GetNormal(
{
//assert(vert_index >= 0 && vert_index < 4);
SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- BMLoop **lt = pMesh->looptris[face_num];
- const bool smoothnormal = BM_elem_flag_test_bool(lt[0]->f, BM_ELEM_SMOOTH);
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+finally:
if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(lt[vert_index])]);
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
}
- else if (!smoothnormal) {
+ else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(lt[0]->f)]);
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
}
else {
- copy_v3_v3(r_no, lt[0]->f->no);
+ copy_v3_v3(r_no, l->f->no);
}
}
else {
- copy_v3_v3(r_no, lt[vert_index]->v->no);
+ copy_v3_v3(r_no, l->v->no);
}
}
@@ -325,8 +423,30 @@ static void emdm_ts_SetTSpace(
{
//assert(vert_index >= 0 && vert_index < 4);
SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- BMLoop **lt = pMesh->looptris[face_num];
- float *pRes = pMesh->tangent[BM_elem_index_get(lt[vert_index])];
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[BM_elem_index_get(l)];
copy_v3_v3(pRes, fvTangent);
pRes[3] = fSign;
}
@@ -387,6 +507,31 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
DM_add_loop_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
tangent = DM_get_loop_data_layer(dm, CD_TANGENT);
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (bmdm->em->tottri != bm->totface) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (em->looptris[j][0]->f->len == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
+#endif
+
/* new computation method */
{
SGLSLEditMeshToTangent mesh2tangent = {NULL};
@@ -395,12 +540,17 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
mesh2tangent.precomputedFaceNormals = fnors;
mesh2tangent.precomputedLoopNormals = tlnors;
- mesh2tangent.looptris = em->looptris;
+ mesh2tangent.looptris = (const BMLoop *(*)[3])em->looptris;
mesh2tangent.cd_loop_uv_offset = cd_loop_uv_offset;
mesh2tangent.orco = (const float (*)[3])orco;
mesh2tangent.tangent = tangent;
mesh2tangent.numTessFaces = totface;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent.face_as_quad_map = face_as_quad_map;
+ mesh2tangent.num_face_as_quad_map = num_face_as_quad_map;
+#endif
+
sContext.m_pUserData = &mesh2tangent;
sContext.m_pInterface = &sInterface;
sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
@@ -412,9 +562,19 @@ static void emDM_calcLoopTangents(DerivedMesh *dm)
/* 0 if failed */
genTangSpaceDefault(&sContext);
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+#endif
}
}
+/** \} */
+
+
static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
{
/* do nothing */
@@ -729,11 +889,9 @@ static void emDM_drawMappedFaces(
BMFace *efa;
struct BMLoop *(*looptris)[3] = bmdm->em->looptris;
const int tottri = bmdm->em->tottri;
- const int lasttri = tottri - 1; /* compare agasint this a lot */
DMDrawOption draw_option;
- int i, flush;
- const int skip_normals = !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */
-
+ int i;
+ const int skip_normals = !(flag & DM_DRAW_NEED_NORMALS);
const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
unsigned char(*color_vert_array)[4] = em->derivedVertColor;
@@ -745,6 +903,7 @@ static void emDM_drawMappedFaces(
/* GL_ZERO is used to detect if drawing has started or not */
GLenum poly_prev = GL_ZERO;
GLenum shade_prev = GL_ZERO;
+ DMDrawOption draw_option_prev = DM_DRAW_OPTION_SKIP;
/* call again below is ok */
if (has_vcol_preview) {
@@ -755,7 +914,8 @@ static void emDM_drawMappedFaces(
}
if (has_vcol_preview || has_fcol_preview) {
flag |= DM_DRAW_ALWAYS_SMOOTH;
- glDisable(GL_LIGHTING); /* grr */
+ /* weak, this logic should really be moved higher up */
+ setMaterial = NULL;
}
if (bmdm->vertexCos) {
@@ -792,8 +952,22 @@ static void emDM_drawMappedFaces(
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
+ if (draw_option_prev != draw_option) {
+ if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
+ if (poly_prev != GL_ZERO) glEnd();
+ poly_prev = GL_ZERO; /* force glBegin */
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
+ draw_option_prev = draw_option;
+ }
+
+
if (efa->mat_nr != prev_mat_nr) {
if (setMaterial) {
+ if (poly_prev != GL_ZERO) glEnd();
+ poly_prev = GL_ZERO; /* force glBegin */
+
setMaterial(efa->mat_nr + 1, NULL);
}
prev_mat_nr = efa->mat_nr;
@@ -804,8 +978,8 @@ static void emDM_drawMappedFaces(
if (poly_prev != GL_ZERO) glEnd();
poly_prev = GL_ZERO; /* force glBegin */
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
}
if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
@@ -858,17 +1032,6 @@ static void emDM_drawMappedFaces(
glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
}
}
-
- flush = (draw_option == DM_DRAW_OPTION_STIPPLE);
- if (!skip_normals && !flush && (i != lasttri))
- flush |= efa->mat_nr != looptris[i + 1][0]->f->mat_nr; /* TODO, make this neater */
-
- if (flush) {
- glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- glDisable(GL_POLYGON_STIPPLE);
- }
}
}
}
@@ -891,8 +1054,21 @@ static void emDM_drawMappedFaces(
if (draw_option != DM_DRAW_OPTION_SKIP) {
const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
+ if (draw_option_prev != draw_option) {
+ if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
+ if (poly_prev != GL_ZERO) glEnd();
+ poly_prev = GL_ZERO; /* force glBegin */
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
+ draw_option_prev = draw_option;
+ }
+
if (efa->mat_nr != prev_mat_nr) {
if (setMaterial) {
+ if (poly_prev != GL_ZERO) glEnd();
+ poly_prev = GL_ZERO; /* force glBegin */
+
setMaterial(efa->mat_nr + 1, NULL);
}
prev_mat_nr = efa->mat_nr;
@@ -903,8 +1079,8 @@ static void emDM_drawMappedFaces(
if (poly_prev != GL_ZERO) glEnd();
poly_prev = GL_ZERO; /* force glBegin */
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
}
if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
@@ -958,18 +1134,6 @@ static void emDM_drawMappedFaces(
glVertex3fv(ltri[2]->v->co);
}
}
-
- flush = (draw_option == DM_DRAW_OPTION_STIPPLE);
- if (!skip_normals && !flush && (i != lasttri)) {
- flush |= efa->mat_nr != looptris[i + 1][0]->f->mat_nr; /* TODO, make this neater */
- }
-
- if (flush) {
- glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- glDisable(GL_POLYGON_STIPPLE);
- }
}
}
}
@@ -1226,7 +1390,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
if (attribs->orco.gl_texco)
glTexCoord3fv(orco);
else
- glVertexAttrib3fvARB(attribs->orco.gl_index, orco);
+ glVertexAttrib3fv(attribs->orco.gl_index, orco);
}
for (i = 0; i < attribs->tottface; i++) {
const float *uv;
@@ -1242,18 +1406,18 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
if (attribs->tface[i].gl_texco)
glTexCoord2fv(uv);
else
- glVertexAttrib2fvARB(attribs->tface[i].gl_index, uv);
+ glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
}
for (i = 0; i < attribs->totmcol; i++) {
GLubyte col[4];
if (attribs->mcol[i].em_offset != -1) {
const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- copy_v4_v4_char((char *)col, &cp->r);
+ copy_v4_v4_uchar(col, &cp->r);
}
else {
col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
}
- glVertexAttrib4ubvARB(attribs->mcol[i].gl_index, col);
+ glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
}
if (attribs->tottang) {
const float *tang;
@@ -1263,7 +1427,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
else {
tang = zero;
}
- glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
+ glVertexAttrib4fv(attribs->tang.gl_index, tang);
}
}
@@ -2170,8 +2334,8 @@ static void statvis_calc_overhang(
rgb_float_to_uchar(r_face_colors[index], fcol);
}
else {
- unsigned char *fallback = is_max ? col_fallback_max : col_fallback;
- copy_v4_v4_char((char *)r_face_colors[index], (const char *)fallback);
+ const unsigned char *fallback = is_max ? col_fallback_max : col_fallback;
+ copy_v4_v4_uchar(r_face_colors[index], fallback);
}
}
}
@@ -2210,7 +2374,7 @@ static void statvis_calc_thickness(
struct BMLoop *(*looptris)[3] = em->looptris;
/* fallback */
- const char col_fallback[4] = {64, 64, 64, 255};
+ const unsigned char col_fallback[4] = {64, 64, 64, 255};
struct BMBVHTree *bmtree;
@@ -2305,7 +2469,7 @@ static void statvis_calc_thickness(
rgb_float_to_uchar(r_face_colors[i], fcol);
}
else {
- copy_v4_v4_char((char *)r_face_colors[i], (const char *)col_fallback);
+ copy_v4_v4_uchar(r_face_colors[i], col_fallback);
}
}
}
@@ -2357,7 +2521,7 @@ static void statvis_calc_intersect(
index = BM_elem_index_get(f_hit);
- copy_v3_v3_char((char *)r_face_colors[index], (const char *)col);
+ copy_v3_v3_uchar(r_face_colors[index], col);
}
}
MEM_freeN(overlap);
@@ -2382,7 +2546,7 @@ static void statvis_calc_distort(
const float minmax_irange = 1.0f / (max - min);
/* fallback */
- const char col_fallback[4] = {64, 64, 64, 255};
+ const unsigned char col_fallback[4] = {64, 64, 64, 255};
/* now convert into global space */
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, index) {
@@ -2431,7 +2595,7 @@ static void statvis_calc_distort(
rgb_float_to_uchar(r_face_colors[index], fcol);
}
else {
- copy_v4_v4_char((char *)r_face_colors[index], (const char *)col_fallback);
+ copy_v4_v4_uchar(r_face_colors[index], col_fallback);
}
}
}
@@ -2453,7 +2617,7 @@ static void statvis_calc_sharp(
int i;
/* fallback */
- const char col_fallback[4] = {64, 64, 64, 255};
+ const unsigned char col_fallback[4] = {64, 64, 64, 255};
(void)vertexCos; /* TODO */
@@ -2481,7 +2645,7 @@ static void statvis_calc_sharp(
rgb_float_to_uchar(r_vert_colors[i], fcol);
}
else {
- copy_v4_v4_char((char *)r_vert_colors[i], (const char *)col_fallback);
+ copy_v4_v4_uchar(r_vert_colors[i], col_fallback);
}
}
}
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 87a5c6f149f..fea3c24d322 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -142,7 +142,7 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
em->looptris = looptris;
/* after allocating the em->looptris, we're ready to tessellate */
- BM_bmesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
+ BM_mesh_calc_tessellation(em->bm, em->looptris, &em->tottri);
}
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index 07706a38deb..ccea2d4ece4 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -439,6 +439,60 @@ BMVert *BKE_bmbvh_find_vert_closest(BMBVHTree *bmtree, const float co[3], const
return NULL;
}
+struct FaceSearchUserData {
+ /* from the bmtree */
+ const BMLoop *(*looptris)[3];
+ const float (*cos_cage)[3];
+
+ /* from the hit */
+ float dist_max_sq;
+};
+
+static void bmbvh_find_face_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
+{
+ struct FaceSearchUserData *bmcb_data = userdata;
+ const BMLoop **ltri = bmcb_data->looptris[index];
+ const float dist_max_sq = bmcb_data->dist_max_sq;
+
+ const float *tri_cos[3];
+
+ bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);
+
+ float co_close[3];
+ closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos));
+ const float dist_sq = len_squared_v3v3(co, co_close);
+ if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
+ /* XXX, normal ignores cage */
+ copy_v3_v3(hit->no, ltri[0]->f->no);
+ hit->dist_sq = dist_sq;
+ hit->index = index;
+ }
+}
+
+struct BMFace *BKE_bmbvh_find_face_closest(BMBVHTree *bmtree, const float co[3], const float dist_max)
+{
+ BVHTreeNearest hit;
+ struct FaceSearchUserData bmcb_data;
+ const float dist_max_sq = dist_max * dist_max;
+
+ if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));
+
+ hit.dist_sq = dist_max_sq;
+ hit.index = -1;
+
+ bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
+ bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
+ bmcb_data.dist_max_sq = dist_max_sq;
+
+ BLI_bvhtree_find_nearest(bmtree->tree, co, &hit, bmbvh_find_face_closest_cb, &bmcb_data);
+ if (hit.index != -1) {
+ BMLoop **ltri = bmtree->looptris[hit.index];
+ return ltri[0]->f;
+ }
+
+ return NULL;
+}
+
/* -------------------------------------------------------------------- */
/* BKE_bmbvh_overlap */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index bf53acc1d95..12bce70594b 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -64,6 +64,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -139,7 +140,7 @@ void free_partdeflect(PartDeflect *pd)
return;
if (pd->tex)
- pd->tex->id.us--;
+ id_us_min(&pd->tex->id);
if (pd->rng)
BLI_rng_free(pd->rng);
@@ -687,10 +688,10 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
}
static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p, int *step)
{
- if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
- efd->index = p;
+ *p = 0;
+ efd->index = p;
- *p = 0;
+ if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
*tot = eff->ob->derivedFinal ? eff->ob->derivedFinal->numVertData : 1;
if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
@@ -699,9 +700,6 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin
}
}
else if (eff->psys) {
- efd->index = p;
-
- *p = 0;
*tot = eff->psys->totpart;
if (eff->pd->forcefield == PFIELD_CHARGE) {
@@ -727,7 +725,6 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin
}
}
else {
- *p = 0;
*tot = 1;
}
}
@@ -760,7 +757,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
scene_color_manage = BKE_scene_check_color_management_enabled(eff->scene);
- hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL, scene_color_manage, false);
+ hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, 0, NULL, scene_color_manage, false);
if (hasrgb && mode==PFIELD_TEX_RGB) {
force[0] = (0.5f - result->tr) * strength;
@@ -771,15 +768,15 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
strength/=nabla;
tex_co[0] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL, scene_color_manage, false);
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, 0, NULL, scene_color_manage, false);
tex_co[0] -= nabla;
tex_co[1] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL, scene_color_manage, false);
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, 0, NULL, scene_color_manage, false);
tex_co[1] -= nabla;
tex_co[2] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL, scene_color_manage, false);
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, 0, NULL, scene_color_manage, false);
if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
/* generate intensity if texture only has rgb value */
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index d747fb0cea2..a2b5a05feac 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -314,23 +314,25 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
return matches;
}
-FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **adt,
- bAction **action, bool *r_driven, bool *r_special)
+FCurve *rna_get_fcurve(
+ PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
+ AnimData **r_adt, bAction **r_action, bool *r_driven, bool *r_special)
{
- return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, adt, action, r_driven, r_special);
+ return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, AnimData **animdata,
- bAction **action, bool *r_driven, bool *r_special)
+FCurve *rna_get_fcurve_context_ui(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
+ AnimData **r_animdata, bAction **r_action, bool *r_driven, bool *r_special)
{
FCurve *fcu = NULL;
PointerRNA tptr = *ptr;
- if (animdata) *animdata = NULL;
*r_driven = false;
*r_special = false;
- if (action) *action = NULL;
+ if (r_animdata) *r_animdata = NULL;
+ if (r_action) *r_action = NULL;
/* Special case for NLA Control Curves... */
if (ptr->type == &RNA_NlaStrip) {
@@ -372,8 +374,8 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
if (adt->action && adt->action->curves.first) {
fcu = list_find_fcurve(&adt->action->curves, path, rnaindex);
- if (fcu && action)
- *action = adt->action;
+ if (fcu && r_action)
+ *r_action = adt->action;
}
/* if not animated, check if driven */
@@ -381,14 +383,14 @@ FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *pro
fcu = list_find_fcurve(&adt->drivers, path, rnaindex);
if (fcu) {
- if (animdata) *animdata = adt;
+ if (r_animdata) *r_animdata = adt;
*r_driven = true;
}
}
- if (fcu && action) {
- if (animdata) *animdata = adt;
- *action = adt->action;
+ if (fcu && r_action) {
+ if (r_animdata) *r_animdata = adt;
+ *r_action = adt->action;
break;
}
else if (step) {
@@ -1149,6 +1151,71 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
return value;
}
+/**
+ * Same as 'dtar_get_prop_val'. but get the RNA property.
+ */
+bool driver_get_variable_property(
+ ChannelDriver *driver, DriverTarget *dtar,
+ PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
+{
+ PointerRNA id_ptr;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ int index = -1;
+
+ /* sanity check */
+ if (ELEM(NULL, driver, dtar))
+ return false;
+
+ id = dtar_id_ensure_proxy_from(dtar->id);
+
+ /* error check for missing pointer... */
+ if (id == NULL) {
+ if (G.debug & G_DEBUG) {
+ printf("Error: driver has an invalid target to use (path = %s)\n", dtar->rna_path);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ /* get RNA-pointer for the ID-block given in target */
+ RNA_id_pointer_create(id, &id_ptr);
+
+ /* get property to read from, and get value as appropriate */
+ if (dtar->rna_path == NULL || dtar->rna_path[0] == '\0') {
+ ptr = PointerRNA_NULL;
+ prop = NULL; /* ok */
+ }
+ else if (RNA_path_resolve_property_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
+ /* ok */
+ }
+ else {
+ /* path couldn't be resolved */
+ if (G.debug & G_DEBUG) {
+ printf("Driver Evaluation Error: cannot resolve target for %s -> %s\n", id->name, dtar->rna_path);
+ }
+
+ ptr = PointerRNA_NULL;
+ *r_prop = NULL;
+ *r_index = -1;
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return false;
+ }
+
+ *r_ptr = ptr;
+ *r_prop = prop;
+ *r_index = index;
+
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ return true;
+}
+
/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
{
@@ -1235,7 +1302,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
mat4_to_quat(q1, pchan->pose_mat);
mat4_to_quat(q2, pchan2->pose_mat);
- invert_qt(q1);
+ invert_qt_normalized(q1);
mul_qt_qtqt(quat, q1, q2);
angle = 2.0f * (saacos(quat[0]));
angle = ABS(angle);
@@ -1533,8 +1600,8 @@ static const DriverVarTypeInfo *get_dvar_typeinfo(int type)
/* Driver API --------------------------------- */
-/* This frees the driver variable itself */
-void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
+/* Perform actual freeing driver variable and remove it from the given list */
+void driver_free_variable(ListBase *variables, DriverVar *dvar)
{
/* sanity checks */
if (dvar == NULL)
@@ -1554,8 +1621,15 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
DRIVER_TARGETS_LOOPER_END
/* remove the variable from the driver */
- BLI_freelinkN(&driver->variables, dvar);
+ BLI_freelinkN(variables, dvar);
+}
+/* Free the driver variable and do extra updates */
+void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
+{
+ /* remove and free the driver variable */
+ driver_free_variable(&driver->variables, dvar);
+
#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
if (driver->type == DRIVER_TYPE_PYTHON)
@@ -1563,6 +1637,24 @@ void driver_free_variable(ChannelDriver *driver, DriverVar *dvar)
#endif
}
+/* Copy driver variables from src_vars list to dst_vars list */
+void driver_variables_copy(ListBase *dst_vars, const ListBase *src_vars)
+{
+ BLI_assert(BLI_listbase_is_empty(dst_vars));
+ BLI_duplicatelist(dst_vars, src_vars);
+
+ for (DriverVar *dvar = dst_vars->first; dvar; dvar = dvar->next) {
+ /* need to go over all targets so that we don't leave any dangling paths */
+ DRIVER_TARGETS_LOOPER(dvar)
+ {
+ /* make a copy of target's rna path if available */
+ if (dtar->rna_path)
+ dtar->rna_path = MEM_dupallocN(dtar->rna_path);
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+}
+
/* Change the type of driver variable */
void driver_change_variable_type(DriverVar *dvar, int type)
{
@@ -1593,6 +1685,71 @@ void driver_change_variable_type(DriverVar *dvar, int type)
DRIVER_TARGETS_LOOPER_END
}
+/* Validate driver name (after being renamed) */
+void driver_variable_name_validate(DriverVar *dvar)
+{
+ /* Special character blacklist */
+ const char special_char_blacklist[] = {
+ '~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '+', '=', '-',
+ '/', '\\', '?', ':', ';', '<', '>', '{', '}', '[', ']', '|',
+ ' ', '.', '\t', '\n', '\r'
+ };
+
+ /* sanity checks */
+ if (dvar == NULL)
+ return;
+
+ /* clear all invalid-name flags */
+ dvar->flag &= ~DVAR_ALL_INVALID_FLAGS;
+
+ /* 0) Zero-length identifiers are not allowed */
+ if (dvar->name[0] == '\0') {
+ dvar->flag |= DVAR_FLAG_INVALID_EMPTY;
+ }
+
+ /* 1) Must start with a letter */
+ /* XXX: We assume that valid unicode letters in other languages are ok too, hence the blacklisting */
+ if (ELEM(dvar->name[0], '0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) {
+ dvar->flag |= DVAR_FLAG_INVALID_START_NUM;
+ }
+ else if (dvar->name[0] == '_') {
+ /* NOTE: We don't allow names to start with underscores (i.e. it helps when ruling out security risks) */
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ }
+
+ /* 2) Must not contain invalid stuff in the middle of the string */
+ if (strchr(dvar->name, ' ')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPACE;
+ }
+ if (strchr(dvar->name, '.')) {
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_DOT;
+ }
+
+ /* 3) Check for special characters - Either at start, or in the middle */
+ for (int i = 0; i < sizeof(special_char_blacklist); i++) {
+ char *match = strchr(dvar->name, special_char_blacklist[i]);
+
+ if (match == dvar->name)
+ dvar->flag |= DVAR_FLAG_INVALID_START_CHAR;
+ else if (match != NULL)
+ dvar->flag |= DVAR_FLAG_INVALID_HAS_SPECIAL;
+ }
+
+ /* 4) Check if the name is a reserved keyword
+ * NOTE: These won't confuse Python, but it will be impossible to use the variable
+ * in an expression without Python misinterpreting what these are for
+ */
+#ifdef WITH_PYTHON
+ if (BPY_string_is_keyword(dvar->name)) {
+ dvar->flag |= DVAR_FLAG_INVALID_PY_KEYWORD;
+ }
+#endif
+
+ /* If any these conditions match, the name is invalid */
+ if (dvar->flag & DVAR_ALL_INVALID_FLAGS)
+ dvar->flag |= DVAR_FLAG_INVALID_NAME;
+}
+
/* Add a new driver variable */
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
@@ -1619,7 +1776,7 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
if (driver->type == DRIVER_TYPE_PYTHON)
driver->flag |= DRIVER_FLAG_RENAMEVAR;
#endif
-
+
/* return the target */
return dvar;
}
@@ -1638,7 +1795,7 @@ void fcurve_free_driver(FCurve *fcu)
/* free driver targets */
for (dvar = driver->variables.first; dvar; dvar = dvarn) {
dvarn = dvar->next;
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
}
#ifdef WITH_PYTHON
@@ -1656,7 +1813,6 @@ void fcurve_free_driver(FCurve *fcu)
ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
{
ChannelDriver *ndriver;
- DriverVar *dvar;
/* sanity checks */
if (driver == NULL)
@@ -1667,19 +1823,8 @@ ChannelDriver *fcurve_copy_driver(ChannelDriver *driver)
ndriver->expr_comp = NULL;
/* copy variables */
- BLI_listbase_clear(&ndriver->variables);
- BLI_duplicatelist(&ndriver->variables, &driver->variables);
-
- for (dvar = ndriver->variables.first; dvar; dvar = dvar->next) {
- /* need to go over all targets so that we don't leave any dangling paths */
- DRIVER_TARGETS_LOOPER(dvar)
- {
- /* make a copy of target's rna path if available */
- if (dtar->rna_path)
- dtar->rna_path = MEM_dupallocN(dtar->rna_path);
- }
- DRIVER_TARGETS_LOOPER_END
- }
+ BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */
+ driver_variables_copy(&ndriver->variables, &driver->variables);
/* return the new driver */
return ndriver;
@@ -1714,7 +1859,7 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
*/
-static float evaluate_driver(ChannelDriver *driver, const float evaltime)
+float evaluate_driver(ChannelDriver *driver, const float evaltime)
{
DriverVar *dvar;
@@ -2436,11 +2581,11 @@ static float fcurve_eval_samples(FCurve *fcu, FPoint *fpts, float evaltime)
float t = fabsf(evaltime - floorf(evaltime));
/* find the one on the right frame (assume that these are spaced on 1-frame intervals) */
- fpt = prevfpt + (int)(evaltime - prevfpt->vec[0]);
+ fpt = prevfpt + ((int)evaltime - (int)prevfpt->vec[0]);
/* if not exactly on the frame, perform linear interpolation with the next one */
- if (t != 0.0f)
- cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], t);
+ if ((t != 0.0f) && (t < 1.0f))
+ cvalue = interpf(fpt->vec[1], (fpt + 1)->vec[1], 1.0f - t);
else
cvalue = fpt->vec[1];
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 2305ae89abd..2c301c04100 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -103,8 +103,8 @@ static FModifierTypeInfo FMI_MODNAME = {
/* Generators available:
* 1) simple polynomial generator:
- * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
- * - Factorized form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
+ * - Expanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
+ * - Factorized form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
*/
static void fcm_generator_free(FModifier *fcm)
@@ -849,7 +849,7 @@ static FModifierTypeInfo FMI_FILTER = {
NULL, /* copy data */
NULL, /* new data */
NULL /*fcm_filter_verify*/, /* verify */
- NULL, /* evlauate time */
+ NULL, /* evaluate time */
fcm_filter_evaluate, /* evaluate */
NULL, /* evaluate time with storage */
NULL /* evaluate with storage */
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 23261b63486..0a887dcf676 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -203,7 +203,27 @@ static VFontData *vfont_get_data(Main *bmain, VFont *vfont)
return vfont->data;
}
-VFont *BKE_vfont_load(Main *bmain, const char *name)
+/* Bad naming actually in this case... */
+void BKE_vfont_init(VFont *vfont)
+{
+ PackedFile *pf = get_builtin_packedfile();
+
+ if (pf) {
+ VFontData *vfd;
+
+ vfd = BLI_vfontdata_from_freetypefont(pf);
+ if (vfd) {
+ vfont->data = vfd;
+
+ BLI_strncpy(vfont->name, FO_BUILTIN_NAME, sizeof(vfont->name));
+ }
+
+ /* Free the packed file */
+ freePackedFile(pf);
+ }
+}
+
+VFont *BKE_vfont_load(Main *bmain, const char *filepath)
{
char filename[FILE_MAXFILE];
VFont *vfont = NULL;
@@ -211,16 +231,16 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
PackedFile *temp_pf = NULL;
bool is_builtin;
- if (STREQ(name, FO_BUILTIN_NAME)) {
- BLI_strncpy(filename, name, sizeof(filename));
+ if (STREQ(filepath, FO_BUILTIN_NAME)) {
+ BLI_strncpy(filename, filepath, sizeof(filename));
pf = get_builtin_packedfile();
is_builtin = true;
}
else {
- BLI_split_file_part(name, filename, sizeof(filename));
- pf = newPackedFile(NULL, name, bmain->name);
- temp_pf = newPackedFile(NULL, name, bmain->name);
+ BLI_split_file_part(filepath, filename, sizeof(filename));
+ pf = newPackedFile(NULL, filepath, bmain->name);
+ temp_pf = newPackedFile(NULL, filepath, bmain->name);
is_builtin = false;
}
@@ -237,7 +257,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
if (vfd->name[0] != '\0') {
BLI_strncpy(vfont->id.name + 2, vfd->name, sizeof(vfont->id.name) - 2);
}
- BLI_strncpy(vfont->name, name, sizeof(vfont->name));
+ BLI_strncpy(vfont->name, filepath, sizeof(vfont->name));
/* if autopack is on store the packedfile in de font structure */
if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
@@ -259,6 +279,37 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
return vfont;
}
+VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
+{
+ VFont *vfont;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ BLI_strncpy(str, filepath, sizeof(str));
+ BLI_path_abs(str, bmain->name);
+
+ /* first search an identical filepath */
+ for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
+ BLI_strncpy(strtest, vfont->name, sizeof(vfont->name));
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id));
+
+ if (BLI_path_cmp(strtest, str) == 0) {
+ id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
+ if (r_exists)
+ *r_exists = true;
+ return vfont;
+ }
+ }
+
+ if (r_exists)
+ *r_exists = false;
+ return BKE_vfont_load(bmain, filepath);
+}
+
+VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath)
+{
+ return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
+}
+
static VFont *which_vfont(Curve *cu, CharInfo *info)
{
switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
@@ -1210,3 +1261,77 @@ bool BKE_vfont_to_curve(Main *bmain, Object *ob, int mode)
return BKE_vfont_to_curve_ex(bmain, ob, mode, &cu->nurb, NULL, NULL, NULL, NULL);
}
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name VFont Clipboard
+ * \{ */
+
+static struct {
+ wchar_t *text_buffer;
+ CharInfo *info_buffer;
+ size_t len_wchar;
+ size_t len_utf8;
+} g_vfont_clipboard = {NULL};
+
+void BKE_vfont_clipboard_free(void)
+{
+ MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
+ MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);
+ g_vfont_clipboard.len_wchar = 0;
+ g_vfont_clipboard.len_utf8 = 0;
+}
+
+void BKE_vfont_clipboard_set(const wchar_t *text_buf, const CharInfo *info_buf, const size_t len)
+{
+ wchar_t *text;
+ CharInfo *info;
+
+ /* clean previous buffers*/
+ BKE_vfont_clipboard_free();
+
+ text = MEM_mallocN((len + 1) * sizeof(wchar_t), __func__);
+ if (text == NULL) {
+ return;
+ }
+
+ info = MEM_mallocN(len * sizeof(CharInfo), __func__);
+ if (info == NULL) {
+ MEM_freeN(text);
+ return;
+ }
+
+ memcpy(text, text_buf, len * sizeof(wchar_t));
+ text[len] = '\0';
+ memcpy(info, info_buf, len * sizeof(CharInfo));
+
+ /* store new buffers */
+ g_vfont_clipboard.text_buffer = text;
+ g_vfont_clipboard.info_buffer = info;
+ g_vfont_clipboard.len_utf8 = BLI_wstrlen_utf8(text);
+ g_vfont_clipboard.len_wchar = len;
+}
+
+void BKE_vfont_clipboard_get(
+ wchar_t **r_text_buf, CharInfo **r_info_buf,
+ size_t *r_len_utf8, size_t *r_len_wchar)
+{
+ if (r_text_buf) {
+ *r_text_buf = g_vfont_clipboard.text_buffer;
+ }
+
+ if (r_info_buf) {
+ *r_info_buf = g_vfont_clipboard.info_buffer;
+ }
+
+ if (r_len_wchar) {
+ *r_len_wchar = g_vfont_clipboard.len_wchar;
+ }
+
+ if (r_len_utf8) {
+ *r_len_utf8 = g_vfont_clipboard.len_utf8;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index f6c4263cff7..3a15be5a09d 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -35,6 +35,7 @@
#include "DNA_group_types.h"
#include "BKE_freestyle.h"
+#include "BKE_library.h"
#include "BKE_linestyle.h"
#include "BLI_blenlib.h"
@@ -65,11 +66,11 @@ void BKE_freestyle_config_free(FreestyleConfig *config)
for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
if (lineset->group) {
- lineset->group->id.us--;
+ id_us_min(&lineset->group->id);
lineset->group = NULL;
}
if (lineset->linestyle) {
- lineset->linestyle->id.us--;
+ id_us_min(&lineset->linestyle->id);
lineset->linestyle = NULL;
}
}
@@ -107,7 +108,7 @@ static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *linese
{
new_lineset->linestyle = lineset->linestyle;
if (new_lineset->linestyle)
- new_lineset->linestyle->id.us++;
+ id_us_plus(&new_lineset->linestyle->id);
new_lineset->flags = lineset->flags;
new_lineset->selection = lineset->selection;
new_lineset->qi = lineset->qi;
@@ -117,7 +118,7 @@ static void copy_lineset(FreestyleLineSet *new_lineset, FreestyleLineSet *linese
new_lineset->exclude_edge_types = lineset->exclude_edge_types;
new_lineset->group = lineset->group;
if (new_lineset->group) {
- new_lineset->group->id.us++;
+ id_us_plus(&new_lineset->group->id);
}
strcpy(new_lineset->name, lineset->name);
}
@@ -215,10 +216,10 @@ bool BKE_freestyle_lineset_delete(FreestyleConfig *config, FreestyleLineSet *lin
if (BLI_findindex(&config->linesets, lineset) == -1)
return false;
if (lineset->group) {
- lineset->group->id.us--;
+ id_us_min(&lineset->group->id);
}
if (lineset->linestyle) {
- lineset->linestyle->id.us--;
+ id_us_min(&lineset->linestyle->id);
}
BLI_remlink(&config->linesets, lineset);
MEM_freeN(lineset);
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index ee5c9192371..485c4f5b29f 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -132,7 +132,7 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
bGPDframe *gpf = NULL, *gf = NULL;
short state = 0;
- /* error checking (neg frame only if they are not allowed in Blender!) */
+ /* error checking */
if (gpl == NULL)
return NULL;
@@ -178,8 +178,63 @@ bGPDframe *gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
return gpf;
}
+/* add a copy of the active gp-frame to the given layer */
+bGPDframe *gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
+{
+ bGPDframe *new_frame, *gpf;
+ bool found = false;
+
+ /* Error checking/handling */
+ if (gpl == NULL) {
+ /* no layer */
+ return NULL;
+ }
+ else if (gpl->actframe == NULL) {
+ /* no active frame, so just create a new one from scratch */
+ return gpencil_frame_addnew(gpl, cframe);
+ }
+
+ /* Create a copy of the frame */
+ new_frame = gpencil_frame_duplicate(gpl->actframe);
+
+ /* Find frame to insert it before */
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->framenum > cframe) {
+ /* Add it here */
+ BLI_insertlinkbefore(&gpl->frames, gpf, new_frame);
+
+ found = true;
+ break;
+ }
+ else if (gpf->framenum == cframe) {
+ /* This only happens when we're editing with framelock on...
+ * - Delete the new frame and don't do anything else here...
+ */
+ free_gpencil_strokes(new_frame);
+ MEM_freeN(new_frame);
+ new_frame = NULL;
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* Add new frame to the end */
+ BLI_addtail(&gpl->frames, new_frame);
+ }
+
+ /* Ensure that frame is set up correctly, and return it */
+ if (new_frame) {
+ new_frame->framenum = cframe;
+ gpl->actframe = new_frame;
+ }
+
+ return new_frame;
+}
+
/* add a new gp-layer and make it the active layer */
-bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, int setactive)
+bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
{
bGPDlayer *gpl;
@@ -197,6 +252,16 @@ bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, int setactive)
copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
gpl->thickness = 3;
+ /* onion-skinning settings */
+ if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
+ gpl->flag |= GP_LAYER_ONIONSKIN;
+
+ gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
+
+ ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
+ ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+
+
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
@@ -370,16 +435,41 @@ void gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
/* -------- GP-Layer API ---------- */
+/* Check if the given layer is able to be edited or not */
+bool gpencil_layer_is_editable(const bGPDlayer *gpl)
+{
+ /* Sanity check */
+ if (gpl == NULL)
+ return false;
+
+ /* Layer must be: Visible + Editable */
+ if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
+ /* Opacity must be sufficiently high that it is still "visible"
+ * Otherwise, it's not really "visible" to the user, so no point editing...
+ */
+ if ((gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH)) {
+ return true;
+ }
+ }
+
+ /* Something failed */
+ return false;
+}
+
+/* Look up the gp-frame on the requested frame number, but don't add a new one */
bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
{
bGPDframe *gpf;
-
+
+ /* Search in reverse order, since this is often used for playback/adding,
+ * where it's less likely that we're interested in the earlier frames
+ */
for (gpf = gpl->frames.last; gpf; gpf = gpf->prev) {
if (gpf->framenum == cframe) {
return gpf;
}
}
-
+
return NULL;
}
@@ -387,7 +477,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe)
* - this sets the layer's actframe var (if allowed to)
* - extension beyond range (if first gp-frame is after all frame in interest and cannot add)
*/
-bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew)
+bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
{
bGPDframe *gpf = NULL;
short found = 0;
@@ -425,6 +515,8 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew)
if (addnew) {
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
+ else if (addnew == GP_GETFRAME_ADD_COPY)
+ gpl->actframe = gpencil_frame_addcopy(gpl, cframe);
else
gpl->actframe = gpencil_frame_addnew(gpl, cframe);
}
@@ -445,6 +537,8 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew)
if (addnew) {
if ((found) && (gpf->framenum == cframe))
gpl->actframe = gpf;
+ else if (addnew == GP_GETFRAME_ADD_COPY)
+ gpl->actframe = gpencil_frame_addcopy(gpl, cframe);
else
gpl->actframe = gpencil_frame_addnew(gpl, cframe);
}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 3f68339be11..a44eb1df9fe 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -73,9 +73,8 @@ void BKE_group_free(Group *group)
}
}
-void BKE_group_unlink(Group *group)
+void BKE_group_unlink(Main *bmain, Group *group)
{
- Main *bmain = G.main;
Material *ma;
Object *ob;
Scene *sce;
@@ -183,6 +182,7 @@ static bool group_object_add_internal(Group *group, Object *ob)
BLI_addtail(&group->gobject, go);
go->ob = ob;
+ id_us_ensure_real(&go->ob->id);
return true;
}
@@ -232,12 +232,12 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group)
{
if (object->dup_group) {
Group *dup_group = object->dup_group;
- if ((dup_group->id.flag & LIB_DOIT) == 0) {
+ if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) {
/* Cycle already exists in groups, let's prevent further crappyness */
return true;
}
/* flag the object to identify cyclic dependencies in further dupli groups */
- dup_group->id.flag &= ~LIB_DOIT;
+ dup_group->id.tag &= ~LIB_TAG_DOIT;
if (dup_group == group)
return true;
@@ -251,7 +251,7 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group)
}
/* un-flag the object, it's allowed to have the same group multiple times in parallel */
- dup_group->id.flag |= LIB_DOIT;
+ dup_group->id.tag |= LIB_TAG_DOIT;
}
return false;
@@ -260,7 +260,7 @@ static bool group_object_cyclic_check_internal(Object *object, Group *group)
bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
{
/* first flag all groups */
- BKE_main_id_tag_listbase(&bmain->group, true);
+ BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true);
return group_object_cyclic_check_internal(object, group);
}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 2171f193bac..f3e86b44459 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -55,7 +55,7 @@
#include "BLI_sys_types.h" // for intptr_t support
-#include "GPU_extensions.h"
+#include "GPU_texture.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -273,9 +273,10 @@ PreviewImage *BKE_previewimg_cached_get(const char *name)
PreviewImage *BKE_previewimg_cached_ensure(const char *name)
{
PreviewImage *prv = NULL;
- void **prv_p;
+ void **key_p, **prv_p;
- if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &prv_p, (GHashKeyCopyFP)BLI_strdup)) {
+ if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
+ *key_p = BLI_strdup(name);
*prv_p = BKE_previewimg_create();
}
prv = *prv_p;
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index cf1eb8838e9..68a741bc3fc 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -103,12 +103,12 @@ static IDType *idtype_from_name(const char *str)
return NULL;
}
-static IDType *idtype_from_code(int code)
+static IDType *idtype_from_code(short idcode)
{
int i = ARRAY_SIZE(idtypes);
while (i--)
- if (code == idtypes[i].code)
+ if (idcode == idtypes[i].code)
return &idtypes[i];
return NULL;
@@ -120,9 +120,9 @@ static IDType *idtype_from_code(int code)
* \param code The code to check.
* \return Boolean, 0 when invalid.
*/
-bool BKE_idcode_is_valid(int code)
+bool BKE_idcode_is_valid(short idcode)
{
- return idtype_from_code(code) ? true : false;
+ return idtype_from_code(idcode) ? true : false;
}
/**
@@ -131,9 +131,9 @@ bool BKE_idcode_is_valid(int code)
* \param code The code to check.
* \return Boolean, 0 when non linkable.
*/
-bool BKE_idcode_is_linkable(int code)
+bool BKE_idcode_is_linkable(short idcode)
{
- IDType *idt = idtype_from_code(code);
+ IDType *idt = idtype_from_code(idcode);
BLI_assert(idt);
return idt ? ((idt->flags & IDTYPE_FLAGS_ISLINKABLE) != 0) : false;
}
@@ -145,9 +145,9 @@ bool BKE_idcode_is_linkable(int code)
* \return A static string representing the name of
* the code.
*/
-const char *BKE_idcode_to_name(int code)
+const char *BKE_idcode_to_name(short idcode)
{
- IDType *idt = idtype_from_code(code);
+ IDType *idt = idtype_from_code(idcode);
BLI_assert(idt);
return idt ? idt->name : NULL;
}
@@ -158,7 +158,7 @@ const char *BKE_idcode_to_name(int code)
* \param name The name to convert.
* \return The code for the name, or 0 if invalid.
*/
-int BKE_idcode_from_name(const char *name)
+short BKE_idcode_from_name(const char *name)
{
IDType *idt = idtype_from_name(name);
BLI_assert(idt);
@@ -168,7 +168,7 @@ int BKE_idcode_from_name(const char *name)
/**
* Convert an idcode into an idfilter (e.g. ID_OB -> FILTER_ID_OB).
*/
-int BKE_idcode_to_idfilter(const int idcode)
+int BKE_idcode_to_idfilter(const short idcode)
{
#define CASE_IDFILTER(_id) case ID_##_id: return FILTER_ID_##_id
@@ -211,7 +211,7 @@ int BKE_idcode_to_idfilter(const int idcode)
/**
* Convert an idfilter into an idcode (e.g. FILTER_ID_OB -> ID_OB).
*/
-int BKE_idcode_from_idfilter(const int idfilter)
+short BKE_idcode_from_idfilter(const int idfilter)
{
#define CASE_IDFILTER(_id) case FILTER_ID_##_id: return ID_##_id
@@ -258,9 +258,9 @@ int BKE_idcode_from_idfilter(const int idfilter)
* \return A static string representing the name of
* the code.
*/
-const char *BKE_idcode_to_name_plural(int code)
+const char *BKE_idcode_to_name_plural(short idcode)
{
- IDType *idt = idtype_from_code(code);
+ IDType *idt = idtype_from_code(idcode);
BLI_assert(idt);
return idt ? idt->plural : NULL;
}
@@ -271,9 +271,9 @@ const char *BKE_idcode_to_name_plural(int code)
* \param code The code to convert.
* \return A static string representing the i18n context of the code.
*/
-const char *BKE_idcode_to_translation_context(int code)
+const char *BKE_idcode_to_translation_context(short idcode)
{
- IDType *idt = idtype_from_code(code);
+ IDType *idt = idtype_from_code(idcode);
BLI_assert(idt);
return idt ? idt->i18n_context : BLT_I18NCONTEXT_DEFAULT;
}
@@ -284,7 +284,7 @@ const char *BKE_idcode_to_translation_context(int code)
* \param index start as 0.
* \return the code, 0 when all codes have been returned.
*/
-int BKE_idcode_iter_step(int *index)
+short BKE_idcode_iter_step(int *index)
{
return (*index < ARRAY_SIZE(idtypes)) ? idtypes[(*index)++].code : 0;
}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 4d83f8cf916..86d010f5f7c 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -439,14 +439,15 @@ void IDP_FreeString(IDProperty *prop)
* \{ */
void IDP_LinkID(IDProperty *prop, ID *id)
{
- if (prop->data.pointer) ((ID *)prop->data.pointer)->us--;
+ if (prop->data.pointer)
+ id_us_min(((ID *)prop->data.pointer));
prop->data.pointer = id;
id_us_plus(id);
}
void IDP_UnlinkID(IDProperty *prop)
{
- ((ID *)prop->data.pointer)->us--;
+ id_us_min(((ID *)prop->data.pointer));
}
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 4a76c704130..cdb3d1afc29 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -100,7 +100,7 @@
static SpinLock image_spin;
/* prototypes */
-static size_t image_num_files(struct Image *ima);
+static int image_num_files(struct Image *ima);
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock);
static void image_update_views_format(Image *ima, ImageUser *iuser);
static void image_add_view(Image *ima, const char *viewname, const char *filepath);
@@ -280,14 +280,9 @@ void BKE_image_free_packedfiles(Image *ima)
image_free_packedfiles(ima);
}
-static void image_free_views(Image *ima)
-{
- BLI_freelistN(&ima->views);
-}
-
void BKE_image_free_views(Image *image)
{
- image_free_views(image);
+ BLI_freelistN(&image->views);
}
static void image_free_anims(Image *ima)
@@ -350,7 +345,7 @@ void BKE_image_free(Image *ima)
}
}
- image_free_views(ima);
+ BKE_image_free_views(ima);
MEM_freeN(ima->stereo3d_format);
}
@@ -557,8 +552,8 @@ void BKE_image_make_local(struct Image *ima)
if (tex->id.lib == NULL) {
if (tex->ima == ima) {
tex->ima = ima_new;
- ima_new->id.us++;
- ima->id.us--;
+ id_us_plus(&ima_new->id);
+ id_us_min(&ima->id);
}
}
tex = tex->id.next;
@@ -568,8 +563,8 @@ void BKE_image_make_local(struct Image *ima)
if (brush->id.lib == NULL) {
if (brush->clone.image == ima) {
brush->clone.image = ima_new;
- ima_new->id.us++;
- ima->id.us--;
+ id_us_plus(&ima_new->id);
+ id_us_min(&ima->id);
}
}
brush = brush->id.next;
@@ -590,9 +585,7 @@ void BKE_image_make_local(struct Image *ima)
for (a = 0; a < me->totface; a++, tface++) {
if (tface->tpage == ima) {
tface->tpage = ima_new;
- if (ima_new->id.us == 0) {
- tface->tpage->id.us = 1;
- }
+ id_us_ensure_real((ID *)ima_new);
id_lib_extern((ID *)ima_new);
}
}
@@ -611,9 +604,7 @@ void BKE_image_make_local(struct Image *ima)
for (a = 0; a < me->totpoly; a++, mtpoly++) {
if (mtpoly->tpage == ima) {
mtpoly->tpage = ima_new;
- if (ima_new->id.us == 0) {
- mtpoly->tpage->id.us = 1;
- }
+ id_us_ensure_real((ID *)ima_new);
id_lib_extern((ID *)ima_new);
}
}
@@ -666,6 +657,18 @@ bool BKE_image_scale(Image *image, int width, int height)
return (ibuf != NULL);
}
+bool BKE_image_has_bindcode(Image *ima)
+{
+ bool has_bindcode = false;
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ if (ima->bindcode[i]) {
+ has_bindcode = true;
+ break;
+ }
+ }
+ return has_bindcode;
+}
+
static void image_init_color_management(Image *ima)
{
ImBuf *ibuf;
@@ -704,8 +707,7 @@ void BKE_image_alpha_mode_from_extension(Image *image)
Image *BKE_image_load(Main *bmain, const char *filepath)
{
Image *ima;
- int file, len;
- const char *libname;
+ int file;
char str[FILE_MAX];
BLI_strncpy(str, filepath, sizeof(str));
@@ -717,13 +719,7 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
return NULL;
close(file);
- /* create a short library name */
- len = strlen(filepath);
-
- while (len > 0 && filepath[len - 1] != '/' && filepath[len - 1] != '\\') len--;
- libname = filepath + len;
-
- ima = image_alloc(bmain, libname, IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
BLI_strncpy(ima->name, filepath, sizeof(ima->name));
if (BLI_testextensie_array(filepath, imb_ext_movie))
@@ -746,7 +742,7 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
BLI_strncpy(str, filepath, sizeof(str));
BLI_path_abs(str, G.main->name);
- /* first search an identical image */
+ /* first search an identical filepath */
for (ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->source != IMA_SRC_VIEWER && ima->source != IMA_SRC_GENERATED) {
BLI_strncpy(strtest, ima->name, sizeof(ima->name));
@@ -756,7 +752,7 @@ Image *BKE_image_load_exists_ex(const char *filepath, bool *r_exists)
if ((BKE_image_has_anim(ima) == false) ||
(ima->id.us == 0))
{
- ima->id.us++; /* officially should not, it doesn't link here! */
+ id_us_plus(&ima->id); /* officially should not, it doesn't link here! */
if (ima->ok == 0)
ima->ok = IMA_OK;
if (r_exists)
@@ -843,13 +839,15 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char
}
/* adds new image block, creates ImBuf and initializes color */
-Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int height, const char *name, int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d)
+Image *BKE_image_add_generated(
+ Main *bmain, unsigned int width, unsigned int height, const char *name,
+ int depth, int floatbuf, short gen_type, const float color[4], const bool stereo3d)
{
/* on save, type is changed to FILE in editsima.c */
Image *ima = image_alloc(bmain, name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
if (ima) {
- size_t view_id;
+ int view_id;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
/* BLI_strncpy(ima->name, name, FILE_MAX); */ /* don't do this, this writes in ain invalid filepath! */
@@ -873,8 +871,6 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
}
ima->ok = IMA_OK_LOADED;
- if (stereo3d)
- ima->flag |= IMA_IS_STEREO | IMA_IS_MULTIVIEW;
}
return ima;
@@ -909,7 +905,7 @@ Image *BKE_image_add_from_imbuf(ImBuf *ibuf, const char *name)
static void image_memorypack_multiview(Image *ima)
{
ImageView *iv;
- size_t i;
+ int i;
image_free_packedfiles(ima);
@@ -964,7 +960,7 @@ void BKE_image_memorypack(Image *ima)
{
ImBuf *ibuf;
- if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ if (BKE_image_is_multiview(ima)) {
image_memorypack_multiview(ima);
return;
}
@@ -1010,7 +1006,7 @@ void BKE_image_memorypack(Image *ima)
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
{
- const size_t totfiles = image_num_files(ima);
+ const int totfiles = image_num_files(ima);
if (totfiles == 1) {
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image packed file");
@@ -1042,7 +1038,7 @@ void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
void BKE_image_packfiles_from_mem(ReportList *reports, Image *ima, char *data, const size_t data_len)
{
- const size_t totfiles = image_num_files(ima);
+ const int totfiles = image_num_files(ima);
if (totfiles != 1) {
BKE_report(reports, RPT_ERROR, "Cannot pack multiview images from raw data currently...");
@@ -1154,14 +1150,14 @@ void BKE_image_free_all_textures(void)
#endif
for (ima = G.main->image.first; ima; ima = ima->id.next)
- ima->id.flag &= ~LIB_DOIT;
+ ima->id.tag &= ~LIB_TAG_DOIT;
for (tex = G.main->tex.first; tex; tex = tex->id.next)
if (tex->ima)
- tex->ima->id.flag |= LIB_DOIT;
+ tex->ima->id.tag |= LIB_TAG_DOIT;
for (ima = G.main->image.first; ima; ima = ima->id.next) {
- if (ima->cache && (ima->id.flag & LIB_DOIT)) {
+ if (ima->cache && (ima->id.tag & LIB_TAG_DOIT)) {
#ifdef CHECK_FREED_SIZE
uintptr_t old_size = image_mem_size(ima);
#endif
@@ -1370,6 +1366,7 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file)
if (write_file) break;
/* fall-through */
case R_IMF_IMTYPE_TARGA:
+ case R_IMF_IMTYPE_RAWTGA:
case R_IMF_IMTYPE_IRIS:
case R_IMF_IMTYPE_PNG:
case R_IMF_IMTYPE_RADHDR:
@@ -1427,7 +1424,7 @@ char BKE_imtype_valid_depths(const char imtype)
/* string is from command line --render-format arg, keep in sync with
- * creator.c help info */
+ * creator_args.c help info */
char BKE_imtype_from_arg(const char *imtype_arg)
{
if (STREQ(imtype_arg, "TGA")) return R_IMF_IMTYPE_TARGA;
@@ -1638,6 +1635,14 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i
im_format->imtype = R_IMF_IMTYPE_TIFF;
if (custom_flags & TIF_16BIT)
im_format->depth = R_IMF_CHAN_DEPTH_16;
+ if (custom_flags & TIF_COMPRESS_NONE)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_NONE;
+ if (custom_flags & TIF_COMPRESS_DEFLATE)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_DEFLATE;
+ if (custom_flags & TIF_COMPRESS_LZW)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_LZW;
+ if (custom_flags & TIF_COMPRESS_PACKBITS)
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_PACKBITS;
}
#endif
@@ -1860,8 +1865,81 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
}
}
+/* Will always add prefix. */
+static void stampdata_from_template(StampData *stamp_data,
+ const Scene *scene,
+ const StampData *stamp_data_template)
+{
+ if (scene->r.stamp & R_STAMP_FILENAME) {
+ BLI_snprintf(stamp_data->file, sizeof(stamp_data->file), "File %s", stamp_data_template->file);
+ }
+ else {
+ stamp_data->file[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_NOTE) {
+ BLI_snprintf(stamp_data->note, sizeof(stamp_data->note), "%s", stamp_data_template->note);
+ }
+ else {
+ stamp_data->note[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_DATE) {
+ BLI_snprintf(stamp_data->date, sizeof(stamp_data->date), "Date %s", stamp_data_template->date);
+ }
+ else {
+ stamp_data->date[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_MARKER) {
+ BLI_snprintf(stamp_data->marker, sizeof(stamp_data->marker), "Marker %s", stamp_data_template->marker);
+ }
+ else {
+ stamp_data->marker[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_TIME) {
+ BLI_snprintf(stamp_data->time, sizeof(stamp_data->time), "Timecode %s", stamp_data_template->time);
+ }
+ else {
+ stamp_data->time[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_FRAME) {
+ BLI_snprintf(stamp_data->frame, sizeof(stamp_data->frame), "Frame %s", stamp_data_template->frame);
+ }
+ else {
+ stamp_data->frame[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_CAMERA) {
+ BLI_snprintf(stamp_data->camera, sizeof(stamp_data->camera), "Camera %s", stamp_data_template->camera);
+ }
+ else {
+ stamp_data->camera[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_CAMERALENS) {
+ BLI_snprintf(stamp_data->cameralens, sizeof(stamp_data->cameralens), "Lens %s", stamp_data_template->cameralens);
+ }
+ else {
+ stamp_data->cameralens[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_SCENE) {
+ BLI_snprintf(stamp_data->scene, sizeof(stamp_data->scene), "Scene %s", stamp_data_template->scene);
+ }
+ else {
+ stamp_data->scene[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_SEQSTRIP) {
+ BLI_snprintf(stamp_data->strip, sizeof(stamp_data->strip), "Strip %s", stamp_data_template->strip);
+ }
+ else {
+ stamp_data->strip[0] = '\0';
+ }
+ if (scene->r.stamp & R_STAMP_RENDERTIME) {
+ BLI_snprintf(stamp_data->rendertime, sizeof(stamp_data->rendertime), "RenderTime %s", stamp_data_template->rendertime);
+ }
+ else {
+ stamp_data->rendertime[0] = '\0';
+ }
+}
+
void BKE_image_stamp_buf(
- Scene *scene, Object *camera,
+ Scene *scene, Object *camera, const StampData *stamp_data_template,
unsigned char *rect, float *rectf, int width, int height, int channels)
{
struct StampData stamp_data;
@@ -1898,7 +1976,12 @@ void BKE_image_stamp_buf(
display_device = scene->display_settings.display_device;
display = IMB_colormanagement_display_get_named(display_device);
- stampdata(scene, camera, &stamp_data, 1);
+ if (stamp_data_template == NULL) {
+ stampdata(scene, camera, &stamp_data, 1);
+ }
+ else {
+ stampdata_from_template(&stamp_data, scene, stamp_data_template);
+ }
/* TODO, do_versions */
if (scene->r.stamp_font_id < 8)
@@ -1909,7 +1992,7 @@ void BKE_image_stamp_buf(
BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2));
BLF_buffer(mono, rectf, rect, width, height, channels, display);
- BLF_buffer_col(mono, scene->r.fg_stamp[0], scene->r.fg_stamp[1], scene->r.fg_stamp[2], 1.0);
+ BLF_buffer_col(mono, UNPACK4(scene->r.fg_stamp));
pad = BLF_width_max(mono);
/* use 'h_fixed' rather than 'h', aligns better */
@@ -2109,7 +2192,7 @@ void BKE_render_result_stamp_info(Scene *scene, Object *camera, struct RenderRes
void BKE_stamp_info_callback(void *data, struct StampData *stamp_data, StampCallback callback, bool noskip)
{
- if (!callback || !stamp_data) {
+ if ((callback == NULL) || (stamp_data == NULL)) {
return;
}
@@ -2183,12 +2266,15 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
/* note: imf->planes is ignored here, its assumed the image channels
* are already set */
-void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf)
+void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
{
char imtype = imf->imtype;
char compress = imf->compress;
char quality = imf->quality;
+ /* initialize all from image format */
+ ibuf->foptions.flag = 0;
+
if (imtype == R_IMF_IMTYPE_IRIS) {
ibuf->ftype = IMB_FTYPE_IMAGIC;
}
@@ -2220,8 +2306,21 @@ void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf)
else if (imtype == R_IMF_IMTYPE_TIFF) {
ibuf->ftype = IMB_FTYPE_TIF;
- if (imf->depth == R_IMF_CHAN_DEPTH_16)
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
ibuf->foptions.flag |= TIF_16BIT;
+ }
+ if (imf->tiff_codec == R_IMF_TIFF_CODEC_NONE) {
+ ibuf->foptions.flag |= TIF_COMPRESS_NONE;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_DEFLATE) {
+ ibuf->foptions.flag |= TIF_COMPRESS_DEFLATE;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_LZW) {
+ ibuf->foptions.flag |= TIF_COMPRESS_LZW;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_PACKBITS) {
+ ibuf->foptions.flag |= TIF_COMPRESS_PACKBITS;
+ }
}
#endif
#ifdef WITH_OPENEXR
@@ -2314,7 +2413,7 @@ void BKE_imbuf_write_prepare(ImBuf *ibuf, ImageFormatData *imf)
}
}
-int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
+int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
{
int ok;
@@ -2348,12 +2447,15 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf,
/* note that we are not restoring _all_ settings */
ibuf->planes = ibuf_back.planes;
ibuf->ftype = ibuf_back.ftype;
+ ibuf->foptions = ibuf_back.foptions;
}
return ok;
}
-int BKE_imbuf_write_stamp(Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name, struct ImageFormatData *imf)
+int BKE_imbuf_write_stamp(
+ Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name,
+ const struct ImageFormatData *imf)
{
if (scene && scene->r.stamp & R_STAMP_ALL)
BKE_imbuf_stamp_info(rr, ibuf);
@@ -2490,15 +2592,8 @@ void BKE_image_verify_viewer_views(const RenderData *rd, Image *ima, ImageUser *
BLI_lock_thread(LOCK_DRAW_IMAGE);
- if (BKE_scene_multiview_is_stereo3d(rd)) {
- ima->flag |= IMA_IS_STEREO;
- ima->flag |= IMA_IS_MULTIVIEW;
- }
- else {
- ima->flag &= ~IMA_IS_STEREO;
- ima->flag &= ~IMA_IS_MULTIVIEW;
+ if (!BKE_scene_multiview_is_stereo3d(rd))
iuser->flag &= ~IMA_SHOW_STEREO;
- }
/* see if all scene render views are in the image view list */
do_reset = (BKE_scene_multiview_num_views_get(rd) != BLI_listbase_count(&ima->views));
@@ -2544,6 +2639,17 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
if (tex->type == TEX_IMAGE && tex->ima) {
callback(tex->ima, &tex->iuser, customdata);
}
+
+ if (tex->nodetree) {
+ bNode *node;
+ for (node = tex->nodetree->nodes.first; node; node = node->next) {
+ if (node->id && node->type == TEX_NODE_IMAGE) {
+ Image *ima = (Image *)node->id;
+ ImageUser *iuser = node->storage;
+ callback(ima, iuser, customdata);
+ }
+ }
+ }
}
/* image window, compo node users */
@@ -2674,7 +2780,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
case IMA_SIGNAL_RELOAD:
/* try to repack file */
if (BKE_image_has_packedfile(ima)) {
- const size_t totfiles = image_num_files(ima);
+ const int totfiles = image_num_files(ima);
if (totfiles != BLI_listbase_count_ex(&ima->packedfiles, totfiles + 1)) {
/* in case there are new available files to be loaded */
@@ -2828,7 +2934,7 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
void BKE_image_multiview_index(Image *ima, ImageUser *iuser)
{
if (iuser) {
- bool is_stereo = (ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO);
+ bool is_stereo = BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO);
if (is_stereo) {
iuser->multi_index = iuser->multiview_eye;
}
@@ -2861,27 +2967,47 @@ bool BKE_image_is_multilayer(Image *ima)
return false;
}
-static void image_init_multilayer_multiview_flag(Image *ima, RenderResult *rr)
+bool BKE_image_is_multiview(Image *ima)
{
- if (rr) {
- if (RE_RenderResult_is_stereo(rr)) {
- ima->flag |= IMA_IS_STEREO;
- ima->flag |= IMA_IS_MULTIVIEW;
- }
- else {
- ima->flag &= ~IMA_IS_STEREO;
- if (BLI_listbase_count_ex(&rr->views, 2) > 1)
- ima->flag |= IMA_IS_MULTIVIEW;
- else
- ima->flag &= ~IMA_IS_MULTIVIEW;
+ return (BLI_listbase_count_ex(&ima->views, 2) > 1);
+}
+
+bool BKE_image_is_stereo(Image *ima)
+{
+ return BKE_image_is_multiview(ima) &&
+ (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
+ BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)));
+}
+
+static void image_init_multilayer_multiview(Image *ima, RenderResult *rr)
+{
+ /* update image views from render views, but only if they actually changed,
+ * to avoid invalid memory access during render. ideally these should always
+ * be acquired with a mutex along with the render result, but there are still
+ * some places with just an image pointer that need to access views */
+ if (rr && BLI_listbase_count(&ima->views) == BLI_listbase_count(&rr->views)) {
+ ImageView *iv = ima->views.first;
+ RenderView *rv = rr->views.first;
+ bool modified = false;
+ for (; rv; rv = rv->next, iv = iv->next) {
+ modified |= !STREQ(rv->name, iv->name);
}
+ if (!modified)
+ return;
}
- else {
- ima->flag &= ~IMA_IS_STEREO;
- ima->flag &= ~IMA_IS_MULTIVIEW;
+
+ BKE_image_free_views(ima);
+
+ if (rr) {
+ for (RenderView *rv = rr->views.first; rv; rv = rv->next) {
+ ImageView *iv = MEM_callocN(sizeof(ImageView), "Viewer Image View");
+ BLI_strncpy(iv->name, rv->name, sizeof(iv->name));
+ BLI_addtail(&ima->views, iv);
+ }
}
}
+
RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
{
RenderResult *rr = NULL;
@@ -2894,8 +3020,8 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
else
rr = ima->renders[ima->render_slot];
- /* set proper multiview flag */
- image_init_multilayer_multiview_flag(ima, rr);
+ /* set proper views */
+ image_init_multilayer_multiview(ima, rr);
}
return rr;
@@ -2924,7 +3050,7 @@ bool BKE_image_is_openexr(struct Image *ima)
return false;
}
-void BKE_image_backup_render(Scene *scene, Image *ima)
+void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
{
/* called right before rendering, ima->renders contains render
* result pointers for everything but the current render */
@@ -2932,13 +3058,18 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
int slot = ima->render_slot, last = ima->last_render_slot;
if (slot != last) {
- if (ima->renders[slot]) {
- RE_FreeRenderResult(ima->renders[slot]);
- ima->renders[slot] = NULL;
- }
-
ima->renders[last] = NULL;
RE_SwapResult(re, &ima->renders[last]);
+
+ if (ima->renders[slot]) {
+ if (free_current_slot) {
+ RE_FreeRenderResult(ima->renders[slot]);
+ ima->renders[slot] = NULL;
+ }
+ else {
+ RE_SwapResult(re, &ima->renders[slot]);
+ }
+ }
}
ima->last_render_slot = slot;
@@ -2946,7 +3077,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima)
/**************************** multiview save openexr *********************************/
#ifdef WITH_OPENEXR
-static const char *image_get_view_cb(void *base, const size_t view_id)
+static const char *image_get_view_cb(void *base, const int view_id)
{
Image *ima = base;
ImageView *iv = BLI_findlink(&ima->views, view_id);
@@ -2955,7 +3086,7 @@ static const char *image_get_view_cb(void *base, const size_t view_id)
#endif /* WITH_OPENEXR */
#ifdef WITH_OPENEXR
-static ImBuf *image_get_buffer_cb(void *base, const size_t view_id)
+static ImBuf *image_get_buffer_cb(void *base, const int view_id)
{
Image *ima = base;
ImageUser iuser = {0};
@@ -3031,7 +3162,7 @@ static void image_add_view_cb(void *base, const char *str)
static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const int frame)
{
Image *ima = base;
- size_t id;
+ int id;
bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
const char *colorspace = ima->colorspace_settings.name;
const char *to_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
@@ -3053,39 +3184,15 @@ static void image_add_buffer_cb(void *base, const char *str, ImBuf *ibuf, const
}
#endif /* WITH_OPENEXR */
-#ifdef WITH_OPENEXR
-static void image_update_multiview_flags(Image *ima)
-{
- if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
- ima->flag |= IMA_IS_MULTIVIEW;
-
- if (BLI_findstring(&ima->views, STEREO_LEFT_NAME, offsetof(ImageView, name)) &&
- BLI_findstring(&ima->views, STEREO_RIGHT_NAME, offsetof(ImageView, name)))
- {
- ima->flag |= IMA_IS_STEREO;
- }
- else {
- ima->flag &= ~IMA_IS_STEREO;
- }
- }
- else {
- ima->flag &= ~IMA_IS_STEREO;
- ima->flag &= ~IMA_IS_MULTIVIEW;
- }
-}
-#endif /* WITH_OPENEXR */
-
/* after imbuf load, openexr type can return with a exrhandle open */
/* in that case we have to build a render-result */
#ifdef WITH_OPENEXR
static void image_create_multiview(Image *ima, ImBuf *ibuf, const int frame)
{
- image_free_views(ima);
+ BKE_image_free_views(ima);
IMB_exr_multiview_convert(ibuf->userdata, ima, image_add_view_cb, image_add_buffer_cb, frame);
- image_update_multiview_flags(ima);
-
IMB_exr_close(ibuf->userdata);
}
#endif /* WITH_OPENEXR */
@@ -3098,7 +3205,9 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
const char *colorspace = ima->colorspace_settings.name;
bool predivide = (ima->alpha_mode == IMA_ALPHA_PREMUL);
- ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
+ /* only load rr once for multiview */
+ if (!ima->rr)
+ ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y);
IMB_exr_close(ibuf->userdata);
@@ -3106,8 +3215,8 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
if (ima->rr)
ima->rr->framenr = framenr;
- /* set proper multiview flag */
- image_init_multilayer_multiview_flag(ima, ima->rr);
+ /* set proper views */
+ image_init_multilayer_multiview(ima, ima->rr);
}
#endif /* WITH_OPENEXR */
@@ -3143,9 +3252,9 @@ static int imbuf_alpha_flags_for_image(Image *ima)
}
/* the number of files will vary according to the stereo format */
-static size_t image_num_files(Image *ima)
+static int image_num_files(Image *ima)
{
- const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
+ const bool is_multiview = BKE_image_is_multiview(ima);
if (!is_multiview) {
return 1;
@@ -3159,7 +3268,7 @@ static size_t image_num_files(Image *ima)
}
}
-static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id, bool *r_assign)
+static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, const int view_id, bool *r_assign)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
@@ -3227,8 +3336,8 @@ static ImBuf *load_sequence_single(Image *ima, ImageUser *iuser, int frame, cons
static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
{
struct ImBuf *ibuf = NULL;
- const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
- const size_t totfiles = image_num_files(ima);
+ const bool is_multiview = BKE_image_is_multiview(ima);
+ const int totfiles = image_num_files(ima);
bool assign = false;
if (!is_multiview) {
@@ -3238,16 +3347,16 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
}
}
else {
- size_t i;
+ const int totviews = BLI_listbase_count(&ima->views);
+ int i;
struct ImBuf **ibuf_arr;
- const size_t totviews = BLI_listbase_count(&ima->views);
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
for (i = 0; i < totfiles; i++)
ibuf_arr[i] = load_sequence_single(ima, iuser, frame, i, &assign);
- if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
/* return the original requested ImBuf */
@@ -3325,7 +3434,7 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
return ibuf;
}
-static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const size_t view_id)
+static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const int view_id)
{
struct ImBuf *ibuf = NULL;
ImageAnim *ia;
@@ -3384,9 +3493,9 @@ static ImBuf *load_movie_single(Image *ima, ImageUser *iuser, int frame, const s
static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
{
struct ImBuf *ibuf = NULL;
- const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
- const size_t totfiles = image_num_files(ima);
- size_t i;
+ const bool is_multiview = BKE_image_is_multiview(ima);
+ const int totfiles = image_num_files(ima);
+ int i;
if (totfiles != BLI_listbase_count_ex(&ima->anims, totfiles + 1)) {
image_free_anims(ima);
@@ -3404,7 +3513,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
else {
struct ImBuf **ibuf_arr;
- const size_t totviews = BLI_listbase_count(&ima->views);
+ const int totviews = BLI_listbase_count(&ima->views);
ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * totviews, "Image Views (movie) Imbufs");
@@ -3412,7 +3521,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
ibuf_arr[i] = load_movie_single(ima, iuser, frame, i);
}
- if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
+ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D)
IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
for (i = 0; i < totviews; i++) {
@@ -3446,7 +3555,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
static ImBuf *load_image_single(
Image *ima, ImageUser *iuser, int cfra,
- const size_t view_id,
+ const int view_id,
const bool has_packed,
bool *r_assign)
{
@@ -3540,8 +3649,8 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
{
struct ImBuf *ibuf = NULL;
bool assign = false;
- const bool is_multiview = (ima->flag & IMA_IS_MULTIVIEW) != 0;
- const size_t totfiles = image_num_files(ima);
+ const bool is_multiview = BKE_image_is_multiview(ima);
+ const int totfiles = image_num_files(ima);
bool has_packed = BKE_image_has_packedfile(ima);
/* always ensure clean ima */
@@ -3562,9 +3671,9 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
}
}
else {
- size_t i;
struct ImBuf **ibuf_arr;
- const size_t totviews = BLI_listbase_count(&ima->views);
+ const int totviews = BLI_listbase_count(&ima->views);
+ int i;
BLI_assert(totviews > 0);
ibuf_arr = MEM_callocN(sizeof(ImBuf *) * totviews, "Image Views Imbufs");
@@ -3573,7 +3682,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
ibuf_arr[i] = load_image_single(ima, iuser, cfra, i, has_packed, &assign);
/* multi-views/multi-layers OpenEXR files directly populate ima, and return NULL ibuf... */
- if ((ima->flag & IMA_IS_STEREO) && ima->views_format == R_IMF_VIEWS_STEREO_3D &&
+ if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D &&
ibuf_arr[0] && totfiles == 1 && totviews >= 2)
{
IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
@@ -3673,7 +3782,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
pass = iuser->pass;
actview = iuser->view;
- if ((ima->flag & IMA_IS_STEREO) && (iuser->flag & IMA_SHOW_STEREO))
+ if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
actview = iuser->multiview_eye;
if (from_render) {
@@ -3837,7 +3946,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
return ibuf;
}
-static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
+static int image_get_multiview_index(Image *ima, ImageUser *iuser)
{
const bool is_multilayer = BKE_image_is_multilayer(ima);
const bool is_backdrop = (ima->source == IMA_SRC_VIEWER) && (ima->type == IMA_TYPE_COMPOSITE) && (iuser == NULL);
@@ -3847,12 +3956,12 @@ static size_t image_get_multiview_index(Image *ima, ImageUser *iuser)
return iuser ? iuser->multi_index : index;
}
else if (is_backdrop) {
- if ((ima->flag & IMA_IS_STEREO)) {
+ if (BKE_image_is_stereo(ima)) {
/* backdrop hackaround (since there is no iuser */
return ima->eye;
}
}
- else if ((ima->flag & IMA_IS_MULTIVIEW)) {
+ else if (BKE_image_is_multiview(ima)) {
return iuser ? iuser->multi_index : index;
}
@@ -4341,9 +4450,12 @@ void BKE_image_update_frame(const Main *bmain, int cfra)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
- if ((ima->flag & IMA_IS_MULTIVIEW) && (ima->rr == NULL)) {
+ if (BKE_image_is_multiview(ima) && (ima->rr == NULL)) {
ImageView *iv = BLI_findlink(&ima->views, iuser->view);
- BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+ if (iv->filepath[0])
+ BLI_strncpy(filepath, iv->filepath, FILE_MAX);
+ else
+ BLI_strncpy(filepath, ima->name, FILE_MAX);
}
else {
BLI_strncpy(filepath, ima->name, FILE_MAX);
@@ -4382,18 +4494,33 @@ void BKE_image_get_size(Image *image, ImageUser *iuser, int *width, int *height)
ImBuf *ibuf = NULL;
void *lock;
- ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
+ if (image != NULL) {
+ ibuf = BKE_image_acquire_ibuf(image, iuser, &lock);
+ }
if (ibuf && ibuf->x > 0 && ibuf->y > 0) {
*width = ibuf->x;
*height = ibuf->y;
}
+ else if (image != NULL && image->type == IMA_TYPE_R_RESULT &&
+ iuser != NULL && iuser->scene != NULL)
+ {
+ Scene *scene = iuser->scene;
+ *width = (scene->r.xsch * scene->r.size) / 100;
+ *height = (scene->r.ysch * scene->r.size) / 100;
+ if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) {
+ *width *= BLI_rctf_size_x(&scene->r.border);
+ *height *= BLI_rctf_size_y(&scene->r.border);
+ }
+ }
else {
*width = IMG_SIZE_FALLBACK;
*height = IMG_SIZE_FALLBACK;
}
- BKE_image_release_ibuf(image, ibuf, lock);
+ if (image != NULL) {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
}
void BKE_image_get_size_fl(Image *image, ImageUser *iuser, float size[2])
@@ -4473,14 +4600,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame)
int BKE_image_sequence_guess_offset(Image *image)
{
- unsigned short numlen;
- char head[FILE_MAX], tail[FILE_MAX];
- char num[FILE_MAX] = {0};
-
- BLI_stringdec(image->name, head, tail, &numlen);
- BLI_strncpy(num, image->name + strlen(head), numlen + 1);
-
- return atoi(num);
+ return BLI_stringdec(image->name, NULL, NULL, NULL);
}
bool BKE_image_has_anim(Image *ima)
@@ -4638,15 +4758,12 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
BKE_image_free_views(ima);
if (!is_multiview) {
- goto monoview;
+ /* nothing to do */
}
else if (ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- size_t i;
+ int i;
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
- ima->flag |= IMA_IS_MULTIVIEW;
- ima->flag |= IMA_IS_STEREO;
-
for (i = 0; i < 2; i++) {
image_add_view(ima, names[i], ima->name);
}
@@ -4661,7 +4778,8 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
BKE_scene_multiview_view_prefix_get(scene, name, prefix, &ext);
if (prefix[0] == '\0') {
- goto monoview;
+ BKE_image_free_views(ima);
+ return;
}
/* create all the image views */
@@ -4697,15 +4815,7 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
}
/* all good */
- if (BLI_listbase_count_ex(&ima->views, 2) > 1) {
- ima->flag |= IMA_IS_MULTIVIEW;
- if (BKE_scene_multiview_is_stereo3d(&scene->r))
- ima->flag |= IMA_IS_STEREO;
- }
- else {
-monoview:
- ima->flag &= ~IMA_IS_STEREO;
- ima->flag &= ~IMA_IS_MULTIVIEW;
+ if (!BKE_image_is_multiview(ima)) {
BKE_image_free_views(ima);
}
}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 0c3fd48628f..730d5a93758 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -71,6 +71,8 @@
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_sequencer.h"
@@ -329,7 +331,7 @@ static const char *constraint_adrcodes_to_paths(int adrcode, int *array_index)
* NOTE: as we don't have access to the keyblock where the data comes from (for now),
* we'll just use numerical indices for now...
*/
-static char *shapekey_adrcodes_to_paths(int adrcode, int *UNUSED(array_index))
+static char *shapekey_adrcodes_to_paths(ID *id, int adrcode, int *UNUSED(array_index))
{
static char buf[128];
@@ -339,8 +341,19 @@ static char *shapekey_adrcodes_to_paths(int adrcode, int *UNUSED(array_index))
BLI_strncpy(buf, "eval_time", sizeof(buf));
}
else {
+ /* Find the name of the ShapeKey (i.e. KeyBlock) to look for */
+ Key *key = (Key *)id;
+ KeyBlock *kb = BKE_keyblock_from_key(key, adrcode);
+
/* setting that we alter is the "value" (i.e. keyblock.curval) */
- BLI_snprintf(buf, sizeof(buf), "key_blocks[%d].value", adrcode);
+ if (kb) {
+ /* Use the keyblock name, escaped, so that path lookups for this will work */
+ BLI_snprintf(buf, sizeof(buf), "key_blocks[\"%s\"].value", kb->name);
+ }
+ else {
+ /* Fallback - Use the adrcode as index directly, so that this can be manually fixed */
+ BLI_snprintf(buf, sizeof(buf), "key_blocks[%d].value", adrcode);
+ }
}
return buf;
}
@@ -798,13 +811,14 @@ static const char *particle_adrcodes_to_paths(int adrcode, int *array_index)
/* Allocate memory for RNA-path for some property given a blocktype, adrcode, and 'root' parts of path
* Input:
+ * - id - the datablock that the curve's IPO block is attached to and/or which the new paths will start from
* - blocktype, adrcode - determines setting to get
* - actname, constname,seq - used to build path
* Output:
* - array_index - index in property's array (if applicable) to use
* - return - the allocated path...
*/
-static char *get_rna_access(int blocktype, int adrcode, char actname[], char constname[], Sequence *seq, int *array_index)
+static char *get_rna_access(ID *id, int blocktype, int adrcode, char actname[], char constname[], Sequence *seq, int *array_index)
{
DynStr *path = BLI_dynstr_new();
const char *propname = NULL;
@@ -827,7 +841,7 @@ static char *get_rna_access(int blocktype, int adrcode, char actname[], char con
break;
case ID_KE: /* shapekeys */
- propname = shapekey_adrcodes_to_paths(adrcode, &dummy_index);
+ propname = shapekey_adrcodes_to_paths(id, adrcode, &dummy_index);
break;
case ID_CO: /* constraint */
@@ -1273,7 +1287,7 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i
/* get rna-path
* - we will need to set the 'disabled' flag if no path is able to be made (for now)
*/
- fcu->rna_path = get_rna_access(icu->blocktype, icu->adrcode, actname, constname, seq, &fcu->array_index);
+ fcu->rna_path = get_rna_access(id, icu->blocktype, icu->adrcode, actname, constname, seq, &fcu->array_index);
if (fcu->rna_path == NULL)
fcu->flag |= FCURVE_DISABLED;
@@ -1429,7 +1443,7 @@ static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], S
}
/* if this IPO block doesn't have any users after this one, free... */
- ipo->id.us--;
+ id_us_min(&ipo->id);
if (ID_REAL_USERS(ipo) <= 0) {
IpoCurve *icn;
@@ -1477,7 +1491,7 @@ static void action_to_animato(ID *id, bAction *act, ListBase *groups, ListBase *
/* convert Action Channel's IPO data */
if (achan->ipo) {
ipo_to_animato(id, achan->ipo, achan->name, NULL, NULL, groups, curves, drivers);
- achan->ipo->id.us--;
+ id_us_min(&achan->ipo->id);
achan->ipo = NULL;
}
@@ -1489,7 +1503,7 @@ static void action_to_animato(ID *id, bAction *act, ListBase *groups, ListBase *
/* convert Constraint Channel's IPO data */
if (conchan->ipo) {
ipo_to_animato(id, conchan->ipo, achan->name, conchan->name, NULL, groups, curves, drivers);
- conchan->ipo->id.us--;
+ id_us_min(&conchan->ipo->id);
conchan->ipo = NULL;
}
@@ -1718,7 +1732,7 @@ void do_versions_ipos_to_animato(Main *main)
if (ob->ipo) {
ipo_to_animdata(id, ob->ipo, NULL, NULL, NULL);
- ob->ipo->id.us--;
+ id_us_min(&ob->ipo->id);
ob->ipo = NULL;
}
@@ -1726,7 +1740,7 @@ void do_versions_ipos_to_animato(Main *main)
* causing errors with evaluation in the new evaluation pipeline
*/
if (ob->action) {
- ob->action->id.us--;
+ id_us_min(&ob->action->id);
ob->action = NULL;
}
@@ -1743,7 +1757,7 @@ void do_versions_ipos_to_animato(Main *main)
/* only decrease usercount if this Action isn't now being used by AnimData */
if (ob->action != adt->action) {
- ob->action->id.us--;
+ id_us_min(&ob->action->id);
ob->action = NULL;
}
}
@@ -1751,7 +1765,7 @@ void do_versions_ipos_to_animato(Main *main)
/* IPO second... */
if (ob->ipo) {
ipo_to_animdata(id, ob->ipo, NULL, NULL, NULL);
- ob->ipo->id.us--;
+ id_us_min(&ob->ipo->id);
ob->ipo = NULL;
{
@@ -1788,7 +1802,7 @@ void do_versions_ipos_to_animato(Main *main)
* so that drivers can be added properly...
*/
ipo_to_animdata(id, con->ipo, pchan->name, con->name, NULL);
- con->ipo->id.us--;
+ id_us_min(&con->ipo->id);
con->ipo = NULL;
}
}
@@ -1808,7 +1822,7 @@ void do_versions_ipos_to_animato(Main *main)
* so that drivers can be added properly...
*/
ipo_to_animdata(id, con->ipo, NULL, con->name, NULL);
- con->ipo->id.us--;
+ id_us_min(&con->ipo->id);
con->ipo = NULL;
}
@@ -1828,7 +1842,7 @@ void do_versions_ipos_to_animato(Main *main)
/* convert Constraint Channel's IPO data */
if (conchan->ipo) {
ipo_to_animdata(id, conchan->ipo, NULL, conchan->name, NULL);
- conchan->ipo->id.us--;
+ id_us_min(&conchan->ipo->id);
conchan->ipo = NULL;
}
@@ -1865,7 +1879,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = key->ipo->blocktype;
- key->ipo->id.us--;
+ id_us_min(&key->ipo->id);
key->ipo = NULL;
}
}
@@ -1887,7 +1901,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = ma->ipo->blocktype;
- ma->ipo->id.us--;
+ id_us_min(&ma->ipo->id);
ma->ipo = NULL;
}
}
@@ -1909,7 +1923,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = wo->ipo->blocktype;
- wo->ipo->id.us--;
+ id_us_min(&wo->ipo->id);
wo->ipo = NULL;
}
}
@@ -1960,7 +1974,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = ID_SCE; /* scene-rooted */
- seq->ipo->id.us--;
+ id_us_min(&seq->ipo->id);
seq->ipo = NULL;
}
SEQ_END
@@ -1985,7 +1999,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = te->ipo->blocktype;
- te->ipo->id.us--;
+ id_us_min(&te->ipo->id);
te->ipo = NULL;
}
}
@@ -2007,7 +2021,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = ca->ipo->blocktype;
- ca->ipo->id.us--;
+ id_us_min(&ca->ipo->id);
ca->ipo = NULL;
}
}
@@ -2029,7 +2043,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = la->ipo->blocktype;
- la->ipo->id.us--;
+ id_us_min(&la->ipo->id);
la->ipo = NULL;
}
}
@@ -2051,7 +2065,7 @@ void do_versions_ipos_to_animato(Main *main)
if (adt->action)
adt->action->idroot = cu->ipo->blocktype;
- cu->ipo->id.us--;
+ id_us_min(&cu->ipo->id);
cu->ipo = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index b591dc19685..362f41335d2 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -58,6 +58,7 @@
#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
#include "BKE_editmesh.h"
#include "BKE_scene.h"
@@ -1392,26 +1393,51 @@ float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
}
-Key **BKE_key_from_object_p(Object *ob)
+Key **BKE_key_from_id_p(ID *id)
{
- if (ob == NULL)
- return NULL;
-
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- return &me->key;
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
- Curve *cu = ob->data;
- return &cu->key;
+ switch (GS(id->name)) {
+ case ID_ME:
+ {
+ Mesh *me = (Mesh *)id;
+ return &me->key;
+ }
+ case ID_CU:
+ {
+ Curve *cu = (Curve *)id;
+ if (cu->vfont == NULL) {
+ return &cu->key;
+ }
+ break;
+ }
+ case ID_LT:
+ {
+ Lattice *lt = (Lattice *)id;
+ return &lt->key;
+ }
}
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
- return &lt->key;
+
+ return NULL;
+}
+
+Key *BKE_key_from_id(ID *id)
+{
+ Key **key_p;
+ key_p = BKE_key_from_id_p(id);
+ if (key_p) {
+ return *key_p;
}
+
return NULL;
}
+Key **BKE_key_from_object_p(Object *ob)
+{
+ if (ob == NULL || ob->data == NULL)
+ return NULL;
+
+ return BKE_key_from_id_p(ob->data);
+}
+
Key *BKE_key_from_object(Object *ob)
{
Key **key_p;
@@ -1774,6 +1800,66 @@ void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
}
}
+/**
+ * Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
+ *
+ * \param kb the KeyBlock to use to compute normals.
+ * \param mesh the Mesh to apply keyblock to.
+ * \param r_vertnors if non-NULL, an array of vectors, same length as number of vertices.
+ * \param r_polynors if non-NULL, an array of vectors, same length as number of polygons.
+ * \param r_loopnors if non-NULL, an array of vectors, same length as number of loops.
+ */
+void BKE_keyblock_mesh_calc_normals(
+ struct KeyBlock *kb, struct Mesh *mesh,
+ float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3])
+{
+ /* We use a temp, shallow copy of mesh to work. */
+ Mesh me;
+ bool free_polynors = false;
+
+ if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) {
+ return;
+ }
+
+ me = *mesh;
+ me.mvert = MEM_dupallocN(mesh->mvert);
+ CustomData_reset(&me.vdata);
+ CustomData_reset(&me.edata);
+ CustomData_reset(&me.pdata);
+ CustomData_reset(&me.ldata);
+ CustomData_reset(&me.fdata);
+
+ BKE_keyblock_convert_to_mesh(kb, &me);
+
+ if (r_polynors == NULL && r_loopnors != NULL) {
+ r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
+ free_polynors = true;
+ }
+ BKE_mesh_calc_normals_poly(
+ me.mvert, r_vertnors, me.totvert, me.mloop, me.mpoly, me.totloop, me.totpoly, r_polynors, false);
+
+ if (r_loopnors) {
+ short (*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
+
+ BKE_mesh_normals_loop_split(
+ me.mvert, me.totvert, me.medge, me.totedge,
+ me.mloop, r_loopnors, me.totloop, me.mpoly, r_polynors, me.totpoly,
+ (me.flag & ME_AUTOSMOOTH) != 0, me.smoothresh, NULL, clnors, NULL);
+ }
+
+ CustomData_free(&me.vdata, me.totvert);
+ CustomData_free(&me.edata, me.totedge);
+ CustomData_free(&me.pdata, me.totpoly);
+ CustomData_free(&me.ldata, me.totloop);
+ CustomData_free(&me.fdata, me.totface);
+ MEM_freeN(me.mvert);
+
+ if (free_polynors) {
+ MEM_freeN(r_polynors);
+ }
+}
+
+
/************************* raw coords ************************/
void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 44e35c645de..49a573489ef 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -53,12 +53,10 @@
#include "BKE_main.h"
#include "BKE_node.h"
-Lamp *BKE_lamp_add(Main *bmain, const char *name)
+void BKE_lamp_init(Lamp *la)
{
- Lamp *la;
-
- la = BKE_libblock_alloc(bmain, ID_LA, name);
-
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id));
+
la->r = la->g = la->b = la->k = 1.0f;
la->haint = la->energy = 1.0f;
la->dist = 25.0f;
@@ -81,6 +79,9 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
la->adapt_thresh = 0.001f;
la->preview = NULL;
la->falloff_type = LA_FALLOFF_INVSQUARE;
+ la->coeff_const = 1.0f;
+ la->coeff_lin = 0.0f;
+ la->coeff_quad = 0.0f;
la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
la->sun_effect_type = 0;
la->horizon_brightness = 1.0;
@@ -100,6 +101,16 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
la->shadow_frustum_size = 10.0f;
curvemapping_initialize(la->curfalloff);
+}
+
+Lamp *BKE_lamp_add(Main *bmain, const char *name)
+{
+ Lamp *la;
+
+ la = BKE_libblock_alloc(bmain, ID_LA, name);
+
+ BKE_lamp_init(la);
+
return la;
}
@@ -201,8 +212,8 @@ void BKE_lamp_make_local(Lamp *la)
if (ob->id.lib == NULL) {
ob->data = la_new;
- la_new->id.us++;
- la->id.us--;
+ id_us_plus(&la_new->id);
+ id_us_min(&la->id);
}
}
ob = ob->id.next;
@@ -217,8 +228,10 @@ void BKE_lamp_free(Lamp *la)
for (a = 0; a < MAX_MTEX; a++) {
mtex = la->mtex[a];
- if (mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
BKE_animdata_free((ID *)la);
@@ -255,12 +268,12 @@ static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime
void lamp_drivers_update(Scene *scene, Lamp *la, float ctime)
{
/* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes la->id.flag & LIB_DOIT isn't set by anything else
+ * (see BKE_scene_update_tagged()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else
* in the meantime... [#32017] */
- if (la->id.flag & LIB_DOIT)
+ if (la->id.tag & LIB_TAG_DOIT)
return;
- la->id.flag |= LIB_DOIT;
+ la->id.tag |= LIB_TAG_DOIT;
/* lamp itself */
if (la->adt && la->adt->drivers.first)
@@ -270,6 +283,6 @@ void lamp_drivers_update(Scene *scene, Lamp *la, float ctime)
if (la->nodetree)
lamp_node_drivers_update(scene, la->nodetree, ctime);
- la->id.flag &= ~LIB_DOIT;
+ la->id.tag &= ~LIB_TAG_DOIT;
}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index f5244ffe04c..3996a35c766 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -251,12 +251,10 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
MEM_freeN(vertexCos);
}
-Lattice *BKE_lattice_add(Main *bmain, const char *name)
+void BKE_lattice_init(Lattice *lt)
{
- Lattice *lt;
-
- lt = BKE_libblock_alloc(bmain, ID_LT, name);
-
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(lt, id));
+
lt->flag = LT_GRID;
lt->typeu = lt->typev = lt->typew = KEY_BSPLINE;
@@ -264,7 +262,16 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name)
lt->def = MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
BKE_lattice_resize(lt, 2, 2, 2, NULL); /* creates a uniform lattice */
lt->actbp = LT_ACTBP_NONE;
-
+}
+
+Lattice *BKE_lattice_add(Main *bmain, const char *name)
+{
+ Lattice *lt;
+
+ lt = BKE_libblock_alloc(bmain, ID_LT, name);
+
+ BKE_lattice_init(lt);
+
return lt;
}
@@ -353,8 +360,8 @@ void BKE_lattice_make_local(Lattice *lt)
if (ob->data == lt) {
if (ob->id.lib == NULL) {
ob->data = lt_new;
- lt_new->id.us++;
- lt->id.us--;
+ id_us_plus(&lt_new->id);
+ id_us_min(&lt->id);
}
}
}
@@ -1145,8 +1152,9 @@ static void boundbox_lattice(Object *ob)
Lattice *lt;
float min[3], max[3];
- if (ob->bb == NULL)
- ob->bb = MEM_mallocN(sizeof(BoundBox), "Lattice boundbox");
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "Lattice boundbox");
+ }
bb = ob->bb;
lt = ob->data;
@@ -1154,6 +1162,8 @@ static void boundbox_lattice(Object *ob)
INIT_MINMAX(min, max);
BKE_lattice_minmax_dl(ob, lt, min, max);
BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
BoundBox *BKE_lattice_boundbox_get(Object *ob)
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 9fb0cb42dfc..895d215ca91 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -59,6 +59,7 @@
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -88,6 +89,7 @@
#include "BKE_global.h"
#include "BKE_group.h"
#include "BKE_gpencil.h"
+#include "BKE_idcode.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_ipo.h"
@@ -95,6 +97,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_linestyle.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
@@ -150,31 +153,73 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
void id_lib_extern(ID *id)
{
if (id) {
- if (id->flag & LIB_INDIRECT) {
- id->flag -= LIB_INDIRECT;
- id->flag |= LIB_EXTERN;
+ BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
+ if (id->tag & LIB_TAG_INDIRECT) {
+ id->tag -= LIB_TAG_INDIRECT;
+ id->tag |= LIB_TAG_EXTERN;
}
}
}
/* ensure we have a real user */
+/* Note: Now that we have flags, we could get rid of the 'fake_user' special case, flags are enough to ensure
+ * we always have a real user.
+ * However, ID_REAL_USERS is used in several places outside of core library.c, so think we can wait later
+ * to make this change... */
void id_us_ensure_real(ID *id)
{
if (id) {
- if (ID_REAL_USERS(id) <= 0) {
- id->us = MAX2(id->us, 0) + 1;
+ const int limit = ID_FAKE_USERS(id);
+ id->tag |= LIB_TAG_EXTRAUSER;
+ if (id->us <= limit) {
+ if (id->us < limit || ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER_SET))) {
+ printf("ID user count error: %s (from '%s')\n", id->name, id->lib ? id->lib->filepath : "[Main]");
+ BLI_assert(0);
+ }
+ id->us = limit + 1;
+ id->tag |= LIB_TAG_EXTRAUSER_SET;
}
}
}
-void id_us_plus(ID *id)
+/* Unused currently... */
+void id_us_clear_real(ID *id)
+{
+ if (id && (id->tag & LIB_TAG_EXTRAUSER)) {
+ if (id->tag & LIB_TAG_EXTRAUSER_SET) {
+ id->us--;
+ BLI_assert(id->us >= ID_FAKE_USERS(id));
+ }
+ id->tag &= ~(LIB_TAG_EXTRAUSER | LIB_TAG_EXTRAUSER_SET);
+ }
+}
+
+/**
+ * Same as \a id_us_plus, but does not handle lib indirect -> extern.
+ * Only used by readfile.c so far, but simpler/safer to keep it here nonetheless.
+ */
+void id_us_plus_no_lib(ID *id)
{
if (id) {
- id->us++;
- if (id->flag & LIB_INDIRECT) {
- id->flag -= LIB_INDIRECT;
- id->flag |= LIB_EXTERN;
+ if ((id->tag & LIB_TAG_EXTRAUSER) && (id->tag & LIB_TAG_EXTRAUSER_SET)) {
+ BLI_assert(id->us >= 1);
+ /* No need to increase count, just tag extra user as no more set.
+ * Avoids annoying & inconsistent +1 in user count. */
+ id->tag &= ~LIB_TAG_EXTRAUSER_SET;
}
+ else {
+ BLI_assert(id->us >= 0);
+ id->us++;
+ }
+ }
+}
+
+
+void id_us_plus(ID *id)
+{
+ if (id) {
+ id_us_plus_no_lib(id);
+ id_lib_extern(id);
}
}
@@ -182,15 +227,40 @@ void id_us_plus(ID *id)
void id_us_min(ID *id)
{
if (id) {
- if (id->us < 2 && (id->flag & LIB_FAKEUSER)) {
- id->us = 1;
- }
- else if (id->us <= 0) {
- printf("ID user decrement error: %s\n", id->name);
+ const int limit = ID_FAKE_USERS(id);
+
+ if (id->us <= limit) {
+ printf("ID user decrement error: %s (from '%s'): %d <= %d\n",
+ id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit);
+ /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero),
+ * this is weak but it's how it works for now. */
+ /* BLI_assert(0); */
+ id->us = limit;
}
else {
id->us--;
}
+
+ if ((id->us == limit) && (id->tag & LIB_TAG_EXTRAUSER)) {
+ /* We need an extra user here, but never actually incremented user count for it so far, do it now. */
+ id_us_ensure_real(id);
+ }
+ }
+}
+
+void id_fake_user_set(ID *id)
+{
+ if (id && !(id->flag & LIB_FAKEUSER)) {
+ id->flag |= LIB_FAKEUSER;
+ id_us_plus(id);
+ }
+}
+
+void id_fake_user_clear(ID *id)
+{
+ if (id && (id->flag & LIB_FAKEUSER)) {
+ id->flag &= ~LIB_FAKEUSER;
+ id_us_min(id);
}
}
@@ -198,7 +268,7 @@ void id_us_min(ID *id)
* if the block can be made local. */
bool id_make_local(ID *id, bool test)
{
- if (id->flag & LIB_INDIRECT)
+ if (id->tag & LIB_TAG_INDIRECT)
return false;
switch (GS(id->name)) {
@@ -262,8 +332,6 @@ bool id_make_local(ID *id, bool test)
return false; /* not implemented */
case ID_TXT:
return false; /* not implemented */
- case ID_SCRIPT:
- return false; /* deprecated */
case ID_SO:
return false; /* not implemented */
case ID_GR:
@@ -275,7 +343,7 @@ bool id_make_local(ID *id, bool test)
if (!test) BKE_action_make_local((bAction *)id);
return true;
case ID_NT:
- if (!test) ntreeMakeLocal((bNodeTree *)id);
+ if (!test) ntreeMakeLocal((bNodeTree *)id, true);
return true;
case ID_BR:
if (!test) BKE_brush_make_local((Brush *)id);
@@ -358,8 +426,6 @@ bool id_copy(ID *id, ID **newid, bool test)
case ID_TXT:
if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id);
return true;
- case ID_SCRIPT:
- return false; /* deprecated */
case ID_SO:
return false; /* not implemented */
case ID_GR:
@@ -408,11 +474,11 @@ bool id_unlink(ID *id, int test)
break;
case ID_GR:
if (test) return true;
- BKE_group_unlink((Group *)id);
+ BKE_group_unlink(mainlib, (Group *)id);
break;
case ID_OB:
if (test) return true;
- BKE_object_unlink((Object *)id);
+ BKE_object_unlink(mainlib, (Object *)id);
break;
}
@@ -494,8 +560,6 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->vfont);
case ID_TXT:
return &(mainlib->text);
- case ID_SCRIPT:
- return &(mainlib->script);
case ID_SPK:
return &(mainlib->speaker);
case ID_SO:
@@ -530,21 +594,71 @@ ListBase *which_libbase(Main *mainlib, short type)
return NULL;
}
-/* Flag all ids in listbase */
-void BKE_main_id_flag_listbase(ListBase *lb, const short flag, const bool value)
+/**
+ * Clear or set given tags for all ids in listbase (runtime tags).
+ */
+void BKE_main_id_tag_listbase(ListBase *lb, const int tag, const bool value)
+{
+ ID *id;
+ if (value) {
+ for (id = lb->first; id; id = id->next) {
+ id->tag |= tag;
+ }
+ }
+ else {
+ const int ntag = ~tag;
+ for (id = lb->first; id; id = id->next) {
+ id->tag &= ntag;
+ }
+ }
+}
+
+/**
+ * Clear or set given tags for all ids of given type in bmain (runtime tags).
+ */
+void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value)
+{
+ ListBase *lb = which_libbase(mainvar, type);
+
+ BKE_main_id_tag_listbase(lb, tag, value);
+}
+
+/**
+ * Clear or set given tags for all ids in bmain (runtime tags).
+ */
+void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ BKE_main_id_tag_listbase(lbarray[a], tag, value);
+ }
+}
+
+
+/**
+ * Clear or set given flags for all ids in listbase (persistent flags).
+ */
+void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value)
{
ID *id;
if (value) {
- for (id = lb->first; id; id = id->next) id->flag |= flag;
+ for (id = lb->first; id; id = id->next)
+ id->tag |= flag;
}
else {
- const short nflag = ~flag;
- for (id = lb->first; id; id = id->next) id->flag &= nflag;
+ const int nflag = ~flag;
+ for (id = lb->first; id; id = id->next)
+ id->tag &= nflag;
}
}
-/* Flag all ids in listbase */
-void BKE_main_id_flag_all(Main *bmain, const short flag, const bool value)
+/**
+ * Clear or set given flags for all ids in bmain (persistent flags).
+ */
+void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
{
ListBase *lbarray[MAX_LIBARRAY];
int a;
@@ -582,8 +696,9 @@ int set_listbasepointers(Main *main, ListBase **lb)
/* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
* This is important because freeing data decreases usercounts of other datablocks,
* if this data is its self freed it can crash. */
+ lb[a++] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */
lb[a++] = &(main->ipo);
- lb[a++] = &(main->action); // xxx moved here to avoid problems when freeing with animato (aligorith)
+ lb[a++] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
lb[a++] = &(main->key);
lb[a++] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
lb[a++] = &(main->nodetree);
@@ -612,7 +727,6 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->palettes);
lb[a++] = &(main->paintcurves);
lb[a++] = &(main->brush);
- lb[a++] = &(main->script);
lb[a++] = &(main->particle);
lb[a++] = &(main->speaker);
@@ -622,7 +736,6 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->object);
lb[a++] = &(main->linestyle); /* referenced by scenes */
lb[a++] = &(main->scene);
- lb[a++] = &(main->library);
lb[a++] = &(main->wm);
lb[a++] = &(main->mask);
@@ -647,7 +760,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
* Allocates and returns memory of the right size for the specified block type,
* initialized to zero.
*/
-static ID *alloc_libblock_notest(short type)
+void *BKE_libblock_alloc_notest(short type)
{
ID *id = NULL;
@@ -706,9 +819,6 @@ static ID *alloc_libblock_notest(short type)
case ID_TXT:
id = MEM_callocN(sizeof(Text), "text");
break;
- case ID_SCRIPT:
- //XXX id = MEM_callocN(sizeof(Script), "script");
- break;
case ID_SPK:
id = MEM_callocN(sizeof(Speaker), "speaker");
break;
@@ -769,7 +879,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
ID *id = NULL;
ListBase *lb = which_libbase(bmain, type);
- id = alloc_libblock_notest(type);
+ id = BKE_libblock_alloc_notest(type);
if (id) {
BKE_main_lock(bmain);
BLI_addtail(lb, id);
@@ -784,6 +894,118 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
return id;
}
+/**
+ * Initialize an ID of given type, such that it has valid 'empty' data.
+ * ID is assumed to be just calloc'ed.
+ */
+void BKE_libblock_init_empty(ID *id)
+{
+ /* Note that only ID types that are not valid when filled of zero should have a callback here. */
+ switch (GS(id->name)) {
+ case ID_SCE:
+ BKE_scene_init((Scene *)id);
+ break;
+ case ID_LI:
+ /* Nothing to do. */
+ break;
+ case ID_OB:
+ {
+ Object *ob = (Object *)id;
+ ob->type = OB_EMPTY;
+ BKE_object_init(ob);
+ break;
+ }
+ case ID_ME:
+ BKE_mesh_init((Mesh *)id);
+ break;
+ case ID_CU:
+ BKE_curve_init((Curve *)id);
+ break;
+ case ID_MB:
+ BKE_mball_init((MetaBall *)id);
+ break;
+ case ID_MA:
+ BKE_material_init((Material *)id);
+ break;
+ case ID_TE:
+ BKE_texture_default((Tex *)id);
+ break;
+ case ID_IM:
+ /* Image is a bit complicated, for now assume NULLified im is OK. */
+ break;
+ case ID_LT:
+ BKE_lattice_init((Lattice *)id);
+ break;
+ case ID_LA:
+ BKE_lamp_init((Lamp *)id);
+ break;
+ case ID_SPK:
+ BKE_speaker_init((Speaker *)id);
+ break;
+ case ID_CA:
+ BKE_camera_init((Camera *)id);
+ break;
+ case ID_IP:
+ /* Should not be needed - animation from lib pre-2.5 is broken anyway. */
+ BLI_assert(0);
+ break;
+ case ID_KE:
+ /* Shapekeys are a complex topic too - they depend on their 'user' data type...
+ * They are not linkable, though, so it should never reach here anyway. */
+ BLI_assert(0);
+ break;
+ case ID_WO:
+ BKE_world_init((World *)id);
+ break;
+ case ID_SCR:
+ /* Nothing to do. */
+ break;
+ case ID_VF:
+ BKE_vfont_init((VFont *)id);
+ break;
+ case ID_TXT:
+ BKE_text_init((Text *)id);
+ break;
+ case ID_SO:
+ /* Another fuzzy case, think NULLified content is OK here... */
+ break;
+ case ID_GR:
+ /* Nothing to do. */
+ break;
+ case ID_AR:
+ /* Nothing to do. */
+ break;
+ case ID_AC:
+ /* Nothing to do. */
+ break;
+ case ID_NT:
+ ntreeInitDefault((bNodeTree *)id);
+ break;
+ case ID_BR:
+ BKE_brush_init((Brush *)id);
+ break;
+ case ID_PA:
+ /* Nothing to do. */
+ break;
+ case ID_PC:
+ /* Nothing to do. */
+ break;
+ case ID_WM:
+ /* We should never reach this. */
+ BLI_assert(0);
+ break;
+ case ID_GD:
+ /* Nothing to do. */
+ break;
+ case ID_MSK:
+ /* Nothing to do. */
+ break;
+ case ID_LS:
+ BKE_linestyle_init((FreestyleLineStyle *)id);
+ break;
+ }
+}
+
/* by spec, animdata is first item after ID */
/* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
static void id_copy_animdata(ID *id, const bool do_action)
@@ -825,7 +1047,7 @@ void *BKE_libblock_copy_ex(Main *bmain, ID *id)
}
id->newid = idn;
- idn->flag |= LIB_NEW;
+ idn->tag |= LIB_TAG_NEW;
BKE_libblock_copy_data(idn, id, false);
@@ -837,7 +1059,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
ID *idn;
size_t idn_len;
- idn = alloc_libblock_notest(GS(id->name));
+ idn = BKE_libblock_alloc_notest(GS(id->name));
assert(idn != NULL);
BLI_strncpy(idn->name, id->name, sizeof(idn->name));
@@ -851,7 +1073,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
}
id->newid = idn;
- idn->flag |= LIB_NEW;
+ idn->tag |= LIB_TAG_NEW;
idn->us = 1;
BKE_libblock_copy_data(idn, id, do_action);
@@ -864,29 +1086,54 @@ void *BKE_libblock_copy(ID *id)
return BKE_libblock_copy_ex(G.main, id);
}
+static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag)
+{
+ ID *id = *id_pointer;
+ if (id) {
+ /* See: NEW_ID macro */
+ if (id->newid) {
+ BKE_library_update_ID_link_user(id->newid, id, cd_flag);
+ *id_pointer = id->newid;
+ }
+ else if (id->tag & LIB_TAG_NEW) {
+ id->tag &= ~LIB_TAG_NEW;
+ BKE_libblock_relink(id);
+ }
+ }
+ return IDWALK_RET_NOP;
+}
+
+void BKE_libblock_relink(ID *id)
+{
+ if (id->lib)
+ return;
+
+ BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
+}
+
static void BKE_library_free(Library *lib)
{
if (lib->packedfile)
freePackedFile(lib->packedfile);
}
-static void (*free_windowmanager_cb)(bContext *, wmWindowManager *) = NULL;
+static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL;
-void BKE_library_callback_free_window_manager_set(void (*func)(bContext *C, wmWindowManager *) )
+void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func)
{
free_windowmanager_cb = func;
}
-static void (*free_notifier_reference_cb)(const void *) = NULL;
+static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL;
-void BKE_library_callback_free_notifier_reference_set(void (*func)(const void *) )
+void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func)
{
free_notifier_reference_cb = func;
}
-static void (*free_editor_id_reference_cb)(const ID *) = NULL;
+static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL;
-void BKE_library_callback_free_editor_id_reference_set(void (*func)(const ID *))
+void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func)
{
free_editor_id_reference_cb = func;
}
@@ -993,9 +1240,6 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
case ID_TXT:
BKE_text_free((Text *)id);
break;
- case ID_SCRIPT:
- /* deprecated */
- break;
case ID_SPK:
BKE_speaker_free((Speaker *)id);
break;
@@ -1072,14 +1316,24 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
{
ID *id = idv;
- id->us--;
+ id_us_min(id);
- if (id->us < 0) {
- if (id->lib) printf("ERROR block %s %s users %d\n", id->lib->name, id->name, id->us);
- else printf("ERROR block %s users %d\n", id->name, id->us);
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
+ * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
+ * fully unlinked.
+ * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO.
+ */
+ if ((GS(id->name) == ID_OB) && (id->us == 1)) {
+ id_us_clear_real(id);
}
+
if (id->us == 0) {
- if (GS(id->name) == ID_OB) BKE_object_unlink((Object *)id);
+ switch (GS(id->name)) {
+ case ID_OB:
+ BKE_object_unlink(bmain, (Object *)id);
+ break;
+ }
BKE_libblock_free(bmain, id);
}
@@ -1474,20 +1728,18 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
* Pull an ID out of a library (make it local). Only call this for IDs that
* don't have other library users.
*/
-void id_clear_lib_data(Main *bmain, ID *id)
+void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
{
bNodeTree *ntree = NULL;
BKE_id_lib_local_paths(bmain, id->lib, id);
- if (id->flag & LIB_FAKEUSER) {
- id->us--;
- id->flag &= ~LIB_FAKEUSER;
- }
+ id_fake_user_clear(id);
id->lib = NULL;
- id->flag = LIB_LOCAL;
- new_id(which_libbase(bmain, GS(id->name)), id, NULL);
+ id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
+ if (id_in_mainlist)
+ new_id(which_libbase(bmain, GS(id->name)), id, NULL);
/* internal bNodeTree blocks inside ID types below
* also stores id->lib, make sure this stays in sync.
@@ -1495,7 +1747,7 @@ void id_clear_lib_data(Main *bmain, ID *id)
ntree = ntreeFromID(id);
if (ntree) {
- ntree->id.lib = NULL;
+ ntreeMakeLocal(ntree, false);
}
if (GS(id->name) == ID_OB) {
@@ -1508,6 +1760,11 @@ void id_clear_lib_data(Main *bmain, ID *id)
}
}
+void id_clear_lib_data(Main *bmain, ID *id)
+{
+ id_clear_lib_data_ex(bmain, id, true);
+}
+
/* next to indirect usage in read/writefile also in editobject.c scene.c */
void BKE_main_id_clear_newpoins(Main *bmain)
{
@@ -1520,7 +1777,7 @@ void BKE_main_id_clear_newpoins(Main *bmain)
id = lbarray[a]->first;
while (id) {
id->newid = NULL;
- id->flag &= ~LIB_NEW;
+ id->tag &= ~LIB_TAG_NEW;
id = id->next;
}
}
@@ -1528,7 +1785,8 @@ void BKE_main_id_clear_newpoins(Main *bmain)
static void lib_indirect_test_id(ID *id, Library *lib)
{
-#define LIBTAG(a) if (a && a->id.lib) { a->id.flag &= ~LIB_INDIRECT; a->id.flag |= LIB_EXTERN; } (void)0
+#define LIBTAG(a) \
+ if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
if (id->lib) {
/* datablocks that were indirectly related are now direct links
@@ -1572,42 +1830,9 @@ static void lib_indirect_test_id(ID *id, Library *lib)
#undef LIBTAG
}
-void BKE_main_id_tag_listbase(ListBase *lb, const bool tag)
-{
- ID *id;
- if (tag) {
- for (id = lb->first; id; id = id->next) {
- id->flag |= LIB_DOIT;
- }
- }
- else {
- for (id = lb->first; id; id = id->next) {
- id->flag &= ~LIB_DOIT;
- }
- }
-}
-
-void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const bool tag)
-{
- ListBase *lb = which_libbase(mainvar, type);
-
- BKE_main_id_tag_listbase(lb, tag);
-}
-
-void BKE_main_id_tag_all(struct Main *mainvar, const bool tag)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
-
- a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- BKE_main_id_tag_listbase(lbarray[a], tag);
- }
-}
-
/* if lib!=NULL, only all from lib local
* bmain is almost certainly G.main */
-void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
+void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only, bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
ID *id, *idn;
@@ -1621,30 +1846,38 @@ void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
id->newid = NULL;
idn = id->next; /* id is possibly being inserted again */
- /* The check on the second line (LIB_PRE_EXISTING) is done so its
+ /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
* appending data, so any libdata already linked wont become local
* (very nasty to discover all your links are lost after appending)
* */
- if (id->flag & (LIB_EXTERN | LIB_INDIRECT | LIB_NEW) &&
- ((untagged_only == false) || !(id->flag & LIB_PRE_EXISTING)))
+ if (id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) &&
+ ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING)))
{
if (lib == NULL || id->lib == lib) {
if (id->lib) {
/* for Make Local > All we should be calling id_make_local,
* but doing that breaks append (see #36003 and #36006), we
* we should make it work with all datablocks and id.us==0 */
- id_clear_lib_data(bmain, id); /* sets 'id->flag' */
+ id_clear_lib_data(bmain, id); /* sets 'id->tag' */
/* why sort alphabetically here but not in
* id_clear_lib_data() ? - campbell */
id_sort_by_name(lbarray[a], id);
}
else {
- id->flag &= ~(LIB_EXTERN | LIB_INDIRECT | LIB_NEW);
+ id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
+ }
+ }
+
+ if (set_fake) {
+ if (!ELEM(GS(id->name), ID_OB, ID_GR)) {
+ /* do not set fake user on objects, groups (instancing) */
+ id_fake_user_set(id);
}
}
}
+
id = idn;
}
}
@@ -1656,21 +1889,23 @@ void BKE_library_make_local(Main *bmain, Library *lib, bool untagged_only)
}
}
-
-void test_idbutton(char *name)
+/**
+ * Use after setting the ID's name
+ * When name exists: call 'new_id'
+ */
+void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
{
- /* called from buttons: when name already exists: call new_id */
ListBase *lb;
ID *idtest;
-
- lb = which_libbase(G.main, GS(name));
+
+ lb = which_libbase(bmain, GS(name));
if (lb == NULL) return;
/* search for id */
idtest = BLI_findstring(lb, name + 2, offsetof(ID, name) + 2);
- if (idtest && !new_id(lb, idtest, name + 2)) {
+ if (idtest && !new_id(lb, idtest, idtest->name + 2)) {
id_sort_by_name(lb, idtest);
}
}
@@ -1678,13 +1913,9 @@ void test_idbutton(char *name)
/**
* Sets the name of a block to name, suitably adjusted for uniqueness.
*/
-void rename_id(ID *id, const char *name)
+void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
- ListBase *lb;
-
- BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
- lb = which_libbase(G.main, GS(id->name));
-
+ ListBase *lb = which_libbase(bmain, GS(id->name));
new_id(lb, id, name);
}
@@ -1692,9 +1923,9 @@ void rename_id(ID *id, const char *name)
* Returns in name the name of the block, with a 3-character prefix prepended
* indicating whether it comes from a library, has a fake user, or no users.
*/
-void name_uiprefix_id(char *name, const ID *id)
+void BKE_id_ui_prefix(char name[MAX_ID_NAME + 1], const ID *id)
{
- name[0] = id->lib ? 'L' : ' ';
+ name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' ';
name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
name[2] = ' ';
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index 6d2e2f1ecd4..d29d2191602 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -30,10 +30,12 @@
#include <stdlib.h>
+#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_controller_types.h"
#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
@@ -47,7 +49,9 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force.h"
+#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
+#include "DNA_sensor_types.h"
#include "DNA_sequence_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -57,59 +61,141 @@
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist_stack.h"
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sca.h"
#include "BKE_sequencer.h"
#include "BKE_tracking.h"
-#define FOREACH_CALLBACK_INVOKE_ID_PP(self_id, id_pp, flag, callback, user_data, cb_flag) \
- { \
- ID *old_id = *id_pp; \
- bool keep_working = callback(user_data, id_pp, cb_flag); \
- if (flag & IDWALK_READONLY) { \
- BLI_assert(*id_pp == old_id); \
- (void)old_id; /* quiet warning */ \
+
+#define FOREACH_FINALIZE _finalize
+#define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0
+
+#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \
+ if (!((_data)->status & IDWALK_STOP)) { \
+ const int _flag = (_data)->flag; \
+ ID *old_id = *(id_pp); \
+ const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \
+ if (_flag & IDWALK_READONLY) { \
+ BLI_assert(*(id_pp) == old_id); \
} \
- if (keep_working == false) { \
- /* REAL DANGER! Beware of this return! */ \
- /* TODO(sergey): Make it less creepy without too much duplicated code.. */ \
- return; \
+ if (old_id && (_flag & IDWALK_RECURSE)) { \
+ if (!BLI_gset_haskey((_data)->ids_handled, old_id)) { \
+ BLI_gset_add((_data)->ids_handled, old_id); \
+ if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { \
+ BLI_LINKSTACK_PUSH((_data)->ids_todo, old_id); \
+ } \
+ } \
} \
- } (void) 0
+ if (callback_return & IDWALK_RET_STOP_ITER) { \
+ (_data)->status |= IDWALK_STOP; \
+ goto FOREACH_FINALIZE; \
+ } \
+ } \
+ else { \
+ goto FOREACH_FINALIZE; \
+ } ((void)0)
-#define FOREACH_CALLBACK_INVOKE_ID(self_id, id, flag, callback, user_data, cb_flag) \
- FOREACH_CALLBACK_INVOKE_ID_PP(self_id, &(id), flag, callback, user_data, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE_ID(_data, id, cb_flag) \
+ { \
+ CHECK_TYPE_ANY(id, ID *, void *); \
+ FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id), cb_flag); \
+ } ((void)0)
-#define FOREACH_CALLBACK_INVOKE(self_id, id_super, flag, callback, user_data, cb_flag) \
+#define FOREACH_CALLBACK_INVOKE(_data, id_super, cb_flag) \
{ \
CHECK_TYPE(&((id_super)->id), ID *); \
- FOREACH_CALLBACK_INVOKE_ID_PP(self_id, (ID **)&id_super, flag, callback, user_data, cb_flag); \
- } (void) 0
+ FOREACH_CALLBACK_INVOKE_ID_PP(_data, (ID **)&(id_super), cb_flag); \
+ } ((void)0)
+
+/* status */
+enum {
+ IDWALK_STOP = 1 << 0,
+};
typedef struct LibraryForeachIDData {
ID *self_id;
int flag;
LibraryIDLinkCallback callback;
void *user_data;
+ int status;
+
+ /* To handle recursion. */
+ GSet *ids_handled; /* All IDs that are either already done, or still in ids_todo stack. */
+ BLI_LINKSTACK_DECLARE(ids_todo, ID *);
} LibraryForeachIDData;
-static void library_foreach_modifiersForeachIDLink(void *user_data, Object *UNUSED(object),
- ID **id_pointer)
+static void library_foreach_rigidbodyworldSceneLooper(
+ struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_modifiersForeachIDLink(
+ void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
- bool UNUSED(is_reference), void *user_data)
+ bool is_reference, void *user_data)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_particlesystemsObjectLooper(
+ ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_sensorsObjectLooper(
+ bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_controllersObjectLooper(
+ bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag)
+{
+ LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
+}
+
+static void library_foreach_actuatorsObjectLooper(
+ bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag);
+
+ FOREACH_FINALIZE_VOID;
}
static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt)
@@ -124,18 +210,21 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *
/* only used targets */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- FOREACH_CALLBACK_INVOKE_ID(data->self_id, dtar->id, data->flag, data->callback, data->user_data, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP);
}
DRIVER_TARGETS_LOOPER_END
}
}
-}
+ FOREACH_FINALIZE_VOID;
+}
static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
{
- FOREACH_CALLBACK_INVOKE(data->self_id, mtex->object, data->flag, data->callback, data->user_data, IDWALK_NOP);
- FOREACH_CALLBACK_INVOKE(data->self_id, mtex->tex, data->flag, data->callback, data->user_data, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER);
+
+ FOREACH_FINALIZE_VOID;
}
@@ -146,378 +235,479 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
*/
void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
{
- AnimData *adt;
LibraryForeachIDData data;
int i;
- data.self_id = id;
+ if (flag & IDWALK_RECURSE) {
+ /* For now, recusion implies read-only. */
+ flag |= IDWALK_READONLY;
+
+ data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ BLI_LINKSTACK_INIT(data.ids_todo);
+ }
+ else {
+ data.ids_handled = NULL;
+ }
data.flag = flag;
+ data.status = 0;
data.callback = callback;
data.user_data = user_data;
- adt = BKE_animdata_from_id(id);
- if (adt) {
- library_foreach_animationData(&data, adt);
- }
-
#define CALLBACK_INVOKE_ID(check_id, cb_flag) \
- FOREACH_CALLBACK_INVOKE_ID(id, check_id, flag, callback, user_data, cb_flag)
+ FOREACH_CALLBACK_INVOKE_ID(&data, check_id, cb_flag)
#define CALLBACK_INVOKE(check_id_super, cb_flag) \
- FOREACH_CALLBACK_INVOKE(id, check_id_super, flag, callback, user_data, cb_flag)
-
- switch (GS(id->name)) {
- case ID_SCE:
- {
- Scene *scene = (Scene *) id;
- SceneRenderLayer *srl;
- Base *base;
-
- CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
- CALLBACK_INVOKE(scene->world, IDWALK_NOP);
- CALLBACK_INVOKE(scene->set, IDWALK_NOP);
- if (scene->basact) {
- CALLBACK_INVOKE(scene->basact->object, IDWALK_NOP);
- }
- CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
+ FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag)
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
+ do {
+ data.self_id = id;
- if (srl->mat_override) {
- CALLBACK_INVOKE(srl->mat_override, IDWALK_NOP);
- }
- if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_NOP);
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt) {
+ library_foreach_animationData(&data, adt);
+ }
+
+ switch (GS(id->name)) {
+ case ID_SCE:
+ {
+ Scene *scene = (Scene *) id;
+ ToolSettings *toolsett = scene->toolsettings;
+ SceneRenderLayer *srl;
+ Base *base;
+
+ CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->world, IDWALK_USER);
+ CALLBACK_INVOKE(scene->set, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->clip, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP);
+ /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
+ * since basact is just a pointer to one of those items. */
+ CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
+
+ for (srl = scene->r.layers.first; srl; srl = srl->next) {
+ FreestyleModuleConfig *fmc;
+ FreestyleLineSet *fls;
+
+ if (srl->mat_override) {
+ CALLBACK_INVOKE(srl->mat_override, IDWALK_USER);
+ }
+ if (srl->light_override) {
+ CALLBACK_INVOKE(srl->light_override, IDWALK_USER);
+ }
+ for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ if (fmc->script) {
+ CALLBACK_INVOKE(fmc->script, IDWALK_NOP);
+ }
+ }
+ for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ if (fls->group) {
+ CALLBACK_INVOKE(fls->group, IDWALK_USER);
+ }
+ if (fls->linestyle) {
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_USER);
+ }
+ }
}
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_NOP);
+
+ if (scene->ed) {
+ Sequence *seq;
+ SEQP_BEGIN(scene->ed, seq)
+ {
+ CALLBACK_INVOKE(seq->scene, IDWALK_NOP);
+ CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP);
+ CALLBACK_INVOKE(seq->clip, IDWALK_USER);
+ CALLBACK_INVOKE(seq->mask, IDWALK_USER);
+ CALLBACK_INVOKE(seq->sound, IDWALK_USER);
}
+ SEQ_END
+ }
+
+ CALLBACK_INVOKE(scene->gpd, IDWALK_USER);
+
+ for (base = scene->base.first; base; base = base->next) {
+ CALLBACK_INVOKE(base->object, IDWALK_USER);
}
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_NOP);
+
+ if (toolsett) {
+ CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_NOP);
+ if (toolsett->vpaint) {
+ CALLBACK_INVOKE(toolsett->vpaint->paint.brush, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->vpaint->paint.palette, IDWALK_NOP);
+ }
+ if (toolsett->wpaint) {
+ CALLBACK_INVOKE(toolsett->wpaint->paint.brush, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->wpaint->paint.palette, IDWALK_NOP);
+ }
+ if (toolsett->sculpt) {
+ CALLBACK_INVOKE(toolsett->sculpt->paint.brush, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->sculpt->paint.palette, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP);
}
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_NOP);
+ if (toolsett->uvsculpt) {
+ CALLBACK_INVOKE(toolsett->uvsculpt->paint.brush, IDWALK_NOP);
+ CALLBACK_INVOKE(toolsett->uvsculpt->paint.palette, IDWALK_NOP);
}
}
- }
- if (scene->ed) {
- Sequence *seq;
- SEQP_BEGIN(scene->ed, seq)
- {
- CALLBACK_INVOKE(seq->scene, IDWALK_NOP);
- CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP);
- CALLBACK_INVOKE(seq->clip, IDWALK_NOP);
- CALLBACK_INVOKE(seq->mask, IDWALK_NOP);
+ if (scene->rigidbody_world) {
+ BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- SEQ_END
- }
- CALLBACK_INVOKE(scene->gpd, IDWALK_NOP);
+ CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_NOP);
- for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_NOP);
+ break;
}
- break;
- }
- case ID_OB:
- {
- Object *object = (Object *) id;
- CALLBACK_INVOKE(object->parent, IDWALK_NOP);
- CALLBACK_INVOKE(object->track, IDWALK_NOP);
- CALLBACK_INVOKE(object->proxy, IDWALK_NOP);
- CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
- CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
- CALLBACK_INVOKE(object->poselib, IDWALK_NOP);
- for (i = 0; i < object->totcol; i++) {
- CALLBACK_INVOKE(object->mat[i], IDWALK_NOP);
- }
- CALLBACK_INVOKE(object->gpd, IDWALK_NOP);
- CALLBACK_INVOKE(object->dup_group, IDWALK_NOP);
- if (object->particlesystem.first) {
- ParticleSystem *particle_system;
- for (particle_system = object->particlesystem.first;
- particle_system;
- particle_system = particle_system->next)
- {
- CALLBACK_INVOKE(particle_system->target_ob, IDWALK_NOP);
- CALLBACK_INVOKE(particle_system->parent, IDWALK_NOP);
+ case ID_OB:
+ {
+ Object *object = (Object *) id;
+ ParticleSystem *psys;
+
+ /* object data special case */
+ if (object->type == OB_EMPTY) {
+ /* empty can have NULL or Image */
+ CALLBACK_INVOKE_ID(object->data, IDWALK_USER);
+ }
+ else {
+ /* when set, this can't be NULL */
+ if (object->data) {
+ CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL);
+ }
}
- }
- if (object->pose) {
- bPoseChannel *pose_channel;
- for (pose_channel = object->pose->chanbase.first;
- pose_channel;
- pose_channel = pose_channel->next)
- {
- CALLBACK_INVOKE(pose_channel->custom, IDWALK_NOP);
- BKE_constraints_id_loop(&pose_channel->constraints,
- library_foreach_constraintObjectLooper,
- &data);
+ CALLBACK_INVOKE(object->parent, IDWALK_NOP);
+ CALLBACK_INVOKE(object->track, IDWALK_NOP);
+ /* object->proxy is refcounted, but not object->proxy_group... *sigh* */
+ CALLBACK_INVOKE(object->proxy, IDWALK_USER);
+ CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+ CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
+ CALLBACK_INVOKE(object->poselib, IDWALK_USER);
+ for (i = 0; i < object->totcol; i++) {
+ CALLBACK_INVOKE(object->mat[i], IDWALK_USER);
}
- }
+ CALLBACK_INVOKE(object->gpd, IDWALK_USER);
+ CALLBACK_INVOKE(object->dup_group, IDWALK_USER);
- modifiers_foreachIDLink(object,
- library_foreach_modifiersForeachIDLink,
- &data);
- BKE_constraints_id_loop(&object->constraints,
- library_foreach_constraintObjectLooper,
- &data);
- break;
- }
+ if (object->pd) {
+ CALLBACK_INVOKE(object->pd->tex, IDWALK_USER);
+ CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP);
+ }
- case ID_ME:
- {
- Mesh *mesh = (Mesh *) id;
- CALLBACK_INVOKE(mesh->texcomesh, IDWALK_NOP);
- CALLBACK_INVOKE(mesh->key, IDWALK_NOP);
- for (i = 0; i < mesh->totcol; i++) {
- CALLBACK_INVOKE(mesh->mat[i], IDWALK_NOP);
+ if (object->pose) {
+ bPoseChannel *pchan;
+ for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) {
+ CALLBACK_INVOKE(pchan->custom, IDWALK_USER);
+ BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data);
+ }
+ }
+
+ if (object->rigidbody_constraint) {
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_NOP);
+ CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_NOP);
+ }
+
+ if (object->lodlevels.first) {
+ LodLevel *level;
+ for (level = object->lodlevels.first; level; level = level->next) {
+ CALLBACK_INVOKE(level->source, IDWALK_NOP);
+ }
+ }
+
+ modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
+ BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data);
+
+ for (psys = object->particlesystem.first; psys; psys = psys->next) {
+ BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data);
+ }
+
+ BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
+ BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
+ BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
+ break;
}
- break;
- }
- case ID_CU:
- {
- Curve *curve = (Curve *) id;
- CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP);
- CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP);
- CALLBACK_INVOKE(curve->key, IDWALK_NOP);
- for (i = 0; i < curve->totcol; i++) {
- CALLBACK_INVOKE(curve->mat[i], IDWALK_NOP);
+ case ID_ME:
+ {
+ Mesh *mesh = (Mesh *) id;
+ CALLBACK_INVOKE(mesh->texcomesh, IDWALK_USER);
+ CALLBACK_INVOKE(mesh->key, IDWALK_USER);
+ for (i = 0; i < mesh->totcol; i++) {
+ CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER);
+ }
+ break;
}
- CALLBACK_INVOKE(curve->vfont, IDWALK_NOP);
- CALLBACK_INVOKE(curve->vfontb, IDWALK_NOP);
- CALLBACK_INVOKE(curve->vfonti, IDWALK_NOP);
- CALLBACK_INVOKE(curve->vfontbi, IDWALK_NOP);
- break;
- }
- case ID_MB:
- {
- MetaBall *metaball = (MetaBall *) id;
- for (i = 0; i < metaball->totcol; i++) {
- CALLBACK_INVOKE(metaball->mat[i], IDWALK_NOP);
+ case ID_CU:
+ {
+ Curve *curve = (Curve *) id;
+ CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP);
+ CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP);
+ CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP);
+ CALLBACK_INVOKE(curve->key, IDWALK_USER);
+ for (i = 0; i < curve->totcol; i++) {
+ CALLBACK_INVOKE(curve->mat[i], IDWALK_USER);
+ }
+ CALLBACK_INVOKE(curve->vfont, IDWALK_USER);
+ CALLBACK_INVOKE(curve->vfontb, IDWALK_USER);
+ CALLBACK_INVOKE(curve->vfonti, IDWALK_USER);
+ CALLBACK_INVOKE(curve->vfontbi, IDWALK_USER);
+ break;
}
- break;
- }
- case ID_MA:
- {
- Material *material = (Material *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (material->mtex[i]) {
- library_foreach_mtex(&data, material->mtex[i]);
+ case ID_MB:
+ {
+ MetaBall *metaball = (MetaBall *) id;
+ for (i = 0; i < metaball->totcol; i++) {
+ CALLBACK_INVOKE(metaball->mat[i], IDWALK_USER);
}
+ break;
}
- CALLBACK_INVOKE(material->nodetree, IDWALK_NOP);
- CALLBACK_INVOKE(material->group, IDWALK_NOP);
- break;
- }
- case ID_TE:
- {
- Tex *texture = (Tex *) id;
- CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP);
- CALLBACK_INVOKE(texture->ima, IDWALK_NOP);
- break;
- }
+ case ID_MA:
+ {
+ Material *material = (Material *) id;
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (material->mtex[i]) {
+ library_foreach_mtex(&data, material->mtex[i]);
+ }
+ }
+ CALLBACK_INVOKE(material->nodetree, IDWALK_NOP);
+ CALLBACK_INVOKE(material->group, IDWALK_USER);
+ break;
+ }
- case ID_LT:
- {
- Lattice *lattice = (Lattice *) id;
- CALLBACK_INVOKE(lattice->key, IDWALK_NOP);
- break;
- }
+ case ID_TE:
+ {
+ Tex *texture = (Tex *) id;
+ CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->ima, IDWALK_USER);
+ if (texture->env) {
+ CALLBACK_INVOKE(texture->env->object, IDWALK_NOP);
+ CALLBACK_INVOKE(texture->env->ima, IDWALK_USER);
+ }
+ if (texture->pd)
+ CALLBACK_INVOKE(texture->pd->object, IDWALK_NOP);
+ if (texture->vd)
+ CALLBACK_INVOKE(texture->vd->object, IDWALK_NOP);
+ if (texture->ot)
+ CALLBACK_INVOKE(texture->ot->object, IDWALK_NOP);
+ break;
+ }
+
+ case ID_LT:
+ {
+ Lattice *lattice = (Lattice *) id;
+ CALLBACK_INVOKE(lattice->key, IDWALK_USER);
+ break;
+ }
- case ID_LA:
- {
- Lamp *lamp = (Lamp *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (lamp->mtex[i]) {
- library_foreach_mtex(&data, lamp->mtex[i]);
+ case ID_LA:
+ {
+ Lamp *lamp = (Lamp *) id;
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (lamp->mtex[i]) {
+ library_foreach_mtex(&data, lamp->mtex[i]);
+ }
}
+ CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP);
+ break;
}
- CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP);
- break;
- }
- case ID_CA:
- {
- Camera *camera = (Camera *) id;
- CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP);
- break;
- }
+ case ID_CA:
+ {
+ Camera *camera = (Camera *) id;
+ CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP);
+ break;
+ }
- case ID_KE:
- {
- Key *key = (Key *) id;
- CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
- break;
- }
+ case ID_KE:
+ {
+ Key *key = (Key *) id;
+ CALLBACK_INVOKE_ID(key->from, IDWALK_NOP);
+ break;
+ }
- case ID_SCR:
- {
- bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_NOP);
- break;
- }
+ case ID_SCR:
+ {
+ bScreen *screen = (bScreen *) id;
+ CALLBACK_INVOKE(screen->scene, IDWALK_USER_ONE);
+ break;
+ }
- case ID_WO:
- {
- World *world = (World *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (world->mtex[i]) {
- library_foreach_mtex(&data, world->mtex[i]);
+ case ID_WO:
+ {
+ World *world = (World *) id;
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (world->mtex[i]) {
+ library_foreach_mtex(&data, world->mtex[i]);
+ }
}
+ CALLBACK_INVOKE(world->nodetree, IDWALK_NOP);
+ break;
}
- CALLBACK_INVOKE(world->nodetree, IDWALK_NOP);
- break;
- }
- case ID_SPK:
- {
- Speaker *speaker = (Speaker *) id;
- CALLBACK_INVOKE(speaker->sound, IDWALK_NOP);
- break;
- }
-
- case ID_GR:
- {
- Group *group = (Group *) id;
- GroupObject *group_object;
- for (group_object = group->gobject.first;
- group_object;
- group_object = group_object->next)
+ case ID_SPK:
{
- CALLBACK_INVOKE(group_object->ob, IDWALK_NOP);
+ Speaker *speaker = (Speaker *) id;
+ CALLBACK_INVOKE(speaker->sound, IDWALK_USER);
+ break;
}
- break;
- }
- case ID_NT:
- {
- bNodeTree *ntree = (bNodeTree *) id;
- bNode *node;
- for (node = ntree->nodes.first; node; node = node->next) {
- CALLBACK_INVOKE_ID(node->id, IDWALK_NOP);
+ case ID_GR:
+ {
+ Group *group = (Group *) id;
+ GroupObject *gob;
+ for (gob = group->gobject.first; gob; gob = gob->next) {
+ CALLBACK_INVOKE(gob->ob, IDWALK_USER_ONE);
+ }
+ break;
}
- break;
- }
- case ID_BR:
- {
- Brush *brush = (Brush *) id;
- CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP);
- library_foreach_mtex(&data, &brush->mtex);
- library_foreach_mtex(&data, &brush->mask_mtex);
- break;
- }
+ case ID_NT:
+ {
+ bNodeTree *ntree = (bNodeTree *) id;
+ bNode *node;
+ CALLBACK_INVOKE(ntree->gpd, IDWALK_USER);
+ for (node = ntree->nodes.first; node; node = node->next) {
+ CALLBACK_INVOKE_ID(node->id, IDWALK_USER);
+ }
+ break;
+ }
- case ID_PA:
- {
- ParticleSettings *particle_settings = (ParticleSettings *) id;
- CALLBACK_INVOKE(particle_settings->dup_group, IDWALK_NOP);
- CALLBACK_INVOKE(particle_settings->dup_ob, IDWALK_NOP);
- CALLBACK_INVOKE(particle_settings->bb_ob, IDWALK_NOP);
- if (particle_settings->effector_weights) {
- CALLBACK_INVOKE(particle_settings->effector_weights->group, IDWALK_NOP);
+ case ID_BR:
+ {
+ Brush *brush = (Brush *) id;
+ CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP);
+ CALLBACK_INVOKE(brush->clone.image, IDWALK_NOP);
+ CALLBACK_INVOKE(brush->paint_curve, IDWALK_USER);
+ library_foreach_mtex(&data, &brush->mtex);
+ library_foreach_mtex(&data, &brush->mask_mtex);
+ break;
}
- break;
- }
- case ID_MC:
- {
- MovieClip *clip = (MovieClip *) id;
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object;
- CALLBACK_INVOKE(clip->gpd, IDWALK_NOP);
- for (object = tracking->objects.first;
- object;
- object = object->next)
+ case ID_PA:
{
- ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
- MovieTrackingTrack *track;
- for (track = tracksbase->first;
- track;
- track = track->next)
- {
- CALLBACK_INVOKE(track->gpd, IDWALK_NOP);
+ ParticleSettings *psett = (ParticleSettings *) id;
+ CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP);
+ CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP);
+
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (psett->mtex[i]) {
+ library_foreach_mtex(&data, psett->mtex[i]);
+ }
}
+
+ if (psett->effector_weights) {
+ CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP);
+ }
+
+ if (psett->boids) {
+ BoidState *state;
+ BoidRule *rule;
+
+ for (state = psett->boids->states.first; state; state = state->next) {
+ for (rule = state->rules.first; rule; rule = rule->next) {
+ if (rule->type == eBoidRuleType_Avoid) {
+ BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule;
+ CALLBACK_INVOKE(gabr->ob, IDWALK_NOP);
+ }
+ else if (rule->type == eBoidRuleType_FollowLeader) {
+ BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule;
+ CALLBACK_INVOKE(flbr->ob, IDWALK_NOP);
+ }
+ }
+ }
+ }
+
+ break;
}
- break;
- }
- case ID_MSK:
- {
- Mask *mask = (Mask *) id;
- MaskLayer *mask_layer;
- for (mask_layer = mask->masklayers.first;
- mask_layer;
- mask_layer = mask_layer->next)
+ case ID_MC:
{
- MaskSpline *mask_spline;
-
- for (mask_spline = mask_layer->splines.first;
- mask_spline;
- mask_spline = mask_spline->next)
- {
- int i;
- for (i = 0; i < mask_spline->tot_point; i++) {
- MaskSplinePoint *point = &mask_spline->points[i];
- CALLBACK_INVOKE_ID(point->parent.id, IDWALK_NOP);
+ MovieClip *clip = (MovieClip *) id;
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object;
+
+ CALLBACK_INVOKE(clip->gpd, IDWALK_USER);
+ for (object = tracking->objects.first; object; object = object->next) {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
+ MovieTrackingTrack *track;
+
+ for (track = tracksbase->first; track; track = track->next) {
+ CALLBACK_INVOKE(track->gpd, IDWALK_USER);
}
}
+ break;
}
- break;
- }
- case ID_LS:
- {
- FreestyleLineStyle *linestyle = (FreestyleLineStyle *) id;
- LineStyleModifier *m;
- for (i = 0; i < MAX_MTEX; i++) {
- if (linestyle->mtex[i]) {
- library_foreach_mtex(&data, linestyle->mtex[i]);
+ case ID_MSK:
+ {
+ Mask *mask = (Mask *) id;
+ MaskLayer *mask_layer;
+ for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ MaskSpline *mask_spline;
+
+ for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) {
+ for (i = 0; i < mask_spline->tot_point; i++) {
+ MaskSplinePoint *point = &mask_spline->points[i];
+ CALLBACK_INVOKE_ID(point->parent.id, IDWALK_USER);
+ }
+ }
}
+ break;
}
- CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP);
- for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ case ID_LS:
+ {
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *) id;
+ LineStyleModifier *lsm;
+ for (i = 0; i < MAX_MTEX; i++) {
+ if (linestyle->mtex[i]) {
+ library_foreach_mtex(&data, linestyle->mtex[i]);
}
}
- }
- for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP);
+
+ for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ }
}
}
- }
- for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) {
- if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
- LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
- if (p->target) {
- CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ for (lsm = linestyle->alpha_modifiers.first; lsm; lsm = lsm->next) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ }
+ }
+ }
+ for (lsm = linestyle->thickness_modifiers.first; lsm; lsm = lsm->next) {
+ if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ }
}
}
+ break;
}
- break;
}
+ } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL));
+FOREACH_FINALIZE:
+ if (data.ids_handled) {
+ BLI_gset_free(data.ids_handled, NULL);
+ BLI_LINKSTACK_FREE(data.ids_todo);
}
#undef CALLBACK_INVOKE_ID
@@ -526,3 +716,63 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
#undef FOREACH_CALLBACK_INVOKE_ID
#undef FOREACH_CALLBACK_INVOKE
+
+/**
+ * re-usable function, use when replacing ID's
+ */
+void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
+{
+ if (cd_flag & IDWALK_USER) {
+ id_us_min(id_src);
+ id_us_plus(id_dst);
+ }
+ else if (cd_flag & IDWALK_USER_ONE) {
+ id_us_ensure_real(id_dst);
+ }
+}
+
+/* ***** ID users iterator. ***** */
+typedef struct IDUsersIter {
+ ID *id;
+
+ ListBase *lb_array[MAX_LIBARRAY];
+ int lb_idx;
+
+ ID *curr_id;
+ int count; /* Set by callback. */
+} IDUsersIter;
+
+static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+{
+ IDUsersIter *iter = user_data;
+
+ if (*id_p && (*id_p == iter->id)) {
+ iter->count++;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/**
+ * Return the number of times given \a id_user uses/references \a id_used.
+ *
+ * \note This only checks for pointer references of an ID, shallow usages (like e.g. by RNA paths, as done
+ * for FCurves) are not detected at all.
+ *
+ * \param id_user the ID which is supposed to use (reference) \a id_used.
+ * \param id_used the ID which is supposed to be used (referenced) by \a id_user.
+ * \return the number of direct usages/references of \a id_used by \a id_user.
+ */
+int BKE_library_ID_use_ID(ID *id_user, ID *id_used)
+{
+ IDUsersIter iter;
+
+ /* We do not care about iter.lb_array/lb_idx here... */
+ iter.id = id_used;
+ iter.curr_id = id_user;
+ iter.count = 0;
+
+ BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP);
+
+ return iter.count;
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index ac2c4e35dce..5a1dfc04045 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -80,8 +80,10 @@ static const char *modifier_name[LS_MODIFIER_NUM] = {
"3D Curvature",
};
-static void default_linestyle_settings(FreestyleLineStyle *linestyle)
+void BKE_linestyle_init(FreestyleLineStyle *linestyle)
{
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(linestyle, id));
+
linestyle->panel = LS_PANEL_STROKES;
linestyle->r = linestyle->g = linestyle->b = 0.0f;
linestyle->alpha = 1.0f;
@@ -118,7 +120,7 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name)
linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(bmain, ID_LS, name);
- default_linestyle_settings(linestyle);
+ BKE_linestyle_init(linestyle);
return linestyle;
}
@@ -132,8 +134,10 @@ void BKE_linestyle_free(FreestyleLineStyle *linestyle)
for (a = 0; a < MAX_MTEX; a++) {
mtex = linestyle->mtex[a];
- if (mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
if (linestyle->nodetree) {
ntreeFreeTree(linestyle->nodetree);
@@ -382,7 +386,7 @@ LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linesty
LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m;
LineStyleColorModifier_DistanceFromObject *q = (LineStyleColorModifier_DistanceFromObject *)new_m;
if (p->target)
- p->target->id.us++;
+ id_us_plus(&p->target->id);
q->target = p->target;
q->color_ramp = MEM_dupallocN(p->color_ramp);
q->range_min = p->range_min;
@@ -620,7 +624,7 @@ LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linesty
LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m;
LineStyleAlphaModifier_DistanceFromObject *q = (LineStyleAlphaModifier_DistanceFromObject *)new_m;
if (p->target)
- p->target->id.us++;
+ id_us_plus(&p->target->id);
q->target = p->target;
q->curve = curvemapping_copy(p->curve);
q->flags = p->flags;
@@ -895,7 +899,7 @@ LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *lin
LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
LineStyleThicknessModifier_DistanceFromObject *q = (LineStyleThicknessModifier_DistanceFromObject *)new_m;
if (p->target)
- p->target->id.us++;
+ id_us_plus(&p->target->id);
q->target = p->target;
q->curve = curvemapping_copy(p->curve);
q->flags = p->flags;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 141597e859c..12db3a87ba0 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -804,7 +804,7 @@ static Mask *mask_alloc(Main *bmain, const char *name)
mask = BKE_libblock_alloc(bmain, ID_MSK, name);
- mask->id.flag |= LIB_FAKEUSER;
+ id_fake_user_set(&mask->id);
return mask;
}
@@ -843,10 +843,7 @@ Mask *BKE_mask_copy_nolib(Mask *mask)
BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers);
/* enable fake user by default */
- if (!(mask_new->id.flag & LIB_FAKEUSER)) {
- mask_new->id.flag |= LIB_FAKEUSER;
- mask_new->id.us++;
- }
+ id_fake_user_set(&mask->id);
return mask_new;
}
@@ -862,10 +859,7 @@ Mask *BKE_mask_copy(Mask *mask)
BKE_mask_layer_copy_list(&mask_new->masklayers, &mask->masklayers);
/* enable fake user by default */
- if (!(mask_new->id.flag & LIB_FAKEUSER)) {
- mask_new->id.flag |= LIB_FAKEUSER;
- mask_new->id.us++;
- }
+ id_fake_user_set(&mask->id);
if (mask->id.lib) {
BKE_id_lib_local_paths(G.main, mask->id.lib, &mask_new->id);
@@ -1595,8 +1589,8 @@ void BKE_mask_update_scene(Main *bmain, Scene *scene)
Mask *mask;
for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- if (mask->id.flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA)) {
- bool do_new_frame = (mask->id.flag & LIB_ID_RECALC_DATA) != 0;
+ if (mask->id.tag & (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA)) {
+ bool do_new_frame = (mask->id.tag & LIB_TAG_ID_RECALC_DATA) != 0;
BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame);
}
}
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index 5517fc36bc1..1b275f455f4 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -253,7 +253,7 @@ static void feather_bucket_check_intersect(
if (check_a >= cur_a - 1 || cur_b == check_a)
continue;
- if (isect_seg_seg_v2(v1, v2, v3, v4)) {
+ if (isect_seg_seg_v2_simple(v1, v2, v3, v4)) {
int k;
float p[2];
float min_a[2], max_a[2];
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 3e7e98b4a1d..809b45d4b36 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -78,7 +78,7 @@ Material defmaterial;
/* called on startup, creator.c */
void init_def_material(void)
{
- init_material(&defmaterial);
+ BKE_material_init(&defmaterial);
}
/* not material itself */
@@ -95,8 +95,10 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
for (a = 0; a < MAX_MTEX; a++) {
mtex = ma->mtex[a];
- if (do_id_user && mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (do_id_user && mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
if (ma->ramp_col) MEM_freeN(ma->ramp_col);
@@ -122,8 +124,10 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
GPU_material_free(&ma->gpumaterial);
}
-void init_material(Material *ma)
+void BKE_material_init(Material *ma)
{
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
+
ma->r = ma->g = ma->b = ma->ref = 0.8;
ma->specr = ma->specg = ma->specb = 1.0;
ma->mirr = ma->mirg = ma->mirb = 1.0;
@@ -221,7 +225,7 @@ Material *BKE_material_add(Main *bmain, const char *name)
ma = BKE_libblock_alloc(bmain, ID_MA, name);
- init_material(ma);
+ BKE_material_init(ma);
return ma;
}
@@ -401,8 +405,8 @@ void BKE_material_make_local(Material *ma)
if (ob->mat[a] == ma) {
if (ob->id.lib == NULL) {
ob->mat[a] = ma_new;
- ma_new->id.us++;
- ma->id.us--;
+ id_us_plus(&ma_new->id);
+ id_us_min(&ma->id);
}
}
}
@@ -417,8 +421,8 @@ void BKE_material_make_local(Material *ma)
if (me->mat[a] == ma) {
if (me->id.lib == NULL) {
me->mat[a] = ma_new;
- ma_new->id.us++;
- ma->id.us--;
+ id_us_plus(&ma_new->id);
+ id_us_min(&ma->id);
}
}
}
@@ -433,8 +437,8 @@ void BKE_material_make_local(Material *ma)
if (cu->mat[a] == ma) {
if (cu->id.lib == NULL) {
cu->mat[a] = ma_new;
- ma_new->id.us++;
- ma->id.us--;
+ id_us_plus(&ma_new->id);
+ id_us_min(&ma->id);
}
}
}
@@ -449,8 +453,8 @@ void BKE_material_make_local(Material *ma)
if (mb->mat[a] == ma) {
if (mb->id.lib == NULL) {
mb->mat[a] = ma_new;
- ma_new->id.us++;
- ma->id.us--;
+ id_us_plus(&ma_new->id);
+ id_us_min(&ma->id);
}
}
}
@@ -665,6 +669,10 @@ void BKE_material_clear_id(struct ID *id, bool update_data)
Material ***matar;
if ((matar = give_matarar_id(id))) {
short *totcol = give_totcolp_id(id);
+
+ while ((*totcol)--) {
+ id_us_min((ID *)((*matar)[*totcol]));
+ }
*totcol = 0;
if (*matar) {
MEM_freeN(*matar);
@@ -838,11 +846,12 @@ void assign_material_id(ID *id, Material *ma, short act)
/* in data */
mao = (*matarar)[act - 1];
- if (mao) mao->id.us--;
+ if (mao)
+ id_us_min(&mao->id);
(*matarar)[act - 1] = ma;
if (ma)
- id_us_plus((ID *)ma);
+ id_us_plus(&ma->id);
test_object_materials(G.main, id);
}
@@ -916,17 +925,19 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type)
ob->matbits[act - 1] = bit;
if (bit == 1) { /* in object */
mao = ob->mat[act - 1];
- if (mao) mao->id.us--;
+ if (mao)
+ id_us_min(&mao->id);
ob->mat[act - 1] = ma;
}
else { /* in data */
mao = (*matarar)[act - 1];
- if (mao) mao->id.us--;
+ if (mao)
+ id_us_min(&mao->id);
(*matarar)[act - 1] = ma;
}
if (ma)
- id_us_plus((ID *)ma);
+ id_us_plus(&ma->id);
test_object_materials(G.main, ob->data);
}
@@ -958,6 +969,62 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
}
}
+/**
+ * Calculate a material remapping from \a ob_src to \a ob_dst.
+ *
+ * \param remap_src_to_dst: An array the size of `ob_src->totcol`
+ * where index values are filled in which map to \a ob_dst materials.
+ */
+void BKE_material_remap_object_calc(
+ Object *ob_dst, Object *ob_src,
+ short *remap_src_to_dst)
+{
+ if (ob_src->totcol == 0) {
+ return;
+ }
+
+ GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol);
+
+ for (int i = 0; i < ob_dst->totcol; i++) {
+ Material *ma_src = give_current_material(ob_dst, i + 1);
+ BLI_ghash_reinsert(gh_mat_map, ma_src, SET_INT_IN_POINTER(i), NULL, NULL);
+ }
+
+ /* setup default mapping (when materials don't match) */
+ {
+ int i = 0;
+ if (ob_dst->totcol >= ob_src->totcol) {
+ for (; i < ob_src->totcol; i++) {
+ remap_src_to_dst[i] = i;
+ }
+ }
+ else {
+ for (; i < ob_dst->totcol; i++) {
+ remap_src_to_dst[i] = i;
+ }
+ for (; i < ob_src->totcol; i++) {
+ remap_src_to_dst[i] = 0;
+ }
+ }
+ }
+
+ for (int i = 0; i < ob_src->totcol; i++) {
+ Material *ma_src = give_current_material(ob_src, i + 1);
+
+ if ((i < ob_dst->totcol) && (ma_src == give_current_material(ob_dst, i + 1))) {
+ /* when objects have exact matching materials - keep existing index */
+ }
+ else {
+ void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src);
+ if (index_src_p) {
+ remap_src_to_dst[i] = GET_INT_FROM_POINTER(*index_src_p);
+ }
+ }
+ }
+
+ BLI_ghash_free(gh_mat_map, NULL, NULL);
+}
+
/* XXX - this calls many more update calls per object then are needed, could be optimized */
void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
@@ -1245,13 +1312,13 @@ void material_drivers_update(Scene *scene, Material *ma, float ctime)
// printf("material_drivers_update(%s, %s)\n", scene->id.name, ma->id.name);
/* Prevent infinite recursion by checking (and tagging the material) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes ma->id.flag & LIB_DOIT isn't set by anything else
+ * (see BKE_scene_update_tagged()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else
* in the meantime... [#32017]
*/
- if (ma->id.flag & LIB_DOIT)
+ if (ma->id.tag & LIB_TAG_DOIT)
return;
- ma->id.flag |= LIB_DOIT;
+ ma->id.tag |= LIB_TAG_DOIT;
/* material itself */
if (ma->adt && ma->adt->drivers.first) {
@@ -1263,7 +1330,7 @@ void material_drivers_update(Scene *scene, Material *ma, float ctime)
material_node_drivers_update(scene, ma->nodetree, ctime);
}
- ma->id.flag &= ~LIB_DOIT;
+ ma->id.tag &= ~LIB_TAG_DOIT;
}
bool object_remove_material_slot(Object *ob)
@@ -1304,7 +1371,8 @@ bool object_remove_material_slot(Object *ob)
/* we delete the actcol */
mao = (*matarar)[ob->actcol - 1];
- if (mao) mao->id.us--;
+ if (mao)
+ id_us_min(&mao->id);
for (a = ob->actcol; a < ob->totcol; a++)
(*matarar)[a - 1] = (*matarar)[a];
@@ -1323,7 +1391,8 @@ bool object_remove_material_slot(Object *ob)
/* WATCH IT: do not use actcol from ob or from obt (can become zero) */
mao = obt->mat[actcol - 1];
- if (mao) mao->id.us--;
+ if (mao)
+ id_us_min(&mao->id);
for (a = actcol; a < obt->totcol; a++) {
obt->mat[a - 1] = obt->mat[a];
@@ -1802,8 +1871,10 @@ void paste_matcopybuf(Material *ma)
if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
for (a = 0; a < MAX_MTEX; a++) {
mtex = ma->mtex[a];
- if (mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
if (ma->nodetree) {
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index a3dd4139db4..ad9d9f6a742 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -71,7 +71,8 @@ void BKE_mball_unlink(MetaBall *mb)
int a;
for (a = 0; a < mb->totcol; a++) {
- if (mb->mat[a]) mb->mat[a]->id.us--;
+ if (mb->mat[a])
+ id_us_min(&mb->mat[a]->id);
mb->mat[a] = NULL;
}
}
@@ -91,19 +92,26 @@ void BKE_mball_free(MetaBall *mb)
if (mb->disp.first) BKE_displist_free(&mb->disp);
}
-MetaBall *BKE_mball_add(Main *bmain, const char *name)
+void BKE_mball_init(MetaBall *mb)
{
- MetaBall *mb;
-
- mb = BKE_libblock_alloc(bmain, ID_MB, name);
-
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(mb, id));
+
mb->size[0] = mb->size[1] = mb->size[2] = 1.0;
mb->texflag = MB_AUTOSPACE;
mb->wiresize = 0.4f;
mb->rendersize = 0.2f;
mb->thresh = 0.6f;
-
+}
+
+MetaBall *BKE_mball_add(Main *bmain, const char *name)
+{
+ MetaBall *mb;
+
+ mb = BKE_libblock_alloc(bmain, ID_MB, name);
+
+ BKE_mball_init(mb);
+
return mb;
}
@@ -179,8 +187,8 @@ void BKE_mball_make_local(MetaBall *mb)
if (ob->data == mb) {
if (ob->id.lib == NULL) {
ob->data = mb_new;
- mb_new->id.us++;
- mb->id.us--;
+ id_us_plus(&mb_new->id);
+ id_us_min(&mb->id);
}
}
}
@@ -284,6 +292,8 @@ void BKE_mball_texspace_calc(Object *ob)
size[2] = (max[2] - min[2]) / 2.0f;
#endif
BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 8c89a724975..c10592882c0 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -34,7 +34,7 @@
#include "DNA_object_types.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_ipo_types.h"
+#include "DNA_curve_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
@@ -141,13 +141,15 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
{
- i1++, l1++;
+ i1++;
+ l1++;
}
while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
{
- i2++, l2++;
+ i2++;
+ l2++;
}
if (l1->type == CD_MVERT) {
@@ -438,13 +440,14 @@ void BKE_mesh_unlink(Mesh *me)
if (me->mat) {
for (a = 0; a < me->totcol; a++) {
- if (me->mat[a]) me->mat[a]->id.us--;
+ if (me->mat[a])
+ id_us_min(&me->mat[a]->id);
me->mat[a] = NULL;
}
}
if (me->key) {
- me->key->id.us--;
+ id_us_min(&me->key->id);
}
me->key = NULL;
@@ -490,14 +493,12 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
mesh->totface = 0;
}
-Mesh *BKE_mesh_add(Main *bmain, const char *name)
+void BKE_mesh_init(Mesh *me)
{
- Mesh *me;
-
- me = BKE_libblock_alloc(bmain, ID_ME, name);
-
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(me, id));
+
me->size[0] = me->size[1] = me->size[2] = 1.0;
- me->smoothresh = 30;
+ me->smoothresh = DEG2RADF(30);
me->texflag = ME_AUTOSPACE;
/* disable because its slow on many GPU's, see [#37518] */
@@ -511,6 +512,15 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
CustomData_reset(&me->fdata);
CustomData_reset(&me->pdata);
CustomData_reset(&me->ldata);
+}
+
+Mesh *BKE_mesh_add(Main *bmain, const char *name)
+{
+ Mesh *me;
+
+ me = BKE_libblock_alloc(bmain, ID_ME, name);
+
+ BKE_mesh_init(me);
return me;
}
@@ -987,7 +997,7 @@ int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
SWAP(unsigned int, mface->v2, mface->v3);
if (fdata)
- CustomData_swap(fdata, mfindex, corner_indices);
+ CustomData_swap_corners(fdata, mfindex, corner_indices);
}
}
else if (nr == 4) {
@@ -998,7 +1008,7 @@ int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
SWAP(unsigned int, mface->v2, mface->v4);
if (fdata)
- CustomData_swap(fdata, mfindex, corner_indices);
+ CustomData_swap_corners(fdata, mfindex, corner_indices);
}
}
@@ -1024,7 +1034,7 @@ void BKE_mesh_assign_object(Object *ob, Mesh *me)
if (ob->type == OB_MESH) {
old = ob->data;
if (old)
- old->id.us--;
+ id_us_min(&old->id);
ob->data = me;
id_us_plus((ID *)me);
}
@@ -1721,7 +1731,7 @@ void BKE_mesh_to_curve(Scene *scene, Object *ob)
cu->nurb = nurblist;
- ((Mesh *)ob->data)->id.us--;
+ id_us_min(&((Mesh *)ob->data)->id);
ob->data = cu;
ob->type = OB_CURVE;
@@ -2199,8 +2209,9 @@ void BKE_mesh_calc_normals_split(Mesh *mesh)
}
else {
polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
- polynors, false);
+ BKE_mesh_calc_normals_poly(
+ mesh->mvert, NULL, mesh->totvert,
+ mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
free_polynors = true;
}
@@ -2338,7 +2349,7 @@ Mesh *BKE_mesh_new_from_object(
/* copies object and modifiers (but not the data) */
tmpobj = BKE_object_copy_ex(bmain, ob, true);
tmpcu = (Curve *)tmpobj->data;
- tmpcu->id.us--;
+ id_us_min(&tmpcu->id);
/* Copy cached display list, it might be needed by the stack evaluation.
* Ideally stack should be able to use render-time display list, but doing
@@ -2408,7 +2419,7 @@ Mesh *BKE_mesh_new_from_object(
tmpmesh = BKE_mesh_add(bmain, "Mesh");
/* BKE_mesh_add gives us a user count we don't need */
- tmpmesh->id.us--;
+ id_us_min(&tmpmesh->id);
if (render) {
ListBase disp = {NULL, NULL};
@@ -2463,7 +2474,7 @@ Mesh *BKE_mesh_new_from_object(
}
/* BKE_mesh_add/copy gives us a user count we don't need */
- tmpmesh->id.us--;
+ id_us_min(&tmpmesh->id);
break;
default:
@@ -2486,7 +2497,7 @@ Mesh *BKE_mesh_new_from_object(
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i];
if (tmpmesh->mat[i]) {
- tmpmesh->mat[i]->id.us++;
+ id_us_plus(&tmpmesh->mat[i]->id);
}
}
}
@@ -2503,7 +2514,7 @@ Mesh *BKE_mesh_new_from_object(
for (i = tmpmb->totcol; i-- > 0; ) {
tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */
if (tmpmesh->mat[i]) {
- tmpmb->mat[i]->id.us++;
+ id_us_plus(&tmpmb->mat[i]->id);
}
}
}
@@ -2523,7 +2534,7 @@ Mesh *BKE_mesh_new_from_object(
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
if (tmpmesh->mat[i]) {
- tmpmesh->mat[i]->id.us++;
+ id_us_plus(&tmpmesh->mat[i]->id);
}
}
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 2fc535061ac..83e020cf2ea 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -133,7 +133,7 @@ void BKE_mesh_calc_normals_mapping_ex(
if (only_face_normals == false) {
/* vertex normals are optional, they require some extra calculations,
* so make them optional */
- BKE_mesh_calc_normals_poly(mverts, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
+ BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
}
else {
/* only calc poly normals */
@@ -167,11 +167,33 @@ void BKE_mesh_calc_normals_mapping_ex(
}
-static void mesh_calc_normals_poly_accum(
- const MPoly *mp, const MLoop *ml,
- const MVert *mvert,
- float r_polyno[3], float (*r_tnorms)[3])
+typedef struct MeshCalcNormalsData {
+ const MPoly *mpolys;
+ const MLoop *mloop;
+ MVert *mverts;
+ float (*pnors)[3];
+ float (*vnors)[3];
+} MeshCalcNormalsData;
+
+static void mesh_calc_normals_poly_task_cb(void *userdata, const int pidx)
+{
+ MeshCalcNormalsData *data = userdata;
+ const MPoly *mp = &data->mpolys[pidx];
+
+ BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
+}
+
+static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx)
{
+ MeshCalcNormalsData *data = userdata;
+ const MPoly *mp = &data->mpolys[pidx];
+ const MLoop *ml = &data->mloop[mp->loopstart];
+ const MVert *mverts = data->mverts;
+
+ float pnor_temp[3];
+ float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
+ float (*vnors)[3] = data->vnors;
+
const int nverts = mp->totloop;
float (*edgevecbuf)[3] = BLI_array_alloca(edgevecbuf, (size_t)nverts);
int i;
@@ -180,14 +202,14 @@ static void mesh_calc_normals_poly_accum(
/* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
{
int i_prev = nverts - 1;
- const float *v_prev = mvert[ml[i_prev].v].co;
+ const float *v_prev = mverts[ml[i_prev].v].co;
const float *v_curr;
- zero_v3(r_polyno);
+ zero_v3(pnor);
/* Newell's Method */
for (i = 0; i < nverts; i++) {
- v_curr = mvert[ml[i].v].co;
- add_newell_cross_v3_v3v3(r_polyno, v_prev, v_curr);
+ v_curr = mverts[ml[i].v].co;
+ add_newell_cross_v3_v3v3(pnor, v_prev, v_curr);
/* Unrelated to normalize, calculate edge-vector */
sub_v3_v3v3(edgevecbuf[i_prev], v_prev, v_curr);
@@ -196,8 +218,8 @@ static void mesh_calc_normals_poly_accum(
v_prev = v_curr;
}
- if (UNLIKELY(normalize_v3(r_polyno) == 0.0f)) {
- r_polyno[2] = 1.0f; /* other axis set to 0.0 */
+ if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
+ pnor[2] = 1.0f; /* other axis set to 0.0 */
}
}
@@ -214,7 +236,7 @@ static void mesh_calc_normals_poly_accum(
const float fac = saacos(-dot_v3v3(cur_edge, prev_edge));
/* accumulate */
- madd_v3_v3fl(r_tnorms[ml[i].v], r_polyno, fac);
+ madd_v3_v3fl(vnors[ml[i].v], pnor, fac);
prev_edge = cur_edge;
}
}
@@ -222,46 +244,46 @@ static void mesh_calc_normals_poly_accum(
}
void BKE_mesh_calc_normals_poly(
- MVert *mverts, int numVerts,
+ MVert *mverts, float (*r_vertnors)[3], int numVerts,
const MLoop *mloop, const MPoly *mpolys,
int UNUSED(numLoops), int numPolys, float (*r_polynors)[3],
const bool only_face_normals)
{
float (*pnors)[3] = r_polynors;
- float (*tnorms)[3];
+ float (*vnors)[3] = r_vertnors;
+ bool free_vnors = false;
int i;
- const MPoly *mp;
if (only_face_normals) {
BLI_assert((pnors != NULL) || (numPolys == 0));
+ BLI_assert(r_vertnors == NULL);
-#pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT)
- for (i = 0; i < numPolys; i++) {
- BKE_mesh_calc_poly_normal(&mpolys[i], mloop + mpolys[i].loopstart, mverts, pnors[i]);
- }
+ MeshCalcNormalsData data = {
+ .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors,
+ };
+
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_task_cb, (numPolys > BKE_MESH_OMP_LIMIT));
return;
}
/* first go through and calculate normals for all the polys */
- tnorms = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, __func__);
-
- if (pnors) {
- mp = mpolys;
- for (i = 0; i < numPolys; i++, mp++) {
- mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], tnorms);
- }
+ if (vnors == NULL) {
+ vnors = MEM_callocN(sizeof(*vnors) * (size_t)numVerts, __func__);
+ free_vnors = true;
}
else {
- float tpnor[3]; /* temp poly normal */
- mp = mpolys;
- for (i = 0; i < numPolys; i++, mp++) {
- mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, tnorms);
- }
+ memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
}
+ MeshCalcNormalsData data = {
+ .mpolys = mpolys, .mloop = mloop, .mverts = mverts, .pnors = pnors, .vnors = vnors,
+ };
+
+ BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_accum_task_cb, (numPolys > BKE_MESH_OMP_LIMIT));
+
for (i = 0; i < numVerts; i++) {
MVert *mv = &mverts[i];
- float *no = tnorms[i];
+ float *no = vnors[i];
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
/* following Mesh convention; we use vertex coordinate itself for normal in this case */
@@ -271,7 +293,9 @@ void BKE_mesh_calc_normals_poly(
normal_float_to_short_v3(mv->no, no);
}
- MEM_freeN(tnorms);
+ if (free_vnors) {
+ MEM_freeN(vnors);
+ }
}
void BKE_mesh_calc_normals(Mesh *mesh)
@@ -279,7 +303,7 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#ifdef DEBUG_TIME
TIMEIT_START(BKE_mesh_calc_normals);
#endif
- BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert,
+ BKE_mesh_calc_normals_poly(mesh->mvert, NULL, mesh->totvert,
mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
NULL, false);
#ifdef DEBUG_TIME
@@ -928,7 +952,7 @@ static void loop_split_worker_do(
}
}
-static void loop_split_worker(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void loop_split_worker(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
LoopSplitTaskDataCommon *common_data = taskdata;
LoopSplitTaskData *data_buff;
@@ -1107,7 +1131,7 @@ static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const
#endif
}
-static void loop_split_generator(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void loop_split_generator(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
LoopSplitTaskDataCommon *common_data = taskdata;
@@ -2650,16 +2674,16 @@ int BKE_mesh_recalc_tessellation(
}
}
- /* NOTE: quad detection issue - forth vertidx vs forth loopidx:
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* Polygons take care of their loops ordering, hence not of their vertices ordering.
- * Currently, our tfaces' forth vertex index might be 0 even for a quad. However, we know our forth loop index is
+ * Currently, our tfaces' fourth vertex index might be 0 even for a quad. However, we know our fourth loop index is
* never 0 for quads (because they are sorted for polygons, and our quads are still mere copies of their polygons).
- * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the forth loop index as quad test.
+ * So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
* ...
*/
BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface);
- /* NOTE: quad detection issue - forth vertidx vs forth loopidx:
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
* test_index_face() will check this and rotate the tessellated face if needed.
*/
@@ -3176,6 +3200,112 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, CustomData *fdata, CustomData
}
/** \} */
+/**
+ * Flip a single MLoop's #MDisps structure,
+ * low level function to be called from face-flipping code which re-arranged the mdisps themselves.
+ */
+void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
+{
+ if (UNLIKELY(!md->totdisp || !md->disps)) {
+ return;
+ }
+
+ const int sides = (int)sqrt(md->totdisp);
+ float (*co)[3] = md->disps;
+
+ for (int x = 0; x < sides; x++) {
+ float *co_a, *co_b;
+
+ for (int y = 0; y < x; y++) {
+ co_a = co[y * sides + x];
+ co_b = co[x * sides + y];
+
+ swap_v3_v3(co_a, co_b);
+ SWAP(float, co_a[0], co_a[1]);
+ SWAP(float, co_b[0], co_b[1]);
+
+ if (use_loop_mdisp_flip) {
+ co_a[2] *= -1.0f;
+ co_b[2] *= -1.0f;
+ }
+ }
+
+ co_a = co[x * sides + x];
+
+ SWAP(float, co_a[0], co_a[1]);
+
+ if (use_loop_mdisp_flip) {
+ co_a[2] *= -1.0f;
+ }
+ }
+}
+
+/**
+ * Flip (invert winding of) the given \a mpoly, i.e. reverse order of its loops
+ * (keeping the same vertex as 'start point').
+ *
+ * \param mpoly the polygon to flip.
+ * \param mloop the full loops array.
+ * \param ldata the loops custom data.
+ */
+void BKE_mesh_polygon_flip_ex(
+ MPoly *mpoly, MLoop *mloop, CustomData *ldata,
+ MDisps *mdisp, const bool use_loop_mdisp_flip)
+{
+ int loopstart = mpoly->loopstart;
+ int loopend = loopstart + mpoly->totloop - 1;
+ const bool loops_in_ldata = (CustomData_get_layer(ldata, CD_MLOOP) == mloop);
+
+ if (mdisp) {
+ for (int i = mpoly->loopstart; i <= loopend; i++) {
+ BKE_mesh_mdisp_flip(&mdisp[i], use_loop_mdisp_flip);
+ }
+ }
+
+ /* Note that we keep same start vertex for flipped face. */
+
+ /* We also have to update loops edge
+ * (they will get their original 'other edge', that is, the original edge of their original previous loop)... */
+ unsigned int prev_edge_index = mloop[loopstart].e;
+ mloop[loopstart].e = mloop[loopend].e;
+
+ for (loopstart++; loopend > loopstart; loopstart++, loopend--) {
+ mloop[loopend].e = mloop[loopend - 1].e;
+ SWAP(unsigned int, mloop[loopstart].e, prev_edge_index);
+
+ if (!loops_in_ldata) {
+ SWAP(MLoop, mloop[loopstart], mloop[loopend]);
+ }
+ CustomData_swap(ldata, loopstart, loopend);
+ }
+ /* Even if we did not swap the other 'pivot' loop, we need to set its swapped edge. */
+ if (loopstart == loopend) {
+ mloop[loopstart].e = prev_edge_index;
+ }
+}
+
+void BKE_mesh_polygon_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata)
+{
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
+ BKE_mesh_polygon_flip_ex(mpoly, mloop, ldata, mdisp, true);
+}
+
+/**
+ * Flip (invert winding of) all polygons (used to inverse their normals).
+ *
+ * \note Invalidates tessellation, caller must handle that.
+ */
+void BKE_mesh_polygons_flip(
+ MPoly *mpoly, MLoop *mloop, CustomData *ldata, int totpoly)
+{
+ MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS);
+ MPoly *mp;
+ int i;
+
+ for (mp = mpoly, i = 0; i < totpoly; mp++, i++) {
+ BKE_mesh_polygon_flip_ex(mp, mloop, ldata, mdisp, true);
+ }
+}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index cf4c49a9244..c8bb2e0e758 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -97,7 +97,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(
float (*tf_uv)[2] = NULL;
if (use_winding) {
- tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, mp->totloop);
+ tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, (size_t)mp->totloop);
}
nverts = mp->totloop;
@@ -305,6 +305,49 @@ void BKE_mesh_vert_edge_map_create(MeshElemMap **r_map, int **r_mem,
}
/**
+ * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly (not their edges).
+ */
+void BKE_mesh_vert_edge_vert_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const MEdge *medge, int totvert, int totedge)
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
+ int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
+ int *i_pt = indices;
+
+ int i;
+
+ /* Count number of edges for each vertex */
+ for (i = 0; i < totedge; i++) {
+ map[medge[i].v1].count++;
+ map[medge[i].v2].count++;
+ }
+
+ /* Assign indices mem */
+ for (i = 0; i < totvert; i++) {
+ map[i].indices = i_pt;
+ i_pt += map[i].count;
+
+ /* Reset 'count' for use as index in last loop */
+ map[i].count = 0;
+ }
+
+ /* Find the users */
+ for (i = 0; i < totedge; i++) {
+ const unsigned int v[2] = {medge[i].v1, medge[i].v2};
+
+ map[v[0]].indices[map[v[0]].count] = (int)v[1];
+ map[v[1]].indices[map[v[1]].count] = (int)v[0];
+
+ map[v[0]].count++;
+ map[v[1]].count++;
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the edge and the value is a list of polygons that use that edge.
* The lists are allocated from one memory pool.
*/
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index c3b88b84b8b..c5fa9b15896 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -296,6 +296,8 @@ void BKE_mesh_remap_find_best_match_from_dm(
}
BLI_space_transform_global_from_matrices(r_space_transform, best_mat_dst, mat_src);
+
+ MEM_freeN(vcos_src);
}
/** \} */
@@ -455,14 +457,13 @@ void BKE_mesh_remap_calc_verts_from_dm(
BVHTreeNearest nearest = {0};
BVHTreeRayHit rayhit = {0};
float hit_dist;
+ float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_VERT_NEAREST) {
bvhtree_from_mesh_verts(&treedata, dm_src, 0.0f, 2, 6);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
- float tmp_co[3];
-
copy_v3_v3(tmp_co, verts_dst[i].co);
/* Convert the vertex to tree coordinates, if needed. */
@@ -488,8 +489,6 @@ void BKE_mesh_remap_calc_verts_from_dm(
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
- float tmp_co[3];
-
copy_v3_v3(tmp_co, verts_dst[i].co);
/* Convert the vertex to tree coordinates, if needed. */
@@ -548,8 +547,6 @@ void BKE_mesh_remap_calc_verts_from_dm(
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
- float tmp_co[3], tmp_no[3];
-
copy_v3_v3(tmp_co, verts_dst[i].co);
normal_short_to_float_v3(tmp_no, verts_dst[i].no);
@@ -580,8 +577,6 @@ void BKE_mesh_remap_calc_verts_from_dm(
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
- float tmp_co[3];
-
copy_v3_v3(tmp_co, verts_dst[i].co);
/* Convert the vertex to tree coordinates, if needed. */
@@ -590,7 +585,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- const MLoopTri *lt = &treedata.looptri[rayhit.index];
+ const MLoopTri *lt = &treedata.looptri[nearest.index];
MPoly *mp = &polys_src[lt->poly];
if (mode == MREMAP_MODE_VERT_POLY_NEAREST) {
@@ -656,6 +651,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BVHTreeNearest nearest = {0};
BVHTreeRayHit rayhit = {0};
float hit_dist;
+ float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
const int num_verts_src = dm_src->getNumVerts(dm_src);
@@ -694,8 +690,6 @@ void BKE_mesh_remap_calc_edges_from_dm(
/* Compute closest verts only once! */
if (v_dst_to_src_map[vidx_dst].hit_dist == -1.0f) {
- float tmp_co[3];
-
copy_v3_v3(tmp_co, verts_dst[vidx_dst].co);
/* Convert the vertex to tree coordinates, if needed. */
@@ -786,8 +780,6 @@ void BKE_mesh_remap_calc_edges_from_dm(
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
- float tmp_co[3];
-
interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
/* Convert the vertex to tree coordinates, if needed. */
@@ -814,8 +806,6 @@ void BKE_mesh_remap_calc_edges_from_dm(
bvhtree_from_mesh_looptri(&treedata, dm_src, 0.0f, 2, 6);
for (i = 0; i < numedges_dst; i++) {
- float tmp_co[3];
-
interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
/* Convert the vertex to tree coordinates, if needed. */
@@ -824,7 +814,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
if (mesh_remap_bvhtree_query_nearest(&treedata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
- const MLoopTri *lt = &treedata.looptri[rayhit.index];
+ const MLoopTri *lt = &treedata.looptri[nearest.index];
MPoly *mp_src = &polys_src[lt->poly];
MLoop *ml_src = &loops_src[mp_src->loopstart];
int nloops = mp_src->totloop;
@@ -872,8 +862,8 @@ void BKE_mesh_remap_calc_edges_from_dm(
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
* and use their hits to interpolate from source edges. */
const MEdge *me = &edges_dst[i];
- float tmp_co[3], v1_co[3], v2_co[3];
- float tmp_no[3], v1_no[3], v2_no[3];
+ float v1_co[3], v2_co[3];
+ float v1_no[3], v2_no[3];
int grid_size;
float edge_dst_len;
@@ -1150,6 +1140,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
BVHTreeRayHit rayhit = {0};
int num_trees = 0;
float hit_dist;
+ float tmp_co[3], tmp_no[3];
const bool use_from_vert = (mode & MREMAP_USE_VERT);
@@ -1234,7 +1225,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
if (dirty_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst, numverts_dst, loops_dst, polys_dst,
+ BKE_mesh_calc_normals_poly(verts_dst, NULL, numverts_dst, loops_dst, polys_dst,
numloops_dst, numpolys_dst, poly_nors_dst, true);
}
}
@@ -1440,13 +1431,20 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
for (pidx_dst = 0, mp_dst = polys_dst; pidx_dst < numpolys_dst; pidx_dst++, mp_dst++) {
- float (*pnor_dst)[3] = &poly_nors_dst[pidx_dst];
+ float pnor_dst[3];
/* Only in use_from_vert case, we may need polys' centers as fallback in case we cannot decide which
* corner to use from normals only. */
float pcent_dst[3];
bool pcent_dst_valid = false;
+ if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) {
+ copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]);
+ if (space_transform) {
+ BLI_space_transform_apply_normal(space_transform, pnor_dst);
+ }
+ }
+
if ((size_t)mp_dst->totloop > islands_res_buff_size) {
islands_res_buff_size = (size_t)mp_dst->totloop + MREMAP_DEFAULT_BUFSIZE;
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1460,7 +1458,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
ml_dst = &loops_dst[mp_dst->loopstart];
for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++, ml_dst++) {
if (use_from_vert) {
- float tmp_co[3];
MeshElemMap *vert_to_refelem_map_src = NULL;
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
@@ -1479,12 +1476,16 @@ void BKE_mesh_remap_calc_loops_from_dm(
int best_index_src = -1;
if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) {
- nor_dst = &loop_nors_dst[plidx_dst + mp_dst->loopstart];
+ copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]);
+ if (space_transform) {
+ BLI_space_transform_apply_normal(space_transform, tmp_no);
+ }
+ nor_dst = &tmp_no;
nors_src = loop_nors_src;
vert_to_refelem_map_src = vert_to_loop_map_src;
}
else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */
- nor_dst = pnor_dst;
+ nor_dst = &pnor_dst;
nors_src = poly_nors_src;
vert_to_refelem_map_src = vert_to_poly_map_src;
}
@@ -1556,8 +1557,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
else if (mode & MREMAP_USE_NORPROJ) {
- float tmp_co[3], tmp_no[3];
-
int n = (ray_radius > 0.0f) ? MREMAP_RAYCAST_APPROXIMATE_NR : 1;
float w = 1.0f;
@@ -1615,8 +1614,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
else { /* Nearest poly either to use all its loops/verts or just closest one. */
- float tmp_co[3];
-
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
nearest.index = -1;
@@ -1739,7 +1736,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
* Note we could be much more subtle here, again that's for later... */
int j;
float best_dist_sq = FLT_MAX;
- float tmp_co[3];
ml_dst = &loops_dst[lidx_dst];
copy_v3_v3(tmp_co, verts_dst[ml_dst->v].co);
@@ -1824,7 +1820,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Find a new valid loop in that new poly (nearest point on poly for now).
* Note we could be much more subtle here, again that's for later... */
float best_dist_sq = FLT_MAX;
- float tmp_co[3];
int j;
ml_dst = &loops_dst[lidx_dst];
@@ -1987,6 +1982,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
float (*poly_nors_dst)[3] = NULL;
+ float tmp_co[3], tmp_no[3];
int i;
BLI_assert(mode & MREMAP_MODE_POLY);
@@ -1999,7 +1995,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
if (dirty_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst,
+ BKE_mesh_calc_normals_poly(verts_dst, NULL, numverts_dst, loops_dst, polys_dst, numloops_dst, numpolys_dst,
poly_nors_dst, true);
}
}
@@ -2028,7 +2024,6 @@ void BKE_mesh_remap_calc_polys_from_dm(
for (i = 0; i < numpolys_dst; i++) {
MPoly *mp = &polys_dst[i];
- float tmp_co[3];
BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
@@ -2055,7 +2050,6 @@ void BKE_mesh_remap_calc_polys_from_dm(
for (i = 0; i < numpolys_dst; i++) {
MPoly *mp = &polys_dst[i];
- float tmp_co[3], tmp_no[3];
BKE_mesh_calc_poly_center(mp, &loops_dst[mp->loopstart], verts_dst, tmp_co);
copy_v3_v3(tmp_no, poly_nors_dst[i]);
@@ -2104,7 +2098,6 @@ void BKE_mesh_remap_calc_polys_from_dm(
* and use their hits to interpolate from source polys. */
/* Note: dst poly is early-converted into src space! */
MPoly *mp = &polys_dst[i];
- float tmp_co[3], tmp_no[3];
int tot_rays, done_rays = 0;
float poly_area_2d_inv, done_area = 0.0f;
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index e21dde9c726..49dd0b104ab 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -171,10 +171,10 @@ static int search_poly_cmp(const void *v1, const void *v2)
return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1;
/* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */
for (idx = 0; idx < max_idx; idx++) {
- const int v1 = sp1->verts[idx];
- const int v2 = sp2->verts[idx];
- if (v1 != v2) {
- return (v1 > v2) ? 1 : -1;
+ const int v1_i = sp1->verts[idx];
+ const int v2_i = sp2->verts[idx];
+ if (v1_i != v2_i) {
+ return (v1_i > v2_i) ? 1 : -1;
}
}
return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0;
@@ -241,6 +241,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
struct {
int verts : 1;
int verts_weight : 1;
+ int loops_edge : 1;
};
int as_flag;
} fix_flag;
@@ -495,6 +496,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
SortPoly *sort_polys = MEM_callocN(sizeof(SortPoly) * totpoly, "mesh validate's sort_polys");
SortPoly *prev_sp, *sp = sort_polys;
int prev_end;
+
for (i = 0, mp = mpolys; i < totpoly; i++, mp++, sp++) {
sp->index = i;
@@ -518,6 +520,14 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
sp->numverts = mp->totloop;
sp->loopstart = mp->loopstart;
+ /* Ideally we would only have to do that once on all vertices before we start checking each poly, but
+ * several polys can use same vert, so we have to ensure here all verts of current poly are cleared. */
+ for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++) {
+ if (ml->v < totvert) {
+ mverts[ml->v].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
+
/* Test all poly's loops' vert idx. */
for (j = 0, ml = &mloops[sp->loopstart]; j < mp->totloop; j++, ml++, v++) {
if (ml->v >= totvert) {
@@ -525,24 +535,16 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v);
sp->invalid = true;
}
+ else if (mverts[ml->v].flag & ME_VERT_TMP_TAG) {
+ PRINT_ERR("\tPoly %u has duplicated vert reference at corner (%u)\n", i, j);
+ sp->invalid = true;
+ }
else {
mverts[ml->v].flag |= ME_VERT_TMP_TAG;
}
*v = ml->v;
}
- /* is the same vertex used more than once */
- if (!sp->invalid) {
- v = sp->verts;
- for (j = 0; j < mp->totloop; j++, v++) {
- if ((mverts[*v].flag & ME_VERT_TMP_TAG) == 0) {
- PRINT_ERR("\tPoly %u has duplicate vert reference at corner (%u)\n", i, j);
- sp->invalid = true;
- }
- mverts[*v].flag &= ~ME_VERT_TMP_TAG;
- }
- }
-
if (sp->invalid)
continue;
@@ -564,6 +566,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (do_fixes) {
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
+ fix_flag.loops_edge = true;
PRINT_ERR("\tLoop %u has invalid edge reference (%d), fixed using edge %u\n",
sp->loopstart + j, prev_e, ml->e);
}
@@ -580,6 +583,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (do_fixes) {
int prev_e = ml->e;
ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(edge_hash, v1, v2));
+ fix_flag.loops_edge = true;
PRINT_ERR("\tPoly %u has invalid edge reference (%d), fixed using edge %u\n",
sp->index, prev_e, ml->e);
}
@@ -591,31 +595,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
}
- /* Now check that that poly does not use a same vertex more than once! */
if (!sp->invalid) {
- const int *prev_v = v = sp->verts;
- j = sp->numverts;
-
- qsort(sp->verts, j, sizeof(int), int_cmp);
-
- for (j--, v++; j; j--, v++) {
- if (*v != *prev_v) {
- int dlt = v - prev_v;
- if (dlt > 1) {
- PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %d (%d times)\n",
- sp->index, *prev_v, dlt);
- sp->invalid = true;
- }
- prev_v = v;
- }
- }
- if (v - prev_v > 1) { /* Don't forget final verts! */
- PRINT_ERR("\tPoly %u is invalid, it multi-uses vertex %d (%d times)\n",
- sp->index, *prev_v, (int)(v - prev_v));
- sp->invalid = true;
- }
+ /* Needed for checking polys using same verts below. */
+ qsort(sp->verts, sp->numverts, sizeof(int), int_cmp);
}
-
}
}
@@ -627,66 +610,69 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
for (i = 1; i < totpoly; i++, sp++) {
int p1_nv = sp->numverts, p2_nv = prev_sp->numverts;
const int *p1_v = sp->verts, *p2_v = prev_sp->verts;
- short p1_sub = true, p2_sub = true;
- if (sp->invalid)
+
+ if (sp->invalid) {
+ /* break, because all known invalid polys have been put at the end by qsort with search_poly_cmp. */
break;
+ }
+
/* Test same polys. */
#if 0
- /* NOTE: This performs a sub-set test. */
- /* XXX This (and the sort of verts list) is better than systematic
- * search of all verts of one list into the other if lists have
- * a fair amount of elements.
- * Not sure however it's worth it in this case?
- * But as we also need sorted vert list to check verts multi-used
- * (in first pass of checks)... */
- /* XXX If we consider only "equal" polys (i.e. using exactly same set of verts)
- * as invalid, better to replace this by a simple memory cmp... */
- while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) {
- if (*p1_v < *p2_v) {
- if (p1_sub)
- p1_sub = false;
- p1_nv--;
- p1_v++;
+ {
+ bool p1_sub = true, p2_sub = true;
+
+ /* NOTE: This performs a sub-set test. */
+ /* XXX This (and the sort of verts list) is better than systematic
+ * search of all verts of one list into the other if lists have
+ * a fair amount of elements.
+ * Not sure however it's worth it in this case?
+ * But as we also need sorted vert list to check verts multi-used
+ * (in first pass of checks)... */
+ /* XXX If we consider only "equal" polys (i.e. using exactly same set of verts)
+ * as invalid, better to replace this by a simple memory cmp... */
+ while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) {
+ if (*p1_v < *p2_v) {
+ if (p1_sub)
+ p1_sub = false;
+ p1_nv--;
+ p1_v++;
+ }
+ else if (*p2_v < *p1_v) {
+ if (p2_sub)
+ p2_sub = false;
+ p2_nv--;
+ p2_v++;
+ }
+ else {
+ /* Equality, both next verts. */
+ p1_nv--;
+ p2_nv--;
+ p1_v++;
+ p2_v++;
+ }
}
- else if (*p2_v < *p1_v) {
- if (p2_sub)
- p2_sub = false;
- p2_nv--;
- p2_v++;
+ if (p1_nv && p1_sub)
+ p1_sub = false;
+ else if (p2_nv && p2_sub)
+ p2_sub = false;
+
+ if (p1_sub && p2_sub) {
+ PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n",
+ prev_sp->index, sp->index, sp->index);
+ sp->invalid = true;
}
- else {
- /* Equality, both next verts. */
- p1_nv--;
- p2_nv--;
- p1_v++;
- p2_v++;
+ /* XXX In fact, these might be valid? :/ */
+ else if (p1_sub) {
+ PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index);
+ sp->invalid = true;
+ }
+ else if (p2_sub) {
+ PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index);
+ prev_sp->invalid = true;
+ prev_sp = sp; /* sp is new reference poly. */
}
- }
- if (p1_nv && p1_sub)
- p1_sub = false;
- else if (p2_nv && p2_sub)
- p2_sub = false;
-
- if (p1_sub && p2_sub) {
- PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n",
- prev_sp->index, sp->index, sp->index);
- sp->invalid = true;
- }
- /* XXX In fact, these might be valid? :/ */
- else if (p1_sub) {
- PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index);
- sp->invalid = true;
- }
- else if (p2_sub) {
- PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index);
- prev_sp->invalid = true;
- prev_sp = sp; /* sp is new reference poly. */
}
#else
- if (0) {
- p1_sub += 0;
- p2_sub += 0;
- }
if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
if (do_verbose) {
PRINT_ERR("\tPolys %u and %u use same vertices (%d",
@@ -884,9 +870,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
*r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag);
- if (do_fixes == false) {
- BLI_assert(*r_changed == false);
- }
+ BLI_assert((*r_changed == false) || (do_fixes == true));
return is_valid;
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index b2c0c6d6d0a..716da14cae6 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -215,8 +215,7 @@ void modifiers_clearErrors(Object *ob)
}
}
-void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk,
- void *userData)
+void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk, void *userData)
{
ModifierData *md = ob->modifiers.first;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 7a8c4ad4564..a8d3c600817 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -88,7 +88,7 @@ static int sequence_guess_offset(const char *full_name, int head_len, unsigned s
return atoi(num);
}
-static int rendersize_to_proxy(MovieClipUser *user, int flag)
+static int rendersize_to_proxy(const MovieClipUser *user, int flag)
{
if ((flag & MCLIP_USE_PROXY) == 0)
return IMB_PROXY_NONE;
@@ -143,7 +143,9 @@ static int get_timecode(MovieClip *clip, int flag)
return clip->proxy.tc;
}
-static void get_sequence_fname(MovieClip *clip, int framenr, char *name)
+static void get_sequence_fname(const MovieClip *clip,
+ const int framenr,
+ char *name)
{
unsigned short numlen;
char head[FILE_MAX], tail[FILE_MAX];
@@ -157,16 +159,25 @@ static void get_sequence_fname(MovieClip *clip, int framenr, char *name)
*/
offset = sequence_guess_offset(clip->name, strlen(head), numlen);
- if (numlen)
- BLI_stringenc(name, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
- else
+ if (numlen) {
+ BLI_stringenc(name,
+ head, tail,
+ numlen,
+ offset + framenr - clip->start_frame + clip->frame_offset);
+ }
+ else {
BLI_strncpy(name, clip->name, sizeof(clip->name));
+ }
BLI_path_abs(name, ID_BLEND_PATH(G.main, &clip->id));
}
/* supposed to work with sequences only */
-static void get_proxy_fname(MovieClip *clip, int proxy_render_size, bool undistorted, int framenr, char *name)
+static void get_proxy_fname(const MovieClip *clip,
+ int proxy_render_size,
+ bool undistorted,
+ int framenr,
+ char *name)
{
int size = rendersize_to_number(proxy_render_size);
char dir[FILE_MAX], clipdir[FILE_MAX], clipfile[FILE_MAX];
@@ -192,7 +203,10 @@ static void get_proxy_fname(MovieClip *clip, int proxy_render_size, bool undisto
strcat(name, ".jpg");
}
-static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
+static ImBuf *movieclip_load_sequence_file(MovieClip *clip,
+ const MovieClipUser *user,
+ int framenr,
+ int flag)
{
struct ImBuf *ibuf;
char name[FILE_MAX];
@@ -261,7 +275,10 @@ static void movieclip_open_anim_file(MovieClip *clip)
}
}
-static ImBuf *movieclip_load_movie_file(MovieClip *clip, MovieClipUser *user, int framenr, int flag)
+static ImBuf *movieclip_load_movie_file(MovieClip *clip,
+ const MovieClipUser *user,
+ int framenr,
+ int flag)
{
ImBuf *ibuf = NULL;
int tc = get_timecode(clip, flag);
@@ -300,7 +317,9 @@ static void movieclip_calc_length(MovieClip *clip)
else {
clip->len = 0;
for (;;) {
- get_sequence_fname(clip, clip->len + clip->start_frame, name);
+ get_sequence_fname(clip,
+ clip->len + clip->start_frame,
+ name);
if (BLI_exists(name))
clip->len++;
@@ -348,6 +367,8 @@ typedef struct MovieClipCache {
} stabilized;
int sequence_offset;
+
+ bool is_still_sequence;
} MovieClipCache;
typedef struct MovieClipImBufCacheKey {
@@ -439,12 +460,19 @@ static void moviecache_prioritydeleter(void *priority_data_v)
MEM_freeN(priority_data);
}
-static ImBuf *get_imbuf_cache(MovieClip *clip, MovieClipUser *user, int flag)
+static ImBuf *get_imbuf_cache(MovieClip *clip,
+ const MovieClipUser *user,
+ int flag)
{
if (clip->cache) {
MovieClipImBufCacheKey key;
- key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ if (!clip->cache->is_still_sequence) {
+ key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ }
+ else {
+ key.framenr = 1;
+ }
if (flag & MCLIP_USE_PROXY) {
key.proxy = rendersize_to_proxy(user, flag);
@@ -483,11 +511,15 @@ static bool has_imbuf_cache(MovieClip *clip, MovieClipUser *user, int flag)
return false;
}
-static bool put_imbuf_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int flag, bool destructive)
+static bool put_imbuf_cache(MovieClip *clip,
+ const MovieClipUser *user,
+ ImBuf *ibuf,
+ int flag,
+ bool destructive)
{
MovieClipImBufCacheKey key;
- if (!clip->cache) {
+ if (clip->cache == NULL) {
struct MovieCache *moviecache;
// char cache_name[64];
@@ -495,17 +527,32 @@ static bool put_imbuf_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, i
clip->cache = MEM_callocN(sizeof(MovieClipCache), "movieClipCache");
- moviecache = IMB_moviecache_create("movieclip", sizeof(MovieClipImBufCacheKey), moviecache_hashhash, moviecache_hashcmp);
+ moviecache = IMB_moviecache_create("movieclip",
+ sizeof(MovieClipImBufCacheKey),
+ moviecache_hashhash,
+ moviecache_hashcmp);
IMB_moviecache_set_getdata_callback(moviecache, moviecache_keydata);
- IMB_moviecache_set_priority_callback(moviecache, moviecache_getprioritydata, moviecache_getitempriority,
+ IMB_moviecache_set_priority_callback(moviecache,
+ moviecache_getprioritydata,
+ moviecache_getitempriority,
moviecache_prioritydeleter);
clip->cache->moviecache = moviecache;
clip->cache->sequence_offset = -1;
+ if (clip->source == MCLIP_SRC_SEQUENCE) {
+ unsigned short numlen;
+ BLI_stringdec(clip->name, NULL, NULL, &numlen);
+ clip->cache->is_still_sequence = (numlen == 0);
+ }
}
- key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ if (!clip->cache->is_still_sequence) {
+ key.framenr = user_frame_to_cache_frame(clip, user->framenr);
+ }
+ else {
+ key.framenr = 1;
+ }
if (flag & MCLIP_USE_PROXY) {
key.proxy = rendersize_to_proxy(user, flag);
@@ -603,9 +650,8 @@ static void detect_clip_source(MovieClip *clip)
MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
{
MovieClip *clip;
- int file, len;
- const char *libname;
- char str[FILE_MAX], strtest[FILE_MAX];
+ int file;
+ char str[FILE_MAX];
BLI_strncpy(str, name, sizeof(str));
BLI_path_abs(str, bmain->name);
@@ -616,29 +662,10 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
return NULL;
close(file);
- /* ** first search an identical clip ** */
- for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
- BLI_strncpy(strtest, clip->name, sizeof(clip->name));
- BLI_path_abs(strtest, G.main->name);
-
- if (STREQ(strtest, str)) {
- BLI_strncpy(clip->name, name, sizeof(clip->name)); /* for stringcode */
- clip->id.us++; /* officially should not, it doesn't link here! */
-
- return clip;
- }
- }
-
/* ** add new movieclip ** */
/* create a short library name */
- len = strlen(name);
-
- while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\')
- len--;
- libname = name + len;
-
- clip = movieclip_alloc(bmain, libname);
+ clip = movieclip_alloc(bmain, BLI_path_basename(name));
BLI_strncpy(clip->name, name, sizeof(clip->name));
detect_clip_source(clip);
@@ -655,7 +682,41 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
return clip;
}
-static void real_ibuf_size(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int *width, int *height)
+MovieClip *BKE_movieclip_file_add_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
+{
+ MovieClip *clip;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ BLI_strncpy(str, filepath, sizeof(str));
+ BLI_path_abs(str, bmain->name);
+
+ /* first search an identical filepath */
+ for (clip = bmain->movieclip.first; clip; clip = clip->id.next) {
+ BLI_strncpy(strtest, clip->name, sizeof(clip->name));
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &clip->id));
+
+ if (BLI_path_cmp(strtest, str) == 0) {
+ id_us_plus(&clip->id); /* officially should not, it doesn't link here! */
+ if (r_exists)
+ *r_exists = true;
+ return clip;
+ }
+ }
+
+ if (r_exists)
+ *r_exists = false;
+ return BKE_movieclip_file_add(bmain, filepath);
+}
+
+MovieClip *BKE_movieclip_file_add_exists(Main *bmain, const char *filepath)
+{
+ return BKE_movieclip_file_add_exists_ex(bmain, filepath, NULL);
+}
+
+static void real_ibuf_size(const MovieClip *clip,
+ const MovieClipUser *user,
+ const ImBuf *ibuf,
+ int *width, int *height)
{
*width = ibuf->x;
*height = ibuf->y;
@@ -680,7 +741,9 @@ static void real_ibuf_size(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, in
}
}
-static ImBuf *get_undistorted_ibuf(MovieClip *clip, struct MovieDistortion *distortion, ImBuf *ibuf)
+static ImBuf *get_undistorted_ibuf(MovieClip *clip,
+ struct MovieDistortion *distortion,
+ ImBuf *ibuf)
{
ImBuf *undistibuf;
@@ -694,7 +757,7 @@ static ImBuf *get_undistorted_ibuf(MovieClip *clip, struct MovieDistortion *dist
return undistibuf;
}
-static int need_undistortion_postprocess(MovieClipUser *user)
+static int need_undistortion_postprocess(const MovieClipUser *user)
{
int result = 0;
@@ -705,7 +768,8 @@ static int need_undistortion_postprocess(MovieClipUser *user)
return result;
}
-static int need_postprocessed_frame(MovieClipUser *user, int postprocess_flag)
+static int need_postprocessed_frame(const MovieClipUser *user,
+ int postprocess_flag)
{
int result = postprocess_flag;
@@ -714,10 +778,10 @@ static int need_postprocessed_frame(MovieClipUser *user, int postprocess_flag)
return result;
}
-static bool check_undistortion_cache_flags(MovieClip *clip)
+static bool check_undistortion_cache_flags(const MovieClip *clip)
{
- MovieClipCache *cache = clip->cache;
- MovieTrackingCamera *camera = &clip->tracking.camera;
+ const MovieClipCache *cache = clip->cache;
+ const MovieTrackingCamera *camera = &clip->tracking.camera;
/* check for distortion model changes */
if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) {
@@ -739,9 +803,12 @@ static bool check_undistortion_cache_flags(MovieClip *clip)
return true;
}
-static ImBuf *get_postprocessed_cached_frame(MovieClip *clip, MovieClipUser *user, int flag, int postprocess_flag)
+static ImBuf *get_postprocessed_cached_frame(const MovieClip *clip,
+ const MovieClipUser *user,
+ int flag,
+ int postprocess_flag)
{
- MovieClipCache *cache = clip->cache;
+ const MovieClipCache *cache = clip->cache;
int framenr = user->framenr;
short proxy = IMB_PROXY_NONE;
int render_flag = 0;
@@ -778,7 +845,10 @@ static ImBuf *get_postprocessed_cached_frame(MovieClip *clip, MovieClipUser *use
return cache->postprocessed.ibuf;
}
-static ImBuf *postprocess_frame(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf, int postprocess_flag)
+static ImBuf *postprocess_frame(MovieClip *clip,
+ const MovieClipUser *user,
+ ImBuf *ibuf,
+ int postprocess_flag)
{
ImBuf *postproc_ibuf = NULL;
@@ -802,8 +872,11 @@ static ImBuf *postprocess_frame(MovieClip *clip, MovieClipUser *user, ImBuf *ibu
return postproc_ibuf;
}
-static void put_postprocessed_frame_to_cache(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf,
- int flag, int postprocess_flag)
+static void put_postprocessed_frame_to_cache(MovieClip *clip,
+ const MovieClipUser *user,
+ ImBuf *ibuf,
+ int flag,
+ int postprocess_flag)
{
MovieClipCache *cache = clip->cache;
MovieTrackingCamera *camera = &clip->tracking.camera;
@@ -839,15 +912,18 @@ static void put_postprocessed_frame_to_cache(MovieClip *clip, MovieClipUser *use
cache->postprocessed.ibuf = ibuf;
}
-static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *user, int flag,
- int postprocess_flag, int cache_flag)
+static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip,
+ const MovieClipUser *user,
+ int flag,
+ int postprocess_flag,
+ int cache_flag)
{
ImBuf *ibuf = NULL;
int framenr = user->framenr;
bool need_postprocess = false;
/* cache isn't threadsafe itself and also loading of movies
- * can't happen from concurent threads that's why we use lock here */
+ * can't happen from concurrent threads that's why we use lock here */
BLI_lock_thread(LOCK_MOVIECLIP);
/* try to obtain cached postprocessed frame first */
@@ -869,14 +945,18 @@ static ImBuf *movieclip_get_postprocessed_ibuf(MovieClip *clip, MovieClipUser *u
(user->render_size != MCLIP_PROXY_RENDER_SIZE_FULL);
if (clip->source == MCLIP_SRC_SEQUENCE || use_sequence) {
- ibuf = movieclip_load_sequence_file(clip, user, framenr, flag);
+ ibuf = movieclip_load_sequence_file(clip,
+ user,
+ framenr,
+ flag);
}
else {
ibuf = movieclip_load_movie_file(clip, user, framenr, flag);
}
- if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0)
+ if (ibuf && (cache_flag & MOVIECLIP_CACHE_SKIP) == 0) {
put_imbuf_cache(clip, user, ibuf, flag, true);
+ }
}
if (ibuf) {
@@ -1531,7 +1611,9 @@ bool BKE_movieclip_has_cached_frame(MovieClip *clip, MovieClipUser *user)
return has_frame;
}
-bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, MovieClipUser *user, ImBuf *ibuf)
+bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
+ MovieClipUser *user,
+ ImBuf *ibuf)
{
bool result;
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 9ef5b697079..9679b585e6f 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -106,13 +106,12 @@ void multires_customdata_delete(Mesh *me)
}
/** Grid hiding **/
-static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
- int lo_level,
- int hi_level,
+static BLI_bitmap *multires_mdisps_upsample_hidden(
+ BLI_bitmap *lo_hidden,
+ int lo_level, int hi_level,
- /* assumed to be at hi_level (or
- * null) */
- const BLI_bitmap *prev_hidden)
+ /* assumed to be at hi_level (or null) */
+ const BLI_bitmap *prev_hidden)
{
BLI_bitmap *subd;
int hi_gridsize = BKE_ccg_gridsize(hi_level);
@@ -1415,7 +1414,7 @@ void multires_stitch_grids(Object *ob)
int totface;
if (ccgdm->pbvh) {
- BKE_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void ***)&faces, &totface);
+ BKE_pbvh_get_grid_updates(ccgdm->pbvh, false, (void ***)&faces, &totface);
if (totface) {
ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
@@ -1464,10 +1463,10 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
gridData = result->getGridData(result);
result->getGridKey(result, &key);
- subGridData = MEM_callocN(sizeof(CCGElem *) * numGrids, "subGridData*");
+ subGridData = MEM_mallocN(sizeof(CCGElem *) * numGrids, "subGridData*");
for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_callocN(key.elem_size * gridSize * gridSize, "subGridData");
+ subGridData[i] = MEM_mallocN(key.elem_size * gridSize * gridSize, "subGridData");
memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
}
@@ -1855,7 +1854,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
Multires *mr = me->mr;
MVert *vsrc, *vdst;
unsigned int src, dst;
- int st = multires_side_tot[totlvl - 1] - 1;
+ int st_last = multires_side_tot[totlvl - 1] - 1;
int extedgelen = multires_side_tot[totlvl] - 2;
int *vvmap; // inorder for dst, map to src
int crossedgelen;
@@ -1901,7 +1900,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
int sides = lvl1->faces[i].v[3] ? 4 : 3;
vvmap[dst] = src + lvl1->totedge + i;
- dst += 1 + sides * (st - 1) * st;
+ dst += 1 + sides * (st_last - 1) * st_last;
}
@@ -1943,7 +1942,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
lvl = lvl->next;
}
- dst += sides * (st - 1) * st;
+ dst += sides * (st_last - 1) * st_last;
if (sides == 4) ++totquad;
else ++tottri;
@@ -1967,7 +1966,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
dst = 0;
for (j = 0; j < lvl1->totface; ++j) {
int sides = lvl1->faces[j].v[3] ? 4 : 3;
- int ldst = dst + 1 + sides * (st - 1);
+ int ldst = dst + 1 + sides * (st_last - 1);
for (s = 0; s < sides; ++s) {
int st2 = multires_side_tot[totlvl - 1] - 2;
@@ -1984,7 +1983,7 @@ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
find_old_edge(emap[0], lvl1->edges, cv, nv)->mid,
st2, st4);
- ldst += (st - 1) * (st - 1);
+ ldst += (st_last - 1) * (st_last - 1);
}
@@ -2227,7 +2226,7 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
dGridSize = multires_side_tot[high_mmd.totlvl];
dSkip = (dGridSize - 1) / (gridSize - 1);
-#pragma omp parallel for private(i) if (me->totface * gridSize * gridSize * 4 >= CCG_OMP_LIMIT)
+#pragma omp parallel for private(i) if (me->totloop * gridSize * gridSize >= CCG_OMP_LIMIT)
for (i = 0; i < me->totpoly; ++i) {
const int numVerts = mpoly[i].totloop;
MDisps *mdisp = &mdisps[mpoly[i].loopstart];
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a04eb9bd611..0527df67033 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1178,7 +1178,34 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
NlaStrip *nls = strip->next;
float offset = 0.0f;
- if (strip->end > nls->start) {
+ if (nls->type == NLASTRIP_TYPE_TRANSITION) {
+ /* transition strips should grow/shrink to accomodate the resized strip,
+ * but if the strip's bounds now exceed the transition, we're forced to
+ * offset everything to maintain the balance
+ */
+ if (strip->end <= nls->start) {
+ /* grow the transition to fill the void */
+ nls->start = strip->end;
+ }
+ else if (strip->end < nls->end) {
+ /* shrink the transition to give the strip room */
+ nls->start = strip->end;
+ }
+ else {
+ /* shrink transition down to 1 frame long (so that it can still be found),
+ * then offset everything else by the remaining defict to give the strip room
+ */
+ nls->start = nls->end - 1.0f;
+ offset = ceilf(strip->end - nls->start); /* XXX: review whether preventing fractionals is good here... */
+
+ /* apply necessary offset to ensure that the strip has enough space */
+ for (; nls; nls = nls->next) {
+ nls->start += offset;
+ nls->end += offset;
+ }
+ }
+ }
+ else if (strip->end > nls->start) {
/* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
* otherwise it will be very hard to get rid of later
*/
@@ -1198,7 +1225,34 @@ static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
NlaStrip *nls = strip->prev;
float offset = 0.0f;
- if (strip->start < nls->end) {
+ if (nls->type == NLASTRIP_TYPE_TRANSITION) {
+ /* transition strips should grow/shrink to accomodate the resized strip,
+ * but if the strip's bounds now exceed the transition, we're forced to
+ * offset everything to maintain the balance
+ */
+ if (strip->start >= nls->end) {
+ /* grow the transition to fill the void */
+ nls->end = strip->start;
+ }
+ else if (strip->start > nls->start) {
+ /* shrink the transition to give the strip room */
+ nls->end = strip->start;
+ }
+ else {
+ /* shrink transition down to 1 frame long (so that it can still be found),
+ * then offset everything else by the remaining defict to give the strip room
+ */
+ nls->end = nls->start + 1.0f;
+ offset = ceilf(nls->end - strip->start); /* XXX: review whether preventing fractionals is good here... */
+
+ /* apply necessary offset to ensure that the strip has enough space */
+ for (; nls; nls = nls->next) {
+ nls->start -= offset;
+ nls->end -= offset;
+ }
+ }
+ }
+ else if (strip->start < nls->end) {
/* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
* otherwise it will be very hard to get rid of later
*/
@@ -1778,7 +1832,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
return false;
}
-
+
/* go over all the tracks up to the active one, tagging each strip that uses the same
* action as the active strip, but leaving everything else alone
*/
@@ -1791,6 +1845,13 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
}
+ /* tag all other strips in active track that uses the same action as the active strip */
+ for (strip = activeTrack->strips.first; strip; strip = strip->next) {
+ if ((strip->act == activeStrip->act) && (strip != activeStrip))
+ strip->flag |= NLASTRIP_FLAG_TWEAKUSER;
+ else
+ strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
/* go over all the tracks after AND INCLUDING the active one, tagging them as being disabled
* - the active track needs to also be tagged, otherwise, it'll overlap with the tweaks going on
@@ -1852,8 +1913,19 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
nlt->flag &= ~NLATRACK_DISABLED;
- for (strip = nlt->strips.first; strip; strip = strip->next)
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ /* sync strip extents if this strip uses the same action */
+ if ((adt->actstrip) && (adt->actstrip->act == strip->act) && (strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
+ /* recalculate the length of the action */
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+
+ /* adjust the strip extents in response to this */
+ BKE_nlastrip_recalculate_bounds(strip);
+ }
+
+ /* clear tweakuser flag */
strip->flag &= ~NLASTRIP_FLAG_TWEAKUSER;
+ }
}
/* handle AnimData level changes:
@@ -1863,7 +1935,8 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
* - editing-flag for this AnimData block should also get turned off
* - clear pointer to active strip
*/
- if (adt->action) adt->action->id.us--;
+ if (adt->action)
+ id_us_min(&adt->action->id);
adt->action = adt->tmpact;
adt->tmpact = NULL;
adt->act_track = NULL;
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index c656931d18b..75f899dd597 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -72,6 +72,8 @@
#include "NOD_shader.h"
#include "NOD_texture.h"
+#define NODE_DEFAULT_MAX_WIDTH 700
+
/* Fallback types for undefined tree, nodes, sockets */
bNodeTreeType NodeTreeTypeUndefined;
bNodeType NodeTypeUndefined;
@@ -1151,6 +1153,11 @@ void nodeDetachNode(struct bNode *node)
}
}
+void ntreeInitDefault(bNodeTree *ntree)
+{
+ ntree_set_typeinfo(ntree, NULL);
+}
+
bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
{
bNodeTree *ntree;
@@ -1965,7 +1972,16 @@ bNodeTree *ntreeFromID(ID *id)
}
}
-void ntreeMakeLocal(bNodeTree *ntree)
+static void extern_local_ntree(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->id) {
+ id_lib_extern(node->id);
+ }
+ }
+}
+
+void ntreeMakeLocal(bNodeTree *ntree, bool id_in_mainlist)
{
Main *bmain = G.main;
bool lib = false, local = false;
@@ -1977,7 +1993,8 @@ void ntreeMakeLocal(bNodeTree *ntree)
if (ntree->id.lib == NULL) return;
if (ntree->id.us == 1) {
- id_clear_lib_data(bmain, (ID *)ntree);
+ id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
+ extern_local_ntree(ntree);
return;
}
@@ -1997,7 +2014,8 @@ void ntreeMakeLocal(bNodeTree *ntree)
/* if all users are local, we simply make tree local */
if (local && !lib) {
- id_clear_lib_data(bmain, (ID *)ntree);
+ id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
+ extern_local_ntree(ntree);
}
else if (local && lib) {
/* this is the mixed case, we copy the tree and assign it to local users */
@@ -2012,8 +2030,8 @@ void ntreeMakeLocal(bNodeTree *ntree)
if (node->id == (ID *)ntree) {
if (owner_id->lib == NULL) {
node->id = (ID *)newtree;
- newtree->id.us++;
- ntree->id.us--;
+ id_us_plus(&newtree->id);
+ id_us_min(&ntree->id);
}
}
}
@@ -2101,8 +2119,10 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
adt->action = ladt->action = action_backup;
adt->tmpact = ladt->tmpact = tmpact_backup;
- if (action_backup) action_backup->id.us++;
- if (tmpact_backup) tmpact_backup->id.us++;
+ if (action_backup)
+ id_us_plus(&action_backup->id);
+ if (tmpact_backup)
+ id_us_plus(&tmpact_backup->id);
}
/* end animdata uglyness */
@@ -3405,20 +3425,24 @@ void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
{
switch (size) {
case NODE_SIZE_DEFAULT:
- node_type_size(ntype, 140, 100, 320);
+ node_type_size(ntype, 140, 100, NODE_DEFAULT_MAX_WIDTH);
break;
case NODE_SIZE_SMALL:
- node_type_size(ntype, 100, 80, 320);
+ node_type_size(ntype, 100, 80, NODE_DEFAULT_MAX_WIDTH);
break;
case NODE_SIZE_MIDDLE:
- node_type_size(ntype, 150, 120, 320);
+ node_type_size(ntype, 150, 120, NODE_DEFAULT_MAX_WIDTH);
break;
case NODE_SIZE_LARGE:
- node_type_size(ntype, 240, 140, 320);
+ node_type_size(ntype, 240, 140, NODE_DEFAULT_MAX_WIDTH);
break;
}
}
+/**
+ * \warning Nodes defining a storage type _must_ allocate this for new nodes.
+ * Otherwise nodes will reload as undefined (T46619).
+ */
void node_type_storage(bNodeType *ntype,
const char *storagename,
void (*freefunc)(struct bNode *node),
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 526a71b477d..1ba4852623c 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -40,6 +40,7 @@
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -210,6 +211,9 @@ void BKE_object_free_modifiers(Object *ob)
/* same for softbody */
BKE_object_free_softbody(ob);
+
+ /* modifiers may have stored data in the DM cache */
+ BKE_object_free_derived_caches(ob);
}
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
@@ -360,10 +364,15 @@ void BKE_object_free_caches(Object *object)
for (md = object->modifiers.first; md != NULL; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->dm != NULL) {
- psmd->dm->needsFree = 1;
- psmd->dm->release(psmd->dm);
- psmd->dm = NULL;
+ if (psmd->dm_final != NULL) {
+ psmd->dm_final->needsFree = 1;
+ psmd->dm_final->release(psmd->dm_final);
+ psmd->dm_final = NULL;
+ if (psmd->dm_deformed != NULL) {
+ psmd->dm_deformed->needsFree = 1;
+ psmd->dm_deformed->release(psmd->dm_deformed);
+ psmd->dm_deformed = NULL;
+ }
psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= OB_RECALC_DATA;
}
@@ -384,12 +393,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
{
int a;
- BKE_object_free_derived_caches(ob);
+ BKE_object_free_modifiers(ob);
/* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */
if (ob->data) {
ID *id = ob->data;
- id->us--;
+ id_us_min(id);
if (id->us == 0 && id->lib == NULL) {
switch (ob->type) {
case OB_MESH:
@@ -408,7 +417,8 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->mat) {
for (a = 0; a < ob->totcol; a++) {
- if (ob->mat[a]) ob->mat[a]->id.us--;
+ if (ob->mat[a])
+ id_us_min(&ob->mat[a]->id);
}
MEM_freeN(ob->mat);
}
@@ -420,8 +430,10 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->bb) MEM_freeN(ob->bb);
ob->bb = NULL;
if (ob->adt) BKE_animdata_free((ID *)ob);
- if (ob->poselib) ob->poselib->id.us--;
- if (ob->gpd) ((ID *)ob->gpd)->us--;
+ if (ob->poselib)
+ id_us_min(&ob->poselib->id);
+ if (ob->gpd)
+ id_us_min(&ob->gpd->id);
if (ob->defbase.first)
BLI_freelistN(&ob->defbase);
if (ob->pose)
@@ -429,7 +441,6 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
if (ob->mpath)
animviz_free_motionpath(ob->mpath);
BKE_bproperty_free_list(&ob->prop);
- BKE_object_free_modifiers(ob);
free_sensors(&ob->sensors);
free_controllers(&ob->controllers);
@@ -467,7 +478,7 @@ void BKE_object_free(Object *ob)
BKE_object_free_ex(ob, true);
}
-static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin)
+static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag))
{
Object *unlinkOb = userData;
@@ -478,9 +489,8 @@ static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Objec
}
}
-void BKE_object_unlink(Object *ob)
+void BKE_object_unlink(Main *bmain, Object *ob)
{
- Main *bmain = G.main;
Object *obt;
Material *mat;
World *wrld;
@@ -972,19 +982,10 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
}
}
-/* more general add: creates minimum required data, but without vertices etc. */
-Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
+void BKE_object_init(Object *ob)
{
- Object *ob;
-
- if (!name)
- name = get_obdata_defname(type);
-
- ob = BKE_libblock_alloc(bmain, ID_OB, name);
+ /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ob, id)); */ /* ob->type is already initialized... */
- /* default object vars */
- ob->type = type;
-
ob->col[0] = ob->col[1] = ob->col[2] = 1.0;
ob->col[3] = 1.0;
@@ -1012,7 +1013,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob->empty_drawtype = OB_PLAINAXES;
ob->empty_drawsize = 1.0;
- if (ELEM(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
ob->trackflag = OB_NEGZ;
ob->upflag = OB_POSY;
}
@@ -1041,6 +1042,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob->step_height = 0.15f;
ob->jump_speed = 10.0f;
ob->fall_speed = 55.0f;
+ ob->max_jumps = 1;
ob->col_group = 0x01;
ob->col_mask = 0xffff;
ob->preview = NULL;
@@ -1052,6 +1054,22 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
/* Animation Visualization defaults */
animviz_settings_init(&ob->avs);
+}
+
+/* more general add: creates minimum required data, but without vertices etc. */
+Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
+{
+ Object *ob;
+
+ if (!name)
+ name = get_obdata_defname(type);
+
+ ob = BKE_libblock_alloc(bmain, ID_OB, name);
+
+ /* default object vars */
+ ob->type = type;
+
+ BKE_object_init(ob);
return ob;
}
@@ -1148,16 +1166,15 @@ bool BKE_object_lod_remove(Object *ob, int level)
static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
{
LodLevel *current = ob->currentlod;
- float dist_sq, dist_sq_curr;
+ float dist_sq;
if (!current) return NULL;
dist_sq = len_squared_v3v3(ob->obmat[3], camera_position);
- dist_sq_curr = current->distance * current->distance;
- if (dist_sq < dist_sq_curr) {
+ if (dist_sq < SQUARE(current->distance)) {
/* check for higher LoD */
- while (current->prev && dist_sq < dist_sq_curr) {
+ while (current->prev && dist_sq < SQUARE(current->distance)) {
current = current->prev;
}
}
@@ -1574,8 +1591,7 @@ Object *BKE_object_copy(Object *ob)
}
static void extern_local_object__modifiersForeachIDLink(
- void *UNUSED(userData), Object *UNUSED(ob),
- ID **idpoin)
+ void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
{
if (*idpoin) {
/* intentionally omit ID_OB */
@@ -1651,8 +1667,8 @@ void BKE_object_make_local(Object *ob)
while (base) {
if (base->object == ob) {
base->object = ob_new;
- ob_new->id.us++;
- ob->id.us--;
+ id_us_plus(&ob_new->id);
+ id_us_min(&ob->id);
}
base = base->next;
}
@@ -1791,7 +1807,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
/* set object type and link to data */
ob->type = target->type;
ob->data = target->data;
- id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_EXTERN */
+ id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */
/* copy material and index information */
ob->actcol = ob->totcol = 0;
@@ -1938,39 +1954,45 @@ void BKE_object_rot_to_mat3(Object *ob, float mat[3][3], bool use_drot)
void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], bool use_compat)
{
+ BLI_ASSERT_UNIT_M3(mat);
+
switch (ob->rotmode) {
case ROT_MODE_QUAT:
{
float dquat[4];
- mat3_to_quat(ob->quat, mat);
+ mat3_normalized_to_quat(ob->quat, mat);
normalize_qt_qt(dquat, ob->dquat);
- invert_qt(dquat);
+ invert_qt_normalized(dquat);
mul_qt_qtqt(ob->quat, dquat, ob->quat);
break;
}
case ROT_MODE_AXISANGLE:
{
- mat3_to_axis_angle(ob->rotAxis, &ob->rotAngle, mat);
- sub_v3_v3(ob->rotAxis, ob->drotAxis);
- ob->rotAngle -= ob->drotAngle;
+ float quat[4];
+ float dquat[4];
+
+ /* without drot we could apply 'mat' directly */
+ mat3_normalized_to_quat(quat, mat);
+ axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
+ invert_qt_normalized(dquat);
+ mul_qt_qtqt(quat, dquat, quat);
+ quat_to_axis_angle(ob->rotAxis, &ob->rotAngle, quat);
break;
}
default: /* euler */
{
float quat[4];
float dquat[4];
- float tmat[3][3];
/* without drot we could apply 'mat' directly */
- mat3_to_quat(quat, mat);
+ mat3_normalized_to_quat(quat, mat);
eulO_to_quat(dquat, ob->drot, ob->rotmode);
- invert_qt(dquat);
+ invert_qt_normalized(dquat);
mul_qt_qtqt(quat, dquat, quat);
- quat_to_mat3(tmat, quat);
/* end drot correction */
- if (use_compat) mat3_to_compatible_eulO(ob->rot, ob->rot, ob->rotmode, tmat);
- else mat3_to_eulO(ob->rot, ob->rotmode, tmat);
+ if (use_compat) quat_to_compatible_eulO(ob->rot, ob->rot, ob->rotmode, quat);
+ else quat_to_eulO(ob->rot, ob->rotmode, quat);
break;
}
}
@@ -2665,6 +2687,18 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3],
}
}
+void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale)
+{
+ float cent[3];
+ BKE_boundbox_calc_center_aabb(bb_src, cent);
+
+ for (int i = 0; i < ARRAY_SIZE(bb_dst->vec); i++) {
+ bb_dst->vec[i][0] = ((bb_src->vec[i][0] - cent[0]) * scale) + cent[0];
+ bb_dst->vec[i][1] = ((bb_src->vec[i][1] - cent[1]) * scale) + cent[1];
+ bb_dst->vec[i][2] = ((bb_src->vec[i][2] - cent[2]) * scale) + cent[2];
+ }
+}
+
/**
* Returns a BBox which each dimensions are at least epsilon.
* \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range.
@@ -3197,6 +3231,9 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
case ID_ME:
{
Mesh *me = ob->data;
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
if (r_texflag) *r_texflag = &me->texflag;
if (r_loc) *r_loc = me->loc;
if (r_size) *r_size = me->size;
@@ -3206,6 +3243,9 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
case ID_CU:
{
Curve *cu = ob->data;
+ if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_curve_texspace_calc(cu);
+ }
if (r_texflag) *r_texflag = &cu->texflag;
if (r_loc) *r_loc = cu->loc;
if (r_size) *r_size = cu->size;
@@ -3613,6 +3653,17 @@ static bool object_moves_in_time(Object *object)
return false;
}
+static bool object_deforms_in_time(Object *object)
+{
+ if (BKE_key_from_object(object) != NULL) {
+ return true;
+ }
+ if (!BLI_listbase_is_empty(&object->modifiers)) {
+ return true;
+ }
+ return object_moves_in_time(object);
+}
+
static bool constructive_modifier_is_deform_modified(ModifierData *md)
{
/* TODO(sergey): Consider generalizing this a bit so all modifier logic
@@ -3672,8 +3723,16 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
int flag = 0;
const bool is_modifier_animated = modifiers_has_animation_check(ob);
- if (BKE_key_from_object(ob))
+ if (BKE_key_from_object(ob)) {
flag |= eModifierMode_Realtime | eModifierMode_Render;
+ }
+
+ if (ob->type == OB_CURVE) {
+ Curve *cu = (Curve *)ob->data;
+ if (cu->taperobj != NULL && object_deforms_in_time(cu->taperobj)) {
+ flag |= eModifierMode_Realtime | eModifierMode_Render;
+ }
+ }
/* cloth */
for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -3716,38 +3775,6 @@ bool BKE_object_is_animated(Scene *scene, Object *ob)
return false;
}
-static void copy_object__forwardModifierLinks(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin)
-{
- /* this is copied from ID_NEW; it might be better to have a macro */
- if (*idpoin && (*idpoin)->newid) *idpoin = (*idpoin)->newid;
-}
-
-void BKE_object_relink(Object *ob)
-{
- if (ob->id.lib)
- return;
-
- BKE_constraints_relink(&ob->constraints);
- if (ob->pose) {
- bPoseChannel *chan;
- for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
- BKE_constraints_relink(&chan->constraints);
- }
- }
- modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL);
-
- if (ob->adt)
- BKE_animdata_relink(ob->adt);
-
- if (ob->rigidbody_constraint)
- BKE_rigidbody_relink_constraint(ob->rigidbody_constraint);
-
- ID_NEW(ob->parent);
-
- ID_NEW(ob->proxy);
- ID_NEW(ob->proxy_group);
-}
-
MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
{
MovieClip *clip = use_default ? scene->clip : NULL;
@@ -3798,13 +3825,13 @@ static Object *obrel_armature_find(Object *ob)
static bool obrel_list_test(Object *ob)
{
- return ob && !(ob->id.flag & LIB_DOIT);
+ return ob && !(ob->id.tag & LIB_TAG_DOIT);
}
static void obrel_list_add(LinkNode **links, Object *ob)
{
BLI_linklist_prepend(links, ob);
- ob->id.flag |= LIB_DOIT;
+ ob->id.tag |= LIB_TAG_DOIT;
}
/*
@@ -3822,7 +3849,7 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
/* Remove markers from all objects */
for (base = scene->base.first; base; base = base->next) {
- base->object->id.flag &= ~LIB_DOIT;
+ base->object->id.tag &= ~LIB_TAG_DOIT;
}
/* iterate over all selected and visible objects */
@@ -4097,3 +4124,105 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
return false;
}
+
+/* set "ignore cache" flag for all caches on this object */
+static void object_cacheIgnoreClear(Object *ob, int state)
+{
+ ListBase pidlist;
+ PTCacheID *pid;
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache) {
+ if (state)
+ pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
+ else
+ pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
+ }
+ }
+
+ BLI_freelistN(&pidlist);
+}
+
+/* Note: this function should eventually be replaced by depsgraph functionality.
+ * Avoid calling this in new code unless there is a very good reason for it!
+ */
+bool BKE_object_modifier_update_subframe(Scene *scene, Object *ob, bool update_mesh,
+ int parent_recursion, float frame,
+ int type)
+{
+ ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
+ bConstraint *con;
+
+ if (type == eModifierType_DynamicPaint) {
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+
+ /* if other is dynamic paint canvas, don't update */
+ if (pmd && pmd->canvas)
+ return true;
+ }
+ else if (type == eModifierType_Smoke) {
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) != 0)
+ return true;
+ }
+
+ /* if object has parents, update them too */
+ if (parent_recursion) {
+ int recursion = parent_recursion - 1;
+ bool no_update = false;
+ if (ob->parent) no_update |= BKE_object_modifier_update_subframe(scene, ob->parent, 0, recursion, frame, type);
+ if (ob->track) no_update |= BKE_object_modifier_update_subframe(scene, ob->track, 0, recursion, frame, type);
+
+ /* skip subframe if object is parented
+ * to vertex of a dynamic paint canvas */
+ if (no_update && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
+ return false;
+
+ /* also update constraint targets */
+ for (con = ob->constraints.first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {NULL, NULL};
+
+ if (cti && cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+ cti->get_constraint_targets(con, &targets);
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar)
+ BKE_object_modifier_update_subframe(scene, ct->tar, 0, recursion, frame, type);
+ }
+ /* free temp targets */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
+ ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+ BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
+ if (update_mesh) {
+ /* ignore cache clear during subframe updates
+ * to not mess up cache validity */
+ object_cacheIgnoreClear(ob, 1);
+ BKE_object_handle_update(G.main->eval_ctx, scene, ob);
+ object_cacheIgnoreClear(ob, 0);
+ }
+ else
+ BKE_object_where_is_calc_time(scene, ob, frame);
+
+ /* for curve following objects, parented curve has to be updated too */
+ if (ob->type == OB_CURVE) {
+ Curve *cu = ob->data;
+ BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
+ }
+ /* and armatures... */
+ if (ob->type == OB_ARMATURE) {
+ bArmature *arm = ob->data;
+ BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
+ BKE_pose_where_is(scene, ob);
+ }
+
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index e823f87468d..b5f63588423 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -596,6 +596,31 @@ bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_fl
return dg_selection;
}
+/* Marks mirror vgroups in output and counts them. Output and counter assumed to be already initialized.
+ * Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
+ */
+void BKE_object_defgroup_mirror_selection(
+ struct Object *ob, int defbase_tot, const bool *dg_selection,
+ bool *dg_flags_sel, int *r_dg_flags_sel_tot)
+{
+ bDeformGroup *defgroup;
+ unsigned int i;
+ int i_mirr;
+
+ for (i = 0, defgroup = ob->defbase.first; i < defbase_tot && defgroup; defgroup = defgroup->next, i++) {
+ if (dg_selection[i]) {
+ char name_flip[MAXBONENAME];
+
+ BKE_deform_flip_side_name(name_flip, defgroup->name, false);
+ i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip);
+
+ if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
+ dg_flags_sel[i_mirr] = true;
+ (*r_dg_flags_sel_tot) += 1;
+ }
+ }
+ }
+}
/**
* Return the subset type of the Vertex Group Selection
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 8abe4bdbb97..63c37fddc60 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -354,7 +354,7 @@ static void make_duplis_frames(const DupliContext *ctx)
/* special flag to avoid setting recalc flags to notify the depsgraph of
* updates, as this is not a permanent change to the object */
- ob->id.flag |= LIB_ANIM_NO_RECALC;
+ ob->id.tag |= LIB_TAG_ANIM_NO_RECALC;
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
int ok = 1;
@@ -792,8 +792,10 @@ static void make_duplis_faces(const DupliContext *ctx)
fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
if (use_texcoords) {
+ CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm);
+ const int uv_idx = CustomData_get_render_layer(ml_data, CD_MLOOPUV);
fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO);
- fdd.mloopuv = fdd.dm->getLoopDataArray(fdd.dm, CD_MLOOPUV);
+ fdd.mloopuv = CustomData_get_layer_n(ml_data, CD_MLOOPUV, uv_idx);
}
else {
fdd.orco = NULL;
@@ -1251,15 +1253,16 @@ DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
"DupliObject apply extra data");
for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
- /* copy obmat from duplis */
- copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
-
/* make sure derivedmesh is calculated once, before drawing */
if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
dob->ob->transflag |= OB_DUPLICALCDERIVED;
}
+ }
+ for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
+ /* copy obmat from duplis */
+ copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
copy_m4_m4(dob->ob->obmat, dob->mat);
/* copy layers from the main duplicator object */
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 1a178fb2bdf..c5179e5a428 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_rand.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -494,231 +495,296 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j)
BLI_rw_mutex_unlock(&oc->oceanmutex);
}
-void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
+typedef struct OceanSimulateData {
+ Ocean *o;
+ float t;
+ float scale;
+ float chop_amount;
+} OceanSimulateData;
+
+static void ocean_compute_htilda(void *userdata, const int i)
+{
+ OceanSimulateData *osd = userdata;
+ const Ocean *o = osd->o;
+ const float scale = osd->scale;
+ const float t = osd->t;
+
+ int j;
+
+ /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex exp_param1;
+ fftw_complex exp_param2;
+ fftw_complex conj_param;
+
+ init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
+ init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
+ exp_complex(exp_param1, exp_param1);
+ exp_complex(exp_param2, exp_param2);
+ conj_complex(conj_param, o->_h0_minus[i * o->_N + j]);
+
+ mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1);
+ mul_complex_c(exp_param2, conj_param, exp_param2);
+
+ add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2);
+ mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale);
+ }
+}
+
+static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+
+ fftw_execute(o->_disp_y_plan);
+}
+
+static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float scale = osd->scale;
+ const float chop_amount = osd->chop_amount;
int i, j;
- scale *= o->normalize_factor;
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+ fftw_complex minus_i;
+
+ init_complex(minus_i, 0.0, -1.0);
+ init_complex(mul_param, -scale, 0);
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, minus_i);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_disp_x_plan);
+}
- BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
+static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float scale = osd->scale;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
- /* compute a new htilda */
-#pragma omp parallel for private(i, j)
for (i = 0; i < o->_M; ++i) {
- /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */
for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex exp_param1;
- fftw_complex exp_param2;
- fftw_complex conj_param;
+ fftw_complex mul_param;
+ fftw_complex minus_i;
+
+ init_complex(minus_i, 0.0, -1.0);
+ init_complex(mul_param, -scale, 0);
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, minus_i);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_disp_z_plan);
+}
+
+static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ /* init_complex(mul_param, -scale, 0); */
+ init_complex(mul_param, -1, 0);
+
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_Jxx_plan);
- init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
- init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t);
- exp_complex(exp_param1, exp_param1);
- exp_complex(exp_param2, exp_param2);
- conj_complex(conj_param, o->_h0_minus[i * o->_N + j]);
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j < o->_N; ++j) {
+ o->_Jxx[i * o->_N + j] += 1.0;
+ }
+ }
+}
- mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1);
- mul_complex_c(exp_param2, conj_param, exp_param2);
+static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
- add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2);
- mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale);
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ /* init_complex(mul_param, -scale, 0); */
+ init_complex(mul_param, -1, 0);
+
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
}
}
+ fftw_execute(o->_Jzz_plan);
-#pragma omp parallel sections private(i, j)
- {
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j < o->_N; ++j) {
+ o->_Jzz[i * o->_N + j] += 1.0;
+ }
+ }
+}
-#pragma omp section
- {
- if (o->_do_disp_y) {
- /* y displacement */
- fftw_execute(o->_disp_y_plan);
- }
- } /* section 1 */
-
-#pragma omp section
- {
- if (o->_do_chop) {
- /* x displacement */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
- fftw_complex minus_i;
-
- init_complex(minus_i, 0.0, -1.0);
- init_complex(mul_param, -scale, 0);
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, minus_i);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_disp_x_plan);
- }
- } /* section 2 */
-
-#pragma omp section
- {
- if (o->_do_chop) {
- /* z displacement */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
- fftw_complex minus_i;
-
- init_complex(minus_i, 0.0, -1.0);
- init_complex(mul_param, -scale, 0);
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, minus_i);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_disp_z_plan);
- }
- } /* section 3 */
-
-#pragma omp section
- {
- if (o->_do_jacobian) {
- /* Jxx */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- /* init_complex(mul_param, -scale, 0); */
- init_complex(mul_param, -1, 0);
-
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_Jxx_plan);
+static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ const float chop_amount = osd->chop_amount;
+ int i, j;
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_Jxx[i * o->_N + j] += 1.0;
- }
- }
- }
- } /* section 4 */
-
-#pragma omp section
- {
- if (o->_do_jacobian) {
- /* Jzz */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- /* init_complex(mul_param, -scale, 0); */
- init_complex(mul_param, -1, 0);
-
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_Jzz_plan);
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_Jzz[i * o->_N + j] += 1.0;
- }
- }
- }
- } /* section 5 */
-
-#pragma omp section
- {
- if (o->_do_jacobian) {
- /* Jxz */
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- /* init_complex(mul_param, -scale, 0); */
- init_complex(mul_param, -1, 0);
-
- mul_complex_f(mul_param, mul_param, chop_amount);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param,
- ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
- 0.0f :
- o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
- init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_Jxz_plan);
- }
- } /* section 6 */
-
-#pragma omp section
- {
- /* fft normals */
- if (o->_do_normals) {
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- init_complex(mul_param, 0.0, -1.0);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param, o->_kx[i]);
- init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_N_x_plan);
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ /* init_complex(mul_param, -scale, 0); */
+ init_complex(mul_param, -1, 0);
+
+ mul_complex_f(mul_param, mul_param, chop_amount);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param,
+ ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ?
+ 0.0f :
+ o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j]));
+ init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_Jxz_plan);
+}
- }
- } /* section 7 */
-
-#pragma omp section
- {
- if (o->_do_normals) {
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j <= o->_N / 2; ++j) {
- fftw_complex mul_param;
-
- init_complex(mul_param, 0.0, -1.0);
- mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
- mul_complex_f(mul_param, mul_param, o->_kz[i]);
- init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
- }
- }
- fftw_execute(o->_N_z_plan);
+static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ init_complex(mul_param, 0.0, -1.0);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param, o->_kx[i]);
+ init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_N_x_plan);
+}
+
+static void ocean_compute_normal_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
+{
+ OceanSimulateData *osd = BLI_task_pool_userdata(pool);
+ const Ocean *o = osd->o;
+ int i, j;
+
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j <= o->_N / 2; ++j) {
+ fftw_complex mul_param;
+
+ init_complex(mul_param, 0.0, -1.0);
+ mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]);
+ mul_complex_f(mul_param, mul_param, o->_kz[i]);
+ init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param));
+ }
+ }
+ fftw_execute(o->_N_z_plan);
+}
+
+void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount)
+{
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *pool;
+
+ OceanSimulateData osd;
+
+ scale *= o->normalize_factor;
+
+ osd.o = o;
+ osd.t = t;
+ osd.scale = scale;
+ osd.chop_amount = chop_amount;
+
+ pool = BLI_task_pool_create(scheduler, &osd);
+
+ BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE);
+
+ /* Note about multi-threading here: we have to run a first set of computations (htilda one) before we can run
+ * all others, since they all depend on it.
+ * So we make a first parallelized forloop run for htilda, and then pack all other computations into
+ * a set of parallel tasks.
+ * This is not optimal in all cases, but remains reasonably simple and should be OK most of the time. */
+
+ /* compute a new htilda */
+ BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda, o->_M > 16);
+
+ if (o->_do_disp_y) {
+ BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH);
+ }
+
+ if (o->_do_chop) {
+ BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, TASK_PRIORITY_HIGH);
+ }
+
+ if (o->_do_jacobian) {
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, TASK_PRIORITY_HIGH);
+ }
+
+ if (o->_do_normals) {
+ BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
#if 0
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_N_y[i * o->_N + j] = 1.0f / scale;
- }
- }
- (MEM01)
-#endif
- o->_N_y = 1.0f / scale;
+ for (i = 0; i < o->_M; ++i) {
+ for (j = 0; j < o->_N; ++j) {
+ o->_N_y[i * o->_N + j] = 1.0f / scale;
}
- } /* section 8 */
+ }
+ (MEM01)
+#endif
+ o->_N_y = 1.0f / scale;
+ }
- } /* omp sections */
+ BLI_task_pool_work_and_wait(pool);
BLI_rw_mutex_unlock(&o->oceanmutex);
+
+ BLI_task_pool_free(pool);
}
static void set_height_normalize_factor(struct Ocean *oc)
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 151889b10a1..1c318dfd115 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -262,8 +262,6 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
else if (verbose)
BKE_report(reports, RPT_INFO, "No new files have been packed");
-
-
}
@@ -582,7 +580,7 @@ int unpackImage(ReportList *reports, Image *ima, int how)
{
int ret_value = RET_ERROR;
- if (ima != NULL && ima->name[0]) {
+ if (ima != NULL) {
while (ima->packedfiles.last) {
char localname[FILE_MAX], absname[FILE_MAX];
char *newname;
@@ -605,7 +603,9 @@ int unpackImage(ReportList *reports, Image *ima, int how)
}
/* keep the new name in the image for non-pack specific reasons */
- BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ if (how != PF_REMOVE) {
+ BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
+ }
MEM_freeN(newname);
}
else {
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 06844b09a9b..1b6fc92ef5e 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -373,7 +373,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name)
palette = BKE_libblock_alloc(bmain, ID_PAL, name);
/* enable fake user by default */
- palette->id.flag |= LIB_FAKEUSER;
+ id_fake_user_set(&palette->id);
return palette;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 9aacba8d02e..098700495a0 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -105,7 +105,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
-extern void do_child_modifiers(ParticleSimulationData *sim,
+extern void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim,
ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
@@ -395,8 +395,10 @@ void BKE_particlesettings_free(ParticleSettings *part)
for (a = 0; a < MAX_MTEX; a++) {
mtex = part->mtex[a];
- if (mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
}
@@ -567,7 +569,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
ob->transflag &= ~OB_DUPLIPARTS;
if (psys->part) {
- psys->part->id.us--;
+ id_us_min(&psys->part->id);
psys->part = NULL;
}
@@ -621,8 +623,8 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa
data->childcachebufs.last = psys->childcachebufs.last;
data->totchildcache = psys->totchildcache;
- if (psmd->dm)
- data->dm = CDDM_copy(psmd->dm);
+ if (psmd->dm_final)
+ data->dm = CDDM_copy(psmd->dm_final);
data->totdmvert = psmd->totdmvert;
data->totdmedge = psmd->totdmedge;
data->totdmface = psmd->totdmface;
@@ -663,9 +665,14 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
if (data->elems)
MEM_freeN(data->elems);
- if (psmd->dm) {
- psmd->dm->needsFree = 1;
- psmd->dm->release(psmd->dm);
+ if (psmd->dm_final) {
+ psmd->dm_final->needsFree = 1;
+ psmd->dm_final->release(psmd->dm_final);
+ }
+ if (psmd->dm_deformed) {
+ psmd->dm_deformed->needsFree = 1;
+ psmd->dm_deformed->release(psmd->dm_deformed);
+ psmd->dm_deformed = NULL;
}
psys_free_path_cache(psys, NULL);
@@ -687,14 +694,24 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
psys->childcachebufs.last = data->childcachebufs.last;
psys->totchildcache = data->totchildcache;
- psmd->dm = data->dm;
+ psmd->dm_final = data->dm;
psmd->totdmvert = data->totdmvert;
psmd->totdmedge = data->totdmedge;
psmd->totdmface = data->totdmface;
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- if (psmd->dm)
- psys_calc_dmcache(ob, psmd->dm, psys);
+ if (psmd->dm_final) {
+ if (!psmd->dm_final->deformedOnly) {
+ if (ob->derivedDeform) {
+ psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
+ }
+ else {
+ psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
+ }
+ DM_ensure_tessface(psmd->dm_deformed);
+ }
+ psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys);
+ }
MEM_freeN(data);
psys->renderdata = NULL;
@@ -703,13 +720,19 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
disp = psys_get_current_display_percentage(psys);
if (disp != render_disp) {
- PARTICLE_P;
+ /* Hair can and has to be recalculated if everything isn't displayed. */
+ if (psys->part->type == PART_HAIR) {
+ psys->recalc |= PSYS_RECALC_RESET;
+ }
+ else {
+ PARTICLE_P;
- LOOP_PARTICLES {
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
+ LOOP_PARTICLES {
+ if (psys_frand(psys, p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
+ }
}
}
}
@@ -1381,78 +1404,115 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
}
}
-/* find the derived mesh face for a particle, set the mf passed. this is slow
- * and can be optimized but only for many lookups. returns the face index. */
-int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const float fw[4], struct LinkNode *node)
+/**
+ * Find the final derived mesh tessface for a particle, from its original tessface index.
+ * This is slow and can be optimized but only for many lookups.
+ *
+ * \param dm_final final DM, it may not have the same topology as original mesh.
+ * \param dm_deformed deformed-only DM, it has the exact same topology as original mesh.
+ * \param findex_orig the input tessface index.
+ * \param fw face weights (position of the particle inside the \a findex_orig tessface).
+ * \param poly_nodes may be NULL, otherwise an array of linked list, one for each final DM polygon, containing all
+ * its tessfaces indices.
+ * \return the DM tessface index.
+ */
+int psys_particle_dm_face_lookup(
+ DerivedMesh *dm_final, DerivedMesh *dm_deformed,
+ int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
{
- Mesh *me = (Mesh *)ob->data;
- MPoly *mpoly;
- OrigSpaceFace *osface;
- int quad, findex, totface;
+ MFace *mtessface_final;
+ OrigSpaceFace *osface_final;
+ int pindex_orig;
float uv[2], (*faceuv)[2];
- /* double lookup */
- const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
+ const int *index_mf_to_mpoly_deformed = NULL;
+ const int *index_mf_to_mpoly = NULL;
+ const int *index_mp_to_orig = NULL;
+
+ const int totface_final = dm_final->getNumTessFaces(dm_final);
+ const int totface_deformed = dm_deformed ? dm_deformed->getNumTessFaces(dm_deformed) : totface_final;
- totface = dm->getNumTessFaces(dm);
- if (!totface) {
+ if (ELEM(0, totface_final, totface_deformed)) {
return DMCACHE_NOTFOUND;
}
- mpoly = dm->getPolyArray(dm);
- osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
+ index_mf_to_mpoly = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
+ index_mp_to_orig = dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ BLI_assert(index_mf_to_mpoly);
+
+ if (dm_deformed) {
+ index_mf_to_mpoly_deformed = dm_deformed->getTessFaceDataArray(dm_deformed, CD_ORIGINDEX);
+ }
+ else {
+ BLI_assert(dm_final->deformedOnly);
+ index_mf_to_mpoly_deformed = index_mf_to_mpoly;
+ }
+ BLI_assert(index_mf_to_mpoly_deformed);
+
+ pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
+
+ if (dm_deformed == NULL) {
+ dm_deformed = dm_final;
+ }
+
+ index_mf_to_mpoly_deformed = NULL;
- if (osface == NULL || index_mf_to_mpoly == NULL) {
- /* Assume we don't need osface data */
- if (index < totface) {
+ mtessface_final = dm_final->getTessFaceArray(dm_final);
+ osface_final = dm_final->getTessFaceDataArray(dm_final, CD_ORIGSPACE);
+
+ if (osface_final == NULL) {
+ /* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
+ if (findex_orig < totface_final) {
//printf("\tNO CD_ORIGSPACE, assuming not needed\n");
- return index;
+ return findex_orig;
}
else {
printf("\tNO CD_ORIGSPACE, error out of range\n");
return DMCACHE_NOTFOUND;
}
}
- else if (index >= me->totpoly)
+ else if (findex_orig >= dm_deformed->getNumTessFaces(dm_deformed)) {
return DMCACHE_NOTFOUND; /* index not in the original mesh */
+ }
psys_w_to_origspace(fw, uv);
- if (node) { /* we have a linked list of faces that we use, faster! */
- for (; node; node = node->next) {
- findex = GET_INT_FROM_POINTER(node->link);
- faceuv = osface[findex].uv;
- quad = (mpoly[findex].totloop == 4);
+ if (poly_nodes) {
+ /* we can have a restricted linked list of faces to check, faster! */
+ LinkNode *tessface_node = poly_nodes[pindex_orig];
+
+ for (; tessface_node; tessface_node = tessface_node->next) {
+ int findex_dst = GET_INT_FROM_POINTER(tessface_node->link);
+ faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
- if (quad) {
- if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3]))
- return findex;
+ if (mtessface_final[findex_dst].v4) {
+ if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
+ return findex_dst;
+ }
+ }
+ else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
+ return findex_dst;
}
- else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2]))
- return findex;
}
}
else { /* if we have no node, try every face */
- for (findex = 0; findex < totface; findex++) {
- const int findex_orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex);
- if (findex_orig == index) {
- faceuv = osface[findex].uv;
- quad = (mpoly[findex].totloop == 4);
+ for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
+ /* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
+ if (DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
+ faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
- if (quad) {
- if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3]))
- return findex;
+ if (mtessface_final[findex_dst].v4) {
+ if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
+ return findex_dst;
+ }
+ }
+ else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
+ return findex_dst;
}
- else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2]))
- return findex;
}
}
}
@@ -1521,7 +1581,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
}
/* interprets particle data to get a point on a mesh in object space */
-void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache,
+void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3])
{
@@ -1529,7 +1589,7 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
float (*orcodata)[3];
int mapindex;
- if (!psys_map_index_on_dm(dm, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
+ if (!psys_map_index_on_dm(dm_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
if (vec) { vec[0] = vec[1] = vec[2] = 0.0; }
if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; }
if (orco) { orco[0] = orco[1] = orco[2] = 0.0; }
@@ -1540,21 +1600,27 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
return;
}
- orcodata = dm->getVertDataArray(dm, CD_ORCO);
+ orcodata = dm_final->getVertDataArray(dm_final, CD_ORCO);
if (from == PART_FROM_VERT) {
- dm->getVertCo(dm, mapindex, vec);
+ dm_final->getVertCo(dm_final, mapindex, vec);
if (nor) {
- dm->getVertNo(dm, mapindex, nor);
+ dm_final->getVertNo(dm_final, mapindex, nor);
normalize_v3(nor);
}
- if (orco)
- copy_v3_v3(orco, orcodata[mapindex]);
+ if (orco) {
+ if (orcodata) {
+ copy_v3_v3(orco, orcodata[mapindex]);
+ }
+ else {
+ copy_v3_v3(orco, vec);
+ }
+ }
if (ornor) {
- dm->getVertNo(dm, mapindex, ornor);
+ dm_final->getVertNo(dm_final, mapindex, ornor);
normalize_v3(ornor);
}
@@ -1568,9 +1634,9 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
MTFace *mtface;
MVert *mvert;
- mface = dm->getTessFaceData(dm, mapindex, CD_MFACE);
- mvert = dm->getVertDataArray(dm, CD_MVERT);
- mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ mface = dm_final->getTessFaceData(dm_final, mapindex, CD_MFACE);
+ mvert = dm_final->getVertDataArray(dm_final, CD_MVERT);
+ mtface = CustomData_get_layer(&dm_final->faceData, CD_MTFACE);
if (mtface)
mtface += mapindex;
@@ -1687,7 +1753,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3])
{
- if (psmd && psmd->dm) {
+ if (psmd && psmd->dm_final) {
if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
if (vec)
copy_v3_v3(vec, fuv);
@@ -1697,7 +1763,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
return;
}
/* we cant use the num_dmcache */
- psys_particle_on_dm(psmd->dm, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_dm(psmd->dm_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
}
else
psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco, ornor);
@@ -1969,7 +2035,7 @@ void psys_find_parents(ParticleSimulationData *sim)
psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
/* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
- get_cpa_texture(sim->psmd->dm, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(sim->psmd->dm_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex.exist >= psys_frand(psys, p + 24)) {
BLI_kdtree_insert(tree, p, orco);
@@ -2052,10 +2118,20 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
/* prepare curvemapping tables */
- if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve)
- curvemapping_changed_all(part->clumpcurve);
- if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve)
- curvemapping_changed_all(part->roughcurve);
+ if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
+ ctx->clumpcurve = curvemapping_copy(part->clumpcurve);
+ curvemapping_changed_all(ctx->clumpcurve);
+ }
+ else {
+ ctx->clumpcurve = NULL;
+ }
+ if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve) {
+ ctx->roughcurve = curvemapping_copy(part->roughcurve);
+ curvemapping_changed_all(ctx->roughcurve);
+ }
+ else {
+ ctx->roughcurve = NULL;
+ }
return true;
}
@@ -2181,7 +2257,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
for (w = 0; w < 4; w++)
sub_v3_v3v3(off1[w], co, key[w]->co);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
}
else {
ParticleData *pa = psys->particles + cpa->parent;
@@ -2200,13 +2276,13 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
cpa_from = part->from;
cpa_num = pa->num;
/* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
- if (cpa_num > ctx->sim.psmd->dm->getNumTessFaces(ctx->sim.psmd->dm))
+ if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final))
cpa_num = 0;
cpa_fuv = pa->fuv;
psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
}
child_keys->segments = ctx->segments;
@@ -2325,7 +2401,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
child_keys->segments = -1;
}
-static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
ParticleTask *task = taskdata;
ParticleThreadContext *ctx = task->ctx;
@@ -2499,15 +2575,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
- vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR);
+ vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR);
if (!psys->totchild)
- vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH);
+ vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH);
}
/* ensure we have tessfaces to be used for mapping */
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(psmd->dm);
+ DM_ensure_tessface(psmd->dm_final);
}
/*---first main loop: create all actual particles' paths---*/
@@ -2516,7 +2592,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
if (vg_length)
- pa_length *= psys_particle_value_from_verts(psmd->dm, part->from, pa, vg_length);
+ pa_length *= psys_particle_value_from_verts(psmd->dm_final, part->from, pa, vg_length);
}
pind.keyed = keyed;
@@ -2533,7 +2609,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
/* hairmat is needed for for non-hair particle too so we get proper rotations */
- psys_mat_hair_to_global(sim->ob, psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, psmd->dm_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2588,7 +2664,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
float effector = 1.0f;
if (vg_effector)
- effector *= psys_particle_value_from_verts(psmd->dm, psys->part->from, pa, vg_effector);
+ effector *= psys_particle_value_from_verts(psmd->dm_final, psys->part->from, pa, vg_effector);
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
@@ -2733,7 +2809,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
init_particle_interpolation(ob, psys, pa, &pind);
if (psys) {
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -3315,8 +3391,8 @@ void BKE_particlesettings_make_local(ParticleSettings *part)
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
if (psys->part == part && ob->id.lib == 0) {
psys->part = part_new;
- part_new->id.us++;
- part->id.us--;
+ id_us_plus(&part_new->id);
+ id_us_min(&part->id);
}
}
}
@@ -3374,6 +3450,11 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
#define CLAMP_PARTICLE_TEXTURE_POS(type, pvalue) \
if (event & type) { \
+ CLAMP(pvalue, 0.0f, 1.0f); \
+ } (void)0
+
+#define CLAMP_WARP_PARTICLE_TEXTURE_POS(type, pvalue) \
+ if (event & type) { \
if (pvalue < 0.0f) \
pvalue = 1.0f + pvalue; \
CLAMP(pvalue, 0.0f, 1.0f); \
@@ -3431,7 +3512,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
if ((event & mtex->mapto) & PAMAP_ROUGH)
ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(def, ptex->rough1, value, mtex->roughfac, blend);
@@ -3445,11 +3526,11 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
}
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
}
void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra)
{
@@ -3489,7 +3570,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (get_particle_uv(sim->psmd->dm, pa, 0, pa->fuv, mtex->uvname, texvec))
+ if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname, texvec))
break;
/* no break, failed to get uv's, so let's try orco's */
case TEXCO_ORCO:
@@ -3514,7 +3595,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
if ((event & mtex->mapto) & PAMAP_TIME) {
/* the first time has to set the base value for time regardless of blend mode */
@@ -3539,14 +3620,14 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
}
}
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_TIME, ptex->time);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LIFE, ptex->life);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_TIME, ptex->time);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_LIFE, ptex->life);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_SIZE, ptex->size);
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_IVEL, ptex->ivel);
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_FIELD, ptex->field);
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
}
/************************************************/
@@ -3689,7 +3770,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
if ((pa->flag & PARS_REKEY) == 0) {
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, part->from, pa, hairmat);
mul_m4_v3(hairmat, state->co);
mul_mat3_m4_v3(hairmat, state->vel);
@@ -3756,7 +3837,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
if (part->type == PART_HAIR)
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
else
unit_m4(hairmat);
@@ -3777,7 +3858,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
if (part->type == PART_HAIR) {
psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
}
else {
copy_v3_v3(orco, cpa->fuv);
@@ -3796,7 +3877,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
/* get different child parameters from textures & vgroups */
memset(&ctx, 0, sizeof(ParticleThreadContext));
ctx.sim = *sim;
- ctx.dm = psmd->dm;
+ ctx.dm = psmd->dm_final;
ctx.ma = ma;
/* TODO: assign vertex groups */
get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
@@ -3832,23 +3913,23 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
copy_particle_key(&tstate, state, 1);
/* apply different deformations to the child path */
- do_child_modifiers(sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t);
+ do_child_modifiers(NULL, sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t);
/* try to estimate correct velocity */
if (vel) {
- ParticleKey tstate;
+ ParticleKey tstate_tmp;
float length = len_v3(state->vel);
if (t >= 0.001f) {
- tstate.time = t - 0.001f;
- psys_get_particle_on_path(sim, p, &tstate, 0);
- sub_v3_v3v3(state->vel, state->co, tstate.co);
+ tstate_tmp.time = t - 0.001f;
+ psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
+ sub_v3_v3v3(state->vel, state->co, tstate_tmp.co);
normalize_v3(state->vel);
}
else {
- tstate.time = t + 0.001f;
- psys_get_particle_on_path(sim, p, &tstate, 0);
- sub_v3_v3v3(state->vel, tstate.co, state->co);
+ tstate_tmp.time = t + 0.001f;
+ psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
+ sub_v3_v3v3(state->vel, tstate_tmp.co, state->co);
normalize_v3(state->vel);
}
@@ -3935,7 +4016,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
CLAMP(t, 0.0f, 1.0f);
unit_m4(mat);
- do_child_modifiers(sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
+ do_child_modifiers(NULL, sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
if (psys->lattice_deform_data)
calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
@@ -4013,13 +4094,24 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
float loc[3];
int num;
+ /* XXX: on checking '(psmd->dm != NULL)'
+ * This is incorrect but needed for metaball evaluation.
+ * Ideally this would be calculated via the depsgraph, however with metaballs,
+ * the entire scenes dupli's are scanned, which also looks into uncalculated data.
+ *
+ * For now just include this workaround as an alternative to crashing,
+ * but longer term metaballs should behave in a more manageable way, see: T46622. */
+
uv[0] = uv[1] = 0.f;
if (cpa) {
- if (part->childtype == PART_CHILD_FACES) {
- mtface = CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
+ if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) {
+ CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
+ mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+
if (mtface) {
- mface = psmd->dm->getTessFaceData(psmd->dm, cpa->num, CD_MFACE);
+ mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
@@ -4032,21 +4124,24 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if (part->from == PART_FROM_FACE) {
- mtface = CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
+ if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL)) {
+ CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
+ mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+
num = pa->num_dmcache;
if (num == DMCACHE_NOTFOUND)
num = pa->num;
- if (num >= psmd->dm->getNumTessFaces(psmd->dm)) {
+ if (num >= psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num = DMCACHE_NOTFOUND;
}
if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- mface = psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE);
+ mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
@@ -4221,7 +4316,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
float hairmat[4][4], imat[4][4];
for (p = 0; p < psys->totpart; p++, pa++) {
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
hkey = pa->hair;
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 7b2e07ea96f..ec5f73f87ce 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -43,7 +43,7 @@ void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3],
short type, short axis, float obmat[4][4], int smooth_start);
float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
-void do_child_modifiers(ParticleSimulationData *sim,
+void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim,
ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
@@ -281,7 +281,7 @@ static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, co
}
/* apply different deformations to the child path */
- do_child_modifiers(&ctx->sim, ptex, par_co, par_vel, par_rot, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, par_time);
+ do_child_modifiers(ctx, &ctx->sim, ptex, par_co, par_vel, par_rot, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, par_time);
}
totlen = 0.0f;
@@ -349,7 +349,7 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
par = (ParticleKey *)iter.parent_key;
/* apply different deformations to the child path */
- do_child_modifiers(&ctx->sim, ptex, par->co, par->vel, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
+ do_child_modifiers(ctx, &ctx->sim, ptex, par->co, par->vel, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
}
}
@@ -664,15 +664,22 @@ static void do_rough_curve(const float loc[3], float mat[4][4], float time, floa
madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
}
-void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
+void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim, ParticleTexture *ptex,
+ const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t)
{
ParticleSettings *part = sim->psys->part;
- CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
- CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
+ CurveMapping *clumpcurve = NULL, *roughcurve = NULL;
int i = cpa - sim->psys->child;
int guided = 0;
+ if (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) {
+ clumpcurve = (ctx != NULL) ? ctx->clumpcurve : part->clumpcurve;
+ }
+ if (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) {
+ roughcurve = (ctx != NULL) ? ctx->roughcurve : part->roughcurve;
+ }
+
float kink_amp = part->kink_amp;
float kink_amp_clump = part->kink_amp_clump;
float kink_freq = part->kink_freq;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 87bc355894d..9185c0964b9 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -79,7 +79,7 @@ static void alloc_child_particles(ParticleSystem *psys, int tot)
}
}
-static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, ParticleSystem *psys)
+static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys)
{
ChildParticle *cpa = NULL;
int i, p;
@@ -106,7 +106,7 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
}
}
/* dmcache must be updated for parent particles if children from faces is used */
- psys_calc_dmcache(ob, finaldm, psys);
+ psys_calc_dmcache(ob, finaldm, deformdm, psys);
}
static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
{
@@ -220,16 +220,18 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
copy_v3_v3(v2, mvert[mface->v2].co);
copy_v3_v3(v3, mvert[mface->v3].co);
- if (isect_axial_line_tri_v3(a, co1, co2, v2, v3, v1, &lambda)) {
+ bool intersects_tri = isect_axial_line_segment_tri_v3(a, co1, co2, v2, v3, v1, &lambda);
+ if (intersects_tri) {
if (from==PART_FROM_FACE)
(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
else /* store number of intersections */
(pa+(int)(lambda*size[a])*a0mul)->hair_index++;
}
- else if (mface->v4) {
+
+ if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) {
copy_v3_v3(v4, mvert[mface->v4].co);
- if (isect_axial_line_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) {
+ if (isect_axial_line_segment_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) {
if (from==PART_FROM_FACE)
(pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
else
@@ -660,7 +662,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
BLI_rng_skip(thread->rng, rng_skip_tot);
}
-static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_distribute_parent(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
ParticleTask *task = taskdata;
ParticleSystem *psys= task->ctx->sim.psys;
@@ -686,7 +688,7 @@ static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int U
}
}
-static void exec_distribute_child(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
ParticleTask *task = taskdata;
ParticleSystem *psys = task->ctx->sim.psys;
@@ -763,7 +765,7 @@ static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from)
{
Scene *scene = sim->scene;
- DerivedMesh *finaldm = sim->psmd->dm;
+ DerivedMesh *finaldm = sim->psmd->dm_final;
Object *ob = sim->ob;
ParticleSystem *psys= sim->psys;
ParticleData *pa=0, *tpars= 0;
@@ -793,6 +795,11 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
return 0;
}
+ /* XXX This distribution code is totally broken in case from == PART_FROM_CHILD, it's always using finaldm
+ * even if use_modifier_stack is unset... But making things consistent here break all existing edited
+ * hair systems, so better wait for complete rewrite.
+ */
+
psys_thread_context_init(ctx, sim);
/* First handle special cases */
@@ -800,7 +807,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* Simple children */
if (part->childtype != PART_CHILD_FACES) {
BLI_srandom(31415926 + psys->seed + psys->child_seed);
- distribute_simple_children(scene, ob, finaldm, psys);
+ distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys);
return 0;
}
}
@@ -808,10 +815,21 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* Grid distribution */
if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
BLI_srandom(31415926 + psys->seed);
- dm= CDDM_from_mesh((Mesh*)ob->data);
+
+ if (psys->part->use_modifier_stack) {
+ dm = finaldm;
+ }
+ else {
+ dm = CDDM_from_mesh((Mesh*)ob->data);
+ }
DM_ensure_tessface(dm);
+
distribute_grid(dm,psys);
- dm->release(dm);
+
+ if (dm != finaldm) {
+ dm->release(dm);
+ }
+
return 0;
}
}
@@ -897,7 +915,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
element_weight = MEM_callocN(sizeof(float)*totelem, "particle_distribution_weights");
particle_element= MEM_callocN(sizeof(int)*totpart, "particle_distribution_indexes");
- element_sum = MEM_callocN(sizeof(float)*(totelem+1), "particle_distribution_sum");
+ element_sum = MEM_mallocN(sizeof(*element_sum) * totelem, "particle_distribution_sum");
jitter_offset = MEM_callocN(sizeof(float)*totelem, "particle_distribution_jitoff");
/* Calculate weights from face areas */
@@ -992,9 +1010,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
/* Calculate cumulative weights */
- element_sum[0] = 0.0f;
- for (i=0; i<totelem; i++)
- element_sum[i+1] = element_sum[i] + element_weight[i] * inv_totweight;
+ element_sum[0] = element_weight[0] * inv_totweight;
+ for (i = 1; i < totelem; i++) {
+ element_sum[i] = element_sum[i - 1] + element_weight[i] * inv_totweight;
+ }
/* Finally assign elements to particles */
if ((part->flag&PART_TRAND) || (part->simplify_flag&PART_SIMPLIFY_ENABLE)) {
@@ -1002,7 +1021,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
for (p=0; p<totpart; p++) {
/* In theory element_sum[totelem] should be 1.0, but due to float errors this is not necessarily always true, so scale pos accordingly. */
- pos= BLI_frand() * element_sum[totelem];
+ pos= BLI_frand() * element_sum[totelem - 1];
particle_element[p] = distribute_binary_search(element_sum, totelem, pos);
particle_element[p] = MIN2(totelem-1, particle_element[p]);
jitter_offset[particle_element[p]] = pos;
@@ -1011,22 +1030,34 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
else {
double step, pos;
- step= (totpart < 2) ? 0.5 : 1.0/(double)totpart;
- pos= 1e-6; /* tiny offset to avoid zero weight face */
- i= 0;
+ step = (totpart < 2) ? 0.5 : 1.0 / (double)totpart;
+ /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
+ * distribution (see T47983 and its two example files). It allows us to consider pos as
+ * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
+ * and avoid stumbling over float imprecisions in element_sum. */
+ if (from == PART_FROM_VERT) {
+ pos = (totpart < totelem) ? 0.5 / (double)totelem : step * 0.5; /* We choose the smaller step. */
+ }
+ else {
+ pos = 0.0;
+ }
- for (p=0; p<totpart; p++, pos+=step) {
- while ((i < totelem) && (pos > (double)element_sum[i + 1]))
- i++;
+ /* Avoid initial zero-weight items. */
+ for (i = 0; (element_sum[i] == 0.0) && (i < totelem - 1); i++);
- particle_element[p] = MIN2(totelem-1, i);
+ for (p = 0; p < totpart; p++, pos += step) {
+ for ( ; (pos > (double)element_sum[i]) && (i < totelem - 1); i++);
- /* avoid zero weight face */
- if (p == totpart-1 && element_weight[particle_element[p]] == 0.0f)
- particle_element[p] = particle_element[p-1];
+ particle_element[p] = i;
jitter_offset[particle_element[p]] = pos;
}
+
+ /* Avoid final zero weight items. */
+ BLI_assert(p == totpart);
+ if (element_weight[particle_element[--p]] == 0.0f) {
+ particle_element[p] = particle_element[p - 1];
+ }
}
MEM_freeN(element_sum);
@@ -1110,7 +1141,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks;
- DerivedMesh *finaldm = sim->psmd->dm;
+ DerivedMesh *finaldm = sim->psmd->dm_final;
int i, totpart, numtasks;
/* create a task pool for distribution tasks */
@@ -1135,7 +1166,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
BLI_task_pool_free(task_pool);
- psys_calc_dmcache(sim->ob, finaldm, sim->psys);
+ psys_calc_dmcache(sim->ob, finaldm, sim->psmd->dm_deformed, sim->psys);
if (ctx.dm != finaldm)
ctx.dm->release(ctx.dm);
@@ -1159,7 +1190,7 @@ void distribute_particles(ParticleSimulationData *sim, int from)
int distr_error=0;
if (psmd) {
- if (psmd->dm)
+ if (psmd->dm_final)
distribute_particles_on_dm(sim, from);
else
distr_error=1;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index a3e61bb3681..a859de40910 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -40,10 +40,6 @@
#include <math.h>
#include <string.h>
-#ifdef _OPENMP
-#include <omp.h>
-#endif
-
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
@@ -76,7 +72,9 @@
#include "BKE_boids.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
+#include "BKE_colortools.h"
#include "BKE_effect.h"
+#include "BKE_library_query.h"
#include "BKE_particle.h"
#include "BKE_global.h"
@@ -310,7 +308,7 @@ int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
/* Distribution */
/************************************************/
-void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
+void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deformed, ParticleSystem *psys)
{
/* use for building derived mesh mapping info:
*
@@ -323,13 +321,13 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
PARTICLE_P;
/* CACHE LOCATIONS */
- if (!dm->deformedOnly) {
+ if (!dm_final->deformedOnly) {
/* Will use later to speed up subsurf/derivedmesh */
LinkNode *node, *nodedmelem, **nodearray;
int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
if (psys->part->from == PART_FROM_VERT) {
- totdmelem= dm->getNumVerts(dm);
+ totdmelem= dm_final->getNumVerts(dm_final);
if (use_modifier_stack) {
totelem= totdmelem;
@@ -337,11 +335,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
}
else {
totelem= me->totvert;
- origindex= dm->getVertDataArray(dm, CD_ORIGINDEX);
+ origindex= dm_final->getVertDataArray(dm_final, CD_ORIGINDEX);
}
}
else { /* FROM_FACE/FROM_VOLUME */
- totdmelem= dm->getNumTessFaces(dm);
+ totdmelem= dm_final->getNumTessFaces(dm_final);
if (use_modifier_stack) {
totelem= totdmelem;
@@ -349,20 +347,20 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
origindex_poly= NULL;
}
else {
- totelem= me->totpoly;
- origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ totelem = dm_deformed->getNumTessFaces(dm_deformed);
+ origindex = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
/* for face lookups we need the poly origindex too */
- origindex_poly= dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ origindex_poly= dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
if (origindex_poly == NULL) {
origindex= NULL;
}
}
}
-
+
nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems");
nodearray= MEM_callocN(sizeof(LinkNode *)*totelem, "psys node array");
-
+
for (i=0, node=nodedmelem; i<totdmelem; i++, node++) {
int origindex_final;
node->link = SET_INT_IN_POINTER(i);
@@ -391,7 +389,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
}
}
}
-
+
/* cache the verts/faces! */
LOOP_PARTICLES {
if (pa->num < 0) {
@@ -413,9 +411,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
pa->num_dmcache = DMCACHE_NOTFOUND;
}
else { /* FROM_FACE/FROM_VOLUME */
- /* Note that sometimes the pa->num is over the nodearray size, this is bad, maybe there is a better place to fix this,
- * but for now passing NULL is OK. every face will be searched for the particle so its slower - Campbell */
- pa->num_dmcache= psys_particle_dm_face_lookup(ob, dm, pa->num, pa->fuv, pa->num < totelem ? nodearray[pa->num] : NULL);
+ pa->num_dmcache = psys_particle_dm_face_lookup(dm_final, dm_deformed, pa->num, pa->fuv, nodearray);
}
}
}
@@ -428,8 +424,9 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
* should know to use the num or num_dmcache, set the num_dmcache to
* an invalid value, just in case */
- LOOP_PARTICLES
+ LOOP_PARTICLES {
pa->num_dmcache = DMCACHE_NOTFOUND;
+ }
}
}
@@ -438,7 +435,7 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData
{
memset(ctx, 0, sizeof(ParticleThreadContext));
ctx->sim = *sim;
- ctx->dm = ctx->sim.psmd->dm;
+ ctx->dm = ctx->sim.psmd->dm_final;
ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
}
@@ -515,6 +512,13 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
if (ctx->seams) MEM_freeN(ctx->seams);
//if (ctx->vertpart) MEM_freeN(ctx->vertpart);
BLI_kdtree_free(ctx->tree);
+
+ if (ctx->clumpcurve != NULL) {
+ curvemapping_free(ctx->clumpcurve);
+ }
+ if (ctx->roughcurve != NULL) {
+ curvemapping_free(ctx->roughcurve);
+ }
}
static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p)
@@ -893,7 +897,7 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
float q_imat[4];
mat4_to_quat(q_obmat, ob->obmat);
- invert_qt_qt(q_imat, q_obmat);
+ invert_qt_qt_normalized(q_imat, q_obmat);
if (part->rotmode != PART_ROT_NOR_TAN) {
@@ -1214,8 +1218,8 @@ void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra
{
ParticleSettings *part = psys->part;
- *sfra = MAX2(1, (int)part->sta);
- *efra = MIN2((int)(part->end + part->lifetime + 1.0f), MAX2(scene->r.pefra, scene->r.efra));
+ *sfra = max_ii(1, (int)part->sta);
+ *efra = min_ii((int)(part->end + part->lifetime + 1.0f), max_ii(scene->r.pefra, scene->r.efra));
}
/************************************************/
@@ -1580,13 +1584,15 @@ static void sph_evaluate_func(BVHTree *tree, ParticleSystem **psys, float co[3],
}
}
}
-static void sph_density_accum_cb(void *userdata, int index, float squared_dist)
+static void sph_density_accum_cb(void *userdata, int index, const float co[3], float squared_dist)
{
SPHRangeData *pfr = (SPHRangeData *)userdata;
ParticleData *npa = pfr->npsys->particles + index;
float q;
float dist;
+ UNUSED_VARS(co);
+
if (npa == pfr->pa || squared_dist < FLT_EPSILON)
return;
@@ -1745,7 +1751,6 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa
temp_spring.delete_flag = 0;
/* sph_spring_add is not thread-safe. - z0r */
-#pragma omp critical
sph_spring_add(psys[0], &temp_spring);
}
}
@@ -1764,7 +1769,7 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa
sphdata->pass++;
}
-static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSED(squared_dist))
+static void sphclassical_density_accum_cb(void *userdata, int index, const float co[3], float UNUSED(squared_dist))
{
SPHRangeData *pfr = (SPHRangeData *)userdata;
ParticleData *npa = pfr->npsys->particles + index;
@@ -1776,7 +1781,7 @@ static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSE
/* Exclude particles that are more than 2h away. Can't use squared_dist here
* because it is not accurate enough. Use current state, i.e. the output of
* basic_integrate() - z0r */
- sub_v3_v3v3(vec, npa->state.co, pfr->pa->state.co);
+ sub_v3_v3v3(vec, npa->state.co, co);
rij = len_v3(vec);
rij_h = rij / pfr->h;
if (rij_h > 2.0f)
@@ -1795,7 +1800,7 @@ static void sphclassical_density_accum_cb(void *userdata, int index, float UNUSE
pfr->data[1] += q / npa->sphdensity;
}
-static void sphclassical_neighbour_accum_cb(void *userdata, int index, float UNUSED(squared_dist))
+static void sphclassical_neighbour_accum_cb(void *userdata, int index, const float co[3], float UNUSED(squared_dist))
{
SPHRangeData *pfr = (SPHRangeData *)userdata;
ParticleData *npa = pfr->npsys->particles + index;
@@ -1808,7 +1813,7 @@ static void sphclassical_neighbour_accum_cb(void *userdata, int index, float UNU
/* Exclude particles that are more than 2h away. Can't use squared_dist here
* because it is not accurate enough. Use current state, i.e. the output of
* basic_integrate() - z0r */
- sub_v3_v3v3(vec, npa->state.co, pfr->pa->state.co);
+ sub_v3_v3v3(vec, npa->state.co, co);
rij = len_v3(vec);
rij_h = rij / pfr->h;
if (rij_h > 2.0f)
@@ -1938,7 +1943,7 @@ static void sphclassical_calc_dens(ParticleData *pa, float UNUSED(dfra), SPHData
pfr.mass = sphdata->mass;
sph_evaluate_func( NULL, psys, pa->state.co, &pfr, interaction_radius, sphclassical_density_accum_cb);
- pa->sphdensity = MIN2(MAX2(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f);
+ pa->sphdensity = min_ff(max_ff(data[0], fluid->rest_density * 0.9f), fluid->rest_density * 1.1f);
}
void psys_sph_init(ParticleSimulationData *sim, SPHData *sphdata)
@@ -3053,7 +3058,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
pa->hair_index = hair_index;
use_hair = psys_hair_use_simulation(pa, max_length);
- psys_mat_hair_to_object(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
normalize_m4(root_mat);
@@ -3208,7 +3213,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
if (psys->recalc & PSYS_RECALC_RESET) {
/* need this for changing subsurf levels */
- psys_calc_dmcache(sim->ob, sim->psmd->dm, psys);
+ psys_calc_dmcache(sim->ob, sim->psmd->dm_final, sim->psmd->dm_deformed, psys);
if (psys->clmd)
cloth_free_modifier(psys->clmd);
@@ -3255,7 +3260,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
if (pa->totkey) {
sub_v3_v3(key->co, root->co);
- psys_vec_rot_to_face(sim->psmd->dm, pa, key->co);
+ psys_vec_rot_to_face(sim->psmd->dm_final, pa, key->co);
}
key->time = pa->state.time;
@@ -3286,15 +3291,20 @@ static const float TIMESTEP_EXPANSION_TOLERANCE = 1.5f;
* step, after the velocity has been updated. element_size defines the scale of
* the simulation, and is typically the distance to neighboring particles. */
static void update_courant_num(ParticleSimulationData *sim, ParticleData *pa,
- float dtime, SPHData *sphdata)
+ float dtime, SPHData *sphdata, SpinLock *spin)
{
float relative_vel[3];
- float speed;
sub_v3_v3v3(relative_vel, pa->prev_state.vel, sphdata->flow);
- speed = len_v3(relative_vel);
- if (sim->courant_num < speed * dtime / sphdata->element_size)
- sim->courant_num = speed * dtime / sphdata->element_size;
+
+ const float courant_num = len_v3(relative_vel) * dtime / sphdata->element_size;
+ if (sim->courant_num < courant_num) {
+ BLI_spin_lock(spin);
+ if (sim->courant_num < courant_num) {
+ sim->courant_num = courant_num;
+ }
+ BLI_spin_unlock(spin);
+ }
}
static float get_base_time_step(ParticleSettings *part)
{
@@ -3334,6 +3344,116 @@ static float update_timestep(ParticleSystem *psys, ParticleSimulationData *sim,
/************************************************/
/* System Core */
/************************************************/
+
+typedef struct DynamicStepSolverTaskData {
+ ParticleSimulationData *sim;
+
+ float cfra;
+ float timestep;
+ float dtime;
+
+ SpinLock spin;
+} DynamicStepSolverTaskData;
+
+static void dynamics_step_sph_ddr_task_cb_ex(
+ void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id))
+{
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+
+ SPHData *sphdata = userdata_chunk;
+
+ ParticleData *pa;
+
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
+
+ /* do global forces & effectors */
+ basic_integrate(sim, p, pa->state.time, data->cfra);
+
+ /* actual fluids calculations */
+ sph_integrate(sim, pa, pa->state.time, sphdata);
+
+ if (sim->colliders)
+ collision_check(sim, p, pa->state.time, data->cfra);
+
+ /* SPH particles are not physical particles, just interpolation
+ * particles, thus rotation has not a direct sense for them */
+ basic_rotate(part, pa, pa->state.time, data->timestep);
+
+ if (part->time_flag & PART_TIME_AUTOSF) {
+ update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
+ }
+}
+
+static void dynamics_step_sph_classical_basic_integrate_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int p, const int UNUSED(thread_id))
+{
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
+
+ ParticleData *pa;
+
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
+
+ basic_integrate(sim, p, pa->state.time, data->cfra);
+}
+
+static void dynamics_step_sph_classical_calc_density_task_cb_ex(
+ void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id))
+{
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
+
+ SPHData *sphdata = userdata_chunk;
+
+ ParticleData *pa;
+
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
+
+ sphclassical_calc_dens(pa, pa->state.time, sphdata);
+}
+
+static void dynamics_step_sph_classical_integrate_task_cb_ex(
+ void *userdata, void *userdata_chunk, const int p, const int UNUSED(thread_id))
+{
+ DynamicStepSolverTaskData *data = userdata;
+ ParticleSimulationData *sim = data->sim;
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+
+ SPHData *sphdata = userdata_chunk;
+
+ ParticleData *pa;
+
+ if ((pa = psys->particles + p)->state.time <= 0.0f) {
+ return;
+ }
+
+ /* actual fluids calculations */
+ sph_integrate(sim, pa, pa->state.time, sphdata);
+
+ if (sim->colliders)
+ collision_check(sim, p, pa->state.time, data->cfra);
+
+ /* SPH particles are not physical particles, just interpolation
+ * particles, thus rotation has not a direct sense for them */
+ basic_rotate(part, pa, pa->state.time, data->timestep);
+
+ if (part->time_flag & PART_TIME_AUTOSF) {
+ update_courant_num(sim, pa, data->dtime, sphdata, &data->spin);
+ }
+}
+
/* unbaked particles are calculated dynamically */
static void dynamics_step(ParticleSimulationData *sim, float cfra)
{
@@ -3392,8 +3512,10 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
boids_precalc_rules(part, cfra);
for (; pt; pt=pt->next) {
- if (pt->ob)
- psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
+ ParticleSystem *psys_target = psys_get_target_system(sim->ob, pt);
+ if (psys_target && psys_target != psys) {
+ psys_update_particle_tree(psys_target, cfra);
+ }
}
break;
}
@@ -3488,34 +3610,23 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
case PART_PHYS_FLUID:
{
SPHData sphdata;
- ParticleSettings *part = sim->psys->part;
psys_sph_init(sim, &sphdata);
+ DynamicStepSolverTaskData task_data = {
+ .sim = sim, .cfra = cfra, .timestep = timestep, .dtime = dtime,
+ };
+
+ BLI_spin_init(&task_data.spin);
+
if (part->fluid->solver == SPH_SOLVER_DDR) {
/* Apply SPH forces using double-density relaxation algorithm
* (Clavat et. al.) */
-#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5)
- LOOP_DYNAMIC_PARTICLES {
- /* do global forces & effectors */
- basic_integrate(sim, p, pa->state.time, cfra);
- /* actual fluids calculations */
- sph_integrate(sim, pa, pa->state.time, &sphdata);
-
- if (sim->colliders)
- collision_check(sim, p, pa->state.time, cfra);
-
- /* SPH particles are not physical particles, just interpolation
- * particles, thus rotation has not a direct sense for them */
- basic_rotate(part, pa, pa->state.time, timestep);
-
-#pragma omp critical
- if (part->time_flag & PART_TIME_AUTOSF)
- update_courant_num(sim, pa, dtime, &sphdata);
- }
+ BLI_task_parallel_range_ex(
+ 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata),
+ dynamics_step_sph_ddr_task_cb_ex, psys->totpart > 100, true);
sph_springs_modify(psys, timestep);
-
}
else {
/* SPH_SOLVER_CLASSICAL */
@@ -3523,36 +3634,25 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
* and Monaghan). Note that, unlike double-density relaxation,
* this algorithm is separated into distinct loops. */
-#pragma omp parallel for private (pa) schedule(dynamic,5)
- LOOP_DYNAMIC_PARTICLES {
- basic_integrate(sim, p, pa->state.time, cfra);
- }
+ BLI_task_parallel_range_ex(
+ 0, psys->totpart, &task_data, NULL, 0,
+ dynamics_step_sph_classical_basic_integrate_task_cb_ex, psys->totpart > 100, true);
/* calculate summation density */
-#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5)
- LOOP_DYNAMIC_PARTICLES {
- sphclassical_calc_dens(pa, pa->state.time, &sphdata);
- }
+ /* Note that we could avoid copying sphdata for each thread here (it's only read here),
+ * but doubt this would gain us anything except confusion... */
+ BLI_task_parallel_range_ex(
+ 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata),
+ dynamics_step_sph_classical_calc_density_task_cb_ex, psys->totpart > 100, true);
/* do global forces & effectors */
-#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5)
- LOOP_DYNAMIC_PARTICLES {
- /* actual fluids calculations */
- sph_integrate(sim, pa, pa->state.time, &sphdata);
-
- if (sim->colliders)
- collision_check(sim, p, pa->state.time, cfra);
-
- /* SPH particles are not physical particles, just interpolation
- * particles, thus rotation has not a direct sense for them */
- basic_rotate(part, pa, pa->state.time, timestep);
-
-#pragma omp critical
- if (part->time_flag & PART_TIME_AUTOSF)
- update_courant_num(sim, pa, dtime, &sphdata);
- }
+ BLI_task_parallel_range_ex(
+ 0, psys->totpart, &task_data, &sphdata, sizeof(sphdata),
+ dynamics_step_sph_classical_integrate_task_cb_ex, psys->totpart > 100, true);
}
+ BLI_spin_end(&task_data.spin);
+
psys_sph_finalise(&sphdata);
break;
}
@@ -3780,8 +3880,8 @@ static void system_step(ParticleSimulationData *sim, float cfra)
BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL);
- /* clear everythin on start frame */
- if (cfra == startframe) {
+ /* clear everything on start frame, or when psys needs full reset! */
+ if ((cfra == startframe) || (psys->recalc & PSYS_RECALC_RESET)) {
BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED);
BKE_ptcache_validate(cache, startframe);
cache->flag &= ~PTCACHE_REDO_NEEDED;
@@ -4064,11 +4164,11 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
return;
}
- if (!sim.psmd->dm)
+ if (!sim.psmd->dm_final)
return;
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(sim.psmd->dm);
+ DM_ensure_tessface(sim.psmd->dm_final);
}
/* execute drivers only, as animation has already been done */
@@ -4209,6 +4309,30 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
invert_m4_m4(psys->imat, ob->obmat);
}
+/* ID looper */
+
+void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void *userdata)
+{
+ ParticleTarget *pt;
+
+ func(psys, (ID **)&psys->part, userdata, IDWALK_USER | IDWALK_NEVER_NULL);
+ func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP);
+ func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP);
+
+ for (pt = psys->targets.first; pt; pt = pt->next) {
+ func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP);
+ }
+
+ if (psys->part->phystype == PART_PHYS_BOIDS) {
+ ParticleData *pa;
+ int p;
+
+ for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) {
+ func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP);
+ }
+ }
+}
+
/* **** Depsgraph evaluation **** */
void BKE_particle_system_eval(EvaluationContext *UNUSED(eval_ctx),
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 311e928c348..330b5922c9a 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -30,6 +30,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLI_task.h"
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
@@ -42,6 +43,8 @@
#include "bmesh.h"
+#include "atomic_ops.h"
+
#include "pbvh_intern.h"
#include <limits.h>
@@ -52,18 +55,11 @@
#define STACK_FIXED_DEPTH 100
-/* Setting zero so we can catch bugs in OpenMP/PBVH. */
-#ifdef _OPENMP
-# ifdef DEBUG
-# define PBVH_OMP_LIMIT 0
-# else
-# define PBVH_OMP_LIMIT 8
-# endif
-#endif
+#define PBVH_THREADED_LIMIT 4
typedef struct PBVHStack {
PBVHNode *node;
- int revisiting;
+ bool revisiting;
} PBVHStack;
typedef struct PBVHIter {
@@ -87,8 +83,7 @@ void BB_reset(BB *bb)
/* Expand the bounding box to include a new coordinate */
void BB_expand(BB *bb, const float co[3])
{
- int i;
- for (i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; ++i) {
bb->bmin[i] = min_ff(bb->bmin[i], co[i]);
bb->bmax[i] = max_ff(bb->bmax[i], co[i]);
}
@@ -97,8 +92,7 @@ void BB_expand(BB *bb, const float co[3])
/* Expand the bounding box to include another bounding box */
void BB_expand_with_bb(BB *bb, BB *bb2)
{
- int i;
- for (i = 0; i < 3; ++i) {
+ for (int i = 0; i < 3; ++i) {
bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]);
bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]);
}
@@ -108,9 +102,8 @@ void BB_expand_with_bb(BB *bb, BB *bb2)
int BB_widest_axis(const BB *bb)
{
float dim[3];
- int i;
- for (i = 0; i < 3; ++i)
+ for (int i = 0; i < 3; ++i)
dim[i] = bb->bmax[i] - bb->bmin[i];
if (dim[0] > dim[1]) {
@@ -129,8 +122,7 @@ int BB_widest_axis(const BB *bb)
void BBC_update_centroid(BBC *bbc)
{
- int i;
- for (i = 0; i < 3; ++i)
+ for (int i = 0; i < 3; ++i)
bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f;
}
@@ -170,13 +162,13 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node)
// BB_expand(&node->vb, co);
//}
-static int face_materials_match(const MPoly *f1, const MPoly *f2)
+static bool face_materials_match(const MPoly *f1, const MPoly *f2)
{
return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) &&
(f1->mat_nr == f2->mat_nr));
}
-static int grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2)
+static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2)
{
return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) &&
(f1->mat_nr == f2->mat_nr));
@@ -254,22 +246,19 @@ static int map_insert_vert(PBVH *bvh, GHash *map,
void *key, **value_p;
key = SET_INT_IN_POINTER(vertex);
- value_p = BLI_ghash_lookup_p(map, key);
-
- if (value_p == NULL) {
- void *value;
- if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex)) {
- value = SET_INT_IN_POINTER(~(*face_verts));
- ++(*face_verts);
+ if (!BLI_ghash_ensure_p(map, key, &value_p)) {
+ int value_i;
+ if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex) == 0) {
+ BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
+ value_i = *uniq_verts;
+ (*uniq_verts)++;
}
else {
- BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
- value = SET_INT_IN_POINTER(*uniq_verts);
- ++(*uniq_verts);
+ value_i = ~(*face_verts);
+ (*face_verts)++;
}
-
- BLI_ghash_insert(map, key, value);
- return GET_INT_FROM_POINTER(value);
+ *value_p = SET_INT_IN_POINTER(value_i);
+ return value_i;
}
else {
return GET_INT_FROM_POINTER(*value_p);
@@ -279,29 +268,24 @@ static int map_insert_vert(PBVH *bvh, GHash *map,
/* Find vertices used by the faces in this node and update the draw buffers */
static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
{
- GHashIterator gh_iter;
- GHash *map;
- int i, j, totface;
bool has_visible = false;
- int (*face_vert_indices)[4];
- int *vert_indices;
node->uniq_verts = node->face_verts = 0;
- totface = node->totprim;
+ const int totface = node->totprim;
/* reserve size is rough guess */
- map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface);
+ GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface);
- face_vert_indices = MEM_callocN(sizeof(int[4]) * totface,
- "bvh node face vert indices");
+ int (*face_vert_indices)[4] = MEM_callocN(sizeof(int[4]) * totface,
+ "bvh node face vert indices");
node->face_vert_indices = (const int (*)[4])face_vert_indices;
- for (i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; ++i) {
const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]];
const int sides = 3;
- for (j = 0; j < sides; ++j) {
+ for (int j = 0; j < sides; ++j) {
face_vert_indices[i][j] =
map_insert_vert(bvh, map, &node->face_verts,
&node->uniq_verts, bvh->mloop[lt->tri[j]].v);
@@ -312,12 +296,12 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
}
}
- vert_indices = MEM_callocN(sizeof(int) *
- (node->uniq_verts + node->face_verts),
- "bvh node vert indices");
+ int *vert_indices = MEM_callocN(sizeof(int) * (node->uniq_verts + node->face_verts),
+ "bvh node vert indices");
node->vert_indices = vert_indices;
/* Build the vertex list, unique verts first */
+ GHashIterator gh_iter;
GHASH_ITER (gh_iter, map) {
void *value = BLI_ghashIterator_getValue(&gh_iter);
int ndx = GET_INT_FROM_POINTER(value);
@@ -329,10 +313,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
}
- for (i = 0; i < totface; ++i) {
+ for (int i = 0; i < totface; ++i) {
const int sides = 3;
- for (j = 0; j < sides; ++j) {
+ for (int j = 0; j < sides; ++j) {
if (face_vert_indices[i][j] < 0)
face_vert_indices[i][j] =
-face_vert_indices[i][j] +
@@ -350,10 +334,8 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc,
int offset, int count)
{
- int i;
-
BB_reset(&node->vb);
- for (i = offset + count - 1; i >= offset; --i) {
+ for (int i = offset + count - 1; i >= offset; --i) {
BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]]));
}
node->orig_vb = node->vb;
@@ -364,19 +346,19 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
int *grid_indices, int totgrid,
int gridsize)
{
- int gridarea = (gridsize - 1) * (gridsize - 1);
- int i, x, y, totquad;
+ const int gridarea = (gridsize - 1) * (gridsize - 1);
+ int totquad = 0;
/* grid hidden layer is present, so have to check each grid for
* visibility */
- for (i = 0, totquad = 0; i < totgrid; i++) {
+ for (int i = 0; i < totgrid; i++) {
const BLI_bitmap *gh = grid_hidden[grid_indices[i]];
if (gh) {
/* grid hidden are present, have to check each element */
- for (y = 0; y < gridsize - 1; y++) {
- for (x = 0; x < gridsize - 1; x++) {
+ for (int y = 0; y < gridsize - 1; y++) {
+ for (int x = 0; x < gridsize - 1; x++) {
if (!paint_is_grid_face_hidden(gh, gridsize, x, y))
totquad++;
}
@@ -418,36 +400,34 @@ static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc,
/* Return zero if all primitives in the node can be drawn with the
* same material (including flat/smooth shading), non-zero otherwise */
-static int leaf_needs_material_split(PBVH *bvh, int offset, int count)
+static bool leaf_needs_material_split(PBVH *bvh, int offset, int count)
{
- int i;
-
if (count <= 1)
- return 0;
+ return false;
if (bvh->looptri) {
const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]];
const MPoly *mp = &bvh->mpoly[first->poly];
- for (i = offset + count - 1; i > offset; --i) {
+ for (int i = offset + count - 1; i > offset; --i) {
int prim = bvh->prim_indices[i];
const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly];
if (!face_materials_match(mp, mp_other)) {
- return 1;
+ return true;
}
}
}
else {
const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]];
- for (i = offset + count - 1; i > offset; --i) {
+ for (int i = offset + count - 1; i > offset; --i) {
int prim = bvh->prim_indices[i];
if (!grid_materials_match(first, &bvh->grid_flag_mats[prim]))
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
@@ -465,11 +445,11 @@ static int leaf_needs_material_split(PBVH *bvh, int offset, int count)
static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
int offset, int count)
{
- int i, axis, end, below_leaf_limit;
+ int end;
BB cb_backing;
/* Decide whether this is a leaf or not */
- below_leaf_limit = count <= bvh->leaf_limit;
+ const bool below_leaf_limit = count <= bvh->leaf_limit;
if (below_leaf_limit) {
if (!leaf_needs_material_split(bvh, offset, count)) {
build_leaf(bvh, node_index, prim_bbc, offset, count);
@@ -489,10 +469,10 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
if (!cb) {
cb = &cb_backing;
BB_reset(cb);
- for (i = offset + count - 1; i >= offset; --i)
+ for (int i = offset + count - 1; i >= offset; --i)
BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid);
}
- axis = BB_widest_axis(cb);
+ const int axis = BB_widest_axis(cb);
/* Partition primitives along that axis */
end = partition_indices(bvh->prim_indices,
@@ -515,15 +495,13 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
{
- int i;
-
if (totprim != bvh->totprim) {
bvh->totprim = totprim;
if (bvh->nodes) MEM_freeN(bvh->nodes);
if (bvh->prim_indices) MEM_freeN(bvh->prim_indices);
- bvh->prim_indices = MEM_callocN(sizeof(int) * totprim,
+ bvh->prim_indices = MEM_mallocN(sizeof(int) * totprim,
"bvh prim indices");
- for (i = 0; i < totprim; ++i)
+ for (int i = 0; i < totprim; ++i)
bvh->prim_indices[i] = i;
bvh->totnode = 0;
if (bvh->node_mem_count < 100) {
@@ -538,7 +516,12 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
}
-/* Do a full rebuild with on Mesh data structure */
+/**
+ * Do a full rebuild with on Mesh data structure.
+ *
+ * \note Unlike mpoly/mloop/verts, looptri is **totally owned** by PBVH (which means it may rewrite it if needed,
+ * see BKE_pbvh_apply_vertCos().
+ */
void BKE_pbvh_build_mesh(
PBVH *bvh, const MPoly *mpoly, const MLoop *mloop, MVert *verts,
int totvert, struct CustomData *vdata,
@@ -546,7 +529,6 @@ void BKE_pbvh_build_mesh(
{
BBC *prim_bbc = NULL;
BB cb;
- int i, j;
bvh->type = PBVH_FACES;
bvh->mpoly = mpoly;
@@ -563,14 +545,14 @@ void BKE_pbvh_build_mesh(
/* For each face, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc");
- for (i = 0; i < looptri_num; ++i) {
+ for (int i = 0; i < looptri_num; ++i) {
const MLoopTri *lt = &looptri[i];
const int sides = 3;
BBC *bbc = prim_bbc + i;
BB_reset((BB *)bbc);
- for (j = 0; j < sides; ++j)
+ for (int j = 0; j < sides; ++j)
BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co);
BBC_update_centroid(bbc);
@@ -589,10 +571,7 @@ void BKE_pbvh_build_mesh(
void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
- BBC *prim_bbc = NULL;
- BB cb;
- int gridsize = key->grid_size;
- int i, j;
+ const int gridsize = key->grid_size;
bvh->type = PBVH_GRIDS;
bvh->grids = grids;
@@ -603,18 +582,19 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids,
bvh->grid_hidden = grid_hidden;
bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1);
+ BB cb;
BB_reset(&cb);
/* For each grid, store the AABB and the AABB centroid */
- prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
+ BBC *prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
- for (i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; ++i) {
CCGElem *grid = grids[i];
BBC *bbc = prim_bbc + i;
BB_reset((BB *)bbc);
- for (j = 0; j < gridsize * gridsize; ++j)
+ for (int j = 0; j < gridsize * gridsize; ++j)
BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j));
BBC_update_centroid(bbc);
@@ -637,11 +617,8 @@ PBVH *BKE_pbvh_new(void)
void BKE_pbvh_free(PBVH *bvh)
{
- PBVHNode *node;
- int i;
-
- for (i = 0; i < bvh->totnode; ++i) {
- node = &bvh->nodes[i];
+ for (int i = 0; i < bvh->totnode; ++i) {
+ PBVHNode *node = &bvh->nodes[i];
if (node->flag & PBVH_Leaf) {
if (node->draw_buffers)
@@ -684,8 +661,7 @@ void BKE_pbvh_free(PBVH *bvh)
void BKE_pbvh_free_layer_disp(PBVH *bvh)
{
- int i;
- for (i = 0; i < bvh->totnode; ++i)
+ for (int i = 0; i < bvh->totnode; ++i)
BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]);
}
@@ -699,7 +675,7 @@ static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BKE_pbvh_SearchCallback s
iter->stackspace = STACK_FIXED_DEPTH;
iter->stack[0].node = bvh->nodes;
- iter->stack[0].revisiting = 0;
+ iter->stack[0].revisiting = false;
iter->stacksize = 1;
}
@@ -709,7 +685,7 @@ static void pbvh_iter_end(PBVHIter *iter)
MEM_freeN(iter->stack);
}
-static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting)
+static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting)
{
if (UNLIKELY(iter->stacksize == iter->stackspace)) {
iter->stackspace *= 2;
@@ -730,23 +706,20 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting)
static PBVHNode *pbvh_iter_next(PBVHIter *iter)
{
- PBVHNode *node;
- int revisiting;
-
/* purpose here is to traverse tree, visiting child nodes before their
* parents, this order is necessary for e.g. computing bounding boxes */
while (iter->stacksize) {
/* pop node */
iter->stacksize--;
- node = iter->stack[iter->stacksize].node;
+ PBVHNode *node = iter->stack[iter->stacksize].node;
/* on a mesh with no faces this can happen
* can remove this check if we know meshes have at least 1 face */
if (node == NULL)
return NULL;
- revisiting = iter->stack[iter->stacksize].revisiting;
+ bool revisiting = iter->stack[iter->stacksize].revisiting;
/* revisiting node already checked */
if (revisiting)
@@ -761,11 +734,11 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
}
else {
/* come back later when children are done */
- pbvh_stack_push(iter, node, 1);
+ pbvh_stack_push(iter, node, true);
/* push two child nodes on the stack */
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, 0);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, 0);
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
}
}
@@ -774,12 +747,10 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
{
- PBVHNode *node;
-
while (iter->stacksize) {
/* pop node */
iter->stacksize--;
- node = iter->stack[iter->stacksize].node;
+ PBVHNode *node = iter->stack[iter->stacksize].node;
/* on a mesh with no faces this can happen
* can remove this check if we know meshes have at least 1 face */
@@ -792,8 +763,8 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
return node;
}
else {
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, 0);
- pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, 0);
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false);
+ pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false);
}
}
@@ -953,14 +924,113 @@ static bool update_search_cb(PBVHNode *node, void *data_v)
return true;
}
+typedef struct PBVHUpdateData {
+ PBVH *bvh;
+ PBVHNode **nodes;
+ int totnode;
+
+ float (*fnors)[3];
+ float (*vnors)[3];
+ int flag;
+} PBVHUpdateData;
+
+static void pbvh_update_normals_accum_task_cb(void *userdata, const int n)
+{
+ PBVHUpdateData *data = userdata;
+
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ float (*fnors)[3] = data->fnors;
+ float (*vnors)[3] = data->vnors;
+
+ if ((node->flag & PBVH_UpdateNormals)) {
+ unsigned int mpoly_prev = UINT_MAX;
+ float fn[3];
+
+ const int *faces = node->prim_indices;
+ const int totface = node->totprim;
+
+ for (int i = 0; i < totface; ++i) {
+ const MLoopTri *lt = &bvh->looptri[faces[i]];
+ const unsigned int vtri[3] = {
+ bvh->mloop[lt->tri[0]].v,
+ bvh->mloop[lt->tri[1]].v,
+ bvh->mloop[lt->tri[2]].v,
+ };
+ const int sides = 3;
+
+ /* Face normal and mask */
+ if (lt->poly != mpoly_prev) {
+ const MPoly *mp = &bvh->mpoly[lt->poly];
+ BKE_mesh_calc_poly_normal(mp, &bvh->mloop[mp->loopstart], bvh->verts, fn);
+ mpoly_prev = lt->poly;
+
+ if (fnors) {
+ /* We can assume a face is only present in one node ever. */
+ copy_v3_v3(fnors[lt->poly], fn);
+ }
+ }
+
+ for (int j = sides; j--; ) {
+ const int v = vtri[j];
+
+ if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
+ /* Note: This avoids `lock, add_v3_v3, unlock` and is five to ten times quicker than a spinlock.
+ * Not exact equivalent though, since atomicity is only ensured for one component
+ * of the vector at a time, but here it shall not make any sensible difference. */
+ for (int k = 3; k--; ) {
+ /* Atomic float addition.
+ * Note that since collision are unlikely, loop will nearly always run once. */
+ float oldval, newval;
+ uint32_t prevval;
+ do {
+ oldval = vnors[v][k];
+ newval = oldval + fn[k];
+ prevval = atomic_cas_uint32(
+ (uint32_t *)&vnors[v][k], *(uint32_t *)(&oldval), *(uint32_t *)(&newval));
+ } while (UNLIKELY(prevval != *(uint32_t *)(&oldval)));
+ }
+ }
+ }
+ }
+ }
+}
+
+static void pbvh_update_normals_store_task_cb(void *userdata, const int n)
+{
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ float (*vnors)[3] = data->vnors;
+
+ if (node->flag & PBVH_UpdateNormals) {
+ const int *verts = node->vert_indices;
+ const int totvert = node->uniq_verts;
+
+ for (int i = 0; i < totvert; ++i) {
+ const int v = verts[i];
+ MVert *mvert = &bvh->verts[v];
+
+ /* mvert is shared between nodes, hence between threads. */
+ if (atomic_fetch_and_and_uint8(
+ (uint8_t *)&mvert->flag, (uint8_t)~ME_VERT_PBVH_UPDATE) & ME_VERT_PBVH_UPDATE)
+ {
+ normalize_v3(vnors[v]);
+ normal_float_to_short_v3(mvert->no, vnors[v]);
+ }
+ }
+
+ node->flag &= ~PBVH_UpdateNormals;
+ }
+}
+
static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
- int totnode, float (*face_nors)[3])
+ int totnode, float (*fnors)[3])
{
- float (*vnor)[3];
- int n;
+ float (*vnors)[3];
if (bvh->type == PBVH_BMESH) {
- BLI_assert(face_nors == NULL);
+ BLI_assert(fnors == NULL);
pbvh_bmesh_normals_update(nodes, totnode);
return;
}
@@ -970,7 +1040,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
/* could be per node to save some memory, but also means
* we have to store for each vertex which node it is in */
- vnor = MEM_callocN(sizeof(float) * 3 * bvh->totvert, "bvh temp vnors");
+ vnors = MEM_callocN(sizeof(*vnors) * bvh->totvert, __func__);
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
@@ -982,118 +1052,53 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
* can only update vertices marked with ME_VERT_PBVH_UPDATE.
*/
-#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
+ PBVHUpdateData data = {
+ .bvh = bvh, .nodes = nodes,
+ .fnors = fnors, .vnors = vnors,
+ };
- if ((node->flag & PBVH_UpdateNormals)) {
- int i, j, totface, *faces;
- unsigned int mpoly_prev = UINT_MAX;
- float fn[3];
-
- faces = node->prim_indices;
- totface = node->totprim;
-
- for (i = 0; i < totface; ++i) {
- const MLoopTri *lt = &bvh->looptri[faces[i]];
- const unsigned int vtri[3] = {
- bvh->mloop[lt->tri[0]].v,
- bvh->mloop[lt->tri[1]].v,
- bvh->mloop[lt->tri[2]].v,
- };
- const int sides = 3;
-
- /* Face normal and mask */
- if (lt->poly != mpoly_prev) {
- const MPoly *mp = &bvh->mpoly[lt->poly];
- BKE_mesh_calc_poly_normal(mp, &bvh->mloop[mp->loopstart], bvh->verts, fn);
- mpoly_prev = lt->poly;
-
- if (face_nors) {
- copy_v3_v3(face_nors[lt->poly], fn);
- }
- }
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, totnode > PBVH_THREADED_LIMIT);
- for (j = 0; j < sides; ++j) {
- int v = vtri[j];
-
- if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) {
- /* this seems like it could be very slow but profile
- * does not show this, so just leave it for now? */
-#pragma omp atomic
- vnor[v][0] += fn[0];
-#pragma omp atomic
- vnor[v][1] += fn[1];
-#pragma omp atomic
- vnor[v][2] += fn[2];
- }
- }
- }
- }
- }
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, totnode > PBVH_THREADED_LIMIT);
-#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if (node->flag & PBVH_UpdateNormals) {
- const int *verts;
- int i, totvert;
-
- verts = node->vert_indices;
- totvert = node->uniq_verts;
-
- for (i = 0; i < totvert; ++i) {
- const int v = verts[i];
- MVert *mvert = &bvh->verts[v];
+ MEM_freeN(vnors);
+}
- if (mvert->flag & ME_VERT_PBVH_UPDATE) {
- float no[3];
+static void pbvh_update_BB_redraw_task_cb(void *userdata, const int n)
+{
+ PBVHUpdateData *data = userdata;
+ PBVH *bvh = data->bvh;
+ PBVHNode *node = data->nodes[n];
+ const int flag = data->flag;
- copy_v3_v3(no, vnor[v]);
- normalize_v3(no);
- normal_float_to_short_v3(mvert->no, no);
+ if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB))
+ /* don't clear flag yet, leave it for flushing later */
+ /* Note that bvh usage is read-only here, so no need to thread-protect it. */
+ update_node_vb(bvh, node);
- mvert->flag &= ~ME_VERT_PBVH_UPDATE;
- }
- }
+ if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB))
+ node->orig_vb = node->vb;
- node->flag &= ~PBVH_UpdateNormals;
- }
- }
-
- MEM_freeN(vnor);
+ if ((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw))
+ node->flag &= ~PBVH_UpdateRedraw;
}
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
{
- int n;
-
/* update BB, redraw flag */
-#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHNode *node = nodes[n];
-
- if ((flag & PBVH_UpdateBB) && (node->flag & PBVH_UpdateBB))
- /* don't clear flag yet, leave it for flushing later */
- update_node_vb(bvh, node);
+ PBVHUpdateData data = {
+ .bvh = bvh, .nodes = nodes,
+ .flag = flag,
+ };
- if ((flag & PBVH_UpdateOriginalBB) && (node->flag & PBVH_UpdateOriginalBB))
- node->orig_vb = node->vb;
-
- if ((flag & PBVH_UpdateRedraw) && (node->flag & PBVH_UpdateRedraw))
- node->flag &= ~PBVH_UpdateRedraw;
- }
+ BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, totnode > PBVH_THREADED_LIMIT);
}
static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
{
- PBVHNode *node;
- int n;
-
/* can't be done in parallel with OpenGL */
- for (n = 0; n < totnode; n++) {
- node = nodes[n];
+ for (int n = 0; n < totnode; n++) {
+ PBVHNode *node = nodes[n];
if (node->flag & PBVH_RebuildDrawBuffers) {
GPU_free_pbvh_buffers(node->draw_buffers);
@@ -1116,8 +1121,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
break;
case PBVH_BMESH:
node->draw_buffers =
- GPU_build_bmesh_pbvh_buffers(bvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
+ GPU_build_bmesh_pbvh_buffers(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
@@ -1163,13 +1167,10 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
static void pbvh_draw_BB(PBVH *bvh)
{
- PBVHNode *node;
- int a;
-
GPU_init_draw_pbvh_BB();
- for (a = 0; a < bvh->totnode; a++) {
- node = &bvh->nodes[a];
+ for (int a = 0; a < bvh->totnode; a++) {
+ PBVHNode *node = &bvh->nodes[a];
GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
}
@@ -1208,19 +1209,19 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
return update;
}
-void BKE_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3])
+void BKE_pbvh_update(PBVH *bvh, int flag, float (*fnors)[3])
{
- PBVHNode **nodes;
- int totnode;
-
if (!bvh->nodes)
return;
+ PBVHNode **nodes;
+ int totnode;
+
BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag),
&nodes, &totnode);
if (flag & PBVH_UpdateNormals)
- pbvh_update_normals(bvh, nodes, totnode, face_nors);
+ pbvh_update_normals(bvh, nodes, totnode, fnors);
if (flag & (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw))
pbvh_update_BB_redraw(bvh, nodes, totnode, flag);
@@ -1251,26 +1252,19 @@ void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
copy_v3_v3(bb_max, bb.bmax);
}
-void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface)
+void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface)
{
- PBVHIter iter;
+ GSet *face_set = BLI_gset_ptr_new(__func__);
PBVHNode *node;
- GSetIterator gs_iter;
- GSet *face_set;
- void *face, **faces;
- unsigned i;
- int tot;
-
- face_set = BLI_gset_ptr_new(__func__);
+ PBVHIter iter;
pbvh_iter_begin(&iter, bvh, NULL, NULL);
while ((node = pbvh_iter_next(&iter))) {
if (node->flag & PBVH_UpdateNormals) {
- for (i = 0; i < node->totprim; ++i) {
- face = bvh->gridfaces[node->prim_indices[i]];
- if (!BLI_gset_haskey(face_set, face))
- BLI_gset_insert(face_set, face);
+ for (unsigned i = 0; i < node->totprim; ++i) {
+ void *face = bvh->gridfaces[node->prim_indices[i]];
+ BLI_gset_add(face_set, face);
}
if (clear)
@@ -1280,7 +1274,7 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r
pbvh_iter_end(&iter);
- tot = BLI_gset_size(face_set);
+ const int tot = BLI_gset_size(face_set);
if (tot == 0) {
*r_totface = 0;
*r_gridfaces = NULL;
@@ -1288,8 +1282,10 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r
return;
}
- faces = MEM_mallocN(sizeof(*faces) * tot, "PBVH Grid Faces");
+ void **faces = MEM_mallocN(sizeof(*faces) * tot, "PBVH Grid Faces");
+ GSetIterator gs_iter;
+ int i;
GSET_ITER_INDEX (gs_iter, face_set, i) {
faces[i] = BLI_gsetIterator_getKey(&gs_iter);
}
@@ -1474,10 +1470,34 @@ void BKE_pbvh_node_get_bm_orco_data(
*r_orco_coords = node->bm_orco;
}
+/**
+ * \note doing a full search on all vertices here seems expensive,
+ * however this is important to avoid having to recalculate boundbox & sync the buffers to the GPU
+ * (which is far more expensive!) See: T47232.
+ */
+bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node)
+{
+ BLI_assert(bvh->type == PBVH_FACES);
+ const int *verts = node->vert_indices;
+ const int totvert = node->uniq_verts + node->face_verts;
+
+ for (int i = 0; i < totvert; ++i) {
+ const int v = verts[i];
+ const MVert *mvert = &bvh->verts[v];
+
+ if (mvert->flag & ME_VERT_PBVH_UPDATE) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
/********************************* Raycast ***********************************/
typedef struct {
- IsectRayAABBData ray;
+ struct IsectRayAABB_Precalc ray;
bool original;
} RaycastData;
@@ -1491,7 +1511,7 @@ static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
else
BKE_pbvh_node_get_BB(node, bb_min, bb_max);
- return isect_ray_aabb(&rcd->ray, bb_min, bb_max, &node->tmin);
+ return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin);
}
void BKE_pbvh_raycast(
@@ -1501,7 +1521,7 @@ void BKE_pbvh_raycast(
{
RaycastData rcd;
- isect_ray_aabb_initialize(&rcd.ray, ray_start, ray_normal);
+ isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
rcd.original = original;
BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
@@ -1589,12 +1609,11 @@ static bool pbvh_grids_node_raycast(
const float ray_start[3], const float ray_normal[3],
float *dist)
{
- int totgrid = node->totprim;
- int gridsize = bvh->gridkey.grid_size;
- int i, x, y;
+ const int totgrid = node->totprim;
+ const int gridsize = bvh->gridkey.grid_size;
bool hit = false;
- for (i = 0; i < totgrid; ++i) {
+ for (int i = 0; i < totgrid; ++i) {
CCGElem *grid = bvh->grids[node->prim_indices[i]];
BLI_bitmap *gh;
@@ -1603,8 +1622,8 @@ static bool pbvh_grids_node_raycast(
gh = bvh->grid_hidden[node->prim_indices[i]];
- for (y = 0; y < gridsize - 1; ++y) {
- for (x = 0; x < gridsize - 1; ++x) {
+ for (int y = 0; y < gridsize - 1; ++y) {
+ for (int x = 0; x < gridsize - 1; ++x) {
/* check if grid face is hidden */
if (gh) {
if (paint_is_grid_face_hidden(gh, gridsize, x, y))
@@ -1640,14 +1659,14 @@ static bool pbvh_grids_node_raycast(
}
bool BKE_pbvh_node_raycast(
- PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco,
+ PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
const float ray_start[3], const float ray_normal[3],
float *dist)
{
bool hit = false;
if (node->flag & PBVH_FullyHidden)
- return 0;
+ return false;
switch (bvh->type) {
case PBVH_FACES:
@@ -1676,7 +1695,7 @@ void BKE_pbvh_raycast_project_ray_root(
if (bvh->nodes) {
float rootmin_start, rootmin_end;
float bb_min_root[3], bb_max_root[3], bb_center[3], bb_diff[3];
- IsectRayAABBData ray;
+ struct IsectRayAABB_Precalc ray;
float ray_normal_inv[3];
float offset = 1.0f + 1e-3f;
float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
@@ -1697,15 +1716,15 @@ void BKE_pbvh_raycast_project_ray_root(
madd_v3_v3v3fl(bb_min_root, bb_center, bb_diff, -offset);
/* first project start ray */
- isect_ray_aabb_initialize(&ray, ray_start, ray_normal);
- if (!isect_ray_aabb(&ray, bb_min_root, bb_max_root, &rootmin_start))
+ isect_ray_aabb_v3_precalc(&ray, ray_start, ray_normal);
+ if (!isect_ray_aabb_v3(&ray, bb_min_root, bb_max_root, &rootmin_start))
return;
/* then the end ray */
mul_v3_v3fl(ray_normal_inv, ray_normal, -1.0);
- isect_ray_aabb_initialize(&ray, ray_end, ray_normal_inv);
+ isect_ray_aabb_v3_precalc(&ray, ray_end, ray_normal_inv);
/* unlikely to fail exiting if entering succeeded, still keep this here */
- if (!isect_ray_aabb(&ray, bb_min_root, bb_max_root, &rootmin_end))
+ if (!isect_ray_aabb_v3(&ray, bb_min_root, bb_max_root, &rootmin_end))
return;
madd_v3_v3v3fl(ray_start, ray_start, ray_normal, rootmin_start);
@@ -1713,9 +1732,6 @@ void BKE_pbvh_raycast_project_ray_root(
}
}
-
-//#include "GPU_glew.h"
-
typedef struct {
DMSetMaterial setMaterial;
bool wireframe;
@@ -1728,18 +1744,19 @@ void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
#if 0
/* XXX: Just some quick code to show leaf nodes in different colors */
- float col[3]; int i;
+ float col[3];
+ float spec[3] = {0.0f, 0.0f, 0.0f};
if (0) { //is_partial) {
col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
}
else {
srand((long long)node);
- for (i = 0; i < 3; ++i)
+ for (int i = 0; i < 3; ++i)
col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
}
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
+ GPU_basic_shader_colors(col, spec, 0, 1.0f);
glColor3f(1, 0, 0);
#endif
@@ -1768,10 +1785,9 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3],
{
float vmin[3], vmax[3];
PlaneAABBIsect ret = ISECT_INSIDE;
- int i, axis;
- for (i = 0; i < 4; ++i) {
- for (axis = 0; axis < 3; ++axis) {
+ for (int i = 0; i < 4; ++i) {
+ for (int axis = 0; axis < 3; ++axis) {
if (planes[i][axis] > 0) {
vmin[axis] = bb_min[axis];
vmax[axis] = bb_max[axis];
@@ -1816,20 +1832,20 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node)
node->flag |= PBVH_UpdateDrawBuffers;
}
-void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
+void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
DMSetMaterial setMaterial, bool wireframe, bool fast)
{
PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast};
PBVHNode **nodes;
- int a, totnode;
+ int totnode;
- for (a = 0; a < bvh->totnode; a++)
+ for (int a = 0; a < bvh->totnode; a++)
pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]);
BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
&nodes, &totnode);
- pbvh_update_normals(bvh, nodes, totnode, face_nors);
+ pbvh_update_normals(bvh, nodes, totnode, fnors);
pbvh_update_draw_buffers(bvh, nodes, totnode);
if (nodes) MEM_freeN(nodes);
@@ -1849,8 +1865,6 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
DMFlagMat *flagmats, BLI_bitmap **grid_hidden)
{
- int a;
-
bvh->grids = grids;
bvh->gridfaces = gridfaces;
@@ -1858,7 +1872,7 @@ void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
bvh->grid_flag_mats = flagmats;
bvh->grid_hidden = grid_hidden;
- for (a = 0; a < bvh->totnode; ++a)
+ for (int a = 0; a < bvh->totnode; ++a)
BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]);
}
}
@@ -1885,17 +1899,15 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node)
float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
{
- int a;
float (*vertCos)[3] = NULL;
if (pbvh->verts) {
- float *co;
MVert *mvert = pbvh->verts;
vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BKE_pbvh_get_vertCoords");
- co = (float *)vertCos;
+ float *co = (float *)vertCos;
- for (a = 0; a < pbvh->totvert; a++, mvert++, co += 3) {
+ for (int a = 0; a < pbvh->totvert; a++, mvert++, co += 3) {
copy_v3_v3(co, mvert->co);
}
}
@@ -1905,8 +1917,6 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
{
- int a;
-
if (!pbvh->deformed) {
if (pbvh->verts) {
/* if pbvh is not already deformed, verts/faces points to the */
@@ -1914,18 +1924,21 @@ void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
/* unneeded deformation -- duplicate verts/faces to avoid this */
pbvh->verts = MEM_dupallocN(pbvh->verts);
- pbvh->looptri = MEM_dupallocN(pbvh->looptri);
+ /* No need to dupalloc pbvh->looptri, this one is 'totally owned' by pbvh, it's never some mesh data. */
- pbvh->deformed = 1;
+ pbvh->deformed = true;
}
}
if (pbvh->verts) {
MVert *mvert = pbvh->verts;
/* copy new verts coords */
- for (a = 0; a < pbvh->totvert; ++a, ++mvert) {
- copy_v3_v3(mvert->co, vertCos[a]);
- mvert->flag |= ME_VERT_PBVH_UPDATE;
+ for (int a = 0; a < pbvh->totvert; ++a, ++mvert) {
+ /* no need for float comparison here (memory is exactly equal or not) */
+ if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) {
+ copy_v3_v3(mvert->co, vertCos[a]);
+ mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
}
/* coordinates are new -- normals should also be updated */
@@ -1935,7 +1948,7 @@ void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
pbvh->looptri, pbvh->totprim,
NULL);
- for (a = 0; a < pbvh->totnode; ++a)
+ for (int a = 0; a < pbvh->totnode; ++a)
BKE_pbvh_node_mark_update(&pbvh->nodes[a]);
BKE_pbvh_update(pbvh, PBVH_UpdateBB, NULL);
@@ -1954,51 +1967,41 @@ PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node)
{
int index, totverts;
-#pragma omp critical
- {
-
- index = node->proxy_count;
+ index = node->proxy_count;
- node->proxy_count++;
+ node->proxy_count++;
- if (node->proxies)
- node->proxies = MEM_reallocN(node->proxies, node->proxy_count * sizeof(PBVHProxyNode));
- else
- node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
+ if (node->proxies)
+ node->proxies = MEM_reallocN(node->proxies, node->proxy_count * sizeof(PBVHProxyNode));
+ else
+ node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
- BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL);
- node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co");
- }
+ BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL);
+ node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co");
return node->proxies + index;
}
void BKE_pbvh_node_free_proxies(PBVHNode *node)
{
-#pragma omp critical
- {
- int p;
-
- for (p = 0; p < node->proxy_count; p++) {
- MEM_freeN(node->proxies[p].co);
- node->proxies[p].co = NULL;
- }
+ for (int p = 0; p < node->proxy_count; p++) {
+ MEM_freeN(node->proxies[p].co);
+ node->proxies[p].co = NULL;
+ }
- MEM_freeN(node->proxies);
- node->proxies = NULL;
+ MEM_freeN(node->proxies);
+ node->proxies = NULL;
- node->proxy_count = 0;
- }
+ node->proxy_count = 0;
}
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot)
{
- PBVHNode **array = NULL, *node;
+ PBVHNode **array = NULL;
int tot = 0, space = 0;
- int n;
- for (n = 0; n < pbvh->totnode; n++) {
- node = pbvh->nodes + n;
+ for (int n = 0; n < pbvh->totnode; n++) {
+ PBVHNode *node = pbvh->nodes + n;
if (node->proxy_count > 0) {
if (tot == space) {
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 3e236079a66..88dc63d6cb2 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -87,17 +87,16 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- BMLoop *l_iter;
- BMLoop *l_first;
- BMVert *v;
/* Update ownership of faces */
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
- /* Update vertices */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ /* Update vertices */
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
+
do {
- v = l_iter->v;
+ BMVert *v = l_iter->v;
if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_add(n->bm_other_verts, v);
@@ -131,15 +130,9 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver
/* Recursively split the node if it exceeds the leaf_limit */
static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index)
{
- GSet *empty, *other;
- GSetIterator gs_iter;
- PBVHNode *n, *c1, *c2;
- BB cb;
- float mid;
- int axis, children;
const int cd_vert_node_offset = bvh->cd_vert_node_offset;
const int cd_face_node_offset = bvh->cd_face_node_offset;
- n = &bvh->nodes[node_index];
+ PBVHNode *n = &bvh->nodes[node_index];
if (BLI_gset_size(n->bm_faces) <= bvh->leaf_limit) {
/* Node limit not exceeded */
@@ -148,7 +141,9 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
}
/* Calculate bounding box around primitive centroids */
+ BB cb;
BB_reset(&cb);
+ GSetIterator gs_iter;
GSET_ITER (gs_iter, n->bm_faces) {
const BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
const BBC *bbc = &bbc_array[BM_elem_index_get(f)];
@@ -157,11 +152,11 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
}
/* Find widest axis and its midpoint */
- axis = BB_widest_axis(&cb);
- mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+ const int axis = BB_widest_axis(&cb);
+ const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
/* Add two new child nodes */
- children = bvh->totnode;
+ const int children = bvh->totnode;
n->children_offset = children;
pbvh_grow_nodes(bvh, bvh->totnode + 2);
@@ -169,8 +164,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
n = &bvh->nodes[node_index];
/* Initialize children */
- c1 = &bvh->nodes[children];
- c2 = &bvh->nodes[children + 1];
+ PBVHNode *c1 = &bvh->nodes[children],
+ *c2 = &bvh->nodes[children + 1];
c1->flag |= PBVH_Leaf;
c2->flag |= PBVH_Leaf;
c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_size(n->bm_faces) / 2);
@@ -188,7 +183,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
}
/* Enforce at least one primitive in each node */
- empty = NULL;
+ GSet *empty = NULL, *other;
if (BLI_gset_size(c1->bm_faces) == 0) {
empty = c1->bm_faces;
other = c2->bm_faces;
@@ -242,7 +237,6 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
n->flag &= ~PBVH_Leaf;
/* Recurse */
- c1 = c2 = NULL;
pbvh_bmesh_node_split(bvh, bbc_array, children);
pbvh_bmesh_node_split(bvh, bbc_array, children + 1);
@@ -259,30 +253,25 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde
/* Recursively split the node if it exceeds the leaf_limit */
static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
{
- GSet *bm_faces;
- int bm_faces_size;
- GSetIterator gs_iter;
- BBC *bbc_array;
- unsigned int i;
-
- bm_faces = bvh->nodes[node_index].bm_faces;
- bm_faces_size = BLI_gset_size(bm_faces);
+ GSet *bm_faces = bvh->nodes[node_index].bm_faces;
+ const int bm_faces_size = BLI_gset_size(bm_faces);
if (bm_faces_size <= bvh->leaf_limit) {
/* Node limit not exceeded */
return false;
}
/* For each BMFace, store the AABB and AABB centroid */
- bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
+ BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
+ GSetIterator gs_iter;
+ int i;
GSET_ITER_INDEX (gs_iter, bm_faces, i) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
BBC *bbc = &bbc_array[i];
- BMLoop *l_iter;
- BMLoop *l_first;
BB_reset((BB *)bbc);
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
BB_expand((BB *)bbc, l_iter->v->co);
} while ((l_iter = l_iter->next) != l_first);
@@ -347,12 +336,11 @@ static BMVert *pbvh_bmesh_vert_create(
const int cd_vert_mask_offset)
{
PBVHNode *node = &bvh->nodes[node_index];
- BMVert *v;
BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
/* avoid initializing customdata because its quite involved */
- v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
+ BMVert *v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD);
CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data);
/* This value is logged below */
@@ -374,13 +362,12 @@ static BMFace *pbvh_bmesh_face_create(
BMVert *v_tri[3], BMEdge *e_tri[3],
const BMFace *f_example)
{
- BMFace *f;
PBVHNode *node = &bvh->nodes[node_index];
/* ensure we never add existing face */
BLI_assert(BM_face_exists(v_tri, 3, NULL) == false);
- f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
+ BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE);
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
@@ -442,14 +429,10 @@ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
{
BMIter bm_iter;
BMFace *f;
- PBVHNode *current_node;
-
- current_node = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v);
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node;
-
- f_node = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
if (f_node != current_node)
return f_node;
@@ -462,13 +445,10 @@ static void pbvh_bmesh_vert_ownership_transfer(
PBVH *bvh, PBVHNode *new_owner,
BMVert *v)
{
- PBVHNode *current_owner;
-
- current_owner = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
-
BLI_assert(current_owner != new_owner);
/* Remove current ownership */
@@ -486,21 +466,18 @@ static void pbvh_bmesh_vert_ownership_transfer(
static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
{
- PBVHNode *v_node;
- BMIter bm_iter;
- BMFace *f;
-
/* never match for first time */
int f_node_index_prev = DYNTOPO_NODE_NONE;
- v_node = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
+ BMIter bm_iter;
+ BMFace *f;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f);
- PBVHNode *f_node;
/* faces often share the same node,
* quick check to avoid redundant #BLI_gset_remove calls */
@@ -508,7 +485,7 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
continue;
f_node_index_prev = f_node_index;
- f_node = &bvh->nodes[f_node_index];
+ PBVHNode *f_node = &bvh->nodes[f_node_index];
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Remove current ownership */
@@ -521,19 +498,14 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
{
- PBVHNode *f_node;
- BMVert *v;
-
- BMLoop *l_iter;
- BMLoop *l_first;
-
- f_node = pbvh_bmesh_node_lookup(bvh, f);
+ PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
- v = l_iter->v;
+ BMVert *v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) {
if (BLI_gset_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
@@ -575,7 +547,7 @@ static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
buf->count = 2;
}
else {
- BLI_buffer_resize(buf, BM_edge_face_count(e));
+ BLI_buffer_reinit(buf, BM_edge_face_count(e));
BM_iter_as_array(NULL, BM_LOOPS_OF_EDGE, e, buf->data, buf->count);
}
}
@@ -630,12 +602,10 @@ typedef struct {
* (it's a requirement that edges enter and leave a clean tag state) */
static void pbvh_bmesh_edge_tag_verify(PBVH *bvh)
{
- int n;
-
- for (n = 0; n < bvh->totnode; n++) {
+ for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
- GSetIterator gs_iter;
if (node->bm_faces) {
+ GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
BMEdge *e_tri[3];
@@ -668,21 +638,19 @@ static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f)
closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
/* Check if triangle intersects the sphere */
- return ((len_squared_v3v3(q->center, c) <= q->radius_squared));
+ return len_squared_v3v3(q->center, c) <= q->radius_squared;
}
/* Return true if the vertex mask is less than 1.0, false otherwise */
static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v)
{
- return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f);
+ return BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f;
}
static void edge_queue_insert(
EdgeQueueContext *eq_ctx, BMEdge *e,
float priority)
{
- BMVert **pair;
-
/* Don't let topology update affect fully masked vertices. This used to
* have a 50% mask cutoff, with the reasoning that you can't do a 50%
* topology update. But this gives an ugly border in the mesh. The mask
@@ -694,7 +662,7 @@ static void edge_queue_insert(
!(BM_elem_flag_test_bool(e->v1, BM_ELEM_HIDDEN) ||
BM_elem_flag_test_bool(e->v2, BM_ELEM_HIDDEN)))
{
- pair = BLI_mempool_alloc(eq_ctx->pool);
+ BMVert **pair = BLI_mempool_alloc(eq_ctx->pool);
pair[0] = e->v1;
pair[1] = e->v2;
BLI_heap_insert(eq_ctx->q->heap, priority, pair);
@@ -757,19 +725,15 @@ static void long_edge_queue_edge_add_recursive(
#define EVEN_GENERATION_SCALE 1.6f
const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD;
- float limit_len_sq;
- BMLoop *l_iter;
limit_len *= EVEN_GENERATION_SCALE;
- limit_len_sq = SQUARE(limit_len);
+ const float limit_len_sq = SQUARE(limit_len);
- l_iter = l_edge;
+ BMLoop *l_iter = l_edge;
do {
- float len_sq_other;
BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev};
- int i;
- for (i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
- len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
+ for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) {
+ float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e);
if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) {
// edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other);
long_edge_queue_edge_add_recursive(
@@ -813,24 +777,20 @@ static void long_edge_queue_face_add(
#endif
if (edge_queue_tri_in_sphere(eq_ctx->q, f)) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
/* Check each edge of the face */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
- {
#ifdef USE_EDGEQUEUE_EVEN_SUBDIV
- const float len_sq = BM_edge_calc_length_squared(l_iter->e);
- if (len_sq > eq_ctx->q->limit_len_squared) {
- long_edge_queue_edge_add_recursive(
- eq_ctx, l_iter->radial_next, l_iter,
- len_sq, eq_ctx->q->limit_len);
- }
+ const float len_sq = BM_edge_calc_length_squared(l_iter->e);
+ if (len_sq > eq_ctx->q->limit_len_squared) {
+ long_edge_queue_edge_add_recursive(
+ eq_ctx, l_iter->radial_next, l_iter,
+ len_sq, eq_ctx->q->limit_len);
+ }
#else
- long_edge_queue_edge_add(eq_ctx, l_iter->e);
+ long_edge_queue_edge_add(eq_ctx, l_iter->e);
#endif
- }
} while ((l_iter = l_iter->next) != l_first);
}
}
@@ -873,8 +833,6 @@ static void long_edge_queue_create(
PBVH *bvh, const float center[3], const float view_normal[3],
float radius)
{
- int n;
-
eq_ctx->q->heap = BLI_heap_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
@@ -894,8 +852,7 @@ static void long_edge_queue_create(
pbvh_bmesh_edge_tag_verify(bvh);
#endif
-
- for (n = 0; n < bvh->totnode; n++) {
+ for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
/* Check leaf nodes marked for topology update */
@@ -929,8 +886,6 @@ static void short_edge_queue_create(
PBVH *bvh, const float center[3], const float view_normal[3],
float radius)
{
- int n;
-
eq_ctx->q->heap = BLI_heap_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
@@ -946,7 +901,7 @@ static void short_edge_queue_create(
UNUSED_VARS(view_normal);
#endif
- for (n = 0; n < bvh->totnode; n++) {
+ for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
/* Check leaf nodes marked for topology update */
@@ -979,9 +934,7 @@ static void pbvh_bmesh_split_edge(
EdgeQueueContext *eq_ctx, PBVH *bvh,
BMEdge *e, BLI_Buffer *edge_loops)
{
- BMVert *v_new;
float co_mid[3], no_mid[3];
- int i, node_index;
/* Get all faces adjacent to the edge */
pbvh_bmesh_edge_loops(edge_loops, e);
@@ -991,8 +944,8 @@ static void pbvh_bmesh_split_edge(
mid_v3_v3v3(no_mid, e->v1->no, e->v2->no);
normalize_v3(no_mid);
- node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
- v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
+ int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset);
+ BMVert *v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset);
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
@@ -1004,17 +957,16 @@ static void pbvh_bmesh_split_edge(
}
/* For each face, add two new triangles and delete the original */
- for (i = 0; i < edge_loops->count; i++) {
+ for (int i = 0; i < edge_loops->count; i++) {
BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
BMFace *f_adj = l_adj->f;
BMFace *f_new;
BMVert *v_opp, *v1, *v2;
BMVert *v_tri[3];
BMEdge *e_tri[3];
- int ni;
BLI_assert(f_adj->len == 3);
- ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset);
+ int ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset);
/* Find the vertex not in the edge */
v_opp = l_adj->prev->v;
@@ -1153,11 +1105,7 @@ static void pbvh_bmesh_collapse_edge(
BLI_Buffer *deleted_faces,
EdgeQueueContext *eq_ctx)
{
- BMIter bm_iter;
- BMFace *f;
- BMLoop *l_adj;
BMVert *v_del, *v_conn;
- int i;
float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset);
/* one of the two vertices may be masked, select the correct one for deletion */
@@ -1174,6 +1122,7 @@ static void pbvh_bmesh_collapse_edge(
pbvh_bmesh_vert_remove(bvh, v_del);
/* Remove all faces adjacent to the edge */
+ BMLoop *l_adj;
while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
@@ -1192,16 +1141,17 @@ static void pbvh_bmesh_collapse_edge(
* really buy anything. */
BLI_buffer_empty(deleted_faces);
+ BMIter bm_iter;
+ BMFace *f;
+
BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) {
BMVert *v_tri[3];
BMFace *existing_face;
- PBVHNode *n;
- int ni;
/* Get vertices, replace use of v_del with v_conn */
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3);
BM_face_as_array_vert_tri(f, v_tri);
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
if (v_tri[i] == v_del) {
v_tri[i] = v_conn;
}
@@ -1217,8 +1167,8 @@ static void pbvh_bmesh_collapse_edge(
}
else {
BMEdge *e_tri[3];
- n = pbvh_bmesh_node_lookup(bvh, f);
- ni = n - bvh->nodes;
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
+ int ni = n - bvh->nodes;
bm_edges_from_tri(bvh->bm, v_tri, e_tri);
pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f);
@@ -1232,16 +1182,14 @@ static void pbvh_bmesh_collapse_edge(
}
/* Delete the tagged faces */
- for (i = 0; i < deleted_faces->count; i++) {
+ for (int i = 0; i < deleted_faces->count; i++) {
BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i);
- BMLoop *l_iter;
- BMVert *v_tri[3];
- BMEdge *e_tri[3];
- int j;
/* Get vertices and edges of face */
BLI_assert(f_del->len == 3);
- l_iter = BM_FACE_FIRST_LOOP(f_del);
+ BMLoop *l_iter = BM_FACE_FIRST_LOOP(f_del);
+ BMVert *v_tri[3];
+ BMEdge *e_tri[3];
v_tri[0] = l_iter->v; e_tri[0] = l_iter->e; l_iter = l_iter->next;
v_tri[1] = l_iter->v; e_tri[1] = l_iter->e; l_iter = l_iter->next;
v_tri[2] = l_iter->v; e_tri[2] = l_iter->e;
@@ -1252,14 +1200,14 @@ static void pbvh_bmesh_collapse_edge(
/* Check if any of the face's edges are now unused by any
* face, if so delete them */
- for (j = 0; j < 3; j++) {
+ for (int j = 0; j < 3; j++) {
if (BM_edge_is_wire(e_tri[j]))
BM_edge_kill(bvh->bm, e_tri[j]);
}
/* Check if any of the face's vertices are now unused, if so
* remove them from the PBVH */
- for (j = 0; j < 3; j++) {
+ for (int j = 0; j < 3; j++) {
if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) {
BLI_gset_insert(deleted_verts, v_tri[j]);
pbvh_bmesh_vert_remove(bvh, v_tri[j]);
@@ -1291,17 +1239,13 @@ static bool pbvh_bmesh_collapse_short_edges(
PBVH *bvh,
BLI_Buffer *deleted_faces)
{
- float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
- GSet *deleted_verts;
+ const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
bool any_collapsed = false;
-
- deleted_verts = BLI_gset_ptr_new("deleted_verts");
+ GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts");
while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap);
BMVert *v1 = pair[0], *v2 = pair[1];
- BMEdge *e;
-
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
@@ -1313,6 +1257,7 @@ static bool pbvh_bmesh_collapse_short_edges(
}
/* Check that the edge still exists */
+ BMEdge *e;
if (!(e = BM_edge_exists(v1, v2))) {
continue;
}
@@ -1355,8 +1300,7 @@ bool pbvh_bmesh_node_raycast(
bool hit = false;
if (use_original && node->bm_tot_ortri) {
- int i;
- for (i = 0; i < node->bm_tot_ortri; i++) {
+ for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
hit |= ray_face_intersection_tri(
ray_start, ray_normal,
@@ -1395,13 +1339,13 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
const float ray_start[3], const float ray_normal[3],
float *dist, float *r_detail)
{
+ if (node->flag & PBVH_FullyHidden)
+ return 0;
+
GSetIterator gs_iter;
bool hit = false;
BMFace *f_hit = NULL;
- if (node->flag & PBVH_FullyHidden)
- return 0;
-
GSET_ITER (gs_iter, node->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
@@ -1425,12 +1369,11 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
}
if (hit) {
- float len1, len2, len3;
BMVert *v_tri[3];
BM_face_as_array_vert_tri(f_hit, v_tri);
- len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
- len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
- len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
+ float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
+ float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
+ float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
/* detail returned will be set to the maximum allowed size, so take max here */
*r_detail = sqrtf(max_fff(len1, len2, len3));
@@ -1442,9 +1385,7 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
{
- int n;
-
- for (n = 0; n < totnode; n++) {
+ for (int n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
if (node->flag & PBVH_UpdateNormals) {
@@ -1476,25 +1417,18 @@ typedef struct FastNodeBuildInfo {
* to a sub part of the arrays */
static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena)
{
- BMFace *f;
- BB cb;
- BBC *bbc;
- float mid;
- int axis, i;
- int end;
FastNodeBuildInfo *child1, *child2;
- int num_child1, num_child2;
- BMFace *tmp;
if (node->totface <= bvh->leaf_limit) {
return;
}
/* Calculate bounding box around primitive centroids */
+ BB cb;
BB_reset(&cb);
- for (i = 0; i < node->totface; i++) {
- f = nodeinfo[i + node->start];
- bbc = &bbc_array[BM_elem_index_get(f)];
+ for (int i = 0; i < node->totface; i++) {
+ BMFace *f = nodeinfo[i + node->start];
+ BBC *bbc = &bbc_array[BM_elem_index_get(f)];
BB_expand(&cb, bbc->bcentroid);
}
@@ -1502,16 +1436,16 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
/* initialize the children */
/* Find widest axis and its midpoint */
- axis = BB_widest_axis(&cb);
- mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
+ const int axis = BB_widest_axis(&cb);
+ const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f;
- num_child1 = 0, num_child2 = 0;
+ int num_child1 = 0, num_child2 = 0;
/* split vertices along the middle line */
- end = node->start + node->totface;
- for (i = node->start; i < end - num_child2; i++) {
- f = nodeinfo[i];
- bbc = &bbc_array[BM_elem_index_get(f)];
+ const int end = node->start + node->totface;
+ for (int i = node->start; i < end - num_child2; i++) {
+ BMFace *f = nodeinfo[i];
+ BBC *bbc = &bbc_array[BM_elem_index_get(f)];
if (bbc->bcentroid[axis] > mid) {
int i_iter = end - num_child2 - 1;
@@ -1531,7 +1465,7 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
}
if (candidate != -1) {
- tmp = nodeinfo[i];
+ BMFace *tmp = nodeinfo[i];
nodeinfo[i] = nodeinfo[candidate];
nodeinfo[candidate] = tmp;
/* increase both counts */
@@ -1574,8 +1508,6 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC
pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena);
pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena);
-
- return;
}
static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index)
@@ -1605,12 +1537,6 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo,
const int cd_face_node_offset = bvh->cd_face_node_offset;
bool has_visible = false;
- int i, end;
- BMFace *f;
- BMLoop *l_iter;
- BMLoop *l_first;
- BMVert *v;
- BBC *bbc;
n->flag = PBVH_Leaf;
n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface);
@@ -1621,20 +1547,21 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo,
BB_reset(&n->vb);
- end = node->start + node->totface;
+ const int end = node->start + node->totface;
- for (i = node->start; i < end; i++) {
- f = nodeinfo[i];
- bbc = &bbc_array[BM_elem_index_get(f)];
+ for (int i = node->start; i < end; i++) {
+ BMFace *f = nodeinfo[i];
+ BBC *bbc = &bbc_array[BM_elem_index_get(f)];
/* Update ownership of faces */
BLI_gset_insert(n->bm_faces, f);
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
/* Update vertices */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
do {
- v = l_iter->v;
+ BMVert *v = l_iter->v;
if (!BLI_gset_haskey(n->bm_unique_verts, v)) {
if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_add(n->bm_other_verts, v);
@@ -1654,8 +1581,8 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo,
}
BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] &&
- n->vb.bmin[1] <= n->vb.bmax[1] &&
- n->vb.bmin[2] <= n->vb.bmax[2]);
+ n->vb.bmin[1] <= n->vb.bmax[1] &&
+ n->vb.bmin[2] <= n->vb.bmax[2]);
n->orig_vb = n->vb;
@@ -1675,16 +1602,6 @@ void BKE_pbvh_build_bmesh(
PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log,
const int cd_vert_node_offset, const int cd_face_node_offset)
{
- BMIter iter;
- BMFace *f;
- BMVert *v;
- int i;
- /* bounding box array of all faces, no need to recalculate every time */
- BBC *bbc_array;
- BMFace **nodeinfo;
- FastNodeBuildInfo rootnode = {0};
- MemArena *arena;
-
bvh->cd_vert_node_offset = cd_vert_node_offset;
bvh->cd_face_node_offset = cd_face_node_offset;
bvh->bm = bm;
@@ -1700,18 +1617,20 @@ void BKE_pbvh_build_bmesh(
if (smooth_shading)
bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
- /* calculate all bounding boxes once for all faces */
- bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
- nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+ /* bounding box array of all faces, no need to recalculate every time */
+ BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC");
+ BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo");
+ MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
+ BMIter iter;
+ BMFace *f;
+ int i;
BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) {
BBC *bbc = &bbc_array[i];
- BMLoop *l_iter;
- BMLoop *l_first;
+ BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
+ BMLoop *l_iter = l_first;
BB_reset((BB *)bbc);
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BB_expand((BB *)bbc, l_iter->v->co);
} while ((l_iter = l_iter->next) != l_first);
@@ -1723,6 +1642,7 @@ void BKE_pbvh_build_bmesh(
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
}
+ BMVert *v;
BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
@@ -1731,6 +1651,7 @@ void BKE_pbvh_build_bmesh(
bm->elem_index_dirty |= BM_FACE;
/* setup root node */
+ FastNodeBuildInfo rootnode = {0};
rootnode.totface = bm->totface;
/* start recursion, assign faces to nodes accordingly */
@@ -1764,7 +1685,6 @@ bool BKE_pbvh_bmesh_update_topology(
const int cd_face_node_offset = bvh->cd_face_node_offset;
bool modified = false;
- int n;
if (view_normal) {
BLI_assert(len_squared_v3(view_normal) != 0.0f);
@@ -1796,7 +1716,7 @@ bool BKE_pbvh_bmesh_update_topology(
}
/* Unmark nodes */
- for (n = 0; n < bvh->totnode; n++) {
+ for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
if (node->flag & PBVH_Leaf &&
@@ -1832,23 +1752,21 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3])
* Skips triangles that are hidden. */
void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node)
{
- GSetIterator gs_iter;
- int i, totvert, tottri;
-
/* Skip if original coords/triangles are already saved */
if (node->bm_orco)
return;
- totvert = (BLI_gset_size(node->bm_unique_verts) +
- BLI_gset_size(node->bm_other_verts));
+ const int totvert = BLI_gset_size(node->bm_unique_verts) +
+ BLI_gset_size(node->bm_other_verts);
- tottri = BLI_gset_size(node->bm_faces);
+ const int tottri = BLI_gset_size(node->bm_faces);
node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
/* Copy out the vertices and assign a temporary index */
- i = 0;
+ int i = 0;
+ GSetIterator gs_iter;
GSET_ITER (gs_iter, node->bm_unique_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
copy_v3_v3(node->bm_orco[i], v->co);
@@ -1888,9 +1806,7 @@ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node)
void BKE_pbvh_bmesh_after_stroke(PBVH *bvh)
{
- int i;
-
- for (i = 0; i < bvh->totnode; i++) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *n = &bvh->nodes[i];
if (n->flag & PBVH_Leaf) {
/* Free orco/ortri data */
@@ -1935,15 +1851,11 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
static void pbvh_bmesh_print(PBVH *bvh)
{
- GSetIterator gs_iter;
- int n;
- BMIter iter;
- BMFace *f;
- BMVert *v;
-
fprintf(stderr, "\npbvh=%p\n", bvh);
fprintf(stderr, "bm_face_to_node:\n");
+ BMIter iter;
+ BMFace *f;
BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
BM_elem_index_get(v),
@@ -1951,17 +1863,19 @@ static void pbvh_bmesh_print(PBVH *bvh)
}
fprintf(stderr, "bm_vert_to_node:\n");
+ BMVert *v;
BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
BM_elem_index_get(v),
pbvh_bmesh_node_lookup_index(bvh, v));
}
- for (n = 0; n < bvh->totnode; n++) {
+ for (int n = 0; n < bvh->totnode; n++) {
PBVHNode *node = &bvh->nodes[n];
if (!(node->flag & PBVH_Leaf))
continue;
+ GSetIterator gs_iter;
fprintf(stderr, "node %d\n faces:\n", n);
GSET_ITER (gs_iter, node->bm_faces)
fprintf(stderr, " %d\n",
@@ -1979,9 +1893,8 @@ static void pbvh_bmesh_print(PBVH *bvh)
static void print_flag_factors(int flag)
{
- int i;
printf("flag=0x%x:\n", flag);
- for (i = 0; i < 32; i++) {
+ for (int i = 0; i < 32; i++) {
if (flag & (1 << i)) {
printf(" %d (1 << %d)\n", 1 << i, i);
}
@@ -1994,23 +1907,16 @@ static void print_flag_factors(int flag)
static void pbvh_bmesh_verify(PBVH *bvh)
{
- GSetIterator gs_iter;
- int i;
- BMIter iter;
- BMFace *f;
- BMVert *v;
-
- GSet *faces_all;
- GSet *verts_all;
-
-
/* build list of faces & verts to lookup */
- faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
- verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
-
+ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
+ BMFace *f;
+ BMIter iter;
BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
BLI_gset_insert(faces_all, f);
}
+
+ GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
+ BMVert *v;
BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
BLI_gset_insert(verts_all, v);
@@ -2020,7 +1926,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check vert/face counts */
{
int totface = 0, totvert = 0;
- for (i = 0; i < bvh->totnode; i++) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *n = &bvh->nodes[i];
totface += n->bm_faces ? BLI_gset_size(n->bm_faces) : 0;
totvert += n->bm_unique_verts ? BLI_gset_size(n->bm_unique_verts) : 0;
@@ -2062,16 +1968,12 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check verts */
BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
- BMIter bm_iter;
- PBVHNode *n;
- bool found;
-
/* vertex isn't tracked */
if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
continue;
}
- n = pbvh_bmesh_node_lookup(bvh, v);
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v);
/* Check that the vert's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -2084,6 +1986,8 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Check that the vert's node also contains one of the vert's
* adjacent faces */
+ bool found = false;
+ BMIter bm_iter;
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
if (pbvh_bmesh_node_lookup(bvh, f) == n) {
found = true;
@@ -2095,13 +1999,12 @@ static void pbvh_bmesh_verify(PBVH *bvh)
#if 1
/* total freak stuff, check if node exists somewhere else */
/* Slow */
- for (i = 0; i < bvh->totnode; i++) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *n_other = &bvh->nodes[i];
if ((n != n_other) && (n_other->bm_unique_verts)) {
BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
}
}
-
#endif
}
@@ -2110,7 +2013,7 @@ static void pbvh_bmesh_verify(PBVH *bvh)
/* Slow */
BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) {
bool has_unique = false;
- for (i = 0; i < bvh->totnode; i++) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *n = &bvh->nodes[i];
if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi))
has_unique = true;
@@ -2124,9 +2027,10 @@ static void pbvh_bmesh_verify(PBVH *bvh)
#endif
/* Check that node elements are recorded in the top level */
- for (i = 0; i < bvh->totnode; i++) {
+ for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *n = &bvh->nodes[i];
if (n->flag & PBVH_Leaf) {
+ GSetIterator gs_iter;
GSET_ITER (gs_iter, n->bm_faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 9054ecc7c3f..448aaaa7830 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -83,6 +83,10 @@
#include "smoke_API.h"
#endif
+#ifdef WITH_OPENVDB
+#include "openvdb_capi.h"
+#endif
+
#ifdef WITH_LZO
# ifdef WITH_SYSTEM_LZO
# include <lzo/lzo1x.h>
@@ -691,10 +695,10 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
SmokeDomainSettings *sds = smd->domain;
if (sds->fluid) {
- size_t res = sds->res[0]*sds->res[1]*sds->res[2];
+ const size_t res = sds->res[0] * sds->res[1] * sds->res[2];
+ const unsigned int out_len = (unsigned int)res * sizeof(float);
float dt, dx, *dens, *heat, *heatold, *vx, *vy, *vz;
unsigned char *obstacles;
- unsigned int out_len = (unsigned int)res * sizeof(float);
float *tmp_array = MEM_callocN(out_len, "Smoke old cache tmp");
int fluid_fields = smoke_get_data_flags(sds);
@@ -733,13 +737,10 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v)
MEM_freeN(tmp_array);
if (pf->data_types & (1<<BPHYS_DATA_SMOKE_HIGH) && sds->wt) {
- int res = sds->res[0]*sds->res[1]*sds->res[2];
int res_big, res_big_array[3];
- float *dens, *tcu, *tcv, *tcw;
- unsigned int out_len = sizeof(float)*(unsigned int)res;
+ float *tcu, *tcv, *tcw;
unsigned int out_len_big;
unsigned char *tmp_array_big;
-
smoke_turbulence_get_res(sds->wt, res_big_array);
res_big = res_big_array[0]*res_big_array[1]*res_big_array[2];
out_len_big = sizeof(float) * (unsigned int)res_big;
@@ -890,6 +891,274 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
return 1;
}
+#ifdef WITH_OPENVDB
+/**
+ * Construct matrices which represent the fluid object, for low and high res:
+ * <pre>
+ * vs 0 0 0
+ * 0 vs 0 0
+ * 0 0 vs 0
+ * px py pz 1
+ * </pre>
+ *
+ * with `vs` = voxel size, and `px, py, pz`,
+ * the min position of the domain's bounding box.
+ */
+static void compute_fluid_matrices(SmokeDomainSettings *sds)
+{
+ float bbox_min[3];
+
+ copy_v3_v3(bbox_min, sds->p0);
+
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]);
+ bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]);
+ bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]);
+ add_v3_v3(bbox_min, sds->obj_shift_f);
+ }
+
+ /* construct low res matrix */
+ size_to_mat4(sds->fluidmat, sds->cell_size);
+ copy_v3_v3(sds->fluidmat[3], bbox_min);
+
+ /* The smoke simulator stores voxels cell-centered, whilst VDB is node
+ * centered, so we offset the matrix by half a voxel to compensate. */
+ madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f);
+
+ mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat);
+
+ if (sds->wt) {
+ float voxel_size_high[3];
+ /* construct high res matrix */
+ mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1));
+ size_to_mat4(sds->fluidmat_wt, voxel_size_high);
+ copy_v3_v3(sds->fluidmat_wt[3], bbox_min);
+
+ /* Same here, add half a voxel to adjust the position of the fluid. */
+ madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f);
+
+ mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt);
+ }
+}
+
+static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+ SmokeDomainSettings *sds = smd->domain;
+
+ OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16));
+
+ OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0);
+ OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f);
+ OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color);
+ OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat);
+
+ int fluid_fields = smoke_get_data_flags(sds);
+
+ struct OpenVDBFloatGrid *clip_grid = NULL;
+
+ compute_fluid_matrices(sds);
+
+ OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields);
+
+ if (sds->wt) {
+ struct OpenVDBFloatGrid *wt_density_grid;
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ wt_density_grid = OpenVDB_export_grid_fl(writer, "density", dens, sds->res_wt, sds->fluidmat_wt, NULL);
+ clip_grid = wt_density_grid;
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ OpenVDB_export_grid_fl(writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ OpenVDB_export_grid_fl(writer, "react", react, sds->res_wt, sds->fluidmat_wt, wt_density_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ OpenVDB_export_grid_vec(writer, "color", r, g, b, sds->res_wt, sds->fluidmat_wt, VEC_INVARIANT, true, wt_density_grid);
+ }
+
+ OpenVDB_export_grid_vec(writer, "texture coordinates", tcu, tcv, tcw, sds->res, sds->fluidmat, VEC_INVARIANT, false, wt_density_grid);
+ }
+
+ if (sds->fluid) {
+ struct OpenVDBFloatGrid *density_grid;
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+
+ smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
+ &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
+
+ OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx);
+ OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt);
+
+ const char *name = (!sds->wt) ? "density" : "density low";
+ density_grid = OpenVDB_export_grid_fl(writer, name, dens, sds->res, sds->fluidmat, NULL);
+ clip_grid = sds->wt ? clip_grid : density_grid;
+
+ OpenVDB_export_grid_fl(writer, "shadow", sds->shadow, sds->res, sds->fluidmat, NULL);
+
+ if (fluid_fields & SM_ACTIVE_HEAT) {
+ OpenVDB_export_grid_fl(writer, "heat", heat, sds->res, sds->fluidmat, clip_grid);
+ OpenVDB_export_grid_fl(writer, "heat old", heatold, sds->res, sds->fluidmat, clip_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ name = (!sds->wt) ? "flame" : "flame low";
+ OpenVDB_export_grid_fl(writer, name, flame, sds->res, sds->fluidmat, density_grid);
+ name = (!sds->wt) ? "fuel" : "fuel low";
+ OpenVDB_export_grid_fl(writer, name, fuel, sds->res, sds->fluidmat, density_grid);
+ name = (!sds->wt) ? "react" : "react low";
+ OpenVDB_export_grid_fl(writer, name, react, sds->res, sds->fluidmat, density_grid);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ name = (!sds->wt) ? "color" : "color low";
+ OpenVDB_export_grid_vec(writer, name, r, g, b, sds->res, sds->fluidmat, VEC_INVARIANT, true, density_grid);
+ }
+
+ OpenVDB_export_grid_vec(writer, "velocity", vx, vy, vz, sds->res, sds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, clip_grid);
+ OpenVDB_export_grid_ch(writer, "obstacles", obstacles, sds->res, sds->fluidmat, NULL);
+ }
+
+ return 1;
+}
+
+static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)smoke_v;
+
+ if (!smd) {
+ return 0;
+ }
+
+ SmokeDomainSettings *sds = smd->domain;
+
+ int fluid_fields = smoke_get_data_flags(sds);
+ int active_fields, cache_fields = 0;
+ int cache_res[3];
+ float cache_dx;
+ bool reallocate = false;
+
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f);
+ OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color);
+ OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat);
+ OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields);
+ OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields);
+ OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx);
+ OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res);
+
+ /* check if resolution has changed */
+ if (sds->res[0] != cache_res[0] ||
+ sds->res[1] != cache_res[1] ||
+ sds->res[2] != cache_res[2])
+ {
+ if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
+ reallocate = true;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ /* check if active fields have changed */
+ if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) {
+ reallocate = true;
+ }
+
+ /* reallocate fluid if needed*/
+ if (reallocate) {
+ sds->active_fields = active_fields | cache_fields;
+ smoke_reallocate_fluid(sds, cache_dx, cache_res, 1);
+ sds->dx = cache_dx;
+ copy_v3_v3_int(sds->res, cache_res);
+ sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2];
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1);
+ }
+ }
+
+ if (sds->fluid) {
+ float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b;
+ unsigned char *obstacles;
+
+ smoke_export(sds->fluid, &dt, &dx, &dens, &react, &flame, &fuel, &heat,
+ &heatold, &vx, &vy, &vz, &r, &g, &b, &obstacles);
+
+ OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt);
+
+ OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res);
+
+ const char *name = (!sds->wt) ? "density" : "density low";
+ OpenVDB_import_grid_fl(reader, name, &dens, sds->res);
+
+ if (cache_fields & SM_ACTIVE_HEAT) {
+ OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res);
+ OpenVDB_import_grid_fl(reader, "heat old", &heatold, sds->res);
+ }
+
+ if (cache_fields & SM_ACTIVE_FIRE) {
+ name = (!sds->wt) ? "flame" : "flame low";
+ OpenVDB_import_grid_fl(reader, name, &flame, sds->res);
+ name = (!sds->wt) ? "fuel" : "fuel low";
+ OpenVDB_import_grid_fl(reader, name, &fuel, sds->res);
+ name = (!sds->wt) ? "react" : "react low";
+ OpenVDB_import_grid_fl(reader, name, &react, sds->res);
+ }
+
+ if (cache_fields & SM_ACTIVE_COLORS) {
+ name = (!sds->wt) ? "color" : "color low";
+ OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res);
+ }
+
+ OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res);
+ OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res);
+ }
+
+ if (sds->wt) {
+ float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b;
+
+ smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw);
+
+ OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt);
+
+ if (fluid_fields & SM_ACTIVE_FIRE) {
+ OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt);
+ OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt);
+ }
+
+ if (fluid_fields & SM_ACTIVE_COLORS) {
+ OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt);
+ }
+
+ OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res);
+ }
+
+ OpenVDBReader_free(reader);
+
+ return 1;
+}
+#endif
+
#else // WITH_SMOKE
static int ptcache_smoke_totpoint(void *UNUSED(smoke_v), int UNUSED(cfra)) { return 0; }
static void ptcache_smoke_error(void *UNUSED(smoke_v), const char *UNUSED(message)) { }
@@ -897,6 +1166,20 @@ static int ptcache_smoke_read(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) {
static int ptcache_smoke_write(PTCacheFile *UNUSED(pf), void *UNUSED(smoke_v)) { return 0; }
#endif // WITH_SMOKE
+#if !defined(WITH_SMOKE) || !defined(WITH_OPENVDB)
+static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v)
+{
+ UNUSED_VARS(writer, smoke_v);
+ return 0;
+}
+
+static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v)
+{
+ UNUSED_VARS(reader, smoke_v);
+ return 0;
+}
+#endif
+
static int ptcache_dynamicpaint_totpoint(void *sd, int UNUSED(cfra))
{
DynamicPaintSurface *surface = (DynamicPaintSurface*)sd;
@@ -1116,6 +1399,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
pid->write_stream = NULL;
pid->read_stream = NULL;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
+
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@@ -1130,6 +1416,7 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
pid->default_step = 10;
pid->max_step = 20;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *psys)
{
@@ -1157,6 +1444,9 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
pid->write_stream = NULL;
pid->read_stream = NULL;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
+
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@@ -1188,6 +1478,7 @@ void BKE_ptcache_id_from_particles(PTCacheID *pid, Object *ob, ParticleSystem *p
pid->default_step = 10;
pid->max_step = 20;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *clmd)
{
@@ -1207,6 +1498,9 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->read_point = ptcache_cloth_read;
pid->interpolate_point = ptcache_cloth_interpolate;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
+
pid->write_stream = NULL;
pid->read_stream = NULL;
@@ -1222,6 +1516,7 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl
pid->default_step = 1;
pid->max_step = 1;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd)
{
@@ -1249,6 +1544,9 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
pid->read_stream = ptcache_smoke_read;
pid->write_stream = ptcache_smoke_write;
+ pid->write_openvdb_stream = ptcache_smoke_openvdb_write;
+ pid->read_openvdb_stream = ptcache_smoke_openvdb_read;
+
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@@ -1266,6 +1564,7 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
pid->default_step = 1;
pid->max_step = 1;
+ pid->file_type = smd->domain->cache_file_format;
}
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface)
@@ -1289,6 +1588,9 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
pid->write_stream = ptcache_dynamicpaint_write;
pid->read_stream = ptcache_dynamicpaint_read;
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
+
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
pid->interpolate_extra_data = NULL;
@@ -1303,6 +1605,7 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSu
pid->default_step = 1;
pid->max_step = 1;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *rbw)
@@ -1325,6 +1628,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->write_stream = NULL;
pid->read_stream = NULL;
+
+ pid->write_openvdb_stream = NULL;
+ pid->read_openvdb_stream = NULL;
pid->write_extra_data = NULL;
pid->read_extra_data = NULL;
@@ -1340,6 +1646,7 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->default_step = 1;
pid->max_step = 1;
+ pid->file_type = PTCACHE_FILE_PTCACHE;
}
void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
@@ -1432,6 +1739,38 @@ void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int dup
/* File handling */
+static const char *ptcache_file_extension(const PTCacheID *pid)
+{
+ switch (pid->file_type) {
+ default:
+ case PTCACHE_FILE_PTCACHE:
+ return PTCACHE_EXT;
+ case PTCACHE_FILE_OPENVDB:
+ return ".vdb";
+ }
+}
+
+/**
+ * Similar to #BLI_path_frame_get, but takes into account the stack-index which is after the frame.
+ */
+static int ptcache_frame_from_filename(const char *filename, const char *ext)
+{
+ const int frame_len = 6;
+ const int ext_len = frame_len + strlen(ext);
+ const int len = strlen(filename);
+
+ /* could crash if trying to copy a string out of this range */
+ if (len > ext_len) {
+ /* using frame_len here gives compile error (vla) */
+ char num[/* frame_len */6 + 1];
+ BLI_strncpy(num, filename + len - ext_len, sizeof(num));
+
+ return atoi(num);
+ }
+
+ return -1;
+}
+
/* Takes an Object ID and returns a unique name
* - id: object id
* - cfra: frame for the cache, can be negative
@@ -1510,18 +1849,19 @@ static int ptcache_filename(PTCacheID *pid, char *filename, int cfra, short do_p
}
if (do_ext) {
-
if (pid->cache->index < 0)
pid->cache->index = pid->stack_index = BKE_object_insert_ptcache(pid->ob);
+ const char *ext = ptcache_file_extension(pid);
+
if (pid->cache->flag & PTCACHE_EXTERNAL) {
if (pid->cache->index >= 0)
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */
else
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d"PTCACHE_EXT, cfra); /* always 6 chars */
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d%s", cfra, ext); /* always 6 chars */
}
else {
- BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u"PTCACHE_EXT, cfra, pid->stack_index); /* always 6 chars */
+ BLI_snprintf(newname, MAX_PTCACHE_FILE, "_%06d_%02u%s", cfra, pid->stack_index, ext); /* always 6 chars */
}
len += 16;
}
@@ -1546,9 +1886,6 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra)
ptcache_filename(pid, filename, cfra, 1, 1);
if (mode==PTCACHE_FILE_READ) {
- if (!BLI_exists(filename)) {
- return NULL;
- }
fp = BLI_fopen(filename, "rb");
}
else if (mode==PTCACHE_FILE_WRITE) {
@@ -2159,6 +2496,36 @@ static int ptcache_read_stream(PTCacheID *pid, int cfra)
return error == 0;
}
+
+static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra)
+{
+#ifdef WITH_OPENVDB
+ char filename[FILE_MAX * 2];
+
+ /* save blend file before using disk pointcache */
+ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0)
+ return 0;
+
+ ptcache_filename(pid, filename, cfra, 1, 1);
+
+ if (!BLI_exists(filename)) {
+ return 0;
+ }
+
+ struct OpenVDBReader *reader = OpenVDBReader_create();
+ OpenVDBReader_open(reader, filename);
+
+ if (!pid->read_openvdb_stream(reader, pid->calldata)) {
+ return 0;
+ }
+
+ return 1;
+#else
+ UNUSED_VARS(pid, cfra);
+ return 0;
+#endif
+}
+
static int ptcache_read(PTCacheID *pid, int cfra)
{
PTCacheMem *pm = NULL;
@@ -2300,8 +2667,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
return 0;
if (cfra1) {
-
- if (pid->read_stream) {
+ if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
+ if (!ptcache_read_openvdb_stream(pid, cfra1)) {
+ return 0;
+ }
+ }
+ else if (pid->read_stream) {
if (!ptcache_read_stream(pid, cfra1))
return 0;
}
@@ -2310,8 +2681,12 @@ int BKE_ptcache_read(PTCacheID *pid, float cfra)
}
if (cfra2) {
-
- if (pid->read_stream) {
+ if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->read_openvdb_stream) {
+ if (!ptcache_read_openvdb_stream(pid, cfra2)) {
+ return 0;
+ }
+ }
+ else if (pid->read_stream) {
if (!ptcache_read_stream(pid, cfra2))
return 0;
}
@@ -2377,6 +2752,28 @@ static int ptcache_write_stream(PTCacheID *pid, int cfra, int totpoint)
return error == 0;
}
+static int ptcache_write_openvdb_stream(PTCacheID *pid, int cfra)
+{
+#ifdef WITH_OPENVDB
+ struct OpenVDBWriter *writer = OpenVDBWriter_create();
+ char filename[FILE_MAX * 2];
+
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_FRAME, cfra);
+
+ ptcache_filename(pid, filename, cfra, 1, 1);
+ BLI_make_existing_file(filename);
+
+ int error = pid->write_openvdb_stream(writer, pid->calldata);
+
+ OpenVDBWriter_write(writer, filename);
+ OpenVDBWriter_free(writer);
+
+ return error == 0;
+#else
+ UNUSED_VARS(pid, cfra);
+ return 0;
+#endif
+}
static int ptcache_write(PTCacheID *pid, int cfra, int overwrite)
{
PointCache *cache = pid->cache;
@@ -2508,7 +2905,10 @@ int BKE_ptcache_write(PTCacheID *pid, unsigned int cfra)
if (ptcache_write_needed(pid, cfra, &overwrite)==0)
return 0;
- if (pid->write_stream) {
+ if (pid->file_type == PTCACHE_FILE_OPENVDB && pid->write_openvdb_stream) {
+ ptcache_write_openvdb_stream(pid, cfra);
+ }
+ else if (pid->write_stream) {
ptcache_write_stream(pid, cfra, totpoint);
}
else if (pid->write_point) {
@@ -2566,7 +2966,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
#endif
/*if (!G.relbase_valid) return; *//* save blend file before using pointcache */
-
+
+ const char *fext = ptcache_file_extension(pid);
+
/* clear all files in the temp dir with the prefix of the ID and the ".bphys" suffix */
switch (mode) {
case PTCACHE_CLEAR_ALL:
@@ -2588,7 +2990,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
len += 1;
}
- BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
+ BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
@@ -2600,13 +3002,9 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
}
else {
/* read the number of the file */
- unsigned int frame, len2 = (int)strlen(de->d_name);
- char num[7];
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
- if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
- BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
- frame = atoi(num);
-
+ if (frame != -1) {
if ((mode == PTCACHE_CLEAR_BEFORE && frame < cfra) ||
(mode == PTCACHE_CLEAR_AFTER && frame > cfra))
{
@@ -2794,21 +3192,18 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
if (dir==NULL)
return;
- BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
+ const char *fext = ptcache_file_extension(pid);
+
+ BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
- unsigned int frame, len2 = (int)strlen(de->d_name);
- char num[7];
-
- if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
- BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
- frame = atoi(num);
-
- if (frame >= sta && frame <= end)
- cache->cached_frames[frame-sta] = 1;
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+
+ if ((frame != -1) && (frame >= sta && frame <= end)) {
+ cache->cached_frames[frame-sta] = 1;
}
}
}
@@ -3113,34 +3508,17 @@ void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene)
{
PTCacheBaker baker;
- baker.bake=0;
- baker.break_data=NULL;
- baker.break_test=NULL;
- baker.pid=NULL;
- baker.progressbar=NULL;
- baker.progressend=NULL;
- baker.progresscontext=NULL;
- baker.render=0;
+ memset(&baker, 0, sizeof(baker));
+ baker.main = bmain;
+ baker.scene = scene;
+ baker.bake = 0;
+ baker.render = 0;
baker.anim_init = 0;
- baker.main=bmain;
- baker.scene=scene;
- baker.quick_step=scene->physics_settings.quick_cache_step;
+ baker.quick_step = scene->physics_settings.quick_cache_step;
BKE_ptcache_bake(&baker);
}
-/* Simulation thread, no need for interlocks as data written in both threads
- * are only unitary integers (I/O assumed to be atomic for them) */
-typedef struct {
- int break_operation;
- int thread_ended;
- int endframe;
- int step;
- int *cfra_ptr;
- Main *main;
- Scene *scene;
-} ptcache_bake_data;
-
static void ptcache_dt_to_str(char *str, double dtime)
{
if (dtime > 60.0) {
@@ -3153,52 +3531,6 @@ static void ptcache_dt_to_str(char *str, double dtime)
sprintf(str, "%is", ((int)dtime) % 60);
}
-static void *ptcache_bake_thread(void *ptr)
-{
- bool use_timer = false;
- int sfra, efra;
- double stime, ptime, ctime, fetd;
- char run[32], cur[32], etd[32];
-
- ptcache_bake_data *data = (ptcache_bake_data*)ptr;
-
- stime = ptime = PIL_check_seconds_timer();
- sfra = *data->cfra_ptr;
- efra = data->endframe;
-
- for (; (*data->cfra_ptr <= data->endframe) && !data->break_operation; *data->cfra_ptr+=data->step) {
- BKE_scene_update_for_newframe(G.main->eval_ctx, data->main, data->scene, data->scene->lay);
- if (G.background) {
- printf("bake: frame %d :: %d\n", (int)*data->cfra_ptr, data->endframe);
- }
- else {
- ctime = PIL_check_seconds_timer();
-
- fetd = (ctime-ptime)*(efra-*data->cfra_ptr)/data->step;
-
- if (use_timer || fetd > 60.0) {
- use_timer = true;
-
- ptcache_dt_to_str(cur, ctime-ptime);
- ptcache_dt_to_str(run, ctime-stime);
- ptcache_dt_to_str(etd, fetd);
-
- printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s\r", run, *data->cfra_ptr-sfra+1, efra-sfra+1, ctime-ptime, etd);
- }
- ptime = ctime;
- }
- }
-
- if (use_timer) {
- /* start with newline because of \r above */
- ptcache_dt_to_str(run, PIL_check_seconds_timer()-stime);
- printf("\nBake %s %s (%i frames simulated).\n", (data->break_operation ? "canceled after" : "finished in"), run, *data->cfra_ptr-sfra);
- }
-
- data->thread_ended = true;
- return NULL;
-}
-
/* if bake is not given run simulations to current frame */
void BKE_ptcache_bake(PTCacheBaker *baker)
{
@@ -3207,27 +3539,18 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
Scene *sce_iter; /* SETLOOPER macro only */
Base *base;
ListBase pidlist;
- PTCacheID *pid = baker->pid;
+ PTCacheID *pid = &baker->pid;
PointCache *cache = NULL;
float frameleno = scene->r.framelen;
int cfrao = CFRA;
- int startframe = MAXFRAME;
+ int startframe = MAXFRAME, endframe = baker->anim_init ? scene->r.sfra : CFRA;
int bake = baker->bake;
int render = baker->render;
- ListBase threads;
- ptcache_bake_data thread_data;
- int progress, old_progress;
- thread_data.endframe = baker->anim_init ? scene->r.sfra : CFRA;
- thread_data.step = baker->quick_step;
- thread_data.cfra_ptr = &CFRA;
- thread_data.scene = baker->scene;
- thread_data.main = baker->main;
-
G.is_break = false;
/* set caches to baking mode and figure out start frame */
- if (pid) {
+ if (pid->ob) {
/* cache/bake a single object */
cache = pid->cache;
if ((cache->flag & PTCACHE_BAKED)==0) {
@@ -3264,11 +3587,11 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
startframe = MAX2(cache->last_exact, cache->startframe);
if (bake) {
- thread_data.endframe = cache->endframe;
+ endframe = cache->endframe;
cache->flag |= PTCACHE_BAKING;
}
else {
- thread_data.endframe = MIN2(thread_data.endframe, cache->endframe);
+ endframe = MIN2(endframe, cache->endframe);
}
cache->flag &= ~PTCACHE_BAKED;
@@ -3303,7 +3626,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
cache->flag |= PTCACHE_BAKING;
if (bake)
- thread_data.endframe = MAX2(thread_data.endframe, cache->endframe);
+ endframe = MAX2(endframe, cache->endframe);
}
cache->flag &= ~PTCACHE_BAKED;
@@ -3316,46 +3639,60 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
CFRA = startframe;
scene->r.framelen = 1.0;
- thread_data.break_operation = false;
- thread_data.thread_ended = false;
- old_progress = -1;
- WM_cursor_wait(1);
-
- if (G.background) {
- ptcache_bake_thread((void*)&thread_data);
- }
- else {
- BLI_init_threads(&threads, ptcache_bake_thread, 1);
- BLI_insert_thread(&threads, (void*)&thread_data);
+ /* bake */
- while (thread_data.thread_ended == false) {
+ bool use_timer = false;
+ double stime, ptime, ctime, fetd;
+ char run[32], cur[32], etd[32];
+ int cancel = 0;
- if (bake)
- progress = (int)(100.0f * (float)(CFRA - startframe)/(float)(thread_data.endframe-startframe));
- else
- progress = CFRA;
+ stime = ptime = PIL_check_seconds_timer();
- /* NOTE: baking should not redraw whole ui as this slows things down */
- if ((baker->progressbar) && (progress != old_progress)) {
- baker->progressbar(baker->progresscontext, progress);
- old_progress = progress;
- }
+ for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
+ BKE_scene_update_for_newframe(G.main->eval_ctx, bmain, scene, scene->lay);
+
+ if (baker->update_progress) {
+ float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe));
+ baker->update_progress(baker->bake_job, progress, &cancel);
+ }
+
+ if (G.background) {
+ printf("bake: frame %d :: %d\n", CFRA, endframe);
+ }
+ else {
+ ctime = PIL_check_seconds_timer();
+
+ fetd = (ctime - ptime) * (endframe - CFRA) / baker->quick_step;
- /* Delay to lessen CPU load from UI thread */
- PIL_sleep_ms(200);
+ if (use_timer || fetd > 60.0) {
+ use_timer = true;
+
+ ptcache_dt_to_str(cur, ctime - ptime);
+ ptcache_dt_to_str(run, ctime - stime);
+ ptcache_dt_to_str(etd, fetd);
- /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
- if (blender_test_break() && !thread_data.break_operation) {
- thread_data.break_operation = true;
- if (baker->progressend)
- baker->progressend(baker->progresscontext);
- WM_cursor_wait(1);
+ printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s\r",
+ run, CFRA - startframe + 1, endframe - startframe + 1, ctime - ptime, etd);
}
+
+ ptime = ctime;
+ }
+
+ /* NOTE: breaking baking should leave calculated frames in cache, not clear it */
+ if ((cancel || G.is_break)) {
+ break;
}
- BLI_end_threads(&threads);
+ CFRA += 1;
}
+
+ if (use_timer) {
+ /* start with newline because of \r above */
+ ptcache_dt_to_str(run, PIL_check_seconds_timer()-stime);
+ printf("\nBake %s %s (%i frames simulated).\n", (cancel ? "canceled after" : "finished in"), run, CFRA - startframe);
+ }
+
/* clear baking flag */
if (pid) {
cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED);
@@ -3378,7 +3715,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
cache = pid->cache;
- if (thread_data.step > 1)
+ if (baker->quick_step > 1)
cache->flag &= ~(PTCACHE_BAKING|PTCACHE_OUTDATED);
else
cache->flag &= ~(PTCACHE_BAKING|PTCACHE_REDO_NEEDED);
@@ -3402,13 +3739,6 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
}
- if (thread_data.break_operation)
- WM_cursor_wait(0);
- else if (baker->progressend)
- baker->progressend(baker->progresscontext);
-
- WM_cursor_wait(0);
-
/* TODO: call redraw all windows somehow */
}
/* Helpers */
@@ -3529,7 +3859,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
return;
}
- BLI_snprintf(ext, sizeof(ext), "_%02u"PTCACHE_EXT, pid->stack_index);
+ const char *fext = ptcache_file_extension(pid);
+
+ BLI_snprintf(ext, sizeof(ext), "_%02u%s", pid->stack_index, fext);
/* put new name into cache */
BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name));
@@ -3538,13 +3870,9 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
- int frame, len2 = (int)strlen(de->d_name);
- char num[7];
-
- if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
- BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
- frame = atoi(num);
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+ if (frame != -1) {
BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name);
ptcache_filename(pid, new_path_full, frame, 1, 1);
BLI_rename(old_path_full, new_path_full);
@@ -3584,22 +3912,20 @@ void BKE_ptcache_load_external(PTCacheID *pid)
if (dir==NULL)
return;
+ const char *fext = ptcache_file_extension(pid);
+
if (cache->index >= 0)
- BLI_snprintf(ext, sizeof(ext), "_%02d"PTCACHE_EXT, cache->index);
+ BLI_snprintf(ext, sizeof(ext), "_%02d%s", cache->index, fext);
else
- BLI_strncpy(ext, PTCACHE_EXT, sizeof(ext));
+ BLI_strncpy(ext, fext, sizeof(ext));
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
- int frame, len2 = (int)strlen(de->d_name);
- char num[7];
-
- if (len2 > 15) { /* could crash if trying to copy a string out of this range*/
- BLI_strncpy(num, de->d_name + (strlen(de->d_name) - 15), sizeof(num));
- frame = atoi(num);
+ const int frame = ptcache_frame_from_filename(de->d_name, ext);
+ if (frame != -1) {
if (frame) {
start = MIN2(start, frame);
end = MAX2(end, frame);
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
index 100df5fd121..dc4063b42ed 100644
--- a/source/blender/blenkernel/intern/property.c
+++ b/source/blender/blenkernel/intern/property.c
@@ -142,8 +142,8 @@ void BKE_bproperty_object_set(Object *ob, bProperty *propc)
bProperty *prop;
prop = BKE_bproperty_object_get(ob, propc->name);
if (prop) {
- BKE_bproperty_free(prop);
BLI_remlink(&ob->prop, prop);
+ BKE_bproperty_free(prop);
}
BLI_addtail(&ob->prop, BKE_bproperty_copy(propc));
}
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index 3b371ce1e2f..67b076c0153 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -43,7 +43,7 @@
#include "BKE_report.h"
#include "BKE_global.h" /* G.background only */
-static const char *report_type_str(int type)
+const char *BKE_report_type_str(ReportType type)
{
switch (type) {
case RPT_DEBUG:
@@ -109,7 +109,7 @@ void BKE_report(ReportList *reports, ReportType type, const char *_message)
/* in background mode always print otherwise there are cases the errors wont be displayed,
* but still add to the report list since this is used for python exception handling */
if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
- printf("%s: %s\n", report_type_str(type), message);
+ printf("%s: %s\n", BKE_report_type_str(type), message);
fflush(stdout); /* this ensures the message is printed before a crash */
}
@@ -117,7 +117,7 @@ void BKE_report(ReportList *reports, ReportType type, const char *_message)
char *message_alloc;
report = MEM_callocN(sizeof(Report), "Report");
report->type = type;
- report->typestr = report_type_str(type);
+ report->typestr = BKE_report_type_str(type);
len = strlen(message);
message_alloc = MEM_callocN(sizeof(char) * (len + 1), "ReportMessage");
@@ -136,7 +136,7 @@ void BKE_reportf(ReportList *reports, ReportType type, const char *_format, ...)
const char *format = TIP_(_format);
if (G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
- printf("%s: ", report_type_str(type));
+ printf("%s: ", BKE_report_type_str(type));
va_start(args, _format);
vprintf(format, args);
va_end(args);
@@ -157,7 +157,7 @@ void BKE_reportf(ReportList *reports, ReportType type, const char *_format, ...)
BLI_dynstr_free(ds);
report->type = type;
- report->typestr = report_type_str(type);
+ report->typestr = BKE_report_type_str(type);
BLI_addtail(&reports->list, report);
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 476b9a22238..0f1f9b4bdf7 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -58,6 +58,7 @@
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
@@ -957,6 +958,20 @@ void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw)
rbw->effector_weights->group = (Group *)rbw->effector_weights->group->id.newid;
}
+void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata)
+{
+ func(rbw, (ID **)&rbw->group, userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_NOP);
+ func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_NOP);
+
+ if (rbw->objects) {
+ int i;
+ for (i = 0; i < rbw->numbodies; i++) {
+ func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_NOP);
+ }
+ }
+}
+
/* Add rigid body settings to the specified object */
RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
{
@@ -1597,6 +1612,7 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(
struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; }
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {}
+void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {}
struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; }
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index c902659c039..e90a39e8c0e 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -48,6 +48,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_sca.h"
/* ******************* SENSORS ************************ */
@@ -434,9 +435,6 @@ void init_actuator(bActuator *act)
oa= act->data;
oa->flag= 15;
break;
- case ACT_IPO:
- act->data= MEM_callocN(sizeof(bIpoActuator), "ipoact");
- break;
case ACT_PROPERTY:
act->data= MEM_callocN(sizeof(bPropertyActuator), "propact");
break;
@@ -903,6 +901,178 @@ void unlink_logicbricks(void **poin, void ***ppoin, short *tot)
}
}
+void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *userdata)
+{
+ bSensor *sensor;
+
+ for (sensor = senslist->first; sensor; sensor = sensor->next) {
+ func(sensor, (ID **)&sensor->ob, userdata, IDWALK_NOP);
+
+ switch (sensor->type) {
+ case SENS_TOUCH: /* DEPRECATED */
+ {
+ bTouchSensor *ts = sensor->data;
+ func(sensor, (ID **)&ts->ma, userdata, IDWALK_NOP);
+ break;
+ }
+ case SENS_MESSAGE:
+ {
+ bMessageSensor *ms = sensor->data;
+ func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_NOP);
+ break;
+ }
+ case SENS_ALWAYS:
+ case SENS_NEAR:
+ case SENS_KEYBOARD:
+ case SENS_PROPERTY:
+ case SENS_MOUSE:
+ case SENS_COLLISION:
+ case SENS_RADAR:
+ case SENS_RANDOM:
+ case SENS_RAY:
+ case SENS_JOYSTICK:
+ case SENS_ACTUATOR:
+ case SENS_DELAY:
+ case SENS_ARMATURE:
+ default:
+ break;
+ }
+ }
+}
+
+void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, void *userdata)
+{
+ bController *controller;
+
+ for (controller = contlist->first; controller; controller = controller->next) {
+ switch (controller->type) {
+ case CONT_PYTHON:
+ {
+ bPythonCont *pc = controller->data;
+ func(controller, (ID **)&pc->text, userdata, IDWALK_NOP);
+ break;
+ }
+ case CONT_LOGIC_AND:
+ case CONT_LOGIC_OR:
+ case CONT_EXPRESSION:
+ case CONT_LOGIC_NAND:
+ case CONT_LOGIC_NOR:
+ case CONT_LOGIC_XOR:
+ case CONT_LOGIC_XNOR:
+ default:
+ break;
+ }
+ }
+}
+
+void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *userdata)
+{
+ bActuator *actuator;
+
+ for (actuator = actlist->first; actuator; actuator = actuator->next) {
+ func(actuator, (ID **)&actuator->ob, userdata, IDWALK_NOP);
+
+ switch (actuator->type) {
+ case ACT_ADD_OBJECT: /* DEPRECATED */
+ {
+ bAddObjectActuator *aoa = actuator->data;
+ func(actuator, (ID **)&aoa->ob, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_ACTION:
+ {
+ bActionActuator *aa = actuator->data;
+ func(actuator, (ID **)&aa->act, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_SOUND:
+ {
+ bSoundActuator *sa = actuator->data;
+ func(actuator, (ID **)&sa->sound, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_EDIT_OBJECT:
+ {
+ bEditObjectActuator *eoa = actuator->data;
+ func(actuator, (ID **)&eoa->ob, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&eoa->me, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_SCENE:
+ {
+ bSceneActuator *sa = actuator->data;
+ func(actuator, (ID **)&sa->scene, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->camera, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_PROPERTY:
+ {
+ bPropertyActuator *pa = actuator->data;
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_OBJECT:
+ {
+ bObjectActuator *oa = actuator->data;
+ func(actuator, (ID **)&oa->reference, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_CAMERA:
+ {
+ bCameraActuator *ca = actuator->data;
+ func(actuator, (ID **)&ca->ob, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_MESSAGE:
+ {
+ bMessageActuator *ma = actuator->data;
+ func(actuator, (ID **)&ma->toObject, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_2DFILTER:
+ {
+ bTwoDFilterActuator *tdfa = actuator->data;
+ func(actuator, (ID **)&tdfa->text, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_PARENT:
+ {
+ bParentActuator *pa = actuator->data;
+ func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_ARMATURE:
+ {
+ bArmatureActuator *aa = actuator->data;
+ func(actuator, (ID **)&aa->target, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_NOP);
+ break;
+ }
+ case ACT_STEERING:
+ {
+ bSteeringActuator *sa = actuator->data;
+ func(actuator, (ID **)&sa->target, userdata, IDWALK_NOP);
+ func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_NOP);
+ break;
+ }
+ /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */
+ case ACT_LAMP:
+ case ACT_MATERIAL:
+ case ACT_END_OBJECT: /* DEPRECATED */
+ case ACT_CONSTRAINT:
+ case ACT_GROUP:
+ case ACT_RANDOM:
+ case ACT_GAME:
+ case ACT_VISIBILITY:
+ case ACT_SHAPEACTION:
+ case ACT_STATE:
+ case ACT_MOUSE:
+ default:
+ break;
+ }
+ }
+}
+
const char *sca_state_name_get(Object *ob, short bit)
{
bController *cont;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index f9ca66b443c..c0b79118467 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -90,11 +90,6 @@
#include "BKE_unit.h"
#include "BKE_world.h"
-#ifdef WITH_OPENSUBDIV
-# include "BKE_modifier.h"
-# include "CCGSubSurf.h"
-#endif
-
#include "DEG_depsgraph.h"
#include "RE_engine.h"
@@ -175,6 +170,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
rl = scen->r.layers;
rv = scen->r.views;
+ curvemapping_free_data(&scen->r.mblur_shutter_curve);
scen->r = sce->r;
scen->r.layers = rl;
scen->r.actlay = 0;
@@ -188,6 +184,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
scen->id.properties = IDP_CopyProperty(sce->id.properties);
MEM_freeN(scen->toolsettings);
+ BKE_sound_destroy_scene(scen);
}
else {
scen = BKE_libblock_copy(&sce->id);
@@ -197,7 +194,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
id_us_plus((ID *)scen->world);
id_us_plus((ID *)scen->set);
- id_us_plus((ID *)scen->gm.dome.warptext);
+ /* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */
scen->ed = NULL;
scen->theDag = NULL;
@@ -231,14 +228,6 @@ Scene *BKE_scene_copy(Scene *sce, int type)
base = base->next;
}
- /* copy color management settings */
- BKE_color_managed_display_settings_copy(&scen->display_settings, &sce->display_settings);
- BKE_color_managed_view_settings_copy(&scen->view_settings, &sce->view_settings);
- BKE_color_managed_view_settings_copy(&scen->r.im_format.view_settings, &sce->r.im_format.view_settings);
-
- BLI_strncpy(scen->sequencer_colorspace_settings.name, sce->sequencer_colorspace_settings.name,
- sizeof(scen->sequencer_colorspace_settings.name));
-
/* copy action and remove animation used by sequencer */
BKE_animdata_copy_id_action(&scen->id);
@@ -261,6 +250,19 @@ Scene *BKE_scene_copy(Scene *sce, int type)
}
}
+ /* copy color management settings */
+ BKE_color_managed_display_settings_copy(&scen->display_settings, &sce->display_settings);
+ BKE_color_managed_view_settings_copy(&scen->view_settings, &sce->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&scen->sequencer_colorspace_settings, &sce->sequencer_colorspace_settings);
+
+ BKE_color_managed_display_settings_copy(&scen->r.im_format.display_settings, &sce->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&scen->r.im_format.view_settings, &sce->r.im_format.view_settings);
+
+ BKE_color_managed_display_settings_copy(&scen->r.bake.im_format.display_settings, &sce->r.bake.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&scen->r.bake.im_format.view_settings, &sce->r.bake.im_format.view_settings);
+
+ curvemapping_copy_data(&scen->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
+
/* tool settings */
scen->toolsettings = MEM_dupallocN(sce->toolsettings);
@@ -371,7 +373,7 @@ void BKE_scene_free(Scene *sce)
base = sce->base.first;
while (base) {
- base->object->id.us--;
+ id_us_min(&base->object->id);
base = base->next;
}
/* do not free objects! */
@@ -381,7 +383,7 @@ void BKE_scene_free(Scene *sce)
/* since the grease pencil data is freed before the scene.
* since grease pencil data is not (yet?), shared between objects
* its probably safe not to do this, some save and reload will free this. */
- sce->gpd->id.us--;
+ id_us_min(&sce->gpd->id);
#endif
sce->gpd = NULL;
}
@@ -462,17 +464,19 @@ void BKE_scene_free(Scene *sce)
BKE_color_managed_view_settings_free(&sce->view_settings);
BKE_previewimg_free(&sce->preview);
+ curvemapping_free_data(&sce->r.mblur_shutter_curve);
}
-Scene *BKE_scene_add(Main *bmain, const char *name)
+void BKE_scene_init(Scene *sce)
{
- Scene *sce;
ParticleEditSettings *pset;
int a;
const char *colorspace_name;
SceneRenderView *srv;
+ CurveMapping *mblur_shutter_curve;
+
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id));
- sce = BKE_libblock_alloc(bmain, ID_SCE, name);
sce->lay = sce->layact = 1;
sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE;
@@ -529,6 +533,7 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->r.bake_biasdist = 0.001;
sce->r.bake.flag = R_BAKE_CLEAR;
+ sce->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
sce->r.bake.width = 512;
sce->r.bake.height = 512;
sce->r.bake.margin = 16;
@@ -574,6 +579,14 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
sce->r.unit_line_thickness = 1.0f;
+ mblur_shutter_curve = &sce->r.mblur_shutter_curve;
+ curvemapping_set_defaults(mblur_shutter_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(mblur_shutter_curve);
+ curvemap_reset(mblur_shutter_curve->cm,
+ &mblur_shutter_curve->clipr,
+ CURVE_PRESET_MAX,
+ CURVEMAP_SLOPE_POS_NEG);
+
sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
sce->toolsettings->doublimit = 0.001;
sce->toolsettings->vgroup_weight = 1.0f;
@@ -603,6 +616,12 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+ sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
+ sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
+ sce->toolsettings->curve_paint_settings.error_threshold = 8;
+ sce->toolsettings->curve_paint_settings.radius_max = 1.0f;
+ sce->toolsettings->curve_paint_settings.corner_angle = DEG2RADF(70.0f);
+
sce->toolsettings->statvis.overhang_axis = OB_NEGZ;
sce->toolsettings->statvis.overhang_min = 0;
sce->toolsettings->statvis.overhang_max = DEG2RADF(45.0f);
@@ -637,14 +656,14 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
pset->fade_frames = 2;
pset->selectmode = SCE_SELECT_PATH;
for (a = 0; a < PE_TOT_BRUSH; a++) {
- pset->brush[a].strength = 0.5;
+ pset->brush[a].strength = 0.5f;
pset->brush[a].size = 50;
pset->brush[a].step = 10;
pset->brush[a].count = 10;
}
- pset->brush[PE_BRUSH_CUT].strength = 100;
+ pset->brush[PE_BRUSH_CUT].strength = 1.0f;
- sce->r.ffcodecdata.audio_mixrate = 44100;
+ sce->r.ffcodecdata.audio_mixrate = 48000;
sce->r.ffcodecdata.audio_volume = 1.0f;
sce->r.ffcodecdata.audio_bitrate = 192;
sce->r.ffcodecdata.audio_channels = 2;
@@ -743,6 +762,62 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
sce->preview = NULL;
+
+ /* GP Sculpt brushes */
+ {
+ GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt;
+ GP_EditBrush_Data *gp_brush;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
+ gp_brush->size = 50;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.3f;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
+ gp_brush->size = 50;
+ gp_brush->strength = 0.3f; // XXX?
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
+ gp_brush->size = 50;
+ gp_brush->strength = 0.5f; // XXX?
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
+ gp_brush->size = 25;
+ gp_brush->strength = 0.5f;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ }
+
+ /* GP Stroke Placement */
+ sce->toolsettings->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
+ sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
+ sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
+ sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+}
+
+Scene *BKE_scene_add(Main *bmain, const char *name)
+{
+ Scene *sce;
+
+ sce = BKE_libblock_alloc(bmain, ID_SCE, name);
+
+ BKE_scene_init(sce);
return sce;
}
@@ -820,7 +895,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
/* no full animation update, this to enable render code to work (render code calls own animation updates) */
}
-/* called from creator.c */
+/* called from creator_args.c */
Scene *BKE_scene_set_name(Main *bmain, const char *name)
{
Scene *sce = (Scene *)BKE_libblock_find_name_ex(bmain, ID_SCE, name);
@@ -1364,11 +1439,6 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
-/* Need this because CCFDM holds some OpenGL resources. */
-#ifdef WITH_OPENSUBDIV
-# define OPENSUBDIV_GL_WORKAROUND
-#endif
-
#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
@@ -1414,7 +1484,7 @@ static void scene_update_all_bases(EvaluationContext *eval_ctx, Scene *scene, Sc
}
}
-static void scene_update_object_func(TaskPool *pool, void *taskdata, int threadid)
+static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid)
{
/* Disable print for now in favor of summary statistics at the end of update. */
#define PRINT if (false) printf
@@ -1570,47 +1640,6 @@ static bool scene_need_update_objects(Main *bmain)
DAG_id_type_tagged(bmain, ID_AR); /* Armature */
}
-#ifdef OPENSUBDIV_GL_WORKAROUND
-/* CCG DrivedMesh currently hold some OpenGL handles, which could only be
- * released from the main thread.
- *
- * Ideally we need to use gpu_buffer_free, but it's a bit tricky because
- * some buffers are only accessible from OpenSubdiv side.
- */
-static void scene_free_unused_opensubdiv_cache(Scene *scene)
-{
- Base *base;
- for (base = scene->base.first; base; base = base->next) {
- Object *object = base->object;
- if (object->type == OB_MESH && object->recalc & OB_RECALC_DATA) {
- ModifierData *md = object->modifiers.last;
- if (md != NULL && md->type == eModifierType_Subsurf) {
- SubsurfModifierData *smd = (SubsurfModifierData *) md;
- bool object_in_editmode = object->mode == OB_MODE_EDIT;
- if (!smd->use_opensubdiv ||
- DAG_get_eval_flags_for_object(scene, object) & DAG_EVAL_NEED_CPU)
- {
- if (smd->mCache != NULL) {
- ccgSubSurf_free_osd_mesh(smd->mCache);
- }
- if (smd->emCache != NULL) {
- ccgSubSurf_free_osd_mesh(smd->emCache);
- }
- }
- if (object_in_editmode && smd->mCache != NULL) {
- ccgSubSurf_free(smd->mCache);
- smd->mCache = NULL;
- }
- if (!object_in_editmode && smd->emCache != NULL) {
- ccgSubSurf_free(smd->emCache);
- smd->emCache = NULL;
- }
- }
- }
- }
-}
-#endif
-
static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
{
TaskScheduler *task_scheduler = BLI_task_scheduler_get();
@@ -1629,10 +1658,6 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
return;
}
-#ifdef OPENSUBDIV_GL_WORKAROUND
- scene_free_unused_opensubdiv_cache(scene);
-#endif
-
state.eval_ctx = eval_ctx;
state.scene = scene;
state.scene_parent = scene_parent;
@@ -1744,8 +1769,8 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
if (obedit) {
Mesh *mesh = obedit->data;
if ((obedit->type == OB_MESH) &&
- ((obedit->id.flag & LIB_ID_RECALC_ALL) ||
- (mesh->id.flag & LIB_ID_RECALC_ALL)))
+ ((obedit->id.tag & LIB_TAG_ID_RECALC_ALL) ||
+ (mesh->id.tag & LIB_TAG_ID_RECALC_ALL)))
{
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_btmesh->bm;
@@ -1788,11 +1813,11 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
/* removed calls to quick_cache, see pointcache.c */
- /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
+ /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, false);
+ BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
/* update all objects: drivers, matrices, displists, etc. flags set
* by depgraph or manual, no layer check here, gets correct flushed
@@ -1806,11 +1831,6 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
else
#endif
{
-#ifdef OPENSUBDIV_GL_WORKAROUND
- if (DEG_needs_eval(scene->depsgraph)) {
- scene_free_unused_opensubdiv_cache(scene);
- }
-#endif
DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
/* TODO(sergey): This is to beocme a node in new depsgraph. */
BKE_mask_update_scene(bmain, scene);
@@ -1952,11 +1972,11 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
}
#endif
- /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
+ /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, false);
+ BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
+ BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
/* run rigidbody sim */
/* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
@@ -2174,8 +2194,14 @@ bool BKE_scene_use_new_shading_nodes(const Scene *scene)
bool BKE_scene_use_shading_nodes_custom(Scene *scene)
{
- RenderEngineType *type = RE_engines_find(scene->r.engine);
- return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
+}
+
+bool BKE_scene_use_spherical_stereo(Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return (type && type->flag & RE_USE_SPHERICAL_STEREO);
}
bool BKE_scene_uses_blender_internal(const Scene *scene)
@@ -2287,10 +2313,10 @@ double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, doubl
/******************** multiview *************************/
-size_t BKE_scene_multiview_num_views_get(const RenderData *rd)
+int BKE_scene_multiview_num_views_get(const RenderData *rd)
{
SceneRenderView *srv;
- size_t totviews = 0;
+ int totviews = 0;
if ((rd->scemode & R_MULTIVIEW) == 0)
return 1;
@@ -2423,7 +2449,7 @@ const char *BKE_scene_multiview_render_view_name_get(const RenderData *rd, const
return "";
}
-size_t BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
+int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
{
SceneRenderView *srv;
size_t nr;
@@ -2494,7 +2520,7 @@ const char *BKE_scene_multiview_view_suffix_get(const RenderData *rd, const char
return viewname;
}
-const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const size_t view_id)
+const char *BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, const int view_id)
{
if ((rd->scemode & R_MULTIVIEW) == 0) {
return "";
@@ -2516,13 +2542,15 @@ void BKE_scene_multiview_view_prefix_get(Scene *scene, const char *name, char *r
/* begin of extension */
index_act = BLI_str_rpartition(name, delims, rext, &suf_act);
+ if (*rext == NULL)
+ return;
BLI_assert(index_act > 0);
UNUSED_VARS_NDEBUG(index_act);
for (srv = scene->r.views.first; srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) {
size_t len = strlen(srv->suffix);
- if (STREQLEN(*rext - len, srv->suffix, len)) {
+ if (strlen(*rext) >= len && STREQLEN(*rext - len, srv->suffix, len)) {
BLI_strncpy(rprefix, name, strlen(name) - strlen(*rext) - len + 1);
break;
}
@@ -2549,7 +2577,7 @@ void BKE_scene_multiview_videos_dimensions_get(
}
}
-size_t BKE_scene_multiview_num_videos_get(const RenderData *rd)
+int BKE_scene_multiview_num_videos_get(const RenderData *rd)
{
if (BKE_imtype_is_movie(rd->im_format.imtype) == false)
return 0;
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 7401ef28f62..139c6670f74 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -180,6 +180,7 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
BLI_listbase_clear(&newar->panels_category_active);
BLI_listbase_clear(&newar->ui_lists);
newar->swinid = 0;
+ newar->regiontimer = NULL;
/* use optional regiondata callback */
if (ar->regiondata) {
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index f375c2b1e4f..1b807adca4b 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -146,6 +146,11 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1,
if (out->rect_float)
IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
+ /* If effect only affecting a single channel, forward input's metadata to the output. */
+ if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) {
+ IMB_metadata_copy(out, ibuf1);
+ }
+
return out;
}
@@ -860,9 +865,10 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned
x = xo;
while (x--) {
- rt[0] = min_ii(cp1[0] + ((fac1 * cp2[0]) >> 8), 255);
- rt[1] = min_ii(cp1[1] + ((fac1 * cp2[1]) >> 8), 255);
- rt[2] = min_ii(cp1[2] + ((fac1 * cp2[2]) >> 8), 255);
+ const int m = fac1 * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
rt[3] = cp1[3];
cp1 += 4; cp2 += 4; rt += 4;
@@ -874,9 +880,10 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned
x = xo;
while (x--) {
- rt[0] = min_ii(cp1[0] + ((fac3 * cp2[0]) >> 8), 255);
- rt[1] = min_ii(cp1[1] + ((fac3 * cp2[1]) >> 8), 255);
- rt[2] = min_ii(cp1[2] + ((fac3 * cp2[2]) >> 8), 255);
+ const int m = fac3 * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
rt[3] = cp1[3];
cp1 += 4; cp2 += 4; rt += 4;
@@ -887,7 +894,7 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned
static void do_add_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
{
int xo;
- float m, fac1, fac3;
+ float fac1, fac3;
float *rt1, *rt2, *rt;
xo = x;
@@ -901,7 +908,7 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r
while (y--) {
x = xo;
while (x--) {
- m = 1.0f - (rt1[3] * (1.0f - fac1));
+ const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3];
rt[0] = rt1[0] + m * rt2[0];
rt[1] = rt1[1] + m * rt2[1];
rt[2] = rt1[2] + m * rt2[2];
@@ -916,7 +923,7 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r
x = xo;
while (x--) {
- m = 1.0f - (rt1[3] * (1.0f - fac3));
+ const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3];
rt[0] = rt1[0] + m * rt2[0];
rt[1] = rt1[1] + m * rt2[1];
rt[2] = rt1[2] + m * rt2[2];
@@ -964,9 +971,10 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned
while (y--) {
x = xo;
while (x--) {
- rt[0] = max_ii(cp1[0] - ((fac1 * cp2[0]) >> 8), 0);
- rt[1] = max_ii(cp1[1] - ((fac1 * cp2[1]) >> 8), 0);
- rt[2] = max_ii(cp1[2] - ((fac1 * cp2[2]) >> 8), 0);
+ const int m = fac1 * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
rt[3] = cp1[3];
cp1 += 4; cp2 += 4; rt += 4;
@@ -978,9 +986,10 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned
x = xo;
while (x--) {
- rt[0] = max_ii(cp1[0] - ((fac3 * cp2[0]) >> 8), 0);
- rt[1] = max_ii(cp1[1] - ((fac3 * cp2[1]) >> 8), 0);
- rt[2] = max_ii(cp1[2] - ((fac3 * cp2[2]) >> 8), 0);
+ const int m = fac3 * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
rt[3] = cp1[3];
cp1 += 4; cp2 += 4; rt += 4;
@@ -991,7 +1000,7 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned
static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out)
{
int xo;
- float m /*, fac1*/, fac3;
+ float /* fac1, */ fac3_inv;
float *rt1, *rt2, *rt;
xo = x;
@@ -1001,12 +1010,12 @@ static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y,
/* UNUSED */
// fac1 = facf0;
- fac3 = facf1;
+ fac3_inv = 1.0f - facf1;
while (y--) {
x = xo;
while (x--) {
- m = 1.0f - (rt1[3] * (1 - fac3));
+ const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
@@ -1021,7 +1030,7 @@ static void do_sub_effect_float(float UNUSED(facf0), float facf1, int x, int y,
x = xo;
while (x--) {
- m = 1.0f - (rt1[3] * (1 - fac3));
+ const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
@@ -1536,7 +1545,7 @@ static void init_wipe_effect(Sequence *seq)
static int num_inputs_wipe(void)
{
- return 1;
+ return 2;
}
static void free_wipe_effect(Sequence *seq)
@@ -2354,6 +2363,9 @@ static ImBuf *do_adjustment(const SeqRenderData *context, Sequence *seq, float c
if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
out = IMB_dupImBuf(i);
+ if (out) {
+ IMB_metadata_copy(out, i);
+ }
IMB_freeImBuf(i);
}
else {
@@ -2663,36 +2675,81 @@ static float *make_gaussian_blur_kernel(float rad, int size)
return gausstab;
}
-static void do_gaussian_blur_effect_byte(Sequence *seq,
- int start_line,
- int x, int y,
- int frame_width, int frame_height,
- unsigned char *rect,
- unsigned char *out)
+static void do_gaussian_blur_effect_byte_x(Sequence *seq,
+ int start_line,
+ int x, int y,
+ int frame_width,
+ int UNUSED(frame_height),
+ unsigned char *rect,
+ unsigned char *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
const int size_x = (int) (data->size_x + 0.5f);
- const int size_y = (int) (data->size_y + 0.5f);
int i, j;
/* Make gaussian weight tabke. */
- float *gausstab_x, *gausstab_y;
+ float *gausstab_x;
gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
- if (data->size_x == data->size_y) {
- gausstab_y = gausstab_x;
- }
- else {
- gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+
+ for (int current_x = j - size_x;
+ current_x <= j + size_x;
+ ++current_x)
+ {
+ if (current_x < 0 || current_x >= frame_width) {
+ /* Out of bounds. */
+ continue;
+ }
+ int index = INDEX(current_x, i + start_line);
+ float weight = gausstab_x[current_x - j + size_x];
+ accum[0] += rect[index] * weight;
+ accum[1] += rect[index + 1] * weight;
+ accum[2] += rect[index + 2] * weight;
+ accum[3] += rect[index + 3] * weight;
+ accum_weight += weight;
+ }
+
+ float inv_accum_weight = 1.0f / accum_weight;
+ out[out_index + 0] = accum[0] * inv_accum_weight;
+ out[out_index + 1] = accum[1] * inv_accum_weight;
+ out[out_index + 2] = accum[2] * inv_accum_weight;
+ out[out_index + 3] = accum[3] * inv_accum_weight;
+ }
}
+ MEM_freeN(gausstab_x);
+#undef INDEX
+}
+
+static void do_gaussian_blur_effect_byte_y(Sequence *seq,
+ int start_line,
+ int x, int y,
+ int UNUSED(frame_width),
+ int frame_height,
+ unsigned char *rect,
+ unsigned char *out)
+{
+#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_y = (int) (data->size_y + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight tabke. */
+ float *gausstab_y;
+ gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
+
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
int out_index = INDEX(j, i);
- int current_x, current_y;
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (current_y = i - size_y;
+ for (int current_y = i - size_y;
current_y <= i + size_y;
++current_y)
{
@@ -2702,144 +2759,182 @@ static void do_gaussian_blur_effect_byte(Sequence *seq,
/* Out of bounds. */
continue;
}
+ int index = INDEX(j, current_y + start_line);
+ float weight = gausstab_y[current_y - i + size_y];
+ accum[0] += rect[index] * weight;
+ accum[1] += rect[index + 1] * weight;
+ accum[2] += rect[index + 2] * weight;
+ accum[3] += rect[index + 3] * weight;
+ accum_weight += weight;
+ }
+ float inv_accum_weight = 1.0f / accum_weight;
+ out[out_index + 0] = accum[0] * inv_accum_weight;
+ out[out_index + 1] = accum[1] * inv_accum_weight;
+ out[out_index + 2] = accum[2] * inv_accum_weight;
+ out[out_index + 3] = accum[3] * inv_accum_weight;
+ }
+ }
- for (current_x = j - size_x;
- current_x <= j + size_x;
- ++current_x)
- {
- float weight;
- int index = INDEX(current_x, current_y + start_line);
- if (current_x < 0 || current_x >= frame_width) {
- /* Out of bounds. */
- continue;
- }
- BLI_assert(index >= 0);
- BLI_assert(index < frame_width * frame_height * 4);
-
- if (size_x != 0 && size_y != 0) {
- weight = gausstab_x[current_x - j + size_x] *
- gausstab_y[current_y - i + size_y];
- }
- else if (size_x == 0) {
- weight = gausstab_y[current_y - i + size_y];
- }
- else {
- weight = gausstab_x[current_x - j + size_x];
- }
- accum[0] += rect[index] * weight;
- accum[1] += rect[index + 1] * weight;
- accum[2] += rect[index + 2] * weight;
- accum[3] += rect[index + 3] * weight;
- accum_weight += weight;
+ MEM_freeN(gausstab_y);
+#undef INDEX
+}
+
+static void do_gaussian_blur_effect_float_x(Sequence *seq,
+ int start_line,
+ int x, int y,
+ int frame_width,
+ int UNUSED(frame_height),
+ float *rect,
+ float *out)
+{
+#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_x = (int) (data->size_x + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight tabke. */
+ float *gausstab_x;
+ gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+ for (int current_x = j - size_x;
+ current_x <= j + size_x;
+ ++current_x)
+ {
+ if (current_x < 0 || current_x >= frame_width) {
+ /* Out of bounds. */
+ continue;
}
+ int index = INDEX(current_x, i + start_line);
+ float weight = gausstab_x[current_x - j + size_x];
+ madd_v4_v4fl(accum, &rect[index], weight);
+ accum_weight += weight;
}
- out[out_index + 0] = accum[0] / accum_weight;
- out[out_index + 1] = accum[1] / accum_weight;
- out[out_index + 2] = accum[2] / accum_weight;
- out[out_index + 3] = accum[3] / accum_weight;
+ mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
}
}
MEM_freeN(gausstab_x);
- if (gausstab_x != gausstab_y) {
- MEM_freeN(gausstab_y);
- }
#undef INDEX
}
-static void do_gaussian_blur_effect_float(Sequence *seq,
- int start_line,
- int x, int y,
- int frame_width, int frame_height,
- float *rect,
- float *out)
+static void do_gaussian_blur_effect_float_y(Sequence *seq,
+ int start_line,
+ int x, int y,
+ int UNUSED(frame_width),
+ int frame_height,
+ float *rect,
+ float *out)
{
#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
GaussianBlurVars *data = seq->effectdata;
- const int size_x = (int) (data->size_x + 0.5f);
const int size_y = (int) (data->size_y + 0.5f);
int i, j;
/* Make gaussian weight tabke. */
- float *gausstab_x, *gausstab_y;
- gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
- if (data->size_x == data->size_y) {
- gausstab_y = gausstab_x;
- }
- else {
- gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
- }
+ float *gausstab_y;
+ gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j) {
int out_index = INDEX(j, i);
- int current_x, current_y;
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float accum_weight = 0.0f;
- for (current_y = i - size_y;
+ for (int current_y = i - size_y;
current_y <= i + size_y;
++current_y)
{
- float weight;
if (current_y < -start_line ||
current_y + start_line >= frame_height)
{
/* Out of bounds. */
continue;
}
-
- for (current_x = j - size_x;
- current_x <= j + size_x;
- ++current_x)
- {
- int index = INDEX(current_x, current_y + start_line);
- if (current_x < 0 || current_x >= frame_width) {
- /* Out of bounds. */
- continue;
- }
-
- if (size_x != 0 && size_y != 0) {
- weight = gausstab_x[current_x - j + size_x] *
- gausstab_y[current_y - i + size_y];
- }
- else if (size_x == 0) {
- weight = gausstab_y[current_y - i + size_y];
- }
- else {
- weight = gausstab_x[current_x - j + size_x];
- }
- madd_v4_v4fl(accum, &rect[index], weight);
- accum_weight += weight;
- }
+ int index = INDEX(j, current_y + start_line);
+ float weight = gausstab_y[current_y - i + size_y];
+ madd_v4_v4fl(accum, &rect[index], weight);
+ accum_weight += weight;
}
mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
}
}
- MEM_freeN(gausstab_x);
- if (gausstab_x != gausstab_y) {
- MEM_freeN(gausstab_y);
- }
+ MEM_freeN(gausstab_y);
#undef INDEX
}
-static void do_gaussian_blur_effect(const SeqRenderData *context,
- Sequence *seq,
- float UNUSED(cfra),
- float UNUSED(facf0),
- float UNUSED(facf1),
- ImBuf *ibuf1,
- ImBuf *ibuf2,
- ImBuf *UNUSED(ibuf3),
- int start_line,
- int total_lines,
- ImBuf *out)
+static void do_gaussian_blur_effect_x_cb(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(context,
+ ibuf,
+ NULL,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_float_x(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf->rect_float,
+ rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(context,
+ ibuf,
+ NULL,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_byte_x(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *) ibuf->rect,
+ rect_out);
+ }
+}
+
+static void do_gaussian_blur_effect_y_cb(const SeqRenderData *context,
+ Sequence *seq,
+ ImBuf *ibuf,
+ int start_line,
+ int total_lines,
+ ImBuf *out)
{
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_float_buffers(context,
- ibuf1, ibuf2,
+ ibuf,
+ NULL,
NULL,
out,
start_line,
@@ -2848,20 +2943,21 @@ static void do_gaussian_blur_effect(const SeqRenderData *context,
NULL,
&rect_out);
- do_gaussian_blur_effect_float(seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- ibuf1->rect_float,
- rect_out);
+ do_gaussian_blur_effect_float_y(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf->rect_float,
+ rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(context,
- ibuf1, ibuf2,
+ ibuf,
+ NULL,
NULL,
out,
start_line,
@@ -2870,17 +2966,114 @@ static void do_gaussian_blur_effect(const SeqRenderData *context,
NULL,
&rect_out);
- do_gaussian_blur_effect_byte(seq,
- start_line,
- context->rectx,
- total_lines,
- context->rectx,
- context->recty,
- (unsigned char *) ibuf1->rect,
- rect_out);
+ do_gaussian_blur_effect_byte_y(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *) ibuf->rect,
+ rect_out);
}
}
+typedef struct RenderGaussianBlurEffectInitData {
+ const SeqRenderData *context;
+ Sequence *seq;
+ ImBuf *ibuf;
+ ImBuf *out;
+} RenderGaussianBlurEffectInitData;
+
+typedef struct RenderGaussianBlurEffectThread {
+ const SeqRenderData *context;
+ Sequence *seq;
+ ImBuf *ibuf;
+ ImBuf *out;
+ int start_line, tot_line;
+} RenderGaussianBlurEffectThread;
+
+static void render_effect_execute_init_handle(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
+{
+ RenderGaussianBlurEffectThread *handle = (RenderGaussianBlurEffectThread *) handle_v;
+ RenderGaussianBlurEffectInitData *init_data = (RenderGaussianBlurEffectInitData *) init_data_v;
+
+ handle->context = init_data->context;
+ handle->seq = init_data->seq;
+ handle->ibuf = init_data->ibuf;
+ handle->out = init_data->out;
+
+ handle->start_line = start_line;
+ handle->tot_line = tot_line;
+}
+
+static void *render_effect_execute_do_x_thread(void *thread_data_v)
+{
+ RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
+ do_gaussian_blur_effect_x_cb(thread_data->context,
+ thread_data->seq,
+ thread_data->ibuf,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
+ return NULL;
+}
+
+static void *render_effect_execute_do_y_thread(void *thread_data_v)
+{
+ RenderGaussianBlurEffectThread *thread_data = (RenderGaussianBlurEffectThread *) thread_data_v;
+ do_gaussian_blur_effect_y_cb(thread_data->context,
+ thread_data->seq,
+ thread_data->ibuf,
+ thread_data->start_line,
+ thread_data->tot_line,
+ thread_data->out);
+
+ return NULL;
+}
+
+static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *UNUSED(ibuf2),
+ ImBuf *UNUSED(ibuf3))
+{
+ ImBuf *out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);
+
+ RenderGaussianBlurEffectInitData init_data;
+
+ init_data.context = context;
+ init_data.seq = seq;
+ init_data.ibuf = ibuf1;
+ init_data.out = out;
+
+ IMB_processor_apply_threaded(out->y,
+ sizeof(RenderGaussianBlurEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_x_thread);
+
+ ibuf1 = out;
+ init_data.ibuf = ibuf1;
+ out = prepare_effect_imbufs(context, ibuf1, NULL, NULL);;
+ init_data.out = out;
+
+ IMB_processor_apply_threaded(out->y,
+ sizeof(RenderGaussianBlurEffectThread),
+ &init_data,
+ render_effect_execute_init_handle,
+ render_effect_execute_do_y_thread);
+
+ IMB_freeImBuf(ibuf1);
+
+ return out;
+}
+
/*********************** text *************************/
static void init_text_effect(Sequence *seq)
{
@@ -3211,13 +3404,12 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.execute = do_adjustment;
break;
case SEQ_TYPE_GAUSSIAN_BLUR:
- rval.multithreaded = true;
rval.init = init_gaussian_blur_effect;
rval.num_inputs = num_inputs_gaussian_blur;
rval.free = free_gaussian_blur_effect;
rval.copy = copy_gaussian_blur_effect;
rval.early_out = early_out_gaussian_blur;
- rval.execute_slice = do_gaussian_blur_effect;
+ rval.execute = do_gaussian_blur_effect;
break;
case SEQ_TYPE_TEXT:
rval.num_inputs = num_inputs_text;
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 07242aa2f6e..95c6b7736e1 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -42,12 +42,14 @@
#include "BLT_translation.h"
#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
#include "BKE_colortools.h"
#include "BKE_sequencer.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_colormanagement.h"
static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
static bool modifierTypesInit = false;
@@ -173,6 +175,92 @@ static SequenceModifierTypeInfo seqModifier_ColorBalance = {
colorBalance_apply /* apply */
};
+/* **** White Balance Modifier **** */
+
+static void whiteBalance_init_data(SequenceModifierData *smd)
+{
+ WhiteBalanceModifierData *cbmd = (WhiteBalanceModifierData *) smd;
+ copy_v3_fl(cbmd->white_value, 1.0f);
+}
+
+typedef struct WhiteBalanceThreadData {
+ float white[3];
+} WhiteBalanceThreadData;
+
+static void whiteBalance_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
+ unsigned char *mask_rect, float *mask_rect_float, void *data_v)
+{
+ int x, y;
+ float multiplier[3];
+
+ WhiteBalanceThreadData *data = (WhiteBalanceThreadData *) data_v;
+
+ multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
+ multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
+ multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float result[4], mask[3] = {1.0f, 1.0f, 1.0f};
+
+ if (rect_float) {
+ copy_v3_v3(result, rect_float + pixel_index);
+ }
+ else {
+ straight_uchar_to_premul_float(result, rect + pixel_index);
+ }
+
+#if 0
+ mul_v3_v3(result, multiplier);
+#else
+ /* similar to division without the clipping */
+ for (int i = 0; i < 3; i++) {
+ result[i] = 1.0f - powf(1.0f - result[i], multiplier[i]);
+ }
+#endif
+
+ if (mask_rect_float) {
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ }
+ else if (mask_rect) {
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+ }
+
+ result[0] = result[0] * (1.0f - mask[0]) + result[0] * mask[0];
+ result[1] = result[1] * (1.0f - mask[1]) + result[1] * mask[1];
+ result[2] = result[2] * (1.0f - mask[2]) + result[2] * mask[2];
+
+ if (rect_float) {
+ copy_v3_v3(rect_float + pixel_index, result);
+ }
+ else {
+ premul_float_to_straight_uchar(rect + pixel_index, result);
+ }
+ }
+ }
+}
+
+static void whiteBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
+{
+ WhiteBalanceThreadData data;
+ WhiteBalanceModifierData *wbmd = (WhiteBalanceModifierData *) smd;
+
+ copy_v3_v3(data.white, wbmd->white_value);
+
+ modifier_apply_threaded(ibuf, mask, whiteBalance_apply_threaded, &data);
+}
+
+static SequenceModifierTypeInfo seqModifier_WhiteBalance = {
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"), /* name */
+ "WhiteBalanceModifierData", /* struct_name */
+ sizeof(WhiteBalanceModifierData), /* struct_size */
+ whiteBalance_init_data, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ whiteBalance_apply /* apply */
+};
+
/* **** Curves Modifier **** */
static void curves_init_data(SequenceModifierData *smd)
@@ -548,6 +636,227 @@ static SequenceModifierTypeInfo seqModifier_Mask = {
maskmodifier_apply /* apply */
};
+/* **** Tonemap Modifier **** */
+
+typedef struct AvgLogLum {
+ SequencerTonemapModifierData *tmmd;
+ struct ColorSpace *colorspace;
+ float al;
+ float auto_key;
+ float lav;
+ float cav[4];
+ float igm;
+} AvgLogLum;
+
+static void tonemapmodifier_init_data(SequenceModifierData *smd)
+{
+ SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
+ /* Same as tonemap compositor node. */
+ tmmd->type = SEQ_TONEMAP_RD_PHOTORECEPTOR;
+ tmmd->key = 0.18f;
+ tmmd->offset = 1.0f;
+ tmmd->gamma = 1.0f;
+ tmmd->intensity = 0.0f;
+ tmmd->contrast = 0.0f;
+ tmmd->adaptation = 1.0f;
+ tmmd->correction = 0.0f;
+}
+
+static void tonemapmodifier_apply_threaded_simple(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v)
+{
+ AvgLogLum *avg = (AvgLogLum *)data_v;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ /* Get input value. */
+ if (rect_float) {
+ copy_v4_v4(input, &rect_float[pixel_index]);
+ }
+ else {
+ straight_uchar_to_premul_float(input, &rect[pixel_index]);
+ }
+ IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
+ copy_v4_v4(output, input);
+ /* Get mask value. */
+ if (mask_rect_float) {
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ }
+ else if (mask_rect) {
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+ }
+ /* Apply correction. */
+ mul_v3_fl(output, avg->al);
+ float dr = output[0] + avg->tmmd->offset;
+ float dg = output[1] + avg->tmmd->offset;
+ float db = output[2] + avg->tmmd->offset;
+ output[0] /= ((dr == 0.0f) ? 1.0f : dr);
+ output[1] /= ((dg == 0.0f) ? 1.0f : dg);
+ output[2] /= ((db == 0.0f) ? 1.0f : db);
+ const float igm = avg->igm;
+ if (igm != 0.0f) {
+ output[0] = powf(max_ff(output[0], 0.0f), igm);
+ output[1] = powf(max_ff(output[1], 0.0f), igm);
+ output[2] = powf(max_ff(output[2], 0.0f), igm);
+ }
+ /* Apply mask. */
+ output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
+ output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
+ output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
+ /* Copy result back. */
+ IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
+ if (rect_float) {
+ copy_v4_v4(&rect_float[pixel_index], output);
+ }
+ else {
+ premul_float_to_straight_uchar(&rect[pixel_index], output);
+ }
+ }
+ }
+}
+
+static void tonemapmodifier_apply_threaded_photoreceptor(int width,
+ int height,
+ unsigned char *rect,
+ float *rect_float,
+ unsigned char *mask_rect,
+ float *mask_rect_float,
+ void *data_v)
+{
+ AvgLogLum *avg = (AvgLogLum *)data_v;
+ const float f = expf(-avg->tmmd->intensity);
+ const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
+ const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int pixel_index = (y * width + x) * 4;
+ float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
+ /* Get input value. */
+ if (rect_float) {
+ copy_v4_v4(input, &rect_float[pixel_index]);
+ }
+ else {
+ straight_uchar_to_premul_float(input, &rect[pixel_index]);
+ }
+ IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
+ copy_v4_v4(output, input);
+ /* Get mask value. */
+ if (mask_rect_float) {
+ copy_v3_v3(mask, mask_rect_float + pixel_index);
+ }
+ else if (mask_rect) {
+ rgb_uchar_to_float(mask, mask_rect + pixel_index);
+ }
+ /* Apply correction. */
+ const float L = IMB_colormanagement_get_luminance(output);
+ float I_l = output[0] + ic * (L - output[0]);
+ float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
+ float I_a = I_l + ia * (I_g - I_l);
+ output[0] /= (output[0] + powf(f * I_a, m));
+ I_l = output[1] + ic * (L - output[1]);
+ I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
+ I_a = I_l + ia * (I_g - I_l);
+ output[1] /= (output[1] + powf(f * I_a, m));
+ I_l = output[2] + ic * (L - output[2]);
+ I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
+ I_a = I_l + ia * (I_g - I_l);
+ output[2] /= (output[2] + powf(f * I_a, m));
+ /* Apply mask. */
+ output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
+ output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
+ output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
+ /* Copy result back. */
+ IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
+ if (rect_float) {
+ copy_v4_v4(&rect_float[pixel_index], output);
+ }
+ else {
+ premul_float_to_straight_uchar(&rect[pixel_index], output);
+ }
+ }
+ }
+}
+
+static void tonemapmodifier_apply(struct SequenceModifierData *smd,
+ ImBuf *ibuf,
+ ImBuf *mask)
+{
+ SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
+ AvgLogLum data;
+ data.tmmd = tmmd;
+ data.colorspace = (ibuf->rect_float != NULL)
+ ? ibuf->float_colorspace
+ : ibuf->rect_colorspace;
+ float lsum = 0.0f;
+ int p = ibuf->x * ibuf->y;
+ float *fp = ibuf->rect_float;
+ unsigned char *cp = (unsigned char *)ibuf->rect;
+ float avl, maxl = -FLT_MAX, minl = FLT_MAX;
+ const float sc = 1.0f / p;
+ float Lav = 0.f;
+ float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ while (p--) {
+ float pixel[4];
+ if (fp != NULL) {
+ copy_v4_v4(pixel, fp);
+ }
+ else {
+ straight_uchar_to_premul_float(pixel, cp);
+ }
+ IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, data.colorspace);
+ float L = IMB_colormanagement_get_luminance(pixel);
+ Lav += L;
+ add_v3_v3(cav, pixel);
+ lsum += logf(max_ff(L, 0.0f) + 1e-5f);
+ maxl = (L > maxl) ? L : maxl;
+ minl = (L < minl) ? L : minl;
+ if (fp != NULL) {
+ fp += 4;
+ }
+ else {
+ cp += 4;
+ }
+ }
+ data.lav = Lav * sc;
+ mul_v3_v3fl(data.cav, cav, sc);
+ maxl = logf(maxl + 1e-5f);
+ minl = logf(minl + 1e-5f);
+ avl = lsum * sc;
+ data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
+ float al = expf(avl);
+ data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
+ data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
+
+ if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
+ modifier_apply_threaded(ibuf,
+ mask,
+ tonemapmodifier_apply_threaded_photoreceptor,
+ &data);
+ }
+ else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
+ modifier_apply_threaded(ibuf,
+ mask,
+ tonemapmodifier_apply_threaded_simple,
+ &data);
+ }
+}
+
+static SequenceModifierTypeInfo seqModifier_Tonemap = {
+ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"), /* name */
+ "SequencerTonemapModifierData", /* struct_name */
+ sizeof(SequencerTonemapModifierData), /* struct_size */
+ tonemapmodifier_init_data, /* init_data */
+ NULL, /* free_data */
+ NULL, /* copy_data */
+ tonemapmodifier_apply /* apply */
+};
+
/*********************** Modifier functions *************************/
static void sequence_modifier_type_info_init(void)
@@ -559,6 +868,8 @@ static void sequence_modifier_type_info_init(void)
INIT_TYPE(HueCorrect);
INIT_TYPE(BrightContrast);
INIT_TYPE(Mask);
+ INIT_TYPE(WhiteBalance);
+ INIT_TYPE(Tonemap);
#undef INIT_TYPE
}
@@ -667,7 +978,19 @@ ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence
continue;
if (smti->apply) {
- ImBuf *mask = modifier_mask_get(smd, context, cfra, seq->start, ibuf->rect_float != NULL);
+ int frame_offset;
+ if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
+ frame_offset = seq->start;
+ }
+ else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ {
+ frame_offset = 0;
+ }
+
+ ImBuf *mask = modifier_mask_get(smd,
+ context,
+ cfra,
+ frame_offset,
+ ibuf->rect_float != NULL);
if (processed_ibuf == ibuf)
processed_ibuf = IMB_dupImBuf(ibuf);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index f0e59eda321..c82f3a3af23 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -47,6 +47,7 @@
#include "BLI_math.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
+#include "BLI_linklist.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
@@ -91,12 +92,21 @@
# include AUD_SPECIAL_H
#endif
-static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seqbasep, float cfra, int chanshown);
-static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra);
+/* mutable state for sequencer */
+typedef struct SeqRenderState {
+ LinkNode *scene_parents;
+} SeqRenderState;
+
+static ImBuf *seq_render_strip_stack(
+ const SeqRenderData *context, SeqRenderState *state, ListBase *seqbasep,
+ float cfra, int chanshown);
+static ImBuf *seq_render_strip(
+ const SeqRenderData *context, SeqRenderState *state,
+ Sequence *seq, float cfra);
static void seq_free_animdata(Scene *scene, Sequence *seq);
static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr, bool make_float);
-static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview);
-static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id);
+static int seq_num_files(Scene *scene, char views_format, const bool is_multiview);
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id);
/* **** XXX ******** */
#define SELECT 1
@@ -117,6 +127,11 @@ static void printf_strip(Sequence *seq)
}
#endif
+static void sequencer_state_init(SeqRenderState *state)
+{
+ state->scene_parents = NULL;
+}
+
int BKE_sequencer_base_recursive_apply(ListBase *seqbase, int (*apply_func)(Sequence *seq, void *), void *arg)
{
Sequence *iseq;
@@ -198,7 +213,7 @@ static void BKE_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cach
}
if (seq->sound) {
- ((ID *)seq->sound)->us--;
+ id_us_min(((ID *)seq->sound));
}
if (seq->stereo3d_format) {
@@ -563,6 +578,9 @@ void BKE_sequencer_new_render_data(
r_context->skip_cache = false;
r_context->is_proxy_render = false;
r_context->view_id = 0;
+ r_context->gpu_offscreen = NULL;
+ r_context->gpu_samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0;
+ r_context->gpu_full_samples = (r_context->gpu_samples) && (scene->r.scemode & R_FULL_SAMPLE);
}
/* ************************* iterator ************************** */
@@ -797,8 +815,9 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq)
}
}
-static void seq_multiview_name(Scene *scene, const size_t view_id, const char *prefix,
- const char *ext, char *r_path, size_t r_size)
+static void seq_multiview_name(
+ Scene *scene, const int view_id, const char *prefix, const char *ext,
+ char *r_path, size_t r_size)
{
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
BLI_snprintf(r_path, r_size, "%s%s%s", prefix, suffix, ext);
@@ -855,7 +874,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
if (is_multiview && (seq->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
char prefix[FILE_MAX];
const char *ext = NULL;
- size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ const int totfiles = seq_num_files(scene, seq->views_format, true);
int i = 0;
BKE_scene_multiview_view_prefix_get(scene, path, prefix, &ext);
@@ -1013,6 +1032,15 @@ void BKE_sequencer_sort(Scene *scene)
*(ed->seqbasep) = seqbase;
}
+/** Comparision function suitable to be used with BLI_listbase_sort()... */
+int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b)
+{
+ const Sequence *seq_a = a;
+ const Sequence *seq_b = b;
+
+ return (seq_a->startdisp > seq_b->startdisp);
+}
+
static int clear_scene_in_allseqs_cb(Sequence *seq, void *arg_pt)
{
if (seq->scene == (Scene *)arg_pt)
@@ -1136,6 +1164,33 @@ const char *BKE_sequence_give_name(Sequence *seq)
return name;
}
+ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset)
+{
+ ListBase *seqbase = NULL;
+
+ switch (seq->type) {
+ case SEQ_TYPE_META:
+ {
+ seqbase = &seq->seqbase;
+ *r_offset = seq->start;
+ break;
+ }
+ case SEQ_TYPE_SCENE:
+ {
+ if (seq->flag & SEQ_SCENE_STRIPS) {
+ Editing *ed = BKE_sequencer_editing_get(seq->scene, false);
+ if (ed) {
+ seqbase = &ed->seqbase;
+ *r_offset = seq->scene->r.sfra;
+ }
+ }
+ break;
+ }
+ }
+
+ return seqbase;
+}
+
/*********************** DO THE SEQUENCE *************************/
static void make_black_ibuf(ImBuf *ibuf)
@@ -1372,7 +1427,7 @@ typedef struct SeqIndexBuildContext {
int size_flags;
int quality;
bool overwrite;
- size_t view_id;
+ int view_id;
Main *bmain;
Scene *scene;
@@ -1413,7 +1468,7 @@ static double seq_rendersize_to_scale_factor(int size)
}
/* the number of files will vary according to the stereo format */
-static size_t seq_num_files(Scene *scene, char views_format, const bool is_multiview)
+static int seq_num_files(Scene *scene, char views_format, const bool is_multiview)
{
if (!is_multiview) {
return 1;
@@ -1478,7 +1533,7 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
if (is_multiview && seq->views_format == R_IMF_VIEWS_INDIVIDUAL) {
- size_t totfiles = seq_num_files(scene, seq->views_format, true);
+ int totfiles = seq_num_files(scene, seq->views_format, true);
char prefix[FILE_MAX];
const char *ext = NULL;
int i;
@@ -1561,7 +1616,7 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
}
-static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const size_t view_id)
+static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render_size, char *name, const int view_id)
{
int frameno;
char dir[PROXY_MAXFILE];
@@ -1619,7 +1674,7 @@ static bool seq_proxy_get_fname(Editing *ed, Sequence *seq, int cfra, int render
}
if (view_id > 0)
- BLI_snprintf(suffix, sizeof(suffix), "_%zu", view_id);
+ BLI_snprintf(suffix, sizeof(suffix), "_%d", view_id);
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE && sanim && sanim->anim &&
ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE)
@@ -1716,8 +1771,10 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
}
}
-static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, int cfra,
- int proxy_render_size, const bool overwrite)
+static void seq_proxy_build_frame(
+ const SeqRenderData *context, SeqRenderState *state,
+ Sequence *seq, int cfra,
+ int proxy_render_size, const bool overwrite)
{
char name[PROXY_MAXFILE];
int quality;
@@ -1734,7 +1791,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
return;
}
- ibuf_tmp = seq_render_strip(context, seq, cfra);
+ ibuf_tmp = seq_render_strip(context, state, seq, cfra);
rectx = (proxy_render_size * ibuf_tmp->x) / 100;
recty = (proxy_render_size * ibuf_tmp->y) / 100;
@@ -1771,7 +1828,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
/* returns whether the file this context would read from even exist, if not, don't create the context
*/
-static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const size_t view_id)
+static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id)
{
if ((scene->r.scemode & R_MULTIVIEW) == 0)
return false;
@@ -1807,9 +1864,9 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con
/** This returns the maximum possible number of required contexts
*/
-static size_t seq_proxy_context_count(Sequence *seq, Scene *scene)
+static int seq_proxy_context_count(Sequence *seq, Scene *scene)
{
- size_t num_views = 1;
+ int num_views = 1;
if ((scene->r.scemode & R_MULTIVIEW) == 0)
return 1;
@@ -1847,8 +1904,8 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *se
SeqIndexBuildContext *context;
Sequence *nseq;
LinkData *link;
- size_t i;
- size_t num_files;
+ int num_files;
+ int i;
if (!seq->strip || !seq->strip->proxy) {
return;
@@ -1936,18 +1993,21 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
render_context.is_proxy_render = true;
render_context.view_id = context->view_id;
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
if (context->size_flags & IMB_PROXY_25) {
- seq_proxy_build_frame(&render_context, seq, cfra, 25, overwrite);
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 25, overwrite);
}
if (context->size_flags & IMB_PROXY_50) {
- seq_proxy_build_frame(&render_context, seq, cfra, 50, overwrite);
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 50, overwrite);
}
if (context->size_flags & IMB_PROXY_75) {
- seq_proxy_build_frame(&render_context, seq, cfra, 75, overwrite);
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 75, overwrite);
}
if (context->size_flags & IMB_PROXY_100) {
- seq_proxy_build_frame(&render_context, seq, cfra, 100, overwrite);
+ seq_proxy_build_frame(&render_context, &state, seq, cfra, 100, overwrite);
}
*progress = (float) (cfra - seq->startdisp - seq->startstill) / (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
@@ -2256,7 +2316,10 @@ ImBuf *BKE_sequencer_render_mask_input(
if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
if (mask_sequence) {
- mask_input = seq_render_strip(context, mask_sequence, cfra);
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
+ mask_input = seq_render_strip(context, &state, mask_sequence, cfra);
if (make_float) {
if (!mask_input->rect_float)
@@ -2617,7 +2680,9 @@ static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, con
return out;
}
-static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequence *seq, float cfra)
+static ImBuf *seq_render_effect_strip_impl(
+ const SeqRenderData *context, SeqRenderState *state,
+ Sequence *seq, float cfra)
{
Scene *scene = context->scene;
float fac, facf;
@@ -2667,7 +2732,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
if (input[i])
- ibuf[i] = seq_render_strip(context, input[i], cfra);
+ ibuf[i] = seq_render_strip(context, state, input[i], cfra);
}
if (ibuf[0] && ibuf[1]) {
@@ -2679,7 +2744,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc
break;
case EARLY_USE_INPUT_1:
if (input[0]) {
- ibuf[0] = seq_render_strip(context, input[0], cfra);
+ ibuf[0] = seq_render_strip(context, state, input[0], cfra);
}
if (ibuf[0]) {
if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
@@ -2693,7 +2758,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, Sequenc
break;
case EARLY_USE_INPUT_2:
if (input[1]) {
- ibuf[1] = seq_render_strip(context, input[1], cfra);
+ ibuf[1] = seq_render_strip(context, state, input[1], cfra);
}
if (ibuf[1]) {
if (BKE_sequencer_input_have_to_preprocess(context, seq, cfra)) {
@@ -2740,8 +2805,8 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context, Sequence *seq
/* don't do anything */
}
else if (is_multiview) {
- size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
- size_t totviews;
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int totviews;
struct ImBuf **ibufs_arr;
char prefix[FILE_MAX];
const char *ext = NULL;
@@ -2842,8 +2907,8 @@ static ImBuf *seq_render_movie_strip(const SeqRenderData *context, Sequence *seq
if (is_multiview) {
ImBuf **ibuf_arr;
- size_t totviews;
- size_t totfiles = seq_num_files(context->scene, seq->views_format, true);
+ const int totfiles = seq_num_files(context->scene, seq->views_format, true);
+ int totviews;
int i;
if (totfiles != BLI_listbase_count_ex(&seq->anims, totfiles + 1))
@@ -3009,6 +3074,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
return NULL;
}
else {
+ AnimData *adt;
Mask *mask_temp;
MaskRasterHandle *mr_handle;
@@ -3016,6 +3082,10 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
BKE_mask_evaluate(mask_temp, mask->sfra + nr, true);
+ /* anim-data */
+ adt = BKE_animdata_from_id(&mask->id);
+ BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
+
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
mr_handle = BKE_maskrasterize_handle_new();
@@ -3189,26 +3259,31 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
char err_out[256] = "unknown";
int width = (scene->r.xsch * scene->r.size) / 100;
int height = (scene->r.ysch * scene->r.size) / 100;
+ const bool use_background = (scene->r.alphamode == R_ADDSKY);
const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
- /* for old scened this can be uninitialized,
+ /* for old scene this can be uninitialized,
* should probably be added to do_versions at some point if the functionality stays */
if (context->scene->r.seq_prev_type == 0)
context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
/* opengl offscreen render */
BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
- ibuf = sequencer_view3d_cb(scene, camera, width, height, IB_rect,
- context->scene->r.seq_prev_type,
- (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
- use_gpencil, true, scene->r.alphamode, viewname, err_out);
+ ibuf = sequencer_view3d_cb(
+ /* set for OpenGL render (NULL when scrubbing) */
+ scene, camera, width, height, IB_rect,
+ context->scene->r.seq_prev_type,
+ (context->scene->r.seq_flag & R_SEQ_SOLID_TEX) != 0,
+ use_gpencil, use_background, scene->r.alphamode,
+ context->gpu_samples, context->gpu_full_samples, viewname,
+ context->gpu_fx, context->gpu_offscreen, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
}
else {
Render *re = RE_GetRender(scene->id.name);
- size_t totviews = BKE_scene_multiview_num_views_get(&scene->r);
+ const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
int i;
ImBuf **ibufs_arr;
@@ -3276,8 +3351,6 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
}
}
MEM_freeN(ibufs_arr);
-
- // BIF_end_render_callbacks();
}
@@ -3299,7 +3372,43 @@ finally:
return ibuf;
}
-static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *seq, float cfra)
+/**
+ * Used for meta-strips & scenes with #SEQ_SCENE_STRIPS flag set.
+ */
+static ImBuf *do_render_strip_seqbase(
+ const SeqRenderData *context, SeqRenderState *state,
+ Sequence *seq, float nr, bool use_preprocess)
+{
+ ImBuf *meta_ibuf = NULL, *ibuf = NULL;
+ ListBase *seqbase = NULL;
+ int offset;
+
+ seqbase = BKE_sequence_seqbase_get(seq, &offset);
+
+ if (seqbase && !BLI_listbase_is_empty(seqbase)) {
+ meta_ibuf = seq_render_strip_stack(
+ context, state, seqbase,
+ /* scene strips don't have their start taken into account */
+ nr + offset, 0);
+ }
+
+ if (meta_ibuf) {
+ ibuf = meta_ibuf;
+ if (ibuf && use_preprocess) {
+ ImBuf *i = IMB_dupImBuf(ibuf);
+
+ IMB_freeImBuf(ibuf);
+
+ ibuf = i;
+ }
+ }
+
+ return ibuf;
+}
+
+static ImBuf *do_render_strip_uncached(
+ const SeqRenderData *context, SeqRenderState *state,
+ Sequence *seq, float cfra)
{
ImBuf *ibuf = NULL;
float nr = give_stripelem_index(seq, cfra);
@@ -3309,22 +3418,37 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
switch (type) {
case SEQ_TYPE_META:
{
- ImBuf *meta_ibuf = NULL;
-
- if (seq->seqbase.first)
- meta_ibuf = seq_render_strip_stack(context, &seq->seqbase, seq->start + nr, 0);
+ ibuf = do_render_strip_seqbase(context, state, seq, nr, use_preprocess);
+ break;
+ }
- if (meta_ibuf) {
- ibuf = meta_ibuf;
- if (ibuf && use_preprocess) {
- ImBuf *i = IMB_dupImBuf(ibuf);
+ case SEQ_TYPE_SCENE:
+ {
+ if (seq->flag & SEQ_SCENE_STRIPS) {
+ if (seq->scene && (context->scene != seq->scene)) {
+ /* recusrive check */
+ if (BLI_linklist_index(state->scene_parents, seq->scene) != -1) {
+ break;
+ }
+ LinkNode scene_parent = {.next = state->scene_parents, .link = seq->scene};
+ state->scene_parents = &scene_parent;
+ /* end check */
- IMB_freeImBuf(ibuf);
+ ibuf = do_render_strip_seqbase(context, state, seq, nr, use_preprocess);
- ibuf = i;
+ /* step back in the list */
+ state->scene_parents = state->scene_parents->next;
}
}
+ else {
+ /* scene can be NULL after deletions */
+ ibuf = seq_render_scene_strip(context, seq, nr, cfra);
+
+ /* Scene strips update all animation, so we need to restore original state.*/
+ BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
+ copy_to_ibuf_still(context, seq, nr, ibuf);
+ }
break;
}
@@ -3340,7 +3464,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
/* weeek! */
f_cfra = seq->start + s->frameMap[(int)nr];
- child_ibuf = seq_render_strip(context, seq->seq1, f_cfra);
+ child_ibuf = seq_render_strip(context, state, seq->seq1, f_cfra);
if (child_ibuf) {
ibuf = child_ibuf;
@@ -3357,7 +3481,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_EFFECT:
{
- ibuf = seq_render_effect_strip_impl(context, seq, seq->start + nr);
+ ibuf = seq_render_effect_strip_impl(context, state, seq, seq->start + nr);
break;
}
@@ -3375,18 +3499,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
break;
}
- case SEQ_TYPE_SCENE:
- {
- /* scene can be NULL after deletions */
- ibuf = seq_render_scene_strip(context, seq, nr, cfra);
-
- /* Scene strips update all animation, so we need to restore original state.*/
- BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
-
- copy_to_ibuf_still(context, seq, nr, ibuf);
- break;
- }
-
case SEQ_TYPE_MOVIECLIP:
{
ibuf = seq_render_movieclip_strip(context, seq, nr);
@@ -3408,7 +3520,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_MASK:
{
- /* ibuf is alwats new */
+ /* ibuf is always new */
ibuf = seq_render_mask_strip(context, seq, nr);
copy_to_ibuf_still(context, seq, nr, ibuf);
@@ -3422,7 +3534,9 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
return ibuf;
}
-static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra)
+static ImBuf *seq_render_strip(
+ const SeqRenderData *context, SeqRenderState *state,
+ Sequence *seq, float cfra)
{
ImBuf *ibuf = NULL;
bool use_preprocess = false;
@@ -3430,7 +3544,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa
float nr = give_stripelem_index(seq, cfra);
/* all effects are handled similarly with the exception of speed effect */
int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
- bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE);
+ bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP);
ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
@@ -3448,7 +3562,7 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa
}
if (ibuf == NULL)
- ibuf = do_render_strip_uncached(context, seq, cfra);
+ ibuf = do_render_strip_uncached(context, state, seq, cfra);
if (ibuf) {
if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
@@ -3549,7 +3663,9 @@ static ImBuf *seq_render_strip_stack_apply_effect(const SeqRenderData *context,
return out;
}
-static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seqbasep, float cfra, int chanshown)
+static ImBuf *seq_render_strip_stack(
+ const SeqRenderData *context, SeqRenderState *state, ListBase *seqbasep,
+ float cfra, int chanshown)
{
Sequence *seq_arr[MAXSEQ + 1];
int count;
@@ -3592,13 +3708,13 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
}
if (ELEM(early_out, EARLY_NO_INPUT, EARLY_USE_INPUT_2)) {
- out = seq_render_strip(context, seq, cfra);
+ out = seq_render_strip(context, state, seq, cfra);
}
else if (early_out == EARLY_USE_INPUT_1) {
out = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
}
else {
- out = seq_render_strip(context, seq, cfra);
+ out = seq_render_strip(context, state, seq, cfra);
if (early_out == EARLY_DO_EFFECT) {
ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32,
@@ -3606,8 +3722,9 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
ImBuf *ibuf2 = out;
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
-
- IMB_metadata_copy(out, ibuf2);
+ if (out) {
+ IMB_metadata_copy(out, ibuf2);
+ }
IMB_freeImBuf(ibuf1);
IMB_freeImBuf(ibuf2);
@@ -3615,7 +3732,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
}
}
else {
- out = seq_render_strip(context, seq, cfra);
+ out = seq_render_strip(context, state, seq, cfra);
}
BKE_sequencer_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF_COMP, out);
@@ -3633,7 +3750,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
break;
}
if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- out = seq_render_strip(context, seq, cfra);
+ out = seq_render_strip(context, state, seq, cfra);
break;
}
@@ -3642,7 +3759,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
switch (early_out) {
case EARLY_NO_INPUT:
case EARLY_USE_INPUT_2:
- out = seq_render_strip(context, seq, cfra);
+ out = seq_render_strip(context, state, seq, cfra);
break;
case EARLY_USE_INPUT_1:
if (i == 0) {
@@ -3652,7 +3769,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
case EARLY_DO_EFFECT:
if (i == 0) {
ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
- ImBuf *ibuf2 = seq_render_strip(context, seq, cfra);
+ ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
@@ -3676,7 +3793,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
if (seq_get_early_out_for_blend_mode(seq) == EARLY_DO_EFFECT) {
ImBuf *ibuf1 = out;
- ImBuf *ibuf2 = seq_render_strip(context, seq, cfra);
+ ImBuf *ibuf2 = seq_render_strip(context, state, seq, cfra);
out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
@@ -3711,18 +3828,27 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha
seqbasep = ed->seqbasep;
}
- return seq_render_strip_stack(context, seqbasep, cfra, chanshown);
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
+ return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
}
ImBuf *BKE_sequencer_give_ibuf_seqbase(const SeqRenderData *context, float cfra, int chanshown, ListBase *seqbasep)
{
- return seq_render_strip_stack(context, seqbasep, cfra, chanshown);
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
+ return seq_render_strip_stack(context, &state, seqbasep, cfra, chanshown);
}
ImBuf *BKE_sequencer_give_ibuf_direct(const SeqRenderData *context, float cfra, Sequence *seq)
{
- return seq_render_strip(context, seq, cfra);
+ SeqRenderState state;
+ sequencer_state_init(&state);
+
+ return seq_render_strip(context, &state, seq, cfra);
}
/* *********************** threading api ******************* */
@@ -4232,6 +4358,17 @@ bool BKE_sequence_tx_test(Sequence *seq)
return !(seq->type & SEQ_TYPE_EFFECT) || (BKE_sequence_effect_get_num_inputs(seq->type) == 0);
}
+/**
+ * Return \a true if given \a seq needs a complete cleanup of its cache when it is transformed.
+ *
+ * Some (effect) strip types need a complete recache of themselves when they are transformed, because
+ * they do not 'contain' anything and do not have any explicit relations to other strips.
+ */
+bool BKE_sequence_tx_fullupdate_test(Sequence *seq)
+{
+ return BKE_sequence_tx_test(seq) && ELEM(seq->type, SEQ_TYPE_ADJUSTMENT, SEQ_TYPE_MULTICAM);
+}
+
static bool seq_overlap(Sequence *seq1, Sequence *seq2)
{
return (seq1 != seq2 && seq1->machine == seq2->machine &&
@@ -4317,7 +4454,7 @@ bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep, Sequence *test, Scene *evi
test->machine += channel_delta;
BKE_sequence_calc(evil_scene, test);
while (BKE_sequence_test_overlap(seqbasep, test)) {
- if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine <= 1)) {
+ if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
break;
}
@@ -4866,7 +5003,7 @@ Mask *BKE_sequencer_mask_get(Scene *scene)
/* api like funcs for adding */
-static void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
+static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
{
if (seq) {
BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2);
@@ -4882,6 +5019,11 @@ static void seq_load_apply(Scene *scene, Sequence *seq, SeqLoadInfo *seq_load)
BKE_sequencer_active_set(scene, seq);
}
+ if (seq_load->flag & SEQ_LOAD_SOUND_MONO) {
+ seq->sound->flags |= SOUND_FLAGS_MONO;
+ BKE_sound_load(bmain, seq->sound);
+ }
+
if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) {
if (seq->sound)
BKE_sound_cache(seq->sound);
@@ -4979,7 +5121,7 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq->views_format = seq_load->views_format;
seq->flag |= seq_load->flag & SEQ_USE_VIEWS;
- seq_load_apply(scene, seq, seq_load);
+ seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
return seq;
}
@@ -5029,7 +5171,8 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
- seq->len = (int)ceil((double)info.length * FPS);
+ /* We add a very small negative offset here, because ceil(132.0) == 133.0, not nice with videos, see T47135. */
+ seq->len = (int)ceil((double)info.length * FPS - 1e-4);
strip->us = 1;
/* we only need 1 element to store the filename */
@@ -5044,7 +5187,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
/* last active name */
BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR);
- seq_load_apply(scene, seq, seq_load);
+ seq_load_apply(bmain, scene, seq, seq_load);
return seq;
}
@@ -5058,7 +5201,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
}
#endif // WITH_AUDASPACE
-static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const size_t view_id)
+static void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id)
{
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
IMB_suffix_anim(anim, suffix);
@@ -5075,7 +5218,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */
bool is_multiview_loaded = false;
const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0;
- size_t totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
+ const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview);
struct anim **anim_arr;
int i;
@@ -5147,6 +5290,11 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]);
BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
+
+ /* adjust scene's frame rate settings to match */
+ if (seq_load->flag & SEQ_LOAD_SYNC_FPS) {
+ IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true);
+ }
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
@@ -5176,7 +5324,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
}
/* can be NULL */
- seq_load_apply(scene, seq, seq_load);
+ seq_load_apply(CTX_data_main(C), scene, seq, seq_load);
MEM_freeN(anim_arr);
return seq;
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 7d492586b7d..badf78edfb1 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -96,6 +96,11 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
float *co = calc->vertexCos[i];
float tmp_co[3];
float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
if (weight == 0.0f) {
continue;
}
@@ -282,9 +287,11 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
/* use editmesh to avoid array allocation */
if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
treeData.em_evil = BKE_editmesh_from_object(calc->smd->target);
+ treeData.em_evil_all = true;
}
if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
auxData.em_evil = BKE_editmesh_from_object(calc->smd->auxTarget);
+ auxData.em_evil_all = true;
}
/* After sucessufuly build the trees, start projection vertexs */
@@ -298,7 +305,11 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
for (i = 0; i < calc->numVerts; ++i) {
float *co = calc->vertexCos[i];
float tmp_co[3], tmp_no[3];
- const float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+ float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
if (weight == 0.0f) {
continue;
@@ -324,7 +335,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
hit.index = -1;
- hit.dist = 10000.0f; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+ hit.dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
/* Project over positive direction of axis */
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
@@ -409,6 +420,11 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
float *co = calc->vertexCos[i];
float tmp_co[3];
float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
+
+ if (calc->invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
if (weight == 0.0f) continue;
/* Convert the vertex to tree coordinates */
@@ -478,6 +494,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
calc.ob = ob;
calc.numVerts = numVerts;
calc.vertexCos = vertexCos;
+ calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0;
/* DeformVertex */
calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name);
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 4e2f6edfcdd..d20994a2e39 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -44,6 +44,7 @@
#include "BLI_math.h"
#include "BLI_kdtree.h"
#include "BLI_kdopbvh.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_voxel.h"
@@ -89,57 +90,18 @@
/* UNUSED so far, may be enabled later */
/* #define USE_SMOKE_COLLISION_DM */
+//#define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+#endif
+
#include "smoke_API.h"
#ifdef WITH_SMOKE
static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
-#ifdef _WIN32
-#include <time.h>
-#include <stdio.h>
-#include <conio.h>
-#include <windows.h>
-
-static LARGE_INTEGER liFrequency;
-static LARGE_INTEGER liStartTime;
-static LARGE_INTEGER liCurrentTime;
-
-static void tstart(void)
-{
- QueryPerformanceFrequency(&liFrequency);
- QueryPerformanceCounter(&liStartTime);
-}
-static void tend(void)
-{
- QueryPerformanceCounter(&liCurrentTime);
-}
-static double UNUSED_FUNCTION(tval) (void)
-{
- return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart) * (double)1000.0 / (double)liFrequency.QuadPart));
-}
-#else
-#include <sys/time.h>
-static struct timeval _tstart, _tend;
-static struct timezone tz;
-static void tstart(void)
-{
- gettimeofday(&_tstart, &tz);
-}
-static void tend(void)
-{
- gettimeofday(&_tend, &tz);
-}
-
-static double UNUSED_FUNCTION(tval) (void)
-{
- double t1, t2;
- t1 = ( double ) _tstart.tv_sec * 1000 + ( double ) _tstart.tv_usec / (1000);
- t2 = ( double ) _tend.tv_sec * 1000 + ( double ) _tend.tv_usec / (1000);
- return t2 - t1;
-}
-#endif
-
struct Object;
struct Scene;
struct DerivedMesh;
@@ -148,8 +110,8 @@ struct SmokeModifierData;
// timestep default value for nice appearance 0.1f
#define DT_DEFAULT 0.1f
-#define ADD_IF_LOWER_POS(a, b) (MIN2((a) + (b), MAX2((a), (b))))
-#define ADD_IF_LOWER_NEG(a, b) (MAX2((a) + (b), MIN2((a), (b))))
+#define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b))))
+#define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b))))
#define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b)))
#else /* WITH_SMOKE */
@@ -164,9 +126,8 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s
void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm), bool UNUSED(for_render)) { return NULL; }
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
-void flame_get_spectrum(unsigned char *UNUSED(spec), int UNUSED(width), float UNUSED(t1), float UNUSED(t2)) {}
#endif /* WITH_SMOKE */
@@ -285,21 +246,21 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *
scale = res / size[0];
sds->scale = size[0] / fabsf(ob->size[0]);
sds->base_res[0] = res;
- sds->base_res[1] = (int)(size[1] * scale + 0.5f);
- sds->base_res[2] = (int)(size[2] * scale + 0.5f);
+ sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
+ sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
}
else if (size[1] >= MAX2(size[0], size[2])) {
scale = res / size[1];
sds->scale = size[1] / fabsf(ob->size[1]);
- sds->base_res[0] = (int)(size[0] * scale + 0.5f);
+ sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
sds->base_res[1] = res;
- sds->base_res[2] = (int)(size[2] * scale + 0.5f);
+ sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4);
}
else {
scale = res / size[2];
sds->scale = size[2] / fabsf(ob->size[2]);
- sds->base_res[0] = (int)(size[0] * scale + 0.5f);
- sds->base_res[1] = (int)(size[1] * scale + 0.5f);
+ sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4);
+ sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4);
sds->base_res[2] = res;
}
@@ -323,6 +284,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
add_v3_fl(sds->shift_f, 0.5f);
zero_v3(sds->prev_loc);
mul_m4_v3(ob->obmat, sds->prev_loc);
+ copy_m4_m4(sds->obmat, ob->obmat);
/* set resolutions */
if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) {
@@ -566,6 +528,14 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOWBIG;
smd->domain->effector_weights = BKE_add_effector_weights(NULL);
+
+#ifdef WITH_OPENVDB_BLOSC
+ smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC;
+#else
+ smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP;
+#endif
+ smd->domain->data_depth = 0;
+ smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE;
}
else if (smd->type & MOD_SMOKE_TYPE_FLOW)
{
@@ -656,6 +626,9 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData
MEM_freeN(tsmd->domain->effector_weights);
tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
+ tsmd->domain->openvdb_comp = smd->domain->openvdb_comp;
+ tsmd->domain->data_depth = smd->domain->data_depth;
+ tsmd->domain->cache_file_format = smd->domain->cache_file_format;
}
else if (tsmd->flow) {
tsmd->flow->psys = smd->flow->psys;
@@ -723,7 +696,75 @@ static int get_lamp(Scene *scene, float *light)
* Obstacles
**********************************************************/
-static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs, unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
+typedef struct ObstaclesFromDMData {
+ SmokeDomainSettings *sds;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *looptri;
+ BVHTreeFromMesh *tree;
+ unsigned char *obstacle_map;
+
+ bool has_velocity;
+ float *vert_vel;
+ float *velocityX, *velocityY, *velocityZ;
+} ObstaclesFromDMData;
+
+static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
+{
+ ObstaclesFromDMData *data = userdata;
+ SmokeDomainSettings *sds = data->sds;
+
+ /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
+ const float surface_distance = 0.867f;
+
+ for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) {
+ for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) {
+ const int index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
+
+ float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
+ BVHTreeNearest nearest = {0};
+ nearest.index = -1;
+ nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */
+
+ /* find the nearest point on the mesh */
+ if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) {
+ const MLoopTri *lt = &data->looptri[nearest.index];
+ float weights[4];
+ int v1, v2, v3;
+
+ /* calculate barycentric weights for nearest point */
+ v1 = data->mloop[lt->tri[0]].v;
+ v2 = data->mloop[lt->tri[1]].v;
+ v3 = data->mloop[lt->tri[2]].v;
+ interp_weights_face_v3(
+ weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co);
+
+ // DG TODO
+ if (data->has_velocity)
+ {
+ /* apply object velocity */
+ {
+ float hit_vel[3];
+ interp_v3_v3v3v3(hit_vel, &data->vert_vel[v1 * 3], &data->vert_vel[v2 * 3], &data->vert_vel[v3 * 3], weights);
+ data->velocityX[index] += hit_vel[0];
+ data->velocityY[index] += hit_vel[1];
+ data->velocityZ[index] += hit_vel[2];
+ }
+ }
+
+ /* tag obstacle cells */
+ data->obstacle_map[index] = 1;
+
+ if (data->has_velocity)
+ data->obstacle_map[index] |= 8;
+ }
+ }
+ }
+}
+
+static void obstacles_from_derivedmesh(
+ Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
+ unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
{
if (!scs->dm) return;
{
@@ -732,15 +773,10 @@ static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds
const MLoopTri *looptri;
const MLoop *mloop;
BVHTreeFromMesh treeData = {NULL};
- int numverts, i, z;
-
- /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */
- const float surface_distance = 0.867f;
+ int numverts, i;
float *vert_vel = NULL;
- int has_velocity = 0;
-
- tstart();
+ bool has_velocity = false;
dm = CDDM_copy(scs->dm);
CDDM_calc_normals(dm);
@@ -763,7 +799,7 @@ static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds
scs->numverts = numverts;
}
else {
- has_velocity = 1;
+ has_velocity = true;
}
}
@@ -795,51 +831,14 @@ static void obstacles_from_derivedmesh(Object *coll_ob, SmokeDomainSettings *sds
}
if (bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 4, 6)) {
-#pragma omp parallel for schedule(static)
- for (z = sds->res_min[2]; z < sds->res_max[2]; z++) {
- int x, y;
- for (x = sds->res_min[0]; x < sds->res_max[0]; x++)
- for (y = sds->res_min[1]; y < sds->res_max[1]; y++) {
- int index = smoke_get_index(x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]);
-
- float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f};
- BVHTreeNearest nearest = {0};
- nearest.index = -1;
- nearest.dist_sq = surface_distance * surface_distance; /* find_nearest uses squared distance */
-
- /* find the nearest point on the mesh */
- if (BLI_bvhtree_find_nearest(treeData.tree, ray_start, &nearest, treeData.nearest_callback, &treeData) != -1) {
- const MLoopTri *lt = &looptri[nearest.index];
- float weights[4];
- int v1, v2, v3;
-
- /* calculate barycentric weights for nearest point */
- v1 = mloop[lt->tri[0]].v;
- v2 = mloop[lt->tri[1]].v;
- v3 = mloop[lt->tri[2]].v;
- interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co);
-
- // DG TODO
- if (has_velocity)
- {
- /* apply object velocity */
- {
- float hit_vel[3];
- interp_v3_v3v3v3(hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights);
- velocityX[index] += hit_vel[0];
- velocityY[index] += hit_vel[1];
- velocityZ[index] += hit_vel[2];
- }
- }
-
- /* tag obstacle cells */
- obstacle_map[index] = 1;
-
- if (has_velocity)
- obstacle_map[index] |= 8;
- }
- }
- }
+ ObstaclesFromDMData data = {
+ .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
+ .tree = &treeData, .obstacle_map = obstacle_map,
+ .has_velocity = has_velocity, .vert_vel = vert_vel,
+ .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ
+ };
+ BLI_task_parallel_range(
+ sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
@@ -930,98 +929,6 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
}
}
-
-/**********************************************************
- * Object subframe update method from dynamicpaint.c
- **********************************************************/
-
-/* set "ignore cache" flag for all caches on this object */
-static void object_cacheIgnoreClear(Object *ob, bool state)
-{
- ListBase pidlist;
- PTCacheID *pid;
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
-
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pid->cache) {
- if (state)
- pid->cache->flag |= PTCACHE_IGNORE_CLEAR;
- else
- pid->cache->flag &= ~PTCACHE_IGNORE_CLEAR;
- }
- }
-
- BLI_freelistN(&pidlist);
-}
-
-static bool subframe_updateObject(Scene *scene, Object *ob, int update_mesh, int parent_recursion, float frame, bool for_render)
-{
- SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke);
- bConstraint *con;
-
- /* if other is dynamic paint canvas, don't update */
- if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN))
- return true;
-
- /* if object has parents, update them too */
- if (parent_recursion) {
- int recursion = parent_recursion - 1;
- bool is_domain = false;
- if (ob->parent) is_domain |= subframe_updateObject(scene, ob->parent, 0, recursion, frame, for_render);
- if (ob->track) is_domain |= subframe_updateObject(scene, ob->track, 0, recursion, frame, for_render);
-
- /* skip subframe if object is parented
- * to vertex of a dynamic paint canvas */
- if (is_domain && (ob->partype == PARVERT1 || ob->partype == PARVERT3))
- return false;
-
- /* also update constraint targets */
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {NULL, NULL};
-
- if (cti && cti->get_constraint_targets) {
- bConstraintTarget *ct;
- cti->get_constraint_targets(con, &targets);
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar)
- subframe_updateObject(scene, ct->tar, 0, recursion, frame, for_render);
- }
- /* free temp targets */
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
- if (update_mesh) {
- /* ignore cache clear during subframe updates
- * to not mess up cache validity */
- object_cacheIgnoreClear(ob, 1);
- BKE_object_handle_update(G.main->eval_ctx, scene, ob);
- object_cacheIgnoreClear(ob, 0);
- }
- else
- BKE_object_where_is_calc_time(scene, ob, frame);
-
- /* for curve following objects, parented curve has to be updated too */
- if (ob->type == OB_CURVE) {
- Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
- }
- /* and armatures... */
- if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
- BKE_pose_where_is(scene, ob);
- }
-
- return false;
-}
-
/**********************************************************
* Flow emission code
**********************************************************/
@@ -1220,8 +1127,85 @@ static void em_combineMaps(EmissionMap *output, EmissionMap *em2, int hires_mult
em_freeData(&em1);
}
+typedef struct EmitFromParticlesData {
+ SmokeFlowSettings *sfs;
+ KDTree *tree;
+ int hires_multiplier;
+
+ EmissionMap *em;
+ float *particle_vel;
+ float hr;
+
+ int *min, *max, *res;
-static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float dt)
+ float solid;
+ float smooth;
+ float hr_smooth;
+} EmitFromParticlesData;
+
+static void emit_from_particles_task_cb(void *userdata, const int z)
+{
+ EmitFromParticlesData *data = userdata;
+ SmokeFlowSettings *sfs = data->sfs;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = smoke_get_index(lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest nearest;
+ const float range = data->solid + data->smooth;
+ BLI_kdtree_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence[index] = (nearest.dist < data->solid) ?
+ 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth);
+ /* Uses particle velocity as initial velocity for smoke */
+ if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (sfs->psys->part->phystype != PART_PHYS_NO)) {
+ VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3],
+ &data->particle_vel[nearest.index * 3], sfs->vel_multi);
+ }
+ }
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = smoke_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ /* find particle distance from the kdtree */
+ KDTreeNearest nearest;
+ const float range = data->solid + data->hr_smooth;
+ BLI_kdtree_find_nearest(data->tree, ray_start, &nearest);
+
+ if (nearest.dist < range) {
+ em->influence_high[index] = (nearest.dist < data->solid) ?
+ 1.0f : (1.0f - (nearest.dist - data->solid) / data->smooth);
+ }
+ }
+
+ }
+ }
+}
+
+static void emit_from_particles(
+ Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float dt)
{
if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
{
@@ -1235,11 +1219,10 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
int bounds_margin = 1;
/* radius based flow */
- float solid = sfs->particle_size * 0.5f;
- float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
+ const float solid = sfs->particle_size * 0.5f;
+ const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */
int hires_multiplier = 1;
- int i, z;
- KDTree *tree;
+ KDTree *tree = NULL;
sim.scene = scene;
sim.ob = flow_ob;
@@ -1350,15 +1333,14 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
} // particles loop
}
else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE
-
int min[3], max[3], res[3];
- float hr = 1.0f / ((float)hires_multiplier);
+ const float hr = 1.0f / ((float)hires_multiplier);
/* slightly adjust high res antialias smoothness based on number of divisions
* to allow smaller details but yet not differing too much from the low res size */
const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f);
/* setup loop bounds */
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
min[i] = em->min[i] * hires_multiplier;
max[i] = em->max[i] * hires_multiplier;
res[i] = em->res[i] * hires_multiplier;
@@ -1366,62 +1348,13 @@ static void emit_from_particles(Object *flow_ob, SmokeDomainSettings *sds, Smoke
BLI_kdtree_balance(tree);
- /* begin thread safe malloc */
- BLI_begin_threaded_malloc();
-
-#pragma omp parallel for schedule(static)
- for (z = min[2]; z < max[2]; z++) {
- int x, y;
- for (x = min[0]; x < max[0]; x++)
- for (y = min[1]; y < max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- int lx = x / hires_multiplier;
- int ly = y / hires_multiplier;
- int lz = z / hires_multiplier;
-
- int index = smoke_get_index(lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- /* find particle distance from the kdtree */
- KDTreeNearest nearest;
- float range = solid + smooth;
- BLI_kdtree_find_nearest(tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence[index] = (nearest.dist < solid) ? 1.0f : (1.0f - (nearest.dist-solid) / smooth);
- /* Uses particle velocity as initial velocity for smoke */
- if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO))
- {
- VECADDFAC(&em->velocity[index * 3], &em->velocity[index * 3], &particle_vel[nearest.index * 3], sfs->vel_multi);
- }
- }
- }
-
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- float lx = ((float)x) * hr;
- float ly = ((float)y) * hr;
- float lz = ((float)z) * hr;
-
- int index = smoke_get_index(x - min[0], res[0], y - min[1], res[1], z - min[2]);
- float ray_start[3] = {lx + 0.5f*hr, ly + 0.5f*hr, lz + 0.5f*hr};
-
- /* find particle distance from the kdtree */
- KDTreeNearest nearest;
- float range = solid + hr_smooth;
- BLI_kdtree_find_nearest(tree, ray_start, &nearest);
-
- if (nearest.dist < range) {
- em->influence_high[index] = (nearest.dist < solid) ? 1.0f : (1.0f - (nearest.dist-solid) / smooth);
- }
- }
+ EmitFromParticlesData data = {
+ .sfs = sfs, .tree = tree, .hires_multiplier = hires_multiplier, .hr = hr,
+ .em = em, .particle_vel = particle_vel, .min = min, .max = max, .res = res,
+ .solid = solid, .smooth = smooth, .hr_smooth = hr_smooth,
+ };
- }
- }
- BLI_end_threaded_malloc();
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, true);
}
if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) {
@@ -1571,6 +1504,76 @@ static void sample_derivedmesh(
influence_map[index] = MAX2(volume_factor, sample_str);
}
+typedef struct EmitFromDMData {
+ SmokeDomainSettings *sds;
+ SmokeFlowSettings *sfs;
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MLoopTri *mlooptri;
+ const MLoopUV *mloopuv;
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ BVHTreeFromMesh *tree;
+ int hires_multiplier;
+ float hr;
+
+ EmissionMap *em;
+ bool has_velocity;
+ float *vert_vel;
+
+ float *flow_center;
+ int *min, *max, *res;
+} EmitFromDMData;
+
+static void emit_from_derivedmesh_task_cb(void *userdata, const int z)
+{
+ EmitFromDMData *data = userdata;
+ EmissionMap *em = data->em;
+ const int hires_multiplier = data->hires_multiplier;
+
+ for (int x = data->min[0]; x < data->max[0]; x++) {
+ for (int y = data->min[1]; y < data->max[1]; y++) {
+ /* take low res samples where possible */
+ if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
+ /* get low res space coordinates */
+ const int lx = x / hires_multiplier;
+ const int ly = y / hires_multiplier;
+ const int lz = z / hires_multiplier;
+
+ const int index = smoke_get_index(
+ lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
+ const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
+
+ sample_derivedmesh(
+ data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
+ em->influence, em->velocity, index, data->sds->base_res, data->flow_center,
+ data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
+ (float)lx, (float)ly, (float)lz);
+ }
+
+ /* take high res samples if required */
+ if (hires_multiplier > 1) {
+ /* get low res space coordinates */
+ const float lx = ((float)x) * data->hr;
+ const float ly = ((float)y) * data->hr;
+ const float lz = ((float)z) * data->hr;
+
+ const int index = smoke_get_index(
+ x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
+ const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
+
+ sample_derivedmesh(
+ data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
+ em->influence_high, NULL, index, data->sds->base_res, data->flow_center,
+ data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
+ /* x,y,z needs to be always lowres */
+ lx, ly, lz);
+ }
+ }
+ }
+}
+
static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
if (sfs->dm) {
@@ -1583,7 +1586,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
const MLoopUV *mloopuv = NULL;
const MLoop *mloop = NULL;
BVHTreeFromMesh treeData = {NULL};
- int numOfVerts, i, z;
+ int numOfVerts, i;
float flow_center[3] = {0};
float *vert_vel = NULL;
@@ -1665,49 +1668,18 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
}
if (bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 4, 6)) {
-#pragma omp parallel for schedule(static)
- for (z = min[2]; z < max[2]; z++) {
- int x, y;
- for (x = min[0]; x < max[0]; x++)
- for (y = min[1]; y < max[1]; y++) {
- /* take low res samples where possible */
- if (hires_multiplier <= 1 || !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) {
- /* get low res space coordinates */
- int lx = x / hires_multiplier;
- int ly = y / hires_multiplier;
- int lz = z / hires_multiplier;
-
- int index = smoke_get_index(lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
- float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
-
- sample_derivedmesh(
- sfs, mvert, mloop, mlooptri, mloopuv,
- em->influence, em->velocity, index, sds->base_res, flow_center,
- &treeData, ray_start,vert_vel, has_velocity, defgrp_index, dvert,
- (float)lx, (float)ly, (float)lz);
- }
+ const float hr = 1.0f / ((float)hires_multiplier);
- /* take high res samples if required */
- if (hires_multiplier > 1) {
- /* get low res space coordinates */
- float hr = 1.0f / ((float)hires_multiplier);
- float lx = ((float)x) * hr;
- float ly = ((float)y) * hr;
- float lz = ((float)z) * hr;
-
- int index = smoke_get_index(x - min[0], res[0], y - min[1], res[1], z - min[2]);
- float ray_start[3] = {lx + 0.5f*hr, ly + 0.5f*hr, lz + 0.5f*hr};
-
- sample_derivedmesh(
- sfs, mvert, mloop, mlooptri, mloopuv,
- em->influence_high, NULL, index, sds->base_res, flow_center,
- &treeData, ray_start, vert_vel, has_velocity, defgrp_index, dvert,
- /* x,y,z needs to be always lowres */
- lx, ly, lz);
- }
+ EmitFromDMData data = {
+ .sds = sds, .sfs = sfs,
+ .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, .mloopuv = mloopuv,
+ .dvert = dvert, .defgrp_index = defgrp_index,
+ .tree = &treeData, .hires_multiplier = hires_multiplier, .hr = hr,
+ .em = em, .has_velocity = has_velocity, .vert_vel = vert_vel,
+ .flow_center = flow_center, .min = min, .max = max, .res = res,
+ };
- }
- }
+ BLI_task_parallel_range(min[2], max[2], &data, emit_from_derivedmesh_task_cb, true);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
@@ -1732,10 +1704,11 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], EmissionMap *emaps, unsigned int numflowobj, float dt)
{
+ const int block_size = sds->amplify + 1;
int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3];
int total_cells = 1, res_changed = 0, shift_changed = 0;
float min_vel[3], max_vel[3];
- int x, y, z, i;
+ int x, y, z;
float *density = smoke_get_density(sds->fluid);
float *fuel = smoke_get_fuel(sds->fluid);
float *bigdensity = smoke_turbulence_get_density(sds->wt);
@@ -1743,7 +1716,6 @@ static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], E
float *vx = smoke_get_velocity_x(sds->fluid);
float *vy = smoke_get_velocity_y(sds->fluid);
float *vz = smoke_get_velocity_z(sds->fluid);
- int block_size = sds->amplify + 1;
int wt_res[3];
if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) {
@@ -1810,8 +1782,7 @@ static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], E
}
/* also apply emission maps */
- for (i = 0; i < numflowobj; i++)
- {
+ for (int i = 0; i < numflowobj; i++) {
EmissionMap *em = &emaps[i];
for (x = em->min[0]; x < em->max[0]; x++)
@@ -1838,7 +1809,7 @@ static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], E
mul_v3_fl(max_vel, 1.0f / sds->dx);
clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt);
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
/* calculate new resolution */
res[i] = max[i] - min[i];
total_cells *= res[i];
@@ -1938,7 +1909,6 @@ static void adjustDomainResolution(SmokeDomainSettings *sds, int new_shift[3], E
n_vz[index_new] = o_vz[index_old];
if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) {
- int block_size = sds->amplify + 1;
int i, j, k;
/* old grid index */
int xx_o = xo * block_size;
@@ -2060,7 +2030,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value
}
}
-static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt, bool for_render)
+static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
{
Object **flowobjs = NULL;
EmissionMap *emaps = NULL;
@@ -2167,7 +2137,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
/* update flow object frame */
BLI_mutex_lock(&object_update_lock);
- subframe_updateObject(scene, collob, 1, 5, BKE_scene_frame_get(scene), for_render);
+ BKE_object_modifier_update_subframe(scene, collob, true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke);
BLI_mutex_unlock(&object_update_lock);
/* apply flow */
@@ -2197,6 +2167,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
active_fields |= SM_ACTIVE_COLOR_SET;
}
else if (!equals_v3v3(sds->active_color, sfs->color)) {
+ copy_v3_v3(sds->active_color, sfs->color);
active_fields |= SM_ACTIVE_COLORS;
}
}
@@ -2215,6 +2186,7 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
active_fields |= SM_ACTIVE_COLOR_SET;
}
else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) {
+ copy_v3_v3(sds->active_color, sds->flame_smoke_color);
active_fields |= SM_ACTIVE_COLORS;
}
}
@@ -2407,6 +2379,73 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
MEM_freeN(emaps);
}
+typedef struct UpdateEffectorsData {
+ Scene *scene;
+ SmokeDomainSettings *sds;
+ ListBase *effectors;
+
+ float *density;
+ float *fuel;
+ float *force_x;
+ float *force_y;
+ float *force_z;
+ float *velocity_x;
+ float *velocity_y;
+ float *velocity_z;
+ unsigned char *obstacle;
+} UpdateEffectorsData;
+
+static void update_effectors_task_cb(void *userdata, const int x)
+{
+ UpdateEffectorsData *data = userdata;
+ SmokeDomainSettings *sds = data->sds;
+
+ for (int y = 0; y < sds->res[1]; y++) {
+ for (int z = 0; z < sds->res[2]; z++)
+ {
+ EffectedPoint epoint;
+ float mag;
+ float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
+ const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
+
+ if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) < FLT_EPSILON) ||
+ data->obstacle[index])
+ {
+ continue;
+ }
+
+ vel[0] = data->velocity_x[index];
+ vel[1] = data->velocity_y[index];
+ vel[2] = data->velocity_z[index];
+
+ /* convert vel to global space */
+ mag = len_v3(vel);
+ mul_mat3_m4_v3(sds->obmat, vel);
+ normalize_v3(vel);
+ mul_v3_fl(vel, mag);
+
+ voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
+ voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
+ voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
+ mul_m4_v3(sds->obmat, voxelCenter);
+
+ pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
+ pdDoEffectors(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+
+ /* convert retvel to local space */
+ mag = len_v3(retvel);
+ mul_mat3_m4_v3(sds->imat, retvel);
+ normalize_v3(retvel);
+ mul_v3_fl(retvel, mag);
+
+ // TODO dg - do in force!
+ data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
+ data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
+ data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
+ }
+ }
+}
+
static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
ListBase *effectors;
@@ -2414,71 +2453,29 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
- if (effectors)
- {
- float *density = smoke_get_density(sds->fluid);
- float *fuel = smoke_get_fuel(sds->fluid);
- float *force_x = smoke_get_force_x(sds->fluid);
- float *force_y = smoke_get_force_y(sds->fluid);
- float *force_z = smoke_get_force_z(sds->fluid);
- float *velocity_x = smoke_get_velocity_x(sds->fluid);
- float *velocity_y = smoke_get_velocity_y(sds->fluid);
- float *velocity_z = smoke_get_velocity_z(sds->fluid);
- unsigned char *obstacle = smoke_get_obstacle(sds->fluid);
- int x;
-
+ if (effectors) {
// precalculate wind forces
-#pragma omp parallel for schedule(static)
- for (x = 0; x < sds->res[0]; x++)
- {
- int y, z;
- for (y = 0; y < sds->res[1]; y++)
- for (z = 0; z < sds->res[2]; z++)
- {
- EffectedPoint epoint;
- float mag;
- float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0};
- unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z);
-
- if (((fuel ? MAX2(density[index], fuel[index]) : density[index]) < FLT_EPSILON) || obstacle[index])
- continue;
-
- vel[0] = velocity_x[index];
- vel[1] = velocity_y[index];
- vel[2] = velocity_z[index];
-
- /* convert vel to global space */
- mag = len_v3(vel);
- mul_mat3_m4_v3(sds->obmat, vel);
- normalize_v3(vel);
- mul_v3_fl(vel, mag);
-
- voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f);
- voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f);
- voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f);
- mul_m4_v3(sds->obmat, voxelCenter);
-
- pd_point_from_loc(scene, voxelCenter, vel, index, &epoint);
- pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
-
- /* convert retvel to local space */
- mag = len_v3(retvel);
- mul_mat3_m4_v3(sds->imat, retvel);
- normalize_v3(retvel);
- mul_v3_fl(retvel, mag);
-
- // TODO dg - do in force!
- force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f);
- force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f);
- force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f);
- }
- }
+ UpdateEffectorsData data;
+ data.scene = scene;
+ data.sds = sds;
+ data.effectors = effectors;
+ data.density = smoke_get_density(sds->fluid);
+ data.fuel = smoke_get_fuel(sds->fluid);
+ data.force_x = smoke_get_force_x(sds->fluid);
+ data.force_y = smoke_get_force_y(sds->fluid);
+ data.force_z = smoke_get_force_z(sds->fluid);
+ data.velocity_x = smoke_get_velocity_x(sds->fluid);
+ data.velocity_y = smoke_get_velocity_y(sds->fluid);
+ data.velocity_z = smoke_get_velocity_z(sds->fluid);
+ data.obstacle = smoke_get_obstacle(sds->fluid);
+
+ BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, true);
}
pdEndEffectors(&effectors);
}
-static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps, bool for_render)
+static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps)
{
SmokeDomainSettings *sds = smd->domain;
/* stability values copied from wturbulence.cpp */
@@ -2548,7 +2545,7 @@ static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *
for (substep = 0; substep < totalSubsteps; substep++)
{
// calc animated obstacle velocities
- update_flowsfluids(scene, ob, sds, dtSubdiv, for_render);
+ update_flowsfluids(scene, ob, sds, dtSubdiv);
update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps);
if (sds->total_cells > 1) {
@@ -2645,7 +2642,7 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
return result;
}
-static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, bool for_render)
+static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
{
if ((smd->type & MOD_SMOKE_TYPE_FLOW))
{
@@ -2741,7 +2738,9 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
if (framenr != scene->r.cfra)
return;
- tstart();
+#ifdef DEBUG_TIME
+ double start = PIL_check_seconds_timer();
+#endif
/* if on second frame, write cache for first frame */
if ((int)smd->time == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
@@ -2767,7 +2766,7 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
}
- step(scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base, for_render);
+ step(scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base);
}
// create shadows before writing cache so they get stored
@@ -2782,18 +2781,20 @@ static void smokeModifier_process(SmokeModifierData *smd, Scene *scene, Object *
if (framenr != startframe)
BKE_ptcache_write(&pid, framenr);
- tend();
- // printf ( "Frame: %d, Time: %f\n\n", (int)smd->time, (float) tval() );
+#ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+ printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start));
+#endif
}
}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, bool for_render)
+struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
{
/* lock so preview render does not read smoke data while it gets modified */
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- smokeModifier_process(smd, scene, ob, dm, for_render);
+ smokeModifier_process(smd, scene, ob, dm);
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
@@ -2819,7 +2820,6 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix
if (result[index] < 0.0f)
{
-// #pragma omp critical
result[index] = *tRay;
}
@@ -2934,7 +2934,6 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
bv[3] = (float)sds->res[1]; // y
bv[5] = (float)sds->res[2]; // z
-// #pragma omp parallel for schedule(static, 1)
for (z = 0; z < sds->res[2]; z++)
{
size_t index = z * slabsize;
@@ -2976,7 +2975,6 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
bresenham_linie_3D(cell[0], cell[1], cell[2], x, y, z, &tRay, calc_voxel_transp, sds->shadow, density, sds->res, correct);
// convention -> from a RGBA float array, use G value for tRay
-// #pragma omp critical
sds->shadow[index] = tRay;
}
}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index dac395645c9..25a4fdc0cc7 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -81,7 +81,6 @@ variables on the UI for now
#include "BKE_scene.h"
#include "PIL_time.h"
-// #include "ONL_opennl.h" remove linking to ONL for now
/* callbacks for errors and interrupts and some goo */
static int (*SB_localInterruptCallBack)(void) = NULL;
@@ -142,11 +141,6 @@ typedef struct SB_thread_context {
int tot;
} SB_thread_context;
-#define NLF_BUILD 1
-#if 0
-# define NLF_SOLVE 2
-#endif
-
#define MID_PRESERVE 1
#define SOFTGOALSNAP 0.999f
@@ -272,7 +266,6 @@ typedef struct ccdf_minmax {
} ccdf_minmax;
-
typedef struct ccd_Mesh {
int mvert_num, tri_num;
const MVert *mvert;
@@ -286,8 +279,6 @@ typedef struct ccd_Mesh {
} ccd_Mesh;
-
-
static ccd_Mesh *ccd_mesh_make(Object *ob)
{
CollisionModifierData *cmd;
@@ -561,8 +552,6 @@ static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash *
}
-
-
/*--- collider caching and dicing ---*/
@@ -1224,9 +1213,9 @@ static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], fl
sub_v3_v3v3(edge2, nv3, nv2);
cross_v3_v3v3(d_nvect, edge2, edge1);
normalize_v3(d_nvect);
- if (isect_line_tri_v3(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) ||
- isect_line_tri_v3(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) ||
- isect_line_tri_v3(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL) )
+ if (isect_line_segment_tri_v3(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) ||
+ isect_line_segment_tri_v3(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) ||
+ isect_line_segment_tri_v3(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL) )
{
madd_v3_v3fl(force, d_nvect, -0.5f);
*damp=tune*ob->pd->pdef_sbdamp;
@@ -1407,7 +1396,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
cross_v3_v3v3(d_nvect, edge2, edge1);
normalize_v3(d_nvect);
- if ( isect_line_tri_v3(edge_v1, edge_v2, nv1, nv2, nv3, &t, NULL)) {
+ if (isect_line_segment_tri_v3(edge_v1, edge_v2, nv1, nv2, nv3, &t, NULL)) {
float v1[3], v2[3];
float intrusiondepth, i1, i2;
sub_v3_v3v3(v1, edge_v1, nv2);
@@ -1821,14 +1810,14 @@ static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len
for (j=0;j<3;j++) {
delta_ij = (i==j ? (1.0f): (0.0f));
m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j]));
- nlMatrixAdd(ia+i, op+ic+j, m);
+ EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
}
}
else {
for (i=0;i<3;i++)
for (j=0;j<3;j++) {
m=factor*dir[i]*dir[j];
- nlMatrixAdd(ia+i, op+ic+j, m);
+ EIG_linear_solver_matrix_add(ia+i, op+ic+j, m);
}
}
}
@@ -1837,16 +1826,16 @@ static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len
static void dfdx_goal(int ia, int ic, int op, float factor)
{
int i;
- for (i=0;i<3;i++) nlMatrixAdd(ia+i, op+ic+i, factor);
+ for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, op+ic+i, factor);
}
static void dfdv_goal(int ia, int ic, float factor)
{
int i;
- for (i=0;i<3;i++) nlMatrixAdd(ia+i, ic+i, factor);
+ for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, ic+i, factor);
}
*/
-static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float UNUSED(forcetime), int nl_flags)
+static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float UNUSED(forcetime))
{
SoftBody *sb= ob->soft; /* is supposed to be there */
BodyPoint *bp1, *bp2;
@@ -1920,23 +1909,6 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa
projvel = dot_v3v3(dir, dvel);
kd *= absvel * projvel;
madd_v3_v3fl(bp1->force, dir, -kd);
-
- /* do jacobian stuff if needed */
- if (nl_flags & NLF_BUILD) {
- //int op =3*sb->totpoint;
- //float mvel = -forcetime*kd;
- //float mpos = -forcetime*forcefactor;
- /* depending on my pos */
- // dfdx_spring(ia, ia, op, dir, bs->len, distance, -mpos);
- /* depending on my vel */
- // dfdv_goal(ia, ia, mvel); // well that ignores geometie
- if (bp2->goal < SOFTGOALSNAP) { /* omit this bp when it snaps */
- /* depending on other pos */
- // dfdx_spring(ia, ic, op, dir, bs->len, distance, mpos);
- /* depending on other vel */
- // dfdv_goal(ia, ia, -mvel); // well that ignores geometie
- }
- }
}
@@ -2136,8 +2108,8 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
bp->choke = bs->cf;
}
- // sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float forcetime, int nl_flags)
- sb_spring_force(ob, ilast-bb, bs, iks, forcetime, 0);
+ // sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float forcetime)
+ sb_spring_force(ob, ilast-bb, bs, iks, forcetime);
}/* loop springs */
}/* existing spring list */
}/*any edges*/
@@ -2209,7 +2181,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
MEM_freeN(sb_threads);
}
-static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow, int UNUSED(nl_flags))
+static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow)
{
/* rule we never alter free variables :bp->vec bp->pos in here !
* this will ruin adaptive stepsize AKA heun! (BM)
@@ -2234,7 +2206,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
if (do_springcollision || do_aero)
- sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
+ sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
/* after spring scan because it uses Effoctors too */
do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
@@ -2254,13 +2226,11 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
}
-
-
-static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow, int nl_flags)
+static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow)
{
/* redirection to the new threaded Version */
if (!(G.debug_value & 0x10)) { // 16
- softbody_calc_forcesEx(scene, ob, forcetime, timenow, nl_flags);
+ softbody_calc_forcesEx(scene, ob, forcetime, timenow);
return;
}
else {
@@ -2283,18 +2253,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
float iks, ks, kd, gravity[3] = {0.0f, 0.0f, 0.0f};
float fieldfactor = -1.0f, windfactor = 0.25f;
float tune = sb->ballstiff;
- int a, b, do_deflector, do_selfcollision, do_springcollision, do_aero;
-
-
- /* jacobian
- NLboolean success;
-
- if (nl_flags) {
- nlBegin(NL_SYSTEM);
- nlBegin(NL_MATRIX);
- }
- */
-
+ int do_deflector, do_selfcollision, do_springcollision, do_aero;
if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
copy_v3_v3(gravity, scene->physics_settings.gravity);
@@ -2319,29 +2278,10 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
}
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ bp = sb->bpoint;
+ for (int a = sb->totpoint; a > 0; a--, bp++) {
/* clear forces accumulator */
bp->force[0] = bp->force[1] = bp->force[2] = 0.0;
- if (nl_flags & NLF_BUILD) {
- //int ia =3*(sb->totpoint-a);
- //int op =3*sb->totpoint;
- /* dF/dV = v */
- /* jacobioan
- nlMatrixAdd(op+ia, ia, -forcetime);
- nlMatrixAdd(op+ia+1, ia+1, -forcetime);
- nlMatrixAdd(op+ia+2, ia+2, -forcetime);
-
- nlMatrixAdd(ia, ia, 1);
- nlMatrixAdd(ia+1, ia+1, 1);
- nlMatrixAdd(ia+2, ia+2, 1);
-
- nlMatrixAdd(op+ia, op+ia, 1);
- nlMatrixAdd(op+ia+1, op+ia+1, 1);
- nlMatrixAdd(op+ia+2, op+ia+2, 1);
- */
-
-
- }
/* naive ball self collision */
/* needs to be done if goal snaps or not */
@@ -2384,30 +2324,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
madd_v3_v3fl(bp->force, def, f * (1.0f - sb->balldamp));
madd_v3_v3fl(bp->force, dvel, sb->balldamp);
- if (nl_flags & NLF_BUILD) {
- //int ia =3*(sb->totpoint-a);
- //int ic =3*(sb->totpoint-c);
- //int op =3*sb->totpoint;
- //float mvel = forcetime*sb->nodemass*sb->balldamp;
- //float mpos = forcetime*tune*(1.0f-sb->balldamp);
- /*some quick and dirty entries to the jacobian*/
- //dfdx_goal(ia, ia, op, mpos);
- //dfdv_goal(ia, ia, mvel);
- /* exploit force(a, b) == -force(b, a) part1/2 */
- //dfdx_goal(ic, ic, op, mpos);
- //dfdv_goal(ic, ic, mvel);
-
-
- /*TODO sit down an X-out the true jacobian entries*/
- /*well does not make to much sense because the eigenvalues
- of the jacobian go negative; and negative eigenvalues
- on a complex iterative system z(n+1)=A * z(n)
- give imaginary roots in the charcateristic polynom
- --> solutions that to z(t)=u(t)* exp ( i omega t) --> oscilations we don't want here
- where u(t) is a unknown amplitude function (worst case rising fast)
- */
- }
-
/* exploit force(a, b) == -force(b, a) part2/2 */
sub_v3_v3v3(dvel, velcenter, obp->vec);
mul_v3_fl(dvel, (_final_mass(ob, bp)+_final_mass(ob, obp))/2.0f);
@@ -2433,14 +2349,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
bp->force[1]+= -ks*(auxvect[1]);
bp->force[2]+= -ks*(auxvect[2]);
- if (nl_flags & NLF_BUILD) {
- //int ia =3*(sb->totpoint-a);
- //int op =3*(sb->totpoint);
- /* depending on my pos */
- //dfdx_goal(ia, ia, op, ks*forcetime);
- }
-
-
/* calulate damping forces generated by goals*/
sub_v3_v3v3(velgoal, bp->origS, bp->origE);
kd = sb->goalfrict * sb_fric_force_scale(ob);
@@ -2450,12 +2358,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
bp->force[0]-= kd * (auxvect[0]);
bp->force[1]-= kd * (auxvect[1]);
bp->force[2]-= kd * (auxvect[2]);
- if (nl_flags & NLF_BUILD) {
- //int ia =3*(sb->totpoint-a);
- normalize_v3(auxvect);
- /* depending on my vel */
- //dfdv_goal(ia, ia, kd*forcetime);
- }
}
else {
@@ -2500,15 +2402,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
bp->force[1]-= bp->vec[1]*kd;
bp->force[2]-= bp->vec[2]*kd;
/* friction in media done */
- if (nl_flags & NLF_BUILD) {
- //int ia =3*(sb->totpoint-a);
- /* da/dv = */
-
- // nlMatrixAdd(ia, ia, forcetime*kd);
- // nlMatrixAdd(ia+1, ia+1, forcetime*kd);
- // nlMatrixAdd(ia+2, ia+2, forcetime*kd);
- }
-
}
/* +++cached collision targets */
bp->choke = 0.0f;
@@ -2519,7 +2412,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
kd = 1.0f;
if (sb_deflect_face(ob, bp->pos, facenormal, defforce, &cf, timenow, vel, &intrusion)) {
- if ((!nl_flags)&&(intrusion < 0.0f)) {
+ if (intrusion < 0.0f) {
if (G.debug_value & 0x01) { // 17 we did check for bit 0x10 before
/*fixing bug [17428] this forces adaptive step size to tiny steps
in some situations .. keeping G.debug_value==17 option for old files 'needing' the bug
@@ -2549,13 +2442,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
madd_v3_v3fl(bp->force, cfforce, -cf * 50.0f);
}
madd_v3_v3fl(bp->force, defforce, kd);
- if (nl_flags & NLF_BUILD) {
- // int ia =3*(sb->totpoint-a);
- // int op =3*sb->totpoint;
- //dfdx_goal(ia, ia, op, mpos); // don't do unless you know
- //dfdv_goal(ia, ia, -cf);
-
- }
}
@@ -2565,7 +2451,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* +++springs */
if (ob->softflag & OB_SB_EDGES) {
if (sb->bspring) { /* spring list exists at all ? */
- for (b=bp->nofsprings;b>0;b--) {
+ for (int b = bp->nofsprings; b > 0; b--) {
bs = sb->bspring + bp->springs[b-1];
if (do_springcollision || do_aero) {
add_v3_v3(bp->force, bs->ext_force);
@@ -2573,9 +2459,9 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
bp->choke = bs->cf;
}
- // sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float forcetime, int nl_flags)
+ // sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float forcetime)
// rather remove nl_falgs from code .. will make things a lot cleaner
- sb_spring_force(ob, sb->totpoint-a, bs, iks, forcetime, 0);
+ sb_spring_force(ob, sb->totpoint-a, bs, iks, forcetime);
}/* loop springs */
}/* existing spring list */
}/*any edges*/
@@ -2586,76 +2472,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
-
- /* finish matrix and solve */
-#if (0) // remove onl linking for now .. still i am not sure .. the jacobian can be useful .. so keep that BM
- if (nl_flags & NLF_SOLVE) {
- //double sct, sst=PIL_check_seconds_timer();
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- int iv =3*(sb->totpoint-a);
- int ip =3*(2*sb->totpoint-a);
- int n;
- for (n=0;n<3;n++) {nlRightHandSideSet(0, iv+n, bp->force[0+n]);}
- for (n=0;n<3;n++) {nlRightHandSideSet(0, ip+n, bp->vec[0+n]);}
- }
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
-
- if ((G.debug_value == 32) && (nl_flags & NLF_BUILD)) {
- printf("####MEE#####\n");
- nlPrintMatrix();
- }
-
- success= nlSolveAdvanced(NULL, 1);
-
- // nlPrintMatrix(); /* for debug purpose .. anyhow cropping B vector looks like working */
- if (success) {
- float f;
- int index =0;
- /* for debug purpose .. anyhow cropping B vector looks like working */
- if (G.debug_value ==32)
- for (a=2*sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- f=nlGetVariable(0, index);
- printf("(%f ", f);index++;
- f=nlGetVariable(0, index);
- printf("%f ", f);index++;
- f=nlGetVariable(0, index);
- printf("%f)", f);index++;
- }
-
- index =0;
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- f=nlGetVariable(0, index);
- bp->impdv[0] = f; index++;
- f=nlGetVariable(0, index);
- bp->impdv[1] = f; index++;
- f=nlGetVariable(0, index);
- bp->impdv[2] = f; index++;
- }
- /*
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- f=nlGetVariable(0, index);
- bp->impdx[0] = f; index++;
- f=nlGetVariable(0, index);
- bp->impdx[1] = f; index++;
- f=nlGetVariable(0, index);
- bp->impdx[2] = f; index++;
- }
- */
- }
- else {
- printf("Matrix inversion failed\n");
- for (a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
- copy_v3_v3(bp->impdv, bp->force);
- }
-
- }
-
- //sct=PIL_check_seconds_timer();
- //if (sct-sst > 0.01f) printf(" implicit solver time %f %s \r", sct-sst, ob->id.name);
- }
- /* cleanup */
-#endif
pdEndEffectors(&do_effector);
}
}
@@ -3690,12 +3506,12 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
sb->scratch->flag &= ~SBF_DOFUZZY;
/* do predictive euler step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime, 0);
+ softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags);
/* crop new slope values to do averaged slope step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime, 0);
+ softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
softbody_apply_goalsnap(ob);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 0b89931aa75..b016f8a49ed 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -71,27 +71,20 @@ static int sound_cfra;
static char **audio_device_names = NULL;
#endif
-bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
+bSound *BKE_sound_new_file(struct Main *bmain, const char *filepath)
{
bSound *sound;
-
- char str[FILE_MAX];
const char *path;
+ char str[FILE_MAX];
- size_t len;
-
- BLI_strncpy(str, filename, sizeof(str));
+ BLI_strncpy(str, filepath, sizeof(str));
path = /*bmain ? bmain->name :*/ G.main->name;
BLI_path_abs(str, path);
- len = strlen(filename);
- while (len > 0 && filename[len - 1] != '/' && filename[len - 1] != '\\')
- len--;
-
- sound = BKE_libblock_alloc(bmain, ID_SO, filename + len);
- BLI_strncpy(sound->name, filename, FILE_MAX);
+ sound = BKE_libblock_alloc(bmain, ID_SO, BLI_path_basename(filepath));
+ BLI_strncpy(sound->name, filepath, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
BKE_sound_load(bmain, sound);
@@ -99,6 +92,37 @@ bSound *BKE_sound_new_file(struct Main *bmain, const char *filename)
return sound;
}
+bSound *BKE_sound_new_file_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists)
+{
+ bSound *sound;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ BLI_strncpy(str, filepath, sizeof(str));
+ BLI_path_abs(str, bmain->name);
+
+ /* first search an identical filepath */
+ for (sound = bmain->sound.first; sound; sound = sound->id.next) {
+ BLI_strncpy(strtest, sound->name, sizeof(sound->name));
+ BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &sound->id));
+
+ if (BLI_path_cmp(strtest, str) == 0) {
+ id_us_plus(&sound->id); /* officially should not, it doesn't link here! */
+ if (r_exists)
+ *r_exists = true;
+ return sound;
+ }
+ }
+
+ if (r_exists)
+ *r_exists = false;
+ return BKE_sound_new_file(bmain, filepath);
+}
+
+bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath)
+{
+ return BKE_sound_new_file_exists_ex(bmain, filepath, NULL);
+}
+
void BKE_sound_free(bSound *sound)
{
if (sound->packedfile) {
@@ -203,7 +227,7 @@ void BKE_sound_init(struct Main *bmain)
buffersize = 1024;
if (specs.rate < AUD_RATE_8000)
- specs.rate = AUD_RATE_44100;
+ specs.rate = AUD_RATE_48000;
if (specs.format <= AUD_FORMAT_INVALID)
specs.format = AUD_FORMAT_S16;
@@ -538,6 +562,7 @@ void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
+ printf("%s\n", __func__);
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
}
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index 7a800555144..c452065fbad 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -37,11 +37,9 @@
#include "BKE_main.h"
#include "BKE_speaker.h"
-void *BKE_speaker_add(Main *bmain, const char *name)
+void BKE_speaker_init(Speaker *spk)
{
- Speaker *spk;
-
- spk = BKE_libblock_alloc(bmain, ID_SPK, name);
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(spk, id));
spk->attenuation = 1.0f;
spk->cone_angle_inner = 360.0f;
@@ -55,6 +53,15 @@ void *BKE_speaker_add(Main *bmain, const char *name)
spk->volume = 1.0f;
spk->volume_max = 1.0f;
spk->volume_min = 0.0f;
+}
+
+void *BKE_speaker_add(Main *bmain, const char *name)
+{
+ Speaker *spk;
+
+ spk = BKE_libblock_alloc(bmain, ID_SPK, name);
+
+ BKE_speaker_init(spk);
return spk;
}
@@ -65,7 +72,7 @@ Speaker *BKE_speaker_copy(Speaker *spk)
spkn = BKE_libblock_copy(&spk->id);
if (spkn->sound)
- spkn->sound->id.us++;
+ id_us_plus(&spkn->sound->id);
if (spk->id.lib) {
BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id);
@@ -74,6 +81,11 @@ Speaker *BKE_speaker_copy(Speaker *spk)
return spkn;
}
+static void extern_local_speaker(Speaker *spk)
+{
+ id_lib_extern((ID *)spk->sound);
+}
+
void BKE_speaker_make_local(Speaker *spk)
{
Main *bmain = G.main;
@@ -88,6 +100,7 @@ void BKE_speaker_make_local(Speaker *spk)
if (spk->id.lib == NULL) return;
if (spk->id.us == 1) {
id_clear_lib_data(bmain, &spk->id);
+ extern_local_speaker(spk);
return;
}
@@ -102,6 +115,7 @@ void BKE_speaker_make_local(Speaker *spk)
if (is_local && is_lib == false) {
id_clear_lib_data(bmain, &spk->id);
+ extern_local_speaker(spk);
}
else if (is_local && is_lib) {
Speaker *spk_new = BKE_speaker_copy(spk);
@@ -116,8 +130,8 @@ void BKE_speaker_make_local(Speaker *spk)
if (ob->id.lib == NULL) {
ob->data = spk_new;
- spk_new->id.us++;
- spk->id.us--;
+ id_us_plus(&spk_new->id);
+ id_us_min(&spk->id);
}
}
ob = ob->id.next;
@@ -128,7 +142,7 @@ void BKE_speaker_make_local(Speaker *spk)
void BKE_speaker_free(Speaker *spk)
{
if (spk->sound)
- spk->sound->id.us--;
+ id_us_min(&spk->sound->id);
BKE_animdata_free((ID *)spk);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 509ca9cdd19..97994332411 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -30,6 +30,9 @@
*/
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wvla"
+# endif
# define USE_DYNSIZE
#endif
@@ -71,9 +74,10 @@
#endif
#include "GPU_draw.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_buffers.h"
+#include "GPU_shader.h"
+#include "GPU_basic_shader.h"
#include "CCGSubSurf.h"
@@ -84,8 +88,6 @@
/* assumes MLoop's are layed out 4 for each poly, in order */
#define USE_LOOP_LAYOUT_FAST
-extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
-
static ThreadRWMutex loops_cache_rwlock = BLI_RWLOCK_INITIALIZER;
static ThreadRWMutex origindex_cache_rwlock = BLI_RWLOCK_INITIALIZER;
@@ -1522,19 +1524,19 @@ static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop)
mv->v = v1;
mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
- mv++, i++;
+ mv++; i++;
mv->v = v2;
mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
- mv++, i++;
+ mv++; i++;
mv->v = v3;
mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
- mv++, i++;
+ mv++; i++;
mv->v = v4;
mv->e = GET_UINT_FROM_POINTER(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
- mv++, i++;
+ mv++; i++;
}
}
}
@@ -1912,6 +1914,10 @@ static void ccgDM_buffer_copy_normal(
int shademodel;
int start = 0;
+ /* we are in sculpt mode, disable loop normals (since they won't get updated) */
+ if (ccgdm->pbvh)
+ lnors = NULL;
+
CCG_key_top_level(&key, ss);
for (i = 0; i < totface; i++) {
@@ -2054,13 +2060,13 @@ static void ccgDM_buffer_copy_triangles(
for (x = 0; x < gridFaces; x++) {
start = gpumat->start + fc[mati].i_tri_hidden;
- varray[start--] = totloops + 1;
+ varray[start--] = totloops;
varray[start--] = totloops + 2;
varray[start--] = totloops + 3;
varray[start--] = totloops;
varray[start--] = totloops + 1;
- varray[start--] = totloops + 3;
+ varray[start--] = totloops + 2;
fc[mati].i_tri_hidden -= 6;
@@ -2078,9 +2084,9 @@ static void ccgDM_buffer_copy_triangles(
varray[start++] = totloops + 3;
varray[start++] = totloops + 2;
- varray[start++] = totloops + 1;
+ varray[start++] = totloops;
- varray[start++] = totloops + 3;
+ varray[start++] = totloops + 2;
varray[start++] = totloops + 1;
varray[start++] = totloops;
@@ -2167,7 +2173,7 @@ static void ccgDM_buffer_copy_color(
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
- const char *mloopcol = user_data;
+ const unsigned char *mloopcol = user_data;
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int i, totface = ccgSubSurf_getNumFaces(ss);
@@ -2184,10 +2190,10 @@ static void ccgDM_buffer_copy_color(
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridFaces; y++) {
for (x = 0; x < gridFaces; x++) {
- copy_v3_v3_char((char *)&varray[start + 0], &mloopcol[iface * 16 + 0]);
- copy_v3_v3_char((char *)&varray[start + 3], &mloopcol[iface * 16 + 12]);
- copy_v3_v3_char((char *)&varray[start + 6], &mloopcol[iface * 16 + 8]);
- copy_v3_v3_char((char *)&varray[start + 9], &mloopcol[iface * 16 + 4]);
+ copy_v3_v3_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
+ copy_v3_v3_uchar(&varray[start + 3], &mloopcol[iface * 16 + 12]);
+ copy_v3_v3_uchar(&varray[start + 6], &mloopcol[iface * 16 + 8]);
+ copy_v3_v3_uchar(&varray[start + 9], &mloopcol[iface * 16 + 4]);
start += 12;
iface++;
@@ -2705,6 +2711,13 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
GPU_buffers_unbind();
}
+typedef struct {
+ DMVertexAttribs attribs;
+ int numdata;
+
+ GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
+} GPUMaterialConv;
+
/* Only used by non-editmesh types */
static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
DMSetMaterial setMaterial,
@@ -2715,19 +2728,18 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
GPUVertexAttribs gattribs;
- DMVertexAttribs attribs = {{{NULL}}};
- /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
+ int a, b;
+ const DMFlagMat *faceFlags = ccgdm->faceFlags;
+ unsigned char *varray;
+ size_t max_element_size = 0;
+ int tot_loops = 0;
+ int totpoly = ccgSubSurf_getNumFaces(ss);
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, i, do_draw, numVerts, matnr, new_matnr, totface;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- CCGSubSurf *ss = ccgdm->ss;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
const int level = ccgSubSurf_getSubdivisionLevels(ss);
const int face_side = 1 << level;
const int grid_side = 1 << (level - 1);
@@ -2748,6 +2760,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
: num_face_verts * grid_patches;
int new_matnr;
bool new_draw_smooth;
+
if (faceFlags) {
new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
new_matnr = (faceFlags[i].mat_nr + 1);
@@ -2791,154 +2804,359 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
#endif
+ glShadeModel(GL_SMOOTH);
+
CCG_key_top_level(&key, ss);
ccgdm_pbvh_update(ccgdm);
- do_draw = 0;
- matnr = -1;
+ if (setDrawOptions != NULL) {
+ const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
+ DMVertexAttribs attribs = {{{NULL}}};
+ int i;
+ int matnr = -1;
+ int do_draw = 0;
#define PASSATTRIB(dx, dy, vert) { \
if (attribs.totorco) \
index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
else \
index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
} (void)0
- totface = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
-
- numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
+ totpoly = ccgSubSurf_getNumFaces(ss);
+ for (a = 0, i = 0; i < totpoly; i++) {
+ CCGFace *f = ccgdm->faceMap[i].face;
+ const float (*ln)[3] = NULL;
+ int S, x, y, drawSmooth;
+ int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
+ int origIndex = ccgDM_getFaceMapIndex(ss, f);
- if (new_matnr != matnr) {
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw)
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
+ int numVerts = ccgSubSurf_getFaceNumVerts(f);
+ int new_matnr;
- if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) &&
- (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP)))
- {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
+ if (faceFlags) {
+ drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
+ new_matnr = faceFlags[index].mat_nr + 1;
+ }
+ else {
+ drawSmooth = 1;
+ new_matnr = 1;
+ }
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
+ if (lnors) {
+ ln = lnors;
+ lnors += (gridFaces * gridFaces * numVerts) * 4;
+ }
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
+ if (new_matnr != matnr) {
+ do_draw = setMaterial(matnr = new_matnr, &gattribs);
+ if (do_draw)
+ DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ }
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
+ if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) &&
+ (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP)))
+ {
+ a += gridFaces * gridFaces * numVerts;
+ continue;
+ }
- ln += 4;
- a++;
+ glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
+ for (S = 0; S < numVerts; S++) {
+ CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ CCGElem *vda, *vdb;
+
+ if (ln) {
+ glBegin(GL_QUADS);
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+ float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
+ float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
+ float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
+ float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
+
+ PASSATTRIB(0, 1, 1);
+ glNormal3fv(ln[1]);
+ glVertex3fv(dco);
+ PASSATTRIB(1, 1, 2);
+ glNormal3fv(ln[2]);
+ glVertex3fv(cco);
+ PASSATTRIB(1, 0, 3);
+ glNormal3fv(ln[3]);
+ glVertex3fv(bco);
+ PASSATTRIB(0, 0, 0);
+ glNormal3fv(ln[0]);
+ glVertex3fv(aco);
+
+ ln += 4;
+ a++;
+ }
}
+ glEnd();
}
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
+ else if (drawSmooth) {
+ for (y = 0; y < gridFaces; y++) {
+ glBegin(GL_QUAD_STRIP);
+ for (x = 0; x < gridFaces; x++) {
+ vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
+ vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
+
+ PASSATTRIB(0, 0, 0);
+ glNormal3fv(CCG_elem_no(&key, vda));
+ glVertex3fv(CCG_elem_co(&key, vda));
+
+ PASSATTRIB(0, 1, 1);
+ glNormal3fv(CCG_elem_no(&key, vdb));
+ glVertex3fv(CCG_elem_co(&key, vdb));
+
+ if (x != gridFaces - 1)
+ a++;
+ }
+
vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
+
+ PASSATTRIB(0, 0, 3);
glNormal3fv(CCG_elem_no(&key, vda));
glVertex3fv(CCG_elem_co(&key, vda));
- PASSATTRIB(0, 1, 1);
+ PASSATTRIB(0, 1, 2);
glNormal3fv(CCG_elem_no(&key, vdb));
glVertex3fv(CCG_elem_co(&key, vdb));
- if (x != gridFaces - 1)
+ glEnd();
+
+ a++;
+ }
+ }
+ else {
+ glBegin(GL_QUADS);
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+ float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
+ float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
+ float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
+ float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
+
+ ccgDM_glNormalFast(aco, bco, cco, dco);
+
+ PASSATTRIB(0, 1, 1);
+ glVertex3fv(dco);
+ PASSATTRIB(1, 1, 2);
+ glVertex3fv(cco);
+ PASSATTRIB(1, 0, 3);
+ glVertex3fv(bco);
+ PASSATTRIB(0, 0, 0);
+ glVertex3fv(aco);
+
a++;
+ }
}
+ glEnd();
+ }
+ }
+ }
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
+#undef PASSATTRIB
+ }
+ else {
+ GPUMaterialConv *matconv;
+ size_t offset;
+ int *mat_orig_to_new;
+ int tot_active_mat;
+ GPUBuffer *buffer = NULL;
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
+ GPU_vertex_setup(dm);
+ GPU_normal_setup(dm);
+ GPU_triangle_setup(dm);
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
+ tot_active_mat = dm->drawObject->totmaterial;
- glEnd();
+ matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat,
+ "cdDM_drawMappedFacesGLSL.matconv");
+ mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
+ "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
- a++;
+ /* part one, check what attributes are needed per material */
+ for (a = 0; a < tot_active_mat; a++) {
+ int new_matnr;
+ int do_draw;
+
+ new_matnr = dm->drawObject->materials[a].mat_nr;
+
+ /* map from original material index to new
+ * GPUBufferMaterial index */
+ mat_orig_to_new[new_matnr] = a;
+ do_draw = setMaterial(new_matnr + 1, &gattribs);
+
+ if (do_draw) {
+ int numdata = 0;
+ DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
+
+ if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
+ matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+ matconv[a].datatypes[numdata].size = 3;
+ matconv[a].datatypes[numdata].type = GL_FLOAT;
+ numdata++;
+ }
+ for (b = 0; b < matconv[a].attribs.tottface; b++) {
+ if (matconv[a].attribs.tface[b].array) {
+ matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+ matconv[a].datatypes[numdata].size = 2;
+ matconv[a].datatypes[numdata].type = GL_FLOAT;
+ numdata++;
+ }
+ }
+ for (b = 0; b < matconv[a].attribs.totmcol; b++) {
+ if (matconv[a].attribs.mcol[b].array) {
+ matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+ matconv[a].datatypes[numdata].size = 4;
+ matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
+ numdata++;
+ }
+ }
+ if (matconv[a].attribs.tottang && matconv[a].attribs.tang.array) {
+ matconv[a].datatypes[numdata].index = matconv[a].attribs.tang.gl_index;
+ matconv[a].datatypes[numdata].size = 4;
+ matconv[a].datatypes[numdata].type = GL_FLOAT;
+ numdata++;
+ }
+ if (numdata != 0) {
+ matconv[a].numdata = numdata;
+ max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
}
}
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
+ }
- ccgDM_glNormalFast(aco, bco, cco, dco);
+ /* part two, generate and fill the arrays with the data */
+ if (max_element_size > 0) {
+ buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
+ varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
+ if (varray == NULL) {
+ GPU_buffers_unbind();
+ GPU_buffer_free(buffer);
+ MEM_freeN(mat_orig_to_new);
+ MEM_freeN(matconv);
+ fprintf(stderr, "Out of memory, can't draw object\n");
+ return;
+ }
+
+ for (a = 0; a < totpoly; a++) {
+ CCGFace *f = ccgdm->faceMap[a].face;
+ int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
+ int i;
+
+ if (faceFlags) {
+ i = mat_orig_to_new[faceFlags[orig_index].mat_nr];
+ }
+ else {
+ i = mat_orig_to_new[0];
+ }
+
+ if (matconv[i].numdata != 0) {
+ for (S = 0; S < numVerts; S++) {
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+
+ offset = tot_loops * max_element_size;
+
+ if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
+ int index;
+
+ index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize);
+ copy_v3_v3((float *)&varray[offset],
+ (float *)matconv[i].attribs.orco.array[index]);
+ index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize);
+ copy_v3_v3((float *)&varray[offset + max_element_size],
+ (float *)matconv[i].attribs.orco.array[index]);
+ index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize);
+ copy_v3_v3((float *)&varray[offset + 2 * max_element_size],
+ (float *)matconv[i].attribs.orco.array[index]);
+ index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize);
+ copy_v3_v3((float *)&varray[offset + 3 * max_element_size],
+ (float *)matconv[i].attribs.orco.array[index]);
+
+ offset += sizeof(float) * 3;
+ }
+ for (b = 0; b < matconv[i].attribs.tottface; b++) {
+ if (matconv[i].attribs.tface[b].array) {
+ const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops;
+
+ copy_v2_v2((float *)&varray[offset], mloopuv[0].uv);
+ copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv);
+ copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv);
+ copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv);
+
+ offset += sizeof(float) * 2;
+ }
+ }
+ for (b = 0; b < matconv[i].attribs.totmcol; b++) {
+ if (matconv[i].attribs.mcol[b].array) {
+ const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops;
+
+ copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r);
+ copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r);
+ copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r);
+ copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r);
+
+ offset += sizeof(unsigned char) * 4;
+ }
+ }
+ if (matconv[i].attribs.tottang && matconv[i].attribs.tang.array) {
+ const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang.array + tot_loops;
+
+ copy_v4_v4((float *)&varray[offset], looptang[0]);
+ copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
+ copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
+ copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
+
+ offset += sizeof(float) * 4;
+ }
+
+ tot_loops += 4;
+ }
+ }
}
}
- glEnd();
+ else {
+ tot_loops += 4 * numVerts * gridFaces * gridFaces;
+ }
+ }
+ GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
+ }
+
+ for (a = 0; a < tot_active_mat; a++) {
+ int new_matnr;
+ int do_draw;
+
+ new_matnr = dm->drawObject->materials[a].mat_nr;
+
+ do_draw = setMaterial(new_matnr + 1, &gattribs);
+
+ if (do_draw) {
+ if (matconv[a].numdata) {
+ GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
+ }
+ GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
+ dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
+ if (matconv[a].numdata) {
+ GPU_interleaved_attrib_unbind();
+ }
}
}
+
+ GPU_buffers_unbind();
+ if (buffer)
+ GPU_buffer_free(buffer);
+
+ MEM_freeN(mat_orig_to_new);
+ MEM_freeN(matconv);
}
-#undef PASSATTRIB
+ glShadeModel(GL_FLAT);
}
static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
@@ -2961,7 +3179,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
int edgeSize = ccgSubSurf_getEdgeSize(ss);
DMFlagMat *faceFlags = ccgdm->faceFlags;
const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, i, numVerts, matnr, new_matnr, totface;
+ int a, i, numVerts, matnr, totface;
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
@@ -3007,6 +3225,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
int S, x, y, drawSmooth;
int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int origIndex = ccgDM_getFaceMapIndex(ss, f);
+ int new_matnr;
numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -3212,7 +3431,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
CCGFace *f = ccgdm->faceMap[polyindex].face;
int numVerts = ccgSubSurf_getFaceNumVerts(f);
int index = ccgDM_getFaceMapIndex(ss, f);
- int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
+ int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
int mat_nr;
int facequads = numVerts * gridFaces * gridFaces;
int actualFace = ccgdm->faceMap[polyindex].startFace;
@@ -3223,7 +3442,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
}
if (faceFlags) {
- mat_nr = faceFlags[origIndex].mat_nr;
+ mat_nr = faceFlags[orig_index].mat_nr;
}
else {
mat_nr = 0;
@@ -3340,7 +3559,6 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- DMFlagMat *faceFlags = ccgdm->faceFlags;
int new_matnr;
bool draw_smooth, do_draw = true;
if (setDrawOptions == NULL) {
@@ -3433,8 +3651,8 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
if (draw_option != DM_DRAW_OPTION_SKIP) {
if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
}
/* no need to set shading mode to flat because
@@ -3533,7 +3751,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
}
}
if (draw_option == DM_DRAW_OPTION_STIPPLE)
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
}
}
@@ -4120,7 +4338,6 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
looptri);
ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new();
- BLI_assert(!(me->mface == NULL && me->mpoly != NULL)); /* BMESH ONLY complain if mpoly is valid but not mface */
BKE_pbvh_build_mesh(ccgdm->pbvh, me->mpoly, me->mloop, me->mvert, me->totvert, &me->vdata,
looptri, looptris_num);
}
diff --git a/source/blender/blenkernel/intern/suggestions.c b/source/blender/blenkernel/intern/suggestions.c
index d46fa591885..eb17e103671 100644
--- a/source/blender/blenkernel/intern/suggestions.c
+++ b/source/blender/blenkernel/intern/suggestions.c
@@ -35,6 +35,9 @@
#include <ctype.h>
#include "MEM_guardedalloc.h"
+
+#include "BLI_string.h"
+
#include "DNA_text_types.h"
#include "BKE_suggestions.h"
@@ -47,18 +50,6 @@ static SuggList suggestions = {NULL, NULL, NULL, NULL, NULL};
static char *documentation = NULL;
//static int doc_lines = 0;
-/* TODO, replace with BLI_strncasecmp() */
-static int txttl_cmp(const char *first, const char *second, int len)
-{
- int cmp, i;
- for (cmp = 0, i = 0; i < len; i++) {
- if ((cmp = toupper(first[i]) - toupper(second[i]))) {
- break;
- }
- }
- return cmp;
-}
-
static void txttl_free_suggest(void)
{
SuggItem *item, *prev;
@@ -124,7 +115,6 @@ void texttool_suggest_add(const char *name, char type)
return;
}
- newitem->name = (char *) (newitem + 1);
memcpy(newitem->name, name, len + 1);
newitem->type = type;
newitem->prev = newitem->next = NULL;
@@ -136,7 +126,7 @@ void texttool_suggest_add(const char *name, char type)
else {
cmp = -1;
for (item = suggestions.last; item; item = item->prev) {
- cmp = txttl_cmp(name, item->name, len);
+ cmp = BLI_strncasecmp(name, item->name, len);
/* Newitem comes after this item, insert here */
if (cmp >= 0) {
@@ -177,7 +167,7 @@ void texttool_suggest_prefix(const char *prefix, const int prefix_len)
first = last = NULL;
for (match = suggestions.first; match; match = match->next) {
- cmp = txttl_cmp(prefix, match->name, prefix_len);
+ cmp = BLI_strncasecmp(prefix, match->name, prefix_len);
if (cmp == 0) {
if (!first) {
first = match;
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 77d6043d6f3..6def9e3e503 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -152,17 +152,28 @@ static void init_undo_text(Text *text)
text->undo_buf = MEM_mallocN(text->undo_len, "undo buf");
}
-void BKE_text_free(Text *text)
+/**
+ * \note caller must handle `undo_buf` and `compiled` members.
+ */
+void BKE_text_free_lines(Text *text)
{
- TextLine *tmp;
-
- for (tmp = text->lines.first; tmp; tmp = tmp->next) {
+ for (TextLine *tmp = text->lines.first, *tmp_next; tmp; tmp = tmp_next) {
+ tmp_next = tmp->next;
MEM_freeN(tmp->line);
- if (tmp->format)
+ if (tmp->format) {
MEM_freeN(tmp->format);
+ }
+ MEM_freeN(tmp);
}
-
- BLI_freelistN(&text->lines);
+
+ BLI_listbase_clear(&text->lines);
+
+ text->curl = text->sell = NULL;
+}
+
+void BKE_text_free(Text *text)
+{
+ BKE_text_free_lines(text);
if (text->name) MEM_freeN(text->name);
MEM_freeN(text->undo_buf);
@@ -171,14 +182,12 @@ void BKE_text_free(Text *text)
#endif
}
-Text *BKE_text_add(Main *bmain, const char *name)
+void BKE_text_init(Text *ta)
{
- Text *ta;
TextLine *tmp;
-
- ta = BKE_libblock_alloc(bmain, ID_TXT, name);
- ta->id.us = 1;
-
+
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ta, id));
+
ta->name = NULL;
init_undo_text(ta);
@@ -206,6 +215,15 @@ Text *BKE_text_add(Main *bmain, const char *name)
ta->curc = 0;
ta->sell = ta->lines.first;
ta->selc = 0;
+}
+
+Text *BKE_text_add(Main *bmain, const char *name)
+{
+ Text *ta;
+
+ ta = BKE_libblock_alloc(bmain, ID_TXT, name);
+
+ BKE_text_init(ta);
return ta;
}
@@ -332,63 +350,40 @@ static void text_from_buf(Text *text, const unsigned char *buffer, const int len
bool BKE_text_reload(Text *text)
{
- FILE *fp;
- int len;
unsigned char *buffer;
- TextLine *tmp;
- char str[FILE_MAX];
+ size_t buffer_len;
+ char filepath_abs[FILE_MAX];
BLI_stat_t st;
if (!text->name) {
return false;
}
- BLI_strncpy(str, text->name, FILE_MAX);
- BLI_path_abs(str, G.main->name);
+ BLI_strncpy(filepath_abs, text->name, FILE_MAX);
+ BLI_path_abs(filepath_abs, G.main->name);
- fp = BLI_fopen(str, "r");
- if (fp == NULL) {
- return false;
- }
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
- if (UNLIKELY(len == -1)) {
- fclose(fp);
+ buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
+ if (buffer == NULL) {
return false;
}
/* free memory: */
-
- for (tmp = text->lines.first; tmp; tmp = tmp->next) {
- MEM_freeN(tmp->line);
- if (tmp->format) MEM_freeN(tmp->format);
- }
-
- BLI_freelistN(&text->lines);
-
- BLI_listbase_clear(&text->lines);
- text->curl = text->sell = NULL;
+ BKE_text_free_lines(text);
+ txt_make_dirty(text);
/* clear undo buffer */
MEM_freeN(text->undo_buf);
init_undo_text(text);
- buffer = MEM_mallocN(len, "text_buffer");
- /* under windows fread can return less than len bytes because
- * of CR stripping */
- len = fread(buffer, 1, len, fp);
-
- fclose(fp);
- if (BLI_stat(str, &st) != -1) {
+ if (BLI_stat(filepath_abs, &st) != -1) {
text->mtime = st.st_mtime;
}
else {
text->mtime = 0;
}
- text_from_buf(text, buffer, len);
+ text_from_buf(text, buffer, buffer_len);
MEM_freeN(buffer);
return true;
@@ -396,32 +391,22 @@ bool BKE_text_reload(Text *text)
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
- FILE *fp;
- int len;
unsigned char *buffer;
+ size_t buffer_len;
Text *ta;
- char str[FILE_MAX];
+ char filepath_abs[FILE_MAX];
BLI_stat_t st;
- BLI_strncpy(str, file, FILE_MAX);
+ BLI_strncpy(filepath_abs, file, FILE_MAX);
if (relpath) /* can be NULL (bg mode) */
- BLI_path_abs(str, relpath);
+ BLI_path_abs(filepath_abs, relpath);
- fp = BLI_fopen(str, "r");
- if (fp == NULL) {
- return NULL;
- }
-
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
- if (UNLIKELY(len == -1)) {
- fclose(fp);
- return NULL;
+ buffer = BLI_file_read_text_as_mem(filepath_abs, 0, &buffer_len);
+ if (buffer == NULL) {
+ return false;
}
- ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(str));
- ta->id.us = 1;
+ ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs));
BLI_listbase_clear(&ta->lines);
ta->curl = ta->sell = NULL;
@@ -439,22 +424,15 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
/* clear undo buffer */
init_undo_text(ta);
-
- buffer = MEM_mallocN(len, "text_buffer");
- /* under windows fread can return less than len bytes because
- * of CR stripping */
- len = fread(buffer, 1, len, fp);
-
- fclose(fp);
- if (BLI_stat(str, &st) != -1) {
+ if (BLI_stat(filepath_abs, &st) != -1) {
ta->mtime = st.st_mtime;
}
else {
ta->mtime = 0;
}
- text_from_buf(ta, buffer, len);
+ text_from_buf(ta, buffer, buffer_len);
MEM_freeN(buffer);
@@ -1012,11 +990,51 @@ void txt_move_down(Text *text, const bool sel)
if (!sel) txt_pop_sel(text);
}
+int txt_calc_tab_left(TextLine *tl, int ch)
+{
+ /* do nice left only if there are only spaces */
+
+ int tabsize = (ch < TXT_TABSIZE) ? ch : TXT_TABSIZE;
+
+ for (int i = 0; i < ch; i++)
+ if (tl->line[i] != ' ') {
+ tabsize = 0;
+ break;
+ }
+
+ /* if in the middle of the space-tab */
+ if (tabsize && ch % TXT_TABSIZE != 0)
+ tabsize = (ch % TXT_TABSIZE);
+ return tabsize;
+}
+
+int txt_calc_tab_right(TextLine *tl, int ch)
+{
+ if (tl->line[ch] == ' ') {
+ int i;
+ for (i = 0; i < ch; i++) {
+ if (tl->line[i] != ' ') {
+ return 0;
+ }
+ }
+
+ int tabsize = (ch) % TXT_TABSIZE + 1;
+ for (i = ch + 1; tl->line[i] == ' ' && tabsize < TXT_TABSIZE; i++) {
+ tabsize++;
+ }
+
+ return i - ch;
+ }
+ else {
+ return 0;
+ }
+}
+
void txt_move_left(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
- int tabsize = 0, i = 0;
+ int tabsize = 0;
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
@@ -1029,24 +1047,15 @@ void txt_move_left(Text *text, const bool sel)
}
}
else {
- // do nice left only if there are only spaces
+ /* do nice left only if there are only spaces */
// TXT_TABSIZE hardcoded in DNA_text_types.h
if (text->flags & TXT_TABSTOSPACES) {
- tabsize = (*charp < TXT_TABSIZE) ? *charp : TXT_TABSIZE;
-
- for (i = 0; i < (*charp); i++)
- if ((*linep)->line[i] != ' ') {
- tabsize = 0;
- break;
- }
-
- // if in the middle of the space-tab
- if (tabsize && (*charp) % TXT_TABSIZE != 0)
- tabsize = ((*charp) % TXT_TABSIZE);
+ tabsize = txt_calc_tab_left(*linep, *charp);
}
- if (tabsize)
+ if (tabsize) {
(*charp) -= tabsize;
+ }
else {
const char *prev = BLI_str_prev_char_utf8((*linep)->line + *charp);
*charp = prev - (*linep)->line;
@@ -1059,8 +1068,7 @@ void txt_move_left(Text *text, const bool sel)
void txt_move_right(Text *text, const bool sel)
{
TextLine **linep;
- int *charp, i;
- bool do_tab = false;
+ int *charp;
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
@@ -1073,22 +1081,16 @@ void txt_move_right(Text *text, const bool sel)
}
}
else {
- // do nice right only if there are only spaces
- // spaces hardcoded in DNA_text_types.h
- if (text->flags & TXT_TABSTOSPACES && (*linep)->line[*charp] == ' ') {
- do_tab = true;
- for (i = 0; i < *charp; i++)
- if ((*linep)->line[i] != ' ') {
- do_tab = false;
- break;
- }
+ /* do nice right only if there are only spaces */
+ /* spaces hardcoded in DNA_text_types.h */
+ int tabsize = 0;
+
+ if (text->flags & TXT_TABSTOSPACES) {
+ tabsize = txt_calc_tab_right(*linep, *charp);
}
- if (do_tab) {
- int tabsize = (*charp) % TXT_TABSIZE + 1;
- for (i = *charp + 1; (*linep)->line[i] == ' ' && tabsize < TXT_TABSIZE; i++)
- tabsize++;
- (*charp) = i;
+ if (tabsize) {
+ (*charp) += tabsize;
}
else {
(*charp) += BLI_str_utf8_size((*linep)->line + *charp);
@@ -2109,7 +2111,7 @@ void txt_do_undo(Text *text)
{
int op = text->undo_buf[text->undo_pos];
int prev_flags;
- unsigned int linep, i;
+ unsigned int linep;
unsigned int uchar;
unsigned int curln, selln;
unsigned short curc, selc;
@@ -2178,6 +2180,8 @@ void txt_do_undo(Text *text)
break;
case UNDO_DBLOCK:
+ {
+ int i;
/* length of the string in the buffer */
linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
@@ -2207,8 +2211,10 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
-
+ }
case UNDO_IBLOCK:
+ {
+ int i;
/* length of the string in the buffer */
linep = txt_undo_read_uint32(text->undo_buf, &text->undo_pos);
@@ -2246,6 +2252,7 @@ void txt_do_undo(Text *text)
text->undo_pos--;
break;
+ }
case UNDO_INDENT:
case UNDO_COMMENT:
case UNDO_DUPLICATE:
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 88a412d5e95..d353042b711 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -580,6 +580,8 @@ void BKE_texture_free(Tex *tex)
void BKE_texture_default(Tex *tex)
{
+ /* BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(tex, id)); */ /* Not here, can be called with some pointers set. :/ */
+
tex->type = TEX_IMAGE;
tex->ima = NULL;
tex->stype = 0;
@@ -1007,8 +1009,8 @@ void BKE_texture_make_local(Tex *tex)
if (ma->mtex[a] && ma->mtex[a]->tex == tex) {
if (ma->id.lib == NULL) {
ma->mtex[a]->tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
}
@@ -1020,8 +1022,8 @@ void BKE_texture_make_local(Tex *tex)
if (la->mtex[a] && la->mtex[a]->tex == tex) {
if (la->id.lib == NULL) {
la->mtex[a]->tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
}
@@ -1033,8 +1035,8 @@ void BKE_texture_make_local(Tex *tex)
if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) {
if (wrld->id.lib == NULL) {
wrld->mtex[a]->tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
}
@@ -1045,15 +1047,15 @@ void BKE_texture_make_local(Tex *tex)
if (br->mtex.tex == tex) {
if (br->id.lib == NULL) {
br->mtex.tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
if (br->mask_mtex.tex == tex) {
if (br->id.lib == NULL) {
br->mask_mtex.tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
br = br->id.next;
@@ -1064,8 +1066,8 @@ void BKE_texture_make_local(Tex *tex)
if (pa->mtex[a] && pa->mtex[a]->tex == tex) {
if (pa->id.lib == NULL) {
pa->mtex[a]->tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
}
@@ -1077,8 +1079,8 @@ void BKE_texture_make_local(Tex *tex)
if (ls->mtex[a] && ls->mtex[a]->tex == tex) {
if (ls->id.lib == NULL) {
ls->mtex[a]->tex = tex_new;
- tex_new->id.us++;
- tex->id.us--;
+ id_us_plus(&tex_new->id);
+ id_us_min(&tex->id);
}
}
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 9368e58d467..3b76e456ff7 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -64,13 +64,15 @@
#include "RNA_access.h"
-#include "raskter.h"
-
#include "libmv-capi.h"
#include "tracking_private.h"
typedef struct MovieDistortion {
struct libmv_CameraIntrinsics *intrinsics;
+ /* Parameters needed for coordinates normalization. */
+ float principal[2];
+ float pixel_aspect;
+ float focal;
} MovieDistortion;
static struct {
@@ -810,38 +812,54 @@ static bGPDlayer *track_mask_gpencil_layer_get(MovieTrackingTrack *track)
return NULL;
}
+typedef struct TrackMaskSetPixelData {
+ float *mask;
+ int mask_width;
+ int mask_height;
+} TrackMaskSetPixelData;
+
+static void track_mask_set_pixel_cb(int x, int x_end, int y, void *user_data)
+{
+ TrackMaskSetPixelData *data = (TrackMaskSetPixelData *)user_data;
+ size_t index = (size_t)y * data->mask_width + x;
+ size_t index_end = (size_t)y * data->mask_width + x_end;
+ do {
+ data->mask[index] = 1.0f;
+ } while (++index != index_end);
+}
+
static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height,
MovieTrackingMarker *marker, bGPDlayer *layer,
float *mask, int mask_width, int mask_height)
{
bGPDframe *frame = layer->frames.first;
+ TrackMaskSetPixelData data;
+
+ data.mask = mask;
+ data.mask_width = mask_width;
+ data.mask_height = mask_height;
while (frame) {
bGPDstroke *stroke = frame->strokes.first;
while (stroke) {
bGPDspoint *stroke_points = stroke->points;
- float *mask_points, *fp;
- int i;
-
if (stroke->flag & GP_STROKE_2DSPACE) {
- fp = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(float),
+ int *mask_points, *point;
+ point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
"track mask rasterization points");
-
- for (i = 0; i < stroke->totpoints; i++, fp += 2) {
- fp[0] = (stroke_points[i].x - marker->search_min[0]) * frame_width / mask_width;
- fp[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height / mask_height;
+ for (int i = 0; i < stroke->totpoints; i++, point += 2) {
+ point[0] = (stroke_points[i].x - marker->search_min[0]) * frame_width;
+ point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height;
}
-
/* TODO: add an option to control whether AA is enabled or not */
- PLX_raskterize((float (*)[2])mask_points, stroke->totpoints, mask, mask_width, mask_height);
-
+ fill_poly_v2i_n(0, 0, mask_width, mask_height,
+ (const int (*)[2])mask_points, stroke->totpoints,
+ track_mask_set_pixel_cb, &data);
MEM_freeN(mask_points);
}
-
stroke = stroke->next;
}
-
frame = frame->next;
}
}
@@ -1864,6 +1882,11 @@ MovieDistortion *BKE_tracking_distortion_new(MovieTracking *tracking,
distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
distortion->intrinsics = libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
+ const MovieTrackingCamera *camera = &tracking->camera;
+ copy_v2_v2(distortion->principal, camera->principal);
+ distortion->pixel_aspect = camera->pixel_aspect;
+ distortion->focal = camera->focal;
+
return distortion;
}
@@ -1877,6 +1900,11 @@ void BKE_tracking_distortion_update(MovieDistortion *distortion, MovieTracking *
calibration_height,
&camera_intrinsics_options);
+ const MovieTrackingCamera *camera = &tracking->camera;
+ copy_v2_v2(distortion->principal, camera->principal);
+ distortion->pixel_aspect = camera->pixel_aspect;
+ distortion->focal = camera->focal;
+
libmv_cameraIntrinsicsUpdate(&camera_intrinsics_options, distortion->intrinsics);
}
@@ -1890,7 +1918,7 @@ MovieDistortion *BKE_tracking_distortion_copy(MovieDistortion *distortion)
MovieDistortion *new_distortion;
new_distortion = MEM_callocN(sizeof(MovieDistortion), "BKE_tracking_distortion_create");
-
+ *new_distortion = *distortion;
new_distortion->intrinsics = libmv_cameraIntrinsicsCopy(distortion->intrinsics);
return new_distortion;
@@ -1948,6 +1976,36 @@ ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion, MovieTracking *
return resibuf;
}
+void BKE_tracking_distortion_distort_v2(MovieDistortion *distortion,
+ const float co[2],
+ float r_co[2])
+{
+ const float aspy = 1.0f / distortion->pixel_aspect;
+
+ /* Normalize coords. */
+ float inv_focal = 1.0f / distortion->focal;
+ double x = (co[0] - distortion->principal[0]) * inv_focal,
+ y = (co[1] - distortion->principal[1] * aspy) * inv_focal;
+
+ libmv_cameraIntrinsicsApply(distortion->intrinsics, x, y, &x, &y);
+
+ /* Result is in image coords already. */
+ r_co[0] = x;
+ r_co[1] = y;
+}
+
+void BKE_tracking_distortion_undistort_v2(MovieDistortion *distortion,
+ const float co[2],
+ float r_co[2])
+{
+ double x = co[0], y = co[1];
+ libmv_cameraIntrinsicsInvert(distortion->intrinsics, x, y, &x, &y);
+
+ const float aspy = 1.0f / distortion->pixel_aspect;
+ r_co[0] = (float)x * distortion->focal + distortion->principal[0];
+ r_co[1] = (float)y * distortion->focal + distortion->principal[1] * aspy;
+}
+
void BKE_tracking_distortion_free(MovieDistortion *distortion)
{
libmv_cameraIntrinsicsDestroy(distortion->intrinsics);
@@ -1957,40 +2015,43 @@ void BKE_tracking_distortion_free(MovieDistortion *distortion)
void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
{
- MovieTrackingCamera *camera = &tracking->camera;
+ const MovieTrackingCamera *camera = &tracking->camera;
+ const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- double x, y;
- float aspy = 1.0f / tracking->camera.pixel_aspect;
-
tracking_cameraIntrinscisOptionsFromTracking(tracking,
0, 0,
&camera_intrinsics_options);
+ libmv_CameraIntrinsics *intrinsics =
+ libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
- /* normalize coords */
- x = (co[0] - camera->principal[0]) / camera->focal;
- y = (co[1] - camera->principal[1] * aspy) / camera->focal;
+ /* Normalize coordinates. */
+ double x = (co[0] - camera->principal[0]) / camera->focal,
+ y = (co[1] - camera->principal[1] * aspy) / camera->focal;
- libmv_cameraIntrinsicsApply(&camera_intrinsics_options, x, y, &x, &y);
+ libmv_cameraIntrinsicsApply(intrinsics, x, y, &x, &y);
+ libmv_cameraIntrinsicsDestroy(intrinsics);
- /* result is in image coords already */
+ /* Result is in image coords already. */
r_co[0] = x;
r_co[1] = y;
}
void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float r_co[2])
{
- MovieTrackingCamera *camera = &tracking->camera;
+ const MovieTrackingCamera *camera = &tracking->camera;
+ const float aspy = 1.0f / tracking->camera.pixel_aspect;
libmv_CameraIntrinsicsOptions camera_intrinsics_options;
- double x = co[0], y = co[1];
- float aspy = 1.0f / tracking->camera.pixel_aspect;
-
tracking_cameraIntrinscisOptionsFromTracking(tracking,
0, 0,
&camera_intrinsics_options);
+ libmv_CameraIntrinsics *intrinsics =
+ libmv_cameraIntrinsicsNew(&camera_intrinsics_options);
- libmv_cameraIntrinsicsInvert(&camera_intrinsics_options, x, y, &x, &y);
+ double x = co[0], y = co[1];
+ libmv_cameraIntrinsicsInvert(intrinsics, x, y, &x, &y);
+ libmv_cameraIntrinsicsDestroy(intrinsics);
r_co[0] = (float)x * camera->focal + camera->principal[0];
r_co[1] = (float)y * camera->focal + camera->principal[1] * aspy;
@@ -2577,7 +2638,6 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
int frames, start_frame = INT_MAX, end_frame = -INT_MAX;
int *per_frame_counter;
int prev_coverage, last_segment_frame;
- int i;
/* find frame boundaries */
for (track = tracksbase->first; track; track = track->next) {
@@ -2592,9 +2652,7 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
/* find per-frame markers count */
for (track = tracksbase->first; track; track = track->next) {
- int i;
-
- for (i = 0; i < track->markersnr; i++) {
+ for (int i = 0; i < track->markersnr; i++) {
MovieTrackingMarker *marker = &track->markers[i];
/* TODO: perhaps we need to add check for non-single-frame track here */
@@ -2611,7 +2669,7 @@ static void tracking_dopesheet_calc_coverage(MovieTracking *tracking)
if (!per_frame_counter[0])
prev_coverage = TRACKING_COVERAGE_OK;
- for (i = 1; i < frames; i++) {
+ for (int i = 1; i < frames; i++) {
int coverage = coverage_from_count(per_frame_counter[i]);
/* means only disabled tracks in the end, could be ignored */
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 76261bddfbc..9df30a8acc9 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -447,7 +447,7 @@ bool BKE_autotrack_context_step(AutoTrackContext *context)
void BKE_autotrack_context_sync(AutoTrackContext *context)
{
int newframe, frame_delta = context->backwards ? -1 : 1;
- int clip, frame;
+ int frame;
BLI_spin_lock(&context->spin_lock);
newframe = context->user.framenr;
@@ -502,7 +502,7 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
}
BLI_spin_unlock(&context->spin_lock);
- for (clip = 0; clip < context->num_clips; ++clip) {
+ for (int clip = 0; clip < context->num_clips; ++clip) {
MovieTracking *tracking = &context->clips[clip]->tracking;
BKE_tracking_dopesheet_tag_update(tracking);
}
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 1cbfc5eb834..3c2444b0ef1 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -482,7 +482,18 @@ MovieTrackingMarker *tracking_get_keyframed_marker(MovieTrackingTrack *track,
* fallback to the first marker in current tracked segment
* as a keyframe.
*/
- if (next_marker && next_marker->flag & MARKER_DISABLED) {
+ if (next_marker == NULL) {
+ /* Could happen when trying to get reference marker for the fist
+ * one on the segment which isn't surrounded by disabled markers.
+ *
+ * There's no really good choice here, just use the reference
+ * marker which looks correct..
+ */
+ if (marker_keyed_fallback == NULL) {
+ marker_keyed_fallback = cur_marker;
+ }
+ }
+ else if (next_marker->flag & MARKER_DISABLED) {
if (marker_keyed_fallback == NULL)
marker_keyed_fallback = cur_marker;
}
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 64d561491e2..cf11fe2323d 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -460,29 +460,34 @@ BLI_INLINE bool isalpha_or_utf8(const int ch)
static const char *unit_find_str(const char *str, const char *substr)
{
- const char *str_found;
-
if (substr && substr[0] != '\0') {
- str_found = strstr(str, substr);
- if (str_found) {
- /* previous char cannot be a letter */
- if (str_found == str ||
- /* weak unicode support!, so "µm" won't match up be replaced by "m"
- * since non ascii utf8 values will NEVER return true */
- isalpha_or_utf8(*BLI_str_prev_char_utf8(str_found)) == 0)
- {
- /* next char cannot be alphanum */
- int len_name = strlen(substr);
-
- if (!isalpha_or_utf8(*(str_found + len_name))) {
- return str_found;
+ while (true) {
+ const char *str_found = strstr(str, substr);
+
+ if (str_found) {
+ /* Previous char cannot be a letter. */
+ if (str_found == str ||
+ /* weak unicode support!, so "µm" won't match up be replaced by "m"
+ * since non ascii utf8 values will NEVER return true */
+ isalpha_or_utf8(*BLI_str_prev_char_utf8(str_found)) == 0)
+ {
+ /* next char cannot be alphanum */
+ int len_name = strlen(substr);
+
+ if (!isalpha_or_utf8(*(str_found + len_name))) {
+ return str_found;
+ }
}
+ /* If str_found is not a valid unit, we have to check further in the string... */
+ for (str_found++; isalpha_or_utf8(*str_found); str_found++);
+ str = str_found;
+ }
+ else {
+ break;
}
}
-
}
return NULL;
-
}
/* Note that numbers are added within brackets
@@ -512,10 +517,8 @@ static bool ch_is_op(char op)
case '=':
case '%':
return true;
- break;
default:
return false;
- break;
}
}
@@ -730,11 +733,10 @@ void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int syste
bUnitCollection *usys = unit_get_system(system, type);
bUnitDef *unit;
- bUnitDef *unit_def = unit_default(usys);
/* find and substitute all units */
for (unit = usys->units; unit->name; unit++) {
- if (len_max > 0 && (unit->name_alt || unit == unit_def)) {
+ if (len_max > 0 && unit->name_alt) {
const char *found = unit_find_str(orig_str, unit->name_short);
if (found) {
int offset = (int)(found - orig_str);
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index e4736b1f54c..17a2e7f14fd 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -31,6 +31,7 @@
#include <string.h>
+#include <stdlib.h>
#include <math.h>
#include "MEM_guardedalloc.h"
@@ -58,8 +59,10 @@ void BKE_world_free_ex(World *wrld, bool do_id_user)
for (a = 0; a < MAX_MTEX; a++) {
mtex = wrld->mtex[a];
- if (do_id_user && mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (do_id_user && mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
BKE_previewimg_free(&wrld->preview);
@@ -83,12 +86,10 @@ void BKE_world_free(World *wrld)
BKE_world_free_ex(wrld, true);
}
-World *add_world(Main *bmain, const char *name)
+void BKE_world_init(World *wrld)
{
- World *wrld;
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(wrld, id));
- wrld = BKE_libblock_alloc(bmain, ID_WO, name);
-
wrld->horr = 0.05f;
wrld->horg = 0.05f;
wrld->horb = 0.05f;
@@ -113,6 +114,15 @@ World *add_world(Main *bmain, const char *name)
wrld->preview = NULL;
wrld->miststa = 5.0f;
wrld->mistdist = 25.0f;
+}
+
+World *add_world(Main *bmain, const char *name)
+{
+ World *wrld;
+
+ wrld = BKE_libblock_alloc(bmain, ID_WO, name);
+
+ BKE_world_init(wrld);
return wrld;
}
@@ -212,8 +222,8 @@ void BKE_world_make_local(World *wrld)
if (sce->world == wrld) {
if (sce->id.lib == NULL) {
sce->world = wrld_new;
- wrld_new->id.us++;
- wrld->id.us--;
+ id_us_plus(&wrld_new->id);
+ id_us_min(&wrld->id);
}
}
}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index cec455e01b9..89b2caa5ac7 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -147,7 +147,9 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#endif
/* in case all above are disabled */
- (void)imtype;return &mh;
+ (void)imtype;
+
+ return (mh.append_movie != append_stub) ? &mh : NULL;
}
/* ****************************************************************** */
@@ -213,8 +215,6 @@ static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int
if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
- MEM_freeN(avi);
- avi = NULL;
return 0;
}
@@ -298,8 +298,10 @@ static void context_free_avi(void *context_v)
void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
- if (mh->get_movie_path)
+ if (mh && mh->get_movie_path) {
mh->get_movie_path(string, rd, preview, suffix);
- else
+ }
+ else {
string[0] = '\0';
+ }
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index edda852a032..edeccf472c8 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -138,8 +138,8 @@ static int write_audio_frame(FFMpegContext *context)
context->audio_time += (double) context->audio_input_samples / (double) c->sample_rate;
#ifdef FFMPEG_HAVE_ENCODE_AUDIO2
- frame = avcodec_alloc_frame();
- avcodec_get_frame_defaults(frame);
+ frame = av_frame_alloc();
+ av_frame_unref(frame);
frame->pts = context->audio_time / av_q2d(c->time_base);
frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
@@ -172,7 +172,7 @@ static int write_audio_frame(FFMpegContext *context)
}
if (!got_output) {
- avcodec_free_frame(&frame);
+ av_frame_free(&frame);
return 0;
}
#else
@@ -202,7 +202,7 @@ static int write_audio_frame(FFMpegContext *context)
if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
if (frame)
- avcodec_free_frame(&frame);
+ av_frame_free(&frame);
return -1;
}
@@ -210,7 +210,7 @@ static int write_audio_frame(FFMpegContext *context)
}
if (frame)
- avcodec_free_frame(&frame);
+ av_frame_free(&frame);
return 0;
}
@@ -224,7 +224,7 @@ static AVFrame *alloc_picture(int pix_fmt, int width, int height)
int size;
/* allocate space for the struct */
- f = avcodec_alloc_frame();
+ f = av_frame_alloc();
if (!f) return NULL;
size = avpicture_get_size(pix_fmt, width, height);
/* allocate the actual picture buffer */
@@ -363,8 +363,8 @@ static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, Re
int height = c->height;
AVFrame *rgb_frame;
- if (c->pix_fmt != PIX_FMT_BGR32) {
- rgb_frame = alloc_picture(PIX_FMT_BGR32, width, height);
+ if (c->pix_fmt != AV_PIX_FMT_BGR32) {
+ rgb_frame = alloc_picture(AV_PIX_FMT_BGR32, width, height);
if (!rgb_frame) {
BKE_report(reports, RPT_ERROR, "Could not allocate temporary frame");
return NULL;
@@ -414,14 +414,14 @@ static AVFrame *generate_video_frame(FFMpegContext *context, uint8_t *pixels, Re
}
}
- if (c->pix_fmt != PIX_FMT_BGR32) {
+ if (c->pix_fmt != AV_PIX_FMT_BGR32) {
sws_scale(context->img_convert_ctx, (const uint8_t *const *) rgb_frame->data,
rgb_frame->linesize, 0, c->height,
context->current_frame->data, context->current_frame->linesize);
delete_picture(rgb_frame);
}
- context->current_frame->format = PIX_FMT_BGR32;
+ context->current_frame->format = AV_PIX_FMT_BGR32;
context->current_frame->width = width;
context->current_frame->height = height;
@@ -586,12 +586,12 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
else {
/* makes HuffYUV happy ... */
- c->pix_fmt = PIX_FMT_YUV422P;
+ c->pix_fmt = AV_PIX_FMT_YUV422P;
}
if (context->ffmpeg_type == FFMPEG_XVID) {
/* arghhhh ... */
- c->pix_fmt = PIX_FMT_YUV420P;
+ c->pix_fmt = AV_PIX_FMT_YUV420P;
c->codec_tag = (('D' << 24) + ('I' << 16) + ('V' << 8) + 'X');
}
@@ -604,26 +604,26 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
/* Keep lossless encodes in the RGB domain. */
if (codec_id == AV_CODEC_ID_HUFFYUV) {
if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
- c->pix_fmt = PIX_FMT_BGRA;
+ c->pix_fmt = AV_PIX_FMT_BGRA;
}
else {
- c->pix_fmt = PIX_FMT_RGB32;
+ c->pix_fmt = AV_PIX_FMT_RGB32;
}
}
if (codec_id == AV_CODEC_ID_FFV1) {
- c->pix_fmt = PIX_FMT_RGB32;
+ c->pix_fmt = AV_PIX_FMT_RGB32;
}
if (codec_id == AV_CODEC_ID_QTRLE) {
if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
- c->pix_fmt = PIX_FMT_ARGB;
+ c->pix_fmt = AV_PIX_FMT_ARGB;
}
}
if (codec_id == AV_CODEC_ID_PNG) {
if (rd->im_format.planes == R_IMF_PLANES_RGBA) {
- c->pix_fmt = PIX_FMT_RGBA;
+ c->pix_fmt = AV_PIX_FMT_RGBA;
}
}
@@ -661,8 +661,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
context->current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
- context->img_convert_ctx = sws_getContext(c->width, c->height, PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
- NULL, NULL, NULL);
+ context->img_convert_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR32, c->width, c->height, c->pix_fmt, SWS_BICUBIC,
+ NULL, NULL, NULL);
return st;
}
@@ -809,7 +809,7 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
AVFormatContext *of;
AVOutputFormat *fmt;
AVDictionary *opts = NULL;
- char name[256], error[1024];
+ char name[FILE_MAX], error[1024];
const char **exts;
context->ffmpeg_type = rd->ffcodecdata.type;
@@ -847,7 +847,10 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
BKE_report(reports, RPT_ERROR, "Error opening output file");
return 0;
}
-
+
+
+ /* Returns after this must 'goto fail;' */
+
of->oformat = fmt;
of->packet_size = rd->ffcodecdata.mux_packet_size;
if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) {
@@ -900,15 +903,15 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
if (fmt->video_codec == AV_CODEC_ID_DVVIDEO) {
if (rectx != 720) {
BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!");
- return 0;
+ goto fail;
}
if (rd->frs_sec != 25 && recty != 480) {
BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!");
- return 0;
+ goto fail;
}
if (rd->frs_sec == 25 && recty != 576) {
BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!");
- return 0;
+ goto fail;
}
}
@@ -916,8 +919,7 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
fmt->audio_codec = AV_CODEC_ID_PCM_S16LE;
if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
- av_dict_free(&opts);
- return 0;
+ goto fail;
}
}
@@ -929,9 +931,7 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
BKE_report(reports, RPT_ERROR, error);
else
BKE_report(reports, RPT_ERROR, "Error initializing video stream");
-
- av_dict_free(&opts);
- return 0;
+ goto fail;
}
}
@@ -942,22 +942,18 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
BKE_report(reports, RPT_ERROR, error);
else
BKE_report(reports, RPT_ERROR, "Error initializing audio stream");
- av_dict_free(&opts);
- return 0;
+ goto fail;
}
}
if (!(fmt->flags & AVFMT_NOFILE)) {
if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
BKE_report(reports, RPT_ERROR, "Could not open file for writing");
- av_dict_free(&opts);
- return 0;
+ goto fail;
}
}
if (avformat_write_header(of, NULL) < 0) {
BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination");
- av_dict_free(&opts);
- avio_close(of->pb);
- return 0;
+ goto fail;
}
context->outfile = of;
@@ -965,6 +961,26 @@ static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int
av_dict_free(&opts);
return 1;
+
+
+fail:
+ if (of->pb) {
+ avio_close(of->pb);
+ }
+
+ if (context->video_stream && context->video_stream->codec) {
+ avcodec_close(context->video_stream->codec);
+ context->video_stream = NULL;
+ }
+
+ if (context->audio_stream && context->audio_stream->codec) {
+ avcodec_close(context->audio_stream->codec);
+ context->audio_stream = NULL;
+ }
+
+ av_dict_free(&opts);
+ avformat_free_context(of);
+ return 0;
}
/**
@@ -1198,8 +1214,6 @@ int BKE_ffmpeg_append(void *context_v, RenderData *rd, int start_frame, int fram
static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
- unsigned int i;
-
PRINT("Closing ffmpeg...\n");
#if 0
@@ -1234,15 +1248,11 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
context->video_stream = 0;
}
-
- /* Close the output file */
- if (context->outfile) {
- for (i = 0; i < context->outfile->nb_streams; i++) {
- if (&context->outfile->streams[i]) {
- av_freep(&context->outfile->streams[i]);
- }
- }
+ if (context->audio_stream && context->audio_stream->codec) {
+ avcodec_close(context->audio_stream->codec);
+ context->audio_stream = 0;
}
+
/* free the temp buffer */
if (context->current_frame) {
delete_picture(context->current_frame);
@@ -1254,7 +1264,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
}
}
if (context->outfile) {
- av_free(context->outfile);
+ avformat_free_context(context->outfile);
context->outfile = 0;
}
if (context->audio_input_buffer) {
diff --git a/source/blender/blenlib/BLI_alloca.h b/source/blender/blenlib/BLI_alloca.h
index fd814940624..b44e6c66d2a 100644
--- a/source/blender/blenlib/BLI_alloca.h
+++ b/source/blender/blenlib/BLI_alloca.h
@@ -34,8 +34,13 @@
#endif
#if defined(__GNUC__) || defined(__clang__)
+#if defined(__cplusplus) && (__cplusplus > 199711L)
+#define BLI_array_alloca(arr, realsize) \
+ (decltype(arr))alloca(sizeof(*arr) * (realsize))
+#else
#define BLI_array_alloca(arr, realsize) \
(typeof(arr))alloca(sizeof(*arr) * (realsize))
+#endif
#else
#define BLI_array_alloca(arr, realsize) \
alloca(sizeof(*arr) * (realsize))
diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h
index ff7976dc701..c5359d56f9c 100644
--- a/source/blender/blenlib/BLI_array_utils.h
+++ b/source/blender/blenlib/BLI_array_utils.h
@@ -26,6 +26,8 @@
* \brief Generic array manipulation API.
*/
+#include "BLI_compiler_typecheck.h"
+
void _bli_array_reverse(void *arr, unsigned int arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) \
_bli_array_reverse(arr, arr_len, sizeof(*(arr)))
@@ -46,4 +48,20 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
#define BLI_array_findindex(arr, arr_len, p) \
_bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
+void _bli_array_binary_and(
+ void *arr, const void *arr_a, const void *arr_b,
+ unsigned int arr_len, size_t arr_stride);
+#define BLI_array_binary_and(arr, arr_a, arr_b, arr_len) \
+ (CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \
+ CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
+ _bli_array_binary_and(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
+
+void _bli_array_binary_or(
+ void *arr, const void *arr_a, const void *arr_b,
+ unsigned int arr_len, size_t arr_stride);
+#define BLI_array_binary_or(arr, arr_a, arr_b, arr_len) \
+ (CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_a)), \
+ CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
+ _bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
+
#endif /* __BLI_ARRAY_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index 60fc143a447..82704e95fdd 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -86,6 +86,12 @@ typedef unsigned int BLI_bitmap;
((_bitmap)[(_index) >> _BITMAP_POWER] &= \
~(1u << ((_index) & _BITMAP_MASK))))
+/* flip the value of a single bit at '_index' */
+#define BLI_BITMAP_FLIP(_bitmap, _index) \
+ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
+ ((_bitmap)[(_index) >> _BITMAP_POWER] ^= \
+ (1u << ((_index) & _BITMAP_MASK))))
+
/* set or clear the value of a single bit at '_index' */
#define BLI_BITMAP_SET(_bitmap, _index, _set) \
{ \
diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h
index 4e5b61da532..0c0845daf19 100644
--- a/source/blender/blenlib/BLI_buffer.h
+++ b/source/blender/blenlib/BLI_buffer.h
@@ -23,63 +23,44 @@
/** \file BLI_buffer.h
* \ingroup bli
- *
- * \note this more or less fills same purpose as BLI_array, but makes
- * it much easier to resize the array outside of the function it was
- * declared in since.
- *
- * Usage examples:
- * \code{.c}
- * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32);
- *
- * BLI_buffer_append(my_int_array, int, 42);
- * assert(my_int_array.count == 1);
- * assert(BLI_buffer_at(my_int_array, int, 0) == 42);
- *
- * BLI_buffer_free(&my_int_array);
- * \endcode
*/
typedef struct {
void *data;
- const int elem_size;
- int count, alloc_count;
+ const size_t elem_size;
+ size_t count, alloc_count;
int flag;
} BLI_Buffer;
enum {
BLI_BUFFER_NOP = 0,
BLI_BUFFER_USE_STATIC = (1 << 0),
- BLI_BUFFER_USE_CALLOC = (1 << 1), /* ensure the array is always calloc'd */
};
#define BLI_buffer_declare_static(type_, name_, flag_, static_count_) \
char name_ ## user; /* warn for free only */ \
type_ name_ ## _static_[static_count_]; \
BLI_Buffer name_ = { \
- /* clear the static memory if this is a calloc'd array */ \
- ((void)((flag_ & BLI_BUFFER_USE_CALLOC) ? \
- memset(name_ ## _static_, 0, sizeof(name_ ## _static_)) : NULL \
- ), /* memset-end */ \
- name_ ## _static_), \
- sizeof(type_), \
- 0, \
- static_count_, \
- BLI_BUFFER_USE_STATIC | flag_}
+ (name_ ## _static_), \
+ sizeof(type_), \
+ 0, \
+ static_count_, \
+ BLI_BUFFER_USE_STATIC | (flag_)}
/* never use static*/
#define BLI_buffer_declare(type_, name_, flag_) \
bool name_ ## user; /* warn for free only */ \
- BLI_Buffer name_ = {NULL, \
- sizeof(type_), \
- 0, \
- 0, \
- flag_}
+ BLI_Buffer name_ = { \
+ NULL, \
+ sizeof(type_), \
+ 0, \
+ 0, \
+ (flag_)}
#define BLI_buffer_at(buffer_, type_, index_) ( \
(((type_ *)(buffer_)->data)[ \
(BLI_assert(sizeof(type_) == (buffer_)->elem_size)), \
- (BLI_assert(index_ >= 0 && index_ < (buffer_)->count)), \
+ (BLI_assert((int)(index_) >= 0 && (size_t)(index_) < (buffer_)->count)), \
index_]))
#define BLI_buffer_array(buffer_, type_) ( \
@@ -88,6 +69,9 @@ enum {
#define BLI_buffer_resize_data(buffer_, type_, new_count_) ( \
(BLI_buffer_resize(buffer_, new_count_), new_count_ ? BLI_buffer_array(buffer_, type_) : NULL))
+#define BLI_buffer_reinit_data(buffer_, type_, new_count_) ( \
+ (BLI_buffer_reinit(buffer_, new_count_), new_count_ ? BLI_buffer_array(buffer_, type_) : NULL))
+
#define BLI_buffer_append(buffer_, type_, val_) ( \
BLI_buffer_resize(buffer_, (buffer_)->count + 1), \
(BLI_buffer_at(buffer_, type_, (buffer_)->count - 1) = val_) \
@@ -98,7 +82,10 @@ enum {
} (void)0
/* Never decreases the amount of memory allocated */
-void BLI_buffer_resize(BLI_Buffer *buffer, int new_count);
+void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
+
+/* Ensure size, throwing away old data, respecting BLI_BUFFER_USE_CALLOC */
+void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count);
/* Does not free the buffer structure itself */
void _bli_buffer_free(BLI_Buffer *buffer);
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index 92928889c52..8edbc25bcbc 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -49,4 +49,16 @@ extern "C++" {
}
#endif
+/* little macro so inline keyword works */
+#if defined(_MSC_VER)
+# define BLI_INLINE static __forceinline
+#else
+# if (defined(__APPLE__) && defined(__ppc__))
+/* static inline __attribute__ here breaks osx ppc gcc42 build */
+# define BLI_INLINE static __attribute__((always_inline)) __attribute__((__unused__))
+# else
+# define BLI_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__))
+# endif
+#endif
+
#endif /* __BLI_COMPILER_COMPAT_H__ */
diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h
index b9fb3ebf47a..74638938214 100644
--- a/source/blender/blenlib/BLI_compiler_typecheck.h
+++ b/source/blender/blenlib/BLI_compiler_typecheck.h
@@ -39,13 +39,13 @@
} (void)0
#define CHECK_TYPE_PAIR(var_a, var_b) { \
- typeof(var_a) *__tmp; \
+ const typeof(var_a) *__tmp; \
__tmp = (typeof(var_b) *)NULL; \
(void)__tmp; \
} (void)0
#define CHECK_TYPE_PAIR_INLINE(var_a, var_b) ((void)({ \
- typeof(var_a) *__tmp; \
+ const typeof(var_a) *__tmp; \
__tmp = (typeof(var_b) *)NULL; \
(void)__tmp; \
}))
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 33dae45ac26..91d139c7085 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -89,7 +89,7 @@ bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL();
double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_NONNULL();
+char *BLI_current_working_dir(char *dir, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* Filelist */
@@ -130,6 +130,8 @@ bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RES
/* read ascii file as lines, empty list if reading fails */
struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
+void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
void BLI_file_free_lines(struct LinkNode *lines);
/* this weirdo pops up in two places ... */
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index a81fee2cdb7..7e3a009ede8 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -39,6 +39,14 @@
extern "C" {
#endif
+#define _GHASH_INTERNAL_ATTR
+#ifndef GHASH_INTERNAL_API
+# ifdef __GNUC__
+# undef _GHASH_INTERNAL_ATTR
+# define _GHASH_INTERNAL_ATTR __attribute__ ((deprecated))
+# endif
+#endif
+
typedef unsigned int (*GHashHashFP) (const void *key);
/** returns false when equal */
typedef bool (*GHashCmpFP) (const void *a, const void *b);
@@ -55,6 +63,12 @@ typedef struct GHashIterator {
unsigned int curBucket;
} GHashIterator;
+typedef struct GHashIterState {
+ unsigned int curr_bucket _GHASH_INTERNAL_ATTR;
+} GHashIterState;
+
+
+
enum {
GHASH_FLAG_ALLOW_DUPES = (1 << 0), /* Only checked for in debug mode */
GHASH_FLAG_ALLOW_SHRINK = (1 << 1), /* Allow to shrink buckets' size. */
@@ -80,13 +94,14 @@ void *BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT;
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
-bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_val, GHashKeyCopyFP keycopyfp) ATTR_WARN_UNUSED_RESULT;
+bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
void BLI_ghash_clear_ex(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
const unsigned int nentries_reserve);
void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
+bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
unsigned int BLI_ghash_size(GHash *gh) ATTR_WARN_UNUSED_RESULT;
void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
@@ -116,14 +131,14 @@ BLI_INLINE bool BLI_ghashIterator_done(GHashIterator *ghi) { return !ghi
# define _gh_Entry void
#endif
-#define GHASH_ITER(gh_iter_, ghash_) \
- for (BLI_ghashIterator_init(&gh_iter_, ghash_); \
- BLI_ghashIterator_done(&gh_iter_) == false; \
+#define GHASH_ITER(gh_iter_, ghash_) \
+ for (BLI_ghashIterator_init(&gh_iter_, ghash_); \
+ BLI_ghashIterator_done(&gh_iter_) == false; \
BLI_ghashIterator_step(&gh_iter_))
-#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_) \
- for (BLI_ghashIterator_init(&gh_iter_, ghash_), i_ = 0; \
- BLI_ghashIterator_done(&gh_iter_) == false; \
+#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_) \
+ for (BLI_ghashIterator_init(&gh_iter_, ghash_), i_ = 0; \
+ BLI_ghashIterator_done(&gh_iter_) == false; \
BLI_ghashIterator_step(&gh_iter_), i_++)
/** \name Callbacks for GHash
@@ -208,6 +223,8 @@ typedef GHashCmpFP GSetCmpFP;
typedef GHashKeyFreeFP GSetKeyFreeFP;
typedef GHashKeyCopyFP GSetKeyCopyFP;
+typedef GHashIterState GSetIterState;
+
/* so we can cast but compiler sees as different */
typedef struct GSetIterator {
GHashIterator _ghi
@@ -227,8 +244,10 @@ void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
void BLI_gset_insert(GSet *gh, void *key);
bool BLI_gset_add(GSet *gs, void *key);
+bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
+bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp,
const unsigned int nentries_reserve);
@@ -249,14 +268,14 @@ BLI_INLINE void *BLI_gsetIterator_getKey(GSetIterator *gsi) { return BLI_ghashIt
BLI_INLINE void BLI_gsetIterator_step(GSetIterator *gsi) { BLI_ghashIterator_step((GHashIterator *)gsi); }
BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashIterator_done((GHashIterator *)gsi); }
-#define GSET_ITER(gs_iter_, gset_) \
- for (BLI_gsetIterator_init(&gs_iter_, gset_); \
- BLI_gsetIterator_done(&gs_iter_) == false; \
+#define GSET_ITER(gs_iter_, gset_) \
+ for (BLI_gsetIterator_init(&gs_iter_, gset_); \
+ BLI_gsetIterator_done(&gs_iter_) == false; \
BLI_gsetIterator_step(&gs_iter_))
-#define GSET_ITER_INDEX(gs_iter_, gset_, i_) \
- for (BLI_gsetIterator_init(&gs_iter_, gset_), i_ = 0; \
- BLI_gsetIterator_done(&gs_iter_) == false; \
+#define GSET_ITER_INDEX(gs_iter_, gset_, i_) \
+ for (BLI_gsetIterator_init(&gs_iter_, gset_), i_ = 0; \
+ BLI_gsetIterator_done(&gs_iter_) == false; \
BLI_gsetIterator_step(&gs_iter_), i_++)
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 0c359c7f090..be792669ef1 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -43,6 +43,16 @@ struct BVHTree;
typedef struct BVHTree BVHTree;
#define USE_KDOPBVH_WATERTIGHT
+typedef struct BVHTreeAxisRange {
+ union {
+ struct {
+ float min, max;
+ };
+ /* alternate access */
+ float range[2];
+ };
+} BVHTreeAxisRange;
+
typedef struct BVHTreeOverlap {
int indexA;
int indexB;
@@ -77,6 +87,7 @@ enum {
BVH_RAYCAST_WATERTIGHT = (1 << 0),
};
#define BVH_RAYCAST_DEFAULT (BVH_RAYCAST_WATERTIGHT)
+#define BVH_RAYCAST_DIST_MAX (FLT_MAX / 2.0f)
/* callback must update nearest in case it finds a nearest result */
typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const float co[3], BVHTreeNearest *nearest);
@@ -84,11 +95,24 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl
/* callback must update hit in case it finds a nearest successful hit */
typedef void (*BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit);
+/* callback must update nearest in case it finds a nearest result */
+typedef void (*BVHTree_NearestToRayCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeNearest *nearest);
+
/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
/* callback to range search query */
-typedef void (*BVHTree_RangeQuery)(void *userdata, int index, float dist_sq);
+typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq);
+
+
+/* callbacks to BLI_bvhtree_walk_dfs */
+/* return true to traverse into this nodes children, else skip. */
+typedef bool (*BVHTree_WalkParentCallback)(const BVHTreeAxisRange *bounds, void *userdata);
+/* return true to keep walking, else early-exit the search. */
+typedef bool (*BVHTree_WalkLeafCallback)(const BVHTreeAxisRange *bounds, int index, void *userdata);
+/* return true to search (min, max) else (max, min). */
+typedef bool (*BVHTree_WalkOrderCallback)(const BVHTreeAxisRange *bounds, char axis, void *userdata);
+
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
void BLI_bvhtree_free(BVHTree *tree);
@@ -112,8 +136,13 @@ float BLI_bvhtree_getepsilon(const BVHTree *tree);
/* find nearest node to the given coordinates
* (if nearest is given it will only search nodes where square distance is smaller than nearest->dist) */
-int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
- BVHTree_NearestPointCallback callback, void *userdata);
+int BLI_bvhtree_find_nearest(
+ BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
+ BVHTree_NearestPointCallback callback, void *userdata);
+
+int BLI_bvhtree_find_nearest_to_ray(
+ BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest,
+ BVHTree_NearestToRayCallback callback, void *userdata);
int BLI_bvhtree_ray_cast_ex(
BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit,
@@ -134,8 +163,20 @@ int BLI_bvhtree_ray_cast_all(
float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3]);
/* range query */
-int BLI_bvhtree_range_query(BVHTree *tree, const float co[3], float radius,
- BVHTree_RangeQuery callback, void *userdata);
+int BLI_bvhtree_range_query(
+ BVHTree *tree, const float co[3], float radius,
+ BVHTree_RangeQuery callback, void *userdata);
+
+void BLI_bvhtree_walk_dfs(
+ BVHTree *tree,
+ BVHTree_WalkParentCallback walk_parent_cb,
+ BVHTree_WalkLeafCallback walk_leaf_cb,
+ BVHTree_WalkOrderCallback walk_order_cb,
+ void *userdata);
+
+
+/* expose for bvh callbacks to use */
+extern const float bvhtree_kdop_axes[13][3];
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h
index ebf03b5bc67..aa54e1c823c 100644
--- a/source/blender/blenlib/BLI_kdtree.h
+++ b/source/blender/blenlib/BLI_kdtree.h
@@ -50,7 +50,7 @@ void BLI_kdtree_insert(
KDTree *tree, int index,
const float co[3]) ATTR_NONNULL(1, 3);
int BLI_kdtree_find_nearest(
- KDTree *tree, const float co[3],
+ const KDTree *tree, const float co[3],
KDTreeNearest *r_nearest) ATTR_NONNULL(1, 2);
#define BLI_kdtree_find_nearest_n(tree, co, r_nearest, n) \
@@ -58,14 +58,22 @@ int BLI_kdtree_find_nearest(
#define BLI_kdtree_range_search(tree, co, r_nearest, range) \
BLI_kdtree_range_search__normal(tree, co, NULL, r_nearest, range)
+int BLI_kdtree_find_nearest_cb(
+ const KDTree *tree, const float co[3],
+ int (*filter_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data,
+ KDTreeNearest *r_nearest);
+void BLI_kdtree_range_search_cb(
+ const KDTree *tree, const float co[3], float range,
+ bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data);
+
/* Normal use is deprecated */
/* remove __normal functions when last users drop */
int BLI_kdtree_find_nearest_n__normal(
- KDTree *tree, const float co[3], const float nor[3],
+ const KDTree *tree, const float co[3], const float nor[3],
KDTreeNearest *r_nearest,
unsigned int n) ATTR_NONNULL(1, 2, 4);
int BLI_kdtree_range_search__normal(
- KDTree *tree, const float co[3], const float nor[3],
+ const KDTree *tree, const float co[3], const float nor[3],
KDTreeNearest **r_nearest,
float range) ATTR_NONNULL(1, 2, 4) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
index 67cb30e8d17..367f1bb9de5 100644
--- a/source/blender/blenlib/BLI_linklist.h
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -58,8 +58,8 @@ typedef struct LinkNodePair {
LinkNode *list, *last_node;
} LinkNodePair;
-int BLI_linklist_count(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
-int BLI_linklist_index(LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT;
+int BLI_linklist_count(const LinkNode *list) ATTR_WARN_UNUSED_RESULT;
+int BLI_linklist_index(const LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT;
LinkNode *BLI_linklist_find(LinkNode *list, int index) ATTR_WARN_UNUSED_RESULT;
@@ -91,5 +91,7 @@ LinkNode *BLI_linklist_sort_r(LinkNode *list, int (*cmp)(void *, const void *, c
#define BLI_linklist_prepend_alloca(listp, ptr) \
BLI_linklist_prepend_nlink(listp, ptr, alloca(sizeof(LinkNode)))
+#define BLI_linklist_append_alloca(list_pair, ptr) \
+ BLI_linklist_append_nlink(list_pair, ptr, alloca(sizeof(LinkNode)))
#endif /* __BLI_LINKLIST_H__ */
diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h
index c5f9be927d3..dd92dcec936 100644
--- a/source/blender/blenlib/BLI_linklist_stack.h
+++ b/source/blender/blenlib/BLI_linklist_stack.h
@@ -161,7 +161,7 @@
(_BLI_SMALLSTACK_CAST(var_src) ((_##var_src##_stack) ? \
(_BLI_SMALLSTACK_DEL_EX(var_src, var_dst), (_##var_dst##_free->link)) : NULL))
-#define BLI_SMALLSTACK_LAST(var) \
+#define BLI_SMALLSTACK_PEEK(var) \
(_BLI_SMALLSTACK_CAST(var) ((_##var##_stack) ? \
_##var##_stack->link : NULL))
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index d70dfcd9e58..5e6b1256d30 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -145,6 +145,8 @@ MINLINE void rgba_char_args_set(char col[4], const char r, const char g, const c
MINLINE void rgba_char_args_test_set(char col[4], const char r, const char g, const char b, const char a);
MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
+void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max);
+
/********* lift/gamma/gain / ASC-CDL conversion ***********/
void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index b3526b6fc60..45edaca544d 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -95,7 +95,6 @@ float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
-void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4]);
float dist_squared_to_plane_v3(const float p[3], const float plane[4]);
@@ -116,8 +115,9 @@ float dist_signed_squared_to_corner_v3v3v3(
const float p[3],
const float v1[3], const float v2[3], const float v3[3],
const float axis_ref[3]);
-float closest_to_line_v3(float r[3], const float p[3], const float l1[3], const float l2[3]);
-float closest_to_line_v2(float r[2], const float p[2], const float l1[2], const float l2[2]);
+float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
+float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
+void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
void closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]);
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3]);
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]);
@@ -127,6 +127,12 @@ void closest_to_plane3_v3(float r_close[3], const float plane[3], const float pt
/* Set 'r' to the point in triangle (t1, t2, t3) closest to point 'p' */
void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], const float t2[3], const float t3[3]);
+float ray_point_factor_v3_ex(
+ const float p[3], const float ray_origin[3], const float ray_direction[3],
+ const float epsilon, const float fallback);
+float ray_point_factor_v3(
+ const float p[3], const float ray_origin[3], const float ray_direction[3]);
+
float line_point_factor_v3_ex(
const float p[3], const float l1[3], const float l2[3],
const float epsilon, const float fallback);
@@ -154,34 +160,41 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist);
#define ISECT_LINE_LINE_EXACT 1
#define ISECT_LINE_LINE_CROSS 2
-int isect_line_line_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2]);
-int isect_line_line_v2(const float a1[2], const float a2[2], const float b1[2], const float b2[2]);
-int isect_line_line_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[2]);
+int isect_seg_seg_v2(const float a1[2], const float a2[2], const float b1[2], const float b2[2]);
+int isect_seg_seg_v2_int(const int a1[2], const int a2[2], const int b1[2], const int b2[2]);
+int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]);
+bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+
int isect_line_sphere_v3(const float l1[3], const float l2[3], const float sp[3], const float r, float r_p1[3], float r_p2[3]);
int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[2], const float r, float r_p1[2], float r_p2[2]);
-int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float vi[2]);
-bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
+int isect_line_line_v2_point(
+ const float v0[2], const float v1[2],
+ const float v2[2], const float v3[2],
+ float r_vi[2]);
int isect_line_line_epsilon_v3(
const float v1[3], const float v2[3],
- const float v3[3], const float v4[3], float i1[3], float i2[3],
+ const float v3[3], const float v4[3],
+ float i1[3], float i2[3],
const float epsilon);
int isect_line_line_v3(
const float v1[3], const float v2[3],
const float v3[3], const float v4[3],
- float i1[3], float i2[3]);
-bool isect_line_line_strict_v3(const float v1[3], const float v2[3],
- const float v3[3], const float v4[3],
- float vi[3], float *r_lambda);
+ float r_i1[3], float r_i2[3]);
+bool isect_line_line_strict_v3(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3],
+ float vi[3], float *r_lambda);
bool isect_ray_plane_v3(
- const float p1[3], const float d[3],
- const float v0[3], const float v1[3], const float v2[3],
+ const float ray_origin[3], const float ray_direction[3],
+ const float plane[4],
float *r_lambda, const bool clip);
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]);
-bool isect_line_plane_v3(float out[3], const float l1[3], const float l2[3],
- const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT;
+bool isect_line_plane_v3(
+ float r_isect_co[3], const float l1[3], const float l2[3],
+ const float plane_co[3], const float plane_no[3]) ATTR_WARN_UNUSED_RESULT;
bool isect_plane_plane_plane_v3(
const float plane_a[4], const float plane_b[4], const float plane_c[4],
@@ -191,24 +204,28 @@ bool isect_plane_plane_v3(
float r_isect_co[3], float r_isect_no[3]) ATTR_WARN_UNUSED_RESULT;
/* line/ray triangle */
-bool isect_line_tri_v3(
+bool isect_line_segment_tri_v3(
const float p1[3], const float p2[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2]);
-bool isect_line_tri_epsilon_v3(
+bool isect_line_segment_tri_epsilon_v3(
const float p1[3], const float p2[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2], const float epsilon);
+bool isect_axial_line_segment_tri_v3(
+ const int axis, const float p1[3], const float p2[3],
+ const float v0[3], const float v1[3], const float v2[3], float *r_lambda);
+
bool isect_ray_tri_v3(
- const float p1[3], const float d[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2]);
bool isect_ray_tri_threshold_v3(
- const float p1[3], const float d[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2], const float threshold);
bool isect_ray_tri_epsilon_v3(
- const float p1[3], const float d[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2], const float epsilon);
bool isect_tri_tri_epsilon_v3(
@@ -227,17 +244,22 @@ struct IsectRayPrecalc {
};
void isect_ray_tri_watertight_v3_precalc(
- struct IsectRayPrecalc *isect_precalc, const float dir[3]);
+ struct IsectRayPrecalc *isect_precalc, const float ray_direction[3]);
bool isect_ray_tri_watertight_v3(
- const float P[3], const struct IsectRayPrecalc *isect_precalc,
+ const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
const float v0[3], const float v1[3], const float v2[3],
float *r_dist, float r_uv[2]);
/* slower version which calculates IsectRayPrecalc each time */
bool isect_ray_tri_watertight_v3_simple(
- const float P[3], const float dir[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2]);
+bool isect_ray_seg_v2(
+ const float ray_origin[2], const float ray_direction[2],
+ const float v0[2], const float v1[2],
+ float *r_lambda, float *r_u);
+
/* point in polygon */
bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr, const bool use_holes);
bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsigned int nr, const bool use_holes);
@@ -248,36 +270,59 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2],
bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[2], const float v3[2]);
int isect_point_tri_v2_int(const int x1, const int y1, const int x2, const int y2, const int a, const int b);
bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]);
-bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3],
- float r_vi[3]);
+bool isect_point_tri_v3(
+ const float p[3], const float v1[3], const float v2[3], const float v3[3],
+ float r_isect_co[3]);
/* axis-aligned bounding box */
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3]);
-typedef struct {
- float ray_start[3];
+struct IsectRayAABB_Precalc {
+ float ray_origin[3];
float ray_inv_dir[3];
int sign[3];
-} IsectRayAABBData;
+};
+
+void isect_ray_aabb_v3_precalc(
+ struct IsectRayAABB_Precalc *data,
+ const float ray_origin[3], const float ray_direction[3]);
+bool isect_ray_aabb_v3(
+ const struct IsectRayAABB_Precalc *data,
+ const float bb_min[3], const float bb_max[3], float *tmin);
-void isect_ray_aabb_initialize(IsectRayAABBData *data, const float ray_start[3], const float ray_direction[3]);
-bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3], const float bb_max[3], float *tmin);
+struct NearestRayToAABB_Precalc {
+ float ray_origin[3];
+ float ray_direction[3];
+ float ray_inv_dir[3];
+ float cdot_axis[3];
+ float idiag_sq[3];
+ bool sign[3];
+};
+
+void dist_squared_ray_to_aabb_v3_precalc(
+ struct NearestRayToAABB_Precalc *data,
+ const float ray_origin[3], const float ray_direction[3]);
+float dist_squared_ray_to_aabb_v3(
+ const struct NearestRayToAABB_Precalc *data,
+ const float bb_min[3], const float bb_max[3],
+ bool r_axis_closest[3]);
/* other */
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius,
const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float ipoint[3]);
-bool isect_axial_line_tri_v3(const int axis, const float co1[3], const float co2[3],
- const float v0[3], const float v1[3], const float v2[3], float *r_lambda);
-
-bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4]);
-bool clip_segment_v3_plane_n(float p1[3], float p2[3], float plane_array[][4], const int plane_tot);
+bool clip_segment_v3_plane(
+ const float p1[3], const float p2[3], const float plane[4],
+ float r_p1[3], float r_p2[3]);
+bool clip_segment_v3_plane_n(
+ const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot,
+ float r_p1[3], float r_p2[3]);
void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData);
void fill_poly_v2i_n(
const int xmin, const int ymin, const int xmax, const int ymax,
const int polyXY[][2], const int polyCorners,
- void (*callback)(int, int, void *), void *userData);
+ void (*callback)(int x, int x_end, int y, void *), void *userData);
/****************************** Interpolation ********************************/
/* tri or quad, d can be NULL */
@@ -411,7 +456,8 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]);
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]);
MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3]) ATTR_WARN_UNUSED_RESULT;
-MINLINE int axis_dominant_v3_single(const float vec[3]);
+MINLINE int axis_dominant_v3_single(const float vec[3]);
+MINLINE int axis_dominant_v3_ortho_single(const float vec[3]);
MINLINE int max_axis_v3(const float vec[3]);
MINLINE int min_axis_v3(const float vec[3]);
diff --git a/source/blender/blenlib/BLI_math_inline.h b/source/blender/blenlib/BLI_math_inline.h
index 2bf3b9532dd..840cf24f8cf 100644
--- a/source/blender/blenlib/BLI_math_inline.h
+++ b/source/blender/blenlib/BLI_math_inline.h
@@ -46,9 +46,9 @@ extern "C" {
# define MINLINE static inline
# if (defined(__APPLE__) && defined(__ppc__))
/* static inline __attribute__ here breaks osx ppc gcc42 build */
-# define MALWAYS_INLINE static __attribute__((always_inline))
+# define MALWAYS_INLINE static __attribute__((always_inline)) __attribute__((unused))
# else
-# define MALWAYS_INLINE static inline __attribute__((always_inline))
+# define MALWAYS_INLINE static inline __attribute__((always_inline)) __attribute__((unused))
# endif
# endif
#else
diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h
index d2ec7b80d86..a3c5ce82630 100644
--- a/source/blender/blenlib/BLI_math_interp.h
+++ b/source/blender/blenlib/BLI_math_interp.h
@@ -45,6 +45,12 @@ void BLI_bilinear_interpolation_fl(const float *buffer, float *output, int width
void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height,
int components, float u, float v);
+void BLI_bilinear_interpolation_wrap_fl(const float *buffer, float *output, int width, int height,
+ int components, float u, float v, bool wrap_x, bool wrap_y);
+
+void BLI_bilinear_interpolation_wrap_char(const unsigned char *buffer, unsigned char *output, int width, int height,
+ int components, float u, float v, bool wrap_x, bool wrap_y);
+
#define EWA_MAXIDX 255
extern const float EWA_WTS[EWA_MAXIDX + 1];
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index d7a309e0835..6fb983a622e 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -153,10 +153,14 @@ void transpose_m4_m4(float R[4][4], float A[4][4]);
int compare_m4m4(float mat1[4][4], float mat2[4][4], float limit);
-void normalize_m3(float R[3][3]);
-void normalize_m3_m3(float R[3][3], float A[3][3]);
-void normalize_m4(float R[4][4]);
-void normalize_m4_m4(float R[4][4], float A[4][4]);
+void normalize_m3_ex(float R[3][3], float r_scale[3]) ATTR_NONNULL();
+void normalize_m3(float R[3][3]) ATTR_NONNULL();
+void normalize_m3_m3_ex(float R[3][3], float A[3][3], float r_scale[3]) ATTR_NONNULL();
+void normalize_m3_m3(float R[3][3], float A[3][3]) ATTR_NONNULL();
+void normalize_m4_ex(float R[4][4], float r_scale[3]) ATTR_NONNULL();
+void normalize_m4(float R[4][4]) ATTR_NONNULL();
+void normalize_m4_m4_ex(float R[4][4], float A[4][4], float r_scale[3]) ATTR_NONNULL();
+void normalize_m4_m4(float R[4][4], float A[4][4]) ATTR_NONNULL();
void orthogonalize_m3(float R[3][3], int axis);
void orthogonalize_m4(float R[4][4], int axis);
@@ -169,6 +173,10 @@ bool is_orthonormal_m4(float mat[4][4]);
bool is_uniform_scaled_m3(float mat[3][3]);
bool is_uniform_scaled_m4(float m[4][4]);
+/* Note: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix!
+ * Nowadays 'adjoint' usually refers to the conjugate transpose,
+ * which for real-valued matrices is simply the transpose.
+ */
void adjoint_m2_m2(float R[2][2], float A[2][2]);
void adjoint_m3_m3(float R[3][3], float A[3][3]);
void adjoint_m4_m4(float R[4][4], float A[4][4]);
@@ -215,6 +223,8 @@ void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], float wm
void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4]);
void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]);
+void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+
void loc_eul_size_to_mat4(float R[4][4],
const float loc[3], const float eul[3], const float size[3]);
void loc_eulO_size_to_mat4(float R[4][4],
@@ -227,6 +237,9 @@ void loc_axisangle_size_to_mat4(float R[4][4],
void blend_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t);
void blend_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t);
+void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t);
+void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t);
+
bool is_negative_m3(float mat[3][3]);
bool is_negative_m4(float mat[4][4]);
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index fbd026f7617..24c20ee7b50 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -59,6 +59,8 @@ void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);
void invert_qt(float q[4]);
void invert_qt_qt(float q1[4], const float q2[4]);
+void invert_qt_normalized(float q[4]);
+void invert_qt_qt_normalized(float q1[4], const float q2[4]);
void conjugate_qt(float q[4]);
void conjugate_qt_qt(float q1[4], const float q2[4]);
float dot_qtqt(const float a[4], const float b[4]);
@@ -77,6 +79,8 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
+void mat3_normalized_to_quat(float q[4], float mat[3][3]);
+void mat4_normalized_to_quat(float q[4], float mat[4][4]);
void mat3_to_quat(float q[4], float mat[3][3]);
void mat4_to_quat(float q[4], float mat[4][4]);
void tri_to_quat_ex(float quat[4], const float v1[3], const float v2[3], const float v3[3],
@@ -112,13 +116,17 @@ void axis_angle_normalized_to_mat3_ex(float mat[3][3], const float axis[3],
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle);
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle);
-void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
+void mat3_normalized_to_axis_angle(float axis[3], float *angle, float M[3][3]);
+void mat4_normalized_to_axis_angle(float axis[3], float *angle, float M[4][4]);
void mat3_to_axis_angle(float axis[3], float *angle, float M[3][3]);
void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]);
+void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
void angle_to_mat2(float R[2][2], const float angle);
+void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
+
/****************************** Exponential Map ******************************/
void quat_to_expmap(float expmap[3], const float q[4]);
void quat_normalized_to_expmap(float expmap[3], const float q[4]);
@@ -130,12 +138,16 @@ void eul_to_quat(float quat[4], const float eul[3]);
void eul_to_mat3(float mat[3][3], const float eul[3]);
void eul_to_mat4(float mat[4][4], const float eul[3]);
-void quat_to_eul(float eul[3], const float quat[4]);
+void mat3_normalized_to_eul(float eul[3], float mat[3][3]);
+void mat4_normalized_to_eul(float eul[3], float mat[4][4]);
void mat3_to_eul(float eul[3], float mat[3][3]);
void mat4_to_eul(float eul[3], float mat[4][4]);
+void quat_to_eul(float eul[3], const float quat[4]);
-void compatible_eul(float eul[3], const float old[3]);
+void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
+void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
+void compatible_eul(float eul[3], const float old[3]);
void rotate_eul(float eul[3], const char axis, const float angle);
@@ -160,14 +172,19 @@ void eulO_to_mat3(float mat[3][3], const float eul[3], const short order);
void eulO_to_mat4(float mat[4][4], const float eul[3], const short order);
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order);
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order);
-
-void quat_to_eulO(float eul[3], const short order, const float quat[4]);
+
+void mat3_normalized_to_eulO(float eul[3], const short order, float mat[3][3]);
+void mat4_normalized_to_eulO(float eul[3], const short order, float mat[4][4]);
void mat3_to_eulO(float eul[3], const short order, float mat[3][3]);
void mat4_to_eulO(float eul[3], const short order, float mat[4][4]);
+void quat_to_eulO(float eul[3], const short order, const float quat[4]);
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle);
+void mat3_normalized_to_compatible_eulO(float eul[3], float old[3], const short order, float mat[3][3]);
+void mat4_normalized_to_compatible_eulO(float eul[3], float old[3], const short order, float mat[4][4]);
void mat3_to_compatible_eulO(float eul[3], float old[3], const short order, float mat[3][3]);
void mat4_to_compatible_eulO(float eul[3], float old[3], const short order, float mat[4][4]);
+void quat_to_compatible_eulO(float eul[3], float old[3], const short order, const float quat[4]);
void rotate_eulO(float eul[3], const short order, char axis, float angle);
diff --git a/source/blender/blenlib/BLI_math_solvers.h b/source/blender/blenlib/BLI_math_solvers.h
index ec9ba5538e2..810c84cc830 100644
--- a/source/blender/blenlib/BLI_math_solvers.h
+++ b/source/blender/blenlib/BLI_math_solvers.h
@@ -46,6 +46,7 @@ extern "C" {
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3], float r_eigen_vectors[3][3]);
+void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[], float r_V[3][3]);
/**************************** Inline Definitions ******************************/
#if 0 /* None so far. */
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 493c285d251..c44fcf47fdb 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -61,11 +61,14 @@ MINLINE void swap_v2_v2(float a[2], float b[2]);
MINLINE void swap_v3_v3(float a[3], float b[3]);
MINLINE void swap_v4_v4(float a[4], float b[4]);
+/* unsigned char */
+MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
+MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
+MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
/* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
-
/* short */
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
@@ -146,6 +149,8 @@ MINLINE void negate_v4_v4(float r[4], const float a[3]);
MINLINE void negate_v3_short(short r[3]);
+MINLINE void invert_v2(float r[2]);
+
MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]);
MINLINE void abs_v3(float r[3]);
@@ -267,6 +272,7 @@ float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
+float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -307,7 +313,7 @@ MINLINE void normal_float_to_short_v3(short r[3], const float n[3]);
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
-void minmax_v3v3_v3_array(float r_min[3], float r_max[3], float (*vec_arr)[3], int nbr);
+void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr);
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
diff --git a/source/blender/blenlib/BLI_memory_utils.h b/source/blender/blenlib/BLI_memory_utils.h
new file mode 100644
index 00000000000..32bbdf8a7b5
--- /dev/null
+++ b/source/blender/blenlib/BLI_memory_utils.h
@@ -0,0 +1,34 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_MEMORY_UTILS_H__
+#define __BLI_MEMORY_UTILS_H__
+
+/** \file BLI_memory_utils.h
+ * \ingroup bli
+ * \brief Generic memory manipulation API.
+ */
+
+/* it may be defined already */
+#ifndef __BLI_UTILDEFINES_H__
+bool BLI_memory_is_zero(const void *arr, const size_t size);
+#endif
+
+#endif /* __BLI_MEMORY_UTILS_H__ */
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index a344c9d2bc1..1a626ff44bd 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -99,12 +99,6 @@ int BLI_stringdec(const char *string, char *head, char *start, unsigned short *n
void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic);
int BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
-/**
- * dir can be any input, like from buttons, and this function
- * converts it to a regular full path.
- * Also removes garbage from directory paths, like /../ or double slashes etc
- */
-
/* removes trailing slash */
void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2);
/* same as above but adds a trailing slash */
@@ -118,25 +112,13 @@ bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
/* go back one directory */
bool BLI_parent_dir(char *path) ATTR_NONNULL();
-/**
- * Blender's path code replacement function.
- * Bases \a path strings leading with "//" by the
- * directory \a basepath, and replaces instances of
- * '#' with the \a framenum. Results are written
- * back into \a path.
- *
- * \a path The path to convert
- * \a basepath The directory to base relative paths with.
- * \a framenum The framenumber to replace the frame code with.
- * \retval Returns true if the path was relative (started with "//").
- */
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
-void BLI_path_frame_strip(char *path, bool setsharp, char *ext) ATTR_NONNULL();
+void BLI_path_frame_strip(char *path, bool set_frame_char, char *ext) ATTR_NONNULL();
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
-bool BLI_path_cwd(char *path) ATTR_NONNULL();
+bool BLI_path_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
@@ -158,10 +140,6 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define BLI_path_ncmp strncmp
#endif
-#ifdef WITH_ICONV
-void BLI_string_to_utf8(char *original, char *utf_8, const char *code);
-#endif
-
/* these values need to be hardcoded in structs, dna does not recognize defines */
/* also defined in DNA_space_types.h */
#ifndef FILE_MAXDIR
@@ -183,5 +161,4 @@ void BLI_string_to_utf8(char *original, char *utf_8, const char *code);
}
#endif
-#endif
-
+#endif /* __BLI_PATH_UTIL_H__ */
diff --git a/source/blender/blenlib/BLI_rect.h b/source/blender/blenlib/BLI_rect.h
index a98931d2ae8..59bf3644912 100644
--- a/source/blender/blenlib/BLI_rect.h
+++ b/source/blender/blenlib/BLI_rect.h
@@ -66,6 +66,8 @@ void BLI_rctf_interp(struct rctf *rect, const struct rctf *rect_a, const struct
//void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac);
bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]);
bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]);
+bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]);
+bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]);
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit);
bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b);
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest);
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
index 2d8d6e4482d..b26dc3e26aa 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -44,6 +44,7 @@
#define STACK_SIZE(stack) ((void)stack, (_##stack##_index))
+#define STACK_CLEAR(stack) {(void)stack; _##stack##_index = 0; } ((void)0)
/** add item to stack */
#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = val))
#define STACK_PUSH_RET(stack) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++]))
@@ -63,26 +64,26 @@
if (--_##stack##_index != _i) { \
stack[_i] = stack[_##stack##_index]; \
} \
- } (void)0
+ } ((void)0)
#define STACK_DISCARD(stack, n) \
{ \
const unsigned int _n = n; \
BLI_assert(_##stack##_index >= _n); \
(void)stack; \
_##stack##_index -= _n; \
- } (void)0
+ } ((void)0)
#ifdef __GNUC__
#define STACK_SWAP(stack_a, stack_b) { \
SWAP(typeof(stack_a), stack_a, stack_b); \
SWAP(unsigned int, _##stack_a##_index, _##stack_b##_index); \
_STACK_SWAP_TOTALLOC(stack_a, stack_b); \
- } (void)0
+ } ((void)0)
#else
#define STACK_SWAP(stack_a, stack_b) { \
SWAP(void *, stack_a, stack_b); \
SWAP(unsigned int, _##stack_a##_index, _##stack_b##_index); \
_STACK_SWAP_TOTALLOC(stack_a, stack_b); \
- } (void)0
+ } ((void)0)
#endif
#endif /* __BLI_STACKDEFINES_H__ */
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index 82780394ce7..d137806c575 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -74,6 +74,7 @@ size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_natstrcmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -97,6 +98,11 @@ size_t BLI_str_partition_ex(
const char *str, const char *end, const char delim[], const char **sep, const char **suf, const bool from_right)
ATTR_NONNULL(1, 3, 4, 5);
+int BLI_string_find_split_words(
+ const char *str, const size_t len,
+ const char delim, int r_words[][2], int words_max)
+ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index c9cf33f2f69..7929e1d6551 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -78,25 +78,7 @@ typedef uint64_t u_int64_t;
#endif /* ifdef platform for types */
#include <stddef.h> /* size_t define */
-
-#ifdef HAVE_STDBOOL_H
-# include <stdbool.h>
-#elif !defined(__bool_true_false_are_defined) && !defined(__BOOL_DEFINED)
-# ifndef HAVE__BOOL
-# ifdef __cplusplus
-typedef bool _BLI_Bool;
-# else
-/* Make sure bool is alays defined with the same size for both C and C++ */
-# define _BLI_Bool unsigned char
-# endif
-# else
-# define _BLI_Bool _Bool
-# endif
-# define bool _BLI_Bool
-# define false 0
-# define true 1
-# define __bool_true_false_are_defined 1
-#endif
+#include <stdbool.h>
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 780b0bfbbd6..63a07957336 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -74,10 +74,15 @@ typedef enum TaskPriority {
typedef struct TaskPool TaskPool;
typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata, int threadid);
+typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata, int threadid);
TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata);
+TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata);
void BLI_task_pool_free(TaskPool *pool);
+void BLI_task_pool_push_ex(
+ TaskPool *pool, TaskRunFunction run, void *taskdata,
+ bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority);
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run,
void *taskdata, bool free_taskdata, TaskPriority priority);
@@ -107,17 +112,20 @@ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
size_t BLI_task_pool_tasks_done(TaskPool *pool);
/* Parallel for routines */
-typedef void (*TaskParallelRangeFunc)(void *userdata, int iter);
+typedef void (*TaskParallelRangeFunc)(void *userdata, const int iter);
+typedef void (*TaskParallelRangeFuncEx)(void *userdata, void *userdata_chunk, const int iter, const int thread_id);
void BLI_task_parallel_range_ex(
int start, int stop,
void *userdata,
- TaskParallelRangeFunc func,
- const int range_threshold,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size, TaskParallelRangeFuncEx func_ex,
+ const bool use_threading,
const bool use_dynamic_scheduling);
void BLI_task_parallel_range(
int start, int stop,
void *userdata,
- TaskParallelRangeFunc func);
+ TaskParallelRangeFunc func,
+ const bool use_threading);
#ifdef __cplusplus
}
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 6ae833d5ed7..b4a465bbc74 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -181,6 +181,27 @@ bool BLI_thread_queue_is_empty(ThreadQueue *queue);
void BLI_thread_queue_wait_finish(ThreadQueue *queue);
void BLI_thread_queue_nowait(ThreadQueue *queue);
+
+/* Thread local storage */
+
+#if defined(__APPLE__)
+# define ThreadLocal(type) pthread_key_t
+# define BLI_thread_local_create(name) pthread_key_create(&name, NULL)
+# define BLI_thread_local_delete(name) pthread_key_delete(name)
+# define BLI_thread_local_get(name) pthread_getspecific(name)
+# define BLI_thread_local_set(name, value) pthread_setspecific(name, value)
+#else /* defined(__APPLE__) */
+# ifdef _MSC_VER
+# define ThreadLocal(type) __declspec(thread) type
+# else
+# define ThreadLocal(type) __thread type
+# endif
+# define BLI_thread_local_create(name)
+# define BLI_thread_local_delete(name)
+# define BLI_thread_local_get(name) name
+# define BLI_thread_local_set(name, value) name = value
+#endif /* defined(__APPLE__) */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_timecode.h b/source/blender/blenlib/BLI_timecode.h
index 235d928b460..a45613c6b1e 100644
--- a/source/blender/blenlib/BLI_timecode.h
+++ b/source/blender/blenlib/BLI_timecode.h
@@ -39,7 +39,7 @@ size_t BLI_timecode_string_from_time(
ATTR_NONNULL();
size_t BLI_timecode_string_from_time_simple(
- char *str, size_t maxlen, const double time_seconds)
+ char *str, const size_t maxlen, const double time_seconds)
ATTR_NONNULL();
size_t BLI_timecode_string_from_time_seconds(
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 65e8dcdba4a..d504e503c68 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -406,9 +406,9 @@ extern "C" {
CHECK_TYPE_INLINE(a, float), CHECK_TYPE_INLINE(b, float), \
((fabsf((float)((a) - (b))) >= (float) FLT_EPSILON) ? false : true))
-#define IS_EQT(a, b, c) ((a > b) ? ((((a) - (b)) <= c) ? 1 : 0) : (((((b) - (a)) <= c) ? 1 : 0)))
-#define IN_RANGE(a, b, c) ((b < c) ? ((b < a && a < c) ? 1 : 0) : ((c < a && a < b) ? 1 : 0))
-#define IN_RANGE_INCL(a, b, c) ((b < c) ? ((b <= a && a <= c) ? 1 : 0) : ((c <= a && a <= b) ? 1 : 0))
+#define IS_EQT(a, b, c) (((a) > (b)) ? ((((a) - (b)) <= (c))) : (((((b) - (a)) <= (c)))))
+#define IN_RANGE(a, b, c) (((b) < (c)) ? (((b) < (a) && (a) < (c))) : (((c) < (a) && (a) < (b))))
+#define IN_RANGE_INCL(a, b, c) (((b) < (c)) ? (((b) <= (a) && (a) <= (c))) : (((c) <= (a) && (a) <= (b))))
/* unpack vector for args */
#define UNPACK2(a) ((a)[0]), ((a)[1])
@@ -513,6 +513,17 @@ extern "C" {
sizeof(*(struct_var)) - OFFSETOF_STRUCT(struct_var, member)); \
} (void)0
+/* defined
+ * in memory_utils.c for now. I do not know where we should put it actually... */
+#ifndef __BLI_MEMORY_UTILS_H__
+extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
+#endif
+
+#define MEMCMP_STRUCT_OFS_IS_ZERO(struct_var, member) \
+ (BLI_memory_is_zero( \
+ (char *)(struct_var) + OFFSETOF_STRUCT(struct_var, member), \
+ sizeof(*(struct_var)) - OFFSETOF_STRUCT(struct_var, member)))
+
/* Warning-free macros for storing ints in pointers. Use these _only_
* for storing an int in a pointer, not a pointer in an int (64bit)! */
#define SET_INT_IN_POINTER(i) ((void *)(intptr_t)(i))
@@ -617,18 +628,6 @@ extern "C" {
# define UNUSED_VARS_NDEBUG UNUSED_VARS
#endif
-/*little macro so inline keyword works*/
-#if defined(_MSC_VER)
-# define BLI_INLINE static __forceinline
-#else
-# if (defined(__APPLE__) && defined(__ppc__))
-/* static inline __attribute__ here breaks osx ppc gcc42 build */
-# define BLI_INLINE static __attribute__((always_inline))
-# else
-# define BLI_INLINE static inline __attribute__((always_inline))
-# endif
-#endif
-
/* BLI_assert(), default only to print
* for aborting need to define WITH_ASSERT_ABORT
diff --git a/source/blender/blenlib/BLI_voxel.h b/source/blender/blenlib/BLI_voxel.h
index 7b92ac05d29..815d319b6db 100644
--- a/source/blender/blenlib/BLI_voxel.h
+++ b/source/blender/blenlib/BLI_voxel.h
@@ -33,7 +33,11 @@
*/
/** find the index number of a voxel, given x/y/z integer coords and resolution vector */
-#define BLI_VOXEL_INDEX(x, y, z, res) ((z) * (res)[1] * (res)[0] + (y) * (res)[0] + (x))
+
+#define BLI_VOXEL_INDEX(x, y, z, res) \
+ ((int64_t)(x) + \
+ (int64_t)(y) * (int64_t)(res)[0] + \
+ (int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1])
/* all input coordinates must be in bounding box 0.0 - 1.0 */
float BLI_voxel_sample_nearest(float *data, const int res[3], const float co[3]);
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index 8cf6f188e19..b421b7dbb90 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -90,7 +90,9 @@ extern "C" {
#endif
/* defines for using ISO C++ conformant names */
-#define snprintf _snprintf
+#if !defined(_MSC_VER) || _MSC_VER < 1900
+# define snprintf _snprintf
+#endif
#if defined(_MSC_VER) || (defined(FREE_WINDOWS) && !defined(FREE_WINDOWS64))
# define R_OK 4
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index dcf7c3b5d39..944ba60eb58 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -29,8 +29,8 @@ set(INC
../makesdna
../../../intern/guardedalloc
../../../intern/atomic
+ ../../../intern/eigen
../../../extern/wcwidth
- ../../../extern/Eigen3
)
set(INC_SYS
@@ -88,6 +88,7 @@ set(SRC
intern/math_statistics.c
intern/math_vector.c
intern/math_vector_inline.c
+ intern/memory_utils.c
intern/noise.c
intern/path_util.c
intern/polyfill2d.c
@@ -169,6 +170,7 @@ set(SRC
BLI_math_statistics.h
BLI_math_vector.h
BLI_memarena.h
+ BLI_memory_utils.h
BLI_mempool.h
BLI_noise.h
BLI_path_util.h
diff --git a/source/blender/blenlib/PIL_time_utildefines.h b/source/blender/blenlib/PIL_time_utildefines.h
index 4141befb130..9157e04a7bf 100644
--- a/source/blender/blenlib/PIL_time_utildefines.h
+++ b/source/blender/blenlib/PIL_time_utildefines.h
@@ -51,15 +51,40 @@
#define TIMEIT_VALUE_PRINT(var) \
{ \
- printf("time update(" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var));\
+ printf("time update (" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var));\
fflush(stdout); \
} (void)0
#define TIMEIT_END(var) \
- } \
- printf("time end (" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var)); \
- fflush(stdout); \
-} (void)0
+ } \
+ printf("time end (" #var "): %.6f" " " AT "\n", TIMEIT_VALUE(var));\
+ fflush(stdout); \
+ } (void)0
+
+/**
+ * _AVERAGED variants do same thing as their basic counterpart, but additionally add elapsed time to an averaged
+ * static value, useful to get sensible timing of code running fast and often.
+ */
+#define TIMEIT_START_AVERAGED(var) \
+ { \
+ static float _sum_##var = 0.0f; \
+ static float _num_##var = 0.0f; \
+ double _timeit_##var = PIL_check_seconds_timer(); \
+ printf("time start (" #var "): " AT "\n"); \
+ fflush(stdout); \
+ { (void)0
+
+#define TIMEIT_AVERAGED_VALUE(var) (_num##var ? (_sum_##var / _num_##var) : 0.0f)
+
+#define TIMEIT_END_AVERAGED(var) \
+ } \
+ const float _delta_##var = TIMEIT_VALUE(var); \
+ _sum_##var += _delta_##var; \
+ printf("time end (" #var "): %.6f" " " AT "\n", _delta_##var); \
+ printf("time averaged (" #var "): %.6f" " " AT "\n", \
+ (_sum_##var / ++_num_##var)); \
+ fflush(stdout); \
+ } (void)0
/**
* Given some function/expression:
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
deleted file mode 100644
index 0e4b9bf4efd..00000000000
--- a/source/blender/blenlib/SConscript
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-
-cflags=''
-# don't add ../blenkernel back!
-incs = [
- '.',
- '#/extern/wcwidth',
- '#/extern/Eigen3',
- '#/intern/guardedalloc',
- '#/intern/atomic',
- '../makesdna',
- env['BF_FREETYPE_INC'],
- env['BF_ZLIB_INC'],
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
- incs += ' ../../../intern/utfconv'
-
-if env['OURPLATFORM'] == 'linuxcross':
- if env['WITH_BF_OPENMP']:
- incs += ' ' + env['BF_OPENMP_INC']
-
-env.BlenderLib ( 'bf_blenlib', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [370,230], compileflags =cflags )
diff --git a/source/blender/blenlib/intern/BLI_args.c b/source/blender/blenlib/intern/BLI_args.c
index 9faf6c93447..340ae52120c 100644
--- a/source/blender/blenlib/intern/BLI_args.c
+++ b/source/blender/blenlib/intern/BLI_args.c
@@ -213,8 +213,6 @@ void BLI_argsAddCase(struct bArgs *ba, int pass,
if (long_arg)
internalAdd(ba, long_arg, pass, long_case, cb, data, d);
-
-
}
void BLI_argsAdd(struct bArgs *ba, int pass,
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 62690ff4f3c..527d9934797 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -333,7 +333,8 @@ void BLI_filelist_entry_datetime_to_string(
const struct stat *st, const int64_t ts, const bool compact,
char r_time[FILELIST_DIRENTRY_TIME_LEN], char r_date[FILELIST_DIRENTRY_DATE_LEN])
{
- const struct tm *tm = localtime(st ? &st->st_mtime : &ts);
+ time_t ts_mtime = ts;
+ const struct tm *tm = localtime(st ? &st->st_mtime : &ts_mtime);
const time_t zero = 0;
/* Prevent impossible dates in windows. */
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 7e6dabdffef..06946e520a8 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -155,7 +155,7 @@ BLI_INLINE unsigned int ghash_entryhash(GHash *gh, const Entry *e)
}
/**
- * Get the bucket-hash for an already-computed full hash.
+ * Get the bucket-index for an already-computed full hash.
*/
BLI_INLINE unsigned int ghash_bucket_index(GHash *gh, const unsigned int hash)
{
@@ -167,6 +167,31 @@ BLI_INLINE unsigned int ghash_bucket_index(GHash *gh, const unsigned int hash)
}
/**
+ * Find the index of next used bucket, starting from \a curr_bucket (\a gh is assumed non-empty).
+ */
+BLI_INLINE unsigned int ghash_find_next_bucket_index(GHash *gh, unsigned int curr_bucket)
+{
+ if (curr_bucket >= gh->nbuckets) {
+ curr_bucket = 0;
+ }
+ if (gh->buckets[curr_bucket]) {
+ return curr_bucket;
+ }
+ for (; curr_bucket < gh->nbuckets; curr_bucket++) {
+ if (gh->buckets[curr_bucket]) {
+ return curr_bucket;
+ }
+ }
+ for (curr_bucket = 0; curr_bucket < gh->nbuckets; curr_bucket++) {
+ if (gh->buckets[curr_bucket]) {
+ return curr_bucket;
+ }
+ }
+ BLI_assert(0);
+ return 0;
+}
+
+/**
* Expand buckets to the next size up or down.
*/
static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
@@ -175,7 +200,6 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
Entry **buckets_new;
const unsigned int nbuckets_old = gh->nbuckets;
unsigned int i;
- Entry *e;
BLI_assert((gh->nbuckets != nbuckets) || !gh->buckets);
// printf("%s: %d -> %d\n", __func__, nbuckets_old, nbuckets);
@@ -191,8 +215,7 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
if (buckets_old) {
if (nbuckets > nbuckets_old) {
for (i = 0; i < nbuckets_old; i++) {
- Entry *e_next;
- for (e = buckets_old[i]; e; e = e_next) {
+ for (Entry *e = buckets_old[i], *e_next; e; e = e_next) {
const unsigned hash = ghash_entryhash(gh, e);
const unsigned bucket_index = ghash_bucket_index(gh, hash);
e_next = e->next;
@@ -204,8 +227,7 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
else {
for (i = 0; i < nbuckets_old; i++) {
#ifdef GHASH_USE_MODULO_BUCKETS
- Entry *e_next;
- for (e = buckets_old[i]; e; e = e_next) {
+ for (Entry *e = buckets_old[i], *e_next; e; e = e_next) {
const unsigned hash = ghash_entryhash(gh, e);
const unsigned bucket_index = ghash_bucket_index(gh, hash);
e_next = e->next;
@@ -217,6 +239,7 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets)
* will go in same new bucket (i & new_mask)! */
const unsigned bucket_index = ghash_bucket_index(gh, i);
BLI_assert(!buckets_old[i] || (bucket_index == ghash_bucket_index(gh, ghash_entryhash(gh, buckets_old[i]))));
+ Entry *e;
for (e = buckets_old[i]; e && e->next; e = e->next);
if (e) {
e->next = buckets_new[bucket_index];
@@ -376,17 +399,16 @@ BLI_INLINE Entry *ghash_lookup_entry_ex(
/**
* Internal lookup function, returns previous entry of target one too.
- * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
+ * Takes bucket_index argument to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times.
* Useful when modifying buckets somehow (like removing an entry...).
*/
BLI_INLINE Entry *ghash_lookup_entry_prev_ex(
- GHash *gh, const void *key, Entry **r_e_prev, const unsigned int bucket_index)
+ GHash *gh, const void *key,
+ Entry **r_e_prev, const unsigned int bucket_index)
{
- Entry *e, *e_prev = NULL;
-
/* If we do not store GHash, not worth computing it for each entry here!
* Typically, comparison function will be quicker, and since it's needed in the end anyway... */
- for (e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) {
+ for (Entry *e_prev = NULL, *e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) {
if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
*r_e_prev = e_prev;
return e;
@@ -487,7 +509,8 @@ BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val)
}
BLI_INLINE bool ghash_insert_safe(
- GHash *gh, void *key, void *val, const bool override, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
+ GHash *gh, void *key, void *val, const bool override,
+ GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
const unsigned int bucket_index = ghash_bucket_index(gh, hash);
@@ -497,8 +520,12 @@ BLI_INLINE bool ghash_insert_safe(
if (e) {
if (override) {
- if (keyfreefp) keyfreefp(e->e.key);
- if (valfreefp) valfreefp(e->val);
+ if (keyfreefp) {
+ keyfreefp(e->e.key);
+ }
+ if (valfreefp) {
+ valfreefp(e->val);
+ }
e->e.key = key;
e->val = val;
}
@@ -510,7 +537,9 @@ BLI_INLINE bool ghash_insert_safe(
}
}
-BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool override, GHashKeyFreeFP keyfreefp)
+BLI_INLINE bool ghash_insert_safe_keyonly(
+ GHash *gh, void *key, const bool override,
+ GHashKeyFreeFP keyfreefp)
{
const unsigned int hash = ghash_keyhash(gh, key);
const unsigned int bucket_index = ghash_bucket_index(gh, hash);
@@ -520,7 +549,9 @@ BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool overr
if (e) {
if (override) {
- if (keyfreefp) keyfreefp(e->key);
+ if (keyfreefp) {
+ keyfreefp(e->key);
+ }
e->key = key;
}
return false;
@@ -535,7 +566,8 @@ BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool overr
* Remove the entry and return it, caller must free from gh->entrypool.
*/
static Entry *ghash_remove_ex(
- GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
+ GHash *gh, const void *key,
+ GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp,
const unsigned int bucket_index)
{
Entry *e_prev;
@@ -544,11 +576,19 @@ static Entry *ghash_remove_ex(
BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET));
if (e) {
- if (keyfreefp) keyfreefp(e->key);
- if (valfreefp) valfreefp(((GHashEntry *)e)->val);
+ if (keyfreefp) {
+ keyfreefp(e->key);
+ }
+ if (valfreefp) {
+ valfreefp(((GHashEntry *)e)->val);
+ }
- if (e_prev) e_prev->next = e->next;
- else gh->buckets[bucket_index] = e->next;
+ if (e_prev) {
+ e_prev->next = e->next;
+ }
+ else {
+ gh->buckets[bucket_index] = e->next;
+ }
ghash_buckets_contract(gh, --gh->nentries, false, false);
}
@@ -557,9 +597,34 @@ static Entry *ghash_remove_ex(
}
/**
+ * Remove a random entry and return it (or NULL if empty), caller must free from gh->entrypool.
+ */
+static Entry *ghash_pop(GHash *gh, GHashIterState *state)
+{
+ unsigned int curr_bucket = state->curr_bucket;
+ if (gh->nentries == 0) {
+ return NULL;
+ }
+
+ /* Note: using first_bucket_index here allows us to avoid potential huge number of loops over buckets,
+ * in case we are popping from a large ghash with few items in it... */
+ curr_bucket = ghash_find_next_bucket_index(gh, curr_bucket);
+
+ Entry *e = gh->buckets[curr_bucket];
+ BLI_assert(e);
+
+ ghash_remove_ex(gh, e->key, NULL, NULL, curr_bucket);
+
+ state->curr_bucket = curr_bucket;
+ return e;
+}
+
+/**
* Run free callbacks for freeing entries.
*/
-static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
+static void ghash_free_cb(
+ GHash *gh,
+ GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{
unsigned int i;
@@ -570,8 +635,12 @@ static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP va
Entry *e;
for (e = gh->buckets[i]; e; e = e->next) {
- if (keyfreefp) keyfreefp(e->key);
- if (valfreefp) valfreefp(((GHashEntry *)e)->val);
+ if (keyfreefp) {
+ keyfreefp(e->key);
+ }
+ if (valfreefp) {
+ valfreefp(((GHashEntry *)e)->val);
+ }
}
}
}
@@ -767,11 +836,13 @@ bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
}
/**
- * A version of #BLI_ghash_ensure_p copies the key on insertion.
+ * A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
+ * Typically used when the key is to be duplicated.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
*/
bool BLI_ghash_ensure_p_ex(
- GHash *gh, const void *key, void ***r_val,
- GHashKeyCopyFP keycopyfp)
+ GHash *gh, const void *key, void ***r_key, void ***r_val)
{
const unsigned int hash = ghash_keyhash(gh, key);
const unsigned int bucket_index = ghash_bucket_index(gh, hash);
@@ -779,11 +850,13 @@ bool BLI_ghash_ensure_p_ex(
const bool haskey = (e != NULL);
if (!haskey) {
- /* keycopyfp(key) is the only difference to BLI_ghash_ensure_p */
+ /* pass 'key' incase we resize */
e = BLI_mempool_alloc(gh->entrypool);
- ghash_insert_ex_keyonly_entry(gh, keycopyfp(key), bucket_index, (Entry *)e);
+ ghash_insert_ex_keyonly_entry(gh, (void *)key, bucket_index, (Entry *)e);
+ e->e.key = NULL; /* caller must re-assign */
}
+ *r_key = &e->e.key;
*r_val = &e->val;
return haskey;
}
@@ -844,6 +917,35 @@ bool BLI_ghash_haskey(GHash *gh, const void *key)
}
/**
+ * Remove a random entry from \a gh, returning true if a key/value pair could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param r_val: The removed value.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if ghash was already empty.
+ */
+bool BLI_ghash_pop(
+ GHash *gh, GHashIterState *state,
+ void **r_key, void **r_val)
+{
+ GHashEntry *e = (GHashEntry *)ghash_pop(gh, state);
+
+ BLI_assert(!(gh->flag & GHASH_FLAG_IS_GSET));
+
+ if (e) {
+ *r_key = e->e.key;
+ *r_val = e->val;
+
+ BLI_mempool_free(gh->entrypool, e);
+ return true;
+ }
+ else {
+ *r_key = *r_val = NULL;
+ return false;
+ }
+}
+
+/**
* Reset \a gh clearing all entries.
*
* \param keyfreefp Optional callback to free the key.
@@ -1293,6 +1395,30 @@ bool BLI_gset_add(GSet *gs, void *key)
}
/**
+ * Set counterpart to #BLI_ghash_ensure_p_ex.
+ * similar to BLI_gset_add, except it returns the key pointer.
+ *
+ * \warning Caller _must_ write to \a r_key when returning false.
+ */
+bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
+{
+ const unsigned int hash = ghash_keyhash((GHash *)gs, key);
+ const unsigned int bucket_index = ghash_bucket_index((GHash *)gs, hash);
+ GSetEntry *e = (GSetEntry *)ghash_lookup_entry_ex((GHash *)gs, key, bucket_index);
+ const bool haskey = (e != NULL);
+
+ if (!haskey) {
+ /* pass 'key' incase we resize */
+ e = BLI_mempool_alloc(((GHash *)gs)->entrypool);
+ ghash_insert_ex_keyonly_entry((GHash *)gs, (void *)key, bucket_index, (Entry *)e);
+ e->key = NULL; /* caller must re-assign */
+ }
+
+ *r_key = &e->key;
+ return haskey;
+}
+
+/**
* Adds the key to the set (duplicates are managed).
* Matching #BLI_ghash_reinsert
*
@@ -1314,6 +1440,31 @@ bool BLI_gset_haskey(GSet *gs, const void *key)
return (ghash_lookup_entry((GHash *)gs, key) != NULL);
}
+/**
+ * Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
+ *
+ * \param r_key: The removed key.
+ * \param state: Used for efficient removal.
+ * \return true if there was something to pop, false if gset was already empty.
+ */
+bool BLI_gset_pop(
+ GSet *gs, GSetIterState *state,
+ void **r_key)
+{
+ GSetEntry *e = (GSetEntry *)ghash_pop((GHash *)gs, (GHashIterState *)state);
+
+ if (e) {
+ *r_key = e->key;
+
+ BLI_mempool_free(((GHash *)gs)->entrypool, e);
+ return true;
+ }
+ else {
+ *r_key = NULL;
+ return false;
+ }
+}
+
void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp,
const unsigned int nentries_reserve)
{
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index ddb61e415ac..bba3fdb37bc 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -29,7 +29,12 @@
* \ingroup bli
* \brief BVH-tree implementation.
*
- * KD-Overlap-BVH, implements a bvh-tree structure with support for:
+ * k-DOP BVH (Discrete Oriented Polytope, Bounding Volume Hierarchy).
+ * A k-DOP is represented as k/2 pairs of min , max values for k/2 directions (intervals, "slabs").
+ *
+ * See: http://www.gris.uni-tuebingen.de/people/staff/jmezger/papers/bvh.pdf
+ *
+ * implements a bvh-tree structure with support for:
*
* - Ray-cast:
* #BLI_bvhtree_ray_cast, #BVHRayCastData
@@ -37,6 +42,8 @@
* #BLI_bvhtree_find_nearest, #BVHNearestData
* - Overlapping 2 trees:
* #BLI_bvhtree_overlap, #BVHOverlapData_Shared, #BVHOverlapData_Thread
+ * - Range Query:
+ * #BLI_bvhtree_range_query
*/
#include <assert.h>
@@ -49,27 +56,28 @@
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BLI_strict_flags.h"
-
-#ifdef _OPENMP
-#include <omp.h>
-#endif
+#include "BLI_task.h"
/* used for iterative_raycast */
// #define USE_SKIP_LINKS
#define MAX_TREETYPE 32
-/* Setting zero so we can catch bugs in OpenMP/KDOPBVH.
+/* Setting zero so we can catch bugs in BLI_task/KDOPBVH.
* TODO(sergey): Deduplicate the limits with PBVH from BKE.
*/
-#ifdef _OPENMP
-# ifdef DEBUG
-# define KDOPBVH_OMP_LIMIT 0
-# else
-# define KDOPBVH_OMP_LIMIT 1024
-# endif
+#ifdef DEBUG
+# define KDOPBVH_THREAD_LEAF_THRESHOLD 0
+#else
+# define KDOPBVH_THREAD_LEAF_THRESHOLD 1024
#endif
+
+/* -------------------------------------------------------------------- */
+
+/** \name Struct Definitions
+ * \{ */
+
typedef unsigned char axis_t;
typedef struct BVHNode {
@@ -93,7 +101,7 @@ struct BVHTree {
float epsilon; /* epslion is used for inflation of the k-dop */
int totleaf; /* leafs */
int totbranch;
- axis_t start_axis, stop_axis; /* KDOP_AXES array indices according to axis */
+ axis_t start_axis, stop_axis; /* bvhtree_kdop_axes array indices according to axis */
axis_t axis; /* kdop type (6 => OBB, 7 => AABB, ...) */
char tree_type; /* type of tree (4 => quadtree) */
};
@@ -151,6 +159,20 @@ typedef struct BVHRayCastData {
BVHTreeRayHit hit;
} BVHRayCastData;
+typedef struct BVHNearestRayData {
+ BVHTree *tree;
+ BVHTree_NearestToRayCallback callback;
+ void *userdata;
+ BVHTreeRay ray;
+
+ struct NearestRayToAABB_Precalc nearest_precalc;
+
+ bool pick_smallest[3];
+ BVHTreeNearest nearest;
+} BVHNearestRayData;
+
+/** \} */
+
/**
* Bounding Volume Hierarchy Definition
@@ -160,12 +182,18 @@ typedef struct BVHRayCastData {
* Notes: You can choose the tree type --> binary, quad, octree, choose below
*/
-static const float KDOP_AXES[13][3] = {
+const float bvhtree_kdop_axes[13][3] = {
{1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}, {1.0, 1.0, 1.0}, {1.0, -1.0, 1.0}, {1.0, 1.0, -1.0},
{1.0, -1.0, -1.0}, {1.0, 1.0, 0}, {1.0, 0, 1.0}, {0, 1.0, 1.0}, {1.0, -1.0, 0}, {1.0, 0, -1.0},
{0, 1.0, -1.0}
};
+
+/* -------------------------------------------------------------------- */
+
+/** \name Utility Functions
+ * \{ */
+
MINLINE axis_t min_axis(axis_t a, axis_t b)
{
return (a < b) ? a : b;
@@ -275,6 +303,14 @@ static void node_minmax_init(const BVHTree *tree, BVHNode *node)
}
}
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Balance Utility Functions
+ * \{ */
+
/**
* Insertion sort algorithm
*/
@@ -455,7 +491,7 @@ static void create_kdop_hull(BVHTree *tree, BVHNode *node, const float *co, int
for (k = 0; k < numpoints; k++) {
/* for all Axes. */
for (axis_iter = tree->start_axis; axis_iter < tree->stop_axis; axis_iter++) {
- newminmax = dot_v3v3(&co[k * 3], KDOP_AXES[axis_iter]);
+ newminmax = dot_v3v3(&co[k * 3], bvhtree_kdop_axes[axis_iter]);
if (newminmax < bv[2 * axis_iter])
bv[2 * axis_iter] = newminmax;
if (newminmax > bv[(2 * axis_iter) + 1])
@@ -740,6 +776,81 @@ static void split_leafs(BVHNode **leafs_array, int *nth, int partitions, int spl
}
}
+typedef struct BVHDivNodesData {
+ BVHTree *tree;
+ BVHNode *branches_array;
+ BVHNode **leafs_array;
+
+ int tree_type;
+ int tree_offset;
+
+ BVHBuildHelper *data;
+
+ int depth;
+ int i;
+ int first_of_next_level;
+} BVHDivNodesData;
+
+static void non_recursive_bvh_div_nodes_task_cb(void *userdata, const int j)
+{
+ BVHDivNodesData *data = userdata;
+
+ int k;
+ const int parent_level_index = j - data->i;
+ BVHNode *parent = data->branches_array + j;
+ int nth_positions[MAX_TREETYPE + 1];
+ char split_axis;
+
+ int parent_leafs_begin = implicit_leafs_index(data->data, data->depth, parent_level_index);
+ int parent_leafs_end = implicit_leafs_index(data->data, data->depth, parent_level_index + 1);
+
+ /* This calculates the bounding box of this branch
+ * and chooses the largest axis as the axis to divide leafs */
+ refit_kdop_hull(data->tree, parent, parent_leafs_begin, parent_leafs_end);
+ split_axis = get_largest_axis(parent->bv);
+
+ /* Save split axis (this can be used on raytracing to speedup the query time) */
+ parent->main_axis = split_axis / 2;
+
+ /* Split the childs along the split_axis, note: its not needed to sort the whole leafs array
+ * Only to assure that the elements are partitioned on a way that each child takes the elements
+ * it would take in case the whole array was sorted.
+ * Split_leafs takes care of that "sort" problem. */
+ nth_positions[0] = parent_leafs_begin;
+ nth_positions[data->tree_type] = parent_leafs_end;
+ for (k = 1; k < data->tree_type; k++) {
+ const int child_index = j * data->tree_type + data->tree_offset + k;
+ const int child_level_index = child_index - data->first_of_next_level; /* child level index */
+ nth_positions[k] = implicit_leafs_index(data->data, data->depth + 1, child_level_index);
+ }
+
+ split_leafs(data->leafs_array, nth_positions, data->tree_type, split_axis);
+
+ /* Setup children and totnode counters
+ * Not really needed but currently most of BVH code relies on having an explicit children structure */
+ for (k = 0; k < data->tree_type; k++) {
+ const int child_index = j * data->tree_type + data->tree_offset + k;
+ const int child_level_index = child_index - data->first_of_next_level; /* child level index */
+
+ const int child_leafs_begin = implicit_leafs_index(data->data, data->depth + 1, child_level_index);
+ const int child_leafs_end = implicit_leafs_index(data->data, data->depth + 1, child_level_index + 1);
+
+ if (child_leafs_end - child_leafs_begin > 1) {
+ parent->children[k] = data->branches_array + child_index;
+ parent->children[k]->parent = parent;
+ }
+ else if (child_leafs_end - child_leafs_begin == 1) {
+ parent->children[k] = data->leafs_array[child_leafs_begin];
+ parent->children[k]->parent = parent;
+ }
+ else {
+ break;
+ }
+
+ parent->totnode = (char)(k + 1);
+ }
+}
+
/**
* This functions builds an optimal implicit tree from the given leafs.
* Where optimal stands for:
@@ -787,77 +898,35 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
build_implicit_tree_helper(tree, &data);
+ BVHDivNodesData cb_data = {
+ .tree = tree, .branches_array = branches_array, .leafs_array = leafs_array,
+ .tree_type = tree_type, .tree_offset = tree_offset, .data = &data,
+ .first_of_next_level = 0, .depth = 0, .i = 0,
+ };
+
/* Loop tree levels (log N) loops */
for (i = 1, depth = 1; i <= num_branches; i = i * tree_type + tree_offset, depth++) {
const int first_of_next_level = i * tree_type + tree_offset;
const int end_j = min_ii(first_of_next_level, num_branches + 1); /* index of last branch on this level */
- int j;
/* Loop all branches on this level */
+ cb_data.first_of_next_level = first_of_next_level;
+ cb_data.i = i;
+ cb_data.depth = depth;
-#pragma omp parallel for private(j) schedule(static) if (num_leafs > KDOPBVH_OMP_LIMIT)
- for (j = i; j < end_j; j++) {
- int k;
- const int parent_level_index = j - i;
- BVHNode *parent = branches_array + j;
- int nth_positions[MAX_TREETYPE + 1];
- char split_axis;
-
- int parent_leafs_begin = implicit_leafs_index(&data, depth, parent_level_index);
- int parent_leafs_end = implicit_leafs_index(&data, depth, parent_level_index + 1);
-
- /* This calculates the bounding box of this branch
- * and chooses the largest axis as the axis to divide leafs */
- refit_kdop_hull(tree, parent, parent_leafs_begin, parent_leafs_end);
- split_axis = get_largest_axis(parent->bv);
-
- /* Save split axis (this can be used on raytracing to speedup the query time) */
- parent->main_axis = split_axis / 2;
-
- /* Split the childs along the split_axis, note: its not needed to sort the whole leafs array
- * Only to assure that the elements are partitioned on a way that each child takes the elements
- * it would take in case the whole array was sorted.
- * Split_leafs takes care of that "sort" problem. */
- nth_positions[0] = parent_leafs_begin;
- nth_positions[tree_type] = parent_leafs_end;
- for (k = 1; k < tree_type; k++) {
- int child_index = j * tree_type + tree_offset + k;
- int child_level_index = child_index - first_of_next_level; /* child level index */
- nth_positions[k] = implicit_leafs_index(&data, depth + 1, child_level_index);
- }
-
- split_leafs(leafs_array, nth_positions, tree_type, split_axis);
-
-
- /* Setup children and totnode counters
- * Not really needed but currently most of BVH code relies on having an explicit children structure */
- for (k = 0; k < tree_type; k++) {
- int child_index = j * tree_type + tree_offset + k;
- int child_level_index = child_index - first_of_next_level; /* child level index */
-
- int child_leafs_begin = implicit_leafs_index(&data, depth + 1, child_level_index);
- int child_leafs_end = implicit_leafs_index(&data, depth + 1, child_level_index + 1);
-
- if (child_leafs_end - child_leafs_begin > 1) {
- parent->children[k] = branches_array + child_index;
- parent->children[k]->parent = parent;
- }
- else if (child_leafs_end - child_leafs_begin == 1) {
- parent->children[k] = leafs_array[child_leafs_begin];
- parent->children[k]->parent = parent;
- }
- else {
- break;
- }
-
- parent->totnode = (char)(k + 1);
- }
- }
+ BLI_task_parallel_range(
+ i, end_j, &cb_data, non_recursive_bvh_div_nodes_task_cb,
+ num_leafs > KDOPBVH_THREAD_LEAF_THRESHOLD);
}
}
+/** \} */
+
+
/* -------------------------------------------------------------------- */
-/* BLI_bvhtree api */
+
+/** \name BLI_bvhtree API
+ * \{ */
/**
* \note many callers don't check for ``NULL`` return.
@@ -1051,9 +1120,13 @@ float BLI_bvhtree_getepsilon(const BVHTree *tree)
return tree->epsilon;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* BLI_bvhtree_overlap */
+
+/** \name BLI_bvhtree_overlap
+ * \{ */
/**
* overlap - is it possible for 2 bv's to collide ?
@@ -1172,6 +1245,23 @@ int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode);
}
+static void bvhtree_overlap_task_cb(void *userdata, const int j)
+{
+ BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
+ BVHOverlapData_Shared *data_shared = data->shared;
+
+ if (data_shared->callback) {
+ tree_overlap_traverse_cb(
+ data, data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+ }
+ else {
+ tree_overlap_traverse(
+ data, data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+ }
+}
+
BVHTreeOverlap *BLI_bvhtree_overlap(
const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_tot,
/* optional callback to test the overlap before adding (must be thread-safe!) */
@@ -1220,15 +1310,9 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
data[j].thread = j;
}
-#pragma omp parallel for private(j) schedule(static) if (tree1->totleaf > KDOPBVH_OMP_LIMIT)
- for (j = 0; j < thread_num; j++) {
- if (callback) {
- tree_overlap_traverse_cb(&data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
- }
- else {
- tree_overlap_traverse(&data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
- }
- }
+ BLI_task_parallel_range(
+ 0, thread_num, data, bvhtree_overlap_task_cb,
+ tree1->totleaf > KDOPBVH_THREAD_LEAF_THRESHOLD);
for (j = 0; j < thread_num; j++)
total += BLI_stack_count(data[j].overlap);
@@ -1246,6 +1330,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
return overlap;
}
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name BLI_bvhtree_find_nearest
+ * \{ */
+
/* Determines the nearest point of the given node BV. Returns the squared distance to that point. */
static float calc_nearest_point_squared(const float proj[3], BVHNode *node, float nearest[3])
{
@@ -1266,15 +1358,15 @@ static float calc_nearest_point_squared(const float proj[3], BVHNode *node, floa
/* nearest on a general hull */
copy_v3_v3(nearest, data->co);
for (i = data->tree->start_axis; i != data->tree->stop_axis; i++, bv += 2) {
- float proj = dot_v3v3(nearest, KDOP_AXES[i]);
+ float proj = dot_v3v3(nearest, bvhtree_kdop_axes[i]);
float dl = bv[0] - proj;
float du = bv[1] - proj;
if (dl > 0) {
- madd_v3_v3fl(nearest, KDOP_AXES[i], dl);
+ madd_v3_v3fl(nearest, bvhtree_kdop_axes[i], dl);
}
else if (du < 0) {
- madd_v3_v3fl(nearest, KDOP_AXES[i], du);
+ madd_v3_v3fl(nearest, bvhtree_kdop_axes[i], du);
}
}
#endif
@@ -1352,7 +1444,7 @@ POP_HEAP_BODY(NodeDistance, NodeDistance_priority, heap, heap_size)
* It may make sense to use this function if the callback queries are very slow.. or if its impossible
* to get a nice heuristic
*
- * this function uses "malloc/free" instead of the MEM_* because it intends to be openmp safe */
+ * this function uses "malloc/free" instead of the MEM_* because it intends to be thread safe */
static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
{
int i;
@@ -1420,8 +1512,9 @@ static void bfs_find_nearest(BVHNearestData *data, BVHNode *node)
#endif
-int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
- BVHTree_NearestPointCallback callback, void *userdata)
+int BLI_bvhtree_find_nearest(
+ BVHTree *tree, const float co[3], BVHTreeNearest *nearest,
+ BVHTree_NearestPointCallback callback, void *userdata)
{
axis_t axis_iter;
@@ -1436,7 +1529,7 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *n
data.userdata = userdata;
for (axis_iter = data.tree->start_axis; axis_iter != data.tree->stop_axis; axis_iter++) {
- data.proj[axis_iter] = dot_v3v3(data.co, KDOP_AXES[axis_iter]);
+ data.proj[axis_iter] = dot_v3v3(data.co, bvhtree_kdop_axes[axis_iter]);
}
if (nearest) {
@@ -1459,12 +1552,16 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *n
return data.nearest.index;
}
+/** \} */
-/**
- * Raycast - BLI_bvhtree_ray_cast
+
+/* -------------------------------------------------------------------- */
+
+/** \name BLI_bvhtree_ray_cast
*
- * raycast is done by performing a DFS on the BVHTree and saving the closest hit
- */
+ * raycast is done by performing a DFS on the BVHTree and saving the closest hit.
+ *
+ * \{ */
/* Determines the distance that the ray must travel to hit the bounding volume of the given node */
@@ -1577,7 +1674,7 @@ static void dfs_raycast_all(BVHRayCastData *data, BVHNode *node)
if (node->totnode == 0) {
if (data->callback) {
data->hit.index = -1;
- data->hit.dist = FLT_MAX;
+ data->hit.dist = BVH_RAYCAST_DIST_MAX;
data->callback(data->userdata, node->index, &data->ray, &data->hit);
}
else {
@@ -1635,7 +1732,7 @@ static void bvhtree_ray_cast_data_precalc(BVHRayCastData *data, int flag)
int i;
for (i = 0; i < 3; i++) {
- data->ray_dot_axis[i] = dot_v3v3(data->ray.direction, KDOP_AXES[i]);
+ data->ray_dot_axis[i] = dot_v3v3(data->ray.direction, bvhtree_kdop_axes[i]);
data->idot_axis[i] = 1.0f / data->ray_dot_axis[i];
if (fabsf(data->ray_dot_axis[i]) < FLT_EPSILON) {
@@ -1686,7 +1783,7 @@ int BLI_bvhtree_ray_cast_ex(
}
else {
data.hit.index = -1;
- data.hit.dist = FLT_MAX;
+ data.hit.dist = BVH_RAYCAST_DIST_MAX;
}
if (root) {
@@ -1713,7 +1810,7 @@ float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], cons
BVHRayCastData data;
float dist;
- data.hit.dist = FLT_MAX;
+ data.hit.dist = BVH_RAYCAST_DIST_MAX;
/* get light direction */
sub_v3_v3v3(data.ray.direction, light_end, light_start);
@@ -1758,7 +1855,7 @@ int BLI_bvhtree_ray_cast_all_ex(
bvhtree_ray_cast_data_precalc(&data, flag);
data.hit.index = -1;
- data.hit.dist = FLT_MAX;
+ data.hit.dist = BVH_RAYCAST_DIST_MAX;
if (root) {
dfs_raycast_all(&data, root);
@@ -1774,12 +1871,112 @@ int BLI_bvhtree_ray_cast_all(
return BLI_bvhtree_ray_cast_all_ex(tree, co, dir, radius, callback, userdata, BVH_RAYCAST_DEFAULT);
}
-/**
- * Range Query - as request by broken :P
+
+/* -------------------------------------------------------------------- */
+
+/** \name BLI_bvhtree_find_nearest_to_ray
+ *
+ * \{ */
+
+static float calc_dist_sq_to_ray(BVHNearestRayData *data, BVHNode *node)
+{
+ const float *bv = node->bv;
+ const float bb_min[3] = {bv[0], bv[2], bv[4]};
+ const float bb_max[3] = {bv[1], bv[3], bv[5]};
+ return dist_squared_ray_to_aabb_v3(&data->nearest_precalc, bb_min, bb_max, data->pick_smallest);
+}
+
+static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node)
+{
+ if (node->totnode == 0) {
+ if (data->callback) {
+ data->callback(data->userdata, node->index, &data->ray, &data->nearest);
+ }
+ else {
+ const float dist_sq = calc_dist_sq_to_ray(data, node);
+ if (dist_sq != FLT_MAX) { /* not an invalid ray */
+ data->nearest.index = node->index;
+ data->nearest.dist_sq = dist_sq;
+ /* TODO: return a value to the data->nearest.co
+ * not urgent however since users currently define own callbacks */
+ }
+ }
+ }
+ else {
+ int i;
+ /* First pick the closest node to dive on */
+ if (data->pick_smallest[node->main_axis]) {
+ for (i = 0; i != node->totnode; i++) {
+ if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) {
+ continue;
+ }
+ dfs_find_nearest_to_ray_dfs(data, node->children[i]);
+ }
+ }
+ else {
+ for (i = node->totnode - 1; i >= 0; i--) {
+ if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) {
+ continue;
+ }
+ dfs_find_nearest_to_ray_dfs(data, node->children[i]);
+ }
+ }
+ }
+}
+
+int BLI_bvhtree_find_nearest_to_ray(
+ BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest,
+ BVHTree_NearestToRayCallback callback, void *userdata)
+{
+ BVHNearestRayData data;
+ BVHNode *root = tree->nodes[tree->totleaf];
+
+ data.tree = tree;
+
+ data.callback = callback;
+ data.userdata = userdata;
+
+ copy_v3_v3(data.ray.origin, co);
+ copy_v3_v3(data.ray.direction, dir);
+ data.ray.radius = 0.0f; /* unused here */
+
+ dist_squared_ray_to_aabb_v3_precalc(&data.nearest_precalc, co, dir);
+
+ if (nearest) {
+ memcpy(&data.nearest, nearest, sizeof(*nearest));
+ }
+ else {
+ data.nearest.index = -1;
+ data.nearest.dist_sq = FLT_MAX;
+ }
+
+ /* dfs search */
+ if (root) {
+ if (calc_dist_sq_to_ray(&data, root) < data.nearest.dist_sq) {
+ dfs_find_nearest_to_ray_dfs(&data, root);
+ }
+ }
+
+ /* copy back results */
+ if (nearest) {
+ memcpy(nearest, &data.nearest, sizeof(*nearest));
+ }
+
+ return data.nearest.index;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name BLI_bvhtree_range_query
*
- * Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius)
+ * Allocs and fills an array with the indexs of node that are on the given spherical range (center, radius).
* Returns the size of the array.
- */
+ *
+ * \{ */
+
typedef struct RangeQueryData {
BVHTree *tree;
const float *center;
@@ -1789,8 +1986,6 @@ typedef struct RangeQueryData {
BVHTree_RangeQuery callback;
void *userdata;
-
-
} RangeQueryData;
@@ -1814,7 +2009,7 @@ static void dfs_range_query(RangeQueryData *data, BVHNode *node)
/* Its a leaf.. call the callback */
if (node->children[i]->totnode == 0) {
data->hits++;
- data->callback(data->userdata, node->children[i]->index, dist_sq);
+ data->callback(data->userdata, node->children[i]->index, data->center, dist_sq);
}
else
dfs_range_query(data, node->children[i]);
@@ -1823,7 +2018,9 @@ static void dfs_range_query(RangeQueryData *data, BVHNode *node)
}
}
-int BLI_bvhtree_range_query(BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata)
+int BLI_bvhtree_range_query(
+ BVHTree *tree, const float co[3], float radius,
+ BVHTree_RangeQuery callback, void *userdata)
{
BVHNode *root = tree->nodes[tree->totleaf];
@@ -1843,7 +2040,7 @@ int BLI_bvhtree_range_query(BVHTree *tree, const float co[3], float radius, BVHT
/* Its a leaf.. call the callback */
if (root->totnode == 0) {
data.hits++;
- data.callback(data.userdata, root->index, dist_sq);
+ data.callback(data.userdata, root->index, co, dist_sq);
}
else
dfs_range_query(&data, root);
@@ -1852,3 +2049,84 @@ int BLI_bvhtree_range_query(BVHTree *tree, const float co[3], float radius, BVHT
return data.hits;
}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name BLI_bvhtree_walk_dfs
+ * \{ */
+
+/**
+ * Runs first among nodes children of the first node before going to the next node in the same layer.
+ *
+ * \return false to break out of the search early.
+ */
+static bool bvhtree_walk_dfs_recursive(
+ BVHTree_WalkParentCallback walk_parent_cb,
+ BVHTree_WalkLeafCallback walk_leaf_cb,
+ BVHTree_WalkOrderCallback walk_order_cb,
+ const BVHNode *node, void *userdata)
+{
+ if (node->totnode == 0) {
+ return walk_leaf_cb((const BVHTreeAxisRange *)node->bv, node->index, userdata);
+ }
+ else {
+ /* First pick the closest node to recurse into */
+ if (walk_order_cb((const BVHTreeAxisRange *)node->bv, node->main_axis, userdata)) {
+ for (int i = 0; i != node->totnode; i++) {
+ if (walk_parent_cb((const BVHTreeAxisRange *)node->children[i]->bv, userdata)) {
+ if (!bvhtree_walk_dfs_recursive(
+ walk_parent_cb, walk_leaf_cb, walk_order_cb,
+ node->children[i], userdata))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ else {
+ for (int i = node->totnode - 1; i >= 0; i--) {
+ if (walk_parent_cb((const BVHTreeAxisRange *)node->children[i]->bv, userdata)) {
+ if (!bvhtree_walk_dfs_recursive(
+ walk_parent_cb, walk_leaf_cb, walk_order_cb,
+ node->children[i], userdata))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * This is a generic function to perform a depth first search on the BVHTree
+ * where the search order and nodes traversed depend on callbacks passed in.
+ *
+ * \param tree: Tree to walk.
+ * \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
+ * \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
+ * returning false exits early.
+ * \param walk_order_cb: Callback that indicates which direction to search,
+ * either from the node with the lower or higher k-dop axis value.
+ * \param userdata: Argument passed to all callbacks.
+ */
+void BLI_bvhtree_walk_dfs(
+ BVHTree *tree,
+ BVHTree_WalkParentCallback walk_parent_cb,
+ BVHTree_WalkLeafCallback walk_leaf_cb,
+ BVHTree_WalkOrderCallback walk_order_cb, void *userdata)
+{
+ const BVHNode *root = tree->nodes[tree->totleaf];
+ if (root != NULL) {
+ /* first make sure the bv of root passes in the test too */
+ if (walk_parent_cb((const BVHTreeAxisRange *)root->bv, userdata)) {
+ bvhtree_walk_dfs_recursive(walk_parent_cb, walk_leaf_cb, walk_order_cb, root, userdata);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c
index bf470d88578..a81f9b28b83 100644
--- a/source/blender/blenlib/intern/BLI_kdtree.c
+++ b/source/blender/blenlib/intern/BLI_kdtree.c
@@ -32,9 +32,14 @@
#include "BLI_utildefines.h"
#include "BLI_strict_flags.h"
+typedef struct KDTreeNode_head {
+ unsigned int left, right;
+ float co[3];
+ int index;
+} KDTreeNode_head;
typedef struct KDTreeNode {
- struct KDTreeNode *left, *right;
+ unsigned int left, right;
float co[3];
int index;
unsigned int d; /* range is only (0-2) */
@@ -43,7 +48,7 @@ typedef struct KDTreeNode {
struct KDTree {
KDTreeNode *nodes;
unsigned int totnode;
- KDTreeNode *root;
+ unsigned int root;
#ifdef DEBUG
bool is_balanced; /* ensure we call balance first */
unsigned int maxsize; /* max size of the tree */
@@ -54,6 +59,8 @@ struct KDTree {
#define KD_NEAR_ALLOC_INC 100 /* alloc increment for collecting nearest */
#define KD_FOUND_ALLOC_INC 50 /* alloc increment for collecting nearest */
+#define KD_NODE_UNSET ((unsigned int)-1)
+
/**
* Creates or free a kdtree
*/
@@ -64,7 +71,7 @@ KDTree *BLI_kdtree_new(unsigned int maxsize)
tree = MEM_mallocN(sizeof(KDTree), "KDTree");
tree->nodes = MEM_mallocN(sizeof(KDTreeNode) * maxsize, "KDTreeNode");
tree->totnode = 0;
- tree->root = NULL;
+ tree->root = KD_NODE_UNSET;
#ifdef DEBUG
tree->is_balanced = false;
@@ -96,7 +103,7 @@ void BLI_kdtree_insert(KDTree *tree, int index, const float co[3])
/* note, array isn't calloc'd,
* need to initialize all struct members */
- node->left = node->right = NULL;
+ node->left = node->right = KD_NODE_UNSET;
copy_v3_v3(node->co, co);
node->index = index;
node->d = 0;
@@ -106,16 +113,16 @@ void BLI_kdtree_insert(KDTree *tree, int index, const float co[3])
#endif
}
-static KDTreeNode *kdtree_balance(KDTreeNode *nodes, unsigned int totnode, unsigned int axis)
+static unsigned int kdtree_balance(KDTreeNode *nodes, unsigned int totnode, unsigned int axis, const unsigned int ofs)
{
KDTreeNode *node;
float co;
unsigned int left, right, median, i, j;
if (totnode <= 0)
- return NULL;
+ return KD_NODE_UNSET;
else if (totnode == 1)
- return nodes;
+ return 0 + ofs;
/* quicksort style sorting around median */
left = 0;
@@ -134,10 +141,10 @@ static KDTreeNode *kdtree_balance(KDTreeNode *nodes, unsigned int totnode, unsig
if (i >= j)
break;
- SWAP(KDTreeNode, nodes[i], nodes[j]);
+ SWAP(KDTreeNode_head, *(KDTreeNode_head *)&nodes[i], *(KDTreeNode_head *)&nodes[j]);
}
- SWAP(KDTreeNode, nodes[i], nodes[right]);
+ SWAP(KDTreeNode_head, *(KDTreeNode_head *)&nodes[i], *(KDTreeNode_head *)&nodes[right]);
if (i >= median)
right = i - 1;
if (i <= median)
@@ -147,15 +154,16 @@ static KDTreeNode *kdtree_balance(KDTreeNode *nodes, unsigned int totnode, unsig
/* set node and sort subnodes */
node = &nodes[median];
node->d = axis;
- node->left = kdtree_balance(nodes, median, (axis + 1) % 3);
- node->right = kdtree_balance(nodes + median + 1, (totnode - (median + 1)), (axis + 1) % 3);
+ axis = (axis + 1) % 3;
+ node->left = kdtree_balance(nodes, median, axis, ofs);
+ node->right = kdtree_balance(nodes + median + 1, (totnode - (median + 1)), axis, (median + 1) + ofs);
- return node;
+ return median + ofs;
}
void BLI_kdtree_balance(KDTree *tree)
{
- tree->root = kdtree_balance(tree->nodes, tree->totnode, 0);
+ tree->root = kdtree_balance(tree->nodes, tree->totnode, 0, 0);
#ifdef DEBUG
tree->is_balanced = true;
@@ -180,11 +188,11 @@ static float squared_distance(const float v2[3], const float v1[3], const float
return dist;
}
-static KDTreeNode **realloc_nodes(KDTreeNode **stack, unsigned int *totstack, const bool is_alloc)
+static unsigned int *realloc_nodes(unsigned int *stack, unsigned int *totstack, const bool is_alloc)
{
- KDTreeNode **stack_new = MEM_mallocN((*totstack + KD_NEAR_ALLOC_INC) * sizeof(KDTreeNode *), "KDTree.treestack");
- memcpy(stack_new, stack, *totstack * sizeof(KDTreeNode *));
- // memset(stack_new + *totstack, 0, sizeof(KDTreeNode *) * KD_NEAR_ALLOC_INC);
+ unsigned int *stack_new = MEM_mallocN((*totstack + KD_NEAR_ALLOC_INC) * sizeof(unsigned int), "KDTree.treestack");
+ memcpy(stack_new, stack, *totstack * sizeof(unsigned int));
+ // memset(stack_new + *totstack, 0, sizeof(unsigned int) * KD_NEAR_ALLOC_INC);
if (is_alloc)
MEM_freeN(stack);
*totstack += KD_NEAR_ALLOC_INC;
@@ -195,11 +203,12 @@ static KDTreeNode **realloc_nodes(KDTreeNode **stack, unsigned int *totstack, co
* Find nearest returns index, and -1 if no node is found.
*/
int BLI_kdtree_find_nearest(
- KDTree *tree, const float co[3],
+ const KDTree *tree, const float co[3],
KDTreeNearest *r_nearest)
{
- KDTreeNode *root, *node, *min_node;
- KDTreeNode **stack, *defaultstack[KD_STACK_INIT];
+ const KDTreeNode *nodes = tree->nodes;
+ const KDTreeNode *root, *min_node;
+ unsigned int *stack, defaultstack[KD_STACK_INIT];
float min_dist, cur_dist;
unsigned int totstack, cur = 0;
@@ -207,31 +216,31 @@ int BLI_kdtree_find_nearest(
BLI_assert(tree->is_balanced == true);
#endif
- if (UNLIKELY(!tree->root))
+ if (UNLIKELY(tree->root == KD_NODE_UNSET))
return -1;
stack = defaultstack;
totstack = KD_STACK_INIT;
- root = tree->root;
+ root = &nodes[tree->root];
min_node = root;
min_dist = len_squared_v3v3(root->co, co);
if (co[root->d] < root->co[root->d]) {
- if (root->right)
+ if (root->right != KD_NODE_UNSET)
stack[cur++] = root->right;
- if (root->left)
+ if (root->left != KD_NODE_UNSET)
stack[cur++] = root->left;
}
else {
- if (root->left)
+ if (root->left != KD_NODE_UNSET)
stack[cur++] = root->left;
- if (root->right)
+ if (root->right != KD_NODE_UNSET)
stack[cur++] = root->right;
}
while (cur--) {
- node = stack[cur];
+ const KDTreeNode *node = &nodes[stack[cur]];
cur_dist = node->co[node->d] - co[node->d];
@@ -244,10 +253,10 @@ int BLI_kdtree_find_nearest(
min_dist = cur_dist;
min_node = node;
}
- if (node->left)
+ if (node->left != KD_NODE_UNSET)
stack[cur++] = node->left;
}
- if (node->right)
+ if (node->right != KD_NODE_UNSET)
stack[cur++] = node->right;
}
else {
@@ -259,10 +268,10 @@ int BLI_kdtree_find_nearest(
min_dist = cur_dist;
min_node = node;
}
- if (node->right)
+ if (node->right != KD_NODE_UNSET)
stack[cur++] = node->right;
}
- if (node->left)
+ if (node->left != KD_NODE_UNSET)
stack[cur++] = node->left;
}
if (UNLIKELY(cur + 3 > totstack)) {
@@ -282,6 +291,112 @@ int BLI_kdtree_find_nearest(
return min_node->index;
}
+
+/**
+ * A version of #BLI_kdtree_find_nearest which runs a callback
+ * to filter out values.
+ *
+ * \param filter_cb: Filter find results,
+ * Return codes: (1: accept, 0: skip, -1: immediate exit).
+ */
+int BLI_kdtree_find_nearest_cb(
+ const KDTree *tree, const float co[3],
+ int (*filter_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data,
+ KDTreeNearest *r_nearest)
+{
+ const KDTreeNode *nodes = tree->nodes;
+ const KDTreeNode *min_node = NULL;
+
+ unsigned int *stack, defaultstack[KD_STACK_INIT];
+ float min_dist = FLT_MAX, cur_dist;
+ unsigned int totstack, cur = 0;
+
+#ifdef DEBUG
+ BLI_assert(tree->is_balanced == true);
+#endif
+
+ if (UNLIKELY(tree->root == KD_NODE_UNSET))
+ return -1;
+
+ stack = defaultstack;
+ totstack = KD_STACK_INIT;
+
+#define NODE_TEST_NEAREST(node) \
+{ \
+ const float dist_sq = len_squared_v3v3((node)->co, co); \
+ if (dist_sq < min_dist) { \
+ const int result = filter_cb(user_data, (node)->index, (node)->co, dist_sq); \
+ if (result == 1) { \
+ min_dist = dist_sq; \
+ min_node = node; \
+ } \
+ else if (result == 0) { \
+ /* pass */ \
+ } \
+ else { \
+ BLI_assert(result == -1); \
+ goto finally; \
+ } \
+ } \
+} ((void)0)
+
+ stack[cur++] = tree->root;
+
+ while (cur--) {
+ const KDTreeNode *node = &nodes[stack[cur]];
+
+ cur_dist = node->co[node->d] - co[node->d];
+
+ if (cur_dist < 0.0f) {
+ cur_dist = -cur_dist * cur_dist;
+
+ if (-cur_dist < min_dist) {
+ NODE_TEST_NEAREST(node);
+
+ if (node->left != KD_NODE_UNSET)
+ stack[cur++] = node->left;
+ }
+ if (node->right != KD_NODE_UNSET)
+ stack[cur++] = node->right;
+ }
+ else {
+ cur_dist = cur_dist * cur_dist;
+
+ if (cur_dist < min_dist) {
+ NODE_TEST_NEAREST(node);
+
+ if (node->right != KD_NODE_UNSET)
+ stack[cur++] = node->right;
+ }
+ if (node->left != KD_NODE_UNSET)
+ stack[cur++] = node->left;
+ }
+ if (UNLIKELY(cur + 3 > totstack)) {
+ stack = realloc_nodes(stack, &totstack, defaultstack != stack);
+ }
+ }
+
+#undef NODE_TEST_NEAREST
+
+
+finally:
+ if (stack != defaultstack)
+ MEM_freeN(stack);
+
+ if (min_node) {
+ if (r_nearest) {
+ r_nearest->index = min_node->index;
+ r_nearest->dist = sqrtf(min_dist);
+ copy_v3_v3(r_nearest->co, min_node->co);
+ }
+
+ return min_node->index;
+ }
+ else {
+ return -1;
+ }
+}
+
static void add_nearest(KDTreeNearest *ptn, unsigned int *found, unsigned int n, int index,
float dist, const float *co)
{
@@ -308,12 +423,13 @@ static void add_nearest(KDTreeNearest *ptn, unsigned int *found, unsigned int n,
* \param r_nearest An array of nearest, sized at least \a n.
*/
int BLI_kdtree_find_nearest_n__normal(
- KDTree *tree, const float co[3], const float nor[3],
+ const KDTree *tree, const float co[3], const float nor[3],
KDTreeNearest r_nearest[],
unsigned int n)
{
- KDTreeNode *root, *node = NULL;
- KDTreeNode **stack, *defaultstack[KD_STACK_INIT];
+ const KDTreeNode *nodes = tree->nodes;
+ const KDTreeNode *root;
+ unsigned int *stack, defaultstack[KD_STACK_INIT];
float cur_dist;
unsigned int totstack, cur = 0;
unsigned int i, found = 0;
@@ -322,32 +438,32 @@ int BLI_kdtree_find_nearest_n__normal(
BLI_assert(tree->is_balanced == true);
#endif
- if (UNLIKELY(!tree->root || n == 0))
+ if (UNLIKELY((tree->root == KD_NODE_UNSET) || n == 0))
return 0;
stack = defaultstack;
totstack = KD_STACK_INIT;
- root = tree->root;
+ root = &nodes[tree->root];
cur_dist = squared_distance(root->co, co, nor);
add_nearest(r_nearest, &found, n, root->index, cur_dist, root->co);
if (co[root->d] < root->co[root->d]) {
- if (root->right)
+ if (root->right != KD_NODE_UNSET)
stack[cur++] = root->right;
- if (root->left)
+ if (root->left != KD_NODE_UNSET)
stack[cur++] = root->left;
}
else {
- if (root->left)
+ if (root->left != KD_NODE_UNSET)
stack[cur++] = root->left;
- if (root->right)
+ if (root->right != KD_NODE_UNSET)
stack[cur++] = root->right;
}
while (cur--) {
- node = stack[cur];
+ const KDTreeNode *node = &nodes[stack[cur]];
cur_dist = node->co[node->d] - co[node->d];
@@ -360,10 +476,10 @@ int BLI_kdtree_find_nearest_n__normal(
if (found < n || cur_dist < r_nearest[found - 1].dist)
add_nearest(r_nearest, &found, n, node->index, cur_dist, node->co);
- if (node->left)
+ if (node->left != KD_NODE_UNSET)
stack[cur++] = node->left;
}
- if (node->right)
+ if (node->right != KD_NODE_UNSET)
stack[cur++] = node->right;
}
else {
@@ -374,10 +490,10 @@ int BLI_kdtree_find_nearest_n__normal(
if (found < n || cur_dist < r_nearest[found - 1].dist)
add_nearest(r_nearest, &found, n, node->index, cur_dist, node->co);
- if (node->right)
+ if (node->right != KD_NODE_UNSET)
stack[cur++] = node->right;
}
- if (node->left)
+ if (node->left != KD_NODE_UNSET)
stack[cur++] = node->left;
}
if (UNLIKELY(cur + 3 > totstack)) {
@@ -434,65 +550,47 @@ static void add_in_range(
* Remember to free nearest after use!
*/
int BLI_kdtree_range_search__normal(
- KDTree *tree, const float co[3], const float nor[3],
+ const KDTree *tree, const float co[3], const float nor[3],
KDTreeNearest **r_nearest, float range)
{
- KDTreeNode *root, *node = NULL;
- KDTreeNode **stack, *defaultstack[KD_STACK_INIT];
+ const KDTreeNode *nodes = tree->nodes;
+ unsigned int *stack, defaultstack[KD_STACK_INIT];
KDTreeNearest *foundstack = NULL;
- float range2 = range * range, dist2;
+ float range_sq = range * range, dist_sq;
unsigned int totstack, cur = 0, found = 0, totfoundstack = 0;
#ifdef DEBUG
BLI_assert(tree->is_balanced == true);
#endif
- if (UNLIKELY(!tree->root))
+ if (UNLIKELY(tree->root == KD_NODE_UNSET))
return 0;
stack = defaultstack;
totstack = KD_STACK_INIT;
- root = tree->root;
-
- if (co[root->d] + range < root->co[root->d]) {
- if (root->left)
- stack[cur++] = root->left;
- }
- else if (co[root->d] - range > root->co[root->d]) {
- if (root->right)
- stack[cur++] = root->right;
- }
- else {
- dist2 = squared_distance(root->co, co, nor);
- if (dist2 <= range2)
- add_in_range(&foundstack, &totfoundstack, found++, root->index, dist2, root->co);
-
- if (root->left)
- stack[cur++] = root->left;
- if (root->right)
- stack[cur++] = root->right;
- }
+ stack[cur++] = tree->root;
while (cur--) {
- node = stack[cur];
+ const KDTreeNode *node = &nodes[stack[cur]];
if (co[node->d] + range < node->co[node->d]) {
- if (node->left)
+ if (node->left != KD_NODE_UNSET)
stack[cur++] = node->left;
}
else if (co[node->d] - range > node->co[node->d]) {
- if (node->right)
+ if (node->right != KD_NODE_UNSET)
stack[cur++] = node->right;
}
else {
- dist2 = squared_distance(node->co, co, nor);
- if (dist2 <= range2)
- add_in_range(&foundstack, &totfoundstack, found++, node->index, dist2, node->co);
+ dist_sq = squared_distance(node->co, co, nor);
+ if (dist_sq <= range_sq) {
+ add_in_range(&foundstack, &totfoundstack, found++, node->index, dist_sq, node->co);
+ }
- if (node->left)
+ if (node->left != KD_NODE_UNSET)
stack[cur++] = node->left;
- if (node->right)
+ if (node->right != KD_NODE_UNSET)
stack[cur++] = node->right;
}
@@ -511,3 +609,68 @@ int BLI_kdtree_range_search__normal(
return (int)found;
}
+
+/**
+ * A version of #BLI_kdtree_range_search which runs a callback
+ * instead of allocating an array.
+ *
+ * \param search_cb: Called for every node found in \a range, false return value performs an early exit.
+ *
+ * \note the order of calls isn't sorted based on distance.
+ */
+void BLI_kdtree_range_search_cb(
+ const KDTree *tree, const float co[3], float range,
+ bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data)
+{
+ const KDTreeNode *nodes = tree->nodes;
+
+ unsigned int *stack, defaultstack[KD_STACK_INIT];
+ float range_sq = range * range, dist_sq;
+ unsigned int totstack, cur = 0;
+
+#ifdef DEBUG
+ BLI_assert(tree->is_balanced == true);
+#endif
+
+ if (UNLIKELY(tree->root == KD_NODE_UNSET))
+ return;
+
+ stack = defaultstack;
+ totstack = KD_STACK_INIT;
+
+ stack[cur++] = tree->root;
+
+ while (cur--) {
+ const KDTreeNode *node = &nodes[stack[cur]];
+
+ if (co[node->d] + range < node->co[node->d]) {
+ if (node->left != KD_NODE_UNSET)
+ stack[cur++] = node->left;
+ }
+ else if (co[node->d] - range > node->co[node->d]) {
+ if (node->right != KD_NODE_UNSET)
+ stack[cur++] = node->right;
+ }
+ else {
+ dist_sq = len_squared_v3v3(node->co, co);
+ if (dist_sq <= range_sq) {
+ if (search_cb(user_data, node->index, node->co, dist_sq) == false) {
+ goto finally;
+ }
+ }
+
+ if (node->left != KD_NODE_UNSET)
+ stack[cur++] = node->left;
+ if (node->right != KD_NODE_UNSET)
+ stack[cur++] = node->right;
+ }
+
+ if (UNLIKELY(cur + 3 > totstack)) {
+ stack = realloc_nodes(stack, &totstack, defaultstack != stack);
+ }
+ }
+
+finally:
+ if (stack != defaultstack)
+ MEM_freeN(stack);
+}
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 1da39967945..1500e23d72e 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -41,7 +41,7 @@
#include "BLI_strict_flags.h"
-int BLI_linklist_count(LinkNode *list)
+int BLI_linklist_count(const LinkNode *list)
{
int len;
@@ -51,7 +51,7 @@ int BLI_linklist_count(LinkNode *list)
return len;
}
-int BLI_linklist_index(LinkNode *list, void *ptr)
+int BLI_linklist_index(const LinkNode *list, void *ptr)
{
int index;
diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c
index cef912e42a3..52ca835876e 100644
--- a/source/blender/blenlib/intern/array_utils.c
+++ b/source/blender/blenlib/intern/array_utils.c
@@ -142,3 +142,31 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid
}
return -1;
}
+
+void _bli_array_binary_and(
+ void *arr, const void *arr_a, const void *arr_b,
+ unsigned int arr_len, size_t arr_stride)
+{
+ char *dst = arr;
+ const char *src_a = arr_a;
+ const char *src_b = arr_b;
+
+ size_t i = arr_stride * arr_len;
+ while (i--) {
+ *(dst++) = *(src_a++) & *(src_b++);
+ }
+}
+
+void _bli_array_binary_or(
+ void *arr, const void *arr_a, const void *arr_b,
+ unsigned int arr_len, size_t arr_stride)
+{
+ char *dst = arr;
+ const char *src_a = arr_a;
+ const char *src_b = arr_b;
+
+ size_t i = arr_stride * arr_len;
+ while (i--) {
+ *(dst++) = *(src_a++) | *(src_b++);
+ }
+} \ No newline at end of file
diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c
index 9e96205a5e8..a54fc2428fe 100644
--- a/source/blender/blenlib/intern/buffer.c
+++ b/source/blender/blenlib/intern/buffer.c
@@ -20,30 +20,51 @@
/** \file blender/blenlib/intern/buffer.c
* \ingroup bli
+ *
+ * Primitive generic buffer library.
+ *
+ * - Automatically grow as needed.
+ * (currently never shrinks).
+ * - Can be passed between functions.
+ * - Supports using stack memory by default,
+ * falling back to heap as needed.
+ *
+ * Usage examples:
+ * \code{.c}
+ * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32);
+ *
+ * BLI_buffer_append(my_int_array, int, 42);
+ * assert(my_int_array.count == 1);
+ * assert(BLI_buffer_at(my_int_array, int, 0) == 42);
+ *
+ * BLI_buffer_free(&my_int_array);
+ * \endcode
+ *
+ * \note this more or less fills same purpose as #BLI_array,
+ * but supports resizing the array outside of the function
+ * it was declared in.
*/
+#include <string.h>
+
#include "MEM_guardedalloc.h"
#include "BLI_buffer.h"
#include "BLI_utildefines.h"
-#include <string.h>
+#include "BLI_strict_flags.h"
-static void *buffer_alloc(BLI_Buffer *buffer, int len)
+static void *buffer_alloc(BLI_Buffer *buffer, const size_t len)
{
- return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ?
- MEM_callocN : MEM_mallocN)
- (buffer->elem_size * len, "BLI_Buffer.data");
+ return MEM_mallocN(buffer->elem_size * len, "BLI_Buffer.data");
}
-static void *buffer_realloc(BLI_Buffer *buffer, int len)
+static void *buffer_realloc(BLI_Buffer *buffer, const size_t len)
{
- return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ?
- MEM_recallocN_id : MEM_reallocN_id)
- (buffer->data, buffer->elem_size * len, "BLI_Buffer.data");
+ return MEM_reallocN_id(buffer->data, buffer->elem_size * len, "BLI_Buffer.data");
}
-void BLI_buffer_resize(BLI_Buffer *buffer, int new_count)
+void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count)
{
if (UNLIKELY(new_count > buffer->alloc_count)) {
if (buffer->flag & BLI_BUFFER_USE_STATIC) {
@@ -69,6 +90,34 @@ void BLI_buffer_resize(BLI_Buffer *buffer, int new_count)
buffer->count = new_count;
}
+/**
+ * Similar to #BLI_buffer_resize, but use when the existing data can be:
+ * - Ignored (malloc'd)
+ * - Cleared (when BLI_BUFFER_USE_CALLOC is set)
+ */
+void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
+{
+ if (UNLIKELY(new_count > buffer->alloc_count)) {
+ if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) {
+ if (buffer->data) {
+ MEM_freeN(buffer->data);
+ }
+ }
+
+ if (buffer->alloc_count && (new_count < buffer->alloc_count * 2)) {
+ buffer->alloc_count *= 2;
+ }
+ else {
+ buffer->alloc_count = new_count;
+ }
+
+ buffer->flag &= ~BLI_BUFFER_USE_STATIC;
+ buffer->data = buffer_alloc(buffer, buffer->alloc_count);
+ }
+
+ buffer->count = new_count;
+}
+
/* callers use BLI_buffer_free */
void _bli_buffer_free(BLI_Buffer *buffer)
{
diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c
index e916b01e859..b47c2ee60a6 100644
--- a/source/blender/blenlib/intern/dynlib.c
+++ b/source/blender/blenlib/intern/dynlib.c
@@ -42,8 +42,9 @@ struct DynamicLibrary {
};
#ifdef WIN32
-
+#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x501 /* Windows XP or newer */
+#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "utf_winfunc.h"
diff --git a/source/blender/blenlib/intern/easing.c b/source/blender/blenlib/intern/easing.c
index 90c8528338e..93c3cad904c 100644
--- a/source/blender/blenlib/intern/easing.c
+++ b/source/blender/blenlib/intern/easing.c
@@ -330,7 +330,7 @@ float BLI_easing_quint_ease_out(float time, float begin, float change, float dur
float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
{
if ((time /= duration / 2) < 1.0f)
- return change / 2 * time * time * time * time * time + begin;
+ return change / 2 * time * time * time * time * time + begin;
time -= 2.0f;
return change / 2 * (time * time * time * time * time + 2) + begin;
}
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index cde4a8bf59d..358b5b5696f 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -88,9 +88,9 @@ struct EdgeHash {
* \{ */
/**
- * Get the hash for a key.
+ * Compute the hash and get the bucket-index.
*/
-BLI_INLINE unsigned int edgehash_keyhash(EdgeHash *eh, unsigned int v0, unsigned int v1)
+BLI_INLINE unsigned int edgehash_bucket_index(EdgeHash *eh, unsigned int v0, unsigned int v1)
{
BLI_assert(v0 < v1);
@@ -114,7 +114,6 @@ BLI_INLINE void edgehash_resize_buckets(EdgeHash *eh, const unsigned int nbucket
EdgeEntry **buckets_new;
const unsigned int nbuckets_old = eh->nbuckets;
unsigned int i;
- EdgeEntry *e;
BLI_assert(eh->nbuckets != nbuckets);
@@ -122,12 +121,11 @@ BLI_INLINE void edgehash_resize_buckets(EdgeHash *eh, const unsigned int nbucket
buckets_new = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets");
for (i = 0; i < nbuckets_old; i++) {
- EdgeEntry *e_next;
- for (e = buckets_old[i]; e; e = e_next) {
- const unsigned hash = edgehash_keyhash(eh, e->v0, e->v1);
+ for (EdgeEntry *e = buckets_old[i], *e_next; e; e = e_next) {
+ const unsigned bucket_index = edgehash_bucket_index(eh, e->v0, e->v1);
e_next = e->next;
- e->next = buckets_new[hash];
- buckets_new[hash] = e;
+ e->next = buckets_new[bucket_index];
+ buckets_new[bucket_index] = e;
}
}
@@ -147,14 +145,15 @@ BLI_INLINE void edgehash_buckets_reserve(EdgeHash *eh, const unsigned int nentri
/**
* Internal lookup function.
- * Takes a hash argument to avoid calling #edgehash_keyhash multiple times.
+ * Takes a \a bucket_index argument to avoid calling #edgehash_bucket_index multiple times.
*/
-BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, unsigned int v1,
- const unsigned int hash)
+BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(
+ EdgeHash *eh, unsigned int v0, unsigned int v1,
+ const unsigned int bucket_index)
{
EdgeEntry *e;
BLI_assert(v0 < v1);
- for (e = eh->buckets[hash]; e; e = e->next) {
+ for (e = eh->buckets[bucket_index]; e; e = e->next) {
if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) {
return e;
}
@@ -163,14 +162,34 @@ BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, un
}
/**
+ * Internal lookup function, returns previous entry of target one too.
+ * Takes bucket_index argument to avoid calling #edgehash_bucket_index multiple times.
+ * Useful when modifying buckets somehow (like removing an entry...).
+ */
+BLI_INLINE EdgeEntry *edgehash_lookup_entry_prev_ex(
+ EdgeHash *eh, unsigned int v0, unsigned int v1,
+ EdgeEntry **r_e_prev, const unsigned int bucket_index)
+{
+ BLI_assert(v0 < v1);
+ for (EdgeEntry *e_prev = NULL, *e = eh->buckets[bucket_index]; e; e_prev = e, e = e->next) {
+ if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) {
+ *r_e_prev = e_prev;
+ return e;
+ }
+ }
+
+ *r_e_prev = NULL;
+ return NULL;
+}
+
+/**
* Internal lookup function. Only wraps #edgehash_lookup_entry_ex
*/
BLI_INLINE EdgeEntry *edgehash_lookup_entry(EdgeHash *eh, unsigned int v0, unsigned int v1)
{
- unsigned int hash;
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash(eh, v0, v1);
- return edgehash_lookup_entry_ex(eh, v0, v1, hash);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1);
+ return edgehash_lookup_entry_ex(eh, v0, v1, bucket_index);
}
@@ -198,10 +217,11 @@ static EdgeHash *edgehash_new(const char *info,
/**
* Internal insert function.
- * Takes a hash argument to avoid calling #edgehash_keyhash multiple times.
+ * Takes a \a bucket_index argument to avoid calling #edgehash_bucket_index multiple times.
*/
-BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val,
- unsigned int hash)
+BLI_INLINE void edgehash_insert_ex(
+ EdgeHash *eh, unsigned int v0, unsigned int v1, void *val,
+ const unsigned int bucket_index)
{
EdgeEntry *e = BLI_mempool_alloc(eh->epool);
@@ -212,11 +232,11 @@ BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v
BLI_assert(v0 < v1);
BLI_assert(v0 != v1);
- e->next = eh->buckets[hash];
+ e->next = eh->buckets[bucket_index];
e->v0 = v0;
e->v1 = v1;
e->val = val;
- eh->buckets[hash] = e;
+ eh->buckets[bucket_index] = e;
if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
@@ -226,8 +246,9 @@ BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v
/**
* Insert function that doesn't set the value (use for EdgeSet)
*/
-BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsigned int v1,
- unsigned int hash)
+BLI_INLINE void edgehash_insert_ex_keyonly(
+ EdgeHash *eh, unsigned int v0, unsigned int v1,
+ const unsigned int bucket_index)
{
EdgeEntry *e = BLI_mempool_alloc(eh->epool);
@@ -237,10 +258,10 @@ BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsign
BLI_assert(v0 < v1);
BLI_assert(v0 != v1);
- e->next = eh->buckets[hash];
+ e->next = eh->buckets[bucket_index];
e->v0 = v0;
e->v1 = v1;
- eh->buckets[hash] = e;
+ eh->buckets[bucket_index] = e;
if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
@@ -252,7 +273,7 @@ BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsign
*/
BLI_INLINE void edgehash_insert_ex_keyonly_entry(
EdgeHash *eh, unsigned int v0, unsigned int v1,
- unsigned int hash,
+ const unsigned int bucket_index,
EdgeEntry *e)
{
BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0));
@@ -261,11 +282,11 @@ BLI_INLINE void edgehash_insert_ex_keyonly_entry(
BLI_assert(v0 < v1);
BLI_assert(v0 != v1);
- e->next = eh->buckets[hash];
+ e->next = eh->buckets[bucket_index];
e->v0 = v0;
e->v1 = v1;
/* intentionally leave value unset */
- eh->buckets[hash] = e;
+ eh->buckets[bucket_index] = e;
if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) {
edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]);
@@ -274,39 +295,43 @@ BLI_INLINE void edgehash_insert_ex_keyonly_entry(
BLI_INLINE void edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
{
- unsigned int hash;
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash(eh, v0, v1);
- edgehash_insert_ex(eh, v0, v1, val, hash);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1);
+ edgehash_insert_ex(eh, v0, v1, val, bucket_index);
}
/**
* Remove the entry and return it, caller must free from eh->epool.
*/
-static EdgeEntry *edgehash_remove_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp,
- unsigned int hash)
+BLI_INLINE EdgeEntry *edgehash_remove_ex(
+ EdgeHash *eh, unsigned int v0, unsigned int v1,
+ EdgeHashFreeFP valfreefp,
+ const unsigned int bucket_index)
{
- EdgeEntry *e;
- EdgeEntry *e_prev = NULL;
+ EdgeEntry *e_prev;
+ EdgeEntry *e = edgehash_lookup_entry_prev_ex(eh, v0, v1, &e_prev, bucket_index);
BLI_assert(v0 < v1);
- for (e = eh->buckets[hash]; e; e = e->next) {
- if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) {
- EdgeEntry *e_next = e->next;
-
- if (valfreefp) valfreefp(e->val);
+ if (e) {
+ EdgeEntry *e_next = e->next;
- if (e_prev) e_prev->next = e_next;
- else eh->buckets[hash] = e_next;
+ if (valfreefp) {
+ valfreefp(e->val);
+ }
- eh->nentries--;
- return e;
+ if (e_prev) {
+ e_prev->next = e_next;
+ }
+ else {
+ eh->buckets[bucket_index] = e_next;
}
- e_prev = e;
+
+ eh->nentries--;
+ return e;
}
- return NULL;
+ return e;
}
/**
@@ -366,21 +391,18 @@ void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *v
*/
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val)
{
- unsigned int hash;
- EdgeEntry *e;
-
IS_EDGEHASH_ASSERT(eh);
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash(eh, v0, v1);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1);
- e = edgehash_lookup_entry_ex(eh, v0, v1, hash);
+ EdgeEntry *e = edgehash_lookup_entry_ex(eh, v0, v1, bucket_index);
if (e) {
e->val = val;
return false;
}
else {
- edgehash_insert_ex(eh, v0, v1, val, hash);
+ edgehash_insert_ex(eh, v0, v1, val, bucket_index);
return true;
}
}
@@ -412,18 +434,14 @@ void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1)
*/
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
{
- unsigned int hash;
- EdgeEntry *e;
- bool haskey;
-
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash(eh, v0, v1);
- e = edgehash_lookup_entry_ex(eh, v0, v1, hash);
- haskey = (e != NULL);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1);
+ EdgeEntry *e = edgehash_lookup_entry_ex(eh, v0, v1, bucket_index);
+ const bool haskey = (e != NULL);
if (!haskey) {
e = BLI_mempool_alloc(eh->epool);
- edgehash_insert_ex_keyonly_entry(eh, v0, v1, hash, e);
+ edgehash_insert_ex_keyonly_entry(eh, v0, v1, bucket_index, e);
}
*r_val = &e->val;
@@ -462,12 +480,9 @@ void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1
*/
bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp)
{
- unsigned int hash;
- EdgeEntry *e;
-
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash(eh, v0, v1);
- e = edgehash_remove_ex(eh, v0, v1, valfreefp, hash);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1);
+ EdgeEntry *e = edgehash_remove_ex(eh, v0, v1, valfreefp, bucket_index);
if (e) {
BLI_mempool_free(eh->epool, e);
return true;
@@ -487,12 +502,9 @@ bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHas
*/
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1)
{
- unsigned int hash;
- EdgeEntry *e;
-
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash(eh, v0, v1);
- e = edgehash_remove_ex(eh, v0, v1, NULL, hash);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1);
+ EdgeEntry *e = edgehash_remove_ex(eh, v0, v1, NULL, bucket_index);
IS_EDGEHASH_ASSERT(eh);
if (e) {
void *val = e->val;
@@ -728,10 +740,9 @@ int BLI_edgeset_size(EdgeSet *es)
*/
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1)
{
- unsigned int hash;
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash((EdgeHash *)es, v0, v1);
- edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index((EdgeHash *)es, v0, v1);
+ edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, bucket_index);
}
/**
@@ -742,18 +753,15 @@ void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1)
*/
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1)
{
- unsigned int hash;
- EdgeEntry *e;
-
- EDGE_ORD(v0, v1); /* ensure v0 is smaller */
- hash = edgehash_keyhash((EdgeHash *)es, v0, v1);
+ EDGE_ORD(v0, v1);
+ const unsigned int bucket_index = edgehash_bucket_index((EdgeHash *)es, v0, v1);
- e = edgehash_lookup_entry_ex((EdgeHash *)es, v0, v1, hash);
+ EdgeEntry *e = edgehash_lookup_entry_ex((EdgeHash *)es, v0, v1, bucket_index);
if (e) {
return false;
}
else {
- edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash);
+ edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, bucket_index);
return true;
}
}
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index ef9a7c0603f..db4b3bcf20c 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -304,7 +304,7 @@ static bool delete_unique(const char *path, const bool dir)
if (dir) {
err = !RemoveDirectoryW(path_16);
- if (err) printf("Unable to remove directory");
+ if (err) printf("Unable to remove directory\n");
}
else {
err = !DeleteFileW(path_16);
@@ -720,6 +720,8 @@ int BLI_access(const char *filename, int mode)
/**
* Deletes the specified file or directory (depending on dir), optionally
* doing recursive delete of directory contents.
+ *
+ * \return zero on success (matching 'remove' behavior).
*/
int BLI_delete(const char *file, bool dir, bool recursive)
{
@@ -825,7 +827,7 @@ static int copy_single_file(const char *from, const char *to)
ssize_t link_len;
/* get large enough buffer to read link content */
- if (st.st_size < sizeof(buf)) {
+ if ((st.st_size + 1) < sizeof(buf)) {
link_buffer = buf;
need_free = 0;
}
@@ -843,7 +845,7 @@ static int copy_single_file(const char *from, const char *to)
return RecursiveOp_Callback_Error;
}
- link_buffer[link_len] = 0;
+ link_buffer[link_len] = '\0';
if (symlink(link_buffer, to)) {
perror("symlink");
@@ -1043,9 +1045,14 @@ bool BLI_dir_create_recursive(const char *dirname)
return ret;
}
+/**
+ * \return zero on success (matching 'rename' behavior).
+ */
int BLI_rename(const char *from, const char *to)
{
- if (!BLI_exists(from)) return 0;
+ if (!BLI_exists(from)) {
+ return 1;
+ }
if (BLI_exists(to))
if (BLI_delete(to, false, false)) return 1;
diff --git a/source/blender/blenlib/intern/lasso.c b/source/blender/blenlib/intern/lasso.c
index 23704538413..710da09521a 100644
--- a/source/blender/blenlib/intern/lasso.c
+++ b/source/blender/blenlib/intern/lasso.c
@@ -71,15 +71,12 @@ bool BLI_lasso_is_edge_inside(const int mcords[][2], const unsigned int moves,
int x0, int y0, int x1, int y1,
const int error_value)
{
- int v1[2], v2[2];
- unsigned int a;
if (x0 == error_value || x1 == error_value || moves == 0) {
return false;
}
- v1[0] = x0, v1[1] = y0;
- v2[0] = x1, v2[1] = y1;
+ const int v1[2] = {x0, y0}, v2[2] = {x1, y1};
/* check points in lasso */
if (BLI_lasso_is_point_inside(mcords, moves, v1[0], v1[1], error_value)) return true;
@@ -87,9 +84,9 @@ bool BLI_lasso_is_edge_inside(const int mcords[][2], const unsigned int moves,
/* no points in lasso, so we have to intersect with lasso edge */
- if (isect_line_line_v2_int(mcords[0], mcords[moves - 1], v1, v2) > 0) return true;
- for (a = 0; a < moves - 1; a++) {
- if (isect_line_line_v2_int(mcords[a], mcords[a + 1], v1, v2) > 0) return true;
+ if (isect_seg_seg_v2_int(mcords[0], mcords[moves - 1], v1, v2) > 0) return true;
+ for (unsigned int a = 0; a < moves - 1; a++) {
+ if (isect_seg_seg_v2_int(mcords[a], mcords[a + 1], v1, v2) > 0) return true;
}
return false;
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index e149fdb2d26..6d7d24c79c3 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -455,7 +455,7 @@ void minmax_rgb(short c[3])
else if (c[2] < 0) c[2] = 0;
}
-/*If the requested RGB shade contains a negative weight for
+/* If the requested RGB shade contains a negative weight for
* one of the primaries, it lies outside the color gamut
* accessible from the given triple of primaries. Desaturate
* it by adding white, equal quantities of R, G, and B, enough
@@ -463,21 +463,15 @@ void minmax_rgb(short c[3])
* components were modified, zero otherwise.*/
int constrain_rgb(float *r, float *g, float *b)
{
- float w;
-
- /* Amount of white needed is w = - min(0, *r, *g, *b) */
-
- w = (0 < *r) ? 0 : *r;
- w = (w < *g) ? w : *g;
- w = (w < *b) ? w : *b;
- w = -w;
+ /* Amount of white needed */
+ const float w = -min_ffff(0.0f, *r, *g, *b);
/* Add just enough white to make r, g, b all positive. */
-
- if (w > 0) {
+ if (w > 0.0f) {
*r += w;
*g += w;
*b += w;
+
return 1; /* Color modified to fit RGB gamut */
}
@@ -659,3 +653,136 @@ void rgb_to_lab(float r, float g, float b, float *ll, float *la, float *lb)
rgb_to_xyz(r, g, b, &x, &y, &z);
xyz_to_lab(x, y, z, ll, la, lb);
}
+
+static void xyz_to_lms(float x, float y, float z, float *l, float *m, float *s)
+{
+ *l = 0.3897f * x + 0.6890f * y - 0.0787f * z;
+ *m = -0.2298f * x + 1.1834f * y + 0.0464f * z;
+ *s = z;
+}
+
+static void lms_to_xyz(float l, float m, float s, float *x, float *y, float *z)
+{
+ *x = 1.9102f * l - 1.1121f * m + 0.2019f * s;
+ *y = 0.3709f * l + 0.6290f * m + 0.0000f * s;
+ *z = s;
+}
+
+static void normalize_rgb(float rgb[3])
+{
+ const float max = max_fff(rgb[0], rgb[1], rgb[2]);
+
+ if (max > 0.0f) {
+ mul_v3_fl(rgb, 1.0f / max);
+ }
+}
+
+/* Color rendering of spectra, adapted from public domain code by John Walker,
+ * http://www.fourmilab.ch/
+ */
+
+static void spectrum_to_xyz(float temperature, float xyz[3])
+{
+ int i;
+ float lambda, x = 0.0f, y = 0.0f, z = 0.0f, xyz_sum;
+
+ /* CIE colour matching functions xBar, yBar, and zBar for wavelengths from
+ * 380 through 780 nanometers, every 5 nanometers.
+ * For a wavelength lambda in this range:
+ *
+ * cie_colour_match[(lambda - 380) / 5][0] = xBar
+ * cie_colour_match[(lambda - 380) / 5][1] = yBar
+ * cie_colour_match[(lambda - 380) / 5][2] = zBar
+ */
+
+ const float cie_colour_match[81][3] = {
+ {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
+ {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
+ {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
+ {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
+ {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
+ {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
+ {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
+ {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
+ {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
+ {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
+ {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
+ {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
+ {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
+ {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
+ {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
+ {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
+ {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
+ {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
+ {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
+ {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
+ {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
+ {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
+ {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
+ {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
+ {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
+ {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
+ {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}
+ };
+
+ for (i = 0, lambda = 380.0f; lambda < 780.1f; i++, lambda += 5.0f) {
+ /* wavelength in meter */
+ const float wlm = lambda * 1e-9f;
+ const float Me = (3.74183e-16f * powf(wlm, -5.0f)) / (expf(1.4388e-2f / (wlm * temperature)) - 1.0f);
+
+ x += Me * cie_colour_match[i][0];
+ y += Me * cie_colour_match[i][1];
+ z += Me * cie_colour_match[i][2];
+ }
+
+ xyz_sum = (x + y + z);
+
+ xyz[0] = x / xyz_sum;
+ xyz[1] = y / xyz_sum;
+ xyz[2] = z / xyz_sum;
+}
+
+void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max)
+{
+ int i, j = 0, dj = 1;
+ float rgb[3], xyz[3], lms[3], lms_w[3];
+ float bb_temp;
+
+ if (min < max) {
+ SWAP(float, min, max);
+ j = width - 1;
+ dj = -1;
+ }
+
+ for (i = 0; i < width; i++, j += dj) {
+ bb_temp = min + (max - min) / (float)width * (float)i;
+
+ /* integrate blackbody radiation spectrum to XYZ */
+ spectrum_to_xyz(bb_temp, xyz);
+
+ /* normalize highest temperature to white (in LMS system) */
+ xyz_to_lms(xyz[0], xyz[1], xyz[2], &lms[0], &lms[1], &lms[2]);
+
+ if (i == 0) {
+ lms_w[0] = 1.0f / lms[0];
+ lms_w[1] = 1.0f / lms[1];
+ lms_w[2] = 1.0f / lms[2];
+ }
+
+ mul_v3_v3(lms, lms_w);
+
+ lms_to_xyz(lms[0], lms[1], lms[2], &xyz[0], &xyz[1], &xyz[2]);
+
+ /* convert to RGB */
+ xyz_to_rgb(xyz[0], xyz[1], xyz[2], &rgb[0], &rgb[1], &rgb[2], BLI_XYZ_CIE);
+ constrain_rgb(&rgb[0], &rgb[1], &rgb[2]);
+ normalize_rgb(rgb);
+
+ copy_v3_v3(&r_table[(j << 2)], rgb);
+
+ if (rgb[2] > 0.1f)
+ r_table[(j << 2) + 3] = rgb[2];
+ else
+ r_table[(j << 2) + 3] = 0.0f;
+ }
+}
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 88be86aa1c2..048ab71c6dc 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -72,7 +72,7 @@ MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -94,7 +94,7 @@ MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -116,7 +116,7 @@ MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -139,7 +139,7 @@ MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -162,7 +162,7 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -185,7 +185,7 @@ MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char s
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -202,7 +202,7 @@ MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned c
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -219,7 +219,7 @@ MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned cha
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -244,7 +244,7 @@ MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -270,7 +270,7 @@ MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const cha
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -289,7 +289,7 @@ MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -308,7 +308,7 @@ MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const ch
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -327,7 +327,7 @@ MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char sr
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -345,7 +345,7 @@ MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char s
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -371,7 +371,7 @@ MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const cha
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -397,7 +397,7 @@ MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -423,7 +423,7 @@ MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const c
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -455,7 +455,7 @@ MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const ch
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -475,7 +475,7 @@ MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const ch
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -494,7 +494,7 @@ MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const cha
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -521,7 +521,7 @@ MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char sr
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -547,7 +547,7 @@ MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -575,7 +575,7 @@ MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const ch
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -601,7 +601,7 @@ MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const ch
}
else {
/* no op */
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
@@ -621,7 +621,7 @@ MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned c
dst[3] = (unsigned char)divide_round_i(tmp, 255);
}
else {
- copy_v4_v4_char((char *)dst, (char *)src1);
+ copy_v4_v4_uchar(dst, src1);
}
}
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index dad2a2fc288..f80099bee1b 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -341,27 +341,35 @@ void closest_to_line_segment_v2(float r_close[2], const float p[2], const float
lambda = closest_to_line_v2(cp, p, l1, l2);
- if (lambda <= 0.0f)
+ /* flip checks for !finite case (when segment is a point) */
+ if (!(lambda > 0.0f)) {
copy_v2_v2(r_close, l1);
- else if (lambda >= 1.0f)
+ }
+ else if (!(lambda < 1.0f)) {
copy_v2_v2(r_close, l2);
- else
+ }
+ else {
copy_v2_v2(r_close, cp);
+ }
}
/* point closest to v1 on line v2-v3 in 3D */
-void closest_to_line_segment_v3(float r_close[3], const float v1[3], const float v2[3], const float v3[3])
+void closest_to_line_segment_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
{
float lambda, cp[3];
- lambda = closest_to_line_v3(cp, v1, v2, v3);
+ lambda = closest_to_line_v3(cp, p, l1, l2);
- if (lambda <= 0.0f)
- copy_v3_v3(r_close, v2);
- else if (lambda >= 1.0f)
- copy_v3_v3(r_close, v3);
- else
+ /* flip checks for !finite case (when segment is a point) */
+ if (!(lambda > 0.0f)) {
+ copy_v3_v3(r_close, l1);
+ }
+ else if (!(lambda < 1.0f)) {
+ copy_v3_v3(r_close, l2);
+ }
+ else {
copy_v3_v3(r_close, cp);
+ }
}
/**
@@ -497,7 +505,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
* \note the distance from \a v1 & \a v3 to \a v2 doesnt matter
* (it just defines the planes).
*
- * \return the lowest squared distance to eithe of the planes.
+ * \return the lowest squared distance to either of the planes.
* where ``(return < 0.0)`` is outside.
*
* <pre>
@@ -649,7 +657,7 @@ void closest_on_tri_to_point_v3(float r[3], const float p[3],
/******************************* Intersection ********************************/
/* intersect Line-Line, shorts */
-int isect_line_line_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
+int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
{
float div, lambda, mu;
@@ -692,7 +700,7 @@ int isect_line_line_v2_point(const float v0[2], const float v1[2], const float v
}
/* intersect Line-Line, floats */
-int isect_line_line_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
+int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
float div, lambda, mu;
@@ -714,7 +722,10 @@ int isect_line_line_v2(const float v1[2], const float v2[2], const float v3[2],
* -1: collinear
* 1: intersection
*/
-int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
+int isect_seg_seg_v2_point(
+ const float v0[2], const float v1[2],
+ const float v2[2], const float v3[2],
+ float r_vi[2])
{
float s10[2], s32[2], s30[2], d;
const float eps = 1e-6f;
@@ -813,7 +824,7 @@ int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[
}
}
-bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
+bool isect_seg_seg_v2_simple(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
#define CCW(A, B, C) \
((C[1] - A[1]) * (B[0] - A[0]) > \
@@ -824,17 +835,23 @@ bool isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], c
#undef CCW
}
+/**
+ * \param l1, l2: Coordinates (point of line).
+ * \param sp, r: Coordinate and radius (sphere).
+ * \return r_p1, r_p2: Intersection coordinates.
+ *
+ * \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
+ * based on the direction defined by ``l2 - l1``,
+ * this direction compared with the normal of each point on the sphere:
+ * \a r_p1 always has a >= 0.0 dot product.
+ * \a r_p2 always has a <= 0.0 dot product.
+ * For example, when \a l1 is inside the sphere and \a l2 is outside,
+ * \a r_p1 will always be between \a l1 and \a l2.
+ */
int isect_line_sphere_v3(const float l1[3], const float l2[3],
const float sp[3], const float r,
float r_p1[3], float r_p2[3])
{
- /* l1: coordinates (point of line)
- * l2: coordinates (point of line)
- * sp, r: coordinates and radius (sphere)
- * r_p1, r_p2: return intersection coordinates
- */
-
-
/* adapted for use in blender by Campbell Barton - 2011
*
* atelier iebele abel - 2001
@@ -1130,7 +1147,7 @@ int isect_point_quad_v2(const float pt[2], const float v1[2], const float v2[2],
* test if the line starting at p1 ending at p2 intersects the triangle v0..v2
* return non zero if it does
*/
-bool isect_line_tri_v3(
+bool isect_line_segment_tri_v3(
const float p1[3], const float p2[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2])
@@ -1169,8 +1186,8 @@ bool isect_line_tri_v3(
return true;
}
-/* like isect_line_tri_v3, but allows epsilon tolerance around triangle */
-bool isect_line_tri_epsilon_v3(
+/* like isect_line_segment_tri_v3, but allows epsilon tolerance around triangle */
+bool isect_line_segment_tri_epsilon_v3(
const float p1[3], const float p2[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2], const float epsilon)
@@ -1214,7 +1231,7 @@ bool isect_line_tri_epsilon_v3(
* return non zero if it does
*/
bool isect_ray_tri_v3(
- const float p1[3], const float d[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2])
{
@@ -1227,19 +1244,19 @@ bool isect_ray_tri_v3(
sub_v3_v3v3(e1, v1, v0);
sub_v3_v3v3(e2, v2, v0);
- cross_v3_v3v3(p, d, e2);
+ cross_v3_v3v3(p, ray_direction, e2);
a = dot_v3v3(e1, p);
if ((a > -epsilon) && (a < epsilon)) return false;
f = 1.0f / a;
- sub_v3_v3v3(s, p1, v0);
+ sub_v3_v3v3(s, ray_origin, v0);
u = f * dot_v3v3(s, p);
if ((u < 0.0f) || (u > 1.0f)) return false;
cross_v3_v3v3(q, s, e1);
- v = f * dot_v3v3(d, q);
+ v = f * dot_v3v3(ray_direction, q);
if ((v < 0.0f) || ((u + v) > 1.0f)) return false;
*r_lambda = f * dot_v3v3(e2, q);
@@ -1255,46 +1272,35 @@ bool isect_ray_tri_v3(
/**
* if clip is nonzero, will only return true if lambda is >= 0.0
- * (i.e. intersection point is along positive d)
+ * (i.e. intersection point is along positive \a ray_direction)
+ *
+ * \note #line_plane_factor_v3() shares logic.
*/
bool isect_ray_plane_v3(
- const float p1[3], const float d[3],
- const float v0[3], const float v1[3], const float v2[3],
+ const float ray_origin[3], const float ray_direction[3],
+ const float plane[4],
float *r_lambda, const bool clip)
{
- const float epsilon = 0.00000001f;
- float p[3], s[3], e1[3], e2[3], q[3];
- float a, f;
- /* float u, v; */ /*UNUSED*/
-
- sub_v3_v3v3(e1, v1, v0);
- sub_v3_v3v3(e2, v2, v0);
-
- cross_v3_v3v3(p, d, e2);
- a = dot_v3v3(e1, p);
- /* note: these values were 0.000001 in 2.4x but for projection snapping on
- * a human head (1BU == 1m), subsurf level 2, this gave many errors - campbell */
- if ((a > -epsilon) && (a < epsilon)) return false;
- f = 1.0f / a;
-
- sub_v3_v3v3(s, p1, v0);
-
- /* u = f * dot_v3v3(s, p); */ /*UNUSED*/
-
- cross_v3_v3v3(q, s, e1);
-
- /* v = f * dot_v3v3(d, q); */ /*UNUSED*/
-
- *r_lambda = f * dot_v3v3(e2, q);
- if (clip && (*r_lambda < 0.0f)) return false;
+ float h[3], plane_co[3];
+ float dot;
+ dot = dot_v3v3(plane, ray_direction);
+ if (dot == 0.0f) {
+ return false;
+ }
+ mul_v3_v3fl(plane_co, plane, (-plane[3] / len_squared_v3(plane)));
+ sub_v3_v3v3(h, ray_origin, plane_co);
+ *r_lambda = -dot_v3v3(plane, h) / dot;
+ if (clip && (*r_lambda < 0.0f)) {
+ return false;
+ }
return true;
}
bool isect_ray_tri_epsilon_v3(
- const float p1[3], const float d[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
- float *r_lambda, float uv[2], const float epsilon)
+ float *r_lambda, float r_uv[2], const float epsilon)
{
float p[3], s[3], e1[3], e2[3], q[3];
float a, f, u, v;
@@ -1302,50 +1308,50 @@ bool isect_ray_tri_epsilon_v3(
sub_v3_v3v3(e1, v1, v0);
sub_v3_v3v3(e2, v2, v0);
- cross_v3_v3v3(p, d, e2);
+ cross_v3_v3v3(p, ray_direction, e2);
a = dot_v3v3(e1, p);
if (a == 0.0f) return false;
f = 1.0f / a;
- sub_v3_v3v3(s, p1, v0);
+ sub_v3_v3v3(s, ray_origin, v0);
u = f * dot_v3v3(s, p);
if ((u < -epsilon) || (u > 1.0f + epsilon)) return false;
cross_v3_v3v3(q, s, e1);
- v = f * dot_v3v3(d, q);
+ v = f * dot_v3v3(ray_direction, q);
if ((v < -epsilon) || ((u + v) > 1.0f + epsilon)) return false;
*r_lambda = f * dot_v3v3(e2, q);
if ((*r_lambda < 0.0f)) return false;
- if (uv) {
- uv[0] = u;
- uv[1] = v;
+ if (r_uv) {
+ r_uv[0] = u;
+ r_uv[1] = v;
}
return true;
}
-void isect_ray_tri_watertight_v3_precalc(struct IsectRayPrecalc *isect_precalc, const float dir[3])
+void isect_ray_tri_watertight_v3_precalc(struct IsectRayPrecalc *isect_precalc, const float ray_direction[3])
{
float inv_dir_z;
/* Calculate dimension where the ray direction is maximal. */
- int kz = axis_dominant_v3_single(dir);
+ int kz = axis_dominant_v3_single(ray_direction);
int kx = (kz != 2) ? (kz + 1) : 0;
int ky = (kx != 2) ? (kx + 1) : 0;
/* Swap kx and ky dimensions to preserve winding direction of triangles. */
- if (dir[kz] < 0.0f) {
+ if (ray_direction[kz] < 0.0f) {
SWAP(int, kx, ky);
}
/* Calculate the shear constants. */
- inv_dir_z = 1.0f / dir[kz];
- isect_precalc->sx = dir[kx] * inv_dir_z;
- isect_precalc->sy = dir[ky] * inv_dir_z;
+ inv_dir_z = 1.0f / ray_direction[kz];
+ isect_precalc->sx = ray_direction[kx] * inv_dir_z;
+ isect_precalc->sy = ray_direction[ky] * inv_dir_z;
isect_precalc->sz = inv_dir_z;
/* Store the dimensions. */
@@ -1355,7 +1361,7 @@ void isect_ray_tri_watertight_v3_precalc(struct IsectRayPrecalc *isect_precalc,
}
bool isect_ray_tri_watertight_v3(
- const float p[3], const struct IsectRayPrecalc *isect_precalc,
+ const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2])
{
@@ -1367,9 +1373,9 @@ bool isect_ray_tri_watertight_v3(
const float sz = isect_precalc->sz;
/* Calculate vertices relative to ray origin. */
- const float a[3] = {v0[0] - p[0], v0[1] - p[1], v0[2] - p[2]};
- const float b[3] = {v1[0] - p[0], v1[1] - p[1], v1[2] - p[2]};
- const float c[3] = {v2[0] - p[0], v2[1] - p[1], v2[2] - p[2]};
+ const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
+ const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
+ const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
@@ -1384,16 +1390,14 @@ bool isect_ray_tri_watertight_v3(
const float cy = c_ky - sy * c_kz;
/* Calculate scaled barycentric coordinates. */
- float u = cx * by - cy * bx;
- int sign_mask = (float_as_int(u) & (int)0x80000000);
- float v = ax * cy - ay * cx;
- float w, det;
+ const float u = cx * by - cy * bx;
+ const float v = ax * cy - ay * cx;
+ const float w = bx * ay - by * ax;
+ float det;
- if (sign_mask != (float_as_int(v) & (int)0x80000000)) {
- return false;
- }
- w = bx * ay - by * ax;
- if (sign_mask != (float_as_int(w) & (int)0x80000000)) {
+ if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
+ (u > 0.0f || v > 0.0f || w > 0.0f))
+ {
return false;
}
@@ -1406,8 +1410,9 @@ bool isect_ray_tri_watertight_v3(
/* Calculate scaled z-coordinates of vertices and use them to calculate
* the hit distance.
*/
+ const int sign_det = (float_as_int(det) & (int)0x80000000);
const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
- const float sign_t = xor_fl(t, sign_mask);
+ const float sign_t = xor_fl(t, sign_det);
if ((sign_t < 0.0f)
/* differ from Cycles, don't read r_lambda's original value
* otherwise we won't match any of the other intersect functions here...
@@ -1434,13 +1439,13 @@ bool isect_ray_tri_watertight_v3(
}
bool isect_ray_tri_watertight_v3_simple(
- const float P[3], const float dir[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2])
{
struct IsectRayPrecalc isect_precalc;
- isect_ray_tri_watertight_v3_precalc(&isect_precalc, dir);
- return isect_ray_tri_watertight_v3(P, &isect_precalc, v0, v1, v2, r_lambda, r_uv);
+ isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction);
+ return isect_ray_tri_watertight_v3(ray_origin, &isect_precalc, v0, v1, v2, r_lambda, r_uv);
}
#if 0 /* UNUSED */
@@ -1449,7 +1454,7 @@ bool isect_ray_tri_watertight_v3_simple(
* so rays slightly outside the triangle to be considered as intersecting.
*/
bool isect_ray_tri_threshold_v3(
- const float p1[3], const float d[3],
+ const float ray_origin[3], const float ray_direction[3],
const float v0[3], const float v1[3], const float v2[3],
float *r_lambda, float r_uv[2], const float threshold)
{
@@ -1461,19 +1466,19 @@ bool isect_ray_tri_threshold_v3(
sub_v3_v3v3(e1, v1, v0);
sub_v3_v3v3(e2, v2, v0);
- cross_v3_v3v3(p, d, e2);
+ cross_v3_v3v3(p, ray_direction, e2);
a = dot_v3v3(e1, p);
if ((a > -epsilon) && (a < epsilon)) return false;
f = 1.0f / a;
- sub_v3_v3v3(s, p1, v0);
+ sub_v3_v3v3(s, ray_origin, v0);
cross_v3_v3v3(q, s, e1);
*r_lambda = f * dot_v3v3(e2, q);
if ((*r_lambda < 0.0f)) return false;
u = f * dot_v3v3(s, p);
- v = f * dot_v3v3(d, q);
+ v = f * dot_v3v3(ray_direction, q);
if (u > 0 && v > 0 && u + v > 1) {
float t = (u + v - 1) / 2;
@@ -1506,6 +1511,51 @@ bool isect_ray_tri_threshold_v3(
}
#endif
+
+bool isect_ray_seg_v2(
+ const float ray_origin[2], const float ray_direction[2],
+ const float v0[2], const float v1[2],
+ float *r_lambda, float *r_u)
+{
+ float v0_local[2], v1_local[2];
+ sub_v2_v2v2(v0_local, v0, ray_origin);
+ sub_v2_v2v2(v1_local, v1, ray_origin);
+
+ float s10[2];
+ float det;
+
+ sub_v2_v2v2(s10, v1_local, v0_local);
+
+ det = cross_v2v2(ray_direction, s10);
+ if (det != 0.0f) {
+ const float v = cross_v2v2(v0_local, v1_local);
+ float p[2] = {(ray_direction[0] * v) / det, (ray_direction[1] * v) / det};
+
+ const float t = (dot_v2v2(p, ray_direction) / dot_v2v2(ray_direction, ray_direction));
+ if ((t >= 0.0f) == 0) {
+ return false;
+ }
+
+ float h[2];
+ sub_v2_v2v2(h, v1_local, p);
+ const float u = (dot_v2v2(s10, h) / dot_v2v2(s10, s10));
+ if ((u >= 0.0f && u <= 1.0f) == 0) {
+ return false;
+ }
+
+ if (r_lambda) {
+ *r_lambda = t;
+ }
+ if (r_u) {
+ *r_u = u;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
/**
* Check if a point is behind all planes.
*/
@@ -1525,7 +1575,7 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
/**
* Intersect line/plane.
*
- * \param out The intersection point.
+ * \param r_isect_co The intersection point.
* \param l1 The first point of the line.
* \param l2 The second point of the line.
* \param plane_co A point on the plane to intersect with.
@@ -1533,9 +1583,10 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
*
* \note #line_plane_factor_v3() shares logic.
*/
-bool isect_line_plane_v3(float out[3],
- const float l1[3], const float l2[3],
- const float plane_co[3], const float plane_no[3])
+bool isect_line_plane_v3(
+ float r_isect_co[3],
+ const float l1[3], const float l2[3],
+ const float plane_co[3], const float plane_no[3])
{
float u[3], h[3];
float dot;
@@ -1546,7 +1597,7 @@ bool isect_line_plane_v3(float out[3],
if (fabsf(dot) > FLT_EPSILON) {
float lambda = -dot_v3v3(plane_no, h) / dot;
- madd_v3_v3v3fl(out, l1, u, lambda);
+ madd_v3_v3v3fl(r_isect_co, l1, u, lambda);
return true;
}
else {
@@ -1967,8 +2018,9 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
return found_by_sweep;
}
-bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3],
- const float v0[3], const float v1[3], const float v2[3], float *r_lambda)
+bool isect_axial_line_segment_tri_v3(
+ const int axis, const float p1[3], const float p2[3],
+ const float v0[3], const float v1[3], const float v2[3], float *r_lambda)
{
const float epsilon = 0.000001f;
float p[3], e1[3], e2[3];
@@ -1976,7 +2028,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
int a0 = axis, a1 = (axis + 1) % 3, a2 = (axis + 2) % 3;
#if 0
- return isect_line_tri_v3(p1, p2, v0, v1, v2, lambda);
+ return isect_line_segment_tri_v3(p1, p2, v0, v1, v2, lambda);
/* first a simple bounding box test */
if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return false;
@@ -2023,7 +2075,8 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
*/
int isect_line_line_epsilon_v3(
const float v1[3], const float v2[3],
- const float v3[3], const float v4[3], float i1[3], float i2[3],
+ const float v3[3], const float v4[3],
+ float r_i1[3], float r_i2[3],
const float epsilon)
{
float a[3], b[3], c[3], ab[3], cb[3];
@@ -2047,8 +2100,8 @@ int isect_line_line_epsilon_v3(
cross_v3_v3v3(cb, c, b);
mul_v3_fl(a, dot_v3v3(cb, ab) / div);
- add_v3_v3v3(i1, v1, a);
- copy_v3_v3(i2, i1);
+ add_v3_v3v3(r_i1, v1, a);
+ copy_v3_v3(r_i2, r_i1);
return 1; /* one intersection only */
}
@@ -2074,10 +2127,10 @@ int isect_line_line_epsilon_v3(
cross_v3_v3v3(cb, c, b);
mul_v3_fl(a, dot_v3v3(cb, ab) / dot_v3v3(ab, ab));
- add_v3_v3v3(i1, v1, a);
+ add_v3_v3v3(r_i1, v1, a);
/* for the second line, just substract the offset from the first intersection point */
- sub_v3_v3v3(i2, i1, t);
+ sub_v3_v3v3(r_i2, r_i1, t);
return 2; /* two nearest points */
}
@@ -2085,10 +2138,11 @@ int isect_line_line_epsilon_v3(
int isect_line_line_v3(
const float v1[3], const float v2[3],
- const float v3[3], const float v4[3], float i1[3], float i2[3])
+ const float v3[3], const float v4[3],
+ float r_i1[3], float r_i2[3])
{
const float epsilon = 0.000001f;
- return isect_line_line_epsilon_v3(v1, v2, v3, v4, i1, i2, epsilon);
+ return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon);
}
/** Intersection point strictly between the two lines
@@ -2149,9 +2203,11 @@ bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float mi
min2[0] < max1[0] && min2[1] < max1[1] && min2[2] < max1[2]);
}
-void isect_ray_aabb_initialize(IsectRayAABBData *data, const float ray_start[3], const float ray_direction[3])
+void isect_ray_aabb_v3_precalc(
+ struct IsectRayAABB_Precalc *data,
+ const float ray_origin[3], const float ray_direction[3])
{
- copy_v3_v3(data->ray_start, ray_start);
+ copy_v3_v3(data->ray_origin, ray_origin);
data->ray_inv_dir[0] = 1.0f / ray_direction[0];
data->ray_inv_dir[1] = 1.0f / ray_direction[1];
@@ -2163,20 +2219,20 @@ void isect_ray_aabb_initialize(IsectRayAABBData *data, const float ray_start[3],
}
/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
-bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3],
- const float bb_max[3], float *tmin_out)
+bool isect_ray_aabb_v3(
+ const struct IsectRayAABB_Precalc *data, const float bb_min[3],
+ const float bb_max[3], float *tmin_out)
{
float bbox[2][3];
- float tmin, tmax, tymin, tymax, tzmin, tzmax;
copy_v3_v3(bbox[0], bb_min);
copy_v3_v3(bbox[1], bb_max);
- tmin = (bbox[data->sign[0]][0] - data->ray_start[0]) * data->ray_inv_dir[0];
- tmax = (bbox[1 - data->sign[0]][0] - data->ray_start[0]) * data->ray_inv_dir[0];
+ float tmin = (bbox[data->sign[0]][0] - data->ray_origin[0]) * data->ray_inv_dir[0];
+ float tmax = (bbox[1 - data->sign[0]][0] - data->ray_origin[0]) * data->ray_inv_dir[0];
- tymin = (bbox[data->sign[1]][1] - data->ray_start[1]) * data->ray_inv_dir[1];
- tymax = (bbox[1 - data->sign[1]][1] - data->ray_start[1]) * data->ray_inv_dir[1];
+ const float tymin = (bbox[data->sign[1]][1] - data->ray_origin[1]) * data->ray_inv_dir[1];
+ const float tymax = (bbox[1 - data->sign[1]][1] - data->ray_origin[1]) * data->ray_inv_dir[1];
if ((tmin > tymax) || (tymin > tmax))
return false;
@@ -2187,8 +2243,8 @@ bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3],
if (tymax < tmax)
tmax = tymax;
- tzmin = (bbox[data->sign[2]][2] - data->ray_start[2]) * data->ray_inv_dir[2];
- tzmax = (bbox[1 - data->sign[2]][2] - data->ray_start[2]) * data->ray_inv_dir[2];
+ const float tzmin = (bbox[data->sign[2]][2] - data->ray_origin[2]) * data->ray_inv_dir[2];
+ const float tzmax = (bbox[1 - data->sign[2]][2] - data->ray_origin[2]) * data->ray_inv_dir[2];
if ((tmin > tzmax) || (tzmin > tmax))
return false;
@@ -2206,32 +2262,266 @@ bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3],
return true;
}
+void dist_squared_ray_to_aabb_v3_precalc(
+ struct NearestRayToAABB_Precalc *data,
+ const float ray_origin[3], const float ray_direction[3])
+{
+ float dir_sq[3];
+
+ for (int i = 0; i < 3; i++) {
+ data->ray_origin[i] = ray_origin[i];
+ data->ray_direction[i] = ray_direction[i];
+ data->ray_inv_dir[i] = (data->ray_direction[i] != 0.0f) ? (1.0f / data->ray_direction[i]) : FLT_MAX;
+ /* It has to be a function of `ray_inv_dir`,
+ * since the division of 1 by 0.0f, can be -inf or +inf */
+ data->sign[i] = (data->ray_inv_dir[i] < 0.0f);
+
+ dir_sq[i] = SQUARE(data->ray_direction[i]);
+ }
+
+ /* `diag_sq` Length square of each face diagonal */
+ float diag_sq[3] = {
+ dir_sq[1] + dir_sq[2],
+ dir_sq[0] + dir_sq[2],
+ dir_sq[0] + dir_sq[1],
+ };
+ data->idiag_sq[0] = (diag_sq[0] > FLT_EPSILON) ? (1.0f / diag_sq[0]) : FLT_MAX;
+ data->idiag_sq[1] = (diag_sq[1] > FLT_EPSILON) ? (1.0f / diag_sq[1]) : FLT_MAX;
+ data->idiag_sq[2] = (diag_sq[2] > FLT_EPSILON) ? (1.0f / diag_sq[2]) : FLT_MAX;
+
+ data->cdot_axis[0] = data->ray_direction[0] * data->idiag_sq[0];
+ data->cdot_axis[1] = data->ray_direction[1] * data->idiag_sq[1];
+ data->cdot_axis[2] = data->ray_direction[2] * data->idiag_sq[2];
+}
+
+/**
+ * Returns the squared distance from a ray to a bound-box `AABB`.
+ * It is based on `fast_ray_nearest_hit` solution to obtain
+ * the coordinates of the nearest edge of Bound Box to the ray
+ */
+float dist_squared_ray_to_aabb_v3(
+ const struct NearestRayToAABB_Precalc *data,
+ const float bb_min[3], const float bb_max[3],
+ bool r_axis_closest[3])
+{
+ /* `tmin` is a vector that has the smaller distances to each of the
+ * infinite planes of the `AABB` faces (hit in nearest face X plane,
+ * nearest face Y plane and nearest face Z plane) */
+ float local_bvmin[3], local_bvmax[3];
+
+ if (data->sign[0] == 0) {
+ local_bvmin[0] = bb_min[0] - data->ray_origin[0];
+ local_bvmax[0] = bb_max[0] - data->ray_origin[0];
+ }
+ else {
+ local_bvmin[0] = bb_max[0] - data->ray_origin[0];
+ local_bvmax[0] = bb_min[0] - data->ray_origin[0];
+ }
+
+ if (data->sign[1] == 0) {
+ local_bvmin[1] = bb_min[1] - data->ray_origin[1];
+ local_bvmax[1] = bb_max[1] - data->ray_origin[1];
+ }
+ else {
+ local_bvmin[1] = bb_max[1] - data->ray_origin[1];
+ local_bvmax[1] = bb_min[1] - data->ray_origin[1];
+ }
+
+ if (data->sign[2] == 0) {
+ local_bvmin[2] = bb_min[2] - data->ray_origin[2];
+ local_bvmax[2] = bb_max[2] - data->ray_origin[2];
+ }
+ else {
+ local_bvmin[2] = bb_max[2] - data->ray_origin[2];
+ local_bvmax[2] = bb_min[2] - data->ray_origin[2];
+ }
+
+ const float tmin[3] = {
+ local_bvmin[0] * data->ray_inv_dir[0],
+ local_bvmin[1] * data->ray_inv_dir[1],
+ local_bvmin[2] * data->ray_inv_dir[2],
+ };
+
+ /* `tmax` is a vector that has the longer distances to each of the
+ * infinite planes of the `AABB` faces (hit in farthest face X plane,
+ * farthest face Y plane and farthest face Z plane) */
+ const float tmax[3] = {
+ local_bvmax[0] * data->ray_inv_dir[0],
+ local_bvmax[1] * data->ray_inv_dir[1],
+ local_bvmax[2] * data->ray_inv_dir[2],
+ };
+ /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/
+ float v1[3], v2[3];
+ /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin)
+ * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/
+ float rtmin, rtmax, mul, rdist;
+ /* `main_axis` is the axis equivalent to edge close to the ray */
+ int main_axis;
+
+ r_axis_closest[0] = false;
+ r_axis_closest[1] = false;
+ r_axis_closest[2] = false;
+
+ /* *** min_axis_v3(tmax) *** */
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ // printf("# Hit in X %s\n", data->sign[0] ? "min", "max");
+ rtmax = tmax[0];
+ v1[0] = v2[0] = local_bvmax[0];
+ mul = local_bvmax[0] * data->ray_direction[0];
+ main_axis = 3;
+ r_axis_closest[0] = data->sign[0];
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max");
+ rtmax = tmax[1];
+ v1[1] = v2[1] = local_bvmax[1];
+ mul = local_bvmax[1] * data->ray_direction[1];
+ main_axis = 2;
+ r_axis_closest[1] = data->sign[1];
+ }
+ else {
+ // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max");
+ rtmax = tmax[2];
+ v1[2] = v2[2] = local_bvmax[2];
+ mul = local_bvmax[2] * data->ray_direction[2];
+ main_axis = 1;
+ r_axis_closest[2] = data->sign[2];
+ }
+
+ /* *** max_axis_v3(tmin) *** */
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ // printf("# To X %s\n", data->sign[0] ? "max", "min");
+ rtmin = tmin[0];
+ v1[0] = v2[0] = local_bvmin[0];
+ mul += local_bvmin[0] * data->ray_direction[0];
+ main_axis -= 3;
+ r_axis_closest[0] = !data->sign[0];
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ // printf("# To Y %s\n", data->sign[1] ? "max", "min");
+ rtmin = tmin[1];
+ v1[1] = v2[1] = local_bvmin[1];
+ mul += local_bvmin[1] * data->ray_direction[1];
+ main_axis -= 1;
+ r_axis_closest[1] = !data->sign[1];
+ }
+ else {
+ // printf("# To Z %s\n", data->sign[2] ? "max", "min");
+ rtmin = tmin[2];
+ v1[2] = v2[2] = local_bvmin[2];
+ mul += local_bvmin[2] * data->ray_direction[2];
+ main_axis -= 2;
+ r_axis_closest[2] = !data->sign[2];
+ }
+ /* *** end min/max axis *** */
+
+
+ /* `if rtmax < 0`, the whole `AABB` is behing us */
+ if ((rtmax < 0.0f) && (rtmin < 0.0f)) {
+ return FLT_MAX;
+ }
+
+ if (main_axis < 0) {
+ main_axis += 3;
+ }
+
+ if (data->sign[main_axis] == 0) {
+ v1[main_axis] = local_bvmin[main_axis];
+ v2[main_axis] = local_bvmax[main_axis];
+ }
+ else {
+ v1[main_axis] = local_bvmax[main_axis];
+ v2[main_axis] = local_bvmin[main_axis];
+ }
+
+ /* if rtmin < rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+ const float proj = rtmin * data->ray_direction[main_axis];
+ rdist = 0.0f;
+ r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
+ }
+ else {
+ /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */
+ const float proj = mul * data->cdot_axis[main_axis];
+ float depth;
+ if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */
+ /* `depth` is equivalent the distance from the origin to the point v1,
+ * Here's a faster way to calculate the dot product of v1 and ray
+ * (depth = dot_v3v3(v1, data->ray.direction))*/
+ depth = mul + data->ray_direction[main_axis] * v1[main_axis];
+ rdist = len_squared_v3(v1) - SQUARE(depth);
+ r_axis_closest[main_axis] = true;
+ }
+ else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */
+ depth = mul + data->ray_direction[main_axis] * v2[main_axis];
+ rdist = len_squared_v3(v2) - SQUARE(depth);
+ r_axis_closest[main_axis] = false;
+ }
+ else { /* the nearest point of the ray is on the edge of the `AABB`. */
+ float v[2];
+ mul *= data->idiag_sq[main_axis];
+ if (main_axis == 0) {
+ v[0] = (mul * data->ray_direction[1]) - v1[1];
+ v[1] = (mul * data->ray_direction[2]) - v1[2];
+ }
+ else if (main_axis == 1) {
+ v[0] = (mul * data->ray_direction[0]) - v1[0];
+ v[1] = (mul * data->ray_direction[2]) - v1[2];
+ }
+ else {
+ v[0] = (mul * data->ray_direction[0]) - v1[0];
+ v[1] = (mul * data->ray_direction[1]) - v1[1];
+ }
+ rdist = len_squared_v2(v);
+ r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj);
+ }
+ }
+
+ return rdist;
+}
+
/* find closest point to p on line through (l1, l2) and return lambda,
* where (0 <= lambda <= 1) when cp is in the line segment (l1, l2)
*/
-float closest_to_line_v3(float cp[3], const float p[3], const float l1[3], const float l2[3])
+float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
{
float h[3], u[3], lambda;
sub_v3_v3v3(u, l2, l1);
sub_v3_v3v3(h, p, l1);
lambda = dot_v3v3(u, h) / dot_v3v3(u, u);
- cp[0] = l1[0] + u[0] * lambda;
- cp[1] = l1[1] + u[1] * lambda;
- cp[2] = l1[2] + u[2] * lambda;
+ r_close[0] = l1[0] + u[0] * lambda;
+ r_close[1] = l1[1] + u[1] * lambda;
+ r_close[2] = l1[2] + u[2] * lambda;
return lambda;
}
-float closest_to_line_v2(float cp[2], const float p[2], const float l1[2], const float l2[2])
+float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
{
float h[2], u[2], lambda;
sub_v2_v2v2(u, l2, l1);
sub_v2_v2v2(h, p, l1);
lambda = dot_v2v2(u, h) / dot_v2v2(u, u);
- cp[0] = l1[0] + u[0] * lambda;
- cp[1] = l1[1] + u[1] * lambda;
+ r_close[0] = l1[0] + u[0] * lambda;
+ r_close[1] = l1[1] + u[1] * lambda;
return lambda;
}
+float ray_point_factor_v3_ex(
+ const float p[3], const float ray_origin[3], const float ray_direction[3],
+ const float epsilon, const float fallback)
+{
+ float p_relative[3];
+ sub_v3_v3v3(p_relative, p, ray_origin);
+ const float dot = len_squared_v3(ray_direction);
+ return (dot > epsilon) ? (dot_v3v3(ray_direction, p_relative) / dot) : fallback;
+}
+
+float ray_point_factor_v3(
+ const float p[3], const float ray_origin[3], const float ray_direction[3])
+{
+ return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
+}
+
/**
* A simplified version of #closest_to_line_v3
* we only need to return the ``lambda``
@@ -2251,8 +2541,8 @@ float line_point_factor_v3_ex(
return (dot_v3v3(u, h) / dot_v3v3(u, u));
#else
/* better check for zero */
- dot = dot_v3v3(u, u);
- return (fabsf(dot) > epsilon) ? (dot_v3v3(u, h) / dot) : fallback;
+ dot = len_squared_v3(u);
+ return (dot > epsilon) ? (dot_v3v3(u, h) / dot) : fallback;
#endif
}
float line_point_factor_v3(
@@ -2273,8 +2563,8 @@ float line_point_factor_v2_ex(
return (dot_v2v2(u, h) / dot_v2v2(u, u));
#else
/* better check for zero */
- dot = dot_v2v2(u, u);
- return (fabsf(dot) > epsilon) ? (dot_v2v2(u, h) / dot) : fallback;
+ dot = len_squared_v2(u);
+ return (dot > epsilon) ? (dot_v2v2(u, h) / dot) : fallback;
#endif
}
@@ -2364,7 +2654,9 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3
sub_v3_v3v3(rp, p, v1);
h = dot_v3v3(q, rp) / dot_v3v3(q, q);
- return (h < 0.0f || h > 1.0f) ? false : true;
+ /* note: when 'h' is nan/-nan, this check returns false
+ * without explicit check - covering the degenerate case */
+ return (h >= 0.0f && h <= 1.0f);
}
#if 0
@@ -2404,26 +2696,20 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v
* \return True when \a p is inside the triangle.
* \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin.
*/
-bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3],
- float r_vi[3])
+bool isect_point_tri_v3(
+ const float p[3], const float v1[3], const float v2[3], const float v3[3],
+ float r_isect_co[3])
{
if (isect_point_tri_prism_v3(p, v1, v2, v3)) {
- float no[3], n1[3], n2[3];
+ float plane[4];
+ float no[3];
/* Could use normal_tri_v3, but doesn't have to be unit-length */
- sub_v3_v3v3(n1, v1, v2);
- sub_v3_v3v3(n2, v2, v3);
- cross_v3_v3v3(no, n1, n2);
-
- if (LIKELY(len_squared_v3(no) != 0.0f)) {
- float plane[4];
- plane_from_point_normal_v3(plane, v1, no);
- closest_to_plane_v3(r_vi, plane, p);
- }
- else {
- /* degenerate */
- copy_v3_v3(r_vi, p);
- }
+ cross_tri_v3(no, v1, v2, v3);
+ BLI_assert(len_squared_v3(no) != 0.0f);
+
+ plane_from_point_normal_v3(plane, v1, no);
+ closest_to_plane_v3(r_isect_co, plane, p);
return true;
}
@@ -2432,9 +2718,12 @@ bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3],
}
}
-bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4])
+bool clip_segment_v3_plane(
+ const float p1[3], const float p2[3],
+ const float plane[4],
+ float r_p1[3], float r_p2[3])
{
- float dp[3], div, t, pc[3];
+ float dp[3], div;
sub_v3_v3v3(dp, p2, p1);
div = dot_v3v3(dp, plane);
@@ -2442,98 +2731,96 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4])
if (div == 0.0f) /* parallel */
return true;
- t = -plane_point_side_v3(plane, p1) / div;
+ float t = -plane_point_side_v3(plane, p1);
if (div > 0.0f) {
/* behind plane, completely clipped */
- if (t >= 1.0f) {
- zero_v3(p1);
- zero_v3(p2);
+ if (t >= div) {
return false;
}
-
- /* intersect plane */
- if (t > 0.0f) {
- madd_v3_v3v3fl(pc, p1, dp, t);
- copy_v3_v3(p1, pc);
+ else if (t > 0.0f) {
+ const float p1_copy[3] = {UNPACK3(p1)};
+ copy_v3_v3(r_p2, p2);
+ madd_v3_v3v3fl(r_p1, p1_copy, dp, t / div);
return true;
}
-
- return true;
}
else {
/* behind plane, completely clipped */
- if (t <= 0.0f) {
- zero_v3(p1);
- zero_v3(p2);
+ if (t >= 0.0f) {
return false;
}
-
- /* intersect plane */
- if (t < 1.0f) {
- madd_v3_v3v3fl(pc, p1, dp, t);
- copy_v3_v3(p2, pc);
+ else if (t > div) {
+ const float p1_copy[3] = {UNPACK3(p1)};
+ copy_v3_v3(r_p1, p1);
+ madd_v3_v3v3fl(r_p2, p1_copy, dp, t / div);
return true;
}
-
- return true;
}
+
+ /* incase input/output values match (above also) */
+ const float p1_copy[3] = {UNPACK3(p1)};
+ copy_v3_v3(r_p2, p2);
+ copy_v3_v3(r_p1, p1_copy);
+ return true;
}
-bool clip_segment_v3_plane_n(float r_p1[3], float r_p2[3], float plane_array[][4], const int plane_tot)
+bool clip_segment_v3_plane_n(
+ const float p1[3], const float p2[3],
+ const float plane_array[][4], const int plane_tot,
+ float r_p1[3], float r_p2[3])
{
/* intersect from both directions */
- float p1[3], p2[3], dp[3], dp_orig[3];
- int i;
- copy_v3_v3(p1, r_p1);
- copy_v3_v3(p2, r_p2);
+ float p1_fac = 0.0f, p2_fac = 1.0f;
+ float dp[3];
sub_v3_v3v3(dp, p2, p1);
- copy_v3_v3(dp_orig, dp);
- for (i = 0; i < plane_tot; i++) {
+ for (int i = 0; i < plane_tot; i++) {
const float *plane = plane_array[i];
const float div = dot_v3v3(dp, plane);
if (div != 0.0f) {
- const float t = -plane_point_side_v3(plane, p1) / div;
+ float t = -plane_point_side_v3(plane, p1);
if (div > 0.0f) {
- /* clip a */
- if (t >= 1.0f) {
+ /* clip p1 lower bounds */
+ if (t >= div) {
return false;
}
-
- /* intersect plane */
- if (t > 0.0f) {
- madd_v3_v3v3fl(p1, p1, dp, t);
- /* recalc direction and test for flipping */
- sub_v3_v3v3(dp, p2, p1);
- if (dot_v3v3(dp, dp_orig) < 0.0f) {
- return false;
+ else if (t > 0.0f) {
+ t /= div;
+ if (t > p1_fac) {
+ p1_fac = t;
+ if (p1_fac > p2_fac) {
+ return false;
+ }
}
}
}
else if (div < 0.0f) {
- /* clip b */
- if (t <= 0.0f) {
+ /* clip p2 upper bounds */
+ if (t >= 0.0f) {
return false;
}
-
- /* intersect plane */
- if (t < 1.0f) {
- madd_v3_v3v3fl(p2, p1, dp, t);
- /* recalc direction and test for flipping */
- sub_v3_v3v3(dp, p2, p1);
- if (dot_v3v3(dp, dp_orig) < 0.0f) {
- return false;
+ else if (t > div) {
+ t /= div;
+ if (t < p2_fac) {
+ p2_fac = t;
+ if (p1_fac > p2_fac) {
+ return false;
+ }
}
}
}
}
}
- copy_v3_v3(r_p1, p1);
- copy_v3_v3(r_p2, p2);
+ /* incase input/output values match */
+ const float p1_copy[3] = {UNPACK3(p1)};
+
+ madd_v3_v3v3fl(r_p1, p1_copy, dp, p1_fac);
+ madd_v3_v3v3fl(r_p2, p1_copy, dp, p2_fac);
+
return true;
}
@@ -2548,8 +2835,8 @@ void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int
signed char iy;
/* if x1 == x2 or y1 == y2, then it does not matter what we set here */
- int delta_x = (x2 > x1 ? (ix = 1, x2 - x1) : (ix = -1, x1 - x2)) << 1;
- int delta_y = (y2 > y1 ? (iy = 1, y2 - y1) : (iy = -1, y1 - y2)) << 1;
+ int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1;
+ int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1;
if (callback(x1, y1, userData) == 0) {
return;
@@ -2601,10 +2888,20 @@ void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int
}
}
+/**
+ * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
+ * note that \a x_end will always be greater than \a x, so we can use:
+ *
+ * \code{.c}
+ * do {
+ * func(x, y);
+ * } while (++x != x_end);
+ * \endcode
+ */
void fill_poly_v2i_n(
const int xmin, const int ymin, const int xmax, const int ymax,
const int verts[][2], const int nr,
- void (*callback)(int, int, void *), void *userData)
+ void (*callback)(int x, int x_end, int y, void *), void *userData)
{
/* originally by Darel Rex Finley, 2007 */
@@ -2645,9 +2942,18 @@ void fill_poly_v2i_n(
if (node_x[i + 1] > xmin) {
if (node_x[i ] < xmin) node_x[i ] = xmin;
if (node_x[i + 1] > xmax) node_x[i + 1] = xmax;
+
+#if 0
+ /* for many x/y calls */
for (j = node_x[i]; j < node_x[i + 1]; j++) {
callback(j - xmin, pixel_y - ymin, userData);
}
+#else
+ /* for single call per x-span */
+ if (node_x[i] < node_x[i + 1]) {
+ callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData);
+ }
+#endif
}
}
}
@@ -3570,8 +3876,8 @@ void perspective_m4(float mat[4][4], const float left, const float right, const
mat[2][3] = -1.0f;
mat[3][2] = (-2.0f * nearClip * farClip) / Zdelta;
mat[0][1] = mat[0][2] = mat[0][3] =
- mat[1][0] = mat[1][2] = mat[1][3] =
- mat[3][0] = mat[3][1] = mat[3][3] = 0.0f;
+ mat[1][0] = mat[1][2] = mat[1][3] =
+ mat[3][0] = mat[3][1] = mat[3][3] = 0.0f;
}
@@ -4555,61 +4861,65 @@ float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], fl
return contrib;
}
-/* evaluate if entire quad is a proper convex quad */
+/**
+ * Evaluate if entire quad is a proper convex quad
+ */
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
- float nor[3], nor_a[3], nor_b[3], vec[4][2];
- float mat[3][3];
- const bool is_ok_a = (normal_tri_v3(nor_a, v1, v2, v3) > FLT_EPSILON);
- const bool is_ok_b = (normal_tri_v3(nor_b, v1, v3, v4) > FLT_EPSILON);
-
- /* define projection, do both trias apart, quad is undefined! */
-
- /* check normal length incase one size is zero area */
- if (is_ok_a) {
- if (is_ok_b) {
- /* use both, most common outcome */
-
- /* when the face is folded over as 2 tris we probably don't want to create
- * a quad from it, but go ahead with the intersection test since this
- * isn't a function for degenerate faces */
- if (UNLIKELY(dot_v3v3(nor_a, nor_b) < 0.0f)) {
- /* flip so adding normals in the opposite direction
- * doesn't give a zero length vector */
- negate_v3(nor_b);
- }
+ /**
+ * Method projects points onto a plane and checks its convex using following method:
+ *
+ * - Create a plane from the cross-product of both diagonal vectors.
+ * - Project all points onto the plane.
+ * - Subtract for direction vectors.
+ * - Return true if all corners cross-products point the direction of the plane.
+ */
- add_v3_v3v3(nor, nor_a, nor_b);
- normalize_v3(nor);
- }
- else {
- copy_v3_v3(nor, nor_a); /* only 'a' */
+ /* non-unit length normal, used as a projection plane */
+ float plane[3];
+
+ {
+ float v13[3], v24[3];
+
+ sub_v3_v3v3(v13, v1, v3);
+ sub_v3_v3v3(v24, v2, v4);
+
+ cross_v3_v3v3(plane, v13, v24);
+
+ if (len_squared_v3(plane) < FLT_EPSILON) {
+ return false;
}
}
- else {
- if (is_ok_b) {
- copy_v3_v3(nor, nor_b); /* only 'b' */
- }
- else {
- return false; /* both zero, we can't do anything useful here */
- }
+
+ const float *quad_coords[4] = {v1, v2, v3, v4};
+ float quad_proj[4][3];
+
+ for (int i = 0; i < 4; i++) {
+ project_plane_v3_v3v3(quad_proj[i], quad_coords[i], plane);
+ }
+
+ float quad_dirs[4][3];
+ for (int i = 0, j = 3; i < 4; j = i++) {
+ sub_v3_v3v3(quad_dirs[i], quad_proj[i], quad_proj[j]);
}
- axis_dominant_v3_to_m3(mat, nor);
+ float test_dir[3];
- mul_v2_m3v3(vec[0], mat, v1);
- mul_v2_m3v3(vec[1], mat, v2);
- mul_v2_m3v3(vec[2], mat, v3);
- mul_v2_m3v3(vec[3], mat, v4);
+#define CROSS_SIGN(dir_a, dir_b) \
+ ((void)cross_v3_v3v3(test_dir, dir_a, dir_b), (dot_v3v3(plane, test_dir) > 0.0f))
- /* linetests, the 2 diagonals have to instersect to be convex */
- return (isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0);
+ return (CROSS_SIGN(quad_dirs[0], quad_dirs[1]) &&
+ CROSS_SIGN(quad_dirs[1], quad_dirs[2]) &&
+ CROSS_SIGN(quad_dirs[2], quad_dirs[3]) &&
+ CROSS_SIGN(quad_dirs[3], quad_dirs[0]));
+
+#undef CROSS_SIGN
}
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{
/* linetests, the 2 diagonals have to instersect to be convex */
- return (isect_line_line_v2(v1, v3, v2, v4) > 0);
+ return (isect_seg_seg_v2(v1, v3, v2, v4) > 0);
}
bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c
index 44b17681540..68a2e68db4f 100644
--- a/source/blender/blenlib/intern/math_geom_inline.c
+++ b/source/blender/blenlib/intern/math_geom_inline.c
@@ -199,6 +199,17 @@ MINLINE int axis_dominant_v3_single(const float vec[3])
((y > z) ? 1 : 2));
}
+/* the dominant axis of an orthogonal vector */
+MINLINE int axis_dominant_v3_ortho_single(const float vec[3])
+{
+ const float x = fabsf(vec[0]);
+ const float y = fabsf(vec[1]);
+ const float z = fabsf(vec[2]);
+ return ((x < y) ?
+ ((x < z) ? 0 : 2) :
+ ((y < z) ? 1 : 2));
+}
+
MINLINE int max_axis_v3(const float vec[3])
{
const float x = vec[0];
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index b45d8b4c13b..069d23e7147 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -262,7 +262,7 @@ void BLI_bicubic_interpolation_char(const unsigned char *buffer, unsigned char *
/* BILINEAR INTERPOLATION */
BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const float *float_buffer,
unsigned char *byte_output, float *float_output, int width, int height,
- int components, float u, float v)
+ int components, float u, float v, bool wrap_x, bool wrap_y)
{
float a, b;
float a_b, ma_b, a_mb, ma_mb;
@@ -279,11 +279,21 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
const float *row1, *row2, *row3, *row4;
float empty[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- /* sample area entirely outside image? */
- if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) {
- copy_vn_fl(float_output, components, 0.0f);
- return;
+ /* pixel value must be already wrapped, however values at boundaries may flip */
+ if (wrap_x) {
+ if (x1 < 0) x1 = width - 1;
+ if (x2 >= width) x2 = 0;
}
+ if (wrap_y) {
+ if (y1 < 0) y1 = height - 1;
+ if (y2 >= height) y2 = 0;
+ }
+
+ CLAMP(x1, 0, width - 1);
+ CLAMP(x2, 0, width - 1);
+
+ CLAMP(y1, 0, height - 1);
+ CLAMP(y2, 0, height - 1);
/* sample including outside of edges of image */
if (x1 < 0 || y1 < 0) row1 = empty;
@@ -364,15 +374,28 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f
void BLI_bilinear_interpolation_fl(const float *buffer, float *output, int width, int height,
int components, float u, float v)
{
- bilinear_interpolation(NULL, buffer, NULL, output, width, height, components, u, v);
+ bilinear_interpolation(NULL, buffer, NULL, output, width, height, components, u, v, false, false);
}
void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height,
int components, float u, float v)
{
- bilinear_interpolation(buffer, NULL, output, NULL, width, height, components, u, v);
+ bilinear_interpolation(buffer, NULL, output, NULL, width, height, components, u, v, false, false);
}
+void BLI_bilinear_interpolation_wrap_fl(const float *buffer, float *output, int width, int height,
+ int components, float u, float v, bool wrap_x, bool wrap_y)
+{
+ bilinear_interpolation(NULL, buffer, NULL, output, width, height, components, u, v, wrap_x, wrap_y);
+}
+
+void BLI_bilinear_interpolation_wrap_char(const unsigned char *buffer, unsigned char *output, int width, int height,
+ int components, float u, float v, bool wrap_x, bool wrap_y)
+{
+ bilinear_interpolation(buffer, NULL, output, NULL, width, height, components, u, v, wrap_x, wrap_y);
+}
+
+
/**************************************************************************
* Filtering method based on
* "Creating raster omnimax images from multiple perspective views using the elliptical weighted average filter"
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 33d0fb87aca..52ff6fd3e8a 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -516,7 +516,8 @@ void mul_v3_mat3_m4v3(float r[3], float mat[4][4], const float vec[3])
void mul_project_m4_v3(float mat[4][4], float vec[3])
{
- const float w = mul_project_m4_v3_zfac(mat, vec);
+ /* absolute value to not flip the frustum upside down behind the camera */
+ const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
mul_m4_v3(mat, vec);
vec[0] /= w;
@@ -526,7 +527,7 @@ void mul_project_m4_v3(float mat[4][4], float vec[3])
void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3])
{
- const float w = mul_project_m4_v3_zfac(mat, vec);
+ const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
mul_v3_m4v3(r, mat, vec);
r[0] /= w;
@@ -536,7 +537,7 @@ void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3])
void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3])
{
- const float w = mul_project_m4_v3_zfac(mat, vec);
+ const float w = fabsf(mul_project_m4_v3_zfac(mat, vec));
mul_v2_m4v3(r, mat, vec);
r[0] /= w;
@@ -1247,36 +1248,74 @@ bool is_uniform_scaled_m4(float m[4][4])
return is_uniform_scaled_m3(t);
}
+void normalize_m3_ex(float mat[3][3], float r_scale[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ r_scale[i] = normalize_v3(mat[i]);
+ }
+}
void normalize_m3(float mat[3][3])
{
- normalize_v3(mat[0]);
- normalize_v3(mat[1]);
- normalize_v3(mat[2]);
+ int i;
+ for (i = 0; i < 3; i++) {
+ normalize_v3(mat[i]);
+ }
}
+void normalize_m3_m3_ex(float rmat[3][3], float mat[3][3], float r_scale[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ r_scale[i] = normalize_v3_v3(rmat[i], mat[i]);
+ }
+}
void normalize_m3_m3(float rmat[3][3], float mat[3][3])
{
- normalize_v3_v3(rmat[0], mat[0]);
- normalize_v3_v3(rmat[1], mat[1]);
- normalize_v3_v3(rmat[2], mat[2]);
+ int i;
+ for (i = 0; i < 3; i++) {
+ normalize_v3_v3(rmat[i], mat[i]);
+ }
}
+void normalize_m4_ex(float mat[4][4], float r_scale[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ r_scale[i] = normalize_v3(mat[i]);
+ if (r_scale[i] != 0.0f) {
+ mat[i][3] /= r_scale[i];
+ }
+ }
+}
void normalize_m4(float mat[4][4])
{
- float len;
-
- len = normalize_v3(mat[0]);
- if (len != 0.0f) mat[0][3] /= len;
- len = normalize_v3(mat[1]);
- if (len != 0.0f) mat[1][3] /= len;
- len = normalize_v3(mat[2]);
- if (len != 0.0f) mat[2][3] /= len;
+ int i;
+ for (i = 0; i < 3; i++) {
+ float len = normalize_v3(mat[i]);
+ if (len != 0.0f) {
+ mat[i][3] /= len;
+ }
+ }
}
+void normalize_m4_m4_ex(float rmat[4][4], float mat[4][4], float r_scale[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ r_scale[i] = normalize_v3_v3(rmat[i], mat[i]);
+ rmat[i][3] = (r_scale[i] != 0.0f) ? (mat[i][3] / r_scale[i]) : mat[i][3];
+ }
+ copy_v4_v4(rmat[3], mat[3]);
+}
void normalize_m4_m4(float rmat[4][4], float mat[4][4])
{
- copy_m4_m4(rmat, mat);
- normalize_m4(rmat);
+ int i;
+ for (i = 0; i < 3; i++) {
+ float len = normalize_v3_v3(rmat[i], mat[i]);
+ rmat[i][3] = (len != 0.0f) ? (mat[i][3] / len) : mat[i][3];
+ }
+ copy_v4_v4(rmat[3], mat[3]);
}
void adjoint_m2_m2(float m1[2][2], float m[2][2])
@@ -1510,7 +1549,7 @@ void mat4_to_loc_quat(float loc[3], float quat[4], float wmat[4][4])
negate_m3(mat3_n);
}
- mat3_to_quat(quat, mat3_n);
+ mat3_normalized_to_quat(quat, mat3_n);
copy_v3_v3(loc, wmat[3]);
}
@@ -1518,8 +1557,37 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4]
{
float rot[3][3];
mat4_to_loc_rot_size(loc, rot, size, wmat);
- mat3_to_quat(quat, rot);
+ mat3_normalized_to_quat(quat, rot);
+}
+
+/**
+ * Right polar decomposition:
+ * M = UP
+ *
+ * U is the 'rotation'-like component, the closest orthogonal matrix to M.
+ * P is the 'scaling'-like component, defined in U space.
+ *
+ * See https://en.wikipedia.org/wiki/Polar_decomposition for more.
+ */
+#ifndef MATH_STANDALONE
+void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3])
+{
+ /* From svd decomposition (M = WSV*), we have:
+ * U = WV*
+ * P = VSV*
+ */
+ float W[3][3], S[3][3], V[3][3], Vt[3][3];
+ float sval[3];
+
+ BLI_svd_m3(mat3, W, sval, V);
+
+ size_to_mat3(S, sval);
+
+ transpose_m3_m3(Vt, V);
+ mul_m3_m3m3(r_U, W, Vt);
+ mul_m3_series(r_P, V, S, Vt);
}
+#endif
void scale_m3_fl(float m[3][3], float scale)
{
@@ -1625,8 +1693,8 @@ void blend_m3_m3m3(float out[3][3], float dst[3][3], float src[3][3], const floa
mat3_to_rot_size(drot, dscale, dst);
mat3_to_rot_size(srot, sscale, src);
- mat3_to_quat(dquat, drot);
- mat3_to_quat(squat, srot);
+ mat3_normalized_to_quat(dquat, drot);
+ mat3_normalized_to_quat(squat, srot);
/* do blending */
interp_qt_qtqt(fquat, dquat, squat, srcweight);
@@ -1648,8 +1716,8 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa
mat4_to_loc_rot_size(dloc, drot, dscale, dst);
mat4_to_loc_rot_size(sloc, srot, sscale, src);
- mat3_to_quat(dquat, drot);
- mat3_to_quat(squat, srot);
+ mat3_normalized_to_quat(dquat, drot);
+ mat3_normalized_to_quat(squat, srot);
/* do blending */
interp_v3_v3v3(floc, dloc, sloc, srcweight);
@@ -1660,6 +1728,78 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa
loc_quat_size_to_mat4(out, floc, fquat, fsize);
}
+/* for builds without Eigen */
+#ifndef MATH_STANDALONE
+/**
+ * A polar-decomposition-based interpolation between matrix A and matrix B.
+ *
+ * \note This code is about five times slower as the 'naive' interpolation done by \a blend_m3_m3m3
+ * (it typically remains below 2 usec on an average i74700, while \a blend_m3_m3m3 remains below 0.4 usec).
+ * However, it gives expected results even with non-uniformaly scaled matrices, see T46418 for an example.
+ *
+ * Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
+ *
+ * @return R the interpolated matrix.
+ * @param A the intput matrix which is totally effective with \a t = 0.0.
+ * @param B the intput matrix which is totally effective with \a t = 1.0.
+ * @param t the interpolation factor.
+ */
+void interp_m3_m3m3(float R[3][3], float A[3][3], float B[3][3], const float t)
+{
+ /* 'Rotation' component ('U' part of polar decomposition, the closest orthogonal matrix to M3 rot/scale
+ * transformation matrix), spherically interpolated. */
+ float U_A[3][3], U_B[3][3], U[3][3];
+ float quat_A[4], quat_B[4], quat[4];
+ /* 'Scaling' component ('P' part of polar decomposition, i.e. scaling in U-defined space), linearly interpolated. */
+ float P_A[3][3], P_B[3][3], P[3][3];
+
+ int i;
+
+ mat3_polar_decompose(A, U_A, P_A);
+ mat3_polar_decompose(B, U_B, P_B);
+
+ mat3_to_quat(quat_A, U_A);
+ mat3_to_quat(quat_B, U_B);
+ interp_qt_qtqt(quat, quat_A, quat_B, t);
+ quat_to_mat3(U, quat);
+
+ for (i = 0; i < 3; i++) {
+ interp_v3_v3v3(P[i], P_A[i], P_B[i], t);
+ }
+
+ /* And we reconstruct rot/scale matrix from interpolated polar components */
+ mul_m3_m3m3(R, U, P);
+}
+
+/**
+ * Complete transform matrix interpolation, based on polar-decomposition-based interpolation from interp_m3_m3m3.
+ *
+ * @return R the interpolated matrix.
+ * @param A the intput matrix which is totally effective with \a t = 0.0.
+ * @param B the intput matrix which is totally effective with \a t = 1.0.
+ * @param t the interpolation factor.
+ */
+void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t)
+{
+ float A3[3][3], B3[3][3], R3[3][3];
+
+ /* Location component, linearly interpolated. */
+ float loc_A[3], loc_B[3], loc[3];
+
+ copy_v3_v3(loc_A, A[3]);
+ copy_v3_v3(loc_B, B[3]);
+ interp_v3_v3v3(loc, loc_A, loc_B, t);
+
+ copy_m3_m4(A3, A);
+ copy_m3_m4(B3, B);
+
+ interp_m3_m3m3(R3, A3, B3, t);
+
+ copy_m4_m3(R, R3);
+ copy_v3_v3(R[3], loc);
+}
+#endif /* MATH_STANDALONE */
+
bool is_negative_m3(float mat[3][3])
{
float vec[3];
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 575710e8d75..d962e4f0fa7 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -154,6 +154,24 @@ void invert_qt_qt(float q1[4], const float q2[4])
invert_qt(q1);
}
+/**
+ * This is just conjugate_qt for cases we know \a q is unit-length.
+ * we could use #conjugate_qt directly, but use this function to show intent,
+ * and assert if its ever becomes non-unit-length.
+ */
+void invert_qt_normalized(float q[4])
+{
+ BLI_ASSERT_UNIT_QUAT(q);
+ conjugate_qt(q);
+
+}
+
+void invert_qt_qt_normalized(float q1[4], const float q2[4])
+{
+ copy_qt_qt(q1, q2);
+ invert_qt_normalized(q1);
+}
+
/* simple mult */
void mul_qt_fl(float q[4], const float f)
{
@@ -275,14 +293,11 @@ void quat_to_mat4(float m[4][4], const float q[4])
m[3][3] = 1.0f;
}
-void mat3_to_quat(float q[4], float wmat[3][3])
+void mat3_normalized_to_quat(float q[4], float mat[3][3])
{
double tr, s;
- float mat[3][3];
- /* work on a copy */
- copy_m3_m3(mat, wmat);
- normalize_m3(mat); /* this is needed AND a 'normalize_qt' in the end */
+ BLI_ASSERT_UNIT_M3(mat);
tr = 0.25 * (double)(1.0f + mat[0][0] + mat[1][1] + mat[2][2]);
@@ -326,13 +341,30 @@ void mat3_to_quat(float q[4], float wmat[3][3])
normalize_qt(q);
}
+void mat3_to_quat(float q[4], float m[3][3])
+{
+ float unit_mat[3][3];
+
+ /* work on a copy */
+ /* this is needed AND a 'normalize_qt' in the end */
+ normalize_m3_m3(unit_mat, m);
+ mat3_normalized_to_quat(q, unit_mat);
+}
+
+void mat4_normalized_to_quat(float q[4], float m[4][4])
+{
+ float mat3[3][3];
+
+ copy_m3_m4(mat3, m);
+ mat3_normalized_to_quat(q, mat3);
+}
void mat4_to_quat(float q[4], float m[4][4])
{
- float mat[3][3];
+ float mat3[3][3];
- copy_m3_m4(mat, m);
- mat3_to_quat(q, mat);
+ copy_m3_m4(mat3, m);
+ mat3_to_quat(q, mat3);
}
void mat3_to_quat_is_ok(float q[4], float wmat[3][3])
@@ -936,7 +968,16 @@ void axis_angle_to_mat4(float mat[4][4], const float axis[3], const float angle)
copy_m4_m3(mat, tmat);
}
-/* 3x3 matrix to axis angle (see Mat4ToVecRot too) */
+/* 3x3 matrix to axis angle */
+void mat3_normalized_to_axis_angle(float axis[3], float *angle, float mat[3][3])
+{
+ float q[4];
+
+ /* use quaternions as intermediate representation */
+ /* TODO: it would be nicer to go straight there... */
+ mat3_normalized_to_quat(q, mat);
+ quat_to_axis_angle(axis, angle, q);
+}
void mat3_to_axis_angle(float axis[3], float *angle, float mat[3][3])
{
float q[4];
@@ -947,7 +988,18 @@ void mat3_to_axis_angle(float axis[3], float *angle, float mat[3][3])
quat_to_axis_angle(axis, angle, q);
}
-/* 4x4 matrix to axis angle (see Mat4ToVecRot too) */
+/* 4x4 matrix to axis angle */
+void mat4_normalized_to_axis_angle(float axis[3], float *angle, float mat[4][4])
+{
+ float q[4];
+
+ /* use quaternions as intermediate representation */
+ /* TODO: it would be nicer to go straight there... */
+ mat4_normalized_to_quat(q, mat);
+ quat_to_axis_angle(axis, angle, q);
+}
+
+/* 4x4 matrix to axis angle */
void mat4_to_axis_angle(float axis[3], float *angle, float mat[4][4])
{
float q[4];
@@ -1016,6 +1068,20 @@ void angle_to_mat2(float mat[2][2], const float angle)
mat[1][1] = angle_cos;
}
+void axis_angle_to_quat_single(float q[4], const char axis, const float angle)
+{
+ const float angle_half = angle * 0.5f;
+ const float angle_cos = cosf(angle_half);
+ const float angle_sin = sinf(angle_half);
+ const int axis_index = (axis - 'X');
+
+ assert(axis >= 'X' && axis <= 'Z');
+
+ q[0] = angle_cos;
+ zero_v3(q + 1);
+ q[axis_index + 1] = angle_sin;
+}
+
/****************************** Exponential Map ******************************/
void quat_normalized_to_expmap(float expmap[3], const float q[4])
@@ -1115,15 +1181,11 @@ void eul_to_mat4(float mat[4][4], const float eul[3])
/* returns two euler calculation methods, so we can pick the best */
/* XYZ order */
-static void mat3_to_eul2(float tmat[3][3], float eul1[3], float eul2[3])
+static void mat3_normalized_to_eul2(const float mat[3][3], float eul1[3], float eul2[3])
{
- float cy, quat[4], mat[3][3];
-
- mat3_to_quat(quat, tmat);
- quat_to_mat3(mat, quat);
- normalize_m3_m3(mat, tmat);
+ const float cy = hypotf(mat[0][0], mat[0][1]);
- cy = hypotf(mat[0][0], mat[0][1]);
+ BLI_ASSERT_UNIT_M3(mat);
if (cy > 16.0f * FLT_EPSILON) {
@@ -1146,11 +1208,11 @@ static void mat3_to_eul2(float tmat[3][3], float eul1[3], float eul2[3])
}
/* XYZ order */
-void mat3_to_eul(float *eul, float tmat[3][3])
+void mat3_normalized_to_eul(float eul[3], float mat[3][3])
{
float eul1[3], eul2[3];
- mat3_to_eul2(tmat, eul1, eul2);
+ mat3_normalized_to_eul2(mat, eul1, eul2);
/* return best, which is just the one with lowest values it in */
if (fabsf(eul1[0]) + fabsf(eul1[1]) + fabsf(eul1[2]) > fabsf(eul2[0]) + fabsf(eul2[1]) + fabsf(eul2[2])) {
@@ -1160,24 +1222,33 @@ void mat3_to_eul(float *eul, float tmat[3][3])
copy_v3_v3(eul, eul1);
}
}
+void mat3_to_eul(float eul[3], float mat[3][3])
+{
+ float unit_mat[3][3];
+ normalize_m3_m3(unit_mat, mat);
+ mat3_normalized_to_eul(eul, unit_mat);
+}
/* XYZ order */
-void mat4_to_eul(float *eul, float tmat[4][4])
+void mat4_normalized_to_eul(float eul[3], float m[4][4])
{
- float tempMat[3][3];
-
- copy_m3_m4(tempMat, tmat);
- normalize_m3(tempMat);
- mat3_to_eul(eul, tempMat);
+ float mat3[3][3];
+ copy_m3_m4(mat3, m);
+ mat3_normalized_to_eul(eul, mat3);
+}
+void mat4_to_eul(float eul[3], float m[4][4])
+{
+ float mat3[3][3];
+ copy_m3_m4(mat3, m);
+ mat3_to_eul(eul, mat3);
}
/* XYZ order */
-void quat_to_eul(float *eul, const float quat[4])
+void quat_to_eul(float eul[3], const float quat[4])
{
- float mat[3][3];
-
- quat_to_mat3(mat, quat);
- mat3_to_eul(eul, mat);
+ float unit_mat[3][3];
+ quat_to_mat3(unit_mat, quat);
+ mat3_normalized_to_eul(eul, unit_mat);
}
/* XYZ order */
@@ -1267,12 +1338,12 @@ void compatible_eul(float eul[3], const float oldrot[3])
/* uses 2 methods to retrieve eulers, and picks the closest */
/* XYZ order */
-void mat3_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
+void mat3_normalized_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
{
float eul1[3], eul2[3];
float d1, d2;
- mat3_to_eul2(mat, eul1, eul2);
+ mat3_normalized_to_eul2(mat, eul1, eul2);
compatible_eul(eul1, oldrot);
compatible_eul(eul2, oldrot);
@@ -1288,6 +1359,19 @@ void mat3_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3]
copy_v3_v3(eul, eul1);
}
}
+void mat3_to_compatible_eul(float eul[3], const float oldrot[3], float mat[3][3])
+{
+ float unit_mat[3][3];
+ normalize_m3_m3(unit_mat, mat);
+ mat3_normalized_to_compatible_eul(eul, oldrot, unit_mat);
+}
+
+void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4])
+{
+ float unit_mat[3][3];
+ quat_to_mat3(unit_mat, quat);
+ mat3_normalized_to_compatible_eul(eul, oldrot, unit_mat);
+}
/************************** Arbitrary Order Eulers ***************************/
@@ -1373,10 +1457,10 @@ void eulO_to_quat(float q[4], const float e[3], const short order)
/* Convert quaternion to Euler angles (in radians). */
void quat_to_eulO(float e[3], short const order, const float q[4])
{
- float M[3][3];
+ float unit_mat[3][3];
- quat_to_mat3(M, q);
- mat3_to_eulO(e, order, M);
+ quat_to_mat3(unit_mat, q);
+ mat3_normalized_to_eulO(e, order, unit_mat);
}
/* Construct 3x3 matrix from Euler angles (in radians). */
@@ -1421,15 +1505,13 @@ void eulO_to_mat3(float M[3][3], const float e[3], const short order)
}
/* returns two euler calculation methods, so we can pick the best */
-static void mat3_to_eulo2(float M[3][3], float eul1[3], float eul2[3], const short order)
+static void mat3_normalized_to_eulo2(float mat[3][3], float eul1[3], float eul2[3], const short order)
{
const RotOrderInfo *R = get_rotation_order_info(order);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
- float mat[3][3];
float cy;
- /* process the matrix first */
- normalize_m3_m3(mat, M);
+ BLI_ASSERT_UNIT_M3(mat);
cy = hypotf(mat[i][i], mat[i][j]);
@@ -1457,23 +1539,22 @@ static void mat3_to_eulo2(float M[3][3], float eul1[3], float eul2[3], const sho
}
/* Construct 4x4 matrix from Euler angles (in radians). */
-void eulO_to_mat4(float M[4][4], const float e[3], const short order)
+void eulO_to_mat4(float mat[4][4], const float e[3], const short order)
{
- float m[3][3];
+ float unit_mat[3][3];
/* for now, we'll just do this the slow way (i.e. copying matrices) */
- normalize_m3(m);
- eulO_to_mat3(m, e, order);
- copy_m4_m3(M, m);
+ eulO_to_mat3(unit_mat, e, order);
+ copy_m4_m3(mat, unit_mat);
}
/* Convert 3x3 matrix to Euler angles (in radians). */
-void mat3_to_eulO(float eul[3], const short order, float M[3][3])
+void mat3_normalized_to_eulO(float eul[3], const short order, float m[3][3])
{
float eul1[3], eul2[3];
float d1, d2;
- mat3_to_eulo2(M, eul1, eul2, order);
+ mat3_normalized_to_eulo2(m, eul1, eul2, order);
d1 = fabsf(eul1[0]) + fabsf(eul1[1]) + fabsf(eul1[2]);
d2 = fabsf(eul2[0]) + fabsf(eul2[1]) + fabsf(eul2[2]);
@@ -1486,25 +1567,39 @@ void mat3_to_eulO(float eul[3], const short order, float M[3][3])
copy_v3_v3(eul, eul1);
}
}
+void mat3_to_eulO(float eul[3], const short order, float m[3][3])
+{
+ float unit_mat[3][3];
+ normalize_m3_m3(unit_mat, m);
+ mat3_normalized_to_eulO(eul, order, unit_mat);
+}
/* Convert 4x4 matrix to Euler angles (in radians). */
-void mat4_to_eulO(float e[3], const short order, float M[4][4])
+void mat4_normalized_to_eulO(float eul[3], const short order, float m[4][4])
{
- float m[3][3];
+ float mat3[3][3];
/* for now, we'll just do this the slow way (i.e. copying matrices) */
- copy_m3_m4(m, M);
- normalize_m3(m);
- mat3_to_eulO(e, order, m);
+ copy_m3_m4(mat3, m);
+ mat3_normalized_to_eulO(eul, order, mat3);
+}
+
+void mat4_to_eulO(float eul[3], const short order, float m[4][4])
+{
+ float mat3[3][3];
+ copy_m3_m4(mat3, m);
+ normalize_m3(mat3);
+ mat3_normalized_to_eulO(eul, order, mat3);
}
+
/* uses 2 methods to retrieve eulers, and picks the closest */
-void mat3_to_compatible_eulO(float eul[3], float oldrot[3], const short order, float mat[3][3])
+void mat3_normalized_to_compatible_eulO(float eul[3], float oldrot[3], const short order, float mat[3][3])
{
float eul1[3], eul2[3];
float d1, d2;
- mat3_to_eulo2(mat, eul1, eul2, order);
+ mat3_normalized_to_eulo2(mat, eul1, eul2, order);
compatible_eul(eul1, oldrot);
compatible_eul(eul2, oldrot);
@@ -1520,16 +1615,40 @@ void mat3_to_compatible_eulO(float eul[3], float oldrot[3], const short order, f
copy_v3_v3(eul, eul1);
}
}
+void mat3_to_compatible_eulO(float eul[3], float oldrot[3], const short order, float mat[3][3])
+{
+ float unit_mat[3][3];
+
+ normalize_m3_m3(unit_mat, mat);
+ mat3_normalized_to_compatible_eulO(eul, oldrot, order, unit_mat);
+}
+
+void mat4_normalized_to_compatible_eulO(float eul[3], float oldrot[3], const short order, float m[4][4])
+{
+ float mat3[3][3];
-void mat4_to_compatible_eulO(float eul[3], float oldrot[3], const short order, float M[4][4])
+ /* for now, we'll just do this the slow way (i.e. copying matrices) */
+ copy_m3_m4(mat3, m);
+ mat3_normalized_to_compatible_eulO(eul, oldrot, order, mat3);
+}
+void mat4_to_compatible_eulO(float eul[3], float oldrot[3], const short order, float m[4][4])
{
- float m[3][3];
+ float mat3[3][3];
/* for now, we'll just do this the slow way (i.e. copying matrices) */
- copy_m3_m4(m, M);
- normalize_m3(m);
- mat3_to_compatible_eulO(eul, oldrot, order, m);
+ copy_m3_m4(mat3, m);
+ normalize_m3(mat3);
+ mat3_normalized_to_compatible_eulO(eul, oldrot, order, mat3);
}
+
+void quat_to_compatible_eulO(float eul[3], float oldrot[3], const short order, const float quat[4])
+{
+ float unit_mat[3][3];
+
+ quat_to_mat3(unit_mat, quat);
+ mat3_normalized_to_compatible_eulO(eul, oldrot, order, unit_mat);
+}
+
/* rotate the given euler by the given angle on the specified axis */
/* NOTE: is this safe to do with different axis orders? */
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 2f962714c8c..641e50c9bde 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -34,7 +34,7 @@
#include "BLI_strict_flags.h"
-#include "eigen3_capi.h"
+#include "eigen_capi.h"
/********************************** Eigen Solvers *********************************/
@@ -57,5 +57,18 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3
}
#endif
- return EG3_self_adjoint_eigen_solve(3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors);
+ return EIG_self_adjoint_eigen_solve(3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors);
+}
+
+/**
+ * \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
+ *
+ * \param m3 the matrix to decompose.
+ * \return r_U the computed left singular vector of \a m3 (NULL if not needed).
+ * \return r_S the computed singular values of \a m3 (NULL if not needed).
+ * \return r_V the computed right singular vector of \a m3 (NULL if not needed).
+ */
+void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3])
+{
+ EIG_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V);
}
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index a8cb8e2c40d..fd7418a8f7b 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -30,12 +30,66 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BLI_strict_flags.h"
/********************************** Covariance Matrices *********************************/
+typedef struct CovarianceData {
+ const float *cos_vn;
+ const float *center;
+ float *r_covmat;
+ float covfac;
+ int n;
+ int nbr_cos_vn;
+} CovarianceData;
+
+static void covariance_m_vn_ex_task_cb(void *userdata, const int a)
+{
+ CovarianceData *data = userdata;
+ const float *cos_vn = data->cos_vn;
+ const float *center = data->center;
+ float *r_covmat = data->r_covmat;
+ const int n = data->n;
+ const int nbr_cos_vn = data->nbr_cos_vn;
+
+ int k;
+
+ /* Covariance matrices are always symetrical, so we can compute only one half of it,
+ * and mirror it to the other half (at the end of the func).
+ *
+ * This allows using a flat loop of n*n with same results as imbricated one over half the matrix:
+ *
+ * for (i = 0; i < n; i++) {
+ * for (j = i; j < n; j++) {
+ * ...
+ * }
+ * }
+ */
+ const int i = a / n;
+ const int j = a % n;
+ if (j < i)
+ return;
+
+ if (center) {
+ for (k = 0; k < nbr_cos_vn; k++) {
+ r_covmat[a] += (cos_vn[k * n + i] - center[i]) * (cos_vn[k * n + j] - center[j]);
+ }
+ }
+ else {
+ for (k = 0; k < nbr_cos_vn; k++) {
+ r_covmat[a] += cos_vn[k * n + i] * cos_vn[k * n + j];
+ }
+ }
+ r_covmat[a] *= data->covfac;
+ if (j != i) {
+ /* Mirror result to other half... */
+ r_covmat[j * n + i] = r_covmat[a];
+ }
+}
+
/**
* \brief Compute the covariance matrix of given set of nD coordinates.
*
@@ -51,8 +105,6 @@ void BLI_covariance_m_vn_ex(
const int n, const float *cos_vn, const int nbr_cos_vn, const float *center, const bool use_sample_correction,
float *r_covmat)
{
- int i, j, k;
-
/* Note about that division: see https://en.wikipedia.org/wiki/Bessel%27s_correction.
* In a nutshell, it must be 1 / (n - 1) for 'sample data', and 1 / n for 'population data'...
*/
@@ -60,30 +112,13 @@ void BLI_covariance_m_vn_ex(
memset(r_covmat, 0, sizeof(*r_covmat) * (size_t)(n * n));
-#pragma omp parallel for default(shared) private(i, j, k) schedule(static) if ((nbr_cos_vn * n) >= 10000)
- for (i = 0; i < n; i++) {
- for (j = i; j < n; j++) {
- r_covmat[i * n + j] = 0.0f;
- if (center) {
- for (k = 0; k < nbr_cos_vn; k++) {
- r_covmat[i * n + j] += (cos_vn[k * n + i] - center[i]) * (cos_vn[k * n + j] - center[j]);
- }
- }
- else {
- for (k = 0; k < nbr_cos_vn; k++) {
- r_covmat[i * n + j] += cos_vn[k * n + i] * cos_vn[k * n + j];
- }
- }
- r_covmat[i * n + j] *= covfac;
- }
- }
- /* Covariance matrices are always symetrical, so we can compute only one half of it (as done above),
- * and copy it to the other half! */
- for (i = 1; i < n; i++) {
- for (j = 0; j < i; j++) {
- r_covmat[i * n + j] = r_covmat[j * n + i];
- }
- }
+ CovarianceData data = {
+ .cos_vn = cos_vn, .center = center, .r_covmat = r_covmat,
+ .covfac = covfac, .n = n, .nbr_cos_vn = nbr_cos_vn,
+ };
+
+ BLI_task_parallel_range(
+ 0, n * n, &data, covariance_m_vn_ex_task_cb, (nbr_cos_vn * n * n) >= 10000);
}
/**
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 6da0e87355d..72a3da265c7 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -397,6 +397,19 @@ float angle_v2v2v2(const float v1[2], const float v2[2], const float v3[2])
return angle_normalized_v2v2(vec1, vec2);
}
+/* Quicker than full angle computation */
+float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2])
+{
+ float vec1[2], vec2[2];
+
+ sub_v2_v2v2(vec1, p2, p1);
+ sub_v2_v2v2(vec2, p2, p3);
+ normalize_v2(vec1);
+ normalize_v2(vec2);
+
+ return dot_v2v2(vec1, vec2);
+}
+
/* Return the shortest angle in radians between the 2 vectors */
float angle_v2v2(const float v1[2], const float v2[2])
{
@@ -785,7 +798,7 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
if (max[1] < vec[1]) max[1] = vec[1];
}
-void minmax_v3v3_v3_array(float r_min[3], float r_max[3], float (*vec_arr)[3], int nbr)
+void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr)
{
while (nbr--) {
minmax_v3v3_v3(r_min, r_max, *vec_arr++);
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index c21b09748c9..17e2da3f1cb 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -97,7 +97,29 @@ MINLINE void copy_v4_fl(float r[4], float f)
r[3] = f;
}
-/* short */
+/* unsigned char */
+MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2])
+{
+ r[0] = a[0];
+ r[1] = a[1];
+}
+
+MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3])
+{
+ r[0] = a[0];
+ r[1] = a[1];
+ r[2] = a[2];
+}
+
+MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4])
+{
+ r[0] = a[0];
+ r[1] = a[1];
+ r[2] = a[2];
+ r[3] = a[3];
+}
+
+/* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2])
{
r[0] = a[0];
@@ -611,6 +633,13 @@ MINLINE void negate_v3_short(short r[3])
r[2] = (short)-r[2];
}
+MINLINE void invert_v2(float r[2])
+{
+ BLI_assert(!ELEM(0.0f, r[0], r[1]));
+ r[0] = 1.0f / r[0];
+ r[1] = 1.0f / r[1];
+}
+
MINLINE void abs_v2(float r[2])
{
r[0] = fabsf(r[0]);
diff --git a/source/blender/blenlib/intern/memory_utils.c b/source/blender/blenlib/intern/memory_utils.c
new file mode 100644
index 00000000000..2ebb8be5bb4
--- /dev/null
+++ b/source/blender/blenlib/intern/memory_utils.c
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenlib/intern/memory_utils.c
+ * \ingroup bli
+ * \brief Generic memory manipulation API.
+ *
+ * This is to extend on existing functions
+ * such as ``memcpy`` & ``memcmp``.
+ */
+#include <string.h>
+
+#include "BLI_sys_types.h"
+#include "BLI_utildefines.h"
+
+#include "BLI_memory_utils.h"
+
+#include "BLI_strict_flags.h"
+
+/**
+ * Check if memory is zero'd, as with memset(s, 0, nbytes)
+ */
+bool BLI_memory_is_zero(const void *s, const size_t nbytes)
+{
+ const char *s_byte = s;
+ const char *s_end = (const char *)s + nbytes;
+
+ while ((s_byte != s_end) && (*s_byte == 0)) {
+ s_byte++;
+ }
+
+ return (s_byte == s_end);
+}
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
index 4b2ad834d75..c3a0c44d7c5 100644
--- a/source/blender/blenlib/intern/noise.c
+++ b/source/blender/blenlib/intern/noise.c
@@ -452,7 +452,7 @@ float BLI_turbulence1(float noisesize, float x, float y, float z, int nr)
/* ********************* FROM PERLIN HIMSELF: ******************** */
-static const char p[512 + 2] = {
+static const char g_perlin_data_ub[512 + 2] = {
0xA2, 0xA0, 0x19, 0x3B, 0xF8, 0xEB, 0xAA, 0xEE, 0xF3, 0x1C, 0x67, 0x28,
0x1D, 0xED, 0x0, 0xDE, 0x95, 0x2E, 0xDC, 0x3F, 0x3A, 0x82, 0x35, 0x4D,
0x6C, 0xBA, 0x36, 0xD0, 0xF6, 0xC, 0x79, 0x32, 0xD1, 0x59, 0xF4, 0x8,
@@ -499,7 +499,7 @@ static const char p[512 + 2] = {
};
-static const float g[512 + 2][3] = {
+static const float g_perlin_data_v3[512 + 2][3] = {
{0.33783, 0.715698, -0.611206},
{-0.944031, -0.326599, -0.045624},
{-0.101074, -0.416443, -0.903503},
@@ -1028,6 +1028,8 @@ static const float g[512 + 2][3] = {
static float noise3_perlin(float vec[3])
{
+ const char *p = g_perlin_data_ub;
+ const float (*g)[3] = g_perlin_data_v3;
int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, rz0, rz1, sx, sy, sz, a, b, c, d, t, u, v;
const float *q;
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 4692af0ffa7..fadfb64f1e1 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -191,31 +191,6 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
}
/**
- * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
- */
-void BLI_newname(char *name, int add)
-{
- char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX];
- int pic;
- unsigned short digits;
-
- pic = BLI_stringdec(name, head, tail, &digits);
-
- /* are we going from 100 -> 99 or from 10 -> 9 */
- if (add < 0 && digits < 4 && digits > 0) {
- int i, exp;
- exp = 1;
- for (i = digits; i > 1; i--) exp *= 10;
- if (pic >= exp && (pic + add) < exp) digits--;
- }
-
- pic += add;
-
- if (digits == 4 && pic < 0) pic = 0;
- BLI_stringenc(name, head, tail, digits, pic);
-}
-
-/**
* Ensures name is unique (according to criteria specified by caller in unique_check callback),
* incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
*
@@ -332,14 +307,15 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f
/* ******************** string encoding ***************** */
-/* This is quite an ugly function... its purpose is to
- * take the dir name, make it absolute, and clean it up, replacing
- * excess file entry stuff (like /tmp/../tmp/../)
- * note that dir isn't protected for max string names...
- *
- * If relbase is NULL then its ignored
+/**
+ * Remove redundant characters from \a path and optionally make absolute.
+ *
+ * \param relbase: The path this is relative to, or ignored when NULL.
+ * \param path: Can be any input, and this function converts it to a regular full path.
+ * Also removes garbage from directory paths, like `/../` or double slashes etc.
+ *
+ * \note \a path isn't protected for max string names...
*/
-
void BLI_cleanup_path(const char *relabase, char *path)
{
ptrdiff_t a;
@@ -428,6 +404,9 @@ void BLI_cleanup_path(const char *relabase, char *path)
#endif
}
+/**
+ * Cleanup filepath ensuring a trailing slash.
+ */
void BLI_cleanup_dir(const char *relabase, char *dir)
{
BLI_cleanup_path(relabase, dir);
@@ -435,6 +414,9 @@ void BLI_cleanup_dir(const char *relabase, char *dir)
}
+/**
+ * Cleanup filepath ensuring no trailing slash.
+ */
void BLI_cleanup_file(const char *relabase, char *path)
{
BLI_cleanup_path(relabase, path);
@@ -453,6 +435,8 @@ void BLI_cleanup_file(const char *relabase, char *path)
*
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue
* in some cases, so we simply replace it by an underscore too (good practice anyway).
+ * REMOVED based on popular demand (see T45900).
+ * Percent '%' char is a bit same case - not recommended to use it, but supported by all decent FS/OS around...
*
* \note On Windows, it also ensures there is no '.' (dot char) at the end of the file, this can lead to issues...
*
@@ -461,9 +445,9 @@ void BLI_cleanup_file(const char *relabase, char *path)
*/
bool BLI_filename_make_safe(char *fname)
{
- const char *invalid = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ const char *invalid = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
- "/\\?%*:|\"<> ";
+ "/\\?*:|\"<>";
char *fn;
bool changed = false;
@@ -533,7 +517,7 @@ bool BLI_filename_make_safe(char *fname)
bool BLI_path_make_safe(char *path)
{
/* Simply apply BLI_filename_make_safe() over each component of the path.
- * Luckily enough, same 'sfae' rules applies to filenames and dirnames. */
+ * Luckily enough, same 'safe' rules applies to filenames and dirnames. */
char *curr_slash, *curr_path = path;
bool changed = false;
bool skip_first = false;
@@ -977,7 +961,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
*/
bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
{
- if (path && *path) {
+ if (*path) {
char *file = (char *)BLI_last_slash(path);
char *c;
int len, numdigits;
@@ -1026,9 +1010,9 @@ bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
return false;
}
-void BLI_path_frame_strip(char *path, bool setsharp, char *ext)
+void BLI_path_frame_strip(char *path, bool set_frame_char, char *ext)
{
- if (path && *path) {
+ if (*path) {
char *file = (char *)BLI_last_slash(path);
char *c, *suffix;
int len;
@@ -1063,15 +1047,12 @@ void BLI_path_frame_strip(char *path, bool setsharp, char *ext)
if (numdigits) {
/* replace the number with the suffix and terminate the string */
while (numdigits--) {
- if (ext) *ext++ = *suffix;
-
- if (setsharp) *c++ = '#';
- else *c++ = *suffix;
-
+ *ext++ = *suffix;
+ *c++ = set_frame_char ? '#' : *suffix;
suffix++;
}
- *c = 0;
- if (ext) *ext = 0;
+ *c = '\0';
+ *ext = '\0';
}
}
}
@@ -1087,9 +1068,14 @@ bool BLI_path_frame_check_chars(const char *path)
}
/**
- * If path begins with "//", strips that and replaces it with basepath directory. Also converts
- * a drive-letter prefix to something more sensible if this is a non-drive-letter-based system.
- * Returns true if "//" prefix expansion was done.
+ * If path begins with "//", strips that and replaces it with basepath directory.
+ *
+ * \note Also converts drive-letter prefix to something more sensible
+ * if this is a non-drive-letter-based system.
+ *
+ * \param path: The path to convert.
+ * \param basepath: The directory to base relative paths with.
+ * \return true if the path was relative (started with "//").
*/
bool BLI_path_abs(char *path, const char *basepath)
{
@@ -1202,7 +1188,7 @@ bool BLI_path_abs(char *path, const char *basepath)
* \note Should only be done with command line paths.
* this is _not_ something blenders internal paths support like the "//" prefix
*/
-bool BLI_path_cwd(char *path)
+bool BLI_path_cwd(char *path, const size_t maxlen)
{
bool wasrelative = true;
const int filelen = strlen(path);
@@ -1216,24 +1202,15 @@ bool BLI_path_cwd(char *path)
#endif
if (wasrelative) {
- char cwd[FILE_MAX] = "";
- BLI_current_working_dir(cwd, sizeof(cwd)); /* in case the full path to the blend isn't used */
-
- if (cwd[0] == '\0') {
- printf("Could not get the current working directory - $PWD for an unknown reason.\n");
- }
- else {
- /* uses the blend path relative to cwd important for loading relative linked files.
- *
- * cwd should contain c:\ etc on win32 so the relbase can be NULL
- * relbase being NULL also prevents // being misunderstood as relative to the current
- * blend file which isn't a feature we want to use in this case since were dealing
- * with a path from the command line, rather than from inside Blender */
-
+ char cwd[FILE_MAX];
+ /* in case the full path to the blend isn't used */
+ if (BLI_current_working_dir(cwd, sizeof(cwd))) {
char origpath[FILE_MAX];
BLI_strncpy(origpath, path, FILE_MAX);
-
- BLI_make_file_string(NULL, path, cwd, origpath);
+ BLI_join_dirfile(path, maxlen, cwd, origpath);
+ }
+ else {
+ printf("Could not get the current working directory - $PWD for an unknown reason.\n");
}
}
@@ -1784,7 +1761,7 @@ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__r
}
/* inline BLI_add_slash */
- if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
+ if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) {
dst[dirlen++] = SEP;
dst[dirlen] = '\0';
}
@@ -2014,38 +1991,3 @@ void BLI_path_native_slash(char *path)
BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/');
#endif
}
-
-
-#ifdef WITH_ICONV
-
-/**
- * Converts a string encoded in the charset named by *code to UTF-8.
- * Opens a new iconv context each time it is run, which is probably not the
- * most efficient. */
-void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
-{
- size_t inbytesleft = strlen(original);
- size_t outbytesleft = 512;
- size_t rv = 0;
- iconv_t cd;
-
- if (NULL == code) {
- code = locale_charset();
- }
- cd = iconv_open("UTF-8", code);
-
- if (cd == (iconv_t)(-1)) {
- printf("iconv_open Error");
- *utf_8 = '\0';
- return;
- }
- rv = iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
- if (rv == (size_t) -1) {
- printf("iconv Error\n");
- iconv_close(cd);
- return;
- }
- *utf_8 = '\0';
- iconv_close(cd);
-}
-#endif // WITH_ICONV
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index df6caa4b65a..800f4cb23c3 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -516,18 +516,6 @@ static void pf_triangulate(PolyFill *pf)
#endif
);
-#ifdef USE_CLIP_SWEEP
-#ifdef USE_CLIP_EVEN
- if (pi_ear != pi_ear_init) {
- reverse = !reverse;
- }
-#else
- if (pi_ear != pf->indices) {
- reverse = !reverse;
- }
-#endif
-#endif
-
#ifdef USE_CONVEX_SKIP
if (pi_ear->sign != CONVEX) {
pf->coords_tot_concave -= 1;
@@ -576,6 +564,20 @@ static void pf_triangulate(PolyFill *pf)
#endif
#endif
+#ifdef USE_CLIP_EVEN
+#ifdef USE_CLIP_SWEEP
+ if (pi_ear_init->sign != CONVEX) {
+ /* take the extra step since this ear isn't a good candidate */
+ pi_ear_init = reverse ? pi_ear_init->prev : pi_ear_init->next;
+ reverse = !reverse;
+ }
+#endif
+#else
+ if ((reverse ? pi_prev->prev : pi_next->next)->sign != CONVEX) {
+ reverse = !reverse;
+ }
+#endif
+
}
if (pf->coords_tot == 3) {
@@ -799,7 +801,7 @@ static void polyfill_prepare(
coords_sign = (cross_poly_v2(coords, coords_tot) >= 0.0f) ? 1 : -1;
}
else {
- /* chech we're passing in correcty args */
+ /* check we're passing in correcty args */
#ifdef USE_STRICT_ASSERT
#ifndef NDEBUG
if (coords_sign == 1) {
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 646613d9a29..9d5a4630f68 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -173,7 +173,7 @@ bool BLI_rcti_inside_rcti(rcti *rct_a, const rcti *rct_b)
}
-/* based closely on 'isect_line_line_v2_int', but in modified so corner cases are treated as intersections */
+/* based closely on 'isect_seg_seg_v2_int', but in modified so corner cases are treated as intersections */
static int isect_segments_i(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
{
const double div = (double)((v2[0] - v1[0]) * (v4[1] - v3[1]) - (v2[1] - v1[1]) * (v4[0] - v3[0]));
@@ -474,7 +474,7 @@ void BLI_rctf_interp(rctf *rect, const rctf *rect_a, const rctf *rect_b, const f
/* BLI_rcti_interp() not needed yet */
-bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2])
+bool BLI_rctf_clamp_pt_v(const rctf *rect, float xy[2])
{
bool changed = false;
if (xy[0] < rect->xmin) { xy[0] = rect->xmin; changed = true; }
@@ -484,7 +484,7 @@ bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2])
return changed;
}
-bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2])
+bool BLI_rcti_clamp_pt_v(const rcti *rect, int xy[2])
{
bool changed = false;
if (xy[0] < rect->xmin) { xy[0] = rect->xmin; changed = true; }
@@ -494,7 +494,96 @@ bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2])
return changed;
}
-bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit)
+/**
+ * Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
+ *
+ * \return true if a change is made.
+ */
+bool BLI_rctf_clamp(rctf *rect, const rctf *rect_bounds, float r_xy[2])
+{
+ bool changed = false;
+
+ r_xy[0] = 0.0f;
+ r_xy[1] = 0.0f;
+
+ if (rect->xmin < rect_bounds->xmin) {
+ float ofs = rect_bounds->xmin - rect->xmin;
+ rect->xmin += ofs;
+ rect->xmax += ofs;
+ r_xy[0] += ofs;
+ changed = true;
+ }
+
+ if (rect->xmax > rect_bounds->xmax) {
+ float ofs = rect_bounds->xmax - rect->xmax;
+ rect->xmin += ofs;
+ rect->xmax += ofs;
+ r_xy[0] += ofs;
+ changed = true;
+ }
+
+ if (rect->ymin < rect_bounds->ymin) {
+ float ofs = rect_bounds->ymin - rect->ymin;
+ rect->ymin += ofs;
+ rect->ymax += ofs;
+ r_xy[1] += ofs;
+ changed = true;
+ }
+
+ if (rect->ymax > rect_bounds->ymax) {
+ float ofs = rect_bounds->ymax - rect->ymax;
+ rect->ymin += ofs;
+ rect->ymax += ofs;
+ r_xy[1] += ofs;
+ changed = true;
+ }
+
+ return changed;
+}
+
+bool BLI_rcti_clamp(rcti *rect, const rcti *rect_bounds, int r_xy[2])
+{
+ bool changed = false;
+
+ r_xy[0] = 0;
+ r_xy[1] = 0;
+
+ if (rect->xmin < rect_bounds->xmin) {
+ int ofs = rect_bounds->xmin - rect->xmin;
+ rect->xmin += ofs;
+ rect->xmax += ofs;
+ r_xy[0] += ofs;
+ changed = true;
+ }
+
+ if (rect->xmax > rect_bounds->xmax) {
+ int ofs = rect_bounds->xmax - rect->xmax;
+ rect->xmin += ofs;
+ rect->xmax += ofs;
+ r_xy[0] += ofs;
+ changed = true;
+ }
+
+ if (rect->ymin < rect_bounds->ymin) {
+ int ofs = rect_bounds->ymin - rect->ymin;
+ rect->ymin += ofs;
+ rect->ymax += ofs;
+ r_xy[1] += ofs;
+ changed = true;
+ }
+
+ if (rect->ymax > rect_bounds->ymax) {
+ int ofs = rect_bounds->ymax - rect->ymax;
+ rect->ymin += ofs;
+ rect->ymax += ofs;
+ r_xy[1] += ofs;
+ changed = true;
+ }
+
+ return changed;
+}
+
+bool BLI_rctf_compare(const rctf *rect_a, const rctf *rect_b, const float limit)
{
if (fabsf(rect_a->xmin - rect_b->xmin) < limit)
if (fabsf(rect_a->xmax - rect_b->xmax) < limit)
@@ -505,7 +594,7 @@ bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, cons
return false;
}
-bool BLI_rcti_compare(const struct rcti *rect_a, const struct rcti *rect_b)
+bool BLI_rcti_compare(const rcti *rect_a, const rcti *rect_b)
{
if (rect_a->xmin == rect_b->xmin)
if (rect_a->xmax == rect_b->xmax)
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index 8a96daeeb91..e913499ba2b 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -602,7 +602,7 @@ static unsigned int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int fl
else {
/* test rest of vertices */
ScanFillVertLink *best_sc = NULL;
- float best_angle = 3.14f;
+ float angle_best_cos = -1.0f;
float miny;
bool firsttime = false;
@@ -633,21 +633,18 @@ static unsigned int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int fl
best_sc = sc1;
}
else {
- float angle;
-
/* prevent angle calc for the simple cases only 1 vertex is found */
if (firsttime == false) {
- best_angle = angle_v2v2v2(v2->xy, v1->xy, best_sc->vert->xy);
+ angle_best_cos = cos_v2v2v2(v2->xy, v1->xy, best_sc->vert->xy);
firsttime = true;
}
- angle = angle_v2v2v2(v2->xy, v1->xy, sc1->vert->xy);
- if (angle < best_angle) {
+ const float angle_test_cos = cos_v2v2v2(v2->xy, v1->xy, sc1->vert->xy);
+ if (angle_test_cos > angle_best_cos) {
best_sc = sc1;
- best_angle = angle;
+ angle_best_cos = angle_test_cos;
}
}
-
}
}
}
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index ba336ab6c4b..0b976e9612e 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -28,12 +28,16 @@
/** \file blender/blenlib/intern/smallhash.c
* \ingroup bli
*
- * A light stack-friendly hash library, it uses stack space for smallish hash tables
- * but falls back to heap memory once the stack limits reached.
+ * A light stack-friendly hash library, it uses stack space for relatively small, fixed size hash tables
+ * but falls back to heap memory once the stack limits reached (#SMSTACKSIZE).
*
- * based on a doubling non-chaining approach which uses more buckets then entries
+ * based on a doubling hashing approach (non-chaining) which uses more buckets then entries
* stepping over buckets when two keys share the same hash so any key can find a free bucket.
*
+ * See: http://en.wikipedia.org/wiki/Double_hashing
+ *
+ * \warning This should _only_ be used for small hashes where allocating a hash every time is unacceptable.
+ * Otherwise #GHash should be used instead.
*
* #SmallHashEntry.key
* - ``SMHASH_KEY_UNUSED`` means the key in the cell has not been initialized.
@@ -48,7 +52,8 @@
#include <string.h>
#include <stdlib.h>
-#include <BLI_sys_types.h>
+
+#include "BLI_sys_types.h"
#include "MEM_guardedalloc.h"
@@ -126,7 +131,7 @@ BLI_INLINE SmallHashEntry *smallhash_lookup(const SmallHash *sh, const uintptr_t
BLI_assert(key != SMHASH_KEY_UNUSED);
- /* note: there are always more buckets then entries,
+ /* note: there are always more buckets than entries,
* so we know there will always be a free bucket if the key isn't found. */
for (e = &sh->buckets[h % sh->nbuckets];
e->val != SMHASH_CELL_FREE;
@@ -221,7 +226,7 @@ void BLI_smallhash_init(SmallHash *sh)
BLI_smallhash_init_ex(sh, 0);
}
-/*NOTE: does *not* free *sh itself! only the direct data!*/
+/* NOTE: does *not* free *sh itself! only the direct data! */
void BLI_smallhash_release(SmallHash *sh)
{
if (sh->buckets != sh->buckets_stack) {
diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c
index c5922feb0ed..19fea87fb41 100644
--- a/source/blender/blenlib/intern/sort.c
+++ b/source/blender/blenlib/intern/sort.c
@@ -40,12 +40,21 @@
#include "BLI_sort.h"
-/* note: modified to use glibc arg order for callback */
-/* **** qsort based on FreeBSD source (libkern\qsort.c) **** */
+#ifdef min /* for msvc */
+# undef min
+#endif
+
+/**
+ * qsort, copied from FreeBSD source.
+ * with only very minor edits, see:
+ * http://github.com/freebsd/freebsd/blob/master/sys/libkern/qsort.c
+ *
+ * \note modified to use glibc arg order for callbacks.
+ */
BLI_INLINE char *med3(char *, char *, char *, BLI_sort_cmp_t, void *);
BLI_INLINE void swapfunc(char *, char *, int, int);
-#define min(a, b) (a) < (b) ? a : b
+#define min(a, b) (a) < (b) ? (a) : (b)
#define swapcode(TYPE, parmi, parmj, n) \
{ \
long i = (n) / sizeof(TYPE); \
@@ -88,8 +97,6 @@ BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk
/**
* Quick sort reentrant.
- *
- * \note Follows BSD arg order (incompatible with glibc).
*/
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
{
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 7fdf6ec8101..aba7c9d5ee2 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -91,8 +91,14 @@ char *BLI_current_working_dir(char *dir, const size_t maxncpy)
{
const char *pwd = getenv("PWD");
if (pwd) {
- BLI_strncpy(dir, pwd, maxncpy);
- return dir;
+ size_t srclen = BLI_strnlen(pwd, maxncpy);
+ if (srclen != maxncpy) {
+ memcpy(dir, pwd, srclen + 1);
+ return dir;
+ }
+ else {
+ return NULL;
+ }
}
return getcwd(dir, maxncpy);
@@ -226,7 +232,6 @@ int BLI_exists(const char *name)
if (res == -1) return(0);
#else
struct stat st;
- BLI_assert(name);
BLI_assert(!BLI_path_is_rel(name));
if (stat(name, &st)) return(0);
#endif
@@ -281,6 +286,81 @@ bool BLI_is_file(const char *path)
return (mode && !S_ISDIR(mode));
}
+void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
+{
+ FILE *fp = BLI_fopen(filepath, "r");
+ void *mem = NULL;
+
+ if (fp) {
+ fseek(fp, 0L, SEEK_END);
+ const long int filelen = ftell(fp);
+ if (filelen == -1) {
+ goto finally;
+ }
+ fseek(fp, 0L, SEEK_SET);
+
+ mem = MEM_mallocN(filelen + pad_bytes, __func__);
+ if (mem == NULL) {
+ goto finally;
+ }
+
+ const long int filelen_read = fread(mem, 1, filelen, fp);
+ if ((filelen_read < 0) || ferror(fp)) {
+ MEM_freeN(mem);
+ mem = NULL;
+ goto finally;
+ }
+
+ if (filelen_read < filelen) {
+ mem = MEM_reallocN(mem, filelen_read + pad_bytes);
+ if (mem == NULL) {
+ goto finally;
+ }
+ }
+
+ *r_size = filelen_read;
+
+finally:
+ fclose(fp);
+ }
+
+ return mem;
+}
+
+void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
+{
+ FILE *fp = BLI_fopen(filepath, "rb");
+ void *mem = NULL;
+
+ if (fp) {
+ fseek(fp, 0L, SEEK_END);
+ const long int filelen = ftell(fp);
+ if (filelen == -1) {
+ goto finally;
+ }
+ fseek(fp, 0L, SEEK_SET);
+
+ mem = MEM_mallocN(filelen + pad_bytes, __func__);
+ if (mem == NULL) {
+ goto finally;
+ }
+
+ const long int filelen_read = fread(mem, 1, filelen, fp);
+ if ((filelen_read != filelen) || ferror(fp)) {
+ MEM_freeN(mem);
+ mem = NULL;
+ goto finally;
+ }
+
+ *r_size = filelen_read;
+
+finally:
+ fclose(fp);
+ }
+
+ return mem;
+}
+
/**
* Reads the contents of a text file and returns the lines in a linked list.
*/
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index e93d2b7507a..f62ffe9e985 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -302,8 +302,6 @@ char *BLI_sprintfN(const char *__restrict format, ...)
va_list arg;
char *n;
- BLI_assert(format != NULL);
-
va_start(arg, format);
ds = BLI_dynstr_new();
@@ -527,6 +525,37 @@ char *BLI_strcasestr(const char *s, const char *find)
return ((char *) s);
}
+/**
+ * Variation of #BLI_strcasestr with string length limited to \a len
+ */
+char *BLI_strncasestr(const char *s, const char *find, size_t len)
+{
+ register char c, sc;
+
+ if ((c = *find++) != 0) {
+ c = tolower(c);
+ if (len > 1) {
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return NULL;
+ sc = tolower(sc);
+ } while (sc != c);
+ } while (BLI_strncasecmp(s, find, len - 1) != 0);
+ }
+ else {
+ {
+ do {
+ if ((sc = *s++) == 0)
+ return NULL;
+ sc = tolower(sc);
+ } while (sc != c);
+ }
+ }
+ s--;
+ }
+ return ((char *)s);
+}
int BLI_strcasecmp(const char *s1, const char *s2)
{
@@ -841,7 +870,7 @@ bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, s
* \param end The string we look for at the end.
* \return If str ends with end.
*/
-bool BLI_str_endswith(const char *__restrict str, const char *end)
+bool BLI_str_endswith(const char *__restrict str, const char * __restrict end)
{
const size_t slength = strlen(str);
return BLI_strn_endswith(str, end, slength);
@@ -964,3 +993,49 @@ size_t BLI_str_format_int_grouped(char dst[16], int num)
return (size_t)(p_dst - dst);
}
+
+/**
+ * Find the ranges needed to split \a str into its individual words.
+ *
+ * \param str: The string to search for words.
+ * \param len: Size of the string to search.
+ * \param delim: Character to use as a delimiter.
+ * \param r_words: Info about the words found. Set to [index, len] pairs.
+ * \param words_max: Max number of words to find
+ * \return The number of words found in \a str
+ */
+int BLI_string_find_split_words(
+ const char *str, const size_t len,
+ const char delim, int r_words[][2], int words_max)
+{
+ int n = 0, i;
+ bool charsearch = true;
+
+ /* Skip leading spaces */
+ for (i = 0; (i < len) && (str[i] != '\0'); i++) {
+ if (str[i] != delim) {
+ break;
+ }
+ }
+
+ for (; (i < len) && (str[i] != '\0') && (n < words_max); i++) {
+ if ((str[i] != delim) && (charsearch == true)) {
+ r_words[n][0] = i;
+ charsearch = false;
+ }
+ else {
+ if ((str[i] == delim) && (charsearch == false)) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ charsearch = true;
+ }
+ }
+ }
+
+ if (charsearch == false) {
+ r_words[n][1] = i - r_words[n][0];
+ n++;
+ }
+
+ return n;
+}
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 08d40a158ca..e7938b750da 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -43,6 +43,7 @@ typedef struct Task {
TaskRunFunction run;
void *taskdata;
bool free_taskdata;
+ TaskFreeFunction freedata;
TaskPool *pool;
} Task;
@@ -60,12 +61,17 @@ struct TaskPool {
ThreadMutex user_mutex;
volatile bool do_cancel;
+
+ /* If set, this pool may never be work_and_wait'ed, which means TaskScheduler has to use its special
+ * background fallback thread in case we are in single-threaded situation. */
+ bool run_in_background;
};
struct TaskScheduler {
pthread_t *threads;
struct TaskThread *task_threads;
int num_threads;
+ bool background_thread_only;
ListBase queue;
ThreadMutex queue_mutex;
@@ -79,6 +85,19 @@ typedef struct TaskThread {
int id;
} TaskThread;
+/* Helper */
+static void task_data_free(Task *task, const int thread_id)
+{
+ if (task->free_taskdata) {
+ if (task->freedata) {
+ task->freedata(task->pool, task->taskdata, thread_id);
+ }
+ else {
+ MEM_freeN(task->taskdata);
+ }
+ }
+}
+
/* Task Scheduler */
static void task_pool_num_decrease(TaskPool *pool, size_t done)
@@ -117,16 +136,32 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task
do {
Task *current_task;
- if (!scheduler->queue.first) {
+
+ /* Assuming we can only have a void queue in 'exit' case here seems logical (we should only be here after
+ * our worker thread has been woken up from a condition_wait(), which only happens after a new task was
+ * added to the queue), but it is wrong.
+ * Waiting on condition may wake up the thread even if condition is not signaled (spurious wake-ups), and some
+ * race condition may also empty the queue **after** condition has been signaled, but **before** awoken thread
+ * reaches this point...
+ * See http://stackoverflow.com/questions/8594591
+ *
+ * So we only abort here if do_exit is set.
+ */
+ if (scheduler->do_exit) {
BLI_mutex_unlock(&scheduler->queue_mutex);
- BLI_assert(scheduler->do_exit);
return false;
}
+
for (current_task = scheduler->queue.first;
current_task != NULL;
current_task = current_task->next)
{
TaskPool *pool = current_task->pool;
+
+ if (scheduler->background_thread_only && !pool->run_in_background) {
+ continue;
+ }
+
if (pool->num_threads == 0 ||
pool->currently_running_tasks < pool->num_threads)
{
@@ -161,8 +196,7 @@ static void *task_scheduler_thread_run(void *thread_p)
task->run(pool, task->taskdata, thread_id);
/* delete task */
- if (task->free_taskdata)
- MEM_freeN(task->taskdata);
+ task_data_free(task, thread_id);
MEM_freeN(task);
/* notify pool task was done */
@@ -192,6 +226,12 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
/* main thread will also work, so we count it too */
num_threads -= 1;
+ /* Add background-only thread if needed. */
+ if (num_threads == 0) {
+ scheduler->background_thread_only = true;
+ num_threads = 1;
+ }
+
/* launch threads that will be waiting for work */
if (num_threads > 0) {
int i;
@@ -207,11 +247,10 @@ TaskScheduler *BLI_task_scheduler_create(int num_threads)
if (pthread_create(&scheduler->threads[i], NULL, task_scheduler_thread_run, thread) != 0) {
fprintf(stderr, "TaskScheduler failed to launch thread %d/%d\n", i, num_threads);
- MEM_freeN(thread);
}
}
}
-
+
return scheduler;
}
@@ -244,8 +283,7 @@ void BLI_task_scheduler_free(TaskScheduler *scheduler)
/* delete leftover tasks */
for (task = scheduler->queue.first; task; task = task->next) {
- if (task->free_taskdata)
- MEM_freeN(task->taskdata);
+ task_data_free(task, 0);
}
BLI_freelistN(&scheduler->queue);
@@ -289,8 +327,7 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
nexttask = task->next;
if (task->pool == pool) {
- if (task->free_taskdata)
- MEM_freeN(task->taskdata);
+ task_data_free(task, 0);
BLI_freelinkN(&scheduler->queue, task);
done++;
@@ -305,15 +342,28 @@ static void task_scheduler_clear(TaskScheduler *scheduler, TaskPool *pool)
/* Task Pool */
-TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
+static TaskPool *task_pool_create_ex(TaskScheduler *scheduler, void *userdata, const bool is_background)
{
TaskPool *pool = MEM_callocN(sizeof(TaskPool), "TaskPool");
+#ifndef NDEBUG
+ /* Assert we do not try to create a background pool from some parent task - those only work OK from main thread. */
+ if (is_background) {
+ const pthread_t thread_id = pthread_self();
+ int i = scheduler->num_threads;
+
+ while (i--) {
+ BLI_assert(!pthread_equal(scheduler->threads[i], thread_id));
+ }
+ }
+#endif
+
pool->scheduler = scheduler;
pool->num = 0;
pool->num_threads = 0;
pool->currently_running_tasks = 0;
pool->do_cancel = false;
+ pool->run_in_background = is_background;
BLI_mutex_init(&pool->num_mutex);
BLI_condition_init(&pool->num_cond);
@@ -332,6 +382,31 @@ TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
return pool;
}
+/**
+ * Create a normal task pool.
+ * This means that in single-threaded context, it will not be executed at all until you call
+ * \a BLI_task_pool_work_and_wait() on it.
+ */
+TaskPool *BLI_task_pool_create(TaskScheduler *scheduler, void *userdata)
+{
+ return task_pool_create_ex(scheduler, userdata, false);
+}
+
+/**
+ * Create a background task pool.
+ * In multi-threaded context, there is no differences with \a BLI_task_pool_create(), but in single-threaded case
+ * it is ensured to have at least one worker thread to run on (i.e. you do not have to call
+ * \a BLI_task_pool_work_and_wait() on it to be sure it will be processed).
+ *
+ * \note Background pools are non-recursive (that is, you should not create other background pools in tasks assigned
+ * to a background pool, they could end never being executed, since the 'fallback' background thread is already
+ * busy with parent task in single-threaded context).
+ */
+TaskPool *BLI_task_pool_create_background(TaskScheduler *scheduler, void *userdata)
+{
+ return task_pool_create_ex(scheduler, userdata, true);
+}
+
void BLI_task_pool_free(TaskPool *pool)
{
BLI_task_pool_stop(pool);
@@ -346,19 +421,27 @@ void BLI_task_pool_free(TaskPool *pool)
BLI_end_threaded_malloc();
}
-void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run,
- void *taskdata, bool free_taskdata, TaskPriority priority)
+void BLI_task_pool_push_ex(
+ TaskPool *pool, TaskRunFunction run, void *taskdata,
+ bool free_taskdata, TaskFreeFunction freedata, TaskPriority priority)
{
Task *task = MEM_callocN(sizeof(Task), "Task");
task->run = run;
task->taskdata = taskdata;
task->free_taskdata = free_taskdata;
+ task->freedata = freedata;
task->pool = pool;
task_scheduler_push(pool->scheduler, task, priority);
}
+void BLI_task_pool_push(
+ TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskPriority priority)
+{
+ BLI_task_pool_push_ex(pool, run, taskdata, free_taskdata, NULL, priority);
+}
+
void BLI_task_pool_work_and_wait(TaskPool *pool)
{
TaskScheduler *scheduler = pool->scheduler;
@@ -398,8 +481,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool)
work_task->run(pool, work_task->taskdata, 0);
/* delete task */
- if (work_task->free_taskdata)
- MEM_freeN(work_task->taskdata);
+ task_data_free(task, 0);
MEM_freeN(work_task);
/* notify pool task was done */
@@ -493,10 +575,18 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool)
* - Chunk iterations to reduce number of spin locks.
*/
+/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */
+#define MALLOCA(_size) ((_size) <= 8192) ? alloca((_size)) : MEM_mallocN((_size), __func__)
+#define MALLOCA_FREE(_mem, _size) if (((_mem) != NULL) && ((_size) > 8192)) MEM_freeN((_mem))
+
typedef struct ParallelRangeState {
int start, stop;
void *userdata;
+ void *userdata_chunk;
+ size_t userdata_chunk_size;
+
TaskParallelRangeFunc func;
+ TaskParallelRangeFuncEx func_ex;
int iter;
int chunk_size;
@@ -522,23 +612,50 @@ BLI_INLINE bool parallel_range_next_iter_get(
static void parallel_range_func(
TaskPool * __restrict pool,
void *UNUSED(taskdata),
- int UNUSED(threadid))
+ int threadid)
{
ParallelRangeState * __restrict state = BLI_task_pool_userdata(pool);
int iter, count;
+
+ const bool use_userdata_chunk = (state->func_ex != NULL) &&
+ (state->userdata_chunk_size != 0) && (state->userdata_chunk != NULL);
+ void *userdata_chunk = use_userdata_chunk ? MALLOCA(state->userdata_chunk_size) : NULL;
+
while (parallel_range_next_iter_get(state, &iter, &count)) {
int i;
- for (i = 0; i < count; ++i) {
- state->func(state->userdata, iter + i);
+
+ if (state->func_ex) {
+ if (use_userdata_chunk) {
+ memcpy(userdata_chunk, state->userdata_chunk, state->userdata_chunk_size);
+ }
+
+ for (i = 0; i < count; ++i) {
+ state->func_ex(state->userdata, userdata_chunk, iter + i, threadid);
+ }
+ }
+ else {
+ for (i = 0; i < count; ++i) {
+ state->func(state->userdata, iter + i);
+ }
}
}
+
+ MALLOCA_FREE(userdata_chunk, state->userdata_chunk_size);
}
-void BLI_task_parallel_range_ex(
+/**
+ * This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement.
+ *
+ * See public API doc for description of parameters.
+ */
+static void task_parallel_range_ex(
int start, int stop,
void *userdata,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size,
TaskParallelRangeFunc func,
- const int range_threshold,
+ TaskParallelRangeFuncEx func_ex,
+ const bool use_threading,
const bool use_dynamic_scheduling)
{
TaskScheduler *task_scheduler;
@@ -546,15 +663,41 @@ void BLI_task_parallel_range_ex(
ParallelRangeState state;
int i, num_threads, num_tasks;
+ if (start == stop) {
+ return;
+ }
+
BLI_assert(start < stop);
+ if (userdata_chunk_size != 0) {
+ BLI_assert(func_ex != NULL && func == NULL);
+ BLI_assert(userdata_chunk != NULL);
+ }
/* If it's not enough data to be crunched, don't bother with tasks at all,
* do everything from the main thread.
*/
- if (stop - start < range_threshold) {
- for (i = start; i < stop; ++i) {
- func(userdata, i);
+ if (!use_threading) {
+ if (func_ex) {
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+ void *userdata_chunk_local = NULL;
+
+ if (use_userdata_chunk) {
+ userdata_chunk_local = MALLOCA(userdata_chunk_size);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+
+ for (i = start; i < stop; ++i) {
+ func_ex(userdata, userdata_chunk, i, 0);
+ }
+
+ MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
}
+ else {
+ for (i = start; i < stop; ++i) {
+ func(userdata, i);
+ }
+ }
+
return;
}
@@ -572,15 +715,20 @@ void BLI_task_parallel_range_ex(
state.start = start;
state.stop = stop;
state.userdata = userdata;
+ state.userdata_chunk = userdata_chunk;
+ state.userdata_chunk_size = userdata_chunk_size;
state.func = func;
+ state.func_ex = func_ex;
state.iter = start;
if (use_dynamic_scheduling) {
state.chunk_size = 32;
}
else {
- state.chunk_size = (stop - start) / (num_tasks);
+ state.chunk_size = max_ii(1, (stop - start) / (num_tasks));
}
+ num_tasks = max_ii(1, (stop - start) / state.chunk_size);
+
for (i = 0; i < num_tasks; i++) {
BLI_task_pool_push(task_pool,
parallel_range_func,
@@ -594,10 +742,55 @@ void BLI_task_parallel_range_ex(
BLI_spin_end(&state.lock);
}
+/**
+ * This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement.
+ *
+ * \param start First index to process.
+ * \param stop Index to stop looping (excluded).
+ * \param userdata Common userdata passed to all instances of \a func.
+ * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data
+ * (similar to OpenMP's firstprivate).
+ * \param userdata_chunk_size Memory size of \a userdata_chunk.
+ * \param func_ex Callback function (advanced version).
+ * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently),
+ * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently).
+ */
+void BLI_task_parallel_range_ex(
+ int start, int stop,
+ void *userdata,
+ void *userdata_chunk,
+ const size_t userdata_chunk_size,
+ TaskParallelRangeFuncEx func_ex,
+ const bool use_threading,
+ const bool use_dynamic_scheduling)
+{
+ task_parallel_range_ex(
+ start, stop, userdata, userdata_chunk, userdata_chunk_size, NULL, func_ex,
+ use_threading, use_dynamic_scheduling);
+}
+
+/**
+ * A simpler version of \a BLI_task_parallel_range_ex, which does not use \a use_dynamic_scheduling,
+ * and does not handle 'firstprivate'-like \a userdata_chunk.
+ *
+ * \param start First index to process.
+ * \param stop Index to stop looping (excluded).
+ * \param userdata Common userdata passed to all instances of \a func.
+ * \param func Callback function (simple version).
+ * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop
+ * (allows caller to use any kind of test to switch on parallelization or not).
+ */
void BLI_task_parallel_range(
int start, int stop,
void *userdata,
- TaskParallelRangeFunc func)
+ TaskParallelRangeFunc func,
+ const bool use_threading)
{
- BLI_task_parallel_range_ex(start, stop, userdata, func, 64, false);
+ task_parallel_range_ex(start, stop, userdata, NULL, 0, func, NULL, use_threading, false);
}
+
+#undef MALLOCA
+#undef MALLOCA_FREE
+
diff --git a/source/blender/blenlib/intern/time.c b/source/blender/blenlib/intern/time.c
index a0fb78cd193..3cf3221bd08 100644
--- a/source/blender/blenlib/intern/time.c
+++ b/source/blender/blenlib/intern/time.c
@@ -33,8 +33,9 @@
#include "PIL_time.h"
#ifdef WIN32
-
+#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x501 /* Windows XP or newer */
+#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 4ae9249ec0d..e755a7ae52c 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -72,20 +72,20 @@ size_t BLI_timecode_string_from_time(
time = -time;
}
- if (time >= 3600) {
+ if (time >= 3600.0f) {
/* hours */
/* XXX should we only display a single digit for hours since clips are
* VERY UNLIKELY to be more than 1-2 hours max? However, that would
* go against conventions...
*/
hours = (int)time / 3600;
- time = (float)fmod(time, 3600);
+ time = fmodf(time, 3600);
}
- if (time >= 60) {
+ if (time >= 60.0f) {
/* minutes */
minutes = (int)time / 60;
- time = (float)fmod(time, 60);
+ time = fmodf(time, 60);
}
if (power <= 0) {
@@ -163,6 +163,18 @@ size_t BLI_timecode_string_from_time(
}
break;
}
+ case USER_TIMECODE_SUBRIP:
+ {
+ /* SubRip, like SMPTE milliseconds but seconds and milliseconds are separated by a comma, not a dot... */
+
+ /* precision of decimal part */
+ const int ms_dp = (power <= 0) ? (1 - power) : 1;
+ const int ms = iroundf((time - (float)seconds) * 1000.0f);
+
+ rlen = BLI_snprintf_rlen(
+ str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
+ break;
+ }
case USER_TIMECODE_SECONDS_ONLY:
{
/* only show the original seconds display */
diff --git a/source/blender/blenlib/intern/voxel.c b/source/blender/blenlib/intern/voxel.c
index 5d58f9e9231..093333769d6 100644
--- a/source/blender/blenlib/intern/voxel.c
+++ b/source/blender/blenlib/intern/voxel.c
@@ -29,10 +29,10 @@
* \ingroup bli
*/
-
-#include "BLI_voxel.h"
#include "BLI_utildefines.h"
+#include "BLI_voxel.h"
+#include "BLI_strict_flags.h"
BLI_INLINE float D(float *data, const int res[3], int x, int y, int z)
@@ -49,9 +49,9 @@ float BLI_voxel_sample_nearest(float *data, const int res[3], const float co[3])
{
int xi, yi, zi;
- xi = co[0] * res[0];
- yi = co[1] * res[1];
- zi = co[2] * res[2];
+ xi = (int)(co[0] * (float)res[0]);
+ yi = (int)(co[1] * (float)res[1]);
+ zi = (int)(co[2] * (float)res[2]);
return D(data, res, xi, yi, zi);
}
@@ -68,7 +68,7 @@ BLI_INLINE int FLOORI(float x)
*
* this causes the test (x + 2) < 0 with int x == 2147483647 to return false (x being an integer,
* x + 2 should wrap around to -2147483647 so the test < 0 should return true, which it doesn't) */
-BLI_INLINE int _clamp(int a, int b, int c)
+BLI_INLINE int64_t _clamp(int a, int b, int c)
{
return (a < b) ? b : ((a > c) ? c : a);
}
@@ -77,15 +77,24 @@ float BLI_voxel_sample_trilinear(float *data, const int res[3], const float co[3
{
if (data) {
- const float xf = co[0] * res[0] - 0.5f;
- const float yf = co[1] * res[1] - 0.5f;
- const float zf = co[2] * res[2] - 0.5f;
+ const float xf = co[0] * (float)res[0] - 0.5f;
+ const float yf = co[1] * (float)res[1] - 0.5f;
+ const float zf = co[2] * (float)res[2] - 0.5f;
const int x = FLOORI(xf), y = FLOORI(yf), z = FLOORI(zf);
- const int xc[2] = {_clamp(x, 0, res[0] - 1), _clamp(x + 1, 0, res[0] - 1)};
- const int yc[2] = {res[0] * _clamp(y, 0, res[1] - 1), res[0] * _clamp(y + 1, 0, res[1] - 1)};
- const int zc[2] = {res[0] * res[1] * _clamp(z, 0, res[2] - 1), res[0] * res[1] * _clamp(z + 1, 0, res[2] - 1)};
+ const int64_t xc[2] = {
+ _clamp(x, 0, res[0] - 1),
+ _clamp(x + 1, 0, res[0] - 1),
+ };
+ const int64_t yc[2] = {
+ _clamp(y, 0, res[1] - 1) * res[0],
+ _clamp(y + 1, 0, res[1] - 1) * res[0],
+ };
+ const int64_t zc[2] = {
+ _clamp(z, 0, res[2] - 1) * res[0] * res[1],
+ _clamp(z + 1, 0, res[2] - 1) * res[0] * res[1],
+ };
const float dx = xf - (float)x;
const float dy = yf - (float)y;
@@ -103,18 +112,31 @@ float BLI_voxel_sample_trilinear(float *data, const int res[3], const float co[3
}
return 0.f;
}
-
float BLI_voxel_sample_triquadratic(float *data, const int res[3], const float co[3])
{
if (data) {
- const float xf = co[0] * res[0], yf = co[1] * res[1], zf = co[2] * res[2];
+ const float xf = co[0] * (float)res[0];
+ const float yf = co[1] * (float)res[1];
+ const float zf = co[2] * (float)res[2];
const int x = FLOORI(xf), y = FLOORI(yf), z = FLOORI(zf);
- const int xc[3] = {_clamp(x - 1, 0, res[0] - 1), _clamp(x, 0, res[0] - 1), _clamp(x + 1, 0, res[0] - 1)};
- const int yc[3] = {res[0] * _clamp(y - 1, 0, res[1] - 1), res[0] * _clamp(y, 0, res[1] - 1), res[0] * _clamp(y + 1, 0, res[1] - 1)};
- const int zc[3] = {res[0] * res[1] * _clamp(z - 1, 0, res[2] - 1), res[0] * res[1] * _clamp(z, 0, res[2] - 1), res[0] * res[1] * _clamp(z + 1, 0, res[2] - 1)};
+ const int64_t xc[3] = {
+ _clamp(x - 1, 0, res[0] - 1),
+ _clamp(x, 0, res[0] - 1),
+ _clamp(x + 1, 0, res[0] - 1),
+ };
+ const int64_t yc[3] = {
+ _clamp(y - 1, 0, res[1] - 1) * res[0],
+ _clamp(y, 0, res[1] - 1) * res[0],
+ _clamp(y + 1, 0, res[1] - 1) * res[0],
+ };
+ const int64_t zc[3] = {
+ _clamp(z - 1, 0, res[2] - 1) * res[0] * res[1],
+ _clamp(z, 0, res[2] - 1) * res[0] * res[1],
+ _clamp(z + 1, 0, res[2] - 1) * res[0] * res[1],
+ };
const float dx = xf - (float)x, dy = yf - (float)y, dz = zf - (float)z;
const float u[3] = {dx * (0.5f * dx - 1.f) + 0.5f, dx * (1.0f - dx) + 0.5f, 0.5f * dx * dx};
@@ -139,13 +161,29 @@ float BLI_voxel_sample_tricubic(float *data, const int res[3], const float co[3]
{
if (data) {
- const float xf = co[0] * res[0] - 0.5f, yf = co[1] * res[1] - 0.5f, zf = co[2] * res[2] - 0.5f;
+ const float xf = co[0] * (float)res[0] - 0.5f;
+ const float yf = co[1] * (float)res[1] - 0.5f;
+ const float zf = co[2] * (float)res[2] - 0.5f;
const int x = FLOORI(xf), y = FLOORI(yf), z = FLOORI(zf);
- const int xc[4] = {_clamp(x - 1, 0, res[0] - 1), _clamp(x, 0, res[0] - 1), _clamp(x + 1, 0, res[0] - 1), _clamp(x + 2, 0, res[0] - 1)};
- const int yc[4] = {res[0] * _clamp(y - 1, 0, res[1] - 1), res[0] * _clamp(y, 0, res[1] - 1), res[0] * _clamp(y + 1, 0, res[1] - 1), res[0] * _clamp(y + 2, 0, res[1] - 1)};
- const int zc[4] = {res[0] * res[1] * _clamp(z - 1, 0, res[2] - 1), res[0] * res[1] * _clamp(z, 0, res[2] - 1), res[0] * res[1] * _clamp(z + 1, 0, res[2] - 1), res[0] * res[1] * _clamp(z + 2, 0, res[2] - 1)};
-
+ const int64_t xc[4] = {
+ _clamp(x - 1, 0, res[0] - 1),
+ _clamp(x, 0, res[0] - 1),
+ _clamp(x + 1, 0, res[0] - 1),
+ _clamp(x + 2, 0, res[0] - 1),
+ };
+ const int64_t yc[4] = {
+ _clamp(y - 1, 0, res[1] - 1) * res[0],
+ _clamp(y, 0, res[1] - 1) * res[0],
+ _clamp(y + 1, 0, res[1] - 1) * res[0],
+ _clamp(y + 2, 0, res[1] - 1) * res[0],
+ };
+ const int64_t zc[4] = {
+ _clamp(z - 1, 0, res[2] - 1) * res[0] * res[1],
+ _clamp(z, 0, res[2] - 1) * res[0] * res[1],
+ _clamp(z + 1, 0, res[2] - 1) * res[0] * res[1],
+ _clamp(z + 2, 0, res[2] - 1) * res[0] * res[1],
+ };
const float dx = xf - (float)x, dy = yf - (float)y, dz = zf - (float)z;
float u[4], v[4], w[4];
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 32ab16b4b5a..3b06b7df09a 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -198,7 +198,8 @@ void get_default_root(char *root)
/* if GetWindowsDirectory fails, something has probably gone wrong,
* we are trying the blender install dir though */
if (GetModuleFileName(NULL, str, MAX_PATH + 1)) {
- printf("Error! Could not get the Windows Directory - Defaulting to Blender installation Dir!");
+ printf("Error! Could not get the Windows Directory - "
+ "Defaulting to Blender installation Dir!\n");
root[0] = str[0];
root[1] = ':';
root[2] = '\\';
@@ -209,7 +210,8 @@ void get_default_root(char *root)
int i;
int rc = 0;
/* now something has gone really wrong - still trying our best guess */
- printf("Error! Could not get the Windows Directory - Defaulting to first valid drive! Path might be invalid!");
+ printf("Error! Could not get the Windows Directory - "
+ "Defaulting to first valid drive! Path might be invalid!\n");
tmp = GetLogicalDrives();
for (i = 2; i < 26; i++) {
if ((tmp >> i) & 1) {
@@ -224,7 +226,7 @@ void get_default_root(char *root)
}
}
if (0 == rc) {
- printf("ERROR in 'get_default_root': can't find a valid drive!");
+ printf("ERROR in 'get_default_root': can't find a valid drive!\n");
root[0] = 'C';
root[1] = ':';
root[2] = '\\';
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 77bdb99b54b..bf47682297d 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -44,6 +44,7 @@ struct MemFile;
struct ReportList;
struct Scene;
struct UserDef;
+struct View3D;
struct bContext;
struct BHead;
struct FileData;
@@ -70,186 +71,39 @@ typedef struct BlendFileData {
BlenFileType type;
} BlendFileData;
-/**
- * Open a blender file from a pathname. The function
- * returns NULL and sets a report in the list if
- * it cannot open the file.
- *
- * \param filepath The path of the file to open.
- * \param reports If the return value is NULL, errors
- * indicating the cause of the failure.
- * \return The data of the file.
- */
-BlendFileData *BLO_read_from_file(
- const char *filepath,
- struct ReportList *reports);
-
-/**
- * Open a blender file from memory. The function
- * returns NULL and sets a report in the list if
- * it cannot open the file.
- *
- * \param mem The file data.
- * \param memsize The length of \a mem.
- * \param reports If the return value is NULL, errors
- * indicating the cause of the failure.
- * \return The data of the file.
- */
-BlendFileData *BLO_read_from_memory(
- const void *mem, int memsize,
- struct ReportList *reports);
-
-/**
- * oldmain is old main, from which we will keep libraries, images, ..
- * file name is current file, only for retrieving library data */
-
+BlendFileData *BLO_read_from_file(const char *filepath, struct ReportList *reports);
+BlendFileData *BLO_read_from_memory(const void *mem, int memsize, struct ReportList *reports);
BlendFileData *BLO_read_from_memfile(
struct Main *oldmain, const char *filename, struct MemFile *memfile,
struct ReportList *reports);
-/**
- * Free's a BlendFileData structure and _all_ the
- * data associated with it (the userdef data, and
- * the main libblock data).
- *
- * \param bfd The structure to free.
- */
-void
-BLO_blendfiledata_free(BlendFileData *bfd);
-
-/**
- * Open a blendhandle from a file path.
- *
- * \param filepath: The file path to open.
- * \param reports: Report errors in opening the file (can be NULL).
- * \return A handle on success, or NULL on failure.
- */
-BlendHandle *BLO_blendhandle_from_file(
- const char *filepath,
- struct ReportList *reports);
-
-/**
- * Open a blendhandle from memory.
- *
- * \param mem The data to load from.
- * \param memsize The size of the data.
- * \return A handle on success, or NULL on failure.
- */
-
-BlendHandle *BLO_blendhandle_from_memory(
- const void *mem, int memsize);
-
-/**
- * Gets the names of all the datablocks in a file
- * of a certain type (ie. All the scene names in
- * a file).
- *
- * \param bh The blendhandle to access.
- * \param ofblocktype The type of names to get.
- * \param tot_names The length of the returned list.
- * \return A BLI_linklist of strings. The string links
- * should be freed with malloc.
- */
-struct LinkNode *BLO_blendhandle_get_datablock_names(
- BlendHandle *bh,
- int ofblocktype, int *tot_names);
+void BLO_blendfiledata_free(BlendFileData *bfd);
-/**
- * Gets the previews of all the datablocks in a file
- * of a certain type (ie. All the scene names in
- * a file).
- *
- * \param bh The blendhandle to access.
- * \param ofblocktype The type of names to get.
- * \param tot_prev The length of the returned list.
- * \return A BLI_linklist of PreviewImage. The PreviewImage links
- * should be freed with malloc.
- */
-struct LinkNode *BLO_blendhandle_get_previews(
- BlendHandle *bh,
- int ofblocktype, int *tot_prev);
+BlendHandle *BLO_blendhandle_from_file(const char *filepath, struct ReportList *reports);
+BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize);
-/**
- * Gets the names of all the datablock groups in a
- * file. (ie. file contains Scene, Mesh, and Lamp
- * datablocks).
- *
- * \param bh The blendhandle to access.
- * \return A BLI_linklist of strings. The string links
- * should be freed with malloc.
- */
+struct LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names);
+struct LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev);
struct LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh);
-/**
- * Close and free a blendhandle. The handle
- * becomes invalid after this call.
- *
- * \param bh The handle to close.
- */
-void
-BLO_blendhandle_close(BlendHandle *bh);
+void BLO_blendhandle_close(BlendHandle *bh);
/***/
#define BLO_GROUP_MAX 32
bool BLO_has_bfile_extension(const char *str);
-
-/**
- * \param path the full path to explode.
- * \param r_dir the string that'll contain path up to blend file itself ('library' path).
- * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
- * \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
- * \return true if path contains a blend file.
- */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name);
-
-/**
- * Initialize the BlendHandle for appending or linking library data.
- *
- * \param mainvar The current main database eg G.main or CTX_data_main(C).
- * \param bh A blender file handle as returned by BLO_blendhandle_from_file or BLO_blendhandle_from_memory.
- * \param filepath Used for relative linking, copied to the lib->name
- * \return the library Main, to be passed to BLO_library_append_named_part as mainl.
- */
-struct Main *BLO_library_append_begin(
- struct Main *mainvar, BlendHandle **bh,
- const char *filepath);
-
-
-/**
- * Link/Append a named datablock from an external blend file.
- *
- * \param mainl The main database to link from (not the active one).
- * \param bh The blender file handle.
- * \param idname The name of the datablock (without the 2 char ID prefix)
- * \param idcode The kind of datablock to link.
- * \return the appended ID when found.
- */
-struct ID *BLO_library_append_named_part(
+struct Main *BLO_library_link_begin(struct Main *mainvar, BlendHandle **bh, const char *filepath);
+struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, const short idcode, const char *name);
+struct ID *BLO_library_link_named_part_ex(
struct Main *mainl, BlendHandle **bh,
- const char *idname, const int idcode);
-
-/**
- * Link/Append a named datablock from an external blend file.
- * optionally instance the object in the scene when the flags are set.
- *
- * \param C The context, when NULL instancing object in the scene isn't done.
- * \param mainl The main database to link from (not the active one).
- * \param bh The blender file handle.
- * \param idname The name of the datablock (without the 2 char ID prefix)
- * \param idcode The kind of datablock to link.
- * \param flag Options for linking, used for instancing.
- * \return the appended ID when found.
- */
-struct ID *BLO_library_append_named_part_ex(
- const struct bContext *C, struct Main *mainl, BlendHandle **bh,
- const char *idname, const int idcode, const short flag);
-
-void BLO_library_append_end(const struct bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag);
+ const short idcode, const char *name, const short flag,
+ struct Scene *scene, struct View3D *v3d);
+void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d);
-void BLO_library_append_all(struct Main *mainl, BlendHandle *bh);
+void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh);
void *BLO_library_read_struct(struct FileData *fd, struct BHead *bh, const char *blockname);
@@ -258,34 +112,15 @@ BlendFileData *blo_read_blendafterruntime(int file, const char *name, int actual
/* internal function but we need to expose it */
void blo_lib_link_screen_restore(struct Main *newmain, struct bScreen *curscreen, struct Scene *curscene);
-/**
- * BLO_expand_main() loops over all ID data in Main to mark relations.
- * Set (id->flag & LIB_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
- *
- * \param expand_doit_func() gets called for each ID block it finds
- */
-void BLO_main_expander(void (*expand_doit_func)(void *, struct Main *, void *));
+typedef void (*BLOExpandDoitCallback) (void *fdhandle, struct Main *mainvar, void *idv);
-/**
- * BLO_expand_main() loops over all ID data in Main to mark relations.
- * Set (id->flag & LIB_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
- *
- * \param fdhandle usually filedata, or own handle
- * \param mainvar the Main database to expand
- */
+void BLO_main_expander(BLOExpandDoitCallback expand_doit_func);
void BLO_expand_main(void *fdhandle, struct Main *mainvar);
/* Update defaults in startup.blend & userprefs.blend, without having to save and embed it */
void BLO_update_defaults_userpref_blend(void);
void BLO_update_defaults_startup_blend(struct Main *mainvar);
-/**
- * Does a very light reading of given .blend file to extract its stored thumbnail.
- *
- * \param filepath The path of the file to extract thumbnail from.
- * \return The raw thumbnail
- * (MEM-allocated, as stored in file, use BKE_main_thumbnail_to_imbuf() to convert it to ImBuf image).
- */
struct BlendThumbnail *BLO_thumbnail_from_file(const char *filepath);
#ifdef __cplusplus
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
index 0d66eb743aa..af3bc2dbdcd 100644
--- a/source/blender/blenloader/BLO_writefile.h
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -38,9 +38,11 @@ struct MemFile;
struct Main;
struct ReportList;
-extern int BLO_write_file(struct Main *mainvar, const char *filepath, int write_flags,
+extern bool BLO_write_file(
+ struct Main *mainvar, const char *filepath, int write_flags,
struct ReportList *reports, const struct BlendThumbnail *thumb);
-extern int BLO_write_file_mem(struct Main *mainvar, struct MemFile *compare, struct MemFile *current, int write_flags);
+extern bool BLO_write_file_mem(
+ struct Main *mainvar, struct MemFile *compare, struct MemFile *current, int write_flags);
#endif
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
deleted file mode 100644
index 7f2a1e0723c..00000000000
--- a/source/blender/blenloader/SConscript
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- '#/intern/guardedalloc',
- '../blenfont',
- '../blenkernel',
- '../blenlib',
- '../blentranslation',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../nodes',
- '../render/extern/include',
- env['BF_ZLIB_INC'],
- ]
-
-defs = []
-
-if env['BF_BUILDINFO']:
- defs.append('WITH_BUILDINFO')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- env.BlenderLib('bf_blenloader', sources, incs, defs, libtype=['core', 'player'], priority = [167, 30]) #, cc_compileflags=['/WX'])
-else:
- env.BlenderLib('bf_blenloader', sources, incs, defs, libtype=['core', 'player', 'player2'], priority=[167, 30, 5])
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
index e8d7a46687f..3cae95d418e 100644
--- a/source/blender/blenloader/intern/readblenentry.c
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -72,6 +72,13 @@ void BLO_blendhandle_print_sizes(BlendHandle *, void *);
/* Access routines used by filesel. */
+/**
+ * Open a blendhandle from a file path.
+ *
+ * \param filepath The file path to open.
+ * \param reports Report errors in opening the file (can be NULL).
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports)
{
BlendHandle *bh;
@@ -81,6 +88,13 @@ BlendHandle *BLO_blendhandle_from_file(const char *filepath, ReportList *reports
return bh;
}
+/**
+ * Open a blendhandle from memory.
+ *
+ * \param mem The data to load from.
+ * \param memsize The size of the data.
+ * \return A handle on success, or NULL on failure.
+ */
BlendHandle *BLO_blendhandle_from_memory(const void *mem, int memsize)
{
BlendHandle *bh;
@@ -120,6 +134,14 @@ void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
fprintf(fp, "]\n");
}
+/**
+ * Gets the names of all the datablocks in a file of a certain type (e.g. all the scene names in a file).
+ *
+ * \param bh The blendhandle to access.
+ * \param ofblocktype The type of names to get.
+ * \param tot_names The length of the returned list.
+ * \return A BLI_linklist of strings. The string links should be freed with malloc.
+ */
LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype, int *tot_names)
{
FileData *fd = (FileData *) bh;
@@ -142,6 +164,14 @@ LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype,
return names;
}
+/**
+ * Gets the previews of all the datablocks in a file of a certain type (e.g. all the scene previews in a file).
+ *
+ * \param bh The blendhandle to access.
+ * \param ofblocktype The type of names to get.
+ * \param tot_prev The length of the returned list.
+ * \return A BLI_linklist of PreviewImage. The PreviewImage links should be freed with malloc.
+ */
LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *tot_prev)
{
FileData *fd = (FileData *) bh;
@@ -232,7 +262,13 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *to
return previews;
}
-LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
+/**
+ * Gets the names of all the linkable datablock types available in a file. (e.g. "Scene", "Mesh", "Lamp", etc.).
+ *
+ * \param bh The blendhandle to access.
+ * \return A BLI_linklist of strings. The string links should be freed with malloc.
+ */
+LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
{
FileData *fd = (FileData *) bh;
GSet *gathered = BLI_gset_ptr_new("linkable_groups gh");
@@ -247,9 +283,8 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
if (BKE_idcode_is_linkable(bhead->code)) {
const char *str = BKE_idcode_to_name(bhead->code);
- if (!BLI_gset_haskey(gathered, (void *)str)) {
+ if (BLI_gset_add(gathered, (void *)str)) {
BLI_linklist_prepend(&names, strdup(str));
- BLI_gset_insert(gathered, (void *)str);
}
}
}
@@ -260,6 +295,11 @@ LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
return names;
}
+/**
+ * Close and free a blendhandle. The handle becomes invalid after this call.
+ *
+ * \param bh The handle to close.
+ */
void BLO_blendhandle_close(BlendHandle *bh)
{
FileData *fd = (FileData *) bh;
@@ -269,6 +309,14 @@ void BLO_blendhandle_close(BlendHandle *bh)
/**********/
+/**
+ * Open a blender file from a pathname. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param filepath The path of the file to open.
+ * \param reports If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
{
BlendFileData *bfd = NULL;
@@ -284,6 +332,15 @@ BlendFileData *BLO_read_from_file(const char *filepath, ReportList *reports)
return bfd;
}
+/**
+ * Open a blender file from memory. The function returns NULL
+ * and sets a report in the list if it cannot open the file.
+ *
+ * \param mem The file data.
+ * \param memsize The length of \a mem.
+ * \param reports If the return value is NULL, errors indicating the cause of the failure.
+ * \return The data of the file.
+ */
BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *reports)
{
BlendFileData *bfd = NULL;
@@ -299,11 +356,17 @@ BlendFileData *BLO_read_from_memory(const void *mem, int memsize, ReportList *re
return bfd;
}
+/**
+ * Used for undo/redo, skips part of libraries reading (assuming their data are already loaded & valid).
+ *
+ * \param oldmain old main, from which we will keep libraries and other datablocks that should not have changed.
+ * \param filename current file, only for retrieving library data.
+ */
BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFile *memfile, ReportList *reports)
{
BlendFileData *bfd = NULL;
FileData *fd;
- ListBase mainlist;
+ ListBase old_mainlist;
fd = blo_openblendermemfile(memfile, reports);
if (fd) {
@@ -314,9 +377,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
blo_clear_proxy_pointers_from_lib(oldmain);
/* separate libraries from old main */
- blo_split_main(&mainlist, oldmain);
+ blo_split_main(&old_mainlist, oldmain);
/* add the library pointers in oldmap lookup */
- blo_add_library_pointer_map(&mainlist, fd);
+ blo_add_library_pointer_map(&old_mainlist, fd);
/* makes lookup of existing images in old main */
blo_make_image_pointer_map(fd, oldmain);
@@ -340,25 +403,55 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil
/* ensures relinked sounds are not freed */
blo_end_sound_pointer_map(fd, oldmain);
- /* move libraries from old main to new main */
- if (bfd && mainlist.first != mainlist.last) {
-
- /* Library structs themselves */
- bfd->main->library = oldmain->library;
- BLI_listbase_clear(&oldmain->library);
-
- /* add the Library mainlist to the new main */
- BLI_remlink(&mainlist, oldmain);
- BLI_addhead(&mainlist, bfd->main);
+ /* Still in-use libraries have already been moved from oldmain to new mainlist,
+ * but oldmain itself shall *never* be 'transferred' to new mainlist! */
+ BLI_assert(old_mainlist.first == oldmain);
+
+ if (bfd && old_mainlist.first != old_mainlist.last) {
+ /* Even though directly used libs have been already moved to new main, indirect ones have not.
+ * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused
+ * data may remain in memory, but think we'll have to live with it. */
+ Main *libmain;
+ Main *newmain = bfd->main;
+ ListBase new_mainlist = {newmain, newmain};
+
+ for (libmain = oldmain->next; libmain; libmain = libmain->next) {
+ /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent
+ * to detect indirect-linked ones... */
+ if (libmain->curlib && (libmain->curlib->parent != NULL)) {
+ BLI_remlink(&old_mainlist, libmain);
+ BLI_addtail(&new_mainlist, libmain);
+ }
+#if 0
+ else {
+ printf("Dropped Main for lib: %s\n", libmain->curlib->id.name);
+ }
+#endif
+ }
+ /* In any case, we need to move all lib datablocks themselves - those are 'first level data',
+ * getting rid of them would imply updating spaces & co to prevent invalid pointers access. */
+ BLI_movelisttolist(&newmain->library, &oldmain->library);
+
+ blo_join_main(&new_mainlist);
}
- blo_join_main(&mainlist);
-
+
+ /* printf("Remaining mains/libs in oldmain: %d\n", BLI_listbase_count(&fd->old_mainlist) - 1); */
+
+ /* That way, libs (aka mains) we did not reuse in new undone/redone state
+ * will be cleared together with oldmain... */
+ blo_join_main(&old_mainlist);
+
blo_freefiledata(fd);
}
return bfd;
}
+/**
+ * Frees a BlendFileData structure and *all* the data associated with it (the userdef data, and the main libblock data).
+ *
+ * \param bfd The structure to free.
+ */
void BLO_blendfiledata_free(BlendFileData *bfd)
{
if (bfd->main) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 55cadaef459..a5267175dfa 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -124,6 +124,7 @@
#include "BKE_global.h" // for G
#include "BKE_group.h"
#include "BKE_library.h" // for which_libbase
+#include "BKE_library_query.h"
#include "BKE_idcode.h"
#include "BKE_material.h"
#include "BKE_main.h" // for Main
@@ -254,7 +255,7 @@ void blo_reportf_wrap(ReportList *reports, ReportType type, const char *format,
BKE_report(reports, type, fixed_buf);
if (G.background == 0) {
- printf("%s\n", fixed_buf);
+ printf("%s: %s\n", BKE_report_type_str(type), fixed_buf);
}
}
@@ -618,7 +619,10 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab
m = BKE_main_new();
BLI_addtail(mainlist, m);
- lib = BKE_libblock_alloc(m, ID_LI, "lib");
+ /* Add library datablock itself to 'main' Main, since libraries are **never** linked data.
+ * Fixes bug where you could end with all ID_LI datablocks having the same name... */
+ lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib");
+ lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */
BLI_strncpy(lib->name, filepath, sizeof(lib->name));
BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath));
@@ -851,6 +855,12 @@ BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
return(bhead);
}
+/* Warning! Caller's responsability to ensure given bhead **is** and ID one! */
+const char *bhead_id_name(const FileData *fd, const BHead *bhead)
+{
+ return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
+}
+
static void decode_blender_header(FileData *fd)
{
char header[SIZEOFBLENDERHEADER], num[4];
@@ -1290,12 +1300,27 @@ void blo_freefiledata(FileData *fd)
/* ************ DIV ****************** */
+/**
+ * Check whether given path ends with a blend file compatible extension (.blend, .ble or .blend.gz).
+ *
+ * \param str The path to check.
+ * \return true is this path ends with a blender file extension.
+ */
bool BLO_has_bfile_extension(const char *str)
{
const char *ext_test[4] = {".blend", ".ble", ".blend.gz", NULL};
return BLI_testextensie_array(str, ext_test);
}
+/**
+ * Try to explode given path into its 'library components' (i.e. a .blend file, id type/group, and datablock itself).
+ *
+ * \param path the full path to explode.
+ * \param r_dir the string that'll contain path up to blend file itself ('library' path).
+ * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL.
+ * \param r_name the string that'll contain data's name part of the path, if any. May be NULL.
+ * \return true if path contains a blend file.
+ */
bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
{
/* We might get some data names with slashes, so we have to go up in path until we find blend file itself,
@@ -1320,7 +1345,7 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
while ((slash = (char *)BLI_last_slash(r_dir))) {
char tc = *slash;
*slash = '\0';
- if (BLO_has_bfile_extension(r_dir)) {
+ if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) {
break;
}
@@ -1352,6 +1377,13 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha
return true;
}
+/**
+ * Does a very light reading of given .blend file to extract its stored thumbnail.
+ *
+ * \param filepath The path of the file to extract thumbnail from.
+ * \return The raw thumbnail
+ * (MEM-allocated, as stored in file, use BKE_main_thumbnail_to_imbuf() to convert it to ImBuf image).
+ */
BlendThumbnail *BLO_thumbnail_from_file(const char *filepath)
{
FileData *fd;
@@ -1465,8 +1497,7 @@ static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user
{
ID *id = newlibadr(fd, lib, adr);
- if (id)
- id->us++;
+ id_us_plus_no_lib(id);
return id;
}
@@ -1533,8 +1564,9 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain)
for (; ima; ima = ima->id.next) {
if (ima->cache)
oldnewmap_insert(fd->imamap, ima->cache, ima->cache, 0);
- if (ima->gputexture)
- oldnewmap_insert(fd->imamap, ima->gputexture, ima->gputexture, 0);
+ for (a = 0; a < TEXTARGET_COUNT; a++)
+ if (ima->gputexture[a])
+ oldnewmap_insert(fd->imamap, ima->gputexture[a], ima->gputexture[a], 0);
if (ima->rr)
oldnewmap_insert(fd->imamap, ima->rr, ima->rr, 0);
for (a=0; a < IMA_MAX_RENDER_SLOT; a++)
@@ -1570,15 +1602,18 @@ void blo_end_image_pointer_map(FileData *fd, Main *oldmain)
for (; ima; ima = ima->id.next) {
ima->cache = newimaadr(fd, ima->cache);
if (ima->cache == NULL) {
- ima->bindcode = 0;
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
- ima->gputexture = NULL;
+ for (i = 0; i < TEXTARGET_COUNT; i++) {
+ ima->bindcode[i] = 0;
+ ima->gputexture[i] = NULL;
+ }
ima->rr = NULL;
}
for (i = 0; i < IMA_MAX_RENDER_SLOT; i++)
ima->renders[i] = newimaadr(fd, ima->renders[i]);
- ima->gputexture = newimaadr(fd, ima->gputexture);
+ for (i = 0; i < TEXTARGET_COUNT; i++)
+ ima->gputexture[i] = newimaadr(fd, ima->gputexture[i]);
ima->rr = newimaadr(fd, ima->rr);
}
for (; sce; sce = sce->id.next) {
@@ -1769,9 +1804,9 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain)
/* undo file support: add all library pointers in lookup */
-void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
+void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd)
{
- Main *ptr = mainlist->first;
+ Main *ptr = old_mainlist->first;
ListBase *lbarray[MAX_LIBARRAY];
for (ptr = ptr->next; ptr; ptr = ptr->next) {
@@ -1782,6 +1817,8 @@ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
oldnewmap_insert(fd->libmap, id, id, GS(id->name));
}
}
+
+ fd->old_mainlist = old_mainlist;
}
@@ -1813,11 +1850,12 @@ static void *read_struct(FileData *fd, BHead *bh, const char *blockname)
if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN))
switch_endian_structs(fd->filesdna, bh);
- if (fd->compflags[bh->SDNAnr]) { /* flag==0: doesn't exist anymore */
- if (fd->compflags[bh->SDNAnr] == 2) {
+ if (fd->compflags[bh->SDNAnr] != SDNA_CMP_REMOVED) {
+ if (fd->compflags[bh->SDNAnr] == SDNA_CMP_NOT_EQUAL) {
temp = DNA_struct_reconstruct(fd->memsdna, fd->filesdna, fd->compflags, bh->SDNAnr, bh->nr, (bh+1));
}
else {
+ /* SDNA_CMP_EQUAL */
temp = MEM_mallocN(bh->len, blockname);
memcpy(temp, (bh+1), bh->len);
}
@@ -2065,6 +2103,7 @@ static void _IDP_DirectLinkGroup_OrFree(IDProperty **prop, int switch_endian, Fi
/* stub function */
static void IDP_LibLinkProperty(IDProperty *UNUSED(prop), int UNUSED(switch_endian), FileData *UNUSED(fd))
{
+ /* Should we do something here, prop should be ensured to be non-NULL first... */
}
/* ************ READ IMAGE PREVIEW *************** */
@@ -2123,12 +2162,13 @@ static void lib_link_brush(FileData *fd, Main *main)
/* only link ID pointers */
for (brush = main->brush.first; brush; brush = brush->id.next) {
- if (brush->id.flag & LIB_NEED_LINK) {
- brush->id.flag -= LIB_NEED_LINK;
+ if (brush->id.tag & LIB_TAG_NEED_LINK) {
+ brush->id.tag &= ~LIB_TAG_NEED_LINK;
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image);
+ brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush);
brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
}
}
@@ -2158,8 +2198,8 @@ static void lib_link_palette(FileData *UNUSED(fd), Main *main)
/* only link ID pointers */
for (palette = main->palettes.first; palette; palette = palette->id.next) {
- if (palette->id.flag & LIB_NEED_LINK) {
- palette->id.flag -= LIB_NEED_LINK;
+ if (palette->id.tag & LIB_TAG_NEED_LINK) {
+ palette->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2176,8 +2216,8 @@ static void lib_link_paint_curve(FileData *UNUSED(fd), Main *main)
/* only link ID pointers */
for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
- if (pc->id.flag & LIB_NEED_LINK) {
- pc->id.flag -= LIB_NEED_LINK;
+ if (pc->id.tag & LIB_TAG_NEED_LINK) {
+ pc->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2187,14 +2227,6 @@ static void direct_link_paint_curve(FileData *fd, PaintCurve *pc)
pc->points = newdataadr(fd, pc->points);
}
-
-static void direct_link_script(FileData *UNUSED(fd), Script *script)
-{
- script->id.us = 1;
- SCRIPT_SET_NULL(script);
-}
-
-
/* ************ READ PACKEDFILE *************** */
static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
@@ -2218,13 +2250,13 @@ static void lib_link_ipo(FileData *fd, Main *main)
Ipo *ipo;
for (ipo = main->ipo.first; ipo; ipo = ipo->id.next) {
- if (ipo->id.flag & LIB_NEED_LINK) {
+ if (ipo->id.tag & LIB_TAG_NEED_LINK) {
IpoCurve *icu;
for (icu = ipo->curve.first; icu; icu = icu->next) {
if (icu->driver)
icu->driver->ob = newlibadr(fd, ipo->id.lib, icu->driver->ob);
}
- ipo->id.flag -= LIB_NEED_LINK;
+ ipo->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -2440,8 +2472,8 @@ static void lib_link_action(FileData *fd, Main *main)
bActionChannel *chan;
for (act = main->action.first; act; act = act->id.next) {
- if (act->id.flag & LIB_NEED_LINK) {
- act->id.flag -= LIB_NEED_LINK;
+ if (act->id.tag & LIB_TAG_NEED_LINK) {
+ act->id.tag &= ~LIB_TAG_NEED_LINK;
// XXX deprecated - old animation system <<<
for (chan=act->chanbase.first; chan; chan=chan->next) {
@@ -2652,8 +2684,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock
{
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (sock->prop)
- IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
/* singe node tree (also used for material/scene trees), ntree is not NULL */
@@ -2662,15 +2693,14 @@ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
bNode *node;
bNodeSocket *sock;
- if (ntree->adt) lib_link_animdata(fd, &ntree->id, ntree->adt);
+ lib_link_animdata(fd, &ntree->id, ntree->adt);
ntree->gpd = newlibadr_us(fd, id->lib, ntree->gpd);
for (node = ntree->nodes.first; node; node = node->next) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (node->prop)
- IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(node->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
node->id= newlibadr_us(fd, id->lib, node->id);
@@ -2693,8 +2723,8 @@ static void lib_link_nodetree(FileData *fd, Main *main)
/* only link ID pointers */
for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
- if (ntree->id.flag & LIB_NEED_LINK) {
- ntree->id.flag -= LIB_NEED_LINK;
+ if (ntree->id.tag & LIB_TAG_NEED_LINK) {
+ ntree->id.tag &= ~LIB_TAG_NEED_LINK;
lib_link_ntree(fd, &ntree->id, ntree);
}
}
@@ -2758,8 +2788,6 @@ static void lib_node_do_versions_group_indices(bNode *gnode)
* typedefs */
static void lib_verify_nodetree(Main *main, int UNUSED(open))
{
- bNodeTree *ntree;
-
/* this crashes blender on undo/redo */
#if 0
if (open == 1) {
@@ -2786,9 +2814,10 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
* we have set the NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2 flag, so at this point we can do the
* actual group node updates.
*/
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
- if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2)
+ for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ if (ntree->flag & NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2) {
has_old_groups = 1;
+ }
}
if (has_old_groups) {
@@ -2805,8 +2834,9 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
} FOREACH_NODETREE_END
}
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
ntree->flag &= ~NTREE_DO_VERSIONS_GROUP_EXPOSE_2_56_2;
+ }
}
{
@@ -2912,7 +2942,7 @@ static void lib_verify_nodetree(Main *main, int UNUSED(open))
}
/* verify all group user nodes */
- for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
+ for (bNodeTree *ntree = main->nodetree.first; ntree; ntree = ntree->id.next) {
ntreeVerifyNodes(main, &ntree->id);
}
@@ -2957,7 +2987,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
ntree->adt = newdataadr(fd, ntree->adt);
direct_link_animdata(fd, ntree->adt);
- ntree->id.flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA);
+ ntree->id.tag &= ~(LIB_TAG_ID_RECALC|LIB_TAG_ID_RECALC_DATA);
link_list(fd, &ntree->nodes);
for (node = ntree->nodes.first; node; node = node->next) {
@@ -2994,6 +3024,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
NodeShaderScript *nss = (NodeShaderScript *) node->storage;
nss->bytecode = newdataadr(fd, nss->bytecode);
}
+ else if (node->type==SH_NODE_TEX_POINTDENSITY) {
+ NodeShaderTexPointDensity *npd = (NodeShaderTexPointDensity *) node->storage;
+ memset(&npd->pd, 0, sizeof(npd->pd));
+ }
}
else if (ntree->type==NTREE_COMPOSIT) {
if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
@@ -3159,18 +3193,23 @@ static void direct_link_constraints(FileData *fd, ListBase *lb)
static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
{
- bPoseChannel *pchan;
bArmature *arm = ob->data;
- int rebuild = 0;
if (!pose || !arm)
return;
/* always rebuild to match proxy or lib changes, but on Undo */
- if (fd->memfile == NULL)
- if (ob->proxy || (ob->id.lib==NULL && arm->id.lib))
- rebuild = 1;
-
+ bool rebuild = false;
+
+ if (fd->memfile == NULL) {
+ if (ob->proxy || (ob->id.lib==NULL && arm->id.lib)) {
+ rebuild = true;
+ }
+ }
+
+ /* avoid string */
+ GHash *bone_hash = BKE_armature_bone_from_name_map(arm);
+
if (ob->proxy) {
/* sync proxy layer */
if (pose->proxy_layer)
@@ -3178,28 +3217,32 @@ static void lib_link_pose(FileData *fd, Main *bmain, Object *ob, bPose *pose)
/* sync proxy active bone */
if (pose->proxy_act_bone[0]) {
- Bone *bone = BKE_armature_find_bone_name(arm, pose->proxy_act_bone);
- if (bone)
+ Bone *bone = BLI_ghash_lookup(bone_hash, pose->proxy_act_bone);
+ if (bone) {
arm->act_bone = bone;
+ }
}
}
-
- for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
lib_link_constraints(fd, (ID *)ob, &pchan->constraints);
-
- /* hurms... loop in a loop, but yah... later... (ton) */
- pchan->bone = BKE_armature_find_bone_name(arm, pchan->name);
+
+ pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
pchan->custom = newlibadr_us(fd, arm->id.lib, pchan->custom);
- if (pchan->bone == NULL)
- rebuild= 1;
- else if (ob->id.lib==NULL && arm->id.lib) {
+ if (UNLIKELY(pchan->bone == NULL)) {
+ rebuild = true;
+ }
+ else if ((ob->id.lib == NULL) && arm->id.lib) {
/* local pose selection copied to armature, bit hackish */
pchan->bone->flag &= ~BONE_SELECTED;
pchan->bone->flag |= pchan->selectflag;
}
}
+
+ BLI_ghash_free(bone_hash, NULL, NULL);
+
if (rebuild) {
DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
BKE_pose_tag_recalc(bmain, pose);
@@ -3211,9 +3254,9 @@ static void lib_link_armature(FileData *fd, Main *main)
bArmature *arm;
for (arm = main->armature.first; arm; arm = arm->id.next) {
- if (arm->id.flag & LIB_NEED_LINK) {
- if (arm->adt) lib_link_animdata(fd, &arm->id, arm->adt);
- arm->id.flag -= LIB_NEED_LINK;
+ if (arm->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &arm->id, arm->adt);
+ arm->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3260,14 +3303,14 @@ static void lib_link_camera(FileData *fd, Main *main)
Camera *ca;
for (ca = main->camera.first; ca; ca = ca->id.next) {
- if (ca->id.flag & LIB_NEED_LINK) {
- if (ca->adt) lib_link_animdata(fd, &ca->id, ca->adt);
+ if (ca->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &ca->id, ca->adt);
ca->ipo = newlibadr_us(fd, ca->id.lib, ca->ipo); // XXX deprecated - old animation system
- ca->dof_ob = newlibadr_us(fd, ca->id.lib, ca->dof_ob);
+ ca->dof_ob = newlibadr(fd, ca->id.lib, ca->dof_ob);
- ca->id.flag -= LIB_NEED_LINK;
+ ca->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3288,8 +3331,8 @@ static void lib_link_lamp(FileData *fd, Main *main)
int a;
for (la = main->lamp.first; la; la = la->id.next) {
- if (la->id.flag & LIB_NEED_LINK) {
- if (la->adt) lib_link_animdata(fd, &la->id, la->adt);
+ if (la->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &la->id, la->adt);
for (a = 0; a < MAX_MTEX; a++) {
mtex = la->mtex[a];
@@ -3306,7 +3349,7 @@ static void lib_link_lamp(FileData *fd, Main *main)
la->nodetree->id.lib = la->id.lib;
}
- la->id.flag -= LIB_NEED_LINK;
+ la->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3357,13 +3400,15 @@ static void lib_link_key(FileData *fd, Main *main)
blo_do_versions_key_uidgen(key);
}
- if (key->id.flag & LIB_NEED_LINK) {
- if (key->adt) lib_link_animdata(fd, &key->id, key->adt);
+ BLI_assert((key->id.tag & LIB_TAG_EXTERN) == 0);
+
+ if (key->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &key->id, key->adt);
key->ipo = newlibadr_us(fd, key->id.lib, key->ipo); // XXX deprecated - old animation system
key->from = newlibadr(fd, key->id.lib, key->from);
- key->id.flag -= LIB_NEED_LINK;
+ key->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3424,15 +3469,15 @@ static void lib_link_mball(FileData *fd, Main *main)
int a;
for (mb = main->mball.first; mb; mb = mb->id.next) {
- if (mb->id.flag & LIB_NEED_LINK) {
- if (mb->adt) lib_link_animdata(fd, &mb->id, mb->adt);
+ if (mb->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &mb->id, mb->adt);
for (a = 0; a < mb->totcol; a++)
mb->mat[a] = newlibadr_us(fd, mb->id.lib, mb->mat[a]);
mb->ipo = newlibadr_us(fd, mb->id.lib, mb->ipo); // XXX deprecated - old animation system
- mb->id.flag -= LIB_NEED_LINK;
+ mb->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3462,8 +3507,8 @@ static void lib_link_world(FileData *fd, Main *main)
int a;
for (wrld = main->world.first; wrld; wrld = wrld->id.next) {
- if (wrld->id.flag & LIB_NEED_LINK) {
- if (wrld->adt) lib_link_animdata(fd, &wrld->id, wrld->adt);
+ if (wrld->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &wrld->id, wrld->adt);
wrld->ipo = newlibadr_us(fd, wrld->id.lib, wrld->ipo); // XXX deprecated - old animation system
@@ -3480,7 +3525,7 @@ static void lib_link_world(FileData *fd, Main *main)
wrld->nodetree->id.lib = wrld->id.lib;
}
- wrld->id.flag -= LIB_NEED_LINK;
+ wrld->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3514,8 +3559,8 @@ static void lib_link_vfont(FileData *UNUSED(fd), Main *main)
VFont *vf;
for (vf = main->vfont.first; vf; vf = vf->id.next) {
- if (vf->id.flag & LIB_NEED_LINK) {
- vf->id.flag -= LIB_NEED_LINK;
+ if (vf->id.tag & LIB_TAG_NEED_LINK) {
+ vf->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3534,8 +3579,8 @@ static void lib_link_text(FileData *UNUSED(fd), Main *main)
Text *text;
for (text = main->text.first; text; text = text->id.next) {
- if (text->id.flag & LIB_NEED_LINK) {
- text->id.flag -= LIB_NEED_LINK;
+ if (text->id.tag & LIB_TAG_NEED_LINK) {
+ text->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3576,7 +3621,7 @@ static void direct_link_text(FileData *fd, Text *text)
text->flags = (text->flags) & ~TXT_ISEXT;
- text->id.us = 1;
+ id_us_ensure_real(&text->id);
}
/* ************ READ IMAGE ***************** */
@@ -3586,10 +3631,10 @@ static void lib_link_image(FileData *fd, Main *main)
Image *ima;
for (ima = main->image.first; ima; ima = ima->id.next) {
- if (ima->id.flag & LIB_NEED_LINK) {
- if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ if (ima->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- ima->id.flag -= LIB_NEED_LINK;
+ ima->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3606,9 +3651,11 @@ static void direct_link_image(FileData *fd, Image *ima)
/* if not restored, we keep the binded opengl index */
if (!ima->cache) {
- ima->bindcode = 0;
ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
- ima->gputexture = NULL;
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ ima->bindcode[i] = 0;
+ ima->gputexture[i] = NULL;
+ }
ima->rr = NULL;
}
@@ -3654,8 +3701,8 @@ static void lib_link_curve(FileData *fd, Main *main)
int a;
for (cu = main->curve.first; cu; cu = cu->id.next) {
- if (cu->id.flag & LIB_NEED_LINK) {
- if (cu->adt) lib_link_animdata(fd, &cu->id, cu->adt);
+ if (cu->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &cu->id, cu->adt);
for (a = 0; a < cu->totcol; a++)
cu->mat[a] = newlibadr_us(fd, cu->id.lib, cu->mat[a]);
@@ -3671,7 +3718,7 @@ static void lib_link_curve(FileData *fd, Main *main)
cu->ipo = newlibadr_us(fd, cu->id.lib, cu->ipo); // XXX deprecated - old animation system
cu->key = newlibadr_us(fd, cu->id.lib, cu->key);
- cu->id.flag -= LIB_NEED_LINK;
+ cu->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3746,8 +3793,8 @@ static void lib_link_texture(FileData *fd, Main *main)
Tex *tex;
for (tex = main->tex.first; tex; tex = tex->id.next) {
- if (tex->id.flag & LIB_NEED_LINK) {
- if (tex->adt) lib_link_animdata(fd, &tex->id, tex->adt);
+ if (tex->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &tex->id, tex->adt);
tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima);
tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo);
@@ -3765,7 +3812,7 @@ static void lib_link_texture(FileData *fd, Main *main)
tex->nodetree->id.lib = tex->id.lib;
}
- tex->id.flag -= LIB_NEED_LINK;
+ tex->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3790,6 +3837,7 @@ static void direct_link_texture(FileData *fd, Tex *tex)
if (tex->pd->falloff_curve) {
direct_link_curvemapping(fd, tex->pd->falloff_curve);
}
+ tex->pd->point_data = NULL; /* runtime data */
}
tex->vd = newdataadr(fd, tex->vd);
@@ -3826,12 +3874,12 @@ static void lib_link_material(FileData *fd, Main *main)
int a;
for (ma = main->mat.first; ma; ma = ma->id.next) {
- if (ma->id.flag & LIB_NEED_LINK) {
- if (ma->adt) lib_link_animdata(fd, &ma->id, ma->adt);
+ if (ma->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &ma->id, ma->adt);
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo);
ma->group = newlibadr_us(fd, ma->id.lib, ma->group);
@@ -3849,7 +3897,7 @@ static void lib_link_material(FileData *fd, Main *main)
ma->nodetree->id.lib = ma->id.lib;
}
- ma->id.flag -= LIB_NEED_LINK;
+ ma->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -3963,7 +4011,7 @@ static void lib_link_partdeflect(FileData *fd, ID *id, PartDeflect *pd)
if (pd && pd->tex)
pd->tex = newlibadr_us(fd, id->lib, pd->tex);
if (pd && pd->f_source)
- pd->f_source = newlibadr_us(fd, id->lib, pd->f_source);
+ pd->f_source = newlibadr(fd, id->lib, pd->f_source);
}
static void lib_link_particlesettings(FileData *fd, Main *main)
@@ -3974,8 +4022,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
int a;
for (part = main->particle.first; part; part = part->id.next) {
- if (part->id.flag & LIB_NEED_LINK) {
- if (part->adt) lib_link_animdata(fd, &part->id, part->adt);
+ if (part->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &part->id, part->adt);
part->ipo = newlibadr_us(fd, part->id.lib, part->ipo); // XXX deprecated - old animation system
part->dup_ob = newlibadr(fd, part->id.lib, part->dup_ob);
@@ -4056,7 +4104,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
}
- part->id.flag -= LIB_NEED_LINK;
+ part->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -4237,8 +4285,7 @@ static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
* to each image it used. - z0r */
for (i = 0; i < totface; i++, tf++) {
tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
- if (tf->tpage && tf->tpage->id.us==0)
- tf->tpage->id.us= 1;
+ id_us_ensure_real(&tf->tpage->id);
}
}
@@ -4267,9 +4314,7 @@ static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata
for (j = 0; j < totface; j++, tf++) {
tf->tpage = newlibadr(fd, me->id.lib, tf->tpage);
- if (tf->tpage && tf->tpage->id.us == 0) {
- tf->tpage->id.us = 1;
- }
+ id_us_ensure_real((ID *)tf->tpage);
}
}
}
@@ -4280,13 +4325,13 @@ static void lib_link_mesh(FileData *fd, Main *main)
Mesh *me;
for (me = main->mesh.first; me; me = me->id.next) {
- if (me->id.flag & LIB_NEED_LINK) {
+ if (me->id.tag & LIB_TAG_NEED_LINK) {
int i;
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (me->id.properties) IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- if (me->adt) lib_link_animdata(fd, &me->id, me->adt);
+ IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ lib_link_animdata(fd, &me->id, me->adt);
/* this check added for python created meshes */
if (me->mat) {
@@ -4304,9 +4349,10 @@ static void lib_link_mesh(FileData *fd, Main *main)
lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
- if (me->mr && me->mr->levels.first)
+ if (me->mr && me->mr->levels.first) {
lib_link_customdata_mtface(fd, me, &me->mr->fdata,
- ((MultiresLevel*)me->mr->levels.first)->totface);
+ ((MultiresLevel*)me->mr->levels.first)->totface);
+ }
}
}
@@ -4314,7 +4360,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
convert_tface_mt(fd, main);
for (me = main->mesh.first; me; me = me->id.next) {
- if (me->id.flag & LIB_NEED_LINK) {
+ if (me->id.tag & LIB_TAG_NEED_LINK) {
/*check if we need to convert mfaces to mpolys*/
if (me->totface && !me->totpoly) {
/* temporarily switch main so that reading from
@@ -4343,7 +4389,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
BKE_mesh_tessface_clear(me);
#endif
- me->id.flag -= LIB_NEED_LINK;
+ me->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -4560,13 +4606,13 @@ static void lib_link_latt(FileData *fd, Main *main)
Lattice *lt;
for (lt = main->latt.first; lt; lt = lt->id.next) {
- if (lt->id.flag & LIB_NEED_LINK) {
- if (lt->adt) lib_link_animdata(fd, &lt->id, lt->adt);
+ if (lt->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &lt->id, lt->adt);
lt->ipo = newlibadr_us(fd, lt->id.lib, lt->ipo); // XXX deprecated - old animation system
lt->key = newlibadr_us(fd, lt->id.lib, lt->key);
- lt->id.flag -= LIB_NEED_LINK;
+ lt->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -4587,15 +4633,15 @@ static void direct_link_latt(FileData *fd, Lattice *lt)
/* ************ READ OBJECT ***************** */
-static void lib_link_modifiers__linkModifiers(void *userData, Object *ob,
- ID **idpoin)
+static void lib_link_modifiers__linkModifiers(
+ void *userData, Object *ob, ID **idpoin, int cd_flag)
{
FileData *fd = userData;
*idpoin = newlibadr(fd, ob->id.lib, *idpoin);
- /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */
- if (*idpoin && GS((*idpoin)->name)!=ID_OB)
- (*idpoin)->us++;
+ if (*idpoin != NULL && (cd_flag & IDWALK_USER) != 0) {
+ id_us_plus_no_lib(*idpoin);
+ }
}
static void lib_link_modifiers(FileData *fd, Object *ob)
{
@@ -4613,9 +4659,9 @@ static void lib_link_object(FileData *fd, Main *main)
int warn=0, a;
for (ob = main->object.first; ob; ob = ob->id.next) {
- if (ob->id.flag & LIB_NEED_LINK) {
- if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- if (ob->adt) lib_link_animdata(fd, &ob->id, ob->adt);
+ if (ob->id.tag & LIB_TAG_NEED_LINK) {
+ IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ lib_link_animdata(fd, &ob->id, ob->adt);
// XXX deprecated - old animation system <<<
ob->ipo = newlibadr_us(fd, ob->id.lib, ob->ipo);
@@ -4690,7 +4736,7 @@ static void lib_link_object(FileData *fd, Main *main)
ob->gpd = newlibadr_us(fd, ob->id.lib, ob->gpd);
ob->duplilist = NULL;
- ob->id.flag -= LIB_NEED_LINK;
+ ob->id.tag &= ~LIB_TAG_NEED_LINK;
/* if id.us==0 a new base will be created later on */
/* WARNING! Also check expand_object(), should reflect the stuff below. */
@@ -5110,7 +5156,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
else if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
- psmd->dm= NULL;
+ psmd->dm_final = NULL;
+ psmd->dm_deformed = NULL;
psmd->psys= newdataadr(fd, psmd->psys);
psmd->flag &= ~eParticleSystemFlag_psys_updated;
psmd->flag |= eParticleSystemFlag_file_loaded;
@@ -5209,7 +5256,7 @@ static void direct_link_object(FileData *fd, Object *ob)
* Also when linking in a file don't allow edit and pose modes.
* See [#34776, #42780] for more information.
*/
- if (fd->memfile || (ob->id.flag & (LIB_EXTERN | LIB_INDIRECT))) {
+ if (fd->memfile || (ob->id.tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT))) {
ob->mode &= ~(OB_MODE_EDIT | OB_MODE_PARTICLE_EDIT);
if (!fd->memfile) {
ob->mode &= ~OB_MODE_POSE;
@@ -5479,7 +5526,7 @@ static bool scene_validate_setscene__liblink(Scene *sce, const int totscene)
if (sce->set == NULL) return 1;
for (a = 0, sce_iter = sce; sce_iter->set; sce_iter = sce_iter->set, a++) {
- if (sce_iter->id.flag & LIB_NEED_LINK) {
+ if (sce_iter->id.tag & LIB_TAG_NEED_LINK) {
return 1;
}
@@ -5509,11 +5556,11 @@ static void lib_link_scene(FileData *fd, Main *main)
#endif
for (sce = main->scene.first; sce; sce = sce->id.next) {
- if (sce->id.flag & LIB_NEED_LINK) {
+ if (sce->id.tag & LIB_TAG_NEED_LINK) {
/* Link ID Properties -- and copy this comment EXACTLY for easy finding
* of library blocks that implement this.*/
- if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- if (sce->adt) lib_link_animdata(fd, &sce->id, sce->adt);
+ IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ lib_link_animdata(fd, &sce->id, sce->adt);
lib_link_keyingsets(fd, &sce->id, &sce->keyingsets);
@@ -5530,7 +5577,7 @@ static void lib_link_scene(FileData *fd, Main *main)
if (sce->toolsettings->sculpt)
sce->toolsettings->sculpt->gravity_object =
- newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object);
+ newlibadr(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object);
if (sce->toolsettings->imapaint.stencil)
sce->toolsettings->imapaint.stencil =
@@ -5555,7 +5602,7 @@ static void lib_link_scene(FileData *fd, Main *main)
base->object = newlibadr_us(fd, sce->id.lib, base->object);
if (base->object == NULL) {
- blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: object lost from scene: '%s'"),
+ blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: object lost from scene: '%s'"),
sce->id.name + 2);
BLI_remlink(&sce->base, base);
if (base == sce->basact) sce->basact = NULL;
@@ -5574,16 +5621,10 @@ static void lib_link_scene(FileData *fd, Main *main)
}
}
if (seq->clip) {
- seq->clip = newlibadr(fd, sce->id.lib, seq->clip);
- if (seq->clip) {
- seq->clip->id.us++;
- }
+ seq->clip = newlibadr_us(fd, sce->id.lib, seq->clip);
}
if (seq->mask) {
- seq->mask = newlibadr(fd, sce->id.lib, seq->mask);
- if (seq->mask) {
- seq->mask->id.us++;
- }
+ seq->mask = newlibadr_us(fd, sce->id.lib, seq->mask);
}
if (seq->scene_camera) {
seq->scene_camera = newlibadr(fd, sce->id.lib, seq->scene_camera);
@@ -5597,7 +5638,7 @@ static void lib_link_scene(FileData *fd, Main *main)
seq->sound = newlibadr(fd, sce->id.lib, seq->sound);
}
if (seq->sound) {
- seq->sound->id.us++;
+ id_us_plus_no_lib((ID *)seq->sound);
seq->scene_sound = BKE_sound_add_scene_sound_defaults(sce, seq);
}
}
@@ -5664,10 +5705,10 @@ static void lib_link_scene(FileData *fd, Main *main)
}
else {
/* postpone un-setting the flag until we've checked the set-scene */
- sce->id.flag &= ~LIB_NEED_LINK;
+ sce->id.tag &= ~LIB_TAG_NEED_LINK;
}
#else
- sce->id.flag &= ~LIB_NEED_LINK;
+ sce->id.tag &= ~LIB_TAG_NEED_LINK;
#endif
}
@@ -5679,8 +5720,8 @@ static void lib_link_scene(FileData *fd, Main *main)
#ifdef USE_SETSCENE_CHECK
if (need_check_set) {
for (sce = main->scene.first; sce; sce = sce->id.next) {
- if (sce->id.flag & LIB_NEED_LINK) {
- sce->id.flag &= ~LIB_NEED_LINK;
+ if (sce->id.tag & LIB_TAG_NEED_LINK) {
+ sce->id.tag &= ~LIB_TAG_NEED_LINK;
if (!scene_validate_setscene__liblink(sce, totscene)) {
printf("Found cyclic background scene when linking %s\n", sce->id.name + 2);
}
@@ -5777,7 +5818,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
BKE_sound_create_scene(sce);
/* set users to one by default, not in lib-link, this will increase it for compo nodes */
- sce->id.us = 1;
+ id_us_ensure_real(&sce->id);
link_list(fd, &(sce->base));
@@ -5802,6 +5843,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->particle.paintcursor = NULL;
sce->toolsettings->particle.scene = NULL;
sce->toolsettings->particle.object = NULL;
+ sce->toolsettings->gp_sculpt.paintcursor = NULL;
/* in rare cases this is needed, see [#33806] */
if (sce->toolsettings->vpaint) {
@@ -5988,6 +6030,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
sce->preview = direct_link_preview_image(fd, sce->preview);
+
+ direct_link_curvemapping(fd, &sce->r.mblur_shutter_curve);
}
/* ************ READ WM ***************** */
@@ -5996,7 +6040,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
{
wmWindow *win;
- wm->id.us = 1;
+ id_us_ensure_real(&wm->id);
link_list(fd, &wm->windows);
for (win = wm->windows.first; win; win = win->next) {
@@ -6019,9 +6063,12 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
win->drawfail = 0;
win->active = 0;
- win->cursor = 0;
- win->lastcursor = 0;
- win->modalcursor = 0;
+ win->cursor = 0;
+ win->lastcursor = 0;
+ win->modalcursor = 0;
+ win->grabcursor = 0;
+ win->addmousemove = true;
+ win->multisamples = 0;
win->stereo3d_format = newdataadr(fd, win->stereo3d_format);
/* multiview always fallback to anaglyph at file opening
@@ -6058,11 +6105,11 @@ static void lib_link_windowmanager(FileData *fd, Main *main)
wmWindow *win;
for (wm = main->wm.first; wm; wm = wm->id.next) {
- if (wm->id.flag & LIB_NEED_LINK) {
+ if (wm->id.tag & LIB_TAG_NEED_LINK) {
for (win = wm->windows.first; win; win = win->next)
win->screen = newlibadr(fd, NULL, win->screen);
- wm->id.flag -= LIB_NEED_LINK;
+ wm->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -6075,11 +6122,10 @@ static void lib_link_gpencil(FileData *fd, Main *main)
bGPdata *gpd;
for (gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
- if (gpd->id.flag & LIB_NEED_LINK) {
- gpd->id.flag -= LIB_NEED_LINK;
+ if (gpd->id.tag & LIB_TAG_NEED_LINK) {
+ gpd->id.tag &= ~LIB_TAG_NEED_LINK;
- if (gpd->adt)
- lib_link_animdata(fd, &gpd->id, gpd->adt);
+ lib_link_animdata(fd, &gpd->id, gpd->adt);
}
}
}
@@ -6128,8 +6174,8 @@ static void lib_link_screen(FileData *fd, Main *main)
ScrArea *sa;
for (sc = main->screen.first; sc; sc = sc->id.next) {
- if (sc->id.flag & LIB_NEED_LINK) {
- sc->id.us = 1;
+ if (sc->id.tag & LIB_TAG_NEED_LINK) {
+ id_us_ensure_real(&sc->id);
sc->scene = newlibadr(fd, sc->id.lib, sc->scene);
/* this should not happen, but apparently it does somehow. Until we figure out the cause,
@@ -6318,7 +6364,7 @@ static void lib_link_screen(FileData *fd, Main *main)
}
}
}
- sc->id.flag -= LIB_NEED_LINK;
+ sc->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -6326,20 +6372,14 @@ static void lib_link_screen(FileData *fd, Main *main)
/* how to handle user count on pointer restore */
typedef enum ePointerUserMode {
USER_IGNORE = 0, /* ignore user count */
- USER_ONE = 1, /* ensure at least one user (fake also counts) */
- USER_REAL = 2, /* ensure at least one real user (fake user ignored) */
+ USER_REAL = 1, /* ensure at least one real user (fake user ignored) */
} ePointerUserMode;
static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
{
if (STREQ(newid->name + 2, id->name + 2)) {
if (newid->lib == id->lib) {
- if (user == USER_ONE) {
- if (newid->us == 0) {
- newid->us++;
- }
- }
- else if (user == USER_REAL) {
+ if (user == USER_REAL) {
id_us_ensure_real(newid);
}
return true;
@@ -6353,7 +6393,6 @@ static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
*
* user
* - USER_IGNORE: no usercount change
- * - USER_ONE: ensure a user
* - USER_REAL: ensure a real user (even if a fake one is set)
*/
static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user)
@@ -6379,7 +6418,7 @@ static void lib_link_seq_clipboard_pt_restore(ID *id, Main *newmain)
if (id) {
/* clipboard must ensure this */
BLI_assert(id->newid != NULL);
- id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_ONE);
+ id->newid = restore_pointer_by_name(newmain, (ID *)id->newid, USER_REAL);
}
}
static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
@@ -6413,7 +6452,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* first windowmanager */
for (wm = newmain->wm.first; wm; wm = wm->id.next) {
for (win= wm->windows.first; win; win= win->next) {
- win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_ONE);
+ win->screen = restore_pointer_by_name(newmain, (ID *)win->screen, USER_REAL);
if (win->screen == NULL)
win->screen = curscreen;
@@ -6426,7 +6465,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
for (sc = newmain->screen.first; sc; sc = sc->id.next) {
Scene *oldscene = sc->scene;
- sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_ONE);
+ sc->scene= restore_pointer_by_name(newmain, (ID *)sc->scene, USER_REAL);
if (sc->scene == NULL)
sc->scene = curscene;
@@ -6445,10 +6484,10 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
if (v3d->scenelock)
v3d->camera = NULL; /* always get from scene */
else
- v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_ONE);
+ v3d->camera = restore_pointer_by_name(newmain, (ID *)v3d->camera, USER_REAL);
if (v3d->camera == NULL)
v3d->camera = sc->scene->camera;
- v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_ONE);
+ v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_REAL);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
@@ -6498,7 +6537,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bDopeSheet *ads = sipo->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_ONE);
+ ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
@@ -6528,8 +6567,8 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)sl;
- saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_ONE);
- saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_ONE);
+ saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, USER_REAL);
+ saction->ads.source = restore_pointer_by_name(newmain, (ID *)saction->ads.source, USER_REAL);
if (saction->ads.filter_grp)
saction->ads.filter_grp = restore_pointer_by_name(newmain, (ID *)saction->ads.filter_grp, USER_IGNORE);
@@ -6558,7 +6597,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_ONE);
+ sima->gpd = restore_pointer_by_name(newmain, (ID *)sima->gpd, USER_REAL);
sima->mask_info.mask = restore_pointer_by_name(newmain, (ID *)sima->mask_info.mask, USER_REAL);
}
else if (sl->spacetype == SPACE_SEQ) {
@@ -6567,14 +6606,14 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
* so assume that here we're doing for undo only...
*/
- sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_ONE);
+ sseq->gpd = restore_pointer_by_name(newmain, (ID *)sseq->gpd, USER_REAL);
}
else if (sl->spacetype == SPACE_NLA) {
SpaceNla *snla = (SpaceNla *)sl;
bDopeSheet *ads = snla->ads;
if (ads) {
- ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_ONE);
+ ads->source = restore_pointer_by_name(newmain, (ID *)ads->source, USER_REAL);
if (ads->filter_grp)
ads->filter_grp = restore_pointer_by_name(newmain, (ID *)ads->filter_grp, USER_IGNORE);
@@ -6583,13 +6622,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_TEXT) {
SpaceText *st = (SpaceText *)sl;
- st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_ONE);
+ st->text = restore_pointer_by_name(newmain, (ID *)st->text, USER_REAL);
if (st->text == NULL) st->text = newmain->text.first;
}
else if (sl->spacetype == SPACE_SCRIPT) {
SpaceScript *scpt = (SpaceScript *)sl;
- scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_ONE);
+ scpt->script = restore_pointer_by_name(newmain, (ID *)scpt->script, USER_REAL);
/*sc->script = NULL; - 2.45 set to null, better re-run the script */
if (scpt->script) {
@@ -6627,7 +6666,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
bNodeTree *ntree;
/* node tree can be stored locally in id too, link this first */
- snode->id = restore_pointer_by_name(newmain, snode->id, USER_ONE);
+ snode->id = restore_pointer_by_name(newmain, snode->id, USER_REAL);
snode->from = restore_pointer_by_name(newmain, snode->from, USER_IGNORE);
ntree = nodetree_from_id(snode->id);
@@ -6676,7 +6715,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
else if (sl->spacetype == SPACE_LOGIC) {
SpaceLogic *slogic = (SpaceLogic *)sl;
- slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_ONE);
+ slogic->gpd = restore_pointer_by_name(newmain, (ID *)slogic->gpd, USER_REAL);
}
}
}
@@ -7129,7 +7168,7 @@ static void lib_link_library(FileData *UNUSED(fd), Main *main)
{
Library *lib;
for (lib = main->library.first; lib; lib = lib->id.next) {
- lib->id.us = 1;
+ id_us_ensure_real(&lib->id);
}
}
@@ -7169,15 +7208,11 @@ static void lib_link_speaker(FileData *fd, Main *main)
Speaker *spk;
for (spk = main->speaker.first; spk; spk = spk->id.next) {
- if (spk->id.flag & LIB_NEED_LINK) {
- if (spk->adt) lib_link_animdata(fd, &spk->id, spk->adt);
-
- spk->sound= newlibadr(fd, spk->id.lib, spk->sound);
- if (spk->sound) {
- spk->sound->id.us++;
- }
+ if (spk->id.tag & LIB_TAG_NEED_LINK) {
+ lib_link_animdata(fd, &spk->id, spk->adt);
- spk->id.flag -= LIB_NEED_LINK;
+ spk->sound = newlibadr_us(fd, spk->id.lib, spk->sound);
+ spk->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7229,8 +7264,8 @@ static void lib_link_sound(FileData *fd, Main *main)
bSound *sound;
for (sound = main->sound.first; sound; sound = sound->id.next) {
- if (sound->id.flag & LIB_NEED_LINK) {
- sound->id.flag -= LIB_NEED_LINK;
+ if (sound->id.tag & LIB_TAG_NEED_LINK) {
+ sound->id.tag &= ~LIB_TAG_NEED_LINK;
sound->ipo = newlibadr_us(fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
BKE_sound_load(main, sound);
@@ -7250,25 +7285,26 @@ static void lib_link_group(FileData *fd, Main *main)
{
Group *group;
GroupObject *go;
- int add_us;
+ bool add_us;
for (group = main->group.first; group; group = group->id.next) {
- if (group->id.flag & LIB_NEED_LINK) {
- group->id.flag -= LIB_NEED_LINK;
+ if (group->id.tag & LIB_TAG_NEED_LINK) {
+ group->id.tag &= ~LIB_TAG_NEED_LINK;
- add_us = 0;
+ add_us = false;
for (go = group->gobject.first; go; go = go->next) {
go->ob= newlibadr(fd, group->id.lib, go->ob);
if (go->ob) {
go->ob->flag |= OB_FROMGROUP;
/* if group has an object, it increments user... */
- add_us = 1;
- if (go->ob->id.us == 0)
- go->ob->id.us = 1;
+ add_us = true;
+ id_us_ensure_real(&go->ob->id);
}
}
- if (add_us) group->id.us++;
+ if (add_us) {
+ id_us_ensure_real(&group->id);
+ }
BKE_group_object_unlink(group, NULL, NULL, NULL); /* removes NULL entries */
}
}
@@ -7377,12 +7413,11 @@ static void lib_link_movieclip(FileData *fd, Main *main)
MovieClip *clip;
for (clip = main->movieclip.first; clip; clip = clip->id.next) {
- if (clip->id.flag & LIB_NEED_LINK) {
+ if (clip->id.tag & LIB_TAG_NEED_LINK) {
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object;
- if (clip->adt)
- lib_link_animdata(fd, &clip->id, clip->adt);
+ lib_link_animdata(fd, &clip->id, clip->adt);
clip->gpd = newlibadr_us(fd, clip->id.lib, clip->gpd);
@@ -7393,7 +7428,7 @@ static void lib_link_movieclip(FileData *fd, Main *main)
lib_link_movieTracks(fd, clip, &object->tracks);
}
- clip->id.flag -= LIB_NEED_LINK;
+ clip->id.tag &= ~LIB_TAG_NEED_LINK;
}
}
}
@@ -7457,11 +7492,10 @@ static void lib_link_mask(FileData *fd, Main *main)
mask = main->mask.first;
while (mask) {
- if (mask->id.flag & LIB_NEED_LINK) {
+ if (mask->id.tag & LIB_TAG_NEED_LINK) {
MaskLayer *masklay;
- if (mask->adt)
- lib_link_animdata(fd, &mask->id, mask->adt);
+ lib_link_animdata(fd, &mask->id, mask->adt);
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
@@ -7482,7 +7516,7 @@ static void lib_link_mask(FileData *fd, Main *main)
}
}
- mask->id.flag -= LIB_NEED_LINK;
+ mask->id.tag &= ~LIB_TAG_NEED_LINK;
}
mask = mask->id.next;
}
@@ -7499,13 +7533,11 @@ static void lib_link_linestyle(FileData *fd, Main *main)
linestyle = main->linestyle.first;
while (linestyle) {
- if (linestyle->id.flag & LIB_NEED_LINK) {
- linestyle->id.flag -= LIB_NEED_LINK;
+ if (linestyle->id.tag & LIB_TAG_NEED_LINK) {
+ linestyle->id.tag &= ~LIB_TAG_NEED_LINK;
- if (linestyle->id.properties)
- IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
- if (linestyle->adt)
- lib_link_animdata(fd, &linestyle->id, linestyle->adt);
+ IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ lib_link_animdata(fd, &linestyle->id, linestyle->adt);
for (m = linestyle->color_modifiers.first; m; m = m->next) {
switch (m->type) {
case LS_MODIFIER_DISTANCE_FROM_OBJECT:
@@ -7829,40 +7861,94 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **r_id)
{
- /* this routine reads a libblock and its direct data. Use link functions
- * to connect it all
+ /* this routine reads a libblock and its direct data. Use link functions to connect it all
*/
ID *id;
ListBase *lb;
const char *allocname;
bool wrong_id = false;
-
+
+ /* In undo case, most libs and linked data should be kept as is from previous state (see BLO_read_from_memfile).
+ * However, some needed by the snapshot being read may have been removed in previous one, and would go missing.
+ * This leads e.g. to desappearing objects in some undo/redo case, see T34446.
+ * That means we have to carefully check whether current lib or libdata already exits in old main, if it does
+ * we merely copy it over into new main area, otherwise we have to do a full read of that bhead... */
+ if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) {
+ const char *idname = bhead_id_name(fd, bhead);
+
+ /* printf("Checking %s...\n", idname); */
+
+ if (bhead->code == ID_LI) {
+ Main *libmain = fd->old_mainlist->first;
+ /* Skip oldmain itself... */
+ for (libmain = libmain->next; libmain; libmain = libmain->next) {
+ /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */
+ if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) {
+ Main *oldmain = fd->old_mainlist->first;
+ /* printf("FOUND!\n"); */
+ /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later
+ * a missing ID_ID, we need to get the correct lib it is linked to!
+ * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */
+ BLI_remlink(fd->old_mainlist, libmain);
+ BLI_remlink_safe(&oldmain->library, libmain->curlib);
+ BLI_addtail(fd->mainlist, libmain);
+ BLI_addtail(&main->library, libmain->curlib);
+
+ if (r_id) {
+ *r_id = NULL; /* Just in case... */
+ }
+ return blo_nextbhead(fd, bhead);
+ }
+ /* printf("nothing...\n"); */
+ }
+ }
+ else {
+ /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */
+ if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) {
+ /* printf("FOUND!\n"); */
+ /* Even though we found our linked ID, there is no guarantee its address is still the same... */
+ if (id != bhead->old) {
+ oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name));
+ }
+
+ /* No need to do anything else for ID_ID, it's assumed already present in its lib's main... */
+ if (r_id) {
+ *r_id = NULL; /* Just in case... */
+ }
+ return blo_nextbhead(fd, bhead);
+ }
+ /* printf("nothing...\n"); */
+ }
+ }
+
/* read libblock */
id = read_struct(fd, bhead, "lib block");
+
+ if (id) {
+ const short idcode = (bhead->code == ID_ID) ? GS(id->name) : bhead->code;
+ /* do after read_struct, for dna reconstruct */
+ lb = which_libbase(main, idcode);
+ if (lb) {
+ oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */
+ BLI_addtail(lb, id);
+ }
+ else {
+ /* unknown ID type */
+ printf("%s: unknown id code '%c%c'\n", __func__, (idcode & 0xff), (idcode >> 8));
+ MEM_freeN(id);
+ id = NULL;
+ }
+ }
+
if (r_id)
*r_id = id;
if (!id)
return blo_nextbhead(fd, bhead);
- oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */
-
- /* do after read_struct, for dna reconstruct */
- if (bhead->code == ID_ID) {
- lb = which_libbase(main, GS(id->name));
- }
- else {
- lb = which_libbase(main, bhead->code);
- }
-
- BLI_addtail(lb, id);
-
- /* clear first 8 bits */
- id->flag = (id->flag & 0xFF00) | flag | LIB_NEED_LINK;
+ id->tag = flag | LIB_TAG_NEED_LINK;
id->lib = main->curlib;
- if (id->flag & LIB_FAKEUSER) id->us= 1;
- else id->us = 0;
+ id->us = ID_FAKE_USERS(id);
id->icon_id = 0;
- id->flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA|LIB_DOIT);
/* this case cannot be direct_linked: it's just the ID part */
if (bhead->code == ID_ID) {
@@ -7960,9 +8046,6 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_PA:
direct_link_particlesettings(fd, (ParticleSettings*)id);
break;
- case ID_SCRIPT:
- direct_link_script(fd, (Script*)id);
- break;
case ID_GD:
direct_link_gpencil(fd, (bGPdata *)id);
break;
@@ -8307,26 +8390,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = NULL;
break;
- case ID_LI:
- /* skip library datablocks in undo, this works together with
- * BLO_read_from_memfile, where the old main->library is restored
- * overwriting the libraries from the memory file. previously
- * it did not save ID_LI/ID_ID blocks in this case, but they are
- * needed to make quit.blend recover them correctly. */
- if (fd->memfile)
- bhead = blo_nextbhead(fd, bhead);
- else
- bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
- break;
case ID_ID:
- /* same as above */
- if (fd->memfile)
- bhead = blo_nextbhead(fd, bhead);
- else
- /* always adds to the most recently loaded
- * ID_LI block, see direct_link_library.
- * this is part of the file format definition. */
- bhead = read_libblock(fd, mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
+ /* Always adds to the most recently loaded ID_LI block, see direct_link_library.
+ * This is part of the file format definition. */
+ bhead = read_libblock(fd, mainlist.last, bhead, LIB_TAG_READ | LIB_TAG_EXTERN, NULL);
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
@@ -8334,7 +8401,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead->code = ID_SCR;
/* deliberate pass on to default */
default:
- bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_TAG_LOCAL, NULL);
}
}
@@ -8480,11 +8547,6 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname)
#endif
}
-const char *bhead_id_name(const FileData *fd, const BHead *bhead)
-{
- return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs);
-}
-
static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
{
const char *idname= bhead_id_name(fd, bhead);
@@ -8511,7 +8573,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
if (ptr->curlib == NULL) {
const char *idname= bhead_id_name(fd, bhead);
- blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: Data refers to main .blend file: '%s' from %s"),
+ blo_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB: Data refers to main .blend file: '%s' from %s"),
idname, mainvar->curlib->filepath);
return;
}
@@ -8519,7 +8581,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
id = is_yet_read(fd, ptr, bhead);
if (id == NULL) {
- read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL);
+ read_libblock(fd, ptr, bhead, LIB_TAG_READ | LIB_TAG_INDIRECT, NULL);
// commented because this can print way too much
// if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
@@ -8537,10 +8599,10 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
/* Update: the issue is that in file reading, the oldnewmap is OK, but for existing data, it has to be
* inserted in the map to be found! */
- /* Update: previously it was checking for id->flag & LIB_PRE_EXISTING, however that does not affect file
- * reading. For file reading we may need to insert it into the libmap as well, because you might have
- * two files indirectly linking the same datablock, and in that case we need this in the libmap for the
- * fd of both those files.
+ /* Update: previously it was checking for id->tag & LIB_TAG_PRE_EXISTING, however that
+ * does not affect file reading. For file reading we may need to insert it into the libmap as well,
+ * because you might have two files indirectly linking the same datablock, and in that case
+ * we need this in the libmap for the fd of both those files.
*
* The crash that this check avoided earlier was because bhead->code wasn't properly passed in, making
* change_idid_adr not detect the mapping was for an ID_ID datablock. */
@@ -8557,7 +8619,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
else {
id = is_yet_read(fd, mainvar, bhead);
if (id == NULL) {
- read_libblock(fd, mainvar, bhead, LIB_TESTIND, NULL);
+ read_libblock(fd, mainvar, bhead, LIB_TAG_TESTIND, NULL);
}
else {
/* this is actually only needed on UI call? when ID was already read before, and another append
@@ -8570,7 +8632,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
}
}
-static void (*expand_doit)(void *, Main *, void *);
+static BLOExpandDoitCallback expand_doit;
// XXX deprecated - old animation system
static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo)
@@ -9007,8 +9069,8 @@ static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
#endif
}
-static void expand_object_expandModifiers(void *userData, Object *UNUSED(ob),
- ID **idpoin)
+static void expand_object_expandModifiers(
+ void *userData, Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag))
{
struct { FileData *fd; Main *mainvar; } *data= userData;
@@ -9345,11 +9407,23 @@ static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd)
expand_animdata(fd, mainvar, gpd->adt);
}
-void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
+/**
+ * Set the callback func used over all ID data found by \a BLO_expand_main func.
+ *
+ * \param expand_doit_func Called for each ID block it finds.
+ */
+void BLO_main_expander(BLOExpandDoitCallback expand_doit_func)
{
expand_doit = expand_doit_func;
}
+/**
+ * Loop over all ID data in Main to mark relations.
+ * Set (id->tag & LIB_TAG_NEED_EXPAND) to mark expanding. Flags get cleared after expanding.
+ *
+ * \param fdhandle usually filedata, or own handle.
+ * \param mainvar the Main database to expand.
+ */
void BLO_expand_main(void *fdhandle, Main *mainvar)
{
ListBase *lbarray[MAX_LIBARRAY];
@@ -9365,7 +9439,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
while (a--) {
id = lbarray[a]->first;
while (id) {
- if (id->flag & LIB_NEED_EXPAND) {
+ if (id->tag & LIB_TAG_NEED_EXPAND) {
switch (GS(id->name)) {
case ID_OB:
expand_object(fd, mainvar, (Object *)id);
@@ -9445,7 +9519,7 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
}
do_it = true;
- id->flag -= LIB_NEED_EXPAND;
+ id->tag &= ~LIB_TAG_NEED_EXPAND;
}
id = id->next;
@@ -9461,101 +9535,86 @@ static bool object_in_any_scene(Main *mainvar, Object *ob)
{
Scene *sce;
- for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
- if (BKE_scene_base_find(sce, ob))
- return 1;
+ for (sce = mainvar->scene.first; sce; sce = sce->id.next) {
+ if (BKE_scene_base_find(sce, ob)) {
+ return true;
+ }
}
- return 0;
+ return false;
}
-static void give_base_to_objects(Main *mainvar, Scene *sce, Library *lib, const short idcode, const bool is_link, const short active_lay)
+static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Library *lib, const short flag)
{
Object *ob;
Base *base;
- const bool is_group_append = (is_link == false && idcode == ID_GR);
+ const unsigned int active_lay = (flag & FILE_ACTIVELAY) ? BKE_screen_view3d_layer_active(v3d, scene) : 0;
+ const bool is_link = (flag & FILE_LINK) != 0;
- /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */
+ BLI_assert(scene);
+
+ /* give all objects which are LIB_TAG_INDIRECT a base, or for a group when *lib has been set */
for (ob = mainvar->object.first; ob; ob = ob->id.next) {
- if (ob->id.flag & LIB_INDIRECT) {
- /* IF below is quite confusing!
- * if we are appending, but this object wasnt just added along with a group,
- * then this is already used indirectly in the scene somewhere else and we didnt just append it.
- *
- * (ob->id.flag & LIB_PRE_EXISTING)==0 means that this is a newly appended object - Campbell */
- if (is_group_append==0 || (ob->id.flag & LIB_PRE_EXISTING)==0) {
- bool do_it = false;
-
- if (ob->id.us == 0) {
- do_it = true;
- }
- else if (idcode==ID_GR) {
- if ((is_link == false) && (ob->id.lib == lib)) {
- if ((ob->flag & OB_FROMGROUP) && object_in_any_scene(mainvar, ob)==0) {
- do_it = true;
- }
- }
- }
- else {
- /* when appending, make sure any indirectly loaded objects
- * get a base else they cant be accessed at all [#27437] */
- if ((is_link == false) && (ob->id.lib == lib)) {
- /* we may be appending from a scene where we already
- * have a linked object which is not in any scene [#27616] */
- if ((ob->id.flag & LIB_PRE_EXISTING)==0) {
- if (object_in_any_scene(mainvar, ob)==0) {
- do_it = true;
- }
- }
- }
- }
-
- if (do_it) {
- base = MEM_callocN(sizeof(Base), "add_ext_base");
- BLI_addtail(&sce->base, base);
-
- if (active_lay) ob->lay = sce->lay;
-
- base->lay = ob->lay;
- base->object = ob;
- base->flag = ob->flag;
+ if ((ob->id.tag & LIB_TAG_INDIRECT) && (ob->id.tag & LIB_TAG_PRE_EXISTING) == 0) {
+ bool do_it = false;
- CLAMP_MIN(ob->id.us, 0);
- ob->id.us += 1;
-
- ob->id.flag -= LIB_INDIRECT;
- ob->id.flag |= LIB_EXTERN;
+ if (ob->id.us == 0) {
+ do_it = true;
+ }
+ else if (!is_link && (ob->id.lib == lib) && (object_in_any_scene(mainvar, ob) == 0)) {
+ /* When appending, make sure any indirectly loaded objects get a base, else they cant be accessed at all
+ * (see T27437). */
+ do_it = true;
+ }
+
+ if (do_it) {
+ base = MEM_callocN(sizeof(Base), __func__);
+ BLI_addtail(&scene->base, base);
+
+ if (active_lay) {
+ ob->lay = active_lay;
}
+
+ base->lay = ob->lay;
+ base->object = ob;
+ base->flag = ob->flag;
+
+ CLAMP_MIN(ob->id.us, 0);
+ id_us_plus_no_lib((ID *)ob);
+
+ ob->id.tag &= ~LIB_TAG_INDIRECT;
+ ob->id.tag |= LIB_TAG_EXTERN;
}
}
}
}
-static void give_base_to_groups(Main *mainvar, Scene *scene)
+static void give_base_to_groups(
+ Main *mainvar, Scene *scene, View3D *v3d, Library *UNUSED(lib), const short UNUSED(flag))
{
Group *group;
-
+ Base *base;
+ Object *ob;
+ const unsigned int active_lay = BKE_screen_view3d_layer_active(v3d, scene);
+
/* give all objects which are tagged a base */
for (group = mainvar->group.first; group; group = group->id.next) {
- if (group->id.flag & LIB_DOIT) {
- Base *base;
- Object *ob;
-
+ if (group->id.tag & LIB_TAG_DOIT) {
/* any indirect group should not have been tagged */
- BLI_assert((group->id.flag & LIB_INDIRECT)==0);
-
+ BLI_assert((group->id.tag & LIB_TAG_INDIRECT) == 0);
+
/* BKE_object_add(...) messes with the selection */
ob = BKE_object_add_only_object(mainvar, OB_EMPTY, group->id.name + 2);
ob->type = OB_EMPTY;
- ob->lay = scene->lay;
-
+ ob->lay = active_lay;
+
/* assign the base */
base = BKE_scene_base_add(scene, ob);
base->flag |= SELECT;
- base->object->flag= base->flag;
+ base->object->flag = base->flag;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
scene->basact = base;
-
+
/* assign the group */
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
@@ -9564,18 +9623,39 @@ static void give_base_to_groups(Main *mainvar, Scene *scene)
}
}
+static ID *create_placeholder(Main *mainvar, const char *idname, const short flag)
+{
+ const short idcode = GS(idname);
+ ListBase *lb = which_libbase(mainvar, idcode);
+ ID *ph_id = BKE_libblock_alloc_notest(idcode);
+
+ memcpy(ph_id->name, idname, sizeof(ph_id->name));
+ BKE_libblock_init_empty(ph_id);
+ ph_id->lib = mainvar->curlib;
+ ph_id->tag = flag | LIB_TAG_MISSING;
+ ph_id->us = ID_FAKE_USERS(ph_id);
+ ph_id->icon_id = 0;
+
+ BLI_addtail(lb, ph_id);
+ id_sort_by_name(lb, ph_id);
+
+ return ph_id;
+}
+
/* returns true if the item was found
* but it may already have already been appended/linked */
-static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, const short idcode)
+static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name)
{
- BHead *bhead = find_bhead_from_code_name(fd, idcode, idname);
+ BHead *bhead = find_bhead_from_code_name(fd, idcode, name);
ID *id;
+ BLI_assert(BKE_idcode_is_linkable(idcode) && BKE_idcode_is_valid(idcode));
+
if (bhead) {
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
/* not read yet */
- read_libblock(fd, mainl, bhead, LIB_TESTEXT, &id);
+ read_libblock(fd, mainl, bhead, LIB_TAG_TESTEXT, &id);
if (id) {
/* sort by name in list */
@@ -9588,9 +9668,9 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons
if (G.debug)
printf("append: already linked\n");
oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code);
- if (id->flag & LIB_INDIRECT) {
- id->flag -= LIB_INDIRECT;
- id->flag |= LIB_EXTERN;
+ if (id->tag & LIB_TAG_INDIRECT) {
+ id->tag &= ~LIB_TAG_INDIRECT;
+ id->tag |= LIB_TAG_EXTERN;
}
}
}
@@ -9604,104 +9684,178 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons
return id;
}
-/* simple reader for copy/paste buffers */
-void BLO_library_append_all(Main *mainl, BlendHandle *bh)
+static void link_object_postprocess(ID *id, Scene *scene, View3D *v3d, const short flag)
+{
+ if (scene) {
+ Base *base;
+ Object *ob;
+
+ base = MEM_callocN(sizeof(Base), "app_nam_part");
+ BLI_addtail(&scene->base, base);
+
+ ob = (Object *)id;
+
+ /* link at active layer (view3d if available in context, else scene one */
+ if (flag & FILE_ACTIVELAY) {
+ ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
+ }
+
+ ob->mode = OB_MODE_OBJECT;
+ base->lay = ob->lay;
+ base->object = ob;
+ base->flag = ob->flag;
+ id_us_plus_no_lib((ID *)ob);
+
+ if (flag & FILE_AUTOSELECT) {
+ base->flag |= SELECT;
+ base->object->flag = base->flag;
+ /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
+ }
+ }
+}
+
+/**
+ * Simple reader for copy/paste buffers.
+ */
+void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh)
{
FileData *fd = (FileData *)(bh);
BHead *bhead;
- ID *id = NULL;
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
+ ID *id = NULL;
+
if (bhead->code == ENDB)
break;
- if (bhead->code == ID_OB)
- read_libblock(fd, mainl, bhead, LIB_TESTIND, &id);
-
+ if (ELEM(bhead->code, ID_OB, ID_GR)) {
+ read_libblock(fd, mainl, bhead, LIB_TAG_TESTIND, &id);
+ }
+
+
if (id) {
/* sort by name in list */
ListBase *lb = which_libbase(mainl, GS(id->name));
id_sort_by_name(lb, id);
+
+ if (bhead->code == ID_OB) {
+ /* Instead of instancing Base's directly, postpone until after groups are loaded
+ * otherwise the base's flag is set incorrectly when groups are used */
+ Object *ob = (Object *)id;
+ ob->mode = OB_MODE_OBJECT;
+ /* ensure give_base_to_objects runs on this object */
+ BLI_assert(id->us == 0);
+ }
}
}
}
-
-static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, const char *idname, const int idcode, const int flag)
+static ID *link_named_part_ex(
+ Main *mainl, FileData *fd, const short idcode, const char *name, const short flag,
+ Scene *scene, View3D *v3d)
{
- ID *id= append_named_part(mainl, fd, idname, idcode);
+ ID *id = link_named_part(mainl, fd, idcode, name);
if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */
- Scene *scene = CTX_data_scene(C); /* can be NULL */
- if (scene) {
- Base *base;
- Object *ob;
-
- base= MEM_callocN(sizeof(Base), "app_nam_part");
- BLI_addtail(&scene->base, base);
-
- ob = (Object *)id;
-
- /* link at active layer (view3d if available in context, else scene one */
- if ((flag & FILE_ACTIVELAY)) {
- View3D *v3d = CTX_wm_view3d(C);
- ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
- }
-
- ob->mode = OB_MODE_OBJECT;
- base->lay = ob->lay;
- base->object = ob;
- ob->id.us++;
-
- if (flag & FILE_AUTOSELECT) {
- base->flag |= SELECT;
- base->object->flag = base->flag;
- /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
- }
- }
+ link_object_postprocess(id, scene, v3d, flag);
}
else if (id && (GS(id->name) == ID_GR)) {
- /* tag as needing to be instanced */
+ /* tag as needing to be instantiated */
if (flag & FILE_GROUP_INSTANCE)
- id->flag |= LIB_DOIT;
+ id->tag |= LIB_TAG_DOIT;
}
-
+
return id;
}
-ID *BLO_library_append_named_part(Main *mainl, BlendHandle **bh, const char *idname, const int idcode)
+/**
+ * Link a named datablock from an external blend file.
+ *
+ * \param mainl The main database to link from (not the active one).
+ * \param bh The blender file handle.
+ * \param idcode The kind of datablock to link.
+ * \param name The name of the datablock (without the 2 char ID prefix).
+ * \return the linked ID when found.
+ */
+ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name)
{
FileData *fd = (FileData*)(*bh);
- return append_named_part(mainl, fd, idname, idcode);
+ return link_named_part(mainl, fd, idcode, name);
}
-ID *BLO_library_append_named_part_ex(const bContext *C, Main *mainl, BlendHandle **bh, const char *idname, const int idcode, const short flag)
+/**
+ * Link a named datablock from an external blend file.
+ * Optionally instantiate the object/group in the scene when the flags are set.
+ *
+ * \param mainl The main database to link from (not the active one).
+ * \param bh The blender file handle.
+ * \param idcode The kind of datablock to link.
+ * \param name The name of the datablock (without the 2 char ID prefix).
+ * \param flag Options for linking, used for instantiating.
+ * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
+ * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ * \return the linked ID when found.
+ */
+ID *BLO_library_link_named_part_ex(
+ Main *mainl, BlendHandle **bh,
+ const short idcode, const char *name, const short flag,
+ Scene *scene, View3D *v3d)
{
FileData *fd = (FileData*)(*bh);
- return append_named_part_ex(C, mainl, fd, idname, idcode, flag);
+ return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d);
}
-static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id)
+static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id)
{
- BHead *bhead = find_bhead_from_idname(fd, id->name);
+ BHead *bhead = NULL;
+ const bool is_valid = BKE_idcode_is_linkable(GS(id->name)) || ((id->tag & LIB_TAG_EXTERN) == 0);
+
+ if (fd) {
+ bhead = find_bhead_from_idname(fd, id->name);
+ }
+
+ id->tag &= ~LIB_TAG_READ;
+
+ if (!is_valid) {
+ blo_reportf_wrap(
+ reports, RPT_ERROR,
+ TIP_("LIB: %s: '%s' is directly linked from '%s' (parent '%s'), but is a non-linkable data type"),
+ BKE_idcode_to_name(GS(id->name)),
+ id->name + 2,
+ mainvar->curlib->filepath,
+ library_parent_filepath(mainvar->curlib));
+ }
if (bhead) {
- id->flag &= ~LIB_READ;
- id->flag |= LIB_NEED_EXPAND;
+ id->tag |= LIB_TAG_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
- read_libblock(fd, mainvar, bhead, id->flag, r_id);
+ read_libblock(fd, mainvar, bhead, id->tag, r_id);
+ }
+ else {
+ blo_reportf_wrap(
+ reports, RPT_WARNING,
+ TIP_("LIB: %s: '%s' missing from '%s', parent '%s'"),
+ BKE_idcode_to_name(GS(id->name)),
+ id->name + 2,
+ mainvar->curlib->filepath,
+ library_parent_filepath(mainvar->curlib));
+
+ /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */
+ if (r_id) {
+ *r_id = is_valid ? create_placeholder(mainvar, id->name, id->tag) : NULL;
+ }
}
}
/* common routine to append/link something from a library */
-static Main *library_append_begin(Main *mainvar, FileData **fd, const char *filepath)
+static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath)
{
Main *mainl;
(*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist");
- /* clear for group instancing tag */
- BKE_main_id_tag_listbase(&(mainvar->group), false);
+ /* clear for group instantiating tag */
+ BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false);
/* make mains */
blo_split_main((*fd)->mainlist, mainvar);
@@ -9719,77 +9873,72 @@ static Main *library_append_begin(Main *mainvar, FileData **fd, const char *file
return mainl;
}
-Main *BLO_library_append_begin(Main *mainvar, BlendHandle **bh, const char *filepath)
+/**
+ * Initialize the BlendHandle for linking library data.
+ *
+ * \param mainvar The current main database, e.g. G.main or CTX_data_main(C).
+ * \param bh A blender file handle as returned by \a BLO_blendhandle_from_file or \a BLO_blendhandle_from_memory.
+ * \param filepath Used for relative linking, copied to the \a lib->name.
+ * \return the library Main, to be passed to \a BLO_library_append_named_part as \a mainl.
+ */
+Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepath)
{
FileData *fd = (FileData*)(*bh);
- return library_append_begin(mainvar, &fd, filepath);
+ return library_link_begin(mainvar, &fd, filepath);
}
-
-/* Context == NULL signifies not to do any scene manipulation */
-static void library_append_end(const bContext *C, Main *mainl, FileData **fd, int idcode, short flag)
+/* scene and v3d may be NULL. */
+static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d)
{
Main *mainvar;
Library *curlib;
-
+
/* expander now is callback function */
BLO_main_expander(expand_doit_library);
-
+
/* make main consistent */
BLO_expand_main(*fd, mainl);
-
+
/* do this when expand found other libs */
read_libraries(*fd, (*fd)->mainlist);
-
+
curlib = mainl->curlib;
-
+
/* make the lib path relative if required */
if (flag & FILE_RELPATH) {
/* use the full path, this could have been read by other library even */
BLI_strncpy(curlib->name, curlib->filepath, sizeof(curlib->name));
-
+
/* uses current .blend file as reference */
BLI_path_rel(curlib->name, G.main->name);
}
-
+
blo_join_main((*fd)->mainlist);
mainvar = (*fd)->mainlist->first;
MEM_freeN((*fd)->mainlist);
mainl = NULL; /* blo_join_main free's mainl, cant use anymore */
-
+
lib_link_all(*fd, mainvar);
lib_verify_nodetree(mainvar, false);
fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */
-
- if (C) {
- Scene *scene = CTX_data_scene(C);
-
- /* give a base to loose objects. If group append, do it for objects too */
- if (scene) {
- const bool is_link = (flag & FILE_LINK) != 0;
- if (idcode == ID_SCE) {
- /* don't instance anything when linking in scenes, assume the scene its self instances the data */
- }
- else {
- give_base_to_objects(mainvar, scene, curlib, idcode, is_link, flag & FILE_ACTIVELAY);
-
- if (flag & FILE_GROUP_INSTANCE) {
- give_base_to_groups(mainvar, scene);
- }
- }
- }
- else {
- printf("library_append_end, scene is NULL (objects wont get bases)\n");
+
+ /* Give a base to loose objects. If group append, do it for objects too.
+ * Only directly linked objects & groups are instantiated by `BLO_library_link_named_part_ex()` & co,
+ * here we handle indirect ones and other possible edge-cases. */
+ if (scene) {
+ give_base_to_objects(mainvar, scene, v3d, curlib, flag);
+
+ if (flag & FILE_GROUP_INSTANCE) {
+ give_base_to_groups(mainvar, scene, v3d, curlib, flag);
}
}
+ else {
+ /* printf("library_append_end, scene is NULL (objects wont get bases)\n"); */
+ }
+
+ /* clear group instantiating tag */
+ BKE_main_id_tag_listbase(&(mainvar->group), LIB_TAG_DOIT, false);
- /* clear group instancing tag */
- BKE_main_id_tag_listbase(&(mainvar->group), false);
-
- /* has been removed... erm, why? s..ton) */
- /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */
- /* 20041208: put back. It only linked direct, not indirect objects (ton) */
-
/* patch to prevent switch_endian happens twice */
if ((*fd)->flags & FD_FLAGS_SWITCH_ENDIAN) {
blo_freefiledata(*fd);
@@ -9797,10 +9946,21 @@ static void library_append_end(const bContext *C, Main *mainl, FileData **fd, in
}
}
-void BLO_library_append_end(const bContext *C, struct Main *mainl, BlendHandle **bh, int idcode, short flag)
+/**
+ * Finalize linking from a given .blend file (library).
+ * Optionally instance the indirect object/group in the scene when the flags are set.
+ * \note Do not use \a bh after calling this function, it may frees it.
+ *
+ * \param mainl The main database to link from (not the active one).
+ * \param bh The blender file handle (WARNING! may be freed by this function!).
+ * \param flag Options for linking, used for instantiating.
+ * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done).
+ * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL).
+ */
+void BLO_library_link_end(Main *mainl, BlendHandle **bh, short flag, Scene *scene, View3D *v3d)
{
FileData *fd = (FileData*)(*bh);
- library_append_end(C, mainl, &fd, idcode, flag);
+ library_link_end(mainl, &fd, flag, scene, v3d);
*bh = (BlendHandle*)fd;
}
@@ -9821,7 +9981,7 @@ static int mainvar_count_libread_blocks(Main *mainvar)
ID *id;
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->flag & LIB_READ)
+ if (id->tag & LIB_TAG_READ)
tot++;
}
}
@@ -9847,7 +10007,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
while (mainptr) {
int tot = mainvar_count_libread_blocks(mainptr);
- // printf("found LIB_READ %s\n", mainptr->curlib->name);
+ // printf("found LIB_TAG_READ %s\n", mainptr->curlib->name);
if (tot) {
FileData *fd = mainptr->curlib->filedata;
@@ -9887,7 +10047,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
printf(" relative lib: %s\n", mainptr->curlib->name);
printf(" enter a new path:\n");
- if (scanf("%s", newlib_path) > 0) {
+ if (scanf("%1023s", newlib_path) > 0) { /* Warning, keep length in sync with FILE_MAX! */
BLI_strncpy(mainptr->curlib->name, newlib_path, sizeof(mainptr->curlib->name));
BLI_strncpy(mainptr->curlib->filepath, newlib_path, sizeof(mainptr->curlib->filepath));
BLI_cleanup_path(G.main->name, mainptr->curlib->filepath);
@@ -9928,6 +10088,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
else {
mainptr->curlib->filedata = NULL;
+ mainptr->curlib->id.tag |= LIB_TAG_MISSING;
}
if (fd == NULL) {
@@ -9937,37 +10098,31 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
if (fd) {
do_it = true;
- a = set_listbasepointers(mainptr, lbarray);
- while (a--) {
- ID *id = lbarray[a]->first;
-
- while (id) {
- ID *idn = id->next;
- if (id->flag & LIB_READ) {
- ID *realid = NULL;
- BLI_remlink(lbarray[a], id);
-
- append_id_part(fd, mainptr, id, &realid);
- if (!realid) {
- blo_reportf_wrap(
- fd->reports, RPT_WARNING,
- TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
- BKE_idcode_to_name(GS(id->name)),
- id->name + 2,
- mainptr->curlib->filepath,
- library_parent_filepath(mainptr->curlib));
- }
-
- change_idid_adr(mainlist, basefd, id, realid);
-
- MEM_freeN(id);
- }
- id = idn;
+ }
+ a = set_listbasepointers(mainptr, lbarray);
+ while (a--) {
+ ID *id = lbarray[a]->first;
+
+ while (id) {
+ ID *idn = id->next;
+ if (id->tag & LIB_TAG_READ) {
+ ID *realid = NULL;
+ BLI_remlink(lbarray[a], id);
+
+ link_id_part(basefd->reports, fd, mainptr, id, &realid);
+
+ /* realid shall never be NULL - unless some source file/lib is broken
+ * (known case: some directly linked shapekey from a missing lib...). */
+ /* BLI_assert(realid != NULL); */
+
+ change_idid_adr(mainlist, basefd, id, realid);
+
+ MEM_freeN(id);
}
+ id = idn;
}
-
- BLO_expand_main(fd, mainptr);
}
+ BLO_expand_main(fd, mainptr);
}
mainptr = mainptr->next;
@@ -9975,6 +10130,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
}
/* test if there are unread libblocks */
+ /* XXX This code block is kept for 2.77, until we are sure it never gets reached anymore. Can be removed later. */
for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) {
a = set_listbasepointers(mainptr, lbarray);
while (a--) {
@@ -9982,11 +10138,13 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
for (id = lbarray[a]->first; id; id = idn) {
idn = id->next;
- if (id->flag & LIB_READ) {
+ if (id->tag & LIB_TAG_READ) {
+ BLI_assert(0);
BLI_remlink(lbarray[a], id);
blo_reportf_wrap(
- basefd->reports, RPT_WARNING,
- TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"),
+ basefd->reports, RPT_ERROR,
+ TIP_("LIB: %s: '%s' unread lib block missing from '%s', parent '%s' - "
+ "Please file a bug report if you see this message"),
BKE_idcode_to_name(GS(id->name)),
id->name + 2,
mainptr->curlib->filepath,
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index ed22daef9ec..f5c19f5ee22 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -75,7 +75,7 @@ typedef struct FileData {
// general reading variables
struct SDNA *filesdna;
struct SDNA *memsdna;
- char *compflags;
+ char *compflags; /* array of eSDNA_StructCompare */
int fileversion;
int id_name_offs; /* used to retrieve ID names from (bhead+1) */
@@ -96,7 +96,8 @@ typedef struct FileData {
struct GHash *bhead_idname_hash;
ListBase *mainlist;
-
+ ListBase *old_mainlist; /* Used for undo. */
+
/* ick ick, used to return
* data through streamglue.
*/
@@ -109,13 +110,15 @@ typedef struct BHeadN {
struct BHead bhead;
} BHeadN;
-
-#define FD_FLAGS_SWITCH_ENDIAN (1 << 0)
-#define FD_FLAGS_FILE_POINTSIZE_IS_4 (1 << 1)
-#define FD_FLAGS_POINTSIZE_DIFFERS (1 << 2)
-#define FD_FLAGS_FILE_OK (1 << 3)
-#define FD_FLAGS_NOT_MY_BUFFER (1 << 4)
-#define FD_FLAGS_NOT_MY_LIBMAP (1 << 5)
+/* FileData->flags */
+enum {
+ FD_FLAGS_SWITCH_ENDIAN = 1 << 0,
+ FD_FLAGS_FILE_POINTSIZE_IS_4 = 1 << 1,
+ FD_FLAGS_POINTSIZE_DIFFERS = 1 << 2,
+ FD_FLAGS_FILE_OK = 1 << 3,
+ FD_FLAGS_NOT_MY_BUFFER = 1 << 4,
+ FD_FLAGS_NOT_MY_LIBMAP = 1 << 5, /* XXX Unused in practice (checked once but never set). */
+};
#define SIZEOFBLENDERHEADER 12
@@ -139,7 +142,7 @@ void blo_make_sound_pointer_map(FileData *fd, Main *oldmain);
void blo_end_sound_pointer_map(FileData *fd, Main *oldmain);
void blo_make_packed_pointer_map(FileData *fd, Main *oldmain);
void blo_end_packed_pointer_map(FileData *fd, Main *oldmain);
-void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd);
+void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd);
void blo_freefiledata(FileData *fd);
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 25074effaab..907baab0aee 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -343,7 +343,7 @@ static void do_versions_mesh_mloopcol_swap_2_62_1(Mesh *me)
if (layer->type == CD_MLOOPCOL) {
mloopcol = (MLoopCol *)layer->data;
for (i = 0; i < me->totloop; i++, mloopcol++) {
- SWAP(char, mloopcol->r, mloopcol->b);
+ SWAP(unsigned char, mloopcol->r, mloopcol->b);
}
}
}
@@ -459,19 +459,19 @@ static void do_versions_affine_tracker_track(MovieTrackingTrack *track)
if (is_zero_v2(marker->pattern_corners[0]) && is_zero_v2(marker->pattern_corners[1]) &&
is_zero_v2(marker->pattern_corners[2]) && is_zero_v2(marker->pattern_corners[3]))
- {
- marker->pattern_corners[0][0] = track->pat_min[0];
- marker->pattern_corners[0][1] = track->pat_min[1];
+ {
+ marker->pattern_corners[0][0] = track->pat_min[0];
+ marker->pattern_corners[0][1] = track->pat_min[1];
- marker->pattern_corners[1][0] = track->pat_max[0];
- marker->pattern_corners[1][1] = track->pat_min[1];
+ marker->pattern_corners[1][0] = track->pat_max[0];
+ marker->pattern_corners[1][1] = track->pat_min[1];
- marker->pattern_corners[2][0] = track->pat_max[0];
- marker->pattern_corners[2][1] = track->pat_max[1];
+ marker->pattern_corners[2][0] = track->pat_max[0];
+ marker->pattern_corners[2][1] = track->pat_max[1];
- marker->pattern_corners[3][0] = track->pat_min[0];
- marker->pattern_corners[3][1] = track->pat_max[1];
- }
+ marker->pattern_corners[3][0] = track->pat_min[0];
+ marker->pattern_corners[3][1] = track->pat_max[1];
+ }
if (is_zero_v2(marker->search_min) && is_zero_v2(marker->search_max)) {
copy_v2_v2(marker->search_min, track->search_min);
@@ -1386,7 +1386,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
SpaceClip *sclip = (SpaceClip *)sl;
if (sclip->around == 0) {
- sclip->around = V3D_CENTROID;
+ sclip->around = V3D_AROUND_CENTER_MEAN;
}
}
}
@@ -1864,7 +1864,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 5)) {
Scene *scene;
- Image *image;
Tex *tex;
for (scene = main->scene.first; scene; scene = scene->id.next) {
@@ -1904,7 +1903,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- for (image = main->image.first; image; image = image->id.next) {
+ for (Image *image = main->image.first; image; image = image->id.next) {
if (image->flag & IMA_DO_PREMUL) {
image->alpha_mode = IMA_ALPHA_STRAIGHT;
}
@@ -1915,7 +1914,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
for (tex = main->tex.first; tex; tex = tex->id.next) {
if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) {
- image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima);
+ Image *image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima);
if (image && (image->flag & IMA_DO_PREMUL) == 0)
image->flag |= IMA_IGNORE_ALPHA;
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 5518b1513f4..18740d43a26 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -38,6 +38,7 @@
#include "DNA_camera_types.h"
#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_sdna_types.h"
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
@@ -53,6 +54,8 @@
#include "DNA_genfile.h"
+#include "BKE_colortools.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -581,34 +584,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!MAIN_VERSION_ATLEAST(main, 273, 7)) {
- bScreen *scr;
- ScrArea *sa;
- SpaceLink *sl;
- ARegion *ar;
-
- for (scr = main->screen.first; scr; scr = scr->id.next) {
- /* Remove old deprecated region from filebrowsers */
- for (sa = scr->areabase.first; sa; sa = sa->next) {
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_FILE) {
- for (ar = sl->regionbase.first; ar; ar = ar->next) {
- if (ar->regiontype == RGN_TYPE_CHANNELS) {
- break;
- }
- }
-
- if (ar) {
- /* Free old deprecated 'channel' region... */
- BKE_area_region_free(NULL, ar);
- BLI_freelinkN(&sl->regionbase, ar);
- }
- }
- }
- }
- }
- }
-
if (!MAIN_VERSION_ATLEAST(main, 273, 8)) {
Object *ob;
for (ob = main->object.first; ob != NULL; ob = ob->id.next) {
@@ -853,4 +828,261 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
#undef BRUSH_TORUS
}
+
+ if (!MAIN_VERSION_ATLEAST(main, 276, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale")) {
+ Object *ob;
+
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ if (ob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->custom_scale = 1.0f;
+ }
+ }
+ }
+ }
+
+ {
+ bScreen *screen;
+#define RV3D_VIEW_PERSPORTHO 7
+ for (screen = main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ SpaceLink *sl;
+ for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ ARegion *ar;
+ ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ar = lb->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (ar->regiondata) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->view == RV3D_VIEW_PERSPORTHO) {
+ rv3d->view = RV3D_VIEW_USER;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+#undef RV3D_VIEW_PERSPORTHO
+ }
+
+ {
+ Lamp *lamp;
+#define LA_YF_PHOTON 5
+ for (lamp = main->lamp.first; lamp; lamp = lamp->id.next) {
+ if (lamp->type == LA_YF_PHOTON) {
+ lamp->type = LA_LOCAL;
+ }
+ }
+#undef LA_YF_PHOTON
+ }
+
+ {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ if (ob->body_type == OB_BODY_TYPE_CHARACTER && (ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) {
+ ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX;
+ }
+ }
+ }
+
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 276, 3)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "CurveMapping", "mblur_shutter_curve")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ CurveMapping *curve_mapping = &scene->r.mblur_shutter_curve;
+ curvemapping_set_defaults(curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(curve_mapping);
+ curvemap_reset(curve_mapping->cm,
+ &curve_mapping->clipr,
+ CURVE_PRESET_MAX,
+ CURVEMAP_SLOPE_POS_NEG);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 276, 4)) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->gp_sculpt.brush[0].size == 0) {
+ GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+ GP_EditBrush_Data *brush;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
+ brush->size = 25;
+ brush->strength = 0.3f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
+ brush->size = 50;
+ brush->strength = 0.3f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
+ brush->size = 25;
+ brush->strength = 0.3f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
+ brush->size = 50;
+ brush->strength = 0.3f; // XXX?
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
+ brush->size = 50;
+ brush->strength = 0.5f; // XXX?
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_CLONE];
+ brush->size = 50;
+ brush->strength = 1.0f;
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "gpencil_v3d_align")) {
+#if 0 /* XXX: Cannot do this, as we get random crashes... */
+ if (scene->gpd) {
+ bGPdata *gpd = scene->gpd;
+
+ /* Copy over the settings stored in the GP datablock linked to the scene, for minimal disruption */
+ ts->gpencil_v3d_align = 0;
+
+ if (gpd->flag & GP_DATA_VIEWALIGN) ts->gpencil_v3d_align |= GP_PROJECT_VIEWSPACE;
+ if (gpd->flag & GP_DATA_DEPTH_VIEW) ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_VIEW;
+ if (gpd->flag & GP_DATA_DEPTH_STROKE) ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_STROKE;
+
+ if (gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS)
+ ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_STROKE_ENDPOINTS;
+ }
+ else {
+ /* Default to cursor for all standard 3D views */
+ ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
+ }
+#endif
+
+ ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
+ ts->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
+ ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
+ ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+ }
+ }
+
+ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) {
+ bool enabled = false;
+
+ /* Ensure that the datablock's onionskinning toggle flag
+ * stays in sync with the status of the actual layers
+ */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_ONIONSKIN) {
+ enabled = true;
+ }
+ }
+
+ if (enabled)
+ gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
+ else
+ gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Object", "unsigned char", "max_jumps")) {
+ for (Object *ob = main->object.first; ob; ob = ob->id.next) {
+ ob->max_jumps = 1;
+ }
+ }
+ }
+ if (!MAIN_VERSION_ATLEAST(main, 276, 5)) {
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ /* Important to clear all non-persistent flags from older versions here, otherwise they could collide
+ * with any new persistent flag we may add in the future. */
+ a = set_listbasepointers(main, lbarray);
+ while (a--) {
+ for (ID *id = lbarray[a]->first; id; id = id->next) {
+ id->flag &= LIB_FAKEUSER;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 276, 7)) {
+ Scene *scene;
+ for (scene = main->scene.first; scene != NULL; scene = scene->id.next) {
+ scene->r.bake.pass_filter = R_BAKE_PASS_FILTER_ALL;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 277, 1)) {
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+ for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ if (pset->brush[a].strength > 1.0f) {
+ pset->brush[a].strength *= 0.01f;
+ }
+ }
+ }
+
+ for (bScreen *screen = main->screen.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ /* Bug: Was possible to add preview region to sequencer view by using AZones. */
+ if (sl->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ if (sseq->view == SEQ_VIEW_SEQUENCE) {
+ for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
+ /* remove preview region for sequencer-only view! */
+ if (ar->regiontype == RGN_TYPE_PREVIEW) {
+ ar->flag |= RGN_FLAG_HIDDEN;
+ ar->alignment = RGN_ALIGN_NONE;
+ break;
+ }
+ }
+ }
+ }
+ /* Remove old deprecated region from filebrowsers */
+ else if (sl->spacetype == SPACE_FILE) {
+ for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_CHANNELS) {
+ /* Free old deprecated 'channel' region... */
+ BKE_area_region_free(NULL, ar);
+ BLI_freelinkN(regionbase, ar);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
+ CurvePaintSettings *cps = &scene->toolsettings->curve_paint_settings;
+ if (cps->error_threshold == 0) {
+ cps->curve_type = CU_BEZIER;
+ cps->flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
+ cps->error_threshold = 8;
+ cps->radius_max = 1.0f;
+ cps->corner_angle = DEG2RADF(70.0f);
+ }
+ }
+
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 01af11e78d1..ad7a3c5b9c4 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -60,6 +60,14 @@ void BLO_update_defaults_userpref_blend(void)
U.versions = 1;
U.savetime = 2;
+
+ /* default from T47064 */
+ U.audiorate = 48000;
+
+ /* Keep this a very small, non-zero number so zero-alpha doesn't mask out objects behind it.
+ * but take care since some hardware has driver bugs here (T46962).
+ * Further hardware workarounds should be made in gpu_extensions.c */
+ U.glalphaclip = (1.0f / 255);
}
/**
@@ -67,17 +75,11 @@ void BLO_update_defaults_userpref_blend(void)
* This function can be emptied each time the startup.blend is updated. */
void BLO_update_defaults_startup_blend(Main *bmain)
{
- Scene *scene;
- SceneRenderLayer *srl;
- FreestyleLineStyle *linestyle;
- Mesh *me;
- Material *mat;
-
- for (scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->r.im_format.planes = R_IMF_PLANES_RGBA;
scene->r.im_format.compress = 15;
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
+ for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) {
srl->freestyleConfig.sphere_radius = 0.1f;
srl->pass_alpha_threshold = 0.5f;
}
@@ -91,13 +93,66 @@ void BLO_update_defaults_startup_blend(Main *bmain)
sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE;
sculpt->detail_size = 12;
}
+
+ if (ts->gp_sculpt.brush[0].size == 0) {
+ GP_BrushEdit_Settings *gset = &ts->gp_sculpt;
+ GP_EditBrush_Data *brush;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
+ brush->size = 25;
+ brush->strength = 0.3f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
+ brush->size = 50;
+ brush->strength = 0.3f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
+ brush->size = 25;
+ brush->strength = 0.3f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
+ brush->size = 50;
+ brush->strength = 0.3f; // XXX?
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
+ brush->size = 50;
+ brush->strength = 0.5f; // XXX?
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+
+ brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
+ brush->size = 25;
+ brush->strength = 0.5f;
+ brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ }
+
+ ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
+ ts->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
+ ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
+ ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+
+ ParticleEditSettings *pset = &ts->particle;
+ for (int a = 0; a < PE_TOT_BRUSH; a++) {
+ pset->brush[a].strength = 0.5f;
+ }
+ pset->brush[PE_BRUSH_CUT].strength = 1.0f;
}
scene->gm.lodflag |= SCE_LOD_USE_HYST;
scene->gm.scehysteresis = 10;
+
+ scene->r.ffcodecdata.audio_mixrate = 48000;
}
- for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ for (FreestyleLineStyle *linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
linestyle->integration_type = LS_INTEGRATION_MEAN;
@@ -105,48 +160,52 @@ void BLO_update_defaults_startup_blend(Main *bmain)
linestyle->chain_count = 10;
}
- {
- bScreen *screen;
-
- for (screen = bmain->screen.first; screen; screen = screen->id.next) {
- ScrArea *area;
- for (area = screen->areabase.first; area; area = area->next) {
- SpaceLink *space_link;
- ARegion *ar;
-
- for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
- if (space_link->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *) space_link;
- space_clip->flag &= ~SC_MANUAL_CALIBRATION;
- }
+ for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *space_link;
+ ARegion *ar;
+
+ for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
+ if (space_link->spacetype == SPACE_CLIP) {
+ SpaceClip *space_clip = (SpaceClip *) space_link;
+ space_clip->flag &= ~SC_MANUAL_CALIBRATION;
}
+ }
- for (ar = area->regionbase.first; ar; ar = ar->next) {
- /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
- BLI_freelistN(&ar->panels);
+ for (ar = area->regionbase.first; ar; ar = ar->next) {
+ /* Remove all stored panels, we want to use defaults (order, open/closed) as defined by UI code here! */
+ BLI_freelistN(&ar->panels);
- /* simple fix for 3d view properties scrollbar being not set to top */
- if (ar->regiontype == RGN_TYPE_UI) {
- float offset = ar->v2d.tot.ymax - ar->v2d.cur.ymax;
- ar->v2d.cur.ymax += offset;
- ar->v2d.cur.ymin += offset;
- }
+ /* some toolbars have been saved as initialized,
+ * we don't want them to have odd zoom-level or scrolling set, see: T47047 */
+ if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
+ ar->v2d.flag &= ~V2D_IS_INITIALISED;
}
}
}
}
- for (me = bmain->mesh.first; me; me = me->id.next) {
+ for (Mesh *me = bmain->mesh.first; me; me = me->id.next) {
me->smoothresh = DEG2RADF(180.0f);
me->flag &= ~ME_TWOSIDED;
}
- for (mat = bmain->mat.first; mat; mat = mat->id.next) {
+ for (Material *mat = bmain->mat.first; mat; mat = mat->id.next) {
mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f;
mat->line_col[3] = 1.0f;
}
{
+ Object *ob;
+
+ ob = (Object *)BKE_libblock_find_name_ex(bmain, ID_OB, "Camera");
+ if (ob) {
+ ob->rot[1] = 0.0f;
+ }
+ }
+
+ {
Brush *br;
br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Fill");
@@ -179,6 +238,24 @@ void BLO_update_defaults_startup_blend(Main *bmain)
if (br) {
br->ob_mode &= ~OB_MODE_TEXTURE_PAINT;
}
+
+ /* rename twist brush to rotate brush to match rotate tool */
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Twist");
+ if (br) {
+ BKE_libblock_rename(bmain, &br->id, "Rotate");
+ }
+
+ /* use original normal for grab brush (otherwise flickers with normal weighting). */
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Grab");
+ if (br) {
+ br->flag |= BRUSH_ORIGINAL_NORMAL;
+ }
+
+ /* increase strength, better for smoothing method */
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Blur");
+ if (br) {
+ br->alpha = 1.0f;
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 12069fd80dd..f2d42849bcc 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -589,7 +589,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
/* tex->extend and tex->imageflag have changed: */
Tex *tex = main->tex.first;
while (tex) {
- if (tex->id.flag & LIB_NEED_LINK) {
+ if (tex->id.tag & LIB_TAG_NEED_LINK) {
if (tex->extend == 0) {
if (tex->xrepeat || tex->yrepeat) {
@@ -1418,7 +1418,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
for (sce = main->scene.first; sce; sce = sce->id.next) {
- sce->audio.mixrate = 44100;
+ sce->audio.mixrate = 48000;
sce->audio.flag |= AUDIO_SCRUB;
sce->r.mode |= R_ENVMAP;
}
@@ -1787,14 +1787,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
ma = ma->id.next;
}
- /* this should have been done loooong before! */
-#if 0 /* deprecated in 2.5+ */
- while (ob) {
- if (ob->ipowin == 0)
- ob->ipowin = ID_OB;
- ob = ob->id.next;
- }
-#endif
for (sc = main->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
@@ -2219,7 +2211,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
for (sce = main->scene.first; sce; sce = sce->id.next) {
if (sce->audio.mixrate == 0)
- sce->audio.mixrate = 44100;
+ sce->audio.mixrate = 48000;
if (sce->r.xparts <2 )
sce->r.xparts = 4;
@@ -3043,7 +3035,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
part->id.lib = ob->id.lib;
part->id.us--;
- part->id.flag |= (ob->id.flag & LIB_NEED_LINK);
+ part->id.tag |= (ob->id.tag & LIB_TAG_NEED_LINK);
psys->totpart = 0;
psys->flag = PSYS_CURRENT;
@@ -3246,7 +3238,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
idproperties_fix_group_lengths(main->key);
idproperties_fix_group_lengths(main->world);
idproperties_fix_group_lengths(main->screen);
- idproperties_fix_group_lengths(main->script);
idproperties_fix_group_lengths(main->vfont);
idproperties_fix_group_lengths(main->text);
idproperties_fix_group_lengths(main->sound);
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index d320274ef96..4871dc2f161 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -150,6 +150,7 @@
#include "BKE_curve.h"
#include "BKE_constraint.h"
#include "BKE_global.h" // for G
+#include "BKE_idcode.h"
#include "BKE_library.h" // for set_listbasepointers
#include "BKE_main.h"
#include "BKE_node.h"
@@ -1356,9 +1357,6 @@ static void write_actuators(WriteData *wd, ListBase *lb)
case ACT_OBJECT:
writestruct(wd, DATA, "bObjectActuator", 1, act->data);
break;
- case ACT_IPO:
- writestruct(wd, DATA, "bIpoActuator", 1, act->data);
- break;
case ACT_PROPERTY:
writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
break;
@@ -2576,6 +2574,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
}
write_previews(wd, sce->preview);
+ write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve);
sce= sce->id.next;
}
@@ -2898,7 +2897,7 @@ static void write_libraries(WriteData *wd, Main *main)
found_one = false;
while (tot--) {
for (id= lbarray[tot]->first; id; id= id->next) {
- if (id->us>0 && (id->flag & LIB_EXTERN)) {
+ if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
found_one = true;
break;
}
@@ -2923,7 +2922,12 @@ static void write_libraries(WriteData *wd, Main *main)
while (a--) {
for (id= lbarray[a]->first; id; id= id->next) {
- if (id->us>0 && (id->flag & LIB_EXTERN)) {
+ if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) {
+ if (!BKE_idcode_is_linkable(GS(id->name))) {
+ printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable "
+ "but is flagged as directly linked", id->name, main->curlib->filepath);
+ BLI_assert(0);
+ }
writestruct(wd, ID_ID, "ID", 1, id);
}
}
@@ -3214,18 +3218,6 @@ static void write_paintcurves(WriteData *wd, ListBase *idbase)
}
}
-static void write_scripts(WriteData *wd, ListBase *idbase)
-{
- Script *script;
-
- for (script=idbase->first; script; script= script->id.next) {
- if (script->id.us>0 || wd->current) {
- writestruct(wd, ID_SCRIPT, "Script", 1, script);
- if (script->id.properties) IDP_WriteProperty(script->id.properties, wd);
- }
- }
-}
-
static void write_movieTracks(WriteData *wd, ListBase *tracks)
{
MovieTrackingTrack *track;
@@ -3762,7 +3754,6 @@ static int write_file_handle(
write_brushes (wd, &mainvar->brush);
write_palettes (wd, &mainvar->palettes);
write_paintcurves (wd, &mainvar->paintcurves);
- write_scripts (wd, &mainvar->script);
write_gpencils (wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
write_libraries(wd, mainvar->next);
@@ -3807,32 +3798,39 @@ static bool do_history(const char *name, ReportList *reports)
BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short");
return 1;
}
-
+
while (hisnr > 1) {
BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr-1);
- BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
-
- if (BLI_rename(tempname1, tempname2)) {
- BKE_report(reports, RPT_ERROR, "Unable to make version backup");
- return 1;
+ if (BLI_exists(tempname1)) {
+ BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr);
+
+ if (BLI_rename(tempname1, tempname2)) {
+ BKE_report(reports, RPT_ERROR, "Unable to make version backup");
+ return true;
+ }
}
hisnr--;
}
/* is needed when hisnr==1 */
- BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr);
+ if (BLI_exists(name)) {
+ BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr);
- if (BLI_rename(name, tempname1)) {
- BKE_report(reports, RPT_ERROR, "Unable to make version backup");
- return 1;
+ if (BLI_rename(name, tempname1)) {
+ BKE_report(reports, RPT_ERROR, "Unable to make version backup");
+ return true;
+ }
}
return 0;
}
-/* return: success (1) */
-int BLO_write_file(
- Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const BlendThumbnail *thumb)
+/**
+ * \return Success.
+ */
+bool BLO_write_file(
+ Main *mainvar, const char *filepath, int write_flags,
+ ReportList *reports, const BlendThumbnail *thumb)
{
char tempname[FILE_MAX+1];
int err, write_user_block;
@@ -3930,14 +3928,14 @@ int BLO_write_file(
return 1;
}
-/* return: success (1) */
-int BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
+/**
+ * \return Success.
+ */
+bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags)
{
int err;
err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL);
-
- if (err==0) return 1;
- return 0;
-}
+ return (err == 0);
+}
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 6f24f00acfc..efd59c3fa94 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -106,7 +106,11 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
/* Default context for operator names/labels. */
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT "Operator"
-/* Mark the msgid applies to several elements (needed in some cases, as english adjectives have no plural mark. :( */
+/* Context for events/keymaps (necessary, since those often use one or two letters,
+ * easy to get collisions with other areas...). */
+#define BLT_I18NCONTEXT_UI_EVENTS "UI_Events_KeyMaps"
+
+/* Mark the msgid applies to several elements (needed in some cases, as english adjectives have no plural mark :( ). */
#define BLT_I18NCONTEXT_PLURAL "Plural"
/* ID-types contexts. */
@@ -160,6 +164,7 @@ typedef struct {
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_DEFAULT, "default_real"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_DEFAULT_BPYRNA, "default"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "operator_default"), \
+ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UI_EVENTS, "ui_events_keymaps"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_PLURAL, "plural"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ACTION, "id_action"), \
BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_ID_ARMATURE, "id_armature"), \
diff --git a/source/blender/blentranslation/SConscript b/source/blender/blentranslation/SConscript
deleted file mode 100644
index c7e9853618c..00000000000
--- a/source/blender/blentranslation/SConscript
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- '#/intern/guardedalloc',
- '#/intern/locale',
- '../blenkernel',
- '../blenlib',
- '../blentranslation',
- '../makesdna',
- '../makesrna',
- ]
-
-defs = []
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
- incs.append('../python')
-
-env.BlenderLib('bf_blentranslation', sources, incs, defines=defs, libtype=['core', 'player'], priority=[211, 211])
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 257768b0ac8..30fefe37f0e 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blentranslation
../makesdna
../../../intern/guardedalloc
+ ../../../intern/eigen
../../../extern/rangetree
)
@@ -112,6 +113,8 @@ set(SRC
intern/bmesh_operators_private.h
intern/bmesh_polygon.c
intern/bmesh_polygon.h
+ intern/bmesh_polygon_edgenet.c
+ intern/bmesh_polygon_edgenet.h
intern/bmesh_private.h
intern/bmesh_queries.c
intern/bmesh_queries.h
@@ -145,6 +148,8 @@ set(SRC
tools/bmesh_intersect.h
tools/bmesh_path.c
tools/bmesh_path.h
+ tools/bmesh_path_region.c
+ tools/bmesh_path_region.h
tools/bmesh_region_match.c
tools/bmesh_region_match.h
tools/bmesh_triangulate.c
@@ -160,7 +165,7 @@ set(SRC
)
if(MSVC)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX /wd4101")
endif()
if(WITH_BULLET)
@@ -174,13 +179,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_OPENNL)
- add_definitions(-DWITH_OPENNL)
- list(APPEND INC_SYS
- ../../../intern/opennl/extern
- )
-endif()
-
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript
deleted file mode 100644
index c53974be1a7..00000000000
--- a/source/blender/bmesh/SConscript
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-cflags=''
-
-sources = env.Glob('intern/*.c')
-sources += env.Glob('operators/*.c')
-sources += env.Glob('tools/*.c')
-
-incs = [
- './',
- '../blenlib',
- '../blentranslation',
- '../makesdna',
- '../blenkernel',
- '#/intern/guardedalloc',
- '#/extern/bullet2/src',
- '#/extern/rangetree',
- '#/intern/opennl/extern'
- ]
-
-defs = []
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-env.BlenderLib ( libname = 'bf_bmesh', sources = sources, includes = Split(incs), libtype = ['core','player'], defines=defs, priority=[100, 100], compileflags=cflags )
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 78c814af86e..f29d280d071 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -244,6 +244,7 @@ extern "C" {
#include "intern/bmesh_mods.h"
#include "intern/bmesh_operators.h"
#include "intern/bmesh_polygon.h"
+#include "intern/bmesh_polygon_edgenet.h"
#include "intern/bmesh_queries.h"
#include "intern/bmesh_walkers.h"
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 57107ed4e37..e3caeedd2c9 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -217,7 +217,7 @@ typedef struct BMesh {
/* operator api stuff (must be all NULL or all alloc'd) */
struct BLI_mempool *vtoolflagpool, *etoolflagpool, *ftoolflagpool;
- int stackdepth;
+ int toolflag_index;
struct BMOperator *currentop;
CustomData vdata, edata, ldata, pdata;
@@ -276,8 +276,16 @@ enum {
#define BM_CHECK_TYPE_ELEM(ele) \
CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST)
+/* Assignment from a void* to a typed pointer is not allowed in C++,
+ * casting the LHS to void works fine though.
+ */
+#ifdef __cplusplus
+#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
+ (BM_CHECK_TYPE_ELEM(ele)), *((void **)&ele)
+#else
#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \
(BM_CHECK_TYPE_ELEM(ele)), ele
+#endif
/* BMHeader->hflag (char) */
enum {
@@ -309,7 +317,11 @@ enum {
struct BPy_BMGeneric;
extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self);
-typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data);
+typedef bool (*BMElemFilterFunc)(const BMElem *, void *user_data);
+typedef bool (*BMVertFilterFunc)(const BMVert *, void *user_data);
+typedef bool (*BMEdgeFilterFunc)(const BMEdge *, void *user_data);
+typedef bool (*BMFaceFilterFunc)(const BMFace *, void *user_data);
+typedef bool (*BMLoopFilterFunc)(const BMLoop *, void *user_data);
/* defines */
#define BM_ELEM_CD_SET_INT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index f7f767f91bf..23212dd085e 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -41,6 +41,7 @@ extern "C" {
#include "tools/bmesh_edgenet.h"
#include "tools/bmesh_edgesplit.h"
#include "tools/bmesh_path.h"
+#include "tools/bmesh_path_region.h"
#include "tools/bmesh_region_match.h"
#include "tools/bmesh_triangulate.h"
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index 7664108f348..fdad93ee90d 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -46,10 +46,29 @@
#define SELECT 1
+
+/**
+ * Fill in a vertex array from an edge array.
+ *
+ * \returns false if any verts aren't found.
+ */
+bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len)
+{
+ int i, i_prev = len - 1;
+ for (i = 0; i < len; i++) {
+ vert_arr[i] = BM_edge_share_vert(edge_arr[i_prev], edge_arr[i]);
+ if (vert_arr[i] == NULL) {
+ return false;
+ }
+ i_prev = i;
+ }
+ return true;
+}
+
/**
* Fill in an edge array from a vertex array (connected polygon loop).
*
- * \returns false if any edges aren't found .
+ * \returns false if any edges aren't found.
*/
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len)
{
@@ -116,7 +135,7 @@ BMFace *BM_face_create_quad_tri(
*/
void BM_face_copy_shared(
BMesh *bm, BMFace *f,
- BMElemFilterFunc filter_fn, void *user_data)
+ BMLoopFilterFunc filter_fn, void *user_data)
{
BMLoop *l_first;
BMLoop *l_iter;
@@ -149,7 +168,7 @@ void BM_face_copy_shared(
for (j = 0; j < 2; j++) {
BLI_assert(l_dst[j]->v == l_src[j]->v);
if (BM_ELEM_API_FLAG_TEST(l_dst[j], _FLAG_OVERLAP) == 0) {
- if ((filter_fn == NULL) || filter_fn((BMElem *)l_src[j], user_data)) {
+ if ((filter_fn == NULL) || filter_fn(l_src[j], user_data)) {
bm_loop_attrs_copy(bm, bm, l_src[j], l_dst[j]);
BM_ELEM_API_FLAG_ENABLE(l_dst[j], _FLAG_OVERLAP);
}
diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h
index 29503679547..06bc5465a19 100644
--- a/source/blender/bmesh/intern/bmesh_construct.h
+++ b/source/blender/bmesh/intern/bmesh_construct.h
@@ -29,6 +29,8 @@
struct BMAllocTemplate;
+bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len);
+
bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len);
void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len);
@@ -38,7 +40,7 @@ BMFace *BM_face_create_quad_tri(
void BM_face_copy_shared(
BMesh *bm, BMFace *f,
- BMElemFilterFunc filter_fn, void *user_data);
+ BMLoopFilterFunc filter_fn, void *user_data);
BMFace *BM_face_create_ngon(
BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len,
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index e67aa1da340..f7e709ce9cc 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -37,6 +37,7 @@
#include "BLT_translation.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
#include "bmesh.h"
#include "intern/bmesh_private.h"
@@ -206,6 +207,11 @@ BMEdge *BM_edge_create(
return e;
}
+/**
+ * \note In most cases a \a l_example should be NULL,
+ * since this is a low level API and we shouldn't attempt to be clever and guess whats intended.
+ * In cases where copying adjacent loop-data is useful, see #BM_face_copy_shared.
+ */
static BMLoop *bm_loop_create(
BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
const BMLoop *l_example, const eBMCreateFlag create_flag)
@@ -217,6 +223,14 @@ static BMLoop *bm_loop_create(
BLI_assert((l_example == NULL) || (l_example->head.htype == BM_LOOP));
BLI_assert(!(create_flag & 1));
+#ifndef NDEBUG
+ if (l_example) {
+ /* ensure passing a loop is either sharing the same vertex, or entirely disconnected
+ * use to catch mistake passing in loop offset-by-one. */
+ BLI_assert((v == l_example->v) || !ELEM(v, l_example->prev->v, l_example->next->v));
+ }
+#endif
+
/* --- assign all members --- */
l->head.data = NULL;
@@ -247,6 +261,9 @@ static BMLoop *bm_loop_create(
if (!(create_flag & BM_CREATE_SKIP_CD)) {
if (l_example) {
+ /* no need to copy attrs, just handle customdata */
+ // BM_elem_attrs_copy(bm, bm, l_example, l);
+ CustomData_bmesh_free_block_data(&bm->ldata, l->head.data);
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_example->head.data, &l->head.data);
}
else {
@@ -264,7 +281,7 @@ static BMLoop *bm_face_boundary_add(
#ifdef USE_BMESH_HOLES
BMLoopList *lst = BLI_mempool_calloc(bm->looplistpool);
#endif
- BMLoop *l = bm_loop_create(bm, startv, starte, f, starte->l, create_flag);
+ BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag);
bmesh_radial_append(starte, l);
@@ -439,7 +456,7 @@ BMFace *BM_face_create(
startl->v = verts[0];
startl->e = edges[0];
for (i = 1; i < len; i++) {
- l = bm_loop_create(bm, verts[i], edges[i], f, edges[i]->l, create_flag);
+ l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag);
l->f = f;
bmesh_radial_append(edges[i], l);
@@ -503,47 +520,84 @@ BMFace *BM_face_create_verts(
/**
* Check the element is valid.
*
- * BMESH_TODO, when this raises an error the output is incredible confusing.
- * need to have some nice way to print/debug what the hecks going on.
+ * BMESH_TODO, when this raises an error the output is incredibly confusing.
+ * need to have some nice way to print/debug what the heck's going on.
*/
int bmesh_elem_check(void *element, const char htype)
{
BMHeader *head = element;
- int err = 0;
+ enum {
+ IS_NULL = (1 << 0),
+ IS_WRONG_TYPE = (1 << 1),
+
+ IS_VERT_WRONG_EDGE_TYPE = (1 << 2),
+
+ IS_EDGE_NULL_DISK_LINK = (1 << 3),
+ IS_EDGE_WRONG_LOOP_TYPE = (1 << 4),
+ IS_EDGE_WRONG_FACE_TYPE = (1 << 5),
+ IS_EDGE_NULL_RADIAL_LINK = (1 << 6),
+ IS_EDGE_ZERO_FACE_LENGTH = (1 << 7),
+
+ IS_LOOP_WRONG_FACE_TYPE = (1 << 8),
+ IS_LOOP_WRONG_EDGE_TYPE = (1 << 9),
+ IS_LOOP_WRONG_VERT_TYPE = (1 << 10),
+ IS_LOOP_VERT_NOT_IN_EDGE = (1 << 11),
+ IS_LOOP_NULL_CYCLE_LINK = (1 << 12),
+ IS_LOOP_ZERO_FACE_LENGTH = (1 << 13),
+ IS_LOOP_WRONG_FACE_LENGTH = (1 << 14),
+ IS_LOOP_WRONG_RADIAL_LENGTH = (1 << 15),
+
+ IS_FACE_NULL_LOOP = (1 << 16),
+ IS_FACE_WRONG_LOOP_FACE = (1 << 17),
+ IS_FACE_NULL_EDGE = (1 << 18),
+ IS_FACE_NULL_VERT = (1 << 19),
+ IS_FACE_LOOP_VERT_NOT_IN_EDGE = (1 << 20),
+ IS_FACE_LOOP_WRONG_RADIAL_LENGTH = (1 << 21),
+ IS_FACE_LOOP_WRONG_DISK_LENGTH = (1 << 22),
+ IS_FACE_LOOP_DUPE_LOOP = (1 << 23),
+ IS_FACE_LOOP_DUPE_VERT = (1 << 24),
+ IS_FACE_LOOP_DUPE_EDGE = (1 << 25),
+ IS_FACE_WRONG_LENGTH = (1 << 26),
+ } err = 0;
if (!element)
- return (1 << 0);
+ return IS_NULL;
if (head->htype != htype)
- return (1 << 1);
+ return IS_WRONG_TYPE;
switch (htype) {
case BM_VERT:
{
BMVert *v = element;
if (v->e && v->e->head.htype != BM_EDGE) {
- err |= (1 << 2);
+ err |= IS_VERT_WRONG_EDGE_TYPE;
}
break;
}
case BM_EDGE:
{
BMEdge *e = element;
- if (e->l && e->l->head.htype != BM_LOOP)
- err |= (1 << 3);
- if (e->l && e->l->f->head.htype != BM_FACE)
- err |= (1 << 4);
if (e->v1_disk_link.prev == NULL ||
e->v2_disk_link.prev == NULL ||
e->v1_disk_link.next == NULL ||
e->v2_disk_link.next == NULL)
{
- err |= (1 << 5);
+ err |= IS_EDGE_NULL_DISK_LINK;
+ }
+
+ if (e->l && e->l->head.htype != BM_LOOP) {
+ err |= IS_EDGE_WRONG_LOOP_TYPE;
+ }
+ if (e->l && e->l->f->head.htype != BM_FACE) {
+ err |= IS_EDGE_WRONG_FACE_TYPE;
+ }
+ if (e->l && (e->l->radial_next == NULL || e->l->radial_prev == NULL)) {
+ err |= IS_EDGE_NULL_RADIAL_LINK;
+ }
+ if (e->l && e->l->f->len <= 0) {
+ err |= IS_EDGE_ZERO_FACE_LENGTH;
}
- if (e->l && (e->l->radial_next == NULL || e->l->radial_prev == NULL))
- err |= (1 << 6);
- if (e->l && e->l->f->len <= 0)
- err |= (1 << 7);
break;
}
case BM_LOOP:
@@ -551,21 +605,26 @@ int bmesh_elem_check(void *element, const char htype)
BMLoop *l = element, *l2;
int i;
- if (l->f->head.htype != BM_FACE)
- err |= (1 << 8);
- if (l->e->head.htype != BM_EDGE)
- err |= (1 << 9);
- if (l->v->head.htype != BM_VERT)
- err |= (1 << 10);
+ if (l->f->head.htype != BM_FACE) {
+ err |= IS_LOOP_WRONG_FACE_TYPE;
+ }
+ if (l->e->head.htype != BM_EDGE) {
+ err |= IS_LOOP_WRONG_EDGE_TYPE;
+ }
+ if (l->v->head.htype != BM_VERT) {
+ err |= IS_LOOP_WRONG_VERT_TYPE;
+ }
if (!BM_vert_in_edge(l->e, l->v)) {
fprintf(stderr, "%s: fatal bmesh error (vert not in edge)! (bmesh internal error)\n", __func__);
- err |= (1 << 11);
+ err |= IS_LOOP_VERT_NOT_IN_EDGE;
}
- if (l->radial_next == NULL || l->radial_prev == NULL)
- err |= (1 << 12);
- if (l->f->len <= 0)
- err |= (1 << 13);
+ if (l->radial_next == NULL || l->radial_prev == NULL) {
+ err |= IS_LOOP_NULL_CYCLE_LINK;
+ }
+ if (l->f->len <= 0) {
+ err |= IS_LOOP_ZERO_FACE_LENGTH;
+ }
/* validate boundary loop -- invalid for hole loops, of course,
* but we won't be allowing those for a while yet */
@@ -579,11 +638,13 @@ int bmesh_elem_check(void *element, const char htype)
i++;
} while ((l2 = l2->next) != l);
- if (i != l->f->len || l2 != l)
- err |= (1 << 14);
+ if (i != l->f->len || l2 != l) {
+ err |= IS_LOOP_WRONG_FACE_LENGTH;
+ }
- if (!bmesh_radial_validate(bmesh_radial_length(l), l))
- err |= (1 << 15);
+ if (!bmesh_radial_validate(bmesh_radial_length(l), l)) {
+ err |= IS_LOOP_WRONG_RADIAL_LENGTH;
+ }
break;
}
@@ -600,34 +661,73 @@ int bmesh_elem_check(void *element, const char htype)
if (!f->l_first)
#endif
{
- err |= (1 << 16);
+ err |= IS_FACE_NULL_LOOP;
}
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (l_iter->f != f) {
fprintf(stderr, "%s: loop inside one face points to another! (bmesh internal error)\n", __func__);
- err |= (1 << 17);
+ err |= IS_FACE_WRONG_LOOP_FACE;
}
- if (!l_iter->e)
- err |= (1 << 18);
- if (!l_iter->v)
- err |= (1 << 19);
- if (!BM_vert_in_edge(l_iter->e, l_iter->v) || !BM_vert_in_edge(l_iter->e, l_iter->next->v)) {
- err |= (1 << 20);
+ if (!l_iter->e) {
+ err |= IS_FACE_NULL_EDGE;
}
+ if (!l_iter->v) {
+ err |= IS_FACE_NULL_VERT;
+ }
+ if (l_iter->e && l_iter->v) {
+ if (!BM_vert_in_edge(l_iter->e, l_iter->v) ||
+ !BM_vert_in_edge(l_iter->e, l_iter->next->v))
+ {
+ err |= IS_FACE_LOOP_VERT_NOT_IN_EDGE;
+ }
- if (!bmesh_radial_validate(bmesh_radial_length(l_iter), l_iter))
- err |= (1 << 21);
+ if (!bmesh_radial_validate(bmesh_radial_length(l_iter), l_iter)) {
+ err |= IS_FACE_LOOP_WRONG_RADIAL_LENGTH;
+ }
- if (!bmesh_disk_count(l_iter->v) || !bmesh_disk_count(l_iter->next->v))
- err |= (1 << 22);
+ if (bmesh_disk_count_ex(l_iter->v, 2) < 2) {
+ err |= IS_FACE_LOOP_WRONG_DISK_LENGTH;
+ }
+ }
+
+ /* check for duplicates */
+ if (BM_ELEM_API_FLAG_TEST(l_iter, _FLAG_ELEM_CHECK)) {
+ err |= IS_FACE_LOOP_DUPE_LOOP;
+ }
+ BM_ELEM_API_FLAG_ENABLE(l_iter, _FLAG_ELEM_CHECK);
+ if (l_iter->v) {
+ if (BM_ELEM_API_FLAG_TEST(l_iter->v, _FLAG_ELEM_CHECK)) {
+ err |= IS_FACE_LOOP_DUPE_VERT;
+ }
+ BM_ELEM_API_FLAG_ENABLE(l_iter->v, _FLAG_ELEM_CHECK);
+ }
+ if (l_iter->e) {
+ if (BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_ELEM_CHECK)) {
+ err |= IS_FACE_LOOP_DUPE_EDGE;
+ }
+ BM_ELEM_API_FLAG_ENABLE(l_iter->e, _FLAG_ELEM_CHECK);
+ }
len++;
} while ((l_iter = l_iter->next) != l_first);
- if (len != f->len)
- err |= (1 << 23);
+ /* cleanup duplicates flag */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ELEM_API_FLAG_DISABLE(l_iter, _FLAG_ELEM_CHECK);
+ if (l_iter->v) {
+ BM_ELEM_API_FLAG_DISABLE(l_iter->v, _FLAG_ELEM_CHECK);
+ }
+ if (l_iter->e) {
+ BM_ELEM_API_FLAG_DISABLE(l_iter->e, _FLAG_ELEM_CHECK);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (len != f->len) {
+ err |= IS_FACE_WRONG_LENGTH;
+ }
break;
}
default:
@@ -773,7 +873,12 @@ void BM_face_kill(BMesh *bm, BMFace *f)
BMLoopList *ls, *ls_next;
#endif
- BM_CHECK_ELEMENT(f);
+#ifdef NDEBUG
+ /* check length since we may be removing degenerate faces */
+ if (f->len >= 3) {
+ BM_CHECK_ELEMENT(f);
+ }
+#endif
#ifdef USE_BMESH_HOLES
for (ls = f->loops.first; ls; ls = ls_next)
@@ -805,15 +910,72 @@ void BM_face_kill(BMesh *bm, BMFace *f)
bm_kill_only_face(bm, f);
}
+
+/**
+ * A version of #BM_face_kill which removes edges and verts
+ * which have no remaining connected geometry.
+ */
+void BM_face_kill_loose(BMesh *bm, BMFace *f)
+{
+#ifdef USE_BMESH_HOLES
+ BMLoopList *ls, *ls_next;
+#endif
+
+ BM_CHECK_ELEMENT(f);
+
+#ifdef USE_BMESH_HOLES
+ for (ls = f->loops.first; ls; ls = ls_next)
+#else
+ if (f->l_first)
+#endif
+ {
+ BMLoop *l_iter, *l_next, *l_first;
+
+#ifdef USE_BMESH_HOLES
+ ls_next = ls->next;
+ l_iter = l_first = ls->first;
+#else
+ l_iter = l_first = f->l_first;
+#endif
+
+ do {
+ BMEdge *e;
+ l_next = l_iter->next;
+
+ e = l_iter->e;
+ bmesh_radial_loop_remove(l_iter, e);
+ bm_kill_only_loop(bm, l_iter);
+
+ if (e->l == NULL) {
+ BMVert *v1 = e->v1, *v2 = e->v2;
+
+ bmesh_disk_edge_remove(e, e->v1);
+ bmesh_disk_edge_remove(e, e->v2);
+ bm_kill_only_edge(bm, e);
+
+ if (v1->e == NULL) {
+ bm_kill_only_vert(bm, v1);
+ }
+ if (v2->e == NULL) {
+ bm_kill_only_vert(bm, v2);
+ }
+ }
+ } while ((l_iter = l_next) != l_first);
+
+#ifdef USE_BMESH_HOLES
+ BLI_mempool_free(bm->looplistpool, ls);
+#endif
+ }
+
+ bm_kill_only_face(bm, f);
+}
+
/**
* kills \a e and all faces that use it.
*/
void BM_edge_kill(BMesh *bm, BMEdge *e)
{
- bmesh_disk_edge_remove(e, e->v1);
- bmesh_disk_edge_remove(e, e->v2);
-
if (e->l) {
BMLoop *l = e->l, *lnext, *startl = e->l;
@@ -831,6 +993,9 @@ void BM_edge_kill(BMesh *bm, BMEdge *e)
l = lnext;
} while (l != startl);
}
+
+ bmesh_disk_edge_remove(e, e->v1);
+ bmesh_disk_edge_remove(e, e->v2);
bm_kill_only_edge(bm, e);
}
@@ -880,13 +1045,18 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l)
*
* BMESH_TODO: reinsert validation code.
*
+ * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`.
+ * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp,
+ * (use when flipping normals, disable when mirroring, eg: symmetrize).
+ *
* \return Success
*/
-static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
+static bool bm_loop_reverse_loop(
+ BMesh *bm, BMFace *f,
#ifdef USE_BMESH_HOLES
- , BMLoopList *lst
+ BMLoopList *lst,
#endif
- )
+ const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
#ifdef USE_BMESH_HOLES
@@ -896,7 +1066,6 @@ static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
#endif
const int len = f->len;
- const bool do_disps = CustomData_has_layer(&bm->ldata, CD_MDISPS);
BMLoop *l_iter, *oldprev, *oldnext;
BMEdge **edar = BLI_array_alloca(edar, len);
int i, j, edok;
@@ -913,26 +1082,9 @@ static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
l_iter->prev = oldnext;
l_iter = oldnext;
- if (do_disps) {
- float (*co)[3];
- int x, y, sides;
- MDisps *md;
-
- md = CustomData_bmesh_get(&bm->ldata, l_iter->head.data, CD_MDISPS);
- if (!md->totdisp || !md->disps)
- continue;
-
- sides = (int)sqrt(md->totdisp);
- co = md->disps;
-
- for (x = 0; x < sides; x++) {
- for (y = 0; y < x; y++) {
- swap_v3_v3(co[y * sides + x], co[sides * x + y]);
- SWAP(float, co[y * sides + x][0], co[y * sides + x][1]);
- SWAP(float, co[x * sides + y][0], co[x * sides + y][1]);
- }
- SWAP(float, co[x * sides + x][0], co[x * sides + x][1]);
- }
+ if (cd_loop_mdisp_offset != -1) {
+ MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
+ BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip);
}
}
@@ -957,6 +1109,7 @@ static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next)
bmesh_radial_append(l_iter->e, l_iter);
+#ifndef NDEBUG
/* validate radial */
for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) {
BM_CHECK_ELEMENT(l_iter);
@@ -966,6 +1119,7 @@ static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
}
BM_CHECK_ELEMENT(f);
+#endif
/* Loop indices are no more valid! */
bm->elem_index_dirty |= BM_LOOP;
@@ -976,12 +1130,14 @@ static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
/**
* \brief Flip the faces direction
*/
-bool bmesh_loop_reverse(BMesh *bm, BMFace *f)
+bool bmesh_loop_reverse(
+ BMesh *bm, BMFace *f,
+ const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
#ifdef USE_BMESH_HOLES
- return bm_loop_reverse_loop(bm, f, f->loops.first);
+ return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip);
#else
- return bm_loop_reverse_loop(bm, f);
+ return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
#endif
}
@@ -1092,6 +1248,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
BMVert *v1 = NULL, *v2 = NULL;
const char *err = NULL;
int i, tote = 0;
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
if (UNLIKELY(!totface)) {
BMESH_ASSERT(0);
@@ -1222,11 +1379,19 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF);
/* handle multi-res data */
- if (CustomData_has_layer(&bm->ldata, CD_MDISPS)) {
+ if (cd_loop_mdisp_offset != -1) {
+ float f_center[3];
+ float (*faces_center)[3] = BLI_array_alloca(faces_center, totface);
+
+ BM_face_calc_center_mean(f_new, f_center);
+ for (i = 0; i < totface; i++) {
+ BM_face_calc_center_mean(faces[i], faces_center[i]);
+ }
+
l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
do {
for (i = 0; i < totface; i++) {
- BM_loop_interp_multires(bm, l_iter, faces[i]);
+ BM_loop_interp_multires_ex(bm, l_iter, faces[i], f_center, faces_center[i], cd_loop_mdisp_offset);
}
} while ((l_iter = l_iter->next) != l_first);
}
@@ -1644,16 +1809,15 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
* \par Examples:
*
* <pre>
- * Before: OE KE
- * ------- -------
- * | || |
- * OV KV TV
- *
- *
- * After: OE
- * ---------------
- * | |
- * OV TV
+ * Before: e_old e_kill
+ * +-------+-------+
+ * | | |
+ * v_old v_kill v_target
+ *
+ * After: e_old
+ * +---------------+
+ * | |
+ * v_old v_target
* </pre>
*
* \par Restrictions:
@@ -1668,14 +1832,15 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
*/
BMEdge *bmesh_jekv(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool check_edge_double)
+ const bool do_del, const bool check_edge_double,
+ const bool kill_degenerate_faces)
{
BMEdge *e_old;
- BMVert *v_old, *tv;
+ BMVert *v_old, *v_target;
BMLoop *l_kill;
- int radlen = 0, i;
bool halt = false;
#ifndef NDEBUG
+ int radlen, i;
bool edok;
#endif
@@ -1692,39 +1857,46 @@ BMEdge *bmesh_jekv(
#endif
e_old = bmesh_disk_edge_next(e_kill, v_kill);
- tv = BM_edge_other_vert(e_kill, v_kill);
+ v_target = BM_edge_other_vert(e_kill, v_kill);
v_old = BM_edge_other_vert(e_old, v_kill);
- halt = BM_verts_in_edge(v_kill, tv, e_old); /* check for double edges */
+ halt = BM_verts_in_edge(v_kill, v_target, e_old); /* check for double edges */
if (halt) {
return NULL;
}
else {
BMEdge *e_splice;
+ BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
+ BMLoop *l_kill_next;
#ifndef NDEBUG
- /* For verification later, count valence of v_old and tv */
+ /* For verification later, count valence of 'v_old' and 'v_target' */
valence1 = bmesh_disk_count(v_old);
- valence2 = bmesh_disk_count(tv);
+ valence2 = bmesh_disk_count(v_target);
#endif
if (check_edge_double) {
- e_splice = BM_edge_exists(tv, v_old);
+ e_splice = BM_edge_exists(v_target, v_old);
}
- bmesh_disk_vert_replace(e_old, tv, v_kill);
+ bmesh_disk_vert_replace(e_old, v_target, v_kill);
- /* remove e_kill from tv's disk cycle */
- bmesh_disk_edge_remove(e_kill, tv);
+ /* remove e_kill from 'v_target's disk cycle */
+ bmesh_disk_edge_remove(e_kill, v_target);
+#ifndef NDEBUG
/* deal with radial cycle of e_kill */
radlen = bmesh_radial_length(e_kill->l);
+#endif
if (e_kill->l) {
- /* first step, fix the neighboring loops of all loops in e_kill's radial cycle */
- for (i = 0, l_kill = e_kill->l; i < radlen; i++, l_kill = l_kill->radial_next) {
+
+
+ /* fix the neighboring loops of all loops in e_kill's radial cycle */
+ l_kill = e_kill->l;
+ do {
/* relink loops and fix vertex pointer */
if (l_kill->next->v == v_kill) {
- l_kill->next->v = tv;
+ l_kill->next->v = v_target;
}
l_kill->next->prev = l_kill->prev;
@@ -1732,29 +1904,20 @@ BMEdge *bmesh_jekv(
if (BM_FACE_FIRST_LOOP(l_kill->f) == l_kill) {
BM_FACE_FIRST_LOOP(l_kill->f) = l_kill->next;
}
- l_kill->next = NULL;
- l_kill->prev = NULL;
/* fix len attribute of face */
l_kill->f->len--;
- }
- /* second step, remove all the hanging loops attached to e_kill */
- radlen = bmesh_radial_length(e_kill->l);
-
- if (LIKELY(radlen)) {
- BMLoop **loops = BLI_array_alloca(loops, radlen);
+ if (kill_degenerate_faces) {
+ if (l_kill->f->len < 3) {
+ BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
+ }
+ }
+ l_kill_next = l_kill->radial_next;
- l_kill = e_kill->l;
+ bm_kill_only_loop(bm, l_kill);
- /* this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well... */
- for (i = 0; i < radlen; i++) {
- loops[i] = l_kill;
- l_kill = l_kill->radial_next;
- }
- for (i = 0; i < radlen; i++) {
- bm_kill_only_loop(bm, loops[i]);
- }
- }
+ } while ((l_kill = l_kill_next) != e_kill->l);
+ /* `e_kill->l` is invalid but the edge is freed next. */
#ifndef NDEBUG
/* Validate radial cycle of e_old */
edok = bmesh_radial_validate(radlen, e_old->l);
@@ -1773,10 +1936,10 @@ BMEdge *bmesh_jekv(
}
#ifndef NDEBUG
- /* Validate disk cycle lengths of v_old, tv are unchanged */
+ /* Validate disk cycle lengths of 'v_old', 'v_target' are unchanged */
edok = bmesh_disk_validate(valence1, v_old->e, v_old);
BMESH_ASSERT(edok != false);
- edok = bmesh_disk_validate(valence2, tv->e, tv);
+ edok = bmesh_disk_validate(valence2, v_target->e, v_target);
BMESH_ASSERT(edok != false);
/* Validate loop cycle of all faces attached to 'e_old' */
@@ -1793,7 +1956,6 @@ BMEdge *bmesh_jekv(
BM_CHECK_ELEMENT(l->f);
}
#endif
-
if (check_edge_double) {
if (e_splice) {
/* removes e_splice */
@@ -1801,8 +1963,15 @@ BMEdge *bmesh_jekv(
}
}
+ if (kill_degenerate_faces) {
+ BMFace *f_kill;
+ while ((f_kill = BLI_SMALLSTACK_POP(faces_degenerate))) {
+ BM_face_kill(bm, f_kill);
+ }
+ }
+
BM_CHECK_ELEMENT(v_old);
- BM_CHECK_ELEMENT(tv);
+ BM_CHECK_ELEMENT(v_target);
BM_CHECK_ELEMENT(e_old);
return e_old;
@@ -1812,6 +1981,104 @@ BMEdge *bmesh_jekv(
}
/**
+ * \brief Join Vert Kill Edge (JVKE)
+ *
+ * Collapse an edge, merging surrounding data.
+ *
+ * Unlike #BM_vert_collapse_edge & #bmesh_jekv which only handle 2 valence verts,
+ * this can handle any number of connected edges/faces.
+ *
+ * <pre>
+ * Before: -> After:
+ * +-+-+-+ +-+-+-+
+ * | | | | | \ / |
+ * +-+-+-+ +--+--+
+ * | | | | | / \ |
+ * +-+-+-+ +-+-+-+
+ * </pre>
+ */
+BMVert *bmesh_jvke(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool check_edge_double,
+ const bool kill_degenerate_faces)
+{
+ BLI_SMALLSTACK_DECLARE(faces_degenerate, BMFace *);
+ BMVert *v_target = BM_edge_other_vert(e_kill, v_kill);
+
+ BLI_assert(BM_vert_in_edge(e_kill, v_kill));
+
+ if (e_kill->l) {
+ BMLoop *l_kill, *l_first, *l_kill_next;
+ l_kill = l_first = e_kill->l;
+ do {
+ /* relink loops and fix vertex pointer */
+ if (l_kill->next->v == v_kill) {
+ l_kill->next->v = v_target;
+ }
+
+ l_kill->next->prev = l_kill->prev;
+ l_kill->prev->next = l_kill->next;
+ if (BM_FACE_FIRST_LOOP(l_kill->f) == l_kill) {
+ BM_FACE_FIRST_LOOP(l_kill->f) = l_kill->next;
+ }
+
+ /* fix len attribute of face */
+ l_kill->f->len--;
+ if (kill_degenerate_faces) {
+ if (l_kill->f->len < 3) {
+ BLI_SMALLSTACK_PUSH(faces_degenerate, l_kill->f);
+ }
+ }
+ l_kill_next = l_kill->radial_next;
+
+ bm_kill_only_loop(bm, l_kill);
+
+ } while ((l_kill = l_kill_next) != l_first);
+
+ e_kill->l = NULL;
+ }
+
+ BM_edge_kill(bm, e_kill);
+ BM_CHECK_ELEMENT(v_kill);
+ BM_CHECK_ELEMENT(v_target);
+
+ if (v_target->e && v_kill->e) {
+ /* inline BM_vert_splice(bm, v_target, v_kill); */
+ BMEdge *e;
+ while ((e = v_kill->e)) {
+ BMEdge *e_target;
+
+ if (check_edge_double) {
+ e_target = BM_edge_exists(v_target, BM_edge_other_vert(e, v_kill));
+ }
+
+ bmesh_edge_vert_swap(e, v_target, v_kill);
+ BLI_assert(e->v1 != e->v2);
+
+ if (check_edge_double) {
+ if (e_target) {
+ BM_edge_splice(bm, e_target, e);
+ }
+ }
+ }
+ }
+
+ if (kill_degenerate_faces) {
+ BMFace *f_kill;
+ while ((f_kill = BLI_SMALLSTACK_POP(faces_degenerate))) {
+ BM_face_kill(bm, f_kill);
+ }
+ }
+
+ if (do_del) {
+ BLI_assert(v_kill->e == NULL);
+ bm_kill_only_vert(bm, v_kill);
+ }
+
+ return v_target;
+}
+
+/**
* \brief Join Face Kill Edge (JFKE)
*
* Takes two faces joined by a single 2-manifold edge and fuses them together.
@@ -2212,7 +2479,8 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate)
n_prev->next = n_step->next;
n_step = n_prev;
}
- } while ((n_prev = n_step),
+ } while ((void)
+ (n_prev = n_step),
(n_step = n_step->next));
} while ((n_orig = n_orig->next) && n_orig->next);
@@ -2275,7 +2543,7 @@ void BM_vert_separate_hflag(
do {
BMLoop *l_sep = e->l;
bmesh_edge_separate(bm, e, l_sep, copy_select);
- /* trick to avoid looping over seperated edges */
+ /* trick to avoid looping over separated edges */
if (edges_separate == NULL && edges_orig == NULL) {
e_first = l_sep->e;
}
@@ -2295,6 +2563,30 @@ void BM_vert_separate_hflag(
}
}
+void BM_vert_separate_wire_hflag(
+ BMesh *UNUSED(bm), BMVert *v_dst, BMVert *v_src,
+ const char hflag)
+{
+ LinkNode *edges_hflag = NULL;
+ BMEdge *e_iter, *e_first;
+
+ e_iter = e_first = v_src->e;
+ do {
+ if (BM_elem_flag_test(e_iter, hflag)) {
+ if (BM_edge_is_wire(e_iter)) {
+ BLI_linklist_prepend_alloca(&edges_hflag, e_iter);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_src)) != e_first);
+
+ if (edges_hflag) {
+ do {
+ e_iter = edges_hflag->link;
+ bmesh_disk_vert_replace(e_iter, v_dst, v_src);
+ } while ((edges_hflag = edges_hflag->next));
+ }
+}
+
/** \} */
@@ -2524,7 +2816,7 @@ BMVert *bmesh_urmv_loop_multi(
}
if (is_mixed_any == false) {
- /* all loops in 'larr' are the soul owners of their edges.
+ /* all loops in 'larr' are the sole owners of their edges.
* nothing to split away from, this is a no-op */
v_new = v_sep;
}
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index 2b100eb7b8d..fb5702bc574 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -58,6 +58,8 @@ BMFace *BM_face_create_verts(
void BM_face_edges_kill(BMesh *bm, BMFace *f);
void BM_face_verts_kill(BMesh *bm, BMFace *f);
+void BM_face_kill_loose(BMesh *bm, BMFace *f);
+
void BM_face_kill(BMesh *bm, BMFace *f);
void BM_edge_kill(BMesh *bm, BMEdge *e);
void BM_vert_kill(BMesh *bm, BMVert *v);
@@ -73,7 +75,9 @@ void bmesh_vert_separate(
BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len,
const bool copy_select);
-bool bmesh_loop_reverse(BMesh *bm, BMFace *f);
+bool bmesh_loop_reverse(
+ BMesh *bm, BMFace *f,
+ const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip);
BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del);
void BM_vert_separate(
@@ -82,6 +86,9 @@ void BM_vert_separate(
void BM_vert_separate_hflag(
BMesh *bm, BMVert *v, const char hflag, const bool copy_select,
BMVert ***r_vout, int *r_vout_len);
+void BM_vert_separate_wire_hflag(
+ BMesh *bm, BMVert *v_dst, BMVert *v_src,
+ const char hflag);
/* EULER API - For modifying structure */
BMFace *bmesh_sfme(
@@ -98,7 +105,12 @@ BMFace *bmesh_sfme(
BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
BMEdge *bmesh_jekv(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
- const bool do_del, const bool check_edge_splice);
+ const bool do_del, const bool check_edge_splice,
+ const bool kill_degenerate_faces);
+BMVert *bmesh_jvke(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool check_edge_double,
+ const bool kill_degenerate_faces);
BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e);
BMVert *bmesh_urmv(BMesh *bm, BMFace *f_sep, BMVert *v_sep);
BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index eaa070151a6..5e1d9c3a98d 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -664,17 +664,47 @@ void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
BLI_listbase_reverse(&el_store->verts);
}
-void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_store_len)
+void BM_edgeloop_expand(
+ BMesh *bm, BMEdgeLoopStore *el_store, int el_store_len,
+ bool split, GSet *split_edges)
{
+ bool split_swap = true;
+
+#define EDGE_SPLIT(node_copy, node_other) { \
+ BMVert *v_split, *v_other = (node_other)->data; \
+ BMEdge *e_split, *e_other = BM_edge_exists((node_copy)->data, v_other); \
+ v_split = BM_edge_split(bm, e_other, split_swap ? (node_copy)->data : v_other, &e_split, 0.0f); \
+ v_split->e = e_split; \
+ BLI_assert(v_split == e_split->v2); \
+ BLI_gset_insert(split_edges, e_split); \
+ (node_copy)->data = v_split; \
+ } ((void)0)
+
/* first double until we are more than half as big */
while ((el_store->len * 2) < el_store_len) {
LinkData *node_curr = el_store->verts.first;
while (node_curr) {
LinkData *node_curr_copy = MEM_dupallocN(node_curr);
- BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
+ if (split == false) {
+ BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
+ node_curr = node_curr_copy->next;
+ }
+ else {
+ if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
+ EDGE_SPLIT(node_curr_copy, node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
+ BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
+ node_curr = node_curr_copy->next;
+ }
+ else {
+ EDGE_SPLIT(node_curr_copy, node_curr->prev);
+ BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
+ node_curr = node_curr->next;
+ }
+ split_swap = !split_swap;
+ }
el_store->len++;
- node_curr = node_curr_copy->next;
}
+ split_swap = !split_swap;
}
if (el_store->len < el_store_len) {
@@ -694,12 +724,29 @@ void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_sto
BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init);
node_curr_copy = MEM_dupallocN(node_curr);
- BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
+ if (split == false) {
+ BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
+ node_curr = node_curr_copy->next;
+ }
+ else {
+ if (node_curr->next || (el_store->flag & BM_EDGELOOP_IS_CLOSED)) {
+ EDGE_SPLIT(node_curr_copy, node_curr->next ? node_curr->next : (LinkData *)el_store->verts.first);
+ BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
+ node_curr = node_curr_copy->next;
+ }
+ else {
+ EDGE_SPLIT(node_curr_copy, node_curr->prev);
+ BLI_insertlinkbefore(&el_store->verts, node_curr, node_curr_copy);
+ node_curr = node_curr->next;
+ }
+ split_swap = !split_swap;
+ }
el_store->len++;
- node_curr = node_curr_copy->next;
} while (el_store->len < el_store_len);
}
+#undef EDGE_SPLIT
+
BLI_assert(el_store->len == el_store_len);
}
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.h b/source/blender/bmesh/intern/bmesh_edgeloop.h
index 5df4ee5848e..68583562888 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.h
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.h
@@ -30,6 +30,7 @@
struct ListBase;
struct BMEdgeLoopStore;
+struct GSet;
/* multiple edgeloops (ListBase) */
int BM_mesh_edgeloops_find(
@@ -66,7 +67,9 @@ bool BM_edgeloop_calc_normal_aligned(
BMesh *bm, struct BMEdgeLoopStore *el_store,
const float no_align[3]);
void BM_edgeloop_flip(BMesh *bm, struct BMEdgeLoopStore *el_store);
-void BM_edgeloop_expand(BMesh *bm, struct BMEdgeLoopStore *el_store, int el_store_len);
+void BM_edgeloop_expand(
+ BMesh *bm, struct BMEdgeLoopStore *el_store, int el_store_len,
+ bool split, struct GSet *split_edges);
bool BM_edgeloop_overlap_check(struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b);
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 6e468bf44f2..f51013c3f1c 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -197,7 +197,7 @@ void BM_face_interp_from_face_ex(
if (do_vertex) {
CustomData_bmesh_interp(&bm->vdata, blocks_v, w, NULL, f_src->len, l_iter->v->head.data);
}
- } while (i++, (l_iter = l_iter->next) != l_first);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
}
void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex)
@@ -221,7 +221,7 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, con
mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
blocks_l[i] = l_iter->head.data;
if (do_vertex) blocks_v[i] = l_iter->v->head.data;
- } while (i++, (l_iter = l_iter->next) != l_first);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
BM_face_interp_from_face_ex(bm, f_dst, f_src, do_vertex,
blocks_l, blocks_v, cos_2d, axis_mat);
@@ -242,18 +242,25 @@ void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, con
* </pre>
*/
static int compute_mdisp_quad(
- BMLoop *l, float v1[3], float v2[3], float v3[3], float v4[3],
+ const BMLoop *l, const float l_f_center[3],
+ float v1[3], float v2[3], float v3[3], float v4[3],
float e1[3], float e2[3])
{
- float cent[3], n[3], p[3];
-
- /* computer center */
- BM_face_calc_center_mean(l->f, cent);
+ float n[3], p[3];
+
+#ifndef NDEBUG
+ {
+ float cent[3];
+ /* computer center */
+ BM_face_calc_center_mean(l->f, cent);
+ BLI_assert(equals_v3v3(cent, l_f_center));
+ }
+#endif
mid_v3_v3v3(p, l->prev->v->co, l->v->co);
mid_v3_v3v3(n, l->next->v->co, l->v->co);
- copy_v3_v3(v1, cent);
+ copy_v3_v3(v1, l_f_center);
copy_v3_v3(v2, p);
copy_v3_v3(v3, l->v->co);
copy_v3_v3(v4, n);
@@ -264,52 +271,13 @@ static int compute_mdisp_quad(
return 1;
}
-/* funnily enough, I think this is identical to face_to_crn_interp, heh */
-static float quad_coord(const float aa[3], const float bb[3], const float cc[3], const float dd[3], int a1, int a2)
-{
- float x, y, z, f1;
- float div;
-
- x = aa[a1] * cc[a2] - cc[a1] * aa[a2];
- y = aa[a1] * dd[a2] + bb[a1] * cc[a2] - cc[a1] * bb[a2] - dd[a1] * aa[a2];
- z = bb[a1] * dd[a2] - dd[a1] * bb[a2];
-
- div = 2.0f * (x - y + z);
-
- if (fabsf(div) > FLT_EPSILON * 10.0f) {
- const float f_tmp = sqrtf(y * y - 4.0f * x * z);
-
- f1 = min_ff(fabsf(( f_tmp - y + 2.0f * z) / div),
- fabsf((-f_tmp - y + 2.0f * z) / div));
-
- CLAMP_MAX(f1, 1.0f + FLT_EPSILON);
- }
- else {
- f1 = -z / (y - 2 * z);
- CLAMP(f1, 0.0f, 1.0f + FLT_EPSILON);
-
- if (isnan(f1) || f1 > 1.0f || f1 < 0.0f) {
- int i;
-
- for (i = 0; i < 2; i++) {
- if (fabsf(aa[i]) < FLT_EPSILON * 100.0f)
- return aa[(i + 1) % 2] / fabsf(bb[(i + 1) % 2] - aa[(i + 1) % 2]);
- if (fabsf(cc[i]) < FLT_EPSILON * 100.0f)
- return cc[(i + 1) % 2] / fabsf(dd[(i + 1) % 2] - cc[(i + 1) % 2]);
- }
- }
- }
-
- return f1;
-}
-
-static int quad_co(
- float *r_x, float *r_y,
+static bool quad_co(
const float v1[3], const float v2[3], const float v3[3], const float v4[3],
- const float p[3], const float n[3])
+ const float p[3], const float n[3],
+ float r_uv[2])
{
float projverts[5][3], n2[3];
- float dprojverts[4][3], origin[3] = {0.0f, 0.0f, 0.0f};
+ float origin[2] = {0.0f, 0.0f};
int i;
/* project points into 2d along normal */
@@ -322,7 +290,7 @@ static int quad_co(
normal_quad_v3(n2, projverts[0], projverts[1], projverts[2], projverts[3]);
if (dot_v3v3(n, n2) < -FLT_EPSILON) {
- return 0;
+ return false;
}
/* rotate */
@@ -330,50 +298,45 @@ static int quad_co(
/* subtract origin */
for (i = 0; i < 4; i++) {
- sub_v3_v3(projverts[i], projverts[4]);
+ sub_v2_v2(projverts[i], projverts[4]);
}
-
- copy_v3_v3(dprojverts[0], projverts[0]);
- copy_v3_v3(dprojverts[1], projverts[1]);
- copy_v3_v3(dprojverts[2], projverts[2]);
- copy_v3_v3(dprojverts[3], projverts[3]);
- if (!isect_point_quad_v2(origin, dprojverts[0], dprojverts[1], dprojverts[2], dprojverts[3])) {
- return 0;
+ if (!isect_point_quad_v2(origin, projverts[0], projverts[1], projverts[2], projverts[3])) {
+ return false;
}
-
- *r_y = quad_coord(dprojverts[1], dprojverts[0], dprojverts[2], dprojverts[3], 0, 1);
- *r_x = quad_coord(dprojverts[2], dprojverts[1], dprojverts[3], dprojverts[0], 0, 1);
- return 1;
+ resolve_quad_uv_v2(r_uv, origin, projverts[0], projverts[3], projverts[2], projverts[1]);
+
+ return true;
}
static void mdisp_axis_from_quad(
float v1[3], float v2[3], float UNUSED(v3[3]), float v4[3],
- float axis_x[3], float axis_y[3])
+ float r_axis_x[3], float r_axis_y[3])
{
- sub_v3_v3v3(axis_x, v4, v1);
- sub_v3_v3v3(axis_y, v2, v1);
+ sub_v3_v3v3(r_axis_x, v4, v1);
+ sub_v3_v3v3(r_axis_y, v2, v1);
- normalize_v3(axis_x);
- normalize_v3(axis_y);
+ normalize_v3(r_axis_x);
+ normalize_v3(r_axis_y);
}
/* tl is loop to project onto, l is loop whose internal displacement, co, is being
* projected. x and y are location in loop's mdisps grid of point co. */
static bool mdisp_in_mdispquad(
- BMLoop *l, BMLoop *tl, float p[3], float *x, float *y,
- int res, float axis_x[3], float axis_y[3])
+ BMLoop *l_src, BMLoop *l_dst, const float l_dst_f_center[3],
+ const float p[3], int res,
+ float r_axis_x[3], float r_axis_y[3], float r_uv[2])
{
float v1[3], v2[3], c[3], v3[3], v4[3], e1[3], e2[3];
float eps = FLT_EPSILON * 4000;
- if (is_zero_v3(l->v->no))
- BM_vert_normal_update_all(l->v);
- if (is_zero_v3(tl->v->no))
- BM_vert_normal_update_all(tl->v);
+ if (is_zero_v3(l_src->v->no))
+ BM_vert_normal_update_all(l_src->v);
+ if (is_zero_v3(l_dst->v->no))
+ BM_vert_normal_update_all(l_dst->v);
- compute_mdisp_quad(tl, v1, v2, v3, v4, e1, e2);
+ compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2);
/* expand quad a bit */
cent_quad_v3(c, v1, v2, v3, v4);
@@ -385,13 +348,12 @@ static bool mdisp_in_mdispquad(
add_v3_v3(v1, c); add_v3_v3(v2, c);
add_v3_v3(v3, c); add_v3_v3(v4, c);
- if (!quad_co(x, y, v1, v2, v3, v4, p, l->v->no))
+ if (!quad_co(v1, v2, v3, v4, p, l_src->v->no, r_uv))
return 0;
- *x *= res - 1;
- *y *= res - 1;
+ mul_v2_fl(r_uv, (float)(res - 1));
- mdisp_axis_from_quad(v1, v2, v3, v4, axis_x, axis_y);
+ mdisp_axis_from_quad(v1, v2, v3, v4, r_axis_x, r_axis_y);
return 1;
}
@@ -439,23 +401,21 @@ static void bm_loop_flip_disp(
disp[1] = (mat[0][0] * b[1] - b[0] * mat[1][0]) / d;
}
-static void bm_loop_interp_mdisps(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
+void BM_loop_interp_multires_ex(
+ BMesh *UNUSED(bm), BMLoop *l_dst, const BMFace *f_src,
+ const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset)
{
- const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
MDisps *md_dst;
float d, v1[3], v2[3], v3[3], v4[3] = {0.0f, 0.0f, 0.0f}, e1[3], e2[3];
int ix, res;
float axis_x[3], axis_y[3];
-
- if (cd_loop_mdisp_offset == -1)
- return;
/* ignore 2-edged faces */
if (UNLIKELY(l_dst->f->len < 3))
return;
md_dst = BM_ELEM_CD_GET_VOID_P(l_dst, cd_loop_mdisp_offset);
- compute_mdisp_quad(l_dst, v1, v2, v3, v4, e1, e2);
+ compute_mdisp_quad(l_dst, f_dst_center, v1, v2, v3, v4, e1, e2);
/* if no disps data allocate a new grid, the size of the first grid in f_src. */
if (!md_dst->totdisp) {
@@ -484,29 +444,20 @@ static void bm_loop_interp_mdisps(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
BMLoop *l_first;
float co1[3], co2[3], co[3];
- copy_v3_v3(co1, e1);
-
- mul_v3_fl(co1, y);
- add_v3_v3(co1, v1);
-
- copy_v3_v3(co2, e2);
- mul_v3_fl(co2, y);
- add_v3_v3(co2, v4);
-
- sub_v3_v3v3(co, co2, co1);
- mul_v3_fl(co, x);
- add_v3_v3(co, co1);
+ madd_v3_v3v3fl(co1, v1, e1, y);
+ madd_v3_v3v3fl(co2, v4, e2, y);
+ interp_v3_v3v3(co, co1, co2, x);
l_iter = l_first = BM_FACE_FIRST_LOOP(f_src);
do {
- float x2, y2;
MDisps *md_src;
float src_axis_x[3], src_axis_y[3];
+ float uv[2];
md_src = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset);
- if (mdisp_in_mdispquad(l_dst, l_iter, co, &x2, &y2, res, src_axis_x, src_axis_y)) {
- old_mdisps_bilinear(md_dst->disps[iy * res + ix], md_src->disps, res, (float)x2, (float)y2);
+ if (mdisp_in_mdispquad(l_dst, l_iter, f_src_center, co, res, src_axis_x, src_axis_y, uv)) {
+ old_mdisps_bilinear(md_dst->disps[iy * res + ix], md_src->disps, res, uv[0], uv[1]);
bm_loop_flip_disp(src_axis_x, src_axis_y, axis_x, axis_y, md_dst->disps[iy * res + ix]);
break;
@@ -517,6 +468,52 @@ static void bm_loop_interp_mdisps(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
}
/**
+ * project the multires grid in target onto f_src's set of multires grids
+ */
+void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
+{
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+
+ if (cd_loop_mdisp_offset != -1) {
+ float f_dst_center[3];
+ float f_src_center[3];
+
+ BM_face_calc_center_mean(l_dst->f, f_dst_center);
+ BM_face_calc_center_mean(f_src, f_src_center);
+
+ BM_loop_interp_multires_ex(bm, l_dst, f_src, f_dst_center, f_src_center, cd_loop_mdisp_offset);
+ }
+}
+
+void BM_face_interp_multires_ex(
+ BMesh *bm, BMFace *f_dst, const BMFace *f_src,
+ const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset)
+{
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_dst);
+ do {
+ BM_loop_interp_multires_ex(
+ bm, l_iter, f_src,
+ f_dst_center, f_src_center, cd_loop_mdisp_offset);
+ } while ((l_iter = l_iter->next) != l_first);
+}
+
+void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src)
+{
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+
+ if (cd_loop_mdisp_offset != -1) {
+ float f_dst_center[3];
+ float f_src_center[3];
+
+ BM_face_calc_center_mean(f_dst, f_dst_center);
+ BM_face_calc_center_mean(f_src, f_src_center);
+
+ BM_face_interp_multires_ex(bm, f_dst, f_src, f_dst_center, f_src_center, cd_loop_mdisp_offset);
+ }
+}
+
+/**
* smooths boundaries between multires grids,
* including some borders in adjacent faces
*/
@@ -623,14 +620,6 @@ void BM_face_multires_bounds_smooth(BMesh *bm, BMFace *f)
}
/**
- * project the multires grid in target onto f_src's set of multires grids
- */
-void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src)
-{
- bm_loop_interp_mdisps(bm, l_dst, f_src);
-}
-
-/**
* projects a single loop, target, onto f_src for customdata interpolation. multires is handled.
* if do_vertex is true, target's vert data will also get interpolated.
*/
@@ -661,7 +650,7 @@ void BM_loop_interp_from_face(
if (do_vertex) {
vblocks[i] = l_iter->v->head.data;
}
- } while (i++, (l_iter = l_iter->next) != l_first);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
mul_v2_m3v3(co, axis_mat, l_dst->v->co);
@@ -673,7 +662,7 @@ void BM_loop_interp_from_face(
}
if (do_multires) {
- bm_loop_interp_mdisps(bm, l_dst, f_src);
+ BM_loop_interp_multires(bm, l_dst, f_src);
}
}
@@ -698,7 +687,7 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
do {
mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
blocks[i] = l_iter->v->head.data;
- } while (i++, (l_iter = l_iter->next) != l_first);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
mul_v2_m3v3(co, axis_mat, v_dst->co);
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index 969e92f37db..dabdd23cf6f 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -30,7 +30,17 @@
struct LinkNode;
struct MemArena;
-void BM_loop_interp_multires(BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
+void BM_loop_interp_multires_ex(
+ BMesh *bm, BMLoop *l_dst, const BMFace *f_src,
+ const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset);
+void BM_loop_interp_multires(
+ BMesh *bm, BMLoop *l_dst, const BMFace *f_src);
+
+void BM_face_interp_multires_ex(
+ BMesh *UNUSED(bm), BMFace *f_dst, const BMFace *f_src,
+ const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset);
+void BM_face_interp_multires(BMesh *bm, BMFace *f_dst, const BMFace *f_src);
+
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src);
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 0abf41709a0..4014d29966a 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -48,7 +48,6 @@ const char bm_iter_itype_htype_map[BM_ITYPE_MAX] = {
BM_VERT, /* BM_VERTS_OF_FACE */
BM_EDGE, /* BM_EDGES_OF_FACE */
BM_LOOP, /* BM_LOOPS_OF_FACE */
- BM_LOOP, /* BM_ALL_LOOPS_OF_FACE */
BM_LOOP, /* BM_LOOPS_OF_LOOP */
BM_LOOP /* BM_LOOPS_OF_EDGE */
};
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index c4b184ef8b8..336e9d88dea 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -70,15 +70,15 @@ typedef enum BMIterType {
/* returns elements from all boundaries, and returns
* the first element at the end to flag that we're entering
* a different face hole boundary*/
- BM_ALL_LOOPS_OF_FACE = 12,
+ // BM_ALL_LOOPS_OF_FACE = 12,
/* iterate through loops around this loop, which are fetched
* from the other faces in the radial cycle surrounding the
* input loop's edge.*/
- BM_LOOPS_OF_LOOP = 13,
- BM_LOOPS_OF_EDGE = 14
+ BM_LOOPS_OF_LOOP = 12,
+ BM_LOOPS_OF_EDGE = 13
} BMIterType;
-#define BM_ITYPE_MAX 15
+#define BM_ITYPE_MAX 14
/* the iterator htype for each iterator */
extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index 17b6d1d99e7..3fe888736f0 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -498,23 +498,49 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
BM_elem_flag_disable(f, BM_ELEM_SELECT);
bm->totfacesel -= 1;
}
-
- /* flush down to edges */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- /* vertex flushing is handled below */
- if (bm_edge_is_face_select_any_other(l_iter) == false) {
+ /**
+ * \note This allows a temporarily invalid state - where for eg
+ * an edge bay be de-selected, but an adjacent face remains selected.
+ *
+ * Rely on #BM_mesh_select_mode_flush to correct these cases.
+ *
+ * \note flushing based on mode, see T46494
+ */
+ if (bm->selectmode & SCE_SELECT_VERTEX) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_vert_select_set(bm, l_iter->v, false);
BM_edge_select_set_noflush(bm, l_iter->e, false);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else {
+ /**
+ * \note use #BM_edge_select_set_noflush,
+ * vertex flushing is handled last.
+ */
+ if (bm->selectmode & SCE_SELECT_EDGE) {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_edge_select_set_noflush(bm, l_iter->e, false);
+ } while ((l_iter = l_iter->next) != l_first);
}
- } while ((l_iter = l_iter->next) != l_first);
-
- /* flush down to verts */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
- BM_vert_select_set(bm, l_iter->v, false);
+ else {
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (bm_edge_is_face_select_any_other(l_iter) == false) {
+ BM_edge_select_set_noflush(bm, l_iter->e, false);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
}
- } while ((l_iter = l_iter->next) != l_first);
+
+ /* flush down to verts */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
+ BM_vert_select_set(bm, l_iter->v, false);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index 115330cb25a..ed1bd16b2e4 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -143,7 +143,7 @@ BMesh *BM_mesh_create(const BMAllocTemplate *allocsize)
bm_mempool_init(bm, allocsize);
/* allocate one flag pool that we don't get rid of. */
- bm->stackdepth = 1;
+ bm->toolflag_index = 0;
bm->totflags = 0;
CustomData_reset(&bm->vdata);
@@ -246,7 +246,7 @@ void BM_mesh_clear(BMesh *bm)
/* allocate the memory pools for the mesh elements */
bm_mempool_init(bm, &bm_mesh_allocsize_default);
- bm->stackdepth = 1;
+ bm->toolflag_index = 0;
bm->totflags = 0;
CustomData_reset(&bm->vdata);
@@ -1665,6 +1665,40 @@ void BM_mesh_remap(
}
}
+ /* Selection history */
+ {
+ BMEditSelection *ese;
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ switch (ese->htype) {
+ case BM_VERT:
+ if (vptr_map) {
+ ese->ele = BLI_ghash_lookup(vptr_map, ese->ele);
+ BLI_assert(ese->ele);
+ }
+ break;
+ case BM_EDGE:
+ if (eptr_map) {
+ ese->ele = BLI_ghash_lookup(eptr_map, ese->ele);
+ BLI_assert(ese->ele);
+ }
+ break;
+ case BM_FACE:
+ if (fptr_map) {
+ ese->ele = BLI_ghash_lookup(fptr_map, ese->ele);
+ BLI_assert(ese->ele);
+ }
+ break;
+ }
+ }
+ }
+
+ if (fptr_map) {
+ if (bm->act_face) {
+ bm->act_face = BLI_ghash_lookup(fptr_map, bm->act_face);
+ BLI_assert(bm->act_face);
+ }
+ }
+
if (vptr_map)
BLI_ghash_free(vptr_map, NULL, NULL);
if (eptr_map)
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index b157237c7d0..b9cdc4ccf66 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -94,8 +94,26 @@ extern const BMAllocTemplate bm_mesh_chunksize_default;
(bm)->totvert), (bm)->totedge, (bm)->totloop, (bm)->totface}
#define BMALLOC_TEMPLATE_FROM_ME(me) { (CHECK_TYPE_INLINE(me, Mesh *), \
(me)->totvert), (me)->totedge, (me)->totloop, (me)->totpoly}
-#define BMALLOC_TEMPLATE_FROM_DM(dm) { (CHECK_TYPE_INLINE(dm, DerivedMesh *), \
- (dm)->getNumVerts(dm)), (dm)->getNumEdges(dm), (dm)->getNumLoops(dm), (dm)->getNumPolys(dm)}
+
+#define _VA_BMALLOC_TEMPLATE_FROM_DM_1(dm) { \
+ (CHECK_TYPE_INLINE(dm, DerivedMesh *), \
+ (dm)->getNumVerts(dm)), \
+ (dm)->getNumEdges(dm), \
+ (dm)->getNumLoops(dm), \
+ (dm)->getNumPolys(dm), \
+ }
+#define _VA_BMALLOC_TEMPLATE_FROM_DM_2(dm_a, dm_b) { \
+ (CHECK_TYPE_INLINE(dm_a, DerivedMesh *), \
+ CHECK_TYPE_INLINE(dm_b, DerivedMesh *), \
+ (dm_a)->getNumVerts(dm_a)) + (dm_b)->getNumVerts(dm_b), \
+ (dm_a)->getNumEdges(dm_a) + (dm_b)->getNumEdges(dm_b), \
+ (dm_a)->getNumLoops(dm_a) + (dm_b)->getNumLoops(dm_b), \
+ (dm_a)->getNumPolys(dm_a) + (dm_b)->getNumPolys(dm_b), \
+ }
+
+#define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__)
+
+
enum {
BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0)
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index 24d70cefb2e..931413d834f 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -728,7 +728,6 @@ void BM_mesh_bm_to_me(BMesh *bm, Mesh *me, bool do_tessface)
Object *ob;
ModifierData *md;
BMVert **vertMap = NULL;
- int i, j;
for (ob = G.main->object.first; ob; ob = ob->id.next) {
if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) {
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 13c43fabdb0..d3c847de64e 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -29,22 +29,14 @@
#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_array.h"
-#include "BLI_alloca.h"
-#include "BLI_stackdefines.h"
-#include "BLI_linklist_stack.h"
-#include "BLI_sort_utils.h"
#include "BKE_customdata.h"
#include "bmesh.h"
#include "intern/bmesh_private.h"
-// #define DEBUG_PRINT
-
-
/**
* \brief Dissolve Vert
*
@@ -252,7 +244,8 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const
BLI_assert(l_a && l_b);
if (l_a->v == l_b->v) {
- bmesh_loop_reverse(bm, f_b);
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true);
}
return BM_faces_join(bm, faces, 2, do_del);
@@ -282,7 +275,7 @@ BMFace *BM_face_split(
BMLoop **r_l, BMEdge *example,
const bool no_double)
{
- const bool has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
BMFace *f_new, *f_tmp;
BLI_assert(l_a != l_b);
@@ -300,7 +293,7 @@ BMFace *BM_face_split(
}
/* do we have a multires layer? */
- if (has_mdisp) {
+ if (cd_loop_mdisp_offset != -1) {
f_tmp = BM_face_copy(bm, bm, f, false, false);
}
@@ -312,19 +305,17 @@ BMFace *BM_face_split(
if (f_new) {
/* handle multires update */
- if (has_mdisp) {
- BMLoop *l_iter;
- BMLoop *l_first;
+ if (cd_loop_mdisp_offset != -1) {
+ float f_dst_center[3];
+ float f_src_center[3];
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BM_loop_interp_multires(bm, l_iter, f_tmp);
- } while ((l_iter = l_iter->next) != l_first);
+ BM_face_calc_center_mean(f_tmp, f_src_center);
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
- do {
- BM_loop_interp_multires(bm, l_iter, f_tmp);
- } while ((l_iter = l_iter->next) != l_first);
+ BM_face_calc_center_mean(f, f_dst_center);
+ BM_face_interp_multires_ex(bm, f, f_tmp, f_dst_center, f_src_center, cd_loop_mdisp_offset);
+
+ BM_face_calc_center_mean(f_new, f_dst_center);
+ BM_face_interp_multires_ex(bm, f_new, f_tmp, f_dst_center, f_src_center, cd_loop_mdisp_offset);
#if 0
/* BM_face_multires_bounds_smooth doesn't flip displacement correct */
@@ -334,7 +325,7 @@ BMFace *BM_face_split(
}
}
- if (has_mdisp) {
+ if (cd_loop_mdisp_offset != -1) {
BM_face_kill(bm, f_tmp);
}
@@ -427,549 +418,6 @@ BMFace *BM_face_split_n(
return f_new;
}
-
-/* -------------------------------------------------------------------- */
-/* Face Split Edge-Net */
-
-/** \name BM_face_split_edgenet and helper functions.
- *
- * \note Don't use #BM_edge_is_wire or #BM_edge_is_boundary
- * since we need to take flagged faces into account.
- * Also take care accessing e->l directly.
- *
- * \{ */
-
-/* Note: All these flags _must_ be cleared on exit */
-
-/* face is apart of the edge-net (including the original face we're splitting) */
-#define FACE_NET _FLAG_WALK
-/* edge is apart of the edge-net we're filling */
-#define EDGE_NET _FLAG_WALK
-/* tag verts we've visit */
-#define VERT_VISIT _FLAG_WALK
-
-struct VertOrder {
- float angle;
- BMVert *v;
-};
-
-static unsigned int bm_edge_flagged_radial_count(BMEdge *e)
-{
- unsigned int count = 0;
- BMLoop *l;
-
- if ((l = e->l)) {
- do {
- if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) {
- count++;
- }
- } while ((l = l->radial_next) != e->l);
- }
- return count;
-}
-
-static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
-{
- BMLoop *l;
-
- if ((l = e->l)) {
- do {
- if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) {
- return l;
- }
- } while ((l = l->radial_next) != e->l);
- }
- return NULL;
-}
-
-static bool bm_face_split_edgenet_find_loop_pair(
- BMVert *v_init, const float face_normal[3],
- BMEdge *e_pair[2])
-{
- /* Always find one boundary edge (to determine winding)
- * and one wire (if available), otherwise another boundary.
- */
- BMIter iter;
- BMEdge *e;
-
- /* detect winding */
- BMLoop *l_walk;
- bool swap;
-
- BLI_SMALLSTACK_DECLARE(edges_boundary, BMEdge *);
- BLI_SMALLSTACK_DECLARE(edges_wire, BMEdge *);
- int edges_boundary_len = 0;
- int edges_wire_len = 0;
-
- BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) {
- if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
- const unsigned int count = bm_edge_flagged_radial_count(e);
- if (count == 1) {
- BLI_SMALLSTACK_PUSH(edges_boundary, e);
- edges_boundary_len++;
- }
- else if (count == 0) {
- BLI_SMALLSTACK_PUSH(edges_wire, e);
- edges_wire_len++;
- }
- }
- }
-
- /* first edge should always be boundary */
- if (edges_boundary_len == 0) {
- return false;
- }
- e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
-
- /* attempt one boundary and one wire, or 2 boundary */
- if (edges_wire_len == 0) {
- if (edges_boundary_len >= 2) {
- e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
- }
- else {
- /* one boundary and no wire */
- return false;
- }
- }
- else {
- e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
-
- if (edges_wire_len > 1) {
- BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
- BMVert *v_next;
- float angle_best;
-
- v_next = BM_edge_other_vert(e_pair[1], v_init);
- angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
-
- while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
- float angle_test;
- v_next = BM_edge_other_vert(e, v_init);
- angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
- if (angle_test < angle_best) {
- angle_best = angle_test;
- e_pair[1] = e;
- }
- }
- }
- }
-
-
- /* flip based on winding */
- l_walk = bm_edge_flagged_radial_first(e_pair[0]);
- swap = false;
- if (face_normal == l_walk->f->no) {
- swap = !swap;
- }
- if (l_walk->v != v_init) {
- swap = !swap;
- }
- if (swap) {
- SWAP(BMEdge *, e_pair[0], e_pair[1]);
- }
-
- return true;
-}
-
-static bool bm_face_split_edgenet_find_loop_walk(
- BMVert *v_init, const float face_normal[3],
- /* cache to avoid realloc every time */
- struct VertOrder *edge_order, const unsigned int edge_order_len,
- BMEdge *e_pair[2])
-{
- /* fast-path for the common case (avoid push-pop).
- * Also avoids tagging as visited since we know we
- * can't reach these verts some other way */
-#define USE_FASTPATH_NOFORK
-
- BMVert *v;
- BMVert *v_dst;
- bool found = false;
-
- struct VertOrder *eo;
- STACK_DECLARE(edge_order);
-
- /* store visited verts so we can clear the visit flag after execution */
- BLI_SMALLSTACK_DECLARE(vert_visit, BMVert *);
-
- /* likely this will stay very small
- * all verts pushed into this stack _must_ have their previous edges set! */
- BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *);
- BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *);
-
- STACK_INIT(edge_order, edge_order_len);
-
- /* start stepping */
- v = BM_edge_other_vert(e_pair[0], v_init);
- v->e = e_pair[0];
- BLI_SMALLSTACK_PUSH(vert_stack, v);
-
- v_dst = BM_edge_other_vert(e_pair[1], v_init);
-
-#ifdef DEBUG_PRINT
- printf("%s: vert (search) %d\n", __func__, BM_elem_index_get(v_init));
-#endif
-
- /* This loop will keep stepping over the best possible edge,
- * in most cases it finds the direct route to close the face.
- *
- * In cases where paths can't be closed,
- * alternatives are stored in the 'vert_stack'.
- */
- while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
- BMIter eiter;
- BMEdge *e_next;
-
-#ifdef USE_FASTPATH_NOFORK
-walk_nofork:
-#else
- BLI_SMALLSTACK_PUSH(vert_visit, v);
- BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
-#endif
-
- BLI_assert(STACK_SIZE(edge_order) == 0);
-
- /* check if we're done! */
- if (v == v_dst) {
- found = true;
- goto finally;
- }
-
- BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
- if ((v->e != e_next) &&
- (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
- (bm_edge_flagged_radial_count(e_next) < 2))
- {
- BMVert *v_next;
-
- v_next = BM_edge_other_vert(e_next, v);
-
-#ifdef DEBUG_PRINT
- /* indent and print */
- {
- BMVert *_v = v;
- do {
- printf(" ");
- } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
- printf("vert %d -> %d (add=%d)\n",
- BM_elem_index_get(v), BM_elem_index_get(v_next),
- BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
- }
-#endif
-
- if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
- eo = STACK_PUSH_RET_PTR(edge_order);
- eo->v = v_next;
-
- v_next->e = e_next;
- }
- }
- }
-
-#ifdef USE_FASTPATH_NOFORK
- if (STACK_SIZE(edge_order) == 1) {
- eo = STACK_POP_PTR(edge_order);
- v = eo->v;
-
- goto walk_nofork;
- }
-#endif
-
- /* sort by angle if needed */
- if (STACK_SIZE(edge_order) > 1) {
- unsigned int j;
- BMVert *v_prev = BM_edge_other_vert(v->e, v);
-
- for (j = 0; j < STACK_SIZE(edge_order); j++) {
- edge_order[j].angle = angle_signed_on_axis_v3v3v3_v3(v_prev->co, v->co, edge_order[j].v->co, face_normal);
- }
- qsort(edge_order, STACK_SIZE(edge_order), sizeof(struct VertOrder), BLI_sortutil_cmp_float_reverse);
-
-#ifdef USE_FASTPATH_NOFORK
- /* only tag forks */
- BLI_SMALLSTACK_PUSH(vert_visit, v);
- BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
-#endif
- }
-
- while ((eo = STACK_POP_PTR(edge_order))) {
- BLI_SMALLSTACK_PUSH(vert_stack_next, eo->v);
- }
-
- if (!BLI_SMALLSTACK_IS_EMPTY(vert_stack_next)) {
- BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next);
- }
- }
-
-
-finally:
- /* clear flag for next execution */
- while ((v = BLI_SMALLSTACK_POP(vert_visit))) {
- BM_ELEM_API_FLAG_DISABLE(v, VERT_VISIT);
- }
-
- return found;
-
-#undef USE_FASTPATH_NOFORK
-}
-
-static bool bm_face_split_edgenet_find_loop(
- BMVert *v_init, const float face_normal[3],
- /* cache to avoid realloc every time */
- struct VertOrder *edge_order, const unsigned int edge_order_len,
- BMVert **r_face_verts, int *r_face_verts_len)
-{
- BMEdge *e_pair[2];
- BMVert *v;
-
- if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
- return false;
- }
-
- BLI_assert((bm_edge_flagged_radial_count(e_pair[0]) == 1) ||
- (bm_edge_flagged_radial_count(e_pair[1]) == 1));
-
- if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) {
- unsigned int i = 0;
-
- r_face_verts[i++] = v_init;
- v = BM_edge_other_vert(e_pair[1], v_init);
- do {
- r_face_verts[i++] = v;
- } while ((v = BM_edge_other_vert(v->e, v)) != v_init);
- *r_face_verts_len = i;
- return (i > 2) ? true : false;
- }
- else {
- return false;
- }
-}
-
-/**
- * Splits a face into many smaller faces defined by an edge-net.
- * handle customdata and degenerate cases.
- *
- * - isolated holes or unsupported face configurations, will be ignored.
- * - customdata calculations aren't efficient
- * (need to calculate weights for each vert).
- */
-bool BM_face_split_edgenet(
- BMesh *bm,
- BMFace *f, BMEdge **edge_net, const int edge_net_len,
- BMFace ***r_face_arr, int *r_face_arr_len)
-{
- /* re-use for new face verts */
- BMVert **face_verts;
- int face_verts_len;
-
- BMFace **face_arr = NULL;
- BLI_array_declare(face_arr);
-
- BMVert **vert_queue;
- STACK_DECLARE(vert_queue);
- int i;
-
- struct VertOrder *edge_order;
- const unsigned int edge_order_len = edge_net_len + 2;
-
- BMVert *v;
-
- BMLoop *l_iter, *l_first;
-
-
- if (!edge_net_len) {
- if (r_face_arr) {
- *r_face_arr = NULL;
- *r_face_arr_len = 0;
- }
- return false;
- }
-
- /* over-alloc (probably 2-4 is only used in most cases), for the biggest-fan */
- edge_order = BLI_array_alloca(edge_order, edge_order_len);
-
- /* use later */
- face_verts = BLI_array_alloca(face_verts, edge_net_len + f->len);
-
- vert_queue = BLI_array_alloca(vert_queue, edge_net_len + f->len);
- STACK_INIT(vert_queue, f->len + edge_net_len);
-
- BLI_assert(BM_ELEM_API_FLAG_TEST(f, FACE_NET) == 0);
- BM_ELEM_API_FLAG_ENABLE(f, FACE_NET);
-
-#ifdef DEBUG
- for (i = 0; i < edge_net_len; i++) {
- BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET) == 0);
- BLI_assert(BM_edge_in_face(edge_net[i], f) == false);
- }
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter->e, EDGE_NET) == 0);
- } while ((l_iter = l_iter->next) != l_first);
-#endif
-
-
- for (i = 0; i < edge_net_len; i++) {
- BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET);
- }
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
- } while ((l_iter = l_iter->next) != l_first);
-
-
- /* any vert can be used to begin with */
- STACK_PUSH(vert_queue, l_first->v);
-
- while ((v = STACK_POP(vert_queue))) {
- if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
- BMFace *f_new;
-
- f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
-
- for (i = 0; i < edge_net_len; i++) {
- BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET));
- }
-
- if (f_new) {
- bool l_prev_is_boundary;
- BLI_array_append(face_arr, f_new);
- copy_v3_v3(f_new->no, f->no);
-
- BM_ELEM_API_FLAG_ENABLE(f_new, FACE_NET);
-
- /* add new verts to keep finding loops for
- * (verts between boundary and manifold edges) */
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
- l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1);
- do {
- bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1);
- if (l_prev_is_boundary != l_iter_is_boundary) {
- STACK_PUSH(vert_queue, l_iter->v);
- }
- l_prev_is_boundary = l_iter_is_boundary;
- } while ((l_iter = l_iter->next) != l_first);
- }
- }
- }
-
-
- if (CustomData_has_math(&bm->ldata)) {
- /* reuse VERT_VISIT here to tag vert's already interpolated */
- BMIter iter;
- BMLoop *l_other;
-
- /* see: #BM_loop_interp_from_face for similar logic */
- void **blocks = BLI_array_alloca(blocks, f->len);
- float (*cos_2d)[2] = BLI_array_alloca(cos_2d, f->len);
- float *w = BLI_array_alloca(w, f->len);
- float axis_mat[3][3];
- float co[2];
-
- /* interior loops */
- axis_dominant_v3_to_m3(axis_mat, f->no);
-
-
- /* first simply copy from existing face */
- i = 0;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BM_ITER_ELEM (l_other, &iter, l_iter->v, BM_LOOPS_OF_VERT) {
- if ((l_other->f != f) && BM_ELEM_API_FLAG_TEST(l_other->f, FACE_NET)) {
- CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata,
- l_iter->head.data, &l_other->head.data);
- }
- }
- /* tag not to interpolate */
- BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_VISIT);
-
-
- mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
- blocks[i] = l_iter->head.data;
-
- } while (i++, (l_iter = l_iter->next) != l_first);
-
-
- for (i = 0; i < edge_net_len; i++) {
- BM_ITER_ELEM (v, &iter, edge_net[i], BM_VERTS_OF_EDGE) {
- if (!BM_ELEM_API_FLAG_TEST(v, VERT_VISIT)) {
- BMIter liter;
-
- BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
-
- /* interpolate this loop, then copy to the rest */
- l_first = NULL;
-
- BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) {
- if (BM_ELEM_API_FLAG_TEST(l_iter->f, FACE_NET)) {
- if (l_first == NULL) {
- mul_v2_m3v3(co, axis_mat, v->co);
- interp_weights_poly_v2(w, cos_2d, f->len, co);
- CustomData_bmesh_interp(
- &bm->ldata, (const void **)blocks,
- w, NULL, f->len, l_iter->head.data);
- l_first = l_iter;
- }
- else {
- CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata,
- l_first->head.data, &l_iter->head.data);
- }
- }
- }
- }
- }
- }
- }
-
-
-
- /* cleanup */
- for (i = 0; i < edge_net_len; i++) {
- BM_ELEM_API_FLAG_DISABLE(edge_net[i], EDGE_NET);
- /* from interp only */
- BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_VISIT);
- BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_VISIT);
- }
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- BM_ELEM_API_FLAG_DISABLE(l_iter->e, EDGE_NET);
- /* from interp only */
- BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT);
- } while ((l_iter = l_iter->next) != l_first);
-
- if (BLI_array_count(face_arr)) {
- bmesh_face_swap_data(f, face_arr[0]);
- BM_face_kill(bm, face_arr[0]);
- face_arr[0] = f;
- }
- else {
- BM_ELEM_API_FLAG_DISABLE(f, FACE_NET);
- }
-
- for (i = 0; i < BLI_array_count(face_arr); i++) {
- BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET);
- }
-
- if (r_face_arr) {
- *r_face_arr = face_arr;
- *r_face_arr_len = BLI_array_count(face_arr);
- }
- else {
- if (face_arr) {
- MEM_freeN(face_arr);
- }
- }
-
- return true;
-}
-
-#undef FACE_NET
-#undef VERT_VISIT
-#undef EDGE_NET
-
-/** \} */
-
-
/**
* \brief Vert Collapse Faces
*
@@ -1068,32 +516,8 @@ BMEdge *BM_vert_collapse_faces(
/* single face or no faces */
/* same as BM_vert_collapse_edge() however we already
* have vars to perform this operation so don't call. */
- e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true);
+ e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
/* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
-
- if (e_new && kill_degenerate_faces) {
- BMFace **bad_faces = NULL;
- BLI_array_staticdeclare(bad_faces, BM_DEFAULT_ITER_STACK_SIZE);
-
- BMIter fiter;
- BMFace *f;
- BMVert *verts[2] = {e_new->v1, e_new->v2};
- int i;
-
- for (i = 0; i < 2; i++) {
- /* cant kill data we loop on, build a list and remove those */
- BLI_array_empty(bad_faces);
- BM_ITER_ELEM (f, &fiter, verts[i], BM_FACES_OF_VERT) {
- if (UNLIKELY(f->len < 3)) {
- BLI_array_append(bad_faces, f);
- }
- }
- while ((f = BLI_array_pop(bad_faces))) {
- BM_face_kill(bm, f);
- }
- }
- BLI_array_free(bad_faces);
- }
}
return e_new;
@@ -1143,6 +567,16 @@ BMEdge *BM_vert_collapse_edge(
#undef DO_V_INTERP
/**
+ * Collapse and edge into a single vertex.
+ */
+BMVert *BM_edge_collapse(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool kill_degenerate_faces)
+{
+ return bmesh_jvke(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces);
+}
+
+/**
* \brief Edge Split
*
* <pre>
@@ -1167,7 +601,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
BMFace **oldfaces = NULL;
BMEdge *e_dummy;
BLI_array_staticdeclare(oldfaces, 32);
- const bool do_mdisp = (e->l && CustomData_has_layer(&bm->ldata, CD_MDISPS));
+ const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ? -1 : CustomData_get_offset(&bm->ldata, CD_MDISPS);
BLI_assert(BM_vert_in_edge(e, v) == true);
@@ -1177,7 +611,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
}
/* do we have a multi-res layer? */
- if (do_mdisp) {
+ if (cd_loop_mdisp_offset != -1) {
BMLoop *l;
int i;
@@ -1212,14 +646,18 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac);
BM_data_interp_from_verts(bm, v, v_other, v_new, fac);
- if (do_mdisp) {
+ if (cd_loop_mdisp_offset != -1) {
int i, j;
/* interpolate new/changed loop data from copied old faces */
- for (j = 0; j < 2; j++) {
- for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ for (i = 0; i < BLI_array_count(oldfaces); i++) {
+ float f_center_old[3];
+
+ BM_face_calc_center_mean(oldfaces[i], f_center_old);
+
+ for (j = 0; j < 2; j++) {
BMEdge *e1 = j ? *r_e : e;
- BMLoop *l, *l2;
+ BMLoop *l;
l = e1->l;
@@ -1227,16 +665,16 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
BMESH_ASSERT(0);
break;
}
-
+
do {
/* check this is an old face */
if (BM_ELEM_API_FLAG_TEST(l->f, _FLAG_OVERLAP)) {
- BMLoop *l2_first;
+ float f_center[3];
- l2 = l2_first = BM_FACE_FIRST_LOOP(l->f);
- do {
- BM_loop_interp_multires(bm, l2, oldfaces[i]);
- } while ((l2 = l2->next) != l2_first);
+ BM_face_calc_center_mean(l->f, f_center);
+ BM_face_interp_multires_ex(
+ bm, l->f, oldfaces[i],
+ f_center, f_center_old, cd_loop_mdisp_offset);
}
l = l->radial_next;
} while (l != e1->l);
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index 1b826b1e0b2..2e557e3b606 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -27,14 +27,15 @@
* \ingroup bmesh
*/
-#include <stdio.h>
-
bool BM_vert_dissolve(BMesh *bm, BMVert *v);
bool BM_disk_dissolve(BMesh *bm, BMVert *v);
BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
+
+/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */
+
BMFace *BM_face_split(
BMesh *bm, BMFace *f,
BMLoop *l_a, BMLoop *l_b,
@@ -47,11 +48,6 @@ BMFace *BM_face_split_n(
float cos[][3], int n,
BMLoop **r_l, BMEdge *example);
-bool BM_face_split_edgenet(
- BMesh *bm, BMFace *f,
- BMEdge **edge_net, const int edge_net_len,
- BMFace ***r_face_arr, int *r_face_arr_len);
-
BMEdge *BM_vert_collapse_faces(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
const bool do_del, const bool join_faces, const bool kill_degenerate_faces);
@@ -59,6 +55,9 @@ BMEdge *BM_vert_collapse_edge(
BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
const bool do_del, const bool kill_degenerate_faces);
+BMVert *BM_edge_collapse(
+ BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
+ const bool do_del, const bool kill_degenerate_faces);
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float percent);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 3e814948ade..79c2f80d6aa 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -168,8 +168,8 @@ static BMOpDefine bmo_planar_faces_def = {
"planar_faces",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input geometry. */
- {"iterations", BMO_OP_SLOT_INT},
- {"factor", BMO_OP_SLOT_FLT}, /* planar factor */
+ {"iterations", BMO_OP_SLOT_INT}, /* Number of times to flatten faces (for when connected faces are used) */
+ {"factor", BMO_OP_SLOT_FLT}, /* Influence for making planar each iteration */
{{'\0'}},
},
/* slots_out */
@@ -243,6 +243,7 @@ static BMOpDefine bmo_reverse_faces_def = {
"reverse_faces",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
+ {"flip_multires", BMO_OP_SLOT_BOOL}, /* maintain multi-res offset */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -262,7 +263,7 @@ static BMOpDefine bmo_bisect_edges_def = {
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input edges */
{"cuts", BMO_OP_SLOT_INT}, /* number of cuts */
- {"edge_percents", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_FLT}},
+ {"edge_percents", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_FLT}},
{{'\0'}},
},
/* slots_out */
@@ -322,7 +323,7 @@ static BMOpDefine bmo_find_doubles_def = {
{{'\0'}},
},
/* slots_out */
- {{"targetmap.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {{"targetmap.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
{{'\0'}},
},
bmo_find_doubles_exec,
@@ -401,7 +402,7 @@ static BMOpDefine bmo_pointmerge_facedata_def = {
"pointmerge_facedata",
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */
- {"vert_snap", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE}}, /* snap vertex */
+ {"vert_snap", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | (int)BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE}}, /* snap vertex */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -435,8 +436,8 @@ static BMOpDefine bmo_average_vert_facedata_def = {
static BMOpDefine bmo_pointmerge_def = {
"pointmerge",
/* slots_in */
- {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */
- {"merge_co", BMO_OP_SLOT_VEC},
+ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices (all verts will be merged into the first). */
+ {"merge_co", BMO_OP_SLOT_VEC}, /* Position to merge at. */
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -474,7 +475,7 @@ static BMOpDefine bmo_weld_verts_def = {
"weld_verts",
/* slots_in */
/* maps welded vertices to verts they should weld to */
- {{"targetmap", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {{"targetmap", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -819,8 +820,8 @@ static BMOpDefine bmo_transform_def = {
static BMOpDefine bmo_object_load_bmesh_def = {
"object_load_bmesh",
/* slots_in */
- {{"scene", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_SCENE}},
- {"object", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}},
+ {{"scene", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_SCENE}},
+ {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}},
{{'\0'}},
},
{{{'\0'}}}, /* no output */
@@ -839,9 +840,9 @@ static BMOpDefine bmo_bmesh_to_mesh_def = {
/* slots_in */
{
/* pointer to a mesh structure to fill in */
- {"mesh", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_MESH}},
+ {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}},
/* pointer to an object structure */
- {"object", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}},
+ {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}},
{"skip_tessface", BMO_OP_SLOT_BOOL}, /* don't calculate mfaces */
{{'\0'}},
},
@@ -861,9 +862,9 @@ static BMOpDefine bmo_mesh_to_bmesh_def = {
/* slots_in */
{
/* pointer to a Mesh structure */
- {"mesh", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_MESH}},
+ {"mesh", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_MESH}},
/* pointer to an Object structure */
- {"object", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}},
+ {"object", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_OBJECT}},
{"use_shapekey", BMO_OP_SLOT_BOOL}, /* load active shapekey coordinates into verts */
{{'\0'}},
},
@@ -1035,7 +1036,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
"extrude_face_region",
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */
- {"edges_exclude", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}},
+ {"edges_exclude", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}},
{"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */
{"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
@@ -1170,7 +1171,8 @@ static BMOpDefine bmo_triangulate_def = {
/* slots_out */
{{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}},
{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
- {"face_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"face_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"face_map_double.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}}, /* duplicate faces */
{{'\0'}},
},
bmo_triangulate_exec,
@@ -1215,8 +1217,8 @@ static BMOpDefine bmo_subdivide_edges_def = {
{"along_normal", BMO_OP_SLOT_FLT},
{"cuts", BMO_OP_SLOT_INT},
{"seed", BMO_OP_SLOT_INT},
- {"custom_patterns", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* uses custom pointers */
- {"edge_percents", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_FLT}},
+ {"custom_patterns", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL}}, /* uses custom pointers */
+ {"edge_percents", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_FLT}},
{"quad_corner_type", BMO_OP_SLOT_INT}, /* quad corner type, see bmesh_operators.h */
{"use_grid_fill", BMO_OP_SLOT_BOOL}, /* fill in fully-selected faces with a grid */
@@ -1322,7 +1324,7 @@ static BMOpDefine bmo_duplicate_def = {
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
/* destination bmesh, if NULL will use current on */
- {"dest", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_BMESH}},
+ {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}},
{"use_select_history", BMO_OP_SLOT_BOOL},
{{'\0'}},
},
@@ -1331,11 +1333,11 @@ static BMOpDefine bmo_duplicate_def = {
{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
/* facemap maps from source faces to dupe
* faces, and from dupe faces to source faces */
- {"vert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
- {"edge_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
- {"face_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
- {"boundary_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
- {"isovert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"vert_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"edge_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"face_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"boundary_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"isovert_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
{{'\0'}},
},
bmo_duplicate_exec,
@@ -1354,14 +1356,14 @@ static BMOpDefine bmo_split_def = {
/* slots_in */
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
/* destination bmesh, if NULL will use current one */
- {"dest", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_BMESH}},
+ {"dest", BMO_OP_SLOT_PTR, {(int)BMO_OP_SLOT_SUBTYPE_PTR_BMESH}},
{"use_only_faces", BMO_OP_SLOT_BOOL}, /* when enabled. don't duplicate loose verts/edges */
{{'\0'}},
},
/* slots_out */
{{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
- {"boundary_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
- {"isovert_map.out", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"boundary_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
+ {"isovert_map.out", BMO_OP_SLOT_MAPPING, {(int)BMO_OP_SLOT_SUBTYPE_MAP_ELEM}},
{{'\0'}},
},
bmo_split_exec,
@@ -1566,6 +1568,7 @@ static BMOpDefine bmo_create_grid_def = {
{"y_segments", BMO_OP_SLOT_INT}, /* number of y segments */
{"size", BMO_OP_SLOT_FLT}, /* size of the grid */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1589,6 +1592,7 @@ static BMOpDefine bmo_create_uvsphere_def = {
{"v_segments", BMO_OP_SLOT_INT}, /* number of v segment */
{"diameter", BMO_OP_SLOT_FLT}, /* diameter */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1611,6 +1615,7 @@ static BMOpDefine bmo_create_icosphere_def = {
{{"subdivisions", BMO_OP_SLOT_INT}, /* how many times to recursively subdivide the sphere */
{"diameter", BMO_OP_SLOT_FLT}, /* diameter */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1657,6 +1662,7 @@ static BMOpDefine bmo_create_cone_def = {
{"diameter2", BMO_OP_SLOT_FLT}, /* diameter of the opposite */
{"depth", BMO_OP_SLOT_FLT}, /* distance between ends */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1679,6 +1685,7 @@ static BMOpDefine bmo_create_circle_def = {
{"segments", BMO_OP_SLOT_INT},
{"diameter", BMO_OP_SLOT_FLT}, /* diameter of one end */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
@@ -1700,6 +1707,7 @@ static BMOpDefine bmo_create_cube_def = {
/* slots_in */
{{"size", BMO_OP_SLOT_FLT}, /* size of the cube */
{"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */
+ {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */
{{'\0'}},
},
/* slots_out */
diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
index 4f995e08b9c..00fcd9e7a9b 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h
@@ -41,38 +41,38 @@
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
- return oflags[bm->stackdepth - 1].f & oflag;
+ return oflags[bm->toolflag_index].f & oflag;
}
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2)
BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
- return (oflags[bm->stackdepth - 1].f & oflag) != 0;
+ return (oflags[bm->toolflag_index].f & oflag) != 0;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
- oflags[bm->stackdepth - 1].f |= oflag;
+ oflags[bm->toolflag_index].f |= oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
- oflags[bm->stackdepth - 1].f &= (short)~oflag;
+ oflags[bm->toolflag_index].f &= (short)~oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val)
{
- if (val) oflags[bm->stackdepth - 1].f |= oflag;
- else oflags[bm->stackdepth - 1].f &= (short)~oflag;
+ if (val) oflags[bm->toolflag_index].f |= oflag;
+ else oflags[bm->toolflag_index].f &= (short)~oflag;
}
ATTR_NONNULL(1, 2)
BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag)
{
- oflags[bm->stackdepth - 1].f ^= oflag;
+ oflags[bm->toolflag_index].f ^= oflag;
}
ATTR_NONNULL(1, 2)
@@ -82,7 +82,7 @@ BLI_INLINE void BMO_slot_map_int_insert(
{
union { void *ptr; int val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT);
- BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
+ BMO_slot_map_insert(op, slot, element, ((void)(t.val = val), t.ptr));
}
ATTR_NONNULL(1, 2)
@@ -92,7 +92,7 @@ BLI_INLINE void BMO_slot_map_bool_insert(
{
union { void *ptr; bool val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL);
- BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
+ BMO_slot_map_insert(op, slot, element, ((void)(t.val = val), t.ptr));
}
ATTR_NONNULL(1, 2)
@@ -102,7 +102,7 @@ BLI_INLINE void BMO_slot_map_float_insert(
{
union { void *ptr; float val; } t = {NULL};
BLI_assert(slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT);
- BMO_slot_map_insert(op, slot, element, ((t.val = val), t.ptr));
+ BMO_slot_map_insert(op, slot, element, ((void)(t.val = val), t.ptr));
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index e65f3e38900..960ff568e93 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -97,12 +97,12 @@ void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
*/
void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
{
- bm->stackdepth++;
+ bm->toolflag_index++;
BLI_assert(bm->totflags > 0);
/* add flag layer, if appropriate */
- if (bm->stackdepth > 1)
+ if (bm->toolflag_index > 0)
bmo_flag_layer_alloc(bm);
else
bmo_flag_layer_clear(bm);
@@ -117,10 +117,10 @@ void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
*/
void BMO_pop(BMesh *bm)
{
- if (bm->stackdepth > 1)
+ if (bm->toolflag_index > 0)
bmo_flag_layer_free(bm);
- bm->stackdepth--;
+ bm->toolflag_index--;
}
@@ -214,11 +214,11 @@ void BMO_op_exec(BMesh *bm, BMOperator *op)
BMO_push(bm, op);
- if (bm->stackdepth == 2)
+ if (bm->toolflag_index == 1)
bmesh_edit_begin(bm, op->type_flag);
op->exec(bm, op);
- if (bm->stackdepth == 2)
+ if (bm->toolflag_index == 1)
bmesh_edit_end(bm, op->type_flag);
BMO_pop(bm);
@@ -1266,8 +1266,6 @@ static void bmo_flag_layer_alloc(BMesh *bm)
BLI_mempool_destroy(foldpool);
bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
-
-
}
static void bmo_flag_layer_free(BMesh *bm)
@@ -1913,7 +1911,6 @@ error:
fprintf(stderr, " ");
{
int pos = (int)(fmt - ofmt);
- int i;
for (i = 0; i < pos; i++) {
fprintf(stderr, " ");
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index d9961e589da..0a4fb1d56a4 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -141,6 +141,14 @@ void BM_mesh_esubdivide(
const short use_only_quads,
const int seed);
+void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag);
+void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag);
+void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag);
+void BM_mesh_calc_uvs_cone(
+ BMesh *bm, float mat[4][4],
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag);
+void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag);
+
#include "intern/bmesh_operator_api_inline.h"
#endif /* __BMESH_OPERATORS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index b0eddf73960..62b29e61d08 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -38,10 +38,13 @@
#include "BLI_memarena.h"
#include "BLI_polyfill2d.h"
#include "BLI_polyfill2d_beautify.h"
+#include "BLI_linklist.h"
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "BKE_customdata.h"
+
#include "intern/bmesh_private.h"
/**
@@ -103,7 +106,7 @@ static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
* but takes an array of vertex locations.
*/
static float bm_face_calc_poly_normal_vertex_cos(
- BMFace *f, float r_no[3],
+ const BMFace *f, float r_no[3],
float const (*vertexCos)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@@ -129,15 +132,15 @@ static float bm_face_calc_poly_normal_vertex_cos(
* \brief COMPUTE POLY CENTER (BMFace)
*/
static void bm_face_calc_poly_center_mean_vertex_cos(
- BMFace *f, float r_cent[3],
+ const BMFace *f, float r_cent[3],
float const (*vertexCos)[3])
{
- BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
- BMLoop *l_iter = l_first;
+ const BMLoop *l_first, *l_iter;
zero_v3(r_cent);
/* Newell's Method */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
add_v3_v3(r_cent, vertexCos[BM_elem_index_get(l_iter->v)]);
} while ((l_iter = l_iter->next) != l_first);
@@ -147,10 +150,14 @@ static void bm_face_calc_poly_center_mean_vertex_cos(
/**
* For tools that insist on using triangles, ideally we would cache this data.
*
- * \param r_loops Store face loop pointers, (f->len)
- * \param r_index Store triangle triples, indices into \a r_loops, ((f->len - 2) * 3)
+ * \param use_fixed_quad: When true, always split quad along (0 -> 2) regardless of concave corners,
+ * (as done in #BM_mesh_calc_tessellation).
+ * \param r_loops: Store face loop pointers, (f->len)
+ * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)`
*/
-void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3])
+void BM_face_calc_tessellation(
+ const BMFace *f, const bool use_fixed_quad,
+ BMLoop **r_loops, unsigned int (*r_index)[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter;
@@ -164,7 +171,7 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (
r_index[0][1] = 1;
r_index[0][2] = 2;
}
- else if (f->len == 4) {
+ else if (f->len == 4 && use_fixed_quad) {
*r_loops++ = (l_iter = l_first);
*r_loops++ = (l_iter = l_iter->next);
*r_loops++ = (l_iter = l_iter->next);
@@ -199,11 +206,51 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (
}
/**
+ * Return a point inside the face.
+ */
+void BM_face_calc_point_in_face(const BMFace *f, float r_co[3])
+{
+ const BMLoop *l_tri[3];
+
+ if (f->len == 3) {
+ const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ ARRAY_SET_ITEMS(l_tri, l, l->next, l->prev);
+ }
+ else {
+ /* tessellation here seems overkill when in many cases this will be the center,
+ * but without this we can't be sure the point is inside a concave face. */
+ const int tottri = f->len - 2;
+ BMLoop **loops = BLI_array_alloca(loops, f->len);
+ unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
+ int j;
+ int j_best = 0; /* use as fallback when unset */
+ float area_best = -1.0f;
+
+ BM_face_calc_tessellation(f, false, loops, index);
+
+ for (j = 0; j < tottri; j++) {
+ const float *p1 = loops[index[j][0]]->v->co;
+ const float *p2 = loops[index[j][1]]->v->co;
+ const float *p3 = loops[index[j][2]]->v->co;
+ const float area = area_squared_tri_v3(p1, p2, p3);
+ if (area > area_best) {
+ j_best = j;
+ area_best = area;
+ }
+ }
+
+ ARRAY_SET_ITEMS(l_tri, loops[index[j_best][0]], loops[index[j_best][1]], loops[index[j_best][2]]);
+ }
+
+ mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co);
+}
+
+/**
* get the area of the face
*/
-float BM_face_calc_area(BMFace *f)
+float BM_face_calc_area(const BMFace *f)
{
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
float (*verts)[3] = BLI_array_alloca(verts, f->len);
float area;
unsigned int i = 0;
@@ -226,9 +273,9 @@ float BM_face_calc_area(BMFace *f)
/**
* compute the perimeter of an ngon
*/
-float BM_face_calc_perimeter(BMFace *f)
+float BM_face_calc_perimeter(const BMFace *f)
{
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
float perimeter = 0.0f;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
@@ -262,12 +309,12 @@ void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3])
* Compute a meaningful direction along the face (use for manipulator axis).
* \note result isnt normalized.
*/
-void BM_face_calc_plane(BMFace *f, float r_plane[3])
+void BM_face_calc_plane(const BMFace *f, float r_plane[3])
{
if (f->len == 3) {
BMVert *verts[3];
- BM_face_as_array_vert_tri(f, verts);
+ BM_face_as_array_vert_tri((BMFace *)f, verts);
BM_vert_tri_calc_plane(verts, r_plane);
}
@@ -276,7 +323,7 @@ void BM_face_calc_plane(BMFace *f, float r_plane[3])
float vec[3], vec_a[3], vec_b[3];
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, efa, (void **)verts, 4);
- BM_face_as_array_vert_quad(f, verts);
+ BM_face_as_array_vert_quad((BMFace *)f, verts);
sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co);
sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co);
@@ -291,7 +338,7 @@ void BM_face_calc_plane(BMFace *f, float r_plane[3])
}
}
else {
- BMLoop *l_long = BM_face_find_longest_loop(f);
+ const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f);
sub_v3_v3v3(r_plane, l_long->v->co, l_long->next->v->co);
}
@@ -302,10 +349,9 @@ void BM_face_calc_plane(BMFace *f, float r_plane[3])
/**
* computes center of face in 3d. uses center of bounding box.
*/
-void BM_face_calc_center_bounds(BMFace *f, float r_cent[3])
+void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
{
- BMLoop *l_iter;
- BMLoop *l_first;
+ const BMLoop *l_iter, *l_first;
float min[3], max[3];
INIT_MINMAX(min, max);
@@ -321,9 +367,9 @@ void BM_face_calc_center_bounds(BMFace *f, float r_cent[3])
/**
* computes the center of a face, using the mean average
*/
-void BM_face_calc_center_mean(BMFace *f, float r_cent[3])
+void BM_face_calc_center_mean(const BMFace *f, float r_cent[3])
{
- BMLoop *l_iter, *l_first;
+ const BMLoop *l_iter, *l_first;
zero_v3(r_cent);
@@ -338,10 +384,10 @@ void BM_face_calc_center_mean(BMFace *f, float r_cent[3])
* computes the center of a face, using the mean average
* weighted by edge length
*/
-void BM_face_calc_center_mean_weighted(BMFace *f, float r_cent[3])
+void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3])
{
- BMLoop *l_iter;
- BMLoop *l_first;
+ const BMLoop *l_iter;
+ const BMLoop *l_first;
float totw = 0.0f;
float w_prev;
@@ -422,32 +468,42 @@ void BM_edge_normals_update(BMEdge *e)
BM_vert_normal_update(e->v2);
}
-bool BM_vert_normal_update_ex(BMVert *v, const char hflag, float r_no[3])
+static void bm_loop_normal_accum(const BMLoop *l, float no[3])
{
- /* TODO, we can normalize each edge only once, then compare with previous edge */
-
- BMIter liter;
- BMLoop *l;
- int len = 0;
+ float vec1[3], vec2[3], fac;
- zero_v3(r_no);
+ /* Same calculation used in BM_mesh_normals_update */
+ sub_v3_v3v3(vec1, l->v->co, l->prev->v->co);
+ sub_v3_v3v3(vec2, l->next->v->co, l->v->co);
+ normalize_v3(vec1);
+ normalize_v3(vec2);
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- if (BM_elem_flag_test(l->f, hflag)) {
- float vec1[3], vec2[3], fac;
+ fac = saacos(-dot_v3v3(vec1, vec2));
- /* Same calculation used in BM_mesh_normals_update */
- sub_v3_v3v3(vec1, l->v->co, l->prev->v->co);
- sub_v3_v3v3(vec2, l->next->v->co, l->v->co);
- normalize_v3(vec1);
- normalize_v3(vec2);
+ madd_v3_v3fl(no, l->f->no, fac);
+}
- fac = saacos(-dot_v3v3(vec1, vec2));
+bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3])
+{
+ int len = 0;
- madd_v3_v3fl(r_no, l->f->no, fac);
+ zero_v3(r_no);
- len++;
- }
+ if (v->e) {
+ const BMEdge *e = v->e;
+ do {
+ if (e->l) {
+ const BMLoop *l = e->l;
+ do {
+ if (l->v == v) {
+ if (BM_elem_flag_test(l->f, hflag)) {
+ bm_loop_normal_accum(l, r_no);
+ len++;
+ }
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
}
if (len) {
@@ -459,33 +515,56 @@ bool BM_vert_normal_update_ex(BMVert *v, const char hflag, float r_no[3])
}
}
-/**
- * update a vert normal (but not the faces incident on it)
- */
-void BM_vert_normal_update(BMVert *v)
+bool BM_vert_calc_normal(const BMVert *v, float r_no[3])
{
- /* TODO, we can normalize each edge only once, then compare with previous edge */
-
- BMIter liter;
- BMLoop *l;
int len = 0;
- zero_v3(v->no);
+ zero_v3(r_no);
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- float vec1[3], vec2[3], fac;
+ if (v->e) {
+ const BMEdge *e = v->e;
+ do {
+ if (e->l) {
+ const BMLoop *l = e->l;
+ do {
+ if (l->v == v) {
+ bm_loop_normal_accum(l, r_no);
+ len++;
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
+ }
- /* Same calculation used in BM_mesh_normals_update */
- sub_v3_v3v3(vec1, l->v->co, l->prev->v->co);
- sub_v3_v3v3(vec2, l->next->v->co, l->v->co);
- normalize_v3(vec1);
- normalize_v3(vec2);
+ if (len) {
+ normalize_v3(r_no);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- fac = saacos(-dot_v3v3(vec1, vec2));
+void BM_vert_normal_update_all(BMVert *v)
+{
+ int len = 0;
- madd_v3_v3fl(v->no, l->f->no, fac);
+ zero_v3(v->no);
- len++;
+ if (v->e) {
+ const BMEdge *e = v->e;
+ do {
+ if (e->l) {
+ const BMLoop *l = e->l;
+ do {
+ if (l->v == v) {
+ BM_face_normal_update(l->f);
+ bm_loop_normal_accum(l, v->no);
+ len++;
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ } while ((e = bmesh_disk_edge_next(e, v)) != v->e);
}
if (len) {
@@ -493,16 +572,12 @@ void BM_vert_normal_update(BMVert *v)
}
}
-void BM_vert_normal_update_all(BMVert *v)
+/**
+ * update a vert normal (but not the faces incident on it)
+ */
+void BM_vert_normal_update(BMVert *v)
{
- BMIter iter;
- BMFace *f;
-
- BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- BM_face_normal_update(f);
- }
-
- BM_vert_normal_update(v);
+ BM_vert_calc_normal(v, v->no);
}
/**
@@ -551,7 +626,7 @@ void BM_face_normal_update(BMFace *f)
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
float BM_face_calc_normal_vcos(
- BMesh *bm, BMFace *f, float r_no[3],
+ const BMesh *bm, const BMFace *f, float r_no[3],
float const (*vertexCos)[3])
{
BMLoop *l;
@@ -589,13 +664,13 @@ float BM_face_calc_normal_vcos(
/**
* Calculates the face subset normal.
*/
-float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3])
+float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3])
{
const float *v_prev, *v_curr;
/* Newell's Method */
- BMLoop *l_iter = l_first;
- BMLoop *l_term = l_last->next;
+ const BMLoop *l_iter = l_first;
+ const BMLoop *l_term = l_last->next;
zero_v3(r_no);
@@ -611,7 +686,7 @@ float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3])
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
void BM_face_calc_center_mean_vcos(
- BMesh *bm, BMFace *f, float r_cent[3],
+ const BMesh *bm, const BMFace *f, float r_cent[3],
float const (*vertexCos)[3])
{
/* must have valid index data */
@@ -627,12 +702,20 @@ void BM_face_calc_center_mean_vcos(
* Reverses the winding of a face.
* \note This updates the calculated normal.
*/
-void BM_face_normal_flip(BMesh *bm, BMFace *f)
+void BM_face_normal_flip_ex(
+ BMesh *bm, BMFace *f,
+ const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip)
{
- bmesh_loop_reverse(bm, f);
+ bmesh_loop_reverse(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
negate_v3(f->no);
}
+void BM_face_normal_flip(BMesh *bm, BMFace *f)
+{
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
+}
+
/* detects if two line segments cross each other (intersects).
* note, there could be more winding cases then there needs to be. */
static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
@@ -704,7 +787,7 @@ static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v
* instead of projecting co directly into f's orientation space,
* so there might be accuracy issues.
*/
-bool BM_face_point_inside_test(BMFace *f, const float co[3])
+bool BM_face_point_inside_test(const BMFace *f, const float co[3])
{
float axis_mat[3][3];
float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
@@ -713,8 +796,7 @@ bool BM_face_point_inside_test(BMFace *f, const float co[3])
BMLoop *l_iter;
int i;
- if (is_zero_v3(f->no))
- BM_face_normal_update(f);
+ BLI_assert(BM_face_is_normal_valid(f));
axis_dominant_v3_to_m3(axis_mat, f->no);
@@ -738,6 +820,12 @@ bool BM_face_point_inside_test(BMFace *f, const float co[3])
* with a length equal to (f->len - 3). It will be filled with the new
* triangles (not including the original triangle).
*
+ * \param r_faces_double: When newly created faces are duplicates of existing faces, they're added to this list.
+ * Caller must handle de-duplication.
+ * This is done because its possible _all_ faces exist already,
+ * and in that case we would have to remove all faces including the one passed,
+ * which causes complications adding/removing faces while looking over them.
+ *
* \note The number of faces is _almost_ always (f->len - 3),
* However there may be faces that already occupying the
* triangles we would make, so the caller must check \a r_faces_new_tot.
@@ -750,6 +838,7 @@ void BM_face_triangulate(
int *r_faces_new_tot,
BMEdge **r_edges_new,
int *r_edges_new_tot,
+ LinkNode **r_faces_double,
const int quad_method,
const int ngon_method,
const bool use_tag,
@@ -758,125 +847,132 @@ void BM_face_triangulate(
/* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
struct Heap *pf_heap, struct EdgeHash *pf_ehash)
{
- BMLoop *l_iter, *l_first, *l_new;
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ const bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY);
+ BMLoop *l_first, *l_new;
BMFace *f_new;
int nf_i = 0;
int ne_i = 0;
- bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY);
BLI_assert(BM_face_is_normal_valid(f));
/* ensure both are valid or NULL */
BLI_assert((r_faces_new == NULL) == (r_faces_new_tot == NULL));
- if (f->len == 4) {
- BMLoop *l_v1, *l_v2;
- l_first = BM_FACE_FIRST_LOOP(f);
+ BLI_assert(f->len > 3);
- switch (quad_method) {
- case MOD_TRIANGULATE_QUAD_FIXED:
- {
- l_v1 = l_first;
- l_v2 = l_first->next->next;
- break;
- }
- case MOD_TRIANGULATE_QUAD_ALTERNATE:
- {
- l_v1 = l_first->next;
- l_v2 = l_first->prev;
- break;
- }
- case MOD_TRIANGULATE_QUAD_SHORTEDGE:
- case MOD_TRIANGULATE_QUAD_BEAUTY:
- default:
- {
- BMLoop *l_v3, *l_v4;
- bool split_24;
-
- l_v1 = l_first->next;
- l_v2 = l_first->next->next;
- l_v3 = l_first->prev;
- l_v4 = l_first;
-
- if (quad_method == MOD_TRIANGULATE_QUAD_SHORTEDGE) {
- float d1, d2;
- d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
- d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
- split_24 = ((d2 - d1) > 0.0f);
+ {
+ BMLoop **loops = BLI_array_alloca(loops, f->len);
+ unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len);
+ const int totfilltri = f->len - 2;
+ const int last_tri = f->len - 3;
+ int i;
+ /* for mdisps */
+ float f_center[3];
+
+ if (f->len == 4) {
+ /* even though we're not using BLI_polyfill, fill in 'tris' and 'loops'
+ * so we can share code to handle face creation afterwards. */
+ BMLoop *l_v1, *l_v2;
+
+ l_first = BM_FACE_FIRST_LOOP(f);
+
+ switch (quad_method) {
+ case MOD_TRIANGULATE_QUAD_FIXED:
+ {
+ l_v1 = l_first;
+ l_v2 = l_first->next->next;
+ break;
}
- else {
- /* first check if the quad is concave on either diagonal */
- const int flip_flag = is_quad_flip_v3(l_v1->v->co, l_v2->v->co, l_v3->v->co, l_v4->v->co);
- if (UNLIKELY(flip_flag & (1 << 0))) {
- split_24 = true;
- }
- else if (UNLIKELY(flip_flag & (1 << 1))) {
- split_24 = false;
+ case MOD_TRIANGULATE_QUAD_ALTERNATE:
+ {
+ l_v1 = l_first->next;
+ l_v2 = l_first->prev;
+ break;
+ }
+ case MOD_TRIANGULATE_QUAD_SHORTEDGE:
+ case MOD_TRIANGULATE_QUAD_BEAUTY:
+ default:
+ {
+ BMLoop *l_v3, *l_v4;
+ bool split_24;
+
+ l_v1 = l_first->next;
+ l_v2 = l_first->next->next;
+ l_v3 = l_first->prev;
+ l_v4 = l_first;
+
+ if (quad_method == MOD_TRIANGULATE_QUAD_SHORTEDGE) {
+ float d1, d2;
+ d1 = len_squared_v3v3(l_v4->v->co, l_v2->v->co);
+ d2 = len_squared_v3v3(l_v1->v->co, l_v3->v->co);
+ split_24 = ((d2 - d1) > 0.0f);
}
else {
- split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) > 0.0f);
+ /* first check if the quad is concave on either diagonal */
+ const int flip_flag = is_quad_flip_v3(l_v1->v->co, l_v2->v->co, l_v3->v->co, l_v4->v->co);
+ if (UNLIKELY(flip_flag & (1 << 0))) {
+ split_24 = true;
+ }
+ else if (UNLIKELY(flip_flag & (1 << 1))) {
+ split_24 = false;
+ }
+ else {
+ split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) > 0.0f);
+ }
}
- }
- /* named confusingly, l_v1 is in fact the second vertex */
- if (split_24) {
- l_v1 = l_v4;
- //l_v2 = l_v2;
- }
- else {
- //l_v1 = l_v1;
- l_v2 = l_v3;
+ /* named confusingly, l_v1 is in fact the second vertex */
+ if (split_24) {
+ l_v1 = l_v4;
+ //l_v2 = l_v2;
+ }
+ else {
+ //l_v1 = l_v1;
+ l_v2 = l_v3;
+ }
+ break;
}
- break;
}
- }
-
- f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true);
- copy_v3_v3(f_new->no, f->no);
- if (use_tag) {
- BM_elem_flag_enable(l_new->e, BM_ELEM_TAG);
- BM_elem_flag_enable(f_new, BM_ELEM_TAG);
- }
+ loops[0] = l_v1;
+ loops[1] = l_v1->next;
+ loops[2] = l_v2;
+ loops[3] = l_v2->next;
- if (r_faces_new) {
- r_faces_new[nf_i++] = f_new;
- }
- if (r_edges_new) {
- r_edges_new[ne_i++] = l_new->e;
+ ARRAY_SET_ITEMS(tris[0], 0, 1, 2);
+ ARRAY_SET_ITEMS(tris[1], 0, 2, 3);
}
- }
- else if (f->len > 4) {
+ else {
+ BMLoop *l_iter;
+ float axis_mat[3][3];
+ float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
- float axis_mat[3][3];
- float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
- BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*tris)[3] = BLI_array_alloca(tris, f->len);
- const int totfilltri = f->len - 2;
- const int last_tri = f->len - 3;
- int i;
+ axis_dominant_v3_to_m3_negate(axis_mat, f->no);
- axis_dominant_v3_to_m3_negate(axis_mat, f->no);
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) {
+ loops[i] = l_iter;
+ mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
+ }
- for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) {
- loops[i] = l_iter;
- mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
- }
+ BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, 1, tris,
+ pf_arena);
- BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, 1, tris,
- pf_arena);
+ if (use_beauty) {
+ BLI_polyfill_beautify(
+ (const float (*)[2])projverts, f->len, tris,
+ pf_arena, pf_heap, pf_ehash);
+ }
- if (use_beauty) {
- BLI_polyfill_beautify(
- (const float (*)[2])projverts, f->len, tris,
- pf_arena, pf_heap, pf_ehash);
+ BLI_memarena_clear(pf_arena);
}
- BLI_memarena_clear(pf_arena);
+ if (cd_loop_mdisp_offset != -1) {
+ BM_face_calc_center_mean(f, f_center);
+ }
/* loop over calculated triangles and create new geometry */
for (i = 0; i < totfilltri; i++) {
- /* the order is reverse, otherwise the normal is flipped */
BMLoop *l_tri[3] = {
loops[tris[i][0]],
loops[tris[i][1]],
@@ -892,6 +988,18 @@ void BM_face_triangulate(
BLI_assert(v_tri[0] == l_new->v);
+ /* check for duplicate */
+ if (l_new->radial_next != l_new) {
+ BMLoop *l_iter = l_new->radial_next;
+ do {
+ if (UNLIKELY((l_iter->f->len == 3) && (l_new->prev->v == l_iter->prev->v))) {
+ /* Check the last tri because we swap last f_new with f at the end... */
+ BLI_linklist_prepend(r_faces_double, (i != last_tri) ? f_new : f);
+ break;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_new);
+ }
+
/* copy CD data */
BM_elem_attrs_copy(bm, bm, l_tri[0], l_new);
BM_elem_attrs_copy(bm, bm, l_tri[1], l_new->next);
@@ -909,6 +1017,8 @@ void BM_face_triangulate(
if (use_tag || r_edges_new) {
/* new faces loops */
+ BMLoop *l_iter;
+
l_iter = l_first = l_new;
do {
BMEdge *e = l_iter->e;
@@ -927,6 +1037,12 @@ void BM_face_triangulate(
/* note, never disable tag's */
} while ((l_iter = l_iter->next) != l_first);
}
+
+ if (cd_loop_mdisp_offset != -1) {
+ float f_new_center[3];
+ BM_face_calc_center_mean(f_new, f_new_center);
+ BM_face_interp_multires_ex(bm, f_new, f, f_new_center, f_center, cd_loop_mdisp_offset);
+ }
}
{
@@ -1159,12 +1275,12 @@ void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4])
/**
- * \brief BM_bmesh_calc_tessellation get the looptris and its number from a certain bmesh
+ * \brief BM_mesh_calc_tessellation get the looptris and its number from a certain bmesh
* \param looptris
*
* \note \a looptris Must be pre-allocated to at least the size of given by: poly_to_tri_count
*/
-void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot)
+void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot)
{
/* use this to avoid locking pthread for _every_ polygon
* and calling the fill function */
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index 582b4248c7d..8f0df81af73 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -32,34 +32,41 @@ struct Heap;
#include "BLI_compiler_attrs.h"
-void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
+void BM_mesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
-void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]);
+void BM_face_calc_tessellation(
+ const BMFace *f, const bool use_fixed_quad,
+ BMLoop **r_loops, unsigned int (*r_index)[3]);
+void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]);
float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
float BM_face_calc_normal_vcos(
- BMesh *bm, BMFace *f, float r_no[3],
+ const BMesh *bm, const BMFace *f, float r_no[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
-float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
-float BM_face_calc_area(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_face_calc_perimeter(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void BM_face_calc_plane(BMFace *f, float r_plane[3]) ATTR_NONNULL();
-void BM_face_calc_center_bounds(BMFace *f, float center[3]) ATTR_NONNULL();
-void BM_face_calc_center_mean(BMFace *f, float center[3]) ATTR_NONNULL();
+float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3]) ATTR_NONNULL();
+float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+void BM_face_calc_plane(const BMFace *f, float r_plane[3]) ATTR_NONNULL();
+void BM_face_calc_center_bounds(const BMFace *f, float center[3]) ATTR_NONNULL();
+void BM_face_calc_center_mean(const BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_calc_center_mean_vcos(
- BMesh *bm, BMFace *f, float r_cent[3],
+ const BMesh *bm, const BMFace *f, float r_cent[3],
float const (*vertexCos)[3]) ATTR_NONNULL();
-void BM_face_calc_center_mean_weighted(BMFace *f, float center[3]) ATTR_NONNULL();
+void BM_face_calc_center_mean_weighted(const BMFace *f, float center[3]) ATTR_NONNULL();
void BM_face_normal_update(BMFace *f) ATTR_NONNULL();
void BM_edge_normals_update(BMEdge *e) ATTR_NONNULL();
-bool BM_vert_normal_update_ex(BMVert *v, const char hflag, float r_no[3]);
+bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3]);
+bool BM_vert_calc_normal(const BMVert *v, float r_no[3]);
void BM_vert_normal_update(BMVert *v) ATTR_NONNULL();
void BM_vert_normal_update_all(BMVert *v) ATTR_NONNULL();
+void BM_face_normal_flip_ex(
+ BMesh *bm, BMFace *f,
+ const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) ATTR_NONNULL();
void BM_face_normal_flip(BMesh *bm, BMFace *f) ATTR_NONNULL();
-bool BM_face_point_inside_test(BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_point_inside_test(const BMFace *f, const float co[3]) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BM_face_triangulate(
BMesh *bm, BMFace *f,
@@ -67,6 +74,7 @@ void BM_face_triangulate(
int *r_faces_new_tot,
BMEdge **r_edges_new,
int *r_edges_new_tot,
+ struct LinkNode **r_faces_double,
const int quad_method, const int ngon_method,
const bool use_tag,
struct MemArena *pf_arena,
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
new file mode 100644
index 00000000000..c224a1ad587
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c
@@ -0,0 +1,1543 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/intern/bmesh_polygon_edgenet.c
+ * \ingroup bmesh
+ *
+ * This file contains functions for splitting faces into isolated regions,
+ * defined by connected edges.
+ */
+// #define DEBUG_PRINT
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_array.h"
+#include "BLI_alloca.h"
+#include "BLI_stackdefines.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_sort.h"
+#include "BLI_sort_utils.h"
+#include "BLI_kdopbvh.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+#include "intern/bmesh_private.h"
+
+/* -------------------------------------------------------------------- */
+/* Face Split Edge-Net */
+
+/** \name BM_face_split_edgenet and helper functions.
+ *
+ * \note Don't use #BM_edge_is_wire or #BM_edge_is_boundary
+ * since we need to take flagged faces into account.
+ * Also take care accessing e->l directly.
+ *
+ * \{ */
+
+/* Note: All these flags _must_ be cleared on exit */
+
+/* face is apart of the edge-net (including the original face we're splitting) */
+#define FACE_NET _FLAG_WALK
+/* edge is apart of the edge-net we're filling */
+#define EDGE_NET _FLAG_WALK
+/* tag verts we've visit */
+#define VERT_VISIT _FLAG_WALK
+
+struct VertOrder {
+ float angle;
+ BMVert *v;
+};
+
+static unsigned int bm_edge_flagged_radial_count(BMEdge *e)
+{
+ unsigned int count = 0;
+ BMLoop *l;
+
+ if ((l = e->l)) {
+ do {
+ if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) {
+ count++;
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ return count;
+}
+
+static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
+{
+ BMLoop *l;
+
+ if ((l = e->l)) {
+ do {
+ if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) {
+ return l;
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ return NULL;
+}
+
+static bool bm_face_split_edgenet_find_loop_pair(
+ BMVert *v_init, const float face_normal[3],
+ BMEdge *e_pair[2])
+{
+ /* Always find one boundary edge (to determine winding)
+ * and one wire (if available), otherwise another boundary.
+ */
+ BMIter iter;
+ BMEdge *e;
+
+ /* detect winding */
+ BMLoop *l_walk;
+ bool swap;
+
+ BLI_SMALLSTACK_DECLARE(edges_boundary, BMEdge *);
+ BLI_SMALLSTACK_DECLARE(edges_wire, BMEdge *);
+ int edges_boundary_len = 0;
+ int edges_wire_len = 0;
+
+ BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) {
+ if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
+ const unsigned int count = bm_edge_flagged_radial_count(e);
+ if (count == 1) {
+ BLI_SMALLSTACK_PUSH(edges_boundary, e);
+ edges_boundary_len++;
+ }
+ else if (count == 0) {
+ BLI_SMALLSTACK_PUSH(edges_wire, e);
+ edges_wire_len++;
+ }
+ }
+ }
+
+ /* first edge should always be boundary */
+ if (edges_boundary_len == 0) {
+ return false;
+ }
+ e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
+
+ /* attempt one boundary and one wire, or 2 boundary */
+ if (edges_wire_len == 0) {
+ if (edges_boundary_len >= 2) {
+ e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
+ }
+ else {
+ /* one boundary and no wire */
+ return false;
+ }
+ }
+ else {
+ e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
+
+ if (edges_wire_len > 1) {
+ BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
+ BMVert *v_next;
+ float angle_best;
+
+ v_next = BM_edge_other_vert(e_pair[1], v_init);
+ angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
+
+ while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
+ float angle_test;
+ v_next = BM_edge_other_vert(e, v_init);
+ angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
+ if (angle_test < angle_best) {
+ angle_best = angle_test;
+ e_pair[1] = e;
+ }
+ }
+ }
+ }
+
+
+ /* flip based on winding */
+ l_walk = bm_edge_flagged_radial_first(e_pair[0]);
+ swap = false;
+ if (face_normal == l_walk->f->no) {
+ swap = !swap;
+ }
+ if (l_walk->v != v_init) {
+ swap = !swap;
+ }
+ if (swap) {
+ SWAP(BMEdge *, e_pair[0], e_pair[1]);
+ }
+
+ return true;
+}
+
+static bool bm_face_split_edgenet_find_loop_walk(
+ BMVert *v_init, const float face_normal[3],
+ /* cache to avoid realloc every time */
+ struct VertOrder *edge_order, const unsigned int edge_order_len,
+ BMEdge *e_pair[2])
+{
+ /* fast-path for the common case (avoid push-pop).
+ * Also avoids tagging as visited since we know we
+ * can't reach these verts some other way */
+#define USE_FASTPATH_NOFORK
+
+ BMVert *v;
+ BMVert *v_dst;
+ bool found = false;
+
+ struct VertOrder *eo;
+ STACK_DECLARE(edge_order);
+
+ /* store visited verts so we can clear the visit flag after execution */
+ BLI_SMALLSTACK_DECLARE(vert_visit, BMVert *);
+
+ /* likely this will stay very small
+ * all verts pushed into this stack _must_ have their previous edges set! */
+ BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *);
+ BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *);
+
+ STACK_INIT(edge_order, edge_order_len);
+
+ /* start stepping */
+ v = BM_edge_other_vert(e_pair[0], v_init);
+ v->e = e_pair[0];
+ BLI_SMALLSTACK_PUSH(vert_stack, v);
+
+ v_dst = BM_edge_other_vert(e_pair[1], v_init);
+
+#ifdef DEBUG_PRINT
+ printf("%s: vert (search) %d\n", __func__, BM_elem_index_get(v_init));
+#endif
+
+ /* This loop will keep stepping over the best possible edge,
+ * in most cases it finds the direct route to close the face.
+ *
+ * In cases where paths can't be closed,
+ * alternatives are stored in the 'vert_stack'.
+ */
+ while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
+ BMIter eiter;
+ BMEdge *e_next;
+
+#ifdef USE_FASTPATH_NOFORK
+walk_nofork:
+#else
+ BLI_SMALLSTACK_PUSH(vert_visit, v);
+ BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
+#endif
+
+ BLI_assert(STACK_SIZE(edge_order) == 0);
+
+ /* check if we're done! */
+ if (v == v_dst) {
+ found = true;
+ goto finally;
+ }
+
+ BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
+ if ((v->e != e_next) &&
+ (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
+ (bm_edge_flagged_radial_count(e_next) < 2))
+ {
+ BMVert *v_next;
+
+ v_next = BM_edge_other_vert(e_next, v);
+
+#ifdef DEBUG_PRINT
+ /* indent and print */
+ {
+ BMVert *_v = v;
+ do {
+ printf(" ");
+ } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
+ printf("vert %d -> %d (add=%d)\n",
+ BM_elem_index_get(v), BM_elem_index_get(v_next),
+ BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
+ }
+#endif
+
+ if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
+ eo = STACK_PUSH_RET_PTR(edge_order);
+ eo->v = v_next;
+
+ v_next->e = e_next;
+ }
+ }
+ }
+
+#ifdef USE_FASTPATH_NOFORK
+ if (STACK_SIZE(edge_order) == 1) {
+ eo = STACK_POP_PTR(edge_order);
+ v = eo->v;
+
+ goto walk_nofork;
+ }
+#endif
+
+ /* sort by angle if needed */
+ if (STACK_SIZE(edge_order) > 1) {
+ unsigned int j;
+ BMVert *v_prev = BM_edge_other_vert(v->e, v);
+
+ for (j = 0; j < STACK_SIZE(edge_order); j++) {
+ edge_order[j].angle = angle_signed_on_axis_v3v3v3_v3(v_prev->co, v->co, edge_order[j].v->co, face_normal);
+ }
+ qsort(edge_order, STACK_SIZE(edge_order), sizeof(struct VertOrder), BLI_sortutil_cmp_float_reverse);
+
+#ifdef USE_FASTPATH_NOFORK
+ /* only tag forks */
+ BLI_SMALLSTACK_PUSH(vert_visit, v);
+ BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
+#endif
+ }
+
+ while ((eo = STACK_POP_PTR(edge_order))) {
+ BLI_SMALLSTACK_PUSH(vert_stack_next, eo->v);
+ }
+
+ if (!BLI_SMALLSTACK_IS_EMPTY(vert_stack_next)) {
+ BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next);
+ }
+ }
+
+
+finally:
+ /* clear flag for next execution */
+ while ((v = BLI_SMALLSTACK_POP(vert_visit))) {
+ BM_ELEM_API_FLAG_DISABLE(v, VERT_VISIT);
+ }
+
+ return found;
+
+#undef USE_FASTPATH_NOFORK
+}
+
+static bool bm_face_split_edgenet_find_loop(
+ BMVert *v_init, const float face_normal[3],
+ /* cache to avoid realloc every time */
+ struct VertOrder *edge_order, const unsigned int edge_order_len,
+ BMVert **r_face_verts, int *r_face_verts_len)
+{
+ BMEdge *e_pair[2];
+ BMVert *v;
+
+ if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
+ return false;
+ }
+
+ BLI_assert((bm_edge_flagged_radial_count(e_pair[0]) == 1) ||
+ (bm_edge_flagged_radial_count(e_pair[1]) == 1));
+
+ if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) {
+ unsigned int i = 0;
+
+ r_face_verts[i++] = v_init;
+ v = BM_edge_other_vert(e_pair[1], v_init);
+ do {
+ r_face_verts[i++] = v;
+ } while ((v = BM_edge_other_vert(v->e, v)) != v_init);
+ *r_face_verts_len = i;
+ return (i > 2) ? true : false;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * Splits a face into many smaller faces defined by an edge-net.
+ * handle customdata and degenerate cases.
+ *
+ * - isolated holes or unsupported face configurations, will be ignored.
+ * - customdata calculations aren't efficient
+ * (need to calculate weights for each vert).
+ */
+bool BM_face_split_edgenet(
+ BMesh *bm,
+ BMFace *f, BMEdge **edge_net, const int edge_net_len,
+ BMFace ***r_face_arr, int *r_face_arr_len)
+{
+ /* re-use for new face verts */
+ BMVert **face_verts;
+ int face_verts_len;
+
+ BMFace **face_arr = NULL;
+ BLI_array_declare(face_arr);
+
+ BMVert **vert_queue;
+ STACK_DECLARE(vert_queue);
+ int i;
+
+ struct VertOrder *edge_order;
+ const unsigned int edge_order_len = edge_net_len + 2;
+
+ BMVert *v;
+
+ BMLoop *l_iter, *l_first;
+
+
+ if (!edge_net_len) {
+ if (r_face_arr) {
+ *r_face_arr = NULL;
+ *r_face_arr_len = 0;
+ }
+ return false;
+ }
+
+ /* over-alloc (probably 2-4 is only used in most cases), for the biggest-fan */
+ edge_order = BLI_array_alloca(edge_order, edge_order_len);
+
+ /* use later */
+ face_verts = BLI_array_alloca(face_verts, edge_net_len + f->len);
+
+ vert_queue = BLI_array_alloca(vert_queue, edge_net_len + f->len);
+ STACK_INIT(vert_queue, f->len + edge_net_len);
+
+ BLI_assert(BM_ELEM_API_FLAG_TEST(f, FACE_NET) == 0);
+ BM_ELEM_API_FLAG_ENABLE(f, FACE_NET);
+
+#ifdef DEBUG
+ for (i = 0; i < edge_net_len; i++) {
+ BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET) == 0);
+ BLI_assert(BM_edge_in_face(edge_net[i], f) == false);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter->e, EDGE_NET) == 0);
+ } while ((l_iter = l_iter->next) != l_first);
+#endif
+
+
+ for (i = 0; i < edge_net_len; i++) {
+ BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
+ } while ((l_iter = l_iter->next) != l_first);
+
+
+ /* any vert can be used to begin with */
+ STACK_PUSH(vert_queue, l_first->v);
+
+ while ((v = STACK_POP(vert_queue))) {
+ if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
+ BMFace *f_new;
+
+ f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
+
+ for (i = 0; i < edge_net_len; i++) {
+ BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET));
+ }
+
+ if (f_new) {
+ bool l_prev_is_boundary;
+ BLI_array_append(face_arr, f_new);
+ copy_v3_v3(f_new->no, f->no);
+
+ /* warning, normally don't do this,
+ * its needed for mesh intersection - which tracks face-sides based on selection */
+ f_new->head.hflag = f->head.hflag;
+ if (f->head.hflag & BM_ELEM_SELECT) {
+ bm->totfacesel++;
+ }
+
+ BM_ELEM_API_FLAG_ENABLE(f_new, FACE_NET);
+
+ /* add new verts to keep finding loops for
+ * (verts between boundary and manifold edges) */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
+ l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1);
+ do {
+ bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1);
+ if (l_prev_is_boundary != l_iter_is_boundary) {
+ STACK_PUSH(vert_queue, l_iter->v);
+ }
+ l_prev_is_boundary = l_iter_is_boundary;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+ }
+
+
+ if (CustomData_has_math(&bm->ldata)) {
+ /* reuse VERT_VISIT here to tag vert's already interpolated */
+ BMIter iter;
+ BMLoop *l_other;
+
+ /* see: #BM_loop_interp_from_face for similar logic */
+ void **blocks = BLI_array_alloca(blocks, f->len);
+ float (*cos_2d)[2] = BLI_array_alloca(cos_2d, f->len);
+ float *w = BLI_array_alloca(w, f->len);
+ float axis_mat[3][3];
+ float co[2];
+
+ /* interior loops */
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+
+
+ /* first simply copy from existing face */
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ITER_ELEM (l_other, &iter, l_iter->v, BM_LOOPS_OF_VERT) {
+ if ((l_other->f != f) && BM_ELEM_API_FLAG_TEST(l_other->f, FACE_NET)) {
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata,
+ l_iter->head.data, &l_other->head.data);
+ }
+ }
+ /* tag not to interpolate */
+ BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_VISIT);
+
+
+ mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
+ blocks[i] = l_iter->head.data;
+
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
+
+
+ for (i = 0; i < edge_net_len; i++) {
+ BM_ITER_ELEM (v, &iter, edge_net[i], BM_VERTS_OF_EDGE) {
+ if (!BM_ELEM_API_FLAG_TEST(v, VERT_VISIT)) {
+ BMIter liter;
+
+ BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
+
+ /* interpolate this loop, then copy to the rest */
+ l_first = NULL;
+
+ BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BM_ELEM_API_FLAG_TEST(l_iter->f, FACE_NET)) {
+ if (l_first == NULL) {
+ mul_v2_m3v3(co, axis_mat, v->co);
+ interp_weights_poly_v2(w, cos_2d, f->len, co);
+ CustomData_bmesh_interp(
+ &bm->ldata, (const void **)blocks,
+ w, NULL, f->len, l_iter->head.data);
+ l_first = l_iter;
+ }
+ else {
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata,
+ l_first->head.data, &l_iter->head.data);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ /* cleanup */
+ for (i = 0; i < edge_net_len; i++) {
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i], EDGE_NET);
+ /* from interp only */
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_VISIT);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ELEM_API_FLAG_DISABLE(l_iter->e, EDGE_NET);
+ /* from interp only */
+ BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (BLI_array_count(face_arr)) {
+ bmesh_face_swap_data(f, face_arr[0]);
+ BM_face_kill(bm, face_arr[0]);
+ face_arr[0] = f;
+ }
+ else {
+ BM_ELEM_API_FLAG_DISABLE(f, FACE_NET);
+ }
+
+ for (i = 0; i < BLI_array_count(face_arr); i++) {
+ BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET);
+ }
+
+ if (r_face_arr) {
+ *r_face_arr = face_arr;
+ *r_face_arr_len = BLI_array_count(face_arr);
+ }
+ else {
+ if (face_arr) {
+ MEM_freeN(face_arr);
+ }
+ }
+
+ return true;
+}
+
+#undef FACE_NET
+#undef VERT_VISIT
+#undef EDGE_NET
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Face Split Edge-Net Connect Islands */
+
+/** \name BM_face_split_edgenet_connect_islands and helper functions.
+ *
+ * Connect isolated mesh 'islands' so they form legal regions from which we can create faces.
+ *
+ * Intended to be used as a pre-processing step for #BM_face_split_edgenet.
+ *
+ * \warning Currently this risks running out of stack memory (#alloca),
+ * likely we'll pass in a memory arena (cleared each use) eventually.
+ *
+ * \{ */
+
+
+#define USE_PARTIAL_CONNECT
+
+
+#define VERT_IS_VALID BM_ELEM_INTERNAL_TAG
+
+/* can be X or Y */
+#define SORT_AXIS 0
+
+BLI_INLINE bool edge_isect_verts_point_2d(
+ const BMEdge *e, const BMVert *v_a, const BMVert *v_b,
+ float r_isect[2])
+{
+ return ((isect_seg_seg_v2_point(v_a->co, v_b->co, e->v1->co, e->v2->co, r_isect) == 1) &&
+ ((e->v1 != v_a) && (e->v2 != v_a) && (e->v1 != v_b) && (e->v2 != v_b)));
+}
+
+/**
+ * Represents isolated edge-links,
+ * each island owns contiguous slices of the vert array.
+ * (edges remain in `edge_links`).
+ */
+struct EdgeGroupIsland {
+ LinkNode edge_links; /* keep first */
+ unsigned int vert_len, edge_len;
+
+ /* Set the following vars once we have >1 groups */
+
+ /* when when an edge in a previous group connects to this one,
+ * so theres no need to create one pointing back. */
+ unsigned int has_prev_edge : 1;
+
+ /* verts in the group which has the lowest & highest values,
+ * the lower vertex is connected to the first edge */
+ struct {
+ BMVert *min, *max;
+ /* used for sorting only */
+ float min_axis;
+ } vert_span;
+};
+
+static int group_min_cmp_fn(const void *p1, const void *p2)
+{
+ const struct EdgeGroupIsland *g1 = *(struct EdgeGroupIsland **)p1;
+ const struct EdgeGroupIsland *g2 = *(struct EdgeGroupIsland **)p2;
+ /* min->co[SORT_AXIS] hasn't been applied yet */
+ const float f1 = g1->vert_span.min_axis;
+ const float f2 = g2->vert_span.min_axis;
+
+ if (f1 < f2) return -1;
+ if (f1 > f2) return 1;
+ else return 0;
+}
+
+struct Edges_VertVert_BVHTreeTest {
+ float dist_orig;
+ BMEdge **edge_arr;
+
+ BMVert *v_origin;
+ BMVert *v_other;
+
+ const unsigned int *vert_range;
+};
+
+struct Edges_VertRay_BVHTreeTest {
+ BMEdge **edge_arr;
+
+ BMVert *v_origin;
+
+ const unsigned int *vert_range;
+};
+
+static void bvhtree_test_edges_isect_2d_vert_cb(
+ void *user_data, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit)
+{
+ struct Edges_VertVert_BVHTreeTest *data = user_data;
+ const BMEdge *e = data->edge_arr[index];
+ const int v1_index = BM_elem_index_get(e->v1);
+ float co_isect[2];
+
+ if (edge_isect_verts_point_2d(e, data->v_origin, data->v_other, co_isect)) {
+ const float t = line_point_factor_v2(co_isect, data->v_origin->co, data->v_other->co);
+ const float dist_new = data->dist_orig * t;
+ /* avoid float precision issues, possible this is greater,
+ * check above zero to allow some overlap
+ * (and needed for partial-connect which will overlap vertices) */
+ if (LIKELY((dist_new < hit->dist) && (dist_new > 0.0f))) {
+ /* v1/v2 will both be in the same group */
+ if (v1_index < (int)data->vert_range[0] ||
+ v1_index >= (int)data->vert_range[1])
+ {
+ hit->dist = dist_new;
+ hit->index = index;
+ }
+ }
+ }
+}
+
+static void bvhtree_test_edges_isect_2d_ray_cb(
+ void *user_data, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ struct Edges_VertRay_BVHTreeTest *data = user_data;
+ const BMEdge *e = data->edge_arr[index];
+
+ /* direction is normalized, so this will be the distance */
+ float dist_new;
+ if (isect_ray_seg_v2(data->v_origin->co, ray->direction, e->v1->co, e->v2->co, &dist_new, NULL)) {
+ /* avoid float precision issues, possible this is greater,
+ * check above zero to allow some overlap
+ * (and needed for partial-connect which will overlap vertices) */
+ if (LIKELY(dist_new < hit->dist && (dist_new > 0.0f))) {
+ if (e->v1 != data->v_origin && e->v2 != data->v_origin) {
+ const int v1_index = BM_elem_index_get(e->v1);
+ /* v1/v2 will both be in the same group */
+ if (v1_index < (int)data->vert_range[0] ||
+ v1_index >= (int)data->vert_range[1])
+ {
+ hit->dist = dist_new;
+ hit->index = index;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Store values for:
+ * - #bm_face_split_edgenet_find_connection
+ * - #test_edges_isect_2d
+ * ... which don't change each call.
+ */
+struct EdgeGroup_FindConnection_Args {
+ BVHTree *bvhtree;
+ BMEdge **edge_arr;
+ unsigned int edge_arr_len;
+
+ BMEdge **edge_arr_new;
+ unsigned int edge_arr_new_len;
+
+ const unsigned int *vert_range;
+};
+
+static BMEdge *test_edges_isect_2d_vert(
+ const struct EdgeGroup_FindConnection_Args *args,
+ BMVert *v_origin, BMVert *v_other)
+{
+ int index;
+
+ BVHTreeRayHit hit = {0};
+ float dir[3];
+
+ sub_v2_v2v2(dir, v_other->co, v_origin->co);
+ dir[2] = 0.0f;
+ hit.index = -1;
+ hit.dist = normalize_v2(dir);
+
+ struct Edges_VertVert_BVHTreeTest user_data = {0};
+ user_data.dist_orig = hit.dist;
+ user_data.edge_arr = args->edge_arr;
+ user_data.v_origin = v_origin;
+ user_data.v_other = v_other;
+ user_data.vert_range = args->vert_range;
+
+ index = BLI_bvhtree_ray_cast_ex(
+ args->bvhtree, v_origin->co, dir, 0.0f, &hit,
+ bvhtree_test_edges_isect_2d_vert_cb, &user_data, 0);
+
+ BMEdge *e_hit = (index != -1) ? args->edge_arr[index] : NULL;
+
+ /* check existing connections (no spatial optimization here since we're continually adding). */
+ if (LIKELY(index == -1)) {
+ float t_best = 1.0f;
+ for (unsigned int i = 0; i < args->edge_arr_new_len; i++) {
+ float co_isect[2];
+ if (UNLIKELY(edge_isect_verts_point_2d(args->edge_arr_new[i], v_origin, v_other, co_isect))) {
+ const float t_test = line_point_factor_v2(co_isect, v_origin->co, v_other->co);
+ if (t_test < t_best) {
+ t_best = t_test;
+
+ e_hit = args->edge_arr_new[i];
+ }
+ }
+ }
+ }
+
+ return e_hit;
+}
+
+/**
+ * Similar to #test_edges_isect_2d_vert but we're casting into a direction,
+ * (not to a vertex)
+ */
+static BMEdge *test_edges_isect_2d_ray(
+ const struct EdgeGroup_FindConnection_Args *args,
+ BMVert *v_origin, const float dir[3])
+{
+ int index;
+ BVHTreeRayHit hit = {0};
+
+ BLI_ASSERT_UNIT_V2(dir);
+
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ struct Edges_VertRay_BVHTreeTest user_data = {0};
+ user_data.edge_arr = args->edge_arr;
+ user_data.v_origin = v_origin;
+ user_data.vert_range = args->vert_range;
+
+ index = BLI_bvhtree_ray_cast_ex(
+ args->bvhtree, v_origin->co, dir, 0.0f, &hit,
+ bvhtree_test_edges_isect_2d_ray_cb, &user_data, 0);
+
+ BMEdge *e_hit = (index != -1) ? args->edge_arr[index] : NULL;
+
+ /* check existing connections (no spatial optimization here since we're continually adding). */
+ if (LIKELY(index != -1)) {
+ for (unsigned int i = 0; i < args->edge_arr_new_len; i++) {
+ BMEdge *e = args->edge_arr_new[i];
+ float dist_new;
+ if (isect_ray_seg_v2(v_origin->co, dir, e->v1->co, e->v2->co, &dist_new, NULL)) {
+ if (e->v1 != v_origin && e->v2 != v_origin) {
+ /* avoid float precision issues, possible this is greater */
+ if (LIKELY(dist_new < hit.dist)) {
+ hit.dist = dist_new;
+
+ e_hit = args->edge_arr_new[i];
+ }
+ }
+ }
+ }
+ }
+
+ return e_hit;
+}
+
+static int bm_face_split_edgenet_find_connection(
+ const struct EdgeGroup_FindConnection_Args *args,
+ BMVert *v_origin,
+ /* false = negative, true = positive */
+ bool direction_sign)
+{
+ /**
+ * Method for finding connection is as follows:
+ *
+ * - Cast a ray along either the positive or negative directions.
+ * - Take the hit-edge, and cast rays to their vertices checking those rays don't intersect a closer edge.
+ * - Keep taking the hit-edge and testing its verts until a vertex is found which isn't blocked by an edge.
+ *
+ * \note It's possible none of the verts can be accessed (with self-intersecting lines).
+ * In that case theres no right answer (without subdividing edges),
+ * so return a fall-back vertex in that case.
+ */
+
+ const float dir[3] = {[SORT_AXIS] = direction_sign ? 1.0f : -1.0f};
+ BMEdge *e_hit = test_edges_isect_2d_ray(args, v_origin, dir);
+ BMVert *v_other = NULL;
+
+ if (e_hit) {
+ BMVert *v_other_fallback = NULL;
+
+ BLI_SMALLSTACK_DECLARE(vert_search, BMVert *);
+
+ /* ensure we never add verts multiple times (not all that likely - but possible) */
+ BLI_SMALLSTACK_DECLARE(vert_blacklist, BMVert *);
+
+ do {
+ BMVert *v_pair[2];
+ /* ensure the closest vertex is popped back off the stack first */
+ if (len_squared_v2v2(v_origin->co, e_hit->v1->co) >
+ len_squared_v2v2(v_origin->co, e_hit->v2->co))
+ {
+ ARRAY_SET_ITEMS(v_pair, e_hit->v1, e_hit->v2);
+ }
+ else {
+ ARRAY_SET_ITEMS(v_pair, e_hit->v2, e_hit->v1);
+ }
+
+ for (int j = 0; j < 2; j++) {
+ BMVert *v_iter = v_pair[j];
+ if (BM_elem_flag_test(v_iter, VERT_IS_VALID)) {
+ if (direction_sign ? (v_iter->co[SORT_AXIS] >= v_origin->co[SORT_AXIS]) :
+ (v_iter->co[SORT_AXIS] <= v_origin->co[SORT_AXIS]))
+ {
+ BLI_SMALLSTACK_PUSH(vert_search, v_iter);
+ BLI_SMALLSTACK_PUSH(vert_blacklist, v_iter);
+ BM_elem_flag_disable(v_iter, VERT_IS_VALID);
+ }
+ }
+ }
+ v_other_fallback = v_other;
+
+ } while ((v_other = BLI_SMALLSTACK_POP(vert_search)) &&
+ (e_hit = test_edges_isect_2d_vert(args, v_origin, v_other)));
+
+ if (v_other == NULL) {
+ printf("Using fallback\n");
+ v_other = v_other_fallback;
+ }
+
+ /* reset the blacklist flag, for future use */
+ BMVert *v;
+ while ((v = BLI_SMALLSTACK_POP(vert_blacklist))) {
+ BM_elem_flag_enable(v, VERT_IS_VALID);
+ }
+ }
+
+ /* if we reach this line, v_other is either the best vertex or its NULL */
+ return v_other ? BM_elem_index_get(v_other) : -1;
+}
+
+
+/**
+ * Support for connecting islands that have single-edge connections.
+ * This options is not very optimal (however its not needed for booleans either).
+ */
+#ifdef USE_PARTIAL_CONNECT
+
+/**
+ * Split vertices which are part of a partial connection
+ * (only a single vertex connecting an island).
+ *
+ * \note All edges and vertices must have their #BM_ELEM_INTERNAL_TAG flag enabled.
+ * This function leaves all the flags set as well.
+ *
+ */
+static BMVert *bm_face_split_edgenet_partial_connect(BMesh *bm, BMVert *v_delimit)
+{
+ /* -------------------------------------------------------------------- */
+ /* Initial check that we may be a delimiting vert (keep this fast) */
+
+ /* initial check - see if we have 3+ flagged edges attached to 'v_delimit'
+ * if not, we can early exit */
+ LinkNode *e_delimit_list = NULL;
+ unsigned int e_delimit_list_len = 0;
+
+#define EDGE_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
+#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
+
+#define FOREACH_VERT_EDGE(v_, e_, body_) { \
+ BMEdge *e_ = v_->e; \
+ do { body_ } while ((e_ = BM_DISK_EDGE_NEXT(e_, v_)) != v_->e); \
+} ((void)0)
+
+ /* start with face edges, since we need to split away wire-only edges */
+ BMEdge *e_face_init = NULL;
+
+ FOREACH_VERT_EDGE(v_delimit, e_iter, {
+ if (BM_elem_flag_test(e_iter, EDGE_NOT_IN_STACK)) {
+ BLI_assert(BM_elem_flag_test(BM_edge_other_vert(e_iter, v_delimit), VERT_NOT_IN_STACK));
+ BLI_linklist_prepend_alloca(&e_delimit_list, e_iter);
+ e_delimit_list_len++;
+ if (e_iter->l != NULL) {
+ e_face_init = e_iter;
+ }
+ }
+ });
+
+ /* skip typical edge-chain verts */
+ if (LIKELY(e_delimit_list_len <= 2)) {
+ return NULL;
+ }
+
+
+ /* -------------------------------------------------------------------- */
+ /* Complicated stuff starts now! */
+
+
+ /* Store connected vertices for restoring the flag */
+ LinkNode *vert_stack = NULL;
+ BLI_linklist_prepend_alloca(&vert_stack, v_delimit);
+ BM_elem_flag_disable(v_delimit, VERT_NOT_IN_STACK);
+
+ /* Walk the net... */
+ {
+ BLI_SMALLSTACK_DECLARE(search, BMVert *);
+ BMVert *v_other = BM_edge_other_vert(e_face_init ? e_face_init : v_delimit->e, v_delimit);
+
+ BLI_SMALLSTACK_PUSH(search, v_other);
+ BM_elem_flag_disable(v_other, VERT_NOT_IN_STACK);
+
+ while ((v_other = BLI_SMALLSTACK_POP(search))) {
+ BLI_assert(BM_elem_flag_test(v_other, VERT_NOT_IN_STACK) == false);
+ BLI_linklist_prepend_alloca(&vert_stack, v_other);
+ BMEdge *e_iter = v_other->e;
+ do {
+ BMVert *v_step = BM_edge_other_vert(e_iter, v_other);
+ if (BM_elem_flag_test(e_iter, EDGE_NOT_IN_STACK)) {
+ if (BM_elem_flag_test(v_step, VERT_NOT_IN_STACK)) {
+ BM_elem_flag_disable(v_step, VERT_NOT_IN_STACK);
+ BLI_SMALLSTACK_PUSH(search, v_step);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_other)) != v_other->e);
+ }
+ }
+
+ /* Detect if this is a delimiter by checking if we didn't walk any of edges connected to 'v_delimit' */
+ bool is_delimit = false;
+ FOREACH_VERT_EDGE(v_delimit, e_iter, {
+ BMVert *v_step = BM_edge_other_vert(e_iter, v_delimit);
+ if (BM_elem_flag_test(v_step, VERT_NOT_IN_STACK) && BM_edge_is_wire(e_iter)) {
+ is_delimit = true; /* if one vertex is valid - we have a mix */
+ }
+ else {
+ /* match the vertex flag (only for edges around 'v_delimit') */
+ BM_elem_flag_disable(e_iter, EDGE_NOT_IN_STACK);
+ }
+ });
+
+#undef FOREACH_VERT_EDGE
+
+ /* Execute the split */
+ BMVert *v_split = NULL;
+ if (is_delimit) {
+ v_split = BM_vert_create(bm, v_delimit->co, NULL, 0);
+ BM_vert_separate_wire_hflag(bm, v_split, v_delimit, EDGE_NOT_IN_STACK);
+ BM_elem_flag_enable(v_split, VERT_NOT_IN_STACK);
+
+ BLI_assert(v_delimit->e != NULL);
+ BLI_assert(v_split->e != NULL);
+ }
+
+ /* Restore flags */
+ do {
+ BM_elem_flag_enable((BMVert *)vert_stack->link, VERT_NOT_IN_STACK);
+ } while ((vert_stack = vert_stack->next));
+
+ do {
+ BM_elem_flag_enable((BMEdge *)e_delimit_list->link, EDGE_NOT_IN_STACK);
+ } while ((e_delimit_list = e_delimit_list->next));
+
+#undef EDGE_NOT_IN_STACK
+#undef VERT_NOT_IN_STACK
+
+ return v_split;
+}
+
+
+/**
+ * Check if connecting vertices would cause an edge with duplicate verts.
+ */
+static bool bm_vert_partial_connect_check_overlap(
+ const int *remap,
+ const int v_a_index, const int v_b_index)
+{
+ /* connected to eachother */
+ if (UNLIKELY((remap[v_a_index] == v_b_index) ||
+ (remap[v_b_index] == v_a_index)))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+
+#endif /* USE_PARTIAL_CONNECT */
+
+
+
+/**
+ * For when the edge-net has holes in it-this connects them.
+ *
+ * \param use_partial_connect: Support for handling islands connected by only a single edge,
+ * \note that this is quite slow so avoid using where possible.
+ * \param mem_arena: Avoids many small allocs & should be cleared after each use.
+ * take care since \a r_edge_net_new is stored in \a r_edge_net_new.
+ */
+bool BM_face_split_edgenet_connect_islands(
+ BMesh *bm,
+ BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len,
+ bool use_partial_connect,
+ MemArena *mem_arena,
+ BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len)
+{
+ /* -------------------------------------------------------------------- */
+ /* This function has 2 main parts.
+ *
+ * - Check if there are any holes.
+ * - Connect the holes with edges (if any are found).
+ *
+ * Keep the first part fast since it will run very often for edge-nets that have no holes.
+ *
+ * \note Don't use the mem_arena unless he have holes to fill.
+ * (avoid thrashing the area when the initial check isn't so intensive on the stack).
+ */
+
+ const unsigned int edge_arr_len = (unsigned int)edge_net_init_len + (unsigned int)f->len;
+ BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
+ bool ok = false;
+
+ memcpy(edge_arr, edge_net_init, sizeof(*edge_arr) * (size_t)edge_net_init_len);
+
+ /* _must_ clear on exit */
+#define EDGE_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
+#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG
+
+ {
+ unsigned int i = edge_net_init_len;
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ edge_arr[i++] = l_iter->e;
+ } while ((l_iter = l_iter->next) != l_first);
+ BLI_assert(i == edge_arr_len);
+ }
+
+ for (unsigned int i = 0; i < edge_arr_len; i++) {
+ BM_elem_flag_enable(edge_arr[i], EDGE_NOT_IN_STACK);
+ BM_elem_flag_enable(edge_arr[i]->v1, VERT_NOT_IN_STACK);
+ BM_elem_flag_enable(edge_arr[i]->v2, VERT_NOT_IN_STACK);
+ }
+
+
+
+#ifdef USE_PARTIAL_CONNECT
+ /* Split-out delimiting vertices */
+ struct TempVertPair {
+ struct TempVertPair *next;
+ BMVert *v_temp;
+ BMVert *v_orig;
+ };
+
+ struct {
+ struct TempVertPair *list;
+ unsigned int len;
+ int *remap; /* temp -> orig mapping */
+ } temp_vert_pairs = {NULL};
+
+ if (use_partial_connect) {
+ for (unsigned int i = 0; i < edge_net_init_len; i++) {
+ for (unsigned j = 0; j < 2; j++) {
+ BMVert *v_delimit = (&edge_arr[i]->v1)[j];
+ BMVert *v_other;
+
+ /* note, remapping will _never_ map a vertex to an already mapped vertex */
+ while (UNLIKELY((v_other = bm_face_split_edgenet_partial_connect(bm, v_delimit)))) {
+ struct TempVertPair *tvp = BLI_memarena_alloc(mem_arena, sizeof(*tvp));
+ tvp->next = temp_vert_pairs.list;
+ tvp->v_orig = v_delimit;
+ tvp->v_temp = v_other;
+ temp_vert_pairs.list = tvp;
+ temp_vert_pairs.len++;
+ }
+ }
+ }
+
+ if (temp_vert_pairs.len == 0) {
+ use_partial_connect = false;
+ }
+ }
+#endif /* USE_PARTIAL_CONNECT */
+
+
+
+ unsigned int group_arr_len = 0;
+ LinkNode *group_head = NULL;
+ {
+ /* scan 'edge_arr' backwards so the outer face boundary is handled first
+ * (since its likely to be the largest) */
+ unsigned int edge_index = (edge_arr_len - 1);
+ unsigned int edge_in_group_tot = 0;
+
+ BLI_SMALLSTACK_DECLARE(vstack, BMVert *);
+
+ while (true) {
+ LinkNode *edge_links = NULL;
+ unsigned int unique_verts_in_group = 0, unique_edges_in_group = 0;
+
+ /* list of groups */
+ BLI_assert(BM_elem_flag_test(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK));
+ BLI_SMALLSTACK_PUSH(vstack, edge_arr[edge_index]->v1);
+ BM_elem_flag_disable(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK);
+
+ BMVert *v_iter;
+ while ((v_iter = BLI_SMALLSTACK_POP(vstack))) {
+ unique_verts_in_group++;
+
+ BMEdge *e_iter = v_iter->e;
+ do {
+ if (BM_elem_flag_test(e_iter, EDGE_NOT_IN_STACK)) {
+ BM_elem_flag_disable(e_iter, EDGE_NOT_IN_STACK);
+ unique_edges_in_group++;
+
+ BLI_linklist_prepend_alloca(&edge_links, e_iter);
+
+ BMVert *v_other = BM_edge_other_vert(e_iter, v_iter);
+ if (BM_elem_flag_test(v_other, VERT_NOT_IN_STACK)) {
+ BLI_SMALLSTACK_PUSH(vstack, v_other);
+ BM_elem_flag_disable(v_other, VERT_NOT_IN_STACK);
+ }
+ }
+ } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_iter)) != v_iter->e);
+ }
+
+ struct EdgeGroupIsland *g = alloca(sizeof(*g));
+ g->vert_len = unique_verts_in_group;
+ g->edge_len = unique_edges_in_group;
+ edge_in_group_tot += unique_edges_in_group;
+
+ BLI_linklist_prepend_nlink(&group_head, edge_links, (LinkNode *)g);
+
+ group_arr_len++;
+
+ if (edge_in_group_tot == edge_arr_len) {
+ break;
+ }
+
+ /* skip edges in the stack */
+ while (BM_elem_flag_test(edge_arr[edge_index], EDGE_NOT_IN_STACK) == false) {
+ BLI_assert(edge_index != 0);
+ edge_index--;
+ }
+ }
+ }
+
+ /* single group - no holes */
+ if (group_arr_len == 1) {
+ goto finally;
+ }
+
+
+ /* -------------------------------------------------------------------- */
+ /* Previous checks need to be kept fast, since they will run very often,
+ * now we know there are holes, so calculate a spatial lookup info and
+ * other per-group data.
+ */
+
+ float axis_mat[3][3];
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+
+#define VERT_IN_ARRAY BM_ELEM_INTERNAL_TAG
+
+ struct EdgeGroupIsland **group_arr = BLI_memarena_alloc(mem_arena, sizeof(*group_arr) * group_arr_len);
+ unsigned int vert_arr_len = 0;
+ /* sort groups by lowest value vertex */
+ {
+ /* fill 'groups_arr' in reverse order so the boundary face is first */
+ struct EdgeGroupIsland **group_arr_p = &group_arr[group_arr_len];
+
+ for (struct EdgeGroupIsland *g = (void *)group_head; g; g = (struct EdgeGroupIsland *)g->edge_links.next) {
+ LinkNode *edge_links = g->edge_links.link;
+
+ /* init with *any* different verts */
+ g->vert_span.min = ((BMEdge *)edge_links->link)->v1;
+ g->vert_span.max = ((BMEdge *)edge_links->link)->v2;
+ float min_axis = FLT_MAX;
+ float max_axis = -FLT_MAX;
+
+ do {
+ BMEdge *e = edge_links->link;
+ BLI_assert(e->head.htype == BM_EDGE);
+
+ for (int j = 0; j < 2; j++) {
+ BMVert *v_iter = (&e->v1)[j];
+ BLI_assert(v_iter->head.htype == BM_VERT);
+ /* ideally we could use 'v_iter->co[SORT_AXIS]' here,
+ * but we need to sort the groups before setting the vertex array order */
+#if SORT_AXIS == 0
+ const float axis_value = dot_m3_v3_row_x(axis_mat, v_iter->co);
+#else
+ const float axis_value = dot_m3_v3_row_y(axis_mat, v_iter->co);
+#endif
+
+ if (axis_value < min_axis) {
+ g->vert_span.min = v_iter;
+ min_axis = axis_value;
+ }
+ if (axis_value > max_axis ) {
+ g->vert_span.max = v_iter;
+ max_axis = axis_value;
+ }
+ }
+ } while ((edge_links = edge_links->next));
+
+ g->vert_span.min_axis = min_axis;
+
+ g->has_prev_edge = false;
+
+ vert_arr_len += g->vert_len;
+
+ *(--group_arr_p) = g;
+ }
+ }
+
+ qsort(group_arr, group_arr_len, sizeof(*group_arr), group_min_cmp_fn);
+
+ /* we don't know how many unique verts there are connecting the edges, so over-alloc */
+ BMVert **vert_arr = BLI_memarena_alloc(mem_arena, sizeof(*vert_arr) * vert_arr_len);
+ /* map vertex -> group index */
+ unsigned int *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len);
+
+ float (*vert_coords_backup)[3] = BLI_memarena_alloc(mem_arena, sizeof(*vert_coords_backup) * vert_arr_len);
+
+ {
+ /* relative location, for higher precision calculations */
+ const float f_co_ref[3] = {UNPACK3(BM_FACE_FIRST_LOOP(f)->v->co)};
+
+ int v_index = 0; /* global vert index */
+ for (unsigned int g_index = 0; g_index < group_arr_len; g_index++) {
+ LinkNode *edge_links = group_arr[g_index]->edge_links.link;
+ do {
+ BMEdge *e = edge_links->link;
+ for (int j = 0; j < 2; j++) {
+ BMVert *v_iter = (&e->v1)[j];
+ if (!BM_elem_flag_test(v_iter, VERT_IN_ARRAY)) {
+ BM_elem_flag_enable(v_iter, VERT_IN_ARRAY);
+
+ /* not nice, but alternatives arent much better :S */
+ {
+ copy_v3_v3(vert_coords_backup[v_index], v_iter->co);
+
+ /* for higher precision */
+ sub_v3_v3(v_iter->co, f_co_ref);
+
+ float co_2d[2];
+ mul_v2_m3v3(co_2d, axis_mat, v_iter->co);
+ v_iter->co[0] = co_2d[0];
+ v_iter->co[1] = co_2d[1];
+ v_iter->co[2] = 0.0f;
+ }
+
+ BM_elem_index_set(v_iter, v_index); /* set_dirty */
+
+ vert_arr[v_index] = v_iter;
+ verts_group_table[v_index] = g_index;
+ v_index++;
+ }
+ }
+ } while ((edge_links = edge_links->next));
+ }
+ }
+
+ bm->elem_index_dirty |= BM_VERT;
+
+ /* Now create bvh tree*/
+ BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8);
+ for (unsigned int i = 0; i < edge_arr_len; i++) {
+ const float e_cos[2][3] = {
+ {UNPACK2(edge_arr[i]->v1->co), 0.0f},
+ {UNPACK2(edge_arr[i]->v2->co), 0.0f},
+ };
+ BLI_bvhtree_insert(bvhtree, i, (const float *)e_cos, 2);
+ }
+ BLI_bvhtree_balance(bvhtree);
+
+
+
+#ifdef USE_PARTIAL_CONNECT
+ if (use_partial_connect) {
+ /* needs to be done once the vertex indices have been written into */
+ temp_vert_pairs.remap = BLI_memarena_alloc(mem_arena, sizeof(*temp_vert_pairs.remap) * vert_arr_len);
+ copy_vn_i(temp_vert_pairs.remap, vert_arr_len, -1);
+
+ struct TempVertPair *tvp = temp_vert_pairs.list;
+ do {
+ temp_vert_pairs.remap[BM_elem_index_get(tvp->v_temp)] = BM_elem_index_get(tvp->v_orig);
+ } while ((tvp = tvp->next));
+ }
+#endif /* USE_PARTIAL_CONNECT */
+
+
+
+ /* Create connections between groups */
+
+ /* may be an over-alloc, but not by much */
+ unsigned int edge_net_new_len = (unsigned int)edge_net_init_len + ((group_arr_len - 1) * 2);
+ BMEdge **edge_net_new = BLI_memarena_alloc(mem_arena, sizeof(*edge_net_new) * edge_net_new_len);
+ memcpy(edge_net_new, edge_net_init, sizeof(*edge_net_new) * (size_t)edge_net_init_len);
+
+ {
+ unsigned int edge_net_new_index = edge_net_init_len;
+ /* start-end of the verts in the current group */
+
+ unsigned int vert_range[2];
+
+ vert_range[0] = 0;
+ vert_range[1] = group_arr[0]->vert_len;
+
+ struct EdgeGroup_FindConnection_Args args = {
+ .bvhtree = bvhtree,
+
+ /* use the new edge array so we can scan edges which have been added */
+ .edge_arr = edge_arr,
+ .edge_arr_len = edge_arr_len,
+
+ /* we only want to check newly created edges */
+ .edge_arr_new = edge_net_new + edge_net_init_len,
+ .edge_arr_new_len = 0,
+
+ .vert_range = vert_range,
+ };
+
+ for (unsigned int g_index = 1; g_index < group_arr_len; g_index++) {
+ struct EdgeGroupIsland *g = group_arr[g_index];
+
+ /* the range of verts this group uses in 'verts_arr' (not uncluding the last index) */
+ vert_range[0] = vert_range[1];
+ vert_range[1] += g->vert_len;
+
+ if (g->has_prev_edge == false) {
+ BMVert *v_origin = g->vert_span.min;
+
+ const int index_other = bm_face_split_edgenet_find_connection(&args, v_origin, false);
+ // BLI_assert(index_other >= 0 && index_other < (int)vert_arr_len);
+
+ /* only for degenerate geometry */
+ if (index_other != -1) {
+#ifdef USE_PARTIAL_CONNECT
+ if ((use_partial_connect == false) ||
+ (bm_vert_partial_connect_check_overlap(
+ temp_vert_pairs.remap,
+ BM_elem_index_get(v_origin), index_other) == false))
+#endif
+ {
+ BMVert *v_end = vert_arr[index_other];
+
+ edge_net_new[edge_net_new_index] = BM_edge_create(bm, v_origin, v_end, NULL, 0);
+#ifdef USE_PARTIAL_CONNECT
+ BM_elem_index_set(edge_net_new[edge_net_new_index], edge_net_new_index);
+#endif
+ edge_net_new_index++;
+ args.edge_arr_new_len++;
+ }
+ }
+ }
+
+ {
+ BMVert *v_origin = g->vert_span.max;
+
+ const int index_other = bm_face_split_edgenet_find_connection(&args, v_origin, true);
+ // BLI_assert(index_other >= 0 && index_other < (int)vert_arr_len);
+
+ /* only for degenerate geometry */
+ if (index_other != -1) {
+#ifdef USE_PARTIAL_CONNECT
+ if ((use_partial_connect == false) ||
+ (bm_vert_partial_connect_check_overlap(
+ temp_vert_pairs.remap,
+ BM_elem_index_get(v_origin), index_other) == false))
+#endif
+ {
+ BMVert *v_end = vert_arr[index_other];
+ edge_net_new[edge_net_new_index] = BM_edge_create(bm, v_origin, v_end, NULL, 0);
+#ifdef USE_PARTIAL_CONNECT
+ BM_elem_index_set(edge_net_new[edge_net_new_index], edge_net_new_index);
+#endif
+ edge_net_new_index++;
+ args.edge_arr_new_len++;
+ }
+
+ /* tell the 'next' group it doesn't need to create its own back-link */
+ unsigned int g_index_other = verts_group_table[index_other];
+ group_arr[g_index_other]->has_prev_edge = true;
+ }
+ }
+
+ }
+ BLI_assert(edge_net_new_len >= edge_net_new_index);
+ edge_net_new_len = edge_net_new_index;
+ }
+
+ BLI_bvhtree_free(bvhtree);
+
+ *r_edge_net_new = edge_net_new;
+ *r_edge_net_new_len = edge_net_new_len;
+ ok = true;
+
+ for (unsigned int i = 0; i < vert_arr_len; i++) {
+ copy_v3_v3(vert_arr[i]->co, vert_coords_backup[i]);
+ }
+
+finally:
+
+#ifdef USE_PARTIAL_CONNECT
+ /* don't free 'vert_temp_pair_list', its part of the arena */
+ if (use_partial_connect) {
+
+ /* Sanity check: ensure we don't have connecting edges before splicing begins. */
+#ifdef DEBUG
+ {
+ struct TempVertPair *tvp = temp_vert_pairs.list;
+ do {
+ /* we must _never_ create connections here
+ * (inface the islands can't have a connection at all) */
+ BLI_assert(BM_edge_exists(tvp->v_orig, tvp->v_temp) == NULL);
+ } while ((tvp = tvp->next));
+ }
+#endif
+
+ struct TempVertPair *tvp = temp_vert_pairs.list;
+ do {
+ /* its _very_ unlikely the edge exists,
+ * however splicing may case this. see: T48012 */
+ if (!BM_edge_exists(tvp->v_orig, tvp->v_temp)) {
+ BM_vert_splice(bm, tvp->v_orig, tvp->v_temp);
+ }
+ } while ((tvp = tvp->next));
+
+ /* Remove edges which have become doubles since splicing vertices together,
+ * its less trouble then detecting future-doubles on edge-creation. */
+ for (unsigned int i = edge_net_init_len; i < edge_net_new_len; i++) {
+ while (BM_edge_find_double(edge_net_new[i])) {
+ BM_edge_kill(bm, edge_net_new[i]);
+ edge_net_new_len--;
+ if (i == edge_net_new_len) {
+ break;
+ }
+ edge_net_new[i] = edge_net_new[edge_net_new_len];
+ }
+ }
+
+ *r_edge_net_new_len = edge_net_new_len;
+ }
+#endif
+
+
+ for (unsigned int i = 0; i < edge_arr_len; i++) {
+ BM_elem_flag_disable(edge_arr[i], EDGE_NOT_IN_STACK);
+ BM_elem_flag_disable(edge_arr[i]->v1, VERT_NOT_IN_STACK);
+ BM_elem_flag_disable(edge_arr[i]->v2, VERT_NOT_IN_STACK);
+ }
+
+#undef VERT_IN_ARRAY
+#undef VERT_NOT_IN_STACK
+#undef EDGE_NOT_IN_STACK
+
+ return ok;
+}
+
+#undef SORT_AXIS
+
+/** \} */
diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
new file mode 100644
index 00000000000..72ae7695f0f
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h
@@ -0,0 +1,41 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_POLYGON_EDGENET_H__
+#define __BMESH_POLYGON_EDGENET_H__
+
+/** \file blender/bmesh/intern/bmesh_polygon_edgenet.h
+ * \ingroup bmesh
+ */
+
+bool BM_face_split_edgenet(
+ BMesh *bm, BMFace *f,
+ BMEdge **edge_net, const int edge_net_len,
+ BMFace ***r_face_arr, int *r_face_arr_len);
+
+bool BM_face_split_edgenet_connect_islands(
+ BMesh *bm,
+ BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len,
+ bool use_partial_connect,
+ struct MemArena *arena,
+ BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len)
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 6, 7, 8);
+
+#endif /* __BMESH_POLYGON_EDGENET_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index 814015a2a74..9b3a147301d 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -67,6 +67,8 @@ enum {
_FLAG_MV = (1 << 1), /* make face, vertex */
_FLAG_OVERLAP = (1 << 2), /* general overlap flag */
_FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */
+
+ _FLAG_ELEM_CHECK = (1 << 7), /* reserved for bmesh_elem_check */
};
#define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 1a8ea1e3a0d..ffad3e59e47 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -768,13 +768,35 @@ bool BM_vert_is_edge_pair(const BMVert *v)
{
const BMEdge *e = v->e;
if (e) {
- const BMDiskLink *dl = bmesh_disk_edge_link_from_vert(e, v);
- return (dl->next == dl->prev);
+ BMEdge *e_other = BM_DISK_EDGE_NEXT(e, v);
+ return ((e_other != e) && (BM_DISK_EDGE_NEXT(e_other, v) == e));
}
return false;
}
/**
+ * Access a verts 2 connected edges.
+ *
+ * \return true when only 2 verts are found.
+ */
+bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b)
+{
+ BMEdge *e_a = v->e;
+ if (e_a) {
+ BMEdge *e_b = BM_DISK_EDGE_NEXT(e_a, v);
+ if ((e_b != e_a) && (BM_DISK_EDGE_NEXT(e_b, v) == e_a)) {
+ *r_e_a = e_a;
+ *r_e_b = e_b;
+ return true;
+ }
+ }
+
+ *r_e_a = NULL;
+ *r_e_b = NULL;
+ return false;
+}
+
+/**
* Returns the number of edges around this vertex.
*/
int BM_vert_edge_count(const BMVert *v)
@@ -1216,6 +1238,53 @@ bool BM_face_share_edge_check(BMFace *f1, BMFace *f2)
}
/**
+ * Counts the number of verts two faces share (if any).
+ */
+int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ int count = 0;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
+ do {
+ if (BM_vert_in_face(l_iter->v, f_b)) {
+ count++;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return count;
+}
+
+/**
+ * Returns true if the faces share a vert.
+ */
+bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b)
+{
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
+ do {
+ if (BM_vert_in_face(l_iter->v, f_b)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+ return false;
+}
+
+/**
+ * Returns true when 2 loops share an edge (are adjacent in the face-fan)
+ */
+bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b)
+{
+ BLI_assert(l_a->v == l_b->v);
+ return (ELEM(l_a->e, l_b->e, l_b->prev->e) ||
+ ELEM(l_b->e, l_a->e, l_a->prev->e));
+}
+
+/**
* Test if e1 shares any faces with e2
*/
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2)
@@ -1882,7 +1951,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
if (l_walk->v != varr[i_walk]) {
break;
}
- } while ((l_walk = l_walk->next), ++i_walk != len);
+ } while ((void)(l_walk = l_walk->next), ++i_walk != len);
}
else if (l_iter_radial->prev->v == varr[1]) {
BMLoop *l_walk = l_iter_radial->prev->prev;
@@ -1890,7 +1959,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface)
if (l_walk->v != varr[i_walk]) {
break;
}
- } while ((l_walk = l_walk->prev), ++i_walk != len);
+ } while ((void)(l_walk = l_walk->prev), ++i_walk != len);
}
if (i_walk == len) {
@@ -2035,26 +2104,13 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len)
{
BMVert **varr = BLI_array_alloca(varr, len);
- bool ok;
- int i, i_next;
-
/* first check if verts have edges, if not we can bail out early */
- ok = true;
- for (i = len - 1, i_next = 0; i_next < len; (i = i_next++)) {
- if (!(varr[i] = BM_edge_share_vert(earr[i], earr[i_next]))) {
- ok = false;
- break;
- }
- }
-
- if (ok == false) {
+ if (!BM_verts_from_edges(varr, earr, len)) {
BMESH_ASSERT(0);
return false;
}
- ok = BM_face_exists_multi(varr, earr, len);
-
- return ok;
+ return BM_face_exists_multi(varr, earr, len);
}
@@ -2299,7 +2355,7 @@ static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol)
unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
int j;
- BM_face_calc_tessellation(f, loops, index);
+ BM_face_calc_tessellation(f, false, loops, index);
for (j = 0; j < tottri; j++) {
const float *p1 = loops[index[j][0]]->v->co;
@@ -2339,8 +2395,7 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
* (or when hflag_test is set, the number of flagged faces).
* \param r_group_index index, length pairs into \a r_groups_array, size of return value
* int pairs: (array_start, array_length).
- * \param filter_fn Filter the edges or verts we step over (depends on \a htype_step)
- * as to which types we deal with.
+ * \param filter_fn Filter the edge-loops or vert-loops we step over (depends on \a htype_step).
* \param user_data Optional user data for \a filter_fn, can be NULL.
* \param hflag_test Optional flag to test faces,
* use to exclude faces from the calculation, 0 for all faces.
@@ -2350,7 +2405,7 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
*/
int BM_mesh_calc_face_groups(
BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
+ BMLoopFilterFunc filter_fn, void *user_data,
const char hflag_test, const char htype_step)
{
#ifdef DEBUG
@@ -2443,7 +2498,7 @@ int BM_mesh_calc_face_groups(
do {
BMLoop *l_radial_iter = l_iter->radial_next;
if ((l_radial_iter != l_iter) &&
- ((filter_fn == NULL) || filter_fn((BMElem *)l_iter->e, user_data)))
+ ((filter_fn == NULL) || filter_fn(l_iter, user_data)))
{
do {
BMFace *f_other = l_radial_iter->f;
@@ -2461,7 +2516,7 @@ int BM_mesh_calc_face_groups(
/* search for other faces */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- if ((filter_fn == NULL) || filter_fn((BMElem *)l_iter->v, user_data)) {
+ if ((filter_fn == NULL) || filter_fn(l_iter, user_data)) {
BMLoop *l_other;
BM_ITER_ELEM (l_other, &liter, l_iter, BM_LOOPS_OF_LOOP) {
BMFace *f_other = l_other->f;
@@ -2508,7 +2563,7 @@ int BM_mesh_calc_face_groups(
*/
int BM_mesh_calc_edge_groups(
BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
+ BMVertFilterFunc filter_fn, void *user_data,
const char hflag_test)
{
#ifdef DEBUG
@@ -2597,7 +2652,7 @@ int BM_mesh_calc_edge_groups(
/* search for other edges */
BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
- if ((filter_fn == NULL) || filter_fn((BMElem *)v, user_data)) {
+ if ((filter_fn == NULL) || filter_fn(v, user_data)) {
BMEdge *e_other;
BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e_other, BM_ELEM_TAG) == false) {
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 2b18a5c8641..10e4b9a15aa 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -85,6 +85,7 @@ int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b);
bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -143,10 +144,15 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overla
bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BM_face_share_edge_count(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_face_share_edge_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_face_share_vert_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+bool BM_face_share_face_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_share_edge_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_share_vert_check(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+bool BM_loop_share_edge_check(BMLoop *l_a, BMLoop *l_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_share_face_check(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_share_edge_check(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -175,12 +181,12 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATT
int BM_mesh_calc_face_groups(
BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
+ BMLoopFilterFunc filter_fn, void *user_data,
const char hflag_test, const char htype_step)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
int BM_mesh_calc_edge_groups(
BMesh *bm, int *r_groups_array, int (**r_group_index)[2],
- BMElemFilterFunc filter_fn, void *user_data,
+ BMVertFilterFunc filter_fn, void *user_data,
const char hflag_test)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index d16eb572540..d39fb382b96 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -96,7 +96,7 @@ void BMW_init(
if (UNLIKELY(type >= BMW_MAXWALKERS || type < 0)) {
fprintf(stderr,
"%s: Invalid walker type in BMW_init; type: %d, "
- "searchmask: (v:%d, e:%d, f:%d), flag: %d, layer: %d\n",
+ "searchmask: (v:%d, e:%d, f:%d), flag: %u, layer: %d\n",
__func__, type, mask_vert, mask_edge, mask_face, flag, layer);
BLI_assert(0);
return;
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 28c3debb93c..627f8358410 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -475,7 +475,7 @@ static void bmw_LoopShellWireWalker_begin(BMWalker *walker, void *data)
bmw_LoopShellWireWalker_visitVert(walker, e->v1, NULL);
bmw_LoopShellWireWalker_visitVert(walker, e->v2, NULL);
}
- else {
+ else if (e->l) {
BMLoop *l_iter, *l_first;
l_iter = l_first = e->l;
@@ -928,7 +928,6 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
BMEdge *e, *nexte = NULL;
BMLoop *l;
BMVert *v;
- int i = 0;
BMW_state_remove_r(walker, &owalk);
lwalk = &owalk;
@@ -968,7 +967,7 @@ static void *bmw_EdgeLoopWalker_step(BMWalker *walker)
BMIter eiter;
/* match trunk: mark all connected wire edges */
- for (i = 0; i < 2; i++) {
+ for (int i = 0; i < 2; i++) {
v = i ? e->v2 : e->v1;
BM_ITER_ELEM (nexte, &eiter, v, BM_EDGES_OF_VERT) {
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index b4570e03c83..c7bf481d7d5 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -54,7 +54,8 @@ static void bm_bridge_splice_loops(BMesh *bm, LinkData *el_a, LinkData *el_b, co
interp_v3_v3v3(v_b->co, v_a->co, v_b->co, merge_factor);
BLI_assert(v_a != v_b);
BMO_slot_map_elem_insert(&op_weld, slot_targetmap, v_a, v_b);
- } while ((el_b = el_b->next),
+ } while ((void)
+ (el_b = el_b->next),
(el_a = el_a->next));
BMO_op_exec(bm, &op_weld);
@@ -95,7 +96,8 @@ static float bm_edgeloop_offset_length(
BLI_assert(el_a->prev == NULL); /* must be first */
do {
len += len_v3v3(((BMVert *)el_a->data)->co, ((BMVert *)el_b->data)->co);
- } while ((el_b = el_b->next ? el_b->next : el_b_first),
+ } while ((void)
+ (el_b = el_b->next ? el_b->next : el_b_first),
(el_a = el_a->next) && (len < len_max));
return len;
}
@@ -284,7 +286,7 @@ static void bridge_loop_pair(
if (el_store_a_len > el_store_b_len) {
el_store_b = BM_edgeloop_copy(el_store_b);
- BM_edgeloop_expand(bm, el_store_b, el_store_a_len);
+ BM_edgeloop_expand(bm, el_store_b, el_store_a_len, false, NULL);
el_store_b_free = true;
}
@@ -367,10 +369,10 @@ static void bridge_loop_pair(
f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true);
l_iter = BM_FACE_FIRST_LOOP(f);
- if (l_b) BM_elem_attrs_copy(bm, bm, l_b, l_iter); l_iter = l_iter->next;
- if (l_b_next) BM_elem_attrs_copy(bm, bm, l_b_next, l_iter); l_iter = l_iter->next;
- if (l_a_next) BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); l_iter = l_iter->next;
- if (l_a) BM_elem_attrs_copy(bm, bm, l_a, l_iter);
+ if (l_b) { BM_elem_attrs_copy(bm, bm, l_b, l_iter); } l_iter = l_iter->next;
+ if (l_b_next) { BM_elem_attrs_copy(bm, bm, l_b_next, l_iter); } l_iter = l_iter->next;
+ if (l_a_next) { BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); } l_iter = l_iter->next;
+ if (l_a) { BM_elem_attrs_copy(bm, bm, l_a, l_iter); }
}
}
else {
@@ -380,9 +382,9 @@ static void bridge_loop_pair(
f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true);
l_iter = BM_FACE_FIRST_LOOP(f);
- if (l_b) BM_elem_attrs_copy(bm, bm, l_b, l_iter); l_iter = l_iter->next;
- if (l_a_next) BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); l_iter = l_iter->next;
- if (l_a) BM_elem_attrs_copy(bm, bm, l_a, l_iter);
+ if (l_b) { BM_elem_attrs_copy(bm, bm, l_b, l_iter); } l_iter = l_iter->next;
+ if (l_a_next) { BM_elem_attrs_copy(bm, bm, l_a_next, l_iter); } l_iter = l_iter->next;
+ if (l_a) { BM_elem_attrs_copy(bm, bm, l_a, l_iter); }
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c
index 107aead6994..34f59aad4f1 100644
--- a/source/blender/bmesh/operators/bmo_connect_concave.c
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -42,6 +42,7 @@
#include "BLI_polyfill2d.h"
#include "BLI_polyfill2d_beautify.h"
#include "BLI_edgehash.h"
+#include "BLI_linklist.h"
#include "bmesh.h"
@@ -84,6 +85,7 @@ static bool bm_face_split_by_concave(
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
const int quad_method = 0, ngon_method = 0; /* beauty */
+ LinkNode *r_faces_double = NULL;
float normal[3];
BLI_assert(f_base->len > 3);
@@ -94,6 +96,7 @@ static bool bm_face_split_by_concave(
bm, f_base,
faces_array, &faces_array_tot,
edges_array, &edges_array_tot,
+ &r_faces_double,
quad_method, ngon_method, false,
pf_arena,
pf_heap, pf_ehash);
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index c9ce2c5f6b8..c80fb95c44a 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -120,8 +120,6 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
*r_angle = angle_best;
return found;
-
-
}
static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit)
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 12af8902dc5..3b860778e1c 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -494,6 +494,108 @@ static bool state_step(PathContext *pc, PathLinkState *state)
return (state_orig.link_last != state->link_last);
}
+/**
+ * Get a orientation matrix from 2 vertices.
+ */
+static void bm_vert_pair_to_matrix(BMVert *v_pair[2], float r_unit_mat[3][3])
+{
+ const float eps = 1e-8f;
+
+ float basis_dir[3];
+ float basis_tmp[3];
+ float basis_nor[3];
+
+ sub_v3_v3v3(basis_dir, v_pair[0]->co, v_pair[1]->co);
+ normalize_v3(basis_dir);
+
+#if 0
+ add_v3_v3v3(basis_nor, v_pair[0]->no, v_pair[1]->no);
+ cross_v3_v3v3(basis_tmp, basis_nor, basis_dir);
+ cross_v3_v3v3(basis_nor, basis_tmp, basis_dir);
+#else
+ /* align both normals to the directions before combining */
+ {
+ float basis_nor_a[3];
+ float basis_nor_b[3];
+
+ /* align normal to direction */
+ project_plane_v3_v3v3(basis_nor_a, v_pair[0]->no, basis_dir);
+ project_plane_v3_v3v3(basis_nor_b, v_pair[1]->no, basis_dir);
+
+ /* don't normalize before combining so as normals approach the direction, they have less effect (T46784). */
+
+ /* combine the normals */
+ /* for flipped faces */
+ if (dot_v3v3(basis_nor_a, basis_nor_b) < 0.0f) {
+ negate_v3(basis_nor_b);
+ }
+ add_v3_v3v3(basis_nor, basis_nor_a, basis_nor_b);
+ }
+#endif
+
+ /* get third axis */
+ normalize_v3(basis_nor);
+ cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
+
+
+ /* Try get the axis from surrounding faces, fallback to 'ortho_v3_v3' */
+ if (UNLIKELY(normalize_v3(basis_tmp) < eps)) {
+ /* vertex normals are directly opposite */
+
+ /* find the loop with the lowest angle */
+ struct { float nor[3]; float angle_cos; } axis_pair[2];
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ BMIter liter;
+ BMLoop *l;
+
+ zero_v2(axis_pair[i].nor);
+ axis_pair[i].angle_cos = -FLT_MAX;
+
+ BM_ITER_ELEM (l, &liter, v_pair[i], BM_LOOPS_OF_VERT) {
+ float basis_dir_proj[3];
+ float angle_cos_test;
+
+ /* project basis dir onto the normal to find its closest angle */
+ project_plane_v3_v3v3(basis_dir_proj, basis_dir, l->f->no);
+
+ if (normalize_v3(basis_dir_proj) > eps) {
+ angle_cos_test = dot_v3v3(basis_dir_proj, basis_dir);
+
+ if (angle_cos_test > axis_pair[i].angle_cos) {
+ axis_pair[i].angle_cos = angle_cos_test;
+ copy_v3_v3(axis_pair[i].nor, basis_dir_proj);
+ }
+ }
+ }
+ }
+
+ /* create a new 'basis_nor' from the best direction.
+ * note: we could add the directions,
+ * but this more often gives 45d rotated matrix, so just use the best one. */
+ copy_v3_v3(basis_nor, axis_pair[axis_pair[0].angle_cos < axis_pair[1].angle_cos].nor);
+ project_plane_v3_v3v3(basis_nor, basis_nor, basis_dir);
+
+ cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
+
+ /* last resort, pick _any_ ortho axis */
+ if (UNLIKELY(normalize_v3(basis_tmp) < eps)) {
+ ortho_v3_v3(basis_nor, basis_dir);
+ normalize_v3(basis_nor);
+ cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
+ normalize_v3(basis_tmp);
+ }
+ }
+
+ copy_v3_v3(r_unit_mat[0], basis_tmp);
+ copy_v3_v3(r_unit_mat[1], basis_dir);
+ copy_v3_v3(r_unit_mat[2], basis_nor);
+ if (invert_m3(r_unit_mat) == false) {
+ unit_m3(r_unit_mat);
+ }
+}
+
void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
{
BMOpSlot *op_verts_slot = BMO_slot_get(op->slots_in, "verts");
@@ -532,60 +634,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
/* calculate matrix */
{
- float basis_dir[3];
- float basis_tmp[3];
- float basis_nor[3];
-
-
- sub_v3_v3v3(basis_dir, pc.v_a->co, pc.v_b->co);
-
-#if 0
- add_v3_v3v3(basis_nor, pc.v_a->no, pc.v_b->no);
- cross_v3_v3v3(basis_tmp, basis_nor, basis_dir);
- cross_v3_v3v3(basis_nor, basis_tmp, basis_dir);
-#else
- /* align both normals to the directions before combining */
- {
- float basis_nor_a[3];
- float basis_nor_b[3];
-
- /* align normal to direction */
- cross_v3_v3v3(basis_tmp, pc.v_a->no, basis_dir);
- cross_v3_v3v3(basis_nor_a, basis_tmp, basis_dir);
-
- cross_v3_v3v3(basis_tmp, pc.v_b->no, basis_dir);
- cross_v3_v3v3(basis_nor_b, basis_tmp, basis_dir);
-
- /* combine the normals */
- normalize_v3(basis_nor_a);
- normalize_v3(basis_nor_b);
-
- /* for flipped faces */
- if (dot_v3v3(basis_nor_a, basis_nor_b) < 0.0f) {
- negate_v3(basis_nor_b);
- }
- add_v3_v3v3(basis_nor, basis_nor_a, basis_nor_b);
- }
-#endif
-
- /* get third axis */
- normalize_v3(basis_dir);
- normalize_v3(basis_nor);
- cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
- if (UNLIKELY(normalize_v3(basis_tmp) < FLT_EPSILON)) {
- ortho_v3_v3(basis_nor, basis_dir);
- normalize_v3(basis_nor);
- cross_v3_v3v3(basis_tmp, basis_dir, basis_nor);
- normalize_v3(basis_tmp);
- }
-
- copy_v3_v3(pc.matrix[0], basis_tmp);
- copy_v3_v3(pc.matrix[1], basis_dir);
- copy_v3_v3(pc.matrix[2], basis_nor);
- if (invert_m3(pc.matrix) == false) {
- unit_m3(pc.matrix);
- }
-
+ bm_vert_pair_to_matrix(&pc.v_a, pc.matrix);
pc.axis_sep = dot_m3_v3_row_x(pc.matrix, pc.v_a->co);
}
diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c
index 1c054e89e39..a1e20dab63e 100644
--- a/source/blender/bmesh/operators/bmo_create.c
+++ b/source/blender/bmesh/operators/bmo_create.c
@@ -291,6 +291,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op)
if (use_smooth) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
}
+ BM_face_copy_shared(bm, f, NULL, NULL);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, ELE_OUT);
}
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index ac0466a74d2..c8dff4a8598 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -544,7 +544,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op)
if (
/* check the loop hasn't already been tested (and flag not to test again) */
!BM_elem_flag_test(l_iter, BM_ELEM_TAG) &&
- (BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
+ ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG),
/* check we're marked to tested (radial edge already tested) */
BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_MARK) &&
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index 33048e6c86e..fd430de80f9 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -170,7 +170,8 @@ static BMFace *bmo_face_copy(
l_iter_dst = BM_FACE_FIRST_LOOP(f_dst);
do {
BM_elem_attrs_copy(bm_src, bm_dst, l_iter_src, l_iter_dst);
- } while ((l_iter_dst = l_iter_dst->next),
+ } while ((void)
+ (l_iter_dst = l_iter_dst->next),
(l_iter_src = l_iter_src->next) != l_first_src);
/* Mark the face for output */
diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c
index 4423123f65e..f348014cead 100644
--- a/source/blender/bmesh/operators/bmo_edgenet.c
+++ b/source/blender/bmesh/operators/bmo_edgenet.c
@@ -73,8 +73,8 @@ void bmo_edgenet_fill_exec(BMesh *bm, BMOperator *op)
/* --- Attribute Fill --- */
/* may as well since we have the faces already in a buffer */
BMO_op_initf(bm, &op_attr, op->flag,
- "face_attribute_fill faces=%S use_normals=%b",
- op, "faces.out", true);
+ "face_attribute_fill faces=%S use_normals=%b use_data=%b",
+ op, "faces.out", true, true);
BMO_op_exec(bm, &op_attr);
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 4449f223f35..5a3bef6ba81 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -116,7 +116,8 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
}
}
- } while (((l_new = l_new->next),
+ } while (((void)
+ (l_new = l_new->next),
(l_org = l_org->next)) != l_org_first);
}
@@ -728,9 +729,9 @@ static void solidify_add_thickness(BMesh *bm, const float dist)
if (BMO_elem_flag_test(bm, f, FACE_MARK)) {
/* array for passing verts to angle_poly_v3 */
- float *face_angles = BLI_buffer_resize_data(&face_angles_buf, float, f->len);
+ float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len);
/* array for receiving angles from angle_poly_v3 */
- float **verts = BLI_buffer_resize_data(&verts_buf, float *, f->len);
+ float **verts = BLI_buffer_reinit_data(&verts_buf, float *, f->len);
BM_ITER_ELEM_INDEX (l, &loopIter, f, BM_LOOPS_OF_FACE, i) {
verts[i] = l->v->co;
@@ -772,6 +773,7 @@ void bmo_solidify_face_region_exec(BMesh *bm, BMOperator *op)
/* Flip original faces (so the shell is extruded inward) */
BMO_op_init(bm, &reverseop, op->flag, "reverse_faces");
+ BMO_slot_bool_set(reverseop.slots_in, "flip_multires", true);
BMO_slot_copy(op, slots_in, "geom",
&reverseop, slots_in, "faces");
BMO_op_exec(bm, &reverseop);
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index 85bca744d86..233ed746ed4 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -53,9 +53,9 @@ static bool bm_loop_is_all_radial_tag(BMLoop *l)
/**
* Callback to run on source-loops for #BM_face_copy_shared
*/
-static bool bm_loop_is_face_untag(BMElem *ele, void *UNUSED(user_data))
+static bool bm_loop_is_face_untag(const BMLoop *l, void *UNUSED(user_data))
{
- return (BM_elem_flag_test(((BMLoop *)ele)->f, BM_ELEM_TAG) == 0);
+ return (BM_elem_flag_test(l->f, BM_ELEM_TAG) == 0);
}
/**
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index fd1e91a0b30..77556591728 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -569,6 +569,20 @@ static void bm_grid_fill(
#undef USE_FLIP_DETECT
}
+static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, bool set)
+{
+ /* only handle closed loops in this case */
+ LinkData *link = BM_edgeloop_verts_get(estore)->first;
+ link = link->next;
+ while (link) {
+ BMEdge *e = BM_edge_exists(link->data, link->prev->data);
+ if (e) {
+ BM_elem_flag_set(e, hflag, set);
+ }
+ link = link->next;
+ }
+}
+
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
{
return BMO_elem_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK);
@@ -595,6 +609,7 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op)
const short mat_nr = (short)BMO_slot_int_get(op->slots_in, "mat_nr");
const bool use_smooth = BMO_slot_bool_get(op->slots_in, "use_smooth");
const bool use_interp_simple = BMO_slot_bool_get(op->slots_in, "use_interp_simple");
+ GSet *split_edges = NULL;
int count;
bool changed = false;
@@ -616,12 +631,6 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op)
v_b_first = ((LinkData *)BM_edgeloop_verts_get(estore_b)->first)->data;
v_b_last = ((LinkData *)BM_edgeloop_verts_get(estore_b)->last)->data;
- if (BM_edgeloop_length_get(estore_a) != BM_edgeloop_length_get(estore_b)) {
- BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
- "Edge loop vertex count mismatch");
- goto cleanup;
- }
-
if (BM_edgeloop_is_closed(estore_a) || BM_edgeloop_is_closed(estore_b)) {
BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
"Closed loops unsupported");
@@ -630,71 +639,89 @@ void bmo_grid_fill_exec(BMesh *bm, BMOperator *op)
/* ok. all error checking done, now we can find the rail edges */
- if (BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_first) == false) {
- BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
- "Loops are not connected by wire/boundary edges");
- goto cleanup;
- }
-
- /* We may find a first path, but not a second one! See geometry attached to bug [#37388]. */
- if (BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_last) == false) {
- BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
- "Loops are not connected by wire/boundary edges");
- goto cleanup;
- }
- /* Check flipping by comparing path length */
- estore_rail_a = eloops_rail.first;
- estore_rail_b = eloops_rail.last;
+ /* cheat here, temp hide all edges so they won't be included in rails
+ * this puts the mesh in an invalid state for a short time. */
+ bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, true);
+ bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, true);
- BLI_assert(BM_edgeloop_length_get(estore_rail_a) != BM_edgeloop_length_get(estore_rail_b));
-
- if (BM_edgeloop_length_get(estore_rail_a) < BM_edgeloop_length_get(estore_rail_b)) {
- BLI_remlink(&eloops_rail, estore_rail_b);
- BM_edgeloop_free(estore_rail_b);
- estore_rail_b = NULL;
-
- BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, (void *)bm,
- v_a_last,
- v_b_last);
+ if ((BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_first)) &&
+ (BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_last)))
+ {
+ estore_rail_a = eloops_rail.first;
estore_rail_b = eloops_rail.last;
}
- else { /* a > b */
- BLI_remlink(&eloops_rail, estore_rail_a);
- BM_edgeloop_free(estore_rail_a);
- estore_rail_a = estore_rail_b;
-
- /* reverse so both are sorted the same way */
- BM_edgeloop_flip(bm, estore_b);
- SWAP(BMVert *, v_b_first, v_b_last);
-
- BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, (void *)bm,
- v_a_last,
- v_b_last);
- estore_rail_b = eloops_rail.last;
+ else {
+ BM_mesh_edgeloops_free(&eloops_rail);
+
+ if ((BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_first, v_b_last)) &&
+ (BM_mesh_edgeloops_find_path(bm, &eloops_rail, bm_edge_test_rail_cb, bm, v_a_last, v_b_first)))
+ {
+ estore_rail_a = eloops_rail.first;
+ estore_rail_b = eloops_rail.last;
+ BM_edgeloop_flip(bm, estore_b);
+ }
+ else {
+ BM_mesh_edgeloops_free(&eloops_rail);
+ }
}
- BLI_assert(estore_a != estore_b);
- BLI_assert(v_a_last != v_b_last);
+ bm_edgeloop_flag_set(estore_a, BM_ELEM_HIDDEN, false);
+ bm_edgeloop_flag_set(estore_b, BM_ELEM_HIDDEN, false);
+
- if (BM_edgeloop_length_get(estore_rail_a) != BM_edgeloop_length_get(estore_rail_b)) {
+ if (BLI_listbase_is_empty(&eloops_rail)) {
BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
- "Connecting edges vertex mismatch");
+ "Loops are not connected by wire/boundary edges");
goto cleanup;
}
+ BLI_assert(estore_a != estore_b);
+ BLI_assert(v_a_last != v_b_last);
+
if (BM_edgeloop_overlap_check(estore_rail_a, estore_rail_b)) {
BMO_error_raise(bm, op, BMERR_INVALID_SELECTION,
"Connecting edge loops overlap");
goto cleanup;
}
+ /* add vertices if needed */
+ {
+ struct BMEdgeLoopStore *estore_pairs[2][2] = {{estore_a, estore_b}, {estore_rail_a, estore_rail_b}};
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ const int len_a = BM_edgeloop_length_get(estore_pairs[i][0]);
+ const int len_b = BM_edgeloop_length_get(estore_pairs[i][1]);
+ if (len_a != len_b) {
+ if (split_edges == NULL) {
+ split_edges = BLI_gset_ptr_new(__func__);
+ }
+
+ if (len_a < len_b) {
+ BM_edgeloop_expand(bm, estore_pairs[i][0], len_b, true, split_edges);
+ }
+ else {
+ BM_edgeloop_expand(bm, estore_pairs[i][1], len_a, true, split_edges);
+ }
+ }
+ }
+ }
+
/* finally we have all edge loops needed */
bm_grid_fill(bm, estore_a, estore_b, estore_rail_a, estore_rail_b,
mat_nr, use_smooth, use_interp_simple);
changed = true;
+ if (split_edges) {
+ GSetIterator gs_iter;
+ GSET_ITER (gs_iter, split_edges) {
+ BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
+ BM_edge_collapse(bm, e, e->v2, true, true);
+ }
+ BLI_gset_free(split_edges, NULL);
+ }
cleanup:
BM_mesh_edgeloops_free(&eloops);
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index 118a19d3082..ef5d90e6acb 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -94,7 +94,7 @@ static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemAre
/* use later for index lookups */
BM_elem_index_set(l_iter, i); /* set_dirty */
- } while (i++, (l_iter = l_iter->next) != l_first);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
bm->elem_index_dirty |= BM_LOOP;
}
static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
@@ -173,7 +173,7 @@ static void bm_loop_customdata_merge(
l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner);
BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v);
- /* check if ther is no chance of diversion */
+ /* check if there is no chance of diversion */
if (l_a_inner_inset->f == l_b_inner_inset->f) {
return;
}
@@ -293,7 +293,7 @@ static void bmo_face_inset_individual(
/* unrelated to splitting, but calc here */
BM_edge_calc_face_tangent(l_iter->e, l_iter, edge_nors[i]);
- } while (i++, ((l_iter = l_iter->next) != l_first));
+ } while ((void)i++, ((l_iter = l_iter->next) != l_first));
/* build rim faces */
@@ -324,7 +324,7 @@ static void bmo_face_inset_individual(
BM_elem_attrs_copy(bm, bm, l_iter->next, l_other);
BM_elem_attrs_copy(bm, bm, l_iter, l_other->next);
}
- } while (i++, ((l_iter = l_iter->next) != l_first));
+ } while ((void)i++, ((l_iter = l_iter->next) != l_first));
/* hold interpolation values */
if (use_interpolate) {
@@ -376,14 +376,14 @@ static void bmo_face_inset_individual(
copy_v3_v3(coords[i], v_new_co);
- } while (i++, ((l_iter = l_iter->next) != l_first));
+ } while ((void)i++, ((l_iter = l_iter->next) != l_first));
/* update the coords */
l_iter = l_first;
i = 0;
do {
copy_v3_v3(l_iter->v->co, coords[i]);
- } while (i++, ((l_iter = l_iter->next) != l_first));
+ } while ((void)i++, ((l_iter = l_iter->next) != l_first));
if (use_interpolate) {
@@ -571,7 +571,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
BMVert *v;
BMEdge *e;
BMFace *f;
- int i, j, k;
+ int i, k;
if (use_interpolate) {
interp_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -722,7 +722,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
* here but don't do this since we will be splitting them off (iterating stuff you modify is bad juju)
* instead loop over edges then their verts */
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
- for (j = 0; j < 2; j++) {
+ for (int j = 0; j < 2; j++) {
v = (j == 0) ? es->e_new->v1 : es->e_new->v2;
/* end confusing part - just pretend this is a typical loop on verts */
@@ -1004,6 +1004,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
/* create faces */
for (i = 0, es = edge_info; i < edge_info_len; i++, es++) {
BMVert *varr[4] = {NULL};
+ int j;
/* get the verts in the correct order */
BM_edge_ordered_verts_ex(es->e_new, &varr[1], &varr[0], es->l);
#if 0
@@ -1095,6 +1096,8 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)];
const int i_a = BM_elem_index_get(l_a_other);
const int i_b = BM_elem_index_get(l_b_other);
+ CustomData_bmesh_free_block_data(&bm->ldata, l_b->head.data);
+ CustomData_bmesh_free_block_data(&bm->ldata, l_a->head.data);
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_a], &l_b->head.data);
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_b], &l_a->head.data);
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index f62e445ca18..6044960265b 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -41,9 +41,9 @@
#define FACE_FLIP (1 << 1)
#define FACE_TEMP (1 << 2)
-static bool bmo_recalc_normal_edge_filter_cb(BMElem *ele, void *UNUSED(user_data))
+static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_data))
{
- return BM_edge_is_manifold((BMEdge *)ele);
+ return BM_edge_is_manifold(l->e);
}
/**
@@ -69,48 +69,47 @@ static bool bmo_recalc_normal_edge_filter_cb(BMElem *ele, void *UNUSED(user_data
* In the example above, the a\ face can point towards the \a center
* which would end up flipping the normals inwards.
*
- * To take these spikes into account, use the normals of the faces edges.
+ * To take these spikes into account, find the furthest face-loop-vertex.
*/
-#define USE_FACE_EDGE_NORMAL_TEST
-
-/**
- * The center of the entire island is't necessarily well placed,
- *
- * This re-calculated a center relative to this face.
- */
-#ifdef USE_FACE_EDGE_NORMAL_TEST
-# define USE_FACE_LOCAL_CENTER_TEST
-#endif
/**
* \return a face index in \a faces and set \a r_is_flip if the face is flipped away from the center.
*/
static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int faces_len, bool *r_is_flip)
{
+ const float eps = FLT_EPSILON;
float cent_area_accum = 0.0f;
- float f_len_best_sq;
-
- float cent[3], tvec[3];
+ float cent[3];
const float cent_fac = 1.0f / (float)faces_len;
- float (*faces_center)[3] = MEM_mallocN(sizeof(*faces_center) * faces_len, __func__);
- float *faces_area = MEM_mallocN(sizeof(*faces_area) * faces_len, __func__);
bool is_flip = false;
int f_start_index;
int i;
+ /* Search for the best loop. Members are comapred in-order defined here. */
+ struct {
+ /* Squared distance from the center to the loops vertex 'l->v'.
+ * The normalized direction between the center and this vertex is also used for the dot-products below. */
+ float dist_sq;
+ /* Signed dot product using the normalized edge vector,
+ * (best of 'l->prev->v' or 'l->next->v'). */
+ float edge_dot;
+ /* Unsigned dot product using the loop-normal
+ * (sign is used to check if we need to flip) */
+ float loop_dot;
+ } best, test;
+
UNUSED_VARS_NDEBUG(bm);
zero_v3(cent);
/* first calculate the center */
for (i = 0; i < faces_len; i++) {
- float *f_cent = faces_center[i];
+ float f_cent[3];
const float f_area = BM_face_calc_area(faces[i]);
BM_face_calc_center_mean_weighted(faces[i], f_cent);
madd_v3_v3fl(cent, f_cent, cent_fac * f_area);
cent_area_accum += f_area;
- faces_area[i] = f_area;
BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0);
BLI_assert(BM_face_is_normal_valid(faces[i]));
@@ -120,82 +119,69 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f
mul_v3_fl(cent, 1.0f / cent_area_accum);
}
- f_len_best_sq = -FLT_MAX;
+ /* Distances must start above zero,
+ * or we can't do meaningful calculations based on the direction to the center */
+ best.dist_sq = eps;
+ best.edge_dot = best.loop_dot = -FLT_MAX;
+
/* used in degenerate cases only */
f_start_index = 0;
+ /**
+ * Find the outer-most vertex, comparing distance to the center,
+ * then the outer-most loop attached to that vertex.
+ *
+ * Important this is correctly detected,
+ * where casting a ray from the center wont hit any loops past this one.
+ * Otherwise the result may be incorrect.
+ */
for (i = 0; i < faces_len; i++) {
- float f_len_test_sq;
-
- if (faces_area[i] > FLT_EPSILON) {
- if ((f_len_test_sq = len_squared_v3v3(faces_center[i], cent)) > f_len_best_sq) {
- f_len_best_sq = f_len_test_sq;
- f_start_index = i;
- }
- }
- }
-
-#ifdef USE_FACE_EDGE_NORMAL_TEST
- {
- BMFace *f_test = faces[f_start_index];
BMLoop *l_iter, *l_first;
- float e_len_best_sq = -FLT_MAX;
- BMLoop *l_other_best = NULL;
- float no_edge[3];
- const float *no_best;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f_test);
+ l_iter = l_first = BM_FACE_FIRST_LOOP(faces[i]);
do {
- if (BM_edge_is_manifold(l_iter->e) &&
- bmo_recalc_normal_edge_filter_cb((BMElem *)l_iter->e, NULL))
- {
- BMLoop *l_other = l_iter->radial_next;
-
- if (len_squared_v3v3(l_iter->v->co, l_iter->next->v->co) > FLT_EPSILON) {
- float e_len_test_sq;
- float e_cent[3];
- mid_v3_v3v3(e_cent, l_iter->v->co, l_iter->next->v->co);
- e_len_test_sq = len_squared_v3v3(cent, e_cent);
- if (e_len_test_sq > e_len_best_sq) {
- l_other_best = l_other;
- e_len_best_sq = e_len_test_sq;
+ bool is_best_dist_sq;
+ float dir[3];
+ sub_v3_v3v3(dir, l_iter->v->co, cent);
+ test.dist_sq = len_squared_v3(dir);
+ is_best_dist_sq = (test.dist_sq > best.dist_sq);
+ if (is_best_dist_sq || (test.dist_sq == best.dist_sq)) {
+ float edge_dir_pair[2][3];
+ mul_v3_fl(dir, 1.0f / sqrtf(test.dist_sq));
+
+ sub_v3_v3v3(edge_dir_pair[0], l_iter->next->v->co, l_iter->v->co);
+ sub_v3_v3v3(edge_dir_pair[1], l_iter->prev->v->co, l_iter->v->co);
+
+ if ((normalize_v3(edge_dir_pair[0]) > eps) &&
+ (normalize_v3(edge_dir_pair[1]) > eps))
+ {
+ bool is_best_edge_dot;
+ test.edge_dot = max_ff(dot_v3v3(dir, edge_dir_pair[0]),
+ dot_v3v3(dir, edge_dir_pair[1]));
+ is_best_edge_dot = (test.edge_dot > best.edge_dot);
+ if (is_best_dist_sq || is_best_edge_dot || (test.edge_dot == best.edge_dot)) {
+ float loop_dir[3];
+ cross_v3_v3v3(loop_dir, edge_dir_pair[0], edge_dir_pair[1]);
+ if (normalize_v3(loop_dir) > eps) {
+ float loop_dir_dot;
+ /* Highly unlikely the furthest loop is also the concave part of an ngon,
+ * but it can be contrived with _very_ non-planar faces - so better check. */
+ if (UNLIKELY(dot_v3v3(loop_dir, l_iter->f->no) < 0.0f)) {
+ negate_v3(loop_dir);
+ }
+ loop_dir_dot = dot_v3v3(dir, loop_dir);
+ test.loop_dot = fabsf(loop_dir_dot);
+ if (is_best_dist_sq || is_best_edge_dot || (test.loop_dot > best.loop_dot)) {
+ best = test;
+ f_start_index = i;
+ is_flip = (loop_dir_dot < 0.0f);
+ }
+ }
}
}
}
} while ((l_iter = l_iter->next) != l_first);
-
- /* furthest edge on furthest face */
- if (l_other_best) {
- float e_cent[3];
-
-#ifdef USE_FACE_LOCAL_CENTER_TEST
- {
- float f_cent_other[3];
- BM_face_calc_center_mean_weighted(l_other_best->f, f_cent_other);
- mid_v3_v3v3(cent, f_cent_other, faces_center[f_start_index]);
- }
-#endif
- mid_v3_v3v3(e_cent, l_other_best->e->v1->co, l_other_best->e->v2->co);
- sub_v3_v3v3(tvec, e_cent, cent);
-
- madd_v3_v3v3fl(no_edge, f_test->no, l_other_best->f->no, BM_edge_is_contiguous(l_other_best->e) ? 1 : -1);
- no_best = no_edge;
- }
- else {
- sub_v3_v3v3(tvec, faces_center[f_start_index], cent);
- no_best = f_test->no;
- }
-
- is_flip = (dot_v3v3(tvec, no_best) < 0.0f);
}
-#else
- sub_v3_v3v3(tvec, faces_center[f_start_index], cent);
- is_flip = (dot_v3v3(tvec, faces[f_start_index]->no) < 0.0f);
-#endif
-
- /* make sure the starting face has the correct winding */
- MEM_freeN(faces_center);
- MEM_freeN(faces_area);
*r_is_flip = is_flip;
return f_start_index;
@@ -243,7 +229,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
do {
BMLoop *l_other = l_iter->radial_next;
- if ((l_other != l_iter) && bmo_recalc_normal_edge_filter_cb((BMElem *)l_iter->e, NULL)) {
+ if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) {
if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) {
BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP);
BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state);
@@ -278,9 +264,10 @@ void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op)
BMFace **faces_grp = MEM_mallocN(sizeof(*faces_grp) * bm->totface, __func__);
int (*group_index)[2];
- const int group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index,
- bmo_recalc_normal_edge_filter_cb, NULL,
- 0, BM_EDGE);
+ const int group_tot = BM_mesh_calc_face_groups(
+ bm, groups_array, &group_index,
+ bmo_recalc_normal_loop_filter_cb, NULL,
+ 0, BM_EDGE);
int i;
BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG);
diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
index a2f3f0bb519..8f4bc5ef3ad 100644
--- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c
+++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c
@@ -278,7 +278,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op)
}
while ((v = STACK_POP(varr))) {
- bmesh_jekv(bm, v->e, v, true, false);
+ bmesh_jekv(bm, v->e, v, true, false, false);
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c
index 363e395e082..4d86d6e8e5b 100644
--- a/source/blender/bmesh/operators/bmo_poke.c
+++ b/source/blender/bmesh/operators/bmo_poke.c
@@ -34,6 +34,8 @@
#include "intern/bmesh_operators_private.h" /* own include */
+#include "BKE_customdata.h"
+
#define ELE_NEW 1
/**
@@ -45,13 +47,14 @@
*/
void bmo_poke_exec(BMesh *bm, BMOperator *op)
{
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
BMOIter oiter;
BMFace *f;
const float offset = BMO_slot_float_get(op->slots_in, "offset");
const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
const int center_mode = BMO_slot_int_get(op->slots_in, "center_mode");
- void (*bm_face_calc_center_fn)(BMFace *f, float r_cent[3]);
+ void (*bm_face_calc_center_fn)(const BMFace *f, float r_cent[3]);
switch (center_mode) {
case BMOP_POKE_MEAN_WEIGHTED:
@@ -70,7 +73,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) {
BMFace *f_new;
- float f_center[3];
+ float f_center[3], f_center_mean[3];
BMVert *v_center = NULL;
BMLoop *l_iter, *l_first;
/* only interpolate the central loop from the face once,
@@ -86,6 +89,15 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, v_center, ELE_NEW);
+ if (cd_loop_mdisp_offset != -1) {
+ if (center_mode == BMOP_POKE_MEAN) {
+ copy_v3_v3(f_center_mean, f_center);
+ }
+ else {
+ BM_face_calc_center_mean(f, f_center_mean);
+ }
+ }
+
/* handled by BM_loop_interp_from_face */
// BM_vert_interp_from_face(bm, v_center, f);
@@ -106,7 +118,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
if (i == 0) {
l_center_example = l_new->prev;
- BM_loop_interp_from_face(bm, l_center_example, f, true, true);
+ BM_loop_interp_from_face(bm, l_center_example, f, true, false);
}
else {
BM_elem_attrs_copy(bm, bm, l_center_example, l_new->prev);
@@ -118,11 +130,17 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
BMO_elem_flag_enable(bm, f_new, ELE_NEW);
+ if (cd_loop_mdisp_offset != -1) {
+ float f_new_center[3];
+ BM_face_calc_center_mean(f_new, f_new_center);
+ BM_face_interp_multires_ex(bm, f_new, f, f_new_center, f_center, cd_loop_mdisp_offset);
+ }
+
if (use_relative_offset) {
offset_fac += len_v3v3(f_center, l_iter->v->co);
}
- } while (i++, (l_iter = l_iter->next) != l_first);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
if (use_relative_offset) {
offset_fac /= (float)f->len;
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index 2108a2c0589..e3be4db804b 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -30,6 +30,10 @@
#include "BLI_math.h"
+#include "BKE_customdata.h"
+
+#include "DNA_meshdata_types.h"
+
#include "bmesh.h"
#include "intern/bmesh_operators_private.h"
@@ -74,10 +78,6 @@ static const short icoface[20][3] = {
{10, 9, 11}
};
-/* HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
- * this hack is only used so that scons & mingw + split-sources hack works
- * ------------------------------- start copied code */
-/* these are not the monkeys you are looking for */
static const int monkeyo = 4;
static const int monkeynv = 271;
static const int monkeynf = 250;
@@ -235,6 +235,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
const unsigned int ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments"));
const float xtot_inv2 = 2.0f / (xtot - 1);
const float ytot_inv2 = 2.0f / (ytot - 1);
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert **varr;
BMVert *vquad[4];
@@ -257,7 +258,9 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
for (x = 0; x < xtot; x++) {
vec[0] = ((x * xtot_inv2) - 1.0f) * dia;
mul_v3_m4v3(tvec, mat, vec);
- varr[i++] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
+ varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP);
+ BMO_elem_flag_enable(bm, varr[i], VERT_MARK);
+ i++;
}
}
@@ -265,17 +268,86 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op)
for (y = 1; y < ytot; y++) {
for (x = 1; x < xtot; x++) {
+ BMFace *f;
+
vquad[0] = varr[XY(x - 1, y - 1)];
vquad[1] = varr[XY(x, y - 1)];
vquad[2] = varr[XY(x, y)];
vquad[3] = varr[XY(x - 1, y)];
- BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true);
+ f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
}
}
#undef XY
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK);
+ }
+}
+
+/**
+ * Fills first available UVmap with grid-like UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on
+ * \param x_segments The x-resolution of the grid
+ * \param y_segments The y-resolution of the grid
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const float dx = 1.0f / (float)(x_segments - 1);
+ const float dy = 1.0f / (float)(y_segments - 1);
+ float x = 0.0f;
+ float y = 0.0f;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ int loop_index;
+
+ BLI_assert(cd_loop_uv_offset != -1);
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (loop_index) {
+ case 0:
+ x += dx;
+ break;
+ case 1:
+ y += dy;
+ break;
+ case 2:
+ x -= dx;
+ break;
+ case 3:
+ y -= dy;
+ break;
+ default:
+ break;
+ }
+
+ luv->uv[0] = x;
+ luv->uv[1] = y;
+ }
+
+ x += dx;
+ if (x >= 1.0f) {
+ x = 0.0f;
+ y += dy;
+ }
+ }
}
void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
@@ -283,6 +355,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const int seg = BMO_slot_int_get(op->slots_in, "u_segments");
const int tot = BMO_slot_int_get(op->slots_in, "v_segments");
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMOperator bmop, prevop;
BMVert *eve, *preveve;
@@ -303,8 +376,8 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
phid /= 2;
for (a = 0; a <= tot; a++) {
/* Going in this direction, then edge extruding, makes normals face outward */
- vec[0] = -dia * sinf(phi);
- vec[1] = 0.0;
+ vec[0] = 0.0;
+ vec[1] = dia * sinf(phi);
vec[2] = dia * cosf(phi);
eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, eve, VERT_MARK);
@@ -358,6 +431,31 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op)
BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f);
}
+ if (calc_uvs) {
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices
+ * being tagged. */
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ bool valid = true;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+ }
+
+ BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
+ }
+
/* and now do imat */
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, eve, VERT_MARK)) {
@@ -373,6 +471,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
const float dia = BMO_slot_float_get(op->slots_in, "diameter");
const float dia_div = dia / 200.0f;
const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions");
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert *eva[12];
BMVert *v;
@@ -431,6 +530,30 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_op_finish(bm, &bmop);
}
+ if (calc_uvs) {
+ BMFace *f;
+ BMIter fiter;
+
+ /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices
+ * being tagged. */
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ bool valid = true;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
+ valid = false;
+ break;
+ }
+ }
+
+ if (valid) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+ }
+
+ BM_mesh_calc_uvs_sphere(bm, FACE_MARK);
+ }
+
/* must transform after because of sphere subdivision */
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
@@ -441,9 +564,77 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const int cd_loop_uv_offset)
+{
+ float *uvs[4];
+ BMLoop *l;
+ BMIter iter;
+ float dx;
+ int loop_index, loop_index_max_x;
+
+ BLI_assert(f->len <= 4);
+
+ BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float vco[3];
+
+ mul_v3_m3v3(vco, mat_rot, l->v->co);
+ map_to_sphere(&luv->uv[0], &luv->uv[1], vco[0], vco[1], vco[2]);
+
+ uvs[loop_index] = luv->uv;
+ }
+
+ /* Fix awkwardly-wrapping UVs */
+ loop_index_max_x = 0;
+ for (loop_index = 1; loop_index < f->len; loop_index++) {
+ if (uvs[loop_index][0] > uvs[loop_index_max_x][0]) {
+ loop_index_max_x = loop_index;
+ }
+ }
+
+ for (loop_index = 0; loop_index < f->len; loop_index++) {
+ if (loop_index != loop_index_max_x) {
+ dx = uvs[loop_index_max_x][0] - uvs[loop_index][0];
+ if (dx > 0.5f) {
+ uvs[loop_index][0] += 1.0f;
+ }
+ }
+ }
+}
+
+/**
+ * Fills first available UVmap with spherical projected UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag)
+{
+ BMFace *f;
+ BMIter iter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ /* We apply a 'magic' rotationto vcos before mapping them to sphere,
+ * those values seem to give best results for both ico and uv sphere projections. */
+ float mat_rot[3][3];
+ const float axis[3] = {0.806f, 0.329f, 0.491f};
+ const float angle = DEG2RADF(120.0f);
+
+ axis_angle_to_mat3(mat_rot, axis, angle);
+
+ BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset);
+ }
+}
+
void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
{
- BMVert *eve;
BMVert **tv = MEM_mallocN(sizeof(*tv) * monkeynv * 2, "tv");
float mat[4][4];
int i;
@@ -461,9 +652,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, tv[i], VERT_MARK);
- tv[monkeynv + i] = (fabsf(v[0] = -v[0]) < 0.001f) ?
- tv[i] :
- (eve = BM_vert_create(bm, v, NULL, BM_CREATE_NOP), mul_m4_v3(mat, eve->co), eve);
+ if (fabsf(v[0] = -v[0]) < 0.001f) {
+ tv[monkeynv + i] = tv[i];
+ }
+ else {
+ BMVert *eve = BM_vert_create(bm, v, NULL, BM_CREATE_NOP);
+ mul_m4_v3(mat, eve->co);
+ tv[monkeynv + i] = eve;
+ }
BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK);
@@ -498,6 +694,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
const int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL;
float vec[3], mat[4][4], phi, phid;
@@ -555,6 +752,10 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
+
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW);
+ }
}
if (!cap_tris) {
@@ -564,9 +765,54 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+/**
+ * Fills first available UVmap with 2D projected UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on.
+ * \param mat The transform matrix applied to the created circle.
+ * \param radius The size of the circle.
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ const float uv_scale = 0.5f / radius;
+ const float uv_center = 0.5f;
+
+ float inv_mat[4][4];
+
+ BLI_assert(cd_loop_uv_offset != -1); /* caller must ensure we have UVs already */
+
+ invert_m4_m4(inv_mat, mat);
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ float uv_vco[3];
+ copy_v3_v3(uv_vco, l->v->co);
+ /* transform back into the unit circle flat on the Z-axis */
+ mul_m4_v3(inv_mat, uv_vco);
+
+ /* then just take those coords for UVs */
+ luv->uv[0] = uv_center + uv_scale * uv_vco[0];
+ luv->uv[1] = uv_center + uv_scale * uv_vco[1];
+ }
+ }
+}
+
void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
{
BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2;
+ BMFace *f;
float vec[3], mat[4][4], phi, phid;
float dia1 = BMO_slot_float_get(op->slots_in, "diameter1");
float dia2 = BMO_slot_float_get(op->slots_in, "diameter2");
@@ -574,6 +820,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
int segs = BMO_slot_int_get(op->slots_in, "segments");
const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends");
const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris");
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
int a;
if (!segs)
@@ -620,14 +867,23 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (a) {
if (cap_ends) {
- BMFace *f;
-
f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
+
f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
- BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
+
+ f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
}
else {
firstv1 = v1;
@@ -642,29 +898,149 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
return;
if (cap_ends) {
- BMFace *f;
-
f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
+
f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
-
+
+ f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK);
+ }
+
if (!cap_tris) {
BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW);
}
- BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
-
BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+/**
+ * Fills first available UVmap with cylinder/cone-like UVs for all faces OpFlag-ged by given flag.
+ *
+ * \param bm The BMesh to operate on.
+ * \param mat The transform matrix applied to the created cone/cylinder.
+ * \param radius_top The size of the top end of the cone/cylinder.
+ * \param radius_bottom The size of the bottom end of the cone/cylinder.
+ * \param segments The number of subdivisions in the sides of the cone/cylinder.
+ * \param cap_ends Whether the ends of the cone/cylinder are filled or not.
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_cone(
+ BMesh *bm, float mat[4][4],
+ const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ const float uv_width = 1.0f / (float)segments;
+ const float uv_height = cap_ends ? 0.5f : 1.0f;
+
+ /* Note that all this allows us to handle all cases (real cone, truncated cone, with or without ends capped)
+ * with a single common code. */
+ const float uv_center_y = cap_ends ? 0.25f : 0.5f;
+ const float uv_center_x_top = cap_ends ? 0.25f : 0.5f;
+ const float uv_center_x_bottom = cap_ends ? 0.75f : 0.5f;
+ const float uv_radius = cap_ends ? 0.24f : 0.5f;
+
+ /* Using the opposite's end uv_scale as fallback allows us to handle 'real cone' case. */
+ const float uv_scale_top = (radius_top != 0.0f) ? (uv_radius / radius_top) :
+ ((radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : uv_radius);
+ const float uv_scale_bottom = (radius_bottom != 0.0f) ? (uv_radius / radius_bottom) :
+ uv_scale_top;
+
+ float local_up[3] = {0.0f, 0.0f, 1.0f};
+
+ float x, y;
+ float inv_mat[4][4];
+ int loop_index;
+
+ mul_mat3_m4_v3(mat, local_up); /* transform the upvector like we did the cone itself, without location. */
+ normalize_v3(local_up); /* remove global scaling... */
+
+ invert_m4_m4(inv_mat, mat);
+
+ BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */
+
+ x = 0.0f;
+ y = 1.0f - uv_height;
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag))
+ continue;
+
+ if (f->len == 4 && radius_top && radius_bottom) {
+ /* side face - so unwrap it in a rectangle */
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (loop_index) {
+ case 0:
+ x += uv_width;
+ break;
+ case 1:
+ y += uv_height;
+ break;
+ case 2:
+ x -= uv_width;
+ break;
+ case 3:
+ y -= uv_height;
+ break;
+ default:
+ break;
+ }
+
+ luv->uv[0] = x;
+ luv->uv[1] = y;
+ }
+
+ x += uv_width;
+ }
+ else {
+ /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */
+ BM_face_normal_update(f);
+
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float uv_vco[3];
+
+ mul_v3_m4v3(uv_vco, inv_mat, l->v->co);
+
+ if (dot_v3v3(f->no, local_up) > 0.0f) { /* if this is a top face of the cone */
+ luv->uv[0] = uv_center_x_top + uv_vco[0] * uv_scale_top;
+ luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_top;
+ }
+ else {
+ luv->uv[0] = uv_center_x_bottom + uv_vco[0] * uv_scale_bottom;
+ luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_bottom;
+ }
+ }
+ }
+ }
+}
+
void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
{
BMVert *verts[8];
float mat[4][4];
float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f;
+ const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs");
int i, x, y, z;
const char faces[6][4] = {
{1, 3, 2, 0},
@@ -693,6 +1069,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
}
for (i = 0; i < ARRAY_SIZE(faces); i++) {
+ BMFace *f;
BMVert *quad[4] = {
verts[faces[i][0]],
verts[faces[i][1]],
@@ -700,8 +1077,82 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
verts[faces[i][3]],
};
- BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true);
+ f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true);
+ if (calc_uvs) {
+ BMO_elem_flag_enable(bm, f, FACE_MARK);
+ }
+ }
+
+ if (calc_uvs) {
+ BM_mesh_calc_uvs_cube(bm, FACE_MARK);
}
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
+
+/**
+ * Fills first available UVmap with cube-like UVs for all faces OpFlag-ged by given flag.
+ *
+ * \note Expects tagged faces to be six quads...
+ *
+ * \param bm The BMesh to operate on.
+ * \param oflag The flag to check faces with.
+ */
+void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag)
+{
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
+ const float width = 0.25f;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float x = 0.375f;
+ float y = 0.0f;
+
+ int loop_index;
+
+ BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BMO_elem_flag_test(bm, f, oflag)) {
+ continue;
+ }
+
+ BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ luv->uv[0] = x;
+ luv->uv[1] = y;
+
+ switch (loop_index) {
+ case 0:
+ x += width;
+ break;
+ case 1:
+ y += width;
+ break;
+ case 2:
+ x -= width;
+ break;
+ case 3:
+ y -= width;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (y >= 0.75f && x > 0.125f) {
+ x = 0.125f;
+ y = 0.5f;
+ }
+ else if (x <= 0.125f) {
+ x = 0.625f;
+ y = 0.5f;
+ }
+ else {
+ y += 0.25f;
+ }
+ }
+}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 42373ad0ef0..a1f40b31fc7 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -73,87 +73,114 @@ static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot
#define ELE_DEL 1
#define EDGE_COL 2
-#define FACE_MARK 2
+#define VERT_IN_FACE 4
/**
* helper function for bmo_weld_verts_exec so we can use stack memory
*/
-static void remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap)
+static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap)
{
- BMIter liter;
- BMFace *f_new;
BMEdge *e_new;
- BMLoop *l;
-
- BMEdge **edges = BLI_array_alloca(edges, f->len);
- BMLoop **loops = BLI_array_alloca(loops, f->len);
+ BMEdge **edges = BLI_array_alloca(edges, f->len); /* new ordered edges */
+ BMVert **verts = BLI_array_alloca(verts, f->len); /* new ordered verts */
+ BMLoop **loops = BLI_array_alloca(loops, f->len); /* original ordered loops to copy attrs into the new face */
STACK_DECLARE(edges);
STACK_DECLARE(loops);
+ STACK_DECLARE(verts);
STACK_INIT(edges, f->len);
STACK_INIT(loops, f->len);
+ STACK_INIT(verts, f->len);
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BMVert *v1 = l->v;
- BMVert *v2 = l->next->v;
- const bool is_del_v1 = BMO_elem_flag_test_bool(bm, v1, ELE_DEL);
- const bool is_del_v2 = BMO_elem_flag_test_bool(bm, v2, ELE_DEL);
+ {
+#define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \
+ v_map = l_init->v; \
+ is_del = BMO_elem_flag_test_bool(bm, v_map, ELE_DEL); \
+ if (is_del) { \
+ v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \
+ } ((void)0)
- /* only search for a new edge if one of the verts is mapped */
- if (is_del_v1 || is_del_v2) {
- if (is_del_v1)
- v1 = BMO_slot_map_elem_get(slot_targetmap, v1);
- if (is_del_v2)
- v2 = BMO_slot_map_elem_get(slot_targetmap, v2);
- e_new = (v1 != v2) ? BM_edge_exists(v1, v2) : NULL;
- }
- else {
- e_new = l->e;
- }
+ BMLoop *l_first, *l_curr, *l_next;
+ BMVert *v_curr;
+ bool is_del_v_curr;
- if (e_new) {
- unsigned int i;
- for (i = 0; i < STACK_SIZE(edges); i++) {
- if (edges[i] == e_new) {
- break;
- }
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ LOOP_MAP_VERT_INIT(l_curr, v_curr, is_del_v_curr);
+
+ do {
+ BMVert *v_next;
+ bool is_del_v_next;
+
+ l_next = l_curr->next;
+ LOOP_MAP_VERT_INIT(l_next, v_next, is_del_v_next);
+
+ /* only search for a new edge if one of the verts is mapped */
+ if ((is_del_v_curr || is_del_v_next) == 0) {
+ e_new = l_curr->e;
}
- if (UNLIKELY(i != STACK_SIZE(edges))) {
- continue;
+ else if (v_curr == v_next) {
+ e_new = NULL; /* skip */
+ }
+ else {
+ e_new = BM_edge_exists(v_curr, v_next);
+ BLI_assert(e_new); /* never fails */
}
- STACK_PUSH(edges, e_new);
- STACK_PUSH(loops, l);
- }
- }
+ if (e_new) {
+ if (UNLIKELY(BMO_elem_flag_test(bm, v_curr, VERT_IN_FACE))) {
+ /* we can't make the face, bail out */
+ STACK_CLEAR(edges);
+ goto finally;
+ }
+ BMO_elem_flag_enable(bm, v_curr, VERT_IN_FACE);
- if (STACK_SIZE(edges) >= 3) {
- BMVert *v1 = loops[0]->v;
- BMVert *v2 = loops[1]->v;
+ STACK_PUSH(edges, e_new);
+ STACK_PUSH(loops, l_curr);
+ STACK_PUSH(verts, v_curr);
+ }
- if (BMO_elem_flag_test(bm, v1, ELE_DEL)) {
- v1 = BMO_slot_map_elem_get(slot_targetmap, v1);
- }
- if (BMO_elem_flag_test(bm, v2, ELE_DEL)) {
- v2 = BMO_slot_map_elem_get(slot_targetmap, v2);
- }
+ v_curr = v_next;
+ is_del_v_curr = is_del_v_next;
+ } while ((l_curr = l_next) != l_first);
- f_new = BM_face_create_ngon(bm, v1, v2, edges, STACK_SIZE(edges), f, BM_CREATE_NO_DOUBLE);
- BLI_assert(f_new != f);
+#undef LOOP_MAP_VERT_INIT
- if (f_new) {
- unsigned int i;
- BM_ITER_ELEM_INDEX (l, &liter, f_new, BM_LOOPS_OF_FACE, i) {
- BM_elem_attrs_copy(bm, bm, loops[i], l);
+ }
+
+finally:
+ {
+ unsigned int i;
+ for (i = 0; i < STACK_SIZE(verts); i++) {
+ BMO_elem_flag_disable(bm, verts[i], VERT_IN_FACE);
+ }
+ }
+
+ if (STACK_SIZE(edges) >= 3) {
+ if (!BM_face_exists(verts, STACK_SIZE(edges), NULL)) {
+ BMFace *f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP);
+ BLI_assert(f_new != f);
+
+ if (f_new) {
+ unsigned int i = 0;
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
+ do {
+ BM_elem_attrs_copy(bm, bm, loops[i], l_iter);
+ } while ((void)i++, (l_iter = l_iter->next) != l_first);
+
+ return f_new;
}
}
}
+
+ return NULL;
}
+
/**
* \note with 'targetmap', multiple 'keys' are currently supported, though no callers should be using.
* (because slot maps currently use GHash without the GHASH_FLAG_ALLOW_DUPES flag set)
@@ -198,39 +225,58 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op)
BMO_elem_flag_enable(bm, e, EDGE_COL);
}
else if (!BM_edge_exists(v1, v2)) {
- BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
+ BMEdge *e_new = BM_edge_create(bm, v1, v2, e, BM_CREATE_NOP);
+
+ /* low level selection, not essential but means we can keep
+ * edge selection valid on auto-merge for example. */
+ if ((BM_elem_flag_test(e, BM_ELEM_SELECT) == true) &&
+ (BM_elem_flag_test(e_new, BM_ELEM_SELECT) == false))
+ {
+ BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ BM_elem_flag_merge_into(e_new, e_new, e);
+ BM_elem_flag_enable(e_new, BM_ELEM_SELECT);
+ /* bm->totedgesel remains valid */
+ }
+ else {
+ BM_elem_flag_merge_into(e_new, e_new, e);
+ }
}
BMO_elem_flag_enable(bm, e, ELE_DEL);
}
}
- /* BMESH_TODO, stop abusing face index here */
+ /* faces get "modified" by creating new faces here, then at the
+ * end the old faces are deleted */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BM_elem_index_set(f, 0); /* set_dirty! */
+ bool vert_delete = false;
+ int edge_collapse = 0;
+
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
if (BMO_elem_flag_test(bm, l->v, ELE_DEL)) {
- BMO_elem_flag_enable(bm, f, FACE_MARK | ELE_DEL);
+ vert_delete = true;
}
if (BMO_elem_flag_test(bm, l->e, EDGE_COL)) {
- BM_elem_index_set(f, BM_elem_index_get(f) + 1); /* set_dirty! */
+ edge_collapse++;
}
}
- }
- bm->elem_index_dirty |= BM_FACE | BM_LOOP;
- /* faces get "modified" by creating new faces here, then at the
- * end the old faces are deleted */
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (!BMO_elem_flag_test(bm, f, FACE_MARK))
- continue;
-
- if (f->len - BM_elem_index_get(f) < 3) {
+ if (vert_delete) {
BMO_elem_flag_enable(bm, f, ELE_DEL);
- continue;
- }
- remdoubles_createface(bm, f, slot_targetmap);
+ if (f->len - edge_collapse >= 3) {
+ BMFace *f_new = remdoubles_createface(bm, f, slot_targetmap);
+
+ /* do this so we don't need to return a list of created faces */
+ if (f_new) {
+ bmesh_face_swap_data(f_new, f);
+ SWAP(BMFlagLayer *, f->oflags, f_new->oflags);
+ BMO_elem_flag_disable(bm, f, ELE_DEL);
+
+ BM_face_kill(bm, f_new);
+ }
+ }
+ }
}
BMO_mesh_delete_oflag_context(bm, ELE_DEL, DEL_ONLYTAGGED);
diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
index a250c716c16..1a83bafc074 100644
--- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c
+++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
@@ -28,18 +28,15 @@
#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
+#include "eigen_capi.h"
+
#include "bmesh.h"
#include "intern/bmesh_operators_private.h" /* own include */
-#ifdef WITH_OPENNL
-
-#include "ONL_opennl.h"
-
// #define SMOOTH_LAPLACIAN_AREA_FACTOR 4.0f /* UNUSED */
// #define SMOOTH_LAPLACIAN_EDGE_FACTOR 2.0f /* UNUSED */
#define SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE 1.8f
@@ -59,7 +56,7 @@ struct BLaplacianSystem {
/* Pointers to data*/
BMesh *bm;
BMOperator *op;
- NLContext *context;
+ LinearSolver *context;
/*Data*/
float min_area;
@@ -92,7 +89,7 @@ static void delete_laplacian_system(LaplacianSystem *sys)
delete_void_pointer(sys->vweights);
delete_void_pointer(sys->zerola);
if (sys->context) {
- nlDeleteContext(sys->context);
+ EIG_linear_solver_delete(sys->context);
}
sys->bm = NULL;
sys->op = NULL;
@@ -333,9 +330,9 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
w4 = w4 / 4.0f;
if (!vert_is_boundary(vf[j]) && sys->zerola[idv1] == 0) {
- nlMatrixAdd(idv1, idv2, w2 * sys->vweights[idv1]);
- nlMatrixAdd(idv1, idv3, w3 * sys->vweights[idv1]);
- nlMatrixAdd(idv1, idv4, w4 * sys->vweights[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv2, w2 * sys->vweights[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv3, w3 * sys->vweights[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv4, w4 * sys->vweights[idv1]);
}
}
}
@@ -346,16 +343,16 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
/* Is ring if number of faces == number of edges around vertice*/
i = BM_elem_index_get(f);
if (!vert_is_boundary(vf[0]) && sys->zerola[idv1] == 0) {
- nlMatrixAdd(idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]);
- nlMatrixAdd(idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]);
}
if (!vert_is_boundary(vf[1]) && sys->zerola[idv2] == 0) {
- nlMatrixAdd(idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]);
- nlMatrixAdd(idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]);
+ EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]);
+ EIG_linear_solver_matrix_add(sys->context, idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]);
}
if (!vert_is_boundary(vf[2]) && sys->zerola[idv3] == 0) {
- nlMatrixAdd(idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]);
- nlMatrixAdd(idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]);
+ EIG_linear_solver_matrix_add(sys->context, idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]);
+ EIG_linear_solver_matrix_add(sys->context, idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]);
}
}
}
@@ -368,8 +365,8 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
idv2 = BM_elem_index_get(e->v2);
if (sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) {
i = BM_elem_index_get(e);
- nlMatrixAdd(idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
- nlMatrixAdd(idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
}
}
}
@@ -434,12 +431,12 @@ static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez
idv2 = BM_elem_index_get(e->v2);
vi1 = e->v1->co;
vi2 = e->v2->co;
- ve1[0] = nlGetVariable(0, idv1);
- ve1[1] = nlGetVariable(1, idv1);
- ve1[2] = nlGetVariable(2, idv1);
- ve2[0] = nlGetVariable(0, idv2);
- ve2[1] = nlGetVariable(1, idv2);
- ve2[2] = nlGetVariable(2, idv2);
+ ve1[0] = EIG_linear_solver_variable_get(sys->context, 0, idv1);
+ ve1[1] = EIG_linear_solver_variable_get(sys->context, 1, idv1);
+ ve1[2] = EIG_linear_solver_variable_get(sys->context, 2, idv1);
+ ve2[0] = EIG_linear_solver_variable_get(sys->context, 0, idv2);
+ ve2[1] = EIG_linear_solver_variable_get(sys->context, 1, idv2);
+ ve2[2] = EIG_linear_solver_variable_get(sys->context, 2, idv2);
leni = len_v3v3(vi1, vi2);
lene = len_v3v3(ve1, ve2);
if (lene > leni * SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE || lene < leni * SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE) {
@@ -455,13 +452,13 @@ static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez
m_vertex_id = BM_elem_index_get(v);
if (sys->zerola[m_vertex_id] == 0) {
if (usex) {
- v->co[0] = nlGetVariable(0, m_vertex_id);
+ v->co[0] = EIG_linear_solver_variable_get(sys->context, 0, m_vertex_id);
}
if (usey) {
- v->co[1] = nlGetVariable(1, m_vertex_id);
+ v->co[1] = EIG_linear_solver_variable_get(sys->context, 1, m_vertex_id);
}
if (usez) {
- v->co[2] = nlGetVariable(2, m_vertex_id);
+ v->co[2] = EIG_linear_solver_variable_get(sys->context, 2, m_vertex_id);
}
}
}
@@ -501,33 +498,25 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op)
preserve_volume = BMO_slot_bool_get(op->slots_in, "preserve_volume");
- nlNewContext();
- sys->context = nlGetCurrent();
-
- nlSolverParameteri(NL_NB_VARIABLES, bm->totvert);
- nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
- nlSolverParameteri(NL_NB_ROWS, bm->totvert);
- nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);
+ sys->context = EIG_linear_least_squares_solver_new(bm->totvert, bm->totvert, 3);
- nlBegin(NL_SYSTEM);
for (i = 0; i < bm->totvert; i++) {
- nlLockVariable(i);
+ EIG_linear_solver_variable_lock(sys->context, i);
}
BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
m_vertex_id = BM_elem_index_get(v);
- nlUnlockVariable(m_vertex_id);
- nlSetVariable(0, m_vertex_id, v->co[0]);
- nlSetVariable(1, m_vertex_id, v->co[1]);
- nlSetVariable(2, m_vertex_id, v->co[2]);
+ EIG_linear_solver_variable_unlock(sys->context, m_vertex_id);
+ EIG_linear_solver_variable_set(sys->context, 0, m_vertex_id, v->co[0]);
+ EIG_linear_solver_variable_set(sys->context, 1, m_vertex_id, v->co[1]);
+ EIG_linear_solver_variable_set(sys->context, 2, m_vertex_id, v->co[2]);
}
- nlBegin(NL_MATRIX);
init_laplacian_matrix(sys);
BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
m_vertex_id = BM_elem_index_get(v);
- nlRightHandSideAdd(0, m_vertex_id, v->co[0]);
- nlRightHandSideAdd(1, m_vertex_id, v->co[1]);
- nlRightHandSideAdd(2, m_vertex_id, v->co[2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, m_vertex_id, v->co[0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, m_vertex_id, v->co[1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, m_vertex_id, v->co[2]);
i = m_vertex_id;
if (sys->zerola[i] == 0) {
w = sys->vweights[i] * sys->ring_areas[i];
@@ -536,34 +525,22 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op)
sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w;
if (!vert_is_boundary(v)) {
- nlMatrixAdd(i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i]));
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i]));
}
else {
- nlMatrixAdd(i, i, 1.0f + lambda_border * 2.0f);
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_border * 2.0f);
}
}
else {
- nlMatrixAdd(i, i, 1.0f);
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f);
}
}
fill_laplacian_matrix(sys);
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
-
- if (nlSolveAdvanced(NULL, NL_TRUE) ) {
+ if (EIG_linear_solver_solve(sys->context) ) {
validate_solution(sys, usex, usey, usez, preserve_volume);
}
delete_laplacian_system(sys);
}
-#else /* WITH_OPENNL */
-
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wunused-parameter"
-#endif
-
-void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) {}
-
-#endif /* WITH_OPENNL */
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index 45e3c8d193d..38fa2cfdcc8 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -163,6 +163,85 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace
return NULL;
}
+
+/**
+ * Specialized slerp that uses a sphere defined by each points normal.
+ */
+static void interp_slerp_co_no_v3(
+ const float co_a[3], const float no_a[3],
+ const float co_b[3], const float no_b[3],
+ const float no_dir[3], /* caller already knows, avoid normalize */
+ float fac,
+ float r_co[3])
+{
+ /* center of the sphere defined by both normals */
+ float center[3];
+
+ BLI_assert(len_squared_v3v3(no_a, no_b) != 0);
+
+ /* calculate sphere 'center' */
+ {
+ /* use point on plane to */
+ float plane_a[4], plane_b[4], plane_c[4];
+ float no_mid[3], no_ortho[3];
+ /* pass this as an arg instead */
+#if 0
+ float no_dir[3];
+#endif
+
+ float v_a_no_ortho[3], v_b_no_ortho[3];
+
+ add_v3_v3v3(no_mid, no_a, no_b);
+ normalize_v3(no_mid);
+
+#if 0
+ sub_v3_v3v3(no_dir, co_a, co_b);
+ normalize_v3(no_dir);
+#endif
+
+ /* axis of slerp */
+ cross_v3_v3v3(no_ortho, no_mid, no_dir);
+ normalize_v3(no_ortho);
+
+ /* create planes */
+ cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
+ cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
+ project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
+ project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);
+
+ plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
+ plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
+ plane_from_point_normal_v3(plane_c, co_b, no_ortho);
+
+ /* find the sphere center from 3 planes */
+ if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
+ /* pass */
+ }
+ else {
+ mid_v3_v3v3(center, co_a, co_b);
+ }
+ }
+
+ /* calculate the final output 'r_co' */
+ {
+ float ofs_a[3], ofs_b[3], ofs_slerp[3];
+ float dist_a, dist_b;
+
+ sub_v3_v3v3(ofs_a, co_a, center);
+ sub_v3_v3v3(ofs_b, co_b, center);
+
+ dist_a = normalize_v3(ofs_a);
+ dist_b = normalize_v3(ofs_b);
+
+ if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
+ madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
+ }
+ else {
+ interp_v3_v3v3(r_co, co_a, co_b, fac);
+ }
+ }
+}
+
/* calculates offset for co, based on fractal, sphere or smooth settings */
static void alter_co(
BMVert *v, BMEdge *UNUSED(e_orig),
@@ -179,32 +258,72 @@ static void alter_co(
mul_v3_fl(co, params->smooth);
}
else if (params->use_smooth) {
- /* we calculate an offset vector vec1[], to be added to *co */
- float dir[3], tvec[3];
- float fac, len, val;
+ /* calculating twice and blending gives smoother results,
+ * removing visible seams. */
+#define USE_SPHERE_DUAL_BLEND
- sub_v3_v3v3(dir, v_a->co, v_b->co);
- len = (float)M_SQRT1_2 * normalize_v3(dir);
+ const float eps_unit_vec = 1e-5f;
+ float smooth;
+ float no_dir[3];
- /* cosine angle */
- fac = dot_v3v3(dir, v_a->no);
- mul_v3_v3fl(tvec, v_a->no, fac);
+#ifdef USE_SPHERE_DUAL_BLEND
+ float no_reflect[3], co_a[3], co_b[3];
+#endif
- /* cosine angle */
- fac = -dot_v3v3(dir, v_b->no);
- madd_v3_v3fl(tvec, v_b->no, fac);
+ sub_v3_v3v3(no_dir, v_a->co, v_b->co);
+ normalize_v3(no_dir);
- /* falloff for multi subdivide */
- val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
- val = bmesh_subd_falloff_calc(params->smooth_falloff, val);
+#ifndef USE_SPHERE_DUAL_BLEND
+ if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
+ interp_v3_v3v3(co, v_a->co, v_b->co, perc);
+ }
+ else {
+ interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
+ }
+#else
+ /* sphere-a */
+ reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
+ if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
+ interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
+ }
+ else {
+ interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
+ }
+
+ /* sphere-b */
+ reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
+ if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
+ interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
+ }
+ else {
+ interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
+ }
+
+ /* blend both spheres */
+ interp_v3_v3v3(co, co_a, co_b, perc);
+#endif /* USE_SPHERE_DUAL_BLEND */
+
+ /* apply falloff */
+ if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
+ smooth = 1.0f;
+ }
+ else {
+ smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
+ smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
+ }
if (params->use_smooth_even) {
- val *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
+ smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
}
- mul_v3_fl(tvec, params->smooth * val * len);
+ smooth *= params->smooth;
+ if (smooth != 1.0f) {
+ float co_flat[3];
+ interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
+ interp_v3_v3v3(co, co_flat, co, smooth);
+ }
- add_v3_v3(co, tvec);
+#undef USE_SPHERE_DUAL_BLEND
}
if (params->use_fractal) {
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index 0e619b4cece..b5a95ad6283 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -258,11 +258,10 @@ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim)
if (pair_test.first > pair_test.second)
SWAP(const void *, pair_test.first, pair_test.second);
- if (!BLI_gset_haskey(eloop_pair_gs, &pair_test)) {
- GHashPair *pair = BLI_ghashutil_pairalloc(pair_test.first, pair_test.second);
- BLI_gset_insert(eloop_pair_gs, pair);
+ void **pair_key_p;
+ if (!BLI_gset_ensure_p_ex(eloop_pair_gs, &pair_test, &pair_key_p)) {
+ *pair_key_p = BLI_ghashutil_pairalloc(pair_test.first, pair_test.second);
}
-
}
}
}
diff --git a/source/blender/bmesh/operators/bmo_symmetrize.c b/source/blender/bmesh/operators/bmo_symmetrize.c
index 5c1b4287c2f..2afd2c574f9 100644
--- a/source/blender/bmesh/operators/bmo_symmetrize.c
+++ b/source/blender/bmesh/operators/bmo_symmetrize.c
@@ -79,6 +79,9 @@ void bmo_symmetrize_exec(BMesh *bm, BMOperator *op)
BMO_op_callf(bm, op->flag, "scale verts=%S vec=%v", &op_dupe, "geom.out", scale);
+
+ /* important 'flip_multires' is disabled,
+ * otherwise multi-res data will be reversed, see: T47788 */
BMO_op_callf(bm, op->flag, "reverse_faces faces=%S", &op_dupe, "geom.out");
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index cb9ba5e361c..6fb09c76ea4 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -48,14 +48,16 @@ void bmo_triangulate_exec(BMesh *bm, BMOperator *op)
const int ngon_method = BMO_slot_int_get(op->slots_in, "ngon_method");
BMOpSlot *slot_facemap_out = BMO_slot_get(op->slots_out, "face_map.out");
+ BMOpSlot *slot_facemap_double_out = BMO_slot_get(op->slots_out, "face_map_double.out");
BM_mesh_elem_hflag_disable_all(bm, BM_FACE | BM_EDGE, BM_ELEM_TAG, false);
BMO_slot_buffer_hflag_enable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
- BM_mesh_triangulate(bm, quad_method, ngon_method, true, op, slot_facemap_out);
+ BM_mesh_triangulate(bm, quad_method, ngon_method, true, op, slot_facemap_out, slot_facemap_double_out);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "edges.out", BM_EDGE, BM_ELEM_TAG);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
+
}
struct SortNormal {
@@ -121,7 +123,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
for (sf_vert = sf_ctx.fillvertbase.first, i = 0; sf_vert; sf_vert = sf_vert->next, i++) {
BMVert *v = sf_vert->tmp.p;
BMIter eiter;
- BMEdge *e, *e_pair[2];
+ BMEdge *e_pair[2];
unsigned int e_index = 0;
nors[i].value = -1.0f;
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index 964d0b1dfc6..e596032663e 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -111,11 +111,13 @@ void bmo_rotate_exec(BMesh *bm, BMOperator *op)
void bmo_reverse_faces_exec(BMesh *bm, BMOperator *op)
{
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
+ const bool use_loop_mdisp_flip = BMO_slot_bool_get(op->slots_in, "flip_multires");
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
- BM_face_normal_flip(bm, f);
+ BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c
index fbcf573acd9..9fb6d39a008 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -264,8 +264,18 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
/* in fact this simple test is good enough,
* test if the loops are adjacent */
if (found && !BM_loop_is_adjacent(l_a, l_b)) {
+ BMLoop *l_new;
BMFace *f_tmp;
- f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, NULL, NULL, true);
+ f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, &l_new, NULL, true);
+
+ if (l_new) {
+ if (oflag_center) {
+ BMO_elem_flag_enable(bm, l_new->e, oflag_center);
+ BMO_elem_flag_enable(bm, l_new->f, oflag_center);
+ BMO_elem_flag_enable(bm, face_split_arr[j], oflag_center);
+ }
+ }
+
if (f_tmp) {
if (f_tmp != face_split_arr[j]) {
STACK_PUSH(face_split_arr, f_tmp);
diff --git a/source/blender/bmesh/tools/bmesh_decimate.h b/source/blender/bmesh/tools/bmesh_decimate.h
index 6415da9a0c2..42d90cb75e5 100644
--- a/source/blender/bmesh/tools/bmesh_decimate.h
+++ b/source/blender/bmesh/tools/bmesh_decimate.h
@@ -30,7 +30,8 @@
void BM_mesh_decimate_collapse(
BMesh *bm, const float factor,
float *vweights, float vweight_factor,
- const bool do_triangulate);
+ const bool do_triangulate,
+ const int symmetry_axis, const float symmetry_eps);
void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool tag_only);
void BM_mesh_decimate_unsubdivide(BMesh *bm, const int iterations);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 43a34331fc2..0a5e5aba86b 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -42,6 +42,11 @@
#include "../intern/bmesh_structure.h"
+#define USE_SYMMETRY
+#ifdef USE_SYMMETRY
+#include "BLI_kdtree.h"
+#endif
+
/* defines for testing */
#define USE_CUSTOMDATA
#define USE_TRIANGULATE
@@ -237,6 +242,13 @@ static void bm_decim_build_edge_cost_single(
BLI_heap_remove(eheap, eheap_table[BM_elem_index_get(e)]);
}
+ if (UNLIKELY(vweights &&
+ ((vweights[BM_elem_index_get(e->v1)] == 0.0f) ||
+ (vweights[BM_elem_index_get(e->v2)] == 0.0f))))
+ {
+ goto clear;
+ }
+
/* check we can collapse, some edges we better not touch */
if (BM_edge_is_boundary(e)) {
if (e->l->f->len == 3) {
@@ -343,6 +355,107 @@ static void bm_decim_build_edge_cost(
}
}
+#ifdef USE_SYMMETRY
+
+struct KD_Symmetry_Data {
+ /* pre-flipped coords */
+ float e_v1_co[3], e_v2_co[3];
+ /* Use to compare the correct endpoints incase v1/v2 are swapped */
+ float e_dir[3];
+
+ int e_found_index;
+
+ /* same for all */
+ BMEdge **etable;
+ float limit_sq;
+};
+
+static bool bm_edge_symmetry_check_cb(void *user_data, int index, const float UNUSED(co[3]), float UNUSED(dist_sq))
+{
+ struct KD_Symmetry_Data *sym_data = user_data;
+ BMEdge *e_other = sym_data->etable[index];
+ float e_other_dir[3];
+
+ sub_v3_v3v3(e_other_dir, e_other->v2->co, e_other->v1->co);
+
+ if (dot_v3v3(e_other_dir, sym_data->e_dir) > 0.0f) {
+ if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v1->co) > sym_data->limit_sq) ||
+ (len_squared_v3v3(sym_data->e_v2_co, e_other->v2->co) > sym_data->limit_sq))
+ {
+ return true;
+ }
+ }
+ else {
+ if ((len_squared_v3v3(sym_data->e_v1_co, e_other->v2->co) > sym_data->limit_sq) ||
+ (len_squared_v3v3(sym_data->e_v2_co, e_other->v1->co) > sym_data->limit_sq))
+ {
+ return true;
+ }
+ }
+
+ /* exit on first-hit, this is OK since the search range is very small */
+ sym_data->e_found_index = index;
+ return false;
+}
+
+static int *bm_edge_symmetry_map(BMesh *bm, unsigned int symmetry_axis, float limit)
+{
+ struct KD_Symmetry_Data sym_data;
+ BMIter iter;
+ BMEdge *e, **etable;
+ unsigned int i;
+ int *edge_symmetry_map;
+ const float limit_sq = SQUARE(limit);
+ KDTree *tree;
+
+ tree = BLI_kdtree_new(bm->totedge);
+
+ etable = MEM_mallocN(sizeof(BMEdge **) * bm->totedge, __func__);
+ edge_symmetry_map = MEM_mallocN(sizeof(*edge_symmetry_map) * bm->totedge, __func__);
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ float co[3];
+ mid_v3_v3v3(co, e->v1->co, e->v2->co);
+ BLI_kdtree_insert(tree, i, co);
+ etable[i] = e;
+ edge_symmetry_map[i] = -1;
+ }
+
+ BLI_kdtree_balance(tree);
+
+ sym_data.etable = etable;
+ sym_data.limit_sq = limit_sq;
+
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ if (edge_symmetry_map[i] == -1) {
+ float co[3];
+ mid_v3_v3v3(co, e->v1->co, e->v2->co);
+ co[symmetry_axis] *= -1.0f;
+
+ copy_v3_v3(sym_data.e_v1_co, e->v1->co);
+ copy_v3_v3(sym_data.e_v2_co, e->v2->co);
+ sym_data.e_v1_co[symmetry_axis] *= -1.0f;
+ sym_data.e_v2_co[symmetry_axis] *= -1.0f;
+ sub_v3_v3v3(sym_data.e_dir, sym_data.e_v2_co, sym_data.e_v1_co);
+ sym_data.e_found_index = -1;
+
+ BLI_kdtree_range_search_cb(tree, co, limit, bm_edge_symmetry_check_cb, &sym_data);
+
+ if (sym_data.e_found_index != -1) {
+ const int i_other = sym_data.e_found_index;
+ edge_symmetry_map[i] = i_other;
+ edge_symmetry_map[i_other] = i;
+ }
+ }
+ }
+
+ MEM_freeN(etable);
+ BLI_kdtree_free(tree);
+
+ return edge_symmetry_map;
+}
+#endif /* USE_SYMMETRY */
+
#ifdef USE_TRIANGULATE
/* Temp Triangulation
* ****************** */
@@ -763,6 +876,9 @@ static bool bm_edge_collapse_is_degenerate_topology(BMEdge *e_first)
*/
static bool bm_edge_collapse(
BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e_clear_other[2],
+#ifdef USE_SYMMETRY
+ int *edge_symmetry_map,
+#endif
#ifdef USE_CUSTOMDATA
const CD_UseFlag customdata_flag,
const float customdata_fac
@@ -853,6 +969,18 @@ static bool bm_edge_collapse(
BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
BM_edge_splice(bm, e_b_other[1], e_b_other[0]);
+#ifdef USE_SYMMETRY
+ /* update mirror map */
+ if (edge_symmetry_map) {
+ if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
+ edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
+ }
+ if (edge_symmetry_map[r_e_clear_other[1]] != -1) {
+ edge_symmetry_map[edge_symmetry_map[r_e_clear_other[1]]] = BM_elem_index_get(e_b_other[1]);
+ }
+ }
+#endif
+
// BM_mesh_validate(bm);
return true;
@@ -900,6 +1028,15 @@ static bool bm_edge_collapse(
e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag;
BM_edge_splice(bm, e_a_other[1], e_a_other[0]);
+#ifdef USE_SYMMETRY
+ /* update mirror map */
+ if (edge_symmetry_map) {
+ if (edge_symmetry_map[r_e_clear_other[0]] != -1) {
+ edge_symmetry_map[edge_symmetry_map[r_e_clear_other[0]]] = BM_elem_index_get(e_a_other[1]);
+ }
+ }
+#endif
+
// BM_mesh_validate(bm);
return true;
@@ -910,19 +1047,27 @@ static bool bm_edge_collapse(
}
-/* collapse e the edge, removing e->v2 */
-static void bm_decim_edge_collapse(
+/**
+ * Collapse e the edge, removing e->v2
+ *
+ * \return true when the edge was collapsed.
+ */
+static bool bm_decim_edge_collapse(
BMesh *bm, BMEdge *e,
Quadric *vquadrics,
float *vweights, const float vweight_factor,
Heap *eheap, HeapNode **eheap_table,
- const CD_UseFlag customdata_flag)
+#ifdef USE_SYMMETRY
+ int *edge_symmetry_map,
+#endif
+ const CD_UseFlag customdata_flag,
+ float optimize_co[3], bool optimize_co_calc
+ )
{
int e_clear_other[2];
BMVert *v_other = e->v1;
const int v_other_index = BM_elem_index_get(e->v1);
const int v_clear_index = BM_elem_index_get(e->v2); /* the vert is removed so only store the index */
- float optimize_co[3];
float customdata_fac;
#ifdef USE_VERT_NORMAL_INTERP
@@ -930,18 +1075,21 @@ static void bm_decim_edge_collapse(
copy_v3_v3(v_clear_no, e->v2->no);
#endif
- /* disallow collapsing which results in degenerate cases */
- if (UNLIKELY(bm_edge_collapse_is_degenerate_topology(e))) {
- bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */
- return;
- }
+ /* when false, use without degenerate checks */
+ if (optimize_co_calc) {
+ /* disallow collapsing which results in degenerate cases */
+ if (UNLIKELY(bm_edge_collapse_is_degenerate_topology(e))) {
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */
+ return false;
+ }
- bm_decim_calc_target_co(e, optimize_co, vquadrics);
+ bm_decim_calc_target_co(e, optimize_co, vquadrics);
- /* check if this would result in an overlapping face */
- if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
- bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */
- return;
+ /* check if this would result in an overlapping face */
+ if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */
+ return false;
+ }
}
/* use for customdata merging */
@@ -950,7 +1098,7 @@ static void bm_decim_edge_collapse(
#if 0
/* simple test for stupid collapse */
if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) {
- return;
+ return false;
}
#endif
}
@@ -959,7 +1107,13 @@ static void bm_decim_edge_collapse(
customdata_fac = 0.5f;
}
- if (bm_edge_collapse(bm, e, e->v2, e_clear_other, customdata_flag, customdata_fac)) {
+ if (bm_edge_collapse(
+ bm, e, e->v2, e_clear_other,
+#ifdef USE_SYMMETRY
+ edge_symmetry_map,
+#endif
+ customdata_flag, customdata_fac))
+ {
/* update collapse info */
int i;
@@ -1031,11 +1185,13 @@ static void bm_decim_edge_collapse(
}
}
/* end optional update */
+ return true;
#endif
}
else {
/* add back with a high cost */
bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
+ return false;
}
}
@@ -1049,12 +1205,14 @@ static void bm_decim_edge_collapse(
* \param factor face count multiplier [0 - 1]
* \param vweights Optional array of vertex aligned weights [0 - 1],
* a vertex group is the usual source for this.
+ * \param axis: Axis of symmetry, -1 to disable mirror decimate.
*/
void BM_mesh_decimate_collapse(
BMesh *bm,
const float factor,
float *vweights, float vweight_factor,
- const bool do_triangulate)
+ const bool do_triangulate,
+ const int symmetry_axis, const float symmetry_eps)
{
Heap *eheap; /* edge heap */
HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
@@ -1065,6 +1223,11 @@ void BM_mesh_decimate_collapse(
CD_UseFlag customdata_flag = 0;
+#ifdef USE_SYMMETRY
+ bool use_symmetry = (symmetry_axis != -1);
+ int *edge_symmetry_map;
+#endif
+
#ifdef USE_TRIANGULATE
/* temp convert quads to triangles */
use_triangulate = bm_decim_triangulate_begin(bm);
@@ -1087,6 +1250,11 @@ void BM_mesh_decimate_collapse(
face_tot_target = bm->totface * factor;
bm->elem_index_dirty |= BM_ALL;
+#ifdef USE_SYMMETRY
+ edge_symmetry_map = (use_symmetry) ? bm_edge_symmetry_map(bm, symmetry_axis, symmetry_eps) : NULL;
+#else
+ UNUSED_VARS(symmetry_axis, symmetry_eps);
+#endif
#ifdef USE_CUSTOMDATA
/* initialize customdata flag, we only need math for loops */
@@ -1096,21 +1264,151 @@ void BM_mesh_decimate_collapse(
#endif
/* iterative edge collapse and maintain the eheap */
- while ((bm->totface > face_tot_target) &&
- (BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID))
+#ifdef USE_SYMMETRY
+ if (use_symmetry == false)
+#endif
{
- // const float value = BLI_heap_node_value(BLI_heap_top(eheap));
- BMEdge *e = BLI_heap_popmin(eheap);
- BLI_assert(BM_elem_index_get(e) < tot_edge_orig); /* handy to detect corruptions elsewhere */
+ /* simple non-mirror case */
+ while ((bm->totface > face_tot_target) &&
+ (BLI_heap_is_empty(eheap) == false) &&
+ (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID))
+ {
+ // const float value = BLI_heap_node_value(BLI_heap_top(eheap));
+ BMEdge *e = BLI_heap_popmin(eheap);
+ float optimize_co[3];
+ BLI_assert(BM_elem_index_get(e) < tot_edge_orig); /* handy to detect corruptions elsewhere */
+
+ /* under normal conditions wont be accessed again,
+ * but NULL just incase so we don't use freed node */
+ eheap_table[BM_elem_index_get(e)] = NULL;
+
+ bm_decim_edge_collapse(
+ bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table,
+#ifdef USE_SYMMETRY
+ edge_symmetry_map,
+#endif
+ customdata_flag,
+ optimize_co, true
+ );
+ }
+ }
+#ifdef USE_SYMMETRY
+ else {
+ while ((bm->totface > face_tot_target) &&
+ (BLI_heap_is_empty(eheap) == false) &&
+ (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID))
+ {
+ /**
+ * \note
+ * - `eheap_table[e_index_mirr]` is only removed from the heap at the last moment
+ * since its possible (in theory) for collapsing `e` to remove `e_mirr`.
+ * - edges sharing a vertex are ignored, so the pivot vertex isnt moved to one side.
+ */
+
+ BMEdge *e = BLI_heap_popmin(eheap);
+ const int e_index = BM_elem_index_get(e);
+ const int e_index_mirr = edge_symmetry_map[e_index];
+ BMEdge *e_mirr = NULL;
+ float optimize_co[3];
+ char e_invalidate = 0;
+
+ BLI_assert(e_index < tot_edge_orig);
+
+ eheap_table[e_index] = NULL;
+
+ if (e_index_mirr != -1) {
+ if (e_index_mirr == e_index) {
+ /* pass */
+ }
+ else if (eheap_table[e_index_mirr]) {
+ e_mirr = BLI_heap_node_ptr(eheap_table[e_index_mirr]);
+ /* for now ignore edges with a shared vertex */
+ if (BM_edge_share_vert_check(e, e_mirr)) {
+ /* ignore permanently!
+ * Otherwise we would keep re-evaluating and attempting to collapse. */
+ // e_invalidate |= (1 | 2);
+ goto invalidate;
+ }
+ }
+ else {
+ /* mirror edge can't be operated on (happens with asymmetrical meshes) */
+ e_invalidate |= 1;
+ goto invalidate;
+ }
+ }
- /* under normal conditions wont be accessed again,
- * but NULL just incase so we don't use freed node */
- eheap_table[BM_elem_index_get(e)] = NULL;
+ /* when false, use without degenerate checks */
+ {
+ /* run both before checking (since they invalidate surrounding geometry) */
+ bool ok_a, ok_b;
- bm_decim_edge_collapse(bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table, customdata_flag);
- }
+ ok_a = !bm_edge_collapse_is_degenerate_topology(e);
+ ok_b = e_mirr ? !bm_edge_collapse_is_degenerate_topology(e_mirr) : true;
+
+ /* disallow collapsing which results in degenerate cases */
+
+ if (UNLIKELY(!ok_a || !ok_b)) {
+ e_invalidate |= (1 | (e_mirr ? 2 : 0));
+ goto invalidate;
+ }
+
+ bm_decim_calc_target_co(e, optimize_co, vquadrics);
+
+ if (e_index_mirr == e_index) {
+ optimize_co[symmetry_axis] = 0.0f;
+ }
+
+ /* check if this would result in an overlapping face */
+ if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) {
+ e_invalidate |= (1 | (e_mirr ? 2 : 0));
+ goto invalidate;
+ }
+ }
+ if (bm_decim_edge_collapse(
+ bm, e, vquadrics, vweights, vweight_factor, eheap, eheap_table,
+ edge_symmetry_map,
+ customdata_flag,
+ optimize_co, false))
+ {
+ if (e_mirr && (eheap_table[e_index_mirr])) {
+ BLI_assert(e_index_mirr != e_index);
+ BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
+ eheap_table[e_index_mirr] = NULL;
+ optimize_co[symmetry_axis] *= -1.0f;
+ bm_decim_edge_collapse(
+ bm, e_mirr, vquadrics, vweights, vweight_factor, eheap, eheap_table,
+ edge_symmetry_map,
+ customdata_flag,
+ optimize_co, false);
+ }
+ }
+ else {
+ if (e_mirr && (eheap_table[e_index_mirr])) {
+ e_invalidate |= 2;
+ goto invalidate;
+ }
+ }
+
+ BLI_assert(e_invalidate == 0);
+ continue;
+
+invalidate:
+ if (e_invalidate & 1) {
+ bm_decim_invalid_edge_cost_single(e, eheap, eheap_table);
+ }
+
+ if (e_invalidate & 2) {
+ BLI_assert(eheap_table[e_index_mirr] != NULL);
+ BLI_heap_remove(eheap, eheap_table[e_index_mirr]);
+ eheap_table[e_index_mirr] = NULL;
+ bm_decim_invalid_edge_cost_single(e_mirr, eheap, eheap_table);
+ }
+ }
+
+ MEM_freeN((void *)edge_symmetry_map);
+ }
+#endif /* USE_SYMMETRY */
#ifdef USE_TRIANGULATE
if (do_triangulate == false) {
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index a1460cec7d1..5a7a2f3ee29 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -37,6 +37,9 @@
#include "bmesh.h"
#include "bmesh_decimate.h" /* own include */
+/* check that collapsing a vertex between 2 edges doesn't cause a degenerate face. */
+#define USE_DEGENERATE_CHECK
+
#define COST_INVALID FLT_MAX
@@ -88,9 +91,6 @@ static float bm_edge_calc_dissolve_error(
const BMEdge *e, const BMO_Delimit delimit,
const struct DelimitData *delimit_data)
{
- const bool is_contig = BM_edge_is_contiguous(e);
- float angle;
-
if (!BM_edge_is_manifold(e)) {
goto fail;
}
@@ -113,6 +113,8 @@ static float bm_edge_calc_dissolve_error(
goto fail;
}
+ const bool is_contig = BM_edge_is_contiguous(e);
+
if ((delimit & BMO_DELIM_NORMAL) &&
(is_contig == false))
{
@@ -125,18 +127,130 @@ static float bm_edge_calc_dissolve_error(
goto fail;
}
- angle = BM_edge_calc_face_angle(e);
- if (is_contig == false) {
- angle = (float)M_PI - angle;
+ float angle_cos_neg = dot_v3v3(e->l->f->no, e->l->radial_next->f->no);
+ if (is_contig) {
+ angle_cos_neg *= -1;
}
- return angle;
+ return angle_cos_neg;
fail:
return COST_INVALID;
}
+#ifdef USE_DEGENERATE_CHECK
+
+static void mul_v2_m3v3_center(float r[2], float m[3][3], const float a[3], const float center[3])
+{
+ BLI_assert(r != a);
+ BLI_assert(r != center);
+
+ float co[3];
+ sub_v3_v3v3(co, a, center);
+
+ r[0] = m[0][0] * co[0] + m[1][0] * co[1] + m[2][0] * co[2];
+ r[1] = m[0][1] * co[0] + m[1][1] * co[1] + m[2][1] * co[2];
+}
+
+static bool bm_loop_collapse_is_degenerate(BMLoop *l_ear)
+{
+ /* calculate relative to the centeral vertex for higher precision */
+ const float *center = l_ear->v->co;
+
+ float tri_2d[3][2];
+ float axis_mat[3][3];
+
+ axis_dominant_v3_to_m3(axis_mat, l_ear->f->no);
+
+ {
+ mul_v2_m3v3_center(tri_2d[0], axis_mat, l_ear->prev->v->co, center);
+#if 0
+ mul_v2_m3v3_center(tri_2d[1], axis_mat, l_ear->v->co, center);
+#else
+ zero_v2(tri_2d[1]);
+#endif
+ mul_v2_m3v3_center(tri_2d[2], axis_mat, l_ear->next->v->co, center);
+ }
+
+ /* check we're not flipping face corners before or after the ear */
+ {
+ float adjacent_2d[2];
+
+ if (!BM_vert_is_edge_pair(l_ear->prev->v)) {
+ mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->prev->prev->v->co, center);
+ if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[1])) !=
+ signum_i(cross_tri_v2(adjacent_2d, tri_2d[0], tri_2d[2])))
+ {
+ return true;
+ }
+ }
+
+ if (!BM_vert_is_edge_pair(l_ear->next->v)) {
+ mul_v2_m3v3_center(adjacent_2d, axis_mat, l_ear->next->next->v->co, center);
+ if (signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[1])) !=
+ signum_i(cross_tri_v2(adjacent_2d, tri_2d[2], tri_2d[0])))
+ {
+ return true;
+ }
+ }
+ }
+
+ /* check no existing verts are inside the triangle */
+ {
+ /* triangle may be concave, if so - flip so we can use clockwise check */
+ if (cross_tri_v2(UNPACK3(tri_2d)) < 0.0f) {
+ swap_v2_v2(tri_2d[1], tri_2d[2]);
+ }
+
+ /* skip l_ear and adjacent verts */
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_ear->next->next;
+ l_first = l_ear->prev;
+ do {
+ float co_2d[2];
+ mul_v2_m3v3_center(co_2d, axis_mat, l_iter->v->co, center);
+ if (isect_point_tri_v2_cw(co_2d, tri_2d[0], tri_2d[1], tri_2d[2])) {
+ return true;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ return false;
+}
+
+static bool bm_vert_collapse_is_degenerate(BMVert *v)
+{
+ BMEdge *e_pair[2];
+ BMVert *v_pair[2];
+
+ if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
+ v_pair[0] = BM_edge_other_vert(e_pair[0], v);
+ v_pair[1] = BM_edge_other_vert(e_pair[1], v);
+
+ if (fabsf(cos_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)) < (1.0f - FLT_EPSILON)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_pair[1]->l;
+ do {
+ if (l_iter->f->len > 3) {
+ BMLoop *l_pivot = (l_iter->v == v ? l_iter : l_iter->next);
+ BLI_assert(v == l_pivot->v);
+ if (bm_loop_collapse_is_degenerate(l_pivot)) {
+ return true;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+#endif /* USE_DEGENERATE_CHECK */
+
+
void BM_mesh_decimate_dissolve_ex(
BMesh *bm, const float angle_limit, const bool do_dissolve_boundaries,
BMO_Delimit delimit,
@@ -144,6 +258,7 @@ void BM_mesh_decimate_dissolve_ex(
BMEdge **einput_arr, const int einput_len,
const short oflag_out)
{
+ const float angle_limit_cos_neg = -cosf(angle_limit);
struct DelimitData delimit_data = {0};
const int eheap_table_len = do_dissolve_boundaries ? einput_len : max_ii(einput_len, vinput_len);
void *_heap_table = MEM_mallocN(sizeof(HeapNode *) * eheap_table_len, __func__);
@@ -193,7 +308,7 @@ void BM_mesh_decimate_dissolve_ex(
}
while ((BLI_heap_is_empty(eheap) == false) &&
- (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit))
+ (BLI_heap_node_value((enode_top = BLI_heap_top(eheap))) < angle_limit_cos_neg))
{
BMFace *f_new = NULL;
BMEdge *e;
@@ -328,7 +443,14 @@ void BM_mesh_decimate_dissolve_ex(
v = BLI_heap_node_ptr(vnode_top);
i = BM_elem_index_get(v);
- if (BM_vert_is_edge_pair(v)) {
+ if (
+#ifdef USE_DEGENERATE_CHECK
+ !bm_vert_collapse_is_degenerate(v)
+#else
+ BM_vert_is_edge_pair(v)
+#endif
+ )
+ {
e_new = BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
if (e_new) {
@@ -343,7 +465,6 @@ void BM_mesh_decimate_dissolve_ex(
do {
BM_face_normal_update(l_iter->f);
} while ((l_iter = l_iter->radial_next) != l_first);
-
}
/* re-calculate costs */
@@ -355,6 +476,33 @@ void BM_mesh_decimate_dissolve_ex(
vheap_table[j] = BLI_heap_insert(vheap, cost, v_iter);
}
}
+
+#ifdef USE_DEGENERATE_CHECK
+ /* dissolving a vertex may mean vertices we previously weren't able to dissolve
+ * can now be re-evaluated. */
+ if (e_new->l) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = e_new->l;
+ do {
+ /* skip vertices part of this edge, evaluated above */
+ BMLoop *l_cycle_first, *l_cycle_iter;
+ l_cycle_iter = l_iter->next->next;
+ l_cycle_first = l_iter->prev;
+ do {
+ const int j = BM_elem_index_get(l_cycle_iter->v);
+ if (j != -1 && vheap_table[j] &&
+ (BLI_heap_node_value(vheap_table[j]) == COST_INVALID))
+ {
+ const float cost = bm_vert_edge_face_angle(l_cycle_iter->v);
+ BLI_heap_remove(vheap, vheap_table[j]);
+ vheap_table[j] = BLI_heap_insert(vheap, cost, l_cycle_iter->v);
+ }
+ } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_first);
+
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+#endif /* USE_DEGENERATE_CHECK */
+
}
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 19cf2d29aff..e6437aa6c59 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -50,6 +50,7 @@
#endif
#include "BLI_kdopbvh.h"
+#include "BLI_buffer.h"
#include "bmesh.h"
#include "bmesh_intersect.h" /* own include */
@@ -70,12 +71,19 @@
#define USE_SEPARATE
/* remove verts created by intersecting triangles */
#define USE_DISSOLVE
+/* detect isolated holes and fill them */
+#define USE_NET_ISLAND_CONNECT
/* strict asserts that may fail in practice (handy for debugging cases which should succeed) */
// #define USE_PARANOID
/* use accelerated overlap check */
#define USE_BVH
+// #define USE_BOOLEAN_RAYCAST_DRAW
+
+#ifdef USE_BOOLEAN_RAYCAST_DRAW
+/* insert bl_debug_draw_quad_clear... here */
+#endif
static void tri_v3_scale(
float v1[3], float v2[3], float v3[3],
@@ -147,21 +155,20 @@ static bool ghash_insert_link(
GHash *gh, void *key, void *val, bool use_test,
MemArena *mem_arena)
{
+ void **ls_base_p;
struct LinkBase *ls_base;
LinkNode *ls;
- ls_base = BLI_ghash_lookup(gh, key);
-
- if (ls_base) {
- if (use_test && (BLI_linklist_index(ls_base->list, key) != -1)) {
- return false;
- }
- }
- else {
- ls_base = BLI_memarena_alloc(mem_arena, sizeof(*ls_base));
+ if (!BLI_ghash_ensure_p(gh, key, &ls_base_p)) {
+ ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base));
ls_base->list = NULL;
ls_base->list_len = 0;
- BLI_ghash_insert(gh, key, ls_base);
+ }
+ else {
+ ls_base = *ls_base_p;
+ if (use_test && (BLI_linklist_index(ls_base->list, val) != -1)) {
+ return false;
+ }
}
ls = BLI_memarena_alloc(mem_arena, sizeof(*ls));
@@ -231,12 +238,13 @@ static void face_edges_add(
#ifdef USE_NET
static void face_edges_split(
- BMesh *bm,
- BMFace *f,
- struct LinkBase *e_ls_base)
+ BMesh *bm, BMFace *f, struct LinkBase *e_ls_base,
+ bool use_island_connect,
+ MemArena *mem_arena_edgenet)
{
unsigned int i;
- BMEdge **edge_arr = BLI_array_alloca(edge_arr, e_ls_base->list_len);
+ unsigned int edge_arr_len = e_ls_base->list_len;
+ BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len);
LinkNode *node;
BLI_assert(f->head.htype == BM_FACE);
@@ -249,7 +257,26 @@ static void face_edges_split(
printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len);
#endif
- BM_face_split_edgenet(bm, f, edge_arr, (int)e_ls_base->list_len, NULL, NULL);
+#ifdef USE_NET_ISLAND_CONNECT
+ if (use_island_connect) {
+ unsigned int edge_arr_holes_len;
+ BMEdge **edge_arr_holes;
+ if (BM_face_split_edgenet_connect_islands(
+ bm, f,
+ edge_arr, edge_arr_len,
+ false,
+ mem_arena_edgenet,
+ &edge_arr_holes, &edge_arr_holes_len))
+ {
+ edge_arr_len = edge_arr_holes_len;
+ edge_arr = edge_arr_holes; /* owned by the arena */
+ }
+ }
+#else
+ UNUSED_VARS(use_island_connect, mem_arena_edgenet);
+#endif
+
+ BM_face_split_edgenet(bm, f, edge_arr, (int)edge_arr_len, NULL, NULL);
}
#endif
@@ -318,7 +345,7 @@ static enum ISectType intersect_line_tri(
/* check ray isn't planar with tri */
if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) {
- if (isect_line_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) {
+ if (isect_line_segment_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) {
if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
interp_v3_v3v3(r_ix, p0, p1, fac);
if (min_fff(len_squared_v3v3(t_cos[0], r_ix),
@@ -461,6 +488,35 @@ static BMVert *bm_isect_edge_tri(
return NULL;
}
+struct LoopFilterWrap {
+ int (*test_fn)(BMFace *f, void *user_data);
+ void *user_data;
+};
+
+static bool bm_loop_filter_fn(const BMLoop *l, void *user_data)
+{
+ if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) {
+ return false;
+ }
+
+ if (l->radial_next != l) {
+ struct LoopFilterWrap *data = user_data;
+ BMLoop *l_iter = l->radial_next;
+ const int face_side = data->test_fn(l->f, data->user_data);
+ do {
+ const int face_side_other = data->test_fn(l_iter->f, data->user_data);
+ if (UNLIKELY(face_side_other == -1)) {
+ /* pass */
+ }
+ else if (face_side_other != face_side) {
+ return false;
+ }
+ } while ((l_iter = l_iter->radial_next) != l);
+ return true;
+ }
+ return false;
+}
+
/**
* Return true if we have any intersections.
*/
@@ -774,23 +830,148 @@ static void bm_isect_tri_tri(
}
}
+#ifdef USE_BVH
+
+struct RaycastData {
+ const float **looptris;
+ BLI_Buffer *z_buffer;
+};
+
+#ifdef USE_KDOPBVH_WATERTIGHT
+static const struct IsectRayPrecalc isect_precalc_x = {1, 2, 0, 0, 0, 1};
+#endif
+
+static void raycast_callback(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *UNUSED(hit))
+{
+ struct RaycastData *raycast_data = userdata;
+ const float **looptris = raycast_data->looptris;
+ const float *v0 = looptris[index * 3 + 0];
+ const float *v1 = looptris[index * 3 + 1];
+ const float *v2 = looptris[index * 3 + 2];
+ float dist;
+
+ if (
+#ifdef USE_KDOPBVH_WATERTIGHT
+ isect_ray_tri_watertight_v3(ray->origin, &isect_precalc_x, v0, v1, v2, &dist, NULL)
+#else
+ isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON)
+#endif
+ )
+ {
+ if (dist >= 0.0f) {
+#ifdef USE_DUMP
+ printf("%s:\n", __func__);
+ print_v3(" origin", ray->origin);
+ print_v3(" direction", ray->direction);
+ printf(" dist %f\n", dist);
+ print_v3(" v0", v0);
+ print_v3(" v1", v1);
+ print_v3(" v2", v2);
+#endif
+
+#ifdef USE_DUMP
+ printf("%s: Adding depth %f\n", __func__, depth);
+#endif
+ BLI_buffer_append(raycast_data->z_buffer, float, dist);
+ }
+ }
+}
+
+static int isect_bvhtree_point_v3(
+ BVHTree *tree,
+ const float **looptris,
+ const float co[3])
+{
+ BLI_buffer_declare_static(float, z_buffer, BLI_BUFFER_NOP, 64);
+
+ struct RaycastData raycast_data = {
+ looptris,
+ &z_buffer,
+ };
+ BVHTreeRayHit hit = {0};
+ float dir[3] = {1.0f, 0.0f, 0.0f};
+
+ /* Need to initialize hit even tho it's not used.
+ * This is to make it so kdotree believes we didn't intersect anything and
+ * keeps calling the intersect callback.
+ */
+ hit.index = -1;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
+
+ BLI_bvhtree_ray_cast(tree,
+ co, dir,
+ 0.0f,
+ &hit,
+ raycast_callback,
+ &raycast_data);
+
+#ifdef USE_DUMP
+ printf("%s: Total intersections: %d\n", __func__, raycast_data.num_isect);
+#endif
+
+ int num_isect;
+
+ if (z_buffer.count == 0) {
+ num_isect = 0;
+ }
+ else if (z_buffer.count == 1) {
+ num_isect = 1;
+ }
+ else {
+ /* 2 or more */
+ const float eps = FLT_EPSILON * 10;
+ num_isect = 1; /* always count first */
+
+ qsort(z_buffer.data, z_buffer.count, sizeof(float), BLI_sortutil_cmp_float);
+
+ const float *depth_arr = z_buffer.data;
+ float depth_last = depth_arr[0];
+
+ for (unsigned int i = 1; i < z_buffer.count; i++) {
+ if (depth_arr[i] - depth_last > eps) {
+ depth_last = depth_arr[i];
+ num_isect++;
+ }
+ }
+
+ BLI_buffer_free(&z_buffer);
+ }
+
+
+ // return (num_isect & 1) == 1;
+ return num_isect;
+}
+
+#endif /* USE_BVH */
+
/**
* Intersect tessellated faces
* leaving the resulting edges tagged.
*
* \param test_fn Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
+ * \param boolean_mode -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT.
+ * \return true if the mesh is changed (intersections cut or faces removed from boolean).
*/
bool BM_mesh_intersect(
BMesh *bm,
struct BMLoop *(*looptris)[3], const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data), void *user_data,
- const bool use_self, const bool use_separate,
+ const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
+ const int boolean_mode,
const float eps)
{
struct ISectState s;
- bool has_isect;
const int totface_orig = bm->totface;
+ /* use to check if we made any changes */
+ bool has_edit_isect = false, has_edit_boolean = false;
+
+ /* needed for boolean, since cutting up faces moves the loops within the face */
+ const float **looptri_coords = NULL;
+
#ifdef USE_BVH
BVHTree *tree_a, *tree_b;
unsigned int tree_overlap_tot;
@@ -799,6 +980,10 @@ bool BM_mesh_intersect(
int i_a, i_b;
#endif
+#ifdef USE_BOOLEAN_RAYCAST_DRAW
+ bl_debug_draw_quad_clear();
+#endif
+
s.bm = bm;
s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
@@ -840,13 +1025,31 @@ bool BM_mesh_intersect(
0);
#ifdef USE_DISSOLVE
- BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
+ if (use_dissolve) {
+ BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
+ }
+#else
+ UNUSED_VARS(use_dissolve);
#endif
#ifdef USE_DUMP
printf("data = [\n");
#endif
+ if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ /* keep original geometrty for raycast callbacks */
+ float **cos;
+ int i, j;
+
+ cos = MEM_mallocN((size_t)looptris_tot * sizeof(*looptri_coords) * 3, __func__);
+ for (i = 0, j = 0; i < looptris_tot; i++) {
+ cos[j++] = looptris[i][0]->v->co;
+ cos[j++] = looptris[i][1]->v->co;
+ cos[j++] = looptris[i][2]->v->co;
+ }
+ looptri_coords = (const float **)cos;
+ }
+
#ifdef USE_BVH
{
int i;
@@ -908,9 +1111,13 @@ bool BM_mesh_intersect(
}
MEM_freeN(overlap);
}
- BLI_bvhtree_free(tree_a);
- if (tree_a != tree_b) {
- BLI_bvhtree_free(tree_b);
+
+ if (boolean_mode == BMESH_ISECT_BOOLEAN_NONE) {
+ /* no booleans, just free immediate */
+ BLI_bvhtree_free(tree_a);
+ if (tree_a != tree_b) {
+ BLI_bvhtree_free(tree_b);
+ }
}
#else
@@ -979,7 +1186,7 @@ bool BM_mesh_intersect(
}
#ifdef USE_DUMP
- printf("# SPLITTING EDGE: %d, %d\n", e_index, v_ls_base->list_len);
+ printf("# SPLITTING EDGE: %d, %d\n", BM_elem_index_get(e), v_ls_base->list_len);
#endif
/* intersect */
is_wire = BLI_gset_haskey(s.wire_edges, e);
@@ -999,7 +1206,8 @@ bool BM_mesh_intersect(
const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co);
if (BM_vert_in_edge(e, v_prev)) {
- v_prev = BM_edge_split(bm, e, v_prev, NULL, CLAMPIS(fac, 0.0f, 1.0f));
+ BMEdge *e_split;
+ v_prev = BM_edge_split(bm, e, v_prev, &e_split, CLAMPIS(fac, 0.0f, 1.0f));
BLI_assert(BM_vert_in_edge(e, v_end));
if (!BM_edge_exists(v_prev, vi) &&
@@ -1013,7 +1221,7 @@ bool BM_mesh_intersect(
}
v_prev = vi;
if (is_wire) {
- BLI_gset_insert(s.wire_edges, e);
+ BLI_gset_insert(s.wire_edges, e_split);
}
}
}
@@ -1025,7 +1233,7 @@ bool BM_mesh_intersect(
/* important to handle before edgenet */
#ifdef USE_DISSOLVE
- {
+ if (use_dissolve && (boolean_mode == BMESH_ISECT_BOOLEAN_NONE)) {
/* first pass */
BMVert *(*splice_ls)[2];
STACK_DECLARE(splice_ls);
@@ -1249,6 +1457,8 @@ bool BM_mesh_intersect(
GHashIterator gh_iter;
BMFace **faces;
+ MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
faces = bm->ftable;
GHASH_ITER (gh_iter, s.face_edges) {
@@ -1265,9 +1475,15 @@ bool BM_mesh_intersect(
BLI_assert(BM_elem_index_get(f) == f_index);
- face_edges_split(bm, f, e_ls_base);
+ face_edges_split(bm, f, e_ls_base, use_island_connect, mem_arena_edgenet);
+
+ BLI_memarena_clear(mem_arena_edgenet);
}
+
+ BLI_memarena_free(mem_arena_edgenet);
}
+#else
+ UNUSED_VARS(use_island_connect);
#endif /* USE_NET */
(void)totface_orig;
@@ -1284,11 +1500,171 @@ bool BM_mesh_intersect(
BM_mesh_edgesplit(bm, false, true, false);
}
+ else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ GSetIterator gs_iter;
+
+ /* no need to clear for boolean */
+
+ GSET_ITER (gs_iter, s.wire_edges) {
+ BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
#else
(void)use_separate;
#endif /* USE_SEPARATE */
- has_isect = (BLI_ghash_size(s.face_edges) != 0);
+ if ((boolean_mode != BMESH_ISECT_BOOLEAN_NONE)) {
+ BVHTree *tree_pair[2] = {tree_a, tree_b};
+
+ /* group vars */
+ int *groups_array;
+ int (*group_index)[2];
+ int group_tot;
+ int i;
+ BMFace **ftable;
+
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+ ftable = bm->ftable;
+
+ /* wrap the face-test callback to make it into an edge-loop delimiter */
+ struct LoopFilterWrap user_data_wrap = {
+ .test_fn = test_fn,
+ .user_data = user_data,
+ };
+
+ groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__);
+ group_tot = BM_mesh_calc_face_groups(
+ bm, groups_array, &group_index,
+ bm_loop_filter_fn, &user_data_wrap,
+ 0, BM_EDGE);
+
+#ifdef USE_DUMP
+ printf("%s: Total face-groups: %d\n", __func__, group_tot);
+#endif
+
+ /* Check if island is inside/outside */
+ for (i = 0; i < group_tot; i++) {
+ int fg = group_index[i][0];
+ int fg_end = group_index[i][1] + fg;
+ bool do_remove, do_flip;
+
+ {
+ /* for now assyme this is an OK face to test with (not degenerate!) */
+ BMFace *f = ftable[groups_array[fg]];
+ float co[3];
+ int hits;
+ int side = test_fn(f, user_data);
+
+ if (side == -1) {
+ continue;
+ }
+ BLI_assert(ELEM(side, 0, 1));
+ side = !side;
+
+ // BM_face_calc_center_mean(f, co);
+ BM_face_calc_point_in_face(f, co);
+
+ hits = isect_bvhtree_point_v3(tree_pair[side], looptri_coords, co);
+
+ switch (boolean_mode) {
+ case BMESH_ISECT_BOOLEAN_ISECT:
+ do_remove = ((hits & 1) != 1);
+ do_flip = false;
+ break;
+ case BMESH_ISECT_BOOLEAN_UNION:
+ do_remove = ((hits & 1) == 1);
+ do_flip = false;
+ break;
+ case BMESH_ISECT_BOOLEAN_DIFFERENCE:
+ do_remove = ((hits & 1) == 1) == side;
+ do_flip = (side == 0);
+ break;
+ }
+
+#ifdef USE_BOOLEAN_RAYCAST_DRAW
+ {
+ unsigned int colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff};
+ float co_other[3] = {UNPACK3(co)};
+ co_other[0] += 1000.0f;
+ bl_debug_color_set(colors[(hits & 1) == 1]);
+ bl_debug_draw_edge_add(co, co_other);
+ }
+#endif
+
+ }
+
+ if (do_remove) {
+ for (; fg != fg_end; fg++) {
+ /* postpone killing the face since we access below, mark instead */
+ // BM_face_kill_loose(bm, ftable[groups_array[fg]]);
+ ftable[groups_array[fg]]->mat_nr = -1;
+ }
+ }
+ else if (do_flip) {
+ for (; fg != fg_end; fg++) {
+ BM_face_normal_flip(bm, ftable[groups_array[fg]]);
+ }
+ }
+
+ has_edit_boolean |= (do_flip || do_remove);
+ }
+
+ MEM_freeN(groups_array);
+ MEM_freeN(group_index);
+
+#ifdef USE_DISSOLVE
+ /* We have dissolve code above, this is alternative logic,
+ * we need to do it after the boolean is executed. */
+ if (use_dissolve) {
+ LinkNode *node;
+ for (node = s.vert_dissolve; node; node = node->next) {
+ BMVert *v = node->link;
+ if (BM_vert_is_edge_pair(v)) {
+ /* we wont create degenerate faces from this */
+ bool ok = true;
+
+ /* would we create a 2-sided-face?
+ * if so, don't dissolve this since we may */
+ if (v->e->l) {
+ BMLoop *l_iter = v->e->l;
+ do {
+ if (l_iter->f->len == 3) {
+ ok = false;
+ break;
+ }
+ } while ((l_iter = l_iter->radial_next) != v->e->l);
+ }
+
+ if (ok) {
+ BM_vert_collapse_edge(bm, v->e, v, true, false);
+ }
+ }
+ }
+ }
+#endif
+
+ {
+ int tot = bm->totface;
+ for (i = 0; i < tot; i++) {
+ if (ftable[i]->mat_nr == -1) {
+ BM_face_kill_loose(bm, ftable[i]);
+ }
+ }
+ }
+ }
+
+ if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) {
+ MEM_freeN((void *)looptri_coords);
+
+ /* no booleans, just free immediate */
+ BLI_bvhtree_free(tree_a);
+ if (tree_a != tree_b) {
+ BLI_bvhtree_free(tree_b);
+ }
+ }
+
+ has_edit_isect = (BLI_ghash_size(s.face_edges) != 0);
/* cleanup */
BLI_ghash_free(s.edgetri_cache, NULL, NULL);
@@ -1299,5 +1675,5 @@ bool BM_mesh_intersect(
BLI_memarena_free(s.mem_arena);
- return has_isect;
+ return (has_edit_isect || has_edit_boolean);
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
index af6e510a8f6..d0cc41654eb 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.h
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -29,7 +29,16 @@ bool BM_mesh_intersect(
BMesh *bm,
struct BMLoop *(*looptris)[3], const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data), void *user_data,
- const bool use_self, const bool use_separate,
+ const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect,
+ const int boolean_mode,
const float eps);
+enum {
+ BMESH_ISECT_BOOLEAN_NONE = -1,
+ /* aligned with BooleanModifierOp */
+ BMESH_ISECT_BOOLEAN_ISECT = 0,
+ BMESH_ISECT_BOOLEAN_UNION = 1,
+ BMESH_ISECT_BOOLEAN_DIFFERENCE = 2,
+};
+
#endif /* __BMESH_INTERSECT_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c
index 6633803414b..30b083cacda 100644
--- a/source/blender/bmesh/tools/bmesh_path.c
+++ b/source/blender/bmesh/tools/bmesh_path.c
@@ -15,13 +15,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2004 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
* ***** END GPL LICENSE BLOCK *****
*/
@@ -41,6 +34,7 @@
#include "bmesh.h"
#include "bmesh_path.h" /* own include */
+
/* -------------------------------------------------------------------- */
/* Generic Helpers */
@@ -67,35 +61,66 @@ static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3
/* -------------------------------------------------------------------- */
/* BM_mesh_calc_path_vert */
-static void verttag_add_adjacent(Heap *heap, BMVert *v_a, BMVert **verts_prev, float *cost, const bool use_length)
+static void verttag_add_adjacent(
+ Heap *heap, BMVert *v_a, BMVert **verts_prev, float *cost,
+ const struct BMCalcPathParams *params)
{
- BMIter eiter;
- BMEdge *e;
- BMVert *v_b;
-
const int v_a_index = BM_elem_index_get(v_a);
- /* loop over faces of face, but do so by first looping over loops */
- BM_ITER_ELEM (e, &eiter, v_a, BM_EDGES_OF_VERT) {
- v_b = BM_edge_other_vert(e, v_a);
- if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
- /* we know 'f_b' is not visited, check it out! */
- const int v_b_index = BM_elem_index_get(v_b);
- const float cost_cut = use_length ? len_v3v3(v_a->co, v_b->co) : 1.0f;
- const float cost_new = cost[v_a_index] + cost_cut;
-
- if (cost[v_b_index] > cost_new) {
- cost[v_b_index] = cost_new;
- verts_prev[v_b_index] = v_a;
- BLI_heap_insert(heap, cost_new, v_b);
+ {
+ BMIter eiter;
+ BMEdge *e;
+ /* loop over faces of face, but do so by first looping over loops */
+ BM_ITER_ELEM (e, &eiter, v_a, BM_EDGES_OF_VERT) {
+ BMVert *v_b = BM_edge_other_vert(e, v_a);
+ if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ /* we know 'v_b' is not visited, check it out! */
+ const int v_b_index = BM_elem_index_get(v_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f : len_v3v3(v_a->co, v_b->co);
+ const float cost_new = cost[v_a_index] + cost_cut;
+
+ if (cost[v_b_index] > cost_new) {
+ cost[v_b_index] = cost_new;
+ verts_prev[v_b_index] = v_a;
+ BLI_heap_insert(heap, cost_new, v_b);
+ }
+ }
+ }
+ }
+
+ if (params->use_step_face) {
+ BMIter liter;
+ BMLoop *l;
+ /* loop over faces of face, but do so by first looping over loops */
+ BM_ITER_ELEM (l, &liter, v_a, BM_LOOPS_OF_VERT) {
+ if (l->f->len > 3) {
+ /* skip loops on adjacent edges */
+ BMLoop *l_iter = l->next->next;
+ do {
+ BMVert *v_b = l_iter->v;
+ if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ /* we know 'v_b' is not visited, check it out! */
+ const int v_b_index = BM_elem_index_get(v_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f : len_v3v3(v_a->co, v_b->co);
+ const float cost_new = cost[v_a_index] + cost_cut;
+
+ if (cost[v_b_index] > cost_new) {
+ cost[v_b_index] = cost_new;
+ verts_prev[v_b_index] = v_a;
+ BLI_heap_insert(heap, cost_new, v_b);
+ }
+ }
+ } while ((l_iter = l_iter->next) != l->prev);
}
}
}
}
LinkNode *BM_mesh_calc_path_vert(
- BMesh *bm, BMVert *v_src, BMVert *v_dst, const bool use_length,
- bool (*test_fn)(BMVert *, void *user_data), void *user_data)
+ BMesh *bm, BMVert *v_src, BMVert *v_dst, const struct BMCalcPathParams *params,
+ bool (*filter_fn)(BMVert *, void *user_data), void *user_data)
{
LinkNode *path = NULL;
/* BM_ELEM_TAG flag is used to store visited edges */
@@ -110,13 +135,7 @@ LinkNode *BM_mesh_calc_path_vert(
// BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
- if (test_fn(v, user_data)) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
- else {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
-
+ BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
BM_elem_index_set(v, i); /* set_inline */
}
bm->elem_index_dirty &= ~BM_VERT;
@@ -152,7 +171,7 @@ LinkNode *BM_mesh_calc_path_vert(
if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
BM_elem_flag_enable(v, BM_ELEM_TAG);
- verttag_add_adjacent(heap, v, verts_prev, cost, use_length);
+ verttag_add_adjacent(heap, v, verts_prev, cost, params);
}
}
@@ -169,58 +188,110 @@ LinkNode *BM_mesh_calc_path_vert(
return path;
}
-
-
/* -------------------------------------------------------------------- */
/* BM_mesh_calc_path_edge */
-
-static float edgetag_cut_cost(BMEdge *e1, BMEdge *e2, BMVert *v)
+static float edgetag_cut_cost_vert(BMEdge *e_a, BMEdge *e_b, BMVert *v)
{
- BMVert *v1 = BM_edge_other_vert(e1, v);
- BMVert *v2 = BM_edge_other_vert(e2, v);
+ BMVert *v1 = BM_edge_other_vert(e_a, v);
+ BMVert *v2 = BM_edge_other_vert(e_b, v);
return step_cost_3_v3(v1->co, v->co, v2->co);
}
-static void edgetag_add_adjacent(Heap *heap, BMEdge *e1, BMEdge **edges_prev, float *cost, const bool use_length)
+static float edgetag_cut_cost_face(BMEdge *e_a, BMEdge *e_b, BMFace *f)
{
- BMIter viter;
- BMVert *v;
+ float e_a_cent[3], e_b_cent[3], f_cent[3];
- BMIter eiter;
- BMEdge *e2;
+ mid_v3_v3v3(e_a_cent, e_a->v1->co, e_a->v1->co);
+ mid_v3_v3v3(e_b_cent, e_b->v1->co, e_b->v1->co);
- const int e1_index = BM_elem_index_get(e1);
+ BM_face_calc_center_mean_weighted(f, f_cent);
- BM_ITER_ELEM (v, &viter, e1, BM_VERTS_OF_EDGE) {
+ return step_cost_3_v3(e_a_cent, e_b_cent, f_cent);
+}
- /* don't walk over previous vertex */
- if ((edges_prev[e1_index]) &&
- (BM_vert_in_edge(edges_prev[e1_index], v)))
- {
- continue;
- }
+static void edgetag_add_adjacent(
+ Heap *heap, BMEdge *e_a, BMEdge **edges_prev, float *cost,
+ const struct BMCalcPathParams *params)
+{
+ const int e_a_index = BM_elem_index_get(e_a);
+
+ /* unlike vert/face, stepping faces disables scanning connected edges
+ * and only steps over faces (selecting a ring of edges instead of a loop) */
+ if (params->use_step_face == false) {
+ BMIter viter;
+ BMVert *v;
+
+ BMIter eiter;
+ BMEdge *e_b;
+
+ BM_ITER_ELEM (v, &viter, e_a, BM_VERTS_OF_EDGE) {
- BM_ITER_ELEM (e2, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e2, BM_ELEM_TAG)) {
- /* we know 'e2' is not visited, check it out! */
- const int e2_index = BM_elem_index_get(e2);
- const float cost_cut = use_length ? edgetag_cut_cost(e1, e2, v) : 1.0f;
- const float cost_new = cost[e1_index] + cost_cut;
-
- if (cost[e2_index] > cost_new) {
- cost[e2_index] = cost_new;
- edges_prev[e2_index] = e1;
- BLI_heap_insert(heap, cost_new, e2);
+ /* don't walk over previous vertex */
+ if ((edges_prev[e_a_index]) &&
+ (BM_vert_in_edge(edges_prev[e_a_index], v)))
+ {
+ continue;
+ }
+
+ BM_ITER_ELEM (e_b, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
+ /* we know 'e_b' is not visited, check it out! */
+ const int e_b_index = BM_elem_index_get(e_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f : edgetag_cut_cost_vert(e_a, e_b, v);
+ const float cost_new = cost[e_a_index] + cost_cut;
+
+ if (cost[e_b_index] > cost_new) {
+ cost[e_b_index] = cost_new;
+ edges_prev[e_b_index] = e_a;
+ BLI_heap_insert(heap, cost_new, e_b);
+ }
}
}
}
}
+ else {
+ BMLoop *l_first, *l_iter;
+
+ l_iter = l_first = e_a->l;
+ do {
+ BMLoop *l_cycle_iter, *l_cycle_end;
+
+ l_cycle_iter = l_iter->next;
+ l_cycle_end = l_iter;
+
+ /* good, but we need to allow this otherwise paths may fail to connect at all */
+#if 0
+ if (l_iter->f->len > 3) {
+ l_cycle_iter = l_cycle_iter->next;
+ l_cycle_end = l_cycle_end->prev;
+ }
+#endif
+
+ do {
+ BMEdge *e_b = l_cycle_iter->e;
+ if (!BM_elem_flag_test(e_b, BM_ELEM_TAG)) {
+ /* we know 'e_b' is not visited, check it out! */
+ const int e_b_index = BM_elem_index_get(e_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f : edgetag_cut_cost_face(e_a, e_b, l_iter->f);
+ const float cost_new = cost[e_a_index] + cost_cut;
+
+ if (cost[e_b_index] > cost_new) {
+ cost[e_b_index] = cost_new;
+ edges_prev[e_b_index] = e_a;
+ BLI_heap_insert(heap, cost_new, e_b);
+ }
+ }
+ } while ((l_cycle_iter = l_cycle_iter->next) != l_cycle_end);
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
}
LinkNode *BM_mesh_calc_path_edge(
- BMesh *bm, BMEdge *e_src, BMEdge *e_dst, const bool use_length,
+ BMesh *bm, BMEdge *e_src, BMEdge *e_dst, const struct BMCalcPathParams *params,
bool (*filter_fn)(BMEdge *, void *user_data), void *user_data)
{
LinkNode *path = NULL;
@@ -236,13 +307,7 @@ LinkNode *BM_mesh_calc_path_edge(
BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
- if (filter_fn(e, user_data)) {
- BM_elem_flag_disable(e, BM_ELEM_TAG);
- }
- else {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
-
+ BM_elem_flag_set(e, BM_ELEM_TAG, !filter_fn(e, user_data));
BM_elem_index_set(e, i); /* set_inline */
}
bm->elem_index_dirty &= ~BM_EDGE;
@@ -278,7 +343,7 @@ LinkNode *BM_mesh_calc_path_edge(
if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
BM_elem_flag_enable(e, BM_ELEM_TAG);
- edgetag_add_adjacent(heap, e, edges_prev, cost, use_length);
+ edgetag_add_adjacent(heap, e, edges_prev, cost, params);
}
}
@@ -296,58 +361,117 @@ LinkNode *BM_mesh_calc_path_edge(
}
-
/* -------------------------------------------------------------------- */
/* BM_mesh_calc_path_face */
-static float facetag_cut_cost(BMFace *f_a, BMFace *f_b, BMEdge *e)
+static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e)
{
float f_a_cent[3];
float f_b_cent[3];
float e_cent[3];
- BM_face_calc_center_mean(f_a, f_a_cent);
- BM_face_calc_center_mean(f_b, f_b_cent);
+ BM_face_calc_center_mean_weighted(f_a, f_a_cent);
+ BM_face_calc_center_mean_weighted(f_b, f_b_cent);
+#if 0
mid_v3_v3v3(e_cent, e->v1->co, e->v2->co);
+#else
+ /* for triangle fans it gives better results to pick a point on the edge */
+ {
+ float ix_e[3], ix_f[3], f;
+ isect_line_line_v3(e->v1->co, e->v2->co, f_a_cent, f_b_cent, ix_e, ix_f);
+ f = line_point_factor_v3(ix_e, e->v1->co, e->v2->co);
+ if (f < 0.0f) {
+ copy_v3_v3(e_cent, e->v1->co);
+ }
+ else if (f > 1.0f) {
+ copy_v3_v3(e_cent, e->v2->co);
+ }
+ else {
+ copy_v3_v3(e_cent, ix_e);
+ }
+ }
+#endif
return step_cost_3_v3(f_a_cent, e_cent, f_b_cent);
}
-static void facetag_add_adjacent(Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost, const bool use_length)
+static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v)
{
- BMIter liter;
- BMLoop *l_a;
- BMFace *f_b;
+ float f_a_cent[3];
+ float f_b_cent[3];
+
+ BM_face_calc_center_mean_weighted(f_a, f_a_cent);
+ BM_face_calc_center_mean_weighted(f_b, f_b_cent);
+
+ return step_cost_3_v3(f_a_cent, v->co, f_b_cent);
+}
+static void facetag_add_adjacent(
+ Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost,
+ const struct BMCalcPathParams *params)
+{
const int f_a_index = BM_elem_index_get(f_a);
/* loop over faces of face, but do so by first looping over loops */
- BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
- BMLoop *l_first;
- BMLoop *l_iter;
+ {
+ BMIter liter;
+ BMLoop *l_a;
+
+ BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
+ BMLoop *l_first, *l_iter;
+
+ l_iter = l_first = l_a;
+ do {
+ BMFace *f_b = l_iter->f;
+ if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
+ /* we know 'f_b' is not visited, check it out! */
+ const int f_b_index = BM_elem_index_get(f_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e);
+ const float cost_new = cost[f_a_index] + cost_cut;
+
+ if (cost[f_b_index] > cost_new) {
+ cost[f_b_index] = cost_new;
+ faces_prev[f_b_index] = f_a;
+ BLI_heap_insert(heap, cost_new, f_b);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ }
- l_iter = l_first = l_a;
- do {
- f_b = l_iter->f;
- if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
- /* we know 'f_b' is not visited, check it out! */
- const int f_b_index = BM_elem_index_get(f_b);
- const float cost_cut = use_length ? facetag_cut_cost(f_a, f_b, l_iter->e) : 1.0f;
- const float cost_new = cost[f_a_index] + cost_cut;
-
- if (cost[f_b_index] > cost_new) {
- cost[f_b_index] = cost_new;
- faces_prev[f_b_index] = f_a;
- BLI_heap_insert(heap, cost_new, f_b);
+ if (params->use_step_face) {
+ BMIter liter;
+ BMLoop *l_a;
+
+ BM_ITER_ELEM (l_a, &liter, f_a, BM_LOOPS_OF_FACE) {
+ BMIter litersub;
+ BMLoop *l_b;
+ BM_ITER_ELEM (l_b, &litersub, l_a->v, BM_LOOPS_OF_VERT) {
+ if ((l_a != l_b) && !BM_loop_share_edge_check(l_a, l_b)) {
+ BMFace *f_b = l_b->f;
+ if (!BM_elem_flag_test(f_b, BM_ELEM_TAG)) {
+ /* we know 'f_b' is not visited, check it out! */
+ const int f_b_index = BM_elem_index_get(f_b);
+ const float cost_cut = params->use_topology_distance ?
+ 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v);
+ const float cost_new = cost[f_a_index] + cost_cut;
+
+ if (cost[f_b_index] > cost_new) {
+ cost[f_b_index] = cost_new;
+ faces_prev[f_b_index] = f_a;
+ BLI_heap_insert(heap, cost_new, f_b);
+ }
+ }
}
}
- } while ((l_iter = l_iter->radial_next) != l_first);
+ }
}
}
LinkNode *BM_mesh_calc_path_face(
- BMesh *bm, BMFace *f_src, BMFace *f_dst, const bool use_length,
- bool (*test_fn)(BMFace *, void *user_data), void *user_data)
+ BMesh *bm, BMFace *f_src, BMFace *f_dst, const struct BMCalcPathParams *params,
+ bool (*filter_fn)(BMFace *, void *user_data), void *user_data)
{
LinkNode *path = NULL;
/* BM_ELEM_TAG flag is used to store visited edges */
@@ -362,13 +486,7 @@ LinkNode *BM_mesh_calc_path_face(
// BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG
BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
- if (test_fn(f, user_data)) {
- BM_elem_flag_disable(f, BM_ELEM_TAG);
- }
- else {
- BM_elem_flag_enable(f, BM_ELEM_TAG);
- }
-
+ BM_elem_flag_set(f, BM_ELEM_TAG, !filter_fn(f, user_data));
BM_elem_index_set(f, i); /* set_inline */
}
bm->elem_index_dirty &= ~BM_FACE;
@@ -404,7 +522,7 @@ LinkNode *BM_mesh_calc_path_face(
if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
- facetag_add_adjacent(heap, f, faces_prev, cost, use_length);
+ facetag_add_adjacent(heap, f, faces_prev, cost, params);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_path.h b/source/blender/bmesh/tools/bmesh_path.h
index c39e08e83ef..b6de5e0e4e0 100644
--- a/source/blender/bmesh/tools/bmesh_path.h
+++ b/source/blender/bmesh/tools/bmesh_path.h
@@ -27,19 +27,24 @@
* \ingroup bmesh
*/
+struct BMCalcPathParams {
+ unsigned int use_topology_distance : 1;
+ unsigned int use_step_face : 1;
+};
+
struct LinkNode *BM_mesh_calc_path_vert(
- BMesh *bm, BMVert *v_src, BMVert *v_dst, const bool use_length,
+ BMesh *bm, BMVert *v_src, BMVert *v_dst, const struct BMCalcPathParams *params,
bool (*filter_fn)(BMVert *, void *), void *user_data)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5);
struct LinkNode *BM_mesh_calc_path_edge(
- BMesh *bm, BMEdge *e_src, BMEdge *e_dst, const bool use_length,
+ BMesh *bm, BMEdge *e_src, BMEdge *e_dst, const struct BMCalcPathParams *params,
bool (*filter_fn)(BMEdge *, void *), void *user_data)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5);
struct LinkNode *BM_mesh_calc_path_face(
- BMesh *bm, BMFace *f_src, BMFace *f_dst, const bool use_length,
- bool (*test_fn)(BMFace *, void *), void *user_data)
+ BMesh *bm, BMFace *f_src, BMFace *f_dst, const struct BMCalcPathParams *params,
+ bool (*filter_fn)(BMFace *, void *), void *user_data)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5);
#endif /* __BMESH_PATH_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_path_region.c b/source/blender/bmesh/tools/bmesh_path_region.c
new file mode 100644
index 00000000000..aad1f9c5a49
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_path_region.c
@@ -0,0 +1,477 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/tools/bmesh_path_region.c
+ * \ingroup bmesh
+ *
+ * Find the region defined by the path(s) between 2 elements.
+ * (path isn't ordered).
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+#include "BLI_stackdefines.h"
+#include "BLI_alloca.h"
+
+#include "bmesh.h"
+#include "bmesh_path_region.h" /* own include */
+
+
+/* Special handling of vertices with 2 edges
+ * (act as if the edge-chain is a single edge). */
+#define USE_EDGE_CHAIN
+
+
+#ifdef USE_EDGE_CHAIN
+/**
+ * Takes a vertex with 2 edge users and fills in the vertices at each end-point,
+ * or nothing if if the edges loop back to its self.
+ */
+static bool bm_vert_pair_ends(BMVert *v_pivot, BMVert *v_end_pair[2])
+{
+ BMEdge *e = v_pivot->e;
+ int j = 0;
+ do {
+ BMEdge *e_chain = e;
+ BMVert *v_other = BM_edge_other_vert(e_chain, v_pivot);
+ while (BM_vert_is_edge_pair(v_other)) {
+ BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_other);
+ BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_other) == e_chain);
+ v_other = BM_edge_other_vert(e_chain_next, v_other);
+ if (v_other == v_pivot) {
+ return false;
+ }
+ e_chain = e_chain_next;
+ }
+ v_end_pair[j++] = v_other;
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != v_pivot->e);
+
+ BLI_assert(j == 2);
+ return true;
+}
+#endif /* USE_EDGE_CHAIN */
+
+
+/** \name Vertex in Region Checks
+ * \{ */
+
+static bool bm_vert_region_test(BMVert *v, int * const depths[2], const int pass)
+{
+ const int index = BM_elem_index_get(v);
+ return (((depths[0][index] != -1) && (depths[1][index] != -1)) && \
+ ((depths[0][index] + depths[1][index]) < pass));
+}
+
+#ifdef USE_EDGE_CHAIN
+static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const int pass)
+{
+ BMVert *v_end_pair[2];
+ if (bm_vert_region_test(v, depths, pass)) {
+ return true;
+ }
+ else if (BM_vert_is_edge_pair(v) &&
+ bm_vert_pair_ends(v, v_end_pair) &&
+ bm_vert_region_test(v_end_pair[0], depths, pass) &&
+ bm_vert_region_test(v_end_pair[1], depths, pass))
+ {
+ return true;
+ }
+
+ return false;
+}
+#else
+static bool bm_vert_region_test_chain(BMVert *v, int * const depths[2], const int pass)
+{
+ return bm_vert_region_test(v, depths, pass);
+}
+#endif
+
+/** \} */
+
+
+/**
+ * Main logic for calculating region between 2 elements.
+ *
+ * This method works walking (breadth first) over all vertices,
+ * keeping track of topological distance from the source.
+ *
+ * This is done in both directions, after that each vertices 'depth' is added to check
+ * if its less than the number of passes needed to complete the search.
+ * When it is, we know the path is one of possible paths that have the minimum topological distance.
+ *
+ * \note Only verts without BM_ELEM_TAG will be walked over.
+ */
+static LinkNode *mesh_calc_path_region_elem(
+ BMesh *bm,
+ BMElem *ele_src, BMElem *ele_dst,
+ const char path_htype)
+{
+ int ele_verts_len[2];
+ BMVert **ele_verts[2];
+
+ /* Get vertices from any `ele_src/ele_dst` elements. */
+ for (int side = 0; side < 2; side++) {
+ BMElem *ele = side ? ele_dst : ele_src;
+ int j = 0;
+
+ if (ele->head.htype == BM_FACE) {
+ BMFace *f = (BMFace *)ele;
+ ele_verts[side] = BLI_array_alloca(ele_verts[side], f->len);
+
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ ele_verts[side][j++] = l_iter->v;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ else if (ele->head.htype == BM_EDGE) {
+ BMEdge *e = (BMEdge *)ele;
+ ele_verts[side] = BLI_array_alloca(ele_verts[side], 2);
+
+ ele_verts[side][j++] = e->v1;
+ ele_verts[side][j++] = e->v2;
+ }
+ else if (ele->head.htype == BM_VERT) {
+ BMVert *v = (BMVert *)ele;
+ ele_verts[side] = BLI_array_alloca(ele_verts[side], 1);
+
+ ele_verts[side][j++] = v;
+ }
+ else {
+ BLI_assert(0);
+ }
+ ele_verts_len[side] = j;
+ }
+
+ int *depths[2] = {NULL};
+ int pass = 0;
+
+ BMVert **stack = MEM_mallocN(sizeof(*stack) * bm->totvert, __func__);
+ BMVert **stack_other = MEM_mallocN(sizeof(*stack_other) * bm->totvert, __func__);
+
+ STACK_DECLARE(stack);
+ STACK_INIT(stack, bm->totvert);
+
+ STACK_DECLARE(stack_other);
+ STACK_INIT(stack_other, bm->totvert);
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ /* After exhausting all possible elements, we should have found all elements on the 'side_other'.
+ * otherwise, exit early. */
+ bool found_all = false;
+
+ for (int side = 0; side < 2; side++) {
+ const int side_other = !side;
+
+ /* initialize depths to -1 (un-touched), fill in with the depth as we walk over the edges. */
+ depths[side] = MEM_mallocN(sizeof(*depths[side]) * bm->totvert, __func__);
+ copy_vn_i(depths[side], bm->totvert, -1);
+
+ /* needed for second side */
+ STACK_CLEAR(stack);
+ STACK_CLEAR(stack_other);
+
+ for (int i = 0; i < ele_verts_len[side]; i++) {
+ BMVert *v = ele_verts[side][i];
+ depths[side][BM_elem_index_get(v)] = 0;
+ if (v->e && !BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ STACK_PUSH(stack, v);
+ }
+ }
+
+#ifdef USE_EDGE_CHAIN
+ /* Expand initial state to end-point vertices when they only have 2x edges,
+ * this prevents odd behavior when source or destination are in the middle of a long chain of edges. */
+ if (ELEM(path_htype, BM_VERT, BM_EDGE)) {
+ for (int i = 0; i < ele_verts_len[side]; i++) {
+ BMVert *v = ele_verts[side][i];
+ BMVert *v_end_pair[2];
+ if (BM_vert_is_edge_pair(v) && bm_vert_pair_ends(v, v_end_pair)) {
+ for (int j = 0; j < 2; j++) {
+ const int v_end_index = BM_elem_index_get(v_end_pair[j]);
+ if (depths[side][v_end_index] == -1) {
+ depths[side][v_end_index] = 0;
+ if (!BM_elem_flag_test(v_end_pair[j], BM_ELEM_TAG)) {
+ STACK_PUSH(stack, v_end_pair[j]);
+ }
+ }
+ }
+ }
+ }
+ }
+#endif /* USE_EDGE_CHAIN */
+
+ /* Keep walking over connected geometry until we find all the vertices in `ele_verts[side_other]`,
+ * or exit the loop when theres no connection. */
+ found_all = false;
+ for (pass = 1; (STACK_SIZE(stack) != 0); pass++) {
+ while (STACK_SIZE(stack) != 0) {
+ BMVert *v_a = STACK_POP(stack);
+ // const int v_a_index = BM_elem_index_get(v_a); /* only for assert */
+ BMEdge *e = v_a->e;
+
+ do {
+ BMVert *v_b = BM_edge_other_vert(e, v_a);
+ int v_b_index = BM_elem_index_get(v_b);
+ if (depths[side][v_b_index] == -1) {
+
+#ifdef USE_EDGE_CHAIN
+ /* Walk along the chain, fill in values until we reach a vertex with 3+ edges. */
+ {
+ BMEdge *e_chain = e;
+ while (BM_vert_is_edge_pair(v_b) &&
+ ((depths[side][v_b_index] == -1)))
+ {
+ depths[side][v_b_index] = pass;
+
+ BMEdge *e_chain_next = BM_DISK_EDGE_NEXT(e_chain, v_b);
+ BLI_assert(BM_DISK_EDGE_NEXT(e_chain_next, v_b) == e_chain);
+ v_b = BM_edge_other_vert(e_chain_next, v_b);
+ v_b_index = BM_elem_index_get(v_b);
+ e_chain = e_chain_next;
+ }
+ }
+#endif /* USE_EDGE_CHAIN */
+
+ /* Add the other vertex to the stack, to be traversed in the next pass. */
+ if (depths[side][v_b_index] == -1) {
+#ifdef USE_EDGE_CHAIN
+ BLI_assert(!BM_vert_is_edge_pair(v_b));
+#endif
+ BLI_assert(pass == depths[side][BM_elem_index_get(v_a)] + 1);
+ depths[side][v_b_index] = pass;
+ if (!BM_elem_flag_test(v_b, BM_ELEM_TAG)) {
+ STACK_PUSH(stack_other, v_b);
+ }
+ }
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != v_a->e);
+ }
+
+ /* Stop searching once theres none left.
+ * Note that this looks in-efficient, however until the target elements reached,
+ * it will exit immediately.
+ * After that, it takes as many passes as the element has edges to finish off. */
+ found_all = true;
+ for (int i = 0; i < ele_verts_len[side_other]; i++) {
+ if (depths[side][BM_elem_index_get(ele_verts[side_other][i])] == -1) {
+ found_all = false;
+ break;
+ }
+ }
+ if (found_all == true) {
+ pass++;
+ break;
+ }
+
+ STACK_SWAP(stack, stack_other);
+ }
+
+ /* if we have nothing left, and didn't find all elements on the other side,
+ * exit early and don't continue */
+ if (found_all == false) {
+ break;
+ }
+ }
+
+ MEM_freeN(stack);
+ MEM_freeN(stack_other);
+
+
+ /* Now we have depths recorded from both sides,
+ * select elements that use tagged verts. */
+ LinkNode *path = NULL;
+
+ if (found_all == false) {
+ /* fail! (do nothing) */
+ }
+ else if (path_htype == BM_FACE) {
+ BMIter fiter;
+ BMFace *f;
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ /* check all verts in face are tagged */
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ bool ok = true;
+#if 0
+ do {
+ if (!bm_vert_region_test_chain(l_iter->v, depths, pass)) {
+ ok = false;
+ break;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+#else
+ /* Allowing a single failure on a face gives fewer 'gaps'.
+ * While correct, in practice they're often part of what a user would consider the 'region'. */
+ int ok_tests = f->len > 3 ? 1 : 0; /* how many times we may fail */
+ do {
+ if (!bm_vert_region_test_chain(l_iter->v, depths, pass)) {
+ if (ok_tests == 0) {
+ ok = false;
+ break;
+ }
+ ok_tests--;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+#endif
+
+ if (ok) {
+ BLI_linklist_prepend(&path, f);
+ }
+ }
+ }
+ }
+ else if (path_htype == BM_EDGE) {
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ /* check all verts in edge are tagged */
+ bool ok = true;
+ for (int j = 0; j < 2; j++) {
+ if (!bm_vert_region_test_chain(*((&e->v1) + j), depths, pass)) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ BLI_linklist_prepend(&path, e);
+ }
+ }
+ }
+ }
+ else if (path_htype == BM_VERT) {
+ BMIter viter;
+ BMVert *v;
+
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ if (bm_vert_region_test_chain(v, depths, pass)) {
+ BLI_linklist_prepend(&path, v);
+ }
+ }
+ }
+
+
+ for (int side = 0; side < 2; side++) {
+ if (depths[side]) {
+ MEM_freeN(depths[side]);
+ }
+ }
+
+ return path;
+}
+
+#undef USE_EDGE_CHAIN
+
+
+/** \name Main Functions (exposed externally).
+ * \{ */
+
+LinkNode *BM_mesh_calc_path_region_vert(
+ BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
+ bool (*filter_fn)(BMVert *, void *user_data), void *user_data)
+{
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited verts */
+ BMVert *v;
+ BMIter viter;
+ int i;
+
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, !filter_fn(v, user_data));
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_VERT);
+
+ return path;
+}
+
+LinkNode *BM_mesh_calc_path_region_edge(
+ BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
+ bool (*filter_fn)(BMEdge *, void *user_data), void *user_data)
+{
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited verts */
+ BMEdge *e;
+ BMIter eiter;
+ int i;
+
+ /* flush flag to verts */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
+ bool test;
+ BM_elem_flag_set(e, BM_ELEM_TAG, test = !filter_fn(e, user_data));
+
+ /* flush tag to verts */
+ if (test == false) {
+ for (int j = 0; j < 2; j++) {
+ BM_elem_flag_disable(*((&e->v1) + j), BM_ELEM_TAG);
+ }
+ }
+ }
+
+ path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_EDGE);
+
+ return path;
+}
+
+LinkNode *BM_mesh_calc_path_region_face(
+ BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
+ bool (*filter_fn)(BMFace *, void *user_data), void *user_data)
+{
+ LinkNode *path = NULL;
+ /* BM_ELEM_TAG flag is used to store visited verts */
+ BMFace *f;
+ BMIter fiter;
+ int i;
+
+ /* flush flag to verts */
+ BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) {
+ bool test;
+ BM_elem_flag_set(f, BM_ELEM_TAG, test = !filter_fn(f, user_data));
+
+ /* flush tag to verts */
+ if (test == false) {
+ BMLoop *l_first, *l_iter;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+
+ path = mesh_calc_path_region_elem(bm, ele_src, ele_dst, BM_FACE);
+
+ return path;
+}
+
+/** \} */
diff --git a/source/blender/bmesh/tools/bmesh_path_region.h b/source/blender/bmesh/tools/bmesh_path_region.h
new file mode 100644
index 00000000000..06e56a59fb2
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_path_region.h
@@ -0,0 +1,43 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_PATH_REGION_H__
+#define __BMESH_PATH_REGION_H__
+
+/** \file blender/bmesh/tools/bmesh_path_region.h
+ * \ingroup bmesh
+ */
+
+struct LinkNode *BM_mesh_calc_path_region_vert(
+ BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
+ bool (*test_fn)(BMVert *, void *user_data), void *user_data)
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+
+struct LinkNode *BM_mesh_calc_path_region_edge(
+ BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
+ bool (*test_fn)(BMEdge *, void *user_data), void *user_data)
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+
+struct LinkNode *BM_mesh_calc_path_region_face(
+ BMesh *bm, BMElem *ele_src, BMElem *ele_dst,
+ bool (*test_fn)(BMFace *, void *user_data), void *user_data)
+ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3);
+
+#endif /* __BMESH_PATH_REGION_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c
index 6f2aaf28179..ce1bc46d5e8 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.c
+++ b/source/blender/bmesh/tools/bmesh_triangulate.c
@@ -36,6 +36,7 @@
#include "BLI_memarena.h"
#include "BLI_heap.h"
#include "BLI_edgehash.h"
+#include "BLI_linklist.h"
/* only for defines */
#include "BLI_polyfill2d.h"
@@ -52,7 +53,7 @@ static void bm_face_triangulate_mapping(
BMesh *bm, BMFace *face,
const int quad_method, const int ngon_method,
const bool use_tag,
- BMOperator *op, BMOpSlot *slot_facemap_out,
+ BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out,
MemArena *pf_arena,
/* use for MOD_TRIANGULATE_NGON_BEAUTY only! */
@@ -60,12 +61,14 @@ static void bm_face_triangulate_mapping(
{
int faces_array_tot = face->len - 3;
BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
+ LinkNode *faces_double = NULL;
BLI_assert(face->len > 3);
BM_face_triangulate(
bm, face,
faces_array, &faces_array_tot,
NULL, NULL,
+ &faces_double,
quad_method, ngon_method, use_tag,
pf_arena,
pf_heap, pf_ehash);
@@ -76,13 +79,20 @@ static void bm_face_triangulate_mapping(
for (i = 0; i < faces_array_tot; i++) {
BMO_slot_map_elem_insert(op, slot_facemap_out, faces_array[i], face);
}
+
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BMO_slot_map_elem_insert(op, slot_facemap_double_out, faces_double->link, face);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
}
}
void BM_mesh_triangulate(
BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only,
- BMOperator *op, BMOpSlot *slot_facemap_out)
+ BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out)
{
BMIter iter;
BMFace *face;
@@ -107,10 +117,9 @@ void BM_mesh_triangulate(
if (face->len > 3) {
if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
bm_face_triangulate_mapping(
- bm, face, quad_method,
- ngon_method, tag_only,
- op, slot_facemap_out,
-
+ bm, face,
+ quad_method, ngon_method, tag_only,
+ op, slot_facemap_out, slot_facemap_double_out,
pf_arena,
pf_heap, pf_ehash);
}
@@ -118,6 +127,8 @@ void BM_mesh_triangulate(
}
}
else {
+ LinkNode *faces_double = NULL;
+
BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
if (face->len > 3) {
if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
@@ -125,12 +136,20 @@ void BM_mesh_triangulate(
bm, face,
NULL, NULL,
NULL, NULL,
+ &faces_double,
quad_method, ngon_method, tag_only,
pf_arena,
pf_heap, pf_ehash);
}
}
}
+
+ while (faces_double) {
+ LinkNode *next = faces_double->next;
+ BM_face_kill(bm, faces_double->link);
+ MEM_freeN(faces_double);
+ faces_double = next;
+ }
}
BLI_memarena_free(pf_arena);
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.h b/source/blender/bmesh/tools/bmesh_triangulate.h
index c6a5e04dfb2..644d7884202 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.h
+++ b/source/blender/bmesh/tools/bmesh_triangulate.h
@@ -32,6 +32,6 @@
void BM_mesh_triangulate(
BMesh *bm, const int quad_method, const int ngon_method, const bool tag_only,
- BMOperator *op, BMOpSlot *slot_facemap_out);
+ BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_doubles_out);
#endif /* __BMESH_TRIANGULATE_H__ */
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index 7bea0b70c95..3bff20e846b 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -142,8 +142,6 @@ void AnimationExporter::operator()(Object *ob)
}
}
}
-
-
}
void AnimationExporter::export_object_constraint_animation(Object *ob)
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 1bcf51f9d1f..5cd01eff263 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -626,8 +626,6 @@ void AnimationImporter:: Assign_color_animations(const COLLADAFW::UniqueId& list
fcurve_is_used(fcu);
}
}
-
-
}
void AnimationImporter:: Assign_float_animations(const COLLADAFW::UniqueId& listid, ListBase *AnimCurves, const char *anim_type)
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 6ddce75ec33..fd08e1ebfab 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -255,9 +255,13 @@ void ArmatureImporter::connect_bone_chains(bArmature *armature, Bone *parentbone
{
BoneExtended *dominant_child = NULL;
int maxlen = 0;
- Bone *child = (Bone *)parentbone->childbase.first;
- if (child && (import_settings->find_chains || child->next==NULL) )
- {
+ Bone *child;
+
+ if (parentbone == NULL)
+ return;
+
+ child = (Bone *)parentbone->childbase.first;
+ if (child && (import_settings->find_chains || child->next==NULL)) {
for (; child; child = child->next) {
BoneExtended *be = extended_bones[child->name];
if (be != NULL) {
diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp
index 7398126c97b..15e95a05425 100644
--- a/source/blender/collada/DocumentExporter.cpp
+++ b/source/blender/collada/DocumentExporter.cpp
@@ -98,6 +98,7 @@ extern "C"
#include "BKE_material.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_appdir.h"
#include "ED_keyframing.h"
#ifdef WITH_BUILDINFO
@@ -132,6 +133,7 @@ extern bool bc_has_object_type(LinkNode *export_set, short obtype);
#include "LightExporter.h"
#include "MaterialExporter.h"
+#include <errno.h>
char *bc_CustomData_get_layer_name(const struct CustomData *data, int type, int n)
{
@@ -153,28 +155,45 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type)
DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) {
}
+static COLLADABU::NativeString make_temp_filepath(const char *name, const char *extension)
+{
+ char tempfile[FILE_MAX];
+ const char *tempdir = BKE_tempdir_session();
+
+ if (name == NULL) {
+ name = "untitled";
+ }
+
+ BLI_make_file_string(NULL, tempfile, tempdir, name);
+
+ if (extension) {
+ BLI_ensure_extension(tempfile, FILE_MAX, extension);
+ }
+
+ COLLADABU::NativeString native_filename =
+ COLLADABU::NativeString(tempfile, COLLADABU::NativeString::ENCODING_UTF8);
+ return native_filename;
+}
+
// TODO: it would be better to instantiate animations rather than create a new one per object
// COLLADA allows this through multiple <channel>s in <animation>.
// For this to work, we need to know objects that use a certain action.
-void DocumentExporter::exportCurrentScene(Scene *sce)
+int DocumentExporter::exportCurrentScene(Scene *sce)
{
PointerRNA sceneptr, unit_settings;
PropertyRNA *system; /* unused , *scale; */
clear_global_id_map();
-
- COLLADABU::NativeString native_filename =
- COLLADABU::NativeString(std::string(this->export_settings->filepath), COLLADABU::NativeString::ENCODING_UTF8);
- COLLADASW::StreamWriter sw(native_filename);
- fprintf(stdout, "Collada export: %s\n", this->export_settings->filepath);
+ COLLADABU::NativeString native_filename = make_temp_filepath(NULL, ".dae");
+ COLLADASW::StreamWriter *writer = new COLLADASW::StreamWriter(native_filename);
// open <collada>
- sw.startDocument();
+ writer->startDocument();
// <asset>
- COLLADASW::Asset asset(&sw);
+ COLLADASW::Asset asset(writer);
RNA_id_pointer_create(&(sce->id), &sceneptr);
unit_settings = RNA_pointer_get(&sceneptr, "unit_settings");
@@ -241,41 +260,41 @@ void DocumentExporter::exportCurrentScene(Scene *sce)
LinkNode *export_set = this->export_settings->export_set;
// <library_cameras>
if (bc_has_object_type(export_set, OB_CAMERA)) {
- CamerasExporter ce(&sw, this->export_settings);
+ CamerasExporter ce(writer, this->export_settings);
ce.exportCameras(sce);
}
// <library_lights>
if (bc_has_object_type(export_set, OB_LAMP)) {
- LightsExporter le(&sw, this->export_settings);
+ LightsExporter le(writer, this->export_settings);
le.exportLights(sce);
}
// <library_images>
- ImagesExporter ie(&sw, this->export_settings);
+ ImagesExporter ie(writer, this->export_settings);
ie.exportImages(sce);
// <library_effects>
- EffectsExporter ee(&sw, this->export_settings);
+ EffectsExporter ee(writer, this->export_settings);
ee.exportEffects(sce);
// <library_materials>
- MaterialsExporter me(&sw, this->export_settings);
+ MaterialsExporter me(writer, this->export_settings);
me.exportMaterials(sce);
// <library_geometries>
if (bc_has_object_type(export_set, OB_MESH)) {
- GeometryExporter ge(&sw, this->export_settings);
+ GeometryExporter ge(writer, this->export_settings);
ge.exportGeom(sce);
}
// <library_animations>
- AnimationExporter ae(&sw, this->export_settings);
+ AnimationExporter ae(writer, this->export_settings);
bool has_animations = ae.exportAnimations(sce);
// <library_controllers>
- ArmatureExporter arm_exporter(&sw, this->export_settings);
- ControllerExporter controller_exporter(&sw , this->export_settings);
+ ArmatureExporter arm_exporter(writer, this->export_settings);
+ ControllerExporter controller_exporter(writer, this->export_settings);
if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys)
{
controller_exporter.export_controllers(sce);
@@ -283,7 +302,7 @@ void DocumentExporter::exportCurrentScene(Scene *sce)
// <library_visual_scenes>
- SceneExporter se(&sw, &arm_exporter, this->export_settings);
+ SceneExporter se(writer, &arm_exporter, this->export_settings);
if (has_animations && this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) {
// channels adressing <matrix> objects is not (yet) supported
@@ -301,13 +320,22 @@ void DocumentExporter::exportCurrentScene(Scene *sce)
// <scene>
std::string scene_name(translate_id(id_name(sce)));
- COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
+ COLLADASW::Scene scene(writer, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING,
scene_name));
scene.add();
// close <Collada>
- sw.endDocument();
-
+ writer->endDocument();
+ delete writer;
+
+ // Finally move the created document into place
+ fprintf(stdout, "Collada export to: %s\n", this->export_settings->filepath);
+ int status = BLI_rename(native_filename.c_str(), this->export_settings->filepath);
+ if (status != 0) {
+ status = BLI_copy(native_filename.c_str(), this->export_settings->filepath);
+ BLI_delete(native_filename.c_str(), false, false);
+ }
+ return status;
}
void DocumentExporter::exportScenes(const char *filename)
diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h
index 84c0610282e..6e3c1ecd7cd 100644
--- a/source/blender/collada/DocumentExporter.h
+++ b/source/blender/collada/DocumentExporter.h
@@ -39,7 +39,7 @@ class DocumentExporter
{
public:
DocumentExporter(const ExportSettings *export_settings);
- void exportCurrentScene(Scene *sce);
+ int exportCurrentScene(Scene *sce);
void exportScenes(const char *filename);
private:
const ExportSettings *export_settings;
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 674a79f0fe7..45dcf436473 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -388,7 +388,7 @@ Object *DocumentImporter::create_camera_object(COLLADAFW::InstanceCamera *camera
Camera *cam = uid_camera_map[cam_uid];
Camera *old_cam = (Camera *)ob->data;
ob->data = cam;
- old_cam->id.us--;
+ id_us_min(&old_cam->id);
if (old_cam->id.us == 0)
BKE_libblock_free(G.main, old_cam);
return ob;
@@ -406,7 +406,7 @@ Object *DocumentImporter::create_lamp_object(COLLADAFW::InstanceLight *lamp, Sce
Lamp *la = uid_lamp_map[lamp_uid];
Lamp *old_lamp = (Lamp *)ob->data;
ob->data = la;
- old_lamp->id.us--;
+ id_us_min(&old_lamp->id);
if (old_lamp->id.us == 0)
BKE_libblock_free(G.main, old_lamp);
return ob;
@@ -654,7 +654,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
for (std::vector<Object *>::iterator it = objects_done->begin(); it != objects_done->end(); ++it) {
ob = *it;
std::string nodename = node->getName().size() ? node->getName() : node->getOriginalId();
- rename_id(&ob->id, (char *)nodename.c_str());
+ BKE_libblock_rename(G.main, &ob->id, (char *)nodename.c_str());
object_map.insert(std::pair<COLLADAFW::UniqueId, Object *>(node->getUniqueId(), ob));
node_map[node->getUniqueId()] = node;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 2adbdd27cdf..64df42fc823 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -1176,7 +1176,7 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
const std::string& str_geom_id = mesh->getName().size() ? mesh->getName() : mesh->getOriginalId();
Mesh *me = BKE_mesh_add(G.main, (char *)str_geom_id.c_str());
- me->id.us--; // is already 1 here, but will be set later in BKE_mesh_assign_object
+ id_us_min(&me->id); // is already 1 here, but will be set later in BKE_mesh_assign_object
// store the Mesh pointer to link it later with an Object
// mesh_geom_map needed to map mesh to its geometry name (for shape key naming)
diff --git a/source/blender/collada/SConscript b/source/blender/collada/SConscript
deleted file mode 100644
index 7853769a0f8..00000000000
--- a/source/blender/collada/SConscript
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Arystanbek Dyussenov, Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-defs = []
-
-# TODO sanitize inc path building
-# relative paths to include dirs, space-separated, string
-incs = [
- '../ikplugin',
- '#/intern/iksolver/extern',
- '../blenlib',
- '../blenkernel',
- '../blentranslation',
- '../windowmanager',
- '../makesdna',
- '../makesrna',
- '../editors/include',
- '../imbuf',
- '../bmesh',
- '#/intern/guardedalloc',
-]
-incs += [
- env['BF_OPENCOLLADA_INC'] + '/COLLADAStreamWriter',
- env['BF_OPENCOLLADA_INC'] + '/COLLADABaseUtils',
- env['BF_OPENCOLLADA_INC'] + '/COLLADAFramework',
- env['BF_OPENCOLLADA_INC'] + '/COLLADASaxFrameworkLoader',
- env['BF_OPENCOLLADA_INC'] + '/GeneratedSaxParser',
-]
-
-if env['BF_BUILDINFO']:
- defs.append('WITH_BUILDINFO')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ('bf_collada', sources, incs, defs, libtype='core', priority=200 )
diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
index ac8ac2b9867..30cd6ddf197 100644
--- a/source/blender/collada/SceneExporter.cpp
+++ b/source/blender/collada/SceneExporter.cpp
@@ -61,7 +61,7 @@ void SceneExporter::exportHierarchy(Scene *sce)
// Ensure all objects in the export_set are marked
for (node = this->export_settings->export_set; node; node = node->next) {
Object *ob = (Object *) node->link;
- ob->id.flag |= LIB_DOIT;
+ ob->id.tag |= LIB_TAG_DOIT;
}
// Now find all exportable base ojects (highest in export hierarchy)
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index 4ca21869ec2..b1cbc01a9a6 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -133,11 +133,11 @@ int collada_export(Scene *sce,
}
DocumentExporter exporter(&export_settings);
- exporter.exportCurrentScene(sce);
+ int status = exporter.exportCurrentScene(sce);
BLI_linklist_free(export_settings.export_set, NULL);
- return export_count;
+ return (status) ? -1:export_count;
}
/* end extern C */
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index d669487db28..efdfaadd3e2 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -198,7 +198,7 @@ Object *bc_get_assigned_armature(Object *ob)
// returns NULL if no ancestor is selected
// IMPORTANT: This function expects that
// all exported objects have set:
-// ob->id.flag & LIB_DOIT
+// ob->id.tag & LIB_TAG_DOIT
Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob)
{
Object *ancestor = ob;
@@ -237,17 +237,17 @@ bool bc_has_object_type(LinkNode *export_set, short obtype)
int bc_is_marked(Object *ob)
{
- return ob && (ob->id.flag & LIB_DOIT);
+ return ob && (ob->id.tag & LIB_TAG_DOIT);
}
void bc_remove_mark(Object *ob)
{
- ob->id.flag &= ~LIB_DOIT;
+ ob->id.tag &= ~LIB_TAG_DOIT;
}
void bc_set_mark(Object *ob)
{
- ob->id.flag |= LIB_DOIT;
+ ob->id.tag |= LIB_TAG_DOIT;
}
// Use bubble sort algorithm for sorting the export set
@@ -358,7 +358,7 @@ void bc_triangulate_mesh(Mesh *me)
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
BM_mesh_bm_from_me(bm, me, true, false, 0);
- BM_mesh_triangulate(bm, quad_method, use_beauty, tag_only, NULL, NULL);
+ BM_mesh_triangulate(bm, quad_method, use_beauty, tag_only, NULL, NULL, NULL);
BM_mesh_bm_to_me(bm, me, false);
BM_mesh_free(bm);
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 972db6b71d2..35e5ec98e57 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
operations
../blenkernel
../blenlib
+ ../blentranslation
../imbuf
../makesdna
../makesrna
@@ -541,9 +542,9 @@ list(APPEND INC
${CMAKE_CURRENT_BINARY_DIR}/operations
)
-if(WITH_COMPOSITOR_WERROR)
- ADD_CHECK_C_COMPILER_FLAG(CMAKE_C_FLAGS C_WERROR -Werror)
- ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS C_WERROR -Werror)
+if(MSVC AND NOT CMAKE_CL_64)
+ set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2")
endif()
data_to_c(${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl
@@ -551,6 +552,10 @@ data_to_c(${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl
add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS)
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
add_definitions(-DWITH_CYCLES_DEBUG)
endif()
diff --git a/source/blender/compositor/SConscript b/source/blender/compositor/SConscript
deleted file mode 100644
index b3fe494a25c..00000000000
--- a/source/blender/compositor/SConscript
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Jeroen Bakker, Monique Dewanchand, Blender Developers Fund.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-defs = ['GLEW_STATIC', 'CL_USE_DEPRECATED_OPENCL_1_1_APIS']
-
-sources_intern = env.Glob('intern/*.cpp')
-sources_nodes = env.Glob('nodes/*.cpp')
-sources_operations = env.Glob('operations/*.cpp')
-
-incs = [
- '.',
- 'intern',
- 'nodes',
- 'operations',
- '#/extern/clew/include',
- '../blenkernel',
- '../blenlib',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../nodes',
- '../nodes/composite',
- '../nodes/intern',
- '../render/extern/include',
- '../render/intern/include',
- '../windowmanager',
- '../../../intern/guardedalloc',
- '../../../intern/atomic',
-
- # data files
- env['DATA_HEADERS'],
- ]
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
- incs.append(env['BF_PTHREADS_INC'])
-
-if env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-if False: # gives link errors 'win' in env['OURPLATFORM']:
- # split into 3 modules to work around command length limit on Windows
- env.BlenderLib('bf_composite_intern', sources_intern, incs, defines=defs, libtype=['core'], priority=[166])
- env.BlenderLib('bf_composite_nodes', sources_nodes, incs, defines=defs, libtype=['core'], priority=[165])
- env.BlenderLib('bf_composite_operations', sources_operations, incs, defines=defs, libtype=['core'], priority=[164])
-else:
- sources = sources_intern + sources_nodes + sources_operations
- env.BlenderLib('bf_composite', sources, incs, defines=defs, libtype=['core'], priority=[164])
-
-
diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cpp
index c7c3f7769fe..a5824ec5248 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.cpp
+++ b/source/blender/compositor/intern/COM_CPUDevice.cpp
@@ -22,6 +22,12 @@
#include "COM_CPUDevice.h"
+CPUDevice::CPUDevice(int thread_id)
+ : Device(),
+ m_thread_id(thread_id)
+{
+}
+
void CPUDevice::execute(WorkPackage *work)
{
const unsigned int chunkNumber = work->getChunkNumber();
diff --git a/source/blender/compositor/intern/COM_CPUDevice.h b/source/blender/compositor/intern/COM_CPUDevice.h
index 3dc8fff66a3..d12666593d4 100644
--- a/source/blender/compositor/intern/COM_CPUDevice.h
+++ b/source/blender/compositor/intern/COM_CPUDevice.h
@@ -31,11 +31,18 @@
*/
class CPUDevice : public Device {
public:
+ CPUDevice(int thread_id);
+
/**
* @brief execute a WorkPackage
* @param work the WorkPackage to execute
*/
void execute(WorkPackage *work);
+
+ int thread_id() { return m_thread_id; }
+
+protected:
+ int m_thread_id;
};
#endif
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index d7ec653f480..3cc6e9d4ac8 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -24,7 +24,6 @@
#define _COM_CompositorContext_h
#include <vector>
-#include "BKE_text.h"
#include <string>
#include "DNA_node_types.h"
#include "DNA_color_types.h"
diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
index 5cb757d7dcb..e5c2b8ace4e 100644
--- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp
@@ -40,7 +40,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BKE_global.h"
+#include "BLT_translation.h"
#include "PIL_time.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -403,7 +403,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo
this->m_bTree->progress(this->m_bTree->prh, progress);
char buf[128];
- BLI_snprintf(buf, sizeof(buf), "Compositing | Tile %u-%u",
+ BLI_snprintf(buf, sizeof(buf), IFACE_("Compositing | Tile %u-%u"),
this->m_chunksFinished,
this->m_numberOfChunks);
this->m_bTree->stats_draw(this->m_bTree->sdh, buf);
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
index caeaa07d9f9..5e847439830 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
@@ -28,6 +28,8 @@ extern "C" {
#include "BKE_node.h"
}
+#include "BLT_translation.h"
+
#include "COM_Converter.h"
#include "COM_NodeOperationBuilder.h"
#include "COM_NodeOperation.h"
@@ -36,8 +38,6 @@ extern "C" {
#include "COM_ReadBufferOperation.h"
#include "COM_Debug.h"
-#include "BKE_global.h"
-
#ifdef WITH_CXX_GUARDEDALLOC
#include "MEM_guardedalloc.h"
#endif
@@ -78,7 +78,7 @@ ExecutionSystem::ExecutionSystem(RenderData *rd, Scene *scene, bNodeTree *editin
viewer_border->xmin < viewer_border->xmax &&
viewer_border->ymin < viewer_border->ymax;
- editingtree->stats_draw(editingtree->sdh, "Compositing | Determining resolution");
+ editingtree->stats_draw(editingtree->sdh, IFACE_("Compositing | Determining resolution"));
for (index = 0; index < this->m_groups.size(); index++) {
resolution[0] = 0;
@@ -129,7 +129,7 @@ void ExecutionSystem::set_operations(const Operations &operations, const Groups
void ExecutionSystem::execute()
{
const bNodeTree *editingtree = this->m_context.getbNodeTree();
- editingtree->stats_draw(editingtree->sdh, (char *)"Compositing | Initializing execution");
+ editingtree->stats_draw(editingtree->sdh, IFACE_("Compositing | Initializing execution"));
DebugInfo::execute_started(this);
@@ -185,7 +185,7 @@ void ExecutionSystem::execute()
WorkScheduler::finish();
WorkScheduler::stop();
- editingtree->stats_draw(editingtree->sdh, (char *)"Compositing | Deinitializing execution");
+ editingtree->stats_draw(editingtree->sdh, IFACE_("Compositing | De-initializing execution"));
for (index = 0; index < this->m_operations.size(); index++) {
NodeOperation *operation = this->m_operations[index];
operation->deinitExecution();
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
index 7ee5e2f7c57..8900a5940e3 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
@@ -178,7 +178,8 @@ void MemoryBuffer::writePixel(int x, int y, const float color[4])
y >= this->m_rect.ymin && y < this->m_rect.ymax)
{
const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * this->m_num_channels;
- memcpy(&this->m_buffer[offset], color, sizeof(float)*this->m_num_channels); }
+ memcpy(&this->m_buffer[offset], color, sizeof(float) * this->m_num_channels);
+ }
}
void MemoryBuffer::addPixel(int x, int y, const float color[4])
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index de8c14e1a66..5ff3b51ce5a 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -259,7 +259,15 @@ public:
float u = x;
float v = y;
this->wrap_pixel(u, v, extend_x, extend_y);
- BLI_bilinear_interpolation_fl(this->m_buffer, result, this->m_width, this->m_height, this->m_num_channels, u, v);
+ if ((extend_x != COM_MB_REPEAT && (u < 0.0f || u >= this->m_width)) ||
+ (extend_y != COM_MB_REPEAT && (v < 0.0f || v >= this->m_height)))
+ {
+ copy_vn_fl(result, this->m_num_channels, 0.0f);
+ return;
+ }
+ BLI_bilinear_interpolation_wrap_fl(
+ this->m_buffer, result, this->m_width, this->m_height, this->m_num_channels, u, v,
+ extend_x == COM_MB_REPEAT, extend_y == COM_MB_REPEAT);
}
void readEWA(float *result, const float uv[2], const float derivatives[2][2]);
diff --git a/source/blender/compositor/intern/COM_Node.h b/source/blender/compositor/intern/COM_Node.h
index 6046af24c55..559ca46ae8b 100644
--- a/source/blender/compositor/intern/COM_Node.h
+++ b/source/blender/compositor/intern/COM_Node.h
@@ -24,7 +24,6 @@
#define __COM_NODE_H__
#include "DNA_node_types.h"
-#include "BKE_text.h"
#include <vector>
#include <string>
#include <algorithm>
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index fc6ea1299cf..e5b9f58ee93 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -50,7 +50,8 @@
/// @brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
-static vector<CPUDevice *> g_cpudevices;
+static vector<CPUDevice*> g_cpudevices;
+static ThreadLocal(CPUDevice *) g_thread_device;
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
/// @brief list of all thread for every CPUDevice in cpudevices a thread exists
@@ -153,9 +154,9 @@ int COM_isHighlightedbNode(bNode *bnode)
#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE
void *WorkScheduler::thread_execute_cpu(void *data)
{
- Device *device = (Device *)data;
+ CPUDevice *device = (CPUDevice *)data;
WorkPackage *work;
-
+ BLI_thread_local_set(g_thread_device, device);
while ((work = (WorkPackage *)BLI_thread_queue_pop(g_cpuqueue))) {
HIGHLIGHT(work);
device->execute(work);
@@ -310,18 +311,20 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
device->deinitialize();
delete device;
}
-
+ if (g_cpuInitialized) {
+ BLI_thread_local_delete(g_thread_device);
+ }
g_cpuInitialized = false;
}
/* initialize CPU threads */
if (!g_cpuInitialized) {
for (int index = 0; index < num_cpu_threads; index++) {
- CPUDevice *device = new CPUDevice();
+ CPUDevice *device = new CPUDevice(index);
device->initialize();
g_cpudevices.push_back(device);
}
-
+ BLI_thread_local_create(g_thread_device);
g_cpuInitialized = true;
}
@@ -407,7 +410,7 @@ void WorkScheduler::deinitialize()
device->deinitialize();
delete device;
}
-
+ BLI_thread_local_delete(g_thread_device);
g_cpuInitialized = false;
}
@@ -450,3 +453,8 @@ void WorkScheduler::deinitialize()
}
}
+int WorkScheduler::current_thread_id()
+{
+ CPUDevice *device = (CPUDevice *)BLI_thread_local_get(g_thread_device);
+ return device->thread_id();
+}
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h
index 71c5f859418..67d3fc87ce1 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.h
+++ b/source/blender/compositor/intern/COM_WorkScheduler.h
@@ -59,7 +59,7 @@ public:
* @brief schedule a chunk of a group to be calculated.
* An execution group schedules a chunk in the WorkScheduler
* when ExecutionGroup.isOpenCL is set the work will be handled by a OpenCLDevice
- * otherwide the work is scheduled for an CPUDevice
+ * otherwise the work is scheduled for an CPUDevice
* @see ExecutionGroup.execute
* @param group the execution group
* @param chunkNumber the number of the chunk in the group to be executed
@@ -113,6 +113,8 @@ public:
*/
static bool hasGPUDevices();
+ static int current_thread_id();
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkScheduler")
#endif
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index 7f7fc141aca..e3dfd69d8ec 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -25,9 +25,10 @@ extern "C" {
#include "BKE_node.h"
#include "BLI_threads.h"
}
-#include "BKE_main.h"
+
+#include "BLT_translation.h"
+
#include "BKE_scene.h"
-#include "BKE_global.h"
#include "COM_compositor.h"
#include "COM_ExecutionSystem.h"
@@ -38,11 +39,6 @@ extern "C" {
static ThreadMutex s_compositorMutex;
static bool is_compositorMutex_init = false;
-static void intern_freeCompositorCaches()
-{
- deintializeDistortionCache();
-}
-
void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering,
const ColorManagedViewSettings *viewSettings,
const ColorManagedDisplaySettings *displaySettings,
@@ -78,7 +74,7 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
/* set progress bar to 0% and status to init compositing */
editingtree->progress(editingtree->prh, 0.0);
- editingtree->stats_draw(editingtree->sdh, (char *)"Compositing");
+ editingtree->stats_draw(editingtree->sdh, IFACE_("Compositing"));
bool twopass = (editingtree->flag & NTREE_TWO_PASS) > 0 && !rendering;
/* initialize execution system */
@@ -103,20 +99,10 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
BLI_mutex_unlock(&s_compositorMutex);
}
-static void UNUSED_FUNCTION(COM_freeCaches)()
-{
- if (is_compositorMutex_init) {
- BLI_mutex_lock(&s_compositorMutex);
- intern_freeCompositorCaches();
- BLI_mutex_unlock(&s_compositorMutex);
- }
-}
-
void COM_deinitialize()
{
if (is_compositorMutex_init) {
BLI_mutex_lock(&s_compositorMutex);
- intern_freeCompositorCaches();
WorkScheduler::deinitialize();
is_compositorMutex_init = false;
BLI_mutex_unlock(&s_compositorMutex);
diff --git a/source/blender/compositor/nodes/COM_BlurNode.cpp b/source/blender/compositor/nodes/COM_BlurNode.cpp
index f3d0c33d3b3..6fbfc24a6b6 100644
--- a/source/blender/compositor/nodes/COM_BlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BlurNode.cpp
@@ -46,13 +46,15 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
bool connectedSizeSocket = inputSizeSocket->isLinked();
const float size = this->getInputSocket(1)->getEditorValueFloat();
-
+ const bool extend_bounds = (editorNode->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0;
+
CompositorQuality quality = context.getQuality();
NodeOperation *input_operation = NULL, *output_operation = NULL;
if (data->filtertype == R_FILTER_FAST_GAUSS) {
FastGaussianBlurOperation *operationfgb = new FastGaussianBlurOperation();
operationfgb->setData(data);
+ operationfgb->setExtendBounds(extend_bounds);
converter.addOperation(operationfgb);
converter.mapInputSocket(getInputSocket(1), operationfgb->getInputSocket(1));
@@ -77,6 +79,7 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
operationx->setSize(1.0f);
operationx->setFalloff(PROP_SMOOTH);
operationx->setSubtract(false);
+ operationx->setExtendBounds(extend_bounds);
converter.addOperation(operationx);
converter.addLink(clamp->getOutputSocket(), operationx->getInputSocket(0));
@@ -87,14 +90,16 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
operationy->setSize(1.0f);
operationy->setFalloff(PROP_SMOOTH);
operationy->setSubtract(false);
-
+ operationy->setExtendBounds(extend_bounds);
+
converter.addOperation(operationy);
converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0));
GaussianBlurReferenceOperation *operation = new GaussianBlurReferenceOperation();
operation->setData(data);
operation->setQuality(quality);
-
+ operation->setExtendBounds(extend_bounds);
+
converter.addOperation(operation);
converter.addLink(operationy->getOutputSocket(), operation->getInputSocket(1));
@@ -106,7 +111,8 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
operationx->setData(data);
operationx->setQuality(quality);
operationx->checkOpenCL();
-
+ operationx->setExtendBounds(extend_bounds);
+
converter.addOperation(operationx);
converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1));
@@ -114,6 +120,7 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
operationy->setData(data);
operationy->setQuality(quality);
operationy->checkOpenCL();
+ operationy->setExtendBounds(extend_bounds);
converter.addOperation(operationy);
converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1));
@@ -131,7 +138,8 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
GaussianBokehBlurOperation *operation = new GaussianBokehBlurOperation();
operation->setData(data);
operation->setQuality(quality);
-
+ operation->setExtendBounds(extend_bounds);
+
converter.addOperation(operation);
converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1));
diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp b/source/blender/compositor/nodes/COM_BokehBlurNode.cpp
index 7ab05e438ec..91c26eecb73 100644
--- a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cpp
@@ -41,6 +41,7 @@ void BokehBlurNode::convertToOperations(NodeConverter &converter, const Composit
NodeInput *inputSizeSocket = this->getInputSocket(2);
bool connectedSizeSocket = inputSizeSocket->isLinked();
+ const bool extend_bounds = (b_node->custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS) != 0;
if ((b_node->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) && connectedSizeSocket) {
VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation();
@@ -58,6 +59,7 @@ void BokehBlurNode::convertToOperations(NodeConverter &converter, const Composit
else {
BokehBlurOperation *operation = new BokehBlurOperation();
operation->setQuality(context.getQuality());
+ operation->setExtendBounds(extend_bounds);
converter.addOperation(operation);
converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
index d1babcc8103..f25c7b3fc2d 100644
--- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
+++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp
@@ -40,11 +40,13 @@ Stabilize2dNode::Stabilize2dNode(bNode *editorNode) : Node(editorNode)
void Stabilize2dNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
+ bNode *editorNode = this->getbNode();
NodeInput *imageInput = this->getInputSocket(0);
- MovieClip *clip = (MovieClip *)getbNode()->id;
+ MovieClip *clip = (MovieClip *)editorNode->id;
+ bool invert = (editorNode->custom2 & CMP_NODEFLAG_STABILIZE_INVERSE) != 0;
ScaleOperation *scaleOperation = new ScaleOperation();
- scaleOperation->setSampler((PixelSampler)this->getbNode()->custom1);
+ scaleOperation->setSampler((PixelSampler)editorNode->custom1);
RotateOperation *rotateOperation = new RotateOperation();
rotateOperation->setDoDegree2RadConversion(false);
TranslateOperation *translateOperation = new TranslateOperation();
@@ -53,24 +55,28 @@ void Stabilize2dNode::convertToOperations(NodeConverter &converter, const Compos
MovieClipAttributeOperation *xAttribute = new MovieClipAttributeOperation();
MovieClipAttributeOperation *yAttribute = new MovieClipAttributeOperation();
SetSamplerOperation *psoperation = new SetSamplerOperation();
- psoperation->setSampler((PixelSampler)this->getbNode()->custom1);
-
+ psoperation->setSampler((PixelSampler)editorNode->custom1);
+
scaleAttribute->setAttribute(MCA_SCALE);
scaleAttribute->setFramenumber(context.getFramenumber());
scaleAttribute->setMovieClip(clip);
-
+ scaleAttribute->setInvert(invert);
+
angleAttribute->setAttribute(MCA_ANGLE);
angleAttribute->setFramenumber(context.getFramenumber());
angleAttribute->setMovieClip(clip);
-
+ angleAttribute->setInvert(invert);
+
xAttribute->setAttribute(MCA_X);
xAttribute->setFramenumber(context.getFramenumber());
xAttribute->setMovieClip(clip);
-
+ xAttribute->setInvert(invert);
+
yAttribute->setAttribute(MCA_Y);
yAttribute->setFramenumber(context.getFramenumber());
yAttribute->setMovieClip(clip);
-
+ yAttribute->setInvert(invert);
+
converter.addOperation(scaleAttribute);
converter.addOperation(angleAttribute);
converter.addOperation(xAttribute);
diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp b/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
index 75c8c786ae8..490f72b4aa1 100644
--- a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
+++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cpp
@@ -22,6 +22,8 @@
*/
#include "COM_TrackPositionNode.h"
+
+#include "COM_ConvertOperation.h"
#include "COM_ExecutionSystem.h"
#include "COM_TrackPositionOperation.h"
@@ -36,6 +38,26 @@ TrackPositionNode::TrackPositionNode(bNode *editorNode) : Node(editorNode)
/* pass */
}
+static TrackPositionOperation *create_motion_operation(NodeConverter &converter,
+ MovieClip *clip,
+ NodeTrackPosData *trackpos_data,
+ int axis,
+ int frame_number,
+ int delta)
+{
+ TrackPositionOperation *operation = new TrackPositionOperation();
+ operation->setMovieClip(clip);
+ operation->setTrackingObject(trackpos_data->tracking_object);
+ operation->setTrackName(trackpos_data->track_name);
+ operation->setFramenumber(frame_number);
+ operation->setAxis(axis);
+ operation->setPosition(CMP_TRACKPOS_ABSOLUTE);
+ operation->setRelativeFrame(frame_number + delta);
+ operation->setSpeedOutput(true);
+ converter.addOperation(operation);
+ return operation;
+}
+
void TrackPositionNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
bNode *editorNode = this->getbNode();
@@ -44,6 +66,7 @@ void TrackPositionNode::convertToOperations(NodeConverter &converter, const Comp
NodeOutput *outputX = this->getOutputSocket(0);
NodeOutput *outputY = this->getOutputSocket(1);
+ NodeOutput *outputSpeed = this->getOutputSocket(2);
int frame_number;
if (editorNode->custom1 == CMP_TRACKPOS_ABSOLUTE_FRAME) {
@@ -62,7 +85,8 @@ void TrackPositionNode::convertToOperations(NodeConverter &converter, const Comp
operationX->setPosition(editorNode->custom1);
operationX->setRelativeFrame(editorNode->custom2);
converter.addOperation(operationX);
-
+ converter.mapOutputSocket(outputX, operationX->getOutputSocket());
+
TrackPositionOperation *operationY = new TrackPositionOperation();
operationY->setMovieClip(clip);
operationY->setTrackingObject(trackpos_data->tracking_object);
@@ -72,7 +96,26 @@ void TrackPositionNode::convertToOperations(NodeConverter &converter, const Comp
operationY->setPosition(editorNode->custom1);
operationY->setRelativeFrame(editorNode->custom2);
converter.addOperation(operationY);
-
- converter.mapOutputSocket(outputX, operationX->getOutputSocket());
converter.mapOutputSocket(outputY, operationY->getOutputSocket());
+
+ TrackPositionOperation *operationMotionPreX =
+ create_motion_operation(converter, clip, trackpos_data, 0, frame_number, -1);
+ TrackPositionOperation *operationMotionPreY =
+ create_motion_operation(converter, clip, trackpos_data, 1, frame_number, -1);
+ TrackPositionOperation *operationMotionPostX =
+ create_motion_operation(converter, clip, trackpos_data, 0, frame_number, 1);
+ TrackPositionOperation *operationMotionPostY =
+ create_motion_operation(converter, clip, trackpos_data, 1, frame_number, 1);
+
+ CombineChannelsOperation *combine_operation = new CombineChannelsOperation();
+ converter.addOperation(combine_operation);
+ converter.addLink(operationMotionPreX->getOutputSocket(),
+ combine_operation->getInputSocket(0));
+ converter.addLink(operationMotionPreY->getOutputSocket(),
+ combine_operation->getInputSocket(1));
+ converter.addLink(operationMotionPostX->getOutputSocket(),
+ combine_operation->getInputSocket(2));
+ converter.addLink(operationMotionPostY->getOutputSocket(),
+ combine_operation->getInputSocket(3));
+ converter.mapOutputSocket(outputSpeed, combine_operation->getOutputSocket());
}
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
index 2e60c2d3e42..97ac09d4abb 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
@@ -15,9 +15,9 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Jeroen Bakker
- * Monique Dewanchand
+ * Contributor(s): Jeroen Bakker
+ * Monique Dewanchand
+ * Sergey Sharybin
*/
#include "COM_AntiAliasOperation.h"
@@ -31,76 +31,122 @@ extern "C" {
}
+/* An implementation of the Scale3X edge-extrapolation algorithm.
+ *
+ * Code from GIMP plugin, based on code from Adam D. Moss (adam@gimp.org)
+ * licensed by the MIT license.
+ */
+static int extrapolate9(float *E0, float *E1, float *E2,
+ float *E3, float *E4, float *E5,
+ float *E6, float *E7, float *E8,
+ const float *A, const float *B, const float *C,
+ const float *D, const float *E, const float *F,
+ const float *G, const float *H, const float *I)
+{
+#define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f)
+#define PCPY(DST, SRC) do { *DST = *SRC; } while (0)
+ if ((!PEQ(B, H)) && (!PEQ(D, F))) {
+ if (PEQ(D, B)) PCPY(E0, D); else PCPY(E0, E);
+ if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A)))
+ PCPY(E1, B); else PCPY(E1, E);
+ if (PEQ(B, F)) PCPY(E2, F); else PCPY(E2, E);
+ if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A)))
+ PCPY(E3, D); else PCPY(E3, E);
+ PCPY(E4, E);
+ if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C)))
+ PCPY(E5, F); else PCPY(E5, E);
+ if (PEQ(D, H)) PCPY(E6, D); else PCPY(E6, E);
+ if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G)))
+ PCPY(E7, H); else PCPY(E7, E);
+ if (PEQ(H, F)) PCPY(E8, F); else PCPY(E8, E);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+#undef PEQ
+#undef PCPY
+}
+
AntiAliasOperation::AntiAliasOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_VALUE);
this->m_valueReader = NULL;
- this->m_buffer = NULL;
this->setComplex(true);
}
+
void AntiAliasOperation::initExecution()
{
this->m_valueReader = this->getInputSocketReader(0);
- NodeOperation::initMutex();
}
-void AntiAliasOperation::executePixel(float output[4], int x, int y, void * /*data*/)
+void AntiAliasOperation::executePixel(float output[4],
+ int x, int y,
+ void *data)
{
- if (y < 0 || (unsigned int)y >= this->m_height || x < 0 || (unsigned int)x >= this->m_width) {
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const int buffer_width = input_buffer->getWidth(),
+ buffer_height = input_buffer->getHeight();
+ if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) {
output[0] = 0.0f;
}
else {
- int offset = y * this->m_width + x;
- output[0] = this->m_buffer[offset] / 255.0f;
+ const float *buffer = input_buffer->getBuffer();
+ const float *row_curr = &buffer[y * buffer_width];
+ if (x == 0 || x == buffer_width - 1 ||
+ y == 0 || y == buffer_height - 1)
+ {
+ output[0] = row_curr[x];
+ return;
+ }
+ const float *row_prev = &buffer[(y - 1) * buffer_width],
+ *row_next = &buffer[(y + 1) * buffer_width];
+ float ninepix[9];
+ if (extrapolate9(&ninepix[0], &ninepix[1], &ninepix[2],
+ &ninepix[3], &ninepix[4], &ninepix[5],
+ &ninepix[6], &ninepix[7], &ninepix[8],
+ &row_prev[x - 1], &row_prev[x], &row_prev[x + 1],
+ &row_curr[x - 1], &row_curr[x], &row_curr[x + 1],
+ &row_next[x - 1], &row_next[x], &row_next[x + 1]))
+ {
+ /* Some rounding magic to so make weighting correct with the
+ * original coefficients.
+ */
+ unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] +
+ 5 * ninepix[3] + 6 * ninepix[4] + 5 * ninepix[5] +
+ 3 * ninepix[6] + 5 * ninepix[7] + 3 * ninepix[8]) * 255.0f +
+ 19.0f) / 38.0f;
+ output[0] = result / 255.0f;
+ }
+ else {
+ output[0] = row_curr[x];
+ }
}
-
}
void AntiAliasOperation::deinitExecution()
{
this->m_valueReader = NULL;
- if (this->m_buffer) {
- MEM_freeN(this->m_buffer);
- }
- NodeOperation::deinitMutex();
}
-bool AntiAliasOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
+bool AntiAliasOperation::determineDependingAreaOfInterest(
+ rcti *input,
+ ReadBufferOperation *readOperation,
+ rcti *output)
{
rcti imageInput;
- if (this->m_buffer) {
- return false;
- }
- else {
- NodeOperation *operation = getInputOperation(0);
- imageInput.xmax = operation->getWidth();
- imageInput.xmin = 0;
- imageInput.ymax = operation->getHeight();
- imageInput.ymin = 0;
- if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output) ) {
- return true;
- }
- }
- return false;
+ NodeOperation *operation = getInputOperation(0);
+ imageInput.xmax = input->xmax + 1;
+ imageInput.xmin = input->xmin - 1;
+ imageInput.ymax = input->ymax + 1;
+ imageInput.ymin = input->ymin - 1;
+ return operation->determineDependingAreaOfInterest(&imageInput,
+ readOperation,
+ output);
}
void *AntiAliasOperation::initializeTileData(rcti *rect)
{
- if (this->m_buffer) { return this->m_buffer; }
- lockMutex();
- if (this->m_buffer == NULL) {
- MemoryBuffer *tile = (MemoryBuffer *)this->m_valueReader->initializeTileData(rect);
- int size = tile->getHeight() * tile->getWidth();
- float *input = tile->getBuffer();
- char *valuebuffer = (char *)MEM_mallocN(sizeof(char) * size, __func__);
- for (int i = 0; i < size; i++) {
- float in = input[i];
- valuebuffer[i] = FTOCHAR(in);
- }
- antialias_tagbuf(tile->getWidth(), tile->getHeight(), valuebuffer);
- this->m_buffer = valuebuffer;
- }
- unlockMutex();
- return this->m_buffer;
+ return getInputOperation(0)->initializeTileData(rect);
}
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.h b/source/blender/compositor/operations/COM_AntiAliasOperation.h
index 385d59fec3c..996c7c2fe41 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.h
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.h
@@ -36,7 +36,6 @@ protected:
* @brief Cached reference to the reader
*/
SocketReader *m_valueReader;
- char *m_buffer;
public:
AntiAliasOperation();
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index ce42de7a149..2003d6e7b69 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -39,6 +39,7 @@ BlurBaseOperation::BlurBaseOperation(DataType data_type) : NodeOperation()
memset(&m_data, 0, sizeof(NodeBlurData));
this->m_size = 1.0f;
this->m_sizeavailable = false;
+ this->m_extend_bounds = false;
}
void BlurBaseOperation::initExecution()
{
@@ -118,7 +119,7 @@ float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff
for (i = -size; i <= size; i++) {
val = 1.0f - fabsf((float)i * fac);
- /* keep in sync with proportional_falloff_curve_only_items */
+ /* keep in sync with rna_enum_proportional_falloff_curve_only_items */
switch (falloff) {
case PROP_SMOOTH:
/* ease - gives less hard lines for dilate/erode feather */
@@ -174,3 +175,14 @@ void BlurBaseOperation::updateSize()
this->m_sizeavailable = true;
}
}
+
+void BlurBaseOperation::determineResolution(unsigned int resolution[2],
+ unsigned int preferredResolution[2])
+{
+ NodeOperation::determineResolution(resolution,
+ preferredResolution);
+ if (this->m_extend_bounds) {
+ resolution[0] += 2 * this->m_size * m_data.sizex;
+ resolution[1] += 2 * this->m_size * m_data.sizey;
+ }
+}
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index f9f37479c56..84cdcfeeba8 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -55,6 +55,8 @@ protected:
float m_size;
bool m_sizeavailable;
+ bool m_extend_bounds;
+
public:
/**
* Initialize the execution
@@ -69,5 +71,10 @@ public:
void setData(const NodeBlurData *data);
void setSize(float size) { this->m_size = size; this->m_sizeavailable = true; }
+
+ void setExtendBounds(bool extend_bounds) { this->m_extend_bounds = extend_bounds; }
+
+ void determineResolution(unsigned int resolution[2],
+ unsigned int preferredResolution[2]);
};
#endif
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
index 189483708b5..5ed36635f81 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
@@ -43,6 +43,8 @@ BokehBlurOperation::BokehBlurOperation() : NodeOperation()
this->m_inputProgram = NULL;
this->m_inputBokehProgram = NULL;
this->m_inputBoundingBoxReader = NULL;
+
+ this->m_extend_bounds = false;
}
void *BokehBlurOperation::initializeTileData(rcti * /*rect*/)
@@ -226,3 +228,15 @@ void BokehBlurOperation::updateSize()
this->m_sizeavailable = true;
}
}
+
+void BokehBlurOperation::determineResolution(unsigned int resolution[2],
+ unsigned int preferredResolution[2])
+{
+ NodeOperation::determineResolution(resolution,
+ preferredResolution);
+ if (this->m_extend_bounds) {
+ const float max_dim = max(resolution[0], resolution[1]);
+ resolution[0] += 2 * this->m_size * max_dim / 100.0f;
+ resolution[1] += 2 * this->m_size * max_dim / 100.0f;
+ }
+}
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h
index d2944825583..ed967d0fdb9 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.h
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h
@@ -37,6 +37,7 @@ private:
float m_bokehMidX;
float m_bokehMidY;
float m_bokehDimension;
+ bool m_extend_bounds;
public:
BokehBlurOperation();
@@ -64,5 +65,10 @@ public:
MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
list<cl_kernel> *clKernelsToCleanUp);
+
+ void setExtendBounds(bool extend_bounds) { this->m_extend_bounds = extend_bounds; }
+
+ void determineResolution(unsigned int resolution[2],
+ unsigned int preferredResolution[2]);
};
#endif
diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp
index 4e956905311..c4765b849bf 100644
--- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp
@@ -107,8 +107,6 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi
}
break;
}
-
-
}
void BoxMaskOperation::deinitExecution()
@@ -116,4 +114,3 @@ void BoxMaskOperation::deinitExecution()
this->m_inputMask = NULL;
this->m_inputValue = NULL;
}
-
diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp
index 14494841c49..3faffc1e3ff 100644
--- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp
@@ -110,7 +110,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4], float x, float
alpha = inColor[3]; /*whatever it was prior */
}
else if (alpha < limit_min) {
- alpha = 0.f;
+ alpha = 0.0f;
}
else { /*blend */
alpha = (alpha - limit_min) / limit_range;
diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp b/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp
index 9a20ca412e0..bc6389c5bbd 100644
--- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp
@@ -84,16 +84,16 @@ void ChromaMatteOperation::executePixelSampled(float output[4], float x, float y
/*if within the acceptance angle */
/* if kfg is <0 then the pixel is outside of the key color */
- kfg = x_angle - (fabsf(z_angle) / tanf(acceptance / 2.f));
+ kfg = x_angle - (fabsf(z_angle) / tanf(acceptance / 2.0f));
- if (kfg > 0.f) { /* found a pixel that is within key color */
+ if (kfg > 0.0f) { /* found a pixel that is within key color */
alpha = 1.0f - (kfg / gain);
beta = atan2(z_angle, x_angle);
/* if beta is within the cutoff angle */
- if (fabsf(beta) < (cutoff / 2.f)) {
- alpha = 0.f;
+ if (fabsf(beta) < (cutoff / 2.0f)) {
+ alpha = 0.0f;
}
/* don't make something that was more transparent less transparent */
diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp
index 2846642570c..3482f639ecb 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp
@@ -28,7 +28,7 @@ inline float colorbalance_cdl(float in, float offset, float power, float slope)
float x = in * slope + offset;
/* prevent NaN */
- CLAMP(x, 0.0f, 1.0f);
+ if (x < 0.0f) x = 0.0f;
return powf(x, power);
}
diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
index 9588687372e..627bbb73e3b 100644
--- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp
@@ -33,7 +33,7 @@ inline float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float g
float x = (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain;
/* prevent NaN */
- if (x < 0.f) x = 0.f;
+ if (x < 0.0f) x = 0.0f;
return powf(srgb_to_linearrgb(x), gamma_inv);
}
diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp b/source/blender/compositor/operations/COM_ColorMatteOperation.cpp
index b928141f41d..c95811e5e11 100644
--- a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cpp
@@ -72,7 +72,7 @@ void ColorMatteOperation::executePixelSampled(float output[4], float x, float y,
/* multiply by 2 because it wraps on both sides of the hue,
* otherwise 0.5 would key all hue's */
- /* hue */ ((h_wrap = 2.f * fabsf(inColor[0] - inKey[0])) < hue || (2.f - h_wrap) < hue)
+ /* hue */ ((h_wrap = 2.0f * fabsf(inColor[0] - inKey[0])) < hue || (2.0f - h_wrap) < hue)
)
{
output[0] = 0.0f; /* make transparent */
diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.h b/source/blender/compositor/operations/COM_ColorRampOperation.h
index 333e6c36d97..f143e1568d5 100644
--- a/source/blender/compositor/operations/COM_ColorRampOperation.h
+++ b/source/blender/compositor/operations/COM_ColorRampOperation.h
@@ -53,7 +53,5 @@ public:
void setColorBand(ColorBand *colorBand) {
this->m_colorBand = colorBand;
}
-
-
};
#endif
diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp
index fa9a957f83c..7fdd10affaf 100644
--- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp
@@ -79,8 +79,8 @@ void ConvertDepthToRadiusOperation::executePixelSampled(float output[4], float x
float radius;
this->m_inputOperation->readSampled(inputValue, x, y, sampler);
z = inputValue[0];
- if (z != 0.f) {
- float iZ = (1.f / z);
+ if (z != 0.0f) {
+ float iZ = (1.0f / z);
// bug #6656 part 2b, do not rescale
#if 0
@@ -88,7 +88,7 @@ void ConvertDepthToRadiusOperation::executePixelSampled(float output[4], float x
// scale crad back to original maximum and blend
crad->rect[px] = bcrad + wts->rect[px] * (scf * crad->rect[px] - bcrad);
#endif
- radius = 0.5f * fabsf(this->m_aperture * (this->m_dof_sp * (this->m_inverseFocalDistance - iZ) - 1.f));
+ radius = 0.5f * fabsf(this->m_aperture * (this->m_dof_sp * (this->m_inverseFocalDistance - iZ) - 1.0f));
// 'bug' #6615, limit minimum radius to 1 pixel, not really a solution, but somewhat mitigates the problem
if (radius < 0.0f) radius = 0.0f;
if (radius > this->m_maxRadius) {
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
index 699db11d56e..68ec2be5ebd 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp
@@ -33,7 +33,6 @@ ConvolutionFilterOperation::ConvolutionFilterOperation() : NodeOperation()
this->addOutputSocket(COM_DT_COLOR);
this->setResolutionInputSocketIndex(0);
this->m_inputOperation = NULL;
- this->m_filter = NULL;
this->setComplex(true);
}
void ConvolutionFilterOperation::initExecution()
@@ -44,7 +43,6 @@ void ConvolutionFilterOperation::initExecution()
void ConvolutionFilterOperation::set3x3Filter(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9)
{
- this->m_filter = (float *)MEM_mallocN(sizeof(float) * 9, __func__);
this->m_filter[0] = f1;
this->m_filter[1] = f2;
this->m_filter[2] = f3;
@@ -62,10 +60,6 @@ void ConvolutionFilterOperation::deinitExecution()
{
this->m_inputOperation = NULL;
this->m_inputValueOperation = NULL;
- if (this->m_filter) {
- MEM_freeN(this->m_filter);
- this->m_filter = NULL;
- }
}
diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h
index 4c192481ba1..faab6577be9 100644
--- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h
+++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.h
@@ -33,7 +33,7 @@ private:
protected:
SocketReader *m_inputOperation;
SocketReader *m_inputValueOperation;
- float *m_filter;
+ float m_filter[9];
public:
ConvolutionFilterOperation();
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
index 408395bfcf0..9bb5ac88343 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cpp
@@ -34,14 +34,25 @@ CurveBaseOperation::CurveBaseOperation() : NodeOperation()
{
this->m_curveMapping = NULL;
}
+
+CurveBaseOperation::~CurveBaseOperation()
+{
+ if (this->m_curveMapping) {
+ curvemapping_free(this->m_curveMapping);
+ this->m_curveMapping = NULL;
+ }
+}
+
void CurveBaseOperation::initExecution()
{
curvemapping_initialize(this->m_curveMapping);
}
void CurveBaseOperation::deinitExecution()
{
- curvemapping_free(this->m_curveMapping);
- this->m_curveMapping = NULL;
+ if (this->m_curveMapping) {
+ curvemapping_free(this->m_curveMapping);
+ this->m_curveMapping = NULL;
+ }
}
void CurveBaseOperation::setCurveMapping(CurveMapping *mapping)
diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.h b/source/blender/compositor/operations/COM_CurveBaseOperation.h
index 6bfce26f532..154eb18e387 100644
--- a/source/blender/compositor/operations/COM_CurveBaseOperation.h
+++ b/source/blender/compositor/operations/COM_CurveBaseOperation.h
@@ -33,6 +33,7 @@ protected:
CurveMapping *m_curveMapping;
public:
CurveBaseOperation();
+ ~CurveBaseOperation();
/**
* Initialize the execution
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
index 641499ddde4..d9809eb0296 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h
@@ -57,9 +57,9 @@ public:
void setData(NodeDBlurData *data) { this->m_data = data; }
void executeOpenCL(OpenCLDevice *device,
- MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
- MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
- list<cl_kernel> *clKernelsToCleanUp);
+ MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
+ MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
+ list<cl_kernel> *clKernelsToCleanUp);
};
#endif
diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp
index 48160d5db2c..40b4fdec28e 100644
--- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp
+++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp
@@ -79,8 +79,8 @@ void DisplaceSimpleOperation::executePixelSampled(float output[4], float x, floa
/* clamp nodes to avoid glitches */
u = x - p_dx + 0.5f;
v = y - p_dy + 0.5f;
- CLAMP(u, 0.f, this->getWidth() - 1.f);
- CLAMP(v, 0.f, this->getHeight() - 1.f);
+ CLAMP(u, 0.0f, this->getWidth() - 1.0f);
+ CLAMP(v, 0.0f, this->getHeight() - 1.0f);
this->m_inputColorProgram->readSampled(output, u, v, sampler);
}
diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp
index 072ca1022e7..b9e6864b340 100644
--- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp
@@ -71,7 +71,7 @@ void DistanceRGBMatteOperation::executePixelSampled(float output[4], float x, fl
/*make 100% transparent */
if (distance < tolerance) {
- output[0] = 0.f;
+ output[0] = 0.0f;
}
/*in the falloff region, make partially transparent */
else if (distance < falloff + tolerance) {
diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp
index bc1a6848a57..49c4662ed0c 100644
--- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp
@@ -111,8 +111,6 @@ void EllipseMaskOperation::executePixelSampled(float output[4], float x, float y
}
break;
}
-
-
}
void EllipseMaskOperation::deinitExecution()
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 968319b3f46..b83ebdd0913 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -91,7 +91,7 @@ void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
this->m_sx = this->m_data.sizex * this->m_size / 2.0f;
this->m_sy = this->m_data.sizey * this->m_size / 2.0f;
- if ((this->m_sx == this->m_sy) && (this->m_sx > 0.f)) {
+ if ((this->m_sx == this->m_sy) && (this->m_sx > 0.0f)) {
for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c)
IIR_gauss(copy, this->m_sx, c, 3);
}
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
index 37d59229e50..7c4132238e3 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
@@ -273,7 +273,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
float *gausstaby, *gausstabcentx;
int i, j;
float *src;
- register float sum, val;
+ float sum, val;
float rval, gval, bval, aval;
int imgx = getWidth();
int imgy = getHeight();
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
index 04993b08ddf..fe2864461dc 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
@@ -126,7 +126,6 @@ static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
unsigned int nzp, unsigned int inverse)
{
unsigned int i, j, Nx, Ny, maxy;
- fREAL t;
Nx = 1 << Mx;
Ny = 1 << My;
@@ -141,7 +140,7 @@ static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
for (j = 0; j < Ny; ++j)
for (i = j + 1; i < Nx; ++i) {
unsigned int op = i + (j << Mx), np = j + (i << My);
- t = data[op], data[op] = data[np], data[np] = t;
+ SWAP(fREAL, data[op], data[np]);
}
}
else { // rectangular
@@ -151,15 +150,15 @@ static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
for (j = PRED(i); j > i; j = PRED(j)) ;
if (j < i) continue;
for (k = i, j = PRED(i); j != i; k = j, j = PRED(j), stm--) {
- t = data[j], data[j] = data[k], data[k] = t;
+ SWAP(fREAL, data[j], data[k]);
}
#undef PRED
stm--;
}
}
- // swap Mx/My & Nx/Ny
- i = Nx, Nx = Ny, Ny = i;
- i = Mx, Mx = My, My = i;
+
+ SWAP(unsigned int, Nx, Ny);
+ SWAP(unsigned int, Mx, My);
// now columns == transposed rows
for (j = 0; j < Ny; ++j)
@@ -274,15 +273,15 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
data2 = (fREAL *)MEM_callocN(w2 * h2 * sizeof(fREAL), "convolve_fast FHT data2");
// normalize convolutor
- wt[0] = wt[1] = wt[2] = 0.f;
+ wt[0] = wt[1] = wt[2] = 0.0f;
for (y = 0; y < kernelHeight; y++) {
colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < kernelWidth; x++)
add_v3_v3(wt, colp[x]);
}
- if (wt[0] != 0.f) wt[0] = 1.f / wt[0];
- if (wt[1] != 0.f) wt[1] = 1.f / wt[1];
- if (wt[2] != 0.f) wt[2] = 1.f / wt[2];
+ if (wt[0] != 0.0f) wt[0] = 1.0f / wt[0];
+ if (wt[1] != 0.0f) wt[1] = 1.0f / wt[1];
+ if (wt[2] != 0.0f) wt[2] = 1.0f / wt[2];
for (y = 0; y < kernelHeight; y++) {
colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < kernelWidth; x++)
@@ -375,7 +374,7 @@ void GlareFogGlowOperation::generateGlare(float *data, MemoryBuffer *inputTile,
fRGB fcol;
MemoryBuffer *ckrn;
unsigned int sz = 1 << settings->size;
- const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f;
+ const float cs_r = 1.0f, cs_g = 1.0f, cs_b = 1.0f;
// temp. src image
// make the convolution kernel
@@ -386,14 +385,16 @@ void GlareFogGlowOperation::generateGlare(float *data, MemoryBuffer *inputTile,
scale = 0.25f * sqrtf((float)(sz * sz));
for (y = 0; y < sz; ++y) {
- v = 2.f * (y / (float)sz) - 1.0f;
+ v = 2.0f * (y / (float)sz) - 1.0f;
for (x = 0; x < sz; ++x) {
- u = 2.f * (x / (float)sz) - 1.0f;
+ u = 2.0f * (x / (float)sz) - 1.0f;
r = (u * u + v * v) * scale;
d = -sqrtf(sqrtf(sqrtf(r))) * 9.0f;
- fcol[0] = expf(d * cs_r), fcol[1] = expf(d * cs_g), fcol[2] = expf(d * cs_b);
+ fcol[0] = expf(d * cs_r);
+ fcol[1] = expf(d * cs_g);
+ fcol[2] = expf(d * cs_b);
// linear window good enough here, visual result counts, not scientific analysis
- //w = (1.f-fabs(u))*(1.f-fabs(v));
+ //w = (1.0f-fabs(u))*(1.0f-fabs(v));
// actually, Hanning window is ok, cos^2 for some reason is slower
w = (0.5f + 0.5f * cosf(u * (float)M_PI)) * (0.5f + 0.5f * cosf(v * (float)M_PI));
mul_v3_fl(fcol, w);
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
index eea6588a9a6..1c515f89d4f 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
@@ -40,11 +40,11 @@ static float smoothMask(float x, float y)
void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, NodeGlare *settings)
{
const int qt = 1 << settings->quality;
- const float s1 = 4.f / (float)qt, s2 = 2.f * s1;
+ const float s1 = 4.0f / (float)qt, s2 = 2.0f * s1;
int x, y, n, p, np;
fRGB c, tc, cm[64];
float sc, isc, u, v, sm, s, t, ofs, scalef[64];
- const float cmo = 1.f - settings->colmod;
+ const float cmo = 1.0f - settings->colmod;
MemoryBuffer *gbuf = inputTile->duplicate();
MemoryBuffer *tbuf1 = inputTile->duplicate();
@@ -69,10 +69,10 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
for (x = 0; x < (settings->iter * 4); x++) {
y = x & 3;
cm[x][0] = cm[x][1] = cm[x][2] = 1;
- if (y == 1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo);
- if (y == 2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f);
- if (y == 3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo);
- scalef[x] = 2.1f * (1.f - (x + ofs) / (float)(settings->iter * 4));
+ if (y == 1) fRGB_rgbmult(cm[x], 1.0f, cmo, cmo);
+ if (y == 2) fRGB_rgbmult(cm[x], cmo, cmo, 1.0f);
+ if (y == 3) fRGB_rgbmult(cm[x], cmo, 1.0f, cmo);
+ scalef[x] = 2.1f * (1.0f - (x + ofs) / (float)(settings->iter * 4));
if (x & 1) scalef[x] = -0.99f / scalef[x];
}
@@ -82,11 +82,13 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
v = ((float)y + 0.5f) / (float)gbuf->getHeight();
for (x = 0; x < gbuf->getWidth(); x++) {
u = ((float)x + 0.5f) / (float)gbuf->getWidth();
- s = (u - 0.5f) * sc + 0.5f, t = (v - 0.5f) * sc + 0.5f;
+ s = (u - 0.5f) * sc + 0.5f;
+ t = (v - 0.5f) * sc + 0.5f;
tbuf1->readBilinear(c, s * gbuf->getWidth(), t * gbuf->getHeight());
sm = smoothMask(s, t);
mul_v3_fl(c, sm);
- s = (u - 0.5f) * isc + 0.5f, t = (v - 0.5f) * isc + 0.5f;
+ s = (u - 0.5f) * isc + 0.5f;
+ t = (v - 0.5f) * isc + 0.5f;
tbuf2->readBilinear(tc, s * gbuf->getWidth() - 0.5f, t * gbuf->getHeight() - 0.5f);
sm = smoothMask(s, t);
madd_v3_v3fl(c, tc, sm);
@@ -103,7 +105,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
v = ((float)y + 0.5f) / (float)gbuf->getHeight();
for (x = 0; x < gbuf->getWidth(); x++) {
u = ((float)x + 0.5f) / (float)gbuf->getWidth();
- tc[0] = tc[1] = tc[2] = 0.f;
+ tc[0] = tc[1] = tc[2] = 0.0f;
for (p = 0; p < 4; p++) {
np = (n << 2) + p;
s = (u - 0.5f) * scalef[np] + 0.5f;
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index deeb5094bd0..da6076337b4 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -40,14 +40,14 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile,
tdst->clear();
memset(data, 0, size4 * sizeof(float));
- for (a = 0.f; a < DEG2RADF(360.0f) && (!breaked); a += ang) {
+ for (a = 0.0f; a < DEG2RADF(360.0f) && (!breaked); a += ang) {
const float an = a + settings->angle_ofs;
const float vx = cos((double)an), vy = sin((double)an);
for (n = 0; n < settings->iter && (!breaked); ++n) {
const float p4 = pow(4.0, (double)n);
const float vxp = vx * p4, vyp = vy * p4;
const float wt = pow((double)settings->fade, (double)p4);
- const float cmo = 1.f - (float)pow((double)settings->colmod, (double)n + 1); // colormodulation amount relative to current pass
+ const float cmo = 1.0f - (float)pow((double)settings->colmod, (double)n + 1); // colormodulation amount relative to current pass
float *tdstcol = tdst->getBuffer();
for (y = 0; y < tsrc->getHeight() && (!breaked); ++y) {
for (x = 0; x < tsrc->getWidth(); ++x, tdstcol += 4) {
@@ -55,8 +55,8 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile,
// otherwise results in uneven brightness, only need once
if (n == 0) tsrc->read(c1, x, y); else c1[0] = c1[1] = c1[2] = 0;
tsrc->readBilinear(c2, x + vxp, y + vyp);
- tsrc->readBilinear(c3, x + vxp * 2.f, y + vyp * 2.f);
- tsrc->readBilinear(c4, x + vxp * 3.f, y + vyp * 3.f);
+ tsrc->readBilinear(c3, x + vxp * 2.0f, y + vyp * 2.0f);
+ tsrc->readBilinear(c4, x + vxp * 3.0f, y + vyp * 3.0f);
// modulate color to look vaguely similar to a color spectrum
c2[1] *= cmo;
c2[2] *= cmo;
@@ -80,7 +80,7 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile,
}
float *sourcebuffer = tsrc->getBuffer();
- float factor = 1.f / (float)(6 - settings->iter);
+ float factor = 1.0f / (float)(6 - settings->iter);
for (int i = 0; i < size4; i += 4) {
madd_v3_v3fl(&data[i], &sourcebuffer[i], factor);
data[i + 3] = 1.0f;
diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
index d2bd7cbeeab..f54e75a6b35 100644
--- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp
@@ -52,7 +52,10 @@ void GlareThresholdOperation::executePixelSampled(float output[4], float x, floa
this->m_inputProgram->readSampled(output, x, y, sampler);
if (IMB_colormanagement_get_luminance(output) >= threshold) {
- output[0] -= threshold, output[1] -= threshold, output[2] -= threshold;
+ output[0] -= threshold;
+ output[1] -= threshold;
+ output[2] -= threshold;
+
output[0] = max(output[0], 0.0f);
output[1] = max(output[1], 0.0f);
output[2] = max(output[2], 0.0f);
diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
index 2cdf0170fbd..573049cf07f 100644
--- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
+++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp
@@ -57,11 +57,11 @@ void HueSaturationValueCorrectOperation::executePixelSampled(float output[4], fl
/* adjust saturation, scaling returned default 0.5 up to 1 */
f = curvemapping_evaluateF(this->m_curveMapping, 1, hsv[0]);
- hsv[1] *= (f * 2.f);
+ hsv[1] *= (f * 2.0f);
/* adjust value, scaling returned default 0.5 up to 1 */
f = curvemapping_evaluateF(this->m_curveMapping, 2, hsv[0]);
- hsv[2] *= (f * 2.f);
+ hsv[2] *= (f * 2.0f);
hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
CLAMP(hsv[1], 0.0f, 1.0f);
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cpp b/source/blender/compositor/operations/COM_IDMaskOperation.cpp
index a021f07d2a7..05462d31ed2 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.cpp
@@ -26,24 +26,23 @@ IDMaskOperation::IDMaskOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_VALUE);
this->addOutputSocket(COM_DT_VALUE);
- this->m_inputProgram = NULL;
-}
-void IDMaskOperation::initExecution()
-{
- this->m_inputProgram = this->getInputSocketReader(0);
+ this->setComplex(true);
}
-void IDMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
+void *IDMaskOperation::initializeTileData(rcti *rect)
{
- float inputValue[4];
-
- this->m_inputProgram->readSampled(inputValue, x, y, sampler);
- const float a = (inputValue[0] == this->m_objectIndex) ? 1.0f : 0.0f;
- output[0] = a;
+ void *buffer = getInputOperation(0)->initializeTileData(rect);
+ return buffer;
}
-void IDMaskOperation::deinitExecution()
+void IDMaskOperation::executePixel(float output[4],
+ int x,
+ int y,
+ void *data)
{
- this->m_inputProgram = NULL;
+ MemoryBuffer *input_buffer = (MemoryBuffer *)data;
+ const int buffer_width = input_buffer->getWidth();
+ float *buffer = input_buffer->getBuffer();
+ int buffer_index = (y * buffer_width + x);
+ output[0] = (roundf(buffer[buffer_index]) == this->m_objectIndex) ? 1.0f : 0.0f;
}
-
diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.h b/source/blender/compositor/operations/COM_IDMaskOperation.h
index dfddc489ca4..841d4a76124 100644
--- a/source/blender/compositor/operations/COM_IDMaskOperation.h
+++ b/source/blender/compositor/operations/COM_IDMaskOperation.h
@@ -27,30 +27,13 @@
class IDMaskOperation : public NodeOperation {
private:
- /**
- * Cached reference to the inputProgram
- */
- SocketReader *m_inputProgram;
-
float m_objectIndex;
public:
IDMaskOperation();
-
- /**
- * the inner loop of this program
- */
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
-
- /**
- * Initialize the execution
- */
- void initExecution();
-
- /**
- * Deinitialize the execution
- */
- void deinitExecution();
-
+
+ void *initializeTileData(rcti *rect);
+ void executePixel(float output[4], int x, int y, void *data);
+
void setObjectIndex(float objectIndex) { this->m_objectIndex = objectIndex; }
};
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index c55366ab370..624378f2ae9 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -159,7 +159,11 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
void ImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
+ int ix = x, iy = y;
+ if (ix < 0 || iy < 0 || ix >= this->m_buffer->x || iy >= this->m_buffer->y) {
+ zero_v4(output);
+ }
+ else if (this->m_imageFloatBuffer == NULL && this->m_imageByteBuffer == NULL) {
zero_v4(output);
}
else {
diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
index 50ac3b5e055..3be5447db3b 100644
--- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
+++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp
@@ -57,10 +57,10 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], float x, floa
/* test range */
if (inColor[0] > high) {
- alpha = 1.f;
+ alpha = 1.0f;
}
else if (inColor[0] < low) {
- alpha = 0.f;
+ alpha = 0.0f;
}
else { /*blend */
alpha = (inColor[0] - low) / (high - low);
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index d091675286d..0112f4bbf21 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -63,7 +63,7 @@ void MapUVOperation::executePixelSampled(float output[4], float x, float y, Pixe
float du = len_v2(deriv[0]);
float dv = len_v2(deriv[1]);
float factor = 1.0f - threshold * (du / m_inputColorProgram->getWidth() + dv / m_inputColorProgram->getHeight());
- if (factor < 0.f) alpha = 0.f;
+ if (factor < 0.0f) alpha = 0.0f;
else alpha *= factor;
/* "premul" */
diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cpp
index d379839a457..e202006e954 100644
--- a/source/blender/compositor/operations/COM_MixOperation.cpp
+++ b/source/blender/compositor/operations/COM_MixOperation.cpp
@@ -462,7 +462,7 @@ void MixGlareOperation::executePixelSampled(float output[4], float x, float y, P
this->m_inputColor1Operation->readSampled(inputColor1, x, y, sampler);
this->m_inputColor2Operation->readSampled(inputColor2, x, y, sampler);
value = inputValue[0];
- float mf = 2.f - 2.f * fabsf(value - 0.5f);
+ float mf = 2.0f - 2.0f * fabsf(value - 0.5f);
if (inputColor1[0] < 0.0f) inputColor1[0] = 0.0f;
if (inputColor1[1] < 0.0f) inputColor1[1] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
index 040a0315d69..5ddf15f7684 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp
@@ -31,12 +31,14 @@ MovieClipAttributeOperation::MovieClipAttributeOperation() : NodeOperation()
this->m_valueSet = false;
this->m_framenumber = 0;
this->m_attribute = MCA_X;
+ this->m_invert = false;
}
void MovieClipAttributeOperation::executePixelSampled(float output[4],
float /*x*/, float /*y*/,
PixelSampler /*sampler*/)
{
+ /* TODO(sergey): This code isn't really thread-safe. */
if (!this->m_valueSet) {
float loc[2], scale, angle;
loc[0] = 0.0f;
@@ -61,6 +63,14 @@ void MovieClipAttributeOperation::executePixelSampled(float output[4],
this->m_value = loc[1];
break;
}
+ if (this->m_invert) {
+ if (this->m_attribute != MCA_SCALE) {
+ this->m_value = -this->m_value;
+ }
+ else {
+ this->m_value = 1.0f / this->m_value;
+ }
+ }
this->m_valueSet = true;
}
output[0] = this->m_value;
diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
index 49c86c7fafc..731b9debaf0 100644
--- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
+++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.h
@@ -41,6 +41,7 @@ private:
float m_value;
bool m_valueSet;
int m_framenumber;
+ bool m_invert;
MovieClipAttribute m_attribute;
public:
/**
@@ -57,5 +58,6 @@ public:
void setMovieClip(MovieClip *clip) { this->m_clip = clip; }
void setFramenumber(int framenumber) { this->m_framenumber = framenumber; }
void setAttribute(MovieClipAttribute attribute) { this->m_attribute = attribute; }
+ void setInvert(bool invert) { this->m_invert = invert; }
};
#endif
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
index 4f34d7fb150..3b8f09fffb2 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
@@ -15,9 +15,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Jeroen Bakker
+ * Contributor:
+ * Jeroen Bakker
* Monique Dewanchand
+ * Sergey Sharybin
*/
#include "COM_MovieDistortionOperation.h"
@@ -29,17 +30,6 @@ extern "C" {
}
-static vector<DistortionCache *> s_cache;
-
-void deintializeDistortionCache(void)
-{
- while (s_cache.size() > 0) {
- DistortionCache * cache = s_cache.back();
- s_cache.pop_back();
- delete cache;
- }
-}
-
MovieDistortionOperation::MovieDistortionOperation(bool distortion) : NodeOperation()
{
this->addInputSocket(COM_DT_COLOR);
@@ -47,40 +37,32 @@ MovieDistortionOperation::MovieDistortionOperation(bool distortion) : NodeOperat
this->setResolutionInputSocketIndex(0);
this->m_inputOperation = NULL;
this->m_movieClip = NULL;
- this->m_cache = NULL;
- this->m_distortion = distortion;
+ this->m_apply = distortion;
}
void MovieDistortionOperation::initExecution()
{
this->m_inputOperation = this->getInputSocketReader(0);
if (this->m_movieClip) {
+ MovieTracking *tracking = &this->m_movieClip->tracking;
MovieClipUser clipUser = {0};
int calibration_width, calibration_height;
BKE_movieclip_user_set_frame(&clipUser, this->m_framenumber);
- BKE_movieclip_get_size(this->m_movieClip, &clipUser, &calibration_width, &calibration_height);
-
- for (unsigned int i = 0; i < s_cache.size(); i++) {
- DistortionCache *c = (DistortionCache *)s_cache[i];
- if (c->isCacheFor(this->m_movieClip, this->m_width, this->m_height,
- calibration_width, calibration_height, this->m_distortion))
- {
- this->m_cache = c;
- this->m_cache->updateLastUsage();
- this->m_cache->getMargin(this->m_margin);
- return;
- }
- }
+ BKE_movieclip_get_size(this->m_movieClip,
+ &clipUser,
+ &calibration_width,
+ &calibration_height);
float delta[2];
rcti full_frame;
full_frame.xmin = full_frame.ymin = 0;
full_frame.xmax = this->m_width;
full_frame.ymax = this->m_height;
- BKE_tracking_max_distortion_delta_across_bound(
- &this->m_movieClip->tracking, &full_frame,
- !this->m_distortion, delta);
+ BKE_tracking_max_distortion_delta_across_bound(tracking,
+ &full_frame,
+ !this->m_apply,
+ delta);
/* 5 is just in case we didn't hit real max of distortion in
* BKE_tracking_max_undistortion_delta_across_bound
@@ -88,17 +70,16 @@ void MovieDistortionOperation::initExecution()
m_margin[0] = delta[0] + 5;
m_margin[1] = delta[1] + 5;
- DistortionCache *newC = new DistortionCache(this->m_movieClip,
- this->m_width, this->m_height,
- calibration_width, calibration_height,
- this->m_distortion,
- this->m_margin);
- s_cache.push_back(newC);
- this->m_cache = newC;
+ this->m_distortion = BKE_tracking_distortion_new(tracking,
+ calibration_width,
+ calibration_height);
+ this->m_calibration_width = calibration_width;
+ this->m_calibration_height = calibration_height;
+ this->m_pixel_aspect = tracking->camera.pixel_aspect;
}
else {
- this->m_cache = NULL;
m_margin[0] = m_margin[1] = 0;
+ this->m_distortion = NULL;
}
}
@@ -106,27 +87,39 @@ void MovieDistortionOperation::deinitExecution()
{
this->m_inputOperation = NULL;
this->m_movieClip = NULL;
- while (s_cache.size() > COM_DISTORTIONCACHE_MAXSIZE) {
- double minTime = PIL_check_seconds_timer();
- vector<DistortionCache*>::iterator minTimeIterator = s_cache.begin();
- for (vector<DistortionCache*>::iterator it = s_cache.begin(); it < s_cache.end(); it ++) {
- DistortionCache * cache = *it;
- if (cache->getTimeLastUsage() < minTime) {
- minTime = cache->getTimeLastUsage();
- minTimeIterator = it;
- }
- }
- s_cache.erase(minTimeIterator);
+ if (this->m_distortion != NULL) {
+ BKE_tracking_distortion_free(this->m_distortion);
}
}
-
-void MovieDistortionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
+void MovieDistortionOperation::executePixelSampled(float output[4],
+ float x,
+ float y,
+ PixelSampler /*sampler*/)
{
-
- if (this->m_cache != NULL) {
- float u, v;
- this->m_cache->getUV(&this->m_movieClip->tracking, x, y, &u, &v);
+ if (this->m_distortion != NULL) {
+ /* float overscan = 0.0f; */
+ const float pixel_aspect = this->m_pixel_aspect;
+ const float w = (float)this->m_width /* / (1 + overscan) */;
+ const float h = (float)this->m_height /* / (1 + overscan) */;
+ const float aspx = w / (float)this->m_calibration_width;
+ const float aspy = h / (float)this->m_calibration_height;
+ float in[2];
+ float out[2];
+
+ in[0] = (x /* - 0.5 * overscan * w */) / aspx;
+ in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect;
+
+ if (this->m_apply) {
+ BKE_tracking_distortion_undistort_v2(this->m_distortion, in, out);
+ }
+ else {
+ BKE_tracking_distortion_distort_v2(this->m_distortion, in, out);
+ }
+
+ float u = out[0] * aspx /* + 0.5 * overscan * w */,
+ v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect;
+
this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR);
}
else {
@@ -134,12 +127,17 @@ void MovieDistortionOperation::executePixelSampled(float output[4], float x, flo
}
}
-bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+bool MovieDistortionOperation::determineDependingAreaOfInterest(
+ rcti *input,
+ ReadBufferOperation *readOperation,
+ rcti *output)
{
rcti newInput;
newInput.xmin = input->xmin - m_margin[0];
newInput.ymin = input->ymin - m_margin[1];
newInput.xmax = input->xmax + m_margin[0];
newInput.ymax = input->ymax + m_margin[1];
- return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+ return NodeOperation::determineDependingAreaOfInterest(&newInput,
+ readOperation,
+ output);
}
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
index 85f075ab65a..689fcfe11ad 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
@@ -15,9 +15,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Jeroen Bakker
+ * Contributor:
+ * Jeroen Bakker
* Monique Dewanchand
+ * Sergey Sharybin
*/
#ifndef _COM_MovieDistortionOperation_h_
@@ -29,166 +30,37 @@
extern "C" {
# include "BKE_tracking.h"
-# include "PIL_time.h"
}
-#define COM_DISTORTIONCACHE_MAXSIZE 10
-
-class DistortionCache {
-private:
- short m_distortion_model;
- float m_k1, m_k2, m_k3;
- float m_division_k1, m_division_k2;
- float m_principal_x;
- float m_principal_y;
- float m_pixel_aspect;
- int m_width;
- int m_height;
- int m_calibration_width;
- int m_calibration_height;
- bool m_inverted;
- float *m_buffer;
- int *m_bufferCalculated;
- double timeLastUsage;
- int m_margin[2];
-
-public:
- DistortionCache(MovieClip *movieclip,
- int width, int height,
- int calibration_width, int calibration_height,
- bool inverted,
- const int margin[2])
- {
- this->m_distortion_model = movieclip->tracking.camera.distortion_model;
- this->m_k1 = movieclip->tracking.camera.k1;
- this->m_k2 = movieclip->tracking.camera.k2;
- this->m_k3 = movieclip->tracking.camera.k3;
- this->m_division_k1 = movieclip->tracking.camera.division_k1;
- this->m_division_k2 = movieclip->tracking.camera.division_k2;
- this->m_principal_x = movieclip->tracking.camera.principal[0];
- this->m_principal_y = movieclip->tracking.camera.principal[1];
- this->m_pixel_aspect = movieclip->tracking.camera.pixel_aspect;
- this->m_width = width;
- this->m_height = height;
- this->m_calibration_width = calibration_width;
- this->m_calibration_height = calibration_height;
- this->m_inverted = inverted;
- this->m_bufferCalculated = (int *)MEM_callocN(sizeof(int) * this->m_width * this->m_height, __func__);
- this->m_buffer = (float *)MEM_mallocN(sizeof(float) * this->m_width * this->m_height * 2, __func__);
- copy_v2_v2_int(this->m_margin, margin);
- this->updateLastUsage();
- }
-
- ~DistortionCache() {
- if (this->m_buffer) {
- MEM_freeN(this->m_buffer);
- this->m_buffer = NULL;
- }
-
- if (this->m_bufferCalculated) {
- MEM_freeN(this->m_bufferCalculated);
- this->m_bufferCalculated = NULL;
- }
- }
-
- void updateLastUsage() {
- this->timeLastUsage = PIL_check_seconds_timer();
- }
-
- inline double getTimeLastUsage() {
- return this->timeLastUsage;
- }
-
- bool isCacheFor(MovieClip *movieclip,
- int width, int height,
- int calibration_width, int claibration_height,
- bool inverted)
- {
- return this->m_distortion_model == movieclip->tracking.camera.distortion_model &&
- this->m_k1 == movieclip->tracking.camera.k1 &&
- this->m_k2 == movieclip->tracking.camera.k2 &&
- this->m_k3 == movieclip->tracking.camera.k3 &&
- this->m_division_k1 == movieclip->tracking.camera.division_k1 &&
- this->m_division_k2 == movieclip->tracking.camera.division_k2 &&
- this->m_principal_x == movieclip->tracking.camera.principal[0] &&
- this->m_principal_y == movieclip->tracking.camera.principal[1] &&
- this->m_pixel_aspect == movieclip->tracking.camera.pixel_aspect &&
- this->m_inverted == inverted &&
- this->m_width == width &&
- this->m_height == height &&
- this->m_calibration_width == calibration_width &&
- this->m_calibration_height == claibration_height;
- }
-
- void getUV(MovieTracking *trackingData, int x, int y, float *u, float *v)
- {
- if (x < 0 || x >= this->m_width || y < 0 || y >= this->m_height) {
- *u = x;
- *v = y;
- }
- else {
- int offset = y * this->m_width + x;
- int offset2 = offset * 2;
-
- if (!this->m_bufferCalculated[offset]) {
- //float overscan = 0.0f;
- const float w = (float)this->m_width /* / (1 + overscan) */;
- const float h = (float)this->m_height /* / (1 + overscan) */;
- const float aspx = w / (float)this->m_calibration_width;
- const float aspy = h / (float)this->m_calibration_height;
- float in[2];
- float out[2];
-
- in[0] = (x /* - 0.5 * overscan * w */) / aspx;
- in[1] = (y /* - 0.5 * overscan * h */) / aspy / this->m_pixel_aspect;
-
- if (this->m_inverted) {
- BKE_tracking_undistort_v2(trackingData, in, out);
- }
- else {
- BKE_tracking_distort_v2(trackingData, in, out);
- }
-
- this->m_buffer[offset2] = out[0] * aspx /* + 0.5 * overscan * w */;
- this->m_buffer[offset2 + 1] = (out[1] * aspy /* + 0.5 * overscan * h */) * this->m_pixel_aspect;
-
- this->m_bufferCalculated[offset] = 1;
- }
- *u = this->m_buffer[offset2];
- *v = this->m_buffer[offset2 + 1];
- }
- }
-
- void getMargin(int margin[2])
- {
- copy_v2_v2_int(margin, m_margin);
- }
-};
-
class MovieDistortionOperation : public NodeOperation {
private:
- DistortionCache *m_cache;
SocketReader *m_inputOperation;
MovieClip *m_movieClip;
int m_margin[2];
protected:
- bool m_distortion;
+ bool m_apply;
int m_framenumber;
+ struct MovieDistortion *m_distortion;
+ int m_calibration_width, m_calibration_height;
+ float m_pixel_aspect;
+
public:
MovieDistortionOperation(bool distortion);
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ void executePixelSampled(float output[4],
+ float x, float y,
+ PixelSampler sampler);
void initExecution();
void deinitExecution();
-
+
void setMovieClip(MovieClip *clip) { this->m_movieClip = clip; }
void setFramenumber(int framenumber) { this->m_framenumber = framenumber; }
- bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+ bool determineDependingAreaOfInterest(rcti *input,
+ ReadBufferOperation *readOperation,
+ rcti *output);
};
-void deintializeDistortionCache(void);
-
#endif
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
index 504470f1a7e..6106a805f87 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
@@ -109,7 +109,7 @@ void *NormalizeOperation::initializeTileData(rcti *rect)
minmult->x = minv;
/* The rare case of flat buffer would cause a divide by 0 */
- minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.f);
+ minmult->y = ((maxv != minv) ? 1.0f / (maxv - minv) : 0.0f);
this->m_cachedInstance = minmult;
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 1a7e775113b..099208ce600 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -77,21 +77,19 @@ void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, Pi
unsigned int offset;
int width = this->getWidth(), height = this->getHeight();
+ int ix = x, iy = y;
+ if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
+ if (this->m_elementsize == 1)
+ output[0] = 0.0f;
+ else if (this->m_elementsize == 3)
+ zero_v3(output);
+ else
+ zero_v4(output);
+ return;
+ }
+
switch (sampler) {
case COM_PS_NEAREST: {
- int ix = x;
- int iy = y;
- if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
- if (this->m_elementsize == 1)
- output[0] = 0.0f;
- else if (this->m_elementsize == 3)
- zero_v3(output);
- else
- zero_v4(output);
- break;
-
- }
-
offset = (iy * width + ix) * this->m_elementsize;
if (this->m_elementsize == 1)
@@ -150,6 +148,7 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y
expected_element_size = 4;
}
else {
+ expected_element_size = 0;
BLI_assert(!"Something horribly wrong just happened");
}
BLI_assert(expected_element_size == actual_element_size);
@@ -276,7 +275,7 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float
float *inputBuffer = this->getInputBuffer();
if (inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) {
- output[0] = 0.0f;
+ output[0] = 10e10f;
}
else {
unsigned int offset = (iy * this->getWidth() + ix);
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
index acd76fa79a8..e0e5e923654 100644
--- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
@@ -149,9 +149,10 @@ void ScreenLensDistortionOperation::accumulate(MemoryBuffer *buffer,
distort_uv(uv, t, xy);
buffer->readBilinear(color, xy[0], xy[1]);
- sum[a] += (1.0f - tz) * color[a], sum[b] += tz * color[b];
- ++count[a];
- ++count[b];
+ sum[a] += (1.0f - tz) * color[a];
+ sum[b] += (tz ) * color[b];
+ count[a]++;
+ count[b]++;
}
}
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index c75c4040823..665bffc2c1c 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -21,14 +21,17 @@
*/
#include "COM_TextureOperation.h"
+#include "COM_WorkScheduler.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BKE_image.h"
-static ThreadMutex mutex_lock = BLI_MUTEX_INITIALIZER;
+extern "C" {
+#include "BKE_node.h"
+}
-TextureBaseOperation::TextureBaseOperation() : SingleThreadedOperation()
+TextureBaseOperation::TextureBaseOperation() : NodeOperation()
{
this->addInputSocket(COM_DT_VECTOR); //offset
this->addInputSocket(COM_DT_VECTOR); //size
@@ -53,7 +56,13 @@ void TextureBaseOperation::initExecution()
this->m_inputOffset = getInputSocketReader(0);
this->m_inputSize = getInputSocketReader(1);
this->m_pool = BKE_image_pool_new();
- SingleThreadedOperation::initExecution();
+ if (this->m_texture != NULL &&
+ this->m_texture->nodetree != NULL &&
+ this->m_texture->use_nodes)
+ {
+ ntreeTexBeginExecTree(this->m_texture->nodetree);
+ }
+ NodeOperation::initExecution();
}
void TextureBaseOperation::deinitExecution()
{
@@ -61,7 +70,14 @@ void TextureBaseOperation::deinitExecution()
this->m_inputOffset = NULL;
BKE_image_pool_free(this->m_pool);
this->m_pool = NULL;
- SingleThreadedOperation::deinitExecution();
+ if (this->m_texture != NULL &&
+ this->m_texture->use_nodes &&
+ this->m_texture->nodetree != NULL &&
+ this->m_texture->nodetree->execdata != NULL)
+ {
+ ntreeTexEndExecTree(this->m_texture->nodetree->execdata);
+ }
+ NodeOperation::deinitExecution();
}
void TextureBaseOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
@@ -82,7 +98,8 @@ void TextureAlphaOperation::executePixelSampled(float output[4], float x, float
{
float color[4];
TextureBaseOperation::executePixelSampled(color, x, y, sampler);
- output[0] = color[3];}
+ output[0] = color[3];
+}
void TextureBaseOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
@@ -103,12 +120,16 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
vec[1] = textureSize[1] * (v + textureOffset[1]);
vec[2] = textureSize[2] * textureOffset[2];
- /* TODO(sergey): Need to pass thread ID to the multitex code,
- * then we can avoid having mutex here.
- */
- BLI_mutex_lock(&mutex_lock);
- retval = multitex_ext(this->m_texture, vec, NULL, NULL, 0, &texres, m_pool, m_sceneColorManage, false);
- BLI_mutex_unlock(&mutex_lock);
+ const int thread_id = WorkScheduler::current_thread_id();
+ retval = multitex_ext(this->m_texture,
+ vec,
+ NULL, NULL,
+ 0,
+ &texres,
+ thread_id,
+ m_pool,
+ m_sceneColorManage,
+ false);
if (texres.talpha)
output[3] = texres.ta;
diff --git a/source/blender/compositor/operations/COM_TextureOperation.h b/source/blender/compositor/operations/COM_TextureOperation.h
index 47ef40882c5..4cc203b54a2 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.h
+++ b/source/blender/compositor/operations/COM_TextureOperation.h
@@ -24,7 +24,7 @@
#ifndef _COM_TextureOperation_h
#define _COM_TextureOperation_h
-#include "COM_SingleThreadedOperation.h"
+#include "COM_NodeOperation.h"
#include "DNA_texture_types.h"
#include "BLI_listbase.h"
extern "C" {
@@ -39,7 +39,7 @@ extern "C" {
*
* @todo: rename to operation.
*/
-class TextureBaseOperation : public SingleThreadedOperation {
+class TextureBaseOperation : public NodeOperation {
private:
Tex *m_texture;
const RenderData *m_rd;
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp
index c581d115a2f..abef644bab8 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.cpp
+++ b/source/blender/compositor/operations/COM_TonemapOperation.cpp
@@ -52,9 +52,9 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data)
float dr = output[0] + this->m_data->offset;
float dg = output[1] + this->m_data->offset;
float db = output[2] + this->m_data->offset;
- output[0] /= ((dr == 0.f) ? 1.0f : dr);
- output[1] /= ((dg == 0.f) ? 1.0f : dg);
- output[2] /= ((db == 0.f) ? 1.0f : db);
+ output[0] /= ((dr == 0.0f) ? 1.0f : dr);
+ output[1] /= ((dg == 0.0f) ? 1.0f : dg);
+ output[2] /= ((db == 0.0f) ? 1.0f : db);
const float igm = avg->igm;
if (igm != 0.0f) {
output[0] = powf(max(output[0], 0.0f), igm);
@@ -126,7 +126,7 @@ void *TonemapOperation::initializeTileData(rcti *rect)
float *bc = buffer;
float avl, maxl = -1e10f, minl = 1e10f;
const float sc = 1.0f / p;
- float Lav = 0.f;
+ float Lav = 0.0f;
float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
while (p--) {
float L = IMB_colormanagement_get_luminance(bc);
@@ -140,10 +140,10 @@ void *TonemapOperation::initializeTileData(rcti *rect)
data->lav = Lav * sc;
mul_v3_v3fl(data->cav, cav, sc);
maxl = log((double)maxl + 1e-5); minl = log((double)minl + 1e-5); avl = lsum * sc;
- data->auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.f;
+ data->auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
float al = exp((double)avl);
data->al = (al == 0.0f) ? 0.0f : (this->m_data->key / al);
- data->igm = (this->m_data->gamma == 0.f) ? 1 : (1.f / this->m_data->gamma);
+ data->igm = (this->m_data->gamma == 0.0f) ? 1 : (1.0f / this->m_data->gamma);
this->m_cachedInstance = data;
}
unlockMutex();
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 843bf89dc92..9b6858cdaf1 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -82,8 +82,6 @@ public:
void setData(NodeTonemap *data) { this->m_data = data; }
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
-
-
};
/**
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
index ca169d03fbc..f9db897deba 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp
@@ -45,6 +45,7 @@ TrackPositionOperation::TrackPositionOperation() : NodeOperation()
this->m_axis = 0;
this->m_position = CMP_TRACKPOS_ABSOLUTE;
this->m_relativeFrame = 0;
+ this->m_speed_output = false;
}
void TrackPositionOperation::initExecution()
@@ -78,7 +79,25 @@ void TrackPositionOperation::initExecution()
copy_v2_v2(this->m_markerPos, marker->pos);
- if (this->m_position == CMP_TRACKPOS_RELATIVE_START) {
+ if (this->m_speed_output) {
+ int relative_clip_framenr =
+ BKE_movieclip_remap_scene_to_clip_frame(
+ this->m_movieClip,
+ this->m_relativeFrame);
+
+ marker = BKE_tracking_marker_get_exact(track,
+ relative_clip_framenr);
+ if (marker != NULL && (marker->flag & MARKER_DISABLED) == 0) {
+ copy_v2_v2(this->m_relativePos, marker->pos);
+ }
+ else {
+ copy_v2_v2(this->m_relativePos, this->m_markerPos);
+ }
+ if (this->m_relativeFrame < this->m_framenumber) {
+ swap_v2_v2(this->m_relativePos, this->m_markerPos);
+ }
+ }
+ else if (this->m_position == CMP_TRACKPOS_RELATIVE_START) {
int i;
for (i = 0; i < track->markersnr; i++) {
diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.h b/source/blender/compositor/operations/COM_TrackPositionOperation.h
index 10dbaf96646..87bb0623ad5 100644
--- a/source/blender/compositor/operations/COM_TrackPositionOperation.h
+++ b/source/blender/compositor/operations/COM_TrackPositionOperation.h
@@ -47,6 +47,7 @@ protected:
int m_axis;
int m_position;
int m_relativeFrame;
+ bool m_speed_output;
int m_width, m_height;
float m_markerPos[2];
@@ -67,6 +68,7 @@ public:
void setAxis(int value) {this->m_axis = value;}
void setPosition(int value) {this->m_position = value;}
void setRelativeFrame(int value) {this->m_relativeFrame = value;}
+ void setSpeedOutput(bool speed_output) {this->m_speed_output = speed_output;}
void initExecution();
diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt
index 4c35a941757..0f123fbf9f0 100644
--- a/source/blender/datatoc/CMakeLists.txt
+++ b/source/blender/datatoc/CMakeLists.txt
@@ -51,6 +51,9 @@ if(NOT WITH_HEADLESS)
../blenlib/intern/winstuff_dir.c
../../../intern/utfconv/utfconv.c
)
+
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
endif()
include_directories(${PNG_INCLUDE_DIRS})
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index f3ff709e98b..e1dc8b020fb 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -83,7 +83,6 @@ set(SRC
util/depsgraph_util_transitive.h
)
-TEST_UNORDERED_MAP_SUPPORT()
if(HAVE_STD_UNORDERED_MAP_HEADER)
if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
add_definitions(-DDEG_STD_UNORDERED_MAP)
diff --git a/source/blender/depsgraph/SConscript b/source/blender/depsgraph/SConscript
deleted file mode 100644
index 7f49e8f4643..00000000000
--- a/source/blender/depsgraph/SConscript
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2013, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory, Joshua Leung.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-sources = env.Glob('intern/*.cc') + env.Glob('util/*.cc')
-
-incs = [
- '.',
- './intern',
- './util',
- '#/intern/atomic',
- '#/intern/guardedalloc',
- '../bmesh',
- '../blenlib',
- '../blenkernel',
- '../makesdna',
- '../makesrna',
- '../modifiers',
- '../windowmanager',
- ]
-
-defs = []
-
-if env['WITH_BF_BOOST']:
- incs.append(env['BF_BOOST_INC'])
- defs.append('HAVE_BOOST_FUNCTION_BINDINGS')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-
-if env['WITH_UNORDERED_MAP_SUPPORT']:
- if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
- if env['UNORDERED_MAP_NAMESPACE'] == 'std':
- defs.append('DEG_STD_UNORDERED_MAP')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
- elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
- defs.append('DEG_TR1_UNORDERED_MAP')
-else:
- print("-- Replacing unordered_map/set with map/set (warning: slower!)")
- defs.append('DEG_NO_UNORDERED_MAP')
-
-if env['WITH_BF_LEGACY_DEPSGRAPH']:
- defs.append('WITH_LEGACY_DEPSGRAPH')
-
-if env['WITH_BF_OPENSUBDIV']:
- defs.append('WITH_OPENSUBDIV')
-
-env.BlenderLib(libname='bf_depsgraph', sources=sources,
- includes=incs, defines=defs,
- libtype=['core', 'player'], priority=[200, 40])
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index dedb6e322ba..18c7c5bd8e1 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -317,7 +317,7 @@ IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
if (!id_node) {
DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
id_node = (IDDepsNode *)factory->create_node(id, "", name);
- id->flag |= LIB_DOIT;
+ id->tag |= LIB_TAG_DOIT;
/* register */
this->id_hash[id] = id_node;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 7a2ee2c416a..a62b23bde68 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -206,7 +206,7 @@ static void deg_graph_build_finalize(Depsgraph *graph)
stack.push(node);
}
IDDepsNode *id_node = node->owner->owner;
- id_node->id->flag |= LIB_DOIT;
+ id_node->id->tag |= LIB_TAG_DOIT;
}
while (!stack.empty()) {
@@ -249,11 +249,11 @@ static void deg_graph_build_finalize(Depsgraph *graph)
* update tag.
*/
ID *id = id_node->id;
- if (id->flag & LIB_ID_RECALC_ALL &&
- id->flag & LIB_DOIT)
+ if (id->tag & LIB_TAG_ID_RECALC_ALL &&
+ id->tag & LIB_TAG_DOIT)
{
id_node->tag_update(graph);
- id->flag &= ~LIB_DOIT;
+ id->tag &= ~LIB_TAG_DOIT;
}
}
}
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
index ad8d756edc4..f38e81e0013 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
@@ -245,12 +245,12 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
{
- /* LIB_DOIT is used to indicate whether node for given ID was already
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
* created or not. This flag is being set in add_id_node(), so functions
* shouldn't bother with setting it, they only might query this flag when
* needed.
*/
- BKE_main_id_tag_all(bmain, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
/* scene ID block */
add_id_node(&scene->id);
@@ -275,6 +275,7 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
/* object that this is a proxy for */
// XXX: the way that proxies work needs to be completely reviewed!
if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
build_object(scene, base, ob->proxy);
}
@@ -318,10 +319,10 @@ void DepsgraphNodeBuilder::build_group(Scene *scene,
Group *group)
{
ID *group_id = &group->id;
- if (group_id->flag & LIB_DOIT) {
+ if (group_id->tag & LIB_TAG_DOIT) {
return;
}
- group_id->flag |= LIB_DOIT;
+ group_id->tag |= LIB_TAG_DOIT;
for (GroupObject *go = (GroupObject *)group->gobject.first;
go != NULL;
@@ -368,7 +369,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{
- if (ob->id.flag & LIB_DOIT) {
+ if (ob->id.tag & LIB_TAG_DOIT) {
IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
id_node->layers = base->lay;
return;
@@ -433,7 +434,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
default:
{
ID *obdata = (ID *)ob->data;
- if ((obdata->flag & LIB_DOIT) == 0) {
+ if ((obdata->tag & LIB_TAG_DOIT) == 0) {
build_animdata(obdata);
}
break;
@@ -601,7 +602,7 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
void DepsgraphNodeBuilder::build_world(World *world)
{
ID *world_id = &world->id;
- if (world_id->flag & LIB_DOIT) {
+ if (world_id->tag & LIB_TAG_DOIT) {
return;
}
@@ -780,6 +781,14 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
}
}
+ /* Make sure pose is up-to-date with armature updates. */
+ add_operation_node(&arm->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC,
+ NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+
/**
* Pose Rig Graph
* ==============
@@ -1020,7 +1029,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
/* ---- ob->data datablock updates ---- */
/* XXX perhaps move this to a separate function? - lukas_t */
- if (obdata->flag & LIB_DOIT) {
+ if (obdata->tag & LIB_TAG_DOIT) {
+
return;
}
/* XXX is this missing 'obdata->flag |= LIB_DOIT' ?! - lukas_t */
@@ -1105,7 +1115,7 @@ void DepsgraphNodeBuilder::build_camera(Object *ob)
/* TODO: Link scene-camera links in somehow... */
Camera *cam = (Camera *)ob->data;
ID *camera_id = &cam->id;
- if (camera_id->flag & LIB_DOIT) {
+ if (camera_id->tag & LIB_TAG_DOIT) {
return;
}
@@ -1128,7 +1138,7 @@ void DepsgraphNodeBuilder::build_lamp(Object *ob)
{
Lamp *la = (Lamp *)ob->data;
ID *lamp_id = &la->id;
- if (lamp_id->flag & LIB_DOIT) {
+ if (lamp_id->tag & LIB_TAG_DOIT) {
return;
}
@@ -1161,7 +1171,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
build_animdata(ntree_id);
/* Parameters for drivers. */
- add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
/* nodetree's nodes... */
@@ -1174,9 +1184,9 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
build_texture(owner_node, (Tex *)bnode->id);
}
else if (bnode->type == NODE_GROUP) {
- bNodeTree *ntree = (bNodeTree *)bnode->id;
- if ((ntree_id->flag & LIB_DOIT) == 0) {
- build_nodetree(owner_node, ntree);
+ bNodeTree *group_ntree = (bNodeTree *)bnode->id;
+ if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
+ build_nodetree(owner_node, group_ntree);
}
}
}
@@ -1189,7 +1199,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree
void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
{
ID *ma_id = &ma->id;
- if (ma_id->flag & LIB_DOIT) {
+ if (ma_id->tag & LIB_TAG_DOIT) {
return;
}
@@ -1227,10 +1237,10 @@ void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **text
void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
{
ID *tex_id = &tex->id;
- if (tex_id->flag & LIB_DOIT) {
+ if (tex_id->tag & LIB_TAG_DOIT) {
return;
}
- tex_id->flag |= LIB_DOIT;
+ tex_id->tag |= LIB_TAG_DOIT;
/* texture itself */
build_animdata(tex_id);
/* texture's nodetree */
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
index d182aab8cc0..a3f00e79adf 100644
--- a/source/blender/depsgraph/intern/depsgraph_build_relations.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
@@ -240,10 +240,10 @@ void DepsgraphRelationBuilder::add_operation_relation(
void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
{
- /* LIB_DOIT is used to indicate whether node for given ID was already
+ /* LIB_TAG_DOIT is used to indicate whether node for given ID was already
* created or not.
*/
- BKE_main_id_tag_all(bmain, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
if (scene->set) {
// TODO: link set to scene, especially our timesource...
@@ -305,7 +305,7 @@ void DepsgraphRelationBuilder::build_group(Main *bmain,
Group *group)
{
ID *group_id = &group->id;
- bool group_done = (group_id->flag & LIB_DOIT) != 0;
+ bool group_done = (group_id->tag & LIB_TAG_DOIT) != 0;
OperationKey object_local_transform_key(&object->id,
DEPSNODE_TYPE_TRANSFORM,
DEG_OPCODE_TRANSFORM_LOCAL);
@@ -322,12 +322,12 @@ void DepsgraphRelationBuilder::build_group(Main *bmain,
DEPSREL_TYPE_TRANSFORM,
"Dupligroup");
}
- group_id->flag |= LIB_DOIT;
+ group_id->tag |= LIB_TAG_DOIT;
}
void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *ob)
{
- if (ob->id.flag & LIB_DOIT) {
+ if (ob->id.tag & LIB_TAG_DOIT) {
return;
}
@@ -565,9 +565,9 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode
add_relation(camera_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
}
- /* tracker <-> constraints */
- // FIXME: actually motionclip dependency on results of motionclip block here...
- //dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
+ /* TODO(sergey): This is more a TimeSource -> MovieClip -> Constraint dependency chain. */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, constraint_op_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
}
else if (cti->get_constraint_targets) {
ListBase targets = {NULL, NULL};
@@ -812,6 +812,10 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
ComponentKey geometry_key(shape_key->from, DEPSNODE_TYPE_GEOMETRY);
add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
}
+ else if (strstr(fcu->rna_path, "key_blocks[")) {
+ ComponentKey geometry_key(id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ }
else {
if (GS(id->name) == ID_OB) {
/* assume that driver affects a transform... */
@@ -906,10 +910,10 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
void DepsgraphRelationBuilder::build_world(World *world)
{
ID *world_id = &world->id;
- if (world_id->flag & LIB_DOIT) {
+ if (world_id->tag & LIB_TAG_DOIT) {
return;
}
- world_id->flag |= LIB_DOIT;
+ world_id->tag |= LIB_TAG_DOIT;
build_animdata(world_id);
@@ -1118,8 +1122,28 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
}
}
}
+
+ if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
+ ComponentKey dup_ob_key(&part->dup_ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(dup_ob_key,
+ psys_key,
+ DEPSREL_TYPE_TRANSFORM,
+ "Particle Object Visualization");
+ }
}
+ /* Particle depends on the object transform, so that channel is to be ready
+ * first.
+ *
+ * TODO(sergey): This relation should be altered once real granular update
+ * is implemented.
+ */
+ ComponentKey transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(transform_key,
+ obdata_ready_key,
+ DEPSREL_TYPE_GEOMETRY_EVAL,
+ "Partcile Eval");
+
/* pointcache */
// TODO...
}
@@ -1342,6 +1366,8 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
{
/* Armature-Data */
+ bArmature *arm = (bArmature *)ob->data;
+
// TODO: selection status?
/* attach links between pose operations */
@@ -1350,6 +1376,13 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
+ /* Make sure pose is up-to-date with armature updates. */
+ OperationKey armature_key(&arm->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Armature Eval");
+ add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
+
if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
@@ -1679,10 +1712,11 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje
/* ---- ob->data datablock updates ---- */
/* XXX perhaps move this to a separate function? - lukas_t */
- if (obdata->flag & LIB_DOIT) {
+ if (obdata->tag & LIB_TAG_DOIT) {
+
return;
}
- obdata->flag |= LIB_DOIT;
+ obdata->tag |= LIB_TAG_DOIT;
/* Link object data evaluation node to exit operation. */
OperationKey obdata_geom_eval_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
@@ -1766,10 +1800,10 @@ void DepsgraphRelationBuilder::build_camera(Object *ob)
{
Camera *cam = (Camera *)ob->data;
ID *camera_id = &cam->id;
- if (camera_id->flag & LIB_DOIT) {
+ if (camera_id->tag & LIB_TAG_DOIT) {
return;
}
- camera_id->flag |= LIB_DOIT;
+ camera_id->tag |= LIB_TAG_DOIT;
ComponentKey parameters_key(camera_id, DEPSNODE_TYPE_PARAMETERS);
@@ -1792,10 +1826,10 @@ void DepsgraphRelationBuilder::build_lamp(Object *ob)
{
Lamp *la = (Lamp *)ob->data;
ID *lamp_id = &la->id;
- if (lamp_id->flag & LIB_DOIT) {
+ if (lamp_id->tag & LIB_TAG_DOIT) {
return;
}
- lamp_id->flag |= LIB_DOIT;
+ lamp_id->tag |= LIB_TAG_DOIT;
ComponentKey parameters_key(lamp_id, DEPSNODE_TYPE_PARAMETERS);
@@ -1826,6 +1860,11 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
build_animdata(ntree_id);
+ OperationKey parameters_key(ntree_id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+
/* nodetree's nodes... */
for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
if (bnode->id) {
@@ -1836,17 +1875,22 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
build_texture(owner, (Tex *)bnode->id);
}
else if (bnode->type == NODE_GROUP) {
- bNodeTree *ntree = (bNodeTree *)bnode->id;
- if ((ntree_id->flag & LIB_DOIT) == 0) {
- build_nodetree(owner, ntree);
- ntree_id->flag |= LIB_DOIT;
+ bNodeTree *group_ntree = (bNodeTree *)bnode->id;
+ if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) {
+ build_nodetree(owner, group_ntree);
+ group_ntree->id.tag |= LIB_TAG_DOIT;
}
+ OperationKey group_parameters_key(&group_ntree->id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_PLACEHOLDER,
+ "Parameters Eval");
+ add_relation(group_parameters_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Group Node");
}
}
}
if (needs_animdata_node(ntree_id)) {
- ComponentKey parameters_key(ntree_id, DEPSNODE_TYPE_PARAMETERS);
ComponentKey animation_key(ntree_id, DEPSNODE_TYPE_ANIMATION);
add_relation(animation_key, parameters_key,
DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
@@ -1859,10 +1903,10 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
{
ID *ma_id = &ma->id;
- if (ma_id->flag & LIB_DOIT) {
+ if (ma_id->tag & LIB_TAG_DOIT) {
return;
}
- ma_id->flag |= LIB_DOIT;
+ ma_id->tag |= LIB_TAG_DOIT;
/* animation */
build_animdata(ma_id);
@@ -1878,10 +1922,10 @@ void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
{
ID *tex_id = &tex->id;
- if (tex_id->flag & LIB_DOIT) {
+ if (tex_id->tag & LIB_TAG_DOIT) {
return;
}
- tex_id->flag |= LIB_DOIT;
+ tex_id->tag |= LIB_TAG_DOIT;
/* texture itself */
build_animdata(tex_id);
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
index 54980436733..efb3e330857 100644
--- a/source/blender/depsgraph/intern/depsgraph_debug.cc
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -59,8 +59,6 @@ extern "C" {
/* ****************** */
/* Graphviz Debugging */
-static SpinLock lock;
-
#define NL "\r\n"
/* Only one should be enabled, defines whether graphviz nodes
@@ -145,6 +143,7 @@ static int deg_debug_node_color_index(const DepsNode *node)
OperationDepsNode *op_node = (OperationDepsNode *)node;
if (op_node->is_noop())
return 8;
+ break;
}
default:
@@ -328,7 +327,8 @@ static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
int color_index = deg_debug_node_color_index(node);
const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
if (ctx.show_tags &&
- (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE))) {
+ (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE)))
+ {
deg_debug_fprintf(ctx, "\"");
for (int i = 0; i < num_stripes; ++i) {
if (i > 0) {
@@ -514,6 +514,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx,
case DEPSNODE_TYPE_EVAL_POSE:
case DEPSNODE_TYPE_BONE:
case DEPSNODE_TYPE_SHADING:
+ case DEPSNODE_TYPE_EVAL_PARTICLES:
{
ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
if (!comp_node->operations.empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 65d75fccad3..486526ed46c 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -76,13 +76,13 @@ namespace {
void lib_id_recalc_tag(Main *bmain, ID *id)
{
- id->flag |= LIB_ID_RECALC;
+ id->tag |= LIB_TAG_ID_RECALC;
DEG_id_type_tag(bmain, GS(id->name));
}
void lib_id_recalc_data_tag(Main *bmain, ID *id)
{
- id->flag |= LIB_ID_RECALC_DATA;
+ id->tag |= LIB_TAG_ID_RECALC_DATA;
DEG_id_type_tag(bmain, GS(id->name));
}
@@ -284,6 +284,7 @@ void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
{
OperationDepsNode *node = *it;
node->scheduled = false;
+ node->owner->flags &= ~DEPSCOMP_FULLY_SCHEDULED;
}
FlushQueue queue;
@@ -353,12 +354,16 @@ void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
* witin a component at least we tag the whole component
* for update.
*/
- for (ComponentDepsNode::OperationMap::iterator it = node->owner->operations.begin();
- it != node->owner->operations.end();
- ++it)
- {
- OperationDepsNode *op = it->second;
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ ComponentDepsNode *component = node->owner;
+ if ((component->flags & DEPSCOMP_FULLY_SCHEDULED) == 0) {
+ for (ComponentDepsNode::OperationMap::iterator it = component->operations.begin();
+ it != node->owner->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op = it->second;
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ component->flags |= DEPSCOMP_FULLY_SCHEDULED;
}
}
}
@@ -407,16 +412,16 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
int old_layers = graph->layers;
if (wm != NULL) {
- BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, true);
+ BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
graph->layers = 0;
for (wmWindow *win = (wmWindow *)wm->windows.first;
win != NULL;
win = (wmWindow *)win->next)
{
Scene *scene = win->screen->scene;
- if (scene->id.flag & LIB_DOIT) {
+ if (scene->id.tag & LIB_TAG_DOIT) {
graph->layers |= BKE_screen_visible_layers(win->screen, scene);
- scene->id.flag &= ~LIB_DOIT;
+ scene->id.tag &= ~LIB_TAG_DOIT;
}
}
}
@@ -438,7 +443,7 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
OperationDepsNode *node = *it;
IDDepsNode *id_node = node->owner->owner;
ID *id = id_node->id;
- if ((id->flag & LIB_ID_RECALC_ALL) != 0 ||
+ if ((id->tag & LIB_TAG_ID_RECALC_ALL) != 0 ||
(id_node->layers & scene->lay_updated) == 0)
{
id_node->tag_update(graph);
@@ -450,7 +455,7 @@ void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
*/
if (GS(id->name) == ID_OB) {
Object *object = (Object *)id;
- if ((id->flag & LIB_ID_RECALC_ALL) == 0 &&
+ if ((id->tag & LIB_TAG_ID_RECALC_ALL) == 0 &&
(object->recalc & OB_RECALC_ALL) != 0)
{
id_node->tag_update(graph);
@@ -526,12 +531,12 @@ void DEG_ids_clear_recalc(Main *bmain)
*/
if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
for (; id; id = (ID *)id->next) {
- id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ id->tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
/* Some ID's contain semi-datablock nodetree */
ntree = ntreeFromID(id);
if (ntree != NULL) {
- ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ ntree->id.tag &= ~(LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA);
}
}
}
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/depsnode_component.cc
index 1d939c6580d..a47a0d29228 100644
--- a/source/blender/depsgraph/intern/depsnode_component.cc
+++ b/source/blender/depsgraph/intern/depsnode_component.cc
@@ -50,7 +50,8 @@ extern "C" {
ComponentDepsNode::ComponentDepsNode() :
entry_operation(NULL),
- exit_operation(NULL)
+ exit_operation(NULL),
+ flags(0)
{
}
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/depsnode_component.h
index e3550bb2371..7f44c0ed03f 100644
--- a/source/blender/depsgraph/intern/depsnode_component.h
+++ b/source/blender/depsgraph/intern/depsnode_component.h
@@ -46,6 +46,12 @@ struct EvaluationContext;
struct OperationDepsNode;
struct BoneComponentDepsNode;
+typedef enum eDepsComponent_Flag {
+ /* Temporary flags, meaning all the component's operations has been
+ * scheduled for update.
+ */
+ DEPSCOMP_FULLY_SCHEDULED = 1,
+} eDepsComponent_Flag;
/* ID Component - Base type for all components */
struct ComponentDepsNode : public DepsNode {
@@ -146,6 +152,8 @@ struct ComponentDepsNode : public DepsNode {
OperationDepsNode *exit_operation;
// XXX: a poll() callback to check if component's first node can be started?
+
+ int flags;
};
/* ---------------------------------------- */
diff --git a/source/blender/editors/SConscript b/source/blender/editors/SConscript
deleted file mode 100644
index 1ea2bc0e4ef..00000000000
--- a/source/blender/editors/SConscript
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-
-SConscript(['datafiles/SConscript',
- 'space_api/SConscript',
- 'util/SConscript',
- 'interface/SConscript',
- 'io/SConscript',
- 'animation/SConscript',
- 'armature/SConscript',
- 'mask/SConscript',
- 'mesh/SConscript',
- 'metaball/SConscript',
- 'object/SConscript',
- 'curve/SConscript',
- 'gpencil/SConscript',
- 'physics/SConscript',
- 'render/SConscript',
- 'sound/SConscript',
- 'space_buttons/SConscript',
- 'space_clip/SConscript',
- 'space_file/SConscript',
- 'space_image/SConscript',
- 'space_info/SConscript',
- 'space_graph/SConscript',
- 'space_node/SConscript',
- 'space_outliner/SConscript',
- 'space_time/SConscript',
- 'space_view3d/SConscript',
- 'space_action/SConscript',
- 'space_nla/SConscript',
- 'space_script/SConscript',
- 'space_text/SConscript',
- 'space_sequencer/SConscript',
- 'space_logic/SConscript',
- 'space_console/SConscript',
- 'space_userpref/SConscript',
- 'transform/SConscript',
- 'screen/SConscript',
- 'sculpt_paint/SConscript',
- 'uvedit/SConscript'])
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index 473b0e6bc5a..1bf1bb2a474 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -59,6 +59,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_PYTHON)
+ add_definitions(-DWITH_PYTHON)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript
deleted file mode 100644
index fb5ff53cf16..00000000000
--- a/source/blender/editors/animation/SConscript
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_animation', sources, incs, defs, libtype=['core'], priority=[125])
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 6979850c21a..9d54fd8f730 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -2812,7 +2812,6 @@ static bool acf_gpl_setting_valid(bAnimContext *UNUSED(ac), bAnimListElem *UNUSE
switch (setting) {
/* unsupported */
case ACHANNEL_SETTING_EXPAND: /* gpencil layers are more like F-Curves than groups */
- case ACHANNEL_SETTING_VISIBLE: /* graph editor only */
case ACHANNEL_SETTING_SOLO: /* nla editor only */
return false;
@@ -2832,7 +2831,11 @@ static int acf_gpl_setting_flag(bAnimContext *UNUSED(ac), eAnimChannel_Settings
case ACHANNEL_SETTING_SELECT: /* selected */
return GP_LAYER_SELECT;
- case ACHANNEL_SETTING_MUTE: /* muted */
+ case ACHANNEL_SETTING_MUTE: /* animation muting - similar to frame lock... */
+ return GP_LAYER_FRAMELOCK;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visiblity of the layers (NOT muting) */
+ *neg = true;
return GP_LAYER_HIDE;
case ACHANNEL_SETTING_PROTECT: /* protected */
@@ -3716,7 +3719,6 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
glLineWidth(2.0);
fdrawline((float)(offset), yminc,
(float)(v2d->cur.xmax), yminc);
- glLineWidth(1.0);
}
}
@@ -3758,9 +3760,13 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
/* protect... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PROTECT))
offset += ICON_WIDTH;
+
/* mute... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MUTE))
offset += ICON_WIDTH;
+ if (ale->type == ANIMTYPE_GPLAYER)
+ offset += ICON_WIDTH;
+
/* pinned... */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_PINNED))
offset += ICON_WIDTH;
@@ -3868,6 +3874,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
short flag = 0;
@@ -3890,7 +3897,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -3906,6 +3913,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
short flag = 0;
@@ -3933,7 +3941,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -3956,6 +3964,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po
ReportList *reports = CTX_wm_reports(C);
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
short flag = 0;
bool done = false;
float cfra;
@@ -3975,7 +3984,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C, void *UNUSED(id_po
flag |= INSERTKEY_REPLACE;
/* insert a keyframe for this F-Curve */
- done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+ done = insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, flag);
if (done)
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -4007,6 +4016,8 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE))
tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
+ else if (ale->type == ANIMTYPE_GPLAYER)
+ tooltip = TIP_("Grease Pencil layer is visible in the viewport");
else
tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
@@ -4052,6 +4063,9 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, const bAni
else if ((ac) && (ac->spacetype == SPACE_NLA) && (ale->type != ANIMTYPE_NLATRACK)) {
tooltip = TIP_("Temporarily disable NLA stack evaluation (i.e. only the active action is evaluated)");
}
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ tooltip = TIP_("Lock current frame displayed by layer (i.e. disable animation playback)");
+ }
else {
tooltip = TIP_("Do channels contribute to result (toggle channel muting)");
}
@@ -4248,6 +4262,13 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
UI_block_emboss_set(block, UI_EMBOSS_NONE);
}
+ else {
+ /* Cannot get property/cannot or rename for some reason, so clear rename index
+ * so that this doesn't hang around, and the name can be drawn normally - T47492
+ */
+ ac->ads->renameIndex = 0;
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL);
+ }
}
/* step 5) draw mute+protection toggles + (sliders) ....................... */
@@ -4288,6 +4309,11 @@ void ANIM_channel_draw_widgets(const bContext *C, bAnimContext *ac, bAnimListEle
offset += ICON_WIDTH;
draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_MUTE);
}
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ /* Not technically "mute" (in terms of anim channels, but this sets layer visibility instead) */
+ offset += ICON_WIDTH;
+ draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_VISIBLE);
+ }
/* modifiers disable */
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_MOD_OFF)) {
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index a38f5dbc8ea..5665ce59783 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -35,6 +35,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
@@ -46,6 +47,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
@@ -351,7 +353,7 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
{
bAnimListElem *ale;
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ELEM(ac->datatype, ANIMCONT_MASK)) {
#ifdef DEBUG
/* quiet assert */
for (ale = anim_data->first; ale; ale = ale->next) {
@@ -362,25 +364,42 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
}
for (ale = anim_data->first; ale; ale = ale->next) {
- FCurve *fcu = ale->key_data;
-
- if (ale->update & ANIM_UPDATE_ORDER) {
- ale->update &= ~ANIM_UPDATE_ORDER;
- if (fcu)
- sort_time_fcurve(fcu);
- }
-
- if (ale->update & ANIM_UPDATE_HANDLES) {
- ale->update &= ~ANIM_UPDATE_HANDLES;
- if (fcu)
- calchandles_fcurve(fcu);
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPDlayer *gpl = ale->data;
+
+ if (ale->update & ANIM_UPDATE_ORDER) {
+ ale->update &= ~ANIM_UPDATE_ORDER;
+ if (gpl) {
+ //gpencil_sort_frames(gpl);
+ }
+ }
+
+ if (ale->update & ANIM_UPDATE_DEPS) {
+ ale->update &= ~ANIM_UPDATE_DEPS;
+ ANIM_list_elem_update(ac->scene, ale);
+ }
}
-
- if (ale->update & ANIM_UPDATE_DEPS) {
- ale->update &= ~ANIM_UPDATE_DEPS;
- ANIM_list_elem_update(ac->scene, ale);
+ else if (ale->datatype == ALE_FCURVE) {
+ FCurve *fcu = ale->key_data;
+
+ if (ale->update & ANIM_UPDATE_ORDER) {
+ ale->update &= ~ANIM_UPDATE_ORDER;
+ if (fcu)
+ sort_time_fcurve(fcu);
+ }
+
+ if (ale->update & ANIM_UPDATE_HANDLES) {
+ ale->update &= ~ANIM_UPDATE_HANDLES;
+ if (fcu)
+ calchandles_fcurve(fcu);
+ }
+
+ if (ale->update & ANIM_UPDATE_DEPS) {
+ ale->update &= ~ANIM_UPDATE_DEPS;
+ ANIM_list_elem_update(ac->scene, ale);
+ }
}
-
+
BLI_assert(ale->update == 0);
}
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index ed3d228a93e..dbc9c8b4f23 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -111,31 +111,23 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
Scene *scene = CTX_data_scene(C);
- float vec[2];
-
+
/* Draw a light green line to indicate current frame */
- vec[0] = (float)(scene->r.cfra * scene->r.framelen);
-
UI_ThemeColor(TH_CFRAME);
- if (flag & DRAWCFRA_WIDE)
- glLineWidth(3.0);
- else
- glLineWidth(2.0);
-
- glBegin(GL_LINE_STRIP);
- vec[1] = v2d->cur.ymin - 500.0f; /* XXX arbitrary... want it go to bottom */
- glVertex2fv(vec);
-
- vec[1] = v2d->cur.ymax;
- glVertex2fv(vec);
+
+ const float x = (float)(scene->r.cfra * scene->r.framelen);
+
+ glLineWidth((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
+
+ glBegin(GL_LINES);
+ glVertex2f(x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
+ glVertex2f(x, v2d->cur.ymax);
glEnd();
-
- glLineWidth(1.0);
-
+
/* Draw current frame number in a little box */
if (flag & DRAWCFRA_SHOW_NUMBOX) {
UI_view2d_view_orthoSpecial(CTX_wm_region(C), v2d, 1);
- draw_cfra_number(scene, v2d, vec[0], (flag & DRAWCFRA_UNIT_SECONDS) != 0);
+ draw_cfra_number(scene, v2d, x, (flag & DRAWCFRA_UNIT_SECONDS) != 0);
}
}
@@ -181,11 +173,17 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
/* abort if rendering - we may get some race condition issues... */
if (G.is_rendering) return NULL;
- /* handling depends on the type of animation-context we've got */
- if (ale) {
- /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
- if (ale->type != ANIMTYPE_NLACURVE)
- return ale->adt;
+ /* apart from strictly keyframe-related contexts, this shouldn't even happen */
+ // XXX: nla and channel here may not be necessary...
+ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_SHAPEKEY, ANIMCONT_DOPESHEET,
+ ANIMCONT_FCURVES, ANIMCONT_NLA, ANIMCONT_CHANNEL))
+ {
+ /* handling depends on the type of animation-context we've got */
+ if (ale) {
+ /* NLA Control Curves occur on NLA strips, and shouldn't be subjected to this kind of mapping */
+ if (ale->type != ANIMTYPE_NLACURVE)
+ return ale->adt;
+ }
}
/* cannot handle... */
@@ -403,7 +401,6 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
Mask *mask = CTX_data_edit_mask(C);
bDopeSheet ads = {NULL};
DLRBT_Tree keys;
@@ -425,11 +422,12 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev
/* populate tree with keyframe nodes */
scene_to_keylist(&ads, scene, &keys, NULL);
+ gpencil_to_keylist(&ads, scene->gpd, &keys);
- if (ob)
+ if (ob) {
ob_to_keylist(&ads, ob, &keys, NULL);
-
- gpencil_to_keylist(&ads, gpd, &keys);
+ gpencil_to_keylist(&ads, ob->gpd, &keys);
+ }
if (mask) {
MaskLayer *masklay = BKE_mask_layer_active(mask);
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 8853422df8f..910e195173c 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -76,7 +76,9 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
#include "BLI_ghash.h"
+#include "BLI_string.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
@@ -986,6 +988,35 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
return false;
}
+/* Helper for name-based filtering - Perform "partial/fuzzy matches" (as in 80a7efd) */
+static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name)
+{
+ if (ads->flag & ADS_FLAG_FUZZY_NAMES) {
+ /* full fuzzy, multi-word, case insensitive matches */
+ const size_t str_len = strlen(ads->searchstr);
+ const int words_max = (str_len / 2) + 1;
+
+ int (*words)[2] = BLI_array_alloca(words, words_max);
+ const int words_len = BLI_string_find_split_words(ads->searchstr, str_len, ' ', words, words_max);
+ bool found = false;
+
+ /* match name against all search words */
+ for (int index = 0; index < words_len; index++) {
+ if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) {
+ found = true;
+ break;
+ }
+ }
+
+ /* if we have a match somewhere, this returns true */
+ return found;
+ }
+ else {
+ /* fallback/default - just case insensitive, but starts from start of word */
+ return BLI_strcasestr(name, ads->searchstr) != NULL;
+ }
+}
+
/* (Display-)Name-based F-Curve filtering
* NOTE: when this function returns true, the F-Curve is to be skipped
*/
@@ -1010,7 +1041,7 @@ static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
/* check for partial match with the match string, assuming case insensitive filtering
* if match, this channel shouldn't be ignored!
*/
- return BLI_strcasestr(name, ads->searchstr) == NULL;
+ return !name_matches_dopesheet_filter(ads, name);
}
/* just let this go... */
@@ -1315,12 +1346,12 @@ static size_t animfilter_nla(bAnimContext *UNUSED(ac), ListBase *anim_data, bDop
bool track_ok = false, strip_ok = false;
/* check if the name of the track, or the strips it has are ok... */
- track_ok = BLI_strcasestr(nlt->name, ads->searchstr);
+ track_ok = name_matches_dopesheet_filter(ads, nlt->name);
if (track_ok == false) {
NlaStrip *strip;
for (strip = nlt->strips.first; strip; strip = strip->next) {
- if (BLI_strcasestr(strip->name, ads->searchstr)) {
+ if (name_matches_dopesheet_filter(ads, strip->name)) {
strip_ok = true;
break;
}
@@ -1505,7 +1536,7 @@ static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Ke
}
/* Helper for Grease Pencil - layers within a datablock */
-static size_t animdata_filter_gpencil_data(ListBase *anim_data, bGPdata *gpd, int filter_mode)
+static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode)
{
bGPDlayer *gpl;
size_t items = 0;
@@ -1518,6 +1549,13 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data, bGPdata *gpd, in
if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) {
/* active... */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (gpl->flag & GP_LAYER_ACTIVE)) {
+ /* skip layer if the name doesn't match the filter string */
+ if ((ads) && (ads->filterflag & ADS_FILTER_BY_FCU_NAME)) {
+ if (name_matches_dopesheet_filter(ads, gpl->info) == false)
+ continue;
+ }
+
+
/* add to list */
ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd);
}
@@ -1528,54 +1566,121 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data, bGPdata *gpd, in
return items;
}
-/* Grab all Grease Pencil datablocks in file */
-// TODO: should this be amalgamated with the dopesheet filtering code?
-static size_t animdata_filter_gpencil(ListBase *anim_data, void *UNUSED(data), int filter_mode)
+/* Helper for Grease Pencil - Grease Pencil datablock - GP Frames */
+static size_t animdata_filter_gpencil_data(ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode)
{
- bGPdata *gpd;
size_t items = 0;
- /* for now, grab grease pencil datablocks directly from main */
- // XXX: this is not good...
- for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
+ /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
+ * for convenience, this will return GP Datablocks instead. This may cause issues down
+ * the track, but for now, this will do...
+ */
+ if (filter_mode & ANIMFILTER_ANIMDATA) {
+ /* just add GPD as a channel - this will add everything needed */
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ }
+ else {
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
- /* only show if gpd is used by something... */
- if (ID_REAL_USERS(gpd) < 1)
- continue;
-
- /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
- * for convenience, this will return GP Datablocks instead. This may cause issues down
- * the track, but for now, this will do...
- */
- if (filter_mode & ANIMFILTER_ANIMDATA) {
- /* just add GPD as a channel - this will add everything needed */
- ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ /* add gpencil animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
+ {
+ tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
}
- else {
- /* add gpencil animation channels */
- BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
- {
- tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include data-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* add gpd as channel too (if for drawing, and it has layers) */
+ ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
}
- END_ANIMFILTER_SUBCHANNELS;
- /* did we find anything? */
- if (tmp_items) {
- /* include data-expand widget first */
- if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
- /* add gpd as channel too (if for drawing, and it has layers) */
- ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert(BLI_listbase_is_empty(&tmp_data));
+ items += tmp_items;
+ }
+ }
+
+ return items;
+}
+
+/* Grab all Grease Pencil datablocks in file */
+// TODO: should this be amalgamated with the dopesheet filtering code?
+static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, void *UNUSED(data), int filter_mode)
+{
+ bDopeSheet *ads = ac->ads;
+ size_t items = 0;
+
+ if (ads->filterflag & ADS_FILTER_GP_3DONLY) {
+ Scene *scene = (Scene *)ads->source;
+ Base *base;
+
+ /* Active scene's GPencil block first - No parent item needed... */
+ if (scene->gpd) {
+ items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
+ }
+
+ /* Objects in the scene */
+ for (base = scene->base.first; base; base = base->next) {
+ /* Only consider this object if it has got some GP data (saving on all the other tests) */
+ if (base->object && base->object->gpd) {
+ Object *ob = base->object;
+
+ /* firstly, check if object can be included, by the following factors:
+ * - if only visible, must check for layer and also viewport visibility
+ * --> while tools may demand only visible, user setting takes priority
+ * as user option controls whether sets of channels get included while
+ * tool-flag takes into account collapsed/open channels too
+ * - if only selected, must check if object is selected
+ * - there must be animation data to edit (this is done recursively as we
+ * try to add the channels)
+ */
+ if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+ /* layer visibility - we check both object and base, since these may not be in sync yet */
+ if ((scene->lay & (ob->lay | base->lay)) == 0) continue;
+
+ /* outliner restrict-flag */
+ if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
}
- /* now add the list of collected channels */
- BLI_movelisttolist(anim_data, &tmp_data);
- BLI_assert(BLI_listbase_is_empty(&tmp_data));
- items += tmp_items;
+ /* check selection and object type filters */
+ if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == scene->basact)*/) ) {
+ /* only selected should be shown */
+ continue;
+ }
+
+ /* check if object belongs to the filtering group if option to filter
+ * objects by the grouped status is on
+ * - used to ease the process of doing multiple-character choreographies
+ */
+ if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) {
+ if (BKE_group_object_exists(ads->filter_grp, ob) == 0)
+ continue;
+ }
+
+ /* finally, include this object's grease pencil datablock */
+ /* XXX: Should we store these under expanders per item? */
+ items += animdata_filter_gpencil_data(anim_data, ads, ob->gpd, filter_mode);
}
}
}
+ else {
+ bGPdata *gpd;
+
+ /* Grab all Grease Pencil datablocks directly from main, but only those that seem to be useful somewhere */
+ for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
+ /* only show if gpd is used by something... */
+ if (ID_REAL_USERS(gpd) < 1)
+ continue;
+
+ /* add GP frames from this datablock */
+ items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
+ }
+ }
/* return the number of items added to the list */
return items;
@@ -1754,7 +1859,7 @@ static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data
for (srl = sce->r.layers.first; srl; srl = srl->next) {
for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
- lineset->linestyle->id.flag |= LIB_DOIT;
+ lineset->linestyle->id.tag |= LIB_TAG_DOIT;
}
}
}
@@ -1771,11 +1876,11 @@ static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data
size_t tmp_items = 0;
if ((linestyle == NULL) ||
- !(linestyle->id.flag & LIB_DOIT))
+ !(linestyle->id.tag & LIB_TAG_DOIT))
{
continue;
}
- linestyle->id.flag &= ~LIB_DOIT;
+ linestyle->id.tag &= ~LIB_TAG_DOIT;
/* add scene-level animation channels */
BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle))
@@ -2016,7 +2121,7 @@ typedef struct tAnimFilterModifiersContext {
/* dependency walker callback for modifier dependencies */
-static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin)
+static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, int UNUSED(cd_flag))
{
tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
ID *owner_id = &ob->id;
@@ -2880,7 +2985,7 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_F
case ANIMCONT_GPENCIL:
{
if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
- items = animdata_filter_gpencil(anim_data, data, filter_mode);
+ items = animdata_filter_gpencil(ac, anim_data, data, filter_mode);
break;
}
case ANIMCONT_MASK:
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index b2a34d7c317..f92967ef5ff 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "DNA_anim_types.h"
#include "DNA_texture_types.h"
@@ -50,6 +51,7 @@
#include "ED_keyframing.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -59,9 +61,6 @@
#include "anim_intern.h"
-/* called by WM */
-void free_anim_drivers_copybuf(void);
-
/* ************************************************** */
/* Animation Data Validation */
@@ -130,8 +129,8 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
* - These are configured to 0,0 and 1,1 to give a 1-1 mapping
* which can be easily tweaked from there.
*/
- insert_vert_fcurve(fcu, 0.0f, 0.0f, INSERTKEY_FAST);
- insert_vert_fcurve(fcu, 1.0f, 1.0f, INSERTKEY_FAST);
+ insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
+ insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
/* configure this curve to extrapolate */
for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
@@ -154,6 +153,214 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* ************************************************** */
/* Driver Management API */
+/* Helper for ANIM_add_driver_with_target - Adds the actual driver */
+static int add_driver_with_target(
+ ReportList *UNUSED(reports),
+ ID *dst_id, const char dst_path[], int dst_index,
+ ID *src_id, const char src_path[], int src_index,
+ PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop,
+ PointerRNA *src_ptr, PropertyRNA *src_prop,
+ short flag, int driver_type)
+{
+ FCurve *fcu;
+ short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
+ const char *prop_name = RNA_property_identifier(src_prop);
+
+ /* Create F-Curve with Driver */
+ fcu = verify_driver_fcurve(dst_id, dst_path, dst_index, add_mode);
+
+ if (fcu && fcu->driver) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ /* Set the type of the driver */
+ driver->type = driver_type;
+
+ /* Set driver expression, so that the driver works out of the box
+ *
+ * The following checks define a bit of "autodetection magic" we use
+ * to ensure that the drivers will behave as expected out of the box
+ * when faced with properties with different units.
+ */
+ /* XXX: if we have N-1 mapping, should we include all those in the expression? */
+ if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) &&
+ (RNA_property_unit(src_prop) != PROP_UNIT_ROTATION))
+ {
+ /* Rotation Destination: normal -> radians, so convert src to radians
+ * (However, if both input and output is a rotation, don't apply such corrections)
+ */
+ BLI_strncpy(driver->expression, "radians(var)", sizeof(driver->expression));
+ }
+ else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) &&
+ (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION))
+ {
+ /* Rotation Source: radians -> normal, so convert src to degrees
+ * (However, if both input and output is a rotation, don't apply such corrections)
+ */
+ BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression));
+ }
+ else {
+ /* Just a normal property without any unit problems */
+ BLI_strncpy(driver->expression, "var", sizeof(driver->expression));
+ }
+
+ /* Create a driver variable for the target
+ * - For transform properties, we want to automatically use "transform channel" instead
+ * (The only issue is with quat rotations vs euler channels...)
+ */
+ dvar = driver_add_new_variable(driver);
+
+ if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) &&
+ (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")))
+ {
+ /* Transform Channel */
+ DriverTarget *dtar;
+
+ driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN);
+ dtar = &dvar->targets[0];
+
+ /* Bone or Object target? */
+ dtar->id = src_id;
+ dtar->idtype = GS(src_id->name);
+
+ if (src_ptr->type == &RNA_PoseBone) {
+ RNA_string_get(src_ptr, "name", dtar->pchan_name);
+ }
+
+ /* Transform channel depends on type */
+ if (STREQ(prop_name, "location")) {
+ if (src_index == 2)
+ dtar->transChan = DTAR_TRANSCHAN_LOCZ;
+ else if (src_index == 1)
+ dtar->transChan = DTAR_TRANSCHAN_LOCY;
+ else
+ dtar->transChan = DTAR_TRANSCHAN_LOCX;
+ }
+ else if (STREQ(prop_name, "scale")) {
+ if (src_index == 2)
+ dtar->transChan = DTAR_TRANSCHAN_SCALEZ;
+ else if (src_index == 1)
+ dtar->transChan = DTAR_TRANSCHAN_SCALEY;
+ else
+ dtar->transChan = DTAR_TRANSCHAN_SCALEX;
+ }
+ else {
+ /* XXX: With quaternions and axis-angle, this mapping might not be correct...
+ * But since those have 4 elements instead, there's not much we can do
+ */
+ if (src_index == 2)
+ dtar->transChan = DTAR_TRANSCHAN_ROTZ;
+ else if (src_index == 1)
+ dtar->transChan = DTAR_TRANSCHAN_ROTY;
+ else
+ dtar->transChan = DTAR_TRANSCHAN_ROTX;
+ }
+ }
+ else {
+ /* Single RNA Property */
+ DriverTarget *dtar = &dvar->targets[0];
+
+ /* ID is as-is */
+ dtar->id = src_id;
+ dtar->idtype = GS(src_id->name);
+
+ /* Need to make a copy of the path (or build one with array index built in) */
+ if (RNA_property_array_check(src_prop)) {
+ dtar->rna_path = BLI_sprintfN("%s[%d]", src_path, src_index);
+ }
+ else {
+ dtar->rna_path = BLI_strdup(src_path);
+ }
+ }
+ }
+
+ /* set the done status */
+ return (fcu != NULL);
+}
+
+/* Main Driver Management API calls:
+ * Add a new driver for the specified property on the given ID block,
+ * and make it be driven by the specified target.
+ *
+ * This is intended to be used in conjunction with a modal "eyedropper"
+ * for picking the variable that is going to be used to drive this one.
+ *
+ * - flag: eCreateDriverFlags
+ * - driver_type: eDriver_Types
+ * - mapping_type: eCreateDriver_MappingTypes
+ */
+int ANIM_add_driver_with_target(
+ ReportList *reports,
+ ID *dst_id, const char dst_path[], int dst_index,
+ ID *src_id, const char src_path[], int src_index,
+ short flag, int driver_type, short mapping_type)
+{
+ PointerRNA id_ptr, ptr;
+ PropertyRNA *prop;
+
+ PointerRNA id_ptr2, ptr2;
+ PropertyRNA *prop2;
+ int done_tot = 0;
+
+ /* validate pointers first - exit if failure */
+ RNA_id_pointer_create(dst_id, &id_ptr);
+ if (RNA_path_resolve_property(&id_ptr, dst_path, &ptr, &prop) == false) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
+ dst_id->name, dst_path);
+ return 0;
+ }
+
+ RNA_id_pointer_create(src_id, &id_ptr2);
+ if ((RNA_path_resolve_property(&id_ptr2, src_path, &ptr2, &prop2) == false) ||
+ (mapping_type == CREATEDRIVER_MAPPING_NONE))
+ {
+ /* No target - So, fall back to default method for adding a "simple" driver normally */
+ return ANIM_add_driver(reports, dst_id, dst_path, dst_index, flag | CREATEDRIVER_WITH_DEFAULT_DVAR, driver_type);
+ }
+
+ /* handle curve-property mappings based on mapping_type */
+ switch (mapping_type) {
+ case CREATEDRIVER_MAPPING_N_N: /* N-N - Try to match as much as possible, then use the first one */
+ {
+ /* Use the shorter of the two (to avoid out of bounds access) */
+ int dst_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1;
+ int src_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr2, prop2) : 1;
+
+ int len = MIN2(dst_len, src_len);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ done_tot += add_driver_with_target(reports, dst_id, dst_path, i, src_id, src_path, i, &ptr, prop, &ptr2, prop2, flag, driver_type);
+ }
+ break;
+ }
+
+ case CREATEDRIVER_MAPPING_1_N: /* 1-N - Specified target index for all */
+ default:
+ {
+ int len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ done_tot += add_driver_with_target(reports, dst_id, dst_path, i, src_id, src_path, src_index, &ptr, prop, &ptr2, prop2, flag, driver_type);
+ }
+ break;
+ }
+
+ case CREATEDRIVER_MAPPING_1_1: /* 1-1 - Use the specified index (unless -1) */
+ {
+ done_tot = add_driver_with_target(reports, dst_id, dst_path, dst_index, src_id, src_path, src_index, &ptr, prop, &ptr2, prop2, flag, driver_type);
+ break;
+ }
+ }
+
+ /* done */
+ return done_tot;
+}
+
+/* --------------------------------- */
+
/* Main Driver Management API calls:
* Add a new driver for the specified property on the given ID block
*/
@@ -304,8 +511,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports), ID *id, const char rna_path
static FCurve *channeldriver_copypaste_buf = NULL;
/* This function frees any MEM_calloc'ed copy/paste buffer data */
-// XXX find some header to put this in!
-void free_anim_drivers_copybuf(void)
+void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
if (channeldriver_copypaste_buf)
@@ -343,7 +549,7 @@ bool ANIM_copy_driver(ReportList *reports, ID *id, const char rna_path[], int ar
fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
/* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
- free_anim_drivers_copybuf();
+ ANIM_drivers_copybuf_free();
/* copy this to the copy/paste buf if it exists */
if (fcu && fcu->driver) {
@@ -394,7 +600,7 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
/* create Driver F-Curve, but without data which will be copied across... */
fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
-
+
if (fcu) {
/* copy across the curve data from the buffer curve
* NOTE: this step needs care to not miss new settings
@@ -419,22 +625,203 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
}
/* ************************************************** */
+/* Driver Management API - Copy/Paste Driver Variables */
+
+/* Copy/Paste Buffer for Driver Variables... */
+static ListBase driver_vars_copybuf = {NULL, NULL};
+
+/* This function frees any MEM_calloc'ed copy/paste buffer data */
+void ANIM_driver_vars_copybuf_free(void)
+{
+ /* Free the driver variables kept in the buffer */
+ if (driver_vars_copybuf.first) {
+ DriverVar *dvar, *dvarn;
+
+ /* Free variables (and any data they use) */
+ for (dvar = driver_vars_copybuf.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable(&driver_vars_copybuf, dvar);
+ }
+ }
+
+ BLI_listbase_clear(&driver_vars_copybuf);
+}
+
+/* Checks if there are driver variables in the copy/paste buffer */
+bool ANIM_driver_vars_can_paste(void)
+{
+ return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
+}
+
+/* -------------------------------------------------- */
+
+/* Copy the given driver's variables to the buffer */
+bool ANIM_driver_vars_copy(ReportList *reports, FCurve *fcu)
+{
+ /* sanity checks */
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ BKE_report(reports, RPT_ERROR, "No driver to copy variables from");
+ return false;
+ }
+
+ if (BLI_listbase_is_empty(&fcu->driver->variables)) {
+ BKE_report(reports, RPT_ERROR, "Driver has no variables to copy");
+ return false;
+ }
+
+ /* clear buffer */
+ ANIM_driver_vars_copybuf_free();
+
+ /* copy over the variables */
+ driver_variables_copy(&driver_vars_copybuf, &fcu->driver->variables);
+
+ return (BLI_listbase_is_empty(&driver_vars_copybuf) == false);
+}
+
+/* Paste the variables in the buffer to the given FCurve */
+bool ANIM_driver_vars_paste(ReportList *reports, FCurve *fcu, bool replace)
+{
+ ChannelDriver *driver = (fcu) ? fcu->driver : NULL;
+ ListBase tmp_list = {NULL, NULL};
+
+ /* sanity checks */
+ if (BLI_listbase_is_empty(&driver_vars_copybuf)) {
+ BKE_report(reports, RPT_ERROR, "No driver variables in clipboard to paste");
+ return false;
+ }
+
+ if (ELEM(NULL, fcu, fcu->driver)) {
+ BKE_report(reports, RPT_ERROR, "Cannot paste driver variables without a driver");
+ return false;
+ }
+
+ /* 1) Make a new copy of the variables in the buffer - these will get pasted later... */
+ driver_variables_copy(&tmp_list, &driver_vars_copybuf);
+
+ /* 2) Prepare destination array */
+ if (replace) {
+ DriverVar *dvar, *dvarn;
+
+ /* Free all existing vars first - We aren't retaining anything */
+ for (dvar = driver->variables.first; dvar; dvar = dvarn) {
+ dvarn = dvar->next;
+ driver_free_variable_ex(driver, dvar);
+ }
+
+ BLI_listbase_clear(&driver->variables);
+ }
+
+ /* 3) Add new vars */
+ if (driver->variables.last) {
+ DriverVar *last = driver->variables.last;
+ DriverVar *first = tmp_list.first;
+
+ last->next = first;
+ first->prev = last;
+
+ driver->variables.last = tmp_list.last;
+ }
+ else {
+ driver->variables.first = tmp_list.first;
+ driver->variables.last = tmp_list.last;
+ }
+
+#ifdef WITH_PYTHON
+ /* since driver variables are cached, the expression needs re-compiling too */
+ if (driver->type == DRIVER_TYPE_PYTHON)
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+#endif
+
+ return true;
+}
+
+/* ************************************************** */
/* UI-Button Interface */
+/* Add Driver - Enum Defines ------------------------- */
+
+/* Mapping Types enum for operators */
+/* NOTE: Used by ANIM_OT_driver_button_add and UI_OT_eyedropper_driver */
+// XXX: These names need reviewing
+EnumPropertyItem prop_driver_create_mapping_types[] = {
+ {CREATEDRIVER_MAPPING_1_N, "SINGLE_MANY", ICON_UI, "All from Target",
+ "Drive all components of this property using the target picked"},
+ {CREATEDRIVER_MAPPING_1_1, "DIRECT", 0, "Single from Target",
+ "Drive this component of this property using the target picked"},
+
+ {CREATEDRIVER_MAPPING_N_N, "MATCH", ICON_COLOR, "Match Indices",
+ "Create drivers for each pair of corresponding elements"},
+
+ {CREATEDRIVER_MAPPING_NONE_ALL, "NONE_ALL", ICON_HAND, "Manually Create Later",
+ "Create drivers for all properites without assigning any targets yet"},
+ {CREATEDRIVER_MAPPING_NONE, "NONE_SINGLE", 0, "Manually Create Later (Single)",
+ "Create driver for this property only and without assigning any targets yet"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* Filtering callback for driver mapping types enum */
+static EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, PointerRNA *UNUSED(owner_ptr), PropertyRNA *UNUSED(owner_prop), bool *r_free)
+{
+ EnumPropertyItem *input = prop_driver_create_mapping_types;
+ EnumPropertyItem *item = NULL;
+
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ int totitem = 0;
+
+ if (!C) /* needed for docs */
+ return prop_driver_create_mapping_types;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
+ const bool is_array = RNA_property_array_check(prop);
+
+ while (input->identifier) {
+ if (ELEM(input->value, CREATEDRIVER_MAPPING_1_1, CREATEDRIVER_MAPPING_NONE) || (is_array)) {
+ RNA_enum_item_add(&item, &totitem, input);
+ }
+ input++;
+ }
+ }
+ else {
+ /* We need at least this one! */
+ RNA_enum_items_add_value(&item, &totitem, input, CREATEDRIVER_MAPPING_NONE);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+
+ *r_free = true;
+ return item;
+}
+
+
/* Add Driver Button Operator ------------------------ */
-static int add_driver_button_exec(bContext *C, wmOperator *op)
+static int add_driver_button_poll(bContext *C)
{
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
- int success = 0;
int index;
- const bool all = RNA_boolean_get(op->ptr, "all");
- /* try to create driver using property retrieved from UI */
+ /* this operator can only run if there's a property button active, and it can be animated */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+ return (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop));
+}
+
+/* Wrapper for creating a driver without knowing what the targets will be yet (i.e. "manual/add later") */
+static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_type)
+{
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+ int success = 0;
- if (all)
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ if (mapping_type == CREATEDRIVER_MAPPING_NONE_ALL)
index = -1;
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
@@ -443,7 +830,6 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
if (path) {
success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
-
MEM_freeN(path);
}
}
@@ -452,10 +838,47 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
/* send updates */
UI_context_update_anim_flag(C);
DAG_relations_tag_update(CTX_data_main(C));
- WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int add_driver_button_exec(bContext *C, wmOperator *op)
+{
+ short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
+ if (ELEM(mapping_type, CREATEDRIVER_MAPPING_NONE, CREATEDRIVER_MAPPING_NONE_ALL)) {
+ /* Just create driver with no targets */
+ return add_driver_button_none(C, op, mapping_type);
+ }
+ else {
+ /* Create Driver using Eyedropper */
+ wmOperatorType *ot = WM_operatortype_find("UI_OT_eyedropper_driver", true);
+
+ /* XXX: We assume that it's fine to use the same set of properties, since they're actually the same... */
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, op->ptr);
+
+ return OPERATOR_FINISHED;
}
+}
+
+/* Show menu or create drivers */
+static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ PropertyRNA *prop;
- return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if ((prop = RNA_struct_find_property(op->ptr, "mapping_type")) && RNA_property_is_set(op->ptr, prop)) {
+ /* Mapping Type is Set - Directly go into creating drivers */
+ return add_driver_button_exec(C, op);
+ }
+ else {
+ /* Show menu */
+ // TODO: This should get filtered by the enum filter
+ return WM_menu_invoke(C, op, event);
+ }
}
void ANIM_OT_driver_button_add(wmOperatorType *ot)
@@ -466,14 +889,20 @@ void ANIM_OT_driver_button_add(wmOperatorType *ot)
ot->description = "Add driver(s) for the property(s) connected represented by the highlighted button";
/* callbacks */
+ /* NOTE: No exec, as we need all these to use the current context info
+ * (especially the eyedropper, which is interactive)
+ */
+ ot->invoke = add_driver_button_invoke;
ot->exec = add_driver_button_exec;
- //op->poll = ??? // TODO: need to have some animatable property to do this
+ ot->poll = add_driver_button_poll;
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
-
+
/* properties */
- RNA_def_boolean(ot->srna, "all", 1, "All", "Create drivers for all elements of the array");
+ ot->prop = RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
+ "Mapping Type", "Method used to match target and driven properties");
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
}
/* Remove Driver Button Operator ------------------------ */
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 91705d63286..6bb73416fec 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -697,14 +697,14 @@ static ListBase fmodifier_copypaste_buf = {NULL, NULL};
/* ---------- */
/* free the copy/paste buffer */
-void free_fmodifiers_copybuf(void)
+void ANIM_fmodifiers_copybuf_free(void)
{
/* just free the whole buffer */
free_fmodifiers(&fmodifier_copypaste_buf);
}
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
+ * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
* - active: only copy the active modifier
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index bd34f32dda8..08a7355694b 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -44,6 +44,7 @@
#include "DNA_scene_types.h"
#include "BKE_fcurve.h"
+#include "BKE_nla.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
@@ -290,9 +291,39 @@ static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, Key
case ALE_MASKLAY:
case ALE_GPFRAME:
break;
+
+ case ALE_FCURVE:
default:
- ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
+ {
+ if (ked && ked->iterflags) {
+ /* make backups of the current values, so that a localised fix
+ * (e.g. NLA time remapping) can be applied to these values
+ */
+ float f1 = ked->f1;
+ float f2 = ked->f2;
+
+ if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ if (ked->iterflags & KED_F1_NLA_UNMAP)
+ ked->f1 = BKE_nla_tweakedit_remap(adt, f1, NLATIME_CONVERT_UNMAP);
+ if (ked->iterflags & KED_F2_NLA_UNMAP)
+ ked->f2 = BKE_nla_tweakedit_remap(adt, f2, NLATIME_CONVERT_UNMAP);
+ }
+
+ /* now operate on the channel as per normal */
+ ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
+
+ /* reset */
+ ked->f1 = f1;
+ ked->f2 = f2;
+ }
+ else {
+ /* no special handling required... */
+ ret_code = ANIM_fcurve_keyframes_loop(ked, ale->data, key_ok, key_cb, fcu_cb);
+ }
break;
+ }
}
if (ret_code)
@@ -516,9 +547,9 @@ static bool bezier_region_lasso_test(
{
if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) {
float xy_view[2];
-
+
BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
-
+
if (BLI_lasso_is_point_inside(data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) {
return true;
}
@@ -529,16 +560,14 @@ static bool bezier_region_lasso_test(
static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt)
{
- /* rect is stored in data property (it's of type rectf, but may not be set) */
+ /* check for lasso customdata (KeyframeEdit_LassoData) */
if (ked->data) {
short ok = 0;
-
+
#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
-
- /* check for lasso */
-
+
/* return ok flags */
return ok;
}
@@ -555,9 +584,9 @@ static bool bezier_region_circle_test(
{
if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) {
float xy_view[2];
-
+
BLI_rctf_transform_pt_v(data_circle->rectf_view, data_circle->rectf_scaled, xy_view, xy);
-
+
xy_view[0] = xy_view[0] - data_circle->mval[0];
xy_view[1] = xy_view[1] - data_circle->mval[1];
return len_squared_v2(xy_view) < data_circle->radius_squared;
@@ -569,14 +598,14 @@ static bool bezier_region_circle_test(
static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt)
{
- /* rect is stored in data property (it's of type rectf, but may not be set) */
+ /* check for circle select customdata (KeyframeEdit_CircleData) */
if (ked->data) {
short ok = 0;
-
+
#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index])
KEYFRAME_OK_CHECKS(KEY_CHECK_OK);
#undef KEY_CHECK_OK
-
+
/* return ok flags */
return ok;
}
@@ -603,7 +632,7 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode)
return ok_bezier_region;
case BEZT_OK_REGION_LASSO: /* only if the point falls within KeyframeEdit_LassoData defined data */
return ok_bezier_region_lasso;
- case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_LassoData defined data */
+ case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */
return ok_bezier_region_circle;
default: /* nothing was ok */
return NULL;
@@ -714,6 +743,14 @@ static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *be
return 0;
}
+/* frame to snap to is stored in the custom data -> first float value slot */
+static short snap_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->vec[1][0] = ked->f1;
+ return 0;
+}
+
/* value to snap to is stored in the custom data -> first float value slot */
static short snap_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
{
@@ -736,6 +773,8 @@ KeyframeEditFunc ANIM_editkeyframes_snap(short type)
return snap_bezier_nearestsec;
case SNAP_KEYS_HORIZONTAL: /* snap handles to same value */
return snap_bezier_horizontal;
+ case SNAP_KEYS_TIME: /* snap to given frame/time */
+ return snap_bezier_time;
case SNAP_KEYS_VALUE: /* snap to given value */
return snap_bezier_value;
default: /* just in case */
@@ -812,6 +851,16 @@ static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
return 0;
}
+static short mirror_bezier_time(KeyframeEditData *ked, BezTriple *bezt)
+{
+ /* value to mirror over is strored in f1 */
+ if (bezt->f2 & SELECT) {
+ mirror_bezier_xaxis_ex(bezt, ked->f1);
+ }
+
+ return 0;
+}
+
static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
{
/* value to mirror over is stored in the custom data -> first float value slot */
@@ -835,6 +884,8 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
return mirror_bezier_xaxis;
case MIRROR_KEYS_MARKER: /* mirror over marker */
return mirror_bezier_marker;
+ case MIRROR_KEYS_TIME: /* mirror over frame/time */
+ return mirror_bezier_time;
case MIRROR_KEYS_VALUE: /* mirror over given value */
return mirror_bezier_value;
default: /* just in case */
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 3642c07b758..1703210f0b6 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -203,7 +203,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* now insert first keyframe, as it should be ok */
bezt = old_bezts;
- insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
+ insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], BEZKEYTYPE(bezt), 0);
if (!(bezt->f2 & SELECT)) {
lastb = fcu->bezt;
lastb->f1 = lastb->f2 = lastb->f3 = 0;
@@ -226,13 +226,13 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
lastb = (fcu->bezt + (fcu->totvert - 1));
bezt = (old_bezts + i);
-
+
/* get references for quicker access */
prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
-
+
if (!(bezt->f2 & SELECT)) {
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
lastb = (fcu->bezt + (fcu->totvert - 1));
lastb->f1 = lastb->f2 = lastb->f3 = 0;
continue;
@@ -251,7 +251,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
if (cur[1] > next[1]) {
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
}
}
}
@@ -259,7 +259,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* only add if values are a considerable distance apart */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
}
}
}
@@ -269,18 +269,18 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
/* does current have same value as previous and next? */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe*/
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
}
else if (IS_EQT(cur[1], next[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
}
}
else {
/* add if value doesn't equal that of previous */
if (IS_EQT(cur[1], prev[1], thresh) == 0) {
/* add new keyframe */
- insert_vert_fcurve(fcu, cur[0], cur[1], 0);
+ insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0);
}
}
}
@@ -436,7 +436,7 @@ void sample_fcurve(FCurve *fcu)
BezTriple *bezt, *start = NULL, *end = NULL;
TempFrameValCache *value_cache, *fp;
int sfra, range;
- int i, n, nIndex;
+ int i, n;
if (fcu->bezt == NULL) /* ignore baked */
return;
@@ -467,8 +467,7 @@ void sample_fcurve(FCurve *fcu)
/* add keyframes with these, tagging as 'breakdowns' */
for (n = 1, fp = value_cache; n < range && fp; n++, fp++) {
- nIndex = insert_vert_fcurve(fcu, fp->frame, fp->val, 1);
- BEZKEYTYPE(fcu->bezt + nIndex) = BEZT_KEYTYPE_BREAKDOWN;
+ insert_vert_fcurve(fcu, fp->frame, fp->val, BEZT_KEYTYPE_BREAKDOWN, 1);
}
/* free temp cache */
@@ -528,8 +527,7 @@ typedef struct tAnimCopybufItem {
/* This function frees any MEM_calloc'ed copy/paste buffer data */
-// XXX find some header to put this in!
-void free_anim_copybuf(void)
+void ANIM_fcurves_copybuf_free(void)
{
tAnimCopybufItem *aci, *acn;
@@ -564,7 +562,7 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
Scene *scene = ac->scene;
/* clear buffer first */
- free_anim_copybuf();
+ ANIM_fcurves_copybuf_free();
/* assume that each of these is an F-Curve */
for (ale = anim_data->first; ale; ale = ale->next) {
@@ -885,14 +883,14 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
/* ------------------- */
-EnumPropertyItem keyframe_paste_offset_items[] = {
+EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
{KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"},
{KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"},
{KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"},
{KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"},
{0, NULL, 0, NULL, NULL}};
-EnumPropertyItem keyframe_paste_merge_items[] = {
+EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
{KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"},
{KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"},
{KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"},
@@ -929,7 +927,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
return -1;
}
- /* mathods of offset */
+ /* methods of offset */
switch (offset_mode) {
case KEYFRAME_PASTE_OFFSET_CFRA_START:
offset = (float)(CFRA - animcopy_firstframe);
@@ -955,6 +953,7 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
aci = animcopybuf.first;
paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, false);
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
else {
/* from selected channels
@@ -997,9 +996,9 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
totmatch++;
if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode, flip);
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 479b4272755..6a19cf679be 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -301,7 +301,7 @@ void update_autoflags_fcurve(FCurve *fcu, bContext *C, ReportList *reports, Poin
* NOTE: any recalculate of the F-Curve that needs to be done will need to
* be done by the caller.
*/
-int insert_bezt_fcurve(FCurve *fcu, BezTriple *bezt, short flag)
+int insert_bezt_fcurve(FCurve *fcu, const BezTriple *bezt, short flag)
{
int i = 0;
@@ -383,11 +383,16 @@ int insert_bezt_fcurve(FCurve *fcu, BezTriple *bezt, short flag)
return i;
}
-/* This function is a wrapper for insert_bezt_fcurve_internal(), and should be used when
+/**
+ * This function is a wrapper for insert_bezt_fcurve_internal(), and should be used when
* adding a new keyframe to a curve, when the keyframe doesn't exist anywhere else yet.
* It returns the index at which the keyframe was added.
+ *
+ * \param keyframe_type: The type of keyframe (eBezTriple_KeyframeTypes)
+ * \param flag: Optional flags (eInsertKeyFlags) for controlling how keys get added
+ * and/or whether updates get done
*/
-int insert_vert_fcurve(FCurve *fcu, float x, float y, short flag)
+int insert_vert_fcurve(FCurve *fcu, float x, float y, char keyframe_type, short flag)
{
BezTriple beztr = {{{0}}};
unsigned int oldTot = fcu->totvert;
@@ -413,9 +418,8 @@ int insert_vert_fcurve(FCurve *fcu, float x, float y, short flag)
beztr.ipo = BEZT_IPO_BEZ;
}
else {
- /* for UI usage - defaults should come from the */
+ /* for UI usage - defaults should come from the userprefs and/or toolsettings */
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
- //BEZKEYTYPE(&beztr)= scene->keytype; /* default keyframe type */
/* use default interpolation mode, with exceptions for int/discrete values */
beztr.ipo = U.ipo_new;
@@ -429,6 +433,9 @@ int insert_vert_fcurve(FCurve *fcu, float x, float y, short flag)
beztr.ipo = BEZT_IPO_LIN;
}
+ /* set keyframe type value (supplied), which should come from the scene settings in most cases */
+ BEZKEYTYPE(&beztr) = keyframe_type;
+
/* set default values for "easing" interpolation mode settings
* NOTE: Even if these modes aren't currently used, if users switch
* to these later, we want these to work in a sane way out of
@@ -873,11 +880,13 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
* Use this when validation of necessary animation data is not necessary, since an RNA-pointer to the necessary
* data being keyframed, and a pointer to the F-Curve to use have both been provided.
*
+ * keytype is the "keyframe type" (eBezTriple_KeyframeTypes), as shown in the Dope Sheet.
+ *
* The flag argument is used for special settings that alter the behavior of
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
* and extra keyframe filtering.
*/
-bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, short flag)
+bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, char keytype, short flag)
{
float curval = 0.0f;
@@ -922,6 +931,12 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
/* update F-Curve flags to ensure proper behaviour for property type */
update_autoflags_fcurve_direct(fcu, prop);
+ /* adjust frame on which to add keyframe */
+ if ((flag & INSERTKEY_DRIVER) && (fcu->driver)) {
+ /* for making it easier to add corrective drivers... */
+ cfra = evaluate_driver(fcu->driver, cfra);
+ }
+
/* obtain value to give keyframe */
if ( (flag & INSERTKEY_MATRIX) &&
(visualkey_can_use(&ptr, prop)) )
@@ -946,7 +961,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
/* insert new keyframe at current frame */
if (insert_mode)
- insert_vert_fcurve(fcu, cfra, curval, flag);
+ insert_vert_fcurve(fcu, cfra, curval, keytype, flag);
/* delete keyframe immediately before/after newly added */
switch (insert_mode) {
@@ -964,7 +979,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
}
else {
/* just insert keyframe */
- insert_vert_fcurve(fcu, cfra, curval, flag);
+ insert_vert_fcurve(fcu, cfra, curval, keytype, flag);
/* return success */
return true;
@@ -983,7 +998,7 @@ bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *pr
*
* index of -1 keys all array indices
*/
-short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag)
+short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char group[], const char rna_path[], int array_index, float cfra, char keytype, short flag)
{
PointerRNA id_ptr, ptr;
PropertyRNA *prop = NULL;
@@ -1057,7 +1072,7 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
}
/* insert keyframe */
- ret += insert_keyframe_direct(reports, ptr, prop, fcu, cfra, flag);
+ ret += insert_keyframe_direct(reports, ptr, prop, fcu, cfra, keytype, flag);
}
}
@@ -1253,8 +1268,9 @@ static short clear_keyframe(ReportList *reports, ID *id, bAction *act, const cha
continue;
if (BKE_fcurve_is_protected(fcu)) {
- if (G.debug & G_DEBUG)
- printf("WARNING: not deleting keyframe for locked F-Curve\n");
+ BKE_reportf(reports, RPT_WARNING,
+ "Not clearing all keyframes from locked F-Curve '%s' for %s '%s'",
+ fcu->rna_path, BKE_idcode_to_name(GS(id->name)), id->name + 2);
continue;
}
@@ -1645,14 +1661,45 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op)
for (fcu = act->curves.first; fcu; fcu = fcn) {
fcn = fcu->next;
-
+
+ /* don't touch protected F-Curves */
if (BKE_fcurve_is_protected(fcu)) {
BKE_reportf(op->reports, RPT_WARNING,
"Not deleting keyframe for locked F-Curve '%s', object '%s'",
fcu->rna_path, id->name + 2);
continue;
}
-
+
+ /* special exception for bones, as this makes this operator more convenient to use
+ * NOTE: This is only done in pose mode. In object mode, we're dealign with the entire object.
+ */
+ if ((ob->mode & OB_MODE_POSE) && strstr(fcu->rna_path, "pose.bones[\"")) {
+ bPoseChannel *pchan;
+ char *bone_name;
+
+ /* get bone-name, and check if this bone is selected */
+ bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (bone_name) MEM_freeN(bone_name);
+
+ /* skip if bone is not selected */
+ if ((pchan) && (pchan->bone)) {
+ /* bones are only selected/editable if visible... */
+ bArmature *arm = (bArmature *)ob->data;
+
+ /* skipping - not visible on currently visible layers */
+ if ((arm->layer & pchan->bone->layer) == 0)
+ continue;
+ /* skipping - is currently hidden */
+ if (pchan->bone->flag & BONE_HIDDEN_P)
+ continue;
+
+ /* selection flag... */
+ if ((pchan->bone->flag & BONE_SELECTED) == 0)
+ continue;
+ }
+ }
+
/* delete keyframes on current frame
* WARNING: this can delete the next F-Curve, hence the "fcn" copying
*/
@@ -1661,7 +1708,11 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op)
}
/* report success (or failure) */
- BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %d keyframes removed", id->name + 2, success);
+ if (success)
+ BKE_reportf(op->reports, RPT_INFO, "Object '%s' successfully had %d keyframes removed", id->name + 2, success);
+ else
+ BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2);
+
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
}
CTX_DATA_END;
@@ -1676,7 +1727,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Delete Keyframe";
- ot->description = "Remove keyframes on current frame for selected objects";
+ ot->description = "Remove keyframes on current frame for selected objects and bones";
ot->idname = "ANIM_OT_keyframe_delete_v3d";
/* callbacks */
@@ -1695,9 +1746,11 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
static int insert_key_button_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
char *path;
+ uiBut *but;
float cfra = (float)CFRA;
short success = 0;
int index;
@@ -1708,6 +1761,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
flag = ANIM_get_keyframing_flags(scene, 1);
/* try to insert keyframe using property retrieved from UI */
+ but = UI_context_active_but_get(C);
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if ((ptr.id.data && ptr.data && prop) && RNA_property_animateable(&ptr, prop)) {
@@ -1719,7 +1773,18 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
NlaStrip *strip = (NlaStrip *)ptr.data;
FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
- success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, 0);
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
+ }
+ else if (UI_but_flag_is_set(but, UI_BUT_DRIVEN)) {
+ /* Driven property - Find driver */
+ FCurve *fcu;
+ bool driven, special;
+
+ fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+
+ if (fcu && driven) {
+ success = insert_keyframe_direct(op->reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
+ }
}
else {
/* standard properties */
@@ -1731,7 +1796,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
- success = insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, flag);
+ success = insert_keyframe(op->reports, ptr.id.data, NULL, NULL, path, index, cfra, ts->keyframe_type, flag);
MEM_freeN(path);
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 4b9a629183e..b907ad150aa 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -955,8 +955,9 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
ReportList *reports = CTX_wm_reports(C);
KS_Path *ksp;
const short base_kflags = ANIM_get_keyframing_flags(scene, 1);
- short kflag = 0, success = 0;
const char *groupname = NULL;
+ short kflag = 0, success = 0;
+ char keytype = scene->toolsettings->keyframe_type;
/* sanity checks */
if (ks == NULL)
@@ -1014,8 +1015,10 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
PropertyRNA *prop;
RNA_id_pointer_create(ksp->id, &id_ptr);
- if (RNA_path_resolve_property(&id_ptr, ksp->rna_path, &ptr, &prop))
+ if (RNA_path_resolve_property(&id_ptr, ksp->rna_path, &ptr, &prop)) {
arraylen = RNA_property_array_length(&ptr, prop);
+ i = 0; /* start from start of array, instead of the previously specified index - T48020 */
+ }
}
/* we should do at least one step */
@@ -1028,7 +1031,7 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
for (; i < arraylen; i++) {
/* action to take depends on mode */
if (mode == MODIFYKEY_MODE_INSERT)
- success += insert_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
+ success += insert_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, keytype, kflag2);
else if (mode == MODIFYKEY_MODE_DELETE)
success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
}
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 1ed70b3cd98..b213aca478f 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/eigen
../../../../intern/glew-mx
)
@@ -68,13 +69,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_OPENNL)
- add_definitions(-DWITH_OPENNL)
- list(APPEND INC_SYS
- ../../../../intern/opennl/extern
- )
-endif()
-
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_armature "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript
deleted file mode 100644
index 9c3959ecb5b..00000000000
--- a/source/blender/editors/armature/SConscript
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/opennl/extern',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_armature', sources, Split(incs), defs, libtype=['core'], priority=[44] )
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 59453f0ac71..218f215a350 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -38,6 +38,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_ghash.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
@@ -287,6 +288,66 @@ void preEditBoneDuplicate(ListBase *editbones)
ED_armature_ebone_listbase_temp_clear(editbones);
}
+/**
+ * Helper function for #postEditBoneDuplicate,
+ * return the destination pchan from the original.
+ *
+ * \param use_orig_fallback: return the input value if no new channel is found.
+ */
+static bPoseChannel *pchan_duplicate_map(
+ const bPose *pose, GHash *name_map,
+ bPoseChannel *pchan_src, bool use_orig_fallback)
+{
+ bPoseChannel *pchan_dst = NULL;
+ const char *name_src = pchan_src->name;
+ const char *name_dst = BLI_ghash_lookup(name_map, name_src);
+ if (name_dst) {
+ pchan_dst = BKE_pose_channel_find_name(pose, name_dst);
+ }
+
+ if ((pchan_dst == NULL) && use_orig_fallback) {
+ pchan_dst = pchan_src;
+ }
+
+ return pchan_dst;
+}
+
+void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
+{
+ if (ob->pose == NULL) {
+ return;
+ }
+
+ BKE_pose_channels_hash_free(ob->pose);
+ BKE_pose_channels_hash_make(ob->pose);
+
+ GHash *name_map = BLI_ghash_str_new(__func__);
+
+ for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ EditBone *ebone_dst = ebone_src->temp.ebone;
+ if (ebone_dst) {
+ BLI_ghash_insert(name_map, ebone_src->name, ebone_dst->name);
+ }
+ }
+
+ for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ EditBone *ebone_dst = ebone_src->temp.ebone;
+ if (ebone_dst) {
+ bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
+ if (pchan_src) {
+ bPoseChannel *pchan_dst = BKE_pose_channel_find_name(ob->pose, ebone_dst->name);
+ if (pchan_dst) {
+ if (pchan_src->custom_tx) {
+ pchan_dst->custom_tx = pchan_duplicate_map(ob->pose, name_map, pchan_src->custom_tx, true);
+ }
+ }
+ }
+ }
+ }
+
+ BLI_ghash_free(name_map, NULL, NULL);
+}
+
/*
* Note: When duplicating cross objects, editbones here is the list of bones
* from the SOURCE object but ob is the DESTINATION object
@@ -490,6 +551,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
}
}
+ postEditBoneDuplicate(arm->edbo, obedit);
+
ED_armature_validate_active(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
@@ -687,6 +750,8 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
arm->act_edbone = arm->act_edbone->temp.ebone;
}
+ postEditBoneDuplicate(arm->edbo, obedit);
+
ED_armature_validate_active(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
@@ -697,7 +762,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
/* following conventions from #MESH_OT_symmetrize */
void ARMATURE_OT_symmetrize(wmOperatorType *ot)
{
- /* subset of 'symmetrize_direction_items' */
+ /* subset of 'rna_enum_symmetrize_direction_items' */
static EnumPropertyItem arm_symmetrize_direction_items[] = {
{-1, "NEGATIVE_X", 0, "-X to +X", ""},
{+1, "POSITIVE_X", 0, "+X to -X", ""},
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 5a0e70dc5dd..b1c23fb4cac 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -156,7 +156,7 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente
mul_m4_v3(ob->imat, cent);
}
else {
- if (around == V3D_CENTROID) {
+ if (around == V3D_AROUND_CENTER_MEAN) {
int total = 0;
zero_v3(cent);
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
@@ -459,6 +459,58 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
}
+static int armature_roll_clear_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+
+ bArmature *arm = ob->data;
+ EditBone *ebone;
+
+ const float roll = RNA_float_get(op->ptr, "roll");
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ /* roll func is a callback which assumes that all is well */
+ ebone->roll = roll;
+ }
+ }
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
+ EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone);
+ if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
+ ebone->roll = -ebone_mirr->roll;
+ }
+ }
+ }
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_roll_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Roll";
+ ot->idname = "ARMATURE_OT_roll_clear";
+ ot->description = "Clear roll for selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_roll_clear_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_rotation(
+ ot->srna, "roll", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f),
+ "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f));
+}
+
/* ******************************** Chain-Based Tools ********************************* */
/* temporary data-structure for merge/fill bones */
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 2968851f2eb..ac150b9af74 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -54,6 +54,7 @@ void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_align(struct wmOperatorType *ot);
void ARMATURE_OT_calculate_roll(struct wmOperatorType *ot);
+void ARMATURE_OT_roll_clear(struct wmOperatorType *ot);
void ARMATURE_OT_switch_direction(struct wmOperatorType *ot);
void ARMATURE_OT_subdivide(struct wmOperatorType *ot);
@@ -221,6 +222,7 @@ bool BIF_sk_selectStroke(struct bContext *C, const int mval[2], const bool exten
/* duplicate method */
void preEditBoneDuplicate(struct ListBase *editbones);
+void postEditBoneDuplicate(struct ListBase *editbones, struct Object *ob);
struct EditBone *duplicateEditBone(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *ob);
void updateDuplicateSubtarget(struct EditBone *dupBone, struct ListBase *editbones, struct Object *ob);
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index e7f036f6911..ed5f96a5829 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -49,6 +49,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_align);
WM_operatortype_append(ARMATURE_OT_calculate_roll);
+ WM_operatortype_append(ARMATURE_OT_roll_clear);
WM_operatortype_append(ARMATURE_OT_switch_direction);
WM_operatortype_append(ARMATURE_OT_subdivide);
@@ -228,6 +229,7 @@ void ED_keymap_armature(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ARMATURE_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_align", AKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_calculate_roll", NKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "ARMATURE_OT_roll_clear", RKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ARMATURE_OT_switch_direction", FKEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index f4575105426..5a70a45fad4 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -425,7 +425,7 @@ static int ebone_select_flag(EditBone *ebone)
}
/* context: editmode armature in view3d */
-bool mouse_armature(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
Object *obedit = CTX_data_edit_object(C);
bArmature *arm = obedit->data;
@@ -740,14 +740,20 @@ void ARMATURE_OT_select_less(wmOperatorType *ot)
}
enum {
- SIMEDBONE_LENGTH = 1,
+ SIMEDBONE_CHILDREN = 1,
+ SIMEDBONE_CHILDREN_IMMEDIATE,
+ SIMEDBONE_SIBLINGS,
+ SIMEDBONE_LENGTH,
SIMEDBONE_DIRECTION,
SIMEDBONE_PREFIX,
SIMEDBONE_SUFFIX,
- SIMEDBONE_LAYER
+ SIMEDBONE_LAYER,
};
static EnumPropertyItem prop_similar_types[] = {
+ {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""},
+ {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""},
+ {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""},
{SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
{SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
{SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
@@ -855,6 +861,57 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
}
}
+static void is_ancestor(EditBone * bone, EditBone * ancestor)
+{
+ if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL)
+ return;
+
+ if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor)
+ is_ancestor(bone->temp.ebone, ancestor);
+
+ bone->temp.ebone = bone->temp.ebone->temp.ebone;
+}
+
+static void select_similar_children(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone_iter;
+
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ ebone_iter->temp.ebone = ebone_iter->parent;
+ }
+
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ is_ancestor(ebone_iter, ebone_act);
+
+ if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter))
+ ED_armature_ebone_select_set(ebone_iter, true);
+ }
+}
+
+static void select_similar_children_immediate(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone_iter;
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
+ ED_armature_ebone_select_set(ebone_iter, true);
+ }
+ }
+}
+
+static void select_similar_siblings(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone_iter;
+
+ if (ebone_act->parent == NULL)
+ return;
+
+ for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
+ ED_armature_ebone_select_set(ebone_iter, true);
+ }
+ }
+}
+
static int armature_select_similar_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -872,6 +929,15 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
}
switch (type) {
+ case SIMEDBONE_CHILDREN:
+ select_similar_children(arm, ebone_act);
+ break;
+ case SIMEDBONE_CHILDREN_IMMEDIATE:
+ select_similar_children_immediate(arm, ebone_act);
+ break;
+ case SIMEDBONE_SIBLINGS:
+ select_similar_siblings(arm, ebone_act);
+ break;
case SIMEDBONE_LENGTH:
select_similar_length(arm, ebone_act, thresh);
break;
@@ -929,7 +995,7 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
ob = obedit;
arm = (bArmature *)ob->data;
- ebone_active = arm->act_edbone;
+ ebone_active = arm->act_edbone;
if (ebone_active == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index ea1a94fbba6..28fddbab796 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -51,12 +51,10 @@
#include "ED_armature.h"
#include "ED_mesh.h"
+#include "eigen_capi.h"
#include "armature_intern.h"
-
-#ifdef WITH_OPENNL
-# include "meshlaplacian.h"
-#endif
+#include "meshlaplacian.h"
#if 0
#include "reeb.h"
@@ -216,7 +214,7 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
continue;
}
- iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : -1;
+ iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, NULL, i, use_topology) : -1;
/* for each skinnable bone */
for (j = 0; j < numbones; ++j) {
@@ -401,12 +399,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
if (heat) {
const char *error = NULL;
-#ifdef WITH_OPENNL
heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
root, tip, selected, &error);
-#else
- error = "Built without OpenNL";
-#endif
if (error) {
BKE_report(reports, RPT_WARNING, error);
}
@@ -417,7 +411,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
}
/* only generated in some cases but can call anyway */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
/* free the memory allocated */
MEM_freeN(bonelist);
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 2235f9f92cc..7c09ad49f35 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -82,7 +82,7 @@ static RigGraph *GLOBAL_RIGG = NULL;
/*******************************************************************************************************/
-void exec_retargetArctoArc(TaskPool *pool, void *taskdata, int threadid);
+void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid);
static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second);
float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]);
@@ -2143,7 +2143,7 @@ static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode
BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH);
}
-void exec_retargetArctoArc(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
RetargetParam *p = (RetargetParam *)taskdata;
RigGraph *rigg = p->rigg;
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index e4c3f73dd94..87d75aa8fad 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -982,7 +982,7 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
mvalf[0] = dd->mval[0];
mvalf[1] = dd->mval[1];
- peelObjectsContext(C, &sketch->depth_peels, mvalf, SNAP_ALL);
+ peelObjectsContext(C, mvalf, SNAP_ALL, &sketch->depth_peels);
if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) {
last_p = stk->points[stk->nb_points - 1].p;
@@ -1086,7 +1086,9 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S
mval[1] = dd->mval[1];
/* try to snap to closer object */
- found = snapObjectsContext(C, mval, &dist_px, vec, no, SNAP_NOT_SELECTED);
+ found = snapObjectsContext(
+ C, mval, SNAP_NOT_SELECTED,
+ vec, no, &dist_px);
if (found == 1) {
pt->type = dd->type;
pt->mode = PT_SNAP;
@@ -1779,14 +1781,13 @@ int sk_detectMergeGesture(bContext *C, SK_Gesture *gest, SK_Sketch *UNUSED(sketc
{
ARegion *ar = CTX_wm_region(C);
if (gest->nb_segments > 2 && gest->nb_intersections == 2) {
- short start_val[2], end_val[2];
- short dist;
+ int start_val[2], end_val[2];
+ int dist;
- if ((ED_view3d_project_short_global(ar, gest->stk->points[0].p, start_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
- (ED_view3d_project_short_global(ar, sk_lastStrokePoint(gest->stk)->p, end_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
+ if ((ED_view3d_project_int_global(ar, gest->stk->points[0].p, start_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) &&
+ (ED_view3d_project_int_global(ar, sk_lastStrokePoint(gest->stk)->p, end_val, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK))
{
-
- dist = MAX2(ABS(start_val[0] - end_val[0]), ABS(start_val[1] - end_val[1]));
+ dist = len_manhattan_v2v2_int(start_val, end_val);
/* if gesture is a circle */
if (dist <= 20) {
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index b8dc4e1e7ab..9500fd59b8b 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -43,18 +43,12 @@
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#ifdef RIGID_DEFORM
-#include "BLI_polardecomp.h"
-#endif
-
#include "ED_mesh.h"
#include "ED_armature.h"
-#include "meshlaplacian.h"
-
-#ifdef WITH_OPENNL
+#include "eigen_capi.h"
-#include "ONL_opennl.h"
+#include "meshlaplacian.h"
/* ************* XXX *************** */
static void waitcursor(int UNUSED(val)) {}
@@ -68,7 +62,7 @@ static void error(const char *str) { printf("error: %s\n", str); }
/************************** Laplacian System *****************************/
struct LaplacianSystem {
- NLContext context; /* opennl context */
+ LinearSolver *context; /* linear solver */
int totvert, totface;
@@ -80,7 +74,7 @@ struct LaplacianSystem {
int areaweights; /* use area in cotangent weights? */
int storeweights; /* store cotangent weights in fweights */
- int nlbegun; /* nlBegin(NL_SYSTEM/NL_MATRIX) done */
+ bool variablesdone; /* variables set in linear system */
EdgeHash *edgehash; /* edge hash for construction */
@@ -104,17 +98,6 @@ struct LaplacianSystem {
BVHTree *bvhtree; /* ray tracing acceleration structure */
const MLoopTri **vltree; /* a looptri that the vertex belongs to */
} heat;
-
-#ifdef RIGID_DEFORM
- struct RigidDeformation {
- EditMesh *mesh;
-
- float (*R)[3][3];
- float (*rhs)[3];
- float (*origco)[3];
- int thrownerror;
- } rigid;
-#endif
};
/* Laplacian matrix construction */
@@ -197,18 +180,18 @@ static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int
t2 = cotangent_tri_weight_v3(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1);
t3 = cotangent_tri_weight_v3(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2);
- nlMatrixAdd(i1, i1, (t2 + t3) * varea[i1]);
- nlMatrixAdd(i2, i2, (t1 + t3) * varea[i2]);
- nlMatrixAdd(i3, i3, (t1 + t2) * varea[i3]);
+ EIG_linear_solver_matrix_add(sys->context, i1, i1, (t2 + t3) * varea[i1]);
+ EIG_linear_solver_matrix_add(sys->context, i2, i2, (t1 + t3) * varea[i2]);
+ EIG_linear_solver_matrix_add(sys->context, i3, i3, (t1 + t2) * varea[i3]);
- nlMatrixAdd(i1, i2, -t3 * varea[i1]);
- nlMatrixAdd(i2, i1, -t3 * varea[i2]);
+ EIG_linear_solver_matrix_add(sys->context, i1, i2, -t3 * varea[i1]);
+ EIG_linear_solver_matrix_add(sys->context, i2, i1, -t3 * varea[i2]);
- nlMatrixAdd(i2, i3, -t1 * varea[i2]);
- nlMatrixAdd(i3, i2, -t1 * varea[i3]);
+ EIG_linear_solver_matrix_add(sys->context, i2, i3, -t1 * varea[i2]);
+ EIG_linear_solver_matrix_add(sys->context, i3, i2, -t1 * varea[i3]);
- nlMatrixAdd(i3, i1, -t2 * varea[i3]);
- nlMatrixAdd(i1, i3, -t2 * varea[i1]);
+ EIG_linear_solver_matrix_add(sys->context, i3, i1, -t2 * varea[i3]);
+ EIG_linear_solver_matrix_add(sys->context, i1, i3, -t2 * varea[i1]);
if (sys->storeweights) {
sys->fweights[f][0] = t1 * varea[i1];
@@ -233,13 +216,11 @@ static LaplacianSystem *laplacian_system_construct_begin(int totvert, int totfac
sys->areaweights = 1;
sys->storeweights = 0;
- /* create opennl context */
- nlNewContext();
- nlSolverParameteri(NL_NB_VARIABLES, totvert);
+ /* create linear solver */
if (lsq)
- nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
-
- sys->context = nlGetCurrent();
+ sys->context = EIG_linear_least_squares_solver_new(0, totvert, 1);
+ else
+ sys->context = EIG_linear_solver_new(0, totvert, 1);
return sys;
}
@@ -289,7 +270,7 @@ static void laplacian_system_construct_end(LaplacianSystem *sys)
/* for heat weighting */
if (sys->heat.H)
- nlMatrixAdd(a, a, sys->heat.H[a]);
+ EIG_linear_solver_matrix_add(sys->context, a, a, sys->heat.H[a]);
}
if (sys->storeweights)
@@ -318,7 +299,7 @@ static void laplacian_system_delete(LaplacianSystem *sys)
if (sys->faces) MEM_freeN(sys->faces);
if (sys->fweights) MEM_freeN(sys->fweights);
- nlDeleteContext(sys->context);
+ EIG_linear_solver_delete(sys->context);
MEM_freeN(sys);
}
@@ -326,42 +307,37 @@ void laplacian_begin_solve(LaplacianSystem *sys, int index)
{
int a;
- if (!sys->nlbegun) {
- nlBegin(NL_SYSTEM);
-
+ if (!sys->variablesdone) {
if (index >= 0) {
for (a = 0; a < sys->totvert; a++) {
if (sys->vpinned[a]) {
- nlSetVariable(0, a, sys->verts[a][index]);
- nlLockVariable(a);
+ EIG_linear_solver_variable_set(sys->context, 0, a, sys->verts[a][index]);
+ EIG_linear_solver_variable_lock(sys->context, a);
}
}
}
- nlBegin(NL_MATRIX);
- sys->nlbegun = 1;
+ sys->variablesdone = true;
}
}
-void laplacian_add_right_hand_side(LaplacianSystem *UNUSED(sys), int v, float value)
+void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value)
{
- nlRightHandSideAdd(0, v, value);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, v, value);
}
int laplacian_system_solve(LaplacianSystem *sys)
{
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
- sys->nlbegun = 0;
+ sys->variablesdone = false;
- //nlPrintMatrix();
+ //EIG_linear_solver_print_matrix(sys->context, );
- return nlSolveAdvanced(NULL, NL_TRUE);
+ return EIG_linear_solver_solve(sys->context);
}
-float laplacian_system_get_solution(int v)
+float laplacian_system_get_solution(LaplacianSystem *sys, int v)
{
- return nlGetVariable(0, v);
+ return EIG_linear_solver_variable_get(sys->context, 0, v);
}
/************************* Heat Bone Weighting ******************************/
@@ -463,11 +439,7 @@ static int heat_ray_source_visible(LaplacianSystem *sys, int vertex, int source)
data.sys = sys;
copy_v3_v3(data.start, sys->heat.verts[vertex]);
- if (sys->heat.root) /* bone */
- closest_to_line_segment_v3(end, data.start,
- sys->heat.root[source], sys->heat.tip[source]);
- else /* vertex */
- copy_v3_v3(end, sys->heat.source[source]);
+ closest_to_line_segment_v3(end, data.start, sys->heat.root[source], sys->heat.tip[source]);
sub_v3_v3v3(data.vec, end, data.start);
madd_v3_v3v3fl(data.start, data.start, data.vec, 1e-5);
@@ -487,11 +459,7 @@ static float heat_source_distance(LaplacianSystem *sys, int vertex, int source)
float closest[3], d[3], dist, cosine;
/* compute euclidian distance */
- if (sys->heat.root) /* bone */
- closest_to_line_segment_v3(closest, sys->heat.verts[vertex],
- sys->heat.root[source], sys->heat.tip[source]);
- else /* vertex */
- copy_v3_v3(closest, sys->heat.source[source]);
+ closest_to_line_segment_v3(closest, sys->heat.verts[vertex], sys->heat.root[source], sys->heat.tip[source]);
sub_v3_v3v3(d, sys->heat.verts[vertex], closest);
dist = normalize_v3(d);
@@ -608,7 +576,7 @@ static void heat_laplacian_create(LaplacianSystem *sys)
static void heat_system_free(LaplacianSystem *sys)
{
BLI_bvhtree_free(sys->heat.bvhtree);
- MEM_freeN(sys->heat.vltree);
+ MEM_freeN((void *)sys->heat.vltree);
MEM_freeN((void *)sys->heat.mlooptri);
MEM_freeN(sys->heat.mindist);
@@ -707,7 +675,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
if (dgroupflip) {
vertsflipped = MEM_callocN(sizeof(int) * me->totvert, "vertsflipped");
for (a = 0; a < me->totvert; a++)
- vertsflipped[a] = mesh_get_x_mirror_vert(ob, a, use_topology);
+ vertsflipped[a] = mesh_get_x_mirror_vert(ob, NULL, a, use_topology);
}
/* compute weights per bone */
@@ -746,7 +714,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
if (mask && !mask[a])
continue;
- solution = laplacian_system_get_solution(a);
+ solution = laplacian_system_get_solution(sys, a);
if (bbone) {
if (solution > 0.0f)
@@ -815,232 +783,6 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
laplacian_system_delete(sys);
}
-#ifdef RIGID_DEFORM
-/********************** As-Rigid-As-Possible Deformation ******************/
-/* From "As-Rigid-As-Possible Surface Modeling",
- * Olga Sorkine and Marc Alexa, ESGP 2007. */
-
-/* investigate:
- * - transpose R in orthogonal
- * - flipped normals and per face adding
- * - move canceling to transform, make origco pointer
- */
-
-static LaplacianSystem *RigidDeformSystem = NULL;
-
-static void rigid_add_half_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
-{
- float e[3], e_[3];
- int i;
-
- sub_v3_v3v3(e, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
- sub_v3_v3v3(e_, v1->co, v2->co);
-
- /* formula (5) */
- for (i = 0; i < 3; i++) {
- sys->rigid.R[v1->tmp.l][i][0] += w * e[0] * e_[i];
- sys->rigid.R[v1->tmp.l][i][1] += w * e[1] * e_[i];
- sys->rigid.R[v1->tmp.l][i][2] += w * e[2] * e_[i];
- }
-}
-
-static void rigid_add_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
-{
- rigid_add_half_edge_to_R(sys, v1, v2, w);
- rigid_add_half_edge_to_R(sys, v2, v1, w);
-}
-
-static void rigid_orthogonalize_R(float R[3][3])
-{
- HMatrix M, Q, S;
-
- copy_m4_m3(M, R);
- polar_decomp(M, Q, S);
- copy_m3_m4(R, Q);
-}
-
-static void rigid_add_half_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
-{
- /* formula (8) */
- float Rsum[3][3], rhs[3];
-
- if (sys->vpinned[v1->tmp.l])
- return;
-
- add_m3_m3m3(Rsum, sys->rigid.R[v1->tmp.l], sys->rigid.R[v2->tmp.l]);
- transpose_m3(Rsum);
-
- sub_v3_v3v3(rhs, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
- mul_m3_v3(Rsum, rhs);
- mul_v3_fl(rhs, 0.5f);
- mul_v3_fl(rhs, w);
-
- add_v3_v3(sys->rigid.rhs[v1->tmp.l], rhs);
-}
-
-static void rigid_add_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
-{
- rigid_add_half_edge_to_rhs(sys, v1, v2, w);
- rigid_add_half_edge_to_rhs(sys, v2, v1, w);
-}
-
-void rigid_deform_iteration()
-{
- LaplacianSystem *sys = RigidDeformSystem;
- EditMesh *em;
- EditVert *eve;
- EditFace *efa;
- int a, i;
-
- if (!sys)
- return;
-
- nlMakeCurrent(sys->context);
- em = sys->rigid.mesh;
-
- /* compute R */
- memset(sys->rigid.R, 0, sizeof(float) * 3 * 3 * sys->totvert);
- memset(sys->rigid.rhs, 0, sizeof(float) * 3 * sys->totvert);
-
- for (a = 0, efa = em->faces.first; efa; efa = efa->next, a++) {
- rigid_add_edge_to_R(sys, efa->v1, efa->v2, sys->fweights[a][2]);
- rigid_add_edge_to_R(sys, efa->v2, efa->v3, sys->fweights[a][0]);
- rigid_add_edge_to_R(sys, efa->v3, efa->v1, sys->fweights[a][1]);
-
- if (efa->v4) {
- a++;
- rigid_add_edge_to_R(sys, efa->v1, efa->v3, sys->fweights[a][2]);
- rigid_add_edge_to_R(sys, efa->v3, efa->v4, sys->fweights[a][0]);
- rigid_add_edge_to_R(sys, efa->v4, efa->v1, sys->fweights[a][1]);
- }
- }
-
- for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++) {
- rigid_orthogonalize_R(sys->rigid.R[a]);
- eve->tmp.l = a;
- }
-
- /* compute right hand sides for solving */
- for (a = 0, efa = em->faces.first; efa; efa = efa->next, a++) {
- rigid_add_edge_to_rhs(sys, efa->v1, efa->v2, sys->fweights[a][2]);
- rigid_add_edge_to_rhs(sys, efa->v2, efa->v3, sys->fweights[a][0]);
- rigid_add_edge_to_rhs(sys, efa->v3, efa->v1, sys->fweights[a][1]);
-
- if (efa->v4) {
- a++;
- rigid_add_edge_to_rhs(sys, efa->v1, efa->v3, sys->fweights[a][2]);
- rigid_add_edge_to_rhs(sys, efa->v3, efa->v4, sys->fweights[a][0]);
- rigid_add_edge_to_rhs(sys, efa->v4, efa->v1, sys->fweights[a][1]);
- }
- }
-
- /* solve for positions, for X, Y and Z separately */
- for (i = 0; i < 3; i++) {
- laplacian_begin_solve(sys, i);
-
- for (a = 0; a < sys->totvert; a++)
- if (!sys->vpinned[a])
- laplacian_add_right_hand_side(sys, a, sys->rigid.rhs[a][i]);
-
- if (laplacian_system_solve(sys)) {
- for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++)
- eve->co[i] = laplacian_system_get_solution(a);
- }
- else {
- if (!sys->rigid.thrownerror) {
- error("RigidDeform: failed to find solution");
- sys->rigid.thrownerror = 1;
- }
- break;
- }
- }
-}
-
-static void rigid_laplacian_create(LaplacianSystem *sys)
-{
- EditMesh *em = sys->rigid.mesh;
- EditVert *eve;
- EditFace *efa;
- int a;
-
- /* add verts and faces to laplacian */
- for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++) {
- laplacian_add_vertex(sys, eve->co, eve->pinned);
- eve->tmp.l = a;
- }
-
- for (efa = em->faces.first; efa; efa = efa->next) {
- laplacian_add_triangle(sys,
- efa->v1->tmp.l, efa->v2->tmp.l, efa->v3->tmp.l);
- if (efa->v4)
- laplacian_add_triangle(sys,
- efa->v1->tmp.l, efa->v3->tmp.l, efa->v4->tmp.l);
- }
-}
-
-void rigid_deform_begin(EditMesh *em)
-{
- LaplacianSystem *sys;
- EditVert *eve;
- EditFace *efa;
- int a, totvert, totface;
-
- /* count vertices, triangles */
- for (totvert = 0, eve = em->verts.first; eve; eve = eve->next)
- totvert++;
-
- for (totface = 0, efa = em->faces.first; efa; efa = efa->next) {
- totface++;
- if (efa->v4) totface++;
- }
-
- /* create laplacian */
- sys = laplacian_system_construct_begin(totvert, totface, 0);
-
- sys->rigid.mesh = em;
- sys->rigid.R = MEM_callocN(sizeof(float) * 3 * 3 * totvert, "RigidDeformR");
- sys->rigid.rhs = MEM_callocN(sizeof(float) * 3 * totvert, "RigidDeformRHS");
- sys->rigid.origco = MEM_callocN(sizeof(float) * 3 * totvert, "RigidDeformCo");
-
- for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++)
- copy_v3_v3(sys->rigid.origco[a], eve->co);
-
- sys->areaweights = 0;
- sys->storeweights = 1;
-
- rigid_laplacian_create(sys);
-
- laplacian_system_construct_end(sys);
-
- RigidDeformSystem = sys;
-}
-
-void rigid_deform_end(int cancel)
-{
- LaplacianSystem *sys = RigidDeformSystem;
-
- if (sys) {
- EditMesh *em = sys->rigid.mesh;
- EditVert *eve;
- int a;
-
- if (cancel)
- for (a = 0, eve = em->verts.first; eve; eve = eve->next, a++)
- if (!eve->pinned)
- copy_v3_v3(eve->co, sys->rigid.origco[a]);
-
- if (sys->rigid.R) MEM_freeN(sys->rigid.R);
- if (sys->rigid.rhs) MEM_freeN(sys->rigid.rhs);
- if (sys->rigid.origco) MEM_freeN(sys->rigid.origco);
-
- /* free */
- laplacian_system_delete(sys);
- }
-
- RigidDeformSystem = NULL;
-}
-#endif
-
/************************** Harmonic Coordinates ****************************/
/* From "Harmonic Coordinates for Character Articulation",
* Pushkar Joshi, Mark Meyer, Tony DeRose, Brian Green and Tom Sanocki,
@@ -1251,7 +993,6 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const
&isect_mdef,
};
float end[3], vec_normal[3];
- // static float epsilon[3] = {1e-4, 1e-4, 1e-4};
/* happens binding when a cage has no faces */
if (UNLIKELY(mdb->bvhtree == NULL))
@@ -1261,18 +1002,13 @@ static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const
memset(&isect_mdef, 0, sizeof(isect_mdef));
isect_mdef.lambda = 1e10f;
-#if 0
- add_v3_v3v3(isect_mdef.start, co1, epsilon);
- add_v3_v3v3(end, co2, epsilon);
-#else
copy_v3_v3(isect_mdef.start, co1);
copy_v3_v3(end, co2);
-#endif
sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);
hit.index = -1;
- hit.dist = FLT_MAX;
+ hit.dist = BVH_RAYCAST_DIST_MAX;
if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, vec_normal,
0.0, &hit, harmonic_ray_callback, &data) != -1)
{
@@ -1541,7 +1277,7 @@ static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y,
return totweight;
}
-static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z)
+static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z)
{
MDefBoundIsect *isect;
float weight, totweight;
@@ -1551,7 +1287,7 @@ static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z)
if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
return;
- nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
+ EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
for (i = 1; i <= 6; i++) {
@@ -1562,12 +1298,12 @@ static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z)
isect = mdb->boundisect[acenter][i - 1];
if (!isect) {
weight = (1.0f / mdb->width[0]) / totweight;
- nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[a], -weight);
+ EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[a], -weight);
}
}
}
-static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
+static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z, int cagevert)
{
MDefBoundIsect *isect;
float rhs, weight, totweight;
@@ -1588,7 +1324,7 @@ static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z,
if (isect) {
weight = (1.0f / isect->len) / totweight;
rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert);
- nlRightHandSideAdd(0, mdb->varidx[acenter], rhs);
+ EIG_linear_solver_right_hand_side_add(context, 0, mdb->varidx[acenter], rhs);
}
}
}
@@ -1643,7 +1379,7 @@ static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y
static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb)
{
- NLContext *context;
+ LinearSolver *context;
float vec[3], gridvec[3];
int a, b, x, y, z, totvar;
char message[256];
@@ -1660,44 +1396,24 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
progress_bar(0, "Starting mesh deform solve");
- /* setup opennl solver */
- nlNewContext();
- context = nlGetCurrent();
-
- nlSolverParameteri(NL_NB_VARIABLES, totvar);
- nlSolverParameteri(NL_NB_ROWS, totvar);
- nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 1);
-
- nlBegin(NL_SYSTEM);
- nlBegin(NL_MATRIX);
+ /* setup linear solver */
+ context = EIG_linear_solver_new(totvar, totvar, 1);
/* build matrix */
for (z = 0; z < mdb->size; z++)
for (y = 0; y < mdb->size; y++)
for (x = 0; x < mdb->size; x++)
- meshdeform_matrix_add_cell(mdb, x, y, z);
+ meshdeform_matrix_add_cell(mdb, context, x, y, z);
/* solve for each cage vert */
for (a = 0; a < mdb->totcagevert; a++) {
- if (a != 0) {
- nlBegin(NL_SYSTEM);
- nlBegin(NL_MATRIX);
- }
-
/* fill in right hand side and solve */
for (z = 0; z < mdb->size; z++)
for (y = 0; y < mdb->size; y++)
for (x = 0; x < mdb->size; x++)
- meshdeform_matrix_add_rhs(mdb, x, y, z, a);
-
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
-
-#if 0
- nlPrintMatrix();
-#endif
+ meshdeform_matrix_add_rhs(mdb, context, x, y, z, a);
- if (nlSolveAdvanced(NULL, NL_TRUE)) {
+ if (EIG_linear_solver_solve(context)) {
for (z = 0; z < mdb->size; z++)
for (y = 0; y < mdb->size; y++)
for (x = 0; x < mdb->size; x++)
@@ -1710,7 +1426,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
for (b = 0; b < mdb->size3; b++) {
if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
- mdb->phi[b] = nlGetVariable(0, mdb->varidx[b]);
+ mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]);
mdb->totalphi[b] += mdb->phi[b];
}
@@ -1764,7 +1480,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
/* free */
MEM_freeN(mdb->varidx);
- nlDeleteContext(context);
+ EIG_linear_solver_delete(context);
}
static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb)
@@ -1917,77 +1633,9 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa
free_bvhtree_from_mesh(&mdb->bvhdata);
}
-#if 0
-static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb)
-{
- LaplacianSystem *sys;
- MFace *mface = dm->getTessFaceArray(dm), *mf;
- int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumTessFaces(dm);
- float solution, weight;
- int a, tottri, j, thrownerror = 0;
-
- mdb->weights = MEM_callocN(sizeof(float) * mdb->totvert * mdb->totcagevert, "MDefWeights");
-
- /* count triangles */
- for (tottri = 0, a = 0, mf = mface; a < totface; a++, mf++) {
- tottri++;
- if (mf->v4) tottri++;
- }
-
- /* create laplacian */
- sys = laplacian_system_construct_begin(totvert, tottri, 1);
-
- sys->heat.mface = mface;
- sys->heat.totface = totface;
- sys->heat.totvert = totvert;
- sys->heat.verts = mdb->vertexcos;
- sys->heat.source = mdb->cagecos;
- sys->heat.numsource = mdb->totcagevert;
-
- heat_ray_tree_create(sys);
- heat_laplacian_create(sys);
-
- laplacian_system_construct_end(sys);
-
- /* compute weights per bone */
- for (j = 0; j < mdb->totcagevert; j++) {
- /* fill right hand side */
- laplacian_begin_solve(sys, -1);
-
- for (a = 0; a < totvert; a++)
- if (heat_source_closest(sys, a, j))
- laplacian_add_right_hand_side(sys, a,
- sys->heat.H[a] * sys->heat.p[a]);
-
- /* solve */
- if (laplacian_system_solve(sys)) {
- /* load solution into vertex groups */
- for (a = 0; a < totvert; a++) {
- solution = laplacian_system_get_solution(a);
-
- weight = heat_limit_weight(solution);
- if (weight > 0.0f)
- mdb->weights[a * mdb->totcagevert + j] = weight;
- }
- }
- else if (!thrownerror) {
- error("Mesh Deform Heat Weighting:"
- " failed to find solution for one or more vertices");
- thrownerror = 1;
- break;
- }
- }
-
- /* free */
- heat_system_free(sys);
- laplacian_system_delete(sys);
-
- mmd->bindweights = mdb->weights;
-}
-#endif
-
-void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[4][4])
+void mesh_deform_bind(
+ Scene *scene, MeshDeformModifierData *mmd, DerivedMesh *cagedm,
+ float *vertexcos, int totvert, float cagemat[4][4])
{
MeshDeformBind mdb;
MVert *mvert;
@@ -2002,7 +1650,7 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco
mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos");
mdb.totvert = totvert;
- mdb.cagedm = mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH);
+ mdb.cagedm = cagedm;
mdb.totcagevert = mdb.cagedm->getNumVerts(mdb.cagedm);
mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos");
copy_m4_m4(mdb.cagemat, cagemat);
@@ -2014,14 +1662,7 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco
mul_v3_m4v3(mdb.vertexcos[a], mdb.cagemat, vertexcos + a * 3);
/* solve */
-#if 0
- if (mmd->mode == MOD_MDEF_VOLUME)
- harmonic_coordinates_bind(scene, mmd, &mdb);
- else
- heat_weighting_bind(scene, dm, mmd, &mdb);
-#else
harmonic_coordinates_bind(scene, mmd, &mdb);
-#endif
/* assign bind variables */
mmd->bindcagecos = (float *)mdb.cagecos;
@@ -2034,7 +1675,6 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco
mul_m4_v3(mmd->object->obmat, mmd->bindcagecos + a * 3);
/* free */
- mdb.cagedm->release(mdb.cagedm);
MEM_freeN(mdb.vertexcos);
/* compact weights */
@@ -2043,14 +1683,3 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco
end_progress_bar();
waitcursor(0);
}
-
-#else /* WITH_OPENNL */
-
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wunused-parameter"
-#endif
-
-void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[4][4]) {}
-void *modifier_mdef_compact_influences_link_kludge = modifier_mdef_compact_influences;
-
-#endif /* WITH_OPENNL */
diff --git a/source/blender/editors/armature/meshlaplacian.h b/source/blender/editors/armature/meshlaplacian.h
index 1412136c1a8..bba8c739abf 100644
--- a/source/blender/editors/armature/meshlaplacian.h
+++ b/source/blender/editors/armature/meshlaplacian.h
@@ -48,7 +48,7 @@ void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3);
void laplacian_begin_solve(LaplacianSystem *sys, int index);
void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value);
int laplacian_system_solve(LaplacianSystem *sys);
-float laplacian_system_get_solution(int v);
+float laplacian_system_get_solution(LaplacianSystem *sys, int v);
/* Heat Weighting */
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index e87c324d7ec..a929507929f 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -255,13 +255,23 @@ void POSE_OT_paths_calculate(wmOperatorType *ot)
RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End",
"Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
- RNA_def_enum(ot->srna, "bake_location", motionpath_bake_location_items, 0,
+ RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items, 0,
"Bake Location",
"Which point on the bones is used when calculating paths");
}
/* --------- */
+static int pose_update_paths_poll(bContext *C)
+{
+ if (ED_operator_posemode_exclusive(C)) {
+ bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ return (pchan && pchan->mpath);
+ }
+
+ return false;
+}
+
static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
@@ -289,7 +299,7 @@ void POSE_OT_paths_update(wmOperatorType *ot)
/* api callbakcs */
ot->exec = pose_update_paths_exec;
- ot->poll = ED_operator_posemode_exclusive; /* TODO: this should probably check for active bone and/or existing paths */
+ ot->poll = pose_update_paths_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -298,42 +308,44 @@ void POSE_OT_paths_update(wmOperatorType *ot)
/* --------- */
/* for the object with pose/action: clear path curves for selected bones only */
-static void ED_pose_clear_paths(Object *ob)
+static void ED_pose_clear_paths(Object *ob, bool only_selected)
{
bPoseChannel *pchan;
- short skipped = 0;
+ bool skipped = false;
if (ELEM(NULL, ob, ob->pose))
return;
- /* free the motionpath blocks, but also take note of whether we skipped some... */
+ /* free the motionpath blocks for all bones - This is easier for users to quickly clear all */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->mpath) {
- if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
+ if ((only_selected == false) || ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))) {
animviz_free_motionpath(pchan->mpath);
pchan->mpath = NULL;
}
- else
- skipped = 1;
+ else {
+ skipped = true;
+ }
}
}
- /* if we didn't skip any, we shouldn't have any paths left */
- if (skipped == 0)
+ /* if nothing was skipped, there should be no paths left! */
+ if (skipped == false)
ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
}
-/* operator callback for this */
-static int pose_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
+/* operator callback - wrapper for the backend function */
+static int pose_clear_paths_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
+ bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
+
/* only continue if there's an object */
if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
/* use the backend function for this */
- ED_pose_clear_paths(ob);
+ ED_pose_clear_paths(ob, only_selected);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -341,19 +353,34 @@ static int pose_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+/* operator callback/wrapper */
+static int pose_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+{
+ if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
+ RNA_boolean_set(op->ptr, "only_selected", true);
+ }
+ return pose_clear_paths_exec(C, op);
+}
+
void POSE_OT_paths_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Bone Paths";
ot->idname = "POSE_OT_paths_clear";
- ot->description = "Clear path caches for selected bones";
+ ot->description = "Clear path caches for all bones, hold Shift key for selected bones only";
/* api callbacks */
+ ot->invoke = pose_clear_paths_invoke;
ot->exec = pose_clear_paths_exec;
ot->poll = ED_operator_posemode_exclusive;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected",
+ "Only clear paths from selected bones");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
/* ********************************************** */
@@ -700,7 +727,7 @@ void POSE_OT_rotation_mode_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_posebone_rotmode_items, 0, "Rotation Mode", "");
}
/* ********************************************** */
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 40328e0c06e..16ba1483e38 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -655,6 +655,15 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
return OPERATOR_RUNNING_MODAL;
}
+/* calculate percentage based on position of mouse (we only use x-axis for now.
+ * since this is more convenient for users to do), and store new percentage value
+ */
+static void pose_slide_mouse_update_percentage(tPoseSlideOp *pso, wmOperator *op, const wmEvent *event)
+{
+ pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
+ RNA_float_set(op->ptr, "percentage", pso->percentage);
+}
+
/* common code for modal() */
static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -702,11 +711,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
/* only handle mousemove if not doing numinput */
if (has_numinput == false) {
- /* calculate percentage based on position of mouse (we only use x-axis for now.
- * since this is more convenient for users to do), and store new percentage value
- */
- pso->percentage = (event->x - pso->ar->winrct.xmin) / ((float)pso->ar->winx);
- RNA_float_set(op->ptr, "percentage", pso->percentage);
+ /* update percentage based on position of mouse */
+ pose_slide_mouse_update_percentage(pso, op, event);
/* update percentage indicator in header */
pose_slide_draw_status(pso);
@@ -787,7 +793,7 @@ static void pose_slide_opdef_properties(wmOperatorType *ot)
/* ------------------------------------ */
/* invoke() - for 'push' mode */
-static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
@@ -798,6 +804,9 @@ static int pose_slide_push_invoke(bContext *C, wmOperator *op, const wmEvent *UN
}
else
pso = op->customdata;
+
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
/* do common setup work */
return pose_slide_invoke_common(C, op, pso);
@@ -844,7 +853,7 @@ void POSE_OT_push(wmOperatorType *ot)
/* ........................ */
/* invoke() - for 'relax' mode */
-static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
@@ -856,6 +865,9 @@ static int pose_slide_relax_invoke(bContext *C, wmOperator *op, const wmEvent *U
else
pso = op->customdata;
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
+
/* do common setup work */
return pose_slide_invoke_common(C, op, pso);
}
@@ -901,7 +913,7 @@ void POSE_OT_relax(wmOperatorType *ot)
/* ........................ */
/* invoke() - for 'breakdown' mode */
-static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
tPoseSlideOp *pso;
@@ -913,6 +925,9 @@ static int pose_slide_breakdown_invoke(bContext *C, wmOperator *op, const wmEven
else
pso = op->customdata;
+ /* initialise percentage so that it won't pop on first mouse move */
+ pose_slide_mouse_update_percentage(pso, op, event);
+
/* do common setup work */
return pose_slide_invoke_common(C, op, pso);
}
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index f29d15ff416..661a8e1de9f 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -2497,7 +2497,7 @@ int weightFromLoc(EditMesh *em, int axis)
return 1;
}
-static void addTriangle(EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3)
+static void addTriangle(LinearSolver *context, EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3)
{
/* Angle opposite e1 */
float t1 = cotangent_tri_weight_v3(v1->co, v2->co, v3->co) / e2;
@@ -2512,22 +2512,23 @@ static void addTriangle(EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2
int i2 = indexData(v2);
int i3 = indexData(v3);
- nlMatrixAdd(i1, i1, t2 + t3);
- nlMatrixAdd(i2, i2, t1 + t3);
- nlMatrixAdd(i3, i3, t1 + t2);
+ EIG_linear_solver_matrix_add(context, i1, i1, t2 + t3);
+ EIG_linear_solver_matrix_add(context, i2, i2, t1 + t3);
+ EIG_linear_solver_matrix_add(context, i3, i3, t1 + t2);
- nlMatrixAdd(i1, i2, -t3);
- nlMatrixAdd(i2, i1, -t3);
+ EIG_linear_solver_matrix_add(context, i1, i2, -t3);
+ EIG_linear_solver_matrix_add(context, i2, i1, -t3);
- nlMatrixAdd(i2, i3, -t1);
- nlMatrixAdd(i3, i2, -t1);
+ EIG_linear_solver_matrix_add(context, i2, i3, -t1);
+ EIG_linear_solver_matrix_add(context, i3, i2, -t1);
- nlMatrixAdd(i3, i1, -t2);
- nlMatrixAdd(i1, i3, -t2);
+ EIG_linear_solver_matrix_add(context, i3, i1, -t2);
+ EIG_linear_solver_matrix_add(context, i1, i3, -t2);
}
int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges)
{
+ LinearSolver *context;
NLboolean success;
EditVert *eve;
EditEdge *eed;
@@ -2541,14 +2542,10 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges)
totvert++;
}
- /* Solve with openNL */
+ /* Solve */
- nlNewContext();
+ context = EIG_linear_solver_new(, 0, totvert, 1);
- nlSolverParameteri(NL_NB_VARIABLES, totvert);
-
- nlBegin(NL_SYSTEM);
-
/* Find local extrema */
for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) {
if (eve->h == 0) {
@@ -2582,8 +2579,8 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges)
if (maximum || minimum) {
float w = weightData(eve);
eve->f1 = 0;
- nlSetVariable(0, index, w);
- nlLockVariable(index);
+ EIG_linear_solver_variable_set(context, 0, index, w);
+ EIG_linear_solver_variable_lock(context, index);
}
else {
eve->f1 = 1;
@@ -2591,8 +2588,6 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges)
}
}
- nlBegin(NL_MATRIX);
-
/* Zero edge weight */
for (eed = em->edges.first; eed; eed = eed->next) {
eed->tmp.l = 0;
@@ -2615,32 +2610,28 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges)
for (efa = em->faces.first; efa; efa = efa->next) {
if (efa->h == 0) {
if (efa->v4 == NULL) {
- addTriangle(efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, efa->e3->tmp.l);
+ addTriangle(context, efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, efa->e3->tmp.l);
}
else {
- addTriangle(efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, 2);
- addTriangle(efa->v3, efa->v4, efa->v1, efa->e3->tmp.l, efa->e4->tmp.l, 2);
+ addTriangle(context, efa->v1, efa->v2, efa->v3, efa->e1->tmp.l, efa->e2->tmp.l, 2);
+ addTriangle(context, efa->v3, efa->v4, efa->v1, efa->e3->tmp.l, efa->e4->tmp.l, 2);
}
}
}
- nlEnd(NL_MATRIX);
-
- nlEnd(NL_SYSTEM);
-
- success = nlSolveAdvanced(NULL, NL_TRUE);
+ success = EIG_linear_solver_solve(context);
if (success) {
rval = 1;
for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) {
- weightSetData(eve, nlGetVariable(0, index));
+ weightSetData(eve, EIG_linear_solver_variable_get(context, 0, index));
}
}
else {
rval = 0;
}
- nlDeleteContext(nlGetCurrent());
+ EIG_linear_solver_delete(context);
return rval;
}
@@ -3439,9 +3430,6 @@ void REEB_draw()
}
}
glEnable(GL_DEPTH_TEST);
-
- glLineWidth(1.0);
- glPointSize(1.0);
}
#endif
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 83346e9550c..ebdf6bb43ff 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -23,20 +23,24 @@ set(INC
../../blenkernel
../../blenlib
../../blentranslation
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
+ ../../../../extern/curve_fit_nd
)
set(INC_SYS
-
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
curve_ops.c
editcurve.c
editcurve_add.c
+ editcurve_paint.c
editcurve_select.c
editfont.c
@@ -47,4 +51,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_curve "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/curve/SConscript b/source/blender/editors/curve/SConscript
deleted file mode 100644
index eadec4f65b6..00000000000
--- a/source/blender/editors/curve/SConscript
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-
-incs = [
- '#/intern/guardedalloc',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_curve', sources, incs, defs, libtype=['core'], priority=[45])
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 29904bf2344..d63616e4f43 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -79,7 +79,6 @@ void FONT_OT_text_copy(struct wmOperatorType *ot);
void FONT_OT_text_cut(struct wmOperatorType *ot);
void FONT_OT_text_paste(struct wmOperatorType *ot);
void FONT_OT_text_paste_from_file(struct wmOperatorType *ot);
-void FONT_OT_text_paste_from_clipboard(struct wmOperatorType *ot);
void FONT_OT_move(struct wmOperatorType *ot);
void FONT_OT_move_select(struct wmOperatorType *ot);
@@ -134,7 +133,7 @@ bool ED_curve_pick_vert(
/* helper functions */
void ed_editnurb_translate_flag(struct ListBase *editnurb, short flag, const float vec[3]);
-bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, short flag);
+bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const short flag);
bool ed_editnurb_spin(float viewmat[4][4], struct Object *obedit, const float axis[3], const float cent[3]);
/* editcurve_select.c */
@@ -167,4 +166,7 @@ void SURFACE_OT_primitive_nurbs_surface_cylinder_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot);
+/* editcurve_paint.c */
+void CURVE_OT_draw(struct wmOperatorType *ot);
+
#endif /* __CURVE_INTERN_H__ */
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 4828fb3ec5f..d1994c8fc15 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -66,7 +66,6 @@ void ED_operatortypes_curve(void)
WM_operatortype_append(FONT_OT_text_cut);
WM_operatortype_append(FONT_OT_text_paste);
WM_operatortype_append(FONT_OT_text_paste_from_file);
- WM_operatortype_append(FONT_OT_text_paste_from_clipboard);
WM_operatortype_append(FONT_OT_move);
WM_operatortype_append(FONT_OT_move_select);
@@ -136,6 +135,7 @@ void ED_operatortypes_curve(void)
WM_operatortype_append(CURVE_OT_make_segment);
WM_operatortype_append(CURVE_OT_spin);
WM_operatortype_append(CURVE_OT_vertex_add);
+ WM_operatortype_append(CURVE_OT_draw);
WM_operatortype_append(CURVE_OT_extrude);
WM_operatortype_append(CURVE_OT_cyclic_toggle);
@@ -214,6 +214,7 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "FONT_OT_text_cut", XKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "FONT_OT_text_paste", VKEY, KM_PRESS, KM_CTRL, 0);
#ifdef __APPLE__
+ WM_keymap_add_item(keymap, "FONT_OT_select_all", AKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "FONT_OT_text_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "FONT_OT_text_cut", XKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "FONT_OT_text_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
@@ -234,6 +235,9 @@ void ED_keymap_curve(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "CURVE_OT_vertex_add", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "CURVE_OT_draw", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", AKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
kmi = WM_keymap_add_item(keymap, "CURVE_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index f7dab0c0935..9df611b3216 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -49,6 +49,7 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_key.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_animsys.h"
@@ -1177,7 +1178,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit)
}
/* load editNurb in object */
-void load_editNurb(Object *obedit)
+void ED_curve_editnurb_load(Object *obedit)
{
ListBase *editnurb = object_editcurve_get(obedit);
@@ -1209,7 +1210,7 @@ void load_editNurb(Object *obedit)
}
/* make copy in cu->editnurb */
-void make_editNurb(Object *obedit)
+void ED_curve_editnurb_make(Object *obedit)
{
Curve *cu = (Curve *)obedit->data;
EditNurb *editnurb = cu->editnurb;
@@ -1252,7 +1253,7 @@ void make_editNurb(Object *obedit)
}
}
-void free_editNurb(Object *obedit)
+void ED_curve_editnurb_free(Object *obedit)
{
Curve *cu = obedit->data;
@@ -1298,10 +1299,10 @@ static int separate_exec(bContext *C, wmOperator *op)
newob = newbase->object;
newcu = newob->data = BKE_curve_copy(oldcu);
newcu->editnurb = NULL;
- oldcu->id.us--; /* because new curve is a copy: reduce user count */
+ id_us_min(&oldcu->id); /* because new curve is a copy: reduce user count */
/* 3. put new object in editmode, clear it and set separated nurbs */
- make_editNurb(newob);
+ ED_curve_editnurb_make(newob);
newedit = newcu->editnurb;
BKE_nurbList_free(&newedit->nurbs);
BKE_curve_editNurb_keyIndex_free(newedit);
@@ -1309,8 +1310,8 @@ static int separate_exec(bContext *C, wmOperator *op)
BLI_movelisttolist(&newedit->nurbs, &newnurb);
/* 4. put old object out of editmode and delete separated geometry */
- load_editNurb(newob);
- free_editNurb(newob);
+ ED_curve_editnurb_load(newob);
+ ED_curve_editnurb_free(newob);
curve_delete_segments(oldob, true);
DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
@@ -1351,7 +1352,11 @@ static int curve_split_exec(bContext *C, wmOperator *op)
adduplicateflagNurb(obedit, &newnurb, SELECT, true);
if (BLI_listbase_is_empty(&newnurb) == false) {
+ Curve *cu = obedit->data;
+ const int len_orig = BLI_listbase_count(editnurb);
+
curve_delete_segments(obedit, true);
+ cu->actnu -= len_orig - BLI_listbase_count(editnurb);
BLI_movelisttolist(editnurb, &newnurb);
if (ED_curve_updateAnimPaths(obedit->data))
@@ -1385,7 +1390,9 @@ void CURVE_OT_split(wmOperatorType *ot)
/* ******************* FLAGS ********************* */
-static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
+static bool isNurbselUV(
+ const Nurb *nu, int flag,
+ int *r_u, int *r_v)
{
/* return (u != -1): 1 row in u-direction selected. U has value between 0-pntsv
* return (v != -1): 1 column in v-direction selected. V has value between 0-pntsu
@@ -1393,7 +1400,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
BPoint *bp;
int a, b, sel;
- *u = *v = -1;
+ *r_u = *r_v = -1;
bp = nu->bp;
for (b = 0; b < nu->pntsv; b++) {
@@ -1402,7 +1409,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
if (bp->f1 & flag) sel++;
}
if (sel == nu->pntsu) {
- if (*u == -1) *u = b;
+ if (*r_u == -1) *r_u = b;
else return 0;
}
else if (sel > 1) {
@@ -1417,7 +1424,7 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
if (bp->f1 & flag) sel++;
}
if (sel == nu->pntsv) {
- if (*v == -1) *v = a;
+ if (*r_v == -1) *r_v = a;
else return 0;
}
else if (sel > 1) {
@@ -1425,8 +1432,8 @@ static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
}
}
- if (*u == -1 && *v > -1) return 1;
- if (*v == -1 && *u > -1) return 1;
+ if (*r_u == -1 && *r_v > -1) return 1;
+ if (*r_v == -1 && *r_u > -1) return 1;
return 0;
}
@@ -1846,7 +1853,7 @@ bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag)
else {
/* which row or column is selected */
- if (isNurbselUV(nu, &u, &v, flag)) {
+ if (isNurbselUV(nu, flag, &u, &v)) {
/* deselect all */
bp = nu->bp;
@@ -1918,18 +1925,30 @@ bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag)
return ok;
}
+static bool calc_duplicate_actvert(
+ const ListBase *editnurb, const ListBase *newnurb, Curve *cu,
+ int start, int end, int vert)
+{
+ if ((start <= cu->actvert) && (end > cu->actvert)) {
+ cu->actvert = vert;
+ cu->actnu = BLI_listbase_count(editnurb) + BLI_listbase_count(newnurb);
+ return true;
+ }
+ return false;
+}
+
static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
const short flag, const bool split)
{
ListBase *editnurb = object_editcurve_get(obedit);
- Nurb *nu = editnurb->last, *newnu;
+ Nurb *nu, *newnu;
BezTriple *bezt, *bezt1;
BPoint *bp, *bp1, *bp2, *bp3;
Curve *cu = (Curve *)obedit->data;
- int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv;
+ int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv, i;
char *usel;
- while (nu) {
+ for (i = 0, nu = editnurb->first; nu; i++, nu = nu->next) {
cyclicu = cyclicv = 0;
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
@@ -1950,12 +1969,21 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
else {
if (enda == nu->pntsu - 1) newu += cyclicu;
+ if (i == cu->actnu) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ starta, starta + diffa, cu->actvert - starta);
+ }
newnu = BKE_nurb_copy(nu, newu, 1);
- BLI_addtail(newnurb, newnu);
memcpy(newnu->bezt, &nu->bezt[starta], diffa * sizeof(BezTriple));
if (newu != diffa) {
memcpy(&newnu->bezt[diffa], nu->bezt, cyclicu * sizeof(BezTriple));
+ if (i == cu->actnu) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ 0, cyclicu, newu - cyclicu + cu->actvert);
+ }
cyclicu = 0;
}
@@ -1964,19 +1992,28 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
select_beztriple(bezt1, SELECT, flag, HIDDEN);
}
+
+ BLI_addtail(newnurb, newnu);
}
}
}
if (cyclicu != 0) {
+ if (i == cu->actnu) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ 0, cyclicu, cu->actvert);
+ }
+
newnu = BKE_nurb_copy(nu, cyclicu, 1);
- BLI_addtail(newnurb, newnu);
memcpy(newnu->bezt, nu->bezt, cyclicu * sizeof(BezTriple));
newnu->flagu &= ~CU_NURB_CYCLIC;
for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) {
select_beztriple(bezt1, SELECT, flag, HIDDEN);
}
+
+ BLI_addtail(newnurb, newnu);
}
}
else if (nu->pntsv == 1) { /* because UV Nurb has a different method for dupli */
@@ -1998,12 +2035,21 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
else {
if (enda == nu->pntsu - 1) newu += cyclicu;
+ if (i == cu->actnu) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ starta, starta + diffa, cu->actvert - starta);
+ }
newnu = BKE_nurb_copy(nu, newu, 1);
- BLI_addtail(newnurb, newnu);
memcpy(newnu->bp, &nu->bp[starta], diffa * sizeof(BPoint));
if (newu != diffa) {
memcpy(&newnu->bp[diffa], nu->bp, cyclicu * sizeof(BPoint));
+ if (i == cu->actnu) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ 0, cyclicu, newu - cyclicu + cu->actvert);
+ }
cyclicu = 0;
}
@@ -2012,19 +2058,28 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
select_bpoint(bp1, SELECT, flag, HIDDEN);
}
+
+ BLI_addtail(newnurb, newnu);
}
}
}
if (cyclicu != 0) {
+ if (i == cu->actnu) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ 0, cyclicu, cu->actvert);
+ }
+
newnu = BKE_nurb_copy(nu, cyclicu, 1);
- BLI_addtail(newnurb, newnu);
memcpy(newnu->bp, nu->bp, cyclicu * sizeof(BPoint));
newnu->flagu &= ~CU_NURB_CYCLIC;
for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) {
select_bpoint(bp1, SELECT, flag, HIDDEN);
}
+
+ BLI_addtail(newnurb, newnu);
}
}
else {
@@ -2100,6 +2155,28 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
memcpy(&newnu->bp[b * newnu->pntsu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint));
memcpy(&newnu->bp[b * newnu->pntsu + newu], &nu->bp[b * nu->pntsu], cyclicu * sizeof(BPoint));
}
+
+ if (cu->actnu == i) {
+ for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
+ starta = b * nu->pntsu + a;
+ if (calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ cu->actvert, starta,
+ cu->actvert % nu->pntsu + newu + b * newnu->pntsu))
+ {
+ /* actvert in cyclicu selection */
+ break;
+ }
+ else if (calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ starta, starta + newu,
+ cu->actvert - starta + b * newnu->pntsu))
+ {
+ /* actvert in 'current' iteration selection */
+ break;
+ }
+ }
+ }
cyclicu = cyclicv = 0;
}
else if ((a / nu->pntsu) + newv == nu->pntsv && cyclicv != 0) {
@@ -2107,6 +2184,14 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
newnu = BKE_nurb_copy(nu, newu, newv + cyclicv);
memcpy(newnu->bp, &nu->bp[a], newu * newv * sizeof(BPoint));
memcpy(&newnu->bp[newu * newv], nu->bp, newu * cyclicv * sizeof(BPoint));
+
+ /* check for actvert in cylicv selection */
+ if (cu->actnu == i) {
+ calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ cu->actvert, a,
+ (newu * newv) + cu->actvert);
+ }
cyclicu = cyclicv = 0;
}
else {
@@ -2115,6 +2200,20 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint));
}
}
+
+ /* general case if not handled by cyclicu or cyclicv */
+ if (cu->actnu == i) {
+ for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
+ starta = b * nu->pntsu + a;
+ if (calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ starta, starta + newu,
+ cu->actvert - (a / nu->pntsu * nu->pntsu + diffa + (starta % nu->pntsu))))
+ {
+ break;
+ }
+ }
+ }
BLI_addtail(newnurb, newnu);
if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC;
@@ -2131,6 +2230,20 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
for (b = 0; b < newv; b++) {
memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu], newu * sizeof(BPoint));
}
+
+ /* check for actvert in the unused cyclicuv selection */
+ if (cu->actnu == i) {
+ for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) {
+ starta = b * nu->pntsu;
+ if (calc_duplicate_actvert(
+ editnurb, newnurb, cu,
+ starta, starta + newu,
+ cu->actvert - (diffa + (starta % nu->pntsu))))
+ {
+ break;
+ }
+ }
+ }
BLI_addtail(newnurb, newnu);
if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC;
@@ -2144,12 +2257,9 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
}
}
- nu = nu->prev;
}
if (BLI_listbase_is_empty(newnurb) == false) {
- cu->actnu = cu->actvert = CU_ACT_NONE;
-
for (nu = newnurb->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
if (split) {
@@ -4163,7 +4273,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
/***************** pick select from 3d view **********************/
-bool mouse_nurb(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_curve_editnurb_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
@@ -4659,7 +4769,7 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
/***************** add vertex operator **********************/
-static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float location[3])
+static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float location_init[3])
{
Nurb *nu;
@@ -4700,7 +4810,7 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
int i;
mid_v3_v3v3(center, minmax[0], minmax[1]);
- sub_v3_v3v3(ofs, location, center);
+ sub_v3_v3v3(ofs, location_init, center);
if ((cu->flag & CU_3D) == 0) {
ofs[2] = 0.0f;
@@ -4722,6 +4832,8 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
}
}
}
+
+ BKE_nurb_handles_calc(nu);
}
else {
BPoint *bp;
@@ -4736,6 +4848,14 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
changed = true;
}
else {
+ float location[3];
+
+ copy_v3_v3(location, location_init);
+
+ if ((cu->flag & CU_3D) == 0) {
+ location[2] = 0.0f;
+ }
+
/* nothing selected: create a new curve */
nu = BKE_curve_nurb_active_get(cu);
@@ -4753,6 +4873,10 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
nurb_new->orderu = 4;
nurb_new->flag |= CU_SMOOTH;
BKE_nurb_bezierPoints_add(nurb_new, 1);
+
+ if ((cu->flag & CU_3D) == 0) {
+ nurb_new->flag |= CU_2D;
+ }
}
BLI_addtail(&editnurb->nurbs, nurb_new);
@@ -4784,6 +4908,10 @@ static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float locat
nurb_new->flag |= CU_SMOOTH;
nurb_new->orderu = 4;
BKE_nurb_points_add(nurb_new, 1);
+
+ if ((cu->flag & CU_3D) == 0) {
+ nurb_new->flag |= CU_2D;
+ }
}
BLI_addtail(&editnurb->nurbs, nurb_new);
@@ -4867,7 +4995,40 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval[2] = {UNPACK2(event->mval)};
float no_dummy[3];
float dist_px_dummy;
- snapObjectsContext(C, mval, &dist_px_dummy, location, no_dummy, SNAP_NOT_OBEDIT);
+ snapObjectsContext(
+ C, mval, SNAP_NOT_OBEDIT,
+ location, no_dummy, &dist_px_dummy);
+ }
+
+ if ((cu->flag & CU_3D) == 0) {
+ const float eps = 1e-6f;
+
+ /* get the view vector to 'location' */
+ float view_dir[3];
+ ED_view3d_global_to_vector(vc.rv3d, location, view_dir);
+
+ /* get the plane */
+ float plane[4];
+ /* only normalize to avoid precision errors */
+ normalize_v3_v3(plane, vc.obedit->obmat[2]);
+ plane[3] = -dot_v3v3(plane, vc.obedit->obmat[3]);
+
+ if (fabsf(dot_v3v3(view_dir, plane)) < eps) {
+ /* can't project on an aligned plane. */
+ }
+ else {
+ float lambda;
+ if (isect_ray_plane_v3(location, view_dir, plane, &lambda, false)) {
+ /* check if we're behind the viewport */
+ float location_test[3];
+ madd_v3_v3v3fl(location_test, location, view_dir, lambda);
+ if ((vc.rv3d->is_persp == false) ||
+ (mul_project_m4_v3_zfac(vc.rv3d->persmat, location_test) > 0.0f))
+ {
+ copy_v3_v3(location, location_test);
+ }
+ }
+ }
}
RNA_float_set_array(op->ptr, "location", location);
@@ -4953,7 +5114,7 @@ void CURVE_OT_extrude(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* to give to transform */
- RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+ RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/***************** make cyclic operator **********************/
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 5347ef05105..cc8e272d4f7 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -105,7 +105,7 @@ static const char *get_surf_defname(int type)
}
-Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob)
+Nurb *ED_curve_add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob)
{
static int xzproj = 0; /* this function calls itself... */
ListBase *editnurb = object_editcurve_get(obedit);
@@ -121,7 +121,6 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
const float grid = 1.0f;
const int cutype = (type & CU_TYPE); // poly, bezier, nurbs, etc
const int stype = (type & CU_PRIMITIVE);
- const bool force_3d = (((Curve *)obedit->data)->flag & CU_3D) != 0; /* could be adding to an existing 3D curve */
unit_m4(umat);
unit_m4(viewmat);
@@ -145,7 +144,6 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
case CU_PRIM_CURVE: /* curve */
nu->resolu = cu->resolu;
if (cutype == CU_BEZIER) {
- if (!force_3d) nu->flag |= CU_2D;
nu->pntsu = 2;
nu->bezt = (BezTriple *)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1");
bezt = nu->bezt;
@@ -247,7 +245,6 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
nu->resolu = cu->resolu;
if (cutype == CU_BEZIER) {
- if (!force_3d) nu->flag |= CU_2D;
nu->pntsu = 4;
nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * 4, "addNurbprim1");
nu->flagu = CU_NURB_CYCLIC;
@@ -346,7 +343,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
break;
case CU_PRIM_TUBE: /* Cylinder */
if (cutype == CU_NURBS) {
- nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
+ nu = ED_curve_add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
nu->resolu = cu->resolu;
nu->flag = CU_SMOOTH;
BLI_addtail(editnurb, nu); /* temporal for extrude and translate */
@@ -423,7 +420,7 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
float tmp_vec[3] = {0.f, 0.f, 1.f};
xzproj = 1;
- nu = add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
+ nu = ED_curve_add_nurbs_primitive(C, obedit, mat, CU_NURBS | CU_PRIM_CIRCLE, 0); /* circle */
xzproj = 0;
nu->resolu = cu->resolu;
nu->resolv = cu->resolv;
@@ -459,6 +456,10 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
BLI_assert(nu != NULL);
if (nu) { /* should always be set */
+ if ((obedit->type != OB_SURF) && ((cu->flag & CU_3D) == 0)) {
+ nu->flag |= CU_2D;
+ }
+
nu->flag |= CU_SMOOTH;
cu->actnu = BLI_listbase_count(editnurb);
cu->actvert = CU_ACT_NONE;
@@ -523,7 +524,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
dia = RNA_float_get(op->ptr, "radius");
mul_mat3_m4_fl(mat, dia);
- nu = add_nurbs_primitive(C, obedit, mat, type, newob);
+ nu = ED_curve_add_nurbs_primitive(C, obedit, mat, type, newob);
editnurb = object_editcurve_get(obedit);
BLI_addtail(editnurb, nu);
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
new file mode 100644
index 00000000000..5c74a3e43c2
--- /dev/null
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -0,0 +1,1180 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/curve/editcurve_paint.c
+ * \ingroup edcurve
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_space_api.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "ED_curve.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "curve_intern.h"
+
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#define USE_SPLINE_FIT
+
+#ifdef USE_SPLINE_FIT
+#include "curve_fit_nd.h"
+#endif
+
+/* Distance between input samples */
+#define STROKE_SAMPLE_DIST_MIN_PX 3
+#define STROKE_SAMPLE_DIST_MAX_PX 6
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Depth Utilities
+ * \{ */
+
+
+static float depth_read_zbuf(const ViewContext *vc, int x, int y)
+{
+ ViewDepths *vd = vc->rv3d->depths;
+
+ if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
+ return vd->depths[y * vd->w + x];
+ else
+ return -1.0f;
+}
+
+static bool depth_unproject(
+ const ARegion *ar, const bglMats *mats,
+ const int mval[2], const float depth,
+ float r_location_world[3])
+{
+ double p[3];
+ if (gluUnProject(
+ (double)ar->winrct.xmin + mval[0] + 0.5,
+ (double)ar->winrct.ymin + mval[1] + 0.5,
+ depth, mats->modelview, mats->projection, (const GLint *)mats->viewport,
+ &p[0], &p[1], &p[2]))
+ {
+ copy_v3fl_v3db(r_location_world, p);
+ return true;
+ }
+ return false;
+}
+
+static bool depth_read_normal(
+ const ViewContext *vc, const bglMats *mats, const int mval[2],
+ float r_normal[3])
+{
+ /* pixels surrounding */
+ bool depths_valid[9] = {false};
+ float coords[9][3] = {{0}};
+
+ ARegion *ar = vc->ar;
+ const ViewDepths *depths = vc->rv3d->depths;
+
+ for (int x = 0, i = 0; x < 2; x++) {
+ for (int y = 0; y < 2; y++) {
+ const int mval_ofs[2] = {mval[0] + (x - 1), mval[1] + (y - 1)};
+
+ float depth = depth_read_zbuf(vc, mval_ofs[0], mval_ofs[1]);
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ if (depth_unproject(ar, mats, mval_ofs, depth, coords[i])) {
+ depths_valid[i] = true;
+ }
+ }
+ i++;
+ }
+ }
+
+ const int edges[2][6][2] = {
+ /* x edges */
+ {{0, 1}, {1, 2},
+ {3, 4}, {4, 5},
+ {6, 7}, {7, 8}},
+ /* y edges */
+ {{0, 3}, {3, 6},
+ {1, 4}, {4, 7},
+ {2, 5}, {5, 8}},
+ };
+
+ float cross[2][3] = {{0.0f}};
+
+ for (int i = 0; i < 6; i++) {
+ for (int axis = 0; axis < 2; axis++) {
+ if (depths_valid[edges[axis][i][0]] && depths_valid[edges[axis][i][1]]) {
+ float delta[3];
+ sub_v3_v3v3(delta, coords[edges[axis][i][0]], coords[edges[axis][i][1]]);
+ add_v3_v3(cross[axis], delta);
+ }
+ }
+ }
+
+ cross_v3_v3v3(r_normal, cross[0], cross[1]);
+
+ if (normalize_v3(r_normal) != 0.0f) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name StrokeElem / #RNA_OperatorStrokeElement Conversion Functions
+ * \{ */
+
+struct StrokeElem {
+ float mval[2];
+ float location_world[3];
+ float location_local[3];
+ float pressure;
+};
+
+struct CurveDrawData {
+ short init_event_type;
+ short curve_type;
+
+ /* projecting 2D into 3D space */
+ struct {
+ /* use a plane or project to the surface */
+ bool use_plane;
+ float plane[4];
+
+ /* use 'rv3d->depths', note that this will become 'damaged' while drawing, but thats OK. */
+ bool use_depth;
+
+ /* offset projection by this value */
+ bool use_offset;
+ float offset[3]; /* worldspace */
+ } project;
+
+ /* cursor sampling */
+ struct {
+ /* use substeps, needed for nicely interpolating depth */
+ bool use_substeps;
+ } sample;
+
+ struct {
+ float min, max, range;
+ float offset;
+ } radius;
+
+ struct {
+ float mouse[2];
+ /* used incase we can't calculate the depth */
+ float location_world[3];
+
+ float location_world_valid[3];
+
+ const struct StrokeElem *selem;
+ } prev;
+
+ ViewContext vc;
+ bglMats mats;
+ enum {
+ CURVE_DRAW_IDLE = 0,
+ CURVE_DRAW_PAINTING = 1,
+ } state;
+
+ /* StrokeElem */
+ BLI_mempool *stroke_elem_pool;
+
+ void *draw_handle_view;
+};
+
+static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
+{
+ const Curve *cu = cdd->vc.obedit->data;
+ return ((selem->pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2;
+}
+
+static void stroke_elem_interp(
+ struct StrokeElem *selem_out,
+ const struct StrokeElem *selem_a, const struct StrokeElem *selem_b, float t)
+{
+ interp_v2_v2v2(selem_out->mval, selem_a->mval, selem_b->mval, t);
+ interp_v3_v3v3(selem_out->location_world, selem_a->location_world, selem_b->location_world, t);
+ interp_v3_v3v3(selem_out->location_local, selem_a->location_local, selem_b->location_local, t);
+ selem_out->pressure = interpf(selem_a->pressure, selem_b->pressure, t);
+}
+
+
+/**
+ * Sets the depth from #StrokeElem.mval
+ */
+static bool stroke_elem_project(
+ const struct CurveDrawData *cdd,
+ const int mval_i[2], const float mval_fl[2],
+ const float radius_offset, const float radius,
+ float r_location_world[3])
+{
+ View3D *v3d = cdd->vc.v3d;
+ ARegion *ar = cdd->vc.ar;
+ RegionView3D *rv3d = cdd->vc.rv3d;
+
+ bool is_location_world_set = false;
+
+ /* project to 'location_world' */
+ if (cdd->project.use_plane) {
+ /* get the view vector to 'location' */
+ float ray_origin[3], ray_direction[3];
+ ED_view3d_win_to_ray(cdd->vc.ar, v3d, mval_fl, ray_origin, ray_direction, false);
+
+ float lambda;
+ if (isect_ray_plane_v3(ray_origin, ray_direction, cdd->project.plane, &lambda, true)) {
+ madd_v3_v3v3fl(r_location_world, ray_origin, ray_direction, lambda);
+ is_location_world_set = true;
+ }
+ }
+ else {
+ const ViewDepths *depths = rv3d->depths;
+ if (depths &&
+ ((unsigned int)mval_i[0] < depths->w) &&
+ ((unsigned int)mval_i[1] < depths->h))
+ {
+ float depth = depth_read_zbuf(&cdd->vc, mval_i[0], mval_i[1]);
+ if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
+ if (depth_unproject(ar, &cdd->mats, mval_i, depth, r_location_world)) {
+ is_location_world_set = true;
+
+ if (radius_offset != 0.0f) {
+ float normal[3];
+ if (depth_read_normal(&cdd->vc, &cdd->mats, mval_i, normal)) {
+ madd_v3_v3fl(r_location_world, normal, radius_offset * radius);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (is_location_world_set) {
+ if (cdd->project.use_offset) {
+ add_v3_v3(r_location_world, cdd->project.offset);
+ }
+ }
+
+ return is_location_world_set;
+}
+
+static bool stroke_elem_project_fallback(
+ const struct CurveDrawData *cdd,
+ const int mval_i[2], const float mval_fl[2],
+ const float radius_offset, const float radius,
+ const float location_fallback_depth[3],
+ float r_location_world[3], float r_location_local[3])
+{
+ bool is_depth_found = stroke_elem_project(
+ cdd, mval_i, mval_fl,
+ radius_offset, radius,
+ r_location_world);
+ if (is_depth_found == false) {
+ ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world);
+ }
+ mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);
+
+ return is_depth_found;
+}
+
+/**
+ * \note #StrokeElem.mval & #StrokeElem.pressure must be set first.
+ */
+static bool stroke_elem_project_fallback_elem(
+ const struct CurveDrawData *cdd,
+ const float location_fallback_depth[3],
+ struct StrokeElem *selem)
+{
+ const int mval_i[2] = {UNPACK2(selem->mval)};
+ const float radius = stroke_elem_radius(cdd, selem);
+ return stroke_elem_project_fallback(
+ cdd, mval_i, selem->mval,
+ cdd->radius.offset, radius,
+ location_fallback_depth,
+ selem->location_world, selem->location_local);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Operator/Stroke Conversion
+ * \{ */
+
+static void curve_draw_stroke_to_operator_elem(
+ wmOperator *op, const struct StrokeElem *selem)
+{
+ PointerRNA itemptr;
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", selem->mval);
+ RNA_float_set_array(&itemptr, "location", selem->location_world);
+ RNA_float_set(&itemptr, "pressure", selem->pressure);
+}
+
+static void curve_draw_stroke_from_operator_elem(
+ wmOperator *op, PointerRNA *itemptr)
+{
+ struct CurveDrawData *cdd = op->customdata;
+
+ struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
+
+ RNA_float_get_array(itemptr, "mouse", selem->mval);
+ RNA_float_get_array(itemptr, "location", selem->location_world);
+ mul_v3_m4v3(selem->location_local, cdd->vc.obedit->imat, selem->location_world);
+ selem->pressure = RNA_float_get(itemptr, "pressure");
+}
+
+static void curve_draw_stroke_to_operator(wmOperator *op)
+{
+ struct CurveDrawData *cdd = op->customdata;
+
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ curve_draw_stroke_to_operator_elem(op, selem);
+ }
+}
+
+static void curve_draw_stroke_from_operator(wmOperator *op)
+{
+ RNA_BEGIN (op->ptr, itemptr, "stroke")
+ {
+ curve_draw_stroke_from_operator_elem(op, &itemptr);
+ }
+ RNA_END;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Operator Callbacks & Helpers
+ * \{ */
+
+static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ wmOperator *op = arg;
+ struct CurveDrawData *cdd = op->customdata;
+
+ const int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+
+ if (stroke_len == 0) {
+ return;
+ }
+
+ View3D *v3d = cdd->vc.v3d;
+ Object *obedit = cdd->vc.obedit;
+ Curve *cu = obedit->data;
+
+ UI_ThemeColor(TH_WIRE);
+
+ if (cu->ext2 > 0.0f) {
+ GLUquadricObj *qobj = gluNewQuadric();
+
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ const float location_zero[3] = {0};
+ const float *location_prev = location_zero;
+
+ /* scale to edit-mode space */
+ glPushMatrix();
+ glMultMatrixf(obedit->obmat);
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ glTranslatef(
+ selem->location_local[0] - location_prev[0],
+ selem->location_local[1] - location_prev[1],
+ selem->location_local[2] - location_prev[2]);
+ location_prev = selem->location_local;
+ const float radius = stroke_elem_radius(cdd, selem);
+ gluSphere(qobj, radius , 12, 8);
+
+ location_prev = selem->location_local;
+ }
+
+ glPopMatrix();
+
+ gluDeleteQuadric(qobj);
+ }
+
+ if (stroke_len > 1) {
+ float (*coord_array)[3] = MEM_mallocN(sizeof(*coord_array) * stroke_len, __func__);
+
+ {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+ int i;
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter), i = 0; selem; selem = BLI_mempool_iterstep(&iter), i++) {
+ copy_v3_v3(coord_array[i], selem->location_world);
+ }
+ }
+
+ {
+ glEnable(GL_BLEND);
+ glEnable(GL_LINE_SMOOTH);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, coord_array);
+
+ cpack(0x0);
+ glLineWidth(3.0f);
+ glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
+
+ if (v3d->zbuf)
+ glDisable(GL_DEPTH_TEST);
+
+ cpack(0xffffffff);
+ glLineWidth(1.0f);
+ glDrawArrays(GL_LINE_STRIP, 0, stroke_len);
+
+ if (v3d->zbuf)
+ glEnable(GL_DEPTH_TEST);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ MEM_freeN(coord_array);
+ }
+}
+
+static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ Object *obedit = cdd->vc.obedit;
+
+ invert_m4_m4(obedit->imat, obedit->obmat);
+
+ struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
+
+ ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]);
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ selem->pressure = wmtab->Pressure;
+ }
+ else {
+ selem->pressure = 1.0f;
+ }
+
+ bool is_depth_found = stroke_elem_project_fallback_elem(
+ cdd, cdd->prev.location_world_valid, selem);
+
+ if (is_depth_found) {
+ /* use the depth if a fallback wasn't used */
+ copy_v3_v3(cdd->prev.location_world_valid, selem->location_world);
+ }
+ copy_v3_v3(cdd->prev.location_world, selem->location_world);
+
+ float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval);
+ copy_v2_v2(cdd->prev.mouse, selem->mval);
+
+ if (cdd->sample.use_substeps && cdd->prev.selem) {
+ const struct StrokeElem selem_target = *selem;
+ struct StrokeElem *selem_new_last = selem;
+ if (len_sq >= SQUARE(STROKE_SAMPLE_DIST_MAX_PX)) {
+ int n = (int)ceil(sqrt((double)len_sq)) / STROKE_SAMPLE_DIST_MAX_PX ;
+
+ for (int i = 1; i < n; i++) {
+ struct StrokeElem *selem_new = selem_new_last;
+ stroke_elem_interp(selem_new, cdd->prev.selem, &selem_target, (float)i / n);
+
+ const bool is_depth_found_substep = stroke_elem_project_fallback_elem(
+ cdd, cdd->prev.location_world_valid, selem_new);
+ if (is_depth_found == false) {
+ if (is_depth_found_substep) {
+ copy_v3_v3(cdd->prev.location_world_valid, selem_new->location_world);
+ }
+ }
+
+ selem_new_last = BLI_mempool_calloc(cdd->stroke_elem_pool);
+ }
+ }
+ selem = selem_new_last;
+ *selem_new_last = selem_target;
+ }
+
+ cdd->prev.selem = selem;
+
+ ED_region_tag_redraw(cdd->vc.ar);
+}
+
+static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+
+ /* add first point */
+ curve_draw_event_add(op, event);
+
+ if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) && cdd->project.use_depth &&
+ (cps->flag & CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS))
+ {
+ RegionView3D *rv3d = cdd->vc.rv3d;
+
+ cdd->project.use_depth = false;
+ cdd->project.use_plane = true;
+
+ float normal[3] = {0.0f};
+ if (ELEM(cps->surface_plane,
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE))
+ {
+ if (depth_read_normal(&cdd->vc, &cdd->mats, event->mval, normal)) {
+ if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
+ float cross_a[3], cross_b[3];
+ cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
+ cross_v3_v3v3(cross_b, normal, cross_a);
+ copy_v3_v3(normal, cross_b);
+ }
+ }
+ }
+
+ /* CURVE_PAINT_SURFACE_PLANE_VIEW or fallback */
+ if (is_zero_v3(normal)) {
+ copy_v3_v3(normal, rv3d->viewinv[2]);
+ }
+
+ normalize_v3_v3(cdd->project.plane, normal);
+ cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, cdd->prev.location_world_valid);
+
+ /* Special case for when we only have offset applied on the first-hit,
+ * the remaining stroke must be offset too. */
+ if (cdd->radius.offset != 0.0f) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ float location_no_offset[3];
+
+ if (stroke_elem_project(
+ cdd, event->mval, mval_fl, 0.0f, 0.0f,
+ location_no_offset))
+ {
+ sub_v3_v3v3(cdd->project.offset, cdd->prev.location_world_valid, location_no_offset);
+ if (!is_zero_v3(cdd->project.offset)) {
+ cdd->project.use_offset = true;
+ }
+ }
+ }
+ /* end special case */
+
+ }
+
+ cdd->init_event_type = event->type;
+ cdd->state = CURVE_DRAW_PAINTING;
+}
+
+static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
+{
+ BLI_assert(op->customdata == NULL);
+
+ struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+
+ if (is_invoke) {
+ view3d_set_viewcontext(C, &cdd->vc);
+ if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
+ MEM_freeN(cdd);
+ BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport.");
+ return false;
+ }
+ }
+ else {
+ cdd->vc.scene = CTX_data_scene(C);
+ cdd->vc.obedit = CTX_data_edit_object(C);
+ }
+
+ op->customdata = cdd;
+
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+
+ cdd->curve_type = cps->curve_type;
+
+ cdd->radius.min = cps->radius_min;
+ cdd->radius.max = cps->radius_max;
+ cdd->radius.range = cps->radius_max - cps->radius_min;
+ cdd->radius.offset = cps->radius_offset;
+
+ cdd->stroke_elem_pool = BLI_mempool_create(
+ sizeof(struct StrokeElem), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
+
+ return true;
+}
+
+
+static void curve_draw_exit(wmOperator *op)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ if (cdd) {
+ if (cdd->draw_handle_view) {
+ ED_region_draw_cb_exit(cdd->vc.ar->type, cdd->draw_handle_view);
+ WM_cursor_modal_restore(cdd->vc.win);
+ }
+
+ if (cdd->stroke_elem_pool) {
+ BLI_mempool_destroy(cdd->stroke_elem_pool);
+ }
+
+ MEM_freeN(cdd);
+ op->customdata = NULL;
+ }
+}
+
+/**
+ * Initialize values before calling 'exec' (when running interactively).
+ */
+static void curve_draw_exec_precalc(wmOperator *op)
+{
+ struct CurveDrawData *cdd = op->customdata;
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "corner_angle");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : M_PI;
+ RNA_property_float_set(op->ptr, prop, corner_angle);
+ }
+
+ prop = RNA_struct_find_property(op->ptr, "error_threshold");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+
+ /* error isnt set so we'll have to calculate it from the pixel values */
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem, *selem_prev;
+
+ float len_3d = 0.0f, len_2d = 0.0f;
+ float scale_px; /* pixel to local space scale */
+
+ int i = 0;
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ selem_prev = BLI_mempool_iterstep(&iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
+ len_3d += len_v3v3(selem->location_local, selem_prev->location_local);
+ len_2d += len_v2v2(selem->mval, selem_prev->mval);
+ selem_prev = selem;
+ }
+ scale_px = ((len_3d > 0.0f) && (len_2d > 0.0f)) ? (len_3d / len_2d) : 0.0f;
+ float error_threshold = (cps->error_threshold * U.pixelsize) * scale_px;
+ RNA_property_float_set(op->ptr, prop, error_threshold);
+ }
+
+ if ((cps->radius_taper_start != 0.0f) ||
+ (cps->radius_taper_end != 0.0f))
+ {
+ /* note, we could try to de-duplicate the length calculations above */
+ const int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+
+ BLI_mempool_iter iter;
+ struct StrokeElem *selem, *selem_prev;
+
+ float *lengths = MEM_mallocN(sizeof(float) * stroke_len, __func__);
+ struct StrokeElem **selem_array = MEM_mallocN(sizeof(*selem_array) * stroke_len, __func__);
+ lengths[0] = 0.0f;
+
+ float len_3d = 0.0f;
+
+ int i = 1;
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ selem_prev = BLI_mempool_iterstep(&iter);
+ selem_array[0] = selem_prev;
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
+ const float len_3d_segment = len_v3v3(selem->location_local, selem_prev->location_local);
+ len_3d += len_3d_segment;
+ lengths[i] = len_3d;
+ selem_array[i] = selem;
+ selem_prev = selem;
+ }
+
+ if (cps->radius_taper_start != 0.0) {
+ selem_array[0]->pressure = 0.0f;
+ const float len_taper_max = cps->radius_taper_start * len_3d;
+ for (i = 1; i < stroke_len && lengths[i] < len_taper_max; i++) {
+ selem_array[i]->pressure *= lengths[i] / len_taper_max;
+ }
+ }
+
+ if (cps->radius_taper_end != 0.0) {
+ selem_array[stroke_len - 1]->pressure = 0.0f;
+ const float len_taper_max = cps->radius_taper_end * len_3d;
+ const float len_taper_min = len_3d - len_taper_max;
+ for (i = stroke_len - 2; i > 0 && lengths[i] > len_taper_min; i--) {
+ selem_array[i]->pressure *= (len_3d - lengths[i]) / len_taper_max;
+ }
+ }
+
+ MEM_freeN(lengths);
+ MEM_freeN(selem_array);
+ }
+}
+
+static int curve_draw_exec(bContext *C, wmOperator *op)
+{
+ if (op->customdata == NULL) {
+ if (!curve_draw_init(C, op, false)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ struct CurveDrawData *cdd = op->customdata;
+
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+ Object *obedit = cdd->vc.scene->obedit;
+ Curve *cu = obedit->data;
+ ListBase *nurblist = object_editcurve_get(obedit);
+
+ int stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+
+ const bool is_3d = (cu->flag & CU_3D) != 0;
+ invert_m4_m4(obedit->imat, obedit->obmat);
+
+ if (BLI_mempool_count(cdd->stroke_elem_pool) == 0) {
+ curve_draw_stroke_from_operator(op);
+ stroke_len = BLI_mempool_count(cdd->stroke_elem_pool);
+ }
+
+ ED_curve_deselect_all(cu->editnurb);
+
+ const double radius_min = cps->radius_min;
+ const double radius_max = cps->radius_max;
+ const double radius_range = cps->radius_max - cps->radius_min;
+
+ Nurb *nu = MEM_callocN(sizeof(Nurb), __func__);
+ nu->pntsv = 1;
+ nu->resolu = cu->resolu;
+ nu->resolv = cu->resolv;
+ nu->flag |= CU_SMOOTH;
+
+ const bool use_pressure_radius =
+ (cps->flag & CURVE_PAINT_FLAG_PRESSURE_RADIUS) ||
+ ((cps->radius_taper_start != 0.0f) ||
+ (cps->radius_taper_end != 0.0f));
+
+ if (cdd->curve_type == CU_BEZIER) {
+ nu->type = CU_BEZIER;
+
+#ifdef USE_SPLINE_FIT
+
+ /* Allow to interpolate multiple channels */
+ int dims = 3;
+ struct {
+ int radius;
+ } coords_indices;
+ coords_indices.radius = use_pressure_radius ? dims++ : -1;
+
+ float *coords = MEM_mallocN(sizeof(*coords) * stroke_len * dims, __func__);
+
+ float *cubic_spline = NULL;
+ unsigned int cubic_spline_len = 0;
+
+ /* error in object local space */
+ const float error_threshold = RNA_float_get(op->ptr, "error_threshold");
+ const float corner_angle = RNA_float_get(op->ptr, "corner_angle");
+
+ {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+ float *co = coords;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), co += dims) {
+ copy_v3_v3(co, selem->location_local);
+ if (coords_indices.radius != -1) {
+ co[coords_indices.radius] = selem->pressure;
+ }
+ }
+ }
+
+ unsigned int *corners = NULL;
+ unsigned int corners_len = 0;
+
+ if (corner_angle < M_PI) {
+ /* this could be configurable... */
+ const float corner_radius_min = error_threshold / 8;
+ const float corner_radius_max = error_threshold * 2;
+ const unsigned int samples_max = 16;
+
+ curve_fit_corners_detect_fl(
+ (const float *)coords, stroke_len, dims,
+ corner_radius_min, corner_radius_max,
+ samples_max, corner_angle,
+ &corners, &corners_len);
+ }
+
+ unsigned int *corners_index = NULL;
+ unsigned int corners_index_len = 0;
+
+ const int result = curve_fit_cubic_to_points_fl(
+ coords, stroke_len, dims, error_threshold,
+ corners, corners_len,
+ &cubic_spline, &cubic_spline_len,
+ NULL,
+ &corners_index, &corners_index_len);
+
+ MEM_freeN(coords);
+ if (corners) {
+ free(corners);
+ }
+
+ if (result == 0) {
+ nu->pntsu = cubic_spline_len;
+ nu->bezt = MEM_callocN(sizeof(BezTriple) * nu->pntsu, __func__);
+
+ float *co = cubic_spline;
+ BezTriple *bezt = nu->bezt;
+ for (int j = 0; j < cubic_spline_len; j++, bezt++, co += (dims * 3)) {
+ const float *handle_l = co + (dims * 0);
+ const float *pt = co + (dims * 1);
+ const float *handle_r = co + (dims * 2);
+
+ copy_v3_v3(bezt->vec[0], handle_l);
+ copy_v3_v3(bezt->vec[1], pt);
+ copy_v3_v3(bezt->vec[2], handle_r);
+
+ if (coords_indices.radius != -1) {
+ bezt->radius = (pt[coords_indices.radius] * cdd->radius.range) + cdd->radius.min;
+ }
+ else {
+ bezt->radius = radius_max;
+ }
+
+ bezt->h1 = bezt->h2 = HD_ALIGN; /* will set to free in second pass */
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ }
+
+ if (corners_index) {
+ /* ignore the first and last */
+ for (unsigned int i = 1; i < corners_index_len - 1; i++) {
+ bezt = &nu->bezt[corners_index[i]];
+ bezt->h1 = bezt->h2 = HD_FREE;
+ }
+ }
+ }
+
+ if (corners_index) {
+ free(corners_index);
+ }
+
+ if (cubic_spline) {
+ free(cubic_spline);
+ }
+
+#else
+ nu->pntsu = stroke_len;
+ nu->bezt = MEM_callocN(nu->pntsu * sizeof(BezTriple), __func__);
+
+ BezTriple *bezt = nu->bezt;
+
+ {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ copy_v3_v3(bezt->vec[1], selem->location_local);
+ if (!is_3d) {
+ bezt->vec[1][2] = 0.0f;
+ }
+
+ if (use_pressure_radius) {
+ bezt->radius = selem->pressure;
+ }
+ else {
+ bezt->radius = radius_max;
+ }
+
+ bezt->h1 = bezt->h2 = HD_AUTO;
+
+ bezt->f1 |= SELECT;
+ bezt->f2 |= SELECT;
+ bezt->f3 |= SELECT;
+
+ bezt++;
+ }
+ }
+#endif
+
+ BKE_nurb_handles_calc(nu);
+ }
+ else { /* CU_POLY */
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem;
+
+ nu->pntsu = stroke_len;
+ nu->type = CU_POLY;
+ nu->bp = MEM_callocN(nu->pntsu * sizeof(BPoint), __func__);
+
+ BPoint *bp = nu->bp;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ copy_v3_v3(bp->vec, selem->location_local);
+ if (!is_3d) {
+ bp->vec[2] = 0.0f;
+ }
+
+ if (use_pressure_radius) {
+ bp->radius = (selem->pressure * radius_range) + radius_min;
+ }
+ else {
+ bp->radius = cps->radius_max;
+ }
+ bp->f1 = SELECT;
+ bp->vec[3] = 1.0f;
+
+ bp++;
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+ }
+
+ BLI_addtail(nurblist, nu);
+
+ BKE_curve_nurb_active_set(cu, nu);
+ cu->actvert = nu->pntsu - 1;
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
+
+ curve_draw_exit(op);
+
+ return OPERATOR_FINISHED;
+}
+
+static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (RNA_struct_property_is_set(op->ptr, "stroke")) {
+ return curve_draw_exec(C, op);
+ }
+
+ if (!curve_draw_init(C, op, true)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ struct CurveDrawData *cdd = op->customdata;
+
+ const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
+
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+
+ /* fallback (incase we can't find the depth on first test) */
+ {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ float center[3];
+ negate_v3_v3(center, cdd->vc.rv3d->ofs);
+ ED_view3d_win_to_3d(cdd->vc.ar, center, mval_fl, cdd->prev.location_world);
+ copy_v3_v3(cdd->prev.location_world_valid, cdd->prev.location_world);
+ }
+
+ cdd->draw_handle_view = ED_region_draw_cb_activate(
+ cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
+ WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR);
+
+ {
+ View3D *v3d = cdd->vc.v3d;
+ RegionView3D *rv3d = cdd->vc.rv3d;
+ Object *obedit = cdd->vc.obedit;
+ Curve *cu = obedit->data;
+
+ const float *plane_no = NULL;
+ const float *plane_co = NULL;
+
+ if ((cu->flag & CU_3D) == 0) {
+ /* 2D overrides other options */
+ plane_co = obedit->obmat[3];
+ plane_no = obedit->obmat[2];
+ cdd->project.use_plane = true;
+ }
+ else {
+ if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) &&
+ (v3d->drawtype > OB_WIRE))
+ {
+ view3d_get_transformation(cdd->vc.ar, cdd->vc.rv3d, NULL, &cdd->mats);
+
+ /* needed or else the draw matrix can be incorrect */
+ view3d_operator_needs_opengl(C);
+
+ ED_view3d_autodist_init(cdd->vc.scene, cdd->vc.ar, cdd->vc.v3d, 0);
+
+ if (cdd->vc.rv3d->depths) {
+ cdd->vc.rv3d->depths->damaged = true;
+ }
+
+ ED_view3d_depth_update(cdd->vc.ar);
+
+ if (cdd->vc.rv3d->depths != NULL) {
+ cdd->project.use_depth = true;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane.");
+ cdd->project.use_depth = false;
+ }
+ }
+
+ /* use view plane (when set or as fallback when surface can't be found) */
+ if (cdd->project.use_depth == false) {
+ plane_co = ED_view3d_cursor3d_get(cdd->vc.scene, v3d);;
+ plane_no = rv3d->viewinv[2];
+ cdd->project.use_plane = true;
+ }
+
+ if (cdd->project.use_depth && (cdd->curve_type != CU_POLY)) {
+ cdd->sample.use_substeps = true;
+ }
+ }
+
+ if (cdd->project.use_plane) {
+ normalize_v3_v3(cdd->project.plane, plane_no);
+ cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, plane_co);
+ }
+ }
+
+ if (is_modal == false) {
+ curve_draw_event_add_first(op, event);
+ }
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void curve_draw_cancel(bContext *UNUSED(C), wmOperator *op)
+{
+ curve_draw_exit(op);
+}
+
+
+/* Modal event handling of frame changing */
+static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int ret = OPERATOR_RUNNING_MODAL;
+ struct CurveDrawData *cdd = op->customdata;
+
+ UNUSED_VARS(C, op);
+
+ if (event->type == cdd->init_event_type) {
+ if (event->val == KM_RELEASE) {
+ ED_region_tag_redraw(cdd->vc.ar);
+
+ curve_draw_exec_precalc(op);
+
+ curve_draw_stroke_to_operator(op);
+
+ curve_draw_exec(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+ else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
+ ED_region_tag_redraw(cdd->vc.ar);
+ curve_draw_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ else if (ELEM(event->type, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ curve_draw_event_add_first(op, event);
+ }
+ }
+ else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ if (cdd->state == CURVE_DRAW_PAINTING) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (len_squared_v2v2(mval_fl, cdd->prev.location_world) > SQUARE(STROKE_SAMPLE_DIST_MIN_PX)) {
+ curve_draw_event_add(op, event);
+ }
+ }
+ }
+
+ return ret;
+}
+
+void CURVE_OT_draw(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Draw Curve";
+ ot->idname = "CURVE_OT_draw";
+ ot->description = "Draw a freehand spline";
+
+ /* api callbacks */
+ ot->exec = curve_draw_exec;
+ ot->invoke = curve_draw_invoke;
+ ot->cancel = curve_draw_cancel;
+ ot->modal = curve_draw_modal;
+ ot->poll = ED_operator_editcurve;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_distance(
+ ot->srna, "error_threshold", 0.0f, 0.0f, 10.0f, "Error",
+ "Error distance threshold (in object units)",
+ 0.0001f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0, 10, 1, 4);
+
+ prop = RNA_def_float_distance(
+ ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI);
+ RNA_def_property_subtype(prop, PROP_ANGLE);
+
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/** \} */
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 0f3942b0c90..a29266294b4 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -999,20 +999,22 @@ void CURVE_OT_select_less(wmOperatorType *ot)
/********************** select random *********************/
-static void curve_select_random(ListBase *editnurb, float randfac, bool select)
+static void curve_select_random(ListBase *editnurb, float randfac, int seed, bool select)
{
Nurb *nu;
BezTriple *bezt;
BPoint *bp;
int a;
+ RNG *rng = BLI_rng_new_srandom(seed);
+
for (nu = editnurb->first; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
bezt = nu->bezt;
a = nu->pntsu;
while (a--) {
if (!bezt->hide) {
- if (BLI_frand() < randfac) {
+ if (BLI_rng_get_float(rng) < randfac) {
select_beztriple(bezt, select, SELECT, VISIBLE);
}
}
@@ -1025,7 +1027,7 @@ static void curve_select_random(ListBase *editnurb, float randfac, bool select)
while (a--) {
if (!bp->hide) {
- if (BLI_frand() < randfac) {
+ if (BLI_rng_get_float(rng) < randfac) {
select_bpoint(bp, select, SELECT, VISIBLE);
}
}
@@ -1033,6 +1035,8 @@ static void curve_select_random(ListBase *editnurb, float randfac, bool select)
}
}
}
+
+ BLI_rng_free(rng);
}
static int curve_select_random_exec(bContext *C, wmOperator *op)
@@ -1041,8 +1045,9 @@ static int curve_select_random_exec(bContext *C, wmOperator *op)
ListBase *editnurb = object_editcurve_get(obedit);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
- curve_select_random(editnurb, randfac, select);
+ curve_select_random(editnurb, randfac, seed, select);
BKE_curve_nurb_vert_active_validate(obedit->data);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -1065,14 +1070,12 @@ void CURVE_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
- "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
- WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+ WM_operator_properties_select_random(ot);
}
/********************* every nth number of point *******************/
-static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int offset)
+static void select_nth_bezt(Nurb *nu, BezTriple *bezt, const struct CheckerIntervalParams *params)
{
int a, start;
@@ -1082,7 +1085,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int of
while (a--) {
const int depth = abs(start - a);
- if ((offset + depth) % (skip + nth) >= skip) {
+ if (WM_operator_properties_checker_interval_test(params, depth)) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
}
@@ -1090,7 +1093,7 @@ static void select_nth_bezt(Nurb *nu, BezTriple *bezt, int nth, int skip, int of
}
}
-static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
+static void select_nth_bp(Nurb *nu, BPoint *bp, const struct CheckerIntervalParams *params)
{
int a, startrow, startpnt;
int row, pnt;
@@ -1105,7 +1108,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
while (a--) {
const int depth = abs(pnt - startpnt) + abs(row - startrow);
- if ((offset + depth) % (skip + nth) >= skip) {
+ if (WM_operator_properties_checker_interval_test(params, depth)) {
select_bpoint(bp, DESELECT, SELECT, HIDDEN);
}
@@ -1119,7 +1122,7 @@ static void select_nth_bp(Nurb *nu, BPoint *bp, int nth, int skip, int offset)
}
}
-bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
+static bool ed_curve_select_nth(Curve *cu, const struct CheckerIntervalParams *params)
{
Nurb *nu = NULL;
void *vert = NULL;
@@ -1128,10 +1131,10 @@ bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
return false;
if (nu->bezt) {
- select_nth_bezt(nu, vert, nth, skip, offset);
+ select_nth_bezt(nu, vert, params);
}
else {
- select_nth_bp(nu, vert, nth, skip, offset);
+ select_nth_bp(nu, vert, params);
}
return true;
@@ -1140,14 +1143,11 @@ bool ED_curve_select_nth(Curve *cu, int nth, int skip, int offset)
static int select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- const int nth = RNA_int_get(op->ptr, "nth") - 1;
- const int skip = RNA_int_get(op->ptr, "skip");
- int offset = RNA_int_get(op->ptr, "offset");
+ struct CheckerIntervalParams op_params;
- /* so input of offset zero ends up being (nth - 1) */
- offset = mod_i(offset, nth + skip);
+ WM_operator_properties_checker_interval_from_op(op, &op_params);
- if (!ED_curve_select_nth(obedit->data, nth, skip, offset)) {
+ if (!ed_curve_select_nth(obedit->data, &op_params)) {
if (obedit->type == OB_SURF) {
BKE_report(op->reports, RPT_ERROR, "Surface has not got active point");
}
@@ -1177,9 +1177,7 @@ void CURVE_OT_select_nth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
- RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
- RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
+ WM_operator_properties_checker_interval(ot, false);
}
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index ea6b6154be8..7c1fe0cadf0 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -51,6 +51,7 @@
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_font.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -344,50 +345,18 @@ static bool font_paste_utf8(bContext *C, const char *str, const size_t str_len)
static int paste_from_file(bContext *C, ReportList *reports, const char *filename)
{
Object *obedit = CTX_data_edit_object(C);
- FILE *fp;
char *strp;
- int filelen;
+ size_t filelen;
int retval;
- fp = BLI_fopen(filename, "r");
-
- if (!fp) {
+ strp = BLI_file_read_text_as_mem(filename, 1, &filelen);
+ if (strp == NULL) {
BKE_reportf(reports, RPT_ERROR, "Failed to open file '%s'", filename);
return OPERATOR_CANCELLED;
}
+ strp[filelen] = 0;
- fseek(fp, 0L, SEEK_END);
-
- errno = 0;
- filelen = ftell(fp);
- if (filelen == -1) {
- goto fail;
- }
-
- if (filelen <= MAXTEXT) {
- strp = MEM_mallocN(filelen + 4, "tempstr");
-
- fseek(fp, 0L, SEEK_SET);
-
- /* fread() instead of read(), because windows read() converts text
- * to DOS \r\n linebreaks, causing double linebreaks in the 3d text */
- errno = 0;
- filelen = fread(strp, 1, filelen, fp);
- if (filelen == -1) {
- MEM_freeN(strp);
- goto fail;
- }
-
- strp[filelen] = 0;
- }
- else {
- strp = NULL;
- }
-
- fclose(fp);
-
-
- if (strp && font_paste_utf8(C, strp, filelen)) {
+ if (font_paste_utf8(C, strp, filelen)) {
text_update_edited(C, obedit, FO_EDIT);
retval = OPERATOR_FINISHED;
@@ -397,18 +366,9 @@ static int paste_from_file(bContext *C, ReportList *reports, const char *filenam
retval = OPERATOR_CANCELLED;
}
- if (strp) {
- MEM_freeN(strp);
- }
+ MEM_freeN(strp);
return retval;
-
-
- /* failed to seek or read */
-fail:
- BKE_reportf(reports, RPT_ERROR, "Failed to read file '%s', %s", filename, strerror(errno));
- fclose(fp);
- return OPERATOR_CANCELLED;
}
static int paste_from_file_exec(bContext *C, wmOperator *op)
@@ -449,66 +409,9 @@ void FONT_OT_text_paste_from_file(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-}
-
-
-/* -------------------------------------------------------------------- */
-/* Paste From Clipboard */
-
-static int paste_from_clipboard(bContext *C, ReportList *reports)
-{
- Object *obedit = CTX_data_edit_object(C);
- char *strp;
- int filelen;
- int retval;
-
- strp = WM_clipboard_text_get(false, &filelen);
- if (strp == NULL) {
- BKE_report(reports, RPT_ERROR, "Clipboard empty");
- return OPERATOR_CANCELLED;
- }
-
- if ((filelen <= MAXTEXT) && font_paste_utf8(C, strp, filelen)) {
- text_update_edited(C, obedit, FO_EDIT);
- retval = OPERATOR_FINISHED;
- }
- else {
- BKE_report(reports, RPT_ERROR, "Clipboard too long");
- retval = OPERATOR_CANCELLED;
- }
- MEM_freeN(strp);
-
- return retval;
-}
-
-static int paste_from_clipboard_exec(bContext *C, wmOperator *op)
-{
- int retval;
-
- retval = paste_from_clipboard(C, op->reports);
-
- return retval;
-}
-
-void FONT_OT_text_paste_from_clipboard(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Paste Clipboard";
- ot->description = "Paste contents from system clipboard";
- ot->idname = "FONT_OT_text_paste_from_clipboard";
-
- /* api callbacks */
- ot->exec = paste_from_clipboard_exec;
- ot->poll = ED_operator_editfont;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************* text to object operator ********************/
@@ -538,7 +441,7 @@ static void txt_add_object(bContext *C, TextLine *firstline, int totline, const
cu = obedit->data;
cu->vfont = BKE_vfont_builtin_get();
- cu->vfont->id.us++;
+ id_us_plus(&cu->vfont->id);
for (tmp = firstline, a = 0; nbytes < MAXTEXT && a < totline; tmp = tmp->next, a++) {
size_t nchars_line, nbytes_line;
@@ -799,10 +702,21 @@ static void copy_selection(Object *obedit)
if (BKE_vfont_select_get(obedit, &selstart, &selend)) {
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
-
- memcpy(ef->copybuf, ef->textbuf + selstart, ((selend - selstart) + 1) * sizeof(wchar_t));
- ef->copybuf[(selend - selstart) + 1] = 0;
- memcpy(ef->copybufinfo, ef->textbufinfo + selstart, ((selend - selstart) + 1) * sizeof(CharInfo));
+ char *buf = NULL;
+ wchar_t *text_buf;
+ size_t len_utf8;
+
+ /* internal clipboard (for style) */
+ BKE_vfont_clipboard_set(ef->textbuf + selstart, ef->textbufinfo + selstart, selend - selstart + 1);
+ BKE_vfont_clipboard_get(&text_buf, NULL, &len_utf8, NULL);
+
+ /* system clipboard */
+ buf = MEM_mallocN(len_utf8 + 1, __func__);
+ if (buf) {
+ BLI_strncpy_wchar_as_utf8(buf, text_buf, len_utf8 + 1);
+ WM_clipboard_text_set(buf, false);
+ MEM_freeN(buf);
+ }
}
}
@@ -864,11 +778,13 @@ void FONT_OT_text_cut(wmOperatorType *ot)
static bool paste_selection(Object *obedit, ReportList *reports)
{
- Curve *cu = obedit->data;
- EditFont *ef = cu->editfont;
- int len = wcslen(ef->copybuf);
+ wchar_t *text_buf;
+ CharInfo *info_buf;
+ size_t len;
+
+ BKE_vfont_clipboard_get(&text_buf, &info_buf, NULL, &len);
- if (font_paste_wchar(obedit, ef->copybuf, len, ef->copybufinfo)) {
+ if (font_paste_wchar(obedit, text_buf, len, info_buf)) {
return true;
}
else {
@@ -880,13 +796,68 @@ static bool paste_selection(Object *obedit, ReportList *reports)
static int paste_text_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
+ int retval;
+ size_t len_utf8;
+ wchar_t *text_buf;
+
+ /* Store both clipboards as utf8 for comparison,
+ * Give priority to the internal 'vfont' clipboard with its 'CharInfo' text styles
+ * as long as its synchronized with the systems clipboard. */
+ struct {
+ char *buf;
+ int len;
+ } clipboard_system = {NULL}, clipboard_vfont = {NULL};
+
+ clipboard_system.buf = WM_clipboard_text_get(false, &clipboard_system.len);
- if (!paste_selection(obedit, op->reports))
+ if (clipboard_system.buf == NULL) {
return OPERATOR_CANCELLED;
+ }
- text_update_edited(C, obedit, FO_EDIT);
+ BKE_vfont_clipboard_get(&text_buf, NULL, &len_utf8, NULL);
- return OPERATOR_FINISHED;
+ if (text_buf) {
+ clipboard_vfont.buf = MEM_mallocN(len_utf8 + 1, __func__);
+
+ if (clipboard_vfont.buf == NULL) {
+ MEM_freeN(clipboard_system.buf);
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_strncpy_wchar_as_utf8(clipboard_vfont.buf, text_buf, len_utf8 + 1);
+ }
+
+ if (clipboard_vfont.buf && STREQ(clipboard_vfont.buf, clipboard_system.buf)) {
+ retval = paste_selection(obedit, op->reports) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+ else {
+ if ((clipboard_system.len <= MAXTEXT) &&
+ font_paste_utf8(C, clipboard_system.buf, clipboard_system.len))
+ {
+ text_update_edited(C, obedit, FO_EDIT);
+ retval = OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Clipboard too long");
+ retval = OPERATOR_CANCELLED;
+ }
+
+ /* free the existent clipboard buffer */
+ BKE_vfont_clipboard_free();
+ }
+
+ if (retval != OPERATOR_CANCELLED) {
+ text_update_edited(C, obedit, FO_EDIT);
+ }
+
+ /* cleanup */
+ if (clipboard_vfont.buf) {
+ MEM_freeN(clipboard_vfont.buf);
+ }
+
+ MEM_freeN(clipboard_system.buf);
+
+ return retval;
}
void FONT_OT_text_paste(wmOperatorType *ot)
@@ -1509,7 +1480,7 @@ void FONT_OT_textbox_remove(wmOperatorType *ot)
/***************** editmode enter/exit ********************/
-void make_editText(Object *obedit)
+void ED_curve_editfont_make(Object *obedit)
{
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
@@ -1520,8 +1491,6 @@ void make_editText(Object *obedit)
ef->textbuf = MEM_callocN((MAXTEXT + 4) * sizeof(wchar_t), "texteditbuf");
ef->textbufinfo = MEM_callocN((MAXTEXT + 4) * sizeof(CharInfo), "texteditbufinfo");
- ef->copybuf = MEM_callocN((MAXTEXT + 4) * sizeof(wchar_t), "texteditcopybuf");
- ef->copybufinfo = MEM_callocN((MAXTEXT + 4) * sizeof(CharInfo), "texteditcopybufinfo");
}
/* Convert the original text to wchar_t */
@@ -1545,7 +1514,7 @@ void make_editText(Object *obedit)
BKE_vfont_select_clamp(obedit);
}
-void load_editText(Object *obedit)
+void ED_curve_editfont_load(Object *obedit)
{
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
@@ -1574,7 +1543,7 @@ void load_editText(Object *obedit)
cu->selend = ef->selend;
}
-void free_editText(Object *obedit)
+void ED_curve_editfont_free(Object *obedit)
{
BKE_curve_editfont_free((Curve *)obedit->data);
}
@@ -1727,7 +1696,7 @@ static int font_open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- font->id.us--;
+ id_us_min(&font->id);
RNA_id_pointer_create(&font->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
@@ -1784,8 +1753,9 @@ void FONT_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_FTFONT, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_FTFONT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************* delete operator *********************/
@@ -1885,7 +1855,7 @@ void undo_push_font(bContext *C, const char *name)
/**
* TextBox selection
*/
-bool mouse_font(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_curve_editfont_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript
deleted file mode 100644
index 6bc8f21e384..00000000000
--- a/source/blender/editors/datafiles/SConscript
+++ /dev/null
@@ -1,113 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-# all source generated now
-# sources = env.Glob('*.c')
-sources = []
-incs = []
-defs = []
-
-# generated data files
-import os
-sources.extend((
- os.path.join(env['DATA_SOURCES'], "bfont.pfb.c"),
- os.path.join(env['DATA_SOURCES'], "bfont.ttf.c"),
- os.path.join(env['DATA_SOURCES'], "bmonofont.ttf.c"),
-
- os.path.join(env['DATA_SOURCES'], "splash.png.c"),
- os.path.join(env['DATA_SOURCES'], "splash_2x.png.c"),
- os.path.join(env['DATA_SOURCES'], "blender_icons16.png.c"),
- os.path.join(env['DATA_SOURCES'], "blender_icons32.png.c"),
- os.path.join(env['DATA_SOURCES'], "prvicons.png.c"),
-
- os.path.join(env['DATA_SOURCES'], "startup.blend.c"),
- os.path.join(env['DATA_SOURCES'], "preview.blend.c"),
- os.path.join(env['DATA_SOURCES'], "preview_cycles.blend.c"),
-
- os.path.join(env['DATA_SOURCES'], "add.png.c"),
- os.path.join(env['DATA_SOURCES'], "blob.png.c"),
- os.path.join(env['DATA_SOURCES'], "blur.png.c"),
- os.path.join(env['DATA_SOURCES'], "clay.png.c"),
- os.path.join(env['DATA_SOURCES'], "claystrips.png.c"),
- os.path.join(env['DATA_SOURCES'], "clone.png.c"),
- os.path.join(env['DATA_SOURCES'], "crease.png.c"),
- os.path.join(env['DATA_SOURCES'], "darken.png.c"),
- os.path.join(env['DATA_SOURCES'], "draw.png.c"),
- os.path.join(env['DATA_SOURCES'], "fill.png.c"),
- os.path.join(env['DATA_SOURCES'], "flatten.png.c"),
- os.path.join(env['DATA_SOURCES'], "grab.png.c"),
- os.path.join(env['DATA_SOURCES'], "inflate.png.c"),
- os.path.join(env['DATA_SOURCES'], "layer.png.c"),
- os.path.join(env['DATA_SOURCES'], "lighten.png.c"),
- os.path.join(env['DATA_SOURCES'], "mask.png.c"),
- os.path.join(env['DATA_SOURCES'], "mix.png.c"),
- os.path.join(env['DATA_SOURCES'], "multiply.png.c"),
- os.path.join(env['DATA_SOURCES'], "nudge.png.c"),
- os.path.join(env['DATA_SOURCES'], "pinch.png.c"),
- os.path.join(env['DATA_SOURCES'], "scrape.png.c"),
- os.path.join(env['DATA_SOURCES'], "smear.png.c"),
- os.path.join(env['DATA_SOURCES'], "smooth.png.c"),
- os.path.join(env['DATA_SOURCES'], "snake_hook.png.c"),
- os.path.join(env['DATA_SOURCES'], "soften.png.c"),
- os.path.join(env['DATA_SOURCES'], "subtract.png.c"),
- os.path.join(env['DATA_SOURCES'], "texdraw.png.c"),
- os.path.join(env['DATA_SOURCES'], "texfill.png.c"),
- os.path.join(env['DATA_SOURCES'], "texmask.png.c"),
- os.path.join(env['DATA_SOURCES'], "thumb.png.c"),
- os.path.join(env['DATA_SOURCES'], "twist.png.c"),
- os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"),
-
- os.path.join(env['DATA_SOURCES'], "mc01.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc02.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc03.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc04.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc05.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc06.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc07.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc08.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc09.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc10.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc11.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc12.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc13.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc14.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc15.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc16.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc17.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc18.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc19.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc20.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc21.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc22.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc23.jpg.c"),
- os.path.join(env['DATA_SOURCES'], "mc24.jpg.c"),
-
- ))
-
-env.BlenderLib ( 'bf_editor_datafiles', sources, incs, defs, libtype=['core', 'player'], priority=[235, 30] )
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 83a13abb33f..6604d595573 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -40,6 +40,7 @@ set(INC_SYS
set(SRC
drawgpencil.c
editaction_gpencil.c
+ gpencil_brush.c
gpencil_convert.c
gpencil_data.c
gpencil_edit.c
diff --git a/source/blender/editors/gpencil/SConscript b/source/blender/editors/gpencil/SConscript
deleted file mode 100644
index 3830a164b7b..00000000000
--- a/source/blender/editors/gpencil/SConscript
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/elbeem/extern',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_gpencil', sources, incs, defs, libtype=['core'], priority=[45])
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 6b71c0ac053..b5d9283f6c6 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -105,9 +105,9 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
return;
- /* if drawing a single point, draw it larger */
if (totpoints == 1) {
- /* draw point */
+ /* if drawing a single point, draw it larger */
+ glPointSize((float)(thickness + 2) * points->pressure);
glBegin(GL_POINTS);
glVertex2iv(&points->x);
glEnd();
@@ -145,9 +145,6 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
glVertex2iv(&pt->x);
}
glEnd();
-
- /* reset for predictable OpenGL context */
- glLineWidth(1.0f);
if (G.debug & G_DEBUG) setlinestyle(0);
}
@@ -996,7 +993,7 @@ static void gp_draw_data_layers(bGPdata *gpd, int offsx, int offsy, int winx, in
/* fill strokes... */
// XXX: this is not a very good limit
- GP_DRAWFLAG_APPLY((gpl->fill[3] > 0.001f), GP_DRAWDATA_FILL);
+ GP_DRAWFLAG_APPLY((gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH), GP_DRAWDATA_FILL);
#undef GP_DRAWFLAG_APPLY
/* draw 'onionskins' (frame left + right) */
@@ -1111,13 +1108,7 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
*/
/* turn on alpha-blending */
- if (GLEW_VERSION_1_4) {
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- }
- else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
/* draw! */
@@ -1128,8 +1119,6 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
glDisable(GL_LINE_SMOOTH); // smooth lines
/* restore initial gl conditions */
- glLineWidth(1.0);
- glPointSize(1.0);
glColor4f(0, 0, 0, 1);
}
@@ -1172,6 +1161,7 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i
/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
void ED_gpencil_draw_2dimage(const bContext *C)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -1224,6 +1214,13 @@ void ED_gpencil_draw_2dimage(const bContext *C)
break;
}
+ if (ED_screen_animation_playing(wm)) {
+ /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
+ * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
+ */
+ dflag |= GP_DRAWDATA_NO_ONIONS;
+ }
+
/* draw it! */
gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
@@ -1234,6 +1231,7 @@ void ED_gpencil_draw_2dimage(const bContext *C)
* second time with onlyv2d=0 for screen-aligned strokes */
void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -1252,6 +1250,8 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
/* draw it! */
if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS);
+ if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS;
+
gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype);
/* draw status text (if in screen/pixel-space) */
@@ -1263,7 +1263,7 @@ void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
* Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
* second time with only3d=0 for screen-aligned strokes */
-void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
+void ED_gpencil_draw_view3d(wmWindowManager *wm, Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
{
bGPdata *gpd;
int dflag = 0;
@@ -1306,13 +1306,15 @@ void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
dflag |= GP_DRAWDATA_NOSTATUS;
}
+ if ((wm == NULL) || ED_screen_animation_playing(wm)) {
+ /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses)
+ * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes)
+ */
+ dflag |= GP_DRAWDATA_NO_ONIONS;
+ }
+
/* draw it! */
gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (only3d == false) {
- gp_draw_status_text(gpd, ar);
- }
}
void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index a2ba6216f9c..09a72c10457 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -44,11 +44,15 @@
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
+#include "BKE_report.h"
+#include "ED_anim_api.h"
#include "ED_gpencil.h"
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
+#include "WM_api.h"
+
/* ***************************************** */
/* NOTE ABOUT THIS FILE:
* This file contains code for editing Grease Pencil data in the Action Editor
@@ -268,7 +272,7 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
}
}
-#if 0 // XXX disabled until grease pencil code stabilises again
+
/* -------------------------------------- */
/* Copy and Paste Tools */
/* - The copy/paste buffer currently stores a set of GP_Layers, with temporary
@@ -280,118 +284,155 @@ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
*/
/* globals for copy/paste data (like for other copy/paste buffers) */
-ListBase gpcopybuf = {NULL, NULL};
-static int gpcopy_firstframe = 999999999;
+ListBase gp_anim_copybuf = {NULL, NULL};
+static int gp_anim_copy_firstframe = 999999999;
+static int gp_anim_copy_lastframe = -999999999;
+static int gp_anim_copy_cfra = 0;
+
/* This function frees any MEM_calloc'ed copy/paste buffer data */
-void free_gpcopybuf()
+void ED_gpencil_anim_copybuf_free(void)
{
- free_gpencil_layers(&gpcopybuf);
+ free_gpencil_layers(&gp_anim_copybuf);
+ BLI_listbase_clear(&gp_anim_copybuf);
- BLI_listbase_clear(&gpcopybuf);
- gpcopy_firstframe = 999999999;
+ gp_anim_copy_firstframe = 999999999;
+ gp_anim_copy_lastframe = -999999999;
+ gp_anim_copy_cfra = 0;
}
+
/* This function adds data to the copy/paste buffer, freeing existing data first
* Only the selected GP-layers get their selected keyframes copied.
+ *
+ * Returns whether the copy operation was successful or not
*/
-void copy_gpdata()
+bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
{
- ListBase act_data = {NULL, NULL};
- bActListElem *ale;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
int filter;
- void *data;
- short datatype;
- /* clear buffer first */
- free_gpcopybuf();
+ Scene *scene = ac->scene;
- /* get data */
- data = get_action_context(&datatype);
- if (data == NULL) return;
- if (datatype != ACTCONT_GPENCIL) return;
- /* filter data */
- filter = (ACTFILTER_VISIBLE | ACTFILTER_SEL);
- actdata_filter(&act_data, filter, data, datatype);
+ /* clear buffer first */
+ ED_gpencil_anim_copybuf_free();
- /* assume that each of these is an ipo-block */
- for (ale = act_data.first; ale; ale = ale->next) {
- bGPDlayer *gpls, *gpln;
- bGPDframe *gpf, *gpfn;
-
- /* get new layer to put into buffer */
- gpls = (bGPDlayer *)ale->data;
- gpln = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
-
- BLI_listbase_clear(&gpln->frames);
- BLI_strncpy(gpln->info, gpls->info, sizeof(gpln->info));
-
- BLI_addtail(&gpcopybuf, gpln);
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* assume that each of these is a GP layer */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ ListBase copied_frames = {NULL, NULL};
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ bGPDframe *gpf;
/* loop over frames, and copy only selected frames */
- for (gpf = gpls->frames.first; gpf; gpf = gpf->next) {
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
/* if frame is selected, make duplicate it and its strokes */
if (gpf->flag & GP_FRAME_SELECT) {
- /* add frame to buffer */
- gpfn = gpencil_frame_duplicate(gpf);
- BLI_addtail(&gpln->frames, gpfn);
+ /* make a copy of this frame */
+ bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
+ BLI_addtail(&copied_frames, new_frame);
- /* check if this is the earliest frame encountered so far */
- if (gpf->framenum < gpcopy_firstframe)
- gpcopy_firstframe = gpf->framenum;
+ /* extend extents for keyframes encountered */
+ if (gpf->framenum < gp_anim_copy_firstframe)
+ gp_anim_copy_firstframe = gpf->framenum;
+ if (gpf->framenum > gp_anim_copy_lastframe)
+ gp_anim_copy_lastframe = gpf->framenum;
}
}
+
+ /* create a new layer in buffer if there were keyframes here */
+ if (BLI_listbase_is_empty(&copied_frames) == false) {
+ bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
+ BLI_addtail(&gp_anim_copybuf, new_layer);
+
+ /* move over copied frames */
+ BLI_movelisttolist(&new_layer->frames, &copied_frames);
+ BLI_assert(copied_frames.first == NULL);
+
+ /* make a copy of the layer's name - for name-based matching later... */
+ BLI_strncpy(new_layer->info, gpl->info, sizeof(new_layer->info));
+ }
}
+ /* in case 'relative' paste method is used */
+ gp_anim_copy_cfra = CFRA;
+
+ /* clean up */
+ ANIM_animdata_freelist(&anim_data);
+
/* check if anything ended up in the buffer */
- if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last))
- error("Nothing copied to buffer");
+ if (ELEM(NULL, gp_anim_copybuf.first, gp_anim_copybuf.last)) {
+ BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
+ return false;
+ }
- /* free temp memory */
- BLI_freelistN(&act_data);
+ /* report success */
+ return true;
}
-void paste_gpdata(Scene *scene)
+
+/* Pastes keyframes from buffer, and reports success */
+bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
{
- ListBase act_data = {NULL, NULL};
- bActListElem *ale;
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
int filter;
- void *data;
- short datatype;
- const int offset = (CFRA - gpcopy_firstframe);
- short no_name = 0;
+ Scene *scene = ac->scene;
+ bool no_name = false;
+ int offset = 0;
/* check if buffer is empty */
- if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) {
- error("No data in buffer to paste");
- return;
+ if (BLI_listbase_is_empty(&gp_anim_copybuf)) {
+ BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste");
+ return false;
}
+
/* check if single channel in buffer (disregard names if so) */
- if (gpcopybuf.first == gpcopybuf.last)
- no_name = 1;
+ if (gp_anim_copybuf.first == gp_anim_copybuf.last) {
+ no_name = true;
+ }
- /* get data */
- data = get_action_context(&datatype);
- if (data == NULL) return;
- if (datatype != ACTCONT_GPENCIL) return;
+ /* methods of offset (eKeyPasteOffset) */
+ switch (offset_mode) {
+ case KEYFRAME_PASTE_OFFSET_CFRA_START:
+ offset = (CFRA - gp_anim_copy_firstframe);
+ break;
+ case KEYFRAME_PASTE_OFFSET_CFRA_END:
+ offset = (CFRA - gp_anim_copy_lastframe);
+ break;
+ case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
+ offset = (CFRA - gp_anim_copy_cfra);
+ break;
+ case KEYFRAME_PASTE_OFFSET_NONE:
+ offset = 0;
+ break;
+ }
+
/* filter data */
- filter = (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT);
- actdata_filter(&act_data, filter, data, datatype);
+ // TODO: try doing it with selection, then without selection imits
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* from selected channels */
- for (ale = act_data.first; ale; ale = ale->next) {
+ for (ale = anim_data.first; ale; ale = ale->next) {
bGPDlayer *gpld = (bGPDlayer *)ale->data;
bGPDlayer *gpls = NULL;
bGPDframe *gpfs, *gpf;
+
/* find suitable layer from buffer to use to paste from */
- for (gpls = gpcopybuf.first; gpls; gpls = gpls->next) {
+ for (gpls = gp_anim_copybuf.first; gpls; gpls = gpls->next) {
/* check if layer name matches */
- if ((no_name) || STREQ(gpls->info, gpld->info))
+ if ((no_name) || STREQ(gpls->info, gpld->info)) {
break;
+ }
}
/* this situation might occur! */
@@ -407,58 +448,21 @@ void paste_gpdata(Scene *scene)
gpf = gpencil_layer_getframe(gpld, gpfs->framenum, 1);
if (gpf) {
bGPDstroke *gps, *gpsn;
- ScrArea *sa;
-
- /* get area that gp-data comes from */
- //sa = gpencil_data_findowner((bGPdata *)ale->owner);
- sa = NULL;
- /* this should be the right frame... as it may be a pre-existing frame,
+ /* This should be the right frame... as it may be a pre-existing frame,
* must make sure that only compatible stroke types get copied over
- * - we cannot just add a duplicate frame, as that would cause errors
- * - need to check for compatible types to minimize memory usage (copying 'junk' over)
+ * - We cannot just add a duplicate frame, as that would cause errors
+ * - For now, we don't check if the types will be compatible since we
+ * don't have enough info to do so. Instead, we simply just paste,
+ * af it works, it will show up.
*/
for (gps = gpfs->strokes.first; gps; gps = gps->next) {
- short stroke_ok;
+ /* make a copy of stroke, then of its points array */
+ gpsn = MEM_dupallocN(gps);
+ gpsn->points = MEM_dupallocN(gps->points);
- /* if there's an area, check that it supports this type of stroke */
- if (sa) {
- stroke_ok = 0;
-
- /* check if spacetype supports this type of stroke
- * - NOTE: must sync this with gp_paint_initstroke() in gpencil.c
- */
- switch (sa->spacetype) {
- case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */
- if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE))
- stroke_ok = 1;
- break;
-
- case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */
- case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */
- case SPACE_CLIP: /* Image Editor: either screen-aligned or view\image-aligned */
- if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE))
- stroke_ok = 1;
- break;
-
- case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */
- if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE))
- stroke_ok = 1;
- break;
- }
- }
- else
- stroke_ok = 1;
-
- /* if stroke is ok, we make a copy of this stroke and add to frame */
- if (stroke_ok) {
- /* make a copy of stroke, then of its points array */
- gpsn = MEM_dupallocN(gps);
- gpsn->points = MEM_dupallocN(gps->points);
-
- /* append stroke to frame */
- BLI_addtail(&gpf->strokes, gpsn);
- }
+ /* append stroke to frame */
+ BLI_addtail(&gpf->strokes, gpsn);
}
/* if no strokes (i.e. new frame) added, free gpf */
@@ -471,13 +475,10 @@ void paste_gpdata(Scene *scene)
}
}
- /* free temp memory */
- BLI_freelistN(&act_data);
-
- /* undo and redraw stuff */
- BIF_undo_push("Paste Grease Pencil Frames");
+ /* clean up */
+ ANIM_animdata_freelist(&anim_data);
+ return true;
}
-#endif /* XXX disabled until Grease Pencil code stabilises again... */
/* -------------------------------------- */
/* Snap Tools */
@@ -534,7 +535,6 @@ void ED_gplayer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
}
}
-#if 0 /* XXX disabled until grease pencil code stabilises again */
/* -------------------------------------- */
/* Mirror Tools */
@@ -544,13 +544,13 @@ static short mirror_gpf_cframe(bGPDframe *gpf, Scene *scene)
if (gpf->flag & GP_FRAME_SELECT) {
diff = CFRA - gpf->framenum;
- gpf->framenum = CFRA;
+ gpf->framenum = CFRA + diff;
}
return 0;
}
-static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *scene)
+static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *UNUSED(scene))
{
int diff;
@@ -562,10 +562,11 @@ static short mirror_gpf_yaxis(bGPDframe *gpf, Scene *scene)
return 0;
}
-static short mirror_gpf_xaxis(bGPDframe *gpf, Scene *scene)
+static short mirror_gpf_xaxis(bGPDframe *gpf, Scene *UNUSED(scene))
{
int diff;
+ /* NOTE: since we can't really do this, we just do the same as for yaxis... */
if (gpf->flag & GP_FRAME_SELECT) {
diff = -gpf->framenum;
gpf->framenum = diff;
@@ -616,19 +617,20 @@ static short mirror_gpf_marker(bGPDframe *gpf, Scene *scene)
/* mirror selected gp-frames on... */
-void mirror_gplayer_frames(bGPDlayer *gpl, Scene *scene, short mode)
+// TODO: mirror over a specific time
+void ED_gplayer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
{
switch (mode) {
- case 1: /* mirror over current frame */
+ case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
ED_gplayer_frames_looper(gpl, scene, mirror_gpf_cframe);
break;
- case 2: /* mirror over frame 0 */
+ case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
ED_gplayer_frames_looper(gpl, scene, mirror_gpf_yaxis);
break;
- case 3: /* mirror over value 0 */
+ case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
ED_gplayer_frames_looper(gpl, scene, mirror_gpf_xaxis);
break;
- case 4: /* mirror over marker */
+ case MIRROR_KEYS_MARKER: /* mirror over marker */
mirror_gpf_marker(NULL, NULL);
ED_gplayer_frames_looper(gpl, scene, mirror_gpf_marker);
mirror_gpf_marker(NULL, NULL);
@@ -640,4 +642,3 @@ void mirror_gplayer_frames(bGPDlayer *gpl, Scene *scene, short mode)
}
/* ***************************************** */
-#endif // XXX disabled until Grease Pencil code stabilises again...
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
new file mode 100644
index 00000000000..43751dbadb9
--- /dev/null
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -0,0 +1,1688 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Brush based operators for editing Grease Pencil strokes
+ */
+
+/** \file blender/editors/gpencil/gpencil_brush.c
+ * \ingroup edgpencil
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_gpencil_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_library.h"
+#include "BKE_report.h"
+#include "BKE_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "UI_view2d.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "gpencil_intern.h"
+
+/* ************************************************ */
+/* General Brush Editing Context */
+
+/* Context for brush operators */
+typedef struct tGP_BrushEditData {
+ /* Current editor/region/etc. */
+ /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
+ Scene *scene;
+
+ ScrArea *sa;
+ ARegion *ar;
+
+ /* Current GPencil datablock */
+ bGPdata *gpd;
+
+ /* Brush Settings */
+ GP_BrushEdit_Settings *settings;
+ GP_EditBrush_Data *brush;
+
+ eGP_EditBrush_Types brush_type;
+ eGP_EditBrush_Flag flag;
+
+ /* Space Conversion Data */
+ GP_SpaceConversion gsc;
+
+
+ /* Is the brush currently painting? */
+ bool is_painting;
+
+ /* Start of new sculpt stroke */
+ bool first;
+
+ /* Current frame */
+ int cfra;
+
+
+ /* Brush Runtime Data: */
+ /* - position and pressure
+ * - the *_prev variants are the previous values
+ */
+ int mval[2], mval_prev[2];
+ float pressure, pressure_prev;
+
+ /* - effect vector (e.g. 2D/3D translation for grab brush) */
+ float dvec[3];
+
+ /* brush geometry (bounding box) */
+ rcti brush_rect;
+
+ /* Custom data for certain brushes */
+ /* - map from bGPDstroke's to structs containing custom data about those strokes */
+ GHash *stroke_customdata;
+ /* - general customdata */
+ void *customdata;
+
+
+ /* Timer for in-place accumulation of brush effect */
+ wmTimer *timer;
+ bool timerTick; /* is this event from a timer */
+} tGP_BrushEditData;
+
+
+/* Callback for performing some brush operation on a single point */
+typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2]);
+
+/* ************************************************ */
+/* Utility Functions */
+
+/* Context ---------------------------------------- */
+
+/* Get the sculpting settings */
+static GP_BrushEdit_Settings *gpsculpt_get_settings(Scene *scene)
+{
+ return &scene->toolsettings->gp_sculpt;
+}
+
+/* Get the active brush */
+static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene)
+{
+ GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt;
+ return &gset->brush[gset->brushtype];
+}
+
+/* Brush Operations ------------------------------- */
+
+/* Invert behaviour of brush? */
+static bool gp_brush_invert_check(tGP_BrushEditData *gso)
+{
+ /* The basic setting is the brush's setting (from the panel) */
+ bool invert = ((gso->brush->flag & GP_EDITBRUSH_FLAG_INVERT) != 0);
+
+ /* During runtime, the user can hold down the Ctrl key to invert the basic behaviour */
+ if (gso->flag & GP_EDITBRUSH_FLAG_INVERT) {
+ invert ^= true;
+ }
+
+ return invert;
+}
+
+/* Compute strength of effect */
+static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
+{
+ GP_EditBrush_Data *brush = gso->brush;
+
+ /* basic strength factor from brush settings */
+ float influence = brush->strength;
+
+ /* use pressure? */
+ if (brush->flag & GP_EDITBRUSH_FLAG_USE_PRESSURE) {
+ influence *= gso->pressure;
+ }
+
+ /* distance fading */
+ if (brush->flag & GP_EDITBRUSH_FLAG_USE_FALLOFF) {
+ float distance = (float)len_v2v2_int(gso->mval, co);
+ float fac;
+
+ CLAMP(distance, 0.0f, (float)radius);
+ fac = 1.0f - (distance / (float)radius);
+
+ influence *= fac;
+ }
+
+ /* return influence */
+ return influence;
+}
+
+/* ************************************************ */
+/* Brush Callbacks */
+/* This section defines the callbacks used by each brush to perform their magic.
+ * These are called on each point within the brush's radius.
+ */
+
+/* ----------------------------------------------- */
+/* Smooth Brush */
+
+/* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */
+static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ GP_EditBrush_Data *brush = gso->brush;
+ float inf = gp_brush_influence_calc(gso, radius, co);
+ bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0;
+
+ /* perform smoothing */
+ return gp_smooth_stroke(gps, i, inf, affect_pressure);
+}
+
+/* ----------------------------------------------- */
+/* Line Thickness Brush */
+
+/* Make lines thicker or thinner by the specified amounts */
+static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* apply */
+ // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
+ if (gp_brush_invert_check(gso)) {
+ /* make line thinner - reduce stroke pressure */
+ pt->pressure -= inf;
+ }
+ else {
+ /* make line thicker - increase stroke pressure */
+ pt->pressure += inf;
+ }
+
+ /* Pressure should stay within [0.0, 1.0]
+ * However, it is nice for volumetric strokes to be able to exceed
+ * the upper end of this range. Therefore, we don't actually clamp
+ * down on the upper end.
+ */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
+}
+
+
+/* ----------------------------------------------- */
+/* Grab Brush */
+
+/* Custom data per stroke for the Grab Brush
+ *
+ * This basically defines the strength of the effect for each
+ * affected stroke point that was within the initial range of
+ * the brush region.
+ */
+typedef struct tGPSB_Grab_StrokeData {
+ /* array of indices to corresponding points in the stroke */
+ int *points;
+ /* array of influence weights for each of the included points */
+ float *weights;
+
+ /* capacity of the arrays */
+ int capacity;
+ /* actual number of items currently stored */
+ int size;
+} tGPSB_Grab_StrokeData;
+
+/* initialise custom data for handling this stroke */
+static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
+{
+ tGPSB_Grab_StrokeData *data = NULL;
+
+ BLI_assert(gps->totpoints > 0);
+
+ /* Check if there are buffers already (from a prior run) */
+ if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
+ /* Ensure that the caches are empty
+ * - Since we reuse these between different strokes, we don't
+ * want the previous invocation's data polluting the arrays
+ */
+ data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ BLI_assert(data != NULL);
+
+ data->size = 0; /* minimum requirement - so that we can repopulate again */
+
+ memset(data->points, 0, sizeof(int) * data->capacity);
+ memset(data->weights, 0, sizeof(float) * data->capacity);
+ }
+ else {
+ /* Create new instance */
+ data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
+
+ data->capacity = gps->totpoints;
+ data->size = 0;
+
+ data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
+ data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
+
+ /* hook up to the cache */
+ BLI_ghash_insert(gso->stroke_customdata, gps, data);
+ }
+}
+
+/* store references to stroke points in the initial stage */
+static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ float inf = gp_brush_influence_calc(gso, radius, co);
+
+ BLI_assert(data != NULL);
+ BLI_assert(data->size < data->capacity);
+
+ /* insert this point into the set of affected points */
+ data->points[data->size] = i;
+ data->weights[data->size] = inf;
+ data->size++;
+
+ /* done */
+ return true;
+}
+
+/* Compute effect vector for grab brush */
+static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
+{
+ /* Convert mouse-movements to movement vector */
+ // TODO: incorporate pressure into this?
+ // XXX: screen-space strokes in 3D space will suffer!
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = gso->sa->spacedata.first;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d);
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2];
+
+ /* convert from 2D screenspace to 3D... */
+ mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac);
+ }
+ else {
+ /* 2D - just copy */
+ // XXX: view2d?
+ gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+ gso->dvec[2] = 0.0f; /* unused */
+ }
+}
+
+/* Apply grab transform to all relevant points of the affected strokes */
+static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps)
+{
+ tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ int i;
+
+ /* Apply dvec to all of the stored points */
+ for (i = 0; i < data->size; i++) {
+ bGPDspoint *pt = &gps->points[data->points[i]];
+ float delta[3] = {0.0f};
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
+
+ /* apply */
+ add_v3_v3(&pt->x, delta);
+ }
+}
+
+/* free customdata used for handling this stroke */
+static void gp_brush_grab_stroke_free(void *ptr)
+{
+ tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr;
+
+ /* free arrays */
+ MEM_freeN(data->points);
+ MEM_freeN(data->weights);
+
+ /* ... and this item itself, since it was also allocated */
+ MEM_freeN(data);
+}
+
+/* ----------------------------------------------- */
+/* Push Brush */
+/* NOTE: Depends on gp_brush_grab_calc_dvec() */
+
+static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+ float inf = gp_brush_influence_calc(gso, radius, co);
+ float delta[3] = {0.0f};
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, inf);
+
+ /* apply */
+ add_v3_v3(&pt->x, delta);
+
+ /* done */
+ return true;
+}
+
+/* ----------------------------------------------- */
+/* Pinch Brush */
+
+/* Compute reference midpoint for the brush - this is what we'll be moving towards */
+static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
+{
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ /* Convert mouse position to 3D space
+ * See: gpencil_paint.c :: gp_stroke_convertcoords()
+ */
+ View3D *v3d = gso->sa->spacedata.first;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d);
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2] = {UNPACK2(gso->mval)};
+ float mval_prj[2];
+ float dvec[3];
+
+
+ if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(gso->dvec, rvec, dvec);
+ }
+ else {
+ zero_v3(gso->dvec);
+ }
+ }
+ else {
+ /* Just 2D coordinates */
+ // XXX: fix View2D offsets later
+ gso->dvec[0] = (float)gso->mval[0];
+ gso->dvec[1] = (float)gso->mval[1];
+ gso->dvec[2] = 0.0f;
+ }
+}
+
+/* Shrink distance between midpoint and this point... */
+static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+ float fac, inf;
+ float vec[3];
+
+ /* Scale down standard influence value to get it more manageable...
+ * - No damping = Unmanageable at > 0.5 strength
+ * - Div 10 = Not enough effect
+ * - Div 5 = Happy medium... (by trial and error)
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 5.0f;
+
+ /* 1) Make this point relative to the cursor/midpoint (dvec) */
+ sub_v3_v3v3(vec, &pt->x, gso->dvec);
+
+ /* 2) Shrink the distance by pulling the point towards the midpoint
+ * (0.0 = at midpoint, 1 = at edge of brush region)
+ * OR
+ * Increase the distance (if inverting the brush action!)
+ */
+ if (gp_brush_invert_check(gso)) {
+ /* Inflate (inverse) */
+ fac = 1.0f + (inf * inf); /* squared to temper the effect... */
+ }
+ else {
+ /* Shrink (default) */
+ fac = 1.0f - (inf * inf); /* squared to temper the effect... */
+ }
+ mul_v3_fl(vec, fac);
+
+ /* 3) Translate back to original space, with the shrinkage applied */
+ add_v3_v3v3(&pt->x, gso->dvec, vec);
+
+ /* done */
+ return true;
+}
+
+/* ----------------------------------------------- */
+/* Twist Brush - Rotate Around midpoint */
+
+/* Take the screenspace coordinates of the point, rotate this around the brush midpoint,
+ * convert the rotated point and convert it into "data" space
+ */
+
+static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+ float angle, inf;
+
+ /* Angle to rotate by */
+ inf = gp_brush_influence_calc(gso, radius, co);
+ angle = DEG2RADF(1.0f) * inf;
+
+ if (gp_brush_invert_check(gso)) {
+ /* invert angle that we rotate by */
+ angle *= -1;
+ }
+
+ /* Rotate in 2D or 3D space? */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* Perform rotation in 3D space... */
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float rmat[3][3];
+ float axis[3];
+ float vec[3];
+
+ /* Compute rotation matrix - rotate around view vector by angle */
+ negate_v3_v3(axis, rv3d->persinv[2]);
+ normalize_v3(axis);
+
+ axis_angle_normalized_to_mat3(rmat, axis, angle);
+
+ /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */
+ sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */
+ mul_m3_v3(rmat, vec);
+ add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
+ }
+ else {
+ const float axis[3] = {0.0f, 0.0f, 1.0f};
+ float vec[3] = {0.0f};
+ float rmat[3][3];
+
+ /* Express position of point relative to cursor, ready to rotate */
+ // XXX: There is still some offset here, but it's close to working as expected...
+ vec[0] = (float)(co[0] - gso->mval[0]);
+ vec[1] = (float)(co[1] - gso->mval[1]);
+
+ /* rotate point */
+ axis_angle_normalized_to_mat3(rmat, axis, angle);
+ mul_m3_v3(rmat, vec);
+
+ /* Convert back to screen-coordinates */
+ vec[0] += (float)gso->mval[0];
+ vec[1] += (float)gso->mval[1];
+
+ /* Map from screen-coordinates to final coordinate space */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = gso->gsc.v2d;
+ UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
+ }
+ else {
+ // XXX
+ copy_v2_v2(&pt->x, vec);
+ }
+ }
+
+ /* done */
+ return true;
+}
+
+
+/* ----------------------------------------------- */
+/* Randomize Brush */
+
+/* Apply some random jitter to the point */
+static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i,
+ const int radius, const int co[2])
+{
+ bGPDspoint *pt = gps->points + i;
+
+ /* Amount of jitter to apply depends on the distance of the point to the cursor,
+ * as well as the strength of the brush
+ */
+ const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
+ const float fac = BLI_frand() * inf;
+
+ /* Jitter is applied perpendicular to the mouse movement vector
+ * - We compute all effects in screenspace (since it's easier)
+ * and then project these to get the points/distances in
+ * viewspace as needed
+ */
+ float mvec[2], svec[2];
+
+ /* mouse movement in ints -> floats */
+ mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+
+ //printf("svec = %f %f, ", svec[0], svec[1]);
+
+ /* scale the displacement by the random displacement, and apply */
+ if (BLI_frand() > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
+
+ /* convert to dataspace */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D: Project to 3D space */
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ bool flip;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
+ if (flip == false) {
+ float dvec[3];
+ ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
+ add_v3_v3(&pt->x, dvec);
+ }
+ }
+ else {
+ /* ERROR */
+ BLI_assert("3D stroke being sculpted in non-3D view");
+ }
+ }
+ else {
+ /* 2D: As-is */
+ // XXX: v2d scaling/offset?
+ float nco[2];
+ nco[0] = (float)co[0] + svec[0];
+ nco[1] = (float)co[1] + svec[1];
+
+ copy_v2_v2(&pt->x, nco);
+ }
+
+ /* done */
+ return true;
+}
+
+/* ************************************************ */
+/* Non Callback-Based Brushes */
+
+/* Clone Brush ------------------------------------- */
+/* How this brush currently works:
+ * - If this is start of the brush stroke, paste immediately under the cursor
+ * by placing the midpoint of the buffer strokes under the cursor now
+ *
+ * - Otherwise, in:
+ * "Stamp Mode" - Move the newly pasted strokes so that their center follows the cursor
+ * "Continuous" - Repeatedly just paste new copies for where the brush is now
+ */
+
+/* Custom state data for clone brush */
+typedef struct tGPSB_CloneBrushData {
+ /* midpoint of the strokes on the clipboard */
+ float buffer_midpoint[3];
+
+ /* number of strokes in the paste buffer (and/or to be created each time) */
+ size_t totitems;
+
+ /* for "stamp" mode, the currently pasted brushes */
+ bGPDstroke **new_strokes;
+} tGPSB_CloneBrushData;
+
+/* Initialise "clone" brush data */
+static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
+{
+ tGPSB_CloneBrushData *data;
+ bGPDstroke *gps;
+
+ /* init custom data */
+ gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
+
+ /* compute midpoint of strokes on clipboard */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ const float dfac = 1.0f / ((float)gps->totpoints);
+ float mid[3] = {0.0f};
+
+ bGPDspoint *pt;
+ int i;
+
+ /* compute midpoint of this stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float co[3];
+
+ mul_v3_v3fl(co, &pt->x, dfac);
+ add_v3_v3(mid, co);
+ }
+
+ /* combine this stroke's data with the main data */
+ add_v3_v3(data->buffer_midpoint, mid);
+ data->totitems++;
+ }
+ }
+
+ /* Divide the midpoint by the number of strokes, to finish averaging it */
+ if (data->totitems > 1) {
+ mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
+ }
+
+ /* Create a buffer for storing the current strokes */
+ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
+ data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array");
+ }
+}
+
+/* Free custom data used for "clone" brush */
+static void gp_brush_clone_free(tGP_BrushEditData *gso)
+{
+ tGPSB_CloneBrushData *data = gso->customdata;
+
+ /* free strokes array */
+ if (data->new_strokes) {
+ MEM_freeN(data->new_strokes);
+ data->new_strokes = NULL;
+ }
+
+ /* free the customdata itself */
+ MEM_freeN(data);
+ gso->customdata = NULL;
+}
+
+/* Create new copies of the strokes on the clipboard */
+static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
+{
+ tGPSB_CloneBrushData *data = gso->customdata;
+
+ Scene *scene = gso->scene;
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, true);
+ bGPDstroke *gps;
+
+ float delta[3];
+ size_t strokes_added = 0;
+
+ /* Compute amount to offset the points by */
+ /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
+
+ gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
+ sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
+
+ /* Copy each stroke into the layer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ bGPDstroke *new_stroke;
+ bGPDspoint *pt;
+ int i;
+
+ /* Make a new stroke */
+ new_stroke = MEM_dupallocN(gps);
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+ new_stroke->next = new_stroke->prev = NULL;
+
+ BLI_addtail(&gpf->strokes, new_stroke);
+
+ /* Adjust all the stroke's points, so that the strokes
+ * get pasted relative to where the cursor is now
+ */
+ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
+ /* assume that the delta can just be applied, and then everything works */
+ add_v3_v3(&pt->x, delta);
+ }
+
+ /* Store ref for later */
+ if ((data->new_strokes) && (strokes_added < data->totitems)) {
+ data->new_strokes[strokes_added] = new_stroke;
+ strokes_added++;
+ }
+ }
+ }
+}
+
+/* Move newly-added strokes around - "Stamp" mode of the Clone brush */
+static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
+{
+ tGPSB_CloneBrushData *data = gso->customdata;
+ size_t snum;
+
+ /* Compute the amount of movement to apply (overwrites dvec) */
+ gp_brush_grab_calc_dvec(gso);
+
+ /* For each of the stored strokes, apply the offset to each point */
+ /* NOTE: Again this assumes that in the 3D view, we only have 3d space and not screenspace strokes... */
+ for (snum = 0; snum < data->totitems; snum++) {
+ bGPDstroke *gps = data->new_strokes[snum];
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (gso->brush->flag & GP_EDITBRUSH_FLAG_USE_FALLOFF) {
+ /* "Smudge" Effect when falloff is enabled */
+ float delta[3] = {0.0f};
+ int sco[2] = {0};
+ float influence;
+
+ /* compute influence on point */
+ gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
+ influence = gp_brush_influence_calc(gso, gso->brush->size, sco);
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, influence);
+
+ /* apply */
+ add_v3_v3(&pt->x, delta);
+ }
+ else {
+ /* Just apply the offset - All points move perfectly in sync with the cursor */
+ add_v3_v3(&pt->x, gso->dvec);
+ }
+ }
+ }
+}
+
+/* Entrypoint for applying "clone" brush */
+static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
+{
+ /* Which "mode" are we operating in? */
+ if (gso->first) {
+ /* Create initial clones */
+ gp_brush_clone_add(C, gso);
+ }
+ else {
+ /* Stamp or Continous Mode */
+ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
+ /* Stamp - Proceed to translate the newly added strokes */
+ gp_brush_clone_adjust(gso);
+ }
+ else {
+ /* Continuous - Just keep pasting everytime we move */
+ /* TODO: The spacing of repeat should be controlled using a "stepsize" or similar property? */
+ gp_brush_clone_add(C, gso);
+ }
+ }
+
+ return true;
+}
+
+/* ************************************************ */
+/* Cursor drawing */
+
+/* Helper callback for drawing the cursor itself */
+static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
+{
+ GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C));
+
+ if (brush) {
+ glPushMatrix();
+
+ glTranslatef((float)x, (float)y, 0.0f);
+
+ /* TODO: toggle between add and remove? */
+ glColor4ub(255, 255, 255, 128);
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ glutil_draw_lined_arc(0.0, M_PI * 2.0, brush->size, 40);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+
+ glPopMatrix();
+ }
+}
+
+/* Turn brush cursor in on/off */
+static void gpencil_toggle_brush_cursor(bContext *C, bool enable)
+{
+ GP_BrushEdit_Settings *gset = gpsculpt_get_settings(CTX_data_scene(C));
+
+ if (gset->paintcursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ gset->paintcursor = NULL;
+ }
+ else if (enable) {
+ /* enable cursor */
+ gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ NULL,
+ gp_brush_drawcursor, NULL);
+ }
+}
+
+
+/* ************************************************ */
+/* Header Info for GPencil Sculpt */
+
+static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
+{
+ const char *brush_name = NULL;
+ char str[256] = "";
+
+ RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
+
+ BLI_snprintf(str, sizeof(str),
+ IFACE_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
+ " | Ctrl to Invert Action | Wheel Up/Down for Size "
+ " | Shift-Wheel Up/Down for Strength"),
+ (brush_name) ? brush_name : "<?>");
+
+ ED_area_headerprint(CTX_wm_area(C), str);
+}
+
+/* ************************************************ */
+/* Grease Pencil Sculpting Operator */
+
+/* Init/Exit ----------------------------------------------- */
+
+static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ tGP_BrushEditData *gso;
+
+ /* setup operator data */
+ gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
+ op->customdata = gso;
+
+ /* store state */
+ gso->settings = gpsculpt_get_settings(scene);
+ gso->brush = gpsculpt_get_brush(scene);
+
+ gso->brush_type = gso->settings->brushtype;
+
+
+ gso->is_painting = false;
+ gso->first = true;
+
+ gso->gpd = ED_gpencil_data_get_active(C);
+ gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
+
+ gso->scene = scene;
+
+ gso->sa = CTX_wm_area(C);
+ gso->ar = CTX_wm_region(C);
+
+ /* initialise custom data for brushes */
+ switch (gso->brush_type) {
+ case GP_EDITBRUSH_TYPE_CLONE:
+ {
+ bGPDstroke *gps;
+ bool found = false;
+
+ /* check that there are some usable strokes in the buffer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* STOP HERE! Nothing to paste! */
+ BKE_report(op->reports, RPT_ERROR,
+ "Copy some strokes to the clipboard before using the Clone brush to paste copies of them");
+
+ MEM_freeN(gso);
+ op->customdata = NULL;
+ return false;
+ }
+ else {
+ /* initialise customdata */
+ gp_brush_clone_init(C, gso);
+ }
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_GRAB:
+ {
+ /* initialise the cache needed for this brush */
+ gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
+ break;
+ }
+
+ /* Others - No customdata needed */
+ default:
+ break;
+ }
+
+
+ /* setup space conversions */
+ gp_point_conversion_init(C, &gso->gsc);
+
+ /* update header */
+ gpsculpt_brush_header_set(C, gso);
+
+ /* setup cursor drawing */
+ WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ gpencil_toggle_brush_cursor(C, true);
+
+ return true;
+}
+
+static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
+{
+ tGP_BrushEditData *gso = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* free brush-specific data */
+ switch (gso->brush_type) {
+ case GP_EDITBRUSH_TYPE_GRAB:
+ {
+ /* Free per-stroke customdata
+ * - Keys don't need to be freed, as those are the strokes
+ * - Values assigned to those keys do, as they are custom structs
+ */
+ BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_CLONE:
+ {
+ /* Free customdata */
+ gp_brush_clone_free(gso);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* unregister timer (only used for realtime) */
+ if (gso->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
+ }
+
+ /* disable cursor and headerprints */
+ ED_area_headerprint(CTX_wm_area(C), NULL);
+ WM_cursor_modal_restore(win);
+ gpencil_toggle_brush_cursor(C, false);
+
+ /* free operator data */
+ MEM_freeN(gso);
+ op->customdata = NULL;
+}
+
+/* poll callback for stroke sculpting operator(s) */
+static int gpsculpt_brush_poll(bContext *C)
+{
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+}
+
+/* Init Sculpt Stroke ---------------------------------- */
+
+static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
+{
+ Scene *scene = gso->scene;
+ bGPdata *gpd = gso->gpd;
+ bGPDlayer *gpl;
+ int cfra = CFRA;
+
+ /* only try to add a new frame if this is the first stroke, or the frame has changed */
+ if ((gpd == NULL) || (cfra == gso->cfra))
+ return;
+
+ /* go through each layer, and ensure that we've got a valid frame to use */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+
+ /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
+ * spent too much time editing the wrong frame...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if (gpf->framenum != cfra) {
+ gpencil_frame_addcopy(gpl, cfra);
+ }
+ }
+ }
+
+ /* save off new current frame, so that next update works fine */
+ gso->cfra = cfra;
+}
+
+/* Apply ----------------------------------------------- */
+
+/* Apply brush operation to points in this stroke */
+static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, GP_BrushApplyCb apply)
+{
+ GP_SpaceConversion *gsc = &gso->gsc;
+ rcti *rect = &gso->brush_rect;
+ const int radius = gso->brush->size;
+
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ bool include_last = false;
+ bool changed = false;
+
+ if (gps->totpoints == 1) {
+ gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ if (len_v2v2_int(gso->mval, pc1) <= radius) {
+ /* apply operation to this point */
+ changed = apply(gso, gps, 0, radius, pc1);
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */
+ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) {
+ if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
+ include_last = false;
+ continue;
+ }
+ }
+
+ gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
+ {
+ /* Check if point segment of stroke had anything to do with
+ * brush region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ /* Apply operation to these points */
+ bool ok = false;
+
+ /* To each point individually... */
+ ok = apply(gso, gps, i, radius, pc1);
+
+ /* Only do the second point if this is the last segment,
+ * and it is unlikely that the point will get handled
+ * otherwise.
+ *
+ * NOTE: There is a small risk here that the second point wasn't really
+ * actually in-range. In that case, it only got in because
+ * the line linking the points was!
+ */
+ if (i + 1 == gps->totpoints - 1) {
+ ok |= apply(gso, gps, i + 1, radius, pc2);
+ include_last = false;
+ }
+ else {
+ include_last = true;
+ }
+
+ changed |= ok;
+ }
+ else if (include_last) {
+ /* This case is for cases where for whatever reason the second vert (1st here) doesn't get included
+ * because the whole edge isn't in bounds, but it would've qualified since it did with the
+ * previous step (but wasn't added then, to avoid double-ups)
+ */
+ changed |= apply(gso, gps, i, radius, pc1);
+ include_last = false;
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Perform two-pass brushes which modify the existing strokes */
+static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
+{
+ bool changed = false;
+
+ /* Calculate brush-specific data which applies equally to all points */
+ switch (gso->brush_type) {
+ case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
+ case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
+ {
+ /* calculate amount of displacement to apply */
+ gp_brush_grab_calc_dvec(gso);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
+ case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ /* calculate midpoint of the brush (in data space) */
+ gp_brush_calc_midpoint(gso);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Random jitter */
+ {
+ /* compute the displacement vector for the cursor (in data space) */
+ gp_brush_grab_calc_dvec(gso);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+
+ /* Find visible strokes, and perform operations on those if hit */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ switch (gso->brush_type) {
+ case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_smooth_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_thickness_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */
+ {
+ if (gso->first) {
+ /* First time this brush stroke is being applied:
+ * 1) Prepare data buffers (init/clear) for this stroke
+ * 2) Use the points now under the cursor
+ */
+ gp_brush_grab_stroke_init(gso, gps);
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps);
+ changed |= true;
+ }
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PUSH: /* Push points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_push_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_pinch_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_twist_apply);
+ break;
+ }
+
+ case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, gp_brush_randomize_apply);
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ return changed;
+}
+
+/* Calculate settings for applying brush */
+static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+{
+ tGP_BrushEditData *gso = op->customdata;
+ const int radius = gso->brush->size;
+ float mousef[2];
+ int mouse[2];
+ bool changed = false;
+
+ /* Get latest mouse coordinates */
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ gso->mval[0] = mouse[0] = (int)(mousef[0]);
+ gso->mval[1] = mouse[1] = (int)(mousef[1]);
+
+ gso->pressure = RNA_float_get(itemptr, "pressure");
+
+ if (RNA_boolean_get(itemptr, "pen_flip"))
+ gso->flag |= GP_EDITBRUSH_FLAG_INVERT;
+ else
+ gso->flag &= ~GP_EDITBRUSH_FLAG_INVERT;
+
+
+ /* Store coordinates as reference, if operator just started running */
+ if (gso->first) {
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ }
+
+ /* Update brush_rect, so that it represents the bounding rectangle of brush */
+ gso->brush_rect.xmin = mouse[0] - radius;
+ gso->brush_rect.ymin = mouse[1] - radius;
+ gso->brush_rect.xmax = mouse[0] + radius;
+ gso->brush_rect.ymax = mouse[1] + radius;
+
+
+ /* Apply brush */
+ if (gso->brush_type == GP_EDITBRUSH_TYPE_CLONE) {
+ changed = gpsculpt_brush_apply_clone(C, gso);
+ }
+ else {
+ changed = gpsculpt_brush_apply_standard(C, gso);
+ }
+
+
+ /* Updates */
+ if (changed) {
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ /* Store values for next step */
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ gso->first = false;
+}
+
+/* Running --------------------------------------------- */
+
+/* helper - a record stroke, and apply paint event */
+static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushEditData *gso = op->customdata;
+ PointerRNA itemptr;
+ float mouse[2];
+ int tablet = 0;
+
+ mouse[0] = event->mval[0] + 1;
+ mouse[1] = event->mval[1] + 1;
+
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
+ RNA_boolean_set(&itemptr, "is_start", gso->first);
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ float pressure = wmtab->Pressure;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets: clamp the values to be sane
+ */
+ if (tablet && (pressure >= 0.99f)) {
+ pressure = 1.0f;
+ }
+ RNA_float_set(&itemptr, "pressure", pressure);
+ }
+ else {
+ RNA_float_set(&itemptr, "pressure", 1.0f);
+ }
+
+ /* apply */
+ gpsculpt_brush_apply(C, op, &itemptr);
+}
+
+/* reapply */
+static int gpsculpt_brush_exec(bContext *C, wmOperator *op)
+{
+ if (!gpsculpt_brush_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ RNA_BEGIN(op->ptr, itemptr, "stroke")
+ {
+ gpsculpt_brush_apply(C, op, &itemptr);
+ }
+ RNA_END;
+
+ gpsculpt_brush_exit(C, op);
+
+ return OPERATOR_FINISHED;
+}
+
+
+/* start modal painting */
+static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushEditData *gso = NULL;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ bool needs_timer = false;
+ float brush_rate = 0.0f;
+
+ /* init painting data */
+ if (!gpsculpt_brush_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ gso = op->customdata;
+
+ /* initialise type-specific data (used for the entire session) */
+ switch (gso->brush_type) {
+ /* Brushes requiring timer... */
+ case GP_EDITBRUSH_TYPE_THICKNESS:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_EDITBRUSH_TYPE_PINCH:
+ brush_rate = 0.001f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_EDITBRUSH_TYPE_TWIST:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /* register timer for increasing influence by hovering over an area */
+ if (needs_timer) {
+ gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
+ }
+
+ /* register modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ /* start drawing immediately? */
+ if (is_modal == false) {
+ ARegion *ar = CTX_wm_region(C);
+
+ /* ensure that we'll have a new frame to draw on */
+ gpsculpt_brush_init_stroke(gso);
+
+ /* apply first dab... */
+ gso->is_painting = true;
+ gpsculpt_brush_apply_event(C, op, event);
+
+ /* redraw view with feedback */
+ ED_region_tag_redraw(ar);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* painting - handle events */
+static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGP_BrushEditData *gso = op->customdata;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ bool redraw_region = false;
+ bool redraw_toolsettings = false;
+
+ /* The operator can be in 2 states: Painting and Idling */
+ if (gso->is_painting) {
+ /* Painting */
+ switch (event->type) {
+ /* Mouse Move = Apply somewhere else */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ /* apply brush effect at new position */
+ gpsculpt_brush_apply_event(C, op, event);
+
+ /* force redraw, so that the cursor will at least be valid */
+ redraw_region = true;
+ break;
+
+ /* Timer Tick - Only if this was our own timer */
+ case TIMER:
+ if (event->customdata == gso->timer) {
+ gso->timerTick = true;
+ gpsculpt_brush_apply_event(C, op, event);
+ gso->timerTick = false;
+ }
+ break;
+
+ /* Adjust brush settings */
+ /* FIXME: Step increments and modifier keys are hardcoded here! */
+ case WHEELUPMOUSE:
+ case PADPLUSKEY:
+ if (event->shift) {
+ /* increase strength */
+ gso->brush->strength += 0.05f;
+ CLAMP_MAX(gso->brush->strength, 1.0f);
+ }
+ else {
+ /* increase brush size */
+ gso->brush->size += 3;
+ CLAMP_MAX(gso->brush->size, 300);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PADMINUS:
+ if (event->shift) {
+ /* decrease strength */
+ gso->brush->strength -= 0.05f;
+ CLAMP_MIN(gso->brush->strength, 0.0f);
+ }
+ else {
+ /* decrease brush size */
+ gso->brush->size -= 3;
+ CLAMP_MIN(gso->brush->size, 1);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ /* Painting mbut release = Stop painting (back to idle) */
+ case LEFTMOUSE:
+ //BLI_assert(event->val == KM_RELEASE);
+ if (is_modal) {
+ /* go back to idling... */
+ gso->is_painting = false;
+ }
+ else {
+ /* end sculpt session, since we're not modal */
+ gso->is_painting = false;
+
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ /* Abort painting if any of the usual things are tried */
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ /* Idling */
+ BLI_assert(is_modal == true);
+
+ switch (event->type) {
+ /* Painting mbut press = Start painting (switch to painting state) */
+ case LEFTMOUSE:
+ /* do initial "click" apply */
+ gso->is_painting = true;
+ gso->first = true;
+
+ gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_apply_event(C, op, event);
+ break;
+
+ /* Exit modal operator, based on the "standard" ops */
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+
+ /* MMB is often used for view manipulations */
+ case MIDDLEMOUSE:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Mouse movements should update the brush cursor - Just redraw the active region */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ redraw_region = true;
+ break;
+
+ /* Adjust brush settings */
+ /* FIXME: Step increments and modifier keys are hardcoded here! */
+ case WHEELUPMOUSE:
+ case PADPLUSKEY:
+ if (event->shift) {
+ /* increase strength */
+ gso->brush->strength += 0.05f;
+ CLAMP_MAX(gso->brush->strength, 1.0f);
+ }
+ else {
+ /* increase brush size */
+ gso->brush->size += 3;
+ CLAMP_MAX(gso->brush->size, 300);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PADMINUS:
+ if (event->shift) {
+ /* decrease strength */
+ gso->brush->strength -= 0.05f;
+ CLAMP_MIN(gso->brush->strength, 0.0f);
+ }
+ else {
+ /* decrease brush size */
+ gso->brush->size -= 3;
+ CLAMP_MIN(gso->brush->size, 1);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ /* Change Frame - Allowed */
+ case LEFTARROWKEY:
+ case RIGHTARROWKEY:
+ case UPARROWKEY:
+ case DOWNARROWKEY:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Unhandled event */
+ default:
+ break;
+ }
+ }
+
+ /* Redraw region? */
+ if (redraw_region) {
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+
+ /* Redraw toolsettings (brush settings)? */
+ if (redraw_toolsettings) {
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+/* Operator --------------------------------------------- */
+
+void GPENCIL_OT_brush_paint(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Stroke Sculpt";
+ ot->idname = "GPENCIL_OT_brush_paint";
+ ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX
+
+ /* api callbacks */
+ ot->exec = gpsculpt_brush_exec;
+ ot->invoke = gpsculpt_brush_invoke;
+ ot->modal = gpsculpt_brush_modal;
+ ot->cancel = gpsculpt_brush_exit;
+ ot->poll = gpsculpt_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input",
+ "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index e8d73eaffdf..c47985ebc1b 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -77,6 +77,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "ED_gpencil.h"
@@ -106,9 +107,9 @@ enum {
/* RNA enum define */
static EnumPropertyItem prop_gpencil_convertmodes[] = {
- {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""},
- {GP_STROKECONVERT_CURVE, "CURVE", 0, "Bezier Curve", ""},
- {GP_STROKECONVERT_POLY, "POLY", 0, "Polygon Curve", ""},
+ {GP_STROKECONVERT_PATH, "PATH", ICON_CURVE_PATH, "Path", "Animation path"},
+ {GP_STROKECONVERT_CURVE, "CURVE", ICON_CURVE_BEZCURVE, "Bezier Curve", "Smooth Bezier curve"},
+ {GP_STROKECONVERT_POLY, "POLY", ICON_MESH_DATA, "Polygon Curve", "Bezier curve with straight-line segments (vector handles)"},
{0, NULL, 0, NULL, NULL}
};
@@ -397,7 +398,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
cfra = last_valid_time + MIN_TIME_DELTA;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
last_valid_time = cfra;
}
else if (G.debug & G_DEBUG) {
@@ -409,7 +410,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
cfra = last_valid_time + MIN_TIME_DELTA;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
last_valid_time = cfra;
}
else {
@@ -417,7 +418,7 @@ static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerR
* and also far enough from (not yet added!) end_stroke keyframe!
*/
if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_BREAKDOWN, INSERTKEY_FAST);
last_valid_time = cfra;
}
else if (G.debug & G_DEBUG) {
@@ -471,7 +472,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
cu->ctime = 0.0f;
cfra = (float)gtd->start_frame;
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
cu->ctime = cu->pathlen;
if (gtd->realtime) {
@@ -480,7 +481,7 @@ static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu
else {
cfra = (float)gtd->end_frame;
}
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST);
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
}
else {
/* Use actual recorded timing! */
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index de966776645..746497f0ff5 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -59,12 +59,14 @@
#include "BKE_screen.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "ED_gpencil.h"
@@ -180,7 +182,7 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
*gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
/* add new layer now */
- gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
+ gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -444,4 +446,220 @@ void GPENCIL_OT_reveal(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ***************** Lock/Unlock All Layers ************************ */
+
+static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* make all layers non-editable */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_lock_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Lock All Layers";
+ ot->idname = "GPENCIL_OT_lock_all";
+ ot->description = "Lock all Grease Pencil layers to prevent them from being accidentally modified";
+
+ /* callbacks */
+ ot->exec = gp_lock_all_exec;
+ ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------- */
+
+static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl;
+
+ /* sanity checks */
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* make all layers editable again */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_LOCKED;
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_unlock_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlock All Layers";
+ ot->idname = "GPENCIL_OT_unlock_all";
+ ot->description = "Unlock all Grease Pencil layers so that they can be edited";
+
+ /* callbacks */
+ ot->exec = gp_unlock_all_exec;
+ ot->poll = gp_reveal_poll; /* XXX: could use dedicated poll later */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************** Isolate Layer **************************** */
+
+static int gp_isolate_layer_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *layer = gpencil_layer_getactive(gpd);
+ bGPDlayer *gpl;
+ int flags = GP_LAYER_LOCKED;
+ bool isolate = false;
+
+ if (RNA_boolean_get(op->ptr, "affect_visibility"))
+ flags |= GP_LAYER_HIDE;
+
+ if (ELEM(NULL, gpd, layer)) {
+ BKE_report(op->reports, RPT_ERROR, "No active layer to isolate");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Test whether to isolate or clear all flags */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Skip if this is the active layer */
+ if (gpl == layer)
+ continue;
+
+ /* If the flags aren't set, that means that the layer is
+ * not alone, so we have some layers to isolate still
+ */
+ if ((gpl->flag & flags) == 0) {
+ isolate = true;
+ break;
+ }
+ }
+
+ /* Set/Clear flags as appropriate */
+ /* TODO: Include onionskinning on this list? */
+ if (isolate) {
+ /* Set flags on all "other" layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl == layer)
+ continue;
+ else
+ gpl->flag |= flags;
+ }
+ }
+ else {
+ /* Clear flags - Restore everything else */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~flags;
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_isolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Isolate Layer";
+ ot->idname = "GPENCIL_OT_layer_isolate";
+ ot->description = "Toggle whether the active layer is the only one that can be edited and/or visible";
+
+ /* callbacks */
+ ot->exec = gp_isolate_layer_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility",
+ "In addition to toggling the editability, also affect the visibility");
+}
+
+/* ********************** Change Layer ***************************** */
+
+static int gp_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ /* call the menu, which will call this operator again, hence the canceled */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+static int gp_layer_change_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = NULL;
+ int layer_num = RNA_enum_get(op->ptr, "layer");
+
+ /* Get layer or create new one */
+ if (layer_num == -1) {
+ /* Create layer */
+ gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ else {
+ /* Try to get layer */
+ gpl = BLI_findlink(&gpd->layers, layer_num);
+
+ if (gpl == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent layer (index = %d)", layer_num);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Set active layer */
+ gpencil_layer_setactive(gpd, gpl);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_change(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Layer";
+ ot->idname = "GPENCIL_OT_layer_change";
+ ot->description = "Change active Grease Pencil layer";
+
+ /* callbacks */
+ ot->invoke = gp_layer_change_invoke;
+ ot->exec = gp_layer_change_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* gp layer to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
+}
+
/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 5c37a0a5b60..03d5ed3e24f 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -44,6 +44,7 @@
#include "BLT_translation.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -58,21 +59,63 @@
#include "BKE_screen.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_view2d.h"
#include "ED_gpencil.h"
+#include "ED_object.h"
#include "ED_view3d.h"
#include "gpencil_intern.h"
/* ************************************************ */
+/* Stroke Edit Mode Management */
+
+static int gpencil_editmode_toggle_poll(bContext *C)
+{
+ return ED_gpencil_data_get_active(C) != NULL;
+}
+
+static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ if (gpd == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* Just toggle editmode flag... */
+ gpd->flag ^= GP_DATA_STROKE_EDITMODE;
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Strokes Edit Mode Toggle";
+ ot->idname = "GPENCIL_OT_editmode_toggle";
+ ot->description = "Enter/Exit edit mode for Grease Pencil strokes";
+
+ /* callbacks */
+ ot->exec = gpencil_editmode_toggle_exec;
+ ot->poll = gpencil_editmode_toggle_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+}
+
+/* ************************************************ */
/* Stroke Editing Operators */
/* poll callback for all stroke editing operators */
@@ -233,7 +276,8 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
*/
/* list of bGPDstroke instances */
-static ListBase gp_strokes_copypastebuf = {NULL, NULL};
+/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
+ListBase gp_strokes_copypastebuf = {NULL, NULL};
/* Free copy/paste buffer data */
void ED_gpencil_strokes_copybuf_free(void)
@@ -339,15 +383,15 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
return OPERATOR_CANCELLED;
}
- else if (gp_strokes_copypastebuf.first == NULL) {
+ else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) {
BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again");
return OPERATOR_CANCELLED;
}
else if (gpl == NULL) {
/* no active layer - let's just create one */
- gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), 1);
+ gpl = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
}
- else if (gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) {
+ else if (gpencil_layer_is_editable(gpl) == false) {
BKE_report(op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked");
return OPERATOR_CANCELLED;
}
@@ -434,6 +478,110 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ******************* Move To Layer ****************************** */
+
+static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ /* call the menu, which will call this operator again, hence the canceled */
+ pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
+ layout = UI_popup_menu_layout(pup);
+ uiItemsEnumO(layout, "GPENCIL_OT_move_to_layer", "layer");
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+// FIXME: allow moving partial strokes
+static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *target_layer = NULL;
+ ListBase strokes = {NULL, NULL};
+ int layer_num = RNA_enum_get(op->ptr, "layer");
+
+ /* Get layer or create new one */
+ if (layer_num == -1) {
+ /* Create layer */
+ target_layer = gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+ }
+ else {
+ /* Try to get layer */
+ target_layer = BLI_findlink(&gpd->layers, layer_num);
+
+ if (target_layer == NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "There is no layer number %d", layer_num);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ /* Extract all strokes to move to this layer
+ * NOTE: We need to do this in a two-pass system to avoid conflicts with strokes
+ * getting repeatedly moved
+ */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ bGPDstroke *gps, *gpsn;
+
+ /* skip if no frame with strokes, or if this is the layer we're moving strokes to */
+ if ((gpl == target_layer) || (gpf == NULL))
+ continue;
+
+ /* make copies of selected strokes, and deselect these once we're done */
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* TODO: Don't just move entire strokes - instead, only copy the selected portions... */
+ if (gps->flag & GP_STROKE_SELECT) {
+ BLI_remlink(&gpf->strokes, gps);
+ BLI_addtail(&strokes, gps);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* Paste them all in one go */
+ if (strokes.first) {
+ Scene *scene = CTX_data_scene(C);
+ bGPDframe *gpf = gpencil_layer_getframe(target_layer, CFRA, true);
+
+ BLI_movelisttolist(&gpf->strokes, &strokes);
+ BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL));
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Move Strokes to Layer";
+ ot->idname = "GPENCIL_OT_move_to_layer";
+ ot->description = "Move selected strokes to another layer"; // XXX: allow moving individual points too?
+
+ /* callbacks */
+ ot->invoke = gp_move_to_layer_invoke;
+ ot->exec = gp_move_to_layer_exec;
+ ot->poll = gp_stroke_edit_poll; // XXX?
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* gp layer to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "layer", DummyRNA_DEFAULT_items, 0, "Grease Pencil Layer", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf);
+}
+
/* ******************* Delete Active Frame ************************ */
static int gp_actframe_delete_poll(bContext *C)
@@ -497,6 +645,7 @@ typedef enum eGP_DeleteMode {
GP_DELETEOP_FRAME = 2,
} eGP_DeleteMode;
+/* ----------------------------------- */
/* Delete selected strokes */
static int gp_delete_selected_strokes(bContext *C)
@@ -540,6 +689,8 @@ static int gp_delete_selected_strokes(bContext *C)
}
}
+/* ----------------------------------- */
+
/* Delete selected points but keep the stroke */
static int gp_dissolve_selected_points(bContext *C)
{
@@ -621,6 +772,124 @@ static int gp_dissolve_selected_points(bContext *C)
}
}
+/* ----------------------------------- */
+
+/* Temp data for storing information about an "island" of points
+ * that should be kept when splitting up a stroke. Used in:
+ * gp_stroke_delete_tagged_points()
+ */
+typedef struct tGPDeleteIsland {
+ int start_idx;
+ int end_idx;
+} tGPDeleteIsland;
+
+
+/* Split the given stroke into several new strokes, partitioning
+ * it based on whether the stroke points have a particular flag
+ * is set (e.g. "GP_SPOINT_SELECT" in most cases, but not always)
+ *
+ * The algorithm used here is as follows:
+ * 1) We firstly identify the number of "islands" of non-tagged points
+ * which will all end up being in new strokes.
+ * - In the most extreme case (i.e. every other vert is a 1-vert island),
+ * we have at most n / 2 islands
+ * - Once we start having larger islands than that, the number required
+ * becomes much less
+ * 2) Each island gets converted to a new stroke
+ */
+void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags)
+{
+ tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
+ bool in_island = false;
+ int num_islands = 0;
+
+ bGPDspoint *pt;
+ int i;
+
+ /* First Pass: Identify start/end of islands */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & tag_flags) {
+ /* selected - stop accumulating to island */
+ in_island = false;
+ }
+ else {
+ /* unselected - start of a new island? */
+ int idx;
+
+ if (in_island) {
+ /* extend existing island */
+ idx = num_islands - 1;
+ islands[idx].end_idx = i;
+ }
+ else {
+ /* start of new island */
+ in_island = true;
+ num_islands++;
+
+ idx = num_islands - 1;
+ islands[idx].start_idx = islands[idx].end_idx = i;
+ }
+ }
+ }
+
+ /* Watch out for special case where No islands = All points selected = Delete Stroke only */
+ if (num_islands) {
+ /* there are islands, so create a series of new strokes, adding them before the "next" stroke */
+ int idx;
+
+ /* Create each new stroke... */
+ for (idx = 0; idx < num_islands; idx++) {
+ tGPDeleteIsland *island = &islands[idx];
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+
+ /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
+ new_stroke->totpoints = island->end_idx - island->start_idx + 1;
+ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
+
+ /* Copy over the relevant points */
+ memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints);
+
+
+ /* Each island corresponds to a new stroke. We must adjust the
+ * timings of these new strokes:
+ *
+ * Each point's timing data is a delta from stroke's inittime, so as we erase some points from
+ * the start of the stroke, we have to offset this inittime and all remaining points' delta values.
+ * This way we get a new stroke with exactly the same timing as if user had started drawing from
+ * the first non-removed point...
+ */
+ {
+ bGPDspoint *pts;
+ float delta = gps->points[island->start_idx].time;
+ int j;
+
+ new_stroke->inittime += (double)delta;
+
+ pts = new_stroke->points;
+ for (j = 0; j < new_stroke->totpoints; j++, pts++) {
+ pts->time -= delta;
+ }
+ }
+
+ /* Add new stroke to the frame */
+ if (next_stroke) {
+ BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke);
+ }
+ else {
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* free islands */
+ MEM_freeN(islands);
+
+ /* Delete the old stroke */
+ MEM_freeN(gps->points);
+ BLI_freelinkN(&gpf->strokes, gps);
+}
+
+
/* Split selected strokes into segments, splitting on selected points */
static int gp_delete_selected_points(bContext *C)
{
@@ -644,89 +913,11 @@ static int gp_delete_selected_points(bContext *C)
if (gps->flag & GP_STROKE_SELECT) {
- bGPDspoint *pt;
- int i;
-
- /* The algorithm used here is as follows:
- * 1) We firstly identify the number of "islands" of non-selected points
- * which will all end up being in new strokes.
- * - In the most extreme case (i.e. every other vert is a 1-vert island),
- * we have at most n / 2 islands
- * - Once we start having larger islands than that, the number required
- * becomes much less
- * 2) Each island gets converted to a new stroke
- */
- typedef struct tGPDeleteIsland {
- int start_idx;
- int end_idx;
- } tGPDeleteIsland;
-
- tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands");
- bool in_island = false;
- int num_islands = 0;
-
- /* First Pass: Identify start/end of islands */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->flag & GP_SPOINT_SELECT) {
- /* selected - stop accumulating to island */
- in_island = false;
- }
- else {
- /* unselected - start of a new island? */
- int idx;
-
- if (in_island) {
- /* extend existing island */
- idx = num_islands - 1;
- islands[idx].end_idx = i;
- }
- else {
- /* start of new island */
- in_island = true;
- num_islands++;
-
- idx = num_islands - 1;
- islands[idx].start_idx = islands[idx].end_idx = i;
- }
- }
- }
-
- /* Watch out for special case where No islands = All points selected = Delete Stroke only */
- if (num_islands) {
- /* there are islands, so create a series of new strokes, adding them before the "next" stroke */
- int idx;
-
- /* deselect old stroke, since it will be used as template for the new strokes */
- gps->flag &= ~GP_STROKE_SELECT;
-
- /* create each new stroke... */
- for (idx = 0; idx < num_islands; idx++) {
- tGPDeleteIsland *island = &islands[idx];
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
-
- /* compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */
- new_stroke->totpoints = island->end_idx - island->start_idx + 1;
- new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment");
-
- /* copy over the relevant points */
- memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints);
-
- /* add new stroke to the frame */
- if (gpsn) {
- BLI_insertlinkbefore(&gpf->strokes, gpsn, new_stroke);
- }
- else {
- BLI_addtail(&gpf->strokes, new_stroke);
- }
- }
- }
-
- /* free islands */
- MEM_freeN(islands);
+ /* deselect old stroke, since it will be used as template for the new strokes */
+ gps->flag &= ~GP_STROKE_SELECT;
- /* Delete the old stroke */
- MEM_freeN(gps->points);
- BLI_freelinkN(&gpf->strokes, gps);
+ /* delete unwanted points by splitting stroke into several smaller ones */
+ gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT);
changed = true;
}
@@ -743,6 +934,7 @@ static int gp_delete_selected_points(bContext *C)
}
}
+/* ----------------------------------- */
static int gp_delete_exec(bContext *C, wmOperator *op)
{
@@ -812,4 +1004,190 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
+/* ****************** Snapping - Strokes <-> Cursor ************************ */
+
+/* Poll callback for snap operators */
+/* NOTE: For now, we only allow these in the 3D view, as other editors do not
+ * define a cursor or gridstep which can be used
+ */
+static int gp_snap_poll(bContext *C)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ ScrArea *sa = CTX_wm_area(C);
+
+ return (gpd != NULL) && ((sa != NULL) && (sa->spacetype == SPACE_VIEW3D));
+}
+
+/* --------------------------------- */
+
+static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
+{
+ RegionView3D *rv3d = CTX_wm_region_data(C);
+ float gridf = rv3d->gridview;
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ // TOOD: if entire stroke is selected, offset entire stroke by same amount?
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ /* only if point is selected.. */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ pt->x = gridf * floorf(0.5f + pt->x / gridf);
+ pt->y = gridf * floorf(0.5f + pt->y / gridf);
+ pt->z = gridf * floorf(0.5f + pt->z / gridf);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Snap Selection to Grid";
+ ot->idname = "GPENCIL_OT_snap_to_grid";
+ ot->description = "Snap selected points to the nearest grid points";
+
+ /* callbacks */
+ ot->exec = gp_snap_to_grid;
+ ot->poll = gp_snap_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------------------------- */
+
+static int gp_snap_to_cursor(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
+ const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ if (use_offset) {
+ float offset[3];
+
+ /* compute offset from first point of stroke to cursor */
+ /* TODO: Allow using midpoint instead? */
+ sub_v3_v3v3(offset, cursor_global, &gps->points->x);
+
+ /* apply offset to all points in the stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ add_v3_v3(&pt->x, offset);
+ }
+ }
+ else {
+ /* affect each selected point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ copy_v3_v3(&pt->x, cursor_global);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Snap Selection to Cursor";
+ ot->idname = "GPENCIL_OT_snap_to_cursor";
+ ot->description = "Snap selected points/strokes to the cursor";
+
+ /* callbacks */
+ ot->exec = gp_snap_to_cursor;
+ ot->poll = gp_snap_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_boolean(ot->srna, "use_offset", true, "With Offset",
+ "Offset the entire stroke instead of selected points only");
+}
+
+/* ------------------------------- */
+
+static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ float *cursor = ED_view3d_cursor3d_get(scene, v3d);
+ float centroid[3] = {0.0f};
+ float min[3], max[3];
+ size_t count = 0;
+
+ INIT_MINMAX(min, max);
+
+ /* calculate midpoints from selected points */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ bGPDspoint *pt;
+ int i;
+
+ /* only continue if this stroke is selected (editable doesn't guarantee this)... */
+ if ((gps->flag & GP_STROKE_SELECT) == 0)
+ continue;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ add_v3_v3(centroid, &pt->x);
+ minmax_v3v3_v3(min, max, &pt->x);
+ count++;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (v3d->around == V3D_AROUND_CENTER_MEAN && count) {
+ mul_v3_fl(centroid, 1.0f / (float)count);
+ copy_v3_v3(cursor, centroid);
+ }
+ else {
+ mid_v3_v3v3(cursor, min, max);
+ }
+
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Snap Cursor to Selected Points";
+ ot->idname = "GPENCIL_OT_snap_cursor_to_selected";
+ ot->description = "Snap cursor to center of selected points";
+
+ /* callbacks */
+ ot->exec = gp_snap_cursor_to_sel;
+ ot->poll = gp_snap_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 290935a06cf..368da618a1d 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -44,6 +44,10 @@ struct ARegion;
struct View2D;
struct wmOperatorType;
+struct PointerRNA;
+struct PropertyRNA;
+struct EnumPropertyItem;
+
/* ***************************************************** */
/* Internal API */
@@ -96,12 +100,54 @@ void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
int *r_x, int *r_y);
+/**
+ * Convert a screenspace point to a 3D Grease Pencil coordinate.
+ *
+ * For use with editing tools where it is easier to perform the operations in 2D,
+ * and then later convert the transformed points back to 3D.
+ *
+ * \param screeN_co The screenspace 2D coordinates to convert to
+ * \param[out] r_out The resulting 3D coordinates of the input point
+ */
+bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]);
+
/* Poll Callbacks ------------------------------------ */
/* gpencil_utils.c */
int gp_add_poll(struct bContext *C);
int gp_active_layer_poll(struct bContext *C);
+/* Copy/Paste Buffer --------------------------------- */
+/* gpencil_edit.c */
+
+extern ListBase gp_strokes_copypastebuf;
+
+/* Stroke Editing ------------------------------------ */
+
+void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags);
+
+
+/**
+ * Apply smooth to stroke point
+ * \param gps Stroke to smooth
+ * \param i Point index
+ * \param inf Amount of smoothing to apply
+ * \param affect_pressure Apply smoothing to pressure values too?
+ */
+bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure);
+
+/**
+ * Subdivide a stroke once, by adding points at the midpoint between each pair of points
+ * \param gps Stroke data
+ * \param new_totpoints Total number of points (after subdividing)
+ */
+void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
+
+/* Layers Enums -------------------------------------- */
+
+struct EnumPropertyItem *ED_gpencil_layers_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free);
+
/* ***************************************************** */
/* Operator Defines */
@@ -119,6 +165,8 @@ typedef enum eGPencil_PaintModes {
/* stroke editing ----- */
+void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
+
void GPENCIL_OT_select(struct wmOperatorType *ot);
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
void GPENCIL_OT_select_circle(struct wmOperatorType *ot);
@@ -126,6 +174,7 @@ void GPENCIL_OT_select_border(struct wmOperatorType *ot);
void GPENCIL_OT_select_lasso(struct wmOperatorType *ot);
void GPENCIL_OT_select_linked(struct wmOperatorType *ot);
+void GPENCIL_OT_select_grouped(struct wmOperatorType *ot);
void GPENCIL_OT_select_more(struct wmOperatorType *ot);
void GPENCIL_OT_select_less(struct wmOperatorType *ot);
@@ -135,6 +184,19 @@ void GPENCIL_OT_dissolve(struct wmOperatorType *ot);
void GPENCIL_OT_copy(struct wmOperatorType *ot);
void GPENCIL_OT_paste(struct wmOperatorType *ot);
+void GPENCIL_OT_move_to_layer(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_change(struct wmOperatorType *ot);
+
+void GPENCIL_OT_snap_to_grid(struct wmOperatorType *ot);
+void GPENCIL_OT_snap_to_cursor(struct wmOperatorType *ot);
+void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
+void GPENCIL_OT_snap_cursor_to_center(struct wmOperatorType *ot);
+
+
+/* stroke sculpting -- */
+
+void GPENCIL_OT_brush_paint(struct wmOperatorType *ot);
+
/* buttons editing --- */
void GPENCIL_OT_data_add(struct wmOperatorType *ot);
@@ -148,6 +210,11 @@ void GPENCIL_OT_layer_duplicate(struct wmOperatorType *ot);
void GPENCIL_OT_hide(struct wmOperatorType *ot);
void GPENCIL_OT_reveal(struct wmOperatorType *ot);
+void GPENCIL_OT_lock_all(struct wmOperatorType *ot);
+void GPENCIL_OT_unlock_all(struct wmOperatorType *ot);
+
+void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot);
+
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
void GPENCIL_OT_convert(struct wmOperatorType *ot);
@@ -203,8 +270,4 @@ typedef enum ACTCONT_TYPES {
ACTCONT_GPENCIL
} ACTCONT_TYPES;
-
-
-
#endif /* __GPENCIL_INTERN_H__ */
-
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index ab56565f4ca..9f5633ae668 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -79,11 +79,25 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ /* Tablet Mappings for Drawing ------------------ */
+ /* For now, only support direct drawing using the eraser, as most users using a tablet
+ * may still want to use that as their primary pointing device!
+ */
+#if 0
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_STYLUS, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+#endif
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0);
+ RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
/* Viewport Tools ------------------------------- */
/* Enter EditMode */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, DKEY);
- RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode");
+ WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, DKEY);
/* Pie Menu - For standard tools */
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY);
@@ -111,8 +125,10 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
/* ----------------------------------------------- */
/* Exit EditMode */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode");
+ WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0);
+
+ /* Pie Menu - For settings/tools easy access */
+ WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_sculpt", EKEY, KM_PRESS, 0, DKEY);
/* Brush Settings */
/* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys
@@ -160,11 +176,13 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
+ /* select grouped */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
+
/* select more/less */
WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
-
/* Editing ----------------------------------------- */
/* duplicate and move selected points */
@@ -185,6 +203,14 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_item(keymap, "GPENCIL_OT_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
#endif
+
+ /* snap */
+ WM_keymap_add_menu(keymap, "GPENCIL_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
+
+
+ /* convert to geometry */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_convert", CKEY, KM_PRESS, KM_ALT, 0);
+
/* Show/Hide */
/* NOTE: These are available only in EditMode now, since they clash with general-purpose hotkeys */
@@ -196,35 +222,62 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "unselected", true);
+ /* Isolate Layer */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0);
+
+ /* Move to Layer */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_move_to_layer", MKEY, KM_PRESS, 0, 0);
+
+
+
+ /* Brush-Based Editing:
+ * EKEY + LMB = Single stroke, draw immediately
+ * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc.
+ *
+ * For the modal version, use D+E -> Sculpt
+ */
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/
+
+ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY);
+ RNA_boolean_set(kmi->ptr, "wait_for_input", false);
+ /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/
+
+
+ /* Shift-FKEY = Sculpt Strength */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength");
+
+ /* Ctrl-FKEY = Sculpt Brush Size */
+ kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size");
+
+
+
/* Transform Tools */
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_bend", WKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
WM_keymap_add_item(keymap, "TRANSFORM_OT_tosphere", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
WM_keymap_add_item(keymap, "TRANSFORM_OT_shear", SKEY, KM_PRESS, KM_ALT | KM_CTRL | KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_transform", SKEY, KM_PRESS, KM_ALT, 0);
RNA_enum_set(kmi->ptr, "mode", TFM_GPENCIL_SHRINKFATTEN);
- RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
/* Proportional Editing */
ED_keymap_proportional_cycle(keyconf, keymap);
@@ -249,6 +302,8 @@ void ED_operatortypes_gpencil(void)
/* Editing (Strokes) ------------ */
+ WM_operatortype_append(GPENCIL_OT_editmode_toggle);
+
WM_operatortype_append(GPENCIL_OT_select);
WM_operatortype_append(GPENCIL_OT_select_all);
WM_operatortype_append(GPENCIL_OT_select_circle);
@@ -256,6 +311,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_select_lasso);
WM_operatortype_append(GPENCIL_OT_select_linked);
+ WM_operatortype_append(GPENCIL_OT_select_grouped);
WM_operatortype_append(GPENCIL_OT_select_more);
WM_operatortype_append(GPENCIL_OT_select_less);
@@ -265,6 +321,15 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_copy);
WM_operatortype_append(GPENCIL_OT_paste);
+ WM_operatortype_append(GPENCIL_OT_move_to_layer);
+ WM_operatortype_append(GPENCIL_OT_layer_change);
+
+ WM_operatortype_append(GPENCIL_OT_snap_to_grid);
+ WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
+ WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
+
+ WM_operatortype_append(GPENCIL_OT_brush_paint);
+
/* Editing (Buttons) ------------ */
WM_operatortype_append(GPENCIL_OT_data_add);
@@ -277,6 +342,9 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_hide);
WM_operatortype_append(GPENCIL_OT_reveal);
+ WM_operatortype_append(GPENCIL_OT_lock_all);
+ WM_operatortype_append(GPENCIL_OT_unlock_all);
+ WM_operatortype_append(GPENCIL_OT_layer_isolate);
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
@@ -290,12 +358,14 @@ void ED_operatormacros_gpencil(void)
wmOperatorType *ot;
wmOperatorTypeMacro *otmacro;
+ /* Duplicate + Move = Interactively place newly duplicated strokes */
ot = WM_operatortype_append_macro("GPENCIL_OT_duplicate_move", "Duplicate Strokes",
"Make copies of the selected Grease Pencil strokes and move them",
OPTYPE_UNDO | OPTYPE_REGISTER);
WM_operatortype_macro_define(ot, "GPENCIL_OT_duplicate");
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "gpencil_strokes", true);
+
}
/* ****************************************** */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 184482eeacb..2a81b481ed1 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -77,7 +77,33 @@
/* ******************************************* */
/* 'Globals' and Defines */
-/* Temporary 'Stroke' Operation data */
+/* values for tGPsdata->status */
+typedef enum eGPencil_PaintStatus {
+ GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
+ GP_STATUS_PAINTING, /* a stroke is in progress */
+ GP_STATUS_ERROR, /* something wasn't correctly set up */
+ GP_STATUS_DONE /* painting done */
+} eGPencil_PaintStatus;
+
+/* Return flags for adding points to stroke buffer */
+typedef enum eGP_StrokeAdd_Result {
+ GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
+ GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
+ GP_STROKEADD_NORMAL, /* point was successfully added */
+ GP_STROKEADD_FULL /* cannot add any more points to buffer */
+} eGP_StrokeAdd_Result;
+
+/* Runtime flags */
+typedef enum eGPencil_PaintFlags {
+ GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
+ GP_PAINTFLAG_STROKEADDED = (1 << 1),
+ GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
+} eGPencil_PaintFlags;
+
+
+/* Temporary 'Stroke' Operation data
+ * "p" = op->customdata
+ */
typedef struct tGPsdata {
Scene *scene; /* current scene from context */
@@ -95,8 +121,13 @@ typedef struct tGPsdata {
bGPDlayer *gpl; /* layer we're working on */
bGPDframe *gpf; /* frame we're working on */
- short status; /* current status of painting */
- short paintmode; /* mode for painting */
+ char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */
+
+ eGPencil_PaintStatus status; /* current status of painting */
+ eGPencil_PaintModes paintmode; /* mode for painting */
+ eGPencil_PaintFlags flags; /* flags that can get set during runtime (eGPencil_PaintFlags) */
+
+ short radius; /* radius of influence for eraser */
int mval[2]; /* current mouse-position */
int mvalo[2]; /* previous recorded mouse-position */
@@ -104,9 +135,6 @@ typedef struct tGPsdata {
float pressure; /* current stylus pressure */
float opressure; /* previous stylus pressure */
- short radius; /* radius of influence for eraser */
- short flags; /* flags that can get set during runtime */
-
/* These need to be doubles, as (at least under unix) they are in seconds since epoch,
* float (and its 7 digits precision) is definitively not enough here!
* double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
@@ -124,29 +152,6 @@ typedef struct tGPsdata {
void *erasercursor; /* radial cursor data for drawing eraser */
} tGPsdata;
-/* values for tGPsdata->status */
-enum {
- GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
- GP_STATUS_PAINTING, /* a stroke is in progress */
- GP_STATUS_ERROR, /* something wasn't correctly set up */
- GP_STATUS_DONE /* painting done */
-};
-
-/* Return flags for adding points to stroke buffer */
-enum {
- GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
- GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
- GP_STROKEADD_NORMAL, /* point was successfully added */
- GP_STROKEADD_FULL /* cannot add any more points to buffer */
-};
-
-/* Runtime flags */
-enum {
- GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
- GP_PAINTFLAG_STROKEADDED = (1 << 1),
- GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2)
-};
-
/* ------ */
/* maximum sizes of gp-session buffer */
@@ -204,7 +209,7 @@ static int gpencil_draw_poll(bContext *C)
static bool gpencil_project_check(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
- return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (p->gpd->flag & (GP_DATA_DEPTH_VIEW | GP_DATA_DEPTH_STROKE)));
+ return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)));
}
/* ******************************************* */
@@ -444,45 +449,6 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure,
return GP_STROKEADD_INVALID;
}
-/* smooth a stroke (in buffer) before storing it */
-static void gp_stroke_smooth(tGPsdata *p)
-{
- bGPdata *gpd = p->gpd;
- tGPspoint *spt, tmp_spt[3];
- int i = 0, cmx = gpd->sbuffer_size;
-
- /* only smooth if smoothing is enabled, and we're not doing a straight line */
- if (!(U.gp_settings & GP_PAINT_DOSMOOTH) || ELEM(p->paintmode, GP_PAINTMODE_DRAW_STRAIGHT, GP_PAINTMODE_DRAW_POLY))
- return;
-
- /* don't try if less than 2 points in buffer */
- if ((cmx <= 2) || (gpd->sbuffer == NULL))
- return;
-
- /* Calculate smoothing coordinates using weighted-averages
- * WARNING: we do NOT smooth first and last points (to avoid shrinkage)
- */
- spt = (tGPspoint *)gpd->sbuffer;
-
- /* This (tmp_spt) small array stores the last two points' original coordinates,
- * as we don't want to use already averaged ones! It is used as a cyclic buffer...
- */
- tmp_spt[0] = *spt;
- for (i = 1, spt++; i < cmx - 1; i++, spt++) {
- const tGPspoint *pc = spt;
- const tGPspoint *pb = &tmp_spt[(i - 1) % 3];
- const tGPspoint *pa = (i - 1 > 0) ? (&tmp_spt[(i - 2) % 3]) : (pb);
- const tGPspoint *pd = pc + 1;
- const tGPspoint *pe = (i + 2 < cmx) ? (pc + 2) : (pd);
-
- /* Store current point's original state for the two next points! */
- tmp_spt[i % 3] = *spt;
-
- spt->x = (int)(0.1 * pa->x + 0.2 * pb->x + 0.4 * pc->x + 0.2 * pd->x + 0.1 * pe->x);
- spt->y = (int)(0.1 * pa->y + 0.2 * pb->y + 0.4 * pc->y + 0.2 * pd->y + 0.1 * pe->y);
- }
-}
-
/* simplify a stroke (in buffer) before storing it
* - applies a reverse Chaikin filter
* - code adapted from etch-a-ton branch (editarmature_sketch.c)
@@ -563,9 +529,11 @@ static void gp_stroke_simplify(tGPsdata *p)
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
bGPdata *gpd = p->gpd;
+ bGPDlayer *gpl = p->gpl;
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
+
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
@@ -605,7 +573,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->inittime = p->inittime;
/* allocate enough memory for a continuous array for storage points */
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+ int sublevel = gpl->sublevel;
+ int new_totpoints = gps->totpoints;
+
+ for (i = 0; i < sublevel; i++) {
+ new_totpoints += new_totpoints - 1;
+ }
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points");
/* set pointer to first non-initialized point */
pt = gps->points + (gps->totpoints - totelem);
@@ -725,10 +699,29 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->time = ptc->time;
}
+ /* subdivide the stroke */
+ if (sublevel > 0) {
+ int totpoints = gps->totpoints;
+ for (i = 0; i < sublevel; i++) {
+ /* we're adding one new point between each pair of verts on each step */
+ totpoints += totpoints - 1;
+
+ gp_subdivide_stroke(gps, totpoints);
+ }
+ }
+
+ /* smooth stroke - only if there's something to do */
+ /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */
+ if (gpl->draw_smoothfac > 0.0f) {
+ for (i = 0; i < gps->totpoints; i++) {
+ gp_smooth_stroke(gps, i, gpl->draw_smoothfac, false);
+ }
+ }
+
if (depth_arr)
MEM_freeN(depth_arr);
}
-
+
/* add stroke to frame */
BLI_addtail(&p->gpf->strokes, gps);
gp_stroke_added_enable(p);
@@ -736,112 +729,6 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
/* --- 'Eraser' for 'Paint' Tool ------ */
-/* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
-static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
-{
- bGPDspoint *pt_tmp = gps->points;
- bGPDstroke *gsn = NULL;
-
- /* if stroke only had two points, get rid of stroke */
- if (gps->totpoints == 2) {
- /* free stroke points, then stroke */
- MEM_freeN(pt_tmp);
- BLI_freelinkN(&gpf->strokes, gps);
-
- /* nothing left in stroke, so stop */
- return 1;
- }
-
- /* if last segment, just remove segment from the stroke */
- else if (i == gps->totpoints - 2) {
- /* allocate new points array, and assign most of the old stroke there */
- gps->totpoints--;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * gps->totpoints);
-
- /* free temp buffer */
- MEM_freeN(pt_tmp);
-
- /* nothing left in stroke, so stop */
- return 1;
- }
-
- /* if first segment, just remove segment from the stroke */
- else if (i == 0) {
- /* allocate new points array, and assign most of the old stroke there */
- gps->totpoints--;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint) * gps->totpoints);
-
- /* We must adjust timings!
- * Each point's timing data is a delta from stroke's inittime, so as we erase the first
- * point of the stroke, we have to offset this inittime and all remaining points' delta values.
- * This way we get a new stroke with exactly the same timing as if user had started drawing from
- * the second point...
- */
- {
- bGPDspoint *pts;
- float delta = pt_tmp[1].time;
- int j;
-
- gps->inittime += (double)delta;
-
- pts = gps->points;
- for (j = 0; j < gps->totpoints; j++, pts++) {
- pts->time -= delta;
- }
- }
-
- /* free temp buffer */
- MEM_freeN(pt_tmp);
-
- /* no break here, as there might still be stuff to remove in this stroke */
- return 0;
- }
-
- /* segment occurs in 'middle' of stroke, so split */
- else {
- /* duplicate stroke, and assign 'later' data to that stroke */
- gsn = MEM_dupallocN(gps);
- gsn->prev = gsn->next = NULL;
- BLI_insertlinkafter(&gpf->strokes, gps, gsn);
-
- gsn->totpoints = gps->totpoints - i;
- gsn->points = MEM_callocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points");
- memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint) * gsn->totpoints);
-
- /* We must adjust timings of this new stroke!
- * Each point's timing data is a delta from stroke's inittime, so as we erase the first
- * point of the stroke, we have to offset this inittime and all remaing points' delta values.
- * This way we get a new stroke with exactly the same timing as if user had started drawing from
- * the second point...
- */
- {
- bGPDspoint *pts;
- float delta = pt_tmp[i].time;
- int j;
-
- gsn->inittime += (double)delta;
-
- pts = gsn->points;
- for (j = 0; j < gsn->totpoints; j++, pts++) {
- pts->time -= delta;
- }
- }
-
- /* adjust existing stroke */
- gps->totpoints = i;
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * i);
-
- /* free temp buffer */
- MEM_freeN(pt_tmp);
-
- /* nothing left in stroke, so stop */
- return 1;
- }
-}
-
/* which which point is infront (result should only be used for comparison) */
static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
{
@@ -853,6 +740,7 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3])
}
}
+/* only erase stroke points that are visible */
static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
{
if ((p->sa->spacetype == SPACE_VIEW3D) &&
@@ -874,15 +762,33 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons
return false;
}
+/* apply a falloff effect to brush strength, based on distance */
+static float gp_stroke_eraser_calc_influence(tGPsdata *p, const int mval[2], const int radius, const int co[2])
+{
+ /* Linear Falloff... */
+ float distance = (float)len_v2v2_int(mval, co);
+ float fac;
+
+ CLAMP(distance, 0.0f, (float)radius);
+ fac = 1.0f - (distance / (float)radius);
+
+ /* Control this further using pen pressure */
+ fac *= p->pressure;
+
+ /* Return influence factor computed here */
+ return fac;
+}
/* eraser tool - evaluation per stroke */
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
static void gp_stroke_eraser_dostroke(tGPsdata *p,
+ bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps,
const int mval[2], const int mvalo[2],
- short rad, const rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
+ const int radius, const rcti *rect)
{
bGPDspoint *pt1, *pt2;
- int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
int i;
if (gps->totpoints == 0) {
@@ -892,56 +798,101 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(&p->gsc, gps, gps->points, &x0, &y0);
+ gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
/* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
- if (((x0 - mval[0]) * (x0 - mval[0]) + (y0 - mval[1]) * (y0 - mval[1])) <= rad * rad) {
+ if (len_v2v2_int(mval, pc1) <= radius) {
/* free stroke */
+ // XXX: pressure sensitive eraser should apply here too?
MEM_freeN(gps->points);
BLI_freelinkN(&gpf->strokes, gps);
}
}
}
else {
- /* loop over the points in the stroke, checking for intersections
- * - an intersection will require the stroke to be split
+ /* Pressure threshold at which stroke should be culled: Calculated as pressure value
+ * below which we would have invisible strokes
+ */
+ const float cull_thresh = (gpl->thickness) ? 1.0f / ((float)gpl->thickness) : 1.0f;
+
+ /* Amount to decrease the pressure of each point with each stroke */
+ // TODO: Fetch from toolsettings, or compute based on thickness instead?
+ const float strength = 0.1f;
+
+ /* Perform culling? */
+ bool do_cull = false;
+
+
+ /* Clear Tags
+ *
+ * Note: It's better this way, as we are sure that
+ * we don't miss anything, though things will be
+ * slightly slower as a result
+ */
+ for (i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ pt->flag &= ~GP_SPOINT_TAG;
+ }
+
+ /* First Pass: Loop over the points in the stroke
+ * 1) Thin out parts of the stroke under the brush
+ * 2) Tag "too thin" parts for removal (in second pass)
*/
for (i = 0; (i + 1) < gps->totpoints; i++) {
/* get points to work with */
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
- gp_point_to_xy(&p->gsc, gps, pt1, &x0, &y0);
- gp_point_to_xy(&p->gsc, gps, pt2, &x1, &y1);
+ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
+ gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
- /* check that point segment of the boundbox of the eraser stroke */
- if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
- ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1)))
+ /* Check that point segment of the boundbox of the eraser stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
{
- /* check if point segment of stroke had anything to do with
+ /* Check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, rad, x0, y0, x1, y1)) {
- if ((gp_stroke_eraser_is_occluded(p, pt1, x0, y0) == false) ||
- (gp_stroke_eraser_is_occluded(p, pt2, x1, y1) == false))
+ if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
+ (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false))
{
- /* if function returns true, break this loop (as no more point to check) */
- if (gp_stroke_eraser_splitdel(gpf, gps, i))
- break;
+ /* Point is affected: */
+ /* 1) Adjust thickness
+ * - Influence of eraser falls off with distance from the middle of the eraser
+ * - Second point gets less influence, as it might get hit again in the next segment
+ */
+ pt1->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc1) * strength;
+ pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength / 2.0f;
+
+ /* 2) Tag any point with overly low influence for removal in the next pass */
+ if (pt1->pressure < cull_thresh) {
+ pt1->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
+ if (pt2->pressure < cull_thresh) {
+ pt2->flag |= GP_SPOINT_TAG;
+ do_cull = true;
+ }
}
}
}
}
+
+ /* Second Pass: Remove any points that are tagged */
+ if (do_cull) {
+ gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG);
+ }
}
}
/* erase strokes which fall under the eraser strokes */
static void gp_stroke_doeraser(tGPsdata *p)
{
- bGPDframe *gpf = p->gpf;
+ bGPDlayer *gpl;
bGPDstroke *gps, *gpn;
rcti rect;
@@ -960,10 +911,32 @@ static void gp_stroke_doeraser(tGPsdata *p)
}
}
- /* loop over strokes, checking segments for intersections */
- for (gps = gpf->strokes.first; gps; gps = gpn) {
- gpn = gps->next;
- gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps);
+ /* loop over all layers too, since while it's easy to restrict editing to
+ * only a subset of layers, it is harder to perform the same erase operation
+ * on multiple layers...
+ */
+ for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
+
+ /* only affect layer if it's editable (and visible) */
+ if (gpencil_layer_is_editable(gpl) == false) {
+ continue;
+ }
+ else if (gpf == NULL) {
+ continue;
+ }
+
+ /* loop over strokes, checking segments for intersections */
+ for (gps = gpf->strokes.first; gps; gps = gpn) {
+ gpn = gps->next;
+
+ /* Not all strokes in the datablock may be valid in the current editor/context
+ * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
+ */
+ if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
+ gp_stroke_eraser_dostroke(p, gpl, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ }
+ }
}
}
@@ -1001,6 +974,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
bGPdata **gpd_ptr = NULL;
ScrArea *curarea = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
/* make sure the active view (at the starting time) is a 3d-view */
if (curarea == NULL) {
@@ -1030,6 +1004,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* CAUTION: If this is the "toolbar", then this will change on the first stroke */
p->sa = curarea;
p->ar = ar;
+ p->align_flag = &ts->gpencil_v3d_align;
if (ar->regiondata == NULL) {
p->status = GP_STATUS_ERROR;
@@ -1047,6 +1022,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
p->sa = curarea;
p->ar = ar;
p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
break;
}
case SPACE_SEQ:
@@ -1057,6 +1033,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
p->sa = curarea;
p->ar = ar;
p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_seq_align;
/* check that gpencil data is allowed to be drawn */
if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
@@ -1075,6 +1052,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
p->sa = curarea;
p->ar = ar;
p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_ima_align;
break;
}
case SPACE_CLIP:
@@ -1091,6 +1069,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
p->sa = curarea;
p->ar = ar;
p->v2d = &ar->v2d;
+ p->align_flag = &ts->gpencil_v2d_align;
invert_m4_m4(p->imat, sc->unistabmat);
@@ -1167,6 +1146,12 @@ static tGPsdata *gp_session_initpaint(bContext *C)
gp_session_initdata(C, p);
+ /* radius for eraser circle is defined in userprefs now */
+ /* NOTE: we do this here, so that if we exit immediately,
+ * erase size won't get lost
+ */
+ p->radius = U.gp_eraser;
+
/* return context data for running paint operator */
return p;
}
@@ -1194,12 +1179,14 @@ static void gp_session_cleanup(tGPsdata *p)
}
/* init new stroke */
-static void gp_paint_initstroke(tGPsdata *p, short paintmode)
+static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode)
{
+ Scene *scene = p->scene;
+
/* get active layer (or add a new one if non-existent) */
p->gpl = gpencil_layer_getactive(p->gpd);
if (p->gpl == NULL) {
- p->gpl = gpencil_layer_addnew(p->gpd, "GP_Layer", 1);
+ p->gpl = gpencil_layer_addnew(p->gpd, "GP_Layer", true);
if (p->custom_color[3])
copy_v3_v3(p->gpl->color, p->custom_color);
@@ -1212,15 +1199,61 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
}
/* get active frame (add a new one if not matching frame) */
- p->gpf = gpencil_layer_getframe(p->gpl, p->scene->r.cfra, 1);
- if (p->gpf == NULL) {
- p->status = GP_STATUS_ERROR;
- if (G.debug & G_DEBUG)
- printf("Error: No frame created (gpencil_paint_init)\n");
- return;
+ if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Add new frames to all frames that we might touch,
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ */
+ bGPDlayer *gpl;
+ for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) {
+ /* Skip if layer not editable */
+ if (gpencil_layer_is_editable(gpl) == false)
+ continue;
+
+ /* Add a new frame if needed (and based off the active frame,
+ * as we need some existing strokes to erase)
+ */
+ gpl->actframe = gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+
+ /* XXX: we omit GP_FRAME_PAINT here for now,
+ * as it is only really useful for doing
+ * paintbuffer drawing
+ */
+ }
+
+ /* Ensure this gets set... */
+ p->gpf = p->gpl->actframe;
+
+ if (p->gpf == NULL) {
+ p->status = GP_STATUS_ERROR;
+ //if (G.debug & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init)\n");
+ return;
+ }
+ }
+ else {
+ /* Drawing Modes - Add a new frame if needed on the active layer */
+ ToolSettings *ts = p->scene->toolsettings;
+ short add_frame_mode;
+
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
+ else
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+ p->gpf = gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode);
+
+ if (p->gpf == NULL) {
+ p->status = GP_STATUS_ERROR;
+ if (G.debug & G_DEBUG)
+ printf("Error: No frame created (gpencil_paint_init)\n");
+ return;
+ }
+ else {
+ p->gpf->flag |= GP_FRAME_PAINT;
+ }
}
- else
- p->gpf->flag |= GP_FRAME_PAINT;
/* set 'eraser' for this stroke if using eraser */
p->paintmode = paintmode;
@@ -1251,7 +1284,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
- if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) {
+ if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
if (p->sa->spacetype == SPACE_VIEW3D) {
View3D *v3d = p->sa->spacedata.first;
RegionView3D *rv3d = p->ar->regiondata;
@@ -1279,7 +1312,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
/* check if points will need to be made in view-aligned space */
- if (p->gpd->flag & GP_DATA_VIEWALIGN) {
+ if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
switch (p->sa->spacetype) {
case SPACE_VIEW3D:
{
@@ -1308,7 +1341,7 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
if (ELEM(NULL, sima, sima->image)) {
/* make strokes be drawn in screen space */
p->gpd->sbuffer_sflag &= ~GP_STROKE_2DSPACE;
- p->gpd->flag &= ~GP_DATA_VIEWALIGN;
+ *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE;
}
else {
p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
@@ -1340,9 +1373,6 @@ static void gp_paint_strokeend(tGPsdata *p)
/* check if doing eraser or not */
if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
- /* smooth stroke before transferring? */
- gp_stroke_smooth(p);
-
/* simplify stroke before transferring? */
gp_stroke_simplify(p);
@@ -1417,6 +1447,17 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en
}
}
+/* Check if tablet eraser is being used (when processing events) */
+static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
+{
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ return (wmtab->Active == EVT_TABLET_ERASER);
+ }
+
+ return false;
+}
+
/* ------------------------------- */
@@ -1467,7 +1508,7 @@ static void gpencil_draw_cancel(bContext *C, wmOperator *op)
static int gpencil_draw_init(bContext *C, wmOperator *op)
{
tGPsdata *p;
- int paintmode = RNA_enum_get(op->ptr, "mode");
+ eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
/* check context */
p = op->customdata = gp_session_initpaint(C);
@@ -1484,9 +1525,6 @@ static int gpencil_draw_init(bContext *C, wmOperator *op)
return 0;
}
- /* radius for eraser circle is defined in userprefs now */
- p->radius = U.gp_eraser;
-
/* everything is now setup ok */
return 1;
}
@@ -1518,20 +1556,24 @@ static void gpencil_draw_status_indicators(tGPsdata *p)
/* print status info */
switch (p->paintmode) {
case GP_PAINTMODE_ERASER:
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase |"
- " ESC/Enter to end"));
+ ED_area_headerprint(p->sa, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | "
+ "ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW_STRAIGHT:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | "
- "ESC/Enter to end"));
+ "ESC/Enter to end (or click outside this area)"));
break;
case GP_PAINTMODE_DRAW:
ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
- "ESC/Enter to end"));
+ "ESC/Enter to end (or click outside this area)"));
+ break;
+ case GP_PAINTMODE_DRAW_POLY:
+ ED_area_headerprint(p->sa, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | "
+ "ESC/Enter to end (or click outside this area)"));
break;
default: /* unhandled future cases */
- ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end"));
+ ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end (or click outside this area)"));
break;
}
break;
@@ -1623,11 +1665,22 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event)
tablet = (wmtab->Active != EVT_TABLET_NONE);
p->pressure = wmtab->Pressure;
- /* if (wmtab->Active == EVT_TABLET_ERASER) */
- /* TODO... this should get caught by the keymaps which call drawing in the first place */
+ /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
+ * The pen has to float over the tablet surface, resulting in
+ * zero pressure (T47101). Ignore pressure values if floating
+ * (i.e. "effectively zero" pressure), and only when the "active"
+ * end is the stylus (i.e. the default when not eraser)
+ */
+ if (p->paintmode == GP_PAINTMODE_ERASER) {
+ if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
+ p->pressure = 1.0f;
+ }
+ }
}
- else
+ else {
+ /* No tablet data -> No pressure info is available */
p->pressure = 1.0f;
+ }
/* special exception for start of strokes (i.e. maybe for just a dot) */
if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
@@ -1819,7 +1872,6 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* we may need to set up paint env again if we're resuming */
/* XXX: watch it with the paintmode! in future,
* it'd be nice to allow changing paint-mode when in sketching-sessions */
- /* XXX: with tablet events, we may event want to check for eraser here, for nicer tablet support */
if (gp_session_initdata(C, p))
gp_paint_initstroke(p, p->paintmode);
@@ -1882,6 +1934,13 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* - for undo (during sketching sessions)
*/
}
+ else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) {
+ /* allow numpad keys so that camera/view manipulations can still take place
+ * - PAD0 in particular is really important for Grease Pencil drawing,
+ * as animators may be working "to camera", so having this working
+ * is essential for ensuring that they can quickly return to that view
+ */
+ }
else {
estate = OPERATOR_RUNNING_MODAL;
}
@@ -2008,14 +2067,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Switch paintmode (temporarily if need be) based on which button was used
* NOTE: This is to make it more convenient to erase strokes when using drawing sessions
*/
- if (event->type == LEFTMOUSE) {
- /* restore drawmode to default */
- p->paintmode = RNA_enum_get(op->ptr, "mode");
- }
- else if (event->type == RIGHTMOUSE) {
+ if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) {
/* turn on eraser */
p->paintmode = GP_PAINTMODE_ERASER;
}
+ else if (event->type == LEFTMOUSE) {
+ /* restore drawmode to default */
+ p->paintmode = RNA_enum_get(op->ptr, "mode");
+ }
gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
@@ -2078,8 +2137,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
case PADMINUS:
p->radius -= 5;
- if (p->radius < 0)
- p->radius = 0;
+ if (p->radius <= 0)
+ p->radius = 1;
break;
}
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 0dd91019a8c..0a36df471f1 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -41,6 +41,7 @@
#include "BLI_math_vector.h"
#include "DNA_gpencil_types.h"
+#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BKE_context.h"
@@ -67,10 +68,15 @@
static int gpencil_select_poll(bContext *C)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = gpencil_layer_getactive(gpd);
- /* only if there's an active layer with an active frame */
- return (gpl && gpl->actframe);
+ /* we just need some visible strokes, and to be in editmode */
+ if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ /* TODO: include a check for visible strokes? */
+ if (gpd->layers.first)
+ return true;
+ }
+
+ return false;
}
/* ********************************************** */
@@ -240,6 +246,109 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot)
}
/* ********************************************** */
+/* Select Grouped */
+
+typedef enum eGP_SelectGrouped {
+ /* Select strokes in the same layer */
+ GP_SEL_SAME_LAYER = 0,
+
+ /* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */
+ /* TODO: All with same appearance - colour/opacity/volumetric/fills ? */
+} eGP_SelectGrouped;
+
+/* ----------------------------------- */
+
+/* On each visible layer, check for selected strokes - if found, select all others */
+static void gp_select_same_layer(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
+ bGPDstroke *gps;
+ bool found = false;
+
+ if (gpf == NULL)
+ continue;
+
+ /* Search for a selected stroke */
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ /* Select all if found */
+ if (found) {
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+}
+
+
+
+/* ----------------------------------- */
+
+static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
+{
+ eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type");
+
+ switch (mode) {
+ case GP_SEL_SAME_LAYER:
+ gp_select_same_layer(C);
+ break;
+
+ default:
+ BLI_assert(!"unhandled select grouped gpencil mode");
+ break;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_select_grouped(wmOperatorType *ot)
+{
+ static EnumPropertyItem prop_select_grouped_types[] = {
+ {GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->idname = "GPENCIL_OT_select_grouped";
+ ot->description = "Select all strokes with similar characteristics";
+
+ /* callbacks */
+ //ot->invoke = WM_menu_invoke;
+ ot->exec = gpencil_select_grouped_exec;
+ ot->poll = gpencil_select_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, GP_SEL_SAME_LAYER, "Type", "");
+}
+
+/* ********************************************** */
/* Select More */
static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 0d7aac7f48f..f54da91af71 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -51,7 +51,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "ED_gpencil.h"
@@ -76,8 +78,6 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
switch (sa->spacetype) {
case SPACE_VIEW3D: /* 3D-View */
- case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
- case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
{
BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
@@ -212,6 +212,45 @@ bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
}
/* ******************************************************** */
+/* Keyframe Indicator Checks */
+
+/* Check whether there's an active GP keyframe on the current frame */
+bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra)
+{
+ /* just check both for now... */
+ // XXX: this could get confusing (e.g. if only on the object, but other places don't show this)
+ if (scene->gpd) {
+ bGPDlayer *gpl = gpencil_layer_getactive(scene->gpd);
+ if (gpl) {
+ if (gpl->actframe) {
+ // XXX: assumes that frame has been fetched already
+ return (gpl->actframe->framenum == cfra);
+ }
+ else {
+ /* XXX: disabled as could be too much of a penalty */
+ /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
+ }
+ }
+ }
+
+ if (ob && ob->gpd) {
+ bGPDlayer *gpl = gpencil_layer_getactive(ob->gpd);
+ if (gpl) {
+ if (gpl->actframe) {
+ // XXX: assumes that frame has been fetched already
+ return (gpl->actframe->framenum == cfra);
+ }
+ else {
+ /* XXX: disabled as could be too much of a penalty */
+ /* return BKE_gpencil_layer_find_frame(gpl, cfra); */
+ }
+ }
+ }
+
+ return false;
+}
+
+/* ******************************************************** */
/* Poll Callbacks */
/* poll callback for adding data/layers - special */
@@ -231,6 +270,92 @@ int gp_active_layer_poll(bContext *C)
}
/* ******************************************************** */
+/* Dynamic Enums of GP Layers */
+/* NOTE: These include an option to create a new layer and use that... */
+
+/* Just existing layers */
+EnumPropertyItem *ED_gpencil_layers_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next, i++) {
+ item_tmp.identifier = gpl->info;
+ item_tmp.name = gpl->info;
+ item_tmp.value = i;
+
+ if (gpl->flag & GP_LAYER_ACTIVE)
+ item_tmp.icon = ICON_GREASEPENCIL;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+/* Existing + Option to add/use new layer */
+EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl;
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, gpd)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Create new layer */
+ /* TODO: have some way of specifying that we don't want this? */
+ {
+ /* active Keying Set */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ZOOMIN;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
+
+ /* Existing layers */
+ for (gpl = gpd->layers.first, i = 0; gpl; gpl = gpl->next, i++) {
+ item_tmp.identifier = gpl->info;
+ item_tmp.name = gpl->info;
+ item_tmp.value = i;
+
+ if (gpl->flag & GP_LAYER_ACTIVE)
+ item_tmp.icon = ICON_GREASEPENCIL;
+ else
+ item_tmp.icon = ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+
+
+/* ******************************************************** */
/* Brush Tool Core */
/* Check if part of stroke occurs within last segment drawn by eraser */
@@ -372,4 +497,147 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
}
}
+/**
+ * Project screenspace coordinates to 3D-space
+ *
+ * \note We include this as a utility function, since the standard method
+ * involves quite a few steps, which are invariably always the same
+ * for all GPencil operations. So, it's nicer to just centralize these.
+ *
+ * \warning Assumes that it is getting called in a 3D view only.
+ */
+bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen_co[2], float r_out[3])
+{
+ View3D *v3d = gsc->sa->spacedata.first;
+ RegionView3D *rv3d = gsc->ar->regiondata;
+ float *rvec = ED_view3d_cursor3d_get(scene, v3d);
+ float ref[3] = {rvec[0], rvec[1], rvec[2]};
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2], mval_prj[2];
+ float dvec[3];
+
+ copy_v2_v2(mval_f, screen_co);
+
+ if (ED_view3d_project_float_global(gsc->ar, ref, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(gsc->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(r_out, rvec, dvec);
+
+ return true;
+ }
+ else {
+ zero_v3(r_out);
+
+ return false;
+ }
+}
+
+/**
+ * Apply smooth to stroke point
+ * \param gps Stroke to smooth
+ * \param i Point index
+ * \param inf Amount of smoothing to apply
+ * \param affect_pressure Apply smoothing to pressure values too?
+ */
+bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure)
+{
+ bGPDspoint *pt = &gps->points[i];
+ float pressure = 0.0f;
+ float sco[3] = {0.0f};
+
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
+ }
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
+
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
+
+ if (affect_pressure) {
+ pressure += pt->pressure * average_fac;
+ }
+
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+
+ /* do pressure too? */
+ if (affect_pressure) {
+ pressure += pt1->pressure * average_fac;
+ pressure += pt2->pressure * average_fac;
+ }
+ }
+ }
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+
+ if (affect_pressure) {
+ pt->pressure = pressure;
+ }
+
+ return true;
+}
+
+/**
+ * Subdivide a stroke once, by adding a point half way between each pair of existing points
+ * \param gps Stroke data
+ * \param new_totpoints Total number of points (after subdividing)
+ */
+void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
+{
+ /* Move points towards end of enlarged points array to leave space for new points */
+ int y = 1;
+ for (int i = gps->totpoints - 1; i > 0; i--) {
+ gps->points[new_totpoints - y] = gps->points[i];
+ y += 2;
+ }
+
+ /* Create interpolated points */
+ for (int i = 0; i < new_totpoints - 1; i += 2) {
+ bGPDspoint *prev = &gps->points[i];
+ bGPDspoint *pt = &gps->points[i + 1];
+ bGPDspoint *next = &gps->points[i + 2];
+
+ /* Interpolate all values */
+ interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f);
+
+ pt->pressure = interpf(prev->pressure, next->pressure, 0.5f);
+ pt->time = interpf(prev->time, next->time, 0.5f);
+ }
+
+ /* Update to new total number of points */
+ gps->totpoints = new_totpoints;
+}
+
/* ******************************************************** */
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index e2a24b9fed7..e264d9e16a3 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -87,19 +87,18 @@ void cpack(unsigned int x);
#define GLA_PIXEL_OFS 0.375f
+BLI_INLINE void glTranslate3iv(const int vec[3]) { glTranslatef(UNPACK3_EX((const float), vec, )); }
+BLI_INLINE void glTranslate2iv(const int vec[2]) { glTranslatef(UNPACK2_EX((const float), vec, ), 0.0f); }
BLI_INLINE void glTranslate3fv(const float vec[3]) { glTranslatef(UNPACK3(vec)); }
BLI_INLINE void glTranslate2fv(const float vec[2]) { glTranslatef(UNPACK2(vec), 0.0f); }
-BLI_INLINE void glTranslate3dv(const double vec[3]) { glTranslated(UNPACK3(vec)); }
-BLI_INLINE void glTranslate2dv(const double vec[2]) { glTranslated(UNPACK2(vec), 0.0f); }
+BLI_INLINE void glScale3iv(const int vec[3]) { glTranslatef(UNPACK3_EX((const float), vec, )); }
+BLI_INLINE void glScale2iv(const int vec[2]) { glTranslatef(UNPACK2_EX((const float), vec, ), 0.0f); }
BLI_INLINE void glScale3fv(const float vec[3]) { glScalef(UNPACK3(vec)); }
BLI_INLINE void glScale2fv(const float vec[2]) { glScalef(UNPACK2(vec), 0.0); }
-BLI_INLINE void glScale3dv(const double vec[3]) { glScaled(UNPACK3(vec)); }
-BLI_INLINE void glScale2dv(const double vec[2]) { glScaled(UNPACK2(vec), 0.0); }
/* v2 versions don't make much sense for rotation */
BLI_INLINE void glRotate3fv(const float angle, const float vec[3]) { glRotatef(angle, UNPACK3(vec)); }
-BLI_INLINE void glRotate3dv(const double angle, const double vec[3]) { glRotated(angle, UNPACK3(vec)); }
#endif /* #ifdef __BIF_GL_H__ */
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index b904417cfcb..e45e5f5e7ab 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -90,12 +90,6 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments
void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments);
/**
- * Returns an integer value as obtained by glGetIntegerv.
- * The param must cause only one value to be gotten from GL.
- */
-int glaGetOneInteger(int param);
-
-/**
* Returns a float value as obtained by glGetFloatv.
* The param must cause only one value to be gotten from GL.
*/
@@ -191,15 +185,6 @@ void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect);
void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect);
#endif
-/* use this for platform hacks. glPointSize is solved here */
-void bglBegin(int mode);
-void bglEnd(void);
-// int bglPointHack(void); /* UNUSED */
-void bglVertex3fv(const float vec[3]);
-void bglVertex3f(float x, float y, float z);
-void bglVertex2fv(const float vec[2]);
-/* intel gfx cards frontbuffer problem */
-// void bglFlush(void); /* UNUSED */
void set_inverted_drawing(int enable);
void setlinestyle(int nr);
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 3c8442218be..fb4897c6532 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -544,10 +544,10 @@ void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, List
/* free the copy/paste buffer */
-void free_fmodifiers_copybuf(void);
+void ANIM_fmodifiers_copybuf_free(void);
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
- * assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
+ * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
* - active: only copy the active modifier
*/
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 35bb12ddaad..15c68378b9a 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -42,6 +42,7 @@ struct bPoseChannel;
struct IDProperty;
struct ListBase;
struct MeshDeformModifierData;
+struct DerivedMesh;
struct Object;
struct ReportList;
struct Scene;
@@ -128,7 +129,7 @@ void ED_armature_deselect_all_visible(struct Object *obedit);
int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
short hits, bool extend, bool deselect, bool toggle, bool do_nearest);
-bool mouse_armature(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
int join_armature_exec(struct bContext *C, struct wmOperator *op);
struct Bone *get_indexed_bone(struct Object *ob, int index);
float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const bool axis_only);
@@ -208,6 +209,7 @@ int BDR_drawSketchNames(struct ViewContext *vc);
/* meshlaplacian.c */
void mesh_deform_bind(struct Scene *scene,
struct MeshDeformModifierData *mmd,
+ struct DerivedMesh *cagedm,
float *vertexcos, int totvert, float cagemat[4][4]);
#ifdef __cplusplus
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 6d53209688d..278e3f97ba7 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -51,13 +51,13 @@ void ED_keymap_curve(struct wmKeyConfig *keyconf);
void undo_push_curve(struct bContext *C, const char *name);
ListBase *object_editcurve_get(struct Object *ob);
-void load_editNurb(struct Object *obedit);
-void make_editNurb(struct Object *obedit);
-void free_editNurb(struct Object *obedit);
+void ED_curve_editnurb_load(struct Object *obedit);
+void ED_curve_editnurb_make(struct Object *obedit);
+void ED_curve_editnurb_free(struct Object *obedit);
-bool mouse_nurb(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_curve_editnurb_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-struct Nurb *add_nurbs_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob);
+struct Nurb *ED_curve_add_nurbs_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob);
bool ED_curve_nurb_select_check(struct Curve *cu, struct Nurb *nu);
int ED_curve_nurb_select_count(struct Curve *cu, struct Nurb *nu);
@@ -71,13 +71,12 @@ bool ED_curve_select_check(struct Curve *cu, struct EditNurb *editnurb);
void ED_curve_deselect_all(struct EditNurb *editnurb);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
-bool ED_curve_select_nth(struct Curve *cu, int nth, int skip, int offset);
/* editfont.h */
void undo_push_font(struct bContext *C, const char *name);
-void make_editText(struct Object *obedit);
-void load_editText(struct Object *obedit);
-void free_editText(struct Object *obedit);
+void ED_curve_editfont_load(struct Object *obedit);
+void ED_curve_editfont_make(struct Object *obedit);
+void ED_curve_editfont_free(struct Object *obedit);
void ED_text_to_object(struct bContext *C, struct Text *text, const bool split_lines);
@@ -88,7 +87,7 @@ int ED_curve_updateAnimPaths(struct Curve *cu);
bool ED_curve_active_center(struct Curve *cu, float center[3]);
-bool mouse_font(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_curve_editfont_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
#if 0
/* debug only */
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 448f2c83aad..0f638c449ad 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -41,7 +41,9 @@ struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
+struct bAnimContext;
struct PointerRNA;
+struct wmWindowManager;
struct wmKeyConfig;
@@ -77,6 +79,8 @@ struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct S
/* 3D View */
struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d);
+bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra);
+
/* ----------- Stroke Editing Utilities ---------------- */
bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
@@ -100,7 +104,7 @@ void ED_gpencil_strokes_copybuf_free(void);
void ED_gpencil_draw_2dimage(const struct bContext *C);
void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
-void ED_gpencil_draw_view3d(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
+void ED_gpencil_draw_view3d(struct wmWindowManager *wm, struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
const int cfra, const char spacetype);
@@ -121,14 +125,12 @@ void ED_gplayer_frames_duplicate(struct bGPDlayer *gpl);
void ED_gplayer_frames_keytype_set(struct bGPDlayer *gpl, short type);
void ED_gplayer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
+void ED_gplayer_mirror_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
-#if 0
-void free_gpcopybuf(void);
-void copy_gpdata(void);
-void paste_gpdata(void);
+void ED_gpencil_anim_copybuf_free(void);
+bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac);
+bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mode);
-void mirror_gplayer_frames(struct bGPDlayer *gpl, short mode);
-#endif
/* ------------ Grease-Pencil Undo System ------------------ */
int ED_gpencil_session_active(void);
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 4c4cec2ee29..283113f93d6 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -66,6 +66,7 @@ void ED_image_get_uv_aspect(struct Image *ima, struct ImageUser *iuser, float *a
void ED_image_mouse_pos(struct SpaceImage *sima, struct ARegion *ar, const int mval[2], float co[2]);
void ED_image_point_pos(struct SpaceImage *sima, struct ARegion *ar, float x, float y, float *xr, float *yr);
void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, const float co[2], float r_co[2]);
+bool ED_image_slot_cycle(struct Image *image, int direction);
bool ED_space_image_show_render(struct SpaceImage *sima);
bool ED_space_image_show_paint(struct SpaceImage *sima);
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index c6ef303b694..fae3e3677a0 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -82,7 +82,8 @@ typedef enum eEditKeyframes_Snap {
SNAP_KEYS_NEARSEC,
SNAP_KEYS_NEARMARKER,
SNAP_KEYS_HORIZONTAL,
- SNAP_KEYS_VALUE
+ SNAP_KEYS_VALUE,
+ SNAP_KEYS_TIME,
} eEditKeyframes_Snap;
/* mirroring tools */
@@ -91,7 +92,8 @@ typedef enum eEditKeyframes_Mirror {
MIRROR_KEYS_YAXIS,
MIRROR_KEYS_XAXIS,
MIRROR_KEYS_MARKER,
- MIRROR_KEYS_VALUE
+ MIRROR_KEYS_VALUE,
+ MIRROR_KEYS_TIME,
} eEditKeyframes_Mirror;
/* use with BEZT_OK_REGION_LASSO */
@@ -114,6 +116,34 @@ struct KeyframeEdit_CircleData {
/* ************************************************ */
/* Non-Destuctive Editing API (keyframes_edit.c) */
+/* --- Defines for 'OK' polls + KeyframeEditData Flags --------- */
+
+/* which verts of a keyframe is active (after polling) */
+typedef enum eKeyframeVertOk {
+ /* 'key' itself is ok */
+ KEYFRAME_OK_KEY = (1 << 0),
+ /* 'handle 1' is ok */
+ KEYFRAME_OK_H1 = (1 << 1),
+ /* 'handle 2' is ok */
+ KEYFRAME_OK_H2 = (1 << 2),
+ /* all flags */
+ KEYFRAME_OK_ALL = (KEYFRAME_OK_KEY | KEYFRAME_OK_H1 | KEYFRAME_OK_H2)
+} eKeyframeVertOk;
+
+/* Flags for use during iteration */
+typedef enum eKeyframeIterFlags {
+ /* consider handles in addition to key itself */
+ KEYFRAME_ITER_INCL_HANDLES = (1 << 0),
+
+ /* Perform NLA time remapping (global -> strip) for the "f1" parameter
+ * (e.g. used for selection tools on summary tracks)
+ */
+ KED_F1_NLA_UNMAP = (1 << 1),
+
+ /* Perform NLA time remapping (global -> strip) for the "f2" parameter */
+ KED_F2_NLA_UNMAP = (1 << 2),
+} eKeyframeIterFlags;
+
/* --- Generic Properties for Keyframe Edit Tools ----- */
typedef struct KeyframeEditData {
@@ -129,8 +159,8 @@ typedef struct KeyframeEditData {
int curIndex; /* index of current keyframe being iterated over */
/* flags */
- short curflags; /* current flags for the keyframe we're reached in the iteration process */
- short iterflags; /* settings for iteration process */ // XXX: unused...
+ eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */
+ eKeyframeIterFlags iterflags; /* settings for iteration process */
} KeyframeEditData;
/* ------- Function Pointer Typedefs ---------------- */
@@ -140,25 +170,6 @@ typedef void (*FcuEditFunc)(struct FCurve *fcu);
/* callback function that operates on the given BezTriple */
typedef short (*KeyframeEditFunc)(KeyframeEditData *ked, struct BezTriple *bezt);
-/* ---------- Defines for 'OK' polls ----------------- */
-
-/* which verts of a keyframe is active (after polling) */
-typedef enum eKeyframeVertOk {
- /* 'key' itself is ok */
- KEYFRAME_OK_KEY = (1 << 0),
- /* 'handle 1' is ok */
- KEYFRAME_OK_H1 = (1 << 1),
- /* 'handle 2' is ok */
- KEYFRAME_OK_H2 = (1 << 2),
- /* all flags */
- KEYFRAME_OK_ALL = (KEYFRAME_OK_KEY | KEYFRAME_OK_H1 | KEYFRAME_OK_H2)
-} eKeyframeVertOk;
-
-/* Flags for use during iteration */
-typedef enum eKeyframeIterFlags {
- /* consider handles in addition to key itself */
- KEYFRAME_ITER_INCL_HANDLES = (1 << 0),
-} eKeyframeIterFlags;
/* ------- Custom Data Type Defines ------------------ */
@@ -261,7 +272,7 @@ void sample_fcurve(struct FCurve *fcu);
/* ----------- */
-void free_anim_copybuf(void);
+void ANIM_fcurves_copybuf_free(void);
short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data);
short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data,
const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 5d76c9e0f6f..81e2558e765 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -91,14 +91,14 @@ void update_autoflags_fcurve(struct FCurve *fcu, struct bContext *C, struct Repo
* Use this when validation of necessary animation data isn't necessary as it already
* exists, and there is a beztriple that can be directly copied into the array.
*/
-int insert_bezt_fcurve(struct FCurve *fcu, struct BezTriple *bezt, short flag);
+int insert_bezt_fcurve(struct FCurve *fcu, const struct BezTriple *bezt, short flag);
/* Main Keyframing API call:
* Use this when validation of necessary animation data isn't necessary as it
* already exists. It will insert a keyframe using the current value being keyframed.
* Returns the index at which a keyframe was added (or -1 if failed)
*/
-int insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag);
+int insert_vert_fcurve(struct FCurve *fcu, float x, float y, char keytype, short flag);
/* -------- */
@@ -106,7 +106,7 @@ int insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag);
* Use this to insert a keyframe using the current value being keyframed, in the
* nominated F-Curve (no creation of animation data performed). Returns success.
*/
-bool insert_keyframe_direct(struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, short flag);
+bool insert_keyframe_direct(struct ReportList *reports, struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, char keytype, short flag);
/* -------- */
@@ -114,7 +114,7 @@ bool insert_keyframe_direct(struct ReportList *reports, struct PointerRNA ptr, s
* Use this to create any necessary animation data, and then insert a keyframe
* using the current value being keyframed, in the relevant place. Returns success.
*/
-short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag);
+short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, char keytype, short flag);
/* Main Keyframing API call:
* Use this to delete keyframe on current frame for relevant channel. Will perform checks just in case.
@@ -235,6 +235,19 @@ typedef enum eCreateDriverFlags {
CREATEDRIVER_WITH_FMODIFIER = (1 << 1), /* create drivers with Generator FModifier (for backwards compat) */
} eCreateDriverFlags;
+/* Heuristic to use for connecting target properties to driven ones */
+typedef enum eCreateDriver_MappingTypes {
+ CREATEDRIVER_MAPPING_1_N = 0, /* 1 to Many - Use the specified index, and drive all elements with it */
+ CREATEDRIVER_MAPPING_1_1 = 1, /* 1 to 1 - Only for the specified index on each side */
+ CREATEDRIVER_MAPPING_N_N = 2, /* Many to Many - Match up the indices one by one (only for drivers on vectors/arrays) */
+
+ CREATEDRIVER_MAPPING_NONE = 3, /* None (Single Prop) - Do not create driver with any targets; these will get added later instead */
+ CREATEDRIVER_MAPPING_NONE_ALL = 4, /* None (All Properties) - Do not create driver with any targets; these will get added later instead */
+} eCreateDriver_MappingTypes;
+
+/* RNA Enum of eCreateDriver_MappingTypes, for use by the appropriate operators */
+extern EnumPropertyItem prop_driver_create_mapping_types[];
+
/* -------- */
/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
@@ -244,8 +257,24 @@ struct FCurve *verify_driver_fcurve(struct ID *id, const char rna_path[], const
/* -------- */
-/* Returns whether there is a driver in the copy/paste buffer to paste */
-bool ANIM_driver_can_paste(void);
+/* Main Driver Management API calls:
+ * Add a new driver for the specified property on the given ID block,
+ * and make it be driven by the specified target.
+ *
+ * This is intended to be used in conjunction with a modal "eyedropper"
+ * for picking the variable that is going to be used to drive this one.
+ *
+ * - flag: eCreateDriverFlags
+ * - driver_type: eDriver_Types
+ * - mapping_type: eCreateDriver_MappingTypes
+ */
+int ANIM_add_driver_with_target(
+ struct ReportList *reports,
+ struct ID *dst_id, const char dst_path[], int dst_index,
+ struct ID *src_id, const char src_path[], int src_index,
+ short flag, int driver_type, short mapping_type);
+
+/* -------- */
/* Main Driver Management API calls:
* Add a new driver for the specified property on the given ID block
@@ -257,6 +286,19 @@ int ANIM_add_driver(struct ReportList *reports, struct ID *id, const char rna_pa
*/
bool ANIM_remove_driver(struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
+/* -------- */
+
+/* Clear copy-paste buffer for drivers */
+void ANIM_drivers_copybuf_free(void);
+
+/* Clear copy-paste buffer for driver variable sets */
+void ANIM_driver_vars_copybuf_free(void);
+
+/* -------- */
+
+/* Returns whether there is a driver in the copy/paste buffer to paste */
+bool ANIM_driver_can_paste(void);
+
/* Main Driver Management API calls:
* Make a copy of the driver for the specified property on the given ID block
*/
@@ -268,6 +310,17 @@ bool ANIM_copy_driver(struct ReportList *reports, struct ID *id, const char rna_
*/
bool ANIM_paste_driver(struct ReportList *reports, struct ID *id, const char rna_path[], int array_index, short flag);
+/* -------- */
+
+/* Checks if there are driver variables in the copy/paste buffer */
+bool ANIM_driver_vars_can_paste(void);
+
+/* Copy the given driver's variables to the buffer */
+bool ANIM_driver_vars_copy(struct ReportList *reports, struct FCurve *fcu);
+
+/* Paste the variables in the buffer to the given FCurve */
+bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool replace);
+
/* ************ Auto-Keyframing ********************** */
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 6fe1524cb6d..30d66577770 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -33,8 +33,8 @@
struct Object;
-void free_editLatt(struct Object *ob);
-void make_editLatt(struct Object *obedit);
-void load_editLatt(struct Object *obedit);
+void ED_lattice_editlatt_free(struct Object *ob);
+void ED_lattice_editlatt_make(struct Object *obedit);
+void ED_lattice_editlatt_load(struct Object *obedit);
#endif /* __ED_LATTICE_H__ */
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 05a4ccabd1b..232d7d1d234 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -39,13 +39,13 @@ void ED_operatortypes_metaball(void);
void ED_operatormacros_metaball(void);
void ED_keymap_metaball(struct wmKeyConfig *keyconf);
-struct MetaElem *add_metaball_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], float dia, int type);
+struct MetaElem *ED_mball_add_primitive(struct bContext *C, struct Object *obedit, float mat[4][4], float dia, int type);
-bool mouse_mball(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_mball_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
-void free_editMball(struct Object *obedit);
-void make_editMball(struct Object *obedit);
-void load_editMball(struct Object *obedit);
+void ED_mball_editmball_free(struct Object *obedit);
+void ED_mball_editmball_make(struct Object *obedit);
+void ED_mball_editmball_load(struct Object *obedit);
void undo_push_mball(struct bContext *C, const char *name);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 8e19ec839d8..5436ef4b06b 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -129,8 +129,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
/* editmesh_select.c */
-void EDBM_select_mirrored(struct BMEditMesh *em, bool extend,
- int *r_totmirr, int *r_totfail);
+void EDBM_select_mirrored(
+ struct BMEditMesh *em, const int axis, const bool extend,
+ int *r_totmirr, int *r_totfail);
void EDBM_automerge(struct Scene *scene, struct Object *ob, bool update, const char hflag);
bool EDBM_backbuf_border_init(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
@@ -196,7 +197,7 @@ void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEd
/* editface.c */
-void paintface_flush_flags(struct Object *ob);
+void paintface_flush_flags(struct Object *ob, short flag);
bool paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], bool extend, bool deselect, bool toggle);
int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, bool select, bool extend);
void paintface_deselect_all_visible(struct Object *ob, int action, bool flush_flags);
@@ -218,8 +219,8 @@ typedef struct MirrTopoStore_t {
int prev_ob_mode;
} MirrTopoStore_t;
-bool ED_mesh_mirrtopo_recalc_check(struct Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_topo_store);
-void ED_mesh_mirrtopo_init(struct Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
+bool ED_mesh_mirrtopo_recalc_check(struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store);
+void ED_mesh_mirrtopo_init(struct Mesh *me, struct DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
const bool skip_em_vert_array_init);
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store);
@@ -308,17 +309,18 @@ int join_mesh_exec(struct bContext *C, struct wmOperator *op);
int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
-int ED_mesh_mirror_spatial_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode);
-int ED_mesh_mirror_topo_table(struct Object *ob, char mode);
+int ED_mesh_mirror_spatial_table(
+ struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, const float co[3], char mode);
+int ED_mesh_mirror_topo_table(struct Object *ob, struct DerivedMesh *dm, char mode);
/* retrieves mirrored cache vert, or NULL if there isn't one.
* note: calling this without ensuring the mirror cache state
* is bad.*/
-int mesh_get_x_mirror_vert(struct Object *ob, int index, const bool use_topology);
+int mesh_get_x_mirror_vert(struct Object *ob, struct DerivedMesh *dm, int index, const bool use_topology);
struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em,
struct BMVert *eve, const float co[3],
int index, const bool use_topology);
-int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em);
+int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm);
int ED_mesh_mirror_get_vert(struct Object *ob, int index);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 1445308c485..7fe9a0c320c 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -80,7 +80,7 @@ void ED_node_draw_snap(struct View2D *v2d, const float cent[2], float size, Node
/* node_draw.c */
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
-void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree);
+void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
void ED_node_sort(struct bNodeTree *ntree);
float ED_node_grid_size(void);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c62bdc1ba87..04ff5692717 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -137,6 +137,7 @@ float ED_object_new_primitive_matrix(
void ED_object_add_unit_props(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
+void ED_object_add_mesh_props(struct wmOperatorType *ot);
bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, const char view_align_axis,
float loc[3], float rot[3],
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned);
@@ -151,7 +152,7 @@ void ED_object_single_users(struct Main *bmain, struct Scene *scene, const bool
void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Object *ob);
/* object motion paths */
-void ED_objects_clear_paths(struct bContext *C);
+void ED_objects_clear_paths(struct bContext *C, bool only_selected);
void ED_objects_recalculate_paths(struct bContext *C, struct Scene *scene);
/* constraints */
@@ -169,12 +170,12 @@ void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con)
void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con);
/* object_lattice.c */
-bool mouse_lattice(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_lattice_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
void undo_push_lattice(struct bContext *C, const char *name);
/* object_lattice.c */
-void ED_setflagsLatt(struct Object *obedit, int flag);
+void ED_lattice_flags_set(struct Object *obedit, int flag);
/* object_modifier.c */
enum {
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 5bc606ca725..6a558d1c185 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -67,9 +67,10 @@ void ED_region_panels(
const bool vertical);
void ED_region_header_init(struct ARegion *ar);
void ED_region_header(const struct bContext *C, struct ARegion *ar);
+void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *ar);
void ED_region_info_draw(struct ARegion *ar, const char *text, float fill_color[4], const bool full_redraw);
-void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, rctf frame, float zoomx, float zoomy);
+void ED_region_image_metadata_draw(int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy);
void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy);
float ED_region_blend_factor(struct ARegion *ar);
void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect);
@@ -90,7 +91,7 @@ void ED_area_tag_refresh(ScrArea *sa);
void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
void ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
void ED_area_headerprint(ScrArea *sa, const char *str);
-void ED_area_newspace(struct bContext *C, ScrArea *sa, int type);
+void ED_area_newspace(struct bContext *C, ScrArea *sa, int type, const bool skip_ar_exit);
void ED_area_prevspace(struct bContext *C, ScrArea *sa);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
@@ -112,7 +113,7 @@ void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh,
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh);
void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
-void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa, const bool was_prev_temp);
+void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index b14ba45a64d..db8085a6696 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -94,7 +94,6 @@ enum TfmMode {
#define CTX_NO_PET (1 << 2)
#define CTX_NO_MIRROR (1 << 3)
#define CTX_AUTOCONFIRM (1 << 4)
-#define CTX_NDOF (1 << 5)
#define CTX_MOVIECLIP (1 << 6)
#define CTX_MASK (1 << 7)
#define CTX_PAINT_CURVE (1 << 8)
@@ -110,6 +109,7 @@ struct TransInfo;
struct Base;
struct Scene;
struct Object;
+struct wmOperator;
/* UNUSED */
// int BIF_snappingSupported(struct Object *obedit);
@@ -169,30 +169,52 @@ typedef struct DepthPeel {
struct ListBase;
-typedef enum SnapMode {
+typedef enum SnapSelect {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
SNAP_NOT_OBEDIT = 2
-} SnapMode;
+} SnapSelect;
#define SNAP_MIN_DISTANCE 30
-#define TRANSFORM_DIST_MAX_RAY (FLT_MAX / 2.0f)
-bool peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
-bool peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode);
-bool snapObjectsTransform(struct TransInfo *t, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode);
-bool snapObjectsContext(struct bContext *C, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode);
+bool peelObjectsTransForm(
+ struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+ /* return args */
+ struct ListBase *r_depth_peels);
+bool peelObjectsContext(
+ struct bContext *C, const float mval[2], SnapSelect snap_select,
+ /* return args */
+ struct ListBase *r_depth_peels);
+bool snapObjectsTransform(
+ struct TransInfo *t, const float mval[2], SnapSelect snap_select,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_dist_px);
+bool snapObjectsContext(
+ struct bContext *C, const float mval[2], SnapSelect snap_select,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_dist_px);
/* taks args for all settings */
-bool snapObjectsEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode,
- const float mval[2], float *r_dist_px,
- float r_loc[3], float r_no[3], float *r_ray_dist, SnapMode mode);
-bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode,
- struct Object **r_ob, float r_obmat[4][4],
- const float ray_start[3], const float ray_normal[3], float *r_ray_dist,
- const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode);
-
-bool snapNodesTransform(struct TransInfo *t, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode);
-bool snapNodesContext(struct bContext *C, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode);
-
-#endif
-
+bool snapObjectsEx(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit,
+ const float mval[2], SnapSelect snap_select, const short snap_mode,
+ float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_dist_px);
+bool snapObjectsRayEx(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit,
+ const float mval[2], SnapSelect snap_select, const short snap_mode,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
+ struct Object **r_ob, float r_obmat[4][4]);
+
+bool snapNodesTransform(
+ struct TransInfo *t, const int mval[2], SnapSelect snap_select,
+ /* return args */
+ float r_loc[2], float *r_dist_px, char *r_node_border);
+bool snapNodesContext(
+ struct bContext *C, const int mval[2], SnapSelect snap_select,
+ /* return args */
+ float r_loc[2], float *r_dist_px, char *r_node_border);
+
+#endif /* __ED_TRANSFORM_H__ */
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 496ce7f2c60..f143ea478c6 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -32,6 +32,7 @@
#define __ED_UTIL_H__
struct bContext;
+struct SpaceLink;
struct wmOperator;
struct wmOperatorType;
@@ -44,6 +45,8 @@ bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id);
+void ED_OT_flush_edits(struct wmOperatorType *ot);
+
/* ************** Undo ************************ */
/* undo.c */
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 416e821b3f8..d8a3f5e75f5 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -74,6 +74,7 @@ typedef struct ViewContext {
struct Object *obedit;
struct ARegion *ar;
struct View3D *v3d;
+ struct wmWindow *win;
struct RegionView3D *rv3d;
struct BMEditMesh *em;
int mval[2];
@@ -265,7 +266,7 @@ float ED_view3d_radius_to_dist(
const char persp, const bool use_aspect,
const float radius);
-void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4]);
+void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4]);
/* backbuffer select and draw support */
void ED_view3d_backbuf_validate(struct ViewContext *vc);
@@ -319,19 +320,27 @@ void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d);
#endif
int ED_view3d_scene_layer_set(int lay, const int *values, int *active);
+void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
+void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt);
+
bool ED_view3d_context_activate(struct bContext *C);
void ED_view3d_draw_offscreen_init(struct Scene *scene, struct View3D *v3d);
void ED_view3d_draw_offscreen(
struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int winx, int winy, float viewmat[4][4],
- float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp,
- struct GPUOffScreen *ofs,
+ float winmat[4][4], bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
struct GPUFX *fx, struct GPUFXSettings *fx_settings,
- const char *viewname);
-
-struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
-struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, const char *viewname, char err_out[256]);
+ struct GPUOffScreen *ofs);
+
+struct ImBuf *ED_view3d_draw_offscreen_imbuf(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey,
+ unsigned int flag, bool draw_background,
+ int alpha_mode, int samples, bool full_samples, const char *viewname,
+ struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
+struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
+ struct Scene *scene, struct Object *camera, int width, int height,
+ unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background,
+ int alpha_mode, int samples, bool full_samples, const char *viewname,
+ struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
@@ -387,6 +396,18 @@ void ED_view3d_operator_properties_viewmat_set(struct bContext *C, struct wmOper
void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx, int *winy, float persmat[4][4]);
#endif
+bool ED_view3d_snap_from_region(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar,
+ const float mval[2], float dist_px,
+ bool use_depth, bool use_obedit,
+ bool use_vert, bool use_edge, bool use_face,
+ float r_co[3], float r_no[3]);
+
+bool ED_view3d_snap_from_ray(
+ struct Scene *scene,
+ const float ray_start[3], const float ray_normal[3],
+ float r_co[3]);
+
/* render */
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *ar);
void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index e6421b0de41..76ff9e0fbd8 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -374,8 +374,8 @@ DEF_ICON(MESH_MONKEY)
DEF_ICON(MESH_CYLINDER)
DEF_ICON(MESH_TORUS)
DEF_ICON(MESH_CONE)
+DEF_ICON(MESH_CAPSULE)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK610)
DEF_ICON(BLANK611)
#endif
DEF_ICON(LAMP_POINT)
@@ -1015,3 +1015,8 @@ DEF_VICO(MOVE_UP_VEC)
DEF_VICO(MOVE_DOWN_VEC)
DEF_VICO(X_VEC)
DEF_VICO(SMALL_TRI_RIGHT_VEC)
+
+DEF_VICO(KEYTYPE_KEYFRAME_VEC)
+DEF_VICO(KEYTYPE_BREAKDOWN_VEC)
+DEF_VICO(KEYTYPE_EXTREME_VEC)
+DEF_VICO(KEYTYPE_JITTER_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index ba3e3a61aee..9aad340d2fb 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -39,9 +39,11 @@
/* Struct Declarations */
struct ID;
+struct IDProperty;
struct ListBase;
struct ARegion;
struct ScrArea;
+struct bScreen;
struct wmEvent;
struct wmWindow;
struct wmOperator;
@@ -60,6 +62,7 @@ struct uiFontStyle;
struct uiWidgetColors;
struct Image;
struct ImageUser;
+struct wmKeyConfig;
struct wmOperatorType;
struct uiWidgetColors;
struct MTex;
@@ -176,7 +179,7 @@ enum {
UI_BUT_DRAG_MULTI = (1 << 25), /* edit this button as well as the active button (not just dragging) */
UI_BUT_SCA_LINK_GREY = (1 << 26), /* used to flag if sca links shoud be gray out */
UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */
- UI_BUT_TIP_FORCE = (1 << 28), /* force show tooltips when holding option/alt if U's USER_TOOLTIPS is off */
+ UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */
UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */
UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */
};
@@ -203,6 +206,12 @@ enum {
UI_BUT_ALIGN_RIGHT = (1 << 16),
UI_BUT_ALIGN_DOWN = (1 << 17),
UI_BUT_ALIGN = (UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT | UI_BUT_ALIGN_DOWN),
+
+ /* Warning - HACK! Needed for buttons which are not TOP/LEFT aligned, but have some top/left corner stitched to some
+ * other TOP/LEFT-aligned button, because of 'corrective' hack in widget_roundbox_set()... */
+ UI_BUT_ALIGN_STITCH_TOP = (1 << 18),
+ UI_BUT_ALIGN_STITCH_LEFT = (1 << 19),
+ UI_BUT_ALIGN_ALL = (UI_BUT_ALIGN | UI_BUT_ALIGN_STITCH_TOP | UI_BUT_ALIGN_STITCH_LEFT),
};
/* scale fixed button widths by this to account for DPI */
@@ -345,6 +354,7 @@ typedef void (*uiButHandleFunc)(struct bContext *C, void *arg1, void *arg2);
typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char *origstr);
typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
+typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
typedef void (*uiButSearchFunc)(const struct bContext *C, void *arg, const char *str, uiSearchItems *items);
/* Must return allocated string. */
typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip);
@@ -355,6 +365,13 @@ typedef void (*uiBlockHandleFunc)(struct bContext *C, void *arg, int event);
typedef void (*uiMenuCreateFunc)(struct bContext *C, struct uiLayout *layout, void *arg1);
typedef void (*uiMenuHandleFunc)(struct bContext *C, void *arg, int event);
+/**
+ * Used for cycling menu values without opening the menu (Ctrl-Wheel).
+ * \param direction: forward or backwards [1 / -1].
+ * \param arg1: uiBut.poin (as with #uiMenuCreateFunc).
+ * \return true when the button was changed.
+ */
+typedef bool (*uiMenuStepFunc)(struct bContext *C, int direction, void *arg1);
/* Popup Menus
*
@@ -478,6 +495,7 @@ bool UI_but_active_drop_color(struct bContext *C);
void UI_but_flag_enable(uiBut *but, int flag);
void UI_but_flag_disable(uiBut *but, int flag);
+bool UI_but_flag_is_set(uiBut *but, int flag);
void UI_but_drawflag_enable(uiBut *but, int flag);
void UI_but_drawflag_disable(uiBut *but, int flag);
@@ -623,8 +641,7 @@ void UI_but_string_info_get(struct bContext *C, uiBut *but, ...) ATTR_SENTINEL(0
#define UI_ID_AUTO_NAME (1 << 7)
#define UI_ID_FAKE_USER (1 << 8)
#define UI_ID_PIN (1 << 9)
-#define UI_ID_BROWSE_RENDER (1 << 10)
-#define UI_ID_PREVIEWS (1 << 11)
+#define UI_ID_PREVIEWS (1 << 10)
#define UI_ID_FULL (UI_ID_RENAME | UI_ID_BROWSE | UI_ID_ADD_NEW | UI_ID_OPEN | UI_ID_ALONE | UI_ID_DELETE | UI_ID_LOCAL)
int UI_icon_from_id(struct ID *id);
@@ -645,7 +662,7 @@ uiBut *uiDefKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y
uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y, short width, short height, short *keypoin, short *modkeypoin, const char *tip);
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, int x, int y, short width, short height, float a1, float a2, const char *tip);
-uiBut *uiDefSearchButO_ptr(uiBlock *block, struct wmOperatorType *ot, IDProperty *properties,
+uiBut *uiDefSearchButO_ptr(uiBlock *block, struct wmOperatorType *ot, struct IDProperty *properties,
void *arg, int retval, int icon, int maxlen, int x, int y,
short width, short height, float a1, float a2, const char *tip);
@@ -665,7 +682,9 @@ uiBut *UI_block_links_find_inlink(uiBlock *block, void *poin);
/* use inside searchfunc to add items */
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid);
/* bfunc gets search item *poin as arg2, or if NULL the old string */
-void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg1, uiButHandleFunc bfunc, void *active);
+void UI_but_func_search_set(
+ uiBut *but, uiButSearchCreateFunc cfunc, uiButSearchFunc sfunc,
+ void *arg1, uiButHandleFunc bfunc, void *active);
/* height in pixels, it's using hardcoded values still */
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
@@ -688,7 +707,10 @@ void UI_but_func_drawextra_set(
void (*func)(const struct bContext *C, void *, void *, void *, struct rcti *rect),
void *arg1, void *arg2);
+void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func);
+
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN);
+void UI_but_tooltip_refresh(struct bContext *C, uiBut *but);
void UI_but_tooltip_timer_remove(struct bContext *C, uiBut *but);
bool UI_textbutton_activate_rna(const struct bContext *C, struct ARegion *ar,
@@ -759,6 +781,7 @@ void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers)
void UI_init(void);
void UI_init_userdef(void);
void UI_reinit_font(void);
+void UI_reinit_gl_state(void);
void UI_exit(void);
/* Layout
@@ -950,7 +973,7 @@ void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname
void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value);
void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value);
-PointerRNA uiItemFullO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, IDProperty *properties, int context, int flag);
+PointerRNA uiItemFullO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, struct IDProperty *properties, int context, int flag);
PointerRNA uiItemFullO(uiLayout *layout, const char *idname, const char *name, int icon, struct IDProperty *properties, int context, int flag);
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon);
@@ -960,7 +983,13 @@ void uiItemEnumR(uiLayout *layout, const char *name, int icon, struct PointerRNA
void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *value, const char *name, int icon);
void uiItemsEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon);
-void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, struct IDProperty *properties, int context, int flag);
+void uiItemsFullEnumO(
+ uiLayout *layout, const char *opname, const char *propname,
+ struct IDProperty *properties, int context, int flag);
+void uiItemsFullEnumO_items(
+ uiLayout *layout, struct wmOperatorType *ot, PointerRNA ptr, PropertyRNA *prop,
+ IDProperty *properties, int context, int flag,
+ const EnumPropertyItem *item_array, int totitem);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemLDrag(uiLayout *layout, struct PointerRNA *ptr, const char *name, int icon); /* label icon for dragging */
@@ -979,7 +1008,9 @@ typedef struct uiDragColorHandle {
bool gamma_corrected;
} uiDragColorHandle;
-void ED_button_operatortypes(void);
+void ED_operatortypes_ui(void);
+void ED_keymap_ui(struct wmKeyConfig *keyconf);
+
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 2b19b6180e5..dc843952229 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -200,8 +200,9 @@ enum {
TH_SEQ_EFFECT,
TH_SEQ_TRANSITION,
TH_SEQ_META,
+ TH_SEQ_TEXT,
TH_SEQ_PREVIEW,
-
+
TH_EDGE_SHARP,
TH_EDITMESH_ACTIVE,
@@ -334,6 +335,9 @@ void UI_ThemeColorBlendShadeAlpha(int colorid1, int colorid2, float fac, int
float UI_GetThemeValuef(int colorid);
int UI_GetThemeValue(int colorid);
+float UI_GetThemeValueTypef(int colorid, int spacetype);
+int UI_GetThemeValueType(int colorid, int spacetype);
+
// get three color values, scaled to 0.0-1.0 range
void UI_GetThemeColor3fv(int colorid, float col[3]);
void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]);
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 2c8f5f6590a..4caacb65f5f 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -153,7 +153,7 @@ void UI_view2d_curRect_reset(struct View2D *v2d);
void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag);
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
-void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, int resize);
+void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
/* per tab offsets, returns 1 if tab changed */
bool UI_view2d_tab_set(struct View2D *v2d, int tab);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 3efb4921bbe..c57f8d5c7a8 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -40,6 +40,7 @@ set(INC_SYS
set(SRC
interface.c
+ interface_align.c
interface_anim.c
interface_draw.c
interface_eyedropper.c
diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript
deleted file mode 100644
index ea6f35c54e6..00000000000
--- a/source/blender/editors/interface/SConscript
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- # python button eval
- '../../python',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
- if env['WITH_BF_IME']:
- defs.append('WITH_INPUT_IME')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-env.BlenderLib('bf_editors_interface', sources, incs, defs, libtype=['core'], priority=[110])
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 78021612195..fac1267cc62 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -262,7 +262,7 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
}
if (bt->next && bt->rect.xmin < bt->next->rect.xmin) {
- /* End of this column, and it’s not the last one. */
+ /* End of this column, and it's not the last one. */
for (col_bt = init_col_bt; col_bt->prev != bt; col_bt = col_bt->next) {
col_bt->rect.xmin = x1addval;
col_bt->rect.xmax = x1addval + i + block->bounds;
@@ -368,9 +368,11 @@ static void ui_block_bounds_calc_popup(
wmWindow *window, uiBlock *block,
eBlockBoundsCalc bounds_calc, const int xy[2])
{
- int startx, starty, endx, endy, width, height, oldwidth, oldheight;
+ int width, height, oldwidth, oldheight;
int oldbounds, xmax, ymax;
const int margin = UI_SCREEN_MARGIN;
+ rcti rect, rect_bounds;
+ int ofs_dummy[2];
oldbounds = block->bounds;
@@ -405,27 +407,18 @@ static void ui_block_bounds_calc_popup(
/* offset block based on mouse position, user offset is scaled
* along in case we resized the block in ui_block_bounds_calc_text */
- startx = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth;
- starty = xy[1] + block->rect.ymin + (block->my * height) / oldheight;
+ rect.xmin = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth;
+ rect.ymin = xy[1] + block->rect.ymin + (block->my * height) / oldheight;
+ rect.xmax = rect.xmin + width;
+ rect.ymax = rect.ymin + height;
- if (startx < margin)
- startx = margin;
- if (starty < margin)
- starty = margin;
+ rect_bounds.xmin = margin;
+ rect_bounds.ymin = margin;
+ rect_bounds.xmax = xmax - margin;
+ rect_bounds.ymax = ymax - UI_POPUP_MENU_TOP;
- endx = startx + width;
- endy = starty + height;
-
- if (endx > xmax) {
- endx = xmax - margin;
- startx = endx - width;
- }
- if (endy > ymax - margin) {
- endy = ymax - margin;
- starty = endy - height;
- }
-
- ui_block_translate(block, startx - block->rect.xmin, starty - block->rect.ymin);
+ BLI_rcti_clamp(&rect, &rect_bounds, ofs_dummy);
+ ui_block_translate(block, rect.xmin - block->rect.xmin, rect.ymin - block->rect.ymin);
/* now recompute bounds and safety */
ui_block_bounds_calc(block);
@@ -742,8 +735,15 @@ static bool ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBu
/* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
* when scrolling without moving mouse (see [#28432]) */
- if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW))
+ if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
oldbut->hardmax = but->hardmax;
+ }
+
+ /* Selectively copy a1, a2 since their use differs across all button types
+ * (and we'll probably split these out later) */
+ if (ELEM(oldbut->type, UI_BTYPE_PROGRESS_BAR)) {
+ oldbut->a1 = but->a1;
+ }
ui_but_update_linklines(block, oldbut, but);
@@ -1053,6 +1053,10 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
/* dopesheet filtering options... */
data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(but->rnaprop));
}
+ else if (RNA_struct_is_a(but->rnapoin.type, &RNA_FileSelectParams)) {
+ /* Filebrowser options... */
+ data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(but->rnaprop));
+ }
}
}
else if (GS(id->name) == ID_SCE) {
@@ -1100,7 +1104,6 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
/* check each until one works... */
for (i = 0; (i < num_ops) && (ctx_toggle_opnames[i]); i++) {
- //printf("\t%s\n", ctx_toggle_opnames[i]);
if (WM_key_event_operator_string(C, ctx_toggle_opnames[i], WM_OP_INVOKE_REGION_WIN, prop_path, false,
buf_len, buf))
{
@@ -1204,6 +1207,11 @@ void UI_block_update_from_old(const bContext *C, uiBlock *block)
for (but = block->buttons.first; but; but = but->next) {
if (ui_but_update_from_old_block(C, block, &but, &but_old)) {
ui_but_update(but);
+
+ /* redraw dynamic tooltip if we have one open */
+ if (but->tip_func) {
+ UI_but_tooltip_refresh((bContext *)C, but);
+ }
}
}
@@ -1352,9 +1360,9 @@ void UI_block_draw(const bContext *C, uiBlock *block)
UI_block_end(C, block);
/* disable AA, makes widgets too blurry */
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB);
+ multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
if (multisample_enabled)
- glDisable(GL_MULTISAMPLE_ARB);
+ glDisable(GL_MULTISAMPLE);
/* we set this only once */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1375,7 +1383,7 @@ void UI_block_draw(const bContext *C, uiBlock *block)
glPushMatrix();
glLoadIdentity();
- wmOrtho2_region_ui(ar);
+ wmOrtho2_region_pixelspace(ar);
/* back */
if (block->flag & UI_BLOCK_RADIAL)
@@ -1404,7 +1412,7 @@ void UI_block_draw(const bContext *C, uiBlock *block)
glPopMatrix();
if (multisample_enabled)
- glEnable(GL_MULTISAMPLE_ARB);
+ glEnable(GL_MULTISAMPLE);
ui_draw_links(block);
}
@@ -1812,7 +1820,8 @@ bool ui_but_supports_cycling(const uiBut *but)
{
return ((ELEM(but->type, UI_BTYPE_ROW, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER, UI_BTYPE_LISTBOX)) ||
(but->type == UI_BTYPE_MENU && ui_but_menu_step_poll(but)) ||
- (but->type == UI_BTYPE_COLOR && but->a1 != -1));
+ (but->type == UI_BTYPE_COLOR && but->a1 != -1) ||
+ (but->menu_step_func != NULL));
}
double ui_but_value_get(uiBut *but)
@@ -2100,7 +2109,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
BLI_assert(step > 0.0);
- step_final = (step / scale_unit) / UI_PRECISION_FLOAT_SCALE;
+ step_final = (step / scale_unit) / (double)UI_PRECISION_FLOAT_SCALE;
if (step == step_unit) {
/* Logic here is to scale by the original 'step_orig'
@@ -2204,6 +2213,63 @@ void ui_but_string_get(uiBut *but, char *str, const size_t maxlen)
ui_but_string_get_ex(but, str, maxlen, -1);
}
+/**
+ * A version of #ui_but_string_get_ex for dynamic buffer sizes
+ * (where #ui_but_string_get_max_length returns 0).
+ *
+ * \param r_str_size: size of the returned string (including terminator).
+ */
+char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
+{
+ char *str = NULL;
+ *r_str_size = 1;
+
+ if (but->rnaprop && ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
+ PropertyType type;
+
+ type = RNA_property_type(but->rnaprop);
+
+ if (type == PROP_STRING) {
+ /* RNA string */
+ str = RNA_property_string_get_alloc(&but->rnapoin, but->rnaprop, NULL, 0, r_str_size);
+ (*r_str_size) += 1;
+ }
+ else if (type == PROP_ENUM) {
+ /* RNA enum */
+ int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
+ const char *value_id;
+ if (!RNA_property_enum_name(but->block->evil_C, &but->rnapoin, but->rnaprop, value, &value_id)) {
+ value_id = "";
+ }
+
+ *r_str_size = strlen(value_id) + 1;
+ str = BLI_strdupn(value_id, *r_str_size);
+ }
+ else if (type == PROP_POINTER) {
+ /* RNA pointer */
+ PointerRNA ptr = RNA_property_pointer_get(&but->rnapoin, but->rnaprop);
+ str = RNA_struct_name_get_alloc(&ptr, NULL, 0, r_str_size);
+ (*r_str_size) += 1;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (UNLIKELY(str == NULL)) {
+ /* should never happen, paranoid check */
+ *r_str_size = 1;
+ str = BLI_strdup("");
+ BLI_assert(0);
+
+ }
+
+ return str;
+}
+
#ifdef WITH_PYTHON
static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char *str, double *value)
@@ -2218,7 +2284,7 @@ static bool ui_set_but_string_eval_num_unit(bContext *C, uiBut *but, const char
bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), but->drawstr,
ui_get_but_scale_unit(but, 1.0), but->block->unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
- return (BPY_button_exec(C, str_unit_convert, value, true) != -1);
+ return BPY_execute_string_as_number(C, str_unit_convert, value, true);
}
#endif /* WITH_PYTHON */
@@ -2233,7 +2299,7 @@ bool ui_but_string_set_eval_num(bContext *C, uiBut *but, const char *str, double
if (str[0] != '\0') {
bool is_unit_but = (ui_but_is_float(but) && ui_but_is_unit(but));
/* only enable verbose if we won't run again with units */
- if (BPY_button_exec(C, str, value, is_unit_but == false) != -1) {
+ if (BPY_execute_string_as_number(C, str, value, is_unit_but == false)) {
/* if the value parsed ok without unit conversion this button may still need a unit multiplier */
if (is_unit_but) {
char str_new[128];
@@ -2363,7 +2429,7 @@ bool ui_but_string_set(bContext *C, uiBut *but, const char *str)
double value;
if (ui_but_string_set_eval_num(C, but, str, &value) == false) {
- WM_report_banner_show(C);
+ WM_report_banner_show();
return false;
}
@@ -2721,7 +2787,12 @@ void UI_block_emboss_set(uiBlock *block, char dt)
block->dt = dt;
}
-void ui_but_update(uiBut *but)
+/**
+ * \param but: Button to update.
+ * \param validate: When set, this function may change the button value.
+ * Otherwise treat the button value as read-only.
+ */
+void ui_but_update_ex(uiBut *but, const bool validate)
{
/* if something changed in the button */
double value = UI_BUT_VALUE_UNSET;
@@ -2743,13 +2814,19 @@ void ui_but_update(uiBut *but)
case UI_BTYPE_NUM:
case UI_BTYPE_SCROLL:
case UI_BTYPE_NUM_SLIDER:
- UI_GET_BUT_VALUE_INIT(but, value);
- if (value < (double)but->hardmin) ui_but_value_set(but, but->hardmin);
- else if (value > (double)but->hardmax) ui_but_value_set(but, but->hardmax);
+ if (validate) {
+ UI_GET_BUT_VALUE_INIT(but, value);
+ if (value < (double)but->hardmin) {
+ ui_but_value_set(but, but->hardmin);
+ }
+ else if (value > (double)but->hardmax) {
+ ui_but_value_set(but, but->hardmax);
+ }
- /* max must never be smaller than min! Both being equal is allowed though */
- BLI_assert(but->softmin <= but->softmax &&
- but->hardmin <= but->hardmax);
+ /* max must never be smaller than min! Both being equal is allowed though */
+ BLI_assert(but->softmin <= but->softmax &&
+ but->hardmin <= but->hardmax);
+ }
break;
case UI_BTYPE_ICON_TOGGLE:
@@ -2777,14 +2854,17 @@ void ui_but_update(uiBut *but)
/* only needed for menus in popup blocks that don't recreate buttons on redraw */
if (but->block->flag & UI_BLOCK_LOOP) {
if (but->rnaprop && (RNA_property_type(but->rnaprop) == PROP_ENUM)) {
- int value = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
- const char *buf;
- if (RNA_property_enum_name_gettexted(but->block->evil_C,
- &but->rnapoin, but->rnaprop, value, &buf))
+ int value_enum = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
+
+ EnumPropertyItem item;
+ if (RNA_property_enum_item_from_value_gettexted(
+ but->block->evil_C,
+ &but->rnapoin, but->rnaprop, value_enum, &item))
{
- size_t slen = strlen(buf);
+ size_t slen = strlen(item.name);
ui_but_string_free_internal(but);
- ui_but_string_set_internal(but, buf, slen);
+ ui_but_string_set_internal(but, item.name, slen);
+ but->icon = item.icon;
}
}
}
@@ -2922,6 +3002,15 @@ void ui_but_update(uiBut *but)
/* text clipping moved to widget drawing code itself */
}
+void ui_but_update(uiBut *but)
+{
+ ui_but_update_ex(but, false);
+}
+
+void ui_but_update_edited(uiBut *but)
+{
+ ui_but_update_ex(but, true);
+}
void UI_block_align_begin(uiBlock *block)
{
@@ -2934,200 +3023,11 @@ void UI_block_align_begin(uiBlock *block)
/* buttons declared after this call will get this align nr */ // XXX flag?
}
-static bool buts_are_horiz(uiBut *but1, uiBut *but2)
-{
- float dx, dy;
-
- /* simple case which can fail if buttons shift apart
- * with proportional layouts, see: [#38602] */
- if ((but1->rect.ymin == but2->rect.ymin) &&
- (but1->rect.xmin != but2->rect.xmin))
- {
- return true;
- }
-
- dx = fabsf(but1->rect.xmax - but2->rect.xmin);
- dy = fabsf(but1->rect.ymin - but2->rect.ymax);
-
- return (dx <= dy);
-}
-
void UI_block_align_end(uiBlock *block)
{
block->flag &= ~UI_BUT_ALIGN; /* all 4 flags */
}
-bool ui_but_can_align(uiBut *but)
-{
- return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE);
-}
-
-static void ui_block_align_calc_but(uiBut *first, short nr)
-{
- uiBut *prev, *but = NULL, *next;
- int flag = 0, cols = 0, rows = 0;
-
- /* auto align */
-
- for (but = first; but && but->alignnr == nr; but = but->next) {
- if (but->next && but->next->alignnr == nr) {
- if (buts_are_horiz(but, but->next)) cols++;
- else rows++;
- }
- }
-
- /* rows == 0: 1 row, cols == 0: 1 column */
-
- /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */
- for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) {
- next = but->next;
- if (next && next->alignnr != nr)
- next = NULL;
-
- /* clear old flag */
- but->drawflag &= ~UI_BUT_ALIGN;
-
- if (flag == 0) { /* first case */
- if (next) {
- if (buts_are_horiz(but, next)) {
- if (rows == 0)
- flag = UI_BUT_ALIGN_RIGHT;
- else
- flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT;
- }
- else {
- flag = UI_BUT_ALIGN_DOWN;
- }
- }
- }
- else if (next == NULL) { /* last case */
- if (prev) {
- if (buts_are_horiz(prev, but)) {
- if (rows == 0)
- flag = UI_BUT_ALIGN_LEFT;
- else
- flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT;
- }
- else {
- flag = UI_BUT_ALIGN_TOP;
- }
- }
- }
- else if (buts_are_horiz(but, next)) {
- /* check if this is already second row */
- if (prev && buts_are_horiz(prev, but) == 0) {
- flag &= ~UI_BUT_ALIGN_LEFT;
- flag |= UI_BUT_ALIGN_TOP;
- /* exception case: bottom row */
- if (rows > 0) {
- uiBut *bt = but;
- while (bt && bt->alignnr == nr) {
- if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) {
- break;
- }
- bt = bt->next;
- }
- if (bt == NULL || bt->alignnr != nr) flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT;
- }
- }
- else {
- flag |= UI_BUT_ALIGN_LEFT;
- }
- }
- else {
- if (cols == 0) {
- flag |= UI_BUT_ALIGN_TOP;
- }
- else { /* next button switches to new row */
-
- if (prev && buts_are_horiz(prev, but))
- flag |= UI_BUT_ALIGN_LEFT;
- else {
- flag &= ~UI_BUT_ALIGN_LEFT;
- flag |= UI_BUT_ALIGN_TOP;
- }
-
- if ((flag & UI_BUT_ALIGN_TOP) == 0) { /* stil top row */
- if (prev) {
- if (next && buts_are_horiz(but, next))
- flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT;
- else {
- /* last button in top row */
- flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT;
- }
- }
- else
- flag |= UI_BUT_ALIGN_DOWN;
- }
- else
- flag |= UI_BUT_ALIGN_TOP;
- }
- }
-
- but->drawflag |= flag;
-
- /* merge coordinates */
- if (prev) {
- /* simple cases */
- if (rows == 0) {
- but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
- prev->rect.xmax = but->rect.xmin;
- }
- else if (cols == 0) {
- but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
- prev->rect.ymin = but->rect.ymax;
- }
- else {
- if (buts_are_horiz(prev, but)) {
- but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
- prev->rect.xmax = but->rect.xmin;
- /* copy height too */
- but->rect.ymax = prev->rect.ymax;
- }
- else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) {
- /* the previous button is a single one in its row */
- but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
- prev->rect.ymin = but->rect.ymax;
-
- but->rect.xmin = prev->rect.xmin;
- if (next && buts_are_horiz(but, next) == 0)
- but->rect.xmax = prev->rect.xmax;
- }
- else {
- /* the previous button is not a single one in its row */
- but->rect.ymax = prev->rect.ymin;
- }
- }
- }
- }
-}
-
-void ui_block_align_calc(uiBlock *block)
-{
- uiBut *but;
- short nr;
-
- /* align buttons with same align nr */
- for (but = block->buttons.first; but; ) {
- if (but->alignnr) {
- nr = but->alignnr;
- ui_block_align_calc_but(but, nr);
-
- /* skip with same number */
- for (; but && but->alignnr == nr; but = but->next) {
- /* pass */
- }
-
- if (!but) {
- break;
- }
- }
- else {
- but = but->next;
- }
- }
-}
-
struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block)
{
return IMB_colormanagement_display_get_named(block->display_device);
@@ -3563,8 +3463,7 @@ static uiBut *ui_def_but_rna(
else if (proptype == PROP_STRING) {
min = 0;
max = RNA_property_string_maxlength(prop);
- if (max == 0) /* interface code should ideally support unlimited length */
- max = UI_MAX_DRAW_STR;
+ /* note, 'max' may be zero (code for dynamically resized array) */
}
}
@@ -3680,11 +3579,11 @@ static int findBitIndex(unsigned int x)
else {
int idx = 0;
- if (x & 0xFFFF0000) idx += 16, x >>= 16;
- if (x & 0xFF00) idx += 8, x >>= 8;
- if (x & 0xF0) idx += 4, x >>= 4;
- if (x & 0xC) idx += 2, x >>= 2;
- if (x & 0x2) idx += 1;
+ if (x & 0xFFFF0000) { idx += 16; x >>= 16; }
+ if (x & 0xFF00) { idx += 8; x >>= 8; }
+ if (x & 0xF0) { idx += 4; x >>= 4; }
+ if (x & 0xC) { idx += 2; x >>= 2; }
+ if (x & 0x2) { idx += 1; }
return idx;
}
@@ -4085,6 +3984,11 @@ void UI_but_flag_disable(uiBut *but, int flag)
but->flag &= ~flag;
}
+bool UI_but_flag_is_set(uiBut *but, int flag)
+{
+ return (but->flag & flag) != 0;
+}
+
void UI_but_drawflag_enable(uiBut *but, int flag)
{
but->drawflag |= flag;
@@ -4271,6 +4175,11 @@ void UI_but_func_complete_set(uiBut *but, uiButCompleteFunc func, void *arg)
but->autofunc_arg = arg;
}
+void UI_but_func_menu_step_set(uiBut *but, uiMenuStepFunc func)
+{
+ but->menu_step_func = func;
+}
+
void UI_but_func_tooltip_set(uiBut *but, uiButToolTipFunc func, void *argN)
{
but->tip_func = func;
@@ -4418,12 +4327,30 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle
* \param arg: user value,
* \param active: when set, button opens with this item visible and selected.
*/
-void UI_but_func_search_set(uiBut *but, uiButSearchFunc sfunc, void *arg, uiButHandleFunc bfunc, void *active)
+void UI_but_func_search_set(
+ uiBut *but,
+ uiButSearchCreateFunc search_create_func,
+ uiButSearchFunc search_func, void *arg,
+ uiButHandleFunc bfunc, void *active)
{
- but->search_func = sfunc;
+ /* needed since callers don't have access to internal functions (as an alternative we could expose it) */
+ if (search_create_func == NULL) {
+ search_create_func = ui_searchbox_create_generic;
+ }
+
+ but->search_create_func = search_create_func;
+ but->search_func = search_func;
but->search_arg = arg;
- UI_but_func_set(but, bfunc, arg, active);
+ if (bfunc) {
+#ifdef DEBUG
+ if (but->func) {
+ /* watch this, can be cause of much confusion, see: T47691 */
+ printf("%s: warning, overwriting button callback with search function callback!\n", __func__);
+ }
+#endif
+ UI_but_func_set(but, bfunc, arg, active);
+ }
/* search buttons show red-alert if item doesn't exist, not for menus */
if (0 == (but->block->flag & UI_BLOCK_LOOP)) {
@@ -4452,7 +4379,7 @@ static void operator_enum_search_cb(const struct bContext *C, void *but, const c
EnumPropertyItem *item, *item_array;
bool do_free;
- RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, NULL, &do_free);
+ RNA_property_enum_items_gettexted((bContext *)C, ptr, prop, &item_array, NULL, &do_free);
for (item = item_array; item->identifier; item++) {
/* note: need to give the index rather than the identifier because the enum can be freed */
@@ -4498,7 +4425,9 @@ uiBut *uiDefSearchButO_ptr(
uiBut *but;
but = uiDefSearchBut(block, arg, retval, icon, maxlen, x, y, width, height, a1, a2, tip);
- UI_but_func_search_set(but, operator_enum_search_cb, but, operator_enum_call_cb, NULL);
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, operator_enum_search_cb,
+ but, operator_enum_call_cb, NULL);
but->optype = ot;
but->opcontext = WM_OP_EXEC_DEFAULT;
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
new file mode 100644
index 00000000000..500744c366d
--- /dev/null
+++ b/source/blender/editors/interface/interface_align.c
@@ -0,0 +1,651 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation 2002-2008, full recode.
+ * Bastien Montagne 2015, full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_align.c
+ * \ingroup edinterface
+ */
+
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "UI_interface.h"
+
+#include "interface_intern.h"
+
+#ifdef USE_UIBUT_SPATIAL_ALIGN
+
+/**
+ * This struct stores a (simplified) 2D representation of all buttons of a same align group, with their
+ * immediate neighbors (if found), and needed value to compute 'stitching' of aligned buttons.
+ *
+ * \note This simplistic struct cannot fully represent complex layouts where buttons share some 'align space' with
+ * several others (see schema below), we'd need linked list and more complex code to handle that.
+ * However, looks like we can do without that for now, which is rather lucky!
+ *
+ * <pre>
+ * +-----------+-----------+
+ * | BUT 1 | BUT 2 | BUT 3 has two 'top' neighbors...
+ * |-----------------------| => In practice, we only store one of BUT 1 or 2 (which ones is not
+ * | BUT 3 | really deterministic), and assume the other stores a ref to BUT 3.
+ * +-----------------------+
+ * </pre>
+ *
+ * This will probably not work in all possible cases, but not sure we want to support such exotic cases anyway.
+ */
+typedef struct ButAlign {
+ uiBut *but;
+
+ /* Neighbor buttons */
+ struct ButAlign *neighbors[4];
+
+ /* Pointers to coordinates (rctf values) of the button. */
+ float *borders[4];
+
+ /* Distances to the neighbors. */
+ float dists[4];
+
+ /* Flags, used to mark whether we should 'stitch' the corners of this button with its neighbors' ones. */
+ char flags[4];
+} ButAlign;
+
+/* Side-related enums and flags. */
+enum {
+ /* Sides (used as indices, order is **crucial**, this allows us to factorize code in a loop over the four sides). */
+ LEFT = 0,
+ TOP = 1,
+ RIGHT = 2,
+ DOWN = 3,
+ TOTSIDES = 4,
+
+ /* Stitch flags, built from sides values. */
+ STITCH_LEFT = 1 << LEFT,
+ STITCH_TOP = 1 << TOP,
+ STITCH_RIGHT = 1 << RIGHT,
+ STITCH_DOWN = 1 << DOWN,
+};
+
+/* Mapping between 'our' sides and 'public' UI_BUT_ALIGN flags, order must match enum above. */
+#define SIDE_TO_UI_BUT_ALIGN {UI_BUT_ALIGN_LEFT, UI_BUT_ALIGN_TOP, UI_BUT_ALIGN_RIGHT, UI_BUT_ALIGN_DOWN}
+
+/* Given one side, compute the three other ones */
+#define SIDE1(_s) (((_s) + 1) % TOTSIDES)
+#define OPPOSITE(_s) (((_s) + 2) % TOTSIDES)
+#define SIDE2(_s) (((_s) + 3) % TOTSIDES)
+
+/* 0: LEFT/RIGHT sides; 1 = TOP/DOWN sides. */
+#define IS_COLUMN(_s) ((_s) % 2)
+
+/* Stitch flag from side value. */
+#define STITCH(_s) (1 << (_s))
+
+/* Max distance between to buttons for them to be 'mergeable'. */
+#define MAX_DELTA 0.45f * max_ii(UI_UNIT_Y, UI_UNIT_X)
+
+bool ui_but_can_align(const uiBut *but)
+{
+ return (
+ !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE) &&
+ (BLI_rctf_size_x(&but->rect) > 0.0f) && (BLI_rctf_size_y(&but->rect) > 0.0f));
+}
+
+/**
+ * This function checks a pair of buttons (assumed in a same align group), and if they are neighbors,
+ * set needed data accordingly.
+ *
+ * \note It is designed to be called in total random order of buttons. Order-based optimizations are done by caller.
+ */
+static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other)
+{
+ /* That's the biggest gap between two borders to consider them 'alignable'. */
+ const float max_delta = MAX_DELTA;
+ float delta, delta_side_opp;
+ int side, side_opp;
+
+ const bool butal_can_align = ui_but_can_align(butal->but);
+ const bool butal_other_can_align = ui_but_can_align(butal_other->but);
+
+ const bool buts_share[2] = {
+ /* Sharing same line? */
+ !((*butal->borders[DOWN] >= *butal_other->borders[TOP]) ||
+ (*butal->borders[TOP] <= *butal_other->borders[DOWN])),
+ /* Sharing same column? */
+ !((*butal->borders[LEFT] >= *butal_other->borders[RIGHT]) ||
+ (*butal->borders[RIGHT] <= *butal_other->borders[LEFT])),
+ };
+
+ /* Early out in case buttons share no column or line, or if none can align... */
+ if (!(buts_share[0] || buts_share[1]) || !(butal_can_align || butal_other_can_align)) {
+ return;
+ }
+
+ for (side = 0; side < RIGHT; side++) {
+ /* We are only interested in buttons which share a same line (LEFT/RIGHT sides) or column (TOP/DOWN sides). */
+ if (buts_share[IS_COLUMN(side)]) {
+ side_opp = OPPOSITE(side);
+
+ /* We check both opposite sides at once, because with very small buttons, delta could be below max_delta for
+ * the wrong side (that is, in horizontal case, the total width of two buttons can be below max_delta).
+ * We rely on exact zero value here as an 'already processed' flag, so ensure we never actually
+ * set a zero value at this stage. FLT_MIN is zero-enough for UI position computing. ;) */
+ delta = max_ff(fabsf(*butal->borders[side] - *butal_other->borders[side_opp]), FLT_MIN);
+ delta_side_opp = max_ff(fabsf(*butal->borders[side_opp] - *butal_other->borders[side]), FLT_MIN);
+ if (delta_side_opp < delta) {
+ SWAP(int, side, side_opp);
+ delta = delta_side_opp;
+ }
+
+ if (delta < max_delta) {
+ /* We are only interested in neighbors that are at least as close as already found ones. */
+ if (delta <= butal->dists[side]) {
+ {
+ /* We found an as close or closer neighbor.
+ * If both buttons are alignable, we set them as each other neighbors.
+ * Else, we have an unalignable one, we need to reset the others matching neighbor to NULL
+ * if its 'proximity distance' is really lower with current one.
+ *
+ * NOTE: We cannot only execute that piece of code in case we found a **closer** neighbor,
+ * due to the limited way we represent neighbors (buttons only know **one** neighbor
+ * on each side, when they can actually have several ones), it would prevent
+ * some buttons to be properly 'neighborly-initialized'. */
+ if (butal_can_align && butal_other_can_align) {
+ butal->neighbors[side] = butal_other;
+ butal_other->neighbors[side_opp] = butal;
+ }
+ else if (butal_can_align && (delta < butal->dists[side])) {
+ butal->neighbors[side] = NULL;
+ }
+ else if (butal_other_can_align && (delta < butal_other->dists[side_opp])) {
+ butal_other->neighbors[side_opp] = NULL;
+ }
+ butal->dists[side] = butal_other->dists[side_opp] = delta;
+ }
+
+ if (butal_can_align && butal_other_can_align) {
+ const int side_s1 = SIDE1(side);
+ const int side_s2 = SIDE2(side);
+
+ const int stitch = STITCH(side);
+ const int stitch_opp = STITCH(side_opp);
+
+ if (butal->neighbors[side] == NULL) {
+ butal->neighbors[side] = butal_other;
+ }
+ if (butal_other->neighbors[side_opp] == NULL) {
+ butal_other->neighbors[side_opp] = butal;
+ }
+
+ /* We have a pair of neighbors, we have to check whether we can stitch their matching corners.
+ * E.g. if butal_other is on the left of butal (that is, side == LEFT),
+ * if both TOP (side_s1) coordinates of buttons are close enough, we can stitch
+ * their upper matching corners, and same for DOWN (side_s2) side. */
+ delta = fabsf(*butal->borders[side_s1] - *butal_other->borders[side_s1]);
+ if (delta < max_delta) {
+ butal->flags[side_s1] |= stitch;
+ butal_other->flags[side_s1] |= stitch_opp;
+ }
+ delta = fabsf(*butal->borders[side_s2] - *butal_other->borders[side_s2]);
+ if (delta < max_delta) {
+ butal->flags[side_s2] |= stitch;
+ butal_other->flags[side_s2] |= stitch_opp;
+ }
+ }
+ }
+ /* We assume two buttons can only share one side at most - for until we have sperical UI... */
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * This function takes care of case described in this schema:
+ *
+ * <pre>
+ * +-----------+-----------+
+ * | BUT 1 | BUT 2 |
+ * |-----------------------+
+ * | BUT 3 |
+ * +-----------+
+ * </pre>
+ *
+ * Here, BUT 3 RIGHT side would not get 'dragged' to align with BUT 1 RIGHT side, since BUT 3 has not RIGHT neighbor.
+ * So, this function, when called with BUT 1, will 'walk' the whole column in \a side_s1 direction (TOP or DOWN when
+ * called for RIGHT side), and force buttons like BUT 3 to align as needed, if BUT 1 and BUT 3 were detected as needing
+ * top-right corner stitching in \a block_align_proximity_compute() step.
+ *
+ * \note To avoid doing this twice, some stitching flags are cleared to break the 'stitching connection'
+ * between neighbors.
+ */
+static void block_align_stitch_neighbors(
+ ButAlign *butal,
+ const int side, const int side_opp, const int side_s1, const int side_s2,
+ const int align, const int align_opp, const float co)
+{
+ ButAlign *butal_neighbor;
+
+ const int stitch_s1 = STITCH(side_s1);
+ const int stitch_s2 = STITCH(side_s2);
+
+ /* We have to check stitching flags on both sides of the stitching, since we only clear one of them flags to break
+ * any future loop on same 'columns/side' case.
+ * Also, if butal is spanning over several rows or columns of neighbors, it may have both of its stitching flags
+ * set, but would not be the case of its immediate neighbor! */
+ while ((butal->flags[side] & stitch_s1) &&
+ (butal = butal->neighbors[side_s1]) &&
+ (butal->flags[side] & stitch_s2))
+ {
+ butal_neighbor = butal->neighbors[side];
+
+ /* If we actually do have a neighbor, we directly set its values accordingly, and clear its matching 'dist'
+ * to prevent it being set again later... */
+ if (butal_neighbor) {
+ butal->but->drawflag |= align;
+ butal_neighbor->but->drawflag |= align_opp;
+ *butal_neighbor->borders[side_opp] = co;
+ butal_neighbor->dists[side_opp] = 0.0f;
+ }
+ /* See definition of UI_BUT_ALIGN_STITCH_LEFT/TOP for reason of this... */
+ else if (side == LEFT) {
+ butal->but->drawflag |= UI_BUT_ALIGN_STITCH_LEFT;
+ }
+ else if (side == TOP) {
+ butal->but->drawflag |= UI_BUT_ALIGN_STITCH_TOP;
+ }
+ *butal->borders[side] = co;
+ butal->dists[side] = 0.0f;
+ /* Clearing one of the 'flags pair' here is enough to prevent this loop running on
+ * the same column, side and direction again. */
+ butal->flags[side] &= ~stitch_s2;
+ }
+}
+
+/**
+ * Helper to sort ButAlign items by:
+ * - Their align group.
+ * - Their vertical position.
+ * - Their horizontal position.
+ */
+static int ui_block_align_butal_cmp(const void *a, const void *b)
+{
+ const ButAlign *butal = a;
+ const ButAlign *butal_other = b;
+
+ /* Sort by align group. */
+ if (butal->but->alignnr != butal_other->but->alignnr) {
+ return butal->but->alignnr - butal_other->but->alignnr;
+ }
+
+ /* Sort vertically.
+ * Note that Y of buttons is decreasing (first buttons have higher Y value than later ones). */
+ if (*butal->borders[TOP] != *butal_other->borders[TOP]) {
+ return (*butal_other->borders[TOP] > *butal->borders[TOP]) ? 1 : -1;
+ }
+
+ /* Sort horizontally. */
+ if (*butal->borders[LEFT] != *butal_other->borders[LEFT]) {
+ return (*butal->borders[LEFT] > *butal_other->borders[LEFT]) ? 1 : -1;
+ }
+
+ /* XXX We cannot actually assert here, since in some very compressed space cases, stupid UI code produces
+ * widgets which have the same TOP and LEFT positions...
+ * We do not care really, because this happens when UI is way too small to be usable anyway. */
+ /* BLI_assert(0); */
+ return 0;
+}
+
+/**
+ * Compute the alignment of all 'align groups' of buttons in given block.
+ *
+ * This is using an order-independent algorithm, i.e. alignment of buttons should be OK regardless of order in which
+ * they are added to the block.
+ */
+void ui_block_align_calc(uiBlock *block)
+{
+ uiBut *but;
+ int num_buttons = 0;
+
+ const int sides_to_ui_but_align_flags[4] = SIDE_TO_UI_BUT_ALIGN;
+
+ ButAlign *butal_array;
+ ButAlign *butal, *butal_other;
+ int side;
+ int i, j;
+
+ /* First loop: we count number of buttons belonging to an align group, and clear their align flag. */
+ for (but = block->buttons.first; but; but = but->next) {
+ /* Clear old align flags. */
+ but->drawflag &= ~UI_BUT_ALIGN_ALL;
+
+ if (but->alignnr != 0) {
+ num_buttons++;
+ }
+ }
+
+ if (num_buttons < 2) {
+ /* No need to go further if we have nothing to align... */
+ return;
+ }
+
+ butal_array = alloca(sizeof(*butal_array) * (size_t)num_buttons);
+ memset(butal_array, 0, sizeof(*butal_array) * (size_t)num_buttons);
+
+ /* Second loop: we initialize our ButAlign data for each button. */
+ for (but = block->buttons.first, butal = butal_array; but; but = but->next) {
+ if (but->alignnr != 0) {
+ butal->but = but;
+ butal->borders[LEFT] = &but->rect.xmin;
+ butal->borders[RIGHT] = &but->rect.xmax;
+ butal->borders[DOWN] = &but->rect.ymin;
+ butal->borders[TOP] = &but->rect.ymax;
+ copy_v4_fl(butal->dists, FLT_MAX);
+ butal++;
+ }
+ }
+
+ /* This will give us ButAlign items regrouped by align group, vertical and horizontal location.
+ * Note that, given how buttons are defined in UI code, butal_array shall already be "nearly sorted"... */
+ qsort(butal_array, (size_t)num_buttons, sizeof(*butal_array), ui_block_align_butal_cmp);
+
+ /* Third loop: for each pair of buttons in the same align group, we compute their potential proximity.
+ * Note that each pair is checked only once, and that we break early in case we know all remaining pairs will
+ * always be too far away. */
+ for (i = 0, butal = butal_array; i < num_buttons; i++, butal++) {
+ const short alignnr = butal->but->alignnr;
+
+ for (j = i + 1, butal_other = &butal_array[i + 1]; j < num_buttons; j++, butal_other++) {
+ const float max_delta = MAX_DELTA;
+
+ /* Since they are sorted, buttons after current butal can only be of same or higher group, and once
+ * they are not of same group, we know we can break this sub-loop and start checking with next butal. */
+ if (butal_other->but->alignnr != alignnr) {
+ break;
+ }
+
+ /* Since they are sorted vertically first, buttons after current butal can only be at same or lower height,
+ * and once they are lower than a given threshold, we know we can break this sub-loop and
+ * start checking with next butal. */
+ if ((*butal->borders[DOWN] - *butal_other->borders[TOP]) > max_delta) {
+ break;
+ }
+
+ block_align_proximity_compute(butal, butal_other);
+ }
+ }
+
+ /* Fourth loop: we have all our 'aligned' buttons as a 'map' in butal_array. We need to:
+ * - update their relevant coordinates to stitch them.
+ * - assign them valid flags.
+ */
+ for (i = 0; i < num_buttons; i++) {
+ butal = &butal_array[i];
+
+ for (side = 0; side < TOTSIDES; side++) {
+ butal_other = butal->neighbors[side];
+
+ if (butal_other) {
+ const int side_opp = OPPOSITE(side);
+ const int side_s1 = SIDE1(side);
+ const int side_s2 = SIDE2(side);
+
+ const int align = sides_to_ui_but_align_flags[side];
+ const int align_opp = sides_to_ui_but_align_flags[side_opp];
+
+ float co;
+
+ butal->but->drawflag |= align;
+ butal_other->but->drawflag |= align_opp;
+ if (butal->dists[side]) {
+ float *delta = &butal->dists[side];
+
+ if (*butal->borders[side] < *butal_other->borders[side_opp]) {
+ *delta *= 0.5f;
+ }
+ else {
+ *delta *= -0.5f;
+ }
+ co = (*butal->borders[side] += *delta);
+
+ if (butal_other->dists[side_opp]) {
+ BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta));
+ *butal_other->borders[side_opp] = co;
+ butal_other->dists[side_opp] = 0.0f;
+ }
+ *delta = 0.0f;
+ }
+ else {
+ co = *butal->borders[side];
+ }
+
+ block_align_stitch_neighbors(butal, side, side_opp, side_s1, side_s2, align, align_opp, co);
+ block_align_stitch_neighbors(butal, side, side_opp, side_s2, side_s1, align, align_opp, co);
+ }
+ }
+ }
+}
+
+#undef SIDE_TO_UI_BUT_ALIGN
+#undef SIDE1
+#undef OPPOSITE
+#undef SIDE2
+#undef IS_COLUMN
+#undef STITCH
+#undef MAX_DELTA
+
+#else
+
+bool ui_but_can_align(uiBut *but)
+{
+ return !ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE);
+}
+
+static bool buts_are_horiz(uiBut *but1, uiBut *but2)
+{
+ float dx, dy;
+
+ /* simple case which can fail if buttons shift apart
+ * with proportional layouts, see: [#38602] */
+ if ((but1->rect.ymin == but2->rect.ymin) &&
+ (but1->rect.xmin != but2->rect.xmin))
+ {
+ return true;
+ }
+
+ dx = fabsf(but1->rect.xmax - but2->rect.xmin);
+ dy = fabsf(but1->rect.ymin - but2->rect.ymax);
+
+ return (dx <= dy);
+}
+
+static void ui_block_align_calc_but(uiBut *first, short nr)
+{
+ uiBut *prev, *but = NULL, *next;
+ int flag = 0, cols = 0, rows = 0;
+
+ /* auto align */
+
+ for (but = first; but && but->alignnr == nr; but = but->next) {
+ if (but->next && but->next->alignnr == nr) {
+ if (buts_are_horiz(but, but->next)) cols++;
+ else rows++;
+ }
+ }
+
+ /* rows == 0: 1 row, cols == 0: 1 column */
+
+ /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */
+ for (but = first, prev = NULL; but && but->alignnr == nr; prev = but, but = but->next) {
+ next = but->next;
+ if (next && next->alignnr != nr)
+ next = NULL;
+
+ /* clear old flag */
+ but->drawflag &= ~UI_BUT_ALIGN;
+
+ if (flag == 0) { /* first case */
+ if (next) {
+ if (buts_are_horiz(but, next)) {
+ if (rows == 0)
+ flag = UI_BUT_ALIGN_RIGHT;
+ else
+ flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT;
+ }
+ else {
+ flag = UI_BUT_ALIGN_DOWN;
+ }
+ }
+ }
+ else if (next == NULL) { /* last case */
+ if (prev) {
+ if (buts_are_horiz(prev, but)) {
+ if (rows == 0)
+ flag = UI_BUT_ALIGN_LEFT;
+ else
+ flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT;
+ }
+ else {
+ flag = UI_BUT_ALIGN_TOP;
+ }
+ }
+ }
+ else if (buts_are_horiz(but, next)) {
+ /* check if this is already second row */
+ if (prev && buts_are_horiz(prev, but) == 0) {
+ flag &= ~UI_BUT_ALIGN_LEFT;
+ flag |= UI_BUT_ALIGN_TOP;
+ /* exception case: bottom row */
+ if (rows > 0) {
+ uiBut *bt = but;
+ while (bt && bt->alignnr == nr) {
+ if (bt->next && bt->next->alignnr == nr && buts_are_horiz(bt, bt->next) == 0) {
+ break;
+ }
+ bt = bt->next;
+ }
+ if (bt == NULL || bt->alignnr != nr) flag = UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT;
+ }
+ }
+ else {
+ flag |= UI_BUT_ALIGN_LEFT;
+ }
+ }
+ else {
+ if (cols == 0) {
+ flag |= UI_BUT_ALIGN_TOP;
+ }
+ else { /* next button switches to new row */
+
+ if (prev && buts_are_horiz(prev, but))
+ flag |= UI_BUT_ALIGN_LEFT;
+ else {
+ flag &= ~UI_BUT_ALIGN_LEFT;
+ flag |= UI_BUT_ALIGN_TOP;
+ }
+
+ if ((flag & UI_BUT_ALIGN_TOP) == 0) { /* still top row */
+ if (prev) {
+ if (next && buts_are_horiz(but, next))
+ flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_RIGHT;
+ else {
+ /* last button in top row */
+ flag = UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT;
+ }
+ }
+ else
+ flag |= UI_BUT_ALIGN_DOWN;
+ }
+ else
+ flag |= UI_BUT_ALIGN_TOP;
+ }
+ }
+
+ but->drawflag |= flag;
+
+ /* merge coordinates */
+ if (prev) {
+ /* simple cases */
+ if (rows == 0) {
+ but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
+ prev->rect.xmax = but->rect.xmin;
+ }
+ else if (cols == 0) {
+ but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
+ prev->rect.ymin = but->rect.ymax;
+ }
+ else {
+ if (buts_are_horiz(prev, but)) {
+ but->rect.xmin = (prev->rect.xmax + but->rect.xmin) / 2.0f;
+ prev->rect.xmax = but->rect.xmin;
+ /* copy height too */
+ but->rect.ymax = prev->rect.ymax;
+ }
+ else if (prev->prev && buts_are_horiz(prev->prev, prev) == 0) {
+ /* the previous button is a single one in its row */
+ but->rect.ymax = (prev->rect.ymin + but->rect.ymax) / 2.0f;
+ prev->rect.ymin = but->rect.ymax;
+
+ but->rect.xmin = prev->rect.xmin;
+ if (next && buts_are_horiz(but, next) == 0)
+ but->rect.xmax = prev->rect.xmax;
+ }
+ else {
+ /* the previous button is not a single one in its row */
+ but->rect.ymax = prev->rect.ymin;
+ }
+ }
+ }
+ }
+}
+
+void ui_block_align_calc(uiBlock *block)
+{
+ uiBut *but;
+ short nr;
+
+ /* align buttons with same align nr */
+ for (but = block->buttons.first; but; ) {
+ if (but->alignnr) {
+ nr = but->alignnr;
+ ui_block_align_calc_but(but, nr);
+
+ /* skip with same number */
+ for (; but && but->alignnr == nr; but = but->next) {
+ /* pass */
+ }
+
+ if (!but) {
+ break;
+ }
+ }
+ else {
+ but = but->next;
+ }
+ }
+}
+#endif
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 37895a711fd..06831576507 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -231,33 +231,52 @@ void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
/* NLA Strip property */
if (IS_AUTOKEY_ON(scene)) {
ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
PointerRNA ptr = {{NULL}};
PropertyRNA *prop = NULL;
int index;
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
- insert_keyframe_direct(reports, ptr, prop, fcu, cfra, 0);
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, 0);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
- else if (!driven) {
+ else if (driven) {
+ /* Driver - Try to insert keyframe using the driver's input as the frame,
+ * making it easier to set up corrective drivers
+ */
+ if (IS_AUTOKEY_ON(scene)) {
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index;
+
+ UI_context_active_but_prop_get(C, &ptr, &prop, &index);
+
+ insert_keyframe_direct(reports, ptr, prop, fcu, cfra, ts->keyframe_type, INSERTKEY_DRIVER);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+ }
+ else {
id = but->rnapoin.id.data;
-
+
/* TODO: this should probably respect the keyingset only option for anim */
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
short flag = ANIM_get_keyframing_flags(scene, 1);
-
+
fcu->flag &= ~FCURVE_SELECTED;
-
+
/* Note: We use but->rnaindex instead of fcu->array_index,
* because a button may control all items of an array at once.
* E.g., color wheels (see T42567). */
BLI_assert((fcu->array_index == but->rnaindex) || (but->rnaindex == -1));
insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path, but->rnaindex, cfra, flag);
-
+ fcu->rna_path, but->rnaindex, cfra, ts->keyframe_type, flag);
+
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 84767eae350..8fbc545cb77 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -55,6 +55,9 @@
#include "BLF_api.h"
+#include "GPU_draw.h"
+#include "GPU_basic_shader.h"
+
#include "UI_interface.h"
/* own include */
@@ -142,11 +145,11 @@ void UI_draw_roundbox_gl_mode(int mode, float minx, float miny, float maxx, floa
static void round_box_shade_col(const float col1[3], float const col2[3], const float fac)
{
- float col[3];
-
- col[0] = (fac * col1[0] + (1.0f - fac) * col2[0]);
- col[1] = (fac * col1[1] + (1.0f - fac) * col2[1]);
- col[2] = (fac * col1[2] + (1.0f - fac) * col2[2]);
+ float col[3] = {
+ fac * col1[0] + (1.0f - fac) * col2[0],
+ fac * col1[1] + (1.0f - fac) * col2[1],
+ fac * col1[2] + (1.0f - fac) * col2[2]
+ };
glColor3fv(col);
}
@@ -410,13 +413,11 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
(void)but;
#else
ImBuf *ibuf = (ImBuf *)but->poin;
- //GLint scissor[4];
- int w, h;
if (!ibuf) return;
- w = BLI_rcti_size_x(rect);
- h = BLI_rcti_size_y(rect);
+ int w = BLI_rcti_size_x(rect);
+ int h = BLI_rcti_size_y(rect);
/* scissor doesn't seem to be doing the right thing...? */
#if 0
@@ -424,6 +425,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
//fdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax)
/* prevent drawing outside widget area */
+ GLint scissor[4];
glGetIntegerv(GL_SCISSOR_BOX, scissor);
glScissor(ar->winrct.xmin + rect->xmin, ar->winrct.ymin + rect->ymin, w, h);
#endif
@@ -463,10 +465,10 @@ void UI_draw_safe_areas(
const float size_y_half = (y2 - y1) * 0.5f;
const float *safe_areas[] = {title_aspect, action_aspect};
- int i, safe_len = ARRAY_SIZE(safe_areas);
+ int safe_len = ARRAY_SIZE(safe_areas);
bool is_first = true;
- for (i = 0; i < safe_len; i++) {
+ for (int i = 0; i < safe_len; i++) {
if (safe_areas[i][0] || safe_areas[i][1]) {
float margin_x, margin_y;
float minx, miny, maxx, maxy;
@@ -512,38 +514,28 @@ static void histogram_draw_one(
float r, float g, float b, float alpha,
float x, float y, float w, float h, const float *data, int res, const bool is_line)
{
- int i;
-
- if (is_line) {
-
- glLineWidth(1.5);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glColor4f(r, g, b, alpha);
+ glEnable(GL_LINE_SMOOTH);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ glColor4f(r, g, b, alpha);
+ if (is_line) {
/* curve outline */
+ glLineWidth(1.5);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_STRIP);
- for (i = 0; i < res; i++) {
+ for (int i = 0; i < res; i++) {
float x2 = x + i * (w / (float)res);
glVertex2f(x2, y + (data[i] * h));
}
glEnd();
- glDisable(GL_LINE_SMOOTH);
-
- glLineWidth(1.0);
}
else {
/* under the curve */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- glColor4f(r, g, b, alpha);
-
glShadeModel(GL_FLAT);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x, y);
glVertex2f(x, y + (data[0] * h));
- for (i = 1; i < res; i++) {
+ for (int i = 1; i < res; i++) {
float x2 = x + i * (w / (float)res);
glVertex2f(x2, y + (data[i] * h));
glVertex2f(x2, y);
@@ -554,15 +546,15 @@ static void histogram_draw_one(
glColor4f(0.f, 0.f, 0.f, 0.25f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_STRIP);
- for (i = 0; i < res; i++) {
+ for (int i = 0; i < res; i++) {
float x2 = x + i * (w / (float)res);
glVertex2f(x2, y + (data[i] * h));
}
glEnd();
- glDisable(GL_LINE_SMOOTH);
}
+
+ glDisable(GL_LINE_SMOOTH);
}
#define HISTOGRAM_TOT_GRID_LINES 4
@@ -571,20 +563,17 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
{
Histogram *hist = (Histogram *)but->poin;
int res = hist->x_resolution;
- rctf rect;
- int i;
- float w, h;
const bool is_line = (hist->flag & HISTO_FLAG_LINE) != 0;
- //float alpha;
- GLint scissor[4];
- rect.xmin = (float)recti->xmin + 1;
- rect.xmax = (float)recti->xmax - 1;
- rect.ymin = (float)recti->ymin + 1;
- rect.ymax = (float)recti->ymax - 1;
+ rctf rect = {
+ .xmin = (float)recti->xmin + 1,
+ .xmax = (float)recti->xmax - 1,
+ .ymin = (float)recti->ymin + 1,
+ .ymax = (float)recti->ymax - 1
+ };
- w = BLI_rctf_size_x(&rect);
- h = BLI_rctf_size_y(&rect) * hist->ymax;
+ float w = BLI_rctf_size_x(&rect);
+ float h = BLI_rctf_size_y(&rect) * hist->ymax;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -594,6 +583,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
/* need scissor test, histogram can draw outside of boundary */
+ GLint scissor[4];
glGetIntegerv(GL_VIEWPORT, scissor);
glScissor(ar->winrct.xmin + (rect.xmin - 1),
ar->winrct.ymin + (rect.ymin - 1),
@@ -602,7 +592,7 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
glColor4f(1.f, 1.f, 1.f, 0.08f);
/* draw grid lines here */
- for (i = 1; i <= HISTOGRAM_TOT_GRID_LINES; i++) {
+ for (int i = 1; i <= HISTOGRAM_TOT_GRID_LINES; i++) {
const float fac = (float)i / (float)HISTOGRAM_TOT_GRID_LINES;
/* so we can tell the 1.0 color point */
@@ -638,9 +628,6 @@ void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol)
void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
Scopes *scopes = (Scopes *)but->poin;
- rctf rect;
- int i, c;
- float w, w3, h, alpha, yofs;
GLint scissor[4];
float colors[3][3];
float colorsycc[3][3] = {{1, 0, 1}, {1, 1, 0}, {0, 1, 1}};
@@ -649,25 +636,27 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
if (scopes == NULL) return;
- rect.xmin = (float)recti->xmin + 1;
- rect.xmax = (float)recti->xmax - 1;
- rect.ymin = (float)recti->ymin + 1;
- rect.ymax = (float)recti->ymax - 1;
+ rctf rect = {
+ .xmin = (float)recti->xmin + 1,
+ .xmax = (float)recti->xmax - 1,
+ .ymin = (float)recti->ymin + 1,
+ .ymax = (float)recti->ymax - 1
+ };
if (scopes->wavefrm_yfac < 0.5f)
scopes->wavefrm_yfac = 0.98f;
- w = BLI_rctf_size_x(&rect) - 7;
- h = BLI_rctf_size_y(&rect) * scopes->wavefrm_yfac;
- yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) / 2.0f;
- w3 = w / 3.0f;
+ float w = BLI_rctf_size_x(&rect) - 7;
+ float h = BLI_rctf_size_y(&rect) * scopes->wavefrm_yfac;
+ float yofs = rect.ymin + (BLI_rctf_size_y(&rect) - h) / 2.0f;
+ float w3 = w / 3.0f;
/* log scale for alpha */
- alpha = scopes->wavefrm_alpha * scopes->wavefrm_alpha;
+ float alpha = scopes->wavefrm_alpha * scopes->wavefrm_alpha;
unit_m3(colors);
- for (c = 0; c < 3; c++) {
- for (i = 0; i < 3; i++) {
+ for (int c = 0; c < 3; c++) {
+ for (int i = 0; i < 3; i++) {
colors_alpha[c][i] = colors[c][i] * alpha;
colorsycc_alpha[c][i] = colorsycc[c][i] * alpha;
}
@@ -689,7 +678,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
glColor4f(1.f, 1.f, 1.f, 0.08f);
/* draw grid lines here */
- for (i = 0; i < 6; i++) {
+ for (int i = 0; i < 6; i++) {
char str[4];
BLI_snprintf(str, sizeof(str), "%-3d", i * 20);
str[3] = '\0';
@@ -701,7 +690,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
}
/* 3 vertical separation */
if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA) {
- for (i = 1; i < 3; i++) {
+ for (int i = 1; i < 3; i++) {
fdrawline(rect.xmin + i * w3, rect.ymin, rect.xmin + i * w3, rect.ymax);
}
}
@@ -725,6 +714,8 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
/* LUMA (1 channel) */
glBlendFunc(GL_ONE, GL_ONE);
glColor3f(alpha, alpha, alpha);
+ glPointSize(1.0);
+
if (scopes->wavefrm_mode == SCOPES_WAVEFRM_LUMA) {
glBlendFunc(GL_ONE, GL_ONE);
@@ -785,7 +776,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
/* min max */
- for (c = 0; c < 3; c++) {
+ for (int c = 0; c < 3; c++) {
if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB)
glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f);
else
@@ -831,12 +822,11 @@ static void vectorscope_draw_target(float centerx, float centery, float diam, co
glColor4f(1.0f, 1.0f, 1.0, 0.12f);
dangle = DEG2RADF(2.5f);
dampli = 2.5f / 200.0f;
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINE_LOOP);
glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle + dangle), polar_to_y(centery, diam, tampli - dampli, tangle + dangle));
glVertex2f(polar_to_x(centerx, diam, tampli - dampli, tangle - dangle), polar_to_y(centery, diam, tampli - dampli, tangle - dangle));
glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle - dangle), polar_to_y(centery, diam, tampli + dampli, tangle - dangle));
- glVertex2f(polar_to_x(centerx, diam, tampli + dampli, tangle + dangle), polar_to_y(centery, diam, tampli + dampli, tangle + dangle));
glEnd();
/* big target vary by 10 degree and 20% amplitude */
glColor4f(1.0f, 1.0f, 1.0, 0.12f);
@@ -870,27 +860,25 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
{
const float skin_rad = DEG2RADF(123.0f); /* angle in radians of the skin tone line */
Scopes *scopes = (Scopes *)but->poin;
- rctf rect;
- int i, j;
- float w, h, centerx, centery, diam;
- float alpha;
+
const float colors[6][3] = {
{0.75, 0.0, 0.0}, {0.75, 0.75, 0.0}, {0.0, 0.75, 0.0},
{0.0, 0.75, 0.75}, {0.0, 0.0, 0.75}, {0.75, 0.0, 0.75}};
- GLint scissor[4];
- rect.xmin = (float)recti->xmin + 1;
- rect.xmax = (float)recti->xmax - 1;
- rect.ymin = (float)recti->ymin + 1;
- rect.ymax = (float)recti->ymax - 1;
+ rctf rect = {
+ .xmin = (float)recti->xmin + 1,
+ .xmax = (float)recti->xmax - 1,
+ .ymin = (float)recti->ymin + 1,
+ .ymax = (float)recti->ymax - 1
+ };
- w = BLI_rctf_size_x(&rect);
- h = BLI_rctf_size_y(&rect);
- centerx = rect.xmin + w / 2;
- centery = rect.ymin + h / 2;
- diam = (w < h) ? w : h;
+ float w = BLI_rctf_size_x(&rect);
+ float h = BLI_rctf_size_y(&rect);
+ float centerx = rect.xmin + w / 2;
+ float centery = rect.ymin + h / 2;
+ float diam = (w < h) ? w : h;
- alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha;
+ float alpha = scopes->vecscope_alpha * scopes->vecscope_alpha * scopes->vecscope_alpha;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -900,6 +888,7 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin - 1, rect.xmax + 1, rect.ymax + 1, 3.0f);
/* need scissor test, hvectorscope can draw outside of boundary */
+ GLint scissor[4];
glGetIntegerv(GL_VIEWPORT, scissor);
glScissor(ar->winrct.xmin + (rect.xmin - 1),
ar->winrct.ymin + (rect.ymin - 1),
@@ -912,9 +901,10 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
fdrawline(centerx - (diam / 2) - 5, centery, centerx + (diam / 2) + 5, centery);
fdrawline(centerx, centery - (diam / 2) - 5, centerx, centery + (diam / 2) + 5);
/* circles */
- for (j = 0; j < 5; j++) {
- glBegin(GL_LINE_STRIP);
- for (i = 0; i <= 360; i = i + 15) {
+ for (int j = 0; j < 5; j++) {
+ glBegin(GL_LINE_LOOP);
+ const int increment = 15;
+ for (int i = 0; i <= 360 - increment; i += increment) {
const float a = DEG2RADF((float)i);
const float r = (j + 1) / 10.0f;
glVertex2f(polar_to_x(centerx, diam, r, a), polar_to_y(centery, diam, r, a));
@@ -926,7 +916,7 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
fdrawline(polar_to_x(centerx, diam, 0.5f, skin_rad), polar_to_y(centery, diam, 0.5, skin_rad),
polar_to_x(centerx, diam, 0.1f, skin_rad), polar_to_y(centery, diam, 0.1, skin_rad));
/* saturation points */
- for (i = 0; i < 6; i++)
+ for (int i = 0; i < 6; i++)
vectorscope_draw_target(centerx, centery, diam, colors[i]);
if (scopes->ok && scopes->vecscope != NULL) {
@@ -941,6 +931,7 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
glScalef(diam, diam, 0.f);
glVertexPointer(2, GL_FLOAT, 0, scopes->vecscope);
+ glPointSize(1.0);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
glDisableClientState(GL_VERTEX_ARRAY);
@@ -955,17 +946,12 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
static void ui_draw_colorband_handle_tri_hlight(float x1, float y1, float halfwidth, float height)
{
- float v[2];
-
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_STRIP);
- copy_v2_fl2(v, x1 + halfwidth, y1);
- glVertex2fv(v);
- copy_v2_fl2(v, x1, y1 + height);
- glVertex2fv(v);
- copy_v2_fl2(v, x1 - halfwidth, y1);
- glVertex2fv(v);
+ glVertex2f(x1 + halfwidth, y1);
+ glVertex2f(x1, y1 + height);
+ glVertex2f(x1 - halfwidth, y1);
glEnd();
glDisable(GL_LINE_SMOOTH);
@@ -973,60 +959,25 @@ static void ui_draw_colorband_handle_tri_hlight(float x1, float y1, float halfwi
static void ui_draw_colorband_handle_tri(float x1, float y1, float halfwidth, float height, bool fill)
{
- float v[2];
-
- if (fill) {
- glPolygonMode(GL_FRONT, GL_FILL);
- glEnable(GL_POLYGON_SMOOTH);
- }
- else {
- glPolygonMode(GL_FRONT, GL_LINE);
- glEnable(GL_LINE_SMOOTH);
- }
+ glEnable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH);
- glBegin(GL_TRIANGLES);
- copy_v2_fl2(v, x1 + halfwidth, y1);
- glVertex2fv(v);
- copy_v2_fl2(v, x1, y1 + height);
- glVertex2fv(v);
- copy_v2_fl2(v, x1 - halfwidth, y1);
- glVertex2fv(v);
+ glBegin(fill ? GL_TRIANGLES : GL_LINE_LOOP);
+ glVertex2f(x1 + halfwidth, y1);
+ glVertex2f(x1, y1 + height);
+ glVertex2f(x1 - halfwidth, y1);
glEnd();
- if (fill) {
- glDisable(GL_POLYGON_SMOOTH);
- }
- else {
- glDisable(GL_LINE_SMOOTH);
- glPolygonMode(GL_FRONT, GL_FILL);
- }
+ glDisable(fill ? GL_POLYGON_SMOOTH : GL_LINE_SMOOTH);
}
static void ui_draw_colorband_handle_box(float x1, float y1, float x2, float y2, bool fill)
{
- float v[2];
-
- if (fill) {
- glPolygonMode(GL_FRONT, GL_FILL);
- }
- else {
- glPolygonMode(GL_FRONT, GL_LINE);
- }
-
- glBegin(GL_QUADS);
- copy_v2_fl2(v, x1, y1);
- glVertex2fv(v);
- copy_v2_fl2(v, x1, y2);
- glVertex2fv(v);
- copy_v2_fl2(v, x2, y2);
- glVertex2fv(v);
- copy_v2_fl2(v, x2, y1);
- glVertex2fv(v);
+ glBegin(fill ? GL_QUADS : GL_LINE_LOOP);
+ glVertex2f(x1, y1);
+ glVertex2f(x1, y2);
+ glVertex2f(x2, y2);
+ glVertex2f(x2, y1);
glEnd();
-
- if (!fill) {
- glPolygonMode(GL_FRONT, GL_FILL);
- }
}
static void ui_draw_colorband_handle(
@@ -1036,14 +987,13 @@ static void ui_draw_colorband_handle(
{
const float sizey = BLI_rcti_size_y(rect);
const float min_width = 3.0f;
- float half_width, height, y1, y2;
float colf[3] = {UNPACK3(rgb)};
- half_width = floorf(sizey / 3.5f);
- height = half_width * 1.4f;
+ float half_width = floorf(sizey / 3.5f);
+ float height = half_width * 1.4f;
- y1 = rect->ymin + (sizey * 0.16f);
- y2 = rect->ymax;
+ float y1 = rect->ymin + (sizey * 0.16f);
+ float y2 = rect->ymax;
/* align to pixels */
x = floorf(x + 0.5f);
@@ -1070,7 +1020,7 @@ static void ui_draw_colorband_handle(
}
/* shift handle down */
- y1 = y1 - half_width;
+ y1 -= half_width;
glColor3ub(0, 0, 0);
ui_draw_colorband_handle_box(x - half_width, y1 - 1, x + half_width, y1 + height, false);
@@ -1110,47 +1060,47 @@ static void ui_draw_colorband_handle(
void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
{
- ColorBand *coba;
- CBData *cbd;
- float x1, y1, sizex, sizey, sizey_solid;
- float v1[2], v2[2];
- int a;
- float pos, colf[4] = {0, 0, 0, 0}; /* initialize in case the colorband isn't valid */
struct ColorManagedDisplay *display = NULL;
- coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
+ ColorBand *coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
if (coba == NULL) return;
if (but->block->color_profile)
display = ui_block_cm_display_get(but->block);
- x1 = rect->xmin;
- sizex = rect->xmax - x1;
- sizey = BLI_rcti_size_y(rect);
- sizey_solid = sizey / 4;
- y1 = rect->ymin;
+ float x1 = rect->xmin;
+ float sizex = rect->xmax - x1;
+ float sizey = BLI_rcti_size_y(rect);
+ float sizey_solid = sizey / 4;
+ float y1 = rect->ymin;
+ /* Drawing the checkerboard.
+ * This could be optimized with a single checkerboard shader,
+ * instead of drawing twice and using stippling the second time. */
/* layer: background, to show tranparency */
glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255);
glRectf(x1, y1, x1 + sizex, rect->ymax);
- glEnable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
- glPolygonStipple(stipple_checker_8px);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX);
glRectf(x1, y1, x1 + sizex, rect->ymax);
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* layer: color ramp */
glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
- cbd = coba->data;
+ CBData *cbd = coba->data;
+
+ float v1[2], v2[2];
+ float colf[4] = {0, 0, 0, 0}; /* initialize in case the colorband isn't valid */
v1[1] = y1 + sizey_solid;
v2[1] = rect->ymax;
glBegin(GL_TRIANGLE_STRIP);
- for (a = 0; a <= sizex; a++) {
- pos = ((float)a) / sizex;
+ for (int a = 0; a <= sizex; a++) {
+ float pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
@@ -1168,8 +1118,8 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v2[1] = y1 + sizey_solid;
glBegin(GL_TRIANGLE_STRIP);
- for (a = 0; a <= sizex; a++) {
- pos = ((float)a) / sizex;
+ for (int a = 0; a <= sizex; a++) {
+ float pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
@@ -1198,9 +1148,9 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
glDisable(GL_BLEND);
/* layer: draw handles */
- for (a = 0; a < coba->tot; a++, cbd++) {
+ for (int a = 0; a < coba->tot; a++, cbd++) {
if (a != coba->cur) {
- pos = x1 + cbd->pos * (sizex - 1) + 1;
+ float pos = x1 + cbd->pos * (sizex - 1) + 1;
ui_draw_colorband_handle(rect, pos, &cbd->r, display, false);
}
}
@@ -1208,7 +1158,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
/* layer: active handle */
if (coba->tot != 0) {
cbd = &coba->data[coba->cur];
- pos = x1 + cbd->pos * (sizex - 1) + 1;
+ float pos = x1 + cbd->pos * (sizex - 1) + 1;
ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
}
}
@@ -1216,43 +1166,33 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
{
static GLuint displist = 0;
- int a, old[8];
- GLfloat diff[4], diffn[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- float vec0[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float dir[4], size;
+ float diffuse[3] = {1.0f, 1.0f, 1.0f};
+ float size;
- /* store stuff */
- glGetMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
-
/* backdrop */
glColor3ubv((unsigned char *)wcol->inner);
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_gl_mode(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f);
/* sphere color */
- glMaterialfv(GL_FRONT, GL_DIFFUSE, diffn);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
- /* disable blender light */
- for (a = 0; a < 8; a++) {
- old[a] = glIsEnabled(GL_LIGHT0 + a);
- glDisable(GL_LIGHT0 + a);
- }
-
- /* own light */
- glEnable(GL_LIGHT7);
- glEnable(GL_LIGHTING);
-
- ui_but_v3_get(but, dir);
+ /* setup lights */
+ GPULightData light = {0};
+ light.type = GPU_LIGHT_SUN;
+ copy_v3_v3(light.diffuse, diffuse);
+ zero_v3(light.specular);
+ ui_but_v3_get(but, light.direction);
+
+ GPU_basic_shader_light_set(0, &light);
+ for (int a = 1; a < 8; a++)
+ GPU_basic_shader_light_set(a, NULL);
+
+ /* setup shader */
+ GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
- dir[3] = 0.0f; /* glLightfv needs 4 args, 0.0 is sun */
- glLightfv(GL_LIGHT7, GL_POSITION, dir);
- glLightfv(GL_LIGHT7, GL_DIFFUSE, diffn);
- glLightfv(GL_LIGHT7, GL_SPECULAR, vec0);
- glLightf(GL_LIGHT7, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf(GL_LIGHT7, GL_LINEAR_ATTENUATION, 0.0f);
-
/* transform to button */
glPushMatrix();
glTranslatef(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect), 0.0f);
@@ -1283,10 +1223,9 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
glCallList(displist);
/* restore */
- glDisable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ GPU_default_lights();
glDisable(GL_CULL_FACE);
- glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
- glDisable(GL_LIGHT7);
/* AA circle */
glEnable(GL_BLEND);
@@ -1298,21 +1237,13 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
/* matrix after circle */
glPopMatrix();
-
- /* enable blender light */
- for (a = 0; a < 8; a++) {
- if (old[a])
- glEnable(GL_LIGHT0 + a);
- }
}
static void ui_draw_but_curve_grid(const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step)
{
- float dx, dy, fx, fy;
-
glBegin(GL_LINES);
- dx = step * zoomx;
- fx = rect->xmin + zoomx * (-offsx);
+ float dx = step * zoomx;
+ float fx = rect->xmin + zoomx * (-offsx);
if (fx > rect->xmin) fx -= dx * (floorf(fx - rect->xmin));
while (fx < rect->xmax) {
glVertex2f(fx, rect->ymin);
@@ -1320,8 +1251,8 @@ static void ui_draw_but_curve_grid(const rcti *rect, float zoomx, float zoomy, f
fx += dx;
}
- dy = step * zoomy;
- fy = rect->ymin + zoomy * (-offsy);
+ float dy = step * zoomy;
+ float fy = rect->ymin + zoomy * (-offsy);
if (fy > rect->ymin) fy -= dy * (floorf(fy - rect->ymin));
while (fy < rect->ymax) {
glVertex2f(rect->xmin, fy);
@@ -1342,12 +1273,6 @@ static void gl_shaded_color(unsigned char *col, int shade)
void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti *rect)
{
CurveMapping *cumap;
- CurveMap *cuma;
- CurveMapPoint *cmp;
- float fx, fy, fac[2], zoomx, zoomy, offsx, offsy;
- GLint scissor[4];
- rcti scissor_new;
- int a;
if (but->editcumap) {
cumap = but->editcumap;
@@ -1356,14 +1281,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
cumap = (CurveMapping *)but->poin;
}
- cuma = &cumap->cm[cumap->cur];
+ CurveMap *cuma = &cumap->cm[cumap->cur];
/* need scissor test, curve can draw outside of boundary */
+ GLint scissor[4];
glGetIntegerv(GL_VIEWPORT, scissor);
- scissor_new.xmin = ar->winrct.xmin + rect->xmin;
- scissor_new.ymin = ar->winrct.ymin + rect->ymin;
- scissor_new.xmax = ar->winrct.xmin + rect->xmax;
- scissor_new.ymax = ar->winrct.ymin + rect->ymax;
+ rcti scissor_new = {
+ .xmin = ar->winrct.xmin + rect->xmin,
+ .ymin = ar->winrct.ymin + rect->ymin,
+ .xmax = ar->winrct.xmin + rect->xmax,
+ .ymax = ar->winrct.ymin + rect->ymax
+ };
BLI_rcti_isect(&scissor_new, &ar->winrct, &scissor_new);
glScissor(scissor_new.xmin,
scissor_new.ymin,
@@ -1371,21 +1299,24 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
BLI_rcti_size_y(&scissor_new));
/* calculate offset and zoom */
- zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
- zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
- offsx = cumap->curr.xmin - (1.0f / zoomx);
- offsy = cumap->curr.ymin - (1.0f / zoomy);
+ float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
+ float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
+ float offsx = cumap->curr.xmin - (1.0f / zoomx);
+ float offsy = cumap->curr.ymin - (1.0f / zoomy);
+ glLineWidth(1.0f);
+
/* backdrop */
if (but->a1 == UI_GRAD_H) {
/* magic trigger for curve backgrounds */
- rcti grid;
float col[3] = {0.0f, 0.0f, 0.0f}; /* dummy arg */
- grid.xmin = rect->xmin + zoomx * (-offsx);
- grid.xmax = grid.xmin + zoomx;
- grid.ymin = rect->ymin + zoomy * (-offsy);
- grid.ymax = grid.ymin + zoomy;
+ rcti grid = {
+ .xmin = rect->xmin + zoomx * (-offsx),
+ .xmax = grid.xmin + zoomx,
+ .ymin = rect->ymin + zoomy * (-offsy),
+ .ymax = grid.ymin + zoomy
+ };
ui_draw_gradient(&grid, col, UI_GRAD_H, 1.0f);
@@ -1441,6 +1372,7 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
/* sample option */
if (cumap->flag & CUMA_DRAW_SAMPLE) {
+ glBegin(GL_LINES); /* will draw one of the following 3 lines */
if (but->a1 == UI_GRAD_H) {
float tsample[3];
float hsv[3];
@@ -1448,19 +1380,15 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
rgb_to_hsv_v(tsample, hsv);
glColor3ub(240, 240, 240);
- glBegin(GL_LINES);
glVertex2f(rect->xmin + zoomx * (hsv[0] - offsx), rect->ymin);
glVertex2f(rect->xmin + zoomx * (hsv[0] - offsx), rect->ymax);
- glEnd();
}
else if (cumap->cur == 3) {
float lum = IMB_colormanagement_get_luminance(cumap->sample);
glColor3ub(240, 240, 240);
- glBegin(GL_LINES);
glVertex2f(rect->xmin + zoomx * (lum - offsx), rect->ymin);
glVertex2f(rect->xmin + zoomx * (lum - offsx), rect->ymax);
- glEnd();
}
else {
if (cumap->cur == 0)
@@ -1470,11 +1398,10 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
else
glColor3ub(100, 100, 240);
- glBegin(GL_LINES);
glVertex2f(rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymin);
glVertex2f(rect->xmin + zoomx * (cumap->sample[cumap->cur] - offsx), rect->ymax);
- glEnd();
}
+ glEnd();
}
/* the curve */
@@ -1485,20 +1412,21 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
if (cuma->table == NULL)
curvemapping_changed(cumap, false);
- cmp = cuma->table;
-
+
+ CurveMapPoint *cmp = cuma->table;
+
/* first point */
if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
glVertex2f(rect->xmin, rect->ymin + zoomy * (cmp[0].y - offsy));
}
else {
- fx = rect->xmin + zoomx * (cmp[0].x - offsx + cuma->ext_in[0]);
- fy = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]);
+ float fx = rect->xmin + zoomx * (cmp[0].x - offsx + cuma->ext_in[0]);
+ float fy = rect->ymin + zoomy * (cmp[0].y - offsy + cuma->ext_in[1]);
glVertex2f(fx, fy);
}
- for (a = 0; a <= CM_TABLE; a++) {
- fx = rect->xmin + zoomx * (cmp[a].x - offsx);
- fy = rect->ymin + zoomy * (cmp[a].y - offsy);
+ for (int a = 0; a <= CM_TABLE; a++) {
+ float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
+ float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
glVertex2f(fx, fy);
}
/* last point */
@@ -1506,8 +1434,8 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
glVertex2f(rect->xmax, rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy));
}
else {
- fx = rect->xmin + zoomx * (cmp[CM_TABLE].x - offsx - cuma->ext_out[0]);
- fy = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
+ float fx = rect->xmin + zoomx * (cmp[CM_TABLE].x - offsx - cuma->ext_out[0]);
+ float fy = rect->ymin + zoomy * (cmp[CM_TABLE].y - offsy - cuma->ext_out[1]);
glVertex2f(fx, fy);
}
glEnd();
@@ -1517,18 +1445,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
/* the points, use aspect to make them visible on edges */
cmp = cuma->curve;
glPointSize(3.0f);
- bglBegin(GL_POINTS);
- for (a = 0; a < cuma->totpoint; a++) {
+ glBegin(GL_POINTS);
+ for (int a = 0; a < cuma->totpoint; a++) {
if (cmp[a].flag & CUMA_SELECT)
UI_ThemeColor(TH_TEXT_HI);
else
UI_ThemeColor(TH_TEXT);
- fac[0] = rect->xmin + zoomx * (cmp[a].x - offsx);
- fac[1] = rect->ymin + zoomy * (cmp[a].y - offsy);
- bglVertex2fv(fac);
+ float fx = rect->xmin + zoomx * (cmp[a].x - offsx);
+ float fy = rect->ymin + zoomy * (cmp[a].y - offsy);
+ glVertex2f(fx, fy);
}
- bglEnd();
- glPointSize(1.0f);
+ glEnd();
/* restore scissortest */
glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
@@ -1540,24 +1467,24 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *recti)
{
- rctf rect;
bool ok = false;
- int width, height;
- GLint scissor[4];
MovieClipScopes *scopes = (MovieClipScopes *)but->poin;
- rect.xmin = (float)recti->xmin + 1;
- rect.xmax = (float)recti->xmax - 1;
- rect.ymin = (float)recti->ymin + 1;
- rect.ymax = (float)recti->ymax - 1;
+ rctf rect = {
+ .xmin = (float)recti->xmin + 1,
+ .xmax = (float)recti->xmax - 1,
+ .ymin = (float)recti->ymin + 1,
+ .ymax = (float)recti->ymax - 1
+ };
- width = BLI_rctf_size_x(&rect) + 1;
- height = BLI_rctf_size_y(&rect);
+ int width = BLI_rctf_size_x(&rect) + 1;
+ int height = BLI_rctf_size_y(&rect);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* need scissor test, preview image can draw outside of boundary */
+ GLint scissor[4];
glGetIntegerv(GL_VIEWPORT, scissor);
glScissor(ar->winrct.xmin + (rect.xmin - 1),
ar->winrct.ymin + (rect.ymin - 1),
@@ -1569,22 +1496,19 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
UI_draw_roundbox_corner_set(UI_CNR_ALL);
UI_draw_roundbox_gl_mode(GL_POLYGON, rect.xmin - 1, rect.ymin, rect.xmax + 1, rect.ymax + 1, 3.0f);
- ok = 1;
+ ok = true;
}
else if ((scopes->track_search) &&
((!scopes->track_preview) ||
(scopes->track_preview->x != width || scopes->track_preview->y != height)))
{
- ImBuf *tmpibuf;
-
if (scopes->track_preview)
IMB_freeImBuf(scopes->track_preview);
- tmpibuf = BKE_tracking_sample_pattern(scopes->frame_width, scopes->frame_height,
- scopes->track_search, scopes->track,
- &scopes->undist_marker, true, scopes->use_track_mask,
- width, height, scopes->track_pos);
-
+ ImBuf *tmpibuf = BKE_tracking_sample_pattern(scopes->frame_width, scopes->frame_height,
+ scopes->track_search, scopes->track,
+ &scopes->undist_marker, true, scopes->use_track_mask,
+ width, height, scopes->track_pos);
if (tmpibuf) {
if (tmpibuf->rect_float)
IMB_rect_from_float(tmpibuf);
@@ -1597,20 +1521,13 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
}
if (!ok && scopes->track_preview) {
- float track_pos[2];
- int a;
- ImBuf *drawibuf;
-
glPushMatrix();
- track_pos[0] = scopes->track_pos[0];
- track_pos[1] = scopes->track_pos[1];
-
/* draw content of pattern area */
glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + rect.ymin, scissor[2], scissor[3]);
if (width > 0 && height > 0) {
- drawibuf = scopes->track_preview;
+ ImBuf *drawibuf = scopes->track_preview;
if (scopes->use_track_mask) {
glColor4f(0.0f, 0.0f, 0.0f, 0.3f);
@@ -1621,14 +1538,14 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
glaDrawPixelsSafe(rect.xmin, rect.ymin + 1, drawibuf->x, drawibuf->y,
drawibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, drawibuf->rect);
- /* draw cross for pizel position */
- glTranslatef(rect.xmin + track_pos[0], rect.ymin + track_pos[1], 0.f);
+ /* draw cross for pixel position */
+ glTranslatef(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1], 0.f);
glScissor(ar->winrct.xmin + rect.xmin,
ar->winrct.ymin + rect.ymin,
BLI_rctf_size_x(&rect),
BLI_rctf_size_y(&rect));
- for (a = 0; a < 2; a++) {
+ for (int a = 0; a < 2; a++) {
if (a == 1) {
glLineStipple(3, 0xaaaa);
glEnable(GL_LINE_STIPPLE);
@@ -1650,7 +1567,7 @@ void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wc
glDisable(GL_LINE_STIPPLE);
glPopMatrix();
- ok = 1;
+ ok = true;
}
if (!ok) {
@@ -1684,47 +1601,44 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol
0.15142777f, 0.52896401f, 0.82076344f, 0.97952994f,
};
- unsigned char *col = but->col;
- int a;
GLint scissor[4];
- rcti scissor_new;
- float x, y;
-
- x = 0.5f * (recti->xmin + recti->xmax);
- y = 0.5f * (recti->ymin + recti->ymax);
/* need scissor test, can draw outside of boundary */
glGetIntegerv(GL_VIEWPORT, scissor);
- scissor_new.xmin = ar->winrct.xmin + recti->xmin;
- scissor_new.ymin = ar->winrct.ymin + recti->ymin;
- scissor_new.xmax = ar->winrct.xmin + recti->xmax;
- scissor_new.ymax = ar->winrct.ymin + recti->ymax;
+
+ rcti scissor_new = {
+ .xmin = ar->winrct.xmin + recti->xmin,
+ .ymin = ar->winrct.ymin + recti->ymin,
+ .xmax = ar->winrct.xmin + recti->xmax,
+ .ymax = ar->winrct.ymin + recti->ymax
+ };
+
BLI_rcti_isect(&scissor_new, &ar->winrct, &scissor_new);
glScissor(scissor_new.xmin,
scissor_new.ymin,
BLI_rcti_size_x(&scissor_new),
BLI_rcti_size_y(&scissor_new));
- glColor4ubv(col);
+ glColor4ubv(but->col);
+
+ float x = 0.5f * (recti->xmin + recti->xmax);
+ float y = 0.5f * (recti->ymin + recti->ymax);
glEnable(GL_BLEND);
glBegin(GL_POLYGON);
- for (a = 0; a < 16; a++)
+ for (int a = 0; a < 16; a++)
glVertex2f(x + size * si[a], y + size * co[a]);
glEnd();
- glDisable(GL_BLEND);
glColor4ub(0, 0, 0, 150);
-
- glEnable(GL_BLEND);
+ glLineWidth(1);
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_LOOP);
- for (a = 0; a < 16; a++)
+ for (int a = 0; a < 16; a++)
glVertex2f(x + size * si[a], y + size * co[a]);
glEnd();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
- glLineWidth(1.0f);
/* restore scissortest */
glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
@@ -1735,68 +1649,60 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol
static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha)
{
- glEnable(GL_BLEND);
- glShadeModel(GL_SMOOTH);
-
/* right quad */
- glBegin(GL_POLYGON);
glColor4ub(0, 0, 0, alpha);
glVertex2f(maxx, miny);
glVertex2f(maxx, maxy - 0.3f * shadsize);
glColor4ub(0, 0, 0, 0);
glVertex2f(maxx + shadsize, maxy - 0.75f * shadsize);
glVertex2f(maxx + shadsize, miny);
- glEnd();
/* corner shape */
- glBegin(GL_POLYGON);
glColor4ub(0, 0, 0, alpha);
glVertex2f(maxx, miny);
glColor4ub(0, 0, 0, 0);
glVertex2f(maxx + shadsize, miny);
glVertex2f(maxx + 0.7f * shadsize, miny - 0.7f * shadsize);
glVertex2f(maxx, miny - shadsize);
- glEnd();
/* bottom quad */
- glBegin(GL_POLYGON);
glColor4ub(0, 0, 0, alpha);
glVertex2f(minx + 0.3f * shadsize, miny);
glVertex2f(maxx, miny);
glColor4ub(0, 0, 0, 0);
glVertex2f(maxx, miny - shadsize);
glVertex2f(minx + 0.5f * shadsize, miny - shadsize);
- glEnd();
-
- glDisable(GL_BLEND);
- glShadeModel(GL_FLAT);
}
void UI_draw_box_shadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+
+ glBegin(GL_QUADS);
+
/* accumulated outline boxes to make shade not linear, is more pleasant */
ui_shadowbox(minx, miny, maxx, maxy, 11.0, (20 * alpha) >> 8);
ui_shadowbox(minx, miny, maxx, maxy, 7.0, (40 * alpha) >> 8);
ui_shadowbox(minx, miny, maxx, maxy, 5.0, (80 * alpha) >> 8);
+ glEnd();
+
+ glDisable(GL_BLEND);
+ glShadeModel(GL_FLAT);
}
void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha, int UNUSED(select))
{
- int i;
float rad;
- float a;
- float dalpha = alpha * 2.0f / 255.0f, calpha;
-
- glEnable(GL_BLEND);
if (radius > (BLI_rctf_size_y(rct) - 10.0f) / 2.0f)
rad = (BLI_rctf_size_y(rct) - 10.0f) / 2.0f;
else
rad = radius;
- i = 12;
+ int a, i = 12;
#if 0
if (select) {
a = i * aspect; /* same as below */
@@ -1806,8 +1712,11 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha
{
a = i * aspect;
}
+
+ glEnable(GL_BLEND);
- calpha = dalpha;
+ const float dalpha = alpha * 2.0f / 255.0f;
+ float calpha = dalpha;
for (; i--; a -= aspect) {
/* alpha ranges from 2 to 20 or so */
glColor4f(0.0f, 0.0f, 0.0f, calpha);
@@ -1825,3 +1734,14 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha
glDisable(GL_BLEND);
}
+/**
+ * Reset GL state (keep minimal).
+ *
+ * \note Blender's internal code doesn't assume these are reset,
+ * but external callbacks may depend on their state.
+ */
+void UI_reinit_gl_state(void)
+{
+ glLineWidth(1.0f);
+ glPointSize(1.0f);
+}
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index ceea4ff42d9..2cbc56b14d3 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
@@ -41,10 +42,13 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
+#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
#include "BKE_idcode.h"
#include "BKE_unit.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "BIF_gl.h"
@@ -67,6 +71,62 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+/* for Driver eyedropper */
+#include "ED_keyframing.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Keymap
+ */
+/** \name Modal Keymap
+ * \{ */
+
+enum {
+ EYE_MODAL_CANCEL = 1,
+ EYE_MODAL_SAMPLE_CONFIRM,
+ EYE_MODAL_SAMPLE_BEGIN,
+ EYE_MODAL_SAMPLE_RESET,
+};
+
+wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
+{
+ static EnumPropertyItem modal_items[] = {
+ {EYE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {EYE_MODAL_SAMPLE_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
+ {EYE_MODAL_SAMPLE_BEGIN, "SAMPLE_BEGIN", 0, "Start Sampling", ""},
+ {EYE_MODAL_SAMPLE_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper Modal Map");
+
+ /* this function is called for each spacetype, only needs to add map once */
+ if (keymap && keymap->modal_items)
+ return NULL;
+
+ keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_SAMPLE_BEGIN);
+ WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET);
+
+ /* assign to operators */
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
+
+ return keymap;
+}
+
+/** \} */
+
+
/* -------------------------------------------------------------------- */
/* Utility Functions
*/
@@ -97,6 +157,32 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
}
+
+/**
+ * Utility to retrieve a button representing a RNA property that is currently under the cursor.
+ *
+ * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
+ * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
+ * upon to provide this information, as it is not updated until the operator finishes.
+ *
+ * \return A button under the mouse which relates to some RNA Property, or NULL
+ */
+static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
+{
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, event->x, event->y);
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
+
+ uiBut *but = ui_but_find_mouse_over(ar, event);
+
+ if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) {
+ return NULL;
+ }
+ else {
+ return but;
+ }
+}
+
/** \} */
@@ -114,7 +200,9 @@ typedef struct Eyedropper {
PropertyRNA *prop;
int index;
- bool accum_start; /* has mouse been presed */
+ float init_col[3]; /* for resetting on cancel */
+
+ bool accum_start; /* has mouse been pressed */
float accum_col[3];
int accum_tot;
} Eyedropper;
@@ -139,9 +227,17 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
if (RNA_property_subtype(eye->prop) == PROP_COLOR) {
const char *display_device;
+ float col[4];
display_device = scene->display_settings.display_device;
eye->display = IMB_colormanagement_display_get_named(display_device);
+
+ /* store inital color */
+ RNA_property_float_get_array(&eye->ptr, eye->prop, col);
+ if (eye->display) {
+ IMB_colormanagement_scene_linear_to_display_v3(col, eye->display);
+ }
+ copy_v3_v3(eye->init_col, col);
}
return true;
@@ -157,11 +253,6 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
}
}
-static void eyedropper_cancel(bContext *C, wmOperator *op)
-{
- eyedropper_exit(C, op);
-}
-
/* *** eyedropper_color_ helper functions *** */
/**
@@ -268,18 +359,25 @@ static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx,
eye->accum_tot++;
}
+static void eyedropper_cancel(bContext *C, wmOperator *op)
+{
+ Eyedropper *eye = op->customdata;
+ eyedropper_color_set(C, eye, eye->init_col);
+ eyedropper_exit(C, op);
+}
+
/* main modal status check */
static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Eyedropper *eye = (Eyedropper *)op->customdata;
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- eyedropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ eyedropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
if (eye->accum_tot == 0) {
eyedropper_color_sample(C, eye, event->x, event->y);
}
@@ -288,28 +386,25 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
eyedropper_exit(C, op);
return OPERATOR_FINISHED;
- }
- else if (event->val == KM_PRESS) {
+ case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
eye->accum_start = true;
eyedropper_color_sample_accum(C, eye, event->x, event->y);
- }
- break;
- case MOUSEMOVE:
- if (eye->accum_start) {
- /* button is pressed so keep sampling */
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- eyedropper_color_set_accum(C, eye);
- }
- break;
- case SPACEKEY:
- if (event->val == KM_RELEASE) {
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
eye->accum_tot = 0;
zero_v3(eye->accum_col);
eyedropper_color_sample_accum(C, eye, event->x, event->y);
eyedropper_color_set_accum(C, eye);
- }
- break;
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (eye->accum_start) {
+ /* button is pressed so keep sampling */
+ eyedropper_color_sample_accum(C, eye, event->x, event->y);
+ eyedropper_color_set_accum(C, eye);
+ }
}
return OPERATOR_RUNNING_MODAL;
@@ -362,7 +457,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a data-block from the 3D view";
+ ot->description = "Sample a color from the Blender Window to store in a property";
/* api callbacks */
ot->invoke = eyedropper_invoke;
@@ -394,6 +489,8 @@ typedef struct DataDropper {
short idcode;
const char *idcode_name;
+ ID *init_id; /* for resetting on cancel */
+
ARegionType *art;
void *draw_handle_pixel;
char name[200];
@@ -440,6 +537,9 @@ static int datadropper_init(bContext *C, wmOperator *op)
/* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
+ PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
+ ddr->init_id = ptr.id.data;
+
return true;
}
@@ -462,11 +562,6 @@ static void datadropper_exit(bContext *C, wmOperator *op)
WM_event_add_mousemove(C);
}
-static void datadropper_cancel(bContext *C, wmOperator *op)
-{
- datadropper_exit(C, op);
-}
-
/* *** datadropper id helper functions *** */
/**
* \brief get the ID from the screen.
@@ -474,7 +569,6 @@ static void datadropper_cancel(bContext *C, wmOperator *op)
*/
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
{
-
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my);
@@ -555,18 +649,26 @@ static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
return datadropper_id_set(C, ddr, id);
}
+static void datadropper_cancel(bContext *C, wmOperator *op)
+{
+ DataDropper *ddr = op->customdata;
+ datadropper_id_set(C, ddr, ddr->init_id);
+ datadropper_exit(C, op);
+}
+
/* main modal status check */
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
DataDropper *ddr = (DataDropper *)op->customdata;
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- datadropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ datadropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ {
bool success;
success = datadropper_id_sample(C, ddr, event->x, event->y);
@@ -580,14 +682,12 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
}
- break;
- case MOUSEMOVE:
- {
- ID *id = NULL;
- datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
- break;
}
}
+ else if (event->type == MOUSEMOVE) {
+ ID *id = NULL;
+ datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
+ }
return OPERATOR_RUNNING_MODAL;
}
@@ -636,7 +736,7 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper Datablock";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a datablock from the Blender Window to store in a property";
+ ot->description = "Sample a datablock from the 3D View to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -666,6 +766,8 @@ typedef struct DepthDropper {
PointerRNA ptr;
PropertyRNA *prop;
+ float init_depth; /* for resetting on cancel */
+
bool accum_start; /* has mouse been presed */
float accum_depth;
int accum_tot;
@@ -720,6 +822,7 @@ static int depthdropper_init(bContext *C, wmOperator *op)
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+ ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
return true;
}
@@ -741,11 +844,6 @@ static void depthdropper_exit(bContext *C, wmOperator *op)
}
}
-static void depthdropper_cancel(bContext *C, wmOperator *op)
-{
- depthdropper_exit(C, op);
-}
-
/* *** depthdropper id helper functions *** */
/**
* \brief get the ID from the screen.
@@ -850,18 +948,25 @@ static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int
}
}
+static void depthdropper_cancel(bContext *C, wmOperator *op)
+{
+ DepthDropper *ddr = op->customdata;
+ depthdropper_depth_set(C, ddr, ddr->init_depth);
+ depthdropper_exit(C, op);
+}
+
/* main modal status check */
static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
DepthDropper *ddr = (DepthDropper *)op->customdata;
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- depthdropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ depthdropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
if (ddr->accum_tot == 0) {
depthdropper_depth_sample(C, ddr, event->x, event->y);
}
@@ -870,28 +975,25 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
depthdropper_exit(C, op);
return OPERATOR_FINISHED;
- }
- else if (event->val == KM_PRESS) {
+ case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
ddr->accum_start = true;
depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- }
- break;
- case MOUSEMOVE:
- if (ddr->accum_start) {
- /* button is pressed so keep sampling */
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- depthdropper_depth_set_accum(C, ddr);
- }
- break;
- case SPACEKEY:
- if (event->val == KM_RELEASE) {
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
ddr->accum_tot = 0;
ddr->accum_depth = 0.0f;
depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
depthdropper_depth_set_accum(C, ddr);
- }
- break;
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (ddr->accum_start) {
+ /* button is pressed so keep sampling */
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_set_accum(C, ddr);
+ }
}
return OPERATOR_RUNNING_MODAL;
@@ -957,3 +1059,191 @@ void UI_OT_eyedropper_depth(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/* Eyedropper
+ */
+
+/* NOTE: This is here (instead of in drivers.c) because we need access the button internals,
+ * which we cannot access outside of the interface module
+ */
+
+/** \name Eyedropper (Driver Target)
+ * \{ */
+
+typedef struct DriverDropper {
+ /* Destination property (i.e. where we'll add a driver) */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ // TODO: new target?
+} DriverDropper;
+
+static bool driverdropper_init(bContext *C, wmOperator *op)
+{
+ DriverDropper *ddr;
+ uiBut *but;
+
+ op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
+ but = UI_context_active_but_get(C);
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) ||
+ (but->flag & UI_BUT_DRIVEN))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static void driverdropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+ }
+}
+
+static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ DriverDropper *ddr = (DriverDropper *)op->customdata;
+ uiBut *but = eyedropper_get_property_button_under_mouse(C, event);
+
+ short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
+ short flag = 0;
+
+ /* we can only add a driver if we know what RNA property it corresponds to */
+ if (but == NULL) {
+ return;
+ }
+ else {
+ /* Get paths for src... */
+ PointerRNA *target_ptr = &but->rnapoin;
+ PropertyRNA *target_prop = but->rnaprop;
+ int target_index = but->rnaindex;
+
+ char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
+
+ /* ... and destination */
+ char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
+
+ /* Now create driver(s) */
+ if (target_path && dst_path) {
+ int success = ANIM_add_driver_with_target(op->reports,
+ ddr->ptr.id.data, dst_path, ddr->index,
+ target_ptr->id.data, target_path, target_index,
+ flag, DRIVER_TYPE_PYTHON, mapping_type);
+
+ if (success) {
+ /* send updates */
+ UI_context_update_anim_flag(C);
+ DAG_relations_tag_update(CTX_data_main(C));
+ DAG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
+ }
+ }
+
+ /* cleanup */
+ if (target_path)
+ MEM_freeN(target_path);
+ if (dst_path)
+ MEM_freeN(dst_path);
+ }
+}
+
+static void driverdropper_cancel(bContext *C, wmOperator *op)
+{
+ driverdropper_exit(C, op);
+}
+
+/* main modal status check */
+static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ driverdropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ driverdropper_sample(C, op, event);
+ driverdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (driverdropper_init(C, op)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ driverdropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int driverdropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (driverdropper_init(C, op)) {
+ /* cleanup */
+ driverdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int driverdropper_poll(bContext *C)
+{
+ if (!CTX_wm_window(C)) return 0;
+ else return 1;
+}
+
+void UI_OT_eyedropper_driver(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Driver";
+ ot->idname = "UI_OT_eyedropper_driver";
+ ot->description = "Pick a property to use as a driver target";
+
+ /* api callbacks */
+ ot->invoke = driverdropper_invoke;
+ ot->modal = driverdropper_modal;
+ ot->cancel = driverdropper_cancel;
+ ot->exec = driverdropper_exec;
+ ot->poll = driverdropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
+ "Mapping Type", "Method used to match target and driven properties");
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index fe5a5031725..6c961179c6f 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -119,6 +119,7 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to);
static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to);
static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event);
static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b);
+static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str);
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -138,6 +139,8 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
#define MENU_TOWARDS_MARGIN 20 /* margin in pixels */
#define MENU_TOWARDS_WIGGLE_ROOM 64 /* tolerance in pixels */
+/* drag-lock distance threshold in pixels */
+#define BUTTON_DRAGLOCK_THRESH 3
typedef enum uiButtonActivateType {
BUTTON_ACTIVATE_OVER,
@@ -280,7 +283,9 @@ typedef struct uiHandleButtonData {
wmTimer *flashtimer;
/* edited value */
- char *str, *origstr;
+ /* use 'ui_textedit_string_set' to assign new strings */
+ char *str;
+ char *origstr;
double value, origvalue, startvalue;
float vec[3], origvec[3];
#if 0 /* UNUSED */
@@ -291,14 +296,25 @@ typedef struct uiHandleButtonData {
/* tooltip */
ARegion *tooltip;
wmTimer *tooltiptimer;
+ unsigned int tooltip_force : 1;
/* auto open */
bool used_mouse;
wmTimer *autoopentimer;
/* text selection/editing */
- int maxlen, selextend;
+ /* size of 'str' (including terminator) */
+ int maxlen;
+ /* Button text selection:
+ * extension direction, selextend, inside ui_do_but_TEX */
+ enum {
+ EXTEND_NONE = 0,
+ EXTEND_LEFT = 1,
+ EXTEND_RIGHT = 2,
+ } selextend;
float selstartx;
+ /* allow to realloc str/editstr and use 'maxlen' to track alloc size (maxlen + 1) */
+ bool is_str_dynamic;
/* number editing / dragging */
/* coords are Window/uiBlock relative (depends on the button) */
@@ -381,7 +397,6 @@ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit);
static bool ui_but_contains_pt(uiBut *but, float mx, float my);
static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y);
static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, const bool labeledit);
-static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event);
static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonActivateType type);
static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state);
static void button_activate_exit(
@@ -529,6 +544,30 @@ static bool ui_but_is_cursor_warp(uiBut *but)
return false;
}
+/**
+ * Ignore mouse movements within some horizontal pixel threshold before starting to drag
+ */
+static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx)
+{
+ if (mx == data->draglastx)
+ return false;
+
+ if (data->draglock) {
+ if (ABS(mx - data->dragstartx) <= BUTTON_DRAGLOCK_THRESH) {
+ return false;
+ }
+#ifdef USE_DRAG_MULTINUM
+ if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) {
+ return false;
+ }
+#endif
+ data->draglock = false;
+ data->dragstartx = mx; /* ignore mouse movement within drag-lock */
+ }
+
+ return true;
+}
+
static float ui_mouse_scale_warp_factor(const bool shift)
{
return shift ? 0.05f : 1.0f;
@@ -721,7 +760,7 @@ static void ui_apply_but_funcs_after(bContext *C)
if (after.opptr) {
/* free in advance to avoid leak on exit */
- opptr = *after.opptr,
+ opptr = *after.opptr;
MEM_freeN(after.opptr);
}
@@ -783,7 +822,7 @@ static void ui_apply_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data
if (but->type == UI_BTYPE_MENU)
ui_but_value_set(but, data->value);
- ui_but_update(but);
+ ui_but_update_edited(but);
ui_apply_but_func(C, but);
data->retval = but->retval;
data->applied = true;
@@ -803,7 +842,9 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
else lvalue = UI_BITBUT_SET(lvalue, but->bitnr);
ui_but_value_set(but, (double)lvalue);
- if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) ui_but_update(but);
+ if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) {
+ ui_but_update_edited(but);
+ }
}
else {
@@ -812,7 +853,9 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
if (ELEM(but->type, UI_BTYPE_TOGGLE_N, UI_BTYPE_ICON_TOGGLE_N, UI_BTYPE_CHECKBOX_N)) push = !push;
ui_but_value_set(but, (double)push);
- if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) ui_but_update(but);
+ if (but->type == UI_BTYPE_ICON_TOGGLE || but->type == UI_BTYPE_ICON_TOGGLE_N) {
+ ui_but_update_edited(but);
+ }
}
ui_apply_but_func(C, but);
@@ -830,9 +873,11 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
ui_apply_but_func(C, but);
/* states of other row buttons */
- for (bt = block->buttons.first; bt; bt = bt->next)
- if (bt != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW))
- ui_but_update(bt);
+ for (bt = block->buttons.first; bt; bt = bt->next) {
+ if (bt != but && bt->poin == but->poin && ELEM(bt->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
+ ui_but_update_edited(bt);
+ }
+ }
data->retval = but->retval;
data->applied = true;
@@ -844,7 +889,7 @@ static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
return;
ui_but_string_set(C, but, data->str);
- ui_but_update(but);
+ ui_but_update_edited(but);
/* give butfunc a copy of the original text too.
* feature used for bone renaming, channels, etc.
@@ -875,10 +920,11 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
return;
}
}
- else
+ else {
ui_but_value_set(but, data->value);
+ }
- ui_but_update(but);
+ ui_but_update_edited(but);
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -888,7 +934,7 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
static void ui_apply_but_VEC(bContext *C, uiBut *but, uiHandleButtonData *data)
{
ui_but_v3_set(but, data->vec);
- ui_but_update(but);
+ ui_but_update_edited(but);
ui_apply_but_func(C, but);
data->retval = but->retval;
@@ -1199,7 +1245,7 @@ static bool ui_drag_toggle_set_xy_xy(
if (is_set_but != is_set) {
UI_but_execute(C, but);
if (do_check) {
- ui_but_update(but);
+ ui_but_update_edited(but);
}
changed = true;
}
@@ -2130,7 +2176,8 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- BLI_strncpy(data->str, id->name + 2, data->maxlen);
+
+ ui_textedit_string_set(but, data, id->name + 2);
if (ELEM(but->type, UI_BTYPE_SEARCH_MENU)) {
but->changed = true;
@@ -2146,12 +2193,39 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
/* ******************* copy and paste ******************** */
+static void ui_but_copy_data_path(uiBut *but, const bool full_path)
+{
+ char *id_path;
+
+ if (but->rnapoin.id.data == NULL) {
+ return;
+ }
+
+ if (full_path) {
+ if (but->rnaprop) {
+ id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true);
+ }
+ else {
+ id_path = RNA_path_full_struct_py(&but->rnapoin);
+ }
+ }
+ else {
+ id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+ }
+
+ if (id_path) {
+ WM_clipboard_text_set(id_path, false);
+ MEM_freeN(id_path);
+ }
+}
+
/* c = copy, v = paste */
static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode)
{
int buf_paste_len = 0;
const char *buf_paste = "";
bool buf_paste_alloc = false;
+ bool show_report = false; /* use to display errors parsing paste input */
if (mode == 'v' && but->lock == true) {
return;
@@ -2186,9 +2260,9 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
else if (mode == 'c') {
/* Get many decimal places, then strip trailing zeros.
- * note: too high values start to give strange results (6 or so is ok) */
+ * note: too high values start to give strange results */
char buf_copy[UI_MAX_DRAW_STR];
- ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), 6);
+ ui_but_string_get_ex(but, buf_copy, sizeof(buf_copy), UI_PRECISION_FLOAT_MAX);
BLI_str_rstrip_float_zero(buf_copy, '\0');
WM_clipboard_text_set(buf_copy, 0);
@@ -2202,6 +2276,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
ui_but_string_set(C, but, buf_paste);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
+ else {
+ /* evaluating will report errors */
+ show_report = true;
+ }
}
}
@@ -2228,6 +2306,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
ui_but_v3_set(but, xyz);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
+ else {
+ WM_report(RPT_ERROR, "Paste expected 3 numbers, formatted: '[n, n, n]'");
+ show_report = true;
+ }
}
}
@@ -2269,6 +2351,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
+ else {
+ WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'");
+ show_report = true;
+ }
}
}
@@ -2288,10 +2374,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
else {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
- if (ui_but_is_utf8(but))
- BLI_strncpy_utf8(active_data->str, buf_paste, active_data->maxlen);
- else
- BLI_strncpy(active_data->str, buf_paste, active_data->maxlen);
+ ui_textedit_string_set(but, active_data, buf_paste);
if (but->type == UI_BTYPE_SEARCH_MENU) {
/* else uiSearchboxData.active member is not updated [#26856] */
@@ -2366,6 +2449,10 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
if (buf_paste_alloc) {
MEM_freeN((void *)buf_paste);
}
+
+ if (show_report) {
+ WM_report_banner_show();
+ }
}
/**
@@ -2442,6 +2529,31 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu
/* ************* in-button text selection/editing ************* */
+static void ui_textedit_string_ensure_max_length(uiBut *but, uiHandleButtonData *data, int maxlen)
+{
+ BLI_assert(data->is_str_dynamic);
+ BLI_assert(data->str == but->editstr);
+
+ if (maxlen > data->maxlen) {
+ data->str = but->editstr = MEM_reallocN(data->str, sizeof(char) * maxlen);
+ data->maxlen = maxlen;
+ }
+}
+
+static void ui_textedit_string_set(uiBut *but, uiHandleButtonData *data, const char *str)
+{
+ if (data->is_str_dynamic) {
+ ui_textedit_string_ensure_max_length(but, data, strlen(str) + 1);
+ }
+
+ if (ui_but_is_utf8(but)) {
+ BLI_strncpy_utf8(data->str, str, data->maxlen);
+ }
+ else {
+ BLI_strncpy(data->str, str, data->maxlen);
+ }
+}
+
static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
{
@@ -2471,7 +2583,9 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
float startx = but->rect.xmin;
float starty_dummy = 0.0f;
- char *origstr, password_str[UI_MAX_PASSWORD_STR];
+ char password_str[UI_MAX_PASSWORD_STR];
+ /* treat 'str_last' as null terminator for str, no need to modify in-place */
+ const char *str = but->editstr, *str_last;
ui_block_to_window_fl(data->region, but->block, &startx, &starty_dummy);
@@ -2484,10 +2598,6 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
ui_but_text_password_hide(password_str, but, false);
- origstr = MEM_mallocN(sizeof(char) * data->maxlen, "ui_textedit origstr");
-
- BLI_strncpy(origstr, but->editstr, data->maxlen);
-
if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
@@ -2500,12 +2610,12 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
if (x < startx) {
int i = but->ofs;
- origstr[but->ofs] = '\0';
+ str_last = &str[but->ofs];
while (i > 0) {
- if (BLI_str_cursor_step_prev_utf8(origstr, but->ofs, &i)) {
+ if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &i)) {
/* 0.25 == scale factor for less sensitivity */
- if (BLF_width(fstyle->uifont_id, origstr + i, BLF_DRAW_STR_DUMMY_MAX) > (startx - x) * 0.25f) {
+ if (BLF_width(fstyle->uifont_id, str + i, (str_last - str) - i) > (startx - x) * 0.25f) {
break;
}
}
@@ -2524,10 +2634,12 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
float cdist, cdist_prev = 0.0f;
short pos_prev;
- but->pos = pos_prev = strlen(origstr) - but->ofs;
+ str_last = &str[strlen(str)];
+
+ but->pos = pos_prev = ((str_last - str) - but->ofs);
while (true) {
- cdist = startx + BLF_width(fstyle->uifont_id, origstr + but->ofs, BLF_DRAW_STR_DUMMY_MAX);
+ cdist = startx + BLF_width(fstyle->uifont_id, str + but->ofs, (str_last - str) - but->ofs);
/* check if position is found */
if (cdist < x) {
@@ -2543,9 +2655,9 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
pos_i = but->pos;
if (but->pos <= 0) break;
- if (BLI_str_cursor_step_prev_utf8(origstr, but->ofs, &pos_i)) {
+ if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &pos_i)) {
but->pos = pos_i;
- origstr[but->pos + but->ofs] = 0;
+ str_last = &str[but->pos + but->ofs];
}
else {
break; /* unlikely but possible */
@@ -2560,8 +2672,6 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
ui_but_text_password_hide(password_str, but, true);
- MEM_freeN(origstr);
-
fstyle->points = fstyle_points_prev;
}
@@ -2579,22 +2689,25 @@ static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data,
}
/**
- * This is used for both utf8 and ascii, its meant to be used for single keys,
- * notice the buffer is either copied or not, so its not suitable for pasting in
- * - campbell */
-static bool ui_textedit_type_buf(
+ * This is used for both utf8 and ascii
+ *
+ * For unicode buttons, \a buf is treated as unicode.
+ */
+static bool ui_textedit_insert_buf(
uiBut *but, uiHandleButtonData *data,
- const char *utf8_buf, int utf8_buf_len)
+ const char *buf, int buf_len)
{
- char *str;
- int len;
+ int len = strlen(data->str);
+ int len_new = len - (but->selend - but->selsta) + 1;
bool changed = false;
- str = data->str;
- len = strlen(str);
+ if (data->is_str_dynamic) {
+ ui_textedit_string_ensure_max_length(but, data, len_new + buf_len);
+ }
- if (len - (but->selend - but->selsta) + 1 <= data->maxlen) {
- int step = utf8_buf_len;
+ if (len_new <= data->maxlen) {
+ char *str = data->str;
+ size_t step = buf_len;
/* type over the current selection */
if ((but->selend - but->selsta) > 0) {
@@ -2602,9 +2715,19 @@ static bool ui_textedit_type_buf(
len = strlen(str);
}
- if (len + step < data->maxlen) {
+ if ((len + step >= data->maxlen) && (data->maxlen - (len + 1) > 0)) {
+ if (ui_but_is_utf8(but)) {
+ /* shorten 'step' to a utf8 algined size that fits */
+ BLI_strnlen_utf8_ex(buf, data->maxlen - (len + 1), &step);
+ }
+ else {
+ step = data->maxlen - (len + 1);
+ }
+ }
+
+ if (step && (len + step < data->maxlen)) {
memmove(&str[but->pos + step], &str[but->pos], (len + 1) - but->pos);
- memcpy(&str[but->pos], utf8_buf, step * sizeof(char));
+ memcpy(&str[but->pos], buf, step * sizeof(char));
but->pos += step;
changed = true;
}
@@ -2613,7 +2736,7 @@ static bool ui_textedit_type_buf(
return changed;
}
-static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
+static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
{
char buf[2] = {ascii, '\0'};
@@ -2625,7 +2748,7 @@ static bool ui_textedit_type_ascii(uiBut *but, uiHandleButtonData *data, char as
}
/* in some cases we want to allow invalid utf8 chars */
- return ui_textedit_type_buf(but, data, buf, 1);
+ return ui_textedit_insert_buf(but, data, buf, 1);
}
static void ui_textedit_move(
@@ -2652,7 +2775,7 @@ static void ui_textedit_move(
but->pos = but->selend = but->selsta;
}
}
- data->selextend = 0;
+ data->selextend = EXTEND_NONE;
}
else {
int pos_i = but->pos;
@@ -2663,7 +2786,7 @@ static void ui_textedit_move(
/* existing selection */
if (has_sel) {
- if (data->selextend == 0) {
+ if (data->selextend == EXTEND_NONE) {
data->selextend = EXTEND_RIGHT;
}
@@ -2779,48 +2902,24 @@ enum {
static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const int mode)
{
- char *str, *pbuf;
- int x;
+ char *pbuf;
bool changed = false;
- int str_len, buf_len;
-
- str = data->str;
- str_len = strlen(str);
+ int buf_len;
/* paste */
if (mode == UI_TEXTEDIT_PASTE) {
- /* TODO, ensure UTF8 ui_but_is_utf8() - campbell */
/* extract the first line from the clipboard */
pbuf = WM_clipboard_text_get_firstline(false, &buf_len);
if (pbuf) {
- char buf[UI_MAX_DRAW_STR] = {0};
- unsigned int y;
-
- buf_len = BLI_strncpy_rlen(buf, pbuf, sizeof(buf));
-
- /* paste over the current selection */
- if ((but->selend - but->selsta) > 0) {
- ui_textedit_delete_selection(but, data);
- str_len = strlen(str);
- }
-
- for (y = 0; y < buf_len; y++) {
- /* add contents of buffer */
- if (str_len + 1 < data->maxlen) {
- for (x = data->maxlen; x > but->pos; x--)
- str[x] = str[x - 1];
- str[but->pos] = buf[y];
- but->pos++;
- str_len++;
- str[str_len] = '\0';
- }
+ if (ui_but_is_utf8(but)) {
+ buf_len -= BLI_utf8_invalid_strip(pbuf, buf_len);
}
+ ui_textedit_insert_buf(but, data, pbuf, buf_len);
+
changed = true;
- }
- if (pbuf) {
MEM_freeN(pbuf);
}
}
@@ -2830,7 +2929,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in
int sellen = but->selend - but->selsta;
char *buf = MEM_mallocN(sizeof(char) * (sellen + 1), "ui_textedit_copypaste");
- BLI_strncpy(buf, str + but->selsta, sellen + 1);
+ BLI_strncpy(buf, data->str + but->selsta, sellen + 1);
WM_clipboard_text_set(buf, 0);
MEM_freeN(buf);
@@ -2934,14 +3033,21 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
/* retrieve string */
data->maxlen = ui_but_string_get_max_length(but);
- data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str");
- ui_but_string_get(but, data->str, data->maxlen);
+ if (data->maxlen != 0) {
+ data->str = MEM_callocN(sizeof(char) * data->maxlen, "textedit str");
+ ui_but_string_get(but, data->str, data->maxlen);
+ }
+ else {
+ data->is_str_dynamic = true;
+ data->str = ui_but_string_get_dynamic(but, &data->maxlen);
+ }
if (ui_but_is_float(but) && !ui_but_is_unit(but)) {
BLI_str_rstrip_float_zero(data->str, '\0');
}
if (is_num_but) {
+ BLI_assert(data->is_str_dynamic == false);
ui_but_convert_to_unit_alt_name(but, data->str, data->maxlen);
}
@@ -2949,7 +3055,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
len = strlen(data->str);
data->origstr = BLI_strdupn(data->str, len);
- data->selextend = 0;
+ data->selextend = EXTEND_NONE;
data->selstartx = 0.0f;
/* set cursor pos to the end of the text */
@@ -2960,7 +3066,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
/* optional searchbox */
if (but->type == UI_BTYPE_SEARCH_MENU) {
- data->searchbox = ui_searchbox_create(C, data->region, but);
+ data->searchbox = but->search_create_func(C, data->region, but);
ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
}
@@ -3323,10 +3429,10 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
}
// strcpy(utf8_buf, "12345");
- changed = ui_textedit_type_buf(but, data, event->utf8_buf, utf8_buf_len);
+ changed = ui_textedit_insert_buf(but, data, event->utf8_buf, utf8_buf_len);
}
else {
- changed = ui_textedit_type_ascii(but, data, ascii);
+ changed = ui_textedit_insert_ascii(but, data, ascii);
}
retval = WM_UI_HANDLER_BREAK;
@@ -3346,7 +3452,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_textedit_delete_selection(but, data);
}
if (event->type == WM_IME_COMPOSITE_EVENT && ime_data->result_len) {
- ui_textedit_type_buf(
+ ui_textedit_insert_buf(
but, data,
ime_data->str_result,
ime_data->result_len);
@@ -3363,7 +3469,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_apply_but(C, block, but, data, true);
}
else {
- ui_but_update(but);
+ ui_but_update_edited(but);
}
but->changed = true;
@@ -3936,8 +4042,12 @@ static float ui_numedit_apply_snapf(
/* snapping by 10's for float buttons is quite annoying (location, scale...),
* but allow for rotations */
if (softrange >= 21.0f) {
+ UnitSettings *unit = but->block->unit;
int unit_type = UI_but_unit_type_get(but);
- if (!ELEM(unit_type, PROP_UNIT_ROTATION)) {
+ if ((unit_type == PROP_UNIT_ROTATION) && (unit->system_rotation != USER_UNIT_ROT_RADIANS)) {
+ /* pass (degrees)*/
+ }
+ else {
softrange = 20.0f;
}
}
@@ -3993,23 +4103,10 @@ static bool ui_numedit_but_NUM(
int lvalue, temp;
bool changed = false;
const bool is_float = ui_but_is_float(but);
-
- if (mx == data->draglastx)
- return changed;
-
- /* drag-lock - prevent unwanted scroll adjustments */
- /* change value (now 3) to adjust threshold in pixels */
- if (data->draglock) {
- if (abs(mx - data->dragstartx) <= 3)
- return changed;
-#ifdef USE_DRAG_MULTINUM
- if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) {
- return changed;
- }
-#endif
- data->draglock = false;
- data->dragstartx = mx; /* ignore mouse movement within drag-lock */
+ /* prevent unwanted drag adjustments */
+ if (ui_but_dragedit_update_mval(data, mx) == false) {
+ return changed;
}
softmin = but->softmin;
@@ -4074,9 +4171,23 @@ static bool ui_numedit_but_NUM(
data->draglastx = mx;
}
else {
+ float non_linear_range_limit;
+ float non_linear_pixel_map;
+ float non_linear_scale;
+
/* Use a non-linear mapping of the mouse drag especially for large floats (normal behavior) */
deler = 500;
- if (!is_float) {
+ if (is_float) {
+ /* not needed for smaller float buttons */
+ non_linear_range_limit = 11.0f;
+ non_linear_pixel_map = 500.0f;
+ }
+ else {
+ /* only scale large int buttons */
+ non_linear_range_limit = 129.0f;
+ /* larger for ints, we dont need to fine tune them */
+ non_linear_pixel_map = 250.0f;
+
/* prevent large ranges from getting too out of control */
if (softrange > 600) deler = powf(softrange, 0.75f);
else if (softrange < 25) deler = 50.0;
@@ -4084,18 +4195,19 @@ static bool ui_numedit_but_NUM(
}
deler /= fac;
- if ((is_float == true) && (softrange > 11)) {
- /* non linear change in mouse input- good for high precicsion */
- data->dragf += (((float)(mx - data->draglastx)) / deler) * ((float)abs(mx - data->dragstartx) / 500.0f);
- }
- else if ((is_float == false) && (softrange > 129)) { /* only scale large int buttons */
- /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */
- data->dragf += (((float)(mx - data->draglastx)) / deler) * ((float)abs(mx - data->dragstartx) / 250.0f);
+ if (softrange > non_linear_range_limit) {
+ non_linear_scale = (float)abs(mx - data->dragstartx) / non_linear_pixel_map;
}
else {
- /*no scaling */
- data->dragf += ((float)(mx - data->draglastx)) / deler;
+ non_linear_scale = 1.0f;
}
+
+ if (is_float == false) {
+ /* at minimum, moving cursor 2 pixels should change an int button. */
+ CLAMP_MIN(non_linear_scale, 0.5f * U.pixelsize);
+ }
+
+ data->dragf += (((float)(mx - data->draglastx)) / deler) * non_linear_scale;
CLAMP(data->dragf, 0.0f, 1.0f);
data->draglastx = mx;
@@ -4332,6 +4444,13 @@ static bool ui_numedit_but_SLI(
/* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */
float offs;
+ /* prevent unwanted drag adjustments */
+ if ((but->type != UI_BTYPE_SCROLL) &&
+ (ui_but_dragedit_update_mval(data, mx) == false))
+ {
+ return changed;
+ }
+
softmin = but->softmin;
softmax = but->softmax;
softrange = softmax - softmin;
@@ -4511,6 +4630,10 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
}
else {
+#ifdef USE_CONT_MOUSE_CORRECT
+ /* reset! */
+ copy_v2_fl(data->ungrab_mval, FLT_MAX);
+#endif
click = 1;
}
}
@@ -6317,10 +6440,10 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
uiLayout *layout;
uiStyle *style = UI_style_get_dpi();
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
- int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
- kmi = WM_keymap_item_find_id(km, kmi_id);
-
+ kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, true, &km);
+ BLI_assert(kmi != NULL);
+
RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
@@ -6414,7 +6537,6 @@ static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_but_tooltip_timer_remove(C, but);
UI_popup_block_invoke(C, menu_change_shortcut, but);
}
@@ -6424,9 +6546,10 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
wmKeyMap *km;
wmKeyMapItem *kmi;
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
- int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
-
- kmi = WM_keymap_item_find_id(km, kmi_id);
+
+ kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, true, &km);
+ BLI_assert(kmi != NULL);
+
WM_keymap_remove_item(km, kmi);
but_shortcut_name_func(C, but, 0);
@@ -6435,7 +6558,6 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
- UI_but_tooltip_timer_remove(C, but);
UI_popup_block_ex(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
}
@@ -6484,8 +6606,6 @@ static bool ui_but_menu(bContext *C, uiBut *but)
return false;
}
- UI_but_tooltip_timer_remove(C, but);
-
/* highly unlikely getting the label ever fails */
UI_but_string_info_get(C, but, &label, NULL);
@@ -6517,7 +6637,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
/* replace/delete keyfraemes */
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframes"),
- ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
+ ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Single Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframes"),
@@ -6527,7 +6647,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Replace Keyframe"),
- ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
+ ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_delete_button", "all", 1);
}
@@ -6543,26 +6663,26 @@ static bool ui_but_menu(bContext *C, uiBut *but)
else if (is_anim) {
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframes"),
- ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
+ ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Single Keyframe"),
ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 0);
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Insert Keyframe"),
- ICON_NONE, "ANIM_OT_keyframe_insert_button", "all", 1);
+ ICON_KEY_HLT, "ANIM_OT_keyframe_insert_button", "all", 1);
}
}
if ((but->flag & UI_BUT_ANIMATED) && (but->rnapoin.type != &RNA_NlaStrip)) {
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
- ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1);
+ ICON_KEY_DEHLT, "ANIM_OT_keyframe_clear_button", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Single Keyframes"),
ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 0);
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Keyframes"),
- ICON_NONE, "ANIM_OT_keyframe_clear_button", "all", 1);
+ ICON_KEY_DEHLT, "ANIM_OT_keyframe_clear_button", "all", 1);
}
}
@@ -6572,13 +6692,13 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Drivers"),
- ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1);
+ ICON_X, "ANIM_OT_driver_button_remove", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Single Driver"),
ICON_NONE, "ANIM_OT_driver_button_remove", "all", 0);
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Delete Driver"),
- ICON_NONE, "ANIM_OT_driver_button_remove", "all", 1);
+ ICON_X, "ANIM_OT_driver_button_remove", "all", 1);
}
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Driver"),
@@ -6595,14 +6715,14 @@ static bool ui_but_menu(bContext *C, uiBut *but)
uiItemS(layout);
if (is_array_component) {
- uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
- ICON_NONE, "ANIM_OT_driver_button_add", "all", 1);
- uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single Driver"),
- ICON_NONE, "ANIM_OT_driver_button_add", "all", 0);
+ uiItemMenuEnumO(layout, C, "ANIM_OT_driver_button_add", "mapping_type",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Drivers"),
+ ICON_DRIVER);
}
else {
- uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
- ICON_NONE, "ANIM_OT_driver_button_add", "all", 1);
+ uiItemMenuEnumO(layout, C, "ANIM_OT_driver_button_add", "mapping_type",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Driver"),
+ ICON_DRIVER);
}
if (ANIM_driver_can_paste()) {
@@ -6618,7 +6738,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add All to Keying Set"),
- ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1);
+ ICON_KEYINGSET, "ANIM_OT_keyingset_button_add", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Single to Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 0);
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
@@ -6626,7 +6746,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add to Keying Set"),
- ICON_NONE, "ANIM_OT_keyingset_button_add", "all", 1);
+ ICON_KEYINGSET, "ANIM_OT_keyingset_button_add", "all", 1);
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove from Keying Set"),
ICON_NONE, "ANIM_OT_keyingset_button_remove");
}
@@ -6641,23 +6761,32 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset All to Default Values"),
- ICON_NONE, "UI_OT_reset_default_button", "all", 1);
+ ICON_LOOP_BACK, "UI_OT_reset_default_button", "all", 1);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset Single to Default Value"),
ICON_NONE, "UI_OT_reset_default_button", "all", 0);
}
else {
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Reset to Default Value"),
- ICON_NONE, "UI_OT_reset_default_button", "all", 1);
+ ICON_LOOP_BACK, "UI_OT_reset_default_button", "all", 1);
}
if (is_editable /*&& is_idprop*/ && is_set) {
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Unset"),
ICON_NONE, "UI_OT_unset_property_button");
}
+ if (is_array_component) {
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"),
+ ICON_NONE, "UI_OT_copy_to_selected_button", "all", true);
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"),
+ ICON_NONE, "UI_OT_copy_to_selected_button", "all", false);
+ }
+ else {
+ uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ ICON_NONE, "UI_OT_copy_to_selected_button", "all", true);
+ }
+
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Data Path"),
ICON_NONE, "UI_OT_copy_data_path_button");
- uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
- ICON_NONE, "UI_OT_copy_to_selected_button");
uiItemS(layout);
}
@@ -6669,29 +6798,39 @@ static bool ui_but_menu(bContext *C, uiBut *but)
IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
int w = uiLayoutGetWidth(layout);
wmKeyMap *km;
- wmKeyMapItem *kmi = NULL;
- int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
-
- if (kmi_id)
- kmi = WM_keymap_item_find_id(km, kmi_id);
-
- /* keyboard shortcuts */
- if ((kmi) && ISKEYBOARD(kmi->type)) {
+ /* We want to know if this op has a shortcut, be it hotkey or not. */
+ wmKeyMapItem *kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, false, &km);
+
+ /* We do have a shortcut, but only keyboard ones are editbale that way... */
+ if (kmi) {
+ if (ISKEYBOARD(kmi->type)) {
+#if 0 /* would rather use a block but, but gets weirdly positioned... */
+ uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut",
+ 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, "");
+#endif
- /* would rather use a block but, but gets weirdly positioned... */
- //uiDefBlockBut(block, menu_change_shortcut, but, "Change Shortcut", 0, 0, uiLayoutGetWidth(layout), UI_UNIT_Y, "");
-
- but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"),
- 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- UI_but_func_set(but2, popup_change_shortcut_func, but, NULL);
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_HAND,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"),
+ 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ UI_but_func_set(but2, popup_change_shortcut_func, but, NULL);
- but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
- 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
- UI_but_func_set(but2, remove_shortcut_func, but, NULL);
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_NONE,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"),
+ 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ UI_but_func_set(but2, remove_shortcut_func, but, NULL);
+ }
+ else {
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_HAND, IFACE_("Non-Keyboard Shortcut"),
+ 0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0,
+ TIP_("Only keyboard shortcuts can be edited that way, "
+ "please use User Preferences otherwise"));
+ UI_but_flag_enable(but2, UI_BUT_DISABLED);
+ }
}
/* only show 'add' if there's a suitable key map for it to go in */
else if (WM_keymap_guess_opname(C, but->optype->idname)) {
- but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, 0, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"),
+ but2 = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_HAND,
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Add Shortcut"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
UI_but_func_set(but2, popup_add_shortcut_func, but, NULL);
}
@@ -6714,7 +6853,7 @@ static bool ui_but_menu(bContext *C, uiBut *but)
if (UI_but_online_manual_id(but, buf, sizeof(buf))) {
uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Manual"),
- ICON_NONE, "WM_OT_doc_view_manual_ui_context");
+ ICON_URL, "WM_OT_doc_view_manual_ui_context");
WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
RNA_string_set(&ptr_props, "doc_id", buf);
@@ -6732,6 +6871,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
}
}
+ if (but->optype) {
+ uiItemO(layout, NULL,
+ ICON_NONE, "UI_OT_copy_python_command_button");
+ }
+
/* perhaps we should move this into (G.debug & G_DEBUG) - campbell */
if (ui_block_is_menu(but->block) == false) {
uiItemFullO(layout, "UI_OT_editsource", NULL, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0);
@@ -6768,6 +6912,12 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
}
+ /* special case, copy-data-path */
+ if ((event->type == CKEY) && event->shift) {
+ ui_but_copy_data_path(but, event->alt != 0);
+ return WM_UI_HANDLER_BREAK;
+ }
+
ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v');
return WM_UI_HANDLER_BREAK;
}
@@ -6832,12 +6982,12 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle drivers */
else if ((event->type == DKEY) &&
- !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
+ !IS_EVENT_MOD(event, shift, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt)
ui_but_anim_remove_driver(C);
- else
+ else if (event->ctrl)
ui_but_anim_add_driver(C);
ED_region_tag_redraw(data->region);
@@ -6875,7 +7025,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
/* this should become disabled button .. */
if (but->lock == true) {
if (but->lockstr) {
- WM_report(C, RPT_INFO, but->lockstr);
+ WM_report(RPT_INFO, but->lockstr);
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
@@ -7360,7 +7510,7 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
return butover;
}
-static uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event)
+uiBut *ui_but_find_mouse_over(ARegion *ar, const wmEvent *event)
{
return ui_but_find_mouse_over_ex(ar, event->x, event->y, event->ctrl != 0);
}
@@ -7408,6 +7558,20 @@ static bool button_modal_state(uiHandleButtonState state)
BUTTON_STATE_MENU_OPEN);
}
+/**
+ * Recreate tooltip (use to update dynamic tips)
+ */
+void UI_but_tooltip_refresh(bContext *C, uiBut *but)
+{
+ uiHandleButtonData *data;
+
+ data = but->active;
+ if (data && data->tooltip) {
+ ui_tooltip_free(C, data->tooltip);
+ data->tooltip = ui_tooltip_create(C, data->region, but);
+ }
+}
+
/* removes tooltip timer from active but (meaning tooltip is disabled until it's reenabled again) */
void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
{
@@ -7444,7 +7608,7 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
data->tooltiptimer = NULL;
}
- if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_BUT_TIP_FORCE)) {
+ if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) {
if (!but->block->tooltipdisabled) {
if (!wm->drags.first) {
data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY);
@@ -7513,8 +7677,14 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
else if (data->state == BUTTON_STATE_NUM_EDITING) {
ui_numedit_end(but, data);
- if (but->flag & UI_BUT_DRIVEN)
- WM_report(C, RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup.");
+ if (but->flag & UI_BUT_DRIVEN) {
+ /* Only warn when editing stepping/dragging the value.
+ * No warnings should show for editing driver expressions though!
+ */
+ if (state != BUTTON_STATE_TEXT_EDITING) {
+ WM_report(RPT_INFO, "Can't edit driven number value, see graph editor for the driver setup.");
+ }
+ }
if (ui_but_is_cursor_warp(but)) {
@@ -7604,7 +7774,9 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
/* XXX curve is temp */
}
else {
- data->interactive = true;
+ if ((but->flag & UI_BUT_UPDATE_DELAY) == 0) {
+ data->interactive = true;
+ }
}
data->state = BUTTON_STATE_INIT;
@@ -7964,14 +8136,12 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
if (event->type == MOUSEMOVE) {
but = ui_but_find_mouse_over(ar, event);
if (but) {
- if (event->alt) {
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+
+ if (event->alt && but->active) {
/* display tooltips if holding alt on mouseover when tooltips are off in prefs */
- but->flag |= UI_BUT_TIP_FORCE;
+ but->active->tooltip_force = true;
}
- else {
- but->flag &= ~UI_BUT_TIP_FORCE;
- }
- button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
}
}
else if (event->type == EVT_BUT_OPEN) {
@@ -8145,7 +8315,6 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
case MOUSEMOVE:
if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) {
- ARegion *ar = data->region;
but->flag |= UI_SELECT;
ui_do_button(C, block, but, event);
ED_region_tag_redraw(ar);
@@ -9318,6 +9487,9 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
is_click_style = (block->pie_data.flags & UI_PIE_CLICK_STYLE);
+ /* if there's an active modal button, don't check events or outside, except for search menu */
+ but = ui_but_find_active_in_region(ar);
+
if (menu->scrolltimer == NULL) {
menu->scrolltimer =
WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL);
@@ -9333,210 +9505,214 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
dist = ui_block_calc_pie_segment(block, event_xy);
- if (event->type == TIMER) {
- if (event->customdata == menu->scrolltimer) {
- /* deactivate initial direction after a while */
- if (duration > 0.01 * U.pie_initial_timeout) {
- block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION;
- }
+ if (but && button_modal_state(but->active->state)) {
+ retval = ui_handle_menu_button(C, event, menu);
+ }
+ else {
+ if (event->type == TIMER) {
+ if (event->customdata == menu->scrolltimer) {
+ /* deactivate initial direction after a while */
+ if (duration > 0.01 * U.pie_initial_timeout) {
+ block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION;
+ }
- /* handle animation */
- if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) {
- uiBut *but;
- double final_time = 0.01 * U.pie_animation_timeout;
- float fac = duration / final_time;
- float pie_radius = U.pie_menu_radius * UI_DPI_FAC;
+ /* handle animation */
+ if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) {
+ double final_time = 0.01 * U.pie_animation_timeout;
+ float fac = duration / final_time;
+ float pie_radius = U.pie_menu_radius * UI_DPI_FAC;
- if (fac > 1.0f) {
- fac = 1.0f;
- block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED;
- }
+ if (fac > 1.0f) {
+ fac = 1.0f;
+ block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED;
+ }
- for (but = block->buttons.first; but; but = but->next) {
- if (but->pie_dir != UI_RADIAL_NONE) {
- float vec[2];
- float center[2];
-
- ui_but_pie_dir(but->pie_dir, vec);
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ float vec[2];
+ float center[2];
- center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f);
- center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f);
+ ui_but_pie_dir(but->pie_dir, vec);
- center[0] *= BLI_rctf_size_x(&but->rect);
- center[1] *= BLI_rctf_size_y(&but->rect);
-
- mul_v2_fl(vec, pie_radius);
- add_v2_v2(vec, center);
- mul_v2_fl(vec, fac);
- add_v2_v2(vec, block->pie_data.pie_center_spawned);
-
- BLI_rctf_recenter(&but->rect, vec[0], vec[1]);
+ center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f);
+ center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f);
+
+ center[0] *= BLI_rctf_size_x(&but->rect);
+ center[1] *= BLI_rctf_size_y(&but->rect);
+
+ mul_v2_fl(vec, pie_radius);
+ add_v2_v2(vec, center);
+ mul_v2_fl(vec, fac);
+ add_v2_v2(vec, block->pie_data.pie_center_spawned);
+
+ BLI_rctf_recenter(&but->rect, vec[0], vec[1]);
+ }
}
- }
- block->pie_data.alphafac = fac;
+ block->pie_data.alphafac = fac;
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw(ar);
+ }
}
- }
- /* check pie velociy here if gesture has ended */
- if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) {
- float len_sq = 10;
+ /* check pie velociy here if gesture has ended */
+ if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) {
+ float len_sq = 10;
- /* use a time threshold to ensure we leave time to the mouse to move */
- if (duration - block->pie_data.duration_gesture > 0.02) {
- len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos);
- copy_v2_v2(block->pie_data.last_pos, event_xy);
- block->pie_data.duration_gesture = duration;
- }
+ /* use a time threshold to ensure we leave time to the mouse to move */
+ if (duration - block->pie_data.duration_gesture > 0.02) {
+ len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos);
+ copy_v2_v2(block->pie_data.last_pos, event_xy);
+ block->pie_data.duration_gesture = duration;
+ }
- if (len_sq < 1.0f) {
- uiBut *but = ui_but_find_active_in_region(menu->region);
+ if (len_sq < 1.0f) {
+ but = ui_but_find_active_in_region(menu->region);
- if (but) {
- return ui_but_pie_menu_apply(C, menu, but, true);
+ if (but) {
+ return ui_but_pie_menu_apply(C, menu, but, true);
+ }
}
}
}
- }
- if (event->type == block->pie_data.event && !is_click_style) {
- if (event->val != KM_RELEASE) {
- ui_handle_menu_button(C, event, menu);
+ if (event->type == block->pie_data.event && !is_click_style) {
+ if (event->val != KM_RELEASE) {
+ ui_handle_menu_button(C, event, menu);
- if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) {
- block->pie_data.flags |= UI_PIE_DRAG_STYLE;
- }
- /* why redraw here? It's simple, we are getting many double click events here.
- * Those operate like mouse move events almost */
- ED_region_tag_redraw(ar);
- }
- else {
- /* distance from initial point */
- if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) {
- block->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
+ /* why redraw here? It's simple, we are getting many double click events here.
+ * Those operate like mouse move events almost */
+ ED_region_tag_redraw(ar);
}
else {
- uiBut *but = ui_but_find_active_in_region(menu->region);
-
- if (but && (U.pie_menu_confirm > 0) &&
- (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
- {
- if (but)
- return ui_but_pie_menu_apply(C, menu, but, true);
+ /* distance from initial point */
+ if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) {
+ block->pie_data.flags |= UI_PIE_CLICK_STYLE;
}
+ else {
+ but = ui_but_find_active_in_region(menu->region);
- retval = ui_but_pie_menu_apply(C, menu, but, true);
+ if (but && (U.pie_menu_confirm > 0) &&
+ (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ {
+ if (but)
+ return ui_but_pie_menu_apply(C, menu, but, true);
+ }
+
+ retval = ui_but_pie_menu_apply(C, menu, but, true);
+ }
}
}
- }
- else {
- /* direction from numpad */
- RadialDirection num_dir = UI_RADIAL_NONE;
+ else {
+ /* direction from numpad */
+ RadialDirection num_dir = UI_RADIAL_NONE;
- switch (event->type) {
- case MOUSEMOVE:
- if (!is_click_style) {
- float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init);
+ switch (event->type) {
+ case MOUSEMOVE:
+ if (!is_click_style) {
+ float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init);
- /* here we use the initial position explicitly */
- if (len_sq > PIE_CLICK_THRESHOLD_SQ) {
- block->pie_data.flags |= UI_PIE_DRAG_STYLE;
- }
+ /* here we use the initial position explicitly */
+ if (len_sq > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
- /* here instead, we use the offset location to account for the initial direction timeout */
- if ((U.pie_menu_confirm > 0) &&
- (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
- {
- block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT;
- copy_v2_v2(block->pie_data.last_pos, event_xy);
- block->pie_data.duration_gesture = duration;
+ /* here instead, we use the offset location to account for the initial direction timeout */
+ if ((U.pie_menu_confirm > 0) &&
+ (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ {
+ block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT;
+ copy_v2_v2(block->pie_data.last_pos, event_xy);
+ block->pie_data.duration_gesture = duration;
+ }
}
- }
- ui_handle_menu_button(C, event, menu);
-
- /* mouse move should always refresh the area for pie menus */
- ED_region_tag_redraw(ar);
- break;
+ ui_handle_menu_button(C, event, menu);
- case LEFTMOUSE:
- if (is_click_style) {
- if (block->pie_data.flags & UI_PIE_INVALID_DIR) {
- menu->menuretval = UI_RETURN_CANCEL;
- }
- else {
- retval = ui_handle_menu_button(C, event, menu);
+ /* mouse move should always refresh the area for pie menus */
+ ED_region_tag_redraw(ar);
+ break;
+
+ case LEFTMOUSE:
+ if (is_click_style) {
+ if (block->pie_data.flags & UI_PIE_INVALID_DIR) {
+ menu->menuretval = UI_RETURN_CANCEL;
+ }
+ else {
+ retval = ui_handle_menu_button(C, event, menu);
+ }
}
- }
- break;
+ break;
- case ESCKEY:
- case RIGHTMOUSE:
- menu->menuretval = UI_RETURN_CANCEL;
- break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ menu->menuretval = UI_RETURN_CANCEL;
+ break;
- case AKEY:
- case BKEY:
- case CKEY:
- case DKEY:
- case EKEY:
- case FKEY:
- case GKEY:
- case HKEY:
- case IKEY:
- case JKEY:
- case KKEY:
- case LKEY:
- case MKEY:
- case NKEY:
- case OKEY:
- case PKEY:
- case QKEY:
- case RKEY:
- case SKEY:
- case TKEY:
- case UKEY:
- case VKEY:
- case WKEY:
- case XKEY:
- case YKEY:
- case ZKEY:
- {
- if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
- !IS_EVENT_MOD(event, shift, ctrl, oskey))
+ case AKEY:
+ case BKEY:
+ case CKEY:
+ case DKEY:
+ case EKEY:
+ case FKEY:
+ case GKEY:
+ case HKEY:
+ case IKEY:
+ case JKEY:
+ case KKEY:
+ case LKEY:
+ case MKEY:
+ case NKEY:
+ case OKEY:
+ case PKEY:
+ case QKEY:
+ case RKEY:
+ case SKEY:
+ case TKEY:
+ case UKEY:
+ case VKEY:
+ case WKEY:
+ case XKEY:
+ case YKEY:
+ case ZKEY:
{
- for (but = block->buttons.first; but; but = but->next) {
- if (but->menu_key == event->type) {
- ui_but_pie_button_activate(C, but, menu);
+ if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
+ !IS_EVENT_MOD(event, shift, ctrl, oskey))
+ {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->menu_key == event->type) {
+ ui_but_pie_button_activate(C, but, menu);
+ }
}
}
+ break;
}
- break;
- }
#define CASE_NUM_TO_DIR(n, d) \
case (ZEROKEY + n): case (PAD0 + n): \
{ if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0
- CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
- CASE_NUM_TO_DIR(2, UI_RADIAL_S);
- CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
- CASE_NUM_TO_DIR(4, UI_RADIAL_W);
- CASE_NUM_TO_DIR(6, UI_RADIAL_E);
- CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
- CASE_NUM_TO_DIR(8, UI_RADIAL_N);
- CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
- {
- but = ui_block_pie_dir_activate(block, event, num_dir);
- retval = ui_but_pie_button_activate(C, but, menu);
- break;
- }
+ CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
+ CASE_NUM_TO_DIR(2, UI_RADIAL_S);
+ CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
+ CASE_NUM_TO_DIR(4, UI_RADIAL_W);
+ CASE_NUM_TO_DIR(6, UI_RADIAL_E);
+ CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
+ CASE_NUM_TO_DIR(8, UI_RADIAL_N);
+ CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
+ {
+ but = ui_block_pie_dir_activate(block, event, num_dir);
+ retval = ui_but_pie_button_activate(C, but, menu);
+ break;
+ }
#undef CASE_NUM_TO_DIR
- default:
- retval = ui_handle_menu_button(C, event, menu);
- break;
+ default:
+ retval = ui_handle_menu_button(C, event, menu);
+ break;
+ }
}
}
@@ -9783,10 +9959,14 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
menu_region = CTX_wm_menu(C);
CTX_wm_menu_set(C, menu->region);
- if (event->type == EVT_DROP) {
- /* if we're handling drop event we'll want it to be handled by popup callee as well,
- * so it'll be possible to perform such operations as opening .blend files by dropping
- * them into blender even if there's opened popup like splash screen (sergey)
+ if (event->type == EVT_DROP || event->val == KM_DBL_CLICK) {
+ /* EVT_DROP:
+ * If we're handling drop event we'll want it to be handled by popup callee as well,
+ * so it'll be possible to perform such operations as opening .blend files by dropping
+ * them into blender, even if there's opened popup like splash screen (sergey).
+ * KM_DBL_CLICK:
+ * Continue in case of double click so wm_handlers_do calls handler again with KM_PRESS
+ * event. This is needed to ensure correct button handling for fast clicking (T47532).
*/
retval = WM_UI_HANDLER_CONTINUE;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 796a7646b87..7be153e942e 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -34,12 +34,14 @@
#include "MEM_guardedalloc.h"
#include "GPU_extensions.h"
+#include "GPU_basic_shader.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
#include "DNA_brush_types.h"
+#include "DNA_curve_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
@@ -61,6 +63,7 @@
#include "BIF_glutil.h"
#include "ED_datafiles.h"
+#include "ED_keyframes_draw.h"
#include "ED_render.h"
#include "UI_interface.h"
@@ -273,8 +276,6 @@ static void vicon_x_draw(int x, int y, int w, int h, float alpha)
glVertex2i(x + w, y);
glVertex2i(x, y + h);
glEnd();
-
- glLineWidth(1.0);
glDisable(GL_LINE_SMOOTH);
}
@@ -442,7 +443,6 @@ static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha))
glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
glEnd();
- glLineWidth(1.0);
glDisable(GL_LINE_SMOOTH);
}
@@ -460,10 +460,57 @@ static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha)
glVertex2i(x + w / 2 + d * 2, y + h / 2 + d);
glEnd();
- glLineWidth(1.0);
glDisable(GL_LINE_SMOOTH);
}
+static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type)
+{
+ /* init dummy theme state for Action Editor - where these colors are defined
+ * (since we're doing this offscreen, free from any particular space_id)
+ */
+ struct bThemeState theme_state;
+ int xco, yco;
+
+ UI_Theme_Store(&theme_state);
+ UI_SetTheme(SPACE_ACTION, RGN_TYPE_WINDOW);
+
+ /* the "x" and "y" given are the bottom-left coordinates of the icon,
+ * while the draw_keyframe_shape() function needs the midpoint for
+ * the keyframe
+ */
+ xco = x + w / 2;
+ yco = y + h / 2;
+
+ /* draw keyframe
+ * - xscale: 1.0 (since there's no timeline scaling to compensate for)
+ * - yscale: 0.3 * h (found out experimentally... dunno why!)
+ * - sel: true (so that "keyframe" state shows the iconic yellow icon)
+ */
+ draw_keyframe_shape(xco, yco, 1.0f, 0.3f * h, true, key_type, KEYFRAME_SHAPE_BOTH, alpha);
+
+ UI_Theme_Restore(&theme_state);
+}
+
+static void vicon_keytype_keyframe_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME);
+}
+
+static void vicon_keytype_breakdown_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_BREAKDOWN);
+}
+
+static void vicon_keytype_extreme_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_EXTREME);
+}
+
+static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha)
+{
+ vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER);
+}
+
#ifndef WITH_HEADLESS
static void init_brush_icons(void)
@@ -626,7 +673,7 @@ static void init_internal_icons(void)
}
/* we only use a texture for cards with non-power of two */
- if (GPU_non_power_of_two_support()) {
+ if (GPU_full_non_power_of_two_support()) {
glGenTextures(1, &icongltex.id);
if (icongltex.id) {
@@ -639,12 +686,12 @@ static void init_internal_icons(void)
glBindTexture(GL_TEXTURE_2D, icongltex.id);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, b32buf->x, b32buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b32buf->rect);
- glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, b32buf->x, b32buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b32buf->rect);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect);
while (b16buf->x > 1) {
ImBuf *nbuf = IMB_onehalf(b16buf);
- glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect);
+ glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect);
level++;
IMB_freeImBuf(b16buf);
b16buf = nbuf;
@@ -689,6 +736,11 @@ static void init_internal_icons(void)
def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw);
def_internal_vicon(VICO_X_VEC, vicon_x_draw);
def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
+
+ def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
+ def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
+ def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
+ def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
IMB_freeImBuf(b16buf);
IMB_freeImBuf(b32buf);
@@ -1122,7 +1174,7 @@ static void icon_draw_texture(
y1 = iy * icongltex.invh;
y2 = (iy + ih) * icongltex.invh;
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glBindTexture(GL_TEXTURE_2D, icongltex.id);
/* sharper downscaling, has no effect when scale matches with a mip level */
@@ -1145,7 +1197,7 @@ static void icon_draw_texture(
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f);
glBindTexture(GL_TEXTURE_2D, 0);
- glDisable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
/* Drawing size for preview images */
@@ -1228,12 +1280,7 @@ static void icon_draw_size(
if (!pi->rect[size]) return; /* something has gone wrong! */
/* preview images use premul alpha ... */
- if (GLEW_VERSION_1_4) {
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- }
- else {
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
icon_draw_rect(x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, rgb, is_preview);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1317,15 +1364,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
/* reset the icon */
if (mode == OB_MODE_SCULPT) {
- items = brush_sculpt_tool_items;
+ items = rna_enum_brush_sculpt_tool_items;
tool = br->sculpt_tool;
}
else if (mode == OB_MODE_VERTEX_PAINT) {
- items = brush_vertex_tool_items;
+ items = rna_enum_brush_vertex_tool_items;
tool = br->vertexpaint_tool;
}
else if (mode == OB_MODE_TEXTURE_PAINT) {
- items = brush_image_tool_items;
+ items = rna_enum_brush_image_tool_items;
tool = br->imagepaint_tool;
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 032efad885e..f02aad1ff87 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -42,6 +42,7 @@ struct ARegion;
struct bContext;
struct uiHandleButtonData;
struct wmEvent;
+struct wmKeyConfig;
struct wmOperatorType;
struct wmTimer;
struct uiStyle;
@@ -92,6 +93,7 @@ typedef enum {
/* specials */
UI_WTYPE_ICON,
+ UI_WTYPE_ICON_LABEL,
UI_WTYPE_SWATCH,
UI_WTYPE_RGB_PICKER,
UI_WTYPE_UNITVEC,
@@ -155,14 +157,6 @@ extern const short ui_radial_dir_to_angle[8];
#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y + 4) /* 24 default */
-/* Button text selection:
- * extension direction, selextend, inside ui_do_but_TEX */
-#define EXTEND_LEFT 1
-#define EXTEND_RIGHT 2
-
-/* for scope resize zone */
-#define SCOPE_RESIZE_PAD 9
-
/* bit button defines */
/* Bit operations */
#define UI_BITBUT_TEST(a, b) ( ( (a) & 1 << (b) ) != 0)
@@ -174,6 +168,9 @@ extern const short ui_radial_dir_to_angle[8];
/* split numbuts by ':' and align l/r */
#define USE_NUMBUTS_LR_ALIGN
+/* Use new 'align' computation code. */
+#define USE_UIBUT_SPATIAL_ALIGN
+
/* PieMenuData->flags */
enum {
UI_PIE_DEGREES_RANGE_LARGE = (1 << 0), /* pie menu item collision is detected at 90 degrees */
@@ -187,6 +184,9 @@ enum {
#define PIE_CLICK_THRESHOLD_SQ 50.0f
+/* max amount of items a radial menu (pie menu) can contain */
+#define PIE_MAX_ITEMS 8
+
typedef struct uiLinkLine { /* only for draw/edit */
struct uiLinkLine *next, *prev;
struct uiBut *from, *to;
@@ -230,6 +230,7 @@ struct uiBut {
* (type == UI_BTYPE_SCROLL) Use as scroll size.
* (type == UI_BTYPE_SEARCH_MENU) Use as number or rows.
* (type == UI_BTYPE_COLOR) Use as indication of color palette
+ * (type == UI_BTYPE_PROGRESS_BAR) Use to store progress (0..1).
*/
float a1;
@@ -255,6 +256,7 @@ struct uiBut {
uiButCompleteFunc autocomplete_func;
void *autofunc_arg;
+ uiButSearchCreateFunc search_create_func;
uiButSearchFunc search_func;
void *search_arg;
@@ -286,6 +288,8 @@ struct uiBut {
/* UI_BTYPE_PULLDOWN/UI_BTYPE_MENU data */
uiMenuCreateFunc menu_create_func;
+ uiMenuStepFunc menu_step_func;
+
/* RNA data */
struct PointerRNA rnapoin;
struct PropertyRNA *rnaprop;
@@ -334,6 +338,10 @@ typedef struct ColorPickerData {
} ColorPickerData;
struct PieMenuData {
+ /* store title and icon to allow access when pie levels are created */
+ const char *title;
+ int icon;
+
float pie_dir[2];
float pie_center_init[2];
float pie_center_spawned[2];
@@ -467,6 +475,7 @@ bool ui_but_is_colorpicker_display_space(struct uiBut *but);
extern void ui_but_string_get_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision) ATTR_NONNULL();
extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL();
+extern char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size);
extern void ui_but_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL();
extern bool ui_but_string_set(struct bContext *C, uiBut *but, const char *str) ATTR_NONNULL();
extern bool ui_but_string_set_eval_num(struct bContext *C, uiBut *but, const char *str, double *value) ATTR_NONNULL();
@@ -478,7 +487,9 @@ extern uiButExtraIconType ui_but_icon_extra_get(uiBut *but);
extern void ui_but_default_set(struct bContext *C, const bool all, const bool use_afterfunc);
+extern void ui_but_update_ex(uiBut *but, const bool validate);
extern void ui_but_update(uiBut *but);
+extern void ui_but_update_edited(uiBut *but);
extern bool ui_but_is_float(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_bool(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern bool ui_but_is_unit(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -493,7 +504,6 @@ extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT;
extern void ui_block_bounds_calc(uiBlock *block);
extern void ui_block_translate(uiBlock *block, int x, int y);
-extern void ui_block_align_calc(uiBlock *block);
extern struct ColorManagedDisplay *ui_block_cm_display_get(uiBlock *block);
void ui_block_cm_to_display_space_v3(uiBlock *block, float pixel[3]);
@@ -583,7 +593,8 @@ void ui_color_picker_to_rgb_v(const float r_cp[3], float rgb[3]);
void ui_color_picker_to_rgb(float r_cp0, float r_cp1, float r_cp2, float *r, float *g, float *b);
/* searchbox for string button */
-ARegion *ui_searchbox_create(struct bContext *C, struct ARegion *butregion, uiBut *but);
+ARegion *ui_searchbox_create_generic(struct bContext *C, struct ARegion *butregion, uiBut *but);
+ARegion *ui_searchbox_create_operator(struct bContext *C, struct ARegion *butregion, uiBut *but);
bool ui_searchbox_inside(struct ARegion *ar, int x, int y);
int ui_searchbox_find_index(struct ARegion *ar, const char *name);
void ui_searchbox_update(struct bContext *C, struct ARegion *ar, uiBut *but, const bool reset);
@@ -605,6 +616,10 @@ uiPopupBlockHandle *ui_popup_menu_create(
struct bContext *C, struct ARegion *butregion, uiBut *but,
uiMenuCreateFunc create_func, void *arg);
+void ui_pie_menu_level_create(
+ uiBlock *block, struct wmOperatorType *ot, const char *propname, IDProperty *properties,
+ const EnumPropertyItem *items, int totitem, int context, int flag);
+
void ui_popup_block_free(struct bContext *C, uiPopupBlockHandle *handle);
int ui_but_menu_step(uiBut *but, int step);
@@ -645,12 +660,14 @@ extern int ui_but_menu_direction(uiBut *but);
extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
extern uiBut *ui_but_find_active_in_region(struct ARegion *ar);
+extern uiBut *ui_but_find_mouse_over(struct ARegion *ar, const struct wmEvent *event);
bool ui_but_is_editable(const uiBut *but);
bool ui_but_is_editable_as_text(const uiBut *but);
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]);
+void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip);
void ui_but_clipboard_free(void);
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
@@ -682,6 +699,8 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na
#define UI_TEXT_MARGIN_X 0.4f
#define UI_POPUP_MARGIN (UI_DPI_FAC * 12)
+/* margin at top of screen for popups */
+#define UI_POPUP_MENU_TOP (int)(8 * UI_DPI_FAC)
/* interface_style.c */
void uiStyleInit(void);
@@ -699,11 +718,13 @@ void ui_resources_free(void);
/* interface_layout.c */
void ui_layout_add_but(uiLayout *layout, uiBut *but);
-bool ui_but_can_align(uiBut *but) ATTR_WARN_UNUSED_RESULT;
void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop);
-void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip);
void ui_layout_list_set_labels_active(uiLayout *layout);
+/* interface_align.c */
+bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+void ui_block_align_calc(uiBlock *block);
+
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
void ui_but_anim_insert_keyframe(struct bContext *C);
@@ -721,8 +742,10 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str);
void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, float cfra);
/* interface_eyedropper.c */
+struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
+void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 67b4f183c82..e802cf82b8e 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -720,7 +720,7 @@ void UI_context_active_but_prop_get_filebrowser(
/**
* Update a buttons tip with an enum's description if possible.
*/
-static void ui_but_tip_from_enum_item(uiBut *but, EnumPropertyItem *item)
+static void ui_but_tip_from_enum_item(uiBut *but, const EnumPropertyItem *item)
{
if (but->tip == NULL || but->tip[0] == '\0') {
if (item->description && item->description[0]) {
@@ -883,6 +883,125 @@ void uiItemEnumO(uiLayout *layout, const char *opname, const char *name, int ico
}
+BLI_INLINE bool ui_layout_is_radial(const uiLayout *layout)
+{
+ return (layout->item.type == ITEM_LAYOUT_RADIAL) ||
+ ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
+}
+
+/**
+ * Create ui items for enum items in \a item_array.
+ *
+ * A version of #uiItemsFullEnumO that takes pre-calculated item array.
+ */
+void uiItemsFullEnumO_items(
+ uiLayout *layout, wmOperatorType *ot, PointerRNA ptr, PropertyRNA *prop, IDProperty *properties,
+ int context, int flag,
+ const EnumPropertyItem *item_array, int totitem)
+{
+ const char *propname = RNA_property_identifier(prop);
+ if (RNA_property_type(prop) != PROP_ENUM) {
+ RNA_warning("%s.%s, not an enum type", RNA_struct_identifier(ptr.type), propname);
+ return;
+ }
+
+ uiLayout *target, *split = NULL;
+ const EnumPropertyItem *item;
+ uiBlock *block = layout->root->block;
+ const bool radial = ui_layout_is_radial(layout);
+
+ if (radial) {
+ target = uiLayoutRadial(layout);
+ }
+ else {
+ split = uiLayoutSplit(layout, 0.0f, false);
+ target = uiLayoutColumn(split, layout->align);
+ }
+
+
+ int i;
+ bool last_iter = false;
+
+ for (i = 1, item = item_array; item->identifier && !last_iter; i++, item++) {
+ /* handle oversized pies */
+ if (radial && (totitem > PIE_MAX_ITEMS) && (i >= PIE_MAX_ITEMS)) {
+ if (item->name) { /* only visible items */
+ const EnumPropertyItem *tmp;
+
+ /* Check if there are more visible items for the next level. If not, we don't
+ * add a new level and add the remaining item instead of the 'more' button. */
+ for (tmp = item + 1; tmp->identifier; tmp++)
+ if (tmp->name)
+ break;
+
+ if (tmp->identifier) { /* only true if loop above found item and did early-exit */
+ ui_pie_menu_level_create(block, ot, propname, properties, item_array, totitem, context, flag);
+ /* break since rest of items is handled in new pie level */
+ break;
+ }
+ else {
+ last_iter = true;
+ }
+ }
+ else {
+ continue;
+ }
+ }
+
+ if (item->identifier[0]) {
+ PointerRNA tptr;
+
+ WM_operator_properties_create_ptr(&tptr, ot);
+ if (properties) {
+ if (tptr.data) {
+ IDP_FreeProperty(tptr.data);
+ MEM_freeN(tptr.data);
+ }
+ tptr.data = IDP_CopyProperty(properties);
+ }
+ RNA_property_enum_set(&tptr, prop, item->value);
+
+ uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag);
+
+ ui_but_tip_from_enum_item(block->buttons.last, item);
+ }
+ else {
+ if (item->name) {
+ uiBut *but;
+
+ if (item != item_array && !radial) {
+ target = uiLayoutColumn(split, layout->align);
+
+ /* inconsistent, but menus with labels do not look good flipped */
+ block->flag |= UI_BLOCK_NO_FLIP;
+ }
+
+ if (item->icon || radial) {
+ uiItemL(target, item->name, item->icon);
+
+ but = block->buttons.last;
+ }
+ else {
+ /* Do not use uiItemL here, as our root layout is a menu one, it will add a fake blank icon! */
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL,
+ 0.0, 0.0, 0, 0, "");
+ }
+ ui_but_tip_from_enum_item(but, item);
+ }
+ else {
+ if (radial) {
+ /* invisible dummy button to ensure all items are always at the same position */
+ uiItemS(target);
+ }
+ else {
+ /* XXX bug here, colums draw bottom item badly */
+ uiItemS(target);
+ }
+ }
+ }
+ }
+}
+
void uiItemsFullEnumO(
uiLayout *layout, const char *opname, const char *propname, IDProperty *properties,
int context, int flag)
@@ -892,8 +1011,6 @@ void uiItemsFullEnumO(
PointerRNA ptr;
PropertyRNA *prop;
uiBlock *block = layout->root->block;
- const bool radial = (layout->item.type == ITEM_LAYOUT_RADIAL) ||
- ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
if (!ot || !ot->srna) {
ui_item_disabled(layout, opname);
@@ -910,78 +1027,22 @@ void uiItemsFullEnumO(
BLI_assert((prop == NULL) || (RNA_property_type(prop) == PROP_ENUM));
if (prop && RNA_property_type(prop) == PROP_ENUM) {
- EnumPropertyItem *item, *item_array = NULL;
+ EnumPropertyItem *item_array = NULL;
+ int totitem;
bool free;
- uiLayout *split = NULL;
- uiLayout *target;
- if (radial) {
- target = uiLayoutRadial(layout);
+ if (ui_layout_is_radial(layout)) {
+ RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
}
else {
- split = uiLayoutSplit(layout, 0.0f, false);
- target = uiLayoutColumn(split, layout->align);
+ RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free);
}
- if (radial) {
- RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, NULL, &free);
- }
- else {
- RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
- }
-
- for (item = item_array; item->identifier; item++) {
- if (item->identifier[0]) {
- PointerRNA tptr;
-
- WM_operator_properties_create_ptr(&tptr, ot);
- if (properties) {
- if (tptr.data) {
- IDP_FreeProperty(tptr.data);
- MEM_freeN(tptr.data);
- }
- tptr.data = IDP_CopyProperty(properties);
- }
- RNA_property_enum_set(&tptr, prop, item->value);
-
- uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag);
+ /* add items */
+ uiItemsFullEnumO_items(
+ layout, ot, ptr, prop, properties, context, flag,
+ item_array, totitem);
- ui_but_tip_from_enum_item(block->buttons.last, item);
- }
- else {
- if (item->name) {
- uiBut *but;
-
- if (item != item_array && !radial) {
- target = uiLayoutColumn(split, layout->align);
-
- /* inconsistent, but menus with labels do not look good flipped */
- block->flag |= UI_BLOCK_NO_FLIP;
- }
-
- if (item->icon || radial) {
- uiItemL(target, item->name, item->icon);
-
- but = block->buttons.last;
- }
- else {
- /* Do not use uiItemL here, as our root layout is a menu one, it will add a fake blank icon! */
- but = uiDefBut(block, UI_BTYPE_LABEL, 0, item->name, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, NULL,
- 0.0, 0.0, 0, 0, "");
- }
- ui_but_tip_from_enum_item(but, item);
- }
- else {
- if (radial) {
- uiItemS(target);
- }
- else {
- /* XXX bug here, colums draw bottom item badly */
- uiItemS(target);
- }
- }
- }
- }
if (free) {
MEM_freeN(item_array);
}
@@ -1513,7 +1574,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, const char *s
#if 0 /* this name is used for a string comparison and can't be modified, TODO */
/* if ever enabled, make name_ui be MAX_ID_NAME+1 */
- name_uiprefix_id(name_ui, id);
+ BKE_id_ui_prefix(name_ui, id);
#else
BLI_strncpy(name_ui, id->name + 2, sizeof(name_ui));
#endif
@@ -1611,7 +1672,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
but->str[0] = 0;
}
- UI_but_func_search_set(but, rna_search_cb, but, NULL, NULL);
+ UI_but_func_search_set(but, ui_searchbox_create_generic, rna_search_cb, but, NULL, NULL);
}
}
@@ -2167,9 +2228,9 @@ static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
{
RadialDirection dir;
- if (itemnum >= 8) {
- itemnum %= 8;
- printf("Warning: Pie menus with more than 8 items are currently unsupported\n");
+ if (itemnum >= PIE_MAX_ITEMS) {
+ itemnum %= PIE_MAX_ITEMS;
+ printf("Warning: Pie menus with more than %i items are currently unsupported\n", PIE_MAX_ITEMS);
}
dir = ui_radial_dir_order[itemnum];
@@ -2203,7 +2264,6 @@ static void ui_litem_layout_radial(uiLayout *litem)
int itemnum = 0;
int totitems = 0;
- int minx, miny, maxx, maxy;
/* For the radial layout we will use Matt Ebb's design
* for radiation, see http://mattebb.com/weblog/radiation/
* also the old code at http://developer.blender.org/T5103
@@ -2214,7 +2274,7 @@ static void ui_litem_layout_radial(uiLayout *litem)
x = litem->x;
y = litem->y;
- minx = x, miny = y, maxx = x, maxy = y;
+ int minx = x, miny = y, maxx = x, maxy = y;
/* first count total items */
for (item = litem->items.first; item; item = item->next)
@@ -3012,9 +3072,14 @@ static void ui_item_align(uiLayout *litem, short nr)
for (item = litem->items.last; item; item = item->prev) {
if (item->type == ITEM_BUTTON) {
bitem = (uiButtonItem *)item;
+#ifndef USE_UIBUT_SPATIAL_ALIGN
if (ui_but_can_align(bitem->but))
- if (!bitem->but->alignnr)
+#endif
+ {
+ if (!bitem->but->alignnr) {
bitem->but->alignnr = nr;
+ }
+ }
}
else if (item->type == ITEM_LAYOUT_ABSOLUTE) {
/* pass */
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 6ac657fa7a3..7a9c3e827cf 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -151,6 +151,53 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
+static int copy_python_command_button_poll(bContext *C)
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but && (but->optype != NULL)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but && (but->optype != NULL)) {
+ PointerRNA *opptr;
+ char *str;
+ opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */
+
+ str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr);
+
+ WM_clipboard_text_set(str, 0);
+
+ MEM_freeN(str);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static void UI_OT_copy_python_command_button(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Python Command";
+ ot->idname = "UI_OT_copy_python_command_button";
+ ot->description = "Copy the Python command matching this button";
+
+ /* callbacks */
+ ot->exec = copy_python_command_button_exec;
+ ot->poll = copy_python_command_button_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
/* Reset to Default Values Button Operator ------------------------ */
static int operator_button_property_finish(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
@@ -358,7 +405,7 @@ bool UI_context_copy_to_selected_list(
Object *ob = link->ptr.id.data;
if (ob->data) {
ID *id_data = ob->data;
- id_data->flag |= LIB_DOIT;
+ id_data->tag |= LIB_TAG_DOIT;
}
}
@@ -368,7 +415,7 @@ bool UI_context_copy_to_selected_list(
link_next = link->next;
if ((id_data == NULL) ||
- (id_data->flag & LIB_DOIT) == 0 ||
+ (id_data->tag & LIB_TAG_DOIT) == 0 ||
(id_data->lib) ||
(GS(id_data->name) != id_code))
{
@@ -381,7 +428,7 @@ bool UI_context_copy_to_selected_list(
}
if (id_data) {
- id_data->flag &= ~LIB_DOIT;
+ id_data->tag &= ~LIB_TAG_DOIT;
}
}
}
@@ -510,7 +557,7 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
+ RNA_def_boolean(ot->srna, "all", true, "All", "Copy to selected all elements of the array");
}
/* Reports to Textblock Operator ------------------------ */
@@ -1040,10 +1087,11 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/* ********************************************************* */
/* Registration */
-void ED_button_operatortypes(void)
+void ED_operatortypes_ui(void)
{
WM_operatortype_append(UI_OT_reset_default_theme);
WM_operatortype_append(UI_OT_copy_data_path_button);
+ WM_operatortype_append(UI_OT_copy_python_command_button);
WM_operatortype_append(UI_OT_reset_default_button);
WM_operatortype_append(UI_OT_unset_property_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
@@ -1059,4 +1107,17 @@ void ED_button_operatortypes(void)
WM_operatortype_append(UI_OT_eyedropper_color);
WM_operatortype_append(UI_OT_eyedropper_id);
WM_operatortype_append(UI_OT_eyedropper_depth);
+ WM_operatortype_append(UI_OT_eyedropper_driver);
+}
+
+/**
+ * \brief User Interface Keymap
+ *
+ * For now only modal maps here, since UI uses special ui-handlers instead of operators.
+ */
+void ED_keymap_ui(wmKeyConfig *keyconf)
+{
+ WM_keymap_find(keyconf, "User Interface", 0, 0);
+
+ eyedropper_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 5ee7556a042..2fdd84b626b 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -452,8 +452,6 @@ static void ui_draw_anti_x(float x1, float y1, float x2, float y2)
fdrawline(x1, y1, x2, y2);
fdrawline(x1, y2, x2, y1);
- glLineWidth(1.0);
-
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -1475,6 +1473,7 @@ void UI_panel_category_active_set(ARegion *ar, const char *idname)
pc_act_next = pc_act->next;
if (!BLI_findstring(&ar->type->paneltypes, pc_act->idname, offsetof(PanelType, category))) {
BLI_remlink(lb, pc_act);
+ MEM_freeN(pc_act);
}
}
}
@@ -1648,7 +1647,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* Secondary theme colors */
unsigned char theme_col_tab_outline[3];
- unsigned char theme_col_tab_divider[3]; /* line that divides tabs from the main area */
+ unsigned char theme_col_tab_divider[3]; /* line that divides tabs from the main region */
unsigned char theme_col_tab_highlight[3];
unsigned char theme_col_tab_highlight_inactive[3];
@@ -1761,7 +1760,6 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
/* tab outline */
glColor3ubv(theme_col_tab_outline);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin - px, rct->ymin - px, rct->xmax - px, rct->ymax + px,
tab_curve_radius, roundboxtype, true, true, NULL);
/* tab highlight (3d look) */
@@ -1771,8 +1769,6 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
tab_curve_radius, roundboxtype, true, false,
is_active ? theme_col_back : theme_col_tab_inactive);
glShadeModel(GL_FLAT);
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
/* tab blackline */
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 0b586dd9fca..b3972bebd96 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -70,7 +70,6 @@
#include "interface_intern.h"
-#define MENU_TOP (int)(8 * UI_DPI_FAC)
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
#define MENU_BORDER (int)(0.3f * U.widget_unit)
@@ -112,13 +111,19 @@ bool ui_but_menu_step_poll(const uiBut *but)
BLI_assert(but->type == UI_BTYPE_MENU);
/* currenly only RNA buttons */
- return (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM);
+ return ((but->menu_step_func != NULL) ||
+ (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM));
}
int ui_but_menu_step(uiBut *but, int direction)
{
if (ui_but_menu_step_poll(but)) {
- return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
+ if (but->menu_step_func) {
+ return but->menu_step_func(but->block->evil_C, direction, but->poin);
+ }
+ else {
+ return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
+ }
}
printf("%s: cannot cycle button '%s'\n", __func__, but->str);
@@ -233,11 +238,11 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
int i, multisample_enabled;
/* disable AA, makes widgets too blurry */
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB);
+ multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
if (multisample_enabled)
- glDisable(GL_MULTISAMPLE_ARB);
+ glDisable(GL_MULTISAMPLE);
- wmOrtho2_region_ui(ar);
+ wmOrtho2_region_pixelspace(ar);
/* draw background */
ui_draw_tooltip_background(UI_style_get(), NULL, &bbox);
@@ -337,7 +342,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
BLF_disable(blf_mono_font, BLF_WORD_WRAP);
if (multisample_enabled)
- glEnable(GL_MULTISAMPLE_ARB);
+ glEnable(GL_MULTISAMPLE);
}
static void ui_tooltip_region_free_cb(ARegion *ar)
@@ -349,24 +354,8 @@ static void ui_tooltip_region_free_cb(ARegion *ar)
ar->regiondata = NULL;
}
-ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
+static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
{
- const float pad_px = UI_TIP_PADDING;
- wmWindow *win = CTX_wm_window(C);
- uiStyle *style = UI_style_get();
- static ARegionType type;
- ARegion *ar;
- uiTooltipData *data;
-/* IDProperty *prop;*/
- char buf[512];
- /* aspect values that shrink text are likely unreadable */
- const float aspect = min_ff(1.0f, but->block->aspect);
- int fonth, fontw;
- int winx, ofsx, ofsy, h, i;
- rctf rect_fl;
- rcti rect_i;
- int font_flag = 0;
-
uiStringInfo but_tip = {BUT_GET_TIP, NULL};
uiStringInfo enum_label = {BUT_GET_RNAENUM_LABEL, NULL};
uiStringInfo enum_tip = {BUT_GET_RNAENUM_TIP, NULL};
@@ -375,11 +364,10 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
uiStringInfo rna_struct = {BUT_GET_RNASTRUCT_IDENTIFIER, NULL};
uiStringInfo rna_prop = {BUT_GET_RNAPROP_IDENTIFIER, NULL};
- if (but->drawflag & UI_BUT_NO_TOOLTIP)
- return NULL;
+ char buf[512];
/* create tooltip data */
- data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
+ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
UI_but_string_info_get(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &prop_keymap, &rna_struct, &rna_prop, NULL);
@@ -529,33 +517,18 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
if (but->rnapoin.id.data) {
/* this could get its own 'BUT_GET_...' type */
- PointerRNA *ptr = &but->rnapoin;
- PropertyRNA *prop = but->rnaprop;
- ID *id = ptr->id.data;
-
- char *id_path;
- char *data_path = NULL;
/* never fails */
- id_path = RNA_path_full_ID_py(id);
-
- if (ptr->data && prop) {
- data_path = RNA_path_from_ID_to_property(ptr, prop);
- }
+ char *id_path;
- if (data_path) {
- const char *data_delim = (data_path[0] == '[') ? "" : ".";
- BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]),
- "%s%s%s", /* no need to translate */
- id_path, data_delim, data_path);
- MEM_freeN(data_path);
+ if (but->rnaprop) {
+ id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true);
}
- else if (prop) {
- /* can't find the path. be explicit in our ignorance "..." */
- BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]),
- "%s ... %s", /* no need to translate */
- id_path, rna_prop.strinfo ? rna_prop.strinfo : RNA_property_identifier(prop));
+ else {
+ id_path = RNA_path_full_struct_py(&but->rnapoin);
}
+
+ BLI_strncat_utf8(data->lines[data->totline], id_path, sizeof(data->lines[0]));
MEM_freeN(id_path);
data->format[data->totline].style = UI_TIP_STYLE_MONO;
@@ -586,6 +559,36 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
MEM_freeN(data);
return NULL;
}
+ else {
+ return data;
+ }
+}
+
+ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
+{
+ const float pad_px = UI_TIP_PADDING;
+ wmWindow *win = CTX_wm_window(C);
+ const int winx = WM_window_pixels_x(win);
+ uiStyle *style = UI_style_get();
+ static ARegionType type;
+ ARegion *ar;
+/* IDProperty *prop;*/
+ /* aspect values that shrink text are likely unreadable */
+ const float aspect = min_ff(1.0f, but->block->aspect);
+ int fonth, fontw;
+ int ofsx, ofsy, h, i;
+ rctf rect_fl;
+ rcti rect_i;
+ int font_flag = 0;
+
+ if (but->drawflag & UI_BUT_NO_TOOLTIP) {
+ return NULL;
+ }
+
+ uiTooltipData *data = ui_tooltip_data_from_button(C, but);
+ if (data == NULL) {
+ return NULL;
+ }
/* create area region */
ar = ui_region_temp_add(CTX_wm_screen(C));
@@ -602,7 +605,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
UI_fontstyle_set(&data->fstyle);
- data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, WM_window_pixels_x(win) - (UI_TIP_PADDING * 2));
+ data->wrap_width = min_ii(UI_TIP_MAXWIDTH * U.pixelsize / aspect, winx - (UI_TIP_PADDING * 2));
font_flag |= BLF_WORD_WRAP;
if (data->fstyle.kerning == 1) {
@@ -625,8 +628,9 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
if (data->format[i].style == UI_TIP_STYLE_HEADER) {
w = BLF_width_ex(data->fstyle.uifont_id, data->header, sizeof(data->header), &info);
- if (enum_label.strinfo) {
- x_pos = info.width + (U.widget_unit / 2);
+ /* check for enum label */
+ if (data->active_info[0]) {
+ x_pos = info.width;
w = max_ii(w, x_pos + BLF_width(data->fstyle.uifont_id, data->active_info, sizeof(data->active_info)));
}
}
@@ -694,8 +698,6 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
#undef TIP_BORDER_Y
/* clip with window boundaries */
- winx = WM_window_pixels_x(win);
-
if (rect_i.xmax > winx) {
/* super size */
if (rect_i.xmax > winx + rect_i.xmin) {
@@ -822,12 +824,12 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int
int UI_searchbox_size_y(void)
{
- return SEARCH_ITEMS * UI_UNIT_Y + 2 * MENU_TOP;
+ return SEARCH_ITEMS * UI_UNIT_Y + 2 * UI_POPUP_MENU_TOP;
}
int UI_searchbox_size_x(void)
{
- return 12 * UI_UNIT_X;
+ return 10 * UI_UNIT_X;
}
int UI_search_items_find_index(uiSearchItems *items, const char *name)
@@ -898,13 +900,13 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr
}
/* list view */
else {
- int buth = (BLI_rcti_size_y(&data->bbox) - 2 * MENU_TOP) / SEARCH_ITEMS;
+ int buth = (BLI_rcti_size_y(&data->bbox) - 2 * UI_POPUP_MENU_TOP) / SEARCH_ITEMS;
*r_rect = data->bbox;
r_rect->xmin = data->bbox.xmin + 3.0f;
r_rect->xmax = data->bbox.xmax - 3.0f;
- r_rect->ymax = data->bbox.ymax - MENU_TOP - itemnr * buth;
+ r_rect->ymax = data->bbox.ymax - UI_POPUP_MENU_TOP - itemnr * buth;
r_rect->ymin = r_rect->ymax - buth;
}
@@ -1083,7 +1085,7 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
uiSearchboxData *data = ar->regiondata;
/* pixel space */
- wmOrtho2_region_ui(ar);
+ wmOrtho2_region_pixelspace(ar);
if (data->noback == false)
ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */
@@ -1162,7 +1164,7 @@ static void ui_searchbox_region_free_cb(ARegion *ar)
ar->regiondata = NULL;
}
-ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
+ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but)
{
wmWindow *win = CTX_wm_window(C);
uiStyle *style = UI_style_get();
@@ -1326,6 +1328,110 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
return ar;
}
+/**
+ * Similar to Python's `str.title` except...
+ *
+ * - we know words are upper case and ascii only.
+ * - '_' are replaces by spaces.
+ */
+static void str_tolower_titlecaps_ascii(char *str, const size_t len)
+{
+ size_t i;
+ bool prev_delim = true;
+
+ for (i = 0; (i < len) && str[i]; i++) {
+ if (str[i] >= 'A' && str[i] <= 'Z') {
+ if (prev_delim == false) {
+ str[i] += 'a' - 'A';
+ }
+ }
+ else if (str[i] == '_') {
+ str[i] = ' ';
+ }
+
+ prev_delim = ELEM(str[i], ' ') || (str[i] >= '0' && str[i] <= '9');
+ }
+
+}
+
+static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *ar)
+{
+ uiSearchboxData *data = ar->regiondata;
+
+ /* pixel space */
+ wmOrtho2_region_pixelspace(ar);
+
+ if (data->noback == false)
+ ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */
+
+ /* draw text */
+ if (data->items.totitem) {
+ rcti rect;
+ int a;
+
+ /* draw items */
+ for (a = 0; a < data->items.totitem; a++) {
+ rcti rect_pre, rect_post;
+ ui_searchbox_butrect(&rect, data, a);
+
+ rect_pre = rect;
+ rect_post = rect;
+
+ rect_pre.xmax = rect_post.xmin = rect.xmin + ((rect.xmax - rect.xmin) / 4);
+
+ /* widget itself */
+ {
+ wmOperatorType *ot = data->items.pointers[a];
+
+ int state = (a == data->active) ? UI_ACTIVE : 0;
+ char text_pre[128];
+ char *text_pre_p = strstr(ot->idname, "_OT_");
+ if (text_pre_p == NULL) {
+ text_pre[0] = '\0';
+ }
+ else {
+ int text_pre_len;
+ text_pre_p += 1;
+ text_pre_len = BLI_strncpy_rlen(
+ text_pre, ot->idname, min_ii(sizeof(text_pre), text_pre_p - ot->idname));
+ text_pre[text_pre_len] = ':';
+ text_pre[text_pre_len + 1] = '\0';
+ str_tolower_titlecaps_ascii(text_pre, sizeof(text_pre));
+ }
+
+ rect_pre.xmax += 4; /* sneaky, avoid showing ugly margin */
+ ui_draw_menu_item(&data->fstyle, &rect_pre, text_pre, data->items.icons[a], state, false);
+ ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep);
+ }
+
+ }
+ /* indicate more */
+ if (data->items.more) {
+ ui_searchbox_butrect(&rect, data, data->items.maxitem - 1);
+ glEnable(GL_BLEND);
+ UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymin - 9, ICON_TRIA_DOWN);
+ glDisable(GL_BLEND);
+ }
+ if (data->items.offset) {
+ ui_searchbox_butrect(&rect, data, 0);
+ glEnable(GL_BLEND);
+ UI_icon_draw((BLI_rcti_size_x(&rect)) / 2, rect.ymax - 7, ICON_TRIA_UP);
+ glDisable(GL_BLEND);
+ }
+ }
+}
+
+ARegion *ui_searchbox_create_operator(bContext *C, ARegion *butregion, uiBut *but)
+{
+ ARegion *ar;
+
+ ar = ui_searchbox_create_generic(C, butregion, but);
+
+ ar->type->draw = ui_searchbox_region_draw_cb__operator;
+
+ return ar;
+}
+
void ui_searchbox_free(bContext *C, ARegion *ar)
{
ui_region_temp_remove(C, CTX_wm_screen(C), ar);
@@ -1515,7 +1621,8 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
// yof = ysize; (not with menu scrolls)
}
}
-
+
+#if 0 /* seems redundant and causes issues with blocks inside big regions */
/* or no space left or right */
if (left == 0 && right == 0) {
if (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN) {
@@ -1523,7 +1630,8 @@ static void ui_block_position(wmWindow *window, ARegion *butregion, uiBut *but,
xof = -block->rect.xmin + 5;
}
}
-
+#endif
+
#if 0
/* clamp to window bounds, could be made into an option if its ever annoying */
if ( (offscreen = (block->rect.ymin + yof)) < 0) yof -= offscreen; /* bottom */
@@ -1630,8 +1738,8 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
if (block->rect.ymin < width)
block->rect.ymin = width;
- if (block->rect.ymax > winy - MENU_TOP)
- block->rect.ymax = winy - MENU_TOP;
+ if (block->rect.ymax > winy - UI_POPUP_MENU_TOP)
+ block->rect.ymax = winy - UI_POPUP_MENU_TOP;
/* ensure menu items draw inside left/right boundary */
for (bt = block->buttons.first; bt; bt = bt->next) {
@@ -1680,10 +1788,20 @@ void ui_popup_block_scrolltest(uiBlock *block)
static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
- ui_region_temp_remove(C, CTX_wm_screen(C), handle->region);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *sc = CTX_wm_screen(C);
+
+ ui_region_temp_remove(C, sc, handle->region);
+
+ /* reset to region cursor (only if there's not another menu open) */
+ if (BLI_listbase_is_empty(&sc->regionbase)) {
+ ED_region_cursor_set(win, CTX_wm_area(C), CTX_wm_region(C));
+ /* in case cursor needs to be changed again */
+ WM_event_add_mousemove(C);
+ }
if (handle->scrolltimer)
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), handle->scrolltimer);
+ WM_event_remove_timer(CTX_wm_manager(C), win, handle->scrolltimer);
}
/**
@@ -1760,7 +1878,6 @@ uiBlock *ui_popup_block_refresh(
}
if (block->flag & UI_BLOCK_RADIAL) {
- uiBut *but;
int win_width = UI_SCREEN_MARGIN;
int winx, winy;
@@ -1802,9 +1919,9 @@ uiBlock *ui_popup_block_refresh(
/* lastly set the buttons at the center of the pie menu, ready for animation */
if (U.pie_animation_timeout > 0) {
- for (but = block->buttons.first; but; but = but->next) {
- if (but->pie_dir != UI_RADIAL_NONE) {
- BLI_rctf_recenter(&but->rect, UNPACK2(block->pie_data.pie_center_spawned));
+ for (uiBut *but_iter = block->buttons.first; but_iter; but_iter = but_iter->next) {
+ if (but_iter->pie_dir != UI_RADIAL_NONE) {
+ BLI_rctf_recenter(&but_iter->rect, UNPACK2(block->pie_data.pie_center_spawned));
}
}
}
@@ -1818,7 +1935,7 @@ uiBlock *ui_popup_block_refresh(
ar->winrct.xmin = block->rect.xmin - margin;
ar->winrct.xmax = block->rect.xmax + margin;
ar->winrct.ymin = block->rect.ymin - margin;
- ar->winrct.ymax = block->rect.ymax + MENU_TOP;
+ ar->winrct.ymax = block->rect.ymax + UI_POPUP_MENU_TOP;
ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
}
@@ -1858,11 +1975,19 @@ uiPopupBlockHandle *ui_popup_block_create(
void *arg)
{
wmWindow *window = CTX_wm_window(C);
+ uiBut *activebut = UI_context_active_but_get(C);
static ARegionType type;
ARegion *ar;
uiBlock *block;
uiPopupBlockHandle *handle;
+ /* disable tooltips from buttons below */
+ if (activebut) {
+ UI_but_tooltip_timer_remove(C, activebut);
+ }
+ /* standard cursor by default */
+ WM_cursor_set(window, CURSOR_STD);
+
/* create handle */
handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
@@ -2839,6 +2964,8 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co
}
/* do not align left */
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+ pie->block_radial->pie_data.title = but->str;
+ pie->block_radial->pie_data.icon = icon;
}
return pie;
@@ -2950,6 +3077,101 @@ int UI_pie_menu_invoke_from_rna_enum(
return OPERATOR_INTERFACE;
}
+/**
+ * \name Pie Menu Levels
+ *
+ * Pie menus can't contain more than 8 items (yet). When using #uiItemsFullEnumO, a "More" button is created that calls
+ * a new pie menu if the enum has too many items. We call this a new "level".
+ * Indirect recursion is used, so that a theoretically unlimited number of items is supported.
+ *
+ * This is a implementation specifically for operator enums, needed since the object mode pie now has more than 8
+ * items. Ideally we'd have some way of handling this for all kinds of pie items, but that's tricky.
+ *
+ * - Julian (Feb 2016)
+ *
+ * \{ */
+
+typedef struct PieMenuLevelData {
+ char title[UI_MAX_NAME_STR]; /* parent pie title, copied for level */
+ int icon; /* parent pie icon, copied for level */
+ int totitem; /* total count of *remaining* items */
+
+ /* needed for calling uiItemsFullEnumO_array again for new level */
+ wmOperatorType *ot;
+ const char *propname;
+ IDProperty *properties;
+ int context, flag;
+} PieMenuLevelData;
+
+/**
+ * Invokes a new pie menu for a new level.
+ */
+static void ui_pie_menu_level_invoke(bContext *C, void *argN, void *arg2)
+{
+ EnumPropertyItem *item_array = (EnumPropertyItem *)argN;
+ PieMenuLevelData *lvl = (PieMenuLevelData *)arg2;
+ wmWindow *win = CTX_wm_window(C);
+
+ uiPieMenu *pie = UI_pie_menu_begin(C, IFACE_(lvl->title), lvl->icon, win->eventstate);
+ uiLayout *layout = UI_pie_menu_layout(pie);
+
+ layout = uiLayoutRadial(layout);
+
+ PointerRNA ptr;
+
+ WM_operator_properties_create_ptr(&ptr, lvl->ot);
+ /* so the context is passed to itemf functions (some need it) */
+ WM_operator_properties_sanitize(&ptr, false);
+ PropertyRNA *prop = RNA_struct_find_property(&ptr, lvl->propname);
+
+ if (prop) {
+ uiItemsFullEnumO_items(
+ layout, lvl->ot, ptr, prop, lvl->properties, lvl->context, lvl->flag,
+ item_array, lvl->totitem);
+ }
+ else {
+ RNA_warning("%s.%s not found", RNA_struct_identifier(ptr.type), lvl->propname);
+ }
+
+ UI_pie_menu_end(C, pie);
+}
+
+/**
+ * Set up data for defining a new pie menu level and add button that invokes it.
+ */
+void ui_pie_menu_level_create(
+ uiBlock *block, wmOperatorType *ot, const char *propname, IDProperty *properties,
+ const EnumPropertyItem *items, int totitem, int context, int flag)
+{
+ const int totitem_parent = PIE_MAX_ITEMS - 1;
+ const int totitem_remain = totitem - totitem_parent;
+ size_t array_size = sizeof(EnumPropertyItem) * totitem_remain;
+
+ /* used as but->func_argN so freeing is handled elsewhere */
+ EnumPropertyItem *remaining = MEM_mallocN(array_size + sizeof(EnumPropertyItem), "pie_level_item_array");
+ memcpy(remaining, items + totitem_parent, array_size);
+ /* a NULL terminating sentinal element is required */
+ memset(&remaining[totitem_remain], 0, sizeof(EnumPropertyItem));
+
+
+ /* yuk, static... issue is we can't reliably free this without doing dangerous changes */
+ static PieMenuLevelData lvl;
+ BLI_strncpy(lvl.title, block->pie_data.title, UI_MAX_NAME_STR);
+ lvl.totitem = totitem_remain;
+ lvl.ot = ot;
+ lvl.propname = propname;
+ lvl.properties = properties;
+ lvl.context = context;
+ lvl.flag = flag;
+
+ /* add a 'more' menu entry */
+ uiBut *but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_PLUS, "More", 0, 0, UI_UNIT_X * 3, UI_UNIT_Y, NULL,
+ 0.0f, 0.0f, 0.0f, 0.0f, "Show more items of this menu");
+ UI_but_funcN_set(but, ui_pie_menu_level_invoke, remaining, &lvl);
+}
+
+/** \} */ /* Pie Menu Levels */
+
/*************************** Standard Popup Menus ****************************/
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 25a187c43ad..bfde02dbefd 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -410,6 +410,11 @@ void uiStyleInit(void)
BLF_unload_id(font->blf_id);
}
+ if (blf_mono_font != -1) {
+ BLF_unload_id(blf_mono_font);
+ blf_mono_font = -1;
+ }
+
font = U.uifonts.first;
/* default builtin */
@@ -496,16 +501,16 @@ void uiStyleInit(void)
monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf;
}
}
-
- /* reload */
- BLF_unload("monospace");
- blf_mono_font = -1;
- blf_mono_font_render = -1;
#endif
/* XXX, this should be moved into a style, but for now best only load the monospaced font once. */
- if (blf_mono_font == -1)
+ BLI_assert(blf_mono_font == -1);
+ if (U.font_path_ui_mono[0]) {
+ blf_mono_font = BLF_load_unique(U.font_path_ui_mono);
+ }
+ if (blf_mono_font == -1) {
blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size);
+ }
BLF_size(blf_mono_font, 12 * U.pixelsize, 72);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 44e130ed896..a47d60812b4 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -25,6 +25,7 @@
*/
+#include <ctype.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
@@ -39,12 +40,14 @@
#include "DNA_texture_types.h"
#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
#include "BLI_rect.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_fnmatch.h"
+#include "BLI_timecode.h"
#include "BLF_api.h"
#include "BLT_translation.h"
@@ -81,6 +84,8 @@
#include "UI_interface_icons.h"
#include "interface_intern.h"
+#include "PIL_time.h"
+
void UI_template_fix_linking(void)
{
}
@@ -148,11 +153,11 @@ static void id_search_cb(const bContext *C, void *arg_template, const char *str,
continue;
if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) {
- /* +1 is needed because name_uiprefix_id used 3 letter prefix
+ /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
* followed by ID_NAME-2 characters from id->name
*/
char name_ui[MAX_ID_NAME + 1];
- name_uiprefix_id(name_ui, id);
+ BKE_id_ui_prefix(name_ui, id);
iconid = ui_id_icon_get(C, id, template->preview);
@@ -194,7 +199,9 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, w, UI_UNIT_Y,
template.prv_rows, template.prv_cols, "");
- UI_but_func_search_set(but, id_search_cb, &template, id_search_call_cb, idptr.data);
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, id_search_cb,
+ &template, id_search_call_cb, idptr.data);
}
/* list view */
else {
@@ -204,7 +211,9 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, searchbox_width, searchbox_height, NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, searchbox_width, UI_UNIT_Y - 1, 0, 0, "");
- UI_but_func_search_set(but, id_search_cb, &template, id_search_call_cb, idptr.data);
+ UI_but_func_search_set(
+ but, ui_searchbox_create_generic, id_search_cb,
+ &template, id_search_call_cb, idptr.data);
}
@@ -275,7 +284,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id && CTX_wm_window(C)->eventstate->shift) {
/* only way to force-remove data (on save) */
- id->flag &= ~LIB_FAKEUSER;
+ id_fake_user_clear(id);
id->us = 0;
}
@@ -436,7 +445,7 @@ static void template_ID(
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib) {
- if (id->flag & LIB_INDIRECT) {
+ if (id->tag & LIB_TAG_INDIRECT) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_INDIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Indirect library datablock, cannot change"));
UI_but_flag_enable(but, UI_BUT_DISABLED);
@@ -1636,7 +1645,7 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
h = UI_UNIT_X * (args.icon_scale + args.show_labels);
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS_PULLDOWN);
- UI_block_flag_enable(block, UI_BLOCK_LOOP);
+ UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_NO_FLIP);
RNA_property_enum_items(C, &args.ptr, args.prop, &item, NULL, &free);
@@ -1644,7 +1653,7 @@ static uiBlock *ui_icon_view_menu_cb(bContext *C, ARegion *ar, void *arg_litem)
int x, y;
x = (a % 8) * w;
- y = (a / 8) * h;
+ y = -(a / 8) * h;
icon = item[a].icon;
value = item[a].value;
@@ -1969,26 +1978,42 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
ED_region_tag_redraw(CTX_wm_region(C));
}
-static uiBlock *curvemap_tools_posslope_func(bContext *C, ARegion *ar, void *cumap_v)
+static uiBlock *curvemap_tools_func(
+ bContext *C, ARegion *ar, CurveMapping *cumap,
+ bool show_extend, int reset_mode)
{
uiBlock *block;
short yco = 0, menuwidth = 10 * UI_UNIT_X;
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
- UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap_v);
-
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_HOZ, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_EXP, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_POS, "");
+ UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap);
+
+ {
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
+ }
+
+ if (show_extend) {
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Horizontal"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_HOZ, "");
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_EXP, "");
+ }
+
+ {
+ uiDefIconTextBut(
+ block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"),
+ 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, reset_mode, "");
+ }
UI_block_direction_set(block, UI_DIR_RIGHT);
UI_block_bounds_set_text(block, 50);
@@ -1996,54 +2021,19 @@ static uiBlock *curvemap_tools_posslope_func(bContext *C, ARegion *ar, void *cum
return block;
}
-static uiBlock *curvemap_tools_negslope_func(bContext *C, ARegion *ar, void *cumap_v)
+static uiBlock *curvemap_tools_posslope_func(bContext *C, ARegion *ar, void *cumap_v)
{
- uiBlock *block;
- short yco = 0, menuwidth = 10 * UI_UNIT_X;
-
- block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
- UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap_v);
-
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_HOZ, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_EXP, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_NEG, "");
-
- UI_block_direction_set(block, UI_DIR_RIGHT);
- UI_block_bounds_set_text(block, 50);
+ return curvemap_tools_func(C, ar, cumap_v, true, UICURVE_FUNC_RESET_POS);
+}
- return block;
+static uiBlock *curvemap_tools_negslope_func(bContext *C, ARegion *ar, void *cumap_v)
+{
+ return curvemap_tools_func(C, ar, cumap_v, true, UICURVE_FUNC_RESET_NEG);
}
static uiBlock *curvemap_brush_tools_func(bContext *C, ARegion *ar, void *cumap_v)
{
- uiBlock *block;
- short yco = 0, menuwidth = 10 * UI_UNIT_X;
-
- block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
- UI_block_func_butmenu_set(block, curvemap_tools_dofunc, cumap_v);
-
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
- uiDefIconTextBut(block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
- menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_NEG, "");
-
- UI_block_direction_set(block, UI_DIR_RIGHT);
- UI_block_bounds_set_text(block, 50);
-
- return block;
+ return curvemap_tools_func(C, ar, cumap_v, false, UICURVE_FUNC_RESET_NEG);
}
static void curvemap_buttons_redraw(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
@@ -2165,10 +2155,10 @@ static void curvemap_buttons_layout(
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMIN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
+ bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_ZOOM_IN, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom in"));
UI_but_func_set(bt, curvemap_buttons_zoom_in, cumap, NULL);
- bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_ZOOMOUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
+ bt = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_ZOOM_OUT, 0, 0, dx, dx, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Zoom out"));
UI_but_func_set(bt, curvemap_buttons_zoom_out, cumap, NULL);
if (brush)
@@ -2418,15 +2408,15 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
uiLayoutRow(col, true);
for (; color; color = color->next) {
- PointerRNA ptr;
+ PointerRNA color_ptr;
if (row_cols >= cols_per_row) {
uiLayoutRow(col, true);
row_cols = 0;
}
- RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr);
- uiDefButR(block, UI_BTYPE_COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
+ RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &color_ptr);
+ uiDefButR(block, UI_BTYPE_COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &color_ptr, "color", -1, 0.0, 1.0,
UI_PALETTE_COLOR, col_id, "");
row_cols++;
col_id++;
@@ -3033,7 +3023,7 @@ void uiTemplateList(
/* So that we do not map again activei! */
activei_mapping_pending = false;
}
-# if 0 /* For now, do not alter active element, even if it will be hidden... */
+#if 0 /* For now, do not alter active element, even if it will be hidden... */
else if (activei < i) {
/* We do not want an active but invisible item!
* Only exception is when all items are filtered out...
@@ -3054,6 +3044,11 @@ void uiTemplateList(
i++;
}
RNA_PROP_END;
+
+ if (activei_mapping_pending) {
+ /* No active item found, set to 'invalid' -1 value... */
+ activei = -1;
+ }
}
if (dyn_data->items_shown >= 0) {
len = dyn_data->items_shown;
@@ -3282,18 +3277,47 @@ static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
}
+static bool has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
+{
+ const char *match = BLI_strncasestr(haystack, needle, needle_len);
+ if (match) {
+ if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
+ return true;
+ }
+ else {
+ return has_word_prefix(match + 1, needle, needle_len);
+ }
+ }
+ else {
+ return false;
+ }
+}
+
static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
{
GHashIterator iter;
+ const size_t str_len = strlen(str);
+ const int words_max = (str_len / 2) + 1;
+ int (*words)[2] = BLI_array_alloca(words, words_max);
+
+ const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
+ int index;
if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0)
continue;
- if (BLI_strcasestr(ot_ui_name, str)) {
+ /* match name against all search words */
+ for (index = 0; index < words_len; index++) {
+ if (!has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) {
+ break;
+ }
+ }
+
+ if (index == words_len) {
if (WM_operator_poll((bContext *)C, ot)) {
char name[256];
int len = strlen(ot_ui_name);
@@ -3319,7 +3343,9 @@ static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char
void UI_but_func_operator_search(uiBut *but)
{
- UI_but_func_search_set(but, operator_search_cb, NULL, operator_call_cb, NULL);
+ UI_but_func_search_set(
+ but, ui_searchbox_create_operator, operator_search_cb,
+ NULL, operator_call_cb, NULL);
}
void uiTemplateOperatorSearch(uiLayout *layout)
@@ -3376,6 +3402,36 @@ static void do_running_jobs(bContext *C, void *UNUSED(arg), int event)
}
}
+struct ProgressTooltip_Store {
+ wmWindowManager *wm;
+ void *owner;
+};
+
+static char *progress_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
+{
+ struct ProgressTooltip_Store *arg = argN;
+ wmWindowManager *wm = arg->wm;
+ void *owner = arg->owner;
+
+ const float progress = WM_jobs_progress(wm, owner);
+
+ /* create tooltip text and associate it with the job */
+ char elapsed_str[32];
+ char remaining_str[32] = "Unknown";
+ const double elapsed = PIL_check_seconds_timer() - WM_jobs_starttime(wm, owner);
+ BLI_timecode_string_from_time_simple(elapsed_str, sizeof(elapsed_str), elapsed);
+
+ if (progress) {
+ const double remaining = (elapsed / (double)progress) - elapsed;
+ BLI_timecode_string_from_time_simple(remaining_str, sizeof(remaining_str), remaining);
+ }
+
+ return BLI_sprintfN(
+ "Time Remaining: %s\n"
+ "Time Elapsed: %s",
+ remaining_str, elapsed_str);
+}
+
void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
@@ -3383,7 +3439,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
ScrArea *sa = CTX_wm_area(C);
uiBlock *block;
void *owner = NULL;
- int handle_event;
+ int handle_event, icon = 0;
block = uiLayoutGetBlock(layout);
UI_block_layout_set_current(block, layout);
@@ -3394,17 +3450,20 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
if (WM_jobs_test(wm, sa, WM_JOB_TYPE_ANY))
owner = sa;
handle_event = B_STOPSEQ;
+ icon = ICON_SEQUENCE;
}
else if (sa->spacetype == SPACE_CLIP) {
if (WM_jobs_test(wm, sa, WM_JOB_TYPE_ANY))
owner = sa;
handle_event = B_STOPCLIP;
+ icon = ICON_CLIP;
}
else if (sa->spacetype == SPACE_FILE) {
if (WM_jobs_test(wm, sa, WM_JOB_TYPE_FILESEL_READDIR)) {
owner = sa;
}
handle_event = B_STOPFILE;
+ icon = ICON_FILESEL;
}
else {
Scene *scene;
@@ -3412,10 +3471,12 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
for (scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next) {
if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
handle_event = B_STOPRENDER;
+ icon = ICON_SCENE;
break;
}
else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_COMPOSITE)) {
handle_event = B_STOPCOMPO;
+ icon = ICON_RENDERLAYERS;
break;
}
else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_OBJECT_BAKE_TEXTURE) ||
@@ -3427,11 +3488,33 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
*/
if (sa->spacetype != SPACE_NODE) {
handle_event = B_STOPOTHER;
+ icon = ICON_IMAGE_COL;
break;
}
}
+ else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_DPAINT_BAKE)) {
+ handle_event = B_STOPOTHER;
+ icon = ICON_MOD_DYNAMICPAINT;
+ break;
+ }
+ else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_POINTCACHE)) {
+ handle_event = B_STOPOTHER;
+ icon = ICON_PHYSICS;
+ break;
+ }
+ else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
+ handle_event = B_STOPOTHER;
+ icon = ICON_MOD_FLUIDSIM;
+ break;
+ }
+ else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_OBJECT_SIM_OCEAN)) {
+ handle_event = B_STOPOTHER;
+ icon = ICON_MOD_OCEAN;
+ break;
+ }
else if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) {
handle_event = B_STOPOTHER;
+ icon = ICON_NONE;
break;
}
}
@@ -3439,18 +3522,45 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
}
if (owner) {
- uiLayout *ui_abs;
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ bool active = !(G.is_break || WM_jobs_is_stopped(wm, owner));
- ui_abs = uiLayoutAbsolute(layout, false);
- (void)ui_abs; /* UNUSED */
-
- uiDefIconBut(block, UI_BTYPE_BUT, handle_event, ICON_PANEL_CLOSE, 0, UI_UNIT_Y * 0.1, UI_UNIT_X * 0.8, UI_UNIT_Y * 0.8,
- NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop this job"));
- uiDefBut(block, UI_BTYPE_PROGRESS_BAR, 0, WM_jobs_name(wm, owner),
- UI_UNIT_X, 0, UI_UNIT_X * 5.0f, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, TIP_("Progress"));
-
- uiLayoutRow(layout, false);
+ uiLayout *row = uiLayoutRow(layout, false);
+ block = uiLayoutGetBlock(row);
+
+ /* get percentage done and set it as the UI text */
+ const float progress = WM_jobs_progress(wm, owner);
+ char text[8];
+ BLI_snprintf(text, 8, "%d%%", (int)(progress * 100));
+
+ const char *name = active ? WM_jobs_name(wm, owner) : "Canceling...";
+
+ /* job name and icon */
+ const int textwidth = UI_fontstyle_string_width(fstyle, name);
+ uiDefIconTextBut(block, UI_BTYPE_LABEL, 0, icon, name, 0, 0,
+ textwidth + UI_UNIT_X * 1.5f, UI_UNIT_Y, NULL, 0.0f, 0.0f, 0.0f, 0.0f, "");
+
+ /* stick progress bar and cancel button together */
+ row = uiLayoutRow(layout, true);
+ uiLayoutSetActive(row, active);
+ block = uiLayoutGetBlock(row);
+
+ {
+ struct ProgressTooltip_Store *tip_arg = MEM_mallocN(sizeof(*tip_arg), __func__);
+ tip_arg->wm = wm;
+ tip_arg->owner = owner;
+ uiBut *but_progress = uiDefIconTextBut(
+ block, UI_BTYPE_PROGRESS_BAR, 0, 0, text,
+ UI_UNIT_X, 0, UI_UNIT_X * 6.0f, UI_UNIT_Y, NULL, 0.0f, 0.0f,
+ progress, 0, NULL);
+ UI_but_func_tooltip_set(but_progress, progress_tooltip_func, tip_arg);
+ }
+
+ uiDefIconTextBut(block, UI_BTYPE_BUT, handle_event, ICON_PANEL_CLOSE,
+ "", 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop this job"));
}
+
if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST))
uiDefIconTextBut(block, UI_BTYPE_BUT, B_STOPCAST, ICON_CANCEL, IFACE_("Capture"), 0, 0, UI_UNIT_X * 4.25f, UI_UNIT_Y,
NULL, 0.0f, 0.0f, 0, 0, TIP_("Stop screencast"));
@@ -3484,7 +3594,8 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
ui_abs = uiLayoutAbsolute(layout, false);
block = uiLayoutGetBlock(ui_abs);
- width = BLF_width(style->widget.uifont_id, report->message, report->len);
+ UI_fontstyle_set(&style->widgetlabel);
+ width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len);
width = min_ii((int)(rti->widthfac * width), width);
width = max_ii(width, 10);
@@ -3593,6 +3704,9 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
/* operator buttons may store props for use (file selector, [#36492]) */
if (but->rnaprop) {
UI_but_func_set(but, keymap_item_modified, ptr->data, NULL);
+
+ /* Otherwise the keymap will be re-generated which we're trying to edit, see: T47685 */
+ UI_but_flag_enable(but, UI_BUT_UPDATE_DELAY);
}
}
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 5d37f5c0fcf..d1461f1acec 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -57,6 +57,8 @@
#include "interface_intern.h"
+#include "GPU_basic_shader.h"
+
#ifdef WITH_INPUT_IME
# include "WM_types.h"
#endif
@@ -660,14 +662,14 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
/* light checkers */
- glEnable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
- glPolygonStipple(stipple_checker_8px);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX);
glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* alpha fill */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -737,18 +739,18 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
wcol->outline[1],
wcol->outline[2],
wcol->outline[3] / WIDGET_AA_JITTER};
+ unsigned char emboss[4];
widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
if (wtb->draw_emboss) {
widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
}
glEnableClientState(GL_VERTEX_ARRAY);
for (j = 0; j < WIDGET_AA_JITTER; j++) {
- unsigned char emboss[4];
-
glTranslate2fv(jit[j]);
/* outline */
@@ -759,8 +761,6 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* emboss bottom shadow */
if (wtb->draw_emboss) {
- UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
-
if (emboss[3]) {
glColor4ubv(emboss);
glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss);
@@ -780,19 +780,17 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
wcol->item[1],
wcol->item[2],
(unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
+ glColor4ubv(tcol);
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
glTranslate2fv(jit[j]);
- if (wtb->tria1.tot) {
- glColor4ubv(tcol);
+ if (wtb->tria1.tot)
widget_trias_draw(&wtb->tria1);
- }
- if (wtb->tria2.tot) {
- glColor4ubv(tcol);
+
+ if (wtb->tria2.tot)
widget_trias_draw(&wtb->tria2);
- }
glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
}
@@ -975,7 +973,7 @@ float UI_text_clip_middle_ex(
float strwidth;
/* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits!
- * Better to have a small piece of the last char cut out, than two remaining chars replaced by an allipsis... */
+ * Better to have a small piece of the last char cut out, than two remaining chars replaced by an ellipsis... */
okwidth += 1.0f + UI_DPI_FAC;
BLI_assert(str[0]);
@@ -1856,7 +1854,7 @@ static struct uiWidgetColors wcol_progress = {
{0, 0, 0, 255},
{190, 190, 190, 255},
{100, 100, 100, 180},
- {68, 68, 68, 255},
+ {128, 128, 128, 255},
{0, 0, 0, 255},
{255, 255, 255, 255},
@@ -1869,10 +1867,10 @@ static struct uiWidgetColors wcol_list_item = {
{0, 0, 0, 255},
{0, 0, 0, 0},
{86, 128, 194, 255},
- {0, 0, 0, 255},
+ {90, 90, 90, 255},
{0, 0, 0, 255},
- {0, 0, 0, 255},
+ {255, 255, 255, 255},
0,
0, 0
@@ -2621,12 +2619,12 @@ static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
static void ui_draw_separator(const rcti *rect, uiWidgetColors *wcol)
{
int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
- unsigned char col[4];
-
- col[0] = wcol->text[0];
- col[1] = wcol->text[1];
- col[2] = wcol->text[2];
- col[3] = 30;
+ unsigned char col[4] = {
+ wcol->text[0],
+ wcol->text[1],
+ wcol->text[2],
+ 30
+ };
glEnable(GL_BLEND);
glColor4ubv(col);
@@ -2865,30 +2863,37 @@ static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
UI_draw_widget_scroll(wcol, rect, &rect1, state);
}
-static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
+ uiWidgetBase wtb, wtb_bar;
rcti rect_prog = *rect, rect_bar = *rect;
+
+ widget_init(&wtb);
+ widget_init(&wtb_bar);
+
+ /* round corners */
float value = but->a1;
- float w, min;
-
- /* make the progress bar a proportion of the original height */
- /* hardcoded 4px high for now */
- rect_prog.ymax = rect_prog.ymin + 4 * UI_DPI_FAC;
- rect_bar.ymax = rect_bar.ymin + 4 * UI_DPI_FAC;
-
- w = value * BLI_rcti_size_x(&rect_prog);
-
+ float offs = 0.25f * BLI_rcti_size_y(&rect_prog);
+ float w = value * BLI_rcti_size_x(&rect_prog);
+
/* ensure minimium size */
- min = BLI_rcti_size_y(&rect_prog);
- w = MAX2(w, min);
-
+ w = MAX2(w, offs);
+
rect_bar.xmax = rect_bar.xmin + w;
-
- UI_draw_widget_scroll(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
-
+
+ round_box_edges(&wtb, roundboxalign, &rect_prog, offs);
+ round_box_edges(&wtb_bar, roundboxalign, &rect_bar, offs);
+
+ wtb.draw_outline = true;
+ widgetbase_draw(&wtb, wcol);
+
+ /* "slider" bar color */
+ copy_v3_v3_char(wcol->inner, wcol->item);
+ widgetbase_draw(&wtb_bar, wcol);
+
/* raise text a bit */
- rect->ymin += 6 * UI_DPI_FAC;
- rect->xmin -= 6 * UI_DPI_FAC;
+ rect->xmin += (BLI_rcti_size_x(&rect_prog) / 2);
+ rect->xmax += (BLI_rcti_size_x(&rect_prog) / 2);
}
static void widget_link(uiBut *but, uiWidgetColors *UNUSED(wcol), rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
@@ -3037,6 +3042,15 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
wcol->shaded = 0;
wcol->alpha_check = (wcol->inner[3] < 255);
+
+ if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ /* Now we reduce alpha of the inner color (i.e. the color shown)
+ * so that this setting can look greyed out, while retaining
+ * the checkboard (for transparent values). This is needed
+ * here as the effects of ui_widget_color_disabled() are overwritten.
+ */
+ wcol->inner[3] /= 2;
+ }
widgetbase_draw(&wtb, wcol);
@@ -3248,7 +3262,7 @@ static void widget_optionbut(uiWidgetColors *wcol, rcti *rect, int state, int UN
recttemp.ymax -= delta;
/* half rounded */
- rad = 0.2f * U.widget_unit;
+ rad = BLI_rcti_size_y(&recttemp) / 3;
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
@@ -3496,6 +3510,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
case UI_WTYPE_ICON:
wt.custom = widget_icon_has_anim;
break;
+
+ case UI_WTYPE_ICON_LABEL:
+ /* behave like regular labels (this is simply a label with an icon) */
+ wt.state = widget_state_label;
+ wt.custom = widget_icon_has_anim;
+ break;
case UI_WTYPE_SWATCH:
wt.custom = widget_swatch;
@@ -3548,9 +3568,9 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
if ((but->drawflag & UI_BUT_ALIGN) && but->type != UI_BTYPE_PULLDOWN) {
/* ui_block_position has this correction too, keep in sync */
- if (but->drawflag & UI_BUT_ALIGN_TOP)
+ if (but->drawflag & (UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_STITCH_TOP))
rect->ymax += U.pixelsize;
- if (but->drawflag & UI_BUT_ALIGN_LEFT)
+ if (but->drawflag & (UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_STITCH_LEFT))
rect->xmin -= U.pixelsize;
switch (but->drawflag & UI_BUT_ALIGN) {
@@ -3621,7 +3641,14 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
}
else if (but->dt == UI_EMBOSS_NONE) {
/* "nothing" */
- wt = widget_type(UI_WTYPE_ICON);
+ switch (but->type) {
+ case UI_BTYPE_LABEL:
+ wt = widget_type(UI_WTYPE_ICON_LABEL);
+ break;
+ default:
+ wt = widget_type(UI_WTYPE_ICON);
+ break;
+ }
}
else if (but->dt == UI_EMBOSS_RADIAL) {
wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
@@ -4080,7 +4107,9 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
- UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
+ if (drawstr[0]) {
+ UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
+ }
glColor4ubv((unsigned char *)wt->wcol.text);
UI_fontstyle_draw(fstyle, rect, drawstr);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 13eafd7eade..b1d2e329da1 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -492,6 +492,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->transition; break;
case TH_SEQ_META:
cp = ts->meta; break;
+ case TH_SEQ_TEXT:
+ cp = ts->text_strip; break;
case TH_SEQ_PREVIEW:
cp = ts->preview_back; break;
@@ -1062,6 +1064,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tseq.effect, 169, 84, 124, 255);
rgba_char_args_set(btheme->tseq.transition, 162, 95, 111, 255);
rgba_char_args_set(btheme->tseq.meta, 109, 145, 131, 255);
+ rgba_char_args_set(btheme->tseq.text_strip, 162, 151, 0, 255);
rgba_char_args_set(btheme->tseq.preview_back, 0, 0, 0, 255);
rgba_char_args_set(btheme->tseq.grid, 64, 64, 64, 255);
@@ -1077,7 +1080,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tima.face, 255, 255, 255, 10);
rgba_char_args_set(btheme->tima.face_select, 255, 133, 0, 60);
rgba_char_args_set(btheme->tima.editmesh_active, 255, 255, 255, 128);
- rgba_char_args_set_fl(btheme->tima.preview_back, 0.45, 0.45, 0.45, 1.0);
+ rgba_char_args_set_fl(btheme->tima.preview_back, 0.0, 0.0, 0.0, 0.3);
rgba_char_args_set_fl(btheme->tima.preview_stitch_face, 0.5, 0.5, 0.0, 0.2);
rgba_char_args_set_fl(btheme->tima.preview_stitch_edge, 1.0, 0.0, 1.0, 0.2);
rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2);
@@ -1382,6 +1385,23 @@ int UI_GetThemeValue(int colorid)
return ((int) cp[0]);
}
+/* versions of the function above, which take a space-type */
+float UI_GetThemeValueTypef(int colorid, int spacetype)
+{
+ const unsigned char *cp;
+
+ cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
+ return ((float)cp[0]);
+}
+
+int UI_GetThemeValueType(int colorid, int spacetype)
+{
+ const unsigned char *cp;
+
+ cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
+ return ((int)cp[0]);
+}
+
/* get the color, range 0.0-1.0 */
void UI_GetThemeColor3fv(int colorid, float col[3])
@@ -1920,11 +1940,7 @@ void init_userdef_do_versions(void)
if (U.audioformat == 0)
U.audioformat = 0x24;
if (U.audiorate == 0)
- U.audiorate = 44100;
- }
-
- if (!USER_VERSION_ATLEAST(250, 3)) {
- U.gameflags |= USER_DISABLE_VBO;
+ U.audiorate = 48000;
}
if (!USER_VERSION_ATLEAST(250, 8)) {
@@ -2008,7 +2024,7 @@ void init_userdef_do_versions(void)
{0, 0, 0, 255},
{190, 190, 190, 255},
{100, 100, 100, 180},
- {68, 68, 68, 255},
+ {128, 128, 128, 255},
{0, 0, 0, 255},
{255, 255, 255, 255},
@@ -2646,6 +2662,56 @@ void init_userdef_do_versions(void)
}
}
+ if (!USER_VERSION_ATLEAST(276, 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set(btheme->tclip.gp_vertex, 0, 0, 0, 255);
+ rgba_char_args_set(btheme->tclip.gp_vertex_select, 255, 133, 0, 255);
+ btheme->tclip.gp_vertex_size = 3;
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(276, 3)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set(btheme->tseq.text_strip, 162, 151, 0, 255);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(276, 8)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set(btheme->tui.wcol_progress.item, 128, 128, 128, 255);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(276, 10)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* 3dView Keyframe Indicators */
+ rgba_char_args_set(btheme->tv3d.time_keyframe, 0xDD, 0xD7, 0x00, 1.0);
+ rgba_char_args_set(btheme->tv3d.time_gp_keyframe, 0xB5, 0xE6, 0x1D, 1.0);
+ }
+ }
+
+ if (!USER_VERSION_ATLEAST(277, 0)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ if (memcmp(btheme->tui.wcol_list_item.item, btheme->tui.wcol_list_item.text_sel, sizeof(char) * 3) == 0) {
+ copy_v4_v4_char(btheme->tui.wcol_list_item.item, btheme->tui.wcol_text.item);
+ copy_v4_v4_char(btheme->tui.wcol_list_item.text_sel, btheme->tui.wcol_text.text_sel);
+ }
+ }
+ }
+
+ /**
+ * Include next version bump.
+ *
+ * (keep this block even if it becomes empty).
+ */
+ {
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 5f0c3ff6993..c78d97ef86f 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -63,7 +63,7 @@
#include "interface_intern.h"
-static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers);
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers);
/* *********************************************************************** */
@@ -116,7 +116,7 @@ static int view2d_scroll_mapped(int scroll)
}
/* called each time cur changes, to dynamically update masks */
-static void view2d_masks(View2D *v2d, int check_scrollers)
+static void view2d_masks(View2D *v2d, bool check_scrollers)
{
int scroll;
@@ -211,7 +211,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
uiStyle *style = UI_style_get();
do_init = (v2d->flag & V2D_IS_INITIALISED) == 0;
-
+
/* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */
switch (type) {
/* 'standard view' - optimum setup for 'standard' view behavior,
@@ -317,21 +317,24 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
v2d->keeptot = V2D_KEEPTOT_BOUNDS;
/* note, scroll is being flipped in ED_region_panels() drawing */
- v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
- v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE;
+ v2d->scroll |= (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE);
+
+ /* initialize without scroll bars (interferes with zoom level see: T47047) */
+ if (do_init) {
+ v2d->scroll |= (V2D_SCROLL_VERTICAL_FULLR | V2D_SCROLL_HORIZONTAL_FULLR);
+ }
if (do_init) {
float panelzoom = (style) ? style->panelzoom : 1.0f;
- float scrolw = (v2d->scroll & V2D_SCROLL_RIGHT) ? V2D_SCROLL_WIDTH : 0.0f;
v2d->tot.xmin = 0.0f;
- v2d->tot.xmax = winx - scrolw;
+ v2d->tot.xmax = winx;
v2d->tot.ymax = 0.0f;
v2d->tot.ymin = -winy;
v2d->cur.xmin = 0.0f;
- v2d->cur.xmax = (winx) * panelzoom - scrolw;
+ v2d->cur.xmax = (winx) * panelzoom;
v2d->cur.ymax = 0.0f;
v2d->cur.ymin = (-winy) * panelzoom;
@@ -368,7 +371,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
* 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
-static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers)
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers)
{
float totwidth, totheight, curwidth, curheight, width, height;
float winx, winy;
@@ -472,7 +475,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
/* check if we should restore aspect ratio (if view size changed) */
if (v2d->keepzoom & V2D_KEEPASPECT) {
bool do_x = false, do_y = false, do_cur /* , do_win */ /* UNUSED */;
- float /* curRatio, */ /* UNUSED */ winRatio;
+ float curRatio, winRatio;
/* when a window edge changes, the aspect ratio can't be used to
* find which is the best new 'cur' rect. thats why it stores 'old'
@@ -480,7 +483,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
if (winx != v2d->oldwinx) do_x = true;
if (winy != v2d->oldwiny) do_y = true;
- /* curRatio = height / width; */ /* UNUSED */
+ curRatio = height / width;
winRatio = winy / winx;
/* both sizes change (area/region maximized) */
@@ -490,7 +493,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
if (fabsf(winx - v2d->oldwinx) > fabsf(winy - v2d->oldwiny)) do_y = false;
else do_x = false;
}
- else if (winRatio > 1.0f) {
+ else if (winRatio > curRatio) {
do_x = false;
}
else {
@@ -899,7 +902,7 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* ------------------ */
/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
-void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize)
+void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
// int scroll = view2d_scroll_mapped(v2d->scroll);
@@ -1218,7 +1221,7 @@ View2DGrid *UI_view2d_grid_calc(
{
View2DGrid *grid;
- float space, pixels, seconddiv;
+ float space, seconddiv;
/* check that there are at least some workable args */
if (ELEM(V2D_ARG_DUMMY, xunits, xclamp) && ELEM(V2D_ARG_DUMMY, yunits, yclamp))
@@ -1238,32 +1241,37 @@ View2DGrid *UI_view2d_grid_calc(
/* calculate x-axis grid scale (only if both args are valid) */
if (ELEM(V2D_ARG_DUMMY, xunits, xclamp) == 0) {
space = BLI_rctf_size_x(&v2d->cur);
- pixels = (float)BLI_rcti_size_x(&v2d->mask);
-
- if (pixels != 0.0f) {
- grid->dx = (U.v2d_min_gridsize * UI_DPI_FAC * space) / (seconddiv * pixels);
- step_to_grid(&grid->dx, &grid->powerx, xunits);
- grid->dx *= seconddiv;
+
+ if (space != 0.0f) {
+ const float pixels = (float)BLI_rcti_size_x(&v2d->mask);
+ if (pixels != 0.0f) {
+ grid->dx = (U.v2d_min_gridsize * UI_DPI_FAC * space) / (seconddiv * pixels);
+ step_to_grid(&grid->dx, &grid->powerx, xunits);
+ grid->dx *= seconddiv;
+ }
}
if (xclamp == V2D_GRID_CLAMP) {
- if (grid->dx < 0.1f) grid->dx = 0.1f;
+ CLAMP_MIN(grid->dx, 0.1f);
+ CLAMP_MIN(grid->powerx, 0);
grid->powerx -= 2;
- if (grid->powerx < -2) grid->powerx = -2;
}
}
/* calculate y-axis grid scale (only if both args are valid) */
if (ELEM(V2D_ARG_DUMMY, yunits, yclamp) == 0) {
space = BLI_rctf_size_y(&v2d->cur);
- pixels = (float)winy;
-
- grid->dy = U.v2d_min_gridsize * UI_DPI_FAC * space / pixels;
- step_to_grid(&grid->dy, &grid->powery, yunits);
-
+ if (space != 0.0f) {
+ const float pixels = (float)winy;
+ if (pixels != 0.0f) {
+ grid->dy = U.v2d_min_gridsize * UI_DPI_FAC * space / pixels;
+ step_to_grid(&grid->dy, &grid->powery, yunits);
+ }
+ }
+
if (yclamp == V2D_GRID_CLAMP) {
- if (grid->dy < 1.0f) grid->dy = 1.0f;
- if (grid->powery < 1) grid->powery = 1;
+ CLAMP_MIN(grid->dy, 1.0f);
+ CLAMP_MIN(grid->powery, 1);
}
}
@@ -1294,7 +1302,9 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
/* check for grid first, as it may not exist */
if (grid == NULL)
return;
-
+
+ glBegin(GL_LINES);
+
/* vertical lines */
if (flag & V2D_VERTICAL_LINES) {
/* initialize initial settings */
@@ -1307,10 +1317,8 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
UI_ThemeColor(TH_GRID);
for (a = 0; a < step; a++) {
- glBegin(GL_LINE_STRIP);
glVertex2fv(vec1);
glVertex2fv(vec2);
- glEnd();
vec2[0] = vec1[0] += grid->dx;
}
@@ -1321,10 +1329,8 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
step++;
for (a = 0; a <= step; a++) {
- glBegin(GL_LINE_STRIP);
glVertex2fv(vec1);
glVertex2fv(vec2);
- glEnd();
vec2[0] = vec1[0] -= grid->dx;
}
@@ -1341,10 +1347,8 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
UI_ThemeColor(TH_GRID);
for (a = 0; a <= step; a++) {
- glBegin(GL_LINE_STRIP);
glVertex2fv(vec1);
glVertex2fv(vec2);
- glEnd();
vec2[1] = vec1[1] += grid->dy;
}
@@ -1356,10 +1360,8 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
if (flag & V2D_HORIZONTAL_FINELINES) {
UI_ThemeColorShade(TH_GRID, 16);
for (a = 0; a < step; a++) {
- glBegin(GL_LINE_STRIP);
glVertex2fv(vec1);
glVertex2fv(vec2);
- glEnd();
vec2[1] = vec1[1] -= grid->dy;
}
@@ -1375,10 +1377,8 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
vec2[0] = v2d->cur.xmax;
vec1[1] = vec2[1] = 0.0f;
- glBegin(GL_LINE_STRIP);
glVertex2fv(vec1);
glVertex2fv(vec2);
- glEnd();
}
/* vertical axis */
@@ -1387,11 +1387,11 @@ void UI_view2d_grid_draw(View2D *v2d, View2DGrid *grid, int flag)
vec2[1] = v2d->cur.ymax;
vec1[0] = vec2[0] = 0.0f;
- glBegin(GL_LINE_STRIP);
glVertex2fv(vec1);
glVertex2fv(vec2);
- glEnd();
}
+
+ glEnd();
}
/* Draw a constant grid in given 2d-region */
@@ -1431,7 +1431,8 @@ void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_s
int offset = -10;
float lstep = step;
int level;
-
+
+ glLineWidth(1.0f);
for (level = 0; level < totlevels; ++level) {
int i;
float start;
@@ -2393,7 +2394,7 @@ void UI_view2d_text_cache_draw(ARegion *ar)
/* investigate using BLF_ascender() */
const float default_height = g_v2d_strings ? BLF_height_default("28", 3) : 0.0f;
- wmOrtho2_region_ui(ar);
+ wmOrtho2_region_pixelspace(ar);
for (v2s = g_v2d_strings; v2s; v2s = v2s->next) {
int xofs = 0, yofs;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 07275d6be2a..f60fed398ec 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -572,7 +572,7 @@ static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2])
if (sa && sa->spacetype == SPACE_SEQ) {
ARegion *ar = CTX_wm_region(C);
- if (ar && ar->regiontype != RGN_TYPE_PREVIEW)
+ if (ar && ar->regiontype == RGN_TYPE_WINDOW)
r_do_zoom_xy[1] = false;
}
}
@@ -612,15 +612,20 @@ static int view_zoom_poll(bContext *C)
/* check if there's a region in context to work with */
if (ar == NULL)
- return 0;
+ return false;
+
+ /* Do not show that in 3DView context. */
+ if (CTX_wm_region_view3d(C))
+ return false;
+
v2d = &ar->v2d;
/* check that 2d-view is zoomable */
if ((v2d->keepzoom & V2D_LOCKZOOM_X) && (v2d->keepzoom & V2D_LOCKZOOM_Y))
- return 0;
+ return false;
/* view is zoomable */
- return 1;
+ return true;
}
/* apply transform to view (i.e. adjust 'cur' rect) */
diff --git a/source/blender/editors/io/SConscript b/source/blender/editors/io/SConscript
deleted file mode 100644
index 2b1a638b891..00000000000
--- a/source/blender/editors/io/SConscript
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-
-incs = [
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../collada',
- '../../makesrna',
- '../../windowmanager',
- '../../bmesh../../makesdna',
- ]
-
-if env['WITH_BF_COLLADA']:
- defs += ['WITH_COLLADA']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs += ['WITH_INTERNATIONAL']
-
-env.BlenderLib ( 'bf_editor_io', sources, incs, defines=defs, libtype=['core','player'], priority=[330,210] )
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 021b040fdd5..d4c976fb544 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -175,6 +175,10 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_WARNING, "Export file is empty");
return OPERATOR_CANCELLED;
}
+ else if (export_count < 0) {
+ BKE_report(op->reports, RPT_WARNING, "Error during export (see Console)");
+ return OPERATOR_CANCELLED;
+ }
else {
char buff[100];
sprintf(buff, "Exported %d Objects", export_count);
@@ -298,8 +302,9 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->ui = wm_collada_export_draw;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna,
"apply_modifiers", 0, "Apply Modifiers",
@@ -444,8 +449,9 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->ui = wm_collada_import_draw;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_COLLADA, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna,
"import_units", 0, "Import Units",
diff --git a/source/blender/editors/mask/SConscript b/source/blender/editors/mask/SConscript
deleted file mode 100644
index c4e6daaf5df..00000000000
--- a/source/blender/editors/mask/SConscript
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-env.BlenderLib('bf_editors_mask', sources, incs, defs, libtype=['core'], priority=[100])
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 2efa9e211c9..9a8382b2136 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -197,7 +197,6 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin
glVertex2fv(point_pos);
glVertex2fv(handle_pos);
glEnd();
- glLineWidth(1);
}
switch (handle_type) {
@@ -213,6 +212,7 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin
break;
}
+ glLineWidth(1);
glBegin(GL_LINES);
glVertex2fv(point_pos);
glVertex2fv(handle_pos);
@@ -387,8 +387,6 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
draw_circle(x, y, 6.0f, false, xscale, yscale);
}
- glPointSize(1.0f);
-
if (is_smooth) {
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -669,7 +667,7 @@ typedef struct ThreadedMaskRasterizeData {
int num_scanlines;
} ThreadedMaskRasterizeData;
-static void mask_rasterize_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
+static void mask_rasterize_func(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
{
ThreadedMaskRasterizeState *state = (ThreadedMaskRasterizeState *) BLI_task_pool_userdata(pool);
ThreadedMaskRasterizeData *data = (ThreadedMaskRasterizeData *) taskdata;
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index e1a58d529b6..9a2635c37d2 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -403,6 +403,10 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *mask_layer;
bool ok = false;
+
+ if (mask == NULL)
+ return ok;
+
INIT_MINMAX2(min, max);
for (mask_layer = mask->masklayers.first;
mask_layer != NULL;
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index bf8630ff843..eef03852007 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -929,7 +929,6 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (data->is_sliding_new_point) {
if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) {
- BezTriple *bezt = &data->point->bezt;
float vec[2];
short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2;
short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0;
@@ -1005,12 +1004,12 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
w = len_v2(vec);
if (is_overall_feather) {
- float delta;
+ float w_delta;
if (dot_v2v2(no, vec) <= 0.0f)
w = -w;
- delta = w - data->weight * data->weight_scalar;
+ w_delta = w - data->weight * data->weight_scalar;
if (data->orig_spline == NULL) {
/* restore weight for currently sliding point, so orig_spline would be created
@@ -1025,7 +1024,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
*weight = w * weight_scalar;
}
- slide_point_delta_all_feather(data, delta);
+ slide_point_delta_all_feather(data, w_delta);
}
else {
if (dot_v2v2(no, vec) <= 0.0f)
@@ -1081,7 +1080,6 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (data->is_sliding_new_point) {
- BezTriple *bezt = &data->point->bezt;
if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) {
bezt->h1 = HD_VECT;
}
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
deleted file mode 100644
index df58b2a90b3..00000000000
--- a/source/blender/editors/mesh/SConscript
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../uvedit',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_GAMEENGINE']:
- incs += ' #/extern/recastnavigation'
- defs.append('WITH_GAMEENGINE')
-else:
- sources.remove('mesh_navmesh.c')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-env.BlenderLib ( 'bf_editors_mesh', sources, Split(incs), defs, libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 0017cd3c2ae..01be8f848aa 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -53,11 +53,13 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_buffers.h"
+
/* own include */
/* copy the face flags, most importantly selection from the mesh to the final derived mesh,
* use in object mode when selecting faces (while painting) */
-void paintface_flush_flags(Object *ob)
+void paintface_flush_flags(Object *ob, short flag)
{
Mesh *me = BKE_mesh_from_object(ob);
DerivedMesh *dm = ob->derivedFinal;
@@ -66,6 +68,8 @@ void paintface_flush_flags(Object *ob)
int totpoly;
int i;
+ BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0);
+
if (me == NULL)
return;
@@ -73,7 +77,9 @@ void paintface_flush_flags(Object *ob)
/* we could call this directly in all areas that change selection,
* since this could become slow for realtime updates (circle-select for eg) */
- BKE_mesh_flush_select_from_polys(me);
+ if (flag & SELECT) {
+ BKE_mesh_flush_select_from_polys(me);
+ }
if (dm == NULL)
return;
@@ -90,9 +96,15 @@ void paintface_flush_flags(Object *ob)
/* Copy flags onto the final derived poly from the original mesh poly */
mp_orig = me->mpoly + index_array[i];
polys[i].flag = mp_orig->flag;
+
}
}
}
+
+ if (flag & ME_HIDE) {
+ /* draw-object caches hidden faces, force re-generation T46867 */
+ GPU_drawobject_free(dm);
+ }
}
void paintface_hide(Object *ob, const bool unselected)
@@ -122,7 +134,7 @@ void paintface_hide(Object *ob, const bool unselected)
BKE_mesh_flush_hidden_from_polys(me);
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT | ME_HIDE);
}
@@ -147,7 +159,7 @@ void paintface_reveal(Object *ob)
BKE_mesh_flush_hidden_from_polys(me);
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT | ME_HIDE);
}
/* Set tface seams based on edge data, uses hash table to find seam edges. */
@@ -241,7 +253,7 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b
select_linked_tfaces_with_seams(me, index, select);
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT);
}
void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags)
@@ -287,7 +299,7 @@ void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags)
}
if (flush_flags) {
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT);
}
}
@@ -376,7 +388,7 @@ bool paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], b
/* image window redraw */
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
return true;
@@ -454,7 +466,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten
glReadBuffer(GL_BACK);
#endif
- paintface_flush_flags(vc->obact);
+ paintface_flush_flags(vc->obact, SELECT);
return OPERATOR_FINISHED;
}
@@ -620,12 +632,16 @@ static int mirrtopo_vert_sort(const void *v1, const void *v2)
return 0;
}
-bool ED_mesh_mirrtopo_recalc_check(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_topo_store)
+bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store)
{
int totvert;
int totedge;
- if (me->edit_btmesh) {
+ if (dm) {
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ }
+ else if (me->edit_btmesh) {
totvert = me->edit_btmesh->bm->totvert;
totedge = me->edit_btmesh->bm->totedge;
}
@@ -647,11 +663,11 @@ bool ED_mesh_mirrtopo_recalc_check(Mesh *me, const int ob_mode, MirrTopoStore_t
}
-void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
+void ED_mesh_mirrtopo_init(Mesh *me, DerivedMesh *dm, const int ob_mode, MirrTopoStore_t *mesh_topo_store,
const bool skip_em_vert_array_init)
{
- MEdge *medge;
- BMEditMesh *em = me->edit_btmesh;
+ MEdge *medge = NULL, *med;
+ BMEditMesh *em = dm ? NULL : me->edit_btmesh;
/* editmode*/
BMEdge *eed;
@@ -680,7 +696,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
totvert = em->bm->totvert;
}
else {
- totvert = me->totvert;
+ totvert = dm ? dm->getNumVerts(dm) : me->totvert;
}
topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr");
@@ -696,10 +712,11 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
}
}
else {
- totedge = me->totedge;
+ totedge = dm ? dm->getNumEdges(dm) : me->totedge;
+ medge = dm ? dm->getEdgeArray(dm) : me->medge;
- for (a = 0, medge = me->medge; a < me->totedge; a++, medge++) {
- const unsigned int i1 = medge->v1, i2 = medge->v2;
+ for (a = 0, med = medge; a < totedge; a++, med++) {
+ const unsigned int i1 = med->v1, i2 = med->v2;
topo_hash[i1]++;
topo_hash[i2]++;
}
@@ -724,8 +741,8 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
}
}
else {
- for (a = 0, medge = me->medge; a < me->totedge; a++, medge++) {
- const unsigned int i1 = medge->v1, i2 = medge->v2;
+ for (a = 0, med = medge; a < totedge; a++, med++) {
+ const unsigned int i1 = med->v1, i2 = med->v2;
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
@@ -770,7 +787,6 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to
}
}
-
for (a = 0; a < totvert; a++) {
topo_pairs[a].hash = topo_hash[a];
topo_pairs[a].v_index = a;
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index e073a255f73..2a9f9c830f4 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -29,6 +29,7 @@
* \ingroup edmesh
*/
+#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -49,6 +50,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_object.h"
+#include "ED_uvedit.h"
#include "mesh_intern.h" /* own include */
@@ -105,16 +107,21 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4",
- 1, 1, RNA_float_get(op->ptr, "radius"), mat))
+ "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
+ 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -139,6 +146,7 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ED_object_add_unit_props(ot);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -150,16 +158,21 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_cube matrix=%m4 size=%f",
- mat, RNA_float_get(op->ptr, "radius") * 2.0f))
+ "create_cube matrix=%m4 size=%f calc_uvs=%b",
+ mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -185,6 +198,7 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ED_object_add_unit_props(ot);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -203,6 +217,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
int cap_end, cap_tri;
unsigned int layer;
bool was_editmode;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
cap_end = RNA_enum_get(op->ptr, "fill_type");
cap_tri = (cap_end == 2);
@@ -212,11 +227,15 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4",
+ "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
- cap_end, cap_tri, mat))
+ cap_end, cap_tri, mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -245,6 +264,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot)
ED_object_add_unit_props(ot);
RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -259,20 +279,25 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"),
RNA_float_get(op->ptr, "radius"),
RNA_float_get(op->ptr, "radius"),
cap_end, cap_tri,
- RNA_float_get(op->ptr, "depth"), mat))
+ RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -284,8 +309,6 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add Cylinder";
ot->description = "Construct a cylinder mesh";
@@ -301,10 +324,10 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
ED_object_add_unit_props(ot);
- prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
+ RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -319,17 +342,22 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
const bool cap_end = (end_fill_type != 0);
const bool cap_tri = (end_fill_type == 2);
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
- RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat))
+ RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -341,8 +369,6 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
void MESH_OT_primitive_cone_add(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add Cone";
ot->description = "Construct a conic mesh";
@@ -357,14 +383,12 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500);
- prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
- prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
- prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
+ RNA_def_float_distance(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00);
+ RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00);
+ RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00);
RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -376,18 +400,23 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4",
+ "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "x_subdivisions"),
RNA_int_get(op->ptr, "y_subdivisions"),
- RNA_float_get(op->ptr, "radius"), mat))
+ RNA_float_get(op->ptr, "radius"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -418,6 +447,7 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot)
RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000);
ED_object_add_unit_props(ot);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -479,17 +509,22 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4",
+ "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"),
- RNA_float_get(op->ptr, "size"), mat))
+ RNA_float_get(op->ptr, "size"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -501,8 +536,6 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add UV Sphere";
ot->description = "Construct a UV sphere mesh";
@@ -518,9 +551,9 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500);
RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500);
- prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
+ RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -532,17 +565,22 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
bool enter_editmode;
bool was_editmode;
unsigned int layer;
+ const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL);
obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer);
em = BKE_editmesh_from_object(obedit);
+ if (calc_uvs) {
+ ED_mesh_uv_texture_ensure(obedit->data, NULL);
+ }
+
if (!EDBM_op_call_and_selectf(
em, op, "verts.out", false,
- "create_icosphere subdivisions=%i diameter=%f matrix=%m4",
+ "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "subdivisions"),
- RNA_float_get(op->ptr, "size"), mat))
+ RNA_float_get(op->ptr, "size"), mat, calc_uvs))
{
return OPERATOR_CANCELLED;
}
@@ -554,8 +592,6 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Add Ico Sphere";
ot->description = "Construct an Icosphere mesh";
@@ -570,8 +606,8 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8);
- prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
+ RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00);
+ ED_object_add_mesh_props(ot);
ED_object_add_generic_props(ot, true);
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index ce6856321d2..847a7b5336e 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -99,7 +99,7 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(msg, HEADER_LENGTH, str, type_str,
WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
- WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "vertex_only")),
offset_str, RNA_int_get(op->ptr, "segments"));
ED_area_headerprint(sa, msg);
@@ -259,7 +259,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
opdata = op->customdata;
/* initialize mouse values */
- if (!calculateTransformCenter(C, V3D_CENTROID, center_3d, opdata->mcenter)) {
+ if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, center_3d, opdata->mcenter)) {
/* in this case the tool will likely do nothing,
* ideally this will never happen and should be checked for above */
opdata->mcenter[0] = opdata->mcenter[1] = 0;
@@ -361,9 +361,12 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case PADENTER:
case RETKEY:
- edbm_bevel_calc(op);
- edbm_bevel_exit(C, op);
- return OPERATOR_FINISHED;
+ if (event->val == KM_PRESS) {
+ edbm_bevel_calc(op);
+ edbm_bevel_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
/* Note this will prevent padplus and padminus to ever activate modal numinput.
* This is not really an issue though, as we only expect positive values here...
@@ -421,7 +424,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "clamp_overlap");
- RNA_property_enum_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
+ RNA_property_boolean_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
}
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
@@ -433,7 +436,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "vertex_only");
- RNA_property_enum_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
+ RNA_property_boolean_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
}
edbm_bevel_calc(op);
edbm_bevel_update_header(C, op);
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 08d0697e0f1..0e1ba2b1c25 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -285,13 +285,13 @@ static int mesh_bisect_exec(bContext *C, wmOperator *op)
/* Fill */
BMO_op_initf(
- bm, &bmop_fill, op->flag,
+ bm, &bmop_fill, 0,
"triangle_fill edges=%S normal=%v use_dissolve=%b",
&bmop, "geom_cut.out", normal_fill, true);
BMO_op_exec(bm, &bmop_fill);
/* Copy Attributes */
- BMO_op_initf(bm, &bmop_attr, op->flag,
+ BMO_op_initf(bm, &bmop_attr, 0,
"face_attribute_fill faces=%S use_normals=%b use_data=%b",
&bmop_fill, "geom.out", false, true);
BMO_op_exec(bm, &bmop_attr);
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index a020fed0835..161159d0be0 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -326,7 +326,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
+ RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
}
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index c037b0c6b0f..937547c99ef 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -280,7 +280,7 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
opdata = op->customdata;
/* initialize mouse values */
- if (!calculateTransformCenter(C, V3D_CENTROID, center_3d, opdata->mcenter)) {
+ if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, center_3d, opdata->mcenter)) {
/* in this case the tool will likely do nothing,
* ideally this will never happen and should be checked for above */
opdata->mcenter[0] = opdata->mcenter[1] = 0;
@@ -507,10 +507,10 @@ void MESH_OT_inset(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f);
+ prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- prop = RNA_def_float(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f);
+ prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f);
RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4);
RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset");
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index e2e4638254b..69588928253 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -27,10 +27,13 @@
#include "DNA_object_types.h"
#include "BLI_math.h"
-#include "BLI_array.h"
+#include "BLI_memarena.h"
+#include "BLI_stack.h"
+#include "BLI_buffer.h"
+#include "BLI_kdopbvh.h"
#include "BLI_linklist_stack.h"
-
+#include "BKE_editmesh_bvh.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
@@ -50,8 +53,8 @@
#include "tools/bmesh_intersect.h"
-/* -------------------------------------------------------------------- */
-/* Cut intersections into geometry */
+/* detect isolated holes and fill them */
+#define USE_NET_ISLAND_CONNECT
/**
* Compare selected with its self.
@@ -75,6 +78,23 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
return -1;
}
else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/**
+ * A flipped version of #bm_face_isect_pair
+ * use for boolean 'difference', which depends on order.
+ */
+static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ return -1;
+ }
+ else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
return 0;
}
else {
@@ -82,19 +102,41 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
}
}
+/**
+ * Use for intersect and boolean.
+ */
+static void edbm_intersect_select(BMEditMesh *em)
+{
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
+ }
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+
+}
+
+/* -------------------------------------------------------------------- */
+/* Cut intersections into geometry */
+
+/** \name Simple Intersect (self-intersect)
+ * \{
+ */
+
enum {
ISECT_SEL = 0,
ISECT_SEL_UNSEL = 1,
};
-static EnumPropertyItem isect_mode_items[] = {
- {ISECT_SEL, "SELECT", 0, "Self Intersect",
- "Self intersect selected faces"},
- {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected",
- "Intersect selected with unselected faces"},
- {0, NULL, 0, NULL, NULL}
-};
-
static int edbm_intersect_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -123,26 +165,13 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
bm,
em->looptris, em->tottri,
test_fn, NULL,
- use_self, use_separate,
+ use_self, use_separate, true, true,
+ -1,
eps);
if (has_isect) {
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
-
- if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- BMIter iter;
- BMEdge *e;
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(bm, e, true);
- }
- }
- }
-
- EDBM_mesh_normals_update(em);
- EDBM_update_generic(em, true, true);
+ edbm_intersect_select(em);
}
else {
BKE_report(op->reports, RPT_WARNING, "No intersections found");
@@ -153,8 +182,16 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
void MESH_OT_intersect(struct wmOperatorType *ot)
{
+ static EnumPropertyItem isect_mode_items[] = {
+ {ISECT_SEL, "SELECT", 0, "Self Intersect",
+ "Self intersect selected faces"},
+ {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected",
+ "Intersect selected with unselected faces"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
- ot->name = "Intersect";
+ ot->name = "Intersect (Knife)";
ot->description = "Cut an intersection into faces";
ot->idname = "MESH_OT_intersect";
@@ -165,25 +202,98 @@ void MESH_OT_intersect(struct wmOperatorType *ot)
/* props */
RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", "");
RNA_def_boolean(ot->srna, "use_separate", true, "Separate", "");
- RNA_def_float(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
+ RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Face Split by Edges */
+/* Boolean (a kind of intersect) */
+
+/** \name Boolean Intersect
+ *
+ * \note internally this is nearly exactly the same as 'MESH_OT_intersect',
+ * however from a user perspective they are quite different, so expose as different tools.
+ *
+ * \{
+ */
+
+static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int boolean_operation = RNA_enum_get(op->ptr, "operation");
+ bool use_swap = RNA_boolean_get(op->ptr, "use_swap");
+ const float eps = RNA_float_get(op->ptr, "threshold");
+ int (*test_fn)(BMFace *, void *);
+ bool has_isect;
+
+ test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair;
+
+ has_isect = BM_mesh_intersect(
+ bm,
+ em->looptris, em->tottri,
+ test_fn, NULL,
+ false, false, true, true,
+ boolean_operation,
+ eps);
+
+
+ if (has_isect) {
+ edbm_intersect_select(em);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No intersections found");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_intersect_boolean(struct wmOperatorType *ot)
+{
+ static EnumPropertyItem isect_boolean_operation_items[] = {
+ {BMESH_ISECT_BOOLEAN_ISECT, "INTERSECT", 0, "Intersect", ""},
+ {BMESH_ISECT_BOOLEAN_UNION, "UNION", 0, "Union", ""},
+ {BMESH_ISECT_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+ /* identifiers */
+ ot->name = "Intersect (Boolean)";
+ ot->description = "Cut solid geometry from selected to unselected";
+ ot->idname = "MESH_OT_intersect_boolean";
+
+ /* api callbacks */
+ ot->exec = edbm_intersect_boolean_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* props */
+ RNA_def_enum(ot->srna, "operation", isect_boolean_operation_items, BMESH_ISECT_BOOLEAN_DIFFERENCE, "Boolean", "");
+ RNA_def_boolean(ot->srna, "use_swap", false, "Swap", "Use with difference intersection to swap which side is kept");
+ RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/* Face Split by Edges */
/** \name Face/Edge Split
* \{ */
-static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
+static void bm_face_split_by_edges(
+ BMesh *bm, BMFace *f, const char hflag,
+ /* reusable memory buffer */
+ BLI_Buffer *edge_net_temp_buf)
{
- BMEdge **edge_net = NULL;
- BLI_array_declare(edge_net);
-
const int f_index = BM_elem_index_get(f);
BMLoop *l_iter;
@@ -198,6 +308,7 @@ static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *);
BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *);
+ BLI_assert(edge_net_temp_buf->count == 0);
/* collect all edges */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
@@ -213,7 +324,7 @@ static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
v->e = e;
BLI_SMALLSTACK_PUSH(vert_stack, v);
- BLI_array_append(edge_net, e);
+ BLI_buffer_append(edge_net_temp_buf, BMEdge *, e);
}
}
} while ((l_iter = l_iter->next) != l_first);
@@ -234,7 +345,7 @@ static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
v_next = BM_edge_other_vert(e_next, v);
BM_elem_index_set(e_next, f_index);
BLI_SMALLSTACK_PUSH(vert_stack_next, v_next);
- BLI_array_append(edge_net, e_next);
+ BLI_buffer_append(edge_net_temp_buf, BMEdge *, e_next);
}
}
@@ -243,8 +354,11 @@ static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
}
}
- BM_face_split_edgenet(bm, f, edge_net, BLI_array_count(edge_net), &face_arr, &face_arr_len);
- BLI_array_free(edge_net);
+ BM_face_split_edgenet(
+ bm, f, edge_net_temp_buf->data, edge_net_temp_buf->count,
+ &face_arr, &face_arr_len);
+
+ BLI_buffer_empty(edge_net_temp_buf);
if (face_arr_len) {
int i;
@@ -259,6 +373,241 @@ static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
}
}
+/**
+ * Check if a vert is in any of the faces connected to the edge,
+ * \a f_ignore is a face we happen to know isn't shared by the vertex.
+ */
+static bool bm_vert_in_faces_radial(BMVert *v, BMEdge *e_radial, BMFace *f_ignore)
+{
+ BLI_assert(BM_vert_in_face(v, f_ignore) == false);
+ if (e_radial->l) {
+ BMLoop *l_iter = e_radial->l;
+ do {
+ if (l_iter->f != f_ignore) {
+ if (BM_vert_in_face(v, l_iter->f)) {
+ return true;
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != e_radial->l);
+ }
+ return false;
+}
+
+#ifdef USE_NET_ISLAND_CONNECT
+
+struct LinkBase {
+ LinkNode *list;
+ unsigned int list_len;
+};
+
+static void ghash_insert_face_edge_link(
+ GHash *gh, BMFace *f_key, BMEdge *e_val,
+ MemArena *mem_arena)
+{
+ void **ls_base_p;
+ struct LinkBase *ls_base;
+ LinkNode *ls;
+
+ if (!BLI_ghash_ensure_p(gh, f_key, &ls_base_p)) {
+ ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base));
+ ls_base->list = NULL;
+ ls_base->list_len = 0;
+ }
+ else {
+ ls_base = *ls_base_p;
+ }
+
+ ls = BLI_memarena_alloc(mem_arena, sizeof(*ls));
+ ls->next = ls_base->list;
+ ls->link = e_val;
+ ls_base->list = ls;
+ ls_base->list_len += 1;
+}
+
+static int bm_edge_sort_length_cb(const void *e_a_v, const void *e_b_v)
+{
+ const float val_a = -BM_edge_calc_length_squared(*((BMEdge **)e_a_v));
+ const float val_b = -BM_edge_calc_length_squared(*((BMEdge **)e_b_v));
+
+ if (val_a > val_b) return 1;
+ else if (val_a < val_b) return -1;
+ else return 0;
+}
+
+static void bm_face_split_by_edges_island_connect(
+ BMesh *bm, BMFace *f,
+ LinkNode *e_link, const int e_link_len,
+ MemArena *mem_arena_edgenet)
+{
+ BMEdge **edge_arr = BLI_memarena_alloc(mem_arena_edgenet, sizeof(BMEdge **) * e_link_len);
+ int edge_arr_len = 0;
+
+ while (e_link) {
+ edge_arr[edge_arr_len++] = e_link->link;
+ e_link = e_link->next;
+ }
+
+ {
+ unsigned int edge_arr_holes_len;
+ BMEdge **edge_arr_holes;
+ if (BM_face_split_edgenet_connect_islands(
+ bm, f,
+ edge_arr, e_link_len,
+ true,
+ mem_arena_edgenet,
+ &edge_arr_holes, &edge_arr_holes_len))
+ {
+ edge_arr_len = edge_arr_holes_len;
+ edge_arr = edge_arr_holes; /* owned by the arena */
+ }
+ }
+
+ BM_face_split_edgenet(
+ bm, f, edge_arr, edge_arr_len,
+ NULL, NULL);
+
+ for (int i = e_link_len; i < edge_arr_len; i++) {
+ BM_edge_select_set(bm, edge_arr[i], true);
+ }
+
+ if (e_link_len != edge_arr_len) {
+ /* connecting partial islands can add redundant edges
+ * sort before removal to give deterministic outcome */
+ qsort(edge_arr, edge_arr_len - e_link_len, sizeof(*edge_arr), bm_edge_sort_length_cb);
+ for (int i = e_link_len; i < edge_arr_len; i++) {
+ BMFace *f_pair[2];
+ if (BM_edge_face_pair(edge_arr[i], &f_pair[0], &f_pair[1])) {
+ if (BM_face_share_vert_count(f_pair[0], f_pair[1]) == 2) {
+ BMFace *f_new = BM_faces_join(bm, f_pair, 2, true);
+ if (f_new) {
+ BM_face_select_set(bm, f_new, true);
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Check if \a v_pivot should be spliced into an existing edge.
+ *
+ * Detect one of 3 cases:
+ *
+ * - \a v_pivot is shared by 2+ edges from different faces.
+ * in this case return the closest edge shared by all faces.
+ *
+ * - \a v_pivot is an end-point of an edge which has no other edges connected.
+ * in this case return the closest edge in \a f_a to the \a v_pivot.
+ *
+ * - \a v_pivot has only edges from the same face connected,
+ * in this case return NULL. This is the most common case - no action is needed.
+ *
+ * \return the edge to be split.
+ *
+ * \note Currently we don't snap to verts or split chains by verts on-edges.
+ */
+static BMEdge *bm_face_split_edge_find(
+ BMEdge *e_a, BMFace *f_a, BMVert *v_pivot, BMFace **ftable, const int ftable_len,
+ float r_v_pivot_co[3], float *r_v_pivot_fac)
+{
+ const int f_a_index = BM_elem_index_get(e_a);
+ bool found_other_self = false;
+ int found_other_face = 0;
+ BLI_SMALLSTACK_DECLARE(face_stack, BMFace *);
+
+ /* loop over surrounding edges to check if we're part of a chain or a delimiter vertex */
+ BMEdge *e_b = v_pivot->e;
+ do {
+ if (e_b != e_a) {
+ const int f_b_index = BM_elem_index_get(e_b);
+ if (f_b_index == f_a_index) {
+ /* not an endpoint */
+ found_other_self = true;
+ }
+ else if (f_b_index != -1) {
+ BLI_assert(f_b_index < ftable_len);
+ UNUSED_VARS_NDEBUG(ftable_len);
+
+ /* 'v_pivot' spans 2+ faces,
+ * tag to ensure we pick an edge that includes this face */
+ BMFace *f_b = ftable[f_b_index];
+ if (!BM_elem_flag_test(f_b, BM_ELEM_INTERNAL_TAG)) {
+ BM_elem_flag_enable(f_b, BM_ELEM_INTERNAL_TAG);
+ BLI_SMALLSTACK_PUSH(face_stack, f_b);
+ found_other_face++;
+ }
+ }
+ }
+ } while ((e_b = BM_DISK_EDGE_NEXT(e_b, v_pivot)) != v_pivot->e);
+
+ BMEdge *e_split = NULL;
+
+ /* if we have no others or the other edge is outside this face,
+ * we're an endpoint to connect to a boundary */
+ if ((found_other_self == false) || found_other_face) {
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_a);
+ float dist_best_sq = FLT_MAX;
+
+ do {
+ float v_pivot_co_test[3];
+ float v_pivot_fac = line_point_factor_v3(v_pivot->co, l_iter->e->v1->co, l_iter->e->v2->co);
+ CLAMP(v_pivot_fac, 0.0f, 1.0f);
+ interp_v3_v3v3(v_pivot_co_test, l_iter->e->v1->co, l_iter->e->v2->co, v_pivot_fac);
+
+ float dist_test_sq = len_squared_v3v3(v_pivot_co_test, v_pivot->co);
+ if ((dist_test_sq < dist_best_sq) || (e_split == NULL)) {
+ bool ok = true;
+
+ if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) ||
+ BM_edge_exists(v_pivot, l_iter->e->v2)))
+ {
+ /* very unlikley but will cause complications splicing the verts together,
+ * so just skip this case */
+ ok = false;
+ }
+ else if (found_other_face) {
+ /* double check that _all_ the faces used by v_pivot's edges are attached to this edge
+ * otherwise don't attempt the split since it will give non-deterministic results */
+ BMLoop *l_radial_iter = l_iter->radial_next;
+ int other_face_shared = 0;
+ if (l_radial_iter != l_iter) {
+ do {
+ if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_INTERNAL_TAG)) {
+ other_face_shared++;
+ }
+ } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter);
+ }
+ if (other_face_shared != found_other_face) {
+ ok = false;
+ }
+ }
+
+ if (ok) {
+ e_split = l_iter->e;
+ dist_best_sq = dist_test_sq;
+ copy_v3_v3(r_v_pivot_co, v_pivot_co_test);
+ *r_v_pivot_fac = v_pivot_fac;
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ {
+ /* reset the flag, for future use */
+ BMFace *f;
+ while ((f = BLI_SMALLSTACK_POP(face_stack))) {
+ BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG);
+ }
+ }
+
+ return e_split;
+}
+
+#endif /* USE_NET_ISLAND_CONNECT */
+
+
static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
@@ -266,15 +615,16 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BMesh *bm = em->bm;
const char hflag = BM_ELEM_TAG;
- BMVert *v;
BMEdge *e;
- BMFace *f;
BMIter iter;
BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(v, hflag);
+ {
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_disable(v, hflag);
+ }
}
/* edge index is set to -1 then used to assosiate them with faces */
@@ -291,19 +641,28 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
}
BM_elem_index_set(e, -1); /* set_dirty */
}
+ bm->elem_index_dirty |= BM_EDGE;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(f, hflag);
- }
- else {
- BM_elem_flag_disable(f, hflag);
+ {
+ BMFace *f;
+ int i;
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(f, hflag);
+ }
+ else {
+ BM_elem_flag_disable(f, hflag);
+ }
+ BM_elem_flag_disable(f, BM_ELEM_INTERNAL_TAG);
+ BM_elem_index_set(f, i); /* set_ok */
}
}
+ bm->elem_index_dirty &= ~BM_FACE;
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, hflag)) {
BMIter viter;
+ BMVert *v;
BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
BMIter liter;
BMLoop *l;
@@ -365,18 +724,143 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- bm->elem_index_dirty |= BM_EDGE;
+ {
+ BMFace *f;
+ BLI_buffer_declare_static(BMEdge **, edge_net_temp_buf, 0, 128);
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, hflag)) {
+ bm_face_split_by_edges(bm, f, hflag, &edge_net_temp_buf);
+ }
+ }
+ BLI_buffer_free(&edge_net_temp_buf);
+ }
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, hflag)) {
- bm_face_split_by_edges(bm, f, hflag);
+#ifdef USE_NET_ISLAND_CONNECT
+ /* before overwriting edge index values, collect edges left untouched */
+ BLI_Stack *edges_loose = BLI_stack_new(sizeof(BMEdge * ), __func__);
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
+ BLI_stack_push(edges_loose, &e);
}
}
+#endif
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
+
+#ifdef USE_NET_ISLAND_CONNECT
+ /* we may have remaining isolated regions remaining,
+ * these will need to have connecting edges created */
+ if (!BLI_stack_is_empty(edges_loose)) {
+ GHash *face_edge_map = BLI_ghash_ptr_new(__func__);
+
+ MemArena *mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ {
+ BMBVHTree *bmbvh = BKE_bmbvh_new(bm, em->looptris, em->tottri, BMBVH_RESPECT_SELECT, NULL, false);
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_index_set(e, -1); /* set_dirty */
+ }
+
+ while (!BLI_stack_is_empty(edges_loose)) {
+ BLI_stack_pop(edges_loose, &e);
+ float e_center[3];
+ mid_v3_v3v3(e_center, e->v1->co, e->v2->co);
+
+ BMFace *f = BKE_bmbvh_find_face_closest(bmbvh, e_center, FLT_MAX);
+ if (f) {
+ ghash_insert_face_edge_link(face_edge_map, f, e, mem_arena);
+ BM_elem_index_set(e, BM_elem_index_get(f)); /* set_dirty */
+ }
+ }
+
+ BKE_bmbvh_free(bmbvh);
+ }
+
+ bm->elem_index_dirty |= BM_EDGE;
+
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ /* detect edges chains that span faces
+ * and splice vertices into the closest edges */
+ {
+ GHashIterator gh_iter;
+
+ GHASH_ITER(gh_iter, face_edge_map) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+ LinkNode *e_link = e_ls_base->list;
+
+ do {
+ e = e_link->link;
+
+ for (int j = 0; j < 2; j++) {
+ BMVert *v_pivot = (&e->v1)[j];
+ /* checking that \a v_pivot isn't in the face
+ * prevents attempting to splice the same vertex into an edge from multiple faces */
+ if (!BM_vert_in_face(v_pivot, f)) {
+ float v_pivot_co[3];
+ float v_pivot_fac;
+ BMEdge *e_split = bm_face_split_edge_find(
+ e, f, v_pivot, bm->ftable, bm->totface,
+ v_pivot_co, &v_pivot_fac);
+
+ if (e_split) {
+ /* for degenerate cases this vertex may be in one of this edges radial faces */
+ if (!bm_vert_in_faces_radial(v_pivot, e_split, f)) {
+ BMEdge *e_new;
+ BMVert *v_new = BM_edge_split(bm, e_split, e_split->v1, &e_new, v_pivot_fac);
+ if (v_new) {
+ /* we _know_ these don't share an edge */
+ BM_vert_splice(bm, v_pivot, v_new);
+ BM_elem_index_set(e_new, BM_elem_index_get(e_split));
+ }
+ }
+ }
+ }
+ }
+
+ } while ((e_link = e_link->next));
+ }
+ }
+
+
+ {
+ MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ GHashIterator gh_iter;
+
+ GHASH_ITER(gh_iter, face_edge_map) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+
+ bm_face_split_by_edges_island_connect(
+ bm, f,
+ e_ls_base->list, e_ls_base->list_len,
+ mem_arena_edgenet);
+
+ BLI_memarena_clear(mem_arena_edgenet);
+ }
+
+ BLI_memarena_free(mem_arena_edgenet);
+ }
+
+ BLI_memarena_free(mem_arena);
+
+ BLI_ghash_free(face_edge_map, NULL, NULL);
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ }
+
+ BLI_stack_free(edges_loose);
+#endif /* USE_NET_ISLAND_CONNECT */
+
return OPERATOR_FINISHED;
}
@@ -384,8 +868,8 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Split by Edges";
- ot->description = "Split faces by loose edges";
+ ot->name = "Weld Edges into Faces";
+ ot->description = "Weld loose edges into faces (splitting them into new faces)";
ot->idname = "MESH_OT_face_split_by_edges";
/* api callbacks */
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 787b79f0d6e..0fd56fbcc4e 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -75,6 +75,9 @@
#include "mesh_intern.h" /* own include */
+/* detect isolated holes and fill them */
+#define USE_NET_ISLAND_CONNECT
+
#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */
/* WARNING: knife float precision is fragile:
@@ -166,6 +169,15 @@ typedef struct KnifeTool_OpData {
MemArena *arena;
+ /* reused for edge-net filling */
+ struct {
+ /* cleared each use */
+ GSet *edge_visit;
+#ifdef USE_NET_ISLAND_CONNECT
+ MemArena *arena;
+#endif
+ } edgenet;
+
GHash *origvertmap;
GHash *origedgemap;
GHash *kedgefacemap;
@@ -209,6 +221,8 @@ typedef struct KnifeTool_OpData {
bool is_ortho;
float ortho_extent;
+ float ortho_extent_center[3];
+
float clipsta, clipend;
enum {
@@ -226,14 +240,8 @@ typedef struct KnifeTool_OpData {
/* use to check if we're currently dragging an angle snapped line */
bool is_angle_snapping;
-
- enum {
- ANGLE_FREE,
- ANGLE_0,
- ANGLE_45,
- ANGLE_90,
- ANGLE_135
- } angle_snapping;
+ bool angle_snapping;
+ float angle;
const float (*cagecos)[3];
} KnifeTool_OpData;
@@ -863,7 +871,6 @@ static void knife_cut_face(KnifeTool_OpData *kcd, BMFace *f, ListBase *hits)
static void knife_add_cut(KnifeTool_OpData *kcd)
{
int i;
- KnifeLineHit *lh;
GHash *facehits;
BMFace *f;
Ref *r;
@@ -881,7 +888,7 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
/* make facehits: map face -> list of linehits touching it */
facehits = BLI_ghash_ptr_new("knife facehits");
for (i = 0; i < kcd->totlinehit; i++) {
- lh = &kcd->linehits[i];
+ KnifeLineHit *lh = &kcd->linehits[i];
if (lh->f) {
add_hit_to_facehits(kcd, facehits, lh->f, lh);
}
@@ -912,15 +919,14 @@ static void knife_add_cut(KnifeTool_OpData *kcd)
if (kcd->prev.bmface) {
- KnifeLineHit *lh;
/* was "in face" but now we have a KnifeVert it is snapped to */
- lh = &kcd->linehits[kcd->totlinehit - 1];
+ KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1];
kcd->prev.vert = lh->v;
kcd->prev.bmface = NULL;
}
if (kcd->is_drag_hold) {
- lh = &kcd->linehits[kcd->totlinehit - 1];
+ KnifeLineHit *lh = &kcd->linehits[kcd->totlinehit - 1];
linehit_to_knifepos(&kcd->prev, lh);
}
@@ -941,98 +947,66 @@ static void knife_finish_cut(KnifeTool_OpData *kcd)
static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd)
{
- bglMats mats;
- double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy;
- double wminx, wminy, wmaxx, wmaxy;
-
- /* make u the window coords of prevcage */
- view3d_get_transformation(kcd->ar, kcd->vc.rv3d, kcd->ob, &mats);
- gluProject(kcd->prev.cage[0], kcd->prev.cage[1], kcd->prev.cage[2],
- mats.modelview, mats.projection, mats.viewport,
- &u[0], &u[1], &u[2]);
-
- /* make u1, u2 the points on window going through u at snap angle */
- wminx = kcd->ar->winrct.xmin;
- wmaxx = kcd->ar->winrct.xmin + kcd->ar->winx;
- wminy = kcd->ar->winrct.ymin;
- wmaxy = kcd->ar->winrct.ymin + kcd->ar->winy;
-
- switch (kcd->angle_snapping) {
- case ANGLE_0:
- u1[0] = wminx;
- u2[0] = wmaxx;
- u1[1] = u2[1] = u[1];
- break;
- case ANGLE_90:
- u1[0] = u2[0] = u[0];
- u1[1] = wminy;
- u2[1] = wmaxy;
- break;
- case ANGLE_45:
- /* clip against left or bottom */
- dx = u[0] - wminx;
- dy = u[1] - wminy;
- if (dy > dx) {
- u1[0] = wminx;
- u1[1] = u[1] - dx;
- }
- else {
- u1[0] = u[0] - dy;
- u1[1] = wminy;
- }
- /* clip against right or top */
- dx = wmaxx - u[0];
- dy = wmaxy - u[1];
- if (dy > dx) {
- u2[0] = wmaxx;
- u2[1] = u[1] + dx;
- }
- else {
- u2[0] = u[0] + dy;
- u2[1] = wmaxy;
- }
- break;
- case ANGLE_135:
- /* clip against right or bottom */
- dx = wmaxx - u[0];
- dy = u[1] - wminy;
- if (dy > dx) {
- u1[0] = wmaxx;
- u1[1] = u[1] - dx;
- }
- else {
- u1[0] = u[0] + dy;
- u1[1] = wminy;
- }
- /* clip against left or top */
- dx = u[0] - wminx;
- dy = wmaxy - u[1];
- if (dy > dx) {
- u2[0] = wminx;
- u2[1] = u[1] + dx;
- }
- else {
- u2[0] = u[0] - dy;
- u2[1] = wmaxy;
+ float v1[3], v2[3];
+ float planes[4][4];
+
+ planes_from_projmat(
+ (float (*)[4])kcd->projmat,
+ planes[2], planes[0], planes[3], planes[1], NULL, NULL);
+
+ /* ray-cast all planes */
+ {
+ float ray_dir[3];
+ float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}};
+ float lambda_best[2] = {-FLT_MAX, FLT_MAX};
+ int i;
+
+ /* we (sometimes) need the lines to be at the same depth before projecting */
+#if 0
+ sub_v3_v3v3(ray_dir, kcd->curr.cage, kcd->prev.cage);
+#else
+ {
+ float curr_cage_adjust[3];
+ float co_depth[3];
+
+ copy_v3_v3(co_depth, kcd->prev.cage);
+ mul_m4_v3(kcd->ob->obmat, co_depth);
+ ED_view3d_win_to_3d(kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust);
+ mul_m4_v3(kcd->ob->imat, curr_cage_adjust);
+
+ sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage);
+ }
+#endif
+
+ for (i = 0; i < 4; i++) {
+ float ray_hit[3];
+ float lambda_test;
+ if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) {
+ madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test);
+ if (lambda_test < 0.0f) {
+ if (lambda_test > lambda_best[0]) {
+ copy_v3_v3(ray_hit_best[0], ray_hit);
+ lambda_best[0] = lambda_test;
+ }
+ }
+ else {
+ if (lambda_test < lambda_best[1]) {
+ copy_v3_v3(ray_hit_best[1], ray_hit);
+ lambda_best[1] = lambda_test;
+ }
+ }
}
- break;
- default:
- return;
- }
+ }
- /* unproject u1 and u2 back into object space */
- gluUnProject(u1[0], u1[1], 0.0,
- mats.modelview, mats.projection, mats.viewport,
- &v1[0], &v1[1], &v1[2]);
- gluUnProject(u2[0], u2[1], 0.0,
- mats.modelview, mats.projection, mats.viewport,
- &v2[0], &v2[1], &v2[2]);
+ copy_v3_v3(v1, ray_hit_best[0]);
+ copy_v3_v3(v2, ray_hit_best[1]);
+ }
UI_ThemeColor(TH_TRANSFORM);
glLineWidth(2.0);
glBegin(GL_LINES);
- glVertex3dv(v1);
- glVertex3dv(v2);
+ glVertex3fv(v1);
+ glVertex3fv(v2);
glEnd();
}
@@ -1065,7 +1039,7 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glMultMatrixf(kcd->ob->obmat);
if (kcd->mode == MODE_DRAGGING) {
- if (kcd->angle_snapping != ANGLE_FREE)
+ if (kcd->is_angle_snapping)
knifetool_draw_angle_snapping(kcd);
glColor3ubv(kcd->colors.line);
@@ -1076,8 +1050,6 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glVertex3fv(kcd->prev.cage);
glVertex3fv(kcd->curr.cage);
glEnd();
-
- glLineWidth(1.0);
}
if (kcd->prev.vert) {
@@ -1106,8 +1078,6 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glVertex3fv(kcd->curr.edge->v1->cageco);
glVertex3fv(kcd->curr.edge->v2->cageco);
glEnd();
-
- glLineWidth(1.0);
}
else if (kcd->curr.vert) {
glColor3ubv(kcd->colors.point);
@@ -1177,7 +1147,6 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
}
glEnd();
- glLineWidth(1.0);
}
if (kcd->totkvert > 0) {
@@ -1281,20 +1250,29 @@ static bool knife_ray_intersect_face(
return false;
}
-/* Calculate maximum excursion from (0,0,0) of mesh */
+/**
+ * Calculate the center and maximum excursion of mesh.
+ */
static void calc_ortho_extent(KnifeTool_OpData *kcd)
{
BMIter iter;
BMVert *v;
BMesh *bm = kcd->em->bm;
- float max_xyz = 0.0f;
- int i;
+ float min[3], max[3];
+
+ INIT_MINMAX(min, max);
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- for (i = 0; i < 3; i++)
- max_xyz = max_ff(max_xyz, fabsf(v->co[i]));
+ if (kcd->cagecos) {
+ minmax_v3v3_v3_array(min, max, kcd->cagecos, bm->totvert);
}
- kcd->ortho_extent = max_xyz;
+ else {
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ minmax_v3v3_v3(min, max, v->co);
+ }
+ }
+
+ kcd->ortho_extent = len_v3v3(min, max) / 2;
+ mid_v3_v3v3(kcd->ortho_extent_center, min, max);
}
static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe)
@@ -1456,7 +1434,10 @@ static bool point_is_visible(
copy_v3_v3(view_clip[0], p_ofs);
madd_v3_v3v3fl(view_clip[1], p_ofs, view, dist);
- if (clip_segment_v3_plane_n(view_clip[0], view_clip[1], kcd->vc.rv3d->clip_local, 6)) {
+ if (clip_segment_v3_plane_n(
+ view_clip[0], view_clip[1], kcd->vc.rv3d->clip_local, 6,
+ view_clip[0], view_clip[1]))
+ {
dist = len_v3v3(p_ofs, view_clip[1]);
}
}
@@ -1482,14 +1463,20 @@ static bool point_is_visible(
/* Clip the line (v1, v2) to planes perpendicular to it and distances d from
* the closest point on the line to the origin */
-static void clip_to_ortho_planes(float v1[3], float v2[3], float d)
+static void clip_to_ortho_planes(float v1[3], float v2[3], const float center[3], const float d)
{
- float closest[3];
- const float origin[3] = {0.0f, 0.0f, 0.0f};
+ float closest[3], dir[3];
+
+ sub_v3_v3v3(dir, v1, v2);
+ normalize_v3(dir);
- closest_to_line_v3(closest, origin, v1, v2);
- dist_ensure_v3_v3fl(v1, closest, d);
- dist_ensure_v3_v3fl(v2, closest, d);
+ /* could be v1 or v2 */
+ sub_v3_v3(v1, center);
+ project_plane_v3_v3v3(closest, v1, dir);
+ add_v3_v3(closest, center);
+
+ madd_v3_v3v3fl(v1, closest, dir, d);
+ madd_v3_v3v3fl(v2, closest, dir, -d);
}
static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh)
@@ -1573,8 +1560,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
if (kcd->ortho_extent == 0.0f)
calc_ortho_extent(kcd);
- clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f);
- clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f);
+ clip_to_ortho_planes(v1, v3, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
+ clip_to_ortho_planes(v2, v4, kcd->ortho_extent_center, kcd->ortho_extent + 10.0f);
}
/* First use bvh tree to find faces, knife edges, and knife verts that might
@@ -1632,9 +1619,18 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
/* Now go through the candidates and find intersections */
/* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */
- vert_tol = KNIFE_FLT_EPS_PX_VERT;
- line_tol = KNIFE_FLT_EPS_PX_EDGE;
- face_tol = KNIFE_FLT_EPS_PX_FACE;
+ if (kcd->is_interactive) {
+ vert_tol = KNIFE_FLT_EPS_PX_VERT;
+ line_tol = KNIFE_FLT_EPS_PX_EDGE;
+ face_tol = KNIFE_FLT_EPS_PX_FACE;
+ }
+ else {
+ /* Use 1/100th of a pixel, see T43896 (too big), T47910 (too small).
+ *
+ * Update, leave this as is until we investigate not using pixel coords for geometry calculations: T48023
+ */
+ vert_tol = line_tol = face_tol = 0.5f;
+ }
vert_tol_sq = vert_tol * vert_tol;
line_tol_sq = line_tol * line_tol;
@@ -1657,8 +1653,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
hit.v = v;
/* If this isn't from an existing BMVert, it may have been added to a BMEdge originally.
- * knowing if the hit comes from an edge is important for edge-in-face checks later on
- * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */
+ * knowing if the hit comes from an edge is important for edge-in-face checks later on
+ * see: #knife_add_single_cut -> #knife_verts_edge_in_face, T42611 */
if (kfe_hit) {
hit.kfe = kfe_hit;
}
@@ -1693,7 +1689,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
knife_project_v2(kcd, kfe->v2->cageco, se2);
isect_kind = (kfe_verts_in_cut) ? -1 : isect_seg_seg_v2_point(s1, s2, se1, se2, sint);
if (isect_kind == -1) {
- /* isect_seg_seg_v2 doesn't do tolerance test around ends of s1-s2 */
+ /* isect_seg_seg_v2_simple doesn't do tolerance test around ends of s1-s2 */
closest_to_line_segment_v2(sint, s1, se1, se2);
if (len_squared_v2v2(sint, s1) <= line_tol_sq)
isect_kind = 1;
@@ -1895,17 +1891,7 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius
* surrounding mesh (in screen space)*/
static float knife_snap_size(KnifeTool_OpData *kcd, float maxsize)
{
- float density;
-
- if (kcd->is_interactive) {
- density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f);
- }
- else {
- density = 1.0f;
- }
-
- if (density < 1.0f)
- density = 1.0f;
+ float density = (float)knife_sample_screen_density(kcd, maxsize * 2.0f);
return min_ff(maxsize / (density * 0.5f), maxsize);
}
@@ -1916,10 +1902,18 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
{
BMFace *f;
float co[3], cageco[3], sco[2];
- float maxdist = knife_snap_size(kcd, kcd->ethresh);
+ float maxdist;
- if (kcd->ignore_vert_snapping)
- maxdist *= 0.5f;
+ if (kcd->is_interactive) {
+ maxdist = knife_snap_size(kcd, kcd->ethresh);
+
+ if (kcd->ignore_vert_snapping) {
+ maxdist *= 0.5f;
+ }
+ }
+ else {
+ maxdist = KNIFE_FLT_EPS;
+ }
f = knife_find_closest_face(kcd, co, cageco, NULL);
*is_space = !f;
@@ -2039,10 +2033,18 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
bool *is_space)
{
BMFace *f;
- float co[3], cageco[3], sco[2], maxdist = knife_snap_size(kcd, kcd->vthresh);
+ float co[3], cageco[3], sco[2];
+ float maxdist;
- if (kcd->ignore_vert_snapping)
- maxdist *= 0.5f;
+ if (kcd->is_interactive) {
+ maxdist = knife_snap_size(kcd, kcd->vthresh);
+ if (kcd->ignore_vert_snapping) {
+ maxdist *= 0.5f;
+ }
+ }
+ else {
+ maxdist = KNIFE_FLT_EPS;
+ }
f = knife_find_closest_face(kcd, co, cageco, is_space);
@@ -2124,42 +2126,41 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
return NULL;
}
+/**
+ * Snaps a 2d vector to an angle, relative to \a v_ref.
+ */
+static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], float angle_snap)
+{
+ float m2[2][2];
+ float v_unit[2];
+ float angle, angle_delta;
+
+ BLI_ASSERT_UNIT_V2(v_ref);
+
+ normalize_v2_v2(v_unit, v);
+ angle = angle_signed_v2v2(v_unit, v_ref);
+ angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle;
+ rotate_m2(m2, angle_delta);
+
+ mul_v2_m2v2(r, m2, v);
+ return angle + angle_delta;
+}
+
/* update both kcd->curr.mval and kcd->mval to snap to required angle */
static bool knife_snap_angle(KnifeTool_OpData *kcd)
{
- float dx, dy;
- float w, abs_tan;
+ const float dvec_ref[2] = {0.0f, 1.0f};
+ float dvec[2], dvec_snap[2];
+ float snap_step = DEG2RADF(45);
- dx = kcd->curr.mval[0] - kcd->prev.mval[0];
- dy = kcd->curr.mval[1] - kcd->prev.mval[1];
- if (dx == 0.0f && dy == 0.0f)
+ sub_v2_v2v2(dvec, kcd->curr.mval, kcd->prev.mval);
+ if (is_zero_v2(dvec)) {
return false;
-
- if (dx == 0.0f) {
- kcd->angle_snapping = ANGLE_90;
- kcd->curr.mval[0] = kcd->prev.mval[0];
}
- w = dy / dx;
- abs_tan = fabsf(w);
- if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */
- kcd->angle_snapping = ANGLE_0;
- kcd->curr.mval[1] = kcd->prev.mval[1];
- }
- else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */
- if (w > 0) {
- kcd->angle_snapping = ANGLE_45;
- kcd->curr.mval[1] = kcd->prev.mval[1] + dx;
- }
- else {
- kcd->angle_snapping = ANGLE_135;
- kcd->curr.mval[1] = kcd->prev.mval[1] - dx;
- }
- }
- else {
- kcd->angle_snapping = ANGLE_90;
- kcd->curr.mval[0] = kcd->prev.mval[0];
- }
+ kcd->angle = snap_v2_angle(dvec_snap, dvec, dvec_ref, snap_step);
+
+ add_v2_v2v2(kcd->curr.mval, kcd->prev.mval, dvec_snap);
copy_v2_v2(kcd->mval, kcd->curr.mval);
@@ -2175,7 +2176,7 @@ static int knife_update_active(KnifeTool_OpData *kcd)
/* view matrix may have changed, reproject */
knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval);
- if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) {
+ if (kcd->angle_snapping && (kcd->mode == MODE_DRAGGING)) {
kcd->is_angle_snapping = knife_snap_angle(kcd);
}
else {
@@ -2229,330 +2230,6 @@ static int sort_verts_by_dist_cb(void *co_p, const void *cur_a_p, const void *cu
else return 0;
}
-/* The chain so far goes from an instantiated vertex to kfv (some may be reversed).
- * If possible, complete the chain to another instantiated vertex and return 1, else return 0.
- * The visited hash says which KnifeVert's have already been tried, not including kfv. */
-static bool find_chain_search(KnifeTool_OpData *kcd, KnifeVert *kfv, ListBase *fedges, SmallHash *visited,
- ListBase *chain)
-{
- Ref *r;
- KnifeEdge *kfe;
- KnifeVert *kfv_other;
-
- if (kfv->v)
- return true;
-
- BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
- /* Try all possible next edges. Could either go through fedges
- * (all the KnifeEdges for the face being cut) or could go through
- * kve->edges and restrict to cutting face and uninstantiated edges.
- * Not clear which is better. Let's do the first. */
- for (r = fedges->first; r; r = r->next) {
- kfe = r->ref;
- kfv_other = NULL;
- if (kfe->v1 == kfv)
- kfv_other = kfe->v2;
- else if (kfe->v2 == kfv)
- kfv_other = kfe->v1;
- if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
- knife_append_list(kcd, chain, kfe);
- if (find_chain_search(kcd, kfv_other, fedges, visited, chain))
- return true;
- BLI_remlink(chain, chain->last);
- }
- }
- return false;
-}
-
-static ListBase *find_chain_from_vertex(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMVert *v, ListBase *fedges)
-{
- SmallHash visited_, *visited = &visited_;
- ListBase *ans;
- bool found;
-
- ans = knife_empty_list(kcd);
- knife_append_list(kcd, ans, kfe);
- found = false;
- BLI_smallhash_init(visited);
- if (kfe->v1->v == v) {
- BLI_smallhash_insert(visited, (uintptr_t)(kfe->v1), NULL);
- found = find_chain_search(kcd, kfe->v2, fedges, visited, ans);
- }
- else {
- BLI_assert(kfe->v2->v == v);
- BLI_smallhash_insert(visited, (uintptr_t)(kfe->v2), NULL);
- found = find_chain_search(kcd, kfe->v1, fedges, visited, ans);
- }
-
- BLI_smallhash_release(visited);
-
- if (found)
- return ans;
- else
- return NULL;
-}
-
-/* Find a chain in fedges from one instantiated vertex to another.
- * Remove the edges in the chain from fedges and return a separate list of the chain. */
-static ListBase *find_chain(KnifeTool_OpData *kcd, ListBase *fedges)
-{
- Ref *r, *ref;
- KnifeEdge *kfe;
- BMVert *v1, *v2;
- ListBase *ans;
-
- ans = NULL;
-
- for (r = fedges->first; r; r = r->next) {
- kfe = r->ref;
- v1 = kfe->v1->v;
- v2 = kfe->v2->v;
- if (v1 && v2) {
- ans = knife_empty_list(kcd);
- knife_append_list(kcd, ans, kfe);
- break;
- }
- if (v1)
- ans = find_chain_from_vertex(kcd, kfe, v1, fedges);
- else if (v2)
- ans = find_chain_from_vertex(kcd, kfe, v2, fedges);
- if (ans)
- break;
- }
- if (ans) {
- BLI_assert(!BLI_listbase_is_empty(ans));
- for (r = ans->first; r; r = r->next) {
- ref = find_ref(fedges, r->ref);
- BLI_assert(ref != NULL);
- BLI_remlink(fedges, ref);
- }
- }
- return ans;
-}
-
-/* The hole so far goes from kfvfirst to kfv (some may be reversed).
- * If possible, complete the hole back to kfvfirst and return 1, else return 0.
- * The visited hash says which KnifeVert's have already been tried, not including kfv or kfvfirst. */
-static bool find_hole_search(KnifeTool_OpData *kcd, KnifeVert *kfvfirst, KnifeVert *kfv, ListBase *fedges,
- SmallHash *visited, ListBase *hole)
-{
- Ref *r;
- KnifeEdge *kfe, *kfelast;
- KnifeVert *kfv_other;
-
- if (kfv == kfvfirst)
- return true;
-
- BLI_smallhash_insert(visited, (uintptr_t)kfv, NULL);
- kfelast = ((Ref *)hole->last)->ref;
- for (r = fedges->first; r; r = r->next) {
- kfe = r->ref;
- if (kfe == kfelast)
- continue;
- if (kfe->v1->v || kfe->v2->v)
- continue;
- kfv_other = NULL;
- if (kfe->v1 == kfv)
- kfv_other = kfe->v2;
- else if (kfe->v2 == kfv)
- kfv_other = kfe->v1;
- if (kfv_other && !BLI_smallhash_haskey(visited, (uintptr_t)kfv_other)) {
- knife_append_list(kcd, hole, kfe);
- if (find_hole_search(kcd, kfvfirst, kfv_other, fedges, visited, hole))
- return true;
- BLI_remlink(hole, hole->last);
- }
- }
- return false;
-}
-
-/* Find a hole (simple cycle with no instantiated vertices).
- * Remove the edges in the cycle from fedges and return a separate list of the cycle */
-static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges)
-{
- ListBase *ans;
- Ref *r, *ref;
- KnifeEdge *kfe;
- SmallHash visited_, *visited = &visited_;
- bool found;
-
- ans = NULL;
- found = false;
-
- for (r = fedges->first; r && !found; r = r->next) {
- kfe = r->ref;
- if (kfe->v1->v || kfe->v2->v || kfe->v1 == kfe->v2)
- continue;
-
- BLI_smallhash_init(visited);
- ans = knife_empty_list(kcd);
- knife_append_list(kcd, ans, kfe);
-
- found = find_hole_search(kcd, kfe->v1, kfe->v2, fedges, visited, ans);
-
- BLI_smallhash_release(visited);
- }
-
- if (found) {
- for (r = ans->first; r; r = r->next) {
- kfe = r->ref;
- ref = find_ref(fedges, r->ref);
- if (ref)
- BLI_remlink(fedges, ref);
- }
- return ans;
- }
- else {
- return NULL;
- }
-}
-
-/* Try to find "nice" diagonals - short, and far apart from each other.
- * If found, return true and make a 'main chain' going across f which uses
- * the two diagonals and one part of the hole, and a 'side chain' that
- * completes the hole. */
-static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, ListBase **mainchain,
- ListBase **sidechain)
-{
- float (*fco)[2], (*hco)[2];
- BMVert **fv;
- KnifeVert **hv;
- KnifeEdge **he;
- Ref *r;
- KnifeVert *kfv, *kfvother;
- KnifeEdge *kfe;
- ListBase *chain;
- BMVert *v;
- BMIter iter;
- int nh, nf, i, j, k, m, ax, ay, sep = 0 /* Quite warnings */, bestsep;
- int besti[2], bestj[2];
- float dist_sq, dist_best_sq;
-
- nh = BLI_listbase_count(hole);
- nf = f->len;
- if (nh < 2 || nf < 3)
- return false;
-
- /* Gather 2d projections of hole and face vertex coordinates.
- * Use best-axis projection - not completely accurate, maybe revisit */
- axis_dominant_v3(&ax, &ay, f->no);
- hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float[2]));
- fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float[2]));
- hv = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeVert *));
- fv = BLI_memarena_alloc(kcd->arena, nf * sizeof(BMVert *));
- he = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeEdge *));
-
- i = 0;
- kfv = NULL;
- kfvother = NULL;
- for (r = hole->first; r; r = r->next) {
- kfe = r->ref;
- he[i] = kfe;
- if (kfvother == NULL) {
- kfv = kfe->v1;
- }
- else {
- kfv = kfvother;
- BLI_assert(kfv == kfe->v1 || kfv == kfe->v2);
- }
- hco[i][0] = kfv->co[ax];
- hco[i][1] = kfv->co[ay];
- hv[i] = kfv;
- kfvother = (kfe->v1 == kfv) ? kfe->v2 : kfe->v1;
- i++;
- }
-
- j = 0;
- BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
- fco[j][0] = v->co[ax];
- fco[j][1] = v->co[ay];
- fv[j] = v;
- j++;
- }
-
- /* For first diagonal (m == 0), want shortest length.
- * For second diagonal (m == 1), want max separation of index of hole
- * vertex from the hole vertex used in the first diagonal, and from there
- * want the one with shortest length not to the same vertex as the first diagonal. */
- for (m = 0; m < 2; m++) {
- besti[m] = -1;
- bestj[m] = -1;
- dist_best_sq = FLT_MAX;
- bestsep = 0;
- for (i = 0; i < nh; i++) {
- if (m == 1) {
- if (i == besti[0])
- continue;
- sep = (i + nh - besti[0]) % nh;
- sep = MIN2(sep, nh - sep);
- if (sep < bestsep)
- continue;
- dist_best_sq = FLT_MAX;
- }
- for (j = 0; j < nf; j++) {
- bool ok;
-
- if (m == 1 && j == bestj[0])
- continue;
- dist_sq = len_squared_v2v2(hco[i], fco[j]);
- if (dist_sq > dist_best_sq)
- continue;
-
- ok = true;
- for (k = 0; k < nh && ok; k++) {
- if (k == i || (k + 1) % nh == i)
- continue;
- if (isect_line_line_v2(hco[i], fco[j], hco[k], hco[(k + 1) % nh]))
- ok = false;
- }
- if (!ok)
- continue;
- for (k = 0; k < nf && ok; k++) {
- if (k == j || (k + 1) % nf == j)
- continue;
- if (isect_line_line_v2(hco[i], fco[j], fco[k], fco[(k + 1) % nf]))
- ok = false;
- }
- if (ok) {
- besti[m] = i;
- bestj[m] = j;
- if (m == 1)
- bestsep = sep;
- dist_best_sq = dist_sq;
- }
- }
- }
- }
-
- if (besti[0] != -1 && besti[1] != -1) {
- BLI_assert(besti[0] != besti[1] && bestj[0] != bestj[1]);
- kfe = new_knife_edge(kcd);
- kfe->v1 = get_bm_knife_vert(kcd, fv[bestj[0]]);
- kfe->v2 = hv[besti[0]];
- chain = knife_empty_list(kcd);
- knife_append_list(kcd, chain, kfe);
- for (i = besti[0]; i != besti[1]; i = (i + 1) % nh) {
- knife_append_list(kcd, chain, he[i]);
- }
- kfe = new_knife_edge(kcd);
- kfe->v1 = hv[besti[1]];
- kfe->v2 = get_bm_knife_vert(kcd, fv[bestj[1]]);
- knife_append_list(kcd, chain, kfe);
- *mainchain = chain;
-
- chain = knife_empty_list(kcd);
- for (i = besti[1]; i != besti[0]; i = (i + 1) % nh) {
- knife_append_list(kcd, chain, he[i]);
- }
- *sidechain = chain;
-
- return true;
- }
- else {
- return false;
- }
-}
-
static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
{
bool v1_inside, v2_inside;
@@ -2596,202 +2273,119 @@ static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
return false;
}
-static bool knife_edge_in_face(KnifeEdge *kfe, BMFace *f)
-{
- return knife_verts_edge_in_face(kfe->v1, kfe->v2, f);
-}
-
-/* Split face f with KnifeEdges on chain. f remains as one side, the face formed is put in *newface.
- * The new face will be on the left side of the chain as viewed from the normal-out side of f. */
-static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *chain, BMFace **r_f_new)
+static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
{
BMesh *bm = kcd->em->bm;
- KnifeEdge *kfe, *kfelast;
- BMVert *v1, *v2;
- BMLoop *l_v1, *l_v2;
- BMFace *f_new;
+ KnifeEdge *kfe;
Ref *ref;
- KnifeVert *kfv, *kfvprev;
- BMLoop *l_new, *l_iter;
+ int edge_array_len = BLI_listbase_count(kfedges);
int i;
- int nco = BLI_listbase_count(chain) - 1;
- float (*cos)[3] = BLI_array_alloca(cos, nco);
- KnifeVert **kverts = BLI_array_alloca(kverts, nco);
-
- kfe = ((Ref *)chain->first)->ref;
- v1 = kfe->v1->v ? kfe->v1->v : kfe->v2->v;
- kfelast = ((Ref *)chain->last)->ref;
- v2 = kfelast->v2->v ? kfelast->v2->v : kfelast->v1->v;
- BLI_assert(v1 != NULL && v2 != NULL);
- kfvprev = kfe->v1->v == v1 ? kfe->v1 : kfe->v2;
- for (ref = chain->first, i = 0; i < nco && ref != chain->last; ref = ref->next, i++) {
+
+ BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len);
+
+ /* point to knife edges we've created edges in, edge_array aligned */
+ KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len);
+
+ BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0);
+
+ i = 0;
+ for (ref = kfedges->first; ref; ref = ref->next) {
+ bool is_new_edge = false;
kfe = ref->ref;
- BLI_assert(kfvprev == kfe->v1 || kfvprev == kfe->v2);
- kfv = kfe->v1 == kfvprev ? kfe->v2 : kfe->v1;
- copy_v3_v3(cos[i], kfv->co);
- kverts[i] = kfv;
- kfvprev = kfv;
- }
- BLI_assert(i == nco);
- l_new = NULL;
- if ((l_v1 = BM_face_vert_share_loop(f, v1)) &&
- (l_v2 = BM_face_vert_share_loop(f, v2)))
- {
- if (nco == 0) {
- /* Want to prevent creating two-sided polygons */
- if (v1 == v2 || BM_edge_exists(v1, v2)) {
- f_new = NULL;
+ if (kfe->e == NULL) {
+ if (kfe->v1->v && kfe->v2->v) {
+ kfe->e = BM_edge_exists(kfe->v1->v, kfe->v2->v);
}
- else {
- f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true);
+ }
+
+ if (kfe->e) {
+ if (BM_edge_in_face(kfe->e, f)) {
+ /* shouldn't happen, but in this case - just ignore */
+ continue;
}
}
else {
- f_new = BM_face_split_n(bm, f, l_v1, l_v2, cos, nco, &l_new, NULL);
- if (f_new) {
- /* Now go through lnew chain matching up chain kv's and assign real v's to them */
- for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
- BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
- if (kcd->select_result) {
- BM_edge_select_set(bm, l_iter->e, true);
- }
- kverts[i]->v = l_iter->v;
+ if (kfe->v1->v == NULL) {
+ kfe->v1->v = BM_vert_create(bm, kfe->v1->co, NULL, 0);
+ }
+ if (kfe->v2->v == NULL) {
+ kfe->v2->v = BM_vert_create(bm, kfe->v2->co, NULL, 0);
+ }
+ BLI_assert(kfe->e == NULL);
+ kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, 0);
+ if (kfe->e) {
+ if (kcd->select_result || BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_edge_select_set(bm, kfe->e, true);
}
+ is_new_edge = true;
}
}
- }
- else {
- f_new = NULL;
- }
- /* the select chain above doesnt account for the first loop */
- if (kcd->select_result) {
- if (l_new) {
- BM_edge_select_set(bm, l_new->e, true);
+ BLI_assert(kfe->e);
+
+ if (BLI_gset_add(kcd->edgenet.edge_visit, kfe->e)) {
+ kfe_array[i] = is_new_edge ? kfe : 0;
+ edge_array[i] = kfe->e;
+ i += 1;
}
}
- else if (f_new) {
- BM_elem_select_copy(bm, bm, f_new, f);
- }
- *r_f_new = f_new;
-}
+ if (i) {
+ const int edge_array_len_orig = i;
+ edge_array_len = i;
-static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfedges)
-{
- BMesh *bm = kcd->em->bm;
- KnifeEdge *kfe;
- BMFace *fnew, *fnew2, *fhole;
- ListBase *chain, *hole, *sidechain;
- Ref *ref, *refnext;
- int count, oldcount;
-
- oldcount = BLI_listbase_count(kfedges);
- while ((chain = find_chain(kcd, kfedges)) != NULL) {
- ListBase fnew_kfedges;
- knife_make_chain_cut(kcd, f, chain, &fnew);
- if (!fnew) {
- return;
- }
-
- /* Move kfedges to fnew_kfedges if they are now in fnew.
- * The chain edges were removed already */
- BLI_listbase_clear(&fnew_kfedges);
- for (ref = kfedges->first; ref; ref = refnext) {
- kfe = ref->ref;
- refnext = ref->next;
- if (knife_edge_in_face(kfe, fnew)) {
- BLI_remlink(kfedges, ref);
- kfe->basef = fnew;
- BLI_addtail(&fnew_kfedges, ref);
- }
- else if (!knife_edge_in_face(kfe, f)) {
- /* Concave ngon's - this edge might not be in either faces, T41730 */
- BLI_remlink(kfedges, ref);
+#ifdef USE_NET_ISLAND_CONNECT
+ unsigned int edge_array_holes_len;
+ BMEdge **edge_array_holes;
+ if (BM_face_split_edgenet_connect_islands(
+ bm, f,
+ edge_array, edge_array_len,
+ true,
+ kcd->edgenet.arena,
+ &edge_array_holes, &edge_array_holes_len))
+ {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ for (i = edge_array_len; i < edge_array_holes_len; i++) {
+ BM_edge_select_set(bm, edge_array_holes[i], true);
+ }
}
- }
- if (fnew_kfedges.first)
- knife_make_face_cuts(kcd, fnew, &fnew_kfedges);
- /* find_chain should always remove edges if it returns true,
- * but guard against infinite loop anyway */
- count = BLI_listbase_count(kfedges);
- if (count >= oldcount) {
- BLI_assert(!"knife find_chain infinite loop");
- return;
+ edge_array_len = edge_array_holes_len;
+ edge_array = edge_array_holes; /* owned by the arena */
}
- oldcount = count;
- }
+#endif
- while ((hole = find_hole(kcd, kfedges)) != NULL) {
- if (find_hole_chains(kcd, hole, f, &chain, &sidechain)) {
- ListBase fnew_kfedges, fnew2_kfedges;
+ {
+ BMFace **face_arr = NULL;
+ int face_arr_len;
- /* chain goes across f and sidechain comes back
- * from the second last vertex to the second vertex.
- */
- knife_make_chain_cut(kcd, f, chain, &fnew);
- if (!fnew) {
- BLI_assert(!"knife failed hole cut");
- return;
- }
- kfe = ((Ref *)sidechain->first)->ref;
- if (knife_edge_in_face(kfe, f)) {
- knife_make_chain_cut(kcd, f, sidechain, &fnew2);
- if (fnew2 == NULL) {
- return;
- }
- fhole = f;
- }
- else if (knife_edge_in_face(kfe, fnew)) {
- knife_make_chain_cut(kcd, fnew, sidechain, &fnew2);
- if (fnew2 == NULL) {
- return;
- }
- fhole = fnew2;
- }
- else {
- /* shouldn't happen except in funny edge cases */
- return;
+ BM_face_split_edgenet(
+ bm, f, edge_array, edge_array_len,
+ &face_arr, &face_arr_len);
+
+ if (face_arr) {
+ MEM_freeN(face_arr);
}
- BM_face_kill(bm, fhole);
- /* Move kfedges to either fnew or fnew2 if appropriate.
- * The hole edges were removed already */
- BLI_listbase_clear(&fnew_kfedges);
- BLI_listbase_clear(&fnew2_kfedges);
- for (ref = kfedges->first; ref; ref = refnext) {
- kfe = ref->ref;
- refnext = ref->next;
- if (knife_edge_in_face(kfe, fnew)) {
- BLI_remlink(kfedges, ref);
- kfe->basef = fnew;
- BLI_addtail(&fnew_kfedges, ref);
- }
- else if (knife_edge_in_face(kfe, fnew2)) {
- BLI_remlink(kfedges, ref);
- kfe->basef = fnew2;
- BLI_addtail(&fnew2_kfedges, ref);
+ }
+
+ /* remove dangling edges, not essential - but nice for users */
+ for (i = 0; i < edge_array_len_orig; i++) {
+ if (kfe_array[i]) {
+ if (BM_edge_is_wire(kfe_array[i]->e)) {
+ BM_edge_kill(bm, kfe_array[i]->e);
+ kfe_array[i]->e = NULL;
}
}
- /* We'll skip knife edges that are in the newly formed hole.
- * (Maybe we shouldn't have made a hole in the first place?) */
- if (fnew != fhole && fnew_kfedges.first)
- knife_make_face_cuts(kcd, fnew, &fnew_kfedges);
- if (fnew2 != fhole && fnew2_kfedges.first)
- knife_make_face_cuts(kcd, fnew2, &fnew2_kfedges);
- if (f == fhole)
- break;
- /* find_hole should always remove edges if it returns true,
- * but guard against infinite loop anyway */
- count = BLI_listbase_count(kfedges);
- if (count >= oldcount) {
- BLI_assert(!"knife find_hole infinite loop");
- return;
- }
- oldcount = count;
}
+
+
+#ifdef USE_NET_ISLAND_CONNECT
+ BLI_memarena_clear(kcd->edgenet.arena);
+#endif
}
+
+ BLI_gset_clear(kcd->edgenet.edge_visit, NULL);
}
/* Use the network of KnifeEdges and KnifeVerts accumulated to make real BMVerts and BMEdedges */
@@ -2939,6 +2533,10 @@ static void knifetool_exit_ex(bContext *C, KnifeTool_OpData *kcd)
BLI_ghash_free(kcd->facetrimap, NULL, NULL);
BLI_memarena_free(kcd->arena);
+#ifdef USE_NET_ISLAND_CONNECT
+ BLI_memarena_free(kcd->edgenet.arena);
+#endif
+ BLI_gset_free(kcd->edgenet.edge_visit, NULL);
/* tag for redraw */
ED_region_tag_redraw(kcd->ar);
@@ -3024,6 +2622,11 @@ static void knifetool_init(bContext *C, KnifeTool_OpData *kcd,
knifetool_init_bmbvh(kcd);
kcd->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), "knife");
+#ifdef USE_NET_ISLAND_CONNECT
+ kcd->edgenet.arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 15), __func__);
+#endif
+ kcd->edgenet.edge_visit = BLI_gset_ptr_new(__func__);
+
kcd->vthresh = KMAXDIST - 1;
kcd->ethresh = KMAXDIST;
@@ -3365,43 +2968,6 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
/* Knife tool as a utility function
* that can be used for internal slicing operations */
-/**
- * Return a point inside the face.
- *
- * tessellation here seems way overkill,
- * but without this its very hard to know of a point is inside the face
- */
-static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3])
-{
- const int tottri = f->len - 2;
- BMLoop **loops = BLI_array_alloca(loops, f->len);
- unsigned int (*index)[3] = BLI_array_alloca(index, tottri);
- int j;
- int j_best = 0; /* use as fallback when unset */
- float area_best = -1.0f;
-
- BM_face_calc_tessellation(f, loops, index);
-
- for (j = 0; j < tottri; j++) {
- const float *p1 = loops[index[j][0]]->v->co;
- const float *p2 = loops[index[j][1]]->v->co;
- const float *p3 = loops[index[j][2]]->v->co;
- float area;
-
- area = area_squared_tri_v3(p1, p2, p3);
- if (area > area_best) {
- j_best = j;
- area_best = area;
- }
- }
-
- mid_v3_v3v3v3(
- r_cent,
- loops[index[j_best][0]]->v->co,
- loops[index[j_best][1]]->v->co,
- loops[index[j_best][2]]->v->co);
-}
-
static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2])
{
LinkNode *p = polys;
@@ -3519,7 +3085,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
BMIter fiter;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
float cent[3], cent_ss[2];
- edbm_mesh_knife_face_point(f, cent);
+ BM_face_calc_point_in_face(f, cent);
knife_project_v2(kcd, cent, cent_ss);
if (edbm_mesh_knife_point_isect(polys, cent_ss)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
@@ -3555,7 +3121,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug
if (found) {
float cent[3], cent_ss[2];
- edbm_mesh_knife_face_point(f, cent);
+ BM_face_calc_point_in_face(f, cent);
knife_project_v2(kcd, cent, cent_ss);
if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) &&
edbm_mesh_knife_point_isect(polys, cent_ss))
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index c612ebfcc24..c35a36069a7 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -117,8 +117,6 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glVertexPointer(3, GL_FLOAT, 0, lcd->points);
glDrawArrays(GL_POINTS, 0, lcd->totpoint);
glDisableClientState(GL_VERTEX_ARRAY);
-
- glPointSize(1.0f);
}
glPopMatrix();
@@ -401,7 +399,7 @@ static void ringsel_finish(bContext *C, wmOperator *op)
{
RingSelOpData *lcd = op->customdata;
const int cuts = RNA_int_get(op->ptr, "number_cuts");
- const float smoothness = 0.292f * RNA_float_get(op->ptr, "smoothness");
+ const float smoothness = RNA_float_get(op->ptr, "smoothness");
const int smooth_falloff = RNA_enum_get(op->ptr, "falloff");
#ifdef BMW_EDGERING_NGON
const bool use_only_quads = false;
@@ -854,7 +852,7 @@ void MESH_OT_loopcut(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_property(ot->srna, "falloff", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
RNA_def_property_enum_default(prop, PROP_INVSQUARE);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index 72dfb89e5f3..55ed0e521ea 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -53,6 +53,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "bmesh.h"
@@ -60,10 +61,43 @@
#include "mesh_intern.h" /* own include */
+struct PathSelectParams {
+ bool track_active; /* ensure the active element is the last selected item (handy for picking) */
+ bool use_topology_distance;
+ bool use_face_step;
+ bool use_fill;
+ char edge_mode;
+ struct CheckerIntervalParams interval_params;
+};
+
+static void path_select_properties(wmOperatorType *ot)
+{
+ RNA_def_boolean(
+ ot->srna, "use_face_step", false, "Face Stepping",
+ "Traverse connected faces (includes diagonals and edge-rings)");
+ RNA_def_boolean(
+ ot->srna, "use_topology_distance", false, "Topology Distance",
+ "Find the minimum number of steps, ignoring spatial distance");
+ RNA_def_boolean(
+ ot->srna, "use_fill", false, "Fill Region",
+ "Select all paths between the source/destination elements");
+ WM_operator_properties_checker_interval(ot, true);
+}
+
+static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params)
+{
+ op_params->edge_mode = EDGE_MODE_SELECT;
+ op_params->track_active = false;
+ op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
+ op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
+ op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
+ WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params);
+}
+
struct UserData {
BMesh *bm;
Mesh *me;
- Scene *scene;
+ const struct PathSelectParams *op_params;
};
/* -------------------------------------------------------------------- */
@@ -84,70 +118,90 @@ static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
BM_vert_select_set(user_data->bm, v, val);
}
-static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
+static void mouse_mesh_shortest_path_vert(
+ Scene *scene, const struct PathSelectParams *op_params,
+ BMVert *v_act, BMVert *v_dst)
{
- /* unlike edge/face versions, this uses a bmesh operator */
-
- BMEditMesh *em = vc->em;
+ Object *obedit = scene->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
- BMVert *v_dst;
- float dist = ED_view3d_select_dist_px();
- const bool use_length = true;
- v_dst = EDBM_vert_find_nearest(vc, &dist);
- if (v_dst) {
- struct UserData user_data = {bm, vc->obedit->data, vc->scene};
- LinkNode *path = NULL;
- BMVert *v_act = BM_mesh_active_vert_get(bm);
+ struct UserData user_data = {bm, obedit->data, op_params};
+ LinkNode *path = NULL;
+ bool is_path_ordered = false;
- if (v_act && (v_act != v_dst)) {
- if ((path = BM_mesh_calc_path_vert(bm, v_act, v_dst, use_length,
- verttag_filter_cb, &user_data)))
- {
- BM_select_history_remove(bm, v_act);
- }
+ if (v_act && (v_act != v_dst)) {
+ if (op_params->use_fill) {
+ path = BM_mesh_calc_path_region_vert(
+ bm, (BMElem *)v_act, (BMElem *)v_dst,
+ verttag_filter_cb, &user_data);
+ }
+ else {
+ is_path_ordered = true;
+ path = BM_mesh_calc_path_vert(
+ bm, v_act, v_dst,
+ &(const struct BMCalcPathParams) {
+ .use_topology_distance = op_params->use_topology_distance,
+ .use_step_face = op_params->use_face_step,
+ },
+ verttag_filter_cb, &user_data);
}
if (path) {
- /* toggle the flag */
- bool all_set = true;
- LinkNode *node;
-
- node = path;
- do {
- if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
- all_set = false;
- break;
- }
- } while ((node = node->next));
-
- node = path;
- do {
- verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
- } while ((node = node->next));
-
- BLI_linklist_free(path, NULL);
- }
- else {
- const bool is_act = !verttag_test_cb(v_dst, &user_data);
- verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
+ if (op_params->track_active) {
+ BM_select_history_remove(bm, v_act);
+ }
}
+ }
- EDBM_selectmode_flush(em);
+ BMVert *v_dst_last = v_dst;
- /* even if this is selected it may not be in the selection list */
- if (BM_elem_flag_test(v_dst, BM_ELEM_SELECT) == 0)
- BM_select_history_remove(bm, v_dst);
- else
- BM_select_history_store(bm, v_dst);
+ if (path) {
+ /* toggle the flag */
+ bool all_set = true;
+ LinkNode *node;
- EDBM_update_generic(em, false, false);
+ node = path;
+ do {
+ if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
+ all_set = false;
+ break;
+ }
+ } while ((node = node->next));
- return true;
+ int depth = 1;
+ node = path;
+ do {
+ if ((is_path_ordered == false) ||
+ WM_operator_properties_checker_interval_test(&op_params->interval_params, depth))
+ {
+ verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
+ if (is_path_ordered) {
+ v_dst_last = node->link;
+ }
+ }
+ } while ((void)depth++, (node = node->next));
+
+ BLI_linklist_free(path, NULL);
}
else {
- return false;
+ const bool is_act = !verttag_test_cb(v_dst, &user_data);
+ verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
+ }
+
+ EDBM_selectmode_flush(em);
+
+ if (op_params->track_active) {
+ /* even if this is selected it may not be in the selection list */
+ if (BM_elem_flag_test(v_dst_last, BM_ELEM_SELECT) == 0) {
+ BM_select_history_remove(bm, v_dst_last);
+ }
+ else {
+ BM_select_history_store(bm, v_dst_last);
+ }
}
+
+ EDBM_update_generic(em, false, false);
}
@@ -163,10 +217,10 @@ static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
{
struct UserData *user_data = user_data_v;
- Scene *scene = user_data->scene;
+ const char edge_mode = user_data->op_params->edge_mode;
BMesh *bm = user_data->bm;
- switch (scene->toolsettings->edge_mode) {
+ switch (edge_mode) {
case EDGE_MODE_SELECT:
return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
case EDGE_MODE_TAG_SEAM:
@@ -190,10 +244,10 @@ static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
{
struct UserData *user_data = user_data_v;
- Scene *scene = user_data->scene;
+ const char edge_mode = user_data->op_params->edge_mode;
BMesh *bm = user_data->bm;
- switch (scene->toolsettings->edge_mode) {
+ switch (edge_mode) {
case EDGE_MODE_SELECT:
BM_edge_select_set(bm, e, val);
break;
@@ -250,106 +304,127 @@ static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
/* mesh shortest path select, uses prev-selected edge */
/* since you want to create paths with multiple selects, it doesn't have extend option */
-static bool mouse_mesh_shortest_path_edge(ViewContext *vc)
+static void mouse_mesh_shortest_path_edge(
+ Scene *scene, const struct PathSelectParams *op_params,
+ BMEdge *e_act, BMEdge *e_dst)
{
- BMEditMesh *em = vc->em;
+ Object *obedit = scene->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
- BMEdge *e_dst;
- float dist = ED_view3d_select_dist_px();
- const bool use_length = true;
- e_dst = EDBM_edge_find_nearest(vc, &dist);
- if (e_dst) {
- const char edge_mode = vc->scene->toolsettings->edge_mode;
- struct UserData user_data = {bm, vc->obedit->data, vc->scene};
- LinkNode *path = NULL;
- Mesh *me = vc->obedit->data;
- BMEdge *e_act = BM_mesh_active_edge_get(bm);
+ struct UserData user_data = {bm, obedit->data, op_params};
+ LinkNode *path = NULL;
+ Mesh *me = obedit->data;
+ bool is_path_ordered = false;
- edgetag_ensure_cd_flag(vc->scene, em->ob->data);
+ edgetag_ensure_cd_flag(scene, obedit->data);
- if (e_act && (e_act != e_dst)) {
- if ((path = BM_mesh_calc_path_edge(bm, e_act, e_dst, use_length,
- edgetag_filter_cb, &user_data)))
- {
+ if (e_act && (e_act != e_dst)) {
+ if (op_params->use_fill) {
+ path = BM_mesh_calc_path_region_edge(
+ bm, (BMElem *)e_act, (BMElem *)e_dst,
+ edgetag_filter_cb, &user_data);
+ }
+ else {
+ is_path_ordered = true;
+ path = BM_mesh_calc_path_edge(
+ bm, e_act, e_dst,
+ &(const struct BMCalcPathParams) {
+ .use_topology_distance = op_params->use_topology_distance,
+ .use_step_face = op_params->use_face_step,
+ },
+ edgetag_filter_cb, &user_data);
+ }
+
+ if (path) {
+ if (op_params->track_active) {
BM_select_history_remove(bm, e_act);
}
}
+ }
- if (path) {
- /* toggle the flag */
- bool all_set = true;
- LinkNode *node;
-
- node = path;
- do {
- if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
- all_set = false;
- break;
- }
- } while ((node = node->next));
+ BMEdge *e_dst_last = e_dst;
+
+ if (path) {
+ /* toggle the flag */
+ bool all_set = true;
+ LinkNode *node;
+
+ node = path;
+ do {
+ if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
+ all_set = false;
+ break;
+ }
+ } while ((node = node->next));
- node = path;
- do {
+ int depth = 1;
+ node = path;
+ do {
+ if ((is_path_ordered == false) ||
+ WM_operator_properties_checker_interval_test(&op_params->interval_params, depth))
+ {
edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
- } while ((node = node->next));
+ if (is_path_ordered) {
+ e_dst_last = node->link;
+ }
+ }
+ } while ((void)depth++, (node = node->next));
- BLI_linklist_free(path, NULL);
- }
- else {
- const bool is_act = !edgetag_test_cb(e_dst, &user_data);
- edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
- edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
- }
+ BLI_linklist_free(path, NULL);
+ }
+ else {
+ const bool is_act = !edgetag_test_cb(e_dst, &user_data);
+ edgetag_ensure_cd_flag(scene, obedit->data);
+ edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
+ }
- if (edge_mode != EDGE_MODE_SELECT) {
+ if (op_params->edge_mode != EDGE_MODE_SELECT) {
+ if (op_params->track_active) {
/* simple rules - last edge is _always_ active and selected */
if (e_act)
BM_edge_select_set(bm, e_act, false);
- BM_edge_select_set(bm, e_dst, true);
- BM_select_history_store(bm, e_dst);
+ BM_edge_select_set(bm, e_dst_last, true);
+ BM_select_history_store(bm, e_dst_last);
}
+ }
- EDBM_selectmode_flush(em);
+ EDBM_selectmode_flush(em);
+ if (op_params->track_active) {
/* even if this is selected it may not be in the selection list */
- if (edge_mode == EDGE_MODE_SELECT) {
- if (edgetag_test_cb(e_dst, &user_data) == 0)
- BM_select_history_remove(bm, e_dst);
+ if (op_params->edge_mode == EDGE_MODE_SELECT) {
+ if (edgetag_test_cb(e_dst_last, &user_data) == 0)
+ BM_select_history_remove(bm, e_dst_last);
else
- BM_select_history_store(bm, e_dst);
+ BM_select_history_store(bm, e_dst_last);
}
+ }
- /* force drawmode for mesh */
- switch (edge_mode) {
+ /* force drawmode for mesh */
+ switch (op_params->edge_mode) {
- case EDGE_MODE_TAG_SEAM:
- me->drawflag |= ME_DRAWSEAMS;
- ED_uvedit_live_unwrap(vc->scene, vc->obedit);
- break;
- case EDGE_MODE_TAG_SHARP:
- me->drawflag |= ME_DRAWSHARP;
- break;
- case EDGE_MODE_TAG_CREASE:
- me->drawflag |= ME_DRAWCREASES;
- break;
- case EDGE_MODE_TAG_BEVEL:
- me->drawflag |= ME_DRAWBWEIGHTS;
- break;
+ case EDGE_MODE_TAG_SEAM:
+ me->drawflag |= ME_DRAWSEAMS;
+ ED_uvedit_live_unwrap(scene, obedit);
+ break;
+ case EDGE_MODE_TAG_SHARP:
+ me->drawflag |= ME_DRAWSHARP;
+ break;
+ case EDGE_MODE_TAG_CREASE:
+ me->drawflag |= ME_DRAWCREASES;
+ break;
+ case EDGE_MODE_TAG_BEVEL:
+ me->drawflag |= ME_DRAWBWEIGHTS;
+ break;
#ifdef WITH_FREESTYLE
- case EDGE_MODE_TAG_FREESTYLE:
- me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
- break;
+ case EDGE_MODE_TAG_FREESTYLE:
+ me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
+ break;
#endif
- }
-
- EDBM_update_generic(em, false, false);
-
- return true;
- }
- else {
- return false;
}
+
+ EDBM_update_generic(em, false, false);
}
@@ -374,127 +449,234 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
BM_face_select_set(user_data->bm, f, val);
}
-static bool mouse_mesh_shortest_path_face(ViewContext *vc)
+static void mouse_mesh_shortest_path_face(
+ Scene *scene, const struct PathSelectParams *op_params,
+ BMFace *f_act, BMFace *f_dst)
{
- BMEditMesh *em = vc->em;
+ Object *obedit = scene->obedit;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
- BMFace *f_dst;
- float dist = ED_view3d_select_dist_px();
- const bool use_length = true;
-
- f_dst = EDBM_face_find_nearest(vc, &dist);
- if (f_dst) {
- struct UserData user_data = {bm, vc->obedit->data, vc->scene};
- LinkNode *path = NULL;
- BMFace *f_act = BM_mesh_active_face_get(bm, false, true);
-
- if (f_act) {
- if (f_act != f_dst) {
- if ((path = BM_mesh_calc_path_face(bm, f_act, f_dst, use_length,
- facetag_filter_cb, &user_data)))
- {
+
+ struct UserData user_data = {bm, obedit->data, op_params};
+ LinkNode *path = NULL;
+ bool is_path_ordered = false;
+
+ if (f_act) {
+ if (op_params->use_fill) {
+ path = BM_mesh_calc_path_region_face(
+ bm, (BMElem *)f_act, (BMElem *)f_dst,
+ facetag_filter_cb, &user_data);
+ }
+ else {
+ is_path_ordered = true;
+ path = BM_mesh_calc_path_face(
+ bm, f_act, f_dst,
+ &(const struct BMCalcPathParams) {
+ .use_topology_distance = op_params->use_topology_distance,
+ .use_step_face = op_params->use_face_step,
+ },
+ facetag_filter_cb, &user_data);
+ }
+
+
+ if (f_act != f_dst) {
+ if (path) {
+ if (op_params->track_active) {
BM_select_history_remove(bm, f_act);
}
}
}
+ }
- if (path) {
- /* toggle the flag */
- bool all_set = true;
- LinkNode *node;
-
- node = path;
- do {
- if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
- all_set = false;
- break;
- }
- } while ((node = node->next));
+ BMFace *f_dst_last = f_dst;
+
+ if (path) {
+ /* toggle the flag */
+ bool all_set = true;
+ LinkNode *node;
+
+ node = path;
+ do {
+ if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
+ all_set = false;
+ break;
+ }
+ } while ((node = node->next));
- node = path;
- do {
+ int depth = 1;
+ node = path;
+ do {
+ if ((is_path_ordered == false) ||
+ WM_operator_properties_checker_interval_test(&op_params->interval_params, depth))
+ {
facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
- } while ((node = node->next));
+ if (is_path_ordered) {
+ f_dst_last = node->link;
+ }
+ }
+ } while ((void)depth++, (node = node->next));
+
+ BLI_linklist_free(path, NULL);
+ }
+ else {
+ const bool is_act = !facetag_test_cb(f_dst, &user_data);
+ facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
+ }
+
+ EDBM_selectmode_flush(em);
- BLI_linklist_free(path, NULL);
+ if (op_params->track_active) {
+ /* even if this is selected it may not be in the selection list */
+ if (facetag_test_cb(f_dst_last, &user_data) == 0) {
+ BM_select_history_remove(bm, f_dst_last);
}
else {
- const bool is_act = !facetag_test_cb(f_dst, &user_data);
- facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
+ BM_select_history_store(bm, f_dst_last);
}
+ BM_mesh_active_face_set(bm, f_dst_last);
+ }
+
+ EDBM_update_generic(em, false, false);
+}
- EDBM_selectmode_flush(em);
- /* even if this is selected it may not be in the selection list */
- if (facetag_test_cb(f_dst, &user_data) == 0)
- BM_select_history_remove(bm, f_dst);
- else
- BM_select_history_store(bm, f_dst);
- BM_mesh_active_face_set(bm, f_dst);
+/* -------------------------------------------------------------------- */
+/* Main Operator for vert/edge/face tag */
- EDBM_update_generic(em, false, false);
+static bool edbm_shortest_path_pick_ex(
+ Scene *scene, const struct PathSelectParams *op_params,
+ BMElem *ele_src, BMElem *ele_dst)
+{
+ if (ELEM(NULL, ele_src, ele_dst) && (ele_src->head.htype != ele_dst->head.htype)) {
+ /* pass */
+ }
+ else if (ele_src->head.htype == BM_VERT) {
+ mouse_mesh_shortest_path_vert(scene, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
return true;
}
- else {
- return false;
+ else if (ele_src->head.htype == BM_EDGE) {
+ mouse_mesh_shortest_path_edge(scene, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
+ return true;
+ }
+ else if (ele_src->head.htype == BM_FACE) {
+ mouse_mesh_shortest_path_face(scene, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
+ return true;
}
+
+ return false;
}
+static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op);
+
+static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
+{
+ BMEditMesh *em = vc->em;
+ float dist = ED_view3d_select_dist_px();
+ if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) {
+ return (BMElem *)EDBM_vert_find_nearest(vc, &dist);
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) {
+ return (BMElem *)EDBM_edge_find_nearest(vc, &dist);
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) {
+ return (BMElem *)EDBM_face_find_nearest(vc, &dist);
+ }
-/* -------------------------------------------------------------------- */
-/* Main Operator for vert/edge/face tag */
+ return NULL;
+}
-static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ if (RNA_struct_property_is_set(op->ptr, "index")) {
+ return edbm_shortest_path_pick_exec(C, op);
+ }
+
ViewContext vc;
BMEditMesh *em;
- BMElem *ele;
-
+ bool track_active = true;
em_setup_viewcontext(C, &vc);
copy_v2_v2_int(vc.mval, event->mval);
em = vc.em;
- ele = BM_mesh_active_elem_get(em->bm);
- if (ele == NULL) {
- return OPERATOR_PASS_THROUGH;
- }
-
view3d_operator_needs_opengl(C);
- if ((em->selectmode & SCE_SELECT_VERTEX) && (ele->head.htype == BM_VERT)) {
- if (mouse_mesh_shortest_path_vert(&vc)) {
- return OPERATOR_FINISHED;
+ BMElem *ele_src, *ele_dst;
+ if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
+ !(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype)))
+ {
+ /* special case, toggle edge tags even when we don't have a path */
+ if (((em->selectmode & SCE_SELECT_EDGE) &&
+ (vc.scene->toolsettings->edge_mode != EDGE_MODE_SELECT)) &&
+ /* check if we only have a destination edge */
+ ((ele_src == NULL) &&
+ (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE))))
+ {
+ ele_src = ele_dst;
+ track_active = false;
}
else {
return OPERATOR_PASS_THROUGH;
}
}
- else if ((em->selectmode & SCE_SELECT_EDGE) && (ele->head.htype == BM_EDGE)) {
- if (mouse_mesh_shortest_path_edge(&vc)) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_PASS_THROUGH;
- }
+
+ struct PathSelectParams op_params;
+
+ path_select_params_from_op(op, &op_params);
+ op_params.track_active = track_active;
+ op_params.edge_mode = vc.scene->toolsettings->edge_mode;
+
+ if (!edbm_shortest_path_pick_ex(vc.scene, &op_params, ele_src, ele_dst)) {
+ return OPERATOR_PASS_THROUGH;
}
- else if ((em->selectmode & SCE_SELECT_FACE) && (ele->head.htype == BM_FACE)) {
- if (mouse_mesh_shortest_path_face(&vc)) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_PASS_THROUGH;
- }
+
+ /* to support redo */
+ BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype);
+ int index = EDBM_elem_to_index_any(em, ele_dst);
+
+ RNA_int_set(op->ptr, "index", index);
+
+ return OPERATOR_FINISHED;
+}
+
+static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+
+ const int index = RNA_int_get(op->ptr, "index");
+ if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMElem *ele_src, *ele_dst;
+ if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
+ !(ele_dst = EDBM_elem_from_index_any(em, index)))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ struct PathSelectParams op_params;
+ path_select_params_from_op(op, &op_params);
+ op_params.track_active = true;
+ op_params.edge_mode = scene->toolsettings->edge_mode;
+
+ if (!edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst)) {
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_PASS_THROUGH;
+ return OPERATOR_FINISHED;
}
void MESH_OT_shortest_path_pick(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Pick Shortest Path";
ot->idname = "MESH_OT_shortest_path_pick";
@@ -502,15 +684,19 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = edbm_shortest_path_pick_invoke;
+ ot->exec = edbm_shortest_path_pick_exec;
ot->poll = ED_operator_editmesh_region_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
-}
+ path_select_properties(ot);
+ /* use for redo */
+ prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
/* -------------------------------------------------------------------- */
@@ -518,6 +704,7 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em->bm;
@@ -525,8 +712,6 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
BMEditSelection *ese_src, *ese_dst;
BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
- const bool use_length = RNA_boolean_get(op->ptr, "use_length");
-
/* first try to find vertices in edit selection */
ese_src = bm->selected.last;
if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
@@ -570,41 +755,10 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
}
if (ele_src && ele_dst) {
- LinkNode *path = NULL;
- switch (ele_src->head.htype) {
- case BM_VERT:
- path = BM_mesh_calc_path_vert(
- bm, (BMVert *)ele_src, (BMVert *)ele_dst, use_length,
- BM_elem_cb_check_hflag_disabled_simple(BMVert *, BM_ELEM_HIDDEN));
- break;
- case BM_EDGE:
- path = BM_mesh_calc_path_edge(
- bm, (BMEdge *)ele_src, (BMEdge *)ele_dst, use_length,
- BM_elem_cb_check_hflag_disabled_simple(BMEdge *, BM_ELEM_HIDDEN));
- break;
- case BM_FACE:
- path = BM_mesh_calc_path_face(
- bm, (BMFace *)ele_src, (BMFace *)ele_dst, use_length,
- BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN));
- break;
- }
-
- if (path) {
- LinkNode *node = path;
-
- do {
- BM_elem_select_set(bm, node->link, true);
- } while ((node = node->next));
-
- BLI_linklist_free(path, NULL);
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "Path can't be found");
- return OPERATOR_CANCELLED;
- }
+ struct PathSelectParams op_params;
+ path_select_params_from_op(op, &op_params);
- EDBM_selectmode_flush(em);
- EDBM_update_generic(em, false, false);
+ edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst);
return OPERATOR_FINISHED;
}
@@ -629,5 +783,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "use_length", true, "Length", "Use length when measuring distance");
+ path_select_properties(ot);
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 112edef5120..17250fbfb09 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -74,8 +74,9 @@
/* ****************************** MIRROR **************** */
-void EDBM_select_mirrored(BMEditMesh *em, bool extend,
- int *r_totmirr, int *r_totfail)
+void EDBM_select_mirrored(
+ BMEditMesh *em, const int axis, const bool extend,
+ int *r_totmirr, int *r_totfail)
{
Mesh *me = (Mesh *)em->ob->data;
BMesh *bm = em->bm;
@@ -106,7 +107,7 @@ void EDBM_select_mirrored(BMEditMesh *em, bool extend,
}
}
- EDBM_verts_mirror_cache_begin(em, 0, true, true, use_topology);
+ EDBM_verts_mirror_cache_begin(em, axis, true, true, use_topology);
if (!extend)
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -248,10 +249,14 @@ struct LassoMaskData {
int width;
};
-static void edbm_mask_lasso_px_cb(int x, int y, void *user_data)
+static void edbm_mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
{
struct LassoMaskData *data = user_data;
- data->px[(y * data->width) + x] = true;
+ unsigned int *px = &data->px[(y * data->width) + x];
+ do {
+ *px = true;
+ px++;
+ } while (++x != x_end);
}
@@ -1256,11 +1261,10 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
LinkData *link;
while ((link = BLI_pophead(&faces_regions))) {
BMFace *f, **faces = link->data;
- unsigned int i = 0;
- while ((f = faces[i++])) {
+ while ((f = *(faces++))) {
BM_face_select_set(bm, f, true);
}
- MEM_freeN(faces);
+ MEM_freeN(link->data);
MEM_freeN(link);
changed = true;
@@ -2339,6 +2343,9 @@ bool EDBM_select_interior_faces(BMEditMesh *em)
/************************ Select Linked Operator *************************/
+/* so we can have last-used default depend on selection mode (rare exception!) */
+#define USE_LINKED_SELECT_DEFAULT_HACK
+
struct DelimitData {
int cd_loop_type;
int cd_loop_offset;
@@ -2389,6 +2396,40 @@ static bool select_linked_delimit_test(
return false;
}
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+/**
+ * Gets the default from the operator fallback to own last-used value
+ * (selected based on mode)
+ */
+static int select_linked_delimit_default_from_op(wmOperator *op, BMEditMesh *em)
+{
+ static char delimit_last_store[2] = {0, BMO_DELIM_SEAM};
+ int delimit_last_index = (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0;
+ char *delimit_last = &delimit_last_store[delimit_last_index];
+ PropertyRNA *prop_delimit = RNA_struct_find_property(op->ptr, "delimit");
+ int delimit;
+
+ if (RNA_property_is_set(op->ptr, prop_delimit)) {
+ delimit = RNA_property_enum_get(op->ptr, prop_delimit);
+ *delimit_last = delimit;
+ }
+ else {
+ delimit = *delimit_last;
+ RNA_property_enum_set(op->ptr, prop_delimit, delimit);
+ }
+ return delimit;
+}
+#endif
+
+static void select_linked_delimit_validate(BMesh *bm, int *delimit)
+{
+ if ((*delimit) & BMO_DELIM_UV) {
+ if (!CustomData_has_layer(&bm->ldata, CD_MLOOPUV)) {
+ (*delimit) &= ~BMO_DELIM_UV;
+ }
+ }
+}
+
static void select_linked_delimit_begin(BMesh *bm, short selectmode, int delimit)
{
struct DelimitData delimit_data = {0};
@@ -2441,7 +2482,13 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMIter iter;
BMWalker walker;
- const int delimit = RNA_enum_get(op->ptr, "delimit");
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+ int delimit = select_linked_delimit_default_from_op(op, em);
+#else
+ int delimit = RNA_enum_get(op->ptr, "delimit");
+#endif
+
+ select_linked_delimit_validate(bm, &delimit);
if (delimit) {
select_linked_delimit_begin(em->bm, em->selectmode, delimit);
@@ -2581,6 +2628,8 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
void MESH_OT_select_linked(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Select Linked All";
ot->idname = "MESH_OT_select_linked";
@@ -2593,27 +2642,32 @@ void MESH_OT_select_linked(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
- "Delimit selected region");
+ prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+#else
+ UNUSED_VARS(prop);
+#endif
}
static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op);
-static void edbm_select_linked_pick_ex(
- BMEditMesh *em,
- BMVert *eve, BMEdge *eed, BMFace *efa,
- bool sel, int delimit)
+static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, int delimit)
{
BMesh *bm = em->bm;
BMWalker walker;
+ select_linked_delimit_validate(bm, &delimit);
+
if (delimit) {
select_linked_delimit_begin(bm, em->selectmode, delimit);
}
/* Note: logic closely matches 'edbm_select_linked_exec', keep in sync */
- if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+ if (ele->head.htype == BM_VERT) {
+ BMVert *eve = (BMVert *)ele;
BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
@@ -2645,7 +2699,8 @@ static void edbm_select_linked_pick_ex(
EDBM_selectmode_flush(em);
}
- else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+ else if (ele->head.htype == BM_EDGE) {
+ BMEdge *eed = (BMEdge *)ele;
BMW_init(&walker, bm, delimit ? BMW_LOOP_SHELL_WIRE : BMW_VERT_SHELL,
BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
@@ -2677,7 +2732,8 @@ static void edbm_select_linked_pick_ex(
EDBM_selectmode_flush(em);
}
- else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+ else if (ele->head.htype == BM_FACE) {
+ BMFace *efa = (BMFace *)ele;
BMW_init(&walker, bm, BMW_ISLAND,
BMW_MASK_NOP, delimit ? BMO_ELE_TAG : BMW_MASK_NOP, BMW_MASK_NOP,
@@ -2710,7 +2766,6 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
BMEdge *eed;
BMFace *efa;
const bool sel = !RNA_boolean_get(op->ptr, "deselect");
- const int delimit = RNA_enum_get(op->ptr, "delimit");
int index;
if (RNA_struct_property_is_set(op->ptr, "index")) {
@@ -2739,24 +2794,19 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
return OPERATOR_CANCELLED;
}
- edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+ int delimit = select_linked_delimit_default_from_op(op, em);
+#else
+ int delimit = RNA_enum_get(op->ptr, "delimit");
+#endif
+
+ BMElem *ele = EDBM_elem_from_selectmode(em, eve, eed, efa);
+
+ edbm_select_linked_pick_ex(em, ele, sel, delimit);
/* to support redo */
- if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- index = BM_elem_index_get(eve);
- }
- else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
- BM_mesh_elem_index_ensure(bm, BM_EDGE);
- index = BM_elem_index_get(eed) + bm->totvert;
- }
- else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- index = BM_elem_index_get(efa) + bm->totvert + bm->totedge;
- }
- else {
- index = -1;
- }
+ BM_mesh_elem_index_ensure(bm, ele->head.htype);
+ index = EDBM_elem_to_index_any(em, ele);
RNA_int_set(op->ptr, "index", index);
@@ -2772,30 +2822,22 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
int index;
- BMVert *eve = NULL;
- BMEdge *eed = NULL;
- BMFace *efa = NULL;
const bool sel = !RNA_boolean_get(op->ptr, "deselect");
- const int delimit = RNA_enum_get(op->ptr, "delimit");
index = RNA_int_get(op->ptr, "index");
if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
return OPERATOR_CANCELLED;
}
- if (index < bm->totvert) {
- eve = BM_vert_at_index_find_or_table(bm, index);
- }
- else if (index < (bm->totvert + bm->totedge)) {
- index -= bm->totvert;
- eed = BM_edge_at_index_find_or_table(bm, index);
- }
- else if (index < (bm->totvert + bm->totedge + bm->totface)) {
- index -= (bm->totvert + bm->totedge);
- efa = BM_face_at_index_find_or_table(bm, index);
- }
+ BMElem *ele = EDBM_elem_from_index_any(em, index);
- edbm_select_linked_pick_ex(em, eve, eed, efa, sel, delimit);
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+ int delimit = select_linked_delimit_default_from_op(op, em);
+#else
+ int delimit = RNA_enum_get(op->ptr, "delimit");
+#endif
+
+ edbm_select_linked_pick_ex(em, ele, sel, delimit);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
@@ -2820,8 +2862,11 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
- RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
- "Delimit selected region");
+ prop = RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_SEAM, "Delimit",
+ "Delimit selected region");
+#ifdef USE_LINKED_SELECT_DEFAULT_HACK
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+#endif
/* use for redo */
prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
@@ -2979,12 +3024,18 @@ static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool extend = RNA_boolean_get(op->ptr, "extend");
+ const int axis_flag = RNA_enum_get(op->ptr, "axis");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
if (em->bm->totvert && em->bm->totvertsel) {
int totmirr, totfail;
- EDBM_select_mirrored(em, extend, &totmirr, &totfail);
+ for (int axis = 0; axis < 3; axis++) {
+ if ((1 << axis) & axis_flag) {
+ EDBM_select_mirrored(em, axis, extend, &totmirr, &totfail);
+ }
+ }
+
if (totmirr) {
EDBM_selectmode_flush(em);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -3011,6 +3062,8 @@ void MESH_OT_select_mirror(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
+ RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
+
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
}
@@ -3098,7 +3151,9 @@ static bool bm_edge_is_select_isolated(BMEdge *e)
/* Walk all reachable elements of the same type as h_act in breadth-first
* order, starting from h_act. Deselects elements if the depth when they
* are reached is not a multiple of "nth". */
-static void walker_deselect_nth(BMEditMesh *em, int nth, int skip, int offset, BMHeader *h_act)
+static void walker_deselect_nth(
+ BMEditMesh *em, const struct CheckerIntervalParams *op_params,
+ BMHeader *h_act)
{
BMElem *ele;
BMesh *bm = em->bm;
@@ -3165,7 +3220,7 @@ static void walker_deselect_nth(BMEditMesh *em, int nth, int skip, int offset, B
if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) {
/* Deselect elements that aren't at "nth" depth from active */
const int depth = BMW_current_depth(&walker) - 1;
- if ((offset + depth) % (skip + nth) >= skip) {
+ if (WM_operator_properties_checker_interval_test(op_params, depth)) {
BM_elem_select_set(bm, ele, false);
}
BM_elem_flag_enable(ele, BM_ELEM_TAG);
@@ -3232,7 +3287,7 @@ static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed,
}
}
-static bool edbm_deselect_nth(BMEditMesh *em, int nth, int skip, int offset)
+static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params)
{
BMVert *v;
BMEdge *e;
@@ -3241,15 +3296,15 @@ static bool edbm_deselect_nth(BMEditMesh *em, int nth, int skip, int offset)
deselect_nth_active(em, &v, &e, &f);
if (v) {
- walker_deselect_nth(em, nth, skip, offset, &v->head);
+ walker_deselect_nth(em, op_params, &v->head);
return true;
}
else if (e) {
- walker_deselect_nth(em, nth, skip, offset, &e->head);
+ walker_deselect_nth(em, op_params, &e->head);
return true;
}
else if (f) {
- walker_deselect_nth(em, nth, skip, offset, &f->head);
+ walker_deselect_nth(em, op_params, &f->head);
return true;
}
@@ -3260,14 +3315,11 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int nth = RNA_int_get(op->ptr, "nth") - 1;
- const int skip = RNA_int_get(op->ptr, "skip");
- int offset = RNA_int_get(op->ptr, "offset");
+ struct CheckerIntervalParams op_params;
- /* so input of offset zero ends up being (nth - 1) */
- offset = mod_i(offset, nth + skip);
+ WM_operator_properties_checker_interval_from_op(op, &op_params);
- if (edbm_deselect_nth(em, nth, skip, offset) == false) {
+ if (edbm_deselect_nth(em, &op_params) == false) {
BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
return OPERATOR_CANCELLED;
}
@@ -3292,9 +3344,7 @@ void MESH_OT_select_nth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "nth", 2, 2, INT_MAX, "Nth Selection", "", 2, 100);
- RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
- RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
+ WM_operator_properties_checker_interval(ot, false);
}
void em_setup_viewcontext(bContext *C, ViewContext *vc)
@@ -3318,16 +3368,16 @@ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op)
BMIter iter;
BMEdge *e;
BMLoop *l1, *l2;
- const float sharp = RNA_float_get(op->ptr, "sharpness");
+ const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == false &&
BM_edge_loop_pair(e, &l1, &l2))
{
/* edge has exactly two neighboring faces, check angle */
- const float angle = angle_normalized_v3v3(l1->f->no, l2->f->no);
+ const float angle_cos = dot_v3v3(l1->f->no, l2->f->no);
- if (fabsf(angle) > sharp) {
+ if (angle_cos < angle_limit_cos) {
BM_edge_select_set(em->bm, e, true);
}
}
@@ -3371,7 +3421,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
BMIter iter, liter, liter2;
BMFace *f;
BMLoop *l, *l2;
- const float angle_limit = RNA_float_get(op->ptr, "sharpness");
+ const float angle_limit_cos = cosf(RNA_float_get(op->ptr, "sharpness"));
BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false);
@@ -3394,7 +3444,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_ITER_ELEM (l2, &liter2, l, BM_LOOPS_OF_LOOP) {
- float angle;
+ float angle_cos;
if (BM_elem_flag_test(l2->f, BM_ELEM_TAG) ||
BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN))
@@ -3402,9 +3452,9 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op)
continue;
}
- angle = angle_normalized_v3v3(f->no, l2->f->no);
+ angle_cos = dot_v3v3(f->no, l2->f->no);
- if (angle < angle_limit) {
+ if (angle_cos > angle_limit_cos) {
BLI_LINKSTACK_PUSH(stack, l2->f);
}
}
@@ -3538,13 +3588,16 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
BMIter iter;
+ RNG *rng = BLI_rng_new_srandom(seed);
+
if (em->selectmode & SCE_SELECT_VERTEX) {
BMVert *eve;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
BM_vert_select_set(em->bm, eve, select);
}
}
@@ -3552,7 +3605,7 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op)
else if (em->selectmode & SCE_SELECT_EDGE) {
BMEdge *eed;
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
BM_edge_select_set(em->bm, eed, select);
}
}
@@ -3560,12 +3613,14 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op)
else {
BMFace *efa;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_frand() < randfac) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_rng_get_float(rng) < randfac) {
BM_face_select_set(em->bm, efa, select);
}
}
}
+ BLI_rng_free(rng);
+
if (select) {
/* was EDBM_select_flush, but it over select in edge/face mode */
EDBM_selectmode_flush(em);
@@ -3594,9 +3649,7 @@ void MESH_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float_percentage(ot->srna, "percent", 50.0f, 0.0f, 100.0f,
- "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
- WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+ WM_operator_properties_select_random(ot);
}
static int edbm_select_ungrouped_poll(bContext *C)
@@ -3751,57 +3804,6 @@ void MESH_OT_select_axis(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.0001f, 0.000001f, 50.0f, "Threshold", "", 0.00001f, 10.0f);
}
-
-static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *f;
- BMVert *v;
- BMIter iter;
-
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
-
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- BMLoop *l;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(l->next->v, BM_ELEM_TAG);
- BM_vert_select_set(em->bm, l->v, false);
- }
- }
- }
-
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- BM_vert_select_set(em->bm, v, true);
- }
- }
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_next_loop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Next Loop";
- ot->idname = "MESH_OT_select_next_loop";
- ot->description = "Select next edge loop adjacent to a selected loop";
-
- /* api callbacks */
- ot->exec = edbm_select_next_loop_exec;
- ot->poll = ED_operator_editmesh;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
static int edbm_region_to_loop_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index d3937188358..ee33f5f1655 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -85,7 +85,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cuts = RNA_int_get(op->ptr, "number_cuts");
- float smooth = 0.292f * RNA_float_get(op->ptr, "smoothness");
+ float smooth = RNA_float_get(op->ptr, "smoothness");
const float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
const float along_normal = RNA_float_get(op->ptr, "fractal_along_normal");
@@ -96,7 +96,7 @@ static int edbm_subdivide_exec(bContext *C, wmOperator *op)
}
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
- smooth, SUBD_FALLOFF_INVSQUARE, false,
+ smooth, SUBD_FALLOFF_LIN, false,
fractal, along_normal,
cuts,
SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
@@ -191,7 +191,7 @@ static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_defa
"Profile Factor", "How much intermediary new edges are shrunk/expanded", -2.0f, 2.0f);
prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
RNA_def_property_enum_default(prop, PROP_SMOOTH);
RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
@@ -306,7 +306,10 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em)
float mval[2], co_proj[3], no_dummy[3];
float dist_px_dummy;
if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- if (snapObjectsContext(C, mval, &dist_px_dummy, co_proj, no_dummy, SNAP_NOT_OBEDIT)) {
+ if (snapObjectsContext(
+ C, mval, SNAP_NOT_OBEDIT,
+ co_proj, no_dummy, &dist_px_dummy))
+ {
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
}
}
@@ -1062,7 +1065,8 @@ static bool bm_vert_connect_select_history(BMesh *bm)
else {
changed |= bm_vert_connect_pair(bm, (BMVert *)ese_last->ele, (BMVert *)ese->ele);
}
- } while ((ese_last = ese),
+ } while ((void)
+ (ese_last = ese),
(ese = ese->next));
if (changed) {
@@ -1102,7 +1106,8 @@ static bool bm_vert_connect_select_history(BMesh *bm)
BM_edge_select_set(bm, e, true);
changed = true;
}
- } while ((ese_prev = ese),
+ } while ((void)
+ (ese_prev = ese),
(ese = ese->next));
if (changed == false) {
@@ -1465,8 +1470,12 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf", BM_ELEM_SELECT))
+ if (!EDBM_op_callf(
+ em, op, "reverse_faces faces=%hf flip_multires=%b",
+ BM_ELEM_SELECT, true))
+ {
return OPERATOR_CANCELLED;
+ }
EDBM_update_generic(em, true, false);
@@ -1634,8 +1643,9 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT))
return OPERATOR_CANCELLED;
- if (RNA_boolean_get(op->ptr, "inside"))
- EDBM_op_callf(em, op, "reverse_faces faces=%hf", BM_ELEM_SELECT);
+ if (RNA_boolean_get(op->ptr, "inside")) {
+ EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
+ }
EDBM_update_generic(em, true, false);
@@ -2357,8 +2367,8 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 1e-5f, 10.0f);
+ RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices");
}
@@ -2608,7 +2618,7 @@ void MESH_OT_solidify(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
+ prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f);
RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4);
}
@@ -3783,7 +3793,6 @@ static int edbm_poke_face_exec(bContext *C, wmOperator *op)
void MESH_OT_poke(wmOperatorType *ot)
{
-
static EnumPropertyItem poke_center_modes[] = {
{BMOP_POKE_MEAN_WEIGHTED, "MEAN_WEIGHTED", 0, "Weighted Mean", "Weighted Mean Face Center"},
{BMOP_POKE_MEAN, "MEAN", 0, "Mean", "Mean Face Center"},
@@ -3803,7 +3812,7 @@ void MESH_OT_poke(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
+ RNA_def_float_distance(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED,
"Poke Center", "Poke Face Center Calculation");
@@ -3818,12 +3827,20 @@ static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
BMOperator bmop;
const int quad_method = RNA_enum_get(op->ptr, "quad_method");
const int ngon_method = RNA_enum_get(op->ptr, "ngon_method");
+ BMOIter oiter;
+ BMFace *f;
EDBM_op_init(em, &bmop, op, "triangulate faces=%hf quad_method=%i ngon_method=%i", BM_ELEM_SELECT, quad_method, ngon_method);
BMO_op_exec(em->bm, &bmop);
/* select the output */
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+
+ /* remove the doubles */
+ BMO_ITER (f, &oiter, bmop.slots_out, "face_map_double.out", BM_FACE) {
+ BM_face_kill(em->bm, f);
+ }
+
EDBM_selectmode_flush(em);
if (!EDBM_op_finish(em, &bmop, op, true)) {
@@ -3850,9 +3867,9 @@ void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "quad_method", modifier_triangulate_quad_method_items, MOD_TRIANGULATE_QUAD_BEAUTY,
+ RNA_def_enum(ot->srna, "quad_method", rna_enum_modifier_triangulate_quad_method_items, MOD_TRIANGULATE_QUAD_BEAUTY,
"Quad Method", "Method for splitting the quads into triangles");
- RNA_def_enum(ot->srna, "ngon_method", modifier_triangulate_ngon_method_items, MOD_TRIANGULATE_NGON_BEAUTY,
+ RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_ngon_method_items, MOD_TRIANGULATE_NGON_BEAUTY,
"Polygon Method", "Method for splitting the polygons into triangles");
}
@@ -4203,7 +4220,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
RNA_def_property_float_default(prop, DEG2RADF(5.0f));
RNA_def_boolean(ot->srna, "use_dissolve_boundaries", false, "All Boundaries",
"Dissolve all vertices inbetween face boundaries");
- RNA_def_enum_flag(ot->srna, "delimit", mesh_delimit_mode_items, BMO_DELIM_NORMAL, "Delimit",
+ RNA_def_enum_flag(ot->srna, "delimit", rna_enum_mesh_delimit_mode_items, BMO_DELIM_NORMAL, "Delimit",
"Delimit dissolve operation");
}
@@ -4247,8 +4264,8 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
- "Minimum distance between elements to merge", 1e-5f, 10.0f);
+ RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance",
+ "Minimum distance between elements to merge", 1e-5f, 10.0f);
}
@@ -4977,7 +4994,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false);
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false, false);
eve->co[2] += fac * tin;
}
}
@@ -5127,7 +5144,7 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
EDBM_mesh_normals_update(em);
BMO_op_initf(
- em->bm, &bmop_subd, op->flag,
+ em->bm, &bmop_subd, 0,
"subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
"profile_shape=%i profile_shape_factor=%f",
&bmop, "edges.out", op_props.interp_mode, op_props.cuts, op_props.smooth,
@@ -5244,10 +5261,10 @@ void MESH_OT_wireframe(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness");
RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry");
RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces");
- prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
+ prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f);
/* use 1 rather then 10 for max else dragging the button moves too far */
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
- RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
+ RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f);
RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf");
prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2);
@@ -5452,7 +5469,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
+ ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
RNA_def_float(ot->srna, "threshold", 1e-4f, 0.0f, 10.0f, "Threshold", "", 1e-5f, 0.1f);
@@ -5576,10 +5593,10 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
+ ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items,
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
- RNA_def_float(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
+ RNA_def_float_distance(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f);
RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center");
}
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index d521b2c01e5..33f8455e614 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -113,7 +113,7 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
* see: [#31811] */
void EDBM_mesh_ensure_valid_dm_hack(Scene *scene, BMEditMesh *em)
{
- if ((((ID *)em->ob->data)->flag & LIB_ID_RECALC) ||
+ if ((((ID *)em->ob->data)->tag & LIB_TAG_ID_RECALC) ||
(em->ob->recalc & OB_RECALC_DATA))
{
/* since we may not have done selection flushing */
@@ -380,6 +380,10 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob)
EDBM_selectmode_flush(me->edit_btmesh);
}
+/**
+ * \warning This can invalidate the #DerivedMesh cache of other objects (for linked duplicates).
+ * Most callers should run #DAG_id_tag_update on \a ob->data, see: T46738, T46913
+ */
void EDBM_mesh_load(Object *ob)
{
Mesh *me = ob->data;
@@ -411,8 +415,8 @@ void EDBM_mesh_free(BMEditMesh *em)
/* These tables aren't used yet, so it's not strictly necessary
* to 'end' them (with 'e' param) but if someone tries to start
* using them, having these in place will save a lot of pain */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, 'e');
+ ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_topo_table(NULL, NULL, 'e');
BKE_editmesh_free(em);
}
@@ -472,6 +476,9 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
BMO_op_finish(em->bm, &bmop);
EDBM_selectmode_flush(em);
+
+ /* only needed for select less, ensure we don't have isolated elements remaining */
+ BM_mesh_select_mode_clean(em->bm);
}
void EDBM_flag_disable_all(BMEditMesh *em, const char hflag)
@@ -671,7 +678,7 @@ UvVertMap *BM_uv_vert_map_create(
float (*tf_uv)[2];
if (use_winding) {
- tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
}
BM_ITER_ELEM_INDEX(l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -764,8 +771,6 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
return vmap->vert[v];
}
-/* from editmesh_lib.c in trunk */
-
/* A specialized vert map used by stitch operator */
UvElementMap *BM_uv_element_map_create(
@@ -823,7 +828,7 @@ UvElementMap *BM_uv_element_map_create(
float (*tf_uv)[2];
if (use_winding) {
- tf_uv = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa->len);
+ tf_uv = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
}
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -1138,7 +1143,7 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool
BM_mesh_elem_index_ensure(bm, BM_VERT);
if (use_topology) {
- ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, true);
+ ED_mesh_mirrtopo_init(me, NULL, -1, &mesh_topo_store, true);
}
else {
tree = BLI_kdtree_new(bm->totvert);
@@ -1429,7 +1434,69 @@ int EDBM_view3d_poll(bContext *C)
return 0;
}
+BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
+{
+ BMElem *ele = NULL;
+
+ if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
+ ele = (BMElem *)eve;
+ }
+ else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
+ ele = (BMElem *)eed;
+ }
+ else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
+ ele = (BMElem *)efa;
+ }
+
+ return ele;
+}
+
+/**
+ * Used when we want to store a single index for any vert/edge/face.
+ *
+ * Intended for use with operators.
+ */
+int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
+{
+ BMesh *bm = em->bm;
+ int index = BM_elem_index_get(ele);
+
+ if (ele->head.htype == BM_VERT) {
+ BLI_assert(!(bm->elem_index_dirty & BM_VERT));
+ }
+ else if (ele->head.htype == BM_EDGE) {
+ BLI_assert(!(bm->elem_index_dirty & BM_EDGE));
+ index += bm->totvert;
+ }
+ else if (ele->head.htype == BM_FACE) {
+ BLI_assert(!(bm->elem_index_dirty & BM_FACE));
+ index += bm->totvert + bm->totedge;
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ return index;
+}
+
+BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index)
+{
+ BMesh *bm = em->bm;
+
+ if (index < bm->totvert) {
+ return (BMElem *)BM_vert_at_index_find_or_table(bm, index);
+ }
+ index -= bm->totvert;
+ if (index < bm->totedge) {
+ return (BMElem *)BM_edge_at_index_find_or_table(bm, index);
+ }
+ index -= bm->totedge;
+ if (index < bm->totface) {
+ return (BMElem *)BM_face_at_index_find_or_table(bm, index);
+ }
+ return NULL;
+}
/* -------------------------------------------------------------------- */
/* BMBVH functions */
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index c56465f570a..08b4d1aee45 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -36,6 +36,7 @@
struct BMEditMesh;
struct BMOperator;
+struct BMElem;
struct EnumPropertyItem;
struct bContext;
struct wmKeyConfig;
@@ -74,6 +75,11 @@ void EDBM_stats_update(struct BMEditMesh *em);
int EDBM_view3d_poll(struct bContext *C);
+struct BMElem *EDBM_elem_from_selectmode(
+ struct BMEditMesh *em,
+ struct BMVert *eve, struct BMEdge *eed, struct BMFace *efa);
+int EDBM_elem_to_index_any(struct BMEditMesh *em, struct BMElem *ele);
+struct BMElem *EDBM_elem_from_index_any(struct BMEditMesh *em, int index);
/* *** editmesh_add.c *** */
void MESH_OT_primitive_plane_add(struct wmOperatorType *ot);
@@ -109,6 +115,7 @@ void MESH_OT_inset(struct wmOperatorType *ot);
/* *** editmesh_intersect.c *** */
void MESH_OT_intersect(struct wmOperatorType *ot);
+void MESH_OT_intersect_boolean(struct wmOperatorType *ot);
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot);
@@ -154,7 +161,6 @@ void MESH_OT_select_non_manifold(struct wmOperatorType *ot);
void MESH_OT_select_random(struct wmOperatorType *ot);
void MESH_OT_select_ungrouped(struct wmOperatorType *ot);
void MESH_OT_select_axis(struct wmOperatorType *ot);
-void MESH_OT_select_next_loop(struct wmOperatorType *ot);
void MESH_OT_region_to_loop(struct wmOperatorType *ot);
void MESH_OT_loop_to_region(struct wmOperatorType *ot);
void MESH_OT_shortest_path_select(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 1c36826b882..b95921964eb 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -84,6 +84,7 @@ static void createVertsTrisData(bContext *C, LinkNode *obs,
for (oblink = obs; oblink; oblink = oblink->next) {
ob = (Object *) oblink->link;
dm = mesh_create_derived_no_virtual(scene, ob, NULL, CD_MASK_MESH);
+ DM_ensure_tessface(dm);
BLI_linklist_prepend(&dms, dm);
nverts += dm->getNumVerts(dm);
@@ -215,7 +216,7 @@ static bool buildNavMesh(const RecastData *recastParams, int nverts, float *vert
/* Find triangles which are walkable based on their slope and rasterize them */
recast_markWalkableTriangles(RAD2DEGF(recastParams->agentmaxslope), verts, nverts, tris, ntris, triflags);
- recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid);
+ recast_rasterizeTriangles(verts, nverts, tris, triflags, ntris, solid, 1);
MEM_freeN(triflags);
/* ** Step 3: Filter walkables surfaces ** */
@@ -244,27 +245,48 @@ static bool buildNavMesh(const RecastData *recastParams, int nverts, float *vert
return false;
}
- /* Prepare for region partitioning, by calculating distance field along the walkable surface */
- if (!recast_buildDistanceField(chf)) {
- recast_destroyCompactHeightfield(chf);
+ if (recastParams->partitioning == RC_PARTITION_WATERSHED) {
+ /* Prepare for region partitioning, by calculating distance field along the walkable surface */
+ if (!recast_buildDistanceField(chf)) {
+ recast_destroyCompactHeightfield(chf);
- BKE_report(reports, RPT_ERROR, "Failed to build distance field");
- return false;
- }
+ BKE_report(reports, RPT_ERROR, "Failed to build distance field");
+ return false;
+ }
- /* Partition the walkable surface into simple regions without holes */
- if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
- recast_destroyCompactHeightfield(chf);
+ /* Partition the walkable surface into simple regions without holes */
+ if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
+ recast_destroyCompactHeightfield(chf);
- BKE_report(reports, RPT_ERROR, "Failed to build regions");
- return false;
+ BKE_report(reports, RPT_ERROR, "Failed to build watershed regions");
+ return false;
+ }
+ }
+ else if (recastParams->partitioning == RC_PARTITION_MONOTONE) {
+ /* Partition the walkable surface into simple regions without holes */
+ /* Monotone partitioning does not need distancefield. */
+ if (!recast_buildRegionsMonotone(chf, 0, minRegionArea, mergeRegionArea)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build monotone regions");
+ return false;
+ }
+ }
+ else { /* RC_PARTITION_LAYERS */
+ /* Partition the walkable surface into simple regions without holes */
+ if (!recast_buildLayerRegions(chf, 0, minRegionArea)) {
+ recast_destroyCompactHeightfield(chf);
+
+ BKE_report(reports, RPT_ERROR, "Failed to build layer regions");
+ return false;
+ }
}
/* ** Step 5: Trace and simplify region contours ** */
/* Create contours */
cset = recast_newContourSet();
- if (!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset)) {
+ if (!recast_buildContours(chf, recastParams->edgemaxerror, maxEdgeLen, cset, RECAST_CONTOUR_TESS_WALL_EDGES)) {
recast_destroyCompactHeightfield(chf);
recast_destroyContourSet(cset);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 9718e63f012..2853ae3a84c 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -173,12 +173,11 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_bevel);
- WM_operatortype_append(MESH_OT_select_next_loop);
-
WM_operatortype_append(MESH_OT_bridge_edge_loops);
WM_operatortype_append(MESH_OT_inset);
WM_operatortype_append(MESH_OT_offset_edge_loops);
WM_operatortype_append(MESH_OT_intersect);
+ WM_operatortype_append(MESH_OT_intersect_boolean);
WM_operatortype_append(MESH_OT_face_split_by_edges);
WM_operatortype_append(MESH_OT_poke);
WM_operatortype_append(MESH_OT_wireframe);
@@ -339,7 +338,11 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "deselect", false);
RNA_boolean_set(kmi->ptr, "toggle", true);
- WM_keymap_add_item(keymap, "MESH_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "use_fill", false);
+
+ kmi = WM_keymap_add_item(keymap, "MESH_OT_shortest_path_pick", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "use_fill", true);
kmi = WM_keymap_add_item(keymap, "MESH_OT_select_all", AKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
@@ -348,6 +351,10 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
+
+ WM_keymap_add_item(keymap, "MESH_OT_select_next_item", PADPLUSKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_select_prev_item", PADMINUS, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+
WM_keymap_add_item(keymap, "MESH_OT_select_non_manifold", MKEY, KM_PRESS, (KM_CTRL | KM_SHIFT | KM_ALT), 0);
WM_keymap_add_item(keymap, "MESH_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 2491685161c..bad835b13e7 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -513,11 +513,13 @@ int join_mesh_exec(bContext *C, wmOperator *op)
/* old material array */
for (a = 1; a <= ob->totcol; a++) {
ma = ob->mat[a - 1];
- if (ma) ma->id.us--;
+ if (ma)
+ id_us_min(&ma->id);
}
for (a = 1; a <= me->totcol; a++) {
ma = me->mat[a - 1];
- if (ma) ma->id.us--;
+ if (ma)
+ id_us_min(&ma->id);
}
if (ob->mat) MEM_freeN(ob->mat);
if (ob->matbits) MEM_freeN(ob->matbits);
@@ -670,18 +672,15 @@ static struct { void *tree; } MirrKdStore = {NULL};
/* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */
-int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, const float co[3], char mode)
+int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode)
{
if (mode == 'u') { /* use table */
if (MirrKdStore.tree == NULL)
- ED_mesh_mirror_spatial_table(ob, em, NULL, 's');
+ ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
if (MirrKdStore.tree) {
KDTreeNearest nearest;
-
- int i;
-
- i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
+ const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest);
if (i != -1) {
if (nearest.dist < KD_THRESH) {
@@ -693,22 +692,15 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, const float co[3],
}
else if (mode == 's') { /* start table */
Mesh *me = ob->data;
- int totvert;
+ const bool use_em = (!dm && em && me->edit_btmesh == em);
+ const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert;
if (MirrKdStore.tree) /* happens when entering this call without ending it */
- ED_mesh_mirror_spatial_table(ob, em, co, 'e');
-
- if (em && me->edit_btmesh == em) {
- totvert = em->bm->totvert;
- }
- else {
- totvert = me->totvert;
- }
+ ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e');
MirrKdStore.tree = BLI_kdtree_new(totvert);
- if (em && me->edit_btmesh == em) {
-
+ if (use_em) {
BMVert *eve;
BMIter iter;
int i;
@@ -721,10 +713,10 @@ int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, const float co[3],
}
}
else {
- MVert *mvert;
+ MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
int i;
- for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) {
+ for (i = 0; i < totvert; i++, mvert++) {
BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co);
}
}
@@ -758,15 +750,15 @@ static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1};
/* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */
/* note, is supposed return -1 on error, which callers are currently checking for, but is not used so far */
-int ED_mesh_mirror_topo_table(Object *ob, char mode)
+int ED_mesh_mirror_topo_table(Object *ob, DerivedMesh *dm, char mode)
{
if (mode == 'u') { /* use table */
- if (ED_mesh_mirrtopo_recalc_check(ob->data, ob->mode, &mesh_topo_store)) {
- ED_mesh_mirror_topo_table(ob, 's');
+ if (ED_mesh_mirrtopo_recalc_check(ob->data, dm, ob->mode, &mesh_topo_store)) {
+ ED_mesh_mirror_topo_table(ob, dm, 's');
}
}
else if (mode == 's') { /* start table */
- ED_mesh_mirrtopo_init(ob->data, ob->mode, &mesh_topo_store, false);
+ ED_mesh_mirrtopo_init(ob->data, dm, ob->mode, &mesh_topo_store, false);
}
else if (mode == 'e') { /* end table */
ED_mesh_mirrtopo_free(&mesh_topo_store);
@@ -781,35 +773,35 @@ int ED_mesh_mirror_topo_table(Object *ob, char mode)
/** \} */
-static int mesh_get_x_mirror_vert_spatial(Object *ob, int index)
+static int mesh_get_x_mirror_vert_spatial(Object *ob, DerivedMesh *dm, int index)
{
Mesh *me = ob->data;
- MVert *mvert;
+ MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert;
float vec[3];
- mvert = me->mvert + index;
+ mvert = &mvert[index];
vec[0] = -mvert->co[0];
vec[1] = mvert->co[1];
vec[2] = mvert->co[2];
- return ED_mesh_mirror_spatial_table(ob, NULL, vec, 'u');
+ return ED_mesh_mirror_spatial_table(ob, NULL, dm, vec, 'u');
}
-static int mesh_get_x_mirror_vert_topo(Object *ob, int index)
+static int mesh_get_x_mirror_vert_topo(Object *ob, DerivedMesh *dm, int index)
{
- if (ED_mesh_mirror_topo_table(ob, 'u') == -1)
+ if (ED_mesh_mirror_topo_table(ob, dm, 'u') == -1)
return -1;
return mesh_topo_store.index_lookup[index];
}
-int mesh_get_x_mirror_vert(Object *ob, int index, const bool use_topology)
+int mesh_get_x_mirror_vert(Object *ob, DerivedMesh *dm, int index, const bool use_topology)
{
if (use_topology) {
- return mesh_get_x_mirror_vert_topo(ob, index);
+ return mesh_get_x_mirror_vert_topo(ob, dm, index);
}
else {
- return mesh_get_x_mirror_vert_spatial(ob, index);
+ return mesh_get_x_mirror_vert_spatial(ob, dm, index);
}
}
@@ -830,7 +822,7 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
vec[1] = co[1];
vec[2] = co[2];
- i = ED_mesh_mirror_spatial_table(ob, em, vec, 'u');
+ i = ED_mesh_mirror_spatial_table(ob, em, NULL, vec, 'u');
if (i != -1) {
return BM_vert_at_index(em->bm, i);
}
@@ -840,7 +832,7 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *em, BMVert *eve, int index)
{
intptr_t poinval;
- if (ED_mesh_mirror_topo_table(ob, 'u') == -1)
+ if (ED_mesh_mirror_topo_table(ob, NULL, 'u') == -1)
return NULL;
if (index == -1) {
@@ -895,7 +887,7 @@ int ED_mesh_mirror_get_vert(Object *ob, int index)
index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
}
else {
- index_mirr = mesh_get_x_mirror_vert(ob, index, use_topology);
+ index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, use_topology);
}
return index_mirr;
@@ -913,7 +905,9 @@ static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float
if (isnan(uv[0]) || !finite(uv[0]) ||
isnan(uv[1]) || !finite(uv[1])
)
+ {
return NULL;
+ }
if (axis) {
vec[0] = uv[0];
@@ -1005,31 +999,39 @@ static bool mirror_facecmp(const void *a, const void *b)
}
/* BMESH_TODO, convert to MPoly (functions above also) */
-int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
+int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, DerivedMesh *dm)
{
Mesh *me = ob->data;
- MVert *mv, *mvert = me->mvert;
- MFace mirrormf, *mf, *hashmf, *mface = me->mface;
+ MVert *mv, *mvert;
+ MFace mirrormf, *mf, *hashmf, *mface;
GHash *fhash;
- const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
int *mirrorverts, *mirrorfaces;
+
+ BLI_assert(em == NULL); /* Does not work otherwise, currently... */
+
+ const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ const int totvert = dm ? dm->getNumVerts(dm) : me->totvert;
+ const int totface = dm ? dm->getNumTessFaces(dm) : me->totface;
int a;
- mirrorverts = MEM_callocN(sizeof(int) * me->totvert, "MirrorVerts");
- mirrorfaces = MEM_callocN(sizeof(int) * 2 * me->totface, "MirrorFaces");
+ mirrorverts = MEM_callocN(sizeof(int) * totvert, "MirrorVerts");
+ mirrorfaces = MEM_callocN(sizeof(int) * 2 * totface, "MirrorFaces");
+
+ mvert = dm ? dm->getVertArray(dm) : me->mvert;
+ mface = dm ? dm->getTessFaceArray(dm) : me->mface;
- ED_mesh_mirror_spatial_table(ob, em, NULL, 's');
+ ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's');
- for (a = 0, mv = mvert; a < me->totvert; a++, mv++)
- mirrorverts[a] = mesh_get_x_mirror_vert(ob, a, use_topology);
+ for (a = 0, mv = mvert; a < totvert; a++, mv++)
+ mirrorverts[a] = mesh_get_x_mirror_vert(ob, dm, a, use_topology);
- ED_mesh_mirror_spatial_table(ob, em, NULL, 'e');
+ ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 'e');
fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
- for (a = 0, mf = mface; a < me->totface; a++, mf++)
+ for (a = 0, mf = mface; a < totface; a++, mf++)
BLI_ghash_insert(fhash, mf, mf);
- for (a = 0, mf = mface; a < me->totface; a++, mf++) {
+ for (a = 0, mf = mface; a < totface; a++, mf++) {
mirrormf.v1 = mirrorverts[mf->v3];
mirrormf.v2 = mirrorverts[mf->v2];
mirrormf.v3 = mirrorverts[mf->v1];
diff --git a/source/blender/editors/metaball/SConscript b/source/blender/editors/metaball/SConscript
deleted file mode 100644
index d31a10afe90..00000000000
--- a/source/blender/editors/metaball/SConscript
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-
-defs = []
-
-env.BlenderLib ( 'bf_editors_metaball', sources, incs, defs, libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 42eda235276..ed5bf4a92b4 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -63,7 +63,7 @@
#include "mball_intern.h"
/* This function is used to free all MetaElems from MetaBall */
-void free_editMball(Object *obedit)
+void ED_mball_editmball_free(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
@@ -73,7 +73,7 @@ void free_editMball(Object *obedit)
/* This function is called, when MetaBall Object is
* switched from object mode to edit mode */
-void make_editMball(Object *obedit)
+void ED_mball_editmball_make(Object *obedit)
{
MetaBall *mb = (MetaBall *)obedit->data;
MetaElem *ml; /*, *newml;*/
@@ -91,12 +91,12 @@ void make_editMball(Object *obedit)
/* This function is called, when MetaBall Object switched from
* edit mode to object mode. List of MetaElements is copied
* from object->data->edit_elems to object->data->elems. */
-void load_editMball(Object *UNUSED(obedit))
+void ED_mball_editmball_load(Object *UNUSED(obedit))
{
}
/* Add metaelem primitive to metaball object (which is in edit mode) */
-MetaElem *add_metaball_primitive(bContext *UNUSED(C), Object *obedit, float mat[4][4], float dia, int type)
+MetaElem *ED_mball_add_primitive(bContext *UNUSED(C), Object *obedit, float mat[4][4], float dia, int type)
{
MetaBall *mball = (MetaBall *)obedit->data;
MetaElem *ml;
@@ -372,17 +372,22 @@ static int select_random_metaelems_exec(bContext *C, wmOperator *op)
MetaBall *mb = (MetaBall *)obedit->data;
MetaElem *ml;
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- float percent = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
+ RNG *rng = BLI_rng_new_srandom(seed);
+
for (ml = mb->editelems->first; ml; ml = ml->next) {
- if (BLI_frand() < percent) {
+ if (BLI_rng_get_float(rng) < randfac) {
if (select)
ml->flag |= SELECT;
else
ml->flag &= ~SELECT;
}
}
-
+
+ BLI_rng_free(rng);
+
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
return OPERATOR_FINISHED;
@@ -404,9 +409,7 @@ void MBALL_OT_select_random_metaelems(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
- "Percent", "Percentage of elements to select randomly", 0.0f, 100.0f);
- WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+ WM_operator_properties_select_random(ot);
}
/***************************** Duplicate operator *****************************/
@@ -576,7 +579,7 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
/* Select MetaElement with mouse click (user can select radius circle or
* stiffness circle) */
-bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
static MetaElem *startelem = NULL;
Object *obedit = CTX_data_edit_object(C);
@@ -662,6 +665,11 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo
/* ************* undo for MetaBalls ************* */
+typedef struct UndoMBall {
+ ListBase editelems;
+ int lastelem_index;
+} UndoMBall;
+
/* free all MetaElems from ListBase */
static void freeMetaElemlist(ListBase *lb)
{
@@ -675,58 +683,61 @@ static void freeMetaElemlist(ListBase *lb)
}
-static void undoMball_to_editMball(void *lbu, void *lbe, void *UNUSED(obe))
+static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata))
{
- ListBase *lb = lbu;
- ListBase *editelems = lbe;
- MetaElem *ml, *newml;
-
- freeMetaElemlist(editelems);
+ MetaBall *mb = mb_v;
+ UndoMBall *umb = umb_v;
+
+ freeMetaElemlist(mb->editelems);
+ mb->lastelem = NULL;
/* copy 'undo' MetaElems to 'edit' MetaElems */
- ml = lb->first;
- while (ml) {
- newml = MEM_dupallocN(ml);
- BLI_addtail(editelems, newml);
- ml = ml->next;
+ int index = 0;
+ for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) {
+ MetaElem *ml_edit = MEM_dupallocN(ml_undo);
+ BLI_addtail(mb->editelems, ml_edit);
+ if (index == umb->lastelem_index) {
+ mb->lastelem = ml_edit;
+ }
}
}
-static void *editMball_to_undoMball(void *lbe, void *UNUSED(obe))
+static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata))
{
- ListBase *editelems = lbe;
- ListBase *lb;
- MetaElem *ml, *newml;
+ MetaBall *mb = mb_v;
+ UndoMBall *umb;
/* allocate memory for undo ListBase */
- lb = MEM_callocN(sizeof(ListBase), "listbase undo");
+ umb = MEM_callocN(sizeof(UndoMBall), __func__);
+ umb->lastelem_index = -1;
/* copy contents of current ListBase to the undo ListBase */
- ml = editelems->first;
- while (ml) {
- newml = MEM_dupallocN(ml);
- BLI_addtail(lb, newml);
- ml = ml->next;
+ int index = 0;
+ for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) {
+ MetaElem *ml_undo = MEM_dupallocN(ml_edit);
+ BLI_addtail(&umb->editelems, ml_undo);
+ if (ml_edit == mb->lastelem) {
+ umb->lastelem_index = index;
+ }
}
- return lb;
+ return umb;
}
/* free undo ListBase of MetaElems */
-static void free_undoMball(void *lbv)
+static void free_undoMball(void *umb_v)
{
- ListBase *lb = lbv;
+ UndoMBall *umb = umb_v;
- freeMetaElemlist(lb);
- MEM_freeN(lb);
+ freeMetaElemlist(&umb->editelems);
+ MEM_freeN(umb);
}
-static ListBase *metaball_get_editelems(Object *ob)
+static MetaBall *metaball_get_obdata(Object *ob)
{
if (ob && ob->type == OB_MBALL) {
- struct MetaBall *mb = (struct MetaBall *)ob->data;
- return mb->editelems;
+ return ob->data;
}
return NULL;
}
@@ -735,7 +746,7 @@ static ListBase *metaball_get_editelems(Object *ob)
static void *get_data(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
- return metaball_get_editelems(obedit);
+ return metaball_get_obdata(obedit);
}
/* this is undo system for MetaBalls */
diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript
deleted file mode 100644
index 914ffa3061c..00000000000
--- a/source/blender/editors/object/SConscript
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/extern/recastnavigation',
- '#/intern/guardedalloc',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../ikplugin',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../python',
- # for object_bake.c
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_object', sources, Split(incs), defs, libtype=['core'], priority=[35] )
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 615fbb527b3..88ab3450b04 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -116,7 +116,7 @@
/* this is an exact copy of the define in rna_lamp.c
* kept here because of linking order.
* Icons are only defined here */
-EnumPropertyItem lamp_type_items[] = {
+EnumPropertyItem rna_enum_lamp_type_items[] = {
{LA_LOCAL, "POINT", ICON_LAMP_POINT, "Point", "Omnidirectional point light source"},
{LA_SUN, "SUN", ICON_LAMP_SUN, "Sun", "Constant direction parallel ray light source"},
{LA_SPOT, "SPOT", ICON_LAMP_SPOT, "Spot", "Directional cone light source"},
@@ -261,10 +261,7 @@ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(sc
void ED_object_add_unit_props(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
- prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
- RNA_def_property_subtype(prop, PROP_DISTANCE);
+ RNA_def_float_distance(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
}
void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
@@ -293,6 +290,11 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+void ED_object_add_mesh_props(wmOperatorType *ot)
+{
+ RNA_def_boolean(ot->srna, "calc_uvs", false, "Generate UVs", "Generate a default UV map");
+}
+
bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view_align_axis,
float loc[3], float rot[3],
bool *enter_editmode, unsigned int *layer, bool *is_view_aligned)
@@ -482,7 +484,7 @@ void OBJECT_OT_add(wmOperatorType *ot)
/* properties */
ED_object_add_unit_props(ot);
- RNA_def_enum(ot->srna, "type", object_type_items, 0, "Type", "");
+ RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 0, "Type", "");
ED_object_add_generic_props(ot, true);
}
@@ -516,7 +518,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
cu->flag |= CU_PATH | CU_3D;
ED_object_editmode_enter(C, 0);
ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- BLI_addtail(&cu->editnurb->nurbs, add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia));
+ BLI_addtail(&cu->editnurb->nurbs, ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia));
if (!enter_editmode)
ED_object_editmode_exit(C, EM_FREEDATA);
}
@@ -641,7 +643,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
dia = RNA_float_get(op->ptr, "radius");
- add_metaball_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
+ ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
/* userdef */
if (newob && !enter_editmode) {
@@ -668,7 +670,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", metaelem_type_items, 0, "Primitive", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", "");
ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, true);
@@ -815,7 +817,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", object_empty_drawtype_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_empty_drawtype_items, 0, "Type", "");
ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, false);
@@ -951,7 +953,7 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_lamp_type_items, 0, "Type", "");
RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_LAMP);
ED_object_add_unit_props(ot);
@@ -1149,7 +1151,6 @@ static int object_delete_exec(bContext *C, wmOperator *op)
}
}
/* end global */
-
}
CTX_DATA_END;
@@ -1157,12 +1158,12 @@ static int object_delete_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* delete has to handle all open scenes */
- BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, 1);
+ BKE_main_id_tag_listbase(&bmain->scene, LIB_TAG_DOIT, true);
for (win = wm->windows.first; win; win = win->next) {
scene = win->screen->scene;
- if (scene->id.flag & LIB_DOIT) {
- scene->id.flag &= ~LIB_DOIT;
+ if (scene->id.tag & LIB_TAG_DOIT) {
+ scene->id.tag &= ~LIB_TAG_DOIT;
DAG_relations_tag_update(bmain);
@@ -1195,89 +1196,16 @@ void OBJECT_OT_delete(wmOperatorType *ot)
/**************************** Copy Utilities ******************************/
/* after copying objects, copied data should get new pointers */
-static void copy_object_set_idnew(bContext *C, int dupflag)
+static void copy_object_set_idnew(bContext *C)
{
Main *bmain = CTX_data_main(C);
- Material *ma, *mao;
- ID *id;
- int a;
- /* XXX check object pointers */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- BKE_object_relink(ob);
+ BKE_libblock_relink(&ob->id);
}
CTX_DATA_END;
- /* materials */
- if (dupflag & USER_DUP_MAT) {
- mao = bmain->mat.first;
- while (mao) {
- if (mao->id.newid) {
- ma = (Material *)mao->id.newid;
-
- if (dupflag & USER_DUP_TEX) {
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- id = (ID *)ma->mtex[a]->tex;
- if (id) {
- ID_NEW_US(ma->mtex[a]->tex)
- else
- ma->mtex[a]->tex = BKE_texture_copy(ma->mtex[a]->tex);
- id->us--;
- }
- }
- }
- }
-#if 0 // XXX old animation system
- id = (ID *)ma->ipo;
- if (id) {
- ID_NEW_US(ma->ipo)
- else
- ma->ipo = copy_ipo(ma->ipo);
- id->us--;
- }
-#endif // XXX old animation system
- }
- mao = mao->id.next;
- }
- }
-
-#if 0 // XXX old animation system
- /* lamps */
- if (dupflag & USER_DUP_IPO) {
- Lamp *la = bmain->lamp.first;
- while (la) {
- if (la->id.newid) {
- Lamp *lan = (Lamp *)la->id.newid;
- id = (ID *)lan->ipo;
- if (id) {
- ID_NEW_US(lan->ipo)
- else
- lan->ipo = copy_ipo(lan->ipo);
- id->us--;
- }
- }
- la = la->id.next;
- }
- }
-
- /* ipos */
- ipo = bmain->ipo.first;
- while (ipo) {
- if (ipo->id.lib == NULL && ipo->id.newid) {
- Ipo *ipon = (Ipo *)ipo->id.newid;
- IpoCurve *icu;
- for (icu = ipon->curve.first; icu; icu = icu->next) {
- if (icu->driver) {
- ID_NEW(icu->driver->ob);
- }
- }
- }
- ipo = ipo->id.next;
- }
-#endif // XXX old animation system
-
set_sca_new_poins();
BKE_main_id_clear_newpoins(bmain);
@@ -1468,7 +1396,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base,
if (parent_gh)
BLI_ghash_free(parent_gh, NULL, NULL);
- copy_object_set_idnew(C, 0);
+ copy_object_set_idnew(C);
free_object_duplilist(lb);
@@ -1616,7 +1544,7 @@ static int convert_exec(bContext *C, wmOperator *op)
/* flag data thats not been edited (only needed for !keep_original) */
if (ob->data) {
- ((ID *)ob->data)->flag |= LIB_DOIT;
+ ((ID *)ob->data)->tag |= LIB_TAG_DOIT;
}
/* possible metaball basis is not in this scene */
@@ -1660,7 +1588,7 @@ static int convert_exec(bContext *C, wmOperator *op)
/* decrement original mesh's usage count */
me = newob->data;
- me->id.us--;
+ id_us_min(&me->id);
/* make a new copy of the mesh */
newob->data = BKE_mesh_copy(me);
@@ -1685,7 +1613,7 @@ static int convert_exec(bContext *C, wmOperator *op)
/* decrement original mesh's usage count */
me = newob->data;
- me->id.us--;
+ id_us_min(&me->id);
/* make a new copy of the mesh */
newob->data = BKE_mesh_copy(me);
@@ -1716,7 +1644,7 @@ static int convert_exec(bContext *C, wmOperator *op)
newob = basen->object;
/* decrement original curve's usage count */
- ((Curve *)newob->data)->id.us--;
+ id_us_min(&((Curve *)newob->data)->id);
/* make a new copy of the curve */
newob->data = BKE_curve_copy(ob->data);
@@ -1737,19 +1665,19 @@ static int convert_exec(bContext *C, wmOperator *op)
cu->type = OB_CURVE;
if (cu->vfont) {
- cu->vfont->id.us--;
+ id_us_min(&cu->vfont->id);
cu->vfont = NULL;
}
if (cu->vfontb) {
- cu->vfontb->id.us--;
+ id_us_min(&cu->vfontb->id);
cu->vfontb = NULL;
}
if (cu->vfonti) {
- cu->vfonti->id.us--;
+ id_us_min(&cu->vfonti->id);
cu->vfonti = NULL;
}
if (cu->vfontbi) {
- cu->vfontbi->id.us--;
+ id_us_min(&cu->vfontbi->id);
cu->vfontbi = NULL;
}
@@ -1787,7 +1715,7 @@ static int convert_exec(bContext *C, wmOperator *op)
newob = basen->object;
/* decrement original curve's usage count */
- ((Curve *)newob->data)->id.us--;
+ id_us_min(&((Curve *)newob->data)->id);
/* make a new copy of the curve */
newob->data = BKE_curve_copy(ob->data);
@@ -1822,7 +1750,7 @@ static int convert_exec(bContext *C, wmOperator *op)
newob = basen->object;
mb = newob->data;
- mb->id.us--;
+ id_us_min(&mb->id);
newob->data = BKE_mesh_add(bmain, "Mesh");
newob->type = OB_MESH;
@@ -1862,7 +1790,7 @@ static int convert_exec(bContext *C, wmOperator *op)
if (!keep_original && (ob->flag & OB_DONE)) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- ((ID *)ob->data)->flag &= ~LIB_DOIT; /* flag not to convert this datablock again */
+ ((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */
}
}
CTX_DATA_END;
@@ -1988,7 +1916,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
ID_NEW_US(obn->mat[a])
else
obn->mat[a] = BKE_material_copy(obn->mat[a]);
- id->us--;
+ id_us_min(id);
if (dupflag & USER_DUP_ACT) {
BKE_animdata_copy_id_action(&obn->mat[a]->id);
@@ -2009,7 +1937,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
BKE_animdata_copy_id_action(&psys->part->id);
}
- id->us--;
+ id_us_min(id);
}
}
}
@@ -2023,12 +1951,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
ID_NEW_US2(obn->data)
else {
obn->data = BKE_mesh_copy(obn->data);
- if (obn->fluidsimSettings) {
- obn->fluidsimSettings->orgMesh = (Mesh *)obn->data;
- }
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_CURVE:
@@ -2038,7 +1963,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_curve_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_SURF:
@@ -2048,7 +1973,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_curve_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_FONT:
@@ -2058,7 +1983,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_curve_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_MBALL:
@@ -2068,7 +1993,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_mball_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_LAMP:
@@ -2078,7 +2003,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_lamp_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_ARMATURE:
@@ -2092,7 +2017,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
BKE_pose_rebuild(obn, obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_LATTICE:
@@ -2102,7 +2027,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_lattice_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_CAMERA:
@@ -2112,7 +2037,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_camera_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
case OB_SPEAKER:
@@ -2122,7 +2047,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
obn->data = BKE_speaker_copy(obn->data);
didit = 1;
}
- id->us--;
+ id_us_min(id);
}
break;
}
@@ -2159,7 +2084,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base
ID_NEW_US((*matarar)[a])
else
(*matarar)[a] = BKE_material_copy((*matarar)[a]);
- id->us--;
+ id_us_min(id);
}
}
}
@@ -2190,7 +2115,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag
ob = basen->object;
/* link own references to the newly duplicated data [#26816] */
- BKE_object_relink(ob);
+ BKE_libblock_relink(&ob->id);
set_sca_new_poins_ob(ob);
/* DAG_relations_tag_update(bmain); */ /* caller must do */
@@ -2235,7 +2160,7 @@ static int duplicate_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- copy_object_set_idnew(C, dupflag);
+ copy_object_set_idnew(C);
DAG_relations_tag_update(bmain);
@@ -2262,7 +2187,7 @@ void OBJECT_OT_duplicate(wmOperatorType *ot)
/* to give to transform */
RNA_def_boolean(ot->srna, "linked", 0, "Linked", "Duplicate object but not object data, linking to the original data");
- prop = RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+ prop = RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
@@ -2320,7 +2245,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
ED_base_object_select(basen, BA_SELECT);
ED_base_object_activate(C, basen);
- copy_object_set_idnew(C, dupflag);
+ copy_object_set_idnew(C);
DAG_relations_tag_update(bmain);
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index ecaa05ace99..888bf832042 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -267,7 +267,7 @@ static void clear_single_image(Image *image, ClearFlag flag)
const float disp_alpha[4] = {0.5f, 0.5f, 0.5f, 0.0f};
const float disp_solid[4] = {0.5f, 0.5f, 0.5f, 1.0f};
- if ((image->id.flag & LIB_DOIT) == 0) {
+ if ((image->id.tag & LIB_TAG_DOIT) == 0) {
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
if (flag == CLEAR_TANGENT_NORMAL)
@@ -277,7 +277,7 @@ static void clear_single_image(Image *image, ClearFlag flag)
else
IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
- image->id.flag |= LIB_DOIT;
+ image->id.tag |= LIB_TAG_DOIT;
BKE_image_release_ibuf(image, ibuf, NULL);
}
@@ -288,7 +288,7 @@ static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag)
int a;
for (a = 0; a < totpoly; a++) {
- mtpoly[a].tpage->id.flag &= ~LIB_DOIT;
+ mtpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
}
for (a = 0; a < totpoly; a++) {
@@ -296,7 +296,7 @@ static void clear_images_poly(MTexPoly *mtpoly, int totpoly, ClearFlag flag)
}
for (a = 0; a < totpoly; a++) {
- mtpoly[a].tpage->id.flag &= ~LIB_DOIT;
+ mtpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
}
}
@@ -670,7 +670,7 @@ static void finish_bake_internal(BakeRender *bkr)
Mesh *me;
BLI_assert(BLI_thread_is_main());
for (me = G.main->mesh.first; me; me = me->id.next) {
- if (me->id.flag & LIB_DOIT) {
+ if (me->id.tag & LIB_TAG_DOIT) {
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
BKE_mesh_tessface_clear(me);
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 2c4f7a8e107..fd95d6129ad 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -76,6 +76,8 @@
#include "object_intern.h"
+/* prototypes */
+static void bake_set_props(wmOperator *op, Scene *scene);
typedef struct BakeAPIRender {
Object *ob;
@@ -85,6 +87,7 @@ typedef struct BakeAPIRender {
ListBase selected_objects;
ScenePassType pass_type;
+ int pass_filter;
int margin;
int save_mode;
@@ -421,11 +424,72 @@ static bool bake_object_check(Object *ob, ReportList *reports)
return false;
}
- image->id.flag |= LIB_DOIT;
+ image->id.tag |= LIB_TAG_DOIT;
}
return true;
}
+static bool bake_pass_filter_check(ScenePassType pass_type, const int pass_filter, ReportList *reports)
+{
+ switch (pass_type) {
+ case SCE_PASS_COMBINED:
+ if ((pass_filter & R_BAKE_PASS_FILTER_EMIT) != 0) {
+ return true;
+ }
+
+ if (((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) ||
+ ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0))
+ {
+ if (((pass_filter & R_BAKE_PASS_FILTER_DIFFUSE) != 0) ||
+ ((pass_filter & R_BAKE_PASS_FILTER_GLOSSY) != 0) ||
+ ((pass_filter & R_BAKE_PASS_FILTER_TRANSM) != 0) ||
+ ((pass_filter & R_BAKE_PASS_FILTER_SUBSURFACE) != 0))
+ {
+ return true;
+ }
+
+ if ((pass_filter & R_BAKE_PASS_FILTER_AO) != 0) {
+ BKE_report(reports, RPT_ERROR,
+ "Combined bake pass Ambient Occlusion contribution requires an enabled light pass "
+ "(bake the Ambient Occlusion pass type instead)");
+ }
+ else {
+ BKE_report(reports, RPT_ERROR,
+ "Combined bake pass requires Emit, or a light pass with "
+ "Direct or Indirect contributions enabled");
+ }
+
+ return false;
+ }
+ else {
+ BKE_report(reports, RPT_ERROR,
+ "Combined bake pass requires Emit, or a light pass with "
+ "Direct or Indirect contributions enabled");
+ return false;
+ }
+ break;
+ case SCE_PASS_DIFFUSE_COLOR:
+ case SCE_PASS_GLOSSY_COLOR:
+ case SCE_PASS_TRANSM_COLOR:
+ case SCE_PASS_SUBSURFACE_COLOR:
+ if (((pass_filter & R_BAKE_PASS_FILTER_COLOR) != 0) ||
+ ((pass_filter & R_BAKE_PASS_FILTER_DIRECT) != 0) ||
+ ((pass_filter & R_BAKE_PASS_FILTER_INDIRECT) != 0))
+ {
+ return true;
+ }
+ else {
+ BKE_report(reports, RPT_ERROR,
+ "Bake pass requires Direct, Indirect, or Color contributions to be enabled");
+ return false;
+ }
+ break;
+ default:
+ return true;
+ break;
+ }
+}
+
/* before even getting in the bake function we check for some basic errors */
static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objects,
ReportList *reports, const bool is_selected_to_active)
@@ -433,7 +497,7 @@ static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objec
CollectionPointerLink *link;
/* error handling and tag (in case multiple materials share the same image) */
- BKE_main_id_tag_idcode(bmain, ID_IM, false);
+ BKE_main_id_tag_idcode(bmain, ID_IM, LIB_TAG_DOIT, false);
if (is_selected_to_active) {
int tot_objects = 0;
@@ -478,7 +542,7 @@ static void bake_images_clear(Main *bmain, const bool is_tangent)
{
Image *image;
for (image = bmain->image.first; image; image = image->id.next) {
- if ((image->id.flag & LIB_DOIT) != 0) {
+ if ((image->id.tag & LIB_TAG_DOIT) != 0) {
RE_bake_ibuf_clear(image, is_tangent);
}
}
@@ -491,13 +555,13 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
int tot_images = 0;
/* error handling and tag (in case multiple materials share the same image) */
- BKE_main_id_tag_idcode(bmain, ID_IM, false);
+ BKE_main_id_tag_idcode(bmain, ID_IM, LIB_TAG_DOIT, false);
for (i = 0; i < tot_mat; i++) {
Image *image;
ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
- if ((image->id.flag & LIB_DOIT)) {
+ if ((image->id.tag & LIB_TAG_DOIT)) {
for (j = 0; j < i; j++) {
if (bake_images->data[j].image == image) {
bake_images->lookup[i] = j;
@@ -508,7 +572,7 @@ static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
else {
bake_images->lookup[i] = tot_images;
bake_images->data[tot_images].image = image;
- image->id.flag |= LIB_DOIT;
+ image->id.tag |= LIB_TAG_DOIT;
tot_images++;
}
}
@@ -548,9 +612,21 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re
return tot_size;
}
+/* create new mesh with edit mode changes and modifiers applied */
+static Mesh *bake_mesh_new_from_object(Main *bmain, Scene *scene, Object *ob)
+{
+ if (ob->mode & OB_MODE_EDIT)
+ ED_object_editmode_load(ob);
+
+ Mesh *me = BKE_mesh_new_from_object(bmain, scene, ob, 1, 2, 0, 0);
+ BKE_mesh_split_faces(me);
+
+ return me;
+}
+
static int bake(
Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
- const ScenePassType pass_type, const int margin,
+ const ScenePassType pass_type, const int pass_filter, const int margin,
const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage,
const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[],
@@ -571,6 +647,9 @@ static int bake(
Mesh *me_low = NULL;
Mesh *me_cage = NULL;
+ MultiresModifierData *mmd_low = NULL;
+ int mmd_flags_low = 0;
+
float *result = NULL;
BakePixel *pixel_array_low = NULL;
@@ -584,7 +663,6 @@ static int bake(
size_t num_pixels;
int tot_materials;
- int i;
RE_bake_engine_set_engine_parameters(re, bmain, scene);
@@ -641,7 +719,7 @@ static int bake(
num_pixels = (size_t)width * (size_t)height * bake_images.size;
- for (i = 0; i < bake_images.size; i++) {
+ for (int i = 0; i < bake_images.size; i++) {
bake_images.data[i].width = width;
bake_images.data[i].height = height;
bake_images.data[i].offset = (is_split_materials ? num_pixels : 0);
@@ -650,8 +728,9 @@ static int bake(
if (!is_split_materials) {
/* saving a single image */
- for (i = 0; i < tot_materials; i++)
+ for (int i = 0; i < tot_materials; i++) {
bake_images.lookup[i] = 0;
+ }
}
}
@@ -686,10 +765,17 @@ static int bake(
pixel_array_high = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
+ /* for multires bake, use linear UV subdivision to match low res UVs */
+ if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT && !is_selected_to_active) {
+ mmd_low = (MultiresModifierData *) modifiers_findByType(ob_low, eModifierType_Multires);
+ if (mmd_low) {
+ mmd_flags_low = mmd_low->flags;
+ mmd_low->flags |= eMultiresModifierFlag_PlainUv;
+ }
+ }
+
/* get the mesh as it arrives in the renderer */
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
- BKE_mesh_split_faces(me_low);
- BKE_mesh_tessface_ensure(me_low);
+ me_low = bake_mesh_new_from_object(bmain, scene, ob_low);
/* populate the pixel array with the face data */
if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
@@ -704,10 +790,8 @@ static int bake(
/* prepare cage mesh */
if (ob_cage) {
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 0, 0);
- BKE_mesh_split_faces(me_cage);
- BKE_mesh_tessface_ensure(me_cage);
- if (me_low->totface != me_cage->totface) {
+ me_cage = bake_mesh_new_from_object(bmain, scene, ob_cage);
+ if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) {
BKE_report(reports, RPT_ERROR,
"Invalid cage object, the cage mesh must have the same number "
"of faces as the active object");
@@ -738,9 +822,7 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
- BKE_mesh_split_faces(me_cage);
- BKE_mesh_tessface_ensure(me_cage);
+ me_cage = bake_mesh_new_from_object(bmain, scene, ob_low);
RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
@@ -766,10 +848,8 @@ static int bake(
tmd->quad_method = MOD_TRIANGULATE_QUAD_FIXED;
tmd->ngon_method = MOD_TRIANGULATE_NGON_EARCLIP;
- highpoly[i].me = BKE_mesh_new_from_object(bmain, scene, highpoly[i].ob, 1, 2, 0, 0);
+ highpoly[i].me = bake_mesh_new_from_object(bmain, scene, highpoly[i].ob);
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
- BKE_mesh_split_faces(highpoly[i].me);
- BKE_mesh_tessface_ensure(highpoly[i].me);
/* lowpoly to highpoly transformation matrix */
copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat);
@@ -796,7 +876,7 @@ static int bake(
/* the baking itself */
for (i = 0; i < tot_highpoly; i++) {
ok = RE_bake_engine(re, highpoly[i].ob, i, pixel_array_high,
- num_pixels, depth, pass_type, result);
+ num_pixels, depth, pass_type, pass_filter, result);
if (!ok) {
BKE_reportf(reports, RPT_ERROR, "Error baking from object \"%s\"", highpoly[i].ob->id.name + 2);
goto cage_cleanup;
@@ -822,7 +902,7 @@ cage_cleanup:
ob_low->restrictflag &= ~OB_RESTRICT_RENDER;
if (RE_bake_has_engine(re)) {
- ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, result);
+ ok = RE_bake_engine(re, ob_low, 0, pixel_array_low, num_pixels, depth, pass_type, pass_filter, result);
}
else {
BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
@@ -871,9 +951,7 @@ cage_cleanup:
md->mode &= ~eModifierMode_Render;
}
- me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 0, 0);
- BKE_mesh_split_faces(me_nores);
- BKE_mesh_tessface_ensure(me_nores);
+ me_nores = bake_mesh_new_from_object(bmain, scene, ob_low);
RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer);
RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
@@ -895,7 +973,7 @@ cage_cleanup:
}
else {
/* save the results */
- for (i = 0; i < bake_images.size; i++) {
+ for (int i = 0; i < bake_images.size; i++) {
BakeImage *bk_image = &bake_images.data[i];
if (is_save_internal) {
@@ -997,6 +1075,9 @@ cleanup:
ob_low->restrictflag = restrict_flag_low;
+ if (mmd_low)
+ mmd_low->flags = mmd_flags_low;
+
if (ob_cage)
ob_cage->restrictflag = restrict_flag_cage;
@@ -1035,6 +1116,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
bkr->pass_type = RNA_enum_get(op->ptr, "type");
+ bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
bkr->margin = RNA_int_get(op->ptr, "margin");
bkr->save_mode = RNA_enum_get(op->ptr, "save_mode");
@@ -1083,6 +1165,9 @@ static int bake_exec(bContext *C, wmOperator *op)
Render *re;
int result = OPERATOR_CANCELLED;
BakeAPIRender bkr = {NULL};
+ Scene *scene = CTX_data_scene(C);
+
+ bake_set_props(op, scene);
bake_init_api_data(op, C, &bkr);
re = bkr.render;
@@ -1090,6 +1175,10 @@ static int bake_exec(bContext *C, wmOperator *op)
/* setup new render */
RE_test_break_cb(re, NULL, bake_break);
+ if (!bake_pass_filter_check(bkr.pass_type, bkr.pass_filter, bkr.reports)) {
+ goto finally;
+ }
+
if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) {
goto finally;
}
@@ -1104,7 +1193,7 @@ static int bake_exec(bContext *C, wmOperator *op)
if (bkr.is_selected_to_active) {
result = bake(
bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
- bkr.pass_type, bkr.margin, bkr.save_mode,
+ bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode,
bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage,
bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
@@ -1117,7 +1206,7 @@ static int bake_exec(bContext *C, wmOperator *op)
Object *ob_iter = link->ptr.data;
result = bake(
bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports,
- bkr.pass_type, bkr.margin, bkr.save_mode,
+ bkr.pass_type, bkr.pass_filter, bkr.margin, bkr.save_mode,
is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage,
bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
@@ -1143,6 +1232,11 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
RE_SetReports(bkr->render, bkr->reports);
+ if (!bake_pass_filter_check(bkr->pass_type, bkr->pass_filter, bkr->reports)) {
+ bkr->result = OPERATOR_CANCELLED;
+ return;
+ }
+
if (!bake_objects_check(bkr->main, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
bkr->result = OPERATOR_CANCELLED;
return;
@@ -1156,7 +1250,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
if (bkr->is_selected_to_active) {
bkr->result = bake(
bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
- bkr->pass_type, bkr->margin, bkr->save_mode,
+ bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage,
bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
@@ -1169,7 +1263,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
Object *ob_iter = link->ptr.data;
bkr->result = bake(
bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports,
- bkr->pass_type, bkr->margin, bkr->save_mode,
+ bkr->pass_type, bkr->pass_filter, bkr->margin, bkr->save_mode,
is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage,
bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
@@ -1277,6 +1371,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_AUTO_NAME) != 0);
}
+
+ prop = RNA_struct_find_property(op->ptr, "pass_filter");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, bake->pass_filter);
+ }
}
static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -1325,6 +1424,8 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
void OBJECT_OT_bake(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Bake";
ot->description = "Bake image textures of selected objects";
@@ -1336,8 +1437,11 @@ void OBJECT_OT_bake(wmOperatorType *ot)
ot->invoke = bake_invoke;
ot->poll = ED_operator_object_active_editable_mesh;
- RNA_def_enum(ot->srna, "type", render_pass_type_items, SCE_PASS_COMBINED, "Type",
+ RNA_def_enum(ot->srna, "type", rna_enum_bake_pass_type_items, SCE_PASS_COMBINED, "Type",
"Type of pass to bake, some of them may not be supported by the current render engine");
+ prop = RNA_def_enum(ot->srna, "pass_filter", rna_enum_bake_pass_filter_type_items, R_BAKE_PASS_FILTER_NONE, "Pass Filter",
+ "Filter to combined, diffuse, glossy, transmission and subsurface passes");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path",
"Image filepath to use when saving externally");
RNA_def_int(ot->srna, "width", 512, 1, INT_MAX, "Width",
@@ -1352,12 +1456,12 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Distance to use for the inward ray cast when using selected to active", 0.0f, 1.0f);
RNA_def_string(ot->srna, "cage_object", NULL, MAX_NAME, "Cage Object",
"Object to use as cage, instead of calculating the cage from the active object with cage extrusion");
- RNA_def_enum(ot->srna, "normal_space", normal_space_items, R_BAKE_SPACE_TANGENT, "Normal Space",
+ RNA_def_enum(ot->srna, "normal_space", rna_enum_normal_space_items, R_BAKE_SPACE_TANGENT, "Normal Space",
"Choose normal space for baking");
- RNA_def_enum(ot->srna, "normal_r", normal_swizzle_items, R_BAKE_POSX, "R", "Axis to bake in red channel");
- RNA_def_enum(ot->srna, "normal_g", normal_swizzle_items, R_BAKE_POSY, "G", "Axis to bake in green channel");
- RNA_def_enum(ot->srna, "normal_b", normal_swizzle_items, R_BAKE_POSZ, "B", "Axis to bake in blue channel");
- RNA_def_enum(ot->srna, "save_mode", bake_save_mode_items, R_BAKE_SAVE_INTERNAL, "Save Mode",
+ RNA_def_enum(ot->srna, "normal_r", rna_enum_normal_swizzle_items, R_BAKE_POSX, "R", "Axis to bake in red channel");
+ RNA_def_enum(ot->srna, "normal_g", rna_enum_normal_swizzle_items, R_BAKE_POSY, "G", "Axis to bake in green channel");
+ RNA_def_enum(ot->srna, "normal_b", rna_enum_normal_swizzle_items, R_BAKE_POSZ, "B", "Axis to bake in blue channel");
+ RNA_def_enum(ot->srna, "save_mode", rna_enum_bake_save_mode_items, R_BAKE_SAVE_INTERNAL, "Save Mode",
"Choose how to save the baking map");
RNA_def_boolean(ot->srna, "use_clear", false, "Clear",
"Clear Images before baking (only for internal saving)");
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 2697a5e5fb1..efd1ebbd51b 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1879,7 +1879,7 @@ void OBJECT_OT_constraint_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", "");
}
void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot)
@@ -1898,7 +1898,7 @@ void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", "");
}
void POSE_OT_constraint_add(wmOperatorType *ot)
@@ -1917,7 +1917,7 @@ void POSE_OT_constraint_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", "");
}
void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
@@ -1936,7 +1936,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_constraint_type_items, 0, "Type", "");
}
/************************ IK Constraint operators *********************/
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index 95e1204e122..47ee6752e51 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -89,7 +89,7 @@ static EnumPropertyItem DT_layer_items[] = {
{0, NULL, 0, NULL, NULL}
};
-/* Note: DT_layers_select_src_items enum is from rna_modifier.c */
+/* Note: rna_enum_dt_layers_select_src_items enum is from rna_modifier.c */
static EnumPropertyItem *dt_layers_select_src_itemf(
bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -99,18 +99,18 @@ static EnumPropertyItem *dt_layers_select_src_itemf(
const int data_type = RNA_enum_get(ptr, "data_type");
if (!C) { /* needed for docs and i18n tools */
- return DT_layers_select_src_items;
+ return rna_enum_dt_layers_select_src_items;
}
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC);
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ALL_SRC);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC);
if (data_type == DT_TYPE_MDEFORMVERT) {
Object *ob_src = CTX_data_active_object(C);
if (BKE_object_pose_armature_get(ob_src)) {
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
}
if (ob_src) {
@@ -182,7 +182,7 @@ static EnumPropertyItem *dt_layers_select_src_itemf(
return item;
}
-/* Note: DT_layers_select_dst_items enum is from rna_modifier.c */
+/* Note: rna_enum_dt_layers_select_dst_items enum is from rna_modifier.c */
static EnumPropertyItem *dt_layers_select_dst_itemf(
bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -192,14 +192,14 @@ static EnumPropertyItem *dt_layers_select_dst_itemf(
const int layers_select_src = RNA_enum_get(ptr, "layers_select_src");
if (!C) { /* needed for docs and i18n tools */
- return DT_layers_select_dst_items;
+ return rna_enum_dt_layers_select_dst_items;
}
if (layers_select_src == DT_LAYERS_ACTIVE_SRC || layers_select_src >= 0) {
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST);
}
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_NAME_DST);
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_INDEX_DST);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_INDEX_DST);
/* No 'specific' to-layers here, since we may transfer to several objects at once! */
@@ -229,7 +229,7 @@ static EnumPropertyItem *dt_layers_select_itemf(bContext *C, PointerRNA *ptr, Pr
}
}
-/* Note: DT_mix_mode_items enum is from rna_modifier.c */
+/* Note: rna_enum_dt_mix_mode_items enum is from rna_modifier.c */
static EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem *item = NULL;
@@ -239,24 +239,24 @@ static EnumPropertyItem *dt_mix_mode_itemf(bContext *C, PointerRNA *ptr, Propert
bool support_advanced_mixing, support_threshold;
if (!C) { /* needed for docs and i18n tools */
- return DT_mix_mode_items;
+ return rna_enum_dt_mix_mode_items;
}
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_TRANSFER);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER);
BKE_object_data_transfer_get_dttypes_capacity(dtdata_type, &support_advanced_mixing, &support_threshold);
if (support_threshold) {
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD);
}
if (support_advanced_mixing) {
RNA_enum_item_add_separator(&item, &totitem);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MIX);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_ADD);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_SUB);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MUL);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MIX);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_ADD);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_SUB);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MUL);
}
RNA_enum_item_end(&item, &totitem);
@@ -304,11 +304,11 @@ static void data_transfer_exec_preprocess_objects(
/* Do not transfer to linked data, not supported. */
BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified",
ob->id.name + 2, me->id.name + 2);
- me->id.flag &= ~LIB_DOIT;
+ me->id.tag &= ~LIB_TAG_DOIT;
continue;
}
- me->id.flag |= LIB_DOIT;
+ me->id.tag |= LIB_TAG_DOIT;
}
}
@@ -326,8 +326,8 @@ static bool data_transfer_exec_is_object_valid(
}
me = ob_dst->data;
- if (me->id.flag & LIB_DOIT) {
- me->id.flag &= ~LIB_DOIT;
+ if (me->id.tag & LIB_TAG_DOIT) {
+ me->id.tag &= ~LIB_TAG_DOIT;
return true;
}
else if (me->id.lib == NULL) {
@@ -562,13 +562,13 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_create", true, "Create Data", "Add data layers on destination meshes if needed");
/* Mapping methods. */
- RNA_def_enum(ot->srna, "vert_mapping", DT_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping",
+ RNA_def_enum(ot->srna, "vert_mapping", rna_enum_dt_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping",
"Method used to map source vertices to destination ones");
- RNA_def_enum(ot->srna, "edge_mapping", DT_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping",
+ RNA_def_enum(ot->srna, "edge_mapping", rna_enum_dt_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping",
"Method used to map source edges to destination ones");
- RNA_def_enum(ot->srna, "loop_mapping", DT_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR,
+ RNA_def_enum(ot->srna, "loop_mapping", rna_enum_dt_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR,
"Face Corner Mapping", "Method used to map source faces' corners to destination ones");
- RNA_def_enum(ot->srna, "poly_mapping", DT_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping",
+ RNA_def_enum(ot->srna, "poly_mapping", rna_enum_dt_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping",
"Method used to map source faces to destination ones");
/* Mapping options and filtering. */
@@ -593,15 +593,15 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot)
RNA_def_property_subtype(prop, PROP_FACTOR);
/* How to handle multi-layers types of data. */
- prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC,
+ prop = RNA_def_enum(ot->srna, "layers_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC,
"Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf);
- prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST,
+ prop = RNA_def_enum(ot->srna, "layers_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST,
"Destination Layers Matching", "How to match source and destination layers");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_itemf);
- prop = RNA_def_enum(ot->srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode",
+ prop = RNA_def_enum(ot->srna, "mix_mode", rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode",
"How to affect destination elements with source values");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_mix_mode_itemf);
RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor",
@@ -719,11 +719,11 @@ void OBJECT_OT_datalayout_transfer(wmOperatorType *ot)
"Also delete some data layers from destination if necessary, so that it matches exactly source");
/* How to handle multi-layers types of data. */
- prop = RNA_def_enum(ot->srna, "layers_select_src", DT_layers_select_src_items, DT_LAYERS_ACTIVE_SRC,
+ prop = RNA_def_enum(ot->srna, "layers_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ACTIVE_SRC,
"Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_src_itemf);
- prop = RNA_def_enum(ot->srna, "layers_select_dst", DT_layers_select_dst_items, DT_LAYERS_ACTIVE_DST,
+ prop = RNA_def_enum(ot->srna, "layers_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_ACTIVE_DST,
"Destination Layers Matching", "How to match source and destination layers");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, dt_layers_select_dst_itemf);
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index c87eeaeb4a3..38f22beff8d 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -46,6 +46,7 @@
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
@@ -341,8 +342,8 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
me->edit_btmesh = NULL;
}
if (obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, 'e');
+ ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_topo_table(NULL, NULL, 'e');
}
}
else if (obedit->type == OB_ARMATURE) {
@@ -356,20 +357,20 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
DAG_relations_tag_update(bmain);
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
- load_editNurb(obedit);
- if (freedata) free_editNurb(obedit);
+ ED_curve_editnurb_load(obedit);
+ if (freedata) ED_curve_editnurb_free(obedit);
}
else if (obedit->type == OB_FONT) {
- load_editText(obedit);
- if (freedata) free_editText(obedit);
+ ED_curve_editfont_load(obedit);
+ if (freedata) ED_curve_editfont_free(obedit);
}
else if (obedit->type == OB_LATTICE) {
- load_editLatt(obedit);
- if (freedata) free_editLatt(obedit);
+ ED_lattice_editlatt_load(obedit);
+ if (freedata) ED_lattice_editlatt_free(obedit);
}
else if (obedit->type == OB_MBALL) {
- load_editMball(obedit);
- if (freedata) free_editMball(obedit);
+ ED_mball_editmball_load(obedit);
+ if (freedata) ED_mball_editmball_free(obedit);
}
/* Tag update so no access to freed data referenced from
@@ -532,28 +533,28 @@ void ED_object_editmode_enter(bContext *C, int flag)
else if (ob->type == OB_FONT) {
scene->obedit = ob; /* XXX for context */
ok = 1;
- make_editText(ob);
+ ED_curve_editfont_make(ob);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_TEXT, scene);
}
else if (ob->type == OB_MBALL) {
scene->obedit = ob; /* XXX for context */
ok = 1;
- make_editMball(ob);
+ ED_mball_editmball_make(ob);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_MBALL, scene);
}
else if (ob->type == OB_LATTICE) {
scene->obedit = ob; /* XXX for context */
ok = 1;
- make_editLatt(ob);
+ ED_lattice_editlatt_make(ob);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_LATTICE, scene);
}
else if (ob->type == OB_SURF || ob->type == OB_CURVE) {
ok = 1;
scene->obedit = ob; /* XXX for context */
- make_editNurb(ob);
+ ED_curve_editnurb_make(ob);
WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_EDITMODE_CURVE, scene);
}
@@ -934,16 +935,20 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
cu1->wordspace = cu->wordspace;
cu1->ulpos = cu->ulpos;
cu1->ulheight = cu->ulheight;
- if (cu1->vfont) cu1->vfont->id.us--;
+ if (cu1->vfont)
+ id_us_min(&cu1->vfont->id);
cu1->vfont = cu->vfont;
id_us_plus((ID *)cu1->vfont);
- if (cu1->vfontb) cu1->vfontb->id.us--;
+ if (cu1->vfontb)
+ id_us_min(&cu1->vfontb->id);
cu1->vfontb = cu->vfontb;
id_us_plus((ID *)cu1->vfontb);
- if (cu1->vfonti) cu1->vfonti->id.us--;
+ if (cu1->vfonti)
+ id_us_min(&cu1->vfonti->id);
cu1->vfonti = cu->vfonti;
id_us_plus((ID *)cu1->vfonti);
- if (cu1->vfontbi) cu1->vfontbi->id.us--;
+ if (cu1->vfontbi)
+ id_us_min(&cu1->vfontbi->id);
cu1->vfontbi = cu->vfontbi;
id_us_plus((ID *)cu1->vfontbi);
@@ -1276,6 +1281,16 @@ void OBJECT_OT_paths_calculate(wmOperatorType *ot)
/* --------- */
+static int object_update_paths_poll(bContext *C)
+{
+ if (ED_operator_object_active_editable(C)) {
+ Object *ob = ED_object_active_context(C);
+ return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
+ }
+
+ return false;
+}
+
static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1301,7 +1316,7 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
/* api callbakcs */
ot->exec = object_update_paths_exec;
- ot->poll = ED_operator_object_active_editable; /* TODO: this should probably check for existing paths */
+ ot->poll = object_update_paths_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1309,26 +1324,44 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
/* --------- */
-/* Clear motion paths for selected objects only */
-void ED_objects_clear_paths(bContext *C)
+/* Helper for ED_objects_clear_paths() */
+static void object_clear_mpath(Object *ob)
{
- /* loop over objects in scene */
- CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects)
- {
- if (ob->mpath) {
- animviz_free_motionpath(ob->mpath);
- ob->mpath = NULL;
- ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+ if (ob->mpath) {
+ animviz_free_motionpath(ob->mpath);
+ ob->mpath = NULL;
+ ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+ }
+}
+
+/* Clear motion paths for all objects */
+void ED_objects_clear_paths(bContext *C, bool only_selected)
+{
+ if (only_selected) {
+ /* loop over all selected + sedtiable objects in scene */
+ CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects)
+ {
+ object_clear_mpath(ob);
}
+ CTX_DATA_END;
+ }
+ else {
+ /* loop over all edtiable objects in scene */
+ CTX_DATA_BEGIN(C, Object *, ob, editable_objects)
+ {
+ object_clear_mpath(ob);
+ }
+ CTX_DATA_END;
}
- CTX_DATA_END;
}
/* operator callback for this */
-static int object_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
-{
+static int object_clear_paths_exec(bContext *C, wmOperator *op)
+{
+ bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
+
/* use the backend function for this */
- ED_objects_clear_paths(C);
+ ED_objects_clear_paths(C, only_selected);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1336,19 +1369,34 @@ static int object_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+/* operator callback/wrapper */
+static int object_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+{
+ if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) {
+ RNA_boolean_set(op->ptr, "only_selected", true);
+ }
+ return object_clear_paths_exec(C, op);
+}
+
void OBJECT_OT_paths_clear(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Clear Object Paths";
ot->idname = "OBJECT_OT_paths_clear";
- ot->description = "Clear path caches for selected objects";
+ ot->description = "Clear path caches for all objects, hold Shift key for selected objects only";
/* api callbacks */
+ ot->invoke = object_clear_paths_invoke;
ot->exec = object_clear_paths_exec;
ot->poll = ED_operator_object_active_editable;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "only_selected", false, "Only Selected",
+ "Only clear paths from selected objects");
+ RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
@@ -1502,13 +1550,14 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
- EnumPropertyItem *input = object_mode_items;
+ EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
Object *ob;
+ bGPdata *gpd;
int totitem = 0;
if (!C) /* needed for docs */
- return object_mode_items;
+ return rna_enum_object_mode_items;
ob = CTX_data_active_object(C);
if (ob) {
@@ -1532,6 +1581,14 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(
/* We need at least this one! */
RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT);
}
+
+ /* On top of all the rest, GPencil Stroke Edit Mode
+ * is available if there's a valid gp datablock...
+ */
+ gpd = CTX_data_gpencil_data(C);
+ if (gpd) {
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_object_mode_items, OB_MODE_GPENCIL);
+ }
RNA_enum_item_end(&item, &totitem);
@@ -1556,6 +1613,8 @@ static const char *object_mode_op_string(int mode)
return "PARTICLE_OT_particle_edit_toggle";
if (mode == OB_MODE_POSE)
return "OBJECT_OT_posemode_toggle";
+ if (mode == OB_MODE_GPENCIL)
+ return "GPENCIL_OT_editmode_toggle";
return NULL;
}
@@ -1567,6 +1626,8 @@ static bool object_mode_compat_test(Object *ob, ObjectMode mode)
if (ob) {
if (mode == OB_MODE_OBJECT)
return true;
+ else if (mode == OB_MODE_GPENCIL)
+ return true; /* XXX: assume this is the case for now... */
switch (ob->type) {
case OB_MESH:
@@ -1621,13 +1682,45 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *re
return ok;
}
+static int object_mode_set_poll(bContext *C)
+{
+ /* Since Grease Pencil editmode is also handled here,
+ * we have a special exception for allowing this operator
+ * to still work in that case when there's no active object
+ * so that users can exit editmode this way as per normal.
+ */
+ if (ED_operator_object_active_editable(C))
+ return true;
+ else
+ return (CTX_data_gpencil_data(C) != NULL);
+}
+
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
ObjectMode mode = RNA_enum_get(op->ptr, "mode");
ObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
-
+
+ if (gpd) {
+ /* GP Mode is not bound to a specific object. Therefore,
+ * we don't want it to be actually saved on any objects,
+ * as weirdness can happen if you select other objects,
+ * or load old files.
+ *
+ * Instead, we use the following 2 rules to ensure that
+ * the mode selector works as expected:
+ * 1) If there's no object, we want to enter editmode.
+ * (i.e. with no object, we're in object mode)
+ * 2) Otherwise, exit stroke editmode, so that we can
+ * enter another mode...
+ */
+ if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
+ }
+ }
+
if (!ob || !object_mode_compat_test(ob, mode))
return OPERATOR_PASS_THROUGH;
@@ -1671,12 +1764,12 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_mode_set_exec;
- ot->poll = ED_operator_object_active_editable;
+ ot->poll = object_mode_set_poll; //ED_operator_object_active_editable;
/* flags */
ot->flag = 0; /* no register/undo here, leave it to operators being called */
- ot->prop = RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", "");
+ ot->prop = RNA_def_enum(ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
@@ -1734,7 +1827,7 @@ void OBJECT_OT_game_property_new(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "type", gameproperty_type_items, GPROP_FLOAT, "Type", "Type of game property to add");
+ RNA_def_enum(ot->srna, "type", rna_enum_gameproperty_type_items, GPROP_FLOAT, "Type", "Type of game property to add");
RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the game property to add");
}
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 3c43f2729bd..76a8a68c42d 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -521,12 +521,13 @@ void OBJECT_OT_group_remove(wmOperatorType *ot)
static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Main *bmain = CTX_data_main(C);
Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
if (!group)
return OPERATOR_CANCELLED;
- BKE_group_unlink(group);
+ BKE_group_unlink(bmain, group);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 7b7f91b974d..492b6724f93 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -318,6 +318,8 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
EDBM_mesh_load(obedit);
EDBM_mesh_make(scene->toolsettings, obedit);
+ DAG_id_tag_update(obedit->data, 0);
+
em = me->edit_btmesh;
EDBM_mesh_normals_update(em);
@@ -331,8 +333,8 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
}
case OB_CURVE:
case OB_SURF:
- load_editNurb(obedit);
- make_editNurb(obedit);
+ ED_curve_editnurb_load(obedit);
+ ED_curve_editnurb_make(obedit);
return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent);
case OB_LATTICE:
{
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 6344e04ef1b..9710e4f843d 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -106,6 +106,8 @@ void OBJECT_OT_select_by_layer(struct wmOperatorType *ot);
void OBJECT_OT_select_linked(struct wmOperatorType *ot);
void OBJECT_OT_select_grouped(struct wmOperatorType *ot);
void OBJECT_OT_select_mirror(struct wmOperatorType *ot);
+void OBJECT_OT_select_more(struct wmOperatorType *ot);
+void OBJECT_OT_select_less(struct wmOperatorType *ot);
void OBJECT_OT_select_same_group(struct wmOperatorType *ot);
/* object_add.c */
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index 76d9facf701..73ce1fae605 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -72,7 +72,7 @@
/********************** Load/Make/Free ********************/
-void free_editLatt(Object *ob)
+void ED_lattice_editlatt_free(Object *ob)
{
Lattice *lt = ob->data;
@@ -91,12 +91,12 @@ void free_editLatt(Object *ob)
}
}
-void make_editLatt(Object *obedit)
+void ED_lattice_editlatt_make(Object *obedit)
{
Lattice *lt = obedit->data;
KeyBlock *actkey;
- free_editLatt(obedit);
+ ED_lattice_editlatt_free(obedit);
actkey = BKE_keyblock_from_object(obedit);
if (actkey)
@@ -115,7 +115,7 @@ void make_editLatt(Object *obedit)
if (lt->key) lt->editlatt->shapenr = obedit->shapenr;
}
-void load_editLatt(Object *obedit)
+void ED_lattice_editlatt_load(Object *obedit)
{
Lattice *lt, *editlt;
KeyBlock *actkey;
@@ -192,9 +192,13 @@ static int lattice_select_random_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+
const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
+ RNG *rng = BLI_rng_new_srandom(seed);
+
int tot;
BPoint *bp;
@@ -202,7 +206,7 @@ static int lattice_select_random_exec(bContext *C, wmOperator *op)
bp = lt->def;
while (tot--) {
if (!bp->hide) {
- if (BLI_frand() < randfac) {
+ if (BLI_rng_get_float(rng) < randfac) {
bpoint_select_set(bp, select);
}
}
@@ -213,6 +217,8 @@ static int lattice_select_random_exec(bContext *C, wmOperator *op)
lt->actbp = LT_ACTBP_NONE;
}
+ BLI_rng_free(rng);
+
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
return OPERATOR_FINISHED;
@@ -233,30 +239,24 @@ void LATTICE_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f,
- "Percent", "Percentage of elements to select randomly", 0.f, 100.0f);
- WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+ WM_operator_properties_select_random(ot);
}
/* -------------------------------------------------------------------- */
/* Select Mirror Operator */
-static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
+static void ed_lattice_select_mirrored(Lattice *lt, const int axis, const bool extend)
{
- Object *obedit = CTX_data_edit_object(C);
- Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const int axis = RNA_enum_get(op->ptr, "axis");
- bool flip_uvw[3] = {false};
- int tot, i;
+ const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
+ int i;
BPoint *bp;
BLI_bitmap *selpoints;
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
-
+ bool flip_uvw[3] = {false};
flip_uvw[axis] = true;
+ /* we could flip this too */
if (!extend) {
lt->actbp = LT_ACTBP_NONE;
}
@@ -283,6 +283,20 @@ static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
MEM_freeN(selpoints);
+}
+
+static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+ const int axis_flag = RNA_enum_get(op->ptr, "axis");
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+
+ for (int axis = 0; axis < 3; axis++) {
+ if ((1 << axis) & axis_flag) {
+ ed_lattice_select_mirrored(lt, axis, extend);
+ }
+ }
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
@@ -304,7 +318,7 @@ void LATTICE_OT_select_mirror(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_enum(ot->srna, "axis", object_axis_unsigned_items, 0, "Axis", "");
+ RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
@@ -411,7 +425,7 @@ void LATTICE_OT_select_less(wmOperatorType *ot)
/************************** Select All Operator *************************/
-void ED_setflagsLatt(Object *obedit, int flag)
+void ED_lattice_flags_set(Object *obedit, int flag)
{
Lattice *lt = obedit->data;
BPoint *bp;
@@ -457,10 +471,10 @@ static int lattice_select_all_exec(bContext *C, wmOperator *op)
switch (action) {
case SEL_SELECT:
- ED_setflagsLatt(obedit, 1);
+ ED_lattice_flags_set(obedit, 1);
break;
case SEL_DESELECT:
- ED_setflagsLatt(obedit, 0);
+ ED_lattice_flags_set(obedit, 0);
break;
case SEL_INVERT:
bp = lt->editlatt->latt->def;
@@ -514,7 +528,7 @@ static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
}
if (!RNA_boolean_get(op->ptr, "extend")) {
- ED_setflagsLatt(obedit, 0);
+ ED_lattice_flags_set(obedit, 0);
}
dv = lt->dvert;
@@ -863,7 +877,7 @@ static BPoint *findnearestLattvert(ViewContext *vc, const int mval[2], int sel)
return data.bp;
}
-bool mouse_lattice(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_lattice_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
ViewContext vc;
BPoint *bp = NULL;
@@ -884,7 +898,7 @@ bool mouse_lattice(bContext *C, const int mval[2], bool extend, bool deselect, b
bp->f1 ^= SELECT; /* swap */
}
else {
- ED_setflagsLatt(vc.obedit, 0);
+ ED_lattice_flags_set(vc.obedit, 0);
bp->f1 |= SELECT;
}
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 8ef2bd1b2af..264945b00bf 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -324,6 +324,7 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md,
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
+ BKE_object_free_derived_caches(ob);
return 1;
}
@@ -709,6 +710,8 @@ int ED_object_modifier_apply(ReportList *reports, Scene *scene, Object *ob, Modi
BLI_remlink(&ob->modifiers, md);
modifier_free(md);
+ BKE_object_free_derived_caches(ob);
+
return 1;
}
@@ -749,10 +752,10 @@ static EnumPropertyItem *modifier_add_itemf(bContext *C, PointerRNA *UNUSED(ptr)
int totitem = 0, a;
if (!ob)
- return modifier_type_items;
+ return rna_enum_object_modifier_type_items;
- for (a = 0; modifier_type_items[a].identifier; a++) {
- md_item = &modifier_type_items[a];
+ for (a = 0; rna_enum_object_modifier_type_items[a].identifier; a++) {
+ md_item = &rna_enum_object_modifier_type_items[a];
if (md_item->identifier[0]) {
mti = modifierType_getInfo(md_item->value);
@@ -802,7 +805,7 @@ void OBJECT_OT_modifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_enum(ot->srna, "type", modifier_type_items, eModifierType_Subsurf, "Type", "");
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_object_modifier_type_items, eModifierType_Subsurf, "Type", "");
RNA_def_enum_funcs(prop, modifier_add_itemf);
ot->prop = prop;
}
@@ -1355,8 +1358,9 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
edit_modifier_properties(ot);
}
@@ -1456,7 +1460,7 @@ static int skin_edit_poll(bContext *C)
edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH)));
}
-static void skin_root_clear(BMesh *bm, BMVert *bm_vert, GSet *visited)
+static void skin_root_clear(BMVert *bm_vert, GSet *visited, const int cd_vert_skin_offset)
{
BMEdge *bm_edge;
BMIter bm_iter;
@@ -1464,16 +1468,13 @@ static void skin_root_clear(BMesh *bm, BMVert *bm_vert, GSet *visited)
BM_ITER_ELEM (bm_edge, &bm_iter, bm_vert, BM_EDGES_OF_VERT) {
BMVert *v2 = BM_edge_other_vert(bm_edge, bm_vert);
- if (!BLI_gset_haskey(visited, v2)) {
- MVertSkin *vs = CustomData_bmesh_get(&bm->vdata,
- v2->head.data,
- CD_MVERT_SKIN);
+ if (BLI_gset_add(visited, v2)) {
+ MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(v2, cd_vert_skin_offset);
/* clear vertex root flag and add to visited set */
vs->flag &= ~MVERT_SKIN_ROOT;
- BLI_gset_insert(visited, v2);
- skin_root_clear(bm, v2, visited);
+ skin_root_clear(v2, visited, cd_vert_skin_offset);
}
}
}
@@ -1483,6 +1484,7 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em->bm;
+ const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
BMVert *bm_vert;
BMIter bm_iter;
GSet *visited;
@@ -1492,19 +1494,16 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op))
BKE_mesh_ensure_skin_customdata(ob->data);
BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) {
- if (!BLI_gset_haskey(visited, bm_vert) &&
- BM_elem_flag_test(bm_vert, BM_ELEM_SELECT))
+ if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) &&
+ BLI_gset_add(visited, bm_vert))
{
- MVertSkin *vs = CustomData_bmesh_get(&bm->vdata,
- bm_vert->head.data,
- CD_MVERT_SKIN);
+ MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(bm_vert, cd_vert_skin_offset);
/* mark vertex as root and add to visited set */
vs->flag |= MVERT_SKIN_ROOT;
- BLI_gset_insert(visited, bm_vert);
/* clear root flag from all connected vertices (recursively) */
- skin_root_clear(bm, bm_vert, visited);
+ skin_root_clear(bm_vert, visited, cd_vert_skin_offset);
}
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 22cac8638d9..534e59384ce 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -100,6 +100,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_select_linked);
WM_operatortype_append(OBJECT_OT_select_grouped);
WM_operatortype_append(OBJECT_OT_select_mirror);
+ WM_operatortype_append(OBJECT_OT_select_more);
+ WM_operatortype_append(OBJECT_OT_select_less);
WM_operatortype_append(GROUP_OT_create);
WM_operatortype_append(GROUP_OT_objects_remove_all);
@@ -331,24 +333,27 @@ void ED_keymap_object(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
+ WM_keymap_add_item(keymap, "OBJECT_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "OBJECT_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0);
+
WM_keymap_add_item(keymap, "OBJECT_OT_select_linked", LKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "OBJECT_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "OBJECT_OT_select_mirror", MKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set_identifier(kmi->ptr, "direction", "PARENT");
+ RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "PARENT");
RNA_boolean_set(kmi->ptr, "extend", false);
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set_identifier(kmi->ptr, "direction", "PARENT");
+ RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "PARENT");
RNA_boolean_set(kmi->ptr, "extend", true);
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_enum_set_identifier(kmi->ptr, "direction", "CHILD");
+ RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "CHILD");
RNA_boolean_set(kmi->ptr, "extend", false);
kmi = WM_keymap_add_item(keymap, "OBJECT_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
- RNA_enum_set_identifier(kmi->ptr, "direction", "CHILD");
+ RNA_enum_set_identifier(NULL, kmi->ptr, "direction", "CHILD");
RNA_boolean_set(kmi->ptr, "extend", true);
WM_keymap_verify_item(keymap, "OBJECT_OT_parent_set", PKEY, KM_PRESS, KM_CTRL, 0);
@@ -464,6 +469,7 @@ void ED_keymap_proportional_cycle(struct wmKeyConfig *UNUSED(keyconf), struct wm
kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_enum", OKEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit_falloff");
+ RNA_boolean_set(kmi->ptr, "wrap", true);
}
void ED_keymap_proportional_obmode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap)
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index e21f58d8a38..84cf97ecb7c 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -138,6 +138,8 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
EDBM_mesh_load(obedit);
EDBM_mesh_make(scene->toolsettings, obedit);
+ DAG_id_tag_update(obedit->data, 0);
+
em = me->edit_btmesh;
EDBM_mesh_normals_update(em);
@@ -1336,7 +1338,7 @@ static int move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *even
{
View3D *v3d = CTX_wm_view3d(C);
if (v3d && v3d->localvd) {
- return WM_operator_confirm_message(C, op, "Move from localview");
+ return WM_operator_confirm_message(C, op, "Move out of Local View");
}
else {
move_to_layer_init(C, op);
@@ -1555,7 +1557,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
switch (type) {
case MAKE_LINKS_OBDATA: /* obdata */
- obdata_id->us--;
+ id_us_min(obdata_id);
obdata_id = ob_src->data;
id_us_plus(obdata_id);
@@ -1624,16 +1626,20 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
break;
}
- if (cu_dst->vfont) cu_dst->vfont->id.us--;
+ if (cu_dst->vfont)
+ id_us_min(&cu_dst->vfont->id);
cu_dst->vfont = cu_src->vfont;
id_us_plus((ID *)cu_dst->vfont);
- if (cu_dst->vfontb) cu_dst->vfontb->id.us--;
+ if (cu_dst->vfontb)
+ id_us_min(&cu_dst->vfontb->id);
cu_dst->vfontb = cu_src->vfontb;
id_us_plus((ID *)cu_dst->vfontb);
- if (cu_dst->vfonti) cu_dst->vfonti->id.us--;
+ if (cu_dst->vfonti)
+ id_us_min(&cu_dst->vfonti->id);
cu_dst->vfonti = cu_src->vfonti;
id_us_plus((ID *)cu_dst->vfonti);
- if (cu_dst->vfontbi) cu_dst->vfontbi->id.us--;
+ if (cu_dst->vfontbi)
+ id_us_min(&cu_dst->vfontbi->id);
cu_dst->vfontbi = cu_src->vfontbi;
id_us_plus((ID *)cu_dst->vfontbi);
@@ -1758,7 +1764,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
}
base->flag = obn->flag;
- ob->id.us--;
+ id_us_min(&ob->id);
}
}
}
@@ -1794,7 +1800,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in
/* object and group pointers */
for (base = FIRSTBASE; base; base = base->next) {
- BKE_object_relink(base->object);
+ BKE_libblock_relink(&base->object->id);
}
set_sca_new_poins();
@@ -1826,11 +1832,11 @@ static void new_id_matar(Material **matar, const int totcol)
if (id->newid) {
matar[a] = (Material *)id->newid;
id_us_plus(id->newid);
- id->us--;
+ id_us_min(id);
}
else if (id->us > 1) {
matar[a] = BKE_material_copy(matar[a]);
- id->us--;
+ id_us_min(id);
id->newid = (ID *)matar[a];
}
}
@@ -1912,7 +1918,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
*/
BKE_animdata_copy_id_action((ID *)ob->data);
- id->us--;
+ id_us_min(id);
id->newid = ob->data;
}
}
@@ -1953,7 +1959,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
- /* do not test for LIB_NEW: this functions guaranteed delivers single_users! */
+ /* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */
if (ma->id.us > 1) {
man = BKE_material_copy(ma);
@@ -1966,7 +1972,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture
for (b = 0; b < MAX_MTEX; b++) {
if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) {
if (tex->id.us > 1) {
- tex->id.us--;
+ id_us_min(&tex->id);
tex = BKE_texture_copy(tex);
BKE_animdata_copy_id_action(&tex->id);
man->mtex[b]->tex = tex;
@@ -1991,27 +1997,27 @@ static void do_single_tex_user(Tex **from)
if (tex->id.newid) {
*from = (Tex *)tex->id.newid;
id_us_plus(tex->id.newid);
- tex->id.us--;
+ id_us_min(&tex->id);
}
else if (tex->id.us > 1) {
texn = BKE_texture_copy(tex);
BKE_animdata_copy_id_action(&texn->id);
tex->id.newid = (ID *)texn;
- tex->id.us--;
+ id_us_min(&tex->id);
*from = texn;
}
}
static void single_tex_users_expand(Main *bmain)
{
- /* only when 'parent' blocks are LIB_NEW */
+ /* only when 'parent' blocks are LIB_TAG_NEW */
Material *ma;
Lamp *la;
World *wo;
int b;
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->id.flag & LIB_NEW) {
+ if (ma->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (ma->mtex[b] && ma->mtex[b]->tex) {
do_single_tex_user(&(ma->mtex[b]->tex));
@@ -2021,7 +2027,7 @@ static void single_tex_users_expand(Main *bmain)
}
for (la = bmain->lamp.first; la; la = la->id.next) {
- if (la->id.flag & LIB_NEW) {
+ if (la->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (la->mtex[b] && la->mtex[b]->tex) {
do_single_tex_user(&(la->mtex[b]->tex));
@@ -2031,7 +2037,7 @@ static void single_tex_users_expand(Main *bmain)
}
for (wo = bmain->world.first; wo; wo = wo->id.next) {
- if (wo->id.flag & LIB_NEW) {
+ if (wo->id.tag & LIB_TAG_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
if (wo->mtex[b] && wo->mtex[b]->tex) {
do_single_tex_user(&(wo->mtex[b]->tex));
@@ -2043,7 +2049,7 @@ static void single_tex_users_expand(Main *bmain)
static void single_mat_users_expand(Main *bmain)
{
- /* only when 'parent' blocks are LIB_NEW */
+ /* only when 'parent' blocks are LIB_TAG_NEW */
Object *ob;
Mesh *me;
Curve *cu;
@@ -2052,24 +2058,24 @@ static void single_mat_users_expand(Main *bmain)
int a;
for (ob = bmain->object.first; ob; ob = ob->id.next)
- if (ob->id.flag & LIB_NEW)
+ if (ob->id.tag & LIB_TAG_NEW)
new_id_matar(ob->mat, ob->totcol);
for (me = bmain->mesh.first; me; me = me->id.next)
- if (me->id.flag & LIB_NEW)
+ if (me->id.tag & LIB_TAG_NEW)
new_id_matar(me->mat, me->totcol);
for (cu = bmain->curve.first; cu; cu = cu->id.next)
- if (cu->id.flag & LIB_NEW)
+ if (cu->id.tag & LIB_TAG_NEW)
new_id_matar(cu->mat, cu->totcol);
for (mb = bmain->mball.first; mb; mb = mb->id.next)
- if (mb->id.flag & LIB_NEW)
+ if (mb->id.tag & LIB_TAG_NEW)
new_id_matar(mb->mat, mb->totcol);
/* material imats */
for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->id.flag & LIB_NEW)
+ if (ma->id.tag & LIB_TAG_NEW)
for (a = 0; a < MAX_MTEX; a++)
if (ma->mtex[a])
ID_NEW(ma->mtex[a]->object);
@@ -2117,34 +2123,35 @@ enum {
MAKE_LOCAL_ALL = 4,
};
-static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, const int UNUSED(cd_flag))
+static int tag_localizable_looper(
+ void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int UNUSED(cd_flag))
{
if (*id_pointer) {
- (*id_pointer)->flag &= ~LIB_DOIT;
+ (*id_pointer)->tag &= ~LIB_TAG_DOIT;
}
- return true;
+
+ return IDWALK_RET_NOP;
}
static void tag_localizable_objects(bContext *C, const int mode)
{
Main *bmain = CTX_data_main(C);
- Object *object;
- BKE_main_id_tag_all(bmain, false);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- /* Set LIB_DOIT flag for all selected objects, so next we can check whether
+ /* Set LIB_TAG_DOIT flag for all selected objects, so next we can check whether
* object is gonna to become local or not.
*/
CTX_DATA_BEGIN (C, Object *, object, selected_objects)
{
- object->id.flag |= LIB_DOIT;
+ object->id.tag |= LIB_TAG_DOIT;
/* If data is also gonna to become local, mark data we're interested in
* as gonna-to-be-local.
*/
if (mode == MAKE_LOCAL_SELECT_OBDATA && object->data) {
ID *data_id = (ID *) object->data;
- data_id->flag |= LIB_DOIT;
+ data_id->tag |= LIB_TAG_DOIT;
}
}
CTX_DATA_END;
@@ -2152,13 +2159,13 @@ static void tag_localizable_objects(bContext *C, const int mode)
/* Also forbid making objects local if other library objects are using
* them for modifiers or constraints.
*/
- for (object = bmain->object.first; object; object = object->id.next) {
- if ((object->id.flag & LIB_DOIT) == 0) {
+ for (Object *object = bmain->object.first; object; object = object->id.next) {
+ if ((object->id.tag & LIB_TAG_DOIT) == 0) {
BKE_library_foreach_ID_link(&object->id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
if (object->data) {
ID *data_id = (ID *) object->data;
- if ((data_id->flag & LIB_DOIT) == 0) {
+ if ((data_id->tag & LIB_TAG_DOIT) == 0) {
BKE_library_foreach_ID_link(data_id, tag_localizable_looper, NULL, IDWALK_READONLY);
}
}
@@ -2180,10 +2187,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
if (ob->id.lib && (ob->id.us == 0)) {
Base *base;
- ob->id.us = 1;
-
- /* not essential, but for correctness */
- id_lib_extern(&ob->id);
+ id_us_plus(&ob->id);
base = BKE_scene_base_add(scene, ob);
base->flag |= SELECT;
@@ -2218,7 +2222,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
"Orphan library objects added to the current scene to avoid loss");
}
- BKE_library_make_local(bmain, NULL, false); /* NULL is all libs */
+ BKE_library_make_local(bmain, NULL, false, false); /* NULL is all libs */
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
}
@@ -2228,7 +2232,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
- if ((ob->id.flag & LIB_DOIT) == 0) {
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
@@ -2248,7 +2252,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
- if ((ob->id.flag & LIB_DOIT) == 0) {
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
@@ -2281,7 +2285,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
if (mode == MAKE_LOCAL_SELECT_OBDATA_MATERIAL) {
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
- if ((ob->id.flag & LIB_DOIT) == 0) {
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 83334e4e6a3..0cbbe46f461 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -181,7 +181,7 @@ void OBJECT_OT_select_by_type(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
- ot->prop = RNA_def_enum(ot->srna, "type", object_type_items, 1, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 1, "Type", "");
}
/*********************** Selection by Links *********************/
@@ -854,47 +854,47 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case OBJECT_GRPSEL_CHILDREN_RECURSIVE:
- changed = select_grouped_children(C, ob, true);
+ changed |= select_grouped_children(C, ob, true);
break;
case OBJECT_GRPSEL_CHILDREN:
- changed = select_grouped_children(C, ob, false);
+ changed |= select_grouped_children(C, ob, false);
break;
case OBJECT_GRPSEL_PARENT:
- changed = select_grouped_parent(C);
+ changed |= select_grouped_parent(C);
break;
case OBJECT_GRPSEL_SIBLINGS:
- changed = select_grouped_siblings(C, ob);
+ changed |= select_grouped_siblings(C, ob);
break;
case OBJECT_GRPSEL_TYPE:
- changed = select_grouped_type(C, ob);
+ changed |= select_grouped_type(C, ob);
break;
case OBJECT_GRPSEL_LAYER:
- changed = select_grouped_layer(C, ob);
+ changed |= select_grouped_layer(C, ob);
break;
case OBJECT_GRPSEL_GROUP:
- changed = select_grouped_group(C, ob);
+ changed |= select_grouped_group(C, ob);
break;
case OBJECT_GRPSEL_HOOK:
- changed = select_grouped_object_hooks(C, ob);
+ changed |= select_grouped_object_hooks(C, ob);
break;
case OBJECT_GRPSEL_PASS:
- changed = select_grouped_index_object(C, ob);
+ changed |= select_grouped_index_object(C, ob);
break;
case OBJECT_GRPSEL_COLOR:
- changed = select_grouped_color(C, ob);
+ changed |= select_grouped_color(C, ob);
break;
case OBJECT_GRPSEL_PROPERTIES:
- changed = select_grouped_gameprops(C, ob);
+ changed |= select_grouped_gameprops(C, ob);
break;
case OBJECT_GRPSEL_KEYINGSET:
- changed = select_grouped_keyingset(C, ob, op->reports);
+ changed |= select_grouped_keyingset(C, ob, op->reports);
break;
case OBJECT_GRPSEL_LAMP_TYPE:
if (ob->type != OB_LAMP) {
BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp");
break;
}
- changed = select_grouped_lamptype(C, ob);
+ changed |= select_grouped_lamptype(C, ob);
break;
default:
break;
@@ -1175,23 +1175,143 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot)
}
+/** \name Select More/Less
+ * \{ */
+
+static bool object_select_more_less(bContext *C, const bool select)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ for (Base *base = scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+ ob->flag &= ~OB_DONE;
+ ob->id.tag &= ~LIB_TAG_DOIT;
+ /* parent may be in another scene */
+ if (ob->parent) {
+ ob->parent->flag &= ~OB_DONE;
+ ob->parent->id.tag &= ~LIB_TAG_DOIT;
+ }
+ }
+
+ ListBase ctx_base_list;
+ CollectionPointerLink *ctx_base;
+ CTX_data_selectable_bases(C, &ctx_base_list);
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
+ {
+ ob->flag |= OB_DONE;
+ }
+ CTX_DATA_END;
+
+
+
+ for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) {
+ Object *ob = ((Base *)ctx_base->ptr.data)->object;
+ if (ob->parent) {
+ if ((ob->flag & OB_DONE) != (ob->parent->flag & OB_DONE)) {
+ ob->id.tag |= LIB_TAG_DOIT;
+ ob->parent->id.tag |= LIB_TAG_DOIT;
+ }
+ }
+ }
+
+ bool changed = false;
+ const short select_mode = select ? BA_SELECT : BA_DESELECT;
+ const short select_flag = select ? SELECT : 0;
+
+ for (ctx_base = ctx_base_list.first; ctx_base; ctx_base = ctx_base->next) {
+ Base *base = ctx_base->ptr.data;
+ Object *ob = base->object;
+ if ((ob->id.tag & LIB_TAG_DOIT) && ((ob->flag & SELECT) != select_flag)) {
+ ED_base_object_select(base, select_mode);
+ changed = true;
+ }
+ }
+
+ BLI_freelistN(&ctx_base_list);
+
+ return changed;
+}
+
+static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bool changed = object_select_more_less(C, true);
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select More";
+ ot->idname = "OBJECT_OT_select_more";
+ ot->description = "Select connected parent/child objects";
+
+ /* api callbacks */
+ ot->exec = object_select_more_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bool changed = object_select_more_less(C, false);
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->idname = "OBJECT_OT_select_less";
+ ot->description = "Deselect objects at the boundaries of parent/child relationships";
+
+ /* api callbacks */
+ ot->exec = object_select_less_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+
/**************************** Select Random ****************************/
static int object_select_random_exec(bContext *C, wmOperator *op)
{
- float percent;
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- percent = RNA_float_get(op->ptr, "percent") / 100.0f;
-
+ RNG *rng = BLI_rng_new_srandom(seed);
+
CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
{
- if (BLI_frand() < percent) {
+ if (BLI_rng_get_float(rng) < randfac) {
ED_base_object_select(base, select);
}
}
CTX_DATA_END;
-
+
+ BLI_rng_free(rng);
+
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
return OPERATOR_FINISHED;
@@ -1213,6 +1333,5 @@ void OBJECT_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
- WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+ WM_operator_properties_select_random(ot);
}
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index ed71af71ac9..39bd34456be 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -131,10 +131,10 @@ static bool object_shape_key_mirror(bContext *C, Object *ob,
float *fp1, *fp2;
float tvec[3];
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, 's');
+ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) {
- i2 = mesh_get_x_mirror_vert(ob, i1, use_topology);
+ i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology);
if (i2 == i1) {
fp1 = ((float *)kb->data) + i1 * 3;
fp1[0] = -fp1[0];
@@ -162,7 +162,7 @@ static bool object_shape_key_mirror(bContext *C, Object *ob,
}
}
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 340b662c0ef..d2bbb73b597 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -382,7 +382,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
/* first check if we can execute */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) {
ID *obdata = ob->data;
if (ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports, RPT_ERROR,
@@ -418,6 +418,15 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
changed = false;
}
}
+
+ if (ob->type == OB_FONT) {
+ if (apply_rot || apply_loc) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Font's can only have scale applied: \"%s\"",
+ ob->id.name + 2);
+ changed = false;
+ }
+ }
}
CTX_DATA_END;
@@ -496,6 +505,22 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
scale = mat3_to_scale(rsmat);
BKE_curve_transform_ex(cu, mat, true, scale);
}
+ else if (ob->type == OB_FONT) {
+ Curve *cu = ob->data;
+ int i;
+
+ scale = mat3_to_scale(rsmat);
+
+ for (i = 0; i < cu->totbox; i++) {
+ TextBox *tb = &cu->tb[i];
+ tb->x *= scale;
+ tb->y *= scale;
+ tb->w *= scale;
+ tb->h *= scale;
+ }
+
+ cu->fsize *= scale;
+ }
else if (ob->type == OB_CAMERA) {
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
@@ -693,7 +718,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
mul_m4_v3(obedit->imat, cent);
}
else {
- if (around == V3D_CENTROID) {
+ if (around == V3D_AROUND_CENTER_MEAN) {
if (em->bm->totvert) {
const float total_div = 1.0f / (float)em->bm->totvert;
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
@@ -743,9 +768,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
for (tob = bmain->object.first; tob; tob = tob->id.next) {
if (tob->data)
- ((ID *)tob->data)->flag &= ~LIB_DOIT;
+ ((ID *)tob->data)->tag &= ~LIB_TAG_DOIT;
if (tob->dup_group)
- ((ID *)tob->dup_group)->flag &= ~LIB_DOIT;
+ ((ID *)tob->dup_group)->tag &= ~LIB_TAG_DOIT;
}
for (ctx_ob = ctx_data_list.first;
@@ -766,7 +791,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (ob->data == NULL) {
/* special support for dupligroups */
- if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.flag & LIB_DOIT) == 0) {
+ if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) {
if (ob->dup_group->id.lib) {
tot_lib_error++;
}
@@ -787,7 +812,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
add_v3_v3(ob->dup_group->dupli_ofs, cent);
tot_change++;
- ob->dup_group->id.flag |= LIB_DOIT;
+ ob->dup_group->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
}
@@ -800,23 +825,23 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
Mesh *me = ob->data;
if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
- else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); }
- else if (around == V3D_CENTROID) { BKE_mesh_center_median(me, cent); }
- else { BKE_mesh_center_bounds(me, cent); }
+ else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); }
+ else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mesh_center_median(me, cent); }
+ else { BKE_mesh_center_bounds(me, cent); }
negate_v3_v3(cent_neg, cent);
BKE_mesh_translate(me, cent_neg, 1);
tot_change++;
- me->id.flag |= LIB_DOIT;
+ me->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
- else if (around == V3D_CENTROID) { BKE_curve_center_median(cu, cent); }
- else { BKE_curve_center_bounds(cu, cent); }
+ if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
+ else if (around == V3D_AROUND_CENTER_MEAN) { BKE_curve_center_median(cu, cent); }
+ else { BKE_curve_center_bounds(cu, cent); }
/* don't allow Z change if curve is 2D */
if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D))
@@ -826,7 +851,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
BKE_curve_translate(cu, cent_neg, 1);
tot_change++;
- cu->id.flag |= LIB_DOIT;
+ cu->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
if (obedit) {
@@ -860,7 +885,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
cu->yof = cu->yof - (cent[1] / cu->fsize);
tot_change++;
- cu->id.flag |= LIB_DOIT;
+ cu->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
}
@@ -881,7 +906,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
ED_armature_origin_set(scene, ob, cursor, centermode, around);
tot_change++;
- arm->id.flag |= LIB_DOIT;
+ arm->id.tag |= LIB_TAG_DOIT;
/* do_inverse_offset = true; */ /* docenter_armature() handles this */
BKE_object_where_is_calc(scene, ob);
@@ -896,15 +921,15 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_MBALL) {
MetaBall *mb = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
- else if (around == V3D_CENTROID) { BKE_mball_center_median(mb, cent); }
- else { BKE_mball_center_bounds(mb, cent); }
+ if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
+ else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mball_center_median(mb, cent); }
+ else { BKE_mball_center_bounds(mb, cent); }
negate_v3_v3(cent_neg, cent);
BKE_mball_translate(mb, cent_neg);
tot_change++;
- mb->id.flag |= LIB_DOIT;
+ mb->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
if (obedit) {
@@ -917,15 +942,15 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
- if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
- else if (around == V3D_CENTROID) { BKE_lattice_center_median(lt, cent); }
- else { BKE_lattice_center_bounds(lt, cent); }
+ if (centermode == ORIGIN_TO_CURSOR) { /* done */ }
+ else if (around == V3D_AROUND_CENTER_MEAN) { BKE_lattice_center_median(lt, cent); }
+ else { BKE_lattice_center_bounds(lt, cent); }
negate_v3_v3(cent_neg, cent);
BKE_lattice_translate(lt, cent_neg, 1);
tot_change++;
- lt->id.flag |= LIB_DOIT;
+ lt->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
@@ -986,7 +1011,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
BLI_freelistN(&ctx_data_list);
for (tob = bmain->object.first; tob; tob = tob->id.next)
- if (tob->data && (((ID *)tob->data)->flag & LIB_DOIT))
+ if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT))
DAG_id_tag_update(&tob->id, OB_RECALC_OB | OB_RECALC_DATA);
if (tot_change) {
@@ -1019,8 +1044,8 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
};
static EnumPropertyItem prop_set_bounds_types[] = {
- {V3D_CENTROID, "MEDIAN", 0, "Median Center", ""},
- {V3D_CENTER, "BOUNDS", 0, "Bounds Center", ""},
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN", 0, "Median Center", ""},
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDS", 0, "Bounds Center", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1039,5 +1064,5 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
- RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_CENTROID, "Center", "");
+ RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_AROUND_CENTER_MEAN, "Center", "");
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 352c90e805a..4619f998a11 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -257,7 +257,6 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
BMEditMesh *em = BKE_editmesh_from_object(ob);
MDeformVert **dvert_array_all = NULL;
int dvert_tot_all;
- int i;
/* get an array of all verts, not only selected */
if (ED_vgroup_parray_alloc(ob->data, &dvert_array_all, &dvert_tot_all, false) == false) {
@@ -268,22 +267,26 @@ void ED_vgroup_parray_mirror_sync(Object *ob,
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
}
- for (i = 0; i < dvert_tot; i++) {
- if (dvert_array[i] == NULL) {
- /* its unselected, check if its mirror is */
- int i_sel = ED_mesh_mirror_get_vert(ob, i);
- if ((i_sel != -1) && (i_sel != i) && (dvert_array[i_sel])) {
+ int flip_map_len;
+ const int *flip_map = defgroup_flip_map(ob, &flip_map_len, true);
+
+ for (int i_src = 0; i_src < dvert_tot; i_src++) {
+ if (dvert_array[i_src] != NULL) {
+ /* its selected, check if its mirror exists */
+ int i_dst = ED_mesh_mirror_get_vert(ob, i_src);
+ if (i_dst != -1 && dvert_array_all[i_dst] != NULL) {
/* we found a match! */
- MDeformVert *dv_src = dvert_array[i_sel];
- MDeformVert *dv_dst = dvert_array_all[i];
+ const MDeformVert *dv_src = dvert_array[i_src];
+ MDeformVert *dv_dst = dvert_array_all[i_dst];
- defvert_copy_subset(dv_dst, dv_src, vgroup_validmap, vgroup_tot);
+ defvert_mirror_subset(dv_dst, dv_src, vgroup_validmap, vgroup_tot, flip_map, flip_map_len);
- dvert_array[i] = dvert_array_all[i];
+ dvert_array[i_dst] = dvert_array_all[i_dst];
}
}
}
+ MEM_freeN((void *)flip_map);
MEM_freeN(dvert_array_all);
}
@@ -517,7 +520,7 @@ static void ED_mesh_defvert_mirror_update_ob(Object *ob, int def_nr, int vidx)
if (vidx == -1)
return;
- vidx_mirr = mesh_get_x_mirror_vert(ob, vidx, use_topology);
+ vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology);
if ((vidx_mirr) >= 0 && (vidx_mirr != vidx)) {
MDeformVert *dvert_src = &me->dvert[vidx];
@@ -566,7 +569,7 @@ static void vgroup_remove_weight(Object *ob, const int def_nr)
}
-static void vgroup_normalize_active(Object *ob, eVGroupSelect subset_type)
+static bool vgroup_normalize_active_vertex(Object *ob, eVGroupSelect subset_type)
{
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
@@ -585,7 +588,7 @@ static void vgroup_normalize_active(Object *ob, eVGroupSelect subset_type)
}
if (dvert_act == NULL) {
- return;
+ return false;
}
vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
@@ -601,6 +604,8 @@ static void vgroup_normalize_active(Object *ob, eVGroupSelect subset_type)
ED_mesh_defvert_mirror_update_ob(ob, -1, v_act);
}
}
+
+ return true;
}
static void vgroup_copy_active_to_sel(Object *ob, eVGroupSelect subset_type)
@@ -1067,7 +1072,7 @@ static void vgroup_duplicate(Object *ob)
}
}
-static void vgroup_normalize(Object *ob)
+static bool vgroup_normalize(Object *ob)
{
MDeformWeight *dw;
MDeformVert *dv, **dvert_array = NULL;
@@ -1077,7 +1082,7 @@ static void vgroup_normalize(Object *ob)
const int use_vert_sel = vertex_group_use_vert_sel(ob);
if (!BLI_findlink(&ob->defbase, def_nr)) {
- return;
+ return false;
}
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
@@ -1117,7 +1122,11 @@ static void vgroup_normalize(Object *ob)
}
MEM_freeN(dvert_array);
+
+ return true;
}
+
+ return false;
}
/* This finds all of the vertices face-connected to vert by an edge and returns a
@@ -1521,11 +1530,13 @@ static void vgroup_levels_subset(Object *ob, const bool *vgroup_validmap, const
}
}
-static void vgroup_normalize_all(Object *ob,
- const bool *vgroup_validmap,
- const int vgroup_tot,
- const int subset_count,
- const bool lock_active)
+static bool vgroup_normalize_all(
+ Object *ob,
+ const bool *vgroup_validmap,
+ const int vgroup_tot,
+ const int subset_count,
+ const bool lock_active,
+ ReportList *reports)
{
MDeformVert *dv, **dvert_array = NULL;
int i, dvert_tot = 0;
@@ -1533,8 +1544,9 @@ static void vgroup_normalize_all(Object *ob,
const int use_vert_sel = vertex_group_use_vert_sel(ob);
- if ((lock_active && !BLI_findlink(&ob->defbase, def_nr)) || subset_count == 0) {
- return;
+ if (subset_count == 0) {
+ BKE_report(reports, RPT_ERROR, "No vertex groups to operate on");
+ return false;
}
ED_vgroup_parray_alloc(ob->data, &dvert_array, &dvert_tot, use_vert_sel);
@@ -1542,6 +1554,7 @@ static void vgroup_normalize_all(Object *ob,
if (dvert_array) {
const int defbase_tot = BLI_listbase_count(&ob->defbase);
bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, defbase_tot);
+ bool changed = false;
if ((lock_active == true) &&
(lock_flags != NULL) &&
@@ -1550,6 +1563,19 @@ static void vgroup_normalize_all(Object *ob,
lock_flags[def_nr] = true;
}
+ if (lock_flags) {
+ for (i = 0; i < defbase_tot; i++) {
+ if (lock_flags[i] == false) {
+ break;
+ }
+ }
+
+ if (i == defbase_tot) {
+ BKE_report(reports, RPT_ERROR, "All groups are locked");
+ goto finally;
+ }
+ }
+
for (i = 0; i < dvert_tot; i++) {
/* in case its not selected */
if ((dv = dvert_array[i])) {
@@ -1567,12 +1593,19 @@ static void vgroup_normalize_all(Object *ob,
}
}
+ changed = true;
+
+finally:
if (lock_flags) {
MEM_freeN(lock_flags);
}
MEM_freeN(dvert_array);
+
+ return changed;
}
+
+ return false;
}
enum {
@@ -1688,7 +1721,7 @@ static void vgroup_smooth_subset(
{
const float ifac = 1.0f - fac;
MDeformVert **dvert_array = NULL;
- int i, dvert_tot = 0;
+ int dvert_tot = 0;
int *vgroup_subset_map = BLI_array_alloca(vgroup_subset_map, subset_count);
float *vgroup_subset_weights = BLI_array_alloca(vgroup_subset_weights, subset_count);
const bool use_mirror = (ob->type == OB_MESH) ? (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X) != 0 : false;
@@ -1738,7 +1771,7 @@ static void vgroup_smooth_subset(
/* initialize used verts */
if (bm) {
- for (i = 0; i < dvert_tot; i++) {
+ for (int i = 0; i < dvert_tot; i++) {
BMVert *v = BM_vert_at_index(bm, i);
if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
BMIter eiter;
@@ -1756,14 +1789,11 @@ static void vgroup_smooth_subset(
}
}
else {
- for (i = 0; i < dvert_tot; i++) {
+ for (int i = 0; i < dvert_tot; i++) {
MVert *v = &me->mvert[i];
if (v->flag & SELECT) {
- int j;
- for (j = 0; j < emap[i].count; j++) {
- MEdge *e = &me->medge[emap[i].indices[j]];
- const int i_other = (e->v1 == i ? e->v2 : e->v1);
- MVert *v_other = &me->mvert[i_other];
+ for (int j = 0; j < emap[i].count; j++) {
+ MVert *v_other = &me->mvert[emap[i].indices[j]];
if ((source == WEIGHT_SMOOTH_ALL) ||
(source == ((v_other->flag & SELECT) != 0)))
{
@@ -1798,13 +1828,13 @@ static void vgroup_smooth_subset(
float tot_factor = 1.0f; \
if (expand_sign == 1) { /* expand */ \
if (weight_other < weight_accum_prev[i]) { \
- weight_other = (weight_accum_prev[i_other] * iexpand) + (weight_other * expand); \
+ weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
tot_factor = iexpand; \
} \
} \
else if (expand_sign == -1) { /* contract */ \
if (weight_other > weight_accum_prev[i]) { \
- weight_other = (weight_accum_prev[i_other] * iexpand) + (weight_other * expand); \
+ weight_other = (weight_accum_prev[i] * expand) + (weight_other * iexpand); \
tot_factor = iexpand; \
} \
} \
@@ -2093,7 +2123,7 @@ static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
defvert_copy(dvert, dvert_mirr);
}
else {
- defvert_copy_index(dvert, dvert_mirr, act_vgroup);
+ defvert_copy_index(dvert, act_vgroup, dvert_mirr, act_vgroup);
}
}
@@ -2214,7 +2244,7 @@ void ED_vgroup_mirror(Object *ob,
for (vidx = 0, mv = me->mvert; vidx < me->totvert; vidx++, mv++) {
if ((mv->flag & ME_VERT_TMP_TAG) == 0) {
- if ((vidx_mirr = mesh_get_x_mirror_vert(ob, vidx, use_topology)) != -1) {
+ if ((vidx_mirr = mesh_get_x_mirror_vert(ob, NULL, vidx, use_topology)) != -1) {
if (vidx != vidx_mirr) {
mv_mirr = &me->mvert[vidx_mirr];
if ((mv_mirr->flag & ME_VERT_TMP_TAG) == 0) {
@@ -2826,14 +2856,20 @@ void OBJECT_OT_vertex_group_levels(wmOperatorType *ot)
static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_object_context(C);
+ bool changed;
- vgroup_normalize(ob);
+ changed = vgroup_normalize(ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ if (changed) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot)
@@ -2856,18 +2892,24 @@ static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_context(C);
bool lock_active = RNA_boolean_get(op->ptr, "lock_active");
eVGroupSelect subset_type = RNA_enum_get(op->ptr, "group_select_mode");
-
+ bool changed;
int subset_count, vgroup_tot;
-
const bool *vgroup_validmap = BKE_object_defgroup_subset_from_select_type(ob, subset_type, &vgroup_tot, &subset_count);
- vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, subset_count, lock_active);
+
+ changed = vgroup_normalize_all(ob, vgroup_validmap, vgroup_tot, subset_count, lock_active, op->reports);
MEM_freeN((void *)vgroup_validmap);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ if (changed) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
+ }
+ else {
+ /* allow to adjust settings */
+ return OPERATOR_FINISHED;
+ }
}
void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
@@ -3285,8 +3327,14 @@ static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
if (obact != ob) {
- if (ED_vgroup_array_copy(ob, obact)) changed_tot++;
- else fail++;
+ if (ED_vgroup_array_copy(ob, obact)) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
+ changed_tot++;
+ }
+ else {
+ fail++;
+ }
}
}
CTX_DATA_END;
@@ -3825,13 +3873,19 @@ static int vertex_weight_normalize_active_vertex_exec(bContext *C, wmOperator *U
Object *ob = ED_object_context(C);
ToolSettings *ts = CTX_data_tool_settings(C);
eVGroupSelect subset_type = ts->vgroupsubset;
+ bool changed;
- vgroup_normalize_active(ob, subset_type);
+ changed = vgroup_normalize_active_vertex(ob, subset_type);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ if (changed) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void OBJECT_OT_vertex_weight_normalize_active_vertex(wmOperatorType *ot)
diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript
deleted file mode 100644
index be399a58732..00000000000
--- a/source/blender/editors/physics/SConscript
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/rigidbody',
- '#/intern/elbeem/extern',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_physics', sources, Split(incs), defs, libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 93daa15e608..7cc17e4bfea 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -26,6 +26,8 @@
#include <stdio.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_blenlib.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -44,8 +46,10 @@
#include "BKE_depsgraph.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_report.h"
+#include "BKE_screen.h"
#include "ED_mesh.h"
#include "ED_screen.h"
@@ -202,7 +206,7 @@ void DPAINT_OT_type_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_enum(ot->srna, "type", prop_dynamicpaint_type_items, MOD_DYNAMICPAINT_TYPE_CANVAS, "Type", "");
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_prop_dynamicpaint_type_items, MOD_DYNAMICPAINT_TYPE_CANVAS, "Type", "");
ot->prop = prop;
}
@@ -275,49 +279,112 @@ void DPAINT_OT_output_toggle(wmOperatorType *ot)
/***************************** Image Sequence Baking ******************************/
+typedef struct DynamicPaintBakeJob {
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+
+ struct Main *bmain;
+ Scene *scene;
+ Object *ob;
+
+ DynamicPaintSurface *surface;
+ DynamicPaintCanvasSettings *canvas;
+
+ int success;
+ double start;
+} DynamicPaintBakeJob;
+
+static void dpaint_bake_free(void *customdata)
+{
+ DynamicPaintBakeJob *job = customdata;
+ MEM_freeN(job);
+}
+
+static void dpaint_bake_endjob(void *customdata)
+{
+ DynamicPaintBakeJob *job = customdata;
+ DynamicPaintCanvasSettings *canvas = job->canvas;
+
+ canvas->flags &= ~MOD_DPAINT_BAKING;
+
+ dynamicPaint_freeSurfaceData(job->surface);
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+
+ WM_set_locked_interface(G.main->wm.first, false);
+
+ /* Bake was successful:
+ * Report for ended bake and how long it took */
+ if (job->success) {
+ /* Show bake info */
+ WM_reportf(RPT_INFO, "DynamicPaint: Bake complete! (%.2f)", PIL_check_seconds_timer() - job->start);
+ }
+ else {
+ if (strlen(canvas->error)) { /* If an error occurred */
+ WM_reportf(RPT_ERROR, "DynamicPaint: Bake failed: %s", canvas->error);
+ }
+ else { /* User canceled the bake */
+ WM_report(RPT_WARNING, "Baking canceled!");
+ }
+ }
+}
+
/*
* Do actual bake operation. Loop through to-be-baked frames.
* Returns 0 on failure.
*/
-static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surface, Object *cObject)
+static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
{
+ DynamicPaintSurface *surface = job->surface;
+ Object *cObject = job->ob;
DynamicPaintCanvasSettings *canvas = surface->canvas;
- Scene *scene = CTX_data_scene(C);
- wmWindow *win = CTX_wm_window(C);
- int frame = 1;
+ Scene *scene = job->scene;
+ int frame = 1, orig_frame;
int frames;
frames = surface->end_frame - surface->start_frame + 1;
if (frames <= 0) {
BLI_strncpy(canvas->error, N_("No frames to bake"), sizeof(canvas->error));
- return 0;
+ return;
}
/* Set frame to start point (also inits modifier data) */
frame = surface->start_frame;
+ orig_frame = scene->r.cfra;
scene->r.cfra = (int)frame;
- ED_update_for_newframe(CTX_data_main(C), scene, 1);
+ ED_update_for_newframe(job->bmain, scene, 1);
/* Init surface */
- if (!dynamicPaint_createUVSurface(scene, surface)) return 0;
+ if (!dynamicPaint_createUVSurface(scene, surface)) {
+ job->success = 0;
+ return;
+ }
/* Loop through selected frames */
for (frame = surface->start_frame; frame <= surface->end_frame; frame++) {
- float progress = (frame - surface->start_frame) / (float)frames * 100;
+ float progress = (frame - surface->start_frame) / (float)frames;
surface->current_frame = frame;
- /* If user requested stop (esc), quit baking */
- if (blender_test_break()) return 0;
-
- /* Update progress bar cursor */
- if (!G.background) {
- WM_cursor_time(win, (int)progress);
+ /* If user requested stop, quit baking */
+ if (G.is_break) {
+ job->success = 0;
+ return;
}
+ /* Update progress bar */
+ *(job->do_update) = true;
+ *(job->progress) = progress;
+
/* calculate a frame */
scene->r.cfra = (int)frame;
- ED_update_for_newframe(CTX_data_main(C), scene, 1);
- if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) return 0;
+ ED_update_for_newframe(job->bmain, scene, 1);
+ if (!dynamicPaint_calculateFrame(surface, scene, cObject, frame)) {
+ job->success = 0;
+ return;
+ }
/*
* Save output images
@@ -345,21 +412,44 @@ static int dynamicPaint_bakeImageSequence(bContext *C, DynamicPaintSurface *surf
}
}
}
- return 1;
+
+ scene->r.cfra = orig_frame;
}
+static void dpaint_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
+{
+ DynamicPaintBakeJob *job = customdata;
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
+
+ G.is_break = false; /* reset blender_test_break*/
+
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ dynamicPaint_bakeImageSequence(job);
+
+ *do_update = true;
+ *stop = 0;
+}
/*
* Bake Dynamic Paint image sequence surface
*/
-static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
+static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
{
- wmWindow *win = CTX_wm_window(C);
DynamicPaintModifierData *pmd = NULL;
DynamicPaintCanvasSettings *canvas;
Object *ob = ED_object_context(C);
- int status = 0;
- double timer = PIL_check_seconds_timer();
+ Scene *scene = CTX_data_scene(C);
+
DynamicPaintSurface *surface;
/*
@@ -368,54 +458,40 @@ static int dynamicPaint_initBake(struct bContext *C, struct wmOperator *op)
pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint);
if (!pmd) {
BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
- return 0;
+ return OPERATOR_CANCELLED;
}
/* Make sure we're dealing with a canvas */
canvas = pmd->canvas;
if (!canvas) {
BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas");
- return 0;
+ return OPERATOR_CANCELLED;
}
surface = get_activeSurface(canvas);
/* Set state to baking and init surface */
canvas->error[0] = '\0';
canvas->flags |= MOD_DPAINT_BAKING;
- G.is_break = false; /* reset blender_test_break*/
- /* Bake Dynamic Paint */
- status = dynamicPaint_bakeImageSequence(C, surface, ob);
- /* Clear bake */
- canvas->flags &= ~MOD_DPAINT_BAKING;
- if (!G.background) {
- WM_cursor_modal_restore(win);
- }
- dynamicPaint_freeSurfaceData(surface);
+ DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob");
+ job->bmain = CTX_data_main(C);
+ job->scene = scene;
+ job->ob = ob;
+ job->canvas = canvas;
+ job->surface = surface;
- /* Bake was successful:
- * Report for ended bake and how long it took */
- if (status) {
- /* Show bake info */
- BKE_reportf(op->reports, RPT_INFO, "Bake complete! (%.2f)", PIL_check_seconds_timer() - timer);
- }
- else {
- if (strlen(canvas->error)) { /* If an error occurred */
- BKE_reportf(op->reports, RPT_ERROR, "Bake failed: %s", canvas->error);
- }
- else { /* User canceled the bake */
- BKE_report(op->reports, RPT_WARNING, "Baking canceled!");
- }
- }
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene,
+ "Dynamic Paint Bake", WM_JOB_PROGRESS,
+ WM_JOB_TYPE_DPAINT_BAKE);
- return status;
-}
+ WM_jobs_customdata_set(wm_job, job, dpaint_bake_free);
+ WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, dpaint_bake_startjob, NULL, NULL, dpaint_bake_endjob);
-static int dynamicpaint_bake_exec(bContext *C, wmOperator *op)
-{
- /* Bake dynamic paint */
- if (!dynamicPaint_initBake(C, op)) {
- return OPERATOR_CANCELLED;}
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ /* Bake Dynamic Paint */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/physics/particle_boids.c b/source/blender/editors/physics/particle_boids.c
index ef1e661c580..14b12497c4a 100644
--- a/source/blender/editors/physics/particle_boids.c
+++ b/source/blender/editors/physics/particle_boids.c
@@ -94,7 +94,7 @@ void BOID_OT_rule_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
- ot->prop = RNA_def_enum(ot->srna, "type", boidrule_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_boidrule_type_items, 0, "Type", "");
}
static int rule_del_exec(bContext *C, wmOperator *UNUSED(op))
{
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 892545a8efd..29824a348f5 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -659,7 +659,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
if (selected==0 || key->flag & PEK_SELECT) {
if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
invert_m4_m4(imat, mat);
}
@@ -674,7 +674,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
if (selected==0 || key->flag & PEK_SELECT) {
if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
invert_m4_m4(imat, mat);
}
@@ -761,7 +761,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
psmd= psys_get_modifier(ob, psys);
totpart= psys->totpart;
- if (!psmd->dm)
+ if (!psmd->dm_final)
return;
tree= BLI_kdtree_new(totpart);
@@ -769,7 +769,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
/* insert particles into kd tree */
LOOP_PARTICLES {
key = pa->hair;
- psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
+ psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
BLI_kdtree_insert(tree, p, co);
@@ -783,7 +783,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
LOOP_PARTICLES {
key = pa->hair;
- psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
+ psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
co[0] = -co[0];
@@ -898,7 +898,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
edit= psys->edit;
psmd= psys_get_modifier(ob, psys);
- if (!psmd->dm)
+ if (!psmd->dm_final)
return;
if (!edit->mirror_cache)
@@ -911,7 +911,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
* to avoid doing mirror twice */
LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
- PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
+ PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
if (edit->mirror_cache[p] != -1)
edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
@@ -946,11 +946,11 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
psys = edit->psys;
psmd = psys_get_modifier(ob, psys);
- if (!psmd->dm)
+ if (!psmd->dm_final)
return;
LOOP_EDITED_POINTS {
- psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat);
+ psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat);
LOOP_KEYS {
mul_m4_v3(hairmat, key->co);
@@ -1095,7 +1095,7 @@ void recalc_lengths(PTCacheEdit *edit)
/* calculate a tree for finding nearest emitter's vertice */
void recalc_emitter_field(Object *ob, ParticleSystem *psys)
{
- DerivedMesh *dm=psys_get_modifier(ob, psys)->dm;
+ DerivedMesh *dm=psys_get_modifier(ob, psys)->dm_final;
PTCacheEdit *edit= psys->edit;
float *vec, *nor;
int i, totface /*, totvert*/;
@@ -1188,12 +1188,12 @@ void update_world_cos(Object *ob, PTCacheEdit *edit)
POINT_P; KEY_K;
float hairmat[4][4];
- if (psys==0 || psys->edit==0 || psmd->dm==NULL)
+ if (psys==0 || psys->edit==0 || psmd->dm_final==NULL)
return;
LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, hairmat);
LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
@@ -1634,7 +1634,10 @@ static int select_random_exec(bContext *C, wmOperator *op)
int p;
int k;
- const float randf = RNA_float_get (op->ptr, "percent") / 100.0f;
+ const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
+ const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
+ RNG *rng;
type = RNA_enum_get(op->ptr, "type");
@@ -1644,10 +1647,12 @@ static int select_random_exec(bContext *C, wmOperator *op)
ob = CTX_data_active_object(C);
edit = PE_get_current(scene, ob);
+ rng = BLI_rng_new_srandom(seed);
+
switch (type) {
case RAN_HAIR:
LOOP_VISIBLE_POINTS {
- int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT;
+ int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
LOOP_KEYS {
select_action_apply (point, key, flag);
}
@@ -1656,13 +1661,15 @@ static int select_random_exec(bContext *C, wmOperator *op)
case RAN_POINTS:
LOOP_VISIBLE_POINTS {
LOOP_VISIBLE_KEYS {
- int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT;
+ int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
select_action_apply (point, key, flag);
}
}
break;
}
+ BLI_rng_free(rng);
+
PE_update_selection(data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
@@ -1684,9 +1691,7 @@ void PARTICLE_OT_select_random(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
- RNA_def_float_percentage (ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent",
- "Percentage (mean) of elements in randomly selected set",
- 0.0f, 100.0f);
+ WM_operator_properties_select_random(ot);
ot->prop = RNA_def_enum (ot->srna, "type", select_random_type_items, RAN_HAIR,
"Type", "Select either hair or points");
}
@@ -1834,7 +1839,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool
LOOP_VISIBLE_POINTS {
if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
if (pset->selectmode==SCE_SELECT_POINT) {
LOOP_KEYS {
@@ -2268,7 +2273,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
psmd= psys_get_modifier(ob, psys);
LOOP_TAGGED_POINTS {
- PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
+ PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
}
}
@@ -2348,7 +2353,7 @@ static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
LOOP_POINTS {
LOOP_TAGGED_KEYS {
- PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
+ PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
break;
}
}
@@ -2562,7 +2567,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
/* insert particles into kd tree */
LOOP_SELECTED_POINTS {
- psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
+ psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
copy_v3_v3(co, point->keys->co);
mul_m4_v3(mat, co);
BLI_kdtree_insert(tree, p, co);
@@ -2572,7 +2577,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
/* tag particles to be removed */
LOOP_SELECTED_POINTS {
- psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
+ psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
copy_v3_v3(co, point->keys->co);
mul_m4_v3(mat, co);
@@ -2803,13 +2808,17 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
return;
psmd= psys_get_modifier(ob, psys);
- if (!psmd->dm)
+ if (!psmd->dm_final)
return;
+ const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly);
+
/* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
BKE_mesh_tessface_ensure(me);
- mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
+ /* Note: In case psys uses DM tessface indices, we mirror final DM itself, not orig mesh. Avoids an (impossible)
+ * dm -> orig -> dm tessface indices conversion... */
+ mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd->dm_final : NULL);
if (!edit->mirror_cache)
PE_update_mirror_cache(ob, psys);
@@ -2818,11 +2827,12 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
newtotpart= psys->totpart;
LOOP_VISIBLE_POINTS {
pa = psys->particles + p;
+
if (!tagged) {
if (point_is_selected(point)) {
if (edit->mirror_cache[p] != -1) {
/* already has a mirror, don't need to duplicate */
- PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
+ PE_mirror_particle(ob, psmd->dm_final, psys, pa, NULL);
continue;
}
else
@@ -2835,6 +2845,8 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
}
if (newtotpart != psys->totpart) {
+ MFace *mtessface = use_dm_final_indices ? psmd->dm_final->getTessFaceArray(psmd->dm_final) : me->mface;
+
/* allocate new arrays and copy existing */
new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
@@ -2864,10 +2876,12 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
for (p=0, point=edit->points; p<totpart; p++, point++) {
pa = psys->particles + p;
+ const int pa_num = pa->num;
if (point->flag & PEP_HIDE)
continue;
- if (!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1)
+
+ if (!(point->flag & PEP_TAG) || mirrorfaces[pa_num * 2] == -1)
continue;
/* duplicate */
@@ -2877,27 +2891,31 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
if (point->keys) newpoint->keys= MEM_dupallocN(point->keys);
/* rotate weights according to vertex index rotation */
- rotation= mirrorfaces[pa->num*2+1];
+ rotation= mirrorfaces[pa_num * 2 + 1];
newpa->fuv[0] = pa->fuv[2];
newpa->fuv[1] = pa->fuv[1];
newpa->fuv[2] = pa->fuv[0];
newpa->fuv[3] = pa->fuv[3];
- while (rotation-- > 0)
- if (me->mface[pa->num].v4) {
+ while (rotation--) {
+ if (mtessface[pa_num].v4) {
SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]);
}
else {
SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]);
}
+ }
- /* assign face inddex */
- newpa->num= mirrorfaces[pa->num*2];
- newpa->num_dmcache= psys_particle_dm_face_lookup(ob, psmd->dm, newpa->num, newpa->fuv, NULL);
+ /* assign face index */
+ /* NOTE: mesh_get_x_mirror_faces generates -1 for non-found mirror, same as DMCACHE_NOTFOUND... */
+ newpa->num = mirrorfaces[pa_num * 2];
- if ((newpa->num_dmcache != DMCACHE_NOTFOUND) && psys->part->use_modifier_stack && !psmd->dm->deformedOnly) {
- newpa->num = newpa->num_dmcache;
+ if (use_dm_final_indices) {
newpa->num_dmcache = DMCACHE_ISCHILD;
}
+ else {
+ newpa->num_dmcache = psys_particle_dm_face_lookup(
+ psmd->dm_final, psmd->dm_deformed, newpa->num, newpa->fuv, NULL);
+ }
/* update edit key pointers */
key= newpoint->keys;
@@ -2907,7 +2925,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
}
/* map key positions as mirror over x axis */
- PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
+ PE_mirror_particle(ob, psmd->dm_final, psys, pa, newpa);
newpa++;
newpoint++;
@@ -3355,7 +3373,7 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
totface=dm->getNumTessFaces(dm);
mface=dm->getTessFaceDataArray(dm, CD_MFACE);
mvert=dm->getVertDataArray(dm, CD_MVERT);
-
+
/* lets intersect the faces */
for (i=0; i<totface; i++, mface++) {
if (vert_cos) {
@@ -3411,7 +3429,7 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
}
}
else {
- if (isect_line_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)) {
+ if (isect_line_segment_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)) {
if (cur_d<*min_d) {
*min_d=cur_d;
min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
@@ -3425,7 +3443,7 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
}
}
if (mface->v4) {
- if (isect_line_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)) {
+ if (isect_line_segment_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)) {
if (cur_d<*min_d) {
*min_d=cur_d;
min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
@@ -3447,6 +3465,7 @@ static int brush_add(PEData *data, short number)
{
Scene *scene= data->scene;
Object *ob= data->ob;
+ DerivedMesh *dm;
PTCacheEdit *edit = data->edit;
ParticleSystem *psys= edit->psys;
ParticleData *add_pars;
@@ -3460,11 +3479,7 @@ static int brush_add(PEData *data, short number)
float framestep, timestep;
short size= pset->brush[PE_BRUSH_ADD].size;
short size2= size*size;
- DerivedMesh *dm=0;
RNG *rng;
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
- bool release_dm = false;
invert_m4_m4(imat, ob->obmat);
@@ -3482,15 +3497,13 @@ static int brush_add(PEData *data, short number)
timestep= psys_get_timestep(&sim);
- if (psmd->dm->deformedOnly || psys->part->use_modifier_stack)
- dm = psmd->dm;
+ if (psys->part->use_modifier_stack || psmd->dm_final->deformedOnly) {
+ dm = psmd->dm_final;
+ }
else {
- dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
- release_dm = true;
+ dm = psmd->dm_deformed;
}
-
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ BLI_assert(dm);
for (i=0; i<number; i++) {
if (number>1) {
@@ -3518,16 +3531,22 @@ static int brush_add(PEData *data, short number)
/* warning, returns the derived mesh face */
if (particle_intersect_dm(scene, ob, dm, 0, co1, co2, &min_d, &add_pars[n].num_dmcache, add_pars[n].fuv, 0, 0, 0, 0)) {
- if (index_mf_to_mpoly && index_mp_to_orig)
- add_pars[n].num = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, add_pars[n].num_dmcache);
- else
+ if (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly) {
+ add_pars[n].num = add_pars[n].num_dmcache;
+ add_pars[n].num_dmcache = DMCACHE_ISCHILD;
+ }
+ else if (dm == psmd->dm_deformed) {
+ /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */
add_pars[n].num = add_pars[n].num_dmcache;
+ add_pars[n].num_dmcache = psys_particle_dm_face_lookup(
+ psmd->dm_final, psmd->dm_deformed,
+ add_pars[n].num, add_pars[n].fuv, NULL);
+ }
+ else {
+ add_pars[n].num = add_pars[n].num_dmcache;
+ }
- if (psys_particle_dm_face_lookup(ob, psmd->dm, add_pars[n].num_dmcache, add_pars[n].fuv, NULL) != DMCACHE_NOTFOUND) {
- if (psys->part->use_modifier_stack && !psmd->dm->deformedOnly) {
- add_pars[n].num = add_pars[n].num_dmcache;
- add_pars[n].num_dmcache = DMCACHE_ISCHILD;
- }
+ if (add_pars[n].num != DMCACHE_NOTFOUND) {
n++;
}
}
@@ -3562,7 +3581,7 @@ static int brush_add(PEData *data, short number)
tree=BLI_kdtree_new(psys->totpart);
for (i=0, pa=psys->particles; i<totpart; i++, pa++) {
- psys_particle_on_dm(psmd->dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0, 0);
+ psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0, 0);
BLI_kdtree_insert(tree, i, cur_co);
}
@@ -3606,7 +3625,7 @@ static int brush_add(PEData *data, short number)
int w, maxw;
float maxd, totw=0.0, weight[3];
- psys_particle_on_dm(psmd->dm, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0, 0);
+ psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0, 0);
maxw = BLI_kdtree_find_nearest_n(tree, co1, ptn, 3);
maxd= ptn[maxw-1].dist;
@@ -3671,7 +3690,7 @@ static int brush_add(PEData *data, short number)
}
}
for (k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
mul_m4_v3(imat, hkey->co);
}
@@ -3683,9 +3702,6 @@ static int brush_add(PEData *data, short number)
MEM_freeN(add_pars);
- if (release_dm)
- dm->release(dm);
-
BLI_rng_free(rng);
return n;
@@ -3861,7 +3877,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
case PE_BRUSH_PUFF:
{
if (edit->psys) {
- data.dm= psmd->dm;
+ data.dm= psmd->dm_final;
data.mval= mval;
data.rad= pe_brush_size_get(scene, brush);
data.select= selected;
@@ -3917,7 +3933,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
case PE_BRUSH_WEIGHT:
{
if (edit->psys) {
- data.dm= psmd->dm;
+ data.dm= psmd->dm_final;
data.mval= mval;
data.rad= pe_brush_size_get(scene, brush);
@@ -4540,7 +4556,7 @@ int PE_minmax(Scene *scene, float min[3], float max[3])
LOOP_VISIBLE_POINTS {
if (psys)
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
LOOP_SELECTED_KEYS {
copy_v3_v3(co, key->co);
@@ -4571,7 +4587,7 @@ void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, Partic
int totpoint;
/* no psmd->dm happens in case particle system modifier is not enabled */
- if (!(psys && psmd && psmd->dm) && !cache)
+ if (!(psys && psmd && psmd->dm_final) && !cache)
return;
if (cache && cache->flag & PTCACHE_DISK_CACHE)
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 327ce060df9..1297133e1a2 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -202,7 +202,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op))
ob= ptr.id.data;
if (psys->part)
- psys->part->id.us--;
+ id_us_min(&psys->part->id);
psys->part = part;
@@ -592,7 +592,7 @@ static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
point++;
}
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
for (k=0, key=pa->hair; k<pa->totkey; k++, key++) {
mul_m4_v3(hairmat, key->co);
@@ -618,7 +618,6 @@ static int disconnect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *ob= ED_object_context(C);
- PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= NULL;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -631,7 +630,7 @@ static int disconnect_hair_exec(bContext *C, wmOperator *op)
}
}
else {
- psys = ptr.data;
+ psys = psys_get_current(ob);
disconnect_hair(scene, ob, psys);
}
@@ -650,7 +649,7 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
ot->exec = disconnect_hair_exec;
/* flags */
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO; /* No REGISTER, redo does not work due to missing update, see T47750. */
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
}
@@ -676,7 +675,7 @@ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
float from_ob_imat[4][4], to_ob_imat[4][4];
float from_imat[4][4], to_imat[4][4];
- if (!target_psmd->dm)
+ if (!target_psmd->dm_final)
return false;
if (!psys->part || psys->part->type != PART_HAIR)
return false;
@@ -690,15 +689,14 @@ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
invert_m4_m4(from_imat, from_mat);
invert_m4_m4(to_imat, to_mat);
- if (target_psmd->dm->deformedOnly) {
+ if (target_psmd->dm_final->deformedOnly) {
/* we don't want to mess up target_psmd->dm when converting to global coordinates below */
- dm = target_psmd->dm;
+ dm = target_psmd->dm_final;
}
else {
- /* warning: this rebuilds target_psmd->dm! */
- dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
+ dm = target_psmd->dm_deformed;
}
- target_dm = target_psmd->dm;
+ target_dm = target_psmd->dm_final;
/* don't modify the original vertices */
dm = CDDM_copy(dm);
@@ -766,7 +764,7 @@ static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
tpa->foffset = 0.0f;
tpa->num = nearest.index;
- tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL);
+ tpa->num_dmcache = psys_particle_dm_face_lookup(target_dm, dm, tpa->num, tpa->fuv, NULL);
}
else {
me = &medge[nearest.index];
@@ -864,7 +862,6 @@ static int connect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *ob= ED_object_context(C);
- PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= NULL;
const bool all = RNA_boolean_get(op->ptr, "all");
bool any_connected = false;
@@ -878,12 +875,13 @@ static int connect_hair_exec(bContext *C, wmOperator *op)
}
}
else {
- psys = ptr.data;
+ psys = psys_get_current(ob);
any_connected |= connect_hair(scene, ob, psys);
}
if (!any_connected) {
- BKE_report(op->reports, RPT_ERROR, "Can't disconnect hair if particle system modifier is disabled");
+ BKE_report(op->reports, RPT_WARNING,
+ "No hair connected (can't connect hair if particle system modifier is disabled)");
return OPERATOR_CANCELLED;
}
@@ -902,7 +900,7 @@ void PARTICLE_OT_connect_hair(wmOperatorType *ot)
ot->exec = connect_hair_exec;
/* flags */
- ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO; /* No REGISTER, redo does not work due to missing update, see T47750. */
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
}
@@ -1066,9 +1064,9 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
psmd->psys = psys;
- psmd->dm = CDDM_copy(final_dm);
- CDDM_calc_normals(psmd->dm);
- DM_ensure_tessface(psmd->dm);
+ psmd->dm_final = CDDM_copy(final_dm);
+ CDDM_calc_normals(psmd->dm_final);
+ DM_ensure_tessface(psmd->dm_final);
if (psys_from->edit)
copy_particle_edit(scene, ob_to, psys, psys_from);
@@ -1095,6 +1093,7 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti
break;
default:
/* should not happen */
+ from_mat = to_mat = NULL;
BLI_assert(false);
break;
}
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index 71e5e23b5f1..e81aa584586 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -30,6 +30,9 @@
*/
#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -37,6 +40,7 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_screen.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_particle.h"
@@ -52,18 +56,9 @@
#include "physics_intern.h"
-static int cache_break_test(void *UNUSED(cbd))
-{
- return (G.is_break == true);
-}
static int ptcache_bake_all_poll(bContext *C)
{
- Scene *scene= CTX_data_scene(C);
-
- if (!scene)
- return 0;
-
- return 1;
+ return CTX_data_scene(C) != NULL;
}
static int ptcache_poll(bContext *C)
@@ -72,15 +67,82 @@ static int ptcache_poll(bContext *C)
return (ptr.data && ptr.id.data);
}
-static void bake_console_progress(void *UNUSED(arg), int nr)
+typedef struct PointCacheJob {
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+
+ PTCacheBaker *baker;
+} PointCacheJob;
+
+static void ptcache_job_free(void *customdata)
+{
+ PointCacheJob *job = customdata;
+ MEM_freeN(job->baker);
+ MEM_freeN(job);
+}
+
+static int ptcache_job_break(void *customdata)
+{
+ PointCacheJob *job = customdata;
+
+ if (G.is_break) {
+ return 1;
+ }
+
+ if (job->stop && *(job->stop)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void ptcache_job_update(void *customdata, float progress, int *cancel)
+{
+ PointCacheJob *job = customdata;
+
+ if (ptcache_job_break(job)) {
+ *cancel = 1;
+ }
+
+ *(job->do_update) = true;
+ *(job->progress) = progress;
+}
+
+static void ptcache_job_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- printf("\rbake: %3i%%", nr);
- fflush(stdout);
+ PointCacheJob *job = customdata;
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+
+ G.is_break = false;
+
+ /* XXX annoying hack: needed to prevent data corruption when changing
+ * scene frame in separate threads
+ */
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ BKE_ptcache_bake(job->baker);
+
+ *do_update = true;
+ *stop = 0;
}
-static void bake_console_progress_end(void *UNUSED(arg))
+static void ptcache_job_endjob(void *customdata)
{
- printf("\rbake: done!\n");
+ PointCacheJob *job = customdata;
+ Scene *scene = job->baker->scene;
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+
+ WM_set_locked_interface(G.main->wm.first, false);
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
+ WM_main_add_notifier(NC_OBJECT | ND_POINTCACHE, job->baker->pid.ob);
}
static void ptcache_free_bake(PointCache *cache)
@@ -97,44 +159,98 @@ static void ptcache_free_bake(PointCache *cache)
}
}
-static int ptcache_bake_all_exec(bContext *C, wmOperator *op)
+static PTCacheBaker *ptcache_baker_create(bContext *C, wmOperator *op, bool all)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene= CTX_data_scene(C);
- wmWindow *win = G.background ? NULL : CTX_wm_window(C);
- PTCacheBaker baker;
-
- baker.main = bmain;
- baker.scene = scene;
- baker.pid = NULL;
- baker.bake = RNA_boolean_get(op->ptr, "bake");
- baker.render = 0;
- baker.anim_init = 0;
- baker.quick_step = 1;
- baker.break_test = cache_break_test;
- baker.break_data = NULL;
-
- /* Disabled for now as this doesn't work properly,
- * and pointcache baking will be reimplemented with
- * the job system soon anyways. */
- if (win) {
- baker.progressbar = (void (*)(void *, int))WM_cursor_time;
- baker.progressend = (void (*)(void *))WM_cursor_modal_restore;
- baker.progresscontext = win;
- }
- else {
- baker.progressbar = bake_console_progress;
- baker.progressend = bake_console_progress_end;
- baker.progresscontext = NULL;
+ PTCacheBaker *baker = MEM_callocN(sizeof(PTCacheBaker), "PTCacheBaker");
+
+ baker->main = CTX_data_main(C);
+ baker->scene = CTX_data_scene(C);
+ baker->bake = RNA_boolean_get(op->ptr, "bake");
+ baker->render = 0;
+ baker->anim_init = 0;
+ baker->quick_step = 1;
+
+ if (!all) {
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
+ Object *ob = ptr.id.data;
+ PointCache *cache = ptr.data;
+
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, ob, baker->scene, MAX_DUPLI_RECUR);
+
+ for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache == cache) {
+ baker->pid = *pid;
+ break;
+ }
+ }
+
+ BLI_freelistN(&pidlist);
}
- BKE_ptcache_bake(&baker);
+ return baker;
+}
- WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
- WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, NULL);
+static int ptcache_bake_exec(bContext *C, wmOperator *op)
+{
+ bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
+
+ PTCacheBaker *baker = ptcache_baker_create(C, op, all);
+ BKE_ptcache_bake(baker);
+ MEM_freeN(baker);
return OPERATOR_FINISHED;
}
+
+static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all");
+
+ PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob");
+ job->baker = ptcache_baker_create(C, op, all);
+ job->baker->bake_job = job;
+ job->baker->update_progress = ptcache_job_update;
+
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C),
+ "Point Cache", WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE);
+
+ WM_jobs_customdata_set(wm_job, job, ptcache_job_free);
+ WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE);
+ WM_jobs_callbacks(wm_job, ptcache_job_startjob, NULL, NULL, ptcache_job_endjob);
+
+ WM_set_locked_interface(CTX_wm_manager(C), true);
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+
+ WM_event_add_modal_handler(C, op);
+
+ /* we must run modal until the bake job is done, otherwise the undo push
+ * happens before the job ends, which can lead to race conditions between
+ * the baking and file writing code */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Scene *scene = (Scene *) op->customdata;
+
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_POINTCACHE)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void ptcache_bake_cancel(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ Scene *scene = (Scene *) op->customdata;
+
+ /* kill on cancel, because job is using op->reports */
+ WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_POINTCACHE);
+}
+
static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
@@ -167,7 +283,10 @@ void PTCACHE_OT_bake_all(wmOperatorType *ot)
ot->idname = "PTCACHE_OT_bake_all";
/* api callbacks */
- ot->exec = ptcache_bake_all_exec;
+ ot->exec = ptcache_bake_exec;
+ ot->invoke = ptcache_bake_invoke;
+ ot->modal = ptcache_bake_modal;
+ ot->cancel = ptcache_bake_cancel;
ot->poll = ptcache_bake_all_poll;
/* flags */
@@ -189,59 +308,7 @@ void PTCACHE_OT_free_bake_all(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
-static int ptcache_bake_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- wmWindow *win = G.background ? NULL : CTX_wm_window(C);
- PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
- Object *ob= ptr.id.data;
- PointCache *cache= ptr.data;
- PTCacheBaker baker;
- PTCacheID *pid;
- ListBase pidlist;
-
- BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
-
- for (pid=pidlist.first; pid; pid=pid->next) {
- if (pid->cache == cache)
- break;
- }
- baker.main = bmain;
- baker.scene = scene;
- baker.pid = pid;
- baker.bake = RNA_boolean_get(op->ptr, "bake");
- baker.render = 0;
- baker.anim_init = 0;
- baker.quick_step = 1;
- baker.break_test = cache_break_test;
- baker.break_data = NULL;
-
- /* Disabled for now as this doesn't work properly,
- * and pointcache baking will be reimplemented with
- * the job system soon anyways. */
- if (win) {
- baker.progressbar = (void (*)(void *, int))WM_cursor_time;
- baker.progressend = (void (*)(void *))WM_cursor_modal_restore;
- baker.progresscontext = win;
- }
- else {
- printf("\n"); /* empty first line before console reports */
- baker.progressbar = bake_console_progress;
- baker.progressend = bake_console_progress_end;
- baker.progresscontext = NULL;
- }
-
- BKE_ptcache_bake(&baker);
-
- BLI_freelistN(&pidlist);
-
- WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
- WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
-
- return OPERATOR_FINISHED;
-}
static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA ptr= CTX_data_pointer_get_type(C, "point_cache", &RNA_PointCache);
@@ -275,6 +342,9 @@ void PTCACHE_OT_bake(wmOperatorType *ot)
/* api callbacks */
ot->exec = ptcache_bake_exec;
+ ot->invoke = ptcache_bake_invoke;
+ ot->modal = ptcache_bake_modal;
+ ot->cancel = ptcache_bake_cancel;
ot->poll = ptcache_poll;
/* flags */
@@ -377,7 +447,7 @@ void PTCACHE_OT_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = ptcache_add_new_exec;
- ot->poll = ptcache_poll; // ptcache_bake_all_poll;
+ ot->poll = ptcache_poll;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 85b059d5574..f95599592b2 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -153,7 +153,7 @@ void RIGIDBODY_OT_constraint_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_constraint_type_items, RBC_TYPE_FIXED, "Rigid Body Constraint Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_constraint_type_items, RBC_TYPE_FIXED, "Rigid Body Constraint Type", "");
}
/* ************ Remove Rigid Body Constraint ************** */
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 949084973cf..26d8af82b2d 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -179,7 +179,7 @@ void RIGIDBODY_OT_object_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_object_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_object_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
}
/* ************ Remove Rigid Body ************** */
@@ -270,7 +270,7 @@ void RIGIDBODY_OT_objects_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_object_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_object_type_items, RBO_TYPE_ACTIVE, "Rigid Body Type", "");
}
/* ************ Remove Rigid Bodies ************** */
@@ -374,7 +374,7 @@ void RIGIDBODY_OT_shape_change(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", rigidbody_object_shape_items, RB_SHAPE_TRIMESH, "Rigid Body Shape", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_rigidbody_object_shape_items, RB_SHAPE_TRIMESH, "Rigid Body Shape", "");
}
/* ************ Calculate Mass ************** */
diff --git a/source/blender/editors/physics/rigidbody_world.c b/source/blender/editors/physics/rigidbody_world.c
index 0bd9ec5f4cd..bd8505fcf15 100644
--- a/source/blender/editors/physics/rigidbody_world.c
+++ b/source/blender/editors/physics/rigidbody_world.c
@@ -195,5 +195,7 @@ void RIGIDBODY_OT_world_export(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_SPECIAL, FILE_SAVE, FILE_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER, FILE_SPECIAL, FILE_SAVE,
+ FILE_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript
deleted file mode 100644
index 24270ca2324..00000000000
--- a/source/blender/editors/render/SConscript
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/elbeem/extern',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blenloader',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_FREESTYLE']:
- incs += ' ../../freestyle'
- env.Append(CFLAGS=['-DWITH_FREESTYLE'])
-
-if env['WITH_BF_QUICKTIME']:
- incs += ' ../../quicktime'
- env.Append(CFLAGS=['-DWITH_QUICKTIME'])
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_render', sources, Split(incs), defs, libtype=['core'], priority=[45])
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index 54429f9f066..fb07b03c286 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -89,11 +89,12 @@ void TEXTURE_OT_envmap_clear_all(struct wmOperatorType *ot);
/* render_internal.c */
void RENDER_OT_render(struct wmOperatorType *ot);
+void RENDER_OT_shutter_curve_preset(struct wmOperatorType *ot);
void render_view3d_update(struct RenderEngine *engine, const struct bContext *C);
void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C);
/* render_view.c */
-struct ScrArea *render_view_open(struct bContext *C, int mx, int my);
+struct ScrArea *render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports);
void RENDER_OT_view_show(struct wmOperatorType *ot);
void RENDER_OT_view_cancel(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 10de2d667ea..eb8ea01f750 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -192,7 +192,7 @@ static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibu
/* TODO(sergey): Need to check has_combined here? */
if (iuser->pass == 0) {
RenderView *rv;
- size_t view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
+ const int view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
rv = RE_RenderViewGetById(rr, view_id);
/* find current float rect for display, first case is after composite... still weak */
@@ -311,7 +311,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
- BKE_image_backup_render(scene, ima);
+ BKE_image_backup_render(scene, ima, true);
/* cleanup sequencer caches before starting user triggered render.
* otherwise, invalidated cache entries can make their way into
@@ -786,7 +786,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay)
Base *base;
for (object = bmain->object.first; object; object = object->id.next) {
- object->id.flag |= LIB_DOIT;
+ object->id.tag |= LIB_TAG_DOIT;
}
for (SETLOOPER(scene, sce_iter, base)) {
@@ -794,16 +794,16 @@ static void clean_viewport_memory(Main *bmain, Scene *scene, int renderlay)
continue;
}
if (RE_allow_render_generic_object(base->object)) {
- base->object->id.flag &= ~LIB_DOIT;
+ base->object->id.tag &= ~LIB_TAG_DOIT;
}
}
for (SETLOOPER(scene, sce_iter, base)) {
object = base->object;
- if ((object->id.flag & LIB_DOIT) == 0) {
+ if ((object->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
- object->id.flag &= ~LIB_DOIT;
+ object->id.tag &= ~LIB_TAG_DOIT;
BKE_object_free_derived_caches(object);
}
@@ -877,7 +877,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
// store spare
/* ensure at least 1 area shows result */
- sa = render_view_open(C, event->x, event->y);
+ sa = render_view_open(C, event->x, event->y, op->reports);
jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS;
@@ -956,7 +956,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* get a render result image, and make sure it is empty */
ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
- BKE_image_backup_render(rj->scene, ima);
+ BKE_image_backup_render(rj->scene, ima, true);
rj->image = ima;
/* setup new render */
@@ -1188,6 +1188,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
char name[32];
int update_flag;
bool use_border;
+ int ob_inst_update_flag = 0;
update_flag = rp->engine->job_update_flag;
rp->engine->job_update_flag = 0;
@@ -1299,6 +1300,13 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
/* OK, can we enter render code? */
if (rstats->convertdone) {
bool first_time = true;
+
+ if (update_flag & PR_UPDATE_VIEW) {
+ ob_inst_update_flag |= RE_OBJECT_INSTANCES_UPDATE_VIEW;
+ }
+
+ RE_updateRenderInstances(re, ob_inst_update_flag);
+
for (;;) {
if (first_time == false) {
if (restore)
@@ -1640,3 +1648,45 @@ Scene *ED_render_job_get_current_scene(const bContext *C)
}
return NULL;
}
+
+/* Motion blur curve preset */
+
+static int render_shutter_curve_preset_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ CurveMapping *mblur_shutter_curve = &scene->r.mblur_shutter_curve;
+ CurveMap *cm = mblur_shutter_curve->cm;
+ int preset = RNA_enum_get(op->ptr, "shape");
+
+ cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ mblur_shutter_curve->preset = preset;
+ curvemap_reset(cm,
+ &mblur_shutter_curve->clipr,
+ mblur_shutter_curve->preset,
+ CURVEMAP_SLOPE_POS_NEG);
+ curvemapping_changed(mblur_shutter_curve, false);
+
+ return OPERATOR_FINISHED;
+}
+
+void RENDER_OT_shutter_curve_preset(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static EnumPropertyItem prop_shape_items[] = {
+ {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
+ {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
+ {CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
+ {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
+ {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
+ {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ ot->name = "Shutter Curve Preset";
+ ot->description = "Set shutter curve";
+ ot->idname = "RENDER_OT_shutter_curve_preset";
+
+ ot->exec = render_shutter_curve_preset_exec;
+
+ prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+}
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index c718dfa9229..992b827113d 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -69,9 +69,9 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_compositing.h"
+#include "GPU_framebuffer.h"
#include "render_intern.h"
@@ -88,14 +88,21 @@ typedef struct OGLRender {
ScrArea *prevsa;
ARegion *prevar;
+ int views_len; /* multi-view views */
+
bool is_sequencer;
SpaceSeq *sseq;
+ struct {
+ ImBuf **ibufs_arr;
+ } seq_data;
Image *ima;
ImageUser iuser;
GPUOffScreen *ofs;
+ int ofs_samples;
+ bool ofs_full_samples;
GPUFX *fx;
int sizex, sizey;
int write_still;
@@ -104,7 +111,7 @@ typedef struct OGLRender {
bMovieHandle *mh;
int cfrao, nfra;
- size_t totvideos;
+ int totvideos;
/* quick lookup */
int view_id;
@@ -228,13 +235,8 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
BLI_lock_thread(LOCK_DRAW_IMAGE);
- if (is_multiview && BKE_scene_multiview_is_stereo3d(rd)) {
- oglrender->ima->flag |= IMA_IS_STEREO;
- }
- else {
- oglrender->ima->flag &= ~IMA_IS_STEREO;
+ if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd)))
oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
- }
BLI_unlock_thread(LOCK_DRAW_IMAGE);
/* will only work for non multiview correctly */
@@ -256,9 +258,6 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
Object *camera = NULL;
- ImBuf *ibuf;
- float winmat[4][4];
- float *rectf = RE_RenderViewGetById(rr, oglrender->view_id)->rectf;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
const short view_context = (v3d != NULL);
@@ -268,48 +267,35 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
const char *viewname = RE_GetActiveRenderView(oglrender->re);
if (oglrender->is_sequencer) {
- SeqRenderData context;
SpaceSeq *sseq = oglrender->sseq;
- int chanshown = sseq ? sseq->chanshown : 0;
struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;
- BKE_sequencer_new_render_data(
- oglrender->bmain->eval_ctx, oglrender->bmain, scene,
- oglrender->sizex, oglrender->sizey, 100.0f,
- &context);
-
- context.view_id = BKE_scene_multiview_view_id_get(&scene->r, viewname);
- ibuf = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
+ /* use pre-calculated ImBuf (avoids deadlock), see: */
+ ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
if (ibuf) {
- ImBuf *linear_ibuf;
-
- BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
-
- linear_ibuf = IMB_dupImBuf(ibuf);
+ ImBuf *out = IMB_dupImBuf(ibuf);
IMB_freeImBuf(ibuf);
-
- if (linear_ibuf->rect_float == NULL) {
- /* internally sequencer working in display space and stores both bytes and float buffers in that space.
- * It is possible that byte->float onversion didn't happen in sequencer (e.g. when adding image sequence/movie
- * into sequencer) there'll be only byte buffer. Create float buffer from existing byte buffer, making it linear
- */
-
- IMB_float_from_rect(linear_ibuf);
+ /* OpenGL render is considered to be preview and should be
+ * as fast as possible. So currently we're making sure sequencer
+ * result is always byte to simplify color management pipeline.
+ *
+ * TODO(sergey): In the case of output to float container (EXR)
+ * it actually makes sense to keep float buffer instead.
+ */
+ if (out->rect_float != NULL) {
+ IMB_rect_from_float(out);
+ imb_freerectfloatImBuf(out);
}
- else {
- /* ensure float buffer is in linear space, not in display space */
- BKE_sequencer_imbuf_from_sequencer_space(scene, linear_ibuf);
- }
-
- memcpy(rectf, linear_ibuf->rect_float, sizeof(float) * 4 * oglrender->sizex * oglrender->sizey);
-
- IMB_freeImBuf(linear_ibuf);
+ BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
+ RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
+ IMB_freeImBuf(out);
}
if (gpd) {
int i;
unsigned char *gp_rect;
+ unsigned char *render_rect = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
GPU_offscreen_bind(oglrender->ofs, true);
@@ -326,114 +312,41 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
- BLI_assert(rectf != NULL);
-
for (i = 0; i < sizex * sizey * 4; i += 4) {
- float col_src[4];
- rgba_uchar_to_float(col_src, &gp_rect[i]);
- blend_color_mix_float(&rectf[i], &rectf[i], col_src);
+ blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
}
GPU_offscreen_unbind(oglrender->ofs, true);
MEM_freeN(gp_rect);
}
}
- else if (view_context) {
- bool is_persp;
- /* full copy */
- GPUFXSettings fx_settings = v3d->fx_settings;
-
- ED_view3d_draw_offscreen_init(scene, v3d);
-
- GPU_offscreen_bind(oglrender->ofs, true); /* bind */
-
- /* render 3d view */
- if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
-#if 0
- const bool is_ortho = (scene->r.mode & R_ORTHO) != 0;
-#endif
- camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
- RE_GetCameraWindow(oglrender->re, camera, scene->r.cfra, winmat);
- if (camera->type == OB_CAMERA) {
- Camera *cam = camera->data;
- is_persp = cam->type == CAM_PERSP;
+ else {
+ /* shouldnt suddenly give errors mid-render but possible */
+ char err_out[256] = "unknown";
+ ImBuf *ibuf_view;
+ const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
+
+ if (view_context) {
+ ibuf_view = ED_view3d_draw_offscreen_imbuf(
+ scene, v3d, ar, sizex, sizey,
+ IB_rect, draw_bgpic,
+ alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname,
+ oglrender->fx, oglrender->ofs, err_out);
+
+ /* for stamp only */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
}
- else
- is_persp = true;
- BKE_camera_to_gpu_dof(camera, &fx_settings);
}
else {
- rctf viewplane;
- float clipsta, clipend;
-
- bool is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
- if (is_ortho) orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
- else perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
-
- is_persp = !is_ortho;
- }
-
- rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
-
- if ((scene->r.mode & R_OSA) == 0) {
- ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, winmat,
- draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings, viewname);
- GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
- }
- else {
- /* simple accumulation, less hassle then FSAA FBO's */
- static float jit_ofs[32][2];
- float winmat_jitter[4][4];
- int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int) * 4, "accum1");
- int i, j;
-
- BLI_jitter_init(jit_ofs, scene->r.osa);
-
- /* first sample buffer, also initializes 'rv3d->persmat' */
- ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, winmat,
- draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings, viewname);
- GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
-
- for (i = 0; i < sizex * sizey * 4; i++)
- accum_buffer[i] = rect[i];
-
- /* skip the first sample */
- for (j = 1; j < scene->r.osa; j++) {
- copy_m4_m4(winmat_jitter, winmat);
- window_translate_m4(winmat_jitter, rv3d->persmat,
- (jit_ofs[j][0] * 2.0f) / sizex,
- (jit_ofs[j][1] * 2.0f) / sizey);
-
- ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
- draw_bgpic, draw_sky, is_persp,
- oglrender->ofs, oglrender->fx, &fx_settings, viewname);
- GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, rect);
-
- for (i = 0; i < sizex * sizey * 4; i++)
- accum_buffer[i] += rect[i];
- }
-
- for (i = 0; i < sizex * sizey * 4; i++)
- rect[i] = accum_buffer[i] / scene->r.osa;
-
- MEM_freeN(accum_buffer);
+ ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(
+ scene, scene->camera, oglrender->sizex, oglrender->sizey,
+ IB_rect, OB_SOLID, false, true, true,
+ alpha_mode, oglrender->ofs_samples, oglrender->ofs_full_samples, viewname,
+ oglrender->fx, oglrender->ofs, err_out);
+ camera = scene->camera;
}
- GPU_offscreen_unbind(oglrender->ofs, true); /* unbind */
- }
- else {
- /* shouldnt suddenly give errors mid-render but possible */
- char err_out[256] = "unknown";
- ImBuf *ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, oglrender->sizex, oglrender->sizey,
- IB_rect, OB_SOLID, false, true, true,
- (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL, viewname, err_out);
- camera = scene->camera;
-
if (ibuf_view) {
/* steal rect reference from ibuf */
rect = (unsigned char *)ibuf_view->rect;
@@ -472,7 +385,7 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
/* rr->rectf is now filled with image data */
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
- BKE_image_stamp_buf(scene, camera, rect, rectf, rr->rectx, rr->recty, 4);
+ BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
MEM_freeN(rect);
}
@@ -509,8 +422,31 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
ImBuf *ibuf;
void *lock;
+ if (oglrender->is_sequencer) {
+ Scene *scene = oglrender->scene;
+
+ SeqRenderData context;
+ SpaceSeq *sseq = oglrender->sseq;
+ int chanshown = sseq ? sseq->chanshown : 0;
+
+ BKE_sequencer_new_render_data(
+ oglrender->bmain->eval_ctx, oglrender->bmain, scene,
+ oglrender->sizex, oglrender->sizey, 100.0f,
+ &context);
+
+ for (view_id = 0; view_id < oglrender->views_len; view_id++) {
+ context.view_id = view_id;
+ context.gpu_offscreen = oglrender->ofs;
+ context.gpu_fx = oglrender->fx;
+ context.gpu_full_samples = oglrender->ofs_full_samples;
+
+ oglrender->seq_data.ibufs_arr[view_id] = BKE_sequencer_give_ibuf(&context, CFRA, chanshown);
+ }
+ }
+
rr = RE_AcquireResultRead(oglrender->re);
for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
screen_opengl_render_doit(oglrender, rr);
@@ -541,6 +477,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
GPUOffScreen *ofs;
OGLRender *oglrender;
int sizex, sizey;
+ const int samples = (scene->r.mode & R_OSA) ? scene->r.osa : 0;
+ const bool full_samples = (samples != 0) && (scene->r.scemode & R_FULL_SAMPLE);
bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
@@ -585,7 +523,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
sizey = (scene->r.size * scene->r.ysch) / 100;
/* corrects render size with actual size, not every card supports non-power-of-two dimensions */
- ofs = GPU_offscreen_create(sizex, sizey, err_out);
+ ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out);
if (!ofs) {
BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
@@ -597,6 +535,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
op->customdata = oglrender;
oglrender->ofs = ofs;
+ oglrender->ofs_samples = samples;
+ oglrender->ofs_full_samples = full_samples;
oglrender->sizex = sizex;
oglrender->sizey = sizey;
oglrender->bmain = CTX_data_main(C);
@@ -605,9 +545,13 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->write_still = is_write_still && !is_animation;
+ oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
+
oglrender->is_sequencer = is_sequencer;
if (is_sequencer) {
oglrender->sseq = CTX_wm_space_seq(C);
+ ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
+ oglrender->seq_data.ibufs_arr = ibufs_arr;
}
oglrender->prevsa = prevsa;
@@ -635,7 +579,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create image and image user */
oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE);
- BKE_image_backup_render(oglrender->scene, oglrender->ima);
+ BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
oglrender->iuser.scene = scene;
oglrender->iuser.ok = 1;
@@ -661,7 +605,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
{
Main *bmain = CTX_data_main(C);
Scene *scene = oglrender->scene;
- size_t i;
+ int i;
if (oglrender->mh) {
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
@@ -692,6 +636,10 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
GPU_offscreen_free(oglrender->ofs);
+ if (oglrender->is_sequencer) {
+ MEM_freeN(oglrender->seq_data.ibufs_arr);
+ }
+
oglrender->scene->customdata_mask_modal = 0;
CTX_wm_area_set(C, oglrender->prevsa);
@@ -706,7 +654,7 @@ static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
}
/* share between invoke and exec */
-static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
+static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
{
/* initialize animation */
OGLRender *oglrender;
@@ -719,12 +667,20 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender->reports = op->reports;
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- size_t i, width, height;
+ size_t width, height;
+ int i;
BKE_scene_multiview_videos_dimensions_get(&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
- oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+ if (oglrender->mh == NULL) {
+ BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
+ screen_opengl_render_end(C, oglrender);
+ return false;
+ }
+
+ oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+
for (i = 0; i < oglrender->totvideos; i++) {
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
@@ -733,7 +689,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender->sizey, oglrender->reports, PRVRANGEON != 0, suffix))
{
screen_opengl_render_end(C, oglrender);
- return 0;
+ return false;
}
}
}
@@ -742,7 +698,7 @@ static int screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
oglrender->nfra = PSFRA;
scene->r.cfra = PSFRA;
- return 1;
+ return true;
}
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
@@ -807,8 +763,8 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
rr = RE_AcquireResultRead(oglrender->re);
if (is_movie) {
- ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh, oglrender->sizex,
- oglrender->sizey, oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
+ ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh,
+ oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
if (ok) {
printf("Append frame %d", scene->r.cfra);
BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
@@ -904,7 +860,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven
}
oglrender = op->customdata;
- render_view_open(C, event->x, event->y);
+ render_view_open(C, event->x, event->y, op->reports);
/* view may be changed above (R_OUTPUT_WINDOW) */
oglrender->win = CTX_wm_window(C);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index f98083f7e74..c09e8576dc2 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -93,6 +93,7 @@ void ED_operatortypes_render(void)
WM_operatortype_append(RENDER_OT_view_show);
WM_operatortype_append(RENDER_OT_render);
WM_operatortype_append(RENDER_OT_view_cancel);
+ WM_operatortype_append(RENDER_OT_shutter_curve_preset);
/* render_opengl.c */
WM_operatortype_append(RENDER_OT_opengl);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 6dfd2b31d30..f4260a0cd33 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -614,7 +614,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
ID *id = (ID *)idp;
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
- SpaceButs *sbuts = sa->spacedata.first;
+ SpaceButs *sbuts = CTX_wm_space_buts(C);
ShaderPreview *sp = WM_jobs_customdata(wm, sa);
rcti newrect;
int ok;
@@ -639,11 +639,13 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
/* start a new preview render job if signalled through sbuts->preview,
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
- if ((sbuts->spacetype == SPACE_BUTS && sbuts->preview) ||
+ if ((sbuts != NULL && sbuts->preview) ||
(!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (ABS(sp->sizex - newx) >= 2 || ABS(sp->sizey - newy) > 2)))
{
- sbuts->preview = 0;
+ if (sbuts != NULL) {
+ sbuts->preview = 0;
+ }
ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER);
}
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 2e07e19e366..1d20ecf2d99 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -481,7 +481,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer use also increases user, so this compensates it */
- ma->id.us--;
+ id_us_min(&ma->id);
RNA_id_pointer_create(&ma->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
@@ -530,7 +530,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- tex->id.us--;
+ id_us_min(&tex->id);
if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA &&
RNA_property_pointer_get(&ptr, prop).id.data == NULL)
@@ -593,7 +593,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- wo->id.us--;
+ id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
@@ -1039,7 +1039,7 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
if (lineset->linestyle) {
- lineset->linestyle->id.us--;
+ id_us_min(&lineset->linestyle->id);
lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle);
}
else {
@@ -1103,7 +1103,7 @@ void SCENE_OT_freestyle_color_modifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", linestyle_color_modifier_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_color_modifier_type_items, 0, "Type", "");
}
static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
@@ -1143,7 +1143,7 @@ void SCENE_OT_freestyle_alpha_modifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", linestyle_alpha_modifier_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_alpha_modifier_type_items, 0, "Type", "");
}
static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
@@ -1183,7 +1183,7 @@ void SCENE_OT_freestyle_thickness_modifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", linestyle_thickness_modifier_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "Type", "");
}
static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
@@ -1223,7 +1223,7 @@ void SCENE_OT_freestyle_geometry_modifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", linestyle_geometry_modifier_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "Type", "");
}
static int freestyle_get_modifier_type(PointerRNA *ptr)
@@ -1619,8 +1619,9 @@ void TEXTURE_OT_envmap_save(wmOperatorType *ot)
"(use -1 to skip a face)", 0.0f, 0.0f);
RNA_def_property_flag(prop, PROP_HIDDEN);
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
static int envmap_clear_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1826,7 +1827,7 @@ static void paste_mtex_copybuf(ID *id)
*mtex = MEM_mallocN(sizeof(MTex), "mtex copy");
}
else if ((*mtex)->tex) {
- (*mtex)->tex->id.us--;
+ id_us_min(&(*mtex)->tex->id);
}
memcpy(*mtex, &mtexcopybuf, sizeof(MTex));
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index f6690296890..65f0fec50bc 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -38,6 +38,7 @@
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_report.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -125,7 +126,7 @@ static ScrArea *find_area_image_empty(bContext *C)
/********************** open image editor for render *************************/
/* new window uses x,y to set position */
-ScrArea *render_view_open(bContext *C, int mx, int my)
+ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
@@ -155,7 +156,10 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
rect.ymax = rect.ymin + sizey;
/* changes context! */
- WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
+ if (WM_window_open_temp(C, &rect, WM_WINDOW_RENDER) == NULL) {
+ BKE_report(reports, RPT_ERROR, "Failed to open window!");
+ return NULL;
+ }
sa = CTX_wm_area(C);
}
@@ -189,7 +193,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
/* find largest open non-image area */
sa = biggest_non_image_area(C);
if (sa) {
- ED_area_newspace(C, sa, SPACE_IMAGE);
+ ED_area_newspace(C, sa, SPACE_IMAGE, true);
sima = sa->spacedata.first;
/* makes ESC go back to prev space */
@@ -261,7 +265,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa, false);
+ ED_screen_full_prevspace(C, sa);
}
else {
ED_area_prevspace(C, sa);
@@ -292,7 +296,7 @@ void RENDER_OT_view_cancel(struct wmOperatorType *ot)
/************************* show render viewer *****************/
-static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *wincur = CTX_wm_window(C);
@@ -326,22 +330,16 @@ static int render_view_show_invoke(bContext *C, wmOperator *UNUSED(op), const wm
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa, false);
+ ED_screen_full_prevspace(C, sa);
}
- else if (sima->next) {
- /* workaround for case of double prevspace, render window
- * with a file browser on top of it (same as in ED_area_prevspace) */
- if (sima->next->spacetype == SPACE_FILE && sima->next->next)
- ED_area_newspace(C, sa, sima->next->next->spacetype);
- else
- ED_area_newspace(C, sa, sima->next->spacetype);
- ED_area_tag_redraw(sa);
+ else {
+ ED_area_prevspace(C, sa);
}
}
}
}
else {
- render_view_open(C, event->x, event->y);
+ render_view_open(C, event->x, event->y, op->reports);
}
}
diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript
deleted file mode 100644
index 5f48894c3e7..00000000000
--- a/source/blender/editors/screen/SConscript
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_screen', sources, Split(incs), Split(defs), libtype=['core'], priority=[105] )
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 79d6b845361..3511480821a 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -409,6 +409,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
if (!sa)
return;
+ glLineWidth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -501,7 +502,7 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
/* note; this sets state, so we can use wmOrtho and friends */
wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, scissor_pad);
- wmOrtho2_region_ui(ar);
+ wmOrtho2_region_pixelspace(ar);
UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
@@ -1338,7 +1339,7 @@ static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
/* used for area initialize below */
-static void region_subwindow(wmWindow *win, ARegion *ar)
+static void region_subwindow(wmWindow *win, ARegion *ar, bool activate)
{
bool hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) != 0;
@@ -1350,10 +1351,12 @@ static void region_subwindow(wmWindow *win, ARegion *ar)
wm_subwindow_close(win, ar->swinid);
ar->swinid = 0;
}
- else if (ar->swinid == 0)
- ar->swinid = wm_subwindow_open(win, &ar->winrct);
- else
- wm_subwindow_position(win, ar->swinid, &ar->winrct);
+ else if (ar->swinid == 0) {
+ ar->swinid = wm_subwindow_open(win, &ar->winrct, activate);
+ }
+ else {
+ wm_subwindow_position(win, ar->swinid, &ar->winrct, activate);
+ }
}
static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag)
@@ -1456,7 +1459,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
/* region windows, default and own handlers */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- region_subwindow(win, ar);
+ region_subwindow(win, ar, false);
if (ar->swinid) {
/* default region handlers */
@@ -1497,13 +1500,23 @@ void ED_region_update_rect(bContext *C, ARegion *ar)
void ED_region_init(bContext *C, ARegion *ar)
{
// ARegionType *at = ar->type;
-
+
/* refresh can be called before window opened */
- region_subwindow(CTX_wm_window(C), ar);
-
+ region_subwindow(CTX_wm_window(C), ar, false);
+
region_update_rect(ar);
}
+void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
+{
+ if (ar && sa && ar->type && ar->type->cursor) {
+ ar->type->cursor(win, sa, ar);
+ }
+ else {
+ WM_cursor_set(win, CURSOR_STD);
+ }
+}
+
/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
{
@@ -1608,15 +1621,31 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
ED_area_tag_refresh(sa2);
}
-void ED_area_newspace(bContext *C, ScrArea *sa, int type)
+/**
+ * \param skip_ar_exit Skip calling area exit callback. Set for opening temp spaces.
+ */
+void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exit)
{
if (sa->spacetype != type) {
SpaceType *st;
SpaceLink *slold;
SpaceLink *sl;
+ /* store sa->type->exit callback */
+ void *sa_exit = sa->type ? sa->type->exit : NULL;
+
+ /* in some cases (opening temp space) we don't want to
+ * call area exit callback, so we temporarily unset it */
+ if (skip_ar_exit && sa->type) {
+ sa->type->exit = NULL;
+ }
ED_area_exit(C, sa);
+ /* restore old area exit callback */
+ if (skip_ar_exit && sa->type) {
+ sa->type->exit = sa_exit;
+ }
+
st = BKE_spacetype_from_id(type);
slold = sa->spacedata.first;
@@ -1683,12 +1712,12 @@ void ED_area_prevspace(bContext *C, ScrArea *sa)
SpaceLink *sl = sa->spacedata.first;
if (sl && sl->next) {
- /* workaround for case of double prevspace, render window
- * with a file browser on top of it */
- if (sl->next->spacetype == SPACE_FILE && sl->next->next)
- ED_area_newspace(C, sa, sl->next->next->spacetype);
- else
- ED_area_newspace(C, sa, sl->next->spacetype);
+ ED_area_newspace(C, sa, sl->next->spacetype, false);
+
+ /* keep old spacedata but move it to end, so calling
+ * ED_area_prevspace once more won't open it again */
+ BLI_remlink(&sa->spacedata, sl);
+ BLI_addtail(&sa->spacedata, sl);
}
else {
/* no change */
@@ -1734,7 +1763,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
int redo;
int scroll;
- bool use_category_tabs = (ar->regiontype == RGN_TYPE_TOOLS); /* XXX, should use some better check? */
+ bool use_category_tabs = (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI)); /* XXX, should use some better check? */
/* offset panels for small vertical tab area */
const char *category = NULL;
const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
@@ -1940,6 +1969,8 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
glClear(GL_COLOR_BUFFER_BIT);
}
+ /* reset line width for drawing tabs */
+ glLineWidth(1.0f);
/* set the view */
UI_view2d_view_ortho(v2d);
@@ -2083,9 +2114,9 @@ static const char *meta_data_list[] =
{
"File",
"Strip",
- "Note",
"Date",
"RenderTime",
+ "Note",
"Marker",
"Time",
"Frame",
@@ -2106,7 +2137,15 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
short i;
int len;
const float height = BLF_height_max(fontid);
- const float vertical_offset = height + (0.1f * U.widget_unit);
+ const float margin = height / 8;
+ const float vertical_offset = (height + margin);
+
+ /* values taking margins into account */
+ const float descender = BLF_descender(fontid);
+ const float xmin = (rect->xmin + margin);
+ const float xmax = (rect->xmax - margin);
+ const float ymin = (rect->ymin + margin) - descender;
+ const float ymax = (rect->ymax - margin) - descender;
if (is_top) {
for (i = 0; i < 4; i++) {
@@ -2115,8 +2154,7 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
bool do_newline = false;
len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]);
if (metadata_is_valid(ibuf, temp_str, 0, len)) {
- BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit),
- rect->ymax - vertical_offset, 0.0f);
+ BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f);
BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
do_newline = true;
}
@@ -2124,30 +2162,40 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]);
if (metadata_is_valid(ibuf, temp_str, 1, len)) {
line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_position(fontid, rect->xmax - line_width - (0.2f * U.widget_unit),
- rect->ymax - vertical_offset, 0.0f);
+ BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f);
BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
do_newline = true;
}
if (do_newline)
ofs_y += vertical_offset;
- }
- else if (i == 1) {
+ } /* Strip */
+ else if (i == 1 || i == 2) {
len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
- BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit),
- rect->ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
ofs_y += vertical_offset;
}
+ } /* Note (wrapped) */
+ else if (i == 3) {
+ len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
+ if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
+ struct ResultBLF info;
+ BLF_enable(fontid, BLF_WORD_WRAP);
+ BLF_wordwrap(fontid, ibuf->x - (margin * 2));
+ BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info);
+ BLF_wordwrap(fontid, 0);
+ BLF_disable(fontid, BLF_WORD_WRAP);
+ ofs_y += vertical_offset * info.lines;
+ }
}
else {
len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]);
if (metadata_is_valid(ibuf, temp_str, i + 1, len)) {
line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
- BLF_position(fontid, rect->xmax - line_width - (0.2f * U.widget_unit),
- rect->ymax - vertical_offset - ofs_y, 0.0f);
+ BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f);
BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
ofs_y += vertical_offset;
}
@@ -2159,8 +2207,7 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
for (i = 5; i < 10; i++) {
len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]);
if (metadata_is_valid(ibuf, temp_str, i, len)) {
- BLF_position(fontid, rect->xmin + (0.2f * U.widget_unit) + ofs_x,
- rect->ymin + (0.3f * U.widget_unit), 0.0f);
+ BLF_position(fontid, xmin + ofs_x, ymin, 0.0f);
BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX);
ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X;
@@ -2171,9 +2218,10 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const
static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
{
+ const float height = BLF_height_max(fontid);
+ const float margin = (height / 8);
char str[MAX_METADATA_STR] = "";
short i, count = 0;
- const float height = BLF_height_max(fontid) + 0.1f * U.widget_unit;
if (is_top) {
if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) {
@@ -2181,7 +2229,23 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
}
for (i = 2; i < 5; i++) {
if (metadata_is_valid(ibuf, str, i, 0)) {
- count++;
+ if (i == 4) {
+ struct {
+ struct ResultBLF info;
+ rctf rect;
+ } wrap;
+
+ BLF_enable(fontid, BLF_WORD_WRAP);
+ BLF_wordwrap(fontid, ibuf->x - (margin * 2));
+ BLF_boundbox_ex(fontid, str, sizeof(str), &wrap.rect, &wrap.info);
+ BLF_wordwrap(fontid, 0);
+ BLF_disable(fontid, BLF_WORD_WRAP);
+
+ count += wrap.info.lines;
+ }
+ else {
+ count++;
+ }
}
}
}
@@ -2194,7 +2258,7 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
}
if (count) {
- return (height * count + (0.1f * U.widget_unit));
+ return (height + margin) * count;
}
return 0;
@@ -2202,7 +2266,7 @@ static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top)
#undef MAX_METADATA_STR
-void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float zoomx, float zoomy)
+void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy)
{
float box_y;
rctf rect;
@@ -2218,7 +2282,7 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float
glTranslatef(x, y, 0.0f);
glScalef(zoomx, zoomy, 1.0f);
- BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f, U.dpi);
+ BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi);
/* *** upper box*** */
@@ -2229,7 +2293,7 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float
UI_ThemeColor(TH_METADATA_BG);
/* set up rect */
- BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymax, frame.ymax + box_y);
+ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y);
/* draw top box */
glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
@@ -2251,7 +2315,7 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, rctf frame, float
UI_ThemeColor(TH_METADATA_BG);
/* set up box rect */
- BLI_rctf_init(&rect, frame.xmin, frame.xmax, frame.ymin - box_y, frame.ymin);
+ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin);
/* draw top box */
glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index fd65d81baad..b7ad911b6f5 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -45,105 +45,17 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
-
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#include "GPU_basic_shader.h"
+
#include "UI_interface.h"
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
-
-/* ******************************************** */
-
-/* defined in BIF_gl.h */
-const GLubyte stipple_halftone[128] = {
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
- 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
-
-
-/* repeat this pattern
- *
- * X000X000
- * 00000000
- * 00X000X0
- * 00000000 */
-
-
-const GLubyte stipple_quarttone[128] = {
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
- 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0};
-
-
-const GLubyte stipple_diag_stripes_pos[128] = {
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
-
-
-const GLubyte stipple_diag_stripes_neg[128] = {
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
- 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
- 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
- 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
- 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
- 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
- 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
- 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
- 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
-
-const GLubyte stipple_checker_8px[128] = {
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
- 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255};
-
/* UNUSED */
#if 0
void fdrawbezier(float vec[4][3])
@@ -159,7 +71,7 @@ void fdrawbezier(float vec[4][3])
vec[2][0] = vec[3][0] - dist;
vec[2][1] = vec[3][1];
- /* we can reuse the dist variable here to increment the GL curve eval amount*/
+ /* we can reuse the dist variable here to increment the GL curve eval amount */
dist = 1.0f / curve_res;
cpack(0x0);
@@ -179,32 +91,20 @@ void fdrawbezier(float vec[4][3])
void fdrawline(float x1, float y1, float x2, float y2)
{
- float v[2];
-
- glBegin(GL_LINE_STRIP);
- v[0] = x1; v[1] = y1;
- glVertex2fv(v);
- v[0] = x2; v[1] = y2;
- glVertex2fv(v);
+ glBegin(GL_LINES);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y2);
glEnd();
}
void fdrawbox(float x1, float y1, float x2, float y2)
{
- float v[2];
+ glBegin(GL_LINE_LOOP);
- glBegin(GL_LINE_STRIP);
-
- v[0] = x1; v[1] = y1;
- glVertex2fv(v);
- v[0] = x1; v[1] = y2;
- glVertex2fv(v);
- v[0] = x2; v[1] = y2;
- glVertex2fv(v);
- v[0] = x2; v[1] = y1;
- glVertex2fv(v);
- v[0] = x1; v[1] = y1;
- glVertex2fv(v);
+ glVertex2f(x1, y1);
+ glVertex2f(x1, y2);
+ glVertex2f(x2, y2);
+ glVertex2f(x2, y1);
glEnd();
}
@@ -217,21 +117,17 @@ void fdrawcheckerboard(float x1, float y1, float x2, float y2)
glRectf(x1, y1, x2, y2);
glColor3ubv(col2);
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_checker_8px);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX);
glRectf(x1, y1, x2, y2);
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
void sdrawline(int x1, int y1, int x2, int y2)
{
- int v[2];
-
- glBegin(GL_LINE_STRIP);
- v[0] = x1; v[1] = y1;
- glVertex2iv(v);
- v[0] = x2; v[1] = y2;
- glVertex2iv(v);
+ glBegin(GL_LINES);
+ glVertex2i(x1, y1);
+ glVertex2i(x2, y2);
glEnd();
}
@@ -247,13 +143,9 @@ void sdrawline(int x1, int y1, int x2, int y2)
static void sdrawtripoints(int x1, int y1, int x2, int y2)
{
- int v[2];
- v[0] = x1; v[1] = y1;
- glVertex2iv(v);
- v[0] = x1; v[1] = y2;
- glVertex2iv(v);
- v[0] = x2; v[1] = y1;
- glVertex2iv(v);
+ glVertex2i(x1, y1);
+ glVertex2i(x1, y2);
+ glVertex2i(x2, y1);
}
void sdrawtri(int x1, int y1, int x2, int y2)
@@ -273,20 +165,12 @@ void sdrawtrifill(int x1, int y1, int x2, int y2)
void sdrawbox(int x1, int y1, int x2, int y2)
{
- int v[2];
-
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINE_LOOP);
- v[0] = x1; v[1] = y1;
- glVertex2iv(v);
- v[0] = x1; v[1] = y2;
- glVertex2iv(v);
- v[0] = x2; v[1] = y2;
- glVertex2iv(v);
- v[0] = x2; v[1] = y1;
- glVertex2iv(v);
- v[0] = x1; v[1] = y1;
- glVertex2iv(v);
+ glVertex2i(x1, y1);
+ glVertex2i(x1, y2);
+ glVertex2i(x2, y2);
+ glVertex2i(x2, y1);
glEnd();
}
@@ -436,13 +320,6 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments
glEnd();
}
-int glaGetOneInteger(int param)
-{
- GLint i;
- glGetIntegerv(param, &i);
- return i;
-}
-
float glaGetOneFloat(int param)
{
GLfloat v;
@@ -474,9 +351,6 @@ static int get_cached_work_texture(int *r_w, int *r_h)
static int tex_h = 256;
if (texid == -1) {
- GLint ltexid = glaGetOneInteger(GL_TEXTURE_2D);
- unsigned char *tbuf;
-
glGenTextures(1, (GLuint *)&texid);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -484,11 +358,9 @@ static int get_cached_work_texture(int *r_w, int *r_h)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- tbuf = MEM_callocN(tex_w * tex_h * 4, "tbuf");
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf);
- MEM_freeN(tbuf);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, ltexid);
+ glBindTexture(GL_TEXTURE_2D, 0);
}
*r_w = tex_w;
@@ -501,8 +373,6 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
unsigned char *uc_rect = (unsigned char *) rect;
const float *f_rect = (float *)rect;
float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y);
- int ltexid = glaGetOneInteger(GL_TEXTURE_2D);
- int lrowlength = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
int subpart_x, subpart_y, tex_w, tex_h;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
int texid = get_cached_work_texture(&tex_w, &tex_h);
@@ -511,7 +381,6 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
/* Specify the color outside this function, and tex will modulate it.
* This is useful for changing alpha without using glPixelTransferf()
*/
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -520,9 +389,10 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter);
-#ifdef __APPLE__
+#if defined(__APPLE__) && 0
+ /* [merwin] disable this workaround and see if anyone is affected. If not scrap it! Also at end of this function */
/* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */
- glPixelZoom(1.f, 1.f);
+ glPixelZoom(1.0f, 1.0f);
#endif
/* setup seamless 2=on, 0=off */
@@ -538,7 +408,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
components = 4;
else if (format == GL_RGB)
components = 3;
- else if (ELEM(format, GL_LUMINANCE, GL_ALPHA))
+ else if (ELEM(format, GL_LUMINANCE, GL_ALPHA))
components = 1;
else {
BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled");
@@ -557,7 +427,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
}
else {
- /* switch to 8bit RGBA for byte buffer */
+ /* switch to 8bit RGBA for byte buffer */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
}
@@ -574,14 +444,14 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
float rast_x = x + subpart_x * offset_x * xzoom;
float rast_y = y + subpart_y * offset_y * yzoom;
- /* check if we already got these because we always get 2 more when doing seamless*/
+ /* check if we already got these because we always get 2 more when doing seamless */
if (subpart_w <= seamless || subpart_h <= seamless)
continue;
if (type == GL_FLOAT) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]);
- /* add an extra border of pixels so linear looks ok at edges of full image. */
+ /* add an extra border of pixels so linear looks ok at edges of full image */
if (subpart_w < tex_w)
glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
if (subpart_h < tex_h)
@@ -600,7 +470,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]);
}
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glBegin(GL_QUADS);
glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
@@ -614,15 +484,14 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format,
glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
glEnd();
- glDisable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
}
- glBindTexture(GL_TEXTURE_2D, ltexid);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-#ifdef __APPLE__
+#if defined(__APPLE__) && 0
/* workaround for os x 10.5/10.6 driver bug (above) */
glPixelZoom(xzoom, yzoom);
#endif
@@ -676,8 +545,6 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom));
if (draw_w > 0 && draw_h > 0) {
- int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
-
/* Don't use safe RasterPos (slower) if we can avoid it. */
if (rast_x >= 0 && rast_y >= 0) {
glRasterPos2f(rast_x, rast_y);
@@ -708,7 +575,7 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo
}
}
- glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
}
@@ -863,101 +730,6 @@ void glaEnd2DDraw(gla2DDrawInfo *di)
}
#endif
-/* **************** GL_POINT hack ************************ */
-
-static int curmode = 0;
-static int pointhack = 0;
-static GLubyte Squaredot[16] = {0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff};
-
-void bglBegin(int mode)
-{
- curmode = mode;
-
- if (mode == GL_POINTS) {
- float value[4];
- glGetFloatv(GL_POINT_SIZE_RANGE, value);
- if (value[1] < 2.0f) {
- glGetFloatv(GL_POINT_SIZE, value);
- pointhack = iroundf(value[0]);
- if (pointhack > 4) pointhack = 4;
- }
- else {
- glBegin(mode);
- }
- }
-}
-
-#if 0 /* UNUSED */
-int bglPointHack(void)
-{
- float value[4];
- int pointhack_px;
- glGetFloatv(GL_POINT_SIZE_RANGE, value);
- if (value[1] < 2.0f) {
- glGetFloatv(GL_POINT_SIZE, value);
- pointhack_px = floorf(value[0] + 0.5f);
- if (pointhack_px > 4) pointhack_px = 4;
- return pointhack_px;
- }
- return 0;
-}
-#endif
-
-void bglVertex3fv(const float vec[3])
-{
- switch (curmode) {
- case GL_POINTS:
- if (pointhack) {
- glRasterPos3fv(vec);
- glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
- }
- else {
- glVertex3fv(vec);
- }
- break;
- }
-}
-
-void bglVertex3f(float x, float y, float z)
-{
- switch (curmode) {
- case GL_POINTS:
- if (pointhack) {
- glRasterPos3f(x, y, z);
- glBitmap(pointhack, pointhack, (float)pointhack / 2.0f, (float)pointhack / 2.0f, 0.0, 0.0, Squaredot);
- }
- else {
- glVertex3f(x, y, z);
- }
- break;
- }
-}
-
-void bglVertex2fv(const float vec[2])
-{
- switch (curmode) {
- case GL_POINTS:
- if (pointhack) {
- glRasterPos2fv(vec);
- glBitmap(pointhack, pointhack, (float)pointhack / 2, pointhack / 2, 0.0, 0.0, Squaredot);
- }
- else {
- glVertex2fv(vec);
- }
- break;
- }
-}
-
-
-void bglEnd(void)
-{
- if (pointhack) pointhack = 0;
- else glEnd();
-
-}
/* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
void bgl_get_mats(bglMats *mats)
@@ -993,7 +765,7 @@ void bgl_get_mats(bglMats *mats)
*/
void bglPolygonOffset(float viewdist, float dist)
{
- static float winmat[16], offset = 0.0;
+ static float winmat[16], offset = 0.0f;
if (dist != 0.0f) {
float offs;
@@ -1034,7 +806,6 @@ void bglPolygonOffset(float viewdist, float dist)
glMatrixMode(GL_MODELVIEW);
}
else {
-
glMatrixMode(GL_PROJECTION);
winmat[14] += offset;
offset = 0.0;
@@ -1043,17 +814,6 @@ void bglPolygonOffset(float viewdist, float dist)
}
}
-#if 0 /* UNUSED */
-void bglFlush(void)
-{
- glFlush();
-#ifdef __APPLE__
-// if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL))
-// XXX myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
-#endif
-}
-#endif
-
/* **** Color management helper functions for GLSL display/transform ***** */
/* Draw given image buffer on a screen using GLSL for display transform */
@@ -1096,7 +856,6 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
}
if (ok) {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(1.0, 1.0, 1.0, 1.0);
if (ibuf->rect_float) {
@@ -1134,8 +893,7 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle);
if (display_buffer)
- glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
- zoomfilter, display_buffer);
+ glaDrawPixelsAuto(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, display_buffer);
IMB_display_buffer_release(cache_handle);
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 87c0ce398e5..f61ad348501 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -75,6 +75,7 @@ static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx)
const char *screen_context_dir[] = {
"scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases",
"selected_objects", "selected_bases",
+ "editable_objects", "editable_bases",
"selected_editable_objects", "selected_editable_bases",
"visible_bones", "editable_bones", "selected_bones", "selected_editable_bones",
"visible_pose_bones", "selected_pose_bones", "active_bone", "active_pose_bone",
@@ -179,6 +180,24 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
+ else if (CTX_data_equals(member, "editable_objects") || CTX_data_equals(member, "editable_bases")) {
+ const unsigned int lay = context_layers(sc, scene, sa);
+ int editable_objects = CTX_data_equals(member, "editable_objects");
+
+ /* Visible + Editable, but not necessarily selected */
+ for (base = scene->base.first; base; base = base->next) {
+ if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) {
+ if (0 == BKE_object_is_libdata(base->object)) {
+ if (editable_objects)
+ CTX_data_id_list_add(result, &base->object->id);
+ else
+ CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base);
+ }
+ }
+ }
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
else if (CTX_data_equals(member, "visible_bones") || CTX_data_equals(member, "editable_bones")) {
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *ebone, *flipbone = NULL;
@@ -492,7 +511,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
+ if (gpencil_layer_is_editable(gpl)) {
CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
}
}
@@ -508,7 +527,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPDlayer *gpl;
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 && (gpl->actframe)) {
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 1a1cc8894e6..23c6aa37a83 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -42,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -992,65 +993,56 @@ static void draw_join_shape(ScrArea *sa, char dir)
static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
{
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
glColor4ub(0, 0, 0, 50);
draw_join_shape(sa, dir);
- glDisable(GL_BLEND);
}
/* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir))
{
glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
- glEnable(GL_BLEND);
/* value 181 was hardly computed: 181~105 */
glColor4ub(255, 255, 255, 50);
/* draw_join_shape(sa, dir); */
glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
- glDisable(GL_BLEND);
}
-static void drawscredge_area_draw(int sizex, int sizey, int x1, int y1, int x2, int y2, int a)
+static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2)
{
/* right border area */
- if (x2 < sizex - 1)
- sdrawline(x2 + a, y1, x2 + a, y2);
-
+ if (x2 < sizex - 1) {
+ glVertex2s(x2, y1);
+ glVertex2s(x2, y2);
+ }
+
/* left border area */
- if (x1 > 0) /* otherwise it draws the emboss of window over */
- sdrawline(x1 + a, y1, x1 + a, y2);
-
+ if (x1 > 0) { /* otherwise it draws the emboss of window over */
+ glVertex2s(x1, y1);
+ glVertex2s(x1, y2);
+ }
+
/* top border area */
- if (y2 < sizey - 1)
- sdrawline(x1, y2 + a, x2, y2 + a);
-
+ if (y2 < sizey - 1) {
+ glVertex2s(x1, y2);
+ glVertex2s(x2, y2);
+ }
+
/* bottom border area */
- if (y1 > 0)
- sdrawline(x1, y1 + a, x2, y1 + a);
-
+ if (y1 > 0) {
+ glVertex2s(x1, y1);
+ glVertex2s(x2, y1);
+ }
}
/** screen edges drawing **/
-static void drawscredge_area(ScrArea *sa, int sizex, int sizey, int center)
+static void drawscredge_area(ScrArea *sa, int sizex, int sizey)
{
short x1 = sa->v1->vec.x;
short y1 = sa->v1->vec.y;
short x2 = sa->v3->vec.x;
short y2 = sa->v3->vec.y;
- if (center == 0) {
- if (U.pixelsize > 1.0f) {
-
- glColor3ub(0x50, 0x50, 0x50);
- glLineWidth((2.0f * U.pixelsize) - 1);
- drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, 0);
- glLineWidth(1.0f);
- }
- }
- else {
- glColor3ub(0, 0, 0);
- drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, 0);
- }
+ drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2);
}
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
@@ -1072,17 +1064,11 @@ bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
/* screen sets cursor based on swinid */
static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
{
- ScrArea *sa = win->screen->areabase.first;
-
- for (; sa; sa = sa->next) {
- ARegion *ar = sa->regionbase.first;
- for (; ar; ar = ar->next) {
+ for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
if (ar->swinid == swinid) {
if (swin_changed || (ar->type && ar->type->event_cursor)) {
- if (ar->type && ar->type->cursor)
- ar->type->cursor(win, sa, ar);
- else
- WM_cursor_set(win, CURSOR_STD);
+ ED_region_cursor_set(win, sa, ar);
}
return;
}
@@ -1124,23 +1110,37 @@ void ED_screen_draw(wmWindow *win)
ScrArea *sa1 = NULL;
ScrArea *sa2 = NULL;
ScrArea *sa3 = NULL;
- int dir = -1;
- int dira = -1;
wmSubWindowSet(win, win->screen->mainwin);
+ /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */
+ if (U.pixelsize > 1.0f) {
+ /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */
+ glLineWidth((2.0f * U.pixelsize) - 1);
+ glColor3ub(0x50, 0x50, 0x50);
+ glBegin(GL_LINES);
+ for (sa = win->screen->areabase.first; sa; sa = sa->next)
+ drawscredge_area(sa, winsize_x, winsize_y);
+ glEnd();
+ }
+
+ glLineWidth(1);
+ glColor3ub(0, 0, 0);
+ glBegin(GL_LINES);
for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_area(sa, winsize_x, winsize_y);
+
+ /* gather area split/join info */
if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
if (sa->flag & (AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V)) sa3 = sa;
- drawscredge_area(sa, winsize_x, winsize_y, 0);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
- drawscredge_area(sa, winsize_x, winsize_y, 1);
-
+ glEnd();
+
/* blended join arrow */
if (sa1 && sa2) {
- dir = area_getorientation(sa1, sa2);
+ int dir = area_getorientation(sa1, sa2);
+ int dira = -1;
if (dir != -1) {
switch (dir) {
case 0: /* W */
@@ -1161,26 +1161,33 @@ void ED_screen_draw(wmWindow *win)
break;
}
}
+ glEnable(GL_BLEND);
scrarea_draw_shape_dark(sa2, dir);
scrarea_draw_shape_light(sa1, dira);
+ glDisable(GL_BLEND);
}
/* splitpoint */
if (sa3) {
glEnable(GL_BLEND);
+ glBegin(GL_LINES);
glColor4ub(255, 255, 255, 100);
if (sa3->flag & AREA_FLAG_DRAWSPLIT_H) {
- sdrawline(sa3->totrct.xmin, win->eventstate->y, sa3->totrct.xmax, win->eventstate->y);
+ glVertex2s(sa3->totrct.xmin, win->eventstate->y);
+ glVertex2s(sa3->totrct.xmax, win->eventstate->y);
glColor4ub(0, 0, 0, 100);
- sdrawline(sa3->totrct.xmin, win->eventstate->y + 1, sa3->totrct.xmax, win->eventstate->y + 1);
+ glVertex2s(sa3->totrct.xmin, win->eventstate->y + 1);
+ glVertex2s(sa3->totrct.xmax, win->eventstate->y + 1);
}
else {
- sdrawline(win->eventstate->x, sa3->totrct.ymin, win->eventstate->x, sa3->totrct.ymax);
+ glVertex2s(win->eventstate->x, sa3->totrct.ymin);
+ glVertex2s(win->eventstate->x, sa3->totrct.ymax);
glColor4ub(0, 0, 0, 100);
- sdrawline(win->eventstate->x + 1, sa3->totrct.ymin, win->eventstate->x + 1, sa3->totrct.ymax);
+ glVertex2s(win->eventstate->x + 1, sa3->totrct.ymin);
+ glVertex2s(win->eventstate->x + 1, sa3->totrct.ymax);
}
-
+ glEnd();
glDisable(GL_BLEND);
}
@@ -1220,10 +1227,12 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen_test_scale(win->screen, winsize_x, winsize_y);
- if (win->screen->mainwin == 0)
- win->screen->mainwin = wm_subwindow_open(win, &winrct);
- else
- wm_subwindow_position(win, win->screen->mainwin, &winrct);
+ if (win->screen->mainwin == 0) {
+ win->screen->mainwin = wm_subwindow_open(win, &winrct, false);
+ }
+ else {
+ wm_subwindow_position(win, win->screen->mainwin, &winrct, false);
+ }
for (sa = win->screen->areabase.first; sa; sa = sa->next) {
/* set spacetype and region callbacks, calls init() */
@@ -1271,16 +1280,20 @@ void ED_region_exit(bContext *C, ARegion *ar)
CTX_wm_region_set(C, ar);
WM_event_remove_handlers(C, &ar->handlers);
- if (ar->swinid)
+ if (ar->swinid) {
wm_subwindow_close(CTX_wm_window(C), ar->swinid);
- ar->swinid = 0;
+ ar->swinid = 0;
+ }
- if (ar->headerstr)
+ if (ar->headerstr) {
MEM_freeN(ar->headerstr);
- ar->headerstr = NULL;
+ ar->headerstr = NULL;
+ }
- if (ar->regiontimer)
+ if (ar->regiontimer) {
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer);
+ ar->regiontimer = NULL;
+ }
CTX_wm_region_set(C, prevar);
}
@@ -1781,25 +1794,21 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
newsa->flag &= ~AREA_FLAG_TEMP_TYPE;
}
- ED_area_newspace(C, newsa, type);
-
+ ED_area_newspace(C, newsa, type, (newsa->flag & AREA_FLAG_TEMP_TYPE));
+
return newsa;
}
/**
* \a was_prev_temp for the case previous space was a temporary fullscreen as well
*/
-void ED_screen_full_prevspace(bContext *C, ScrArea *sa, const bool was_prev_temp)
+void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
{
BLI_assert(sa->full);
if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
/* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
ED_area_prevspace(C, sa);
- /* only clear if previous space wasn't a temp fullscreen as well */
- if (!was_prev_temp) {
- sa->flag &= ~AREA_FLAG_TEMP_TYPE;
- }
}
else {
ED_screen_restore_temp_type(C, sa);
@@ -1834,7 +1843,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
if (sl->next) {
if (sa->flag & AREA_FLAG_TEMP_TYPE) {
- ED_screen_full_prevspace(C, sa, false);
+ ED_screen_full_prevspace(C, sa);
}
else {
ED_screen_state_toggle(C, win, sa, state);
@@ -1854,6 +1863,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
*/
ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1861,9 +1871,15 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
/* ensure we don't have a button active anymore, can crash when
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
- for (ar = sa->regionbase.first; ar; ar = ar->next)
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
UI_blocklist_free(C, &ar->uiblocks);
+ if (ar->regiontimer) {
+ WM_event_remove_timer(wm, NULL, ar->regiontimer);
+ ar->regiontimer = NULL;
+ }
+ }
+
/* prevent hanging header prints */
ED_area_headerprint(sa, NULL);
}
@@ -1937,7 +1953,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
if (state == SCREENMAXIMIZED) {
/* returns the top small area */
newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
- ED_area_newspace(C, newa, SPACE_INFO);
+ ED_area_newspace(C, newa, SPACE_INFO, false);
/* copy area */
newa = newa->prev;
@@ -2120,8 +2136,6 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
}
}
#endif
-
- //extern void audiostream_scrub(unsigned int frame); /* seqaudio.c */
ED_clip_update_frame(bmain, scene->r.cfra);
@@ -2131,16 +2145,7 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/* this function applies the changes too */
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, layers);
-
- //if ((CFRA > 1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB))
- // audiostream_scrub( CFRA );
-
- /* 3d window, preview */
- //BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
-
- /* all movie/sequence images */
- //BIF_image_update_frame();
-
+
/* composite */
if (scene->use_nodes && scene->nodetree)
ntreeCompositTagAnimated(scene->nodetree);
@@ -2195,7 +2200,7 @@ bool ED_screen_stereo3d_required(bScreen *screen)
/* images should always show in stereo, even if
* the file doesn't have views enabled */
sima = sa->spacedata.first;
- if (sima->image && (sima->image->flag & IMA_IS_STEREO) &&
+ if (sima->image && BKE_image_is_stereo(sima->image) &&
(sima->iuser.flag & IMA_SHOW_STEREO))
{
return true;
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 4a1c1e34414..be421d779eb 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -992,6 +992,11 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
newwin = WM_window_open(C, &rect);
+ if (newwin == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
+ goto finally;
+ }
+
*newwin->stereo3d_format = *win->stereo3d_format;
/* allocs new screen and adds to newly created window, using window size */
@@ -1005,11 +1010,18 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* screen, areas init */
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
-
+
+
+finally:
if (event->type == EVT_ACTIONZONE_AREA)
actionzone_exit(op);
- return OPERATOR_FINISHED;
+ if (newwin) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static void SCREEN_OT_area_dupli(wmOperatorType *ot)
@@ -2192,7 +2204,6 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
bDopeSheet ads = {NULL};
DLRBT_Tree keys;
ActKeyColumn *ak;
@@ -2217,11 +2228,12 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
/* populate tree with keyframe nodes */
scene_to_keylist(&ads, scene, &keys, NULL);
+ gpencil_to_keylist(&ads, scene->gpd, &keys);
- if (ob)
+ if (ob) {
ob_to_keylist(&ads, ob, &keys, NULL);
-
- gpencil_to_keylist(&ads, gpd, &keys);
+ gpencil_to_keylist(&ads, ob->gpd, &keys);
+ }
{
Mask *mask = CTX_data_edit_mask(C);
@@ -3193,8 +3205,8 @@ static int header_exec(bContext *C, wmOperator *UNUSED(op))
static void SCREEN_OT_header(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Header";
- ot->description = "Display header";
+ ot->name = "Toggle Header";
+ ot->description = "Toggle header display";
ot->idname = "SCREEN_OT_header";
/* api callbacks */
@@ -3826,7 +3838,7 @@ static int fullscreen_back_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_screen_full_prevspace(C, sa, false);
+ ED_screen_full_prevspace(C, sa);
return OPERATOR_FINISHED;
}
@@ -3845,7 +3857,7 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
/* *********** show user pref window ****** */
-static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
rcti rect;
@@ -3862,9 +3874,13 @@ static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
rect.ymax = rect.ymin + sizey;
/* changes context! */
- WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
-
- return OPERATOR_FINISHED;
+ if (WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS) != NULL) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
}
@@ -4215,6 +4231,8 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(ED_OT_undo_push);
WM_operatortype_append(ED_OT_redo);
WM_operatortype_append(ED_OT_undo_history);
+
+ WM_operatortype_append(ED_OT_flush_edits);
}
@@ -4286,14 +4304,15 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_area_options", RIGHTMOUSE, KM_PRESS, 0, 0);
-
+
WM_keymap_add_item(keymap, "SCREEN_OT_header", F9KEY, KM_PRESS, KM_ALT, 0);
-
+
/* Header Editing ------------------------------------------------ */
+ /* note: this is only used when the cursor is inside the header */
keymap = WM_keymap_find(keyconf, "Header", 0, 0);
-
+
WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
-
+
/* Screen General ------------------------------------------------ */
keymap = WM_keymap_find(keyconf, "Screen", 0, 0);
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index e23ac1710e3..2dd7400bc37 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -30,6 +30,7 @@
#include <string.h>
+#include <errno.h>
#include "MEM_guardedalloc.h"
@@ -177,6 +178,7 @@ static void screenshot_crop(ImBuf *ibuf, rcti crop)
static int screenshot_exec(bContext *C, wmOperator *op)
{
ScreenshotData *scd = op->customdata;
+ bool ok = false;
if (scd == NULL) {
/* when running exec directly */
@@ -204,14 +206,20 @@ static int screenshot_exec(bContext *C, wmOperator *op)
/* bw screenshot? - users will notice if it fails! */
IMB_color_to_bw(ibuf);
}
- BKE_imbuf_write(ibuf, path, &scd->im_format);
+ if (BKE_imbuf_write(ibuf, path, &scd->im_format)) {
+ ok = true;
+ }
+ else {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
+ }
IMB_freeImBuf(ibuf);
}
}
screenshot_data_free(op);
- return OPERATOR_FINISHED;
+
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -221,7 +229,12 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
return screenshot_exec(C, op);
/* extension is added by 'screenshot_check' after */
- RNA_string_set(op->ptr, "filepath", G.relbase_valid ? G.main->name : "//screen");
+ char filepath[FILE_MAX] = "//screen";
+ if (G.relbase_valid) {
+ BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+ BLI_replace_extension(filepath, sizeof(filepath), ""); /* strip '.blend' */
+ }
+ RNA_string_set(op->ptr, "filepath", filepath);
WM_event_add_fileselect(C, op);
@@ -286,8 +299,9 @@ void SCREEN_OT_screenshot(wmOperatorType *ot)
ot->flag = 0;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "full", 1, "Full Screen",
"Capture the whole window (otherwise only capture the active area)");
}
@@ -354,6 +368,10 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
if (BKE_imtype_is_movie(rd.im_format.imtype)) {
mh = BKE_movie_handle_get(sj->scene->r.im_format.imtype);
+ if (mh == NULL) {
+ printf("Movie format unsupported\n");
+ return;
+ }
sj->movie_ctx = mh->context_create();
sj->movie_handle = mh;
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
deleted file mode 100644
index 52fab472189..00000000000
--- a/source/blender/editors/sculpt_paint/SConscript
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../uvedit',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-if env['OURPLATFORM'] == 'linuxcross':
- if env['WITH_BF_OPENMP']:
- incs += ' ' + env['BF_OPENMP_INC']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), defines=defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index e19756c6a35..e4e9976c10d 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -32,6 +32,7 @@
#include "BLI_math.h"
#include "BLI_rect.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
@@ -59,6 +60,8 @@
#include "ED_view3d.h"
+#include "GPU_basic_shader.h"
+
#include "UI_resources.h"
#include "paint_intern.h"
@@ -66,10 +69,6 @@
* removed eventually (TODO) */
#include "sculpt_intern.h"
-#ifdef _OPENMP
-#include <omp.h>
-#endif
-
/* TODOs:
*
* Some of the cursor drawing code is doing non-draw stuff
@@ -137,6 +136,112 @@ static void make_tex_snap(TexSnapshot *snap, ViewContext *vc, float zoom)
snap->winy = vc->ar->winy;
}
+typedef struct LoadTexData {
+ Brush *br;
+ ViewContext *vc;
+
+ MTex *mtex;
+ GLubyte *buffer;
+ bool col;
+
+ struct ImagePool *pool;
+ int size;
+ float rotation;
+ float radius;
+} LoadTexData;
+
+static void load_tex_task_cb_ex(void *userdata, void *UNUSED(userdata_chunck), const int j, const int thread_id)
+{
+ LoadTexData *data = userdata;
+ Brush *br = data->br;
+ ViewContext *vc = data->vc;
+
+ MTex *mtex = data->mtex;
+ GLubyte *buffer = data->buffer;
+ const bool col = data->col;
+
+ struct ImagePool *pool = data->pool;
+ const int size = data->size;
+ const float rotation = data->rotation;
+ const float radius = data->radius;
+
+ bool convert_to_linear = false;
+ struct ColorSpace *colorspace = NULL;
+
+ if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
+ ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
+ /* For consistency, sampling always returns color in linear space */
+ if (tex_ibuf && tex_ibuf->rect_float == NULL) {
+ convert_to_linear = true;
+ colorspace = tex_ibuf->rect_colorspace;
+ }
+ BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
+ }
+
+ for (int i = 0; i < size; i++) {
+ // largely duplicated from tex_strength
+
+ int index = j * size + i;
+
+ float x = (float)i / size;
+ float y = (float)j / size;
+ float len;
+
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ x *= vc->ar->winx / radius;
+ y *= vc->ar->winy / radius;
+ }
+ else {
+ x = (x - 0.5f) * 2.0f;
+ y = (y - 0.5f) * 2.0f;
+ }
+
+ len = sqrtf(x * x + y * y);
+
+ if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1.0f) {
+ /* it is probably worth optimizing for those cases where the texture is not rotated by skipping the calls to
+ * atan2, sqrtf, sin, and cos. */
+ if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
+ const float angle = atan2f(y, x) + rotation;
+
+ x = len * cosf(angle);
+ y = len * sinf(angle);
+ }
+
+ if (col) {
+ float rgba[4];
+
+ paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
+
+ buffer[index * 4] = rgba[0] * 255;
+ buffer[index * 4 + 1] = rgba[1] * 255;
+ buffer[index * 4 + 2] = rgba[2] * 255;
+ buffer[index * 4 + 3] = rgba[3] * 255;
+ }
+ else {
+ float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
+
+ avg += br->texture_sample_bias;
+
+ /* clamp to avoid precision overflow */
+ CLAMP(avg, 0.0f, 1.0f);
+ buffer[index] = 255 - (GLubyte)(255 * avg);
+ }
+ }
+ else {
+ if (col) {
+ buffer[index * 4] = 0;
+ buffer[index * 4 + 1] = 0;
+ buffer[index * 4 + 2] = 0;
+ buffer[index * 4 + 3] = 0;
+ }
+ else {
+ buffer[index] = 0;
+ }
+ }
+ }
+}
+
static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool primary)
{
bool init;
@@ -147,11 +252,9 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
GLubyte *buffer = NULL;
int size;
- int j;
- int refresh;
- GLenum format = col ? GL_RGBA : GL_ALPHA;
+ bool refresh;
OverlayControlFlags invalid = (primary) ? (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_PRIMARY) :
- (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY);
+ (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY);
target = (primary) ? &primary_snap : &secondary_snap;
@@ -164,13 +267,9 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
if (refresh) {
struct ImagePool *pool = NULL;
- bool convert_to_linear = false;
- struct ColorSpace *colorspace;
/* stencil is rotated later */
- const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ?
- -mtex->rot : 0;
-
- float radius = BKE_brush_size_get(vc->scene, br) * zoom;
+ const float rotation = (mtex->brush_map_mode != MTEX_MAP_MODE_STENCIL) ? -mtex->rot : 0.0f;
+ const float radius = BKE_brush_size_get(vc->scene, br) * zoom;
make_tex_snap(target, vc, zoom);
@@ -189,8 +288,9 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
if (size < target->old_size)
size = target->old_size;
}
- else
+ else {
size = 512;
+ }
if (target->old_size != size) {
if (target->overlay_texture) {
@@ -212,98 +312,12 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
if (mtex->tex && mtex->tex->nodetree)
ntreeTexBeginExecTree(mtex->tex->nodetree); /* has internal flag to detect it only does it once */
-#pragma omp parallel for schedule(static)
- for (j = 0; j < size; j++) {
- int i;
- float y;
- float len;
- int thread_num;
-
-#ifdef _OPENMP
- thread_num = omp_get_thread_num();
-#else
- thread_num = 0;
-#endif
-
- if (mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
- ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
- /* For consistency, sampling always returns color in linear space */
- if (tex_ibuf && tex_ibuf->rect_float == NULL) {
- convert_to_linear = true;
- colorspace = tex_ibuf->rect_colorspace;
- }
- BKE_image_pool_release_ibuf(mtex->tex->ima, tex_ibuf, pool);
- }
-
+ LoadTexData data = {
+ .br = br, .vc = vc, .mtex = mtex, .buffer = buffer, .col = col,
+ .pool = pool, .size = size, .rotation = rotation, .radius = radius,
+ };
- for (i = 0; i < size; i++) {
-
- // largely duplicated from tex_strength
-
- int index = j * size + i;
- float x;
-
- x = (float)i / size;
- y = (float)j / size;
-
- if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- x *= vc->ar->winx / radius;
- y *= vc->ar->winy / radius;
- }
- else {
- x -= 0.5f;
- y -= 0.5f;
-
- x *= 2;
- y *= 2;
- }
-
- len = sqrtf(x * x + y * y);
-
- if (ELEM(mtex->brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL) || len <= 1) {
- /* it is probably worth optimizing for those cases where
- * the texture is not rotated by skipping the calls to
- * atan2, sqrtf, sin, and cos. */
- if (mtex->tex && (rotation > 0.001f || rotation < -0.001f)) {
- const float angle = atan2f(y, x) + rotation;
-
- x = len * cosf(angle);
- y = len * sinf(angle);
- }
-
- if (col) {
- float rgba[4];
-
- paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_num, convert_to_linear, colorspace);
-
- buffer[index * 4] = rgba[0] * 255;
- buffer[index * 4 + 1] = rgba[1] * 255;
- buffer[index * 4 + 2] = rgba[2] * 255;
- buffer[index * 4 + 3] = rgba[3] * 255;
- }
- else {
- float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_num);
-
- avg += br->texture_sample_bias;
-
- /* clamp to avoid precision overflow */
- CLAMP(avg, 0.0f, 1.0f);
- buffer[index] = 255 - (GLubyte)(255 * avg);
- }
- }
- else {
- if (col) {
- buffer[index * 4] = 0;
- buffer[index * 4 + 1] = 0;
- buffer[index * 4 + 2] = 0;
- buffer[index * 4 + 3] = 0;
- }
- else {
- buffer[index] = 0;
- }
- }
- }
- }
+ BLI_task_parallel_range_ex(0, size, &data, NULL, 0, load_tex_task_cb_ex, true, false);
if (mtex->tex && mtex->tex->nodetree)
ntreeTexEndExecTree(mtex->tex->nodetree->execdata);
@@ -321,8 +335,11 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
glBindTexture(GL_TEXTURE_2D, target->overlay_texture);
if (refresh) {
+ GLenum format = col ? GL_RGBA : GL_ALPHA;
+ GLenum internalformat = col ? GL_RGBA8 : GL_ALPHA8;
+
if (!init || (target->old_col != col)) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer);
}
else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, format, GL_UNSIGNED_BYTE, buffer);
@@ -334,9 +351,8 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
target->old_col = col;
}
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -350,6 +366,34 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima
return 1;
}
+static void load_tex_cursor_task_cb(void *userdata, const int j)
+{
+ LoadTexData *data = userdata;
+ Brush *br = data->br;
+
+ GLubyte *buffer = data->buffer;
+
+ const int size = data->size;
+
+ for (int i = 0; i < size; i++) {
+ // largely duplicated from tex_strength
+
+ const int index = j * size + i;
+ const float x = (((float)i / size) - 0.5f) * 2.0f;
+ const float y = (((float)j / size) - 0.5f) * 2.0f;
+ const float len = sqrtf(x * x + y * y);
+
+ if (len <= 1.0f) {
+ float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
+
+ buffer[index] = 255 - (GLubyte)(255 * avg);
+ }
+ else {
+ buffer[index] = 0;
+ }
+ }
+}
+
static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
{
bool init;
@@ -358,10 +402,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
GLubyte *buffer = NULL;
int size;
- int j;
- int refresh;
-
- refresh =
+ const bool refresh =
!cursor_snap.overlay_texture ||
(overlay_flags & PAINT_INVALID_OVERLAY_CURVE) ||
cursor_snap.zoom != zoom;
@@ -401,41 +442,11 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
curvemapping_initialize(br->curve);
-#pragma omp parallel for schedule(static)
- for (j = 0; j < size; j++) {
- int i;
- float y;
- float len;
+ LoadTexData data = {
+ .br = br, .buffer = buffer, .size = size,
+ };
- for (i = 0; i < size; i++) {
-
- // largely duplicated from tex_strength
-
- int index = j * size + i;
- float x;
-
- x = (float)i / size;
- y = (float)j / size;
-
- x -= 0.5f;
- y -= 0.5f;
-
- x *= 2;
- y *= 2;
-
- len = sqrtf(x * x + y * y);
-
- if (len <= 1) {
- float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
-
- buffer[index] = 255 - (GLubyte)(255 * avg);
-
- }
- else {
- buffer[index] = 0;
- }
- }
- }
+ BLI_task_parallel_range(0, size, &data, load_tex_cursor_task_cb, true);
if (!cursor_snap.overlay_texture)
glGenTextures(1, &cursor_snap.overlay_texture);
@@ -448,7 +459,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
if (refresh) {
if (!init) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
}
else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
@@ -458,9 +469,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
MEM_freeN(buffer);
}
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -524,38 +534,44 @@ static int project_brush_radius(ViewContext *vc,
static bool sculpt_get_brush_geometry(
bContext *C, ViewContext *vc,
int x, int y, int *pixel_radius,
- float location[3])
+ float location[3], UnifiedPaintSettings *ups)
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
float mouse[2];
- bool hit;
+ bool hit = false;
mouse[0] = x;
mouse[1] = y;
- if (vc->obact->sculpt && vc->obact->sculpt->pbvh &&
- sculpt_stroke_get_location(C, location, mouse))
- {
+ if (vc->obact->sculpt && vc->obact->sculpt->pbvh) {
+ if (!ups->stroke_active) {
+ hit = sculpt_stroke_get_location(C, location, mouse);
+ }
+ else {
+ hit = ups->last_hit;
+ copy_v3_v3(location, ups->last_location);
+ }
+ }
+
+ if (hit) {
Brush *brush = BKE_paint_brush(paint);
+
*pixel_radius =
- project_brush_radius(vc,
- BKE_brush_unprojected_radius_get(scene, brush),
- location);
+ project_brush_radius(vc,
+ BKE_brush_unprojected_radius_get(scene, brush),
+ location);
if (*pixel_radius == 0)
*pixel_radius = BKE_brush_size_get(scene, brush);
mul_m4_v3(vc->obact->obmat, location);
-
- hit = 1;
}
else {
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
*pixel_radius = BKE_brush_size_get(scene, brush);
- hit = 0;
}
return hit;
@@ -789,6 +805,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
}
glPopAttrib();
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -915,8 +932,6 @@ static void paint_draw_curve_cursor(Brush *brush)
draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
- glLineWidth(1.0);
-
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
glDisableClientState(GL_VERTEX_ARRAY);
@@ -1020,7 +1035,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
bool hit;
/* test if brush is over the mesh */
- hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location);
+ hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
if (BKE_brush_use_locked_size(scene, brush))
BKE_brush_size_set(scene, brush, pixel_radius);
@@ -1049,6 +1064,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
}
/* make lines pretty */
+ glLineWidth(1.0f);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 2f27db835f5..9704db9d035 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -459,7 +459,6 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
Paint *p = BKE_paint_get_active_from_context(C);
Brush *br = p->brush;
PaintCurve *pc;
- PaintCurvePoint *pcp;
int i;
const float loc_fl[2] = {UNPACK2(loc)};
@@ -470,12 +469,13 @@ static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2
paintcurve_undo_begin(C, op, pc);
- pcp = pc->points;
-
if (toggle) {
+ PaintCurvePoint *pcp;
char select = 0;
bool selected = false;
+ pcp = pc->points;
+
for (i = 0; i < pc->tot_points; i++) {
if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
selected = true;
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 2f1d4cd4194..5af6792f10f 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -417,7 +417,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
MEM_freeN(nodes);
/* end undo */
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
/* ensure that edges and faces get hidden as well (not used by
* sculpt but it looks wrong when entering editmode otherwise) */
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index f0c9c023876..a9cd601c9b0 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -564,7 +564,6 @@ BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
MEM_freeN(kernel->wdata);
MEM_freeN(kernel);
return NULL;
- break;
}
return kernel;
@@ -652,7 +651,7 @@ bool paint_use_opacity_masking(Brush *brush)
(brush->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
(brush->imagepaint_tool == PAINT_TOOL_FILL) ||
(brush->flag & BRUSH_USE_GRADIENT) ||
- (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ?
+ (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ?
false : true;
}
@@ -728,7 +727,6 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
glLineWidth(2.0);
glColor4ub(255, 255, 255, 255);
sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
- glLineWidth(1.0);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
@@ -956,7 +954,6 @@ static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int paint_exec(bContext *C, wmOperator *op)
{
- PaintOperation *pop;
PropertyRNA *strokeprop;
PointerRNA firstpoint;
float mouse[2];
@@ -968,18 +965,12 @@ static int paint_exec(bContext *C, wmOperator *op)
RNA_float_get_array(&firstpoint, "mouse", mouse);
- if (!(pop = texture_paint_init(C, op, mouse))) {
- return OPERATOR_CANCELLED;
- }
-
op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
paint_stroke_update_step,
paint_stroke_redraw,
paint_stroke_done, 0);
/* frees op->customdata */
- paint_stroke_exec(C, op);
-
- return OPERATOR_FINISHED;
+ return paint_stroke_exec(C, op);
}
void PAINT_OT_image_paint(wmOperatorType *ot)
@@ -1201,9 +1192,8 @@ static int sample_color_exec(bContext *C, wmOperator *op)
PaintMode mode = BKE_paintmode_get_active_from_context(C);
ARegion *ar = CTX_wm_region(C);
wmWindow *win = CTX_wm_window(C);
- bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
+ const bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
int location[2];
- bool use_palette;
paint->flags &= ~PAINT_SHOW_BRUSH;
/* force redraw without cursor */
@@ -1211,9 +1201,10 @@ static int sample_color_exec(bContext *C, wmOperator *op)
WM_redraw_windows(C);
RNA_int_get_array(op->ptr, "location", location);
- use_palette = RNA_boolean_get(op->ptr, "palette");
+ const bool use_palette = RNA_boolean_get(op->ptr, "palette");
+ const bool use_sample_texture = (mode == ePaintTextureProjective) && !RNA_boolean_get(op->ptr, "merged");
- paint_sample_color(C, ar, location[0], location[1], mode == ePaintTextureProjective, use_palette);
+ paint_sample_color(C, ar, location[0], location[1], use_sample_texture, use_palette);
if (show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
@@ -1228,7 +1219,6 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
- PaintMode mode = BKE_paintmode_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
ARegion *ar = CTX_wm_region(C);
@@ -1251,7 +1241,10 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, false);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const bool use_sample_texture = (mode == ePaintTextureProjective) && !RNA_boolean_get(op->ptr, "merged");
+
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
@@ -1265,7 +1258,6 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
SampleColorData *data = op->customdata;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
- PaintMode mode = BKE_paintmode_get_active_from_context(C);
if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
ScrArea *sa = CTX_wm_area(C);
@@ -1285,12 +1277,15 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_FINISHED;
}
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const bool use_sample_texture = (mode == ePaintTextureProjective) && !RNA_boolean_get(op->ptr, "merged");
+
switch (event->type) {
case MOUSEMOVE:
{
ARegion *ar = CTX_wm_region(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, false);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
break;
}
@@ -1299,7 +1294,7 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->val == KM_PRESS) {
ARegion *ar = CTX_wm_region(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == ePaintTextureProjective, true);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, true);
if (!data->sample_palette) {
data->sample_palette = true;
sample_color_update_header(data, C);
@@ -1334,8 +1329,13 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384);
- RNA_def_boolean(ot->srna, "palette", 0, "Palette", "Add color to palette");
+ PropertyRNA *prop;
+
+ prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+
+ RNA_def_boolean(ot->srna, "merged", 0, "Sample Merged", "Sample the output display color");
+ RNA_def_boolean(ot->srna, "palette", 0, "Add to Palette", "");
}
/******************** texture paint toggle operator ********************/
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index f1489f2fd10..b8693639673 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -306,6 +306,8 @@ typedef struct ProjPaintState {
/* reproject vars */
Image *reproject_image;
ImBuf *reproject_ibuf;
+ bool reproject_ibuf_free_float;
+ bool reproject_ibuf_free_uchar;
/* threads */
int thread_tot;
@@ -2094,8 +2096,9 @@ static void project_bucket_clip_face(
/* detect pathological case where face the three vertices are almost collinear in screen space.
* mostly those will be culled but when flood filling or with smooth shading it's a possibility */
- if (dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS) < 0.5f ||
- dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS) < 0.5f)
+ if (min_fff(dist_squared_to_line_v2(v1coSS, v2coSS, v3coSS),
+ dist_squared_to_line_v2(v2coSS, v3coSS, v1coSS),
+ dist_squared_to_line_v2(v3coSS, v1coSS, v2coSS)) < PROJ_PIXEL_TOLERANCE)
{
collinear = true;
}
@@ -2989,10 +2992,10 @@ static bool project_bucket_face_isect(ProjPaintState *ps, int bucket_x, int buck
isect_point_tri_v2(p3, v1, v2, v3) ||
isect_point_tri_v2(p4, v1, v2, v3) ||
/* we can avoid testing v3,v1 because another intersection MUST exist if this intersects */
- (isect_line_line_v2(p1, p2, v1, v2) || isect_line_line_v2(p1, p2, v2, v3)) ||
- (isect_line_line_v2(p2, p3, v1, v2) || isect_line_line_v2(p2, p3, v2, v3)) ||
- (isect_line_line_v2(p3, p4, v1, v2) || isect_line_line_v2(p3, p4, v2, v3)) ||
- (isect_line_line_v2(p4, p1, v1, v2) || isect_line_line_v2(p4, p1, v2, v3)))
+ (isect_seg_seg_v2(p1, p2, v1, v2) || isect_seg_seg_v2(p1, p2, v2, v3)) ||
+ (isect_seg_seg_v2(p2, p3, v1, v2) || isect_seg_seg_v2(p2, p3, v2, v3)) ||
+ (isect_seg_seg_v2(p3, p4, v1, v2) || isect_seg_seg_v2(p3, p4, v2, v3)) ||
+ (isect_seg_seg_v2(p4, p1, v1, v2) || isect_seg_seg_v2(p4, p1, v2, v3)))
{
return 1;
}
@@ -3638,7 +3641,7 @@ static void project_paint_build_proj_ima(
projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
- memset(projIma->undoRect, 0, size);
+ memset((void *)projIma->undoRect, 0, size);
projIma->maskRect = BLI_memarena_alloc(arena, size);
memset(projIma->maskRect, 0, size);
projIma->valid = BLI_memarena_alloc(arena, size);
@@ -3913,6 +3916,12 @@ static void project_paint_end(ProjPaintState *ps)
}
}
+ if (ps->reproject_ibuf_free_float) {
+ imb_freerectfloatImBuf(ps->reproject_ibuf);
+ }
+ if (ps->reproject_ibuf_free_uchar) {
+ imb_freerectImBuf(ps->reproject_ibuf);
+ }
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
MEM_freeN(ps->screenCoords);
@@ -3925,10 +3934,10 @@ static void project_paint_end(ProjPaintState *ps)
/* must be set for non-shared */
BLI_assert(ps->dm_mloopuv || ps->is_shared_user);
if (ps->dm_mloopuv)
- MEM_freeN(ps->dm_mloopuv);
+ MEM_freeN((void *)ps->dm_mloopuv);
if (ps->do_layer_clone)
- MEM_freeN(ps->dm_mloopuv_clone);
+ MEM_freeN((void *)ps->dm_mloopuv_clone);
if (ps->thread_tot > 1) {
BLI_spin_end(ps->tile_lock);
MEM_freeN((void *)ps->tile_lock);
@@ -4324,7 +4333,7 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
}
else {
premul_float_to_straight_uchar(rgba_ub, rgba);
- blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask);
+ blend_color_interpolate_byte(rgba_ub, projPixel->pixel.ch_pt, rgba_ub, mask);
}
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
@@ -4599,23 +4608,28 @@ static void *do_projectpaint_thread(void *ph_v)
}
else {
if (is_floatbuf) {
- /* re-project buffer is assumed byte - TODO, allow float */
- bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
+ if (UNLIKELY(ps->reproject_ibuf->rect_float == NULL)) {
+ IMB_float_from_rect(ps->reproject_ibuf);
+ ps->reproject_ibuf_free_float = true;
+ }
+
+ bicubic_interpolation_color(ps->reproject_ibuf, NULL, projPixel->newColor.f,
projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.ch[3]) {
- float newColor_f[4];
+ if (projPixel->newColor.f[3]) {
float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
- straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch);
- IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace);
- mul_v4_v4fl(newColor_f, newColor_f, mask);
+ mul_v4_v4fl(projPixel->newColor.f, projPixel->newColor.f, mask);
blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
- newColor_f);
+ projPixel->newColor.f);
}
}
else {
- /* re-project buffer is assumed byte - TODO, allow float */
+ if (UNLIKELY(ps->reproject_ibuf->rect == NULL)) {
+ IMB_rect_from_float(ps->reproject_ibuf);
+ ps->reproject_ibuf_free_uchar = true;
+ }
+
bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
projPixel->projCoSS[0], projPixel->projCoSS[1]);
if (projPixel->newColor.ch[3]) {
@@ -5280,7 +5294,9 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ps.reproject_image = image;
ps.reproject_ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (ps.reproject_ibuf == NULL || ps.reproject_ibuf->rect == NULL) {
+ if ((ps.reproject_ibuf == NULL) ||
+ ((ps.reproject_ibuf->rect || ps.reproject_ibuf->rect_float) == false))
+ {
BKE_report(op->reports, RPT_ERROR, "Image data could not be found");
return OPERATOR_CANCELLED;
}
@@ -5399,7 +5415,10 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
if (w > maxsize) w = maxsize;
if (h > maxsize) h = maxsize;
- ibuf = ED_view3d_draw_offscreen_imbuf(scene, CTX_wm_view3d(C), CTX_wm_region(C), w, h, IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf(
+ scene, CTX_wm_view3d(C), CTX_wm_region(C),
+ w, h, IB_rect, false, R_ALPHAPREMUL, 0, false, NULL,
+ NULL, NULL, err_out);
if (!ibuf) {
/* Mostly happens when OpenGL offscreen buffer was failed to create, */
/* but could be other reasons. Should be handled in the future. nazgul */
@@ -5727,7 +5746,7 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *
BLI_assert(type != -1);
/* take the second letter to avoid the ID identifier */
- BLI_snprintf(imagename, FILE_MAX, "%s %s", &ma->id.name[2], layer_type_items[type].name);
+ BLI_snprintf(imagename, sizeof(imagename), "%s %s", &ma->id.name[2], layer_type_items[type].name);
RNA_string_set(op->ptr, "name", imagename);
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
@@ -5766,7 +5785,7 @@ void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_float_array_default(prop, default_color);
RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
- RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
+ RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index fd7e053fea3..b6a7d671882 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -184,6 +184,7 @@ void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
/* uv sculpting */
int uv_sculpt_poll(struct bContext *C);
+int uv_sculpt_keymap_poll(struct bContext *C);
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
@@ -233,6 +234,7 @@ int paint_curve_poll(struct bContext *C);
int facemask_paint_poll(struct bContext *C);
void flip_v3_v3(float out[3], const float in[3], const char symm);
+void flip_qt_qt(float out[3], const float in[3], const char symm);
/* stroke operator */
typedef enum BrushStrokeMode {
@@ -247,7 +249,8 @@ typedef enum {
RC_ROTATION = 2,
RC_ZOOM = 4,
RC_WEIGHT = 8,
- RC_SECONDARY_ROTATION = 16
+ RC_SECONDARY_ROTATION = 16,
+ RC_COLOR_OVERRIDE = 32,
} RCFlags;
void set_brush_rc_props(struct PointerRNA *ptr, const char *paint, const char *prop, const char *secondary_prop,
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 118f3a7571f..a47b9a0b936 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -41,6 +41,7 @@
#include "BLI_math_geom.h"
#include "BLI_utildefines.h"
#include "BLI_lasso.h"
+#include "BLI_task.h"
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
@@ -91,6 +92,39 @@ static void mask_flood_fill_set_elem(float *elem,
}
}
+typedef struct MaskTaskData {
+ Object *ob;
+ PBVH *pbvh;
+ PBVHNode **nodes;
+ bool multires;
+
+ PaintMaskFloodMode mode;
+ float value;
+ float (*clip_planes_final)[4];
+} MaskTaskData;
+
+static void mask_flood_fill_task_cb(void *userdata, const int i)
+{
+ MaskTaskData *data = userdata;
+
+ PBVHNode *node = data->nodes[i];
+
+ const PaintMaskFloodMode mode = data->mode;
+ const float value = data->value;
+
+ PBVHVertexIter vi;
+
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
+ mask_flood_fill_set_elem(vi.mask, mode, value);
+ } BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_redraw(node);
+ if (data->multires)
+ BKE_pbvh_node_mark_normals_update(node);
+}
+
static int mask_flood_fill_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
@@ -100,7 +134,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
float value;
PBVH *pbvh;
PBVHNode **nodes;
- int totnode, i;
+ int totnode;
bool multires;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -115,25 +149,19 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
sculpt_undo_push_begin("Mask flood fill");
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (i = 0; i < totnode; i++) {
- PBVHVertexIter vi;
-
- sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ MaskTaskData data = {
+ .ob = ob, .pbvh = pbvh, .nodes = nodes, .multires = multires,
+ .mode = mode, .value = value,
+ };
- BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) {
- mask_flood_fill_set_elem(vi.mask, mode, value);
- } BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_redraw(nodes[i]);
- if (multires)
- BKE_pbvh_node_mark_normals_update(nodes[i]);
- }
+ BLI_task_parallel_range(
+ 0, totnode, &data, mask_flood_fill_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
if (multires)
multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
if (nodes)
MEM_freeN(nodes);
@@ -189,6 +217,35 @@ static void flip_plane(float out[4], const float in[4], const char symm)
out[3] = in[3];
}
+static void mask_box_select_task_cb(void *userdata, const int i)
+{
+ MaskTaskData *data = userdata;
+
+ PBVHNode *node = data->nodes[i];
+
+ const PaintMaskFloodMode mode = data->mode;
+ const float value = data->value;
+ float (*clip_planes_final)[4] = data->clip_planes_final;
+
+ PBVHVertexIter vi;
+ bool any_masked = false;
+
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
+ if (is_effected(clip_planes_final, vi.co)) {
+ if (!any_masked) {
+ any_masked = true;
+
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+
+ BKE_pbvh_node_mark_redraw(node);
+ if (data->multires)
+ BKE_pbvh_node_mark_normals_update(node);
+ }
+ mask_flood_fill_set_elem(vi.mask, mode, value);
+ }
+ } BKE_pbvh_vertex_iter_end;
+}
+
int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select, bool UNUSED(extend))
{
Sculpt *sd = vc->scene->toolsettings->sculpt;
@@ -204,7 +261,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
bool multires;
PBVH *pbvh;
PBVHNode **nodes;
- int totnode, i, symmpass;
+ int totnode, symmpass;
int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
mode = PAINT_MASK_FLOOD_VALUE;
@@ -236,26 +293,14 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (i = 0; i < totnode; i++) {
- PBVHVertexIter vi;
- bool any_masked = false;
-
- BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) {
- if (is_effected(clip_planes_final, vi.co)) {
- if (!any_masked) {
- any_masked = true;
-
- sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
-
- BKE_pbvh_node_mark_redraw(nodes[i]);
- if (multires)
- BKE_pbvh_node_mark_normals_update(nodes[i]);
- }
- mask_flood_fill_set_elem(vi.mask, mode, value);
- }
- } BKE_pbvh_vertex_iter_end;
- }
+ MaskTaskData data = {
+ .ob = ob, .pbvh = pbvh, .nodes = nodes, .multires = multires,
+ .mode = mode, .value = value, .clip_planes_final = clip_planes_final,
+ };
+
+ BLI_task_parallel_range(
+ 0, totnode, &data, mask_box_select_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
if (nodes)
MEM_freeN(nodes);
@@ -265,7 +310,7 @@ int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *r
if (multires)
multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
ED_region_tag_redraw(ar);
@@ -281,6 +326,8 @@ typedef struct LassoMaskData {
int width;
rcti rect; /* bounding box for scanfilling */
int symmpass;
+
+ MaskTaskData task_data;
} LassoMaskData;
@@ -315,10 +362,44 @@ static bool is_effected_lasso(LassoMaskData *data, float co[3])
return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]);
}
-static void mask_lasso_px_cb(int x, int y, void *user_data)
+static void mask_lasso_px_cb(int x, int x_end, int y, void *user_data)
+{
+ LassoMaskData *data = user_data;
+ int index = (y * data->width) + x;
+ int index_end = (y * data->width) + x_end;
+ do {
+ BLI_BITMAP_ENABLE(data->px, index);
+ } while (++index != index_end);
+}
+
+static void mask_gesture_lasso_task_cb(void *userdata, const int i)
{
- struct LassoMaskData *data = user_data;
- BLI_BITMAP_ENABLE(data->px, (y * data->width) + x);
+ LassoMaskData *lasso_data = userdata;
+ MaskTaskData *data = &lasso_data->task_data;
+
+ PBVHNode *node = data->nodes[i];
+
+ const PaintMaskFloodMode mode = data->mode;
+ const float value = data->value;
+
+ PBVHVertexIter vi;
+ bool any_masked = false;
+
+ BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) {
+ if (is_effected_lasso(lasso_data, vi.co)) {
+ if (!any_masked) {
+ any_masked = true;
+
+ sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
+
+ BKE_pbvh_node_mark_redraw(node);
+ if (data->multires)
+ BKE_pbvh_node_mark_normals_update(node);
+ }
+
+ mask_flood_fill_set_elem(vi.mask, mode, value);
+ }
+ } BKE_pbvh_vertex_iter_end;
}
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
@@ -338,7 +419,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
PBVH *pbvh;
PBVHNode **nodes;
- int totnode, i, symmpass;
+ int totnode, symmpass;
bool multires;
PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode");
float value = RNA_float_get(op->ptr, "value");
@@ -390,27 +471,16 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle (should greatly help with bigger meshes) */
BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (i = 0; i < totnode; i++) {
- PBVHVertexIter vi;
- bool any_masked = false;
-
- BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) {
- if (is_effected_lasso(&data, vi.co)) {
- if (!any_masked) {
- any_masked = true;
+ data.task_data.ob = ob;
+ data.task_data.pbvh = pbvh;
+ data.task_data.nodes = nodes;
+ data.task_data.multires = multires;
+ data.task_data.mode = mode;
+ data.task_data.value = value;
- sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
-
- BKE_pbvh_node_mark_redraw(nodes[i]);
- if (multires)
- BKE_pbvh_node_mark_normals_update(nodes[i]);
- }
-
- mask_flood_fill_set_elem(vi.mask, mode, value);
- }
- } BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range(
+ 0, totnode, &data, mask_gesture_lasso_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT)));
if (nodes)
MEM_freeN(nodes);
@@ -420,7 +490,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
if (multires)
multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
ED_region_tag_redraw(vc.ar);
MEM_freeN((void *)mcords);
@@ -439,7 +509,7 @@ void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
ot->name = "Mask Lasso Gesture";
ot->idname = "PAINT_OT_mask_lasso_gesture";
- ot->description = "Add mask within the lasso as you move the pointer";
+ ot->description = "Add mask within the lasso as you move the brush";
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 05eda4da63b..da7667c775e 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -407,12 +407,9 @@ static Brush *brush_tool_toggle(Main *bmain, Brush *brush_orig, const int tool,
return br;
}
- else if (brush_orig->toggle_brush &&
- BLI_findindex(bmain->brush.first, brush_orig->toggle_brush) != -1)
- {
+ else if (brush_orig->toggle_brush) {
/* if current brush is using the desired tool, try to toggle
- * back to the previously selected brush (if it was set, and
- * if it still exists) */
+ * back to the previously selected brush. */
return brush_orig->toggle_brush;
}
else
@@ -479,26 +476,26 @@ static int brush_select_exec(bContext *C, wmOperator *op)
paint = &toolsettings->sculpt->paint;
tool_offset = offsetof(Brush, sculpt_tool);
tool = RNA_enum_get(op->ptr, "sculpt_tool");
- RNA_enum_name_from_value(brush_sculpt_tool_items, tool, &tool_name);
+ RNA_enum_name_from_value(rna_enum_brush_sculpt_tool_items, tool, &tool_name);
break;
case OB_MODE_VERTEX_PAINT:
paint = &toolsettings->vpaint->paint;
tool_offset = offsetof(Brush, vertexpaint_tool);
tool = RNA_enum_get(op->ptr, "vertex_paint_tool");
- RNA_enum_name_from_value(brush_vertex_tool_items, tool, &tool_name);
+ RNA_enum_name_from_value(rna_enum_brush_vertex_tool_items, tool, &tool_name);
break;
case OB_MODE_WEIGHT_PAINT:
paint = &toolsettings->wpaint->paint;
/* vertexpaint_tool is used for weight paint mode */
tool_offset = offsetof(Brush, vertexpaint_tool);
tool = RNA_enum_get(op->ptr, "weight_paint_tool");
- RNA_enum_name_from_value(brush_vertex_tool_items, tool, &tool_name);
+ RNA_enum_name_from_value(rna_enum_brush_vertex_tool_items, tool, &tool_name);
break;
case OB_MODE_TEXTURE_PAINT:
paint = &toolsettings->imapaint.paint;
tool_offset = offsetof(Brush, imagepaint_tool);
tool = RNA_enum_get(op->ptr, "texture_paint_tool");
- RNA_enum_name_from_value(brush_image_tool_items, tool, &tool_name);
+ RNA_enum_name_from_value(rna_enum_brush_image_tool_items, tool, &tool_name);
break;
default:
/* invalid paint mode */
@@ -535,10 +532,10 @@ static void PAINT_OT_brush_select(wmOperatorType *ot)
/* props */
RNA_def_enum(ot->srna, "paint_mode", paint_mode_items, OB_MODE_ACTIVE, "Paint Mode", "");
- RNA_def_enum(ot->srna, "sculpt_tool", brush_sculpt_tool_items, 0, "Sculpt Tool", "");
- RNA_def_enum(ot->srna, "vertex_paint_tool", brush_vertex_tool_items, 0, "Vertex Paint Tool", "");
- RNA_def_enum(ot->srna, "weight_paint_tool", brush_vertex_tool_items, 0, "Weight Paint Tool", "");
- RNA_def_enum(ot->srna, "texture_paint_tool", brush_image_tool_items, 0, "Texture Paint Tool", "");
+ RNA_def_enum(ot->srna, "sculpt_tool", rna_enum_brush_sculpt_tool_items, 0, "Sculpt Tool", "");
+ RNA_def_enum(ot->srna, "vertex_paint_tool", rna_enum_brush_vertex_tool_items, 0, "Vertex Paint Tool", "");
+ RNA_def_enum(ot->srna, "weight_paint_tool", rna_enum_brush_vertex_tool_items, 0, "Weight Paint Tool", "");
+ RNA_def_enum(ot->srna, "texture_paint_tool", rna_enum_brush_image_tool_items, 0, "Texture Paint Tool", "");
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle between two brushes rather than cycling");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
@@ -1190,19 +1187,28 @@ void set_brush_rc_props(PointerRNA *ptr, const char *paint,
set_brush_rc_path(ptr, brush_path, "rotation_path", "texture_slot.angle");
RNA_string_set(ptr, "image_id", brush_path);
- if (flags & RC_COLOR)
+ if (flags & RC_COLOR) {
set_brush_rc_path(ptr, brush_path, "fill_color_path", "color");
- else
+ }
+ else {
RNA_string_set(ptr, "fill_color_path", "");
+ }
+
+ if (flags & RC_COLOR_OVERRIDE) {
+ RNA_string_set(ptr, "fill_color_override_path", "tool_settings.unified_paint_settings.color");
+ RNA_string_set(ptr, "fill_color_override_test_path", "tool_settings.unified_paint_settings.use_unified_color");
+ }
+ else {
+ RNA_string_set(ptr, "fill_color_override_path", "");
+ RNA_string_set(ptr, "fill_color_override_test_path", "");
+ }
+
if (flags & RC_ZOOM)
RNA_string_set(ptr, "zoom_path", "space_data.zoom");
else
RNA_string_set(ptr, "zoom_path", "");
- if (flags & RC_SECONDARY_ROTATION)
- RNA_boolean_set(ptr, "secondary_tex", true);
- else
- RNA_boolean_set(ptr, "secondary_tex", false);
+ RNA_boolean_set(ptr, "secondary_tex", (flags & RC_SECONDARY_ROTATION) != 0);
MEM_freeN(brush_path);
}
@@ -1270,6 +1276,7 @@ static void paint_keymap_curve(wmKeyMap *keymap)
WM_keymap_add_item(keymap, "PAINTCURVE_OT_cursor", ACTIONMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", XKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", RETKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", PADENTER, KM_PRESS, 0, 0);
@@ -1375,7 +1382,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_paint_brush_switch(keymap, "vertex_paint");
ed_keymap_paint_brush_size(keymap, "tool_settings.vertex_paint.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR | RC_ROTATION);
+ ed_keymap_paint_brush_radial_control(keymap, "vertex_paint", RC_COLOR | RC_COLOR_OVERRIDE | RC_ROTATION);
ed_keymap_stencil(keymap);
@@ -1451,7 +1458,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_paint_brush_switch(keymap, "image_paint");
ed_keymap_paint_brush_size(keymap, "tool_settings.image_paint.brush.size");
- ed_keymap_paint_brush_radial_control(keymap, "image_paint", RC_COLOR | RC_ZOOM | RC_ROTATION | RC_SECONDARY_ROTATION);
+ ed_keymap_paint_brush_radial_control(
+ keymap, "image_paint",
+ RC_COLOR | RC_COLOR_OVERRIDE | RC_ZOOM | RC_ROTATION | RC_SECONDARY_ROTATION);
ed_keymap_stencil(keymap);
@@ -1487,7 +1496,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "deselect", true);
keymap = WM_keymap_find(keyconf, "UV Sculpt", 0, 0);
- keymap->poll = uv_sculpt_poll;
+ keymap->poll = uv_sculpt_keymap_poll;
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt");
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index b1ddf1172c8..65857cccb15 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -68,7 +68,7 @@
#include <float.h>
#include <math.h>
-#define DEBUG_TIME
+//#define DEBUG_TIME
#ifdef DEBUG_TIME
# include "PIL_time_utildefines.h"
@@ -466,7 +466,10 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
copy_v2_v2(mouse_out, mouse_in);
}
- if (!paint_brush_update(C, brush, mode, stroke, mouse_in, mouse_out, pressure, location)) {
+
+ ups->last_hit = paint_brush_update(C, brush, mode, stroke, mouse_in, mouse_out, pressure, location);
+ copy_v3_v3(ups->last_location, location);
+ if (!ups->last_hit) {
return;
}
@@ -870,8 +873,7 @@ static void paint_stroke_add_sample(const Paint *paint,
float x, float y, float pressure)
{
PaintSample *sample = &stroke->samples[stroke->cur_sample];
- int max_samples = MIN2(PAINT_MAX_INPUT_SAMPLES,
- MAX2(paint->num_input_samples, 1));
+ int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
sample->mouse[0] = x;
sample->mouse[1] = y;
@@ -981,7 +983,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
return true;
#ifdef DEBUG_TIME
- TIMEIT_START(stroke);
+ TIMEIT_START_AVERAGED(whole_stroke);
#endif
pcp = pc->points;
@@ -1042,7 +1044,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
stroke_done(C, op);
#ifdef DEBUG_TIME
- TIMEIT_END(stroke);
+ TIMEIT_END_AVERAGED(whole_stroke);
#endif
return true;
@@ -1237,20 +1239,31 @@ int paint_stroke_exec(bContext *C, wmOperator *op)
/* only when executed for the first time */
if (stroke->stroke_started == 0) {
- /* XXX stroke->last_mouse_position is unset, this may cause problems */
- stroke->test_start(C, op, NULL);
- stroke->stroke_started = 1;
+ PropertyRNA *strokeprop;
+ PointerRNA firstpoint;
+ float mouse[2];
+
+ strokeprop = RNA_struct_find_property(op->ptr, "stroke");
+
+ if (RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) {
+ RNA_float_get_array(&firstpoint, "mouse", mouse);
+ stroke->stroke_started = stroke->test_start(C, op, mouse);
+ }
}
- RNA_BEGIN (op->ptr, itemptr, "stroke")
- {
- stroke->update_step(C, stroke, &itemptr);
+ if (stroke->stroke_started) {
+ RNA_BEGIN (op->ptr, itemptr, "stroke")
+ {
+ stroke->update_step(C, stroke, &itemptr);
+ }
+ RNA_END;
}
- RNA_END;
+
+ bool ok = (stroke->stroke_started != 0);
stroke_done(C, op);
- return OPERATOR_FINISHED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void paint_stroke_cancel(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 7b66632fa42..31c471c3517 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -177,7 +177,7 @@ float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool,
float co[3] = {u, v, 0.0f};
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
return intensity;
}
@@ -189,7 +189,7 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct
float intensity;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
if (!hasrgb) {
rgba[0] = intensity;
rgba[1] = intensity;
@@ -397,6 +397,29 @@ void flip_v3_v3(float out[3], const float in[3], const char symm)
out[2] = in[2];
}
+void flip_qt_qt(float out[4], const float in[4], const char symm)
+{
+ float axis[3], angle;
+
+ quat_to_axis_angle(axis, &angle, in);
+ normalize_v3(axis);
+
+ if (symm & PAINT_SYMM_X) {
+ axis[0] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Y) {
+ axis[1] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Z) {
+ axis[2] *= -1.0f;
+ angle *= -1.0f;
+ }
+
+ axis_angle_normalized_to_quat(out, axis, angle);
+}
+
/* used for both 3d view and image window */
void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 8daad9deea9..4d3712c6e3e 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -33,7 +33,9 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_array_utils.h"
#include "BLI_bitmap.h"
+#include "BLI_stack.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -75,6 +77,12 @@
#include "paint_intern.h" /* own include */
+/* small structure to defer applying weight-paint results */
+struct WPaintDefer {
+ int index;
+ float alpha, weight;
+};
+
/* check if we can do partial updates and have them draw realtime
* (without rebuilding the 'derivedFinal') */
static bool vertex_paint_use_fast_update_check(Object *ob)
@@ -91,6 +99,19 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
return false;
}
+static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
+{
+ const int mval_i[2] = {mval[0], mval[1]};
+ float world[3];
+
+ if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, world);
+ ups->last_stroke_valid = true;
+ }
+}
+
/* polling - retrieve whether cursor should be set or operator should be done */
/* Returns true if vertex paint mode is active */
@@ -399,7 +420,7 @@ bool ED_wpaint_fill(VPaint *wp, Object *ob, float paintweight)
dw->weight = paintweight;
if (me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */
- int j = mesh_get_x_mirror_vert(ob, vidx, topology);
+ int j = mesh_get_x_mirror_vert(ob, NULL, vidx, topology);
if (j >= 0) {
/* copy, not paint again */
if (vgroup_mirror != -1) {
@@ -911,7 +932,7 @@ static float wpaint_blend_tool(const int tool,
static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
const float alpha, float paintval,
const float brush_alpha_value,
- const short do_flip, const short do_multipaint_totsel)
+ const short do_flip)
{
Brush *brush = BKE_paint_brush(&wp->paint);
int tool = brush->vertexpaint_tool;
@@ -933,25 +954,20 @@ static float wpaint_blend(VPaint *wp, float weight, float weight_prev,
weight = wpaint_blend_tool(tool, weight, paintval, alpha);
- /* delay clamping until the end so multi-paint can function when the active group is at the limits */
- if (do_multipaint_totsel == false) {
- CLAMP(weight, 0.0f, 1.0f);
- }
+ CLAMP(weight, 0.0f, 1.0f);
/* if no spray, clip result with orig weight & orig alpha */
if ((wp->flag & VP_SPRAY) == 0) {
- if (do_multipaint_totsel == false) {
- float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value);
+ float testw = wpaint_blend_tool(tool, weight_prev, paintval, brush_alpha_value);
- CLAMP(testw, 0.0f, 1.0f);
- if (testw < weight_prev) {
- if (weight < testw) weight = testw;
- else if (weight > weight_prev) weight = weight_prev;
- }
- else {
- if (weight > testw) weight = testw;
- else if (weight < weight_prev) weight = weight_prev;
- }
+ CLAMP(testw, 0.0f, 1.0f);
+ if (testw < weight_prev) {
+ if (weight < testw) weight = testw;
+ else if (weight > weight_prev) weight = weight_prev;
+ }
+ else {
+ if (weight > testw) weight = testw;
+ else if (weight < weight_prev) weight = weight_prev;
}
}
@@ -972,7 +988,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
view3d_set_viewcontext(C, &vc);
me = BKE_mesh_from_object(vc.obact);
- if (me && me->dvert && vc.v3d && vc.rv3d) {
+ if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
int v_idx_best = -1;
unsigned int index;
@@ -1000,6 +1016,29 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *even
Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
const int vgroup_active = vc.obact->actdef - 1;
float vgroup_weight = defvert_find_weight(&me->dvert[v_idx_best], vgroup_active);
+
+ /* use combined weight in multipaint mode, since that's what is displayed to the user in the colors */
+ if (ts->multipaint) {
+ int defbase_tot_sel;
+ const int defbase_tot = BLI_listbase_count(&vc.obact->defbase);
+ bool *defbase_sel = BKE_object_defgroup_selected_get(vc.obact, defbase_tot, &defbase_tot_sel);
+
+ if (defbase_tot_sel > 1) {
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ BKE_object_defgroup_mirror_selection(
+ vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
+ }
+
+ vgroup_weight = BKE_defvert_multipaint_collective_weight(
+ &me->dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, ts->auto_normalize);
+
+ /* if autonormalize is enabled, but weights are not normalized, the value can exceed 1 */
+ CLAMP(vgroup_weight, 0.0f, 1.0f);
+ }
+
+ MEM_freeN(defbase_sel);
+ }
+
BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
changed = true;
}
@@ -1046,7 +1085,8 @@ static bool weight_paint_sample_enum_itemf__helper(const MDeformVert *dvert, con
}
return found;
}
-static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *weight_paint_sample_enum_itemf(
+ bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
if (C) {
wmWindow *win = CTX_wm_window(C);
@@ -1196,42 +1236,67 @@ static void do_weight_paint_normalize_all(MDeformVert *dvert, const int defbase_
}
}
-/* same as function above except it normalizes against the active vgroup which remains unchanged
- *
- * note that the active is just the group which is unchanged, it can be any,
- * can also be -1 to normalize all but in that case call 'do_weight_paint_normalize_all' */
-static void do_weight_paint_normalize_all_active(MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
- const int vgroup_active)
+/**
+ * A version of #do_weight_paint_normalize_all that includes locked weights
+ * but only changes unlocked weights.
+ */
+static bool do_weight_paint_normalize_all_locked(
+ MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
+ const bool *lock_flags)
{
float sum = 0.0f, fac;
+ float sum_unlock = 0.0f;
+ float lock_weight = 0.0f;
unsigned int i, tot = 0;
MDeformWeight *dw;
- float act_weight = 0.0f;
+
+ if (lock_flags == NULL) {
+ do_weight_paint_normalize_all(dvert, defbase_tot, vgroup_validmap);
+ return true;
+ }
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- if (dw->def_nr != vgroup_active) {
- sum += dw->weight;
- tot++;
+ sum += dw->weight;
+
+ if (lock_flags[dw->def_nr]) {
+ lock_weight += dw->weight;
}
else {
- act_weight = dw->weight;
+ tot++;
+ sum_unlock += dw->weight;
}
}
}
- if ((tot == 0) || (sum + act_weight == 1.0f)) {
- return;
+ if (sum == 1.0f) {
+ return true;
}
- if (sum != 0.0f) {
- fac = (1.0f / sum) * (1.0f - act_weight);
+ if (tot == 0) {
+ return false;
+ }
+ if (lock_weight >= 1.0f) {
+ /* locked groups make it impossible to fully normalize,
+ * zero out what we can and return false */
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- if (dw->def_nr != vgroup_active) {
- dw->weight *= fac;
+ if (lock_flags[dw->def_nr] == false) {
+ dw->weight = 0.0f;
+ }
+ }
+ }
+ return (lock_weight == 1.0f);
+ }
+ else if (sum_unlock != 0.0f) {
+ fac = (1.0f - lock_weight) / sum_unlock;
+
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
+ if (lock_flags[dw->def_nr] == false) {
+ dw->weight *= fac;
/* paranoid but possibly with float error */
CLAMP(dw->weight, 0.0f, 1.0f);
}
@@ -1239,55 +1304,48 @@ static void do_weight_paint_normalize_all_active(MDeformVert *dvert, const int d
}
}
else {
- /* corner case where we need to scale all weights evenly because they're all zero */
-
/* hrmf, not a factor in this case */
- fac = (1.0f - act_weight) / tot;
-
+ fac = (1.0f - lock_weight) / tot;
/* paranoid but possibly with float error */
CLAMP(fac, 0.0f, 1.0f);
for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
if (dw->def_nr < defbase_tot && vgroup_validmap[dw->def_nr]) {
- if (dw->def_nr != vgroup_active) {
+ if (lock_flags[dw->def_nr] == false) {
dw->weight = fac;
}
}
}
}
+
+ return true;
}
-/*
- * See if the current deform vertex has a locked group
+/**
+ * \note same as function above except it does a second pass without active group
+ * if nomalize fails with it.
*/
-static bool has_locked_group(MDeformVert *dvert, const int defbase_tot,
- const bool *bone_groups, const bool *lock_flags)
+static void do_weight_paint_normalize_all_locked_try_active(
+ MDeformVert *dvert, const int defbase_tot, const bool *vgroup_validmap,
+ const bool *lock_flags, const bool *lock_with_active)
{
- int i;
- MDeformWeight *dw;
+ /* first pass with both active and explicitly locked groups restricted from change */
- for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot) {
- if (bone_groups[dw->def_nr] && lock_flags[dw->def_nr] && dw->weight > 0.0f) {
- return true;
- }
- }
- }
- return false;
-}
+ bool success = do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_with_active);
-static bool has_locked_group_selected(int defbase_tot, const bool *defbase_sel, const bool *lock_flags)
-{
- int i;
- for (i = 0; i < defbase_tot; i++) {
- if (defbase_sel[i] && lock_flags[i]) {
- return true;
- }
+ if (!success) {
+ /**
+ * Locks prevented the first pass from full completion, so remove restriction on active group; e.g:
+ *
+ * - With 1.0 weight painted into active:
+ * nonzero locked weight; first pass zeroed out unlocked weight; scale 1 down to fit.
+ * - With 0.0 weight painted into active:
+ * no unlocked groups; first pass did nothing; increaze 0 to fit.
+ */
+ do_weight_paint_normalize_all_locked(dvert, defbase_tot, vgroup_validmap, lock_flags);
}
- return false;
}
-
#if 0 /* UNUSED */
static bool has_unselected_unlocked_bone_group(int defbase_tot, bool *defbase_sel, int selected,
const bool *lock_flags, const bool *vgroup_validmap)
@@ -1305,258 +1363,89 @@ static bool has_unselected_unlocked_bone_group(int defbase_tot, bool *defbase_se
}
#endif
-
-static void multipaint_selection(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
+static void multipaint_clamp_change(
+ MDeformVert *dvert, const int defbase_tot, const bool *defbase_sel,
+ float *change_p)
{
int i;
MDeformWeight *dw;
float val;
- /* make sure they are all at most 1 after the change */
- for (i = 0; i < defbase_tot; i++) {
- if (defbase_sel[i]) {
- dw = defvert_find_index(dvert, i);
- if (dw && dw->weight) {
+ float change = *change_p;
+
+ /* verify that the change does not cause values exceeding 1 and clamp it */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
+ if (dw->weight) {
val = dw->weight * change;
if (val > 1) {
- /* TODO: when the change is reduced, you need to recheck
- * the earlier values to make sure they are not 0
- * (precision error) */
change = 1.0f / dw->weight;
}
- /* the value should never reach zero while multi-painting if it
- * was nonzero beforehand */
- if (val <= 0) {
- return;
- }
- }
- }
- }
- /* apply the valid change */
- for (i = 0; i < defbase_tot; i++) {
- if (defbase_sel[i]) {
- dw = defvert_find_index(dvert, i);
- if (dw && dw->weight) {
- dw->weight = dw->weight * change;
}
}
}
+
+ *change_p = change;
}
-/* move all change onto valid, unchanged groups. If there is change left over,
- * then return it.
- * assumes there are valid groups to shift weight onto */
-static float redistribute_change(MDeformVert *ndv, const int defbase_tot,
- char *change_status, const char change_me, int changeto,
- float totchange, float total_valid,
- bool do_auto_normalize)
+static bool multipaint_verify_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
{
- bool changed;
- float change;
- float oldval;
- MDeformWeight *ndw;
int i;
- do {
- /* assume there is no change until you see one */
- changed = false;
- /* change each group by the same amount each time */
- change = totchange / total_valid;
- for (i = 0; i < ndv->totweight && total_valid && totchange; i++) {
- ndw = (ndv->dw + i);
-
- /* ignore anything outside the value range */
- if (ndw->def_nr < defbase_tot) {
-
- /* change only the groups with a valid status */
- if (change_status[ndw->def_nr] == change_me) {
- oldval = ndw->weight;
- /* if auto normalize is active, don't worry about upper bounds */
- if (do_auto_normalize == false && ndw->weight + change > 1) {
- totchange -= 1.0f - ndw->weight;
- ndw->weight = 1.0f;
- /* stop the changes to this group */
- change_status[ndw->def_nr] = changeto;
- total_valid--;
- }
- else if (ndw->weight + change < 0) { /* check the lower bound */
- totchange -= ndw->weight;
- ndw->weight = 0;
- change_status[ndw->def_nr] = changeto;
- total_valid--;
- }
- else { /* a perfectly valid change occurred to ndw->weight */
- totchange -= change;
- ndw->weight += change;
- }
- /* see if there was a change */
- if (oldval != ndw->weight) {
- changed = true;
- }
- }
- }
- }
- /* don't go again if there was no change, if there is no valid group,
- * or there is no change left */
- } while (changed && total_valid && totchange);
- /* left overs */
- return totchange;
-}
-static float get_mp_change(MDeformVert *odv, const int defbase_tot, const bool *defbase_sel, float brush_change);
-/* observe the changes made to the weights of groups.
- * make sure all locked groups on the vertex have the same deformation
- * by moving the changes made to groups onto other unlocked groups */
-static void enforce_locks(MDeformVert *odv, MDeformVert *ndv,
- const int defbase_tot, const bool *defbase_sel,
- const bool *lock_flags, const bool *vgroup_validmap,
- bool do_auto_normalize, bool do_multipaint)
-{
- float totchange = 0.0f;
- float totchange_allowed = 0.0f;
- float left_over;
-
- int total_valid = 0;
- int total_changed = 0;
- unsigned int i;
- MDeformWeight *ndw;
- MDeformWeight *odw;
-
- // float changed_sum = 0.0f; // UNUSED
-
- char *change_status;
-
- if (!lock_flags || !has_locked_group(ndv, defbase_tot, vgroup_validmap, lock_flags)) {
- return;
- }
- /* record if a group was changed, unlocked and not changed, or locked */
- change_status = MEM_callocN(sizeof(char) * defbase_tot, "unlocked_unchanged");
+ MDeformWeight *dw;
+ float val;
- for (i = 0; i < defbase_tot; i++) {
- ndw = defvert_find_index(ndv, i);
- odw = defvert_find_index(odv, i);
- /* the weights are zero, so we can assume a lot */
- if (!ndw || !odw) {
- if (!lock_flags[i] && vgroup_validmap[i]) {
- defvert_verify_index(odv, i);
- defvert_verify_index(ndv, i);
- total_valid++;
- change_status[i] = 1; /* can be altered while redistributing */
- }
- continue;
- }
- /* locked groups should not be changed */
- if (lock_flags[i]) {
- ndw->weight = odw->weight;
- }
- else if (ndw->weight != odw->weight) { /* changed groups are handled here */
- totchange += ndw->weight - odw->weight;
- // changed_sum += ndw->weight; // UNUSED
- change_status[i] = 2; /* was altered already */
- total_changed++;
- } /* unchanged, unlocked bone groups are handled here */
- else if (vgroup_validmap[i]) {
- totchange_allowed += ndw->weight;
- total_valid++;
- change_status[i] = 1; /* can be altered while redistributing */
- }
- }
- /* if there was any change, and somewhere to redistribute it, do it */
- if (total_changed && total_valid) {
- /* auto normalize will allow weights to temporarily go above 1 in redistribution */
- if (vgroup_validmap && total_changed < 0 && total_valid) {
- totchange_allowed = total_valid;
- }
- /* the way you modify the unlocked + unchanged groups is different depending
- * on whether or not you are painting the weight(s) up or down */
- if (totchange < 0) {
- totchange_allowed = total_valid - totchange_allowed;
- }
- else {
- totchange_allowed *= -1;
- }
- /* there needs to be change allowed, or you should not bother */
- if (totchange_allowed) {
- left_over = 0;
- if (fabsf(totchange_allowed) < fabsf(totchange)) {
- /* this amount goes back onto the changed, unlocked weights */
- left_over = fabsf(fabsf(totchange) - fabsf(totchange_allowed));
- if (totchange > 0) {
- left_over *= -1;
- }
- }
- else {
- /* all of the change will be permitted */
- totchange_allowed = -totchange;
- }
- /* move the weight evenly between the allowed groups, move excess back onto the used groups based on the change */
- totchange_allowed = redistribute_change(ndv, defbase_tot, change_status, 1, -1, totchange_allowed, total_valid, do_auto_normalize);
- left_over += totchange_allowed;
- if (left_over) {
- /* more than one nonzero weights were changed with the same ratio with multipaint, so keep them changed that way! */
- if (total_changed > 1 && do_multipaint) {
- float undo_change = get_mp_change(ndv, defbase_tot, defbase_sel, left_over);
- multipaint_selection(ndv, defbase_tot, undo_change, defbase_sel);
- }
- /* or designatedw is still -1 put weight back as evenly as possible */
- else {
- redistribute_change(ndv, defbase_tot, change_status, 2, -2, left_over, total_changed, do_auto_normalize);
+ /* in case the change is reduced, you need to recheck
+ * the earlier values to make sure they are not 0
+ * (precision error) */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
+ if (dw->weight) {
+ val = dw->weight * change;
+ /* the value should never reach zero while multi-painting if it
+ * was nonzero beforehand */
+ if (val <= 0) {
+ return false;
}
}
}
- else {
- /* reset the weights */
- MDeformWeight *dw_old = odv->dw;
- MDeformWeight *dw_new = ndv->dw;
-
- for (i = odv->totweight; i != 0; i--, dw_old++, dw_new++) {
- dw_new->weight = dw_old->weight;
- }
- }
}
- MEM_freeN(change_status);
+ return true;
}
-/* multi-paint's initial, potential change is computed here based on the user's stroke */
-static float get_mp_change(MDeformVert *odv, const int defbase_tot, const bool *defbase_sel, float brush_change)
+static void multipaint_apply_change(MDeformVert *dvert, const int defbase_tot, float change, const bool *defbase_sel)
{
- float selwsum = 0.0f;
- unsigned int i;
- MDeformWeight *dw = odv->dw;
+ int i;
+ MDeformWeight *dw;
- for (i = odv->totweight; i != 0; i--, dw++) {
- if (dw->def_nr < defbase_tot) {
- if (defbase_sel[dw->def_nr]) {
- selwsum += dw->weight;
+ /* apply the valid change */
+ for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
+ if (dw->def_nr < defbase_tot && defbase_sel[dw->def_nr]) {
+ if (dw->weight) {
+ dw->weight = dw->weight * change;
+ CLAMP(dw->weight, 0.0f, 1.0f);
}
}
}
- if (selwsum && selwsum + brush_change > 0) {
- return (selwsum + brush_change) / selwsum;
- }
- return 0.0f;
}
-/* change the weights back to the wv's weights
- * it assumes you already have the correct pointer index */
-static void defvert_reset_to_prev(MDeformVert *dv_prev, MDeformVert *dv)
-{
- MDeformWeight *dw = dv->dw;
- MDeformWeight *dw_prev;
- unsigned int i;
- for (i = dv->totweight; i != 0; i--, dw++) {
- dw_prev = defvert_find_index(dv_prev, dw->def_nr);
- /* if there was no w when there is a d, then the old weight was 0 */
- dw->weight = dw_prev ? dw_prev->weight : 0.0f;
- }
-}
-
-static void clamp_weights(MDeformVert *dvert)
-{
- MDeformWeight *dw = dvert->dw;
- unsigned int i;
- for (i = dvert->totweight; i != 0; i--, dw++) {
- CLAMP(dw->weight, 0.0f, 1.0f);
- }
-}
+/**
+ * Variables stored both for 'active' and 'mirror' sides.
+ */
+struct WeightPaintGroupData {
+ /** index of active group or its mirror
+ *
+ * - 'active' is always `ob->actdef`.
+ * - 'mirror' is -1 when 'ME_EDIT_MIRROR_X' flag id disabled,
+ * otherwise this will be set to the mirror or the active group (if the group isn't mirrored).
+ */
+ int index;
+ /** lock that includes the 'index' as locked too
+ *
+ * - 'active' is set of locked or active/selected groups
+ * - 'mirror' is set of locked or mirror groups
+ */
+ const bool *lock;
+};
/* struct to avoid passing many args each call to do_weight_paint_vertex()
* this _could_ be made a part of the operators 'WPaintData' struct, or at
@@ -1570,8 +1459,7 @@ typedef struct WeightPaintInfo {
int defbase_tot_sel;
int defbase_tot_unsel;
- int vgroup_active; /* (ob->actdef - 1) */
- int vgroup_mirror; /* mirror group or -1 */
+ struct WeightPaintGroupData active, mirror;
const bool *lock_flags; /* boolean array for locked bones,
* length of defbase_tot */
@@ -1588,86 +1476,7 @@ typedef struct WeightPaintInfo {
float brush_alpha_value; /* result of BKE_brush_alpha_get() */
} WeightPaintInfo;
-/* fresh start to make multi-paint and locking modular */
-/* returns true if it thinks you need to reset the weights due to
- * normalizing while multi-painting
- *
- * note: this assumes dw->def_nr range has been checked by the caller
- */
-static int apply_mp_locks_normalize(Mesh *me, const WeightPaintInfo *wpi,
- const unsigned int index,
- MDeformWeight *dw, MDeformWeight *tdw,
- float change, float oldChange,
- float oldw, float neww)
-{
- MDeformVert *dv = &me->dvert[index];
- MDeformVert dv_test = {NULL};
-
- dv_test.dw = MEM_dupallocN(dv->dw);
- dv_test.flag = dv->flag;
- dv_test.totweight = dv->totweight;
- /* do not multi-paint if a locked group is selected or the active group is locked
- * !lock_flags[dw->def_nr] helps if nothing is selected, but active group is locked */
- if ((wpi->lock_flags == NULL) ||
- ((wpi->lock_flags[dw->def_nr] == false) && /* def_nr range has to be checked for by caller */
- has_locked_group_selected(wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags) == false))
- {
- if (wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
- if (change && change != 1) {
- multipaint_selection(dv, wpi->defbase_tot, change, wpi->defbase_sel);
- }
- }
- else { /* this lets users paint normally, but don't let them paint locked groups */
- dw->weight = neww;
- }
- }
- clamp_weights(dv);
-
- enforce_locks(&dv_test, dv, wpi->defbase_tot, wpi->defbase_sel, wpi->lock_flags, wpi->vgroup_validmap,
- wpi->do_auto_normalize, wpi->do_multipaint);
-
- if (wpi->do_auto_normalize) {
- /* XXX - should we pass the active group? - currently '-1' */
- do_weight_paint_normalize_all(dv, wpi->defbase_tot, wpi->vgroup_validmap);
- }
-
- if (oldChange && wpi->do_multipaint && wpi->defbase_tot_sel > 1) {
- if (tdw->weight != oldw) {
- if (neww > oldw) {
- if (tdw->weight <= oldw) {
- MEM_freeN(dv_test.dw);
- return true;
- }
- }
- else {
- if (tdw->weight >= oldw) {
- MEM_freeN(dv_test.dw);
- return true;
- }
- }
- }
- }
- MEM_freeN(dv_test.dw);
- return false;
-}
-
-/* within the current dvert index, get the dw that is selected and has a weight
- * above 0, this helps multi-paint */
-static int get_first_selected_nonzero_weight(MDeformVert *dvert, const int defbase_tot, const bool *defbase_sel)
-{
- int i;
- MDeformWeight *dw = dvert->dw;
- for (i = 0; i < dvert->totweight; i++, dw++) {
- if (dw->def_nr < defbase_tot) {
- if (defbase_sel[dw->def_nr] && dw->weight > 0.0f) {
- return i;
- }
- }
- }
- return -1;
-}
-
-static void do_weight_paint_vertex(
+static void do_weight_paint_vertex_single(
/* vars which remain the same for every vert */
VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
/* vars which change on each stroke */
@@ -1687,15 +1496,13 @@ static void do_weight_paint_vertex(
MDeformVert *dv_mirr;
MDeformWeight *dw_mirr;
- const short do_multipaint_totsel = (wpi->do_multipaint && wpi->defbase_tot_sel > 1);
-
if (wp->flag & VP_ONLYVGROUP) {
- dw = defvert_find_index(dv, wpi->vgroup_active);
- dw_prev = defvert_find_index(wp->wpaint_prev + index, wpi->vgroup_active);
+ dw = defvert_find_index(dv, wpi->active.index);
+ dw_prev = defvert_find_index(wp->wpaint_prev + index, wpi->active.index);
}
else {
- dw = defvert_verify_index(dv, wpi->vgroup_active);
- dw_prev = defvert_verify_index(wp->wpaint_prev + index, wpi->vgroup_active);
+ dw = defvert_verify_index(dv, wpi->active.index);
+ dw_prev = defvert_verify_index(wp->wpaint_prev + index, wpi->active.index);
}
if (dw == NULL || dw_prev == NULL) {
@@ -1705,12 +1512,12 @@ static void do_weight_paint_vertex(
/* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
if (me->editflag & ME_EDIT_MIRROR_X) {
- index_mirr = mesh_get_x_mirror_vert(ob, index, topology);
- vgroup_mirr = (wpi->vgroup_mirror != -1) ? wpi->vgroup_mirror : wpi->vgroup_active;
+ index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
+ vgroup_mirr = wpi->mirror.index;
/* another possible error - mirror group _and_ active group are the same (which is fine),
* but we also are painting onto a center vertex - this would paint the same weight twice */
- if (index_mirr == index && vgroup_mirr == wpi->vgroup_active) {
+ if (index_mirr == index && vgroup_mirr == wpi->active.index) {
index_mirr = vgroup_mirr = -1;
}
}
@@ -1752,17 +1559,12 @@ static void do_weight_paint_vertex(
dw_mirr = NULL;
}
-
- /* TODO: De-duplicate the simple weight paint - jason */
- /* ... or not, since its <10 SLOC - campbell */
-
- /* If there are no locks or multipaint,
+ /* If there are no normalize-locks or multipaint,
* then there is no need to run the more complicated checks */
- if ((do_multipaint_totsel == false) &&
- (wpi->lock_flags == NULL || has_locked_group(dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags) == false))
+
{
dw->weight = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight,
- wpi->brush_alpha_value, wpi->do_flip, false);
+ wpi->brush_alpha_value, wpi->do_flip);
/* WATCH IT: take care of the ordering of applying mirror -> normalize,
* can give wrong results [#26193], least confusing if normalize is done last */
@@ -1787,12 +1589,14 @@ static void do_weight_paint_vertex(
* do_weight_paint_normalize_all_active() when normalizing the mirror vertex.
* - campbell
*/
- do_weight_paint_normalize_all_active(dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->vgroup_active);
+ do_weight_paint_normalize_all_locked_try_active(
+ dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
if (index_mirr != -1) {
/* only normalize if this is not a center vertex, else we get a conflict, normalizing twice */
if (index != index_mirr) {
- do_weight_paint_normalize_all_active(dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, vgroup_mirr);
+ do_weight_paint_normalize_all_locked_try_active(
+ dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->mirror.lock);
}
else {
/* this case accounts for...
@@ -1815,100 +1619,111 @@ static void do_weight_paint_vertex(
}
}
}
- else {
- /* use locks and/or multipaint */
- float oldw;
- float neww;
- /* float testw = 0; */ /* UNUSED */
- float observedChange = 0;
- float change = 0;
- float oldChange = 0;
- int i;
- MDeformWeight *tdw = NULL, *tdw_prev;
- MDeformVert dv_copy = {NULL};
+}
- oldw = dw->weight;
- neww = wpaint_blend(wp, dw->weight, dw_prev->weight, alpha, paintweight,
- wpi->brush_alpha_value, wpi->do_flip, do_multipaint_totsel);
-
- /* setup multi-paint */
- observedChange = neww - oldw;
- if (do_multipaint_totsel && observedChange) {
- dv_copy.dw = MEM_dupallocN(dv->dw);
- dv_copy.flag = dv->flag;
- dv_copy.totweight = dv->totweight;
- tdw = dw;
- tdw_prev = dw_prev;
- change = get_mp_change(&wp->wpaint_prev[index], wpi->defbase_tot, wpi->defbase_sel, observedChange);
- if (change) {
- if (!tdw->weight) {
- i = get_first_selected_nonzero_weight(dv, wpi->defbase_tot, wpi->defbase_sel);
- if (i >= 0) {
- tdw = &(dv->dw[i]);
- tdw_prev = defvert_verify_index(&wp->wpaint_prev[index], tdw->def_nr);
- }
- else {
- change = 0;
- }
- }
- if (change && tdw_prev->weight && tdw_prev->weight * change) {
- if (tdw->weight != tdw_prev->weight) {
- oldChange = tdw->weight / tdw_prev->weight;
- /* testw = tdw_prev->weight * change; */ /* UNUSED */
- if (observedChange > 0) {
- if (change > oldChange) {
- /* reset the weights and use the new change */
- defvert_reset_to_prev(wp->wpaint_prev + index, dv);
- }
- else {
- /* the old change was more significant, so set
- * the change to 0 so that it will not do another multi-paint */
- change = 0;
- }
- }
- else {
- if (change < oldChange) {
- defvert_reset_to_prev(wp->wpaint_prev + index, dv);
- }
- else {
- change = 0;
- }
- }
- }
- }
- else {
- change = 0;
- }
- }
+static void do_weight_paint_vertex_multi(
+ /* vars which remain the same for every vert */
+ VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
+ /* vars which change on each stroke */
+ const unsigned int index, float alpha, float paintweight)
+{
+ Mesh *me = ob->data;
+ MDeformVert *dv = &me->dvert[index];
+ MDeformVert *dv_prev = &wp->wpaint_prev[index];
+ bool topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+
+ /* mirror vars */
+ int index_mirr = -1;
+ MDeformVert *dv_mirr = NULL;
+
+ /* weights */
+ float oldw, curw, neww, change, curw_mirr, change_mirr;
+
+ /* from now on we can check if mirrors enabled if this var is -1 and not bother with the flag */
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ index_mirr = mesh_get_x_mirror_vert(ob, NULL, index, topology);
+
+ if (index_mirr != -1 && index_mirr != index) {
+ dv_mirr = &me->dvert[index_mirr];
}
-
- if (apply_mp_locks_normalize(me, wpi, index, dw, tdw, change, oldChange, oldw, neww)) {
- defvert_reset_to_prev(&dv_copy, dv);
- change = 0;
- oldChange = 0;
+ }
+
+ /* compute weight change by applying the brush to average or sum of group weights */
+ oldw = BKE_defvert_multipaint_collective_weight(
+ dv_prev, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+ curw = BKE_defvert_multipaint_collective_weight(
+ dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+
+ if (curw == 0.0f) {
+ /* note: no weight to assign to this vertex, could add all groups? */
+ return;
+ }
+
+ neww = wpaint_blend(wp, curw, oldw, alpha, paintweight, wpi->brush_alpha_value, wpi->do_flip);
+
+ change = neww / curw;
+
+ /* verify for all groups that 0 < result <= 1 */
+ multipaint_clamp_change(dv, wpi->defbase_tot, wpi->defbase_sel, &change);
+
+ if (dv_mirr != NULL) {
+ curw_mirr = BKE_defvert_multipaint_collective_weight(
+ dv_mirr, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+
+ if (curw_mirr == 0.0f) {
+ /* can't mirror into a zero weight vertex */
+ dv_mirr = NULL;
}
- if (dv_copy.dw) {
- MEM_freeN(dv_copy.dw);
+ else {
+ /* mirror is changed to achieve the same collective weight value */
+ float orig = change_mirr = curw * change / curw_mirr;
+
+ multipaint_clamp_change(dv_mirr, wpi->defbase_tot, wpi->defbase_sel, &change_mirr);
+
+ if (!multipaint_verify_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel)) {
+ return;
+ }
+
+ change *= change_mirr / orig;
}
-#if 0
- /* dv may have been altered greatly */
- dw = defvert_find_index(dv, vgroup);
-#else
- dw = NULL; /* UNUSED after assignment, set to NULL to ensure we don't
- * use again, we thats needed un-ifdef the line above */
- (void)dw; /* quiet warnigns */
-#endif
+ }
- /* x mirror painting */
- if (index_mirr != -1) {
- /* copy, not paint again */
+ if (!multipaint_verify_change(dv, wpi->defbase_tot, change, wpi->defbase_sel)) {
+ return;
+ }
+
+ /* apply validated change to vertex and mirror */
+ multipaint_apply_change(dv, wpi->defbase_tot, change, wpi->defbase_sel);
+
+ if (dv_mirr != NULL) {
+ multipaint_apply_change(dv_mirr, wpi->defbase_tot, change_mirr, wpi->defbase_sel);
+ }
- /* dw_mirr->weight = dw->weight; */ /* TODO, explain the logic in not assigning weight! - campbell */
- apply_mp_locks_normalize(me, wpi, index_mirr, dw_mirr, tdw, change, oldChange, oldw, neww);
+ /* normalize */
+ if (wpi->do_auto_normalize) {
+ do_weight_paint_normalize_all_locked_try_active(
+ dv, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
+
+ if (dv_mirr != NULL) {
+ do_weight_paint_normalize_all_locked_try_active(
+ dv_mirr, wpi->defbase_tot, wpi->vgroup_validmap, wpi->lock_flags, wpi->active.lock);
}
}
}
+static void do_weight_paint_vertex(
+ /* vars which remain the same for every vert */
+ VPaint *wp, Object *ob, const WeightPaintInfo *wpi,
+ /* vars which change on each stroke */
+ const unsigned int index, float alpha, float paintweight)
+{
+ if (wpi->do_multipaint) {
+ do_weight_paint_vertex_multi(wp, ob, wpi, index, alpha, paintweight);
+ }
+ else {
+ do_weight_paint_vertex_single(wp, ob, wpi, index, alpha, paintweight);
+ }
+}
/* *************** set wpaint operator ****************** */
@@ -1943,8 +1758,8 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
}
/* weight paint specific */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, 'e');
+ ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_topo_table(NULL, NULL, 'e');
paint_cursor_delete_textures();
}
@@ -1959,7 +1774,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_paint_init(scene, ePaintWeight, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, 's');
+ ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
ED_vgroup_sync_from_pose(ob);
}
@@ -2007,11 +1822,20 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
/* ************ weight paint operator ********** */
+enum eWPaintFlag {
+ WPAINT_ENSURE_MIRROR = (1 << 0),
+};
+
+struct WPaintVGroupIndex {
+ int active;
+ int mirror;
+};
+
struct WPaintData {
ViewContext vc;
int *indexar;
- int vgroup_active;
- int vgroup_mirror;
+
+ struct WeightPaintGroupData active, mirror;
void *vp_handle;
DMCoNo *vertexcosnos;
@@ -2021,16 +1845,37 @@ struct WPaintData {
/* variables for auto normalize */
const bool *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
const bool *lock_flags;
+
+ /* variables for multipaint */
+ const bool *defbase_sel; /* set of selected groups */
+ int defbase_tot_sel; /* number of selected groups */
+ bool do_multipaint; /* true if multipaint enabled and multiple groups selected */
+
+ /* variables for blur */
+ struct {
+ MeshElemMap *vmap;
+ int *vmap_mem;
+ } blur_data;
+
+ BLI_Stack *accumulate_stack; /* for reuse (WPaintDefer) */
+
int defbase_tot;
};
/* ensure we have data on wpaint start, add if needed */
-static bool wpaint_ensure_data(bContext *C, wmOperator *op)
+static bool wpaint_ensure_data(
+ bContext *C, wmOperator *op,
+ enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_mesh_from_object(ob);
+ if (vgroup_index) {
+ vgroup_index->active = -1;
+ vgroup_index->mirror = -1;
+ }
+
if (scene->obedit) {
return false;
}
@@ -2077,6 +1922,19 @@ static bool wpaint_ensure_data(bContext *C, wmOperator *op)
return false;
}
+ if (vgroup_index) {
+ vgroup_index->active = ob->actdef - 1;
+ }
+
+ if (flag & WPAINT_ENSURE_MIRROR) {
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ int mirror = wpaint_mirror_vgroup_ensure(ob, ob->actdef - 1);
+ if (vgroup_index) {
+ vgroup_index->mirror = mirror;
+ }
+ }
+ }
+
return true;
}
@@ -2089,21 +1947,57 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN
Object *ob = CTX_data_active_object(C);
Mesh *me = BKE_mesh_from_object(ob);
struct WPaintData *wpd;
+ struct WPaintVGroupIndex vgroup_index;
+ int defbase_tot, defbase_tot_sel;
+ bool *defbase_sel;
+ const Brush *brush = BKE_paint_brush(&wp->paint);
float mat[4][4], imat[4][4];
- if (wpaint_ensure_data(C, op) == false) {
+ if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, &vgroup_index) == false) {
return false;
}
{
/* check if we are attempting to paint onto a locked vertex group,
* and other options disallow it from doing anything useful */
- bDeformGroup *dg = BLI_findlink(&ob->defbase, (ob->actdef - 1));
+ bDeformGroup *dg;
+ dg = BLI_findlink(&ob->defbase, vgroup_index.active);
if (dg->flag & DG_LOCK_WEIGHT) {
BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
return false;
}
+ if (vgroup_index.mirror != -1) {
+ dg = BLI_findlink(&ob->defbase, vgroup_index.mirror);
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_WARNING, "Mirror group is locked, aborting");
+ return false;
+ }
+ }
+ }
+
+ /* check that multipaint groups are unlocked */
+ defbase_tot = BLI_listbase_count(&ob->defbase);
+ defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_tot_sel);
+
+ if (ts->multipaint && defbase_tot_sel > 1) {
+ int i;
+ bDeformGroup *dg;
+
+ if (me->editflag & ME_EDIT_MIRROR_X) {
+ BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
+ }
+
+ for (i = 0; i < defbase_tot; i++) {
+ if (defbase_sel[i]) {
+ dg = BLI_findlink(&ob->defbase, i);
+ if (dg->flag & DG_LOCK_WEIGHT) {
+ BKE_report(op->reports, RPT_WARNING, "Multipaint group is locked, aborting");
+ MEM_freeN(defbase_sel);
+ return false;
+ }
+ }
+ }
}
/* ALLOCATIONS! no return after this line */
@@ -2112,36 +2006,108 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UN
paint_stroke_set_mode_data(stroke, wpd);
view3d_set_viewcontext(C, &wpd->vc);
- wpd->vgroup_active = ob->actdef - 1;
- wpd->vgroup_mirror = -1;
+ wpd->active.index = vgroup_index.active;
+ wpd->mirror.index = vgroup_index.mirror;
+
+ /* multipaint */
+ wpd->defbase_tot = defbase_tot;
+ wpd->defbase_sel = defbase_sel;
+ wpd->defbase_tot_sel = defbase_tot_sel > 1 ? defbase_tot_sel : 1;
+ wpd->do_multipaint = (ts->multipaint && defbase_tot_sel > 1);
/* set up auto-normalize, and generate map for detecting which
* vgroups affect deform bones */
- wpd->defbase_tot = BLI_listbase_count(&ob->defbase);
wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
if (ts->auto_normalize || ts->multipaint || wpd->lock_flags) {
wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
}
+ if (wpd->do_multipaint && ts->auto_normalize) {
+ bool *tmpflags;
+ tmpflags = MEM_mallocN(sizeof(bool) * defbase_tot, __func__);
+ if (wpd->lock_flags) {
+ BLI_array_binary_or(tmpflags, wpd->defbase_sel, wpd->lock_flags, wpd->defbase_tot);
+ }
+ else {
+ memcpy(tmpflags, wpd->defbase_sel, sizeof(*tmpflags) * wpd->defbase_tot);
+ }
+ wpd->active.lock = tmpflags;
+ }
+ else if (ts->auto_normalize) {
+ bool *tmpflags;
+
+ tmpflags = wpd->lock_flags ?
+ MEM_dupallocN(wpd->lock_flags) :
+ MEM_callocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags[wpd->active.index] = true;
+ wpd->active.lock = tmpflags;
+
+ tmpflags = wpd->lock_flags ?
+ MEM_dupallocN(wpd->lock_flags) :
+ MEM_callocN(sizeof(bool) * defbase_tot, __func__);
+ tmpflags[(wpd->mirror.index != -1) ? wpd->mirror.index : wpd->active.index] = true;
+ wpd->mirror.lock = tmpflags;
+ }
+
/* painting on subsurfs should give correct points too, this returns me->totvert amount */
wpd->vp_handle = ED_vpaint_proj_handle_create(scene, ob, &wpd->vertexcosnos);
wpd->indexar = get_indexarray(me);
copy_wpaint_prev(wp, me->dvert, me->totvert);
+ if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+ BKE_mesh_vert_edge_vert_map_create(
+ &wpd->blur_data.vmap, &wpd->blur_data.vmap_mem,
+ me->medge, me->totvert, me->totedge);
+ }
+
+ if ((brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
+ (brush->flag & BRUSH_ACCUMULATE))
+ {
+ wpd->accumulate_stack = BLI_stack_new(sizeof(struct WPaintDefer), __func__);
+ }
+
/* imat for normals */
mul_m4_m4m4(mat, wpd->vc.rv3d->viewmat, ob->obmat);
invert_m4_m4(imat, mat);
copy_m3_m4(wpd->wpimat, imat);
- /* if mirror painting, find the other group */
- if (me->editflag & ME_EDIT_MIRROR_X) {
- wpd->vgroup_mirror = wpaint_mirror_vgroup_ensure(ob, wpd->vgroup_active);
- }
-
return true;
}
+static float wpaint_blur_weight_single(const MDeformVert *dv, const WeightPaintInfo *wpi)
+{
+ return defvert_find_weight(dv, wpi->active.index);
+}
+
+static float wpaint_blur_weight_multi(const MDeformVert *dv, const WeightPaintInfo *wpi)
+{
+ float weight = BKE_defvert_multipaint_collective_weight(
+ dv, wpi->defbase_tot, wpi->defbase_sel, wpi->defbase_tot_sel, wpi->do_auto_normalize);
+ CLAMP(weight, 0.0f, 1.0f);
+ return weight;
+}
+
+static float wpaint_blur_weight_calc_from_connected(
+ const MDeformVert *dvert, WeightPaintInfo *wpi, struct WPaintData *wpd, const unsigned int vidx,
+ float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *))
+{
+ const MeshElemMap *map = &wpd->blur_data.vmap[vidx];
+ float paintweight;
+ if (map->count != 0) {
+ paintweight = 0.0f;
+ for (int j = 0; j < map->count; j++) {
+ paintweight += blur_weight_func(&dvert[map->indices[j]], wpi);
+ }
+ paintweight /= map->count;
+ }
+ else {
+ paintweight = blur_weight_func(&dvert[vidx], wpi);
+ }
+
+ return paintweight;
+}
+
static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
Scene *scene = CTX_data_scene(C);
@@ -2155,24 +2121,19 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
float mat[4][4];
float paintweight;
int *indexar;
- float totw;
unsigned int index, totindex;
- float alpha;
float mval[2];
+ const bool use_blur = (brush->vertexpaint_tool == PAINT_BLEND_BLUR);
bool use_vert_sel;
bool use_face_sel;
bool use_depth;
- MDeformWeight *(*dw_func)(MDeformVert *, const int) =
- (brush->vertexpaint_tool == PAINT_BLEND_BLUR) ?
- ((wp->flag & VP_ONLYVGROUP) ?
- (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index :
- defvert_verify_index) : NULL;
-
const float pressure = RNA_float_get(itemptr, "pressure");
- const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
+ const float brush_size_pressure =
+ BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
const float brush_alpha_value = BKE_brush_alpha_get(scene, brush);
- const float brush_alpha_pressure = brush_alpha_value * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
+ const float brush_alpha_pressure =
+ brush_alpha_value * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
/* intentionally don't initialize as NULL, make sure we initialize all members below */
WeightPaintInfo wpi;
@@ -2185,6 +2146,9 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
return;
}
+ float (*blur_weight_func)(const MDeformVert *, const WeightPaintInfo *) =
+ wpd->do_multipaint ? wpaint_blur_weight_multi : wpaint_blur_weight_single;
+
vc = &wpd->vc;
ob = vc->obact;
me = ob->data;
@@ -2200,18 +2164,16 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* *** setup WeightPaintInfo - pass onto do_weight_paint_vertex *** */
wpi.defbase_tot = wpd->defbase_tot;
- wpi.defbase_sel = BKE_object_defgroup_selected_get(ob, wpi.defbase_tot, &wpi.defbase_tot_sel);
- if (wpi.defbase_tot_sel == 0 && ob->actdef > 0) {
- wpi.defbase_tot_sel = 1;
- }
+ wpi.defbase_sel = wpd->defbase_sel;
+ wpi.defbase_tot_sel = wpd->defbase_tot_sel;
wpi.defbase_tot_unsel = wpi.defbase_tot - wpi.defbase_tot_sel;
- wpi.vgroup_active = wpd->vgroup_active;
- wpi.vgroup_mirror = wpd->vgroup_mirror;
+ wpi.active = wpd->active;
+ wpi.mirror = wpd->mirror;
wpi.lock_flags = wpd->lock_flags;
wpi.vgroup_validmap = wpd->vgroup_validmap;
wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip");
- wpi.do_multipaint = (ts->multipaint != 0);
+ wpi.do_multipaint = wpd->do_multipaint;
wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL));
wpi.brush_alpha_value = brush_alpha_value;
/* *** done setting up WeightPaintInfo *** */
@@ -2259,23 +2221,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* make sure each vertex gets treated only once */
/* and calculate filter weight */
- totw = 0.0f;
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR)
- paintweight = 0.0f;
- else
- paintweight = BKE_brush_weight_get(scene, brush);
-
-#define WP_BLUR_ACCUM(v_idx_var) \
- { \
- const unsigned int vidx = v_idx_var; \
- const float fac = calc_vp_strength_col_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure, NULL); \
- if (fac > 0.0f) { \
- MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \
- paintweight += dw ? (dw->weight * fac) : 0.0f; \
- totw += fac; \
- } \
- } (void)0
-
+ paintweight = BKE_brush_weight_get(scene, brush);
if (use_depth) {
for (index = 0; index < totindex; index++) {
@@ -2294,13 +2240,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
me->dvert[ml->v].flag = 1;
}
}
-
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- ml = me->mloop + mpoly->loopstart;
- for (i = 0; i < mpoly->totloop; i++, ml++) {
- WP_BLUR_ACCUM(ml->v);
- }
- }
}
}
}
@@ -2319,29 +2258,37 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
me->dvert[i].flag = SELECT;
}
}
-
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- for (i = 0; i < totvert; i++) {
- WP_BLUR_ACCUM(i);
- }
- }
}
-#undef WP_BLUR_ACCUM
+ /* accumulate means we refer to the previous,
+ * which is either the last update, or when we started painting */
+ BLI_Stack *accumulate_stack = wpd->accumulate_stack;
+ const bool use_accumulate = (accumulate_stack != NULL);
+ BLI_assert(accumulate_stack == NULL || BLI_stack_is_empty(accumulate_stack));
-
- if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
- paintweight /= totw;
- }
+ const MDeformVert *dvert_prev = use_accumulate ? me->dvert : wp->wpaint_prev;
#define WP_PAINT(v_idx_var) \
{ \
unsigned int vidx = v_idx_var; \
if (me->dvert[vidx].flag) { \
- alpha = calc_vp_alpha_col_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
- mval, brush_size_pressure, brush_alpha_pressure, NULL); \
+ const float alpha = calc_vp_alpha_col_dl( \
+ wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
+ mval, brush_size_pressure, brush_alpha_pressure, NULL); \
if (alpha) { \
- do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
+ if (use_blur) { \
+ paintweight = wpaint_blur_weight_calc_from_connected( \
+ dvert_prev, &wpi, wpd, vidx, blur_weight_func); \
+ } \
+ if (use_accumulate) { \
+ struct WPaintDefer *dweight = BLI_stack_push_r(accumulate_stack); \
+ dweight->index = vidx; \
+ dweight->alpha = alpha; \
+ dweight->weight = paintweight; \
+ } \
+ else { \
+ do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
+ } \
} \
me->dvert[vidx].flag = 0; \
} \
@@ -2371,14 +2318,27 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
#undef WP_PAINT
+ if (use_accumulate) {
+ unsigned int defer_count = BLI_stack_count(accumulate_stack);
+ while (defer_count--) {
+ struct WPaintDefer *dweight = BLI_stack_peek(accumulate_stack);
+ do_weight_paint_vertex(wp, ob, &wpi, dweight->index, dweight->alpha, dweight->weight);
+ BLI_stack_discard(accumulate_stack);
+ }
+ }
+
/* *** free wpi members */
- MEM_freeN((void *)wpi.defbase_sel);
/* *** done freeing wpi members */
swap_m4m4(vc->rv3d->persmat, mat);
+ /* calculate pivot for rotation around seletion if needed */
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ paint_last_stroke_update(scene, vc->ar, mval);
+ }
+
DAG_id_tag_update(ob->data, 0);
ED_region_tag_redraw(vc->ar);
}
@@ -2393,10 +2353,27 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke)
ED_vpaint_proj_handle_free(wpd->vp_handle);
MEM_freeN(wpd->indexar);
+ if (wpd->defbase_sel)
+ MEM_freeN((void *)wpd->defbase_sel);
if (wpd->vgroup_validmap)
MEM_freeN((void *)wpd->vgroup_validmap);
if (wpd->lock_flags)
MEM_freeN((void *)wpd->lock_flags);
+ if (wpd->active.lock)
+ MEM_freeN((void *)wpd->active.lock);
+ if (wpd->mirror.lock)
+ MEM_freeN((void *)wpd->mirror.lock);
+
+ if (wpd->blur_data.vmap) {
+ MEM_freeN(wpd->blur_data.vmap);
+ }
+ if (wpd->blur_data.vmap_mem) {
+ MEM_freeN(wpd->blur_data.vmap_mem);
+ }
+
+ if (wpd->accumulate_stack) {
+ BLI_stack_free(wpd->accumulate_stack);
+ }
MEM_freeN(wpd);
}
@@ -2492,7 +2469,7 @@ static int weight_paint_set_exec(bContext *C, wmOperator *op)
Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
float vgroup_weight = BKE_brush_weight_get(scene, brush);
- if (wpaint_ensure_data(C, op) == false) {
+ if (wpaint_ensure_data(C, op, WPAINT_ENSURE_MIRROR, NULL) == false) {
return OPERATOR_CANCELLED;
}
@@ -2786,8 +2763,10 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
float mval[2];
const float pressure = RNA_float_get(itemptr, "pressure");
- const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
- const float brush_alpha_pressure = BKE_brush_alpha_get(scene, brush) * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
+ const float brush_size_pressure =
+ BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
+ const float brush_alpha_pressure =
+ BKE_brush_alpha_get(scene, brush) * (BKE_brush_use_alpha_pressure(scene, brush) ? pressure : 1.0f);
RNA_float_get_array(itemptr, "mouse", mval);
@@ -2833,6 +2812,11 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
do_shared_vertexcol(me, vpd->mlooptag);
}
+ /* calculate pivot for rotation around seletion if needed */
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ paint_last_stroke_update(scene, vc->ar, mval);
+ }
+
ED_region_tag_redraw(vc->ar);
if (vpd->use_fast_update == false) {
@@ -2995,7 +2979,7 @@ typedef struct DMGradient_userData {
const float *sco_end; /* [2] */
float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
int def_nr;
- short is_init;
+ bool is_init;
DMGradient_vertStore *vert_cache;
/* only for init */
BLI_bitmap *vert_visit;
@@ -3183,7 +3167,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
vert_cache = gesture->userdata;
}
else {
- if (wpaint_ensure_data(C, op) == false) {
+ if (wpaint_ensure_data(C, op, 0, NULL) == false) {
return OPERATOR_CANCELLED;
}
@@ -3242,7 +3226,7 @@ static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEve
{
int ret;
- if (wpaint_ensure_data(C, op) == false) {
+ if (wpaint_ensure_data(C, op, 0, NULL) == false) {
return OPERATOR_CANCELLED;
}
@@ -3250,7 +3234,8 @@ static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEve
if (ret & OPERATOR_RUNNING_MODAL) {
struct ARegion *ar = CTX_wm_region(C);
if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (event->type == LEFTMOUSE && event->val == KM_PRESS) { /* TODO, hardcoded, extend WM_gesture_straightline_ */
+ /* TODO, hardcoded, extend WM_gesture_straightline_ */
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
wmGesture *gesture = op->customdata;
gesture->mode = 1;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 07511e1924e..40ff662a2c2 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -38,6 +38,8 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -97,25 +99,6 @@
#include <stdlib.h>
#include <string.h>
-#ifdef _OPENMP
-#include <omp.h>
-#endif
-
-#if defined(__APPLE__) && defined _OPENMP
-#include <sys/sysctl.h>
-
-#include "BLI_threads.h"
-
-/* Query how many cores not counting HT aka physical cores we've got. */
-static int system_physical_thread_count(void)
-{
- int pcount;
- size_t pcount_len = sizeof(pcount);
- sysctlbyname("hw.physicalcpu", &pcount, &pcount_len, NULL, 0);
- return pcount;
-}
-#endif /* __APPLE__ */
-
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
@@ -159,10 +142,10 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool)
/**
* Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action
*/
-static int sculpt_brush_needs_normal(const Brush *brush)
+static int sculpt_brush_needs_normal(const Brush *brush, float normal_weight)
{
return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) &&
- (brush->normal_weight > 0)) ||
+ (normal_weight > 0.0f)) ||
ELEM(brush->sculpt_tool,
SCULPT_TOOL_BLOB,
@@ -175,9 +158,21 @@ static int sculpt_brush_needs_normal(const Brush *brush)
(brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA));
}
-
/** \} */
+static bool sculpt_brush_needs_rake_rotation(const Brush *brush)
+{
+ return SCULPT_TOOL_HAS_RAKE(brush->sculpt_tool) && (brush->rake_factor != 0.0f);
+}
+
+/* Factor of brush to have rake point following behind
+ * (could be configurable but this is reasonable default). */
+#define SCULPT_RAKE_BRUSH_FACTOR 0.25f
+
+struct SculptRakeData {
+ float follow_dist;
+ float follow_co[3];
+};
typedef enum StrokeFlags {
CLIP_X = 1,
@@ -198,11 +193,6 @@ typedef struct StrokeCache {
float clip_tolerance[3];
float initial_mouse[2];
- /* Pre-allocated temporary storage used during smoothing */
- int num_threads, init_num_threads;
- float (**tmpgrid_co)[3], (**tmprow_co)[3];
- float **tmpgrid_mask, **tmprow_mask;
-
/* Variants */
float radius;
float radius_squared;
@@ -214,6 +204,7 @@ typedef struct StrokeCache {
float pressure;
float mouse[2];
float bstrength;
+ float normal_weight; /* from brush (with optional override) */
/* The rest is temporary storage that isn't saved as a property */
@@ -230,6 +221,11 @@ typedef struct StrokeCache {
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
+ /* screen-space rotation defined by mouse motion */
+ float rake_rotation[4], rake_rotation_symmetry[4];
+ bool is_rake_rotation_valid;
+ struct SculptRakeData rake_data;
+
int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
* 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
@@ -350,6 +346,67 @@ static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
}
}
+static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3])
+{
+ float rake_dist = len_v3v3(srd->follow_co, co);
+ if (rake_dist > srd->follow_dist) {
+ interp_v3_v3v3(srd->follow_co, srd->follow_co, co, rake_dist - srd->follow_dist);
+ }
+}
+
+
+static void sculpt_rake_rotate(
+ const SculptSession *ss, const float sculpt_co[3], const float v_co[3], float factor, float r_delta[3])
+{
+ float vec_rot[3];
+
+#if 0
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
+#else
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ mul_fac_qt_fl(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
+
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+
+}
+
+/**
+ * Align the grab delta to the brush normal.
+ *
+ * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
+ */
+static void sculpt_project_v3_normal_align(SculptSession *ss, const float normal_weight, float grab_delta[3])
+{
+ /* signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+
+ /* this scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
+
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+}
+
+
/** \name SculptProjectVector
*
* Fast-path for #project_plane_v3_v3v3
@@ -419,57 +476,106 @@ static bool sculpt_stroke_is_dynamic_topology(
/*** paint mesh ***/
-static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
+/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */
+typedef struct SculptThreadedTaskData {
+ Sculpt *sd;
+ Object *ob;
+ Brush *brush;
+ PBVHNode **nodes;
+ int totnode;
+
+ /* Data specific to some callbacks. */
+ /* Note: even if only one or two of those are used at a time, keeping them separated, names help figuring out
+ * what it is, and memory overhead is ridiculous anyway... */
+ float flippedbstrength;
+ float angle;
+ float strength;
+ bool smooth_mask;
+ bool has_bm_orco;
+
+ SculptProjectVector *spvc;
+ float *offset;
+ float *grab_delta;
+ float *cono;
+ float *area_no;
+ float *area_no_sp;
+ float *area_co;
+ float (*mat)[4];
+ float (*vertCos)[3];
+
+ /* 0=towards view, 1=flipped */
+ float (*area_cos)[3];
+ float (*area_nos)[3];
+ int *count;
+
+ ThreadMutex mutex;
+} SculptThreadedTaskData;
+
+static void paint_mesh_restore_co_task_cb(void *userdata, const int n)
{
- SculptSession *ss = ob->sculpt;
- const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
- PBVHNode **nodes;
- int n, totnode;
+ SculptUndoNode *unode;
+ SculptUndoType type = (data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ if (ss->bm) {
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], type);
+ }
+ else {
+ unode = sculpt_undo_get_node(data->nodes[n]);
+ }
- /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new
- * entries might be inserted by sculpt_undo_push_node() into the
- * GHash used internally by BM_log_original_vert_co() by a
- * different thread. [#33787] */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- SculptUndoNode *unode;
- SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
- SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ if (unode) {
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
- if (ss->bm) {
- unode = sculpt_undo_push_node(ob, nodes[n], type);
- }
- else {
- unode = sculpt_undo_get_node(nodes[n]);
- }
- if (unode) {
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
+ sculpt_orig_vert_data_unode_init(&orig_data, data->ob, unode);
- sculpt_orig_vert_data_unode_init(&orig_data, ob, unode);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
- if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
- copy_v3_v3(vd.co, orig_data.co);
- if (vd.no) copy_v3_v3_short(vd.no, orig_data.no);
- else normal_short_to_float_v3(vd.fno, orig_data.no);
- }
- else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
- *vd.mask = orig_data.mask;
- }
- if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
+ copy_v3_v3(vd.co, orig_data.co);
+ if (vd.no)
+ copy_v3_v3_short(vd.no, orig_data.no);
+ else
+ normal_short_to_float_v3(vd.fno, orig_data.no);
+ }
+ else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
+ *vd.mask = orig_data.mask;
}
- BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_update(nodes[n]);
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(data->nodes[n]);
}
+}
+
+static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ /* Disable OpenMP when dynamic-topology is enabled. Otherwise, new entries might be inserted by
+ * sculpt_undo_push_node() into the GHash used internally by BM_log_original_vert_co() by a different thread.
+ * See T33787. */
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
+
+ BLI_task_parallel_range(
+ 0, totnode, &data, paint_mesh_restore_co_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_THREADED_LIMIT));
if (nodes)
MEM_freeN(nodes);
@@ -548,6 +654,7 @@ typedef struct SculptBrushTest {
float radius_squared;
float location[3];
float dist;
+ int mirror_symmetry_pass;
/* View3d clipping - only set rv3d for clipping */
RegionView3D *clip_rv3d;
@@ -561,6 +668,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
copy_v3_v3(test->location, ss->cache->location);
test->dist = 0.0f; /* just for initialize */
+ test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
if (rv3d->rflag & RV3D_CLIPPING) {
test->clip_rv3d = rv3d;
@@ -573,7 +681,12 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
BLI_INLINE bool sculpt_brush_test_clipping(const SculptBrushTest *test, const float co[3])
{
RegionView3D *rv3d = test->clip_rv3d;
- return (rv3d && (ED_view3d_clipping_test(rv3d, co, true)));
+ if (!rv3d) {
+ return false;
+ }
+ float symm_co[3];
+ flip_v3_v3(symm_co, co, test->mirror_symmetry_pass);
+ return ED_view3d_clipping_test(rv3d, symm_co, true);
}
static bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
@@ -776,131 +889,163 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
-static void calc_area_center(
- Sculpt *sd, Object *ob,
- PBVHNode **nodes, int totnode,
- float r_area_co[3])
+static void calc_area_normal_and_center_task_cb(void *userdata, const int n)
{
- const Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- int n;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ float (*area_nos)[3] = data->area_nos;
+ float (*area_cos)[3] = data->area_cos;
- /* 0=towards view, 1=flipped */
- float area_co[2][3] = {{0.0f}};
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
- int count[2] = {0};
+ float private_co[2][3] = {{0.0f}};
+ float private_no[2][3] = {{0.0f}};
+ int private_count[2] = {0};
+ bool use_original;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_co[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(
- nodes[n],
- &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no[3];
- int flip_index;
-
- cross_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ unode = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
+ sculpt_brush_test_init(ss, &test);
+
+ use_original = (ss->cache->original && (unode->co || unode->bm_entry));
+
+ /* when the mesh is edited we can't rely on original coords
+ * (original mesh may not even have verts in brush radius) */
+ if (use_original && data->has_bm_orco) {
+ float (*orco_coords)[3];
+ int (*orco_tris)[3];
+ int orco_tris_num;
+ int i;
+
+ BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
+
+ for (i = 0; i < orco_tris_num; i++) {
+ const float *co_tri[3] = {
+ orco_coords[orco_tris[i][0]],
+ orco_coords[orco_tris[i][1]],
+ orco_coords[orco_tris[i][2]],
+ };
+ float co[3];
+
+ closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
+
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no[3];
+ int flip_index;
+
+ normal_tri_v3(no, UNPACK3(co_tri));
+
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ if (area_cos)
add_v3_v3(private_co[flip_index], co);
- private_count[flip_index] += 1;
- }
+ if (area_nos)
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
}
}
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
+ }
+ else {
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float *co;
+ const short *no_s; /* bm_vert only */
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
+ if (use_original) {
+ if (unode->bm_entry) {
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
}
else {
- co = vd.co;
+ co = unode->co[vd.i];
+ no_s = unode->no[vd.i];
}
+ }
+ else {
+ co = vd.co;
+ }
- if (sculpt_brush_test_fast(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
+ if (sculpt_brush_test_fast(&test, co)) {
+ float no_buf[3];
+ const float *no;
+ int flip_index;
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
+ if (use_original) {
+ normal_short_to_float_v3(no_buf, no_s);
+ no = no_buf;
+ }
+ else {
+ if (vd.no) {
+ normal_short_to_float_v3(no_buf, vd.no);
no = no_buf;
}
else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
+ no = vd.fno;
}
+ }
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
+ if (area_cos)
add_v3_v3(private_co[flip_index], co);
- private_count[flip_index] += 1;
- }
+ if (area_nos)
+ add_v3_v3(private_no[flip_index], no);
+ private_count[flip_index] += 1;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
+ }
-#pragma omp critical
- {
- /* for flatten center */
- add_v3_v3(area_co[0], private_co[0]);
- add_v3_v3(area_co[1], private_co[1]);
+ BLI_mutex_lock(&data->mutex);
- /* weights */
- count[0] += private_count[0];
- count[1] += private_count[1];
- }
+ /* for flatten center */
+ if (area_cos) {
+ add_v3_v3(area_cos[0], private_co[0]);
+ add_v3_v3(area_cos[1], private_co[1]);
+ }
+
+ /* for area normal */
+ if (area_nos) {
+ add_v3_v3(area_nos[0], private_no[0]);
+ add_v3_v3(area_nos[1], private_no[1]);
}
+ /* weights */
+ data->count[0] += private_count[0];
+ data->count[1] += private_count[1];
+
+ BLI_mutex_unlock(&data->mutex);
+}
+
+static void calc_area_center(
+ Sculpt *sd, Object *ob,
+ PBVHNode **nodes, int totnode,
+ float r_area_co[3])
+{
+ const Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ int n;
+
+ /* 0=towards view, 1=flipped */
+ float area_cos[2][3] = {{0.0f}};
+
+ int count[2] = {0};
+
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = NULL, .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
+
+ BLI_task_parallel_range(
+ 0, totnode, &data, calc_area_normal_and_center_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
+
+ BLI_mutex_end(&data.mutex);
+
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
break;
}
}
@@ -921,119 +1066,25 @@ static void calc_area_normal(
int n;
/* 0=towards view, 1=flipped */
- float area_no[2][3] = {{0.0f}};
+ float area_nos[2][3] = {{0.0f}};
int count[2] = {0};
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(
- nodes[n],
- &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no[3];
- int flip_index;
-
- normal_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
-
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
- }
- else {
- co = vd.co;
- }
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
-
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
- }
- else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
- }
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .has_bm_orco = has_bm_orco, .area_cos = NULL, .area_nos = area_nos, .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
-#pragma omp critical
- {
- /* for area normal */
- add_v3_v3(area_no[0], private_no[0]);
- add_v3_v3(area_no[1], private_no[1]);
+ BLI_task_parallel_range(
+ 0, totnode, &data, calc_area_normal_and_center_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
- /* weights */
- count[0] += private_count[0];
- count[1] += private_count[1];
- }
- }
+ BLI_mutex_end(&data.mutex);
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_no); n++) {
- if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
break;
}
}
@@ -1052,128 +1103,27 @@ static void calc_area_normal_and_center(
int n;
/* 0=towards view, 1=flipped */
- float area_co[2][3] = {{0.0f}};
- float area_no[2][3] = {{0.0f}};
+ float area_cos[2][3] = {{0.0f}};
+ float area_nos[2][3] = {{0.0f}};
int count[2] = {0};
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptUndoNode *unode;
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
- bool use_original;
-
- unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
- sculpt_brush_test_init(ss, &test);
-
- use_original = (ss->cache->original && (unode->co || unode->bm_entry));
-
- /* when the mesh is edited we can't rely on original coords
- * (original mesh may not even have verts in brush radius) */
- if (use_original && has_bm_orco) {
- float (*orco_coords)[3];
- int (*orco_tris)[3];
- int orco_tris_num;
- int i;
-
- BKE_pbvh_node_get_bm_orco_data(
- nodes[n],
- &orco_tris, &orco_tris_num, &orco_coords);
-
- for (i = 0; i < orco_tris_num; i++) {
- const float *co_tri[3] = {
- orco_coords[orco_tris[i][0]],
- orco_coords[orco_tris[i][1]],
- orco_coords[orco_tris[i][2]],
- };
- float co[3];
-
- closest_on_tri_to_point_v3(co, test.location, UNPACK3(co_tri));
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no[3];
- int flip_index;
-
- normal_tri_v3(no, UNPACK3(co_tri));
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_co[flip_index], co);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- }
- else {
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float *co;
- const short *no_s; /* bm_vert only */
-
- if (use_original) {
- if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
- }
- else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
- }
- }
- else {
- co = vd.co;
- }
-
- if (sculpt_brush_test_fast(&test, co)) {
- float no_buf[3];
- const float *no;
- int flip_index;
-
- if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
- }
- else {
- if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
- }
- else {
- no = vd.fno;
- }
- }
-
- flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- add_v3_v3(private_co[flip_index], co);
- add_v3_v3(private_no[flip_index], no);
- private_count[flip_index] += 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
-#pragma omp critical
- {
- /* for flatten center */
- add_v3_v3(area_co[0], private_co[0]);
- add_v3_v3(area_co[1], private_co[1]);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .nodes = nodes, .totnode = totnode,
+ .has_bm_orco = has_bm_orco, .area_cos = area_cos, .area_nos = area_nos, .count = count,
+ };
+ BLI_mutex_init(&data.mutex);
- /* for area normal */
- add_v3_v3(area_no[0], private_no[0]);
- add_v3_v3(area_no[1], private_no[1]);
+ BLI_task_parallel_range(
+ 0, totnode, &data, calc_area_normal_and_center_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
- /* weights */
- count[0] += private_count[0];
- count[1] += private_count[1];
- }
- }
+ BLI_mutex_end(&data.mutex);
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_co); n++) {
+ for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_co[n], 1.0f / count[n]);
+ mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
break;
}
}
@@ -1182,8 +1132,8 @@ static void calc_area_normal_and_center(
}
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_no); n++) {
- if (normalize_v3_v3(r_area_no, area_no[n]) != 0.0f) {
+ for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
break;
}
}
@@ -1291,14 +1241,14 @@ static float tex_strength(SculptSession *ss, Brush *br,
const float len,
const short vno[3],
const float fno[3],
- const float mask)
+ const float mask,
+ const int thread_id)
{
StrokeCache *cache = ss->cache;
const Scene *scene = cache->vc->scene;
MTex *mtex = &br->mtex;
float avg = 1;
float rgba[4];
- int thread_num;
if (!mtex->tex) {
avg = 1;
@@ -1341,12 +1291,7 @@ static float tex_strength(SculptSession *ss, Brush *br,
x += br->mtex.ofs[0];
y += br->mtex.ofs[1];
-#ifdef _OPENMP
- thread_num = omp_get_thread_num();
-#else
- thread_num = 0;
-#endif
- avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_num);
+ avg = paint_get_tex_pixel(&br->mtex, x, y, ss->tex_pool, thread_id);
avg += br->texture_sample_bias;
}
@@ -1678,36 +1623,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
}
}
-static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+/* Note: uses after-struct allocated mem to store actual cache... */
+typedef struct SculptDoBrushSmoothGridDataChunk {
+ size_t tmpgrid_size;
+} SculptDoBrushSmoothGridDataChunk;
+
+static void do_smooth_brush_mesh_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
PBVHVertexIter vd;
SculptBrushTest test;
-
+
CLAMP(bstrength, 0.0f, 1.0f);
sculpt_brush_test_init(ss, &test);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno,
- smooth_mask ? 0 : (vd.mask ? *vd.mask : 0.0f));
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ thread_id);
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
- CLAMP(*vd.mask, 0, 1);
+ CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
neighbor_average(ss, avg, vd.vert_indices[vd.i]);
sub_v3_v3v3(val, avg, vd.co);
- mul_v3_fl(val, fade);
- add_v3_v3(val, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
sculpt_clip(sd, ss, vd.co, val);
}
@@ -1719,36 +1676,42 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
BKE_pbvh_vertex_iter_end;
}
-static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+static void do_smooth_brush_bmesh_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
PBVHVertexIter vd;
SculptBrushTest test;
-
+
CLAMP(bstrength, 0.0f, 1.0f);
sculpt_brush_test_init(ss, &test);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno,
- smooth_mask ? 0 : *vd.mask);
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, smooth_mask ? 0.0f : *vd.mask,
+ thread_id);
if (smooth_mask) {
float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
val *= fade * bstrength;
*vd.mask += val;
- CLAMP(*vd.mask, 0, 1);
+ CLAMP(*vd.mask, 0.0f, 1.0f);
}
else {
float avg[3], val[3];
bmesh_neighbor_average(avg, vd.bm_vert);
sub_v3_v3v3(val, avg, vd.co);
- mul_v3_fl(val, fade);
- add_v3_v3(val, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
sculpt_clip(sd, ss, vd.co, val);
}
@@ -1760,74 +1723,78 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
BKE_pbvh_vertex_iter_end;
}
-static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
- float bstrength, int smooth_mask)
+static void do_smooth_brush_multires_task_cb_ex(
+ void *userdata, void *userdata_chunk, const int n, const int thread_id)
{
- Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptThreadedTaskData *data = userdata;
+ SculptDoBrushSmoothGridDataChunk *data_chunk = userdata_chunk;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
SculptBrushTest test;
- CCGElem **griddata, *data;
+ CCGElem **griddata, *gddata;
CCGKey key;
- float (*tmpgrid_co)[3], (*tmprow_co)[3];
- float *tmpgrid_mask, *tmprow_mask;
- int v1, v2, v3, v4;
- int thread_num;
+
+ float (*tmpgrid_co)[3] = NULL;
+ float tmprow_co[2][3];
+ float *tmpgrid_mask = NULL;
+ float tmprow_mask[2];
+
BLI_bitmap * const *grid_hidden;
- int *grid_indices, totgrid, gridsize, i, x, y;
+ int *grid_indices, totgrid, gridsize;
+ int i, x, y;
sculpt_brush_test_init(ss, &test);
CLAMP(bstrength, 0.0f, 1.0f);
- BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
- NULL, &gridsize, &griddata);
+ BKE_pbvh_node_get_grids(ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
BKE_pbvh_get_grid_key(ss->pbvh, &key);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
-#ifdef _OPENMP
- thread_num = omp_get_thread_num();
-#else
- thread_num = 0;
-#endif
- tmpgrid_co = ss->cache->tmpgrid_co[thread_num];
- tmprow_co = ss->cache->tmprow_co[thread_num];
- tmpgrid_mask = ss->cache->tmpgrid_mask[thread_num];
- tmprow_mask = ss->cache->tmprow_mask[thread_num];
+ if (smooth_mask)
+ tmpgrid_mask = (void *)(data_chunk + 1);
+ else
+ tmpgrid_co = (void *)(data_chunk + 1);
- for (i = 0; i < totgrid; ++i) {
+ for (i = 0; i < totgrid; i++) {
int gi = grid_indices[i];
const BLI_bitmap *gh = grid_hidden[gi];
- data = griddata[gi];
+ gddata = griddata[gi];
if (smooth_mask)
- memset(tmpgrid_mask, 0, sizeof(float) * gridsize * gridsize);
+ memset(tmpgrid_mask, 0, data_chunk->tmpgrid_size);
else
- memset(tmpgrid_co, 0, sizeof(float) * 3 * gridsize * gridsize);
+ memset(tmpgrid_co, 0, data_chunk->tmpgrid_size);
for (y = 0; y < gridsize - 1; y++) {
- v1 = y * gridsize;
+ const int v = y * gridsize;
if (smooth_mask) {
- tmprow_mask[0] = (*CCG_elem_offset_mask(&key, data, v1) +
- *CCG_elem_offset_mask(&key, data, v1 + gridsize));
+ tmprow_mask[0] = (*CCG_elem_offset_mask(&key, gddata, v) +
+ *CCG_elem_offset_mask(&key, gddata, v + gridsize));
}
else {
add_v3_v3v3(tmprow_co[0],
- CCG_elem_offset_co(&key, data, v1),
- CCG_elem_offset_co(&key, data, v1 + gridsize));
+ CCG_elem_offset_co(&key, gddata, v),
+ CCG_elem_offset_co(&key, gddata, v + gridsize));
}
for (x = 0; x < gridsize - 1; x++) {
- v1 = x + y * gridsize;
- v2 = v1 + 1;
- v3 = v1 + gridsize;
- v4 = v3 + 1;
+ const int v1 = x + y * gridsize;
+ const int v2 = v1 + 1;
+ const int v3 = v1 + gridsize;
+ const int v4 = v3 + 1;
if (smooth_mask) {
float tmp;
- tmprow_mask[x + 1] = (*CCG_elem_offset_mask(&key, data, v2) +
- *CCG_elem_offset_mask(&key, data, v4));
- tmp = tmprow_mask[x + 1] + tmprow_mask[x];
+ tmprow_mask[(x + 1) % 2] = (*CCG_elem_offset_mask(&key, gddata, v2) +
+ *CCG_elem_offset_mask(&key, gddata, v4));
+ tmp = tmprow_mask[(x + 1) % 2] + tmprow_mask[x % 2];
tmpgrid_mask[v1] += tmp;
tmpgrid_mask[v2] += tmp;
@@ -1837,10 +1804,10 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
else {
float tmp[3];
- add_v3_v3v3(tmprow_co[x + 1],
- CCG_elem_offset_co(&key, data, v2),
- CCG_elem_offset_co(&key, data, v4));
- add_v3_v3v3(tmp, tmprow_co[x + 1], tmprow_co[x]);
+ add_v3_v3v3(tmprow_co[(x + 1) % 2],
+ CCG_elem_offset_co(&key, gddata, v2),
+ CCG_elem_offset_co(&key, gddata, v4));
+ add_v3_v3v3(tmp, tmprow_co[(x + 1) % 2], tmprow_co[x % 2]);
add_v3_v3(tmpgrid_co[v1], tmp);
add_v3_v3(tmpgrid_co[v2], tmp);
@@ -1851,49 +1818,44 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
}
/* blend with existing coordinates */
- for (y = 0; y < gridsize; ++y) {
- for (x = 0; x < gridsize; ++x) {
+ for (y = 0; y < gridsize; y++) {
+ for (x = 0; x < gridsize; x++) {
float *co;
const float *fno;
float *mask;
- int index;
+ const int index = y * gridsize + x;
if (gh) {
- if (BLI_BITMAP_TEST(gh, y * gridsize + x))
+ if (BLI_BITMAP_TEST(gh, index))
continue;
}
- index = x + y * gridsize;
- co = CCG_elem_offset_co(&key, data, index);
- fno = CCG_elem_offset_no(&key, data, index);
- mask = CCG_elem_offset_mask(&key, data, index);
+ co = CCG_elem_offset_co(&key, gddata, index);
+ fno = CCG_elem_offset_no(&key, gddata, index);
+ mask = CCG_elem_offset_mask(&key, gddata, index);
if (sculpt_brush_test(&test, co)) {
- const float strength_mask = (smooth_mask ? 0 : *mask);
- const float fade = bstrength * tex_strength(ss, brush, co, test.dist,
- NULL, fno, strength_mask);
- float n = 1.0f / 16.0f;
-
+ const float strength_mask = (smooth_mask ? 0.0f : *mask);
+ const float fade = bstrength * tex_strength(
+ ss, brush, co, test.dist, NULL, fno, strength_mask, thread_id);
+ float f = 1.0f / 16.0f;
+
if (x == 0 || x == gridsize - 1)
- n *= 2;
-
+ f *= 2.0f;
+
if (y == 0 || y == gridsize - 1)
- n *= 2;
-
+ f *= 2.0f;
+
if (smooth_mask) {
- *mask += ((tmpgrid_mask[x + y * gridsize] * n) - *mask) * fade;
+ *mask += ((tmpgrid_mask[index] * f) - *mask) * fade;
}
else {
- float *avg, val[3];
-
- avg = tmpgrid_co[x + y * gridsize];
-
- mul_v3_fl(avg, n);
+ float *avg = tmpgrid_co[index];
+ float val[3];
+ mul_v3_fl(avg, f);
sub_v3_v3v3(val, avg, co);
- mul_v3_fl(val, fade);
-
- add_v3_v3(val, co);
+ madd_v3_v3v3fl(val, co, val, fade);
sculpt_clip(sd, ss, co, val);
}
@@ -1903,17 +1865,19 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
}
}
-static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
- float bstrength, int smooth_mask)
+static void smooth(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength, const bool smooth_mask)
{
SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
const int max_iterations = 4;
const float fract = 1.0f / max_iterations;
PBVHType type = BKE_pbvh_type(ss->pbvh);
- int iteration, n, count;
+ int iteration, count;
float last;
- CLAMP(bstrength, 0, 1);
+ CLAMP(bstrength, 0.0f, 1.0f);
count = (int)(bstrength * max_iterations);
last = max_iterations * (bstrength - count * fract);
@@ -1924,23 +1888,44 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
}
for (iteration = 0; iteration <= count; ++iteration) {
- float strength = (iteration != count) ? 1.0f : last;
+ const float strength = (iteration != count) ? 1.0f : last;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- switch (type) {
- case PBVH_GRIDS:
- do_multires_smooth_brush(sd, ss, nodes[n], strength,
- smooth_mask);
- break;
- case PBVH_FACES:
- do_mesh_smooth_brush(sd, ss, nodes[n], strength,
- smooth_mask);
- break;
- case PBVH_BMESH:
- do_bmesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask);
- break;
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .smooth_mask = smooth_mask, .strength = strength,
+ };
+
+ switch (type) {
+ case PBVH_GRIDS:
+ {
+ int gridsize;
+ size_t size;
+ SculptDoBrushSmoothGridDataChunk *data_chunk;
+
+ BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL, &gridsize, NULL);
+ size = (size_t)gridsize;
+ size = sizeof(float) * size * size * (smooth_mask ? 1 : 3);
+ data_chunk = MEM_mallocN(sizeof(*data_chunk) + size, __func__);
+ data_chunk->tmpgrid_size = size;
+ size += sizeof(*data_chunk);
+
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, data_chunk, size, do_smooth_brush_multires_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+
+ MEM_freeN(data_chunk);
+ break;
}
+ case PBVH_FACES:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_smooth_brush_mesh_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ break;
+ case PBVH_BMESH:
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_smooth_brush_bmesh_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+ break;
}
if (ss->multires)
@@ -1954,38 +1939,48 @@ static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
}
-static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void do_mask_brush_draw_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
- /* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
+ PBVHVertexIter vd;
+ SculptBrushTest test;
- sculpt_brush_test_init(ss, &test);
+ sculpt_brush_test_init(ss, &test);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- float fade = tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, 0);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no, vd.fno, 0.0f, thread_id);
- (*vd.mask) += fade * bstrength;
- CLAMP(*vd.mask, 0, 1);
+ (*vd.mask) += fade * bstrength;
+ CLAMP(*vd.mask, 0, 1);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
+ BKE_pbvh_vertex_iter_end;
}
}
+static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* threaded loop over nodes */
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
+
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_mask_brush_draw_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
+
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
@@ -2001,13 +1996,44 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
}
}
+static void do_draw_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
float offset[3];
- float bstrength = ss->cache->bstrength;
- int n;
+ const float bstrength = ss->cache->bstrength;
/* offset with as much as possible factored in already */
mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
@@ -2015,31 +2041,59 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .offset = offset,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_draw_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_crease_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- /* offset vertex */
- float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no,
- vd.fno, vd.mask ? *vd.mask : 0.0f);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
- mul_v3_v3fl(proxy[vd.i], offset, fade);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ /* offset vertex */
+ const float fade = tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* first we pinch */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* then we draw */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2051,7 +2105,6 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float bstrength = ss->cache->bstrength;
float flippedbstrength, crease_correction;
float brush_alpha;
- int n;
SculptProjectVector spvc;
@@ -2076,422 +2129,532 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .spvc = &spvc, .offset = offset, .flippedbstrength = flippedbstrength,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_crease_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_pinch_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- /* offset vertex */
- const float fade = tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
- float val1[3];
- float val2[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- /* first we pinch */
- sub_v3_v3v3(val1, test.location, vd.co);
- mul_v3_fl(val1, fade * flippedbstrength);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sculpt_project_v3(&spvc, val1, val1);
+ sculpt_brush_test_init(ss, &test);
- /* then we draw */
- mul_v3_v3fl(val2, offset, fade);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float val[3];
- add_v3_v3v3(proxy[vd.i], val1, val2);
+ sub_v3_v3v3(val, test.location, vd.co);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_pinch_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_grab_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, vd.no,
- vd.fno, vd.mask ? *vd.mask : 0.0f);
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- sub_v3_v3v3(val, test.location, vd.co);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float grab_delta[3];
- int n;
- float len;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- len = len_v3(grab_delta);
-
- if (brush->normal_weight > 0) {
- mul_v3_fl(ss->cache->sculpt_normal_symm, len * brush->normal_weight);
- mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
- add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
}
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_grab_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+static void do_nudge_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *cono = data->cono;
- sculpt_brush_test_init(ss, &test);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- if (sculpt_brush_test(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(ss, brush,
- orig_data.co,
- test.dist,
- orig_data.no,
- NULL, vd.mask ? *vd.mask : 0.0f);
+ sculpt_brush_test_init(ss, &test);
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float grab_delta[3];
float tmp[3], cono[3];
- int n;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .cono = cono,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_nudge_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_snake_hook_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ?
+ (2.0f * (0.5f - brush->crease_pinch_factor) * (len_v3(grab_delta) / ss->cache->radius)) : 0.0f;
- mul_v3_v3fl(proxy[vd.i], cono, fade);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* negative pinch will inflate, helps maintain volume */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+
+ /* important to calculate based on the grabbed location (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* when reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness */
+ if (pinch > 0.0f) {
+ /* square to have even less impact for close vertices */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
}
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
+ const float bstrength = ss->cache->bstrength;
float grab_delta[3];
- int n;
- float len;
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ SculptProjectVector spvc;
- len = len_v3(grab_delta);
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
if (bstrength < 0)
negate_v3(grab_delta);
- if (brush->normal_weight > 0) {
- mul_v3_fl(ss->cache->sculpt_normal_symm, len * brush->normal_weight);
- mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
- add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
}
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ /* optionally pinch while painting */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .spvc = &spvc, .grab_delta = grab_delta,
+ };
- sculpt_brush_test_init(ss, &test);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_snake_hook_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+static void do_thumb_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float grab_delta[3];
float tmp[3], cono[3];
- int n;
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .cono = cono,
+ };
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_thumb_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+static void do_rotate_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float angle = data->angle;
- sculpt_brush_test_init(ss, &test);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (sculpt_brush_test(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(ss, brush,
- orig_data.co,
- test.dist,
- orig_data.no,
- NULL, vd.mask ? *vd.mask : 0.0f);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- mul_v3_v3fl(proxy[vd.i], cono, fade);
+ sculpt_brush_test_init(ss, &test);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ float vec[3], rot[3][3];
+ const float fade = bstrength * tex_strength(
+ ss, brush, orig_data.co, test.dist, orig_data.no, NULL, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
+
static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
- float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .angle = angle,
+ };
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_rotate_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+static void do_layer_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Brush *brush = data->brush;
+ const float *offset = data->offset;
- sculpt_brush_test_init(ss, &test);
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptOrigVertData orig_data;
+ float *layer_disp;
+ const float bstrength = ss->cache->bstrength;
+ const float lim = (bstrength < 0) ? -data->brush->height : data->brush->height;
+ /* XXX: layer brush needs conversion to proxy but its more complicated */
+ /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ sculpt_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- if (sculpt_brush_test(&test, orig_data.co)) {
- float vec[3], rot[3][3];
- const float fade = bstrength * tex_strength(ss, brush,
- orig_data.co,
- test.dist,
- orig_data.no,
- NULL, vd.mask ? *vd.mask : 0.0f);
+ /* Why does this have to be thread-protected? */
+ BLI_mutex_lock(&data->mutex);
+ layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
+ BLI_mutex_unlock(&data->mutex);
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
+ sculpt_brush_test_init(ss, &test);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_orig_vert_data_update(&orig_data, &vd);
+
+ if (sculpt_brush_test(&test, orig_data.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float *disp = &layer_disp[vd.i];
+ float val[3];
+
+ *disp += fade;
+
+ /* Don't let the displacement go past the limit */
+ if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim))
+ *disp = lim;
+
+ mul_v3_v3fl(val, offset, *disp);
+
+ if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+ int index = vd.vert_indices[vd.i];
+
+ /* persistent base */
+ add_v3_v3(val, ss->layer_co[index]);
}
+ else {
+ add_v3_v3(val, orig_data.co);
+ }
+
+ sculpt_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
float offset[3];
- float lim = brush->height;
- int n;
-
- if (bstrength < 0)
- lim = -lim;
mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- SculptOrigVertData orig_data;
- float *layer_disp;
- /* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
-
- sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .offset = offset,
+ };
+ BLI_mutex_init(&data.mutex);
-#pragma omp critical
- {
- layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]);
- }
-
- sculpt_brush_test_init(ss, &test);
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_layer_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_orig_vert_data_update(&orig_data, &vd);
+ BLI_mutex_end(&data.mutex);
+}
- if (sculpt_brush_test(&test, orig_data.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
- float *disp = &layer_disp[vd.i];
- float val[3];
+static void do_inflate_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
- *disp += fade;
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- /* Don't let the displacement go past the limit */
- if ((lim < 0 && *disp < lim) || (lim >= 0 && *disp > lim))
- *disp = lim;
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- mul_v3_v3fl(val, offset, *disp);
+ sculpt_brush_test_init(ss, &test);
- if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- int index = vd.vert_indices[vd.i];
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, test.dist, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+ float val[3];
- /* persistent base */
- add_v3_v3(val, ss->layer_co[index]);
- }
- else {
- add_v3_v3(val, orig_data.co);
- }
+ if (vd.fno)
+ copy_v3_v3(val, vd.fno);
+ else
+ normal_short_to_float_v3(val, vd.no);
- sculpt_clip(sd, ss, vd.co, val);
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
- SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- int n;
-
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
-
- sculpt_brush_test_init(ss, &test);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test(&test, vd.co)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
- float val[3];
-
- if (vd.fno) copy_v3_v3(val, vd.fno);
- else normal_short_to_float_v3(val, vd.no);
-
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_inflate_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
}
static void calc_sculpt_plane(
@@ -2619,23 +2782,61 @@ static float get_offset(Sculpt *sd, SculptSession *ss)
return rv;
}
+static void do_flatten_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, area_no, area_co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float area_no[3];
float area_co[3];
float offset = get_offset(sd, ss);
-
float displace;
-
- int n;
-
float temp[3];
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
@@ -2646,19 +2847,39 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_flatten_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_clay_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
float intr[3];
float val[3];
@@ -2667,8 +2888,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2677,8 +2901,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2686,30 +2910,18 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- float radius = ss->cache->radius;
- float offset = get_offset(sd, ss);
-
+ const bool flip = (ss->cache->bstrength < 0);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+
+ float offset = get_offset(sd, ss);
float displace;
float area_no[3];
float area_co[3];
-
- int n;
-
float temp[3];
- bool flip;
-
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
- flip = bstrength < 0;
-
- if (flip) {
- bstrength = -bstrength;
- radius = -radius;
- }
-
displace = radius * (0.25f + offset);
mul_v3_v3v3(temp, area_no, ss->cache->scale);
@@ -2718,43 +2930,63 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* add_v3_v3v3(p, ss->cache->location, area_no); */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_clay_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_clay_strips_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ float (*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side_flip(vd.co, area_no, area_co, flip)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
- point_plane_project(intr, vd.co, area_no, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- /* note, the normal from the vertices is ignored,
- * causes glitch with planes, see: T44390 */
- const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_cube(&test, vd.co, mat)) {
+ if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
+ float intr[3];
+ float val[3];
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ point_plane_project(intr, vd.co, area_no_sp, area_co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ /* note, the normal from the vertices is ignored,
+ * causes glitch with planes, see: T44390 */
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, ss->cache->radius * test.dist,
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2762,25 +2994,20 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
- float radius = ss->cache->radius;
- float offset = get_offset(sd, ss);
-
- float displace;
+ const bool flip = (ss->cache->bstrength < 0);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = get_offset(sd, ss);
+ const float displace = radius * (0.25f + offset);;
float area_no_sp[3]; /* the sculpt-plane normal (whatever its set to) */
float area_no[3]; /* geometry normal */
float area_co[3];
- int n;
-
float temp[3];
float mat[4][4];
float scale[4][4];
float tmat[4][4];
- bool flip;
-
calc_sculpt_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
@@ -2792,15 +3019,6 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
if (ss->cache->first_time)
return;
- flip = bstrength < 0;
-
- if (flip) {
- bstrength = -bstrength;
- radius = -radius;
- }
-
- displace = radius * (0.25f + offset);
-
mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
@@ -2821,44 +3039,59 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
mul_m4_m4m4(tmat, mat, scale);
invert_m4_m4(mat, tmat);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no_sp = area_no_sp, .area_co = area_co, .mat = mat,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_clay_strips_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_fill_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_cube(&test, vd.co, mat)) {
- if (plane_point_side_flip(vd.co, area_no_sp, area_co, flip)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- point_plane_project(intr, vd.co, area_no_sp, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- /* note, the normal from the vertices is ignored,
- * causes glitch with planes, see: T44390 */
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- ss->cache->radius * test.dist,
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (plane_point_side(vd.co, area_no, area_co)) {
+ float intr[3];
+ float val[3];
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ point_plane_project(intr, vd.co, area_no, area_co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f, thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2866,7 +3099,6 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float area_no[3];
@@ -2875,8 +3107,6 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float displace;
- int n;
-
float temp[3];
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
@@ -2887,42 +3117,59 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_fill_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_scrape_brush_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (plane_point_side(vd.co, area_no, area_co)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
- point_plane_project(intr, vd.co, area_no, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (!plane_point_side(vd.co, area_no, area_co)) {
+ float intr[3];
+ float val[3];
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ point_plane_project(intr, vd.co, area_no, area_co);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2930,7 +3177,6 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float bstrength = ss->cache->bstrength;
const float radius = ss->cache->radius;
float area_no[3];
@@ -2939,8 +3185,6 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
float displace;
- int n;
-
float temp[3];
calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
@@ -2951,42 +3195,45 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
mul_v3_fl(temp, displace);
add_v3_v3(area_co, temp);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .area_no = area_no, .area_co = area_co,
+ };
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_scrape_brush_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
+}
- sculpt_brush_test_init(ss, &test);
+static void do_gravity_task_cb_ex(
+ void *userdata, void *UNUSED(userdata_chunk), const int n, const int thread_id)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Brush *brush = data->brush;
+ float *offset = data->offset;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- if (!plane_point_side(vd.co, area_no, area_co)) {
- float intr[3];
- float val[3];
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
- point_plane_project(intr, vd.co, area_no, area_co);
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
- sub_v3_v3v3(val, intr, vd.co);
+ sculpt_brush_test_init(ss, &test);
- if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrtf(test.dist),
- vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ const float fade = tex_strength(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f,
+ thread_id);
- mul_v3_v3fl(proxy[vd.i], val, fade);
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
+ if (vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- BKE_pbvh_vertex_iter_end;
}
+ BKE_pbvh_vertex_iter_end;
}
static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength)
@@ -2995,7 +3242,6 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
Brush *brush = BKE_paint_brush(&sd->paint);
float offset[3]/*, area_no[3]*/;
- int n;
float gravity_vector[3];
mul_v3_v3fl(gravity_vector, ss->cache->gravity_direction, -ss->cache->radius_squared);
@@ -3005,29 +3251,14 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
- float (*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
-
- sculpt_brush_test_init(ss, &test);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (sculpt_brush_test_sq(&test, vd.co)) {
- const float fade = tex_strength(ss, brush, vd.co, sqrtf(test.dist), vd.no,
- vd.fno, vd.mask ? *vd.mask : 0.0f);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .offset = offset,
+ };
- if (vd.mvert)
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range_ex(
+ 0, totnode, &data, NULL, 0, do_gravity_task_cb_ex,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT), false);
}
@@ -3137,12 +3368,21 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush, Unified
}
}
+static void do_brush_action_task_cb(void *userdata, const int n)
+{
+ SculptThreadedTaskData *data = userdata;
+
+ sculpt_undo_push_node(data->ob, data->nodes[n],
+ data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+}
+
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
{
SculptSession *ss = ob->sculpt;
SculptSearchSphereData data;
PBVHNode **nodes = NULL;
- int n, totnode;
+ int totnode;
/* Build a list of all nodes that are potentially within the brush's area of influence */
data.ss = ss;
@@ -3155,15 +3395,15 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (totnode) {
float location[3];
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- sculpt_undo_push_node(ob, nodes[n],
- brush->sculpt_tool == SCULPT_TOOL_MASK ?
- SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(nodes[n]);
- }
+ SculptThreadedTaskData task_data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
+
+ BLI_task_parallel_range(
+ 0, totnode, &task_data, do_brush_action_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
- if (sculpt_brush_needs_normal(brush))
+ if (sculpt_brush_needs_normal(brush, ss->cache->normal_weight))
update_sculpt_normal(sd, ob, nodes, totnode);
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_AREA)
@@ -3273,64 +3513,76 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
copy_v3_v3(me->mvert[index].co, newco);
}
-static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
+static void sculpt_combine_proxies_task_cb(void *userdata, const int n)
{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- PBVHNode **nodes;
- int totnode, n;
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ Object *ob = data->ob;
- BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ /* these brushes start from original coordinates */
+ const bool use_orco = ELEM(data->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
- /* first line is tools that don't support proxies */
- if (ss->cache->supports_gravity ||
- (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
+ PBVHVertexIter vd;
+ PBVHProxyNode *proxies;
+ int proxy_count;
+ float (*orco)[3] = NULL;
+
+ if (use_orco && !ss->bm)
+ orco = sculpt_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS)->co;
+
+ BKE_pbvh_node_get_proxies(data->nodes[n], &proxies, &proxy_count);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- /* these brushes start from original coordinates */
- const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ float val[3];
+ int p;
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- PBVHProxyNode *proxies;
- int proxy_count;
- float (*orco)[3] = NULL;
+ if (use_orco) {
+ if (ss->bm) {
+ copy_v3_v3(val, BM_log_original_vert_co(ss->bm_log, vd.bm_vert));
+ }
+ else {
+ copy_v3_v3(val, orco[vd.i]);
+ }
+ }
+ else {
+ copy_v3_v3(val, vd.co);
+ }
- if (use_orco && !ss->bm)
- orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co;
+ for (p = 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
- BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+ sculpt_clip(sd, ss, vd.co, val);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- float val[3];
- int p;
+ if (ss->modifiers_active)
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+ }
+ BKE_pbvh_vertex_iter_end;
- if (use_orco) {
- if (ss->bm) {
- copy_v3_v3(val,
- BM_log_original_vert_co(ss->bm_log,
- vd.bm_vert));
- }
- else
- copy_v3_v3(val, orco[vd.i]);
- }
- else
- copy_v3_v3(val, vd.co);
+ BKE_pbvh_node_free_proxies(data->nodes[n]);
+}
- for (p = 0; p < proxy_count; p++)
- add_v3_v3(val, proxies[p].co[vd.i]);
+static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ PBVHNode **nodes;
+ int totnode;
- sculpt_clip(sd, ss, vd.co, val);
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
- if (ss->modifiers_active)
- sculpt_flush_pbvhvert_deform(ob, &vd);
- }
- BKE_pbvh_vertex_iter_end;
+ /* first line is tools that don't support proxies */
+ if (ss->cache->supports_gravity ||
+ (sculpt_tool_is_proxy_used(brush->sculpt_tool) == false))
+ {
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ };
- BKE_pbvh_node_free_proxies(nodes[n]);
- }
+ BLI_task_parallel_range(
+ 0, totnode, &data, sculpt_combine_proxies_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
}
if (nodes)
@@ -3356,6 +3608,27 @@ static void sculpt_update_keyblock(Object *ob)
}
}
+static void sculpt_flush_stroke_deform_task_cb(void *userdata, const int n)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Object *ob = data->ob;
+ float (*vertCos)[3] = data->vertCos;
+
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ sculpt_flush_pbvhvert_deform(ob, &vd);
+
+ if (vertCos) {
+ int index = vd.vert_indices[vd.i];
+ copy_v3_v3(vertCos[index], ss->orig_cos[index]);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
/* flush displacement from deformed PBVH to original layer */
static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
{
@@ -3366,7 +3639,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
/* this brushes aren't using proxies, so sculpt_combine_proxies() wouldn't
* propagate needed deformation to original base */
- int n, totnode;
+ int totnode;
Mesh *me = (Mesh *)ob->data;
PBVHNode **nodes;
float (*vertCos)[3] = NULL;
@@ -3378,26 +3651,19 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
* to deal with this we copy old coordinates over new ones
* and then update coordinates for all vertices from BVH
*/
- memcpy(vertCos, ss->orig_cos, 3 * sizeof(float) * me->totvert);
+ memcpy(vertCos, ss->orig_cos, sizeof(*vertCos) * me->totvert);
}
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
+ SculptThreadedTaskData data = {
+ .sd = sd, .ob = ob, .brush = brush, .nodes = nodes,
+ .vertCos = vertCos,
+ };
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- sculpt_flush_pbvhvert_deform(ob, &vd);
-
- if (vertCos) {
- int index = vd.vert_indices[vd.i];
- copy_v3_v3(vertCos[index], ss->orig_cos[index]);
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
+ BLI_task_parallel_range(
+ 0, totnode, &data, sculpt_flush_stroke_deform_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
if (vertCos) {
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -3458,6 +3724,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
flip_v3_v3(cache->gravity_direction, cache->true_gravity_direction, symm);
mul_m4_v3(cache->symm_rot_mat, cache->gravity_direction);
}
+
+ if (cache->is_rake_rotation_valid) {
+ flip_qt_qt(cache->rake_rotation_symmetry, cache->rake_rotation, symm);
+ }
}
typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups);
@@ -3714,83 +3984,6 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
}
}
-static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
-{
- StrokeCache *cache = ss->cache;
-
-#ifdef _OPENMP
-
-#if defined(__APPLE__)
- cache->init_num_threads = BLI_system_thread_count();
-#else
- cache->init_num_threads = omp_get_max_threads();
-#endif
- /* If using OpenMP then create a number of threads two times the
- * number of processor cores.
- * Justification: Empirically I've found that two threads per
- * processor gives higher throughput. */
- if (sd->flags & SCULPT_USE_OPENMP) {
-#if defined(__APPLE__)
- cache->num_threads = system_physical_thread_count();
-#else
- cache->num_threads = 2 * omp_get_num_procs();
-#endif
- }
- else {
- cache->num_threads = 1;
- }
- omp_set_num_threads(cache->num_threads);
-#else
- (void)sd;
- cache->num_threads = 1;
-#endif
- if (ss->multires) {
- int i, gridsize, array_mem_size;
- BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
- &gridsize, NULL);
-
- array_mem_size = cache->num_threads * sizeof(void *);
-
- cache->tmpgrid_co = MEM_mallocN(array_mem_size, "tmpgrid_co array");
- cache->tmprow_co = MEM_mallocN(array_mem_size, "tmprow_co array");
- cache->tmpgrid_mask = MEM_mallocN(array_mem_size, "tmpgrid_mask array");
- cache->tmprow_mask = MEM_mallocN(array_mem_size, "tmprow_mask array");
-
- for (i = 0; i < cache->num_threads; i++) {
- const size_t row_size = sizeof(float) * gridsize;
- const size_t co_row_size = 3 * row_size;
-
- cache->tmprow_co[i] = MEM_mallocN(co_row_size, "tmprow_co");
- cache->tmpgrid_co[i] = MEM_mallocN(co_row_size * gridsize, "tmpgrid_co");
- cache->tmprow_mask[i] = MEM_mallocN(row_size, "tmprow_mask");
- cache->tmpgrid_mask[i] = MEM_mallocN(row_size * gridsize, "tmpgrid_mask");
- }
- }
-}
-
-static void sculpt_omp_done(SculptSession *ss)
-{
-#ifdef _OPENMP
- omp_set_num_threads(ss->cache->init_num_threads);
-#endif
-
- if (ss->multires) {
- int i;
-
- for (i = 0; i < ss->cache->num_threads; i++) {
- MEM_freeN(ss->cache->tmpgrid_co[i]);
- MEM_freeN(ss->cache->tmprow_co[i]);
- MEM_freeN(ss->cache->tmpgrid_mask[i]);
- MEM_freeN(ss->cache->tmprow_mask[i]);
- }
-
- MEM_freeN(ss->cache->tmpgrid_co);
- MEM_freeN(ss->cache->tmprow_co);
- MEM_freeN(ss->cache->tmpgrid_mask);
- MEM_freeN(ss->cache->tmprow_mask);
- }
-}
-
/* Initialize the stroke cache invariants from operator properties */
static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
{
@@ -3837,6 +4030,15 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
mode = RNA_enum_get(op->ptr, "mode");
cache->invert = mode == BRUSH_STROKE_INVERT;
cache->alt_smooth = mode == BRUSH_STROKE_SMOOTH;
+ cache->normal_weight = brush->normal_weight;
+
+ /* interpret invert as following normal, for grab brushes */
+ if (SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool)) {
+ if (cache->invert) {
+ cache->invert = false;
+ cache->normal_weight = (cache->normal_weight == 0.0f);
+ }
+ }
/* not very nice, but with current events system implementation
* we can't handle brush appearance inversion hotkey separately (sergey) */
@@ -3951,8 +4153,6 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
cache->dial = BLI_dial_initialize(cache->initial_mouse, PIXEL_INPUT_THRESHHOLD);
#undef PIXEL_INPUT_THRESHHOLD
-
- sculpt_omp_start(sd, ss);
}
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
@@ -4030,6 +4230,54 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
ups->anchored_size = ups->pixel_radius;
}
+
+
+ /* handle 'rake' */
+ cache->is_rake_rotation_valid = false;
+
+ if (cache->first_time) {
+ copy_v3_v3(cache->rake_data.follow_co, grab_location);
+ }
+
+ if (sculpt_brush_needs_rake_rotation(brush)) {
+ cache->rake_data.follow_dist = cache->radius * SCULPT_RAKE_BRUSH_FACTOR;
+
+ if (!is_zero_v3(cache->grab_delta)) {
+ const float eps = 0.00001f;
+
+ float v1[3], v2[3];
+
+ copy_v3_v3(v1, cache->rake_data.follow_co);
+ copy_v3_v3(v2, cache->rake_data.follow_co);
+ sub_v3_v3(v2, cache->grab_delta);
+
+ sub_v3_v3(v1, grab_location);
+ sub_v3_v3(v2, grab_location);
+
+ if ((normalize_v3(v2) > eps) &&
+ (normalize_v3(v1) > eps) &&
+ (len_squared_v3v3(v1, v2) > eps))
+ {
+ const float rake_dist_sq = len_squared_v3v3(cache->rake_data.follow_co, grab_location);
+ const float rake_fade = (rake_dist_sq > SQUARE(cache->rake_data.follow_dist)) ?
+ 1.0f : sqrtf(rake_dist_sq) / cache->rake_data.follow_dist;
+
+ float axis[3], angle;
+ float tquat[4];
+
+ rotation_between_vecs_to_quat(tquat, v1, v2);
+
+ /* use axis-angle to scale rotation since the factor may be above 1 */
+ quat_to_axis_angle(axis, &angle, tquat);
+ normalize_v3(axis);
+
+ angle *= brush->rake_factor * rake_fade;
+ axis_angle_normalized_to_quat(cache->rake_rotation, axis, angle);
+ cache->is_rake_rotation_valid = true;
+ }
+ }
+ sculpt_rake_data_update(&cache->rake_data, grab_location);
+ }
}
}
@@ -4494,8 +4742,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- sculpt_omp_done(ss);
-
/* Finished */
if (ss->cache) {
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -4522,7 +4768,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_cache_free(ss->cache);
ss->cache = NULL;
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
@@ -4602,8 +4848,11 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ const Brush *brush = BKE_paint_brush(&sd->paint);
- if (ss->cache) {
+ /* XXX Canceling strokes that way does not work with dynamic topology, user will have to do real undo for now.
+ * See T46456. */
+ if (ss->cache && !sculpt_stroke_is_dynamic_topology(ss, brush)) {
paint_mesh_restore_co(sd, ob);
}
@@ -4677,7 +4926,7 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
static void sculpt_dynamic_topology_triangulate(BMesh *bm)
{
if (bm->totloop != bm->totface * 3) {
- BM_mesh_triangulate(bm, MOD_TRIANGULATE_QUAD_FIXED, MOD_TRIANGULATE_NGON_EARCLIP, false, NULL, NULL);
+ BM_mesh_triangulate(bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, false, NULL, NULL, NULL);
}
}
@@ -4846,7 +5095,7 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
sculpt_dynamic_topology_enable(C);
sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
}
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
return OPERATOR_FINISHED;
}
@@ -5008,7 +5257,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
/* Finish undo */
BM_log_all_added(ss->bm, ss->bm_log);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
/* Redraw */
sculpt_pbvh_clear(ob);
@@ -5149,6 +5398,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
paint_cursor_start(C, sculpt_poll_view3d);
}
+ if (ob->derivedFinal) /* VBO no longer valid */
+ GPU_drawobject_free(ob->derivedFinal);
+
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
return OPERATOR_FINISHED;
@@ -5216,7 +5468,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
MEM_freeN(nodes);
- sculpt_undo_push_end();
+ sculpt_undo_push_end(C);
/* force rebuild of pbvh for better BB placement */
sculpt_pbvh_clear(ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 8f1a4655c37..108fe3532e3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -118,17 +118,12 @@ typedef struct SculptUndoNode {
SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
void sculpt_undo_push_begin(const char *name);
-void sculpt_undo_push_end(void);
+void sculpt_undo_push_end(const struct bContext *C);
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void sculpt_update_object_bounding_box(struct Object *ob);
-/* Setting zero so we can catch bugs in OpenMP/sculpt. */
-#ifdef DEBUG
-# define SCULPT_OMP_LIMIT 0
-#else
-# define SCULPT_OMP_LIMIT 4
-#endif
+#define SCULPT_THREADED_LIMIT 4
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 1f1be51b9a6..ceefda99002 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -41,6 +41,7 @@
#include "BLI_string.h"
#include "BLI_listbase.h"
#include "BLI_ghash.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "DNA_meshdata_types.h"
@@ -78,28 +79,57 @@ static void update_cb(PBVHNode *node, void *rebuild)
BKE_pbvh_node_fully_hidden_set(node, 0);
}
-static void sculpt_undo_restore_deformed(const SculptSession *ss,
- SculptUndoNode *unode,
- int uindex, int oindex,
- float coord[3])
+struct PartialUpdateData {
+ PBVH *pbvh;
+ bool rebuild;
+};
+
+/**
+ * A version of #update_cb that tests for 'ME_VERT_PBVH_UPDATE'
+ */
+static void update_cb_partial(PBVHNode *node, void *userdata)
+{
+ struct PartialUpdateData *data = userdata;
+ if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
+ update_cb(node, &(data->rebuild));
+ }
+}
+
+static bool test_swap_v3_v3(float a[3], float b[3])
{
- if (unode->orig_co) {
- swap_v3_v3(coord, unode->orig_co[uindex]);
+ /* no need for float comparison here (memory is exactly equal or not) */
+ if (memcmp(a, b, sizeof(float[3])) != 0) {
+ swap_v3_v3(a, b);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static bool sculpt_undo_restore_deformed(
+ const SculptSession *ss,
+ SculptUndoNode *unode,
+ int uindex, int oindex,
+ float coord[3])
+{
+ if (test_swap_v3_v3(coord, unode->orig_co[uindex])) {
copy_v3_v3(unode->co[uindex], ss->deform_cos[oindex]);
+ return true;
}
else {
- swap_v3_v3(coord, unode->co[uindex]);
+ return false;
}
}
-static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNode *unode)
+static bool sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNode *unode)
{
Scene *scene = CTX_data_scene(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
MVert *mvert;
- int *index, i, j;
+ int *index;
if (unode->maxvert) {
/* regular mesh restore */
@@ -122,6 +152,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
}
}
+ /* no need for float comparison here (memory is exactly equal or not) */
index = unode->index;
mvert = ss->mvert;
@@ -129,13 +160,21 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
float (*vertCos)[3];
vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
- for (i = 0; i < unode->totvert; i++) {
+ if (unode->orig_co) {
if (ss->modifiers_active) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ for (int i = 0; i < unode->totvert; i++) {
+ sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ }
}
else {
- if (unode->orig_co) swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
- else swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ for (int i = 0; i < unode->totvert; i++) {
+ swap_v3_v3(vertCos[index[i]], unode->orig_co[i]);
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < unode->totvert; i++) {
+ swap_v3_v3(vertCos[index[i]], unode->co[i]);
}
}
@@ -149,15 +188,28 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
MEM_freeN(vertCos);
}
else {
- for (i = 0; i < unode->totvert; i++) {
+ if (unode->orig_co) {
if (ss->modifiers_active) {
- sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
+ for (int i = 0; i < unode->totvert; i++) {
+ if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) {
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
}
else {
- if (unode->orig_co) swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
- else swap_v3_v3(mvert[index[i]].co, unode->co[i]);
+ for (int i = 0; i < unode->totvert; i++) {
+ if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) {
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ else {
+ for (int i = 0; i < unode->totvert; i++) {
+ if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) {
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
}
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -173,19 +225,21 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
dm->getGridKey(dm, &key);
co = unode->co;
- for (j = 0; j < unode->totgrid; j++) {
+ for (int j = 0; j < unode->totgrid; j++) {
grid = grids[unode->grids[j]];
- for (i = 0; i < gridsize * gridsize; i++, co++)
+ for (int i = 0; i < gridsize * gridsize; i++, co++) {
swap_v3_v3(CCG_elem_offset_co(&key, grid, i), co[0]);
+ }
}
}
return 1;
}
-static int sculpt_undo_restore_hidden(bContext *C, DerivedMesh *dm,
- SculptUndoNode *unode)
+static bool sculpt_undo_restore_hidden(
+ bContext *C, DerivedMesh *dm,
+ SculptUndoNode *unode)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
@@ -196,16 +250,11 @@ static int sculpt_undo_restore_hidden(bContext *C, DerivedMesh *dm,
for (i = 0; i < unode->totvert; i++) {
MVert *v = &mvert[unode->index[i]];
- int uval = BLI_BITMAP_TEST(unode->vert_hidden, i);
-
- BLI_BITMAP_SET(unode->vert_hidden, i,
- v->flag & ME_HIDE);
- if (uval)
- v->flag |= ME_HIDE;
- else
- v->flag &= ~ME_HIDE;
-
- v->flag |= ME_VERT_PBVH_UPDATE;
+ if ((BLI_BITMAP_TEST(unode->vert_hidden, i) != 0) != ((v->flag & ME_HIDE) != 0)) {
+ BLI_BITMAP_FLIP(unode->vert_hidden, i);
+ v->flag ^= ME_HIDE;
+ v->flag |= ME_VERT_PBVH_UPDATE;
+ }
}
}
else if (unode->maxgrid && dm->getGridData) {
@@ -222,7 +271,7 @@ static int sculpt_undo_restore_hidden(bContext *C, DerivedMesh *dm,
return 1;
}
-static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode *unode)
+static bool sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode *unode)
{
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
@@ -238,8 +287,10 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode
vmask = ss->vmask;
for (i = 0; i < unode->totvert; i++) {
- SWAP(float, vmask[index[i]], unode->mask[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ if (vmask[index[i]] != unode->mask[i]) {
+ SWAP(float, vmask[index[i]], unode->mask[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
}
}
else if (unode->maxgrid && dm->getGridData) {
@@ -265,6 +316,13 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode
return 1;
}
+static void sculpt_undo_bmesh_restore_generic_task_cb(void *userdata, const int n)
+{
+ PBVHNode **nodes = userdata;
+
+ BKE_pbvh_node_mark_redraw(nodes[n]);
+}
+
static void sculpt_undo_bmesh_restore_generic(bContext *C,
SculptUndoNode *unode,
Object *ob,
@@ -280,21 +338,15 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
}
if (unode->type == SCULPT_UNDO_MASK) {
- int i, totnode;
+ int totnode;
PBVHNode **nodes;
-
-#ifdef _OPENMP
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-#else
- (void)C;
-#endif
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
- for (i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
+ BLI_task_parallel_range(
+ 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb,
+ ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT));
if (nodes)
MEM_freeN(nodes);
@@ -402,6 +454,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
SculptUndoNode *unode;
bool update = false, rebuild = false;
bool need_mask = false;
+ bool partial_update = true;
for (unode = lb->first; unode; unode = unode->next) {
if (STREQ(unode->idname, ob->id.name)) {
@@ -438,6 +491,9 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
{
continue;
}
+
+ /* multi-res can't do partial updates since it doesn't flag edited vertices */
+ partial_update = false;
}
switch (unode->type) {
@@ -467,7 +523,16 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
/* we update all nodes still, should be more clever, but also
* needs to work correct when exiting/entering sculpt mode and
* the nodes get recreated, though in that case it could do all */
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
+ if (partial_update) {
+ struct PartialUpdateData data = {
+ .rebuild = rebuild,
+ .pbvh = ss->pbvh,
+ };
+ BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
+ }
+ else {
+ BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
+ }
BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL);
if (BKE_sculpt_multires_active(scene, ob)) {
@@ -481,8 +546,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
if (ss->kb || ss->modifiers_active) {
Mesh *mesh = ob->data;
- BKE_mesh_calc_normals_tessface(mesh->mvert, mesh->totvert,
- mesh->mface, mesh->totface, NULL);
+ BKE_mesh_calc_normals(mesh);
BKE_sculptsession_free_deformMats(ss);
tag_update |= true;
@@ -884,7 +948,7 @@ void sculpt_undo_push_begin(const char *name)
sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup);
}
-void sculpt_undo_push_end(void)
+void sculpt_undo_push_end(const bContext *C)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
@@ -901,4 +965,6 @@ void sculpt_undo_push_end(void)
}
ED_undo_paint_push_end(UNDO_PAINT_MESH);
+
+ WM_file_tag_modified(C);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 405ac3f6808..fd2a0b15cb9 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -157,7 +157,7 @@ static Brush *uv_sculpt_brush(bContext *C)
}
-static int uv_sculpt_brush_poll(bContext *C)
+static int uv_sculpt_brush_poll_do(bContext *C, const bool check_region)
{
BMEditMesh *em;
int ret;
@@ -177,11 +177,17 @@ static int uv_sculpt_brush_poll(bContext *C)
if (ret) {
ARegion *ar = CTX_wm_region(C);
- if ((toolsettings->use_uv_sculpt) && ar->regiontype == RGN_TYPE_WINDOW)
- return 1;
+ if ((!toolsettings->use_uv_sculpt) || (check_region && ar && (ar->regiontype != RGN_TYPE_WINDOW))) {
+ ret = 0;
+ }
}
- return 0;
+ return ret;
+}
+
+static int uv_sculpt_brush_poll(bContext *C)
+{
+ return uv_sculpt_brush_poll_do(C, true);
}
static void brush_drawcursor_uvsculpt(bContext *C, int x, int y, void *UNUSED(customdata))
@@ -252,7 +258,12 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, Scene *scene)
int uv_sculpt_poll(bContext *C)
{
- return uv_sculpt_brush_poll(C);
+ return uv_sculpt_brush_poll_do(C, true);
+}
+
+int uv_sculpt_keymap_poll(bContext *C)
+{
+ return uv_sculpt_brush_poll_do(C, false);
}
/*********** Improved Laplacian Relaxation Operator ************************/
diff --git a/source/blender/editors/sound/SConscript b/source/blender/editors/sound/SConscript
deleted file mode 100644
index fad52c64df1..00000000000
--- a/source/blender/editors/sound/SConscript
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
-
-if env['WITH_BF_SNDFILE']:
- defs.append('WITH_SNDFILE')
-
-env.BlenderLib ( 'bf_editors_sound', sources, Split(incs), defs, libtype=['core'], priority=[35] )
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index f8d84cc0276..a4d9a920cbb 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -137,7 +137,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- sound->id.us--;
+ id_us_min(&sound->id);
RNA_id_pointer_create(&sound->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
@@ -185,10 +185,11 @@ static void SOUND_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
- RNA_def_boolean(ot->srna, "mono", false, "Mono", "Mixdown the sound to mono");
+ RNA_def_boolean(ot->srna, "mono", false, "Mono", "Merge all the sound's channels into one");
}
static void SOUND_OT_open_mono(wmOperatorType *ot)
@@ -207,8 +208,9 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
RNA_def_boolean(ot->srna, "mono", true, "Mono", "Mixdown the sound to mono");
}
@@ -652,10 +654,13 @@ static void SOUND_OT_mixdown(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
#ifdef WITH_AUDASPACE
- RNA_def_int(ot->srna, "accuracy", 1024, 1, 16777216, "Accuracy", "Sample accuracy, important for animation data (the lower the value, the more accurate)", 1, 16777216);
+ RNA_def_int(ot->srna, "accuracy", 1024, 1, 16777216, "Accuracy",
+ "Sample accuracy, important for animation data (the lower the value, the more accurate)",
+ 1, 16777216);
RNA_def_enum(ot->srna, "container", container_items, AUD_CONTAINER_FLAC, "Container", "File format");
RNA_def_enum(ot->srna, "codec", codec_items, AUD_CODEC_FLAC, "Codec", "Audio Codec");
RNA_def_enum(ot->srna, "format", format_items, AUD_FORMAT_S16, "Format", "Sample format");
@@ -778,7 +783,7 @@ static void SOUND_OT_unpack(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
+ RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Sound Name", "Sound datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
}
diff --git a/source/blender/editors/space_action/SConscript b/source/blender/editors/space_action/SConscript
deleted file mode 100644
index 346324e129d..00000000000
--- a/source/blender/editors/space_action/SConscript
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-env.BlenderLib ( 'bf_editors_space_action', sources, Split(incs), defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index c3519423773..a3be7791f9a 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -133,7 +133,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact)
* for that here
*/
BLI_assert(action->id.us == 1);
- action->id.us--;
+ id_us_min(&action->id);
/* set ID-Root type */
if (sa->spacetype == SPACE_ACTION) {
@@ -581,10 +581,7 @@ void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act,
}
/* Clear Fake User */
- if (act->id.flag & LIB_FAKEUSER) {
- act->id.flag &= ~LIB_FAKEUSER;
- act->id.us--;
- }
+ id_fake_user_clear(&act->id);
}
/* If in Tweak Mode, don't unlink. Instead, this
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index e351fb57d9a..b69547b0506 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -55,6 +55,7 @@
#include "BKE_action.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_key.h"
@@ -430,13 +431,7 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
return actkeys_viewall(C, true);
}
-static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
-{
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- ANIM_center_frame(C, smooth_viewtx);
-
- return OPERATOR_FINISHED;
-}
+/* ......... */
void ACTION_OT_view_all(wmOperatorType *ot)
{
@@ -468,17 +463,27 @@ void ACTION_OT_view_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ****************** View-All Operator ****************** */
+
+static int actkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
void ACTION_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
ot->name = "View Frame";
ot->idname = "ACTION_OT_view_frame";
ot->description = "Reset viewable area to show range around current frame";
-
+
/* api callbacks */
ot->exec = actkeys_view_frame_exec;
- ot->poll = ED_operator_action_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
-
+ ot->poll = ED_operator_action_active;
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -495,7 +500,7 @@ static short copy_action_keys(bAnimContext *ac)
int filter, ok = 0;
/* clear buffer first */
- free_anim_copybuf();
+ ANIM_fcurves_copybuf_free();
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
@@ -549,9 +554,10 @@ static int actkeys_copy_exec(bContext *C, wmOperator *op)
/* copy keyframes */
if (ac.datatype == ANIMCONT_GPENCIL) {
- /* FIXME... */
- BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for grease pencil mode");
- return OPERATOR_CANCELLED;
+ if (ED_gpencil_anim_copybuf_copy(&ac) == false) {
+ /* Nothing got copied - An error about this should be been logged already */
+ return OPERATOR_CANCELLED;
+ }
}
else if (ac.datatype == ANIMCONT_MASK) {
/* FIXME... */
@@ -599,7 +605,13 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
ac.reports = op->reports;
/* paste keyframes */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false) {
+ /* An error occurred - Reports should have been fired already */
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if (ac.datatype == ANIMCONT_MASK) {
/* FIXME... */
BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for grease pencil or mask mode");
return OPERATOR_CANCELLED;
@@ -634,8 +646,8 @@ void ACTION_OT_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
- RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
+ RNA_def_enum(ot->srna, "offset", rna_enum_keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
+ RNA_def_enum(ot->srna, "merge", rna_enum_keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -650,7 +662,7 @@ static EnumPropertyItem prop_actkeys_insertkey_types[] = {
{0, NULL, 0, NULL, NULL}
};
-/* this function is responsible for snapping keyframes to frame-times */
+/* this function is responsible for inserting new keyframes */
static void insert_action_keys(bAnimContext *ac, short mode)
{
ListBase anim_data = {NULL, NULL};
@@ -659,6 +671,7 @@ static void insert_action_keys(bAnimContext *ac, short mode)
ReportList *reports = ac->reports;
Scene *scene = ac->scene;
+ ToolSettings *ts = scene->toolsettings;
short flag = 0;
/* filter data */
@@ -690,13 +703,48 @@ static void insert_action_keys(bAnimContext *ac, short mode)
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
if (ale->id && !ale->owner)
- insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
+ insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
else
- insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
-
+ insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+/* this function is for inserting new grease pencil frames */
+static void insert_gpencil_keys(bAnimContext *ac, short mode)
+{
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ Scene *scene = ac->scene;
+ ToolSettings *ts = scene->toolsettings;
+ eGP_GetFrame_Mode add_frame_mode;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ if (mode == 2) filter |= ANIMFILTER_SEL;
+
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+
+ /* add a copy or a blank frame? */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST)
+ add_frame_mode = GP_GETFRAME_ADD_COPY; /* XXX: actframe may not be what we want? */
+ else
+ add_frame_mode = GP_GETFRAME_ADD_NEW;
+
+
+ /* insert gp frames */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ gpencil_layer_getframe(gpl, CFRA, add_frame_mode);
+ }
+
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -711,14 +759,22 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
+
+ if (ac.datatype == ANIMCONT_MASK) {
+ BKE_report(op->reports, RPT_ERROR, "Insert Keyframes is not yet implemented for this mode");
return OPERATOR_CANCELLED;
+ }
/* what channels to affect? */
mode = RNA_enum_get(op->ptr, "type");
/* insert keyframes */
- insert_action_keys(&ac, mode);
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ insert_gpencil_keys(&ac, mode);
+ }
+ else {
+ insert_action_keys(&ac, mode);
+ }
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
@@ -851,16 +907,16 @@ static bool delete_action_keys(bAnimContext *ac)
ale->key_data = NULL;
}
}
-
+
if (changed) {
ale->update |= ANIM_UPDATE_DEFAULT;
changed_final = true;
}
}
-
+
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
-
+
return changed_final;
}
@@ -1223,7 +1279,7 @@ void ACTION_OT_interpolation_type(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
}
/* ******************** Set Handle-Type Operator *********************** */
@@ -1305,7 +1361,7 @@ void ACTION_OT_handle_type(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", keyframe_handle_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
}
/* ******************** Set Keyframe-Type Operator *********************** */
@@ -1407,7 +1463,7 @@ void ACTION_OT_keyframe_type(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", beztriple_keyframe_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", "");
}
/* ************************************************************************** */
@@ -1535,9 +1591,9 @@ static void snap_action_keys(bAnimContext *ac, short mode)
ED_masklayer_snap_frames(ale->data, ac->scene, mode);
}
else if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
@@ -1642,16 +1698,21 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ if (ale->type == ANIMTYPE_GPLAYER) {
+ ED_gplayer_mirror_frames(ale->data, ac->scene, mode);
+ }
+ else if (ale->type == ANIMTYPE_MASKLAYER) {
+ /* TODO */
+ }
+ else if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
- //else if (ale->type == ACTTYPE_GPLAYER)
- // snap_gplayer_frames(ale->data, mode);
- else
+ else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
-
+ }
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1670,10 +1731,6 @@ static int actkeys_mirror_exec(bContext *C, wmOperator *op)
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
- /* XXX... */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
- return OPERATOR_PASS_THROUGH;
-
/* get mirroring mode */
mode = RNA_enum_get(op->ptr, "type");
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 3c9c88a0ae6..f2813b2a8d3 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -244,10 +244,12 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
/* if channel is mapped in NLA, apply correction */
if (adt) {
+ ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
}
else {
+ ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
ked.f1 = rectf.xmin;
ked.f2 = rectf.xmax;
}
@@ -948,6 +950,7 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s
select_cb = ANIM_editkeyframes_select(select_mode);
ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME);
ked.f1 = selx;
+ ked.iterflags |= KED_F1_NLA_UNMAP;
/* select the nominated keyframe on the given frame */
if (ale->type == ANIMTYPE_GPLAYER) {
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 5d0b34a2e0c..53c5a008af8 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -63,6 +63,7 @@
static SpaceLink *action_new(const bContext *C)
{
+ Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
SpaceAction *saction;
ARegion *ar;
@@ -83,7 +84,7 @@ static SpaceLink *action_new(const bContext *C)
ar->alignment = RGN_ALIGN_BOTTOM;
/* channel list region */
- ar = MEM_callocN(sizeof(ARegion), "channel area for action");
+ ar = MEM_callocN(sizeof(ARegion), "channel region for action");
BLI_addtail(&saction->regionbase, ar);
ar->regiontype = RGN_TYPE_CHANNELS;
ar->alignment = RGN_ALIGN_LEFT;
@@ -92,15 +93,15 @@ static SpaceLink *action_new(const bContext *C)
ar->v2d.scroll = V2D_SCROLL_BOTTOM;
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for action");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for action");
BLI_addtail(&saction->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
- ar->v2d.tot.xmin = -10.0f;
+ ar->v2d.tot.xmin = (float)(SFRA - 10);
ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
- ar->v2d.tot.xmax = (float)(sa->winx);
+ ar->v2d.tot.xmax = (float)(EFRA + 10);
ar->v2d.tot.ymax = 0.0f;
ar->v2d.cur = ar->v2d.tot;
@@ -149,7 +150,7 @@ static SpaceLink *action_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
-static void action_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void action_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -160,7 +161,7 @@ static void action_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void action_main_area_draw(const bContext *C, ARegion *ar)
+static void action_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceAction *saction = CTX_wm_space_action(C);
@@ -218,7 +219,7 @@ static void action_main_area_draw(const bContext *C, ARegion *ar)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void action_channel_area_init(wmWindowManager *wm, ARegion *ar)
+static void action_channel_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -232,7 +233,7 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void action_channel_area_draw(const bContext *C, ARegion *ar)
+static void action_channel_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
bAnimContext ac;
@@ -257,17 +258,17 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar)
/* add handlers, stuff you only do once or on area/region changes */
-static void action_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void action_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void action_header_area_draw(const bContext *C, ARegion *ar)
+static void action_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void action_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -295,6 +296,10 @@ static void action_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
break;
}
break;
+ case NC_GPENCIL:
+ if (wmn->action == NA_RENAME)
+ ED_region_tag_redraw(ar);
+ break;
case NC_ID:
if (wmn->action == NA_RENAME)
ED_region_tag_redraw(ar);
@@ -306,7 +311,7 @@ static void action_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
}
-static void action_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -457,7 +462,7 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
}
-static void action_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void action_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
// SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
@@ -543,9 +548,9 @@ void ED_spacetype_action(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype action region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = action_main_area_init;
- art->draw = action_main_area_draw;
- art->listener = action_main_area_listener;
+ art->init = action_main_region_init;
+ art->draw = action_main_region_draw;
+ art->listener = action_main_region_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@@ -556,9 +561,9 @@ void ED_spacetype_action(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = action_header_area_init;
- art->draw = action_header_area_draw;
- art->listener = action_header_area_listener;
+ art->init = action_header_region_init;
+ art->draw = action_header_region_draw;
+ art->listener = action_header_region_listener;
BLI_addhead(&st->regiontypes, art);
@@ -568,9 +573,9 @@ void ED_spacetype_action(void)
art->prefsizex = 200;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
- art->init = action_channel_area_init;
- art->draw = action_channel_area_draw;
- art->listener = action_channel_area_listener;
+ art->init = action_channel_region_init;
+ art->draw = action_channel_region_draw;
+ art->listener = action_channel_region_listener;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_api/SConscript b/source/blender/editors/space_api/SConscript
deleted file mode 100644
index 2ba918ffc84..00000000000
--- a/source/blender/editors/space_api/SConscript
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- '#/extern/glew/include',
- '../include',
- '../io',
- '../../blenkernel',
- '../../blenlib',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = ''
-
-env.BlenderLib ( 'bf_editors_space_api', sources, Split(incs), Split(defs), libtype=['core'], priority=[30] )
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 01f0d1ae54f..ac6e3123e4e 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -120,7 +120,7 @@ void ED_spacetypes_init(void)
ED_operatortypes_io();
ED_operatortypes_view2d();
- ED_button_operatortypes();
+ ED_operatortypes_ui();
/* register operators */
spacetypes = BKE_spacetypes_list();
@@ -188,6 +188,7 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
ED_keymap_marker(keyconf);
ED_keymap_view2d(keyconf);
+ ED_keymap_ui(keyconf);
spacetypes = BKE_spacetypes_list();
for (stype = spacetypes->first; stype; stype = stype->next) {
@@ -249,8 +250,10 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *ar, int type)
RegionDrawCB *rdc;
for (rdc = ar->type->drawcalls.first; rdc; rdc = rdc->next) {
- if (rdc->type == type)
+ if (rdc->type == type) {
+ UI_reinit_gl_state();
rdc->draw(C, ar, rdc->customdata);
+ }
}
}
diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
deleted file mode 100644
index c39df449647..00000000000
--- a/source/blender/editors/space_buttons/SConscript
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-env.BlenderLib ( 'bf_editors_space_buttons', sources, Split(incs), defs, libtype=['core'], priority=[120] )
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index b8b56f8f848..fc1b6877f5e 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -219,17 +219,30 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
fbo->is_undo = is_undo;
op->customdata = fbo;
- RNA_string_set(op->ptr, path_prop, str);
- MEM_freeN(str);
-
/* normally ED_fileselect_get_params would handle this but we need to because of stupid
* user-prefs exception - campbell */
if ((prop_relpath = RNA_struct_find_property(op->ptr, "relative_path"))) {
if (!RNA_property_is_set(op->ptr, prop_relpath)) {
+ bool is_relative = (U.flag & USER_RELPATHS) != 0;
+
+ /* while we want to follow the defaults,
+ * we better not switch existing paths relative/absolute state. */
+ if (str[0]) {
+ is_relative = BLI_path_is_rel(str);
+ }
+
+ if (UNLIKELY(ptr.data == &U)) {
+ is_relative = false;
+ }
+
/* annoying exception!, if were dealing with the user prefs, default relative to be off */
- RNA_property_boolean_set(op->ptr, prop_relpath, U.flag & USER_RELPATHS && (ptr.data != &U));
+ RNA_property_boolean_set(op->ptr, prop_relpath, is_relative);
}
}
+
+ RNA_string_set(op->ptr, path_prop, str);
+ MEM_freeN(str);
+
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -252,8 +265,9 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, 0, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/* second operator, only difference from BUTTONS_OT_file_browse is WM_FILESEL_DIRECTORY */
@@ -273,6 +287,7 @@ void BUTTONS_OT_directory_browse(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, 0, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index b56ff850c35..58c538c4ee5 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -314,7 +314,7 @@ static void buttons_texture_modifier_foreach(void *userData, Object *ob, Modifie
prop = RNA_struct_find_property(&ptr, propname);
buttons_texture_user_property_add(users, &ob->id, ptr, prop,
- "Modifiers", RNA_struct_ui_icon(ptr.type), md->name);
+ N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name);
}
static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts)
@@ -366,13 +366,13 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
BLI_listbase_clear(users);
if (ma && !limited_mode)
- buttons_texture_users_find_nodetree(users, &ma->id, ma->nodetree, "Material");
+ buttons_texture_users_find_nodetree(users, &ma->id, ma->nodetree, N_("Material"));
if (la && !limited_mode)
- buttons_texture_users_find_nodetree(users, &la->id, la->nodetree, "Lamp");
+ buttons_texture_users_find_nodetree(users, &la->id, la->nodetree, N_("Lamp"));
if (wrld && !limited_mode)
- buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, "World");
+ buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, N_("World"));
if (linestyle && !limited_mode)
- buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, "Line Style");
+ buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, N_("Line Style"));
if (ob) {
ParticleSystem *psys = psys_get_current(ob);
@@ -394,8 +394,8 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
RNA_pointer_create(&psys->part->id, &RNA_ParticleSettingsTextureSlot, mtex, &ptr);
prop = RNA_struct_find_property(&ptr, "texture");
- buttons_texture_user_property_add(users, &psys->part->id, ptr, prop,
- "Particles", RNA_struct_ui_icon(&RNA_ParticleSettings), psys->name);
+ buttons_texture_user_property_add(users, &psys->part->id, ptr, prop, N_("Particles"),
+ RNA_struct_ui_icon(&RNA_ParticleSettings), psys->name);
}
}
}
@@ -409,7 +409,7 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
prop = RNA_struct_find_property(&ptr, "texture");
buttons_texture_user_property_add(users, &ob->id, ptr, prop,
- "Fields", ICON_FORCE_TEXTURE, "Texture Field");
+ N_("Fields"), ICON_FORCE_TEXTURE, IFACE_("Texture Field"));
}
}
@@ -423,14 +423,14 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
prop = RNA_struct_find_property(&ptr, "texture");
buttons_texture_user_property_add(users, &brush->id, ptr, prop,
- "Brush", ICON_BRUSH_DATA, "Brush");
+ N_("Brush"), ICON_BRUSH_DATA, IFACE_("Brush"));
/* mask texture */
RNA_pointer_create(&brush->id, &RNA_BrushTextureSlot, &brush->mask_mtex, &ptr);
prop = RNA_struct_find_property(&ptr, "texture");
buttons_texture_user_property_add(users, &brush->id, ptr, prop,
- "Brush", ICON_BRUSH_DATA, "Brush Mask");
+ N_("Brush"), ICON_BRUSH_DATA, IFACE_("Brush Mask"));
}
}
@@ -539,6 +539,9 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg)
if (user->ptr.data == part->mtex[a])
part->texact = a;
}
+
+ if (sbuts && tex)
+ sbuts->preview = 1;
}
ct->user = user;
@@ -560,7 +563,7 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
/* add label per category */
if (!last_category || !STREQ(last_category, user->category)) {
- uiItemL(layout, user->category, ICON_NONE);
+ uiItemL(layout, IFACE_(user->category), ICON_NONE);
but = block->buttons.last;
but->drawflag = UI_BUT_TEXT_LEFT;
}
@@ -678,7 +681,7 @@ void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, Prope
uiBut *but;
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_BUTS, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, "Show texture in texture tab");
+ NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Show texture in texture tab"));
UI_but_func_set(but, template_texture_show, user->ptr.data, user->prop);
}
}
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index e28ad686d2a..126a27c36cb 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -66,15 +66,15 @@ static SpaceLink *buttons_new(const bContext *UNUSED(C))
ar->alignment = RGN_ALIGN_TOP;
#if 0
- /* context area */
- ar = MEM_callocN(sizeof(ARegion), "context area for buts");
+ /* context region */
+ ar = MEM_callocN(sizeof(ARegion), "context region for buts");
BLI_addtail(&sbuts->regionbase, ar);
ar->regiontype = RGN_TYPE_CHANNELS;
ar->alignment = RGN_ALIGN_TOP;
#endif
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for buts");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for buts");
BLI_addtail(&sbuts->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -123,7 +123,7 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void buttons_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void buttons_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -133,7 +133,7 @@ static void buttons_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void buttons_main_area_draw(const bContext *C, ARegion *ar)
+static void buttons_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceButs *sbuts = CTX_wm_space_buts(C);
@@ -189,12 +189,12 @@ static void buttons_keymap(struct wmKeyConfig *keyconf)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void buttons_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void buttons_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void buttons_header_area_draw(const bContext *C, ARegion *ar)
+static void buttons_header_region_draw(const bContext *C, ARegion *ar)
{
SpaceButs *sbuts = CTX_wm_space_buts(C);
@@ -410,8 +410,8 @@ void ED_spacetype_buttons(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = buttons_main_area_init;
- art->draw = buttons_main_area_draw;
+ art->init = buttons_main_region_init;
+ art->draw = buttons_main_region_draw;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@@ -423,8 +423,8 @@ void ED_spacetype_buttons(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = buttons_header_area_init;
- art->draw = buttons_header_area_draw;
+ art->init = buttons_header_region_init;
+ art->draw = buttons_header_region_draw;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index d17d1856502..32d48c9c564 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -53,9 +53,17 @@ set(SRC
clip_utils.c
space_clip.c
tracking_ops.c
+ tracking_ops_detect.c
+ tracking_ops_orient.c
+ tracking_ops_plane.c
+ tracking_ops_solve.c
+ tracking_ops_track.c
+ tracking_ops_stabilize.c
+ tracking_ops_utils.c
tracking_select.c
clip_intern.h
+ tracking_ops_intern.h
)
add_definitions(${GL_DEFINITIONS})
diff --git a/source/blender/editors/space_clip/SConscript b/source/blender/editors/space_clip/SConscript
deleted file mode 100644
index 37b83946e93..00000000000
--- a/source/blender/editors/space_clip/SConscript
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'bf_editors_space_clip', sources, Split(incs), defs, libtype=['core'], priority=[95] )
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 62bb372514b..1c5be3d1fb5 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -58,6 +58,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "WM_types.h"
#include "UI_interface.h"
@@ -286,7 +288,6 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
MovieClip *clip = ED_space_clip_get_clip(sc);
int filter = GL_LINEAR;
int x, y;
- rctf frame;
/* find window pixel coordinates of origin */
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
@@ -313,10 +314,12 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar,
/* reset zoom */
glPixelZoom(1.0f, 1.0f);
- BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
- if (sc->flag & SC_SHOW_METADATA)
- ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
+ if (sc->flag & SC_SHOW_METADATA) {
+ rctf frame;
+ BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
+ ED_region_image_metadata_draw(x, y, ibuf, &frame, zoomx * width / ibuf->x, zoomy * height / ibuf->y);
+ }
if (ibuf->planes == 32)
glDisable(GL_BLEND);
@@ -436,7 +439,6 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
for (i = a; i < b; i++)
glVertex2f(path[i][0], path[i][1]);
glEnd();
- glLineWidth(1.0f);
}
UI_ThemeColor(TH_PATH_BEFORE);
@@ -456,6 +458,8 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
UI_ThemeColor(TH_PATH_BEFORE);
+ glLineWidth(1);
+
glBegin(GL_LINE_STRIP);
for (i = a; i < b; i++) {
if (i == count + 1)
@@ -464,7 +468,6 @@ static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackin
glVertex2f(path[i][0], path[i][1]);
}
glEnd();
- glPointSize(1.0f);
}
static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
@@ -479,6 +482,8 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
px[0] = 1.0f / width / sc->zoom;
px[1] = 1.0f / height / sc->zoom;
+ glLineWidth(tiny ? 1.0f : 3.0f);
+
if ((marker->flag & MARKER_DISABLED) == 0) {
float pos[2];
float p[2];
@@ -492,15 +497,12 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
if (isect_point_quad_v2(p, marker->pattern_corners[0], marker->pattern_corners[1],
marker->pattern_corners[2], marker->pattern_corners[3]))
{
- if (tiny) glPointSize(3.0f);
- else glPointSize(4.0f);
+ glPointSize(tiny ? 3.0f : 4.0f);
glBegin(GL_POINTS);
glVertex2f(pos[0], pos[1]);
glEnd();
- glPointSize(1.0f);
}
else {
- if (!tiny) glLineWidth(3.0f);
glBegin(GL_LINES);
glVertex2f(pos[0] + px[0] * 2, pos[1]);
glVertex2f(pos[0] + px[0] * 8, pos[1]);
@@ -514,7 +516,6 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
glVertex2f(pos[0], pos[1] + px[1] * 2);
glVertex2f(pos[0], pos[1] + px[1] * 8);
glEnd();
- if (!tiny) glLineWidth(1.0f);
}
}
@@ -522,9 +523,6 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
glPushMatrix();
glTranslate2fv(marker_pos);
- if (!tiny)
- glLineWidth(3.0f);
-
if (sc->flag & SC_SHOW_MARKER_PATTERN) {
glBegin(GL_LINE_LOOP);
glVertex2fv(marker->pattern_corners[0]);
@@ -545,9 +543,6 @@ static void draw_marker_outline(SpaceClip *sc, MovieTrackingTrack *track, MovieT
glEnd();
}
glPopMatrix();
-
- if (!tiny)
- glLineWidth(1.0f);
}
static void track_colors(MovieTrackingTrack *track, int act, float col[3], float scol[3])
@@ -582,6 +577,8 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
px[0] = 1.0f / width / sc->zoom;
px[1] = 1.0f / height / sc->zoom;
+ glLineWidth(1.0f);
+
/* marker position and offset position */
if ((track->flag & SELECT) == sel && (marker->flag & MARKER_DISABLED) == 0) {
float pos[2], p[2];
@@ -609,15 +606,10 @@ static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTra
if (isect_point_quad_v2(p, marker->pattern_corners[0], marker->pattern_corners[1],
marker->pattern_corners[2], marker->pattern_corners[3]))
{
- if (!tiny)
- glPointSize(2.0f);
-
+ glPointSize(tiny ? 1.0f : 2.0f);
glBegin(GL_POINTS);
glVertex2f(pos[0], pos[1]);
glEnd();
-
- if (!tiny)
- glPointSize(1.0f);
}
else {
glBegin(GL_LINES);
@@ -800,7 +792,6 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
track_colors(track, act, col, scol);
if (outline) {
- glLineWidth(3.0f);
UI_ThemeColor(TH_MARKER_OUTLINE);
}
@@ -859,26 +850,11 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
+ glLineWidth(outline ? 3.0f : 1.0f);
+
glEnable(GL_LINE_STIPPLE);
glLineStipple(3, 0xaaaa);
-#if 0
- /* TODO: disable for now, needs better approach visualizing this */
-
- glBegin(GL_LINE_LOOP);
- glVertex2f(pat_min[0] - dx, pat_min[1] - dy);
- glVertex2f(pat_max[0] + dx, pat_min[1] - dy);
- glVertex2f(pat_max[0] + dx, pat_max[1] + dy);
- glVertex2f(pat_min[0] - dx, pat_max[1] + dy);
- glEnd();
-
- /* marker's offset slider */
- draw_marker_slide_square(pat_min[0] - dx, pat_max[1] + dy, patdx, patdy, outline, px);
-
- /* pattern re-sizing triangle */
- draw_marker_slide_triangle(pat_max[0] + dx, pat_min[1] - dy, patdx, patdy, outline, px);
-#endif
-
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2fv(tilt_ctrl);
@@ -892,9 +868,6 @@ static void draw_marker_slide_zones(SpaceClip *sc, MovieTrackingTrack *track, Mo
}
glPopMatrix();
-
- if (outline)
- glLineWidth(1.0f);
}
static void draw_marker_texts(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
@@ -1062,7 +1035,7 @@ static void draw_plane_marker_image(Scene *scene,
}
if (display_buffer) {
- GLuint texid, last_texid;
+ GLuint texid;
float frame_corners[4][2] = {{0.0f, 0.0f},
{1.0f, 0.0f},
{1.0f, 1.0f},
@@ -1082,11 +1055,9 @@ static void draw_plane_marker_image(Scene *scene,
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(1.0, 1.0, 1.0, plane_track->image_opacity);
- last_texid = glaGetOneInteger(GL_TEXTURE_2D);
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glGenTextures(1, (GLuint *)&texid);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -1109,8 +1080,8 @@ static void draw_plane_marker_image(Scene *scene,
glPopMatrix();
- glBindTexture(GL_TEXTURE_2D, last_texid);
- glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if (transparent) {
glDisable(GL_BLEND);
@@ -1156,17 +1127,18 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
draw_plane_marker_image(scene, plane_track, plane_marker);
}
- if (draw_outline) {
- if (!tiny) {
- glLineWidth(3.0f);
+ if (draw_plane_quad) {
+
+ const bool stipple = !draw_outline && tiny;
+ const bool thick = draw_outline && !tiny;
+
+ if (stipple) {
+ glLineStipple(3, 0xaaaa);
+ glEnable(GL_LINE_STIPPLE);
}
- }
- else if (tiny) {
- glLineStipple(3, 0xaaaa);
- glEnable(GL_LINE_STIPPLE);
- }
- if (draw_plane_quad) {
+ glLineWidth(thick ? 3.0f : 1.0f);
+
/* Draw rectangle itself. */
glBegin(GL_LINE_LOOP);
glVertex2fv(plane_marker->corners[0]);
@@ -1180,22 +1152,25 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
float end_point[2];
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT);
+ glBegin(GL_LINES);
+
getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[1], end_point);
glColor3f(1.0, 0.0, 0.0f);
- glBegin(GL_LINES);
glVertex2fv(plane_marker->corners[0]);
glVertex2fv(end_point);
- glEnd();
getArrowEndPoint(width, height, sc->zoom, plane_marker->corners[0], plane_marker->corners[3], end_point);
glColor3f(0.0, 1.0, 0.0f);
- glBegin(GL_LINES);
glVertex2fv(plane_marker->corners[0]);
glVertex2fv(end_point);
+
glEnd();
glPopAttrib();
}
+
+ if (stipple)
+ glDisable(GL_LINE_STIPPLE);
}
/* Draw sliders. */
@@ -1206,15 +1181,6 @@ static void draw_plane_marker_ex(SpaceClip *sc, Scene *scene, MovieTrackingPlane
3.0f * px[0], 3.0f * px[1], draw_outline, px);
}
}
-
- if (draw_outline) {
- if (!tiny) {
- glLineWidth(1.0f);
- }
- }
- else if (tiny) {
- glDisable(GL_LINE_STIPPLE);
- }
}
static void draw_plane_marker_outline(SpaceClip *sc, Scene *scene, MovieTrackingPlaneTrack *plane_track,
@@ -1259,7 +1225,7 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
/* ** find window pixel coordinates of origin ** */
/* UI_view2d_view_to_region_no_clip return integer values, this could
- * lead to 1px flickering when view is locked to selection during playbeck.
+ * lead to 1px flickering when view is locked to selection during playback.
* to avoid this flickering, calculate base point in the same way as it happens
* in UI_view2d_view_to_region_no_clip, but do it in floats here */
@@ -1450,7 +1416,6 @@ static void draw_tracking_tracks(SpaceClip *sc, Scene *scene, ARegion *ar, Movie
track = track->next;
}
- glPointSize(1.0f);
glDisable(GL_POINT_SMOOTH);
}
@@ -1674,9 +1639,6 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
layer = layer->next;
}
-
- glLineWidth(1.0f);
- glPointSize(1.0f);
}
glPopMatrix();
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index dbedfaa1de4..1ff656243d6 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -779,7 +779,7 @@ static unsigned char *prefetch_thread_next_frame(
return mem;
}
-static void prefetch_task_func(TaskPool *pool, void *task_data, int UNUSED(threadid))
+static void prefetch_task_func(TaskPool * __restrict pool, void *task_data, int UNUSED(threadid))
{
PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
MovieClip *clip = (MovieClip *)task_data;
diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c
index 2c3b8acf672..424d25defdd 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -115,8 +115,6 @@ static void tracking_segment_start_cb(void *userdata, MovieTrackingTrack *track,
static void tracking_segment_end_cb(void *UNUSED(userdata), int UNUSED(coord))
{
glEnd();
-
- glLineWidth(1.0f);
}
typedef struct TrackMotionCurveUserData {
@@ -261,7 +259,6 @@ static void tracking_error_segment_end_cb(void *UNUSED(userdata), int coord)
{
if (coord == 1) {
glEnd();
- glLineWidth(1.0f);
}
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 55805e0b907..085fdd57309 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -57,6 +57,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_report.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_sound.h"
@@ -213,7 +214,7 @@ static int open_exec(bContext *C, wmOperator *op)
errno = 0;
- clip = BKE_movieclip_file_add(bmain, str);
+ clip = BKE_movieclip_file_add_exists(bmain, str);
if (!clip) {
if (op->customdata)
@@ -234,7 +235,7 @@ static int open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- clip->id.us--;
+ id_us_min(&clip->id);
RNA_id_pointer_create(&clip->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
@@ -299,8 +300,9 @@ void CLIP_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_RELPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************* reload clip operator *********************/
@@ -1179,7 +1181,7 @@ static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip
return mem;
}
-static void proxy_task_func(TaskPool *pool, void *task_data, int UNUSED(threadid))
+static void proxy_task_func(TaskPool * __restrict pool, void *task_data, int UNUSED(threadid))
{
ProxyThread *data = (ProxyThread *)task_data;
ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool);
@@ -1400,7 +1402,7 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
ot->poll = ED_space_clip_poll;
/* properties */
- RNA_def_enum(ot->srna, "mode", clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
+ RNA_def_enum(ot->srna, "mode", rna_enum_clip_editor_mode_items, SC_MODE_TRACKING, "Mode", "");
}
/********************** NDOF operator *********************/
@@ -1533,7 +1535,7 @@ static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op)
bool show_cursor = false;
show_cursor |= sclip->mode == SC_MODE_MASKEDIT;
- show_cursor |= sclip->around == V3D_CURSOR;
+ show_cursor |= sclip->around == V3D_AROUND_CURSOR;
if (!show_cursor) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 48f8f587106..5964e9a898b 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -247,23 +247,18 @@ void clip_draw_cfra(SpaceClip *sc, ARegion *ar, Scene *scene)
{
View2D *v2d = &ar->v2d;
float xscale, yscale;
- float vec[2];
/* Draw a light green line to indicate current frame */
- vec[0] = (float)(sc->user.framenr * scene->r.framelen);
-
UI_ThemeColor(TH_CFRAME);
- glLineWidth(2.0);
- glBegin(GL_LINE_STRIP);
- vec[1] = v2d->cur.ymin;
- glVertex2fv(vec);
+ float x = (float)(sc->user.framenr * scene->r.framelen);
- vec[1] = v2d->cur.ymax;
- glVertex2fv(vec);
- glEnd();
+ glLineWidth(2.0);
- glLineWidth(1.0);
+ glBegin(GL_LINES);
+ glVertex2f(x, v2d->cur.ymin);
+ glVertex2f(x, v2d->cur.ymax);
+ glEnd();
UI_view2d_view_orthoSpecial(ar, v2d, 1);
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index f119fe23c12..e1d4e4fabc5 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -250,7 +250,7 @@ static SpaceLink *clip_new(const bContext *C)
sc->zoom = 1.0f;
sc->path_length = 20;
sc->scopes.track_preview_height = 120;
- sc->around = V3D_LOCAL;
+ sc->around = V3D_AROUND_LOCAL_ORIGINS;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for clip");
@@ -296,8 +296,8 @@ static SpaceLink *clip_new(const bContext *C)
BLI_addtail(&sc->regionbase, ar);
init_preview_region(C, ar);
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for clip");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for clip");
BLI_addtail(&sc->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -1132,7 +1132,7 @@ static void movieclip_main_area_set_view2d(const bContext *C, ARegion *ar)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void clip_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void clip_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1150,7 +1150,7 @@ static void clip_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void clip_main_area_draw(const bContext *C, ARegion *ar)
+static void clip_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -1213,7 +1213,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar)
}
show_cursor |= sc->mode == SC_MODE_MASKEDIT;
- show_cursor |= sc->around == V3D_CURSOR;
+ show_cursor |= sc->around == V3D_AROUND_CURSOR;
if (show_cursor) {
glPushMatrix();
@@ -1241,7 +1241,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar)
}
}
-static void clip_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1256,7 +1256,7 @@ static void clip_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR
/****************** preview region ******************/
-static void clip_preview_area_init(wmWindowManager *wm, ARegion *ar)
+static void clip_preview_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1273,7 +1273,7 @@ static void clip_preview_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void graph_area_draw(const bContext *C, ARegion *ar)
+static void graph_region_draw(const bContext *C, ARegion *ar)
{
View2D *v2d = &ar->v2d;
View2DScrollers *scrollers;
@@ -1304,7 +1304,7 @@ static void graph_area_draw(const bContext *C, ARegion *ar)
UI_view2d_scrollers_free(scrollers);
}
-static void dopesheet_area_draw(const bContext *C, ARegion *ar)
+static void dopesheet_region_draw(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -1342,23 +1342,23 @@ static void dopesheet_area_draw(const bContext *C, ARegion *ar)
UI_view2d_scrollers_free(scrollers);
}
-static void clip_preview_area_draw(const bContext *C, ARegion *ar)
+static void clip_preview_region_draw(const bContext *C, ARegion *ar)
{
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc->view == SC_VIEW_GRAPH)
- graph_area_draw(C, ar);
+ graph_region_draw(C, ar);
else if (sc->view == SC_VIEW_DOPESHEET)
- dopesheet_area_draw(C, ar);
+ dopesheet_region_draw(C, ar);
}
-static void clip_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void clip_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
}
/****************** channels region ******************/
-static void clip_channels_area_init(wmWindowManager *wm, ARegion *ar)
+static void clip_channels_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1371,7 +1371,7 @@ static void clip_channels_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void clip_channels_area_draw(const bContext *C, ARegion *ar)
+static void clip_channels_region_draw(const bContext *C, ARegion *ar)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -1393,24 +1393,24 @@ static void clip_channels_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
-static void clip_channels_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void clip_channels_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
}
/****************** header region ******************/
/* add handlers, stuff you only do once or on area/region changes */
-static void clip_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void clip_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void clip_header_area_draw(const bContext *C, ARegion *ar)
+static void clip_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void clip_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1433,7 +1433,7 @@ static void clip_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
/****************** tools region ******************/
/* add handlers, stuff you only do once or on area/region changes */
-static void clip_tools_area_init(wmWindowManager *wm, ARegion *ar)
+static void clip_tools_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1443,14 +1443,14 @@ static void clip_tools_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void clip_tools_area_draw(const bContext *C, ARegion *ar)
+static void clip_tools_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
/****************** tool properties region ******************/
-static void clip_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1476,7 +1476,7 @@ static void clip_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A
/****************** properties region ******************/
/* add handlers, stuff you only do once or on area/region changes */
-static void clip_properties_area_init(wmWindowManager *wm, ARegion *ar)
+static void clip_properties_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1486,7 +1486,7 @@ static void clip_properties_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void clip_properties_area_draw(const bContext *C, ARegion *ar)
+static void clip_properties_region_draw(const bContext *C, ARegion *ar)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -1495,7 +1495,7 @@ static void clip_properties_area_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void clip_properties_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1535,9 +1535,9 @@ void ED_spacetype_clip(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype clip region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = clip_main_area_init;
- art->draw = clip_main_area_draw;
- art->listener = clip_main_area_listener;
+ art->init = clip_main_region_init;
+ art->draw = clip_main_region_draw;
+ art->listener = clip_main_region_listener;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
@@ -1546,9 +1546,9 @@ void ED_spacetype_clip(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype clip region preview");
art->regionid = RGN_TYPE_PREVIEW;
art->prefsizey = 240;
- art->init = clip_preview_area_init;
- art->draw = clip_preview_area_draw;
- art->listener = clip_preview_area_listener;
+ art->init = clip_preview_region_init;
+ art->draw = clip_preview_region_draw;
+ art->listener = clip_preview_region_listener;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
BLI_addhead(&st->regiontypes, art);
@@ -1558,9 +1558,9 @@ void ED_spacetype_clip(void)
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_COMPACT_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
- art->init = clip_properties_area_init;
- art->draw = clip_properties_area_draw;
- art->listener = clip_properties_area_listener;
+ art->init = clip_properties_region_init;
+ art->draw = clip_properties_region_draw;
+ art->listener = clip_properties_region_listener;
BLI_addhead(&st->regiontypes, art);
ED_clip_buttons_register(art);
@@ -1569,9 +1569,9 @@ void ED_spacetype_clip(void)
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = UI_COMPACT_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
- art->listener = clip_props_area_listener;
- art->init = clip_tools_area_init;
- art->draw = clip_tools_area_draw;
+ art->listener = clip_props_region_listener;
+ art->init = clip_tools_region_init;
+ art->draw = clip_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
@@ -1581,9 +1581,9 @@ void ED_spacetype_clip(void)
art->prefsizex = 0;
art->prefsizey = 120;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
- art->listener = clip_props_area_listener;
- art->init = clip_tools_area_init;
- art->draw = clip_tools_area_draw;
+ art->listener = clip_props_region_listener;
+ art->init = clip_tools_region_init;
+ art->draw = clip_tools_region_draw;
ED_clip_tool_props_register(art);
BLI_addhead(&st->regiontypes, art);
@@ -1594,9 +1594,9 @@ void ED_spacetype_clip(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
- art->init = clip_header_area_init;
- art->draw = clip_header_area_draw;
- art->listener = clip_header_area_listener;
+ art->init = clip_header_region_init;
+ art->draw = clip_header_region_draw;
+ art->listener = clip_header_region_listener;
BLI_addhead(&st->regiontypes, art);
@@ -1607,9 +1607,9 @@ void ED_spacetype_clip(void)
art->regionid = RGN_TYPE_CHANNELS;
art->prefsizex = UI_COMPACT_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI;
- art->listener = clip_channels_area_listener;
- art->init = clip_channels_area_init;
- art->draw = clip_channels_area_draw;
+ art->listener = clip_channels_region_listener;
+ art->init = clip_channels_region_init;
+ art->draw = clip_channels_region_draw;
BLI_addhead(&st->regiontypes, art);
}
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index a19fa97965a..61bfa5b315b 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -31,28 +31,19 @@
#include "MEM_guardedalloc.h"
-#include "DNA_camera_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_object_types.h" /* SELECT */
-#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
-#include "BLI_listbase.h"
#include "BLI_blenlib.h"
-#include "BKE_main.h"
#include "BKE_context.h"
-#include "BKE_constraint.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
-#include "BKE_global.h"
#include "BKE_depsgraph.h"
-#include "BKE_object.h"
#include "BKE_report.h"
-#include "BKE_library.h"
#include "BKE_sound.h"
#include "WM_api.h"
@@ -61,19 +52,13 @@
#include "ED_screen.h"
#include "ED_clip.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "BLT_translation.h"
-#include "PIL_time.h"
-
-
-#include "clip_intern.h" // own include
+#include "clip_intern.h"
+#include "tracking_ops_intern.h"
/********************** add marker operator *********************/
@@ -117,7 +102,9 @@ static int add_marker_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* reset offset from locked position, so frame jumping wouldn't be so confusing */
+ /* Reset offset from locked position, so frame jumping wouldn't be so
+ * confusing.
+ */
sc->xlockof = 0;
sc->ylockof = 0;
@@ -163,28 +150,35 @@ void CLIP_OT_add_marker(wmOperatorType *ot)
/********************** add marker operator *********************/
-static int add_marker_at_click_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int add_marker_at_click_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
{
- ED_area_headerprint(CTX_wm_area(C), IFACE_("Use LMB click to define location where place the marker"));
+ ED_area_headerprint(
+ CTX_wm_area(C),
+ IFACE_("Use LMB click to define location where place the marker"));
- /* add modal handler for ESC */
+ /* Add modal handler for ESC. */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
-static int add_marker_at_click_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int add_marker_at_click_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ARegion *ar = CTX_wm_region(C);
- float pos[2];
-
switch (event->type) {
case MOUSEMOVE:
return OPERATOR_RUNNING_MODAL;
case LEFTMOUSE:
+ {
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ARegion *ar = CTX_wm_region(C);
+ float pos[2];
+
ED_area_headerprint(CTX_wm_area(C), NULL);
ED_clip_point_stable_pos(sc, ar,
@@ -192,11 +186,13 @@ static int add_marker_at_click_modal(bContext *C, wmOperator *UNUSED(op), const
event->y - ar->winrct.ymin,
&pos[0], &pos[1]);
- if (!add_marker(C, pos[0], pos[1]))
+ if (!add_marker(C, pos[0], pos[1])) {
return OPERATOR_CANCELLED;
+ }
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
return OPERATOR_FINISHED;
+ }
case ESCKEY:
ED_area_headerprint(CTX_wm_area(C), NULL);
@@ -229,15 +225,13 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- MovieTrackingTrack *track = tracksbase->first, *next;
- MovieTrackingPlaneTrack *plane_track, *next_plane_track;
bool changed = false;
/* Delete selected plane tracks. */
- for (plane_track = plane_tracks_base->first;
- plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first,
+ *next_plane_track;
+ plane_track != NULL;
plane_track = next_plane_track)
{
next_plane_track = plane_track->next;
@@ -249,23 +243,27 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- /* Remove selected point tracks (they'll also be removed from planes which uses them). */
- while (track) {
- next = track->next;
-
+ /* Remove selected point tracks (they'll also be removed from planes which
+ * uses them).
+ */
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ for (MovieTrackingTrack *track = tracksbase->first, *next_track;
+ track != NULL;
+ track = next_track)
+ {
+ next_track = track->next;
if (TRACK_VIEW_SELECTED(sc, track)) {
clip_delete_track(C, clip, track);
changed = true;
}
-
- track = next;
}
- /* nothing selected now, unlock view so it can be scrolled nice again */
+ /* Nothing selected now, unlock view so it can be scrolled nice again. */
sc->flag &= ~SC_LOCK_SELECTION;
- if (changed)
+ if (changed) {
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+ }
return OPERATOR_FINISHED;
}
@@ -292,41 +290,38 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- MovieTrackingTrack *track = tracksbase->first, *next;
- MovieTrackingPlaneTrack *plane_track, *plane_track_next;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
+ MovieTracking *tracking = &clip->tracking;
+ const int framenr = ED_space_clip_get_clip_frame_number(sc);
bool has_selection = false;
bool changed = false;
- while (track) {
- next = track->next;
-
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ for (MovieTrackingTrack *track = tracksbase->first, *next_track;
+ track != NULL;
+ track = next_track)
+ {
+ next_track = track->next;
if (TRACK_VIEW_SELECTED(sc, track)) {
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
-
- if (marker) {
+ if (marker != NULL) {
has_selection |= track->markersnr > 1;
-
clip_delete_marker(C, clip, track, marker);
changed = true;
}
}
-
- track = next;
}
- for (plane_track = plane_tracks_base->first;
- plane_track;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first,
+ *plane_track_next;
+ plane_track != NULL;
plane_track = plane_track_next)
{
plane_track_next = plane_track->next;
-
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr);
-
- if (plane_marker) {
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_get_exact(plane_track, framenr);
+ if (plane_marker != NULL) {
if (plane_track->markersnr == 1) {
BKE_tracking_plane_track_free(plane_track);
BLI_freelinkN(plane_tracks_base, plane_track);
@@ -334,19 +329,19 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
else {
BKE_tracking_plane_marker_delete(plane_track, framenr);
}
-
changed = true;
}
}
}
if (!has_selection) {
- /* nothing selected now, unlock view so it can be scrolled nice again */
+ /* Nothing selected now, unlock view so it can be scrolled nice again. */
sc->flag &= ~SC_LOCK_SELECTION;
}
- if (!changed)
+ if (!changed) {
return OPERATOR_CANCELLED;
+ }
return OPERATOR_FINISHED;
}
@@ -369,10 +364,12 @@ void CLIP_OT_delete_marker(wmOperatorType *ot)
/********************** slide marker operator *********************/
-#define SLIDE_ACTION_POS 0
-#define SLIDE_ACTION_SIZE 1
-#define SLIDE_ACTION_OFFSET 2
-#define SLIDE_ACTION_TILT_SIZE 3
+enum {
+ SLIDE_ACTION_POS = 0,
+ SLIDE_ACTION_SIZE,
+ SLIDE_ACTION_OFFSET,
+ SLIDE_ACTION_TILT_SIZE,
+};
typedef struct {
short area, action;
@@ -386,21 +383,28 @@ typedef struct {
bool lock, accurate;
- /* data to restore on cancel */
+ /* Data to restore on cancel. */
float old_search_min[2], old_search_max[2], old_pos[2], old_offset[2];
float old_corners[4][2];
float (*old_markers)[2];
} SlideMarkerData;
-static void slide_marker_tilt_slider(MovieTrackingMarker *marker, float slider[2])
+static void slide_marker_tilt_slider(const MovieTrackingMarker *marker,
+ float r_slider[2])
{
- add_v2_v2v2(slider, marker->pattern_corners[1], marker->pattern_corners[2]);
- add_v2_v2(slider, marker->pos);
+ add_v2_v2v2(r_slider, marker->pattern_corners[1], marker->pattern_corners[2]);
+ add_v2_v2(r_slider, marker->pos);
}
-static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTrack *track,
- MovieTrackingMarker *marker, const wmEvent *event,
- int area, int corner, int action, int width, int height)
+static SlideMarkerData *create_slide_marker_data(SpaceClip *sc,
+ MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ const wmEvent *event,
+ int area,
+ int corner,
+ int action,
+ int width,
+ int height)
{
SlideMarkerData *data = MEM_callocN(sizeof(SlideMarkerData), "slide marker data");
int framenr = ED_space_clip_get_clip_frame_number(sc);
@@ -421,14 +425,14 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
data->corners = marker->pattern_corners;
}
else if (action == SLIDE_ACTION_OFFSET) {
- int a;
-
data->pos = marker->pos;
data->offset = track->offset;
-
- data->old_markers = MEM_callocN(sizeof(*data->old_markers) * track->markersnr, "slide marekrs");
- for (a = 0; a < track->markersnr; a++)
+ data->old_markers = MEM_callocN(
+ sizeof(*data->old_markers) * track->markersnr,
+ "slide marekrs");
+ for (int a = 0; a < track->markersnr; a++) {
copy_v2_v2(data->old_markers[a], track->markers[a].pos);
+ }
}
else if (action == SLIDE_ACTION_POS) {
data->corners = marker->pattern_corners;
@@ -451,10 +455,11 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
data->width = width;
data->height = height;
- if (action == SLIDE_ACTION_SIZE)
+ if (action == SLIDE_ACTION_SIZE) {
data->lock = true;
+ }
- /* backup marker's settings */
+ /* Backup marker's settings. */
memcpy(data->old_corners, marker->pattern_corners, sizeof(data->old_corners));
copy_v2_v2(data->old_search_min, marker->search_min);
copy_v2_v2(data->old_search_max, marker->search_max);
@@ -464,132 +469,88 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
return data;
}
-static int mouse_on_slide_zone(SpaceClip *sc, MovieTrackingMarker *marker,
- int area, const float co[2], const float slide_zone[2],
- float padding, int width, int height)
+static float mouse_to_slide_zone_distance_squared(
+ const float co[2],
+ const float slide_zone[2],
+ int width,
+ int height)
{
- const float size = 12.0f;
- float min[2], max[2];
- float dx, dy;
-
- if (area == TRACK_AREA_SEARCH) {
- copy_v2_v2(min, marker->search_min);
- copy_v2_v2(max, marker->search_max);
- }
- else {
- BKE_tracking_marker_pattern_minmax(marker, min, max);
- }
-
- min[0] -= padding / width;
- min[1] -= padding / height;
- max[0] += padding / width;
- max[1] += padding / height;
-
- dx = size / width / sc->zoom;
- dy = size / height / sc->zoom;
-
- dx = min_ff(dx, (max[0] - min[0]) / 6.0f);
- dy = min_ff(dy, (max[1] - min[1]) / 6.0f);
-
- return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) &&
- IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy);
+ float pixel_co[2] = {co[0] * width, co[1] * height},
+ pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
+ return SQUARE(pixel_co[0] - pixel_slide_zone[0]) +
+ SQUARE(pixel_co[1] - pixel_slide_zone[1]);
}
-static int mouse_on_corner(SpaceClip *sc, MovieTrackingMarker *marker,
- int area, const float co[2], int corner, float padding,
- int width, int height)
+static float mouse_to_search_corner_distance_squared(
+ const MovieTrackingMarker *marker,
+ const float co[2],
+ int corner,
+ int width,
+ int height)
{
- float min[2], max[2], crn[2];
-
- if (area == TRACK_AREA_SEARCH) {
- copy_v2_v2(min, marker->search_min);
- copy_v2_v2(max, marker->search_max);
- }
- else {
- BKE_tracking_marker_pattern_minmax(marker, min, max);
- }
-
- min[0] -= padding / width;
- min[1] -= padding / height;
- max[0] += padding / width;
- max[1] += padding / height;
-
+ float side_zone[2];
if (corner == 0) {
- crn[0] = marker->pos[0] + max[0];
- crn[1] = marker->pos[1] + min[1];
+ side_zone[0] = marker->pos[0] + marker->search_max[0];
+ side_zone[1] = marker->pos[1] + marker->search_min[1];
}
else {
- crn[0] = marker->pos[0] + min[0];
- crn[1] = marker->pos[1] + max[1];
- }
-
- return mouse_on_slide_zone(sc, marker, area, co, crn, padding, width, height);
-}
-
-static int get_mouse_pattern_corner(SpaceClip *sc, MovieTrackingMarker *marker, float co[2], int width, int height)
-{
- int i, next;
- float len = FLT_MAX, dx, dy;
-
- for (i = 0; i < 4; i++) {
- float cur_len_sq;
-
- next = (i + 1) % 4;
-
- cur_len_sq = len_squared_v2v2(marker->pattern_corners[i], marker->pattern_corners[next]);
-
- len = min_ff(cur_len_sq, len);
- }
- len = sqrtf(len);
-
- dx = 12.0f / width / sc->zoom;
- dy = 12.0f / height / sc->zoom;
-
- dx = min_ff(dx, len * 2.0f / 3.0f);
- dy = min_ff(dy, len * width / height * 2.0f / 3.0f);
-
- for (i = 0; i < 4; i++) {
- float crn[2];
- int inside;
-
- add_v2_v2v2(crn, marker->pattern_corners[i], marker->pos);
-
- inside = IN_RANGE_INCL(co[0], crn[0] - dx, crn[0] + dx) &&
- IN_RANGE_INCL(co[1], crn[1] - dy, crn[1] + dy);
-
- if (inside)
- return i;
+ side_zone[0] = marker->pos[0] + marker->search_min[0];
+ side_zone[1] = marker->pos[1] + marker->search_max[1];
+ }
+ return mouse_to_slide_zone_distance_squared(co,
+ side_zone,
+ width,
+ height);
+}
+
+static float mouse_to_closest_pattern_corner_distance_squared(
+ const MovieTrackingMarker *marker,
+ const float co[2],
+ int width,
+ int height,
+ int *r_corner)
+{
+ float min_distance_squared = FLT_MAX;
+ for (int i = 0; i < 4; i++) {
+ float corner_co[2];
+ add_v2_v2v2(corner_co, marker->pattern_corners[i], marker->pos);
+ float distance_squared = mouse_to_slide_zone_distance_squared(co,
+ corner_co,
+ width,
+ height);
+ if (distance_squared < min_distance_squared) {
+ min_distance_squared = distance_squared;
+ *r_corner = i;
+ }
}
-
- return -1;
+ return min_distance_squared;
}
-static int mouse_on_offset(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
- const float co[2], int width, int height)
+static float mouse_to_offset_distance_squared(const MovieTrackingTrack *track,
+ const MovieTrackingMarker *marker,
+ const float co[2],
+ int width,
+ int height)
{
- float pos[2], dx, dy;
- float pat_min[2], pat_max[2];
-
- BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
-
+ float pos[2];
add_v2_v2v2(pos, marker->pos, track->offset);
-
- dx = 12.0f / width / sc->zoom;
- dy = 12.0f / height / sc->zoom;
-
- dx = min_ff(dx, (pat_max[0] - pat_min[0]) / 2.0f);
- dy = min_ff(dy, (pat_max[1] - pat_min[1]) / 2.0f);
-
- return co[0] >= pos[0] - dx && co[0] <= pos[0] + dx && co[1] >= pos[1] - dy && co[1] <= pos[1] + dy;
+ return mouse_to_slide_zone_distance_squared(co,
+ pos,
+ width,
+ height);
}
-static int mouse_on_tilt(SpaceClip *sc, MovieTrackingMarker *marker, float co[2], int width, int height)
+static int mouse_to_tilt_distance_squared(const MovieTrackingMarker *marker,
+ const float co[2],
+ int width,
+ int height)
{
float slider[2];
-
slide_marker_tilt_slider(marker, slider);
-
- return mouse_on_slide_zone(sc, marker, TRACK_AREA_PAT, co, slider, 0.0f, width, height);
+ return mouse_to_slide_zone_distance_squared(co,
+ slider,
+ width,
+ height);
}
static bool slide_check_corners(float (*corners)[2])
@@ -625,22 +586,13 @@ static bool slide_check_corners(float (*corners)[2])
return true;
}
-static void hide_cursor(bContext *C)
-{
- wmWindow *win = CTX_wm_window(C);
-
- WM_cursor_set(win, CURSOR_NONE);
-}
-
-static void show_cursor(bContext *C)
-{
- wmWindow *win = CTX_wm_window(C);
-
- WM_cursor_set(win, CURSOR_STD);
-}
-
-MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *event, int *area_r, int *action_r, int *corner_r)
+MovieTrackingTrack *tracking_marker_check_slide(bContext *C,
+ const wmEvent *event,
+ int *area_r,
+ int *action_r,
+ int *corner_r)
{
+ const float distance_clip_squared = 12.0f * 12.0f;
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
@@ -650,7 +602,13 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even
float co[2];
ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
int framenr = ED_space_clip_get_clip_frame_number(sc);
- int action = -1, area = 0, corner = -1;
+ float global_min_distance_squared = FLT_MAX;
+
+ /* Sliding zone designator which is the closest to the mouse
+ * across all the tracks.
+ */
+ int min_action = -1, min_area = 0, min_corner = -1;
+ MovieTrackingTrack *min_track = NULL;
ED_space_clip_get_size(sc, &width, &height);
@@ -662,72 +620,103 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even
track = tracksbase->first;
while (track) {
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
- bool ok = false;
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get(track,
+ framenr);
+ /* Sliding zone designator which is the closest to the mouse for
+ * the current tracks.
+ */
+ float min_distance_squared = FLT_MAX;
+ int action = -1, area = 0, corner = -1;
if ((marker->flag & MARKER_DISABLED) == 0) {
- if (mouse_on_offset(sc, track, marker, co, width, height)) {
- area = TRACK_AREA_POINT;
- action = SLIDE_ACTION_POS;
- ok = true;
- }
-
- if (!ok && (sc->flag & SC_SHOW_MARKER_SEARCH)) {
- if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 1, 0.0f, width, height)) {
+ float distance_squared;
+
+ /* We start checking with whether the mouse is close enough
+ * to the pattern offset area.
+ */
+ distance_squared = mouse_to_offset_distance_squared(track,
+ marker,
+ co,
+ width,
+ height);
+ area = TRACK_AREA_POINT;
+ action = SLIDE_ACTION_POS;
+
+ /* NOTE: All checks here are assuming there's no maximum distance
+ * limit, so checks are quite simple here.
+ * Actual distance clipping happens later once all the sliding
+ * zones are checked.
+ */
+ min_distance_squared = distance_squared;
+
+ /* If search area is visible, check how close to it's sliding
+ * zones mouse is.
+ */
+ if (sc->flag & SC_SHOW_MARKER_SEARCH) {
+ distance_squared = mouse_to_search_corner_distance_squared(
+ marker,
+ co,
+ 1,
+ width,
+ height);
+ if (distance_squared < min_distance_squared) {
area = TRACK_AREA_SEARCH;
action = SLIDE_ACTION_OFFSET;
- ok = true;
+ min_distance_squared = distance_squared;
}
- else if (mouse_on_corner(sc, marker, TRACK_AREA_SEARCH, co, 0, 0.0f, width, height)) {
+
+ distance_squared = mouse_to_search_corner_distance_squared(
+ marker,
+ co,
+ 0,
+ width,
+ height);
+ if (distance_squared < min_distance_squared) {
area = TRACK_AREA_SEARCH;
action = SLIDE_ACTION_SIZE;
- ok = true;
+ min_distance_squared = distance_squared;
}
}
- if (!ok && (sc->flag & SC_SHOW_MARKER_PATTERN)) {
- int current_corner = get_mouse_pattern_corner(sc, marker, co, width, height);
-
- if (current_corner != -1) {
+ /* If pattern area is visible, check which corner is closest to
+ * the mouse.
+ */
+ if (sc->flag & SC_SHOW_MARKER_PATTERN) {
+ int current_corner;
+ distance_squared =
+ mouse_to_closest_pattern_corner_distance_squared(
+ marker,
+ co,
+ width,
+ height,
+ &current_corner);
+ if (distance_squared < min_distance_squared) {
area = TRACK_AREA_PAT;
action = SLIDE_ACTION_POS;
corner = current_corner;
- ok = true;
+ min_distance_squared = distance_squared;
}
- else {
-#if 0
- /* TODO: disable for now, needs better approaches for visualization */
- if (mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 1, 12.0f, width, height)) {
- area = TRACK_AREA_PAT;
- action = SLIDE_ACTION_OFFSET;
- ok = true;
- }
- if (!ok && mouse_on_corner(sc, marker, TRACK_AREA_PAT, co, 0, 12.0f, width, height)) {
- area = TRACK_AREA_PAT;
- action = SLIDE_ACTION_SIZE;
- ok = true;
- }
-#endif
- if (!ok && mouse_on_tilt(sc, marker, co, width, height)) {
- area = TRACK_AREA_PAT;
- action = SLIDE_ACTION_TILT_SIZE;
- ok = true;
- }
+ /* Here we also check whether the mouse is actually closer to
+ * the widget which controls scale and tilt.
+ */
+ distance_squared = mouse_to_tilt_distance_squared(marker,
+ co,
+ width,
+ height);
+ if (distance_squared < min_distance_squared) {
+ area = TRACK_AREA_PAT;
+ action = SLIDE_ACTION_TILT_SIZE;
+ min_distance_squared = distance_squared;
}
}
- if (ok) {
- if (area_r)
- *area_r = area;
-
- if (action_r)
- *action_r = action;
-
- if (corner_r)
- *corner_r = corner;
-
- return track;
+ if (min_distance_squared < global_min_distance_squared) {
+ min_area = area;
+ min_action = action;
+ min_corner = corner;
+ min_track = track;
+ global_min_distance_squared = min_distance_squared;
}
}
}
@@ -735,6 +724,18 @@ MovieTrackingTrack *tracking_marker_check_slide(bContext *C, const wmEvent *even
track = track->next;
}
+ if (global_min_distance_squared < distance_clip_squared / sc->zoom) {
+ if (area_r) {
+ *area_r = min_area;
+ }
+ if (action_r) {
+ *action_r = min_action;
+ }
+ if (corner_r) {
+ *corner_r = min_corner;
+ }
+ return min_track;
+ }
return NULL;
}
@@ -752,16 +753,24 @@ static void *slide_marker_customdata(bContext *C, const wmEvent *event)
ED_space_clip_get_size(sc, &width, &height);
- if (width == 0 || height == 0)
+ if (width == 0 || height == 0) {
return NULL;
+ }
ED_clip_mouse_pos(sc, ar, event->mval, co);
track = tracking_marker_check_slide(C, event, &area, &action, &corner);
- if (track) {
+ if (track != NULL) {
MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- customdata = create_slide_marker_data(sc, track, marker, event, area, corner, action, width, height);
+ customdata = create_slide_marker_data(sc,
+ track,
+ marker,
+ event,
+ area,
+ corner,
+ action,
+ width,
+ height);
}
return customdata;
@@ -770,8 +779,7 @@ static void *slide_marker_customdata(bContext *C, const wmEvent *event)
static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SlideMarkerData *slidedata = slide_marker_customdata(C, event);
-
- if (slidedata) {
+ if (slidedata != NULL) {
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -781,7 +789,7 @@ static int slide_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event
op->customdata = slidedata;
- hide_cursor(C);
+ clip_tracking_hide_cursor(C);
WM_event_add_modal_handler(C, op);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
@@ -797,17 +805,18 @@ static void cancel_mouse_slide(SlideMarkerData *data)
MovieTrackingTrack *track = data->track;
MovieTrackingMarker *marker = data->marker;
- memcpy(marker->pattern_corners, data->old_corners, sizeof(marker->pattern_corners));
+ memcpy(marker->pattern_corners,
+ data->old_corners,
+ sizeof(marker->pattern_corners));
copy_v2_v2(marker->search_min, data->old_search_min);
copy_v2_v2(marker->search_max, data->old_search_max);
copy_v2_v2(marker->pos, data->old_pos);
copy_v2_v2(track->offset, data->old_offset);
- if (data->old_markers) {
- int a;
-
- for (a = 0; a < data->track->markersnr; a++)
+ if (data->old_markers != NULL) {
+ for (int a = 0; a < data->track->markersnr; a++) {
copy_v2_v2(data->track->markers[a].pos, data->old_markers[a]);
+ }
}
}
@@ -816,17 +825,20 @@ static void apply_mouse_slide(bContext *C, SlideMarkerData *data)
if (data->area == TRACK_AREA_POINT) {
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingPlaneTrack *plane_track;
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
int framenr = ED_space_clip_get_clip_frame_number(sc);
- for (plane_track = plane_tracks_base->first;
- plane_track;
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
plane_track = plane_track->next)
{
if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
- if (BKE_tracking_plane_track_has_point_track(plane_track, data->track)) {
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
+ if (BKE_tracking_plane_track_has_point_track(plane_track,
+ data->track))
+ {
+ BKE_tracking_track_plane_from_existing_motion(plane_track,
+ framenr);
}
}
}
@@ -835,9 +847,9 @@ static void apply_mouse_slide(bContext *C, SlideMarkerData *data)
static void free_slide_data(SlideMarkerData *data)
{
- if (data->old_markers)
+ if (data->old_markers != NULL) {
MEM_freeN(data->old_markers);
-
+ }
MEM_freeN(data);
}
@@ -854,12 +866,15 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTCTRLKEY:
case LEFTSHIFTKEY:
case RIGHTSHIFTKEY:
- if (data->action == SLIDE_ACTION_SIZE)
- if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY))
+ if (data->action == SLIDE_ACTION_SIZE) {
+ if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY)) {
data->lock = event->val == KM_RELEASE;
+ }
+ }
- if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
+ if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
data->accurate = event->val == KM_PRESS;
+ }
/* fall-through */
case MOUSEMOVE:
@@ -868,14 +883,16 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
dx = mdelta[0] / data->width / sc->zoom;
- if (data->lock)
+ if (data->lock) {
dy = -dx / data->height * data->width;
- else
+ }
+ else {
dy = mdelta[1] / data->height / sc->zoom;
+ }
if (data->accurate) {
- dx /= 5;
- dy /= 5;
+ dx /= 5.0f;
+ dy /= 5.0f;
}
if (data->area == TRACK_AREA_POINT) {
@@ -896,7 +913,12 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
float start[2], end[2];
float scale;
- ED_clip_point_stable_pos(sc, ar, data->mval[0], data->mval[1], &start[0], &start[1]);
+ ED_clip_point_stable_pos(sc,
+ ar,
+ data->mval[0],
+ data->mval[1],
+ &start[0],
+ &start[1]);
sub_v2_v2(start, data->old_pos);
@@ -912,17 +934,21 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
mval[1] = event->mval[1];
}
- ED_clip_point_stable_pos(sc, ar, mval[0], mval[1], &end[0], &end[1]);
+ ED_clip_point_stable_pos(sc,
+ ar,
+ mval[0],
+ mval[1],
+ &end[0],
+ &end[1]);
sub_v2_v2(end, data->old_pos);
-
scale = len_v2(end) / len_v2(start);
if (scale > 0.0f) {
- int a;
-
- for (a = 0; a < 4; a++) {
- mul_v2_v2fl(data->corners[a], data->old_corners[a], scale);
+ for (int a = 0; a < 4; a++) {
+ mul_v2_v2fl(data->corners[a],
+ data->old_corners[a],
+ scale);
}
}
}
@@ -931,11 +957,11 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (data->action == SLIDE_ACTION_OFFSET) {
float d[2] = {dx, dy};
- int a;
-
- for (a = 0; a < data->track->markersnr; a++)
- add_v2_v2v2(data->track->markers[a].pos, data->old_markers[a], d);
-
+ for (int a = 0; a < data->track->markersnr; a++) {
+ add_v2_v2v2(data->track->markers[a].pos,
+ data->old_markers[a],
+ d);
+ }
sub_v2_v2v2(data->offset, data->old_offset, d);
}
else if (data->action == SLIDE_ACTION_POS) {
@@ -950,13 +976,14 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
copy_v2_v2(data->pos, spos);
}
- /* currently only patterns are allowed to have such combination of event and data */
+ /* Currently only patterns are allowed to have such
+ * combination of event and data.
+ */
BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
}
else if (data->action == SLIDE_ACTION_TILT_SIZE) {
float start[2], end[2];
float scale = 1.0f, angle = 0.0f;
- int a;
float mval[2];
if (data->accurate) {
@@ -983,7 +1010,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
angle = -angle_signed_v2v2(start, end);
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
float vec[2];
mul_v2_v2fl(data->corners[a], data->old_corners[a], scale);
@@ -1012,7 +1039,6 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
else if (data->area == TRACK_AREA_SEARCH) {
float d[2] = {dx, dy};
-
add_v2_v2v2(data->min, data->old_search_min, d);
add_v2_v2v2(data->max, data->old_search_max, d);
}
@@ -1031,7 +1057,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
apply_mouse_slide(C, op->customdata);
free_slide_data(op->customdata);
- show_cursor(C);
+ clip_tracking_show_cursor(C);
return OPERATOR_FINISHED;
}
@@ -1043,7 +1069,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
free_slide_data(op->customdata);
- show_cursor(C);
+ clip_tracking_show_cursor(C);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
@@ -1070,759 +1096,9 @@ void CLIP_OT_slide_marker(wmOperatorType *ot)
/* properties */
RNA_def_float_vector(ot->srna, "offset", 2, NULL, -FLT_MAX, FLT_MAX,
- "Offset", "Offset in floating point units, 1.0 is the width and height of the image", -FLT_MAX, FLT_MAX);
-}
-
-/********************** track operator *********************/
-
-typedef struct TrackMarkersJob {
- struct AutoTrackContext *context; /* tracking context */
- int sfra, efra, lastfra; /* Start, end and recently tracked frames */
- int backwards; /* Backwards tracking flag */
- MovieClip *clip; /* Clip which is tracking */
- float delay; /* Delay in milliseconds to allow tracking at fixed FPS */
-
- struct Main *main;
- struct Scene *scene;
- struct bScreen *screen;
-} TrackMarkersJob;
-
-static bool track_markers_testbreak(void)
-{
- return G.is_break;
-}
-
-static int track_count_markers(SpaceClip *sc, MovieClip *clip, int framenr)
-{
- int tot = 0;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
-
- track = tracksbase->first;
- while (track) {
- bool selected = sc ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
- if (selected && (track->flag & TRACK_LOCKED) == 0) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- if (!marker || (marker->flag & MARKER_DISABLED) == 0)
- tot++;
- }
-
- track = track->next;
- }
-
- return tot;
-}
-
-static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
-{
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- int hidden = 0;
-
- if ((sc->flag & SC_SHOW_MARKER_PATTERN) == 0)
- hidden |= TRACK_AREA_PAT;
-
- if ((sc->flag & SC_SHOW_MARKER_SEARCH) == 0)
- hidden |= TRACK_AREA_SEARCH;
-
- if (hidden) {
- MovieTrackingTrack *track = tracksbase->first;
-
- while (track) {
- if ((track->flag & TRACK_HIDDEN) == 0)
- BKE_tracking_track_flag_clear(track, hidden, SELECT);
-
- track = track->next;
- }
- }
-}
-
-static void track_init_markers(SpaceClip *sc, MovieClip *clip, int framenr, int *frames_limit_r)
-{
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- int frames_limit = 0;
-
- if (sc != NULL) {
- clear_invisible_track_selection(sc, clip);
- }
-
- track = tracksbase->first;
- while (track) {
- bool selected = sc ? TRACK_VIEW_SELECTED(sc, track) : TRACK_SELECTED(track);
- if (selected) {
- if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
- BKE_tracking_marker_ensure(track, framenr);
-
- if (track->frames_limit) {
- if (frames_limit == 0)
- frames_limit = track->frames_limit;
- else
- frames_limit = min_ii(frames_limit, (int)track->frames_limit);
- }
- }
- }
-
- track = track->next;
- }
-
- *frames_limit_r = frames_limit;
-}
-
-static bool track_markers_check_direction(int backwards, int curfra, int efra)
-{
- if (backwards) {
- if (curfra < efra)
- return false;
- }
- else {
- if (curfra > efra)
- return false;
- }
-
- return true;
-}
-
-static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backwards)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- Scene *scene = CTX_data_scene(C);
- MovieTrackingSettings *settings = &clip->tracking.settings;
- int frames_limit;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- track_init_markers(sc, clip, framenr, &frames_limit);
-
- tmj->sfra = ED_space_clip_get_clip_frame_number(sc);
- tmj->clip = clip;
- tmj->backwards = backwards;
-
- if (backwards)
- tmj->efra = SFRA;
- else
- tmj->efra = EFRA;
-
- /* limit frames to be tracked by user setting */
- if (frames_limit) {
- if (backwards)
- tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
- else
- tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
- }
-
- tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
-
- if (settings->speed != TRACKING_SPEED_FASTEST) {
- tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
-
- if (settings->speed == TRACKING_SPEED_HALF)
- tmj->delay *= 2;
- else if (settings->speed == TRACKING_SPEED_QUARTER)
- tmj->delay *= 4;
- else if (settings->speed == TRACKING_SPEED_DOUBLE)
- tmj->delay /= 2;
- }
-
- tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1);
-
- clip->tracking_context = tmj->context;
-
- tmj->lastfra = tmj->sfra;
-
- /* XXX: silly to store this, but this data is needed to update scene and movie-clip
- * frame numbers when tracking is finished. This introduces better feedback for artists.
- * Maybe there's another way to solve this problem, but can't think better way atm.
- * Anyway, this way isn't more unstable as animation rendering animation
- * which uses the same approach (except storing screen). */
- tmj->scene = scene;
- tmj->main = CTX_data_main(C);
- tmj->screen = CTX_wm_screen(C);
-
- return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
-}
-
-static void track_markers_startjob(void *tmv, short *stop, short *do_update, float *progress)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- int framenr = tmj->sfra;
- // double t = PIL_check_seconds_timer();
-
- while (framenr != tmj->efra) {
- if (tmj->delay > 0) {
- /* tracking should happen with fixed fps. Calculate time
- * using current timer value before tracking frame and after.
- *
- * Small (and maybe unneeded optimization): do not calculate exec_time
- * for "Fastest" tracking */
-
- double start_time = PIL_check_seconds_timer(), exec_time;
-
- if (!BKE_autotrack_context_step(tmj->context))
- break;
-
- exec_time = PIL_check_seconds_timer() - start_time;
- if (tmj->delay > (float)exec_time)
- PIL_sleep_ms(tmj->delay - (float)exec_time);
- }
- else if (!BKE_autotrack_context_step(tmj->context))
- break;
-
- *do_update = true;
- *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
-
- if (tmj->backwards)
- framenr--;
- else
- framenr++;
-
- tmj->lastfra = framenr;
-
- if (*stop || track_markers_testbreak())
- break;
- }
-
- // printf("Tracking time: %lf\n", PIL_check_seconds_timer()-t);
-}
-
-static void track_markers_updatejob(void *tmv)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
-
- BKE_autotrack_context_sync(tmj->context);
-}
-
-static void track_markers_endjob(void *tmv)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- wmWindowManager *wm = tmj->main->wm.first;
-
- tmj->clip->tracking_context = NULL;
- tmj->scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(tmj->clip, tmj->lastfra);
- if (wm != NULL) {
- ED_update_for_newframe(tmj->main, tmj->scene, 0);
- }
-
- BKE_autotrack_context_sync(tmj->context);
- BKE_autotrack_context_finish(tmj->context);
-
- WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene);
-}
-
-static void track_markers_freejob(void *tmv)
-{
- TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
- BKE_autotrack_context_free(tmj->context);
- MEM_freeN(tmj);
-}
-
-static int track_markers_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc;
- MovieClip *clip;
- Scene *scene = CTX_data_scene(C);
- struct AutoTrackContext *context;
- MovieClipUser *user, fake_user = {0};
- int framenr, sfra, efra;
- const bool backwards = RNA_boolean_get(op->ptr, "backwards");
- const bool sequence = RNA_boolean_get(op->ptr, "sequence");
- int frames_limit;
-
- if (RNA_struct_property_is_set(op->ptr, "clip")) {
- Main *bmain = CTX_data_main(C);
- char clip_name[MAX_ID_NAME - 2];
-
- RNA_string_get(op->ptr, "clip", clip_name);
- clip = (MovieClip *)BLI_findstring(&bmain->movieclip, clip_name, offsetof(ID, name) + 2);
- sc = NULL;
-
- if (clip == NULL) {
- return OPERATOR_CANCELLED;
- }
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, CFRA);
- fake_user.framenr = framenr;
- user = &fake_user;
- }
- else {
- sc = CTX_wm_space_clip(C);
-
- if (sc == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- clip = ED_space_clip_get_clip(sc);
- framenr = ED_space_clip_get_clip_frame_number(sc);
- user = &sc->user;
- }
-
- sfra = framenr;
-
- if (track_count_markers(sc, clip, framenr) == 0)
- return OPERATOR_CANCELLED;
-
- track_init_markers(sc, clip, framenr, &frames_limit);
-
- if (backwards)
- efra = SFRA;
- else
- efra = EFRA;
-
- /* limit frames to be tracked by user setting */
- if (frames_limit) {
- if (backwards)
- efra = MAX2(efra, sfra - frames_limit);
- else
- efra = MIN2(efra, sfra + frames_limit);
- }
-
- efra = BKE_movieclip_remap_scene_to_clip_frame(clip, efra);
-
- if (!track_markers_check_direction(backwards, framenr, efra))
- return OPERATOR_CANCELLED;
-
- /* do not disable tracks due to threshold when tracking frame-by-frame */
- context = BKE_autotrack_context_new(clip, user, backwards, sequence);
-
- while (framenr != efra) {
- if (!BKE_autotrack_context_step(context))
- break;
-
- if (backwards) framenr--;
- else framenr++;
-
- if (!sequence)
- break;
- }
-
- BKE_autotrack_context_sync(context);
- BKE_autotrack_context_finish(context);
- BKE_autotrack_context_free(context);
-
- /* update scene current frame to the lastes tracked frame */
- scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(clip, framenr);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
-
- return OPERATOR_FINISHED;
-}
-
-static int track_markers_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- TrackMarkersJob *tmj;
- ScrArea *sa = CTX_wm_area(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip;
- wmJob *wm_job;
- bool backwards = RNA_boolean_get(op->ptr, "backwards");
- bool sequence = RNA_boolean_get(op->ptr, "sequence");
- int framenr;
-
- if (sc == NULL) {
- /* TODO(sergey): Support clip for invoke as well. */
- BKE_report(op->reports, RPT_ERROR,
- "Invoking this operator only supported from Clip Editor space");
- return OPERATOR_CANCELLED;
- }
-
- clip = ED_space_clip_get_clip(sc);
- BLI_assert(clip != NULL);
- framenr = ED_space_clip_get_clip_frame_number(sc);
-
- if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
- /* only one tracking is allowed at a time */
- return OPERATOR_CANCELLED;
- }
-
- if (clip->tracking_context)
- return OPERATOR_CANCELLED;
-
- if (track_count_markers(sc, clip, framenr) == 0)
- return OPERATOR_CANCELLED;
-
- if (!sequence)
- return track_markers_exec(C, op);
-
- tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
- if (!track_markers_initjob(C, tmj, backwards)) {
- track_markers_freejob(tmj);
-
- return OPERATOR_CANCELLED;
- }
-
- /* setup job */
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Track Markers",
- WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_TRACK_MARKERS);
- WM_jobs_customdata_set(wm_job, tmj, track_markers_freejob);
-
- /* if there's delay set in tracking job, tracking should happen
- * with fixed FPS. To deal with editor refresh we have to synchronize
- * tracks from job and tracks in clip. Do this in timer callback
- * to prevent threading conflicts. */
- if (tmj->delay > 0)
- WM_jobs_timer(wm_job, tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
- else
- WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
-
- WM_jobs_callbacks(wm_job, track_markers_startjob, NULL, track_markers_updatejob, track_markers_endjob);
-
- G.is_break = false;
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
-
- /* add modal handler for ESC */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
-{
- /* no running tracking, remove handler and pass through */
- if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
-
- /* running tracking */
- switch (event->type) {
- case ESCKEY:
- return OPERATOR_RUNNING_MODAL;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-void CLIP_OT_track_markers(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Track Markers";
- ot->description = "Track selected markers";
- ot->idname = "CLIP_OT_track_markers";
-
- /* api callbacks */
- ot->exec = track_markers_exec;
- ot->invoke = track_markers_invoke;
- ot->modal = track_markers_modal;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
- RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence", "Track marker during image sequence rather than single image");
- prop = RNA_def_string(ot->srna, "clip", NULL, MAX_NAME, "Movie Clip", "Movie Clip to be tracked");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/********************** refine track position operator *********************/
-
-static int refine_marker_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track;
- bool backwards = RNA_boolean_get(op->ptr, "backwards");
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- for (track = tracksbase->first; track; track = track->next) {
- if (TRACK_VIEW_SELECTED(sc, track)) {
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- BKE_tracking_refine_marker(clip, track, marker, backwards);
- }
- }
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_refine_markers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Refine Markers";
- ot->description = "Refine selected markers positions "
- "by running the tracker from track's reference to current frame";
- ot->idname = "CLIP_OT_refine_markers";
-
- /* api callbacks */
- ot->exec = refine_marker_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "backwards", 0, "Backwards", "Do backwards tracking");
-}
-
-/********************** solve camera operator *********************/
-
-typedef struct {
- Scene *scene;
- MovieClip *clip;
- MovieClipUser user;
-
- ReportList *reports;
-
- char stats_message[256];
-
- struct MovieReconstructContext *context;
-} SolveCameraJob;
-
-static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op, char *error_msg, int max_error)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- Scene *scene = CTX_data_scene(C);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- int width, height;
-
- if (!BKE_tracking_reconstruction_check(tracking, object, error_msg, max_error))
- return 0;
-
- /* could fail if footage uses images with different sizes */
- BKE_movieclip_get_size(clip, &sc->user, &width, &height);
-
- scj->clip = clip;
- scj->scene = scene;
- scj->reports = op->reports;
- scj->user = sc->user;
-
- scj->context = BKE_tracking_reconstruction_context_new(clip, object,
- object->keyframe1, object->keyframe2, width, height);
-
- tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
-
- return 1;
-}
-
-static void solve_camera_updatejob(void *scv)
-{
- SolveCameraJob *scj = (SolveCameraJob *)scv;
- MovieTracking *tracking = &scj->clip->tracking;
-
- BLI_strncpy(tracking->stats->message, scj->stats_message, sizeof(tracking->stats->message));
-}
-
-static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
-{
- SolveCameraJob *scj = (SolveCameraJob *)scv;
-
- BKE_tracking_reconstruction_solve(scj->context, stop, do_update, progress,
- scj->stats_message, sizeof(scj->stats_message));
-}
-
-static void solve_camera_freejob(void *scv)
-{
- SolveCameraJob *scj = (SolveCameraJob *)scv;
- MovieTracking *tracking = &scj->clip->tracking;
- Scene *scene = scj->scene;
- MovieClip *clip = scj->clip;
- int solved;
-
- if (!scj->context) {
- /* job weren't fully initialized due to some error */
- MEM_freeN(scj);
- return;
- }
-
- solved = BKE_tracking_reconstruction_finish(scj->context, tracking);
- if (!solved)
- BKE_report(scj->reports, RPT_WARNING, "Some data failed to reconstruct (see console for details)");
- else
- BKE_reportf(scj->reports, RPT_INFO, "Average re-projection error: %.3f", tracking->reconstruction.error);
-
- /* set currently solved clip as active for scene */
- if (scene->clip)
- id_us_min(&clip->id);
-
- scene->clip = clip;
- id_us_plus(&clip->id);
-
- /* set blender camera focal length so result would look fine there */
- if (scene->camera && scene->camera->data && GS(((ID *) scene->camera->data)->name) == ID_CA) {
- Camera *camera = (Camera *)scene->camera->data;
- int width, height;
-
- BKE_movieclip_get_size(clip, &scj->user, &width, &height);
-
- BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
-
- WM_main_add_notifier(NC_OBJECT, camera);
- }
-
- MEM_freeN(tracking->stats);
- tracking->stats = NULL;
-
- DAG_id_tag_update(&clip->id, 0);
-
- WM_main_add_notifier(NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
-
- /* update active clip displayed in scene buttons */
- WM_main_add_notifier(NC_SCENE, scene);
-
- BKE_tracking_reconstruction_context_free(scj->context);
- MEM_freeN(scj);
-}
-
-static int solve_camera_exec(bContext *C, wmOperator *op)
-{
- SolveCameraJob *scj;
- char error_msg[256] = "\0";
-
- scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
- if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
- if (error_msg[0])
- BKE_report(op->reports, RPT_ERROR, error_msg);
-
- solve_camera_freejob(scj);
-
- return OPERATOR_CANCELLED;
- }
-
- solve_camera_startjob(scj, NULL, NULL, NULL);
-
- solve_camera_freejob(scj);
-
- return OPERATOR_FINISHED;
-}
-
-static int solve_camera_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- SolveCameraJob *scj;
- ScrArea *sa = CTX_wm_area(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
- wmJob *wm_job;
- char error_msg[256] = "\0";
-
- if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
- /* only one solve is allowed at a time */
- return OPERATOR_CANCELLED;
- }
-
- scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
- if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
- if (error_msg[0])
- BKE_report(op->reports, RPT_ERROR, error_msg);
-
- solve_camera_freejob(scj);
-
- return OPERATOR_CANCELLED;
- }
-
- BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
-
- /* hide reconstruction statistics from previous solve */
- reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
-
- /* setup job */
- wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera",
- WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_SOLVE_CAMERA);
- WM_jobs_customdata_set(wm_job, scj, solve_camera_freejob);
- WM_jobs_timer(wm_job, 0.1, NC_MOVIECLIP | NA_EVALUATED, 0);
- WM_jobs_callbacks(wm_job, solve_camera_startjob, NULL, solve_camera_updatejob, NULL);
-
- G.is_break = false;
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- WM_cursor_wait(0);
-
- /* add modal handler for ESC */
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int solve_camera_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
-{
- /* no running solver, remove handler and pass through */
- if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
-
- /* running tracking */
- switch (event->type) {
- case ESCKEY:
- return OPERATOR_RUNNING_MODAL;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-void CLIP_OT_solve_camera(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Solve Camera";
- ot->description = "Solve camera motion from tracks";
- ot->idname = "CLIP_OT_solve_camera";
-
- /* api callbacks */
- ot->exec = solve_camera_exec;
- ot->invoke = solve_camera_invoke;
- ot->modal = solve_camera_modal;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** clear solution operator *********************/
-
-static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
- MovieTrackingTrack *track = tracksbase->first;
-
- while (track) {
- track->flag &= ~TRACK_HAS_BUNDLE;
-
- track = track->next;
- }
-
- if (reconstruction->cameras)
- MEM_freeN(reconstruction->cameras);
-
- reconstruction->cameras = NULL;
- reconstruction->camnr = 0;
-
- reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
-
- DAG_id_tag_update(&clip->id, 0);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_clear_solution(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Solution";
- ot->description = "Clear all calculated data";
- ot->idname = "CLIP_OT_clear_solution";
-
- /* api callbacks */
- ot->exec = clear_solution_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ "Offset",
+ "Offset in floating point units, 1.0 is the width and height of the image",
+ -FLT_MAX, FLT_MAX);
}
/********************** clear track operator *********************/
@@ -1832,25 +1108,25 @@ static int clear_track_path_exec(bContext *C, wmOperator *op)
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
int action = RNA_enum_get(op->ptr, "action");
const bool clear_active = RNA_boolean_get(op->ptr, "clear_active");
int framenr = ED_space_clip_get_clip_frame_number(sc);
if (clear_active) {
- track = BKE_tracking_track_get_active(tracking);
- if (track) {
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(tracking);
+ if (track != NULL) {
BKE_tracking_track_path_clear(track, framenr, action);
}
}
else {
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track))
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track)) {
BKE_tracking_track_path_clear(track, framenr, action);
-
- track = track->next;
+ }
}
}
@@ -1888,28 +1164,41 @@ void CLIP_OT_clear_track_path(wmOperatorType *ot)
/********************** disable markers operator *********************/
+enum {
+ MARKER_OP_DISABLE = 0,
+ MARKER_OP_ENABLE = 1,
+ MARKER_OP_TOGGLE = 2,
+};
+
static int disable_markers_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track = tracksbase->first;
int action = RNA_enum_get(op->ptr, "action");
int framenr = ED_space_clip_get_clip_frame_number(sc);
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_LOCKED) == 0)
+ {
MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
-
- if (action == 0)
- marker->flag |= MARKER_DISABLED;
- else if (action == 1)
- marker->flag &= ~MARKER_DISABLED;
- else marker->flag ^= MARKER_DISABLED;
+ switch (action) {
+ case MARKER_OP_DISABLE:
+ marker->flag |= MARKER_DISABLED;
+ break;
+ case MARKER_OP_ENABLE:
+ marker->flag &= ~MARKER_DISABLED;
+ break;
+ case MARKER_OP_TOGGLE:
+ marker->flag ^= MARKER_DISABLED;
+ break;
+ }
}
-
- track = track->next;
}
DAG_id_tag_update(&clip->id, 0);
@@ -1922,9 +1211,12 @@ static int disable_markers_exec(bContext *C, wmOperator *op)
void CLIP_OT_disable_markers(wmOperatorType *ot)
{
static EnumPropertyItem actions_items[] = {
- {0, "DISABLE", 0, "Disable", "Disable selected markers"},
- {1, "ENABLE", 0, "Enable", "Enable selected markers"},
- {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
+ {MARKER_OP_DISABLE, "DISABLE", 0, "Disable",
+ "Disable selected markers"},
+ {MARKER_OP_ENABLE, "ENABLE", 0, "Enable",
+ "Enable selected markers"},
+ {MARKER_OP_TOGGLE, "TOGGLE", 0, "Toggle",
+ "Toggle disabled flag for selected markers"},
{0, NULL, 0, NULL, NULL}
};
@@ -1944,800 +1236,6 @@ void CLIP_OT_disable_markers(wmOperatorType *ot)
RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
}
-/********************** set origin operator *********************/
-
-static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
-{
- Object *camera = scene->camera;
- Base *base;
-
- if (camera && BKE_object_movieclip_get(scene, camera, false) == clip)
- return camera;
-
- base = scene->base.first;
- while (base) {
- if (base->object->type == OB_CAMERA) {
- if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
- camera = base->object;
- break;
- }
- }
-
- base = base->next;
- }
-
- return camera;
-}
-
-static Object *get_orientation_object(bContext *C)
-{
- Scene *scene = CTX_data_scene(C);
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- Object *object = NULL;
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- object = get_camera_with_movieclip(scene, clip);
- }
- else {
- object = OBACT;
- }
-
- if (object && object->parent)
- object = object->parent;
-
- return object;
-}
-
-static int set_orientation_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
-
- if (sc) {
- Scene *scene = CTX_data_scene(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- return true;
- }
- else {
- return OBACT != NULL;
- }
- }
- }
-
- return false;
-}
-
-static int count_selected_bundles(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
- MovieTrackingTrack *track;
- int tot = 0;
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE))
- tot++;
-
- track = track->next;
- }
-
- return tot;
-}
-
-static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
-{
- bConstraint *con;
- bool found = false;
-
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (!cti)
- continue;
-
- if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
-
- if (!found) {
- Object *cam = data->camera ? data->camera : scene->camera;
-
- BKE_object_where_is_calc_mat4(scene, cam, invmat);
- }
-
- mul_m4_m4m4(invmat, invmat, data->invmat);
-
- found = true;
- }
- }
-
- if (found)
- invert_m4(invmat);
- else
- unit_m4(invmat);
-}
-
-static Object *object_solver_camera(Scene *scene, Object *ob)
-{
- bConstraint *con;
-
- for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- if (!cti)
- continue;
-
- if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
-
- return data->camera ? data->camera : scene->camera;
- }
- }
-
- return NULL;
-}
-
-static int set_origin_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *track;
- MovieTrackingObject *tracking_object;
- Scene *scene = CTX_data_scene(C);
- Object *object;
- Object *camera = get_camera_with_movieclip(scene, clip);
- ListBase *tracksbase;
- float mat[4][4], vec[3], median[3];
- int selected_count = count_selected_bundles(C);
-
- if (selected_count == 0) {
- BKE_report(op->reports, RPT_ERROR,
- "At least one track with bundle should be selected to define origin position");
-
- return OPERATOR_CANCELLED;
- }
-
- object = get_orientation_object(C);
- if (!object) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
-
- return OPERATOR_CANCELLED;
- }
-
- tracking_object = BKE_tracking_object_get_active(tracking);
-
- tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
-
- track = tracksbase->first;
- zero_v3(median);
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
- add_v3_v3(median, track->bundle_pos);
- }
-
- track = track->next;
- }
- mul_v3_fl(median, 1.0f / selected_count);
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
-
- mul_v3_m4v3(vec, mat, median);
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- sub_v3_v3(object->loc, vec);
- }
- else {
- object_solver_inverted_matrix(scene, object, mat);
- mul_v3_m4v3(vec, mat, vec);
- copy_v3_v3(object->loc, vec);
- }
-
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_set_origin(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Origin";
- ot->description = "Set active marker as origin by moving camera (or its parent if present) in 3D space";
- ot->idname = "CLIP_OT_set_origin";
-
- /* api callbacks */
- ot->exec = set_origin_exec;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
-}
-
-/********************** set floor operator *********************/
-
-static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
- MovieTrackingTrack *track, char axis)
-{
- Object *camera = get_camera_with_movieclip(scene, clip);
- const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
- bool flip = false;
- float mat[4][4], vec[3], obmat[4][4], dvec[3];
-
- BKE_object_to_mat4(ob, obmat);
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
- mul_v3_m4v3(vec, mat, track->bundle_pos);
- copy_v3_v3(dvec, vec);
-
- if (!is_camera) {
- float imat[4][4];
-
- object_solver_inverted_matrix(scene, ob, imat);
- mul_v3_m4v3(vec, imat, vec);
-
- invert_m4_m4(imat, obmat);
- mul_v3_m4v3(dvec, imat, vec);
-
- sub_v3_v3(vec, obmat[3]);
- }
-
- if (len_squared_v2(vec) < (1e-3f * 1e-3f))
- return;
-
- unit_m4(mat);
-
- if (axis == 'X') {
- if (fabsf(dvec[1]) < 1e-3f) {
- flip = true;
-
- mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
- mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- }
- else {
- copy_v3_v3(mat[0], vec);
-
- if (is_camera || fabsf(vec[2]) < 1e-3f) {
- mat[0][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
- }
- else {
- vec[2] = 0.0f;
-
- cross_v3_v3v3(mat[1], mat[0], vec);
- cross_v3_v3v3(mat[2], mat[0], mat[1]);
- }
- }
- }
- else {
- if (fabsf(dvec[0]) < 1e-3f) {
- flip = true;
-
- mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
- mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- }
- else {
- copy_v3_v3(mat[1], vec);
-
- if (is_camera || fabsf(vec[2]) < 1e-3f) {
- mat[1][2] = 0.0f;
- mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
- cross_v3_v3v3(mat[0], mat[1], mat[2]);
- }
- else {
- vec[2] = 0.0f;
-
- cross_v3_v3v3(mat[0], vec, mat[1]);
- cross_v3_v3v3(mat[2], mat[0], mat[1]);
- }
- }
- }
-
- normalize_v3(mat[0]);
- normalize_v3(mat[1]);
- normalize_v3(mat[2]);
-
- if (is_camera) {
- invert_m4(mat);
-
- mul_m4_m4m4(mat, mat, obmat);
- }
- else {
- if (!flip) {
- float lmat[4][4], ilmat[4][4], rmat[3][3];
-
- BKE_object_rot_to_mat3(ob, rmat, true);
- invert_m3(rmat);
- mul_m4_m4m3(mat, mat, rmat);
-
- unit_m4(lmat);
- copy_v3_v3(lmat[3], obmat[3]);
- invert_m4_m4(ilmat, lmat);
-
- mul_m4_series(mat, lmat, mat, ilmat, obmat);
- }
- else {
- mul_m4_m4m4(mat, obmat, mat);
- }
- }
-
- BKE_object_apply_mat4(ob, mat, 0, 0);
-}
-
-static int set_plane_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- Scene *scene = CTX_data_scene(C);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object;
- MovieTrackingTrack *track, *axis_track = NULL, *act_track;
- ListBase *tracksbase;
- Object *object;
- Object *camera = get_camera_with_movieclip(scene, clip);
- int tot = 0;
- float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
- int plane = RNA_enum_get(op->ptr, "plane");
- float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
- {0.0f, 1.0f, 0.0f, 0.0f},
- {1.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 1.0f}}; /* 90 degrees Y-axis rotation matrix */
-
- if (count_selected_bundles(C) != 3) {
- BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
-
- return OPERATOR_CANCELLED;
- }
-
- tracking_object = BKE_tracking_object_get_active(tracking);
- tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
- act_track = BKE_tracking_track_get_active(tracking);
-
- object = get_orientation_object(C);
- if (!object) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
-
- return OPERATOR_CANCELLED;
- }
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
-
- /* get 3 bundles to use as reference */
- track = tracksbase->first;
- while (track && tot < 3) {
- if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
- mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
-
- if (tot == 0 || track == act_track)
- copy_v3_v3(orig, vec[tot]);
- else
- axis_track = track;
-
- tot++;
- }
-
- track = track->next;
- }
-
- sub_v3_v3(vec[1], vec[0]);
- sub_v3_v3(vec[2], vec[0]);
-
- /* construct ortho-normal basis */
- unit_m4(mat);
-
- if (plane == 0) { /* floor */
- cross_v3_v3v3(mat[0], vec[1], vec[2]);
- copy_v3_v3(mat[1], vec[1]);
- cross_v3_v3v3(mat[2], mat[0], mat[1]);
- }
- else if (plane == 1) { /* wall */
- cross_v3_v3v3(mat[2], vec[1], vec[2]);
- copy_v3_v3(mat[1], vec[1]);
- cross_v3_v3v3(mat[0], mat[1], mat[2]);
- }
-
- normalize_v3(mat[0]);
- normalize_v3(mat[1]);
- normalize_v3(mat[2]);
-
- /* move to origin point */
- mat[3][0] = orig[0];
- mat[3][1] = orig[1];
- mat[3][2] = orig[2];
-
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- invert_m4(mat);
-
- BKE_object_to_mat4(object, obmat);
- mul_m4_m4m4(mat, mat, obmat);
- mul_m4_m4m4(newmat, rot, mat);
- BKE_object_apply_mat4(object, newmat, 0, 0);
-
- /* make camera have positive z-coordinate */
- if (object->loc[2] < 0) {
- invert_m4(rot);
- mul_m4_m4m4(newmat, rot, mat);
- BKE_object_apply_mat4(object, newmat, 0, 0);
- }
- }
- else {
- BKE_object_apply_mat4(object, mat, 0, 0);
- }
-
- BKE_object_where_is_calc(scene, object);
- set_axis(scene, object, clip, tracking_object, axis_track, 'X');
-
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_set_plane(wmOperatorType *ot)
-{
- static EnumPropertyItem plane_items[] = {
- {0, "FLOOR", 0, "Floor", "Set floor plane"},
- {1, "WALL", 0, "Wall", "Set wall plane"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Set Plane";
- ot->description = "Set plane based on 3 selected bundles by moving camera (or its parent if present) in 3D space";
- ot->idname = "CLIP_OT_set_plane";
-
- /* api callbacks */
- ot->exec = set_plane_exec;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane", "Plane to be used for orientation");
-}
-
-/********************** set axis operator *********************/
-
-static int set_axis_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- MovieTrackingTrack *track;
- Scene *scene = CTX_data_scene(C);
- Object *object;
- ListBase *tracksbase;
- int axis = RNA_enum_get(op->ptr, "axis");
-
- if (count_selected_bundles(C) != 1) {
- BKE_report(op->reports, RPT_ERROR, "Single track with bundle should be selected to define axis");
-
- return OPERATOR_CANCELLED;
- }
-
- object = get_orientation_object(C);
- if (!object) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
-
- return OPERATOR_CANCELLED;
- }
-
- tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE))
- break;
-
- track = track->next;
- }
-
- set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
-
- DAG_id_tag_update(&clip->id, 0);
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_set_axis(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_actions[] = {
- {0, "X", 0, "X", "Align bundle align X axis"},
- {1, "Y", 0, "Y", "Align bundle align Y axis"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Set Axis";
- ot->description = "Set direction of scene axis rotating camera (or its parent if present) and assume selected track lies on real axis, joining it with the origin";
- ot->idname = "CLIP_OT_set_axis";
-
- /* api callbacks */
- ot->exec = set_axis_exec;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis", "Axis to use to align bundle along");
-}
-
-/********************** set scale operator *********************/
-
-static int do_set_scale(bContext *C, wmOperator *op, bool scale_solution, bool apply_scale)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
- MovieTrackingTrack *track;
- Scene *scene = CTX_data_scene(C);
- Object *object = NULL;
- Object *camera = get_camera_with_movieclip(scene, clip);
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- int tot = 0;
- float vec[2][3], mat[4][4], scale;
- float dist = RNA_float_get(op->ptr, "distance");
-
- if (count_selected_bundles(C) != 2) {
- BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
-
- return OPERATOR_CANCELLED;
- }
-
- if (!scale_solution && !apply_scale) {
- object = get_orientation_object(C);
- if (!object) {
- BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
-
- return OPERATOR_CANCELLED;
- }
- }
-
- BKE_tracking_get_camera_object_matrix(scene, camera, mat);
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track)) {
- mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
- tot++;
- }
-
- track = track->next;
- }
-
- sub_v3_v3(vec[0], vec[1]);
-
- if (len_v3(vec[0]) > 1e-5f) {
- scale = dist / len_v3(vec[0]);
-
- if (apply_scale) {
- /* Apply scale on reconstructed scene itself */
- MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
- MovieReconstructedCamera *reconstructed_cameras;
- int i;
-
- for (track = tracksbase->first; track; track = track->next) {
- mul_v3_fl(track->bundle_pos, scale);
- }
-
- reconstructed_cameras = reconstruction->cameras;
- for (i = 0; i < reconstruction->camnr; i++) {
- mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
- }
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- }
- else {
- if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_v3_fl(object->size, scale);
- mul_v3_fl(object->loc, scale);
- }
- else if (!scale_solution) {
- Object *solver_camera = object_solver_camera(scene, object);
-
- object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
-
- if (solver_camera) {
- object->size[0] /= solver_camera->size[0];
- object->size[1] /= solver_camera->size[1];
- object->size[2] /= solver_camera->size[2];
- }
- }
- else {
- tracking_object->scale = scale;
- }
-
- DAG_id_tag_update(&clip->id, 0);
-
- if (object)
- DAG_id_tag_update(&object->id, OB_RECALC_OB);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- }
- }
-
- return OPERATOR_FINISHED;
-}
-
-static int set_scale_exec(bContext *C, wmOperator *op)
-{
- return do_set_scale(C, op, false, false);
-}
-
-static int set_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (!RNA_struct_property_is_set(op->ptr, "distance"))
- RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
-
- return set_scale_exec(C, op);
-}
-
-void CLIP_OT_set_scale(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Scale";
- ot->description = "Set scale of scene by scaling camera (or its parent if present)";
- ot->idname = "CLIP_OT_set_scale";
-
- /* api callbacks */
- ot->exec = set_scale_exec;
- ot->invoke = set_scale_invoke;
- ot->poll = set_orientation_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
- "Distance", "Distance between selected tracks", -100.0f, 100.0f);
-}
-
-/********************** set solution scale operator *********************/
-
-static int set_solution_scale_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
-
- if (sc) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
-
- return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
- }
- }
-
- return false;
-}
-
-static int set_solution_scale_exec(bContext *C, wmOperator *op)
-{
- return do_set_scale(C, op, true, false);
-}
-
-static int set_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (!RNA_struct_property_is_set(op->ptr, "distance"))
- RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
-
- return set_solution_scale_exec(C, op);
-}
-
-void CLIP_OT_set_solution_scale(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Solution Scale";
- ot->description = "Set object solution scale using distance between two selected tracks";
- ot->idname = "CLIP_OT_set_solution_scale";
-
- /* api callbacks */
- ot->exec = set_solution_scale_exec;
- ot->invoke = set_solution_scale_invoke;
- ot->poll = set_solution_scale_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
- "Distance", "Distance between selected tracks", -100.0f, 100.0f);
-}
-
-/********************** apply solution scale operator *********************/
-
-static int apply_solution_scale_poll(bContext *C)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
-
- if (sc) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (clip) {
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
-
- return tracking_object->flag & TRACKING_OBJECT_CAMERA;
- }
- }
-
- return false;
-}
-
-static int apply_solution_scale_exec(bContext *C, wmOperator *op)
-{
- return do_set_scale(C, op, false, true);
-}
-
-static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
-
- if (!RNA_struct_property_is_set(op->ptr, "distance"))
- RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
-
- return apply_solution_scale_exec(C, op);
-}
-
-void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Solution Scale";
- ot->description = "Apply scale on solution itself to make distance between selected tracks equals to desired";
- ot->idname = "CLIP_OT_apply_solution_scale";
-
- /* api callbacks */
- ot->exec = apply_solution_scale_exec;
- ot->invoke = apply_solution_scale_invoke;
- ot->poll = apply_solution_scale_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
- "Distance", "Distance between selected tracks", -100.0f, 100.0f);
-}
-
/********************** set principal center operator *********************/
static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2748,8 +1246,9 @@ static int set_center_principal_exec(bContext *C, wmOperator *UNUSED(op))
BKE_movieclip_get_size(clip, &sc->user, &width, &height);
- if (width == 0 || height == 0)
+ if (width == 0 || height == 0) {
return OPERATOR_CANCELLED;
+ }
clip->tracking.camera.principal[0] = ((float)width) / 2.0f;
clip->tracking.camera.principal[1] = ((float)height) / 2.0f;
@@ -2780,39 +1279,36 @@ static int hide_tracks_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
- MovieTrackingPlaneTrack *act_plane_track = BKE_tracking_plane_track_get_active(&clip->tracking);
int unselected;
unselected = RNA_boolean_get(op->ptr, "unselected");
- track = tracksbase->first;
- while (track) {
+ /* Hide point tracks. */
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
if (unselected == 0 && TRACK_VIEW_SELECTED(sc, track)) {
track->flag |= TRACK_HIDDEN;
}
else if (unselected == 1 && !TRACK_VIEW_SELECTED(sc, track)) {
track->flag |= TRACK_HIDDEN;
}
-
- track = track->next;
}
- if (act_track && act_track->flag & TRACK_HIDDEN)
+ if (act_track != NULL && act_track->flag & TRACK_HIDDEN) {
clip->tracking.act_track = NULL;
-
- if (unselected == 0) {
- /* no selection on screen now, unlock view so it can be scrolled nice again */
- sc->flag &= ~SC_LOCK_SELECTION;
}
- for (plane_track = plane_tracks_base->first;
- plane_track;
+ /* Hide place tracks. */
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ MovieTrackingPlaneTrack *act_plane_track =
+ BKE_tracking_plane_track_get_active(tracking);
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
plane_track = plane_track->next)
{
if (unselected == 0 && plane_track->flag & SELECT) {
@@ -2822,13 +1318,18 @@ static int hide_tracks_exec(bContext *C, wmOperator *op)
plane_track->flag |= PLANE_TRACK_HIDDEN;
}
}
-
- if (act_plane_track && act_plane_track->flag & TRACK_HIDDEN) {
+ if (act_plane_track != NULL && act_plane_track->flag & TRACK_HIDDEN) {
clip->tracking.act_plane_track = NULL;
}
- BKE_tracking_dopesheet_tag_update(tracking);
+ if (unselected == 0) {
+ /* No selection on screen now, unlock view so it can be
+ * scrolled nice again.
+ */
+ sc->flag &= ~SC_LOCK_SELECTION;
+ }
+ BKE_tracking_dopesheet_tag_update(tracking);
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, NULL);
return OPERATOR_FINISHED;
@@ -2859,20 +1360,20 @@ static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
- track = tracksbase->first;
- while (track) {
+ /* Unhide point tracks. */
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
track->flag &= ~TRACK_HIDDEN;
-
- track = track->next;
}
- for (plane_track = plane_tracks_base->first;
- plane_track;
+ /* Unhide plane tracks. */
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
plane_track = plane_track->next)
{
plane_track->flag &= ~PLANE_TRACK_HIDDEN;
@@ -2900,101 +1401,6 @@ void CLIP_OT_hide_tracks_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** detect features operator *********************/
-
-static bGPDlayer *detect_get_layer(MovieClip *clip)
-{
- bGPDlayer *layer;
-
- if (!clip->gpd)
- return NULL;
-
- layer = clip->gpd->layers.first;
- while (layer) {
- if (layer->flag & GP_LAYER_ACTIVE)
- return layer;
-
- layer = layer->next;
- }
-
- return NULL;
-}
-
-static int detect_features_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
- ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag, MOVIECLIP_CACHE_SKIP);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track = tracksbase->first;
- int placement = RNA_enum_get(op->ptr, "placement");
- int margin = RNA_int_get(op->ptr, "margin");
- int min_distance = RNA_int_get(op->ptr, "min_distance");
- float threshold = RNA_float_get(op->ptr, "threshold");
- int place_outside_layer = 0;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- bGPDlayer *layer = NULL;
-
- if (!ibuf) {
- BKE_report(op->reports, RPT_ERROR, "Feature detection requires valid clip frame");
- return OPERATOR_CANCELLED;
- }
-
- if (placement != 0) {
- layer = detect_get_layer(clip);
- place_outside_layer = placement == 2;
- }
-
- /* deselect existing tracks */
- while (track) {
- track->flag &= ~SELECT;
- track->pat_flag &= ~SELECT;
- track->search_flag &= ~SELECT;
-
- track = track->next;
- }
-
- BKE_tracking_detect_harris(tracking, tracksbase, ibuf, framenr, margin,
- threshold / 100000.0f, min_distance, layer, place_outside_layer);
-
- IMB_freeImBuf(ibuf);
-
- BKE_tracking_dopesheet_tag_update(tracking);
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_detect_features(wmOperatorType *ot)
-{
- static EnumPropertyItem placement_items[] = {
- {0, "FRAME", 0, "Whole Frame", "Place markers across the whole frame"},
- {1, "INSIDE_GPENCIL", 0, "Inside grease pencil", "Place markers only inside areas outlined with grease pencil"},
- {2, "OUTSIDE_GPENCIL", 0, "Outside grease pencil", "Place markers only outside areas outlined with grease pencil"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Detect Features";
- ot->description = "Automatically detect features and place markers to track";
- ot->idname = "CLIP_OT_detect_features";
-
- /* api callbacks */
- ot->exec = detect_features_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
- RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only features further than margin pixels from the image edges are considered", 0, 300);
- RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX);
- RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two features", 0, 300);
-}
-
/********************** frame jump operator *********************/
static int frame_jump_exec(bContext *C, wmOperator *op)
@@ -3002,50 +1408,57 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingTrack *track;
+ MovieTracking *tracking = &clip->tracking;
int pos = RNA_enum_get(op->ptr, "position");
int delta;
if (pos <= 1) { /* jump to path */
- track = BKE_tracking_track_get_active(&clip->tracking);
-
- if (!track)
+ MovieTrackingTrack *track = BKE_tracking_track_get_active(tracking);
+ if (track == NULL) {
return OPERATOR_CANCELLED;
+ }
delta = pos == 1 ? 1 : -1;
+ while (sc->user.framenr + delta >= SFRA &&
+ sc->user.framenr + delta <= EFRA)
+ {
+ int framenr = BKE_movieclip_remap_scene_to_clip_frame(
+ clip,
+ sc->user.framenr + delta);
+ MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track,
+ framenr);
- while (sc->user.framenr + delta >= SFRA && sc->user.framenr + delta <= EFRA) {
- int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr + delta);
- MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
-
- if (!marker || marker->flag & MARKER_DISABLED)
+ if (marker == NULL || marker->flag & MARKER_DISABLED) {
break;
+ }
sc->user.framenr += delta;
}
}
else { /* to to failed frame */
- if (clip->tracking.reconstruction.flag & TRACKING_RECONSTRUCTED) {
- int a = ED_space_clip_get_clip_frame_number(sc);
- MovieTracking *tracking = &clip->tracking;
+ if (tracking->reconstruction.flag & TRACKING_RECONSTRUCTED) {
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
delta = pos == 3 ? 1 : -1;
-
- a += delta;
-
- while (a + delta >= SFRA && a + delta <= EFRA) {
- MovieReconstructedCamera *cam;
-
- cam = BKE_tracking_camera_get_reconstructed(tracking, object, a);
-
- if (!cam) {
- sc->user.framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, a);
-
+ framenr += delta;
+
+ while (framenr + delta >= SFRA &&
+ framenr + delta <= EFRA)
+ {
+ MovieReconstructedCamera *cam =
+ BKE_tracking_camera_get_reconstructed(tracking,
+ object,
+ framenr);
+
+ if (cam == NULL) {
+ sc->user.framenr =
+ BKE_movieclip_remap_clip_to_scene_frame(clip,
+ framenr);
break;
}
- a += delta;
+ framenr += delta;
}
}
}
@@ -3065,10 +1478,10 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
void CLIP_OT_frame_jump(wmOperatorType *ot)
{
static EnumPropertyItem position_items[] = {
- {0, "PATHSTART", 0, "Path Start", "Jump to start of current path"},
- {1, "PATHEND", 0, "Path End", "Jump to end of current path"},
- {2, "FAILEDPREV", 0, "Previous Failed", "Jump to previous failed frame"},
- {2, "FAILNEXT", 0, "Next Failed", "Jump to next failed frame"},
+ {0, "PATHSTART", 0, "Path Start", "Jump to start of current path"},
+ {1, "PATHEND", 0, "Path End", "Jump to end of current path"},
+ {2, "FAILEDPREV", 0, "Previous Failed", "Jump to previous failed frame"},
+ {2, "FAILNEXT", 0, "Next Failed", "Jump to next failed frame"},
{0, NULL, 0, NULL, NULL}
};
@@ -3085,7 +1498,8 @@ void CLIP_OT_frame_jump(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "position", position_items, 0, "Position", "Position to jump to");
+ RNA_def_enum(ot->srna, "position", position_items, 0, "Position",
+ "Position to jump to");
}
/********************** join tracks operator *********************/
@@ -3096,38 +1510,56 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *act_track, *track, *next;
-
- act_track = BKE_tracking_track_get_active(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- if (!act_track) {
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+ if (act_track == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active track to join to");
return OPERATOR_CANCELLED;
}
- track = tracksbase->first;
- while (track) {
- next = track->next;
+ GSet *point_tracks = BLI_gset_ptr_new(__func__);
+ for (MovieTrackingTrack *track = tracksbase->first, *next_track;
+ track != NULL;
+ track = next_track)
+ {
+ next_track = track->next;
if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
BKE_tracking_tracks_join(tracking, act_track, track);
- if (tracking->stabilization.rot_track == track)
+ if (tracking->stabilization.rot_track == track) {
tracking->stabilization.rot_track = act_track;
+ }
- /* TODO(sergey): Re-evaluate planes with auto-key. */
- BKE_tracking_plane_tracks_replace_point_track(tracking,
- track,
- act_track);
-
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
+ plane_track = plane_track->next)
+ {
+ if (BKE_tracking_plane_track_has_point_track(plane_track, track)) {
+ BKE_tracking_plane_track_replace_point_track(plane_track,
+ track,
+ act_track);
+ if ((plane_track->flag & PLANE_TRACK_AUTOKEY) == 0) {
+ BLI_gset_insert(point_tracks, plane_track);
+ }
+ }
+ }
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
}
+ }
- track = next;
+ GSetIterator gs_iter;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ GSET_ITER (gs_iter, point_tracks) {
+ MovieTrackingPlaneTrack *plane_track = BLI_gsetIterator_getKey(&gs_iter);
+ BKE_tracking_track_plane_from_existing_motion( plane_track, framenr);
}
+ BLI_gset_free(point_tracks, NULL);
+
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
return OPERATOR_FINISHED;
@@ -3150,25 +1582,37 @@ void CLIP_OT_join_tracks(wmOperatorType *ot)
/********************** lock tracks operator *********************/
+enum {
+ TRACK_ACTION_LOCK = 0,
+ TRACK_ACTION_UNLOCK = 1,
+ TRACK_ACTION_TOGGLE = 2,
+};
+
static int lock_tracks_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track = tracksbase->first;
int action = RNA_enum_get(op->ptr, "action");
- while (track) {
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
if (TRACK_VIEW_SELECTED(sc, track)) {
- if (action == 0)
- track->flag |= TRACK_LOCKED;
- else if (action == 1)
- track->flag &= ~TRACK_LOCKED;
- else track->flag ^= TRACK_LOCKED;
+ switch (action) {
+ case TRACK_ACTION_LOCK:
+ track->flag |= TRACK_LOCKED;
+ break;
+ case TRACK_ACTION_UNLOCK:
+ track->flag &= ~TRACK_LOCKED;
+ break;
+ case TRACK_ACTION_TOGGLE:
+ track->flag ^= TRACK_LOCKED;
+ break;
+ }
}
-
- track = track->next;
}
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
@@ -3179,9 +1623,10 @@ static int lock_tracks_exec(bContext *C, wmOperator *op)
void CLIP_OT_lock_tracks(wmOperatorType *ot)
{
static EnumPropertyItem actions_items[] = {
- {0, "LOCK", 0, "Lock", "Lock selected tracks"},
- {1, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
- {2, "TOGGLE", 0, "Toggle", "Toggle locked flag for selected tracks"},
+ {TRACK_ACTION_LOCK, "LOCK", 0, "Lock", "Lock selected tracks"},
+ {TRACK_ACTION_UNLOCK, "UNLOCK", 0, "Unlock", "Unlock selected tracks"},
+ {TRACK_ACTION_TOGGLE, "TOGGLE", 0, "Toggle",
+ "Toggle locked flag for selected tracks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3198,11 +1643,17 @@ void CLIP_OT_lock_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Lock action to execute");
+ RNA_def_enum(ot->srna, "action", actions_items, 0, "Action",
+ "Lock action to execute");
}
/********************** set keyframe operator *********************/
+enum {
+ SOLVER_KEYFRAME_A = 0,
+ SOLVER_KEYFRAME_B = 1,
+};
+
static int set_solver_keyframe_exec(bContext *C, wmOperator *op)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -3210,12 +1661,15 @@ static int set_solver_keyframe_exec(bContext *C, wmOperator *op)
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
int keyframe = RNA_enum_get(op->ptr, "keyframe");
- int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr);
+ int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip,
+ sc->user.framenr);
- if (keyframe == 0)
+ if (keyframe == SOLVER_KEYFRAME_A) {
object->keyframe1 = framenr;
- else
+ }
+ else {
object->keyframe2 = framenr;
+ }
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
@@ -3225,8 +1679,8 @@ static int set_solver_keyframe_exec(bContext *C, wmOperator *op)
void CLIP_OT_set_solver_keyframe(wmOperatorType *ot)
{
static EnumPropertyItem keyframe_items[] = {
- {0, "KEYFRAME_A", 0, "Keyframe A", ""},
- {1, "KEYFRAME_B", 0, "Keyframe B", ""},
+ {SOLVER_KEYFRAME_A, "KEYFRAME_A", 0, "Keyframe A", ""},
+ {SOLVER_KEYFRAME_B, "KEYFRAME_B", 0, "Keyframe B", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3243,7 +1697,8 @@ void CLIP_OT_set_solver_keyframe(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe", "Keyframe to set");
+ RNA_def_enum(ot->srna, "keyframe", keyframe_items, 0, "Keyframe",
+ "Keyframe to set");
}
/********************** track copy color operator *********************/
@@ -3254,23 +1709,23 @@ static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track, *act_track = BKE_tracking_track_get_active(tracking);
- if (!act_track)
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+ if (act_track == NULL) {
return OPERATOR_CANCELLED;
+ }
- track = tracksbase->first;
- while (track) {
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
if (TRACK_VIEW_SELECTED(sc, track) && track != act_track) {
track->flag &= ~TRACK_CUSTOMCOLOR;
-
if (act_track->flag & TRACK_CUSTOMCOLOR) {
copy_v3_v3(track->color, act_track->color);
track->flag |= TRACK_CUSTOMCOLOR;
}
}
-
- track = track->next;
}
WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
@@ -3293,229 +1748,31 @@ void CLIP_OT_track_copy_color(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** add 2d stabilization tracks operator *********************/
-
-static int stabilize_2d_poll(bContext *C)
-{
- if (ED_space_clip_tracking_poll(C)) {
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
-
- return tracking_object->flag & TRACKING_OBJECT_CAMERA;
- }
-
- return false;
-}
-
-static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- int update = 0;
-
- track = tracksbase->first;
- while (track) {
- if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_USE_2D_STAB) == 0) {
- track->flag |= TRACK_USE_2D_STAB;
- stab->tot_track++;
-
- update = 1;
- }
-
- track = track->next;
- }
-
- if (update) {
- stab->ok = 0;
-
- DAG_id_tag_update(&clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Stabilization Tracks";
- ot->description = "Add selected tracks to 2D stabilization tool";
- ot->idname = "CLIP_OT_stabilize_2d_add";
-
- /* api callbacks */
- ot->exec = stabilize_2d_add_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** remove 2d stabilization tracks operator *********************/
-
-static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track;
- int a = 0, update = 0;
-
- track = tracksbase->first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB) {
- if (a == stab->act_track) {
- track->flag &= ~TRACK_USE_2D_STAB;
-
- stab->act_track--;
- stab->tot_track--;
-
- if (stab->act_track < 0)
- stab->act_track = 0;
-
- update = 1;
-
- break;
- }
-
- a++;
- }
-
- track = track->next;
- }
-
- if (update) {
- stab->ok = 0;
-
- DAG_id_tag_update(&clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Stabilization Track";
- ot->description = "Remove selected track from stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_remove";
-
- /* api callbacks */
- ot->exec = stabilize_2d_remove_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** select 2d stabilization tracks operator *********************/
-
-static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track;
- int update = 0;
-
- track = tracksbase->first;
- while (track) {
- if (track->flag & TRACK_USE_2D_STAB) {
- BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
-
- update = 1;
- }
-
- track = track->next;
- }
-
- if (update)
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Stabilization Tracks";
- ot->description = "Select tracks which are used for stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_select";
-
- /* api callbacks */
- ot->exec = stabilize_2d_select_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** set 2d stabilization rotation track operator *********************/
-
-static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
-
- if (act_track) {
- MovieTrackingStabilization *stab = &tracking->stabilization;
-
- stab->rot_track = act_track;
- stab->ok = 0;
-
- DAG_id_tag_update(&clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Rotation Track";
- ot->description = "Use active track to compensate rotation when doing 2D stabilization";
- ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
-
- /* api callbacks */
- ot->exec = stabilize_2d_set_rotation_exec;
- ot->poll = stabilize_2d_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/********************** clean tracks operator *********************/
static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
{
bool ok = true;
- int a, prev = -1, count = 0;
+ int prev = -1, count = 0;
MovieTrackingMarker *markers = track->markers, *new_markers = NULL;
int start_disabled = 0;
int markersnr = track->markersnr;
- if (del)
- new_markers = MEM_callocN(markersnr * sizeof(MovieTrackingMarker), "track cleaned markers");
+ if (del) {
+ new_markers = MEM_callocN(markersnr * sizeof(MovieTrackingMarker),
+ "track cleaned markers");
+ }
- for (a = 0; a < markersnr; a++) {
+ for (int a = 0; a < markersnr; a++) {
int end = 0;
if (prev == -1) {
- if ((markers[a].flag & MARKER_DISABLED) == 0)
+ if ((markers[a].flag & MARKER_DISABLED) == 0) {
prev = a;
- else
+ }
+ else {
start_disabled = 1;
+ }
}
if (prev >= 0) {
@@ -3527,19 +1784,24 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
if (end) {
int segok = 1, len = 0;
- if (a != prev && markers[a].framenr != markers[a - 1].framenr + 1)
+ if (a != prev && markers[a].framenr != markers[a - 1].framenr + 1) {
len = a - prev;
- else if (markers[a].flag & MARKER_DISABLED)
+ }
+ else if (markers[a].flag & MARKER_DISABLED) {
len = a - prev;
- else len = a - prev + 1;
+ }
+ else {
+ len = a - prev + 1;
+ }
if (frames) {
if (len < frames) {
segok = 0;
ok = 0;
- if (!del)
+ if (!del) {
break;
+ }
}
}
@@ -3547,12 +1809,15 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
if (segok) {
int t = len;
- if (markers[a].flag & MARKER_DISABLED)
+ if (markers[a].flag & MARKER_DISABLED) {
t++;
+ }
- /* place disabled marker in front of current segment */
+ /* Place disabled marker in front of current segment. */
if (start_disabled) {
- memcpy(new_markers + count, markers + prev, sizeof(MovieTrackingMarker));
+ memcpy(new_markers + count,
+ markers + prev,
+ sizeof(MovieTrackingMarker));
new_markers[count].framenr--;
new_markers[count].flag |= MARKER_DISABLED;
@@ -3560,12 +1825,16 @@ static bool is_track_clean(MovieTrackingTrack *track, int frames, int del)
start_disabled = 0;
}
- memcpy(new_markers + count, markers + prev, t * sizeof(MovieTrackingMarker));
+ memcpy(new_markers + count,
+ markers + prev,
+ t * sizeof(MovieTrackingMarker));
count += t;
}
else if (markers[a].flag & MARKER_DISABLED) {
- /* current segment which would be deleted was finished by disabled marker,
- * so next segment should be started from disabled marker */
+ /* Current segment which would be deleted was finished by
+ * disabled marker, so next segment should be started from
+ * disabled marker.
+ */
start_disabled = 1;
}
}
@@ -3597,49 +1866,56 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
- MovieTrackingTrack *track, *next, *act_track = BKE_tracking_track_get_active(tracking);
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
int frames = RNA_int_get(op->ptr, "frames");
int action = RNA_enum_get(op->ptr, "action");
float error = RNA_float_get(op->ptr, "error");
- if (error && action == TRACKING_CLEAN_DELETE_SEGMENT)
+ if (error && action == TRACKING_CLEAN_DELETE_SEGMENT) {
action = TRACKING_CLEAN_DELETE_TRACK;
+ }
- track = tracksbase->first;
- while (track) {
- next = track->next;
+ for (MovieTrackingTrack *track = tracksbase->first, *next_track;
+ track != NULL;
+ track = next_track)
+ {
+ next_track = track->next;
- if ((track->flag & TRACK_HIDDEN) == 0 && (track->flag & TRACK_LOCKED) == 0) {
+ if ((track->flag & TRACK_HIDDEN) == 0 &&
+ (track->flag & TRACK_LOCKED) == 0)
+ {
bool ok;
- ok = (is_track_clean(track, frames, action == TRACKING_CLEAN_DELETE_SEGMENT)) &&
- (error == 0.0f || (track->flag & TRACK_HAS_BUNDLE) == 0 || track->error < error);
+ ok = (is_track_clean(track,
+ frames,
+ action == TRACKING_CLEAN_DELETE_SEGMENT)) &&
+ ((error == 0.0f) ||
+ (track->flag & TRACK_HAS_BUNDLE) == 0 ||
+ (track->error < error));
if (!ok) {
if (action == TRACKING_CLEAN_SELECT) {
BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
}
else if (action == TRACKING_CLEAN_DELETE_TRACK) {
- if (track == act_track)
+ if (track == act_track) {
clip->tracking.act_track = NULL;
-
+ }
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
track = NULL;
}
- /* happens when all tracking segments are not long enough */
+ /* Happens when all tracking segments are not long enough. */
if (track && track->markersnr == 0) {
- if (track == act_track)
+ if (track == act_track) {
clip->tracking.act_track = NULL;
-
+ }
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
}
}
}
-
- track = next;
}
BKE_tracking_dopesheet_tag_update(tracking);
@@ -3649,19 +1925,24 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int clean_tracks_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int clean_tracks_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
{
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!RNA_struct_property_is_set(op->ptr, "frames"))
+ if (!RNA_struct_property_is_set(op->ptr, "frames")) {
RNA_int_set(op->ptr, "frames", clip->tracking.settings.clean_frames);
+ }
- if (!RNA_struct_property_is_set(op->ptr, "error"))
+ if (!RNA_struct_property_is_set(op->ptr, "error")) {
RNA_float_set(op->ptr, "error", clip->tracking.settings.clean_error);
+ }
- if (!RNA_struct_property_is_set(op->ptr, "action"))
+ if (!RNA_struct_property_is_set(op->ptr, "action")) {
RNA_enum_set(op->ptr, "action", clip->tracking.settings.clean_action);
+ }
return clean_tracks_exec(C, op);
}
@@ -3669,9 +1950,12 @@ static int clean_tracks_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
void CLIP_OT_clean_tracks(wmOperatorType *ot)
{
static EnumPropertyItem actions_items[] = {
- {TRACKING_CLEAN_SELECT, "SELECT", 0, "Select", "Select unclean tracks"},
- {TRACKING_CLEAN_DELETE_TRACK, "DELETE_TRACK", 0, "Delete Track", "Delete unclean tracks"},
- {TRACKING_CLEAN_DELETE_SEGMENT, "DELETE_SEGMENTS", 0, "Delete Segments", "Delete unclean segments of tracks"},
+ {TRACKING_CLEAN_SELECT, "SELECT", 0, "Select",
+ "Select unclean tracks"},
+ {TRACKING_CLEAN_DELETE_TRACK, "DELETE_TRACK", 0, "Delete Track",
+ "Delete unclean tracks"},
+ {TRACKING_CLEAN_DELETE_SEGMENT, "DELETE_SEGMENTS", 0, "Delete Segments",
+ "Delete unclean segments of tracks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3690,10 +1974,14 @@ void CLIP_OT_clean_tracks(wmOperatorType *ot)
/* properties */
RNA_def_int(ot->srna, "frames", 0, 0, INT_MAX, "Tracked Frames",
- "Effect on tracks which are tracked less than specified amount of frames", 0, INT_MAX);
+ "Effect on tracks which are tracked less than "
+ "specified amount of frames",
+ 0, INT_MAX);
RNA_def_float(ot->srna, "error", 0.0f, 0.0f, FLT_MAX, "Reprojection Error",
- "Effect on tracks which have got larger re-projection error", 0.0f, 100.0f);
- RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
+ "Effect on tracks which have got larger re-projection error",
+ 0.0f, 100.0f);
+ RNA_def_enum(ot->srna, "action", actions_items, 0, "Action",
+ "Cleanup action to execute");
}
/********************** add tracking object *********************/
@@ -3738,7 +2026,9 @@ static int tracking_object_remove_exec(bContext *C, wmOperator *op)
object = BKE_tracking_object_get_active(tracking);
if (object->flag & TRACKING_OBJECT_CAMERA) {
- BKE_report(op->reports, RPT_WARNING, "Object used for camera tracking cannot be deleted");
+ BKE_report(op->reports,
+ RPT_WARNING,
+ "Object used for camera tracking cannot be deleted");
return OPERATOR_CANCELLED;
}
@@ -3773,7 +2063,7 @@ static int copy_tracks_exec(bContext *C, wmOperator *UNUSED(op))
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
- clear_invisible_track_selection(sc, clip);
+ clip_tracking_clear_invisible_track_selection(sc, clip);
BKE_tracking_clipboard_copy_tracks(tracking, object);
@@ -3795,7 +2085,7 @@ void CLIP_OT_copy_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************** paste tracks from clipboard operator *********************/
+/********************* paste tracks from clipboard operator ********************/
static int paste_tracks_poll(bContext *C)
{
@@ -3837,357 +2127,6 @@ void CLIP_OT_paste_tracks(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Create plane track operator *********************/
-
-static int create_plane_track_tracks_exec(bContext *C, wmOperator *op)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingPlaneTrack *plane_track;
- ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- plane_track = BKE_tracking_plane_track_add(tracking, plane_tracks_base, tracks_base, framenr);
-
- if (plane_track == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Need at least 4 selected point tracks to create a plane");
- return OPERATOR_CANCELLED;
- }
- else {
- BKE_tracking_tracks_deselect_all(tracks_base);
-
- plane_track->flag |= SELECT;
- clip->tracking.act_track = NULL;
- clip->tracking.act_plane_track = plane_track;
-
- /* Copute homoraphies and apply them on marker's corner, so we've got
- * quite nice motion from the very beginning.
- */
- BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
- }
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
-
- return OPERATOR_FINISHED;
-}
-
-void CLIP_OT_create_plane_track(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Create Plane Track";
- ot->description = "Create new plane track out of selected point tracks";
- ot->idname = "CLIP_OT_create_plane_track";
-
- /* api callbacks */
- ot->exec = create_plane_track_tracks_exec;
- ot->poll = ED_space_clip_tracking_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************** Slide plane marker corner operator *********************/
-
-typedef struct SlidePlaneMarkerData {
- int event_type;
- MovieTrackingPlaneTrack *plane_track;
- MovieTrackingPlaneMarker *plane_marker;
- int width, height;
- int corner_index;
- float *corner;
- int previous_mval[2];
- float previous_corner[2];
- float old_corner[2];
- bool accurate;
-} SlidePlaneMarkerData;
-
-static bool mouse_on_plane_slide_zone(SpaceClip *sc, float co[2], float slide_zone[2], int width, int height)
-{
- const float size = 12.0f;
- float dx, dy;
-
- dx = size / width / sc->zoom;
- dy = size / height / sc->zoom;
-
- return IN_RANGE_INCL(co[0], slide_zone[0] - dx, slide_zone[0] + dx) &&
- IN_RANGE_INCL(co[1], slide_zone[1] - dy, slide_zone[1] + dy);
-}
-
-static MovieTrackingPlaneTrack *tracking_plane_marker_check_slide(bContext *C, const wmEvent *event, int *corner_r)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- ARegion *ar = CTX_wm_region(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTrackingPlaneTrack *plane_track;
- int width, height;
- float co[2];
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- ED_space_clip_get_size(sc, &width, &height);
-
- if (width == 0 || height == 0) {
- return NULL;
- }
-
- ED_clip_mouse_pos(sc, ar, event->mval, co);
-
- for (plane_track = plane_tracks_base->first;
- plane_track;
- plane_track = plane_track->next)
- {
- if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
- bool ok = false;
- int i;
-
- for (i = 0; i < 4; i++) {
- if (mouse_on_plane_slide_zone(sc, co, plane_marker->corners[i], width, height)) {
- if (corner_r) {
- *corner_r = i;
- }
- ok = true;
- break;
- }
- }
-
- if (ok) {
- return plane_track;
- }
- }
- }
-
- return NULL;
-}
-
-static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- ARegion *ar = CTX_wm_region(C);
- MovieTrackingPlaneTrack *plane_track;
- int width, height;
- float co[2];
- SlidePlaneMarkerData *customdata = NULL;
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- int corner;
-
- ED_space_clip_get_size(sc, &width, &height);
-
- if (width == 0 || height == 0) {
- return NULL;
- }
-
- ED_clip_mouse_pos(sc, ar, event->mval, co);
-
- plane_track = tracking_plane_marker_check_slide(C, event, &corner);
- if (plane_track) {
- MovieTrackingPlaneMarker *plane_marker;
-
- customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data");
-
- customdata->event_type = event->type;
-
- plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
-
- customdata->plane_track = plane_track;
- customdata->plane_marker = plane_marker;
- customdata->width = width;
- customdata->height = height;
-
- customdata->previous_mval[0] = event->mval[0];
- customdata->previous_mval[1] = event->mval[1];
-
- customdata->corner_index = corner;
- customdata->corner = plane_marker->corners[corner];
-
- copy_v2_v2(customdata->previous_corner, customdata->corner);
- copy_v2_v2(customdata->old_corner, customdata->corner);
- }
-
- return customdata;
-}
-
-static int slide_plane_marker_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SlidePlaneMarkerData *slidedata = slide_plane_marker_customdata(C, event);
-
- if (slidedata) {
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- MovieTracking *tracking = &clip->tracking;
-
- tracking->act_plane_track = slidedata->plane_track;
- tracking->act_track = NULL;
-
- op->customdata = slidedata;
-
- hide_cursor(C);
- WM_event_add_modal_handler(C, op);
-
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
-
- return OPERATOR_RUNNING_MODAL;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-static void cancel_mouse_slide_plane_marker(SlidePlaneMarkerData *data)
-{
- copy_v2_v2(data->corner, data->old_corner);
-}
-
-static void free_slide_plane_marker_data(SlidePlaneMarkerData *data)
-{
- MEM_freeN(data);
-}
-
-static void slide_plane_marker_update_homographies(SpaceClip *sc, SlidePlaneMarkerData *data)
-{
- int framenr = ED_space_clip_get_clip_frame_number(sc);
-
- BKE_tracking_track_plane_from_existing_motion(data->plane_track, framenr);
-}
-
-static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceClip *sc = CTX_wm_space_clip(C);
- MovieClip *clip = ED_space_clip_get_clip(sc);
- SlidePlaneMarkerData *data = (SlidePlaneMarkerData *) op->customdata;
- float dx, dy, mdelta[2];
- int next_corner_index, prev_corner_index, diag_corner_index;
- const float *next_corner, *prev_corner, *diag_corner;
- float next_edge[2], prev_edge[2], next_diag_edge[2], prev_diag_edge[2];
-
- switch (event->type) {
- case LEFTCTRLKEY:
- case RIGHTCTRLKEY:
- case LEFTSHIFTKEY:
- case RIGHTSHIFTKEY:
- if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
- data->accurate = event->val == KM_PRESS;
-
- /* fall-through */
- case MOUSEMOVE:
- mdelta[0] = event->mval[0] - data->previous_mval[0];
- mdelta[1] = event->mval[1] - data->previous_mval[1];
-
- dx = mdelta[0] / data->width / sc->zoom;
- dy = mdelta[1] / data->height / sc->zoom;
-
- if (data->accurate) {
- dx /= 5.0f;
- dy /= 5.0f;
- }
-
- data->corner[0] = data->previous_corner[0] + dx;
- data->corner[1] = data->previous_corner[1] + dy;
-
-
- /*
- prev_edge
- (Corner 3, current) <----------------------- (Corner 2, previous)
- | ^
- | |
- | |
- | |
- next_edge | | next_diag_edge
- | |
- | |
- | |
- v |
- (Corner 0, next) -----------------------> (Corner 1, diagonal)
- prev_diag_edge
- */
-
- next_corner_index = (data->corner_index + 1) % 4;
- prev_corner_index = (data->corner_index + 3) % 4;
- diag_corner_index = (data->corner_index + 2) % 4;
-
- next_corner = data->plane_marker->corners[next_corner_index];
- prev_corner = data->plane_marker->corners[prev_corner_index];
- diag_corner = data->plane_marker->corners[diag_corner_index];
-
- sub_v2_v2v2(next_edge, next_corner, data->corner);
- sub_v2_v2v2(prev_edge, data->corner, prev_corner);
- sub_v2_v2v2(next_diag_edge, prev_corner, diag_corner);
- sub_v2_v2v2(prev_diag_edge, diag_corner, next_corner);
-
- if (cross_v2v2(prev_edge, next_edge) < 0.0f) {
- closest_to_line_v2(data->corner, data->corner, prev_corner, next_corner);
- }
-
- if (cross_v2v2(next_diag_edge, prev_edge) < 0.0f) {
- closest_to_line_v2(data->corner, data->corner, prev_corner, diag_corner);
- }
-
- if (cross_v2v2(next_edge, prev_diag_edge) < 0.0f) {
- closest_to_line_v2(data->corner, data->corner, next_corner, diag_corner);
- }
-
- data->previous_mval[0] = event->mval[0];
- data->previous_mval[1] = event->mval[1];
- copy_v2_v2(data->previous_corner, data->corner);
-
- DAG_id_tag_update(&sc->clip->id, 0);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
-
- break;
-
- case LEFTMOUSE:
- case RIGHTMOUSE:
- if (event->type == data->event_type && event->val == KM_RELEASE) {
- /* Marker is now keyframed. */
- data->plane_marker->flag &= ~PLANE_MARKER_TRACKED;
-
- slide_plane_marker_update_homographies(sc, data);
-
- free_slide_plane_marker_data(op->customdata);
-
- show_cursor(C);
-
- DAG_id_tag_update(&sc->clip->id, 0);
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
-
- return OPERATOR_FINISHED;
- }
-
- break;
-
- case ESCKEY:
- cancel_mouse_slide_plane_marker(op->customdata);
-
- free_slide_plane_marker_data(op->customdata);
-
- show_cursor(C);
-
- WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
-
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-void CLIP_OT_slide_plane_marker(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Slide Plane Marker";
- ot->description = "Slide plane marker areas";
- ot->idname = "CLIP_OT_slide_plane_marker";
-
- /* api callbacks */
- ot->poll = ED_space_clip_tracking_poll;
- ot->invoke = slide_plane_marker_invoke;
- ot->modal = slide_plane_marker_modal;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
-}
-
/********************** Insert track keyframe operator *********************/
static void keyframe_set_flag(bContext *C, bool set)
@@ -4195,42 +2134,55 @@ static void keyframe_set_flag(bContext *C, bool set)
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
- ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking);
- ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
- MovieTrackingTrack *track;
- MovieTrackingPlaneTrack *plane_track;
int framenr = ED_space_clip_get_clip_frame_number(sc);
- for (track = tracks_base->first; track; track = track->next) {
+ ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking);
+ for (MovieTrackingTrack *track = tracks_base->first;
+ track != NULL;
+ track = track->next)
+ {
if (TRACK_VIEW_SELECTED(sc, track)) {
if (set) {
- MovieTrackingMarker *marker = BKE_tracking_marker_ensure(track, framenr);
+ MovieTrackingMarker *marker =
+ BKE_tracking_marker_ensure(track, framenr);
marker->flag &= ~MARKER_TRACKED;
}
else {
- MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
- if (marker) {
+ MovieTrackingMarker *marker =
+ BKE_tracking_marker_get_exact(track, framenr);
+ if (marker != NULL) {
marker->flag |= MARKER_TRACKED;
}
}
}
}
- for (plane_track = plane_tracks_base->first; plane_track; plane_track = plane_track->next) {
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
+ plane_track = plane_track->next)
+ {
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
if (set) {
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_ensure(plane_track, framenr);
if (plane_marker->flag & PLANE_MARKER_TRACKED) {
plane_marker->flag &= ~PLANE_MARKER_TRACKED;
- BKE_tracking_track_plane_from_existing_motion(plane_track, plane_marker->framenr);
+ BKE_tracking_track_plane_from_existing_motion(
+ plane_track,
+ plane_marker->framenr);
}
}
else {
- MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track, framenr);
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_get_exact(plane_track,
+ framenr);
if (plane_marker) {
if ((plane_marker->flag & PLANE_MARKER_TRACKED) == 0) {
plane_marker->flag |= PLANE_MARKER_TRACKED;
- BKE_tracking_retrack_plane_from_existing_motion_at_segment(plane_track, plane_marker->framenr);
+ BKE_tracking_retrack_plane_from_existing_motion_at_segment(
+ plane_track,
+ plane_marker->framenr);
}
}
}
diff --git a/source/blender/editors/space_clip/tracking_ops_detect.c b/source/blender/editors/space_clip/tracking_ops_detect.c
new file mode 100644
index 00000000000..992c347a630
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_detect.c
@@ -0,0 +1,164 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_detect.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "clip_intern.h"
+#include "tracking_ops_intern.h"
+
+/********************** detect features operator *********************/
+
+static bGPDlayer *detect_get_layer(MovieClip *clip)
+{
+ if (clip->gpd == NULL) {
+ return NULL;
+ }
+ for (bGPDlayer *layer = clip->gpd->layers.first;
+ layer != NULL;
+ layer = layer->next)
+ {
+ if (layer->flag & GP_LAYER_ACTIVE) {
+ return layer;
+ }
+ }
+ return NULL;
+}
+
+static int detect_features_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ int clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS;
+ ImBuf *ibuf = BKE_movieclip_get_ibuf_flag(clip,
+ &sc->user,
+ clip_flag,
+ MOVIECLIP_CACHE_SKIP);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int placement = RNA_enum_get(op->ptr, "placement");
+ int margin = RNA_int_get(op->ptr, "margin");
+ int min_distance = RNA_int_get(op->ptr, "min_distance");
+ float threshold = RNA_float_get(op->ptr, "threshold");
+ int place_outside_layer = 0;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ bGPDlayer *layer = NULL;
+
+ if (!ibuf) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Feature detection requires valid clip frame");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (placement != 0) {
+ layer = detect_get_layer(clip);
+ place_outside_layer = placement == 2;
+ }
+
+ /* Deselect existing tracks. */
+ ed_tracking_delect_all_tracks(tracksbase);
+ /* Run detector. */
+ BKE_tracking_detect_harris(tracking,
+ tracksbase,
+ ibuf,
+ framenr,
+ margin,
+ threshold / 100000.0f,
+ min_distance,
+ layer,
+ place_outside_layer);
+
+ IMB_freeImBuf(ibuf);
+
+ BKE_tracking_dopesheet_tag_update(tracking);
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_detect_features(wmOperatorType *ot)
+{
+ static EnumPropertyItem placement_items[] = {
+ {0, "FRAME", 0, "Whole Frame",
+ "Place markers across the whole frame"},
+ {1, "INSIDE_GPENCIL", 0, "Inside grease pencil",
+ "Place markers only inside areas outlined with grease pencil"},
+ {2, "OUTSIDE_GPENCIL", 0, "Outside grease pencil",
+ "Place markers only outside areas outlined with grease pencil"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Detect Features";
+ ot->description = "Automatically detect features and place markers to track";
+ ot->idname = "CLIP_OT_detect_features";
+
+ /* api callbacks */
+ ot->exec = detect_features_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement",
+ "Placement for detected features");
+ RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin",
+ "Only features further than margin pixels from the image "
+ "edges are considered", 0, 300);
+ RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold",
+ "Threshold level to consider feature good enough for tracking",
+ 0.0001f, FLT_MAX);
+ RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance",
+ "Minimal distance accepted between two features", 0, 300);
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_intern.h b/source/blender/editors/space_clip/tracking_ops_intern.h
new file mode 100644
index 00000000000..6ac9287c914
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_intern.h
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_intern.h
+ * \ingroup spclip
+ */
+
+#ifndef __TRACKING_OPS_INTERN_H__
+#define __TRACKING_OPS_INTERN_H__
+
+struct bContext;
+struct ListBase;
+struct MovieClip;
+struct SpaceClip;
+
+/* tracking_utils.c */
+
+void clip_tracking_clear_invisible_track_selection(struct SpaceClip *sc,
+ struct MovieClip *clip);
+
+void clip_tracking_show_cursor(struct bContext *C);
+void clip_tracking_hide_cursor(struct bContext *C);
+
+/* tracking_select.h */
+
+void ed_tracking_delect_all_tracks(struct ListBase *tracks_base);
+void ed_tracking_delect_all_plane_tracks(struct ListBase *plane_tracks_base);
+
+#endif /* __TRACKING_OPS_INTERN_H__ */ \ No newline at end of file
diff --git a/source/blender/editors/space_clip/tracking_ops_orient.c b/source/blender/editors/space_clip/tracking_ops_orient.c
new file mode 100644
index 00000000000..f81180d65a9
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_orient.c
@@ -0,0 +1,860 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_orient.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h" /* SELECT */
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_constraint.h"
+#include "BKE_tracking.h"
+#include "BKE_global.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "clip_intern.h"
+
+/********************** set origin operator *********************/
+
+static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
+{
+ Object *camera = scene->camera;
+
+ if (camera != NULL &&
+ BKE_object_movieclip_get(scene, camera, false) == clip)
+ {
+ return camera;
+ }
+
+ for (Base *base = scene->base.first;
+ base != NULL;
+ base = base->next)
+ {
+ if (base->object->type == OB_CAMERA) {
+ if (BKE_object_movieclip_get(scene, base->object, false) == clip) {
+ camera = base->object;
+ break;
+ }
+ }
+ }
+
+ return camera;
+}
+
+static Object *get_orientation_object(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ Object *object = NULL;
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ object = get_camera_with_movieclip(scene, clip);
+ }
+ else {
+ object = OBACT;
+ }
+
+ if (object != NULL && object->parent != NULL) {
+ object = object->parent;
+ }
+
+ return object;
+}
+
+static int set_orientation_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc != NULL) {
+ Scene *scene = CTX_data_scene(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip != NULL) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ return true;
+ }
+ else {
+ return OBACT != NULL;
+ }
+ }
+ }
+ return false;
+}
+
+static int count_selected_bundles(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int tot = 0;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
+ tot++;
+ }
+ }
+ return tot;
+}
+
+static void object_solver_inverted_matrix(Scene *scene,
+ Object *ob,
+ float invmat[4][4])
+{
+ bool found = false;
+ for (bConstraint *con = ob->constraints.first;
+ con != NULL;
+ con = con->next)
+ {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ if (cti == NULL) {
+ continue;
+ }
+ if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
+ if (!found) {
+ Object *cam = data->camera ? data->camera : scene->camera;
+ BKE_object_where_is_calc_mat4(scene, cam, invmat);
+ }
+ mul_m4_m4m4(invmat, invmat, data->invmat);
+ found = true;
+ }
+ }
+ if (found) {
+ invert_m4(invmat);
+ }
+ else {
+ unit_m4(invmat);
+ }
+}
+
+static Object *object_solver_camera(Scene *scene, Object *ob)
+{
+ for (bConstraint *con = ob->constraints.first;
+ con != NULL;
+ con = con->next)
+ {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ if (cti == NULL) {
+ continue;
+ }
+ if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
+ return (data->camera != NULL) ? data->camera : scene->camera;
+ }
+ }
+ return NULL;
+}
+
+static int set_origin_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ Scene *scene = CTX_data_scene(C);
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ int selected_count = count_selected_bundles(C);
+
+ if (selected_count == 0) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "At least one track with bundle should be selected to "
+ "define origin position");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+
+ float median[3] = {0.0f, 0.0f, 0.0f};
+ zero_v3(median);
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_HAS_BUNDLE))
+ {
+ add_v3_v3(median, track->bundle_pos);
+ }
+ }
+ mul_v3_fl(median, 1.0f / selected_count);
+
+ float mat[4][4], vec[3];
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ mul_v3_m4v3(vec, mat, median);
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ sub_v3_v3(object->loc, vec);
+ }
+ else {
+ object_solver_inverted_matrix(scene, object, mat);
+ mul_v3_m4v3(vec, mat, vec);
+ copy_v3_v3(object->loc, vec);
+ }
+
+ DAG_id_tag_update(&clip->id, 0);
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_set_origin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Origin";
+ ot->description = "Set active marker as origin by moving camera (or its parent if present) in 3D space";
+ ot->idname = "CLIP_OT_set_origin";
+
+ /* api callbacks */
+ ot->exec = set_origin_exec;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "use_median", 0, "Use Median",
+ "Set origin to median point of selected bundles");
+}
+
+/********************** set floor operator *********************/
+
+static void set_axis(Scene *scene,
+ Object *ob,
+ MovieClip *clip,
+ MovieTrackingObject *tracking_object,
+ MovieTrackingTrack *track,
+ char axis)
+{
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
+ bool flip = false;
+ float mat[4][4], vec[3], obmat[4][4], dvec[3];
+
+ BKE_object_to_mat4(ob, obmat);
+
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+ mul_v3_m4v3(vec, mat, track->bundle_pos);
+ copy_v3_v3(dvec, vec);
+
+ if (!is_camera) {
+ float imat[4][4];
+
+ object_solver_inverted_matrix(scene, ob, imat);
+ mul_v3_m4v3(vec, imat, vec);
+
+ invert_m4_m4(imat, obmat);
+ mul_v3_m4v3(dvec, imat, vec);
+
+ sub_v3_v3(vec, obmat[3]);
+ }
+
+ if (len_squared_v2(vec) < (1e-3f * 1e-3f)) {
+ return;
+ }
+
+ unit_m4(mat);
+
+ if (axis == 'X') {
+ if (fabsf(dvec[1]) < 1e-3f) {
+ flip = true;
+
+ mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
+ mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ }
+ else {
+ copy_v3_v3(mat[0], vec);
+
+ if (is_camera || fabsf(vec[2]) < 1e-3f) {
+ mat[0][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
+ }
+ else {
+ vec[2] = 0.0f;
+
+ cross_v3_v3v3(mat[1], mat[0], vec);
+ cross_v3_v3v3(mat[2], mat[0], mat[1]);
+ }
+ }
+ }
+ else {
+ if (fabsf(dvec[0]) < 1e-3f) {
+ flip = true;
+
+ mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
+ mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ }
+ else {
+ copy_v3_v3(mat[1], vec);
+
+ if (is_camera || fabsf(vec[2]) < 1e-3f) {
+ mat[1][2] = 0.0f;
+ mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
+ cross_v3_v3v3(mat[0], mat[1], mat[2]);
+ }
+ else {
+ vec[2] = 0.0f;
+
+ cross_v3_v3v3(mat[0], vec, mat[1]);
+ cross_v3_v3v3(mat[2], mat[0], mat[1]);
+ }
+ }
+ }
+
+ normalize_v3(mat[0]);
+ normalize_v3(mat[1]);
+ normalize_v3(mat[2]);
+
+ if (is_camera) {
+ invert_m4(mat);
+
+ mul_m4_m4m4(mat, mat, obmat);
+ }
+ else {
+ if (!flip) {
+ float lmat[4][4], ilmat[4][4], rmat[3][3];
+
+ BKE_object_rot_to_mat3(ob, rmat, true);
+ invert_m3(rmat);
+ mul_m4_m4m3(mat, mat, rmat);
+
+ unit_m4(lmat);
+ copy_v3_v3(lmat[3], obmat[3]);
+ invert_m4_m4(ilmat, lmat);
+
+ mul_m4_series(mat, lmat, mat, ilmat, obmat);
+ }
+ else {
+ mul_m4_m4m4(mat, obmat, mat);
+ }
+ }
+
+ BKE_object_apply_mat4(ob, mat, 0, 0);
+}
+
+static int set_plane_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ Scene *scene = CTX_data_scene(C);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object;
+ MovieTrackingTrack *track, *axis_track = NULL, *act_track;
+ ListBase *tracksbase;
+ Object *object;
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ int tot = 0;
+ float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
+ int plane = RNA_enum_get(op->ptr, "plane");
+ float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 0.0f, 1.0f}}; /* 90 degrees Y-axis rotation matrix */
+
+ if (count_selected_bundles(C) != 3) {
+ BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ tracking_object = BKE_tracking_object_get_active(tracking);
+ tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ act_track = BKE_tracking_track_get_active(tracking);
+
+ object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+
+ /* Get 3 bundles to use as reference. */
+ track = tracksbase->first;
+ while (track && tot < 3) {
+ if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
+ mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
+ if (tot == 0 || track == act_track) {
+ copy_v3_v3(orig, vec[tot]);
+ }
+ else {
+ axis_track = track;
+ }
+ tot++;
+ }
+ track = track->next;
+ }
+
+ sub_v3_v3(vec[1], vec[0]);
+ sub_v3_v3(vec[2], vec[0]);
+
+ /* Construct ortho-normal basis. */
+ unit_m4(mat);
+ if (plane == 0) { /* floor */
+ cross_v3_v3v3(mat[0], vec[1], vec[2]);
+ copy_v3_v3(mat[1], vec[1]);
+ cross_v3_v3v3(mat[2], mat[0], mat[1]);
+ }
+ else if (plane == 1) { /* wall */
+ cross_v3_v3v3(mat[2], vec[1], vec[2]);
+ copy_v3_v3(mat[1], vec[1]);
+ cross_v3_v3v3(mat[0], mat[1], mat[2]);
+ }
+
+ normalize_v3(mat[0]);
+ normalize_v3(mat[1]);
+ normalize_v3(mat[2]);
+
+ /* Move to origin point. */
+ mat[3][0] = orig[0];
+ mat[3][1] = orig[1];
+ mat[3][2] = orig[2];
+
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ invert_m4(mat);
+
+ BKE_object_to_mat4(object, obmat);
+ mul_m4_m4m4(mat, mat, obmat);
+ mul_m4_m4m4(newmat, rot, mat);
+ BKE_object_apply_mat4(object, newmat, 0, 0);
+
+ /* Make camera have positive z-coordinate. */
+ if (object->loc[2] < 0) {
+ invert_m4(rot);
+ mul_m4_m4m4(newmat, rot, mat);
+ BKE_object_apply_mat4(object, newmat, 0, 0);
+ }
+ }
+ else {
+ BKE_object_apply_mat4(object, mat, 0, 0);
+ }
+
+ BKE_object_where_is_calc(scene, object);
+ set_axis(scene, object, clip, tracking_object, axis_track, 'X');
+
+ DAG_id_tag_update(&clip->id, 0);
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_set_plane(wmOperatorType *ot)
+{
+ static EnumPropertyItem plane_items[] = {
+ {0, "FLOOR", 0, "Floor", "Set floor plane"},
+ {1, "WALL", 0, "Wall", "Set wall plane"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Plane";
+ ot->description = "Set plane based on 3 selected bundles by moving camera "
+ "(or its parent if present) in 3D space";
+ ot->idname = "CLIP_OT_set_plane";
+
+ /* api callbacks */
+ ot->exec = set_plane_exec;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane",
+ "Plane to be used for orientation");
+}
+
+/********************** set axis operator *********************/
+
+static int set_axis_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ Scene *scene = CTX_data_scene(C);
+ Object *object;
+ int axis = RNA_enum_get(op->ptr, "axis");
+
+ if (count_selected_bundles(C) != 1) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Single track with bundle should be selected to define axis");
+ return OPERATOR_CANCELLED;
+ }
+
+ object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking,
+ tracking_object);
+ MovieTrackingTrack *track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_HAS_BUNDLE))
+ {
+ break;
+ }
+ track = track->next;
+ }
+
+ set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
+
+ DAG_id_tag_update(&clip->id, 0);
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_set_axis(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_actions[] = {
+ {0, "X", 0, "X", "Align bundle align X axis"},
+ {1, "Y", 0, "Y", "Align bundle align Y axis"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Axis";
+ ot->description = "Set direction of scene axis rotating camera "
+ "(or its parent if present) and assume selected track "
+ "lies on real axis, joining it with the origin";
+ ot->idname = "CLIP_OT_set_axis";
+
+ /* api callbacks */
+ ot->exec = set_axis_exec;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis",
+ "Axis to use to align bundle along");
+}
+
+/********************** set scale operator *********************/
+
+static int do_set_scale(bContext *C,
+ wmOperator *op,
+ bool scale_solution,
+ bool apply_scale)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ MovieTrackingTrack *track;
+ Scene *scene = CTX_data_scene(C);
+ Object *object = NULL;
+ Object *camera = get_camera_with_movieclip(scene, clip);
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int tot = 0;
+ float vec[2][3], mat[4][4], scale;
+ float dist = RNA_float_get(op->ptr, "distance");
+
+ if (count_selected_bundles(C) != 2) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Two tracks with bundles should be selected to set scale");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!scale_solution && !apply_scale) {
+ object = get_orientation_object(C);
+ if (object == NULL) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "No object to apply orientation on");
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ BKE_tracking_get_camera_object_matrix(scene, camera, mat);
+
+ track = tracksbase->first;
+ while (track) {
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
+ tot++;
+ }
+ track = track->next;
+ }
+
+ sub_v3_v3(vec[0], vec[1]);
+
+ if (len_v3(vec[0]) > 1e-5f) {
+ scale = dist / len_v3(vec[0]);
+ if (apply_scale) {
+ /* Apply scale on reconstructed scene itself. */
+ MovieTrackingReconstruction *reconstruction =
+ BKE_tracking_get_active_reconstruction(tracking);
+ MovieReconstructedCamera *reconstructed_cameras;
+ int i;
+
+ for (track = tracksbase->first; track; track = track->next) {
+ mul_v3_fl(track->bundle_pos, scale);
+ }
+
+ reconstructed_cameras = reconstruction->cameras;
+ for (i = 0; i < reconstruction->camnr; i++) {
+ mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
+ }
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ }
+ else {
+ if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
+ mul_v3_fl(object->size, scale);
+ mul_v3_fl(object->loc, scale);
+ }
+ else if (!scale_solution) {
+ Object *solver_camera = object_solver_camera(scene, object);
+
+ object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
+
+ if (solver_camera) {
+ object->size[0] /= solver_camera->size[0];
+ object->size[1] /= solver_camera->size[1];
+ object->size[2] /= solver_camera->size[2];
+ }
+ }
+ else {
+ tracking_object->scale = scale;
+ }
+
+ DAG_id_tag_update(&clip->id, 0);
+
+ if (object)
+ DAG_id_tag_update(&object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int set_scale_exec(bContext *C, wmOperator *op)
+{
+ return do_set_scale(C, op, false, false);
+}
+
+static int set_scale_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (!RNA_struct_property_is_set(op->ptr, "distance"))
+ RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
+
+ return set_scale_exec(C, op);
+}
+
+void CLIP_OT_set_scale(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Scale";
+ ot->description = "Set scale of scene by scaling camera (or its parent if present)";
+ ot->idname = "CLIP_OT_set_scale";
+
+ /* api callbacks */
+ ot->exec = set_scale_exec;
+ ot->invoke = set_scale_invoke;
+ ot->poll = set_orientation_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+ "Distance", "Distance between selected tracks", -100.0f, 100.0f);
+}
+
+/********************** set solution scale operator *********************/
+
+static int set_solution_scale_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc != NULL) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip != NULL) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object =
+ BKE_tracking_object_get_active(tracking);
+ return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
+ }
+ }
+ return false;
+}
+
+static int set_solution_scale_exec(bContext *C, wmOperator *op)
+{
+ return do_set_scale(C, op, true, false);
+}
+
+static int set_solution_scale_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+
+ if (!RNA_struct_property_is_set(op->ptr, "distance")) {
+ RNA_float_set(op->ptr,
+ "distance",
+ clip->tracking.settings.object_distance);
+ }
+
+ return set_solution_scale_exec(C, op);
+}
+
+void CLIP_OT_set_solution_scale(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Solution Scale";
+ ot->description = "Set object solution scale using distance between "
+ "two selected tracks";
+ ot->idname = "CLIP_OT_set_solution_scale";
+
+ /* api callbacks */
+ ot->exec = set_solution_scale_exec;
+ ot->invoke = set_solution_scale_invoke;
+ ot->poll = set_solution_scale_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+ "Distance", "Distance between selected tracks",
+ -100.0f, 100.0f);
+}
+
+/********************** apply solution scale operator *********************/
+
+static int apply_solution_scale_poll(bContext *C)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ if (sc != NULL) {
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip != NULL) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object =
+ BKE_tracking_object_get_active(tracking);
+ return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
+ }
+ }
+ return 0;
+}
+
+static int apply_solution_scale_exec(bContext *C, wmOperator *op)
+{
+ return do_set_scale(C, op, false, true);
+}
+
+static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (!RNA_struct_property_is_set(op->ptr, "distance")) {
+ RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
+ }
+ return apply_solution_scale_exec(C, op);
+}
+
+void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Solution Scale";
+ ot->description = "Apply scale on solution itself to make distance between "
+ "selected tracks equals to desired";
+ ot->idname = "CLIP_OT_apply_solution_scale";
+
+ /* api callbacks */
+ ot->exec = apply_solution_scale_exec;
+ ot->invoke = apply_solution_scale_invoke;
+ ot->poll = apply_solution_scale_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+ "Distance", "Distance between selected tracks",
+ -100.0f, 100.0f);
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c
new file mode 100644
index 00000000000..4332f3ea765
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_plane.c
@@ -0,0 +1,431 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2011 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_plane.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_tracking.h"
+#include "BKE_depsgraph.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "clip_intern.h"
+#include "tracking_ops_intern.h"
+
+/********************** Create plane track operator *********************/
+
+static int create_plane_track_tracks_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track;
+ ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking);
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ plane_track = BKE_tracking_plane_track_add(tracking,
+ plane_tracks_base,
+ tracks_base,
+ framenr);
+
+ if (plane_track == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Need at least 4 selected point tracks to create a plane");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ BKE_tracking_tracks_deselect_all(tracks_base);
+
+ plane_track->flag |= SELECT;
+ clip->tracking.act_track = NULL;
+ clip->tracking.act_plane_track = plane_track;
+
+ /* Compute homoraphies and apply them on marker's corner, so we've got
+ * quite nice motion from the very beginning.
+ */
+ BKE_tracking_track_plane_from_existing_motion(plane_track, framenr);
+ }
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_create_plane_track(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Plane Track";
+ ot->description = "Create new plane track out of selected point tracks";
+ ot->idname = "CLIP_OT_create_plane_track";
+
+ /* api callbacks */
+ ot->exec = create_plane_track_tracks_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** Slide plane marker corner operator *********************/
+
+typedef struct SlidePlaneMarkerData {
+ int event_type;
+ MovieTrackingPlaneTrack *plane_track;
+ MovieTrackingPlaneMarker *plane_marker;
+ int width, height;
+ int corner_index;
+ float *corner;
+ int previous_mval[2];
+ float previous_corner[2];
+ float old_corner[2];
+ bool accurate;
+} SlidePlaneMarkerData;
+
+static float mouse_to_plane_slide_zone_distance_squared(
+ const float co[2],
+ const float slide_zone[2],
+ int width,
+ int height)
+{
+ float pixel_co[2] = {co[0] * width, co[1] * height},
+ pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
+ return SQUARE(pixel_co[0] - pixel_slide_zone[0]) +
+ SQUARE(pixel_co[1] - pixel_slide_zone[1]);
+}
+
+static MovieTrackingPlaneTrack *tracking_plane_marker_check_slide(
+ bContext *C,
+ const wmEvent *event,
+ int *corner_r)
+{
+ const float distance_clip_squared = 12.0f * 12.0f;
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ int width, height;
+ float co[2];
+ ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ ED_space_clip_get_size(sc, &width, &height);
+ if (width == 0 || height == 0) {
+ return NULL;
+ }
+
+ ED_clip_mouse_pos(sc, ar, event->mval, co);
+
+ float min_distance_squared = FLT_MAX;
+ int min_corner = -1;
+ MovieTrackingPlaneTrack *min_plane_track = NULL;
+ for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first;
+ plane_track != NULL;
+ plane_track = plane_track->next)
+ {
+ if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
+ MovieTrackingPlaneMarker *plane_marker =
+ BKE_tracking_plane_marker_get(plane_track, framenr);
+ for (int i = 0; i < 4; i++) {
+ float distance_squared =
+ mouse_to_plane_slide_zone_distance_squared(
+ co,
+ plane_marker->corners[i],
+ width,
+ height);
+
+ if (distance_squared < min_distance_squared) {
+ min_distance_squared = distance_squared;
+ min_corner = i;
+ min_plane_track = plane_track;
+ }
+ }
+ }
+ }
+
+ if (min_distance_squared < distance_clip_squared / sc->zoom) {
+ if (corner_r != NULL) {
+ *corner_r = min_corner;
+ }
+ return min_plane_track;
+ }
+
+ return NULL;
+}
+
+static void *slide_plane_marker_customdata(bContext *C, const wmEvent *event)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+ MovieTrackingPlaneTrack *plane_track;
+ int width, height;
+ float co[2];
+ SlidePlaneMarkerData *customdata = NULL;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+ int corner;
+
+ ED_space_clip_get_size(sc, &width, &height);
+ if (width == 0 || height == 0) {
+ return NULL;
+ }
+
+ ED_clip_mouse_pos(sc, ar, event->mval, co);
+
+ plane_track = tracking_plane_marker_check_slide(C, event, &corner);
+ if (plane_track) {
+ MovieTrackingPlaneMarker *plane_marker;
+
+ customdata = MEM_callocN(sizeof(SlidePlaneMarkerData), "slide plane marker data");
+
+ customdata->event_type = event->type;
+
+ plane_marker = BKE_tracking_plane_marker_ensure(plane_track, framenr);
+
+ customdata->plane_track = plane_track;
+ customdata->plane_marker = plane_marker;
+ customdata->width = width;
+ customdata->height = height;
+
+ customdata->previous_mval[0] = event->mval[0];
+ customdata->previous_mval[1] = event->mval[1];
+
+ customdata->corner_index = corner;
+ customdata->corner = plane_marker->corners[corner];
+
+ copy_v2_v2(customdata->previous_corner, customdata->corner);
+ copy_v2_v2(customdata->old_corner, customdata->corner);
+ }
+
+ return customdata;
+}
+
+static int slide_plane_marker_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *event)
+{
+ SlidePlaneMarkerData *slidedata = slide_plane_marker_customdata(C, event);
+
+ if (slidedata) {
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+
+ tracking->act_plane_track = slidedata->plane_track;
+ tracking->act_track = NULL;
+
+ op->customdata = slidedata;
+
+ clip_tracking_hide_cursor(C);
+ WM_event_add_modal_handler(C, op);
+
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static void cancel_mouse_slide_plane_marker(SlidePlaneMarkerData *data)
+{
+ copy_v2_v2(data->corner, data->old_corner);
+}
+
+static void free_slide_plane_marker_data(SlidePlaneMarkerData *data)
+{
+ MEM_freeN(data);
+}
+
+static void slide_plane_marker_update_homographies(SpaceClip *sc,
+ SlidePlaneMarkerData *data)
+{
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ BKE_tracking_track_plane_from_existing_motion(data->plane_track, framenr);
+}
+
+static int slide_plane_marker_modal(bContext *C,
+ wmOperator *op,
+ const wmEvent *event)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ SlidePlaneMarkerData *data = (SlidePlaneMarkerData *) op->customdata;
+ float dx, dy, mdelta[2];
+ int next_corner_index, prev_corner_index, diag_corner_index;
+ const float *next_corner, *prev_corner, *diag_corner;
+ float next_edge[2], prev_edge[2], next_diag_edge[2], prev_diag_edge[2];
+
+ switch (event->type) {
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ case LEFTSHIFTKEY:
+ case RIGHTSHIFTKEY:
+ if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
+ data->accurate = event->val == KM_PRESS;
+ }
+
+ /* fall-through */
+ case MOUSEMOVE:
+ mdelta[0] = event->mval[0] - data->previous_mval[0];
+ mdelta[1] = event->mval[1] - data->previous_mval[1];
+
+ dx = mdelta[0] / data->width / sc->zoom;
+ dy = mdelta[1] / data->height / sc->zoom;
+
+ if (data->accurate) {
+ dx /= 5.0f;
+ dy /= 5.0f;
+ }
+
+ data->corner[0] = data->previous_corner[0] + dx;
+ data->corner[1] = data->previous_corner[1] + dy;
+
+
+ /*
+ prev_edge
+ (Corner 3, current) <----------------------- (Corner 2, previous)
+ | ^
+ | |
+ | |
+ | |
+ next_edge | | next_diag_edge
+ | |
+ | |
+ | |
+ v |
+ (Corner 0, next) -----------------------> (Corner 1, diagonal)
+ prev_diag_edge
+ */
+
+ next_corner_index = (data->corner_index + 1) % 4;
+ prev_corner_index = (data->corner_index + 3) % 4;
+ diag_corner_index = (data->corner_index + 2) % 4;
+
+ next_corner = data->plane_marker->corners[next_corner_index];
+ prev_corner = data->plane_marker->corners[prev_corner_index];
+ diag_corner = data->plane_marker->corners[diag_corner_index];
+
+ sub_v2_v2v2(next_edge, next_corner, data->corner);
+ sub_v2_v2v2(prev_edge, data->corner, prev_corner);
+ sub_v2_v2v2(next_diag_edge, prev_corner, diag_corner);
+ sub_v2_v2v2(prev_diag_edge, diag_corner, next_corner);
+
+ if (cross_v2v2(prev_edge, next_edge) < 0.0f) {
+ closest_to_line_v2(data->corner,
+ data->corner,
+ prev_corner,
+ next_corner);
+ }
+
+ if (cross_v2v2(next_diag_edge, prev_edge) < 0.0f) {
+ closest_to_line_v2(data->corner,
+ data->corner,
+ prev_corner,
+ diag_corner);
+ }
+
+ if (cross_v2v2(next_edge, prev_diag_edge) < 0.0f) {
+ closest_to_line_v2(data->corner,
+ data->corner,
+ next_corner,
+ diag_corner);
+ }
+
+ data->previous_mval[0] = event->mval[0];
+ data->previous_mval[1] = event->mval[1];
+ copy_v2_v2(data->previous_corner, data->corner);
+
+ DAG_id_tag_update(&sc->clip->id, 0);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL);
+
+ break;
+
+ case LEFTMOUSE:
+ case RIGHTMOUSE:
+ if (event->type == data->event_type && event->val == KM_RELEASE) {
+ /* Marker is now keyframed. */
+ data->plane_marker->flag &= ~PLANE_MARKER_TRACKED;
+
+ slide_plane_marker_update_homographies(sc, data);
+
+ free_slide_plane_marker_data(op->customdata);
+
+ clip_tracking_show_cursor(C);
+
+ DAG_id_tag_update(&sc->clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_FINISHED;
+ }
+
+ break;
+
+ case ESCKEY:
+ cancel_mouse_slide_plane_marker(op->customdata);
+
+ free_slide_plane_marker_data(op->customdata);
+
+ clip_tracking_show_cursor(C);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void CLIP_OT_slide_plane_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Slide Plane Marker";
+ ot->description = "Slide plane marker areas";
+ ot->idname = "CLIP_OT_slide_plane_marker";
+
+ /* api callbacks */
+ ot->poll = ED_space_clip_tracking_poll;
+ ot->invoke = slide_plane_marker_invoke;
+ ot->modal = slide_plane_marker_modal;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
new file mode 100644
index 00000000000..5c74c1947e3
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -0,0 +1,351 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_solve.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_object_types.h" /* SELECT */
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+#include "BKE_global.h"
+#include "BKE_depsgraph.h"
+#include "BKE_report.h"
+#include "BKE_library.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+
+#include "clip_intern.h"
+
+/********************** solve camera operator *********************/
+
+typedef struct {
+ Scene *scene;
+ MovieClip *clip;
+ MovieClipUser user;
+
+ ReportList *reports;
+
+ char stats_message[256];
+
+ struct MovieReconstructContext *context;
+} SolveCameraJob;
+
+static bool solve_camera_initjob(bContext *C,
+ SolveCameraJob *scj,
+ wmOperator *op,
+ char *error_msg,
+ int max_error)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ Scene *scene = CTX_data_scene(C);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ int width, height;
+
+ if (!BKE_tracking_reconstruction_check(tracking,
+ object,
+ error_msg,
+ max_error))
+ {
+ return false;
+ }
+
+ /* Could fail if footage uses images with different sizes. */
+ BKE_movieclip_get_size(clip, &sc->user, &width, &height);
+
+ scj->clip = clip;
+ scj->scene = scene;
+ scj->reports = op->reports;
+ scj->user = sc->user;
+
+ scj->context = BKE_tracking_reconstruction_context_new(clip,
+ object,
+ object->keyframe1,
+ object->keyframe2,
+ width,
+ height);
+
+ tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
+
+ return true;
+}
+
+static void solve_camera_updatejob(void *scv)
+{
+ SolveCameraJob *scj = (SolveCameraJob *)scv;
+ MovieTracking *tracking = &scj->clip->tracking;
+
+ BLI_strncpy(tracking->stats->message,
+ scj->stats_message,
+ sizeof(tracking->stats->message));
+}
+
+static void solve_camera_startjob(void *scv, short *stop, short *do_update, float *progress)
+{
+ SolveCameraJob *scj = (SolveCameraJob *)scv;
+ BKE_tracking_reconstruction_solve(scj->context,
+ stop,
+ do_update,
+ progress,
+ scj->stats_message,
+ sizeof(scj->stats_message));
+}
+
+static void solve_camera_freejob(void *scv)
+{
+ SolveCameraJob *scj = (SolveCameraJob *)scv;
+ MovieTracking *tracking = &scj->clip->tracking;
+ Scene *scene = scj->scene;
+ MovieClip *clip = scj->clip;
+ int solved;
+
+ if (!scj->context) {
+ /* job weren't fully initialized due to some error */
+ MEM_freeN(scj);
+ return;
+ }
+
+ solved = BKE_tracking_reconstruction_finish(scj->context, tracking);
+ if (!solved) {
+ BKE_report(scj->reports,
+ RPT_WARNING,
+ "Some data failed to reconstruct (see console for details)");
+ }
+ else {
+ BKE_reportf(scj->reports,
+ RPT_INFO,
+ "Average re-projection error: %.3f",
+ tracking->reconstruction.error);
+ }
+
+ /* Set currently solved clip as active for scene. */
+ if (scene->clip != NULL) {
+ id_us_min(&clip->id);
+ }
+ scene->clip = clip;
+ id_us_plus(&clip->id);
+
+ /* Set blender camera focal length so result would look fine there. */
+ if (scene->camera != NULL &&
+ scene->camera->data &&
+ GS(((ID *) scene->camera->data)->name) == ID_CA)
+ {
+ Camera *camera = (Camera *)scene->camera->data;
+ int width, height;
+ BKE_movieclip_get_size(clip, &scj->user, &width, &height);
+ BKE_tracking_camera_to_blender(tracking, scene, camera, width, height);
+ WM_main_add_notifier(NC_OBJECT, camera);
+ }
+
+ MEM_freeN(tracking->stats);
+ tracking->stats = NULL;
+
+ DAG_id_tag_update(&clip->id, 0);
+
+ WM_main_add_notifier(NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, NULL);
+
+ /* Update active clip displayed in scene buttons. */
+ WM_main_add_notifier(NC_SCENE, scene);
+
+ BKE_tracking_reconstruction_context_free(scj->context);
+ MEM_freeN(scj);
+}
+
+static int solve_camera_exec(bContext *C, wmOperator *op)
+{
+ SolveCameraJob *scj;
+ char error_msg[256] = "\0";
+ scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
+ if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ solve_camera_freejob(scj);
+ return OPERATOR_CANCELLED;
+ }
+ solve_camera_startjob(scj, NULL, NULL, NULL);
+ solve_camera_freejob(scj);
+ return OPERATOR_FINISHED;
+}
+
+static int solve_camera_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ SolveCameraJob *scj;
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingReconstruction *reconstruction =
+ BKE_tracking_get_active_reconstruction(tracking);
+ wmJob *wm_job;
+ char error_msg[256] = "\0";
+
+ if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
+ /* only one solve is allowed at a time */
+ return OPERATOR_CANCELLED;
+ }
+
+ scj = MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
+ if (!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
+ }
+ solve_camera_freejob(scj);
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_strncpy(tracking->stats->message,
+ "Solving camera | Preparing solve",
+ sizeof(tracking->stats->message));
+
+ /* Hide reconstruction statistics from previous solve. */
+ reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+
+ /* Setup job. */
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Solve Camera",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_SOLVE_CAMERA);
+ WM_jobs_customdata_set(wm_job, scj, solve_camera_freejob);
+ WM_jobs_timer(wm_job, 0.1, NC_MOVIECLIP | NA_EVALUATED, 0);
+ WM_jobs_callbacks(wm_job,
+ solve_camera_startjob,
+ NULL,
+ solve_camera_updatejob,
+ NULL);
+
+ G.is_break = false;
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_cursor_wait(0);
+
+ /* add modal handler for ESC */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int solve_camera_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ /* No running solver, remove handler and pass through. */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY))
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+
+ /* Running solver. */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void CLIP_OT_solve_camera(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Solve Camera";
+ ot->description = "Solve camera motion from tracks";
+ ot->idname = "CLIP_OT_solve_camera";
+
+ /* api callbacks */
+ ot->exec = solve_camera_exec;
+ ot->invoke = solve_camera_invoke;
+ ot->modal = solve_camera_modal;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************** clear solution operator *********************/
+
+static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ MovieTrackingReconstruction *reconstruction =
+ BKE_tracking_get_active_reconstruction(tracking);
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ track->flag &= ~TRACK_HAS_BUNDLE;
+ }
+
+ if (reconstruction->cameras != NULL) {
+ MEM_freeN(reconstruction->cameras);
+ reconstruction->cameras = NULL;
+ }
+
+ reconstruction->camnr = 0;
+ reconstruction->flag &= ~TRACKING_RECONSTRUCTED;
+
+ DAG_id_tag_update(&clip->id, 0);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_clear_solution(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Solution";
+ ot->description = "Clear all calculated data";
+ ot->idname = "CLIP_OT_clear_solution";
+
+ /* api callbacks */
+ ot->exec = clear_solution_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_stabilize.c b/source/blender/editors/space_clip/tracking_ops_stabilize.c
new file mode 100644
index 00000000000..8d6173e1cea
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_stabilize.c
@@ -0,0 +1,242 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_stabilize.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_tracking.h"
+#include "BKE_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_clip.h"
+
+#include "clip_intern.h"
+
+/********************* add 2d stabilization tracks operator ********************/
+
+static int stabilize_2d_poll(bContext *C)
+{
+ if (ED_space_clip_tracking_poll(C)) {
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTrackingObject *tracking_object =
+ BKE_tracking_object_get_active(&clip->tracking);
+ return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
+ }
+ return 0;
+}
+
+static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+
+ bool update = false;
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track) &&
+ (track->flag & TRACK_USE_2D_STAB) == 0)
+ {
+ track->flag |= TRACK_USE_2D_STAB;
+ stab->tot_track++;
+ update = true;
+ }
+ }
+
+ if (update) {
+ stab->ok = 0;
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Stabilization Tracks";
+ ot->description = "Add selected tracks to 2D stabilization tool";
+ ot->idname = "CLIP_OT_stabilize_2d_add";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_add_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/******************* remove 2d stabilization tracks operator ******************/
+
+static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ int a = 0;
+ bool update = false;
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ if (a == stab->act_track) {
+ track->flag &= ~TRACK_USE_2D_STAB;
+ stab->act_track--;
+ stab->tot_track--;
+ if (stab->act_track < 0) {
+ stab->act_track = 0;
+ }
+ update = true;
+ break;
+ }
+ a++;
+ }
+ }
+
+ if (update) {
+ stab->ok = 0;
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Stabilization Track";
+ ot->description = "Remove selected track from stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_remove";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_remove_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/******************* select 2d stabilization tracks operator ******************/
+
+static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ bool update = false;
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
+ update = true;
+ }
+ }
+
+ if (update) {
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Stabilization Tracks";
+ ot->description = "Select tracks which are used for stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_select";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_select_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/***************** set 2d stabilization rotation track operator ****************/
+
+static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
+
+ if (act_track != NULL) {
+ MovieTrackingStabilization *stab = &tracking->stabilization;
+ stab->rot_track = act_track;
+ stab->ok = 0;
+
+ DAG_id_tag_update(&clip->id, 0);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_stabilize_2d_set_rotation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Rotation Track";
+ ot->description = "Use active track to compensate rotation when "
+ "doing 2D stabilization";
+ ot->idname = "CLIP_OT_stabilize_2d_set_rotation";
+
+ /* api callbacks */
+ ot->exec = stabilize_2d_set_rotation_exec;
+ ot->poll = stabilize_2d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
new file mode 100644
index 00000000000..368cbeaf955
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -0,0 +1,492 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_track.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_main.h"
+#include "BKE_context.h"
+#include "BKE_movieclip.h"
+#include "BKE_tracking.h"
+#include "BKE_global.h"
+#include "BKE_report.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_clip.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "PIL_time.h"
+
+#include "clip_intern.h" // own include
+#include "tracking_ops_intern.h"
+
+/********************** Track operator *********************/
+
+typedef struct TrackMarkersJob {
+ struct AutoTrackContext *context; /* Tracking context */
+ int sfra, efra, lastfra; /* Start, end and recently tracked frames */
+ int backwards; /* Backwards tracking flag */
+ MovieClip *clip; /* Clip which is tracking */
+ float delay; /* Delay in milliseconds to allow
+ * tracking at fixed FPS */
+
+ struct Main *main;
+ struct Scene *scene;
+ struct bScreen *screen;
+} TrackMarkersJob;
+
+static bool track_markers_testbreak(void)
+{
+ return G.is_break;
+}
+
+static int track_count_markers(SpaceClip *sc,
+ MovieClip *clip,
+ int framenr)
+{
+ int tot = 0;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track)
+ : TRACK_SELECTED(track);
+ if (selected && (track->flag & TRACK_LOCKED) == 0) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track,
+ framenr);
+ if (!marker || (marker->flag & MARKER_DISABLED) == 0) {
+ tot++;
+ }
+ }
+ }
+ return tot;
+}
+
+static void track_init_markers(SpaceClip *sc,
+ MovieClip *clip,
+ int framenr,
+ int *frames_limit_r)
+{
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int frames_limit = 0;
+ if (sc != NULL) {
+ clip_tracking_clear_invisible_track_selection(sc, clip);
+ }
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ bool selected = (sc != NULL) ? TRACK_VIEW_SELECTED(sc, track)
+ : TRACK_SELECTED(track);
+ if (selected) {
+ if ((track->flag & TRACK_HIDDEN) == 0 &&
+ (track->flag & TRACK_LOCKED) == 0)
+ {
+ BKE_tracking_marker_ensure(track, framenr);
+ if (track->frames_limit) {
+ if (frames_limit == 0) {
+ frames_limit = track->frames_limit;
+ }
+ else {
+ frames_limit = min_ii(frames_limit,
+ (int)track->frames_limit);
+ }
+ }
+ }
+ }
+ }
+ *frames_limit_r = frames_limit;
+}
+
+static bool track_markers_check_direction(int backwards, int curfra, int efra)
+{
+ if (backwards) {
+ if (curfra < efra) {
+ return false;
+ }
+ }
+ else {
+ if (curfra > efra) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int track_markers_initjob(bContext *C,
+ TrackMarkersJob *tmj,
+ bool backwards,
+ bool sequence)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ Scene *scene = CTX_data_scene(C);
+ MovieTrackingSettings *settings = &clip->tracking.settings;
+ int frames_limit;
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ track_init_markers(sc, clip, framenr, &frames_limit);
+
+ tmj->sfra = ED_space_clip_get_clip_frame_number(sc);
+ tmj->clip = clip;
+ tmj->backwards = backwards;
+
+ if (sequence) {
+ if (backwards) {
+ tmj->efra = SFRA;
+ }
+ else {
+ tmj->efra = EFRA;
+ }
+ }
+ else {
+ if (backwards) {
+ tmj->efra = tmj->sfra - 1;
+ }
+ else {
+ tmj->efra = tmj->sfra + 1;
+ }
+ }
+
+ /* Limit frames to be tracked by user setting. */
+ if (frames_limit) {
+ if (backwards) {
+ tmj->efra = MAX2(tmj->efra, tmj->sfra - frames_limit);
+ }
+ else {
+ tmj->efra = MIN2(tmj->efra, tmj->sfra + frames_limit);
+ }
+ }
+
+ tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
+
+ if (settings->speed != TRACKING_SPEED_FASTEST) {
+ tmj->delay = 1.0f / scene->r.frs_sec * 1000.0f;
+
+ if (settings->speed == TRACKING_SPEED_HALF) {
+ tmj->delay *= 2;
+ }
+ else if (settings->speed == TRACKING_SPEED_QUARTER) {
+ tmj->delay *= 4;
+ }
+ else if (settings->speed == TRACKING_SPEED_DOUBLE) {
+ tmj->delay /= 2;
+ }
+ }
+
+ tmj->context = BKE_autotrack_context_new(clip, &sc->user, backwards, 1);
+
+ clip->tracking_context = tmj->context;
+
+ tmj->lastfra = tmj->sfra;
+
+ /* XXX: silly to store this, but this data is needed to update scene and
+ * movie-clip numbers when tracking is finished. This introduces
+ * better feedback for artists.
+ * Maybe there's another way to solve this problem, but can't think
+ * better way atm.
+ * Anyway, this way isn't more unstable as animation rendering
+ * animation which uses the same approach (except storing screen).
+ */
+ tmj->scene = scene;
+ tmj->main = CTX_data_main(C);
+ tmj->screen = CTX_wm_screen(C);
+
+ return track_markers_check_direction(backwards, tmj->sfra, tmj->efra);
+}
+
+static void track_markers_startjob(void *tmv,
+ short *stop,
+ short *do_update,
+ float *progress)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ int framenr = tmj->sfra;
+
+ while (framenr != tmj->efra) {
+ if (tmj->delay > 0) {
+ /* Tracking should happen with fixed fps. Calculate time
+ * using current timer value before tracking frame and after.
+ *
+ * Small (and maybe unneeded optimization): do not calculate
+ * exec_time for "Fastest" tracking
+ */
+
+ double start_time = PIL_check_seconds_timer(), exec_time;
+
+ if (!BKE_autotrack_context_step(tmj->context)) {
+ break;
+ }
+
+ exec_time = PIL_check_seconds_timer() - start_time;
+ if (tmj->delay > (float)exec_time) {
+ PIL_sleep_ms(tmj->delay - (float)exec_time);
+ }
+ }
+ else if (!BKE_autotrack_context_step(tmj->context)) {
+ break;
+ }
+
+ *do_update = true;
+ *progress = (float)(framenr - tmj->sfra) / (tmj->efra - tmj->sfra);
+
+ if (tmj->backwards) {
+ framenr--;
+ }
+ else {
+ framenr++;
+ }
+
+ tmj->lastfra = framenr;
+
+ if (*stop || track_markers_testbreak()) {
+ break;
+ }
+ }
+}
+
+static void track_markers_updatejob(void *tmv)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ BKE_autotrack_context_sync(tmj->context);
+}
+
+static void track_markers_endjob(void *tmv)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ wmWindowManager *wm = tmj->main->wm.first;
+
+ tmj->clip->tracking_context = NULL;
+ tmj->scene->r.cfra = BKE_movieclip_remap_clip_to_scene_frame(tmj->clip,
+ tmj->lastfra);
+ if (wm != NULL) {
+ ED_update_for_newframe(tmj->main, tmj->scene, 0);
+ }
+
+ BKE_autotrack_context_sync(tmj->context);
+ BKE_autotrack_context_finish(tmj->context);
+
+ WM_main_add_notifier(NC_SCENE | ND_FRAME, tmj->scene);
+}
+
+static void track_markers_freejob(void *tmv)
+{
+ TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
+ BKE_autotrack_context_free(tmj->context);
+ MEM_freeN(tmj);
+}
+
+static int track_markers(bContext *C, wmOperator *op, bool use_job)
+{
+ TrackMarkersJob *tmj;
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ wmJob *wm_job;
+ bool backwards = RNA_boolean_get(op->ptr, "backwards");
+ bool sequence = RNA_boolean_get(op->ptr, "sequence");
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ if (WM_jobs_test(CTX_wm_manager(C), sa, WM_JOB_TYPE_ANY)) {
+ /* Only one tracking is allowed at a time. */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (clip->tracking_context) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (track_count_markers(sc, clip, framenr) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ tmj = MEM_callocN(sizeof(TrackMarkersJob), "TrackMarkersJob data");
+ if (!track_markers_initjob(C, tmj, backwards, sequence)) {
+ track_markers_freejob(tmj);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Setup job. */
+ if (use_job && sequence) {
+ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa,
+ "Track Markers",
+ WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_TRACK_MARKERS);
+ WM_jobs_customdata_set(wm_job, tmj, track_markers_freejob);
+
+ /* If there's delay set in tracking job, tracking should happen
+ * with fixed FPS. To deal with editor refresh we have to synchronize
+ * tracks from job and tracks in clip. Do this in timer callback
+ * to prevent threading conflicts. */
+ if (tmj->delay > 0) {
+ WM_jobs_timer(wm_job,
+ tmj->delay / 1000.0f, NC_MOVIECLIP | NA_EVALUATED, 0);
+ }
+ else {
+ WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | NA_EVALUATED, 0);
+ }
+
+ WM_jobs_callbacks(wm_job,
+ track_markers_startjob,
+ NULL,
+ track_markers_updatejob,
+ track_markers_endjob);
+
+ G.is_break = false;
+
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_cursor_wait(0);
+
+ /* Add modal handler for ESC. */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ short stop = 0, do_update = 0;
+ float progress = 0.0f;
+ track_markers_startjob(tmj, &stop, &do_update, &progress);
+ track_markers_endjob(tmj);
+ track_markers_freejob(tmj);
+ return OPERATOR_FINISHED;
+ }
+}
+
+static int track_markers_exec(bContext *C, wmOperator *op)
+{
+ return track_markers(C, op, false);
+}
+
+static int track_markers_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ return track_markers(C, op, true);
+}
+
+static int track_markers_modal(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *event)
+{
+ /* No running tracking, remove handler and pass through. */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_ANY)) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+
+ /* Running tracking. */
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void CLIP_OT_track_markers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Track Markers";
+ ot->description = "Track selected markers";
+ ot->idname = "CLIP_OT_track_markers";
+
+ /* api callbacks */
+ ot->exec = track_markers_exec;
+ ot->invoke = track_markers_invoke;
+ ot->modal = track_markers_modal;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "backwards", 0, "Backwards",
+ "Do backwards tracking");
+ RNA_def_boolean(ot->srna, "sequence", 0, "Track Sequence",
+ "Track marker during image sequence rather than "
+ "single image");
+}
+
+/********************** Refine track position operator *********************/
+
+static int refine_marker_exec(bContext *C, wmOperator *op)
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
+ bool backwards = RNA_boolean_get(op->ptr, "backwards");
+ int framenr = ED_space_clip_get_clip_frame_number(sc);
+
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if (TRACK_VIEW_SELECTED(sc, track)) {
+ MovieTrackingMarker *marker = BKE_tracking_marker_get(track,
+ framenr);
+ BKE_tracking_refine_marker(clip, track, marker, backwards);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_refine_markers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Refine Markers";
+ ot->description = "Refine selected markers positions "
+ "by running the tracker from track's reference "
+ "to current frame";
+ ot->idname = "CLIP_OT_refine_markers";
+
+ /* api callbacks */
+ ot->exec = refine_marker_exec;
+ ot->poll = ED_space_clip_tracking_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "backwards", 0, "Backwards",
+ "Do backwards tracking");
+}
diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c
new file mode 100644
index 00000000000..4fbee51407d
--- /dev/null
+++ b/source/blender/editors/space_clip/tracking_ops_utils.c
@@ -0,0 +1,79 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation,
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_clip/tracking_ops_utils.c
+ * \ingroup spclip
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_tracking.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "tracking_ops_intern.h" // own include
+
+void clip_tracking_clear_invisible_track_selection(SpaceClip *sc,
+ MovieClip *clip)
+{
+ ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
+ int hidden = 0;
+ if ((sc->flag & SC_SHOW_MARKER_PATTERN) == 0) {
+ hidden |= TRACK_AREA_PAT;
+ }
+ if ((sc->flag & SC_SHOW_MARKER_SEARCH) == 0) {
+ hidden |= TRACK_AREA_SEARCH;
+ }
+ if (hidden) {
+ for (MovieTrackingTrack *track = tracksbase->first;
+ track != NULL;
+ track = track->next)
+ {
+ if ((track->flag & TRACK_HIDDEN) == 0) {
+ BKE_tracking_track_flag_clear(track, hidden, SELECT);
+ }
+ }
+ }
+}
+
+void clip_tracking_hide_cursor(bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, CURSOR_NONE);
+}
+
+void clip_tracking_show_cursor(bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, CURSOR_STD);
+}
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 8a2bf17c667..e970b1b9743 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -53,7 +53,8 @@
#include "UI_view2d.h"
-#include "clip_intern.h" // own include
+#include "tracking_ops_intern.h" /* own include */
+#include "clip_intern.h" /* own include */
static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
@@ -244,22 +245,22 @@ static MovieTrackingPlaneTrack *find_nearest_plane_track(SpaceClip *sc, ListBase
return plane_track;
}
-static void delect_all_tracks(ListBase *tracks_base)
+void ed_tracking_delect_all_tracks(ListBase *tracks_base)
{
MovieTrackingTrack *track;
for (track = tracks_base->first;
- track;
+ track != NULL;
track = track->next)
{
BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
}
}
-static void delect_all_plane_tracks(ListBase *plane_tracks_base)
+void ed_tracking_delect_all_plane_tracks(ListBase *plane_tracks_base)
{
MovieTrackingPlaneTrack *plane_track;
for (plane_track = plane_tracks_base->first;
- plane_track;
+ plane_track != NULL;
plane_track = plane_track->next)
{
plane_track->flag &= ~SELECT;
@@ -292,7 +293,7 @@ static int mouse_select(bContext *C, float co[2], int extend)
}
if (!extend) {
- delect_all_plane_tracks(plane_tracks_base);
+ ed_tracking_delect_all_plane_tracks(plane_tracks_base);
}
if (track) {
@@ -321,7 +322,7 @@ static int mouse_select(bContext *C, float co[2], int extend)
}
else if (plane_track) {
if (!extend) {
- delect_all_tracks(tracksbase);
+ ed_tracking_delect_all_tracks(tracksbase);
}
if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
diff --git a/source/blender/editors/space_console/SConscript b/source/blender/editors/space_console/SConscript
deleted file mode 100644
index f189cd3920a..00000000000
--- a/source/blender/editors/space_console/SConscript
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '../include',
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../../makesdna',
- '../../makesrna',
- '../../blenkernel',
- '../../blenlib',
- '../../gpu',
- '../../windowmanager',
- '../../blenfont',
- ]
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-env.BlenderLib ( 'bf_editors_space_console', sources, incs, defs, libtype=['core'], priority=[95] )
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index d206ce4699e..6396b390ca0 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -68,21 +68,6 @@ static void console_line_color(unsigned char fg[3], int type)
}
}
-typedef struct ConsoleDrawContext {
- int cwidth;
- int lheight;
- int console_width;
- int ymin, ymax;
-#if 0 /* used by textview, may use later */
- int winx;
- int *xy; // [2]
- int *sel; // [2]
- int *pos_pick; /* bottom of view == 0, top of file == combine chars, end of line is lower then start. */
- int *mval; // [2]
- int draw;
-#endif
-} ConsoleDrawContext;
-
void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy)
{
/* fake the edit line being in the scroll buffer */
diff --git a/source/blender/editors/space_console/console_intern.h b/source/blender/editors/space_console/console_intern.h
index d8a4a6fd2bb..5b016b77e9f 100644
--- a/source/blender/editors/space_console/console_intern.h
+++ b/source/blender/editors/space_console/console_intern.h
@@ -49,6 +49,8 @@ ConsoleLine *console_scrollback_add_str(struct SpaceConsole *sc, char *str, bool
ConsoleLine *console_history_verify(const struct bContext *C);
+void console_textview_update_rect(SpaceConsole *sc, ARegion *ar);
+
void CONSOLE_OT_move(struct wmOperatorType *ot);
void CONSOLE_OT_delete(struct wmOperatorType *ot);
void CONSOLE_OT_insert(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 92731c2f135..2b99c4dfa3d 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -63,7 +63,7 @@ static void console_scroll_bottom(ARegion *ar)
v2d->cur.ymax = (float)v2d->winy;
}
-static void console_textview_update_rect(SpaceConsole *sc, ARegion *ar)
+void console_textview_update_rect(SpaceConsole *sc, ARegion *ar)
{
View2D *v2d = &ar->v2d;
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index a592f35f629..182f2bd2e80 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -74,8 +74,8 @@ static SpaceLink *console_new(const bContext *UNUSED(C))
ar->alignment = RGN_ALIGN_BOTTOM;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for text");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for text");
BLI_addtail(&sconsole->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -129,7 +129,7 @@ static SpaceLink *console_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
-static void console_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void console_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
ListBase *lb;
@@ -219,7 +219,7 @@ static void console_dropboxes(void)
/* ************* end drop *********** */
-static void console_main_area_draw(const bContext *C, ARegion *ar)
+static void console_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceConsole *sc = CTX_wm_space_console(C);
@@ -362,27 +362,39 @@ static void console_keymap(struct wmKeyConfig *keyconf)
/****************** header region ******************/
/* add handlers, stuff you only do once or on area/region changes */
-static void console_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void console_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void console_header_area_draw(const bContext *C, ARegion *ar)
+static void console_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void console_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void console_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn)
{
// SpaceInfo *sinfo = sa->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SPACE:
- if (wmn->data == ND_SPACE_CONSOLE) { /* generic redraw request */
- ED_region_tag_redraw(ar);
+ {
+ if (wmn->data == ND_SPACE_CONSOLE) {
+ if (wmn->action == NA_EDITED) {
+ if ((wmn->reference && sa) && (wmn->reference == sa->spacedata.first)) {
+ /* we've modified the geometry (font size), re-calculate rect */
+ console_textview_update_rect(wmn->reference, ar);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ else {
+ /* generic redraw request */
+ ED_region_tag_redraw(ar);
+ }
}
break;
+ }
}
}
@@ -408,10 +420,10 @@ void ED_spacetype_console(void)
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
- art->init = console_main_area_init;
- art->draw = console_main_area_draw;
+ art->init = console_main_region_init;
+ art->draw = console_main_region_draw;
art->cursor = console_cursor;
- art->listener = console_main_area_listener;
+ art->listener = console_main_region_listener;
@@ -423,8 +435,8 @@ void ED_spacetype_console(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
- art->init = console_header_area_init;
- art->draw = console_header_area_draw;
+ art->init = console_header_region_init;
+ art->draw = console_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_file/SConscript b/source/blender/editors/space_file/SConscript
deleted file mode 100644
index a66a14a32de..00000000000
--- a/source/blender/editors/space_file/SConscript
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-incs = [
- '#/intern/atomic',
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blenloader',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'bf_editors_space_file', sources, Split(incs), defs, libtype=['core'], priority=[115] )
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 2d9ecbdf415..52d01063175 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -31,6 +31,7 @@
#include <math.h>
#include <string.h>
+#include <errno.h>
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -426,7 +427,16 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
if (!STREQ(orgname, newname)) {
if (!BLI_exists(newname)) {
- BLI_rename(orgname, newname);
+ errno = 0;
+ if ((BLI_rename(orgname, newname) != 0) ||
+ !BLI_exists(newname))
+ {
+ WM_reportf(RPT_ERROR,
+ "Could not rename: %s",
+ errno ? strerror(errno) : "unknown error");
+ WM_report_banner_show();
+ }
+
/* to make sure we show what is on disk */
ED_fileselect_clear(wm, sa, sfile);
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index baafefab1f6..71e38f72a7a 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -93,6 +93,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
void FILE_OT_smoothscroll(struct wmOperatorType *ot);
+void FILE_OT_filepath_drop(struct wmOperatorType *ot);
int file_exec(bContext *C, struct wmOperator *exec_op);
int file_cancel_exec(bContext *C, struct wmOperator *unused);
@@ -107,7 +108,9 @@ void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but);
int file_highlight_set(struct SpaceFile *sfile, struct ARegion *ar, int mx, int my);
-void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile, char *filepath);
+void file_sfile_filepath_set(struct SpaceFile *sfile, const char *filepath);
+void file_sfile_to_operator_ex(struct wmOperator *op, struct SpaceFile *sfile, char *filepath);
+void file_sfile_to_operator(struct wmOperator *op, struct SpaceFile *sfile);
void file_operator_to_sfile(struct SpaceFile *sfile, struct wmOperator *op);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 8347ad87258..d83a7d5ea62 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -69,6 +69,7 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <errno.h>
/* ---------- FILE SELECTION ------------ */
static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *ar, const rcti *rect_region)
@@ -1041,7 +1042,7 @@ static int bookmark_move_exec(bContext *C, wmOperator *op)
void FILE_OT_bookmark_move(wmOperatorType *ot)
{
static EnumPropertyItem slot_move[] = {
- {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
{FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
{FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
{FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
@@ -1188,7 +1189,7 @@ void FILE_OT_cancel(struct wmOperatorType *ot)
}
-void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
+void file_sfile_to_operator_ex(wmOperator *op, SpaceFile *sfile, char *filepath)
{
PropertyRNA *prop;
@@ -1258,6 +1259,12 @@ void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile, char *filepath)
}
}
+void file_sfile_to_operator(wmOperator *op, SpaceFile *sfile)
+{
+ char filepath[FILE_MAX];
+
+ file_sfile_to_operator_ex(op, sfile, filepath);
+}
void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
{
@@ -1285,14 +1292,35 @@ void file_operator_to_sfile(SpaceFile *sfile, wmOperator *op)
/* XXX, files and dirs updates missing, not really so important though */
}
+/**
+ * Use to set the file selector path from some arbitrary source.
+ */
+void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
+{
+ BLI_assert(BLI_exists(filepath));
+
+ if (BLI_is_dir(filepath)) {
+ BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
+ sfile->params->file[0] = '\0';
+ }
+ else {
+ if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) {
+ BLI_split_dirfile(filepath, sfile->params->dir, sfile->params->file,
+ sizeof(sfile->params->dir), sizeof(sfile->params->file));
+ }
+ else {
+ BLI_split_dir_part(filepath, sfile->params->dir, sizeof(sfile->params->dir));
+ }
+ }
+}
+
void file_draw_check(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
if (op) { /* fail on reload */
if (op->type->check) {
- char filepath[FILE_MAX];
- file_sfile_to_operator(op, sfile, filepath);
+ file_sfile_to_operator(op, sfile);
/* redraw */
if (op->type->check(C, op)) {
@@ -1346,8 +1374,8 @@ int file_exec(bContext *C, wmOperator *exec_op)
BLI_parent_dir(sfile->params->dir);
}
else {
- BLI_cleanup_dir(G.main->name, sfile->params->dir);
- strcat(sfile->params->dir, file->relpath);
+ BLI_cleanup_path(G.main->name, sfile->params->dir);
+ BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
BLI_add_slash(sfile->params->dir);
}
@@ -1375,7 +1403,7 @@ int file_exec(bContext *C, wmOperator *exec_op)
sfile->op = NULL;
- file_sfile_to_operator(op, sfile, filepath);
+ file_sfile_to_operator_ex(op, sfile, filepath);
if (BLI_exists(sfile->params->dir)) {
fsmenu_insert_entry(ED_fsmenu_get(), FS_CATEGORY_RECENT, sfile->params->dir, NULL,
@@ -1652,6 +1680,45 @@ void FILE_OT_smoothscroll(wmOperatorType *ot)
}
+static int filepath_drop_exec(bContext *C, wmOperator *op)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+
+ if (sfile) {
+ char filepath[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+ if (!BLI_exists(filepath)) {
+ BKE_report(op->reports, RPT_ERROR, "File does not exist");
+ return OPERATOR_CANCELLED;
+ }
+
+ file_sfile_filepath_set(sfile, filepath);
+
+ if (sfile->op) {
+ file_sfile_to_operator(sfile->op, sfile);
+ file_draw_check(C);
+ }
+
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void FILE_OT_filepath_drop(wmOperatorType *ot)
+{
+ ot->name = "File Selector Drop";
+ ot->description = "";
+ ot->idname = "FILE_OT_filepath_drop";
+
+ ot->exec = filepath_drop_exec;
+ ot->poll = WM_operator_winactive;
+
+ RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", "");
+}
+
/* create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created.
* The actual name is returned in 'name', 'folder' contains the complete path, including the new folder name.
*/
@@ -1717,16 +1784,18 @@ int file_directory_new_exec(bContext *C, wmOperator *op)
}
/* create the file */
- if (!BLI_dir_create_recursive(path)) {
- BKE_report(op->reports, RPT_ERROR, "Could not create new folder");
+ errno = 0;
+ if (!BLI_dir_create_recursive(path) ||
+ /* Should no more be needed,
+ * now that BLI_dir_create_recursive returns a success state - but kept just in case. */
+ !BLI_exists(path))
+ {
+ BKE_reportf(op->reports, RPT_ERROR,
+ "Could not create new folder: %s",
+ errno ? strerror(errno) : "unknown error");
return OPERATOR_CANCELLED;
}
- /* Should no more be needed, now that BLI_dir_create_recursive returns a success state - but kept just in case. */
- if (!BLI_exists(path)) {
- BKE_report(op->reports, RPT_ERROR, "Could not create new folder");
- return OPERATOR_CANCELLED;
- }
/* now remember file to jump into editing */
BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
@@ -2033,6 +2102,37 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
}
+/**
+ * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
+ */
+static void filenum_newname(char *name, size_t name_size, int add)
+{
+ char head[FILE_MAXFILE], tail[FILE_MAXFILE];
+ char name_temp[FILE_MAXFILE];
+ int pic;
+ unsigned short digits;
+
+ pic = BLI_stringdec(name, head, tail, &digits);
+
+ /* are we going from 100 -> 99 or from 10 -> 9 */
+ if (add < 0 && digits > 0) {
+ int i, exp;
+ exp = 1;
+ for (i = digits; i > 1; i--) {
+ exp *= 10;
+ }
+ if (pic >= exp && (pic + add) < exp) {
+ digits--;
+ }
+ }
+
+ pic += add;
+ if (pic < 0)
+ pic = 0;
+ BLI_stringenc(name_temp, head, tail, digits, pic);
+ BLI_strncpy(name, name_temp, name_size);
+}
+
static int file_filenum_exec(bContext *C, wmOperator *op)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -2040,7 +2140,7 @@ static int file_filenum_exec(bContext *C, wmOperator *op)
int inc = RNA_int_get(op->ptr, "increment");
if (sfile->params && (inc != 0)) {
- BLI_newname(sfile->params->file, inc);
+ filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc);
ED_area_tag_redraw(sa);
file_draw_check(C);
// WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -2159,7 +2259,7 @@ static int file_delete_poll(bContext *C)
return poll;
}
-int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
+int file_delete_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2169,14 +2269,26 @@ int file_delete_exec(bContext *C, wmOperator *UNUSED(op))
int numfiles = filelist_files_ensure(sfile->files);
int i;
+ bool report_error = false;
+ errno = 0;
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
BLI_make_file_string(G.main->name, str, sfile->params->dir, file->relpath);
- BLI_delete(str, false, false);
+ if (BLI_delete(str, false, false) != 0 ||
+ BLI_exists(str))
+ {
+ report_error = true;
+ }
}
}
+ if (report_error) {
+ BKE_reportf(op->reports, RPT_ERROR,
+ "Could not delete file: %s",
+ errno ? strerror(errno) : "unknown error");
+ }
+
ED_fileselect_clear(wm, sa, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 0d1aff09e9c..207879c2809 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -250,12 +250,8 @@ typedef struct FileListEntryCache {
GHash *uuids;
/* Previews handling. */
- TaskScheduler *previews_scheduler;
TaskPool *previews_pool;
- ThreadQueue *previews_todo;
ThreadQueue *previews_done;
- double previews_timestamp;
- int previews_pending;
} FileListEntryCache;
/* FileListCache.flags */
@@ -274,7 +270,7 @@ typedef struct FileListEntryPreview {
typedef struct FileListFilter {
unsigned int filter;
unsigned int filter_id;
- char filter_glob[64];
+ char filter_glob[256];
char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
short flags;
} FileListFilter;
@@ -398,7 +394,7 @@ static int compare_direntry_generic(const FileListInternEntry *entry1, const Fil
}
}
else if (entry2->typeflag & FILE_TYPE_DIR) {
- return 1;
+ return 1;
}
/* make sure "." and ".." are always first */
@@ -532,6 +528,7 @@ void filelist_sort(struct FileList *filelist)
case FILE_SORT_NONE: /* Should never reach this point! */
default:
BLI_assert(0);
+ break;
}
filelist_filter_clear(filelist);
@@ -1061,61 +1058,66 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
MEM_SAFE_FREE(filelist_intern->filtered);
}
-static void filelist_cache_previewf(TaskPool *pool, void *taskdata, int UNUSED(threadid))
+static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata, int UNUSED(threadid))
{
- FileListEntryCache *cache = taskdata;
- FileListEntryPreview *preview;
+ FileListEntryCache *cache = BLI_task_pool_userdata(pool);
+ FileListEntryPreview *preview = taskdata;
+
+ ThumbSource source = 0;
// printf("%s: Start (%d)...\n", __func__, threadid);
- /* Note we wait on queue here. */
- while (!BLI_task_pool_canceled(pool) && (preview = BLI_thread_queue_pop(cache->previews_todo))) {
- ThumbSource source = 0;
+// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
+ BLI_assert(preview->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
+ FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
-// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- BLI_assert(preview->flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
- FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
- if (preview->flags & FILE_TYPE_IMAGE) {
- source = THB_SOURCE_IMAGE;
- }
- else if (preview->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
- source = THB_SOURCE_BLEND;
- }
- else if (preview->flags & FILE_TYPE_MOVIE) {
- source = THB_SOURCE_MOVIE;
- }
- else if (preview->flags & FILE_TYPE_FTFONT) {
- source = THB_SOURCE_FONT;
- }
+ if (preview->flags & FILE_TYPE_IMAGE) {
+ source = THB_SOURCE_IMAGE;
+ }
+ else if (preview->flags & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ source = THB_SOURCE_BLEND;
+ }
+ else if (preview->flags & FILE_TYPE_MOVIE) {
+ source = THB_SOURCE_MOVIE;
+ }
+ else if (preview->flags & FILE_TYPE_FTFONT) {
+ source = THB_SOURCE_FONT;
+ }
- IMB_thumb_path_lock(preview->path);
- preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source);
- IMB_thumb_path_unlock(preview->path);
+ IMB_thumb_path_lock(preview->path);
+ preview->img = IMB_thumb_manage(preview->path, THB_LARGE, source);
+ IMB_thumb_path_unlock(preview->path);
- BLI_thread_queue_push(cache->previews_done, preview);
- }
+ preview->flags = 0; /* Used to tell free func to not free anything! */
+ BLI_thread_queue_push(cache->previews_done, preview);
// printf("%s: End (%d)...\n", __func__, threadid);
}
+static void filelist_cache_preview_freef(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ FileListEntryPreview *preview = taskdata;
+
+ /* If preview->flag is empty, it means that preview has already been generated and added to done queue,
+ * we do not own it anymore. */
+ if (preview->flags) {
+ if (preview->img) {
+ IMB_freeImBuf(preview->img);
+ }
+ MEM_freeN(preview);
+ }
+}
+
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
{
if (!cache->previews_pool) {
- TaskScheduler *scheduler;
- TaskPool *pool;
- int num_tasks = max_ii(1, (BLI_system_thread_count() / 2) + 1);
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
- scheduler = cache->previews_scheduler = BLI_task_scheduler_create(num_tasks + 1);
- pool = cache->previews_pool = BLI_task_pool_create(scheduler, NULL);
- cache->previews_todo = BLI_thread_queue_init();
+ cache->previews_pool = BLI_task_pool_create_background(scheduler, cache);
cache->previews_done = BLI_thread_queue_init();
- while (num_tasks--) {
- BLI_task_pool_push(pool, filelist_cache_previewf, cache, false, TASK_PRIORITY_HIGH);
- }
IMB_thumb_locks_acquire();
}
- cache->previews_timestamp = 0.0;
}
static void filelist_cache_previews_clear(FileListEntryCache *cache)
@@ -1123,48 +1125,34 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache)
FileListEntryPreview *preview;
if (cache->previews_pool) {
- while ((preview = BLI_thread_queue_pop_timeout(cache->previews_todo, 0))) {
-// printf("%s: TODO %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- MEM_freeN(preview);
- cache->previews_pending--;
- }
+ BLI_task_pool_cancel(cache->previews_pool);
+
while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) {
// printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
if (preview->img) {
IMB_freeImBuf(preview->img);
}
MEM_freeN(preview);
- cache->previews_pending--;
}
}
-// printf("%s: remaining pending previews: %d\n", __func__, cache->previews_pending);
}
-static void filelist_cache_previews_free(FileListEntryCache *cache, const bool set_inactive)
+static void filelist_cache_previews_free(FileListEntryCache *cache)
{
if (cache->previews_pool) {
- BLI_thread_queue_nowait(cache->previews_todo);
BLI_thread_queue_nowait(cache->previews_done);
- BLI_task_pool_cancel(cache->previews_pool);
filelist_cache_previews_clear(cache);
BLI_thread_queue_free(cache->previews_done);
- BLI_thread_queue_free(cache->previews_todo);
BLI_task_pool_free(cache->previews_pool);
- BLI_task_scheduler_free(cache->previews_scheduler);
- cache->previews_scheduler = NULL;
cache->previews_pool = NULL;
- cache->previews_todo = NULL;
cache->previews_done = NULL;
IMB_thumb_locks_release();
}
- if (set_inactive) {
- cache->flags &= ~FLC_PREVIEWS_ACTIVE;
- }
- BLI_assert(cache->previews_pending == 0);
- cache->previews_timestamp = 0.0;
+
+ cache->flags &= ~FLC_PREVIEWS_ACTIVE;
}
static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry, const int index)
@@ -1186,8 +1174,8 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
filelist_cache_preview_ensure_running(cache);
- BLI_thread_queue_push(cache->previews_todo, preview);
- cache->previews_pending++;
+ BLI_task_pool_push_ex(cache->previews_pool, filelist_cache_preview_runf, preview,
+ true, filelist_cache_preview_freef, TASK_PRIORITY_LOW);
}
}
@@ -1219,7 +1207,7 @@ static void filelist_cache_free(FileListEntryCache *cache)
return;
}
- filelist_cache_previews_free(cache, true);
+ filelist_cache_previews_free(cache);
MEM_freeN(cache->block_entries);
@@ -1843,7 +1831,7 @@ void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
else if (use_previews && (filelist->flags & FL_IS_READY)) {
cache->flags |= FLC_PREVIEWS_ACTIVE;
- BLI_assert((cache->previews_pool == NULL) && (cache->previews_todo == NULL) && (cache->previews_done == NULL));
+ BLI_assert((cache->previews_pool == NULL) && (cache->previews_done == NULL));
// printf("%s: Init Previews...\n", __func__);
@@ -1852,7 +1840,7 @@ void filelist_cache_previews_set(FileList *filelist, const bool use_previews)
else {
// printf("%s: Clear Previews...\n", __func__);
- filelist_cache_previews_free(cache, true);
+ filelist_cache_previews_free(cache);
}
}
@@ -1876,7 +1864,7 @@ bool filelist_cache_previews_update(FileList *filelist)
if (!preview) {
continue;
}
- /* entry might have been removed from cache in the mean while, we do not want to cache it again here. */
+ /* entry might have been removed from cache in the mean time, we do not want to cache it again here. */
entry = filelist_file_ex(filelist, preview->index, false);
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
@@ -1899,21 +1887,6 @@ bool filelist_cache_previews_update(FileList *filelist)
}
MEM_freeN(preview);
- cache->previews_pending--;
- BLI_assert(cache->previews_pending >= 0);
- }
-
-// printf("%s: Previews pending: %d\n", __func__, cache->previews_pending);
- if (cache->previews_pending == 0) {
- if (cache->previews_timestamp == 0.0) {
- cache->previews_timestamp = PIL_check_seconds_timer();
- }
- else if (PIL_check_seconds_timer() - cache->previews_timestamp > 1.0) {
- /* Preview task is IDLE since more than (approximatively) 1000ms,
- * kill workers & task for now - they will be automatically restarted when needed. */
-// printf("%s: Inactive preview task, sleeping (%f vs %f)!\n", __func__, PIL_check_seconds_timer(), cache->previews_timestamp);
- filelist_cache_previews_free(cache, false);
- }
}
return changed;
@@ -2215,11 +2188,9 @@ static int filelist_readjob_list_dir(
}
/* Otherwise, do not check extensions for directories! */
else if (!(entry->typeflag & FILE_TYPE_DIR)) {
+ entry->typeflag = file_extension_type(root, entry->relpath);
if (filter_glob[0] && BLI_testextensie_glob(entry->relpath, filter_glob)) {
- entry->typeflag = FILE_TYPE_OPERATOR;
- }
- else {
- entry->typeflag = file_extension_type(root, entry->relpath);
+ entry->typeflag |= FILE_TYPE_OPERATOR;
}
}
@@ -2473,6 +2444,7 @@ static void filelist_readjob_do(
bool is_lib = do_lib;
char *subdir;
+ char rel_subdir[FILE_MAX_LIBEXTRA];
int recursion_level;
bool skip_currpar;
@@ -2483,6 +2455,14 @@ static void filelist_readjob_do(
BLI_stack_discard(todo_dirs);
+ /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over entry->relpath itself
+ * (nor any path containing it), since it may actually be a datablock name inside .blend file,
+ * which can have slashes and backslashes! See T46827.
+ * Note that in the end, this means we 'cache' valid relative subdir once here, this is actually better. */
+ BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir));
+ BLI_cleanup_dir(root, rel_subdir);
+ BLI_path_rel(rel_subdir, root);
+
if (do_lib) {
nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar);
}
@@ -2492,8 +2472,7 @@ static void filelist_readjob_do(
}
for (entry = entries.first; entry; entry = entry->next) {
- BLI_join_dirfile(dir, sizeof(dir), subdir, entry->relpath);
- BLI_cleanup_file(root, dir);
+ BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath);
/* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here,
* things would crash way before we overflow that counter!
@@ -2502,10 +2481,9 @@ static void filelist_readjob_do(
* remain consistent about threading! */
*((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1);
- BLI_path_rel(dir, root);
/* Only thing we change in direntry here, so we need to free it first. */
MEM_freeN(entry->relpath);
- entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' added by BLI_path_rel */
+ entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' added by BLI_path_rel to rel_subdir */
entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir));
/* Here we decide whether current filedirentry is to be listed too, or not. */
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index da24f1ce95d..981b101519c 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -186,7 +186,13 @@ short ED_fileselect_set_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_collada")))
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_COLLADA : 0;
if ((prop = RNA_struct_find_property(op->ptr, "filter_glob"))) {
- RNA_property_string_get(op->ptr, prop, params->filter_glob);
+ /* Protection against pyscripts not setting proper size limit... */
+ char *tmp = RNA_property_string_get_alloc(
+ op->ptr, prop, params->filter_glob, sizeof(params->filter_glob), NULL);
+ if (tmp != params->filter_glob) {
+ BLI_strncpy(params->filter_glob, tmp, sizeof(params->filter_glob));
+ MEM_freeN(tmp);
+ }
params->filter |= (FILE_TYPE_OPERATOR | FILE_TYPE_FOLDER);
}
else {
@@ -260,6 +266,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag |= FILE_HIDE_DOT;
params->flag &= ~FILE_DIRSEL_ONLY;
params->display = FILE_SHORTDISPLAY;
+ params->sort = FILE_SORT_ALPHA;
params->filter = 0;
params->filter_glob[0] = '\0';
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 2142368f758..e71c05d19c5 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -304,7 +304,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const c
for (; tfsm; tfsm = tfsm->next) {
if (STREQ(tfsm->path, fsm_iter->path)) {
- if (tfsm->name && tfsm->name[0]) {
+ if (tfsm->name[0]) {
name = tfsm->name;
}
break;
@@ -509,56 +509,6 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
#else
#ifdef __APPLE__
{
-#if (MAC_OS_X_VERSION_MIN_REQUIRED <= 1050)
- OSErr err = noErr;
- int i;
- const char *home;
-
- /* loop through all the OS X Volumes, and add them to the SYSTEM section */
- for (i = 1; err != nsvErr; i++) {
- FSRef dir;
- unsigned char path[FILE_MAX];
-
- err = FSGetVolumeInfo(kFSInvalidVolumeRefNum, i, NULL, kFSVolInfoNone, NULL, NULL, &dir);
- if (err != noErr)
- continue;
-
- FSRefMakePath(&dir, path, FILE_MAX);
- if (!STREQ((char *)path, "/home") && !STREQ((char *)path, "/net")) {
- /* /net and /home are meaningless on OSX, home folders are stored in /Users */
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, NULL, FS_INSERT_SORTED);
- }
- }
-
- /* As 10.4 doesn't provide proper API to retrieve the favorite places,
- * assume they are the standard ones
- * TODO : replace hardcoded paths with proper BKE_appdir_folder_id calls */
- home = getenv("HOME");
- if (read_bookmarks && home) {
- BLI_snprintf(line, sizeof(line), "%s/", home);
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
- BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
- if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
- }
- BLI_snprintf(line, sizeof(line), "%s/Documents/", home);
- if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
- }
- BLI_snprintf(line, sizeof(line), "%s/Pictures/", home);
- if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
- }
- BLI_snprintf(line, sizeof(line), "%s/Music/", home);
- if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
- }
- BLI_snprintf(line, sizeof(line), "%s/Movies/", home);
- if (BLI_exists(line)) {
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
- }
- }
-#else /* OSX 10.6+ */
/* Get mounted volumes better method OSX 10.6 and higher, see: */
/*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/
/* we get all volumes sorted including network and do not relay on user-defined finder visibility, less confusing */
@@ -622,7 +572,6 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(pathesArray);
CFRelease(list);
}
-#endif /* OSX 10.6+ */
}
#else
/* unix */
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 97c2d75e469..e77f545fbc0 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -82,25 +82,25 @@ static SpaceLink *file_new(const bContext *UNUSED(C))
ar->alignment = RGN_ALIGN_TOP;
/* Tools region */
- ar = MEM_callocN(sizeof(ARegion), "tools area for file");
+ ar = MEM_callocN(sizeof(ARegion), "tools region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
/* Tool props (aka operator) region */
- ar = MEM_callocN(sizeof(ARegion), "tool props area for file");
+ ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_TOOL_PROPS;
ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
/* ui list region */
- ar = MEM_callocN(sizeof(ARegion), "ui area for file");
+ ar = MEM_callocN(sizeof(ARegion), "ui region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_TOP;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for file");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
@@ -281,7 +281,7 @@ static void file_refresh(const bContext *C, ScrArea *sa)
sfile->layout->dirty = true;
}
- /* Might be called with NULL sa, see file_main_area_draw() below. */
+ /* Might be called with NULL sa, see file_main_region_draw() below. */
if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
/* Create TOOLS/TOOL_PROPS regions. */
file_tools_region(sa);
@@ -319,7 +319,7 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void file_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void file_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -333,7 +333,7 @@ static void file_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void file_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void file_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -350,7 +350,7 @@ static void file_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR
}
}
-static void file_main_area_draw(const bContext *C, ARegion *ar)
+static void file_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -435,36 +435,48 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_bookmark_cleanup);
WM_operatortype_append(FILE_OT_bookmark_move);
WM_operatortype_append(FILE_OT_reset_recent);
- WM_operatortype_append(FILE_OT_hidedot);
WM_operatortype_append(FILE_OT_filenum);
WM_operatortype_append(FILE_OT_directory_new);
WM_operatortype_append(FILE_OT_delete);
WM_operatortype_append(FILE_OT_rename);
WM_operatortype_append(FILE_OT_smoothscroll);
+ WM_operatortype_append(FILE_OT_filepath_drop);
}
/* NOTE: do not add .blend file reading on this level */
static void file_keymap(struct wmKeyConfig *keyconf)
{
wmKeyMapItem *kmi;
- /* keys for all areas */
+ /* keys for all regions */
wmKeyMap *keymap = WM_keymap_find(keyconf, "File Browser", SPACE_FILE, 0);
- WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", TKEY, KM_PRESS, 0, 0);
+
+ /* More common 'fliebrowser-like navigation' shortcuts. */
+ WM_keymap_add_item(keymap, "FILE_OT_parent", UPARROWKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "FILE_OT_previous", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "FILE_OT_next", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "FILE_OT_refresh", RKEY, KM_PRESS, 0, 0);
+
WM_keymap_add_item(keymap, "FILE_OT_parent", PKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_bookmark_add", BKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "FILE_OT_hidedot", HKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_previous", BACKSPACEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_next", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", HKEY, KM_PRESS, 0, 0);
+ RNA_string_set(kmi->ptr, "data_path", "space_data.params.show_hidden");
WM_keymap_add_item(keymap, "FILE_OT_directory_new", IKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_delete", DELKEY, KM_PRESS, 0, 0);
+
WM_keymap_verify_item(keymap, "FILE_OT_smoothscroll", TIMER1, KM_ANY, KM_ANY, 0);
- /* keys for main area */
+ WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", TKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "FILE_OT_bookmark_add", BKEY, KM_PRESS, KM_CTRL, 0);
+
+ /* keys for main region */
keymap = WM_keymap_find(keyconf, "File Browser Main", SPACE_FILE, 0);
kmi = WM_keymap_add_item(keymap, "FILE_OT_execute", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
RNA_boolean_set(kmi->ptr, "need_active", true);
+ WM_keymap_add_item(keymap, "FILE_OT_refresh", PADPERIOD, KM_PRESS, 0, 0);
+
/* left mouse selects and opens */
WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0);
kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
@@ -532,7 +544,6 @@ static void file_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "FILE_OT_refresh", PADPERIOD, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_select_border", BKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
WM_keymap_add_item(keymap, "FILE_OT_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
@@ -551,7 +562,7 @@ static void file_keymap(struct wmKeyConfig *keyconf)
RNA_int_set(kmi->ptr, "increment", -100);
- /* keys for button area (top) */
+ /* keys for button region (top) */
keymap = WM_keymap_find(keyconf, "File Browser Buttons", SPACE_FILE, 0);
kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0);
RNA_int_set(kmi->ptr, "increment", 1);
@@ -568,7 +579,7 @@ static void file_keymap(struct wmKeyConfig *keyconf)
}
-static void file_tools_area_init(wmWindowManager *wm, ARegion *ar)
+static void file_tools_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -580,12 +591,12 @@ static void file_tools_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void file_tools_area_draw(const bContext *C, ARegion *ar)
+static void file_tools_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
-static void file_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void file_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
#if 0
/* context changes */
@@ -596,7 +607,7 @@ static void file_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A
}
/* add handlers, stuff you only do once or on area/region changes */
-static void file_header_area_init(wmWindowManager *wm, ARegion *ar)
+static void file_header_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -606,13 +617,13 @@ static void file_header_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void file_header_area_draw(const bContext *C, ARegion *ar)
+static void file_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
/* add handlers, stuff you only do once or on area/region changes */
-static void file_ui_area_init(wmWindowManager *wm, ARegion *ar)
+static void file_ui_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -626,7 +637,7 @@ static void file_ui_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void file_ui_area_draw(const bContext *C, ARegion *ar)
+static void file_ui_region_draw(const bContext *C, ARegion *ar)
{
float col[3];
/* clear */
@@ -647,7 +658,7 @@ static void file_ui_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
-static void file_ui_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void file_ui_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -661,6 +672,30 @@ static void file_ui_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AReg
}
}
+static int filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ if (drag->type == WM_DRAG_PATH) {
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ if (sfile) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void filepath_drop_copy(wmDrag *drag, wmDropBox *drop)
+{
+ RNA_string_set(drop->ptr, "filepath", drag->path);
+}
+
+/* region dropbox definition */
+static void file_dropboxes(void)
+{
+ ListBase *lb = WM_dropboxmap_find("Window", SPACE_EMPTY, RGN_TYPE_WINDOW);
+
+ WM_dropbox_add(lb, "FILE_OT_filepath_drop", filepath_drop_poll, filepath_drop_copy);
+}
+
/* only called once, from space/spacetypes.c */
void ED_spacetype_file(void)
{
@@ -679,13 +714,14 @@ void ED_spacetype_file(void)
st->listener = file_listener;
st->operatortypes = file_operatortypes;
st->keymap = file_keymap;
-
+ st->dropboxes = file_dropboxes;
+
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype file region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = file_main_area_init;
- art->draw = file_main_area_draw;
- art->listener = file_main_area_listener;
+ art->init = file_main_region_init;
+ art->draw = file_main_region_draw;
+ art->listener = file_main_region_listener;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
BLI_addhead(&st->regiontypes, art);
@@ -694,9 +730,9 @@ void ED_spacetype_file(void)
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
- art->init = file_header_area_init;
- art->draw = file_header_area_draw;
- // art->listener = file_header_area_listener;
+ art->init = file_header_region_init;
+ art->draw = file_header_region_draw;
+ // art->listener = file_header_region_listener;
BLI_addhead(&st->regiontypes, art);
/* regions: ui */
@@ -704,9 +740,9 @@ void ED_spacetype_file(void)
art->regionid = RGN_TYPE_UI;
art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
- art->listener = file_ui_area_listener;
- art->init = file_ui_area_init;
- art->draw = file_ui_area_draw;
+ art->listener = file_ui_region_listener;
+ art->init = file_ui_region_init;
+ art->draw = file_ui_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: channels (directories) */
@@ -715,9 +751,9 @@ void ED_spacetype_file(void)
art->prefsizex = 240;
art->prefsizey = 60;
art->keymapflag = ED_KEYMAP_UI;
- art->listener = file_tools_area_listener;
- art->init = file_tools_area_init;
- art->draw = file_tools_area_draw;
+ art->listener = file_tools_region_listener;
+ art->init = file_tools_region_init;
+ art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: tool properties */
@@ -726,9 +762,9 @@ void ED_spacetype_file(void)
art->prefsizex = 0;
art->prefsizey = 360;
art->keymapflag = ED_KEYMAP_UI;
- art->listener = file_tools_area_listener;
- art->init = file_tools_area_init;
- art->draw = file_tools_area_draw;
+ art->listener = file_tools_region_listener;
+ art->init = file_tools_region_init;
+ art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
file_panels_register(art);
diff --git a/source/blender/editors/space_graph/SConscript b/source/blender/editors/space_graph/SConscript
deleted file mode 100644
index af17853556e..00000000000
--- a/source/blender/editors/space_graph/SConscript
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs.append(env['BF_AUDASPACE_C_INC'])
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_space_graph', sources, incs, defs, libtype=['core'], priority=[50])
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 8e471ceca95..a9ab1502e16 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -133,7 +133,10 @@ static void graph_panel_view(const bContext *C, Panel *pa)
sub = uiLayoutColumn(col, true);
uiLayoutSetActive(sub, RNA_boolean_get(&spaceptr, "show_cursor"));
row = uiLayoutSplit(sub, 0.7f, true);
- uiItemR(row, &sceneptr, "frame_current", 0, IFACE_("Cursor X"), ICON_NONE);
+ if (sipo->mode == SIPO_MODE_DRIVERS)
+ uiItemR(row, &spaceptr, "cursor_position_x", 0, IFACE_("Cursor X"), ICON_NONE);
+ else
+ uiItemR(row, &sceneptr, "frame_current", 0, IFACE_("Cursor X"), ICON_NONE);
uiItemEnumO(row, "GRAPH_OT_snap", IFACE_("To Keys"), 0, "type", GRAPHKEYS_SNAP_CFRA);
row = uiLayoutSplit(sub, 0.7f, true);
@@ -355,7 +358,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
/* interpolation */
col = uiLayoutColumn(layout, false);
- uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
+ if (fcu->flag & FCURVE_DISCRETE_VALUES) {
+ uiLayout *split = uiLayoutSplit(col, 0.33f, true);
+ uiItemL(split, IFACE_("Interpolation:"), ICON_NONE);
+ uiItemL(split, IFACE_("None for Enum/Boolean"), ICON_IPO_CONSTANT);
+ }
+ else {
+ uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE);
+ }
/* easing type */
if (bezt->ipo > BEZT_IPO_BEZ)
@@ -506,7 +516,43 @@ static void driver_delete_var_cb(bContext *UNUSED(C), void *driver_v, void *dvar
DriverVar *dvar = (DriverVar *)dvar_v;
/* remove the active variable */
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
+}
+
+/* callback to report why a driver variable is invalid */
+static void driver_dvar_invalid_name_query_cb(bContext *C, void *dvar_v, void *UNUSED(arg))
+{
+ uiPopupMenu *pup = UI_popup_menu_begin(C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Invalid Variable Name"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ DriverVar *dvar = (DriverVar *)dvar_v;
+
+ if (dvar->flag & DVAR_FLAG_INVALID_EMPTY) {
+ uiItemL(layout, "It cannot be left blank", ICON_ERROR);
+ }
+ if (dvar->flag & DVAR_FLAG_INVALID_START_NUM) {
+ uiItemL(layout, "It cannot start with a number", ICON_ERROR);
+ }
+ if (dvar->flag & DVAR_FLAG_INVALID_START_CHAR) {
+ uiItemL(layout,
+ "It cannot start with a special character,"
+ " including '$', '@', '!', '~', '+', '-', '_', '.', or ' '",
+ ICON_NONE);
+ }
+ if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPACE) {
+ uiItemL(layout, "It cannot contain spaces (e.g. 'a space')", ICON_ERROR);
+ }
+ if (dvar->flag & DVAR_FLAG_INVALID_HAS_DOT) {
+ uiItemL(layout, "It cannot contain dots (e.g. 'a.dot')", ICON_ERROR);
+ }
+ if (dvar->flag & DVAR_FLAG_INVALID_HAS_SPECIAL) {
+ uiItemL(layout, "It cannot contain special (non-alphabetical/numeric) characters", ICON_ERROR);
+ }
+ if (dvar->flag & DVAR_FLAG_INVALID_PY_KEYWORD) {
+ uiItemL(layout, "It cannot be a reserved keyword in Python", ICON_INFO);
+ }
+
+ UI_popup_menu_end(C, pup);
}
/* callback to reset the driver's flags */
@@ -561,6 +607,7 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
}
/* settings for 'rotation difference' driver variable type */
+/* FIXME: 1) Must be same armature for both dtars, 2) Alignment issues... */
static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *dvar)
{
DriverTarget *dtar = &dvar->targets[0];
@@ -577,7 +624,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* Bone 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:"));
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Bone 1"), ICON_NONE);
if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
@@ -588,7 +635,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
+ uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Bone 2"), ICON_NONE);
if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
@@ -615,13 +662,13 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
/* Bone 1 */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:"));
-
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object 1"), ICON_NONE);
+
if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
- uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
+ uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
}
uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
@@ -629,13 +676,13 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:"));
-
+ uiItemR(col, &dtar2_ptr, "id", 0, IFACE_("Object 2"), ICON_NONE);
+
if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
- uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
+ uiItemPointerR(col, &dtar2_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
}
uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
@@ -656,13 +703,13 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
/* properties */
col = uiLayoutColumn(layout, true);
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
- uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:"));
-
+ uiItemR(col, &dtar_ptr, "id", 0, IFACE_("Object"), ICON_NONE);
+
if (dtar->id && GS(dtar->id->name) == ID_OB && ob->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
- uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", "", ICON_BONE_DATA);
+ uiItemPointerR(col, &dtar_ptr, "bone_target", &tar_ptr, "bones", IFACE_("Bone"), ICON_BONE_DATA);
}
sub = uiLayoutColumn(layout, true);
@@ -779,45 +826,75 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
uiItemL(row, valBuf, ICON_NONE);
}
- /* add driver variables */
- col = uiLayoutColumn(pa->layout, false);
- block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
- 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0, 0,
- TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
- UI_but_func_set(but, driver_add_var_cb, driver, NULL);
+ /* add/copy/paste driver variables */
+ {
+ uiLayout *row;
+
+ /* add driver variable */
+ row = uiLayoutRow(pa->layout, false);
+ block = uiLayoutGetBlock(row);
+ but = uiDefIconTextBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ZOOMIN, IFACE_("Add Variable"),
+ 0, 0, 10 * UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0, 0,
+ TIP_("Driver variables ensure that all dependencies will be accounted for and that drivers will update correctly"));
+ UI_but_func_set(but, driver_add_var_cb, driver, NULL);
+
+ /* copy/paste (as sub-row) */
+ row = uiLayoutRow(row, true);
+ block = uiLayoutGetBlock(row);
+
+ uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_driver_variables_copy");
+ uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_driver_variables_paste");
+ }
/* loop over targets, drawing them */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
PointerRNA dvar_ptr;
uiLayout *box, *row;
+ uiLayout *subrow, *sub;
/* sub-layout column for this variable's settings */
col = uiLayoutColumn(pa->layout, true);
- /* header panel */
+ /* 1) header panel */
box = uiLayoutBox(col);
- /* first row context info for driver */
RNA_pointer_create(ale->id, &RNA_DriverVariable, dvar, &dvar_ptr);
row = uiLayoutRow(box, false);
block = uiLayoutGetBlock(row);
- /* variable name */
- uiItemR(row, &dvar_ptr, "name", 0, "", ICON_NONE);
- /* remove button */
+ /* 1.1) variable type and name */
+ subrow = uiLayoutRow(row, true);
+
+ /* 1.1.1) variable type */
+ sub = uiLayoutRow(subrow, true); /* HACK: special group just for the enum, otherwise we */
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); /* we get ugly layout with text included too... */
+
+ uiItemR(sub, &dvar_ptr, "type", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+
+ /* 1.1.2) variable name */
+ sub = uiLayoutRow(subrow, true); /* HACK: special group to counteract the effects of the previous */
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_EXPAND); /* enum, which now pushes everything too far right */
+
+ uiItemR(sub, &dvar_ptr, "name", 0, "", ICON_NONE);
+
+ /* 1.2) invalid name? */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ if (dvar->flag & DVAR_FLAG_INVALID_NAME) {
+ but = uiDefIconBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_ERROR, 290, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Invalid variable name, click here for details"));
+ UI_but_func_set(but, driver_dvar_invalid_name_query_cb, dvar, NULL); // XXX: reports?
+ }
+
+ /* 1.3) remove button */
but = uiDefIconBut(block, UI_BTYPE_BUT, B_IPO_DEPCHANGE, ICON_X, 290, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, IFACE_("Delete target variable"));
UI_but_func_set(but, driver_delete_var_cb, driver, dvar);
UI_block_emboss_set(block, UI_EMBOSS);
- /* variable type */
- row = uiLayoutRow(box, false);
- uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
-
- /* variable type settings */
+
+ /* 2) variable type settings */
box = uiLayoutBox(col);
/* controls to draw depends on the type of variable */
switch (dvar->type) {
@@ -835,7 +912,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
break;
}
- /* value of variable */
+ /* 3) value of variable */
if (driver->flag & DRIVER_FLAG_SHOWDEBUG) {
char valBuf[32];
@@ -894,15 +971,13 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
/* 'add modifier' button at top of panel */
{
row = uiLayoutRow(pa->layout, false);
- block = uiLayoutGetBlock(row);
/* this is an operator button which calls a 'add modifier' operator...
* a menu might be nicer but would be tricky as we need some custom filtering
*/
- uiDefButO(block, UI_BTYPE_BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"),
- 0.5 * UI_UNIT_X, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, TIP_("Adds a new F-Curve Modifier for the active F-Curve"));
+ uiItemMenuEnumO(row, (bContext *)C, "GRAPH_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
- /* copy/paste (as sub-row)*/
+ /* copy/paste (as sub-row) */
row = uiLayoutRow(row, true);
uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
@@ -916,7 +991,7 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
}
-
+
MEM_freeN(ale);
}
@@ -926,17 +1001,10 @@ void graph_buttons_register(ARegionType *art)
{
PanelType *pt;
- pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
- strcpy(pt->idname, "GRAPH_PT_view");
- strcpy(pt->label, N_("View Properties"));
- strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw = graph_panel_view;
- pt->flag |= PNL_DEFAULT_CLOSED;
- BLI_addtail(&art->paneltypes, pt);
-
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_properties");
strcpy(pt->label, N_("Active F-Curve"));
+ strcpy(pt->category, "F-Curve");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_properties;
pt->poll = graph_panel_poll;
@@ -945,6 +1013,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_key_properties");
strcpy(pt->label, N_("Active Keyframe"));
+ strcpy(pt->category, "F-Curve");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_key_properties;
pt->poll = graph_panel_poll;
@@ -954,6 +1023,7 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
strcpy(pt->idname, "GRAPH_PT_drivers");
strcpy(pt->label, N_("Drivers"));
+ strcpy(pt->category, "Drivers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_drivers;
pt->poll = graph_panel_drivers_poll;
@@ -962,10 +1032,19 @@ void graph_buttons_register(ARegionType *art)
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
strcpy(pt->idname, "GRAPH_PT_modifiers");
strcpy(pt->label, N_("Modifiers"));
+ strcpy(pt->category, "Modifiers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_modifiers;
pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt);
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
+ strcpy(pt->idname, "GRAPH_PT_view");
+ strcpy(pt->label, N_("View Properties"));
+ strcpy(pt->category, "View");
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->draw = graph_panel_view;
+ BLI_addtail(&art->paneltypes, pt);
}
static int graph_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 91e11ac4b1e..3ac90200aea 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -85,6 +85,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
/* draw two black lines showing the standard reference levels */
glColor3f(0.0f, 0.0f, 0.0f);
+ glLineWidth(1);
setlinestyle(5);
glBegin(GL_LINES);
@@ -93,7 +94,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
glVertex2f(v2d->cur.xmin, env->midval + env->max);
glVertex2f(v2d->cur.xmax, env->midval + env->max);
- glEnd(); /* GL_LINES */
+ glEnd();
setlinestyle(0);
/* set size of vertices (non-adjustable for now) */
@@ -102,10 +103,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
/* for now, point color is fixed, and is white */
glColor3f(1.0f, 1.0f, 1.0f);
- /* we use bgl points not standard gl points, to workaround vertex
- * drawing bugs that some drivers have (probably legacy ones only though)
- */
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
/* only draw if visible
* - min/max here are fixed, not relative
@@ -115,9 +113,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
glVertex2f(fed->time, fed->max);
}
}
- bglEnd(); /* GL_POINTS */
-
- glPointSize(1.0f);
+ glEnd();
}
/* *************************** */
@@ -132,10 +128,7 @@ static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo),
const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur);
int i;
- /* we use bgl points not standard gl points, to workaround vertex
- * drawing bugs that some drivers have (probably legacy ones only though)
- */
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
for (i = 0; i < fcu->totvert; i++, bezt++) {
/* as an optimization step, only draw those in view
@@ -148,17 +141,17 @@ static void draw_fcurve_vertices_keyframes(FCurve *fcu, SpaceIpo *UNUSED(sipo),
* -
*/
if ((bezt->f2 & SELECT) == sel)
- bglVertex3fv(bezt->vec[1]);
+ glVertex3fv(bezt->vec[1]);
}
else {
/* no check for selection here, as curve is not editable... */
/* XXX perhaps we don't want to even draw points? maybe add an option for that later */
- bglVertex3fv(bezt->vec[1]);
+ glVertex3fv(bezt->vec[1]);
}
}
}
- bglEnd(); /* GL_POINTS */
+ glEnd();
}
@@ -294,8 +287,6 @@ static void draw_fcurve_vertices(SpaceIpo *sipo, ARegion *ar, FCurve *fcu, short
set_fcurve_vertex_color(fcu, 1);
draw_fcurve_vertices_keyframes(fcu, sipo, v2d, !(fcu->flag & FCURVE_PROTECTED), 1);
-
- glPointSize(1.0f);
}
/* Handles ---------------- */
@@ -862,7 +853,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
/* cleanup line drawing */
setlinestyle(0);
- glLineWidth(1.0f);
}
/* draw driver only if actually functional */
@@ -921,8 +911,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
glBegin(GL_POINTS);
glVertex2f(x, y);
glEnd();
-
- glPointSize(1.0f);
}
}
}
@@ -958,13 +946,12 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
/* restore settings */
setlinestyle(0);
- glLineWidth(1.0f);
if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
}
-/* This is called twice from space_graph.c -> graph_main_area_draw()
+/* This is called twice from space_graph.c -> graph_main_region_draw()
* Unselected then selected F-Curves are drawn so that they do not occlude each other.
*/
void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid *grid, short sel)
@@ -1021,6 +1008,9 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
if (fcu->flag & FCURVE_ACTIVE) {
glLineWidth(2.0);
}
+ else {
+ glLineWidth(1.0);
+ }
/* anti-aliased lines for less jagged appearance */
if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glEnable(GL_LINE_SMOOTH);
@@ -1048,7 +1038,6 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
/* restore settings */
setlinestyle(0);
- glLineWidth(1.0);
if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
@@ -1072,11 +1061,15 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
short mapping_flag = ANIM_get_normalization_flags(ac);
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
-
+
+ /* apply unit-scaling to all values via OpenGL */
glPushMatrix();
glScalef(1.0f, unit_scale, 1.0f);
glTranslatef(0.0f, offset, 0.0f);
-
+
+ /* set this once and for all - all handles and handle-verts should use the same thickness */
+ glLineWidth(1.0);
+
if (fcu->bezt) {
bool do_handles = draw_fcurve_handles_check(sipo, fcu);
@@ -1093,7 +1086,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
/* samples: only draw two indicators at either end as indicators */
draw_fcurve_samples(sipo, ar, fcu);
}
-
+
glPopMatrix();
}
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index ca5d2db80e7..e1cd1da3a25 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -54,6 +54,7 @@
#include "BLT_translation.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_nla.h"
@@ -140,8 +141,14 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
/* ensure that the extents are not too extreme that view implodes...*/
if (foundBounds) {
- if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.1f)) *xmax += 0.1f;
- if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.1f)) *ymax += 0.1f;
+ if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) {
+ *xmin -= 0.0005f;
+ *xmax += 0.0005f;
+ }
+ if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) {
+ *ymax -= 0.0005f;
+ *ymax += 0.0005f;
+ }
}
else {
if (xmin) *xmin = (float)PSFRA;
@@ -258,13 +265,7 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
}
-static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
-{
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- ANIM_center_frame(C, smooth_viewtx);
- return OPERATOR_FINISHED;
-}
-
+/* ......... */
void GRAPH_OT_view_all(wmOperatorType *ot)
{
@@ -304,17 +305,26 @@ void GRAPH_OT_view_selected(wmOperatorType *ot)
"Include handles of keyframes when calculating extents");
}
+/* ********************** View Frame Operator ****************************** */
+
+static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
void GRAPH_OT_view_frame(wmOperatorType *ot)
{
/* identifiers */
ot->name = "View Frame";
ot->idname = "GRAPH_OT_view_frame";
ot->description = "Reset viewable area to show range around current frame";
-
+
/* api callbacks */
ot->exec = graphkeys_view_frame_exec;
- ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
-
+ ot->poll = ED_operator_graphedit_active;
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -354,7 +364,6 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
FPoint *fpt;
float unitFac, offset;
int cfra;
- SpaceIpo *sipo = (SpaceIpo *) ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
/* disable driver so that it don't muck up the sampling process */
@@ -484,57 +493,126 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot)
/* ******************** Insert Keyframes Operator ************************* */
-/* defines for insert keyframes tool */
+/* Mode defines for insert keyframes tool */
+typedef enum eGraphKeys_InsertKey_Types {
+ GRAPHKEYS_INSERTKEY_ALL = (1 << 0),
+ GRAPHKEYS_INSERTKEY_SEL = (1 << 1),
+ GRAPHKEYS_INSERTKEY_CURSOR = (1 << 2),
+ GRAPHKEYS_INSERTKEY_ACTIVE = (1 << 3),
+} eGraphKeys_InsertKey_Types;
+
+/* RNA mode types for insert keyframes tool */
static EnumPropertyItem prop_graphkeys_insertkey_types[] = {
- {1, "ALL", 0, "All Channels", ""},
- {2, "SEL", 0, "Only Selected Channels", ""},
+ {GRAPHKEYS_INSERTKEY_ALL, "ALL", 0, "All Channels",
+ "Insert a keyframe on all visible and editable F-Curves using each curve's current value"},
+ {GRAPHKEYS_INSERTKEY_SEL, "SEL", 0, "Only Selected Channels",
+ "Insert a keyframe on selected F-Curves using each curve's current value"},
+ {0, "", 0, "", ""},
+ {GRAPHKEYS_INSERTKEY_ACTIVE | GRAPHKEYS_INSERTKEY_CURSOR, "CURSOR_ACTIVE", 0,
+ "Active Channels At Cursor", "Insert a keyframe for the active F-Curve at the cursor point"},
+ {GRAPHKEYS_INSERTKEY_SEL | GRAPHKEYS_INSERTKEY_CURSOR, "CURSOR_SEL", 0,
+ "Selected Channels At Cursor", "Insert a keyframe for selected F-Curves at the cursor point"},
{0, NULL, 0, NULL, NULL}
};
/* this function is responsible for snapping keyframes to frame-times */
-static void insert_graph_keys(bAnimContext *ac, short mode)
+static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+ size_t num_items;
ReportList *reports = ac->reports;
+ SpaceIpo *sipo = (SpaceIpo *)ac->sl;
Scene *scene = ac->scene;
+ ToolSettings *ts = scene->toolsettings;
short flag = 0;
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
- if (mode == 2) filter |= ANIMFILTER_SEL;
-
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ if (mode & GRAPHKEYS_INSERTKEY_SEL)
+ filter |= ANIMFILTER_SEL;
+ else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE)
+ filter |= ANIMFILTER_ACTIVE;
+
+ num_items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ if (num_items == 0) {
+ if (mode & GRAPHKEYS_INSERTKEY_ACTIVE)
+ BKE_report(reports, RPT_ERROR, "No active F-Curve to add a keyframe to. Select an editable F-Curve first");
+ else if (mode & GRAPHKEYS_INSERTKEY_SEL)
+ BKE_report(reports, RPT_ERROR, "No selected F-Curves to add keyframes to");
+ else
+ BKE_report(reports, RPT_ERROR, "No channels to add keyframes to");
+
+ return;
+ }
/* init keyframing flag */
flag = ANIM_get_keyframing_flags(scene, 1);
/* insert keyframes */
- for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
- float cfra;
-
- /* adjust current frame for NLA-mapping */
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
+ if (mode & GRAPHKEYS_INSERTKEY_CURSOR) {
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
- /* read value from property the F-Curve represents, or from the curve only?
- * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
- * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
- * so it's easier for now to just read the F-Curve directly.
- * (TODO: add the full-blown PointerRNA relative parsing case here...)
- */
- if (ale->id && !ale->owner)
- insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
- else
- insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
-
- ale->update |= ANIM_UPDATE_DEFAULT;
+ short mapping_flag = ANIM_get_normalization_flags(ac);
+ float offset;
+ float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
+
+ float x, y;
+
+
+ /* perform time remapping for x-coordinate (if necessary) */
+ if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
+ x = sipo->cursorTime;
+ else if (adt)
+ x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ x = (float)CFRA;
+
+ /* normalise units of cursor's value */
+ if (sipo)
+ y = (sipo->cursorVal / unit_scale) - offset;
+ else
+ y = 0.0f;
+
+ /* insert keyframe directly into the F-Curve */
+ insert_vert_fcurve(fcu, x, y, ts->keyframe_type, 0);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+ }
+ else {
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+ float cfra;
+
+ /* adjust current frame for NLA-mapping */
+ if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
+ cfra = sipo->cursorTime;
+ else if (adt)
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ else
+ cfra = (float)CFRA;
+
+ /* read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL: Typically, this means that we have enough info to try resolving the path
+ * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ * - fcu->driver != NULL: If this is set, then it's a driver. If we don't check for this, we'd end
+ * up adding the keyframes on a new F-Curve in the action data instead.
+ */
+ if (ale->id && !ale->owner && !fcu->driver)
+ insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, ts->keyframe_type, flag);
+ else
+ insert_vert_fcurve(fcu, cfra, fcu->curval, ts->keyframe_type, 0);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
}
ANIM_animdata_update(ac, &anim_data);
@@ -546,7 +624,7 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
- short mode;
+ eGraphKeys_InsertKey_Types mode;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -610,9 +688,11 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
*/
if (fcurve_is_keyframable(fcu)) {
ListBase anim_data;
-
+ ToolSettings *ts = ac.scene->toolsettings;
+
short mapping_flag = ANIM_get_normalization_flags(&ac);
float scale, offset;
+
/* get frame and value from props */
frame = RNA_float_get(op->ptr, "frame");
val = RNA_float_get(op->ptr, "value");
@@ -623,11 +703,11 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
/* apply inverse unit-mapping to value to get correct value for F-Curves */
scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
-
+
val = val * scale - offset;
-
+
/* insert keyframe on the specified frame + value */
- insert_vert_fcurve(fcu, frame, val, 0);
+ insert_vert_fcurve(fcu, frame, val, ts->keyframe_type, 0);
ale->update |= ANIM_UPDATE_DEPS;
@@ -713,7 +793,7 @@ static short copy_graph_keys(bAnimContext *ac)
int filter, ok = 0;
/* clear buffer first */
- free_anim_copybuf();
+ ANIM_fcurves_copybuf_free();
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
@@ -835,8 +915,8 @@ void GRAPH_OT_paste(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
- RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
+ RNA_def_enum(ot->srna, "offset", rna_enum_keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
+ RNA_def_enum(ot->srna, "merge", rna_enum_keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -898,7 +978,7 @@ void GRAPH_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* to give to transform */
- RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+ RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/* ******************** Delete Keyframes Operator ************************* */
@@ -1275,8 +1355,9 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_float(ot->srna, "low", 0.0f, 0.0, 100000.0, "Lowest frequency",
"Cutoff frequency of a high-pass filter that is applied to the audio data", 0.1, 1000.00);
RNA_def_float(ot->srna, "high", 100000.0, 0.0, 100000.0, "Highest frequency",
@@ -1541,7 +1622,7 @@ void GRAPH_OT_interpolation_type(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
}
/* ******************** Set Easing Operator *********************** */
@@ -1607,7 +1688,7 @@ void GRAPH_OT_easing_type(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", beztriple_interpolation_easing_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
}
/* ******************** Set Handle-Type Operator *********************** */
@@ -1683,7 +1764,7 @@ void GRAPH_OT_handle_type(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", keyframe_handle_type_items, 0, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
}
/* ************************************************************************** */
@@ -1934,10 +2015,18 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
SpaceIpo *sipo = (SpaceIpo *)ac.sl;
Scene *scene = ac.scene;
- /* take the average values, rounding to the nearest int for the current frame */
- CFRA = iroundf(ked.f1 / ked.i1);
- SUBFRA = 0.f;
- sipo->cursorVal = ked.f2 / (float)ked.i1;
+ /* take the average values, rounding to the nearest int as necessary for int results */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ /* Drivers Mode - Affects cursor (float) */
+ sipo->cursorTime = ked.f1 / (float)ked.i1;
+ sipo->cursorVal = ked.f2 / (float)ked.i1;
+ }
+ else {
+ /* Animation Mode - Affects current frame (int) */
+ CFRA = iroundf(ked.f1 / ked.i1);
+ SUBFRA = 0.f;
+ sipo->cursorVal = ked.f2 / (float)ked.i1;
+ }
}
/* set notifier that things have changed */
@@ -1987,6 +2076,7 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
bAnimListElem *ale;
int filter;
+ SpaceIpo *sipo = (SpaceIpo *)ac->sl;
KeyframeEditData ked;
KeyframeEditFunc edit_cb;
float cursor_value = 0.0f;
@@ -1995,9 +2085,7 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* get beztriple editing callbacks */
- edit_cb = ANIM_editkeyframes_snap(mode);
-
+ /* init custom data for iterating over keyframes */
memset(&ked, 0, sizeof(KeyframeEditData));
ked.scene = ac->scene;
if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) {
@@ -2005,9 +2093,20 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
ked.list.last = (ac->markers) ? ac->markers->last : NULL;
}
else if (mode == GRAPHKEYS_SNAP_VALUE) {
- SpaceIpo *sipo = (SpaceIpo *)ac->sl;
cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
}
+ else if (mode == GRAPHKEYS_SNAP_CFRA) {
+ /* In drivers mode, use the cursor value instead
+ * (We need to use a different callback for that though)
+ */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ ked.f1 = sipo->cursorTime;
+ mode = SNAP_KEYS_TIME;
+ }
+ }
+
+ /* get beztriple editing callbacks */
+ edit_cb = ANIM_editkeyframes_snap(mode);
/* snap keyframes */
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -2024,13 +2123,13 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* perform snapping */
if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
-
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -2104,18 +2203,16 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
bAnimListElem *ale;
int filter;
+ SpaceIpo *sipo = (SpaceIpo *)ac->sl;
KeyframeEditData ked;
KeyframeEditFunc edit_cb;
float cursor_value = 0.0f;
- /* get beztriple editing callbacks */
- edit_cb = ANIM_editkeyframes_mirror(mode);
-
+ /* init custom data for looping over keyframes */
memset(&ked, 0, sizeof(KeyframeEditData));
ked.scene = ac->scene;
- /* for 'first selected marker' mode, need to find first selected marker first! */
- // XXX should this be made into a helper func in the API?
+ /* store mode-specific custom data... */
if (mode == GRAPHKEYS_MIRROR_MARKER) {
TimeMarker *marker = NULL;
@@ -2129,9 +2226,20 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
return;
}
else if (mode == GRAPHKEYS_MIRROR_VALUE) {
- SpaceIpo *sipo = (SpaceIpo *)ac->sl;
cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
}
+ else if (mode == GRAPHKEYS_MIRROR_CFRA) {
+ /* In drivers mode, use the cursor value instead
+ * (We need to use a different callback for that though)
+ */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ ked.f1 = sipo->cursorTime;
+ mode = MIRROR_KEYS_TIME;
+ }
+ }
+
+ /* get beztriple editing callbacks */
+ edit_cb = ANIM_editkeyframes_mirror(mode);
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
@@ -2152,13 +2260,13 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* perform actual mirroring */
if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
-
+
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -2270,27 +2378,27 @@ static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(p
EnumPropertyItem *item = NULL;
int totitem = 0;
int i = 0;
-
+
if (C == NULL) {
- return fmodifier_type_items;
+ return rna_enum_fmodifier_type_items;
}
-
+
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
int index;
-
+
/* check if modifier is valid for this context */
if (fmi == NULL)
continue;
-
- index = RNA_enum_from_value(fmodifier_type_items, fmi->type);
- RNA_enum_item_add(&item, &totitem, &fmodifier_type_items[index]);
+
+ index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type);
+ RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
}
-
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
-
+
return item;
}
@@ -2331,16 +2439,15 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
break;
}
-
+
ale->update |= ANIM_UPDATE_DEPS;
}
-
+
ANIM_animdata_update(&ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
- // FIXME: this really isn't the best description for it...
- WM_event_add_notifier(C, NC_ANIMATION, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
@@ -2348,11 +2455,11 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
{
PropertyRNA *prop;
-
+
/* identifiers */
ot->name = "Add F-Curve Modifier";
ot->idname = "GRAPH_OT_fmodifier_add";
- ot->description = "Add F-Modifiers to the selected F-Curves";
+ ot->description = "Add F-Modifier to the active/selected F-Curves";
/* api callbacks */
ot->invoke = WM_menu_invoke;
@@ -2363,10 +2470,10 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- prop = RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
RNA_def_enum_funcs(prop, graph_fmodifier_itemf);
ot->prop = prop;
-
+
RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve");
}
@@ -2383,7 +2490,7 @@ static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* clear buffer first */
- free_fmodifiers_copybuf();
+ ANIM_fmodifiers_copybuf_free();
/* get the active F-Curve */
ale = get_active_fcurve_channel(&ac);
@@ -2391,10 +2498,10 @@ static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
/* if this exists, call the copy F-Modifiers API function */
if (ale && ale->data) {
FCurve *fcu = (FCurve *)ale->data;
-
+
/* TODO: when 'active' vs 'all' boolean is added, change last param! */
ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0);
-
+
/* free temp data now */
MEM_freeN(ale);
}
@@ -2431,33 +2538,43 @@ void GRAPH_OT_fmodifier_copy(wmOperatorType *ot)
static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- int filter, ok = 0;
+ int filter;
+
+ const bool replace = RNA_boolean_get(op->ptr, "replace");
+ bool ok = false;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
+ if (RNA_boolean_get(op->ptr, "only_active")) {
+ /* This should be the default (for buttons) - Just paste to the active FCurve */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ }
+ else {
+ /* This is only if the operator gets called from a hotkey or search - Paste to all visible curves */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ }
+
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* paste modifiers */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->data;
int tot;
-
- /* TODO: do we want to replace existing modifiers? add user pref for that! */
- tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0);
-
+
+ tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, replace);
+
if (tot) {
ale->update |= ANIM_UPDATE_DEPS;
+ ok = true;
}
-
- ok += tot;
}
-
+
if (ok) {
ANIM_animdata_update(&ac, &anim_data);
}
@@ -2465,7 +2582,6 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* successful or not? */
if (ok) {
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -2490,6 +2606,128 @@ void GRAPH_OT_fmodifier_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active F-Curve");
+ RNA_def_boolean(ot->srna, "replace", false, "Replace Existing",
+ "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
+}
+
+/* ************************************************************************** */
+/* Drivers */
+
+/* ******************** Copy Driver Vars Operator *********************** */
+
+static int graph_driver_vars_copy_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+ bAnimListElem *ale;
+ bool ok = false;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* clear buffer first */
+ ANIM_driver_vars_copybuf_free();
+
+ /* get the active F-Curve */
+ ale = get_active_fcurve_channel(&ac);
+
+ /* if this exists, call the copy driver vars API function */
+ if (ale && ale->data) {
+ FCurve *fcu = (FCurve *)ale->data;
+
+ ok = ANIM_driver_vars_copy(op->reports, fcu);
+
+ /* free temp data now */
+ MEM_freeN(ale);
+ }
+
+ /* successful or not? */
+ if (ok)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void GRAPH_OT_driver_variables_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Driver Variables";
+ ot->idname = "GRAPH_OT_driver_variables_copy";
+ ot->description = "Copy the driver variables of the active F-Curve";
+
+ /* api callbacks */
+ ot->exec = graph_driver_vars_copy_exec;
+ ot->poll = graphop_active_fcurve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************** Paste Driver Vars Operator *********************** */
+
+static int graph_driver_vars_paste_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ const bool replace = RNA_boolean_get(op->ptr, "replace");
+ bool ok = false;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* filter data */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ /* paste variables */
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->data;
+ ok |= ANIM_driver_vars_paste(op->reports, fcu, replace);
+ }
+
+ /* cleanup */
+ ANIM_animdata_freelist(&anim_data);
+
+ /* successful or not? */
+ if (ok) {
+ /* rebuild depsgraph, now that there are extra deps here */
+ DAG_relations_tag_update(CTX_data_main(C));
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, CTX_data_scene(C));
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void GRAPH_OT_driver_variables_paste(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Paste Driver Variables";
+ ot->idname = "GRAPH_OT_driver_variables_paste";
+ ot->description = "Add copied driver variables to the active driver";
+
+ /* api callbacks */
+ ot->exec = graph_driver_vars_paste_exec;
+ ot->poll = graphop_active_fcurve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "replace", false, "Replace Existing",
+ "Replace existing driver variables, instead of just appending to the end of the existing list");
}
/* ************************************************************************** */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index a478a86a5e2..b6b711e129f 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -148,6 +148,11 @@ void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot);
/* ----------- */
+void GRAPH_OT_driver_variables_copy(struct wmOperatorType *ot);
+void GRAPH_OT_driver_variables_paste(struct wmOperatorType *ot);
+
+/* ----------- */
+
void GRAPH_OT_ghost_curves_create(struct wmOperatorType *ot);
void GRAPH_OT_ghost_curves_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 8e5c85d2c38..7ffa8250067 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -82,14 +82,35 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SpaceIpo *sipo = CTX_wm_space_graph(C);
+ float frame = RNA_float_get(op->ptr, "frame"); /* this isn't technically "frame", but it'll do... */
- /* adjust the frame
- * NOTE: sync this part of the code with ANIM_OT_change_frame
- */
- CFRA = RNA_int_get(op->ptr, "frame");
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.f;
- BKE_sound_seek_scene(bmain, scene);
+ /* adjust the frame or the cursor x-value */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ /* adjust cursor x-value */
+ sipo->cursorTime = frame;
+ }
+ else {
+ /* adjust the frame
+ * NOTE: sync this part of the code with ANIM_OT_change_frame
+ */
+ /* 1) frame is rounded to the nearest int, since frames are ints */
+ CFRA = iroundf(frame);
+
+ if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
+ /* Clip to preview range
+ * NOTE: Preview range won't go into negative values,
+ * so only clamping once should be fine.
+ */
+ CLAMP(CFRA, PSFRA, PEFRA);
+ }
+ else {
+ /* Prevent negative frames */
+ FRAMENUMBER_MIN_CLAMP(CFRA);
+ }
+
+ SUBFRA = 0.0f;
+ BKE_sound_seek_scene(bmain, scene);
+ }
/* set the cursor value */
sipo->cursorVal = RNA_float_get(op->ptr, "value");
@@ -112,10 +133,8 @@ static int graphview_cursor_exec(bContext *C, wmOperator *op)
/* set the operator properties from the initial event */
static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent *event)
{
- Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
float viewx, viewy;
- int frame;
/* abort if not active region (should not really be possible) */
if (ar == NULL)
@@ -124,15 +143,9 @@ static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent
/* convert from region coordinates to View2D 'tot' space */
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &viewx, &viewy);
- /* frame is rounded to the nearest int, since frames are ints */
- frame = iroundf(viewx);
-
- if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
- CLAMP(frame, PSFRA, PEFRA);
- }
-
/* store the values in the operator properties */
- RNA_int_set(op->ptr, "frame", frame);
+ /* NOTE: we don't clamp frame here, as it might be used for the drivers cursor */
+ RNA_float_set(op->ptr, "frame", viewx);
RNA_float_set(op->ptr, "value", viewy);
}
@@ -140,18 +153,18 @@ static void graphview_cursor_setprops(bContext *C, wmOperator *op, const wmEvent
static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
+
/* Change to frame that mouse is over before adding modal handler,
* as user could click on a single frame (jump to frame) as well as
- * click-dragging over a range (modal scrubbing).
+ * click-dragging over a range (modal scrubbing). Apply this change.
*/
graphview_cursor_setprops(C, op, event);
-
- /* apply these changes first */
graphview_cursor_apply(C, op);
+ /* Signal that a scrubbing operating is starting */
if (screen)
screen->scrubbing = true;
-
+
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -161,11 +174,15 @@ static int graphview_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *e
static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
+ Scene *scene = CTX_data_scene(C);
+
/* execute the events */
switch (event->type) {
case ESCKEY:
if (screen)
screen->scrubbing = false;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
return OPERATOR_FINISHED;
case MOUSEMOVE:
@@ -183,6 +200,8 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
if (event->val == KM_RELEASE) {
if (screen)
screen->scrubbing = false;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
return OPERATOR_FINISHED;
}
break;
@@ -196,7 +215,7 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot)
/* identifiers */
ot->name = "Set Cursor";
ot->idname = "GRAPH_OT_cursor_set";
- ot->description = "Interactively set the current frame number and value cursor";
+ ot->description = "Interactively set the current frame and value cursor";
/* api callbacks */
ot->exec = graphview_cursor_exec;
@@ -208,7 +227,7 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO;
/* rna */
- RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
+ RNA_def_float(ot->srna, "frame", 0, MINAFRAMEF, MAXFRAMEF, "Frame", "", MINAFRAMEF, MAXFRAMEF);
RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Value", "", -100.0f, 100.0f);
}
@@ -439,6 +458,10 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_fmodifier_add);
WM_operatortype_append(GRAPH_OT_fmodifier_copy);
WM_operatortype_append(GRAPH_OT_fmodifier_paste);
+
+ /* Drivers */
+ WM_operatortype_append(GRAPH_OT_driver_variables_copy);
+ WM_operatortype_append(GRAPH_OT_driver_variables_paste);
}
void ED_operatormacros_graph(void)
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 4c7ac532411..c6a8a9753d1 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -119,7 +119,7 @@ static SpaceLink *graph_new(const bContext *C)
ar->alignment = RGN_ALIGN_BOTTOM;
/* channels */
- ar = MEM_callocN(sizeof(ARegion), "channels area for graphedit");
+ ar = MEM_callocN(sizeof(ARegion), "channels region for graphedit");
BLI_addtail(&sipo->regionbase, ar);
ar->regiontype = RGN_TYPE_CHANNELS;
@@ -128,15 +128,15 @@ static SpaceLink *graph_new(const bContext *C)
ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
/* ui buttons */
- ar = MEM_callocN(sizeof(ARegion), "buttons area for graphedit");
+ ar = MEM_callocN(sizeof(ARegion), "buttons region for graphedit");
BLI_addtail(&sipo->regionbase, ar);
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for graphedit");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for graphedit");
BLI_addtail(&sipo->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -208,7 +208,7 @@ static SpaceLink *graph_duplicate(SpaceLink *sl)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void graph_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void graph_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -221,7 +221,7 @@ static void graph_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void graph_main_area_draw(const bContext *C, ARegion *ar)
+static void graph_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceIpo *sipo = CTX_wm_space_graph(C);
@@ -240,7 +240,7 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_ortho(v2d);
/* grid */
- unitx = (sipo->flag & SIPO_DRAWTIME) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
+ unitx = ((sipo->mode == SIPO_MODE_ANIMATION) && (sipo->flag & SIPO_DRAWTIME)) ? V2D_UNIT_SECONDS : V2D_UNIT_FRAMESCALE;
grid = UI_view2d_grid_calc(CTX_data_scene(C), v2d, unitx, V2D_GRID_NOCLAMP, unity, V2D_GRID_NOCLAMP, ar->winx, ar->winy);
UI_view2d_grid_draw(v2d, grid, V2D_GRIDLINES_ALL);
@@ -267,29 +267,45 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
/* horizontal component of value-cursor (value line before the current frame line) */
if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) {
- float vec[2];
+
+ float y = sipo->cursorVal;
/* Draw a green line to indicate the cursor value */
- vec[1] = sipo->cursorVal;
-
UI_ThemeColorShadeAlpha(TH_CFRAME, -10, -50);
+ glEnable(GL_BLEND);
glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex2f(v2d->cur.xmin, y);
+ glVertex2f(v2d->cur.xmax, y);
+ glEnd();
+
+ glDisable(GL_BLEND);
+ }
+
+ /* current frame or vertical component of vertical component of the cursor */
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ /* cursor x-value */
+ float x = sipo->cursorTime;
+ /* to help differentiate this from the current frame, draw slightly darker like the horizontal one */
+ UI_ThemeColorShadeAlpha(TH_CFRAME, -40, -50);
glEnable(GL_BLEND);
- glBegin(GL_LINE_STRIP);
- vec[0] = v2d->cur.xmin;
- glVertex2fv(vec);
-
- vec[0] = v2d->cur.xmax;
- glVertex2fv(vec);
- glEnd(); // GL_LINE_STRIP
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex2f(x, v2d->cur.ymin);
+ glVertex2f(x, v2d->cur.ymax);
+ glEnd();
+
glDisable(GL_BLEND);
}
-
- /* current frame */
- if (sipo->flag & SIPO_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS;
- if ((sipo->flag & SIPO_NODRAWCFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX;
- ANIM_draw_cfra(C, v2d, flag);
+ else {
+ /* current frame */
+ if (sipo->flag & SIPO_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS;
+ if ((sipo->flag & SIPO_NODRAWCFRANUM) == 0) flag |= DRAWCFRA_SHOW_NUMBOX;
+ ANIM_draw_cfra(C, v2d, flag);
+ }
/* markers */
UI_view2d_view_orthoSpecial(ar, v2d, 1);
@@ -313,7 +329,7 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar)
UI_view2d_scrollers_free(scrollers);
}
-static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar)
+static void graph_channel_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -332,7 +348,7 @@ static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void graph_channel_area_draw(const bContext *C, ARegion *ar)
+static void graph_channel_region_draw(const bContext *C, ARegion *ar)
{
bAnimContext ac;
View2D *v2d = &ar->v2d;
@@ -361,18 +377,18 @@ static void graph_channel_area_draw(const bContext *C, ARegion *ar)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void graph_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void graph_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void graph_header_area_draw(const bContext *C, ARegion *ar)
+static void graph_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
/* add handlers, stuff you only do once or on area/region changes */
-static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void graph_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -382,7 +398,7 @@ static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void graph_buttons_area_draw(const bContext *C, ARegion *ar)
+static void graph_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
@@ -632,8 +648,8 @@ void ED_spacetype_ipo(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = graph_main_area_init;
- art->draw = graph_main_area_draw;
+ art->init = graph_main_region_init;
+ art->draw = graph_main_region_draw;
art->listener = graph_region_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
@@ -645,8 +661,8 @@ void ED_spacetype_ipo(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
art->listener = graph_region_listener;
- art->init = graph_header_area_init;
- art->draw = graph_header_area_draw;
+ art->init = graph_header_region_init;
+ art->draw = graph_header_region_draw;
BLI_addhead(&st->regiontypes, art);
@@ -656,8 +672,8 @@ void ED_spacetype_ipo(void)
art->prefsizex = 200 + V2D_SCROLL_WIDTH; /* 200 is the 'standard', but due to scrollers, we want a bit more to fit the lock icons in */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
art->listener = graph_region_listener;
- art->init = graph_channel_area_init;
- art->draw = graph_channel_area_draw;
+ art->init = graph_channel_region_init;
+ art->draw = graph_channel_region_draw;
BLI_addhead(&st->regiontypes, art);
@@ -665,10 +681,10 @@ void ED_spacetype_ipo(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = 200;
- art->keymapflag = ED_KEYMAP_UI;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = graph_region_listener;
- art->init = graph_buttons_area_init;
- art->draw = graph_buttons_area_draw;
+ art->init = graph_buttons_region_init;
+ art->draw = graph_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript
deleted file mode 100644
index 95d23d177e7..00000000000
--- a/source/blender/editors/space_image/SConscript
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- '../../gpu',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'bf_editors_space_image', sources, Split(incs), defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 3af210f376b..f22152651e2 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -53,6 +53,7 @@
#include "ED_gpencil.h"
#include "ED_screen.h"
+#include "ED_image.h"
#include "RNA_access.h"
@@ -149,7 +150,7 @@ struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
/* 0: disable preview
* otherwise refresh preview
*
- * XXX if you put this back, also check XXX in image_main_area_draw() */
+ * XXX if you put this back, also check XXX in image_main_region_draw() */
* /
void image_preview_event(int event)
{
@@ -310,6 +311,19 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *
}
}
+static bool ui_imageuser_slot_menu_step(bContext *C, int direction, void *image_p)
+{
+ Image *image = image_p;
+
+ if (ED_image_slot_cycle(image, direction)) {
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ return true;
+ }
+ else {
+ return true;
+ }
+}
+
static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
{
RenderView *rv = RE_RenderViewGetById(rr, 0);
@@ -324,12 +338,19 @@ static const char *ui_imageuser_layer_fake_name(RenderResult *rr)
}
}
+/* workaround for passing many args */
+struct ImageUI_Data {
+ Image *image;
+ ImageUser *iuser;
+ int rpass_index;
+};
+
static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **rnd_data = rnd_pt;
+ struct ImageUI_Data *rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- Image *image = rnd_data[0];
- ImageUser *iuser = rnd_data[1];
+ Image *image = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
Scene *scene = iuser->scene;
RenderResult *rr;
RenderLayer *rl;
@@ -387,12 +408,12 @@ static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **rnd_data = rnd_pt;
+ struct ImageUI_Data *rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- Image *image = rnd_data[0];
- ImageUser *iuser = rnd_data[1];
+ Image *image = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
/* (rpass_index == -1) means composite result */
- const int rpass_index = GET_INT_FROM_POINTER(rnd_data[2]);
+ const int rpass_index = rnd_data->rpass_index;
Scene *scene = iuser->scene;
RenderResult *rr;
RenderLayer *rl;
@@ -454,10 +475,10 @@ final:
/**************************** view menus *****************************/
static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **rnd_data = rnd_pt;
+ struct ImageUI_Data *rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- Image *image = rnd_data[0];
- ImageUser *iuser = rnd_data[1];
+ Image *image = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
RenderResult *rr;
RenderView *rview;
int nr;
@@ -488,10 +509,10 @@ static void ui_imageuser_view_menu_rr(bContext *UNUSED(C), uiLayout *layout, voi
static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
- void **rnd_data = rnd_pt;
+ struct ImageUI_Data *rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- Image *image = rnd_data[0];
- ImageUser *iuser = rnd_data[1];
+ Image *image = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
int nr;
ImageView *iv;
@@ -519,93 +540,125 @@ static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
-static void image_multi_inclay_cb(bContext *C, void *rr_v, void *iuser_v)
+static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_pt)
{
- RenderResult *rr = rr_v;
- ImageUser *iuser = iuser_v;
- int tot = BLI_listbase_count(&rr->layers);
+ Scene *scene = CTX_data_scene(C);
+ struct ImageUI_Data *rnd_data = rnd_pt;
+ Image *image = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
+ RenderResult *rr;
+ bool changed = false;
- if (RE_HasFakeLayer(rr))
- tot++; /* fake compo/sequencer layer */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return false;
+ }
- if (iuser->layer < tot - 1) {
- iuser->layer++;
- BKE_image_multilayer_index(rr, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ if (direction == -1) {
+ if (iuser->layer > 0) {
+ iuser->layer--;
+ changed = true;
+ }
}
-}
-static void image_multi_declay_cb(bContext *C, void *rr_v, void *iuser_v)
-{
- ImageUser *iuser = iuser_v;
+ else if (direction == 1) {
+ int tot = BLI_listbase_count(&rr->layers);
+
+ if (RE_HasFakeLayer(rr))
+ tot++; /* fake compo/sequencer layer */
- if (iuser->layer > 0) {
- iuser->layer--;
- BKE_image_multilayer_index(rr_v, iuser);
+ if (iuser->layer < tot - 1) {
+ iuser->layer++;
+ changed = true;
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (changed) {
+ BKE_image_multilayer_index(rr, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
}
+
+ return changed;
}
-static void image_multi_incpass_cb(bContext *C, void *rr_v, void *iuser_v)
+
+static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt)
{
- RenderResult *rr = rr_v;
- ImageUser *iuser = iuser_v;
- RenderLayer *rl;
- RenderPass *rp;
+ Scene *scene = CTX_data_scene(C);
+ struct ImageUI_Data *rnd_data = rnd_pt;
+ Image *image = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
+ RenderResult *rr;
+ bool changed = false;
int layer = iuser->layer;
+ RenderLayer *rl;
+ RenderPass *rpass;
+
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ BKE_image_release_renderresult(scene, image);
+ return false;
+ }
- if (RE_HasFakeLayer(rr))
+ if (RE_HasFakeLayer(rr)) {
layer -= 1;
+ }
rl = BLI_findlink(&rr->layers, layer);
+ if (rl == NULL) {
+ BKE_image_release_renderresult(scene, image);
+ return false;
+ }
- if (rl) {
- RenderPass *rpass = BLI_findlink(&rl->passes, iuser->pass);
- int rp_index = iuser->pass + 1;
+ rpass = BLI_findlink(&rl->passes, iuser->pass);
+ if (rpass == NULL) {
+ BKE_image_release_renderresult(scene, image);
+ return false;
+ }
- if (rpass == NULL)
- return;
+ /* note, this looks reversed, but matches menu direction */
+ if (direction == -1) {
+ RenderPass *rp;
+ int rp_index = iuser->pass + 1;
for (rp = rpass->next; rp; rp = rp->next, rp_index++) {
if (rp->passtype != rpass->passtype) {
iuser->pass = rp_index;
- BKE_image_multilayer_index(rr, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ changed = true;
break;
}
}
}
-}
-static void image_multi_decpass_cb(bContext *C, void *rr_v, void *iuser_v)
-{
- RenderResult *rr = rr_v;
- ImageUser *iuser = iuser_v;
- RenderLayer *rl;
- RenderPass *rp;
- int layer = iuser->layer;
-
- if (iuser->pass == 0)
- return;
-
- if (RE_HasFakeLayer(rr))
- layer -= 1;
-
- rl = BLI_findlink(&rr->layers, layer);
-
- if (rl) {
- RenderPass *rpass = BLI_findlink(&rl->passes, iuser->pass);
+ else if (direction == 1) {
+ RenderPass *rp;
int rp_index = 0;
- if (rpass == NULL)
- return;
+ if (iuser->pass == 0) {
+ BKE_image_release_renderresult(scene, image);
+ return false;
+ }
for (rp = rl->passes.first; rp; rp = rp->next, rp_index++) {
if (rp->passtype == rpass->passtype) {
iuser->pass = rp_index - 1;
- BKE_image_multilayer_index(rr, iuser);
- WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ changed = true;
break;
}
}
}
+ else {
+ BLI_assert(0);
+ }
+
+ BKE_image_release_renderresult(scene, image);
+
+ if (changed) {
+ BKE_image_multilayer_index(rr, iuser);
+ WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
+ }
+
+ return changed;
}
/* 5 view button callbacks... */
@@ -635,16 +688,18 @@ static void image_user_change(bContext *C, void *iuser_v, void *unused)
}
#endif
-static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
+static void uiblock_layer_pass_buttons(
+ uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w,
+ short *render_slot)
{
- static void *rnd_pt[4]; /* XXX, workaround */
+ static struct ImageUI_Data rnd_pt; /* XXX, workaround */
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
int wmenu1, wmenu2, wmenu3, wmenu4;
const char *fake_name;
const char *display_name = "";
- const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO);
+ const bool show_stereo = (iuser->flag & IMA_SHOW_STEREO) != 0;
uiLayoutRow(layout, true);
@@ -654,9 +709,9 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
wmenu3 = (3 * w) / 6;
wmenu4 = (3 * w) / 6;
- rnd_pt[0] = image;
- rnd_pt[1] = iuser;
- rnd_pt[2] = NULL;
+ rnd_pt.image = image;
+ rnd_pt.iuser = iuser;
+ rnd_pt.rpass_index = 0;
/* menu buts */
if (render_slot) {
@@ -667,7 +722,9 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
else {
BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
}
+
but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
+ UI_but_func_menu_step_set(but, ui_imageuser_slot_menu_step);
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
@@ -681,12 +738,13 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
fake_name = ui_imageuser_layer_fake_name(rr);
rpass_index = iuser->layer - (fake_name ? 1 : 0);
rl = BLI_findlink(&rr->layers, rpass_index);
- rnd_pt[2] = SET_INT_IN_POINTER(rpass_index);
+ rnd_pt.rpass_index = rpass_index;
if (RE_layers_have_name(rr)) {
display_name = rl ? rl->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_layer_menu, rnd_pt, display_name,
+ but = uiDefMenuBut(block, ui_imageuser_layer_menu, &rnd_pt, display_name,
0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
+ UI_but_func_menu_step_set(but, ui_imageuser_layer_menu_step);
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
@@ -696,25 +754,28 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
+ but = uiDefMenuBut(block, ui_imageuser_pass_menu, &rnd_pt, IFACE_(display_name),
0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
+ UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step);
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
/* view */
- if (BLI_listbase_count_ex(&rr->views, 2) > 1 && !show_stereo) {
+ if (BLI_listbase_count_ex(&rr->views, 2) > 1 &&
+ ((!show_stereo) || (!RE_RenderResult_is_stereo(rr))))
+ {
rview = BLI_findlink(&rr->views, iuser->view);
display_name = rview ? rview->name : "";
- but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
+ but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, &rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
UI_but_func_set(but, image_multi_cb, rr, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
}
/* stereo image */
- else if (((image->flag & IMA_IS_STEREO) && (!show_stereo)) ||
- ((image->flag & IMA_IS_MULTIVIEW) && ((image->flag & IMA_IS_STEREO) == 0)))
+ else if ((BKE_image_is_stereo(image) && (!show_stereo)) ||
+ (BKE_image_is_multiview(image) && !BKE_image_is_stereo(image)))
{
ImageView *iv;
int nr = 0;
@@ -726,45 +787,12 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, Image *image, RenderRes
}
}
- but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
+ but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, &rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
UI_but_func_set(but, image_multiview_cb, image, iuser);
UI_but_type_set_menu_from_pulldown(but);
}
}
-static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser,
- int menus_width, short *render_slot)
-{
- uiBlock *block = uiLayoutGetBlock(layout);
- uiLayout *row;
- uiBut *but;
-
- row = uiLayoutRow(layout, true);
-
- if (rr == NULL || iuser == NULL)
- return;
- if (BLI_listbase_is_empty(&rr->layers)) {
- uiItemL(row, IFACE_("No Layers in Render Result"), ICON_NONE);
- return;
- }
-
- /* decrease, increase arrows */
- but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Layer"));
- UI_but_func_set(but, image_multi_declay_cb, rr, iuser);
- but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Layer"));
- UI_but_func_set(but, image_multi_inclay_cb, rr, iuser);
-
- uiblock_layer_pass_buttons(row, image, rr, iuser, menus_width, render_slot);
-
- /* decrease, increase arrows */
- but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Pass"));
- UI_but_func_set(but, image_multi_decpass_cb, rr, iuser);
- but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Pass"));
- UI_but_func_set(but, image_multi_incpass_cb, rr, iuser);
-
- UI_block_align_end(block);
-}
-
// XXX HACK!
// static int packdummy=0;
@@ -876,12 +904,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- if (rr) {
- uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
- }
- else {
- uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
- }
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
BKE_image_release_renderresult(scene, ima);
}
}
@@ -915,7 +938,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
/* multilayer? */
if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
const float dpi_fac = UI_DPI_FAC;
- uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL);
+ uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL);
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
@@ -1110,6 +1133,10 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
#endif
}
+ if (imf->imtype == R_IMF_IMTYPE_TIFF) {
+ uiItemR(col, imfptr, "tiff_codec", 0, NULL, ICON_NONE);
+ }
+
/* color management */
if (color_management &&
(!BKE_imtype_requires_linear_float(imf->imtype) ||
@@ -1232,13 +1259,8 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
/* use BKE_image_acquire_renderresult so we get the correct slot in the menu */
rr = BKE_image_acquire_renderresult(scene, ima);
- if (rr && is_render_result) {
- uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, menus_width, &ima->render_slot);
- }
- else {
- uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width,
- is_render_result ? &ima->render_slot : NULL);
- }
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, menus_width,
+ is_render_result ? &ima->render_slot : NULL);
BKE_image_release_renderresult(scene, ima);
}
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 3a178ed0277..0ddbb1153c0 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -130,6 +130,7 @@ static void draw_render_info(const bContext *C,
UI_ThemeColor(TH_FACE_SELECT);
+ glLineWidth(1.0f);
for (i = 0, tile = tiles; i < total_tiles; i++, tile++) {
glaDrawBorderCorners(tile, zoomx, zoomy);
}
@@ -338,9 +339,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, bool color_manage, bool use_d
/* draw outline */
glColor3ub(128, 128, 128);
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- glRecti(color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ sdrawbox(color_rect.xmin, color_rect.ymin, color_rect.xmax, color_rect.ymax);
dx += 1.75f * UI_UNIT_X;
@@ -478,6 +477,19 @@ static void sima_draw_zbuffloat_pixels(Scene *scene, float x1, float y1, int rec
MEM_freeN(rectf);
}
+static int draw_image_channel_offset(SpaceImage *sima)
+{
+#ifdef __BIG_ENDIAN__
+ if (sima->flag & SI_SHOW_R) return 0;
+ else if (sima->flag & SI_SHOW_G) return 1;
+ else return 2;
+#else
+ if (sima->flag & SI_SHOW_R) return 1;
+ else if (sima->flag & SI_SHOW_G) return 2;
+ else return 3;
+#endif
+}
+
static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar, Scene *scene, ImBuf *ibuf, float fx, float fy, float zoomx, float zoomy)
{
int x, y;
@@ -513,7 +525,27 @@ static void draw_image_buffer(const bContext *C, SpaceImage *sima, ARegion *ar,
fdrawcheckerboard(x, y, x + ibuf->x * zoomx, y + ibuf->y * zoomy);
}
- glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B)) == 0) {
+ glaDrawImBuf_glsl_ctx(C, ibuf, x, y, GL_NEAREST);
+ }
+ else {
+ unsigned char *display_buffer;
+ void *cache_handle;
+
+ /* TODO(sergey): Ideally GLSL shading should be capable of either
+ * disabling some channels or displaying buffer with custom offset.
+ */
+ display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
+
+ if (display_buffer != NULL) {
+ int channel_offset = draw_image_channel_offset(sima);
+ glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT,
+ display_buffer - (4 - channel_offset));
+ }
+ if (cache_handle != NULL) {
+ IMB_display_buffer_release(cache_handle);
+ }
+ }
if (sima->flag & SI_USE_ALPHA)
glDisable(GL_BLEND);
@@ -551,6 +583,7 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
unsigned int *rect;
int dx, dy, sx, sy, x, y;
void *cache_handle;
+ int channel_offset = -1;
/* verify valid values, just leave this a while */
if (ima->xrep < 1) return;
@@ -577,11 +610,19 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
rect = get_part_from_buffer((unsigned int *)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy);
/* draw repeated */
+ if ((sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B)) != 0) {
+ channel_offset = draw_image_channel_offset(sima);
+ }
for (sy = 0; sy + dy <= ibuf->y; sy += dy) {
for (sx = 0; sx + dx <= ibuf->x; sx += dx) {
UI_view2d_view_to_region(&ar->v2d, fx + (float)sx / (float)ibuf->x, fy + (float)sy / (float)ibuf->y, &x, &y);
-
- glaDrawPixelsSafe(x, y, dx, dy, dx, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ if (channel_offset == -1) {
+ glaDrawPixelsSafe(x, y, dx, dy, dx, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ }
+ else {
+ glaDrawPixelsSafe(x, y, dx, dy, dx, GL_LUMINANCE, GL_UNSIGNED_INT,
+ (unsigned char *)rect - (4 - channel_offset));
+ }
}
}
@@ -774,7 +815,7 @@ static void draw_image_paint_helpers(const bContext *C, ARegion *ar, Scene *scen
}
}
-/* draw main image area */
+/* draw main image region */
void draw_image_main(const bContext *C, ARegion *ar)
{
@@ -813,7 +854,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0;
show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0;
show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && (show_render == false));
- show_stereo3d = (ima && (ima->flag & IMA_IS_STEREO) && (sima->iuser.flag & IMA_SHOW_STEREO));
+ show_stereo3d = (ima && BKE_image_is_stereo(ima) && (sima->iuser.flag & IMA_SHOW_STEREO));
show_multilayer = ima && BKE_image_is_multilayer(ima);
if (show_viewer) {
@@ -855,7 +896,7 @@ void draw_image_main(const bContext *C, ARegion *ar)
BLI_rctf_init(&frame, 0.0f, ibuf->x, 0.0f, ibuf->y);
UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x, &y);
- ED_region_image_metadata_draw(x, y, ibuf, frame, zoomx, zoomy);
+ ED_region_image_metadata_draw(x, y, ibuf, &frame, zoomx, zoomy);
}
}
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 38c9604d14b..8f2f6595408 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -119,8 +119,8 @@ ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **r_lock)
if (ibuf) {
if (ibuf->rect || ibuf->rect_float)
return ibuf;
-
- BKE_image_release_ibuf(sima->image, ibuf, NULL);
+ BKE_image_release_ibuf(sima->image, ibuf, *r_lock);
+ *r_lock = NULL;
}
}
else
@@ -291,6 +291,34 @@ void ED_image_point_pos__reverse(SpaceImage *sima, ARegion *ar, const float co[2
r_co[1] = (co[1] * height * zoomy) + (float)sy;
}
+/**
+ * This is more a user-level functionality, for going to next/prev used slot,
+ * Stepping onto the last unused slot too.
+ */
+bool ED_image_slot_cycle(struct Image *image, int direction)
+{
+ const int cur = image->render_slot;
+ int i, slot;
+
+ BLI_assert(ELEM(direction, -1, 1));
+
+ for (i = 1; i < IMA_MAX_RENDER_SLOT; i++) {
+ slot = (cur + ((direction == -1) ? -i : i)) % IMA_MAX_RENDER_SLOT;
+ if (slot < 0) slot += IMA_MAX_RENDER_SLOT;
+
+ if (image->renders[slot] || slot == image->last_render_slot) {
+ image->render_slot = slot;
+ break;
+ }
+ }
+
+ if (i == IMA_MAX_RENDER_SLOT) {
+ image->render_slot = ((cur == 1) ? 0 : 1);
+ }
+
+ return (cur != image->render_slot);
+}
+
void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings)
{
Scene *scene = CTX_data_scene(C);
@@ -301,6 +329,16 @@ void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *s
return;
if (ob && ((ob->mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0))
return;
+
+ /* We also don't update scopes of render result during render. */
+ if (G.is_rendering) {
+ const Image *image = sima->image;
+ if (image != NULL &&
+ (image->type == IMA_TYPE_R_RESULT || image->type == IMA_TYPE_COMPOSITE))
+ {
+ return;
+ }
+ }
scopes_update(&sima->scopes, ibuf, use_view_settings ? &scene->view_settings : NULL, &scene->display_settings);
}
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 6eaad302180..3b57d17f9f3 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -54,7 +54,7 @@ void draw_image_grease_pencil(struct bContext *C, bool onlyv2d);
void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
-int space_image_main_area_poll(struct bContext *C);
+int space_image_main_region_poll(struct bContext *C);
void IMAGE_OT_view_all(struct wmOperatorType *ot);
void IMAGE_OT_view_pan(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 3c5aff4d698..80dbfa140f6 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -230,7 +230,7 @@ static int space_image_poll(bContext *C)
}
#endif
-int space_image_main_area_poll(bContext *C)
+int space_image_main_region_poll(bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
/* XXX ARegion *ar = CTX_wm_region(C); */
@@ -270,7 +270,7 @@ static int image_sample_poll(bContext *C)
return false;
}
- return space_image_main_area_poll(C);
+ return space_image_main_region_poll(C);
}
else {
return false;
@@ -401,7 +401,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
ot->invoke = image_view_pan_invoke;
ot->modal = image_view_pan_modal;
ot->cancel = image_view_pan_cancel;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
@@ -617,7 +617,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
ot->invoke = image_view_zoom_invoke;
ot->modal = image_view_zoom_modal;
ot->cancel = image_view_zoom_cancel;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS;
@@ -672,7 +672,7 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* api callbacks */
ot->invoke = image_view_ndof_invoke;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
@@ -744,7 +744,7 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_view_all_exec;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
@@ -808,7 +808,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
static int image_view_selected_poll(bContext *C)
{
- return (space_image_main_area_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
+ return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
}
void IMAGE_OT_view_selected(wmOperatorType *ot)
@@ -863,7 +863,7 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
/* api callbacks */
ot->invoke = image_view_zoom_in_invoke;
ot->exec = image_view_zoom_in_exec;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
@@ -912,7 +912,7 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
/* api callbacks */
ot->invoke = image_view_zoom_out_invoke;
ot->exec = image_view_zoom_out_exec;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
@@ -959,7 +959,7 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_view_zoom_ratio_exec;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
@@ -1153,8 +1153,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
}
else {
ima->flag &= ~IMA_USE_VIEWS;
- ima->flag &= ~IMA_IS_STEREO;
- ima->flag &= ~IMA_IS_MULTIVIEW;
BKE_image_free_views(ima);
}
@@ -1171,7 +1169,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->pprop.prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- ima->id.us--;
+ id_us_min(&ima->id);
if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) {
ima->source = IMA_SRC_SEQUENCE;
}
@@ -1222,7 +1220,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
const char *path = U.textudir;
Image *ima = NULL;
Scene *scene = CTX_data_scene(C);
- PropertyRNA *prop;
+
if (sima) {
ima = sima->image;
}
@@ -1262,6 +1260,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
/* show multiview save options only if scene has multiviews */
+ PropertyRNA *prop;
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
@@ -1317,8 +1316,10 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************** Match movie length operator ********************/
@@ -1436,8 +1437,9 @@ void IMAGE_OT_replace(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************** save image as operator ********************/
@@ -1581,7 +1583,9 @@ static void save_image_options_to_op(SaveImageOptions *simopts, wmOperator *op)
RNA_string_set(op->ptr, "filepath", simopts->filepath);
}
-static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy, const char *relbase, int relative, int do_newpath, const char *filepath)
+static void save_image_post(
+ wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int save_copy,
+ const char *relbase, int relative, int do_newpath, const char *filepath)
{
if (ok) {
if (!save_copy) {
@@ -1631,7 +1635,7 @@ static void save_image_post(wmOperator *op, ImBuf *ibuf, Image *ima, int ok, int
}
}
else {
- BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", filepath);
+ BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
}
}
@@ -1703,7 +1707,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
/* we need renderresult for exr and rendered multiview */
scene = CTX_data_scene(C);
rr = BKE_image_acquire_renderresult(scene, ima);
- is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : (ima->flag & IMA_IS_MULTIVIEW) == 0;
+ is_mono = rr ? BLI_listbase_count_ex(&rr->views, 2) < 2 : BLI_listbase_count_ex(&ima->views, 2) < 2;
/* error handling */
if (!rr) {
@@ -1714,7 +1718,7 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
else {
if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
- if ((ima->flag & IMA_IS_STEREO) == 0) {
+ if (!BKE_image_is_stereo(ima)) {
BKE_reportf(op->reports, RPT_ERROR, "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
STEREO_LEFT_NAME, STEREO_RIGHT_NAME);
goto cleanup;
@@ -1760,9 +1764,9 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
/* individual multiview images */
else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
- size_t i;
+ int i;
unsigned char planes = ibuf->planes;
- const size_t totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
+ const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
if (!is_multilayer) {
ED_space_image_release_buffer(sima, ibuf, lock);
@@ -1959,9 +1963,9 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
/* show multiview save options only if image has multiviews */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
- RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+ RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
prop = RNA_struct_find_property(op->ptr, "use_multiview");
- RNA_property_boolean_set(op->ptr, prop, (ima->flag & IMA_IS_MULTIVIEW) != 0);
+ RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
image_filesel(C, op, simopts.filepath);
@@ -2045,8 +2049,9 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "save_as_render", 0, "Save As Render", "Apply render part of display transform when saving byte image");
RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/******************** save image operator ********************/
@@ -2152,7 +2157,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op)
BLI_path_abs(name, bmain->name);
if (0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
- BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s", name);
+ BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
break;
}
@@ -2278,7 +2283,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
- ima->id.us--;
+ id_us_min(&ima->id);
RNA_id_pointer_create(&ima->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
@@ -2302,10 +2307,11 @@ static int image_new_exec(bContext *C, wmOperator *op)
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
+ SpaceImage *sima_other = (SpaceImage *)sl;
- if (!sima->pin)
- ED_space_image_set(sima, scene, scene->obedit, ima);
+ if (!sima_other->pin) {
+ ED_space_image_set(sima_other, scene, scene->obedit, ima);
+ }
}
}
}
@@ -2402,7 +2408,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
static EnumPropertyItem gen_context_items[] = {
{GEN_CONTEXT_NONE, "NONE", 0, "None", ""},
{GEN_CONTEXT_PAINT_CANVAS, "PAINT_CANVAS", 0, "Paint Canvas", ""},
- {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
+ {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -2429,7 +2435,7 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_float_array_default(prop, default_color);
RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
- RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
+ RNA_def_enum(ot->srna, "generated_type", rna_enum_image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
prop = RNA_def_enum(ot->srna, "gen_context", gen_context_items, 0, "Gen Context", "Generation context");
@@ -2720,7 +2726,7 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
+ RNA_def_enum(ot->srna, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack");
RNA_def_string(ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image datablock name to unpack"); /* XXX, weark!, will fail with library, name collisions */
}
@@ -3079,7 +3085,7 @@ void IMAGE_OT_sample_line(wmOperatorType *ot)
ot->invoke = image_sample_line_invoke;
ot->modal = WM_gesture_straightline_modal;
ot->exec = image_sample_line_exec;
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
ot->cancel = WM_gesture_straightline_cancel;
/* flags */
@@ -3282,22 +3288,12 @@ static int image_cycle_render_slot_poll(bContext *C)
static int image_cycle_render_slot_exec(bContext *C, wmOperator *op)
{
Image *ima = CTX_data_edit_image(C);
- int a, slot, cur = ima->render_slot;
- const bool use_reverse = RNA_boolean_get(op->ptr, "reverse");
+ const int direction = RNA_boolean_get(op->ptr, "reverse") ? -1 : 1;
- for (a = 1; a < IMA_MAX_RENDER_SLOT; a++) {
- slot = (cur + (use_reverse ? -a : a)) % IMA_MAX_RENDER_SLOT;
- if (slot < 0) slot += IMA_MAX_RENDER_SLOT;
-
- if (ima->renders[slot] || slot == ima->last_render_slot) {
- ima->render_slot = slot;
- break;
- }
+ if (!ED_image_slot_cycle(ima, direction)) {
+ return OPERATOR_CANCELLED;
}
- if (a == IMA_MAX_RENDER_SLOT)
- ima->render_slot = ((cur == 1) ? 0 : 1);
-
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
/* no undo push for browsing existing */
@@ -3319,7 +3315,7 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
ot->poll = image_cycle_render_slot_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
}
@@ -3332,7 +3328,7 @@ static int change_frame_poll(bContext *C)
if (G.is_rendering)
return 0;
- return space_image_main_area_poll(C);
+ return space_image_main_region_poll(C);
}
static void change_frame_apply(bContext *C, wmOperator *op)
@@ -3465,7 +3461,7 @@ void IMAGE_OT_read_renderlayers(wmOperatorType *ot)
ot->idname = "IMAGE_OT_read_renderlayers";
ot->description = "Read all the current scene's render layers from cache, as needed";
- ot->poll = space_image_main_area_poll;
+ ot->poll = space_image_main_region_poll;
ot->exec = image_read_renderlayers_exec;
/* flags */
@@ -3558,7 +3554,7 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
void IMAGE_OT_clear_render_border(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Render Border";
+ ot->name = "Clear Render Border";
ot->description = "Clear the boundaries of the border render and disable border render";
ot->idname = "IMAGE_OT_clear_render_border";
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 97e3390f142..ccf9e825e1b 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -285,7 +285,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
- kmi = WM_keymap_add_item(keymap, "IMAGE_OT_view_all", FKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "fit_view", true);
WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
@@ -582,7 +582,7 @@ static int image_context(const bContext *C, const char *member, bContextDataResu
/************************** main region ***************************/
/* sets up the fields of the View2D from zoom and offset */
-static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar)
+static void image_main_region_set_view2d(SpaceImage *sima, ARegion *ar)
{
Image *ima = ED_space_image(sima);
float x1, y1, w, h;
@@ -635,7 +635,7 @@ static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void image_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void image_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -670,7 +670,7 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar)
}
-static void image_main_area_draw(const bContext *C, ARegion *ar)
+static void image_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceImage *sima = CTX_wm_space_image(C);
@@ -704,7 +704,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
sima->iuser.scene = scene;
/* we set view2d from own zoom and offset each time */
- image_main_area_set_view2d(sima, ar);
+ image_main_region_set_view2d(sima, ar);
/* we draw image in pixelspace */
draw_image_main(C, ar);
@@ -793,7 +793,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
#endif
}
-static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn)
+static void image_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -821,7 +821,7 @@ static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *
/* *********************** buttons region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void image_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -832,12 +832,12 @@ static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void image_buttons_area_draw(const bContext *C, ARegion *ar)
+static void image_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
-static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -873,7 +873,7 @@ static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
/* *********************** scopes region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void image_tools_area_init(wmWindowManager *wm, ARegion *ar)
+static void image_tools_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -884,7 +884,7 @@ static void image_tools_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void image_tools_area_draw(const bContext *C, ARegion *ar)
+static void image_tools_region_draw(const bContext *C, ARegion *ar)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
@@ -910,7 +910,7 @@ static void image_tools_area_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, NULL, -1, true);
}
-static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -946,17 +946,17 @@ static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
/************************* header region **************************/
/* add handlers, stuff you only do once or on area/region changes */
-static void image_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void image_header_area_draw(const bContext *C, ARegion *ar)
+static void image_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void image_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1005,9 +1005,9 @@ void ED_spacetype_image(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
- art->init = image_main_area_init;
- art->draw = image_main_area_draw;
- art->listener = image_main_area_listener;
+ art->init = image_main_region_init;
+ art->draw = image_main_region_draw;
+ art->listener = image_main_region_listener;
BLI_addhead(&st->regiontypes, art);
@@ -1016,9 +1016,9 @@ void ED_spacetype_image(void)
art->regionid = RGN_TYPE_UI;
art->prefsizex = 220; // XXX
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = image_buttons_area_listener;
- art->init = image_buttons_area_init;
- art->draw = image_buttons_area_draw;
+ art->listener = image_buttons_region_listener;
+ art->init = image_buttons_region_init;
+ art->draw = image_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
ED_uvedit_buttons_register(art);
@@ -1029,9 +1029,9 @@ void ED_spacetype_image(void)
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 220; // XXX
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = image_tools_area_listener;
- art->init = image_tools_area_init;
- art->draw = image_tools_area_draw;
+ art->listener = image_tools_region_listener;
+ art->init = image_tools_region_init;
+ art->draw = image_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: header */
@@ -1039,9 +1039,9 @@ void ED_spacetype_image(void)
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->listener = image_header_area_listener;
- art->init = image_header_area_init;
- art->draw = image_header_area_draw;
+ art->listener = image_header_region_listener;
+ art->init = image_header_region_init;
+ art->draw = image_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_info/SConscript b/source/blender/editors/space_info/SConscript
deleted file mode 100644
index e17c39f7e38..00000000000
--- a/source/blender/editors/space_info/SConscript
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blenloader',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_space_info', sources, Split(incs), defs, libtype=['core'], priority=[70] )
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 2bcd56a3ced..0e427623840 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -249,7 +249,7 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
}
if (count == 1)
- strcpy(title, IFACE_("Unpack 1 File"));
+ BLI_strncpy(title, IFACE_("Unpack 1 File"), sizeof(title));
else
BLI_snprintf(title, sizeof(title), IFACE_("Unpack %d Files"), count);
@@ -484,8 +484,9 @@ void FILE_OT_find_missing_files(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "find_all", false, "Find All", "Find all files in the search path (not just missing)");
- WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, 0, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
/********************* report box operator *********************/
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index aeab87e6cb5..21777fd8afa 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -77,8 +77,8 @@ static SpaceLink *info_new(const bContext *UNUSED(C))
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for info");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for info");
BLI_addtail(&sinfo->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -123,7 +123,7 @@ static SpaceLink *info_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
-static void info_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void info_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -145,7 +145,7 @@ static void info_textview_update_rect(const bContext *C, ARegion *ar)
UI_view2d_totRect_set(v2d, ar->winx - 1, info_textview_height(sinfo, ar, CTX_wm_reports(C)));
}
-static void info_main_area_draw(const bContext *C, ARegion *ar)
+static void info_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceInfo *sinfo = CTX_wm_space_info(C);
@@ -226,17 +226,17 @@ static void info_keymap(struct wmKeyConfig *keyconf)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void info_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void info_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void info_header_area_draw(const bContext *C, ARegion *ar)
+static void info_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void info_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void info_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
// SpaceInfo *sinfo = sa->spacedata.first;
@@ -329,9 +329,9 @@ void ED_spacetype_info(void)
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
- art->init = info_main_area_init;
- art->draw = info_main_area_draw;
- art->listener = info_main_area_listener;
+ art->init = info_main_region_init;
+ art->draw = info_main_region_draw;
+ art->listener = info_main_region_listener;
BLI_addhead(&st->regiontypes, art);
@@ -342,8 +342,8 @@ void ED_spacetype_info(void)
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
art->listener = info_header_listener;
- art->init = info_header_area_init;
- art->draw = info_header_area_draw;
+ art->init = info_header_region_init;
+ art->draw = info_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index ebce13389c9..c801a736e31 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -45,13 +45,14 @@
#include "textview.h"
-static void console_font_begin(TextViewContext *sc)
+static void console_font_begin(const int font_id, const int lheight)
{
/* 0.875 is based on: 16 pixels lines get 14 pixel text */
- BLF_size(blf_mono_font, 0.875 * sc->lheight, 72);
+ BLF_size(font_id, 0.875 * lheight, 72);
}
typedef struct ConsoleDrawContext {
+ int font_id;
int cwidth;
int lheight;
int lofs; /* text vertical offset */
@@ -123,7 +124,6 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
int tot_lines; /* total number of lines for wrapping */
int *offsets; /* offsets of line beginnings for wrapping */
int y_next;
- const int mono = blf_mono_font;
str_len = console_wrap_offsets(str, str_len, cdc->console_width, &tot_lines, &offsets);
y_next = cdc->xy[1] + cdc->lheight * tot_lines;
@@ -189,8 +189,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
glColor3ubv(fg);
/* last part needs no clipping */
- BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
- BLF_draw_mono(mono, s, len, cdc->cwidth);
+ BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
+ BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
console_step_sel(cdc, -initial_offset);
@@ -205,8 +205,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
len = offsets[i] - offsets[i - 1];
s = str + offsets[i - 1];
- BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
- BLF_draw_mono(mono, s, len, cdc->cwidth);
+ BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
+ BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
console_step_sel(cdc, len);
@@ -236,8 +236,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str
glColor3ubv(fg);
- BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
- BLF_draw_mono(mono, str, str_len, cdc->cwidth);
+ BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0);
+ BLF_draw_mono(cdc->font_id, str, str_len, cdc->cwidth);
if (cdc->sel[0] != cdc->sel[1]) {
int isel[2];
@@ -272,9 +272,9 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous
int xy[2], y_prev;
int sel[2] = {-1, -1}; /* defaults disabled */
unsigned char fg[3], bg[3];
- const int mono = blf_mono_font;
+ const int font_id = blf_mono_font;
- console_font_begin(tvc);
+ console_font_begin(font_id, tvc->lheight);
xy[0] = x_orig; xy[1] = y_orig;
@@ -285,10 +285,11 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous
*pos_pick = 0;
/* constants for the sequencer context */
- cdc.cwidth = (int)BLF_fixed_width(mono);
+ cdc.font_id = font_id;
+ cdc.cwidth = (int)BLF_fixed_width(font_id);
assert(cdc.cwidth > 0);
cdc.lheight = tvc->lheight;
- cdc.lofs = -BLF_descender(mono);
+ cdc.lofs = -BLF_descender(font_id);
/* note, scroll bar must be already subtracted () */
cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2)) / cdc.cwidth;
/* avoid divide by zero on small windows */
diff --git a/source/blender/editors/space_logic/SConscript b/source/blender/editors/space_logic/SConscript
deleted file mode 100644
index 4b618710d1f..00000000000
--- a/source/blender/editors/space_logic/SConscript
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../interface',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_space_game', sources, Split(incs), defs, libtype=['core'], priority=[120] )
diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c
index e0cbc1c9539..12c7ef3d3ec 100644
--- a/source/blender/editors/space_logic/logic_buttons.c
+++ b/source/blender/editors/space_logic/logic_buttons.c
@@ -91,7 +91,7 @@ static int cut_links_intersect(uiLinkLine *line, float mcoords[][2], int tot)
if (ui_link_bezier_points(&rectlink, coord_array, LINK_RESOL)) {
for (i=0; i<tot-1; i++)
for (b=0; b<LINK_RESOL-1; b++)
- if (isect_line_line_v2(mcoords[i], mcoords[i+1], coord_array[b], coord_array[b+1]) > 0)
+ if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0)
return 1;
}
return 0;
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index abcb767958f..51f4a61047d 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -447,7 +447,7 @@ static void LOGIC_OT_controller_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", controller_type_items, CONT_LOGIC_AND, "Type", "Type of controller to add");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_controller_type_items, CONT_LOGIC_AND, "Type", "Type of controller to add");
prop = RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the Controller to add");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna, "object", NULL, MAX_NAME, "Object", "Name of the Object to add the Controller to");
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index ccf8460e9a3..874e54ba5e7 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -52,6 +52,7 @@
#include "BKE_action.h"
#include "BKE_context.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_sca.h"
@@ -308,12 +309,13 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
}
if (sa->sound)
- ((ID *)sa->sound)->us--;
+ id_us_min(((ID *)sa->sound));
sa->sound= (struct bSound *)sound;
- if (sound)
- sound->us++;
+ if (sound) {
+ id_us_plus(sound);
+ }
sa->sndnr= 0;
didit= 1;
@@ -397,8 +399,6 @@ static const char *actuator_name(int type)
return N_("Action");
case ACT_OBJECT:
return N_("Motion");
- case ACT_IPO:
- return N_("F-Curve");
case ACT_LAMP:
return N_("Lamp");
case ACT_CAMERA:
@@ -1696,7 +1696,7 @@ static void draw_actuator_filter_2d(uiLayout *layout, PointerRNA *ptr)
static void draw_actuator_game(uiLayout *layout, PointerRNA *ptr)
{
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- if (RNA_enum_get(ptr, "mode") == ACT_GAME_LOAD)
+ if (ELEM(RNA_enum_get(ptr, "mode"), ACT_GAME_LOAD, ACT_GAME_SCREENSHOT))
uiItemR(layout, ptr, "filename", 0, NULL, ICON_NONE);
}
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 34a5fee88eb..243a522011b 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -113,8 +113,8 @@ static SpaceLink *logic_new(const bContext *C)
ar->regiontype= RGN_TYPE_UI;
ar->alignment= RGN_ALIGN_RIGHT;
- /* main area */
- ar= MEM_callocN(sizeof(ARegion), "main area for logic");
+ /* main region */
+ ar= MEM_callocN(sizeof(ARegion), "main region for logic");
BLI_addtail(&slogic->regionbase, ar);
ar->regiontype= RGN_TYPE_WINDOW;
@@ -230,7 +230,7 @@ static int logic_context(const bContext *UNUSED(C), const char *UNUSED(member),
/* add handlers, stuff you only do once or on area/region changes */
-static void logic_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void logic_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -241,7 +241,7 @@ static void logic_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void logic_main_area_draw(const bContext *C, ARegion *ar)
+static void logic_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
// SpaceLogic *slogic= CTX_wm_space_logic(C);
@@ -270,7 +270,7 @@ static void logic_main_area_draw(const bContext *C, ARegion *ar)
/* *********************** buttons region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void logic_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -280,7 +280,7 @@ static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void logic_buttons_area_draw(const bContext *C, ARegion *ar)
+static void logic_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
@@ -288,12 +288,12 @@ static void logic_buttons_area_draw(const bContext *C, ARegion *ar)
/************************* header region **************************/
/* add handlers, stuff you only do once or on area/region changes */
-static void logic_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void logic_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void logic_header_area_draw(const bContext *C, ARegion *ar)
+static void logic_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
@@ -322,8 +322,8 @@ void ED_spacetype_logic(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype logic region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_VIEW2D;
- art->init = logic_main_area_init;
- art->draw = logic_main_area_draw;
+ art->init = logic_main_region_init;
+ art->draw = logic_main_region_draw;
art->listener = logic_listener;
BLI_addhead(&st->regiontypes, art);
@@ -334,8 +334,8 @@ void ED_spacetype_logic(void)
art->prefsizex= 220; // XXX
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = logic_listener;
- art->init = logic_buttons_area_init;
- art->draw = logic_buttons_area_draw;
+ art->init = logic_buttons_region_init;
+ art->draw = logic_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: header */
@@ -343,8 +343,8 @@ void ED_spacetype_logic(void)
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = logic_header_area_init;
- art->draw = logic_header_area_draw;
+ art->init = logic_header_region_init;
+ art->draw = logic_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_nla/SConscript b/source/blender/editors/space_nla/SConscript
deleted file mode 100644
index 5bfa8d6c4c2..00000000000
--- a/source/blender/editors/space_nla/SConscript
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_space_nla', sources, Split(incs), defs, libtype=['core'], priority=[85] )
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 8eead9b8e44..cbdc476bee6 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -478,12 +478,10 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
row = uiLayoutRow(pa->layout, false);
block = uiLayoutGetBlock(row);
- // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
// FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
- uiDefButO(block, UI_BTYPE_BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"), 10, 0, 150, 20,
- TIP_("Adds a new F-Modifier for the active NLA Strip"));
+ uiItemMenuEnumO(row, (bContext *)C, "NLA_OT_fmodifier_add", "type", IFACE_("Add Modifier"), ICON_NONE);
- /* copy/paste (as sub-row)*/
+ /* copy/paste (as sub-row) */
row = uiLayoutRow(row, true);
uiItemO(row, "", ICON_COPYDOWN, "NLA_OT_fmodifier_copy");
uiItemO(row, "", ICON_PASTEDOWN, "NLA_OT_fmodifier_paste");
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index a0ea12b8aa0..9e73e03a664 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -268,7 +268,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe
{
AnimData *adt = BKE_animdata_from_id(ale->id);
- /* button area... */
+ /* button region... */
if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
if (nlaedit_is_tweakmode_on(ac) == 0) {
/* 'push-down' action - only usable when not in TweakMode */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index f7673d86f94..baf87f3fee5 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -542,6 +542,30 @@ void NLA_OT_view_selected(wmOperatorType *ot)
}
/* *********************************************** */
+
+static int nlaedit_viewframe_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+ return OPERATOR_FINISHED;
+}
+
+void NLA_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "NLA_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = nlaedit_viewframe_exec;
+ ot->poll = ED_operator_nla_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* *********************************************** */
/* NLA Editing Operations (Constructive/Destructive) */
/* ******************** Add Action-Clip Operator ***************************** */
@@ -1102,7 +1126,7 @@ void NLA_OT_duplicate(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna, "linked", false, "Linked", "When duplicating strips, assign new copies of the actions they use");
/* to give to transform */
- RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+ RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/* ******************** Delete Strips Operator ***************************** */
@@ -1953,7 +1977,7 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
bAction *act = BKE_action_copy(strip->act);
/* set this as the new referenced action, decrementing the users of the old one */
- strip->act->id.us--;
+ id_us_min(&strip->act->id);
strip->act = act;
}
@@ -2213,19 +2237,20 @@ void NLA_OT_snap(wmOperatorType *ot)
/* ******************** Add F-Modifier Operator *********************** */
-/* present a special customised popup menu for this, with some filtering */
-static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+static EnumPropertyItem *nla_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
- uiPopupMenu *pup;
- uiLayout *layout;
- int i;
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+ int i = 0;
- pup = UI_popup_menu_begin(C, IFACE_("Add F-Modifier"), ICON_NONE);
- layout = UI_popup_menu_layout(pup);
+ if (C == NULL) {
+ return rna_enum_fmodifier_type_items;
+ }
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
+ int index;
/* check if modifier is valid for this context */
if (fmi == NULL)
@@ -2233,16 +2258,17 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), const w
if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
continue;
- /* add entry to add this type of modifier */
- uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
+ index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type);
+ RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
}
- uiItemS(layout);
- UI_popup_menu_end(C, pup);
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
- return OPERATOR_INTERFACE;
+ return item;
}
+
static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -2316,10 +2342,10 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Add F-Modifier";
ot->idname = "NLA_OT_fmodifier_add";
- ot->description = "Add a F-Modifier of the specified type to the selected NLA-Strips";
+ ot->description = "Add F-Modifier to the active/selected NLA-Strips";
/* api callbacks */
- ot->invoke = nla_fmodifier_add_invoke;
+ ot->invoke = WM_menu_invoke;
ot->exec = nla_fmodifier_add_exec;
ot->poll = nlaop_poll_tweakmode_off;
@@ -2327,8 +2353,10 @@ void NLA_OT_fmodifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
- RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
+ ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
+ RNA_def_enum_funcs(ot->prop, nla_fmodifier_itemf);
+
+ RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
}
/* ******************** Copy F-Modifiers Operator *********************** */
@@ -2346,7 +2374,7 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* clear buffer first */
- free_fmodifiers_copybuf();
+ ANIM_fmodifiers_copybuf_free();
/* get a list of the editable tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
@@ -2408,12 +2436,15 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
bAnimListElem *ale;
int filter, ok = 0;
+ const bool active_only = RNA_boolean_get(op->ptr, "only_active");
+ const bool replace = RNA_boolean_get(op->ptr, "replace");
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
@@ -2422,8 +2453,20 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
NlaStrip *strip;
for (strip = nlt->strips.first; strip; strip = strip->next) {
- // TODO: do we want to replace existing modifiers? add user pref for that!
- ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
+ /* can F-Modifier be added to the current strip? */
+ if (active_only) {
+ /* if not active, cannot add since we're only adding to active strip */
+ if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
+ continue;
+ }
+ else {
+ /* strip must be selected, since we're not just doing active */
+ if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
+ continue;
+ }
+
+ /* paste FModifiers from buffer */
+ ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, replace);
ale->update |= ANIM_UPDATE_DEPS;
}
}
@@ -2456,6 +2499,11 @@ void NLA_OT_fmodifier_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_active", true, "Only Active", "Only paste F-Modifiers on active strip");
+ RNA_def_boolean(ot->srna, "replace", false, "Replace Existing",
+ "Replace existing F-Modifiers, instead of just appending to the end of the existing list");
}
/* *********************************************** */
diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h
index 344580c0d15..806fbe90ff2 100644
--- a/source/blender/editors/space_nla/nla_intern.h
+++ b/source/blender/editors/space_nla/nla_intern.h
@@ -94,6 +94,7 @@ void NLA_OT_previewrange_set(wmOperatorType *ot);
void NLA_OT_view_all(wmOperatorType *ot);
void NLA_OT_view_selected(wmOperatorType *ot);
+void NLA_OT_view_frame(wmOperatorType *ot);
void NLA_OT_actionclip_add(wmOperatorType *ot);
void NLA_OT_transition_add(wmOperatorType *ot);
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 98da10470f8..386950ead3a 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -130,6 +130,7 @@ void nla_operatortypes(void)
/* view */
WM_operatortype_append(NLA_OT_view_all);
WM_operatortype_append(NLA_OT_view_selected);
+ WM_operatortype_append(NLA_OT_view_frame);
WM_operatortype_append(NLA_OT_previewrange_set);
@@ -243,6 +244,7 @@ static void nla_keymap_main(wmKeyConfig *keyconf, wmKeyMap *keymap)
WM_keymap_add_item(keymap, "NLA_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "NLA_OT_view_frame", PAD0, KM_PRESS, 0, 0);
/* editing ------------------------------------------------ */
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 9fc7b5d6f8f..e2b36c5b5ae 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -125,15 +125,15 @@ static SpaceLink *nla_new(const bContext *C)
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
/* ui buttons */
- ar = MEM_callocN(sizeof(ARegion), "buttons area for nla");
+ ar = MEM_callocN(sizeof(ARegion), "buttons region for nla");
BLI_addtail(&snla->regionbase, ar);
ar->regiontype = RGN_TYPE_UI;
ar->alignment = RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for nla");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for nla");
BLI_addtail(&snla->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -200,7 +200,7 @@ static SpaceLink *nla_duplicate(SpaceLink *sl)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar)
+static void nla_channel_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -222,7 +222,7 @@ static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar)
}
/* draw entirely, view changes should be handled here */
-static void nla_channel_area_draw(const bContext *C, ARegion *ar)
+static void nla_channel_region_draw(const bContext *C, ARegion *ar)
{
bAnimContext ac;
View2D *v2d = &ar->v2d;
@@ -250,7 +250,7 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar)
/* add handlers, stuff you only do once or on area/region changes */
-static void nla_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void nla_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -263,7 +263,7 @@ static void nla_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void nla_main_area_draw(const bContext *C, ARegion *ar)
+static void nla_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceNla *snla = CTX_wm_space_nla(C);
@@ -326,18 +326,18 @@ static void nla_main_area_draw(const bContext *C, ARegion *ar)
/* add handlers, stuff you only do once or on area/region changes */
-static void nla_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void nla_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void nla_header_area_draw(const bContext *C, ARegion *ar)
+static void nla_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
/* add handlers, stuff you only do once or on area/region changes */
-static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void nla_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -347,7 +347,7 @@ static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void nla_buttons_area_draw(const bContext *C, ARegion *ar)
+static void nla_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
@@ -385,7 +385,7 @@ static void nla_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegio
}
-static void nla_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void nla_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -430,7 +430,7 @@ static void nla_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARe
}
}
-static void nla_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void nla_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -521,9 +521,9 @@ void ED_spacetype_nla(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype nla region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = nla_main_area_init;
- art->draw = nla_main_area_draw;
- art->listener = nla_main_area_listener;
+ art->init = nla_main_region_init;
+ art->draw = nla_main_region_draw;
+ art->listener = nla_main_region_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@@ -534,8 +534,8 @@ void ED_spacetype_nla(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = nla_header_area_init;
- art->draw = nla_header_area_draw;
+ art->init = nla_header_region_init;
+ art->draw = nla_header_region_draw;
BLI_addhead(&st->regiontypes, art);
@@ -545,9 +545,9 @@ void ED_spacetype_nla(void)
art->prefsizex = 200;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
- art->init = nla_channel_area_init;
- art->draw = nla_channel_area_draw;
- art->listener = nla_channel_area_listener;
+ art->init = nla_channel_region_init;
+ art->draw = nla_channel_region_draw;
+ art->listener = nla_channel_region_listener;
BLI_addhead(&st->regiontypes, art);
@@ -557,8 +557,8 @@ void ED_spacetype_nla(void)
art->prefsizex = 200;
art->keymapflag = ED_KEYMAP_UI;
art->listener = nla_region_listener;
- art->init = nla_buttons_area_init;
- art->draw = nla_buttons_area_draw;
+ art->init = nla_buttons_region_init;
+ art->draw = nla_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
deleted file mode 100644
index b559b61cf5a..00000000000
--- a/source/blender/editors/space_node/SConscript
+++ /dev/null
@@ -1,73 +0,0 @@
-
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../compositor',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../nodes',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-cf = []
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- #cf.append('/WX')
- pass
-if env['CC'] == 'gcc':
- #cf.append('-Werror')
- pass
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_COMPOSITOR']:
- defs.append("WITH_COMPOSITOR")
-
-env.BlenderLib ( 'bf_editors_space_node', sources, Split(incs), defs, libtype=['core'], priority=[55], compileflags=cf )
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index ab5874682da..b2f3306fb62 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -247,7 +247,7 @@ static void node_browse_tex_cb(bContext *C, void *ntree_v, void *node_v)
if (node->menunr < 1) return;
if (node->id) {
- node->id->us--;
+ id_us_min(node->id);
node->id = NULL;
}
tex = BLI_findlink(&bmain->tex, node->menunr - 1);
@@ -441,9 +441,14 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
for (line = text->lines.first; line; line = line->next) {
struct ResultBLF info;
- BLF_position(fontid, x, y, 0);
- BLF_draw_ex(fontid, line->line, line->len, &info);
- y -= line_spacing * info.lines;
+ if (line->line[0]) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw_ex(fontid, line->line, line->len, &info);
+ y -= line_spacing * info.lines;
+ }
+ else {
+ y -= line_spacing;
+ }
if (y < y_min) {
break;
}
@@ -857,6 +862,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
}
@@ -898,6 +904,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
}
uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE);
uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
}
@@ -937,6 +944,7 @@ static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), Po
static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_profile", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -953,6 +961,11 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, bContext *UNUSED
{
bNode *node = ptr->data;
NodeShaderTexPointDensity *shader_point_density = node->storage;
+ Object *ob = (Object *)node->id;
+ PointerRNA ob_ptr, obdata_ptr;
+
+ RNA_id_pointer_create((ID *)ob, &ob_ptr);
+ RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr);
uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
@@ -968,7 +981,18 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, bContext *UNUSED
uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE);
if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "particle_color_source", 0, NULL, ICON_NONE);
+ }
+ else {
+ uiItemR(layout, ptr, "vertex_color_source", 0, NULL, ICON_NONE);
+ if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
+ if (ob_ptr.data)
+ uiItemPointerR(layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE);
+ }
+ if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) {
+ if (obdata_ptr.data)
+ uiItemPointerR(layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE);
+ }
}
}
@@ -1052,21 +1076,8 @@ static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
}
-static void node_shader_buts_subsurface(uiLayout *layout, bContext *C, PointerRNA *ptr)
+static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- /* SSS only enabled in Experimental Kernel */
- PointerRNA scene = CTX_data_pointer_get(C, "scene");
- if (scene.data) {
- PointerRNA cscene = RNA_pointer_get(&scene, "cycles");
- if (cscene.data &&
- ((U.compute_device_type != USER_COMPUTE_DEVICE_NONE) &&
- (RNA_enum_get(&cscene, "device") == 1) &&
- (RNA_enum_get(&cscene, "feature_set") == 0)))
- {
- uiItemL(layout, IFACE_("Only enabled in experimental GPU kernel"), ICON_ERROR);
- }
- }
-
uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE);
}
@@ -1371,6 +1382,7 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point
uiItemR(col, ptr, "size_x", 0, IFACE_("X"), ICON_NONE);
uiItemR(col, ptr, "size_y", 0, IFACE_("Y"), ICON_NONE);
}
+ uiItemR(col, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
}
static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2033,6 +2045,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
return;
uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", 0, NULL, ICON_NONE);
}
static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2203,6 +2216,7 @@ static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C),
uiItemR(layout, ptr, "use_variable_size", 0, NULL, ICON_NONE);
// uiItemR(layout, ptr, "f_stop", 0, NULL, ICON_NONE); // UNUSED
uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
}
static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y)
@@ -2449,7 +2463,6 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
MovieTrackingObject *object;
uiLayout *col;
PointerRNA tracking_ptr;
- NodeTrackPosData *data = node->storage;
RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr);
@@ -2887,7 +2900,8 @@ static void node_texture_set_butfunc(bNodeType *ntype)
static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = ptr->id.data;
- ED_node_tag_update_nodetree(bmain, ntree);
+ bNode *node = ptr->data;
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
@@ -3239,9 +3253,9 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
#ifdef __BIG_ENDIAN__
- if (snode->flag & SNODE_SHOW_R) ofs = 2;
+ if (snode->flag & SNODE_SHOW_R) ofs = 0;
else if (snode->flag & SNODE_SHOW_G) ofs = 1;
- else ofs = 0;
+ else ofs = 2;
#else
if (snode->flag & SNODE_SHOW_R) ofs = 1;
else if (snode->flag & SNODE_SHOW_G) ofs = 2;
@@ -3252,7 +3266,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
/* swap bytes, so alpha is most significant one, then just draw it as luminance int */
glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT,
- display_buffer + ofs);
+ display_buffer - (4 - ofs));
glPixelZoom(1.0f, 1.0f);
}
@@ -3332,7 +3346,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
/* if v2d not NULL, it clips and returns 0 if not visible */
-int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
+bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
{
float dist, vec[4][2];
float deltax, deltay;
@@ -3368,7 +3382,8 @@ int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, floa
toreroute = 0;
}
- dist = UI_GetThemeValue(TH_NODE_CURVING) * 0.10f * fabsf(vec[0][0] - vec[3][0]);
+ /* may be called outside of drawing (so pass spacetype) */
+ dist = UI_GetThemeValueType(TH_NODE_CURVING, SPACE_NODE) * 0.10f * fabsf(vec[0][0] - vec[3][0]);
deltax = vec[3][0] - vec[0][0];
deltay = vec[3][1] - vec[0][1];
/* check direction later, for top sockets */
@@ -3472,7 +3487,6 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
glBegin(GL_LINE_STRIP);
glVertex2fv(arrow1);
glVertex2fv(arrow);
- glVertex2fv(arrow);
glVertex2fv(arrow2);
glEnd();
}
@@ -3509,15 +3523,11 @@ void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link,
glBegin(GL_LINE_STRIP);
glVertex2fv(arrow1);
glVertex2fv(arrow);
- glVertex2fv(arrow);
glVertex2fv(arrow2);
glEnd();
}
glDisable(GL_LINE_SMOOTH);
-
- /* restore previuos linewidth */
- glLineWidth(1.0f);
}
}
@@ -3548,14 +3558,10 @@ void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link,
int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3)
{
float coord_array[2][2];
- float linew;
int i;
node_link_straight_points(v2d, snode, link, coord_array);
- /* store current linewidth */
- glGetFloatv(GL_LINE_WIDTH, &linew);
-
glEnable(GL_LINE_SMOOTH);
if (do_triple) {
@@ -3601,9 +3607,6 @@ void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link,
}
glDisable(GL_LINE_SMOOTH);
-
- /* restore previuos linewidth */
- glLineWidth(1.0f);
}
#endif
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index ab7fa51856a..b50df02beae 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -107,7 +107,7 @@ static bool add_reroute_intersect_check(bNodeLink *link, float mcoords[][2], int
for (i = 0; i < tot - 1; i++)
for (b = 0; b < NODE_LINK_RESOL; b++)
- if (isect_line_line_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
+ if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0) {
result[0] = (mcoords[i][0] + mcoords[i + 1][0]) / 2.0f;
result[1] = (mcoords[i][1] + mcoords[i + 1][1]) / 2.0f;
return 1;
@@ -379,8 +379,9 @@ void NODE_OT_add_file(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
}
@@ -438,7 +439,7 @@ void NODE_OT_add_mask(wmOperatorType *ot)
ot->poll = node_add_mask_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Datablock name to assign");
}
@@ -487,7 +488,7 @@ static int new_node_tree_exec(bContext *C, wmOperator *op)
/* RNA_property_pointer_set increases the user count,
* fixed here as the editor is the initial user.
*/
- ntree->id.us--;
+ id_us_min(&ntree->id);
RNA_id_pointer_create(&ntree->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 283457d1fc6..d9c51e427c8 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -85,9 +86,7 @@ void ED_node_tree_update(const bContext *C)
if (snode) {
snode_set_context(C);
- if (snode->nodetree && snode->nodetree->id.us == 0) {
- snode->nodetree->id.us = 1;
- }
+ id_us_ensure_real(&snode->nodetree->id);
}
}
@@ -154,18 +153,27 @@ void ED_node_tag_update_id(ID *id)
}
}
-void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree)
+void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
{
if (!ntree)
return;
-
+
+ bool do_tag_update = true;
+ if (node != NULL) {
+ if (!node_connected_to_output(ntree, node)) {
+ do_tag_update = false;
+ }
+ }
+
/* look through all datablocks, to support groups */
- FOREACH_NODETREE(bmain, tntree, id) {
- /* check if nodetree uses the group */
- if (ntreeHasTree(tntree, ntree))
- ED_node_tag_update_id(id);
- } FOREACH_NODETREE_END
-
+ if (do_tag_update) {
+ FOREACH_NODETREE(bmain, tntree, id) {
+ /* check if nodetree uses the group */
+ if (ntreeHasTree(tntree, ntree))
+ ED_node_tag_update_id(id);
+ } FOREACH_NODETREE_END
+ }
+
if (ntree->type == NTREE_TEXTURE)
ntreeTexCheckCyclics(ntree);
}
@@ -652,7 +660,6 @@ static void node_circle_draw(float x, float y, float size, const float col[4], i
glEnd();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
- glLineWidth(1.0f);
}
void node_socket_circle_draw(const bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock, float size, int highlight)
@@ -821,6 +828,8 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
}
#endif
+ glLineWidth(1.0f);
+
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT);
UI_draw_roundbox(rct->xmin, rct->ymax - NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
@@ -1057,7 +1066,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b
// BLI_snprintf(showname, sizeof(showname), "[%s]", showname); /* XXX - don't print into self! */
uiDefBut(node->block, UI_BTYPE_LABEL, 0, showname,
- (int)(rct->xmin + (NODE_MARGIN_X)), (int)(centy - 10),
+ iroundf(rct->xmin + NODE_MARGIN_X), iroundf(centy - NODE_DY * 0.5f),
(short)(BLI_rctf_size_x(rct) - 18.0f - 12.0f), (short)NODE_DY,
NULL, 0, 0, 0, 0, "");
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index ffd51bcc44e..6ae72e2a164 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -277,7 +277,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
G.is_break = false;
#endif
- BKE_image_backup_render(scene, BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"));
+ BKE_image_backup_render(scene, BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), false);
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene_owner, "Compositing",
WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, WM_JOB_TYPE_COMPOSITE);
@@ -657,10 +657,10 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
node->flag |= NODE_DO_OUTPUT;
if (was_output == 0)
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
else if (do_update)
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
/* if active texture changed, free glsl materials */
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
@@ -692,7 +692,7 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
node->flag |= NODE_DO_OUTPUT;
if (was_output == 0)
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
/* addnode() doesnt link this yet... */
node->id = (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
@@ -722,11 +722,11 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
tnode->flag &= ~NODE_DO_OUTPUT;
node->flag |= NODE_DO_OUTPUT;
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
}
else if (do_update)
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
else if (ntree->type == NTREE_TEXTURE) {
// XXX
@@ -791,7 +791,7 @@ static void edit_node_properties(wmOperatorType *ot)
/* XXX could node be a context pointer? */
RNA_def_string(ot->srna, "node", NULL, MAX_NAME, "Node", "");
RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
- RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Side", "");
+ RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Side", "");
}
static int edit_node_invoke_properties(bContext *C, wmOperator *op)
@@ -924,14 +924,13 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
pwidth = &node->miniwidth;
oldwidth = nsw->oldminiwidth;
widthmin = 0.0f;
- widthmax = 100.0f;
}
else {
pwidth = &node->width;
oldwidth = nsw->oldwidth;
widthmin = node->typeinfo->minwidth;
- widthmax = node->typeinfo->maxwidth;
}
+ widthmax = node->typeinfo->maxwidth;
{
if (nsw->directions & NODE_RESIZE_RIGHT) {
@@ -1177,7 +1176,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
bNode *node, *newnode, *lastnode;
bNodeLink *link, *newlink, *lastlink;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
-
+ bool do_tag_update = false;
+
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
lastnode = ntree->nodes.last;
@@ -1254,6 +1254,8 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
nodeSetSelected(node, false);
node->flag &= ~NODE_ACTIVE;
nodeSetSelected(newnode, true);
+
+ do_tag_update |= (do_tag_update || node_connected_to_output(ntree, newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1264,7 +1266,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
- snode_dag_update(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
return OPERATOR_FINISHED;
}
@@ -1317,15 +1321,15 @@ static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
/* first tag scenes unread */
for (scene = bmain->scene.first; scene; scene = scene->id.next)
- scene->id.flag |= LIB_DOIT;
+ scene->id.tag |= LIB_TAG_DOIT;
for (node = snode->edittree->nodes.first; node; node = node->next) {
if (node->type == CMP_NODE_R_LAYERS) {
ID *id = node->id;
- if (id->flag & LIB_DOIT) {
+ if (id->tag & LIB_TAG_DOIT) {
RE_ReadRenderResult(curscene, (Scene *)id);
ntreeCompositTagRender((Scene *)id);
- id->flag &= ~LIB_DOIT;
+ id->tag &= ~LIB_TAG_DOIT;
}
}
}
@@ -1623,6 +1627,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
+ bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
@@ -1631,11 +1636,14 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
if ((node->flag & SELECT) && node->typeinfo->update_internal_links) {
node->flag ^= NODE_MUTED;
snode_update(snode, node);
+ do_tag_update |= (do_tag_update || node_connected_to_output(snode->edittree, node));
}
}
snode_notify(C, snode);
- snode_dag_update(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
return OPERATOR_FINISHED;
}
@@ -1661,15 +1669,17 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node, *next;
-
+ bool do_tag_update = false;
+
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
for (node = snode->edittree->nodes.first; node; node = next) {
next = node->next;
if (node->flag & SELECT) {
/* check id user here, nodeFreeNode is called for free dbase too */
+ do_tag_update |= (do_tag_update || node_connected_to_output(snode->edittree, node));
if (node->id)
- node->id->us--;
+ id_us_min(node->id);
nodeFreeNode(snode->edittree, node);
}
}
@@ -1677,7 +1687,9 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
- snode_dag_update(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
return OPERATOR_FINISHED;
}
@@ -1760,7 +1772,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
/* check id user here, nodeFreeNode is called for free dbase too */
if (node->id)
- node->id->us--;
+ id_us_min(node->id);
nodeFreeNode(snode->edittree, node);
}
}
@@ -2251,7 +2263,7 @@ void NODE_OT_tree_socket_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Type", "");
+ RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
}
/********************** Remove interface socket operator *********************/
@@ -2438,7 +2450,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
SpaceNode *snode = CTX_wm_space_node(C);
PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
- bNodeTree *ntree = NULL;
+ bNodeTree *ntree_base = NULL;
bNode *node = NULL;
RenderEngine *engine;
RenderEngineType *type;
@@ -2451,17 +2463,17 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
/* get node */
if (nodeptr.data) {
- ntree = nodeptr.id.data;
+ ntree_base = nodeptr.id.data;
node = nodeptr.data;
}
else if (snode && snode->edittree) {
- ntree = snode->edittree;
+ ntree_base = snode->edittree;
node = nodeGetActive(snode->edittree);
}
if (node) {
/* update single node */
- type->update_script_node(engine, ntree, node);
+ type->update_script_node(engine, ntree_base, node);
found = true;
}
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index b57f95db4e6..5c58e9b720c 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -253,7 +253,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
if (wgroup->adt) {
LinkData *ld, *ldn = NULL;
bAction *waction;
-
+
/* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */
waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action);
@@ -271,6 +271,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
/* free temp action too */
if (waction) {
BKE_libblock_free(G.main, waction);
+ wgroup->adt->action = NULL;
}
}
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index b08c9b10eeb..6b8fa0b88fe 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -133,7 +133,7 @@ void NODE_OT_backimage_sample(struct wmOperatorType *ot);
/* drawnode.c */
void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link);
void node_draw_link_bezier(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, int th_col1, bool do_shaded, int th_col2, bool do_triple, int th_col3);
-int node_link_bezier_points(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, float coord_array[][2], int resol);
+bool node_link_bezier_points(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link, float coord_array[][2], int resol);
// void node_draw_link_straight(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 );
void draw_nodespace_back_pix(const struct bContext *C, struct ARegion *ar, struct SpaceNode *snode, bNodeInstanceKey parent_key);
@@ -155,6 +155,8 @@ void NODE_OT_group_edit(struct wmOperatorType *ot);
/* node_relationships.c */
+bool node_connected_to_output(struct bNodeTree *ntree, struct bNode *node);
+
void NODE_OT_link(struct wmOperatorType *ot);
void NODE_OT_link_make(struct wmOperatorType *ot);
void NODE_OT_links_cut(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 96f0e69ca71..7788173a8ee 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -233,7 +233,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_properties", NKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NODE_OT_toolbar", TKEY, KM_PRESS, 0, 0);
- /* Main Area only ----------------- */
+ /* Main Region only ----------------- */
keymap = WM_keymap_find(keyconf, "Node Editor", SPACE_NODE, 0);
/* mouse select in nodes used to be both keys, but perhaps this should be reduced?
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index a9f126a75e2..07e79c5a59c 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -29,8 +29,6 @@
* \ingroup spnode
*/
-#include <ctype.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_node_types.h"
@@ -41,6 +39,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_node.h"
#include "ED_node.h" /* own include */
@@ -61,6 +61,104 @@
#include "node_intern.h" /* own include */
+/* ****************** Relations helpers *********************** */
+
+static bool ntree_check_nodes_connected_dfs(bNodeTree *ntree,
+ bNode *from,
+ bNode *to)
+{
+ if (from->flag & NODE_TEST) {
+ return false;
+ }
+ from->flag |= NODE_TEST;
+ for (bNodeLink *link = ntree->links.first; link != NULL; link = link->next) {
+ if (link->fromnode == from) {
+ if (link->tonode == to) {
+ return true;
+ }
+ else {
+ if (ntree_check_nodes_connected_dfs(ntree, link->tonode, to)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool ntree_check_nodes_connected(bNodeTree *ntree, bNode *from, bNode *to)
+{
+ if (from == to) {
+ return true;
+ }
+ ntreeNodeFlagSet(ntree, NODE_TEST, false);
+ return ntree_check_nodes_connected_dfs(ntree, from, to);
+}
+
+static bool node_group_has_output_dfs(bNode *node)
+{
+ bNodeTree *ntree = (bNodeTree *)node->id;
+ if (ntree->id.tag & LIB_TAG_DOIT) {
+ return false;
+ }
+ ntree->id.tag |= LIB_TAG_DOIT;
+ for (bNode *current_node = ntree->nodes.first;
+ current_node != NULL;
+ current_node = current_node->next)
+ {
+ if (current_node->type == NODE_GROUP) {
+ if (node_group_has_output_dfs(current_node)) {
+ return true;
+ }
+ }
+ if (current_node->flag & NODE_DO_OUTPUT &&
+ current_node->type != NODE_GROUP_OUTPUT)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool node_group_has_output(bNode *node)
+{
+ Main *bmain = G.main;
+ BLI_assert(node->type == NODE_GROUP);
+ bNodeTree *ntree = (bNodeTree *)node->id;
+ if (ntree == NULL) {
+ return false;
+ }
+ BKE_main_id_tag_listbase(&bmain->nodetree, LIB_TAG_DOIT, false);
+ return node_group_has_output_dfs(node);
+}
+
+bool node_connected_to_output(bNodeTree *ntree, bNode *node)
+{
+ for (bNode *current_node = ntree->nodes.first;
+ current_node != NULL;
+ current_node = current_node->next)
+ {
+ /* Special case for group nodes -- if modified node connected to a group
+ * with active output inside we consider refresh is needed.
+ *
+ * We could make check more grained here by taking which socket the node
+ * is connected to and so eventually.
+ */
+ if (current_node->type == NODE_GROUP &&
+ ntree_check_nodes_connected(ntree, node, current_node) &&
+ node_group_has_output(current_node))
+ {
+ return true;
+ }
+ if (current_node->flag & NODE_DO_OUTPUT) {
+ if (ntree_check_nodes_connected(ntree, node, current_node)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
/* ****************** Add *********************** */
@@ -227,6 +325,10 @@ static void snode_autoconnect(SpaceNode *snode, const bool allow_multiple, const
node_fr = nli->node;
node_to = nli->next->node;
+ /* corner case: input/output node aligned the wrong way around (T47729) */
+ if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) {
+ SWAP(bNode *, node_fr, node_to);
+ }
/* if there are selected sockets, connect those */
for (sock_to = node_to->inputs.first; sock_to; sock_to = sock_to->next) {
@@ -420,7 +522,6 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag))
#undef HEADER_LENGTH
}
-/* update link_count fields to avoid repeated link counting */
static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
{
bNodeLink *link;
@@ -434,64 +535,13 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
return count;
}
-/* test if two sockets are interchangeable
- * XXX this could be made into a tree-type callback for flexibility
- */
-static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
-{
- /* tests if alphabetic prefix matches
- * this allows for imperfect matches, such as numeric suffixes,
- * like Color1/Color2
- */
- int prefix_len = 0;
- char *ca = a->name, *cb = b->name;
- for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) {
- /* end of common prefix? */
- if (*ca != *cb) {
- /* prefix delimited by non-alphabetic char */
- if (isalpha(*ca) || isalpha(*cb))
- return false;
- break;
- }
- ++prefix_len;
- }
- return prefix_len > 0;
-}
-
-/* find an eligible socket for linking */
-static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur, bool use_swap)
-{
- int cur_link_count = node_count_links(ntree, cur);
- if (cur_link_count <= cur->limit) {
- /* current socket is fine, use it */
- return cur;
- }
- else if (use_swap) {
- /* link swapping: try to find a free slot with a matching name */
-
- bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
- bNodeSocket *sock;
-
- sock = cur->next ? cur->next : first; /* wrap around the list end */
- while (sock != cur) {
- if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) {
- int link_count = node_count_links(ntree, sock);
- /* take +1 into account since we would add a new link */
- if (link_count + 1 <= sock->limit)
- return sock; /* found a valid free socket we can swap to */
- }
-
- sock = sock->next ? sock->next : first; /* wrap around the list end */
- }
- }
- return NULL;
-}
-
-static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_swap)
+static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link)
{
bNodeTree *ntree = snode->edittree;
bNodeSocket *from = link->fromsock, *to = link->tosock;
bNodeLink *tlink, *tlink_next;
+ int to_count = node_count_links(ntree, to);
+ int from_count = node_count_links(ntree, from);
for (tlink = ntree->links.first; tlink; tlink = tlink_next) {
tlink_next = tlink->next;
@@ -499,28 +549,18 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_
continue;
if (tlink && tlink->fromsock == from) {
- bNodeSocket *new_from = node_find_linkable_socket(ntree, tlink->fromnode, from, use_swap);
- if (new_from && new_from != from) {
- /* redirect existing link */
- tlink->fromsock = new_from;
- }
- else if (!new_from) {
- /* no possible replacement, remove tlink */
+ if (from_count > from->limit) {
nodeRemLink(ntree, tlink);
tlink = NULL;
+ --from_count;
}
}
if (tlink && tlink->tosock == to) {
- bNodeSocket *new_to = node_find_linkable_socket(ntree, tlink->tonode, to, use_swap);
- if (new_to && new_to != to) {
- /* redirect existing link */
- tlink->tosock = new_to;
- }
- else if (!new_to) {
- /* no possible replacement, remove tlink */
+ if (to_count > to->limit) {
nodeRemLink(ntree, tlink);
tlink = NULL;
+ --to_count;
}
}
}
@@ -532,11 +572,22 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
bNodeTree *ntree = snode->edittree;
bNodeLinkDrag *nldrag = op->customdata;
LinkData *linkdata;
-
+ bool do_tag_update = false;
+
+ /* avoid updates while applying links */
+ ntree->is_updating = true;
for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) {
bNodeLink *link = linkdata->data;
if (apply_links && link->tosock && link->fromsock) {
+ /* before actually adding the link,
+ * let nodes perform special link insertion handling
+ */
+ if (link->fromnode->typeinfo->insert_link)
+ link->fromnode->typeinfo->insert_link(ntree, link->fromnode, link);
+ if (link->tonode->typeinfo->insert_link)
+ link->tonode->typeinfo->insert_link(ntree, link->tonode, link);
+
/* add link to the node tree */
BLI_addtail(&ntree->links, link);
@@ -546,15 +597,28 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
link->tonode->update |= NODE_UPDATE;
/* we might need to remove a link */
- node_remove_extra_links(snode, link, true);
+ node_remove_extra_links(snode, link);
+
+ if (link->tonode) {
+ do_tag_update |= (do_tag_update || node_connected_to_output(ntree, link->tonode));
+ }
}
- else
+ else {
+ /* See note below, but basically TEST flag means that the link
+ * was connected to output (or to a node which affects the
+ * output).
+ */
+ do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
nodeRemLink(ntree, link);
+ }
}
+ ntree->is_updating = false;
ntreeUpdateTree(CTX_data_main(C), ntree);
snode_notify(C, snode);
- snode_dag_update(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
BLI_remlink(&snode->linkdrag, nldrag);
/* links->data pointers are either held by the tree or freed already */
@@ -685,7 +749,18 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], bool det
*oplink = *link;
oplink->next = oplink->prev = NULL;
oplink->flag |= NODE_LINK_VALID;
-
+
+ /* The link could be disconnected and in that case we
+ * wouldn't be able to check whether tag update is
+ * needed or not when releasing mouse button. So we
+ * cache whether the link affects output or not here
+ * using TEST flag.
+ */
+ oplink->flag &= ~NODE_LINK_TEST;
+ if (node_connected_to_output(snode->edittree, link->tonode)) {
+ oplink->flag |= NODE_LINK_TEST;
+ }
+
BLI_addtail(&nldrag->links, linkdata);
nodeRemLink(snode->edittree, link);
}
@@ -700,7 +775,11 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], bool det
oplink->fromnode = node;
oplink->fromsock = sock;
oplink->flag |= NODE_LINK_VALID;
-
+ oplink->flag &= ~NODE_LINK_TEST;
+ if (node_connected_to_output(snode->edittree, node)) {
+ oplink->flag |= NODE_LINK_TEST;
+ }
+
BLI_addtail(&nldrag->links, linkdata);
}
}
@@ -721,7 +800,11 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], bool det
*oplink = *link;
oplink->next = oplink->prev = NULL;
oplink->flag |= NODE_LINK_VALID;
-
+ oplink->flag &= ~NODE_LINK_TEST;
+ if (node_connected_to_output(snode->edittree, link->tonode)) {
+ oplink->flag |= NODE_LINK_TEST;
+ }
+
BLI_addtail(&nldrag->links, linkdata);
nodeRemLink(snode->edittree, link);
@@ -740,7 +823,11 @@ static bNodeLinkDrag *node_link_init(SpaceNode *snode, float cursor[2], bool det
oplink->tonode = node;
oplink->tosock = sock;
oplink->flag |= NODE_LINK_VALID;
-
+ oplink->flag &= ~NODE_LINK_TEST;
+ if (node_connected_to_output(snode->edittree, node)) {
+ oplink->flag |= NODE_LINK_TEST;
+ }
+
BLI_addtail(&nldrag->links, linkdata);
}
}
@@ -849,7 +936,7 @@ void NODE_OT_link_make(wmOperatorType *ot)
}
/* ********************** Cut Link operator ***************** */
-static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
+static bool cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
{
float coord_array[NODE_LINK_RESOL + 1][2];
int i, b;
@@ -858,7 +945,7 @@ static int cut_links_intersect(bNodeLink *link, float mcoords[][2], int tot)
for (i = 0; i < tot - 1; i++)
for (b = 0; b < NODE_LINK_RESOL; b++)
- if (isect_line_line_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0)
+ if (isect_seg_seg_v2(mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1]) > 0)
return 1;
}
return 0;
@@ -870,6 +957,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
float mcoords[256][2];
int i = 0;
+ bool do_tag_update = false;
RNA_BEGIN (op->ptr, itemptr, "path")
{
@@ -902,6 +990,8 @@ static int cut_links_exec(bContext *C, wmOperator *op)
found = true;
}
+ do_tag_update |= (do_tag_update || node_connected_to_output(snode->edittree, link->tonode));
+
snode_update(snode, link->tonode);
nodeRemLink(snode->edittree, link);
}
@@ -910,7 +1000,9 @@ static int cut_links_exec(bContext *C, wmOperator *op)
if (found) {
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
snode_notify(C, snode);
- snode_dag_update(C, snode);
+ if (do_tag_update) {
+ snode_dag_update(C, snode);
+ }
return OPERATOR_FINISHED;
}
@@ -1646,10 +1738,15 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w
for (node = snode->edittree->nodes.first; node; node = node->next) {
if (UNLIKELY(node->anim_ofsx)) {
const float endval = node->anim_init_locx + node->anim_ofsx;
- if (node->locx < endval) {
+ if (IS_EQF(node->locx, endval) == false) {
node->locx = BLI_easing_cubic_ease_in_out(duration, node->anim_init_locx, node->anim_ofsx,
NODE_INSOFS_ANIM_DURATION);
- CLAMP_MAX(node->locx, endval);
+ if (node->anim_ofsx < 0) {
+ CLAMP_MIN(node->locx, endval);
+ }
+ else {
+ CLAMP_MAX(node->locx, endval);
+ }
redraw = true;
}
}
@@ -1741,7 +1838,7 @@ void ED_node_link_insert(ScrArea *sa)
link->tonode = select;
link->tosock = best_input;
- node_remove_extra_links(snode, link, false);
+ node_remove_extra_links(snode, link);
link->flag &= ~NODE_LINKFLAG_HILITE;
nodeAddLink(snode->edittree, select, best_output, node, sockto);
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 78302fedd97..7195d2a9838 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -531,7 +531,15 @@ static int node_borderselect_exec(bContext *C, wmOperator *op)
UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
for (node = snode->edittree->nodes.first; node; node = node->next) {
- if (BLI_rctf_isect(&rectf, &node->totr, NULL)) {
+ bool select;
+ if (node->type == NODE_FRAME) {
+ select = BLI_rctf_inside_rctf(&rectf, &node->totr);
+ }
+ else {
+ select = BLI_rctf_isect(&rectf, &node->totr, NULL);
+ }
+
+ if (select) {
nodeSetSelected(node, (gesture_mode == GESTURE_MODAL_SELECT));
}
else if (!extend) {
@@ -1010,7 +1018,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, 9 * UI_UNIT_X, UI_UNIT_Y, 0, 0, "");
- UI_but_func_search_set(but, node_find_cb, op->type, node_find_call_cb, NULL);
+ UI_but_func_search_set(but, NULL, node_find_cb, op->type, node_find_call_cb, NULL);
/* fake button, it holds space for search items */
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index f2293754608..0cbb7ea0220 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -150,7 +150,7 @@ static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
if (node->flag & NODE_TEST) {
if (node->id)
- node->id->us--;
+ id_us_min(node->id);
nodeFreeNode(ntree, node);
}
}
@@ -168,7 +168,7 @@ static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to
nodeUpdate(ntree, node_to);
ntreeUpdateTree(bmain, ntree);
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node_to);
}
/* remove all nodes connected to this socket, if they aren't connected to other nodes */
@@ -183,7 +183,7 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN
nodeUpdate(ntree, node_to);
ntreeUpdateTree(bmain, ntree);
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node_to);
}
/* add new node connected to this socket, or replace an existing one */
@@ -279,7 +279,7 @@ static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *
nodeUpdate(ntree, node_to);
ntreeUpdateTree(CTX_data_main(C), ntree);
- ED_node_tag_update_nodetree(CTX_data_main(C), ntree);
+ ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
}
/****************************** Node Link Menu *******************************/
@@ -524,7 +524,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
bNodeSocket *sock = arg->sock;
bNodeTreeType *ntreetype = arg->ntree->typeinfo;
- UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
+ UI_block_flag_enable(block, UI_BLOCK_NO_FLIP | UI_BLOCK_IS_FLIP);
UI_block_layout_set_current(block, layout);
split = uiLayoutSplit(layout, 0.0f, false);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index b9b925f1829..df484724fc5 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -333,8 +333,8 @@ static SpaceLink *node_new(const bContext *UNUSED(C))
ar->flag = RGN_FLAG_HIDDEN;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for node");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for node");
BLI_addtail(&snode->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -586,7 +586,7 @@ static SpaceLink *node_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
-static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void node_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -596,13 +596,13 @@ static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void node_buttons_area_draw(const bContext *C, ARegion *ar)
+static void node_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
/* add handlers, stuff you only do once or on area/region changes */
-static void node_toolbar_area_init(wmWindowManager *wm, ARegion *ar)
+static void node_toolbar_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -612,7 +612,7 @@ static void node_toolbar_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void node_toolbar_area_draw(const bContext *C, ARegion *ar)
+static void node_toolbar_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
@@ -634,8 +634,8 @@ static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
}
-/* Initialize main area, setting handlers. */
-static void node_main_area_init(wmWindowManager *wm, ARegion *ar)
+/* Initialize main region, setting handlers. */
+static void node_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
ListBase *lb;
@@ -655,7 +655,7 @@ static void node_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static void node_main_area_draw(const bContext *C, ARegion *ar)
+static void node_main_region_draw(const bContext *C, ARegion *ar)
{
drawnodespace(C, ar);
}
@@ -722,12 +722,12 @@ static void node_dropboxes(void)
/* add handlers, stuff you only do once or on area/region changes */
-static void node_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void node_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void node_header_area_draw(const bContext *C, ARegion *ar)
+static void node_header_region_draw(const bContext *C, ARegion *ar)
{
/* find and set the context */
snode_set_context(C);
@@ -735,7 +735,7 @@ static void node_header_area_draw(const bContext *C, ARegion *ar)
ED_region_header(C, ar);
}
-/* used for header + main area */
+/* used for header + main region */
static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
@@ -844,8 +844,8 @@ void ED_spacetype_node(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype node region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = node_main_area_init;
- art->draw = node_main_area_draw;
+ art->init = node_main_region_init;
+ art->draw = node_main_region_draw;
art->listener = node_region_listener;
art->cursor = node_cursor;
art->event_cursor = true;
@@ -859,8 +859,8 @@ void ED_spacetype_node(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
art->listener = node_region_listener;
- art->init = node_header_area_init;
- art->draw = node_header_area_draw;
+ art->init = node_header_region_init;
+ art->draw = node_header_region_draw;
BLI_addhead(&st->regiontypes, art);
@@ -870,8 +870,8 @@ void ED_spacetype_node(void)
art->prefsizex = 180; // XXX
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = node_region_listener;
- art->init = node_buttons_area_init;
- art->draw = node_buttons_area_draw;
+ art->init = node_buttons_region_init;
+ art->draw = node_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
node_buttons_register(art);
@@ -883,8 +883,8 @@ void ED_spacetype_node(void)
art->prefsizey = 50; /* XXX */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
art->listener = node_region_listener;
- art->init = node_toolbar_area_init;
- art->draw = node_toolbar_area_draw;
+ art->init = node_toolbar_region_init;
+ art->draw = node_toolbar_region_draw;
BLI_addhead(&st->regiontypes, art);
node_toolbar_register(art);
diff --git a/source/blender/editors/space_outliner/SConscript b/source/blender/editors/space_outliner/SConscript
deleted file mode 100644
index dce559a21df..00000000000
--- a/source/blender/editors/space_outliner/SConscript
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs == env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_space_outliner', sources, incs, defines=defs, libtype=['core'], priority=[60] )
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index ac9e2e36ded..b624c7cba75 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -208,11 +208,12 @@ static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob
id = ptr.id.data;
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
- short flag = ANIM_get_keyframing_flags(scene, 1);
+ ToolSettings *ts = scene->toolsettings;
+ eInsertKeyFlags key_flag = ANIM_get_keyframing_flags(scene, 1);
fcu->flag &= ~FCURVE_SELECTED;
insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path, fcu->array_index, CFRA, flag);
+ fcu->rna_path, fcu->array_index, CFRA, ts->keyframe_type, key_flag);
/* Assuming this is not necessary here, since 'ancestor' object button will do it anyway. */
/* WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); */
}
@@ -434,6 +435,7 @@ static void restrictbutton_gr_restrict_view(bContext *C, void *poin, void *poin2
{
restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_VIEW);
WM_event_add_notifier(C, NC_GROUP, NULL);
+ DAG_id_type_tag(CTX_data_main(C), ID_OB);
}
static void restrictbutton_gr_restrict_select(bContext *C, void *poin, void *poin2)
{
@@ -473,7 +475,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
TreeElement *te = outliner_find_tree_element(&soops->tree, tselem);
if (tselem->type == 0) {
- test_idbutton(tselem->id->name); // library.c, unique name and alpha sort
+ BLI_libblock_ensure_unique_name(G.main, tselem->id->name);
switch (GS(tselem->id->name)) {
case ID_MA:
@@ -508,7 +510,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object
break;
case TSE_NLA_ACTION:
- test_idbutton(tselem->id->name);
+ BLI_libblock_ensure_unique_name(G.main, tselem->id->name);
break;
case TSE_EBONE:
{
@@ -1318,7 +1320,16 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
case ID_GR:
tselem_draw_icon_uibut(&arg, ICON_GROUP); break;
case ID_LI:
- tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break;
+ if (tselem->id->tag & LIB_TAG_MISSING) {
+ tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN);
+ }
+ else if (((Library *)tselem->id)->parent) {
+ tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT);
+ }
+ else {
+ tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT);
+ }
+ break;
case ID_LS:
tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
case ID_GD:
@@ -1553,10 +1564,15 @@ static void outliner_draw_tree_element(
if (tselem->type == 0 && tselem->id->lib) {
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
- if (tselem->id->flag & LIB_INDIRECT)
+ if (tselem->id->tag & LIB_TAG_MISSING) {
+ UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
+ }
+ else if (tselem->id->tag & LIB_TAG_INDIRECT) {
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT);
- else
+ }
+ else {
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
+ }
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
offsx += UI_UNIT_X;
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 6d420674f3e..222fe27983c 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -230,7 +230,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
}
void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ARegion *ar = CTX_wm_region(C);
ReportList *reports = CTX_wm_reports(C); // XXX
@@ -290,6 +290,104 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
+/* Library delete --------------------------------------------------- */
+
+static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
+{
+ Library *lib = (Library *)tselem->id;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ BLI_assert(te->idcode == ID_LI && lib != NULL);
+ UNUSED_VARS_NDEBUG(te);
+
+ /* We simply set all ID from given lib (including lib itself) to zero user count.
+ * It is not possible to do a proper cleanup without a save/reload in current master. */
+ a = set_listbasepointers(CTX_data_main(C), lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->lib == lib) {
+ id_fake_user_clear(id);
+ id->us = 0;
+ }
+ }
+ }
+
+ BKE_reportf(reports, RPT_WARNING,
+ "Please save and reload .blend file to complete deletion of '%s' library",
+ ((Library *)tselem->id)->filepath);
+}
+
+void lib_delete_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *te,
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
+{
+ lib_delete(C, te, tselem, CTX_wm_reports(C));
+}
+
+static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2])
+{
+ if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (te->idcode == ID_LI && tselem->id) {
+ if (((Library *)tselem->id)->parent) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT,
+ "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath);
+ return OPERATOR_CANCELLED;
+ }
+
+ lib_delete(C, te, tselem, reports);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ for (te = te->subtree.first; te; te = te->next) {
+ int ret;
+ if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) {
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ TreeElement *te;
+ float fmval[2];
+
+ BLI_assert(ar && soops);
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ for (te = soops->tree.first; te; te = te->next) {
+ int ret;
+
+ if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) {
+ return ret;
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_lib_delete(wmOperatorType *ot)
+{
+ ot->name = "Delete Library";
+ ot->idname = "OUTLINER_OT_lib_delete";
+ ot->description = "Delete the library under cursor (needs a save/reload)";
+
+ ot->invoke = outliner_lib_delete_invoke;
+ ot->poll = ED_operator_outliner_active;
+}
+
/* ************************************************************** */
/* Setting Toggling Operators */
@@ -370,7 +468,7 @@ int common_restrict_check(bContext *C, Object *ob)
/* Toggle Visibility ---------------------------------------- */
void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *ob = (Object *)tselem->id;
@@ -386,7 +484,7 @@ void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
}
void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW);
@@ -425,7 +523,7 @@ void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
/* Toggle Selectability ---------------------------------------- */
void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -436,7 +534,7 @@ void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme
}
void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT);
@@ -473,7 +571,7 @@ void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
/* Toggle Renderability ---------------------------------------- */
void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -484,7 +582,7 @@ void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme
}
void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER);
@@ -712,6 +810,8 @@ static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
void OUTLINER_OT_scroll_page(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Scroll Page";
ot->idname = "OUTLINER_OT_scroll_page";
@@ -722,7 +822,8 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* properties */
- RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page");
+ prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* Search ------------------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index c89a1bb1b9f..5db4897b36d 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -60,7 +60,7 @@ typedef struct TreeElement {
#define TREESTORE_ID_TYPE(_id) \
(ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
- ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF)) /* Only in 'blendfile' mode ... :/ */
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO)) /* Only in 'blendfile' mode ... :/ */
/* TreeElement->flag */
#define TE_ACTIVE 1
@@ -150,24 +150,35 @@ int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, boo
/* outliner_edit.c ---------------------------------------------- */
-void outliner_do_object_operation(struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
- void (*operation_cb)(struct bContext *C, struct Scene *scene, struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *));
+void outliner_do_object_operation_ex(
+ struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ void (*operation_cb)(struct bContext *C, struct Scene *scene,
+ struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *),
+ bool recurse_selected);
+void outliner_do_object_operation(
+ struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb,
+ void (*operation_cb)(struct bContext *C, struct Scene *scene,
+ struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *));
int common_restrict_check(struct bContext *C, struct Object *ob);
int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel);
void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set);
-void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
+void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
+void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
-void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
+void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
+
+void lib_delete_cb(
+ struct bContext *C, struct Scene *scene, struct TreeElement *te,
+ struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data);
TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
/* ...................................................... */
@@ -176,6 +187,8 @@ void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
void OUTLINER_OT_item_openclose(struct wmOperatorType *ot);
void OUTLINER_OT_item_rename(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_delete(struct wmOperatorType *ot);
+
void OUTLINER_OT_show_one_level(struct wmOperatorType *ot);
void OUTLINER_OT_show_active(struct wmOperatorType *ot);
void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot);
@@ -211,6 +224,7 @@ void OUTLINER_OT_operation(struct wmOperatorType *ot);
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_lib_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 839d44df25d..720cfe12567 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -47,10 +47,12 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_select_border);
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
+ WM_operatortype_append(OUTLINER_OT_lib_delete);
WM_operatortype_append(OUTLINER_OT_operation);
WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_group_operation);
+ WM_operatortype_append(OUTLINER_OT_lib_operation);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
@@ -124,7 +126,8 @@ void outliner_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PERIODKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PADPERIOD, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEDOWNKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEDOWNKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "up", false);
kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEUPKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "up", true);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index e52c68b57e9..84f8c629c5d 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -315,7 +315,7 @@ static eOLDrawState tree_element_active_texture(
/*tselem = TREESTORE(te);*/ /*UNUSED*/
- /* find buttons area (note, this is undefined really still, needs recode in blender) */
+ /* find buttons region (note, this is undefined really still, needs recode in blender) */
/* XXX removed finding sbuts */
/* where is texture linked to? */
@@ -555,10 +555,9 @@ static eOLDrawState tree_element_active_bone(
if (ob) {
if (set != OL_SETSEL_EXTEND) {
/* single select forces all other bones to get unselected */
- Bone *bone;
- for (bone = arm->bonebase.first; bone != NULL; bone = bone->next) {
- bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- do_outliner_bone_select_recursive(arm, bone, false);
+ for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL; bone_iter = bone_iter->next) {
+ bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ do_outliner_bone_select_recursive(arm, bone_iter, false);
}
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 50171d7f032..83677b6bd86 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -119,6 +119,7 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
case ID_MA: case ID_TE: case ID_IP: case ID_IM:
case ID_SO: case ID_KE: case ID_WO: case ID_AC:
case ID_NLA: case ID_TXT: case ID_GR: case ID_LS:
+ case ID_LI:
if (*idlevel == 0) *idlevel = idcode;
else if (*idlevel != idcode) *idlevel = -1;
break;
@@ -133,14 +134,14 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb,
}
static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem))
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* just set action to NULL */
BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL);
}
static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem))
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
Material **matar = NULL;
int a, totcol = 0;
@@ -172,7 +173,7 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl
if (LIKELY(matar != NULL)) {
for (a = 0; a < totcol; a++) {
if (a == te->index && matar[a]) {
- matar[a]->id.us--;
+ id_us_min(&matar[a]->id);
matar[a] = NULL;
}
}
@@ -180,7 +181,7 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl
}
static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te,
- TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem))
+ TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
MTex **mtex = NULL;
int a;
@@ -208,15 +209,16 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle
for (a = 0; a < MAX_MTEX; a++) {
if (a == te->index && mtex[a]) {
if (mtex[a]->tex) {
- mtex[a]->tex->id.us--;
+ id_us_min(&mtex[a]->tex->id);
mtex[a]->tex = NULL;
}
}
}
}
-static void unlink_group_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem)
+static void unlink_group_cb(
+ bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -227,12 +229,13 @@ static void unlink_group_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme
}
}
else {
- BKE_group_unlink(group);
+ Main *bmain = CTX_data_main(C);
+ BKE_group_unlink(bmain, group);
}
}
static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem)
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
Scene *parscene = (Scene *)tsep->id;
World *wo = (World *)tselem->id;
@@ -242,9 +245,10 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme
parscene->world = NULL;
}
-static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
- TreeStoreElem *, TreeStoreElem *))
+static void outliner_do_libdata_operation(
+ bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb,
+ void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *),
+ void *user_data)
{
TreeElement *te;
TreeStoreElem *tselem;
@@ -254,11 +258,11 @@ static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == 0) {
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
- operation_cb(C, scene, te, tsep, tselem);
+ operation_cb(C, scene, te, tsep, tselem, user_data);
}
}
if (TSELEM_OPEN(tselem, soops)) {
- outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb);
+ outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb, user_data);
}
}
}
@@ -349,7 +353,7 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
/* ******************************************** */
static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -361,7 +365,7 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
}
static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem))
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data))
{
/* From where do i get the x,y coordinate of the mouse event ? */
wmWindow *win = CTX_wm_window(C);
@@ -372,7 +376,7 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeEl
static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -384,7 +388,7 @@ static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *t
}
static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
@@ -396,15 +400,18 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te,
ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ /* leave for ED_outliner_id_unref to handle */
+#if 0
te->directdata = NULL;
tselem->id = NULL;
+#endif
}
}
static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- if (tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) {
+ if (tselem->id->lib && (tselem->id->tag & LIB_TAG_EXTERN)) {
/* if the ID type has no special local function,
* just clear the lib */
if (id_make_local(tselem->id, false) == false) {
@@ -415,29 +422,23 @@ static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(t
}
static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
- if ((id) && ((id->flag & LIB_FAKEUSER) == 0)) {
- id->flag |= LIB_FAKEUSER;
- id_us_plus(id);
- }
+ id_fake_user_set(id);
}
static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
- if ((id) && (id->flag & LIB_FAKEUSER)) {
- id->flag &= ~LIB_FAKEUSER;
- id_us_min(id);
- }
+ id_fake_user_clear(id);
}
static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -445,7 +446,7 @@ static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *
}
static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem)
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -462,7 +463,7 @@ static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement
}
static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te),
- TreeStoreElem *tsep, TreeStoreElem *tselem)
+ TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data))
{
ID *id = tselem->id;
@@ -480,7 +481,7 @@ static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *
}
static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
GroupObject *gob;
@@ -506,7 +507,7 @@ static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElemen
}
static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Group *group = (Group *)tselem->id;
@@ -516,15 +517,20 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
id_lib_extern(&group->id);
}
-void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
- void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
- TreeStoreElem *, TreeStoreElem *))
+/**
+ * \param select_recurse: Set to false for operations which are already recursively operating on their children.
+ */
+void outliner_do_object_operation_ex(
+ bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ void (*operation_cb)(bContext *C, Scene *scene, TreeElement *,
+ TreeStoreElem *, TreeStoreElem *, void *),
+ bool select_recurse)
{
TreeElement *te;
- TreeStoreElem *tselem;
for (te = lb->first; te; te = te->next) {
- tselem = TREESTORE(te);
+ TreeStoreElem *tselem = TREESTORE(te);
+ bool select_handled = false;
if (tselem->flag & TSE_SELECTED) {
if (tselem->type == 0 && te->idcode == ID_OB) {
// when objects selected in other scenes... dunno if that should be allowed
@@ -535,15 +541,25 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
/* important to use 'scene_owner' not scene_act else deleting objects can crash.
* only use 'scene_act' when 'scene_owner' is NULL, which can happen when the
* outliner isn't showing scenes: Visible Layer draw mode for eg. */
- operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem);
+ operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL);
+ select_handled = true;
}
}
if (TSELEM_OPEN(tselem, soops)) {
- outliner_do_object_operation(C, scene_act, soops, &te->subtree, operation_cb);
+ if ((select_handled == false) || select_recurse) {
+ outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse);
+ }
}
}
}
+void outliner_do_object_operation(
+ bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb,
+ void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *))
+{
+ outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true);
+}
+
/* ******************************************** */
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
@@ -782,7 +798,7 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
Object *parent;
if (!base) {
- return NULL;
+ return NULL;
}
for (child_base = scene->base.first; child_base; child_base = base_next) {
@@ -799,7 +815,7 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
}
static void object_delete_hierarchy_cb(
- bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+ bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
Base *base = (Base *)te->directdata;
Object *obedit = scene->obedit;
@@ -815,8 +831,11 @@ static void object_delete_hierarchy_cb(
}
outline_delete_hierarchy(C, scene, base);
+ /* leave for ED_outliner_id_unref to handle */
+#if 0
te->directdata = NULL;
tselem->id = NULL;
+#endif
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -834,7 +853,7 @@ enum {
OL_OP_TOGVIS,
OL_OP_TOGSEL,
OL_OP_TOGREN,
- OL_OP_RENAME
+ OL_OP_RENAME,
};
static EnumPropertyItem prop_object_op_types[] = {
@@ -876,7 +895,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_hierarchy_cb);
+ outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false);
if (scene != sce) {
ED_screen_set_scene(C, CTX_wm_screen(C), sce);
}
@@ -903,7 +922,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
else if (event == OL_OP_DELETE_HIERARCHY) {
- outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb);
+ outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false);
/* XXX: See OL_OP_DELETE comment above. */
outliner_cleanup_tree(soops);
@@ -1002,28 +1021,28 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_GROUPOP_UNLINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb, NULL);
break;
case OL_GROUPOP_LOCAL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
break;
case OL_GROUPOP_LINK:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL);
break;
case OL_GROUPOP_INSTANCE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL);
break;
case OL_GROUPOP_TOGVIS:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL);
break;
case OL_GROUPOP_TOGSEL:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL);
break;
case OL_GROUPOP_TOGREN:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL);
break;
case OL_GROUPOP_RENAME:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
break;
default:
BLI_assert(0);
@@ -1108,25 +1127,25 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* unlink datablock from its parent */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Unlink action");
break;
case ID_MA:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink material");
break;
case ID_TE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL);
ED_undo_push(C, "Unlink texture");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Unlink world");
@@ -1140,7 +1159,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_LOCAL:
{
/* make local */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL);
ED_undo_push(C, "Localized Data");
break;
}
@@ -1149,14 +1168,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
/* make single user */
switch (idlevel) {
case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
ED_undo_push(C, "Single-User Action");
break;
case ID_WO:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb, NULL);
WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL);
ED_undo_push(C, "Single-User World");
@@ -1171,7 +1190,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_FAKE_ADD:
{
/* set fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Add Fake User");
@@ -1180,7 +1199,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_FAKE_CLEAR:
{
/* clear fake user */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Clear Fake User");
@@ -1189,14 +1208,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_RENAME:
{
/* rename */
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
ED_undo_push(C, "Rename");
break;
}
case OUTLINER_IDOP_SELECT_LINKED:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb);
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb, NULL);
ED_undo_push(C, "Select");
break;
@@ -1234,6 +1253,88 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
/* **************************************** */
+typedef enum eOutlinerLibOpTypes {
+ OL_LIB_INVALID = 0,
+
+ OL_LIB_RENAME,
+ OL_LIB_DELETE,
+} eOutlinerLibOpTypes;
+
+static EnumPropertyItem outliner_lib_op_type_items[] = {
+ {OL_LIB_RENAME, "RENAME", 0, "Rename", ""},
+ {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"},
+ {0, NULL, 0, NULL, NULL}
+
+};
+
+static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+ eOutlinerIdOpTypes event;
+
+ /* check for invalid states */
+ if (soops == NULL)
+ return OPERATOR_CANCELLED;
+
+ set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ event = RNA_enum_get(op->ptr, "type");
+
+ switch (event) {
+ case OL_LIB_RENAME:
+ {
+ /* rename */
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL);
+
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ ED_undo_push(C, "Rename");
+ break;
+ }
+ case OL_LIB_DELETE:
+ {
+ /* delete */
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL);
+
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+ /* Note: no undo possible here really, not 100% sure why...
+ * Probably because of library optimizations in undo/redo process? */
+ /* ED_undo_push(C, "Rename"); */
+ break;
+ }
+ default:
+ /* invalid - unhandled */
+ break;
+ }
+
+ /* wrong notifier still... */
+ WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
+
+ /* XXX: this is just so that outliner is always up to date */
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void OUTLINER_OT_lib_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Library Operation";
+ ot->idname = "OUTLINER_OT_lib_operation";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_lib_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
+}
+
+/* **************************************** */
+
static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid,
void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *))
{
@@ -1691,10 +1792,17 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
BKE_report(reports, RPT_WARNING, "Mixed selection");
}
else {
- if (idlevel == ID_GR)
- WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
- else
- WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ switch (idlevel) {
+ case ID_GR:
+ WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ case ID_LI:
+ WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ default:
+ WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ break;
+ }
}
}
else if (datalevel) {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index aaca61ed5cf..d688e628967 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -392,7 +392,7 @@ static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce,
for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
FreestyleLineStyle *linestyle = lineset->linestyle;
if (linestyle) {
- linestyle->id.flag |= LIB_DOIT;
+ linestyle->id.tag |= LIB_TAG_DOIT;
}
}
}
@@ -400,9 +400,9 @@ static void outliner_add_line_styles(SpaceOops *soops, ListBase *lb, Scene *sce,
for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
FreestyleLineStyle *linestyle = lineset->linestyle;
if (linestyle) {
- if (!(linestyle->id.flag & LIB_DOIT))
+ if (!(linestyle->id.tag & LIB_TAG_DOIT))
continue;
- linestyle->id.flag &= ~LIB_DOIT;
+ linestyle->id.tag &= ~LIB_TAG_DOIT;
outliner_add_element(soops, lb, linestyle, te, 0, 0);
}
}
@@ -447,8 +447,6 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
// can be inlined if necessary
static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob)
{
- int a = 0;
-
if (outliner_animdata_test(ob->adt))
outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0);
@@ -464,13 +462,13 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
if (ob->pose) {
bArmature *arm = ob->data;
bPoseChannel *pchan;
- TreeElement *ten;
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
tenla->name = IFACE_("Pose");
/* channels undefined in editmode, but we want the 'tenla' pose icon itself */
if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) {
+ TreeElement *ten;
int a = 0, const_index = 1000; /* ensure unique id for bone constraints */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) {
@@ -522,21 +520,22 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
/* Pose Groups */
if (ob->pose->agroups.first) {
bActionGroup *agrp;
- TreeElement *ten;
- TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
+ TreeElement *ten_bonegrp = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0);
int a = 0;
-
- tenla->name = IFACE_("Bone Groups");
+
+ ten_bonegrp->name = IFACE_("Bone Groups");
for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) {
- ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSEGRP, a);
+ TreeElement *ten;
+ ten = outliner_add_element(soops, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a);
ten->name = agrp->name;
ten->directdata = agrp;
}
}
}
- for (a = 0; a < ob->totcol; a++)
+ for (int a = 0; a < ob->totcol; a++) {
outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
+ }
if (ob->constraints.first) {
//Object *target;
@@ -544,6 +543,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
TreeElement *ten;
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
//char *str;
+ int a;
tenla->name = IFACE_("Constraints");
for (con = ob->constraints.first, a = 0; con; con = con->next, a++) {
@@ -562,34 +562,34 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
if (ob->modifiers.first) {
ModifierData *md;
- TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
+ TreeElement *ten_mod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
int index;
- temod->name = IFACE_("Modifiers");
+ ten_mod->name = IFACE_("Modifiers");
for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) {
- TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
- te->name = md->name;
- te->directdata = md;
+ TreeElement *ten = outliner_add_element(soops, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
+ ten->name = md->name;
+ ten->directdata = md;
if (md->type == eModifierType_Lattice) {
- outliner_add_element(soops, &te->subtree, ((LatticeModifierData *) md)->object, te, TSE_LINKED_OB, 0);
+ outliner_add_element(soops, &ten->subtree, ((LatticeModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
}
else if (md->type == eModifierType_Curve) {
- outliner_add_element(soops, &te->subtree, ((CurveModifierData *) md)->object, te, TSE_LINKED_OB, 0);
+ outliner_add_element(soops, &ten->subtree, ((CurveModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
}
else if (md->type == eModifierType_Armature) {
- outliner_add_element(soops, &te->subtree, ((ArmatureModifierData *) md)->object, te, TSE_LINKED_OB, 0);
+ outliner_add_element(soops, &ten->subtree, ((ArmatureModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
}
else if (md->type == eModifierType_Hook) {
- outliner_add_element(soops, &te->subtree, ((HookModifierData *) md)->object, te, TSE_LINKED_OB, 0);
+ outliner_add_element(soops, &ten->subtree, ((HookModifierData *) md)->object, ten, TSE_LINKED_OB, 0);
}
else if (md->type == eModifierType_ParticleSystem) {
- TreeElement *ten;
ParticleSystem *psys = ((ParticleSystemModifierData *) md)->psys;
+ TreeElement *ten_psys;
- ten = outliner_add_element(soops, &te->subtree, ob, te, TSE_LINKED_PSYS, 0);
- ten->directdata = psys;
- ten->name = psys->part->id.name + 2;
+ ten_psys = outliner_add_element(soops, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0);
+ ten_psys->directdata = psys;
+ ten_psys->name = psys->part->id.name + 2;
}
}
}
@@ -599,6 +599,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
bDeformGroup *defgroup;
TreeElement *ten;
TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
+ int a;
tenla->name = IFACE_("Vertex Groups");
for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) {
@@ -1571,7 +1572,6 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
{
Base *base;
- Object *ob;
TreeElement *te = NULL, *ten;
TreeStoreElem *tselem;
int show_opened = !soops->treestore || !BLI_mempool_count(soops->treestore); /* on first view, we open scenes */
@@ -1596,7 +1596,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
outliner_storage_cleanup(soops);
/* clear ob id.new flags */
- for (ob = mainvar->object.first; ob; ob = ob->id.next) ob->id.newid = NULL;
+ for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) {
+ ob->id.newid = NULL;
+ }
/* options */
if (soops->outlinevis == SO_LIBRARIES) {
@@ -1628,7 +1630,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
lib = (Library *)tselem->id;
if (lib && lib->parent) {
par = (TreeElement *)lib->parent->id.newid;
- if (tselem->id->flag & LIB_INDIRECT) {
+ if (tselem->id->tag & LIB_TAG_INDIRECT) {
/* Only remove from 'first level' if lib is not also directly used. */
BLI_remlink(&soops->tree, ten);
BLI_addtail(&par->subtree, ten);
@@ -1715,7 +1717,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
else if (soops->outlinevis == SO_SELECTED) {
for (base = scene->base.first; base; base = base->next) {
if (base->lay & scene->lay) {
- if (base == BASACT || (base->flag & SELECT)) {
+ if (base->flag & SELECT) {
ten = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
ten->directdata = base;
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 7b1ec174a6b..1dd66366e5d 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -62,7 +62,7 @@
#include "outliner_intern.h"
-static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void outliner_main_region_init(wmWindowManager *wm, ARegion *ar)
{
ListBase *lb;
wmKeyMap *keymap;
@@ -266,7 +266,7 @@ static void outliner_dropboxes(void)
WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy);
}
-static void outliner_main_area_draw(const bContext *C, ARegion *ar)
+static void outliner_main_region_draw(const bContext *C, ARegion *ar)
{
View2D *v2d = &ar->v2d;
View2DScrollers *scrollers;
@@ -287,12 +287,12 @@ static void outliner_main_area_draw(const bContext *C, ARegion *ar)
}
-static void outliner_main_area_free(ARegion *UNUSED(ar))
+static void outliner_main_region_free(ARegion *UNUSED(ar))
{
}
-static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -399,21 +399,21 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
/* ************************ header outliner area region *********************** */
/* add handlers, stuff you only do once or on area/region changes */
-static void outliner_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void outliner_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void outliner_header_area_draw(const bContext *C, ARegion *ar)
+static void outliner_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void outliner_header_area_free(ARegion *UNUSED(ar))
+static void outliner_header_region_free(ARegion *UNUSED(ar))
{
}
-static void outliner_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void outliner_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -445,8 +445,8 @@ static SpaceLink *outliner_new(const bContext *UNUSED(C))
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for outliner");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for outliner");
BLI_addtail(&soutliner->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -508,10 +508,10 @@ void ED_spacetype_outliner(void)
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
- art->init = outliner_main_area_init;
- art->draw = outliner_main_area_draw;
- art->free = outliner_main_area_free;
- art->listener = outliner_main_area_listener;
+ art->init = outliner_main_region_init;
+ art->draw = outliner_main_region_draw;
+ art->free = outliner_main_region_free;
+ art->listener = outliner_main_region_listener;
BLI_addhead(&st->regiontypes, art);
/* regions: header */
@@ -520,10 +520,10 @@ void ED_spacetype_outliner(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = outliner_header_area_init;
- art->draw = outliner_header_area_draw;
- art->free = outliner_header_area_free;
- art->listener = outliner_header_area_listener;
+ art->init = outliner_header_region_init;
+ art->draw = outliner_header_region_draw;
+ art->free = outliner_header_region_free;
+ art->listener = outliner_header_region_listener;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_script/SConscript b/source/blender/editors/space_script/SConscript
deleted file mode 100644
index c03a61ec197..00000000000
--- a/source/blender/editors/space_script/SConscript
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../python',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-env.BlenderLib ( 'bf_editors_space_script', sources, incs, defs, libtype=['core'], priority=[90] )
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index d265ae62db6..6bfb51d07c6 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -59,7 +59,7 @@ static int run_pyfile_exec(bContext *C, wmOperator *op)
char path[512];
RNA_string_get(op->ptr, "filepath", path);
#ifdef WITH_PYTHON
- if (BPY_filepath_exec(C, path, op->reports)) {
+ if (BPY_execute_filepath(C, path, op->reports)) {
ARegion *ar = CTX_wm_region(C);
ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
@@ -125,7 +125,7 @@ static int script_reload_exec(bContext *C, wmOperator *op)
/* TODO, this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode */
WM_cursor_wait(1);
- BPY_string_exec(C, "__import__('bpy').utils.load_scripts(reload_scripts=True)");
+ BPY_execute_string(C, "__import__('bpy').utils.load_scripts(reload_scripts=True)");
WM_cursor_wait(0);
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index 759dcd3d0a4..4228635ccd6 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -78,8 +78,8 @@ static SpaceLink *script_new(const bContext *UNUSED(C))
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for script");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for script");
BLI_addtail(&sscript->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -125,7 +125,7 @@ static SpaceLink *script_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
-static void script_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void script_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -136,7 +136,7 @@ static void script_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void script_main_area_draw(const bContext *C, ARegion *ar)
+static void script_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceScript *sscript = (SpaceScript *)CTX_wm_space_data(C);
@@ -166,17 +166,17 @@ static void script_main_area_draw(const bContext *C, ARegion *ar)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void script_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void script_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void script_header_area_draw(const bContext *C, ARegion *ar)
+static void script_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void script_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void script_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
/* context changes */
// XXX - Todo, need the ScriptSpace accessible to get the python script to run.
@@ -202,9 +202,9 @@ void ED_spacetype_script(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype script region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = script_main_area_init;
- art->draw = script_main_area_draw;
- art->listener = script_main_area_listener;
+ art->init = script_main_region_init;
+ art->draw = script_main_region_draw;
+ art->listener = script_main_region_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_UI | ED_KEYMAP_FRAMES; // XXX need to further test this ED_KEYMAP_UI is needed for button interaction
BLI_addhead(&st->regiontypes, art);
@@ -215,8 +215,8 @@ void ED_spacetype_script(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
- art->init = script_header_area_init;
- art->draw = script_header_area_draw;
+ art->init = script_header_region_init;
+ art->draw = script_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_sequencer/SConscript b/source/blender/editors/space_sequencer/SConscript
deleted file mode 100644
index 9c654d7a1e5..00000000000
--- a/source/blender/editors/space_sequencer/SConscript
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs.append(env['BF_AUDASPACE_C_INC'])
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_space_sequencer', sources, incs, defs, libtype=['core'], priority=[100])
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ce03c24e2ab..c11a4d2e5a3 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -44,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_movieclip.h"
@@ -206,8 +207,14 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, wmOperator *op)
if ((prop = RNA_struct_find_property(op->ptr, "cache")) && RNA_property_boolean_get(op->ptr, prop))
seq_load->flag |= SEQ_LOAD_SOUND_CACHE;
+ if ((prop = RNA_struct_find_property(op->ptr, "mono")) && RNA_property_boolean_get(op->ptr, prop))
+ seq_load->flag |= SEQ_LOAD_SOUND_MONO;
+
if ((prop = RNA_struct_find_property(op->ptr, "sound")) && RNA_property_boolean_get(op->ptr, prop))
seq_load->flag |= SEQ_LOAD_MOVIE_SOUND;
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_framerate")) && RNA_property_boolean_get(op->ptr, prop))
+ seq_load->flag |= SEQ_LOAD_SYNC_FPS;
/* always use this for ops */
seq_load->flag |= SEQ_LOAD_FRAME_ADVANCE;
@@ -385,8 +392,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
- if (seq->clip->id.us == 0)
- seq->clip->id.us = 1;
+ id_us_ensure_real(&seq->clip->id);
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
@@ -470,8 +476,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
- if (seq->mask->id.us == 0)
- seq->mask->id.us = 1;
+ id_us_ensure_real(&seq->mask->id);
/* basic defaults */
seq->strip = strip = MEM_callocN(sizeof(Strip), "strip");
@@ -636,6 +641,20 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const w
{
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ /* only enable "use_framerate" if there aren't any existing strips
+ * - When there are no strips yet, there is no harm in enabling this,
+ * and it makes the single-strip case really nice for casual users
+ * - When there are strips, it's best we don't touch the framerate,
+ * as all hell may break loose (e.g. audio strips start overlapping
+ * and can't be restored)
+ * - These initial guesses can still be manually overridden by users
+ * from the modal options panel
+ */
+ if (ed && ed->seqbasep && ed->seqbasep->first) {
+ RNA_boolean_set(op->ptr, "use_framerate", false);
+ }
/* This is for drag and drop */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
@@ -697,10 +716,12 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie");
+ RNA_def_boolean(ot->srna, "use_framerate", true, "Use Movie Framerate", "Use framerate from the movie to keep sound and video in sync");
}
/* add sound operator */
@@ -746,10 +767,12 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
RNA_def_boolean(ot->srna, "cache", false, "Cache", "Cache the sound in memory");
+ RNA_def_boolean(ot->srna, "mono", false, "Mono", "Merge all the sound's channels into one");
}
int sequencer_image_seq_get_minmax_frame(wmOperator *op, int sfra, int *r_minframe, int *r_numdigits)
@@ -932,8 +955,9 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
@@ -1082,8 +1106,9 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, 0, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type");
RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color",
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index afa59876647..9c2d115108d 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -58,6 +58,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_basic_shader.h"
+
#include "ED_anim_api.h"
#include "ED_gpencil.h"
#include "ED_markers.h"
@@ -177,7 +179,11 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
blendcol[0] = blendcol[1] = blendcol[2] = 128;
if (seq->flag & SEQ_MUTE) UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5, 20);
break;
-
+
+ case SEQ_TYPE_TEXT:
+ UI_GetThemeColor3ubv(TH_SEQ_TEXT, col);
+ break;
+
default:
col[0] = 10; col[1] = 255; col[2] = 40;
break;
@@ -191,14 +197,14 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
* x2 the end x value, same for y1 and y2
* stepsize is width of a pixel.
*/
- if ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM)) {
+ if (seq->sound && ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) {
int i, j, pos;
int length = floor((x2 - x1) / stepsize) + 1;
float ymid = (y1 + y2) / 2;
float yscale = (y2 - y1) / 2;
float samplestep;
float startsample, endsample;
- float value;
+ float value1, value2;
bSound *sound = seq->sound;
SoundWaveform *waveform;
@@ -209,10 +215,10 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
}
BLI_spin_lock(sound->spinlock);
- if (!seq->sound->waveform) {
+ if (!sound->waveform) {
if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) {
/* prevent sounds from reloading */
- seq->sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING;
+ sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING;
BLI_spin_unlock(sound->spinlock);
sequencer_preview_add_sound(C, seq);
}
@@ -223,7 +229,7 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
}
BLI_spin_unlock(sound->spinlock);
- waveform = seq->sound->waveform;
+ waveform = sound->waveform;
if (waveform->length == 0) {
/* BKE_sound_read_waveform() set an empty SoundWaveform data in case it cannot generate a valid one...
@@ -238,49 +244,51 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
if (length > floor((waveform->length - startsample) / samplestep))
length = floor((waveform->length - startsample) / samplestep);
- glBegin(GL_LINE_STRIP);
+ glColor4f(1.0f, 1.0f, 1.0f, 0.5);
+ glEnable(GL_BLEND);
+ glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i < length; i++) {
- pos = startsample + i * samplestep;
-
- value = waveform->data[pos * 3];
+ float sampleoffset = startsample + i * samplestep;
+ pos = sampleoffset;
- for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) {
- if (value > waveform->data[j * 3])
- value = waveform->data[j * 3];
- }
+ value1 = waveform->data[pos * 3];
+ value2 = waveform->data[pos * 3 + 1];
- glVertex2f(x1 + i * stepsize, ymid + value * yscale);
- }
- glEnd();
+ if (samplestep > 1.0f) {
+ for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) {
+ if (value1 > waveform->data[j * 3])
+ value1 = waveform->data[j * 3];
- glBegin(GL_LINE_STRIP);
- for (i = 0; i < length; i++) {
- pos = startsample + i * samplestep;
-
- value = waveform->data[pos * 3 + 1];
-
- for (j = pos + 1; (j < waveform->length) && (j < pos + samplestep); j++) {
- if (value < waveform->data[j * 3 + 1])
- value = waveform->data[j * 3 + 1];
+ if (value2 < waveform->data[j * 3 + 1])
+ value2 = waveform->data[j * 3 + 1];
+ }
+ }
+ else {
+ /* use simple linear interpolation */
+ float f = sampleoffset - pos;
+ value1 = (1.0f - f) * value1 + f * waveform->data[pos * 3 + 3];
+ value2 = (1.0f - f) * value2 + f * waveform->data[pos * 3 + 4];
}
- glVertex2f(x1 + i * stepsize, ymid + value * yscale);
+ glVertex2f(x1 + i * stepsize, ymid + value1 * yscale);
+ glVertex2f(x1 + i * stepsize, ymid + value2 * yscale);
}
glEnd();
+ glDisable(GL_BLEND);
}
}
static void drawmeta_stipple(int value)
{
if (value) {
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_halftone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_HALFTONE);
glEnable(GL_LINE_STIPPLE);
glLineStipple(1, 0x8888);
}
else {
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glDisable(GL_LINE_STIPPLE);
}
}
@@ -299,6 +307,20 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
int chan_range = 0;
float draw_range = y2 - y1;
float draw_height;
+ ListBase *seqbase;
+ int offset;
+
+ seqbase = BKE_sequence_seqbase_get(seqm, &offset);
+ if (!seqbase || BLI_listbase_is_empty(seqbase)) {
+ return;
+ }
+
+ if (seqm->type == SEQ_TYPE_SCENE) {
+ offset = seqm->start - offset;
+ }
+ else {
+ offset = 0;
+ }
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -306,7 +328,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
if (seqm->flag & SEQ_MUTE)
drawmeta_stipple(1);
- for (seq = seqm->seqbase.first; seq; seq = seq->next) {
+ for (seq = seqbase->first; seq; seq = seq->next) {
chan_min = min_ii(chan_min, seq->machine);
chan_max = max_ii(chan_max, seq->machine);
}
@@ -316,11 +338,14 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
col[3] = 196; /* alpha, used for all meta children */
- for (seq = seqm->seqbase.first; seq; seq = seq->next) {
- if ((seq->startdisp > x2 || seq->enddisp < x1) == 0) {
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ const int startdisp = seq->startdisp + offset;
+ const int enddisp = seq->enddisp + offset;
+
+ if ((startdisp > x2 || enddisp < x1) == 0) {
float y_chan = (seq->machine - chan_min) / (float)(chan_range) * draw_range;
- float x1_chan = seq->startdisp;
- float x2_chan = seq->enddisp;
+ float x1_chan = startdisp;
+ float x2_chan = enddisp;
float y1_chan, y2_chan;
if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE))
@@ -561,8 +586,8 @@ void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, f
float ymid1, ymid2;
if (seq->flag & SEQ_MUTE) {
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_halftone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_HALFTONE);
}
ymid1 = (y2 - y1) * 0.25f + y1;
@@ -609,7 +634,7 @@ void draw_shadedstrip(Sequence *seq, unsigned char col[3], float x1, float y1, f
glEnd();
if (seq->flag & SEQ_MUTE) {
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
}
@@ -776,32 +801,32 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
/* draw lock */
if (seq->flag & SEQ_LOCK) {
- glEnable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glEnable(GL_BLEND);
/* light stripes */
glColor4ub(255, 255, 255, 32);
- glPolygonStipple(stipple_diag_stripes_pos);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES);
glRectf(x1, y1, x2, y2);
/* dark stripes */
glColor4ub(0, 0, 0, 32);
- glPolygonStipple(stipple_diag_stripes_neg);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP);
glRectf(x1, y1, x2, y2);
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glDisable(GL_BLEND);
}
if (!BKE_sequence_is_valid_check(seq)) {
- glEnable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
/* panic! */
glColor4ub(255, 0, 0, 255);
- glPolygonStipple(stipple_diag_stripes_pos);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_DIAG_STRIPES);
glRectf(x1, y1, x2, y2);
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
color3ubv_from_seq(scene, seq, col);
@@ -828,7 +853,9 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg
glDisable(GL_LINE_STIPPLE);
}
- if (seq->type == SEQ_TYPE_META) {
+ if ((seq->type == SEQ_TYPE_META) ||
+ ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS)))
+ {
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
@@ -1012,6 +1039,8 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
float x2 = v2d->tot.xmax;
float y2 = v2d->tot.ymax;
+ glLineWidth(1.0f);
+
/* border */
setlinestyle(3);
@@ -1043,7 +1072,8 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
}
/* draws checkerboard background for transparent content */
-static void sequencer_draw_background(const SpaceSeq *sseq, View2D *v2d, const float viewrect[2])
+static void sequencer_draw_background(
+ const SpaceSeq *sseq, View2D *v2d, const float viewrect[2], const bool draw_overlay)
{
/* setting up the view */
UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
@@ -1052,7 +1082,7 @@ static void sequencer_draw_background(const SpaceSeq *sseq, View2D *v2d, const f
/* only draw alpha for main buffer */
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
- if (sseq->flag & SEQ_USE_ALPHA) {
+ if ((sseq->flag & SEQ_USE_ALPHA) && !draw_overlay) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1072,7 +1102,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
float viewrect[2];
float col[3];
GLuint texid;
- GLuint last_texid;
void *display_buffer;
void *cache_handle = NULL;
const bool is_imbuf = ED_space_sequencer_check_show_imbuf(sseq);
@@ -1120,10 +1149,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
(ibuf->rect == NULL && ibuf->rect_float == NULL))
{
/* gpencil can also be drawn without a valid imbuf */
- if (draw_gpencil && is_imbuf) {
+ if ((draw_gpencil && is_imbuf) && !draw_overlay) {
sequencer_display_size(scene, sseq, viewrect);
- sequencer_draw_background(sseq, v2d, viewrect);
+ sequencer_draw_background(sseq, v2d, viewrect, false);
sequencer_draw_borders(sseq, v2d, scene);
sequencer_draw_gpencil(C);
@@ -1193,7 +1222,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
if (!draw_backdrop) {
- sequencer_draw_background(sseq, v2d, viewrect);
+ sequencer_draw_background(sseq, v2d, viewrect, draw_overlay);
}
if (scope) {
@@ -1268,11 +1297,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
}
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(1.0, 1.0, 1.0, 1.0);
- last_texid = glaGetOneInteger(GL_TEXTURE_2D);
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glGenTextures(1, (GLuint *)&texid);
glBindTexture(GL_TEXTURE_2D, texid);
@@ -1346,8 +1373,8 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
}
glEnd();
- glBindTexture(GL_TEXTURE_2D, last_texid);
- glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA)
glDisable(GL_BLEND);
glDeleteTextures(1, &texid);
@@ -1362,7 +1389,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
IMB_freeImBuf(ibuf);
if (draw_metadata) {
- ED_region_image_metadata_draw(0.0, 0.0, ibuf, v2d->tot, 1.0, 1.0);
+ ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0);
}
if (draw_backdrop) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 3cc0276104e..e3cdedf042b 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -35,7 +35,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
-#include "BLI_fileops.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_timecode.h"
@@ -44,6 +43,7 @@
#include "BLT_translation.h"
#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -61,6 +61,7 @@
/* for menu/popup icons etc etc*/
+#include "ED_anim_api.h"
#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_transform.h"
@@ -685,6 +686,14 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
/* First Strip! */
/* strips with extended stillfames before */
+ /* Precaution, needed because the length saved on-disk may not match the length saved in the blend file,
+ * or our code may have minor differences reading file length between versions.
+ * This causes hard-cut to fail, see: T47862 */
+ if (seq->type != SEQ_TYPE_META) {
+ BKE_sequence_reload_new_file(scene, seq, true);
+ BKE_sequence_calc(scene, seq);
+ }
+
if ((seq->startstill) && (cutframe < seq->start)) {
/* don't do funny things with METAs ... */
if (seq->type == SEQ_TYPE_META) {
@@ -928,37 +937,6 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
return done;
}
-static void UNUSED_FUNCTION(touch_seq_files) (Scene *scene)
-{
- Sequence *seq;
- Editing *ed = BKE_sequencer_editing_get(scene, false);
- char str[256];
-
- /* touch all strips with movies */
-
- if (ed == NULL) return;
-
- // XXX25 if (okee("Touch and print selected movies")==0) return;
-
- WM_cursor_wait(1);
-
- SEQP_BEGIN (ed, seq)
- {
- if (seq->flag & SELECT) {
- if (seq->type == SEQ_TYPE_MOVIE) {
- if (seq->strip && seq->strip->stripdata) {
- BLI_make_file_string(G.main->name, str, seq->strip->dir, seq->strip->stripdata->name);
- BLI_file_touch(seq->name);
- }
- }
-
- }
- }
- SEQ_END
-
- WM_cursor_wait(0);
-}
-
#if 0
static void set_filter_seq(Scene *scene)
{
@@ -1206,6 +1184,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
BKE_sequence_tx_set_final_right(seq, snap_frame);
}
BKE_sequence_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
+ BKE_sequence_single_fix(seq);
}
BKE_sequence_calc(scene, seq);
}
@@ -2218,7 +2197,7 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* to give to transform */
- RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+ RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/* delete operator */
@@ -2386,7 +2365,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* remove seq so overlap tests don't conflict,
* see seq_free_sequence below for the real free'ing */
BLI_remlink(ed->seqbasep, seq);
- /* if (seq->ipo) seq->ipo->id.us--; */
+ /* if (seq->ipo) id_us_min(&seq->ipo->id); */
/* XXX, remove fcurve and assign to split image strips */
start_ofs = cfra = BKE_sequence_tx_get_final_left(seq, false);
@@ -2456,7 +2435,7 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot)
/* api callbacks */
ot->exec = sequencer_separate_images_exec;
- ot->invoke = WM_operator_props_popup;
+ ot->invoke = WM_operator_props_popup_confirm;
ot->poll = sequencer_edit_poll;
/* flags */
@@ -2516,6 +2495,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
#if 1
BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]);
BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]);
+ BKE_sequence_single_fix(ms->parseq);
BKE_sequence_calc(scene, ms->parseq);
#else
if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq))
@@ -2718,6 +2698,29 @@ void SEQUENCER_OT_view_all(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
+static int sequencer_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "SEQUENCER_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = sequencer_view_frame_exec;
+ ot->poll = ED_operator_sequencer_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* view_all operator */
static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3772,6 +3775,16 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
/* important else we don't get the imbuf cache flushed */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
}
+ else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ bSound *sound = seq->sound;
+ if (sound == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+ BLI_strncpy(sound->name, filepath, sizeof(sound->name));
+ BKE_sound_load(bmain, sound);
+ }
else {
/* lame, set rna filepath */
PointerRNA seq_ptr;
@@ -3830,9 +3843,10 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
}
@@ -3858,8 +3872,9 @@ static int sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const
static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Sequence *seq = BKE_sequencer_active_get(scene);
+ Sequence *seq, *seq_next;
Editing *ed = BKE_sequencer_editing_get(scene, false);
+ ListBase text_seq = {0};
int iter = 0;
FILE *file;
char filepath[FILE_MAX];
@@ -3885,35 +3900,40 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* time to open and write! */
- file = BLI_fopen(filepath, "w");
-
SEQ_BEGIN(ed, seq)
{
if (seq->type == SEQ_TYPE_TEXT) {
- TextVars *data = seq->effectdata;
- char timecode_str[32];
- double sec;
- int frac;
- int len;
- fprintf(file, "%d\n", iter++);
- sec = FRA2TIME(seq->startdisp);
- frac = 1000 * (sec - floor(sec));
- sec = floor(sec);
- BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), 1, sec, FPS, USER_TIMECODE_SMPTE_FULL);
- len = strlen(timecode_str);
- timecode_str[len - 3] = 0;
- fprintf(file, "%s,%d", timecode_str, frac);
- sec = FRA2TIME(seq->enddisp);
- BLI_timecode_string_from_time(timecode_str, sizeof(timecode_str), 1, sec, FPS, USER_TIMECODE_SMPTE_FULL);
- len = strlen(timecode_str);
- timecode_str[len - 3] = 0;
- fprintf(file, " --> %s,%d\n", timecode_str, frac);
- fprintf(file, "%s\n\n", data->text);
+ BLI_addtail(&text_seq, MEM_dupallocN(seq));
}
}
SEQ_END
+ if (BLI_listbase_is_empty(&text_seq)) {
+ BKE_report(op->reports, RPT_ERROR, "No subtitles (text strips) to export");
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp);
+
+ /* time to open and write! */
+ file = BLI_fopen(filepath, "w");
+
+ for (seq = text_seq.first; seq; seq = seq_next) {
+ TextVars *data = seq->effectdata;
+ char timecode_str_start[32];
+ char timecode_str_end[32];
+
+ BLI_timecode_string_from_time(timecode_str_start, sizeof(timecode_str_start),
+ -2, FRA2TIME(seq->startdisp), FPS, USER_TIMECODE_SUBRIP);
+ BLI_timecode_string_from_time(timecode_str_end, sizeof(timecode_str_end),
+ -2, FRA2TIME(seq->enddisp), FPS, USER_TIMECODE_SUBRIP);
+
+ fprintf(file, "%d\n%s --> %s\n%s\n\n", iter++, timecode_str_start, timecode_str_end, data->text);
+
+ seq_next = seq->next;
+ MEM_freeN(seq);
+ }
+
fclose(file);
return OPERATOR_FINISHED;
@@ -3941,6 +3961,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 3e228fd0b31..730cc117287 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -121,6 +121,7 @@ void SEQUENCER_OT_rendersize(struct wmOperatorType *ot);
void SEQUENCER_OT_view_toggle(struct wmOperatorType *ot);
void SEQUENCER_OT_view_all(struct wmOperatorType *ot);
void SEQUENCER_OT_view_selected(struct wmOperatorType *ot);
+void SEQUENCER_OT_view_frame(struct wmOperatorType *ot);
void SEQUENCER_OT_view_zoom_ratio(struct wmOperatorType *ot);
void SEQUENCER_OT_view_ghost_border(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index fad317fdd4e..1b3d458bb69 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -96,7 +96,7 @@ void SEQUENCER_OT_strip_modifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_enum(ot->srna, "type", sequence_modifier_type_items, seqModifierType_ColorBalance, "Type", "");
+ prop = RNA_def_enum(ot->srna, "type", rna_enum_sequence_modifier_type_items, seqModifierType_ColorBalance, "Type", "");
ot->prop = prop;
}
@@ -208,12 +208,20 @@ void SEQUENCER_OT_strip_modifier_move(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", direction_items, SEQ_MODIFIER_MOVE_UP, "Type", "");
}
-static int strip_modifier_copy_exec(bContext *C, wmOperator *UNUSED(op))
+/*********************** Copy to selected operator *************************/
+
+enum {
+ SEQ_MODIFIER_COPY_REPLACE = 0,
+ SEQ_MODIFIER_COPY_APPEND = 1,
+};
+
+static int strip_modifier_copy_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = scene->ed;
Sequence *seq = BKE_sequencer_active_get(scene);
Sequence *seq_iter;
+ const int type = RNA_enum_get(op->ptr, "type");
if (!seq || !seq->modifiers.first)
return OPERATOR_CANCELLED;
@@ -224,16 +232,17 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *UNUSED(op))
if (seq_iter == seq)
continue;
- if (seq_iter->modifiers.first) {
- SequenceModifierData *smd_tmp, *smd = seq_iter->modifiers.first;
-
- while (smd) {
- smd_tmp = smd->next;
- BLI_remlink(&seq_iter->modifiers, smd);
- BKE_sequence_modifier_free(smd);
- smd = smd_tmp;
+ if (type == SEQ_MODIFIER_COPY_REPLACE) {
+ if (seq_iter->modifiers.first) {
+ SequenceModifierData *smd_tmp, *smd = seq_iter->modifiers.first;
+ while (smd) {
+ smd_tmp = smd->next;
+ BLI_remlink(&seq_iter->modifiers, smd);
+ BKE_sequence_modifier_free(smd);
+ smd = smd_tmp;
+ }
+ BLI_listbase_clear(&seq_iter->modifiers);
}
- BLI_listbase_clear(&seq_iter->modifiers);
}
BKE_sequence_modifier_list_copy(seq_iter, seq);
@@ -249,16 +258,27 @@ static int strip_modifier_copy_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_strip_modifier_copy(wmOperatorType *ot)
{
+ static EnumPropertyItem type_items[] = {
+ {SEQ_MODIFIER_COPY_REPLACE, "REPLACE", 0, "Replace",
+ "Replace modifiers in destination"},
+ {SEQ_MODIFIER_COPY_APPEND, "APPEND", 0, "Append",
+ "Append active modifiers to selected strips"},
+ {0, NULL, 0, NULL, NULL}};
+
/* identifiers */
ot->name = "Copy to Selected Strips";
ot->idname = "SEQUENCER_OT_strip_modifier_copy";
ot->description = "Copy modifiers of the active strip to all selected strips";
/* api callbacks */
+ ot->invoke = WM_menu_invoke;
ot->exec = strip_modifier_copy_exec;
ot->poll = strip_modifier_active_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, SEQ_MODIFIER_COPY_REPLACE, "Type", "");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 3d08e0c5ed8..655e029cfdd 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -84,6 +84,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_view_all);
WM_operatortype_append(SEQUENCER_OT_view_selected);
+ WM_operatortype_append(SEQUENCER_OT_view_frame);
WM_operatortype_append(SEQUENCER_OT_view_all_preview);
WM_operatortype_append(SEQUENCER_OT_view_toggle);
WM_operatortype_append(SEQUENCER_OT_view_zoom_ratio);
@@ -202,6 +203,7 @@ void sequencer_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "SEQUENCER_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "SEQUENCER_OT_view_frame", PAD0, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_strip_jump", PAGEUPKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "next", true);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 3dff2442f45..3c2a66cd3af 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -437,7 +437,10 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
select_surrounding_handles(scene, seq);
}
- else if (seq->flag & SELECT) {
+ else {
+ /* always select the strip under the cursor */
+ seq->flag |= SELECT;
+
/* First click selects adjacent handles on that side.
* Second click selects all strips in that direction.
* If there are no adjacent strips, it just selects all in that direction.
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 5b3061bd513..fce40f8ca59 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -136,9 +136,9 @@ static SpaceLink *sequencer_new(const bContext *C)
ar->alignment = RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
- /* preview area */
+ /* preview region */
/* NOTE: if you change values here, also change them in sequencer_init_preview_region */
- ar = MEM_callocN(sizeof(ARegion), "preview area for sequencer");
+ ar = MEM_callocN(sizeof(ARegion), "preview region for sequencer");
BLI_addtail(&sseq->regionbase, ar);
ar->regiontype = RGN_TYPE_PREVIEW;
ar->alignment = RGN_ALIGN_TOP;
@@ -160,8 +160,8 @@ static SpaceLink *sequencer_new(const bContext *C)
ar->v2d.keeptot = V2D_KEEPTOT_FREE;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for sequencer");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for sequencer");
BLI_addtail(&sseq->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -283,7 +283,7 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa)
/* Get available height (without DPI correction). */
const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC;
- /* We reuse hidden area's size, allows to find same layout as before if we just switch
+ /* We reuse hidden region's size, allows to find same layout as before if we just switch
* between one 'full window' view and the combined one. This gets lost if we switch to both
* 'full window' views before, though... Better than nothing. */
if (ar_main->flag & RGN_FLAG_HIDDEN) {
@@ -457,7 +457,7 @@ static int sequencer_context(const bContext *C, const char *member, bContextData
/* *********************** sequencer (main) region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void sequencer_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
ListBase *lb;
@@ -482,13 +482,13 @@ static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
+static void sequencer_main_region_draw(const bContext *C, ARegion *ar)
{
/* NLE - strip editing timeline interface */
draw_timeline_seq(C, ar);
}
-static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -528,18 +528,18 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
/* *********************** header region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void sequencer_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void sequencer_header_area_draw(const bContext *C, ARegion *ar)
+static void sequencer_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
/* *********************** preview region ************************ */
-static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar)
+static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -558,7 +558,7 @@ static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
+static void sequencer_preview_region_draw(const bContext *C, ARegion *ar)
{
ScrArea *sa = CTX_wm_area(C);
SpaceSeq *sseq = sa->spacedata.first;
@@ -594,7 +594,7 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar)
}
}
-static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -645,7 +645,7 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
/* *********************** buttons region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -655,12 +655,12 @@ static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar)
ED_region_panels_init(wm, ar);
}
-static void sequencer_buttons_area_draw(const bContext *C, ARegion *ar)
+static void sequencer_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
-static void sequencer_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -712,9 +712,9 @@ void ED_spacetype_sequencer(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = sequencer_main_area_init;
- art->draw = sequencer_main_area_draw;
- art->listener = sequencer_main_area_listener;
+ art->init = sequencer_main_region_init;
+ art->draw = sequencer_main_region_draw;
+ art->listener = sequencer_main_region_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
BLI_addhead(&st->regiontypes, art);
@@ -722,9 +722,9 @@ void ED_spacetype_sequencer(void)
/* preview */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_PREVIEW;
- art->init = sequencer_preview_area_init;
- art->draw = sequencer_preview_area_draw;
- art->listener = sequencer_preview_area_listener;
+ art->init = sequencer_preview_region_init;
+ art->draw = sequencer_preview_region_draw;
+ art->listener = sequencer_preview_region_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
@@ -733,9 +733,9 @@ void ED_spacetype_sequencer(void)
art->regionid = RGN_TYPE_UI;
art->prefsizex = 220; // XXX
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = sequencer_buttons_area_listener;
- art->init = sequencer_buttons_area_init;
- art->draw = sequencer_buttons_area_draw;
+ art->listener = sequencer_buttons_region_listener;
+ art->init = sequencer_buttons_region_init;
+ art->draw = sequencer_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
sequencer_buttons_register(art);
@@ -746,9 +746,9 @@ void ED_spacetype_sequencer(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = sequencer_header_area_init;
- art->draw = sequencer_header_area_draw;
- art->listener = sequencer_main_area_listener;
+ art->init = sequencer_header_region_init;
+ art->draw = sequencer_header_region_draw;
+ art->listener = sequencer_main_region_listener;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_text/SConscript b/source/blender/editors/space_text/SConscript
deleted file mode 100644
index d11671fe743..00000000000
--- a/source/blender/editors/space_text/SConscript
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../python',
- '../../windowmanager',
- ]
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib('bf_editors_space_text', sources, incs, defs, libtype=['core'], priority=[95])
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index ff53d306e69..0a6a9a81e63 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -79,9 +79,17 @@ static SpaceLink *text_new(const bContext *UNUSED(C))
BLI_addtail(&stext->regionbase, ar);
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
-
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for text");
+
+ /* properties region */
+ ar = MEM_callocN(sizeof(ARegion), "properties region for text");
+
+ BLI_addtail(&stext->regionbase, ar);
+ ar->regiontype = RGN_TYPE_UI;
+ ar->alignment = RGN_ALIGN_LEFT;
+ ar->flag = RGN_FLAG_HIDDEN;
+
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for text");
BLI_addtail(&stext->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -404,7 +412,7 @@ static int text_context(const bContext *C, const char *member, bContextDataResul
/********************* main region ********************/
/* add handlers, stuff you only do once or on area/region changes */
-static void text_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void text_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
ListBase *lb;
@@ -423,7 +431,7 @@ static void text_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static void text_main_area_draw(const bContext *C, ARegion *ar)
+static void text_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
SpaceText *st = CTX_wm_space_text(C);
@@ -511,12 +519,12 @@ static void text_dropboxes(void)
/****************** header region ******************/
/* add handlers, stuff you only do once or on area/region changes */
-static void text_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void text_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void text_header_area_draw(const bContext *C, ARegion *ar)
+static void text_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
@@ -524,7 +532,7 @@ static void text_header_area_draw(const bContext *C, ARegion *ar)
/****************** properties region ******************/
/* add handlers, stuff you only do once or on area/region changes */
-static void text_properties_area_init(wmWindowManager *wm, ARegion *ar)
+static void text_properties_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -537,7 +545,7 @@ static void text_properties_area_init(wmWindowManager *wm, ARegion *ar)
}
-static void text_properties_area_draw(const bContext *C, ARegion *ar)
+static void text_properties_region_draw(const bContext *C, ARegion *ar)
{
SpaceText *st = CTX_wm_space_text(C);
@@ -578,8 +586,8 @@ void ED_spacetype_text(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype text region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = text_main_area_init;
- art->draw = text_main_area_draw;
+ art->init = text_main_region_init;
+ art->draw = text_main_region_draw;
art->cursor = text_cursor;
art->event_cursor = true;
@@ -591,8 +599,8 @@ void ED_spacetype_text(void)
art->prefsizex = UI_COMPACT_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI;
- art->init = text_properties_area_init;
- art->draw = text_properties_area_draw;
+ art->init = text_properties_region_init;
+ art->draw = text_properties_region_draw;
BLI_addhead(&st->regiontypes, art);
/* regions: header */
@@ -601,8 +609,8 @@ void ED_spacetype_text(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
- art->init = text_header_area_init;
- art->draw = text_header_area_draw;
+ art->init = text_header_region_init;
+ art->draw = text_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 1637ae14892..04cff288b03 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -327,8 +327,13 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
if (text_do_suggest_select(st, ar))
swallow = 1;
else {
- if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
- if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+ if (tools & TOOL_SUGG_LIST) {
+ texttool_suggest_clear();
+ }
+ if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ }
retval = OPERATOR_FINISHED;
}
draw = 1;
@@ -342,8 +347,13 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
swallow = 1;
}
else {
- if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
- if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+ if (tools & TOOL_SUGG_LIST) {
+ texttool_suggest_clear();
+ }
+ if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ }
retval = OPERATOR_FINISHED;
}
draw = 1;
@@ -352,8 +362,13 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
case ESCKEY:
if (event->val == KM_PRESS) {
draw = swallow = 1;
- if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
- else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+ if (tools & TOOL_SUGG_LIST) {
+ texttool_suggest_clear();
+ }
+ else if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ }
else draw = swallow = 0;
retval = OPERATOR_CANCELLED;
}
@@ -367,7 +382,11 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
swallow = 1;
draw = 1;
}
- if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
+ if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ draw = 1;
+ }
retval = OPERATOR_FINISHED;
}
break;
@@ -398,7 +417,10 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
}
}
}
- if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+ if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ }
}
break;
case RIGHTARROWKEY:
@@ -427,7 +449,10 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
}
}
}
- if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+ if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ }
}
break;
case PAGEDOWNKEY:
@@ -447,9 +472,15 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
texttool_suggest_select(texttool_suggest_first());
}
else {
- while (sel && sel != texttool_suggest_last() && sel->next && scroll--) {
- texttool_suggest_select(sel->next);
- sel = sel->next;
+ while (sel && scroll--) {
+ if (sel != texttool_suggest_last() && sel->next) {
+ texttool_suggest_select(sel->next);
+ sel = sel->next;
+ }
+ else {
+ texttool_suggest_select(texttool_suggest_first());
+ sel = texttool_suggest_first();
+ }
}
}
text_pop_suggest_list();
@@ -471,9 +502,15 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
}
else if (tools & TOOL_SUGG_LIST) {
SuggItem *sel = texttool_suggest_selected();
- while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) {
- texttool_suggest_select(sel->prev);
- sel = sel->prev;
+ while (sel && scroll--) {
+ if (sel != texttool_suggest_first() && sel->prev) {
+ texttool_suggest_select(sel->prev);
+ sel = sel->prev;
+ }
+ else {
+ texttool_suggest_select(texttool_suggest_last());
+ sel = texttool_suggest_last();
+ }
}
text_pop_suggest_list();
swallow = 1;
@@ -486,8 +523,15 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
break;
#if 0
default:
- if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1;
- if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
+ if (tools & TOOL_SUGG_LIST) {
+ texttool_suggest_clear();
+ draw = 1;
+ }
+ if (tools & TOOL_DOCUMENT) {
+ texttool_docs_clear();
+ doc_scroll = 0;
+ draw = 1;
+ }
#endif
}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 462b619f497..9448f6af69f 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -47,6 +47,7 @@
#include "ED_text.h"
#include "BIF_gl.h"
+#include "BIF_glutil.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -56,45 +57,56 @@
#include "text_format.h"
/******************** text font drawing ******************/
-// XXX, fixme
-#define mono blf_mono_font
-static void text_font_begin(SpaceText *st)
+typedef struct TextDrawContext {
+ int font_id;
+ int cwidth;
+ int lheight_dpi;
+} TextDrawContext;
+
+static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc)
+{
+ tdc->font_id = blf_mono_font;
+ tdc->cwidth = 0;
+ tdc->lheight_dpi = st->lheight_dpi;
+}
+
+static void text_font_begin(const TextDrawContext *tdc)
{
- BLF_size(mono, st->lheight_dpi, 72);
+ BLF_size(tdc->font_id, tdc->lheight_dpi, 72);
}
-static void text_font_end(SpaceText *UNUSED(st))
+static void text_font_end(const TextDrawContext *UNUSED(tdc))
{
}
-static int text_font_draw(SpaceText *st, int x, int y, const char *str)
+static int text_font_draw(const TextDrawContext *tdc, int x, int y, const char *str)
{
int columns;
- BLF_position(mono, x, y, 0);
- columns = BLF_draw_mono(mono, str, BLF_DRAW_STR_DUMMY_MAX, st->cwidth);
+ BLF_position(tdc->font_id, x, y, 0);
+ columns = BLF_draw_mono(tdc->font_id, str, BLF_DRAW_STR_DUMMY_MAX, tdc->cwidth);
- return st->cwidth * columns;
+ return tdc->cwidth * columns;
}
-static int text_font_draw_character(SpaceText *st, int x, int y, char c)
+static int text_font_draw_character(const TextDrawContext *tdc, int x, int y, char c)
{
- BLF_position(mono, x, y, 0);
- BLF_draw(mono, &c, 1);
+ BLF_position(tdc->font_id, x, y, 0);
+ BLF_draw(tdc->font_id, &c, 1);
- return st->cwidth;
+ return tdc->cwidth;
}
-static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c)
+static int text_font_draw_character_utf8(const TextDrawContext *tdc, int x, int y, const char *c)
{
int columns;
const size_t len = BLI_str_utf8_size_safe(c);
- BLF_position(mono, x, y, 0);
- columns = BLF_draw_mono(mono, c, len, st->cwidth);
+ BLF_position(tdc->font_id, x, y, 0);
+ columns = BLF_draw_mono(tdc->font_id, c, len, tdc->cwidth);
- return st->cwidth * columns;
+ return tdc->cwidth * columns;
}
#if 0
@@ -173,7 +185,7 @@ static void format_draw_color(char formatchar)
*
*/
-int wrap_width(SpaceText *st, ARegion *ar)
+int wrap_width(const SpaceText *st, ARegion *ar)
{
int winx = ar->winx - TXT_SCROLL_WIDTH;
int x, max;
@@ -184,7 +196,7 @@ int wrap_width(SpaceText *st, ARegion *ar)
}
/* Sets (offl, offc) for transforming (line, curs) to its wrapped position */
-void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc)
+void wrap_offset(const SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc)
{
Text *text;
TextLine *linep;
@@ -279,7 +291,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *
}
/* cursin - mem, offc - view */
-void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc)
+void wrap_offset_in_line(const SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc)
{
int i, j, start, end, chars, max, chop;
char ch;
@@ -341,7 +353,7 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi
}
}
-int text_get_char_pos(SpaceText *st, const char *line, int cur)
+int text_get_char_pos(const SpaceText *st, const char *line, int cur)
{
int a = 0, i;
@@ -372,7 +384,9 @@ static const char *txt_utf8_forward_columns(const char *str, int columns, int *p
return p;
}
-static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip)
+static int text_draw_wrapped(
+ const SpaceText *st, const TextDrawContext *tdc,
+ const char *str, int x, int y, int w, const char *format, int skip)
{
const bool use_syntax = (st->showsyntax && format);
FlattenString fs;
@@ -417,7 +431,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
if (use_syntax) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
- x += text_font_draw_character_utf8(st, x, y, str + ma);
+ x += text_font_draw_character_utf8(tdc, x, y, str + ma);
fpos++;
}
y -= st->lheight_dpi + TXT_LINE_SPACING;
@@ -441,7 +455,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
- x += text_font_draw_character_utf8(st, x, y, str + ma);
+ x += text_font_draw_character_utf8(tdc, x, y, str + ma);
}
flatten_string_free(&fs);
@@ -449,7 +463,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
return lines;
}
-static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, int y, const char *format)
+static void text_draw(
+ const SpaceText *st, const TextDrawContext *tdc,
+ char *str, int cshift, int maxwidth, int x, int y, const char *format)
{
const bool use_syntax = (st->showsyntax && format);
FlattenString fs;
@@ -482,7 +498,7 @@ static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x,
return; /* String is shorter than shift or ends with a padding */
}
- x += st->cwidth * padding;
+ x += tdc->cwidth * padding;
if (use_syntax) {
int a, str_shift = 0;
@@ -490,12 +506,12 @@ static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x,
for (a = 0; a < amount; a++) {
if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
- x += text_font_draw_character_utf8(st, x, y, in + str_shift);
+ x += text_font_draw_character_utf8(tdc, x, y, in + str_shift);
str_shift += BLI_str_utf8_size_safe(in + str_shift);
}
}
else {
- text_font_draw(st, x, y, in);
+ text_font_draw(tdc, x, y, in);
}
flatten_string_free(&fs);
@@ -695,14 +711,14 @@ void text_free_caches(SpaceText *st)
/************************ word-wrap utilities *****************************/
/* cache should be updated in caller */
-static int text_get_visible_lines_no(SpaceText *st, int lineno)
+static int text_get_visible_lines_no(const SpaceText *st, int lineno)
{
- DrawCache *drawcache = (DrawCache *)st->drawcache;
+ const DrawCache *drawcache = st->drawcache;
return drawcache->line_height[lineno];
}
-int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str)
+int text_get_visible_lines(const SpaceText *st, ARegion *ar, const char *str)
{
int i, j, start, end, max, lines, chars;
char ch;
@@ -741,7 +757,7 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str)
return lines;
}
-int text_get_span_wrap(SpaceText *st, ARegion *ar, TextLine *from, TextLine *to)
+int text_get_span_wrap(const SpaceText *st, ARegion *ar, TextLine *from, TextLine *to)
{
if (st->wordwrap) {
int ret = 0;
@@ -766,7 +782,7 @@ int text_get_total_lines(SpaceText *st, ARegion *ar)
DrawCache *drawcache;
text_update_drawcache(st, ar);
- drawcache = (DrawCache *)st->drawcache;
+ drawcache = st->drawcache;
return drawcache->total_lines;
}
@@ -784,7 +800,7 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
pix_available = ar->winy - pix_top_margin - pix_bottom_margin;
ltexth = text_get_total_lines(st, ar);
blank_lines = st->viewlines / 2;
-
+
/* nicer code: use scroll rect for entire bar */
back->xmin = ar->winx - (V2D_SCROLL_WIDTH + 1);
back->xmax = ar->winx;
@@ -886,7 +902,7 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back)
CLAMP(st->txtscroll.ymax, pix_bottom_margin, ar->winy - pix_top_margin);
}
-static void draw_textscroll(SpaceText *st, rcti *scroll, rcti *back)
+static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back)
{
bTheme *btheme = UI_GetTheme();
uiWidgetColors wcol = btheme->tui.wcol_scroll;
@@ -910,8 +926,9 @@ static void draw_textscroll(SpaceText *st, rcti *scroll, rcti *back)
/*********************** draw documentation *******************************/
-static void draw_documentation(SpaceText *st, ARegion *ar)
+static void draw_documentation(const SpaceText *st, ARegion *ar)
{
+ TextDrawContext tdc = {0};
TextLine *tmp;
char *docs, buf[DOC_WIDTH + 1], *p;
int i, br, lines;
@@ -924,6 +941,8 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
if (!docs) return;
+ text_draw_context_init(st, &tdc);
+
/* Count the visible lines to the cursor */
for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ;
if (l < 0) return;
@@ -973,7 +992,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
buf[i] = '\0';
if (lines >= 0) {
y -= st->lheight_dpi;
- text_draw(st, buf, 0, 0, x + 4, y - 3, NULL);
+ text_draw(st, &tdc, buf, 0, 0, x + 4, y - 3, NULL);
}
i = 0; br = DOC_WIDTH; lines++;
}
@@ -982,7 +1001,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
buf[br] = '\0';
if (lines >= 0) {
y -= st->lheight_dpi;
- text_draw(st, buf, 0, 0, x + 4, y - 3, NULL);
+ text_draw(st, &tdc, buf, 0, 0, x + 4, y - 3, NULL);
}
p -= i - br - 1; /* Rewind pointer to last break */
i = 0; br = DOC_WIDTH; lines++;
@@ -998,7 +1017,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
/*********************** draw suggestion list *******************************/
-static void draw_suggestion_list(SpaceText *st, ARegion *ar)
+static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc, ARegion *ar)
{
SuggItem *item, *first, *last, *sel;
char str[SUGG_LIST_WIDTH * BLI_UTF8_MAX + 1];
@@ -1063,7 +1082,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
}
format_draw_color(item->type);
- text_draw(st, str, 0, 0, x + margin_x, y - 1, NULL);
+ text_draw(st, tdc, str, 0, 0, x + margin_x, y - 1, NULL);
if (item == last) break;
}
@@ -1089,8 +1108,13 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
vsell = txt_get_span(text->lines.first, text->sell) - st->top + offl;
vselc = text_get_char_pos(st, text->sell->line, text->selc) - st->left + offc;
- if (vcurc < 0) vcurc = 0;
- if (vselc < 0) vselc = 0, hidden = 1;
+ if (vcurc < 0) {
+ vcurc = 0;
+ }
+ if (vselc < 0) {
+ vselc = 0;
+ hidden = 1;
+ }
UI_ThemeColor(TH_SHADE2);
x = st->showlinenrs ? TXT_OFFSET + TEXTXLOC : TXT_OFFSET;
@@ -1116,11 +1140,16 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
}
y -= froml * lheight;
- glRecti(x + fromc * st->cwidth - 1, y, ar->winx, y - lheight); y -= lheight;
- for (i = froml + 1; i < tol; i++)
- glRecti(x - 4, y, ar->winx, y - lheight), y -= lheight;
- glRecti(x - 4, y, x + toc * st->cwidth, y - lheight); y -= lheight;
+ glRecti(x + fromc * st->cwidth - 1, y, ar->winx, y - lheight);
+ y -= lheight;
+ for (i = froml + 1; i < tol; i++) {
+ glRecti(x - 4, y, ar->winx, y - lheight);
+ y -= lheight;
+ }
+
+ glRecti(x - 4, y, x + toc * st->cwidth, y - lheight);
+ y -= lheight;
}
}
else {
@@ -1190,7 +1219,7 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
/******************* draw matching brackets *********************/
-static void draw_brackets(SpaceText *st, ARegion *ar)
+static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegion *ar)
{
TextLine *startl, *endl, *linep;
Text *text = st->text;
@@ -1298,8 +1327,8 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
if (viewc >= 0) {
viewl = txt_get_span(text->lines.first, startl) - st->top + offl;
- text_font_draw_character(st, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
- text_font_draw_character(st, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
+ text_font_draw_character(tdc, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
+ text_font_draw_character(tdc, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
}
/* draw closing bracket */
@@ -1310,15 +1339,16 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
if (viewc >= 0) {
viewl = txt_get_span(text->lines.first, endl) - st->top + offl;
- text_font_draw_character(st, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
- text_font_draw_character(st, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
+ text_font_draw_character(tdc, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
+ text_font_draw_character(tdc, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch);
}
}
-/*********************** main area drawing *************************/
+/*********************** main region drawing *************************/
void draw_text_main(SpaceText *st, ARegion *ar)
{
+ TextDrawContext tdc = {0};
Text *text = st->text;
TextFormatType *tft;
TextLine *tmp;
@@ -1327,8 +1357,6 @@ void draw_text_main(SpaceText *st, ARegion *ar)
int i, x, y, winx, linecount = 0, lineno = 0;
int wraplinecount = 0, wrap_skip = 0;
int margin_column_x;
- /* don't draw lines below this */
- const int clip_min_y = -(int)(st->lheight_dpi - 1);
/* if no text, nothing to do */
if (!text)
@@ -1336,8 +1364,14 @@ void draw_text_main(SpaceText *st, ARegion *ar)
/* dpi controlled line height and font size */
st->lheight_dpi = (U.widget_unit * st->lheight) / 20;
+
+ /* don't draw lines below this */
+ const int clip_min_y = -(int)(st->lheight_dpi - 1);
+
st->viewlines = (st->lheight_dpi) ? (int)(ar->winy - clip_min_y) / (st->lheight_dpi + TXT_LINE_SPACING) : 0;
+ text_draw_context_init(st, &tdc);
+
text_update_drawcache(st, ar);
/* make sure all the positional pointers exist */
@@ -1376,9 +1410,11 @@ void draw_text_main(SpaceText *st, ARegion *ar)
lineno++;
}
- text_font_begin(st);
- st->cwidth = BLF_fixed_width(mono);
- st->cwidth = MAX2(st->cwidth, (char)1);
+
+ text_font_begin(&tdc);
+
+ tdc.cwidth = max_ii((int)BLF_fixed_width(tdc.font_id), 1);
+ st->cwidth = tdc.cwidth;
/* draw line numbers background */
if (st->showlinenrs) {
@@ -1413,19 +1449,19 @@ void draw_text_main(SpaceText *st, ARegion *ar)
BLI_snprintf(linenr, sizeof(linenr), "%*d", st->linenrs_tot, i + linecount + 1);
/* itoa(i + linecount + 1, linenr, 10); */ /* not ansi-c :/ */
- text_font_draw(st, TXT_OFFSET - 7, y, linenr);
+ text_font_draw(&tdc, TXT_OFFSET - 7, y, linenr);
UI_ThemeColor(TH_TEXT);
}
if (st->wordwrap) {
/* draw word wrapped text */
- int lines = text_draw_wrapped(st, tmp->line, x, y, winx - x, tmp->format, wrap_skip);
+ int lines = text_draw_wrapped(st, &tdc, tmp->line, x, y, winx - x, tmp->format, wrap_skip);
y -= lines * (st->lheight_dpi + TXT_LINE_SPACING);
}
else {
/* draw unwrapped text */
- text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format);
+ text_draw(st, &tdc, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format);
y -= st->lheight_dpi + TXT_LINE_SPACING;
}
@@ -1433,35 +1469,42 @@ void draw_text_main(SpaceText *st, ARegion *ar)
}
if (st->flags & ST_SHOW_MARGIN) {
- UI_ThemeColor(TH_HILITE);
-
margin_column_x = x + st->cwidth * (st->margin_column - st->left);
if (margin_column_x >= x) {
+ /* same color as line number background */
+ UI_ThemeColor(TH_GRID);
+
+ setlinestyle(1);
glBegin(GL_LINES);
glVertex2i(margin_column_x, 0);
glVertex2i(margin_column_x, ar->winy - 2);
glEnd();
+ setlinestyle(0);
}
}
/* draw other stuff */
- draw_brackets(st, ar);
+ draw_brackets(st, &tdc, ar);
draw_textscroll(st, &scroll, &back);
draw_documentation(st, ar);
- draw_suggestion_list(st, ar);
+ draw_suggestion_list(st, &tdc, ar);
- text_font_end(st);
+ text_font_end(&tdc);
}
/************************** update ***************************/
void text_update_character_width(SpaceText *st)
{
- text_font_begin(st);
- st->cwidth = BLF_fixed_width(mono);
+ TextDrawContext tdc = {0};
+
+ text_draw_context_init(st, &tdc);
+
+ text_font_begin(&tdc);
+ st->cwidth = BLF_fixed_width(tdc.font_id);
st->cwidth = MAX2(st->cwidth, (char)1);
- text_font_end(st);
+ text_font_end(&tdc);
}
/* Moves the view to the cursor location,
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index b29c6420d60..0133122c5a3 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -73,7 +73,7 @@ static void flatten_string_append(FlattenString *fs, const char *c, int accum, i
fs->pos += len;
}
-int flatten_string(SpaceText *st, FlattenString *fs, const char *in)
+int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
{
int r, i, total = 0;
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index daed3b3e447..b901ec83a9c 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -54,7 +54,7 @@ enum {
#define FMT_CONT_ALL \
(FMT_CONT_QUOTESINGLE | FMT_CONT_QUOTEDOUBLE | FMT_CONT_TRIPLE | FMT_CONT_COMMENT_C)
-int flatten_string(struct SpaceText *st, FlattenString *fs, const char *in);
+int flatten_string(const struct SpaceText *st, FlattenString *fs, const char *in);
void flatten_string_free(FlattenString *fs);
int flatten_string_strlen(FlattenString *fs, const char *str);
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 7ae2617f375..3129c1bfc85 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -65,10 +65,10 @@ void text_update_cursor_moved(struct bContext *C);
#define TOOL_SUGG_LIST 0x01
#define TOOL_DOCUMENT 0x02
-int wrap_width(struct SpaceText *st, struct ARegion *ar);
-void wrap_offset(struct SpaceText *st, struct ARegion *ar, struct TextLine *linein, int cursin, int *offl, int *offc);
-void wrap_offset_in_line(struct SpaceText *st, struct ARegion *ar, struct TextLine *linep, int cursin, int *offl, int *offc);
-int text_get_char_pos(struct SpaceText *st, const char *line, int cur);
+int wrap_width(const struct SpaceText *st, struct ARegion *ar);
+void wrap_offset(const struct SpaceText *st, struct ARegion *ar, struct TextLine *linein, int cursin, int *offl, int *offc);
+void wrap_offset_in_line(const struct SpaceText *st, struct ARegion *ar, struct TextLine *linep, int cursin, int *offl, int *offc);
+int text_get_char_pos(const struct SpaceText *st, const char *line, int cur);
void text_drawcache_tag_update(struct SpaceText *st, int full);
void text_free_caches(struct SpaceText *st);
@@ -76,8 +76,8 @@ void text_free_caches(struct SpaceText *st);
int text_do_suggest_select(struct SpaceText *st, struct ARegion *ar);
void text_pop_suggest_list(void);
-int text_get_visible_lines(struct SpaceText *st, struct ARegion *ar, const char *str);
-int text_get_span_wrap(struct SpaceText *st, struct ARegion *ar, struct TextLine *from, struct TextLine *to);
+int text_get_visible_lines(const struct SpaceText *st, struct ARegion *ar, const char *str);
+int text_get_span_wrap(const struct SpaceText *st, struct ARegion *ar, struct TextLine *from, struct TextLine *to);
int text_get_total_lines(struct SpaceText *st, struct ARegion *ar);
/* text_ops.c */
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index a2fae2d5667..d404e7aaf15 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -300,8 +300,9 @@ void TEXT_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); //XXX TODO, relative_path
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); //XXX TODO, relative_path
RNA_def_boolean(ot->srna, "internal", 0, "Make internal", "Make text file internal after loading");
}
@@ -577,8 +578,9 @@ void TEXT_OT_save_as(wmOperatorType *ot)
ot->poll = text_edit_poll;
/* properties */
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); //XXX TODO, relative_path
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_TEXT | FILE_TYPE_PYSCRIPT, FILE_SPECIAL, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); //XXX TODO, relative_path
}
/******************* run script operator *********************/
@@ -598,7 +600,7 @@ static int text_run_script(bContext *C, ReportList *reports)
void *curl_prev = text->curl;
int curc_prev = text->curc;
- if (BPY_text_exec(C, text, reports, !is_live)) {
+ if (BPY_execute_text(C, text, reports, !is_live)) {
if (is_live) {
/* for nice live updates */
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
@@ -1054,108 +1056,102 @@ static int text_convert_whitespace_exec(bContext *C, wmOperator *op)
Text *text = CTX_data_edit_text(C);
TextLine *tmp;
FlattenString fs;
- size_t a, j;
- char *new_line;
- int extra, number; //unknown for now
+ size_t a, j, max_len = 0;
int type = RNA_enum_get(op->ptr, "type");
/* first convert to all space, this make it a lot easier to convert to tabs
* because there is no mixtures of ' ' && '\t' */
for (tmp = text->lines.first; tmp; tmp = tmp->next) {
- const char *text_check_line = tmp->line;
- const int text_check_line_len = tmp->len;
- number = flatten_string(st, &fs, text_check_line) + 1;
+ char *new_line;
+
+ BLI_assert(tmp->line);
+
+ flatten_string(st, &fs, tmp->line);
+ new_line = BLI_strdup(fs.buf);
flatten_string_free(&fs);
- new_line = MEM_callocN(number, "Converted_Line");
- j = 0;
- for (a = 0; a < text_check_line_len; a++) { //foreach char in line
- if (text_check_line[a] == '\t') { //checking for tabs
- //get the number of spaces this tabs is showing
- //i don't like doing it this way but will look into it later
- new_line[j] = '\0';
- number = flatten_string(st, &fs, new_line);
- flatten_string_free(&fs);
- new_line[j] = '\t';
- new_line[j + 1] = '\0';
- number = flatten_string(st, &fs, new_line) - number;
- flatten_string_free(&fs);
- for (extra = 0; extra < number; extra++) {
- new_line[j] = ' ';
- j++;
- }
- }
- else {
- new_line[j] = text_check_line[a];
- j++;
- }
- }
- new_line[j] = '\0';
- // put new_line in the tmp->line spot still need to try and set the curc correctly
- if (tmp->line) MEM_freeN(tmp->line);
- if (tmp->format) MEM_freeN(tmp->format);
+ MEM_freeN(tmp->line);
+ if (tmp->format)
+ MEM_freeN(tmp->format);
+ /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */
tmp->line = new_line;
tmp->len = strlen(new_line);
tmp->format = NULL;
+ if (tmp->len > max_len) {
+ max_len = tmp->len;
+ }
}
- if (type == TO_TABS) { // Converting to tabs
- //start over from the beginning
-
+ if (type == TO_TABS) {
+ char *tmp_line = MEM_mallocN(sizeof(*tmp_line) * (max_len + 1), __func__);
+
for (tmp = text->lines.first; tmp; tmp = tmp->next) {
const char *text_check_line = tmp->line;
const int text_check_line_len = tmp->len;
- extra = 0;
- for (a = 0; a < text_check_line_len; a++) {
- number = 0;
- for (j = 0; j < (size_t)st->tabnumber; j++) {
- if ((a + j) <= text_check_line_len) { //check to make sure we are not pass the end of the line
- if (text_check_line[a + j] != ' ') {
- number = 1;
+ char *tmp_line_cur = tmp_line;
+ const size_t tab_len = st->tabnumber;
+
+ BLI_assert(text_check_line);
+
+ for (a = 0; a < text_check_line_len;) {
+ /* A tab can only start at a position multiple of tab_len... */
+ if (!(a % tab_len) && (text_check_line[a] == ' ')) {
+ /* a + 0 we already know to be ' ' char... */
+ for (j = 1; (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' '); j++);
+
+ if (j == tab_len) {
+ /* We found a set of spaces that can be replaced by a tab... */
+ if ((tmp_line_cur == tmp_line) && a != 0) {
+ /* Copy all 'valid' string already 'parsed'... */
+ memcpy(tmp_line_cur, text_check_line, a);
+ tmp_line_cur += a;
}
+ *tmp_line_cur = '\t';
+ tmp_line_cur++;
+ a += j;
}
- }
- if (!number) { //found all number of space to equal a tab
- a = a + (st->tabnumber - 1);
- extra = extra + 1;
- }
- }
-
- if (extra > 0) { //got tabs make malloc and do what you have to do
- new_line = MEM_callocN(text_check_line_len - (((st->tabnumber * extra) - extra) - 1), "Converted_Line");
- extra = 0; //reuse vars
- for (a = 0; a < text_check_line_len; a++) {
- number = 0;
- for (j = 0; j < (size_t)st->tabnumber; j++) {
- if ((a + j) <= text_check_line_len) { //check to make sure we are not pass the end of the line
- if (text_check_line[a + j] != ' ') {
- number = 1;
- }
+ else {
+ if (tmp_line_cur != tmp_line) {
+ memcpy(tmp_line_cur, &text_check_line[a], j);
+ tmp_line_cur += j;
}
+ a += j;
}
-
- if (!number) { //found all number of space to equal a tab
- new_line[extra] = '\t';
- a = a + (st->tabnumber - 1);
- extra++;
-
- }
- else { //not adding a tab
- new_line[extra] = text_check_line[a];
- extra++;
+ }
+ else {
+ size_t len = BLI_str_utf8_size_safe(&text_check_line[a]);
+ if (tmp_line_cur != tmp_line) {
+ memcpy(tmp_line_cur, &text_check_line[a], len);
+ tmp_line_cur += len;
}
+ a += len;
}
- new_line[extra] = '\0';
- // put new_line in the tmp->line spot still need to try and set the curc correctly
- if (tmp->line) MEM_freeN(tmp->line);
- if (tmp->format) MEM_freeN(tmp->format);
-
- tmp->line = new_line;
- tmp->len = strlen(new_line);
+ }
+
+ if (tmp_line_cur != tmp_line) {
+ *tmp_line_cur = '\0';
+
+#ifndef NDEBUG
+ BLI_assert(tmp_line_cur - tmp_line <= max_len);
+
+ flatten_string(st, &fs, tmp_line);
+ BLI_assert(STREQ(fs.buf, tmp->line));
+ flatten_string_free(&fs);
+#endif
+
+ MEM_freeN(tmp->line);
+ if (tmp->format)
+ MEM_freeN(tmp->format);
+
+ /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */
+ tmp->line = BLI_strdup(tmp_line);
+ tmp->len = strlen(tmp_line);
tmp->format = NULL;
}
}
+
+ MEM_freeN(tmp_line);
}
text_update_edited(text);
@@ -1955,6 +1951,19 @@ static int text_delete_exec(bContext *C, wmOperator *op)
txt_backspace_word(text);
}
else if (type == DEL_PREV_CHAR) {
+
+ if (text->flags & TXT_TABSTOSPACES) {
+ if (!txt_has_sel(text) && !txt_cursor_is_line_start(text)) {
+ int tabsize = 0;
+ tabsize = txt_calc_tab_left(text->curl, text->curc);
+ if (tabsize) {
+ text->sell = text->curl;
+ text->selc = text->curc - tabsize;
+ txt_order_cursors(text, false);
+ }
+ }
+ }
+
txt_backspace_char(text);
}
else if (type == DEL_NEXT_WORD) {
@@ -1964,6 +1973,19 @@ static int text_delete_exec(bContext *C, wmOperator *op)
txt_delete_word(text);
}
else if (type == DEL_NEXT_CHAR) {
+
+ if (text->flags & TXT_TABSTOSPACES) {
+ if (!txt_has_sel(text) && !txt_cursor_is_line_end(text)) {
+ int tabsize = 0;
+ tabsize = txt_calc_tab_right(text->curl, text->curc);
+ if (tabsize) {
+ text->sell = text->curl;
+ text->selc = text->curc + tabsize;
+ txt_order_cursors(text, true);
+ }
+ }
+ }
+
txt_delete_char(text);
}
@@ -2375,21 +2397,23 @@ static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
return j;
}
-static TextLine *get_first_visible_line(SpaceText *st, ARegion *ar, int *y)
+static TextLine *get_line_pos_wrapped(SpaceText *st, ARegion *ar, int *y)
{
TextLine *linep = st->text->lines.first;
- int i;
- for (i = st->top; i > 0 && linep; ) {
- int lines = text_get_visible_lines(st, ar, linep->line);
-
- if (i - lines < 0) {
- *y += i;
+ int i, lines;
+
+ if (*y < -st->top) {
+ return NULL; /* We are beyond the first line... */
+ }
+
+ for (i = -st->top; i <= *y && linep; linep = linep->next, i += lines) {
+ lines = text_get_visible_lines(st, ar, linep->line);
+
+ if (i + lines > *y) {
+ /* We found the line matching given vertical 'coordinate', now set y relative to this line's start. */
+ *y -= i;
break;
}
- else {
- linep = linep->next;
- i -= lines;
- }
}
return linep;
}
@@ -2399,23 +2423,22 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
Text *text = st->text;
int max = wrap_width(st, ar); /* column */
int charp = -1; /* mem */
- int loop = 1, found = 0; /* flags */
- char ch;
+ bool found = false; /* flags */
- /* Point to first visible line */
- TextLine *linep = get_first_visible_line(st, ar, &y);
-
- while (loop && linep) {
+ /* Point to line matching given y position, if any. */
+ TextLine *linep = get_line_pos_wrapped(st, ar, &y);
+
+ if (linep) {
int i = 0, start = 0, end = max; /* column */
- int j = 0, curs = 0, endj = 0; /* mem */
- int chop = 1; /* flags */
-
- for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) {
+ int j, curs = 0, endj = 0; /* mem */
+ bool chop = true; /* flags */
+ char ch;
+
+ for (j = 0 ; !found && ((ch = linep->line[j]) != '\0'); j += BLI_str_utf8_size_safe(linep->line + j)) {
int chars;
int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
/* Mimic replacement of tabs */
- ch = linep->line[j];
if (ch == '\t') {
chars = st->tabnumber - i % st->tabnumber;
ch = ' ';
@@ -2428,7 +2451,8 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
/* Gone too far, go back to last wrap point */
if (y < 0) {
charp = endj;
- loop = 0;
+ y = 0;
+ found = true;
break;
/* Exactly at the cursor */
}
@@ -2436,7 +2460,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
/* current position could be wrapped to next line */
/* this should be checked when end of current line would be reached */
charp = curs = j;
- found = 1;
+ found = true;
/* Prepare curs for next wrap */
}
else if (i - end <= x && i + columns - end > x) {
@@ -2446,68 +2470,70 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in
end = MIN2(end, i);
if (found) {
- /* exact cursor position was found, check if it's */
- /* still on needed line (hasn't been wrapped) */
- if (charp > endj && !chop && ch != '\0') charp = endj;
- loop = 0;
+ /* exact cursor position was found, check if it's still on needed line (hasn't been wrapped) */
+ if (charp > endj && !chop && ch != '\0')
+ charp = endj;
break;
}
- if (chop) endj = j;
+ if (chop)
+ endj = j;
start = end;
end += max;
if (j < linep->len)
y--;
- chop = 1;
+ chop = true;
if (y == 0 && i + columns - start > x) {
charp = curs;
- loop = 0;
+ found = true;
break;
}
}
else if (ch == ' ' || ch == '-' || ch == '\0') {
if (found) {
- loop = 0;
break;
}
if (y == 0 && i + columns - start > x) {
charp = curs;
- loop = 0;
+ found = true;
break;
}
end = i + 1;
endj = j;
- chop = 0;
+ chop = false;
}
i += columns;
}
-
- if (ch == '\0') break;
- }
-
- if (!loop || found) break;
-
- if (!linep->next) {
- charp = linep->len;
- break;
}
+
+ BLI_assert(y == 0);
- /* On correct line but didn't meet cursor, must be at end */
- if (y == 0) {
+ if (!found) {
+ /* On correct line but didn't meet cursor, must be at end */
charp = linep->len;
- break;
}
- linep = linep->next;
-
- y--;
}
+ else if (y < 0) { /* Before start of text. */
+ linep = st->text->lines.first;
+ charp = 0;
+ }
+ else { /* Beyond end of text */
+ linep = st->text->lines.last;
+ charp = linep->len;
+ }
+
+ BLI_assert(linep && charp != -1);
- if (linep && charp != -1) {
- if (sel) { text->sell = linep; text->selc = charp; }
- else { text->curl = linep; text->curc = charp; }
+ if (sel) {
+ text->sell = linep;
+ text->selc = charp;
+ }
+ else {
+ text->curl = linep;
+ text->curc = charp;
}
}
diff --git a/source/blender/editors/space_time/SConscript b/source/blender/editors/space_time/SConscript
deleted file mode 100644
index 86437b9c258..00000000000
--- a/source/blender/editors/space_time/SConscript
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-env.BlenderLib('bf_editors_space_time', sources, incs, defs, libtype=['core'], priority=[65])
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 9ecea7462ff..fde955c24a7 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -349,14 +349,19 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- bGPdata *gpd = CTX_data_gpencil_data(C);
View2D *v2d = &ar->v2d;
bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
- /* draw grease pencil keyframes (if available) */
- if (gpd) {
- UI_ThemeColor(TH_TIME_GP_KEYFRAME);
- time_draw_idblock_keyframes(v2d, (ID *)gpd, onlysel);
+ /* set this for all keyframe lines once and for all */
+ glLineWidth(1.0);
+
+ /* draw grease pencil keyframes (if available) */
+ UI_ThemeColor(TH_TIME_GP_KEYFRAME);
+ if (scene->gpd) {
+ time_draw_idblock_keyframes(v2d, (ID *)scene->gpd, onlysel);
+ }
+ if (ob && ob->gpd) {
+ time_draw_idblock_keyframes(v2d, (ID *)ob->gpd, onlysel);
}
/* draw scene keyframes first
@@ -485,7 +490,7 @@ static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
/* ---------------- */
/* add handlers, stuff you only do once or on area/region changes */
-static void time_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void time_main_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -496,7 +501,7 @@ static void time_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
-static void time_main_area_draw(const bContext *C, ARegion *ar)
+static void time_main_region_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
Scene *scene = CTX_data_scene(C);
@@ -555,7 +560,7 @@ static void time_main_area_draw(const bContext *C, ARegion *ar)
UI_view2d_scrollers_free(scrollers);
}
-static void time_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -586,17 +591,17 @@ static void time_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR
/* ************************ header time area region *********************** */
/* add handlers, stuff you only do once or on area/region changes */
-static void time_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void time_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void time_header_area_draw(const bContext *C, ARegion *ar)
+static void time_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void time_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void time_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -649,8 +654,8 @@ static SpaceLink *time_new(const bContext *C)
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for time");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for time");
BLI_addtail(&stime->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -737,9 +742,9 @@ void ED_spacetype_time(void)
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES;
- art->init = time_main_area_init;
- art->draw = time_main_area_draw;
- art->listener = time_main_area_listener;
+ art->init = time_main_region_init;
+ art->draw = time_main_region_draw;
+ art->listener = time_main_region_listener;
art->keymap = time_keymap;
BLI_addhead(&st->regiontypes, art);
@@ -749,9 +754,9 @@ void ED_spacetype_time(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->init = time_header_area_init;
- art->draw = time_header_area_draw;
- art->listener = time_header_area_listener;
+ art->init = time_header_region_init;
+ art->draw = time_header_region_draw;
+ art->listener = time_header_region_listener;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c
index e2e861fda38..a7f549b65ae 100644
--- a/source/blender/editors/space_time/time_ops.c
+++ b/source/blender/editors/space_time/time_ops.c
@@ -39,6 +39,7 @@
#include "BKE_context.h"
+#include "ED_anim_api.h"
#include "ED_screen.h"
#include "WM_api.h"
@@ -176,6 +177,31 @@ static void TIME_OT_view_all(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ************************ View Frame Operator *******************************/
+
+static int time_view_frame_exec(bContext *C, wmOperator *op)
+{
+ const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ ANIM_center_frame(C, smooth_viewtx);
+
+ return OPERATOR_FINISHED;
+}
+
+static void TIME_OT_view_frame(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "View Frame";
+ ot->idname = "TIME_OT_view_frame";
+ ot->description = "Reset viewable area to show range around current frame";
+
+ /* api callbacks */
+ ot->exec = time_view_frame_exec;
+ ot->poll = ED_operator_timeline_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* ************************** registration **********************************/
void time_operatortypes(void)
@@ -183,6 +209,7 @@ void time_operatortypes(void)
WM_operatortype_append(TIME_OT_start_frame_set);
WM_operatortype_append(TIME_OT_end_frame_set);
WM_operatortype_append(TIME_OT_view_all);
+ WM_operatortype_append(TIME_OT_view_frame);
}
void time_keymap(wmKeyConfig *keyconf)
@@ -193,5 +220,6 @@ void time_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "TIME_OT_end_frame_set", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "TIME_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "TIME_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TIME_OT_view_frame", PAD0, KM_PRESS, 0, 0);
}
diff --git a/source/blender/editors/space_userpref/SConscript b/source/blender/editors/space_userpref/SConscript
deleted file mode 100644
index ce2e83f7b33..00000000000
--- a/source/blender/editors/space_userpref/SConscript
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- '#/extern/glew/include',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-defs = []
-
-env.BlenderLib('bf_editors_space_userpref', sources, incs, defs, libtype=['core'], priority=[70])
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index b5a6821d147..aeba4a86f3e 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -66,8 +66,8 @@ static SpaceLink *userpref_new(const bContext *UNUSED(C))
ar->regiontype = RGN_TYPE_HEADER;
ar->alignment = RGN_ALIGN_BOTTOM;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for userpref");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for userpref");
BLI_addtail(&spref->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -101,7 +101,7 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl)
/* add handlers, stuff you only do once or on area/region changes */
-static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar)
{
/* do not use here, the properties changed in userprefs do a system-wide refresh, then scroller jumps back */
/* ar->v2d.flag &= ~V2D_IS_INITIALISED; */
@@ -111,7 +111,7 @@ static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar)
ED_region_panels_init(wm, ar);
}
-static void userpref_main_area_draw(const bContext *C, ARegion *ar)
+static void userpref_main_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
@@ -126,17 +126,17 @@ static void userpref_keymap(struct wmKeyConfig *UNUSED(keyconf))
}
/* add handlers, stuff you only do once or on area/region changes */
-static void userpref_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void userpref_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
{
ED_region_header_init(ar);
}
-static void userpref_header_area_draw(const bContext *C, ARegion *ar)
+static void userpref_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void userpref_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
+static void userpref_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
{
/* context changes */
}
@@ -171,9 +171,9 @@ void ED_spacetype_userpref(void)
/* regions: main window */
art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region");
art->regionid = RGN_TYPE_WINDOW;
- art->init = userpref_main_area_init;
- art->draw = userpref_main_area_draw;
- art->listener = userpref_main_area_listener;
+ art->init = userpref_main_region_init;
+ art->draw = userpref_main_region_draw;
+ art->listener = userpref_main_region_listener;
art->keymapflag = ED_KEYMAP_UI;
BLI_addhead(&st->regiontypes, art);
@@ -184,8 +184,8 @@ void ED_spacetype_userpref(void)
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
art->listener = userpref_header_listener;
- art->init = userpref_header_area_init;
- art->draw = userpref_header_area_draw;
+ art->init = userpref_header_region_init;
+ art->draw = userpref_header_region_draw;
BLI_addhead(&st->regiontypes, art);
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
deleted file mode 100644
index 7fdccce1c0e..00000000000
--- a/source/blender/editors/space_view3d/SConscript
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/smoke/extern',
- '#/source/gameengine/BlenderRoutines',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../render/extern/include',
- '../../windowmanager',
- '../../depsgraph',
- ]
-
-if env['WITH_BF_PYTHON']:
- incs.append('../../python')
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-if env['WITH_BF_LEGACY_DEPSGRAPH']:
- defs.append('WITH_LEGACY_DEPSGRAPH')
-
-env.BlenderLib ( 'bf_editors_space_view3d', sources, incs, defines = defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c
index d753ad68fcc..9872b05da63 100644
--- a/source/blender/editors/space_view3d/drawanimviz.c
+++ b/source/blender/editors/space_view3d/drawanimviz.c
@@ -220,7 +220,6 @@ void draw_motion_path_instance(Scene *scene,
glVertex3fv(mpv->co);
glEnd();
- glPointSize(1.0f);
UI_ThemeColor(TH_TEXT_HI);
}
@@ -305,8 +304,6 @@ void draw_motion_path_instance(Scene *scene,
}
glEnd();
- glPointSize(1.0f);
-
/* Draw frame numbers of keyframes */
if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) {
float co[3];
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 2579972cf0f..c6b2ccee85b 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -61,6 +61,7 @@
#include "ED_armature.h"
#include "ED_keyframes_draw.h"
+#include "GPU_basic_shader.h"
#include "UI_resources.h"
@@ -118,11 +119,12 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
bcolor = &btheme->tarm[(color_index - 1)];
}
else if (color_index == -1) {
- /* use the group's own custom color set */
- bcolor = (grp) ? &grp->cs : NULL;
+ /* use the group's own custom color set (grp is always != NULL here) */
+ bcolor = &grp->cs;
}
- else
+ else {
bcolor = NULL;
+ }
}
/* This function is for brightening/darkening a given color (like UI_ThemeColorShade()) */
@@ -884,8 +886,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
if (dt == OB_SOLID) {
/* set up solid drawing */
- glEnable(GL_COLOR_MATERIAL);
- glEnable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
gluQuadricDrawStyle(qobj, GLU_FILL);
glShadeModel(GL_SMOOTH);
@@ -967,8 +968,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
/* restore */
if (dt == OB_SOLID) {
glShadeModel(GL_FLAT);
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
glPopMatrix();
@@ -1000,6 +1000,12 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* this chunk not in object mode */
if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) {
glLineWidth(4.0f);
+ if (G.f & G_PICKSEL) {
+ /* no bitmap in selection mode, crashes 3d cards...
+ * instead draw a solid point the same size */
+ glPointSize(8.0f);
+ }
+
if (armflag & ARM_POSEMODE)
set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag);
else if (armflag & ARM_EDITMODE) {
@@ -1008,7 +1014,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
- if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */
+ if (G.f & G_PICKSEL) {
GPU_select_load_id(id | BONESEL_ROOT);
glBegin(GL_POINTS);
glVertex3f(0.0f, 0.0f, 0.0f);
@@ -1084,8 +1090,6 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
glBitmap(8, 8, 4, 4, 0, 0, bm_dot5);
}
- glLineWidth(1.0);
-
glPopMatrix();
}
@@ -1166,8 +1170,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
/* set up solid drawing */
if (dt > OB_WIRE) {
- glEnable(GL_COLOR_MATERIAL);
- glEnable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
if (armflag & ARM_POSEMODE)
set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag);
@@ -1177,8 +1180,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
/* disable solid drawing */
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
else {
/* wire */
@@ -1297,8 +1299,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
/* set up solid drawing */
if (dt > OB_WIRE) {
- glEnable(GL_COLOR_MATERIAL);
- glEnable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
UI_ThemeColor(TH_BONE_SOLID);
}
@@ -1352,8 +1353,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
/* disable solid drawing */
if (dt > OB_WIRE) {
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
}
@@ -1440,7 +1440,8 @@ static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp)
if (segcount == data->chainlen || segcount > 255) break; /* 255 is weak */
parchan = parchan->parent;
}
- if (parchan) /* XXX revise the breaking conditions to only stop at the tail? */
+ /* Only draw line in case our chain is more than one bone long! */
+ if (parchan != pchan) /* XXX revise the breaking conditions to only stop at the tail? */
glVertex3fv(parchan->pose_head);
glEnd();
@@ -1661,10 +1662,14 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
bArmature *arm = ob->data;
bPoseChannel *pchan;
Bone *bone;
- GLfloat tmp;
float smat[4][4], imat[4][4], bmat[4][4];
int index = -1;
- short do_dashed = 3;
+ const enum {
+ DASH_RELATIONSHIP_LINES = 1,
+ DASH_HELP_LINES = 2,
+ } do_dashed = (
+ (is_outline ? 0 : DASH_RELATIONSHIP_LINES) |
+ ((v3d->flag & V3D_HIDE_HELPLINES) ? 0 : DASH_HELP_LINES));
bool draw_wire = false;
int flag;
bool is_cull_enabled;
@@ -1672,11 +1677,6 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* being set below */
arm->layer_used = 0;
- /* hacky... prevent outline select from drawing dashed helplines */
- glGetFloatv(GL_LINE_WIDTH, &tmp);
- if (tmp > 1.1f) do_dashed &= ~1;
- if (v3d->flag & V3D_HIDE_HELPLINES) do_dashed &= ~2;
-
/* precalc inverse matrix for drawing screen aligned */
if (arm->drawtype == ARM_ENVELOPE) {
/* precalc inverse matrix for drawing screen aligned */
@@ -1765,7 +1765,10 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* set color-set to use */
set_pchan_colorset(ob, pchan);
}
-
+
+ /* may be 2x width from custom bone's outline option */
+ glLineWidth(1.0f);
+
if (use_custom) {
/* if drawwire, don't try to draw in solid */
if (pchan->bone->flag & BONE_DRAWWIRE) {
@@ -1778,7 +1781,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
draw_custom_bone(scene, v3d, rv3d, pchan->custom,
- OB_SOLID, arm->flag, flag, index, bone->length);
+ OB_SOLID, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
}
}
else {
@@ -1869,7 +1872,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
flag |= BONE_DRAW_ACTIVE;
draw_custom_bone(scene, v3d, rv3d, pchan->custom,
- OB_WIRE, arm->flag, flag, index, bone->length);
+ OB_WIRE, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan));
glPopMatrix();
}
@@ -1888,6 +1891,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
}
+ /* custom bone may draw outline double-width */
+ glLineWidth(1.0f);
+
/* wire draw over solid only in posemode */
if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
/* draw line check first. we do selection indices */
@@ -1920,11 +1926,11 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
{
if (bone->layer & arm->layer) {
const short constflag = pchan->constflag;
- if ((do_dashed & 1) && (pchan->parent)) {
+ if ((do_dashed & DASH_RELATIONSHIP_LINES) && (pchan->parent)) {
/* Draw a line from our root to the parent's tip
* - only if V3D_HIDE_HELPLINES is enabled...
*/
- if ((do_dashed & 2) && ((bone->flag & BONE_CONNECTED) == 0)) {
+ if ((do_dashed & DASH_HELP_LINES) && ((bone->flag & BONE_CONNECTED) == 0)) {
if (arm->flag & ARM_POSEMODE) {
GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */
UI_ThemeColor(TH_WIRE);
@@ -1947,7 +1953,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
else glColor3ub(200, 200, 50); /* add theme! */
GPU_select_load_id(index & 0xFFFF);
- pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
+ pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES));
}
}
else if (constflag & PCHAN_HAS_SPLINEIK) {
@@ -1955,7 +1961,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glColor3ub(150, 200, 50); /* add theme! */
GPU_select_load_id(index & 0xFFFF);
- pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
+ pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES));
}
}
}
@@ -2076,7 +2082,10 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glMultMatrixf(bmat);
glColor3ubv(col);
- drawaxes(pchan->bone->length * 0.25f, OB_ARROWS);
+
+ float viewmat_pchan[4][4];
+ mul_m4_m4m4(viewmat_pchan, rv3d->viewmatob, bmat);
+ drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS);
glPopMatrix();
}
@@ -2284,7 +2293,10 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
glMultMatrixf(bmat);
glColor3ubv(col);
- drawaxes(eBone->length * 0.25f, OB_ARROWS);
+
+ float viewmat_ebone[4][4];
+ mul_m4_m4m4(viewmat_ebone, rv3d->viewmatob, bmat);
+ drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS);
glPopMatrix();
}
@@ -2590,7 +2602,7 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base)
/* ********************************** Armature Drawing - Main ************************* */
-/* called from drawobject.c, return 1 if nothing was drawn
+/* called from drawobject.c, return true if nothing was drawn
* (ob_wire_col == NULL) when drawing ghost */
bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
const short dt, const short dflag, const unsigned char ob_wire_col[4],
@@ -2602,13 +2614,20 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->flag2 & V3D_RENDER_OVERRIDE)
return true;
-
- if (dt > OB_WIRE && !ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
+
+ if (dt > OB_WIRE) {
/* we use color for solid lighting */
- const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */
+ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
+ const float diffuse[3] = {0.64f, 0.64f, 0.64f};
+ const float specular[3] = {0.5f, 0.5f, 0.5f};
+ GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
+ }
+ else {
+ const float diffuse[3] = {1.0f, 1.0f, 1.0f};
+ const float specular[3] = {1.0f, 1.0f, 1.0f};
+ GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
+ glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */
+ }
}
/* arm->flag is being used to detect mode... */
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index d806dfa015a..345e47940d5 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -60,9 +60,10 @@
#include "UI_resources.h"
-#include "GPU_extensions.h"
#include "GPU_draw.h"
#include "GPU_material.h"
+#include "GPU_basic_shader.h"
+#include "GPU_shader.h"
#include "RE_engine.h"
@@ -166,7 +167,7 @@ static DMDrawOption draw_mesh_face_select__drawFaceOptsInv(void *userData, int i
MPoly *mpoly = &me->mpoly[index];
if (!(mpoly->flag & ME_HIDE) && !(mpoly->flag & ME_FACE_SEL))
- return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
+ return DM_DRAW_OPTION_NORMAL;
else
return DM_DRAW_OPTION_SKIP;
}
@@ -179,7 +180,6 @@ void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool d
data.edge_flags = get_tface_mesh_marked_edge_info(me, draw_select_edges);
glEnable(GL_DEPTH_TEST);
- glDisable(GL_LIGHTING);
ED_view3d_polygon_offset(rv3d, 1.0);
/* Draw (Hidden) Edges */
@@ -231,10 +231,11 @@ static struct TextureDrawState {
int is_lit, is_tex;
int color_profile;
bool use_backface_culling;
+ bool two_sided_lighting;
unsigned char obcol[4];
bool is_texpaint;
bool texpaint_material; /* use material slots for texture painting */
-} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, {0, 0, 0, 0}, false, false};
+} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false};
static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material *ma, struct TextureDrawState gtexdraw)
{
@@ -317,7 +318,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
if (textured) {
if (texpaint) {
c_badtex = false;
- if (GPU_verify_image(ima, NULL, 0, 1, 0, false)) {
+ if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, 0, 1, 0, false)) {
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
@@ -336,7 +337,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
glActiveTexture(GL_TEXTURE0);
}
else {
@@ -370,24 +371,26 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
if (c_badtex) lit = 0;
if (lit != c_lit || ma != c_ma) {
if (lit) {
- float spec[4];
- if (!ma) ma = give_current_material_or_def(NULL, 0); /* default material */
-
- spec[0] = ma->spec * ma->specr;
- spec[1] = ma->spec * ma->specg;
- spec[2] = ma->spec * ma->specb;
- spec[3] = 1.0;
-
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(ma->har, 0, 128));
- glEnable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
+ int options = GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR;
+
+ if (gtexdraw.two_sided_lighting)
+ options |= GPU_SHADER_TWO_SIDED;
+ if (c_textured && !c_badtex)
+ options |= GPU_SHADER_TEXTURE_2D;
+
+ if (!ma)
+ ma = give_current_material_or_def(NULL, 0); /* default material */
+
+ float specular[3];
+ mul_v3_v3fl(specular, &ma->specr, ma->spec);
+
+ GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f);
+ GPU_basic_shader_bind(options);
}
else {
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
+
c_lit = lit;
c_ma = ma;
}
@@ -410,7 +413,16 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
solidtex = false;
Gtexdraw.is_lit = 0;
}
- else if (v3d->drawtype == OB_SOLID || ((ob->mode & OB_MODE_EDIT) && v3d->drawtype != OB_TEXTURE)) {
+ else if ((ob->mode & OB_MODE_TEXTURE_PAINT) && BKE_scene_use_new_shading_nodes(scene)) {
+ solidtex = true;
+ if (v3d->flag2 & V3D_SHADELESS_TEX)
+ Gtexdraw.is_lit = 0;
+ else
+ Gtexdraw.is_lit = -1;
+ }
+ else if ((v3d->drawtype == OB_SOLID) ||
+ ((ob->mode & OB_MODE_EDIT) && (v3d->drawtype != OB_TEXTURE)))
+ {
/* draw with default lights in solid draw mode and edit mode */
solidtex = true;
Gtexdraw.is_lit = -1;
@@ -453,7 +465,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
/* load the stencil texture here */
if (Gtexdraw.stencil != NULL) {
glActiveTexture(GL_TEXTURE2);
- if (GPU_verify_image(Gtexdraw.stencil, NULL, false, false, false, false)) {
+ if (GPU_verify_image(Gtexdraw.stencil, NULL, GL_TEXTURE_2D, false, false, false, false)) {
float col[4] = {imapaint->stencil_col[0], imapaint->stencil_col[1], imapaint->stencil_col[2], 1.0f};
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -479,12 +491,12 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene);
Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0;
Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
+ Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED);
memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
set_draw_settings_cached(1, NULL, NULL, Gtexdraw);
glShadeModel(GL_SMOOTH);
glCullFace(GL_BACK);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE);
}
static void draw_textured_end(void)
@@ -517,7 +529,7 @@ static void draw_textured_end(void)
glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* XXX, bad patch - GPU_default_lights() calls
* glLightfv(GL_POSITION, ...) which
@@ -548,27 +560,28 @@ static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool h
glColor3ub(0xFF, 0x00, 0xFF);
return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
}
- else if (ma && (ma->shade_flag & MA_OBCOLOR)) {
- glColor3ubv(Gtexdraw.obcol);
- return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
- }
else if (!has_mcol) {
if (mtexpoly) {
glColor3f(1.0, 1.0, 1.0);
}
else {
if (ma) {
- float col[3];
- if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
- else copy_v3_v3(col, &ma->r);
-
- glColor3fv(col);
+ if (ma->shade_flag & MA_OBCOLOR) {
+ glColor3ubv(Gtexdraw.obcol);
+ }
+ else {
+ float col[3];
+ if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
+ else copy_v3_v3(col, &ma->r);
+
+ glColor3fv(col);
+ }
}
else {
glColor3f(1.0, 1.0, 1.0);
}
}
- return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */
+ return DM_DRAW_OPTION_NORMAL; /* normal drawing (no mcols anyway, no need to turn off) */
}
else {
return DM_DRAW_OPTION_NORMAL; /* Set color from mcol */
@@ -664,7 +677,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
else if (ma && (ma->shade_flag & MA_OBCOLOR)) {
int loop_index = mp->loopstart;
for (j = 0; j < mp->totloop; j++, loop_index++) {
- copy_v3_v3_char(&finalCol[loop_index].r, (char *)Gtexdraw.obcol);
+ copy_v3_v3_uchar(&finalCol[loop_index].r, Gtexdraw.obcol);
}
copy_mode = COPY_PREV;
}
@@ -806,7 +819,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
/* TEXFACE */
if (glsl) {
- GPU_enable_material(matnr + 1, &gattribs);
+ GPU_object_material_bind(matnr + 1, &gattribs);
for (i = 0; i < gattribs.totlayer; i++) {
if (gattribs.layer[i].type == CD_MTFACE) {
@@ -929,7 +942,6 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
Object *ob, DerivedMesh *dm, const int draw_flags)
{
Mesh *me = ob->data;
- DMDrawFlag uvflag = DM_DRAW_USE_ACTIVE_UV;
/* correct for negative scale */
if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
@@ -940,10 +952,6 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- if (ob->mode & OB_MODE_TEXTURE_PAINT) {
- uvflag = DM_DRAW_USE_TEXPAINT_UV;
- }
-
if (ob->mode & OB_MODE_EDIT) {
drawEMTFMapped_userData data;
@@ -956,34 +964,54 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0);
}
- else if (draw_flags & DRAW_FACE_SELECT) {
- if (ob->mode & OB_MODE_WEIGHT_PAINT)
- dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions_facemask, GPU_enable_material, NULL, me,
- DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN);
+ else {
+ DMDrawFlag dm_draw_flag;
+ drawTFace_userData userData;
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ dm_draw_flag = DM_DRAW_USE_TEXPAINT_UV;
+ }
else {
- drawTFace_userData userData;
+ dm_draw_flag = DM_DRAW_USE_ACTIVE_UV;
+ }
- userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
- userData.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- userData.me = me;
- dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag);
+ if (ob == OBACT) {
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN;
+
+ }
+ else if (ob->mode & OB_MODE_SCULPT) {
+ dm_draw_flag |= DM_DRAW_SKIP_HIDDEN;
+ }
}
- }
- else {
- drawTFace_userData userData;
-
- update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
-
+
+
userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY);
userData.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- userData.me = NULL;
-
- dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag);
+
+ if (draw_flags & DRAW_FACE_SELECT) {
+ userData.me = me;
+
+ dm->drawMappedFacesTex(
+ dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions,
+ &userData, dm_draw_flag);
+ }
+ else {
+ userData.me = NULL;
+
+ update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
+ dm->drawFacesTex(
+ dm, draw_tface__set_draw, compareDrawOptions,
+ &userData, dm_draw_flag);
+ }
}
/* draw game engine text hack */
- if (BKE_bproperty_object_get(ob, "Text"))
- draw_mesh_text(scene, ob, 0);
+ if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
+ if (BKE_bproperty_object_get(ob, "Text")) {
+ draw_mesh_text(scene, ob, 0);
+ }
+ }
draw_textured_end();
@@ -1007,6 +1035,8 @@ typedef struct TexMatCallback {
Object *ob;
Mesh *me;
DerivedMesh *dm;
+ bool shadeless;
+ bool two_sided_lighting;
} TexMatCallback;
static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *attribs)
@@ -1015,7 +1045,7 @@ static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *at
* that the GLSL code will give different result depending on the drawtype,
* in texture draw mode it will output the active texture node, in material
* draw mode it will show the full material. */
- GPU_enable_material(mat_nr, attribs);
+ GPU_object_material_bind(mat_nr, attribs);
}
static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
@@ -1026,31 +1056,21 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
Image *ima;
ImageUser *iuser;
bNode *node;
- int texture_set = 0;
/* draw image texture if we find one */
if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) {
/* get openl texture */
int mipmap = 1;
- int bindcode = (ima) ? GPU_verify_image(ima, iuser, 0, 0, mipmap, false) : 0;
- float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ int bindcode = (ima) ? GPU_verify_image(ima, iuser, GL_TEXTURE_2D, 0, 0, mipmap, false) : 0;
if (bindcode) {
NodeTexBase *texbase = node->storage;
/* disable existing material */
- GPU_disable_material();
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+ GPU_object_material_unbind();
/* bind texture */
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
- glEnable(GL_TEXTURE_2D);
-
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
- glColor3f(1.0f, 1.0f, 1.0f);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(texbase->tex_mapping.mat);
@@ -1064,21 +1084,36 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
gattribs->layer[0].gltexco = 1;
gattribs->totlayer = 1;
- texture_set = 1;
+ /* bind material */
+ float diffuse[3] = {1.0f, 1.0f, 1.0f};
+
+ int options = GPU_SHADER_TEXTURE_2D;
+ if (!data->shadeless)
+ options |= GPU_SHADER_LIGHTING;
+ if (data->two_sided_lighting)
+ options |= GPU_SHADER_TWO_SIDED;
+
+ GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f);
+ GPU_basic_shader_bind(options);
+
+ return;
}
}
- if (!texture_set) {
+ /* disable texture material */
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+
+ if (data->shadeless) {
+ glColor3f(1.0f, 1.0f, 1.0f);
+ memset(gattribs, 0, sizeof(*gattribs));
+ }
+ else {
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
- /* disable texture */
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_COLOR_MATERIAL);
-
- /* draw single color */
- GPU_enable_material(mat_nr, attribs);
+ /* enable solid material */
+ GPU_object_material_bind(mat_nr, attribs);
}
}
@@ -1129,57 +1164,50 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
else glFrontFace(GL_CCW);
- if ((v3d->drawtype == OB_TEXTURE) && (v3d->flag2 & V3D_SHADELESS_TEX))
- glColor3f(1.0f, 1.0f, 1.0f);
- else
- glEnable(GL_LIGHTING);
-
- {
- Mesh *me = ob->data;
- TexMatCallback data = {scene, ob, me, dm};
- bool (*set_face_cb)(void *, int);
- bool glsl, picking = (G.f & G_PICKSEL) != 0;
-
- /* face hiding callback depending on mode */
- if (ob == scene->obedit)
- set_face_cb = tex_mat_set_face_editmesh_cb;
- else if (draw_flags & DRAW_FACE_SELECT)
- set_face_cb = tex_mat_set_face_mesh_cb;
- else
- set_face_cb = NULL;
-
- /* test if we can use glsl */
- glsl = (v3d->drawtype == OB_MATERIAL) && GPU_glsl_support() && !picking;
+ Mesh *me = ob->data;
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+ bool shadeless = ((v3d->flag2 & V3D_SHADELESS_TEX) &&
+ ((v3d->drawtype == OB_TEXTURE) || (ob->mode & OB_MODE_TEXTURE_PAINT)));
+ bool two_sided_lighting = (me->flag & ME_TWOSIDED) != 0;
- if (glsl || picking) {
- /* draw glsl or solid */
- dm->drawMappedFacesMat(dm,
- tex_mat_set_material_cb,
- set_face_cb, &data);
- }
- else {
- float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ TexMatCallback data = {scene, ob, me, dm, shadeless, two_sided_lighting};
+ bool (*set_face_cb)(void *, int);
+ bool picking = (G.f & G_PICKSEL) != 0;
+
+ /* face hiding callback depending on mode */
+ if (ob == scene->obedit)
+ set_face_cb = tex_mat_set_face_editmesh_cb;
+ else if (draw_flags & DRAW_FACE_SELECT)
+ set_face_cb = tex_mat_set_face_mesh_cb;
+ else
+ set_face_cb = NULL;
- /* draw textured */
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0);
+ /* test if we can use glsl */
+ bool glsl = (v3d->drawtype == OB_MATERIAL) && !picking;
- dm->drawMappedFacesMat(dm,
- tex_mat_set_texture_cb,
- set_face_cb, &data);
- }
+ GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
- GPU_end_object_materials();
+ if (glsl || picking) {
+ /* draw glsl or solid */
+ dm->drawMappedFacesMat(dm,
+ tex_mat_set_material_cb,
+ set_face_cb, &data);
}
+ else {
+ /* draw textured */
+ dm->drawMappedFacesMat(dm,
+ tex_mat_set_texture_cb,
+ set_face_cb, &data);
+ }
+
+ GPU_end_object_materials();
/* reset opengl state */
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_LIGHTING);
+ GPU_end_object_materials();
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+
glBindTexture(GL_TEXTURE_2D, 0);
+
glFrontFace(GL_CCW);
glMatrixMode(GL_TEXTURE);
@@ -1196,38 +1224,29 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/* Vertex Paint and Weight Paint */
static void draw_mesh_paint_light_begin(void)
{
- const float spec[4] = {0.47f, 0.47f, 0.47f, 0.47f};
-
- GPU_enable_material(0, NULL);
-
- /* but set default spec */
- glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
-
- /* diffuse */
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
+ /* get material diffuse color from vertex colors but set default spec */
+ const float specular[3] = {0.47f, 0.47f, 0.47f};
+ GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
}
+
static void draw_mesh_paint_light_end(void)
{
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
-
- GPU_disable_material();
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light,
void *facemask_cb, void *user_data)
{
- DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_enable_material : NULL;
+ DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL;
+ int flags = DM_DRAW_USE_COLORS;
if (use_light) {
draw_mesh_paint_light_begin();
+ flags |= DM_DRAW_NEED_NORMALS;
}
- dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data,
- DM_DRAW_USE_COLORS);
+ dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data, flags);
if (use_light) {
draw_mesh_paint_light_end();
@@ -1238,18 +1257,21 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light,
void *facemask_cb, void *user_data,
const Mesh *me)
{
- DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_enable_material : NULL;
+ DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL;
+ int flags = 0;
if (use_light) {
draw_mesh_paint_light_begin();
+ flags |= DM_DRAW_NEED_NORMALS;
}
if (me->mloopcol) {
- dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, DM_DRAW_USE_COLORS);
+ dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data,
+ DM_DRAW_USE_COLORS | flags);
}
else {
glColor3f(1.0f, 1.0f, 1.0f);
- dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, 0);
+ dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, flags);
}
if (use_light) {
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 4e9818deb72..65f1f375443 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -87,8 +87,9 @@
#include "BIF_glutil.h"
#include "GPU_draw.h"
-#include "GPU_extensions.h"
#include "GPU_select.h"
+#include "GPU_basic_shader.h"
+#include "GPU_shader.h"
#include "ED_mesh.h"
#include "ED_particle.h"
@@ -134,7 +135,6 @@ typedef struct drawDMVerts_userData {
unsigned char th_vertex_select[4];
unsigned char th_vertex[4];
unsigned char th_skin_root[4];
- float th_vertex_size;
/* for skin node drawing */
int cd_vskin_offset;
@@ -214,7 +214,7 @@ static void drawcube_size(float size);
static void drawcircle_size(float size);
static void draw_empty_sphere(float size);
static void draw_empty_cone(float size);
-static void draw_box(float vec[8][3], bool solid);
+static void draw_box(const float vec[8][3], bool solid);
static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac)
{
@@ -289,8 +289,6 @@ static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt)
bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
{
- if (!GPU_glsl_support())
- return false;
if (G.f & G_PICKSEL)
return false;
if (!check_object_draw_texture(scene, v3d, dt))
@@ -403,98 +401,117 @@ static const float cosval[CIRCLE_RESOL] = {
1.00000000
};
-static void draw_xyz_wire(const float c[3], float size, int axis)
+/**
+ * \param viewmat_local_unit is typically the 'rv3d->viewmatob'
+ * copied into a 3x3 matrix and normalized.
+ */
+static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis)
{
+ int line_type;
+ float buffer[4][3];
+ int n = 0;
+
float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f};
float dim = size * 0.1f;
- float dx[3], dy[3], dz[3];
+ float dx[3], dy[3];
dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f;
dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f;
- dz[0] = 0.0f; dz[1] = 0.0f; dz[2] = dim;
switch (axis) {
case 0: /* x axis */
- glBegin(GL_LINES);
-
+ line_type = GL_LINES;
+
/* bottom left to top right */
- sub_v3_v3v3(v1, c, dx);
+ negate_v3_v3(v1, dx);
sub_v3_v3(v1, dy);
- add_v3_v3v3(v2, c, dx);
+ copy_v3_v3(v2, dx);
add_v3_v3(v2, dy);
-
- glVertex3fv(v1);
- glVertex3fv(v2);
+
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
/* top left to bottom right */
mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
sub_v3_v3(v2, dy);
- glVertex3fv(v1);
- glVertex3fv(v2);
-
- glEnd();
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
+
break;
case 1: /* y axis */
- glBegin(GL_LINES);
+ line_type = GL_LINES;
/* bottom left to top right */
mul_v3_fl(dx, 0.75f);
- sub_v3_v3v3(v1, c, dx);
+ negate_v3_v3(v1, dx);
sub_v3_v3(v1, dy);
- add_v3_v3v3(v2, c, dx);
+ copy_v3_v3(v2, dx);
add_v3_v3(v2, dy);
- glVertex3fv(v1);
- glVertex3fv(v2);
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
/* top left to center */
mul_v3_fl(dy, 2.0f);
add_v3_v3(v1, dy);
- copy_v3_v3(v2, c);
+ zero_v3(v2);
- glVertex3fv(v1);
- glVertex3fv(v2);
+ copy_v3_v3(buffer[n++], v1);
+ copy_v3_v3(buffer[n++], v2);
- glEnd();
break;
case 2: /* z axis */
- glBegin(GL_LINE_STRIP);
+ line_type = GL_LINE_STRIP;
/* start at top left */
- sub_v3_v3v3(v1, c, dx);
- add_v3_v3v3(v1, c, dz);
+ negate_v3_v3(v1, dx);
+ add_v3_v3(v1, dy);
- glVertex3fv(v1);
+ copy_v3_v3(buffer[n++], v1);
mul_v3_fl(dx, 2.0f);
add_v3_v3(v1, dx);
- glVertex3fv(v1);
+ copy_v3_v3(buffer[n++], v1);
- mul_v3_fl(dz, 2.0f);
+ mul_v3_fl(dy, 2.0f);
sub_v3_v3(v1, dx);
- sub_v3_v3(v1, dz);
+ sub_v3_v3(v1, dy);
- glVertex3fv(v1);
+ copy_v3_v3(buffer[n++], v1);
add_v3_v3(v1, dx);
- glVertex3fv(v1);
+ copy_v3_v3(buffer[n++], v1);
- glEnd();
break;
+ default:
+ BLI_assert(0);
+ return;
}
+
+ for (int i = 0; i < n; i++) {
+ mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]);
+ add_v3_v3(buffer[i], c);
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, buffer);
+ glDrawArrays(line_type, 0, n);
+ glDisableClientState(GL_VERTEX_ARRAY);
}
-void drawaxes(float size, char drawtype)
+void drawaxes(const float viewmat_local[4][4], float size, char drawtype)
{
int axis;
float v1[3] = {0.0, 0.0, 0.0};
float v2[3] = {0.0, 0.0, 0.0};
float v3[3] = {0.0, 0.0, 0.0};
-
+
+ glLineWidth(1);
+
switch (drawtype) {
case OB_PLAINAXES:
@@ -565,6 +582,11 @@ void drawaxes(float size, char drawtype)
case OB_ARROWS:
default:
{
+ float viewmat_local_unit[3][3];
+
+ copy_m3_m4(viewmat_local_unit, (float (*)[4])viewmat_local);
+ normalize_m3(viewmat_local_unit);
+
for (axis = 0; axis < 3; axis++) {
const int arrow_axis = (axis == 0) ? 1 : 0;
@@ -587,7 +609,7 @@ void drawaxes(float size, char drawtype)
v2[axis] += size * 0.125f;
- draw_xyz_wire(v2, size, axis);
+ draw_xyz_wire(viewmat_local_unit, v2, size, axis);
/* reset v1 & v2 to zero */
@@ -605,13 +627,12 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
Image *ima = ob->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL);
- float scale, ofs_x, ofs_y, sca_x, sca_y;
- int ima_x, ima_y;
-
if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) {
IMB_rect_from_float(ibuf);
}
+ int ima_x, ima_y;
+
/* Get the buffer dimensions so we can fallback to fake ones */
if (ibuf && ibuf->rect) {
ima_x = ibuf->x;
@@ -622,45 +643,38 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
ima_y = 1;
}
+ float sca_x = 1.0f;
+ float sca_y = 1.0f;
+
/* Get the image aspect even if the buffer is invalid */
if (ima) {
if (ima->aspx > ima->aspy) {
- sca_x = 1.0f;
sca_y = ima->aspy / ima->aspx;
}
else if (ima->aspx < ima->aspy) {
sca_x = ima->aspx / ima->aspy;
- sca_y = 1.0f;
- }
- else {
- sca_x = 1.0f;
- sca_y = 1.0f;
}
}
- else {
- sca_x = 1.0f;
- sca_y = 1.0f;
- }
/* Calculate the scale center based on object's origin */
- ofs_x = ob->ima_ofs[0] * ima_x;
- ofs_y = ob->ima_ofs[1] * ima_y;
+ float ofs_x = ob->ima_ofs[0] * ima_x;
+ float ofs_y = ob->ima_ofs[1] * ima_y;
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
/* Calculate Image scale */
- scale = (ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y));
+ float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y);
/* Set the object scale */
glScalef(scale * sca_x, scale * sca_y, 1.0f);
if (ibuf && ibuf->rect) {
const bool use_clip = (U.glalphaclip != 1.0f);
- int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP ) ? GL_NEAREST : GL_LINEAR;
+ int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR;
/* Setup GL params */
glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (use_clip) {
glEnable(GL_ALPHA_TEST);
@@ -672,13 +686,12 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
/* Draw the Image on the screen */
glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect);
- glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
glDisable(GL_BLEND);
if (use_clip) {
glDisable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, 0.0f);
+ glAlphaFunc(GL_ALWAYS, 0.0f);
}
}
@@ -694,31 +707,28 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
glVertex2f(ofs_x, ofs_y + ima_y);
glEnd();
-
/* Reset GL settings */
- glMatrixMode(GL_MODELVIEW);
glPopMatrix();
BKE_image_release_ibuf(ima, ibuf, NULL);
}
-static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, float tmat[4][4])
+static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4])
{
float vx[3], vy[3];
float *viter = (float *)verts;
- unsigned int a;
mul_v3_v3fl(vx, tmat[0], rad);
mul_v3_v3fl(vy, tmat[1], rad);
- for (a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
+ for (unsigned int a = 0; a < CIRCLE_RESOL; a++, viter += 3) {
viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0];
viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1];
viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2];
}
}
-void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4])
+void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4])
{
float verts[CIRCLE_RESOL][3];
@@ -736,8 +746,8 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
float verts[CIRCLE_RESOL][3];
- /* using gldepthfunc guarantees that it does write z values,
- * but not checks for it, so centers remain visible independent order of drawing */
+ /* using glDepthFunc guarantees that it does write z values,
+ * but not checks for it, so centers remain visible independent of draw order */
if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
/* write to near buffer always */
glDepthRange(0.0, 0.0);
@@ -745,7 +755,6 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
if (special_color) {
if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
-
else glColor4ub(0x55, 0xCC, 0xCC, 155);
}
else {
@@ -764,6 +773,7 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL);
/* 2. draw outline */
+ glLineWidth(1);
UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL);
@@ -829,7 +839,7 @@ void view3d_cached_text_draw_add(const float co[3],
BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos);
copy_v3_v3(vos->vec, co);
- copy_v4_v4_char((char *)vos->col.ub, (const char *)col);
+ copy_v4_v4_uchar(vos->col.ub, col);
vos->xoffs = xoffs;
vos->flag = flag;
vos->str_len = str_len;
@@ -883,7 +893,7 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- wmOrtho2_region_ui(ar);
+ wmOrtho2_region_pixelspace(ar);
glLoadIdentity();
if (depth_write) {
@@ -947,59 +957,24 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
*/
static void drawcube_size(float size)
{
- glBegin(GL_LINE_STRIP);
- glVertex3f(-size, -size, -size); glVertex3f(-size, -size, size);
- glVertex3f(-size, size, size); glVertex3f(-size, size, -size);
-
- glVertex3f(-size, -size, -size); glVertex3f(size, -size, -size);
- glVertex3f(size, -size, size); glVertex3f(size, size, size);
-
- glVertex3f(size, size, -size); glVertex3f(size, -size, -size);
- glEnd();
-
- glBegin(GL_LINE_STRIP);
- glVertex3f(-size, -size, size); glVertex3f(size, -size, size);
- glEnd();
-
- glBegin(GL_LINE_STRIP);
- glVertex3f(-size, size, size); glVertex3f(size, size, size);
- glEnd();
-
- glBegin(GL_LINE_STRIP);
- glVertex3f(-size, size, -size); glVertex3f(size, size, -size);
- glEnd();
-}
-
-/* this is an unused (old) cube-drawing function based on a given size */
-#if 0
-static void drawcube_size(const float size[3])
-{
-
- glPushMatrix();
- glScale3fv(size);
-
-
- glBegin(GL_LINE_STRIP);
- glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
- glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]);
- glVertex3fv(cube[7]); glVertex3fv(cube[4]);
- glEnd();
+ const GLfloat pos[8][3] = {
+ {-size, -size, -size},
+ {-size, -size, size},
+ {-size, size, -size},
+ {-size, size, size},
+ { size, -size, -size},
+ { size, -size, size},
+ { size, size, -size},
+ { size, size, size}
+ };
- glBegin(GL_LINE_STRIP);
- glVertex3fv(cube[1]); glVertex3fv(cube[5]);
- glEnd();
+ const GLubyte indices[24] = {0,1,1,3,3,2,2,0,0,4,4,5,5,7,7,6,6,4,1,5,3,7,2,6};
- glBegin(GL_LINE_STRIP);
- glVertex3fv(cube[2]); glVertex3fv(cube[6]);
- glEnd();
-
- glBegin(GL_LINE_STRIP);
- glVertex3fv(cube[3]); glVertex3fv(cube[7]);
- glEnd();
-
- glPopMatrix();
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, pos);
+ glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
+ glDisableClientState(GL_VERTEX_ARRAY);
}
-#endif
static void drawshadbuflimits(Lamp *la, float mat[4][4])
{
@@ -1011,17 +986,16 @@ static void drawshadbuflimits(Lamp *la, float mat[4][4])
madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta);
madd_v3_v3v3fl(end, mat[3], lavec, la->clipend);
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex3fv(sta);
glVertex3fv(end);
glEnd();
glPointSize(3.0);
- bglBegin(GL_POINTS);
- bglVertex3fv(sta);
- bglVertex3fv(end);
- bglEnd();
- glPointSize(1.0);
+ glBegin(GL_POINTS);
+ glVertex3fv(sta);
+ glVertex3fv(end);
+ glEnd();
}
static void spotvolume(float lvec[3], float vvec[3], const float inp)
@@ -1085,8 +1059,6 @@ static void spotvolume(float lvec[3], float vvec[3], const float inp)
mul_m3_v3(mat2, lvec);
mul_m3_m3m3(mat2, mat1, mat4);
mul_m3_v3(mat2, vvec);
-
- return;
}
static void draw_spot_cone(Lamp *la, float x, float z)
@@ -1104,11 +1076,8 @@ static void draw_spot_cone(Lamp *la, float x, float z)
glVertex3f(z, z, 0);
}
else {
- float angle;
- int a;
-
- for (a = 0; a < 33; a++) {
- angle = a * M_PI * 2 / (33 - 1);
+ for (int a = 0; a < 33; a++) {
+ float angle = a * M_PI * 2 / (33 - 1);
glVertex3f(z * cosf(angle), z * sinf(angle), 0);
}
}
@@ -1198,7 +1167,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
Object *ob = base->object;
const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]);
Lamp *la = ob->data;
- float vec[3], lvec[3], vvec[3], circrad, x, y, z;
+ float vec[3], lvec[3], vvec[3], circrad;
float lampsize;
float imat[4][4];
@@ -1259,6 +1228,8 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
glColor4ubv(curcol);
}
+ glLineWidth(1);
+
if (lampsize > 0.0f) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1344,8 +1315,8 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
if (is_view) {
/* skip drawing extra info */
}
- else if ((la->type == LA_SPOT) || (la->type == LA_YF_PHOTON)) {
-
+ else if (la->type == LA_SPOT) {
+ float x, y, z, z_abs;
copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f);
copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]);
mul_transposed_mat3_m4_v3(ob->obmat, vvec);
@@ -1358,46 +1329,75 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
mul_v3_fl(lvec, x);
mul_v3_fl(vvec, x);
- /* draw the angled sides of the cone */
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vvec);
- glVertex3fv(vec);
- glVertex3fv(lvec);
- glEnd();
-
x *= y;
- /* draw the circle/square at the end of the cone */
- glTranslatef(0.0, 0.0, x);
+ z_abs = fabsf(z);
+
if (la->mode & LA_SQUARE) {
- float tvec[3];
- float z_abs = fabsf(z);
-
- tvec[0] = tvec[1] = z_abs;
- tvec[2] = 0.0;
-
- glBegin(GL_LINE_LOOP);
- glVertex3fv(tvec);
- tvec[1] = -z_abs; /* neg */
- glVertex3fv(tvec);
- tvec[0] = -z_abs; /* neg */
- glVertex3fv(tvec);
- tvec[1] = z_abs; /* pos */
- glVertex3fv(tvec);
- glEnd();
+ /* draw pyramid */
+ const float vertices[5][3] = {
+ /* 5 of vertex coords of pyramid */
+ {0.0f, 0.0f, 0.0f},
+ {z_abs, z_abs, x},
+ {-z_abs, -z_abs, x},
+ {z_abs, -z_abs, x},
+ {-z_abs, z_abs, x},
+ };
+ const unsigned char indices[] = {
+ 0, 1, 3,
+ 0, 3, 2,
+ 0, 2, 4,
+ 0, 1, 4,
+ };
+
+ /* Draw call:
+ * activate and specify pointer to vertex array */
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vertices);
+ /* draw the pyramid */
+ glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices);
+
+ /* deactivate vertex arrays after drawing */
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glTranslatef(0.0f, 0.0f, x);
+
+ /* draw the square representing spotbl */
+ if (la->type == LA_SPOT) {
+ float blend = z_abs * (1.0f - pow2f(la->spotblend));
+
+ /* hide line if it is zero size or overlaps with outer border,
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
+ if (blend != 0.0f && blend != z_abs) {
+ fdrawbox(blend, -blend, -blend, blend);
+ }
+ }
}
else {
- circ(0.0, 0.0, fabsf(z));
- }
- /* draw the circle/square representing spotbl */
- if (la->type == LA_SPOT) {
- float spotblcirc = fabsf(z) * (1.0f - pow2f(la->spotblend));
- /* hide line if it is zero size or overlaps with outer border,
- * previously it adjusted to always to show it but that seems
- * confusing because it doesn't show the actual blend size */
- if (spotblcirc != 0 && spotblcirc != fabsf(z))
- circ(0.0, 0.0, spotblcirc);
+ /* draw the angled sides of the cone */
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vvec);
+ glVertex3fv(vec);
+ glVertex3fv(lvec);
+ glEnd();
+
+ /* draw the circle at the end of the cone */
+ glTranslatef(0.0f, 0.0f, x);
+ circ(0.0f, 0.0f, z_abs);
+
+ /* draw the circle representing spotbl */
+ if (la->type == LA_SPOT) {
+ float blend = z_abs * (1.0f - pow2f(la->spotblend));
+
+ /* hide line if it is zero size or overlaps with outer border,
+ * previously it adjusted to always to show it but that seems
+ * confusing because it doesn't show the actual blend size */
+ if (blend != 0.0f && blend != z_abs) {
+ circ(0.0f, 0.0f, blend);
+ }
+ }
}
if (drawcone)
@@ -1405,6 +1405,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
/* draw clip start, useful for wide cones where its not obvious where the start is */
glTranslatef(0.0, 0.0, -x); /* reverse translation above */
+ glBegin(GL_LINES);
if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) {
float lvec_clip[3];
float vvec_clip[3];
@@ -1413,23 +1414,20 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac);
interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac);
- glBegin(GL_LINE_STRIP);
glVertex3fv(lvec_clip);
glVertex3fv(vvec_clip);
- glEnd();
}
/* Else, draw spot direction (using distance as end limit, same as for Area lamp). */
else {
- glBegin(GL_LINE_STRIP);
glVertex3f(0.0, 0.0, -circrad);
glVertex3f(0.0, 0.0, -la->dist);
- glEnd();
}
+ glEnd();
}
else if (ELEM(la->type, LA_HEMI, LA_SUN)) {
/* draw the line from the circle along the dist */
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
vec[2] = -circrad;
glVertex3fv(vec);
vec[2] = -la->dist;
@@ -1489,7 +1487,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
else if (la->area_shape == LA_AREA_RECT)
fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f);
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex3f(0.0, 0.0, -circrad);
glVertex3f(0.0, 0.0, -la->dist);
glEnd();
@@ -1516,7 +1514,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
if (vec[2] > 0) vec[2] -= circrad;
else vec[2] += circrad;
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex3fv(vec);
vec[2] = 0;
glVertex3fv(vec);
@@ -1526,7 +1524,6 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
glBegin(GL_POINTS);
glVertex3fv(vec);
glEnd();
- glPointSize(1.0);
glDisable(GL_BLEND);
@@ -1538,7 +1535,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
glPopMatrix();
}
-static void draw_limit_line(float sta, float end, const short dflag, unsigned int col)
+static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3])
{
glBegin(GL_LINES);
glVertex3f(0.0, 0.0, -sta);
@@ -1549,12 +1546,11 @@ static void draw_limit_line(float sta, float end, const short dflag, unsigned in
glPointSize(3.0);
glBegin(GL_POINTS);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
- cpack(col);
+ glColor3ubv(col);
}
glVertex3f(0.0, 0.0, -sta);
glVertex3f(0.0, 0.0, -end);
glEnd();
- glPointSize(1.0);
}
}
@@ -1601,10 +1597,11 @@ static void draw_bundle_sphere(void)
glCallList(displist);
}
-static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D *v3d,
- MovieClip *clip, MovieTrackingObject *tracking_object,
- const short dflag, const unsigned char ob_wire_col[4],
- int *global_track_index, bool draw_selected)
+static void draw_viewport_object_reconstruction(
+ Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d,
+ MovieClip *clip, MovieTrackingObject *tracking_object,
+ const short dflag, const unsigned char ob_wire_col[4],
+ int *global_track_index, bool draw_selected)
{
MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *track;
@@ -1665,8 +1662,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
v3d->bundle_size / 0.05f / camera_size[2]);
if (v3d->drawtype == OB_WIRE) {
- glDisable(GL_LIGHTING);
-
if ((dflag & DRAW_CONSTCOLOR) == 0) {
if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) {
glColor3ubv(ob_wire_col);
@@ -1676,9 +1671,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
}
}
- drawaxes(0.05f, v3d->bundle_drawtype);
-
- glEnable(GL_LIGHTING);
+ drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
}
else if (v3d->drawtype > OB_WIRE) {
if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) {
@@ -1689,14 +1682,11 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
}
glLineWidth(2.0f);
- glDisable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
draw_bundle_sphere();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- glEnable(GL_LIGHTING);
- glLineWidth(1.0f);
}
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -1707,8 +1697,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
draw_bundle_sphere();
}
else {
- glDisable(GL_LIGHTING);
-
if ((dflag & DRAW_CONSTCOLOR) == 0) {
if (selected) {
glColor3ubv(ob_wire_col);
@@ -1719,9 +1707,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
}
}
- drawaxes(0.05f, v3d->bundle_drawtype);
-
- glEnable(GL_LIGHTING);
+ drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype);
}
}
@@ -1747,20 +1733,15 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
if (reconstruction->camnr) {
MovieReconstructedCamera *camera = reconstruction->cameras;
- int a = 0;
- glDisable(GL_LIGHTING);
UI_ThemeColor(TH_CAMERA_PATH);
glLineWidth(2.0f);
glBegin(GL_LINE_STRIP);
- for (a = 0; a < reconstruction->camnr; a++, camera++) {
+ for (int a = 0; a < reconstruction->camnr; a++, camera++) {
glVertex3fv(camera->mat[3]);
}
glEnd();
-
- glLineWidth(1.0f);
- glEnable(GL_LIGHTING);
}
}
}
@@ -1770,9 +1751,10 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
*global_track_index = tracknr;
}
-static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, MovieClip *clip,
- const short dflag, const unsigned char ob_wire_col[4],
- const bool draw_selected)
+static void draw_viewport_reconstruction(
+ Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip,
+ const short dflag, const unsigned char ob_wire_col[4],
+ const bool draw_selected)
{
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *tracking_object;
@@ -1784,23 +1766,23 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d,
if (v3d->flag2 & V3D_RENDER_OVERRIDE)
return;
- glEnable(GL_LIGHTING);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
+ GPU_basic_shader_colors(NULL, NULL, 0, 1.0f);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
+
glShadeModel(GL_SMOOTH);
tracking_object = tracking->objects.first;
while (tracking_object) {
- draw_viewport_object_reconstruction(scene, base, v3d, clip, tracking_object,
- dflag, ob_wire_col, &global_track_index, draw_selected);
+ draw_viewport_object_reconstruction(
+ scene, base, v3d, rv3d, clip, tracking_object,
+ dflag, ob_wire_col, &global_track_index, draw_selected);
tracking_object = tracking_object->next;
}
/* restore */
glShadeModel(GL_FLAT);
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
if ((dflag & DRAW_CONSTCOLOR) == 0) {
glColor3ubv(ob_wire_col);
@@ -1876,7 +1858,6 @@ static void drawcamera_stereo3d(
Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam,
float vec[4][3], float drawsize, const float scale[3])
{
- int i, j;
float obmat[4][4];
float vec_lr[2][4][3];
const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f;
@@ -1893,7 +1874,7 @@ static void drawcamera_stereo3d(
glPushMatrix();
- for (i = 0; i < 2; i++) {
+ for (int i = 0; i < 2; i++) {
ob = BKE_camera_multiview_render(scene, ob, names[i]);
cam_lr[i] = ob->data;
@@ -1909,7 +1890,7 @@ static void drawcamera_stereo3d(
((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) *
(drawsize * scale[0] * fac));
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
vec_lr[i][j][0] += shift_x;
}
}
@@ -1927,7 +1908,7 @@ static void drawcamera_stereo3d(
/* convergence plane */
if (is_stereo3d_plane || is_stereo3d_volume) {
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
mul_m4_v3(obmat, vec_lr[i][j]);
}
}
@@ -1951,7 +1932,7 @@ static void drawcamera_stereo3d(
glPopAttrib();
}
- /* draw convergence plane*/
+ /* draw convergence plane */
if (is_stereo3d_plane) {
float axis_center[3], screen_center[3];
float world_plane[4][3];
@@ -1960,7 +1941,7 @@ static void drawcamera_stereo3d(
mid_v3_v3v3(axis_center, origin[0], origin[1]);
- for (i = 0; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]);
sub_v3_v3v3(local_plane[i], world_plane[i], axis_center);
}
@@ -1968,7 +1949,7 @@ static void drawcamera_stereo3d(
mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]);
offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center);
- for (i = 0; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
mul_v3_fl(local_plane[i], offset);
add_v3_v3(local_plane[i], axis_center);
}
@@ -1991,19 +1972,17 @@ static void drawcamera_stereo3d(
}
}
- /* draw convergence plane*/
+ /* draw convergence plane */
if (is_stereo3d_volume) {
float screen_center[3];
float near_plane[4][3], far_plane[4][3];
- float offset;
- int j;
- for (i = 0; i < 2; i++) {
+ for (int i = 0; i < 2; i++) {
mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]);
- offset = len_v3v3(screen_center, origin[i]);
+ float offset = len_v3v3(screen_center, origin[i]);
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]);
mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset);
add_v3_v3(near_plane[j], origin[i]);
@@ -2051,11 +2030,10 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
Object *ob = base->object;
float tvec[3];
float vec[4][3], asp[2], shift[2], scale[3];
- int i;
- float drawsize;
MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false);
- const bool is_view = (rv3d->persp == RV3D_CAMOB && ob == v3d->camera);
+ const bool is_active = (ob == v3d->camera);
+ const bool is_view = (rv3d->persp == RV3D_CAMOB && is_active);
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob);
const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D);
@@ -2069,8 +2047,8 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
/* draw data for movie clip set as active for scene */
if (clip) {
- draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, false);
- draw_viewport_reconstruction(scene, base, v3d, clip, dflag, ob_wire_col, true);
+ draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, false);
+ draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, true);
}
#ifdef VIEW3D_CAMERA_BORDER_HACK
@@ -2104,11 +2082,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
scale[2] = 1.0f / len_v3(ob->obmat[2]);
}
+ float drawsize;
BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
asp, shift, &drawsize, vec);
- glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
+ glLineWidth(1);
/* camera frame */
if (!is_stereo3d_cameras) {
@@ -2145,9 +2124,9 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
/* draw an outline arrow for inactive cameras and filled
* for active cameras. We actually draw both outline+filled
* for active cameras so the wire can be seen side-on */
- for (i = 0; i < 2; i++) {
+ for (int i = 0; i < 2; i++) {
if (i == 0) glBegin(GL_LINE_LOOP);
- else if (i == 1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES);
+ else if (i == 1 && is_active) glBegin(GL_TRIANGLES);
else break;
tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]);
@@ -2177,15 +2156,20 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base
glMultMatrixf(nobmat);
if (cam->flag & CAM_SHOWLIMITS) {
- draw_limit_line(cam->clipsta, cam->clipend, dflag, 0x77FFFF);
+ const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120};
+
+ draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col));
/* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */
draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize);
}
if (cam->flag & CAM_SHOWMIST) {
World *world = scene->world;
+ const unsigned char col[3] = {128, 128, 128}, col_hi[3] = {255, 255, 255};
+
if (world) {
- draw_limit_line(world->miststa, world->miststa + world->mistdist, dflag, 0xFFFFFF);
+ draw_limit_line(world->miststa, world->miststa + world->mistdist,
+ dflag, (is_active ? col_hi : col));
}
}
glPopMatrix();
@@ -2203,15 +2187,15 @@ static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D
Object *UNUSED(ob), int UNUSED(flag))
{
float vec[3];
- int i, j;
glEnable(GL_BLEND);
+ glLineWidth(1);
- for (j = 0; j < 3; j++) {
+ for (int j = 0; j < 3; j++) {
vec[2] = 0.25f * j - 0.125f;
glBegin(GL_LINE_LOOP);
- for (i = 0; i < 16; i++) {
+ for (int i = 0; i < 16; i++) {
vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f);
glVertex3fv(vec);
@@ -2219,11 +2203,11 @@ static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D
glEnd();
}
- for (j = 0; j < 4; j++) {
+ for (int j = 0; j < 4; j++) {
vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f;
vec[1] = ((j % 2) * (j - 2)) * 0.5f;
glBegin(GL_LINE_STRIP);
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
if (i == 1) {
vec[0] *= 0.5f;
vec[1] *= 0.5f;
@@ -2242,30 +2226,29 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
{
BPoint *bp = lt->def;
const float *co = dl ? dl->verts : NULL;
- int u, v, w;
const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
UI_ThemeColor(color);
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
- for (w = 0; w < lt->pntsw; w++) {
+ for (int w = 0; w < lt->pntsw; w++) {
int wxt = (w == 0 || w == lt->pntsw - 1);
- for (v = 0; v < lt->pntsv; v++) {
+ for (int v = 0; v < lt->pntsv; v++) {
int vxt = (v == 0 || v == lt->pntsv - 1);
- for (u = 0; u < lt->pntsu; u++, bp++, co += 3) {
+ for (int u = 0; u < lt->pntsu; u++, bp++, co += 3) {
int uxt = (u == 0 || u == lt->pntsu - 1);
if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
if (bp->hide == 0) {
/* check for active BPoint and ensure selected */
if ((bp == actbp) && (bp->f1 & SELECT)) {
UI_ThemeColor(TH_ACTIVE_VERT);
- bglVertex3fv(dl ? co : bp->vec);
+ glVertex3fv(dl ? co : bp->vec);
UI_ThemeColor(color);
}
else if ((bp->f1 & SELECT) == sel) {
- bglVertex3fv(dl ? co : bp->vec);
+ glVertex3fv(dl ? co : bp->vec);
}
}
}
@@ -2273,8 +2256,7 @@ static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short s
}
}
- bglEnd();
- glPointSize(1.0);
+ glEnd();
}
static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol)
@@ -2362,7 +2344,8 @@ static void drawlattice(View3D *v3d, Object *ob)
glShadeModel(GL_SMOOTH);
}
}
-
+
+ glLineWidth(1);
glBegin(GL_LINES);
for (w = 0; w < lt->pntsw; w++) {
int wxt = (w == 0 || w == lt->pntsw - 1);
@@ -2406,7 +2389,7 @@ static void drawlattice(View3D *v3d, Object *ob)
/* ***************** ******************** */
-/* draw callback */
+/* draw callback */
typedef struct drawDMVertSel_userData {
MVert *mvert;
@@ -2527,16 +2510,16 @@ static void draw_dm_face_centers__mapFunc(void *userData, int index, const float
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
(BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
{
- bglVertex3fv(cent);
+ glVertex3fv(cent);
}
}
static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
{
drawBMSelect_userData data = {em->bm, select};
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
- bglEnd();
+ glEnd();
}
static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
@@ -2597,33 +2580,26 @@ static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3],
const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset);
if (vs->flag & MVERT_SKIN_ROOT) {
float radius = (vs->radius[0] + vs->radius[1]) * 0.5f;
- bglEnd();
+ glEnd();
glColor4ubv(data->th_skin_root);
drawcircball(GL_LINES, co, radius, data->imat);
glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
}
}
- /* draw active larger - need to stop/start point drawing for this :/ */
+ /* draw active in a different color - no need to stop/start point drawing for this :D */
if (eve == data->eve_act) {
glColor4ubv(data->th_editmesh_active);
-
- bglEnd();
-
- glPointSize(data->th_vertex_size);
- bglBegin(GL_POINTS);
- bglVertex3fv(co);
- bglEnd();
+ glVertex3fv(co);
+ /* back to regular vertex color */
glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex);
- glPointSize(data->th_vertex_size);
- bglBegin(GL_POINTS);
}
else {
- bglVertex3fv(co);
+ glVertex3fv(co);
}
}
}
@@ -2641,7 +2617,6 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select);
UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex);
UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root);
- data.th_vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
/* For skin root drawing */
data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN);
@@ -2649,9 +2624,10 @@ static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVer
mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat);
invert_m4(data.imat);
- bglBegin(GL_POINTS);
+ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
+ glBegin(GL_POINTS);
dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP);
- bglEnd();
+ glEnd();
}
/* Draw edges with color set based on selection */
@@ -2686,6 +2662,7 @@ static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index)
return DM_DRAW_OPTION_SKIP;
}
}
+
static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
{
@@ -2901,11 +2878,11 @@ static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
#ifdef WITH_FREESTYLE
-static int draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
+static bool draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed)
{
FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE);
if (!fed)
- return 0;
+ return false;
return (fed->flag & FREESTYLE_EDGE_MARK) != 0;
}
@@ -2925,11 +2902,11 @@ static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm);
}
-static int draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
+static bool draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa)
{
FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE);
if (!ffa)
- return 0;
+ return false;
return (ffa->flag & FREESTYLE_FACE_MARK) != 0;
}
@@ -3092,7 +3069,6 @@ static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
if (data.cd_layer_offset != -1) {
glLineWidth(3.0);
dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data);
- glLineWidth(1.0);
}
}
@@ -3122,7 +3098,7 @@ static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[
const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset);
if (bweight != 0.0f) {
UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, bweight);
- bglVertex3fv(co);
+ glVertex3fv(co);
}
}
}
@@ -3138,9 +3114,9 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
if (data.cd_layer_offset != -1) {
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP);
- bglEnd();
+ glEnd();
}
}
else {
@@ -3152,7 +3128,6 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
if (data.cd_layer_offset != -1) {
glLineWidth(3.0);
dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data);
- glLineWidth(1.0);
}
}
}
@@ -3164,32 +3139,29 @@ static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
* specialized to be split out (like drawing creases or measurements).
*/
-/* EditMesh drawing routines*/
+/* EditMesh drawing routines */
static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act,
RegionView3D *rv3d)
{
ToolSettings *ts = scene->toolsettings;
- int sel;
if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */
- for (sel = 0; sel < 2; sel++) {
+ for (int sel = 0; sel < 2; sel++) {
unsigned char col[4], fcol[4];
- int pass;
UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col);
UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE_EDIT, fcol);
- for (pass = 0; pass < 2; pass++) {
+ for (int pass = 0; pass < 2; pass++) {
float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
if (pass == 0) {
if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) {
glDisable(GL_DEPTH_TEST);
-
glEnable(GL_BLEND);
}
else {
@@ -3224,7 +3196,6 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit,
}
if (v3d->zbuf) glDepthMask(1);
- glPointSize(1.0);
}
static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
@@ -3232,7 +3203,6 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
BMEdge *eed_act)
{
ToolSettings *ts = scene->toolsettings;
- int pass;
unsigned char wireCol[4], selCol[4], actCol[4];
/* since this function does transparent... */
@@ -3245,7 +3215,7 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
if (sel_only)
wireCol[3] = 0;
- for (pass = 0; pass < 2; pass++) {
+ for (int pass = 0; pass < 2; pass++) {
/* show wires in transparent when no zbuf clipping for select */
if (pass == 0) {
if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) {
@@ -3323,7 +3293,6 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
/* allow for displaying shape keys and deform mods */
DerivedMesh *dm = EDBM_mesh_deform_dm_get(em);
BMIter iter;
- int i;
/* make the precision of the display value proportionate to the gridsize */
@@ -3368,10 +3337,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
copy_v3_v3(v2, eed->v2->co);
}
- copy_v3_v3(v1_clip, v1);
- copy_v3_v3(v2_clip, v2);
-
- if (clip_segment_v3_plane_n(v1_clip, v2_clip, clip_planes, 4)) {
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
if (do_edge_textpair) {
interp_v3_v3v3(vmid, v1, v2, edge_texpair_sep);
@@ -3435,10 +3401,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
copy_v3_v3(v2, eed->v2->co);
}
- copy_v3_v3(v1_clip, v1);
- copy_v3_v3(v2_clip, v2);
-
- if (clip_segment_v3_plane_n(v1_clip, v2_clip, clip_planes, 4)) {
+ if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) {
float no_a[3], no_b[3];
float angle;
@@ -3479,8 +3442,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
if (me->drawflag & ME_DRAWEXTRA_FACEAREA) {
/* would be nice to use BM_face_calc_area, but that is for 2d faces
* so instead add up tessellation triangle areas */
- BMFace *f;
- int n;
+ BMFace *f = NULL;
#define DRAW_EM_MEASURE_STATS_FACEAREA() \
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \
@@ -3503,11 +3465,10 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
}
- f = NULL;
area = 0.0;
zero_v3(vmid);
- n = 0;
- for (i = 0; i < em->tottri; i++) {
+ int n = 0;
+ for (int i = 0; i < em->tottri; i++) {
BMLoop **l = em->looptris[i];
if (f && l[0]->f != f) {
DRAW_EM_MEASURE_STATS_FACEAREA();
@@ -3572,7 +3533,6 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) ||
BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT))))
{
- float angle;
float v2_local[3];
/* lazy init center calc */
@@ -3613,7 +3573,7 @@ static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMe
mul_mat3_m4_v3(ob->obmat, v3);
}
- angle = angle_v3v3v3(v1, v2, v3);
+ float angle = angle_v3v3v3(v1, v2, v3);
numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle));
interp_v3_v3v3(fvec, vmid, v2_local, 0.8f);
@@ -3631,7 +3591,6 @@ static void draw_em_indices(BMEditMesh *em)
BMEdge *e;
BMFace *f;
BMVert *v;
- int i;
char numstr[32];
size_t numstr_len;
float pos[3];
@@ -3641,7 +3600,7 @@ static void draw_em_indices(BMEditMesh *em)
BMesh *bm = em->bm;
/* For now, reuse appropriate theme colors from stats text colors */
- i = 0;
+ int i = 0;
if (em->selectmode & SCE_SELECT_VERTEX) {
UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -3683,12 +3642,11 @@ static void draw_em_indices(BMEditMesh *em)
static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
{
BMEditMesh *em = userData;
- BMFace *efa;
if (UNLIKELY(index >= em->bm->totface))
return DM_DRAW_OPTION_NORMAL;
- efa = BM_face_at_index(em->bm, index);
+ BMFace *efa = BM_face_at_index(em->bm, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
return DM_DRAW_OPTION_NORMAL;
}
@@ -3700,12 +3658,11 @@ static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index)
static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
{
BMEditMesh *em = userData;
- BMFace *efa;
if (UNLIKELY(index >= em->bm->totface))
return DM_DRAW_OPTION_NORMAL;
- efa = BM_face_at_index(em->bm, index);
+ BMFace *efa = BM_face_at_index(em->bm, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
return DM_DRAW_OPTION_NORMAL;
@@ -3721,27 +3678,10 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
{
RegionView3D *rv3d = ar->regiondata;
Mesh *me = ob->data;
- BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true); /* annoying but active faces is stored differently */
- BMEdge *eed_act = NULL;
- BMVert *eve_act = NULL;
- bool use_occlude_wire = (v3d->flag2 & V3D_OCCLUDE_WIRE) && (dt > OB_WIRE);
+ const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE);
+ bool use_depth_offset = false;
- if (em->bm->selected.last) {
- BMEditSelection *ese = em->bm->selected.last;
- /* face is handled above */
-#if 0
- if (ese->type == BM_FACE) {
- efa_act = (BMFace *)ese->data;
- }
- else
-#endif
- if (ese->htype == BM_EDGE) {
- eed_act = (BMEdge *)ese->ele;
- }
- else if (ese->htype == BM_VERT) {
- eve_act = (BMVert *)ese->ele;
- }
- }
+ glLineWidth(1);
BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE);
@@ -3751,6 +3691,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0);
+ use_depth_offset = true;
}
else {
glEnable(GL_DEPTH_TEST);
@@ -3764,16 +3705,17 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
/* use the cageDM since it always overlaps the editmesh faces */
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
cageDM->drawMappedFaces(cageDM, draw_em_fancy__setFaceOpts,
- GPU_enable_material, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN);
+ GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS);
+ GPU_object_material_unbind();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
else if (check_object_draw_texture(scene, v3d, dt)) {
if (draw_glsl_material(scene, ob, v3d, dt)) {
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
+ finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind,
draw_em_fancy__setGLSLFaceOpts, em);
- GPU_disable_material();
+ GPU_object_material_unbind();
glFrontFace(GL_CCW);
}
@@ -3782,17 +3724,12 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
}
else {
- /* 3 floats for position,
- * 3 for normal and times two because the faces may actually be quads instead of triangles */
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE);
-
- glEnable(GL_LIGHTING);
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN);
+ finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS);
glFrontFace(GL_CCW);
- glDisable(GL_LIGHTING);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+
+ GPU_object_material_unbind();
}
/* Setup for drawing wire over, disable zbuffer
@@ -3801,6 +3738,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0);
+ use_depth_offset = true;
}
else {
if (cageDM != finalDM) {
@@ -3809,150 +3747,175 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
}
}
- if ((me->drawflag & ME_DRAWFACES) && (use_occlude_wire == false)) { /* transp faces */
- unsigned char col1[4], col2[4], col3[4];
+ if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) {
+ /* pass */
+ }
+ else {
+ /* annoying but active faces is stored differently */
+ BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true);
+ BMEdge *eed_act = NULL;
+ BMVert *eve_act = NULL;
+
+ if (em->bm->selected.last) {
+ BMEditSelection *ese = em->bm->selected.last;
+ /* face is handled above */
+#if 0
+ if (ese->type == BM_FACE) {
+ efa_act = (BMFace *)ese->data;
+ }
+ else
+#endif
+ if (ese->htype == BM_EDGE) {
+ eed_act = (BMEdge *)ese->ele;
+ }
+ else if (ese->htype == BM_VERT) {
+ eve_act = (BMVert *)ese->ele;
+ }
+ }
+
+ if ((me->drawflag & ME_DRAWFACES) && (use_occlude_wire == false)) { /* transp faces */
+ unsigned char col1[4], col2[4], col3[4];
#ifdef WITH_FREESTYLE
- unsigned char col4[4];
+ unsigned char col4[4];
#endif
- UI_GetThemeColor4ubv(TH_FACE, col1);
- UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
+ UI_GetThemeColor4ubv(TH_FACE, col1);
+ UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
+ UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
#ifdef WITH_FREESTYLE
- UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4);
+ UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4);
#endif
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
- /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
- if (check_object_draw_texture(scene, v3d, dt))
- col1[3] = 0;
+ /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */
+ if (check_object_draw_texture(scene, v3d, dt))
+ col1[3] = 0;
#ifdef WITH_FREESTYLE
- if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE) || !CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE))
- col4[3] = 0;
+ if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE) || !CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE))
+ col4[3] = 0;
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
#else
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
#endif
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
- else if (efa_act) {
- /* even if draw faces is off it would be nice to draw the stipple face
- * Make all other faces zero alpha except for the active */
- unsigned char col1[4], col2[4], col3[4];
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
+ else if (efa_act) {
+ /* even if draw faces is off it would be nice to draw the stipple face
+ * Make all other faces zero alpha except for the active */
+ unsigned char col1[4], col2[4], col3[4];
#ifdef WITH_FREESTYLE
- unsigned char col4[4];
- col4[3] = 0; /* don't draw */
+ unsigned char col4[4];
+ col4[3] = 0; /* don't draw */
#endif
- col1[3] = col2[3] = 0; /* don't draw */
+ col1[3] = col2[3] = 0; /* don't draw */
- UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
+ UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
- glEnable(GL_BLEND);
- glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+ glEnable(GL_BLEND);
+ glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
#ifdef WITH_FREESTYLE
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
#else
- draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
#endif
- glDisable(GL_BLEND);
- glDepthMask(1); /* restore write in zbuffer */
- }
+ glDisable(GL_BLEND);
+ glDepthMask(1); /* restore write in zbuffer */
+ }
- /* here starts all fancy draw-extra over */
- if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
- /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
-
- /* only draw selected edges otherwise there is no way of telling if a face is selected */
- draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
-
- }
- else {
- if (me->drawflag & ME_DRAWSEAMS) {
- UI_ThemeColor(TH_EDGE_SEAM);
- glLineWidth(2);
+ /* here starts all fancy draw-extra over */
+ if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) {
+ /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */
- draw_dm_edges_seams(em, cageDM);
+ /* only draw selected edges otherwise there is no way of telling if a face is selected */
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
- glColor3ub(0, 0, 0);
- glLineWidth(1);
}
-
- if (me->drawflag & ME_DRAWSHARP) {
- UI_ThemeColor(TH_EDGE_SHARP);
- glLineWidth(2);
+ else {
+ if (me->drawflag & ME_DRAWSEAMS) {
+ UI_ThemeColor(TH_EDGE_SEAM);
+ glLineWidth(2);
- draw_dm_edges_sharp(em, cageDM);
+ draw_dm_edges_seams(em, cageDM);
- glColor3ub(0, 0, 0);
- glLineWidth(1);
- }
+ glColor3ub(0, 0, 0);
+ }
+
+ if (me->drawflag & ME_DRAWSHARP) {
+ UI_ThemeColor(TH_EDGE_SHARP);
+ glLineWidth(2);
+
+ draw_dm_edges_sharp(em, cageDM);
+
+ glColor3ub(0, 0, 0);
+ }
#ifdef WITH_FREESTYLE
- if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
- UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
- glLineWidth(2);
-
- draw_dm_edges_freestyle(em, cageDM);
-
- glColor3ub(0, 0, 0);
- glLineWidth(1);
- }
-#endif
-
- if (me->drawflag & ME_DRAWCREASES) {
- draw_dm_creases(em, cageDM);
- }
- if (me->drawflag & ME_DRAWBWEIGHTS) {
- draw_dm_bweights(em, scene, cageDM);
- }
+ if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) {
+ UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
+ glLineWidth(2);
- draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
- }
+ draw_dm_edges_freestyle(em, cageDM);
- {
- draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
+ glColor3ub(0, 0, 0);
+ }
+#endif
- if (me->drawflag & ME_DRAWNORMALS) {
- UI_ThemeColor(TH_NORMAL);
- draw_dm_face_normals(em, scene, ob, cageDM);
- }
- if (me->drawflag & ME_DRAW_VNORMALS) {
- UI_ThemeColor(TH_VNORMAL);
- draw_dm_vert_normals(em, scene, ob, cageDM);
- }
- if (me->drawflag & ME_DRAW_LNORMALS) {
- UI_ThemeColor(TH_LNORMAL);
- draw_dm_loop_normals(em, scene, ob, cageDM);
- }
+ if (me->drawflag & ME_DRAWCREASES) {
+ draw_dm_creases(em, cageDM);
+ }
+ if (me->drawflag & ME_DRAWBWEIGHTS) {
+ draw_dm_bweights(em, scene, cageDM);
+ }
- if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
- ME_DRAWEXTRA_FACEAREA |
- ME_DRAWEXTRA_FACEANG |
- ME_DRAWEXTRA_EDGEANG)) &&
- !(v3d->flag2 & V3D_RENDER_OVERRIDE))
- {
- draw_em_measure_stats(ar, v3d, ob, em, &scene->unit);
+ glLineWidth(1);
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act);
}
- if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) &&
- !(v3d->flag2 & V3D_RENDER_OVERRIDE))
{
- draw_em_indices(em);
+ draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d);
+
+ if (me->drawflag & ME_DRAWNORMALS) {
+ UI_ThemeColor(TH_NORMAL);
+ draw_dm_face_normals(em, scene, ob, cageDM);
+ }
+ if (me->drawflag & ME_DRAW_VNORMALS) {
+ UI_ThemeColor(TH_VNORMAL);
+ draw_dm_vert_normals(em, scene, ob, cageDM);
+ }
+ if (me->drawflag & ME_DRAW_LNORMALS) {
+ UI_ThemeColor(TH_LNORMAL);
+ draw_dm_loop_normals(em, scene, ob, cageDM);
+ }
+
+ if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN |
+ ME_DRAWEXTRA_FACEAREA |
+ ME_DRAWEXTRA_FACEANG |
+ ME_DRAWEXTRA_EDGEANG)) &&
+ !(v3d->flag2 & V3D_RENDER_OVERRIDE))
+ {
+ draw_em_measure_stats(ar, v3d, ob, em, &scene->unit);
+ }
+
+ if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) &&
+ !(v3d->flag2 & V3D_RENDER_OVERRIDE))
+ {
+ draw_em_indices(em);
+ }
}
}
- if (dt > OB_WIRE) {
+ if (use_depth_offset) {
glDepthMask(1);
ED_view3d_polygon_offset(rv3d, 0.0);
- GPU_disable_material();
+ GPU_object_material_unbind();
}
#if 0 /* currently not needed */
else if (use_occlude_wire) {
@@ -3971,19 +3934,18 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
glDepthMask(0);
- /* if transparent, we cannot draw the edges for solid select... edges have no material info.
- * drawFacesSolid() doesn't draw the transparent faces */
+ /* if transparent, we cannot draw the edges for solid select... edges
+ * have no material info. GPU_object_material_visible will skip the
+ * transparent faces */
if (ob->dtx & OB_DRAWTRANSP) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_visible);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- GPU_disable_material();
}
else {
dm->drawEdges(dm, 0, 1);
}
- glLineWidth(1.0);
glDepthMask(1);
}
}
@@ -4049,7 +4011,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
{
glPointSize(1.5);
dm->drawVerts(dm);
- glPointSize(1.0);
}
else if ((dt == OB_WIRE) || no_faces) {
draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */
@@ -4087,18 +4048,18 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
}
- GPU_enable_material(1, &gattribs);
+ GPU_object_material_bind(1, &gattribs);
dm->drawFacesSolid(dm, fpl, fast, NULL);
draw_loose = false;
}
else
- dm->drawFacesGLSL(dm, GPU_enable_material);
+ dm->drawFacesGLSL(dm, GPU_object_material_bind);
#if 0 /* XXX */
if (BKE_bproperty_object_get(ob, "Text"))
draw_mesh_text(ob, 1);
#endif
- GPU_disable_material();
+ GPU_object_material_unbind();
glFrontFace(GL_CCW);
@@ -4114,6 +4075,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if ((dflag & DRAW_CONSTCOLOR) == 0) {
glColor3ubv(ob_wire_col);
}
+ glLineWidth(1.0f);
dm->drawLooseEdges(dm);
}
}
@@ -4122,10 +4084,11 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (draw_flags & DRAW_MODIFIERS_PREVIEW) {
/* for object selection draws no shade */
if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) {
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
+ GPU_object_material_unbind();
}
else {
- const float spec[4] = {0.47f, 0.47f, 0.47f, 0.47f};
+ const float specular[3] = {0.47f, 0.47f, 0.47f};
/* draw outline */
if ((v3d->flag & V3D_SELECT_OUTLINE) &&
@@ -4140,21 +4103,13 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* materials arent compatible with vertex colors */
GPU_end_object_materials();
- GPU_enable_material(0, NULL);
-
- /* set default spec */
- glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
- /* diffuse */
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
+ /* set default specular */
+ GPU_basic_shader_colors(NULL, specular, 35, 1.0f);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
- dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS);
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
+ dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS);
- GPU_disable_material();
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
}
else {
@@ -4169,9 +4124,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_mesh_object_outline(v3d, ob, dm);
}
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE);
-
- glEnable(GL_LIGHTING);
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
if (ob->sculpt && (p = BKE_paint_get_active(scene))) {
@@ -4187,22 +4139,20 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
}
}
- dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material);
+ dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind);
}
else
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
-
- GPU_disable_material();
+ dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
glFrontFace(GL_CCW);
- glDisable(GL_LIGHTING);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+ GPU_object_material_unbind();
if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
if ((dflag & DRAW_CONSTCOLOR) == 0) {
glColor3ubv(ob_wire_col);
}
+ glLineWidth(1.0f);
dm->drawLooseEdges(dm);
}
}
@@ -4245,6 +4195,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
}
+ glLineWidth(1.0f);
dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0);
if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) {
@@ -4263,8 +4214,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
drawSelectedVertices(dm, ob->data);
if (!use_depth) glEnable(GL_DEPTH_TEST);
else ED_view3d_polygon_offset(rv3d, 0.0);
-
- glPointSize(1.0f);
}
dm->release(dm);
}
@@ -4277,13 +4226,12 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
Object *obedit = scene->obedit;
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
- int i;
bool do_alpha_after = false, drawlinked = false, retval = false;
/* If we are drawing shadows and any of the materials don't cast a shadow,
* then don't draw the object */
if (v3d->flag2 & V3D_RENDER_SHADOW) {
- for (i = 0; i < ob->totcol; ++i) {
+ for (int i = 0; i < ob->totcol; ++i) {
Material *ma = give_current_material(ob, i);
if (ma && !(ma->mode2 & MA_CASTSHADOW)) {
return true;
@@ -4313,22 +4261,28 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
scene, ob, em, scene->customdata_mask,
&finalDM);
+ const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0);
+
DM_update_materials(finalDM, ob);
if (cageDM != finalDM) {
DM_update_materials(cageDM, ob);
}
- if (dt > OB_WIRE) {
- const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
+ if (use_material) {
+ if (dt > OB_WIRE) {
+ const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+ GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
+ }
}
draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt);
- GPU_end_object_materials();
+ if (use_material) {
+ GPU_end_object_materials();
+ }
- if (obedit != ob && finalDM)
+ if (obedit != ob)
finalDM->release(finalDM);
}
else {
@@ -4385,16 +4339,12 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
*/
static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
{
- DispList *dl;
- int parts, nr;
- const float *data;
-
- if (dlbase == NULL) return 1;
+ if (dlbase == NULL) return true;
glEnableClientState(GL_VERTEX_ARRAY);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- for (dl = dlbase->first; dl; dl = dl->next) {
+ for (DispList *dl = dlbase->first; dl; dl = dl->next) {
if (dl->parts == 0 || dl->nr == 0) {
continue;
}
@@ -4403,7 +4353,8 @@ static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
continue;
}
- data = dl->verts;
+ const float *data = dl->verts;
+ int parts;
switch (dl->type) {
case DL_SEGM:
@@ -4433,7 +4384,7 @@ static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr);
}
- for (nr = 0; nr < dl->nr; nr++) {
+ for (int nr = 0; nr < dl->nr; nr++) {
int ofs = 3 * dl->nr;
data = (dl->verts) + 3 * nr;
@@ -4494,31 +4445,31 @@ static bool index3_nors_incr = true;
static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
const unsigned char ob_wire_col[4], const bool use_glsl)
{
- DispList *dl;
GPUVertexAttribs gattribs;
- const float *data;
- const float *ndata;
if (lb == NULL) return;
- glEnable(GL_LIGHTING);
glEnableClientState(GL_VERTEX_ARRAY);
if (ob->type == OB_MBALL) { /* mball always smooth shaded */
glShadeModel(GL_SMOOTH);
}
+
+ /* track current material, -1 for none (needed for lines) */
+ short col = -1;
- dl = lb->first;
+ DispList *dl = lb->first;
while (dl) {
- data = dl->verts;
- ndata = dl->nors;
+ const float *data = dl->verts;
+ const float *ndata = dl->nors;
switch (dl->type) {
case DL_SEGM:
if (ob->type == OB_SURF) {
- int nr;
-
- glDisable(GL_LIGHTING);
+ if (col != -1) {
+ GPU_object_material_unbind();
+ col = -1;
+ }
if ((dflag & DRAW_CONSTCOLOR) == 0)
glColor3ubv(ob_wire_col);
@@ -4527,35 +4478,35 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
// glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
glBegin(GL_LINE_STRIP);
- for (nr = dl->nr; nr; nr--, data += 3)
+ for (int nr = dl->nr; nr; nr--, data += 3)
glVertex3fv(data);
glEnd();
-
- glEnable(GL_LIGHTING);
}
break;
case DL_POLY:
if (ob->type == OB_SURF) {
- int nr;
-
- glDisable(GL_LIGHTING);
+ if (col != -1) {
+ GPU_object_material_unbind();
+ col = -1;
+ }
/* for some reason glDrawArrays crashes here in half of the platforms (not osx) */
//glVertexPointer(3, GL_FLOAT, 0, dl->verts);
//glDrawArrays(GL_LINE_LOOP, 0, dl->nr);
glBegin(GL_LINE_LOOP);
- for (nr = dl->nr; nr; nr--, data += 3)
+ for (int nr = dl->nr; nr; nr--, data += 3)
glVertex3fv(data);
glEnd();
-
- glEnable(GL_LIGHTING);
}
break;
case DL_SURF:
if (dl->index) {
- GPU_enable_material(dl->col + 1, (use_glsl) ? &gattribs : NULL);
+ if (col != dl->col) {
+ GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
+ col = dl->col;
+ }
if (dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH);
else glShadeModel(GL_FLAT);
@@ -4569,7 +4520,10 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
break;
case DL_INDEX3:
- GPU_enable_material(dl->col + 1, (use_glsl) ? &gattribs : NULL);
+ if (col != dl->col) {
+ GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
+ col = dl->col;
+ }
glVertexPointer(3, GL_FLOAT, 0, dl->verts);
@@ -4589,7 +4543,10 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
break;
case DL_INDEX4:
- GPU_enable_material(dl->col + 1, (use_glsl) ? &gattribs : NULL);
+ if (col != dl->col) {
+ GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL);
+ col = dl->col;
+ }
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, dl->verts);
@@ -4604,8 +4561,11 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
glDisableClientState(GL_VERTEX_ARRAY);
glShadeModel(GL_FLAT);
- glDisable(GL_LIGHTING);
glFrontFace(GL_CCW);
+
+ if (col != -1) {
+ GPU_object_material_unbind();
+ }
}
static void drawCurveDMWired(Object *ob)
@@ -4629,16 +4589,13 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d,
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
if (dt > OB_WIRE && dm->getNumPolys(dm)) {
- int glsl = draw_glsl_material(scene, ob, v3d, dt);
+ bool glsl = draw_glsl_material(scene, ob, v3d, dt);
GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
- if (!glsl) {
- glEnable(GL_LIGHTING);
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
- glDisable(GL_LIGHTING);
- }
+ if (!glsl)
+ dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
else
- dm->drawFacesGLSL(dm, GPU_enable_material);
+ dm->drawFacesGLSL(dm, GPU_object_material_bind);
GPU_end_object_materials();
}
@@ -4970,7 +4927,6 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
pdd->cd += 12;
}
-
copy_v3_v3(bb->vec, state->co);
copy_v3_v3(bb->vel, state->vel);
@@ -5066,7 +5022,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false;
GLint polygonmode[2];
char numstr[32];
- size_t numstr_len;
unsigned char tcol[4] = {0, 0, 0, 255};
/* 1. */
@@ -5108,9 +5063,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
if (select) {
- select = 0;
+ select = false;
if (psys_get_current(ob) == psys)
- select = 1;
+ select = true;
}
psys->flag |= PSYS_DRAWING;
@@ -5152,6 +5107,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
draw_as = PART_DRAW_DOT;
/* 3. */
+ glLineWidth(1.0f);
+
switch (draw_as) {
case PART_DRAW_DOT:
if (part->draw_size)
@@ -5471,19 +5428,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glEnableClientState(GL_COLOR_ARRAY);
}
- glEnable(GL_LIGHTING);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
- }
-#if 0
- else {
- glDisableClientState(GL_NORMAL_ARRAY);
-
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_LIGHTING);
- UI_ThemeColor(TH_WIRE);
+ // XXX test
+ GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
}
-#endif
if (totchild && (part->draw & PART_DRAW_PARENT) == 0)
totpart = 0;
@@ -5514,8 +5462,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (part->draw & PART_DRAW_GUIDE_HAIRS) {
DerivedMesh *hair_dm = psys->hair_out_dm;
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
@@ -5559,8 +5505,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glEnd();
}
- glEnable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
glEnableClientState(GL_NORMAL_ARRAY);
if ((dflag & DRAW_CONSTCOLOR) == 0)
if (part->draw_col == PART_DRAW_COL_MAT)
@@ -5570,13 +5514,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (part->draw & PART_DRAW_HAIR_GRID) {
ClothModifierData *clmd = psys->clmd;
if (clmd) {
- float *a = clmd->hair_grid_min;
- float *b = clmd->hair_grid_max;
+ float *gmin = clmd->hair_grid_min;
+ float *gmax = clmd->hair_grid_max;
int *res = clmd->hair_grid_res;
int i;
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
@@ -5585,20 +5527,20 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
else
UI_ThemeColor(TH_WIRE);
glBegin(GL_LINES);
- glVertex3f(a[0], a[1], a[2]); glVertex3f(b[0], a[1], a[2]);
- glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], b[1], a[2]);
- glVertex3f(b[0], b[1], a[2]); glVertex3f(a[0], b[1], a[2]);
- glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], a[1], a[2]);
+ glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmin[2]);
+ glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmin[2]);
+ glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmin[2]);
+ glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmin[2]);
- glVertex3f(a[0], a[1], b[2]); glVertex3f(b[0], a[1], b[2]);
- glVertex3f(b[0], a[1], b[2]); glVertex3f(b[0], b[1], b[2]);
- glVertex3f(b[0], b[1], b[2]); glVertex3f(a[0], b[1], b[2]);
- glVertex3f(a[0], b[1], b[2]); glVertex3f(a[0], a[1], b[2]);
+ glVertex3f(gmin[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmin[1], gmax[2]);
+ glVertex3f(gmax[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmax[1], gmax[2]);
+ glVertex3f(gmax[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmax[1], gmax[2]);
+ glVertex3f(gmin[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmin[1], gmax[2]);
- glVertex3f(a[0], a[1], a[2]); glVertex3f(a[0], a[1], b[2]);
- glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], a[1], b[2]);
- glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], b[1], b[2]);
- glVertex3f(b[0], b[1], a[2]); glVertex3f(b[0], b[1], b[2]);
+ glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmax[2]);
+ glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmax[2]);
+ glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmax[2]);
+ glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmax[2]);
glEnd();
if (select)
@@ -5608,31 +5550,29 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glEnable(GL_BLEND);
glBegin(GL_LINES);
for (i = 1; i < res[0] - 1; ++i) {
- float f = interpf(b[0], a[0], (float)i / (float)(res[0] - 1));
- glVertex3f(f, a[1], a[2]); glVertex3f(f, b[1], a[2]);
- glVertex3f(f, b[1], a[2]); glVertex3f(f, b[1], b[2]);
- glVertex3f(f, b[1], b[2]); glVertex3f(f, a[1], b[2]);
- glVertex3f(f, a[1], b[2]); glVertex3f(f, a[1], a[2]);
+ float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1));
+ glVertex3f(f, gmin[1], gmin[2]); glVertex3f(f, gmax[1], gmin[2]);
+ glVertex3f(f, gmax[1], gmin[2]); glVertex3f(f, gmax[1], gmax[2]);
+ glVertex3f(f, gmax[1], gmax[2]); glVertex3f(f, gmin[1], gmax[2]);
+ glVertex3f(f, gmin[1], gmax[2]); glVertex3f(f, gmin[1], gmin[2]);
}
for (i = 1; i < res[1] - 1; ++i) {
- float f = interpf(b[1], a[1], (float)i / (float)(res[1] - 1));
- glVertex3f(a[0], f, a[2]); glVertex3f(b[0], f, a[2]);
- glVertex3f(b[0], f, a[2]); glVertex3f(b[0], f, b[2]);
- glVertex3f(b[0], f, b[2]); glVertex3f(a[0], f, b[2]);
- glVertex3f(a[0], f, b[2]); glVertex3f(a[0], f, a[2]);
+ float f = interpf(gmax[1], gmin[1], (float)i / (float)(res[1] - 1));
+ glVertex3f(gmin[0], f, gmin[2]); glVertex3f(gmax[0], f, gmin[2]);
+ glVertex3f(gmax[0], f, gmin[2]); glVertex3f(gmax[0], f, gmax[2]);
+ glVertex3f(gmax[0], f, gmax[2]); glVertex3f(gmin[0], f, gmax[2]);
+ glVertex3f(gmin[0], f, gmax[2]); glVertex3f(gmin[0], f, gmin[2]);
}
for (i = 1; i < res[2] - 1; ++i) {
- float f = interpf(b[2], a[2], (float)i / (float)(res[2] - 1));
- glVertex3f(a[0], a[1], f); glVertex3f(b[0], a[1], f);
- glVertex3f(b[0], a[1], f); glVertex3f(b[0], b[1], f);
- glVertex3f(b[0], b[1], f); glVertex3f(a[0], b[1], f);
- glVertex3f(a[0], b[1], f); glVertex3f(a[0], a[1], f);
+ float f = interpf(gmax[2], gmin[2], (float)i / (float)(res[2] - 1));
+ glVertex3f(gmin[0], gmin[1], f); glVertex3f(gmax[0], gmin[1], f);
+ glVertex3f(gmax[0], gmin[1], f); glVertex3f(gmax[0], gmax[1], f);
+ glVertex3f(gmax[0], gmax[1], f); glVertex3f(gmin[0], gmax[1], f);
+ glVertex3f(gmin[0], gmax[1], f); glVertex3f(gmin[0], gmin[1], f);
}
glEnd();
glDisable(GL_BLEND);
- glEnable(GL_LIGHTING);
- glEnable(GL_COLOR_MATERIAL);
glEnableClientState(GL_NORMAL_ARRAY);
if ((dflag & DRAW_CONSTCOLOR) == 0)
if (part->draw_col == PART_DRAW_COL_MAT)
@@ -5663,7 +5603,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (1) { //ob_dt > OB_WIRE) {
if (part->draw_col == PART_DRAW_COL_MAT)
glDisableClientState(GL_COLOR_ARRAY);
- glDisable(GL_COLOR_MATERIAL);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
if (cdata2) {
@@ -5671,14 +5611,12 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
cdata2 = NULL;
}
- glLineWidth(1.0f);
-
if ((part->draw & PART_DRAW_NUM) && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
cache = psys->pathcache;
for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
float vec_txt[3];
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a);
+ size_t numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a);
/* use worldspace because object matrix is already applied */
mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co);
view3d_cached_text_draw_add(vec_txt, numstr, numstr_len,
@@ -5724,11 +5662,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (pdd->ndata && ob_dt > OB_WIRE) {
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, pdd->ndata);
- glEnable(GL_LIGHTING);
- }
- else {
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisable(GL_LIGHTING);
+ GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f);
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR);
}
if ((dflag & DRAW_CONSTCOLOR) == 0) {
@@ -5760,7 +5695,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
/* 7. */
- glDisable(GL_LIGHTING);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
@@ -5835,14 +5770,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
- if (pset->brushtype == PE_BRUSH_WEIGHT) {
+ if (pset->brushtype == PE_BRUSH_WEIGHT)
glLineWidth(2.0f);
- glDisable(GL_LIGHTING);
- }
cache = edit->pathcache;
for (i = 0, point = edit->points; i < totpoint; i++, point++) {
@@ -5881,16 +5812,16 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
if (pset->selectmode == SCE_SELECT_POINT) {
float *pd = NULL, *pdata = NULL;
float *cd = NULL, *cdata = NULL;
- int totkeys = 0;
+ int totkeys_visible = 0;
for (i = 0, point = edit->points; i < totpoint; i++, point++)
if (!(point->flag & PEP_HIDE))
- totkeys += point->totkey;
+ totkeys_visible += point->totkey;
- if (totkeys) {
+ if (totkeys_visible) {
if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO))
- pd = pdata = MEM_callocN(totkeys * 3 * sizeof(float), "particle edit point data");
- cd = cdata = MEM_callocN(totkeys * (timed ? 4 : 3) * sizeof(float), "particle edit color data");
+ pd = pdata = MEM_callocN(totkeys_visible * 3 * sizeof(float), "particle edit point data");
+ cd = cdata = MEM_callocN(totkeys_visible * (timed ? 4 : 3) * sizeof(float), "particle edit color data");
}
for (i = 0, point = edit->points; i < totpoint; i++, point++) {
@@ -5938,46 +5869,39 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
if (cdata) { MEM_freeN(cdata); cd = cdata = NULL; }
}
else if (pset->selectmode == SCE_SELECT_END) {
+ glBegin(GL_POINTS);
for (i = 0, point = edit->points; i < totpoint; i++, point++) {
if ((point->flag & PEP_HIDE) == 0 && point->totkey) {
key = point->keys + point->totkey - 1;
- if (key->flag & PEK_SELECT)
- glColor3fv(sel_col);
- else
- glColor3fv(nosel_col);
+ glColor3fv((key->flag & PEK_SELECT) ? sel_col : nosel_col);
/* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
- glBegin(GL_POINTS);
glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co);
- glEnd();
}
}
+ glEnd();
}
}
glDisable(GL_BLEND);
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glShadeModel(GL_FLAT);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
- glLineWidth(1.0f);
- glPointSize(1.0f);
}
static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size)
{
float tr[3][3];
float root[3], tip[3];
- float tw, th;
/* take a copy for not spoiling original */
copy_m3_m3(tr, rotscale);
- tw = itw * drw_size;
- th = ith * drw_size;
+ float tw = itw * drw_size;
+ float th = ith * drw_size;
- glColor4ub(0x7F, 0x00, 0x00, 155);
glBegin(GL_LINES);
+
+ glColor4ub(0x7F, 0x00, 0x00, 155);
root[1] = root[2] = 0.0f;
root[0] = -drw_size;
mul_m3_v3(tr, root);
@@ -5988,47 +5912,37 @@ static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, flo
mul_m3_v3(tr, tip);
add_v3_v3(tip, com);
glVertex3fv(tip);
- glEnd();
root[1] = 0.0f; root[2] = tw;
root[0] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[1] = 0.0f; root[2] = -tw;
root[0] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[1] = tw; root[2] = 0.0f;
root[0] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[1] = -tw; root[2] = 0.0f;
root[0] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
glColor4ub(0x00, 0x7F, 0x00, 155);
- glBegin(GL_LINES);
root[0] = root[2] = 0.0f;
root[1] = -drw_size;
mul_m3_v3(tr, root);
@@ -6039,46 +5953,36 @@ static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, flo
mul_m3_v3(tr, tip);
add_v3_v3(tip, com);
glVertex3fv(tip);
- glEnd();
root[0] = 0.0f; root[2] = tw;
root[1] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[0] = 0.0f; root[2] = -tw;
root[1] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[0] = tw; root[2] = 0.0f;
root[1] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[0] = -tw; root[2] = 0.0f;
root[1] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
glColor4ub(0x00, 0x00, 0x7F, 155);
- glBegin(GL_LINES);
root[0] = root[1] = 0.0f;
root[2] = -drw_size;
mul_m3_v3(tr, root);
@@ -6089,42 +5993,35 @@ static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, flo
mul_m3_v3(tr, tip);
add_v3_v3(tip, com);
glVertex3fv(tip);
- glEnd();
root[0] = 0.0f; root[1] = tw;
root[2] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[0] = 0.0f; root[1] = -tw;
root[2] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[0] = tw; root[1] = 0.0f;
root[2] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
- glEnd();
root[0] = -tw; root[1] = 0.0f;
root[2] = th;
- glBegin(GL_LINES);
mul_m3_v3(tr, root);
add_v3_v3(root, com);
glVertex3fv(root);
glVertex3fv(tip);
+
glEnd();
}
@@ -6132,27 +6029,27 @@ static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, flo
static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
{
- BezTriple *bezt;
- const float *fp;
- int a;
-
if (nu->hide || hide_handles) return;
- glBegin(GL_LINES);
-
if (nu->type == CU_BEZIER) {
+ const float *fp;
+
#define TH_HANDLE_COL_TOT ((TH_HANDLE_SEL_FREE - TH_HANDLE_FREE) + 1)
/* use MIN2 when indexing to ensure newer files don't read outside the array */
unsigned char handle_cols[TH_HANDLE_COL_TOT][3];
const int basecol = sel ? TH_HANDLE_SEL_FREE : TH_HANDLE_FREE;
- for (a = 0; a < TH_HANDLE_COL_TOT; a++) {
+ for (int a = 0; a < TH_HANDLE_COL_TOT; a++) {
UI_GetThemeColor3ubv(basecol + a, handle_cols[a]);
}
- bezt = nu->bezt;
- a = nu->pntsu;
+ glLineWidth(1.0f);
+
+ glBegin(GL_LINES);
+
+ BezTriple *bezt = nu->bezt;
+ int a = nu->pntsu;
while (a--) {
if (bezt->hide == 0) {
if ((bezt->f2 & SELECT) == sel) {
@@ -6184,18 +6081,15 @@ static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles)
bezt++;
}
+ glEnd();
+
#undef TH_HANDLE_COL_TOT
}
- glEnd();
}
static void drawhandlesN_active(Nurb *nu)
{
- BezTriple *bezt;
- const float *fp;
- int a;
-
if (nu->hide) return;
UI_ThemeColor(TH_ACTIVE_SPLINE);
@@ -6204,11 +6098,11 @@ static void drawhandlesN_active(Nurb *nu)
glBegin(GL_LINES);
if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
+ BezTriple *bezt = nu->bezt;
+ int a = nu->pntsu;
while (a--) {
if (bezt->hide == 0) {
- fp = bezt->vec[0];
+ const float *fp = bezt->vec[0];
glVertex3fv(fp);
glVertex3fv(fp + 3);
@@ -6222,93 +6116,81 @@ static void drawhandlesN_active(Nurb *nu)
glEnd();
glColor3ub(0, 0, 0);
- glLineWidth(1);
}
static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert)
{
- BezTriple *bezt;
- BPoint *bp;
- float size;
- int a, color;
-
if (nu->hide) return;
- if (sel) color = TH_VERTEX_SELECT;
- else color = TH_VERTEX;
+ const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX;
UI_ThemeColor(color);
- size = UI_GetThemeValuef(TH_VERTEX_SIZE);
- glPointSize(size);
+ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
if (nu->type == CU_BEZIER) {
- bezt = nu->bezt;
- a = nu->pntsu;
+ BezTriple *bezt = nu->bezt;
+ int a = nu->pntsu;
while (a--) {
if (bezt->hide == 0) {
if (sel == 1 && bezt == vert) {
UI_ThemeColor(TH_ACTIVE_VERT);
- if (bezt->f2 & SELECT) bglVertex3fv(bezt->vec[1]);
+ if (bezt->f2 & SELECT) glVertex3fv(bezt->vec[1]);
if (!hide_handles) {
- if (bezt->f1 & SELECT) bglVertex3fv(bezt->vec[0]);
- if (bezt->f3 & SELECT) bglVertex3fv(bezt->vec[2]);
+ if (bezt->f1 & SELECT) glVertex3fv(bezt->vec[0]);
+ if (bezt->f3 & SELECT) glVertex3fv(bezt->vec[2]);
}
UI_ThemeColor(color);
}
else if (hide_handles) {
- if ((bezt->f2 & SELECT) == sel) bglVertex3fv(bezt->vec[1]);
+ if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]);
}
else {
- if ((bezt->f1 & SELECT) == sel) bglVertex3fv(bezt->vec[0]);
- if ((bezt->f2 & SELECT) == sel) bglVertex3fv(bezt->vec[1]);
- if ((bezt->f3 & SELECT) == sel) bglVertex3fv(bezt->vec[2]);
+ if ((bezt->f1 & SELECT) == sel) glVertex3fv(bezt->vec[0]);
+ if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]);
+ if ((bezt->f3 & SELECT) == sel) glVertex3fv(bezt->vec[2]);
}
}
bezt++;
}
}
else {
- bp = nu->bp;
- a = nu->pntsu * nu->pntsv;
+ BPoint *bp = nu->bp;
+ int a = nu->pntsu * nu->pntsv;
while (a--) {
if (bp->hide == 0) {
if (bp == vert) {
UI_ThemeColor(TH_ACTIVE_VERT);
- bglVertex3fv(bp->vec);
+ glVertex3fv(bp->vec);
UI_ThemeColor(color);
}
else {
- if ((bp->f1 & SELECT) == sel) bglVertex3fv(bp->vec);
+ if ((bp->f1 & SELECT) == sel) glVertex3fv(bp->vec);
}
}
bp++;
}
}
- bglEnd();
- glPointSize(1.0);
+ glEnd();
}
static void editnurb_draw_active_poly(Nurb *nu)
{
- BPoint *bp;
- int a, b;
-
UI_ThemeColor(TH_ACTIVE_SPLINE);
glLineWidth(2);
- bp = nu->bp;
- for (b = 0; b < nu->pntsv; b++) {
+ BPoint *bp = nu->bp;
+ for (int b = 0; b < nu->pntsv; b++) {
if (nu->flagu & 1) glBegin(GL_LINE_LOOP);
else glBegin(GL_LINE_STRIP);
- for (a = 0; a < nu->pntsu; a++, bp++) {
+ for (int a = 0; a < nu->pntsu; a++, bp++) {
glVertex3fv(bp->vec);
}
@@ -6316,24 +6198,20 @@ static void editnurb_draw_active_poly(Nurb *nu)
}
glColor3ub(0, 0, 0);
- glLineWidth(1);
}
static void editnurb_draw_active_nurbs(Nurb *nu)
{
- BPoint *bp, *bp1;
- int a, b, ofs;
-
UI_ThemeColor(TH_ACTIVE_SPLINE);
glLineWidth(2);
glBegin(GL_LINES);
- bp = nu->bp;
- for (b = 0; b < nu->pntsv; b++) {
- bp1 = bp;
+ BPoint *bp = nu->bp;
+ for (int b = 0; b < nu->pntsv; b++) {
+ BPoint *bp1 = bp;
bp++;
- for (a = nu->pntsu - 1; a > 0; a--, bp++) {
+ for (int a = nu->pntsu - 1; a > 0; a--, bp++) {
if (bp->hide == 0 && bp1->hide == 0) {
glVertex3fv(bp->vec);
glVertex3fv(bp1->vec);
@@ -6344,11 +6222,11 @@ static void editnurb_draw_active_nurbs(Nurb *nu)
if (nu->pntsv > 1) { /* surface */
- ofs = nu->pntsu;
- for (b = 0; b < nu->pntsu; b++) {
- bp1 = nu->bp + b;
+ int ofs = nu->pntsu;
+ for (int b = 0; b < nu->pntsu; b++) {
+ BPoint *bp1 = nu->bp + b;
bp = bp1 + ofs;
- for (a = nu->pntsv - 1; a > 0; a--, bp += ofs) {
+ for (int a = nu->pntsv - 1; a > 0; a--, bp += ofs) {
if (bp->hide == 0 && bp1->hide == 0) {
glVertex3fv(bp->vec);
glVertex3fv(bp1->vec);
@@ -6361,18 +6239,16 @@ static void editnurb_draw_active_nurbs(Nurb *nu)
glEnd();
glColor3ub(0, 0, 0);
- glLineWidth(1);
}
static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
{
- Nurb *nu;
BPoint *bp, *bp1;
- int a, b, ofs, index;
+ int a, b;
Curve *cu = ob->data;
- index = 0;
- nu = nurb;
+ int index = 0;
+ Nurb *nu = nurb;
while (nu) {
if (nu->hide == 0) {
switch (nu->type) {
@@ -6382,6 +6258,8 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
editnurb_draw_active_poly(nu);
}
+ glLineWidth(1);
+
UI_ThemeColor(TH_NURB_ULINE);
bp = nu->bp;
for (b = 0; b < nu->pntsv; b++) {
@@ -6401,6 +6279,10 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
editnurb_draw_active_nurbs(nu);
}
+ glLineWidth(1);
+
+ glBegin(GL_LINES);
+
bp = nu->bp;
for (b = 0; b < nu->pntsv; b++) {
bp1 = bp;
@@ -6411,10 +6293,8 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) {
UI_ThemeColor(TH_NURB_SEL_ULINE);
- glBegin(GL_LINE_STRIP);
glVertex3fv(bp->vec);
glVertex3fv(bp1->vec);
- glEnd();
}
}
else {
@@ -6424,19 +6304,17 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
else {
UI_ThemeColor(TH_NURB_ULINE);
- glBegin(GL_LINE_STRIP);
glVertex3fv(bp->vec);
glVertex3fv(bp1->vec);
- glEnd();
}
}
}
bp1 = bp;
}
}
- if (nu->pntsv > 1) { /* surface */
- ofs = nu->pntsu;
+ if (nu->pntsv > 1) { /* surface */
+ int ofs = nu->pntsu;
for (b = 0; b < nu->pntsu; b++) {
bp1 = nu->bp + b;
bp = bp1 + ofs;
@@ -6446,10 +6324,8 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) {
UI_ThemeColor(TH_NURB_SEL_VLINE);
- glBegin(GL_LINE_STRIP);
glVertex3fv(bp->vec);
glVertex3fv(bp1->vec);
- glEnd();
}
}
else {
@@ -6459,18 +6335,17 @@ static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
else {
UI_ThemeColor(TH_NURB_VLINE);
- glBegin(GL_LINE_STRIP);
glVertex3fv(bp->vec);
glVertex3fv(bp1->vec);
- glEnd();
}
}
}
bp1 = bp;
}
}
-
}
+
+ glEnd();
break;
}
}
@@ -6488,10 +6363,8 @@ static void draw_editnurb(
Object *ob = base->object;
Curve *cu = ob->data;
Nurb *nu;
- BevList *bl;
const void *vert = BKE_curve_vert_active_get(cu);
const bool hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0;
- int index;
unsigned char wire_col[3];
/* DispList */
@@ -6501,14 +6374,13 @@ static void draw_editnurb(
drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
/* for shadows only show solid faces */
- if (v3d->flag2 & V3D_RENDER_SHADOW) {
+ if (v3d->flag2 & V3D_RENDER_SHADOW)
return;
- }
if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
/* first non-selected and active handles */
- index = 0;
+ int index = 0;
for (nu = nurb; nu; nu = nu->next) {
if (nu->type == CU_BEZIER) {
if (index == cu->actnu && !hide_handles)
@@ -6533,6 +6405,8 @@ static void draw_editnurb(
/* direction vectors for 3d curve paths
* when at its lowest, don't render normals */
if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) {
+ BevList *bl;
+ glLineWidth(1.0f);
for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) {
BevPoint *bevp = bl->bevpoints;
int nr = bl->nr;
@@ -6602,7 +6476,7 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
Curve *cu = ob->data;
EditFont *ef = cu->editfont;
float vec1[3], vec2[3];
- int i, selstart, selend;
+ int selstart, selend;
draw_editfont_textcurs(rv3d, ef->textcurs);
@@ -6625,7 +6499,7 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
vec1[1] += cu->linedist * cu->fsize;
vec2[1] -= cu->lines * cu->linedist * cu->fsize;
setlinestyle(3);
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex2fv(vec1);
glVertex2fv(vec2);
glEnd();
@@ -6633,7 +6507,7 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
}
setlinestyle(3);
- for (i = 0; i < cu->totbox; i++) {
+ for (int i = 0; i < cu->totbox; i++) {
if (cu->tb[i].w != 0.0f) {
UI_ThemeColor(i == (cu->actbox - 1) ? TH_ACTIVE : TH_WIRE);
vec1[0] = cu->xof + cu->tb[i].x;
@@ -6661,7 +6535,7 @@ static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *b
cpack(0xffffff);
set_inverted_drawing(1);
- for (i = 0; i <= seltot; i++) {
+ for (int i = 0; i <= seltot; i++) {
EditFontSelBox *sb = &ef->selboxes[i];
float tvec[3];
@@ -6846,15 +6720,12 @@ static void drawspiral(const float cent[3], float rad, float tmat[4][4], int sta
* all required matrices have been set (used for drawing empties) */
static void drawcircle_size(float size)
{
- float x, y;
- short degrees;
-
glBegin(GL_LINE_LOOP);
/* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */
- for (degrees = 0; degrees < CIRCLE_RESOL; degrees++) {
- x = cosval[degrees];
- y = sinval[degrees];
+ for (short degrees = 0; degrees < CIRCLE_RESOL; degrees++) {
+ float x = cosval[degrees];
+ float y = sinval[degrees];
glVertex3f(x * size, 0.0f, y * size);
}
@@ -6913,12 +6784,11 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
const char dt, const short dflag, const unsigned char ob_wire_col[4])
{
Object *ob = base->object;
- MetaBall *mb;
MetaElem *ml;
float imat[4][4];
int code = 1;
- mb = ob->data;
+ MetaBall *mb = ob->data;
if (mb->editelems) {
if ((G.f & G_PICKSEL) == 0) {
@@ -6955,6 +6825,8 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
}
}
+ glLineWidth(1.0f);
+
while (ml) {
/* draw radius */
if (mb->editelems) {
@@ -7138,31 +7010,21 @@ static void draw_forcefield(Object *ob, RegionView3D *rv3d,
setlinestyle(0);
}
-static void draw_box(float vec[8][3], bool solid)
+static void draw_box(const float vec[8][3], bool solid)
{
- if (!solid) {
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
- glVertex3fv(vec[0]); glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[6]);
- glVertex3fv(vec[7]); glVertex3fv(vec[4]);
- glEnd();
-
- glBegin(GL_LINES);
- glVertex3fv(vec[1]); glVertex3fv(vec[5]);
- glVertex3fv(vec[2]); glVertex3fv(vec[6]);
- glVertex3fv(vec[3]); glVertex3fv(vec[7]);
- glEnd();
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, vec);
+
+ if (solid) {
+ const GLubyte indices[24] = {0,1,2,3,7,6,5,4,4,5,1,0,3,2,6,7,3,7,4,0,1,5,6,2};
+ glDrawRangeElements(GL_QUADS, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
}
else {
- glBegin(GL_QUADS);
- glVertex3fv(vec[0]); glVertex3fv(vec[1]); glVertex3fv(vec[2]); glVertex3fv(vec[3]);
- glVertex3fv(vec[7]); glVertex3fv(vec[6]); glVertex3fv(vec[5]); glVertex3fv(vec[4]);
- glVertex3fv(vec[4]); glVertex3fv(vec[5]); glVertex3fv(vec[1]); glVertex3fv(vec[0]);
- glVertex3fv(vec[3]); glVertex3fv(vec[2]); glVertex3fv(vec[6]); glVertex3fv(vec[7]);
- glVertex3fv(vec[3]); glVertex3fv(vec[7]); glVertex3fv(vec[4]); glVertex3fv(vec[0]);
- glVertex3fv(vec[1]); glVertex3fv(vec[5]); glVertex3fv(vec[6]); glVertex3fv(vec[2]);
- glEnd();
+ const GLubyte indices[24] = {0,1,1,2,2,3,3,0,0,4,4,5,5,6,6,7,7,4,1,5,2,6,3,7};
+ glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices);
}
+
+ glDisableClientState(GL_VERTEX_ARRAY);
}
static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
@@ -7315,18 +7177,16 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
RegionView3D *rv3d = ar->regiondata;
Object *ob = base->object;
- glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
glDepthMask(0);
if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
- DerivedMesh *dm;
bool has_faces = false;
#ifdef SEQUENCER_DAG_WORKAROUND
ensure_curve_cache(scene, ob);
#endif
- dm = ob->derivedFinal;
+ DerivedMesh *dm = ob->derivedFinal;
if (dm) {
DM_update_materials(dm, ob);
}
@@ -7339,27 +7199,31 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->bb)) {
+ glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
if (dm) {
draw_mesh_object_outline(v3d, ob, dm);
}
else {
- drawDispListwire(&ob->curve_cache->disp, ob->type);
+ /* only draw 'solid' parts of the display list as wire. */
+ drawDispListwire_ex(&ob->curve_cache->disp, (DL_INDEX3 | DL_INDEX4 | DL_SURF));
}
}
}
else if (ob->type == OB_MBALL) {
if (BKE_mball_is_basis(ob)) {
if ((base->flag & OB_FROMDUPLI) == 0) {
+ glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
drawDispListwire(&ob->curve_cache->disp, ob->type);
}
}
}
else if (ob->type == OB_ARMATURE) {
- if (!(ob->mode & OB_MODE_POSE && base == scene->basact))
+ if (!(ob->mode & OB_MODE_POSE && base == scene->basact)) {
+ glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
draw_armature(scene, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true);
+ }
}
- glLineWidth(1.0);
glDepthMask(1);
}
@@ -7376,6 +7240,7 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
+ glLineWidth(1);
if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
@@ -7402,12 +7267,10 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const
/* should be called in view space */
static void draw_hooks(Object *ob)
{
- ModifierData *md;
- float vec[3];
-
- for (md = ob->modifiers.first; md; md = md->next) {
+ for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData *) md;
+ float vec[3];
mul_v3_m4v3(vec, ob->obmat, hmd->cent);
@@ -7421,10 +7284,9 @@ static void draw_hooks(Object *ob)
}
glPointSize(3.0);
- bglBegin(GL_POINTS);
- bglVertex3fv(vec);
- bglEnd();
- glPointSize(1.0);
+ glBegin(GL_POINTS);
+ glVertex3fv(vec);
+ glEnd();
}
}
}
@@ -7433,13 +7295,12 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data,
const short dflag, const unsigned char ob_wire_col[4])
{
const char *axis_str[3] = {"px", "py", "pz"};
- int axis;
float mat[4][4];
eul_to_mat4(mat, &data->axX);
glLineWidth(4.0f);
setlinestyle(2);
- for (axis = 0; axis < 3; axis++) {
+ for (int axis = 0; axis < 3; axis++) {
float dir[3] = {0, 0, 0};
float v[3];
@@ -7459,7 +7320,7 @@ static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data,
view3d_cached_text_draw_add(v, axis_str[axis], 2, 0, V3D_CACHE_TEXT_ASCII, ob_wire_col);
}
}
- glLineWidth(1.0f);
+
setlinestyle(0);
}
@@ -7610,8 +7471,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
unsigned int col = 0;
unsigned char _ob_wire_col[4]; /* dont initialize this */
const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */
- short dtx;
- char dt;
bool zbufoff = false, is_paint = false, empty_object = false;
const bool is_obact = (ob == OBACT);
const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
@@ -7653,7 +7512,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
- if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
+ if (((base->flag & OB_FROMDUPLI) == 0) &&
+ (md = modifiers_findByType(ob, eModifierType_Smoke)) &&
+ (modifier_isEnabled(scene, md, eModifierMode_Realtime)))
+ {
smd = (SmokeModifierData *)md;
if (smd->domain) {
@@ -7699,6 +7561,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* only once set now, will be removed too, should become a global standard */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ /* reset here to avoid having to call all over */
+ glLineWidth(1.0f);
view3d_cached_text_draw_begin();
@@ -7732,11 +7596,11 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* maximum drawtype */
- dt = v3d->drawtype;
+ char dt = v3d->drawtype;
if (dt == OB_RENDER) dt = OB_SOLID;
dt = MIN2(dt, ob->dt);
if (v3d->zbuf == 0 && dt > OB_WIRE) dt = OB_WIRE;
- dtx = 0;
+ short dtx = 0;
/* faceselect exception: also draw solid when (dt == wire), except in editmode */
@@ -7857,7 +7721,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
draw_empty_image(ob, dflag, ob_wire_col);
}
else {
- drawaxes(ob->empty_drawsize, ob->empty_drawtype);
+ drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype);
}
}
break;
@@ -7902,17 +7766,14 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
draw_bounding_volume(ob, ob->boundtype);
}
else {
- if (dt > OB_WIRE)
- GPU_enable_material(0, NULL); /* we use default material */
+ glLineWidth(1.0f);
empty_object = draw_armature(scene, v3d, ar, base, dt, dflag, ob_wire_col, false);
- if (dt > OB_WIRE)
- GPU_disable_material();
}
}
break;
default:
if (!render_override) {
- drawaxes(1.0, OB_ARROWS);
+ drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS);
}
break;
}
@@ -8011,15 +7872,14 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
// glPointSize(3.0);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
for (i = 0; i < scs->numpoints; i++)
{
- bglVertex3fv(&scs->points[3 * i]);
+ glVertex3fv(&scs->points[3 * i]);
}
- bglEnd();
- glPointSize(1.0);
+ glEnd();
glMultMatrixf(ob->obmat);
glDisable(GL_BLEND);
@@ -8037,25 +7897,42 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
glLoadMatrixf(rv3d->viewmat);
glMultMatrixf(ob->obmat);
- /* draw adaptive domain bounds */
- if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) && !render_override) {
- float p0[3], p1[3];
+ if (!render_override) {
BoundBox bb;
- /* draw domain max bounds */
- VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
- VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
- BKE_boundbox_init_from_minmax(&bb, p0, p1);
- draw_box(bb.vec, false);
+ float p0[3], p1[3];
+
+ /* draw adaptive domain bounds */
+ if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)) {
+ /* draw domain max bounds */
+ VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res);
+ VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res);
+ BKE_boundbox_init_from_minmax(&bb, p0, p1);
+ draw_box(bb.vec, false);
+ }
#if 0
/* draw base resolution bounds */
BKE_boundbox_init_from_minmax(&bb, sds->p0, sds->p1);
draw_box(bb.vec);
#endif
+
+
+ /* draw a single voxel to hint the user about the resolution of the fluid */
+ copy_v3_v3(p0, sds->p0);
+
+ if (sds->flags & MOD_SMOKE_HIGHRES) {
+ madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1));
+ }
+ else {
+ add_v3_v3v3(p1, p0, sds->cell_size);
+ }
+
+ BKE_boundbox_init_from_minmax(&bb, p0, p1);
+ draw_box(bb.vec, false);
}
/* don't show smoke before simulation starts, this could be made an option in the future */
- if (smd->domain->fluid && CFRA >= smd->domain->point_cache[0]->startframe) {
+ if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) {
float p0[3], p1[3];
/* get view vector */
@@ -8074,21 +7951,15 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
p1[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_max[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]);
if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
- smd->domain->tex = NULL;
+ sds->tex = NULL;
GPU_create_smoke(smd, 0);
- draw_smoke_volume(sds, ob, sds->tex,
- p0, p1,
- sds->res, sds->dx, sds->scale * sds->maxres,
- viewnormal, sds->tex_shadow, sds->tex_flame);
+ draw_smoke_volume(sds, ob, p0, p1, viewnormal);
GPU_free_smoke(smd);
}
else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) {
sds->tex = NULL;
GPU_create_smoke(smd, 1);
- draw_smoke_volume(sds, ob, sds->tex,
- p0, p1,
- sds->res_wt, sds->dx, sds->scale * sds->maxres,
- viewnormal, sds->tex_shadow, sds->tex_flame);
+ draw_smoke_volume(sds, ob, p0, p1, viewnormal);
GPU_free_smoke(smd);
}
@@ -8129,7 +8000,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (dtx && (G.f & G_RENDER_OGL) == 0) {
if (dtx & OB_AXIS) {
- drawaxes(1.0f, OB_ARROWS);
+ drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS);
}
if (dtx & OB_DRAWBOUNDOX) {
draw_bounding_volume(ob, ob->boundtype);
@@ -8213,13 +8084,21 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (do_draw_center != -1) {
if (dflag & DRAW_PICKING) {
/* draw a single point for opengl selection */
- glBegin(GL_POINTS);
- glVertex3fv(ob->obmat[3]);
- glEnd();
+ if ((base->sx != IS_CLIPPED) &&
+ (U.obcenter_dia != 0.0))
+ {
+ glPointSize(U.obcenter_dia);
+ glBegin(GL_POINTS);
+ glVertex3fv(ob->obmat[3]);
+ glEnd();
+ }
}
else if ((dflag & DRAW_CONSTCOLOR) == 0) {
/* we don't draw centers for duplicators and sets */
- if (U.obcenter_dia > 0 && !(G.f & G_RENDER_OGL)) {
+ if ((base->sx != IS_CLIPPED) &&
+ (U.obcenter_dia != 0.0) &&
+ !(G.f & G_RENDER_OGL))
+ {
/* check > 0 otherwise grease pencil can draw into the circle select which is annoying. */
drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us > 1);
}
@@ -8351,7 +8230,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa
if (!(mv->flag & ME_HIDE)) {
WM_framebuffer_index_set(data->offset + index);
- bglVertex3fv(co);
+ glVertex3fv(co);
}
}
@@ -8363,10 +8242,9 @@ static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
data.mvert = mvert;
data.offset = offset;
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
- bglEnd();
- glPointSize(1.0);
+ glEnd();
}
static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3],
@@ -8377,17 +8255,16 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3]
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
WM_framebuffer_index_set(data->offset + index);
- bglVertex3fv(co);
+ glVertex3fv(co);
}
}
static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
{
drawBMOffset_userData data = {em->bm, offset};
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
- bglEnd();
- glPointSize(1.0);
+ glEnd();
}
static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
@@ -8444,7 +8321,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
WM_framebuffer_index_set(index + 1);
- bglVertex3fv(cent);
+ glVertex3fv(cent);
}
}
@@ -8460,9 +8337,9 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
if (check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, em->bm, DM_FOREACH_NOP);
- bglEnd();
+ glEnd();
}
}
@@ -8511,7 +8388,9 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
DM_update_materials(dm, ob);
- dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, DM_DRAW_SKIP_HIDDEN);
+ dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_object_material_bind, NULL, me, DM_DRAW_SKIP_HIDDEN);
+
+ GPU_object_material_unbind();
bbs_obmode_mesh_verts(ob, dm, 1);
bm_vertoffs = me->totvert + 1;
@@ -8612,7 +8491,6 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
{
Mesh *me = ob->data;
DerivedMesh *dm = NULL, *edm = NULL;
- int glsl;
if (ob->mode & OB_MODE_EDIT) {
edm = editbmesh_get_derived_base(ob, me->edit_btmesh);
@@ -8634,26 +8512,20 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
draw_mesh_object_outline(v3d, ob, dm ? dm : edm);
if (dm) {
- glsl = draw_glsl_material(scene, ob, v3d, dt);
+ bool glsl = draw_glsl_material(scene, ob, v3d, dt);
GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL);
}
- else {
- glEnable(GL_COLOR_MATERIAL);
- UI_ThemeColor(TH_BONE_SOLID);
- glDisable(GL_COLOR_MATERIAL);
- }
glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW);
- glEnable(GL_LIGHTING);
if (dm) {
- dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
+ dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind);
GPU_end_object_materials();
}
else if (edm)
- edm->drawMappedFaces(edm, NULL, GPU_enable_material, NULL, NULL, 0);
-
- glDisable(GL_LIGHTING);
+ edm->drawMappedFaces(edm, NULL, GPU_object_material_bind, NULL, NULL, DM_DRAW_NEED_NORMALS);
+
+ GPU_object_material_unbind();
}
if (edm) edm->release(edm);
@@ -8675,7 +8547,7 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
draw_empty_image(ob, DRAW_CONSTCOLOR, NULL);
}
else {
- drawaxes(ob->empty_drawsize, ob->empty_drawtype);
+ drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype);
}
break;
}
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
index 46320ba6763..91adc905816 100644
--- a/source/blender/editors/space_view3d/drawsimdebug.c
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -62,7 +62,6 @@ static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
}
glEnd();
- glPointSize(1.0f);
/**** circles ****/
@@ -123,7 +122,6 @@ static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
}
glEnd();
- glPointSize(1.0f);
glBegin(GL_LINES);
for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index d6691f431dd..e93d840eddd 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -46,7 +46,9 @@
#include "BIF_gl.h"
-#include "GPU_extensions.h"
+#include "GPU_debug.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
#include "view3d_intern.h" // own include
@@ -59,375 +61,366 @@ struct GPUTexture;
# include "PIL_time_utildefines.h"
#endif
-static int intersect_edges(float (*points)[3], float a, float b, float c, float d, float edges[12][2][3])
+static GPUTexture *create_flame_spectrum_texture(void)
{
- int i;
- float t;
- int numpoints = 0;
-
- for (i = 0; i < 12; i++) {
- t = -(a * edges[i][0][0] + b * edges[i][0][1] + c * edges[i][0][2] + d) /
- (a * edges[i][1][0] + b * edges[i][1][1] + c * edges[i][1][2]);
- if ((t > 0) && (t < 1)) {
- points[numpoints][0] = edges[i][0][0] + edges[i][1][0] * t;
- points[numpoints][1] = edges[i][0][1] + edges[i][1][1] * t;
- points[numpoints][2] = edges[i][0][2] + edges[i][1][2] * t;
- numpoints++;
- }
- }
- return numpoints;
-}
-
-static bool convex(const float p0[3], const float up[3], const float a[3], const float b[3])
-{
- /* Vec3 va = a-p0, vb = b-p0; */
- float va[3], vb[3], tmp[3];
- sub_v3_v3v3(va, a, p0);
- sub_v3_v3v3(vb, b, p0);
- cross_v3_v3v3(tmp, va, vb);
- return dot_v3v3(up, tmp) >= 0;
-}
-
-void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
- GPUTexture *tex, const float min[3], const float max[3],
- const int res[3], float dx, float UNUSED(base_scale), const float viewnormal[3],
- GPUTexture *tex_shadow, GPUTexture *tex_flame)
-{
- const float ob_sizei[3] = {
- 1.0f / fabsf(ob->size[0]),
- 1.0f / fabsf(ob->size[1]),
- 1.0f / fabsf(ob->size[2])};
-
- int i, j, k, n, good_index;
- float d /*, d0 */ /* UNUSED */, dd, ds;
- float (*points)[3] = NULL;
- int numpoints = 0;
- float cor[3] = {1.0f, 1.0f, 1.0f};
- int gl_depth = 0, gl_blend = 0;
-
- const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0;
-
- /* draw slices of smoke is adapted from c++ code authored
- * by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */
- float cv[][3] = {
- {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f},
- {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}
- };
-
- /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */
- float edges[12][2][3] = {
- {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
- {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
- {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
- {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}},
-
- {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
- {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}},
- {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
- {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}},
-
- {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
- {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}},
- {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}},
- {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}
- };
-
- unsigned char *spec_data;
- float *spec_pixels;
- GPUTexture *tex_spec;
- GPUProgram *smoke_program;
- int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE;
- float size[3];
-
- if (!tex) {
- printf("Could not allocate 3D texture for 3D View smoke drawing.\n");
- return;
- }
-
-#ifdef DEBUG_DRAW_TIME
- TIMEIT_START(draw);
-#endif
-
- /* generate flame spectrum texture */
#define SPEC_WIDTH 256
#define FIRE_THRESH 7
#define MAX_FIRE_ALPHA 0.06f
#define FULL_ON_FIRE 100
- spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char));
- flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000);
- spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float));
+
+ GPUTexture *tex;
+ int i, j, k;
+ float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data");
+ float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels");
+
+ blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000);
+
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
for (k = 0; k < SPEC_WIDTH; k++) {
int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4;
if (k >= FIRE_THRESH) {
- spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f;
- spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f;
- spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f;
+ spec_pixels[index] = (spec_data[k * 4]);
+ spec_pixels[index + 1] = (spec_data[k * 4 + 1]);
+ spec_pixels[index + 2] = (spec_data[k * 4 + 2]);
spec_pixels[index + 3] = MAX_FIRE_ALPHA * (
(k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH));
}
else {
- spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f;
+ zero_v4(&spec_pixels[index]);
}
}
}
}
- tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
+ tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL);
+
+ MEM_freeN(spec_data);
+ MEM_freeN(spec_pixels);
#undef SPEC_WIDTH
#undef FIRE_THRESH
#undef MAX_FIRE_ALPHA
#undef FULL_ON_FIRE
- sub_v3_v3v3(size, max, min);
-
- /* maxx, maxy, maxz */
- cv[0][0] = max[0];
- cv[0][1] = max[1];
- cv[0][2] = max[2];
- /* minx, maxy, maxz */
- cv[1][0] = min[0];
- cv[1][1] = max[1];
- cv[1][2] = max[2];
- /* minx, miny, maxz */
- cv[2][0] = min[0];
- cv[2][1] = min[1];
- cv[2][2] = max[2];
- /* maxx, miny, maxz */
- cv[3][0] = max[0];
- cv[3][1] = min[1];
- cv[3][2] = max[2];
-
- /* maxx, maxy, minz */
- cv[4][0] = max[0];
- cv[4][1] = max[1];
- cv[4][2] = min[2];
- /* minx, maxy, minz */
- cv[5][0] = min[0];
- cv[5][1] = max[1];
- cv[5][2] = min[2];
- /* minx, miny, minz */
- cv[6][0] = min[0];
- cv[6][1] = min[1];
- cv[6][2] = min[2];
- /* maxx, miny, minz */
- cv[7][0] = max[0];
- cv[7][1] = min[1];
- cv[7][2] = min[2];
-
- copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */
- copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */
- copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */
- copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */
-
- copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */
- copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */
- copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */
- copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */
-
- copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */
- copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */
- copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */
- copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */
-
- // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]);
- // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]);
-
- edges[0][1][2] = size[2];
- edges[1][1][2] = size[2];
- edges[2][1][2] = size[2];
- edges[3][1][2] = size[2];
-
- edges[4][1][1] = size[1];
- edges[5][1][1] = size[1];
- edges[6][1][1] = size[1];
- edges[7][1][1] = size[1];
-
- edges[8][1][0] = size[0];
- edges[9][1][0] = size[0];
- edges[10][1][0] = size[0];
- edges[11][1][0] = size[0];
+ return tex;
+}
- glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
- glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
+typedef struct VolumeSlicer {
+ float size[3];
+ float min[3];
+ float max[3];
+ float (*verts)[3];
+} VolumeSlicer;
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
+/* *************************** View Aligned Slicing ************************** */
+
+/* Code adapted from:
+ * "GPU-based Volume Rendering, Real-time Volume Graphics", AK Peters/CRC Press
+ */
+static int create_view_aligned_slices(VolumeSlicer *slicer,
+ const int num_slices,
+ const float view_dir[3])
+{
+ const int indices[] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 };
+
+ const float vertices[8][3] = {
+ { slicer->min[0], slicer->min[1], slicer->min[2] },
+ { slicer->max[0], slicer->min[1], slicer->min[2] },
+ { slicer->max[0], slicer->max[1], slicer->min[2] },
+ { slicer->min[0], slicer->max[1], slicer->min[2] },
+ { slicer->min[0], slicer->min[1], slicer->max[2] },
+ { slicer->max[0], slicer->min[1], slicer->max[2] },
+ { slicer->max[0], slicer->max[1], slicer->max[2] },
+ { slicer->min[0], slicer->max[1], slicer->max[2] }
+ };
+
+ const int edges[12][2] = {
+ { 0, 1 }, { 1, 2 }, { 2, 3 },
+ { 3, 0 }, { 0, 4 }, { 1, 5 },
+ { 2, 6 }, { 3, 7 }, { 4, 5 },
+ { 5, 6 }, { 6, 7 }, { 7, 4 }
+ };
+
+ const int edge_list[8][12] = {
+ { 0, 1, 5, 6, 4, 8, 11, 9, 3, 7, 2, 10 },
+ { 0, 4, 3, 11, 1, 2, 6, 7, 5, 9, 8, 10 },
+ { 1, 5, 0, 8, 2, 3, 7, 4, 6, 10, 9, 11 },
+ { 7, 11, 10, 8, 2, 6, 1, 9, 3, 0, 4, 5 },
+ { 8, 5, 9, 1, 11, 10, 7, 6, 4, 3, 0, 2 },
+ { 9, 6, 10, 2, 8, 11, 4, 7, 5, 0, 1, 3 },
+ { 9, 8, 5, 4, 6, 1, 2, 0, 10, 7, 11, 3 },
+ { 10, 9, 6, 5, 7, 2, 3, 1, 11, 4, 8, 0 }
+ };
- /* find cube vertex that is closest to the viewer */
- for (i = 0; i < 8; i++) {
- float x, y, z;
+ /* find vertex that is the furthest from the view plane */
+ int max_index = 0;
+ float max_dist, min_dist;
+ min_dist = max_dist = dot_v3v3(view_dir, vertices[0]);
- x = cv[i][0] - viewnormal[0] * size[0] * 0.5f;
- y = cv[i][1] - viewnormal[1] * size[1] * 0.5f;
- z = cv[i][2] - viewnormal[2] * size[2] * 0.5f;
+ for (int i = 1; i < 8; i++) {
+ float dist = dot_v3v3(view_dir, vertices[i]);
- if ((x >= min[0]) && (x <= max[0]) &&
- (y >= min[1]) && (y <= max[1]) &&
- (z >= min[2]) && (z <= max[2]))
- {
- break;
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_index = i;
+ }
+
+ if (dist < min_dist) {
+ min_dist = dist;
}
}
- if (i >= 8) {
- /* fallback, avoid using buffer over-run */
- i = 0;
+ max_dist -= FLT_EPSILON;
+ min_dist += FLT_EPSILON;
+
+ /* start and direction vectors */
+ float vec_start[12][3], vec_dir[12][3];
+ /* lambda intersection values */
+ float lambda[12], lambda_inc[12];
+ float denom = 0.0f;
+
+ float plane_dist = min_dist;
+ float plane_dist_inc = (max_dist - min_dist) / (float)num_slices;
+
+ /* for all egdes */
+ for (int i = 0; i < 12; i++) {
+ copy_v3_v3(vec_start[i], vertices[edges[edge_list[max_index][i]][0]]);
+ copy_v3_v3(vec_dir[i], vertices[edges[edge_list[max_index][i]][1]]);
+ sub_v3_v3(vec_dir[i], vec_start[i]);
+
+ denom = dot_v3v3(vec_dir[i], view_dir);
+
+ if (1.0f + denom != 1.0f) {
+ lambda_inc[i] = plane_dist_inc / denom;
+ lambda[i] = (plane_dist - dot_v3v3(vec_start[i], view_dir)) / denom;
+ }
+ else {
+ lambda[i] = -1.0f;
+ lambda_inc[i] = 0.0f;
+ }
}
- // printf("i: %d\n", i);
- // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]);
+ float intersections[6][3];
+ float dL[12];
+ int num_points = 0;
+ /* find intersections for each slice, process them in back to front order */
+ for (int i = 0; i < num_slices; i++) {
+ for (int e = 0; e < 12; e++) {
+ dL[e] = lambda[e] + i * lambda_inc[e];
+ }
+
+ if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[0], vec_start[0], vec_dir[0], dL[0]);
+ }
+ else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[0], vec_start[1], vec_dir[1], dL[1]);
+ }
+ else if ((dL[3] >= 0.0f) && (dL[3] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[0], vec_start[3], vec_dir[3], dL[3]);
+ }
+ else continue;
+
+ if ((dL[2] >= 0.0f) && (dL[2] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[1], vec_start[2], vec_dir[2], dL[2]);
+ }
+ else if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[1], vec_start[0], vec_dir[0], dL[0]);
+ }
+ else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[1], vec_start[1], vec_dir[1], dL[1]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[1], vec_start[3], vec_dir[3], dL[3]);
+ }
+
+ if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[2], vec_start[4], vec_dir[4], dL[4]);
+ }
+ else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[2], vec_start[5], vec_dir[5], dL[5]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[2], vec_start[7], vec_dir[7], dL[7]);
+ }
+
+ if ((dL[6] >= 0.0f) && (dL[6] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[3], vec_start[6], vec_dir[6], dL[6]);
+ }
+ else if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[3], vec_start[4], vec_dir[4], dL[4]);
+ }
+ else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[3], vec_start[5], vec_dir[5], dL[5]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[3], vec_start[7], vec_dir[7], dL[7]);
+ }
+
+ if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[4], vec_start[8], vec_dir[8], dL[8]);
+ }
+ else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[4], vec_start[9], vec_dir[9], dL[9]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[4], vec_start[11], vec_dir[11], dL[11]);
+ }
- smoke_program = GPU_shader_get_builtin_program(progtype);
- if (smoke_program) {
- GPU_program_bind(smoke_program);
+ if ((dL[10] >= 0.0f) && (dL[10] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[5], vec_start[10], vec_dir[10], dL[10]);
+ }
+ else if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[5], vec_start[8], vec_dir[8], dL[8]);
+ }
+ else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) {
+ madd_v3_v3v3fl(intersections[5], vec_start[9], vec_dir[9], dL[9]);
+ }
+ else {
+ madd_v3_v3v3fl(intersections[5], vec_start[11], vec_dir[11], dL[11]);
+ }
- /* cell spacing */
- GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0);
- /* custom parameter for smoke style (higher = thicker) */
- if (sds->active_fields & SM_ACTIVE_COLORS)
- GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0);
- else
- GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0);
+ for (int e = 0; e < 12; e++) {
+ copy_v3_v3(slicer->verts[num_points++], intersections[indices[e]]);
+ }
}
- else
- printf("Your gfx card does not support 3D View smoke drawing.\n");
- GPU_texture_bind(tex, 0);
- if (tex_shadow)
- GPU_texture_bind(tex_shadow, 1);
- else
- printf("No volume shadow\n");
+ return num_points;
+}
- if (tex_flame) {
- GPU_texture_bind(tex_flame, 2);
- GPU_texture_bind(tex_spec, 3);
+void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
+ const float min[3], const float max[3],
+ const float viewnormal[3])
+{
+ if (!sds->tex || !sds->tex_shadow) {
+ fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n");
+ return;
}
- if (!GPU_non_power_of_two_support()) {
- cor[0] = (float)res[0] / (float)power_of_2_max_u(res[0]);
- cor[1] = (float)res[1] / (float)power_of_2_max_u(res[1]);
- cor[2] = (float)res[2] / (float)power_of_2_max_u(res[2]);
+ const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(
+ (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE);
+
+ if (!shader) {
+ fprintf(stderr, "Unable to create GLSL smoke shader.\n");
+ return;
}
- cor[0] /= size[0];
- cor[1] /= size[1];
- cor[2] /= size[2];
+ const float ob_sizei[3] = {
+ 1.0f / fabsf(ob->size[0]),
+ 1.0f / fabsf(ob->size[1]),
+ 1.0f / fabsf(ob->size[2])
+ };
+
+ const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] };
+ const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] };
- /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0
- * (a,b,c), the plane normal, are given by viewdir
- * d is the parameter along the view direction. the first d is given by
- * inserting previously found vertex into the plane equation */
+#ifdef DEBUG_DRAW_TIME
+ TIMEIT_START(draw);
+#endif
- /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */
- ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]);
- dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f;
- n = 0;
- good_index = i;
+ /* setup smoke shader */
- // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds);
+ int soot_location = GPU_shader_get_uniform(shader, "soot_texture");
+ int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
+ int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
+ int flame_location = GPU_shader_get_uniform(shader, "flame_texture");
+ int actcol_location = GPU_shader_get_uniform(shader, "active_color");
+ int stepsize_location = GPU_shader_get_uniform(shader, "step_size");
+ int densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
+ int invsize_location = GPU_shader_get_uniform(shader, "invsize");
+ int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
+ int min_location = GPU_shader_get_uniform(shader, "min_location");
- points = MEM_callocN(sizeof(*points) * 12, "smoke_points_preview");
+ GPU_shader_bind(shader);
- while (1) {
- float p0[3];
- float tmp_point[3], tmp_point2[3];
+ GPU_texture_bind(sds->tex, 0);
+ GPU_shader_uniform_texture(shader, soot_location, sds->tex);
- if (dd * (float)n > ds)
- break;
+ GPU_texture_bind(sds->tex_shadow, 1);
+ GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
- copy_v3_v3(tmp_point, viewnormal);
- mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n));
- add_v3_v3v3(tmp_point2, cv[good_index], tmp_point);
- d = dot_v3v3(tmp_point2, viewnormal);
+ GPUTexture *tex_spec = NULL;
- // printf("my d: %f\n", d);
+ if (use_fire) {
+ GPU_texture_bind(sds->tex_flame, 2);
+ GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
- /* intersect_edges returns the intersection points of all cube edges with
- * the given plane that lie within the cube */
- numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges);
+ tex_spec = create_flame_spectrum_texture();
+ GPU_texture_bind(tex_spec, 3);
+ GPU_shader_uniform_texture(shader, spec_location, tex_spec);
+ }
- // printf("points: %d\n", numpoints);
+ float active_color[3] = { 0.9, 0.9, 0.9 };
+ float density_scale = 10.0f;
+ if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
+ mul_v3_v3(active_color, sds->active_color);
- if (numpoints > 2) {
- copy_v3_v3(p0, points[0]);
+ GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
+ GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
+ GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
+ GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
+ GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
+ GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
- /* sort points to get a convex polygon */
- for (i = 1; i < numpoints - 1; i++) {
- for (j = i + 1; j < numpoints; j++) {
- if (!convex(p0, viewnormal, points[j], points[i])) {
- swap_v3_v3(points[i], points[j]);
- }
- }
- }
+ /* setup slicing information */
- /* render fire slice */
- if (use_fire) {
- if (GLEW_VERSION_1_4)
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
- else
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
-
- GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0);
- glBegin(GL_POLYGON);
- glColor3f(1.0, 1.0, 1.0);
- for (i = 0; i < numpoints; i++) {
- glTexCoord3d((points[i][0] - min[0]) * cor[0],
- (points[i][1] - min[1]) * cor[1],
- (points[i][2] - min[2]) * cor[2]);
- glVertex3f(points[i][0] * ob_sizei[0],
- points[i][1] * ob_sizei[1],
- points[i][2] * ob_sizei[2]);
- }
- glEnd();
- }
+ const int max_slices = 256;
+ const int max_points = max_slices * 12;
- /* render smoke slice */
- if (GLEW_VERSION_1_4)
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- else
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0);
- glBegin(GL_POLYGON);
- glColor3f(1.0, 1.0, 1.0);
- for (i = 0; i < numpoints; i++) {
- glTexCoord3d((points[i][0] - min[0]) * cor[0],
- (points[i][1] - min[1]) * cor[1],
- (points[i][2] - min[2]) * cor[2]);
- glVertex3f(points[i][0] * ob_sizei[0],
- points[i][1] * ob_sizei[1],
- points[i][2] * ob_sizei[2]);
- }
- glEnd();
- }
- n++;
- }
+ VolumeSlicer slicer;
+ copy_v3_v3(slicer.min, min);
+ copy_v3_v3(slicer.max, max);
+ copy_v3_v3(slicer.size, size);
+ slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices");
+
+ const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal);
+
+ /* setup buffer and draw */
+
+ int gl_depth = 0, gl_blend = 0;
+ glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend);
+ glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth);
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ GLuint vertex_buffer;
+ glGenBuffers(1, &vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, NULL);
+
+ glDrawArrays(GL_TRIANGLES, 0, num_points);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
#ifdef DEBUG_DRAW_TIME
printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
TIMEIT_END(draw);
#endif
- if (tex_shadow)
- GPU_texture_unbind(tex_shadow);
- GPU_texture_unbind(tex);
- if (tex_flame) {
- GPU_texture_unbind(tex_flame);
- GPU_texture_unbind(tex_spec);
- }
- GPU_texture_free(tex_spec);
+ /* cleanup */
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &vertex_buffer);
- free(spec_data);
- free(spec_pixels);
+ GPU_texture_unbind(sds->tex);
+ GPU_texture_unbind(sds->tex_shadow);
- if (smoke_program)
- GPU_program_unbind(smoke_program);
+ if (use_fire) {
+ GPU_texture_unbind(sds->tex_flame);
+ GPU_texture_unbind(tex_spec);
+ GPU_texture_free(tex_spec);
+ }
+ MEM_freeN(slicer.verts);
- MEM_freeN(points);
+ GPU_shader_unbind();
if (!gl_blend) {
glDisable(GL_BLEND);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 7869522e8fb..fa14ca96fe2 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -54,9 +54,9 @@
#include "ED_space_api.h"
#include "ED_screen.h"
-#include "GPU_extensions.h"
-#include "GPU_material.h"
#include "GPU_compositing.h"
+#include "GPU_framebuffer.h"
+#include "GPU_material.h"
#include "BIF_gl.h"
@@ -342,7 +342,7 @@ static SpaceLink *view3d_new(const bContext *C)
v3d->twflag |= U.tw_flag & V3D_USE_MANIPULATOR;
v3d->twtype = V3D_MANIP_TRANSLATE;
- v3d->around = V3D_CENTROID;
+ v3d->around = V3D_AROUND_CENTER_MEAN;
v3d->bundle_size = 0.2f;
v3d->bundle_drawtype = OB_PLAINAXES;
@@ -384,8 +384,8 @@ static SpaceLink *view3d_new(const bContext *C)
ar->alignment = RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
- /* main area */
- ar = MEM_callocN(sizeof(ARegion), "main area for view3d");
+ /* main region */
+ ar = MEM_callocN(sizeof(ARegion), "main region for view3d");
BLI_addtail(&v3d->regionbase, ar);
ar->regiontype = RGN_TYPE_WINDOW;
@@ -394,7 +394,7 @@ static SpaceLink *view3d_new(const bContext *C)
rv3d = ar->regiondata;
rv3d->viewquat[0] = 1.0f;
rv3d->persp = RV3D_PERSP;
- rv3d->view = RV3D_VIEW_PERSPORTHO;
+ rv3d->view = RV3D_VIEW_USER;
rv3d->dist = 10.0;
return (SpaceLink *)v3d;
@@ -482,7 +482,7 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
+static void view3d_main_region_init(wmWindowManager *wm, ARegion *ar)
{
ListBase *lb;
wmKeyMap *keymap;
@@ -567,7 +567,7 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
}
-static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
+static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
@@ -715,7 +715,7 @@ static void view3d_dropboxes(void)
/* type callback, not region itself */
-static void view3d_main_area_free(ARegion *ar)
+static void view3d_main_region_free(ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
@@ -746,7 +746,7 @@ static void view3d_main_area_free(ARegion *ar)
}
/* copy regiondata */
-static void *view3d_main_area_duplicate(void *poin)
+static void *view3d_main_region_duplicate(void *poin)
{
if (poin) {
RegionView3D *rv3d = poin, *new;
@@ -799,7 +799,7 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene
}
}
-static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn)
+static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn)
{
Scene *scene = sc->scene;
View3D *v3d = sa->spacedata.first;
@@ -1025,7 +1025,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
}
/* concept is to retrieve cursor type context-less */
-static void view3d_main_area_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
+static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar))
{
Scene *scene = win->screen->scene;
@@ -1038,7 +1038,7 @@ static void view3d_main_area_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion
}
/* add handlers, stuff you only do once or on area/region changes */
-static void view3d_header_area_init(wmWindowManager *wm, ARegion *ar)
+static void view3d_header_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0);
@@ -1047,12 +1047,12 @@ static void view3d_header_area_init(wmWindowManager *wm, ARegion *ar)
ED_region_header_init(ar);
}
-static void view3d_header_area_draw(const bContext *C, ARegion *ar)
+static void view3d_header_region_draw(const bContext *C, ARegion *ar)
{
ED_region_header(C, ar);
}
-static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void view3d_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1083,7 +1083,7 @@ static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
}
/* add handlers, stuff you only do once or on area/region changes */
-static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar)
+static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1093,12 +1093,12 @@ static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void view3d_buttons_area_draw(const bContext *C, ARegion *ar)
+static void view3d_buttons_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, NULL, -1, true);
}
-static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void view3d_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1189,7 +1189,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
/* add handlers, stuff you only do once or on area/region changes */
-static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar)
+static void view3d_tools_region_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -1199,12 +1199,12 @@ static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-static void view3d_tools_area_draw(const bContext *C, ARegion *ar)
+static void view3d_tools_region_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, CTX_data_mode_string(C), -1, true);
}
-static void view3d_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
+static void view3d_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
@@ -1223,7 +1223,7 @@ static void view3d_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa),
}
}
-/*area (not region) level listener*/
+/* area (not region) level listener */
static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn)
{
View3D *v3d = sa->spacedata.first;
@@ -1424,13 +1424,13 @@ void ED_spacetype_view3d(void)
art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_GPENCIL;
- art->draw = view3d_main_area_draw;
- art->init = view3d_main_area_init;
- art->exit = view3d_main_area_exit;
- art->free = view3d_main_area_free;
- art->duplicate = view3d_main_area_duplicate;
- art->listener = view3d_main_area_listener;
- art->cursor = view3d_main_area_cursor;
+ art->draw = view3d_main_region_draw;
+ art->init = view3d_main_region_init;
+ art->exit = view3d_main_region_exit;
+ art->free = view3d_main_region_free;
+ art->duplicate = view3d_main_region_duplicate;
+ art->listener = view3d_main_region_listener;
+ art->cursor = view3d_main_region_cursor;
art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */
BLI_addhead(&st->regiontypes, art);
@@ -1439,9 +1439,9 @@ void ED_spacetype_view3d(void)
art->regionid = RGN_TYPE_UI;
art->prefsizex = 180; /* XXX */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = view3d_buttons_area_listener;
- art->init = view3d_buttons_area_init;
- art->draw = view3d_buttons_area_draw;
+ art->listener = view3d_buttons_region_listener;
+ art->init = view3d_buttons_region_init;
+ art->draw = view3d_buttons_region_draw;
BLI_addhead(&st->regiontypes, art);
view3d_buttons_register(art);
@@ -1452,9 +1452,9 @@ void ED_spacetype_view3d(void)
art->prefsizex = 160; /* XXX */
art->prefsizey = 50; /* XXX */
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = view3d_buttons_area_listener;
- art->init = view3d_tools_area_init;
- art->draw = view3d_tools_area_draw;
+ art->listener = view3d_buttons_region_listener;
+ art->init = view3d_tools_region_init;
+ art->draw = view3d_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
#if 0
@@ -1468,9 +1468,9 @@ void ED_spacetype_view3d(void)
art->prefsizex = 0;
art->prefsizey = 120;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
- art->listener = view3d_props_area_listener;
- art->init = view3d_tools_area_init;
- art->draw = view3d_tools_area_draw;
+ art->listener = view3d_props_region_listener;
+ art->init = view3d_tools_region_init;
+ art->draw = view3d_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
view3d_tool_props_register(art);
@@ -1481,9 +1481,9 @@ void ED_spacetype_view3d(void)
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
- art->listener = view3d_header_area_listener;
- art->init = view3d_header_area_init;
- art->draw = view3d_header_area_draw;
+ art->listener = view3d_header_region_listener;
+ art->init = view3d_header_region_init;
+ art->draw = view3d_header_region_draw;
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index d5fd18a77db..c52d1238163 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1156,7 +1156,7 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
}
else {
View3D *v3d = CTX_wm_view3d(C);
- const float lim = 10000.0f * max_ff(1.0f, v3d->grid);
+ const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL));
v3d_editvertex_buts(col, v3d, ob, lim);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index d9ad481ab33..7f1a7a059fc 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -48,6 +48,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_jitter.h"
#include "BLI_utildefines.h"
#include "BLI_endian_switch.h"
#include "BLI_threads.h"
@@ -95,9 +96,10 @@
#include "UI_resources.h"
#include "GPU_draw.h"
+#include "GPU_framebuffer.h"
#include "GPU_material.h"
-#include "GPU_extensions.h"
#include "GPU_compositing.h"
+#include "GPU_extensions.h"
#include "view3d_intern.h" /* own include */
@@ -303,6 +305,8 @@ static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **
dx = fabs(x - (wx) * fx / fw);
if (dx == 0) dx = fabs(y - (wy) * fy / fw);
+ glLineWidth(1.0f);
+
glDepthMask(GL_FALSE); /* disable write in zbuffer */
/* check zoom out */
@@ -489,6 +493,8 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool wr
UI_GetThemeColor3ubv(TH_GRID, col_grid);
+ glLineWidth(1);
+
/* draw the Y axis and/or grid lines */
if (v3d->gridflag & V3D_SHOW_FLOOR) {
const int sublines = v3d->gridsubdiv;
@@ -534,6 +540,7 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool wr
/* draw the Z axis line */
/* check for the 'show Z axis' preference */
if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) {
+ glBegin(GL_LINES);
int axis;
for (axis = 0; axis < 3; axis++) {
if (v3d->gridflag & (V3D_SHOW_X << axis)) {
@@ -543,15 +550,14 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool wr
UI_make_axis_color(col_grid, tcol, 'X' + axis);
glColor3ubv(tcol);
- glBegin(GL_LINE_STRIP);
zero_v3(vert);
vert[axis] = grid;
glVertex3fv(vert);
vert[axis] = -grid;
glVertex3fv(vert);
- glEnd();
}
}
+ glEnd();
}
glDepthMask(GL_TRUE);
@@ -568,6 +574,7 @@ static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d)
const float f10 = 0.5f * U.widget_unit;
const float f20 = U.widget_unit;
+ glLineWidth(1);
setlinestyle(0);
cpack(0xFF);
circ((float)co[0], (float)co[1], f10);
@@ -629,15 +636,12 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
if (fabsf(dx) > toll || fabsf(dy) > toll) {
BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1);
- }
- /* BLF_draw_default disables blending */
- glEnable(GL_BLEND);
+ /* BLF_draw_default disables blending */
+ glEnable(GL_BLEND);
+ }
}
- /* restore line-width */
-
- glLineWidth(1.0);
glDisable(GL_BLEND);
}
@@ -939,7 +943,9 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
/* color depends on whether there is a keyframe */
if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL))
- UI_ThemeColor(TH_VERTEX_SELECT);
+ UI_ThemeColor(TH_TIME_KEYFRAME);
+ else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra))
+ UI_ThemeColor(TH_TIME_GP_KEYFRAME);
else
UI_ThemeColor(TH_TEXT_HI);
}
@@ -1104,6 +1110,8 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
x2 = viewborder.xmax;
y2 = viewborder.ymax;
+ glLineWidth(1.0f);
+
/* apply offsets so the real 3D camera shows through */
/* note: quite un-scientific but without this bit extra
@@ -1129,6 +1137,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
glEnable(GL_BLEND);
glColor4f(0, 0, 0, ca->passepartalpha);
}
+
if (x1i > 0.0f)
glRectf(0.0, winy, x1i, 0.0);
if (x2i < winx)
@@ -1141,19 +1150,16 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
glDisable(GL_BLEND);
}
- /* edge */
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
setlinestyle(0);
UI_ThemeColor(TH_BACK);
- glRectf(x1i, y1i, x2i, y2i);
+ fdrawbox(x1i, y1i, x2i, y2i);
#ifdef VIEW3D_CAMERA_BORDER_HACK
if (view3d_camera_border_hack_test == true) {
glColor3ubv(view3d_camera_border_hack_col);
- glRectf(x1i + 1, y1i + 1, x2i - 1, y2i - 1);
+ fdrawbox(x1i + 1, y1i + 1, x2i - 1, y2i - 1);
view3d_camera_border_hack_test = false;
}
#endif
@@ -1163,11 +1169,11 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* outer line not to confuse with object selecton */
if (v3d->flag2 & V3D_LOCK_CAMERA) {
UI_ThemeColor(TH_REDALERT);
- glRectf(x1i - 1, y1i - 1, x2i + 1, y2i + 1);
+ fdrawbox(x1i - 1, y1i - 1, x2i + 1, y2i + 1);
}
UI_ThemeColor(TH_VIEW_OVERLAY);
- glRectf(x1i, y1i, x2i, y2i);
+ fdrawbox(x1i, y1i, x2i, y2i);
/* border */
if (scene->r.mode & R_BORDER) {
@@ -1179,7 +1185,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
y4 = y1i + 1 + roundf(scene->r.border.ymax * (y2 - y1));
cpack(0x4040FF);
- glRecti(x3, y3, x4, y4);
+ sdrawbox(x3, y3, x4, y4);
}
/* safety border */
@@ -1295,7 +1301,6 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
}
setlinestyle(0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
/* camera name - draw in highlighted text color */
if (ca && (ca->flag & CAM_SHOWNAME)) {
@@ -1308,7 +1313,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* *********************** backdraw for selection *************** */
-static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
+static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d)
{
RegionView3D *rv3d = ar->regiondata;
struct Base *base = scene->basact;
@@ -1359,11 +1364,11 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
/* dithering and AA break color coding, so disable */
glDisable(GL_DITHER);
- multisample_enabled = glIsEnabled(GL_MULTISAMPLE_ARB);
+ multisample_enabled = glIsEnabled(GL_MULTISAMPLE);
if (multisample_enabled)
- glDisable(GL_MULTISAMPLE_ARB);
+ glDisable(GL_MULTISAMPLE);
- if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
+ if (win->multisamples != USER_MULTISAMPLE_NONE) {
/* for multisample we use an offscreen FBO. multisample drawing can fail
* with color coded selection drawing, and reading back depths from such
* a buffer can also cause a few seconds freeze on OS X / NVidia. */
@@ -1381,7 +1386,7 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
}
if (!rv3d->gpuoffscreen) {
- rv3d->gpuoffscreen = GPU_offscreen_create(w, h, error);
+ rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error);
if (!rv3d->gpuoffscreen)
fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
@@ -1423,14 +1428,10 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
glDisable(GL_DEPTH_TEST);
glEnable(GL_DITHER);
if (multisample_enabled)
- glEnable(GL_MULTISAMPLE_ARB);
+ glEnable(GL_MULTISAMPLE);
if (rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
-
- /* it is important to end a view in a transform compatible with buttons */
-// persp(PERSP_WIN); /* set ortho */
-
}
void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
@@ -1458,7 +1459,7 @@ static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h,
void ED_view3d_backbuf_validate(ViewContext *vc)
{
if (vc->v3d->flag & V3D_INVALID_BACKBUF)
- backdrawview3d(vc->scene, vc->ar, vc->v3d);
+ backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d);
}
/**
@@ -1618,7 +1619,7 @@ exit:
static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser)
{
- if ((ima->flag & IMA_IS_STEREO)) {
+ if (BKE_image_is_stereo(ima)) {
iuser->flag |= IMA_SHOW_STEREO;
if ((scene->r.scemode & R_MULTIVIEW) == 0) {
@@ -1961,15 +1962,13 @@ void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag)
/* disables write in zbuffer and draws it over */
static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
{
- View3DAfter *v3da, *next;
+ View3DAfter *v3da;
glDepthMask(GL_FALSE);
v3d->transp = true;
- for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) {
- next = v3da->next;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
- BLI_remlink(&v3d->afterdraw_transp, v3da);
MEM_freeN(v3da);
}
v3d->transp = false;
@@ -1981,7 +1980,7 @@ static void view3d_draw_transp(Scene *scene, ARegion *ar, View3D *v3d)
/* clears zbuffer and draws it over */
static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear)
{
- View3DAfter *v3da, *next;
+ View3DAfter *v3da;
if (*clear && v3d->zbuf) {
glClear(GL_DEPTH_BUFFER_BIT);
@@ -1989,10 +1988,8 @@ static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear
}
v3d->xray = true;
- for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
- next = v3da->next;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
- BLI_remlink(&v3d->afterdraw_xray, v3da);
MEM_freeN(v3da);
}
v3d->xray = false;
@@ -2002,7 +1999,7 @@ static void view3d_draw_xray(Scene *scene, ARegion *ar, View3D *v3d, bool *clear
/* clears zbuffer and draws it over */
static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const bool clear)
{
- View3DAfter *v3da, *next;
+ View3DAfter *v3da;
if (clear && v3d->zbuf)
glClear(GL_DEPTH_BUFFER_BIT);
@@ -2012,10 +2009,8 @@ static void view3d_draw_xraytransp(Scene *scene, ARegion *ar, View3D *v3d, const
glDepthMask(GL_FALSE);
- for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) {
- next = v3da->next;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
draw_object(scene, ar, v3d, v3da->base, v3da->dflag);
- BLI_remlink(&v3d->afterdraw_xraytransp, v3da);
MEM_freeN(v3da);
}
@@ -2069,7 +2064,6 @@ static void draw_dupli_objects_color(
short transflag;
bool use_displist = false; /* -1 is initialize */
char dt;
- bool testbb = false;
short dtx;
DupliApplyData *apply_data;
@@ -2093,10 +2087,11 @@ static void draw_dupli_objects_color(
if (dob) dob_next = dupli_step(dob->next);
for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) {
+ bool testbb = false;
+
tbase.object = dob->ob;
/* Make sure lod is updated from dupli's position */
-
savedlod = dob->ob->currentlod;
#ifdef WITH_GAMEENGINE
@@ -2232,7 +2227,7 @@ void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
{
int x, y, w, h;
rcti r;
- /* clamp rect by area */
+ /* clamp rect by region */
r.xmin = 0;
r.xmax = ar->winx - 1;
@@ -2358,7 +2353,7 @@ void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
glEnable(GL_DEPTH_TEST);
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- ED_gpencil_draw_view3d(scene, v3d, ar, true);
+ ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true);
}
v3d->zbuf = zbuf;
@@ -2392,7 +2387,6 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
glClear(GL_DEPTH_BUFFER_BIT);
glLoadMatrixf(rv3d->viewmat);
-// persp(PERSP_STORE); /* store correct view for persp(PERSP_VIEW) calls */
if (rv3d->rflag & RV3D_CLIPPING) {
ED_view3d_clipping_set(rv3d);
@@ -2431,7 +2425,7 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
v3d->afterdraw_xray.first ||
v3d->afterdraw_xraytransp.first)
{
- View3DAfter *v3da, *next;
+ View3DAfter *v3da;
int mask_orig;
v3d->xray = true;
@@ -2442,8 +2436,7 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) {
glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */
- for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
- next = v3da->next;
+ for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) {
draw_object(scene, ar, v3d, v3da->base, dflag_depth);
}
glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */
@@ -2452,28 +2445,22 @@ void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaover
/* draw 3 passes, transp/xray/xraytransp */
v3d->xray = false;
v3d->transp = true;
- for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) {
- next = v3da->next;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) {
draw_object(scene, ar, v3d, v3da->base, dflag_depth);
- BLI_remlink(&v3d->afterdraw_transp, v3da);
MEM_freeN(v3da);
}
v3d->xray = true;
v3d->transp = false;
- for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
- next = v3da->next;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) {
draw_object(scene, ar, v3d, v3da->base, dflag_depth);
- BLI_remlink(&v3d->afterdraw_xray, v3da);
MEM_freeN(v3da);
}
v3d->xray = true;
v3d->transp = true;
- for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) {
- next = v3da->next;
+ while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) {
draw_object(scene, ar, v3d, v3da->base, dflag_depth);
- BLI_remlink(&v3d->afterdraw_xraytransp, v3da);
MEM_freeN(v3da);
}
@@ -2522,7 +2509,11 @@ static void gpu_render_lamp_update(Scene *scene, View3D *v3d,
if (srl)
layers &= srl->lay;
- if (layers && GPU_lamp_override_visible(lamp, srl, NULL) && GPU_lamp_has_shadow_buffer(lamp)) {
+ if (layers &&
+ GPU_lamp_has_shadow_buffer(lamp) &&
+ /* keep last, may do string lookup */
+ GPU_lamp_override_visible(lamp, srl, NULL))
+ {
shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow");
shadow->lamp = lamp;
BLI_addtail(shadows, shadow);
@@ -2656,6 +2647,9 @@ CustomDataMask ED_view3d_screen_datamask(const bScreen *screen)
return mask;
}
+/**
+ * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore
+ */
void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
{
RegionView3D *rv3d = ar->regiondata;
@@ -2717,7 +2711,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
}
/**
- * Shared by #ED_view3d_draw_offscreen and #view3d_main_area_draw_objects
+ * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects
*
* \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set.
* \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here.
@@ -2867,9 +2861,11 @@ static void view3d_draw_objects(
/* must be before xray draw which clears the depth buffer */
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
+ wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL;
+
/* must be before xray draw which clears the depth buffer */
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- ED_gpencil_draw_view3d(scene, v3d, ar, true);
+ ED_gpencil_draw_view3d(wm, scene, v3d, ar, true);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -2916,7 +2912,7 @@ static void view3d_draw_objects(
}
}
-static void view3d_main_area_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
+static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
{
RegionView3D *rv3d = ar->regiondata;
@@ -2929,6 +2925,47 @@ static void view3d_main_area_setup_view(Scene *scene, View3D *v3d, ARegion *ar,
glLoadMatrixf(rv3d->viewmat);
}
+/**
+ * Store values from #RegionView3D, set when drawing.
+ * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example).
+ *
+ * Values set by #ED_view3d_update_viewmat should be handled here.
+ */
+struct RV3DMatrixStore {
+ float winmat[4][4];
+ float viewmat[4][4];
+ float viewinv[4][4];
+ float persmat[4][4];
+ float persinv[4][4];
+ float viewcamtexcofac[4];
+ float pixsize;
+};
+
+void *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d)
+{
+ struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__);
+ copy_m4_m4(rv3dmat->winmat, rv3d->winmat);
+ copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat);
+ copy_m4_m4(rv3dmat->persmat, rv3d->persmat);
+ copy_m4_m4(rv3dmat->persinv, rv3d->persinv);
+ copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv);
+ copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac);
+ rv3dmat->pixsize = rv3d->pixsize;
+ return (void *)rv3dmat;
+}
+
+void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, void *rv3dmat_pt)
+{
+ struct RV3DMatrixStore *rv3dmat = rv3dmat_pt;
+ copy_m4_m4(rv3d->winmat, rv3dmat->winmat);
+ copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat);
+ copy_m4_m4(rv3d->persmat, rv3dmat->persmat);
+ copy_m4_m4(rv3d->persinv, rv3dmat->persinv);
+ copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv);
+ copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac);
+ rv3d->pixsize = rv3dmat->pixsize;
+}
+
void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
{
/* shadow buffers, before we setup matrices */
@@ -2939,20 +2976,18 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d)
/*
* Function to clear the view
*/
-static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
+static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar)
{
if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) {
- bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes;
-
+ bool glsl = GPU_glsl_support();
if (glsl) {
RegionView3D *rv3d = ar->regiondata;
GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
- bool material_not_bound;
/* calculate full shader for background */
GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
- material_not_bound = !GPU_material_bound(gpumat);
+ bool material_not_bound = !GPU_material_bound(gpumat);
if (material_not_bound) {
glMatrixMode(GL_PROJECTION);
@@ -2996,7 +3031,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
#define VIEWGRAD_RES_Y 16
GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4];
- static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
+ static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3];
static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4];
static bool buf_calculated = false;
@@ -3157,10 +3192,9 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar)
void ED_view3d_draw_offscreen(
Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy,
float viewmat[4][4], float winmat[4][4],
- bool do_bgpic, bool do_sky, bool is_persp,
- GPUOffScreen *ofs,
+ bool do_bgpic, bool do_sky, bool is_persp, const char *viewname,
GPUFX *fx, GPUFXSettings *fx_settings,
- const char *viewname)
+ GPUOffScreen *ofs)
{
struct bThemeState theme_state;
int bwinx, bwiny;
@@ -3198,7 +3232,7 @@ void ED_view3d_draw_offscreen(
if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera)
view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname);
else
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
/* framebuffer fx needed, we need to draw offscreen first */
if (v3d->fx_settings.fx_flag && fx) {
@@ -3217,7 +3251,7 @@ void ED_view3d_draw_offscreen(
/* clear opengl buffers */
if (do_sky) {
- view3d_main_area_clear(scene, v3d, ar);
+ view3d_main_region_clear(scene, v3d, ar);
}
else {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -3241,7 +3275,7 @@ void ED_view3d_draw_offscreen(
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- ED_gpencil_draw_view3d(scene, v3d, ar, false);
+ ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false);
}
/* freeing the images again here could be done after the operator runs, leaving for now */
@@ -3260,36 +3294,53 @@ void ED_view3d_draw_offscreen(
G.f &= ~G_RENDER_OGL;
}
-/* utility func for ED_view3d_draw_offscreen */
-ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
- bool draw_background, int alpha_mode, const char *viewname, char err_out[256])
+/**
+ * Utility func for ED_view3d_draw_offscreen
+ *
+ * \param ofs: Optional off-screen buffer, can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ */
+ImBuf *ED_view3d_draw_offscreen_imbuf(
+ Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey,
+ unsigned int flag, bool draw_background,
+ int alpha_mode, int samples, bool full_samples, const char *viewname,
+ /* output vars */
+ GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
{
RegionView3D *rv3d = ar->regiondata;
ImBuf *ibuf;
- GPUOffScreen *ofs;
- bool draw_sky = (alpha_mode == R_ADDSKY) && v3d && (v3d->flag3 & V3D_SHOW_WORLD);
+ const bool draw_sky = (alpha_mode == R_ADDSKY);
- if (UNLIKELY(v3d == NULL))
- return NULL;
+ /* view state */
+ GPUFXSettings fx_settings = v3d->fx_settings;
+ bool is_ortho = false;
+ float winmat[4][4];
+
+ if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) {
+ /* sizes differ, can't reuse */
+ ofs = NULL;
+ }
- /* state changes make normal drawing go weird otherwise */
- glPushAttrib(GL_LIGHTING_BIT);
+ const bool own_ofs = (ofs == NULL);
- /* bind */
- ofs = GPU_offscreen_create(sizex, sizey, err_out);
- if (ofs == NULL) {
- glPopAttrib();
- return NULL;
+ if (own_ofs) {
+ /* bind */
+ ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out);
+ if (ofs == NULL) {
+ return NULL;
+ }
}
ED_view3d_draw_offscreen_init(scene, v3d);
GPU_offscreen_bind(ofs, true);
+ /* read in pixels & stamp */
+ ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
+
/* render 3d view */
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
CameraParams params;
- GPUFXSettings fx_settings = {NULL};
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
BKE_camera_params_init(&params);
@@ -3303,42 +3354,125 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, in
BKE_camera_to_gpu_dof(camera, &fx_settings);
- ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, params.winmat,
- draw_background, draw_sky, !params.is_ortho,
- ofs, NULL, &fx_settings, viewname);
+ is_ortho = params.is_ortho;
+ copy_m4_m4(winmat, params.winmat);
}
else {
+ rctf viewplane;
+ float clipsta, clipend;
+
+ is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL);
+ if (is_ortho) {
+ orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
+ }
+ else {
+ perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
+ }
+ }
+
+ if ((samples && full_samples) == 0) {
+ /* Single-pass render, common case */
ED_view3d_draw_offscreen(
- scene, v3d, ar, sizex, sizey, NULL, NULL,
- draw_background, draw_sky, true,
- ofs, NULL, NULL, viewname);
+ scene, v3d, ar, sizex, sizey, NULL, winmat,
+ draw_background, draw_sky, !is_ortho, viewname,
+ fx, &fx_settings, ofs);
+
+ if (ibuf->rect_float) {
+ GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
+ }
+ else if (ibuf->rect) {
+ GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
+ }
}
+ else {
+ /* Multi-pass render, use accumulation buffer & jitter for 'full' oversampling.
+ * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */
+ static float jit_ofs[32][2];
+ float winmat_jitter[4][4];
+ /* use imbuf as temp storage, before writing into it from accumulation buffer */
+ unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float;
+ unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1");
+ unsigned int i;
+ int j;
+
+ BLI_jitter_init(jit_ofs, samples);
+
+ /* first sample buffer, also initializes 'rv3d->persmat' */
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, winmat,
+ draw_background, draw_sky, !is_ortho, viewname,
+ fx, &fx_settings, ofs);
+ GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
+
+ i = sizex * sizey * 4;
+ while (i--) {
+ accum_buffer[i] = rect_temp[i];
+ }
- /* read in pixels & stamp */
- ibuf = IMB_allocImBuf(sizex, sizey, 32, flag);
+ /* skip the first sample */
+ for (j = 1; j < samples; j++) {
+ copy_m4_m4(winmat_jitter, winmat);
+ window_translate_m4(
+ winmat_jitter, rv3d->persmat,
+ (jit_ofs[j][0] * 2.0f) / sizex,
+ (jit_ofs[j][1] * 2.0f) / sizey);
+
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, sizex, sizey, NULL, winmat_jitter,
+ draw_background, draw_sky, !is_ortho, viewname,
+ fx, &fx_settings, ofs);
+ GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp);
+
+ i = sizex * sizey * 4;
+ while (i--) {
+ accum_buffer[i] += rect_temp[i];
+ }
+ }
- if (ibuf->rect_float)
- GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float);
- else if (ibuf->rect)
- GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, ibuf->rect);
+ if (ibuf->rect_float) {
+ float *rect_float = ibuf->rect_float;
+ i = sizex * sizey * 4;
+ while (i--) {
+ rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f);
+ }
+ }
+ else {
+ unsigned char *rect_ub = (unsigned char *)ibuf->rect;
+ i = sizex * sizey * 4;
+ while (i--) {
+ rect_ub[i] = accum_buffer[i] / samples;
+ }
+ }
+
+ MEM_freeN(accum_buffer);
+ }
/* unbind */
GPU_offscreen_unbind(ofs, true);
- GPU_offscreen_free(ofs);
- glPopAttrib();
-
+ if (own_ofs) {
+ GPU_offscreen_free(ofs);
+ }
+
if (ibuf->rect_float && ibuf->rect)
IMB_rect_from_float(ibuf);
return ibuf;
}
-/* creates own 3d views, used by the sequencer */
-ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int width, int height, unsigned int flag, int drawtype,
- bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode,
- const char *viewname, char err_out[256])
+/**
+ * Creates own fake 3d views (wrapping #ED_view3d_draw_offscreen_imbuf)
+ *
+ * \param ofs: Optional off-screen buffer can be NULL.
+ * (avoids re-creating when doing multiple GL renders).
+ *
+ * \note used by the sequencer
+ */
+ImBuf *ED_view3d_draw_offscreen_imbuf_simple(
+ Scene *scene, Object *camera, int width, int height,
+ unsigned int flag, int drawtype, bool use_solid_tex, bool use_gpencil, bool draw_background,
+ int alpha_mode, int samples, bool full_samples, const char *viewname,
+ GPUFX *fx, GPUOffScreen *ofs, char err_out[256])
{
View3D v3d = {NULL};
ARegion ar = {NULL};
@@ -3359,6 +3493,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
if (use_solid_tex)
v3d.flag2 |= V3D_SOLID_TEX;
+
+ if (draw_background)
+ v3d.flag3 |= V3D_SHOW_WORLD;
rv3d.persp = RV3D_CAMOB;
@@ -3368,11 +3505,11 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
{
CameraParams params;
- Object *camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
+ Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname);
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camera);
- BKE_camera_multiview_params(&scene->r, &params, camera, viewname);
+ BKE_camera_params_from_object(&params, view_camera);
+ BKE_camera_multiview_params(&scene->r, &params, view_camera, viewname);
BKE_camera_params_compute_viewplane(&params, width, height, scene->r.xasp, scene->r.yasp);
BKE_camera_params_compute_matrix(&params);
@@ -3385,10 +3522,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat);
invert_m4_m4(rv3d.persinv, rv3d.viewinv);
- return ED_view3d_draw_offscreen_imbuf(scene, &v3d, &ar, width, height, flag,
- draw_background, alpha_mode, viewname, err_out);
-
- // seq_view3d_cb(scene, cfra, render_size, seqrectx, seqrecty);
+ return ED_view3d_draw_offscreen_imbuf(
+ scene, &v3d, &ar, width, height, flag,
+ draw_background, alpha_mode, samples, full_samples, viewname,
+ fx, ofs, err_out);
}
@@ -3448,7 +3585,7 @@ void ED_scene_draw_fps(Scene *scene, const rcti *rect)
#endif
}
-static bool view3d_main_area_do_render_draw(Scene *scene)
+static bool view3d_main_region_do_render_draw(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
@@ -3462,7 +3599,7 @@ bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *
bool use_border;
/* test if there is a 3d view rendering */
- if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene))
+ if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene))
return false;
/* test if there is a border render */
@@ -3496,7 +3633,7 @@ bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti *
return true;
}
-static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene,
+static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene,
ARegion *ar, View3D *v3d,
bool clip_border, const rcti *border_rect)
{
@@ -3524,7 +3661,7 @@ static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene,
}
/* setup view matrices */
- view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL);
/* background draw */
ED_region_pixelspace(ar);
@@ -3564,7 +3701,7 @@ static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene,
return true;
}
-static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border)
+static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border)
{
float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
@@ -3573,7 +3710,7 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A
if (render_border) {
/* draw darkened background color. no alpha because border render does
- * partial redraw and will not redraw the area behind this info bar */
+ * partial redraw and will not redraw the region behind this info bar */
float alpha = 1.0f - fill_color[3];
Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
@@ -3620,7 +3757,7 @@ static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d,
* we have no winmatrix (i.e., projection matrix) defined at that time.
* Since the camera and the camera shift are needed for the winmat calculation
* we do a small hack to replace it temporarily so we don't need to change the
- * view3d)main_area_setup_view() code to account for that.
+ * view3d)main_region_setup_view() code to account for that.
*/
static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
{
@@ -3648,7 +3785,7 @@ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname);
BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL);
data->shiftx = shiftx;
BLI_unlock_thread(LOCK_VIEW3D);
@@ -3662,7 +3799,7 @@ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar)
v3d->camera = camera;
BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL);
v3d->camera = view_ob;
BLI_unlock_thread(LOCK_VIEW3D);
@@ -3678,14 +3815,14 @@ static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *
const bool is_left = STREQ(viewname, STEREO_LEFT_NAME);
BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat);
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
}
else { /* SCE_VIEWS_FORMAT_MULTIVIEW */
float viewmat[4][4];
Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname);
BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat);
- view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat);
+ view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat);
}
}
@@ -3703,9 +3840,10 @@ static void update_lods(Scene *scene, float camera_pos[3])
}
#endif
-static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3D *v3d,
+static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d,
ARegion *ar, const char **grid_unit)
{
+ wmWindow *win = CTX_wm_window(C);
RegionView3D *rv3d = ar->regiondata;
unsigned int lay_used = v3d->lay_used;
@@ -3726,7 +3864,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
if (view3d_stereo3d_active(C, scene, v3d, rv3d))
view3d_stereo3d_setup(scene, v3d, ar);
else
- view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL);
+ view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL);
rv3d->rflag &= ~RV3D_IS_GAME_ENGINE;
#ifdef WITH_GAMEENGINE
@@ -3756,11 +3894,11 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
}
/* clear the background */
- view3d_main_area_clear(scene, v3d, ar);
+ view3d_main_region_clear(scene, v3d, ar);
/* enables anti-aliasing for 3D view drawing */
- if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
- glEnable(GL_MULTISAMPLE_ARB);
+ if (win->multisamples != USER_MULTISAMPLE_NONE) {
+ glEnable(GL_MULTISAMPLE);
}
/* main drawing call */
@@ -3772,8 +3910,8 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3
}
/* Disable back anti-aliasing */
- if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
- glDisable(GL_MULTISAMPLE_ARB);
+ if (win->multisamples != USER_MULTISAMPLE_NONE) {
+ glDisable(GL_MULTISAMPLE);
}
if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */
@@ -3823,10 +3961,11 @@ static bool is_cursor_visible(Scene *scene)
return true;
}
-static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
+static void view3d_main_region_draw_info(const bContext *C, Scene *scene,
ARegion *ar, View3D *v3d,
const char *grid_unit, bool render_border)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
RegionView3D *rv3d = ar->regiondata;
rcti rect;
@@ -3837,20 +3976,18 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
drawviewborder(scene, ar, v3d);
}
else if (v3d->flag2 & V3D_RENDER_BORDER) {
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
setlinestyle(3);
cpack(0x4040FF);
- glRecti(v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy,
- v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy);
+ sdrawbox(v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy,
+ v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy);
setlinestyle(0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- ED_gpencil_draw_view3d(scene, v3d, ar, false);
+ ED_gpencil_draw_view3d(wm, scene, v3d, ar, false);
}
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
@@ -3872,13 +4009,11 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
}
if (rv3d->render_engine) {
- view3d_main_area_draw_engine_info(v3d, rv3d, ar, render_border);
+ view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border);
return;
}
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
- wmWindowManager *wm = CTX_wm_manager(C);
-
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
ED_scene_draw_fps(scene, &rect);
}
@@ -3901,7 +4036,7 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
}
}
-void view3d_main_area_draw(const bContext *C, ARegion *ar)
+void view3d_main_region_draw(const bContext *C, ARegion *ar)
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -3915,8 +4050,8 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect));
/* draw viewport using opengl */
- if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) {
- view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit);
+ if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) {
+ view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit);
#ifdef DEBUG_DRAW
bl_debug_draw();
@@ -3929,9 +4064,9 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
/* draw viewport using external renderer */
if (v3d->drawtype == OB_RENDER)
- view3d_main_area_draw_engine(C, scene, ar, v3d, clip_border, &border_rect);
+ view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect);
- view3d_main_area_draw_info(C, scene, ar, v3d, grid_unit, render_border);
+ view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border);
v3d->flag |= V3D_INVALID_BACKBUF;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 2295986faf0..7cd20401a53 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -41,6 +41,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -391,14 +392,14 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_src->view, viewinv) == false)) {
return;
}
- invert_qt(viewinv);
+ invert_qt_normalized(viewinv);
mul_qt_v3(viewinv, view_src_x);
mul_qt_v3(viewinv, view_src_y);
if (UNLIKELY(ED_view3d_quat_from_axis_view(rv3d_dst->view, viewinv) == false)) {
return;
}
- invert_qt(viewinv);
+ invert_qt_normalized(viewinv);
mul_qt_v3(viewinv, view_dst_x);
mul_qt_v3(viewinv, view_dst_y);
@@ -558,7 +559,7 @@ typedef struct ViewOpsData {
} ViewOpsData;
-#define TRACKBALLSIZE (1.1)
+#define TRACKBALLSIZE (1.1f)
static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3])
{
@@ -609,18 +610,18 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
vod->rv3d = vod->ar->regiondata;
}
-static void view3d_orbit_apply_dyn_ofs(
- float r_ofs[3], const float dyn_ofs[3],
- const float oldquat[4], const float viewquat[4])
+void view3d_orbit_apply_dyn_ofs(
+ float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
+ const float viewquat_new[4], const float dyn_ofs[3])
{
- float q1[4];
- conjugate_qt_qt(q1, oldquat);
- mul_qt_qtqt(q1, q1, viewquat);
+ float q[4];
+ invert_qt_qt_normalized(q, viewquat_old);
+ mul_qt_qtqt(q, q, viewquat_new);
- conjugate_qt(q1); /* conj == inv for unit quat */
+ invert_qt_normalized(q);
- sub_v3_v3(r_ofs, dyn_ofs);
- mul_qt_v3(q1, r_ofs);
+ sub_v3_v3v3(r_ofs, ofs_old, dyn_ofs);
+ mul_qt_v3(q, r_ofs);
add_v3_v3(r_ofs, dyn_ofs);
}
@@ -630,28 +631,28 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
bool is_set = false;
Scene *scene = CTX_data_scene(C);
- Object *ob = OBACT;
+ Object *ob_act = OBACT;
- if (ob && (ob->mode & OB_MODE_ALL_PAINT) &&
+ if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) &&
/* with weight-paint + pose-mode, fall through to using calculateTransformCenter */
- ((ob->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob)) == 0)
+ ((ob_act->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(ob_act)) == 0)
{
/* in case of sculpting use last average stroke position as a rotation
* center, in other cases it's not clear what rotation center shall be
* so just rotate around object origin
*/
- if (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT)) {
+ if (ob_act->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
float stroke[3];
- BKE_paint_stroke_get_average(scene, ob, stroke);
+ BKE_paint_stroke_get_average(scene, ob_act, stroke);
copy_v3_v3(lastofs, stroke);
}
else {
- copy_v3_v3(lastofs, ob->obmat[3]);
+ copy_v3_v3(lastofs, ob_act->obmat[3]);
}
is_set = true;
}
- else if (ob && (ob->mode & OB_MODE_EDIT) && (ob->type == OB_FONT)) {
- Curve *cu = ob->data;
+ else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
+ Curve *cu = ob_act->data;
EditFont *ef = cu->editfont;
int i;
@@ -661,11 +662,11 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
}
mul_v2_fl(lastofs, 1.0f / 4.0f);
- mul_m4_v3(ob->obmat, lastofs);
+ mul_m4_v3(ob_act->obmat, lastofs);
is_set = true;
}
- else if (ob == NULL || ob->mode == OB_MODE_OBJECT) {
+ else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) {
/* object mode use boundbox centers */
View3D *v3d = CTX_wm_view3d(C);
Base *base;
@@ -700,7 +701,7 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
}
else {
/* If there's no selection, lastofs is unmodified and last value since static */
- is_set = calculateTransformCenter(C, V3D_CENTROID, lastofs, NULL);
+ is_set = calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, lastofs, NULL);
}
copy_v3_v3(r_dyn_ofs, lastofs);
@@ -910,12 +911,11 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
}
-static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat[4])
+static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
{
if (vod->use_dyn_ofs) {
RegionView3D *rv3d = vod->rv3d;
- copy_v3_v3(rv3d->ofs, vod->ofs);
- view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->dyn_ofs, vod->oldquat, viewquat);
+ view3d_orbit_apply_dyn_ofs(rv3d->ofs, vod->ofs, vod->oldquat, viewquat_new, vod->dyn_ofs);
}
}
@@ -931,7 +931,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
int x, y, z;
bool found = false;
- invert_qt_qt(viewquat_inv, vod->viewquat);
+ invert_qt_qt_normalized(viewquat_inv, vod->viewquat);
mul_qt_v3(viewquat_inv, zaxis);
normalize_v3(zaxis);
@@ -969,11 +969,11 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
normalize_qt(viewquat_align);
mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align);
normalize_qt(viewquat_align);
- invert_qt_qt(viewquat_align_inv, viewquat_align);
+ invert_qt_qt_normalized(viewquat_align_inv, viewquat_align);
vec_to_quat(quat_snap, zaxis_best, OB_NEGZ, OB_POSY);
- invert_qt(quat_snap);
normalize_qt(quat_snap);
+ invert_qt_normalized(quat_snap);
/* check if we can find the roll */
found = false;
@@ -992,7 +992,7 @@ static void viewrotate_apply_snap(ViewOpsData *vod)
normalize_qt(quat_final);
/* compare 2 vector angles to find the least roll */
- invert_qt_qt(quat_final_inv, quat_final);
+ invert_qt_qt_normalized(quat_final_inv, quat_final);
mul_qt_v3(viewquat_align_inv, xaxis1);
mul_qt_v3(quat_final_inv, xaxis2);
angle = angle_v3v3(xaxis1, xaxis2);
@@ -1028,31 +1028,25 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
rv3d->view = RV3D_VIEW_USER; /* need to reset every time because of view snapping */
if (U.flag & USER_TRACKBALL) {
- float phi, si, q1[4], dvec[3], newvec[3];
+ float axis[3], q1[4], dvec[3], newvec[3];
+ float angle;
calctrackballvec(&vod->ar->winrct, x, y, newvec);
sub_v3_v3v3(dvec, newvec, vod->trackvec);
- si = len_v3(dvec);
- si /= (float)(2.0 * TRACKBALLSIZE);
-
- cross_v3_v3v3(q1 + 1, vod->trackvec, newvec);
- normalize_v3(q1 + 1);
+ angle = (len_v3(dvec) / (2.0f * TRACKBALLSIZE)) * (float)M_PI;
/* Allow for rotation beyond the interval [-pi, pi] */
- while (si > 1.0f)
- si -= 2.0f;
-
- /* This relation is used instead of
- * - phi = asin(si) so that the angle
- * - of rotation is linearly proportional
- * - to the distance that the mouse is
- * - dragged. */
- phi = si * (float)M_PI_2;
-
- q1[0] = cosf(phi);
- mul_v3_fl(q1 + 1, sinf(phi));
+ angle = angle_wrap_rad(angle);
+
+ /* This relation is used instead of the actual angle between vectors
+ * so that the angle of rotation is linearly proportional to
+ * the distance that the mouse is dragged. */
+
+ cross_v3_v3v3(axis, vod->trackvec, newvec);
+ axis_angle_to_quat(q1, axis, angle);
+
mul_qt_qtqt(vod->viewquat, q1, vod->oldquat);
viewrotate_apply_dyn_ofs(vod, vod->viewquat);
@@ -1103,7 +1097,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
mul_qt_qtqt(quat_local_x, vod->viewquat, quat_local_x);
/* Perform the orbital rotation */
- axis_angle_normalized_to_quat(quat_global_z, zvec_global, sensitivity * vod->reverse * (x - vod->oldx));
+ axis_angle_to_quat_single(quat_global_z, 'Z', sensitivity * vod->reverse * (x - vod->oldx));
mul_qt_qtqt(vod->viewquat, quat_local_x, quat_global_z);
viewrotate_apply_dyn_ofs(vod, vod->viewquat);
@@ -1227,7 +1221,6 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* makes op->customdata */
viewops_data_alloc(C, op);
- viewops_data_create(C, op, event);
vod = op->customdata;
/* poll should check but in some cases fails, see poll func for details */
@@ -1245,6 +1238,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_region_tag_redraw(vod->ar);
}
+ viewops_data_create(C, op, event);
+
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
/* Rotate direction we keep always same */
int x, y;
@@ -1362,7 +1357,7 @@ static float view3d_ndof_pan_speed_calc_from_dist(RegionView3D *rv3d, const floa
#if 0
mul_mat3_m4_v3(rv3d->viewinv, tvec);
#else
- invert_qt_qt(viewinv, rv3d->viewquat);
+ invert_qt_qt_normalized(viewinv, rv3d->viewquat);
mul_qt_v3(viewinv, tvec);
#endif
@@ -1431,7 +1426,7 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof, ScrArea *s
mul_v3_fl(pan_vec, speed * ndof->dt);
/* transform motion from view to world coordinates */
- invert_qt_qt(view_inv, rv3d->viewquat);
+ invert_qt_qt_normalized(view_inv, rv3d->viewquat);
mul_qt_v3(view_inv, pan_vec);
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
@@ -1459,7 +1454,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa,
rv3d->view = RV3D_VIEW_USER;
- invert_qt_qt(view_inv, rv3d->viewquat);
+ invert_qt_qt_normalized(view_inv, rv3d->viewquat);
if (U.ndof_flag & NDOF_TURNTABLE) {
float rot[3];
@@ -1476,8 +1471,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa,
/* Perform the up/down rotation */
angle = ndof->dt * rot[0];
- quat[0] = cosf(angle);
- mul_v3_v3fl(quat + 1, xvec, sinf(angle));
+ axis_angle_to_quat(quat, xvec, angle);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
/* Perform the orbital rotation */
@@ -1489,10 +1483,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa,
rv3d->rot_axis[1] = 0;
rv3d->rot_axis[2] = 1;
- quat[0] = cosf(angle);
- quat[1] = 0.0f;
- quat[2] = 0.0f;
- quat[3] = sinf(angle);
+ axis_angle_to_quat_single(quat, 'Z', angle);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
}
@@ -1532,7 +1523,7 @@ void view3d_ndof_fly(
bool has_rotate = NDOF_HAS_ROTATE;
float view_inv[4];
- invert_qt_qt(view_inv, rv3d->viewquat);
+ invert_qt_qt_normalized(view_inv, rv3d->viewquat);
rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */
@@ -1605,7 +1596,7 @@ void view3d_ndof_fly(
float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */
/* find new inverse since viewquat has changed */
- invert_qt_qt(view_inv, rv3d->viewquat);
+ invert_qt_qt_normalized(view_inv, rv3d->viewquat);
/* could apply reverse rotation to existing view_inv to save a few cycles */
/* transform view vectors to world coordinates */
@@ -2890,14 +2881,16 @@ static void view3d_from_minmax(bContext *C, View3D *v3d, ARegion *ar,
if (rv3d->persp == RV3D_CAMOB && !ED_view3d_camera_lock_check(v3d, rv3d)) {
rv3d->persp = RV3D_PERSP;
- ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL,
- new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera_old = v3d->camera, .ofs = new_ofs,
+ .dist = ok_dist ? &new_dist : NULL});
}
else {
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = ok_dist ? &new_dist : NULL});
}
/* smooth view does viewlock RV3D_BOXVIEW copy */
@@ -3086,8 +3079,6 @@ static int viewselected_exec(bContext *C, wmOperator *op)
view3d_from_minmax(C, v3d, ar, min, max, ok_dist, smooth_viewtx);
}
-// XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
-
return OPERATOR_FINISHED;
}
@@ -3208,10 +3199,10 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
/* non camera center */
float new_ofs[3];
negate_v3_v3(new_ofs, ED_view3d_cursor3d_get(scene, v3d));
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- new_ofs, NULL, NULL, NULL,
- smooth_viewtx);
-
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.ofs = new_ofs});
+
/* smooth view does viewlock RV3D_BOXVIEW copy */
}
@@ -3255,9 +3246,9 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs);
}
negate_v3(new_ofs);
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- new_ofs, NULL, NULL, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.ofs = new_ofs});
}
return OPERATOR_FINISHED;
@@ -3640,9 +3631,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* clamp after because we may have been zooming out */
CLAMP(new_dist, dist_range[0], dist_range[1]);
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- new_ofs, NULL, &new_dist, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist});
if (rv3d->viewlock & RV3D_BOXVIEW)
view3d_boxview_sync(CTX_wm_area(C), ar);
@@ -3769,10 +3760,10 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
float twmat[3][3];
/* same as transform manipulator when normal is set */
- ED_getTransformOrientationMatrix(C, twmat, V3D_ACTIVE);
+ ED_getTransformOrientationMatrix(C, twmat, V3D_AROUND_ACTIVE);
mat3_to_quat(obact_quat, twmat);
- invert_qt(obact_quat);
+ invert_qt_normalized(obact_quat);
mul_qt_qtqt(quat, quat, obact_quat);
rv3d->view = view = RV3D_VIEW_USER;
@@ -3797,9 +3788,9 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
/* to camera */
- ED_view3d_smooth_view(C, v3d, ar, v3d->camera, NULL,
- rv3d->ofs, quat, NULL, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.camera_old = v3d->camera, .ofs = rv3d->ofs, .quat = quat});
}
else if (orig_persp == RV3D_CAMOB && v3d->camera) {
/* from camera */
@@ -3811,15 +3802,26 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
/* so we animate _from_ the camera location */
ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, &rv3d->dist, NULL);
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- ofs, quat, &dist, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.ofs = ofs, .quat = quat, .dist = &dist});
}
else {
+ /* rotate around selection */
+ const float *dyn_ofs_pt = NULL;
+ float dyn_ofs[3];
+
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ if (view3d_orbit_calc_center(C, dyn_ofs)) {
+ negate_v3(dyn_ofs);
+ dyn_ofs_pt = dyn_ofs;
+ }
+ }
+
/* no camera involved */
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- NULL, quat, NULL, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.quat = quat, .dyn_ofs = dyn_ofs_pt});
}
}
@@ -3908,9 +3910,11 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
/* finally do snazzy view zooming */
rv3d->persp = RV3D_CAMOB;
- ED_view3d_smooth_view(C, v3d, ar, NULL, v3d->camera,
- rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat,
+ .dist = &rv3d->dist, .lens = &v3d->lens});
}
else {
@@ -3991,22 +3995,18 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
float quat_mul[4];
float quat_new[4];
- float ofs_new[3];
- float *ofs_new_pt = NULL;
if (view_opposite == RV3D_VIEW_USER) {
view3d_ensure_persp(v3d, ar);
}
if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) {
- const float zvec[3] = {0.0f, 0.0f, 1.0f};
-
if (orbitdir == V3D_VIEW_STEPRIGHT) {
angle = -angle;
}
/* z-axis */
- axis_angle_normalized_to_quat(quat_mul, zvec, angle);
+ axis_angle_to_quat_single(quat_mul, 'Z', angle);
}
else {
@@ -4029,25 +4029,19 @@ static int vieworbit_exec(bContext *C, wmOperator *op)
rv3d->view = RV3D_VIEW_USER;
}
- if (U.uiflag & USER_ORBIT_SELECTION) {
- float dyn_ofs[3];
- view3d_orbit_calc_center(C, dyn_ofs);
- negate_v3(dyn_ofs);
+ float dyn_ofs[3], *dyn_ofs_pt = NULL;
- copy_v3_v3(ofs_new, rv3d->ofs);
-
- view3d_orbit_apply_dyn_ofs(ofs_new, dyn_ofs, rv3d->viewquat, quat_new);
- ofs_new_pt = ofs_new;
-
- /* disable smoothview in this case
- * although it works OK, it looks a little odd. */
- smooth_viewtx = 0;
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ if (view3d_orbit_calc_center(C, dyn_ofs)) {
+ negate_v3(dyn_ofs);
+ dyn_ofs_pt = dyn_ofs;
+ }
}
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- ofs_new_pt, quat_new, NULL, NULL,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.quat = quat_new, .dyn_ofs = dyn_ofs_pt});
return OPERATOR_FINISHED;
}
@@ -4111,6 +4105,10 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
if (angle != 0.0f)
view_roll_angle(vod->ar, vod->rv3d->viewquat, vod->oldquat, vod->mousevec, angle);
+ if (vod->use_dyn_ofs) {
+ view3d_orbit_apply_dyn_ofs(vod->rv3d->ofs, vod->ofs, vod->oldquat, vod->rv3d->viewquat, vod->dyn_ofs);
+ }
+
if (vod->rv3d->viewlock & RV3D_BOXVIEW)
view3d_boxview_sync(vod->sa, vod->ar);
@@ -4173,9 +4171,9 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
static EnumPropertyItem prop_view_roll_items[] = {
- {0, "ROLLANGLE", 0, "Roll Angle", "Roll the view using an angle value"},
- {V3D_VIEW_STEPLEFT, "ROLLLEFT", 0, "Roll Left", "Roll the view around to the Left"},
- {V3D_VIEW_STEPRIGHT, "ROLLTRIGHT", 0, "Roll Right", "Roll the view around to the Right"},
+ {0, "ANGLE", 0, "Roll Angle", "Roll the view using an angle value"},
+ {V3D_VIEW_STEPLEFT, "LEFT", 0, "Roll Left", "Roll the view around to the Left"},
+ {V3D_VIEW_STEPRIGHT, "RIGHT", 0, "Roll Right", "Roll the view around to the Right"},
{0, NULL, 0, NULL, NULL}
};
@@ -4212,9 +4210,18 @@ static int viewroll_exec(bContext *C, wmOperator *op)
negate_v3(mousevec);
view_roll_angle(ar, quat_new, rv3d->viewquat, mousevec, angle);
- ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
- NULL, quat_new, NULL, NULL,
- smooth_viewtx);
+ const float *dyn_ofs_pt = NULL;
+ float dyn_ofs[3];
+ if (U.uiflag & USER_ORBIT_SELECTION) {
+ if (view3d_orbit_calc_center(C, dyn_ofs)) {
+ negate_v3(dyn_ofs);
+ dyn_ofs_pt = dyn_ofs;
+ }
+ }
+
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {.quat = quat_new, .dyn_ofs = dyn_ofs_pt});
viewops_data_free(C, op);
return OPERATOR_FINISHED;
@@ -4478,8 +4485,9 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
/* properties */
RNA_def_string(ot->srna, "name", "Image", MAX_ID_NAME - 2, "Name", "Image name to assign");
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
}
@@ -4842,9 +4850,11 @@ bool ED_view3d_autodist(
bool depth_ok = false;
/* Get Z Depths, needed for perspective, nice for ortho */
- bgl_get_mats(&mats);
ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
+ /* call after in case settings have been modified since last drawing, see: T47089 */
+ bgl_get_mats(&mats);
+
/* Attempt with low margin's first */
i = 0;
do {
@@ -5011,7 +5021,7 @@ void ED_view3d_distance_set(RegionView3D *rv3d, const float dist)
#if 0
mul_mat3_m4_v3(rv3d->viewinv, tvec);
#else
- invert_qt_qt(viewinv, rv3d->viewquat);
+ invert_qt_qt_normalized(viewinv, rv3d->viewquat);
mul_qt_v3(viewinv, tvec);
#endif
sub_v3_v3(rv3d->ofs, tvec);
@@ -5043,16 +5053,12 @@ void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist
/* Quat */
if (quat) {
- float imat[3][3];
- invert_m3_m3(imat, nmat);
- mat3_to_quat(quat, imat);
+ mat3_normalized_to_quat(quat, nmat);
+ invert_qt_normalized(quat);
}
if (ofs && dist) {
- float vec[3] = {0.0f, 0.0f, -(*dist)};
-
- mul_m3_v3(nmat, vec);
- sub_v3_v3(ofs, vec);
+ madd_v3_v3fl(ofs, nmat[2], *dist);
}
}
@@ -5165,3 +5171,85 @@ void ED_view3D_lock_clear(View3D *v3d)
v3d->ob_centre_cursor = false;
v3d->flag2 &= ~V3D_LOCK_CAMERA;
}
+
+/**
+ * Convenience function for snap ray-casting.
+ *
+ * Given a ray, cast it into the scene (snapping to faces).
+ *
+ * \return Snap success
+ */
+bool ED_view3d_snap_from_ray(
+ Scene *scene,
+ const float ray_start[3], const float ray_normal[3],
+ float r_co[3])
+{
+ float r_no_dummy[3];
+ float ray_dist = BVH_RAYCAST_DIST_MAX;
+ bool ret;
+
+ struct Object *obedit = scene->obedit;
+
+ /* try snap edge, then face if it fails */
+ ret = snapObjectsRayEx(
+ scene, NULL, NULL, NULL, obedit,
+ NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
+ ray_start, ray_normal, &ray_dist,
+ r_co, r_no_dummy, NULL, NULL,
+ NULL, NULL);
+
+ return ret;
+}
+
+/**
+ * Convenience function for performing snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face.
+ *
+ * \param mval: Screenspace coordinate.
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param use_depth: Snap to the closest element, use when using more than one snap type.
+ * \param use_obedit: Use editmode cage.
+ * \param use_vert: Snap to verts.
+ * \param use_edge: Snap to edges.
+ * \param use_face: Snap to faces.
+ * \param r_co: hit location.
+ * \param r_no: hit normal (optional).
+ * \return Snap success
+ */
+bool ED_view3d_snap_from_region(
+ Scene *scene, View3D *v3d, ARegion *ar,
+ const float mval[2], float dist_px,
+ bool use_depth, bool use_obedit,
+ bool use_vert, bool use_edge, bool use_face,
+ float r_co[3], float r_no[3])
+{
+ float r_no_dummy[3];
+ float ray_dist = BVH_RAYCAST_DIST_MAX;
+ bool is_hit = false;
+ float *r_no_ptr = r_no ? r_no : r_no_dummy;
+
+ struct Object *obedit = use_obedit ? scene->obedit : NULL;
+ const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
+ const bool elem_test[3] = {use_vert, use_edge, use_face};
+
+ BLI_assert(use_vert || use_edge || use_face);
+
+ for (int i = 0; i < 3; i++) {
+ if (elem_test[i] && (is_hit == false || use_depth)) {
+ if (use_depth == false) {
+ ray_dist = BVH_RAYCAST_DIST_MAX;
+ }
+ if (snapObjectsEx(
+ scene, v3d, ar, NULL, obedit,
+ mval, SNAP_ALL, elem_type[i],
+ &ray_dist,
+ r_co, r_no_ptr, &dist_px))
+ {
+ is_hit = true;
+ }
+ }
+ }
+
+ return is_hit;
+}
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index e6910cf9303..8418cf0980c 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -720,8 +720,6 @@ static int flyApply(bContext *C, FlyInfo *fly)
float dvec[3] = {0, 0, 0}; /* this is the direction thast added to the view offset per redraw */
/* Camera Uprighting variables */
- float upvec[3] = {0, 0, 0}; /* stores the view's up vector */
-
float moffset[2]; /* mouse offset from the views center */
float tmp_quat[4]; /* used for rotating the view */
@@ -815,6 +813,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
/* rotate about the X axis- look up/down */
if (moffset[1]) {
+ float upvec[3];
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
/* Rotate about the relative up vec */
@@ -830,7 +829,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
/* rotate about the Y axis- look left/right */
if (moffset[0]) {
-
+ float upvec[3];
/* if we're upside down invert the moffset */
copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f);
mul_m3_v3(mat, upvec);
@@ -858,6 +857,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
}
if (fly->zlock == FLY_AXISLOCK_STATE_ACTIVE) {
+ float upvec[3];
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
@@ -882,6 +882,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
/* only apply xcorrect when mouse isn't applying x rot */
if (fly->xlock == FLY_AXISLOCK_STATE_ACTIVE && moffset[1] == 0) {
+ float upvec[3];
copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
mul_m3_v3(mat, upvec);
/* make sure we have some z rolling */
@@ -1064,7 +1065,7 @@ void VIEW3D_OT_fly(wmOperatorType *ot)
ot->invoke = fly_invoke;
ot->cancel = fly_cancel;
ot->modal = fly_modal;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = ED_operator_region_view3d_active;
/* flags */
ot->flag = OPTYPE_BLOCKING;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 42895a7530b..0713377d210 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -34,6 +34,7 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_utildefines.h"
@@ -287,6 +288,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
PointerRNA v3dptr, toolsptr, sceneptr;
Object *ob = OBACT;
Object *obedit = CTX_data_edit_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
uiBlock *block;
uiLayout *row;
bool is_paint = false;
@@ -303,7 +305,10 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
UI_block_emboss_set(block, UI_EMBOSS);
/* mode */
- if (ob) {
+ if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ modeselect = OB_MODE_GPENCIL;
+ }
+ else if (ob) {
modeselect = ob->mode;
is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
}
@@ -313,7 +318,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
row = uiLayoutRow(layout, false);
{
- EnumPropertyItem *item = object_mode_items;
+ EnumPropertyItem *item = rna_enum_object_mode_items;
const char *name = "";
int icon = ICON_OBJECT_DATAMODE;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 95c0ef92680..c398356e941 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -106,6 +106,10 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
+void view3d_orbit_apply_dyn_ofs(
+ float r_ofs[3], const float ofs_old[3], const float viewquat_old[4],
+ const float viewquat_new[4], const float dyn_ofs[3]);
+
void view3d_ndof_fly(
const struct wmNDOFMotionData *ndof,
struct View3D *v3d, struct RegionView3D *rv3d,
@@ -136,7 +140,7 @@ void draw_object(Scene *scene, struct ARegion *ar, View3D *v3d, Base *base, cons
bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt);
void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline);
void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob);
-void drawaxes(float size, char drawtype);
+void drawaxes(const float viewmat_local[4][4], float size, char drawtype);
void view3d_cached_text_draw_begin(void);
void view3d_cached_text_draw_add(const float co[3],
@@ -180,7 +184,7 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar);
/* view3d_draw.c */
-void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar);
+void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d);
void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);
@@ -208,19 +212,22 @@ void VIEW3D_OT_game_start(struct wmOperatorType *ot);
bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]);
bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb);
+typedef struct V3D_SmoothParams {
+ struct Object *camera_old, *camera;
+ const float *ofs, *quat, *dist, *lens;
+ /* alternate rotation center (ofs = must be NULL) */
+ const float *dyn_ofs;
+} V3D_SmoothParams;
+
void ED_view3d_smooth_view_ex(
struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa,
- struct View3D *v3d, struct ARegion *ar,
- struct Object *camera_old, struct Object *camera,
- const float *ofs, const float *quat, const float *dist, const float *lens,
- const int smooth_viewtx);
+ struct View3D *v3d, struct ARegion *ar, const int smooth_viewtx,
+ const V3D_SmoothParams *sview);
void ED_view3d_smooth_view(
struct bContext *C,
- struct View3D *v3d, struct ARegion *ar,
- struct Object *camera_old, struct Object *camera,
- const float *ofs, const float *quat, const float *dist, const float *lens,
- const int smooth_viewtx);
+ struct View3D *v3d, struct ARegion *ar, const int smooth_viewtx,
+ const V3D_SmoothParams *sview);
void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect);
void view3d_viewmatrix_set(Scene *scene, const View3D *v3d, RegionView3D *rv3d);
@@ -273,9 +280,8 @@ extern const char *view3d_context_dir[]; /* doc access */
/* draw_volume.c */
void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob,
- struct GPUTexture *tex, const float min[3], const float max[3],
- const int res[3], float dx, float base_scale, const float viewnormal[3],
- struct GPUTexture *tex_shadow, struct GPUTexture *tex_flame);
+ const float min[3], const float max[3],
+ const float viewnormal[3]);
//#define SMOKE_DEBUG_VELOCITY
//#define SMOKE_DEBUG_HEAT
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 8c668b2b8e0..a5411da131b 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -34,6 +34,7 @@
#include "DNA_object_types.h"
+#include "DNA_group_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -49,6 +50,7 @@
#include "BKE_report.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -77,9 +79,20 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
BKE_copybuffer_tag_ID(&ob->id);
}
CTX_DATA_END;
+
+ for (Group *group = bmain->group.first; group; group = group->id.next) {
+ for (GroupObject *go = group->gobject.first; go; go = go->next) {
+ if (go->ob && (go->ob->id.tag & LIB_TAG_DOIT)) {
+ BKE_copybuffer_tag_ID(&group->id);
+ /* don't expand out to all other objects */
+ group->id.tag &= ~LIB_TAG_NEED_EXPAND;
+ break;
+ }
+ }
+ }
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
- BKE_copybuffer_save(str, op->reports);
+ BKE_copybuffer_save(bmain, str, op->reports);
BKE_report(op->reports, RPT_INFO, "Copied selected objects to buffer");
@@ -102,9 +115,15 @@ static void VIEW3D_OT_copybuffer(wmOperatorType *ot)
static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
+ short flag = 0;
+
+ if (RNA_boolean_get(op->ptr, "autoselect"))
+ flag |= FILE_AUTOSELECT;
+ if (RNA_boolean_get(op->ptr, "active_layer"))
+ flag |= FILE_ACTIVELAY;
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
- if (BKE_copybuffer_paste(C, str, op->reports)) {
+ if (BKE_copybuffer_paste(C, str, flag, op->reports)) {
WM_event_add_notifier(C, NC_WINDOW, NULL);
BKE_report(op->reports, RPT_INFO, "Objects pasted from buffer");
@@ -131,6 +150,9 @@ static void VIEW3D_OT_pastebuffer(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select pasted objects");
+ RNA_def_boolean(ot->srna, "active_layer", true, "Active Layer", "Put pasted objects on the active layer");
}
/* ************************** registration **********************************/
@@ -347,9 +369,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "use_all_regions", false);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", -M_PI_2);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI_2);
-
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index ba0626c58ea..cbabc8e56de 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -348,7 +348,10 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa
BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], float ray_end[3])
{
- if ((rv3d->rflag & RV3D_CLIPPING) && !clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6)) {
+ if ((rv3d->rflag & RV3D_CLIPPING) &&
+ (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
+ ray_start, ray_end) == false))
+ {
return false;
}
return true;
@@ -478,19 +481,22 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
{
RegionView3D *rv3d = ar->regiondata;
- float line_sta[3];
- float line_end[3];
+ float ray_origin[3];
+ float ray_direction[3];
+ float lambda;
if (rv3d->is_persp) {
- float mousevec[3], lambda;
- copy_v3_v3(line_sta, rv3d->viewinv[3]);
- ED_view3d_win_to_vector(ar, mval, mousevec);
- add_v3_v3v3(line_end, line_sta, mousevec);
+ float plane[4];
+
+ copy_v3_v3(ray_origin, rv3d->viewinv[3]);
+ ED_view3d_win_to_vector(ar, mval, ray_direction);
/* note, we could use isect_line_plane_v3() however we want the intersection to be infront of the
* view no matter what, so apply the unsigned factor instead */
- lambda = line_plane_factor_v3(depth_pt, rv3d->viewinv[2], line_sta, line_end);
- interp_v3_v3v3(out, line_sta, line_end, fabsf(lambda));
+ plane_from_point_normal_v3(plane, depth_pt, rv3d->viewinv[2]);
+
+ isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, false);
+ lambda = fabsf(lambda);
}
else {
float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
@@ -501,13 +507,15 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float
dx += rv3d->camdx * zoomfac;
dy += rv3d->camdy * zoomfac;
}
- line_sta[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
- line_sta[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
- line_sta[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
+ ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
+ ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
+ ray_origin[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
- add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
- closest_to_line_v3(out, depth_pt, line_sta, line_end);
+ copy_v3_v3(ray_direction, rv3d->viewinv[2]);
+ lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction);
}
+
+ madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda);
}
void ED_view3d_win_to_3d_int(const ARegion *ar, const float depth_pt[3], const int mval[2], float out[3])
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 98b1e846c70..198cc3e5703 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -45,6 +45,7 @@
#include "WM_types.h"
#include "ED_screen.h"
+#include "ED_view3d.h"
#include "ED_space_api.h"
#include "BLF_api.h"
@@ -55,85 +56,8 @@
#include "view3d_intern.h" /* own include */
-
-/* -------------------------------------------------------------------- */
-/* Snapping (could be own function) */
-/* NOTE - this is not very nice use of transform snapping */
-#include "ED_transform.h"
-
#define MVAL_MAX_PX_DIST 12.0f
-/**
- * Convenience function for performing snapping.
- *
- * \param C Context.
- * \param r_co hit location.
- * \param r_no hit normal (optional).
- * \param co_ss Screenspace coordinate.
- * \param use_depth Snap to the closest element, use when using more than one snap type.
- * \param use_obedit Use editmode cage.
- * \param use_vert Snap to verts.
- * \param use_edge Snap to edges.
- * \param use_face Snap to faces.
- * \return Snap success
- */
-static bool ED_view3d_snap_co(bContext *C, float r_co[3], float r_no[3], const float co_ss[2],
- bool use_depth, bool use_obedit,
- bool use_vert, bool use_edge, bool use_face)
-{
- float dist_px = MVAL_MAX_PX_DIST; /* snap dist */
- float r_no_dummy[3];
- float ray_dist = TRANSFORM_DIST_MAX_RAY;
- bool ret = false;
- float *r_no_ptr = r_no ? r_no : r_no_dummy;
-
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
- struct Object *obedit = use_obedit ? CTX_data_edit_object(C) : NULL;
-
- BLI_assert(use_vert || use_edge || use_face);
-
- /* try snap edge, then face if it fails */
- if (use_vert) {
- ret |= snapObjectsEx(scene, NULL, v3d, ar, obedit, SCE_SNAP_MODE_VERTEX,
- co_ss, &dist_px, r_co, r_no_ptr, &ray_dist, SNAP_ALL);
- }
- if (use_edge && (ret == false || use_depth)) {
- if (use_depth == false) ray_dist = TRANSFORM_DIST_MAX_RAY;
- ret |= snapObjectsEx(scene, NULL, v3d, ar, obedit, SCE_SNAP_MODE_EDGE,
- co_ss, &dist_px, r_co, r_no_ptr, &ray_dist, SNAP_ALL);
- }
- if (use_face && (ret == false || use_depth)) {
- if (use_depth == false) ray_dist = TRANSFORM_DIST_MAX_RAY;
- ret |= snapObjectsEx(scene, NULL, v3d, ar, obedit, SCE_SNAP_MODE_FACE,
- co_ss, &dist_px, r_co, r_no_ptr, &ray_dist, SNAP_ALL);
- }
-
- return ret;
-}
-
-static bool ED_view3d_snap_ray(bContext *C, float r_co[3],
- const float ray_start[3], const float ray_normal[3])
-{
- float dist_px = MVAL_MAX_PX_DIST; /* snap dist */
- float r_no_dummy[3];
- float ray_dist = TRANSFORM_DIST_MAX_RAY;
- bool ret;
-
- Scene *scene = CTX_data_scene(C);
- struct Object *obedit = CTX_data_edit_object(C);
-
- /* try snap edge, then face if it fails */
- ret = snapObjectsRayEx(scene, NULL, NULL, NULL, obedit, SCE_SNAP_MODE_FACE,
- NULL, NULL,
- ray_start, ray_normal, &ray_dist,
- NULL, &dist_px, r_co, r_no_dummy, SNAP_ALL);
-
- return ret;
-}
-/* done snapping */
-
/* -------------------------------------------------------------------- */
/* Ruler Item (we can have many) */
@@ -722,6 +646,7 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons
const bool do_thickness, const bool do_snap)
{
const float eps_bias = 0.0002f;
+ const float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
RulerItem *ruler_item = ruler_item_active_get(ruler_info);
ruler_info->snap_flag &= ~RULER_SNAP_OK;
@@ -732,6 +657,8 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons
copy_v3_v3(co, ruler_info->drag_start_co);
view3d_ruler_item_project(ruler_info, co, mval);
if (do_thickness && ruler_item->co_index != 1) {
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = ruler_info->sa->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
float ray_normal[3];
float ray_start[3];
@@ -739,24 +666,35 @@ static bool view3d_ruler_item_mousemove(bContext *C, RulerInfo *ruler_info, cons
co_other = ruler_item->co[ruler_item->co_index == 0 ? 2 : 0];
- if (ED_view3d_snap_co(C, co, ray_normal, mval_fl, true, false,
- false, false, true))
+ if (ED_view3d_snap_from_region(
+ scene, v3d, ruler_info->ar,
+ mval_fl, dist_px,
+ true, false,
+ false, false, true,
+ co, ray_normal))
{
negate_v3(ray_normal);
/* add some bias */
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
- ED_view3d_snap_ray(C, co_other,
- ray_start, ray_normal);
+ ED_view3d_snap_from_ray(
+ scene,
+ ray_start, ray_normal,
+ co_other);
}
}
else if (do_snap) {
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = ruler_info->sa->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
- View3D *v3d = CTX_wm_view3d(C);
bool use_depth = (v3d->drawtype >= OB_SOLID);
- bool is_hit = ED_view3d_snap_co(C, co, NULL, mval_fl, use_depth, false,
- true, true, use_depth);
- if (is_hit) {
+ if (ED_view3d_snap_from_region(
+ scene, v3d, ruler_info->ar,
+ mval_fl, dist_px,
+ use_depth, false,
+ true, true, use_depth,
+ co, NULL))
+ {
ruler_info->snap_flag |= RULER_SNAP_OK;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 5a35e9fcad1..18cb9fb728d 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -108,6 +108,7 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc)
vc->ar = CTX_wm_region(C);
vc->scene = CTX_data_scene(C);
vc->v3d = CTX_wm_view3d(C);
+ vc->win = CTX_wm_window(C);
vc->rv3d = CTX_wm_region_view3d(C);
vc->obact = CTX_data_active_object(C);
vc->obedit = CTX_data_edit_object(C);
@@ -601,7 +602,7 @@ static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], shor
view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
if (extend == false && select)
- ED_setflagsLatt(vc->obedit, 0);
+ ED_lattice_flags_set(vc->obedit, 0);
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -784,7 +785,7 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh
EDBM_backbuf_free();
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT);
}
#if 0
@@ -1193,7 +1194,10 @@ static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, c
/* we want a select buffer with bones, if there are... */
/* so check three selection levels and compare */
-static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate)
+static short mixed_bones_object_selectbuffer(
+ ViewContext *vc, unsigned int *buffer, const int mval[2],
+ bool use_cycle, bool enumerate,
+ bool *r_do_nearest)
{
rcti rect;
int offs;
@@ -1204,16 +1208,24 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
View3D *v3d = vc->v3d;
/* define if we use solid nearest select or not */
- if (v3d->drawtype > OB_WIRE) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
- do_nearest = false;
+ if (use_cycle) {
+ if (v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+ }
+ else {
+ if (v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
}
}
- copy_v2_v2_int(last_mval, mval);
- if (p_do_nearest)
- *p_do_nearest = do_nearest;
+ if (r_do_nearest) {
+ *r_do_nearest = do_nearest;
+ }
do_nearest = do_nearest && !enumerate;
@@ -1353,7 +1365,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
view3d_set_viewcontext(C, &vc);
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1383,8 +1395,9 @@ static void deselect_all_tracks(MovieTracking *tracking)
}
/* mval is region coords */
-static bool mouse_select(bContext *C, const int mval[2],
- bool extend, bool deselect, bool toggle, bool obcenter, bool enumerate, bool object)
+static bool ed_object_select_pick(
+ bContext *C, const int mval[2],
+ bool extend, bool deselect, bool toggle, bool obcenter, bool enumerate, bool object)
{
ViewContext vc;
ARegion *ar = CTX_wm_region(C);
@@ -1448,7 +1461,7 @@ static bool mouse_select(bContext *C, const int mval[2],
/* if objects have posemode set, the bones are in the same selection buffer */
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest);
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
@@ -1784,7 +1797,7 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool
view3d_userdata_boxselect_init(&data, vc, rect, select);
if (extend == false && select)
- ED_setflagsLatt(vc->obedit, 0);
+ ED_lattice_flags_set(vc->obedit, 0);
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
@@ -2191,7 +2204,9 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
/* mouse selection in weight paint */
/* gets called via generic mouse select operator */
-static bool mouse_weight_paint_vertex_select(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
+static bool ed_wpaint_vertex_select_pick(
+ bContext *C, const int mval[2],
+ bool extend, bool deselect, bool toggle, Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0;
@@ -2272,15 +2287,15 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
if (obedit->type == OB_MESH)
retval = EDBM_select_pick(C, location, extend, deselect, toggle);
else if (obedit->type == OB_ARMATURE)
- retval = mouse_armature(C, location, extend, deselect, toggle);
+ retval = ED_armature_select_pick(C, location, extend, deselect, toggle);
else if (obedit->type == OB_LATTICE)
- retval = mouse_lattice(C, location, extend, deselect, toggle);
+ retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
else if (ELEM(obedit->type, OB_CURVE, OB_SURF))
- retval = mouse_nurb(C, location, extend, deselect, toggle);
+ retval = ED_curve_editnurb_select_pick(C, location, extend, deselect, toggle);
else if (obedit->type == OB_MBALL)
- retval = mouse_mball(C, location, extend, deselect, toggle);
+ retval = ED_mball_select_pick(C, location, extend, deselect, toggle);
else if (obedit->type == OB_FONT)
- retval = mouse_font(C, location, extend, deselect, toggle);
+ retval = ED_curve_editfont_select_pick(C, location, extend, deselect, toggle);
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT)
@@ -2288,9 +2303,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
else if (obact && BKE_paint_select_face_test(obact))
retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle);
else if (BKE_paint_select_vert_test(obact))
- retval = mouse_weight_paint_vertex_select(C, location, extend, deselect, toggle, obact);
+ retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact);
else
- retval = mouse_select(C, location, extend, deselect, toggle, center, enumerate, object);
+ retval = ed_object_select_pick(C, location, extend, deselect, toggle, center, enumerate, object);
/* passthrough allows tweaks
* FINISHED to signal one operator worked
@@ -2448,7 +2463,7 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons
if (bbsel) {
edbm_backbuf_check_and_select_tfaces(me, select);
EDBM_backbuf_free();
- paintface_flush_flags(ob);
+ paintface_flush_flags(ob, SELECT);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index 8bb84d00c83..e8e7d3c62fb 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -223,7 +223,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
cursor_global = ED_view3d_cursor3d_get(scene, v3d);
if (use_offset) {
- if ((v3d && v3d->around == V3D_ACTIVE) &&
+ if ((v3d && v3d->around == V3D_AROUND_ACTIVE) &&
snap_calc_active_center(C, true, center_global))
{
/* pass */
@@ -543,7 +543,7 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
minmax_v3v3_v3(min, max, vec);
}
- if (v3d->around == V3D_CENTROID) {
+ if (v3d->around == V3D_AROUND_CENTER_MEAN) {
mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot);
copy_v3_v3(cursor, centroid);
}
@@ -595,7 +595,7 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
return false;
}
- if (v3d->around == V3D_CENTROID) {
+ if (v3d->around == V3D_AROUND_CENTER_MEAN) {
mul_v3_fl(centroid, 1.0f / (float)count);
copy_v3_v3(cursor, centroid);
}
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index 065c336d001..62f605ab99c 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -185,7 +185,7 @@ static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase)
uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, 19, 0, 0, "");
- UI_but_func_search_set(but, operator_search_cb, arg_listbase, operator_call_cb, NULL);
+ UI_but_func_search_set(but, NULL, operator_search_cb, arg_listbase, operator_call_cb, NULL);
UI_block_bounds_set_normal(block, 6);
UI_block_direction_set(block, UI_DIR_DOWN);
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 0f05f4e52dd..305b4a3785e 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -138,6 +138,9 @@ struct SmoothView3DStore {
bool to_camera;
+ bool use_dyn_ofs;
+ float dyn_ofs[3];
+
/* When smooth-view is enabled, store the 'rv3d->view' here,
* assign back when the view motion is completed. */
char org_view;
@@ -168,10 +171,8 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms
void ED_view3d_smooth_view_ex(
/* avoid passing in the context */
wmWindowManager *wm, wmWindow *win, ScrArea *sa,
-
- View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera,
- const float *ofs, const float *quat, const float *dist, const float *lens,
- const int smooth_viewtx)
+ View3D *v3d, ARegion *ar, const int smooth_viewtx,
+ const V3D_SmoothParams *sview)
{
RegionView3D *rv3d = ar->regiondata;
struct SmoothView3DStore sms = {{0}};
@@ -199,19 +200,34 @@ void ED_view3d_smooth_view_ex(
* camera to be moved or changed, so only when the camera is not being set should
* we allow camera option locking to initialize the view settings from the camera.
*/
- if (camera == NULL && oldcamera == NULL) {
+ if (sview->camera == NULL && sview->camera_old == NULL) {
ED_view3d_camera_lock_init(v3d, rv3d);
}
/* store the options we want to end with */
- if (ofs) copy_v3_v3(sms.dst.ofs, ofs);
- if (quat) copy_qt_qt(sms.dst.quat, quat);
- if (dist) sms.dst.dist = *dist;
- if (lens) sms.dst.lens = *lens;
-
- if (camera) {
- sms.dst.dist = ED_view3d_offset_distance(camera->obmat, ofs, VIEW3D_DIST_FALLBACK);
- ED_view3d_from_object(camera, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens);
+ if (sview->ofs)
+ copy_v3_v3(sms.dst.ofs, sview->ofs);
+ if (sview->quat)
+ copy_qt_qt(sms.dst.quat, sview->quat);
+ if (sview->dist)
+ sms.dst.dist = *sview->dist;
+ if (sview->lens)
+ sms.dst.lens = *sview->lens;
+
+ if (sview->dyn_ofs) {
+ BLI_assert(sview->ofs == NULL);
+ BLI_assert(sview->quat != NULL);
+
+ copy_v3_v3(sms.dyn_ofs, sview->dyn_ofs);
+ sms.use_dyn_ofs = true;
+
+ /* calcualte the final destination offset */
+ view3d_orbit_apply_dyn_ofs(sms.dst.ofs, sms.src.ofs, sms.src.quat, sms.dst.quat, sms.dyn_ofs);
+ }
+
+ if (sview->camera) {
+ sms.dst.dist = ED_view3d_offset_distance(sview->camera->obmat, sview->ofs, VIEW3D_DIST_FALLBACK);
+ ED_view3d_from_object(sview->camera, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens);
sms.to_camera = true; /* restore view3d values in end */
}
@@ -219,7 +235,7 @@ void ED_view3d_smooth_view_ex(
if (smooth_viewtx && v3d->drawtype != OB_RENDER) {
bool changed = false; /* zero means no difference */
- if (oldcamera != camera)
+ if (sview->camera_old != sview->camera)
changed = true;
else if (sms.dst.dist != rv3d->dist)
changed = true;
@@ -234,10 +250,10 @@ void ED_view3d_smooth_view_ex(
* so animate the view */
if (changed) {
/* original values */
- if (oldcamera) {
- sms.src.dist = ED_view3d_offset_distance(oldcamera->obmat, rv3d->ofs, 0.0f);
+ if (sview->camera_old) {
+ sms.src.dist = ED_view3d_offset_distance(sview->camera_old->obmat, rv3d->ofs, 0.0f);
/* this */
- ED_view3d_from_object(oldcamera, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
+ ED_view3d_from_object(sview->camera_old, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
}
/* grid draw as floor */
if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
@@ -251,26 +267,17 @@ void ED_view3d_smooth_view_ex(
* we can decrease the time allowed by
* the angle between quats
* this means small rotations wont lag */
- if (quat && !ofs && !dist) {
- float vec1[3] = {0, 0, 1}, vec2[3] = {0, 0, 1};
- float q1[4], q2[4];
-
- invert_qt_qt(q1, sms.dst.quat);
- invert_qt_qt(q2, sms.src.quat);
-
- mul_qt_v3(q1, vec1);
- mul_qt_v3(q2, vec2);
-
+ if (sview->quat && !sview->ofs && !sview->dist) {
/* scale the time allowed by the rotation */
- sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
+ sms.time_allowed *= (double)angle_normalized_qtqt(sms.dst.quat, sms.src.quat) / M_PI; /* 180deg == 1.0 */
}
/* ensure it shows correct */
if (sms.to_camera) {
/* use ortho if we move from an ortho view to an ortho camera */
rv3d->persp = (((rv3d->is_persp == false) &&
- (camera->type == OB_CAMERA) &&
- (((Camera *)camera->data)->type == CAM_ORTHO)) ?
+ (sview->camera->type == OB_CAMERA) &&
+ (((Camera *)sview->camera->data)->type == CAM_ORTHO)) ?
RV3D_ORTHO : RV3D_PERSP);
}
@@ -316,9 +323,8 @@ void ED_view3d_smooth_view_ex(
void ED_view3d_smooth_view(
bContext *C,
- View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera,
- const float *ofs, const float *quat, const float *dist, const float *lens,
- const int smooth_viewtx)
+ View3D *v3d, ARegion *ar, const int smooth_viewtx,
+ const struct V3D_SmoothParams *sview)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -326,8 +332,8 @@ void ED_view3d_smooth_view(
ED_view3d_smooth_view_ex(
wm, win, sa,
- v3d, ar, oldcamera, camera,
- ofs, quat, dist, lens, smooth_viewtx);
+ v3d, ar, smooth_viewtx,
+ sview);
}
/* only meant for timer usage */
@@ -379,8 +385,14 @@ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
step_inv = 1.0f - step;
- interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step);
interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step);
+
+ if (sms->use_dyn_ofs) {
+ view3d_orbit_apply_dyn_ofs(rv3d->ofs, sms->src.ofs, sms->src.quat, rv3d->viewquat, sms->dyn_ofs);
+ }
+ else {
+ interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step);
+ }
rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv;
v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv;
@@ -576,9 +588,12 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
if (camera_old != ob) {
ED_view3d_lastview_store(rv3d);
- ED_view3d_smooth_view(C, v3d, ar, camera_old, v3d->camera,
- rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens,
- smooth_viewtx);
+ ED_view3d_smooth_view(
+ C, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera_old = camera_old, .camera = v3d->camera,
+ .ofs = rv3d->ofs, .quat = rv3d->viewquat,
+ .dist = &rv3d->dist, .lens = &v3d->lens});
}
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS | NC_OBJECT | ND_DRAW, CTX_data_scene(C));
@@ -764,7 +779,6 @@ bool ED_view3d_clip_range_get(
return params.is_ortho;
}
-/* also exposed in previewrender.c */
bool ED_view3d_viewplane_get(
const View3D *v3d, const RegionView3D *rv3d, int winx, int winy,
rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize)
@@ -850,17 +864,14 @@ void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rctf *rect)
static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
{
float bmat[4][4];
- float tmat[3][3];
-
+
rv3d->view = RV3D_VIEW_USER; /* don't show the grid */
-
- copy_m4_m4(bmat, ob->obmat);
- normalize_m4(bmat);
+
+ normalize_m4_m4(bmat, ob->obmat);
invert_m4_m4(rv3d->viewmat, bmat);
-
+
/* view quat calculation, needed for add object */
- copy_m3_m4(tmat, rv3d->viewmat);
- mat3_to_quat(rv3d->viewquat, tmat);
+ mat4_normalized_to_quat(rv3d->viewquat, rv3d->viewmat);
}
static float view3d_quat_axis[6][4] = {
@@ -1136,7 +1147,6 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
v3d->zbuf = 0;
glDisable(GL_DEPTH_TEST);
}
-// XXX persp(PERSP_WIN);
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_disable();
@@ -1313,10 +1323,11 @@ static bool view3d_localview_init(
}
ED_view3d_smooth_view_ex(
- wm, win, sa,
- v3d, ar, camera_old, NULL,
- ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL,
- smooth_viewtx);
+ wm, win, sa, v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera_old = camera_old,
+ .ofs = ofs_new, .quat = rv3d->viewquat,
+ .dist = ok_dist ? &dist_new : NULL, .lens = &v3d->lens});
}
}
@@ -1377,9 +1388,11 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
ED_view3d_smooth_view_ex(
wm, win, sa,
- v3d, ar, camera_old_rv3d, camera_new_rv3d,
- rv3d->localvd->ofs, rv3d->localvd->viewquat, &rv3d->localvd->dist, NULL,
- smooth_viewtx);
+ v3d, ar, smooth_viewtx,
+ &(const V3D_SmoothParams) {
+ .camera_old = camera_old_rv3d, .camera = camera_new_rv3d,
+ .ofs = rv3d->localvd->ofs, .quat = rv3d->localvd->viewquat,
+ .dist = &rv3d->localvd->dist});
if (free) {
MEM_freeN(rv3d->localvd);
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 0bda6e37fd1..7e1202aef77 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -33,6 +33,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -403,7 +404,6 @@ static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk
*/
static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance)
{
- float dummy_dist_px = 0;
float ray_normal[3] = {0, 0, -1}; /* down */
float ray_start[3];
float r_location[3];
@@ -411,17 +411,19 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w
float dvec_tmp[3];
bool ret;
- *r_distance = TRANSFORM_DIST_MAX_RAY;
+ *r_distance = BVH_RAYCAST_DIST_MAX;
copy_v3_v3(ray_start, rv3d->viewinv[3]);
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(ray_start, dvec_tmp);
- ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE,
- NULL, NULL,
- ray_start, ray_normal, r_distance,
- NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL);
+ ret = snapObjectsRayEx(
+ CTX_data_scene(C), NULL, NULL, NULL, NULL,
+ NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
+ ray_start, ray_normal, r_distance,
+ r_location, r_normal, NULL, NULL,
+ NULL, NULL);
/* artifically scale the distance to the scene size */
*r_distance /= walk->grid;
@@ -435,13 +437,12 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w
*/
static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *ray_distance)
{
- float dummy_dist_px = 0;
float ray_normal[3] = {0, 0, 1}; /* forward */
float ray_start[3];
float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */
bool ret;
- *ray_distance = TRANSFORM_DIST_MAX_RAY;
+ *ray_distance = BVH_RAYCAST_DIST_MAX;
copy_v3_v3(ray_start, rv3d->viewinv[3]);
copy_m3_m4(mat, rv3d->viewinv);
@@ -451,10 +452,12 @@ static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float
mul_v3_fl(ray_normal, -1);
normalize_v3(ray_normal);
- ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE,
- NULL, NULL,
- ray_start, ray_normal, ray_distance,
- NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL);
+ ret = snapObjectsRayEx(
+ CTX_data_scene(C), NULL, NULL, NULL, NULL,
+ NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
+ ray_start, ray_normal, ray_distance,
+ r_location, r_normal, NULL, NULL,
+ NULL, NULL);
/* dot is positive if both rays are facing the same direction */
@@ -972,9 +975,6 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */
float dvec[3] = {0.0f, 0.0f, 0.0f}; /* this is the direction that's added to the view offset per redraw */
- /* Camera Uprighting variables */
- float upvec[3] = {0.0f, 0.0f, 0.0f}; /* stores the view's up vector */
-
int moffset[2]; /* mouse offset from the views center */
float tmp_quat[4]; /* used for rotating the view */
@@ -1033,6 +1033,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
{
/* rotate about the X axis- look up/down */
if (moffset[1]) {
+ float upvec[3];
float angle;
float y;
@@ -1064,6 +1065,7 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
/* rotate about the Y axis- look left/right */
if (moffset[0]) {
+ float upvec[3];
float x;
/* if we're upside down invert the moffset */
@@ -1082,10 +1084,8 @@ static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk)
/* user adjustement factor */
x *= walk->mouse_speed;
- copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f);
-
/* Rotate about the relative up vec */
- axis_angle_normalized_to_quat(tmp_quat, upvec, x);
+ axis_angle_to_quat_single(tmp_quat, 'Z', x);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
}
}
@@ -1421,7 +1421,7 @@ void VIEW3D_OT_walk(wmOperatorType *ot)
ot->invoke = walk_invoke;
ot->cancel = walk_cancel;
ot->modal = walk_modal;
- ot->poll = ED_operator_view3d_active;
+ ot->poll = ED_operator_region_view3d_active;
/* flags */
ot->flag = OPTYPE_BLOCKING;
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 42aa6a0a3a3..f3047c088a9 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../depsgraph
../../../../intern/guardedalloc
../../../../intern/glew-mx
)
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
deleted file mode 100644
index 0f34ce546de..00000000000
--- a/source/blender/editors/transform/SConscript
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../ikplugin',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_LEGACY_DEPSGRAPH']:
- defs.append('WITH_LEGACY_DEPSGRAPH')
-
-env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 2b295b85da0..29c152c2f6e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -168,11 +168,12 @@ static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
static void initBoneRoll(TransInfo *t);
static void applyBoneRoll(TransInfo *t, const int mval[2]);
-static void initEdgeSlide_ex(TransInfo *t, bool use_double_side);
+static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
static void initEdgeSlide(TransInfo *t);
static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
static void applyEdgeSlide(TransInfo *t, const int mval[2]);
+static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
static void initVertSlide(TransInfo *t);
static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event);
static void applyVertSlide(TransInfo *t, const int mval[2]);
@@ -202,7 +203,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2]);
static bool transdata_check_local_center(TransInfo *t, short around)
{
- return ((around == V3D_LOCAL) && (
+ return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
(t->flag & (T_OBJECT | T_POSE)) ||
(t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
(t->spacetype == SPACE_IPO) ||
@@ -212,7 +213,7 @@ static bool transdata_check_local_center(TransInfo *t, short around)
bool transdata_check_local_islands(TransInfo *t, short around)
{
- return ((around == V3D_LOCAL) && (
+ return ((around == V3D_AROUND_LOCAL_ORIGINS) && (
(t->obedit && ELEM(t->obedit->type, OB_MESH))));
}
@@ -274,10 +275,8 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
{
- float divx, divy;
-
- divx = BLI_rcti_size_x(&v2d->mask);
- divy = BLI_rcti_size_y(&v2d->mask);
+ float divx = BLI_rcti_size_x(&v2d->mask);
+ float divy = BLI_rcti_size_y(&v2d->mask);
r_vec[0] = BLI_rctf_size_x(&v2d->cur) * dx / divx;
r_vec[1] = BLI_rctf_size_y(&v2d->cur) * dy / divy;
@@ -286,14 +285,11 @@ static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
{
- float divx, divy;
- float mulx, muly;
-
- divx = BLI_rcti_size_x(&v2d->mask);
- divy = BLI_rcti_size_y(&v2d->mask);
+ float divx = BLI_rcti_size_x(&v2d->mask);
+ float divy = BLI_rcti_size_y(&v2d->mask);
- mulx = BLI_rctf_size_x(&v2d->cur);
- muly = BLI_rctf_size_y(&v2d->cur);
+ float mulx = BLI_rctf_size_x(&v2d->cur);
+ float muly = BLI_rctf_size_y(&v2d->cur);
/* difference with convertViewVec2D */
/* clamp w/h, mask only */
@@ -312,7 +308,7 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
r_vec[2] = 0.0f;
}
-void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
+void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
{
if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
if (t->options & CTX_PAINT_CURVE) {
@@ -1037,6 +1033,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
/* vert slide can fail on unconnected vertices (rare but possible) */
if (t->state == TRANS_CANCEL) {
+ t->mode = TFM_TRANSLATION;
t->state = TRANS_STARTING;
restoreTransObjects(t);
resetTransRestrictions(t);
@@ -1551,8 +1548,8 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
initTransInfo(C, t, NULL, NULL);
- /* avoid doing connectivity lookups (when V3D_LOCAL is set) */
- t->around = V3D_CENTER;
+ /* avoid doing connectivity lookups (when V3D_AROUND_LOCAL_ORIGINS is set) */
+ t->around = V3D_AROUND_CENTER_BOUNDS;
createTransData(C, t); // make TransData structs from selection
@@ -1714,39 +1711,37 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
UI_ThemeColor(TH_VIEW_OVERLAY);
setlinestyle(3);
- glBegin(GL_LINE_STRIP);
+ glLineWidth(1);
+ glBegin(GL_LINES);
glVertex2iv(t->mval);
glVertex2fv(cent);
glEnd();
- glTranslate2fv((const float *)mval);
+ glTranslate2iv(mval);
glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1);
setlinestyle(0);
glLineWidth(3.0);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
- glLineWidth(1.0);
break;
case HLP_HARROW:
UI_ThemeColor(TH_VIEW_OVERLAY);
- glTranslate2fv((const float *)mval);
+ glTranslate2iv(mval);
glLineWidth(3.0);
drawArrow(RIGHT, 5, 10, 5);
drawArrow(LEFT, 5, 10, 5);
- glLineWidth(1.0);
break;
case HLP_VARROW:
UI_ThemeColor(TH_VIEW_OVERLAY);
- glTranslate2fv((const float *)mval);
+ glTranslate2iv(mval);
glLineWidth(3.0);
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
- glLineWidth(1.0);
break;
case HLP_ANGLE:
{
@@ -1758,7 +1753,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
UI_ThemeColor(TH_VIEW_OVERLAY);
setlinestyle(3);
- glBegin(GL_LINE_STRIP);
+ glLineWidth(1);
+ glBegin(GL_LINES);
glVertex2iv(t->mval);
glVertex2fv(cent);
glEnd();
@@ -1783,8 +1779,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1);
drawArrowHead(UP, 5);
-
- glLineWidth(1.0);
break;
}
case HLP_TRACKBALL:
@@ -1792,7 +1786,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
unsigned char col[3], col2[3];
UI_GetThemeColor3ubv(TH_GRID, col);
- glTranslate2fv((const float *)mval);
+ glTranslate2iv(mval);
glLineWidth(3.0);
@@ -1807,7 +1801,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
drawArrow(UP, 5, 10, 5);
drawArrow(DOWN, 5, 10, 5);
- glLineWidth(1.0);
break;
}
}
@@ -1819,6 +1812,8 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
{
TransInfo *t = arg;
+
+ glLineWidth(1.0);
drawConstraint(t);
drawPropCircle(C, t);
@@ -1888,6 +1883,9 @@ static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, vo
}
}
+/**
+ * \see #initTransform which reads values from the operator.
+ */
void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
{
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1901,7 +1899,10 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
if ((prop = RNA_struct_find_property(op->ptr, "value"))) {
- const float *values = (t->flag & T_AUTOVALUES) ? t->auto_values : t->values;
+ float values[4];
+
+ copy_v4_v4(values, (t->flag & T_AUTOVALUES) ? t->auto_values : t->values);
+
if (RNA_property_array_check(prop)) {
RNA_property_float_set_array(op->ptr, prop, values);
}
@@ -2030,9 +2031,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_ALT_TRANSFORM) != 0);
}
}
+
+ if ((prop = RNA_struct_find_property(op->ptr, "correct_uv"))) {
+ RNA_property_boolean_set(op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
+ }
}
-/* note: caller needs to free 't' on a 0 return */
+/**
+ * \note caller needs to free 't' on a 0 return
+ * \warning \a event might be NULL (when tweaking from redo panel)
+ * \see #saveTransform which writes these values back.
+ */
bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event, int mode)
{
int options = 0;
@@ -2158,7 +2167,9 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculatePropRatio(t);
calculateCenter(t);
- initMouseInput(t, &t->mouse, t->center2d, t->imval);
+ if (event) {
+ initMouseInput(t, &t->mouse, t->center2d, event->mval);
+ }
switch (mode) {
case TFM_TRANSLATION:
@@ -2226,14 +2237,20 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->mode = TFM_BONE_ENVELOPE_DIST;
break;
case TFM_EDGE_SLIDE:
+ case TFM_VERT_SLIDE:
{
- const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
- initEdgeSlide_ex(t, use_double_side);
+ const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false);
+ const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false);
+ const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true);
+ if (mode == TFM_EDGE_SLIDE) {
+ const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
+ initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp);
+ }
+ else {
+ initVertSlide_ex(t, use_even, flipped, use_clamp);
+ }
break;
}
- case TFM_VERT_SLIDE:
- initVertSlide(t);
- break;
case TFM_BONE_ROLL:
initBoneRoll(t);
break;
@@ -2289,22 +2306,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
return 0;
}
- /* overwrite initial values if operator supplied a non-null vector */
- if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
- float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
-
- if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
- }
- else {
- values[0] = RNA_float_get(op->ptr, "value");
- }
-
- copy_v4_v4(t->values, values);
- copy_v4_v4(t->auto_values, values);
- t->flag |= T_AUTOVALUES;
- }
-
/* Transformation axis from operator */
if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
RNA_property_float_get_array(op->ptr, prop, t->axis);
@@ -2335,6 +2336,25 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
+ /* overwrite initial values if operator supplied a non-null vector
+ *
+ * keep last so we can apply the constraints space.
+ */
+ if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
+ float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
+
+ if (RNA_property_array_check(prop)) {
+ RNA_float_get_array(op->ptr, "value", values);
+ }
+ else {
+ values[0] = RNA_float_get(op->ptr, "value");
+ }
+
+ copy_v4_v4(t->values, values);
+ copy_v4_v4(t->auto_values, values);
+ t->flag |= T_AUTOVALUES;
+ }
+
t->context = NULL;
return 1;
@@ -2637,7 +2657,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
}
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
/* axis angle */
- axis_angle_to_mat4(cob->matrix, &td->ext->quat[1], td->ext->quat[0]);
+ axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle);
}
else {
/* eulers */
@@ -2703,7 +2723,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
}
else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
/* axis angle */
- mat4_to_axis_angle(&td->ext->quat[1], &td->ext->quat[0], cob.matrix);
+ mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix);
}
else {
/* eulers */
@@ -2840,7 +2860,7 @@ static void initBend(TransInfo *t)
t->num.unit_type[0] = B_UNIT_ROTATION;
t->num.unit_type[1] = B_UNIT_LENGTH;
- t->flag |= T_NO_CONSTRAINT | T_FREE_CUSTOMDATA;
+ t->flag |= T_NO_CONSTRAINT;
//copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
calculateCenterCursor(t, t->center);
@@ -2868,7 +2888,8 @@ static void initBend(TransInfo *t)
data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
- t->customData = data;
+ t->custom.mode.data = data;
+ t->custom.mode.use_free = true;
}
static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
@@ -2890,7 +2911,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
float warp_end_radius[3];
int i;
char str[MAX_INFO_LEN];
- const struct BendCustomData *data = t->customData;
+ const struct BendCustomData *data = t->custom.mode.data;
const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
union {
@@ -2995,7 +3016,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
/* rotation */
if ((t->flag & T_POINTS) == 0) {
- ElementRotation(t, td, mat, V3D_LOCAL);
+ ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
}
/* location */
@@ -3047,27 +3068,27 @@ static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
eRedrawFlag status = TREDRAW_NOTHING;
if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
- // Use customData pointer to signal Shear direction
- if (t->customData == NULL) {
+ /* Use custom.mode.data pointer to signal Shear direction */
+ if (t->custom.mode.data == NULL) {
initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
- t->customData = (void *)1;
+ t->custom.mode.data = (void *)1;
}
else {
initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
- t->customData = NULL;
+ t->custom.mode.data = NULL;
}
status = TREDRAW_HARD;
}
else if (event->type == XKEY && event->val == KM_PRESS) {
initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
- t->customData = NULL;
+ t->custom.mode.data = NULL;
status = TREDRAW_HARD;
}
else if (event->type == YKEY && event->val == KM_PRESS) {
initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
- t->customData = (void *)1;
+ t->custom.mode.data = (void *)1;
status = TREDRAW_HARD;
}
@@ -3084,6 +3105,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
float value;
int i;
char str[MAX_INFO_LEN];
+ const bool is_local_center = transdata_check_local_center(t, t->around);
copy_m3_m4(persmat, t->viewmat);
invert_m3_m3(persinv, persmat);
@@ -3112,15 +3134,17 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
unit_m3(smat);
// Custom data signals shear direction
- if (t->customData == NULL)
+ if (t->custom.mode.data == NULL)
smat[1][0] = value;
else
smat[0][1] = value;
mul_m3_m3m3(tmat, smat, persmat);
mul_m3_m3m3(totmat, persinv, tmat);
-
+
for (i = 0; i < t->total; i++, td++) {
+ const float *center, *co;
+
if (td->flag & TD_NOACTION)
break;
@@ -3135,12 +3159,22 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
else {
copy_m3_m3(tmat, totmat);
}
- sub_v3_v3v3(vec, td->center, t->center);
+
+ if (is_local_center) {
+ center = td->center;
+ co = td->loc;
+ }
+ else {
+ center = t->center;
+ co = td->center;
+ }
+
+ sub_v3_v3v3(vec, co, center);
mul_m3_v3(tmat, vec);
- add_v3_v3(vec, t->center);
- sub_v3_v3(vec, td->center);
+ add_v3_v3(vec, center);
+ sub_v3_v3(vec, co);
mul_v3_fl(vec, td->factor);
@@ -3358,36 +3392,36 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
static void applyResize(TransInfo *t, const int mval[2])
{
TransData *td;
- float size[3], mat[3][3];
- float ratio;
+ float mat[3][3];
int i;
char str[MAX_INFO_LEN];
- /* for manipulator, center handle, the scaling can't be done relative to center */
- if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
- ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1])) / 100.0f;
+ if (t->flag & T_AUTOVALUES) {
+ copy_v3_v3(t->values, t->auto_values);
}
else {
- ratio = t->values[0];
- }
-
- copy_v3_fl(size, ratio);
-
- snapGridIncrement(t, size);
-
- if (applyNumInput(&t->num, size)) {
- constraintNumInput(t, size);
- }
-
- applySnapping(t, size);
-
- if (t->flag & T_AUTOVALUES) {
- copy_v3_v3(size, t->auto_values);
+ float ratio;
+
+ /* for manipulator, center handle, the scaling can't be done relative to center */
+ if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
+ ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f;
+ }
+ else {
+ ratio = t->values[0];
+ }
+
+ copy_v3_fl(t->values, ratio);
+
+ snapGridIncrement(t, t->values);
+
+ if (applyNumInput(&t->num, t->values)) {
+ constraintNumInput(t, t->values);
+ }
+
+ applySnapping(t, t->values);
}
- copy_v3_v3(t->values, size);
-
- size_to_mat3(mat, size);
+ size_to_mat3(mat, t->values);
if (t->con.applySize) {
t->con.applySize(t, NULL, mat);
@@ -3395,7 +3429,7 @@ static void applyResize(TransInfo *t, const int mval[2])
copy_m3_m3(t->mat, mat); // used in manipulator
- headerResize(t, size, str);
+ headerResize(t, t->values, str);
for (i = 0, td = t->data; i < t->total; i++, td++) {
if (td->flag & TD_NOACTION)
@@ -3408,8 +3442,8 @@ static void applyResize(TransInfo *t, const int mval[2])
}
/* evil hack - redo resize if cliping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
- size_to_mat3(mat, size);
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 1)) {
+ size_to_mat3(mat, t->values);
if (t->con.applySize)
t->con.applySize(t, NULL, mat);
@@ -4269,12 +4303,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INF
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
const char *str_old = BLI_strdup(str);
- const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? "right" : "left";
+ const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? IFACE_("right") : IFACE_("left");
char str_km[MAX_INFO_LEN];
WM_modalkeymap_items_to_string(t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, sizeof(str_km), str_km);
- ofs += BLI_snprintf(str, MAX_INFO_LEN, "Auto-offset set to %s - press %s to toggle direction | %s",
+ ofs += BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Auto-offset set to %s - press %s to toggle direction | %s"),
str_dir, str_km, str_old);
MEM_freeN((void *)str_old);
@@ -4309,14 +4343,14 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
- ElementRotation(t, td, mat, V3D_LOCAL);
+ ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
}
else {
float mat[3][3];
unit_m3(mat);
- ElementRotation(t, td, mat, V3D_LOCAL);
+ ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS);
}
}
@@ -4340,36 +4374,46 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
}
}
-/* uses t->vec to store actual translation in */
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[MAX_INFO_LEN];
+ float value_final[3];
+
+ if (t->flag & T_AUTOVALUES) {
+ copy_v3_v3(t->values, t->auto_values);
+ }
+ else {
+ if ((t->con.mode & CON_APPLY) == 0) {
+ snapGridIncrement(t, t->values);
+ }
- if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- float tvec[3];
if (applyNumInput(&t->num, t->values)) {
removeAspectRatio(t, t->values);
}
+
applySnapping(t, t->values);
- t->con.applyVec(t, NULL, t->values, tvec, pvec);
- copy_v3_v3(t->values, tvec);
+ }
+
+ if (t->con.mode & CON_APPLY) {
+ float pvec[3] = {0.0f, 0.0f, 0.0f};
+ t->con.applyVec(t, NULL, t->values, value_final, pvec);
headerTranslation(t, pvec, str);
+
+ /* only so we have re-usable value with redo, see T46741. */
+ mul_v3_m3v3(t->values, t->con.imtx, value_final);
}
else {
- snapGridIncrement(t, t->values);
- if (applyNumInput(&t->num, t->values)) {
- removeAspectRatio(t, t->values);
- }
- applySnapping(t, t->values);
headerTranslation(t, t->values, str);
+ copy_v3_v3(value_final, t->values);
}
- applyTranslationValue(t, t->values);
+ /* don't use 't->values' now on */
+
+ applyTranslationValue(t, value_final);
/* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0)) {
- applyTranslationValue(t, t->values);
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, value_final, 0)) {
+ applyTranslationValue(t, value_final);
/* In proportional edit it can happen that */
/* vertices in the radius of the brush end */
@@ -5164,7 +5208,7 @@ static void applyBoneSize(TransInfo *t, const int mval[2])
// TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
/* for manipulator, center handle, the scaling can't be done relative to center */
if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
- ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1])) / 100.0f;
+ ratio = 1.0f - ((t->mouse.imval[0] - mval[0]) + (t->mouse.imval[1] - mval[1])) / 100.0f;
}
else {
ratio = t->values[0];
@@ -5292,17 +5336,21 @@ static void slide_origdata_init_flag(
{
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
+ const bool has_layer_math = CustomData_has_math(&bm->ldata);
+ const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS);
if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
/* don't do this at all for non-basis shape keys, too easy to
* accidentally break uv maps or vertex colors then */
(bm->shapenr <= 1) &&
- CustomData_has_math(&bm->ldata))
+ (has_layer_math || (cd_loop_mdisp_offset != -1)))
{
sod->use_origfaces = true;
+ sod->cd_loop_mdisp_offset = cd_loop_mdisp_offset;
}
else {
sod->use_origfaces = false;
+ sod->cd_loop_mdisp_offset = -1;
}
}
@@ -5354,7 +5402,7 @@ static void slide_origdata_create_data_vert(
}
/* store cd_loop_groups */
- if (l_num != 0) {
+ if (sod->layer_math_map_num && (l_num != 0)) {
sv->cd_loop_groups = BLI_memarena_alloc(sod->arena, sod->layer_math_map_num * sizeof(void *));
for (j = 0; j < sod->layer_math_map_num; j++) {
const int layer_nr = sod->layer_math_map[j];
@@ -5381,15 +5429,19 @@ static void slide_origdata_create_data(
int layer_index_dst;
int j;
- /* over alloc, only 'math' layers are indexed */
- sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
layer_index_dst = 0;
- for (j = 0; j < bm->ldata.totlayer; j++) {
- if (CustomData_layer_has_math(&bm->ldata, j)) {
- sod->layer_math_map[layer_index_dst++] = j;
+
+ if (CustomData_has_math(&bm->ldata)) {
+ /* over alloc, only 'math' layers are indexed */
+ sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__);
+ for (j = 0; j < bm->ldata.totlayer; j++) {
+ if (CustomData_layer_has_math(&bm->ldata, j)) {
+ sod->layer_math_map[layer_index_dst++] = j;
+ }
}
+ BLI_assert(layer_index_dst != 0);
}
- BLI_assert(layer_index_dst != 0);
+
sod->layer_math_map_num = layer_index_dst;
sod->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@@ -5447,12 +5499,14 @@ static void slide_origdata_interp_data_vert(
BMIter liter;
int j, l_num;
float *loop_weights;
- const bool do_loop_weight = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
+ const bool is_moved = (len_squared_v3v3(sv->v->co, sv->co_orig_3d) > FLT_EPSILON);
+ const bool do_loop_weight = sod->layer_math_map_num && is_moved;
+ const bool do_loop_mdisps = is_final && is_moved && (sod->cd_loop_mdisp_offset != -1);
const float *v_proj_axis = sv->v->no;
/* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
float v_proj[3][3];
- if (do_loop_weight) {
+ if (do_loop_weight || do_loop_mdisps) {
project_plane_v3_v3v3(v_proj[1], sv->co_orig_3d, v_proj_axis);
}
@@ -5468,7 +5522,7 @@ static void slide_origdata_interp_data_vert(
/* only loop data, no vertex data since that contains shape keys,
* and we do not want to mess up other shape keys */
- BM_loop_interp_from_face(bm, l, f_copy, false, is_final);
+ BM_loop_interp_from_face(bm, l, f_copy, false, false);
/* make sure face-attributes are correct (e.g. MTexPoly) */
BM_elem_attrs_copy(sod->bm_origfaces, bm, f_copy, l->f);
@@ -5516,14 +5570,46 @@ static void slide_origdata_interp_data_vert(
}
}
- if (do_loop_weight) {
- for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
+ if (sod->layer_math_map_num) {
+ if (do_loop_weight) {
+ for (j = 0; j < sod->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge_weights(bm, sv->cd_loop_groups[j], sod->layer_math_map[j], loop_weights);
+ }
+ }
+ else {
+ for (j = 0; j < sod->layer_math_map_num; j++) {
+ BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
+ }
}
}
- else {
- for (j = 0; j < sod->layer_math_map_num; j++) {
- BM_vert_loop_groups_data_layer_merge(bm, sv->cd_loop_groups[j], sod->layer_math_map[j]);
+
+ /* Special handling for multires
+ *
+ * Interpolate from every other loop (not ideal)
+ * However values will only be taken from loops which overlap other mdisps.
+ * */
+ if (do_loop_mdisps) {
+ float (*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
+ BMLoop *l;
+
+ BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
+ BM_face_calc_center_mean(l->f, faces_center[j]);
+ }
+
+ BM_ITER_ELEM_INDEX (l, &liter, sv->v, BM_LOOPS_OF_VERT, j) {
+ BMFace *f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
+ float f_copy_center[3];
+ BMIter liter_other;
+ BMLoop *l_other;
+ int j_other;
+
+ BM_face_calc_center_mean(f_copy, f_copy_center);
+
+ BM_ITER_ELEM_INDEX (l_other, &liter_other, sv->v, BM_LOOPS_OF_VERT, j_other) {
+ BM_face_interp_multires_ex(
+ bm, l_other->f, f_copy,
+ faces_center[j_other], f_copy_center, sod->cd_loop_mdisp_offset);
+ }
}
}
}
@@ -5537,10 +5623,11 @@ static void slide_origdata_interp_data(
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
unsigned int i;
+ const bool has_mdisps = (sod->cd_loop_mdisp_offset != -1);
for (i = 0; i < v_num; i++, sv = POINTER_OFFSET(sv, v_stride)) {
- if (sv->cd_loop_groups) {
+ if (sv->cd_loop_groups || has_mdisps) {
slide_origdata_interp_data_vert(sod, bm, is_final, sv);
}
}
@@ -5548,7 +5635,7 @@ static void slide_origdata_interp_data(
if (sod->sv_mirror) {
sv = sod->sv_mirror;
for (i = 0; i < v_num; i++, sv++) {
- if (sv->cd_loop_groups) {
+ if (sv->cd_loop_groups || has_mdisps) {
slide_origdata_interp_data_vert(sod, bm, is_final, sv);
}
}
@@ -5596,7 +5683,7 @@ static void slide_origdata_free_date(
static void calcEdgeSlideCustomPoints(struct TransInfo *t)
{
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = t->custom.mode.data;
setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
@@ -5959,7 +6046,7 @@ static void calcEdgeSlide_mval_range(
}
}
-static void calcEdgeSlide_non_proportional(
+static void calcEdgeSlide_even(
TransInfo *t, EdgeSlideData *sld, const float mval[2])
{
TransDataEdgeSlideVert *sv = sld->sv;
@@ -6005,7 +6092,7 @@ static void calcEdgeSlide_non_proportional(
}
}
-static bool createEdgeSlideVerts_double_side(TransInfo *t)
+static bool createEdgeSlideVerts_double_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
@@ -6024,9 +6111,11 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t)
slide_origdata_init_flag(t, &sld->orig_data);
- sld->is_proportional = true;
+ sld->use_even = use_even;
sld->curr_sv_index = 0;
- sld->flipped_vtx = false;
+ sld->flipped = flipped;
+ if (!use_clamp)
+ t->flag |= T_ALT_TRANSFORM;
/*ensure valid selection*/
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -6332,14 +6421,14 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t)
slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
if (rv3d) {
- calcEdgeSlide_non_proportional(t, sld, mval);
+ calcEdgeSlide_even(t, sld, mval);
}
sld->em = em;
sld->perc = 0.0f;
- t->customData = sld;
+ t->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -6350,19 +6439,18 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t)
* A simple version of #createEdgeSlideVerts_double_side
* Which assumes the longest unselected.
*/
-static bool createEdgeSlideVerts_single_side(TransInfo *t)
+static bool createEdgeSlideVerts_single_side(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
BMIter iter;
BMEdge *e;
- BMVert *v;
TransDataEdgeSlideVert *sv_array;
int sv_tot;
int *sv_table; /* BMVert -> sv_array index */
EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- int i, j, loop_nr;
+ int loop_nr;
bool use_btree_disp = false;
View3D *v3d = NULL;
RegionView3D *rv3d = NULL;
@@ -6375,41 +6463,47 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t)
slide_origdata_init_flag(t, &sld->orig_data);
- sld->is_proportional = true;
+ sld->use_even = use_even;
sld->curr_sv_index = 0;
- /* heppans to be best for single-sided */
- sld->flipped_vtx = true;
+ /* happens to be best for single-sided */
+ sld->flipped = !flipped;
+ if (!use_clamp)
+ t->flag |= T_ALT_TRANSFORM;
/* ensure valid selection */
- j = 0;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- float len_sq_max = -1.0f;
- BMIter iter2;
- BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq > len_sq_max) {
- len_sq_max = len_sq;
- v->e = e;
+ {
+ int i = 0, j = 0;
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float len_sq_max = -1.0f;
+ BMIter iter2;
+ BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > len_sq_max) {
+ len_sq_max = len_sq;
+ v->e = e;
+ }
}
}
- }
- if (len_sq_max != -1.0f) {
- j++;
+ if (len_sq_max != -1.0f) {
+ j++;
+ }
}
+ BM_elem_index_set(v, i); /* set_inline */
}
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
+ bm->elem_index_dirty &= ~BM_VERT;
- if (!j) {
- return false;
- }
+ if (!j) {
+ return false;
+ }
+ sv_tot = j;
+ }
- sv_tot = j;
BLI_assert(sv_tot != 0);
/* over alloc */
sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
@@ -6419,20 +6513,24 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t)
sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
- j = 0;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- sv_table[i] = -1;
- if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
- if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
- TransDataEdgeSlideVert *sv;
- sv = &sv_array[j];
- sv->v = v;
- copy_v3_v3(sv->v_co_orig, v->co);
- sv->v_side[0] = BM_edge_other_vert(v->e, v);
- sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
- sv->loop_nr = 0;
- sv_table[i] = j;
- j += 1;
+ {
+ int i = 0, j = 0;
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ sv_table[i] = -1;
+ if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
+ if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
+ TransDataEdgeSlideVert *sv;
+ sv = &sv_array[j];
+ sv->v = v;
+ copy_v3_v3(sv->v_co_orig, v->co);
+ sv->v_side[0] = BM_edge_other_vert(v->e, v);
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
+ sv->loop_nr = 0;
+ sv_table[i] = j;
+ j += 1;
+ }
}
}
}
@@ -6442,14 +6540,15 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t)
if (sv_tot != bm->totvert) {
const int sv_tot_nowire = sv_tot;
TransDataEdgeSlideVert *sv_iter = sv_array;
- int i;
- for (i = 0; i < sv_tot_nowire; i++, sv_iter++) {
+
+ for (int i = 0; i < sv_tot_nowire; i++, sv_iter++) {
BMIter eiter;
BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
/* walk over wire */
TransDataEdgeSlideVert *sv_end = NULL;
BMEdge *e_step = e;
BMVert *v = sv_iter->v;
+ int j;
j = sv_tot;
@@ -6524,14 +6623,14 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t)
slide_origdata_create_data(t, &sld->orig_data, (TransDataGenericSlideVert *)sld->sv, sizeof(*sld->sv), sld->totsv);
if (rv3d) {
- calcEdgeSlide_non_proportional(t, sld, mval);
+ calcEdgeSlide_even(t, sld, mval);
}
sld->em = em;
sld->perc = 0.0f;
- t->customData = sld;
+ t->custom.mode.data = sld;
MEM_freeN(sv_table);
@@ -6540,7 +6639,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t)
void projectEdgeSlideData(TransInfo *t, bool is_final)
{
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = t->custom.mode.data;
SlideOrigData *sod = &sld->orig_data;
if (sod->use_origfaces == false) {
@@ -6555,9 +6654,9 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld)
slide_origdata_free_date(&sld->orig_data);
}
-void freeEdgeSlideVerts(TransInfo *t)
+void freeEdgeSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
{
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = custom_data->data;
if (!sld)
return;
@@ -6569,10 +6668,10 @@ void freeEdgeSlideVerts(TransInfo *t)
MEM_freeN(sld->sv);
MEM_freeN(sld);
- t->customData = NULL;
+ custom_data->data = NULL;
}
-static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
+static void initEdgeSlide_ex(TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
{
EdgeSlideData *sld;
bool ok;
@@ -6582,10 +6681,10 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
t->handleEvent = handleEventEdgeSlide;
if (use_double_side) {
- ok = createEdgeSlideVerts_double_side(t);
+ ok = createEdgeSlideVerts_double_side(t, use_even, flipped, use_clamp);
}
else {
- ok = createEdgeSlideVerts_single_side(t);
+ ok = createEdgeSlideVerts_single_side(t, use_even, flipped, use_clamp);
}
if (!ok) {
@@ -6593,12 +6692,12 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
return;
}
- sld = t->customData;
+ sld = t->custom.mode.data;
if (!sld)
return;
- t->customFree = freeEdgeSlideVerts;
+ t->custom.mode.free_cb = freeEdgeSlideVerts;
/* set custom point first if you want value to be initialized by init */
calcEdgeSlideCustomPoints(t);
@@ -6619,28 +6718,26 @@ static void initEdgeSlide_ex(TransInfo *t, bool use_double_side)
static void initEdgeSlide(TransInfo *t)
{
- initEdgeSlide_ex(t, true);
+ initEdgeSlide_ex(t, true, false, false, true);
}
static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = t->custom.mode.data;
if (sld) {
switch (event->type) {
case EKEY:
if (event->val == KM_PRESS) {
- sld->is_proportional = !sld->is_proportional;
+ sld->use_even = !sld->use_even;
calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
break;
case FKEY:
if (event->val == KM_PRESS) {
- if (sld->is_proportional == false) {
- sld->flipped_vtx = !sld->flipped_vtx;
- }
+ sld->flipped = !sld->flipped;
calcEdgeSlideCustomPoints(t);
return TREDRAW_HARD;
}
@@ -6676,12 +6773,12 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven
static void drawEdgeSlide(TransInfo *t)
{
- if ((t->mode == TFM_EDGE_SLIDE) && t->customData) {
- EdgeSlideData *sld = t->customData;
+ if ((t->mode == TFM_EDGE_SLIDE) && t->custom.mode.data) {
+ EdgeSlideData *sld = t->custom.mode.data;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
- /* Non-Prop mode */
- if ((sld->is_proportional == false) || (is_clamp == false)) {
+ /* Even mode */
+ if ((sld->use_even == true) || (is_clamp == false)) {
View3D *v3d = t->view;
const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
@@ -6696,7 +6793,7 @@ static void drawEdgeSlide(TransInfo *t)
glMultMatrixf(t->obedit->obmat);
- if (sld->is_proportional == false) {
+ if (sld->use_even == true) {
float co_a[3], co_b[3], co_mark[3];
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
const float fac = (sld->perc + 1.0f) / 2.0f;
@@ -6722,25 +6819,25 @@ static void drawEdgeSlide(TransInfo *t)
UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
glPointSize(ctrl_size);
- bglBegin(GL_POINTS);
- if (sld->flipped_vtx) {
- if (curr_sv->v_side[1]) bglVertex3fv(curr_sv->v_side[1]->co);
+ glBegin(GL_POINTS);
+ if (sld->flipped) {
+ if (curr_sv->v_side[1]) glVertex3fv(curr_sv->v_side[1]->co);
}
else {
- if (curr_sv->v_side[0]) bglVertex3fv(curr_sv->v_side[0]->co);
+ if (curr_sv->v_side[0]) glVertex3fv(curr_sv->v_side[0]->co);
}
- bglEnd();
+ glEnd();
UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
glPointSize(guide_size);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
#if 0
interp_v3_v3v3(co_mark, co_b, co_a, fac);
- bglVertex3fv(co_mark);
+ glVertex3fv(co_mark);
#endif
interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
- bglVertex3fv(co_mark);
- bglEnd();
+ glVertex3fv(co_mark);
+ glEnd();
}
else {
if (is_clamp == false) {
@@ -6792,14 +6889,14 @@ static void drawEdgeSlide(TransInfo *t)
static void doEdgeSlide(TransInfo *t, float perc)
{
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = t->custom.mode.data;
TransDataEdgeSlideVert *svlist = sld->sv, *sv;
int i;
sld->perc = perc;
sv = svlist;
- if (sld->is_proportional == true) {
+ if (sld->use_even == false) {
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
if (is_clamp) {
const int side_index = (perc < 0.0f);
@@ -6829,7 +6926,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
}
else {
/**
- * Implementation note, non proportional mode ignores the starting positions and uses only the
+ * Implementation note, even mode ignores the starting positions and uses only the
* a/b verts, this could be changed/improved so the distance is still met but the verts are moved along
* their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
*
@@ -6837,7 +6934,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
* is the same as the distance between the original vert locations, same goes for the lines below.
*/
TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float curr_length_perc = curr_sv->edge_len * (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f);
+ const float curr_length_perc = curr_sv->edge_len * (((sld->flipped ? perc : -perc) + 1.0f) / 2.0f);
float co_a[3];
float co_b[3];
@@ -6849,7 +6946,7 @@ static void doEdgeSlide(TransInfo *t, float perc)
add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
- if (sld->flipped_vtx) {
+ if (sld->flipped) {
interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
}
else {
@@ -6865,9 +6962,9 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
char str[MAX_INFO_LEN];
size_t ofs = 0;
float final;
- EdgeSlideData *sld = t->customData;
- bool flipped = sld->flipped_vtx;
- bool is_proportional = sld->is_proportional;
+ EdgeSlideData *sld = t->custom.mode.data;
+ bool flipped = sld->flipped;
+ bool use_even = sld->use_even;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
@@ -6894,8 +6991,8 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
else {
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional));
- if (!is_proportional) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ if (use_even) {
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
@@ -6919,7 +7016,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
static void calcVertSlideCustomPoints(struct TransInfo *t)
{
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
const float *co_orig_3d = sv->co_orig_3d;
@@ -6932,11 +7029,11 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat);
ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat);
- ARRAY_SET_ITEMS(mval_ofs, t->imval[0] - co_orig_2d[0], t->imval[1] - co_orig_2d[1]);
+ ARRAY_SET_ITEMS(mval_ofs, t->mouse.imval[0] - co_orig_2d[0], t->mouse.imval[1] - co_orig_2d[1]);
ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
- if (sld->flipped_vtx && sld->is_proportional == false) {
+ if (sld->flipped && sld->use_even) {
setCustomPoints(t, &t->mouse, mval_start, mval_end);
}
else {
@@ -6954,7 +7051,7 @@ static void calcVertSlideCustomPoints(struct TransInfo *t)
*/
static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
{
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
float mval_fl[2] = {UNPACK2(mval)};
TransDataVertSlideVert *sv;
@@ -6981,8 +7078,8 @@ static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
*/
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
{
- VertSlideData *sld = t->customData;
- float imval_fl[2] = {UNPACK2(t->imval)};
+ VertSlideData *sld = t->custom.mode.data;
+ float imval_fl[2] = {UNPACK2(t->mouse.imval)};
float mval_fl[2] = {UNPACK2(mval)};
float dir[3];
@@ -7027,7 +7124,7 @@ static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2]
}
}
-static bool createVertSlideVerts(TransInfo *t)
+static bool createVertSlideVerts(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
BMesh *bm = em->bm;
@@ -7041,9 +7138,11 @@ static bool createVertSlideVerts(TransInfo *t)
slide_origdata_init_flag(t, &sld->orig_data);
- sld->is_proportional = true;
+ sld->use_even = use_even;
sld->curr_sv_index = 0;
- sld->flipped_vtx = false;
+ sld->flipped = flipped;
+ if (!use_clamp)
+ t->flag |= T_ALT_TRANSFORM;
j = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -7113,7 +7212,7 @@ static bool createVertSlideVerts(TransInfo *t)
sld->perc = 0.0f;
- t->customData = sld;
+ t->custom.mode.data = sld;
/* most likely will be set below */
unit_m4(sld->proj_mat);
@@ -7137,7 +7236,7 @@ static bool createVertSlideVerts(TransInfo *t)
void projectVertSlideData(TransInfo *t, bool is_final)
{
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
SlideOrigData *sod = &sld->orig_data;
if (sod->use_origfaces == false) {
@@ -7152,9 +7251,9 @@ void freeVertSlideTempFaces(VertSlideData *sld)
slide_origdata_free_date(&sld->orig_data);
}
-void freeVertSlideVerts(TransInfo *t)
+void freeVertSlideVerts(TransInfo *UNUSED(t), TransCustomData *custom_data)
{
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = custom_data->data;
if (!sld)
return;
@@ -7174,10 +7273,10 @@ void freeVertSlideVerts(TransInfo *t)
MEM_freeN(sld->sv);
MEM_freeN(sld);
- t->customData = NULL;
+ custom_data->data = NULL;
}
-static void initVertSlide(TransInfo *t)
+static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
{
VertSlideData *sld;
@@ -7185,17 +7284,17 @@ static void initVertSlide(TransInfo *t)
t->transform = applyVertSlide;
t->handleEvent = handleEventVertSlide;
- if (!createVertSlideVerts(t)) {
+ if (!createVertSlideVerts(t, use_even, flipped, use_clamp)) {
t->state = TRANS_CANCEL;
return;
}
- sld = t->customData;
+ sld = t->custom.mode.data;
if (!sld)
return;
- t->customFree = freeVertSlideVerts;
+ t->custom.mode.free_cb = freeVertSlideVerts;
/* set custom point first if you want value to be initialized by init */
calcVertSlideCustomPoints(t);
@@ -7214,17 +7313,22 @@ static void initVertSlide(TransInfo *t)
t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
}
+static void initVertSlide(TransInfo *t)
+{
+ initVertSlide_ex(t, false, false, true);
+}
+
static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
{
if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
if (sld) {
switch (event->type) {
case EKEY:
if (event->val == KM_PRESS) {
- sld->is_proportional = !sld->is_proportional;
- if (sld->flipped_vtx) {
+ sld->use_even = !sld->use_even;
+ if (sld->flipped) {
calcVertSlideCustomPoints(t);
}
return TREDRAW_HARD;
@@ -7232,7 +7336,7 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
break;
case FKEY:
if (event->val == KM_PRESS) {
- sld->flipped_vtx = !sld->flipped_vtx;
+ sld->flipped = !sld->flipped;
calcVertSlideCustomPoints(t);
return TREDRAW_HARD;
}
@@ -7277,8 +7381,8 @@ static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEven
static void drawVertSlide(TransInfo *t)
{
- if ((t->mode == TFM_VERT_SLIDE) && t->customData) {
- VertSlideData *sld = t->customData;
+ if ((t->mode == TFM_VERT_SLIDE) && t->custom.mode.data) {
+ VertSlideData *sld = t->custom.mode.data;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
/* Non-Prop mode */
@@ -7326,29 +7430,29 @@ static void drawVertSlide(TransInfo *t)
glVertex3fv(b);
}
}
- bglEnd();
+ glEnd();
glPointSize(ctrl_size);
- bglBegin(GL_POINTS);
- bglVertex3fv((sld->flipped_vtx && sld->is_proportional == false) ?
- curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
- curr_sv->co_orig_3d);
- bglEnd();
+ glBegin(GL_POINTS);
+ glVertex3fv((sld->flipped && sld->use_even) ?
+ curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
+ curr_sv->co_orig_3d);
+ glEnd();
glDisable(GL_BLEND);
/* direction from active vertex! */
- if ((t->mval[0] != t->imval[0]) ||
- (t->mval[1] != t->imval[1]))
+ if ((t->mval[0] != t->mouse.imval[0]) ||
+ (t->mval[1] != t->mouse.imval[1]))
{
float zfac;
float mval_ofs[2];
float co_orig_3d[3];
float co_dest_3d[3];
- mval_ofs[0] = t->mval[0] - t->imval[0];
- mval_ofs[1] = t->mval[1] - t->imval[1];
+ mval_ofs[0] = t->mval[0] - t->mouse.imval[0];
+ mval_ofs[1] = t->mval[1] - t->mouse.imval[1];
mul_v3_m4v3(co_orig_3d, t->obedit->obmat, curr_sv->co_orig_3d);
zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL);
@@ -7382,14 +7486,14 @@ static void drawVertSlide(TransInfo *t)
static void doVertSlide(TransInfo *t, float perc)
{
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
TransDataVertSlideVert *svlist = sld->sv, *sv;
int i;
sld->perc = perc;
sv = svlist;
- if (sld->is_proportional == true) {
+ if (sld->use_even == false) {
for (i = 0; i < sld->totsv; i++, sv++) {
interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
}
@@ -7407,7 +7511,7 @@ static void doVertSlide(TransInfo *t, float perc)
edge_len = normalize_v3(dir);
if (edge_len > FLT_EPSILON) {
- if (sld->flipped_vtx) {
+ if (sld->flipped) {
madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
}
else {
@@ -7426,9 +7530,9 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
char str[MAX_INFO_LEN];
size_t ofs = 0;
float final;
- VertSlideData *sld = t->customData;
- const bool flipped = sld->flipped_vtx;
- const bool is_proportional = sld->is_proportional;
+ VertSlideData *sld = t->custom.mode.data;
+ const bool flipped = sld->flipped;
+ const bool use_even = sld->use_even;
const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
@@ -7455,8 +7559,8 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
else {
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, "%.4f ", final);
}
- ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(!is_proportional));
- if (!is_proportional) {
+ ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ if (use_even) {
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("(F)lipped: %s, "), WM_bool_as_string(flipped));
}
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
@@ -7575,12 +7679,17 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
float fac = 0.1f;
+ /* XXX, disable precision for now,
+ * this isn't even accessible by the user */
+#if 0
if (t->mouse.precision) {
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac;
time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time);
}
- else {
+ else
+#endif
+ {
time = (float)(t->center2d[0] - mval[0]) * fac;
}
@@ -8128,7 +8237,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
if (t->flag & T_MODAL) {
float cval[2], sval[2];
UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[0], &sval[0], &sval[1]);
/* we only need to calculate effect for time (applyTimeTranslate only needs that) */
t->values[0] = cval[0] - sval[0];
@@ -8171,10 +8280,34 @@ static void initTimeSlide(TransInfo *t)
t->mode = TFM_TIME_SLIDE;
t->transform = applyTimeSlide;
- t->flag |= T_FREE_CUSTOMDATA;
initMouseInputMode(t, &t->mouse, INPUT_NONE);
+ {
+ Scene *scene = t->scene;
+ float *range;
+ t->custom.mode.data = range = MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max");
+ t->custom.mode.use_free = true;
+
+ float min = 999999999.0f, max = -999999999.0f;
+ int i;
+
+ TransData *td = t->data;
+ for (i = 0; i < t->total; i++, td++) {
+ if (min > *(td->val)) min = *(td->val);
+ if (max < *(td->val)) max = *(td->val);
+ }
+
+ if (min == max) {
+ /* just use the current frame ranges */
+ min = (float)PSFRA;
+ max = (float)PEFRA;
+ }
+
+ range[0] = min;
+ range[1] = max;
+ }
+
/* num-input has max of (n-1) */
t->idx_max = 0;
t->num.flag = 0;
@@ -8198,8 +8331,9 @@ static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LE
outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
- float minx = *((float *)(t->customData));
- float maxx = *((float *)(t->customData) + 1);
+ const float *range = t->custom.mode.data;
+ float minx = range[0];
+ float maxx = range[1];
float cval = t->values[0];
float val;
@@ -8216,9 +8350,9 @@ static void applyTimeSlideValue(TransInfo *t, float sval)
{
TransData *td = t->data;
int i;
-
- float minx = *((float *)(t->customData));
- float maxx = *((float *)(t->customData) + 1);
+ const float *range = t->custom.mode.data;
+ float minx = range[0];
+ float maxx = range[1];
/* set value for drawing black line */
if (t->spacetype == SPACE_ACTION) {
@@ -8263,13 +8397,14 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
{
View2D *v2d = (View2D *)t->view;
float cval[2], sval[2];
- float minx = *((float *)(t->customData));
- float maxx = *((float *)(t->customData) + 1);
+ const float *range = t->custom.mode.data;
+ float minx = range[0];
+ float maxx = range[1];
char str[MAX_INFO_LEN];
/* calculate mouse co-ordinates */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &sval[0], &sval[1]);
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]);
/* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */
// XXX Need to be able to repeat this
@@ -8314,10 +8449,10 @@ static void initTimeScale(TransInfo *t)
* what is used in time scale */
t->center[0] = t->scene->r.cfra;
projectFloatView(t, t->center, center);
- center[1] = t->imval[1];
+ center[1] = t->mouse.imval[1];
/* force a reinit with the center2d used here */
- initMouseInput(t, &t->mouse, center, t->imval);
+ initMouseInput(t, &t->mouse, center, t->mouse.imval);
initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
@@ -8413,7 +8548,9 @@ bool checkUseAxisMatrix(TransInfo *t)
{
/* currently only checks for editmode */
if (t->flag & T_EDIT) {
- if ((t->around == V3D_LOCAL) && (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)))
+ {
/* not all editmode supports axis-matrix */
return true;
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index aab065675fe..c156e9ecec0 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -90,12 +90,16 @@ typedef struct TransSnap {
char snapNodeBorder;
ListBase points;
TransSnapPoint *selectedPoint;
- float dist; // Distance from snapPoint to snapTarget
double last;
void (*applySnap)(struct TransInfo *, float *);
void (*calcSnap)(struct TransInfo *, float *);
void (*targetSnap)(struct TransInfo *);
- /* Get the transform distance between two points (used by Closest snap) */
+ /**
+ * Get the transform distance between two points (used by Closest snap)
+ *
+ * \note Return value can be anything,
+ * where the smallest absolute value defines whats closest.
+ */
float (*distance)(struct TransInfo *, const float p1[3], const float p2[3]);
} TransSnap;
@@ -225,6 +229,8 @@ typedef struct TransDataEdgeSlideVert {
typedef struct SlideOrigData {
/* flag that is set when origfaces is initialized */
bool use_origfaces;
+ int cd_loop_mdisp_offset;
+
struct GHash *origverts; /* map {BMVert: TransDataGenericSlideVert} */
struct GHash *origfaces;
struct BMesh *bm_origfaces;
@@ -252,8 +258,8 @@ typedef struct EdgeSlideData {
float perc;
- bool is_proportional;
- bool flipped_vtx;
+ bool use_even;
+ bool flipped;
int curr_sv_index;
@@ -284,8 +290,8 @@ typedef struct VertSlideData {
float perc;
- bool is_proportional;
- bool flipped_vtx;
+ bool use_even;
+ bool flipped;
int curr_sv_index;
@@ -326,17 +332,37 @@ typedef struct TransData {
} TransData;
typedef struct MouseInput {
- void (*apply)(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]);
+ void (*apply)(struct TransInfo *t, struct MouseInput *mi, const double mval[2], float output[3]);
void (*post)(struct TransInfo *t, float values[3]);
int imval[2]; /* initial mouse position */
bool precision;
- int precision_mval[2]; /* mouse position when precision key was pressed */
+ float precision_factor;
float center[2];
float factor;
void *data; /* additional data, if needed by the particular function */
+
+ /**
+ * Use virtual cursor, which takes precision into account
+ * keeping track of the cursors 'virtual' location,
+ * to avoid jumping values when its toggled.
+ *
+ * This works well for scaling drag motion,
+ * but not for rotating around a point (rotaton needs its own custom accumulator)
+ */
+ bool use_virtual_mval;
+ struct {
+ double prev[2];
+ double accum[2];
+ } virtual_mval;
} MouseInput;
+typedef struct TransCustomData {
+ void *data;
+ void (*free_cb)(struct TransInfo *, struct TransCustomData *);
+ unsigned int use_free : 1;
+} TransCustomData;
+
typedef struct TransInfo {
int mode; /* current mode */
int flag; /* generic flags for special behaviors */
@@ -344,7 +370,6 @@ typedef struct TransInfo {
short state; /* current state (running, canceled,...)*/
int options; /* current context/options for transform */
float val; /* init value for some transformations (and rotation angle) */
- float fac; /* factor for distance based transform */
void (*transform)(struct TransInfo *, const int[2]);
/* transform function pointer */
eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *);
@@ -365,8 +390,6 @@ typedef struct TransInfo {
float center[3]; /* center of transformation (in local-space) */
float center_global[3]; /* center of transformation (in global-space) */
float center2d[2]; /* center in screen coordinates */
- int imval[2]; /* initial mouse position */
- short event_type; /* event->type used to invoke transform */
short idx_max; /* maximum index on the input vector */
float snap[3]; /* Snapping Gears */
float snap_spatial[3]; /* Spatial snapping gears(even when rotating, scaling... etc) */
@@ -389,8 +412,22 @@ typedef struct TransInfo {
struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */
- void *customData; /* Per Transform custom data */
- void (*customFree)(struct TransInfo *); /* if a special free function is needed */
+ /**
+ * Rule of thumb for choosing between mode/type:
+ * - If transform mode uses the data, assign to `mode`
+ * (typically in transform.c).
+ * - If conversion uses the data as an extension to the #TransData, assign to `type`
+ * (typically in transform_conversion.c).
+ */
+ struct {
+ /* owned by the mode (grab, scale, bend... )*/
+ union {
+ TransCustomData mode, first_elem;
+ };
+ /* owned by the type (mesh, armature, nla...) */
+ TransCustomData type;
+ } custom;
+#define TRANS_CUSTOM_DATA_ELEM_MAX (sizeof(((TransInfo *)NULL)->custom) / sizeof(TransCustomData))
/*************** NEW STUFF *********************/
short launch_event; /* event type used to launch transform */
@@ -465,7 +502,6 @@ typedef struct TransInfo {
#define T_2D_EDIT (1 << 15)
#define T_CLIP_UV (1 << 16)
-#define T_FREE_CUSTOMDATA (1 << 17)
/* auto-ik is on */
#define T_AUTOIK (1 << 18)
@@ -550,7 +586,7 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void setTransformViewAspect(TransInfo *t, float r_aspect[3]);
-void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy);
+void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy);
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag);
void projectIntView(TransInfo *t, const float vec[3], int adr[2]);
void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag);
@@ -739,11 +775,11 @@ int getTransformOrientation_ex(const struct bContext *C, float normal[3], float
int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]);
void freeEdgeSlideTempFaces(EdgeSlideData *sld);
-void freeEdgeSlideVerts(TransInfo *t);
+void freeEdgeSlideVerts(TransInfo *t, TransCustomData *custom_data);
void projectEdgeSlideData(TransInfo *t, bool is_final);
void freeVertSlideTempFaces(VertSlideData *sld);
-void freeVertSlideVerts(TransInfo *t);
+void freeVertSlideVerts(TransInfo *t, TransCustomData *custom_data);
void projectVertSlideData(TransInfo *t, bool is_final);
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 9f4d53f1f22..beeba7cf10f 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -86,7 +86,8 @@ void constraintNumInput(TransInfo *t, float vec[3])
if (mode & CON_APPLY) {
float nval = (t->flag & T_NULL_ONE) ? 1.0f : 0.0f;
- if (getConstraintSpaceDimension(t) == 2) {
+ const int dims = getConstraintSpaceDimension(t);
+ if (dims == 2) {
int axis = mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2);
if (axis == (CON_AXIS0 | CON_AXIS1)) {
/* vec[0] = vec[0]; */ /* same */
@@ -104,7 +105,7 @@ void constraintNumInput(TransInfo *t, float vec[3])
vec[1] = nval;
}
}
- else if (getConstraintSpaceDimension(t) == 1) {
+ else if (dims == 1) {
if (mode & CON_AXIS0) {
/* vec[0] = vec[0]; */ /* same */
vec[1] = nval;
@@ -150,7 +151,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
/* autovalues is operator param, use that directly but not if snapping is forced */
if (t->flag & T_AUTOVALUES && (t->tsnap.status & SNAP_FORCED) == 0) {
- mul_v3_m3v3(vec, t->con.imtx, t->auto_values);
+ copy_v3_v3(vec, t->auto_values);
constraintAutoValues(t, vec);
/* inverse transformation at the end */
}
@@ -273,6 +274,36 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
}
}
+/**
+ * Return true if the 2x axis are both aligned when projected into the view.
+ * In this case, we can't usefully project the cursor onto the plane.
+ */
+static bool isPlaneProjectionViewAligned(TransInfo *t)
+{
+ const float eps = 0.001f;
+ const float *constraint_vector[2];
+ int n = 0;
+ for (int i = 0; i < 3; i++) {
+ if (t->con.mode & (CON_AXIS0 << i)) {
+ constraint_vector[n++] = t->con.mtx[i];
+ if (n == 2) {
+ break;
+ }
+ }
+ }
+ BLI_assert(n == 2);
+
+ float view_to_plane[3], plane_normal[3];
+
+ getViewVector(t, t->center_global, view_to_plane);
+
+ cross_v3_v3v3(plane_normal, constraint_vector[0], constraint_vector[1]);
+ normalize_v3(plane_normal);
+
+ float factor = dot_v3v3(plane_normal, view_to_plane);
+ return fabsf(factor) < eps;
+}
+
static void planeProjection(TransInfo *t, const float in[3], float out[3])
{
float vec[3], factor, norm[3];
@@ -311,12 +342,16 @@ static void applyAxisConstraintVec(TransInfo *t, TransData *td, const float in[3
// With snap, a projection is alright, no need to correct for view alignment
if (!(!ELEM(t->tsnap.mode, SCE_SNAP_MODE_INCREMENT, SCE_SNAP_MODE_GRID) && activeSnap(t))) {
- if (getConstraintSpaceDimension(t) == 2) {
- if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
- planeProjection(t, in, out);
+
+ const int dims = getConstraintSpaceDimension(t);
+ if (dims == 2) {
+ if (!is_zero_v3(out)) {
+ if (!isPlaneProjectionViewAligned(t)) {
+ planeProjection(t, in, out);
+ }
}
}
- else if (getConstraintSpaceDimension(t) == 1) {
+ else if (dims == 1) {
float c[3];
if (t->con.mode & CON_AXIS0) {
@@ -352,12 +387,16 @@ static void applyObjectConstraintVec(TransInfo *t, TransData *td, const float in
if (t->con.mode & CON_APPLY) {
if (!td) {
mul_m3_v3(t->con.pmtx, out);
- if (getConstraintSpaceDimension(t) == 2) {
- if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
- planeProjection(t, in, out);
+
+ const int dims = getConstraintSpaceDimension(t);
+ if (dims == 2) {
+ if (!is_zero_v3(out)) {
+ if (!isPlaneProjectionViewAligned(t)) {
+ planeProjection(t, in, out);
+ }
}
}
- else if (getConstraintSpaceDimension(t) == 1) {
+ else if (dims == 1) {
float c[3];
if (t->con.mode & CON_AXIS0) {
@@ -673,11 +712,6 @@ void drawConstraint(TransInfo *t)
if (t->flag & T_NO_CONSTRAINT)
return;
- /* nasty exception for Z constraint in camera view */
- // TRANSFORM_FIX_ME
-// if ((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB)
-// return;
-
if (tc->drawExtra) {
tc->drawExtra(t);
}
@@ -701,7 +735,7 @@ void drawConstraint(TransInfo *t)
glDisable(GL_DEPTH_TEST);
setlinestyle(1);
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex3fv(t->center_global);
glVertex3fv(vec);
glEnd();
@@ -855,21 +889,15 @@ void getConstraintMatrix(TransInfo *t)
unit_m3(t->con.pmtx);
if (!(t->con.mode & CON_AXIS0)) {
- t->con.pmtx[0][0] =
- t->con.pmtx[0][1] =
- t->con.pmtx[0][2] = 0.0f;
+ zero_v3(t->con.pmtx[0]);
}
if (!(t->con.mode & CON_AXIS1)) {
- t->con.pmtx[1][0] =
- t->con.pmtx[1][1] =
- t->con.pmtx[1][2] = 0.0f;
+ zero_v3(t->con.pmtx[1]);
}
if (!(t->con.mode & CON_AXIS2)) {
- t->con.pmtx[2][0] =
- t->con.pmtx[2][1] =
- t->con.pmtx[2][2] = 0.0f;
+ zero_v3(t->con.pmtx[2]);
}
mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index c12418f1a0f..5d3e71c5a3c 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -117,6 +117,8 @@
#include "RNA_access.h"
+#include "DEG_depsgraph.h"
+
#include "transform.h"
#include "bmesh.h"
@@ -127,10 +129,10 @@
static void transform_around_single_fallback(TransInfo *t)
{
if ((t->total == 1) &&
- (ELEM(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) &&
+ (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEAN, V3D_AROUND_ACTIVE)) &&
(ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
{
- t->around = V3D_LOCAL;
+ t->around = V3D_AROUND_LOCAL_ORIGINS;
}
}
@@ -679,7 +681,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
else if ((bone->flag & BONE_TRANSFORM) &&
(mode == TFM_ROTATION || mode == TFM_TRACKBALL) &&
- (around == V3D_LOCAL))
+ (around == V3D_AROUND_LOCAL_ORIGINS))
{
bone->flag |= BONE_TRANSFORM_CHILD;
}
@@ -845,6 +847,14 @@ static void pose_grab_with_ik_clear(Object *ob)
}
}
}
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!DEG_depsgraph_use_legacy())
+#endif
+ {
+ /* TODO(sergey): Consuder doing partial update only. */
+ DAG_relations_tag_update(G.main);
+ }
}
/* adds the IK to pchan - returns if added */
@@ -995,8 +1005,16 @@ static short pose_grab_with_ik(Object *ob)
}
/* iTaSC needs clear for new IK constraints */
- if (tot_ik)
+ if (tot_ik) {
BIK_clear_data(ob->pose);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!DEG_depsgraph_use_legacy())
+#endif
+ {
+ /* TODO(sergey): Consuder doing partial update only. */
+ DAG_relations_tag_update(G.main);
+ }
+ }
return (tot_ik) ? 1 : 0;
}
@@ -1070,7 +1088,7 @@ static void createTransPose(TransInfo *t, Object *ob)
void restoreBones(TransInfo *t)
{
bArmature *arm = t->obedit->data;
- BoneInitData *bid = t->customData;
+ BoneInitData *bid = t->custom.type.data;
EditBone *ebo;
while (bid->bone) {
@@ -1159,8 +1177,8 @@ static void createTransArmatureVerts(TransInfo *t)
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransEditBone");
if (mirror) {
- t->customData = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
- t->flag |= T_FREE_CUSTOMDATA;
+ t->custom.type.data = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
+ t->custom.type.use_free = true;
}
i = 0;
@@ -1253,11 +1271,18 @@ static void createTransArmatureVerts(TransInfo *t)
if (ebo->flag & BONE_TIPSEL) {
copy_v3_v3(td->iloc, ebo->tail);
- /* don't allow single selected tips to have a modified center,
- * causes problem with snapping T45974 */
- copy_v3_v3(td->center,
- ((t->around == V3D_LOCAL) &&
- (ebo->flag & BONE_ROOTSEL)) ? ebo->head : td->iloc);
+ /* Don't allow single selected tips to have a modified center,
+ * causes problem with snapping (see T45974).
+ * However, in rotation mode, we want to keep that 'rotate bone around root with
+ * only its tip selected' behavior (see T46325). */
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL)))
+ {
+ copy_v3_v3(td->center, ebo->head);
+ }
+ else {
+ copy_v3_v3(td->center, td->iloc);
+ }
td->loc = ebo->tail;
td->flag = TD_SELECTED;
@@ -1528,7 +1553,7 @@ static void createTransCurveVerts(TransInfo *t)
TransDataCurveHandleFlags *hdata = NULL;
float axismtx[3][3];
- if (t->around == V3D_LOCAL) {
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
float normal[3], plane[3];
BKE_nurb_bezt_calc_normal(nu, bezt, normal);
@@ -1551,7 +1576,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_v3_v3(td->iloc, bezt->vec[0]);
td->loc = bezt->vec[0];
copy_v3_v3(td->center, bezt->vec[(hide_handles ||
- (t->around == V3D_LOCAL) ||
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
(bezt->f2 & SELECT)) ? 1 : 0]);
if (hide_handles) {
if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
@@ -1568,7 +1593,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_LOCAL) {
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_m3_m3(td->axismtx, axismtx);
}
@@ -1600,7 +1625,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_LOCAL) {
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_m3_m3(td->axismtx, axismtx);
}
@@ -1621,7 +1646,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_v3_v3(td->iloc, bezt->vec[2]);
td->loc = bezt->vec[2];
copy_v3_v3(td->center, bezt->vec[(hide_handles ||
- (t->around == V3D_LOCAL) ||
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
(bezt->f2 & SELECT)) ? 1 : 2]);
if (hide_handles) {
if (bezt->f2 & SELECT) td->flag = TD_SELECTED;
@@ -1640,7 +1665,7 @@ static void createTransCurveVerts(TransInfo *t)
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
- if (t->around == V3D_LOCAL) {
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_m3_m3(td->axismtx, axismtx);
}
@@ -1840,7 +1865,7 @@ static void createTransParticleVerts(bContext *C, TransInfo *t)
if (!(point->flag & PEP_TRANSFORM)) continue;
if (psys && !(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat);
for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
if (key->flag & PEK_USE_WCO) {
@@ -1914,7 +1939,7 @@ void flushTransParticles(TransInfo *t)
if (!(point->flag & PEP_TRANSFORM)) continue;
if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + i, mat);
invert_m4_m4(imat, mat);
for (k = 0, key = point->keys; k < point->totkey; k++, key++) {
@@ -2024,11 +2049,13 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) {
/* edge distance */
- BMVert *v_other = BM_edge_other_vert(e_iter, v);
- if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
- if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
- BM_elem_flag_enable(v_other, BM_ELEM_TAG);
- BLI_LINKSTACK_PUSH(queue_next, v_other);
+ {
+ BMVert *v_other = BM_edge_other_vert(e_iter, v);
+ if (bmesh_test_dist_add(v, v_other, dists, dists_prev, mtx)) {
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+ BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+ BLI_LINKSTACK_PUSH(queue_next, v_other);
+ }
}
}
@@ -2066,10 +2093,10 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
/* clear for the next loop */
for (lnk = queue_next; lnk; lnk = lnk->next) {
- BMVert *v = lnk->link;
- const int i = BM_elem_index_get(v);
+ BMVert *v_link = lnk->link;
+ const int i = BM_elem_index_get(v_link);
- BM_elem_flag_disable(v, BM_ELEM_TAG);
+ BM_elem_flag_disable(v_link, BM_ELEM_TAG);
/* keep in sync, avoid having to do full memcpy each iteration */
dists_prev[i] = dists[i];
@@ -2224,7 +2251,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
if ((t->mode == TFM_SHRINKFATTEN) &&
(em->selectmode & SCE_SELECT_FACE) &&
BM_elem_flag_test(eve, BM_ELEM_SELECT) &&
- (BM_vert_normal_update_ex(eve, BM_ELEM_SELECT, _no)))
+ (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no)))
{
no = _no;
}
@@ -2236,7 +2263,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx
copy_v3_v3(td->center, v_island->co);
copy_m3_m3(td->axismtx, v_island->axismtx);
}
- else if (t->around == V3D_LOCAL) {
+ else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_v3_v3(td->center, td->loc);
createSpaceNormal(td->axismtx, no);
}
@@ -2304,25 +2331,14 @@ static void createTransEditVerts(TransInfo *t)
mirror = 1;
}
- /* quick check if we can transform */
- /* note: in prop mode we need at least 1 selected */
- if (em->selectmode & SCE_SELECT_VERTEX) {
- if (bm->totvertsel == 0) {
- goto cleanup;
- }
- }
- else if (em->selectmode & SCE_SELECT_EDGE) {
- if (bm->totvertsel == 0 || bm->totedgesel == 0) {
- goto cleanup;
- }
- }
- else if (em->selectmode & SCE_SELECT_FACE) {
- if (bm->totvertsel == 0 || bm->totfacesel == 0) {
- goto cleanup;
- }
- }
- else {
- BLI_assert(0);
+ /**
+ * Quick check if we can transform.
+ *
+ * \note ignore modes here, even in edge/face modes, transform data is created by selected vertices.
+ * \note in prop mode we need at least 1 selected.
+ */
+ if (bm->totvertsel == 0) {
+ goto cleanup;
}
if (t->mode == TFM_BWEIGHT) {
@@ -2367,7 +2383,7 @@ static void createTransEditVerts(TransInfo *t)
editmesh_set_connectivity_distance(em->bm, mtx, dists);
}
- if (t->around == V3D_LOCAL) {
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map);
}
@@ -2735,7 +2751,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
int count = 0, countsel = 0, count_rejected = 0;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
- const bool is_island_center = (t->around == V3D_LOCAL);
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY);
@@ -3022,7 +3038,7 @@ static void createTransNlaData(bContext *C, TransInfo *t)
/* only side on which mouse is gets transformed */
float xmouse, ymouse;
- UI_view2d_region_to_view(&ac.ar->v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
+ UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
}
else {
@@ -3071,9 +3087,8 @@ static void createTransNlaData(bContext *C, TransInfo *t)
t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(NLA Editor)");
td = t->data;
- t->customData = MEM_callocN(t->total * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
- tdn = t->customData;
- t->flag |= T_FREE_CUSTOMDATA;
+ t->custom.type.data = tdn = MEM_callocN(t->total * sizeof(TransDataNla), "TransDataNla (NLA Editor)");
+ t->custom.type.use_free = true;
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -3375,9 +3390,9 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else
posttrans_fcurve_clean(ale->key_data, false); /* only use handles in graph editor */
@@ -3534,15 +3549,9 @@ typedef struct tGPFtransdata {
/* This function helps flush transdata written to tempdata into the gp-frames */
void flushTransIntFrameActionData(TransInfo *t)
{
- tGPFtransdata *tfd;
+ tGPFtransdata *tfd = t->custom.type.data;
int i;
- /* find the first one to start from */
- if (t->mode == TFM_TIME_SLIDE)
- tfd = (tGPFtransdata *)((float *)(t->customData) + 2);
- else
- tfd = (tGPFtransdata *)(t->customData);
-
/* flush data! */
for (i = 0; i < t->total; i++, tfd++) {
*(tfd->sdata) = iroundf(tfd->val);
@@ -3659,7 +3668,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* only side on which mouse is gets transformed */
float xmouse, ymouse;
- UI_view2d_region_to_view(&ac.ar->v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
+ UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
}
else {
@@ -3710,34 +3719,25 @@ static void createTransActionData(bContext *C, TransInfo *t)
td2d = t->data2d;
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- if (t->mode == TFM_TIME_SLIDE) {
- t->customData = MEM_callocN((sizeof(float) * 2) + (sizeof(tGPFtransdata) * count), "TimeSlide + tGPFtransdata");
- t->flag |= T_FREE_CUSTOMDATA;
- tfd = (tGPFtransdata *)((float *)(t->customData) + 2);
- }
- else {
- t->customData = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
- t->flag |= T_FREE_CUSTOMDATA;
- tfd = (tGPFtransdata *)(t->customData);
- }
- }
- else if (t->mode == TFM_TIME_SLIDE) {
- t->customData = MEM_callocN(sizeof(float) * 2, "TimeSlide Min/Max");
- t->flag |= T_FREE_CUSTOMDATA;
+ t->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ t->custom.type.use_free = true;
}
/* loop 2: build transdata array */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt;
if (is_prop_edit && !ale->tag)
continue;
- adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt)
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
- else
- cfra = (float)CFRA;
+ cfra = (float)CFRA;
+
+ {
+ AnimData *adt;
+ adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
+ }
+ }
if (ale->type == ANIMTYPE_GPLAYER) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
@@ -3762,31 +3762,6 @@ static void createTransActionData(bContext *C, TransInfo *t)
td = ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra, is_prop_edit, ypos);
}
}
-
- /* check if we're supposed to be setting minx/maxx for TimeSlide */
- if (t->mode == TFM_TIME_SLIDE) {
- float min = 999999999.0f, max = -999999999.0f;
- int i;
-
- td = t->data;
- for (i = 0; i < count; i++, td++) {
- if (min > *(td->val)) min = *(td->val);
- if (max < *(td->val)) max = *(td->val);
- }
-
- if (min == max) {
- /* just use the current frame ranges */
- min = (float)PSFRA;
- max = (float)PEFRA;
- }
-
- /* minx/maxx values used by TimeSlide are stored as a
- * calloced 2-float array in t->customData. This gets freed
- * in postTrans (T_FREE_CUSTOMDATA).
- */
- *((float *)(t->customData)) = min;
- *((float *)(t->customData) + 1) = max;
- }
/* calculate distances for proportional editing */
if (is_prop_edit) {
@@ -3991,7 +3966,8 @@ static bool graph_edit_is_translation_mode(TransInfo *t)
static bool graph_edit_use_local_center(TransInfo *t)
{
- return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
+ return ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (graph_edit_is_translation_mode(t) == false));
}
@@ -4058,7 +4034,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
/* only side on which mouse is gets transformed */
float xmouse, ymouse;
- UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
}
else {
@@ -4138,12 +4114,12 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
t->data = MEM_callocN(t->total * sizeof(TransData), "TransData (Graph Editor)");
/* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */
t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D (Graph Editor)");
- t->customData = MEM_callocN(t->total * sizeof(TransDataGraph), "TransDataGraph");
- t->flag |= T_FREE_CUSTOMDATA;
+ t->custom.type.data = MEM_callocN(t->total * sizeof(TransDataGraph), "TransDataGraph");
+ t->custom.type.use_free = true;
td = t->data;
td2d = t->data2d;
- tdg = t->customData;
+ tdg = t->custom.type.data;
/* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
unit_m3(mtx);
@@ -4545,7 +4521,7 @@ void flushTransGraphData(TransInfo *t)
int a;
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d, tdg = t->customData;
+ for (a = 0, td = t->data, td2d = t->data2d, tdg = t->custom.type.data;
a < t->total;
a++, td++, td2d++, tdg++)
{
@@ -4555,7 +4531,7 @@ void flushTransGraphData(TransInfo *t)
/* handle snapping for time values
* - we should still be in NLA-mapping timespace
* - only apply to keyframes (but never to handles)
- * - don't do this when cancelling, or else these changes won't go away
+ * - don't do this when canceling, or else these changes won't go away
*/
if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
switch (sipo->autosnap) {
@@ -4585,7 +4561,7 @@ void flushTransGraphData(TransInfo *t)
*
* NOTE: We also have to apply to td->loc, as that's what the handle-adjustment step below looks
* to, otherwise we get "swimming handles"
- * NOTE: We don't do this when cancelling transforms, or else these changes don't go away
+ * NOTE: We don't do this when canceling transforms, or else these changes don't go away
*/
if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0 &&
ELEM(sipo->autosnap, SACTSNAP_STEP, SACTSNAP_TSTEP))
@@ -4908,7 +4884,7 @@ static void SeqTransDataBounds(TransInfo *t, ListBase *seqbase, TransSeq *ts)
}
-static void freeSeqData(TransInfo *t)
+static void freeSeqData(TransInfo *t, TransCustomData *custom_data)
{
Editing *ed = BKE_sequencer_editing_get(t->scene, false);
@@ -5069,11 +5045,11 @@ static void freeSeqData(TransInfo *t)
}
}
- if ((t->customData != NULL) && (t->flag & T_FREE_CUSTOMDATA)) {
- TransSeq *ts = t->customData;
+ if ((custom_data->data != NULL) && custom_data->use_free) {
+ TransSeq *ts = custom_data->data;
MEM_freeN(ts->tdseq);
- MEM_freeN(t->customData);
- t->customData = NULL;
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
}
if (t->data) {
MEM_freeN(t->data); // XXX postTrans usually does this
@@ -5101,9 +5077,9 @@ static void createTransSeqData(bContext *C, TransInfo *t)
return;
}
- t->customFree = freeSeqData;
+ t->custom.type.free_cb = freeSeqData;
- xmouse = (int)UI_view2d_region_to_view_x(v2d, t->imval[0]);
+ xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
@@ -5147,11 +5123,11 @@ static void createTransSeqData(bContext *C, TransInfo *t)
return;
}
- t->customData = ts = MEM_mallocN(sizeof(TransSeq), "transseq");
+ t->custom.type.data = ts = MEM_callocN(sizeof(TransSeq), "transseq");
+ t->custom.type.use_free = true;
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransSeq TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransSeq TransData2D");
ts->tdseq = tdsq = MEM_callocN(t->total * sizeof(TransDataSeq), "TransSeq TransDataSeq");
- t->flag |= T_FREE_CUSTOMDATA;
/* loop 2: build transdata array */
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
@@ -5408,7 +5384,9 @@ static void set_trans_object_base_flags(TransInfo *t)
if (parsel) {
/* rotation around local centers are allowed to propagate */
- if ((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) && t->around == V3D_LOCAL) {
+ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))
+ {
base->flag |= BA_TRANSFORM_CHILD;
}
else {
@@ -5458,7 +5436,9 @@ static int count_proportional_objects(TransInfo *t)
Base *base;
/* rotations around local centers are allowed to propagate, so we take all objects */
- if (!((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) && t->around == V3D_LOCAL)) {
+ if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)))
+ {
/* mark all parents */
for (base = scene->base.first; base; base = base->next) {
if (TESTBASELIB_BGMODE(v3d, scene, base)) {
@@ -5541,6 +5521,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
// TODO: this should probably be done per channel instead...
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase dsources = {NULL, NULL};
float cfra = (float)CFRA; // xxx this will do for now
@@ -5554,7 +5535,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
/* only insert into active keyingset
- * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden spe
+ * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden
*/
ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
}
@@ -5567,7 +5548,8 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
fcu->flag &= ~FCURVE_SELECTED;
insert_keyframe(reports, id, adt->action,
(fcu->grp ? fcu->grp->name : NULL),
- fcu->rna_path, fcu->array_index, cfra, flag);
+ fcu->rna_path, fcu->array_index, cfra,
+ ts->keyframe_type, flag);
}
}
}
@@ -5579,22 +5561,22 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
do_loc = true;
}
else if (tmode == TFM_ROTATION) {
- if (v3d->around == V3D_ACTIVE) {
+ if (v3d->around == V3D_AROUND_ACTIVE) {
if (ob != OBACT)
do_loc = true;
}
- else if (v3d->around == V3D_CURSOR)
+ else if (v3d->around == V3D_AROUND_CURSOR)
do_loc = true;
if ((v3d->flag & V3D_ALIGN) == 0)
do_rot = true;
}
else if (tmode == TFM_RESIZE) {
- if (v3d->around == V3D_ACTIVE) {
+ if (v3d->around == V3D_AROUND_ACTIVE) {
if (ob != OBACT)
do_loc = true;
}
- else if (v3d->around == V3D_CURSOR)
+ else if (v3d->around == V3D_AROUND_CURSOR)
do_loc = true;
if ((v3d->flag & V3D_ALIGN) == 0)
@@ -5659,6 +5641,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
// TODO: this should probably be done per channel instead...
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
float cfra = (float)CFRA;
short flag = 0;
@@ -5699,9 +5682,13 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
/* only if bone name matches too...
* NOTE: this will do constraints too, but those are ok to do here too?
*/
- if (pchanName && STREQ(pchanName, pchan->name))
- insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
-
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ insert_keyframe(reports, id, act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, fcu->array_index, cfra,
+ ts->keyframe_type, flag);
+ }
+
if (pchanName) MEM_freeN(pchanName);
}
}
@@ -5719,14 +5706,14 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
do_loc = true;
}
else if (tmode == TFM_ROTATION) {
- if (ELEM(v3d->around, V3D_CURSOR, V3D_ACTIVE))
+ if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
do_loc = true;
if ((v3d->flag & V3D_ALIGN) == 0)
do_rot = true;
}
else if (tmode == TFM_RESIZE) {
- if (ELEM(v3d->around, V3D_CURSOR, V3D_ACTIVE))
+ if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
do_loc = true;
if ((v3d->flag & V3D_ALIGN) == 0)
@@ -5907,6 +5894,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
}
EDBM_automerge(t->scene, t->obedit, true, hflag);
+
+ if ((em->selectmode & SCE_SELECT_VERTEX) == 0) {
+ EDBM_select_flush(em);
+ }
}
}
@@ -5928,10 +5919,13 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->obedit) {
+ /* Special Exception:
+ * We don't normally access 't->custom.mode' here, but its needed in this case. */
+
if (canceled == 0) {
/* we need to delete the temporary faces before automerging */
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = t->custom.mode.data;
/* handle multires re-projection, done
* on transform completion since it's
@@ -5944,7 +5938,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
else if (t->mode == TFM_VERT_SLIDE) {
/* as above */
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
projectVertSlideData(t, true);
freeVertSlideTempFaces(sld);
}
@@ -5955,13 +5949,13 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
else {
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideData *sld = t->customData;
+ EdgeSlideData *sld = t->custom.mode.data;
sld->perc = 0.0;
projectEdgeSlideData(t, false);
}
else if (t->mode == TFM_VERT_SLIDE) {
- VertSlideData *sld = t->customData;
+ VertSlideData *sld = t->custom.mode.data;
sld->perc = 0.0;
projectVertSlideData(t, false);
@@ -6052,9 +6046,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
((canceled == 0) || (duplicate)) )
{
if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 1);
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
}
else
posttrans_fcurve_clean(fcu, false); /* only use handles in graph editor */
@@ -6241,7 +6235,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if (t->obedit->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
/* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(t->obedit, em, NULL, 'e');
+ ED_mesh_mirror_spatial_table(t->obedit, em, NULL, NULL, 'e');
}
}
else if ((t->flag & T_POSE) && (t->poseobj)) {
@@ -6352,12 +6346,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
clear_trans_object_base_flags(t);
-
-
-#if 0 // TRANSFORM_FIX_ME
- if (resetslowpar)
- reset_slowparents();
-#endif
}
int special_transform_moving(TransInfo *t)
@@ -6727,16 +6715,15 @@ static void planeTrackToTransData(const int framenr, TransData *td, TransData2D
}
}
-static void transDataTrackingFree(TransInfo *t)
+static void transDataTrackingFree(TransInfo *UNUSED(t), TransCustomData *custom_data)
{
- TransDataTracking *tdt = t->customData;
-
- if (tdt) {
+ if (custom_data->data) {
+ TransDataTracking *tdt = custom_data->data;
if (tdt->smarkers)
MEM_freeN(tdt->smarkers);
MEM_freeN(tdt);
- t->customData = NULL;
+ custom_data->data = NULL;
}
}
@@ -6788,9 +6775,9 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
- tdt = t->customData = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
+ tdt = t->custom.type.data = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
- t->customFree = transDataTrackingFree;
+ t->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
@@ -6925,9 +6912,8 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransTracking TransData");
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransTracking TransData2D");
- tdt = t->customData = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
-
- t->customFree = transDataTrackingFree;
+ t->custom.type.data = tdt = MEM_callocN(t->total * sizeof(TransDataTracking), "TransTracking TransDataTracking");
+ t->custom.type.free_cb = transDataTrackingFree;
/* create actual data */
track = tracksbase->first;
@@ -6991,10 +6977,11 @@ static void cancelTransTracking(TransInfo *t)
{
SpaceClip *sc = t->sa->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
+ TransDataTracking *tdt_array = t->custom.type.data;
i = 0;
while (i < t->total) {
- TransDataTracking *tdt = (TransDataTracking *) t->customData + i;
+ TransDataTracking *tdt = &tdt_array[i];
if (tdt->mode == transDataTracking_ModeTracks) {
MovieTrackingTrack *track = tdt->track;
@@ -7051,7 +7038,7 @@ void flushTransTracking(TransInfo *t)
cancelTransTracking(t);
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d, tdt = t->customData; a < t->total; a++, td2d++, td++, tdt++) {
+ for (a = 0, td = t->data, td2d = t->data2d, tdt = t->custom.type.data; a < t->total; a++, td2d++, td++, tdt++) {
if (tdt->mode == transDataTracking_ModeTracks) {
float loc2d[2];
@@ -7382,9 +7369,8 @@ static void createTransMaskingData(bContext *C, TransInfo *t)
/* for each 2d uv coord a 3d vector is allocated, so that they can be
* treated just as if they were 3d verts */
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransObData2D(Mask Editing)");
- tdm = t->customData = MEM_callocN(t->total * sizeof(TransDataMasking), "TransDataMasking(Mask Editing)");
-
- t->flag |= T_FREE_CUSTOMDATA;
+ t->custom.type.data = tdm = MEM_callocN(t->total * sizeof(TransDataMasking), "TransDataMasking(Mask Editing)");
+ t->custom.type.use_free = true;
/* create data */
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
@@ -7446,7 +7432,7 @@ void flushTransMasking(TransInfo *t)
inv[1] = 1.0f / asp[1];
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data2d, tdm = t->customData; a < t->total; a++, td++, tdm++) {
+ for (a = 0, td = t->data2d, tdm = t->custom.type.data; a < t->total; a++, td++, tdm++) {
td->loc2d[0] = td->loc[0] * inv[0];
td->loc2d[1] = td->loc[1] * inv[1];
mul_m3_v2(tdm->parent_inverse_matrix, td->loc2d);
@@ -7594,8 +7580,8 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
t->total = total;
td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D");
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData");
- tdpc = t->customData = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
- t->flag |= T_FREE_CUSTOMDATA;
+ t->custom.type.data = tdpc = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
+ t->custom.type.use_free = true;
for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
if (PC_IS_ANY_SEL(pcp)) {
@@ -7627,7 +7613,7 @@ void flushTransPaintCurve(TransInfo *t)
{
int i;
TransData2D *td2d = t->data2d;
- TransDataPaintCurve *tdpc = (TransDataPaintCurve *)t->customData;
+ TransDataPaintCurve *tdpc = t->custom.type.data;
for (i = 0; i < t->total; i++, tdpc++, td2d++) {
PaintCurvePoint *pcp = tdpc->pcp;
@@ -7666,9 +7652,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
*/
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
- if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
- (gpl->actframe != NULL))
- {
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
@@ -7722,9 +7706,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
/* Second Pass: Build transdata array */
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
- if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
- (gpl->actframe != NULL))
- {
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
@@ -7734,45 +7716,7 @@ static void createTransGPencil(bContext *C, TransInfo *t)
*/
// XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
- bGPDframe *new_frame = gpencil_frame_duplicate(gpf);
- bGPDframe *gf;
- bool found = false;
-
- /* Find frame to insert it before */
- for (gf = gpf->next; gf; gf = gf->next) {
- if (gf->framenum > cfra) {
- /* Add it here */
- BLI_insertlinkbefore(&gpl->frames, gf, new_frame);
-
- found = true;
- break;
- }
- else if (gf->framenum == cfra) {
- /* This only happens when we're editing with framelock on...
- * - Delete the new frame and don't do anything else here...
- */
- //printf("GP Frame convert to TransData - Copy aborted for frame %d -> %d\n", gpf->framenum, gf->framenum);
- free_gpencil_strokes(new_frame);
- MEM_freeN(new_frame);
- new_frame = NULL;
-
- found = true;
- break;
- }
- }
-
- if (found == false) {
- /* Add new frame to the end */
- BLI_addtail(&gpl->frames, new_frame);
- }
-
- /* Edit the new frame instead, if it did get created + added */
- if (new_frame) {
- // TODO: tag this one as being "newly created" so that we can remove it if the edit is cancelled
- new_frame->framenum = cfra;
-
- gpf = new_frame;
- }
+ gpf = gpencil_frame_addcopy(gpl, cfra);
}
/* Loop over strokes, adding TransData for points as needed... */
@@ -7849,15 +7793,26 @@ static void createTransGPencil(bContext *C, TransInfo *t)
td->ival = pt->pressure;
}
- /* configure 2D points so that they don't play up... */
- if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ /* screenspace needs special matrices... */
+ if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) {
+ /* screenspace */
td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
- // XXX: matrices may need to be different?
+
+ copy_m3_m4(td->smtx, t->persmat);
+ copy_m3_m4(td->mtx, t->persinv);
+ unit_m3(td->axismtx);
+ }
+ else {
+ /* configure 2D dataspace points so that they don't play up... */
+ if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
+ td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
+ // XXX: matrices may need to be different?
+ }
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ unit_m3(td->axismtx); // XXX?
}
-
- copy_m3_m3(td->smtx, smtx);
- copy_m3_m3(td->mtx, mtx);
- unit_m3(td->axismtx); // XXX?
td++;
tail++;
@@ -7897,7 +7852,8 @@ void createTransData(bContext *C, TransInfo *t)
}
}
else if (t->options & CTX_GPENCIL_STROKES) {
- t->flag |= T_POINTS; // XXX...
+ t->options |= CTX_GPENCIL_STROKES;
+ t->flag |= T_POINTS;
createTransGPencil(C, t);
if (t->data && (t->flag & T_PROP_EDIT)) {
@@ -8086,8 +8042,4 @@ void createTransData(bContext *C, TransInfo *t)
}
}
}
-
-// TRANSFORM_FIX_ME
-// /* temporal...? */
-// t->scene->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index dc541c6da42..eb6308d1c41 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -39,6 +39,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
@@ -73,6 +74,7 @@
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_paint.h"
@@ -278,7 +280,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
NlaStrip *strip = add_nlastrip_to_stack(adt, adt->action);
/* clear reference to action now that we've pushed it onto the stack */
- adt->action->id.us--;
+ id_us_min(&adt->action->id);
adt->action = NULL;
/* adjust blending + extend so that they will behave correctly */
@@ -420,7 +422,7 @@ static void recalcData_graphedit(TransInfo *t)
/* helper for recalcData() - for NLA Editor transforms */
static void recalcData_nla(TransInfo *t)
{
- TransDataNla *tdn = (TransDataNla *)t->customData;
+ TransDataNla *tdn = t->custom.type.data;
SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
Scene *scene = t->scene;
double secf = FPS;
@@ -950,7 +952,13 @@ static void recalcData_sequencer(TransInfo *t)
Sequence *seq = tdsq->seq;
if (seq != seq_prev) {
- BKE_sequence_invalidate_dependent(t->scene, seq);
+ if (BKE_sequence_tx_fullupdate_test(seq)) {
+ /* A few effect strip types need a complete recache on transform. */
+ BKE_sequence_invalidate_cache(t->scene, seq);
+ }
+ else {
+ BKE_sequence_invalidate_dependent(t->scene, seq);
+ }
}
seq_prev = seq;
@@ -1032,7 +1040,7 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
glColor3ubv(col2);
setlinestyle(0);
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex3fv(v1);
glVertex3fv(v2);
glEnd();
@@ -1047,10 +1055,10 @@ void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis
void resetTransModal(TransInfo *t)
{
if (t->mode == TFM_EDGE_SLIDE) {
- freeEdgeSlideVerts(t);
+ freeEdgeSlideVerts(t, &t->custom.mode);
}
else if (t->mode == TFM_VERT_SLIDE) {
- freeVertSlideVerts(t);
+ freeVertSlideVerts(t, &t->custom.mode);
}
}
@@ -1088,6 +1096,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
ScrArea *sa = CTX_wm_area(C);
Object *obedit = CTX_data_edit_object(C);
Object *ob = CTX_data_active_object(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
PropertyRNA *prop;
t->scene = sce;
@@ -1112,19 +1121,19 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->redraw = TREDRAW_HARD; /* redraw first time */
if (event) {
- copy_v2_v2_int(t->imval, event->mval);
- t->event_type = event->type;
+ t->mouse.imval[0] = event->mval[0];
+ t->mouse.imval[1] = event->mval[1];
}
else {
- t->imval[0] = 0;
- t->imval[1] = 0;
+ t->mouse.imval[0] = 0;
+ t->mouse.imval[1] = 0;
}
- t->con.imval[0] = t->imval[0];
- t->con.imval[1] = t->imval[1];
+ t->con.imval[0] = t->mouse.imval[0];
+ t->con.imval[1] = t->mouse.imval[1];
- t->mval[0] = t->imval[0];
- t->mval[1] = t->imval[1];
+ t->mval[0] = t->mouse.imval[0];
+ t->mval[1] = t->mouse.imval[1];
t->transform = NULL;
t->handleEvent = NULL;
@@ -1156,6 +1165,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->remove_on_cancel = true;
}
}
+
+ /* GPencil editing context */
+ if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
+ t->options |= CTX_GPENCIL_STROKES;
+ }
/* Assign the space type, some exceptions for running in different mode */
if (sa == NULL) {
@@ -1204,13 +1218,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* bend always uses the cursor */
if (t->mode == TFM_BEND) {
- t->around = V3D_CURSOR;
+ t->around = V3D_AROUND_CURSOR;
}
t->current_orientation = v3d->twmode;
/* exceptional case */
- if (t->around == V3D_LOCAL) {
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
const bool use_island = transdata_check_local_islands(t, t->around);
@@ -1266,7 +1280,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else if (t->spacetype == SPACE_NODE) {
// XXX for now, get View2D from the active region
t->view = &ar->v2d;
- t->around = V3D_CENTER;
+ t->around = V3D_AROUND_CENTER_BOUNDS;
}
else if (t->spacetype == SPACE_IPO) {
SpaceIpo *sipo = sa->spacedata.first;
@@ -1292,7 +1306,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else {
t->view = NULL;
}
- t->around = V3D_CENTER;
+ t->around = V3D_AROUND_CENTER_BOUNDS;
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
@@ -1407,8 +1421,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
#endif
- setTransformViewMatrices(t);
setTransformViewAspect(t, t->aspect);
+ setTransformViewMatrices(t);
initNumInput(&t->num);
}
@@ -1426,14 +1440,20 @@ void postTrans(bContext *C, TransInfo *t)
if (t->draw_handle_cursor)
WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
- if (t->customFree) {
- /* Can take over freeing t->data and data2d etc... */
- t->customFree(t);
- BLI_assert(t->customData == NULL);
- }
- else if ((t->customData != NULL) && (t->flag & T_FREE_CUSTOMDATA)) {
- MEM_freeN(t->customData);
- t->customData = NULL;
+ /* Free all custom-data */
+ {
+ TransCustomData *custom_data = &t->custom.first_elem;
+ for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
+ if (custom_data->free_cb) {
+ /* Can take over freeing t->data and data2d etc... */
+ custom_data->free_cb(t, custom_data);
+ BLI_assert(custom_data->data == NULL);
+ }
+ else if ((custom_data->data != NULL) && custom_data->use_free) {
+ MEM_freeN(custom_data->data);
+ custom_data->data = NULL;
+ }
+ }
}
/* postTrans can be called when nothing is selected, so data is NULL already */
@@ -1562,6 +1582,8 @@ void restoreTransObjects(TransInfo *t)
void calculateCenter2D(TransInfo *t)
{
+ BLI_assert(!is_zero_v3(t->aspect));
+
if (t->flag & (T_EDIT | T_POSE)) {
Object *ob = t->obedit ? t->obedit : t->poseobj;
float vec[3];
@@ -1665,8 +1687,14 @@ void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
Scene *scene = t->scene;
/* cursor is combination of current frame, and graph-editor cursor value */
- r_center[0] = (float)(scene->r.cfra);
- r_center[1] = sipo->cursorVal;
+ if (sipo->mode == SIPO_MODE_DRIVERS) {
+ r_center[0] = sipo->cursorTime;
+ r_center[1] = sipo->cursorVal;
+ }
+ else {
+ r_center[0] = (float)(scene->r.cfra);
+ r_center[1] = sipo->cursorVal;
+ }
}
void calculateCenterMedian(TransInfo *t, float r_center[3])
@@ -1757,13 +1785,13 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
void calculateCenter(TransInfo *t)
{
switch (t->around) {
- case V3D_CENTER:
+ case V3D_AROUND_CENTER_BOUNDS:
calculateCenterBound(t, t->center);
break;
- case V3D_CENTROID:
+ case V3D_AROUND_CENTER_MEAN:
calculateCenterMedian(t, t->center);
break;
- case V3D_CURSOR:
+ case V3D_AROUND_CURSOR:
if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
calculateCenterCursor2D(t, t->center);
else if (t->spacetype == SPACE_IPO)
@@ -1771,11 +1799,11 @@ void calculateCenter(TransInfo *t)
else
calculateCenterCursor(t, t->center);
break;
- case V3D_LOCAL:
+ case V3D_AROUND_LOCAL_ORIGINS:
/* Individual element center uses median center for helpline and such */
calculateCenterMedian(t, t->center);
break;
- case V3D_ACTIVE:
+ case V3D_AROUND_ACTIVE:
{
if (calculateCenterActive(t, false, t->center)) {
/* pass */
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 61b2deabe12..9b7d19eacd5 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -41,99 +41,60 @@
/* ************************** INPUT FROM MOUSE *************************** */
-static void InputVector(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputVector(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
- float vec[3], dvec[3];
- if (mi->precision) {
- /* calculate the main translation and the precise one separate */
- convertViewVec(t, dvec, (mval[0] - mi->precision_mval[0]), (mval[1] - mi->precision_mval[1]));
- mul_v3_fl(dvec, 0.1f);
- convertViewVec(t, vec, (mi->precision_mval[0] - t->imval[0]), (mi->precision_mval[1] - t->imval[1]));
- add_v3_v3v3(output, vec, dvec);
- }
- else {
- convertViewVec(t, output, (mval[0] - t->imval[0]), (mval[1] - t->imval[1]));
- }
-
+ convertViewVec(t, output, mval[0] - mi->imval[0], mval[1] - mi->imval[1]);
}
-static void InputSpring(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], float output[3])
+static void InputSpring(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3])
{
- float ratio, precise_ratio, dx, dy;
- if (mi->precision) {
- /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
- dx = (float)(mi->center[0] - mi->precision_mval[0]);
- dy = (float)(mi->center[1] - mi->precision_mval[1]);
- ratio = hypotf(dx, dy);
-
- dx = (float)(mi->center[0] - mval[0]);
- dy = (float)(mi->center[1] - mval[1]);
- precise_ratio = hypotf(dx, dy);
-
- ratio = (ratio + (precise_ratio - ratio) / 10.0f) / mi->factor;
- }
- else {
- dx = (float)(mi->center[0] - mval[0]);
- dy = (float)(mi->center[1] - mval[1]);
- ratio = hypotf(dx, dy) / mi->factor;
- }
+ double dx, dy;
+ float ratio;
+
+ dx = ((double)mi->center[0] - mval[0]);
+ dy = ((double)mi->center[1] - mval[1]);
+ ratio = hypot(dx, dy) / (double)mi->factor;
output[0] = ratio;
}
-static void InputSpringFlip(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
InputSpring(t, mi, mval, output);
/* flip scale */
/* values can become really big when zoomed in so use longs [#26598] */
- if ((long long int)(mi->center[0] - mval[0]) * (long long int)(mi->center[0] - mi->imval[0]) +
- (long long int)(mi->center[1] - mval[1]) * (long long int)(mi->center[1] - mi->imval[1]) < 0)
+ if ((int64_t)((int)mi->center[0] - mval[0]) * (int64_t)((int)mi->center[0] - mi->imval[0]) +
+ (int64_t)((int)mi->center[1] - mval[1]) * (int64_t)((int)mi->center[1] - mi->imval[1]) < 0)
{
output[0] *= -1.0f;
}
}
-static void InputSpringDelta(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputSpringDelta(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
InputSpring(t, mi, mval, output);
output[0] -= 1.0f;
}
-static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], float output[3])
+static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3])
{
-
- if (mi->precision) {
- output[0] = (mi->imval[1] - mi->precision_mval[1]) + (mi->precision_mval[1] - mval[1]) * 0.1f;
- output[1] = (mi->precision_mval[0] - mi->imval[0]) + (mval[0] - mi->precision_mval[0]) * 0.1f;
- }
- else {
- output[0] = (float)(mi->imval[1] - mval[1]);
- output[1] = (float)(mval[0] - mi->imval[0]);
- }
+ output[0] = (float)(mi->imval[1] - mval[1]);
+ output[1] = (float)(mval[0] - mi->imval[0]);
output[0] *= mi->factor;
output[1] *= mi->factor;
}
-static void InputHorizontalRatio(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputHorizontalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3])
{
- float x, pad;
+ const int winx = t->ar ? t->ar->winx : 1;
+ const double pad = winx / 10;
- pad = t->ar->winx / 10;
-
- if (mi->precision) {
- /* deal with Shift key by adding motion / 10 to motion before shift press */
- x = mi->precision_mval[0] + (float)(mval[0] - mi->precision_mval[0]) / 10.0f;
- }
- else {
- x = mval[0];
- }
-
- output[0] = (x - pad) / (t->ar->winx - 2 * pad);
+ output[0] = (mval[0] - pad) / (winx - 2 * pad);
}
-static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
float vec[3];
@@ -143,24 +104,15 @@ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const int mval
output[0] = dot_v3v3(t->viewinv[0], vec) * 2.0f;
}
-static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputVerticalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3])
{
- float y, pad;
-
- pad = t->ar->winy / 10;
+ const int winy = t->ar ? t->ar->winy : 1;
+ const double pad = winy / 10;
- if (mi->precision) {
- /* deal with Shift key by adding motion / 10 to motion before shift press */
- y = mi->precision_mval[1] + (float)(mval[1] - mi->precision_mval[1]) / 10.0f;
- }
- else {
- y = mval[0];
- }
-
- output[0] = (y - pad) / (t->ar->winy - 2 * pad);
+ output[0] = (mval[1] - pad) / (winy - 2 * pad);
}
-static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputVerticalAbsolute(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
float vec[3];
@@ -184,7 +136,7 @@ void setCustomPoints(TransInfo *UNUSED(t), MouseInput *mi, const int mval_start[
data[3] = mval_end[1];
}
-static void InputCustomRatioFlip(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], float output[3])
+static void InputCustomRatioFlip(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3])
{
double length;
double distance;
@@ -192,51 +144,45 @@ static void InputCustomRatioFlip(TransInfo *UNUSED(t), MouseInput *mi, const int
const int *data = mi->data;
if (data) {
+ int mdx, mdy;
dx = data[2] - data[0];
dy = data[3] - data[1];
-
+
length = hypot(dx, dy);
-
- if (mi->precision) {
- /* deal with Shift key by adding motion / 10 to motion before shift press */
- int mdx, mdy;
- mdx = (mi->precision_mval[0] + (float)(mval[0] - mi->precision_mval[0]) / 10.0f) - data[2];
- mdy = (mi->precision_mval[1] + (float)(mval[1] - mi->precision_mval[1]) / 10.0f) - data[3];
- distance = (length != 0.0) ? (mdx * dx + mdy * dy) / length : 0.0;
- }
- else {
- int mdx, mdy;
- mdx = mval[0] - data[2];
- mdy = mval[1] - data[3];
+ mdx = mval[0] - data[2];
+ mdy = mval[1] - data[3];
- distance = (length != 0.0) ? (mdx * dx + mdy * dy) / length : 0.0;
- }
+ distance = (length != 0.0) ? (mdx * dx + mdy * dy) / length : 0.0;
output[0] = (length != 0.0) ? (double)(distance / length) : 0.0;
}
}
-static void InputCustomRatio(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputCustomRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
InputCustomRatioFlip(t, mi, mval, output);
output[0] = -output[0];
}
-static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], float output[3])
+struct InputAngle_Data {
+ double angle;
+ double mval_prev[2];
+};
+
+static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3])
{
- double dx2 = mval[0] - mi->center[0];
- double dy2 = mval[1] - mi->center[1];
+ struct InputAngle_Data *data = mi->data;
+ double dx2 = mval[0] - (double)mi->center[0];
+ double dy2 = mval[1] - (double)mi->center[1];
double B = sqrt(dx2 * dx2 + dy2 * dy2);
- double dx1 = mi->imval[0] - mi->center[0];
- double dy1 = mi->imval[1] - mi->center[1];
+ double dx1 = data->mval_prev[0] - (double)mi->center[0];
+ double dy1 = data->mval_prev[1] - (double)mi->center[1];
double A = sqrt(dx1 * dx1 + dy1 * dy1);
- double dx3 = mval[0] - mi->imval[0];
- double dy3 = mval[1] - mi->imval[1];
-
- double *angle = mi->data;
+ double dx3 = mval[0] - data->mval_prev[0];
+ double dy3 = mval[1] - data->mval_prev[1];
/* use doubles here, to make sure a "1.0" (no rotation) doesn't become 9.999999e-01, which gives 0.02 for acos */
double deler = (((dx1 * dx1 + dy1 * dy1) +
@@ -270,22 +216,15 @@ static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2],
if ((dx1 * dy2 - dx2 * dy1) > 0.0) dphi = -dphi;
}
- if (mi->precision) {
- dphi = dphi / 30.0f;
- }
+ data->angle += ((double)dphi) * (mi->precision ? (double)mi->precision_factor : 1.0);
- /* if no delta angle, don't update initial position */
- if (dphi != 0) {
- mi->imval[0] = mval[0];
- mi->imval[1] = mval[1];
- }
-
- *angle += (double)dphi;
+ data->mval_prev[0] = mval[0];
+ data->mval_prev[1] = mval[1];
- output[0] = *angle;
+ output[0] = data->angle;
}
-static void InputAngleSpring(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
float toutput[3];
@@ -324,6 +263,9 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
/* incase we allocate a new value */
void *mi_data_prev = mi->data;
+ mi->use_virtual_mval = true;
+ mi->precision_factor = 1.0f / 10.0f;
+
switch (mode) {
case INPUT_VECTOR:
mi->apply = InputVector;
@@ -345,17 +287,27 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
t->helpline = HLP_SPRING;
break;
case INPUT_ANGLE:
- mi->data = MEM_callocN(sizeof(double), "angle accumulator");
- mi->apply = InputAngle;
- t->helpline = HLP_ANGLE;
- break;
case INPUT_ANGLE_SPRING:
- calcSpringFactor(mi);
- mi->data = MEM_callocN(sizeof(double), "angle accumulator");
- mi->apply = InputAngleSpring;
+ {
+ struct InputAngle_Data *data;
+ mi->use_virtual_mval = false;
+ mi->precision_factor = 1.0f / 30.0f;
+ data = MEM_callocN(sizeof(struct InputAngle_Data), "angle accumulator");
+ data->mval_prev[0] = mi->imval[0];
+ data->mval_prev[1] = mi->imval[1];
+ mi->data = data;
+ if (mode == INPUT_ANGLE) {
+ mi->apply = InputAngle;
+ }
+ else {
+ calcSpringFactor(mi);
+ mi->apply = InputAngleSpring;
+ }
t->helpline = HLP_ANGLE;
break;
+ }
case INPUT_TRACKBALL:
+ mi->precision_factor = 1.0f / 30.0f;
/* factor has to become setting or so */
mi->factor = 0.01f;
mi->apply = InputTrackBall;
@@ -409,8 +361,37 @@ void setInputPostFct(MouseInput *mi, void (*post)(struct TransInfo *t, float val
void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
{
+ double mval_db[2];
+
+ if (mi->use_virtual_mval) {
+ /* update accumulator */
+ double mval_delta[2];
+
+ mval_delta[0] = (mval[0] - mi->imval[0]) - mi->virtual_mval.prev[0];
+ mval_delta[1] = (mval[1] - mi->imval[1]) - mi->virtual_mval.prev[1];
+
+ mi->virtual_mval.prev[0] += mval_delta[0];
+ mi->virtual_mval.prev[1] += mval_delta[1];
+
+ if (mi->precision) {
+ mval_delta[0] *= (double)mi->precision_factor;
+ mval_delta[1] *= (double)mi->precision_factor;
+ }
+
+ mi->virtual_mval.accum[0] += mval_delta[0];
+ mi->virtual_mval.accum[1] += mval_delta[1];
+
+ mval_db[0] = mi->imval[0] + mi->virtual_mval.accum[0];
+ mval_db[1] = mi->imval[1] + mi->virtual_mval.accum[1];
+ }
+ else {
+ mval_db[0] = mval[0];
+ mval_db[1] = mval[1];
+ }
+
+
if (mi->apply != NULL) {
- mi->apply(t, mi, mval, output);
+ mi->apply(t, mi, mval_db, output);
}
if (mi->post) {
@@ -427,9 +408,7 @@ eRedrawFlag handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event)
case RIGHTSHIFTKEY:
if (event->val == KM_PRESS) {
t->modifiers |= MOD_PRECISION;
- /* shift is modifier for higher precision transform
- * store the mouse position where the normal movement ended */
- copy_v2_v2_int(mi->precision_mval, event->mval);
+ /* shift is modifier for higher precision transforn */
mi->precision = 1;
redraw = TREDRAW_HARD;
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index f13bc6b6b55..992fde0cce3 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -37,12 +37,14 @@
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -272,6 +274,8 @@ static int calc_manipulator_stats(const bContext *C)
RegionView3D *rv3d = ar->regiondata;
Base *base;
Object *ob = OBACT;
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
int a, totsel = 0;
/* transform widget matrix */
@@ -282,8 +286,32 @@ static int calc_manipulator_stats(const bContext *C)
/* transform widget centroid/center */
INIT_MINMAX(scene->twmin, scene->twmax);
zero_v3(scene->twcent);
-
- if (obedit) {
+
+ if (is_gp_edit) {
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ /* we're only interested in selected points here... */
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+
+ /* Change selection status of all points, then make the stroke match */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ calc_tw_center(scene, &pt->x);
+ totsel++;
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* selection center */
+ if (totsel) {
+ mul_v3_fl(scene->twcent, 1.0f / (float)totsel); /* centroid! */
+ }
+ }
+ else if (obedit) {
ob = obedit;
if ((ob->lay & v3d->lay) == 0) return 0;
@@ -293,7 +321,7 @@ static int calc_manipulator_stats(const bContext *C)
float vec[3] = {0, 0, 0};
/* USE LAST SELECTE WITH ACTIVE */
- if ((v3d->around == V3D_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
+ if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
BM_editselection_center(&ese, vec);
calc_tw_center(scene, vec);
totsel = 1;
@@ -318,7 +346,7 @@ static int calc_manipulator_stats(const bContext *C)
bArmature *arm = obedit->data;
EditBone *ebo;
- if ((v3d->around == V3D_ACTIVE) && (ebo = arm->act_edbone)) {
+ if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
/* doesn't check selection or visibility intentionally */
if (ebo->flag & BONE_TIPSEL) {
calc_tw_center(scene, ebo->tail);
@@ -339,7 +367,13 @@ static int calc_manipulator_stats(const bContext *C)
calc_tw_center(scene, ebo->tail);
totsel++;
}
- if (ebo->flag & BONE_ROOTSEL) {
+ if ((ebo->flag & BONE_ROOTSEL) &&
+ /* don't include same point multiple times */
+ ((ebo->flag & BONE_CONNECTED) &&
+ (ebo->parent != NULL) &&
+ (ebo->parent->flag & BONE_TIPSEL) &&
+ EBONE_VISIBLE(arm, ebo->parent)) == 0)
+ {
calc_tw_center(scene, ebo->head);
totsel++;
}
@@ -354,7 +388,7 @@ static int calc_manipulator_stats(const bContext *C)
Curve *cu = obedit->data;
float center[3];
- if (v3d->around == V3D_ACTIVE && ED_curve_active_center(cu, center)) {
+ if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
calc_tw_center(scene, center);
totsel++;
}
@@ -386,11 +420,11 @@ static int calc_manipulator_stats(const bContext *C)
}
else {
if (bezt->f1 & SELECT) {
- calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 0]);
+ calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
totsel++;
}
if (bezt->f3 & SELECT) {
- calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 2]);
+ calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
totsel++;
}
}
@@ -416,7 +450,7 @@ static int calc_manipulator_stats(const bContext *C)
MetaBall *mb = (MetaBall *)obedit->data;
MetaElem *ml;
- if ((v3d->around == V3D_ACTIVE) && (ml = mb->lastelem)) {
+ if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
calc_tw_center(scene, &ml->x);
totsel++;
}
@@ -433,7 +467,7 @@ static int calc_manipulator_stats(const bContext *C)
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
BPoint *bp;
- if ((v3d->around == V3D_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
+ if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
calc_tw_center(scene, bp->vec);
totsel++;
}
@@ -465,7 +499,7 @@ static int calc_manipulator_stats(const bContext *C)
if ((ob->lay & v3d->lay) == 0) return 0;
- if ((v3d->around == V3D_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
+ if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
/* doesn't check selection or visibility intentionally */
Bone *bone = pchan->bone;
if (bone) {
@@ -546,7 +580,7 @@ static int calc_manipulator_stats(const bContext *C)
}
/* global, local or normal orientation? */
- if (ob && totsel) {
+ if (ob && totsel && !is_gp_edit) {
switch (v3d->twmode) {
@@ -958,8 +992,8 @@ static void draw_manipulator_rotate(
if (is_moving) {
float vec[3];
- vec[0] = 0; // XXX (float)(t->imval[0] - t->center2d[0]);
- vec[1] = 0; // XXX (float)(t->imval[1] - t->center2d[1]);
+ vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
+ vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
vec[2] = 0.0f;
normalize_v3(vec);
mul_v3_fl(vec, 1.2f * size);
@@ -1298,6 +1332,7 @@ static void draw_manipulator_scale(
}
}
+#if 0 // XXX
/* if shiftkey, center point as last, for selectbuffer order */
if (is_picksel) {
int shift = 0; // XXX
@@ -1305,11 +1340,13 @@ static void draw_manipulator_scale(
if (shift) {
glTranslatef(0.0, -dz, 0.0);
GPU_select_load_id(MAN_SCALE_C);
+ /* TODO: set glPointSize before drawing center point */
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
}
}
+#endif
/* restore */
glLoadMatrixf(rv3d->viewmat);
@@ -1476,8 +1513,8 @@ static void draw_manipulator_rotate_cyl(
if (is_moving) {
float vec[3];
- vec[0] = 0; // XXX (float)(t->imval[0] - t->center2d[0]);
- vec[1] = 0; // XXX (float)(t->imval[1] - t->center2d[1]);
+ vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
+ vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
vec[2] = 0.0f;
normalize_v3(vec);
mul_v3_fl(vec, 1.2f * size);
@@ -1582,6 +1619,8 @@ void BIF_draw_manipulator(const bContext *C)
if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
+ if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return;
+
{
v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
@@ -1592,12 +1631,15 @@ void BIF_draw_manipulator(const bContext *C)
/* now we can define center */
switch (v3d->around) {
- case V3D_CENTER:
- case V3D_ACTIVE:
+ case V3D_AROUND_CENTER_BOUNDS:
+ case V3D_AROUND_ACTIVE:
{
- Object *ob;
- if (((v3d->around == V3D_ACTIVE) && (scene->obedit == NULL)) &&
- ((ob = OBACT) && !(ob->mode & OB_MODE_POSE)))
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+ Object *ob = OBACT;
+
+ if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
+ ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
+ (ob && !(ob->mode & OB_MODE_POSE)))
{
copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
}
@@ -1606,11 +1648,11 @@ void BIF_draw_manipulator(const bContext *C)
}
break;
}
- case V3D_LOCAL:
- case V3D_CENTROID:
+ case V3D_AROUND_LOCAL_ORIGINS:
+ case V3D_AROUND_CENTER_MEAN:
copy_v3_v3(rv3d->twmat[3], scene->twcent);
break;
- case V3D_CURSOR:
+ case V3D_AROUND_CURSOR:
copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
break;
}
@@ -1627,11 +1669,11 @@ void BIF_draw_manipulator(const bContext *C)
drawflags = rv3d->twdrawflag; /* set in calc_manipulator_stats */
if (v3d->twflag & V3D_DRAW_MANIPULATOR) {
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- if (v3d->twtype & V3D_MANIP_ROTATE) {
+ glLineWidth(1.0f);
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
if (G.debug_value == 3) {
if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT))
draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_MOVECOL, true, is_picksel);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index c6d0d6cde2e..5d49d1d9315 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -122,7 +122,7 @@ static TransformModeItem transform_modes[] =
{NULL, 0}
};
-EnumPropertyItem transform_mode_types[] =
+EnumPropertyItem rna_enum_transform_mode_types[] =
{
{TFM_INIT, "INIT", 0, "Init", ""},
{TFM_DUMMY, "DUMMY", 0, "Dummy", ""},
@@ -524,8 +524,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
if (flags & P_PROPORTIONAL) {
- RNA_def_enum(ot->srna, "proportional", proportional_editing_items, 0, "Proportional Editing", "");
- prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", proportional_falloff_items, 0,
+ RNA_def_enum(ot->srna, "proportional", rna_enum_proportional_editing_items, 0, "Proportional Editing", "");
+ prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0,
"Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100);
@@ -536,7 +536,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
RNA_def_property_flag(prop, PROP_HIDDEN);
if (flags & P_GEO_SNAP) {
- prop = RNA_def_enum(ot->srna, "snap_target", snap_target_items, 0, "Target", "");
+ prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_target_items, 0, "Target", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_float_vector(ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -684,8 +684,6 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
{
- PropertyRNA *prop;
-
/* identifiers */
ot->name = "Tilt";
/* optionals -
@@ -702,8 +700,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_editcurve_3d;
- prop = RNA_def_float(ot->srna, "value", 0.0, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
- RNA_def_property_subtype(prop, PROP_ANGLE);
+ RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
}
@@ -816,7 +813,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Mirror";
- ot->description = "Mirror selected vertices around one or more axes";
+ ot->description = "Mirror selected items around one or more axes";
ot->idname = OP_MIRROR;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
@@ -851,6 +848,12 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ RNA_def_boolean(ot->srna, "use_even", false, "Even",
+ "Make the edge loop match the shape of the adjacent edge loop");
+ RNA_def_boolean(ot->srna, "flipped", false, "Flipped",
+ "When Even mode is active, flips between the two adjacent edge loops");
+ RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
+ "Clamp within the edge extents");
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
@@ -871,6 +874,12 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
ot->poll = ED_operator_editmesh_region_view3d;
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
+ RNA_def_boolean(ot->srna, "use_even", false, "Even",
+ "Make the edge loop match the shape of the adjacent edge loop");
+ RNA_def_boolean(ot->srna, "flipped", false, "Flipped",
+ "When Even mode is active, flips between the two adjacent edge loops");
+ RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp",
+ "Clamp within the edge extents");
Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
@@ -973,7 +982,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
ot->cancel = transform_cancel;
ot->poll = ED_operator_screenactive;
- prop = RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+ prop = RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_float_vector(ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index a1bb6f4e0f3..59d2485c964 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -544,7 +544,7 @@ static unsigned int bm_mesh_elems_select_get_n__internal(
if (i == 0) {
/* pass */
}
- else {
+ else if (i == n) {
return i;
}
}
@@ -591,7 +591,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
Base *base;
Object *ob = OBACT;
int result = ORIENTATION_NONE;
- const bool activeOnly = (around == V3D_ACTIVE);
+ const bool activeOnly = (around == V3D_AROUND_ACTIVE);
zero_v3(normal);
zero_v3(plane);
@@ -756,10 +756,10 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
if (bm_mesh_verts_select_get_n(em->bm, &v, 1) == 1) {
copy_v3_v3(normal, v->no);
+ BMEdge *e_pair[2];
- if (BM_vert_is_edge_pair(v)) {
+ if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
bool v_pair_swap = false;
- BMEdge *e_pair[2] = {v->e, BM_DISK_EDGE_NEXT(v->e, v)};
BMVert *v_pair[2] = {BM_edge_other_vert(e_pair[0], v), BM_edge_other_vert(e_pair[1], v)};
float dir_pair[2][3];
@@ -854,7 +854,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
/* exception */
if (flag) {
float tvec[3];
- if ((around == V3D_LOCAL) ||
+ if ((around == V3D_AROUND_LOCAL_ORIGINS) ||
ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
{
BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
@@ -1044,8 +1044,8 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3
int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
{
- /* dummy value, not V3D_ACTIVE and not V3D_LOCAL */
- short around = V3D_CENTER;
+ /* dummy value, not V3D_AROUND_ACTIVE and not V3D_AROUND_LOCAL_ORIGINS */
+ short around = V3D_AROUND_CENTER_BOUNDS;
return getTransformOrientation_ex(C, normal, plane, around);
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index a7aad427dd6..bb9120c337b 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -85,6 +85,8 @@
#define TRANSFORM_DIST_MAX_PX 1000.0f
#define TRANSFORM_SNAP_MAX_PX 100.0f
+#define TRANSFORM_DIST_INVALID -FLT_MAX
+
/* use half of flt-max so we can scale up without an exception */
/********************* PROTOTYPES ***********************/
@@ -110,7 +112,7 @@ static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]);
/****************** IMPLEMENTATIONS *********************/
-static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode);
+static bool snapNodeTest(View2D *v2d, bNode *node, SnapSelect snap_select);
static NodeBorder snapNodeBorder(int snap_node_mode);
#if 0
@@ -328,7 +330,10 @@ void applyProject(TransInfo *t)
}
if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- if (snapObjectsTransform(t, mval_fl, &dist_px, loc, no, t->tsnap.modeSelect)) {
+ if (snapObjectsTransform(
+ t, mval_fl, t->tsnap.modeSelect,
+ loc, no, &dist_px))
+ {
// if (t->flag & (T_EDIT|T_POSE)) {
// mul_m4_v3(imat, loc);
// }
@@ -798,29 +803,19 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
static void ApplySnapRotation(TransInfo *t, float *value)
{
- if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
- *value = t->tsnap.dist;
- }
- else {
- float point[3];
- getSnapPoint(t, point);
- *value = RotationBetween(t, t->tsnap.snapTarget, point);
- }
+ float point[3];
+ getSnapPoint(t, point);
+
+ float dist = RotationBetween(t, t->tsnap.snapTarget, point);
+ *value = dist;
}
static void ApplySnapResize(TransInfo *t, float vec[3])
{
- float dist;
-
- if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
- dist = t->tsnap.dist;
- }
- else {
- float point[3];
- getSnapPoint(t, point);
- dist = ResizeBetween(t, t->tsnap.snapTarget, point);
- }
+ float point[3];
+ getSnapPoint(t, point);
+ float dist = ResizeBetween(t, t->tsnap.snapTarget, point);
copy_v3_fl(vec, dist);
}
@@ -828,7 +823,7 @@ static void ApplySnapResize(TransInfo *t, float vec[3])
static float TranslationBetween(TransInfo *UNUSED(t), const float p1[3], const float p2[3])
{
- return len_v3v3(p1, p2);
+ return len_squared_v3v3(p1, p2);
}
static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
@@ -887,17 +882,20 @@ static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3])
sub_v3_v3v3(d1, p1, t->center_global);
sub_v3_v3v3(d2, p2, t->center_global);
-
- project_v3_v3v3(d1, d1, d2);
if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
mul_m3_v3(t->con.pmtx, d1);
mul_m3_v3(t->con.pmtx, d2);
}
+
+ project_v3_v3v3(d1, d1, d2);
len_d1 = len_v3(d1);
- return len_d1 != 0.0f ? len_v3(d2) / len_d1 : 1;
+ /* Use 'invalid' dist when `center == p1` (after projecting),
+ * in this case scale will _never_ move the point in relation to the center,
+ * so it makes no sense to take it into account when scaling. see: T46503 */
+ return len_d1 != 0.0f ? len_v3(d2) / len_d1 : TRANSFORM_DIST_INVALID;
}
/********************** CALC **************************/
@@ -928,7 +926,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
BLI_listbase_clear(&depth_peels);
- peelObjectsTransForm(t, &depth_peels, mval, t->tsnap.modeSelect);
+ peelObjectsTransForm(t, mval, t->tsnap.modeSelect, &depth_peels);
// if (LAST_SNAP_POINT_VALID)
// {
@@ -1003,7 +1001,9 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
else {
zero_v3(no); /* objects won't set this */
- found = snapObjectsTransform(t, mval, &dist_px, loc, no, t->tsnap.modeSelect);
+ found = snapObjectsTransform(
+ t, mval, t->tsnap.modeSelect,
+ loc, no, &dist_px);
}
if (found == true) {
@@ -1047,7 +1047,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here
char node_border;
- if (snapNodesTransform(t, t->mval, &dist_px, loc, &node_border, t->tsnap.modeSelect)) {
+ if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) {
copy_v2_v2(t->tsnap.snapPoint, loc);
t->tsnap.snapNodeBorder = node_border;
@@ -1157,6 +1157,7 @@ static void TargetSnapClosest(TransInfo *t)
{
// Only valid if a snap point has been selected
if (t->tsnap.status & POINT_INIT) {
+ float dist_closest = 0.0f;
TransData *closest = NULL, *td = NULL;
/* Object mode */
@@ -1177,11 +1178,13 @@ static void TargetSnapClosest(TransInfo *t)
mul_m4_v3(td->ext->obmat, loc);
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
-
- if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) {
+
+ if ((dist != TRANSFORM_DIST_INVALID) &&
+ (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
+ {
copy_v3_v3(t->tsnap.snapTarget, loc);
closest = td;
- t->tsnap.dist = dist;
+ dist_closest = dist;
}
}
}
@@ -1193,11 +1196,12 @@ static void TargetSnapClosest(TransInfo *t)
copy_v3_v3(loc, td->center);
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
-
- if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) {
+
+ if ((dist != TRANSFORM_DIST_INVALID) &&
+ (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
+ {
copy_v3_v3(t->tsnap.snapTarget, loc);
closest = td;
- t->tsnap.dist = dist;
}
}
}
@@ -1217,10 +1221,12 @@ static void TargetSnapClosest(TransInfo *t)
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
- if (closest == NULL || fabsf(dist) < fabsf(t->tsnap.dist)) {
+ if ((dist != TRANSFORM_DIST_INVALID) &&
+ (closest == NULL || fabsf(dist) < fabsf(dist_closest)))
+ {
copy_v3_v3(t->tsnap.snapTarget, loc);
closest = td;
- t->tsnap.dist = dist;
+ dist_closest = dist;
}
}
}
@@ -1231,9 +1237,11 @@ static void TargetSnapClosest(TransInfo *t)
}
}
-static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], float obmat[4][4], float timat[3][3],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2],
- float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth)
+static bool snapEdge(
+ ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ float r_loc[3], float r_no[3], float *r_dist_px)
{
float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
int result;
@@ -1289,10 +1297,10 @@ static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], cons
* this takes care of series of connected edges a bit slanted w.r.t the viewport
* otherwise, it would stick to the verts of the closest edge and not slide along merrily
* */
- if (new_dist <= *r_dist_px && new_depth < *r_depth * 1.001f) {
+ if (new_dist <= *r_dist_px && new_depth < *ray_depth * 1.001f) {
float n1[3], n2[3];
- *r_depth = new_depth;
+ *ray_depth = new_depth;
retval = true;
sub_v3_v3v3(edge_loc, v1co, v2co);
@@ -1318,9 +1326,11 @@ static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], cons
return retval;
}
-static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], float obmat[4][4], float timat[3][3],
- const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2],
- float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth)
+static bool snapVertex(
+ ARegion *ar, const float vco[3], const short vno[3],
+ float obmat[4][4], float timat[3][3], const float mval_fl[2],
+ const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth,
+ float r_loc[3], float r_no[3], float *r_dist_px)
{
bool retval = false;
float dvec[3];
@@ -1347,8 +1357,8 @@ static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], floa
}
- if (new_dist <= *r_dist_px && new_depth < *r_depth) {
- *r_depth = new_depth;
+ if (new_dist <= *r_dist_px && new_depth < *ray_depth) {
+ *ray_depth = new_depth;
retval = true;
copy_v3_v3(r_loc, location);
@@ -1366,9 +1376,11 @@ static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], floa
return retval;
}
-static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth)
+static bool snapArmature(
+ ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
{
float imat[4][4];
float ray_start_local[3], ray_normal_local[3];
@@ -1386,13 +1398,13 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
- switch (snap_mode) {
+ switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(ar, eBone->head, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
- retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, eBone->head, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
+ retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
break;
}
}
@@ -1410,13 +1422,13 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar
const float *head_vec = pchan->pose_head;
const float *tail_vec = pchan->pose_tail;
- switch (snap_mode) {
+ switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
- retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
+ retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
break;
}
}
@@ -1426,9 +1438,11 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar
return retval;
}
-static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth)
+static bool snapCurve(
+ ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
{
float imat[4][4];
float ray_start_local[3], ray_normal_local[3];
@@ -1438,7 +1452,7 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
Nurb *nu;
/* only vertex snapping mode (eg control points and handles) supported for now) */
- if (snap_mode != SCE_SNAP_MODE_VERTEX) {
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
@@ -1452,7 +1466,7 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
for (u = 0; u < nu->pntsu; u++) {
- switch (snap_mode) {
+ switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
if (ob->mode == OB_MODE_EDIT) {
@@ -1461,13 +1475,13 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
break;
}
- retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
/* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) {
- retval |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
}
if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) {
- retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
}
}
else {
@@ -1475,17 +1489,17 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
break;
}
- retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
}
}
else {
/* curve is not visible outside editmode if nurb length less than two */
if (nu->pntsu > 1) {
if (nu->bezt) {
- retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
}
else {
- retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px);
}
}
}
@@ -1499,19 +1513,33 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
return retval;
}
-static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth, bool do_bb)
+static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
+{
+ const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
+}
+
+static bool snapDerivedMesh(
+ ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
+ const float mval[2], const short snap_to, bool do_bb,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index)
{
bool retval = false;
- const bool do_ray_start_correction = (snap_mode == SCE_SNAP_MODE_FACE && ar &&
- !((RegionView3D *)ar->regiondata)->is_persp);
int totvert = dm->getNumVerts(dm);
if (totvert > 0) {
+ const bool do_ray_start_correction = (
+ ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) &&
+ (ar && !((RegionView3D *)ar->regiondata)->is_persp));
+ bool need_ray_start_correction_init = do_ray_start_correction;
+
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
- float ray_start_local[3], ray_normal_local[3], local_scale, len_diff = TRANSFORM_DIST_MAX_RAY;
+ float ray_start_local[3], ray_normal_local[3];
+ float local_scale, local_depth, len_diff;
+
+ BVHTreeFromMesh treedata = {0};
invert_m4_m4(imat, obmat);
transpose_m3_m4(timat, imat);
@@ -1524,6 +1552,10 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
/* local scale in normal direction */
local_scale = normalize_v3(ray_normal_local);
+ local_depth = *ray_depth;
+ if (local_depth != BVH_RAYCAST_DIST_MAX) {
+ local_depth *= local_scale;
+ }
if (do_bb) {
BoundBox *bb = BKE_object_boundbox_get(ob);
@@ -1535,79 +1567,89 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
* Threshold is rather high, but seems to be needed to get good behavior, see T46099. */
bb = BKE_boundbox_ensure_minimum_dimensions(bb, &bb_temp, 1e-1f);
+ /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'r_dist_px'),
+ * scale up so we can snap against verts & edges on the boundbox, see T46816. */
+ if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) {
+ BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f);
+ bb = &bb_temp;
+ }
+
+ /* was local_depth, see: T47838 */
+ len_diff = BVH_RAYCAST_DIST_MAX;
+
if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
return retval;
}
+ need_ray_start_correction_init = false;
}
}
- else if (do_ray_start_correction) {
+
+ treedata.em_evil = em;
+ treedata.em_evil_all = false;
+ switch (snap_to) {
+ case SCE_SNAP_MODE_FACE:
+ bvhtree_from_mesh_looptri(&treedata, dm, 0.0f, 4, 6);
+ break;
+ case SCE_SNAP_MODE_VERTEX:
+ bvhtree_from_mesh_verts(&treedata, dm, 0.0f, 2, 6);
+ break;
+ }
+
+ if (need_ray_start_correction_init) {
/* We *need* a reasonably valid len_diff in this case.
* Use BHVTree to find the closest face from ray_start_local.
*/
- BVHTreeFromMesh treeData;
BVHTreeNearest nearest;
- len_diff = 0.0f; /* In case BVHTree would fail for some reason... */
- treeData.em_evil = em;
- bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 2, 6);
- if (treeData.tree != NULL) {
+ if (treedata.tree != NULL) {
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
/* Compute and store result. */
- BLI_bvhtree_find_nearest(treeData.tree, ray_start_local, &nearest,
- treeData.nearest_callback, &treeData);
+ BLI_bvhtree_find_nearest(
+ treedata.tree, ray_start_local, &nearest, treedata.nearest_callback, &treedata);
if (nearest.index != -1) {
len_diff = sqrtf(nearest.dist_sq);
}
}
- free_bvhtree_from_mesh(&treeData);
+ }
+ /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
+ * been *inside* boundbox, leading to snap failures (see T38409).
+ * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
+ */
+ if (do_ray_start_correction) {
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
+ * away ray_start values (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
+ len_diff - len_v3v3(ray_start_local, ray_org_local));
+ local_depth -= len_diff;
+ }
+ else {
+ len_diff = 0.0f;
}
- switch (snap_mode) {
+ switch (snap_to) {
case SCE_SNAP_MODE_FACE:
{
BVHTreeRayHit hit;
- BVHTreeFromMesh treeData;
-
- /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
- * been *inside* boundbox, leading to snap failures (see T38409).
- * Note also ar might be null (see T38435), in this case we assume ray_start is ok!
- */
- if (do_ray_start_correction) {
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far
- * away ray_start values (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff - len_v3v3(ray_start_local, ray_org_local));
- }
- else {
- len_diff = 0.0f;
- }
-
- treeData.em_evil = em;
- bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 4, 6);
hit.index = -1;
- hit.dist = *r_depth;
- if (hit.dist != TRANSFORM_DIST_MAX_RAY) {
- hit.dist *= local_scale;
- hit.dist -= len_diff;
- }
+ hit.dist = local_depth;
- if (treeData.tree &&
- BLI_bvhtree_ray_cast(treeData.tree, ray_start_local, ray_normal_local, 0.0f,
- &hit, treeData.raycast_callback, &treeData) != -1)
+ if (treedata.tree &&
+ BLI_bvhtree_ray_cast(treedata.tree, ray_start_local, ray_normal_local, 0.0f,
+ &hit, treedata.raycast_callback, &treedata) != -1)
{
hit.dist += len_diff;
hit.dist /= local_scale;
- if (hit.dist <= *r_depth) {
- *r_depth = hit.dist;
+ if (hit.dist <= *ray_depth) {
+ *ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
copy_v3_v3(r_no, hit.no);
@@ -1617,56 +1659,31 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
normalize_v3(r_no);
retval = true;
+
+ if (r_index) {
+ *r_index = dm_looptri_to_poly_index(dm, &treedata.looptri[hit.index]);
+ }
}
}
- free_bvhtree_from_mesh(&treeData);
break;
}
case SCE_SNAP_MODE_VERTEX:
{
- MVert *verts = dm->getVertArray(dm);
- const int *index_array = NULL;
- int index = 0;
- int i;
+ BVHTreeNearest nearest;
- if (em != NULL) {
- index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- }
-
- for (i = 0; i < totvert; i++) {
- BMVert *eve = NULL;
- MVert *v = verts + i;
- bool test = true;
-
- if (em != NULL) {
- if (index_array) {
- index = index_array[i];
- }
- else {
- index = i;
- }
-
- if (index == ORIGINDEX_NONE) {
- test = false;
- }
- else {
- eve = BM_vert_at_index(em->bm, index);
-
- if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN) ||
- BM_elem_flag_test(eve, BM_ELEM_SELECT))
- {
- test = false;
- }
- }
- }
-
- if (test) {
- retval |= snapVertex(ar, v->co, v->no, obmat, timat, ray_start, ray_start_local,
- ray_normal_local, mval, r_loc, r_no, r_dist_px, r_depth);
- }
+ nearest.index = -1;
+ nearest.dist_sq = local_depth * local_depth;
+ if (treedata.tree &&
+ BLI_bvhtree_find_nearest_to_ray(
+ treedata.tree, ray_start_local, ray_normal_local,
+ &nearest, NULL, NULL) != -1)
+ {
+ const MVert *v = &treedata.vert[nearest.index];
+ retval = snapVertex(
+ ar, v->co, v->no, obmat, timat, mval,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no, r_dist_px);
}
-
break;
}
case SCE_SNAP_MODE_EDGE:
@@ -1711,24 +1728,29 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
}
if (test) {
- retval |= snapEdge(ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no,
- obmat, timat, ray_start, ray_start_local, ray_normal_local, mval,
- r_loc, r_no, r_dist_px, r_depth);
+ retval |= snapEdge(
+ ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, obmat, timat,
+ mval, ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, r_no, r_dist_px);
}
}
break;
}
}
+
+ free_bvhtree_from_mesh(&treedata);
}
return retval;
}
/* may extend later (for now just snaps to empty center) */
-static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth)
+static bool snapEmpty(
+ ARegion *ar, Object *ob, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
{
float imat[4][4];
float ray_start_local[3], ray_normal_local[3];
@@ -1738,7 +1760,7 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4
return retval;
}
/* for now only vertex supported */
- if (snap_mode != SCE_SNAP_MODE_VERTEX) {
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
@@ -1747,11 +1769,14 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4
mul_v3_m4v3(ray_start_local, imat, ray_start);
mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
- switch (snap_mode) {
+ switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
const float zero_co[3] = {0.0f};
- retval |= snapVertex(ar, zero_co, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(
+ ar, zero_co, NULL, obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL, r_dist_px);
break;
}
default:
@@ -1761,9 +1786,11 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4
return retval;
}
-static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float mval[2],
- float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth)
+static bool snapCamera(
+ ARegion *ar, Scene *scene, Object *object, float obmat[4][4],
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float *UNUSED(r_no), float *r_dist_px)
{
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
@@ -1785,7 +1812,7 @@ static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *objec
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
- switch (snap_mode) {
+ switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
MovieTrackingObject *tracking_object;
@@ -1830,9 +1857,10 @@ static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *objec
vertex_obmat = obmat;
}
- retval |= snapVertex(ar, bundle_pos, NULL, vertex_obmat, NULL,
- ray_start, ray_start_local, ray_normal_local, mval,
- r_loc, NULL, r_dist_px, r_depth);
+ retval |= snapVertex(
+ ar, bundle_pos, NULL, vertex_obmat, NULL, mval,
+ ray_start, ray_start_local, ray_normal_local, ray_depth,
+ r_loc, NULL, r_dist_px);
}
}
@@ -1845,10 +1873,13 @@ static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *objec
return retval;
}
-static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit,
- Object **r_ob, float r_obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth)
+static bool snapObject(
+ Scene *scene, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit,
+ const float mval[2], const short snap_to,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
+ Object **r_ob, float r_obmat[4][4])
{
bool retval = false;
@@ -1875,21 +1906,36 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f
em = NULL;
}
- retval = snapDerivedMesh(snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_depth, do_bb);
+ retval = snapDerivedMesh(
+ ar, ob, dm, em, obmat, mval, snap_to, do_bb,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_dist_px, r_index);
dm->release(dm);
}
else if (ob->type == OB_ARMATURE) {
- retval = snapArmature(snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth);
+ retval = snapArmature(
+ ar, ob, ob->data, obmat, mval, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no, r_dist_px);
}
else if (ob->type == OB_CURVE) {
- retval = snapCurve(snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth);
+ retval = snapCurve(
+ ar, ob, ob->data, obmat, mval, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no, r_dist_px);
}
else if (ob->type == OB_EMPTY) {
- retval = snapEmpty(snap_mode, ar, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth);
+ retval = snapEmpty(
+ ar, ob, obmat, mval, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no, r_dist_px);
}
else if (ob->type == OB_CAMERA) {
- retval = snapCamera(snap_mode, ar, scene, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth);
+ retval = snapCamera(
+ ar, scene, ob, obmat, mval, snap_to,
+ ray_start, ray_normal, ray_depth,
+ r_loc, r_no, r_dist_px);
}
if (retval) {
@@ -1902,21 +1948,25 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f
return retval;
}
-static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit,
- Object **r_ob, float r_obmat[4][4],
- const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- float *r_ray_dist,
- const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode)
+static bool snapObjectsRay(
+ Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
+ const float mval[2], SnapSelect snap_select, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth,
+ /* return args */
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
+ Object **r_ob, float r_obmat[4][4])
{
Base *base;
bool retval = false;
- if (mode == SNAP_ALL && obedit) {
+ if (snap_select == SNAP_ALL && obedit) {
Object *ob = obedit;
- retval |= snapObject(scene, snap_mode, ar, ob, ob->obmat, true,
- r_ob, r_obmat,
- ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist);
+ retval |= snapObject(
+ scene, ar, ob, ob->obmat, true,
+ mval, snap_to,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
}
/* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
@@ -1927,17 +1977,19 @@ static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D
base = base_act;
if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) {
Object *ob = base->object;
- retval |= snapObject(scene, snap_mode, ar, ob, ob->obmat, false,
- r_ob, r_obmat,
- ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist);
+ retval |= snapObject(
+ scene, ar, ob, ob->obmat, false,
+ mval, snap_to,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
}
for (base = FIRSTBASE; base != NULL; base = base->next) {
if ((BASE_VISIBLE_BGMODE(v3d, scene, base)) &&
(base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 &&
- ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
- (ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
+ ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) ||
+ (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act)))
{
Object *ob = base->object;
Object *ob_snap = ob;
@@ -1957,25 +2009,31 @@ static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D
bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data);
Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob;
- retval |= snapObject(scene, snap_mode, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli,
- r_ob, r_obmat,
- ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist);
+ retval |= snapObject(
+ scene, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli,
+ mval, snap_to,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
}
free_object_duplilist(lb);
}
- retval |= snapObject(scene, snap_mode, ar, ob_snap, ob->obmat, use_obedit,
- r_ob, r_obmat,
- ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist);
+ retval |= snapObject(
+ scene, ar, ob_snap, ob->obmat, use_obedit,
+ mval, snap_to,
+ ray_start, ray_normal, ray_origin, ray_depth,
+ r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat);
}
}
return retval;
}
-static bool snapObjects(Scene *scene, short snap_mode, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit,
- const float mval[2], float *r_dist_px,
- float r_loc[3], float r_no[3], float *r_ray_dist, SnapMode mode)
+static bool snapObjects(
+ Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
+ const float mval[2], SnapSelect snap_select, const short snap_to,
+ float *ray_depth,
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index)
{
float ray_start[3], ray_normal[3], ray_orgigin[3];
@@ -1983,15 +2041,18 @@ static bool snapObjects(Scene *scene, short snap_mode, Base *base_act, View3D *v
return false;
}
- return snapObjectsRay(scene, snap_mode, base_act, v3d, ar, obedit,
- NULL, NULL,
- ray_start, ray_normal, ray_orgigin, r_ray_dist,
- mval, r_dist_px, r_loc, r_no, mode);
+ return snapObjectsRay(
+ scene, v3d, ar, base_act, obedit,
+ mval, snap_select, snap_to,
+ ray_start, ray_normal, ray_orgigin, ray_depth,
+ r_loc, r_no, r_dist_px, r_index, NULL, NULL);
}
-bool snapObjectsTransform(TransInfo *t, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode)
+bool snapObjectsTransform(
+ TransInfo *t, const float mval[2], SnapSelect snap_select,
+ float r_loc[3], float r_no[3], float *r_dist_px)
{
- float ray_dist = TRANSFORM_DIST_MAX_RAY;
+ float ray_dist = BVH_RAYCAST_DIST_MAX;
Object *obedit = NULL;
Base *base_act = NULL;
@@ -2004,40 +2065,55 @@ bool snapObjectsTransform(TransInfo *t, const float mval[2], float *r_dist_px, f
}
return snapObjects(
- t->scene, t->scene->toolsettings->snap_mode, base_act, t->view, t->ar, obedit,
- mval, r_dist_px, r_loc, r_no, &ray_dist, mode);
+ t->scene, t->view, t->ar, base_act, obedit,
+ mval, snap_select, t->scene->toolsettings->snap_mode,
+ &ray_dist,
+ r_loc, r_no, r_dist_px, NULL);
}
-bool snapObjectsContext(bContext *C, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode)
+bool snapObjectsContext(
+ bContext *C, const float mval[2], SnapSelect snap_select,
+ float r_loc[3], float r_no[3], float *r_dist_px)
{
ScrArea *sa = CTX_wm_area(C);
View3D *v3d = sa->spacedata.first;
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
Object *obedit = CTX_data_edit_object(C);
- float ray_dist = TRANSFORM_DIST_MAX_RAY;
+ float ray_dist = BVH_RAYCAST_DIST_MAX;
- return snapObjects(scene, scene->toolsettings->snap_mode, scene->basact, v3d, ar, obedit,
- mval, r_dist_px, r_loc, r_no, &ray_dist, mode);
+ return snapObjects(
+ scene, v3d, ar, scene->basact, obedit,
+ mval, snap_select, scene->toolsettings->snap_mode,
+ &ray_dist,
+ r_loc, r_no, r_dist_px, NULL);
}
-bool snapObjectsEx(Scene *scene, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit, short snap_mode,
- const float mval[2], float *r_dist_px,
- float r_loc[3], float r_no[3], float *r_ray_dist, SnapMode mode)
+bool snapObjectsEx(
+ Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
+ const float mval[2], SnapSelect snap_select, const short snap_to,
+ float *ray_depth,
+ float r_loc[3], float r_no[3], float *r_dist_px)
{
- return snapObjects(scene, snap_mode, base_act, v3d, ar, obedit,
- mval, r_dist_px,
- r_loc, r_no, r_ray_dist, mode);
+ return snapObjects(
+ scene, v3d, ar, base_act, obedit,
+ mval, snap_select, snap_to,
+ ray_depth,
+ r_loc, r_no, r_dist_px, NULL);
}
-bool snapObjectsRayEx(Scene *scene, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit, short snap_mode,
- Object **r_ob, float r_obmat[4][4],
- const float ray_start[3], const float ray_normal[3], float *r_ray_dist,
- const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode)
-{
- return snapObjectsRay(scene, snap_mode, base_act, v3d, ar, obedit,
- r_ob, r_obmat,
- ray_start, ray_normal, ray_start, r_ray_dist,
- mval, r_dist_px, r_loc, r_no, mode);
+bool snapObjectsRayEx(
+ Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit,
+ const float mval[2], SnapSelect snap_select, const short snap_to,
+ const float ray_start[3], const float ray_normal[3], float *ray_depth,
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
+ Object **r_ob, float r_obmat[4][4])
+{
+ return snapObjectsRay(
+ scene, v3d, ar, base_act, obedit,
+ mval, snap_select, snap_to,
+ ray_start, ray_normal, ray_start, ray_depth,
+ r_loc, r_no, r_dist_px, r_index,
+ r_ob, r_obmat);
}
/******************** PEELING *********************************/
@@ -2177,6 +2253,7 @@ static bool peelDerivedMesh(
struct PeelRayCast_Data data;
data.bvhdata.em_evil = em;
+ data.bvhdata.em_evil_all = false;
bvhtree_from_mesh_looptri(&data.bvhdata, dm, 0.0f, 4, 6);
if (data.bvhdata.tree != NULL) {
@@ -2199,8 +2276,10 @@ static bool peelDerivedMesh(
return retval;
}
-static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
- ListBase *depth_peels, const float mval[2], SnapMode mode)
+static bool peelObjects(
+ Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
+ const float mval[2], SnapSelect snap_select,
+ ListBase *r_depth_peels)
{
Base *base;
bool retval = false;
@@ -2229,13 +2308,13 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
if (dob != obedit) {
dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
- val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, r_depth_peels);
}
else {
em = BKE_editmesh_from_object(dob);
dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
- val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, r_depth_peels);
}
retval = retval || val;
@@ -2250,17 +2329,17 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
if (ob->type == OB_MESH) {
bool val = false;
- if (ob != obedit && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT))) {
+ if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) {
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels);
dm->release(dm);
}
- else if (ob == obedit && mode != SNAP_NOT_OBEDIT) {
+ else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) {
BMEditMesh *em = BKE_editmesh_from_object(ob);
DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
- val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, depth_peels);
+ val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels);
dm->release(dm);
}
@@ -2270,18 +2349,22 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit,
}
}
- BLI_listbase_sort(depth_peels, cmpPeel);
- removeDoublesPeel(depth_peels);
+ BLI_listbase_sort(r_depth_peels, cmpPeel);
+ removeDoublesPeel(r_depth_peels);
return retval;
}
-bool peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, const float mval[2], SnapMode mode)
+bool peelObjectsTransForm(
+ TransInfo *t, const float mval[2], SnapSelect snap_select,
+ ListBase *r_depth_peels)
{
- return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval, mode);
+ return peelObjects(t->scene, t->view, t->ar, t->obedit, mval, snap_select, r_depth_peels);
}
-bool peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], SnapMode mode)
+bool peelObjectsContext(
+ bContext *C, const float mval[2], SnapSelect snap_select,
+ ListBase *r_depth_peels)
{
Scene *scene = CTX_data_scene(C);
ScrArea *sa = CTX_wm_area(C);
@@ -2289,16 +2372,16 @@ bool peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2],
ARegion *ar = CTX_wm_region(C);
Object *obedit = CTX_data_edit_object(C);
- return peelObjects(scene, v3d, ar, obedit, depth_peels, mval, mode);
+ return peelObjects(scene, v3d, ar, obedit, mval, snap_select, r_depth_peels);
}
/******************** NODES ***********************************/
-static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode)
+static bool snapNodeTest(View2D *v2d, bNode *node, SnapSelect snap_select)
{
/* node is use for snapping only if a) snap mode matches and b) node is inside the view */
- return ((mode == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
- (mode == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
+ return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
+ (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
(node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
}
@@ -2316,8 +2399,9 @@ static NodeBorder snapNodeBorder(int snap_node_mode)
return 0;
}
-static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2],
- float r_loc[2], float *r_dist_px, char *r_node_border)
+static bool snapNode(
+ ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2],
+ float r_loc[2], float *r_dist_px, char *r_node_border)
{
View2D *v2d = &ar->v2d;
NodeBorder border = snapNodeBorder(ts->snap_node_mode);
@@ -2370,8 +2454,10 @@ static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bN
return retval;
}
-static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2],
- float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode)
+static bool snapNodes(
+ ToolSettings *ts, SpaceNode *snode, ARegion *ar,
+ const int mval[2], SnapSelect snap_select,
+ float r_loc[2], float *r_dist_px, char *r_node_border)
{
bNodeTree *ntree = snode->edittree;
bNode *node;
@@ -2380,23 +2466,32 @@ static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int
*r_node_border = 0;
for (node = ntree->nodes.first; node; node = node->next) {
- if (snapNodeTest(&ar->v2d, node, mode))
+ if (snapNodeTest(&ar->v2d, node, snap_select)) {
retval |= snapNode(ts, snode, ar, node, mval, r_loc, r_dist_px, r_node_border);
+ }
}
return retval;
}
-bool snapNodesTransform(TransInfo *t, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode)
+bool snapNodesTransform(
+ TransInfo *t, const int mval[2], SnapSelect snap_select,
+ float r_loc[2], float *r_dist_px, char *r_node_border)
{
- return snapNodes(t->settings, t->sa->spacedata.first, t->ar, mval, r_dist_px, r_loc, r_node_border, mode);
+ return snapNodes(
+ t->settings, t->sa->spacedata.first, t->ar, mval, snap_select,
+ r_loc, r_dist_px, r_node_border);
}
-bool snapNodesContext(bContext *C, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode)
+bool snapNodesContext(
+ bContext *C, const int mval[2], SnapSelect snap_select,
+ float r_loc[2], float *r_dist_px, char *r_node_border)
{
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
- return snapNodes(scene->toolsettings, CTX_wm_space_node(C), ar, mval, r_dist_px, r_loc, r_node_border, mode);
+ return snapNodes(
+ scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select,
+ r_loc, r_dist_px, r_node_border);
}
/*================================================================*/
@@ -2438,7 +2533,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2])
float xmouse, ymouse;
int frame;
int mframe;
- TransSeq *ts = t->customData;
+ TransSeq *ts = t->custom.type.data;
/* reuse increment, strictly speaking could be another snap mode, but leave as is */
if (!(t->modifiers & MOD_SNAP_INVERT))
return;
diff --git a/source/blender/editors/util/SConscript b/source/blender/editors/util/SConscript
deleted file mode 100644
index 7d9991e6483..00000000000
--- a/source/blender/editors/util/SConscript
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
- incs.append('../../python')
-
-env.BlenderLib ( 'bf_editors_util', sources, incs, defines=defs, libtype=['core','player'], priority=[330,210] )
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index f727f48e993..1f4ce926f16 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -151,8 +151,8 @@ void ED_editors_exit(bContext *C)
}
/* global in meshtools... */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, 'e');
+ ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_topo_table(NULL, NULL, 'e');
}
/* flush any temp data from object editing to DNA before writing files,
@@ -316,7 +316,7 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info
UI_ThemeColor(TH_VIEW_OVERLAY);
setlinestyle(3);
- glBegin(GL_LINE_STRIP);
+ glBegin(GL_LINES);
glVertex2iv(mval_dst);
glVertex2fv(mval_src);
glEnd();
@@ -344,3 +344,23 @@ void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id)
break;
}
}
+
+static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ED_editors_flush_edits(C, false);
+ return OPERATOR_FINISHED;
+}
+
+void ED_OT_flush_edits(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flush Edits";
+ ot->description = "Flush edit data from active editing modes";
+ ot->idname = "ED_OT_flush_edits";
+
+ /* api callbacks */
+ ot->exec = ed_flush_edits_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_INTERNAL;
+}
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index d2bc8bc80c0..e07831358d6 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -477,6 +477,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
/* At this point, our value has changed, try to interpret it with python (if str is not empty!). */
if (n->str[0]) {
+ const float val_prev = n->val[idx];
#ifdef WITH_PYTHON
Scene *sce = CTX_data_scene(C);
double val;
@@ -496,7 +497,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
n->unit_sys, n->unit_type[idx]);
/* Note: with angles, we always get values as radians here... */
- if (BPY_button_exec(C, str_unit_convert, &val, false) != -1) {
+ if (BPY_execute_string_as_number(C, str_unit_convert, &val, false)) {
n->val[idx] = (float)val;
n->val_flag[idx] &= ~NUM_INVALID;
}
@@ -514,6 +515,11 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
if (n->val_flag[idx] & NUM_INVERSE) {
n->val[idx] = 1.0f / n->val[idx];
}
+
+ if (UNLIKELY(!isfinite(n->val[idx]))) {
+ n->val[idx] = val_prev;
+ n->val_flag[idx] |= NUM_INVALID;
+ }
}
/* REDRAW SINCE NUMBERS HAVE CHANGED */
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index cd68df52ed4..a1853bf8daa 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -76,7 +76,6 @@
void ED_undo_push(bContext *C, const char *str)
{
- wmWindowManager *wm = CTX_wm_manager(C);
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
@@ -111,11 +110,7 @@ void ED_undo_push(bContext *C, const char *str)
BKE_undo_write(C, str);
}
- if (wm->file_saved) {
- wm->file_saved = 0;
- /* notifier that data changed, for save-over warning or header */
- WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
- }
+ WM_file_tag_modified(C);
}
/* note: also check undo_history_exec() in bottom if you change notifiers */
@@ -466,8 +461,6 @@ static int get_undo_system(bContext *C)
}
}
else {
- Object *obact = CTX_data_active_object(C);
-
if (obact) {
if (obact->mode & OB_MODE_PARTICLE_EDIT)
return UNDOSYSTEM_PARTICLE;
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index a90763eed4e..543ef0e0663 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/eigen
../../../../intern/glew-mx
)
@@ -52,13 +53,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_OPENNL)
- add_definitions(-DWITH_OPENNL)
- list(APPEND INC_SYS
- ../../../../intern/opennl/extern
- )
-endif()
-
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_uvedit "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript
deleted file mode 100644
index b5cccab4002..00000000000
--- a/source/blender/editors/uvedit/SConscript
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-sources = env.Glob('*.c')
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/opennl/extern',
- '../include',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../gpu',
- '../../makesdna',
- '../../makesrna',
- '../../windowmanager',
- ]
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-env.BlenderLib ( 'bf_editors_uvedit', sources, incs, defs, libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 4e9ab680dc6..baa471e920b 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -65,6 +65,8 @@
#include "uvedit_intern.h"
+#include "GPU_basic_shader.h"
+
/* use editmesh tessface */
#define USE_EDBM_LOOPTRIS
@@ -187,8 +189,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
const int efa_len = efa->len;
- float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len);
- float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len);
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len);
+ float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len);
tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
@@ -230,8 +232,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
const int efa_len = efa->len;
- float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len);
- float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len);
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len);
+ float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len);
area = BM_face_calc_area(efa) / totarea;
@@ -284,12 +286,12 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
if (uvedit_face_visible_test(scene, ima, efa, tf)) {
const int efa_len = efa->len;
- float (*tf_uv)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uv_buf, vec2f, efa_len);
- float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_resize_data(&tf_uvorig_buf, vec2f, efa_len);
- float *uvang = BLI_buffer_resize_data(&uvang_buf, float, efa_len);
- float *ang = BLI_buffer_resize_data(&ang_buf, float, efa_len);
- float (*av)[3] = (float (*)[3])BLI_buffer_resize_data(&av_buf, vec3f, efa_len);
- float (*auv)[2] = (float (*)[2])BLI_buffer_resize_data(&auv_buf, vec2f, efa_len);
+ float (*tf_uv)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa_len);
+ float (*tf_uvorig)[2] = (float (*)[2])BLI_buffer_reinit_data(&tf_uvorig_buf, vec2f, efa_len);
+ float *uvang = BLI_buffer_reinit_data(&uvang_buf, float, efa_len);
+ float *ang = BLI_buffer_reinit_data(&ang_buf, float, efa_len);
+ float (*av)[3] = (float (*)[3])BLI_buffer_reinit_data(&av_buf, vec3f, efa_len);
+ float (*auv)[2] = (float (*)[2])BLI_buffer_reinit_data(&auv_buf, vec2f, efa_len);
int j;
BM_elem_flag_enable(efa, BM_ELEM_TAG);
@@ -637,8 +639,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (tf == activetf) {
/* only once */
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
UI_ThemeColor4(TH_EDITMESH_ACTIVE);
}
else {
@@ -650,7 +652,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glEnd();
if (tf == activetf) {
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
}
else {
@@ -713,8 +715,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
UI_ThemeColor4(TH_EDITMESH_ACTIVE);
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(stipple_quarttone);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
glBegin(GL_POLYGON);
BM_ITER_ELEM (l, &liter, activef, BM_LOOPS_OF_FACE) {
@@ -723,7 +725,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
}
glEnd();
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glDisable(GL_BLEND);
}
}
@@ -736,7 +738,9 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
-
+
+ glLineWidth(1);
+
switch (sima->dt_uv) {
case SI_UVDT_DASH:
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
@@ -854,37 +858,37 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
float cent[2];
pointsize = UI_GetThemeValuef(TH_FACEDOT_SIZE);
- glPointSize(pointsize); // TODO - drawobject.c changes this value after - Investigate!
+ glPointSize(pointsize);
+ glBegin(GL_POINTS);
+
/* unselected faces */
UI_ThemeColor(TH_WIRE);
- bglBegin(GL_POINTS);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
uv_poly_center(efa, cent, cd_loop_uv_offset);
- bglVertex2fv(cent);
+ glVertex2fv(cent);
}
}
- bglEnd();
/* selected faces */
UI_ThemeColor(TH_FACE_DOT);
- bglBegin(GL_POINTS);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
uv_poly_center(efa, cent, cd_loop_uv_offset);
- bglVertex2fv(cent);
+ glVertex2fv(cent);
}
}
- bglEnd();
+
+ glEnd();
}
/* 6. draw uv vertices */
@@ -895,7 +899,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
glPointSize(pointsize);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -903,17 +907,17 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- bglVertex2fv(luv->uv);
+ glVertex2fv(luv->uv);
}
}
- bglEnd();
+ glEnd();
/* pinned uvs */
/* give odd pointsizes odd pin pointsizes */
glPointSize(pointsize * 2 + (((int)pointsize % 2) ? (-1) : 0));
cpack(0xFF);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -922,16 +926,16 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (luv->flag & MLOOPUV_PINNED)
- bglVertex2fv(luv->uv);
+ glVertex2fv(luv->uv);
}
}
- bglEnd();
+ glEnd();
/* selected uvs */
UI_ThemeColor(TH_VERTEX_SELECT);
glPointSize(pointsize);
- bglBegin(GL_POINTS);
+ glBegin(GL_POINTS);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
@@ -940,13 +944,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
- bglVertex2fv(luv->uv);
+ glVertex2fv(luv->uv);
}
}
- bglEnd();
+ glEnd();
}
-
- glPointSize(1.0);
}
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 71d557f6fc7..1071e0f12e8 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -170,7 +170,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
if (node && is_image_texture_node(node)) {
node->id = &ima->id;
- ED_node_tag_update_nodetree(bmain, ma->nodetree);
+ ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
}
}
@@ -727,7 +727,7 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2
{
bool changed = false;
- if (mode == V3D_CENTER) { /* bounding box */
+ if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
float min[2], max[2];
if (ED_uvedit_minmax(scene, ima, obedit, min, max)) {
mid_v2_v2v2(cent, min, max);
@@ -4119,7 +4119,13 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
}
}
- me->drawflag |= ME_DRAWSEAMS;
+ if (mark_seams) {
+ me->drawflag |= ME_DRAWSEAMS;
+ }
+ if (mark_sharp) {
+ me->drawflag |= ME_DRAWSHARP;
+ }
+
BM_uv_vert_map_free(vmap);
@@ -4189,6 +4195,10 @@ static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
uiPopupMenu *pup;
uiLayout *layout;
+ if (RNA_struct_property_is_set(op->ptr, "clear")) {
+ return uv_mark_seam_exec(C, op);
+ }
+
pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 00615f9bef7..59f9cd16908 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -44,9 +44,7 @@
#include "BLI_sys_types.h" /* for intptr_t support */
-#ifdef WITH_OPENNL
-
-#include "ONL_opennl.h"
+#include "eigen_capi.h"
/* Utils */
@@ -193,7 +191,7 @@ typedef struct PChart {
union PChartUnion {
struct PChartLscm {
- NLContext context;
+ LinearSolver *context;
float *abf_alpha;
PVert *pin1, *pin2;
} lscm;
@@ -2471,16 +2469,12 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
PEdge *e;
int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior;
PBool success;
+ LinearSolver *context;
- nlNewContext();
- nlSolverParameteri(NL_NB_VARIABLES, nvar);
-
- nlBegin(NL_SYSTEM);
-
- nlBegin(NL_MATRIX);
+ context = EIG_linear_solver_new(0, nvar, 1);
for (i = 0; i < nvar; i++)
- nlRightHandSideAdd(0, i, sys->bInterior[i]);
+ EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]);
for (f = chart->faces; f; f = f->nextlink) {
float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
@@ -2526,8 +2520,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2;
sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3;
- nlRightHandSideAdd(0, v1->u.id, j2[0][0] * beta[0]);
- nlRightHandSideAdd(0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]);
+ EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]);
+ EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]);
row1[0] = j2[0][0] * W[0][0];
row2[0] = j2[0][0] * W[1][0];
@@ -2546,8 +2540,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2;
sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3;
- nlRightHandSideAdd(0, v2->u.id, j2[1][1] * beta[1]);
- nlRightHandSideAdd(0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]);
+ EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]);
+ EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]);
row1[1] = j2[1][1] * W[0][1];
row2[1] = j2[1][1] * W[1][1];
@@ -2566,8 +2560,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2;
sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3;
- nlRightHandSideAdd(0, v3->u.id, j2[2][2] * beta[2]);
- nlRightHandSideAdd(0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]);
+ EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]);
+ EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]);
row1[2] = j2[2][2] * W[0][2];
row2[2] = j2[2][2] * W[1][2];
@@ -2591,29 +2585,25 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
continue;
if (i == 0)
- nlMatrixAdd(r, c, j2[0][i] * row1[j]);
+ EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]);
else
- nlMatrixAdd(r + ninterior, c, j2[0][i] * row1[j]);
+ EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]);
if (i == 1)
- nlMatrixAdd(r, c, j2[1][i] * row2[j]);
+ EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]);
else
- nlMatrixAdd(r + ninterior, c, j2[1][i] * row2[j]);
+ EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]);
if (i == 2)
- nlMatrixAdd(r, c, j2[2][i] * row3[j]);
+ EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]);
else
- nlMatrixAdd(r + ninterior, c, j2[2][i] * row3[j]);
+ EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]);
}
}
}
- nlEnd(NL_MATRIX);
-
- nlEnd(NL_SYSTEM);
-
- success = nlSolve();
+ success = EIG_linear_solver_solve(context);
if (success) {
for (f = chart->faces; f; f = f->nextlink) {
@@ -2624,24 +2614,24 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
pre[0] = pre[1] = pre[2] = 0.0;
if (v1->flag & PVERT_INTERIOR) {
- float x = nlGetVariable(0, v1->u.id);
- float x2 = nlGetVariable(0, ninterior + v1->u.id);
+ float x = EIG_linear_solver_variable_get(context, 0, v1->u.id);
+ float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id);
pre[0] += sys->J2dt[e1->u.id][0] * x;
pre[1] += sys->J2dt[e2->u.id][0] * x2;
pre[2] += sys->J2dt[e3->u.id][0] * x2;
}
if (v2->flag & PVERT_INTERIOR) {
- float x = nlGetVariable(0, v2->u.id);
- float x2 = nlGetVariable(0, ninterior + v2->u.id);
+ float x = EIG_linear_solver_variable_get(context, 0, v2->u.id);
+ float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id);
pre[0] += sys->J2dt[e1->u.id][1] * x2;
pre[1] += sys->J2dt[e2->u.id][1] * x;
pre[2] += sys->J2dt[e3->u.id][1] * x2;
}
if (v3->flag & PVERT_INTERIOR) {
- float x = nlGetVariable(0, v3->u.id);
- float x2 = nlGetVariable(0, ninterior + v3->u.id);
+ float x = EIG_linear_solver_variable_get(context, 0, v3->u.id);
+ float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id);
pre[0] += sys->J2dt[e1->u.id][2] * x2;
pre[1] += sys->J2dt[e2->u.id][2] * x2;
pre[2] += sys->J2dt[e3->u.id][2] * x;
@@ -2672,12 +2662,12 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
}
for (i = 0; i < ninterior; i++) {
- sys->lambdaPlanar[i] += (float)nlGetVariable(0, i);
- sys->lambdaLength[i] += (float)nlGetVariable(0, ninterior + i);
+ sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i);
+ sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
}
}
- nlDeleteContext(nlGetCurrent());
+ EIG_linear_solver_delete(context);
return success;
}
@@ -3003,11 +2993,12 @@ static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
static void p_chart_lscm_load_solution(PChart *chart)
{
+ LinearSolver *context = chart->u.lscm.context;
PVert *v;
for (v = chart->verts; v; v = v->nextlink) {
- v->uv[0] = nlGetVariable(0, 2 * v->u.id);
- v->uv[1] = nlGetVariable(0, 2 * v->u.id + 1);
+ v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id);
+ v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1);
}
}
@@ -3062,17 +3053,13 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
for (v = chart->verts; v; v = v->nextlink)
v->u.id = id++;
- nlNewContext();
- nlSolverParameteri(NL_NB_VARIABLES, 2 * chart->nverts);
- nlSolverParameteri(NL_NB_ROWS, 2 * chart->nfaces);
- nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
-
- chart->u.lscm.context = nlGetCurrent();
+ chart->u.lscm.context = EIG_linear_least_squares_solver_new(2 * chart->nfaces, 2 * chart->nverts, 1);
}
}
static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
{
+ LinearSolver *context = chart->u.lscm.context;
PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
PFace *f;
float *alpha = chart->u.lscm.abf_alpha;
@@ -3080,10 +3067,6 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
bool flip_faces;
int row;
- nlMakeCurrent(chart->u.lscm.context);
-
- nlBegin(NL_SYSTEM);
-
#if 0
/* TODO: make loading pins work for simplify/complexify. */
#endif
@@ -3093,25 +3076,25 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
p_vert_load_pin_select_uvs(handle, v); /* reload for live */
if (chart->u.lscm.pin1) {
- nlLockVariable(2 * pin1->u.id);
- nlLockVariable(2 * pin1->u.id + 1);
- nlLockVariable(2 * pin2->u.id);
- nlLockVariable(2 * pin2->u.id + 1);
+ EIG_linear_solver_variable_lock(context, 2 * pin1->u.id);
+ EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1);
+ EIG_linear_solver_variable_lock(context, 2 * pin2->u.id);
+ EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1);
- nlSetVariable(0, 2 * pin1->u.id, pin1->uv[0]);
- nlSetVariable(0, 2 * pin1->u.id + 1, pin1->uv[1]);
- nlSetVariable(0, 2 * pin2->u.id, pin2->uv[0]);
- nlSetVariable(0, 2 * pin2->u.id + 1, pin2->uv[1]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]);
+ EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]);
}
else {
/* set and lock the pins */
for (v = chart->verts; v; v = v->nextlink) {
if (v->flag & PVERT_PIN) {
- nlLockVariable(2 * v->u.id);
- nlLockVariable(2 * v->u.id + 1);
+ EIG_linear_solver_variable_lock(context, 2 * v->u.id);
+ EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1);
- nlSetVariable(0, 2 * v->u.id, v->uv[0]);
- nlSetVariable(0, 2 * v->u.id + 1, v->uv[1]);
+ EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]);
+ EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]);
}
}
}
@@ -3138,8 +3121,6 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
/* construct matrix */
- nlBegin(NL_MATRIX);
-
row = 0;
for (f = chart->faces; f; f = f->nextlink) {
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
@@ -3186,44 +3167,22 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
cosine = cosf(a1) * ratio;
sine = sina1 * ratio;
-#if 0
- nlBegin(NL_ROW);
- nlCoefficient(2 * v1->u.id, cosine - 1.0);
- nlCoefficient(2 * v1->u.id + 1, -sine);
- nlCoefficient(2 * v2->u.id, -cosine);
- nlCoefficient(2 * v2->u.id + 1, sine);
- nlCoefficient(2 * v3->u.id, 1.0);
- nlEnd(NL_ROW);
-
- nlBegin(NL_ROW);
- nlCoefficient(2 * v1->u.id, sine);
- nlCoefficient(2 * v1->u.id + 1, cosine - 1.0);
- nlCoefficient(2 * v2->u.id, -sine);
- nlCoefficient(2 * v2->u.id + 1, -cosine);
- nlCoefficient(2 * v3->u.id + 1, 1.0);
- nlEnd(NL_ROW);
-#else
- nlMatrixAdd(row, 2 * v1->u.id, cosine - 1.0f);
- nlMatrixAdd(row, 2 * v1->u.id + 1, -sine);
- nlMatrixAdd(row, 2 * v2->u.id, -cosine);
- nlMatrixAdd(row, 2 * v2->u.id + 1, sine);
- nlMatrixAdd(row, 2 * v3->u.id, 1.0);
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f);
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0);
row++;
- nlMatrixAdd(row, 2 * v1->u.id, sine);
- nlMatrixAdd(row, 2 * v1->u.id + 1, cosine - 1.0f);
- nlMatrixAdd(row, 2 * v2->u.id, -sine);
- nlMatrixAdd(row, 2 * v2->u.id + 1, -cosine);
- nlMatrixAdd(row, 2 * v3->u.id + 1, 1.0);
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine);
+ EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0);
row++;
-#endif
}
- nlEnd(NL_MATRIX);
-
- nlEnd(NL_SYSTEM);
-
- if (nlSolveAdvanced(NULL, NL_TRUE)) {
+ if (EIG_linear_solver_solve(context)) {
p_chart_lscm_load_solution(chart);
return P_TRUE;
}
@@ -3240,7 +3199,7 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
static void p_chart_lscm_end(PChart *chart)
{
if (chart->u.lscm.context)
- nlDeleteContext(chart->u.lscm.context);
+ EIG_linear_solver_delete(chart->u.lscm.context);
if (chart->u.lscm.abf_alpha) {
MEM_freeN(chart->u.lscm.abf_alpha);
@@ -4199,14 +4158,15 @@ static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
ParamBool *pin, ParamBool *select, const float normal[3])
{
int *boundary = BLI_array_alloca(boundary, nverts);
- int i;
/* boundary vertex indexes */
- for (i = 0; i < nverts; i++)
+ for (int i = 0; i < nverts; i++) {
boundary[i] = i;
+ }
while (nverts > 2) {
float minangle = FLT_MAX;
+ float minshape = FLT_MAX;
int i, mini = 0;
/* find corner with smallest angle */
@@ -4222,8 +4182,20 @@ static void p_add_ngon(ParamHandle *handle, ParamKey key, int nverts,
if (normal && (dot_v3v3(n, normal) < 0.0f))
angle = (float)(2.0 * M_PI) - angle;
- if (angle < minangle) {
+ float other_angle = p_vec_angle(co[v2], co[v0], co[v1]);
+ float shape = fabsf((float)M_PI - angle - 2.0f * other_angle);
+
+ if (fabsf(angle - minangle) < 0.01f) {
+ /* for nearly equal angles, try to get well shaped triangles */
+ if (shape < minshape) {
+ minangle = angle;
+ minshape = shape;
+ mini = i;
+ }
+ }
+ else if (angle < minangle) {
minangle = angle;
+ minshape = shape;
mini = i;
}
}
@@ -4719,36 +4691,3 @@ void param_flush_restore(ParamHandle *handle)
}
}
-#else /* WITH_OPENNL */
-
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wunused-parameter"
-#endif
-
-/* stubs */
-void param_face_add(ParamHandle *handle, ParamKey key, int nverts,
- ParamKey *vkeys, float **co, float **uv,
- ParamBool *pin, ParamBool *select, float normal[3]) {}
-void param_edge_set_seam(ParamHandle *handle,
- ParamKey *vkeys) {}
-void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy) {}
-ParamHandle *param_construct_begin(void) { return NULL; }
-void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl) {}
-void param_delete(ParamHandle *handle) {}
-
-void param_stretch_begin(ParamHandle *handle) {}
-void param_stretch_blend(ParamHandle *handle, float blend) {}
-void param_stretch_iter(ParamHandle *handle) {}
-void param_stretch_end(ParamHandle *handle) {}
-
-void param_pack(ParamHandle *handle, float margin, bool do_rotate) {}
-void param_average(ParamHandle *handle) {}
-
-void param_flush(ParamHandle *handle) {}
-void param_flush_restore(ParamHandle *handle) {}
-
-void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf) {}
-void param_lscm_solve(ParamHandle *handle) {}
-void param_lscm_end(ParamHandle *handle) {}
-
-#endif /* WITH_OPENNL */
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index 828537fd585..20a8ab5c98c 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -87,7 +87,7 @@ typedef struct StitchPreviewer {
unsigned int num_stitchable;
unsigned int num_unstitchable;
unsigned int preview_uvs;
- /* ...and here we'll store the static island triangles*/
+ /* ...and here we'll store the static island triangles */
float *static_tris;
unsigned int num_static_tris;
} StitchPreviewer;
@@ -95,8 +95,11 @@ typedef struct StitchPreviewer {
struct IslandStitchData;
-/* This is a straightforward implementation, count the uv's in the island that will move and take the mean displacement/rotation and apply it to all
- * elements of the island except from the stitchable */
+/**
+ * This is a straightforward implementation, count the UVs in the island
+ * that will move and take the mean displacement/rotation and apply it to all
+ * elements of the island except from the stitchable.
+ */
typedef struct IslandStitchData {
/* rotation can be used only for edges, for vertices there is no such notion */
float rotation;
@@ -145,7 +148,7 @@ typedef struct StitchState {
float limit_dist;
/* snap uv islands together during stitching */
bool snap_islands;
- /* stich at midpoints or at islands */
+ /* stitch at midpoints or at islands */
bool midpoints;
/* editmesh, cached for use in modal handler */
BMEditMesh *em;
@@ -261,7 +264,13 @@ static void stitch_preview_delete(StitchPreviewer *stitch_preview)
/* This function updates the header of the UV editor when the stitch tool updates its settings */
static void stitch_update_header(StitchState *state, bContext *C)
{
- static char str[] = "Mode(TAB) %s, (S)nap %s, (M)idpoints %s, (L)imit %.2f (Alt Wheel adjust) %s, Switch (I)sland, shift select vertices";
+ static char str[] =
+ "Mode(TAB) %s, "
+ "(S)nap %s, "
+ "(M)idpoints %s, "
+ "(L)imit %.2f (Alt Wheel adjust) %s, "
+ "Switch (I)sland, "
+ "shift select vertices";
char msg[HEADER_LENGTH];
ScrArea *sa = CTX_wm_area(C);
@@ -403,7 +412,9 @@ static bool stitch_check_edges_state_stitchable(UvEdge *edge, UvEdge *edge_iter,
}
/* calculate snapping for islands */
-static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final)
+static void stitch_calculate_island_snapping(
+ StitchState *state, PreviewPosition *preview_position, StitchPreviewer *preview,
+ IslandStitchData *island_stitch_data, int final)
{
BMesh *bm = state->em->bm;
int i;
@@ -484,7 +495,9 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition
-static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map, IslandStitchData *island_stitch_data)
+static void stitch_island_calculate_edge_rotation(
+ UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map,
+ IslandStitchData *island_stitch_data)
{
BMesh *bm = state->em->bm;
UvElement *element1, *element2;
@@ -538,7 +551,9 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta
}
-static void stitch_island_calculate_vert_rotation(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data)
+static void stitch_island_calculate_vert_rotation(
+ UvElement *element, StitchState *state,
+ IslandStitchData *island_stitch_data)
{
float edgecos = 1.0f, edgesin = 0.0f;
int index;
@@ -710,7 +725,9 @@ static void stitch_uv_edge_generate_linked_edges(GHash *edge_hash, StitchState *
/* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
-static void determine_uv_stitchability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data)
+static void determine_uv_stitchability(
+ UvElement *element, StitchState *state,
+ IslandStitchData *island_stitch_data)
{
int vert_index;
UvElement *element_iter;
@@ -732,7 +749,9 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I
}
}
-static void determine_uv_edge_stitchability(UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data)
+static void determine_uv_edge_stitchability(
+ UvEdge *edge, StitchState *state,
+ IslandStitchData *island_stitch_data)
{
UvEdge *edge_iter = edge->first;
@@ -747,7 +766,8 @@ static void determine_uv_edge_stitchability(UvEdge *edge, StitchState *state, Is
/* set preview buffer position of UV face in editface->tmp.l */
-static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position)
+static void stitch_set_face_preview_buffer_position(
+ BMFace *efa, StitchPreviewer *preview, PreviewPosition *preview_position)
{
int index = BM_elem_index_get(efa);
@@ -760,8 +780,9 @@ static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer
/* setup face preview for all coincident uvs and their faces */
-static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
- PreviewPosition *preview_position)
+static void stitch_setup_face_preview_for_uv_group(
+ UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position)
{
StitchPreviewer *preview = state->stitch_preview;
@@ -781,8 +802,9 @@ static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchSta
/* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
-static void stitch_validate_uv_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
- PreviewPosition *preview_position)
+static void stitch_validate_uv_stitchability(
+ UvElement *element, StitchState *state, IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position)
{
UvElement *element_iter;
StitchPreviewer *preview = state->stitch_preview;
@@ -817,8 +839,9 @@ static void stitch_validate_uv_stichability(UvElement *element, StitchState *sta
}
-static void stitch_validate_edge_stichability(UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data,
- PreviewPosition *preview_position)
+static void stitch_validate_edge_stitchability(
+ UvEdge *edge, StitchState *state, IslandStitchData *island_stitch_data,
+ PreviewPosition *preview_position)
{
UvEdge *edge_iter = edge->first;
StitchPreviewer *preview = state->stitch_preview;
@@ -844,10 +867,11 @@ static void stitch_validate_edge_stichability(UvEdge *edge, StitchState *state,
}
-static void stitch_propagate_uv_final_position(Scene *scene,
- UvElement *element, int index, PreviewPosition *preview_position,
- UVVertAverage *final_position, StitchState *state,
- const bool final)
+static void stitch_propagate_uv_final_position(
+ Scene *scene,
+ UvElement *element, int index, PreviewPosition *preview_position,
+ UVVertAverage *final_position, StitchState *state,
+ const bool final)
{
BMesh *bm = state->em->bm;
StitchPreviewer *preview = state->stitch_preview;
@@ -957,7 +981,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvElement *element = (UvElement *)state->selection_stack[i];
if (element->flag & STITCH_STITCHABLE_CANDIDATE) {
element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_uv_stichability(element, state, island_stitch_data, preview_position);
+ stitch_validate_uv_stitchability(element, state, island_stitch_data, preview_position);
}
else {
/* add to preview for unstitchable */
@@ -968,7 +992,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
UvEdge *edge = (UvEdge *)state->selection_stack[i];
if (edge->flag & STITCH_STITCHABLE_CANDIDATE) {
edge->flag &= ~STITCH_STITCHABLE_CANDIDATE;
- stitch_validate_edge_stichability(edge, state, island_stitch_data, preview_position);
+ stitch_validate_edge_stitchability(edge, state, island_stitch_data, preview_position);
}
else {
preview->num_unstitchable++;
@@ -1006,8 +1030,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
/* initialize the preview buffers */
preview->preview_polys = (float *)MEM_mallocN(preview->preview_uvs * sizeof(float) * 2, "tri_uv_stitch_prev");
preview->uvs_per_polygon = MEM_mallocN(preview->num_polys * sizeof(*preview->uvs_per_polygon), "tri_uv_stitch_prev");
- preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stichable_data");
- preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, "stitch_preview_unstichable_data");
+ preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable * sizeof(float) * preview_size, "stitch_preview_stitchable_data");
+ preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable * sizeof(float) * preview_size, "stitch_preview_unstitchable_data");
preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island] * sizeof(float) * 6, "static_island_preview_tris");
@@ -1019,7 +1043,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
/* copy data from MLoopUVs to the preview display buffers */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- /* just to test if face was added for processing. uvs of inselected vertices will return NULL */
+ /* just to test if face was added for processing. uvs of unselected vertices will return NULL */
UvElement *element = BM_uv_element_get(state->element_map, efa, BM_FACE_FIRST_LOOP(efa));
if (element) {
@@ -1253,7 +1277,10 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
/* only calculate rotation when an edge has been fully selected */
for (i = 0; i < state->total_separate_edges; i++) {
UvEdge *edge = state->edges + i;
- if ((edge->flag & STITCH_BOUNDARY) && (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)) {
+ if ((edge->flag & STITCH_BOUNDARY) &&
+ (state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
+ (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
+ {
stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
island_stitch_data[state->uvs[edge->uv1]->island].use_edge_rotation = true;
}
@@ -1263,8 +1290,11 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
if (final && state->clear_seams) {
for (i = 0; i < state->total_separate_edges; i++) {
UvEdge *edge = state->edges + i;
- if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
+ if ((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) &&
+ (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE))
+ {
BM_elem_flag_disable(edge->element->l->e, BM_ELEM_SEAM);
+ }
}
}
@@ -1329,8 +1359,10 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
else {
UvEdge *edge = state->selection_stack[i];
- stitch_propagate_uv_final_position(scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, state, final);
- stitch_propagate_uv_final_position(scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, state, final);
+ stitch_propagate_uv_final_position(
+ scene, state->uvs[edge->uv1], edge->uv1, preview_position, final_position, state, final);
+ stitch_propagate_uv_final_position(
+ scene, state->uvs[edge->uv2], edge->uv2, preview_position, final_position, state, final);
edge->flag &= (STITCH_SELECTED | STITCH_BOUNDARY);
}
@@ -1506,19 +1538,15 @@ static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *no
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
{
int i, index = 0;
- float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
StitchState *state = (StitchState *)arg;
StitchPreviewer *stitch_preview = state->stitch_preview;
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
- glPointSize(pointsize * 2.0f);
-
glEnable(GL_BLEND);
UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris);
glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris * 3);
@@ -1542,6 +1570,8 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar
/* draw vert preview */
if (state->mode == STITCH_VERT) {
+ glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) * 2.0f);
+
UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
@@ -1562,8 +1592,6 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar
glPopClientAttrib();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
- glPointSize(1.0);
}
static UvEdge *uv_edge_get(BMLoop *l, StitchState *state)
@@ -1709,8 +1737,11 @@ static int stitch_init(bContext *C, wmOperator *op)
counter = 0;
/* Now, on to generate our uv connectivity data */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
+ if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
+ ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
+ {
continue;
+ }
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
UvElement *element = BM_uv_element_get(state->element_map, efa, l);
@@ -1884,8 +1915,11 @@ static int stitch_init(bContext *C, wmOperator *op)
state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack) * state->total_separate_edges, "uv_stitch_selection_stack");
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
+ if (!(ts->uv_flag & UV_SYNC_SELECTION) &&
+ ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)))
+ {
continue;
+ }
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
@@ -2124,7 +2158,7 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
- /* Use Limit (Default off)*/
+ /* Use Limit (Default off) */
case LKEY:
if (event->val == KM_PRESS) {
state->use_limit = !state->use_limit;
@@ -2159,7 +2193,7 @@ static int stitch_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
break;
- /* Select geometry*/
+ /* Select geometry */
case RIGHTMOUSE:
if (!event->shift) {
stitch_cancel(C, op);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index f915a4b2e51..768624b1968 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -145,9 +145,15 @@ static bool ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
if (ima)
ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
- /* select new UV's */
+ /* select new UV's (ignore UV_SYNC_SELECTION in this case) */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- uvedit_face_select_enable(scene, em, efa, false, cd_loop_uv_offset);
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
}
return 1;
@@ -217,7 +223,7 @@ void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMesh *bm, float *aspx, floa
}
static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
- BMFace *efa, const int cd_loop_uv_offset)
+ BMFace *efa, int face_index, const int cd_loop_uv_offset)
{
ParamKey key;
ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
@@ -230,7 +236,7 @@ static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
BMIter liter;
BMLoop *l;
- key = (ParamKey)efa;
+ key = (ParamKey)face_index;
/* let parametrizer split the ngon, it can make better decisions
* about which split is best for unwrapping than scanfill */
@@ -256,6 +262,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
BMLoop *l;
BMEdge *eed;
BMIter iter, liter;
+ int i;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
@@ -273,7 +280,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
/* we need the vert indices */
BM_mesh_elem_index_ensure(bm, BM_VERT);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
continue;
@@ -293,7 +300,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMesh *bm,
}
}
- construct_param_handle_face_add(handle, scene, efa, cd_loop_uv_offset);
+ construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
}
if (!implicit) {
@@ -344,7 +351,8 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
{
ParamHandle *handle;
/* index pointers */
- MFace *face;
+ MPoly *mpoly;
+ MLoop *mloop;
MEdge *edge;
int i;
@@ -356,11 +364,12 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
/* Used to hold subsurfed Mesh */
DerivedMesh *derivedMesh, *initialDerived;
/* holds original indices for subsurfed mesh */
- const int *origVertIndices, *origEdgeIndices, *origFaceIndices, *origPolyIndices;
+ const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
/* Holds vertices of subsurfed mesh */
MVert *subsurfedVerts;
MEdge *subsurfedEdges;
- MFace *subsurfedFaces;
+ MPoly *subsurfedPolys;
+ MLoop *subsurfedLoops;
/* number of vertices and faces for subsurfed mesh*/
int numOfEdges, numOfFaces;
@@ -398,15 +407,15 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
/* get the derived data */
subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
- subsurfedFaces = derivedMesh->getTessFaceArray(derivedMesh);
+ subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
+ subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
- origFaceIndices = derivedMesh->getTessFaceDataArray(derivedMesh, CD_ORIGINDEX);
origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
numOfEdges = derivedMesh->getNumEdges(derivedMesh);
- numOfFaces = derivedMesh->getNumTessFaces(derivedMesh);
+ numOfFaces = derivedMesh->getNumPolys(derivedMesh);
faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
@@ -415,7 +424,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
/* map subsurfed faces to original editFaces */
for (i = 0; i < numOfFaces; i++)
- faceMap[i] = BM_face_at_index(em->bm, DM_origindex_mface_mpoly(origFaceIndices, origPolyIndices, i));
+ faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
@@ -427,15 +436,13 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
}
/* Prepare and feed faces to the solver */
- for (i = 0; i < numOfFaces; i++) {
+ for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
ParamKey key, vkeys[4];
ParamBool pin[4], select[4];
float *co[4];
float *uv[4];
BMFace *origFace = faceMap[i];
- face = subsurfedFaces + i;
-
if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN))
continue;
@@ -445,24 +452,27 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
continue;
}
+ mloop = &subsurfedLoops[mpoly->loopstart];
+
/* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
- key = (ParamKey)face;
- vkeys[0] = (ParamKey)face->v1;
- vkeys[1] = (ParamKey)face->v2;
- vkeys[2] = (ParamKey)face->v3;
- vkeys[3] = (ParamKey)face->v4;
-
- co[0] = subsurfedVerts[face->v1].co;
- co[1] = subsurfedVerts[face->v2].co;
- co[2] = subsurfedVerts[face->v3].co;
- co[3] = subsurfedVerts[face->v4].co;
+ BLI_assert(mpoly->totloop == 4);
+ key = (ParamKey)i;
+ vkeys[0] = (ParamKey)mloop[0].v;
+ vkeys[1] = (ParamKey)mloop[1].v;
+ vkeys[2] = (ParamKey)mloop[2].v;
+ vkeys[3] = (ParamKey)mloop[3].v;
+
+ co[0] = subsurfedVerts[mloop[0].v].co;
+ co[1] = subsurfedVerts[mloop[1].v].co;
+ co[2] = subsurfedVerts[mloop[2].v].co;
+ co[3] = subsurfedVerts[mloop[3].v].co;
/* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
* flushing the solution to the edit mesh. */
- texface_from_original_index(origFace, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset);
- texface_from_original_index(origFace, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset);
- texface_from_original_index(origFace, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset);
- texface_from_original_index(origFace, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset);
+ texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset);
param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL);
}
@@ -856,12 +866,12 @@ void ED_uvedit_live_unwrap(Scene *scene, Object *obedit)
static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result,
Object *ob, BMEditMesh *em)
{
- int around = (v3d) ? v3d->around : V3D_CENTER;
+ const int around = (v3d) ? v3d->around : V3D_AROUND_CENTER_BOUNDS;
/* only operates on the edit object - this is all that's needed now */
switch (around) {
- case V3D_CENTER: /* bounding box center */
+ case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
{
BMFace *efa;
BMLoop *l;
@@ -880,15 +890,15 @@ static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result,
mid_v3_v3v3(result, min, max);
break;
}
- case V3D_CURSOR: /* cursor center */
+ case V3D_AROUND_CURSOR: /* cursor center */
{
const float *curs = ED_view3d_cursor3d_get(scene, v3d);
/* shift to objects world */
sub_v3_v3v3(result, curs, ob->obmat[3]);
break;
}
- case V3D_LOCAL: /* object center */
- case V3D_CENTROID: /* multiple objects centers, only one object here*/
+ case V3D_AROUND_LOCAL_ORIGINS: /* object center */
+ case V3D_AROUND_CENTER_MEAN: /* multiple objects centers, only one object here*/
default:
zero_v3(result);
break;
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index c14a5c53734..f6b7efe978c 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -556,6 +556,7 @@ set(INC
.
../blenkernel
../blenlib
+ ../blentranslation
../imbuf
../makesdna
../makesrna
@@ -574,6 +575,10 @@ set(INC_SYS
add_definitions(-DWITH_FREESTYLE)
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
if(WIN32)
list(APPEND INC_SYS
${PTHREADS_INC}
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index 975b1212695..039a75a2f0f 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -34,11 +34,17 @@ struct Material;
struct FreestyleConfig;
struct FreestyleLineStyle;
-extern struct Scene *freestyle_scene;
-extern float freestyle_viewpoint[3];
-extern float freestyle_mv[4][4];
-extern float freestyle_proj[4][4];
-extern int freestyle_viewport[4];
+struct FreestyleGlobals {
+ struct Scene *scene;
+
+ /* camera information */
+ float viewpoint[3];
+ float mv[4][4];
+ float proj[4][4];
+ int viewport[4];
+};
+
+extern struct FreestyleGlobals g_freestyle;
/* Rendering */
void FRS_initialize(void);
diff --git a/source/blender/freestyle/SConscript b/source/blender/freestyle/SConscript
deleted file mode 100644
index cae04f8642c..00000000000
--- a/source/blender/freestyle/SConscript
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/python
-import sys
-Import ('env')
-
-sources = []
-
-incs = [
- '#/intern/guardedalloc',
- '#/extern/glew/include',
- '../blenkernel',
- '../blenlib',
- '../freestyle',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../python',
- '../python/intern',
- '../render/extern/include',
- '../render/intern/include',
- env['BF_PYTHON_INC'],
- env['BF_PNG_INC'],
- ]
-incs = ' '.join(incs)
-
-defs = ['WITH_FREESTYLE']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-########################################################
-# folders sources
-########################################################
-
-# system
-prefix = 'intern/system'
-system_sources = env.Glob(prefix + '/*.cpp')
-
-# image
-prefix = 'intern/image'
-image_sources = env.Glob(prefix + '/*.cpp')
-
-# geometry
-prefix = 'intern/geometry'
-geometry_sources = env.Glob(prefix + '/*.cpp')
-
-# scene_graph
-prefix = 'intern/scene_graph'
-scene_graph_sources = env.Glob(prefix + '/*.cpp')
-
-# winged_edge
-prefix = 'intern/winged_edge'
-winged_edge_sources = env.Glob(prefix + '/*.cpp')
-
-# view_map
-prefix = 'intern/view_map'
-view_map_sources = env.Glob(prefix + '/*.cpp')
-
-# stroke
-prefix = 'intern/stroke'
-stroke_sources = env.Glob(prefix + '/*.cpp')
-
-# application
-prefix = 'intern/application'
-application_sources = env.Glob(prefix + '/*.cpp')
-
-# blender_interface
-prefix = 'intern/blender_interface'
-interface_sources = env.Glob(prefix + '/*.cpp')
-
-# Python
-prefix = 'intern/python'
-python_sources = env.Glob(prefix + '/*.cpp') + \
- env.Glob(prefix + '/*/*.cpp') + \
- env.Glob(prefix + '/*/*/*.cpp') + \
- env.Glob(prefix + '/*/*/*/*.cpp')
-
-sources = system_sources + image_sources + geometry_sources + scene_graph_sources + \
- winged_edge_sources + view_map_sources + stroke_sources + \
- application_sources + interface_sources
-
-if False: # gives link errors 'win' in env['OURPLATFORM']:
- env.BlenderLib(libname="bf_freestyle_python", sources=python_sources, includes=Split(incs),
- defines=defs, libtype=['core'], priority = [369] # bf_python is 361
- )
-else:
- sources += python_sources
-
-env.BlenderLib(libname="bf_freestyle", sources=sources, includes=Split(incs),
- defines=defs, libtype=['core'], priority = [370] # bf_python is 361
-)
-
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
index 9de426b91ab..c331d1de9c9 100644
--- a/source/blender/freestyle/intern/application/AppView.cpp
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -110,7 +110,7 @@ real AppView::distanceToSceneCenter()
{
BBox<Vec3r> bbox = _ModelRootNode->bbox();
- Vec3r v(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+ Vec3r v(UNPACK3(g_freestyle.viewpoint));
v -= 0.5 * (bbox.getMin() + bbox.getMax());
return v.norm();
@@ -121,7 +121,7 @@ real AppView::znear()
BBox<Vec3r> bbox = _ModelRootNode->bbox();
Vec3r u = bbox.getMin();
Vec3r v = bbox.getMax();
- Vec3r cameraCenter(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+ Vec3r cameraCenter(UNPACK3(g_freestyle.viewpoint));
Vec3r w1(u[0], u[1], u[2]);
Vec3r w2(v[0], u[1], u[2]);
@@ -156,7 +156,7 @@ real AppView::zfar()
BBox<Vec3r> bbox = _ModelRootNode->bbox();
Vec3r u = bbox.getMin();
Vec3r v = bbox.getMax();
- Vec3r cameraCenter(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+ Vec3r cameraCenter(UNPACK3(g_freestyle.viewpoint));
Vec3r w1(u[0], u[1], u[2]);
Vec3r w2(v[0], u[1], u[2]);
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 8983a781237..136fec3dd1c 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -106,7 +106,9 @@ Controller::Controller()
_ProgressBar = new ProgressBar;
_SceneNumFaces = 0;
+#if 0
_minEdgeSize = DBL_MAX;
+#endif
_EPSILON = 1.0e-6;
_bboxDiag = 0;
@@ -264,9 +266,11 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
}
_SceneNumFaces += loader.numFacesRead();
+#if 0
if (loader.minEdgeSize() < _minEdgeSize) {
_minEdgeSize = loader.minEdgeSize();
}
+#endif
#if 0 // DEBUG
ScenePrettyPrinter spp;
@@ -285,14 +289,14 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
if (_EnableViewMapCache) {
NodeCamera *cam;
- if (freestyle_proj[3][3] != 0.0)
+ if (g_freestyle.proj[3][3] != 0.0)
cam = new NodeOrthographicCamera;
else
cam = new NodePerspectiveCamera;
double proj[16];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- proj[i * 4 + j] = freestyle_proj[i][j];
+ proj[i * 4 + j] = g_freestyle.proj[i][j];
}
}
cam->setProjectionMatrix(proj);
@@ -406,7 +410,9 @@ void Controller::DeleteWingedEdge()
_Grid.clear();
_Scene3dBBox.clear();
_SceneNumFaces = 0;
+#if 0
_minEdgeSize = DBL_MAX;
+#endif
}
void Controller::DeleteViewMap(bool freeCache)
@@ -471,7 +477,7 @@ void Controller::ComputeViewMap()
// Restore the context of view:
// we need to perform all these operations while the
// 3D context is on.
- Vec3f vp(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+ Vec3f vp(UNPACK3(g_freestyle.viewpoint));
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
@@ -481,7 +487,7 @@ void Controller::ComputeViewMap()
real mv[4][4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- mv[i][j] = freestyle_mv[i][j];
+ mv[i][j] = g_freestyle.mv[i][j];
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << mv[i][j] << " ";
@@ -503,7 +509,7 @@ void Controller::ComputeViewMap()
real proj[4][4];
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- proj[i][j] = freestyle_proj[i][j];
+ proj[i][j] = g_freestyle.proj[i][j];
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
cout << proj[i][j] << " ";
@@ -519,7 +525,7 @@ void Controller::ComputeViewMap()
int viewport[4];
for (int i = 0; i < 4; i++)
- viewport[i] = freestyle_viewport[i];
+ viewport[i] = g_freestyle.viewport[i];
#if 0
if (G.debug & G_DEBUG_FREESTYLE) {
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index 22eaaf5082f..6f3cb3b274b 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -209,7 +209,9 @@ private:
BBox<Vec3r> _Scene3dBBox;
unsigned int _SceneNumFaces;
+#if 0
real _minEdgeSize;
+#endif
real _EPSILON;
real _bboxDiag;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index 2b0d3b14697..ea5a55731c3 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -38,7 +38,9 @@ BlenderFileLoader::BlenderFileLoader(Render *re, SceneRenderLayer *srl)
_srl = srl;
_Scene = NULL;
_numFacesRead = 0;
+#if 0
_minEdgeSize = DBL_MAX;
+#endif
_smooth = (srl->freestyleConfig.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
_pRenderMonitor = NULL;
}
@@ -262,7 +264,10 @@ void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v
float n1[3], float n2[3], float n3[3],
bool fm, bool em1, bool em2, bool em3)
{
- float *fv[3], *fn[3], len;
+ float *fv[3], *fn[3];
+#if 0
+ float len;
+#endif
unsigned int i, j;
IndexedFaceSet::FaceEdgeMark marks = 0;
@@ -289,9 +294,11 @@ void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v
ls->maxBBox[j] = ls->pv[j];
}
+#if 0
len = len_v3v3(fv[i], fv[(i + 1) % 3]);
if (_minEdgeSize > len)
_minEdgeSize = len;
+#endif
*ls->pvi = ls->currentIndex;
*ls->pni = ls->currentIndex;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
index d16a311991a..894f8eeeb4e 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -87,8 +87,10 @@ public:
/*! Gets the number of read faces */
inline unsigned int numFacesRead() {return _numFacesRead;}
+#if 0
/*! Gets the smallest edge size read */
inline real minEdgeSize() {return _minEdgeSize;}
+#endif
/*! Modifiers */
inline void setRenderMonitor(RenderMonitor *iRenderMonitor) {_pRenderMonitor = iRenderMonitor;}
@@ -115,7 +117,9 @@ protected:
SceneRenderLayer *_srl;
NodeGroup *_Scene;
unsigned _numFacesRead;
+#if 0
real _minEdgeSize;
+#endif
bool _smooth; /* if true, face smoothness is taken into account */
float _viewplane_left;
float _viewplane_right;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 64ef49d74a3..5c361de8d8d 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -55,6 +55,8 @@ extern "C" {
#include "BLI_ghash.h"
#include "BLI_listbase.h"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "RE_pipeline.h"
@@ -113,7 +115,6 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine));
freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA;
freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
- BKE_scene_disable_color_management(freestyle_scene);
if (G.debug & G_DEBUG_FREESTYLE) {
printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
@@ -242,6 +243,8 @@ Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTr
PointerRNA fromptr, toptr;
NodeShaderAttribute *storage;
+ id_us_min(&ma->id);
+
if (iNodeTree) {
// make a copy of linestyle->nodetree
ntree = ntreeCopyTree_ex(iNodeTree, bmain, do_id_user);
@@ -513,6 +516,8 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
ma->mode |= MA_SHLESS;
ma->vcol_alpha = 1;
+ id_us_min(&ma->id);
+
// Textures
while (iStrokeRep->getMTex(a)) {
ma->mtex[a] = (MTex *)iStrokeRep->getMTex(a);
@@ -733,6 +738,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
it != itend; ++it)
{
mesh->mat[material_index] = (*it)->getMaterial();
+ id_us_plus(&mesh->mat[material_index]->id);
vector<Strip*>& strips = (*it)->getStrips();
for (vector<Strip*>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
@@ -871,38 +877,24 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
}
}
- // colors and alpha transparency
+ // colors and alpha transparency. vertex colors are in sRGB
+ // space by convention, so convert from linear
+ float rgba[3][4];
+
+ for (int i = 0; i < 3; i++) {
+ copy_v3fl_v3db(rgba[i], &svRep[i]->color()[0]);
+ rgba[i][3] = svRep[i]->alpha();
+ }
+
if (is_odd) {
- colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
- colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
- colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
- colors[0].a = (short)(255.0f * svRep[2]->alpha());
-
- colors[1].r = (short)(255.0f * svRep[0]->color()[0]);
- colors[1].g = (short)(255.0f * svRep[0]->color()[1]);
- colors[1].b = (short)(255.0f * svRep[0]->color()[2]);
- colors[1].a = (short)(255.0f * svRep[0]->alpha());
-
- colors[2].r = (short)(255.0f * svRep[1]->color()[0]);
- colors[2].g = (short)(255.0f * svRep[1]->color()[1]);
- colors[2].b = (short)(255.0f * svRep[1]->color()[2]);
- colors[2].a = (short)(255.0f * svRep[1]->alpha());
+ linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
+ linearrgb_to_srgb_uchar4(&colors[1].r, rgba[0]);
+ linearrgb_to_srgb_uchar4(&colors[2].r, rgba[1]);
}
else {
- colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
- colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
- colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
- colors[0].a = (short)(255.0f * svRep[2]->alpha());
-
- colors[1].r = (short)(255.0f * svRep[1]->color()[0]);
- colors[1].g = (short)(255.0f * svRep[1]->color()[1]);
- colors[1].b = (short)(255.0f * svRep[1]->color()[2]);
- colors[1].a = (short)(255.0f * svRep[1]->alpha());
-
- colors[2].r = (short)(255.0f * svRep[0]->color()[0]);
- colors[2].g = (short)(255.0f * svRep[0]->color()[1]);
- colors[2].b = (short)(255.0f * svRep[0]->color()[2]);
- colors[2].a = (short)(255.0f * svRep[0]->alpha());
+ linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
+ linearrgb_to_srgb_uchar4(&colors[1].r, rgba[1]);
+ linearrgb_to_srgb_uchar4(&colors[2].r, rgba[0]);
}
transp[0].r = transp[0].g = transp[0].b = colors[0].a;
transp[1].r = transp[1].g = transp[1].b = colors[1].a;
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index 46724ff530a..dc88f69c95b 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -54,6 +54,8 @@ extern "C" {
#include "BKE_text.h"
#include "BKE_context.h"
+#include "BLT_translation.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_callbacks.h"
@@ -68,6 +70,8 @@ extern "C" {
#define DEFAULT_SPHERE_RADIUS 1.0f
#define DEFAULT_DKR_EPSILON 0.0f
+struct FreestyleGlobals g_freestyle;
+
// Freestyle configuration
static bool freestyle_is_initialized = false;
static Config::Path *pathconfig = NULL;
@@ -78,14 +82,6 @@ static AppView *view = NULL;
static FreestyleLineSet lineset_buffer;
static bool lineset_copied = false;
-// camera information
-float freestyle_viewpoint[3];
-float freestyle_mv[4][4];
-float freestyle_proj[4][4];
-int freestyle_viewport[4];
-
-// current scene
-Scene *freestyle_scene;
static void load_post_callback(struct Main * /*main*/, struct ID * /*id*/, void * /*arg*/)
{
@@ -113,7 +109,7 @@ void FRS_initialize()
view = new AppView;
controller->setView(view);
controller->Clear();
- freestyle_scene = NULL;
+ g_freestyle.scene = NULL;
lineset_copied = false;
BLI_callback_add(&load_post_callback_funcstore, BLI_CB_EVT_LOAD_POST);
@@ -159,9 +155,9 @@ static void init_view(Render *re)
break;
}
- freestyle_viewport[0] = freestyle_viewport[1] = 0;
- freestyle_viewport[2] = width;
- freestyle_viewport[3] = height;
+ g_freestyle.viewport[0] = g_freestyle.viewport[1] = 0;
+ g_freestyle.viewport[2] = width;
+ g_freestyle.viewport[3] = height;
view->setWidth(width);
view->setHeight(height);
@@ -184,17 +180,15 @@ static void init_camera(Render *re)
// Therefore, the view point (i.e., camera position) is at the origin, and
// the model-view matrix is simply the identity matrix.
- freestyle_viewpoint[0] = 0.0;
- freestyle_viewpoint[1] = 0.0;
- freestyle_viewpoint[2] = 0.0;
+ zero_v3(g_freestyle.viewpoint);
- unit_m4(freestyle_mv);
+ unit_m4(g_freestyle.mv);
- copy_m4_m4(freestyle_proj, re->winmat);
+ copy_m4_m4(g_freestyle.proj, re->winmat);
#if 0
- print_m4("mv", freestyle_mv);
- print_m4("proj", freestyle_proj);
+ print_m4("mv", g_freestyle.mv);
+ print_m4("proj", g_freestyle.proj);
#endif
}
@@ -292,7 +286,7 @@ static bool test_edge_type_conditions(struct edge_type_condition *conditions,
static void prepare(Render *re, SceneRenderLayer *srl)
{
// load mesh
- re->i.infostr = "Freestyle: Mesh loading";
+ re->i.infostr = IFACE_("Freestyle: Mesh loading");
re->stats_draw(re->sdh, &re->i);
re->i.infostr = NULL;
if (controller->LoadMesh(re, srl)) // returns if scene cannot be loaded or if empty
@@ -475,7 +469,7 @@ static void prepare(Render *re, SceneRenderLayer *srl)
return;
// compute view map
- re->i.infostr = "Freestyle: View map creation";
+ re->i.infostr = IFACE_("Freestyle: View map creation");
re->stats_draw(re->sdh, &re->i);
re->i.infostr = NULL;
controller->ComputeViewMap();
@@ -630,14 +624,14 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
// render and composite Freestyle result
if (controller->_ViewMap) {
// render strokes
- re->i.infostr = "Freestyle: Stroke rendering";
+ re->i.infostr = IFACE_("Freestyle: Stroke rendering");
re->stats_draw(re->sdh, &re->i);
re->i.infostr = NULL;
- freestyle_scene = re->scene;
+ g_freestyle.scene = re->scene;
controller->DrawStrokes();
freestyle_render = controller->RenderStrokes(re, true);
controller->CloseFile();
- freestyle_scene = NULL;
+ g_freestyle.scene = NULL;
// composite result
FRS_composite_result(re, srl, freestyle_render);
@@ -698,10 +692,10 @@ void FRS_paste_active_lineset(FreestyleConfig *config)
if (lineset) {
if (lineset->linestyle)
- lineset->linestyle->id.us--;
+ id_us_min(&lineset->linestyle->id);
lineset->linestyle = lineset_buffer.linestyle;
if (lineset->linestyle)
- lineset->linestyle->id.us++;
+ id_us_plus(&lineset->linestyle->id);
lineset->flags = lineset_buffer.flags;
lineset->selection = lineset_buffer.selection;
lineset->qi = lineset_buffer.qi;
@@ -710,12 +704,12 @@ void FRS_paste_active_lineset(FreestyleConfig *config)
lineset->edge_types = lineset_buffer.edge_types;
lineset->exclude_edge_types = lineset_buffer.exclude_edge_types;
if (lineset->group) {
- lineset->group->id.us--;
+ id_us_min(&lineset->group->id);
lineset->group = NULL;
}
if (lineset_buffer.group) {
lineset->group = lineset_buffer.group;
- lineset->group->id.us++;
+ id_us_plus(&lineset->group->id);
}
strcpy(lineset->name, lineset_buffer.name);
BKE_freestyle_lineset_unique_name(config, lineset);
diff --git a/source/blender/freestyle/intern/geometry/GridHelpers.cpp b/source/blender/freestyle/intern/geometry/GridHelpers.cpp
index a0543e56a36..d969d3e3024 100644
--- a/source/blender/freestyle/intern/geometry/GridHelpers.cpp
+++ b/source/blender/freestyle/intern/geometry/GridHelpers.cpp
@@ -41,10 +41,10 @@ void GridHelpers::getDefaultViewProscenium(real viewProscenium[4])
// borderZone describes a blank border outside the proscenium, but still inside the image area.
// Only intended for exposing possible artifacts along or outside the proscenium edge during debugging.
const real borderZone = 0.0;
- viewProscenium[0] = freestyle_viewport[2] * (borderZone - bufferZone);
- viewProscenium[1] = freestyle_viewport[2] * (1.0f - borderZone + bufferZone);
- viewProscenium[2] = freestyle_viewport[3] * (borderZone - bufferZone);
- viewProscenium[3] = freestyle_viewport[3] * (1.0f - borderZone + bufferZone);
+ viewProscenium[0] = g_freestyle.viewport[2] * (borderZone - bufferZone);
+ viewProscenium[1] = g_freestyle.viewport[2] * (1.0f - borderZone + bufferZone);
+ viewProscenium[2] = g_freestyle.viewport[3] * (borderZone - bufferZone);
+ viewProscenium[3] = g_freestyle.viewport[3] * (1.0f - borderZone + bufferZone);
}
GridHelpers::Transform::~Transform ()
diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp
index 8ec56e84f95..dd5f2f6ea4c 100644
--- a/source/blender/freestyle/intern/geometry/Noise.cpp
+++ b/source/blender/freestyle/intern/geometry/Noise.cpp
@@ -147,7 +147,7 @@ float Noise::smoothNoise2(Vec2f& vec)
{
int bx0, bx1, by0, by1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
- register int i, j;
+ int i, j;
SETUP(vec.x(), bx0, bx1, rx0, rx1);
SETUP(vec.y(), by0, by1, ry0, ry1);
@@ -186,7 +186,7 @@ float Noise::smoothNoise3(Vec3f& vec)
{
int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
- register int i, j;
+ int i, j;
SETUP(vec.x(), bx0, bx1, rx0, rx1);
SETUP(vec.y(), by0, by1, ry0, ry1);
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index d22632040f4..f8aef2a08ae 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -74,12 +74,13 @@ static char Freestyle_getCurrentScene___doc__[] =
static PyObject *Freestyle_getCurrentScene(PyObject * /*self*/)
{
- if (!freestyle_scene) {
+ Scene *scene = g_freestyle.scene;
+ if (!scene) {
PyErr_SetString(PyExc_TypeError, "current scene not available");
return NULL;
}
PointerRNA ptr_scene;
- RNA_pointer_create(&freestyle_scene->id, &RNA_Scene, freestyle_scene, &ptr_scene);
+ RNA_pointer_create(&scene->id, &RNA_Scene, scene, &ptr_scene);
return pyrna_struct_CreatePyObject(&ptr_scene);
}
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
index 6e253b7bf5d..c07f94c9a05 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
@@ -54,25 +54,6 @@ PyDoc_STRVAR(ChainPredicateIterator_doc,
"predicate is kept as the next one. If none of the potential next\n"
"ViewEdge respects these two predicates, None is returned.\n"
"\n"
-".. method:: __init__(restrict_to_selection=True, restrict_to_unvisited=True, begin=None, orientation=True)\n"
-"\n"
-" Builds a ChainPredicateIterator from a starting ViewEdge and its\n"
-" orientation.\n"
-"\n"
-" :arg restrict_to_selection: Indicates whether to force the chaining\n"
-" to stay within the set of selected ViewEdges or not.\n"
-" :type restrict_to_selection: bool\n"
-" :arg restrict_to_unvisited: Indicates whether a ViewEdge that has\n"
-" already been chained must be ignored ot not.\n"
-" :type restrict_to_unvisited: bool\n"
-" :arg begin: The ViewEdge from where to start the iteration.\n"
-" :type begin: :class:`freestyle.types.ViewEdge` or None\n"
-" :arg orientation: If true, we'll look for the next ViewEdge among\n"
-" the ViewEdges that surround the ending ViewVertex of begin. If\n"
-" false, we'll search over the ViewEdges surrounding the ending\n"
-" ViewVertex of begin. \n"
-" :type orientation: bool\n"
-"\n"
".. method:: __init__(upred, bpred, restrict_to_selection=True, restrict_to_unvisited=True, begin=None, "
"orientation=True)\n"
"\n"
@@ -118,11 +99,14 @@ static int ChainPredicateIterator_init(BPy_ChainPredicateIterator *self, PyObjec
static const char *kwlist_1[] = {"brother", NULL};
static const char *kwlist_2[] = {"upred", "bpred", "restrict_to_selection", "restrict_to_unvisited", "begin",
"orientation", NULL};
- static const char *kwlist_3[] = {"restrict_to_selection", "restrict_to_unvisited", "begin", "orientation", NULL};
PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0, *obj4 = 0, *obj5 = 0, *obj6 = 0;
- if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &ChainingIterator_Type, &obj1)) {
+ if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &ChainPredicateIterator_Type, &obj1)) {
self->cp_it = new ChainPredicateIterator(*(((BPy_ChainPredicateIterator *)obj1)->cp_it));
+ self->upred = ((BPy_ChainPredicateIterator *)obj1)->upred;
+ self->bpred = ((BPy_ChainPredicateIterator *)obj1)->bpred;
+ Py_INCREF(self->upred);
+ Py_INCREF(self->bpred);
}
else if (PyErr_Clear(), (obj3 = obj4 = obj5 = obj6 = 0),
PyArg_ParseTupleAndKeywords(args, kwds, "O!O!|O!O!O&O!", (char **)kwlist_2,
@@ -143,19 +127,6 @@ static int ChainPredicateIterator_init(BPy_ChainPredicateIterator *self, PyObjec
Py_INCREF(self->upred);
Py_INCREF(self->bpred);
}
- else if (PyErr_Clear(), (obj1 = obj2 = obj3 = obj4 = 0),
- PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!O&O!", (char **)kwlist_3,
- &PyBool_Type, &obj1, &PyBool_Type, &obj2, check_begin, &obj3,
- &PyBool_Type, &obj4))
- {
- bool restrict_to_selection = (!obj1) ? true : bool_from_PyBool(obj1);
- bool restrict_to_unvisited = (!obj2) ? true : bool_from_PyBool(obj2);
- ViewEdge *begin = (!obj3 || obj3 == Py_None) ? NULL : ((BPy_ViewEdge *)obj3)->ve;
- bool orientation = (!obj4) ? true : bool_from_PyBool(obj4);
- self->cp_it = new ChainPredicateIterator(restrict_to_selection, restrict_to_unvisited, begin, orientation);
- self->upred = NULL;
- self->bpred = NULL;
- }
else {
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
return -1;
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
index 9d595c235c2..2af02ab5764 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
@@ -30,9 +30,9 @@ namespace Freestyle {
string SceneHash::toString()
{
- stringstream ss;
- ss << hex << _sum;
- return ss.str();
+ stringstream ss;
+ ss << hex << _sum;
+ return ss.str();
}
void SceneHash::visitNodeSceneRenderLayer(NodeSceneRenderLayer& node)
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.cpp b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
index 84d770a96cd..6cacdfedf21 100644
--- a/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
@@ -191,6 +191,8 @@ int ChainSilhouetteIterator::traverse(const AdjacencyIterator& ait)
int ChainPredicateIterator::traverse(const AdjacencyIterator& ait)
{
+ if (!_unary_predicate || !_binary_predicate)
+ return -1;
AdjacencyIterator it(ait);
// Iterates over next edges to see if one of them respects the predicate:
while (!it.isEnd()) {
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index 87ba34e8f42..dfb50d903f7 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -996,6 +996,8 @@ public:
inline bool operator()(Interface1D *i1, Interface1D *i2)
{
+ if (i1 == i2)
+ return false;
if ((*_pred)(*i1, *i2) < 0)
throw std::runtime_error("comparison failed");
return _pred->result;
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
index b4a3646edef..053015f459d 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.cpp
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -419,12 +419,7 @@ Stroke::Stroke(const Stroke& iBrother)
_textureId = iBrother._textureId;
_textureStep = iBrother._textureStep;
for (int a = 0; a < MAX_MTEX; a++) {
- if (iBrother._mtex) {
- _mtex[a] = iBrother._mtex[a];
- }
- else {
- _mtex[a] = NULL;
- }
+ _mtex[a] = iBrother._mtex[a];
}
_nodeTree = iBrother._nodeTree;
_tips = iBrother._tips;
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index ddb79b2df0b..5403ec6b13b 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -78,22 +78,22 @@ public:
BKE_reports_clear(reports);
char *fn = const_cast<char*>(filename.c_str());
#if 0
- int status = BPY_filepath_exec(_context, fn, reports);
+ bool ok = BPY_execute_filepath(_context, fn, reports);
#else
- int status;
+ bool ok;
Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name);
if (text) {
- status = BPY_text_exec(_context, text, reports, false);
+ ok = BPY_execute_text(_context, text, reports, false);
BKE_text_unlink(&_freestyle_bmain, text);
BKE_libblock_free(&_freestyle_bmain, text);
}
else {
BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn);
- status = 0;
+ ok = false;
}
#endif
- if (status != 1) {
+ if (ok == false) {
cerr << "\nError executing Python script from PythonInterpreter::interpretFile" << endl;
cerr << "File: " << fn << endl;
cerr << "Errors: " << endl;
@@ -113,7 +113,7 @@ public:
BKE_reports_clear(reports);
- if (BPY_string_exec(_context, str.c_str()) != 0) {
+ if (!BPY_execute_string(_context, str.c_str())) {
BPy_errors_to_report(reports);
cerr << "\nError executing Python script from PythonInterpreter::interpretString" << endl;
cerr << "Name: " << name << endl;
@@ -133,7 +133,7 @@ public:
BKE_reports_clear(reports);
- if (!BPY_text_exec(_context, text, reports, false)) {
+ if (!BPY_execute_text(_context, text, reports, false)) {
cerr << "\nError executing Python script from PythonInterpreter::interpretText" << endl;
cerr << "Name: " << name << endl;
cerr << "Errors: " << endl;
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
index 87ca3a4235f..99aa2d22239 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
@@ -640,18 +640,19 @@ WFace *WShape::MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeM
vector<WVertex *>::iterator it;
// compute the face normal (v1v2 ^ v1v3)
- WVertex *v1, *v2, *v3;
+ // Double precision numbers are used here to avoid truncation errors [T47705]
+ Vec3r v1, v2, v3;
it = iVertexList.begin();
- v1 = *it;
+ v1 = (*it)->GetVertex();
it++;
- v2 = *it;
+ v2 = (*it)->GetVertex();
it++;
- v3 = *it;
+ v3 = (*it)->GetVertex();
- Vec3f vector1(v2->GetVertex() - v1->GetVertex());
- Vec3f vector2(v3->GetVertex() - v1->GetVertex());
+ Vec3r vector1(v2 - v1);
+ Vec3r vector2(v3 - v1);
- Vec3f normal(vector1 ^ vector2);
+ Vec3r normal(vector1 ^ vector2);
normal.normalize();
face->setNormal(normal);
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 328623f884f..cfa083116f2 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -46,19 +46,19 @@ set(INC_SYS
)
set(SRC
+ intern/gpu_basic_shader.c
intern/gpu_buffers.c
intern/gpu_codegen.c
+ intern/gpu_compositing.c
+ intern/gpu_debug.c
intern/gpu_draw.c
intern/gpu_extensions.c
+ intern/gpu_framebuffer.c
intern/gpu_init_exit.c
intern/gpu_material.c
- intern/gpu_simple_shader.c
intern/gpu_select.c
- intern/gpu_compositing.c
- intern/gpu_debug.c
-
- shaders/gpu_program_smoke_frag.glsl
- shaders/gpu_program_smoke_color_frag.glsl
+ intern/gpu_shader.c
+ intern/gpu_texture.c
shaders/gpu_shader_fx_lib.glsl
shaders/gpu_shader_fx_ssao_frag.glsl
@@ -71,35 +71,42 @@ set(SRC
shaders/gpu_shader_material.glsl
shaders/gpu_shader_sep_gaussian_blur_frag.glsl
shaders/gpu_shader_sep_gaussian_blur_vert.glsl
- shaders/gpu_shader_simple_frag.glsl
- shaders/gpu_shader_simple_vert.glsl
+ shaders/gpu_shader_basic_frag.glsl
+ shaders/gpu_shader_basic_vert.glsl
+ shaders/gpu_shader_basic_geom.glsl
shaders/gpu_shader_vertex.glsl
shaders/gpu_shader_vsm_store_frag.glsl
shaders/gpu_shader_vsm_store_vert.glsl
shaders/gpu_shader_fx_depth_resolve.glsl
+ shaders/gpu_shader_smoke_frag.glsl
+ shaders/gpu_shader_smoke_vert.glsl
+ GPU_basic_shader.h
GPU_buffers.h
- GPU_draw.h
+ GPU_compositing.h
GPU_debug.h
+ GPU_draw.h
GPU_extensions.h
+ GPU_framebuffer.h
GPU_glew.h
GPU_init_exit.h
GPU_material.h
- GPU_simple_shader.h
GPU_select.h
- GPU_compositing.h
+ GPU_shader.h
+ GPU_texture.h
intern/gpu_codegen.h
intern/gpu_private.h
)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
-data_to_c_simple(shaders/gpu_program_smoke_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_simple_frag.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_simple_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_basic_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_basic_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_basic_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
diff --git a/source/blender/gpu/GPU_basic_shader.h b/source/blender/gpu/GPU_basic_shader.h
new file mode 100644
index 00000000000..df2da971845
--- /dev/null
+++ b/source/blender/gpu/GPU_basic_shader.h
@@ -0,0 +1,118 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_basic_shader.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_BASIC_SHADER_H__
+#define __GPU_BASIC_SHADER_H__
+
+#include "BLI_utildefines.h"
+#include "GPU_glew.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Fixed Function Shader */
+
+typedef enum GPUBasicShaderOption {
+ GPU_SHADER_USE_COLOR = (1 << 0), /* use glColor, for lighting it replaces diffuse */
+ GPU_SHADER_LIGHTING = (1 << 1), /* use lighting */
+ GPU_SHADER_TWO_SIDED = (1 << 2), /* flip normals towards viewer */
+ GPU_SHADER_TEXTURE_2D = (1 << 3), /* use 2D texture to replace diffuse color */
+
+ GPU_SHADER_SOLID_LIGHTING = (1 << 4), /* use faster lighting (set automatically) */
+ GPU_SHADER_STIPPLE = (1 << 5), /* use stipple */
+ GPU_SHADER_LINE = (1 << 6), /* draw lines */
+ GPU_SHADER_OPTIONS_NUM = 7,
+ GPU_SHADER_OPTION_COMBINATIONS = (1 << GPU_SHADER_OPTIONS_NUM)
+} GPUBasicShaderOption;
+
+/* Keep these in sync with gpu_shader_basic_frag.glsl */
+typedef enum GPUBasicShaderStipple {
+ GPU_SHADER_STIPPLE_HALFTONE = 0,
+ GPU_SHADER_STIPPLE_QUARTTONE = 1,
+ GPU_SHADER_STIPPLE_CHECKER_8PX = 2,
+ GPU_SHADER_STIPPLE_HEXAGON = 3,
+ GPU_SHADER_STIPPLE_DIAG_STRIPES = 4,
+ GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP = 5,
+ GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW = 6,
+ GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP = 7,
+ GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN = 8,
+ GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP = 9,
+ GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER = 10,
+ GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP = 11
+} GPUBasicShaderStipple;
+
+void GPU_basic_shaders_init(void);
+void GPU_basic_shaders_exit(void);
+
+void GPU_basic_shader_bind(int options);
+int GPU_basic_shader_bound_options(void);
+
+void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
+ int shininess, float alpha);
+
+/* Fixed Function Lighting */
+
+typedef enum GPULightType {
+ GPU_LIGHT_POINT,
+ GPU_LIGHT_SPOT,
+ GPU_LIGHT_SUN
+} GPULightType;
+
+typedef struct GPULightData {
+ GPULightType type;
+
+ float position[3];
+ float direction[3];
+
+ float diffuse[3];
+ float specular[3];
+
+ float constant_attenuation;
+ float linear_attenuation;
+ float quadratic_attenuation;
+
+ float spot_cutoff;
+ float spot_exponent;
+} GPULightData;
+
+void GPU_basic_shader_light_set(int light_num, GPULightData *light);
+void GPU_basic_shader_light_set_viewer(bool local);
+void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id);
+void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern);
+void GPU_basic_shader_line_width(float line_width);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index e653af0c7ec..a8656c05224 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -54,9 +54,7 @@ struct MVert;
typedef struct GPUBuffer {
size_t size; /* in bytes */
- void *pointer; /* used with vertex arrays */
unsigned int id; /* used with vertex buffer objects */
- bool use_vbo; /* true for VBOs, false for vertex arrays */
} GPUBuffer;
typedef struct GPUBufferMaterial {
@@ -156,7 +154,7 @@ typedef struct GPUAttrib {
void GPU_global_buffer_pool_free(void);
void GPU_global_buffer_pool_free_unused(void);
-GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays);
+GPUBuffer *GPU_buffer_alloc(size_t size);
void GPU_buffer_free(GPUBuffer *buffer);
void GPU_drawobject_free(struct DerivedMesh *dm);
@@ -231,7 +229,7 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
unsigned int **grid_hidden, int gridsize, const struct CCGKey *key);
-GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading);
+GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading);
/* update */
diff --git a/source/blender/gpu/GPU_compositing.h b/source/blender/gpu/GPU_compositing.h
index 04e89da00a7..d506d91a9aa 100644
--- a/source/blender/gpu/GPU_compositing.h
+++ b/source/blender/gpu/GPU_compositing.h
@@ -44,6 +44,7 @@ struct GPUOffScreen;
struct GPUFXSettings;
struct rcti;
struct Scene;
+struct GPUShader;
enum eGPUFXFlags;
/**** Public API *****/
@@ -82,7 +83,9 @@ bool GPU_fx_compositor_initialize_passes(
const struct GPUFXSettings *fx_settings);
/* do compositing on the fx passes that have been initialized */
-bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs);
+bool GPU_fx_do_composite_pass(
+ GPUFX *fx, float projmat[4][4], bool is_persp,
+ struct Scene *scene, struct GPUOffScreen *ofs);
/* bind new depth buffer for XRay pass */
void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray);
@@ -92,6 +95,10 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx);
void GPU_fx_compositor_init_dof_settings(struct GPUDOFSettings *dof);
void GPU_fx_compositor_init_ssao_settings(struct GPUSSAOSettings *ssao);
+
+
+/* initialize and cache the shader unform interface for effects */
+void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 0992f8e9d21..75d6362f13e 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -63,7 +63,7 @@ void GPU_state_init(void);
* - first the state is initialized by a particular object and
* it's materials
* - after this, materials can be quickly enabled by their number,
- * GPU_enable_material returns 0 if drawing should be skipped
+ * GPU_object_material_bind returns 0 if drawing should be skipped
* - after drawing, the material must be disabled again */
void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d,
@@ -71,8 +71,9 @@ void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d,
void GPU_end_object_materials(void);
bool GPU_object_materials_check(void);
-int GPU_enable_material(int nr, void *attribs);
-void GPU_disable_material(void);
+int GPU_object_material_bind(int nr, void *attribs);
+void GPU_object_material_unbind(void);
+int GPU_object_material_visible(int nr, void *attribs);
void GPU_begin_dupli_object(struct DupliObject *dob);
void GPU_end_dupli_object(void);
@@ -128,13 +129,16 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap);
/* Image updates and free
* - these deal with images bound as opengl textures */
-void GPU_paint_update_image(struct Image *ima, ImageUser *iuser, int x, int y, int w, int h);
+void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
void GPU_update_images_framechange(void);
int GPU_update_image_time(struct Image *ima, double time);
-int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data);
+int GPU_verify_image(struct Image *ima,
+ struct ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data);
void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
- bool mipmap, bool use_hight_bit_depth, struct Image *ima);
-void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, struct Image *ima, struct ImBuf *ibuf);
+ int textarget, bool mipmap, bool use_hight_bit_depth, struct Image *ima);
+void GPU_create_gl_tex_compressed(
+ unsigned int *bind, unsigned int *pix, int x, int y, int mipmap,
+ int textarget, struct Image *ima, struct ImBuf *ibuf);
bool GPU_upload_dxt_texture(struct ImBuf *ibuf);
void GPU_free_image(struct Image *ima);
void GPU_free_images(void);
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 0e8d204d224..4a728c881b6 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -36,38 +36,24 @@
extern "C" {
#endif
-struct Image;
-struct ImageUser;
-struct PreviewImage;
-
-struct GPUTexture;
-typedef struct GPUTexture GPUTexture;
-
-struct GPUFrameBuffer;
-typedef struct GPUFrameBuffer GPUFrameBuffer;
-
-struct GPUOffScreen;
-typedef struct GPUOffScreen GPUOffScreen;
-
-struct GPUShader;
-typedef struct GPUShader GPUShader;
-
-struct GPUProgram;
-typedef struct GPUProgram GPUProgram;
-
/* GPU extensions support */
void GPU_extensions_disable(void);
+bool GPU_legacy_support(void);
bool GPU_glsl_support(void);
-bool GPU_non_power_of_two_support(void);
-bool GPU_vertex_buffer_support(void);
+bool GPU_full_non_power_of_two_support(void);
bool GPU_display_list_support(void);
bool GPU_bicubic_bump_support(void);
bool GPU_geometry_shader_support(void);
+bool GPU_geometry_shader_support_via_extension(void);
bool GPU_instanced_drawing_support(void);
int GPU_max_texture_size(void);
+int GPU_max_textures(void);
+float GPU_max_texture_anisotropy(void);
+int GPU_max_color_texture_samples(void);
+int GPU_max_cube_map_size(void);
int GPU_color_depth(void);
void GPU_get_dfdy_factors(float fac[2]);
@@ -79,194 +65,30 @@ void GPU_code_generate_glsl_lib(void);
/* GPU Types */
typedef enum GPUDeviceType {
- GPU_DEVICE_NVIDIA = (1<<0),
- GPU_DEVICE_ATI = (1<<1),
- GPU_DEVICE_INTEL = (1<<2),
- GPU_DEVICE_SOFTWARE = (1<<3),
- GPU_DEVICE_UNKNOWN = (1<<4),
+ GPU_DEVICE_NVIDIA = (1 << 0),
+ GPU_DEVICE_ATI = (1 << 1),
+ GPU_DEVICE_INTEL = (1 << 2),
+ GPU_DEVICE_SOFTWARE = (1 << 3),
+ GPU_DEVICE_UNKNOWN = (1 << 4),
GPU_DEVICE_ANY = (0xff)
} GPUDeviceType;
typedef enum GPUOSType {
- GPU_OS_WIN = (1<<8),
- GPU_OS_MAC = (1<<9),
- GPU_OS_UNIX = (1<<10),
+ GPU_OS_WIN = (1 << 8),
+ GPU_OS_MAC = (1 << 9),
+ GPU_OS_UNIX = (1 << 10),
GPU_OS_ANY = (0xff00)
} GPUOSType;
typedef enum GPUDriverType {
- GPU_DRIVER_OFFICIAL = (1<<16),
- GPU_DRIVER_OPENSOURCE = (1<<17),
- GPU_DRIVER_SOFTWARE = (1<<18),
+ GPU_DRIVER_OFFICIAL = (1 << 16),
+ GPU_DRIVER_OPENSOURCE = (1 << 17),
+ GPU_DRIVER_SOFTWARE = (1 << 18),
GPU_DRIVER_ANY = (0xff0000)
} GPUDriverType;
bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver);
-/* GPU Texture
- * - always returns unsigned char RGBA textures
- * - if texture with non square dimensions is created, depending on the
- * graphics card capabilities the texture may actually be stored in a
- * larger texture with power of two dimensions. the actual dimensions
- * may be queried with GPU_texture_opengl_width/height. GPU_texture_coord_2f
- * calls glTexCoord2f with the coordinates adjusted for this.
- * - can use reference counting:
- * - reference counter after GPU_texture_create is 1
- * - GPU_texture_ref increases by one
- * - GPU_texture_free decreases by one, and frees if 0
- * - if created with from_blender, will not free the texture
- */
-
-typedef enum GPUHDRType {
- GPU_HDR_NONE = 0,
- GPU_HDR_HALF_FLOAT = 1,
- GPU_HDR_FULL_FLOAT = (1 << 1),
-} GPUHDRType;
-
-GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
-GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
-GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
-GPUTexture *GPU_texture_from_blender(struct Image *ima,
- struct ImageUser *iuser, bool is_data, double time, int mipmap);
-GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
-void GPU_invalid_tex_init(void);
-void GPU_invalid_tex_bind(int mode);
-void GPU_invalid_tex_free(void);
-
-void GPU_texture_free(GPUTexture *tex);
-
-void GPU_texture_ref(GPUTexture *tex);
-
-void GPU_texture_bind(GPUTexture *tex, int number);
-void GPU_texture_unbind(GPUTexture *tex);
-
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
-
-GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
-
-int GPU_texture_target(const GPUTexture *tex);
-int GPU_texture_opengl_width(const GPUTexture *tex);
-int GPU_texture_opengl_height(const GPUTexture *tex);
-int GPU_texture_opengl_bindcode(const GPUTexture *tex);
-
-/* GPU Framebuffer
- * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
- * multiple FBO's may be created, to get around limitations on the number
- * of attached textures and the dimension requirements.
- * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must
- * be called before rendering to the window framebuffer again */
-
-void GPU_texture_bind_as_framebuffer(GPUTexture *tex);
-
-GPUFrameBuffer *GPU_framebuffer_create(void);
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]);
-void GPU_framebuffer_texture_detach(GPUTexture *tex);
-void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot);
-void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex);
-void GPU_framebuffer_free(GPUFrameBuffer *fb);
-bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
-
-void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot);
-
-void GPU_framebuffer_restore(void);
-void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex);
-
-/* GPU OffScreen
- * - wrapper around framebuffer and texture for simple offscreen drawing
- * - changes size if graphics card can't support it */
-
-GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256]);
-void GPU_offscreen_free(GPUOffScreen *ofs);
-void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
-void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
-void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
-int GPU_offscreen_width(const GPUOffScreen *ofs);
-int GPU_offscreen_height(const GPUOffScreen *ofs);
-
-/* Builtin/Non-generated shaders */
-typedef enum GPUProgramType {
- GPU_PROGRAM_TYPE_FRAGMENT = 0
-} GPUProgramType;
-
-
-GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code);
-void GPU_program_free(GPUProgram *program);
-void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w);
-void GPU_program_bind(GPUProgram *);
-void GPU_program_unbind(GPUProgram *);
-
-/* GPU Shader
- * - only for fragment shaders now
- * - must call texture bind before setting a texture as uniform! */
-
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number);
-enum {
- GPU_SHADER_FLAGS_NONE = 0,
- GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0),
-};
-GPUShader *GPU_shader_create_ex(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- int input,
- int output,
- int number,
- const int flags);
-void GPU_shader_free(GPUShader *shader);
-
-void GPU_shader_bind(GPUShader *shader);
-void GPU_shader_unbind(void);
-
-int GPU_shader_get_uniform(GPUShader *shader, const char *name);
-void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
- int arraysize, const float *value);
-void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
- int arraysize, const int *value);
-
-void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
-void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
-void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
-
-int GPU_shader_get_attribute(GPUShader *shader, const char *name);
-
-/* Builtin/Non-generated shaders */
-typedef enum GPUBuiltinShader {
- GPU_SHADER_VSM_STORE = 0,
- GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
-} GPUBuiltinShader;
-
-typedef enum GPUBuiltinProgram {
- GPU_PROGRAM_SMOKE = 0,
- GPU_PROGRAM_SMOKE_COLORED = 1,
-} GPUBuiltinProgram;
-
-GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
-GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program);
-GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
-
-void GPU_shader_free_builtin_shaders(void);
-
-/* Vertex attributes for shaders */
-
-#define GPU_MAX_ATTRIB 32
-
-typedef struct GPUVertexAttribs {
- struct {
- int type;
- int glindex;
- int gltexco;
- int attribid;
- char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
- } layer[GPU_MAX_ATTRIB];
-
- int totlayer;
-} GPUVertexAttribs;
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
new file mode 100644
index 00000000000..2719b8fa6a8
--- /dev/null
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -0,0 +1,86 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_framebuffer.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_FRAMEBUFFER_H__
+#define __GPU_FRAMEBUFFER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct GPUFrameBuffer GPUFrameBuffer;
+typedef struct GPUOffScreen GPUOffScreen;
+struct GPUTexture;
+
+/* GPU Framebuffer
+ * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice
+ * multiple FBO's may be created, to get around limitations on the number
+ * of attached textures and the dimension requirements.
+ * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must
+ * be called before rendering to the window framebuffer again */
+
+void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex);
+
+GPUFrameBuffer *GPU_framebuffer_create(void);
+int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]);
+void GPU_framebuffer_texture_detach(struct GPUTexture *tex);
+void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot);
+void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex);
+void GPU_framebuffer_free(GPUFrameBuffer *fb);
+bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
+
+void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot);
+
+bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
+
+void GPU_framebuffer_restore(void);
+void GPU_framebuffer_blur(
+ GPUFrameBuffer *fb, struct GPUTexture *tex,
+ GPUFrameBuffer *blurfb, struct GPUTexture *blurtex);
+
+/* GPU OffScreen
+ * - wrapper around framebuffer and texture for simple offscreen drawing
+ * - changes size if graphics card can't support it */
+
+GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]);
+void GPU_offscreen_free(GPUOffScreen *ofs);
+void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
+void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
+void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
+int GPU_offscreen_width(const GPUOffScreen *ofs);
+int GPU_offscreen_height(const GPUOffScreen *ofs);
+int GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_FRAMEBUFFER_H__ */
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index dd08ed83e5a..81b08e2b128 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -78,6 +78,7 @@ typedef enum GPUType {
GPU_TEX2D = 1002,
GPU_SHADOW2D = 1003,
+ GPU_TEXCUBE = 1004,
GPU_ATTRIB = 3001
} GPUType;
@@ -95,6 +96,8 @@ typedef enum GPUBuiltin {
GPU_PARTICLE_LOCATION = (1 << 10),
GPU_PARTICLE_VELOCITY = (1 << 11),
GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
+ GPU_LOC_TO_VIEW_MATRIX = (1 << 13),
+ GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -148,6 +151,8 @@ typedef enum GPUDynamicType {
GPU_DYNAMIC_OBJECT_IMAT = 4 | GPU_DYNAMIC_GROUP_OBJECT,
GPU_DYNAMIC_OBJECT_COLOR = 5 | GPU_DYNAMIC_GROUP_OBJECT,
GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 6 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT = 7 | GPU_DYNAMIC_GROUP_OBJECT,
+ GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT = 8 | GPU_DYNAMIC_GROUP_OBJECT,
GPU_DYNAMIC_LAMP_DYNVEC = 1 | GPU_DYNAMIC_GROUP_LAMP,
GPU_DYNAMIC_LAMP_DYNCO = 2 | GPU_DYNAMIC_GROUP_LAMP,
@@ -160,6 +165,10 @@ typedef enum GPUDynamicType {
GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP,
GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP,
GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_SPOTSCALE = 12 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_COEFFCONST = 13 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_COEFFLIN = 14 | GPU_DYNAMIC_GROUP_LAMP,
+ GPU_DYNAMIC_LAMP_COEFFQUAD = 15 | GPU_DYNAMIC_GROUP_LAMP,
GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER,
GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER,
@@ -174,6 +183,7 @@ typedef enum GPUDynamicType {
GPU_DYNAMIC_HORIZON_COLOR = 1 | GPU_DYNAMIC_GROUP_WORLD,
GPU_DYNAMIC_AMBIENT_COLOR = 2 | GPU_DYNAMIC_GROUP_WORLD,
+ GPU_DYNAMIC_ZENITH_COLOR = 3 | GPU_DYNAMIC_GROUP_WORLD,
GPU_DYNAMIC_MAT_DIFFRGB = 1 | GPU_DYNAMIC_GROUP_MAT,
GPU_DYNAMIC_MAT_REF = 2 | GPU_DYNAMIC_GROUP_MAT,
@@ -182,13 +192,15 @@ typedef enum GPUDynamicType {
GPU_DYNAMIC_MAT_HARD = 5 | GPU_DYNAMIC_GROUP_MAT,
GPU_DYNAMIC_MAT_EMIT = 6 | GPU_DYNAMIC_GROUP_MAT,
GPU_DYNAMIC_MAT_AMB = 7 | GPU_DYNAMIC_GROUP_MAT,
- GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT
+ GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT,
+ GPU_DYNAMIC_MAT_MIR = 9 | GPU_DYNAMIC_GROUP_MAT
} GPUDynamicType;
GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_uniform(float *num);
GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data);
GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
+GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data);
GPUNodeLink *GPU_image_preview(struct PreviewImage *prv);
GPUNodeLink *GPU_texture(int size, float *pixels);
GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, GPUDynamicType dynamictype, void *data);
@@ -213,8 +225,12 @@ void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
-void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
-void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale, GPUParticleInfo *pi);
+void GPU_material_bind(
+ GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
+ float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
+void GPU_material_bind_uniforms(
+ GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
+ float autobumpscale, GPUParticleInfo *pi);
void GPU_material_unbind(GPUMaterial *material);
bool GPU_material_bound(GPUMaterial *material);
struct Scene *GPU_material_scene(GPUMaterial *material);
@@ -234,7 +250,7 @@ typedef struct GPUShadeInput {
GPUNodeLink *rgb, *specrgb, *vn, *view, *vcol, *ref;
GPUNodeLink *alpha, *refl, *spec, *emit, *har, *amb;
- GPUNodeLink *spectra;
+ GPUNodeLink *spectra, *mir, *refcol;
} GPUShadeInput;
typedef struct GPUShadeResult {
@@ -268,7 +284,8 @@ typedef struct GPUInputUniform {
struct Image *image; /* when type=GPU_DYNAMIC_SAMPLER_2DIMAGE */
int texnumber; /* when type=GPU_DYNAMIC_SAMPLER, texture number: 0.. */
unsigned char *texpixels; /* for internally generated texture, pixel data in RGBA format */
- int texsize; /* size in pixel of the texture in texpixels buffer: for 2D textures, this is S and T size (square texture) */
+ int texsize; /* size in pixel of the texture in texpixels buffer:
+ * for 2D textures, this is S and T size (square texture) */
} GPUInputUniform;
typedef struct GPUInputAttribute {
@@ -300,13 +317,18 @@ void GPU_lamp_update_buffer_mats(GPULamp *lamp);
void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]);
void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp);
int GPU_lamp_shadow_buffer_type(GPULamp *lamp);
+int GPU_lamp_shadow_bind_code(GPULamp *lamp);
+float *GPU_lamp_dynpersmat(GPULamp *lamp);
void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]);
void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy);
-void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2);
+void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2,
+ float coeff_const, float coeff_lin, float coeff_quad);
void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
int GPU_lamp_shadow_layer(GPULamp *lamp);
-GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy);
+GPUNodeLink *GPU_lamp_get_data(
+ GPUMaterial *mat, GPULamp *lamp,
+ GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy);
/* World */
void GPU_mist_update_enable(short enable);
@@ -314,13 +336,13 @@ void GPU_mist_update_values(int type, float start, float dist, float inten, floa
void GPU_horizon_update_color(float color[3]);
void GPU_ambient_update_color(float color[3]);
-typedef struct GPUParticleInfo
+struct GPUParticleInfo
{
float scalprops[4];
float location[3];
float velocity[3];
float angular_velocity[3];
-} GPUParticleInfo;
+};
#ifdef WITH_OPENSUBDIV
struct DerivedMesh;
@@ -333,4 +355,3 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
#endif
#endif /*__GPU_MATERIAL_H__*/
-
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index 09137fc998b..6a16b5b7456 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -40,22 +40,9 @@ enum {
GPU_SELECT_NEAREST_SECOND_PASS = 3,
};
-/* initialize and provide buffer for results */
void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits);
-
-/* loads a new selection id and ends previous query, if any. In second pass of selection it also returns
- * if id has been hit on the first pass already. Thus we can skip drawing un-hit objects IMPORTANT: We rely on the order of object rendering on passes to be
- * the same for this to work */
bool GPU_select_load_id(unsigned int id);
-
-/* cleanup and flush selection results to buffer. Return number of hits and hits in buffer.
- * if dopass is true, we will do a second pass with occlusion queries to get the closest hit */
unsigned int GPU_select_end(void);
-
-/* does the GPU support occlusion queries? */
-bool GPU_select_query_check_support(void);
-
-/* is occlusion query supported and user activated? */
bool GPU_select_query_check_active(void);
#endif
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
new file mode 100644
index 00000000000..4c674b460aa
--- /dev/null
+++ b/source/blender/gpu/GPU_shader.h
@@ -0,0 +1,119 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_shader.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_SHADER_H__
+#define __GPU_SHADER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct GPUShader GPUShader;
+struct GPUTexture;
+
+/* GPU Shader
+ * - only for fragment shaders now
+ * - must call texture bind before setting a texture as uniform! */
+
+enum {
+ GPU_SHADER_FLAGS_NONE = 0,
+ GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0),
+ GPU_SHADER_FLAGS_NEW_SHADING = (1 << 1),
+};
+
+GPUShader *GPU_shader_create(
+ const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ int input, int output, int number);
+GPUShader *GPU_shader_create_ex(
+ const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ int input, int output, int number,
+ const int flags);
+void GPU_shader_free(GPUShader *shader);
+
+void GPU_shader_bind(GPUShader *shader);
+void GPU_shader_unbind(void);
+
+void *GPU_shader_get_interface(GPUShader *shader);
+void GPU_shader_set_interface(GPUShader *shader, void *interface);
+int GPU_shader_get_uniform(GPUShader *shader, const char *name);
+void GPU_shader_uniform_vector(GPUShader *shader, int location, int length,
+ int arraysize, const float *value);
+void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length,
+ int arraysize, const int *value);
+
+void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex);
+void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
+void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number);
+
+int GPU_shader_get_attribute(GPUShader *shader, const char *name);
+
+/* Builtin/Non-generated shaders */
+typedef enum GPUBuiltinShader {
+ GPU_SHADER_VSM_STORE = 0,
+ GPU_SHADER_SEP_GAUSSIAN_BLUR = 1,
+ GPU_SHADER_SMOKE = 2,
+ GPU_SHADER_SMOKE_FIRE = 3,
+} GPUBuiltinShader;
+
+GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader);
+GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp);
+
+void GPU_shader_free_builtin_shaders(void);
+
+/* Vertex attributes for shaders */
+
+#define GPU_MAX_ATTRIB 32
+
+typedef struct GPUVertexAttribs {
+ struct {
+ int type;
+ int glindex;
+ int gltexco;
+ int attribid;
+ char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
+ } layer[GPU_MAX_ATTRIB];
+
+ int totlayer;
+} GPUVertexAttribs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_SHADER_H__ */
diff --git a/source/blender/gpu/GPU_simple_shader.h b/source/blender/gpu/GPU_simple_shader.h
deleted file mode 100644
index 239296209b4..00000000000
--- a/source/blender/gpu/GPU_simple_shader.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file GPU_simple_shader.h
- * \ingroup gpu
- */
-
-#ifndef __GPU_SIMPLE_SHADER_H__
-#define __GPU_SIMPLE_SHADER_H__
-
-#include "BLI_utildefines.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Fixed Function Shader */
-
-typedef enum GPUSimpleShaderOption {
- GPU_SHADER_OVERRIDE_DIFFUSE = (1<<0), /* replace diffuse with glcolor */
- GPU_SHADER_LIGHTING = (1<<1), /* use lighting */
- GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */
- GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */
-
- GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */
- GPU_SHADER_OPTIONS_NUM = 5,
- GPU_SHADER_OPTION_COMBINATIONS = (1<<GPU_SHADER_OPTIONS_NUM)
-} GPUSimpleShaderOption;
-
-void GPU_simple_shaders_init(void);
-void GPU_simple_shaders_exit(void);
-
-void GPU_simple_shader_bind(int options);
-void GPU_simple_shader_unbind(void);
-
-void GPU_simple_shader_colors(const float diffuse[3], const float specular[3],
- int shininess, float alpha);
-
-bool GPU_simple_shader_need_normals(void);
-
-/* Fixed Function Lighting */
-
-typedef struct GPULightData {
- float position[4];
- float diffuse[4];
- float specular[4];
-
- float constant_attenuation;
- float linear_attenuation;
- float quadratic_attenuation;
-
- float spot_direction[3];
- float spot_cutoff;
- float spot_exponent;
-} GPULightData;
-
-void GPU_simple_shader_light_set(int light_num, GPULightData *light);
-void GPU_simple_shader_light_set_viewer(bool local);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
new file mode 100644
index 00000000000..756fe79151b
--- /dev/null
+++ b/source/blender/gpu/GPU_texture.h
@@ -0,0 +1,105 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_texture.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_TEXTURE_H__
+#define __GPU_TEXTURE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Image;
+struct ImageUser;
+struct PreviewImage;
+
+struct GPUFrameBuffer;
+typedef struct GPUTexture GPUTexture;
+
+/* GPU Texture
+ * - always returns unsigned char RGBA textures
+ * - if texture with non square dimensions is created, depending on the
+ * graphics card capabilities the texture may actually be stored in a
+ * larger texture with power of two dimensions.
+ * - can use reference counting:
+ * - reference counter after GPU_texture_create is 1
+ * - GPU_texture_ref increases by one
+ * - GPU_texture_free decreases by one, and frees if 0
+ * - if created with from_blender, will not free the texture
+ */
+
+typedef enum GPUHDRType {
+ GPU_HDR_NONE = 0,
+ GPU_HDR_HALF_FLOAT = 1,
+ GPU_HDR_FULL_FLOAT = (1 << 1),
+} GPUHDRType;
+
+GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]);
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
+GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]);
+GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
+GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
+GPUTexture *GPU_texture_create_2D_multisample(
+ int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]);
+GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]);
+GPUTexture *GPU_texture_from_blender(
+ struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap);
+GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
+void GPU_invalid_tex_init(void);
+void GPU_invalid_tex_bind(int mode);
+void GPU_invalid_tex_free(void);
+
+void GPU_texture_free(GPUTexture *tex);
+
+void GPU_texture_ref(GPUTexture *tex);
+
+void GPU_texture_bind(GPUTexture *tex, int number);
+void GPU_texture_unbind(GPUTexture *tex);
+int GPU_texture_bound_number(GPUTexture *tex);
+
+void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter);
+
+struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex);
+int GPU_texture_framebuffer_attachment(GPUTexture *tex);
+void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment);
+
+int GPU_texture_target(const GPUTexture *tex);
+int GPU_texture_width(const GPUTexture *tex);
+int GPU_texture_height(const GPUTexture *tex);
+int GPU_texture_depth(const GPUTexture *tex);
+int GPU_texture_opengl_bindcode(const GPUTexture *tex);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPU_TEXTURE_H__ */
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
deleted file mode 100644
index d27d5b09b56..00000000000
--- a/source/blender/gpu/SConscript
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-sources += env.Glob('shaders/*.c')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '.',
- '#/intern/glew-mx',
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/smoke/extern',
- '../blenkernel',
- '../blenlib',
- '../bmesh',
- '../imbuf',
- '../include',
- '../makesdna',
- '../makesrna',
- '../nodes',
- '../nodes/intern',
- ]
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-if env['WITH_BF_SMOKE']:
- defs.append('WITH_SMOKE')
-
-if env['WITH_BF_DDS']:
- defs.append('WITH_DDS')
-
-if env['WITH_BF_OPENSUBDIV']:
- defs.append('WITH_OPENSUBDIV')
-
-# generated data files
-import os
-sources.extend((
- os.path.join(env['DATA_SOURCES'], "gpu_shader_geometry.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_vert.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_geo.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_vert.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_depth_resolve.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_lib.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_vert.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_material.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_sep_gaussian_blur_vert.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex_world.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_frag.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_vert.glsl.c"),
- ))
-
-env.BlenderLib('bf_gpu', sources, incs, defines=defs, libtype=['core', 'player'], priority=[160, 110])
diff --git a/source/blender/gpu/intern/gpu_basic_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c
new file mode 100644
index 00000000000..b6fe40a13ee
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_basic_shader.c
@@ -0,0 +1,645 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_basic_shader.c
+ * \ingroup gpu
+ *
+ * GLSL shaders to replace fixed function OpenGL materials and lighting. These
+ * are deprecated in newer OpenGL versions and missing in OpenGL ES 2.0. Also,
+ * two sided lighting is no longer natively supported on NVidia cards which
+ * results in slow software fallback.
+ *
+ * Todo:
+ * - Replace glLight and glMaterial functions entirely with GLSL uniforms, to
+ * make OpenGL ES 2.0 work.
+ * - Replace glTexCoord and glColor with generic attributes.
+ * - Optimize for case where fewer than 3 or 8 lights are used.
+ * - Optimize for case where specular is not used.
+ * - Optimize for case where no texture matrix is used.
+ */
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "GPU_basic_shader.h"
+#include "GPU_glew.h"
+#include "GPU_shader.h"
+
+/* State */
+
+static const bool USE_GLSL = false;
+
+static struct {
+ GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
+ bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
+
+ int bound_options;
+
+ int lights_enabled;
+ int lights_directional;
+ float line_width;
+ GLint viewport[4];
+} GPU_MATERIAL_STATE;
+
+
+/* Stipple patterns */
+/* ******************************************** */
+const GLubyte stipple_halftone[128] = {
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
+
+const GLubyte stipple_quarttone[128] = {
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0,
+ 136, 136, 136, 136, 0, 0, 0, 0, 34, 34, 34, 34, 0, 0, 0, 0};
+
+const GLubyte stipple_diag_stripes_pos[128] = {
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
+ 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
+ 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
+ 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
+ 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
+ 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
+ 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
+ 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
+ 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
+ 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
+ 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
+ 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
+ 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
+ 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
+ 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f};
+
+const GLubyte stipple_diag_stripes_neg[128] = {
+ 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
+ 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
+ 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
+ 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
+ 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
+ 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
+ 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80,
+ 0xff, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xfe, 0x01,
+ 0xfc, 0x03, 0xfc, 0x03, 0xf8, 0x07, 0xf8, 0x07,
+ 0xf0, 0x0f, 0xf0, 0x0f, 0xe0, 0x1f, 0xe0, 0x1f,
+ 0xc0, 0x3f, 0xc0, 0x3f, 0x80, 0x7f, 0x80, 0x7f,
+ 0x00, 0xff, 0x00, 0xff, 0x01, 0xfe, 0x01, 0xfe,
+ 0x03, 0xfc, 0x03, 0xfc, 0x07, 0xf8, 0x07, 0xf8,
+ 0x0f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0, 0x1f, 0xe0,
+ 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0x80, 0x7f, 0x80};
+
+const GLubyte stipple_checker_8px[128] = {
+ 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
+ 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
+ 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
+ 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
+ 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
+ 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
+ 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
+ 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255};
+
+const GLubyte stipple_interlace_row[128] = {
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00};
+
+const GLubyte stipple_interlace_row_swap[128] = {
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};
+
+const GLubyte stipple_interlace_column[128] = {
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
+
+const GLubyte stipple_interlace_column_swap[128] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa};
+
+const GLubyte stipple_interlace_checker[128] = {
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa};
+
+const GLubyte stipple_interlace_checker_swap[128] = {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55};
+
+const GLubyte stipple_hexagon[128] = {
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
+/* ********************************************* */
+
+/* Init / exit */
+
+void GPU_basic_shaders_init(void)
+{
+ memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE));
+}
+
+void GPU_basic_shaders_exit(void)
+{
+ int i;
+
+ for (i = 0; i < GPU_SHADER_OPTION_COMBINATIONS; i++)
+ if (GPU_MATERIAL_STATE.cached_shaders[i])
+ GPU_shader_free(GPU_MATERIAL_STATE.cached_shaders[i]);
+}
+
+/* Shader lookup / create */
+
+static bool solid_compatible_lighting(void)
+{
+ int enabled = GPU_MATERIAL_STATE.lights_enabled;
+ int directional = GPU_MATERIAL_STATE.lights_directional;
+
+ /* more than 3 lights? */
+ if (enabled >= (1 << 3))
+ return false;
+
+ /* all directional? */
+ return ((directional & enabled) == enabled);
+}
+
+#if 0
+static int detect_options()
+{
+ GLint two_sided;
+ int options = 0;
+
+ if (glIsEnabled(GL_TEXTURE_2D))
+ options |= GPU_SHADER_TEXTURE_2D;
+ if (glIsEnabled(GL_COLOR_MATERIAL))
+ options |= GPU_SHADER_USE_COLOR;
+
+ if (glIsEnabled(GL_LIGHTING))
+ options |= GPU_SHADER_LIGHTING;
+
+ glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &two_sided);
+ if (two_sided == GL_TRUE)
+ options |= GPU_SHADER_TWO_SIDED;
+
+ return options;
+}
+#endif
+
+static GPUShader *gpu_basic_shader(int options)
+{
+ /* glsl code */
+ extern char datatoc_gpu_shader_basic_vert_glsl[];
+ extern char datatoc_gpu_shader_basic_frag_glsl[];
+ extern char datatoc_gpu_shader_basic_geom_glsl[];
+ char *geom_glsl = NULL;
+ GPUShader *shader;
+
+ /* detect if we can do faster lighting for solid draw mode */
+ if (options & GPU_SHADER_LIGHTING)
+ if (solid_compatible_lighting())
+ options |= GPU_SHADER_SOLID_LIGHTING;
+
+ /* cached shaders */
+ shader = GPU_MATERIAL_STATE.cached_shaders[options];
+
+ if (!shader && !GPU_MATERIAL_STATE.failed_shaders[options]) {
+ /* create shader if it doesn't exist yet */
+ char defines[64 * GPU_SHADER_OPTIONS_NUM] = "";
+
+ if (options & GPU_SHADER_USE_COLOR)
+ strcat(defines, "#define USE_COLOR\n");
+ if (options & GPU_SHADER_TWO_SIDED)
+ strcat(defines, "#define USE_TWO_SIDED\n");
+ if (options & GPU_SHADER_TEXTURE_2D)
+ strcat(defines, "#define USE_TEXTURE\n");
+ if (options & GPU_SHADER_STIPPLE)
+ strcat(defines, "#define USE_STIPPLE\n");
+ if (options & GPU_SHADER_LINE) {
+ strcat(defines, "#define DRAW_LINE\n");
+ geom_glsl = datatoc_gpu_shader_basic_geom_glsl;
+ }
+ if (options & GPU_SHADER_SOLID_LIGHTING)
+ strcat(defines, "#define USE_SOLID_LIGHTING\n");
+ else if (options & GPU_SHADER_LIGHTING)
+ strcat(defines, "#define USE_SCENE_LIGHTING\n");
+
+ shader = GPU_shader_create(
+ datatoc_gpu_shader_basic_vert_glsl,
+ datatoc_gpu_shader_basic_frag_glsl,
+ geom_glsl,
+ NULL,
+ defines, 0, 0, 0);
+
+ if (shader) {
+ /* set texture map to first texture unit */
+ if (options & GPU_SHADER_TEXTURE_2D) {
+ GPU_shader_bind(shader);
+ glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
+ GPU_shader_unbind();
+ }
+
+ GPU_MATERIAL_STATE.cached_shaders[options] = shader;
+ }
+ else
+ GPU_MATERIAL_STATE.failed_shaders[options] = true;
+ }
+
+ return shader;
+}
+
+static void GPU_basic_shader_uniform_autoset(GPUShader *shader, int options)
+{
+ if (options & GPU_SHADER_LINE) {
+ glGetIntegerv(GL_VIEWPORT, &GPU_MATERIAL_STATE.viewport[0]);
+ glUniform4iv(GPU_shader_get_uniform(shader, "viewport"), 1, &GPU_MATERIAL_STATE.viewport[0]);
+ glUniform1f(GPU_shader_get_uniform(shader, "line_width"), GPU_MATERIAL_STATE.line_width);
+ }
+}
+
+/* Bind / unbind */
+
+void GPU_basic_shader_bind(int options)
+{
+ if (USE_GLSL) {
+ if (options) {
+ GPUShader *shader = gpu_basic_shader(options);
+
+ if (shader) {
+ GPU_shader_bind(shader);
+ GPU_basic_shader_uniform_autoset(shader, options);
+ }
+ }
+ else {
+ GPU_shader_unbind();
+ }
+ }
+ else {
+ int bound_options = GPU_MATERIAL_STATE.bound_options;
+
+ if (options & GPU_SHADER_LIGHTING) {
+ glEnable(GL_LIGHTING);
+
+ if (options & GPU_SHADER_USE_COLOR)
+ glEnable(GL_COLOR_MATERIAL);
+ else
+ glDisable(GL_COLOR_MATERIAL);
+
+ if (options & GPU_SHADER_TWO_SIDED)
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+ else
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+ }
+ else if (bound_options & GPU_SHADER_LIGHTING) {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
+ }
+
+ if (options & GPU_SHADER_TEXTURE_2D) {
+ GLint env_mode = (options & (GPU_SHADER_USE_COLOR | GPU_SHADER_LIGHTING)) ? GL_MODULATE : GL_REPLACE;
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env_mode);
+ }
+ else if (bound_options & GPU_SHADER_TEXTURE_2D) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if ((options & GPU_SHADER_LINE) && (options & GPU_SHADER_STIPPLE)) {
+ glEnable(GL_LINE_STIPPLE);
+ }
+ else if ((bound_options & GPU_SHADER_LINE) && (bound_options & GPU_SHADER_STIPPLE)) {
+ glDisable(GL_LINE_STIPPLE);
+ }
+ else {
+ if (options & GPU_SHADER_STIPPLE)
+ glEnable(GL_POLYGON_STIPPLE);
+ else if (bound_options & GPU_SHADER_STIPPLE)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+
+ }
+
+ GPU_MATERIAL_STATE.bound_options = options;
+}
+
+int GPU_basic_shader_bound_options(void)
+{
+ /* ideally this should disappear, anything that uses this is making fragile
+ * assumptions that the basic shader is bound and not another shader */
+ return GPU_MATERIAL_STATE.bound_options;
+}
+
+/* Material Colors */
+
+void GPU_basic_shader_colors(const float diffuse[3], const float specular[3],
+ int shininess, float alpha)
+{
+ float gl_diffuse[4], gl_specular[4];
+
+ if (diffuse)
+ copy_v3_v3(gl_diffuse, diffuse);
+ else
+ zero_v3(gl_diffuse);
+ gl_diffuse[3] = alpha;
+
+ if (specular)
+ copy_v3_v3(gl_specular, specular);
+ else
+ zero_v3(gl_specular);
+ gl_specular[3] = 1.0f;
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gl_specular);
+ glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
+}
+
+void GPU_basic_shader_light_set(int light_num, GPULightData *light)
+{
+ int light_bit = (1 << light_num);
+
+ /* note that light position is affected by the current modelview matrix! */
+
+ GPU_MATERIAL_STATE.lights_enabled &= ~light_bit;
+ GPU_MATERIAL_STATE.lights_directional &= ~light_bit;
+
+ if (light) {
+ float position[4], diffuse[4], specular[4];
+
+ glEnable(GL_LIGHT0 + light_num);
+
+ /* position */
+ if (light->type == GPU_LIGHT_SUN) {
+ copy_v3_v3(position, light->direction);
+ position[3] = 0.0f;
+ }
+ else {
+ copy_v3_v3(position, light->position);
+ position[3] = 1.0f;
+ }
+ glLightfv(GL_LIGHT0 + light_num, GL_POSITION, position);
+
+ /* energy */
+ copy_v3_v3(diffuse, light->diffuse);
+ copy_v3_v3(specular, light->specular);
+ diffuse[3] = 1.0f;
+ specular[3] = 1.0f;
+ glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, diffuse);
+ glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, specular);
+
+ /* attenuation */
+ if (light->type == GPU_LIGHT_SUN) {
+ glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, 1.0f);
+ glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, 0.0f);
+ glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, 0.0f);
+ }
+ else {
+ glLightf(GL_LIGHT0 + light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation);
+ glLightf(GL_LIGHT0 + light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation);
+ glLightf(GL_LIGHT0 + light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation);
+ }
+
+ /* spot */
+ glLightfv(GL_LIGHT0 + light_num, GL_SPOT_DIRECTION, light->direction);
+ if (light->type == GPU_LIGHT_SPOT) {
+ glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, light->spot_cutoff);
+ glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, light->spot_exponent);
+ }
+ else {
+ glLightf(GL_LIGHT0 + light_num, GL_SPOT_CUTOFF, 180.0f);
+ glLightf(GL_LIGHT0 + light_num, GL_SPOT_EXPONENT, 0.0f);
+ }
+
+ GPU_MATERIAL_STATE.lights_enabled |= light_bit;
+ if (position[3] == 0.0f)
+ GPU_MATERIAL_STATE.lights_directional |= light_bit;
+ }
+ else {
+ if (USE_GLSL) {
+ /* glsl shader needs these zero to skip them */
+ const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ glLightfv(GL_LIGHT0 + light_num, GL_POSITION, zero);
+ glLightfv(GL_LIGHT0 + light_num, GL_DIFFUSE, zero);
+ glLightfv(GL_LIGHT0 + light_num, GL_SPECULAR, zero);
+ }
+
+ glDisable(GL_LIGHT0 + light_num);
+ }
+}
+
+void GPU_basic_shader_light_set_viewer(bool local)
+{
+ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local) ? GL_TRUE: GL_FALSE);
+}
+
+void GPU_basic_shader_stipple(GPUBasicShaderStipple stipple_id)
+{
+ if (USE_GLSL) {
+ glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_id"), stipple_id);
+ }
+ else {
+ switch (stipple_id) {
+ case GPU_SHADER_STIPPLE_HALFTONE:
+ glPolygonStipple(stipple_halftone);
+ return;
+ case GPU_SHADER_STIPPLE_QUARTTONE:
+ glPolygonStipple(stipple_quarttone);
+ return;
+ case GPU_SHADER_STIPPLE_CHECKER_8PX:
+ glPolygonStipple(stipple_checker_8px);
+ return;
+ case GPU_SHADER_STIPPLE_HEXAGON:
+ glPolygonStipple(stipple_hexagon);
+ return;
+ case GPU_SHADER_STIPPLE_DIAG_STRIPES_SWAP:
+ glPolygonStipple(stipple_diag_stripes_neg);
+ return;
+ case GPU_SHADER_STIPPLE_DIAG_STRIPES:
+ glPolygonStipple(stipple_diag_stripes_pos);
+ return;
+ case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW:
+ glPolygonStipple(stipple_interlace_row);
+ return;
+ case GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP:
+ glPolygonStipple(stipple_interlace_row_swap);
+ return;
+ case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN:
+ glPolygonStipple(stipple_interlace_column);
+ return;
+ case GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP:
+ glPolygonStipple(stipple_interlace_column_swap);
+ return;
+ case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER:
+ glPolygonStipple(stipple_interlace_checker);
+ return;
+ case GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP:
+ glPolygonStipple(stipple_interlace_checker_swap);
+ return;
+ default:
+ glPolygonStipple(stipple_hexagon);
+ return;
+ }
+ }
+}
+
+void GPU_basic_shader_line_width(float line_width)
+{
+ if (USE_GLSL) {
+ GPU_MATERIAL_STATE.line_width = line_width;
+ if (GPU_MATERIAL_STATE.bound_options & GPU_SHADER_LINE) {
+ glUniform1f(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "line_width"), line_width);
+ }
+ }
+ else {
+ glLineWidth(line_width);
+ }
+}
+
+void GPU_basic_shader_line_stipple(GLint stipple_factor, GLushort stipple_pattern)
+{
+ if (USE_GLSL) {
+ glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_factor"), stipple_factor);
+ glUniform1i(GPU_shader_get_uniform(gpu_basic_shader(GPU_MATERIAL_STATE.bound_options), "stipple_pattern"), stipple_pattern);
+ }
+ else {
+ glLineStipple(stipple_factor, stipple_pattern);
+ }
+}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index b4617b9790e..072ff5235bf 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -28,8 +28,7 @@
/** \file blender/gpu/intern/gpu_buffers.c
* \ingroup gpu
*
- * Mesh drawing using OpenGL VBO (Vertex Buffer Objects),
- * with fall-back to vertex arrays.
+ * Mesh drawing using OpenGL VBO (Vertex Buffer Objects)
*/
#include <limits.h>
@@ -58,6 +57,7 @@
#include "GPU_buffers.h"
#include "GPU_draw.h"
+#include "GPU_basic_shader.h"
#include "bmesh.h"
@@ -80,28 +80,27 @@ static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type);
const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
/* vertex */
- {GL_ARRAY_BUFFER_ARB, 3},
+ {GL_ARRAY_BUFFER, 3},
/* normal */
- {GL_ARRAY_BUFFER_ARB, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */
+ {GL_ARRAY_BUFFER, 4}, /* we copy 3 shorts per normal but we add a fourth for alignment */
/* mcol */
- {GL_ARRAY_BUFFER_ARB, 3},
+ {GL_ARRAY_BUFFER, 3},
/* uv */
- {GL_ARRAY_BUFFER_ARB, 2},
+ {GL_ARRAY_BUFFER, 2},
/* uv for texpaint */
- {GL_ARRAY_BUFFER_ARB, 4},
+ {GL_ARRAY_BUFFER, 4},
/* edge */
- {GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
+ {GL_ELEMENT_ARRAY_BUFFER, 2},
/* uv edge */
- {GL_ELEMENT_ARRAY_BUFFER_ARB, 4},
+ {GL_ELEMENT_ARRAY_BUFFER, 4},
/* triangles, 1 point since we are allocating from tottriangle points, which account for all points */
- {GL_ELEMENT_ARRAY_BUFFER_ARB, 1},
+ {GL_ELEMENT_ARRAY_BUFFER, 1},
};
#define MAX_GPU_ATTRIB_DATA 32
#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n))
-/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
static GPUBufferState GLStates = 0;
static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
@@ -209,10 +208,7 @@ static void gpu_buffer_pool_delete_last(GPUBufferPool *pool)
return;
/* delete the buffer's data */
- if (last->use_vbo)
- glDeleteBuffersARB(1, &last->id);
- else
- MEM_freeN(last->pointer);
+ glDeleteBuffers(1, &last->id);
/* delete the buffer and remove from pool */
MEM_freeN(last);
@@ -273,7 +269,7 @@ void GPU_global_buffer_pool_free_unused(void)
*
* Thread-unsafe version for internal usage only.
*/
-static GPUBuffer *gpu_buffer_alloc_intern(size_t size, bool use_VBO)
+static GPUBuffer *gpu_buffer_alloc_intern(size_t size)
{
GPUBufferPool *pool;
GPUBuffer *buf;
@@ -298,11 +294,6 @@ static GPUBuffer *gpu_buffer_alloc_intern(size_t size, bool use_VBO)
* twice as big */
for (i = 0; i < pool->totbuf; i++) {
bufsize = pool->buffers[i]->size;
-
- /* only return a buffer that matches the VBO preference */
- if (pool->buffers[i]->use_vbo != use_VBO) {
- continue;
- }
/* check for an exact size match */
if (bufsize == size) {
@@ -332,44 +323,19 @@ static GPUBuffer *gpu_buffer_alloc_intern(size_t size, bool use_VBO)
/* no acceptable buffer found in the pool, create a new one */
buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer");
buf->size = size;
- buf->use_vbo = use_VBO;
-
- if (use_VBO) {
- /* create a new VBO and initialize it to the requested
- * size */
- glGenBuffersARB(1, &buf->id);
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, buf->id);
- glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, GL_STATIC_DRAW_ARB);
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
- }
- else {
- static int time = 0;
- buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
-
- time++;
- /* purpose of this seems to be dealing with
- * out-of-memory errors? looks a bit iffy to me
- * though, at least on Linux I expect malloc() would
- * just overcommit. --nicholas */
- while (!buf->pointer && pool->totbuf > 0) {
- gpu_buffer_pool_delete_last(pool);
- buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
- }
- if (!buf->pointer) {
- MEM_freeN(buf);
- return NULL;
- }
- }
+ glGenBuffers(1, &buf->id);
+ glBindBuffer(GL_ARRAY_BUFFER, buf->id);
+ glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
return buf;
}
/* Same as above, but safe for threading. */
-GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays)
+GPUBuffer *GPU_buffer_alloc(size_t size)
{
GPUBuffer *buffer;
- bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO) && !force_vertex_arrays;
if (size == 0) {
/* Early out, no lock needed in this case. */
@@ -377,7 +343,7 @@ GPUBuffer *GPU_buffer_alloc(size_t size, bool force_vertex_arrays)
}
BLI_mutex_lock(&buffer_mutex);
- buffer = gpu_buffer_alloc_intern(size, use_VBOs);
+ buffer = gpu_buffer_alloc_intern(size);
BLI_mutex_unlock(&buffer_mutex);
return buffer;
@@ -451,9 +417,7 @@ void GPU_buffer_multires_free(bool force)
if (force && BLI_thread_is_main()) {
if (mres_glob_buffer) {
if (mres_glob_buffer->id)
- glDeleteBuffersARB(1, &mres_glob_buffer->id);
- else if (mres_glob_buffer->pointer)
- MEM_freeN(mres_glob_buffer->pointer);
+ glDeleteBuffers(1, &mres_glob_buffer->id);
MEM_freeN(mres_glob_buffer);
}
}
@@ -502,7 +466,7 @@ void GPU_drawobject_free(DerivedMesh *dm)
dm->drawObject = NULL;
}
-static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t size, bool use_VBOs)
+static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t size)
{
/* try freeing an entry from the pool
* and reallocating the buffer */
@@ -512,24 +476,22 @@ static GPUBuffer *gpu_try_realloc(GPUBufferPool *pool, GPUBuffer *buffer, size_t
while (pool->totbuf && !buffer) {
gpu_buffer_pool_delete_last(pool);
- buffer = gpu_buffer_alloc_intern(size, use_VBOs);
+ buffer = gpu_buffer_alloc_intern(size);
}
return buffer;
}
static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
- int type, void *user)
+ int type, void *user, GPUBuffer *buffer)
{
GPUBufferPool *pool;
- GPUBuffer *buffer;
float *varray;
int *mat_orig_to_new;
int i;
const GPUBufferTypeSettings *ts = &gpu_buffer_type_settings[type];
GLenum target = ts->gl_buffer_type;
size_t size = gpu_buffer_size_from_type(dm, type);
- bool use_VBOs = (GLEW_ARB_vertex_buffer_object) && !(U.gameflags & USER_DISABLE_VBO);
GLboolean uploaded;
pool = gpu_get_global_buffer_pool();
@@ -537,9 +499,11 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
BLI_mutex_lock(&buffer_mutex);
/* alloc a GPUBuffer; fall back to legacy mode on failure */
- if (!(buffer = gpu_buffer_alloc_intern(size, use_VBOs))) {
- BLI_mutex_unlock(&buffer_mutex);
- return NULL;
+ if (!buffer) {
+ if (!(buffer = gpu_buffer_alloc_intern(size))) {
+ BLI_mutex_unlock(&buffer_mutex);
+ return NULL;
+ }
}
mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
@@ -550,56 +514,35 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
mat_orig_to_new[object->materials[i].mat_nr] = i;
}
- if (use_VBOs) {
- bool success = false;
-
- while (!success) {
- /* bind the buffer and discard previous data,
- * avoids stalling gpu */
- glBindBufferARB(target, buffer->id);
- glBufferDataARB(target, buffer->size, NULL, GL_STATIC_DRAW_ARB);
-
- /* attempt to map the buffer */
- if (!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) {
- buffer = gpu_try_realloc(pool, buffer, size, true);
+ /* bind the buffer and discard previous data,
+ * avoids stalling gpu */
+ glBindBuffer(target, buffer->id);
+ glBufferData(target, buffer->size, NULL, GL_STATIC_DRAW);
- /* allocation still failed; fall back
- * to legacy mode */
- if (!(buffer && (varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB)))) {
- use_VBOs = false;
- success = true;
- }
- }
- else {
- success = true;
- }
- }
+ /* attempt to map the buffer */
+ if (!(varray = glMapBuffer(target, GL_WRITE_ONLY))) {
+ buffer = gpu_try_realloc(pool, buffer, size);
- /* check legacy fallback didn't happen */
- if (use_VBOs) {
- uploaded = GL_FALSE;
- /* attempt to upload the data to the VBO */
- while (uploaded == GL_FALSE) {
- dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user);
- /* glUnmapBuffer returns GL_FALSE if
- * the data store is corrupted; retry
- * in that case */
- uploaded = glUnmapBufferARB(target);
- }
+ /* allocation still failed; unfortunately we need to exit */
+ if (!(buffer && (varray = glMapBuffer(target, GL_WRITE_ONLY)))) {
+ if (buffer)
+ gpu_buffer_free_intern(buffer);
+ BLI_mutex_unlock(&buffer_mutex);
+ return NULL;
}
- glBindBufferARB(target, 0);
}
- if (!use_VBOs) {
- /* VBO not supported, use vertex array fallback */
- if (!buffer || !buffer->pointer) {
- buffer = gpu_try_realloc(pool, buffer, size, false);
- }
-
- if (buffer) {
- varray = buffer->pointer;
- dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user);
- }
+
+ uploaded = GL_FALSE;
+
+ /* attempt to upload the data to the VBO */
+ while (uploaded == GL_FALSE) {
+ dm->copy_gpu_data(dm, type, varray, mat_orig_to_new, user);
+ /* glUnmapBuffer returns GL_FALSE if
+ * the data store is corrupted; retry
+ * in that case */
+ uploaded = glUnmapBuffer(target);
}
+ glBindBuffer(target, 0);
MEM_freeN(mat_orig_to_new);
@@ -636,33 +579,33 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer
/* get the amount of space to allocate for a buffer of a particular type */
static size_t gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
{
+ const int components = gpu_buffer_type_settings[type].num_components;
switch (type) {
case GPU_BUFFER_VERTEX:
- return sizeof(float) * gpu_buffer_type_settings[type].num_components * (dm->drawObject->tot_loop_verts + dm->drawObject->tot_loose_point);
+ return sizeof(float) * components * (dm->drawObject->tot_loop_verts + dm->drawObject->tot_loose_point);
case GPU_BUFFER_NORMAL:
- return sizeof(short) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts;
+ return sizeof(short) * components * dm->drawObject->tot_loop_verts;
case GPU_BUFFER_COLOR:
- return sizeof(char) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts;
+ return sizeof(char) * components * dm->drawObject->tot_loop_verts;
case GPU_BUFFER_UV:
- return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts;
+ return sizeof(float) * components * dm->drawObject->tot_loop_verts;
case GPU_BUFFER_UV_TEXPAINT:
- return sizeof(float) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts;
+ return sizeof(float) * components * dm->drawObject->tot_loop_verts;
case GPU_BUFFER_EDGE:
- return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->totedge;
+ return sizeof(int) * components * dm->drawObject->totedge;
case GPU_BUFFER_UVEDGE:
- return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_loop_verts;
+ return sizeof(int) * components * dm->drawObject->tot_loop_verts;
case GPU_BUFFER_TRIANGLES:
- return sizeof(int) * gpu_buffer_type_settings[type].num_components * dm->drawObject->tot_triangle_point;
+ return sizeof(int) * components * dm->drawObject->tot_triangle_point;
default:
return -1;
}
}
/* call gpu_buffer_setup with settings for a particular type of buffer */
-static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
+static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type, GPUBuffer *buf)
{
void *user_data = NULL;
- GPUBuffer *buf;
/* special handling for MCol and UV buffers */
if (type == GPU_BUFFER_COLOR) {
@@ -674,14 +617,14 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
return NULL;
}
- buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data);
+ buf = gpu_buffer_setup(dm, dm->drawObject, type, user_data, buf);
return buf;
}
/* get the buffer of `type', initializing the GPUDrawObject and
* buffer if needed */
-static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
+static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type, bool update)
{
GPUBuffer **buf;
@@ -690,83 +633,61 @@ static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
if (!(*buf))
- *buf = gpu_buffer_setup_type(dm, type);
+ *buf = gpu_buffer_setup_type(dm, type, NULL);
+ else if (update)
+ *buf = gpu_buffer_setup_type(dm, type, *buf);
return *buf;
}
void GPU_vertex_setup(DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX, false))
return;
glEnableClientState(GL_VERTEX_ARRAY);
- if (dm->drawObject->points->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
- glVertexPointer(3, GL_FLOAT, 0, 0);
- }
- else {
- glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->points->id);
+ glVertexPointer(3, GL_FLOAT, 0, 0);
GLStates |= GPU_BUFFER_VERTEX_STATE;
}
void GPU_normal_setup(DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL, false))
return;
glEnableClientState(GL_NORMAL_ARRAY);
- if (dm->drawObject->normals->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id);
- glNormalPointer(GL_SHORT, 4 * sizeof(short), 0);
- }
- else {
- glNormalPointer(GL_SHORT, 4 * sizeof(short), dm->drawObject->normals->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->normals->id);
+ glNormalPointer(GL_SHORT, 4 * sizeof(short), 0);
GLStates |= GPU_BUFFER_NORMAL_STATE;
}
void GPU_uv_setup(DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV, false))
return;
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- if (dm->drawObject->uv->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id);
- glTexCoordPointer(2, GL_FLOAT, 0, 0);
- }
- else {
- glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uv->id);
+ glTexCoordPointer(2, GL_FLOAT, 0, 0);
GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE;
}
void GPU_texpaint_uv_setup(DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT, false))
return;
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- if (dm->drawObject->uv_tex->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv_tex->id);
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
- glClientActiveTexture(GL_TEXTURE2);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float)));
- glClientActiveTexture(GL_TEXTURE0);
- }
- else {
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv_tex->pointer);
- glClientActiveTexture(GL_TEXTURE2);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv_tex->pointer + 2 * sizeof(float));
- glClientActiveTexture(GL_TEXTURE0);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uv_tex->id);
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
+ glClientActiveTexture(GL_TEXTURE2);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float)));
+ glClientActiveTexture(GL_TEXTURE0);
GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE;
}
@@ -774,6 +695,8 @@ void GPU_texpaint_uv_setup(DerivedMesh *dm)
void GPU_color_setup(DerivedMesh *dm, int colType)
{
+ bool update = false;
+
if (!dm->drawObject) {
/* XXX Not really nice, but we need a valid gpu draw object to set the colType...
* Else we would have to add a new param to gpu_buffer_setup_common. */
@@ -784,27 +707,17 @@ void GPU_color_setup(DerivedMesh *dm, int colType)
/* In paint mode, dm may stay the same during stroke, however we still want to update colors!
* Also check in case we changed color type (i.e. which MCol cdlayer we use). */
else if ((dm->dirty & DM_DIRTY_MCOL_UPDATE_DRAW) || (colType != dm->drawObject->colType)) {
- GPUBuffer **buf = gpu_drawobject_buffer_from_type(dm->drawObject, GPU_BUFFER_COLOR);
- /* XXX Freeing this buffer is a bit stupid, as geometry has not changed, size should remain the same.
- * Not sure though it would be worth defining a sort of gpu_buffer_update func - nor whether
- * it is even possible ! */
- GPU_buffer_free(*buf);
- *buf = NULL;
+ update = true;
dm->dirty &= ~DM_DIRTY_MCOL_UPDATE_DRAW;
dm->drawObject->colType = colType;
}
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR, update))
return;
glEnableClientState(GL_COLOR_ARRAY);
- if (dm->drawObject->colors->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id);
- glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
- }
- else {
- glColorPointer(3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->colors->id);
+ glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
GLStates |= GPU_BUFFER_COLOR_STATE;
}
@@ -812,13 +725,8 @@ void GPU_color_setup(DerivedMesh *dm, int colType)
void GPU_buffer_bind_as_color(GPUBuffer *buffer)
{
glEnableClientState(GL_COLOR_ARRAY);
- if (buffer->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
- }
- else {
- glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, buffer->id);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
GLStates |= GPU_BUFFER_COLOR_STATE;
}
@@ -826,55 +734,39 @@ void GPU_buffer_bind_as_color(GPUBuffer *buffer)
void GPU_edge_setup(DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE, false))
return;
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX, false))
return;
glEnableClientState(GL_VERTEX_ARRAY);
- if (dm->drawObject->points->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
- glVertexPointer(3, GL_FLOAT, 0, 0);
- }
- else {
- glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->points->id);
+ glVertexPointer(3, GL_FLOAT, 0, 0);
- GLStates |= GPU_BUFFER_VERTEX_STATE;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dm->drawObject->edges->id);
- if (dm->drawObject->edges->use_vbo)
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id);
-
- GLStates |= GPU_BUFFER_ELEMENT_STATE;
+ GLStates |= (GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_ELEMENT_STATE);
}
void GPU_uvedge_setup(DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE, false))
return;
glEnableClientState(GL_VERTEX_ARRAY);
- if (dm->drawObject->uvedges->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id);
- glVertexPointer(2, GL_FLOAT, 0, 0);
- }
- else {
- glVertexPointer(2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer);
- }
+ glBindBuffer(GL_ARRAY_BUFFER, dm->drawObject->uvedges->id);
+ glVertexPointer(2, GL_FLOAT, 0, 0);
GLStates |= GPU_BUFFER_VERTEX_STATE;
}
void GPU_triangle_setup(struct DerivedMesh *dm)
{
- if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES))
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_TRIANGLES, false))
return;
- if (dm->drawObject->triangles->use_vbo) {
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->triangles->id);
- }
-
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dm->drawObject->triangles->id);
GLStates |= GPU_BUFFER_ELEMENT_STATE;
}
@@ -912,12 +804,11 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
{
int i;
int elementsize;
- intptr_t offset = 0;
- char *basep;
+ size_t offset = 0;
for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
if (attribData[i].index != -1) {
- glDisableVertexAttribArrayARB(attribData[i].index);
+ glDisableVertexAttribArray(attribData[i].index);
}
else
break;
@@ -927,18 +818,12 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
else
elementsize = element_size;
- if (buffer->use_vbo) {
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
- basep = NULL;
- }
- else {
- basep = buffer->pointer;
- }
+ glBindBuffer(GL_ARRAY_BUFFER, buffer->id);
for (i = 0; i < numdata; i++) {
- glEnableVertexAttribArrayARB(data[i].index);
- glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
- GL_FALSE, elementsize, (void *)(basep + offset));
+ glEnableVertexAttribArray(data[i].index);
+ glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
+ GL_FALSE, elementsize, BUFFER_OFFSET(offset));
offset += data[i].size * GPU_typesize(data[i].type);
attribData[i].index = data[i].index;
@@ -954,7 +839,7 @@ void GPU_interleaved_attrib_unbind(void)
int i;
for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
if (attribData[i].index != -1) {
- glDisableVertexAttribArrayARB(attribData[i].index);
+ glDisableVertexAttribArray(attribData[i].index);
}
else
break;
@@ -979,28 +864,23 @@ void GPU_buffers_unbind(void)
}
if (GLStates & GPU_BUFFER_COLOR_STATE)
glDisableClientState(GL_COLOR_ARRAY);
- if (GLStates & GPU_BUFFER_ELEMENT_STATE) {
- /* not guaranteed we used VBOs but in that case it's just a no-op */
- if (GLEW_ARB_vertex_buffer_object) {
- glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
- }
- }
+ if (GLStates & GPU_BUFFER_ELEMENT_STATE)
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE |
GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE |
GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
if (attribData[i].index != -1) {
- glDisableVertexAttribArrayARB(attribData[i].index);
+ glDisableVertexAttribArray(attribData[i].index);
}
else
break;
}
attribData[0].index = -1;
- /* not guaranteed we used VBOs but in that case it's just a no-op */
- if (GLEW_ARB_vertex_buffer_object)
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void GPU_color_switch(int mode)
@@ -1019,82 +899,65 @@ void GPU_color_switch(int mode)
static int gpu_binding_type_gl[] =
{
- GL_ARRAY_BUFFER_ARB,
- GL_ELEMENT_ARRAY_BUFFER_ARB
+ GL_ARRAY_BUFFER,
+ GL_ELEMENT_ARRAY_BUFFER
};
void *GPU_buffer_lock(GPUBuffer *buffer, GPUBindingType binding)
{
float *varray;
+ int bindtypegl;
if (!buffer)
return 0;
- if (buffer->use_vbo) {
- int bindtypegl = gpu_binding_type_gl[binding];
- glBindBufferARB(bindtypegl, buffer->id);
- varray = glMapBufferARB(bindtypegl, GL_WRITE_ONLY_ARB);
- return varray;
- }
- else {
- return buffer->pointer;
- }
+ bindtypegl = gpu_binding_type_gl[binding];
+ glBindBuffer(bindtypegl, buffer->id);
+ varray = glMapBuffer(bindtypegl, GL_WRITE_ONLY);
+ return varray;
}
void *GPU_buffer_lock_stream(GPUBuffer *buffer, GPUBindingType binding)
{
float *varray;
+ int bindtypegl;
if (!buffer)
return 0;
- if (buffer->use_vbo) {
- int bindtypegl = gpu_binding_type_gl[binding];
- glBindBufferARB(bindtypegl, buffer->id);
- /* discard previous data, avoid stalling gpu */
- glBufferDataARB(bindtypegl, buffer->size, 0, GL_STREAM_DRAW_ARB);
- varray = glMapBufferARB(bindtypegl, GL_WRITE_ONLY_ARB);
- return varray;
- }
- else {
- return buffer->pointer;
- }
+ bindtypegl = gpu_binding_type_gl[binding];
+ glBindBuffer(bindtypegl, buffer->id);
+ /* discard previous data, avoid stalling gpu */
+ glBufferData(bindtypegl, buffer->size, 0, GL_STREAM_DRAW);
+ varray = glMapBuffer(bindtypegl, GL_WRITE_ONLY);
+ return varray;
}
-void GPU_buffer_unlock(GPUBuffer *buffer, GPUBindingType binding)
+void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding)
{
- if (buffer->use_vbo) {
- int bindtypegl = gpu_binding_type_gl[binding];
- /* note: this operation can fail, could return
+ int bindtypegl = gpu_binding_type_gl[binding];
+ /* note: this operation can fail, could return
* an error code from this function? */
- glUnmapBufferARB(bindtypegl);
- glBindBufferARB(bindtypegl, 0);
- }
+ glUnmapBuffer(bindtypegl);
+ glBindBuffer(bindtypegl, 0);
}
void GPU_buffer_bind(GPUBuffer *buffer, GPUBindingType binding)
{
- if (buffer->use_vbo) {
- int bindtypegl = gpu_binding_type_gl[binding];
- glBindBufferARB(bindtypegl, buffer->id);
- }
+ int bindtypegl = gpu_binding_type_gl[binding];
+ glBindBuffer(bindtypegl, buffer->id);
}
-void GPU_buffer_unbind(GPUBuffer *buffer, GPUBindingType binding)
+void GPU_buffer_unbind(GPUBuffer *UNUSED(buffer), GPUBindingType binding)
{
- if (buffer->use_vbo) {
- int bindtypegl = gpu_binding_type_gl[binding];
- glBindBufferARB(bindtypegl, 0);
- }
+ int bindtypegl = gpu_binding_type_gl[binding];
+ glBindBuffer(bindtypegl, 0);
}
/* used for drawing edges */
-void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count)
+void GPU_buffer_draw_elements(GPUBuffer *UNUSED(elements), unsigned int mode, int start, int count)
{
- glDrawElements(mode, count, GL_UNSIGNED_INT,
- (elements->use_vbo ?
- (void *)(start * sizeof(unsigned int)) :
- ((int *)elements->pointer) + start));
+ glDrawElements(mode, count, GL_UNSIGNED_INT, BUFFER_OFFSET(start * sizeof(unsigned int)));
}
@@ -1139,41 +1002,21 @@ struct GPU_PBVH_Buffers {
BLI_bitmap * const *grid_hidden;
const int *grid_indices;
int totgrid;
- int has_hidden;
+ bool has_hidden;
- int use_bmesh;
+ bool use_bmesh;
unsigned int tot_tri, tot_quad;
/* The PBVH ensures that either all faces in the node are
* smooth-shaded or all faces are flat-shaded */
- int smooth;
+ bool smooth;
bool show_diffuse_color;
bool use_matcaps;
float diffuse_color[4];
};
-typedef enum {
- VBO_ENABLED,
- VBO_DISABLED
-} VBO_State;
-
-static void gpu_colors_enable(VBO_State vbo_state)
-{
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- glEnable(GL_COLOR_MATERIAL);
- if (vbo_state == VBO_ENABLED)
- glEnableClientState(GL_COLOR_ARRAY);
-}
-
-static void gpu_colors_disable(VBO_State vbo_state)
-{
- glDisable(GL_COLOR_MATERIAL);
- if (vbo_state == VBO_ENABLED)
- glDisableClientState(GL_COLOR_ARRAY);
-}
-
static float gpu_color_from_mask(float mask)
{
return 1.0f - mask * 0.75f;
@@ -1237,7 +1080,7 @@ void GPU_update_mesh_pbvh_buffers(
/* Build VBO */
if (buffers->vert_buf)
GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem, false);
+ buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totelem);
vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY);
if (vert_data) {
@@ -1378,7 +1221,7 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers(
* shading requires separate vertex normals so an index buffer is
* can't be used there. */
if (buffers->smooth)
- buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3, false);
+ buffers->index_buf = GPU_buffer_alloc(sizeof(unsigned short) * tottri * 3);
if (buffers->index_buf) {
/* Fill the triangle buffer */
@@ -1425,10 +1268,10 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
buffers->show_diffuse_color = show_diffuse_color;
buffers->use_matcaps = GPU_material_use_matcaps_get();
+ buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
/* Build VBO */
if (buffers->vert_buf) {
- int smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
const int has_mask = key->has_mask;
float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
@@ -1453,7 +1296,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
copy_v3_v3(vd->co, CCG_elem_co(key, elem));
- if (smooth) {
+ if (buffers->smooth) {
normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem));
if (has_mask) {
@@ -1465,7 +1308,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
}
}
- if (!smooth) {
+ if (!buffers->smooth) {
/* for flat shading, recalc normals and set the last vertex of
* each triangle in the index buffer to have the flat normal as
* that is what opengl will use */
@@ -1518,8 +1361,6 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
buffers->grid_flag_mats = grid_flag_mats;
buffers->gridkey = *key;
- buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
//printf("node updated %p\n", buffers);
}
@@ -1530,8 +1371,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids,
type_ *tri_data; \
int offset = 0; \
int i, j, k; \
- buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6, \
- false); \
+ buffer_ = GPU_buffer_alloc(sizeof(type_) * (tot_quad_) * 6); \
\
/* Fill the buffer */ \
tri_data = GPU_buffer_lock(buffer_, GPU_BINDING_INDEX); \
@@ -1609,7 +1449,7 @@ static GPUBuffer *gpu_get_grid_buffer(int gridsize, GLenum *index_type, unsigned
#define FILL_FAST_BUFFER(type_) \
{ \
type_ *buffer; \
- buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid, false); \
+ buffers->index_buf_fast = GPU_buffer_alloc(sizeof(type_) * 6 * totgrid); \
buffer = GPU_buffer_lock(buffers->index_buf_fast, GPU_BINDING_INDEX); \
if (buffer) { \
int i; \
@@ -1661,7 +1501,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
if (totquad == fully_visible_totquad) {
buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad);
- buffers->has_hidden = 0;
+ buffers->has_hidden = false;
}
else {
buffers->tot_quad = totquad;
@@ -1675,22 +1515,21 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid,
FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf);
}
- buffers->has_hidden = 1;
+ buffers->has_hidden = true;
}
/* Build coord/normal VBO */
if (buffers->index_buf)
- buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area, false);
+ buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totgrid * key->grid_area);
- if (GLEW_ARB_draw_elements_base_vertex) {
+ if (GLEW_ARB_draw_elements_base_vertex /* 3.2 */) {
int i;
buffers->baseelemarray = MEM_mallocN(sizeof(int) * totgrid * 2, "GPU_PBVH_Buffers.baseelemarray");
buffers->baseindex = MEM_mallocN(sizeof(void *) * totgrid, "GPU_PBVH_Buffers.baseindex");
for (i = 0; i < totgrid; i++) {
buffers->baseelemarray[i] = buffers->tot_quad * 6;
buffers->baseelemarray[i + totgrid] = i * key->grid_area;
- buffers->baseindex[i] = buffers->index_buf && !buffers->index_buf->use_vbo ?
- buffers->index_buf->pointer : NULL;
+ buffers->baseindex[i] = NULL;
}
}
@@ -1822,7 +1661,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
/* Initialize vertex buffer */
if (buffers->vert_buf)
GPU_buffer_free(buffers->vert_buf);
- buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert, false);
+ buffers->vert_buf = GPU_buffer_alloc(sizeof(VertexBufferFormat) * totvert);
/* Fill vertex buffer */
vert_data = GPU_buffer_lock(buffers->vert_buf, GPU_BINDING_ARRAY);
@@ -1905,7 +1744,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
GPU_buffer_free(buffers->index_buf);
buffers->index_buf = GPU_buffer_alloc((use_short ?
sizeof(unsigned short) :
- sizeof(unsigned int)) * 3 * tottri, false);
+ sizeof(unsigned int)) * 3 * tottri);
/* Fill triangle index buffer */
tri_data = GPU_buffer_lock(buffers->index_buf, GPU_BINDING_INDEX);
@@ -1942,8 +1781,8 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
buffers->tot_tri = tottri;
buffers->index_type = (use_short ?
- GL_UNSIGNED_SHORT :
- GL_UNSIGNED_INT);
+ GL_UNSIGNED_SHORT :
+ GL_UNSIGNED_INT);
}
else {
/* Memory map failed */
@@ -1956,7 +1795,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers,
}
}
-GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading)
+GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading)
{
GPU_PBVH_Buffers *buffers;
@@ -1993,35 +1832,33 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
}
}
- glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT);
-
if (buffers->vert_buf) {
char *base = NULL;
char *index_base = NULL;
+ int bound_options = 0;
glEnableClientState(GL_VERTEX_ARRAY);
if (!wireframe) {
glEnableClientState(GL_NORMAL_ARRAY);
- gpu_colors_enable(VBO_ENABLED);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ /* weak inspection of bound options, should not be necessary ideally */
+ bound_options = GPU_basic_shader_bound_options();
+ GPU_basic_shader_bind(bound_options | GPU_SHADER_USE_COLOR);
}
GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY);
- if (!buffers->vert_buf->use_vbo)
- base = (char *)buffers->vert_buf->pointer;
-
if (do_fast) {
GPU_buffer_bind(buffers->index_buf_fast, GPU_BINDING_INDEX);
- if (!buffers->index_buf_fast->use_vbo)
- index_base = buffers->index_buf_fast->pointer;
}
else if (buffers->index_buf) {
GPU_buffer_bind(buffers->index_buf, GPU_BINDING_INDEX);
- if (!buffers->index_buf->use_vbo)
- index_base = buffers->index_buf->pointer;
}
if (wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else
+ glShadeModel((buffers->smooth || buffers->face_indices_len) ? GL_SMOOTH : GL_FLAT);
if (buffers->tot_quad) {
const char *offset = base;
@@ -2031,10 +1868,12 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, co));
- glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, no));
- glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, color));
+ if (!wireframe) {
+ glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
+ offset + offsetof(VertexBufferFormat, no));
+ glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
+ offset + offsetof(VertexBufferFormat, color));
+ }
glMultiDrawElementsBaseVertex(GL_TRIANGLES, buffers->baseelemarray, buffers->index_type,
(const void * const *)buffers->baseindex,
@@ -2047,10 +1886,12 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
for (i = 0; i < last; i++) {
glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
offset + offsetof(VertexBufferFormat, co));
- glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, no));
- glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
- offset + offsetof(VertexBufferFormat, color));
+ if (!wireframe) {
+ glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
+ offset + offsetof(VertexBufferFormat, no));
+ glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
+ offset + offsetof(VertexBufferFormat, color));
+ }
if (do_fast)
glDrawElements(GL_TRIANGLES, buffers->totgrid * 6, buffers->index_type, index_base);
@@ -2066,10 +1907,13 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat),
(void *)(base + offsetof(VertexBufferFormat, co)));
- glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
- (void *)(base + offsetof(VertexBufferFormat, no)));
- glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
- (void *)(base + offsetof(VertexBufferFormat, color)));
+
+ if (!wireframe) {
+ glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat),
+ (void *)(base + offsetof(VertexBufferFormat, no)));
+ glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VertexBufferFormat),
+ (void *)(base + offsetof(VertexBufferFormat, color)));
+ }
if (buffers->index_buf)
glDrawElements(GL_TRIANGLES, totelem, buffers->index_type, index_base);
@@ -2087,7 +1931,8 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial,
glDisableClientState(GL_VERTEX_ARRAY);
if (!wireframe) {
glDisableClientState(GL_NORMAL_ARRAY);
- gpu_colors_disable(VBO_ENABLED);
+ glDisableClientState(GL_COLOR_ARRAY);
+ GPU_basic_shader_bind(bound_options);
}
}
}
@@ -2203,8 +2048,6 @@ void GPU_init_draw_pbvh_BB(void)
glEnableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 496302bb44e..7cd05eff64e 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -42,9 +42,11 @@
#include "BLI_dynstr.h"
#include "BLI_ghash.h"
+#include "GPU_extensions.h"
#include "GPU_glew.h"
#include "GPU_material.h"
-#include "GPU_extensions.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -175,10 +177,15 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
}
}
- if (!type && gpu_str_prefix(code, "sampler2DShadow"))
- type= GPU_SHADOW2D;
- if (!type && gpu_str_prefix(code, "sampler2D"))
- type= GPU_TEX2D;
+ if (!type && gpu_str_prefix(code, "samplerCube")) {
+ type = GPU_TEXCUBE;
+ }
+ if (!type && gpu_str_prefix(code, "sampler2DShadow")) {
+ type = GPU_SHADOW2D;
+ }
+ if (!type && gpu_str_prefix(code, "sampler2D")) {
+ type = GPU_TEX2D;
+ }
if (type) {
/* add parameter */
@@ -311,7 +318,9 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
BLI_dynstr_append(ds, name);
}
else if (to == GPU_FLOAT) {
- if (from == GPU_VEC4 || from == GPU_VEC3)
+ if (from == GPU_VEC4)
+ BLI_dynstr_appendf(ds, "convert_rgba_to_float(%s)", name);
+ else if (from == GPU_VEC3)
BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name);
else if (from == GPU_VEC2)
BLI_dynstr_appendf(ds, "%s.r", name);
@@ -377,6 +386,10 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfinvviewmat";
else if (builtin == GPU_INVERSE_OBJECT_MATRIX)
return "unfinvobmat";
+ else if (builtin == GPU_LOC_TO_VIEW_MATRIX)
+ return "unflocaltoviewmat";
+ else if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX)
+ return "unfinvlocaltoviewmat";
else if (builtin == GPU_VIEW_POSITION)
return "varposition";
else if (builtin == GPU_VIEW_NORMAL)
@@ -495,13 +508,15 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
for (input = node->inputs.first; input; input = input->next) {
if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) {
/* create exactly one sampler for each texture */
- if (codegen_input_has_texture(input) && input->bindtex)
+ if (codegen_input_has_texture(input) && input->bindtex) {
BLI_dynstr_appendf(ds, "uniform %s samp%d;\n",
- (input->textype == GPU_TEX2D) ? "sampler2D" : "sampler2DShadow",
+ (input->textype == GPU_TEX2D) ? "sampler2D" :
+ (input->textype == GPU_TEXCUBE) ? "samplerCube" : "sampler2DShadow",
input->texid);
+ }
}
else if (input->source == GPU_SOURCE_BUILTIN) {
- /* only define each builting uniform/varying once */
+ /* only define each builtin uniform/varying once */
if (!(builtins & input->builtin)) {
builtins |= input->builtin;
name = GPU_builtin_name(input->builtin);
@@ -511,7 +526,8 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
GPU_DATATYPE_STR[input->type], name);
}
else {
- BLI_dynstr_appendf(ds, "varying %s %s;\n",
+ BLI_dynstr_appendf(ds, "%s %s %s;\n",
+ GLEW_VERSION_3_0 ? "in" : "varying",
GPU_DATATYPE_STR[input->type], name);
}
}
@@ -537,7 +553,8 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
- BLI_dynstr_appendf(ds, "varying %s var%d;\n",
+ BLI_dynstr_appendf(ds, "%s %s var%d;\n",
+ GLEW_VERSION_3_0 ? "in" : "varying",
GPU_DATATYPE_STR[input->type], input->attribid);
#ifdef WITH_OPENSUBDIV
if (skip_opensubdiv) {
@@ -566,15 +583,16 @@ static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
if (codegen_input_has_texture(input) && input->definetex) {
BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid);
BLI_dynstr_appendf(ds, "samp%d, gl_TexCoord[%d].st);\n",
- input->texid, input->texid);
+ input->texid, input->texid);
}
}
}
/* declare temporary variables for node output storage */
- for (output = node->outputs.first; output; output = output->next)
+ for (output = node->outputs.first; output; output = output->next) {
BLI_dynstr_appendf(ds, "\t%s tmp%d;\n",
- GPU_DATATYPE_STR[output->type], output->id);
+ GPU_DATATYPE_STR[output->type], output->id);
+ }
}
BLI_dynstr_append(ds, "\n");
@@ -662,11 +680,10 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
BLI_dynstr_appendf(ds, "/* %s */\n", name);
#endif
- BLI_dynstr_append(ds, "void main(void)\n");
- BLI_dynstr_append(ds, "{\n");
+ BLI_dynstr_append(ds, "void main()\n{\n");
if (builtins & GPU_VIEW_NORMAL)
- BLI_dynstr_append(ds, "\tvec3 facingnormal = (gl_FrontFacing)? varnormal: -varnormal;\n");
+ BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? varnormal: -varnormal;\n");
/* Calculate tangent space. */
#ifdef WITH_OPENSUBDIV
@@ -729,9 +746,11 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
}
#endif
- BLI_dynstr_appendf(ds, "attribute %s att%d;\n",
+ BLI_dynstr_appendf(ds, "%s %s att%d;\n",
+ GLEW_VERSION_3_0 ? "in" : "attribute",
GPU_DATATYPE_STR[input->type], input->attribid);
- BLI_dynstr_appendf(ds, "varying %s var%d;\n",
+ BLI_dynstr_appendf(ds, "%s %s var%d;\n",
+ GLEW_VERSION_3_0 ? "out" : "varying",
GPU_DATATYPE_STR[input->type], input->attribid);
#ifdef WITH_OPENSUBDIV
if (skip_opensubdiv) {
@@ -765,8 +784,12 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
#ifdef WITH_OPENSUBDIV
BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
#endif
- BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid);
- BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid);
+ BLI_dynstr_appendf(
+ ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n",
+ input->attribid, input->attribid);
+ BLI_dynstr_appendf(
+ ds, "\tvar%d.w = att%d.w;\n",
+ input->attribid, input->attribid);
#ifdef WITH_OPENSUBDIV
BLI_dynstr_appendf(ds, "#endif\n");
#endif
@@ -791,7 +814,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
if (input->oglbuiltin == GPU_MATCAP_NORMAL) {
/* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
* between shader stages and we want the full range of the normal */
- BLI_dynstr_appendf(ds, "\tvec3 matcapcol = vec3(0.5, 0.5, 0.5) * varnormal + vec3(0.5, 0.5, 0.5);\n");
+ BLI_dynstr_appendf(ds, "\tvec3 matcapcol = vec3(0.5) * varnormal + vec3(0.5);\n");
BLI_dynstr_appendf(ds, "\tgl_FrontSecondaryColor = vec4(matcapcol, 1.0);\n");
}
else if (input->oglbuiltin == GPU_COLOR) {
@@ -799,7 +822,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
}
}
- BLI_dynstr_append(ds, "}\n\n");
+ BLI_dynstr_append(ds, "}\n");
code = BLI_dynstr_get_cstring(ds);
@@ -826,9 +849,11 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
- BLI_dynstr_appendf(ds, "varying %s var%d;\n",
+ BLI_dynstr_appendf(ds, "%s %s var%d%s;\n",
+ GLEW_VERSION_3_0 ? "in" : "varying",
GPU_DATATYPE_STR[input->type],
- input->attribid);
+ input->attribid,
+ GLEW_VERSION_3_0 ? "[]" : "");
BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
input->attribid);
}
@@ -856,7 +881,7 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
}
#endif
- BLI_dynstr_append(ds, "}\n\n");
+ BLI_dynstr_append(ds, "}\n");
code = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -993,18 +1018,21 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
GPU_shader_bind(shader);
- /* now bind the textures */
+ /* create the textures */
for (input = inputs->first; input; input = input->next) {
if (input->ima)
- input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->image_isdata, time, mipmap);
+ input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->textarget, input->image_isdata, time, mipmap);
else if (input->prv)
input->tex = GPU_texture_from_preview(input->prv, mipmap);
+ }
+ /* bind the textures, in second loop so texture binding during
+ * create doesn't overwrite already bound textures */
+ for (input = inputs->first; input; input = input->next) {
if (input->tex && input->bindtex) {
GPU_texture_bind(input->tex, input->texid);
GPU_shader_uniform_texture(shader, input->shaderloc, input->tex);
}
-
}
}
@@ -1022,7 +1050,7 @@ void GPU_pass_update_uniforms(GPUPass *pass)
if (!(input->ima || input->tex || input->prv)) {
if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) {
// The hardness is actually a short pointer, so we convert it here
- float val = (float)(*(short*)input->dynamicvec);
+ float val = (float)(*(short *)input->dynamicvec);
GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val);
}
else {
@@ -1170,15 +1198,25 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input->type = GPU_VEC4;
input->source = GPU_SOURCE_TEX;
- if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW)
+ if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW) {
input->prv = link->ptr1;
- else {
+ input->textarget = GL_TEXTURE_2D;
+ input->textype = GPU_TEX2D;
+ }
+ else if (link->image == GPU_NODE_LINK_IMAGE_BLENDER) {
input->ima = link->ptr1;
input->iuser = link->ptr2;
input->image_isdata = link->image_isdata;
+ input->textarget = GL_TEXTURE_2D;
+ input->textype = GPU_TEX2D;
+ }
+ else if (link->image == GPU_NODE_LINK_IMAGE_CUBE_MAP) {
+ input->ima = link->ptr1;
+ input->iuser = link->ptr2;
+ input->image_isdata = link->image_isdata;
+ input->textarget = GL_TEXTURE_CUBE_MAP;
+ input->textype = GPU_TEXCUBE;
}
- input->textarget = GL_TEXTURE_2D;
- input->textype = GPU_TEX2D;
MEM_freeN(link);
}
else if (link->attribtype) {
@@ -1195,7 +1233,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType
input->type = type;
input->source = GPU_SOURCE_VEC_UNIFORM;
- memcpy(input->vec, link->ptr1, type*sizeof(float));
+ memcpy(input->vec, link->ptr1, type * sizeof(float));
if (link->dynamic) {
input->dynamicvec = link->ptr1;
input->dynamictype = link->dynamictype;
@@ -1383,6 +1421,18 @@ GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
return link;
}
+GPUNodeLink *GPU_cube_map(Image *ima, ImageUser *iuser, bool is_data)
+{
+ GPUNodeLink *link = GPU_node_link_create();
+
+ link->image = GPU_NODE_LINK_IMAGE_CUBE_MAP;
+ link->ptr1 = ima;
+ link->ptr2 = iuser;
+ link->image_isdata = is_data;
+
+ return link;
+}
+
GPUNodeLink *GPU_image_preview(PreviewImage *prv)
{
GPUNodeLink *link = GPU_node_link_create();
@@ -1421,7 +1471,7 @@ GPUNodeLink *GPU_builtin(GPUBuiltin builtin)
{
GPUNodeLink *link = GPU_node_link_create();
- link->builtin= builtin;
+ link->builtin = builtin;
return link;
}
@@ -1452,13 +1502,13 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
node = GPU_node_begin(name);
va_start(params, name);
- for (i = 0; i<function->totparam; i++) {
+ for (i = 0; i < function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
- linkptr = va_arg(params, GPUNodeLink**);
+ linkptr = va_arg(params, GPUNodeLink **);
gpu_node_output(node, function->paramtype[i], linkptr);
}
else {
- link = va_arg(params, GPUNodeLink*);
+ link = va_arg(params, GPUNodeLink *);
gpu_node_input_link(node, link, function->paramtype[i]);
}
}
@@ -1502,10 +1552,10 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
va_start(params, out);
- for (i = 0; i<function->totparam; i++) {
+ for (i = 0; i < function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
- linkptr = va_arg(params, GPUNodeLink**);
+ linkptr = va_arg(params, GPUNodeLink **);
gpu_node_output(node, function->paramtype[i], linkptr);
}
else
@@ -1513,7 +1563,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
else {
if (totin == 0) {
- link = va_arg(params, GPUNodeLink*);
+ link = va_arg(params, GPUNodeLink *);
if (link->socket)
gpu_node_input_socket(node, link->socket);
else
@@ -1590,9 +1640,12 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
}
}
-GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
- GPUVertexAttribs *attribs, int *builtins,
- const GPUMatType type, const char *UNUSED(name), const bool use_opensubdiv)
+GPUPass *GPU_generate_pass(
+ ListBase *nodes, GPUNodeLink *outlink,
+ GPUVertexAttribs *attribs, int *builtins,
+ const GPUMatType type, const char *UNUSED(name),
+ const bool use_opensubdiv,
+ const bool use_new_shading)
{
GPUShader *shader;
GPUPass *pass;
@@ -1615,6 +1668,14 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
fragmentcode = code_generate_fragment(nodes, outlink->output);
vertexcode = code_generate_vertex(nodes, type);
geometrycode = code_generate_geometry(nodes, use_opensubdiv);
+
+ int flags = GPU_SHADER_FLAGS_NONE;
+ if (use_opensubdiv) {
+ flags |= GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV;
+ }
+ if (use_new_shading) {
+ flags |= GPU_SHADER_FLAGS_NEW_SHADING;
+ }
shader = GPU_shader_create_ex(vertexcode,
fragmentcode,
geometrycode,
@@ -1623,8 +1684,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
0,
0,
0,
- use_opensubdiv ? GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV
- : GPU_SHADER_FLAGS_NONE);
+ flags);
/* failed? */
if (!shader) {
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index 5aa187014ba..417e46a83ee 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -63,7 +63,8 @@ typedef enum GPUDataSource {
typedef enum {
GPU_NODE_LINK_IMAGE_NONE = 0,
GPU_NODE_LINK_IMAGE_BLENDER = 1,
- GPU_NODE_LINK_IMAGE_PREVIEW = 2
+ GPU_NODE_LINK_IMAGE_PREVIEW = 2,
+ GPU_NODE_LINK_IMAGE_CUBE_MAP = 3
} GPUNodeLinkImage;
struct GPUNode {
@@ -171,7 +172,9 @@ typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
struct GPUVertexAttribs *attribs, int *builtin,
- const GPUMatType type, const char *name, const bool use_opensubdiv);
+ const GPUMatType type, const char *name,
+ const bool use_opensubdiv,
+ const bool use_new_shading);
struct GPUShader *GPU_pass_shader(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c
index da5db73d382..c2a2b1804ca 100644
--- a/source/blender/gpu/intern/gpu_compositing.c
+++ b/source/blender/gpu/intern/gpu_compositing.c
@@ -38,7 +38,6 @@
#include "BLI_linklist.h"
#include "BLI_rand.h"
-#include "BLI_listbase.h"
#include "DNA_vec_types.h"
#include "DNA_view3d_types.h"
@@ -47,16 +46,99 @@
#include "DNA_camera_types.h"
#include "DNA_gpu_types.h"
-#include "GPU_extensions.h"
#include "GPU_compositing.h"
-
+#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
#include "GPU_glew.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
#include "MEM_guardedalloc.h"
static const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}};
static const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}};
+
+/* shader interfaces (legacy GL 2 style, without uniform buffer objects) */
+
+typedef struct {
+ int ssao_uniform;
+ int ssao_color_uniform;
+ int color_uniform;
+ int depth_uniform;
+ int viewvecs_uniform;
+ int ssao_sample_params_uniform;
+ int ssao_concentric_tex;
+ int ssao_jitter_uniform;
+} GPUSSAOShaderInterface;
+
+typedef struct {
+ int invrendertargetdim_uniform;
+ int color_uniform;
+ int dof_uniform;
+ int depth_uniform;
+ int viewvecs_uniform;
+} GPUDOFHQPassOneInterface;
+
+typedef struct {
+ int rendertargetdim_uniform;
+ int color_uniform;
+ int coc_uniform;
+ int select_uniform;
+ int dof_uniform;
+} GPUDOFHQPassTwoInterface;
+
+typedef struct {
+ int dof_uniform;
+ int invrendertargetdim_uniform;
+ int color_uniform;
+ int far_uniform;
+ int near_uniform;
+ int viewvecs_uniform;
+ int depth_uniform;
+} GPUDOFHQPassThreeInterface;
+
+typedef struct {
+ int dof_uniform;
+ int invrendertargetdim_uniform;
+ int color_uniform;
+ int depth_uniform;
+ int viewvecs_uniform;
+} GPUDOFPassOneInterface;
+
+typedef struct {
+ int dof_uniform;
+ int invrendertargetdim_uniform;
+ int color_uniform;
+ int depth_uniform;
+ int viewvecs_uniform;
+} GPUDOFPassTwoInterface;
+
+typedef struct {
+ int near_coc_downsampled;
+ int near_coc_blurred;
+} GPUDOFPassThreeInterface;
+
+typedef struct {
+ int near_coc_downsampled;
+ int invrendertargetdim_uniform;
+} GPUDOFPassFourInterface;
+
+typedef struct {
+ int medium_blurred_uniform;
+ int high_blurred_uniform;
+ int dof_uniform;
+ int invrendertargetdim_uniform;
+ int original_uniform;
+ int depth_uniform;
+ int viewvecs_uniform;
+} GPUDOFPassFiveInterface;
+
+typedef struct {
+ int depth_uniform;
+} GPUDepthResolveInterface;
+
+
struct GPUFX {
/* we borrow the term gbuffer from deferred rendering however this is just a regular
* depth/color framebuffer. Could be extended later though */
@@ -77,7 +159,8 @@ struct GPUFX {
/* texture used for jittering for various effects */
GPUTexture *jitter_buffer;
- /* all those buffers below have to coexist. Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */
+ /* all those buffers below have to coexist.
+ * Fortunately they are all quarter sized (1/16th of memory) of original framebuffer */
int dof_downsampled_w;
int dof_downsampled_h;
@@ -179,14 +262,13 @@ GPUFX *GPU_fx_compositor_create(void)
{
GPUFX *fx = MEM_callocN(sizeof(GPUFX), "GPUFX compositor");
- if (GLEW_ARB_vertex_buffer_object) {
- glGenBuffersARB(1, &fx->vbuffer);
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
- glBufferDataARB(GL_ARRAY_BUFFER_ARB, 16 * sizeof(float), NULL, GL_STATIC_DRAW);
- glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, 8 * sizeof(float), fullscreencos);
- glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs);
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
- }
+ glGenBuffers(1, &fx->vbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer);
+ glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STATIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, 8 * sizeof(float), fullscreencos);
+ glBufferSubData(GL_ARRAY_BUFFER, 8 * sizeof(float), 8 * sizeof(float), fullscreenuvs);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
return fx;
}
@@ -275,14 +357,13 @@ static void cleanup_fx_gl_data(GPUFX *fx, bool do_fbo)
void GPU_fx_compositor_destroy(GPUFX *fx)
{
cleanup_fx_gl_data(fx, true);
- if (GLEW_ARB_vertex_buffer_object)
- glDeleteBuffersARB(1, &fx->vbuffer);
+ glDeleteBuffers(1, &fx->vbuffer);
MEM_freeN(fx);
}
static GPUTexture * create_jitter_texture(void)
{
- float jitter [64 * 64][2];
+ float jitter[64 * 64][2];
int i;
for (i = 0; i < 64 * 64; i++) {
@@ -306,7 +387,7 @@ bool GPU_fx_compositor_initialize_passes(
fx->effects = 0;
- if (!GPU_non_power_of_two_support() || !GLEW_EXT_framebuffer_object || !GLEW_ARB_fragment_shader)
+ if (!GLEW_EXT_framebuffer_object)
return false;
if (!fx_settings) {
@@ -332,7 +413,8 @@ bool GPU_fx_compositor_initialize_passes(
/* scissor is missing when drawing offscreen, in that case, dimensions match exactly. In opposite case
* add one to match viewport dimensions */
if (scissor_rect) {
- w++, h++;
+ w++;
+ h++;
}
fx->num_passes = 0;
@@ -396,7 +478,7 @@ bool GPU_fx_compositor_initialize_passes(
/* create textures for dof effect */
if (fx_flag & GPU_FX_FLAG_DOF) {
bool dof_high_quality = (fx_settings->dof->high_quality != 0) &&
- GPU_geometry_shader_support() && GPU_instanced_drawing_support();
+ GPU_geometry_shader_support() && GPU_instanced_drawing_support();
/* cleanup buffers if quality setting has changed (no need to keep more buffers around than necessary ) */
if (dof_high_quality != fx->dof_high_quality)
@@ -407,7 +489,8 @@ bool GPU_fx_compositor_initialize_passes(
fx->dof_downsampled_h = h / 2;
if (!fx->dof_half_downsampled_near || !fx->dof_nearfar_coc || !fx->dof_near_blur ||
- !fx->dof_far_blur || !fx->dof_half_downsampled_far) {
+ !fx->dof_far_blur || !fx->dof_half_downsampled_far)
+ {
if (!(fx->dof_half_downsampled_near = GPU_texture_create_2D(
fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, GPU_HDR_NONE, err_out)))
@@ -525,7 +608,7 @@ bool GPU_fx_compositor_initialize_passes(
glPushAttrib(GL_SCISSOR_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(scissor_rect->xmin - rect->xmin, scissor_rect->ymin - rect->ymin,
- w_sc, h_sc);
+ w_sc, h_sc);
fx->restore_stencil = true;
}
else {
@@ -565,7 +648,9 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray)
char err_out[256];
if (do_xray) {
- if (!fx->depth_buffer_xray && !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], err_out))) {
+ if (!fx->depth_buffer_xray &&
+ !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], err_out)))
+ {
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
return;
@@ -605,7 +690,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
/* set up quad buffer */
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer);
glVertexPointer(2, GL_FLOAT, 0, NULL);
glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
@@ -614,15 +699,13 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
depth_resolve_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_RESOLVE, false);
if (depth_resolve_shader) {
- int depth_uniform;
-
- depth_uniform = GPU_shader_get_uniform(depth_resolve_shader, "depthbuffer");
+ GPUDepthResolveInterface *interface = GPU_shader_get_interface(depth_resolve_shader);
GPU_shader_bind(depth_resolve_shader);
GPU_texture_bind(fx->depth_buffer_xray, 0);
GPU_texture_filter_mode(fx->depth_buffer_xray, false, true);
- GPU_shader_uniform_texture(depth_resolve_shader, depth_uniform, fx->depth_buffer_xray);
+ GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray);
/* draw */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -636,7 +719,7 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -644,7 +727,9 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx)
}
-bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, struct Scene *scene, struct GPUOffScreen *ofs)
+bool GPU_fx_do_composite_pass(
+ GPUFX *fx, float projmat[4][4], bool is_persp,
+ struct Scene *scene, struct GPUOffScreen *ofs)
{
GPUTexture *src, *target;
int numslots = 0;
@@ -675,7 +760,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
target = fx->color_buffer_sec;
/* set up quad buffer */
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, fx->vbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, fx->vbuffer);
glVertexPointer(2, GL_FLOAT, 0, NULL);
glTexCoordPointer(2, GL_FLOAT, 0, ((GLubyte *)NULL + 8 * sizeof(float)));
glEnableClientState(GL_VERTEX_ARRAY);
@@ -718,9 +803,6 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp);
if (ssao_shader) {
const GPUSSAOSettings *fx_ssao = fx->settings.ssao;
- int color_uniform, depth_uniform;
- int ssao_uniform, ssao_color_uniform, viewvecs_uniform, ssao_sample_params_uniform;
- int ssao_jitter_uniform, ssao_concentric_tex;
float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f};
float sample_params[3];
@@ -731,34 +813,27 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
ssao_params[3] = (passes_left == 1 && !ofs) ? dfdyfac[0] : dfdyfac[1];
- ssao_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_params");
- ssao_color_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_color");
- color_uniform = GPU_shader_get_uniform(ssao_shader, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(ssao_shader, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(ssao_shader, "viewvecs");
- ssao_sample_params_uniform = GPU_shader_get_uniform(ssao_shader, "ssao_sample_params");
- ssao_concentric_tex = GPU_shader_get_uniform(ssao_shader, "ssao_concentric_tex");
- ssao_jitter_uniform = GPU_shader_get_uniform(ssao_shader, "jitter_tex");
+ GPUSSAOShaderInterface *interface = GPU_shader_get_interface(ssao_shader);
GPU_shader_bind(ssao_shader);
- GPU_shader_uniform_vector(ssao_shader, ssao_uniform, 4, 1, ssao_params);
- GPU_shader_uniform_vector(ssao_shader, ssao_color_uniform, 4, 1, fx_ssao->color);
- GPU_shader_uniform_vector(ssao_shader, viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_shader_uniform_vector(ssao_shader, ssao_sample_params_uniform, 3, 1, sample_params);
+ GPU_shader_uniform_vector(ssao_shader, interface->ssao_uniform, 4, 1, ssao_params);
+ GPU_shader_uniform_vector(ssao_shader, interface->ssao_color_uniform, 4, 1, fx_ssao->color);
+ GPU_shader_uniform_vector(ssao_shader, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(ssao_shader, interface->ssao_sample_params_uniform, 3, 1, sample_params);
GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(ssao_shader, color_uniform, src);
+ GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src);
GPU_texture_bind(fx->depth_buffer, numslots++);
GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(ssao_shader, depth_uniform, fx->depth_buffer);
+ GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->jitter_buffer, numslots++);
- GPU_shader_uniform_texture(ssao_shader, ssao_jitter_uniform, fx->jitter_buffer);
+ GPU_shader_uniform_texture(ssao_shader, interface->ssao_jitter_uniform, fx->jitter_buffer);
GPU_texture_bind(fx->ssao_spiral_samples_tex, numslots++);
- GPU_shader_uniform_texture(ssao_shader, ssao_concentric_tex, fx->ssao_spiral_samples_tex);
+ GPU_shader_uniform_texture(ssao_shader, interface->ssao_concentric_tex, fx->ssao_spiral_samples_tex);
/* draw */
gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
@@ -796,13 +871,15 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
float scale = scene->unit.system ? scene->unit.scale_length : 1.0f;
/* this is factor that converts to the scene scale. focal length and sensor are expressed in mm
* unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though
- * because the shader reads coordinates in world space, which is in blender units. */
+ * because the shader reads coordinates in world space, which is in blender units.
+ * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */
float scale_camera = 0.001f / scale;
/* we want radius here for the aperture number */
float aperture = 0.5f * scale_camera * fx_dof->focal_length / fx_dof->fstop;
- dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length / ((fx_dof->focus_distance / scale) - scale_camera * fx_dof->focal_length));
- dof_params[1] = fx_dof->focus_distance / scale;
+ dof_params[0] = aperture * fabsf(scale_camera * fx_dof->focal_length /
+ (fx_dof->focus_distance - scale_camera * fx_dof->focal_length));
+ dof_params[1] = fx_dof->focus_distance;
dof_params[2] = fx->gbuffer_dim[0] / (scale_camera * fx_dof->sensor);
dof_params[3] = fx_dof->num_blades;
@@ -822,41 +899,32 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
GPU_shader_unbind();
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
return false;
}
/* pass first, downsample the color buffer to near/far targets and calculate coc texture */
{
- int depth_uniform, dof_uniform;
- int viewvecs_uniform;
- int invrendertargetdim_uniform, color_uniform;
-
float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
+ GPUDOFHQPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1);
GPU_shader_bind(dof_shader_pass1);
- GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
- GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
GPU_texture_bind(fx->depth_buffer, numslots++);
GPU_texture_filter_mode(fx->depth_buffer, false, false);
- GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(src, numslots++);
/* disable filtering for the texture so custom downsample can do the right thing */
GPU_texture_filter_mode(src, false, false);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, src);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src);
/* target is the downsampled coc buffer */
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_half_downsampled_near, 0, NULL);
@@ -885,29 +953,23 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* second pass, shoot quads for every pixel in the downsampled buffers, scaling according
* to circle of confusion */
{
- int rendertargetdim_uniform, coc_uniform, color_uniform, select_uniform, dof_uniform;
int rendertargetdim[2] = {fx->dof_downsampled_w, fx->dof_downsampled_h};
float selection[2] = {0.0f, 1.0f};
- rendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "rendertargetdim");
-
- color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
- coc_uniform = GPU_shader_get_uniform(dof_shader_pass2, "cocbuffer");
- select_uniform = GPU_shader_get_uniform(dof_shader_pass2, "layerselection");
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
+ GPUDOFHQPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2);
GPU_shader_bind(dof_shader_pass2);
- GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector_int(dof_shader_pass2, rendertargetdim_uniform, 2, 1, rendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector_int(dof_shader_pass2, interface->rendertargetdim_uniform, 2, 1, rendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection);
GPU_texture_bind(fx->dof_nearfar_coc, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, coc_uniform, fx->dof_nearfar_coc);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->coc_uniform, fx->dof_nearfar_coc);
GPU_texture_bind(fx->dof_half_downsampled_far, numslots++);
GPU_texture_bind(fx->dof_half_downsampled_near, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_far);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far);
GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false);
/* target is the downsampled coc buffer */
@@ -917,6 +979,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
+ glPointSize(1.0f);
/* have to clear the buffer unfortunately */
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -926,13 +989,13 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
GPU_texture_unbind(fx->dof_half_downsampled_far);
GPU_framebuffer_texture_detach(fx->dof_far_blur);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_half_downsampled_near);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near);
GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false);
selection[0] = 1.0f;
selection[1] = 0.0f;
- GPU_shader_uniform_vector(dof_shader_pass2, select_uniform, 2, 1, selection);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->select_uniform, 2, 1, selection);
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_blur, 0, NULL);
/* have to clear the buffer unfortunately */
@@ -954,40 +1017,31 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* third pass, accumulate the near/far blur fields */
{
- int invrendertargetdim_uniform, near_uniform, color_uniform;
- int dof_uniform, far_uniform, viewvecs_uniform, depth_uniform;
-
float invrendertargetdim[2] = {1.0f / fx->dof_downsampled_w, 1.0f / fx->dof_downsampled_h};
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass3, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass3, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
- far_uniform = GPU_shader_get_uniform(dof_shader_pass3, "farbuffer");
- near_uniform = GPU_shader_get_uniform(dof_shader_pass3, "nearbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass3, "viewvecs");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass3, "depthbuffer");
+ GPUDOFHQPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3);
GPU_shader_bind(dof_shader_pass3);
- GPU_shader_uniform_vector(dof_shader_pass3, dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass3, interface->dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass3, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass3, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass3, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass3, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
GPU_texture_bind(fx->dof_near_blur, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_uniform, fx->dof_near_blur);
+ GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur);
GPU_texture_filter_mode(fx->dof_near_blur, false, true);
GPU_texture_bind(fx->dof_far_blur, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, far_uniform, fx->dof_far_blur);
+ GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur);
GPU_texture_filter_mode(fx->dof_far_blur, false, true);
GPU_texture_bind(fx->depth_buffer, numslots++);
GPU_texture_filter_mode(fx->depth_buffer, false, false);
- GPU_shader_uniform_texture(dof_shader_pass3, depth_uniform, fx->depth_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, color_uniform, src);
+ GPU_shader_uniform_texture(dof_shader_pass3, interface->color_uniform, src);
/* if this is the last pass, prepare for rendering on the frambuffer */
gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
@@ -1018,9 +1072,12 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
else {
GPUShader *dof_shader_pass1, *dof_shader_pass2, *dof_shader_pass3, *dof_shader_pass4, *dof_shader_pass5;
- /* DOF effect has many passes but most of them are performed on a texture whose dimensions are 4 times less than the original
- * (16 times lower than original screen resolution). Technique used is not very exact but should be fast enough and is based
- * on "Practical Post-Process Depth of Field" see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
+ /* DOF effect has many passes but most of them are performed
+ * on a texture whose dimensions are 4 times less than the original
+ * (16 times lower than original screen resolution).
+ * Technique used is not very exact but should be fast enough and is based
+ * on "Practical Post-Process Depth of Field"
+ * see http://http.developer.nvidia.com/GPUGems3/gpugems3_ch28.html */
dof_shader_pass1 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE, is_persp);
dof_shader_pass2 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO, is_persp);
dof_shader_pass3 = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE, is_persp);
@@ -1035,35 +1092,28 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
GPU_shader_unbind();
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
return false;
}
/* pass first, first level of blur in low res buffer */
{
- int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
- int viewvecs_uniform;
-
float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass1, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass1, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass1, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass1, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass1, "viewvecs");
+ GPUDOFPassOneInterface *interface = GPU_shader_get_interface(dof_shader_pass1);
GPU_shader_bind(dof_shader_pass1);
- GPU_shader_uniform_vector(dof_shader_pass1, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass1, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass1, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass1, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass1, color_uniform, src);
+ GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src);
GPU_texture_bind(fx->depth_buffer, numslots++);
GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass1, depth_uniform, fx->depth_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer);
/* target is the downsampled coc buffer */
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
@@ -1082,34 +1132,28 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* second pass, gaussian blur the downsampled image */
{
- int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform;
- int viewvecs_uniform;
- float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
+ float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer),
+ 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)};
float tmp = invrendertargetdim[0];
invrendertargetdim[0] = 0.0f;
- dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
+ GPUDOFPassTwoInterface *interface = GPU_shader_get_interface(dof_shader_pass2);
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim");
- color_uniform = GPU_shader_get_uniform(dof_shader_pass2, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass2, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass2, "viewvecs");
+ dof_params[2] = GPU_texture_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor);
/* Blurring vertically */
GPU_shader_bind(dof_shader_pass2);
- GPU_shader_uniform_vector(dof_shader_pass2, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass2, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
GPU_texture_bind(fx->depth_buffer, numslots++);
GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass2, depth_uniform, fx->depth_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer);
GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_buffer);
/* use final buffer as a temp here */
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
@@ -1124,10 +1168,10 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* Blurring horizontally */
invrendertargetdim[0] = tmp;
invrendertargetdim[1] = 0.0f;
- GPU_shader_uniform_vector(dof_shader_pass2, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass2, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass2, color_uniform, fx->dof_near_coc_final_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_near_coc_final_buffer);
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_blurred_buffer, 0, NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -1146,18 +1190,15 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* third pass, calculate near coc */
{
- int near_coc_downsampled, near_coc_blurred;
-
- near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass3, "colorbuffer");
- near_coc_blurred = GPU_shader_get_uniform(dof_shader_pass3, "blurredcolorbuffer");
+ GPUDOFPassThreeInterface *interface = GPU_shader_get_interface(dof_shader_pass3);
GPU_shader_bind(dof_shader_pass3);
GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_coc_downsampled, fx->dof_near_coc_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_downsampled, fx->dof_near_coc_buffer);
GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass3, near_coc_blurred, fx->dof_near_coc_blurred_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass3, interface->near_coc_blurred, fx->dof_near_coc_blurred_buffer);
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_final_buffer, 0, NULL);
@@ -1174,19 +1215,16 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* fourth pass blur final coc once to eliminate discontinuities */
{
- int near_coc_downsampled;
- int invrendertargetdim_uniform;
- float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer),
- 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)};
+ float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer),
+ 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)};
- near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim");
+ GPUDOFPassFourInterface *interface = GPU_shader_get_interface(dof_shader_pass4);
GPU_shader_bind(dof_shader_pass4);
GPU_texture_bind(fx->dof_near_coc_final_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass4, near_coc_downsampled, fx->dof_near_coc_final_buffer);
- GPU_shader_uniform_vector(dof_shader_pass4, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_texture(dof_shader_pass4, interface->near_coc_downsampled, fx->dof_near_coc_final_buffer);
+ GPU_shader_uniform_vector(dof_shader_pass4, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_near_coc_buffer, 0, NULL);
@@ -1203,36 +1241,28 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
/* final pass, merge blurred layers according to final calculated coc */
{
- int medium_blurred_uniform, high_blurred_uniform, original_uniform, depth_uniform, dof_uniform;
- int invrendertargetdim_uniform, viewvecs_uniform;
float invrendertargetdim[2] = {1.0f / fx->gbuffer_dim[0], 1.0f / fx->gbuffer_dim[1]};
- medium_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "mblurredcolorbuffer");
- high_blurred_uniform = GPU_shader_get_uniform(dof_shader_pass5, "blurredcolorbuffer");
- dof_uniform = GPU_shader_get_uniform(dof_shader_pass5, "dof_params");
- invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass5, "invrendertargetdim");
- original_uniform = GPU_shader_get_uniform(dof_shader_pass5, "colorbuffer");
- depth_uniform = GPU_shader_get_uniform(dof_shader_pass5, "depthbuffer");
- viewvecs_uniform = GPU_shader_get_uniform(dof_shader_pass5, "viewvecs");
+ GPUDOFPassFiveInterface *interface = GPU_shader_get_interface(dof_shader_pass5);
GPU_shader_bind(dof_shader_pass5);
- GPU_shader_uniform_vector(dof_shader_pass5, dof_uniform, 4, 1, dof_params);
- GPU_shader_uniform_vector(dof_shader_pass5, invrendertargetdim_uniform, 2, 1, invrendertargetdim);
- GPU_shader_uniform_vector(dof_shader_pass5, viewvecs_uniform, 4, 3, viewvecs[0]);
+ GPU_shader_uniform_vector(dof_shader_pass5, interface->dof_uniform, 4, 1, dof_params);
+ GPU_shader_uniform_vector(dof_shader_pass5, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim);
+ GPU_shader_uniform_vector(dof_shader_pass5, interface->viewvecs_uniform, 4, 3, viewvecs[0]);
GPU_texture_bind(src, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, original_uniform, src);
+ GPU_shader_uniform_texture(dof_shader_pass5, interface->original_uniform, src);
GPU_texture_bind(fx->dof_near_coc_blurred_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass5, interface->high_blurred_uniform, fx->dof_near_coc_blurred_buffer);
GPU_texture_bind(fx->dof_near_coc_buffer, numslots++);
- GPU_shader_uniform_texture(dof_shader_pass5, medium_blurred_uniform, fx->dof_near_coc_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer);
GPU_texture_bind(fx->depth_buffer, numslots++);
GPU_texture_filter_mode(fx->depth_buffer, false, true);
- GPU_shader_uniform_texture(dof_shader_pass5, depth_uniform, fx->depth_buffer);
+ GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer);
/* if this is the last pass, prepare for rendering on the frambuffer */
gpu_fx_bind_render_target(&passes_left, fx, ofs, target);
@@ -1264,7 +1294,7 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
GPU_shader_unbind();
@@ -1287,3 +1317,148 @@ void GPU_fx_compositor_init_ssao_settings(GPUSSAOSettings *fx_ssao)
fx_ssao->attenuation = 1.0f;
fx_ssao->samples = 20;
}
+
+void GPU_fx_shader_init_interface(struct GPUShader *shader, GPUFXShaderEffect effect)
+{
+ if (!shader)
+ return;
+
+ switch (effect) {
+ case GPU_SHADER_FX_SSAO:
+ {
+ GPUSSAOShaderInterface *interface = MEM_mallocN(sizeof(GPUSSAOShaderInterface), "GPUSSAOShaderInterface");
+
+ interface->ssao_uniform = GPU_shader_get_uniform(shader, "ssao_params");
+ interface->ssao_color_uniform = GPU_shader_get_uniform(shader, "ssao_color");
+ interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+ interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
+ interface->ssao_sample_params_uniform = GPU_shader_get_uniform(shader, "ssao_sample_params");
+ interface->ssao_concentric_tex = GPU_shader_get_uniform(shader, "ssao_concentric_tex");
+ interface->ssao_jitter_uniform = GPU_shader_get_uniform(shader, "jitter_tex");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
+ {
+ GPUDOFHQPassOneInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassOneInterface), "GPUDOFHQPassOneInterface");
+
+ interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
+ interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+ interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
+ {
+ GPUDOFHQPassTwoInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassTwoInterface), "GPUDOFHQPassTwoInterface");
+
+ interface->rendertargetdim_uniform = GPU_shader_get_uniform(shader, "rendertargetdim");
+ interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->coc_uniform = GPU_shader_get_uniform(shader, "cocbuffer");
+ interface->select_uniform = GPU_shader_get_uniform(shader, "layerselection");
+ interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
+ {
+ GPUDOFHQPassThreeInterface *interface = MEM_mallocN(sizeof(GPUDOFHQPassThreeInterface), "GPUDOFHQPassThreeInterface");
+
+ interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
+ interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
+ interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->far_uniform = GPU_shader_get_uniform(shader, "farbuffer");
+ interface->near_uniform = GPU_shader_get_uniform(shader, "nearbuffer");
+ interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
+ {
+ GPUDOFPassOneInterface *interface = MEM_mallocN(sizeof(GPUDOFPassOneInterface), "GPUDOFPassOneInterface");
+
+ interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
+ interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
+ interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+ interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
+ {
+ GPUDOFPassTwoInterface *interface = MEM_mallocN(sizeof(GPUDOFPassTwoInterface), "GPUDOFPassTwoInterface");
+
+ interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
+ interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
+ interface->color_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+ interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
+ {
+ GPUDOFPassThreeInterface *interface = MEM_mallocN(sizeof(GPUDOFPassThreeInterface), "GPUDOFPassThreeInterface");
+
+ interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->near_coc_blurred = GPU_shader_get_uniform(shader, "blurredcolorbuffer");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
+ {
+ GPUDOFPassFourInterface *interface = MEM_mallocN(sizeof(GPUDOFPassFourInterface), "GPUDOFPassFourInterface");
+
+ interface->near_coc_downsampled = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
+ {
+ GPUDOFPassFiveInterface *interface = MEM_mallocN(sizeof(GPUDOFPassFiveInterface), "GPUDOFPassFiveInterface");
+
+ interface->medium_blurred_uniform = GPU_shader_get_uniform(shader, "mblurredcolorbuffer");
+ interface->high_blurred_uniform = GPU_shader_get_uniform(shader, "blurredcolorbuffer");
+ interface->dof_uniform = GPU_shader_get_uniform(shader, "dof_params");
+ interface->invrendertargetdim_uniform = GPU_shader_get_uniform(shader, "invrendertargetdim");
+ interface->original_uniform = GPU_shader_get_uniform(shader, "colorbuffer");
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+ interface->viewvecs_uniform = GPU_shader_get_uniform(shader, "viewvecs");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+
+ case GPU_SHADER_FX_DEPTH_RESOLVE:
+ {
+ GPUDepthResolveInterface *interface = MEM_mallocN(sizeof(GPUDepthResolveInterface), "GPUDepthResolveInterface");
+
+ interface->depth_uniform = GPU_shader_get_uniform(shader, "depthbuffer");
+
+ GPU_shader_set_interface(shader, interface);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
diff --git a/source/blender/gpu/intern/gpu_debug.c b/source/blender/gpu/intern/gpu_debug.c
index 1c194f517aa..be9285727fe 100644
--- a/source/blender/gpu/intern/gpu_debug.c
+++ b/source/blender/gpu/intern/gpu_debug.c
@@ -43,7 +43,7 @@
#define CASE_CODE_RETURN_STR(code) case code: return #code;
-static const char* gpu_gl_error_symbol(GLenum err)
+static const char *gpu_gl_error_symbol(GLenum err)
{
switch (err) {
CASE_CODE_RETURN_STR(GL_NO_ERROR)
@@ -81,8 +81,8 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str)
}
else {
/* glGetError should have cleared the error flag, so if we get the
- same flag twice that means glGetError itself probably triggered
- the error. This happens on Windows if the GL context is invalid.
+ * same flag twice that means glGetError itself probably triggered
+ * the error. This happens on Windows if the GL context is invalid.
*/
{
GLenum new_error = glGetError();
@@ -92,22 +92,18 @@ static bool gpu_report_gl_errors(const char *file, int line, const char *str)
}
}
- fprintf(
- stderr,
- "%s(%d): ``%s'' -> GL Error (0x%04X - %s): %s\n",
- file,
- line,
- str,
- gl_error,
- gpu_gl_error_symbol(gl_error),
- gpuErrorString(gl_error));
+ fprintf(stderr,
+ "%s:%d: ``%s'' -> GL Error (0x%04X - %s): %s\n",
+ file, line, str, gl_error,
+ gpu_gl_error_symbol(gl_error),
+ gpuErrorString(gl_error));
return false;
}
}
-const char* gpuErrorString(GLenum err)
+const char *gpuErrorString(GLenum err)
{
switch (err) {
case GL_NO_ERROR:
@@ -199,7 +195,7 @@ void gpu_debug_init(void)
#if !defined(WITH_GLEW_ES) && !defined(GLEW_ES_ONLY)
if (GLEW_VERSION_4_3) {
glEnable(GL_DEBUG_OUTPUT);
- glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext());
+ glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_string_marker(sizeof(success), success);
return;
@@ -208,16 +204,16 @@ void gpu_debug_init(void)
if (GLEW_KHR_debug) {
#ifndef GLEW_ES_ONLY
- glDebugMessageCallback(gpu_debug_proc, mxGetCurrentContext());
- glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
- GPU_string_marker(sizeof(success), success);
+ glDebugMessageCallback((GLDEBUGPROC)gpu_debug_proc, mxGetCurrentContext());
+ glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
+ GPU_string_marker(sizeof(success), success);
#endif
return;
}
#ifndef GLEW_ES_ONLY
if (GLEW_ARB_debug_output) {
- glDebugMessageCallbackARB(gpu_debug_proc, mxGetCurrentContext());
+ glDebugMessageCallbackARB((GLDEBUGPROCARB)gpu_debug_proc, mxGetCurrentContext());
glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
GPU_string_marker(sizeof(success), success);
@@ -280,7 +276,9 @@ void GPU_string_marker(size_t length, const char *buf)
#ifndef WITH_GLEW_ES
#ifndef GLEW_ES_ONLY
if (GLEW_VERSION_4_3) {
- glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
+ glDebugMessageInsert(
+ GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
+ GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
return;
}
@@ -289,20 +287,26 @@ void GPU_string_marker(size_t length, const char *buf)
if (GLEW_KHR_debug) {
#ifndef GLEW_ES_ONLY
- glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0, GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
+ glDebugMessageInsert(
+ GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_MARKER, 0,
+ GL_DEBUG_SEVERITY_NOTIFICATION, length, buf);
#endif
return;
}
#ifndef GLEW_ES_ONLY
if (GLEW_ARB_debug_output) {
- glDebugMessageInsertARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0, GL_DEBUG_SEVERITY_LOW_ARB, length, buf);
+ glDebugMessageInsertARB(
+ GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_OTHER_ARB, 0,
+ GL_DEBUG_SEVERITY_LOW_ARB, length, buf);
return;
}
if (GLEW_AMD_debug_output) {
- glDebugMessageInsertAMD(GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0, length, buf);
+ glDebugMessageInsertAMD(
+ GL_DEBUG_CATEGORY_APPLICATION_AMD, GL_DEBUG_SEVERITY_LOW_AMD, 0,
+ length, buf);
return;
}
@@ -324,7 +328,7 @@ void GPU_print_error_debug(const char *str)
}
-void GPU_assert_no_gl_errors(const char* file, int line, const char* str)
+void GPU_assert_no_gl_errors(const char *file, int line, const char *str)
{
if (G.debug) {
GLboolean gl_ok = gpu_report_gl_errors(file, line, str);
@@ -461,7 +465,7 @@ void GPU_state_print(void)
gpu_state_print_fl(GL_FOG_INDEX);
gpu_state_print_fl(GL_FOG_MODE);
gpu_state_print_fl(GL_FOG_START);
- gpu_state_print_fl(GL_FRAGMENT_PROGRAM_ARB);
+ gpu_state_print_fl(GL_FRAGMENT_PROGRAM_ARB); /* TODO: remove ARB program support */
gpu_state_print_fl(GL_FRAGMENT_SHADER_DERIVATIVE_HINT);
gpu_state_print_fl(GL_FRONT_FACE);
gpu_state_print_fl(GL_GENERATE_MIPMAP_HINT);
@@ -564,7 +568,6 @@ void GPU_state_print(void)
gpu_state_print_fl(GL_MODELVIEW_MATRIX);
gpu_state_print_fl(GL_MODELVIEW_STACK_DEPTH);
gpu_state_print_fl(GL_MULTISAMPLE);
- gpu_state_print_fl(GL_MULTISAMPLE_ARB);
gpu_state_print_fl(GL_NAME_STACK_DEPTH);
gpu_state_print_fl(GL_NORMALIZE);
gpu_state_print_fl(GL_NORMAL_ARRAY);
@@ -690,7 +693,6 @@ void GPU_state_print(void)
gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_STRIDE);
gpu_state_print_fl(GL_TEXTURE_COORD_ARRAY_TYPE);
gpu_state_print_fl(GL_TEXTURE_CUBE_MAP);
- gpu_state_print_fl(GL_TEXTURE_CUBE_MAP_ARB);
gpu_state_print_fl(GL_TEXTURE_GEN_Q);
gpu_state_print_fl(GL_TEXTURE_GEN_R);
gpu_state_print_fl(GL_TEXTURE_GEN_S);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index bf7b8fbc386..1c22c89abf9 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -49,6 +49,7 @@
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
@@ -74,17 +75,19 @@
#include "BKE_subsurf.h"
#include "BKE_DerivedMesh.h"
+#include "GPU_basic_shader.h"
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
#include "PIL_time.h"
#include "smoke_API.h"
#ifdef WITH_OPENSUBDIV
-# include "DNA_mesh_types.h"
# include "BKE_editmesh.h"
# include "gpu_codegen.h"
@@ -113,11 +116,8 @@ void GPU_render_text(
const float *v3 = v_quad[2];
const float *v4 = v_quad[3];
Image *ima = (Image *)mtexpoly->tpage;
- ImBuf *first_ibuf;
const size_t textlen_st = textlen;
- size_t index;
float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
- float advance_tab;
/* multiline */
float line_start = 0.0f, line_height;
@@ -139,14 +139,14 @@ void GPU_render_text(
glPushMatrix();
/* get the tab width */
- first_ibuf = BKE_image_get_first_ibuf(ima);
+ ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima);
matrixGlyph(first_ibuf, ' ', &centerx, &centery,
&sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
- advance_tab = advance * 4; /* tab width could also be an option */
+ float advance_tab = advance * 4; /* tab width could also be an option */
- for (index = 0; index < textlen_st; ) {
+ for (size_t index = 0; index < textlen_st; ) {
unsigned int character;
float uv[4][2];
@@ -182,17 +182,17 @@ void GPU_render_text(
uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy;
glBegin(GL_POLYGON);
- if (glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[0]);
+ if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]);
else glTexCoord2fv(uv[0]);
if (col) gpu_mcol(col[0]);
glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
- if (glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[1]);
+ if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]);
else glTexCoord2fv(uv[1]);
if (col) gpu_mcol(col[1]);
glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
- if (glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[2]);
+ if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[2]);
else glTexCoord2fv(uv[2]);
if (col) gpu_mcol(col[2]);
glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
@@ -201,7 +201,7 @@ void GPU_render_text(
uv[3][0] = (uv_quad[3][0] - centerx) * sizex + transx;
uv[3][1] = (uv_quad[3][1] - centery) * sizey + transy;
- if (glattrib >= 0) glVertexAttrib2fvARB(glattrib, uv[3]);
+ if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[3]);
else glTexCoord2fv(uv[3]);
if (col) gpu_mcol(col[3]);
glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
@@ -217,27 +217,28 @@ void GPU_render_text(
}
}
-/* Checking powers of two for images since opengl 1.x requires it */
+/* Checking powers of two for images since OpenGL ES requires it */
static bool is_power_of_2_resolution(int w, int h)
{
return is_power_of_2_i(w) && is_power_of_2_i(h);
}
-static bool is_over_resolution_limit(int w, int h)
+static bool is_over_resolution_limit(GLenum textarget, int w, int h)
{
- int reslimit = (U.glreslimit != 0)?
- min_ii(U.glreslimit, GPU_max_texture_size()) :
- GPU_max_texture_size();
+ int size = (textarget == GL_TEXTURE_2D) ?
+ GPU_max_texture_size() : GPU_max_cube_map_size();
+ int reslimit = (U.glreslimit != 0) ?
+ min_ii(U.glreslimit, size) : size;
return (w > reslimit || h > reslimit);
}
static int smaller_power_of_2_limit(int num)
{
- int reslimit = (U.glreslimit != 0)?
- min_ii(U.glreslimit, GPU_max_texture_size()) :
- GPU_max_texture_size();
+ int reslimit = (U.glreslimit != 0) ?
+ min_ii(U.glreslimit, GPU_max_texture_size()) :
+ GPU_max_texture_size();
/* take texture clamping into account */
if (num > reslimit)
return reslimit;
@@ -294,7 +295,11 @@ static void gpu_generate_mipmap(GLenum target)
glEnable(target);
}
- glGenerateMipmapEXT(target);
+ /* TODO: simplify when we transition to GL >= 3 */
+ if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object)
+ glGenerateMipmap(target);
+ else if (GLEW_EXT_framebuffer_object)
+ glGenerateMipmapEXT(target);
if (is_ati && !target_enabled)
glDisable(target);
@@ -357,8 +362,9 @@ void GPU_set_anisotropic(float value)
GPU_free_images();
/* Clamp value to the maximum value the graphics card supports */
- if (value > GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)
- value = GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;
+ const float max = GPU_max_texture_anisotropy();
+ if (value > max)
+ value = max;
GTS.anisotropic = value;
}
@@ -373,9 +379,7 @@ float GPU_get_anisotropic(void)
static void gpu_make_repbind(Image *ima)
{
- ImBuf *ibuf;
-
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (ibuf == NULL)
return;
@@ -386,14 +390,27 @@ static void gpu_make_repbind(Image *ima)
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
}
- ima->totbind = ima->xrep*ima->yrep;
+ ima->totbind = ima->xrep * ima->yrep;
- if (ima->totbind>1)
+ if (ima->totbind > 1) {
ima->repbind = MEM_callocN(sizeof(int) * ima->totbind, "repbind");
+ }
BKE_image_release_ibuf(ima, ibuf, NULL);
}
+static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget)
+{
+ unsigned int *bind = 0;
+
+ if (textarget == GL_TEXTURE_2D)
+ bind = &ima->bindcode[TEXTARGET_TEXTURE_2D];
+ else if (textarget == GL_TEXTURE_CUBE_MAP)
+ bind = &ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP];
+
+ return bind;
+}
+
void GPU_clear_tpage(bool force)
{
if (GTS.lasttface == NULL && !force)
@@ -438,10 +455,7 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
/* for OpenGL render we use the alpha channel, this makes alpha blend correct */
- if (GLEW_VERSION_1_4)
- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- else
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
/* if U.glalphaclip == 1.0, some cards go bonkers...
* turn off alpha test in this case */
@@ -495,21 +509,19 @@ static void gpu_verify_reflection(Image *ima)
}
}
-int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data)
+int GPU_verify_image(Image *ima, ImageUser *iuser, int textarget, int tftile, bool compare, bool mipmap, bool is_data)
{
- ImBuf *ibuf = NULL;
unsigned int *bind = NULL;
- int rectw, recth, tpx = 0, tpy = 0, y;
- unsigned int *tilerect = NULL, *rect = NULL;
- float *ftilerect = NULL, *frect = NULL;
+ int tpx = 0, tpy = 0;
+ unsigned int *rect = NULL;
+ float *frect = NULL;
float *srgb_frect = NULL;
- short texwindx, texwindy, texwinsx, texwinsy;
- /* flag to determine whether high resolution format is used */
+ /* flag to determine whether deep format is used */
bool use_high_bit_depth = false, do_color_management = false;
/* initialize tile mode and number of repeats */
GTS.ima = ima;
- GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES|IMA_TWINANIM)));
+ GTS.tilemode = (ima && (ima->tpageflag & (IMA_TILES | IMA_TWINANIM)));
GTS.tileXRep = 0;
GTS.tileYRep = 0;
@@ -552,7 +564,7 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
return 0;
/* check if we have a valid image buffer */
- ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
if (ibuf == NULL)
return 0;
@@ -588,18 +600,18 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (GTS.tile >= ima->totbind) GTS.tile = 0;
/* this happens when you change repeat buttons */
- if (ima->repbind) bind = &ima->repbind[GTS.tile];
- else bind = &ima->bindcode;
+ if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile];
+ else bind = gpu_get_image_bindcode(ima, textarget);
if (*bind == 0) {
- texwindx = ibuf->x / ima->xrep;
- texwindy = ibuf->y / ima->yrep;
+ short texwindx = ibuf->x / ima->xrep;
+ short texwindy = ibuf->y / ima->yrep;
if (GTS.tile >= ima->xrep * ima->yrep)
GTS.tile = ima->xrep * ima->yrep - 1;
- texwinsy = GTS.tile / ima->xrep;
- texwinsx = GTS.tile - texwinsy * ima->xrep;
+ short texwinsy = GTS.tile / ima->xrep;
+ short texwinsx = GTS.tile - texwinsy * ima->xrep;
texwinsx *= texwindx;
texwinsy *= texwindy;
@@ -616,18 +628,20 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
/* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
- frect = srgb_frect + texwinsy*ibuf->x + texwinsx;
+ frect = srgb_frect + texwinsy * ibuf->x + texwinsx;
+ }
+ else {
+ frect = ibuf->rect_float + texwinsy * ibuf->x + texwinsx;
}
- else
- frect = ibuf->rect_float + texwinsy*ibuf->x + texwinsx;
}
- else
- rect = ibuf->rect + texwinsy*ibuf->x + texwinsx;
+ else {
+ rect = ibuf->rect + texwinsy * ibuf->x + texwinsx;
+ }
}
}
else {
/* regular image mode */
- bind= &ima->bindcode;
+ bind = gpu_get_image_bindcode(ima, textarget);
if (*bind == 0) {
tpx = ibuf->x;
@@ -636,9 +650,10 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (use_high_bit_depth) {
if (do_color_management) {
frect = srgb_frect = MEM_mallocN(ibuf->x * ibuf->y * sizeof(*srgb_frect) * 4, "floar_buf_col_cor");
- IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
- ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
- ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+ IMB_buffer_float_from_float(
+ srgb_frect, ibuf->rect_float,
+ ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, true,
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
/* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
@@ -651,24 +666,25 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
if (*bind != 0) {
/* enable opengl drawing with textures */
- glBindTexture(GL_TEXTURE_2D, *bind);
+ glBindTexture(textarget, *bind);
BKE_image_release_ibuf(ima, ibuf, NULL);
return *bind;
}
- rectw = tpx;
- recth = tpy;
+ const int rectw = tpx;
+ const int recth = tpy;
+
+ unsigned *tilerect = NULL;
+ float *ftilerect = NULL;
/* for tiles, copy only part of image into buffer */
if (GTS.tilemode) {
if (use_high_bit_depth) {
- float *frectrow, *ftilerectrow;
-
- ftilerect = MEM_mallocN(rectw*recth*sizeof(*ftilerect), "tilerect");
+ ftilerect = MEM_mallocN(rectw * recth * sizeof(*ftilerect), "tilerect");
- for (y = 0; y < recth; y++) {
- frectrow = &frect[y * ibuf->x];
- ftilerectrow = &ftilerect[y * rectw];
+ for (int y = 0; y < recth; y++) {
+ const float *frectrow = &frect[y * ibuf->x];
+ float *ftilerectrow = &ftilerect[y * rectw];
memcpy(ftilerectrow, frectrow, tpx * sizeof(*frectrow));
}
@@ -676,13 +692,11 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
frect = ftilerect;
}
else {
- unsigned int *rectrow, *tilerectrow;
+ tilerect = MEM_mallocN(rectw * recth * sizeof(*tilerect), "tilerect");
- tilerect = MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
-
- for (y = 0; y < recth; y++) {
- rectrow = &rect[y * ibuf->x];
- tilerectrow = &tilerect[y * rectw];
+ for (int y = 0; y < recth; y++) {
+ const unsigned *rectrow = &rect[y * ibuf->x];
+ unsigned *tilerectrow = &tilerect[y * rectw];
memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
}
@@ -693,10 +707,10 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
#ifdef WITH_DDS
if (ibuf->ftype == IMB_FTYPE_DDS)
- GPU_create_gl_tex_compressed(bind, rect, rectw, recth, mipmap, ima, ibuf);
+ GPU_create_gl_tex_compressed(bind, rect, rectw, recth, textarget, mipmap, ima, ibuf);
else
#endif
- GPU_create_gl_tex(bind, rect, frect, rectw, recth, mipmap, use_high_bit_depth, ima);
+ GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
/* mark as non-color data texture */
if (*bind) {
@@ -719,9 +733,76 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
return *bind;
}
+static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int recth, bool use_high_bit_depth)
+{
+ size_t block_size = use_high_bit_depth ? sizeof(float) * 4 : sizeof(unsigned char) * 4;
+ void **sides = NULL;
+ int h = recth / 2;
+ int w = rectw / 3;
+
+ if ((use_high_bit_depth && frect == NULL) || (!use_high_bit_depth && rect == NULL) || w != h)
+ return sides;
+
+ /* PosX, NegX, PosY, NegY, PosZ, NegZ */
+ sides = MEM_mallocN(sizeof(void *) * 6, "");
+ for (int i = 0; i < 6; i++)
+ sides[i] = MEM_mallocN(block_size * w * h, "");
+
+ /* divide image into six parts */
+ /* ______________________
+ * | | | |
+ * | NegX | NegY | PosX |
+ * |______|______|______|
+ * | | | |
+ * | NegZ | PosZ | PosY |
+ * |______|______|______|
+ */
+ if (use_high_bit_depth) {
+ float (*frectb)[4] = (float(*)[4])frect;
+ float (**fsides)[4] = (float(**)[4])sides;
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ memcpy(&fsides[0][x * h + y], &frectb[(recth - y - 1) * rectw + 2 * w + x], block_size);
+ memcpy(&fsides[1][x * h + y], &frectb[(y + h) * rectw + w - 1 - x], block_size);
+ memcpy(&fsides[3][y * w + x], &frectb[(recth - y - 1) * rectw + 2 * w - 1 - x], block_size);
+ memcpy(&fsides[5][y * w + x], &frectb[(h - y - 1) * rectw + w - 1 - x], block_size);
+ }
+ memcpy(&fsides[2][y * w], frectb[y * rectw + 2 * w], block_size * w);
+ memcpy(&fsides[4][y * w], frectb[y * rectw + w], block_size * w);
+ }
+ }
+ else {
+ unsigned int **isides = (unsigned int **)sides;
+
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ isides[0][x * h + y] = rect[(recth - y - 1) * rectw + 2 * w + x];
+ isides[1][x * h + y] = rect[(y + h) * rectw + w - 1 - x];
+ isides[3][y * w + x] = rect[(recth - y - 1) * rectw + 2 * w - 1 - x];
+ isides[5][y * w + x] = rect[(h - y - 1) * rectw + w - 1 - x];
+ }
+ memcpy(&isides[2][y * w], &rect[y * rectw + 2 * w], block_size * w);
+ memcpy(&isides[4][y * w], &rect[y * rectw + w], block_size * w);
+ }
+ }
+
+ return sides;
+}
+
+static void gpu_del_cube_map(void **cube_map)
+{
+ int i;
+ if (cube_map == NULL)
+ return;
+ for (i = 0; i < 6; i++)
+ MEM_freeN(cube_map[i]);
+ MEM_freeN(cube_map);
+}
+
/* Image *ima can be NULL */
void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int rectw, int recth,
- bool mipmap, bool use_high_bit_depth, Image *ima)
+ int textarget, bool mipmap, bool use_high_bit_depth, Image *ima)
{
ImBuf *ibuf = NULL;
@@ -731,11 +812,13 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int
/* scale if not a power of two. this is not strictly necessary for newer
* GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures
* Then don't bother scaling for hardware that supports NPOT textures! */
- if ((!GPU_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) ||
- is_over_resolution_limit(rectw, recth)) {
+ if (textarget == GL_TEXTURE_2D &&
+ ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) ||
+ is_over_resolution_limit(textarget, rectw, recth)))
+ {
rectw = smaller_power_of_2_limit(rectw);
recth = smaller_power_of_2_limit(recth);
-
+
if (use_high_bit_depth) {
ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
IMB_scaleImBuf(ibuf, rectw, recth);
@@ -752,63 +835,124 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int
/* create image */
glGenTextures(1, (GLuint *)bind);
- glBindTexture(GL_TEXTURE_2D, *bind);
+ glBindTexture(textarget, *bind);
- if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
+ if (textarget == GL_TEXTURE_2D) {
+ if (use_high_bit_depth) {
+ if (GLEW_ARB_texture_float)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
+ }
else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
-
- if (GPU_get_mipmap() && mipmap) {
- if (GTS.gpu_mipmap) {
- gpu_generate_mipmap(GL_TEXTURE_2D);
- }
- else {
- int i;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- if (!ibuf) {
- if (use_high_bit_depth) {
- ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ if (GPU_get_mipmap() && mipmap) {
+ if (GTS.gpu_mipmap) {
+ gpu_generate_mipmap(GL_TEXTURE_2D);
+ }
+ else {
+ int i;
+ if (!ibuf) {
+ if (use_high_bit_depth) {
+ ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ }
+ else {
+ ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ }
}
- else {
- ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ IMB_makemipmap(ibuf, true);
+
+ for (i = 1; i < ibuf->miptot; i++) {
+ ImBuf *mip = ibuf->mipmap[i - 1];
+ if (use_high_bit_depth) {
+ if (GLEW_ARB_texture_float)
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F_ARB, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ else
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ }
+ else {
+ glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ }
}
}
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
+ if (ima)
+ ima->tpageflag |= IMA_MIPMAP_COMPLETE;
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ }
+ else if (textarget == GL_TEXTURE_CUBE_MAP) {
+ int w = rectw / 3, h = recth / 2;
+
+ if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
+ void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth, use_high_bit_depth);
+ GLenum informat = use_high_bit_depth ? (GLEW_ARB_texture_float ? GL_RGBA16F_ARB : GL_RGBA16) : GL_RGBA8;
+ GLenum type = use_high_bit_depth ? GL_FLOAT : GL_UNSIGNED_BYTE;
+
+ if (cube_map)
+ for (int i = 0; i < 6; i++)
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, informat, w, h, 0, GL_RGBA, type, cube_map[i]);
- IMB_makemipmap(ibuf, true);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- for (i = 1; i < ibuf->miptot; i++) {
- ImBuf *mip = ibuf->mipmap[i - 1];
- if (use_high_bit_depth) {
- if (GLEW_ARB_texture_float)
- glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
- else
- glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float);
+ if (GPU_get_mipmap() && mipmap) {
+ if (GTS.gpu_mipmap) {
+ gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP);
}
else {
- glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect);
+ if (!ibuf) {
+ if (use_high_bit_depth) {
+ ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
+ }
+ else {
+ ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
+ }
+ }
+
+ IMB_makemipmap(ibuf, true);
+
+ for (int i = 1; i < ibuf->miptot; i++) {
+ ImBuf *mip = ibuf->mipmap[i - 1];
+ void **mip_cube_map = gpu_gen_cube_map(
+ mip->rect, mip->rect_float,
+ mip->x, mip->y, use_high_bit_depth);
+ int mipw = mip->x / 3, miph = mip->y / 2;
+
+ if (mip_cube_map) {
+ for (int j = 0; j < 6; j++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
+ informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
+ }
+ }
+ gpu_del_cube_map(mip_cube_map);
+ }
}
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
+
+ if (ima)
+ ima->tpageflag |= IMA_MIPMAP_COMPLETE;
}
- }
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
+ else {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- if (ima)
- ima->tpageflag |= IMA_MIPMAP_COMPLETE;
- }
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ gpu_del_cube_map(cube_map);
+ }
+ else {
+ printf("Incorrect envmap size\n");
+ }
}
if (GLEW_EXT_texture_filter_anisotropic)
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
- /* set to modulate with vertex color */
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameterf(textarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
if (ibuf)
IMB_freeImBuf(ibuf);
@@ -850,19 +994,17 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
if (GLEW_EXT_texture_filter_anisotropic)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic());
blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i = 0; i < ibuf->dds_data.nummipmaps && (width||height); ++i) {
+ for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); ++i) {
if (width == 0)
width = 1;
if (height == 0)
height = 1;
- size = ((width+3)/4)*((height+3)/4)*blocksize;
+ size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
0, size, ibuf->dds_data.data + offset);
@@ -882,21 +1024,21 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
#endif
}
-void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x, int y, int mipmap, Image *ima, ImBuf *ibuf)
+void GPU_create_gl_tex_compressed(
+ unsigned int *bind, unsigned int *pix, int x, int y,
+ int textarget, int mipmap, Image *ima, ImBuf *ibuf)
{
#ifndef WITH_DDS
(void)ibuf;
/* Fall back to uncompressed if DDS isn't enabled */
- GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
+ GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
#else
-
-
glGenTextures(1, (GLuint *)bind);
- glBindTexture(GL_TEXTURE_2D, *bind);
+ glBindTexture(textarget, *bind);
- if (GPU_upload_dxt_texture(ibuf) == 0) {
+ if (textarget == GL_TEXTURE_2D && GPU_upload_dxt_texture(ibuf) == 0) {
glDeleteTextures(1, (GLuint *)bind);
- GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
+ GPU_create_gl_tex(bind, pix, NULL, x, y, textarget, mipmap, 0, ima);
}
#endif
}
@@ -916,21 +1058,19 @@ static void gpu_verify_repeat(Image *ima)
int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend)
{
- Image *ima;
-
/* check if we need to clear the state */
if (mtexpoly == NULL) {
GPU_clear_tpage(false);
return 0;
}
- ima = mtexpoly->tpage;
+ Image *ima = mtexpoly->tpage;
GTS.lasttface = mtexpoly;
gpu_verify_alpha_blend(alphablend);
gpu_verify_reflection(ima);
- if (GPU_verify_image(ima, NULL, mtexpoly->tile, 1, mipmap, false)) {
+ if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) {
GTS.curtile = GTS.tile;
GTS.curima = GTS.ima;
GTS.curtilemode = GTS.tilemode;
@@ -965,20 +1105,25 @@ int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend)
* re-uploaded to OpenGL */
void GPU_paint_set_mipmap(bool mipmap)
{
- Image *ima;
-
if (!GTS.domipmap)
return;
GTS.texpaint = !mipmap;
if (mipmap) {
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
- if (ima->bindcode) {
+ for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
+ if (BKE_image_has_bindcode(ima)) {
if (ima->tpageflag & IMA_MIPMAP_COMPLETE) {
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ }
+ if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
+ glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ }
}
else
GPU_free_image(ima);
@@ -989,11 +1134,18 @@ void GPU_paint_set_mipmap(bool mipmap)
}
else {
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
- if (ima->bindcode) {
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
+ if (BKE_image_has_bindcode(ima)) {
+ if (ima->bindcode[TEXTARGET_TEXTURE_2D]) {
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ }
+ if (ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]) {
+ glBindTexture(GL_TEXTURE_CUBE_MAP, ima->bindcode[TEXTARGET_TEXTURE_CUBE_MAP]);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
+ }
}
else
ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@ -1005,8 +1157,8 @@ void GPU_paint_set_mipmap(bool mipmap)
/* check if image has been downscaled and do scaled partial update */
static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
{
- if ((!GPU_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
- is_over_resolution_limit(ibuf->x, ibuf->y))
+ if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
+ is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y))
{
int x_limit = smaller_power_of_2_limit(ibuf->x);
int y_limit = smaller_power_of_2_limit(ibuf->y);
@@ -1029,14 +1181,14 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
/* float rectangles are already continuous in memory so we can use IMB_scaleImBuf */
if (frect) {
- ImBuf *ibuf = IMB_allocFromBuffer(NULL, frect, w, h);
- IMB_scaleImBuf(ibuf, rectw, recth);
+ ImBuf *ibuf_scale = IMB_allocFromBuffer(NULL, frect, w, h);
+ IMB_scaleImBuf(ibuf_scale, rectw, recth);
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
- GL_FLOAT, ibuf->rect_float);
+ GL_FLOAT, ibuf_scale->rect_float);
- IMB_freeImBuf(ibuf);
+ IMB_freeImBuf(ibuf_scale);
}
/* byte images are not continuous in memory so do manual interpolation */
else {
@@ -1052,7 +1204,7 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
bilinear_interpolation_color_wrap(ibuf, (unsigned char *)(p + i + j * (rectw)), NULL, u, v);
}
}
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, rectw, recth, GL_RGBA,
GL_UNSIGNED_BYTE, scalerect);
@@ -1074,12 +1226,13 @@ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
- ImBuf *ibuf;
-
- ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
-
- if (ima->repbind || (GPU_get_mipmap() && !GTS.gpu_mipmap) || !ima->bindcode || !ibuf ||
- (w == 0) || (h == 0))
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+
+ if (ima->repbind ||
+ (!GTS.gpu_mipmap && GPU_get_mipmap()) ||
+ (ima->bindcode[TEXTARGET_TEXTURE_2D] == 0) ||
+ (ibuf == NULL) ||
+ (w == 0) || (h == 0))
{
/* these cases require full reload still */
GPU_free_image(ima);
@@ -1101,7 +1254,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, buffer);
MEM_freeN(buffer);
@@ -1124,7 +1277,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
return;
}
- glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]);
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
@@ -1155,9 +1308,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
void GPU_update_images_framechange(void)
{
- Image *ima;
-
- for (ima = G.main->image.first; ima; ima = ima->id.next) {
+ for (Image *ima = G.main->image.first; ima; ima = ima->id.next) {
if (ima->tpageflag & IMA_TWINANIM) {
if (ima->twend >= ima->xrep * ima->yrep)
ima->twend = ima->xrep * ima->yrep - 1;
@@ -1173,10 +1324,6 @@ void GPU_update_images_framechange(void)
int GPU_update_image_time(Image *ima, double time)
{
- int inc = 0;
- float diff;
- int newframe;
-
if (!ima)
return 0;
@@ -1186,17 +1333,19 @@ int GPU_update_image_time(Image *ima, double time)
if (ima->lastupdate > (float)time)
ima->lastupdate = (float)time;
+ int inc = 0;
+
if (ima->tpageflag & IMA_TWINANIM) {
if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
/* check: is the bindcode not in the array? Then free. (still to do) */
- diff = (float)((float)time - ima->lastupdate);
+ float diff = (float)((float)time - ima->lastupdate);
inc = (int)(diff * (float)ima->animspeed);
ima->lastupdate += ((float)inc / (float)ima->animspeed);
- newframe = ima->lastframe + inc;
+ int newframe = ima->lastframe + inc;
if (newframe > (int)ima->twend) {
if (ima->twend - ima->twsta != 0)
@@ -1284,17 +1433,14 @@ static void gpu_queue_image_for_free(Image *ima)
void GPU_free_unused_buffers(void)
{
- LinkNode *node;
- Image *ima;
-
if (!BLI_thread_is_main())
return;
BLI_lock_thread(LOCK_OPENGL);
/* images */
- for (node = image_free_queue; node; node = node->next) {
- ima = node->link;
+ for (LinkNode *node = image_free_queue; node; node = node->next) {
+ Image *ima = node->link;
/* check in case it was freed in the meantime */
if (G.main && BLI_findindex(&G.main->image, ima) != -1)
@@ -1317,16 +1463,17 @@ void GPU_free_image(Image *ima)
return;
}
- /* free regular image binding */
- if (ima->bindcode) {
- glDeleteTextures(1, (GLuint *)&ima->bindcode);
- ima->bindcode = 0;
- }
-
- /* free glsl image binding */
- if (ima->gputexture) {
- GPU_texture_free(ima->gputexture);
- ima->gputexture = NULL;
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ /* free regular image binding */
+ if (ima->bindcode[i]) {
+ glDeleteTextures(1, (GLuint *)&ima->bindcode[i]);
+ ima->bindcode[i] = 0;
+ }
+ /* free glsl image binding */
+ if (ima->gputexture[i]) {
+ GPU_texture_free(ima->gputexture[i]);
+ ima->gputexture[i] = NULL;
+ }
}
/* free repeated image binding */
@@ -1337,25 +1484,21 @@ void GPU_free_image(Image *ima)
ima->repbind = NULL;
}
- ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE|IMA_GLBIND_IS_DATA);
+ ima->tpageflag &= ~(IMA_MIPMAP_COMPLETE | IMA_GLBIND_IS_DATA);
}
void GPU_free_images(void)
{
- Image *ima;
-
if (G.main)
- for (ima = G.main->image.first; ima; ima = ima->id.next)
+ for (Image *ima = G.main->image.first; ima; ima = ima->id.next)
GPU_free_image(ima);
}
/* same as above but only free animated images */
void GPU_free_images_anim(void)
{
- Image *ima;
-
if (G.main)
- for (ima = G.main->image.first; ima; ima = ima->id.next)
+ for (Image *ima = G.main->image.first; ima; ima = ima->id.next)
if (BKE_image_is_animated(ima))
GPU_free_image(ima);
}
@@ -1363,7 +1506,6 @@ void GPU_free_images_anim(void)
void GPU_free_images_old(void)
{
- Image *ima;
static int lasttime = 0;
int ctime = (int)PIL_check_seconds_timer();
@@ -1380,12 +1522,12 @@ void GPU_free_images_old(void)
lasttime = ctime;
- ima = G.main->image.first;
+ Image *ima = G.main->image.first;
while (ima) {
if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
/* If it's in GL memory, deallocate and set time tag to current time
* This gives textures a "second chance" to be used before dying. */
- if (ima->bindcode || ima->repbind) {
+ if (BKE_image_has_bindcode(ima) || ima->repbind) {
GPU_free_image(ima);
ima->lastused = ctime;
}
@@ -1406,9 +1548,10 @@ void GPU_free_images_old(void)
/* OpenGL state caching for materials */
typedef struct GPUMaterialFixed {
- float diff[4];
- float spec[4];
+ float diff[3];
+ float spec[3];
int hard;
+ float alpha;
} GPUMaterialFixed;
static struct GPUMaterialState {
@@ -1417,7 +1560,7 @@ static struct GPUMaterialState {
int totmat;
/* set when called inside GPU_begin_object_materials / GPU_end_object_materials
- * otherwise calling GPU_enable_material returns zero */
+ * otherwise calling GPU_object_material_bind returns zero */
bool is_enabled;
Material **gmatbuf;
@@ -1433,6 +1576,7 @@ static struct GPUMaterialState {
float (*gviewcamtexcofac);
bool backface_culling;
+ bool two_sided_lighting;
GPUBlendMode *alphablend;
GPUBlendMode alphablend_fixed[FIXEDMAT];
@@ -1445,25 +1589,24 @@ static struct GPUMaterialState {
} GMS = {NULL};
/* fixed function material, alpha handed by caller */
-static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob, const int new_shading_nodes,
- const bool dimdown)
+static void gpu_material_to_fixed(
+ GPUMaterialFixed *smat, const Material *bmat, const int gamma, const Object *ob,
+ const int new_shading_nodes, const bool dimdown)
{
if (bmat->mode & MA_SHLESS) {
copy_v3_v3(smat->diff, &bmat->r);
- smat->diff[3] = 1.0;
if (gamma)
linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
- zero_v4(smat->spec);
+ zero_v3(smat->spec);
+ smat->alpha = 1.0f;
smat->hard = 0;
}
else if (new_shading_nodes) {
copy_v3_v3(smat->diff, &bmat->r);
- smat->diff[3] = 1.0;
-
copy_v3_v3(smat->spec, &bmat->specr);
- smat->spec[3] = 1.0;
+ smat->alpha = 1.0f;
smat->hard = CLAMPIS(bmat->har, 0, 128);
if (dimdown) {
@@ -1478,14 +1621,13 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat,
}
else {
mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit);
- smat->diff[3] = 1.0; /* caller may set this to bmat->alpha */
if (bmat->shade_flag & MA_OBCOLOR)
mul_v3_v3(smat->diff, ob->col);
mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
- smat->spec[3] = 1.0; /* always 1 */
- smat->hard= CLAMPIS(bmat->har, 0, 128);
+ smat->hard = CLAMPIS(bmat->har, 1, 128);
+ smat->alpha = 1.0f;
if (gamma) {
linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
@@ -1518,7 +1660,9 @@ void GPU_end_dupli_object(void)
GMS.dob = NULL;
}
-void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob, bool glsl, bool *do_alpha_after)
+void GPU_begin_object_materials(
+ View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob,
+ bool glsl, bool *do_alpha_after)
{
Material *ma;
GPUMaterial *gpumat;
@@ -1573,11 +1717,15 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
+ GMS.two_sided_lighting = false;
+ if (ob && ob->type == OB_MESH)
+ GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0;
+
GMS.gob = ob;
GMS.gscene = scene;
GMS.is_opensubdiv = use_opensubdiv;
GMS.totmat = use_matcap ? 1 : ob->totcol + 1; /* materials start from 1, default material is 0 */
- GMS.glay = (v3d->localvd)? v3d->localvd->lay: v3d->lay; /* keep lamps visible in local view */
+ GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */
GMS.gscenelock = (v3d->scenelock != 0);
GMS.gviewmat = rv3d->viewmat;
GMS.gviewinv = rv3d->viewinv;
@@ -1639,7 +1787,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
if (ma == NULL) ma = &defmaterial;
/* create glsl material if requested */
- gpumat = glsl? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv): NULL;
+ gpumat = glsl ? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv) : NULL;
if (gpumat) {
/* do glsl only if creating it succeed, else fallback */
@@ -1651,11 +1799,11 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false);
if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) {
- GMS.matbuf[a].diff[3] = ma->alpha;
- alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
+ GMS.matbuf[a].alpha = ma->alpha;
+ alphablend = (ma->alpha == 1.0f) ? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;
}
else {
- GMS.matbuf[a].diff[3] = 1.0f;
+ GMS.matbuf[a].alpha = 1.0f;
alphablend = GPU_BLEND_SOLID;
}
}
@@ -1671,22 +1819,21 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
}
/* let's start with a clean state */
- GPU_disable_material();
+ GPU_object_material_unbind();
}
static int GPU_get_particle_info(GPUParticleInfo *pi)
{
- ParticleData *p;
DupliObject *dob = GMS.dob;
- int ind;
if (dob->particle_system) {
+ int ind;
if (dob->persistent_id[0] < dob->particle_system->totpart)
ind = dob->persistent_id[0];
else {
ind = dob->particle_system->child[dob->persistent_id[0] - dob->particle_system->totpart].parent;
}
if (ind >= 0) {
- p = &dob->particle_system->particles[ind];
+ ParticleData *p = &dob->particle_system->particles[ind];
pi->scalprops[0] = ind;
pi->scalprops[1] = GMS.gscene->r.cfra - p->time;
@@ -1704,27 +1851,23 @@ static int GPU_get_particle_info(GPUParticleInfo *pi)
return 0;
}
-int GPU_enable_material(int nr, void *attribs)
+int GPU_object_material_bind(int nr, void *attribs)
{
GPUVertexAttribs *gattribs = attribs;
- GPUMaterial *gpumat;
- GPUBlendMode alphablend;
/* no GPU_begin_object_materials, use default material */
if (!GMS.matbuf) {
- float diff[4], spec[4];
-
memset(&GMS, 0, sizeof(GMS));
- mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit);
- diff[3] = 1.0;
-
- mul_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec);
- spec[3] = 1.0;
+ float diffuse[3], specular[3];
+ mul_v3_v3fl(diffuse, &defmaterial.r, defmaterial.ref + defmaterial.emit);
+ mul_v3_v3fl(specular, &defmaterial.specr, defmaterial.spec);
+ GPU_basic_shader_colors(diffuse, specular, 35, 1.0f);
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35); /* blender default */
+ if (GMS.two_sided_lighting)
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
+ else
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
return 0;
}
@@ -1761,7 +1904,7 @@ int GPU_enable_material(int nr, void *attribs)
if (GMS.lastretval) {
/* for alpha pass, use alpha blend */
- alphablend = GMS.alphablend[nr];
+ GPUBlendMode alphablend = GMS.alphablend[nr];
if (gattribs && GMS.gmatbuf[nr]) {
/* bind glsl material and get attributes */
@@ -1770,22 +1913,24 @@ int GPU_enable_material(int nr, void *attribs)
float auto_bump_scale;
- gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
+ GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv);
GPU_material_vertex_attributes(gpumat, gattribs);
if (GMS.dob)
GPU_get_particle_info(&partile_info);
- GPU_material_bind(gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
+ GPU_material_bind(
+ gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
+ GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale, &partile_info);
+ GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info);
GMS.gboundmat = mat;
/* for glsl use alpha blend mode, unless it's set to solid and
* we are already drawing in an alpha pass */
if (mat->game.alpha_blend != GPU_BLEND_SOLID)
- alphablend= mat->game.alpha_blend;
+ alphablend = mat->game.alpha_blend;
if (GMS.is_alpha_pass) glDepthMask(1);
@@ -1801,9 +1946,13 @@ int GPU_enable_material(int nr, void *attribs)
}
else {
/* or do fixed function opengl material */
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, GMS.matbuf[nr].diff);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, GMS.matbuf[nr].spec);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, GMS.matbuf[nr].hard);
+ GPU_basic_shader_colors(GMS.matbuf[nr].diff,
+ GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha);
+
+ if (GMS.two_sided_lighting)
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED);
+ else
+ GPU_basic_shader_bind(GPU_SHADER_LIGHTING);
}
/* set (alpha) blending mode */
@@ -1813,6 +1962,31 @@ int GPU_enable_material(int nr, void *attribs)
return GMS.lastretval;
}
+int GPU_object_material_visible(int nr, void *attribs)
+{
+ GPUVertexAttribs *gattribs = attribs;
+ int visible;
+
+ if (!GMS.matbuf)
+ return 0;
+
+ if (gattribs)
+ memset(gattribs, 0, sizeof(*gattribs));
+
+ if (nr >= GMS.totmat)
+ nr = 0;
+
+ if (GMS.use_alpha_pass) {
+ visible = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP);
+ if (GMS.is_alpha_pass)
+ visible = !visible;
+ }
+ else
+ visible = !GMS.is_alpha_pass;
+
+ return visible;
+}
+
void GPU_set_material_alpha_blend(int alphablend)
{
if (GMS.lastalphablend == alphablend)
@@ -1827,7 +2001,7 @@ int GPU_get_material_alpha_blend(void)
return GMS.lastalphablend;
}
-void GPU_disable_material(void)
+void GPU_object_material_unbind(void)
{
GMS.lastmatnr = -1;
GMS.lastretval = 1;
@@ -1840,6 +2014,8 @@ void GPU_disable_material(void)
GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv));
GMS.gboundmat = NULL;
}
+ else
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
GPU_set_material_alpha_blend(GPU_BLEND_SOLID);
}
@@ -1855,7 +2031,8 @@ void GPU_material_diffuse_get(int nr, float diff[4])
mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit);
}
else {
- copy_v4_v4(diff, GMS.matbuf[nr].diff);
+ copy_v3_v3(diff, GMS.matbuf[nr].diff);
+ diff[3] = GMS.matbuf[nr].alpha;
}
}
@@ -1871,7 +2048,7 @@ bool GPU_object_materials_check(void)
void GPU_end_object_materials(void)
{
- GPU_disable_material();
+ GPU_object_material_unbind();
GMS.is_enabled = false;
@@ -1884,6 +2061,7 @@ void GPU_end_object_materials(void)
GMS.matbuf = NULL;
GMS.gmatbuf = NULL;
GMS.alphablend = NULL;
+ GMS.two_sided_lighting = false;
/* resetting the texture matrix after the scaling needed for tiled textures */
if (GTS.tilemode) {
@@ -1897,9 +2075,6 @@ void GPU_end_object_materials(void)
int GPU_default_lights(void)
{
- float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}, position[4];
- int a, count = 0;
-
/* initialize */
if (U.light[0].flag == 0 && U.light[1].flag == 0 && U.light[2].flag == 0) {
U.light[0].flag = 1;
@@ -1921,111 +2096,87 @@ int GPU_default_lights(void)
U.light[2].spec[3] = 1.0;
}
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
+ GPU_basic_shader_light_set_viewer(false);
- for (a = 0; a < 8; a++) {
- if (a < 3) {
- if (U.light[a].flag) {
- glEnable(GL_LIGHT0 + a);
+ int count = 0;
- normalize_v3_v3(position, U.light[a].vec);
- position[3] = 0.0f;
-
- glLightfv(GL_LIGHT0 + a, GL_POSITION, position);
- glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, U.light[a].col);
- glLightfv(GL_LIGHT0 + a, GL_SPECULAR, U.light[a].spec);
+ for (int a = 0; a < 8; a++) {
+ if (a < 3 && U.light[a].flag) {
+ GPULightData light = {0};
- count++;
- }
- else {
- glDisable(GL_LIGHT0 + a);
+ light.type = GPU_LIGHT_SUN;
- glLightfv(GL_LIGHT0 + a, GL_POSITION, zero);
- glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, zero);
- glLightfv(GL_LIGHT0 + a, GL_SPECULAR, zero);
- }
+ normalize_v3_v3(light.direction, U.light[a].vec);
+ copy_v3_v3(light.diffuse, U.light[a].col);
+ copy_v3_v3(light.specular, U.light[a].spec);
+
+ GPU_basic_shader_light_set(a, &light);
- /* clear stuff from other opengl lamp usage */
- glLightf(GL_LIGHT0 + a, GL_SPOT_CUTOFF, 180.0);
- glLightf(GL_LIGHT0 + a, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0 + a, GL_LINEAR_ATTENUATION, 0.0);
+ count++;
}
else
- glDisable(GL_LIGHT0 + a);
+ GPU_basic_shader_light_set(a, NULL);
}
-
- glDisable(GL_LIGHTING);
-
- glDisable(GL_COLOR_MATERIAL);
return count;
}
int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho)
{
- Base *base;
- Lamp *la;
- int count;
- float position[4], direction[4], energy[4];
-
/* disable all lights */
- for (count = 0; count < 8; count++)
- glDisable(GL_LIGHT0 + count);
+ for (int count = 0; count < 8; count++)
+ GPU_basic_shader_light_set(count, NULL);
/* view direction for specular is not computed correct by default in
* opengl, so we set the settings ourselfs */
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, ortho ? GL_FALSE : GL_TRUE);
+ GPU_basic_shader_light_set_viewer(!ortho);
- count = 0;
+ int count = 0;
- for (base = scene->base.first; base; base = base->next) {
+ for (Base *base = scene->base.first; base; base = base->next) {
if (base->object->type != OB_LAMP)
continue;
if (!(base->lay & lay) || !(base->lay & ob->lay))
continue;
- la = base->object->data;
+ Lamp *la = base->object->data;
/* setup lamp transform */
glPushMatrix();
glLoadMatrixf((float *)viewmat);
- if (la->type == LA_SUN) {
- /* sun lamp */
- copy_v3_v3(direction, base->object->obmat[2]);
- direction[3] = 0.0;
+ /* setup light */
+ GPULightData light = {0};
+
+ mul_v3_v3fl(light.diffuse, &la->r, la->energy);
+ mul_v3_v3fl(light.specular, &la->r, la->energy);
- glLightfv(GL_LIGHT0+count, GL_POSITION, direction);
+ if (la->type == LA_SUN) {
+ /* directional sun light */
+ light.type = GPU_LIGHT_SUN;
+ normalize_v3_v3(light.direction, base->object->obmat[2]);
}
else {
- /* other lamps with attenuation */
- copy_v3_v3(position, base->object->obmat[3]);
- position[3] = 1.0f;
-
- glLightfv(GL_LIGHT0+count, GL_POSITION, position);
- glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
- glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1 / la->dist);
- glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2 / (la->dist * la->dist));
+ /* other lamps with position attenuation */
+ copy_v3_v3(light.position, base->object->obmat[3]);
+
+ light.constant_attenuation = 1.0f;
+ light.linear_attenuation = la->att1 / la->dist;
+ light.quadratic_attenuation = la->att2 / (la->dist * la->dist);
if (la->type == LA_SPOT) {
- /* spot lamp */
- negate_v3_v3(direction, base->object->obmat[2]);
- glLightfv(GL_LIGHT0 + count, GL_SPOT_DIRECTION, direction);
- glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f));
- glLightf(GL_LIGHT0 + count, GL_SPOT_EXPONENT, 128.0f * la->spotblend);
+ light.type = GPU_LIGHT_SPOT;
+ negate_v3_v3(light.direction, base->object->obmat[2]);
+ normalize_v3(light.direction);
+ light.spot_cutoff = RAD2DEGF(la->spotsize * 0.5f);
+ light.spot_exponent = 128.0f * la->spotblend;
}
else
- glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, 180.0);
+ light.type = GPU_LIGHT_POINT;
}
- /* setup energy */
- mul_v3_v3fl(energy, &la->r, la->energy);
- energy[3] = 1.0;
-
- glLightfv(GL_LIGHT0 + count, GL_DIFFUSE, energy);
- glLightfv(GL_LIGHT0 + count, GL_SPECULAR, energy);
- glEnable(GL_LIGHT0 + count);
+ GPU_basic_shader_light_set(count, &light);
glPopMatrix();
@@ -2039,50 +2190,50 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
static void gpu_multisample(bool enable)
{
- if (GLEW_VERSION_1_3 || GLEW_ARB_multisample) {
#ifdef __linux__
- /* changing multisample from the default (enabled) causes problems on some
- * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */
- bool toggle_ok = true;
+ /* changing multisample from the default (enabled) causes problems on some
+ * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */
+ bool toggle_ok = true;
- if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
- int samples = 0;
- glGetIntegerv(GL_SAMPLES, &samples);
+ if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
+ int samples = 0;
+ glGetIntegerv(GL_SAMPLES, &samples);
- if (samples == 0)
- toggle_ok = false;
- }
+ if (samples == 0)
+ toggle_ok = false;
+ }
- if (toggle_ok) {
- if (enable)
- glEnable(GL_MULTISAMPLE);
- else
- glDisable(GL_MULTISAMPLE);
- }
-#else
+ if (toggle_ok) {
if (enable)
glEnable(GL_MULTISAMPLE);
else
glDisable(GL_MULTISAMPLE);
-#endif
}
+#else
+ if (enable)
+ glEnable(GL_MULTISAMPLE);
+ else
+ glDisable(GL_MULTISAMPLE);
+#endif
}
-/* Default OpenGL State */
+/* Default OpenGL State
+ *
+ * This is called on startup, for opengl offscreen render and to restore state
+ * for the game engine. Generally we should always return to this state when
+ * temporarily modifying the state for drawing, though that are (undocumented)
+ * exceptions that we should try to get rid of. */
void GPU_state_init(void)
{
- /* also called when doing opengl rendering and in the game engine */
float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
- int a, x, y;
- GLubyte pat[32 * 32];
- const GLubyte *patc = pat;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
GPU_default_lights();
@@ -2097,10 +2248,12 @@ void GPU_state_init(void)
glDisable(GL_DEPTH_TEST);
glDisable(GL_FOG);
glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LOGIC_OP);
glDisable(GL_STENCIL_TEST);
glDisable(GL_TEXTURE_1D);
glDisable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
/* default disabled, enable should be local per function */
glDisableClientState(GL_VERTEX_ARRAY);
@@ -2121,16 +2274,6 @@ void GPU_state_init(void)
glPixelTransferi(GL_DEPTH_BIAS, 0);
glPixelTransferi(GL_DEPTH_SCALE, 1);
glDepthRange(0.0, 1.0);
-
- a = 0;
- for (x = 0; x < 32; x++) {
- for (y = 0; y < 4; y++) {
- if (x & 1) pat[a++] = 0x88;
- else pat[a++] = 0x22;
- }
- }
-
- glPolygonStipple(patc);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
@@ -2141,6 +2284,8 @@ void GPU_state_init(void)
glDisable(GL_CULL_FACE);
gpu_multisample(false);
+
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
#ifdef WITH_OPENSUBDIV
@@ -2149,13 +2294,11 @@ void GPU_state_init(void)
*/
void GPU_draw_update_fvar_offset(DerivedMesh *dm)
{
- int i;
-
/* Sanity check to be sure we only do this for OpenSubdiv draw. */
BLI_assert(dm->type == DM_TYPE_CCGDM);
BLI_assert(GMS.is_opensubdiv);
- for (i = 0; i < GMS.totmat; ++i) {
+ for (int i = 0; i < GMS.totmat; ++i) {
Material *material = GMS.gmatbuf[i];
GPUMaterial *gpu_material;
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index e30eeebf934..7d433a78411 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -32,9 +32,6 @@
* with checks for drivers and GPU support.
*/
-
-#include "DNA_image_types.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
@@ -44,12 +41,11 @@
#include "BKE_global.h"
-#include "GPU_glew.h"
-#include "GPU_debug.h"
+#include "GPU_basic_shader.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
-#include "GPU_compositing.h"
-#include "GPU_simple_shader.h"
+#include "GPU_glew.h"
+#include "GPU_texture.h"
#include "intern/gpu_private.h"
@@ -61,79 +57,36 @@
# include "BLI_winstuff.h"
#endif
-/* TODO(sergey): Find better default values for this constants. */
-#define MAX_DEFINE_LENGTH 1024
-#define MAX_EXT_DEFINE_LENGTH 1024
-
/* Extensions support */
-/* extensions used:
- * - texture border clamp: 1.3 core
- * - fragment shader: 2.0 core
- * - framebuffer object: ext specification
- * - multitexture 1.3 core
- * - arb non power of two: 2.0 core
- * - pixel buffer objects? 2.1 core
- * - arb draw buffers? 2.0 core
+/* -- extension: version of GL that absorbs it
+ * ARB_framebuffer object: 3.0
+ * EXT_framebuffer_object: 3.0
+ * EXT_framebuffer_blit: 3.0
+ * EXT_framebuffer_multisample: 3.0
+ * EXT_framebuffer_multisample_blit_scaled: ???
+ * ARB_draw_instanced: 3.1
+ * ARB_texture_multisample: 3.2
+ * EXT_geometry_shader4: 3.2
+ * ARB_texture_query_lod: 4.0
*/
-/* Non-generated shaders */
-extern char datatoc_gpu_program_smoke_frag_glsl[];
-extern char datatoc_gpu_program_smoke_color_frag_glsl[];
-extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
-extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
-extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
-extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
-extern char datatoc_gpu_shader_fx_vert_glsl[];
-extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
-extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
-extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
-extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[];
-extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[];
-extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[];
-extern char datatoc_gpu_shader_fx_depth_resolve_glsl[];
-extern char datatoc_gpu_shader_fx_lib_glsl[];
-
-typedef struct GPUShaders {
- GPUShader *vsm_store;
- GPUShader *sep_gaussian_blur;
- GPUProgram *smoke;
- GPUProgram *smoke_colored;
- /* cache for shader fx. Those can exist in combinations so store them here */
- GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
-} GPUShaders;
-
static struct GPUGlobal {
GLint maxtexsize;
+ GLint maxcubemapsize;
GLint maxtextures;
- GLuint currentfb;
- int glslsupport;
- int extdisabled;
+ bool extdisabled;
int colordepth;
- int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */
- int dlistsdisabled; /* Legacy ATI driver does not support display lists well */
+ int samples_color_texture_max;
GPUDeviceType device;
GPUOSType os;
GPUDriverType driver;
- GPUShaders shaders;
- GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
- GPUTexture *invalid_tex_2D;
- GPUTexture *invalid_tex_3D;
float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
calculate dfdy in shader differently when drawing to an offscreen buffer. First
number is factor on screen and second is off-screen */
+ float max_anisotropy;
} GG = {1, 0};
-/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
-#define GPU_FB_MAX_SLOTS 4
-
-struct GPUFrameBuffer {
- GLuint object;
- GPUTexture *colortex[GPU_FB_MAX_SLOTS];
- GPUTexture *depthtex;
-};
-
-
/* GPU Types */
bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
@@ -145,7 +98,7 @@ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
void GPU_extensions_disable(void)
{
- GG.extdisabled = 1;
+ GG.extdisabled = true;
}
int GPU_max_texture_size(void)
@@ -153,6 +106,26 @@ int GPU_max_texture_size(void)
return GG.maxtexsize;
}
+int GPU_max_textures(void)
+{
+ return GG.maxtextures;
+}
+
+float GPU_max_texture_anisotropy(void)
+{
+ return GG.max_anisotropy;
+}
+
+int GPU_max_color_texture_samples(void)
+{
+ return GG.samples_color_texture_max;
+}
+
+int GPU_max_cube_map_size(void)
+{
+ return GG.maxcubemapsize;
+}
+
void GPU_get_dfdy_factors(float fac[2])
{
copy_v2_v2(fac, GG.dfdyfactors);
@@ -160,29 +133,32 @@ void GPU_get_dfdy_factors(float fac[2])
void gpu_extensions_init(void)
{
- GLint r, g, b;
- const char *vendor, *renderer, *version;
+ /* BLI_assert(GLEW_VERSION_2_1); */
+ /* ^-- maybe a bit extreme? */
- /* glewIsSupported("GL_VERSION_2_0") */
-
- if (GLEW_ARB_multitexture)
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &GG.maxtextures);
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize);
+ glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize);
- GG.glslsupport = 1;
- if (!GLEW_ARB_multitexture) GG.glslsupport = 0;
- if (!GLEW_ARB_vertex_shader) GG.glslsupport = 0;
- if (!GLEW_ARB_fragment_shader) GG.glslsupport = 0;
+ if (GLEW_EXT_texture_filter_anisotropic)
+ glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GG.max_anisotropy);
+ else
+ GG.max_anisotropy = 1.0f;
+ GLint r, g, b;
glGetIntegerv(GL_RED_BITS, &r);
glGetIntegerv(GL_GREEN_BITS, &g);
glGetIntegerv(GL_BLUE_BITS, &b);
GG.colordepth = r + g + b; /* assumes same depth for RGB */
- vendor = (const char *)glGetString(GL_VENDOR);
- renderer = (const char *)glGetString(GL_RENDERER);
- version = (const char *)glGetString(GL_VERSION);
+ if (GLEW_VERSION_3_2 || GLEW_ARB_texture_multisample) {
+ glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &GG.samples_color_texture_max);
+ }
+
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ const char *renderer = (const char *)glGetString(GL_RENDERER);
+ const char *version = (const char *)glGetString(GL_VERSION);
if (strstr(vendor, "ATI")) {
GG.device = GPU_DEVICE_ATI;
@@ -193,9 +169,10 @@ void gpu_extensions_init(void)
GG.driver = GPU_DRIVER_OFFICIAL;
}
else if (strstr(vendor, "Intel") ||
- /* src/mesa/drivers/dri/intel/intel_context.c */
- strstr(renderer, "Mesa DRI Intel") ||
- strstr(renderer, "Mesa DRI Mobile Intel")) {
+ /* src/mesa/drivers/dri/intel/intel_context.c */
+ strstr(renderer, "Mesa DRI Intel") ||
+ strstr(renderer, "Mesa DRI Mobile Intel"))
+ {
GG.device = GPU_DEVICE_INTEL;
GG.driver = GPU_DRIVER_OFFICIAL;
}
@@ -224,28 +201,6 @@ void gpu_extensions_init(void)
GG.driver = GPU_DRIVER_ANY;
}
- if (GG.device == GPU_DEVICE_ATI) {
- /* ATI 9500 to X2300 cards support NPoT textures poorly
- * Incomplete list http://dri.freedesktop.org/wiki/ATIRadeon
- * New IDs from MESA's src/gallium/drivers/r300/r300_screen.c
- */
- /* This list is close enough to those using the legacy driver which
- * has a bug with display lists and glVertexAttrib
- */
- if (strstr(renderer, "R3") || strstr(renderer, "RV3") ||
- strstr(renderer, "R4") || strstr(renderer, "RV4") ||
- strstr(renderer, "RS4") || strstr(renderer, "RC4") ||
- strstr(renderer, "R5") || strstr(renderer, "RV5") ||
- strstr(renderer, "RS600") || strstr(renderer, "RS690") ||
- strstr(renderer, "RS740") || strstr(renderer, "X1") ||
- strstr(renderer, "X2") || strstr(renderer, "Radeon 9") ||
- strstr(renderer, "RADEON 9"))
- {
- GG.npotdisabled = 1;
- GG.dlistsdisabled = 1;
- }
- }
-
/* make sure double side isn't used by default and only getting enabled in places where it's
* really needed to prevent different unexpected behaviors like with intel gme965 card (sergey) */
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
@@ -264,12 +219,13 @@ void gpu_extensions_init(void)
GG.dfdyfactors[0] = 1.0;
GG.dfdyfactors[1] = -1.0;
}
- else if (GG.device == GPU_DEVICE_INTEL && GG.os == GPU_OS_WIN &&
- (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
- strstr(version, "4.0.0 - Build 9.18.10.3186") ||
- strstr(version, "4.0.0 - Build 9.18.10.3165") ||
- strstr(version, "3.1.0 - Build 9.17.10.3347") ||
- strstr(version, "3.1.0 - Build 9.17.10.4101")))
+ else if ((GG.device == GPU_DEVICE_INTEL) && (GG.os == GPU_OS_WIN) &&
+ (strstr(version, "4.0.0 - Build 10.18.10.3308") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3186") ||
+ strstr(version, "4.0.0 - Build 9.18.10.3165") ||
+ strstr(version, "3.1.0 - Build 9.17.10.3347") ||
+ strstr(version, "3.1.0 - Build 9.17.10.4101") ||
+ strstr(version, "3.3.0 - Build 8.15.10.2618")))
{
GG.dfdyfactors[0] = -1.0;
GG.dfdyfactors[1] = 1.0;
@@ -281,1931 +237,101 @@ void gpu_extensions_init(void)
GPU_invalid_tex_init();
- GPU_simple_shaders_init();
+ GPU_basic_shaders_init();
}
void gpu_extensions_exit(void)
{
- GPU_simple_shaders_exit();
+ GPU_basic_shaders_exit();
GPU_invalid_tex_free();
}
-bool GPU_glsl_support(void)
-{
- return !GG.extdisabled && GG.glslsupport;
-}
-
-bool GPU_non_power_of_two_support(void)
-{
- if (GG.npotdisabled)
- return false;
-
- return GLEW_ARB_texture_non_power_of_two;
-}
-
-bool GPU_vertex_buffer_support(void)
-{
- return GLEW_ARB_vertex_buffer_object || GLEW_VERSION_1_5;
-}
-
-bool GPU_display_list_support(void)
-{
- return !GG.dlistsdisabled;
-}
-
-bool GPU_bicubic_bump_support(void)
-{
- return GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0;
-}
-
-bool GPU_geometry_shader_support(void)
+bool GPU_legacy_support(void)
{
- return GLEW_EXT_geometry_shader4 || GLEW_VERSION_3_2;
-}
+ /* return whether or not current GL context is compatible with legacy OpenGL */
+ static bool checked = false;
+ static bool support = true;
-bool GPU_instanced_drawing_support(void)
-{
- return GLEW_ARB_draw_instanced;
-}
+ if (!checked) {
+ if (GLEW_VERSION_3_2) {
+ GLint profile;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
-int GPU_color_depth(void)
-{
- return GG.colordepth;
-}
-
-static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
-{
- const char *err = "unknown";
-
- switch (status) {
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- break;
- case GL_INVALID_OPERATION:
- err = "Invalid operation";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
- err = "Incomplete attachment";
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- err = "Unsupported framebuffer format";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
- err = "Missing attachment";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
- err = "Attached images must have same dimensions";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
- err = "Attached images must have same format";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
- err = "Missing draw buffer";
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
- err = "Missing read buffer";
- break;
- }
-
- if (err_out) {
- BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
- (int)status, err);
- }
- else {
- fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
- (int)status, err);
- }
-}
-
-/* GPUTexture */
-
-struct GPUTexture {
- int w, h; /* width/height */
- int w_orig, h_orig; /* width/height (before power of 2 is applied) */
- int number; /* number for multitexture binding */
- int refcount; /* reference count */
- GLenum target; /* GL_TEXTURE_* */
- GLuint bindcode; /* opengl identifier for texture */
- int fromblender; /* we got the texture from Blender */
-
- GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
- int fb_attachment; /* slot the texture is attached to */
- int depth; /* is a depth texture? if 3D how deep? */
- int depth_orig; /* depth (before power of 2 is applied) */
-};
-
-static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
-{
- unsigned char *pixels, *p;
- const float *fp = fpixels;
- const int len = 4 * length;
- int a;
-
- p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
-
- for (a = 0; a < len; a++, p++, fp++)
- *p = FTOCHAR((*fp));
-
- return pixels;
-}
-
-static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
-{
- void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
-
- if (target == GL_TEXTURE_1D)
- glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
- else
- glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
-
- MEM_freeN(pixels);
-}
-
-static GPUTexture *GPU_texture_create_nD(
- int w, int h, int n, const float *fpixels, int depth, GPUHDRType hdr_type, int components,
- char err_out[256])
-{
- GPUTexture *tex;
- GLenum type, format, internalformat;
- void *pixels = NULL;
-
- if (depth && !GLEW_ARB_depth_texture)
- return NULL;
-
- tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->w = tex->w_orig = w;
- tex->h = tex->h_orig = h;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = (n == 1)? GL_TEXTURE_1D: GL_TEXTURE_2D;
- tex->depth = tex->depth_orig = depth;
- tex->fb_attachment = -1;
-
- glGenTextures(1, &tex->bindcode);
-
- if (!tex->bindcode) {
- if (err_out) {
- BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
- (int)glGetError());
- }
- else {
- fprintf(stderr, "GPUTexture: texture create failed: %d\n",
- (int)glGetError());
- }
- GPU_texture_free(tex);
- return NULL;
- }
-
- if (!GPU_non_power_of_two_support()) {
- tex->w = power_of_2_max_i(tex->w);
- tex->h = power_of_2_max_i(tex->h);
- }
-
- tex->number = 0;
- glBindTexture(tex->target, tex->bindcode);
-
- if (depth) {
- type = GL_UNSIGNED_BYTE;
- format = GL_DEPTH_COMPONENT;
- internalformat = GL_DEPTH_COMPONENT;
- }
- else {
- type = GL_FLOAT;
-
- if (components == 4) {
- format = GL_RGBA;
- switch (hdr_type) {
- case GPU_HDR_NONE:
- internalformat = GL_RGBA8;
- break;
- case GPU_HDR_HALF_FLOAT:
- internalformat = GL_RGBA16F;
- break;
- case GPU_HDR_FULL_FLOAT:
- internalformat = GL_RGBA32F;
- break;
- default:
- break;
+ if (G.debug & G_DEBUG_GPU) {
+ printf("GL_CONTEXT_PROFILE_MASK = %#x (%s profile)\n", (unsigned int)profile,
+ profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT ? "compatibility" :
+ profile & GL_CONTEXT_CORE_PROFILE_BIT ? "core" : "unknown");
}
- }
- else if (components == 2) {
- format = GL_RG;
- switch (hdr_type) {
- case GPU_HDR_NONE:
- internalformat = GL_RG8;
- break;
- case GPU_HDR_HALF_FLOAT:
- internalformat = GL_RG16F;
- break;
- case GPU_HDR_FULL_FLOAT:
- internalformat = GL_RG32F;
- break;
- default:
- break;
- }
- }
-
- if (fpixels && hdr_type == GPU_HDR_NONE) {
- type = GL_UNSIGNED_BYTE;
- pixels = GPU_texture_convert_pixels(w*h, fpixels);
- }
- }
-
- if (tex->target == GL_TEXTURE_1D) {
- glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
-
- if (fpixels) {
- glTexSubImage1D(tex->target, 0, 0, w, format, type,
- pixels ? pixels : fpixels);
-
- if (tex->w > w)
- GPU_glTexSubImageEmpty(tex->target, format, w, 0,
- tex->w-w, 1);
- }
- }
- else {
- glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
- format, type, NULL);
-
- if (fpixels) {
- glTexSubImage2D(tex->target, 0, 0, 0, w, h,
- format, type, pixels ? pixels : fpixels);
-
- if (tex->w > w)
- GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h);
- if (tex->h > h)
- GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h);
- }
- }
-
- if (pixels)
- MEM_freeN(pixels);
-
- if (depth) {
- glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(tex->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE);
- glTexParameteri(tex->target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- glTexParameteri(tex->target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
- }
- else {
- glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(tex->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
-
- if (tex->target != GL_TEXTURE_1D) {
- glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(tex->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
- else
- glTexParameteri(tex->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-
- return tex;
-}
-
-
-GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
-{
- GPUTexture *tex;
- GLenum type, format, internalformat;
- void *pixels = NULL;
- int r_width;
- bool rescale = false;
-
- if (!GLEW_VERSION_1_2)
- return NULL;
-
- tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->w = tex->w_orig = w;
- tex->h = tex->h_orig = h;
- tex->depth = tex->depth_orig = depth;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = GL_TEXTURE_3D;
-
- glGenTextures(1, &tex->bindcode);
-
- if (!tex->bindcode) {
- fprintf(stderr, "GPUTexture: texture create failed: %d\n",
- (int)glGetError());
- GPU_texture_free(tex);
- return NULL;
- }
-
- if (!GPU_non_power_of_two_support()) {
- tex->w = power_of_2_max_i(tex->w);
- tex->h = power_of_2_max_i(tex->h);
- tex->depth = power_of_2_max_i(tex->depth);
- }
- tex->number = 0;
- glBindTexture(tex->target, tex->bindcode);
-
- GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture");
-
- type = GL_FLOAT;
- if (channels == 4) {
- format = GL_RGBA;
- internalformat = GL_RGBA;
- }
- else {
- format = GL_RED;
- internalformat = GL_INTENSITY;
- }
-
- /* 3D textures are quite heavy, test if it's possible to create them first */
- glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
-
- while (r_width == 0) {
- rescale = true;
- tex->w /= 2;
- tex->h /= 2;
- tex->depth /= 2;
- glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
- glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
- }
-
- /* really unlikely to happen but keep this just in case */
- tex->w = max_ii(tex->w, 1);
- tex->h = max_ii(tex->h, 1);
- tex->depth = max_ii(tex->depth, 1);
-
-#if 0
- if (fpixels)
- pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
-#endif
-
- GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
-
- /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
- * for gooseberry */
- if (rescale && fpixels) {
- unsigned int i, j, k;
- unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
- float *tex3d = MEM_mallocN(channels * sizeof(float)*tex->w*tex->h*tex->depth, "tex3d");
-
- GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
-
- for (k = 0; k < tex->depth; k++) {
- for (j = 0; j < tex->h; j++) {
- for (i = 0; i < tex->w; i++) {
- /* obviously doing nearest filtering here, it's going to be slow in any case, let's not make it worse */
- float xb = i * xf;
- float yb = j * yf;
- float zb = k * zf;
- unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
- unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
-
- if (channels == 4) {
- tex3d[offset * 4] = fpixels[offset_orig * 4];
- tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
- tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
- tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
- }
- else
- tex3d[offset] = fpixels[offset_orig];
- }
- }
- }
-
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
-
- MEM_freeN(tex3d);
- }
- else {
- if (fpixels) {
- if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) {
- /* clear first to avoid unitialized pixels */
- float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero");
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
- glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, GL_INTENSITY, GL_FLOAT, zero);
- glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels);
- MEM_freeN(zero);
+ if (profile == 0) {
+ /* workaround for nVidia's Linux driver */
+ support = GLEW_ARB_compatibility;
}
else {
- glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
+ support = profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
}
-
- GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
- }
- }
-
-
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
-
- if (pixels)
- MEM_freeN(pixels);
-
- GPU_texture_unbind(tex);
-
- return tex;
-}
-
-GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, double time, int mipmap)
-{
- GPUTexture *tex;
- GLint w, h, border, lastbindcode, bindcode;
-
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
-
- GPU_update_image_time(ima, time);
- /* this binds a texture, so that's why to restore it with lastbindcode */
- bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap, is_data);
-
- if (ima->gputexture) {
- ima->gputexture->bindcode = bindcode;
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
- return ima->gputexture;
- }
-
- tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->bindcode = bindcode;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = GL_TEXTURE_2D;
- tex->fromblender = 1;
-
- ima->gputexture= tex;
-
- if (!glIsTexture(tex->bindcode)) {
- GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
- }
- else {
- glBindTexture(GL_TEXTURE_2D, tex->bindcode);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border);
-
- tex->w = tex->w_orig = w - border;
- tex->h = tex->h_orig = h - border;
- }
-
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
-
- return tex;
-}
-
-GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
-{
- GPUTexture *tex = prv->gputexture[0];
- GLint w, h, lastbindcode;
- GLuint bindcode = 0;
-
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
-
- if (tex)
- bindcode = tex->bindcode;
-
- /* this binds a texture, so that's why to restore it */
- if (bindcode == 0) {
- GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], mipmap, 0, NULL);
- }
- if (tex) {
- tex->bindcode = bindcode;
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
- return tex;
- }
-
- tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
- tex->bindcode = bindcode;
- tex->number = -1;
- tex->refcount = 1;
- tex->target = GL_TEXTURE_2D;
-
- prv->gputexture[0] = tex;
-
- if (!glIsTexture(tex->bindcode)) {
- GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
- }
- else {
- glBindTexture(GL_TEXTURE_2D, tex->bindcode);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
- glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
-
- tex->w = tex->w_orig = w;
- tex->h = tex->h_orig = h;
- }
-
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
-
- return tex;
-
-}
-
-GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
-}
-
-GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
-}
-
-GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, err_out);
-
- if (tex)
- GPU_texture_unbind(tex);
-
- return tex;
-}
-
-/**
- * A shadow map for VSM needs two components (depth and depth^2)
- */
-GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, err_out);
-
- if (tex) {
- /* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- GPU_texture_unbind(tex);
- }
-
- return tex;
-}
-
-GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
-
- if (tex) {
- /* Now we tweak some of the settings */
- if (repeat) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
- GPU_texture_unbind(tex);
- }
-
- return tex;
-}
-
-GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
-{
- GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, err_out);
-
- if (tex) {
- /* Now we tweak some of the settings */
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
- GPU_texture_unbind(tex);
- }
-
- return tex;
-}
-
-void GPU_invalid_tex_init(void)
-{
- const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
- GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
- GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
- GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
-}
-
-void GPU_invalid_tex_bind(int mode)
-{
- switch (mode) {
- case GL_TEXTURE_1D:
- glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode);
- break;
- case GL_TEXTURE_2D:
- glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode);
- break;
- case GL_TEXTURE_3D:
- glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode);
- break;
- }
-}
-
-void GPU_invalid_tex_free(void)
-{
- if (GG.invalid_tex_1D)
- GPU_texture_free(GG.invalid_tex_1D);
- if (GG.invalid_tex_2D)
- GPU_texture_free(GG.invalid_tex_2D);
- if (GG.invalid_tex_3D)
- GPU_texture_free(GG.invalid_tex_3D);
-}
-
-
-void GPU_texture_bind(GPUTexture *tex, int number)
-{
- GLenum arbnumber;
-
- if (number >= GG.maxtextures) {
- fprintf(stderr, "Not enough texture slots.");
- return;
- }
-
- if ((G.debug & G_DEBUG)) {
- if (tex->fb && tex->fb->object == GG.currentfb) {
- fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n");
+ else if (GLEW_VERSION_3_1) {
+ support = GLEW_ARB_compatibility;
}
- }
-
- if (number < 0)
- return;
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind");
+ /* any OpenGL version <= 3.0 is legacy, so support remains true */
- arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
- if (number != 0) glActiveTextureARB(arbnumber);
- if (tex->bindcode != 0) {
- glBindTexture(tex->target, tex->bindcode);
+ checked = true;
}
- else
- GPU_invalid_tex_bind(tex->target);
- glEnable(tex->target);
- if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
-
- tex->number = number;
-
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind");
-}
-
-void GPU_texture_unbind(GPUTexture *tex)
-{
- GLenum arbnumber;
-
- if (tex->number >= GG.maxtextures) {
- fprintf(stderr, "Not enough texture slots.");
- return;
- }
-
- if (tex->number == -1)
- return;
-
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
-
- arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
- if (tex->number != 0) glActiveTextureARB(arbnumber);
- glBindTexture(tex->target, 0);
- glDisable(tex->target);
- if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
-
- tex->number = -1;
-
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
-}
-
-void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
-{
- GLenum arbnumber;
-
- if (tex->number >= GG.maxtextures) {
- fprintf(stderr, "Not enough texture slots.");
- return;
- }
-
- if (tex->number == -1)
- return;
-
- GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
-
- arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
- if (tex->number != 0) glActiveTextureARB(arbnumber);
-
- if (tex->depth) {
- if (compare)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- else
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- }
-
- if (use_filter) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
- else {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- }
- if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
-}
-
-void GPU_texture_free(GPUTexture *tex)
-{
- tex->refcount--;
-
- if (tex->refcount < 0)
- fprintf(stderr, "GPUTexture: negative refcount\n");
-
- if (tex->refcount == 0) {
- if (tex->fb)
- GPU_framebuffer_texture_detach(tex);
- if (tex->bindcode && !tex->fromblender)
- glDeleteTextures(1, &tex->bindcode);
-
- MEM_freeN(tex);
- }
-}
-
-void GPU_texture_ref(GPUTexture *tex)
-{
- tex->refcount++;
-}
-
-int GPU_texture_target(const GPUTexture *tex)
-{
- return tex->target;
-}
-
-int GPU_texture_opengl_width(const GPUTexture *tex)
-{
- return tex->w;
-}
-
-int GPU_texture_opengl_height(const GPUTexture *tex)
-{
- return tex->h;
-}
-
-int GPU_texture_opengl_bindcode(const GPUTexture *tex)
-{
- return tex->bindcode;
-}
-
-GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
-{
- return tex->fb;
-}
-
-/* GPUFrameBuffer */
-
-GPUFrameBuffer *GPU_framebuffer_create(void)
-{
- GPUFrameBuffer *fb;
-
- if (!GLEW_EXT_framebuffer_object)
- return NULL;
-
- fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
- glGenFramebuffersEXT(1, &fb->object);
-
- if (!fb->object) {
- fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
- (int)glGetError());
- GPU_framebuffer_free(fb);
- return NULL;
- }
-
- /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- glReadBuffer(GL_NONE);
- glDrawBuffer(GL_NONE);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-
- return fb;
-}
-
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256])
-{
- GLenum attachment;
- GLenum error;
-
- if (slot >= GPU_FB_MAX_SLOTS) {
- fprintf(stderr, "Attaching to index %d framebuffer slot unsupported in blender use at most %d\n", slot, GPU_FB_MAX_SLOTS);
- return 0;
- }
-
- if ((G.debug & G_DEBUG)) {
- if (tex->number != -1) {
- fprintf(stderr, "Feedback loop warning!: Attempting to attach texture to framebuffer while still bound to texture unit for drawing!");
- }
- }
-
- if (tex->depth)
- attachment = GL_DEPTH_ATTACHMENT_EXT;
- else
- attachment = GL_COLOR_ATTACHMENT0_EXT + slot;
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = fb->object;
-
- /* Clean glError buffer. */
- while (glGetError() != GL_NO_ERROR) {}
-
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
- tex->target, tex->bindcode, 0);
-
- error = glGetError();
-
- if (error == GL_INVALID_OPERATION) {
- GPU_framebuffer_restore();
- GPU_print_framebuffer_error(error, err_out);
- return 0;
- }
-
- if (tex->depth)
- fb->depthtex = tex;
- else
- fb->colortex[slot] = tex;
-
- tex->fb= fb;
- tex->fb_attachment = slot;
-
- return 1;
-}
-
-void GPU_framebuffer_texture_detach(GPUTexture *tex)
-{
- GLenum attachment;
- GPUFrameBuffer *fb;
-
- if (!tex->fb)
- return;
-
- fb = tex->fb;
-
- if (GG.currentfb != fb->object) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = tex->fb->object;
- }
-
- if (tex->depth) {
- fb->depthtex = NULL;
- attachment = GL_DEPTH_ATTACHMENT_EXT;
- }
- else {
- BLI_assert(fb->colortex[tex->fb_attachment] == tex);
- fb->colortex[tex->fb_attachment] = NULL;
- attachment = GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment;
- }
-
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0);
-
- tex->fb = NULL;
- tex->fb_attachment = -1;
-}
-
-void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
-{
- if (!tex->fb) {
- fprintf(stderr, "Error, texture not bound to framebuffer!");
- return;
- }
-
- /* push attributes */
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
- glDisable(GL_SCISSOR_TEST);
-
- /* bind framebuffer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object);
-
- if (tex->depth) {
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
- else {
- /* last bound prevails here, better allow explicit control here too */
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment);
- }
-
- /* push matrices and set default viewport and matrix */
- glViewport(0, 0, tex->w_orig, tex->h_orig);
- GG.currentfb = tex->fb->object;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
-}
-
-void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
-{
- int numslots = 0, i;
- GLenum attachments[4];
-
- if (!fb->colortex[slot]) {
- fprintf(stderr, "Error, framebuffer slot empty!");
- return;
- }
-
- for (i = 0; i < 4; i++) {
- if (fb->colortex[i]) {
- attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
- numslots++;
- }
- }
-
- /* push attributes */
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
- glDisable(GL_SCISSOR_TEST);
-
- /* bind framebuffer */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
-
- /* last bound prevails here, better allow explicit control here too */
- glDrawBuffers(numslots, attachments);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
-
- /* push matrices and set default viewport and matrix */
- glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig);
- GG.currentfb = fb->object;
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
-}
-
-void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
-{
- /* restore matrix */
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- /* restore attributes */
- glPopAttrib();
-}
-
-void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
-{
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- /* last bound prevails here, better allow explicit control here too */
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
- glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
-
- /* push matrices and set default viewport and matrix */
- glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig);
- GG.currentfb = fb->object;
- GG.currentfb = fb->object;
+ return support;
}
-bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
+bool GPU_glsl_support(void)
{
- GLenum status;
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- GG.currentfb = fb->object;
-
- /* Clean glError buffer. */
- while (glGetError() != GL_NO_ERROR) {}
-
- status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- GPU_framebuffer_restore();
- GPU_print_framebuffer_error(status, err_out);
- return false;
- }
-
+ /* always supported, still queried by game engine */
return true;
}
-void GPU_framebuffer_free(GPUFrameBuffer *fb)
-{
- int i;
- if (fb->depthtex)
- GPU_framebuffer_texture_detach(fb->depthtex);
-
- for (i = 0; i < GPU_FB_MAX_SLOTS; i++) {
- if (fb->colortex[i]) {
- GPU_framebuffer_texture_detach(fb->colortex[i]);
- }
- }
-
- if (fb->object) {
- glDeleteFramebuffersEXT(1, &fb->object);
-
- if (GG.currentfb == fb->object) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- GG.currentfb = 0;
- }
- }
-
- MEM_freeN(fb);
-}
-
-void GPU_framebuffer_restore(void)
-{
- if (GG.currentfb != 0) {
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- GG.currentfb = 0;
- }
-}
-
-void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex)
-{
- const float scaleh[2] = {1.0f / blurtex->w_orig, 0.0f};
- const float scalev[2] = {0.0f, 1.0f / tex->h_orig};
-
- GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
- int scale_uniform, texture_source_uniform;
-
- if (!blur_shader)
- return;
-
- scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
- texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
-
- /* Blurring horizontally */
-
- /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
- * pushing unnecessary matrices onto the OpenGL stack. */
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
- glDrawBuffer(GL_COLOR_ATTACHMENT0);
-
- /* avoid warnings from texture binding */
- GG.currentfb = blurfb->object;
-
- GPU_shader_bind(blur_shader);
- GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh);
- GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
- glViewport(0, 0, blurtex->w_orig, blurtex->h_orig);
-
- /* Peparing to draw quad */
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-
- glDisable(GL_DEPTH_TEST);
-
- GPU_texture_bind(tex, 0);
-
- /* Drawing quad */
- glBegin(GL_QUADS);
- glTexCoord2d(0, 0); glVertex2f(1, 1);
- glTexCoord2d(1, 0); glVertex2f(-1, 1);
- glTexCoord2d(1, 1); glVertex2f(-1, -1);
- glTexCoord2d(0, 1); glVertex2f(1, -1);
- glEnd();
-
- /* Blurring vertically */
-
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
- glDrawBuffer(GL_COLOR_ATTACHMENT0);
-
- GG.currentfb = fb->object;
-
- glViewport(0, 0, tex->w_orig, tex->h_orig);
- GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev);
- GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
- GPU_texture_bind(blurtex, 0);
-
- glBegin(GL_QUADS);
- glTexCoord2d(0, 0); glVertex2f(1, 1);
- glTexCoord2d(1, 0); glVertex2f(-1, 1);
- glTexCoord2d(1, 1); glVertex2f(-1, -1);
- glTexCoord2d(0, 1); glVertex2f(1, -1);
- glEnd();
-
- GPU_shader_unbind();
-}
-
-/* GPUOffScreen */
-
-struct GPUOffScreen {
- GPUFrameBuffer *fb;
- GPUTexture *color;
- GPUTexture *depth;
-};
-
-GPUOffScreen *GPU_offscreen_create(int width, int height, char err_out[256])
-{
- GPUOffScreen *ofs;
-
- ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
-
- ofs->fb = GPU_framebuffer_create();
- if (!ofs->fb) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- ofs->depth = GPU_texture_create_depth(width, height, err_out);
- if (!ofs->depth) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- ofs->color = GPU_texture_create_2D(width, height, NULL, GPU_HDR_NONE, err_out);
- if (!ofs->color) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- /* check validity at the very end! */
- if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
- GPU_offscreen_free(ofs);
- return NULL;
- }
-
- GPU_framebuffer_restore();
-
- return ofs;
-}
-
-void GPU_offscreen_free(GPUOffScreen *ofs)
-{
- if (ofs->fb)
- GPU_framebuffer_free(ofs->fb);
- if (ofs->color)
- GPU_texture_free(ofs->color);
- if (ofs->depth)
- GPU_texture_free(ofs->depth);
-
- MEM_freeN(ofs);
-}
-
-void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
+bool GPU_full_non_power_of_two_support(void)
{
- glDisable(GL_SCISSOR_TEST);
- if (save)
- GPU_texture_bind_as_framebuffer(ofs->color);
- else {
- GPU_framebuffer_bind_no_save(ofs->fb, 0);
- }
-}
-
-void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
-{
- if (restore)
- GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
- GPU_framebuffer_restore();
- glEnable(GL_SCISSOR_TEST);
-}
-
-void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
-{
- glReadPixels(0, 0, ofs->color->w_orig, ofs->color->h_orig, GL_RGBA, type, pixels);
-}
-
-int GPU_offscreen_width(const GPUOffScreen *ofs)
-{
- return ofs->color->w_orig;
-}
-
-int GPU_offscreen_height(const GPUOffScreen *ofs)
-{
- return ofs->color->h_orig;
-}
-
-/* GPUShader */
-
-struct GPUShader {
- GLhandleARB object; /* handle for full shader */
- GLhandleARB vertex; /* handle for vertex shader */
- GLhandleARB fragment; /* handle for fragment shader */
- GLhandleARB geometry; /* handle for geometry shader */
- GLhandleARB lib; /* handle for libment shader */
- int totattrib; /* total number of attributes */
- int uniforms; /* required uniforms */
-};
-
-struct GPUProgram {
- GPUProgramType type;
- GLuint prog;
-};
-
-
-static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
-{
- int i;
- int line = 1;
-
- fprintf(stderr, "GPUShader: %s error:\n", task);
-
- for (i = 0; i < totcode; i++) {
- const char *c, *pos, *end = code[i] + strlen(code[i]);
-
- if ((G.debug & G_DEBUG)) {
- fprintf(stderr, "===== shader string %d ====\n", i + 1);
-
- c = code[i];
- while ((c < end) && (pos = strchr(c, '\n'))) {
- fprintf(stderr, "%2d ", line);
- fwrite(c, (pos + 1) - c, 1, stderr);
- c = pos + 1;
- line++;
- }
-
- fprintf(stderr, "%s", c);
- }
- }
-
- fprintf(stderr, "%s\n", log);
-}
-
-static const char *gpu_shader_version(bool use_opensubdiv)
-{
-#ifdef WITH_OPENSUBDIV
- if (use_opensubdiv) {
- return "#version 130\n";
- }
-#else
- UNUSED_VARS(use_opensubdiv);
-#endif
-
- /* turn on glsl 1.30 for bicubic bump mapping and ATI clipping support */
- if (GLEW_VERSION_3_0 &&
- (GPU_bicubic_bump_support() || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)))
- {
- return "#version 130\n";
- }
-
- return "";
-}
-
-
-static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_opensubdiv)
-{
-#ifdef WITH_OPENSUBDIV
- if (use_opensubdiv) {
- strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"
- "#extension GL_ARB_gpu_shader5 : enable\n"
- "#extension GL_ARB_explicit_attrib_location : require\n");
- }
- else if (GPU_bicubic_bump_support())
- strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
-#else
- /* need this extension for high quality bump mapping */
- if (GPU_bicubic_bump_support())
- strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
- (void) use_opensubdiv;
-#endif
-
- if (GPU_geometry_shader_support())
- strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
-
- if (GPU_instanced_drawing_support()) {
- strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n");
- strcat(defines, "#extension GL_ARB_draw_instanced: enable\n");
- }
+ /* always supported on full GL but still relevant for OpenGL ES 2.0 where
+ * NPOT textures can't use mipmaps or repeat wrap mode */
+ return true;
}
-static void gpu_shader_standard_defines(bool use_opensubdiv,
- char defines[MAX_DEFINE_LENGTH])
+bool GPU_display_list_support(void)
{
- /* some useful defines to detect GPU type */
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- strcat(defines, "#define GPU_ATI\n");
- if (GLEW_VERSION_3_0)
- strcat(defines, "#define CLIP_WORKAROUND\n");
- }
- else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY))
- strcat(defines, "#define GPU_NVIDIA\n");
- else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY))
- strcat(defines, "#define GPU_INTEL\n");
-
- if (GPU_bicubic_bump_support())
- strcat(defines, "#define BUMP_BICUBIC\n");
-
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Check whether we actually compiling shader for
- * the OpenSubdiv mesh.
+ /* deprecated in GL 3
+ * supported on older GL and compatibility profile
+ * still queried by game engine
*/
- if (use_opensubdiv) {
- strcat(defines, "#define USE_OPENSUBDIV\n");
-
- /* TODO(sergey): not strictly speaking a define, but this is
- * a global typedef which we don't have better place to define
- * in yet.
- */
- strcat(defines, "struct VertexData {\n"
- " vec4 position;\n"
- " vec3 normal;\n"
- " vec2 uv;"
- "};\n");
- }
-#else
- UNUSED_VARS(use_opensubdiv);
-#endif
-
- return;
-}
-
-void GPU_program_bind(GPUProgram *program)
-{
- glEnable(program->type);
- glBindProgramARB(program->type, program->prog);
-}
-
-void GPU_program_unbind(GPUProgram *program)
-{
- glDisable(program->type);
- glBindProgramARB(program->type, 0);
-}
-
-
-GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code)
-{
- GPUProgram *program;
- GLint error_pos, is_native;
-
- if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT))
- return NULL;
-
- program = MEM_callocN(sizeof(GPUProgram), "GPUProgram");
-
- switch (type) {
- case GPU_PROGRAM_TYPE_FRAGMENT:
- program->type = GL_FRAGMENT_PROGRAM_ARB;
- break;
- }
-
- /* create the object and set its code string */
- glGenProgramsARB(1, &program->prog);
- glBindProgramARB(program->type, program->prog);
-
- glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code);
-
- glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
- glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native);
- if ((error_pos == -1) && (is_native == 1)) {
- return program;
- }
- else {
- /* glGetError is set before that, clear it */
- while (glGetError() != GL_NO_ERROR)
- ;
- shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1);
- MEM_freeN(program);
- }
-
- return NULL;
-}
-
-void GPU_program_free(GPUProgram *program)
-{
- glDeleteProgramsARB(1, &program->prog);
- MEM_freeN(program);
-}
-
-void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w)
-{
- glProgramLocalParameter4fARB(program->type, location, x, y, z, w);
+ return true;
}
-GPUShader *GPU_shader_create(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- int input,
- int output,
- int number)
+bool GPU_bicubic_bump_support(void)
{
- return GPU_shader_create_ex(vertexcode,
- fragcode,
- geocode,
- libcode,
- defines,
- input,
- output,
- number,
- GPU_SHADER_FLAGS_NONE);
+ return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0);
}
-GPUShader *GPU_shader_create_ex(const char *vertexcode,
- const char *fragcode,
- const char *geocode,
- const char *libcode,
- const char *defines,
- int input,
- int output,
- int number,
- const int flags)
+bool GPU_geometry_shader_support(void)
{
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): used to add #version 150 to the geometry shader.
- * Could safely be renamed to "use_geometry_code" since it's very
- * likely any of geometry code will want to use GLSL 1.5.
+ /* in GL 3.2 geometry shaders are fully supported
+ * core profile clashes with our other shaders so accept compatibility only
+ * other GL versions can use EXT_geometry_shader4 if available
*/
- bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
-#else
- bool use_opensubdiv = false;
-#endif
- GLint status;
- GLcharARB log[5000];
- GLsizei length = 0;
- GPUShader *shader;
- char standard_defines[MAX_DEFINE_LENGTH] = "";
- char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
-
-#ifndef WITH_OPENSUBDIV
- UNUSED_VARS(flags);
-#endif
-
- if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader || (geocode && !GPU_geometry_shader_support()))
- return NULL;
-
- shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
-
- if (vertexcode)
- shader->vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
- if (fragcode)
- shader->fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
- if (geocode)
- shader->geometry = glCreateShaderObjectARB(GL_GEOMETRY_SHADER_EXT);
-
- shader->object = glCreateProgramObjectARB();
-
- if (!shader->object ||
- (vertexcode && !shader->vertex) ||
- (fragcode && !shader->fragment) ||
- (geocode && !shader->geometry))
- {
- fprintf(stderr, "GPUShader, object creation failed.\n");
- GPU_shader_free(shader);
- return NULL;
- }
-
- gpu_shader_standard_defines(use_opensubdiv, standard_defines);
- gpu_shader_standard_extensions(standard_extensions, use_opensubdiv);
-
- if (vertexcode) {
- const char *source[5];
- /* custom limit, may be too small, beware */
- int num_source = 0;
-
- source[num_source++] = gpu_shader_version(use_opensubdiv);
- source[num_source++] = standard_extensions;
- source[num_source++] = standard_defines;
-
- if (defines) source[num_source++] = defines;
- source[num_source++] = vertexcode;
-
- glAttachObjectARB(shader->object, shader->vertex);
- glShaderSourceARB(shader->vertex, num_source, source, NULL);
-
- glCompileShaderARB(shader->vertex);
- glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
-
- if (!status) {
- glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
- shader_print_errors("compile", log, source, num_source);
-
- GPU_shader_free(shader);
- return NULL;
- }
- }
-
- if (fragcode) {
- const char *source[7];
- int num_source = 0;
-
- source[num_source++] = gpu_shader_version(use_opensubdiv);
- source[num_source++] = standard_extensions;
- source[num_source++] = standard_defines;
-
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Move to fragment shader source code generation. */
- if (use_opensubdiv) {
- source[num_source++] =
- "#ifdef USE_OPENSUBDIV\n"
- "in block {\n"
- " VertexData v;\n"
- "} inpt;\n"
- "#endif\n";
- }
-#endif
-
- if (defines) source[num_source++] = defines;
- if (libcode) source[num_source++] = libcode;
- source[num_source++] = fragcode;
-
- glAttachObjectARB(shader->object, shader->fragment);
- glShaderSourceARB(shader->fragment, num_source, source, NULL);
-
- glCompileShaderARB(shader->fragment);
- glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
-
- if (!status) {
- glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
- shader_print_errors("compile", log, source, num_source);
-
- GPU_shader_free(shader);
- return NULL;
- }
- }
-
- if (geocode) {
- const char *source[6];
- int num_source = 0;
-
- source[num_source++] = gpu_shader_version(use_opensubdiv);
- source[num_source++] = standard_extensions;
- source[num_source++] = standard_defines;
-
- if (defines) source[num_source++] = defines;
- source[num_source++] = geocode;
-
- glAttachObjectARB(shader->object, shader->geometry);
- glShaderSourceARB(shader->geometry, num_source, source, NULL);
-
- glCompileShaderARB(shader->geometry);
- glGetObjectParameterivARB(shader->geometry, GL_OBJECT_COMPILE_STATUS_ARB, &status);
-
- if (!status) {
- glGetInfoLogARB(shader->geometry, sizeof(log), &length, log);
- shader_print_errors("compile", log, source, num_source);
-
- GPU_shader_free(shader);
- return NULL;
- }
-
- if (!use_opensubdiv) {
- GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
- }
- }
-
-
-#if 0
- if (lib && lib->lib)
- glAttachObjectARB(shader->object, lib->lib);
-#endif
-
-#ifdef WITH_OPENSUBDIV
- if (use_opensubdiv) {
- glBindAttribLocation(shader->object, 0, "position");
- glBindAttribLocation(shader->object, 1, "normal");
- GPU_shader_geometry_stage_primitive_io(shader,
- GL_LINES_ADJACENCY_EXT,
- GL_TRIANGLE_STRIP,
- 4);
-
- }
-#endif
-
- glLinkProgramARB(shader->object);
- glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
- if (!status) {
- glGetInfoLogARB(shader->object, sizeof(log), &length, log);
- if (fragcode) shader_print_errors("linking", log, &fragcode, 1);
- else if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1);
- else if (libcode) shader_print_errors("linking", log, &libcode, 1);
- else if (geocode) shader_print_errors("linking", log, &geocode, 1);
-
- GPU_shader_free(shader);
- return NULL;
- }
-
-#ifdef WITH_OPENSUBDIV
- /* TODO(sergey): Find a better place for this. */
- if (use_opensubdiv && GLEW_VERSION_4_1) {
- glProgramUniform1i(shader->object,
- glGetUniformLocation(shader->object, "FVarDataBuffer"),
- 31); /* GL_TEXTURE31 */
- }
-#endif
-
- return shader;
-}
-
-#if 0
-GPUShader *GPU_shader_create_lib(const char *code)
-{
- GLint status;
- GLcharARB log[5000];
- GLsizei length = 0;
- GPUShader *shader;
-
- if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
- return NULL;
-
- shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
-
- shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
-
- if (!shader->lib) {
- fprintf(stderr, "GPUShader, object creation failed.\n");
- GPU_shader_free(shader);
- return NULL;
- }
-
- glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
-
- glCompileShaderARB(shader->lib);
- glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
-
- if (!status) {
- glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
- shader_print_errors("compile", log, code);
-
- GPU_shader_free(shader);
- return NULL;
- }
-
- return shader;
-}
-#endif
-
-void GPU_shader_bind(GPUShader *shader)
-{
- GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind");
- glUseProgramObjectARB(shader->object);
- GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind");
-}
-
-void GPU_shader_unbind(void)
-{
- GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind");
- glUseProgramObjectARB(0);
- GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind");
-}
-
-void GPU_shader_free(GPUShader *shader)
-{
- if (shader->lib)
- glDeleteObjectARB(shader->lib);
- if (shader->vertex)
- glDeleteObjectARB(shader->vertex);
- if (shader->fragment)
- glDeleteObjectARB(shader->fragment);
- if (shader->object)
- glDeleteObjectARB(shader->object);
- MEM_freeN(shader);
-}
-
-int GPU_shader_get_uniform(GPUShader *shader, const char *name)
-{
- return glGetUniformLocationARB(shader->object, name);
+ return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4;
}
-void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
+bool GPU_geometry_shader_support_via_extension(void)
{
- if (location == -1 || value == NULL)
- return;
-
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
-
- if (length == 1) glUniform1fvARB(location, arraysize, value);
- else if (length == 2) glUniform2fvARB(location, arraysize, value);
- else if (length == 3) glUniform3fvARB(location, arraysize, value);
- else if (length == 4) glUniform4fvARB(location, arraysize, value);
- else if (length == 9) glUniformMatrix3fvARB(location, arraysize, 0, value);
- else if (length == 16) glUniformMatrix4fvARB(location, arraysize, 0, value);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
-}
-
-void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
-{
- if (location == -1)
- return;
-
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
-
- if (length == 1) glUniform1ivARB(location, arraysize, value);
- else if (length == 2) glUniform2ivARB(location, arraysize, value);
- else if (length == 3) glUniform3ivARB(location, arraysize, value);
- else if (length == 4) glUniform4ivARB(location, arraysize, value);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
-}
-
-void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
-{
- if (location == -1)
- return;
-
- GPU_CHECK_ERRORS_AROUND(glUniform1iARB(location, value));
+ return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support());
}
-void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number)
-{
- glProgramParameteriEXT(shader->object, GL_GEOMETRY_INPUT_TYPE_EXT, input);
- glProgramParameteriEXT(shader->object, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
- glProgramParameteriEXT(shader->object, GL_GEOMETRY_VERTICES_OUT_EXT, number);
-}
-
-void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
-{
- GLenum arbnumber;
-
- if (tex->number >= GG.maxtextures) {
- fprintf(stderr, "Not enough texture slots.");
- return;
- }
-
- if (tex->number == -1)
- return;
-
- if (location == -1)
- return;
-
- GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture");
-
- arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
-
- if (tex->number != 0) glActiveTextureARB(arbnumber);
- if (tex->bindcode != 0)
- glBindTexture(tex->target, tex->bindcode);
- else
- GPU_invalid_tex_bind(tex->target);
- glUniform1iARB(location, tex->number);
- glEnable(tex->target);
- if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
-
- GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture");
-}
-
-int GPU_shader_get_attribute(GPUShader *shader, const char *name)
-{
- int index;
-
- GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocationARB(shader->object, name));
-
- return index;
-}
-
-GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
-{
- GPUShader *retval = NULL;
-
- switch (shader) {
- case GPU_SHADER_VSM_STORE:
- if (!GG.shaders.vsm_store)
- GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
- retval = GG.shaders.vsm_store;
- break;
- case GPU_SHADER_SEP_GAUSSIAN_BLUR:
- if (!GG.shaders.sep_gaussian_blur)
- GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0);
- retval = GG.shaders.sep_gaussian_blur;
- break;
- }
-
- if (retval == NULL)
- printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
-
- return retval;
-}
-
-GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program)
+bool GPU_instanced_drawing_support(void)
{
- GPUProgram *retval = NULL;
-
- switch (program) {
- case GPU_PROGRAM_SMOKE:
- if (!GG.shaders.smoke)
- GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl);
- retval = GG.shaders.smoke;
- break;
- case GPU_PROGRAM_SMOKE_COLORED:
- if (!GG.shaders.smoke_colored)
- GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl);
- retval = GG.shaders.smoke_colored;
- break;
- }
-
- if (retval == NULL)
- printf("Unable to create a GPUProgram for builtin program: %u\n", program);
-
- return retval;
+ return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced;
}
-#define MAX_DEFINES 100
-
-GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp)
-{
- int offset;
- char defines[MAX_DEFINES] = "";
- /* avoid shaders out of range */
- if (effects >= MAX_FX_SHADERS)
- return NULL;
-
- offset = 2 * effects;
-
- if (persp) {
- offset += 1;
- strcat(defines, "#define PERSP_MATRIX\n");
- }
-
- if (!GG.shaders.fx_shaders[offset]) {
- GPUShader *shader;
-
- switch (effects) {
- case GPU_SHADER_FX_SSAO:
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
- strcat(defines, "#define FIRST_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
- strcat(defines, "#define SECOND_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
- strcat(defines, "#define THIRD_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
- strcat(defines, "#define FOURTH_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
- strcat(defines, "#define FIFTH_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
- strcat(defines, "#define FIRST_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
- strcat(defines, "#define SECOND_PASS\n");
- shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl,
- defines, GL_POINTS, GL_TRIANGLE_STRIP, 4);
- GG.shaders.fx_shaders[offset] = shader;
- break;
-
- case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
- strcat(defines, "#define THIRD_PASS\n");
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
- break;
-
- case GPU_SHADER_FX_DEPTH_RESOLVE:
- GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0);
- }
- }
-
- return GG.shaders.fx_shaders[offset];
-}
-
-
-void GPU_shader_free_builtin_shaders(void)
+int GPU_color_depth(void)
{
- int i;
-
- if (GG.shaders.vsm_store) {
- GPU_shader_free(GG.shaders.vsm_store);
- GG.shaders.vsm_store = NULL;
- }
-
- if (GG.shaders.sep_gaussian_blur) {
- GPU_shader_free(GG.shaders.sep_gaussian_blur);
- GG.shaders.sep_gaussian_blur = NULL;
- }
-
- if (GG.shaders.smoke) {
- GPU_program_free(GG.shaders.smoke);
- GG.shaders.smoke = NULL;
- }
-
- if (GG.shaders.smoke_colored) {
- GPU_program_free(GG.shaders.smoke_colored);
- GG.shaders.smoke_colored = NULL;
- }
-
- for (i = 0; i < 2 * MAX_FX_SHADERS; i++) {
- if (GG.shaders.fx_shaders[i]) {
- GPU_shader_free(GG.shaders.fx_shaders[i]);
- GG.shaders.fx_shaders[i] = NULL;
- }
- }
+ return GG.colordepth;
}
bool GPU_mem_stats_supported(void)
@@ -2235,120 +361,3 @@ void GPU_mem_stats_get(int *totalmem, int *freemem)
}
}
-
-#if 0 /* unused */
-
-/* GPUPixelBuffer */
-
-typedef struct GPUPixelBuffer {
- GLuint bindcode[2];
- GLuint current;
- int datasize;
- int numbuffers;
- int halffloat;
-} GPUPixelBuffer;
-
-void GPU_pixelbuffer_free(GPUPixelBuffer *pb)
-{
- if (pb->bindcode[0])
- glDeleteBuffersARB(pb->numbuffers, pb->bindcode);
- MEM_freeN(pb);
-}
-
-GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers)
-{
- GPUPixelBuffer *pb;
-
- if (!GLEW_ARB_multitexture || !GLEW_EXT_pixel_buffer_object)
- return NULL;
-
- pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO");
- pb->datasize = x * y * 4 * (halffloat ? 16 : 8);
- pb->numbuffers = numbuffers;
- pb->halffloat = halffloat;
-
- glGenBuffersARB(pb->numbuffers, pb->bindcode);
-
- if (!pb->bindcode[0]) {
- fprintf(stderr, "GPUPixelBuffer allocation failed\n");
- GPU_pixelbuffer_free(pb);
- return NULL;
- }
-
- return pb;
-}
-
-void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb)
-{
- void *pixels;
- int i;
-
- glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
-
- for (i = 0; i < pb->numbuffers; i++) {
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->bindcode[pb->current]);
- glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_EXT, pb->datasize, NULL,
- GL_STREAM_DRAW_ARB);
-
- pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
-
-# if 0
- memcpy(pixels, _oImage.data(), pb->datasize);
-# endif
-
- if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
- fprintf(stderr, "Could not unmap OpenGL PBO\n");
- break;
- }
- }
-
- glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
-}
-
-static int pixelbuffer_map_into_gpu(GLuint bindcode)
-{
- void *pixels;
-
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
- pixels = glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
-
- /* do stuff in pixels */
-
- if (!glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT)) {
- fprintf(stderr, "Could not unmap OpenGL PBO\n");
- return 0;
- }
-
- return 1;
-}
-
-static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode)
-{
- GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE;
- glBindTexture(GL_TEXTURE_RECTANGLE_EXT, tex->bindcode);
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, bindcode);
-
- glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, tex->w, tex->h, GL_RGBA, type, NULL);
-
- glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
- glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
-}
-
-void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb)
-{
- int newbuffer;
-
- if (pb->numbuffers == 1) {
- pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]);
- pixelbuffer_map_into_gpu(pb->bindcode[0]);
- }
- else {
- pb->current = (pb->current + 1) % pb->numbuffers;
- newbuffer = (pb->current + 1) % pb->numbuffers;
-
- pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]);
- pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]);
- }
-}
-#endif /* unused */
-
diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c
new file mode 100644
index 00000000000..c15e49a8ed1
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_framebuffer.c
@@ -0,0 +1,639 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_global.h"
+
+#include "GPU_debug.h"
+#include "GPU_glew.h"
+#include "GPU_framebuffer.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+static struct GPUFrameBufferGlobal {
+ GLuint currentfb;
+} GG = {0};
+
+/* Number of maximum output slots.
+ * We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
+#define GPU_FB_MAX_SLOTS 4
+
+struct GPUFrameBuffer {
+ GLuint object;
+ GPUTexture *colortex[GPU_FB_MAX_SLOTS];
+ GPUTexture *depthtex;
+};
+
+static void GPU_print_framebuffer_error(GLenum status, char err_out[256])
+{
+ const char *err = "unknown";
+
+ switch (status) {
+ case GL_FRAMEBUFFER_COMPLETE_EXT:
+ break;
+ case GL_INVALID_OPERATION:
+ err = "Invalid operation";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+ err = "Incomplete attachment";
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ err = "Unsupported framebuffer format";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
+ err = "Missing attachment";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+ err = "Attached images must have same dimensions";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
+ err = "Attached images must have same format";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
+ err = "Missing draw buffer";
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
+ err = "Missing read buffer";
+ break;
+ }
+
+ if (err_out) {
+ BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
+ (int)status, err);
+ }
+ else {
+ fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
+ (int)status, err);
+ }
+}
+
+/* GPUFrameBuffer */
+
+GPUFrameBuffer *GPU_framebuffer_create(void)
+{
+ GPUFrameBuffer *fb;
+
+ if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object ||
+ (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit)))
+ {
+ return NULL;
+ }
+
+ fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
+ glGenFramebuffersEXT(1, &fb->object);
+
+ if (!fb->object) {
+ fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
+ (int)glGetError());
+ GPU_framebuffer_free(fb);
+ return NULL;
+ }
+
+ /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glReadBuffer(GL_NONE);
+ glDrawBuffer(GL_NONE);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ return fb;
+}
+
+int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256])
+{
+ GLenum attachment;
+ GLenum error;
+
+ if (slot >= GPU_FB_MAX_SLOTS) {
+ fprintf(stderr,
+ "Attaching to index %d framebuffer slot unsupported. "
+ "Use at most %d\n", slot, GPU_FB_MAX_SLOTS);
+ return 0;
+ }
+
+ if ((G.debug & G_DEBUG)) {
+ if (GPU_texture_bound_number(tex) != -1) {
+ fprintf(stderr,
+ "Feedback loop warning!: "
+ "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n");
+ }
+ }
+
+ if (GPU_texture_depth(tex))
+ attachment = GL_DEPTH_ATTACHMENT_EXT;
+ else
+ attachment = GL_COLOR_ATTACHMENT0_EXT + slot;
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ GG.currentfb = fb->object;
+
+ /* Clean glError buffer. */
+ while (glGetError() != GL_NO_ERROR) {}
+
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
+ GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0);
+
+ error = glGetError();
+
+ if (error == GL_INVALID_OPERATION) {
+ GPU_framebuffer_restore();
+ GPU_print_framebuffer_error(error, err_out);
+ return 0;
+ }
+
+ if (GPU_texture_depth(tex))
+ fb->depthtex = tex;
+ else
+ fb->colortex[slot] = tex;
+
+ GPU_texture_framebuffer_set(tex, fb, slot);
+
+ return 1;
+}
+
+void GPU_framebuffer_texture_detach(GPUTexture *tex)
+{
+ GLenum attachment;
+ GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
+ int fb_attachment = GPU_texture_framebuffer_attachment(tex);
+
+ if (!fb)
+ return;
+
+ if (GG.currentfb != fb->object) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ GG.currentfb = fb->object;
+ }
+
+ if (GPU_texture_depth(tex)) {
+ fb->depthtex = NULL;
+ attachment = GL_DEPTH_ATTACHMENT_EXT;
+ }
+ else {
+ BLI_assert(fb->colortex[fb_attachment] == tex);
+ fb->colortex[fb_attachment] = NULL;
+ attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment;
+ }
+
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0);
+
+ GPU_texture_framebuffer_set(tex, NULL, -1);
+}
+
+void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
+{
+ GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
+ int fb_attachment = GPU_texture_framebuffer_attachment(tex);
+
+ if (!fb) {
+ fprintf(stderr, "Error, texture not bound to framebuffer!\n");
+ return;
+ }
+
+ /* push attributes */
+ glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
+ /* bind framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+
+ if (GPU_texture_depth(tex)) {
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+ }
+ else {
+ /* last bound prevails here, better allow explicit control here too */
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
+ }
+
+ if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
+ glEnable(GL_MULTISAMPLE);
+ }
+
+ /* push matrices and set default viewport and matrix */
+ glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
+ GG.currentfb = fb->object;
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+}
+
+void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
+{
+ int numslots = 0, i;
+ GLenum attachments[4];
+
+ if (!fb->colortex[slot]) {
+ fprintf(stderr, "Error, framebuffer slot empty!\n");
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (fb->colortex[i]) {
+ attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
+ numslots++;
+ }
+ }
+
+ /* push attributes */
+ glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
+ /* bind framebuffer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+
+ /* last bound prevails here, better allow explicit control here too */
+ glDrawBuffers(numslots, attachments);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+
+ /* push matrices and set default viewport and matrix */
+ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
+ GG.currentfb = fb->object;
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+}
+
+
+void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
+{
+ /* restore matrix */
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ /* restore attributes */
+ glPopAttrib();
+}
+
+void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
+{
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ /* last bound prevails here, better allow explicit control here too */
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+
+ /* push matrices and set default viewport and matrix */
+ glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
+ GG.currentfb = fb->object;
+ GG.currentfb = fb->object;
+}
+
+bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
+{
+ return fb->object == GG.currentfb;
+}
+
+bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
+{
+ GLenum status;
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ GG.currentfb = fb->object;
+
+ /* Clean glError buffer. */
+ while (glGetError() != GL_NO_ERROR) {}
+
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ GPU_framebuffer_restore();
+ GPU_print_framebuffer_error(status, err_out);
+ return false;
+ }
+
+ return true;
+}
+
+void GPU_framebuffer_free(GPUFrameBuffer *fb)
+{
+ int i;
+ if (fb->depthtex)
+ GPU_framebuffer_texture_detach(fb->depthtex);
+
+ for (i = 0; i < GPU_FB_MAX_SLOTS; i++) {
+ if (fb->colortex[i]) {
+ GPU_framebuffer_texture_detach(fb->colortex[i]);
+ }
+ }
+
+ if (fb->object) {
+ glDeleteFramebuffersEXT(1, &fb->object);
+
+ if (GG.currentfb == fb->object) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ GG.currentfb = 0;
+ }
+ }
+
+ MEM_freeN(fb);
+}
+
+void GPU_framebuffer_restore(void)
+{
+ if (GG.currentfb != 0) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ GG.currentfb = 0;
+ }
+}
+
+void GPU_framebuffer_blur(
+ GPUFrameBuffer *fb, GPUTexture *tex,
+ GPUFrameBuffer *blurfb, GPUTexture *blurtex)
+{
+ const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
+ const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
+
+ GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
+ int scale_uniform, texture_source_uniform;
+
+ if (!blur_shader)
+ return;
+
+ scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
+ texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
+
+ /* Blurring horizontally */
+
+ /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
+ * pushing unnecessary matrices onto the OpenGL stack. */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ /* avoid warnings from texture binding */
+ GG.currentfb = blurfb->object;
+
+ GPU_shader_bind(blur_shader);
+ GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh);
+ GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
+ glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
+
+ /* Peparing to draw quad */
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glDisable(GL_DEPTH_TEST);
+
+ GPU_texture_bind(tex, 0);
+
+ /* Drawing quad */
+ glBegin(GL_QUADS);
+ glTexCoord2d(0, 0); glVertex2f(1, 1);
+ glTexCoord2d(1, 0); glVertex2f(-1, 1);
+ glTexCoord2d(1, 1); glVertex2f(-1, -1);
+ glTexCoord2d(0, 1); glVertex2f(1, -1);
+ glEnd();
+
+ /* Blurring vertically */
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ GG.currentfb = fb->object;
+
+ glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
+ GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev);
+ GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
+ GPU_texture_bind(blurtex, 0);
+
+ glBegin(GL_QUADS);
+ glTexCoord2d(0, 0); glVertex2f(1, 1);
+ glTexCoord2d(1, 0); glVertex2f(-1, 1);
+ glTexCoord2d(1, 1); glVertex2f(-1, -1);
+ glTexCoord2d(0, 1); glVertex2f(1, -1);
+ glEnd();
+
+ GPU_shader_unbind();
+}
+
+/* GPUOffScreen */
+
+struct GPUOffScreen {
+ GPUFrameBuffer *fb;
+ GPUTexture *color;
+ GPUTexture *depth;
+};
+
+GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256])
+{
+ GPUOffScreen *ofs;
+
+ ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
+
+ ofs->fb = GPU_framebuffer_create();
+ if (!ofs->fb) {
+ GPU_offscreen_free(ofs);
+ return NULL;
+ }
+
+ if (samples) {
+ if (!GLEW_EXT_framebuffer_multisample ||
+ !GLEW_ARB_texture_multisample ||
+ /* Only needed for GPU_offscreen_read_pixels.
+ * We could add an arg if we intend to use multi-sample
+ * offscreen buffers w/o reading their pixels */
+ !GLEW_EXT_framebuffer_blit ||
+ /* This is required when blitting from a multi-sampled buffers,
+ * even though we're not scaling. */
+ !GLEW_EXT_framebuffer_multisample_blit_scaled)
+ {
+ samples = 0;
+ }
+ }
+
+ ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out);
+ if (!ofs->depth) {
+ GPU_offscreen_free(ofs);
+ return NULL;
+ }
+
+ if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) {
+ GPU_offscreen_free(ofs);
+ return NULL;
+ }
+
+ ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out);
+ if (!ofs->color) {
+ GPU_offscreen_free(ofs);
+ return NULL;
+ }
+
+ if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) {
+ GPU_offscreen_free(ofs);
+ return NULL;
+ }
+
+ /* check validity at the very end! */
+ if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
+ GPU_offscreen_free(ofs);
+ return NULL;
+ }
+
+ GPU_framebuffer_restore();
+
+ return ofs;
+}
+
+void GPU_offscreen_free(GPUOffScreen *ofs)
+{
+ if (ofs->fb)
+ GPU_framebuffer_free(ofs->fb);
+ if (ofs->color)
+ GPU_texture_free(ofs->color);
+ if (ofs->depth)
+ GPU_texture_free(ofs->depth);
+
+ MEM_freeN(ofs);
+}
+
+void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
+{
+ glDisable(GL_SCISSOR_TEST);
+ if (save)
+ GPU_texture_bind_as_framebuffer(ofs->color);
+ else {
+ GPU_framebuffer_bind_no_save(ofs->fb, 0);
+ }
+}
+
+void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
+{
+ if (restore)
+ GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
+ GPU_framebuffer_restore();
+ glEnable(GL_SCISSOR_TEST);
+}
+
+void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
+{
+ const int w = GPU_texture_width(ofs->color);
+ const int h = GPU_texture_height(ofs->color);
+
+ if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) {
+ /* For a multi-sample texture,
+ * we need to create an intermediate buffer to blit to,
+ * before its copied using 'glReadPixels' */
+
+ /* not needed since 'ofs' needs to be bound to the framebuffer already */
+// #define USE_FBO_CTX_SWITCH
+
+ GLuint fbo_blit = 0;
+ GLuint tex_blit = 0;
+ GLenum status;
+
+ /* create texture for new 'fbo_blit' */
+ glGenTextures(1, &tex_blit);
+ if (!tex_blit) {
+ goto finally;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, tex_blit);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0);
+
+#ifdef USE_FBO_CTX_SWITCH
+ /* read from multi-sample buffer */
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object);
+ glFramebufferTexture2DEXT(
+ GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
+ GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
+ status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ goto finally;
+ }
+#endif
+
+ /* write into new single-sample buffer */
+ glGenFramebuffersEXT(1, &fbo_blit);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
+ glFramebufferTexture2DEXT(
+ GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, tex_blit, 0);
+ status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ goto finally;
+ }
+
+ /* perform the copy */
+ glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ /* read the results */
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit);
+ glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
+
+#ifdef USE_FBO_CTX_SWITCH
+ /* restore the original frame-bufer */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object);
+#undef USE_FBO_CTX_SWITCH
+#endif
+
+
+finally:
+ /* cleanup */
+ if (tex_blit) {
+ glDeleteTextures(1, &tex_blit);
+ }
+ if (fbo_blit) {
+ glDeleteFramebuffersEXT(1, &fbo_blit);
+ }
+
+ GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels");
+ }
+ else {
+ glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
+ }
+}
+
+int GPU_offscreen_width(const GPUOffScreen *ofs)
+{
+ return GPU_texture_width(ofs->color);
+}
+
+int GPU_offscreen_height(const GPUOffScreen *ofs)
+{
+ return GPU_texture_height(ofs->color);
+}
+
+int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
+{
+ return GPU_texture_opengl_bindcode(ofs->color);
+}
+
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index 3a8a6fca23b..da4dd65d2e1 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -49,7 +49,7 @@ static bool initialized = false;
void GPU_init(void)
{
- /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */
+ /* can't avoid calling this multiple times, see wm_window_ghostwindow_add */
if (initialized)
return;
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 5b647232934..587e6340450 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -61,7 +61,10 @@
#include "IMB_imbuf_types.h"
#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
#include "GPU_material.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
#include "gpu_codegen.h"
@@ -109,6 +112,7 @@ struct GPUMaterial {
/* for passing uniforms */
int viewmatloc, invviewmatloc;
int obmatloc, invobmatloc;
+ int localtoviewmatloc, invlocaltoviewmatloc;
int obcolloc, obautobumpscaleloc;
int cameratexcofacloc;
@@ -141,8 +145,10 @@ struct GPULamp {
float dynimat[4][4];
float spotsi, spotbl, k;
+ float spotvec[2];
float dyndist, dynatt1, dynatt2;
float dist, att1, att2;
+ float coeff_const, coeff_lin, coeff_quad;
float shadow_color[3];
float bias, d, clipend;
@@ -166,7 +172,9 @@ struct GPULamp {
};
/* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */
-static void texture_rgb_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, int blendtype, GPUNodeLink **in);
+static void texture_rgb_blend(
+ GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
+ int blendtype, GPUNodeLink **in);
/* Functions */
@@ -181,20 +189,14 @@ static GPUMaterial *GPU_material_construct_begin(Material *ma)
static void gpu_material_set_attrib_id(GPUMaterial *material)
{
- GPUVertexAttribs *attribs;
- GPUShader *shader;
- GPUPass *pass;
- char name[32];
- int a, b;
-
- attribs = &material->attribs;
- pass = material->pass;
+ GPUVertexAttribs *attribs = &material->attribs;
+ GPUPass *pass = material->pass;
if (!pass) {
attribs->totlayer = 0;
return;
}
- shader = GPU_pass_shader(pass);
+ GPUShader *shader = GPU_pass_shader(pass);
if (!shader) {
attribs->totlayer = 0;
return;
@@ -204,7 +206,9 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
* in case the attrib does not get a valid index back, it was probably
* removed by the glsl compiler by dead code elimination */
- for (a = 0, b = 0; a < attribs->totlayer; a++) {
+ int b = 0;
+ for (int a = 0; a < attribs->totlayer; a++) {
+ char name[32];
BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
@@ -220,20 +224,19 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
static int GPU_material_construct_end(GPUMaterial *material, const char *passname)
{
if (material->outlink) {
- GPUNodeLink *outlink;
- GPUShader *shader;
-
- outlink = material->outlink;
+ GPUNodeLink *outlink = material->outlink;
material->pass = GPU_generate_pass(&material->nodes, outlink,
&material->attribs, &material->builtins, material->type,
- passname, material->is_opensubdiv);
+ passname,
+ material->is_opensubdiv,
+ GPU_material_use_new_shading_nodes(material));
if (!material->pass)
return 0;
gpu_material_set_attrib_id(material);
- shader = GPU_pass_shader(material->pass);
+ GPUShader *shader = GPU_pass_shader(material->pass);
if (material->builtins & GPU_VIEW_MATRIX)
material->viewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_VIEW_MATRIX));
@@ -243,6 +246,10 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
material->obmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_MATRIX));
if (material->builtins & GPU_INVERSE_OBJECT_MATRIX)
material->invobmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_OBJECT_MATRIX));
+ if (material->builtins & GPU_LOC_TO_VIEW_MATRIX)
+ material->localtoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_LOC_TO_VIEW_MATRIX));
+ if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX)
+ material->invlocaltoviewmatloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_INVERSE_LOC_TO_VIEW_MATRIX));
if (material->builtins & GPU_OBCOLOR)
material->obcolloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBCOLOR));
if (material->builtins & GPU_AUTO_BUMPSCALE)
@@ -265,22 +272,20 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
void GPU_material_free(ListBase *gpumaterial)
{
- LinkData *link;
- LinkData *nlink, *mlink, *next;
-
- for (link = gpumaterial->first; link; link = link->next) {
+ for (LinkData *link = gpumaterial->first; link; link = link->next) {
GPUMaterial *material = link->data;
if (material->pass)
GPU_pass_free(material->pass);
- for (nlink = material->lamps.first; nlink; nlink = nlink->next) {
+ for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
GPULamp *lamp = nlink->data;
if (material->ma) {
Material *ma = material->ma;
- for (mlink = lamp->materials.first; mlink; mlink = next) {
+ LinkData *next = NULL;
+ for (LinkData *mlink = lamp->materials.first; mlink; mlink = next) {
next = mlink->next;
if (mlink->data == ma)
BLI_freelinkN(&lamp->materials, mlink);
@@ -306,11 +311,11 @@ bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *m
return true;
}
-void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock)
+void GPU_material_bind(
+ GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
+ float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock)
{
if (material->pass) {
- LinkData *nlink;
- GPULamp *lamp;
GPUShader *shader = GPU_pass_shader(material->pass);
SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL;
@@ -319,11 +324,12 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
/* handle layer lamps */
if (material->type == GPU_MATERIAL_TYPE_MESH) {
- for (nlink = material->lamps.first; nlink; nlink = nlink->next) {
- lamp = nlink->data;
+ for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
+ GPULamp *lamp = nlink->data;
- if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay))
- && GPU_lamp_override_visible(lamp, srl, material->ma)) {
+ if (!lamp->hide && (lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) &&
+ GPU_lamp_override_visible(lamp, srl, material->ma))
+ {
lamp->dynenergy = lamp->energy;
copy_v3_v3(lamp->dyncol, lamp->col);
}
@@ -349,8 +355,10 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
}
if (material->dynproperty & DYN_LAMP_PERSMAT) {
- if (!GPU_lamp_has_shadow_buffer(lamp)) /* The lamp matrices are already updated if we're using shadow buffers */
+ /* The lamp matrices are already updated if we're using shadow buffers */
+ if (!GPU_lamp_has_shadow_buffer(lamp)) {
GPU_lamp_update_buffer_mats(lamp);
+ }
mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv);
}
}
@@ -361,19 +369,19 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
/* handle per material built-ins */
if (material->builtins & GPU_VIEW_MATRIX) {
- GPU_shader_uniform_vector(shader, material->viewmatloc, 16, 1, (float*)viewmat);
+ GPU_shader_uniform_vector(shader, material->viewmatloc, 16, 1, (float *)viewmat);
}
if (material->builtins & GPU_INVERSE_VIEW_MATRIX) {
- GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float*)viewinv);
+ GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float *)viewinv);
}
if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) {
if (camerafactors) {
- GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float*)camerafactors);
+ GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)camerafactors);
}
else {
/* use default, no scaling no offset */
float borders[4] = {1.0f, 1.0f, 0.0f, 0.0f};
- GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float*)borders);
+ GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)borders);
}
}
@@ -383,19 +391,36 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
}
}
-void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale, GPUParticleInfo* pi)
+void GPU_material_bind_uniforms(
+ GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
+ float autobumpscale, GPUParticleInfo *pi)
{
if (material->pass) {
GPUShader *shader = GPU_pass_shader(material->pass);
float invmat[4][4], col[4];
+ float localtoviewmat[4][4];
+ float invlocaltoviewmat[4][4];
/* handle per object builtins */
if (material->builtins & GPU_OBJECT_MATRIX) {
- GPU_shader_uniform_vector(shader, material->obmatloc, 16, 1, (float*)obmat);
+ GPU_shader_uniform_vector(shader, material->obmatloc, 16, 1, (float *)obmat);
}
if (material->builtins & GPU_INVERSE_OBJECT_MATRIX) {
invert_m4_m4(invmat, obmat);
- GPU_shader_uniform_vector(shader, material->invobmatloc, 16, 1, (float*)invmat);
+ GPU_shader_uniform_vector(shader, material->invobmatloc, 16, 1, (float *)invmat);
+ }
+ if (material->builtins & GPU_LOC_TO_VIEW_MATRIX) {
+ if (viewmat) {
+ mul_m4_m4m4(localtoviewmat, viewmat, obmat);
+ GPU_shader_uniform_vector(shader, material->localtoviewmatloc, 16, 1, (float *)localtoviewmat);
+ }
+ }
+ if (material->builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) {
+ if (viewmat) {
+ mul_m4_m4m4(localtoviewmat, viewmat, obmat);
+ invert_m4_m4(invlocaltoviewmat, localtoviewmat);
+ GPU_shader_uniform_vector(shader, material->invlocaltoviewmatloc, 16, 1, (float *)invlocaltoviewmat);
+ }
}
if (material->builtins & GPU_OBCOLOR) {
copy_v4_v4(col, obcol);
@@ -491,17 +516,20 @@ bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
{
- GPUNodeLink *visifac, *inpr;
+ GPUNodeLink *visifac;
/* from get_lamp_visibility */
if (lamp->type == LA_SUN || lamp->type == LA_HEMI) {
mat->dynproperty |= DYN_LAMP_VEC;
- GPU_link(mat, "lamp_visibility_sun_hemi", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac);
+ GPU_link(mat, "lamp_visibility_sun_hemi",
+ GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), lv, dist, &visifac);
return visifac;
}
else {
mat->dynproperty |= DYN_LAMP_CO;
- GPU_link(mat, "lamp_visibility_other", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac);
+ GPU_link(mat, "lamp_visibility_other",
+ GPU_builtin(GPU_VIEW_POSITION),
+ GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac);
if (lamp->type == LA_AREA)
return visifac;
@@ -510,13 +538,24 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
case LA_FALLOFF_CONSTANT:
break;
case LA_FALLOFF_INVLINEAR:
- GPU_link(mat, "lamp_falloff_invlinear", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
+ GPU_link(mat, "lamp_falloff_invlinear",
+ GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_INVSQUARE:
- GPU_link(mat, "lamp_falloff_invsquare", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
+ GPU_link(mat, "lamp_falloff_invsquare",
+ GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_SLIDERS:
- GPU_link(mat, "lamp_falloff_sliders", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob), GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac);
+ GPU_link(mat, "lamp_falloff_sliders",
+ GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
+ GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob),
+ GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac);
+ break;
+ case LA_FALLOFF_INVCOEFFICIENTS:
+ GPU_link(mat, "lamp_falloff_invcoefficients",
+ GPU_dynamic_uniform(&lamp->coeff_const, GPU_DYNAMIC_LAMP_COEFFCONST, lamp->ob),
+ GPU_dynamic_uniform(&lamp->coeff_lin, GPU_DYNAMIC_LAMP_COEFFLIN, lamp->ob),
+ GPU_dynamic_uniform(&lamp->coeff_quad, GPU_DYNAMIC_LAMP_COEFFQUAD, lamp->ob), *dist, &visifac);
break;
case LA_FALLOFF_CURVE:
{
@@ -525,26 +564,41 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
curvemapping_initialize(lamp->curfalloff);
curvemapping_table_RGBA(lamp->curfalloff, &array, &size);
- GPU_link(mat, "lamp_falloff_curve", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), GPU_texture(size, array), *dist, &visifac);
+ GPU_link(mat, "lamp_falloff_curve",
+ GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
+ GPU_texture(size, array), *dist, &visifac);
break;
}
}
if (lamp->mode & LA_SPHERE)
- GPU_link(mat, "lamp_visibility_sphere", GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, visifac, &visifac);
+ GPU_link(mat, "lamp_visibility_sphere",
+ GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob),
+ *dist, visifac, &visifac);
if (lamp->type == LA_SPOT) {
+ GPUNodeLink *inpr;
+
if (lamp->mode & LA_SQUARE) {
- mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_IMAT;
- GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float*)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), *lv, &inpr);
+ mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
+ GPU_link(mat, "lamp_visibility_spot_square",
+ GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
}
else {
- mat->dynproperty |= DYN_LAMP_VEC;
- GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), *lv, &inpr);
+ mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT;
+ GPU_link(mat, "lamp_visibility_spot_circle",
+ GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr);
}
- GPU_link(mat, "lamp_visibility_spot", GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), inpr, visifac, &visifac);
+ GPU_link(mat, "lamp_visibility_spot",
+ GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob),
+ GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob),
+ inpr, visifac, &visifac);
}
GPU_link(mat, "lamp_visibility_clamp", visifac, &visifac);
@@ -556,10 +610,10 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode
#if 0
static void area_lamp_vectors(LampRen *lar)
{
- float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey, multifac;
+ float xsize = 0.5f * lar->area_size, ysize = 0.5f * lar->area_sizey;
/* make it smaller, so area light can be multisampled */
- multifac = 1.0f / sqrtf((float)lar->ray_totsamp);
+ float multifac = 1.0f / sqrtf((float)lar->ray_totsamp);
xsize *= multifac;
ysize *= multifac;
@@ -587,17 +641,21 @@ static void area_lamp_vectors(LampRen *lar)
}
#endif
-static void ramp_blend(GPUMaterial *mat, GPUNodeLink *fac, GPUNodeLink *col1, GPUNodeLink *col2, int type, GPUNodeLink **outcol)
+static void ramp_blend(
+ GPUMaterial *mat, GPUNodeLink *fac, GPUNodeLink *col1, GPUNodeLink *col2, int type,
+ GPUNodeLink **r_col)
{
static const char *names[] = {"mix_blend", "mix_add", "mix_mult", "mix_sub",
"mix_screen", "mix_div", "mix_diff", "mix_dark", "mix_light",
"mix_overlay", "mix_dodge", "mix_burn", "mix_hue", "mix_sat",
"mix_val", "mix_color", "mix_soft", "mix_linear"};
- GPU_link(mat, names[type], fac, col1, col2, outcol);
+ GPU_link(mat, names[type], fac, col1, col2, r_col);
}
-static void do_colorband_blend(GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type, GPUNodeLink *incol, GPUNodeLink **outcol)
+static void do_colorband_blend(
+ GPUMaterial *mat, ColorBand *coba, GPUNodeLink *fac, float rampfac, int type,
+ GPUNodeLink *incol, GPUNodeLink **r_col)
{
GPUNodeLink *tmp, *alpha, *col;
float *array;
@@ -612,18 +670,18 @@ static void do_colorband_blend(GPUMaterial *mat, ColorBand *coba, GPUNodeLink *f
GPU_link(mat, "math_multiply", alpha, GPU_uniform(&rampfac), &fac);
/* blending method */
- ramp_blend(mat, fac, incol, col, type, outcol);
+ ramp_blend(mat, fac, incol, col, type, r_col);
}
static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *fac;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS)) {
if (ma->ramp_col) {
- if (ma->rampin_col==MA_RAMP_IN_RESULT) {
+ if (ma->rampin_col == MA_RAMP_IN_RESULT) {
+ GPUNodeLink *fac;
GPU_link(mat, "ramp_rgbtobw", *diff, &fac);
/* colorband + blend */
@@ -633,7 +691,9 @@ static void ramp_diffuse_result(GPUShadeInput *shi, GPUNodeLink **diff)
}
}
-static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *rgb, GPUNodeLink **diff)
+static void add_to_diffuse(
+ GPUMaterial *mat, Material *ma, GPUShadeInput *shi, GPUNodeLink *is, GPUNodeLink *rgb,
+ GPUNodeLink **r_diff)
{
GPUNodeLink *fac, *tmp, *addcol;
@@ -641,7 +701,7 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
ma->ramp_col && (ma->mode & MA_RAMP_COL))
{
/* MA_RAMP_IN_RESULT is exceptional */
- if (ma->rampin_col==MA_RAMP_IN_RESULT) {
+ if (ma->rampin_col == MA_RAMP_IN_RESULT) {
addcol = shi->rgb;
}
else {
@@ -651,7 +711,7 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
GPU_link(mat, "ramp_rgbtobw", rgb, &fac);
break;
case MA_RAMP_IN_SHADER:
- fac= is;
+ fac = is;
break;
case MA_RAMP_IN_NOR:
GPU_link(mat, "vec_math_dot", shi->view, shi->vn, &tmp, &fac);
@@ -669,18 +729,18 @@ static void add_to_diffuse(GPUMaterial *mat, Material *ma, GPUShadeInput *shi, G
addcol = shi->rgb;
/* output to */
- GPU_link(mat, "shade_madd", *diff, rgb, addcol, diff);
+ GPU_link(mat, "shade_madd", *r_diff, rgb, addcol, r_diff);
}
static void ramp_spec_result(GPUShadeInput *shi, GPUNodeLink **spec)
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *fac;
if (!(mat->scene->gm.flag & GAME_GLSL_NO_RAMPS) &&
ma->ramp_spec && ma->rampin_spec == MA_RAMP_IN_RESULT)
{
+ GPUNodeLink *fac;
GPU_link(mat, "ramp_rgbtobw", *spec, &fac);
/* colorband + blend */
@@ -729,22 +789,20 @@ static void add_user_list(ListBase *list, void *data)
static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **rgb)
{
- GPUNodeLink *tex_rgb;
- MTex *mtex = NULL;
- int i;
- float one = 1.f;
-
- for (i = 0; i < MAX_MTEX; ++i) {
- mtex = lamp->la->mtex[i];
+ for (int i = 0; i < MAX_MTEX; ++i) {
+ MTex *mtex = lamp->la->mtex[i];
if (mtex && mtex->tex->type & TEX_IMAGE && mtex->tex->ima) {
mat->dynproperty |= DYN_LAMP_PERSMAT;
+ float one = 1.0f;
+ GPUNodeLink *tex_rgb;
+
GPU_link(mat, "shade_light_texture",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_image(mtex->tex->ima, &mtex->tex->iuser, false),
- GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- &tex_rgb);
+ GPU_builtin(GPU_VIEW_POSITION),
+ GPU_image(mtex->tex->ima, &mtex->tex->iuser, false),
+ GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
+ &tex_rgb);
texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb);
}
}
@@ -754,17 +812,17 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
{
Material *ma = shi->mat;
GPUMaterial *mat = shi->gpumat;
- GPUNodeLink *lv, *dist, *visifac, *is, *inp, *i, *vn, *view;
+ GPUNodeLink *lv, *dist, *is, *inp, *i;
GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol;
float one = 1.0f;
if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW))
return;
- vn = shi->vn;
- view = shi->view;
+ GPUNodeLink *vn = shi->vn;
+ GPUNodeLink *view = shi->view;
- visifac = lamp_get_visibility(mat, lamp, &lv, &dist);
+ GPUNodeLink *visifac = lamp_get_visibility(mat, lamp, &lv, &dist);
#if 0
if (ma->mode & MA_TANGENT_V)
@@ -783,22 +841,31 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
if (lamp->type == LA_AREA) {
float area[4][4] = {{0.0f}}, areasize = 0.0f;
- mat->dynproperty |= DYN_LAMP_VEC|DYN_LAMP_CO;
- GPU_link(mat, "shade_inp_area", GPU_builtin(GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn, GPU_uniform((float*)area),
- GPU_uniform(&areasize), GPU_uniform(&lamp->k), &inp);
+ mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_CO;
+ GPU_link(mat, "shade_inp_area",
+ GPU_builtin(GPU_VIEW_POSITION),
+ GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob),
+ GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn,
+ GPU_uniform((float *)area),
+ GPU_uniform(&areasize),
+ GPU_uniform(&lamp->k), &inp);
}
is = inp; /* Lambert */
if (!(mat->scene->gm.flag & GAME_GLSL_NO_SHADERS)) {
if (ma->diff_shader == MA_DIFF_ORENNAYAR)
- GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view, GPU_uniform(&ma->roughness), &is);
+ GPU_link(mat, "shade_diffuse_oren_nayer", inp, vn, lv, view,
+ GPU_uniform(&ma->roughness), &is);
else if (ma->diff_shader == MA_DIFF_TOON)
- GPU_link(mat, "shade_diffuse_toon", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
+ GPU_link(mat, "shade_diffuse_toon", vn, lv, view,
+ GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
else if (ma->diff_shader == MA_DIFF_MINNAERT)
- GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view, GPU_uniform(&ma->darkness), &is);
+ GPU_link(mat, "shade_diffuse_minnaert", inp, vn, view,
+ GPU_uniform(&ma->darkness), &is);
else if (ma->diff_shader == MA_DIFF_FRESNEL)
- GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view, GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
+ GPU_link(mat, "shade_diffuse_fresnel", vn, lv, view,
+ GPU_uniform(&ma->param[0]), GPU_uniform(&ma->param[1]), &is);
}
}
@@ -811,7 +878,8 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol);
shade_light_textures(mat, lamp, &lcol);
- GPU_link(mat, "shade_mul_value_v3", GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol);
+ GPU_link(mat, "shade_mul_value_v3",
+ GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol);
#if 0
if (ma->mode & MA_TANGENT_VN)
@@ -827,17 +895,17 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
GPU_link(mat, "test_shadowbuf_vsm",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadfac);
+ GPU_builtin(GPU_VIEW_POSITION),
+ GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
+ GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadfac);
}
else {
GPU_link(mat, "test_shadowbuf",
- GPU_builtin(GPU_VIEW_POSITION),
- GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), inp, &shadfac);
+ GPU_builtin(GPU_VIEW_POSITION),
+ GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
+ GPU_uniform(&lamp->bias), inp, &shadfac);
}
if (lamp->mode & LA_ONLYSHADOW) {
@@ -848,12 +916,13 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
if (!(lamp->mode & LA_NO_DIFF)) {
GPU_link(mat, "shade_only_shadow_diffuse", shadrgb, shi->rgb,
- shr->diff, &shr->diff);
+ shr->diff, &shr->diff);
}
- if (!(lamp->mode & LA_NO_SPEC))
+ if (!(lamp->mode & LA_NO_SPEC)) {
GPU_link(mat, "shade_only_shadow_specular", shadrgb, shi->specrgb,
- shr->spec, &shr->spec);
+ shr->spec, &shr->spec);
+ }
add_user_list(&mat->lamps, lamp);
add_user_list(&lamp->materials, shi->gpumat->ma);
@@ -892,16 +961,24 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec);
}
else {
- if (ma->spec_shader == MA_SPEC_PHONG)
+ if (ma->spec_shader == MA_SPEC_PHONG) {
GPU_link(mat, "shade_phong_spec", vn, lv, view, shi->har, &specfac);
- else if (ma->spec_shader == MA_SPEC_COOKTORR)
+ }
+ else if (ma->spec_shader == MA_SPEC_COOKTORR) {
GPU_link(mat, "shade_cooktorr_spec", vn, lv, view, shi->har, &specfac);
- else if (ma->spec_shader == MA_SPEC_BLINN)
- GPU_link(mat, "shade_blinn_spec", vn, lv, view, GPU_uniform(&ma->refrac), shi->har, &specfac);
- else if (ma->spec_shader == MA_SPEC_WARDISO)
- GPU_link(mat, "shade_wardiso_spec", vn, lv, view, GPU_uniform(&ma->rms), &specfac);
- else
- GPU_link(mat, "shade_toon_spec", vn, lv, view, GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac);
+ }
+ else if (ma->spec_shader == MA_SPEC_BLINN) {
+ GPU_link(mat, "shade_blinn_spec", vn, lv, view,
+ GPU_uniform(&ma->refrac), shi->har, &specfac);
+ }
+ else if (ma->spec_shader == MA_SPEC_WARDISO) {
+ GPU_link(mat, "shade_wardiso_spec", vn, lv, view,
+ GPU_uniform(&ma->rms), &specfac);
+ }
+ else {
+ GPU_link(mat, "shade_toon_spec", vn, lv, view,
+ GPU_uniform(&ma->param[2]), GPU_uniform(&ma->param[3]), &specfac);
+ }
if (lamp->type == LA_AREA)
GPU_link(mat, "shade_spec_area_inp", specfac, inp, &specfac);
@@ -928,24 +1005,21 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
{
Base *base;
- Object *ob;
Scene *sce_iter;
- GPULamp *lamp;
for (SETLOOPER(shi->gpumat->scene, sce_iter, base)) {
- ob = base->object;
+ Object *ob = base->object;
if (ob->type == OB_LAMP) {
- lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL);
+ GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob, NULL);
if (lamp)
shade_one_light(shi, shr, lamp);
}
if (ob->transflag & OB_DUPLI) {
- DupliObject *dob;
ListBase *lb = object_duplilist(G.main->eval_ctx, shi->gpumat->scene, ob);
- for (dob = lb->first; dob; dob = dob->next) {
+ for (DupliObject *dob = lb->first; dob; dob = dob->next) {
Object *ob_iter = dob->ob;
if (ob_iter->type == OB_LAMP) {
@@ -953,7 +1027,7 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
copy_m4_m4(omat, ob_iter->obmat);
copy_m4_m4(ob_iter->obmat, dob->mat);
- lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob_iter, ob);
+ GPULamp *lamp = GPU_lamp_from_blender(shi->gpumat->scene, ob_iter, ob);
if (lamp)
shade_one_light(shi, shr, lamp);
@@ -970,96 +1044,100 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
GPU_link(shi->gpumat, "shade_clamp_positive", shr->diff, &shr->diff);
}
-static void texture_rgb_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, int blendtype, GPUNodeLink **in)
+static void texture_rgb_blend(
+ GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
+ int blendtype, GPUNodeLink **in)
{
switch (blendtype) {
- case MTEX_BLEND:
- GPU_link(mat, "mtex_rgb_blend", out, tex, fact, facg, in);
- break;
- case MTEX_MUL:
- GPU_link(mat, "mtex_rgb_mul", out, tex, fact, facg, in);
- break;
- case MTEX_SCREEN:
- GPU_link(mat, "mtex_rgb_screen", out, tex, fact, facg, in);
- break;
- case MTEX_OVERLAY:
- GPU_link(mat, "mtex_rgb_overlay", out, tex, fact, facg, in);
- break;
- case MTEX_SUB:
- GPU_link(mat, "mtex_rgb_sub", out, tex, fact, facg, in);
- break;
- case MTEX_ADD:
- GPU_link(mat, "mtex_rgb_add", out, tex, fact, facg, in);
- break;
- case MTEX_DIV:
- GPU_link(mat, "mtex_rgb_div", out, tex, fact, facg, in);
- break;
- case MTEX_DIFF:
- GPU_link(mat, "mtex_rgb_diff", out, tex, fact, facg, in);
- break;
- case MTEX_DARK:
- GPU_link(mat, "mtex_rgb_dark", out, tex, fact, facg, in);
- break;
- case MTEX_LIGHT:
- GPU_link(mat, "mtex_rgb_light", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_HUE:
- GPU_link(mat, "mtex_rgb_hue", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_SAT:
- GPU_link(mat, "mtex_rgb_sat", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_VAL:
- GPU_link(mat, "mtex_rgb_val", out, tex, fact, facg, in);
- break;
- case MTEX_BLEND_COLOR:
- GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in);
- break;
- case MTEX_SOFT_LIGHT:
- GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in);
- break;
- case MTEX_LIN_LIGHT:
- GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in);
- break;
- default:
- GPU_link(mat, "set_rgb_zero", &in);
- break;
+ case MTEX_BLEND:
+ GPU_link(mat, "mtex_rgb_blend", out, tex, fact, facg, in);
+ break;
+ case MTEX_MUL:
+ GPU_link(mat, "mtex_rgb_mul", out, tex, fact, facg, in);
+ break;
+ case MTEX_SCREEN:
+ GPU_link(mat, "mtex_rgb_screen", out, tex, fact, facg, in);
+ break;
+ case MTEX_OVERLAY:
+ GPU_link(mat, "mtex_rgb_overlay", out, tex, fact, facg, in);
+ break;
+ case MTEX_SUB:
+ GPU_link(mat, "mtex_rgb_sub", out, tex, fact, facg, in);
+ break;
+ case MTEX_ADD:
+ GPU_link(mat, "mtex_rgb_add", out, tex, fact, facg, in);
+ break;
+ case MTEX_DIV:
+ GPU_link(mat, "mtex_rgb_div", out, tex, fact, facg, in);
+ break;
+ case MTEX_DIFF:
+ GPU_link(mat, "mtex_rgb_diff", out, tex, fact, facg, in);
+ break;
+ case MTEX_DARK:
+ GPU_link(mat, "mtex_rgb_dark", out, tex, fact, facg, in);
+ break;
+ case MTEX_LIGHT:
+ GPU_link(mat, "mtex_rgb_light", out, tex, fact, facg, in);
+ break;
+ case MTEX_BLEND_HUE:
+ GPU_link(mat, "mtex_rgb_hue", out, tex, fact, facg, in);
+ break;
+ case MTEX_BLEND_SAT:
+ GPU_link(mat, "mtex_rgb_sat", out, tex, fact, facg, in);
+ break;
+ case MTEX_BLEND_VAL:
+ GPU_link(mat, "mtex_rgb_val", out, tex, fact, facg, in);
+ break;
+ case MTEX_BLEND_COLOR:
+ GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in);
+ break;
+ case MTEX_SOFT_LIGHT:
+ GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in);
+ break;
+ case MTEX_LIN_LIGHT:
+ GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in);
+ break;
+ default:
+ GPU_link(mat, "set_rgb_zero", &in);
+ break;
}
}
-static void texture_value_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, int blendtype, GPUNodeLink **in)
+static void texture_value_blend(
+ GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg,
+ int blendtype, GPUNodeLink **in)
{
switch (blendtype) {
- case MTEX_BLEND:
- GPU_link(mat, "mtex_value_blend", out, tex, fact, facg, in);
- break;
- case MTEX_MUL:
- GPU_link(mat, "mtex_value_mul", out, tex, fact, facg, in);
- break;
- case MTEX_SCREEN:
- GPU_link(mat, "mtex_value_screen", out, tex, fact, facg, in);
- break;
- case MTEX_SUB:
- GPU_link(mat, "mtex_value_sub", out, tex, fact, facg, in);
- break;
- case MTEX_ADD:
- GPU_link(mat, "mtex_value_add", out, tex, fact, facg, in);
- break;
- case MTEX_DIV:
- GPU_link(mat, "mtex_value_div", out, tex, fact, facg, in);
- break;
- case MTEX_DIFF:
- GPU_link(mat, "mtex_value_diff", out, tex, fact, facg, in);
- break;
- case MTEX_DARK:
- GPU_link(mat, "mtex_value_dark", out, tex, fact, facg, in);
- break;
- case MTEX_LIGHT:
- GPU_link(mat, "mtex_value_light", out, tex, fact, facg, in);
- break;
- default:
- GPU_link(mat, "set_value_zero", &in);
- break;
+ case MTEX_BLEND:
+ GPU_link(mat, "mtex_value_blend", out, tex, fact, facg, in);
+ break;
+ case MTEX_MUL:
+ GPU_link(mat, "mtex_value_mul", out, tex, fact, facg, in);
+ break;
+ case MTEX_SCREEN:
+ GPU_link(mat, "mtex_value_screen", out, tex, fact, facg, in);
+ break;
+ case MTEX_SUB:
+ GPU_link(mat, "mtex_value_sub", out, tex, fact, facg, in);
+ break;
+ case MTEX_ADD:
+ GPU_link(mat, "mtex_value_add", out, tex, fact, facg, in);
+ break;
+ case MTEX_DIV:
+ GPU_link(mat, "mtex_value_div", out, tex, fact, facg, in);
+ break;
+ case MTEX_DIFF:
+ GPU_link(mat, "mtex_value_diff", out, tex, fact, facg, in);
+ break;
+ case MTEX_DARK:
+ GPU_link(mat, "mtex_value_dark", out, tex, fact, facg, in);
+ break;
+ case MTEX_LIGHT:
+ GPU_link(mat, "mtex_value_light", out, tex, fact, facg, in);
+ break;
+ default:
+ GPU_link(mat, "set_value_zero", &in);
+ break;
}
}
@@ -1073,14 +1151,13 @@ static void do_material_tex(GPUShadeInput *shi)
GPUNodeLink *texco_norm, *texco_orco, *texco_object;
GPUNodeLink *texco_global, *texco_uv = NULL;
GPUNodeLink *newnor, *orn;
- /*char *lastuvname = NULL;*/ /*UNUSED*/
- float one = 1.0f, norfac, ofs[3];
- int tex_nr, rgbnor, talpha;
+ float one = 1.0f;
+ int rgbnor, talpha;
bool init_done = false;
int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */
GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude;
int iFirstTimeNMap = 1;
- int found_deriv_map = 0;
+ bool found_deriv_map = false;
GPU_link(mat, "set_value", GPU_uniform(&one), &stencil);
@@ -1095,10 +1172,10 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
GPU_builtin(GPU_VIEW_POSITION), &texco_global);
- orn= texco_norm;
+ orn = texco_norm;
/* go over texture slots */
- for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
+ for (int tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
/* separate tex switching */
if (ma->septex & (1 << tex_nr)) continue;
@@ -1140,16 +1217,30 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f)
GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco);
- ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0];
- ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
- ofs[2] = 0.0f;
+ float ofs[3] = {
+ mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0],
+ mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1],
+ 0.0f
+ };
+
if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
talpha = 0;
- if (tex && tex->type == TEX_IMAGE && tex->ima) {
- GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
+ if (tex && tex->ima &&
+ ((tex->type == TEX_IMAGE) ||
+ ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL))))
+ {
+ if (tex->type == TEX_IMAGE) {
+ GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
+ }
+ else {
+ GPU_link(mat, "mtex_cube_map_refl",
+ GPU_cube_map(tex->ima, &tex->iuser, false), shi->view, shi->vn,
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ GPU_builtin(GPU_VIEW_MATRIX), &tin, &trgb);
+ }
rgbnor = TEX_RGB;
talpha = ((tex->imaflag & TEX_USEALPHA) && tex->ima && (tex->ima->flag & IMA_IGNORE_ALPHA) == 0);
@@ -1179,9 +1270,9 @@ static void do_material_tex(GPUShadeInput *shi)
}
/* mapping */
- if (mtex->mapto & (MAP_COL+MAP_COLSPEC)) {
+ if (mtex->mapto & (MAP_COL | MAP_COLSPEC | MAP_COLMIR)) {
/* stencil maps on the texture control slider, not texture intensity value */
- if ((rgbnor & TEX_RGB)==0) {
+ if ((rgbnor & TEX_RGB) == 0) {
GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &tcol);
}
else {
@@ -1195,9 +1286,13 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "set_value_one", &tin);
}
- if (tex->type == TEX_IMAGE)
- if (GPU_material_do_color_management(mat))
+ if ((tex->type == TEX_IMAGE) ||
+ ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL)))
+ {
+ if (GPU_material_do_color_management(mat)) {
GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol);
+ }
+ }
if (mtex->mapto & MAP_COL) {
GPUNodeLink *colfac;
@@ -1216,6 +1311,20 @@ static void do_material_tex(GPUShadeInput *shi)
texture_rgb_blend(mat, tcol, shi->specrgb, tin, colspecfac, mtex->blendtype, &shi->specrgb);
}
+
+ if (mtex->mapto & MAP_COLMIR) {
+ GPUNodeLink *colmirfac;
+
+ if (mtex->mirrfac == 1.0f) colmirfac = stencil;
+ else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->mirrfac), stencil, &colmirfac);
+
+ /* exception for envmap only */
+ if (tex->type == TEX_ENVMAP && mtex->blendtype == MTEX_BLEND) {
+ GPU_link(mat, "mtex_mirror", tcol, shi->refcol, tin, colmirfac, &shi->refcol);
+ }
+ else
+ texture_rgb_blend(mat, tcol, shi->mir, tin, colmirfac, mtex->blendtype, &shi->mir);
+ }
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_NORM)) {
@@ -1233,12 +1342,15 @@ static void do_material_tex(GPUShadeInput *shi)
if (iFirstTimeNMap != 0) {
// use unnormalized normal (this is how we bake it - closer to gamedev)
GPUNodeLink *vNegNorm;
- GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm);
- GPU_link(mat, "mtex_nspace_tangent", GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor);
+ GPU_link(mat, "vec_math_negate",
+ GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm);
+ GPU_link(mat, "mtex_nspace_tangent",
+ GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor);
iFirstTimeNMap = 0;
}
else { /* otherwise use accumulated perturbations */
- GPU_link(mat, "mtex_nspace_tangent", GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor);
+ GPU_link(mat, "mtex_nspace_tangent",
+ GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor);
}
}
else if (mtex->normapspace == MTEX_NSPACE_OBJECT) {
@@ -1254,7 +1366,7 @@ static void do_material_tex(GPUShadeInput *shi)
newnor = tnor;
}
- norfac = min_ff(fabsf(mtex->norfac), 1.0f);
+ float norfac = min_ff(fabsf(mtex->norfac), 1.0f);
if (norfac == 1.0f && !GPU_link_changed(stencil)) {
shi->vn = newnor;
@@ -1269,11 +1381,12 @@ static void do_material_tex(GPUShadeInput *shi)
}
}
- else if ((mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) || found_deriv_map) {
+ else if (found_deriv_map ||
+ (mtex->texflag & (MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)))
+ {
/* ntap bumpmap image */
int iBumpSpace;
float ima_x, ima_y;
- float hScale;
float imag_tspace_dimension_x = 1024.0f; /* only used for texture space variant */
float aspect = 1.0f;
@@ -1281,16 +1394,16 @@ static void do_material_tex(GPUShadeInput *shi)
GPUNodeLink *vR1, *vR2;
GPUNodeLink *dBs, *dBt, *fDet;
- hScale = 0.1; /* compatibility adjustment factor for all bumpspace types */
+ float hScale = 0.1f; /* compatibility adjustment factor for all bumpspace types */
if (mtex->texflag & MTEX_BUMP_TEXTURESPACE)
hScale = 13.0f; /* factor for scaling texspace bumps */
- else if (found_deriv_map!=0)
+ else if (found_deriv_map)
hScale = 1.0f;
/* resolve texture resolution */
if ((mtex->texflag & MTEX_BUMP_TEXTURESPACE) || found_deriv_map) {
ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL);
- ima_x = 512.0f; ima_y = 512.f; /* prevent calling textureSize, glsl 1.3 only */
+ ima_x = 512.0f; ima_y = 512.0f; /* prevent calling textureSize, glsl 1.3 only */
if (ibuf) {
ima_x = ibuf->x;
ima_y = ibuf->y;
@@ -1303,7 +1416,7 @@ static void do_material_tex(GPUShadeInput *shi)
* normal in the renderer points inward which corresponds
* to inverting the bump map. Should this ever change
* this negate must be removed. */
- norfac = -hScale * mtex->norfac;
+ float norfac = -hScale * mtex->norfac;
if (found_deriv_map) {
float fVirtDim = sqrtf(fabsf(ima_x * mtex->size[0] * ima_y * mtex->size[1]));
norfac /= MAX2(fVirtDim, FLT_EPSILON);
@@ -1339,7 +1452,10 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->texflag & MTEX_BUMP_OBJECTSPACE)
GPU_link(mat, "mtex_bump_init_objspace",
surf_pos, vNorg,
- GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ GPU_builtin(GPU_VIEW_MATRIX),
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+ GPU_builtin(GPU_OBJECT_MATRIX),
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
fPrevMagnitude, vNacc,
&fPrevMagnitude, &vNacc,
&vR1, &vR2, &fDet);
@@ -1364,7 +1480,8 @@ static void do_material_tex(GPUShadeInput *shi)
if (found_deriv_map) {
GPU_link(mat, "mtex_bump_deriv",
- texco, GPU_image(tex->ima, &tex->iuser, true), GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac,
+ texco, GPU_image(tex->ima, &tex->iuser, true),
+ GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac,
&dBs, &dBt);
}
else if (mtex->texflag & MTEX_3TAP_BUMP)
@@ -1394,7 +1511,8 @@ static void do_material_tex(GPUShadeInput *shi)
GPU_link(mat, "mtex_bump_apply_texspace",
fDet, dBs, dBt, vR1, vR2,
GPU_image(tex->ima, &tex->iuser, true), texco,
- GPU_uniform(&imag_tspace_dimension_x), GPU_uniform(&imag_tspace_dimension_y), vNacc,
+ GPU_uniform(&imag_tspace_dimension_x),
+ GPU_uniform(&imag_tspace_dimension_y), vNacc,
&vNacc, &shi->vn);
}
else
@@ -1422,7 +1540,9 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->difffac == 1.0f) difffac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->difffac), stencil, &difffac);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), shi->refl, tin, difffac, mtex->blendtype, &shi->refl);
+ texture_value_blend(
+ mat, GPU_uniform(&mtex->def_var), shi->refl, tin, difffac,
+ mtex->blendtype, &shi->refl);
GPU_link(mat, "mtex_value_clamp_positive", shi->refl, &shi->refl);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_SPEC) {
@@ -1431,7 +1551,9 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->specfac == 1.0f) specfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->specfac), stencil, &specfac);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), shi->spec, tin, specfac, mtex->blendtype, &shi->spec);
+ texture_value_blend(
+ mat, GPU_uniform(&mtex->def_var), shi->spec, tin, specfac,
+ mtex->blendtype, &shi->spec);
GPU_link(mat, "mtex_value_clamp_positive", shi->spec, &shi->spec);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_EMIT) {
@@ -1440,7 +1562,9 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->emitfac == 1.0f) emitfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->emitfac), stencil, &emitfac);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), shi->emit, tin, emitfac, mtex->blendtype, &shi->emit);
+ texture_value_blend(
+ mat, GPU_uniform(&mtex->def_var), shi->emit, tin, emitfac,
+ mtex->blendtype, &shi->emit);
GPU_link(mat, "mtex_value_clamp_positive", shi->emit, &shi->emit);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_HAR) {
@@ -1450,7 +1574,9 @@ static void do_material_tex(GPUShadeInput *shi)
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->hardfac), stencil, &hardfac);
GPU_link(mat, "mtex_har_divide", shi->har, &shi->har);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), shi->har, tin, hardfac, mtex->blendtype, &shi->har);
+ texture_value_blend(
+ mat, GPU_uniform(&mtex->def_var), shi->har, tin, hardfac,
+ mtex->blendtype, &shi->har);
GPU_link(mat, "mtex_har_multiply_clamp", shi->har, &shi->har);
}
if (mtex->mapto & MAP_ALPHA) {
@@ -1459,7 +1585,9 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->alphafac == 1.0f) alphafac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->alphafac), stencil, &alphafac);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), shi->alpha, tin, alphafac, mtex->blendtype, &shi->alpha);
+ texture_value_blend(
+ mat, GPU_uniform(&mtex->def_var), shi->alpha, tin, alphafac,
+ mtex->blendtype, &shi->alpha);
GPU_link(mat, "mtex_value_clamp", shi->alpha, &shi->alpha);
}
if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_AMB) {
@@ -1468,7 +1596,9 @@ static void do_material_tex(GPUShadeInput *shi)
if (mtex->ambfac == 1.0f) ambfac = stencil;
else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->ambfac), stencil, &ambfac);
- texture_value_blend(mat, GPU_uniform(&mtex->def_var), shi->amb, tin, ambfac, mtex->blendtype, &shi->amb);
+ texture_value_blend(
+ mat, GPU_uniform(&mtex->def_var), shi->amb, tin, ambfac,
+ mtex->blendtype, &shi->amb);
GPU_link(mat, "mtex_value_clamp", shi->amb, &shi->amb);
}
}
@@ -1487,6 +1617,8 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, NULL), &shi->rgb);
GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, NULL), &shi->specrgb);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, NULL), &shi->mir);
+ GPU_link(mat, "set_rgba_zero", &shi->refcol);
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn);
if (mat->alpha)
@@ -1497,7 +1629,7 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi)
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, NULL), &shi->refl);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL), &shi->spec);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, NULL), &shi->emit);
- GPU_link(mat, "set_value", GPU_dynamic_uniform((float*)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har);
+ GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, NULL), &shi->har);
GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL), &shi->amb);
GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra);
GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view);
@@ -1556,7 +1688,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
}
else {
if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) {
- if ((ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) == MA_VERTEXCOL) {
+ if ((ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == MA_VERTEXCOL) {
GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit);
GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff);
}
@@ -1597,15 +1729,19 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
}
}
- if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP|MA_RAYTRANSP))) {
- if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f)
+ if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP | MA_RAYTRANSP))) {
+ if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f) {
GPU_link(mat, "alpha_spec_correction", shr->spec, shi->spectra,
- shi->alpha, &shr->alpha);
+ shi->alpha, &shr->alpha);
+ }
}
if (ma->mode & MA_RAMP_COL) ramp_diffuse_result(shi, &shr->combined);
if (ma->mode & MA_RAMP_SPEC) ramp_spec_result(shi, &shr->spec);
+ if (GPU_link_changed(shi->refcol))
+ GPU_link(mat, "shade_add_mirror", shi->mir, shi->refcol, shr->combined, &shr->combined);
+
if (GPU_link_changed(shi->spec) || ma->spec != 0.0f)
GPU_link(mat, "shade_add", shr->combined, shr->spec, &shr->combined);
}
@@ -1657,7 +1793,8 @@ static GPUNodeLink *gpu_material_diffuse_bsdf(GPUMaterial *mat, Material *ma)
static float roughness = 0.0f;
GPUNodeLink *outlink;
- GPU_link(mat, "node_bsdf_diffuse", GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_builtin(GPU_VIEW_NORMAL), &outlink);
+ GPU_link(mat, "node_bsdf_diffuse",
+ GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_builtin(GPU_VIEW_NORMAL), &outlink);
return outlink;
}
@@ -1670,7 +1807,8 @@ static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma)
* matcap normal holds the normal remapped to the 0.0 - 1.0 range. To take advantage of flat shading, we abuse
* the built in secondary color of opengl. Color is just the regular color, which should include mask value too.
* This also needs flat shading so we use the primary opengl color built-in */
- GPU_link(mat, "material_preview_matcap", GPU_uniform(&ma->r), GPU_image_preview(ma->preview), GPU_opengl_builtin(GPU_MATCAP_NORMAL), GPU_opengl_builtin(GPU_COLOR), &outlink);
+ GPU_link(mat, "material_preview_matcap", GPU_uniform(&ma->r), GPU_image_preview(ma->preview),
+ GPU_opengl_builtin(GPU_MATCAP_NORMAL), GPU_opengl_builtin(GPU_COLOR), &outlink);
return outlink;
}
@@ -1683,7 +1821,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv
LinkData *link;
for (link = ma->gpumaterial.first; link; link = link->next) {
- GPUMaterial *current_material = (GPUMaterial*)link->data;
+ GPUMaterial *current_material = (GPUMaterial *)link->data;
if (current_material->scene == scene &&
current_material->is_opensubdiv == use_opensubdiv)
{
@@ -1719,13 +1857,206 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv
return mat;
}
+static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor, GPUNodeLink **zen, GPUNodeLink **blend)
+{
+ GPUMaterial *mat = shi->gpumat;
+ GPUNodeLink *texco, *tin, *trgb, *stencil, *tcol, *zenfac;
+ MTex *mtex;
+ Tex *tex;
+ float ofs[3], zero = 0.0f;
+ int tex_nr, rgbnor;
+
+ GPU_link(mat, "set_value_one", &stencil);
+ /* go over texture slots */
+ for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) {
+ if (wo->mtex[tex_nr]) {
+ mtex = wo->mtex[tex_nr];
+ tex = mtex->tex;
+ if (tex == NULL || !tex->ima || (tex->type != TEX_IMAGE && tex->type != TEX_ENVMAP))
+ continue;
+ /* which coords */
+ if (mtex->texco == TEXCO_VIEW || mtex->texco == TEXCO_GLOB) {
+ if (tex->type == TEX_IMAGE)
+ texco = GPU_builtin(GPU_VIEW_POSITION);
+ else if (tex->type == TEX_ENVMAP)
+ GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco);
+ }
+ else if (mtex->texco == TEXCO_EQUIRECTMAP || mtex->texco == TEXCO_ANGMAP) {
+ if ((tex->type == TEX_IMAGE && wo->skytype & WO_SKYREAL) || tex->type == TEX_ENVMAP)
+ GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco);
+ else
+ texco = GPU_builtin(GPU_VIEW_POSITION);
+ }
+ else
+ continue;
+ GPU_link(mat, "texco_norm", texco, &texco);
+ if (tex->type == TEX_IMAGE && !(wo->skytype & WO_SKYREAL)) {
+ GPU_link(mat, "mtex_2d_mapping", texco, &texco);
+ }
+ if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) {
+ float size[3] = { mtex->size[0], mtex->size[1], mtex->size[2] };
+ if (tex->type == TEX_ENVMAP) {
+ size[1] = mtex->size[2];
+ size[2] = mtex->size[1];
+ }
+ GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(size), &texco);
+ }
+ ofs[0] = mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0];
+ if (tex->type == TEX_ENVMAP) {
+ ofs[1] = -mtex->ofs[2] + 0.5f - 0.5f * mtex->size[2];
+ ofs[2] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
+ }
+ else {
+ ofs[1] = mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1];
+ ofs[2] = 0.0;
+ }
+ if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f)
+ GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco);
+ if (mtex->texco == TEXCO_EQUIRECTMAP) {
+ GPU_link(mat, "node_tex_environment_equirectangular", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb);
+ }
+ else if (mtex->texco == TEXCO_ANGMAP) {
+ GPU_link(mat, "node_tex_environment_mirror_ball", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb);
+ }
+ else {
+ if (tex->type == TEX_ENVMAP)
+ GPU_link(mat, "mtex_cube_map", texco, GPU_cube_map(tex->ima, &tex->iuser, false), &tin, &trgb);
+ else if (tex->type == TEX_IMAGE)
+ GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb);
+ }
+ rgbnor = TEX_RGB;
+ if (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)
+ if (GPU_material_do_color_management(mat))
+ GPU_link(mat, "srgb_to_linearrgb", trgb, &trgb);
+ /* texture output */
+ if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
+ GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
+ rgbnor -= TEX_RGB;
+ }
+ if (mtex->texflag & MTEX_NEGATIVE) {
+ if (rgbnor & TEX_RGB)
+ GPU_link(mat, "mtex_rgb_invert", trgb, &trgb);
+ else
+ GPU_link(mat, "mtex_value_invert", tin, &tin);
+ }
+ if (mtex->texflag & MTEX_STENCIL) {
+ if (rgbnor & TEX_RGB)
+ GPU_link(mat, "mtex_rgb_stencil", stencil, trgb, &stencil, &trgb);
+ else
+ GPU_link(mat, "mtex_value_stencil", stencil, tin, &stencil, &tin);
+ }
+ else {
+ if (rgbnor & TEX_RGB)
+ GPU_link(mat, "mtex_alpha_multiply_value", trgb, stencil, &trgb);
+ else
+ GPU_link(mat, "math_multiply", stencil, tin, &tin);
+ }
+ /* color mapping */
+ if (mtex->mapto & (WOMAP_HORIZ + WOMAP_ZENUP + WOMAP_ZENDOWN)) {
+ if ((rgbnor & TEX_RGB) == 0)
+ GPU_link(mat, "set_rgb", GPU_uniform(&mtex->r), &trgb);
+ else
+ GPU_link(mat, "mtex_alpha_from_col", trgb, &tin);
+ GPU_link(mat, "set_rgb", trgb, &tcol);
+ if (mtex->mapto & WOMAP_HORIZ) {
+ texture_rgb_blend(mat, tcol, *hor, tin, GPU_uniform(&mtex->colfac), mtex->blendtype, hor);
+ }
+ if (mtex->mapto & (WOMAP_ZENUP + WOMAP_ZENDOWN)) {
+ GPU_link(mat, "set_value_zero", &zenfac);
+ if (wo->skytype & WO_SKYREAL) {
+ if (mtex->mapto & WOMAP_ZENUP) {
+ if (mtex->mapto & WOMAP_ZENDOWN) {
+ GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac),
+ GPU_uniform(&mtex->zendownfac), &zenfac);
+ }
+ else {
+ GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&mtex->zenupfac),
+ GPU_uniform(&zero), &zenfac);
+ }
+ }
+ else if (mtex->mapto & WOMAP_ZENDOWN) {
+ GPU_link(mat, "world_zen_mapping", shi->view, GPU_uniform(&zero),
+ GPU_uniform(&mtex->zendownfac), &zenfac);
+ }
+ }
+ else {
+ if (mtex->mapto & WOMAP_ZENUP)
+ GPU_link(mat, "set_value", GPU_uniform(&mtex->zenupfac), &zenfac);
+ else if (mtex->mapto & WOMAP_ZENDOWN)
+ GPU_link(mat, "set_value", GPU_uniform(&mtex->zendownfac), &zenfac);
+ }
+ texture_rgb_blend(mat, tcol, *zen, tin, zenfac, mtex->blendtype, zen);
+ }
+ }
+ if (mtex->mapto & WOMAP_BLEND && wo->skytype & WO_SKYBLEND) {
+ if (rgbnor & TEX_RGB)
+ GPU_link(mat, "mtex_rgbtoint", trgb, &tin);
+ texture_value_blend(mat, GPU_uniform(&mtex->def_var), *blend, tin, GPU_uniform(&mtex->blendfac), mtex->blendtype, blend);
+ }
+ }
+ }
+}
+
+static void GPU_material_old_world(struct GPUMaterial *mat, struct World *wo)
+{
+ GPUShadeInput shi;
+ GPUShadeResult shr;
+ GPUNodeLink *hor, *zen, *ray, *blend;
+
+ shi.gpumat = mat;
+
+ for (int i = 0; i < MAX_MTEX; i++) {
+ if (wo->mtex[i] && wo->mtex[i]->tex) {
+ wo->skytype |= WO_SKYTEX;
+ break;
+ }
+ }
+ if ((wo->skytype & (WO_SKYBLEND + WO_SKYTEX)) == 0) {
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &shr.combined);
+ }
+ else {
+ GPU_link(mat, "set_rgb_zero", &shi.rgb);
+ GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &ray);
+ if (wo->skytype & WO_SKYPAPER)
+ GPU_link(mat, "world_paper_view", GPU_builtin(GPU_VIEW_POSITION), &shi.view);
+ else
+ GPU_link(mat, "shade_view", ray, &shi.view);
+ if (wo->skytype & WO_SKYBLEND) {
+ if (wo->skytype & WO_SKYPAPER) {
+ if (wo->skytype & WO_SKYREAL)
+ GPU_link(mat, "world_blend_paper_real", GPU_builtin(GPU_VIEW_POSITION), &blend);
+ else
+ GPU_link(mat, "world_blend_paper", GPU_builtin(GPU_VIEW_POSITION), &blend);
+ }
+ else {
+ if (wo->skytype & WO_SKYREAL)
+ GPU_link(mat, "world_blend_real", ray, &blend);
+ else
+ GPU_link(mat, "world_blend", ray, &blend);
+ }
+ }
+ else {
+ GPU_link(mat, "set_value_zero", &blend);
+ }
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->horr, GPU_DYNAMIC_HORIZON_COLOR, NULL), &hor);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&wo->zenr, GPU_DYNAMIC_ZENITH_COLOR, NULL), &zen);
+ do_world_tex(&shi, wo, &hor, &zen, &blend);
+ if (wo->skytype & WO_SKYBLEND)
+ GPU_link(mat, "node_mix_shader", blend, hor, zen, &shi.rgb);
+ else
+ GPU_link(mat, "set_rgb", hor, &shi.rgb);
+ GPU_link(mat, "set_rgb", shi.rgb, &shr.combined);
+ }
+ GPU_material_output_link(mat, shr.combined);
+}
+
GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
{
LinkData *link;
GPUMaterial *mat;
for (link = wo->gpumaterial.first; link; link = link->next)
- if (((GPUMaterial*)link->data)->scene == scene)
+ if (((GPUMaterial *)link->data)->scene == scene)
return link->data;
/* allocate material */
@@ -1737,7 +2068,7 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo)
if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes)
ntreeGPUMaterialNodes(wo->nodetree, mat, NODE_NEW_SHADING);
else {
- /* old fixed function world */
+ GPU_material_old_world(mat, wo);
}
if (GPU_material_do_color_management(mat))
@@ -1765,7 +2096,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open
LinkData *link;
for (link = ma->gpumaterial.first; link; link = link->next) {
- GPUMaterial *current_material = (GPUMaterial*)link->data;
+ GPUMaterial *current_material = (GPUMaterial *)link->data;
if (current_material->scene == scene &&
current_material->is_opensubdiv == use_opensubdiv)
{
@@ -1780,18 +2111,21 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open
mat->is_opensubdiv = use_opensubdiv;
/* render pipeline option */
- if (ma->mode & MA_TRANSP)
+ bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
+ if (!new_shading_nodes && (ma->mode & MA_TRANSP))
+ GPU_material_enable_alpha(mat);
+ else if (new_shading_nodes && ma->alpha < 1.0f)
GPU_material_enable_alpha(mat);
if (!(scene->gm.flag & GAME_GLSL_NO_NODES) && ma->nodetree && ma->use_nodes) {
/* create nodes */
- if (BKE_scene_use_new_shading_nodes(scene))
+ if (new_shading_nodes)
ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_NEW_SHADING);
else
ntreeGPUMaterialNodes(ma->nodetree, mat, NODE_OLD_SHADING);
}
else {
- if (BKE_scene_use_new_shading_nodes(scene)) {
+ if (new_shading_nodes) {
/* create simple diffuse material instead of nodes */
outlink = gpu_material_diffuse_bsdf(mat, ma);
}
@@ -1849,29 +2183,45 @@ static void gpu_lamp_calc_winmat(GPULamp *lamp)
wsize = lamp->la->shadow_frustum_size;
orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
}
- else {
+ else if (lamp->type == LA_SPOT) {
angle = saacos(lamp->spotsi);
temp = 0.5f * lamp->size * cosf(angle) / sinf(angle);
pixsize = lamp->d / temp;
wsize = pixsize * 0.5f * lamp->size;
- perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
+ /* compute shadows according to X and Y scaling factors */
+ perspective_m4(
+ lamp->winmat,
+ -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0],
+ -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1],
+ lamp->d, lamp->clipend);
}
}
void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
{
float mat[4][4];
+ float obmat_scale[3];
lamp->lay = lay;
lamp->hide = hide;
- copy_m4_m4(mat, obmat);
- normalize_m4(mat);
+ normalize_m4_m4_ex(mat, obmat, obmat_scale);
copy_v3_v3(lamp->vec, mat[2]);
copy_v3_v3(lamp->co, mat[3]);
copy_m4_m4(lamp->obmat, mat);
invert_m4_m4(lamp->imat, mat);
+
+ if (lamp->type == LA_SPOT) {
+ /* update spotlamp scale on X and Y axis */
+ lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2];
+ lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2];
+ }
+
+ if (GPU_lamp_has_shadow_buffer(lamp)) {
+ /* makeshadowbuf */
+ gpu_lamp_calc_winmat(lamp);
+ }
}
void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
@@ -1884,19 +2234,21 @@ void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float ener
lamp->col[2] = b;
}
-void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2)
+void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2,
+ float coeff_const, float coeff_lin, float coeff_quad)
{
lamp->dist = distance;
lamp->att1 = att1;
lamp->att2 = att2;
+ lamp->coeff_const = coeff_const;
+ lamp->coeff_lin = coeff_lin;
+ lamp->coeff_quad = coeff_quad;
}
void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend)
{
lamp->spotsi = cosf(spotsize * 0.5f);
lamp->spotbl = (1.0f - lamp->spotsi) * spotblend;
-
- gpu_lamp_calc_winmat(lamp);
}
static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp)
@@ -1931,6 +2283,9 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->falloff_type = la->falloff_type;
lamp->att1 = la->att1;
lamp->att2 = la->att2;
+ lamp->coeff_const = la->coeff_const;
+ lamp->coeff_lin = la->coeff_lin;
+ lamp->coeff_quad = la->coeff_quad;
lamp->curfalloff = la->curfalloff;
/* initshadowbuf */
@@ -1941,9 +2296,6 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
/* arbitrary correction for the fact we do no soft transition */
lamp->bias *= 0.25f;
-
- /* makeshadowbuf */
- gpu_lamp_calc_winmat(lamp);
}
static void gpu_lamp_shadow_free(GPULamp *lamp)
@@ -1977,7 +2329,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
LinkData *link;
for (link = ob->gpulamp.first; link; link = link->next) {
- lamp = (GPULamp*)link->data;
+ lamp = (GPULamp *)link->data;
if (lamp->par == par && lamp->scene == scene)
return link->data;
@@ -1992,7 +2344,9 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
la = ob->data;
gpu_lamp_from_blender(scene, ob, par, la, lamp);
- if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) {
+ if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) ||
+ (la->type == LA_SUN && (la->mode & LA_SHAD_RAY)))
+ {
/* opengl */
lamp->fb = GPU_framebuffer_create();
if (!lamp->fb) {
@@ -2183,49 +2537,61 @@ int GPU_lamp_shadow_buffer_type(GPULamp *lamp)
return lamp->la->shadowmap_type;
}
+int GPU_lamp_shadow_bind_code(GPULamp *lamp)
+{
+ return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1;
+}
+
+float *GPU_lamp_dynpersmat(GPULamp *lamp)
+{
+ return lamp->dynpersmat ? (float *)lamp->dynpersmat : NULL;
+}
+
int GPU_lamp_shadow_layer(GPULamp *lamp)
{
- if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER|LA_LAYER_SHADOW)))
+ if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW)))
return lamp->lay;
else
return -1;
}
-GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy)
+GPUNodeLink *GPU_lamp_get_data(
+ GPUMaterial *mat, GPULamp *lamp,
+ GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy)
{
GPUNodeLink *visifac;
- *col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
- *energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob);
- visifac = lamp_get_visibility(mat, lamp, lv, dist);
+ *r_col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
+ *r_energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob);
+ visifac = lamp_get_visibility(mat, lamp, r_lv, r_dist);
- shade_light_textures(mat, lamp, col);
+ shade_light_textures(mat, lamp, r_col);
if (GPU_lamp_has_shadow_buffer(lamp)) {
GPUNodeLink *vn, *inp;
GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &vn);
- GPU_link(mat, "shade_inp", vn, *lv, &inp);
+ GPU_link(mat, "shade_inp", vn, *r_lv, &inp);
mat->dynproperty |= DYN_LAMP_PERSMAT;
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
GPU_link(mat, "shadows_only_vsm",
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
+ GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias),
- GPU_uniform(lamp->shadow_color), inp, shadow);
+ GPU_uniform(lamp->shadow_color), inp, r_shadow);
}
else {
GPU_link(mat, "shadows_only",
GPU_builtin(GPU_VIEW_POSITION),
GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
- GPU_dynamic_uniform((float*)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
- GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, shadow);
+ GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
+ GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, r_shadow);
}
}
else {
- GPU_link(mat, "set_rgb_one", shadow);
+ GPU_link(mat, "set_rgb_one", r_shadow);
}
/* ensure shadow buffer and lamp textures will be updated */
@@ -2248,32 +2614,26 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
{ GPU_INVERSE_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_VIEWIMAT, GPU_DATA_16F },
{ GPU_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_MAT, GPU_DATA_16F },
{ GPU_INVERSE_OBJECT_MATRIX, GPU_DYNAMIC_OBJECT_IMAT, GPU_DATA_16F },
+ { GPU_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT, GPU_DATA_16F },
+ { GPU_INVERSE_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT, GPU_DATA_16F },
{ GPU_OBCOLOR, GPU_DYNAMIC_OBJECT_COLOR, GPU_DATA_4F },
{ GPU_AUTO_BUMPSCALE, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE, GPU_DATA_1F },
{ 0 }
};
GPUShaderExport *shader = NULL;
- GPUPass *pass;
GPUInput *input;
- GPUMaterial *mat;
- GPUInputUniform *uniform;
- GPUInputAttribute *attribute;
- GLint lastbindcode;
- int i, liblen, fraglen;
-
- if (!GPU_glsl_support())
- return NULL;
+ int liblen, fraglen;
- /* TODO(sergey): How to detemine whether we need OSD or not here? */
- mat = GPU_material_from_blender(scene, ma, false);
- pass = (mat)? mat->pass: NULL;
+ /* TODO(sergey): How to determine whether we need OSD or not here? */
+ GPUMaterial *mat = GPU_material_from_blender(scene, ma, false);
+ GPUPass *pass = (mat) ? mat->pass : NULL;
if (pass && pass->fragmentcode && pass->vertexcode) {
shader = MEM_callocN(sizeof(GPUShaderExport), "GPUShaderExport");
for (input = pass->inputs.first; input; input = input->next) {
- uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
+ GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
if (input->ima) {
/* image sampler uniform */
@@ -2290,61 +2650,62 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
switch (input->textype) {
- case GPU_SHADOW2D:
- uniform->type = GPU_DYNAMIC_SAMPLER_2DSHADOW;
- uniform->lamp = input->dynamicdata;
- break;
- case GPU_TEX2D:
- if (GPU_texture_opengl_bindcode(input->tex)) {
- uniform->type = GPU_DYNAMIC_SAMPLER_2DBUFFER;
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode);
- glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(input->tex));
- uniform->texsize = GPU_texture_opengl_width(input->tex) * GPU_texture_opengl_height(input->tex);
- uniform->texpixels = MEM_mallocN(uniform->texsize*4, "RGBApixels");
- glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, uniform->texpixels);
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
- }
- break;
-
- case GPU_NONE:
- case GPU_FLOAT:
- case GPU_VEC2:
- case GPU_VEC3:
- case GPU_VEC4:
- case GPU_MAT3:
- case GPU_MAT4:
- case GPU_ATTRIB:
- break;
+ case GPU_SHADOW2D:
+ uniform->type = GPU_DYNAMIC_SAMPLER_2DSHADOW;
+ uniform->lamp = input->dynamicdata;
+ break;
+ case GPU_TEX2D:
+ if (GPU_texture_opengl_bindcode(input->tex)) {
+ uniform->type = GPU_DYNAMIC_SAMPLER_2DBUFFER;
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(input->tex));
+ uniform->texsize = GPU_texture_width(input->tex) * GPU_texture_height(input->tex);
+ uniform->texpixels = MEM_mallocN(uniform->texsize * 4, "RGBApixels");
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, uniform->texpixels);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ break;
+
+ case GPU_NONE:
+ case GPU_TEXCUBE:
+ case GPU_FLOAT:
+ case GPU_VEC2:
+ case GPU_VEC3:
+ case GPU_VEC4:
+ case GPU_MAT3:
+ case GPU_MAT4:
+ case GPU_ATTRIB:
+ break;
}
}
else {
uniform->type = input->dynamictype;
BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
switch (input->type) {
- case GPU_FLOAT:
- uniform->datatype = GPU_DATA_1F;
- break;
- case GPU_VEC2:
- uniform->datatype = GPU_DATA_2F;
- break;
- case GPU_VEC3:
- uniform->datatype = GPU_DATA_3F;
- break;
- case GPU_VEC4:
- uniform->datatype = GPU_DATA_4F;
- break;
- case GPU_MAT3:
- uniform->datatype = GPU_DATA_9F;
- break;
- case GPU_MAT4:
- uniform->datatype = GPU_DATA_16F;
- break;
-
- case GPU_NONE:
- case GPU_TEX2D:
- case GPU_SHADOW2D:
- case GPU_ATTRIB:
- break;
+ case GPU_FLOAT:
+ uniform->datatype = GPU_DATA_1F;
+ break;
+ case GPU_VEC2:
+ uniform->datatype = GPU_DATA_2F;
+ break;
+ case GPU_VEC3:
+ uniform->datatype = GPU_DATA_3F;
+ break;
+ case GPU_VEC4:
+ uniform->datatype = GPU_DATA_4F;
+ break;
+ case GPU_MAT3:
+ uniform->datatype = GPU_DATA_9F;
+ break;
+ case GPU_MAT4:
+ uniform->datatype = GPU_DATA_16F;
+ break;
+
+ case GPU_NONE:
+ case GPU_TEX2D:
+ case GPU_TEXCUBE:
+ case GPU_SHADOW2D:
+ case GPU_ATTRIB:
+ break;
}
if (GPU_DYNAMIC_GROUP_FROM_TYPE(uniform->type) == GPU_DYNAMIC_GROUP_LAMP)
@@ -2358,9 +2719,9 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
}
/* process builtin uniform */
- for (i = 0; builtins[i].gputype; i++) {
+ for (int i = 0; builtins[i].gputype; i++) {
if (mat->builtins & builtins[i].gputype) {
- uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
+ GPUInputUniform *uniform = MEM_callocN(sizeof(GPUInputUniform), "GPUInputUniform");
uniform->type = builtins[i].dynamictype;
uniform->datatype = builtins[i].datatype;
BLI_strncpy(uniform->varname, GPU_builtin_name(builtins[i].gputype), sizeof(uniform->varname));
@@ -2379,27 +2740,27 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
shader->fragment[liblen + fraglen] = 0;
// export the attribute
- for (i = 0; i < mat->attribs.totlayer; i++) {
- attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute");
+ for (int i = 0; i < mat->attribs.totlayer; i++) {
+ GPUInputAttribute *attribute = MEM_callocN(sizeof(GPUInputAttribute), "GPUInputAttribute");
attribute->type = mat->attribs.layer[i].type;
attribute->number = mat->attribs.layer[i].glindex;
BLI_snprintf(attribute->varname, sizeof(attribute->varname), "att%d", mat->attribs.layer[i].attribid);
switch (attribute->type) {
- case CD_TANGENT:
- attribute->datatype = GPU_DATA_4F;
- break;
- case CD_MTFACE:
- attribute->datatype = GPU_DATA_2F;
- attribute->name = mat->attribs.layer[i].name;
- break;
- case CD_MCOL:
- attribute->datatype = GPU_DATA_4UB;
- attribute->name = mat->attribs.layer[i].name;
- break;
- case CD_ORCO:
- attribute->datatype = GPU_DATA_3F;
- break;
+ case CD_TANGENT:
+ attribute->datatype = GPU_DATA_4F;
+ break;
+ case CD_MTFACE:
+ attribute->datatype = GPU_DATA_2F;
+ attribute->name = mat->attribs.layer[i].name;
+ break;
+ case CD_MCOL:
+ attribute->datatype = GPU_DATA_4UB;
+ attribute->name = mat->attribs.layer[i].name;
+ break;
+ case CD_ORCO:
+ attribute->datatype = GPU_DATA_3F;
+ break;
}
if (attribute->datatype != GPU_DATA_NONE)
@@ -2417,12 +2778,10 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
void GPU_free_shader_export(GPUShaderExport *shader)
{
- GPUInputUniform *uniform;
-
if (shader == NULL)
return;
- for (uniform = shader->uniforms.first; uniform; uniform = uniform->next)
+ for (GPUInputUniform *uniform = shader->uniforms.first; uniform; uniform = uniform->next)
if (uniform->texpixels)
MEM_freeN(uniform->texpixels);
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 4978229a350..58582232cd5 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -69,6 +69,9 @@ typedef struct GPUQueryState {
static GPUQueryState g_query_state = {0};
+/**
+ * initialize and provide buffer for results
+ */
void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits)
{
g_query_state.select_is_active = true;
@@ -95,7 +98,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries), "gpu selection queries");
g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id), "gpu selection ids");
- glGenQueriesARB(g_query_state.num_of_queries, g_query_state.queries);
+ glGenQueries(g_query_state.num_of_queries, g_query_state.queries);
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
/* disable writing to the framebuffer */
@@ -133,6 +136,13 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
}
}
+/**
+ * loads a new selection id and ends previous query, if any. In second pass of selection it also returns
+ * if id has been hit on the first pass already.
+ * Thus we can skip drawing un-hit objects.
+ *
+ * \warning We rely on the order of object rendering on passes to be the same for this to work.
+ */
bool GPU_select_load_id(unsigned int id)
{
/* if no selection mode active, ignore */
@@ -144,17 +154,17 @@ bool GPU_select_load_id(unsigned int id)
}
else {
if (g_query_state.query_issued) {
- glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+ glEndQuery(GL_SAMPLES_PASSED);
}
/* if required, allocate extra queries */
if (g_query_state.active_query == g_query_state.num_of_queries) {
g_query_state.num_of_queries += ALLOC_QUERIES;
g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id));
- glGenQueriesARB(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ glGenQueries(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
}
- glBeginQueryARB(GL_SAMPLES_PASSED_ARB, g_query_state.queries[g_query_state.active_query]);
+ glBeginQuery(GL_SAMPLES_PASSED, g_query_state.queries[g_query_state.active_query]);
g_query_state.id[g_query_state.active_query] = id;
g_query_state.active_query++;
g_query_state.query_issued = true;
@@ -173,6 +183,11 @@ bool GPU_select_load_id(unsigned int id)
return true;
}
+/**
+ * Cleanup and flush selection results to buffer.
+ * Return number of hits and hits in buffer.
+ * if \a dopass is true, we will do a second pass with occlusion queries to get the closest hit.
+ */
unsigned int GPU_select_end(void)
{
unsigned int hits = 0;
@@ -184,12 +199,12 @@ unsigned int GPU_select_end(void)
int i;
if (g_query_state.query_issued) {
- glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+ glEndQuery(GL_SAMPLES_PASSED);
}
for (i = 0; i < g_query_state.active_query; i++) {
unsigned int result;
- glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result);
+ glGetQueryObjectuiv(g_query_state.queries[i], GL_QUERY_RESULT, &result);
if (result > 0) {
if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
int maxhits = g_query_state.bufsize / 4;
@@ -221,7 +236,7 @@ unsigned int GPU_select_end(void)
}
}
- glDeleteQueriesARB(g_query_state.num_of_queries, g_query_state.queries);
+ glDeleteQueries(g_query_state.num_of_queries, g_query_state.queries);
MEM_freeN(g_query_state.queries);
MEM_freeN(g_query_state.id);
glPopAttrib();
@@ -233,16 +248,15 @@ unsigned int GPU_select_end(void)
return hits;
}
-
-bool GPU_select_query_check_support(void)
-{
- return GLEW_ARB_occlusion_query;
-}
-
-
+/**
+ * has user activated?
+ */
bool GPU_select_query_check_active(void)
{
- return GLEW_ARB_occlusion_query &&
- ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) ||
- ((U.gpu_select_method == USER_SELECT_AUTO) && GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)));
+ return ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) ||
+ ((U.gpu_select_method == USER_SELECT_AUTO) &&
+ (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) ||
+ /* unsupported by nouveau, gallium 0.4, see: T47940 */
+ GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))));
+
}
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
new file mode 100644
index 00000000000..49f244083f9
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -0,0 +1,737 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_global.h"
+
+#include "GPU_compositing.h"
+#include "GPU_debug.h"
+#include "GPU_extensions.h"
+#include "GPU_glew.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+
+/* TODO(sergey): Find better default values for this constants. */
+#define MAX_DEFINE_LENGTH 1024
+#define MAX_EXT_DEFINE_LENGTH 1024
+
+/* Non-generated shaders */
+extern char datatoc_gpu_shader_smoke_vert_glsl[];
+extern char datatoc_gpu_shader_smoke_frag_glsl[];
+extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
+extern char datatoc_gpu_shader_vsm_store_frag_glsl[];
+extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[];
+extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[];
+extern char datatoc_gpu_shader_fx_vert_glsl[];
+extern char datatoc_gpu_shader_fx_ssao_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_vert_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[];
+extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[];
+extern char datatoc_gpu_shader_fx_depth_resolve_glsl[];
+extern char datatoc_gpu_shader_fx_lib_glsl[];
+
+static struct GPUShadersGlobal {
+ struct {
+ GPUShader *vsm_store;
+ GPUShader *sep_gaussian_blur;
+ GPUShader *smoke;
+ GPUShader *smoke_fire;
+ /* cache for shader fx. Those can exist in combinations so store them here */
+ GPUShader *fx_shaders[MAX_FX_SHADERS * 2];
+ } shaders;
+} GG = {{NULL}};
+
+/* GPUShader */
+
+struct GPUShader {
+ GLuint program; /* handle for full program (links shader stages below) */
+
+ GLuint vertex; /* handle for vertex shader */
+ GLuint geometry; /* handle for geometry shader */
+ GLuint fragment; /* handle for fragment shader */
+
+ int totattrib; /* total number of attributes */
+ int uniforms; /* required uniforms */
+
+ void *uniform_interface; /* cached uniform interface for shader. Data depends on shader */
+};
+
+static void shader_print_errors(const char *task, const char *log, const char **code, int totcode)
+{
+ int i;
+ int line = 1;
+
+ fprintf(stderr, "GPUShader: %s error:\n", task);
+
+ for (i = 0; i < totcode; i++) {
+ const char *c, *pos, *end = code[i] + strlen(code[i]);
+
+ if (G.debug & G_DEBUG) {
+ fprintf(stderr, "===== shader string %d ====\n", i + 1);
+
+ c = code[i];
+ while ((c < end) && (pos = strchr(c, '\n'))) {
+ fprintf(stderr, "%2d ", line);
+ fwrite(c, (pos + 1) - c, 1, stderr);
+ c = pos + 1;
+ line++;
+ }
+
+ fprintf(stderr, "%s", c);
+ }
+ }
+
+ fprintf(stderr, "%s\n", log);
+}
+
+static const char *gpu_shader_version(void)
+{
+ if (GLEW_VERSION_3_2) {
+ if (GLEW_ARB_compatibility) {
+ return "#version 150 compatibility\n";
+ /* highest version that is widely supported
+ * gives us native geometry shaders!
+ * use compatibility profile so we can continue using builtin shader input/output names
+ */
+ }
+ else {
+ return "#version 130\n";
+ /* latest version that is compatible with existing shaders */
+ }
+ }
+ else if (GLEW_VERSION_3_1) {
+ if (GLEW_ARB_compatibility) {
+ return "#version 140\n";
+ /* also need the ARB_compatibility extension, handled below */
+ }
+ else {
+ return "#version 130\n";
+ /* latest version that is compatible with existing shaders */
+ }
+ }
+ else if (GLEW_VERSION_3_0) {
+ return "#version 130\n";
+ /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available
+ * older features are deprecated but still available without compatibility extension or profile
+ */
+ }
+ else {
+ return "#version 120\n";
+ /* minimum supported */
+ }
+}
+
+
+static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader)
+{
+ /* enable extensions for features that are not part of our base GLSL version
+ * don't use an extension for something already available!
+ */
+
+ if (GLEW_ARB_texture_query_lod) {
+ /* a #version 400 feature, but we use #version 150 maximum so use extension */
+ strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n");
+ }
+
+ if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) {
+ strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n");
+ }
+
+ if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) {
+ strcat(defines, "#extension GL_ARB_compatibility: enable\n");
+ }
+
+ if (!GLEW_VERSION_3_1) {
+ if (GLEW_ARB_draw_instanced) {
+ strcat(defines, "#extension GL_ARB_draw_instanced: enable\n");
+ }
+
+ if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) {
+ strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n");
+ /* TODO: maybe require this? shaders become so much nicer */
+ }
+ }
+}
+
+static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH],
+ bool use_opensubdiv,
+ bool use_new_shading)
+{
+ /* some useful defines to detect GPU type */
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define GPU_ATI\n");
+ if (GLEW_VERSION_3_0) {
+ /* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */
+ strcat(defines, "#define CLIP_WORKAROUND\n");
+ }
+ }
+ else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY))
+ strcat(defines, "#define GPU_NVIDIA\n");
+ else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY))
+ strcat(defines, "#define GPU_INTEL\n");
+
+ if (GPU_bicubic_bump_support())
+ strcat(defines, "#define BUMP_BICUBIC\n");
+
+#ifdef WITH_OPENSUBDIV
+ /* TODO(sergey): Check whether we actually compiling shader for
+ * the OpenSubdiv mesh.
+ */
+ if (use_opensubdiv) {
+ strcat(defines, "#define USE_OPENSUBDIV\n");
+
+ /* TODO(sergey): not strictly speaking a define, but this is
+ * a global typedef which we don't have better place to define
+ * in yet.
+ */
+ strcat(defines, "struct VertexData {\n"
+ " vec4 position;\n"
+ " vec3 normal;\n"
+ " vec2 uv;"
+ "};\n");
+ }
+#else
+ UNUSED_VARS(use_opensubdiv);
+#endif
+
+ if (use_new_shading) {
+ strcat(defines, "#define USE_NEW_SHADING\n");
+ }
+
+ return;
+}
+
+GPUShader *GPU_shader_create(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ int input,
+ int output,
+ int number)
+{
+ return GPU_shader_create_ex(vertexcode,
+ fragcode,
+ geocode,
+ libcode,
+ defines,
+ input,
+ output,
+ number,
+ GPU_SHADER_FLAGS_NONE);
+}
+
+GPUShader *GPU_shader_create_ex(const char *vertexcode,
+ const char *fragcode,
+ const char *geocode,
+ const char *libcode,
+ const char *defines,
+ int input,
+ int output,
+ int number,
+ const int flags)
+{
+#ifdef WITH_OPENSUBDIV
+ /* TODO(sergey): used to add #version 150 to the geometry shader.
+ * Could safely be renamed to "use_geometry_code" since it's very
+ * likely any of geometry code will want to use GLSL 1.5.
+ */
+ bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0;
+#else
+ UNUSED_VARS(flags);
+ bool use_opensubdiv = false;
+#endif
+ GLint status;
+ GLchar log[5000];
+ GLsizei length = 0;
+ GPUShader *shader;
+ char standard_defines[MAX_DEFINE_LENGTH] = "";
+ char standard_extensions[MAX_EXT_DEFINE_LENGTH] = "";
+
+ if (geocode && !GPU_geometry_shader_support())
+ return NULL;
+
+ shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
+
+ if (vertexcode)
+ shader->vertex = glCreateShader(GL_VERTEX_SHADER);
+ if (fragcode)
+ shader->fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ if (geocode)
+ shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT);
+
+ shader->program = glCreateProgram();
+
+ if (!shader->program ||
+ (vertexcode && !shader->vertex) ||
+ (fragcode && !shader->fragment) ||
+ (geocode && !shader->geometry))
+ {
+ fprintf(stderr, "GPUShader, object creation failed.\n");
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+ gpu_shader_standard_defines(standard_defines,
+ use_opensubdiv,
+ (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0);
+ gpu_shader_standard_extensions(standard_extensions, geocode != NULL);
+
+ if (vertexcode) {
+ const char *source[5];
+ /* custom limit, may be too small, beware */
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (defines) source[num_source++] = defines;
+ source[num_source++] = vertexcode;
+
+ glAttachShader(shader->program, shader->vertex);
+ glShaderSource(shader->vertex, num_source, source, NULL);
+
+ glCompileShader(shader->vertex);
+ glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status);
+
+ if (!status) {
+ glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+ }
+
+ if (fragcode) {
+ const char *source[7];
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+#ifdef WITH_OPENSUBDIV
+ /* TODO(sergey): Move to fragment shader source code generation. */
+ if (use_opensubdiv) {
+ source[num_source++] =
+ "#ifdef USE_OPENSUBDIV\n"
+ "in block {\n"
+ " VertexData v;\n"
+ "} inpt;\n"
+ "#endif\n";
+ }
+#endif
+
+ if (defines) source[num_source++] = defines;
+ if (libcode) source[num_source++] = libcode;
+ source[num_source++] = fragcode;
+
+ glAttachShader(shader->program, shader->fragment);
+ glShaderSource(shader->fragment, num_source, source, NULL);
+
+ glCompileShader(shader->fragment);
+ glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status);
+
+ if (!status) {
+ glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+ }
+
+ if (geocode) {
+ const char *source[6];
+ int num_source = 0;
+
+ source[num_source++] = gpu_shader_version();
+ source[num_source++] = standard_extensions;
+ source[num_source++] = standard_defines;
+
+ if (defines) source[num_source++] = defines;
+ source[num_source++] = geocode;
+
+ glAttachShader(shader->program, shader->geometry);
+ glShaderSource(shader->geometry, num_source, source, NULL);
+
+ glCompileShader(shader->geometry);
+ glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status);
+
+ if (!status) {
+ glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log);
+ shader_print_errors("compile", log, source, num_source);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+ if (!use_opensubdiv) {
+ GPU_shader_geometry_stage_primitive_io(shader, input, output, number);
+ }
+ }
+
+#ifdef WITH_OPENSUBDIV
+ if (use_opensubdiv) {
+ glBindAttribLocation(shader->program, 0, "position");
+ glBindAttribLocation(shader->program, 1, "normal");
+ GPU_shader_geometry_stage_primitive_io(shader,
+ GL_LINES_ADJACENCY_EXT,
+ GL_TRIANGLE_STRIP,
+ 4);
+ }
+#endif
+
+ glLinkProgram(shader->program);
+ glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
+ if (!status) {
+ glGetProgramInfoLog(shader->program, sizeof(log), &length, log);
+ /* print attached shaders in pipeline order */
+ if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1);
+ if (geocode) shader_print_errors("linking", log, &geocode, 1);
+ if (libcode) shader_print_errors("linking", log, &libcode, 1);
+ if (fragcode) shader_print_errors("linking", log, &fragcode, 1);
+
+ GPU_shader_free(shader);
+ return NULL;
+ }
+
+#ifdef WITH_OPENSUBDIV
+ /* TODO(sergey): Find a better place for this. */
+ if (use_opensubdiv && GLEW_VERSION_4_1) {
+ glProgramUniform1i(shader->program,
+ glGetUniformLocation(shader->program, "FVarDataBuffer"),
+ 31); /* GL_TEXTURE31 */
+ }
+#endif
+
+ return shader;
+}
+
+void GPU_shader_bind(GPUShader *shader)
+{
+ GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind");
+ glUseProgram(shader->program);
+ GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind");
+}
+
+void GPU_shader_unbind(void)
+{
+ GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind");
+ glUseProgram(0);
+ GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind");
+}
+
+void GPU_shader_free(GPUShader *shader)
+{
+ if (shader->vertex)
+ glDeleteShader(shader->vertex);
+ if (shader->geometry)
+ glDeleteShader(shader->geometry);
+ if (shader->fragment)
+ glDeleteShader(shader->fragment);
+ if (shader->program)
+ glDeleteProgram(shader->program);
+
+ if (shader->uniform_interface)
+ MEM_freeN(shader->uniform_interface);
+
+ MEM_freeN(shader);
+}
+
+int GPU_shader_get_uniform(GPUShader *shader, const char *name)
+{
+ return glGetUniformLocation(shader->program, name);
+}
+
+void *GPU_shader_get_interface(GPUShader *shader)
+{
+ return shader->uniform_interface;
+}
+
+void GPU_shader_set_interface(GPUShader *shader, void *interface)
+{
+ shader->uniform_interface = interface;
+}
+
+void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value)
+{
+ if (location == -1 || value == NULL)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
+
+ if (length == 1) glUniform1fv(location, arraysize, value);
+ else if (length == 2) glUniform2fv(location, arraysize, value);
+ else if (length == 3) glUniform3fv(location, arraysize, value);
+ else if (length == 4) glUniform4fv(location, arraysize, value);
+ else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value);
+ else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value);
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
+}
+
+void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value)
+{
+ if (location == -1)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector");
+
+ if (length == 1) glUniform1iv(location, arraysize, value);
+ else if (length == 2) glUniform2iv(location, arraysize, value);
+ else if (length == 3) glUniform3iv(location, arraysize, value);
+ else if (length == 4) glUniform4iv(location, arraysize, value);
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector");
+}
+
+void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
+{
+ if (location == -1)
+ return;
+
+ GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value));
+}
+
+void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number)
+{
+ if (GPU_geometry_shader_support_via_extension()) {
+ /* geometry shaders must provide this info themselves for #version 150 and up */
+ glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input);
+ glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output);
+ glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number);
+ }
+}
+
+void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
+{
+ GLenum arbnumber;
+ int number = GPU_texture_bound_number(tex);
+ int bindcode = GPU_texture_opengl_bindcode(tex);
+ int target = GPU_texture_target(tex);
+
+ if (number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
+ }
+
+ if (number == -1)
+ return;
+
+ if (location == -1)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture");
+
+ arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
+
+ if (number != 0) glActiveTexture(arbnumber);
+ if (bindcode != 0)
+ glBindTexture(target, bindcode);
+ else
+ GPU_invalid_tex_bind(target);
+ glUniform1i(location, number);
+ glEnable(target);
+ if (number != 0) glActiveTexture(GL_TEXTURE0);
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture");
+}
+
+int GPU_shader_get_attribute(GPUShader *shader, const char *name)
+{
+ int index;
+
+ GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name));
+
+ return index;
+}
+
+GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
+{
+ GPUShader *retval = NULL;
+
+ switch (shader) {
+ case GPU_SHADER_VSM_STORE:
+ if (!GG.shaders.vsm_store)
+ GG.shaders.vsm_store = GPU_shader_create(
+ datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl,
+ NULL, NULL, NULL, 0, 0, 0);
+ retval = GG.shaders.vsm_store;
+ break;
+ case GPU_SHADER_SEP_GAUSSIAN_BLUR:
+ if (!GG.shaders.sep_gaussian_blur)
+ GG.shaders.sep_gaussian_blur = GPU_shader_create(
+ datatoc_gpu_shader_sep_gaussian_blur_vert_glsl,
+ datatoc_gpu_shader_sep_gaussian_blur_frag_glsl,
+ NULL, NULL, NULL, 0, 0, 0);
+ retval = GG.shaders.sep_gaussian_blur;
+ break;
+ case GPU_SHADER_SMOKE:
+ if (!GG.shaders.smoke)
+ GG.shaders.smoke = GPU_shader_create(
+ datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
+ NULL, NULL, NULL, 0, 0, 0);
+ retval = GG.shaders.smoke;
+ break;
+ case GPU_SHADER_SMOKE_FIRE:
+ if (!GG.shaders.smoke_fire)
+ GG.shaders.smoke_fire = GPU_shader_create(
+ datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
+ NULL, NULL, "#define USE_FIRE;\n", 0, 0, 0);
+ retval = GG.shaders.smoke_fire;
+ break;
+ }
+
+ if (retval == NULL)
+ printf("Unable to create a GPUShader for builtin shader: %u\n", shader);
+
+ return retval;
+}
+
+#define MAX_DEFINES 100
+
+GPUShader *GPU_shader_get_builtin_fx_shader(int effect, bool persp)
+{
+ int offset;
+ char defines[MAX_DEFINES] = "";
+ /* avoid shaders out of range */
+ if (effect >= MAX_FX_SHADERS)
+ return NULL;
+
+ offset = 2 * effect;
+
+ if (persp) {
+ offset += 1;
+ strcat(defines, "#define PERSP_MATRIX\n");
+ }
+
+ if (!GG.shaders.fx_shaders[offset]) {
+ GPUShader *shader = NULL;
+
+ switch (effect) {
+ case GPU_SHADER_FX_SSAO:
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE:
+ strcat(defines, "#define FIRST_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO:
+ strcat(defines, "#define SECOND_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE:
+ strcat(defines, "#define THIRD_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR:
+ strcat(defines, "#define FOURTH_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE:
+ strcat(defines, "#define FIFTH_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE:
+ strcat(defines, "#define FIRST_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO:
+ strcat(defines, "#define SECOND_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl,
+ defines, GL_POINTS, GL_TRIANGLE_STRIP, 4);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE:
+ strcat(defines, "#define THIRD_PASS\n");
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0);
+ break;
+
+ case GPU_SHADER_FX_DEPTH_RESOLVE:
+ shader = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0);
+ break;
+ }
+
+ GG.shaders.fx_shaders[offset] = shader;
+ GPU_fx_shader_init_interface(shader, effect);
+ }
+
+ return GG.shaders.fx_shaders[offset];
+}
+
+
+void GPU_shader_free_builtin_shaders(void)
+{
+ int i;
+
+ if (GG.shaders.vsm_store) {
+ GPU_shader_free(GG.shaders.vsm_store);
+ GG.shaders.vsm_store = NULL;
+ }
+
+ if (GG.shaders.sep_gaussian_blur) {
+ GPU_shader_free(GG.shaders.sep_gaussian_blur);
+ GG.shaders.sep_gaussian_blur = NULL;
+ }
+
+ if (GG.shaders.smoke) {
+ GPU_shader_free(GG.shaders.smoke);
+ GG.shaders.smoke = NULL;
+ }
+
+ if (GG.shaders.smoke_fire) {
+ GPU_shader_free(GG.shaders.smoke_fire);
+ GG.shaders.smoke_fire = NULL;
+ }
+
+ for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) {
+ if (GG.shaders.fx_shaders[i]) {
+ GPU_shader_free(GG.shaders.fx_shaders[i]);
+ GG.shaders.fx_shaders[i] = NULL;
+ }
+ }
+}
+
+
diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c
deleted file mode 100644
index 89d3c0f59df..00000000000
--- a/source/blender/gpu/intern/gpu_simple_shader.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2013 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Brecht Van Lommel.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/gpu/intern/gpu_simple_shader.c
- * \ingroup gpu
- *
- * GLSL shaders to replace fixed function OpenGL materials and lighting. These
- * are deprecated in newer OpenGL versions and missing in OpenGL ES 2.0. Also,
- * two sided lighting is no longer natively supported on NVidia cards which
- * results in slow software fallback.
- *
- * Todo:
- * - Replace glLight and glMaterial functions entirely with GLSL uniforms, to
- * make OpenGL ES 2.0 work.
- * - Replace glTexCoord and glColor with generic attributes.
- * - Optimize for case where fewer than 3 or 8 lights are used.
- * - Optimize for case where specular is not used.
- * - Optimize for case where no texture matrix is used.
- */
-
-#include "GPU_glew.h"
-
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "GPU_extensions.h"
-#include "GPU_simple_shader.h"
-
-/* State */
-
-// #define NUM_OPENGL_LIGHTS 8
-
-static struct {
- GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS];
- bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS];
-
- bool need_normals;
-
- int lights_enabled;
- int lights_directional;
-} GPU_MATERIAL_STATE;
-
-/* Init / exit */
-
-void GPU_simple_shaders_init(void)
-{
- memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE));
-}
-
-void GPU_simple_shaders_exit(void)
-{
- int i;
-
- for (i = 0; i < GPU_SHADER_OPTION_COMBINATIONS; i++)
- if (GPU_MATERIAL_STATE.cached_shaders[i])
- GPU_shader_free(GPU_MATERIAL_STATE.cached_shaders[i]);
-}
-
-/* Shader lookup / create */
-
-static bool solid_compatible_lighting(void)
-{
- int enabled = GPU_MATERIAL_STATE.lights_enabled;
- int directional = GPU_MATERIAL_STATE.lights_directional;
-
- /* more than 3 lights? */
- if (enabled >= (1 << 3))
- return false;
-
- /* all directional? */
- return ((directional & enabled) == enabled);
-}
-
-#if 0
-static int detect_options()
-{
- GLint two_sided;
- int options = 0;
-
- if (glIsEnabled(GL_TEXTURE_2D))
- options |= GPU_SHADER_TEXTURE_2D;
- if (glIsEnabled(GL_COLOR_MATERIAL))
- options |= GPU_SHADER_OVERRIDE_DIFFUSE;
-
- if (glIsEnabled(GL_LIGHTING))
- options |= GPU_SHADER_LIGHTING;
-
- glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &two_sided);
- if (two_sided == GL_TRUE)
- options |= GPU_SHADER_TWO_SIDED;
-
- return options;
-}
-#endif
-
-static GPUShader *gpu_simple_shader(int options)
-{
- /* glsl code */
- extern char datatoc_gpu_shader_simple_vert_glsl[];
- extern char datatoc_gpu_shader_simple_frag_glsl[];
- GPUShader *shader;
-
- /* detect if we can do faster lighting for solid draw mode */
- if (options & GPU_SHADER_LIGHTING)
- if (solid_compatible_lighting())
- options |= GPU_SHADER_SOLID_LIGHTING;
-
- /* cached shaders */
- shader = GPU_MATERIAL_STATE.cached_shaders[options];
-
- if (!shader && !GPU_MATERIAL_STATE.failed_shaders[options]) {
- /* create shader if it doesn't exist yet */
- char defines[64*GPU_SHADER_OPTIONS_NUM] = "";
-
- if (options & GPU_SHADER_OVERRIDE_DIFFUSE)
- strcat(defines, "#define USE_COLOR\n");
- if (options & GPU_SHADER_TWO_SIDED)
- strcat(defines, "#define USE_TWO_SIDED\n");
- if (options & GPU_SHADER_TEXTURE_2D)
- strcat(defines, "#define USE_TEXTURE\n");
-
- if (options & GPU_SHADER_SOLID_LIGHTING)
- strcat(defines, "#define USE_SOLID_LIGHTING\n");
- else if (options & GPU_SHADER_LIGHTING)
- strcat(defines, "#define USE_SCENE_LIGHTING\n");
-
- shader = GPU_shader_create(
- datatoc_gpu_shader_simple_vert_glsl,
- datatoc_gpu_shader_simple_frag_glsl,
- NULL,
- NULL,
- defines, 0, 0, 0);
-
- if (shader) {
- /* set texture map to first texture unit */
- if (options & GPU_SHADER_TEXTURE_2D)
- glUniform1i(GPU_shader_get_uniform(shader, "texture_map"), 0);
-
- GPU_MATERIAL_STATE.cached_shaders[options] = shader;
- }
- else
- GPU_MATERIAL_STATE.failed_shaders[options] = true;
- }
-
- return shader;
-}
-
-/* Bind / unbind */
-
-void GPU_simple_shader_bind(int options)
-{
- if (GPU_glsl_support()) {
- GPUShader *shader = gpu_simple_shader(options);
-
- if (shader)
- GPU_shader_bind(shader);
- }
- else {
- // XXX where does this fit, depends on ortho/persp?
-
- if (options & GPU_SHADER_LIGHTING)
- glEnable(GL_LIGHTING);
-
- if (options & GPU_SHADER_TWO_SIDED)
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
-
- if (options & GPU_SHADER_OVERRIDE_DIFFUSE) {
- glEnable(GL_COLOR_MATERIAL);
- glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
- }
-
- if (options & GPU_SHADER_TEXTURE_2D)
- glEnable(GL_TEXTURE_2D);
- }
-
- /* temporary hack, should be solved outside of this file */
- GPU_MATERIAL_STATE.need_normals = (options & GPU_SHADER_LIGHTING);
-}
-
-void GPU_simple_shader_unbind(void)
-{
- if (GPU_glsl_support()) {
- GPU_shader_unbind();
- }
- else {
- glDisable(GL_LIGHTING);
- glDisable(GL_COLOR_MATERIAL);
- glDisable(GL_TEXTURE_2D);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
- }
-}
-
-/* Material Colors */
-
-void GPU_simple_shader_colors(const float diffuse[3], const float specular[3],
- int shininess, float alpha)
-{
- float gl_diffuse[4], gl_specular[4];
-
- copy_v3_v3(gl_diffuse, diffuse);
- gl_diffuse[3] = alpha;
-
- copy_v3_v3(gl_specular, specular);
- gl_specular[3] = 1.0f;
-
- glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse);
- glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, gl_specular);
- glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
-}
-
-bool GPU_simple_shader_need_normals(void)
-{
- return GPU_MATERIAL_STATE.need_normals;
-}
-
-void GPU_simple_shader_light_set(int light_num, GPULightData *light)
-{
- int light_bit = (1 << light_num);
-
- GPU_MATERIAL_STATE.lights_enabled &= ~light_bit;
- GPU_MATERIAL_STATE.lights_directional &= ~light_bit;
-
- if (light) {
- glEnable(GL_LIGHT0+light_num);
-
- glLightfv(GL_LIGHT0+light_num, GL_POSITION, light->position);
- glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, light->diffuse);
- glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, light->specular);
-
- glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation);
- glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation);
- glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation);
-
- glLightfv(GL_LIGHT0+light_num, GL_SPOT_DIRECTION, light->spot_direction);
- glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, light->spot_cutoff);
- glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, light->spot_exponent);
-
- GPU_MATERIAL_STATE.lights_enabled |= light_bit;
- if (light->position[3] == 0.0f)
- GPU_MATERIAL_STATE.lights_directional |= light_bit;
- }
- else {
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- glLightfv(GL_LIGHT0+light_num, GL_POSITION, zero);
- glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, zero);
- glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, zero);
-
- glDisable(GL_LIGHT0+light_num);
- }
-}
-
-void GPU_simple_shader_light_set_viewer(bool local)
-{
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local)? GL_TRUE: GL_FALSE);
-}
-
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
new file mode 100644
index 00000000000..294b08f155a
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -0,0 +1,769 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_global.h"
+
+#include "GPU_debug.h"
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
+#include "GPU_glew.h"
+#include "GPU_texture.h"
+
+static struct GPUTextureGlobal {
+ GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
+ GPUTexture *invalid_tex_2D;
+ GPUTexture *invalid_tex_3D;
+} GG = {NULL, NULL, NULL};
+
+/* GPUTexture */
+
+struct GPUTexture {
+ int w, h; /* width/height */
+ int number; /* number for multitexture binding */
+ int refcount; /* reference count */
+ GLenum target; /* GL_TEXTURE_* */
+ GLenum target_base; /* same as target, (but no multisample) */
+ GLuint bindcode; /* opengl identifier for texture */
+ int fromblender; /* we got the texture from Blender */
+
+ GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */
+ int fb_attachment; /* slot the texture is attached to */
+ int depth; /* is a depth texture? if 3D how deep? */
+};
+
+static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels)
+{
+ unsigned char *pixels, *p;
+ const float *fp = fpixels;
+ const int len = 4 * length;
+
+ p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels");
+
+ for (int a = 0; a < len; a++, p++, fp++)
+ *p = FTOCHAR((*fp));
+
+ return pixels;
+}
+
+static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h)
+{
+ void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels");
+
+ if (target == GL_TEXTURE_1D)
+ glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels);
+ else
+ glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels);
+
+ MEM_freeN(pixels);
+}
+
+static GPUTexture *GPU_texture_create_nD(
+ int w, int h, int n, const float *fpixels, int depth,
+ GPUHDRType hdr_type, int components, int samples,
+ char err_out[256])
+{
+ GLenum type, format, internalformat;
+ void *pixels = NULL;
+
+ if (samples) {
+ CLAMP_MAX(samples, GPU_max_color_texture_samples());
+ }
+
+ GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ tex->w = w;
+ tex->h = h;
+ tex->number = -1;
+ tex->refcount = 1;
+ tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D);
+ tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D;
+ tex->depth = depth;
+ tex->fb_attachment = -1;
+
+ glGenTextures(1, &tex->bindcode);
+
+ if (!tex->bindcode) {
+ if (err_out) {
+ BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d",
+ (int)glGetError());
+ }
+ else {
+ fprintf(stderr, "GPUTexture: texture create failed: %d\n",
+ (int)glGetError());
+ }
+ GPU_texture_free(tex);
+ return NULL;
+ }
+
+ if (!GPU_full_non_power_of_two_support()) {
+ tex->w = power_of_2_max_i(tex->w);
+ tex->h = power_of_2_max_i(tex->h);
+ }
+
+ tex->number = 0;
+ glBindTexture(tex->target, tex->bindcode);
+
+ if (depth) {
+ type = GL_UNSIGNED_BYTE;
+ format = GL_DEPTH_COMPONENT;
+ internalformat = GL_DEPTH_COMPONENT;
+ }
+ else {
+ type = GL_FLOAT;
+
+ if (components == 4) {
+ format = GL_RGBA;
+ switch (hdr_type) {
+ case GPU_HDR_NONE:
+ internalformat = GL_RGBA8;
+ break;
+ /* the following formats rely on ARB_texture_float or OpenGL 3.0 */
+ case GPU_HDR_HALF_FLOAT:
+ internalformat = GL_RGBA16F_ARB;
+ break;
+ case GPU_HDR_FULL_FLOAT:
+ internalformat = GL_RGBA32F_ARB;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (components == 2) {
+ /* these formats rely on ARB_texture_rg or OpenGL 3.0 */
+ format = GL_RG;
+ switch (hdr_type) {
+ case GPU_HDR_NONE:
+ internalformat = GL_RG8;
+ break;
+ case GPU_HDR_HALF_FLOAT:
+ internalformat = GL_RG16F;
+ break;
+ case GPU_HDR_FULL_FLOAT:
+ internalformat = GL_RG32F;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (fpixels && hdr_type == GPU_HDR_NONE) {
+ type = GL_UNSIGNED_BYTE;
+ pixels = GPU_texture_convert_pixels(w * h, fpixels);
+ }
+ }
+
+ if (tex->target == GL_TEXTURE_1D) {
+ glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL);
+
+ if (fpixels) {
+ glTexSubImage1D(tex->target, 0, 0, w, format, type,
+ pixels ? pixels : fpixels);
+
+ if (tex->w > w) {
+ GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1);
+ }
+ }
+ }
+ else {
+ if (samples) {
+ glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true);
+ }
+ else {
+ glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0,
+ format, type, NULL);
+ }
+
+ if (fpixels) {
+ glTexSubImage2D(tex->target, 0, 0, 0, w, h,
+ format, type, pixels ? pixels : fpixels);
+
+ if (tex->w > w)
+ GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h);
+ if (tex->h > h)
+ GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h);
+ }
+ }
+
+ if (pixels)
+ MEM_freeN(pixels);
+
+ if (depth) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
+ }
+ else {
+ glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+
+ if (tex->target_base != GL_TEXTURE_1D) {
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ else
+ glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+
+ return tex;
+}
+
+
+GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels)
+{
+ GLenum type, format, internalformat;
+ void *pixels = NULL;
+
+ GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ tex->w = w;
+ tex->h = h;
+ tex->depth = depth;
+ tex->number = -1;
+ tex->refcount = 1;
+ tex->target = GL_TEXTURE_3D;
+ tex->target_base = GL_TEXTURE_3D;
+
+ glGenTextures(1, &tex->bindcode);
+
+ if (!tex->bindcode) {
+ fprintf(stderr, "GPUTexture: texture create failed: %d\n",
+ (int)glGetError());
+ GPU_texture_free(tex);
+ return NULL;
+ }
+
+ tex->number = 0;
+ glBindTexture(tex->target, tex->bindcode);
+
+ GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture");
+
+ type = GL_FLOAT;
+ if (channels == 4) {
+ format = GL_RGBA;
+ internalformat = GL_RGBA8;
+ }
+ else {
+ format = GL_RED;
+ internalformat = GL_INTENSITY8;
+ }
+
+ /* 3D textures are quite heavy, test if it's possible to create them first */
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+
+ bool rescale = false;
+ int r_width;
+
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+
+ while (r_width == 0) {
+ rescale = true;
+ tex->w /= 2;
+ tex->h /= 2;
+ tex->depth /= 2;
+ glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL);
+ glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width);
+ }
+
+ /* really unlikely to happen but keep this just in case */
+ tex->w = max_ii(tex->w, 1);
+ tex->h = max_ii(tex->h, 1);
+ tex->depth = max_ii(tex->depth, 1);
+
+#if 0
+ if (fpixels)
+ pixels = GPU_texture_convert_pixels(w*h*depth, fpixels);
+#endif
+
+ GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D");
+
+ /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it
+ * for gooseberry */
+ if (rescale && fpixels) {
+ /* FIXME: should these be floating point? */
+ const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth;
+ float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d");
+
+ GPU_print_error_debug("You need to scale a 3D texture, feel the pain!");
+
+ for (unsigned k = 0; k < tex->depth; k++) {
+ for (unsigned j = 0; j < tex->h; j++) {
+ for (unsigned i = 0; i < tex->w; i++) {
+ /* obviously doing nearest filtering here,
+ * it's going to be slow in any case, let's not make it worse */
+ float xb = i * xf;
+ float yb = j * yf;
+ float zb = k * zf;
+ unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j;
+ unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb);
+
+ if (channels == 4) {
+ tex3d[offset * 4] = fpixels[offset_orig * 4];
+ tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1];
+ tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2];
+ tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3];
+ }
+ else
+ tex3d[offset] = fpixels[offset_orig];
+ }
+ }
+ }
+
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d);
+
+ MEM_freeN(tex3d);
+ }
+ else {
+ if (fpixels) {
+ glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels);
+ GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D");
+ }
+ }
+
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+
+ if (pixels)
+ MEM_freeN(pixels);
+
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double time, int mipmap)
+{
+ int gputt;
+ /* this binds a texture, so that's why to restore it to 0 */
+ GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data);
+ GPU_update_image_time(ima, time);
+
+ if (textarget == GL_TEXTURE_2D)
+ gputt = TEXTARGET_TEXTURE_2D;
+ else
+ gputt = TEXTARGET_TEXTURE_CUBE_MAP;
+
+ if (ima->gputexture[gputt]) {
+ ima->gputexture[gputt]->bindcode = bindcode;
+ glBindTexture(textarget, 0);
+ return ima->gputexture[gputt];
+ }
+
+ GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ tex->bindcode = bindcode;
+ tex->number = -1;
+ tex->refcount = 1;
+ tex->target = textarget;
+ tex->target_base = GL_TEXTURE_2D;
+ tex->fromblender = 1;
+
+ ima->gputexture[gputt] = tex;
+
+ if (!glIsTexture(tex->bindcode)) {
+ GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
+ }
+ else {
+ GLint w, h, border;
+
+ GLenum gettarget;
+
+ if (textarget == GL_TEXTURE_2D)
+ gettarget = GL_TEXTURE_2D;
+ else
+ gettarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+
+ glBindTexture(textarget, tex->bindcode);
+ glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w);
+ glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h);
+ glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_BORDER, &border);
+
+ tex->w = w - border;
+ tex->h = h - border;
+ }
+
+ glBindTexture(textarget, 0);
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
+{
+ GPUTexture *tex = prv->gputexture[0];
+ GLuint bindcode = 0;
+
+ if (tex)
+ bindcode = tex->bindcode;
+
+ /* this binds a texture, so that's why we restore it to 0 */
+ if (bindcode == 0) {
+ GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, 0, NULL);
+ }
+ if (tex) {
+ tex->bindcode = bindcode;
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return tex;
+ }
+
+ tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
+ tex->bindcode = bindcode;
+ tex->number = -1;
+ tex->refcount = 1;
+ tex->target = GL_TEXTURE_2D;
+ tex->target_base = GL_TEXTURE_2D;
+
+ prv->gputexture[0] = tex;
+
+ if (!glIsTexture(tex->bindcode)) {
+ GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded");
+ }
+ else {
+ GLint w, h;
+
+ glBindTexture(GL_TEXTURE_2D, tex->bindcode);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
+
+ tex->w = w;
+ tex->h = h;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ return tex;
+
+}
+
+GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out);
+
+ if (tex)
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out);
+
+ if (tex)
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+GPUTexture *GPU_texture_create_2D_multisample(
+ int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out);
+
+ if (tex)
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out);
+
+ if (tex)
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out);
+
+ if (tex)
+ GPU_texture_unbind(tex);
+
+ return tex;
+}
+
+/**
+ * A shadow map for VSM needs two components (depth and depth^2)
+ */
+GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out);
+
+ if (tex) {
+ /* Now we tweak some of the settings */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ GPU_texture_unbind(tex);
+ }
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
+
+ if (tex) {
+ /* Now we tweak some of the settings */
+ if (repeat) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ GPU_texture_unbind(tex);
+ }
+
+ return tex;
+}
+
+GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256])
+{
+ GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out);
+
+ if (tex) {
+ /* Now we tweak some of the settings */
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ GPU_texture_unbind(tex);
+ }
+
+ return tex;
+}
+
+void GPU_invalid_tex_init(void)
+{
+ const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f};
+ GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
+ GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
+ GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
+}
+
+void GPU_invalid_tex_bind(int mode)
+{
+ switch (mode) {
+ case GL_TEXTURE_1D:
+ glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode);
+ break;
+ case GL_TEXTURE_2D:
+ glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode);
+ break;
+ case GL_TEXTURE_3D:
+ glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode);
+ break;
+ }
+}
+
+void GPU_invalid_tex_free(void)
+{
+ if (GG.invalid_tex_1D)
+ GPU_texture_free(GG.invalid_tex_1D);
+ if (GG.invalid_tex_2D)
+ GPU_texture_free(GG.invalid_tex_2D);
+ if (GG.invalid_tex_3D)
+ GPU_texture_free(GG.invalid_tex_3D);
+}
+
+
+void GPU_texture_bind(GPUTexture *tex, int number)
+{
+ if (number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
+ }
+
+ if ((G.debug & G_DEBUG)) {
+ if (tex->fb && GPU_framebuffer_bound(tex->fb)) {
+ fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n");
+ }
+ }
+
+ if (number < 0)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind");
+
+ GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number);
+ if (number != 0) glActiveTexture(arbnumber);
+ if (tex->bindcode != 0) {
+ glBindTexture(tex->target, tex->bindcode);
+ }
+ else
+ GPU_invalid_tex_bind(tex->target);
+ glEnable(tex->target);
+ if (number != 0) glActiveTexture(GL_TEXTURE0);
+
+ tex->number = number;
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind");
+}
+
+void GPU_texture_unbind(GPUTexture *tex)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
+ }
+
+ if (tex->number == -1)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
+
+ GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
+ if (tex->number != 0) glActiveTexture(arbnumber);
+ glBindTexture(tex->target, 0);
+ glDisable(tex->target);
+ glBindTexture(tex->target_base, 0);
+ glDisable(tex->target_base);
+ if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
+
+ tex->number = -1;
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
+}
+
+int GPU_texture_bound_number(GPUTexture *tex)
+{
+ return tex->number;
+}
+
+void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter)
+{
+ if (tex->number >= GPU_max_textures()) {
+ fprintf(stderr, "Not enough texture slots.\n");
+ return;
+ }
+
+ if (tex->number == -1)
+ return;
+
+ GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind");
+
+ GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number);
+ if (tex->number != 0) glActiveTexture(arbnumber);
+
+ if (tex->depth) {
+ if (compare)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ }
+
+ if (use_filter) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ }
+ if (tex->number != 0) glActiveTexture(GL_TEXTURE0);
+
+ GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind");
+}
+
+void GPU_texture_free(GPUTexture *tex)
+{
+ tex->refcount--;
+
+ if (tex->refcount < 0)
+ fprintf(stderr, "GPUTexture: negative refcount\n");
+
+ if (tex->refcount == 0) {
+ if (tex->fb)
+ GPU_framebuffer_texture_detach(tex);
+ if (tex->bindcode && !tex->fromblender)
+ glDeleteTextures(1, &tex->bindcode);
+
+ MEM_freeN(tex);
+ }
+}
+
+void GPU_texture_ref(GPUTexture *tex)
+{
+ tex->refcount++;
+}
+
+int GPU_texture_target(const GPUTexture *tex)
+{
+ return tex->target;
+}
+
+int GPU_texture_width(const GPUTexture *tex)
+{
+ return tex->w;
+}
+
+int GPU_texture_height(const GPUTexture *tex)
+{
+ return tex->h;
+}
+
+int GPU_texture_depth(const GPUTexture *tex)
+{
+ return tex->depth;
+}
+
+int GPU_texture_opengl_bindcode(const GPUTexture *tex)
+{
+ return tex->bindcode;
+}
+
+GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex)
+{
+ return tex->fb;
+}
+
+int GPU_texture_framebuffer_attachment(GPUTexture *tex)
+{
+ return tex->fb_attachment;
+}
+
+void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment)
+{
+ tex->fb = fb;
+ tex->fb_attachment = attachment;
+}
+
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
deleted file mode 100644
index a94c823f408..00000000000
--- a/source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-!!ARBfp1.0
-PARAM dx = program.local[0];
-PARAM darkness = program.local[1];
-PARAM render = program.local[2];
-PARAM f = {1.442695041, 1.442695041, 1.442695041, 1.442695041};
-TEMP temp, shadow, flame, spec, value;
-TEX temp, fragment.texcoord[0], texture[0], 3D;
-TEX shadow, fragment.texcoord[0], texture[1], 3D;
-TEX flame, fragment.texcoord[0], texture[2], 3D;
-TEX spec, flame.r, texture[3], 1D;
-# unpremultiply volume texture
-RCP value.r, temp.a;
-MUL temp.r, temp.r, value.r;
-MUL temp.g, temp.g, value.r;
-MUL temp.b, temp.b, value.r;
-# calculate shading factor from density
-MUL value.r, temp.a, darkness.a;
-MUL value.r, value.r, dx.r;
-MUL value.r, value.r, f.r;
-EX2 value.r, -value.r;
-# alpha
-SUB temp.a, 1.0, value.r;
-# shade colors
-MUL temp.r, temp.r, shadow.r;
-MUL temp.g, temp.g, shadow.r;
-MUL temp.b, temp.b, shadow.r;
-MUL temp.r, temp.r, value.r;
-MUL temp.g, temp.g, value.r;
-MUL temp.b, temp.b, value.r;
-# for now this just replace smoke shading if rendering fire
-CMP result.color, render.r, temp, spec;
-END
diff --git a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
deleted file mode 100644
index 04b171d24bd..00000000000
--- a/source/blender/gpu/shaders/gpu_program_smoke_frag.glsl
+++ /dev/null
@@ -1,27 +0,0 @@
-!!ARBfp1.0
-PARAM dx = program.local[0];
-PARAM darkness = program.local[1];
-PARAM render = program.local[2];
-PARAM f = {1.442695041, 1.442695041, 1.442695041, 0.01};
-TEMP temp, shadow, flame, spec, value;
-TEX temp, fragment.texcoord[0], texture[0], 3D;
-TEX shadow, fragment.texcoord[0], texture[1], 3D;
-TEX flame, fragment.texcoord[0], texture[2], 3D;
-TEX spec, flame.r, texture[3], 1D;
-# calculate shading factor from density
-MUL value.r, temp.a, darkness.a;
-MUL value.r, value.r, dx.r;
-MUL value.r, value.r, f.r;
-EX2 temp, -value.r;
-# alpha
-SUB temp.a, 1.0, temp.r;
-# shade colors
-MUL temp.r, temp.r, shadow.r;
-MUL temp.g, temp.g, shadow.r;
-MUL temp.b, temp.b, shadow.r;
-MUL temp.r, temp.r, darkness.r;
-MUL temp.g, temp.g, darkness.g;
-MUL temp.b, temp.b, darkness.b;
-# for now this just replace smoke shading if rendering fire
-CMP result.color, render.r, temp, spec;
-END
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
new file mode 100644
index 00000000000..c7b29ee5707
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl
@@ -0,0 +1,273 @@
+
+/* Options:
+ *
+ * USE_COLOR: use glColor for diffuse colors
+ * USE_TEXTURE: use texture for diffuse colors
+ * USE_SCENE_LIGHTING: use lights (up to 8)
+ * USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode
+ * USE_TWO_SIDED: flip normal towards viewer
+ * NO_SPECULAR: use specular component
+ */
+
+#define NUM_SOLID_LIGHTS 3
+#define NUM_SCENE_LIGHTS 8
+
+/* Keep these in sync with GPU_basic_shader.h */
+#define STIPPLE_HALFTONE 0
+#define STIPPLE_QUARTTONE 1
+#define STIPPLE_CHECKER_8PX 2
+#define STIPPLE_HEXAGON 3
+#define STIPPLE_DIAG_STRIPES 4
+#define STIPPLE_DIAG_STRIPES_SWAP 5
+#define STIPPLE_S3D_INTERLACE_ROW 6
+#define STIPPLE_S3D_INTERLACE_ROW_SWAP 7
+#define STIPPLE_S3D_INTERLACE_COLUMN 8
+#define STIPPLE_S3D_INTERLACE_COLUMN_SWAP 9
+#define STIPPLE_S3D_INTERLACE_CHECKERBOARD 10
+#define STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP 11
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+varying vec3 varying_normal;
+
+#ifndef USE_SOLID_LIGHTING
+varying vec3 varying_position;
+#endif
+#endif
+
+#ifdef USE_COLOR
+varying vec4 varying_vertex_color;
+#endif
+
+#ifdef USE_TEXTURE
+varying vec2 varying_texture_coord;
+uniform sampler2D texture_map;
+#endif
+
+#ifdef USE_STIPPLE
+uniform int stipple_id;
+#if defined(DRAW_LINE)
+varying in float t;
+uniform int stipple_pattern;
+#endif
+#endif
+
+void main()
+{
+#if defined(USE_STIPPLE)
+#if defined(DRAW_LINE)
+ /* GLSL 1.3 */
+ if (!bool((1 << int(mod(t, 16))) & stipple_pattern))
+ discard;
+#else
+ /* We have to use mod function and integer casting.
+ * This can be optimized further with the bitwise operations
+ * when GLSL 1.3 is supported. */
+ if (stipple_id == STIPPLE_HALFTONE ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD ||
+ stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ {
+ int result = int(mod(gl_FragCoord.x + gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_CHECKERBOARD_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_QUARTTONE) {
+ int mody = int(mod(gl_FragCoord.y, 4));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody == 0) {
+ if (modx != 2)
+ discard;
+ }
+ else if (mody == 2){
+ if (modx != 0)
+ discard;
+ }
+ else
+ discard;
+ }
+ else if (stipple_id == STIPPLE_CHECKER_8PX) {
+ int result = int(mod(int(gl_FragCoord.x)/8 + int(gl_FragCoord.y)/8, 2));
+ if (result != 0)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if ((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_DIAG_STRIPES_SWAP) {
+ int mody = int(mod(gl_FragCoord.y, 16));
+ int modx = int(mod(gl_FragCoord.x, 16));
+ if (!((16 - modx > mody && mody > 8 - modx) || mody > 24 - modx))
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_ROW || stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP) {
+ int result = int(mod(gl_FragCoord.y, 2));
+ bool dis = result == 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_ROW_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN || stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP) {
+ int result = int(mod(gl_FragCoord.x, 2));
+ bool dis = result != 0;
+ if (stipple_id == STIPPLE_S3D_INTERLACE_COLUMN_SWAP)
+ dis = !dis;
+ if (dis)
+ discard;
+ }
+ else if (stipple_id == STIPPLE_HEXAGON) {
+ int mody = int(mod(gl_FragCoord.y, 2));
+ int modx = int(mod(gl_FragCoord.x, 4));
+ if (mody != 0) {
+ if (modx != 1)
+ discard;
+ }
+ else {
+ if (modx != 3)
+ discard;
+ }
+ }
+#endif /* !DRAW_LINE */
+#endif /* USE_STIPPLE */
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+ /* compute normal */
+ vec3 N = normalize(varying_normal);
+
+#ifdef USE_TWO_SIDED
+ if (!gl_FrontFacing)
+ N = -N;
+#endif
+
+ /* compute diffuse and specular lighting */
+ vec3 L_diffuse = vec3(0.0);
+#ifndef NO_SPECULAR
+ vec3 L_specular = vec3(0.0);
+#endif
+
+#ifdef USE_SOLID_LIGHTING
+ /* assume 3 directional lights */
+ for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
+ vec3 light_direction = gl_LightSource[i].position.xyz;
+
+ /* diffuse light */
+ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ float diffuse_bsdf = max(dot(N, light_direction), 0.0);
+ L_diffuse += light_diffuse*diffuse_bsdf;
+
+#ifndef NO_SPECULAR
+ /* specular light */
+ vec3 light_specular = gl_LightSource[i].specular.rgb;
+ vec3 H = gl_LightSource[i].halfVector.xyz;
+
+ float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
+ L_specular += light_specular*specular_bsdf;
+#endif
+ }
+#else
+ /* all 8 lights, makes no assumptions, potentially slow */
+
+#ifndef NO_SPECULAR
+ /* view vector computation, depends on orthographics or perspective */
+ vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position): vec3(0.0, 0.0, -1.0);
+#endif
+
+ for (int i = 0; i < NUM_SCENE_LIGHTS; i++) {
+ /* todo: this is a slow check for disabled lights */
+ if (gl_LightSource[i].specular.a == 0.0)
+ continue;
+
+ float intensity = 1.0;
+ vec3 light_direction;
+
+ if (gl_LightSource[i].position.w == 0.0) {
+ /* directional light */
+ light_direction = gl_LightSource[i].position.xyz;
+ }
+ else {
+ /* point light */
+ vec3 d = gl_LightSource[i].position.xyz - varying_position;
+ light_direction = normalize(d);
+
+ /* spot light cone */
+ if (gl_LightSource[i].spotCutoff < 90.0) {
+ float cosine = max(dot(light_direction, -gl_LightSource[i].spotDirection), 0.0);
+ intensity = pow(cosine, gl_LightSource[i].spotExponent);
+ intensity *= step(gl_LightSource[i].spotCosCutoff, cosine);
+ }
+
+ /* falloff */
+ float distance = length(d);
+
+ intensity /= gl_LightSource[i].constantAttenuation +
+ gl_LightSource[i].linearAttenuation * distance +
+ gl_LightSource[i].quadraticAttenuation * distance * distance;
+ }
+
+ /* diffuse light */
+ vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+ float diffuse_bsdf = max(dot(N, light_direction), 0.0);
+ L_diffuse += light_diffuse*diffuse_bsdf*intensity;
+
+#ifndef NO_SPECULAR
+ /* specular light */
+ vec3 light_specular = gl_LightSource[i].specular.rgb;
+ vec3 H = normalize(light_direction - V);
+
+ float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
+ L_specular += light_specular*specular_bsdf*intensity;
+#endif
+ }
+#endif
+
+ /* compute diffuse color, possibly from texture or vertex colors */
+ float alpha;
+
+#if defined(USE_TEXTURE) && defined(USE_COLOR)
+ vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+
+ L_diffuse *= texture_color.rgb * varying_vertex_color.rgb;
+ alpha = texture_color.a * varying_vertex_color.a;
+#elif defined(USE_TEXTURE)
+ vec4 texture_color = texture2D(texture_map, varying_texture_coord);
+
+ L_diffuse *= texture_color.rgb;
+ alpha = texture_color.a;
+#elif defined(USE_COLOR)
+ L_diffuse *= varying_vertex_color.rgb;
+ alpha = varying_vertex_color.a;
+#else
+ L_diffuse *= gl_FrontMaterial.diffuse.rgb;
+ alpha = gl_FrontMaterial.diffuse.a;
+#endif
+
+ /* sum lighting */
+ vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
+
+#ifndef NO_SPECULAR
+ L += L_specular*gl_FrontMaterial.specular.rgb;
+#endif
+
+ /* write out fragment color */
+ gl_FragColor = vec4(L, alpha);
+#else
+
+ /* no lighting */
+#if defined(USE_TEXTURE) && defined(USE_COLOR)
+ gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color;
+#elif defined(USE_TEXTURE)
+ gl_FragColor = texture2D(texture_map, varying_texture_coord);
+#elif defined(USE_COLOR)
+ gl_FragColor = varying_vertex_color;
+#else
+ gl_FragColor = gl_FrontMaterial.diffuse;
+#endif
+
+#endif
+}
+
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
new file mode 100644
index 00000000000..ffd747ab1eb
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_basic_geom.glsl
@@ -0,0 +1,100 @@
+/*
+* Used the implementation of wide lines of Timo Suoranta (http://neure.dy.fi/wideline.html)
+*/
+
+#define PASSTHROUGH 0
+
+layout(lines) in;
+
+#if defined(DRAW_LINE)
+
+#if PASSTHROUGH
+layout(line_strip, max_vertices = 10) out;
+#else
+layout(triangle_strip, max_vertices = 6) out;
+#endif
+
+varying out float t;
+varying in vec4 varying_vertex_color_line[];
+varying out vec4 varying_vertex_color;
+
+uniform ivec4 viewport;
+uniform float line_width;
+uniform int stipple_factor;
+
+void main(void)
+{
+ vec2 window_size = viewport.zw;
+ vec4 start = gl_in[0].gl_Position;
+ vec4 end = gl_in[1].gl_Position;
+#if PASSTHROUGH
+ gl_Position = start; EmitVertex();
+ gl_Position = end; EmitVertex();
+ EndPrimitive();
+ return;
+#endif
+
+/* t = 0 t = ~(len(end - start) + 2*line_width)
+ * A-------------------------------------B
+ * | | | |
+ * | side | |
+ * | | | |
+ * |--axis--*start--------------*end-----|
+ * | | | |
+ * | | | |
+ * | | | |
+ * D-------------------------------------C
+ */
+
+ /* Clip the line before homogenization.
+ * Compute line start and end distances to nearplane in clipspace
+ * Distances are t0 = dot(start, plane) and t1 = dot(end, plane)
+ */
+ float t0 = start.z + start.w;
+ float t1 = end.z + end.w;
+ if(t0 < 0.0) {
+ if(t1 < 0.0) {
+ return;
+ }
+ start = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+ if(t1 < 0.0) {
+ end = mix(start, end, (0 - t0) / (t1 - t0));
+ }
+
+ /* Compute line axis and side vector in screen space */
+ vec2 startInNDC = start.xy / start.w; /* clip to NDC: homogenize and drop z */
+ vec2 endInNDC = end.xy / end.w;
+ vec2 lineInNDC = endInNDC - startInNDC;
+ vec2 lineInScreen = lineInNDC * window_size; /* ndc to screen (direction vector) */
+
+ vec2 axisInScreen = normalize(lineInScreen);
+ vec2 sideInScreen = vec2(-axisInScreen.y, axisInScreen.x); /* rotate */
+ vec2 axisInNDC = axisInScreen / window_size; /* screen to NDC */
+ vec2 sideInNDC = sideInScreen / window_size;
+ vec4 axis = vec4(axisInNDC, 0.0, 0.0) * line_width; /* NDC to clip (delta vector) */
+ vec4 side = vec4(sideInNDC, 0.0, 0.0) * line_width;
+
+ vec4 A = (start + (side - axis) * start.w);
+ vec4 B = (end + (side + axis) * end.w);
+ vec4 C = (end - (side - axis) * end.w);
+ vec4 D = (start - (side + axis) * start.w);
+
+ /* There is no relation between lines yet */
+ /* TODO Pass here t0 to make continuous pattern. */
+ t0 = 0;
+ t1 = (length(lineInScreen) + 2*line_width)/ (2*line_width * stipple_factor);
+
+ gl_Position = A; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = D; t = t0; varying_vertex_color = varying_vertex_color_line[0]; EmitVertex();
+ gl_Position = B; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ gl_Position = C; t = t1; varying_vertex_color = varying_vertex_color_line[1]; EmitVertex();
+ EndPrimitive();
+}
+
+#else
+void main(void)
+{
+
+}
+#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
new file mode 100644
index 00000000000..04900001998
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl
@@ -0,0 +1,62 @@
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+varying vec3 varying_normal;
+
+#ifndef USE_SOLID_LIGHTING
+varying vec3 varying_position;
+#endif
+#endif
+
+#ifdef USE_COLOR
+#ifdef DRAW_LINE
+varying vec4 varying_vertex_color_line;
+#else
+varying vec4 varying_vertex_color;
+#endif
+#endif
+
+#ifdef USE_TEXTURE
+varying vec2 varying_texture_coord;
+#endif
+
+#ifdef CLIP_WORKAROUND
+varying float gl_ClipDistance[6];
+#endif
+
+void main()
+{
+ vec4 co = gl_ModelViewMatrix * gl_Vertex;
+
+#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
+ varying_normal = normalize(gl_NormalMatrix * gl_Normal);
+
+#ifndef USE_SOLID_LIGHTING
+ varying_position = co.xyz;
+#endif
+#endif
+
+ gl_Position = gl_ProjectionMatrix * co;
+
+#ifdef CLIP_WORKAROUND
+ int i;
+ for(i = 0; i < 6; i++)
+ gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
+#elif !defined(GPU_ATI)
+ // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
+ // graphic cards, while on ATI it can cause a software fallback.
+ gl_ClipVertex = co;
+#endif
+
+#ifdef USE_COLOR
+#ifdef DRAW_LINE
+ varying_vertex_color_line = gl_Color;
+#else
+ varying_vertex_color = gl_Color;
+#endif
+#endif
+
+#ifdef USE_TEXTURE
+ varying_texture_coord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st;
+#endif
+}
+
diff --git a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
index 7918122a681..4c650e7695f 100644
--- a/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_fx_dof_hq_geo.glsl
@@ -5,23 +5,39 @@ uniform vec2 layerselection;
uniform sampler2D cocbuffer;
-/* initial uv coordinate */
-varying in vec2 uvcoord[1];
-varying out vec2 particlecoord;
-varying out vec4 color;
+#if __VERSION__ >= 150
+ layout(points) in;
+ layout(triangle_strip, max_vertices = 4) out;
+
+ #define POS gl_in[0].gl_Position
+#else
+ /* use the EXT_geometry_shader4 way */
+ #define POS gl_PositionIn[0]
+#endif
+/* initial uv coordinate */
+#if __VERSION__ < 130
+ varying in vec2 uvcoord[];
+ varying out vec2 particlecoord;
+ varying out vec4 color;
+ #define textureLod texture2DLod
+#else
+ in vec2 uvcoord[];
+ out vec2 particlecoord;
+ out vec4 color;
+#endif
#define M_PI 3.1415926535897932384626433832795
-void main(void)
+void main()
{
- vec4 coc = texture2DLod(cocbuffer, uvcoord[0], 0.0);
+ vec4 coc = textureLod(cocbuffer, uvcoord[0], 0.0);
float offset_val = dot(coc.rg, layerselection);
if (offset_val < 1.0)
return;
- vec4 colortex = texture2DLod(colorbuffer, uvcoord[0], 0.0);
+ vec4 colortex = textureLod(colorbuffer, uvcoord[0], 0.0);
/* find the area the pixel will cover and divide the color by it */
float alpha = 1.0 / (offset_val * offset_val * M_PI);
@@ -30,19 +46,19 @@ void main(void)
vec2 offset_far = vec2(offset_val * 0.5) / vec2(rendertargetdim.x, rendertargetdim.y);
- gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
+ gl_Position = POS + vec4(-offset_far.x, -offset_far.y, 0.0, 0.0);
color = colortex;
particlecoord = vec2(-1.0, -1.0);
EmitVertex();
- gl_Position = gl_PositionIn[0] + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
+ gl_Position = POS + vec4(-offset_far.x, offset_far.y, 0.0, 0.0);
particlecoord = vec2(-1.0, 1.0);
color = colortex;
EmitVertex();
- gl_Position = gl_PositionIn[0] + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
+ gl_Position = POS + vec4(offset_far.x, -offset_far.y, 0.0, 0.0);
particlecoord = vec2(1.0, -1.0);
color = colortex;
EmitVertex();
- gl_Position = gl_PositionIn[0] + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
+ gl_Position = POS + vec4(offset_far.x, offset_far.y, 0.0, 0.0);
particlecoord = vec2(1.0, 1.0);
color = colortex;
EmitVertex();
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index a0ae96a1f72..16fba0dd055 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -1,12 +1,18 @@
uniform int PrimitiveIdBase;
uniform int osd_active_uv_offset;
-varying vec3 varnormal;
-varying vec3 varposition;
+#if __VERSION__ >= 150
+ layout(lines_adjacency) in;
+ layout(triangle_strip, max_vertices = 4) out;
+#endif
in block {
VertexData v;
-} inpt[4];
+} inpt[];
+
+/* compatibility */
+out vec3 varnormal;
+out vec3 varposition;
uniform bool osd_flat_shading;
uniform int osd_fvar_count;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 311fcb8ead2..18468c1674f 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1,3 +1,13 @@
+/* Converters */
+
+float convert_rgba_to_float(vec4 color)
+{
+#ifdef USE_NEW_SHADING
+ return color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+#else
+ return (color.r + color.g + color.b) / 3.0;
+#endif
+}
float exp_blender(float f)
{
@@ -166,6 +176,21 @@ void particle_info(vec4 sprops, vec3 loc, vec3 vel, vec3 avel, out float index,
angular_velocity = avel;
}
+void vect_normalize(vec3 vin, out vec3 vout)
+{
+ vout = normalize(vin);
+}
+
+void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = (mat*vec4(vin, 0.0)).xyz;
+}
+
+void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
+{
+ vout = (mat*vec4(vin, 1.0)).xyz;
+}
+
void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
{
outvec = (mat * vec4(vec, 1.0)).xyz;
@@ -369,6 +394,12 @@ void vec_math_negate(vec3 v, out vec3 outv)
outv = -v;
}
+void invert_z(vec3 v, out vec3 outv)
+{
+ v.z = -v.z;
+ outv = v;
+}
+
void normal(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
{
outnor = nor;
@@ -722,7 +753,11 @@ void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha
void rgbtobw(vec4 color, out float outval)
{
+#ifdef USE_NEW_SHADING
+ outval = color.r*0.2126 + color.g*0.7152 + color.b*0.0722;
+#else
outval = color.r*0.35 + color.g*0.45 + color.b*0.2; /* keep these factors in sync with texture.h:RGBTOBW */
+#endif
}
void invert(float fac, vec4 col, out vec4 outcol)
@@ -888,6 +923,11 @@ void shade_norm(vec3 normal, out vec3 outnormal)
outnormal = -normalize(normal);
}
+void mtex_mirror(vec3 tcol, vec4 refcol, float tin, float colmirfac, out vec4 outrefcol)
+{
+ outrefcol = mix(refcol, vec4(1.0, tcol), tin*colmirfac);
+}
+
void mtex_rgb_blend(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
float facm;
@@ -1189,6 +1229,11 @@ void mtex_alpha_to_col(vec4 col, float alpha, out vec4 outcol)
outcol = vec4(col.rgb, alpha);
}
+void mtex_alpha_multiply_value(vec4 col, float value, out vec4 outcol)
+{
+ outcol = vec4(col.rgb, col.a * value);
+}
+
void mtex_rgbtoint(vec4 rgb, out float intensity)
{
intensity = dot(vec3(0.35, 0.45, 0.2), rgb.rgb);
@@ -1238,6 +1283,21 @@ vec3 mtex_2d_mapping(vec3 vec)
return vec3(vec.xy*0.5 + vec2(0.5), vec.z);
}
+void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
+{
+ color = textureCube(ima, co);
+ value = 1.0;
+}
+
+void mtex_cube_map_refl(samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, out float value, out vec4 color)
+{
+ vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
+ vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
+ vec3 reflecteddirection = reflect(viewdirection, normaldirection);
+ color = textureCube(ima, reflecteddirection);
+ value = 1.0;
+}
+
void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color)
{
color = texture2D(ima, texco.xy);
@@ -1572,6 +1632,17 @@ void lamp_falloff_sliders(float lampdist, float ld1, float ld2, float dist, out
visifac *= lampdistkw/(lampdistkw + ld2*dist*dist);
}
+void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coeff_quad, float dist, out float visifac)
+{
+ vec3 coeff = vec3(coeff_const, coeff_lin, coeff_quad);
+ vec3 d_coeff = vec3(1.0, dist, dist*dist);
+ float visifac_r = dot(coeff, d_coeff);
+ if (visifac_r > 0.0)
+ visifac = 1.0 / visifac_r;
+ else
+ visifac = 0.0;
+}
+
void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
{
visifac = texture2D(curvemap, vec2(dist/lampdist, 0.0)).x;
@@ -1584,11 +1655,13 @@ void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float
outvisifac= visifac*max(t, 0.0)/lampdist;
}
-void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float inpr)
+void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
{
if(dot(lv, lampvec) > 0.0) {
vec3 lvrot = (lampimat*vec4(lv, 0.0)).xyz;
- float x = max(abs(lvrot.x/lvrot.z), abs(lvrot.y/lvrot.z));
+ /* without clever non-uniform scale, we could do: */
+ // float x = max(abs(lvrot.x / lvrot.z), abs(lvrot.y / lvrot.z));
+ float x = max(abs((lvrot.x / scale.x) / lvrot.z), abs((lvrot.y / scale.y) / lvrot.z));
inpr = 1.0/sqrt(1.0 + x*x);
}
@@ -1596,9 +1669,21 @@ void lamp_visibility_spot_square(vec3 lampvec, mat4 lampimat, vec3 lv, out float
inpr = 0.0;
}
-void lamp_visibility_spot_circle(vec3 lampvec, vec3 lv, out float inpr)
+void lamp_visibility_spot_circle(vec3 lampvec, mat4 lampimat, vec2 scale, vec3 lv, out float inpr)
{
- inpr = dot(lv, lampvec);
+ /* without clever non-uniform scale, we could do: */
+ // inpr = dot(lv, lampvec);
+ if (dot(lv, lampvec) > 0.0) {
+ vec3 lvrot = (lampimat * vec4(lv, 0.0)).xyz;
+ float x = abs(lvrot.x / lvrot.z);
+ float y = abs(lvrot.y / lvrot.z);
+
+ float ellipse = abs((x * x) / (scale.x * scale.x) + (y * y) / (scale.y * scale.y));
+
+ inpr = 1.0 / sqrt(1.0 + ellipse);
+ }
+ else
+ inpr = 0.0;
}
void lamp_visibility_spot(float spotsi, float spotbl, float inpr, float visifac, out float outvisifac)
@@ -1624,6 +1709,40 @@ void lamp_visibility_clamp(float visifac, out float outvisifac)
outvisifac = (visifac < 0.001)? 0.0: visifac;
}
+void world_paper_view(vec3 vec, out vec3 outvec)
+{
+ vec3 nvec = normalize(vec);
+ outvec = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0);
+}
+
+void world_zen_mapping(vec3 view, float zenup, float zendown, out float zenfac)
+{
+ if (view.z >= 0.0)
+ zenfac = zenup;
+ else
+ zenfac = zendown;
+}
+
+void world_blend_paper_real(vec3 vec, out float blend)
+{
+ blend = abs(vec.y);
+}
+
+void world_blend_paper(vec3 vec, out float blend)
+{
+ blend = (vec.y + 1.0) * 0.5;
+}
+
+void world_blend_real(vec3 vec, out float blend)
+{
+ blend = abs(normalize(vec).z);
+}
+
+void world_blend(vec3 vec, out float blend)
+{
+ blend = (normalize(vec).z + 1) * 0.5;
+}
+
void shade_view(vec3 co, out vec3 view)
{
/* handle perspective/orthographic */
@@ -1944,6 +2063,11 @@ void shade_add_spec(float t, vec3 lampcol, vec3 speccol, out vec3 outcol)
outcol = t*lampcol*speccol;
}
+void shade_add_mirror(vec3 mir, vec4 refcol, vec3 combined, out vec3 result)
+{
+ result = mir*refcol.gba + (vec3(1.0) - mir*refcol.rrr)*combined;
+}
+
void alpha_spec_correction(vec3 spec, float spectra, float alpha, out float outalpha)
{
if (spectra > 0.0) {
@@ -2258,7 +2382,7 @@ void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float shar
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, out vec4 result)
+void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result)
{
result = color;
}
@@ -2546,7 +2670,8 @@ void node_light_path(
out float is_transmission_ray,
out float ray_length,
out float ray_depth,
- out float transparent_depth)
+ out float transparent_depth,
+ out float transmission_depth)
{
is_camera_ray = 1.0;
is_shadow_ray = 0.0;
@@ -2558,6 +2683,7 @@ void node_light_path(
ray_length = 1.0;
ray_depth = 1.0;
transparent_depth = 1.0;
+ transmission_depth = 1.0;
}
void node_light_falloff(float strength, float tsmooth, out float quadratic, out float linear, out float constant)
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_frag.glsl b/source/blender/gpu/shaders/gpu_shader_simple_frag.glsl
deleted file mode 100644
index 94c73d9e248..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_simple_frag.glsl
+++ /dev/null
@@ -1,169 +0,0 @@
-
-/* Options:
- *
- * USE_COLOR: use glColor for diffuse colors
- * USE_TEXTURE: use texture for diffuse colors
- * USE_SCENE_LIGHTING: use lights (up to 8)
- * USE_SOLID_LIGHTING: assume 3 directional lights for solid draw mode
- * USE_TWO_SIDED: flip normal towards viewer
- * NO_SPECULAR: use specular component
- */
-
-#define NUM_SOLID_LIGHTS 3
-#define NUM_SCENE_LIGHTS 8
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
-varying vec3 varying_normal;
-
-#ifndef USE_SOLID_LIGHTING
-varying vec3 varying_position;
-#endif
-#endif
-
-#ifdef USE_COLOR
-varying vec4 varying_vertex_color;
-#endif
-
-#ifdef USE_TEXTURE
-varying vec2 varying_texture_coord;
-uniform sampler2D texture_map;
-#endif
-
-void main()
-{
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
- /* compute normal */
- vec3 N = normalize(varying_normal);
-
-#ifdef USE_TWO_SIDED
- if (!gl_FrontFacing)
- N = -N;
-#endif
-
- /* compute diffuse and specular lighting */
- vec3 L_diffuse = vec3(0.0);
-#ifndef NO_SPECULAR
- vec3 L_specular = vec3(0.0);
-#endif
-
-#ifdef USE_SOLID_LIGHTING
- /* assume 3 directional lights */
- for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
- vec3 light_direction = gl_LightSource[i].position.xyz;
-
- /* diffuse light */
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
- float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf;
-
-#ifndef NO_SPECULAR
- /* specular light */
- vec3 light_specular = gl_LightSource[i].specular.rgb;
- vec3 H = gl_LightSource[i].halfVector.xyz;
-
- float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf;
-#endif
- }
-#else
- /* all 8 lights, makes no assumptions, potentially slow */
-
-#ifndef NO_SPECULAR
- /* view vector computation, depends on orthographics or perspective */
- vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(varying_position): vec3(0.0, 0.0, -1.0);
-#endif
-
- for (int i = 0; i < NUM_SCENE_LIGHTS; i++) {
- /* todo: this is a slow check for disabled lights */
- if (gl_LightSource[i].specular.a == 0.0)
- continue;
-
- float intensity = 1.0;
- vec3 light_direction;
-
- if (gl_LightSource[i].position.w == 0.0) {
- /* directional light */
- light_direction = gl_LightSource[i].position.xyz;
- }
- else {
- /* point light */
- vec3 d = gl_LightSource[i].position.xyz - varying_position;
- light_direction = normalize(d);
-
- /* spot light cone */
- if (gl_LightSource[i].spotCutoff < 90.0) {
- float cosine = max(dot(light_direction, -gl_LightSource[i].spotDirection), 0.0);
- intensity = pow(cosine, gl_LightSource[i].spotExponent);
- intensity *= step(gl_LightSource[i].spotCosCutoff, cosine);
- }
-
- /* falloff */
- float distance = length(d);
-
- intensity /= gl_LightSource[i].constantAttenuation +
- gl_LightSource[i].linearAttenuation * distance +
- gl_LightSource[i].quadraticAttenuation * distance * distance;
- }
-
- /* diffuse light */
- vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
- float diffuse_bsdf = max(dot(N, light_direction), 0.0);
- L_diffuse += light_diffuse*diffuse_bsdf*intensity;
-
-#ifndef NO_SPECULAR
- /* specular light */
- vec3 light_specular = gl_LightSource[i].specular.rgb;
- vec3 H = normalize(light_direction - V);
-
- float specular_bsdf = pow(max(dot(N, H), 0.0), gl_FrontMaterial.shininess);
- L_specular += light_specular*specular_bsdf*intensity;
-#endif
- }
-#endif
-
- /* compute diffuse color, possibly from texture or vertex colors */
- float alpha;
-
-#if defined(USE_TEXTURE) && defined(USE_COLOR)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
-
- L_diffuse *= texture_color.rgb * varying_vertex_color.rgb;
- alpha = texture_color.a * varying_vertex_color.a;
-#elif defined(USE_TEXTURE)
- vec4 texture_color = texture2D(texture_map, varying_texture_coord);
-
- L_diffuse *= texture_color.rgb;
- alpha = texture_color.a;
-#elif defined(USE_COLOR)
- L_diffuse *= varying_vertex_color.rgb;
- alpha = varying_vertex_color.a;
-#else
- L_diffuse *= gl_FrontMaterial.diffuse.rgb;
- alpha = gl_FrontMaterial.diffuse.a;
-#endif
-
- /* sum lighting */
- vec3 L = gl_FrontLightModelProduct.sceneColor.rgb + L_diffuse;
-
-#ifndef NO_SPECULAR
- L += L_specular*gl_FrontMaterial.specular.rgb;
-#endif
-
- /* write out fragment color */
- gl_FragColor = vec4(L, alpha);
-#else
-
- /* no lighting */
-#if defined(USE_TEXTURE) && defined(USE_COLOR)
- gl_FragColor = texture2D(texture_map, varying_texture_coord) * varying_vertex_color;
-#elif defined(USE_TEXTURE)
- gl_FragColor = texture2D(texture_map, varying_texture_coord);
-#elif defined(USE_COLOR)
- gl_FragColor = varying_vertex_color;
-#else
- gl_FragColor = gl_FrontMaterial.diffuse;
-#endif
-
-#endif
-}
-
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl
deleted file mode 100644
index 8ccd0feb5e2..00000000000
--- a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl
+++ /dev/null
@@ -1,54 +0,0 @@
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
-varying vec3 varying_normal;
-
-#ifndef USE_SOLID_LIGHTING
-varying vec3 varying_position;
-#endif
-#endif
-
-#ifdef USE_COLOR
-varying vec4 varying_vertex_color;
-#endif
-
-#ifdef USE_TEXTURE
-varying vec2 varying_texture_coord;
-#endif
-
-#ifdef CLIP_WORKAROUND
-varying float gl_ClipDistance[6];
-#endif
-
-void main()
-{
- vec4 co = gl_ModelViewMatrix * gl_Vertex;
-
-#if defined(USE_SOLID_LIGHTING) || defined(USE_SCENE_LIGHTING)
- varying_normal = normalize(gl_NormalMatrix * gl_Normal);
-
-#ifndef USE_SOLID_LIGHTING
- varying_position = co.xyz;
-#endif
-#endif
-
- gl_Position = gl_ProjectionMatrix * co;
-
-#ifdef CLIP_WORKAROUND
- int i;
- for(i = 0; i < 6; i++)
- gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
-#elif !defined(GPU_ATI)
- // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
- // graphic cards, while on ATI it can cause a software fallback.
- gl_ClipVertex = co;
-#endif
-
-#ifdef USE_COLOR
- varying_vertex_color = gl_Color;
-#endif
-
-#ifdef USE_TEXTURE
- varying_texture_coord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).st;
-#endif
-}
-
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
new file mode 100644
index 00000000000..4d1feb5c83e
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
@@ -0,0 +1,48 @@
+
+varying vec3 coords;
+
+uniform vec3 active_color;
+uniform float step_size;
+uniform float density_scale;
+
+uniform sampler3D soot_texture;
+uniform sampler3D shadow_texture;
+
+#ifdef USE_FIRE
+uniform sampler3D flame_texture;
+uniform sampler1D spectrum_texture;
+#endif
+
+void main()
+{
+ /* compute color and density from volume texture */
+ vec4 soot = texture3D(soot_texture, coords);
+ vec3 soot_color;
+ if (soot.a != 0) {
+ soot_color = active_color * soot.rgb / soot.a;
+ }
+ else {
+ soot_color = vec3(0, 0, 0);
+ }
+ float soot_density = density_scale * soot.a;
+
+ /* compute transmittance and alpha */
+ float soot_transmittance = pow(2.71828182846, -soot_density * step_size);
+ float soot_alpha = 1.0 - soot_transmittance;
+
+ /* shade */
+ float shadow = texture3D(shadow_texture, coords).r;
+ soot_color *= soot_transmittance * shadow;
+
+ /* premultiply alpha */
+ vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
+
+#ifdef USE_FIRE
+ /* fire */
+ float flame = texture3D(flame_texture, coords).r;
+ vec4 emission = texture1D(spectrum_texture, flame);
+ color.rgb += (1 - color.a) * emission.a * emission.rgb;
+#endif
+
+ gl_FragColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
new file mode 100644
index 00000000000..297486ae26a
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_vert.glsl
@@ -0,0 +1,12 @@
+
+varying vec3 coords;
+
+uniform vec3 min_location;
+uniform vec3 invsize;
+uniform vec3 ob_sizei;
+
+void main()
+{
+ gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz * ob_sizei, 1.0);
+ coords = (gl_Vertex.xyz - min_location) * invsize;
+}
diff --git a/source/blender/ikplugin/SConscript b/source/blender/ikplugin/SConscript
deleted file mode 100644
index 4a4cb4f2cbd..00000000000
--- a/source/blender/ikplugin/SConscript
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c') + env.Glob('intern/*.cpp')
-
-incs = [
- '#/extern/Eigen3',
- '#/intern/guardedalloc',
- '#/intern/itasc',
- '#/intern/iksolver/extern',
- '../blenkernel',
- '../blenlib',
- '../ikplugin',
- '../include',
- '../makesdna',
- ]
-
-defs = [
- 'WITH_IK_ITASC',
- 'WITH_IK_SOLVER',
- ]
-
-env.BlenderLib('bf_ikplugin', sources, incs, defs, libtype=['core', 'player'], priority=[180, 190])
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index 5da06ed91ec..b3c83bffb3f 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -242,7 +242,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
float goal[4][4], goalinv[4][4];
float irest_basis[3][3], full_basis[3][3];
float end_pose[4][4], world_pose[4][4];
- float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL;
+ float basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL;
float resultinf = 0.0f;
int a, flag, hasstretch = 0, resultblend = 0;
bPoseChannel *pchan;
@@ -258,6 +258,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree");
for (a = 0; a < tree->totchannel; a++) {
+ float length;
pchan = tree->pchan[a];
bone = pchan->bone;
@@ -335,9 +336,9 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);
if (tree->stretch && (pchan->ikstretch > 0.0f)) {
- const float ikstretch = pchan->ikstretch * pchan->ikstretch;
+ const float ikstretch_sq = SQUARE(pchan->ikstretch);
/* this function does its own clamping */
- IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch);
+ IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch_sq);
IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX);
}
}
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index 295a48dc245..b32f8c54cd6 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -46,12 +46,12 @@ set(SRC
intern/bmp.c
intern/cache.c
intern/colormanagement.c
+ intern/colormanagement_inline.c
intern/divers.c
intern/filetype.c
intern/filter.c
intern/imageprocess.c
intern/indexer.c
- intern/indexer_dv.c
intern/iris.c
intern/jpeg.c
intern/metadata.c
@@ -123,13 +123,6 @@ if(WITH_IMAGE_OPENJPEG)
add_definitions(-DWITH_OPENJPEG ${OPENJPEG_DEFINES})
endif()
-if(WITH_IMAGE_REDCODE)
- list(APPEND INC_SYS
- ${REDCODE_INC}
- )
- add_definitions(-DWITH_REDCODE)
-endif()
-
if(WITH_CODEC_AVI)
list(APPEND INC
../avi
@@ -188,4 +181,10 @@ if(WIN32)
)
endif()
+# no need to compile object files for inline headers.
+set_source_files_properties(
+ intern/colormanagement_inline.c
+ PROPERTIES HEADER_FILE_ONLY TRUE
+)
+
blender_add_lib(bf_imbuf "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 59df8334099..ab822f1cd55 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -36,9 +36,11 @@
*/
#include "BLI_sys_types.h"
+#include "BLI_compiler_compat.h"
#define BCM_CONFIG_FILE "config.ocio"
+
struct bContext;
struct ColorManagedColorspaceSettings;
struct ColorManagedDisplaySettings;
@@ -67,8 +69,8 @@ void IMB_colormanagement_assign_rect_colorspace(struct ImBuf *ibuf, const char *
const char *IMB_colormanagement_get_float_colorspace(struct ImBuf *ibuf);
const char *IMB_colormanagement_get_rect_colorspace(struct ImBuf *ibuf);
-float IMB_colormanagement_get_luminance(const float rgb[3]);
-unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
+BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
+BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
/* ** Color space transformation functions ** */
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels,
@@ -206,4 +208,6 @@ enum {
COLOR_ROLE_DEFAULT_FLOAT,
};
+#include "intern/colormanagement_inline.c"
+
#endif /* __IMB_COLORMANAGEMENT_H__ */
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 77e860191b2..043f1602a76 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -332,7 +332,6 @@ void IMB_free_anim(struct anim *anim);
#define FILTER_MASK_USED 2
void IMB_filter(struct ImBuf *ibuf);
-void IMB_filterN(struct ImBuf *out, struct ImBuf *in);
void IMB_mask_filter_extend(char *mask, int width, int height);
void IMB_mask_clear(struct ImBuf *ibuf, char *mask, int val);
void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter);
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 08ce9c0469b..f4b2539d7d7 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -67,32 +67,34 @@ typedef struct DDSData {
*/
/* ibuf->ftype flag, main image types */
+/* Warning: Keep explicit value assignements here, this file is included in areas where not all format defines
+ * are set (e.g. intern/dds only get WITH_DDS, even if TIFF, HDR etc are also defined). See T46524. */
enum eImbTypes {
- IMB_FTYPE_PNG = 1,
- IMB_FTYPE_TGA,
- IMB_FTYPE_JPG,
- IMB_FTYPE_BMP,
- IMB_FTYPE_OPENEXR,
- IMB_FTYPE_IMAGIC,
+ IMB_FTYPE_PNG = 1,
+ IMB_FTYPE_TGA = 2,
+ IMB_FTYPE_JPG = 3,
+ IMB_FTYPE_BMP = 4,
+ IMB_FTYPE_OPENEXR = 5,
+ IMB_FTYPE_IMAGIC = 6,
#ifdef WITH_OPENIMAGEIO
- IMB_FTYPE_PSD,
+ IMB_FTYPE_PSD = 7,
#endif
#ifdef WITH_OPENJPEG
- IMB_FTYPE_JP2,
+ IMB_FTYPE_JP2 = 8,
#endif
#ifdef WITH_HDR
- IMB_FTYPE_RADHDR,
+ IMB_FTYPE_RADHDR = 9,
#endif
#ifdef WITH_TIFF
- IMB_FTYPE_TIF,
+ IMB_FTYPE_TIF = 10,
#endif
#ifdef WITH_CINEON
- IMB_FTYPE_CINEON,
- IMB_FTYPE_DPX,
+ IMB_FTYPE_CINEON = 11,
+ IMB_FTYPE_DPX = 12,
#endif
#ifdef WITH_DDS
- IMB_FTYPE_DDS,
+ IMB_FTYPE_DDS = 13,
#endif
};
@@ -124,14 +126,12 @@ enum eImbTypes {
#define RAWTGA 1
-#define JPG_STD 0
-#define JPG_VID 1
-#define JPG_JST 2
-#define JPG_MAX 3
-#define JPG_MSK 0x03
-
#ifdef WITH_TIFF
-#define TIF_16BIT (1 << 8 )
+#define TIF_16BIT (1 << 8)
+#define TIF_COMPRESS_NONE (1 << 7)
+#define TIF_COMPRESS_DEFLATE (1 << 6)
+#define TIF_COMPRESS_LZW (1 << 5)
+#define TIF_COMPRESS_PACKBITS (1 << 4)
#endif
typedef struct ImbFormatOptions {
@@ -156,10 +156,19 @@ typedef struct ImBuf {
int mall; /* what is malloced internal, and can be freed */
/* pixels */
- unsigned int *rect; /* pixel values stored here */
- float *rect_float; /* floating point Rect equivalent
- * Linear RGB color space - may need gamma correction to
- * sRGB when generating 8bit representations */
+
+ /** Image pixel buffer (8bit representation):
+ * - color space defaults to `sRGB`.
+ * - alpha defaults to 'straight'.
+ */
+ unsigned int *rect;
+ /** Image pixel buffer (float representation):
+ * - color space defaults to 'linear' (`rec709`).
+ * - alpha defaults to 'premul'.
+ * \note May need gamma correction to `sRGB` when generating 8bit representations.
+ * \note Formats that support higher more than 8 but channels load as floats.
+ */
+ float *rect_float;
/* resolution - pixels per meter */
double ppm[2];
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
index aaa5eea04ad..6ca4b919c1d 100644
--- a/source/blender/imbuf/IMB_thumbs.h
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -63,7 +63,7 @@ typedef enum ThumbSource {
#define PREVIEW_RENDER_DEFAULT_HEIGHT 128
-/* Note this can also be used as versionning system,
+/* Note this can also be used as versioning system,
* to force refreshing all thumbnails if e.g. we change some thumb generating code or so.
* Only used by fonts so far. */
#define THUMB_DEFAULT_HASH "00000000000000000000000000000000"
diff --git a/source/blender/imbuf/SConscript b/source/blender/imbuf/SConscript
deleted file mode 100644
index ccee3ebcc85..00000000000
--- a/source/blender/imbuf/SConscript
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import os
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- '#/intern/opencolorio',
- '#/intern/ffmpeg',
- '#/intern/guardedalloc',
- '#/intern/memutil',
- '../avi',
- '../blenkernel',
- '../blenlib',
- '../blenloader',
- '../makesdna',
- '../makesrna',
- env['BF_JPEG_INC'],
- env['BF_PNG_INC'],
- env['BF_TIFF_INC'],
- env['BF_ZLIB_INC'],
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
- incs += ' ../../../intern/utfconv'
-
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-else:
- sources.append(os.path.join('intern', 'openexr', 'openexr_stub.cpp'))
-
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-else:
- sources.remove(os.path.join('intern', 'tiff.c'))
-
-if env['WITH_BF_DDS']:
- defs.append('WITH_DDS')
-
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-
-if env['WITH_BF_HDR']:
- defs.append('WITH_HDR')
-else:
- sources.remove(os.path.join('intern', 'radiance_hdr.c'))
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
- incs += ' ' + env['BF_FFMPEG_INC']
-
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
- incs += ' ' + env['BF_OPENJPEG_INC']
-else:
- sources.remove(os.path.join('intern', 'jp2.c'))
-
-if env['WITH_BF_REDCODE']:
- defs.append('WITH_REDCODE')
- incs += ' ' + env['BF_REDCODE_INC']
-
-if env['WITH_BF_QUICKTIME']:
- incs += ' ../quicktime ' + env['BF_QUICKTIME_INC']
- defs.append('WITH_QUICKTIME')
-
-env.BlenderLib ( libname = 'bf_imbuf', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [185,115] )
diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h
index f4d6d869f1b..a754a4919eb 100644
--- a/source/blender/imbuf/intern/IMB_allocimbuf.h
+++ b/source/blender/imbuf/intern/IMB_allocimbuf.h
@@ -38,6 +38,18 @@ struct ImBuf;
void imb_refcounter_lock_init(void);
void imb_refcounter_lock_exit(void);
+#ifdef WIN32
+void imb_mmap_lock_init(void);
+void imb_mmap_lock_exit(void);
+void imb_mmap_lock(void);
+void imb_mmap_unlock(void);
+#else
+# define imb_mmap_lock_init()
+# define imb_mmap_lock_exit()
+# define imb_mmap_lock()
+# define imb_mmap_unlock()
+#endif
+
bool imb_addencodedbufferImBuf(struct ImBuf *ibuf);
bool imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf);
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index 690ec813407..f4763883489 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -72,22 +72,16 @@
# endif /* _WIN32 || __APPLE__ */
#endif /* WITH_QUICKTIME */
-#ifdef WITH_FFMPEG
-# include <libavformat/avformat.h>
-# include <libavcodec/avcodec.h>
-# include <libswscale/swscale.h>
-#endif
-
-#ifdef WITH_REDCODE
-# include "libredcode/format.h"
-#endif
-
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_allocimbuf.h"
-
+#ifdef WITH_FFMPEG
+# include <libavformat/avformat.h>
+# include <libavcodec/avcodec.h>
+# include <libswscale/swscale.h>
+#endif
/* actually hard coded endianness */
#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
@@ -111,7 +105,6 @@
#define ANIM_AVI (1 << 6)
#define ANIM_QTIME (1 << 7)
#define ANIM_FFMPEG (1 << 8)
-#define ANIM_REDCODE (1 << 9)
#define MAXNUMSTREAMS 50
@@ -177,10 +170,6 @@ struct anim {
AVPacket next_packet;
#endif
-#ifdef WITH_REDCODE
- struct redcode_handle *redcodeCtx;
-#endif
-
char index_dir[768];
int proxies_tried;
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index 17eb4bf6db4..b75f12b239d 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -41,6 +41,8 @@
struct OCIO_ConstProcessorRcPtr;
struct ImBuf;
+extern float imbuf_luma_coefficients[3];
+
#define MAX_COLORSPACE_NAME 64
#define MAX_COLORSPACE_DESCRIPTION 512
@@ -61,7 +63,7 @@ typedef struct ColorManagedDisplay {
struct ColorManagedDisplay *next, *prev;
int index;
char name[MAX_COLORSPACE_NAME];
- ListBase views;
+ ListBase views; /* LinkData.data -> ColorManagedView */
struct OCIO_ConstProcessorRcPtr *to_scene_linear;
struct OCIO_ConstProcessorRcPtr *from_scene_linear;
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
index 5c79eb2c544..988f43ff9fa 100644
--- a/source/blender/imbuf/intern/allocimbuf.c
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -62,6 +62,30 @@ void imb_refcounter_lock_exit(void)
BLI_spin_end(&refcounter_spin);
}
+#ifdef WIN32
+static SpinLock mmap_spin;
+
+void imb_mmap_lock_init(void)
+{
+ BLI_spin_init(&mmap_spin);
+}
+
+void imb_mmap_lock_exit(void)
+{
+ BLI_spin_end(&mmap_spin);
+}
+
+void imb_mmap_lock(void)
+{
+ BLI_spin_lock(&mmap_spin);
+}
+
+void imb_mmap_unlock(void)
+{
+ BLI_spin_unlock(&mmap_spin);
+}
+#endif
+
void imb_freemipmapImBuf(ImBuf *ibuf)
{
int a;
@@ -478,6 +502,8 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
if (ibuf1->rect) flags |= IB_rect;
if (ibuf1->rect_float) flags |= IB_rectfloat;
+ if (ibuf1->zbuf) flags |= IB_zbuf;
+ if (ibuf1->zbuf_float) flags |= IB_zbuffloat;
x = ibuf1->x;
y = ibuf1->y;
@@ -492,6 +518,12 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
if (flags & IB_rectfloat)
memcpy(ibuf2->rect_float, ibuf1->rect_float, ((size_t)ibuf1->channels) * x * y * sizeof(float));
+ if (flags & IB_zbuf)
+ memcpy(ibuf2->zbuf, ibuf1->zbuf, ((size_t)x) * y * sizeof(int));
+
+ if (flags & IB_zbuffloat)
+ memcpy(ibuf2->zbuf_float, ibuf1->zbuf_float, ((size_t)x) * y * sizeof(float));
+
if (ibuf1->encodedbuffer) {
ibuf2->encodedbuffersize = ibuf1->encodedbuffersize;
if (imb_addencodedbufferImBuf(ibuf2) == false) {
@@ -509,8 +541,8 @@ ImBuf *IMB_dupImBuf(ImBuf *ibuf1)
tbuf.rect = ibuf2->rect;
tbuf.rect_float = ibuf2->rect_float;
tbuf.encodedbuffer = ibuf2->encodedbuffer;
- tbuf.zbuf = NULL;
- tbuf.zbuf_float = NULL;
+ tbuf.zbuf = ibuf2->zbuf;
+ tbuf.zbuf_float = ibuf2->zbuf_float;
for (a = 0; a < IMB_MIPMAP_LEVELS; a++)
tbuf.mipmap[a] = NULL;
tbuf.dds_data.data = NULL;
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index e2d56d29726..d378ca9a78c 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -85,27 +85,21 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "IMB_colormanagement.h"
+#include "IMB_colormanagement_intern.h"
+
#include "IMB_anim.h"
#include "IMB_indexer.h"
#ifdef WITH_FFMPEG
-#include <libavformat/avformat.h>
-#include <libavcodec/avcodec.h>
-#include <libavutil/rational.h>
-#include <libswscale/swscale.h>
-
-#include "ffmpeg_compat.h"
+# include <libavformat/avformat.h>
+# include <libavcodec/avcodec.h>
+# include <libavutil/rational.h>
+# include <libswscale/swscale.h>
+# include "ffmpeg_compat.h"
#endif //WITH_FFMPEG
-#ifdef WITH_REDCODE
-# include "libredcode/format.h"
-# include "libredcode/codec.h"
-#endif
-
-#include "IMB_colormanagement.h"
-#include "IMB_colormanagement_intern.h"
-
int ismovie(const char *UNUSED(filepath))
{
return 0;
@@ -127,9 +121,9 @@ static void free_anim_movie(struct anim *UNUSED(anim))
#if defined(_WIN32)
-# define PATHSEPERATOR '\\'
+# define PATHSEPARATOR '\\'
#else
-# define PATHSEPERATOR '/'
+# define PATHSEPARATOR '/'
#endif
static int an_stringdec(const char *string, char *head, char *tail, unsigned short *numlen)
@@ -142,7 +136,7 @@ static int an_stringdec(const char *string, char *head, char *tail, unsigned sho
nume = len;
for (i = len - 1; i >= 0; i--) {
- if (string[i] == PATHSEPERATOR) break;
+ if (string[i] == PATHSEPARATOR) break;
if (isdigit(string[i])) {
if (found) {
nums = i;
@@ -216,9 +210,6 @@ static void free_anim_avi(struct anim *anim)
#ifdef WITH_FFMPEG
static void free_anim_ffmpeg(struct anim *anim);
#endif
-#ifdef WITH_REDCODE
-static void free_anim_redcode(struct anim *anim);
-#endif
void IMB_free_anim(struct anim *anim)
{
@@ -239,9 +230,6 @@ void IMB_free_anim(struct anim *anim)
#ifdef WITH_FFMPEG
free_anim_ffmpeg(anim);
#endif
-#ifdef WITH_REDCODE
- free_anim_redcode(anim);
-#endif
IMB_free_indices(anim);
MEM_freeN(anim);
@@ -455,6 +443,11 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position)
#ifdef WITH_FFMPEG
+BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
+{
+ return (anim->x & 31) != 0;
+}
+
static int startffmpeg(struct anim *anim)
{
int i, videoStream;
@@ -525,9 +518,14 @@ static int startffmpeg(struct anim *anim)
}
frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
- anim->duration = ceil(pFormatCtx->duration *
- av_q2d(frame_rate) /
- AV_TIME_BASE);
+ if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
+ anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
+ }
+ else {
+ anim->duration = ceil(pFormatCtx->duration *
+ av_q2d(frame_rate) /
+ AV_TIME_BASE);
+ }
frs_num = frame_rate.num;
frs_den = frame_rate.den;
@@ -562,21 +560,38 @@ static int startffmpeg(struct anim *anim)
anim->next_pts = -1;
anim->next_packet.stream_index = -1;
- anim->pFrame = avcodec_alloc_frame();
+ anim->pFrame = av_frame_alloc();
anim->pFrameComplete = false;
- anim->pFrameDeinterlaced = avcodec_alloc_frame();
- anim->pFrameRGB = avcodec_alloc_frame();
+ anim->pFrameDeinterlaced = av_frame_alloc();
+ anim->pFrameRGB = av_frame_alloc();
+
+ if (need_aligned_ffmpeg_buffer(anim)) {
+ anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
+ anim->pFrameRGB->width = anim->x;
+ anim->pFrameRGB->height = anim->y;
+
+ if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+ avcodec_close(anim->pCodecCtx);
+ avformat_close_input(&anim->pFormatCtx);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
+ anim->pCodecCtx = NULL;
+ return -1;
+ }
+ }
- if (avpicture_get_size(PIX_FMT_RGBA, anim->x, anim->y) !=
+ if (avpicture_get_size(AV_PIX_FMT_RGBA, anim->x, anim->y) !=
anim->x * anim->y * 4)
{
fprintf(stderr,
"ffmpeg has changed alloc scheme ... ARGHHH!\n");
avcodec_close(anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_free(anim->pFrameRGB);
- av_free(anim->pFrameDeinterlaced);
- av_free(anim->pFrame);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
anim->pCodecCtx = NULL;
return -1;
}
@@ -606,7 +621,7 @@ static int startffmpeg(struct anim *anim)
anim->pCodecCtx->pix_fmt,
anim->x,
anim->y,
- PIX_FMT_RGBA,
+ AV_PIX_FMT_RGBA,
SWS_FAST_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
NULL, NULL, NULL);
@@ -615,9 +630,9 @@ static int startffmpeg(struct anim *anim)
"Can't transform color space??? Bailing out...\n");
avcodec_close(anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_free(anim->pFrameRGB);
- av_free(anim->pFrameDeinterlaced);
- av_free(anim->pFrame);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrame);
anim->pCodecCtx = NULL;
return -1;
}
@@ -692,10 +707,12 @@ static void ffmpeg_postprocess(struct anim *anim)
input = anim->pFrameDeinterlaced;
}
}
-
- avpicture_fill((AVPicture *) anim->pFrameRGB,
- (unsigned char *) ibuf->rect,
- PIX_FMT_RGBA, anim->x, anim->y);
+
+ if (!need_aligned_ffmpeg_buffer(anim)) {
+ avpicture_fill((AVPicture *) anim->pFrameRGB,
+ (unsigned char *) ibuf->rect,
+ AV_PIX_FMT_RGBA, anim->x, anim->y);
+ }
if (ENDIAN_ORDER == B_ENDIAN) {
int *dstStride = anim->pFrameRGB->linesize;
@@ -760,6 +777,16 @@ static void ffmpeg_postprocess(struct anim *anim)
dstStride2);
}
+ if (need_aligned_ffmpeg_buffer(anim)) {
+ uint8_t *src = anim->pFrameRGB->data[0];
+ uint8_t *dst = (uint8_t *) ibuf->rect;
+ for (int y = 0; y < anim->y; y++) {
+ memcpy(dst, src, anim->x * 4);
+ dst += anim->x * 4;
+ src += anim->pFrameRGB->linesize[0];
+ }
+ }
+
if (filter_y) {
IMB_filtery(ibuf);
}
@@ -826,7 +853,7 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
* which is necessary to decode the remaining data
* in the decoder engine after EOF. It also prevents a memory
* leak, since av_read_frame spills out a full size packet even
- * on EOF... (and: it's save to call on NULL packets) */
+ * on EOF... (and: it's safe to call on NULL packets) */
av_free_packet(&anim->next_packet);
@@ -1141,13 +1168,28 @@ static void free_anim_ffmpeg(struct anim *anim)
if (anim->pCodecCtx) {
avcodec_close(anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_free(anim->pFrameRGB);
+
+ /* Special case here: pFrame could share pointers with codec,
+ * so in order to avoid double-free we don't use av_frame_free()
+ * to free the frame.
+ *
+ * Could it be a bug in FFmpeg?
+ */
av_free(anim->pFrame);
- if (anim->ib_flags & IB_animdeinterlace) {
- MEM_freeN(anim->pFrameDeinterlaced->data[0]);
+ if (!need_aligned_ffmpeg_buffer(anim)) {
+ /* If there's no need for own aligned buffer it means that FFmpeg's
+ * frame shares the same buffer as temporary ImBuf. In this case we
+ * should not free the buffer when freeing the FFmpeg buffer.
+ */
+ avpicture_fill((AVPicture *)anim->pFrameRGB,
+ NULL,
+ AV_PIX_FMT_RGBA,
+ anim->x, anim->y);
}
- av_free(anim->pFrameDeinterlaced);
+ av_frame_free(&anim->pFrameRGB);
+ av_frame_free(&anim->pFrameDeinterlaced);
+
sws_freeContext(anim->img_convert_ctx);
IMB_freeImBuf(anim->last_frame);
if (anim->next_packet.stream_index != -1) {
@@ -1159,62 +1201,6 @@ static void free_anim_ffmpeg(struct anim *anim)
#endif
-#ifdef WITH_REDCODE
-
-static int startredcode(struct anim *anim)
-{
- anim->redcodeCtx = redcode_open(anim->name);
- if (!anim->redcodeCtx) {
- return -1;
- }
- anim->duration = redcode_get_length(anim->redcodeCtx);
-
- return 0;
-}
-
-static ImBuf *redcode_fetchibuf(struct anim *anim, int position)
-{
- struct ImBuf *ibuf;
- struct redcode_frame *frame;
- struct redcode_frame_raw *raw_frame;
-
- if (!anim->redcodeCtx) {
- return NULL;
- }
-
- frame = redcode_read_video_frame(anim->redcodeCtx, position);
-
- if (!frame) {
- return NULL;
- }
-
- raw_frame = redcode_decode_video_raw(frame, 1);
-
- redcode_free_frame(frame);
-
- if (!raw_frame) {
- return NULL;
- }
-
- ibuf = IMB_allocImBuf(raw_frame->width * 2,
- raw_frame->height * 2, 32, IB_rectfloat);
-
- redcode_decode_video_float(raw_frame, ibuf->rect_float, 1);
-
- return ibuf;
-}
-
-static void free_anim_redcode(struct anim *anim)
-{
- if (anim->redcodeCtx) {
- redcode_close(anim->redcodeCtx);
- anim->redcodeCtx = 0;
- }
- anim->duration = 0;
-}
-
-#endif
-
/* Try next picture to read */
/* No picture, try to open next animation */
/* Succeed, remove first image from animation */
@@ -1237,10 +1223,6 @@ static ImBuf *anim_getnew(struct anim *anim)
#ifdef WITH_FFMPEG
free_anim_ffmpeg(anim);
#endif
-#ifdef WITH_REDCODE
- free_anim_redcode(anim);
-#endif
-
if (anim->curtype != 0) return (NULL);
anim->curtype = imb_get_anim_type(anim->name);
@@ -1278,12 +1260,6 @@ static ImBuf *anim_getnew(struct anim *anim)
ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
break;
#endif
-#ifdef WITH_REDCODE
- case ANIM_REDCODE:
- if (startredcode(anim)) return (0);
- ibuf = IMB_allocImBuf(8, 8, 32, 0);
- break;
-#endif
}
return(ibuf);
}
@@ -1390,12 +1366,6 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, int position,
filter_y = 0; /* done internally */
break;
#endif
-#ifdef WITH_REDCODE
- case ANIM_REDCODE:
- ibuf = redcode_fetchibuf(anim, position);
- if (ibuf) anim->curposition = position;
- break;
-#endif
}
if (ibuf) {
diff --git a/source/blender/imbuf/intern/cineon/SConscript b/source/blender/imbuf/intern/cineon/SConscript
deleted file mode 100644
index 037a7fec1bc..00000000000
--- a/source/blender/imbuf/intern/cineon/SConscript
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-source_files = env.Glob('*.c')
-
-incs = ['.',
- '../../../blenkernel',
- '../../',
- '..',
- '../../../blenlib',
- 'intern/include',
- '#/intern/guardedalloc',
- '../../../makesdna']
-
-defs = []
-
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-
-env.BlenderLib ('bf_imbuf_cineon', source_files, incs, defs, libtype=['core','player'], priority = [220,175])
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h
index 9333743a1bf..775572debaf 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.h
+++ b/source/blender/imbuf/intern/cineon/cineonlib.h
@@ -27,8 +27,8 @@
*/
-#ifndef __CINEON_LIB_H__
-#define __CINEON_LIB_H__
+#ifndef __CINEONLIB_H__
+#define __CINEONLIB_H__
#ifdef __cplusplus
extern "C" {
@@ -139,4 +139,4 @@ LogImageFile *cineonCreate(const char *filename, int width, int height, int bits
}
#endif
-#endif /* __CINEON_LIB_H__ */
+#endif /* __CINEONLIB_H__ */
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h
index e910aaa61e1..2b90d8c5e07 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.h
+++ b/source/blender/imbuf/intern/cineon/dpxlib.h
@@ -26,8 +26,8 @@
*/
-#ifndef __DPX_LIB_H__
-#define __DPX_LIB_H__
+#ifndef __DPXLIB_H__
+#define __DPXLIB_H__
#ifdef __cplusplus
extern "C" {
@@ -157,4 +157,4 @@ LogImageFile *dpxCreate(const char *filename, int width, int height, int bitsPer
}
#endif
-#endif
+#endif /* __DPXLIB_H__ */
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
index 389e88a24de..e39df1ea096 100644
--- a/source/blender/imbuf/intern/cineon/logImageCore.h
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -30,8 +30,8 @@
* \ingroup imbcineon
*/
-#ifndef __LOG_IMAGE_CORE_H__
-#define __LOG_IMAGE_CORE_H__
+#ifndef __LOGIMAGECORE_H__
+#define __LOGIMAGECORE_H__
#include <stdio.h>
@@ -278,4 +278,4 @@ BLI_INLINE unsigned int float_uint(float value, unsigned int max)
}
#endif
-#endif /* __LOG_IMAGE_CORE_H__ */
+#endif /* __LOGIMAGECORE_H__ */
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 5a3d9b4c653..e4e93d3c4da 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -93,7 +93,7 @@ static int global_tot_looks = 0;
/* Set to ITU-BT.709 / sRGB primaries weight. Brute force stupid, but only
* option with no colormanagement in place.
*/
-static float luma_coefficients[3] = { 0.2126f, 0.7152f, 0.0722f };
+float imbuf_luma_coefficients[3] = { 0.2126f, 0.7152f, 0.0722f };
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
@@ -552,7 +552,7 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
}
/* Load luminance coefficients. */
- OCIO_configGetDefaultLumaCoefs(config, luma_coefficients);
+ OCIO_configGetDefaultLumaCoefs(config, imbuf_luma_coefficients);
}
static void colormanage_free_config(void)
@@ -1230,34 +1230,6 @@ const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
return ibuf->rect_colorspace->name;
}
-/* Convert a float RGB triplet to the correct luminance weighted average.
- *
- * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
- * based on the luminance positions of the red, green, and blue primaries.
- * Given that the internal reference space may be arbitrarily set, any
- * effort to glean the luminance coefficients must be aware of the reference
- * space primaries.
- *
- * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
- */
-
-float IMB_colormanagement_get_luminance(const float rgb[3])
-{
- return dot_v3v3(luma_coefficients, rgb);
-}
-
-/* Byte equivalent of IMB_colormanagement_get_luminance(). */
-unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
-{
- float rgbf[3];
- float val;
-
- rgb_uchar_to_float(rgbf, rgb);
- val = dot_v3v3(luma_coefficients, rgbf);
-
- return FTOCHAR(val);
-}
-
/*********************** Threaded display buffer transform routines *************************/
typedef struct DisplayBufferThread {
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
new file mode 100644
index 00000000000..8382e2a9bfa
--- /dev/null
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/imbuf/intern/colormanagement_inline.c
+ * \ingroup imbuf
+ */
+
+#ifndef __IMB_COLORMANAGEMENT_INLINE_C__
+#define __IMB_COLORMANAGEMENT_INLINE_C__
+
+#include "IMB_colormanagement_intern.h"
+#include "BLI_math_vector.h"
+
+/* Convert a float RGB triplet to the correct luminance weighted average.
+ *
+ * Grayscale, or Luma is a distillation of RGB data values down to a weighted average
+ * based on the luminance positions of the red, green, and blue primaries.
+ * Given that the internal reference space may be arbitrarily set, any
+ * effort to glean the luminance coefficients must be aware of the reference
+ * space primaries.
+ *
+ * See http://wiki.blender.org/index.php/User:Nazg-gul/ColorManagement#Luminance
+ */
+
+float IMB_colormanagement_get_luminance(const float rgb[3])
+{
+ return dot_v3v3(imbuf_luma_coefficients, rgb);
+}
+
+/* Byte equivalent of IMB_colormanagement_get_luminance(). */
+unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char rgb[3])
+{
+ float rgbf[3];
+ float val;
+
+ rgb_uchar_to_float(rgbf, rgb);
+ val = dot_v3v3(imbuf_luma_coefficients, rgbf);
+
+ return FTOCHAR(val);
+}
+
+#endif /* __IMB_COLORMANAGEMENT_INLINE_H__ */
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
index 28f31fcad8b..dd4ae3e518e 100644
--- a/source/blender/imbuf/intern/dds/ColorBlock.cpp
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -38,6 +38,7 @@
#include <Image.h>
#include <Common.h>
+#if 0
// Get approximate luminance.
inline static uint colorLuminance(Color32 c)
{
@@ -49,6 +50,7 @@
{
return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b);
}
+#endif
/// Default constructor.
@@ -86,8 +88,8 @@ void ColorBlock::init(const Image *img, uint x, uint y)
void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y)
{
- const uint bw = min(w - x, 4U);
- const uint bh = min(h - y, 4U);
+ const uint bw = MIN(w - x, 4U);
+ const uint bh = MIN(h - y, 4U);
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
@@ -107,8 +109,8 @@ void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y)
void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y)
{
- const uint bw = min(w - x, 4U);
- const uint bh = min(h - y, 4U);
+ const uint bw = MIN(w - x, 4U);
+ const uint bh = MIN(h - y, 4U);
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
@@ -124,10 +126,10 @@ void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y)
const uint idx = ((y + by) * w + x + bx);
Color32 & c = color(e, i);
- c.r = uint8(255 * clamp(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes?
- c.g = uint8(255 * clamp(data[idx + 1 * srcPlane], 0.0f, 1.0f));
- c.b = uint8(255 * clamp(data[idx + 2 * srcPlane], 0.0f, 1.0f));
- c.a = uint8(255 * clamp(data[idx + 3 * srcPlane], 0.0f, 1.0f));
+ c.r = uint8(255 * CLAMP(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes?
+ c.g = uint8(255 * CLAMP(data[idx + 1 * srcPlane], 0.0f, 1.0f));
+ c.b = uint8(255 * CLAMP(data[idx + 2 * srcPlane], 0.0f, 1.0f));
+ c.a = uint8(255 * CLAMP(data[idx + 3 * srcPlane], 0.0f, 1.0f));
}
}
}
diff --git a/source/blender/imbuf/intern/dds/Common.h b/source/blender/imbuf/intern/dds/Common.h
index ab929b82264..b1beb3f3a1b 100644
--- a/source/blender/imbuf/intern/dds/Common.h
+++ b/source/blender/imbuf/intern/dds/Common.h
@@ -28,14 +28,14 @@
#ifndef __COMMON_H__
#define __COMMON_H__
-#ifndef min
-#define min(a,b) ((a) <= (b) ? (a) : (b))
+#ifndef MIN
+#define MIN(a,b) ((a) <= (b) ? (a) : (b))
#endif
-#ifndef max
-#define max(a,b) ((a) >= (b) ? (a) : (b))
+#ifndef MAX
+#define MAX(a,b) ((a) >= (b) ? (a) : (b))
#endif
-#ifndef clamp
-#define clamp(x,a,b) min(max((x), (a)), (b))
+#ifndef CLAMP
+#define CLAMP(x,a,b) MIN(MAX((x), (a)), (b))
#endif
template<typename T>
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
index 6bf82776afe..a4281514e39 100644
--- a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -83,7 +83,7 @@ static const uint FOURCC_RXGB = DDS_MAKEFOURCC('R', 'X', 'G', 'B');
static const uint FOURCC_ATI1 = DDS_MAKEFOURCC('A', 'T', 'I', '1');
static const uint FOURCC_ATI2 = DDS_MAKEFOURCC('A', 'T', 'I', '2');
-static const uint FOURCC_A2XY = DDS_MAKEFOURCC('A', '2', 'X', 'Y');
+//static const uint FOURCC_A2XY = DDS_MAKEFOURCC('A', '2', 'X', 'Y');
static const uint FOURCC_DX10 = DDS_MAKEFOURCC('D', 'X', '1', '0');
@@ -107,25 +107,25 @@ static const uint D3DFMT_X8B8G8R8 = 33;
static const uint D3DFMT_G16R16 = 34;
static const uint D3DFMT_A2R10G10B10 = 35;
-static const uint D3DFMT_A16B16G16R16 = 36;
+//static const uint D3DFMT_A16B16G16R16 = 36;
// Palette formats.
-static const uint D3DFMT_A8P8 = 40;
-static const uint D3DFMT_P8 = 41;
+//static const uint D3DFMT_A8P8 = 40;
+//static const uint D3DFMT_P8 = 41;
// Luminance formats.
static const uint D3DFMT_L8 = 50;
-static const uint D3DFMT_A8L8 = 51;
-static const uint D3DFMT_A4L4 = 52;
+//static const uint D3DFMT_A8L8 = 51;
+//static const uint D3DFMT_A4L4 = 52;
static const uint D3DFMT_L16 = 81;
// Floating point formats
-static const uint D3DFMT_R16F = 111;
-static const uint D3DFMT_G16R16F = 112;
-static const uint D3DFMT_A16B16G16R16F = 113;
-static const uint D3DFMT_R32F = 114;
-static const uint D3DFMT_G32R32F = 115;
-static const uint D3DFMT_A32B32G32R32F = 116;
+//static const uint D3DFMT_R16F = 111;
+//static const uint D3DFMT_G16R16F = 112;
+//static const uint D3DFMT_A16B16G16R16F = 113;
+//static const uint D3DFMT_R32F = 114;
+//static const uint D3DFMT_G32R32F = 115;
+//static const uint D3DFMT_A32B32G32R32F = 116;
static const uint DDSD_CAPS = 0x00000001U;
static const uint DDSD_PIXELFORMAT = 0x00001000U;
@@ -1102,8 +1102,8 @@ void DirectDrawSurface::mipmap(Image *img, uint face, uint mipmap)
// Compute width and height.
for (uint m = 0; m < mipmap; m++)
{
- w = max(1U, w / 2);
- h = max(1U, h / 2);
+ w = MAX(1U, w / 2);
+ h = MAX(1U, h / 2);
}
img->allocate(w, h);
@@ -1223,9 +1223,9 @@ void DirectDrawSurface::readBlockImage(Image *img)
readBlock(&block);
// Write color block.
- for (uint y = 0; y < min(4U, h-4*by); y++)
+ for (uint y = 0; y < MIN(4U, h-4*by); y++)
{
- for (uint x = 0; x < min(4U, w-4*bx); x++)
+ for (uint x = 0; x < MIN(4U, w-4*bx); x++)
{
img->pixel(4*bx+x, 4*by+y) = block.color(x, y);
}
@@ -1240,7 +1240,7 @@ static Color32 buildNormal(uint8 x, uint8 y)
float ny = 2 * (y / 255.0f) - 1;
float nz = 0.0f;
if (1 - nx*nx - ny*ny > 0) nz = sqrt(1 - nx*nx - ny*ny);
- uint8 z = clamp(int(255.0f * (nz + 1) / 2.0f), 0, 255);
+ uint8 z = CLAMP(int(255.0f * (nz + 1) / 2.0f), 0, 255);
return Color32(x, y, z);
}
@@ -1379,9 +1379,9 @@ uint DirectDrawSurface::mipmapSize(uint mipmap) const
for (uint m = 0; m < mipmap; m++)
{
- w = max(1U, w / 2);
- h = max(1U, h / 2);
- d = max(1U, d / 2);
+ w = MAX(1U, w / 2);
+ h = MAX(1U, h / 2);
+ d = MAX(1U, d / 2);
}
if (header.pf.flags & DDPF_FOURCC)
diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp
index 4f63d17dc90..604796d1705 100644
--- a/source/blender/imbuf/intern/dds/FlipDXT.cpp
+++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp
@@ -246,8 +246,8 @@ int FlipDXTCImage(unsigned int width, unsigned int height, unsigned int levels,
// mip levels are contiguous.
data += block_bytes * blocks;
- mip_width = max(1U, mip_width >> 1);
- mip_height = max(1U, mip_height >> 1);
+ mip_width = MAX(1U, mip_width >> 1);
+ mip_height = MAX(1U, mip_height >> 1);
}
return 1;
diff --git a/source/blender/imbuf/intern/dds/Image.cpp b/source/blender/imbuf/intern/dds/Image.cpp
index 6954030aaa2..363af61b907 100644
--- a/source/blender/imbuf/intern/dds/Image.cpp
+++ b/source/blender/imbuf/intern/dds/Image.cpp
@@ -76,7 +76,7 @@ uint Image::height() const
const Color32 * Image::scanline(uint h) const
{
if (h >= m_height) {
- printf("DDS: scanline beyond dimensions of image");
+ printf("DDS: scanline beyond dimensions of image\n");
return m_data;
}
return m_data + h * m_width;
@@ -85,7 +85,7 @@ const Color32 * Image::scanline(uint h) const
Color32 * Image::scanline(uint h)
{
if (h >= m_height) {
- printf("DDS: scanline beyond dimensions of image");
+ printf("DDS: scanline beyond dimensions of image\n");
return m_data;
}
return m_data + h * m_width;
@@ -104,7 +104,7 @@ Color32 * Image::pixels()
const Color32 & Image::pixel(uint idx) const
{
if (idx >= m_width * m_height) {
- printf("DDS: pixel beyond dimensions of image");
+ printf("DDS: pixel beyond dimensions of image\n");
return m_data[0];
}
return m_data[idx];
@@ -113,7 +113,7 @@ const Color32 & Image::pixel(uint idx) const
Color32 & Image::pixel(uint idx)
{
if (idx >= m_width * m_height) {
- printf("DDS: pixel beyond dimensions of image");
+ printf("DDS: pixel beyond dimensions of image\n");
return m_data[0];
}
return m_data[idx];
diff --git a/source/blender/imbuf/intern/dds/SConscript b/source/blender/imbuf/intern/dds/SConscript
deleted file mode 100644
index 960e15f8e55..00000000000
--- a/source/blender/imbuf/intern/dds/SConscript
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-source_files = ['dds_api.cpp', 'DirectDrawSurface.cpp', 'Stream.cpp', 'BlockDXT.cpp', 'ColorBlock.cpp', 'Image.cpp', 'FlipDXT.cpp']
-
-incs = [
- '.',
- '..',
- '../..',
- '../../../makesdna',
- '../../../blenkernel',
- '../../../blenlib',
- 'intern/include',
- '#/intern/guardedalloc',
- '#/intern/utfconv'
- ]
-
-
-defs = ['WITH_DDS']
-
-env.BlenderLib ('bf_imbuf_dds', source_files, incs, defs, libtype=['core','player'], priority = [230,190])
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index c963609b321..12e03f55450 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -25,6 +25,10 @@
*/
+extern "C" {
+#include "BLI_utildefines.h"
+}
+
#include <stddef.h>
#include <dds_api.h>
#include <Stream.h>
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index ef445239491..26ced49a333 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -203,54 +203,97 @@ void imb_filterx(struct ImBuf *ibuf)
}
}
-void IMB_filterN(ImBuf *out, ImBuf *in)
+static void imb_filterN(ImBuf *out, ImBuf *in)
{
- register char *row1, *row2, *row3;
- register char *cp, *r11, *r13, *r21, *r23, *r31, *r33;
- int rowlen, x, y;
-
- rowlen = in->x;
-
- /* generate 32-bit version for float images if it is not already generated by other space */
- if (in->rect == NULL)
- IMB_rect_from_float(in);
+ BLI_assert(out->channels == in->channels);
+ BLI_assert(out->x == in->x && out->y == out->y);
+
+ const int channels = in->channels;
+ const int rowlen = in->x;
- for (y = 0; y < in->y; y++) {
- /* setup rows */
- row2 = (char *)(in->rect + y * rowlen);
- row1 = (y == 0) ? row2 : row2 - 4 * rowlen;
- row3 = (y == in->y - 1) ? row2 : row2 + 4 * rowlen;
-
- cp = (char *)(out->rect + y * rowlen);
-
- for (x = 0; x < rowlen; x++) {
- if (x == 0) {
- r11 = row1;
- r21 = row2;
- r31 = row3;
- }
- else {
- r11 = row1 - 4;
- r21 = row2 - 4;
- r31 = row3 - 4;
- }
+ if (in->rect && out->rect) {
+ for (int y = 0; y < in->y; y++) {
+ /* setup rows */
+ const char *row2 = (const char *)in->rect + y * channels * rowlen;
+ const char *row1 = (y == 0) ? row2 : row2 - channels * rowlen;
+ const char *row3 = (y == in->y - 1) ? row2 : row2 + channels * rowlen;
+
+ char *cp = (char *)out->rect + y * channels * rowlen;
+
+ for (int x = 0; x < rowlen; x++) {
+ const char *r11, *r13, *r21, *r23, *r31, *r33;
+
+ if (x == 0) {
+ r11 = row1;
+ r21 = row2;
+ r31 = row3;
+ }
+ else {
+ r11 = row1 - channels;
+ r21 = row2 - channels;
+ r31 = row3 - channels;
+ }
- if (x == rowlen - 1) {
- r13 = row1;
- r23 = row2;
- r33 = row3;
- }
- else {
- r13 = row1 + 4;
- r23 = row2 + 4;
- r33 = row3 + 4;
+ if (x == rowlen - 1) {
+ r13 = row1;
+ r23 = row2;
+ r33 = row3;
+ }
+ else {
+ r13 = row1 + channels;
+ r23 = row2 + channels;
+ r33 = row3 + channels;
+ }
+
+ cp[0] = (r11[0] + 2 * row1[0] + r13[0] + 2 * r21[0] + 4 * row2[0] + 2 * r23[0] + r31[0] + 2 * row3[0] + r33[0]) >> 4;
+ cp[1] = (r11[1] + 2 * row1[1] + r13[1] + 2 * r21[1] + 4 * row2[1] + 2 * r23[1] + r31[1] + 2 * row3[1] + r33[1]) >> 4;
+ cp[2] = (r11[2] + 2 * row1[2] + r13[2] + 2 * r21[2] + 4 * row2[2] + 2 * r23[2] + r31[2] + 2 * row3[2] + r33[2]) >> 4;
+ cp[3] = (r11[3] + 2 * row1[3] + r13[3] + 2 * r21[3] + 4 * row2[3] + 2 * r23[3] + r31[3] + 2 * row3[3] + r33[3]) >> 4;
+ cp += channels; row1 += channels; row2 += channels; row3 += channels;
}
+ }
+ }
+
+ if (in->rect_float && out->rect_float) {
+ for (int y = 0; y < in->y; y++) {
+ /* setup rows */
+ const float *row2 = (const float *)in->rect_float + y * channels * rowlen;
+ const float *row1 = (y == 0) ? row2 : row2 - channels * rowlen;
+ const float *row3 = (y == in->y - 1) ? row2 : row2 + channels * rowlen;
+
+ float *cp = (float *)out->rect_float + y * channels * rowlen;
+
+ for (int x = 0; x < rowlen; x++) {
+ const float *r11, *r13, *r21, *r23, *r31, *r33;
- cp[0] = (r11[0] + 2 * row1[0] + r13[0] + 2 * r21[0] + 4 * row2[0] + 2 * r23[0] + r31[0] + 2 * row3[0] + r33[0]) >> 4;
- cp[1] = (r11[1] + 2 * row1[1] + r13[1] + 2 * r21[1] + 4 * row2[1] + 2 * r23[1] + r31[1] + 2 * row3[1] + r33[1]) >> 4;
- cp[2] = (r11[2] + 2 * row1[2] + r13[2] + 2 * r21[2] + 4 * row2[2] + 2 * r23[2] + r31[2] + 2 * row3[2] + r33[2]) >> 4;
- cp[3] = (r11[3] + 2 * row1[3] + r13[3] + 2 * r21[3] + 4 * row2[3] + 2 * r23[3] + r31[3] + 2 * row3[3] + r33[3]) >> 4;
- cp += 4; row1 += 4; row2 += 4; row3 += 4;
+ if (x == 0) {
+ r11 = row1;
+ r21 = row2;
+ r31 = row3;
+ }
+ else {
+ r11 = row1 - channels;
+ r21 = row2 - channels;
+ r31 = row3 - channels;
+ }
+
+ if (x == rowlen - 1) {
+ r13 = row1;
+ r23 = row2;
+ r33 = row3;
+ }
+ else {
+ r13 = row1 + channels;
+ r23 = row2 + channels;
+ r33 = row3 + channels;
+ }
+
+ cp[0] = (r11[0] + 2 * row1[0] + r13[0] + 2 * r21[0] + 4 * row2[0] + 2 * r23[0] + r31[0] + 2 * row3[0] + r33[0]) * (1.0f / 16.0f);
+ cp[1] = (r11[1] + 2 * row1[1] + r13[1] + 2 * r21[1] + 4 * row2[1] + 2 * r23[1] + r31[1] + 2 * row3[1] + r33[1]) * (1.0f / 16.0f);
+ cp[2] = (r11[2] + 2 * row1[2] + r13[2] + 2 * r21[2] + 4 * row2[2] + 2 * r23[2] + r31[2] + 2 * row3[2] + r33[2]) * (1.0f / 16.0f);
+ cp[3] = (r11[3] + 2 * row1[3] + r13[3] + 2 * r21[3] + 4 * row2[3] + 2 * r23[3] + r31[3] + 2 * row3[3] + r33[3]) * (1.0f / 16.0f);
+ cp += channels; row1 += channels; row2 += channels; row3 += channels;
+ }
}
}
}
@@ -477,8 +520,8 @@ void IMB_remakemipmap(ImBuf *ibuf, int use_filter)
if (ibuf->mipmap[curmap]) {
if (use_filter) {
- ImBuf *nbuf = IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
- IMB_filterN(nbuf, hbuf);
+ ImBuf *nbuf = IMB_allocImBuf(hbuf->x, hbuf->y, hbuf->planes, hbuf->flags);
+ imb_filterN(nbuf, hbuf);
imb_onehalf_no_alloc(ibuf->mipmap[curmap], nbuf);
IMB_freeImBuf(nbuf);
}
@@ -514,8 +557,8 @@ void IMB_makemipmap(ImBuf *ibuf, int use_filter)
while (curmap < IMB_MIPMAP_LEVELS) {
if (use_filter) {
- ImBuf *nbuf = IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect);
- IMB_filterN(nbuf, hbuf);
+ ImBuf *nbuf = IMB_allocImBuf(hbuf->x, hbuf->y, hbuf->planes, hbuf->flags);
+ imb_filterN(nbuf, hbuf);
ibuf->mipmap[curmap] = IMB_onehalf(nbuf);
IMB_freeImBuf(nbuf);
}
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index d44f0dc86f4..9e4bb957f66 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -324,7 +324,7 @@ void nearest_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, in
/*********************** Threaded image processing *************************/
-static void processor_apply_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
+static void processor_apply_func(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
{
void (*do_thread) (void *) = (void (*) (void *)) BLI_task_pool_userdata(pool);
do_thread(taskdata);
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index ac57b095800..e1b3abcf2f6 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -519,7 +519,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
rv->c->pix_fmt = rv->codec->pix_fmts[0];
}
else {
- rv->c->pix_fmt = PIX_FMT_YUVJ420P;
+ rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P;
}
rv->c->sample_aspect_ratio =
@@ -554,7 +554,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
if (st->codec->width != width || st->codec->height != height ||
st->codec->pix_fmt != rv->c->pix_fmt)
{
- rv->frame = avcodec_alloc_frame();
+ rv->frame = av_frame_alloc();
avpicture_fill((AVPicture *) rv->frame,
MEM_mallocN(avpicture_get_size(
rv->c->pix_fmt,
@@ -905,7 +905,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
memset(&next_packet, 0, sizeof(AVPacket));
- in_frame = avcodec_alloc_frame();
+ in_frame = av_frame_alloc();
stream_size = avio_size(context->iFormatCtx->pb);
@@ -1167,12 +1167,13 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecod
char filename[FILE_MAX];
get_proxy_filename(anim, proxy_size, filename, false);
- if (BLI_gset_haskey(file_list, filename)) {
- proxy_sizes_to_build &= ~proxy_size;
- printf("Proxy: %s already registered for generation, skipping\n", filename);
+ void **filename_key_p;
+ if (!BLI_gset_ensure_p_ex(file_list, filename, &filename_key_p)) {
+ *filename_key_p = BLI_strdup(filename);
}
else {
- BLI_gset_insert(file_list, BLI_strdup(filename));
+ proxy_sizes_to_build &= ~proxy_size;
+ printf("Proxy: %s already registered for generation, skipping\n", filename);
}
}
}
diff --git a/source/blender/imbuf/intern/indexer_dv.c b/source/blender/imbuf/intern/indexer_dv.c
deleted file mode 100644
index f456fc420b2..00000000000
--- a/source/blender/imbuf/intern/indexer_dv.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Peter Schlaile <peter [at] schlaile [dot] de> 2011
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/imbuf/intern/indexer_dv.c
- * \ingroup imbuf
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_path_util.h"
-
-#include "IMB_indexer.h"
-#include <time.h>
-
-typedef struct indexer_dv_bitstream {
- unsigned char *buffer;
- int bit_pos;
-} indexer_dv_bitstream;
-
-static indexer_dv_bitstream bitstream_new(unsigned char *buffer_)
-{
- indexer_dv_bitstream rv;
-
- rv.buffer = buffer_;
- rv.bit_pos = 0;
-
- return rv;
-}
-
-static unsigned long bitstream_get_bits(indexer_dv_bitstream *This, int num)
-{
- int byte_pos = This->bit_pos >> 3;
- unsigned long i =
- This->buffer[byte_pos] | (This->buffer[byte_pos + 1] << 8) |
- (This->buffer[byte_pos + 2] << 16) |
- (This->buffer[byte_pos + 3] << 24);
- int rval = (i >> (This->bit_pos & 0x7)) & ((1 << num) - 1);
- This->bit_pos += num;
- return rval;
-}
-
-static int parse_num(indexer_dv_bitstream *b, int numbits)
-{
- return bitstream_get_bits(b, numbits);
-}
-
-static int parse_bcd(indexer_dv_bitstream *b, int n)
-{
- char s[256];
- char *p = s + (n + 3) / 4;
-
- *p-- = 0;
-
- while (n > 4) {
- char a;
- int v = bitstream_get_bits(b, 4);
-
- n -= 4;
- a = '0' + v;
-
- if (a > '9') {
- bitstream_get_bits(b, n);
- return -1;
- }
-
- *p-- = a;
- }
- if (n) {
- char a;
- int v = bitstream_get_bits(b, n);
- a = '0' + v;
- if (a > '9') {
- return -1;
- }
- *p-- = a;
- }
-
- return atol(s);
-}
-
-typedef struct indexer_dv_context {
- int rec_curr_frame;
- int rec_curr_second;
- int rec_curr_minute;
- int rec_curr_hour;
-
- int rec_curr_day;
- int rec_curr_month;
- int rec_curr_year;
-
- char got_record_date;
- char got_record_time;
-
- time_t ref_time_read;
- time_t ref_time_read_new;
- int curr_frame;
-
- time_t gap_start;
- int gap_frame;
-
- int frameno_offset;
-
- anim_index_entry backbuffer[31];
- int fsize;
-
- anim_index_builder *idx;
-} indexer_dv_context;
-
-static void parse_packet(indexer_dv_context *This, unsigned char *p)
-{
- indexer_dv_bitstream b;
- int type = p[0];
-
- b = bitstream_new(p + 1);
-
- switch (type) {
- case 0x62: /* Record date */
- parse_num(&b, 8);
- This->rec_curr_day = parse_bcd(&b, 6);
- parse_num(&b, 2);
- This->rec_curr_month = parse_bcd(&b, 5);
- parse_num(&b, 3);
- This->rec_curr_year = parse_bcd(&b, 8);
- if (This->rec_curr_year < 25) {
- This->rec_curr_year += 2000;
- }
- else {
- This->rec_curr_year += 1900;
- }
- This->got_record_date = 1;
- break;
- case 0x63: /* Record time */
- This->rec_curr_frame = parse_bcd(&b, 6);
- parse_num(&b, 2);
- This->rec_curr_second = parse_bcd(&b, 7);
- parse_num(&b, 1);
- This->rec_curr_minute = parse_bcd(&b, 7);
- parse_num(&b, 1);
- This->rec_curr_hour = parse_bcd(&b, 6);
- This->got_record_time = 1;
- break;
- }
-}
-
-static void parse_header_block(indexer_dv_context *This, unsigned char *target)
-{
- int i;
- for (i = 3; i < 80; i += 5) {
- if (target[i] != 0xff) {
- parse_packet(This, target + i);
- }
- }
-}
-
-static void parse_subcode_blocks(
- indexer_dv_context *This, unsigned char *target)
-{
- int i, j;
-
- for (j = 0; j < 2; j++) {
- for (i = 3; i < 80; i += 5) {
- if (target[i] != 0xff) {
- parse_packet(This, target + i);
- }
- }
- }
-}
-
-static void parse_vaux_blocks(
- indexer_dv_context *This, unsigned char *target)
-{
- int i, j;
-
- for (j = 0; j < 3; j++) {
- for (i = 3; i < 80; i += 5) {
- if (target[i] != 0xff) {
- parse_packet(This, target + i);
- }
- }
- target += 80;
- }
-}
-
-static void parse_audio_headers(
- indexer_dv_context *This, unsigned char *target)
-{
- int i;
-
- for (i = 0; i < 9; i++) {
- if (target[3] != 0xff) {
- parse_packet(This, target + 3);
- }
- target += 16 * 80;
- }
-}
-
-static void parse_frame(indexer_dv_context *This,
- unsigned char *framebuffer, int isPAL)
-{
- int numDIFseq = isPAL ? 12 : 10;
- unsigned char *target = framebuffer;
- int ds;
-
- for (ds = 0; ds < numDIFseq; ds++) {
- parse_header_block(This, target);
- target += 1 * 80;
- parse_subcode_blocks(This, target);
- target += 2 * 80;
- parse_vaux_blocks(This, target);
- target += 3 * 80;
- parse_audio_headers(This, target);
- target += 144 * 80;
- }
-}
-
-static void inc_frame(int *frame, time_t *t, int isPAL)
-{
- if ((isPAL && *frame >= 25) || (!isPAL && *frame >= 30)) {
- fprintf(stderr, "Ouchie: inc_frame: invalid_frameno: %d\n",
- *frame);
- }
- (*frame)++;
- if (isPAL && *frame >= 25) {
- (*t)++;
- *frame = 0;
- }
- else if (!isPAL && *frame >= 30) {
- (*t)++;
- *frame = 0;
- }
-}
-
-static void write_index(indexer_dv_context *This, anim_index_entry *entry)
-{
- IMB_index_builder_add_entry(
- This->idx, entry->frameno + This->frameno_offset,
- entry->seek_pos, entry->seek_pos_dts, entry->pts);
-}
-
-static void fill_gap(indexer_dv_context *This, int isPAL)
-{
- int i;
-
- for (i = 0; i < This->fsize; i++) {
- if (This->gap_start == This->ref_time_read &&
- This->gap_frame == This->curr_frame)
- {
- fprintf(stderr,
- "indexer_dv::fill_gap: "
- "can't seek backwards !\n");
- break;
- }
- inc_frame(&This->gap_frame, &This->gap_start, isPAL);
- }
-
- while (This->gap_start != This->ref_time_read ||
- This->gap_frame != This->curr_frame)
- {
- inc_frame(&This->gap_frame, &This->gap_start, isPAL);
- This->frameno_offset++;
- }
-
- for (i = 0; i < This->fsize; i++) {
- write_index(This, This->backbuffer + i);
- }
- This->fsize = 0;
-}
-
-static void proc_frame(indexer_dv_context *This,
- unsigned char *UNUSED(framebuffer), int isPAL)
-{
- struct tm recDate;
- time_t t;
-
- if (!This->got_record_date || !This->got_record_time) {
- return;
- }
-
- recDate.tm_sec = This->rec_curr_second;
- recDate.tm_min = This->rec_curr_minute;
- recDate.tm_hour = This->rec_curr_hour;
- recDate.tm_mday = This->rec_curr_day;
- recDate.tm_mon = This->rec_curr_month - 1;
- recDate.tm_year = This->rec_curr_year - 1900;
- recDate.tm_wday = -1;
- recDate.tm_yday = -1;
- recDate.tm_isdst = -1;
-
- t = mktime(&recDate);
- if (t == -1) {
- return;
- }
-
- This->ref_time_read_new = t;
-
- if (This->ref_time_read < 0) {
- This->ref_time_read = This->ref_time_read_new;
- This->curr_frame = 0;
- }
- else {
- if (This->ref_time_read_new - This->ref_time_read == 1) {
- This->curr_frame = 0;
- This->ref_time_read = This->ref_time_read_new;
- if (This->gap_frame >= 0) {
- fill_gap(This, isPAL);
- This->gap_frame = -1;
- }
- }
- else if (This->ref_time_read_new == This->ref_time_read) {
- /* do nothing */
- }
- else {
- This->gap_start = This->ref_time_read;
- This->gap_frame = This->curr_frame;
- This->ref_time_read = This->ref_time_read_new;
- This->curr_frame = -1;
- }
- }
-}
-
-static void indexer_dv_proc_frame(anim_index_builder *idx,
- unsigned char *buffer,
- int UNUSED(data_size),
- struct anim_index_entry *entry)
-{
- int isPAL;
-
- indexer_dv_context *This = (indexer_dv_context *) idx->private_data;
-
- isPAL = (buffer[3] & 0x80);
-
- This->got_record_date = false;
- This->got_record_time = false;
-
- parse_frame(This, buffer, isPAL);
- proc_frame(This, buffer, isPAL);
-
- if (This->curr_frame >= 0) {
- write_index(This, entry);
- inc_frame(&This->curr_frame, &This->ref_time_read, isPAL);
- }
- else {
- This->backbuffer[This->fsize++] = *entry;
- if (This->fsize >= 31) {
- int i;
-
- fprintf(stderr, "indexer_dv::indexer_dv_proc_frame: "
- "backbuffer overrun, emergency flush");
-
- for (i = 0; i < This->fsize; i++) {
- write_index(This, This->backbuffer + i);
- }
- This->fsize = 0;
- }
- }
-}
-
-static void indexer_dv_delete(anim_index_builder *idx)
-{
- int i = 0;
- indexer_dv_context *This = (indexer_dv_context *) idx->private_data;
-
- for (i = 0; i < This->fsize; i++) {
- write_index(This, This->backbuffer + i);
- }
-
- MEM_freeN(This);
-}
-
-static void UNUSED_FUNCTION(IMB_indexer_dv_new)(anim_index_builder *idx)
-{
- indexer_dv_context *rv = MEM_callocN(
- sizeof(indexer_dv_context), "index_dv builder context");
-
- rv->ref_time_read = -1;
- rv->curr_frame = -1;
- rv->gap_frame = -1;
- rv->idx = idx;
-
- idx->private_data = rv;
- idx->proc_frame = indexer_dv_proc_frame;
- idx->delete_priv_data = indexer_dv_delete;
-}
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 570ca5ba06e..390f2502ee7 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -63,12 +63,12 @@ enum {
DCP_CINEMA4K = 4,
};
-static int check_jp2(const unsigned char *mem) /* J2K_CFMT */
+static bool check_jp2(const unsigned char *mem) /* J2K_CFMT */
{
return memcmp(JP2_HEAD, mem, sizeof(JP2_HEAD)) ? 0 : 1;
}
-static int check_j2k(const unsigned char *mem) /* J2K_CFMT */
+static bool check_j2k(const unsigned char *mem) /* J2K_CFMT */
{
return memcmp(J2K_HEAD, mem, sizeof(J2K_HEAD)) ? 0 : 1;
}
@@ -133,7 +133,7 @@ struct ImBuf *imb_jp2_decode(const unsigned char *mem, size_t size, int flags, c
unsigned int i, i_next, w, h, planes;
unsigned int y;
int *r, *g, *b, *a; /* matching 'opj_image_comp.data' type */
- int is_jp2, is_j2k;
+ bool is_jp2, is_j2k;
opj_dparameters_t parameters; /* decompression parameters */
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index ff2a9767386..35c7b6363a1 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -54,12 +54,6 @@
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
-// #define IS_jpg(x) (x->ftype & JPG) // UNUSED
-#define IS_stdjpg(x) ((x->foptions.flag & JPG_MSK) == JPG_STD)
-// #define IS_vidjpg(x) ((x->foptions & JPG_MSK) == JPG_VID) // UNUSED
-#define IS_jstjpg(x) ((x->foptions.flag & JPG_MSK) == JPG_JST)
-#define IS_maxjpg(x) ((x->foptions.flag & JPG_MSK) == JPG_MAX)
-
/* the types are from the jpeg lib */
static void jpeg_error(j_common_ptr cinfo) ATTR_NORETURN;
static void init_source(j_decompress_ptr cinfo);
@@ -70,22 +64,8 @@ static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, s
static boolean handle_app1(j_decompress_ptr cinfo);
static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags);
-
-/*
- * In principle there are 4 jpeg formats.
- *
- * 1. jpeg - standard printing, u & v at quarter of resolution
- * 2. jvid - standard video, u & v half resolution, frame not interlaced
- *
- * type 3 is unsupported as of jul 05 2000 Frank.
- *
- * 3. jstr - as 2, but written in 2 separate fields
- *
- * 4. jmax - no scaling in the components
- */
-
-static int jpeg_default_quality;
-static int ibuf_foptions;
+static const uchar jpeg_default_quality = 75;
+static uchar ibuf_quality;
int imb_is_a_jpeg(const unsigned char *mem)
{
@@ -254,6 +234,13 @@ static void memory_source(j_decompress_ptr cinfo, const unsigned char *buffer, s
bytes_in_buffer--; \
V += GETJOCTET(*next_input_byte++); )
+struct NeoGeo_Word {
+ uchar pad1;
+ uchar pad2;
+ uchar pad3;
+ uchar quality;
+} ;
+BLI_STATIC_ASSERT(sizeof(struct NeoGeo_Word) == 4, "Must be 4 bytes");
static boolean handle_app1(j_decompress_ptr cinfo)
{
@@ -267,13 +254,19 @@ static boolean handle_app1(j_decompress_ptr cinfo)
length -= 2;
if (length < 16) {
- for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return false);
+ for (i = 0; i < length; i++) {
+ INPUT_BYTE(cinfo, neogeo[i], return false);
+ }
length = 0;
- if (STREQLEN(neogeo, "NeoGeo", 6)) memcpy(&ibuf_foptions, neogeo + 6, 4);
- ibuf_foptions = BIG_LONG(ibuf_foptions);
+ if (STREQLEN(neogeo, "NeoGeo", 6)) {
+ struct NeoGeo_Word *neogeo_word = (struct NeoGeo_Word *)(neogeo + 6);
+ ibuf_quality = neogeo_word->quality;
+ }
}
INPUT_SYNC(cinfo); /* do before skip_input_data */
- if (length > 0) (*cinfo->src->skip_input_data)(cinfo, length);
+ if (length > 0) {
+ (*cinfo->src->skip_input_data)(cinfo, length);
+ }
return true;
}
@@ -290,7 +283,7 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
char *str, *key, *value;
/* install own app1 handler */
- ibuf_foptions = 0;
+ ibuf_quality = jpeg_default_quality;
jpeg_set_marker_processor(cinfo, 0xe1, handle_app1);
cinfo->dct_method = JDCT_FLOAT;
jpeg_save_markers(cinfo, JPEG_COM, 0xffff);
@@ -304,14 +297,6 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
jpeg_start_decompress(cinfo);
- if (ibuf_foptions == 0) {
- ibuf_foptions = JPG_STD;
- if (cinfo->max_v_samp_factor == 1) {
- if (cinfo->max_h_samp_factor == 1) ibuf_foptions = JPG_MAX;
- else ibuf_foptions = JPG_VID;
- }
- }
-
if (flags & IB_test) {
jpeg_abort_decompress(cinfo);
ibuf = IMB_allocImBuf(x, y, 8 * depth, 0);
@@ -436,7 +421,7 @@ next_stamp_marker:
jpeg_destroy((j_common_ptr) cinfo);
if (ibuf) {
ibuf->ftype = IMB_FTYPE_JPG;
- ibuf->foptions.flag = ibuf_foptions;
+ ibuf->foptions.quality = MIN2(ibuf_quality, 100);
}
}
@@ -481,16 +466,16 @@ static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
uchar *rect;
int x, y;
char neogeo[128];
+ struct NeoGeo_Word *neogeo_word;
char *text;
jpeg_start_compress(cinfo, true);
strcpy(neogeo, "NeoGeo");
- ibuf_foptions = BIG_LONG((((int)ibuf->foptions.flag) << 8) | (int)ibuf->foptions.quality);
-
- memcpy(neogeo + 6, &ibuf_foptions, 4);
+ neogeo_word = (struct NeoGeo_Word *)(neogeo + 6);
+ memset(neogeo_word, 0, sizeof(*neogeo_word));
+ neogeo_word->quality = ibuf->foptions.quality;
jpeg_write_marker(cinfo, 0xe1, (JOCTET *) neogeo, 10);
-
if (ibuf->metadata) {
IDProperty *prop;
/* key + max value + "Blender" */
@@ -613,113 +598,8 @@ static int save_stdjpeg(const char *name, struct ImBuf *ibuf)
struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
struct my_error_mgr jerr;
- if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
- jpeg_default_quality = 75;
-
- cinfo->err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = jpeg_error;
-
- /* Establish the setjmp return context for jpeg_error to use. */
- if (setjmp(jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error.
- * We need to clean up the JPEG object, close the input file, and return.
- */
- jpeg_destroy_compress(cinfo);
- fclose(outfile);
- remove(name);
+ if ((outfile = BLI_fopen(name, "wb")) == NULL)
return 0;
- }
-
- init_jpeg(outfile, cinfo, ibuf);
-
- write_jpeg(cinfo, ibuf);
-
- fclose(outfile);
- jpeg_destroy_compress(cinfo);
-
- return 1;
-}
-
-
-static int save_vidjpeg(const char *name, struct ImBuf *ibuf)
-{
- FILE *outfile;
- struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
- struct my_error_mgr jerr;
-
- if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
- jpeg_default_quality = 90;
-
- cinfo->err = jpeg_std_error(&jerr.pub);
- jerr.pub.error_exit = jpeg_error;
-
- /* Establish the setjmp return context for jpeg_error to use. */
- if (setjmp(jerr.setjmp_buffer)) {
- /* If we get here, the JPEG code has signaled an error.
- * We need to clean up the JPEG object, close the input file, and return.
- */
- jpeg_destroy_compress(cinfo);
- fclose(outfile);
- remove(name);
- return 0;
- }
-
- init_jpeg(outfile, cinfo, ibuf);
-
- /* adjust scaling factors */
- if (cinfo->in_color_space == JCS_RGB) {
- cinfo->comp_info[0].h_samp_factor = 2;
- cinfo->comp_info[0].v_samp_factor = 1;
- }
-
- write_jpeg(cinfo, ibuf);
-
- fclose(outfile);
- jpeg_destroy_compress(cinfo);
-
- return 1;
-}
-
-static int save_jstjpeg(const char *name, struct ImBuf *ibuf)
-{
- char fieldname[1024];
- struct ImBuf *tbuf;
- int oldy, returnval;
-
- tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect);
- tbuf->ftype = ibuf->ftype;
- tbuf->foptions = ibuf->foptions;
- tbuf->flags = ibuf->flags;
-
- oldy = ibuf->y;
- ibuf->x *= 2;
- ibuf->y /= 2;
-
- IMB_rectcpy(tbuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- sprintf(fieldname, "%s.jf0", name);
-
- returnval = save_vidjpeg(fieldname, tbuf);
- if (returnval == 1) {
- IMB_rectcpy(tbuf, ibuf, 0, 0, tbuf->x, 0, ibuf->x, ibuf->y);
- sprintf(fieldname, "%s.jf1", name);
- returnval = save_vidjpeg(fieldname, tbuf);
- }
-
- ibuf->y = oldy;
- ibuf->x /= 2;
- IMB_freeImBuf(tbuf);
-
- return returnval;
-}
-
-static int save_maxjpeg(const char *name, struct ImBuf *ibuf)
-{
- FILE *outfile;
- struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
- struct my_error_mgr jerr;
-
- if ((outfile = BLI_fopen(name, "wb")) == NULL) return 0;
- jpeg_default_quality = 100;
cinfo->err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = jpeg_error;
@@ -737,12 +617,6 @@ static int save_maxjpeg(const char *name, struct ImBuf *ibuf)
init_jpeg(outfile, cinfo, ibuf);
- /* adjust scaling factors */
- if (cinfo->in_color_space == JCS_RGB) {
- cinfo->comp_info[0].h_samp_factor = 1;
- cinfo->comp_info[0].v_samp_factor = 1;
- }
-
write_jpeg(cinfo, ibuf);
fclose(outfile);
@@ -755,9 +629,5 @@ int imb_savejpeg(struct ImBuf *ibuf, const char *name, int flags)
{
ibuf->flags = flags;
- if (IS_stdjpg(ibuf)) return save_stdjpeg(name, ibuf);
- if (IS_jstjpg(ibuf)) return save_jstjpeg(name, ibuf);
- if (IS_maxjpg(ibuf)) return save_maxjpeg(name, ibuf);
- return save_vidjpeg(name, ibuf);
+ return save_stdjpeg(name, ibuf);
}
-
diff --git a/source/blender/imbuf/intern/module.c b/source/blender/imbuf/intern/module.c
index 4097deb00ed..777fe77f032 100644
--- a/source/blender/imbuf/intern/module.c
+++ b/source/blender/imbuf/intern/module.c
@@ -37,6 +37,7 @@
void IMB_init(void)
{
imb_refcounter_lock_init();
+ imb_mmap_lock_init();
imb_filetypes_init();
imb_tile_cache_init();
colormanagement_init();
@@ -47,6 +48,7 @@ void IMB_exit(void)
imb_tile_cache_exit();
imb_filetypes_exit();
colormanagement_exit();
+ imb_mmap_lock_exit();
imb_refcounter_lock_exit();
}
diff --git a/source/blender/imbuf/intern/oiio/SConscript b/source/blender/imbuf/intern/oiio/SConscript
deleted file mode 100644
index 82b47e9c46b..00000000000
--- a/source/blender/imbuf/intern/oiio/SConscript
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2013, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s):
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-source_files = ['openimageio_api.cpp']
-
-incs = ['.',
- '../../../blenkernel',
- '../../',
- '..',
- '../../../blenlib',
- 'intern/include',
- '#/intern/guardedalloc',
- '../../../makesdna',
- '#/intern/utfconv']
-
-incs += Split(env['BF_OIIO_INC'])
-
-defs = ['WITH_OPENIMAGEIO']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
- incs.append(env['BF_PTHREADS_INC'])
-
-env.BlenderLib ('bf_imbuf_openimageio', source_files, incs, defs, libtype=['core','player'], priority = [225,180])
diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
index 0a2e8742ba8..11bf45418d6 100644
--- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp
+++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp
@@ -31,11 +31,6 @@
#include <set>
-#include <openimageio_api.h>
-#include <OpenImageIO/imageio.h>
-
-OIIO_NAMESPACE_USING
-
#if defined(WIN32) && !defined(FREE_WINDOWS)
#include "utfconv.h"
#endif
@@ -53,7 +48,12 @@ extern "C"
#include "IMB_colormanagement_intern.h"
}
-using namespace std;
+#include <openimageio_api.h>
+#include <OpenImageIO/imageio.h>
+
+OIIO_NAMESPACE_USING
+
+using std::string;
typedef unsigned char uchar;
diff --git a/source/blender/imbuf/intern/openexr/SConscript b/source/blender/imbuf/intern/openexr/SConscript
deleted file mode 100644
index ac38c0458d9..00000000000
--- a/source/blender/imbuf/intern/openexr/SConscript
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-source_files = ['openexr_api.cpp']
-
-incs = ['.',
- '../../../blenkernel',
- '../../',
- '..',
- '../../../blenlib',
- 'intern/include',
- '#/intern/guardedalloc',
- '../../../makesdna',
- '#/intern/utfconv']
-
-incs += Split(env['BF_OPENEXR_INC'])
-
-defs = ['WITH_OPENEXR']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
- incs.append(env['BF_PTHREADS_INC'])
-
-env.BlenderLib ('bf_imbuf_openexr', source_files, incs, defs, libtype=['core','player'], priority = [225,180])
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index e3c02736755..47fa4c1de0c 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -32,6 +32,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
+#include <stdexcept>
#include <fstream>
#include <string>
#include <set>
@@ -70,9 +71,6 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "IMB_allocimbuf.h"
#include "IMB_metadata.h"
-#include "IMB_colormanagement.h"
-#include "IMB_colormanagement_intern.h"
-
#include "openexr_multi.h"
}
@@ -103,6 +101,11 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include <ImfPartType.h>
#include <ImfPartHelper.h>
+extern "C" {
+#include "IMB_colormanagement.h"
+#include "IMB_colormanagement_intern.h"
+}
+
using namespace Imf;
using namespace Imath;
@@ -371,9 +374,10 @@ static void openexr_header_metadata_callback(void *data, const char *propname, c
}
-static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
- const char * (*getview)(void *base, size_t view_id),
- ImBuf * (*getbuffer)(void *base, const size_t view_id))
+static bool imb_save_openexr_half(
+ ImBuf *ibuf, const char *name, const int flags, const int totviews,
+ const char * (*getview)(void *base, int view_id),
+ ImBuf *(*getbuffer)(void *base, const int view_id))
{
const int channels = ibuf->channels;
const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
@@ -385,7 +389,7 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
BLI_assert((!is_multiview) || (getview && getbuffer));
std::vector <string> views;
- size_t view_id;
+ int view_id;
try
{
@@ -418,14 +422,22 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
OutputFile file(file_stream, header);
/* we store first everything in half array */
- RGBAZ *pixels = new RGBAZ[height * width * totviews];
+ std::vector<RGBAZ> pixels(height * width * totviews);
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
for (view_id = 0; view_id < totviews; view_id ++) {
ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
const size_t offset = view_id * width * height;
- RGBAZ *to = pixels + offset;
+ RGBAZ *to = &pixels[offset];
+
+ /* TODO (dfelinto)
+ * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
+ * Multiview Render + Image Editor + OpenEXR + Multi-View
+ */
+ if (view_ibuf == NULL) {
+ throw std::runtime_error(std::string("Missing data to write to ") + name);
+ }
/* indicate used buffers */
frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF, (char *) &pixels[offset].r, xstride, ystride));
@@ -475,8 +487,6 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
file.setFrameBuffer(frameBuffer);
file.writePixels(height);
-
- delete[] pixels;
}
catch (const std::exception& exc)
{
@@ -488,9 +498,10 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
return true;
}
-static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
- const char * (*getview)(void *base, const size_t view_id),
- ImBuf * (*getbuffer)(void *base, const size_t view_id))
+static bool imb_save_openexr_float(
+ ImBuf *ibuf, const char *name, const int flags, const int totviews,
+ const char * (*getview)(void *base, const int view_id),
+ ImBuf *(*getbuffer)(void *base, const int view_id))
{
const int channels = ibuf->channels;
const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
@@ -502,7 +513,7 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag
BLI_assert((!is_multiview) || (getview && getbuffer));
std::vector <string> views;
- size_t view_id;
+ int view_id;
try
{
@@ -541,6 +552,14 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag
float *rect[4] = {NULL, NULL, NULL, NULL};
ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
+ /* TODO (dfelinto)
+ * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
+ * Multiview Render + Image Editor + OpenEXR + Multi-View
+ */
+ if (view_ibuf == NULL) {
+ throw std::runtime_error(std::string("Missing data to write to ") + name);
+ }
+
/* last scanline, stride negative */
rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
@@ -591,9 +610,10 @@ int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
}
}
-static bool imb_save_openexr_multiview(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
- const char * (*getview)(void *base, const size_t view_id),
- ImBuf * (*getbuffer)(void *base, const size_t view_id))
+static bool imb_save_openexr_multiview(
+ ImBuf *ibuf, const char *name, const int flags, const int totviews,
+ const char *(*getview)(void *base, const int view_id),
+ ImBuf *(*getbuffer)(void *base, const int view_id))
{
if (flags & IB_mem) {
printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
@@ -616,9 +636,10 @@ static bool imb_save_openexr_multiview(ImBuf *ibuf, const char *name, const int
/* Save single-layer multiview OpenEXR
* If we have more multiview formats in the future, the function below could be incorporated
* in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
-bool IMB_exr_multiview_save(ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
- const char * (*getview)(void *base, size_t view_id),
- ImBuf * (*getbuffer)(void *base, const size_t view_id))
+bool IMB_exr_multiview_save(
+ ImBuf *ibuf, const char *name, const int flags, const int totviews,
+ const char *(*getview)(void *base, const int view_id),
+ ImBuf *(*getbuffer)(void *base, const int view_id))
{
return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
}
@@ -1050,7 +1071,7 @@ float *IMB_exr_channel_rect(void *handle, const char *layname, const char *pass
BLI_strncpy(name, temp_buf, sizeof(name));
}
else if (data->multiView->size() > 1) {
- size_t view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
+ const int view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
std::string raw_name = insertViewName(name, *data->multiView, view_id);
BLI_strncpy(name, raw_name.c_str(), sizeof(name));
}
@@ -1135,7 +1156,7 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, c
FrameBuffer frameBuffer;
ExrChannel *echan;
std::string view(viewname);
- const size_t view_id = imb_exr_get_multiView_id(*data->multiView, view);
+ const int view_id = imb_exr_get_multiView_id(*data->multiView, view);
exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
@@ -1181,7 +1202,7 @@ void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, c
void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
{
ExrHandle *data = (ExrHandle *)handle;
- const size_t view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
+ const int view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
int numparts = (view_id == -1 ? data->parts : view_id + 1);
std::vector <FrameBuffer> frameBuffers(numparts);
std::vector <OutputPart> outputParts;
@@ -1806,8 +1827,15 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
/* will not include empty layer names */
channels.layers(layerNames);
- if (views.size() && views[0] != "")
+ if (views.size() && views[0] != "") {
*r_multiview = true;
+ }
+ else {
+ *r_singlelayer = false;
+ *r_multilayer = true;
+ *r_multiview = false;
+ return;
+ }
if (layerNames.size()) {
/* if layerNames is not empty, it means at least one layer is non-empty,
@@ -1824,7 +1852,7 @@ static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
std::string layerName = *i;
size_t pos = layerName.rfind ('.');
- if (pos != std::string::npos) {
+ if (pos == std::string::npos) {
*r_multilayer = true;
*r_singlelayer = false;
return;
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
index 70ba4978124..0fa0f64bdce 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -85,9 +85,9 @@ void IMB_exr_multiview_convert(
const int frame);
bool IMB_exr_multiview_save(
- struct ImBuf *ibuf, const char *name, const int flags, const size_t totviews,
- const char * (*getview)(void *base, size_t view_id),
- struct ImBuf * (*getbuffer)(void *base, const size_t view_id));
+ struct ImBuf *ibuf, const char *name, const int flags, const int totviews,
+ const char *(*getview)(void *base, int view_id),
+ struct ImBuf *(*getbuffer)(void *base, const int view_id));
void IMB_exr_close(void *handle);
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index c198cac6357..498e246a915 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -69,9 +69,9 @@ void IMB_exr_multiview_convert(
}
bool IMB_exr_multiview_save(
- struct ImBuf * /*ibuf*/, const char * /*name*/, const int /*flags*/, const size_t /*totviews*/,
- const char * (* /*getview*/)(void *base, size_t view_id),
- struct ImBuf * (* /*getbuffer*/)(void *base, const size_t view_id))
+ struct ImBuf * /*ibuf*/, const char * /*name*/, const int /*flags*/, const int /*totviews*/,
+ const char *(* /*getview*/)(void *base, const int view_id),
+ struct ImBuf *(* /*getbuffer*/)(void *base, const int view_id))
{
return false;
}
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 744a05c7091..5192e3f2d26 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -600,7 +600,6 @@ ImBuf *imb_loadpng(const unsigned char *mem, size_t size, int flags, char colors
default:
printf("PNG format not supported\n");
longjmp(png_jmpbuf(png_ptr), 1);
- break;
}
ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0);
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index f97860cc66c..71e74928e20 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -37,13 +37,10 @@
* ----------------------------------------------------------------------
*/
-#ifdef WIN32
-# include "BLI_utildefines.h"
-#endif
-
#include "MEM_guardedalloc.h"
#include "BLI_fileops.h"
+#include "BLI_utildefines.h"
#include "imbuf.h"
@@ -76,7 +73,7 @@ static const unsigned char *oldreadcolrs(RGBE *scan, const unsigned char *mem, i
{
int i, rshift = 0, len = xmax;
while (len > 0) {
- if (mem_eof - mem < 4) {
+ if (UNLIKELY(mem_eof - mem < 4)) {
return NULL;
}
scan[0][RED] = *mem++;
@@ -104,11 +101,11 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int
{
int i, j, code, val;
- if (mem_eof - mem < 4) {
+ if (UNLIKELY(mem_eof - mem < 4)) {
return NULL;
}
- if ((xmax < MINELEN) | (xmax > MAXELEN)) {
+ if (UNLIKELY((xmax < MINELEN) | (xmax > MAXELEN))) {
return oldreadcolrs(scan, mem, xmax, mem_eof);
}
@@ -128,25 +125,31 @@ static const unsigned char *freadcolrs(RGBE *scan, const unsigned char *mem, int
return oldreadcolrs(scan + 1, mem, xmax - 1, mem_eof);
}
- if (((scan[0][BLU] << 8) | i) != xmax) {
+ if (UNLIKELY(((scan[0][BLU] << 8) | i) != xmax)) {
return NULL;
}
for (i = 0; i < 4; i++) {
- if (mem_eof - mem < 2) {
+ if (UNLIKELY(mem_eof - mem < 2)) {
return NULL;
}
for (j = 0; j < xmax; ) {
code = *mem++;
if (code > 128) {
code &= 127;
+ if (UNLIKELY(code + j > xmax)) {
+ return NULL;
+ }
val = *mem++;
while (code--) {
scan[j++][i] = (unsigned char)val;
}
}
else {
- if (mem_eof - mem < code) {
+ if (UNLIKELY(mem_eof - mem < code)) {
+ return NULL;
+ }
+ if (UNLIKELY(code + j > xmax)) {
return NULL;
}
while (code--) {
@@ -240,13 +243,17 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem, size_t size, int flags, char
if (flags & IB_test) ibuf = IMB_allocImBuf(width, height, 32, 0);
else ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat);
- if (ibuf == NULL) return NULL;
+ if (UNLIKELY(ibuf == NULL)) {
+ return NULL;
+ }
ibuf->ftype = IMB_FTYPE_RADHDR;
if (flags & IB_alphamode_detect)
ibuf->flags |= IB_alphamode_premul;
- if (flags & IB_test) return ibuf;
+ if (flags & IB_test) {
+ return ibuf;
+ }
/* read in and decode the actual data */
sline = (RGBE *)MEM_mallocN(sizeof(*sline) * width, __func__);
@@ -290,7 +297,9 @@ static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufs
fCOLOR fcol;
RGBE rgbe, *rgbe_scan;
- if ((ibufscan == NULL) && (fpscan == NULL)) return 0;
+ if (UNLIKELY((ibufscan == NULL) && (fpscan == NULL))) {
+ return 0;
+ }
rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan");
@@ -381,7 +390,9 @@ int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags)
(void)flags; /* unused */
- if (file == NULL) return 0;
+ if (file == NULL) {
+ return 0;
+ }
writeHeader(file, width, height);
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index 1c83b33e296..afa3ffb31f3 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -46,6 +46,7 @@
#include "BLI_fileops.h"
#include "imbuf.h"
+#include "IMB_allocimbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_filetype.h"
@@ -174,7 +175,10 @@ ImBuf *IMB_loadifffile(int file, const char *filepath, int flags, char colorspac
size = BLI_file_descriptor_size(file);
+ imb_mmap_lock();
mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
+ imb_mmap_unlock();
+
if (mem == (unsigned char *) -1) {
fprintf(stderr, "%s: couldn't get mapping %s\n", __func__, descr);
return NULL;
@@ -182,8 +186,10 @@ ImBuf *IMB_loadifffile(int file, const char *filepath, int flags, char colorspac
ibuf = IMB_ibImageFromMemory(mem, size, flags, colorspace, descr);
+ imb_mmap_lock();
if (munmap(mem, size))
fprintf(stderr, "%s: couldn't unmap file %s\n", __func__, descr);
+ imb_mmap_unlock();
return ibuf;
}
@@ -269,7 +275,10 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
size = BLI_file_descriptor_size(file);
+ imb_mmap_lock();
mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
+ imb_mmap_unlock();
+
if (mem == (unsigned char *) -1) {
fprintf(stderr, "Couldn't get memory mapping for %s\n", ibuf->cachename);
return;
@@ -279,8 +288,10 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
if (type->load_tile && type->ftype(type, ibuf))
type->load_tile(ibuf, mem, size, tx, ty, rect);
+ imb_mmap_lock();
if (munmap(mem, size))
fprintf(stderr, "Couldn't unmap memory for %s.\n", ibuf->cachename);
+ imb_mmap_unlock();
}
void imb_loadtile(ImBuf *ibuf, int tx, int ty, unsigned int *rect)
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 605adffb813..504b59b2b1d 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -1485,38 +1485,68 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy)
return(ibuf);
}
-
-/* no float buf needed here! */
static void scalefast_Z_ImBuf(ImBuf *ibuf, int newx, int newy)
{
- unsigned int *rect, *_newrect, *newrect;
+ int *zbuf, *newzbuf, *_newzbuf = NULL;
+ float *zbuf_float, *newzbuf_float, *_newzbuf_float = NULL;
int x, y;
int ofsx, ofsy, stepx, stepy;
if (ibuf->zbuf) {
- _newrect = MEM_mallocN(newx * newy * sizeof(int), "z rect");
- if (_newrect == NULL) return;
-
- stepx = (65536.0 * (ibuf->x - 1.0) / (newx - 1.0)) + 0.5;
- stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5;
- ofsy = 32768;
+ _newzbuf = MEM_mallocN(newx * newy * sizeof(int), __func__);
+ if (_newzbuf == NULL) {
+ IMB_freezbufImBuf(ibuf);
+ }
+ }
- newrect = _newrect;
-
- for (y = newy; y > 0; y--) {
- rect = (unsigned int *) ibuf->zbuf;
- rect += (ofsy >> 16) * ibuf->x;
- ofsy += stepy;
+ if (ibuf->zbuf_float) {
+ _newzbuf_float = MEM_mallocN((size_t)newx * newy * sizeof(float), __func__);
+ if (_newzbuf_float == NULL) {
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ }
+
+ if (!_newzbuf && !_newzbuf_float) {
+ return;
+ }
+
+ stepx = (65536.0 * (ibuf->x - 1.0) / (newx - 1.0)) + 0.5;
+ stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5;
+ ofsy = 32768;
+
+ newzbuf = _newzbuf;
+ newzbuf_float = _newzbuf_float;
+
+ for (y = newy; y > 0; y--, ofsy += stepy) {
+ if (newzbuf) {
+ zbuf = ibuf->zbuf;
+ zbuf += (ofsy >> 16) * ibuf->x;
ofsx = 32768;
- for (x = newx; x > 0; x--) {
- *newrect++ = rect[ofsx >> 16];
- ofsx += stepx;
+ for (x = newx; x > 0; x--, ofsx += stepx) {
+ *newzbuf++ = zbuf[ofsx >> 16];
}
}
-
+
+ if (newzbuf_float) {
+ zbuf_float = ibuf->zbuf_float;
+ zbuf_float += (ofsy >> 16) * ibuf->x;
+ ofsx = 32768;
+ for (x = newx; x > 0; x--, ofsx += stepx) {
+ *newzbuf_float++ = zbuf_float[ofsx >> 16];
+ }
+ }
+ }
+
+ if (_newzbuf) {
IMB_freezbufImBuf(ibuf);
ibuf->mall |= IB_zbuf;
- ibuf->zbuf = (int *) _newrect;
+ ibuf->zbuf = _newzbuf;
+ }
+
+ if (_newzbuf_float) {
+ IMB_freezbuffloatImBuf(ibuf);
+ ibuf->mall |= IB_zbuffloat;
+ ibuf->zbuf_float = _newzbuf_float;
}
}
@@ -1586,30 +1616,24 @@ struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned
stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5;
ofsy = 32768;
- for (y = newy; y > 0; y--) {
+ for (y = newy; y > 0; y--, ofsy += stepy) {
if (do_rect) {
rect = ibuf->rect;
rect += (ofsy >> 16) * ibuf->x;
- }
- if (do_float) {
- rectf = (struct imbufRGBA *)ibuf->rect_float;
- rectf += (ofsy >> 16) * ibuf->x;
- }
- ofsy += stepy;
- ofsx = 32768;
-
- if (do_rect) {
- for (x = newx; x > 0; x--) {
+ ofsx = 32768;
+
+ for (x = newx; x > 0; x--, ofsx += stepx) {
*newrect++ = rect[ofsx >> 16];
- ofsx += stepx;
}
}
if (do_float) {
+ rectf = (struct imbufRGBA *)ibuf->rect_float;
+ rectf += (ofsy >> 16) * ibuf->x;
ofsx = 32768;
- for (x = newx; x > 0; x--) {
+
+ for (x = newx; x > 0; x--, ofsx += stepx) {
*newrectf++ = rectf[ofsx >> 16];
- ofsx += stepx;
}
}
}
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 3b9da639a86..19edce3da3b 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -343,7 +343,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl
};
char i = (char) swap;
for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
- copy_v3_v3_char((char *)to, (char *)from[i]);
+ copy_v3_v3_uchar(to, from[i]);
i = !i;
}
}
@@ -357,7 +357,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl
};
char i = (char) swap;
for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
- copy_v4_v4_char((char *)to, (char *)from[i]);
+ copy_v4_v4_uchar(to, from[i]);
i = !i;
}
}
@@ -392,7 +392,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl
};
char j = i;
for (x = 0; x < width; x++, from[0] += 3, from[1] += 3, to += 3) {
- copy_v3_v3_char((char *)to, (char *)from[j]);
+ copy_v3_v3_uchar(to, from[j]);
j = !j;
}
i = !i;
@@ -408,7 +408,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d, enum eStereo3dInterl
};
char j = i;
for (x = 0; x < width; x++, from[0] += 4, from[1] += 4, to += 4) {
- copy_v4_v4_char((char *)to, (char *)from[j]);
+ copy_v4_v4_uchar(to, from[j]);
j = !j;
}
i = !i;
@@ -508,7 +508,7 @@ static void imb_stereo3d_write_topbottom(Stereo3DData *s3d)
uchar *to = rect_to + stride_to * y * channels;
const uchar *from[2] = {
rect_left + stride_from * y * channels,
- rect_right + stride_from * y * channels,
+ rect_right + stride_from * y * channels,
};
memcpy(to, from[1], sizeof(uchar) * channels * stride_from);
@@ -1035,7 +1035,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla
};
char i = (char) swap;
for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
- copy_v3_v3_char((char *)to[i], (char *)from);
+ copy_v3_v3_uchar(to[i], from);
i = !i;
}
}
@@ -1049,7 +1049,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla
};
char i = (char) swap;
for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
- copy_v4_v4_char((char *)to[i], (char *)from);
+ copy_v4_v4_uchar(to[i], from);
i = !i;
}
}
@@ -1084,7 +1084,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla
};
char j = i;
for (x = 0; x < width; x++, from += 3, to[0] += 3, to[1] += 3) {
- copy_v3_v3_char((char *)to[j], (char *)from);
+ copy_v3_v3_uchar(to[j], from);
j = !j;
}
i = !i;
@@ -1100,7 +1100,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d, enum eStereo3dInterla
};
char j = i;
for (x = 0; x < width; x++, from += 4, to[0] += 4, to[1] += 4) {
- copy_v4_v4_char((char *)to[j], (char *)from);
+ copy_v4_v4_uchar(to[j], from);
j = !j;
}
i = !i;
@@ -1201,7 +1201,7 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
const uchar *from = rect_from + stride_from * y * channels;
uchar *to[2] = {
rect_left + stride_to * y * channels,
- rect_right + stride_to * y * channels,
+ rect_right + stride_to * y * channels,
};
memcpy(to[1], from, sizeof(uchar) * channels * stride_to);
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
index 7073d34e2bc..0949a431293 100644
--- a/source/blender/imbuf/intern/targa.c
+++ b/source/blender/imbuf/intern/targa.c
@@ -554,9 +554,10 @@ ImBuf *imb_loadtarga(const unsigned char *mem, size_t mem_size, int flags, char
{
TARGA tga;
struct ImBuf *ibuf;
- int col, count, size;
- unsigned int *rect, *cmap = NULL /*, mincol = 0*/, maxcol = 0;
- uchar *cp = (uchar *) &col;
+ int count, size;
+ unsigned int *rect, *cmap = NULL /*, mincol = 0*/, cmap_max = 0;
+ int32_t cp_data;
+ uchar *cp = (uchar *) &cp_data;
if (checktarga(&tga, mem) == 0) {
return NULL;
@@ -579,10 +580,10 @@ ImBuf *imb_loadtarga(const unsigned char *mem, size_t mem_size, int flags, char
if (tga.mapsize) {
/* load color map */
/*mincol = tga.maporig;*/ /*UNUSED*/
- maxcol = tga.mapsize;
- cmap = MEM_callocN(sizeof(unsigned int) * maxcol, "targa cmap");
+ cmap_max = tga.mapsize;
+ cmap = MEM_callocN(sizeof(unsigned int) * cmap_max, "targa cmap");
- for (count = 0; count < maxcol; count++) {
+ for (count = 0; count < cmap_max; count++) {
switch (tga.mapbits >> 3) {
case 4:
cp[0] = mem[3];
@@ -603,14 +604,16 @@ ImBuf *imb_loadtarga(const unsigned char *mem, size_t mem_size, int flags, char
mem += 2;
break;
case 1:
- col = *mem++;
+ cp_data = *mem++;
break;
}
- cmap[count] = col;
+ cmap[count] = cp_data;
}
size = 0;
- for (col = maxcol - 1; col > 0; col >>= 1) size++;
+ for (int cmap_index = cmap_max - 1; cmap_index > 0; cmap_index >>= 1) {
+ size++;
+ }
ibuf->planes = size;
if (tga.mapbits != 32) { /* set alpha bits */
@@ -655,14 +658,17 @@ ImBuf *imb_loadtarga(const unsigned char *mem, size_t mem_size, int flags, char
/* apply color map */
rect = ibuf->rect;
for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect) {
- col = *rect;
- if (col >= 0 && col < maxcol) *rect = cmap[col];
+ int cmap_index = *rect;
+ if (cmap_index >= 0 && cmap_index < cmap_max) {
+ *rect = cmap[cmap_index];
+ }
}
MEM_freeN(cmap);
}
if (tga.pixsize == 16) {
+ unsigned int col;
rect = ibuf->rect;
for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect) {
col = *rect;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index e7bec7e643c..95d061bcb75 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -217,7 +217,7 @@ static bool thumbhash_from_path(const char *UNUSED(path), ThumbSource source, ch
}
}
-static int uri_from_filename(const char *path, char *uri)
+static bool uri_from_filename(const char *path, char *uri)
{
char orig_uri[URI_MAX];
const char *dirstart = path;
@@ -243,16 +243,9 @@ static int uri_from_filename(const char *path, char *uri)
#else
BLI_snprintf(orig_uri, URI_MAX, "file://%s", dirstart);
#endif
-
-#ifdef WITH_ICONV
- {
- char uri_utf8[URI_MAX];
- escape_uri_string(orig_uri, uri_utf8, URI_MAX, UNSAFE_PATH);
- BLI_string_to_utf8(uri_utf8, uri, NULL);
- }
-#else
+
escape_uri_string(orig_uri, uri, URI_MAX, UNSAFE_PATH);
-#endif
+
return 1;
}
@@ -489,7 +482,9 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
char uri[URI_MAX] = "";
char thumb_name[40];
- uri_from_filename(path, uri);
+ if (!uri_from_filename(path, uri)) {
+ return NULL;
+ }
thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
return thumb_create_ex(path, uri, thumb_name, false, THUMB_DEFAULT_HASH, NULL, NULL, size, source, img);
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 1c501f8f592..4368a428186 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -708,6 +708,7 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
float *fromf = NULL;
float xres, yres;
int x, y, from_i, to_i, i;
+ int compress_mode = COMPRESSION_NONE;
/* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
@@ -725,6 +726,13 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
else
bitspersample = 8;
+ if (ibuf->foptions.flag & TIF_COMPRESS_DEFLATE)
+ compress_mode = COMPRESSION_DEFLATE;
+ else if (ibuf->foptions.flag & TIF_COMPRESS_LZW)
+ compress_mode = COMPRESSION_LZW;
+ else if (ibuf->foptions.flag & TIF_COMPRESS_PACKBITS)
+ compress_mode = COMPRESSION_PACKBITS;
+
/* open TIFF file for writing */
if (flags & IB_mem) {
/* bork at the creation of a TIFF in memory */
@@ -839,7 +847,7 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x);
TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y);
TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y);
- TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
+ TIFFSetField(image, TIFFTAG_COMPRESSION, compress_mode);
TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index ca793d04d9b..ba8480b636f 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -373,19 +373,6 @@ static int isffmpeg(const char *filename)
}
#endif
-#ifdef WITH_REDCODE
-static int isredcode(const char *filename)
-{
- struct redcode_handle *h = redcode_open(filename);
- if (!h) {
- return 0;
- }
- redcode_close(h);
- return 1;
-}
-
-#endif
-
int imb_get_anim_type(const char *name)
{
int type;
@@ -424,9 +411,6 @@ int imb_get_anim_type(const char *name)
if (isavi(name)) return (ANIM_AVI);
#endif
-#ifdef WITH_REDCODE
- if (isredcode(name)) return (ANIM_REDCODE);
-#endif
type = IMB_ispic(name);
if (type) {
return ANIM_SEQUENCE;
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
index 28710fba823..84ec2534e7f 100644
--- a/source/blender/imbuf/intern/writeimage.c
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -34,6 +34,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include "BLI_utildefines.h"
#include "BLI_path_util.h"
@@ -54,6 +55,8 @@ short IMB_saveiff(struct ImBuf *ibuf, const char *name, int flags)
{
const ImFileType *type;
+ errno = 0;
+
BLI_assert(!BLI_path_is_rel(name));
if (ibuf == NULL) return (false);
diff --git a/source/blender/imbuf/readme.txt b/source/blender/imbuf/readme.txt
index 181d5485310..d50cb8c781d 100644
--- a/source/blender/imbuf/readme.txt
+++ b/source/blender/imbuf/readme.txt
@@ -38,10 +38,8 @@ and add your extension so that your format gets recognized in the thumbnails.
Step 6:
Alter the build process:
-For scons you need to edit blender/source/blender/imbuf/SConscript
+For cmake you need to edit blender/source/blender/imbuf/CMakeLists.txt
and add in your additional files to source_files.
-For msvp you need to edit blender/projectfiles/blender/imbuf/BL_imbuf.dsp
-and add in your additional files.
If you have any external library info you will also need to add that
to the various build processes.
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 342245fa393..0bf3c350263 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -123,12 +123,16 @@ typedef struct ID {
struct Library *lib;
char name[66]; /* MAX_ID_NAME */
/**
- * LIB_... flags report on status of the datablock this ID belongs
- * to.
+ * LIB_... flags report on status of the datablock this ID belongs to (persistent, saved to and read from .blend).
*/
short flag;
+ /**
+ * LIB_TAG_... tags (runtime only, cleared at read time).
+ */
+ short tag;
+ short pad_s1;
int us;
- int icon_id, pad2;
+ int icon_id;
IDProperty *properties;
} ID;
@@ -232,7 +236,6 @@ typedef struct PreviewImage {
#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */
#define ID_AR MAKE_ID2('A', 'R') /* bArmature */
#define ID_AC MAKE_ID2('A', 'C') /* bAction */
-#define ID_SCRIPT MAKE_ID2('P', 'Y') /* Script (depreciated) */
#define ID_NT MAKE_ID2('N', 'T') /* bNodeTree */
#define ID_BR MAKE_ID2('B', 'R') /* Brush */
#define ID_PA MAKE_ID2('P', 'A') /* ParticleSettings */
@@ -255,12 +258,15 @@ typedef struct PreviewImage {
/* fluidsim Ipo */
#define ID_FLUIDSIM MAKE_ID2('F', 'S')
-#define ID_REAL_USERS(id) (((ID *)id)->us - ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0))
+#define ID_FAKE_USERS(id) ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0)
+#define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id))
#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM))
#define ID_BLEND_PATH(_bmain, _id) ((_id)->lib ? (_id)->lib->filepath : (_bmain)->name)
+#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
+
#ifdef GS
# undef GS
#endif
@@ -270,29 +276,61 @@ typedef struct PreviewImage {
#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; }
-/* id->flag: set first 8 bits always at zero while reading */
+/* id->flag (persitent). */
enum {
- LIB_LOCAL = 0,
- LIB_EXTERN = 1 << 0,
- LIB_INDIRECT = 1 << 1,
- LIB_NEED_EXPAND = 1 << 3,
- LIB_TESTEXT = (LIB_NEED_EXPAND | LIB_EXTERN),
- LIB_TESTIND = (LIB_NEED_EXPAND | LIB_INDIRECT),
- LIB_READ = 1 << 4,
- LIB_NEED_LINK = 1 << 5,
-
- LIB_NEW = 1 << 8,
LIB_FAKEUSER = 1 << 9,
- /* free test flag */
- LIB_DOIT = 1 << 10,
- /* tag existing data before linking so we know what is new */
- LIB_PRE_EXISTING = 1 << 11,
- /* runtime */
- LIB_ID_RECALC = 1 << 12,
- LIB_ID_RECALC_DATA = 1 << 13,
- LIB_ANIM_NO_RECALC = 1 << 14,
-
- LIB_ID_RECALC_ALL = (LIB_ID_RECALC | LIB_ID_RECALC_DATA),
+};
+
+/**
+ * id->tag (runtime-only).
+ *
+ * Those flags belong to three different categories, which have different expected handling in code:
+ *
+ * - RESET_BEFORE_USE: piece of code that wants to use such flag has to ensure they are properly 'reset' first.
+ * - RESET_AFTER_USE: piece of code that wants to use such flag has to ensure they are properly 'reset' after usage
+ * (though 'lifetime' of those flags is a bit fuzzy, e.g. _RECALC ones are reset on depsgraph
+ * evaluation...).
+ * - RESET_NEVER: those flags are 'status' one, and never actually need any reset (except on initialization
+ * during .blend file reading).
+ */
+enum {
+ /* RESET_NEVER Datablock is from current .blend file. */
+ LIB_TAG_LOCAL = 0,
+ /* RESET_NEVER Datablock is from a library, but is used (linked) directly by current .blend file. */
+ LIB_TAG_EXTERN = 1 << 0,
+ /* RESET_NEVER Datablock is from a library, and is only used (linked) inderectly through other libraries. */
+ LIB_TAG_INDIRECT = 1 << 1,
+
+ /* RESET_AFTER_USE Three flags used internally in readfile.c, to mark IDs needing to be read (only done once). */
+ LIB_TAG_NEED_EXPAND = 1 << 3,
+ LIB_TAG_TESTEXT = (LIB_TAG_NEED_EXPAND | LIB_TAG_EXTERN),
+ LIB_TAG_TESTIND = (LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT),
+ /* RESET_AFTER_USE Flag used internally in readfile.c, to mark IDs needing to be linked from a library. */
+ LIB_TAG_READ = 1 << 4,
+ /* RESET_AFTER_USE */
+ LIB_TAG_NEED_LINK = 1 << 5,
+
+ /* RESET_NEVER tag datablock as a place-holder (because the real one could not be linked from its library e.g.). */
+ LIB_TAG_MISSING = 1 << 6,
+
+ /* tag datablock has having an extra user. */
+ LIB_TAG_EXTRAUSER = 1 << 2,
+ /* tag datablock has having actually increased usercount for the extra virtual user. */
+ LIB_TAG_EXTRAUSER_SET = 1 << 7,
+
+ /* RESET_AFTER_USE tag newly duplicated/copied IDs. */
+ LIB_TAG_NEW = 1 << 8,
+ /* RESET_BEFORE_USE free test flag.
+ * TODO make it a RESET_AFTER_USE too. */
+ LIB_TAG_DOIT = 1 << 10,
+ /* RESET_AFTER_USE tag existing data before linking so we know what is new. */
+ LIB_TAG_PRE_EXISTING = 1 << 11,
+
+ /* RESET_AFTER_USE, used by update code (depsgraph). */
+ LIB_TAG_ID_RECALC = 1 << 12,
+ LIB_TAG_ID_RECALC_DATA = 1 << 13,
+ LIB_TAG_ANIM_NO_RECALC = 1 << 14,
+ LIB_TAG_ID_RECALC_ALL = (LIB_TAG_ID_RECALC | LIB_TAG_ID_RECALC_DATA),
};
/* To filter ID types (filter_id) */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index b8688e5e12a..96d7ec3128c 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -198,7 +198,8 @@ typedef struct bPoseChannel {
short agrp_index; /* index of action-group this bone belongs to (0 = default/no group) */
char constflag; /* for quick detecting which constraints affect this channel */
char selectflag; /* copy of bone flag, so you can work with library armatures, not for runtime use */
- char pad0[6];
+ char drawflag;
+ char pad0[5];
struct Bone *bone; /* set on read file or rebuild pose */
struct bPoseChannel *parent; /* set on read file or rebuild pose */
@@ -212,6 +213,9 @@ typedef struct bPoseChannel {
struct bPoseChannel *custom_tx; /* odd feature, display with another bones transform.
* needed in rare cases for advanced rigs,
* since the alternative is highly complicated - campbell */
+ float custom_scale;
+
+ char pad1[4];
/* transforms - written in by actions or transform */
float loc[3];
@@ -306,6 +310,14 @@ typedef enum ePchan_IkFlag {
BONE_IK_NO_ZDOF_TEMP = (1 << 12)
} ePchan_IkFlag;
+/* PoseChannel->drawflag */
+typedef enum ePchan_DrawFlag {
+ PCHAN_DRAW_NO_CUSTOM_BONE_SIZE = (1 << 0),
+} ePchan_DrawFlag;
+
+#define PCHAN_CUSTOM_DRAW_SIZE(pchan) \
+ (pchan)->custom_scale * (((pchan)->drawflag & PCHAN_DRAW_NO_CUSTOM_BONE_SIZE) ? 1.0f : (pchan)->bone->length)
+
/* PoseChannel->rotmode and Object->rotmode */
typedef enum eRotationModes {
/* quaternion rotations (default, and for older Blender versions) */
@@ -584,6 +596,9 @@ typedef enum eDopeSheet_FilterFlag {
ADS_FILTER_BY_FCU_NAME = (1 << 27), /* for F-Curves, filter by the displayed name (i.e. to isolate all Location curves only) */
ADS_FILTER_ONLY_ERRORS = (1 << 28), /* show only F-Curves which are disabled/have errors - for debugging drivers */
+ /* GPencil Mode */
+ ADS_FILTER_GP_3DONLY = (1 << 29), /* GP Mode - Only show datablocks used in the scene */
+
/* combination filters (some only used at runtime) */
ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM | ADS_FILTER_NOMAT | ADS_FILTER_NOLAM | ADS_FILTER_NOCUR | ADS_FILTER_NOPART | ADS_FILTER_NOARM | ADS_FILTER_NOSPK | ADS_FILTER_NOMODIFIERS)
} eDopeSheet_FilterFlag;
@@ -591,7 +606,9 @@ typedef enum eDopeSheet_FilterFlag {
/* DopeSheet general flags */
typedef enum eDopeSheet_Flag {
ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */
- ADS_FLAG_SHOW_DBFILTERS = (1 << 1) /* show filters for datablocks */
+ ADS_FLAG_SHOW_DBFILTERS = (1 << 1), /* show filters for datablocks */
+
+ ADS_FLAG_FUZZY_NAMES = (1 << 2), /* use fuzzy/partial string matches when ADS_FILTER_BY_FCU_NAME is enabled (WARNING: expensive operation) */
/* NOTE: datablock filter flags continued (1 << 10) onwards... */
} eDopeSheet_Flag;
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index 9af0c1dac10..6bdea21da1e 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -362,12 +362,7 @@ typedef struct bActuator {
#define ACT_ACTION_ADD 1
/* ipoactuator->type */
-#define ACT_IPO_PLAY 0
-#define ACT_IPO_PINGPONG 1
-#define ACT_IPO_FLIPPER 2
-#define ACT_IPO_LOOP_STOP 3
-#define ACT_IPO_LOOP_END 4
-#define ACT_IPO_KEY2KEY 5
+/* used for conversion from 2.01 */
#define ACT_IPO_FROM_PROP 6
/* groupactuator->type */
@@ -386,12 +381,6 @@ typedef struct bActuator {
#define ACT_IPOCHILD (1 << 4)
#define ACT_IPOADD (1 << 5)
-/* ipoactuator->flag for k2k */
-#define ACT_K2K_PREV 1
-#define ACT_K2K_CYCLIC 2
-#define ACT_K2K_PINGPONG 4
-#define ACT_K2K_HOLD 8
-
/* property actuator->type */
#define ACT_PROP_ASSIGN 0
#define ACT_PROP_ADD 1
@@ -512,6 +501,7 @@ typedef struct bActuator {
#define ACT_GAME_QUIT 3
#define ACT_GAME_SAVECFG 4
#define ACT_GAME_LOADCFG 5
+#define ACT_GAME_SCREENSHOT 6
/* visibilityact->flag */
/* Set means the object will become invisible */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 590179e0a0f..fdad6aae094 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -54,7 +54,7 @@ typedef struct FModifier {
void *data; /* pointer to modifier data */
- char name[64]; /* user-defined description for the modifier */
+ char name[64]; /* user-defined description for the modifier - MAX_ID_NAME-2 */
short type; /* type of f-curve modifier */
short flag; /* settings for the modifier */
@@ -271,7 +271,7 @@ typedef struct DriverTarget {
char *rna_path; /* RNA path defining the setting to use (for DVAR_TYPE_SINGLE_PROP) */
- char pchan_name[32]; /* name of the posebone to use (for vars where DTAR_FLAG_STRUCT_REF is used) */
+ char pchan_name[64]; /* name of the posebone to use (for vars where DTAR_FLAG_STRUCT_REF is used) - MAX_ID_NAME-2 */
short transChan; /* transform channel index (for DVAR_TYPE_TRANSFORM_CHAN)*/
short flag; /* flags for the validity of the target (NOTE: these get reset every time the types change) */
@@ -327,13 +327,15 @@ typedef enum eDriverTarget_TransformChannels {
*/
typedef struct DriverVar {
struct DriverVar *next, *prev;
-
- char name[64]; /* name of the variable to use in py-expression (must be valid python identifier) */
-
+
+ char name[64]; /* name of the variable to use in py-expression (must be valid python identifier) - MAX_ID_NAME-2 */
+
DriverTarget targets[8]; /* MAX_DRIVER_TARGETS, target slots */
- short num_targets; /* number of targets actually used by this variable */
-
- short type; /* type of driver target (eDriverTarget_Types) */
+
+ char num_targets; /* number of targets actually used by this variable */
+ char type; /* type of driver variable (eDriverVar_Types) */
+
+ short flag; /* validation tags, etc. (eDriverVar_Flags) */
float curval; /* result of previous evaluation */
} DriverVar;
@@ -355,6 +357,41 @@ typedef enum eDriverVar_Types {
MAX_DVAR_TYPES
} eDriverVar_Types;
+/* Driver Variable Flags */
+typedef enum eDriverVar_Flags {
+ /* variable is not set up correctly */
+ DVAR_FLAG_ERROR = (1 << 0),
+
+ /* variable name doesn't pass the validation tests */
+ DVAR_FLAG_INVALID_NAME = (1 << 1),
+ /* name starts with a number */
+ DVAR_FLAG_INVALID_START_NUM = (1 << 2),
+ /* name starts with a special character (!, $, @, #, _, etc.) */
+ DVAR_FLAG_INVALID_START_CHAR = (1 << 3),
+ /* name contains a space */
+ DVAR_FLAG_INVALID_HAS_SPACE = (1 << 4),
+ /* name contains a dot */
+ DVAR_FLAG_INVALID_HAS_DOT = (1 << 5),
+ /* name contains invalid chars */
+ DVAR_FLAG_INVALID_HAS_SPECIAL = (1 << 6),
+ /* name is a reserved keyword */
+ DVAR_FLAG_INVALID_PY_KEYWORD = (1 << 7),
+ /* name is zero-length */
+ DVAR_FLAG_INVALID_EMPTY = (1 << 8),
+} eDriverVar_Flags;
+
+/* All invalid dvar name flags */
+#define DVAR_ALL_INVALID_FLAGS ( \
+ DVAR_FLAG_INVALID_NAME | \
+ DVAR_FLAG_INVALID_START_NUM | \
+ DVAR_FLAG_INVALID_START_CHAR | \
+ DVAR_FLAG_INVALID_HAS_SPACE | \
+ DVAR_FLAG_INVALID_HAS_DOT | \
+ DVAR_FLAG_INVALID_HAS_SPECIAL | \
+ DVAR_FLAG_INVALID_PY_KEYWORD | \
+ DVAR_FLAG_INVALID_EMPTY \
+)
+
/* --- */
/* Channel Driver (i.e. Drivers / Expressions) (driver)
@@ -568,7 +605,7 @@ typedef struct NlaStrip {
ListBase fcurves; /* F-Curves for controlling this strip's influence and timing */ // TODO: move out?
ListBase modifiers; /* F-Curve modifiers to be applied to the entire strip's referenced F-Curves */
- char name[64]; /* User-Visible Identifier for Strip */
+ char name[64]; /* User-Visible Identifier for Strip - MAX_ID_NAME-2 */
float influence; /* Influence of strip */
float strip_time; /* Current 'time' within action being used (automatically evaluated, but can be overridden) */
@@ -678,7 +715,7 @@ typedef struct NlaTrack {
int flag; /* settings for this track */
int index; /* index of the track in the stack (NOTE: not really useful, but we need a pad var anyways!) */
- char name[64]; /* short user-description of this track */
+ char name[64]; /* short user-description of this track - MAX_ID_NAME-2 */
} NlaTrack;
/* settings for track */
@@ -714,7 +751,7 @@ typedef struct KS_Path {
struct KS_Path *next, *prev;
ID *id; /* ID block that keyframes are for */
- char group[64]; /* name of the group to add to */
+ char group[64]; /* name of the group to add to - MAX_ID_NAME-2 */
int idtype; /* ID-type that path can be used on */
@@ -765,10 +802,10 @@ typedef struct KeyingSet {
ListBase paths; /* (KS_Path) paths to keyframe to */
- char idname[64]; /* unique name (for search, etc.) */
- char name[64]; /* user-viewable name for KeyingSet (for menus, etc.) */
+ char idname[64]; /* unique name (for search, etc.) - MAX_ID_NAME-2 */
+ char name[64]; /* user-viewable name for KeyingSet (for menus, etc.) - MAX_ID_NAME-2 */
char description[240]; /* (RNA_DYN_DESCR_MAX) short help text. */
- char typeinfo[64]; /* name of the typeinfo data used for the relative paths */
+ char typeinfo[64]; /* name of the typeinfo data used for the relative paths - MAX_ID_NAME-2 */
int active_path; /* index of the active path */
@@ -800,6 +837,7 @@ typedef enum eInsertKeyFlags {
/* Allow to make a full copy of new key into existing one, if any, instead of 'reusing' existing handles.
* Used by copy/paste code. */
INSERTKEY_OVERWRITE_FULL = (1<<7),
+ INSERTKEY_DRIVER = (1<<8), /* for driver FCurves, use driver's "input" value - for easier corrective driver setup */
} eInsertKeyFlags;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 7ec86459f0c..3dca087c7fa 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -69,6 +69,8 @@ typedef struct Brush {
char icon_filepath[1024]; /* 1024 = FILE_MAX */
float normal_weight;
+ float rake_factor; /* rake actual data (not texture), used for sculpt */
+ int pad;
short blend; /* blend mode */
short ob_mode; /* & with ob->mode to see if the brush is compatible, use for display only. */
@@ -273,6 +275,10 @@ typedef enum BrushSculptTool {
SCULPT_TOOL_SNAKE_HOOK \
)
+#define SCULPT_TOOL_HAS_RAKE(t) ELEM(t, \
+ SCULPT_TOOL_SNAKE_HOOK \
+ )
+
#define SCULPT_TOOL_HAS_DYNTOPO(t) (ELEM(t, \
/* These brushes, as currently coded, cannot support dynamic topology */ \
SCULPT_TOOL_GRAB, \
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index c45322b818f..7f2e1aaadf9 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -51,7 +51,8 @@ typedef struct CameraStereoSettings {
float convergence_distance;
short convergence_mode;
short pivot;
- short pad, pad2;
+ short flag;
+ short pad;
} CameraStereoSettings;
typedef struct Camera {
@@ -148,6 +149,11 @@ enum {
CAM_S3D_PIVOT_CENTER = 2,
};
+/* stereo->flag */
+enum {
+ CAM_S3D_SPHERICAL = (1 << 0),
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 9be3fbc2348..8f711c1b23b 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -268,6 +268,9 @@ typedef struct Curve {
} Curve;
+#define CURVE_VFONT_ANY(cu) \
+ ((cu)->vfont), ((cu)->vfontb), ((cu)->vfonti), ((cu)->vfontbi)
+
/* **************** CURVE ********************* */
/* Curve.texflag */
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index 9a6c7144692..d62369803d6 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -41,24 +41,38 @@ struct SDNA;
extern const unsigned char DNAstr[];
extern const int DNAlen; /* length of DNAstr */
-/* primitive (non-struct, non-pointer/function/array) types--do not change ordering! */
+/**
+ * Primitive (non-struct, non-pointer/function/array) types,
+ * \warning Don't change these values!
+ * Currently changes here here will work on native endianness,
+ * however #DNA_struct_switch_endian currently checks these
+ * hard-coded values against those from old files.
+ */
typedef enum eSDNA_Type {
SDNA_TYPE_CHAR = 0,
SDNA_TYPE_UCHAR = 1,
SDNA_TYPE_SHORT = 2,
SDNA_TYPE_USHORT = 3,
SDNA_TYPE_INT = 4,
- SDNA_TYPE_LONG = 5,
- SDNA_TYPE_ULONG = 6,
+ /* SDNA_TYPE_LONG = 5, */ /* deprecated (use as int) */
+ /* SDNA_TYPE_ULONG = 6, */ /* deprecated (use as int) */
SDNA_TYPE_FLOAT = 7,
SDNA_TYPE_DOUBLE = 8,
- /* ,SDNA_TYPE_VOID = 9 */ /* nothing uses yet */
+ /* ,SDNA_TYPE_VOID = 9 */
+/* define so switch statements don't complain */
+#define SDNA_TYPE_VOID 9
SDNA_TYPE_INT64 = 10,
SDNA_TYPE_UINT64 = 11
} eSDNA_Type;
-/* define so switch statements don't complain */
-#define SDNA_TYPE_VOID 9
+/**
+ * For use with #DNA_struct_reconstruct & #DNA_struct_get_compareflags
+ */
+enum eSDNA_StructCompare {
+ SDNA_CMP_REMOVED = 0,
+ SDNA_CMP_EQUAL = 1,
+ SDNA_CMP_NOT_EQUAL = 2,
+};
struct SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap);
void DNA_sdna_free(struct SDNA *sdna);
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index beffbc4c017..e5e193d479b 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -51,7 +51,10 @@ typedef struct bGPDspoint {
/* bGPDspoint->flag */
typedef enum eGPDspoint_Flag {
/* stroke point is selected (for editing) */
- GP_SPOINT_SELECT = (1 << 0)
+ GP_SPOINT_SELECT = (1 << 0),
+
+ /* stroke point is tagged (for some editing operation) */
+ GP_SPOINT_TAG = (1 << 1),
} eGPSPoint_Flag;
/* Grease-Pencil Annotations - 'Stroke'
@@ -127,6 +130,10 @@ typedef struct bGPDlayer {
char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3")
* this is used for the name of the layer too and kept unique. */
+
+ float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */
+ short sublevel; /* number of times to subdivide new strokes */
+ short pad[5]; /* padding for compiler error */
} bGPDlayer;
/* bGPDlayer->flag */
@@ -190,6 +197,7 @@ typedef enum eGPdata_Flag {
/* is the block overriding all clicks? */
/* GP_DATA_EDITPAINT = (1 << 3), */
+/* ------------------------------------------------ DEPRECATED */
/* new strokes are added in viewport space */
GP_DATA_VIEWALIGN = (1 << 4),
@@ -198,9 +206,13 @@ typedef enum eGPdata_Flag {
GP_DATA_DEPTH_STROKE = (1 << 6),
GP_DATA_DEPTH_STROKE_ENDPOINTS = (1 << 7),
+/* ------------------------------------------------ DEPRECATED */
/* Stroke Editing Mode - Toggle to enable alternative keymap for easier editing of stroke points */
- GP_DATA_STROKE_EDITMODE = (1 << 8)
+ GP_DATA_STROKE_EDITMODE = (1 << 8),
+
+ /* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
+ GP_DATA_SHOW_ONIONSKINS = (1 << 9)
} eGPdata_Flag;
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 56a8842a8d2..b4bc26f45cd 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -90,13 +90,19 @@ typedef struct RenderSlot {
#define IMA_NEED_FRAME_RECALC 8
#define IMA_SHOW_STEREO 16
+enum {
+ TEXTARGET_TEXTURE_2D = 0,
+ TEXTARGET_TEXTURE_CUBE_MAP = 1,
+ TEXTARGET_COUNT = 2
+};
+
typedef struct Image {
ID id;
char name[1024]; /* file path, 1024 = FILE_MAX */
struct MovieCache *cache; /* not written in file */
- struct GPUTexture *gputexture; /* not written in file */
+ struct GPUTexture *gputexture[2]; /* not written in file 2 = TEXTARGET_COUNT */
/* sources from: */
ListBase anims;
@@ -113,7 +119,8 @@ typedef struct Image {
short tpageflag, totbind;
short xrep, yrep;
short twsta, twend;
- unsigned int bindcode; /* only for current image... */
+ unsigned int bindcode[2]; /* only for current image... 2 = TEXTARGET_COUNT */
+ char pad1[4];
unsigned int *repbind; /* for repeat of parts of images */
struct PackedFile *packedfile DNA_DEPRECATED; /* deprecated */
@@ -145,7 +152,7 @@ typedef struct Image {
/* Multiview */
char eye; /* for viewer node stereoscopy */
char views_format;
- ListBase views;
+ ListBase views; /* ImageView */
struct Stereo3dFormat *stereo3d_format;
RenderSlot render_slots[8]; /* 8 = IMA_MAX_RENDER_SLOT */
@@ -172,8 +179,8 @@ enum {
IMA_IGNORE_ALPHA = (1 << 12),
IMA_DEINTERLACE = (1 << 13),
IMA_USE_VIEWS = (1 << 14),
- IMA_IS_STEREO = (1 << 15),
- IMA_IS_MULTIVIEW = (1 << 16), /* similar to stereo, but a more general case */
+ // IMA_IS_STEREO = (1 << 15), /* deprecated */
+ // IMA_IS_MULTIVIEW = (1 << 16), /* deprecated */
};
/* Image.tpageflag */
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
index b4088cc5a5d..374104d8b13 100644
--- a/source/blender/makesdna/DNA_ipo_types.h
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -46,9 +46,6 @@
/* -------------------------- Type Defines --------------------------- */
-/* sometimes used - mainly for GE/Ketsji */
-typedef short IPO_Channel;
-
/* --- IPO Curve Driver --- */
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index ce8e86cb512..a2e39f93875 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -61,6 +61,7 @@ typedef struct Lamp {
float att1, att2; /* Quad1 and Quad2 attenuation */
+ float coeff_const, coeff_lin, coeff_quad, coeff_pad;
struct CurveMapping *curfalloff;
short falloff_type;
short pad2;
@@ -127,8 +128,6 @@ typedef struct Lamp {
#define LA_SPOT 2
#define LA_HEMI 3
#define LA_AREA 4
-/* yafray: extra lamp type used for caustic photonmap */
-#define LA_YF_PHOTON 5
/* mode */
#define LA_SHAD_BUF (1 << 0)
@@ -163,11 +162,12 @@ typedef struct Lamp {
#define LA_SUN_EFFECT_AP 2
/* falloff_type */
-#define LA_FALLOFF_CONSTANT 0
+#define LA_FALLOFF_CONSTANT 0
#define LA_FALLOFF_INVLINEAR 1
-#define LA_FALLOFF_INVSQUARE 2
-#define LA_FALLOFF_CURVE 3
-#define LA_FALLOFF_SLIDERS 4
+#define LA_FALLOFF_INVSQUARE 2
+#define LA_FALLOFF_CURVE 3
+#define LA_FALLOFF_SLIDERS 4
+#define LA_FALLOFF_INVCOEFFICIENTS 5
/* buftype, no flag */
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 59e6f28804a..621807d111c 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -71,7 +71,7 @@ typedef struct MVert {
* at the moment alpha is abused for vertex painting and not used for transparency, note that red and blue are swapped
*/
typedef struct MCol {
- char a, r, g, b;
+ unsigned char a, r, g, b;
} MCol;
/* new face structure, replaces MFace, which is now only used for storing tessellations.*/
@@ -224,7 +224,7 @@ enum {
* \note red and blue are _not_ swapped, as they are with #MCol
*/
typedef struct MLoopCol {
- char r, g, b, a;
+ unsigned char r, g, b, a;
} MLoopCol;
#define MESH_MLOOPCOL_FROM_MCOL(_mloopcol, _mcol) \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 67ec9fe3db3..457db70cd28 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -430,7 +430,7 @@ typedef struct DecimateModifierData {
float percent; /* (mode == MOD_DECIM_MODE_COLLAPSE) */
short iter; /* (mode == MOD_DECIM_MODE_UNSUBDIV) */
char delimit; /* (mode == MOD_DECIM_MODE_DISSOLVE) */
- char pad;
+ char symmetry_axis; /* (mode == MOD_DECIM_MODE_COLLAPSE) */
float angle; /* (mode == MOD_DECIM_MODE_DISSOLVE) */
char defgrp_name[64]; /* MAX_VGROUP_NAME */
@@ -445,6 +445,7 @@ enum {
MOD_DECIM_FLAG_INVERT_VGROUP = (1 << 0),
MOD_DECIM_FLAG_TRIANGULATE = (1 << 1), /* for collapse only. dont convert tri pairs back to quads */
MOD_DECIM_FLAG_ALL_BOUNDARY_VERTS = (1 << 2), /* for dissolve only. collapse all verts between 2 faces */
+ MOD_DECIM_FLAG_SYMMETRY = (1 << 3),
};
enum {
@@ -639,7 +640,9 @@ typedef struct BooleanModifierData {
ModifierData modifier;
struct Object *object;
- int operation, pad;
+ char operation;
+ char bm_flag, pad[2];
+ float threshold;
} BooleanModifierData;
typedef enum {
@@ -648,6 +651,14 @@ typedef enum {
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
+/* temp bm_flag (debugging only) */
+enum {
+ eBooleanModifierBMeshFlag_Enabled = (1 << 0),
+ eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 1),
+ eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 2),
+ eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 3),
+};
+
typedef struct MDefInfluence {
int vertex;
float weight;
@@ -687,7 +698,7 @@ typedef struct MeshDeformModifierData {
float *bindcos; /* deprecated storage of cage coords */
/* runtime */
- void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd,
+ void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, struct DerivedMesh *cagedm,
float *vertexcos, int totvert, float cagemat[4][4]);
} MeshDeformModifierData;
@@ -705,7 +716,8 @@ typedef struct ParticleSystemModifierData {
ModifierData modifier;
struct ParticleSystem *psys;
- struct DerivedMesh *dm;
+ struct DerivedMesh *dm_final; /* Final DM - its topology may differ from orig mesh. */
+ struct DerivedMesh *dm_deformed; /* Deformed-onle DM - its topology is same as orig mesh one. */
int totdmvert, totdmedge, totdmface;
short flag, pad;
} ParticleSystemModifierData;
@@ -813,6 +825,8 @@ enum {
MOD_SHRINKWRAP_CULL_TARGET_BACKFACE = (1 << 4),
MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE = (1 << 5), /* distance is measure to the front face of the target */
+
+ MOD_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
};
/* Shrinkwrap->projAxis */
@@ -834,10 +848,17 @@ typedef struct SimpleDeformModifierData {
char mode; /* deform function */
char axis; /* lock axis (for taper and strech) */
- char pad[2];
+ char flag;
+ char pad;
} SimpleDeformModifierData;
+/* SimpleDeform->flag */
+enum {
+ MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP = (1 << 0),
+};
+
+
enum {
MOD_SIMPLEDEFORM_MODE_TWIST = 1,
MOD_SIMPLEDEFORM_MODE_BEND = 2,
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 32f766ecae5..c75a019a28e 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -384,6 +384,7 @@ typedef struct bNodeTree {
/* callbacks */
void (*progress)(void *, float progress);
+ /** \warning may be called by different threads */
void (*stats_draw)(void *, const char *str);
int (*test_break)(void *);
void (*update_draw)(void *);
@@ -502,7 +503,8 @@ enum {
};
enum {
- CMP_NODEFLAG_BLUR_VARIABLE_SIZE = (1 << 0)
+ CMP_NODEFLAG_BLUR_VARIABLE_SIZE = (1 << 0),
+ CMP_NODEFLAG_BLUR_EXTEND_BOUNDS = (1 << 1),
};
typedef struct NodeFrame {
@@ -748,6 +750,8 @@ typedef struct NodeTexEnvironment {
ImageUser iuser;
int color_space;
int projection;
+ int interpolation;
+ int pad;
} NodeTexEnvironment;
typedef struct NodeTexGradient {
@@ -775,7 +779,7 @@ typedef struct NodeTexMusgrave {
typedef struct NodeTexWave {
NodeTexBase base;
int wave_type;
- int pad;
+ int wave_profile;
} NodeTexWave;
typedef struct NodeTexMagic {
@@ -803,7 +807,9 @@ typedef struct NodeShaderTexPointDensity {
short space;
short interpolation;
short color_source;
- short pad2;
+ short ob_color_source;
+ char vertex_attribute_name[64]; /* vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */
+ PointDensity pd;
} NodeShaderTexPointDensity;
/* TEX_output */
@@ -968,6 +974,9 @@ typedef struct NodeSunBeams {
#define SHD_WAVE_BANDS 0
#define SHD_WAVE_RINGS 1
+#define SHD_WAVE_PROFILE_SIN 0
+#define SHD_WAVE_PROFILE_SAW 1
+
/* sky texture */
#define SHD_SKY_OLD 0
#define SHD_SKY_NEW 1
@@ -1049,6 +1058,7 @@ enum {
#endif
SHD_SUBSURFACE_CUBIC = 1,
SHD_SUBSURFACE_GAUSSIAN = 2,
+ SHD_SUBSURFACE_BURLEY = 3,
};
/* blur node */
@@ -1108,6 +1118,11 @@ enum {
CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
};
+/* Stabilization node */
+enum {
+ CMP_NODEFLAG_STABILIZE_INVERSE = 1,
+};
+
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
/* Point Density shader node */
@@ -1128,4 +1143,10 @@ enum {
SHD_POINTDENSITY_COLOR_PARTVEL = 3,
};
+enum {
+ SHD_POINTDENSITY_COLOR_VERTCOL = 0,
+ SHD_POINTDENSITY_COLOR_VERTWEIGHT = 1,
+ SHD_POINTDENSITY_COLOR_VERTNOR = 2,
+};
+
#endif
diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h
index aaebdf579f8..a714195dd5d 100644
--- a/source/blender/makesdna/DNA_object_fluidsim.h
+++ b/source/blender/makesdna/DNA_object_fluidsim.h
@@ -88,11 +88,6 @@ typedef struct FluidsimSettings {
/* gravity strength */
float iniVelx, iniVely, iniVelz;
- /* store pointer to original mesh (for replacing the current one) */
- struct Mesh *orgMesh;
- /* a mesh to display the bounding box used for simulation */
- struct Mesh *meshBB;
-
/* store output path, and file prefix for baked fluid surface */
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
char surfdataPath[1024];
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
index c9c1f618e86..cccee82cb51 100644
--- a/source/blender/makesdna/DNA_object_force.h
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -253,10 +253,10 @@ typedef struct BulletSoftBody {
/* BulletSoftBody.flag */
#define OB_BSB_SHAPE_MATCHING 2
-#define OB_BSB_UNUSED 4
+// #define OB_BSB_UNUSED 4
#define OB_BSB_BENDING_CONSTRAINTS 8
#define OB_BSB_AERO_VPOINT 16 /* aero model, Vertex normals are oriented toward velocity*/
-#define OB_BSB_AERO_VTWOSIDE 32 /* aero model, Vertex normals are flipped to match velocity */
+// #define OB_BSB_AERO_VTWOSIDE 32 /* aero model, Vertex normals are flipped to match velocity */
/* BulletSoftBody.collisionflags */
#define OB_BSB_COL_SDF_RS 2 /* SDF based rigid vs soft */
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index faae78ab500..d53c8360bb5 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -189,7 +189,7 @@ typedef struct Object {
/* did last modifier stack generation need mapping support? */
char lastNeedMapping; /* bool */
- char pad[5];
+ char pad;
/* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
@@ -222,6 +222,8 @@ typedef struct Object {
float step_height;
float jump_speed;
float fall_speed;
+ unsigned char max_jumps;
+ char pad2[3];
/** Collision mask settings */
unsigned short col_group, col_mask;
@@ -673,6 +675,7 @@ typedef enum ObjectMode {
OB_MODE_TEXTURE_PAINT = 1 << 4,
OB_MODE_PARTICLE_EDIT = 1 << 5,
OB_MODE_POSE = 1 << 6,
+ OB_MODE_GPENCIL = 1 << 7, /* NOTE: Just a dummy to make the UI nicer */
} ObjectMode;
/* any mode where the brush system is used */
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 95cb5c84bed..b284a683f8e 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -109,6 +109,7 @@ typedef struct ParticleData {
float time, lifetime; /* dietime is not nescessarily time+lifetime as */
float dietime; /* particles can die unnaturally (collision) */
+ /* WARNING! Those two indices, when not affected to vertices, are for !!! TESSELLATED FACES !!!, not POLYGONS! */
int num; /* index to vert/edge/face */
int num_dmcache; /* index to derived mesh data (face) to avoid slow lookups */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index f9cea3871f6..1ace2b42f15 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -204,7 +204,8 @@ typedef struct SceneRenderLayer {
#define SCE_LAY_SKY 16
#define SCE_LAY_STRAND 32
#define SCE_LAY_FRS 64
- /* flags between 128 and 0x8000 are set to 1 already, for future options */
+#define SCE_LAY_AO 128
+ /* flags between 256 and 0x8000 are set to 1 already, for future options */
#define SCE_LAY_ALL_Z 0x8000
#define SCE_LAY_XOR 0x10000
@@ -354,7 +355,10 @@ typedef struct ImageFormatData {
char jp2_flag;
char jp2_codec;
- char pad[5];
+ /* TIFF */
+ char tiff_codec;
+
+ char pad[4];
/* Multiview */
char views_format;
@@ -441,6 +445,14 @@ typedef struct ImageFormatData {
/* ImageFormatData.cineon_flag */
#define R_IMF_CINEON_FLAG_LOG (1<<0) /* was R_CINEON_LOG */
+/* ImageFormatData.tiff_codec */
+enum {
+ R_IMF_TIFF_CODEC_DEFLATE = 0,
+ R_IMF_TIFF_CODEC_LZW = 1,
+ R_IMF_TIFF_CODEC_PACKBITS = 2,
+ R_IMF_TIFF_CODEC_NONE = 3,
+};
+
typedef struct BakeData {
struct ImageFormatData im_format;
@@ -450,7 +462,7 @@ typedef struct BakeData {
short margin, flag;
float cage_extrusion;
- float pad2;
+ int pass_filter;
char normal_swizzle[3];
char normal_space;
@@ -477,6 +489,22 @@ typedef enum BakeSaveMode {
R_BAKE_SAVE_EXTERNAL = 1,
} BakeSaveMode;
+/* bake->pass_filter */
+typedef enum BakePassFilter {
+ R_BAKE_PASS_FILTER_NONE = 0,
+ R_BAKE_PASS_FILTER_AO = (1 << 0),
+ R_BAKE_PASS_FILTER_EMIT = (1 << 1),
+ R_BAKE_PASS_FILTER_DIFFUSE = (1 << 2),
+ R_BAKE_PASS_FILTER_GLOSSY = (1 << 3),
+ R_BAKE_PASS_FILTER_TRANSM = (1 << 4),
+ R_BAKE_PASS_FILTER_SUBSURFACE = (1 << 5),
+ R_BAKE_PASS_FILTER_DIRECT = (1 << 6),
+ R_BAKE_PASS_FILTER_INDIRECT = (1 << 7),
+ R_BAKE_PASS_FILTER_COLOR = (1 << 8),
+} BakePassFilter;
+
+#define R_BAKE_PASS_FILTER_ALL (~0)
+
/* *************************************************************** */
/* Render Data */
@@ -698,10 +726,13 @@ typedef struct RenderData {
short pad;
/* MultiView */
- ListBase views;
+ ListBase views; /* SceneRenderView */
short actview;
short views_format;
short pad8[2];
+
+ /* Motion blur shutter */
+ struct CurveMapping mblur_shutter_curve;
} RenderData;
/* *************************************************************** */
@@ -764,12 +795,18 @@ typedef struct RecastData {
int vertsperpoly;
float detailsampledist;
float detailsamplemaxerror;
- short pad1, pad2;
+ char partitioning;
+ char pad1;
+ short pad2;
} RecastData;
+#define RC_PARTITION_WATERSHED 0
+#define RC_PARTITION_MONOTONE 1
+#define RC_PARTITION_LAYERS 2
+
typedef struct GameData {
- /* standalone player */
+ /* standalone player */
struct GameFraming framing;
short playerflag, xplay, yplay, freqplay;
short depth, attrib, rt1, rt2;
@@ -792,7 +829,7 @@ typedef struct GameData {
/*
* bit 3: (gameengine): Activity culling is enabled.
- * bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling
+ * bit 5: (gameengine) : enable Bullet DBVT tree for view frustum culling
*/
int flag;
short mode, matmode;
@@ -907,6 +944,7 @@ typedef enum StereoViews {
STEREO_MONO_ID = 3,
} StereoViews;
+/* *************************************************************** */
/* Markers */
typedef struct TimeMarker {
@@ -1037,6 +1075,7 @@ typedef struct Sculpt {
typedef struct UvSculpt {
Paint paint;
} UvSculpt;
+
/* ------------------------------------------- */
/* Vertex Paint */
@@ -1062,6 +1101,65 @@ enum {
VP_ONLYVGROUP = (1 << 7) /* weight paint only */
};
+/* ------------------------------------------- */
+/* GPencil Stroke Sculpting */
+
+/* Brush types */
+typedef enum eGP_EditBrush_Types {
+ GP_EDITBRUSH_TYPE_SMOOTH = 0,
+ GP_EDITBRUSH_TYPE_THICKNESS = 1,
+ GP_EDITBRUSH_TYPE_GRAB = 2,
+ GP_EDITBRUSH_TYPE_PUSH = 3,
+ GP_EDITBRUSH_TYPE_TWIST = 4,
+ GP_EDITBRUSH_TYPE_PINCH = 5,
+ GP_EDITBRUSH_TYPE_RANDOMIZE = 6,
+ GP_EDITBRUSH_TYPE_SUBDIVIDE = 7,
+ GP_EDITBRUSH_TYPE_SIMPLIFY = 8,
+ GP_EDITBRUSH_TYPE_CLONE = 9,
+
+ /* !!! Update GP_EditBrush_Data brush[###]; below !!! */
+ TOT_GP_EDITBRUSH_TYPES
+} eGP_EditBrush_Types;
+
+
+/* Settings for a GPencil Stroke Sculpting Brush */
+typedef struct GP_EditBrush_Data {
+ short size; /* radius of brush */
+ short flag; /* eGP_EditBrush_Flag */
+ float strength; /* strength of effect */
+} GP_EditBrush_Data;
+
+/* GP_EditBrush_Data.flag */
+typedef enum eGP_EditBrush_Flag {
+ /* invert the effect of the brush */
+ GP_EDITBRUSH_FLAG_INVERT = (1 << 0),
+ /* adjust strength using pen pressure */
+ GP_EDITBRUSH_FLAG_USE_PRESSURE = (1 << 1),
+
+ /* strength of brush falls off with distance from cursor */
+ GP_EDITBRUSH_FLAG_USE_FALLOFF = (1 << 2),
+
+ /* smooth brush affects pressure values as well */
+ GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE = (1 << 3)
+} eGP_EditBrush_Flag;
+
+
+
+/* GPencil Stroke Sculpting Settings */
+typedef struct GP_BrushEdit_Settings {
+ GP_EditBrush_Data brush[10]; /* TOT_GP_EDITBRUSH_TYPES */
+ void *paintcursor; /* runtime */
+
+ int brushtype; /* eGP_EditBrush_Types */
+ int flag; /* eGP_BrushEdit_SettingsFlag */
+} GP_BrushEdit_Settings;
+
+/* GP_BrushEdit_Settings.flag */
+typedef enum eGP_BrushEdit_SettingsFlag {
+ /* only affect selected points */
+ GP_BRUSHEDIT_FLAG_SELECT_MASK = (1 << 0)
+} eGP_BrushEdit_SettingsFlag;
+
/* *************************************************************** */
/* Transform Orientations */
@@ -1129,6 +1227,10 @@ typedef struct UnifiedPaintSettings {
char draw_anchored;
char do_linear_conversion;
+ /* store last location of stroke or whether the mesh was hit. Valid only while stroke is active */
+ float last_location[3];
+ int last_hit;
+
float anchored_initial_mouse[2];
/* radius of brush, premultiplied with pressure.
@@ -1164,6 +1266,44 @@ typedef enum {
UNIFIED_PAINT_BRUSH_ALPHA_PRESSURE = (1 << 4)
} UnifiedPaintSettingsFlags;
+
+typedef struct CurvePaintSettings {
+ char curve_type;
+ char flag;
+ char depth_mode;
+ char surface_plane;
+ int error_threshold;
+ float radius_min, radius_max;
+ float radius_taper_start, radius_taper_end;
+ float radius_offset;
+ float corner_angle;
+} CurvePaintSettings;
+
+/* CurvePaintSettings.flag */
+enum {
+ CURVE_PAINT_FLAG_CORNERS_DETECT = (1 << 0),
+ CURVE_PAINT_FLAG_PRESSURE_RADIUS = (1 << 1),
+ CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS = (1 << 2),
+};
+
+/* CurvePaintSettings.depth_mode */
+enum {
+ CURVE_PAINT_PROJECT_CURSOR = 0,
+ CURVE_PAINT_PROJECT_SURFACE = 1,
+};
+
+/* CurvePaintSettings.surface_plane */
+enum {
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW = 0,
+ CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE = 1,
+ CURVE_PAINT_SURFACE_PLANE_VIEW = 2,
+};
+
+
+/* *************************************************************** */
+/* Stats */
+
+/* Stats for Meshes */
typedef struct MeshStatVis {
char type;
char _pad1[2];
@@ -1220,7 +1360,13 @@ typedef struct ToolSettings {
char gpencil_flags; /* flags/options for how the tool works */
char gpencil_src; /* for main 3D view Grease Pencil, where data comes from */
- char pad[4];
+ char gpencil_v3d_align; /* stroke placement settings: 3D View */
+ char gpencil_v2d_align; /* : General 2D Editor */
+ char gpencil_seq_align; /* : Sequencer Preview */
+ char gpencil_ima_align; /* : Image Editor */
+
+ /* Grease Pencil Sculpt */
+ struct GP_BrushEdit_Settings gp_sculpt;
/* Image Paint (8 byttse aligned please!) */
struct ImagePaintSettings imapaint;
@@ -1236,10 +1382,10 @@ typedef struct ToolSettings {
/* Auto-Keying Mode */
short autokey_mode, autokey_flag; /* defines in DNA_userdef_types.h */
+ char keyframe_type; /* keyframe type (see DNA_curve_types.h) */
/* Multires */
char multires_subdiv_type;
- char pad3[1];
/* Skeleton generation */
short skgen_resolution;
@@ -1305,6 +1451,8 @@ typedef struct ToolSettings {
/* Unified Paint Settings */
struct UnifiedPaintSettings unified_paint_settings;
+ struct CurvePaintSettings curve_paint_settings;
+
struct MeshStatVis statvis;
} ToolSettings;
@@ -1411,7 +1559,7 @@ typedef struct Scene {
void *pad1;
struct DagForest *theDag;
short dagflags;
- short recalc; /* recalc = counterpart of ob->recalc */
+ short pad3;
/* User-Defined KeyingSets */
int active_keyingset; /* index of the active KeyingSet. first KeyingSet has index 1, 'none' active is 0, 'add new' is -1 */
@@ -1539,7 +1687,7 @@ typedef struct Scene {
#define R_FREE_IMAGE 0x0100
#define R_SINGLE_LAYER 0x0200
#define R_EXR_TILE_FILE 0x0400
-#define R_COMP_FREE 0x0800
+/* #define R_COMP_FREE 0x0800 */
#define R_NO_IMAGE_LOAD 0x1000
#define R_NO_TEX 0x2000
#define R_NO_FRAME_UPDATE 0x4000
@@ -1633,16 +1781,17 @@ extern const char *RE_engine_id_CYCLES;
/* **************** SCENE ********************* */
+/* note that much higher maxframes give imprecise sub-frames, see: T46859 */
/* for general use */
-#define MAXFRAME 300000
-#define MAXFRAMEF 300000.0f
+#define MAXFRAME 500000
+#define MAXFRAMEF 500000.0f
#define MINFRAME 0
#define MINFRAMEF 0.0f
/* (minimum frame number for current-frame) */
-#define MINAFRAME -300000
-#define MINAFRAMEF -300000.0f
+#define MINAFRAME -500000
+#define MINAFRAMEF -500000.0f
/* depricate this! */
#define TESTBASE(v3d, base) ( \
@@ -1735,9 +1884,6 @@ extern const char *RE_engine_id_CYCLES;
#define SCE_SELECT_POINT 2
#define SCE_SELECT_END 4
-/* sce->recalc (now in use by previewrender) */
-#define SCE_PRV_CHANGED 1
-
/* toolsettings->prop_mode (proportional falloff) */
#define PROP_SMOOTH 0
#define PROP_SPHERE 1
@@ -1912,7 +2058,12 @@ typedef enum ImagePaintMode {
#define EDGE_MODE_TAG_FREESTYLE 5
/* toolsettings->gpencil_flags */
-#define GP_TOOL_FLAG_PAINTSESSIONS_ON (1<<0)
+typedef enum eGPencil_Flags {
+ /* "Continuous Drawing" - The drawing operator enters a mode where multiple strokes can be drawn */
+ GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0),
+ /* When creating new frames, the last frame gets used as the basis for the new one */
+ GP_TOOL_FLAG_RETAIN_LAST = (1 << 1),
+} eGPencil_Flags;
/* toolsettings->gpencil_src */
typedef enum eGPencil_Source_3D {
@@ -1920,6 +2071,22 @@ typedef enum eGPencil_Source_3D {
GP_TOOL_SOURCE_OBJECT = 1
} eGPencil_Source_3d;
+/* toolsettings->gpencil_*_align - Stroke Placement mode flags */
+typedef enum eGPencil_Placement_Flags {
+ /* New strokes are added in viewport/data space (i.e. not screen space) */
+ GP_PROJECT_VIEWSPACE = (1 << 0),
+
+ /* Viewport space, but relative to render canvas (Sequencer Preview Only) */
+ GP_PROJECT_CANVAS = (1 << 1),
+
+ /* Project into the screen's Z values */
+ GP_PROJECT_DEPTH_VIEW = (1 << 2),
+ GP_PROJECT_DEPTH_STROKE = (1 << 3),
+
+ /* "Use Endpoints" */
+ GP_PROJECT_DEPTH_STROKE_ENDPOINTS = (1 << 4),
+} eGPencil_Placement_Flags;
+
/* toolsettings->particle flag */
#define PE_KEEP_LENGTHS 1
#define PE_LOCK_FIRST 2
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 45b3aad92e4..fbeabb351ac 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -290,7 +290,6 @@ enum {
#define AREAGRID 4
#define AREAMINX 32
#define HEADERY 26
-#define AREAMINY (HEADERY+EDGEWIDTH)
#define HEADERDOWN 1
#define HEADERTOP 2
@@ -345,8 +344,10 @@ enum {
#define UI_LIST_AUTO_SIZE_THRESHOLD 1
/* uiList filter flags (dyn_data) */
+/* WARNING! Those values are used by integer RNA too, which does not handle well values > INT_MAX...
+ * So please do not use 32nd bit here. */
enum {
- UILST_FLT_ITEM = 1 << 31, /* This item has passed the filter process successfully. */
+ UILST_FLT_ITEM = 1 << 30, /* This item has passed the filter process successfully. */
};
/* uiList filter options */
@@ -357,7 +358,7 @@ enum {
/* uiList filter orderby type */
enum {
- UILST_FLT_SORT_ALPHA = 1 << 0,
+ UILST_FLT_SORT_ALPHA = 1 << 0,
UILST_FLT_SORT_REVERSE = 1 << 31 /* Special value, bitflag used to reverse order! */
};
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index d886dcf2807..37064854920 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -303,8 +303,6 @@ typedef struct bJoystickSensor {
#define SENS_JOY_ANY_EVENT 1
#define SENS_JOY_BUTTON 0 /* axis type */
-#define SENS_JOY_BUTTON_PRESSED 0
-#define SENS_JOY_BUTTON_RELEASED 1
#define SENS_JOY_AXIS 1 /* axis type */
#define SENS_JOY_X_AXIS 0
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 69e7fb43fb6..3a64890a84b 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -307,8 +307,9 @@ typedef struct SequenceModifierData {
int type, flag;
char name[64]; /* MAX_NAME */
- /* mask input, either sequence or maks ID */
- int mask_input_type, pad;
+ /* mask input, either sequence or mask ID */
+ int mask_input_type;
+ int mask_time;
struct Sequence *mask_sequence;
struct Mask *mask_id;
@@ -344,6 +345,26 @@ typedef struct SequencerMaskModifierData {
SequenceModifierData modifier;
} SequencerMaskModifierData;
+typedef struct WhiteBalanceModifierData {
+ SequenceModifierData modifier;
+
+ float white_value[3];
+ float pad;
+} WhiteBalanceModifierData;
+
+typedef struct SequencerTonemapModifierData {
+ SequenceModifierData modifier;
+
+ float key, offset, gamma;
+ float intensity, contrast, adaptation, correction;
+ int type;
+} SequencerTonemapModifierData;
+
+enum {
+ SEQ_TONEMAP_RH_SIMPLE = 0,
+ SEQ_TONEMAP_RD_PHOTORECEPTOR = 1,
+};
+
/* ***************** Scopes ****************** */
typedef struct SequencerScopes {
@@ -417,6 +438,9 @@ enum {
SEQ_SCENE_NO_GPENCIL = (1 << 28),
SEQ_USE_VIEWS = (1 << 29),
+ /* access scene strips directly (like a metastrip) */
+ SEQ_SCENE_STRIPS = (1 << 30),
+
SEQ_INVALID_EFFECT = (1 << 31),
};
@@ -516,6 +540,8 @@ enum {
seqModifierType_HueCorrect = 3,
seqModifierType_BrightContrast = 4,
seqModifierType_Mask = 5,
+ seqModifierType_WhiteBalance = 6,
+ seqModifierType_Tonemap = 7,
NUM_SEQUENCE_MODIFIER_TYPES
};
@@ -531,4 +557,11 @@ enum {
SEQUENCE_MASK_INPUT_ID = 1
};
+enum {
+ /* Mask animation will be remapped relative to the strip start frame. */
+ SEQUENCE_MASK_TIME_RELATIVE = 0,
+ /* Global (scene) frame number will be used to access the mask. */
+ SEQUENCE_MASK_TIME_ABSOLUTE = 1,
+};
+
#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h
index 5e011678fee..76de8443faa 100644
--- a/source/blender/makesdna/DNA_smoke_types.h
+++ b/source/blender/makesdna/DNA_smoke_types.h
@@ -77,6 +77,12 @@ enum {
#define SM_ACTIVE_COLORS (1<<2)
#define SM_ACTIVE_COLOR_SET (1<<3)
+enum {
+ VDB_COMPRESSION_BLOSC = 0,
+ VDB_COMPRESSION_ZIP = 1,
+ VDB_COMPRESSION_NONE = 2,
+};
+
typedef struct SmokeDomainSettings {
struct SmokeModifierData *smd; /* for fast RNA access */
struct FLUID_3D *fluid;
@@ -103,6 +109,8 @@ typedef struct SmokeDomainSettings {
float obj_shift_f[3]; /* how much object has shifted since previous smoke frame (used to "lock" domain while drawing) */
float imat[4][4]; /* domain object imat */
float obmat[4][4]; /* domain obmat */
+ float fluidmat[4][4]; /* low res fluid matrix */
+ float fluidmat_wt[4][4]; /* high res fluid matrix */
int base_res[3]; /* initial "non-adapted" resolution */
int res_min[3]; /* cell min */
@@ -129,8 +137,14 @@ typedef struct SmokeDomainSettings {
float strength;
int res_wt[3];
float dx_wt;
+ /* point cache options */
int cache_comp;
int cache_high_comp;
+ /* OpenVDB cache options */
+ int openvdb_comp;
+ char cache_file_format;
+ char data_depth;
+ char pad[2];
/* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading old files. */
struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index b8f2ce1b2ea..46b7d717991 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -124,7 +124,7 @@ typedef struct SpaceButs {
short mainb, mainbo, mainbuser; /* context tabs */
short re_align, align; /* align for panels */
short preview; /* preview is signal to refresh */
- /* texture context selector (material, lamp, particles, world, other)*/
+ /* texture context selector (material, lamp, particles, world, other) */
short texture_context, texture_context_prev;
char flag, pad[7];
@@ -147,7 +147,8 @@ typedef struct SpaceButs {
#define CONTEXT_LOGIC 6
/* sbuts->mainb old (deprecated) */
-#define BUTS_VIEW 0
+#ifdef DNA_DEPRECATED_ALLOW
+// #define BUTS_VIEW 0
#define BUTS_LAMP 1
#define BUTS_MAT 2
#define BUTS_TEX 3
@@ -159,9 +160,10 @@ typedef struct SpaceButs {
#define BUTS_FPAINT 9
#define BUTS_RADIO 10
#define BUTS_SCRIPT 11
-#define BUTS_SOUND 12
+// #define BUTS_SOUND 12
#define BUTS_CONSTRAINT 13
-#define BUTS_EFFECTS 14
+// #define BUTS_EFFECTS 14
+#endif
/* buts->mainb new */
typedef enum eSpaceButtons_Context {
@@ -327,8 +329,10 @@ typedef struct SpaceIpo {
short autosnap; /* time-transform autosnapping settings for Graph editor (eAnimEdit_AutoSnap in DNA_action_types.h) */
int flag; /* settings for Graph editor (eGraphEdit_Flag) */
+ float cursorTime; /* time value for cursor (when in drivers mode; animation uses current frame) */
float cursorVal; /* cursor value (y-value, x-value is current frame) */
int around; /* pivot point for transforms */
+ int pad;
} SpaceIpo;
@@ -587,7 +591,7 @@ typedef struct FileSelectParams {
char renamefile[256];
char renameedit[256]; /* annoying but the first is only used for initialization */
- char filter_glob[64]; /* list of filetypes to filter */
+ char filter_glob[256]; /* list of filetypes to filter */
char filter_search[64]; /* text items' name must match to be shown. */
int filter_id; /* same as filter, but for ID types (aka library groups). */
@@ -646,7 +650,7 @@ typedef struct SpaceFile {
short systemnr, system_bookmarknr;
} SpaceFile;
-/* FSMenuEntry's without paths indicate seperators */
+/* FSMenuEntry's without paths indicate separators */
typedef struct FSMenuEntry {
struct FSMenuEntry *next;
@@ -849,7 +853,7 @@ typedef struct FileDirEntryArr {
/* FileDirEntry.status */
enum {
- ASSET_STATUS_LOCAL = 1 << 0, /* If active uuid is available localy/immediately. */
+ ASSET_STATUS_LOCAL = 1 << 0, /* If active uuid is available locally/immediately. */
ASSET_STATUS_LATEST = 1 << 1, /* If active uuid is latest available version. */
};
@@ -920,7 +924,7 @@ typedef enum eSpaceImage_Mode {
/* SpaceImage->sticky
* Note DISABLE should be 0, however would also need to re-arrange icon order,
- * also, sticky loc is the default mode so this means we don't need to 'do_versons' */
+ * also, sticky loc is the default mode so this means we don't need to 'do_versions' */
typedef enum eSpaceImage_Sticky {
SI_STICKY_LOC = 0,
SI_STICKY_DISABLE = 1,
@@ -953,7 +957,7 @@ typedef enum eSpaceImage_Flag {
/* SI_DEPRECATED5 = (1 << 18), */ /* deprecated */
/* this means that the image is drawn until it reaches the view edge,
- * in the image view, its unrelated to the 'tile' mode for texface
+ * in the image view, it's unrelated to the 'tile' mode for texface
*/
SI_DRAW_TILE = (1 << 19),
SI_SMOOTH_UV = (1 << 20),
@@ -964,7 +968,11 @@ typedef enum eSpaceImage_Flag {
SI_COLOR_CORRECTION = (1 << 24),
SI_NO_DRAW_TEXPAINT = (1 << 25),
- SI_DRAW_METADATA = (1 << 26)
+ SI_DRAW_METADATA = (1 << 26),
+
+ SI_SHOW_R = (1 << 27),
+ SI_SHOW_G = (1 << 28),
+ SI_SHOW_B = (1 << 29),
} eSpaceImage_Flag;
/* Text Editor ============================================ */
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index af6adbecd83..995d7645dc0 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -143,15 +143,18 @@ typedef struct PointDensity {
float falloff_softness;
float radius;
short source;
- short color_source;
- int totpoints;
+ short pad0;
+
+ short color_source; /* psys_color_source */
+ short ob_color_source;
- int pdpad;
+ int totpoints;
struct Object *object; /* for 'Object' or 'Particle system' type - source object */
int psys; /* index+1 in ob.particlesystem, non-ID pointer not allowed */
short psys_cache_space; /* cache points in worldspace, object space, ... ? */
short ob_cache_space; /* cache points in worldspace, object space, ... ? */
+ char vertex_attribute_name[64]; /* vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */
void *point_tree; /* the acceleration tree containing points */
float *point_data; /* dynamically allocated extra for extra information, like particle age */
@@ -160,10 +163,10 @@ typedef struct PointDensity {
short noise_depth;
short noise_influence;
short noise_basis;
- short pdpad3[3];
+ short pad1[3];
float noise_fac;
- float speed_scale, falloff_speed_scale, pdpad2;
+ float speed_scale, falloff_speed_scale, pad2;
struct ColorBand *coba; /* for time -> color */
struct CurveMapping *falloff_curve; /* falloff density curve */
@@ -368,12 +371,14 @@ typedef struct ColorMapping {
#define TXF_AREA 3
/* imaflag unused, only for version check */
+#ifdef DNA_DEPRECATED_ALLOW
#define TEX_FIELDS_ 8
#define TEX_ANIMCYCLIC_ 64
#define TEX_ANIM5_ 128
#define TEX_ANTIALI_ 256
#define TEX_ANTISCALE_ 512
#define TEX_STD_FIELD_ 1024
+#endif
/* flag */
#define TEX_COLORBAND 1
@@ -592,13 +597,21 @@ enum {
#define TEX_PD_NOISE_TIME 3
/* color_source */
-#define TEX_PD_COLOR_CONSTANT 0
-#define TEX_PD_COLOR_PARTAGE 1
-#define TEX_PD_COLOR_PARTSPEED 2
-#define TEX_PD_COLOR_PARTVEL 3
+enum {
+ TEX_PD_COLOR_CONSTANT = 0,
+ /* color_source: particles */
+ TEX_PD_COLOR_PARTAGE = 1,
+ TEX_PD_COLOR_PARTSPEED = 2,
+ TEX_PD_COLOR_PARTVEL = 3,
+ /* color_source: vertices */
+ TEX_PD_COLOR_VERTCOL = 1,
+ TEX_PD_COLOR_VERTWEIGHT = 2,
+ TEX_PD_COLOR_VERTNOR = 3,
+};
#define POINT_DATA_VEL 1
#define POINT_DATA_LIFE 2
+#define POINT_DATA_COLOR 4
/******************** Voxel Data *****************************/
/* flag */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 00dc1c1205e..af1dfc62894 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -284,7 +284,7 @@ typedef struct ThemeSpace {
char nodeclass_pattern[4], nodeclass_layout[4];
char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4]; /* for sequence editor */
- char effect[4], transition[4], meta[4];
+ char effect[4], transition[4], meta[4], text_strip[4], pad[4];
char editmesh_active[4];
char handle_vertex[4];
@@ -545,6 +545,7 @@ typedef struct UserDef {
char author[80]; /* author name for file formats supporting it */
char font_path_ui[1024];
+ char font_path_ui_mono[1024];
int compute_device_type;
int compute_device_id;
@@ -683,7 +684,6 @@ typedef enum eUserpref_UI_Flag2 {
USER_KEEP_SESSION = (1 << 0),
USER_REGION_OVERLAP = (1 << 1),
USER_TRACKPAD_NATURAL = (1 << 2),
- USER_OPENGL_NO_WARN_SUPPORT = (1 << 3)
} eUserpref_UI_Flag2;
/* Auto-Keying mode */
@@ -754,7 +754,7 @@ typedef enum eOpenGL_RenderingOptions {
/* USER_DISABLE_SOUND = (1 << 1), */ /* deprecated, don't use without checking for */
/* backwards compatibilty in do_versions! */
USER_DISABLE_MIPMAP = (1 << 2),
- USER_DISABLE_VBO = (1 << 3),
+ /* USER_DISABLE_VBO = (1 << 3), */ /* DEPRECATED we always use vertex buffers now */
/* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */
} eOpenGL_RenderingOptions;
@@ -802,19 +802,23 @@ typedef enum eTimecodeStyles {
* with '+' to denote the frames
* i.e. HH:MM:SS+FF, MM:SS+FF, SS+FF, or MM:SS
*/
- USER_TIMECODE_MINIMAL = 0,
-
+ USER_TIMECODE_MINIMAL = 0,
+
/* reduced SMPTE - (HH:)MM:SS:FF */
- USER_TIMECODE_SMPTE_MSF = 1,
-
+ USER_TIMECODE_SMPTE_MSF = 1,
+
/* full SMPTE - HH:MM:SS:FF */
- USER_TIMECODE_SMPTE_FULL = 2,
-
+ USER_TIMECODE_SMPTE_FULL = 2,
+
/* milliseconds for sub-frames - HH:MM:SS.sss */
- USER_TIMECODE_MILLISECONDS = 3,
-
+ USER_TIMECODE_MILLISECONDS = 3,
+
/* seconds only */
- USER_TIMECODE_SECONDS_ONLY = 4,
+ USER_TIMECODE_SECONDS_ONLY = 4,
+
+ /* Private (not exposed as generic choices) options. */
+ /* milliseconds for sub-frames , SubRip format- HH:MM:SS,sss */
+ USER_TIMECODE_SUBRIP = 100,
} eTimecodeStyles;
/* theme drawtypes */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 0ba6c4dcf01..0ef8f2616c4 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -250,7 +250,6 @@ typedef struct View3D {
#define V3D_DISPBGPICS 2
#define V3D_HIDE_HELPLINES 4
#define V3D_INVALID_BACKBUF 8
-#define V3D_INVALID_BACKBUF 8
#define V3D_ALIGN 1024
#define V3D_SELECT_OUTLINE 2048
@@ -289,7 +288,6 @@ typedef struct View3D {
#define RV3D_VIEW_RIGHT 4
#define RV3D_VIEW_TOP 5
#define RV3D_VIEW_BOTTOM 6
-#define RV3D_VIEW_PERSPORTHO 7
#define RV3D_VIEW_CAMERA 8
#define RV3D_VIEW_IS_AXIS(view) \
@@ -316,11 +314,18 @@ typedef struct View3D {
#define V3D_SHOW_WORLD (1 << 0)
/* View3D->around */
-#define V3D_CENTER 0
-#define V3D_CENTROID 3
-#define V3D_CURSOR 1
-#define V3D_LOCAL 2
-#define V3D_ACTIVE 4
+enum {
+ /* center of the bounding box */
+ V3D_AROUND_CENTER_BOUNDS = 0,
+ /* center from the sum of all points divided by the total */
+ V3D_AROUND_CENTER_MEAN = 3,
+ /* pivot around the 2D/3D cursor */
+ V3D_AROUND_CURSOR = 1,
+ /* pivot around each items own origin */
+ V3D_AROUND_LOCAL_ORIGINS = 2,
+ /* pivot around the active items origin */
+ V3D_AROUND_ACTIVE = 4,
+};
/*View3D types (only used in tools, not actually saved)*/
#define V3D_VIEW_STEPLEFT 1
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 51ed8bb6c0d..14400c84b69 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -62,7 +62,7 @@ struct Stereo3dFormat;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
-/* keep in sync with 'wm_report_items' in wm_rna.c */
+/* keep in sync with 'rna_enum_wm_report_items' in wm_rna.c */
typedef enum ReportType {
RPT_DEBUG = (1 << 0),
RPT_INFO = (1 << 1),
@@ -190,6 +190,8 @@ typedef struct wmWindow {
short modalcursor; /* the current modal cursor */
short grabcursor; /* cursor grab mode */
short addmousemove; /* internal: tag this for extra mousemove event, makes cursors/buttons active on UI switching */
+ short multisamples; /* amount of samples for OpenGL FSA the ghost window was created with, if zero no FSA */
+ short pad[3];
int winid; /* winid also in screens, is for retrieving this window after read */
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
index 73bfa7a36fe..5fd4c9fd407 100644
--- a/source/blender/makesdna/DNA_world_types.h
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -86,7 +86,7 @@ typedef struct World {
* bit 2: (reserved) depth of field
* bit 3: (gameengine): Activity culling is enabled.
* bit 4: ambient occlusion
- * bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling
+ * bit 5: (gameengine) : enable Bullet DBVT tree for view frustum culling
*/
short mode; // partially moved to scene->gamedata in 2.5
short occlusionRes; /* resolution of occlusion Z buffer in pixel */ // XXX moved to scene->gamedata in 2.5
diff --git a/source/blender/makesdna/SConscript b/source/blender/makesdna/SConscript
deleted file mode 100644
index f276070f3dc..00000000000
--- a/source/blender/makesdna/SConscript
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-objs = []
-defs = []
-
-o = SConscript('intern/SConscript')
-objs += o
-
-incs = [
- '.',
- '#/intern/guardedalloc',
- '../blenlib',
- ]
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-env.BlenderLib('bf_dna', objs, incs, defs, libtype=['core', 'player'], priority = [215, 200])
diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript
deleted file mode 100644
index 50c26eb6732..00000000000
--- a/source/blender/makesdna/intern/SConscript
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-import os
-
-def normpath(path):
- return os.path.abspath(os.path.normpath(path))
-
-Import ('env')
-cflags = ''
-defines = []
-root_build_dir=normpath(env['BF_BUILDDIR'])
-
-source_files = ['makesdna.c']
-header_files = env.Glob('../*.h')
-
-makesdna_tool = env.Clone()
-dna = env.Clone()
-makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ')
-
-makesdna_tool.Append (CPPPATH = ['#/intern/guardedalloc',
- '#/intern/atomic',
- '../../makesdna', '../../bmesh',
- '../../blenlib'])
-
-if env['OURPLATFORM'] == 'linuxcross':
- USE_WINE = True # when cross compiling on linux 64bit this is useful
-else:
- USE_WINE = False
-
-if not USE_WINE:
- if env['OURPLATFORM'] == 'linuxcross':
- makesdna_tool.Replace(CC='gcc')
- makesdna_tool.Replace(AR='ar')
- makesdna_tool.Replace(LINK='gcc')
-
-if sys.platform != 'cygwin':
- makesdna_tool.Append (CCFLAGS = cflags)
-makesdna_tool.Append (CPPDEFINES = defines)
-makesdna_tool.Append( CFLAGS = env['CFLAGS'])
-makesdna_tool.Append( CCFLAGS = env['CCFLAGS'])
-makesdna_tool.Append( LINKFLAGS = env['PLATFORM_LINKFLAGS'])
-targetdir = normpath(root_build_dir+'/lib')
-
-if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- targetdir = '#'+targetdir
-makesdna_tool.Append (LIBPATH = targetdir)
-if env['BF_PROFILE']:
- makesdna_tool.Append (LINKFLAGS = env['BF_PROFILE_LINKFLAGS'])
-
-targetdir = normpath(root_build_dir + '/makesdna')
-
-if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- targetdir = '#' + targetdir
-
-makesdna = makesdna_tool.Program (target = targetdir, source = source_files, LIBS=['bf_intern_guardedalloc', 'bf_blenlib'])
-
-dna_dict = dna.Dictionary()
-dna.Depends ('dna.c', makesdna)
-dna.Depends ('dna.c', header_files)
-
-if env['OURPLATFORM'] != 'linuxcross':
- dna.Command ('dna.c', '', "\"" + root_build_dir+os.sep+"makesdna\" $TARGET")
-else:
- dna.Command ('dna.c', '', ('', 'wine ')[USE_WINE] + root_build_dir+os.sep+"makesdna $TARGET")
-
-# TODO, get WITH_DNA_GHASH working, see CMake's 'WITH_DNA_GHASH'
-obj = ['intern/dna.c', 'intern/dna_genfile.c']
-Return ('obj')
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 16fbcbebe50..4f19e819625 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -582,7 +582,7 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn
typenr = sp[0];
for (a = 0; a < sdna->nr_structs; a++) {
- if (a != structnr && compflags[a] == 1) {
+ if ((a != structnr) && (compflags[a] == SDNA_CMP_EQUAL)) {
sp = sdna->structs[a];
elems = sp[1];
sp += 2;
@@ -590,7 +590,7 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn
if (sp[0] == typenr) {
cp = sdna->names[sp[1]];
if (!ispointer(cp)) {
- compflags[a] = 2;
+ compflags[a] = SDNA_CMP_NOT_EQUAL;
recurs_test_compflags(sdna, compflags, a);
}
}
@@ -635,7 +635,8 @@ char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
sp_new = findstruct_name(newsdna, oldsdna->types[sp_old[0]]);
if (sp_new) {
- compflags[a] = 2; /* initial assumption */
+ /* initial assumption */
+ compflags[a] = SDNA_CMP_NOT_EQUAL;
/* compare length and amount of elems */
if (sp_new[1] == sp_old[1]) {
@@ -663,7 +664,10 @@ char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
sp_old += 2;
sp_new += 2;
}
- if (b == 0) compflags[a] = 1; /* no differences found */
+ if (b == 0) {
+ /* no differences found */
+ compflags[a] = SDNA_CMP_EQUAL;
+ }
}
}
@@ -674,18 +678,20 @@ char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna)
/* first struct in util.h is struct Link, this is skipped in compflags (als # 0).
* was a bug, and this way dirty patched! Solve this later....
*/
- compflags[0] = 1;
+ compflags[0] = SDNA_CMP_EQUAL;
/* Because structs can be inside structs, we recursively
* set flags when a struct is altered
*/
for (a = 0; a < oldsdna->nr_structs; a++) {
- if (compflags[a] == 2) recurs_test_compflags(oldsdna, compflags, a);
+ if (compflags[a] == SDNA_CMP_NOT_EQUAL) {
+ recurs_test_compflags(oldsdna, compflags, a);
+ }
}
#if 0
for (a = 0; a < oldsdna->nr_structs; a++) {
- if (compflags[a] == 2) {
+ if (compflags[a] == SDNA_CMP_NOT_EQUAL) {
spold = oldsdna->structs[a];
printf("changed: %s\n", oldsdna->types[spold[0]]);
}
@@ -705,8 +711,6 @@ static eSDNA_Type sdna_type_nr(const char *dna_type)
else if ( strcmp(dna_type, "short") == 0) return SDNA_TYPE_SHORT;
else if ((strcmp(dna_type, "ushort") == 0) || (strcmp(dna_type, "unsigned short") == 0)) return SDNA_TYPE_USHORT;
else if ( strcmp(dna_type, "int") == 0) return SDNA_TYPE_INT;
- else if ( strcmp(dna_type, "long") == 0) return SDNA_TYPE_LONG;
- else if ((strcmp(dna_type, "ulong") == 0) || (strcmp(dna_type, "unsigned long") == 0)) return SDNA_TYPE_ULONG;
else if ( strcmp(dna_type, "float") == 0) return SDNA_TYPE_FLOAT;
else if ( strcmp(dna_type, "double") == 0) return SDNA_TYPE_DOUBLE;
else if ( strcmp(dna_type, "int64_t") == 0) return SDNA_TYPE_INT64;
@@ -758,10 +762,6 @@ static void cast_elem(
val = *( (unsigned short *)olddata); break;
case SDNA_TYPE_INT:
val = *( (int *)olddata); break;
- case SDNA_TYPE_LONG:
- val = *( (int *)olddata); break;
- case SDNA_TYPE_ULONG:
- val = *( (unsigned int *)olddata); break;
case SDNA_TYPE_FLOAT:
val = *( (float *)olddata); break;
case SDNA_TYPE_DOUBLE:
@@ -783,10 +783,6 @@ static void cast_elem(
*( (unsigned short *)curdata) = val; break;
case SDNA_TYPE_INT:
*( (int *)curdata) = val; break;
- case SDNA_TYPE_LONG:
- *( (int *)curdata) = val; break;
- case SDNA_TYPE_ULONG:
- *( (unsigned int *)curdata) = val; break;
case SDNA_TYPE_FLOAT:
if (otypenr < 2) val /= 255;
*( (float *)curdata) = val; break;
@@ -1050,8 +1046,8 @@ static void reconstruct_struct(
if (oldSDNAnr == -1) return;
if (curSDNAnr == -1) return;
- if (compflags[oldSDNAnr] == 1) { /* if recursive: test for equal */
-
+ if (compflags[oldSDNAnr] == SDNA_CMP_EQUAL) {
+ /* if recursive: test for equal */
spo = oldsdna->structs[oldSDNAnr];
elen = oldsdna->typelens[spo[0]];
memcpy(cur, data, elen);
@@ -1168,10 +1164,10 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
}
}
else {
- /* non-struct field type */
+ /* non-struct field type */
if (ispointer(name)) {
if (oldsdna->pointerlen == 8) {
-
+
mul = DNA_elem_array_size(name);
cpo = cur;
while (mul--) {
@@ -1186,20 +1182,14 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
}
}
else {
-
- if (spc[0] == SDNA_TYPE_SHORT ||
- spc[0] == SDNA_TYPE_USHORT)
- {
-
- /* exception: variable called blocktype/ipowin: derived from ID_ */
+ if (ELEM(spc[0], SDNA_TYPE_SHORT, SDNA_TYPE_USHORT)) {
+
+ /* exception: variable called blocktype: derived from ID_ */
bool skip = false;
if (name[0] == 'b' && name[1] == 'l') {
if (strcmp(name, "blocktype") == 0) skip = true;
}
- else if (name[0] == 'i' && name[1] == 'p') {
- if (strcmp(name, "ipowin") == 0) skip = true;
- }
-
+
if (skip == false) {
mul = DNA_elem_array_size(name);
cpo = cur;
@@ -1211,11 +1201,10 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
}
}
}
- else if ( (spc[0] == SDNA_TYPE_INT ||
- spc[0] == SDNA_TYPE_LONG ||
- spc[0] == SDNA_TYPE_ULONG ||
- spc[0] == SDNA_TYPE_FLOAT))
- {
+ else if (ELEM(spc[0], SDNA_TYPE_INT, SDNA_TYPE_FLOAT)) {
+ /* note, intentionally ignore long/ulong here these could be 4 or 8 bits,
+ * but turns out we only used for runtime vars and
+ * only once for a struct type thats no longer used. */
mul = DNA_elem_array_size(name);
cpo = cur;
@@ -1229,9 +1218,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
cpo += 4;
}
}
- else if ( (spc[0] == SDNA_TYPE_INT64) ||
- (spc[0] == SDNA_TYPE_UINT64))
- {
+ else if (ELEM(spc[0], SDNA_TYPE_INT64, SDNA_TYPE_UINT64, SDNA_TYPE_DOUBLE)) {
mul = DNA_elem_array_size(name);
cpo = cur;
while (mul--) {
@@ -1243,7 +1230,6 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data)
cpo += 8;
}
}
- /* FIXME: no conversion for SDNA_TYPE_DOUBLE? */
}
}
cur += elen;
@@ -1340,8 +1326,6 @@ int DNA_elem_type_size(const eSDNA_Type elem_nr)
case SDNA_TYPE_USHORT:
return 2;
case SDNA_TYPE_INT:
- case SDNA_TYPE_LONG:
- case SDNA_TYPE_ULONG:
case SDNA_TYPE_FLOAT:
return 4;
case SDNA_TYPE_DOUBLE:
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index a7ff4244d5f..651794da50d 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -65,7 +65,6 @@ static const char *includefiles[] = {
/* if you add files here, please add them at the end
* of makesdna.c (this file) as well */
-
"DNA_listBase.h",
"DNA_vec_types.h",
"DNA_ID.h",
@@ -80,8 +79,6 @@ static const char *includefiles[] = {
"DNA_lamp_types.h",
"DNA_material_types.h",
"DNA_vfont_types.h",
- /* if you add files here, please add them at the end
- * of makesdna.c (this file) as well */
"DNA_meta_types.h",
"DNA_curve_types.h",
"DNA_mesh_types.h",
@@ -99,8 +96,6 @@ static const char *includefiles[] = {
"DNA_userdef_types.h",
"DNA_screen_types.h",
"DNA_sdna_types.h",
- // if you add files here, please add them at the end
- // of makesdna.c (this file) as well
"DNA_fileglobal_types.h",
"DNA_sequence_types.h",
"DNA_effect_types.h",
@@ -122,8 +117,6 @@ static const char *includefiles[] = {
"DNA_particle_types.h",
"DNA_cloth_types.h",
"DNA_gpencil_types.h",
- /* if you add files here, please add them at the end
- * of makesdna.c (this file) as well */
"DNA_windowmanager_types.h",
"DNA_anim_types.h",
"DNA_boid_types.h",
@@ -136,6 +129,7 @@ static const char *includefiles[] = {
"DNA_rigidbody_types.h",
"DNA_freestyle_types.h",
"DNA_linestyle_types.h",
+ /* see comment above before editing! */
/* empty string to indicate end of includefiles */
""
@@ -197,7 +191,7 @@ static int preprocess_include(char *maindata, int len);
/**
* Scan this file for serializable types.
*/
-static int convert_include(char *filename);
+static int convert_include(const char *filename);
/**
* Determine how many bytes are needed for an array.
@@ -521,7 +515,7 @@ static int preprocess_include(char *maindata, int len)
return newlen;
}
-static void *read_file_data(char *filename, int *r_len)
+static void *read_file_data(const char *filename, int *r_len)
{
#ifdef WIN32
FILE *fp = fopen(filename, "rb");
@@ -562,7 +556,7 @@ static void *read_file_data(char *filename, int *r_len)
return data;
}
-static int convert_include(char *filename)
+static int convert_include(const char *filename)
{
/* read include file, skip structs with a '#' before it.
* store all data in temporal arrays.
@@ -573,7 +567,7 @@ static int convert_include(char *filename)
md = maindata = read_file_data(filename, &filelen);
if (filelen == -1) {
- printf("Can't read file %s\n", filename);
+ fprintf(stderr, "Can't read file %s\n", filename);
return 1;
}
@@ -606,7 +600,7 @@ static int convert_include(char *filename)
strct = add_type(md1, 0);
if (strct == -1) {
- printf("File '%s' contains struct we cant parse \"%s\"\n", filename, md1);
+ fprintf(stderr, "File '%s' contains struct we cant parse \"%s\"\n", filename, md1);
return 1;
}
@@ -638,7 +632,7 @@ static int convert_include(char *filename)
/* we've got a type! */
type = add_type(md1, 0);
if (type == -1) {
- printf("File '%s' contains struct we can't parse \"%s\"\n", filename, md1);
+ fprintf(stderr, "File '%s' contains struct we can't parse \"%s\"\n", filename, md1);
return 1;
}
@@ -728,63 +722,65 @@ static int arraysize(const char *str)
static int calculate_structlens(int firststruct)
{
- int a, b, len_native, len_32, len_64, unknown = nr_structs, lastunknown, structtype, type, mul, namelen;
- const short *sp, *structpoin;
- const char *cp;
- int has_pointer, dna_error = 0;
-
+ int unknown = nr_structs, lastunknown;
+ bool dna_error = false;
+
while (unknown) {
lastunknown = unknown;
unknown = 0;
/* check all structs... */
- for (a = 0; a < nr_structs; a++) {
- structpoin = structs[a];
- structtype = structpoin[0];
+ for (int a = 0; a < nr_structs; a++) {
+ const short *structpoin = structs[a];
+ const int structtype = structpoin[0];
/* when length is not known... */
if (typelens_native[structtype] == 0) {
- sp = structpoin + 2;
- len_native = 0;
- len_32 = 0;
- len_64 = 0;
- has_pointer = 0;
+ const short *sp = structpoin + 2;
+ int len_native = 0;
+ int len_32 = 0;
+ int len_64 = 0;
+ bool has_pointer = false;
/* check all elements in struct */
- for (b = 0; b < structpoin[1]; b++, sp += 2) {
- type = sp[0];
- cp = names[sp[1]];
+ for (int b = 0; b < structpoin[1]; b++, sp += 2) {
+ int type = sp[0];
+ const char *cp = names[sp[1]];
- namelen = (int) strlen(cp);
+ int namelen = (int)strlen(cp);
/* is it a pointer or function pointer? */
if (cp[0] == '*' || cp[1] == '*') {
has_pointer = 1;
/* has the name an extra length? (array) */
- mul = 1;
+ int mul = 1;
if (cp[namelen - 1] == ']') mul = arraysize(cp);
if (mul == 0) {
- printf("Zero array size found or could not parse %s: '%.*s'\n", types[structtype], namelen + 1, cp);
+ fprintf(stderr, "Zero array size found or could not parse %s: '%.*s'\n",
+ types[structtype], namelen + 1, cp);
dna_error = 1;
}
/* 4-8 aligned/ */
if (sizeof(void *) == 4) {
if (len_native % 4) {
- printf("Align pointer error in struct (len_native 4): %s %s\n", types[structtype], cp);
+ fprintf(stderr, "Align pointer error in struct (len_native 4): %s %s\n",
+ types[structtype], cp);
dna_error = 1;
}
}
else {
if (len_native % 8) {
- printf("Align pointer error in struct (len_native 8): %s %s\n", types[structtype], cp);
+ fprintf(stderr, "Align pointer error in struct (len_native 8): %s %s\n",
+ types[structtype], cp);
dna_error = 1;
}
}
if (len_64 % 8) {
- printf("Align pointer error in struct (len_64 8): %s %s\n", types[structtype], cp);
+ fprintf(stderr, "Align pointer error in struct (len_64 8): %s %s\n",
+ types[structtype], cp);
dna_error = 1;
}
@@ -795,38 +791,44 @@ static int calculate_structlens(int firststruct)
}
else if (cp[0] == '[') {
/* parsing can cause names "var" and "[3]" to be found for "float var [3]" ... */
- printf("Parse error in struct, invalid member name: %s %s\n", types[structtype], cp);
+ fprintf(stderr, "Parse error in struct, invalid member name: %s %s\n",
+ types[structtype], cp);
dna_error = 1;
}
else if (typelens_native[type]) {
/* has the name an extra length? (array) */
- mul = 1;
+ int mul = 1;
if (cp[namelen - 1] == ']') mul = arraysize(cp);
if (mul == 0) {
- printf("Zero array size found or could not parse %s: '%.*s'\n", types[structtype], namelen + 1, cp);
+ fprintf(stderr, "Zero array size found or could not parse %s: '%.*s'\n",
+ types[structtype], namelen + 1, cp);
dna_error = 1;
}
/* struct alignment */
if (type >= firststruct) {
if (sizeof(void *) == 8 && (len_native % 8) ) {
- printf("Align struct error: %s %s\n", types[structtype], cp);
+ fprintf(stderr, "Align struct error: %s %s\n",
+ types[structtype], cp);
dna_error = 1;
}
}
/* 2-4-8 aligned/ */
if (type < firststruct && typelens_native[type] > 4 && (len_native % 8)) {
- printf("Align 8 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len_native % 8);
+ fprintf(stderr, "Align 8 error in struct: %s %s (add %d padding bytes)\n",
+ types[structtype], cp, len_native % 8);
dna_error = 1;
}
if (typelens_native[type] > 3 && (len_native % 4) ) {
- printf("Align 4 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len_native % 4);
+ fprintf(stderr, "Align 4 error in struct: %s %s (add %d padding bytes)\n",
+ types[structtype], cp, len_native % 4);
dna_error = 1;
}
else if (typelens_native[type] == 2 && (len_native % 2) ) {
- printf("Align 2 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len_native % 2);
+ fprintf(stderr, "Align 2 error in struct: %s %s (add %d padding bytes)\n",
+ types[structtype], cp, len_native % 2);
dna_error = 1;
}
@@ -854,13 +856,15 @@ static int calculate_structlens(int firststruct)
* has_pointer is set or len_native doesn't match any of 32/64bit lengths*/
if (has_pointer || len_64 != len_native || len_32 != len_native) {
if (len_64 % 8) {
- printf("Sizeerror 8 in struct: %s (add %d bytes)\n", types[structtype], len_64 % 8);
+ fprintf(stderr, "Sizeerror 8 in struct: %s (add %d bytes)\n",
+ types[structtype], len_64 % 8);
dna_error = 1;
}
}
if (len_native % 4) {
- printf("Sizeerror 4 in struct: %s (add %d bytes)\n", types[structtype], len_native % 4);
+ fprintf(stderr, "Sizeerror 4 in struct: %s (add %d bytes)\n",
+ types[structtype], len_native % 4);
dna_error = 1;
}
@@ -872,32 +876,32 @@ static int calculate_structlens(int firststruct)
}
if (unknown) {
- printf("ERROR: still %d structs unknown\n", unknown);
+ fprintf(stderr, "ERROR: still %d structs unknown\n", unknown);
if (debugSDNA) {
- printf("*** Known structs :\n");
+ fprintf(stderr, "*** Known structs :\n");
- for (a = 0; a < nr_structs; a++) {
- structpoin = structs[a];
- structtype = structpoin[0];
+ for (int a = 0; a < nr_structs; a++) {
+ const short *structpoin = structs[a];
+ const int structtype = structpoin[0];
/* length unknown */
if (typelens_native[structtype] != 0) {
- printf(" %s\n", types[structtype]);
+ fprintf(stderr, " %s\n", types[structtype]);
}
}
}
- printf("*** Unknown structs :\n");
+ fprintf(stderr, "*** Unknown structs :\n");
- for (a = 0; a < nr_structs; a++) {
- structpoin = structs[a];
- structtype = structpoin[0];
+ for (int a = 0; a < nr_structs; a++) {
+ const short *structpoin = structs[a];
+ const int structtype = structpoin[0];
/* length unknown yet */
if (typelens_native[structtype] == 0) {
- printf(" %s\n", types[structtype]);
+ fprintf(stderr, " %s\n", types[structtype]);
}
}
@@ -978,16 +982,24 @@ static int make_structDNA(const char *baseDirectory, FILE *file)
typelens_64 = MEM_callocN(sizeof(short) * maxnr, "typelens_64");
structs = MEM_callocN(sizeof(short *) * maxnr, "structs");
- /* insertion of all known types */
- /* watch it: uint is not allowed! use in structs an unsigned int */
- /* watch it: sizes must match DNA_elem_type_size() */
+ /**
+ * Insertion of all known types.
+ *
+ * \warning Order of function calls here must be aligned with #eSDNA_Type.
+ * \warning uint is not allowed! use in structs an unsigned int.
+ * \warning sizes must match #DNA_elem_type_size().
+ */
add_type("char", 1); /* SDNA_TYPE_CHAR */
add_type("uchar", 1); /* SDNA_TYPE_UCHAR */
add_type("short", 2); /* SDNA_TYPE_SHORT */
add_type("ushort", 2); /* SDNA_TYPE_USHORT */
add_type("int", 4); /* SDNA_TYPE_INT */
- add_type("long", 4); /* SDNA_TYPE_LONG */ /* maybe 4 or 8 bytes depending on platform, disallowed for now */
+
+ /* note, long isn't supported,
+ * these are place-holders to maintain alignment with eSDNA_Type*/
+ add_type("long", 4); /* SDNA_TYPE_LONG */
add_type("ulong", 4); /* SDNA_TYPE_ULONG */
+
add_type("float", 4); /* SDNA_TYPE_FLOAT */
add_type("double", 8); /* SDNA_TYPE_DOUBLE */
add_type("int64_t", 8); /* SDNA_TYPE_INT64 */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 406bab011aa..3a19211ab39 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -259,6 +259,8 @@ extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilLayer;
extern StructRNA RNA_GPencilStroke;
extern StructRNA RNA_GPencilStrokePoint;
+extern StructRNA RNA_GPencilSculptSettings;
+extern StructRNA RNA_GPencilSculptBrush;
extern StructRNA RNA_GameBooleanProperty;
extern StructRNA RNA_GameFloatProperty;
extern StructRNA RNA_GameIntProperty;
@@ -816,6 +818,9 @@ bool RNA_enum_description(EnumPropertyItem *item, const int value, const char **
int RNA_enum_from_value(EnumPropertyItem *item, const int value);
int RNA_enum_from_identifier(EnumPropertyItem *item, const char *identifier);
+void RNA_property_enum_items_ex(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const bool use_static,
+ EnumPropertyItem **item, int *r_totitem, bool *r_free);
void RNA_property_enum_items(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **item, int *r_totitem, bool *r_free);
void RNA_property_enum_items_gettexted(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop,
@@ -826,6 +831,14 @@ bool RNA_property_enum_value(struct bContext *C, PointerRNA *ptr, PropertyRNA *p
bool RNA_property_enum_identifier(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **identifier);
bool RNA_property_enum_name(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
bool RNA_property_enum_name_gettexted(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
+
+bool RNA_property_enum_item_from_value(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value,
+ EnumPropertyItem *r_item);
+bool RNA_property_enum_item_from_value_gettexted(
+ struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value,
+ EnumPropertyItem *r_item);
+
int RNA_property_enum_bitflag_identifiers(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **identifier);
StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop);
@@ -973,6 +986,7 @@ char *RNA_path_resolve_from_type_to_property(
char *RNA_path_full_ID_py(struct ID *id);
char *RNA_path_full_struct_py(struct PointerRNA *ptr);
+char *RNA_path_full_property_py_ex(PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback);
char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
@@ -1003,7 +1017,7 @@ void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values
int RNA_enum_get(PointerRNA *ptr, const char *name);
void RNA_enum_set(PointerRNA *ptr, const char *name, int value);
-void RNA_enum_set_identifier(PointerRNA *ptr, const char *name, const char *id);
+void RNA_enum_set_identifier(struct bContext *C, PointerRNA *ptr, const char *name, const char *id);
bool RNA_enum_is_equal(struct bContext *C, PointerRNA *ptr, const char *name, const char *enumname);
/* lower level functions that don't use a PointerRNA */
diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h
index cc876b4375e..bf8ea048fae 100644
--- a/source/blender/makesrna/RNA_define.h
+++ b/source/blender/makesrna/RNA_define.h
@@ -100,6 +100,8 @@ PropertyRNA *RNA_def_float_color(StructOrFunctionRNA *cont, const char *identifi
PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont, const char *identifier, int rows, int columns, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont, const char *identifier, int len, const float *default_value,
float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
+PropertyRNA *RNA_def_float_distance(StructOrFunctionRNA *cont, const char *identifier, float default_value,
+ float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
PropertyRNA *RNA_def_float_array(StructOrFunctionRNA *cont, const char *identifier, int len, const float *default_value,
float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index b1a631cc610..b1048f72022 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -35,127 +35,170 @@ struct bNodeSocketType;
/* Types */
-extern EnumPropertyItem id_type_items[];
-
/* use in cases where only dynamic types are used */
extern EnumPropertyItem DummyRNA_NULL_items[];
extern EnumPropertyItem DummyRNA_DEFAULT_items[];
-extern EnumPropertyItem object_mode_items[];
-extern EnumPropertyItem object_empty_drawtype_items[];
-extern EnumPropertyItem metaelem_type_items[];
+/* all others should follow 'rna_enum_*_items' naming */
+extern EnumPropertyItem rna_enum_id_type_items[];
+
+extern EnumPropertyItem rna_enum_object_mode_items[];
+extern EnumPropertyItem rna_enum_object_empty_drawtype_items[];
+extern EnumPropertyItem rna_enum_metaelem_type_items[];
+
+extern EnumPropertyItem rna_enum_proportional_falloff_items[];
+extern EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[];
+extern EnumPropertyItem rna_enum_proportional_editing_items[];
+extern EnumPropertyItem rna_enum_snap_target_items[];
+extern EnumPropertyItem rna_enum_snap_element_items[];
+extern EnumPropertyItem rna_enum_snap_node_element_items[];
+extern EnumPropertyItem rna_enum_mesh_select_mode_items[];
+extern EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
+extern EnumPropertyItem rna_enum_space_type_items[];
+extern EnumPropertyItem rna_enum_region_type_items[];
+extern EnumPropertyItem rna_enum_object_modifier_type_items[];
+extern EnumPropertyItem rna_enum_constraint_type_items[];
+extern EnumPropertyItem rna_enum_boidrule_type_items[];
+extern EnumPropertyItem rna_enum_sequence_modifier_type_items[];
+
+extern EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[];
+extern EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[];
+
+extern EnumPropertyItem rna_enum_image_type_items[];
+extern EnumPropertyItem rna_enum_image_color_mode_items[];
+extern EnumPropertyItem rna_enum_image_color_depth_items[];
+extern EnumPropertyItem rna_enum_image_generated_type_items[];
+
+extern EnumPropertyItem rna_enum_normal_space_items[];
+extern EnumPropertyItem rna_enum_normal_swizzle_items[];
+extern EnumPropertyItem rna_enum_bake_save_mode_items[];
+
+extern EnumPropertyItem rna_enum_views_format_items[];
+extern EnumPropertyItem rna_enum_views_format_multilayer_items[];
+extern EnumPropertyItem rna_enum_views_format_multiview_items[];
+extern EnumPropertyItem rna_enum_stereo3d_display_items[];
+extern EnumPropertyItem rna_enum_stereo3d_anaglyph_type_items[];
+extern EnumPropertyItem rna_enum_stereo3d_interlace_type_items[];
+
+extern EnumPropertyItem rna_enum_exr_codec_items[];
+extern EnumPropertyItem rna_enum_color_sets_items[];
+
+extern EnumPropertyItem rna_enum_beztriple_keyframe_type_items[];
+extern EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[];
+extern EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[];
+extern EnumPropertyItem rna_enum_keyframe_handle_type_items[];
+
+extern EnumPropertyItem rna_enum_keyblock_type_items[];
+
+extern EnumPropertyItem rna_enum_keyingset_path_grouping_items[];
+extern EnumPropertyItem rna_enum_keying_flag_items[];
+
+extern EnumPropertyItem rna_enum_keyframe_paste_offset_items[];
+extern EnumPropertyItem rna_enum_keyframe_paste_merge_items[];
+
+extern EnumPropertyItem rna_enum_fmodifier_type_items[];
-extern EnumPropertyItem proportional_falloff_items[];
-extern EnumPropertyItem proportional_falloff_curve_only_items[];
-extern EnumPropertyItem proportional_editing_items[];
-extern EnumPropertyItem snap_target_items[];
-extern EnumPropertyItem snap_element_items[];
-extern EnumPropertyItem snap_node_element_items[];
-extern EnumPropertyItem mesh_select_mode_items[];
-extern EnumPropertyItem mesh_delimit_mode_items[];
-extern EnumPropertyItem space_type_items[];
-extern EnumPropertyItem region_type_items[];
-extern EnumPropertyItem modifier_type_items[];
-extern EnumPropertyItem constraint_type_items[];
-extern EnumPropertyItem boidrule_type_items[];
-extern EnumPropertyItem sequence_modifier_type_items[];
+extern EnumPropertyItem rna_enum_nla_mode_extend_items[];
+extern EnumPropertyItem rna_enum_nla_mode_blend_items[];
-extern EnumPropertyItem modifier_triangulate_quad_method_items[];
-extern EnumPropertyItem modifier_triangulate_ngon_method_items[];
+extern EnumPropertyItem rna_enum_motionpath_bake_location_items[];
-extern EnumPropertyItem image_type_items[];
-extern EnumPropertyItem image_color_mode_items[];
-extern EnumPropertyItem image_color_depth_items[];
-extern EnumPropertyItem image_generated_type_items[];
+extern EnumPropertyItem rna_enum_event_value_items[];
+extern EnumPropertyItem rna_enum_event_type_items[];
+extern EnumPropertyItem rna_enum_operator_return_items[];
-extern EnumPropertyItem normal_space_items[];
-extern EnumPropertyItem normal_swizzle_items[];
-extern EnumPropertyItem bake_save_mode_items[];
+extern EnumPropertyItem rna_enum_brush_sculpt_tool_items[];
+extern EnumPropertyItem rna_enum_brush_vertex_tool_items[];
+extern EnumPropertyItem rna_enum_brush_image_tool_items[];
-extern EnumPropertyItem views_format_items[];
-extern EnumPropertyItem views_format_multilayer_items[];
-extern EnumPropertyItem views_format_multiview_items[];
-extern EnumPropertyItem stereo3d_display_items[];
-extern EnumPropertyItem stereo3d_anaglyph_type_items[];
-extern EnumPropertyItem stereo3d_interlace_type_items[];
+extern EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[];
-extern EnumPropertyItem exr_codec_items[];
-extern EnumPropertyItem color_sets_items[];
+extern EnumPropertyItem rna_enum_axis_xy_items[];
+extern EnumPropertyItem rna_enum_axis_xyz_items[];
-extern EnumPropertyItem beztriple_keyframe_type_items[];
-extern EnumPropertyItem beztriple_interpolation_mode_items[];
-extern EnumPropertyItem beztriple_interpolation_easing_items[];
-extern EnumPropertyItem keyframe_handle_type_items[];
+extern EnumPropertyItem rna_enum_axis_flag_xyz_items[];
-extern EnumPropertyItem keyblock_type_items[];
+extern EnumPropertyItem rna_enum_symmetrize_direction_items[];
-extern EnumPropertyItem keyingset_path_grouping_items[];
-extern EnumPropertyItem keying_flag_items[];
+extern EnumPropertyItem rna_enum_texture_type_items[];
-extern EnumPropertyItem keyframe_paste_offset_items[];
-extern EnumPropertyItem keyframe_paste_merge_items[];
+extern EnumPropertyItem rna_enum_lamp_type_items[];
-extern EnumPropertyItem fmodifier_type_items[];
+extern EnumPropertyItem rna_enum_unpack_method_items[];
-extern EnumPropertyItem nla_mode_extend_items[];
-extern EnumPropertyItem nla_mode_blend_items[];
+extern EnumPropertyItem rna_enum_object_type_items[];
-extern EnumPropertyItem motionpath_bake_location_items[];
+extern EnumPropertyItem rna_enum_object_type_curve_items[];
-extern EnumPropertyItem event_value_items[];
-extern EnumPropertyItem event_type_items[];
-extern EnumPropertyItem operator_return_items[];
+extern EnumPropertyItem rna_enum_rigidbody_object_type_items[];
+extern EnumPropertyItem rna_enum_rigidbody_object_shape_items[];
+extern EnumPropertyItem rna_enum_rigidbody_constraint_type_items[];
-extern EnumPropertyItem brush_sculpt_tool_items[];
-extern EnumPropertyItem brush_vertex_tool_items[];
-extern EnumPropertyItem brush_image_tool_items[];
+extern EnumPropertyItem rna_enum_object_axis_items[];
-extern EnumPropertyItem symmetrize_direction_items[];
+extern EnumPropertyItem rna_enum_controller_type_items[];
-extern EnumPropertyItem texture_type_items[];
+extern EnumPropertyItem rna_enum_render_pass_type_items[];
+extern EnumPropertyItem rna_enum_render_pass_debug_type_items[];
-extern EnumPropertyItem lamp_type_items[];
+extern EnumPropertyItem rna_enum_bake_pass_type_items[];
+extern EnumPropertyItem rna_enum_bake_pass_filter_type_items[];
-extern EnumPropertyItem unpack_method_items[];
+extern EnumPropertyItem rna_enum_keymap_propvalue_items[];
-extern EnumPropertyItem object_type_items[];
+extern EnumPropertyItem rna_enum_operator_context_items[];
-extern EnumPropertyItem object_type_curve_items[];
+extern EnumPropertyItem rna_enum_wm_report_items[];
-extern EnumPropertyItem rigidbody_object_type_items[];
-extern EnumPropertyItem rigidbody_object_shape_items[];
-extern EnumPropertyItem rigidbody_constraint_type_items[];
+extern EnumPropertyItem rna_enum_transform_mode_types[];
-extern EnumPropertyItem object_axis_items[];
-extern EnumPropertyItem object_axis_unsigned_items[];
+extern EnumPropertyItem rna_enum_posebone_rotmode_items[];
-extern EnumPropertyItem controller_type_items[];
+extern EnumPropertyItem rna_enum_property_type_items[];
+extern EnumPropertyItem rna_enum_property_subtype_items[];
+extern EnumPropertyItem rna_enum_property_unit_items[];
-extern EnumPropertyItem render_pass_type_items[];
-extern EnumPropertyItem render_pass_debug_type_items[];
+extern EnumPropertyItem rna_enum_gameproperty_type_items[];
-extern EnumPropertyItem keymap_propvalue_items[];
+extern EnumPropertyItem rna_enum_viewport_shade_items[];
-extern EnumPropertyItem operator_context_items[];
+extern EnumPropertyItem rna_enum_navigation_mode_items[];
-extern EnumPropertyItem wm_report_items[];
+extern EnumPropertyItem rna_enum_file_sort_items[];
-extern EnumPropertyItem transform_mode_types[];
+extern EnumPropertyItem rna_enum_node_socket_in_out_items[];
+extern EnumPropertyItem rna_enum_node_icon_items[];
-extern EnumPropertyItem posebone_rotmode_items[];
+extern EnumPropertyItem rna_enum_node_math_items[];
+extern EnumPropertyItem rna_enum_node_vec_math_items[];
+extern EnumPropertyItem rna_enum_node_filter_items[];
-extern EnumPropertyItem property_type_items[];
-extern EnumPropertyItem property_subtype_items[];
-extern EnumPropertyItem property_unit_items[];
+extern EnumPropertyItem rna_enum_ramp_blend_items[];
-extern EnumPropertyItem gameproperty_type_items[];
+extern EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[];
-extern EnumPropertyItem viewport_shade_items[];
+extern EnumPropertyItem rna_enum_clip_editor_mode_items[];
-extern EnumPropertyItem navigation_mode_items[];
+extern EnumPropertyItem rna_enum_icon_items[];
+extern EnumPropertyItem rna_enum_uilist_layout_type_items[];
-extern EnumPropertyItem file_sort_items[];
+extern EnumPropertyItem rna_enum_linestyle_color_modifier_type_items[];
+extern EnumPropertyItem rna_enum_linestyle_alpha_modifier_type_items[];
+extern EnumPropertyItem rna_enum_linestyle_thickness_modifier_type_items[];
+extern EnumPropertyItem rna_enum_linestyle_geometry_modifier_type_items[];
+extern EnumPropertyItem rna_enum_window_cursor_items[];
+
+extern EnumPropertyItem rna_enum_dt_method_vertex_items[];
+extern EnumPropertyItem rna_enum_dt_method_edge_items[];
+extern EnumPropertyItem rna_enum_dt_method_loop_items[];
+extern EnumPropertyItem rna_enum_dt_method_poly_items[];
+extern EnumPropertyItem rna_enum_dt_mix_mode_items[];
+extern EnumPropertyItem rna_enum_dt_layers_select_src_items[];
+extern EnumPropertyItem rna_enum_dt_layers_select_dst_items[];
+
+
+/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
int rna_node_tree_idname_to_enum(const char *idname);
struct bNodeTreeType *rna_node_tree_type_from_enum(int value);
@@ -171,37 +214,6 @@ int rna_node_socket_idname_to_enum(const char *idname);
struct bNodeSocketType *rna_node_socket_type_from_enum(int value);
EnumPropertyItem *rna_node_socket_type_itemf(void *data, int (*poll)(void *data, struct bNodeSocketType *), bool *r_free);
-extern EnumPropertyItem node_socket_in_out_items[];
-extern EnumPropertyItem node_icon_items[];
-
-extern EnumPropertyItem node_math_items[];
-extern EnumPropertyItem node_vec_math_items[];
-extern EnumPropertyItem node_filter_items[];
-
-extern EnumPropertyItem ramp_blend_items[];
-
-extern EnumPropertyItem prop_dynamicpaint_type_items[];
-
-extern EnumPropertyItem clip_editor_mode_items[];
-
-extern EnumPropertyItem icon_items[];
-extern EnumPropertyItem uilist_layout_type_items[];
-
-extern EnumPropertyItem linestyle_color_modifier_type_items[];
-extern EnumPropertyItem linestyle_alpha_modifier_type_items[];
-extern EnumPropertyItem linestyle_thickness_modifier_type_items[];
-extern EnumPropertyItem linestyle_geometry_modifier_type_items[];
-
-extern EnumPropertyItem window_cursor_items[];
-
-extern EnumPropertyItem DT_method_vertex_items[];
-extern EnumPropertyItem DT_method_edge_items[];
-extern EnumPropertyItem DT_method_loop_items[];
-extern EnumPropertyItem DT_method_poly_items[];
-extern EnumPropertyItem DT_mix_mode_items[];
-extern EnumPropertyItem DT_layers_select_src_items[];
-extern EnumPropertyItem DT_layers_select_dst_items[];
-
struct bContext;
struct PointerRNA;
struct PropertyRNA;
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 0c99769a390..04a2361b903 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -403,7 +403,7 @@ typedef enum StructFlag {
STRUCT_RUNTIME = (1 << 3),
STRUCT_GENERATED = (1 << 4),
STRUCT_FREE_POINTERS = (1 << 5),
- STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menu's and Panels don't need properties */
+ STRUCT_NO_IDPROPERTIES = (1 << 6), /* Menus and Panels don't need properties */
} StructFlag;
typedef int (*StructValidateFunc)(struct PointerRNA *ptr, void *data, int *have_function);
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
deleted file mode 100644
index 260784788db..00000000000
--- a/source/blender/makesrna/SConscript
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-objs = []
-
-o = SConscript('intern/SConscript')
-objs += o
-
-incs = [
- '.',
- './intern',
- '#/intern/guardedalloc',
- '#/intern/atomic',
- '#/intern/memutil',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/cycles/blender',
- '#/intern/smoke/extern',
- '../blenfont',
- '../blenkernel',
- '../blenlib',
- '../blentranslation',
- '../bmesh',
- '../depsgraph',
- '../editors/include',
- '../gpu',
- '../ikplugin',
- '../imbuf',
- '../makesdna',
- '../nodes',
- '../physics',
- '../render/extern/include',
- '../windowmanager',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_SMOKE']:
- defs.append('WITH_SMOKE')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
- incs += ' #/intern/rigidbody'
-
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
-
-if env['WITH_BF_DDS']:
- defs.append('WITH_DDS')
-
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-
-if env['WITH_BF_HDR']:
- defs.append('WITH_HDR')
-
-if env['WITH_BF_FRAMESERVER']:
- defs.append('WITH_FRAMESERVER')
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
- incs += ' ' + env['BF_FFMPEG_INC'] + ' #/intern/ffmpeg'
-
-if env['WITH_BF_QUICKTIME']:
- defs.append('WITH_QUICKTIME')
- incs += ' ../quicktime'
- # Quicktime needs audaspace defines
- if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['BF_UNIT_TEST']:
- defs.append('UNIT_TEST')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
- incs += ' ../python'
-
-if env['WITH_BF_COLLADA']:
- defs.append('WITH_COLLADA')
-
-if env['WITH_BF_OCEANSIM']:
- defs.append('WITH_OCEANSIM')
-
-if env['WITH_BF_CYCLES']:
- defs.append('WITH_CYCLES')
-
- if env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-if env['WITH_BF_SDL']:
- if env['WITH_BF_SDL_DYNLOAD']:
- defs.append('WITH_SDL_DYNLOAD')
- incs += ' #extern/sdlew/include'
- defs.append('WITH_SDL')
-
-if env['WITH_BF_OPENAL']:
- defs.append('WITH_OPENAL')
-
-if env['WITH_BF_JACK']:
- defs.append('WITH_JACK')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
- incs += ' ../freestyle'
-
-if env['WITH_BF_OPENSUBDIV']:
- incs += ' #/intern/opensubdiv'
- defs.append('WITH_OPENSUBDIV')
-
-if env['OURPLATFORM'] == 'linux':
- cflags='-pthread'
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-rnalib = env.BlenderLib ( 'bf_rna', objs, Split(incs), defines=defs, libtype=['core','player'], priority = [165,20] )
-
-Return ('rnalib')
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 987b594421f..31bf0c9389b 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -311,6 +311,14 @@ if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB)
+
+ if(WITH_OPENVDB_BLOSC)
+ add_definitions(-DWITH_OPENVDB_BLOSC)
+ endif()
+endif()
+
# Build makesrna executable
blender_include_dirs(
.
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
deleted file mode 100644
index e8842ae2943..00000000000
--- a/source/blender/makesrna/intern/SConscript
+++ /dev/null
@@ -1,244 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-import os
-
-def normpath(path):
- return os.path.abspath(os.path.normpath(path))
-
-Import ('env')
-cflags = [] #['-Wall']
-defines = []
-root_build_dir=normpath(env['BF_BUILDDIR'])
-
-source_files = env.Glob('*.c')
-source_files.remove('rna_access.c')
-
-generated_files = source_files[:]
-generated_files.remove('rna_define.c')
-generated_files.remove('makesrna.c')
-
-api_files = env.Glob('*_api.c')
-for api_file in api_files:
- generated_files.remove(api_file)
-
-generated_files = [filename[:-2] + '_gen.c' for filename in generated_files]
-
-makesrna_tool = env.Clone()
-rna = env.Clone()
-makesrna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesrna/\\"" ')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/cycles/blender',
- '#/intern/smoke/extern',
- '../../blenfont',
- '../../blenkernel',
- '../../blenlib',
- '../../blentranslation',
- '../../bmesh',
- '../../depsgraph',
- '../../editors/include',
- '../../gpu',
- '../../ikplugin',
- '../../imbuf',
- '../../makesdna',
- '../../makesrna',
- '../../physics',
- '../../render/extern/include',
- '../../windowmanager',
- ]
-incs = ' '.join(incs)
-
-if env['WITH_BF_SMOKE']:
- defs.append('WITH_SMOKE')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
- incs += ' #/intern/rigidbody'
-
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
-
-if env['WITH_BF_DDS']:
- defs.append('WITH_DDS')
-
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-
-if env['WITH_BF_HDR']:
- defs.append('WITH_HDR')
-
-if env['WITH_BF_FRAMESERVER']:
- defs.append('WITH_FRAMESERVER')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
- incs += ' ' + env['BF_FFMPEG_INC'] + ' #/intern/ffmpeg'
-
-if env['WITH_BF_QUICKTIME']:
- defs.append('WITH_QUICKTIME')
- incs += ' ../../quicktime'
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_FFTW3']:
- defs.append('WITH_FFTW3')
-
-if env['WITH_BF_SDL']:
- if env['WITH_BF_SDL_DYNLOAD']:
- defs.append('WITH_SDL_DYNLOAD')
- incs += ' #extern/sdlew/include'
- defs.append('WITH_SDL')
-
-if env['WITH_BF_OPENAL']:
- defs.append('WITH_OPENAL')
-
-if env['WITH_BF_JACK']:
- defs.append('WITH_JACK')
-
-if env['BF_UNIT_TEST']:
- defs.append('UNIT_TEST')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_COLLADA']:
- defs.append('WITH_COLLADA')
-
-if env['WITH_BF_CYCLES']:
- defs.append('WITH_CYCLES')
- if env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
- incs += ' ../../freestyle'
-
-if env['WITH_BF_OPENSUBDIV']:
- defs.append('WITH_OPENSUBDIV')
- incs += ' #intern/opensubdiv'
-
-if env['OURPLATFORM'] == 'linux':
- cflags='-pthread'
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if not env['BF_DEBUG']:
- defs.append('NDEBUG')
-
-makesrna_tool.Append(CPPDEFINES=defs)
-
-makesrna_tool.Append (CPPPATH = Split(incs))
-
-if env['OURPLATFORM'] == 'linuxcross':
- USE_WINE = True # when cross compiling on linux 64bit this is useful
-else:
- USE_WINE = False
-
-if not USE_WINE:
- if env['OURPLATFORM'] == 'linuxcross':
- makesdna_tool.Replace(CC='gcc')
- makesdna_tool.Replace(AR='ar')
- makesdna_tool.Replace(LINK='gcc')
-
-if sys.platform != 'cygwin':
- makesrna_tool.Append (CCFLAGS = cflags)
-makesrna_tool.Append (CPPDEFINES = defines)
-
-libdir = root_build_dir+'/lib'
-if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- libdir = '#' + libdir
-
-makesrna_tool.Append (LIBPATH = libdir)
-
-makesrna_tool.Append( CFLAGS = env['CFLAGS'])
-makesrna_tool.Append( CCFLAGS = env['CCFLAGS'])
-makesrna_tool.Append( LINKFLAGS = env['PLATFORM_LINKFLAGS'])
-
-if env['BF_PROFILE']:
- makesrna_tool.Append (LINKFLAGS = env['BF_PROFILE_FLAGS'])
-
-if env['BF_DEBUG']:
- makesrna_tool.Append(CFLAGS = env['BF_DEBUG_CFLAGS'])
- makesrna_tool.Append(CCFLAGS = env['BF_DEBUG_CCFLAGS'])
- if env['OURPLATFORM'] in ('win32-vc','win64-vc'):
- makesrna_tool.Append(LINKFLAGS = ['/DEBUG','/PDB:makesrna.pdb'])
-
-targetpath = root_build_dir+'/makesrna'
-if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
- targetpath = '#' + targetpath
-
-if env['OURPLATFORM'] == 'linux' and root_build_dir[0]==os.sep:
- makesrna = makesrna_tool.Program (target = targetpath, source = source_files, LIBS=['bf_intern_guardedalloc', 'bf_dna', 'bf_blenlib'])
-else:
- makesrna = makesrna_tool.Program (target = targetpath, source = source_files, LIBS=['bf_intern_guardedalloc', 'bf_dna', 'bf_blenlib'])
-
-rna_dict = rna.Dictionary()
-rna.Depends (generated_files, makesrna)
-
-build_dir = Dir(".").abspath + os.sep
-
-if env['OURPLATFORM'] != 'linuxcross':
- if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
- rna.Command (generated_files, '', "\"" + root_build_dir+os.sep+"makesrna.exe\" \"" + build_dir )
- else:
- rna.Command (generated_files, '', "\"" + root_build_dir+os.sep+"makesrna\" \"" + build_dir + '"' )
-else:
- rna.Command (generated_files, '', ('', 'wine ')[USE_WINE] + root_build_dir+os.sep+"makesrna.exe " + build_dir)
-
-
-obj = ['intern/rna_access.c']
-for generated_file in generated_files:
- obj += ['intern/' + generated_file]
-
-Return ('obj')
-
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 0f00dd7a586..535847cfc78 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -1079,11 +1079,18 @@ static char *rna_def_property_length_func(FILE *f, StructRNA *srna, PropertyRNA
fprintf(f, " return %s(ptr);\n", manualfunc);
}
else {
- rna_print_data_get(f, dp);
+ if (dp->dnaarraylength <= 1 || dp->dnalengthname)
+ rna_print_data_get(f, dp);
+
+ if (dp->dnaarraylength > 1)
+ fprintf(f, " return ");
+ else
+ fprintf(f, " return (data->%s == NULL) ? 0 : ", dp->dnaname);
+
if (dp->dnalengthname)
- fprintf(f, " return (data->%s == NULL) ? 0 : data->%s;\n", dp->dnaname, dp->dnalengthname);
+ fprintf(f, "data->%s;\n", dp->dnalengthname);
else
- fprintf(f, " return (data->%s == NULL) ? 0 : %d;\n", dp->dnaname, dp->dnalengthfixed);
+ fprintf(f, "%d;\n", dp->dnalengthfixed);
}
fprintf(f, "}\n\n");
}
@@ -1788,7 +1795,7 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
}
case PROP_STRING:
{
- fprintf(f, "\tinline std::string %s(void);", rna_safe_id(prop->identifier));
+ fprintf(f, "\tinline std::string %s(void);\n", rna_safe_id(prop->identifier));
fprintf(f, "\tinline void %s(const std::string& value);", rna_safe_id(prop->identifier));
break;
}
@@ -1893,9 +1900,13 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn
if (!(flag & PROP_DYNAMIC) && dp->prop->arraydimension)
fprintf(f, "%s %s[%u]", rna_parameter_type_cpp_name(dp->prop),
rna_safe_id(dp->prop->identifier), dp->prop->totarraylength);
- else
- fprintf(f, "%s %s%s", rna_parameter_type_cpp_name(dp->prop),
- ptrstr, rna_safe_id(dp->prop->identifier));
+ else {
+ fprintf(f, "%s%s%s%s",
+ rna_parameter_type_cpp_name(dp->prop),
+ (dp->prop->type == PROP_POINTER && ptrstr[0] == '\0') ? "& " : " ",
+ ptrstr,
+ rna_safe_id(dp->prop->identifier));
+ }
}
fprintf(f, ")");
@@ -3681,6 +3692,7 @@ static const char *cpp_classes = ""
"return *this; }\n"
"\n"
" operator T*() { return data; }\n"
+" operator const T*() const { return data; }\n"
"};\n"
"\n"
"template<typename T>\n"
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 88065d29a50..63ea836e3de 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -47,7 +47,7 @@
/* enum of ID-block types
* NOTE: need to keep this in line with the other defines for these
*/
-EnumPropertyItem id_type_items[] = {
+EnumPropertyItem rna_enum_id_type_items[] = {
{ID_AC, "ACTION", ICON_ACTION, "Action", ""},
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
@@ -90,9 +90,11 @@ EnumPropertyItem id_type_items[] = {
#include "BKE_font.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_animsys.h"
#include "BKE_material.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h" /* XXX, remove me */
#include "WM_api.h"
@@ -113,7 +115,7 @@ void rna_ID_name_set(PointerRNA *ptr, const char *value)
{
ID *id = (ID *)ptr->data;
BLI_strncpy_utf8(id->name + 2, value, sizeof(id->name) - 2);
- test_idbutton(id->name);
+ BLI_libblock_ensure_unique_name(G.main, id->name);
}
static int rna_ID_name_editable(PointerRNA *ptr)
@@ -126,7 +128,7 @@ static int rna_ID_name_editable(PointerRNA *ptr)
return false;
}
- return true;
+ return PROP_EDITABLE;
}
short RNA_type_to_ID_code(StructRNA *type)
@@ -223,13 +225,11 @@ void rna_ID_fake_user_set(PointerRNA *ptr, int value)
{
ID *id = (ID *)ptr->data;
- if (value && !(id->flag & LIB_FAKEUSER)) {
- id->flag |= LIB_FAKEUSER;
- id_us_plus(id);
+ if (value) {
+ id_fake_user_set(id);
}
- else if (!value && (id->flag & LIB_FAKEUSER)) {
- id->flag &= ~LIB_FAKEUSER;
- id_us_min(id);
+ else {
+ id_fake_user_clear(id);
}
}
@@ -329,8 +329,8 @@ static void rna_ID_update_tag(ID *id, ReportList *reports, int flag)
static void rna_ID_user_clear(ID *id)
{
+ id_fake_user_clear(id);
id->us = 0; /* don't save */
- id->flag &= ~LIB_FAKEUSER;
}
static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain)
@@ -911,14 +911,14 @@ static void rna_def_ID(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ID", NULL);
RNA_def_struct_ui_text(srna, "ID",
- "Base type for datablocks, defining a unique name, linking from other libraries "
+ "Base type for data-blocks, defining a unique name, linking from other libraries "
"and garbage collection");
RNA_def_struct_flag(srna, STRUCT_ID | STRUCT_ID_REFCOUNT);
RNA_def_struct_refine_func(srna, "rna_ID_refine");
RNA_def_struct_idprops_func(srna, "rna_ID_idprops");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "Unique datablock ID name");
+ RNA_def_property_ui_text(prop, "Name", "Unique data-block ID name");
RNA_def_property_string_funcs(prop, "rna_ID_name_get", "rna_ID_name_length", "rna_ID_name_set");
RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
RNA_def_property_editable_func(prop, "rna_ID_name_editable");
@@ -928,55 +928,63 @@ static void rna_def_ID(BlenderRNA *brna)
prop = RNA_def_property(srna, "users", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "us");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Users", "Number of times this datablock is referenced");
+ RNA_def_property_ui_text(prop, "Users", "Number of times this data-block is referenced");
prop = RNA_def_property(srna, "use_fake_user", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_FAKEUSER);
- RNA_def_property_ui_text(prop, "Fake User", "Save this datablock even if it has no users");
+ RNA_def_property_ui_text(prop, "Fake User", "Save this data-block even if it has no users");
RNA_def_property_boolean_funcs(prop, NULL, "rna_ID_fake_user_set");
prop = RNA_def_property(srna, "tag", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_DOIT);
+ RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_DOIT);
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_ui_text(prop, "Tag",
"Tools can use this to tag data for their own purposes "
"(initial state is undefined)");
prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_ID_RECALC);
+ RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Updated", "Datablock is tagged for recalculation");
prop = RNA_def_property(srna, "is_updated_data", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_ID_RECALC_DATA);
+ RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_ID_RECALC_DATA);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Updated Data", "Datablock data is tagged for recalculation");
prop = RNA_def_property(srna, "is_library_indirect", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", LIB_INDIRECT);
+ RNA_def_property_boolean_sdna(prop, NULL, "tag", LIB_TAG_INDIRECT);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Is Indirect", "Is this ID block linked indirectly");
prop = RNA_def_property(srna, "library", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "lib");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Library", "Library file the datablock is linked from");
+ RNA_def_property_ui_text(prop, "Library", "Library file the data-block is linked from");
prop = RNA_def_pointer(srna, "preview", "ImagePreview", "Preview",
- "Preview image and icon of this datablock (None if not supported for this type of data)");
+ "Preview image and icon of this data-block (None if not supported for this type of data)");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop, "rna_IDPreview_get", NULL, NULL, NULL);
/* functions */
func = RNA_def_function(srna, "copy", "rna_ID_copy");
- RNA_def_function_ui_description(func, "Create a copy of this datablock (not supported for all datablocks)");
+ RNA_def_function_ui_description(func, "Create a copy of this data-block (not supported for all data-blocks)");
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "user_clear", "rna_ID_user_clear");
- RNA_def_function_ui_description(func, "Clear the user count of a datablock so its not saved, "
+ RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, "
"on reload the data will be removed");
+ func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID");
+ RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one");
+ parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages");
+ RNA_def_property_flag(parm, PROP_NEVER_NULL);
+ parm = RNA_def_int(func, "count", 0, 0, INT_MAX,
+ "", "Number of usages/references of given id by current datablock", 0, INT_MAX);
+ RNA_def_function_return(func, parm);
+
func = RNA_def_function(srna, "animation_data_create", "rna_ID_animation_data_create");
RNA_def_function_flag(func, FUNC_USE_MAIN);
RNA_def_function_ui_description(func, "Create animation data to this ID, note that not all ID types support this");
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index b7478fd3311..97c71715349 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1215,14 +1215,15 @@ EnumPropertyItem DummyRNA_DEFAULT_items[] = {
{0, NULL, 0, NULL, NULL}
};
-void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, EnumPropertyItem **r_item,
- int *r_totitem, bool *r_free)
+void RNA_property_enum_items_ex(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop, const bool use_static,
+ EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);
*r_free = false;
- if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
+ if (!use_static && eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
EnumPropertyItem *item;
if (prop->flag & PROP_ENUM_NO_CONTEXT)
@@ -1250,6 +1251,12 @@ void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, En
}
}
+void RNA_property_enum_items(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop, EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
+{
+ RNA_property_enum_items_ex(C, ptr, prop, false, r_item, r_totitem, r_free);
+}
+
#ifdef WITH_INTERNATIONAL
static void property_enum_translate(PropertyRNA *prop, EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
{
@@ -1514,6 +1521,51 @@ bool RNA_property_enum_name_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA
return result;
}
+bool RNA_property_enum_item_from_value(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value,
+ EnumPropertyItem *r_item)
+{
+ EnumPropertyItem *item = NULL;
+ bool free;
+
+ RNA_property_enum_items(C, ptr, prop, &item, NULL, &free);
+ if (item) {
+ const int i = RNA_enum_from_value(item, value);
+ bool result;
+
+ if (i != -1) {
+ *r_item = item[i];
+ result = true;
+ }
+ else {
+ result = false;
+ }
+
+ if (free)
+ MEM_freeN(item);
+
+ return result;
+ }
+ return false;
+}
+
+bool RNA_property_enum_item_from_value_gettexted(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value,
+ EnumPropertyItem *r_item)
+{
+ bool result;
+
+ result = RNA_property_enum_item_from_value(C, ptr, prop, value, r_item);
+
+ if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) {
+ if (BLT_translate_iface()) {
+ r_item->name = BLT_pgettext(prop->translation_context, r_item->name);
+ }
+ }
+
+ return result;
+}
+
int RNA_property_enum_bitflag_identifiers(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value,
const char **identifier)
{
@@ -1570,7 +1622,9 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
prop = rna_ensure_property(prop);
flag = prop->editable ? prop->editable(ptr) : prop->flag;
- return (flag & PROP_EDITABLE) && (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION));
+ return ((flag & PROP_EDITABLE) &&
+ (flag & PROP_REGISTER) == 0 &&
+ (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION)));
}
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop)
@@ -2089,6 +2143,7 @@ void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
/* BLI_assert(RNA_property_int_clamp(ptr, prop, &value) == 0); */
if ((idprop = rna_idproperty_check(&prop, ptr))) {
+ RNA_property_int_clamp(ptr, prop, &value);
IDP_Int(idprop) = value;
rna_idproperty_touch(idprop);
}
@@ -2347,6 +2402,7 @@ void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
/* BLI_assert(RNA_property_float_clamp(ptr, prop, &value) == 0); */
if ((idprop = rna_idproperty_check(&prop, ptr))) {
+ RNA_property_float_clamp(ptr, prop, &value);
if (idprop->type == IDP_FLOAT)
IDP_Float(idprop) = value;
else
@@ -3394,7 +3450,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
void *inarray, RawPropertyType intype, int inlen, int set)
{
StructRNA *ptype;
- PointerRNA itemptr;
+ PointerRNA itemptr_base;
PropertyRNA *itemprop, *iprop;
PropertyType itemtype = 0;
RawArray in;
@@ -3409,8 +3465,8 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
ptype = RNA_property_pointer_type(ptr, prop);
/* try to get item property pointer */
- RNA_pointer_create(NULL, ptype, NULL, &itemptr);
- itemprop = RNA_struct_find_property(&itemptr, propname);
+ RNA_pointer_create(NULL, ptype, NULL, &itemptr_base);
+ itemprop = RNA_struct_find_property(&itemptr_base, propname);
if (itemprop) {
/* we have item property pointer */
@@ -3425,7 +3481,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
}
/* check item array */
- itemlen = RNA_property_array_length(&itemptr, itemprop);
+ itemlen = RNA_property_array_length(&itemptr_base, itemprop);
/* dynamic array? need to get length per item */
if (itemprop->getlength) {
@@ -4220,7 +4276,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
*r_index = index;
if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index)) {
- PropertyElemRNA *prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
+ prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
prop_elem->ptr = curptr;
prop_elem->prop = prop;
prop_elem->index = index;
@@ -4503,12 +4559,12 @@ static char *rna_idp_path(PointerRNA *ptr, IDProperty *haystack, IDProperty *nee
break;
}
else {
- int i;
+ int j;
link.name = iter->name;
- for (i = 0; i < iter->len; i++, array++) {
+ for (j = 0; j < iter->len; j++, array++) {
PointerRNA child_ptr;
- if (RNA_property_collection_lookup_int(ptr, prop, i, &child_ptr)) {
- link.index = i;
+ if (RNA_property_collection_lookup_int(ptr, prop, j, &child_ptr)) {
+ link.index = j;
if ((path = rna_idp_path(&child_ptr, array, needle, &link))) {
break;
}
@@ -4717,11 +4773,12 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr)
* Get the ID.struct.property as a python representation, eg:
* bpy.data.foo["bar"].some_struct.some_prop[10]
*/
-char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
+char *RNA_path_full_property_py_ex(PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback)
{
char *id_path;
const char *data_delim;
- char *data_path;
+ const char *data_path;
+ bool data_path_free;
char *ret;
@@ -4733,8 +4790,23 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
id_path = RNA_path_full_ID_py(ptr->id.data);
data_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (data_path) {
+ data_delim = (data_path[0] == '[') ? "" : ".";
+ data_path_free = true;
+ }
+ else {
+ if (use_fallback) {
+ /* fuzzy fallback. be explicit in our ignoranc. */
+ data_path = RNA_property_identifier(prop);
+ data_delim = " ... ";
+ }
+ else {
+ data_delim = ".";
+
+ }
+ data_path_free = false;
+ }
- data_delim = (data_path && data_path[0] == '[') ? "" : ".";
if ((index == -1) || (RNA_property_array_check(prop) == false)) {
ret = BLI_sprintfN("%s%s%s",
@@ -4745,13 +4817,18 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
id_path, data_delim, data_path, index);
}
MEM_freeN(id_path);
- if (data_path) {
- MEM_freeN(data_path);
+ if (data_path_free) {
+ MEM_freeN((void *)data_path);
}
return ret;
}
+char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ return RNA_path_full_property_py_ex(ptr, prop, index, false);
+}
+
/**
* Get the struct.property as a python representation, eg:
* some_struct.some_prop[10]
@@ -4969,13 +5046,13 @@ void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
printf("%s: %s.%s not found.\n", __func__, ptr->type->identifier, name);
}
-void RNA_enum_set_identifier(PointerRNA *ptr, const char *name, const char *id)
+void RNA_enum_set_identifier(bContext *C, PointerRNA *ptr, const char *name, const char *id)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, name);
if (prop) {
int value;
- if (RNA_property_enum_value(NULL, ptr, prop, id, &value))
+ if (RNA_property_enum_value(C, ptr, prop, id, &value))
RNA_property_enum_set(ptr, prop, value);
else
printf("%s: %s.%s has no enum id '%s'.\n", __func__, ptr->type->identifier, name, id);
@@ -5457,7 +5534,6 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
{
int type = RNA_property_type(prop);
int len = RNA_property_array_length(ptr, prop);
- int i;
DynStr *dynstr = BLI_dynstr_new();
char *cstring;
@@ -5479,7 +5555,7 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
RNA_property_boolean_get_array(ptr, prop, buf);
BLI_dynstr_append(dynstr, "(");
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
BLI_dynstr_appendf(dynstr, i ? ", %s" : "%s", bool_as_py_string(buf[i]));
}
if (len == 1)
@@ -5505,7 +5581,7 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
RNA_property_int_get_array(ptr, prop, buf);
BLI_dynstr_append(dynstr, "(");
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
BLI_dynstr_appendf(dynstr, i ? ", %d" : "%d", buf[i]);
}
if (len == 1)
@@ -5531,7 +5607,7 @@ char *RNA_property_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop, in
RNA_property_float_get_array(ptr, prop, buf);
BLI_dynstr_append(dynstr, "(");
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
BLI_dynstr_appendf(dynstr, i ? ", %g" : "%g", buf[i]);
}
if (len == 1)
@@ -6077,7 +6153,7 @@ static int rna_function_format_array_length(const char *format, int ofs, int fle
}
static int rna_function_parameter_parse(PointerRNA *ptr, PropertyRNA *prop, PropertyType type,
- char ftype, int len, void *dest, void *src, StructRNA *srna,
+ char ftype, int len, void *dest, const void *src, StructRNA *srna,
const char *tid, const char *fid, const char *pid)
{
/* ptr is always a function pointer, prop always a parameter */
@@ -6372,7 +6448,7 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt
}
case PROP_STRING:
{
- const char **arg = va_arg(args, const char **);
+ char **arg = va_arg(args, char **);
err = rna_function_parameter_parse(&funcptr, parm, type, ftype, len, arg, retdata,
NULL, tid, fid, pid);
break;
@@ -6530,7 +6606,7 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
* since prop in this case is just a fake wrapper around actual IDProp data, and not a 'real' PropertyRNA. */
prop = (PropertyRNA *)rna_idproperty_find(ptr, ((IDProperty *)fromprop)->name);
- /* its possible the custom-prop doesn't exist on this datablock */
+ /* its possible the custom-prop doesn't exist on this data-block */
if (prop == NULL) {
return false;
}
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index b8a490ea904..7c21ce95a1d 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -287,7 +287,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Source",
"ID-Block representing source data, usually ID_SCE (i.e. Scene)");
- /* Show datablock filters */
+ /* Show data-block filters */
prop = RNA_def_property(srna, "show_datablock_filters", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ADS_FLAG_SHOW_DBFILTERS);
RNA_def_property_ui_text(prop, "Show Datablock Filters",
@@ -357,6 +357,14 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ /* Multi-word fuzzy search option for name/text filters */
+ prop = RNA_def_property(srna, "use_multi_word_filter", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ADS_FLAG_FUZZY_NAMES);
+ RNA_def_property_ui_text(prop, "Multi-Word Fuzzy Filter",
+ "Perform fuzzy/multi-word matching (WARNING: May be slow)");
+ RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
/* NLA Specific Settings */
prop = RNA_def_property(srna, "show_missing_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NLA_NOACT);
@@ -395,7 +403,8 @@ static void rna_def_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_modifiers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOMODIFIERS);
- RNA_def_property_ui_text(prop, "Display Modifier Data", "Include visualization of animation data related to datablocks linked to modifiers");
+ RNA_def_property_ui_text(prop, "Display Modifier Data",
+ "Include visualization of animation data related to data-blocks linked to modifiers");
RNA_def_property_ui_icon(prop, ICON_MODIFIER, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -494,6 +503,14 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Display Grease Pencil", "Include visualization of Grease Pencil related animation data and frames");
RNA_def_property_ui_icon(prop, ICON_GREASEPENCIL, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ /* GPencil Mode Settings */
+ prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY);
+ RNA_def_property_ui_text(prop, "Active Scene Only",
+ "Only show Grease Pencil datablocks used as part of the active scene");
+ RNA_def_property_ui_icon(prop, ICON_SCENE_DATA, 0);
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
}
static void rna_def_action_group(BlenderRNA *brna)
@@ -703,7 +720,7 @@ static void rna_def_action(BlenderRNA *brna)
* but is still available/editable in 'emergencies' */
prop = RNA_def_property(srna, "id_root", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "idroot");
- RNA_def_property_enum_items(prop, id_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_id_type_items);
RNA_def_property_ui_text(prop, "ID Root Type",
"Type of ID block that action can be used on - "
"DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING");
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index 5dba21dda40..b425a454d33 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -1706,6 +1706,7 @@ static void rna_def_game_actuator(BlenderRNA *brna)
{ACT_GAME_QUIT, "QUIT", 0, "Quit Game", ""},
{ACT_GAME_SAVECFG, "SAVECFG", 0, "Save bge.logic.globalDict", ""},
{ACT_GAME_LOADCFG, "LOADCFG", 0, "Load bge.logic.globalDict", ""},
+ {ACT_GAME_SCREENSHOT, "SCREENSHOT", 0, "Screenshot", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1722,8 +1723,8 @@ static void rna_def_game_actuator(BlenderRNA *brna)
/* ACT_GAME_LOAD */
prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH);
RNA_def_property_ui_text(prop, "File",
- "Load this blend file, use the \"//\" prefix for a path relative to the current "
- "blend file");
+ "The file to use, depending on the mode (e.g. the blend file to load or a destination "
+ "for saving a screenshot) - use the \"//\" prefix for a relative path");
RNA_def_property_update(prop, NC_LOGIC, NULL);
/*XXX to do: an operator that calls file_browse with relative_path on and blender filtering active */
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index ac30c615438..c3d1070b8c2 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -45,7 +45,7 @@
#include "ED_keyframing.h"
/* exported for use in API */
-EnumPropertyItem keyingset_path_grouping_items[] = {
+EnumPropertyItem rna_enum_keyingset_path_grouping_items[] = {
{KSP_GROUP_NAMED, "NAMED", 0, "Named Group", ""},
{KSP_GROUP_NONE, "NONE", 0, "None", ""},
{KSP_GROUP_KSNAME, "KEYINGSET", 0, "Keying Set Name", ""},
@@ -55,7 +55,7 @@ EnumPropertyItem keyingset_path_grouping_items[] = {
/* It would be cool to get rid of this 'INSERTKEY_' prefix in 'py strings' values, but it would break existing
* exported keyingset... :/
*/
-EnumPropertyItem keying_flag_items[] = {
+EnumPropertyItem rna_enum_keying_flag_items[] = {
{INSERTKEY_NEEDED, "INSERTKEY_NEEDED", 0, "Only Needed",
"Only insert keyframes where they're needed in the relevant F-Curves"},
{INSERTKEY_MATRIX, "INSERTKEY_VISUAL", 0, "Visual Keying",
@@ -97,7 +97,7 @@ static int rna_AnimData_action_editable(PointerRNA *ptr)
if ((adt->flag & ADT_NLA_EDIT_ON) || (adt->actstrip) || (adt->tmpact))
return 0;
else
- return 1;
+ return PROP_EDITABLE;
}
static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
@@ -381,7 +381,7 @@ static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr)
KeyingSet *ks = (KeyingSet *)ptr->data;
/* only editable if there are some paths to change to */
- return (BLI_listbase_is_empty(&ks->paths) == false);
+ return (BLI_listbase_is_empty(&ks->paths) == false) ? PROP_EDITABLE : 0;
}
static PointerRNA rna_KeyingSet_active_ksPath_get(PointerRNA *ptr)
@@ -552,6 +552,17 @@ static FCurve *rna_Driver_from_existing(AnimData *adt, bContext *C, FCurve *src_
}
}
+static FCurve *rna_Driver_find(AnimData *adt, ReportList *reports, const char *data_path, int index)
+{
+ if (data_path[0] == '\0') {
+ BKE_report(reports, RPT_ERROR, "F-Curve data path empty, invalid argument");
+ return NULL;
+ }
+
+ /* Returns NULL if not found. */
+ return list_find_fcurve(&adt->drivers, data_path, index);
+}
+
#else
/* helper function for Keying Set -> keying settings */
@@ -652,7 +663,7 @@ static void rna_def_keyingset_info(BlenderRNA *brna)
*/
prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "keyingflag");
- RNA_def_property_enum_items(prop, keying_flag_items);
+ RNA_def_property_enum_items(prop, rna_enum_keying_flag_items);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Options", "Keying Set options to use when inserting keyframes");
@@ -710,7 +721,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
prop = RNA_def_property(srna, "id_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "idtype");
- RNA_def_property_enum_items(prop, id_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_id_type_items);
RNA_def_property_enum_default(prop, ID_OB);
RNA_def_property_enum_funcs(prop, NULL, "rna_ksPath_id_type_set", NULL);
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
@@ -724,7 +735,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
/* Grouping */
prop = RNA_def_property(srna, "group_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "groupmode");
- RNA_def_property_enum_items(prop, keyingset_path_grouping_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyingset_path_grouping_items);
RNA_def_property_ui_text(prop, "Grouping Method", "Method used to define which Group-name to use");
RNA_def_property_update(prop, NC_SCENE | ND_KEYINGSET | NA_EDITED, NULL); /* XXX: maybe a bit too noisy */
@@ -789,7 +800,7 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop)
"The index of the destination property (i.e. axis of Location/Rotation/etc.), "
"or -1 for the entire array", 0, INT_MAX);
/* grouping */
- RNA_def_enum(func, "group_method", keyingset_path_grouping_items, KSP_GROUP_KSNAME,
+ RNA_def_enum(func, "group_method", rna_enum_keyingset_path_grouping_items, KSP_GROUP_KSNAME,
"Grouping Method", "Method used to define which Group-name to use");
RNA_def_string(func, "group_name", NULL, 64, "Group Name",
"Name of Action Group to assign destination to (only if grouping mode is to use this name)");
@@ -936,6 +947,7 @@ static void rna_api_animdata_drivers(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_sdna(srna, "AnimData");
RNA_def_struct_ui_text(srna, "Drivers", "Collection of Driver F-Curves");
+ /* AnimData.drivers.from_existing(...) */
func = RNA_def_function(srna, "from_existing", "rna_Driver_from_existing");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
RNA_def_function_ui_description(func, "Add a new driver given an existing one");
@@ -943,6 +955,18 @@ static void rna_api_animdata_drivers(BlenderRNA *brna, PropertyRNA *cprop)
/* return type */
parm = RNA_def_pointer(func, "driver", "FCurve", "", "New Driver F-Curve");
RNA_def_function_return(func, parm);
+
+ /* AnimData.drivers.find(...) */
+ func = RNA_def_function(srna, "find", "rna_Driver_find");
+ RNA_def_function_ui_description(func, "Find a driver F-Curve. Note that this function performs a linear scan "
+ "of all driver F-Curves.");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX);
+ /* return type */
+ parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist");
+ RNA_def_function_return(func, parm);
}
void rna_def_animdata_common(StructRNA *srna)
@@ -952,7 +976,7 @@ void rna_def_animdata_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_data", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "adt");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this datablock");
+ RNA_def_property_ui_text(prop, "Animation Data", "Animation data for this data-block");
}
static void rna_def_animdata(BlenderRNA *brna)
@@ -961,7 +985,7 @@ static void rna_def_animdata(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AnimData", NULL);
- RNA_def_struct_ui_text(srna, "Animation Data", "Animation data for datablock");
+ RNA_def_struct_ui_text(srna, "Animation Data", "Animation data for data-block");
RNA_def_struct_ui_icon(srna, ICON_ANIM_DATA);
/* NLA */
@@ -978,20 +1002,20 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
RNA_def_property_pointer_funcs(prop, NULL, "rna_AnimData_action_set", NULL, "rna_Action_id_poll");
RNA_def_property_editable_func(prop, "rna_AnimData_action_editable");
- RNA_def_property_ui_text(prop, "Action", "Active Action for this datablock");
+ RNA_def_property_ui_text(prop, "Action", "Active Action for this data-block");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA_ACTCHANGE, "rna_AnimData_update");
/* Active Action Settings */
prop = RNA_def_property(srna, "action_extrapolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "act_extendmode");
- RNA_def_property_enum_items(prop, nla_mode_extend_items);
+ RNA_def_property_enum_items(prop, rna_enum_nla_mode_extend_items);
RNA_def_property_ui_text(prop, "Action Extrapolation",
"Action to take for gaps past the Active Action's range (when evaluating with NLA)");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL);
prop = RNA_def_property(srna, "action_blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "act_blendmode");
- RNA_def_property_enum_items(prop, nla_mode_blend_items);
+ RNA_def_property_enum_items(prop, rna_enum_nla_mode_blend_items);
RNA_def_property_ui_text(prop, "Action Blending",
"Method used for combining Active Action's result with result of NLA stack");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
@@ -1008,7 +1032,7 @@ static void rna_def_animdata(BlenderRNA *brna)
prop = RNA_def_property(srna, "drivers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "drivers", NULL);
RNA_def_property_struct_type(prop, "FCurve");
- RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this datablock");
+ RNA_def_property_ui_text(prop, "Drivers", "The Drivers/Expressions for this data-block");
rna_api_animdata_drivers(brna, prop);
diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c
index 719eb9f8a20..8e42e68ed1e 100644
--- a/source/blender/makesrna/intern/rna_animviz.c
+++ b/source/blender/makesrna/intern/rna_animviz.c
@@ -43,7 +43,7 @@
/* Which part of bone(s) get baked */
// TODO: icons?
-EnumPropertyItem motionpath_bake_location_items[] = {
+EnumPropertyItem rna_enum_motionpath_bake_location_items[] = {
{MOTIONPATH_BAKE_HEADS, "HEADS", 0, "Heads", "Calculate bone paths from heads"},
{0, "TAILS", 0, "Tails", "Calculate bone paths from tails"},
//{MOTIONPATH_BAKE_CENTERS, "CENTROID", 0, "Centers", "Calculate bone paths from center of mass"},
@@ -269,7 +269,7 @@ static void rna_def_animviz_paths(BlenderRNA *brna)
prop = RNA_def_property(srna, "bake_location", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "path_bakeflag");
- RNA_def_property_enum_items(prop, motionpath_bake_location_items);
+ RNA_def_property_enum_items(prop, rna_enum_motionpath_bake_location_items);
RNA_def_property_ui_text(prop, "Bake Location", "When calculating Bone Paths, use Head or Tips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* XXX since this is only for 3d-view drawing */
@@ -348,7 +348,7 @@ void rna_def_animviz_common(StructRNA *srna)
prop = RNA_def_property(srna, "animation_visualization", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "avs");
- RNA_def_property_ui_text(prop, "Animation Visualization", "Animation data for this datablock");
+ RNA_def_property_ui_text(prop, "Animation Visualization", "Animation data for this data-block");
}
static void rna_def_animviz(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 3e41ea4134c..a8ef4664fd7 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -633,7 +633,7 @@ static void rna_def_bone(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Bone", NULL);
- RNA_def_struct_ui_text(srna, "Bone", "Bone in an Armature datablock");
+ RNA_def_struct_ui_text(srna, "Bone", "Bone in an Armature data-block");
RNA_def_struct_ui_icon(srna, ICON_BONE_DATA);
RNA_def_struct_path_func(srna, "rna_Bone_path");
RNA_def_struct_idprops_func(srna, "rna_Bone_idprops");
@@ -732,7 +732,7 @@ static void rna_def_edit_bone(BlenderRNA *brna)
srna = RNA_def_struct(brna, "EditBone", NULL);
RNA_def_struct_sdna(srna, "EditBone");
RNA_def_struct_idprops_func(srna, "rna_EditBone_idprops");
- RNA_def_struct_ui_text(srna, "Edit Bone", "Editmode bone in an Armature datablock");
+ RNA_def_struct_ui_text(srna, "Edit Bone", "Editmode bone in an Armature data-block");
RNA_def_struct_ui_icon(srna, ICON_BONE_DATA);
RNA_define_verify_sdna(0); /* not in sdna */
@@ -921,7 +921,7 @@ static void rna_def_armature(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Armature", "ID");
RNA_def_struct_ui_text(srna, "Armature",
- "Armature datablock containing a hierarchy of bones, usually used for rigging characters");
+ "Armature data-block containing a hierarchy of bones, usually used for rigging characters");
RNA_def_struct_ui_icon(srna, ICON_ARMATURE_DATA);
RNA_def_struct_sdna(srna, "bArmature");
diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c
index 33048a7196b..72f67b86c23 100644
--- a/source/blender/makesrna/intern/rna_boid.c
+++ b/source/blender/makesrna/intern/rna_boid.c
@@ -48,7 +48,7 @@
#include "WM_api.h"
#include "WM_types.h"
-EnumPropertyItem boidrule_type_items[] = {
+EnumPropertyItem rna_enum_boidrule_type_items[] = {
{eBoidRuleType_Goal, "GOAL", 0, "Goal", "Go to assigned object or loudest assigned signal source"},
{eBoidRuleType_Avoid, "AVOID", 0, "Avoid", "Get away from assigned object or loudest assigned signal source"},
{eBoidRuleType_AvoidCollision, "AVOID_COLLISION", 0, "Avoid Collision",
@@ -432,7 +432,7 @@ static void rna_def_boidrule(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, boidrule_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_boidrule_type_items);
RNA_def_property_ui_text(prop, "Type", "");
/* flags */
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 93cbd5fa246..e13919dd1a1 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -62,7 +62,7 @@ static EnumPropertyItem sculpt_stroke_method_items[] = {
};
-EnumPropertyItem brush_sculpt_tool_items[] = {
+EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""},
{SCULPT_TOOL_CLAY, "CLAY", ICON_BRUSH_CLAY, "Clay", ""},
{SCULPT_TOOL_CLAY_STRIPS, "CLAY_STRIPS", ICON_BRUSH_CLAY_STRIPS, "Clay Strips", ""},
@@ -86,7 +86,7 @@ EnumPropertyItem brush_sculpt_tool_items[] = {
};
-EnumPropertyItem brush_vertex_tool_items[] = {
+EnumPropertyItem rna_enum_brush_vertex_tool_items[] = {
{PAINT_BLEND_MIX, "MIX", ICON_BRUSH_MIX, "Mix", "Use mix blending mode while painting"},
{PAINT_BLEND_ADD, "ADD", ICON_BRUSH_ADD, "Add", "Use add blending mode while painting"},
{PAINT_BLEND_SUB, "SUB", ICON_BRUSH_SUBTRACT, "Subtract", "Use subtract blending mode while painting"},
@@ -97,7 +97,7 @@ EnumPropertyItem brush_vertex_tool_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem brush_image_tool_items[] = {
+EnumPropertyItem rna_enum_brush_image_tool_items[] = {
{PAINT_TOOL_DRAW, "DRAW", ICON_BRUSH_TEXDRAW, "Draw", ""},
{PAINT_TOOL_SOFTEN, "SOFTEN", ICON_BRUSH_SOFTEN, "Soften", ""},
{PAINT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SMEAR, "Smear", ""},
@@ -154,6 +154,12 @@ static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr)
return SCULPT_TOOL_HAS_NORMAL_WEIGHT(br->sculpt_tool);
}
+static int rna_SculptToolCapabilities_has_rake_factor_get(PointerRNA *ptr)
+{
+ Brush *br = (Brush *)ptr->data;
+ return SCULPT_TOOL_HAS_RAKE(br->sculpt_tool);
+}
+
static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
@@ -172,7 +178,7 @@ static int rna_SculptToolCapabilities_has_persistence_get(PointerRNA *ptr)
static int rna_SculptToolCapabilities_has_pinch_factor_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM(br->sculpt_tool, SCULPT_TOOL_BLOB, SCULPT_TOOL_CREASE);
+ return ELEM(br->sculpt_tool, SCULPT_TOOL_BLOB, SCULPT_TOOL_CREASE, SCULPT_TOOL_SNAKE_HOOK);
}
static int rna_SculptToolCapabilities_has_plane_offset_get(PointerRNA *ptr)
@@ -635,7 +641,7 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
srna = RNA_def_struct(brna, "BrushTextureSlot", "TextureSlot");
RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "Brush Texture Slot", "Texture slot for textures in a Brush datablock");
+ RNA_def_struct_ui_text(srna, "Brush Texture Slot", "Texture slot for textures in a Brush data-block");
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "rot");
@@ -647,34 +653,34 @@ static void rna_def_brush_texture_slot(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "tex_paint_map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_tex_paint_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "mask_map_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "brush_map_mode");
RNA_def_property_enum_items(prop, prop_mask_paint_map_mode_items);
RNA_def_property_ui_text(prop, "Mode", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RAKE);
RNA_def_property_ui_text(prop, "Rake", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "use_random", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "brush_angle_mode", MTEX_ANGLE_RANDOM);
RNA_def_property_ui_text(prop, "Random", "");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "random_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI * 2);
RNA_def_property_ui_text(prop, "Random Angle", "Brush texture random angle");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
TEXTURE_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source");
TEXTURE_CAPABILITY(has_random_texture_angle, "Has Random Texture Angle");
@@ -706,6 +712,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna)
SCULPT_TOOL_CAPABILITY(has_height, "Has Height");
SCULPT_TOOL_CAPABILITY(has_jitter, "Has Jitter");
SCULPT_TOOL_CAPABILITY(has_normal_weight, "Has Crease/Pinch Factor");
+ SCULPT_TOOL_CAPABILITY(has_rake_factor, "Has Rake Factor");
SCULPT_TOOL_CAPABILITY(has_persistence, "Has Persistence");
SCULPT_TOOL_CAPABILITY(has_pinch_factor, "Has Pinch Factor");
SCULPT_TOOL_CAPABILITY(has_plane_offset, "Has Plane Offset");
@@ -851,7 +858,7 @@ static void rna_def_brush(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "Brush", "ID");
- RNA_def_struct_ui_text(srna, "Brush", "Brush datablock for storing brush settings for painting and sculpting");
+ RNA_def_struct_ui_text(srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
/* enums */
@@ -861,19 +868,19 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "sculpt_tool", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, brush_sculpt_tool_items);
+ RNA_def_property_enum_items(prop, rna_enum_brush_sculpt_tool_items);
RNA_def_property_ui_text(prop, "Sculpt Tool", "");
RNA_def_property_update(prop, 0, "rna_Brush_sculpt_tool_update");
prop = RNA_def_property(srna, "vertex_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "vertexpaint_tool");
- RNA_def_property_enum_items(prop, brush_vertex_tool_items);
+ RNA_def_property_enum_items(prop, rna_enum_brush_vertex_tool_items);
RNA_def_property_ui_text(prop, "Blending mode", "Brush blending mode");
RNA_def_property_update(prop, 0, "rna_Brush_vertex_tool_update");
prop = RNA_def_property(srna, "image_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "imagepaint_tool");
- RNA_def_property_enum_items(prop, brush_image_tool_items);
+ RNA_def_property_enum_items(prop, rna_enum_brush_image_tool_items);
RNA_def_property_ui_text(prop, "Image Paint Tool", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_Brush_imagepaint_tool_update");
@@ -1025,6 +1032,14 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "rake_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "rake_factor");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 3);
+ RNA_def_property_ui_text(prop, "Rake", "How much grab will follow cursor rotation");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "crease_pinch_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "crease_pinch_factor");
RNA_def_property_float_default(prop, 2.0f / 3.0f);
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index b82f3c88c56..d5044ec9838 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -118,7 +118,7 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
srna = RNA_def_struct(brna, "CameraStereoData", NULL);
RNA_def_struct_sdna(srna, "CameraStereoSettings");
RNA_def_struct_nested(brna, srna, "Camera");
- RNA_def_struct_ui_text(srna, "Stereo", "Stereoscopy settings for a Camera datablock");
+ RNA_def_struct_ui_text(srna, "Stereo", "Stereoscopy settings for a Camera data-block");
prop = RNA_def_property(srna, "convergence_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, convergence_mode_items);
@@ -139,11 +139,18 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "convergence_distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0.00001f, FLT_MAX);
- RNA_def_property_ui_range(prop, 0.0f, 15.f, 1, 2);
+ RNA_def_property_ui_range(prop, 0.00001f, 15.f, 1, 2);
RNA_def_property_ui_text(prop, "Convergence Plane Distance",
"The converge point for the stereo cameras "
"(often the distance between a projector and the projection screen)");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+
+ prop = RNA_def_property(srna, "use_spherical_stereo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_S3D_SPHERICAL);
+ RNA_def_property_ui_text(prop, "Spherical Stereo",
+ "Render every pixel rotating the camera around the "
+ "middle of the interocular distance");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
}
void RNA_def_camera(BlenderRNA *brna)
@@ -180,7 +187,7 @@ void RNA_def_camera(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "Camera", "ID");
- RNA_def_struct_ui_text(srna, "Camera", "Camera datablock for storing camera settings");
+ RNA_def_struct_ui_text(srna, "Camera", "Camera data-block for storing camera settings");
RNA_def_struct_ui_icon(srna, ICON_CAMERA_DATA);
/* Enums */
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index bcb3544049c..b75a3f0320b 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -269,7 +269,7 @@ static void rna_def_cloth_solver_result(BlenderRNA *brna)
{BPH_SOLVER_NUMERICAL_ISSUE, "NUMERICAL_ISSUE", 0, "Numerical Issue", "The provided data did not satisfy the prerequisites"},
{BPH_SOLVER_NO_CONVERGENCE, "NO_CONVERGENCE", 0, "No Convergence", "Iterative procedure did not converge"},
{BPH_SOLVER_INVALID_INPUT, "INVALID_INPUT", 0, "Invalid Input", "The inputs are invalid, or the algorithm has been improperly called"},
- {0, NULL, 0, NULL, NULL}
+ {0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "ClothSolverResult", NULL);
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 8ea67a34fbb..021bc608564 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -154,7 +154,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
{
char *path = NULL;
- /* handle the cases where a single datablock may have 2 ramp types */
+ /* handle the cases where a single data-block may have 2 ramp types */
if (ptr->id.data) {
ID *id = ptr->id.data;
@@ -195,9 +195,8 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
case ID_LS:
{
- char *path = BKE_linestyle_path_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data);
- if (path)
- return path;
+ /* may be NULL */
+ path = BKE_linestyle_path_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data);
break;
}
@@ -327,7 +326,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
for (node = ntree->nodes.first; node; node = node->next) {
if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
}
break;
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 6dac2e27f9c..0b5d0f3d41d 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -46,7 +46,7 @@
#include "ED_object.h"
/* please keep the names in sync with constraint.c */
-EnumPropertyItem constraint_type_items[] = {
+EnumPropertyItem rna_enum_constraint_type_items[] = {
{0, "", 0, N_("Motion Tracking"), ""},
{CONSTRAINT_TYPE_CAMERASOLVER, "CAMERA_SOLVER", ICON_CONSTRAINT_DATA, "Camera Solver", ""},
{CONSTRAINT_TYPE_FOLLOWTRACK, "FOLLOW_TRACK", ICON_CONSTRAINT_DATA, "Follow Track", ""},
@@ -412,6 +412,7 @@ static void rna_Constraint_followTrack_camera_set(PointerRNA *ptr, PointerRNA va
if (ob) {
if (ob->type == OB_CAMERA && ob != (Object *)ptr->id.data) {
data->camera = ob;
+ id_lib_extern((ID *)ob);
}
}
else {
@@ -428,6 +429,7 @@ static void rna_Constraint_followTrack_depthObject_set(PointerRNA *ptr, PointerR
if (ob) {
if (ob->type == OB_MESH && ob != (Object *)ptr->id.data) {
data->depth_ob = ob;
+ id_lib_extern((ID *)ob);
}
}
else {
@@ -457,6 +459,7 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v
if (ob) {
if (ob->type == OB_CAMERA && ob != (Object *)ptr->id.data) {
data->camera = ob;
+ id_lib_extern((ID *)ob);
}
}
else {
@@ -1005,7 +1008,7 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "volume", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, 0.001, 100.f);
+ RNA_def_property_range(prop, 0.001f, 100.0f);
RNA_def_property_ui_text(prop, "Volume", "Volume of the bone at rest");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -1085,7 +1088,6 @@ static void rna_def_constraint_minmax(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_range(prop, -1000.0, 1000.0f);
RNA_def_property_ui_range(prop, -100.0f, 100.0f, 1, -1);
RNA_def_property_ui_text(prop, "Offset", "Offset of floor from object origin");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -1357,7 +1359,7 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "orglength");
- RNA_def_property_range(prop, 0.0, 1000.f);
+ RNA_def_property_range(prop, 0.0f, 1000.0f);
RNA_def_property_ui_range(prop, 0, 100.0f, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "Original Length", "Length at rest position");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -1614,13 +1616,6 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem axis_map_items[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {2, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "TransformConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Transformation Constraint", "Map transformations of the target to the object");
RNA_def_struct_sdna_from(srna, "bTransformConstraint", "data");
@@ -1650,19 +1645,19 @@ static void rna_def_constraint_transform(BlenderRNA *brna)
prop = RNA_def_property(srna, "map_to_x_from", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "map[0]");
- RNA_def_property_enum_items(prop, axis_map_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Map To X From", "The source axis constrained object's X axis uses");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "map_to_y_from", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "map[1]");
- RNA_def_property_enum_items(prop, axis_map_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Map To Y From", "The source axis constrained object's Y axis uses");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "map_to_z_from", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "map[2]");
- RNA_def_property_enum_items(prop, axis_map_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Map To Z From", "The source axis constrained object's Z axis uses");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -1932,37 +1927,37 @@ static void rna_def_constraint_location_limit(BlenderRNA *brna)
prop = RNA_def_property(srna, "min_x", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "xmin");
- RNA_def_property_range(prop, -1000.0, 1000.f);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Minimum X", "Lowest X value to allow");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "min_y", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "ymin");
- RNA_def_property_range(prop, -1000.0, 1000.f);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Minimum Y", "Lowest Y value to allow");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "min_z", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "zmin");
- RNA_def_property_range(prop, -1000.0, 1000.f);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Minimum Z", "Lowest Z value to allow");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "max_x", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "xmax");
- RNA_def_property_range(prop, -1000.0, 1000.f);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Maximum X", "Highest X value to allow");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "max_y", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "ymax");
- RNA_def_property_range(prop, -1000.0, 1000.f);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Maximum Y", "Highest Y value to allow");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "max_z", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "zmax");
- RNA_def_property_range(prop, -1000.0, 1000.f);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Maximum Z", "Highest Z value to allow");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -2147,7 +2142,7 @@ static void rna_def_constraint_distance_limit(BlenderRNA *brna)
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "dist");
- RNA_def_property_range(prop, 0.0, 100.f);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3);
RNA_def_property_ui_text(prop, "Distance", "Radius of limiting sphere");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -2197,13 +2192,14 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "distance", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "dist");
- RNA_def_property_range(prop, 0.0, 100.f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3);
RNA_def_property_ui_text(prop, "Distance", "Distance to Target");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "project_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "projAxis");
- RNA_def_property_enum_items(prop, object_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Project Axis", "Axis constrain to");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -2215,7 +2211,8 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "projLimit");
- RNA_def_property_range(prop, 0.0, 100.f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3);
RNA_def_property_ui_text(prop, "Project Distance", "Limit the distance used for projection (zero disables)");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
@@ -2607,7 +2604,7 @@ void RNA_def_constraint(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, constraint_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_constraint_type_items);
RNA_def_property_ui_text(prop, "Type", "");
prop = RNA_def_property(srna, "owner_space", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index 1a0f3c30b03..ed700916584 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -40,7 +40,7 @@
#include "WM_types.h"
-EnumPropertyItem controller_type_items[] = {
+EnumPropertyItem rna_enum_controller_type_items[] = {
{CONT_LOGIC_AND, "LOGIC_AND", 0, "And", "Logic And"},
{CONT_LOGIC_OR, "LOGIC_OR", 0, "Or", "Logic Or"},
{CONT_LOGIC_NAND, "LOGIC_NAND", 0, "Nand", "Logic Nand"},
@@ -213,7 +213,7 @@ void RNA_def_controller(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_funcs(prop, NULL, "rna_Controller_type_set", NULL);
- RNA_def_property_enum_items(prop, controller_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_controller_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_update(prop, NC_LOGIC, NULL);
@@ -287,7 +287,7 @@ void RNA_def_controller(BlenderRNA *brna)
prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Text");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Text", "Text datablock with the python script");
+ RNA_def_property_ui_text(prop, "Text", "Text data-block with the python script");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index e1e9fc1cf68..d28dd8f7607 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -56,7 +56,7 @@ static EnumPropertyItem beztriple_handle_type_items[] = {
};
#endif
-EnumPropertyItem keyframe_handle_type_items[] = {
+EnumPropertyItem rna_enum_keyframe_handle_type_items[] = {
{HD_FREE, "FREE", 0, "Free", ""},
{HD_VECT, "VECTOR", 0, "Vector", ""},
{HD_ALIGN, "ALIGNED", 0, "Aligned", ""},
@@ -65,7 +65,7 @@ EnumPropertyItem keyframe_handle_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem beztriple_interpolation_mode_items[] = {
+EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
/* interpolation */
{0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
{BEZT_IPO_CONST, "CONSTANT", ICON_IPO_CONSTANT, "Constant", "No interpolation, value of A gets held until B is encountered"},
@@ -385,6 +385,7 @@ static void rna_Curve_bevelObject_set(PointerRNA *ptr, PointerRNA value)
/* set as bevobj, there could be infinity loop in displist calculation */
if (ob->type == OB_CURVE && ob->data != cu) {
cu->bevobj = ob;
+ id_lib_extern((ID *)ob);
}
}
else {
@@ -427,6 +428,7 @@ static void rna_Curve_taperObject_set(PointerRNA *ptr, PointerRNA value)
/* set as bevobj, there could be infinity loop in displist calculation */
if (ob->type == OB_CURVE && ob->data != cu) {
cu->taperobj = ob;
+ id_lib_extern((ID *)ob);
}
}
else {
@@ -1044,8 +1046,8 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
RNA_def_property_string_maxlength(prop, MAX_ID_NAME - 2);
RNA_def_property_ui_text(prop, "Object Font",
"Use Objects as font characters (give font objects a common name "
- "followed by the character they represent, eg. 'family_a', 'family_b', etc, "
- "set this setting to 'family_', and turn on Vertex Duplication)");
+ "followed by the character they represent, eg. 'family-a', 'family-b', etc, "
+ "set this setting to 'family-', and turn on Vertex Duplication)");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
prop = RNA_def_property(srna, "body", PROP_STRING, PROP_NONE);
@@ -1191,7 +1193,7 @@ static void rna_def_surface(BlenderRNA *brna)
srna = RNA_def_struct(brna, "SurfaceCurve", "Curve");
RNA_def_struct_sdna(srna, "Curve");
- RNA_def_struct_ui_text(srna, "Surface Curve", "Curve datablock used for storing surfaces");
+ RNA_def_struct_ui_text(srna, "Surface Curve", "Curve data-block used for storing surfaces");
RNA_def_struct_ui_icon(srna, ICON_SURFACE_DATA);
rna_def_nurbs(brna, srna);
@@ -1203,7 +1205,7 @@ static void rna_def_text(BlenderRNA *brna)
srna = RNA_def_struct(brna, "TextCurve", "Curve");
RNA_def_struct_sdna(srna, "Curve");
- RNA_def_struct_ui_text(srna, "Text Curve", "Curve datablock used for storing text");
+ RNA_def_struct_ui_text(srna, "Text Curve", "Curve data-block used for storing text");
RNA_def_struct_ui_icon(srna, ICON_FONT_DATA);
rna_def_font(brna, srna);
@@ -1334,7 +1336,7 @@ static void rna_def_curve(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "Curve", "ID");
- RNA_def_struct_ui_text(srna, "Curve", "Curve datablock storing curves, splines and NURBS");
+ RNA_def_struct_ui_text(srna, "Curve", "Curve data-block storing curves, splines and NURBS");
RNA_def_struct_ui_icon(srna, ICON_CURVE_DATA);
RNA_def_struct_refine_func(srna, "rna_Curve_refine");
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 3b01305110c..36e2b9b0572 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -1315,7 +1315,7 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive)
* The values hare are a little confusing:
*
* \param step: Used as the value to increase/decrease when clicking on number buttons,
- * \as well as scaling mouse input for click-dragging number buttons.
+ * as well as scaling mouse input for click-dragging number buttons.
* For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows.
* For ints, whole values are used.
*
@@ -2875,6 +2875,18 @@ PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *iden
return prop;
}
+PropertyRNA *RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier,
+ float default_value, float hardmin, float hardmax, const char *ui_name,
+ const char *ui_description, float softmin, float softmax)
+{
+ PropertyRNA *prop = RNA_def_float(cont_, identifier, default_value,
+ hardmin, hardmax, ui_name, ui_description,
+ softmin, softmax);
+ RNA_def_property_subtype(prop, PROP_DISTANCE);
+
+ return prop;
+}
+
PropertyRNA *RNA_def_float_array(StructOrFunctionRNA *cont_, const char *identifier, int len,
const float *default_value, float hardmin, float hardmax, const char *ui_name,
const char *ui_description, float softmin, float softmax)
@@ -3302,7 +3314,7 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;
if (eprop->item) {
- earray = MEM_callocN(sizeof(EnumPropertyItem) * (eprop->totitem + 1), "RNA_def_property_store"),
+ earray = MEM_callocN(sizeof(EnumPropertyItem) * (eprop->totitem + 1), "RNA_def_property_store");
memcpy(earray, eprop->item, sizeof(EnumPropertyItem) * (eprop->totitem + 1));
eprop->item = earray;
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 229cdaa6005..fc2b028e829 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -45,7 +45,7 @@
#include "WM_types.h"
-EnumPropertyItem prop_dynamicpaint_type_items[] = {
+EnumPropertyItem rna_enum_prop_dynamicpaint_type_items[] = {
{MOD_DYNAMICPAINT_TYPE_CANVAS, "CANVAS", 0, "Canvas", ""},
{MOD_DYNAMICPAINT_TYPE_BRUSH, "BRUSH", 0, "Brush", ""},
{0, NULL, 0, NULL, NULL}
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 576af7b3a1c..b428ab30784 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -48,7 +48,7 @@
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
-EnumPropertyItem fmodifier_type_items[] = {
+EnumPropertyItem rna_enum_fmodifier_type_items[] = {
{FMODIFIER_TYPE_NULL, "NULL", 0, "Invalid", ""},
{FMODIFIER_TYPE_GENERATOR, "GENERATOR", 0, "Generator",
"Generate a curve using a factorized or expanded polynomial"},
@@ -61,7 +61,7 @@ EnumPropertyItem fmodifier_type_items[] = {
{FMODIFIER_TYPE_NOISE, "NOISE", 0, "Noise",
"Add pseudo-random noise on top of F-Curves"},
/*{FMODIFIER_TYPE_FILTER, "FILTER", 0, "Filter", ""},*/ /* FIXME: not implemented yet! */
- {FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},
+ /*{FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},*/ /* FIXME: not implemented yet! */
{FMODIFIER_TYPE_LIMITS, "LIMITS", 0, "Limits",
"Restrict maximum and minimum values of F-Curve"},
{FMODIFIER_TYPE_STEPPED, "STEPPED", 0, "Stepped Interpolation",
@@ -69,15 +69,15 @@ EnumPropertyItem fmodifier_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem beztriple_keyframe_type_items[] = {
- {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", 0, "Keyframe", "Normal keyframe - e.g. for key poses"},
- {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", 0, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
- {BEZT_KEYTYPE_EXTREME, "EXTREME", 0, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
- {BEZT_KEYTYPE_JITTER, "JITTER", 0, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
+EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = {
+ {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", VICO_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"},
+ {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", VICO_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"},
+ {BEZT_KEYTYPE_EXTREME, "EXTREME", VICO_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"},
+ {BEZT_KEYTYPE_JITTER, "JITTER", VICO_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"},
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem beztriple_interpolation_easing_items[] = {
+EnumPropertyItem rna_enum_beztriple_interpolation_easing_items[] = {
/* XXX: auto-easing is currently using a placeholder icon... */
{BEZT_IPO_EASE_AUTO, "AUTO", ICON_IPO_EASE_IN_OUT, "Automatic Easing",
"Easing type is chosen automatically based on what the type of interpolation used "
@@ -275,6 +275,15 @@ static void rna_DriverVariable_type_set(PointerRNA *ptr, int value)
driver_change_variable_type(dvar, value);
}
+void rna_DriverVariable_name_set(PointerRNA *ptr, const char *value)
+{
+ DriverVar *data = (DriverVar *)(ptr->data);
+
+ BLI_strncpy_utf8(data->name, value, 64);
+ driver_variable_name_validate(data);
+}
+
+
/* ----------- */
static DriverVar *rna_Driver_new_variable(ChannelDriver *driver)
@@ -291,7 +300,7 @@ static void rna_Driver_remove_variable(ChannelDriver *driver, ReportList *report
return;
}
- driver_free_variable(driver, dvar);
+ driver_free_variable_ex(driver, dvar);
RNA_POINTER_INVALIDATE(dvar_ptr);
}
@@ -740,9 +749,9 @@ static void rna_FModifierStepped_end_frame_range(PointerRNA *ptr, float *min, fl
*max = MAXFRAMEF;
}
-static BezTriple *rna_FKeyframe_points_insert(FCurve *fcu, float frame, float value, int flag)
+static BezTriple *rna_FKeyframe_points_insert(FCurve *fcu, float frame, float value, int keyframe_type, int flag)
{
- int index = insert_vert_fcurve(fcu, frame, value, flag | INSERTKEY_NO_USERPREF);
+ int index = insert_vert_fcurve(fcu, frame, value, (char)keyframe_type, flag | INSERTKEY_NO_USERPREF);
return ((fcu->bezt) && (index >= 0)) ? (fcu->bezt + index) : NULL;
}
@@ -1293,7 +1302,7 @@ static void rna_def_fmodifier(BlenderRNA *brna)
/* type */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, fmodifier_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_fmodifier_type_items);
RNA_def_property_ui_text(prop, "Type", "F-Curve Modifier Type");
/* settings */
@@ -1420,7 +1429,7 @@ static void rna_def_drivertarget(BlenderRNA *brna)
prop = RNA_def_property(srna, "id_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "idtype");
- RNA_def_property_enum_items(prop, id_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_id_type_items);
RNA_def_property_enum_default(prop, ID_OB);
RNA_def_property_enum_funcs(prop, NULL, "rna_DriverTarget_id_type_set", NULL);
RNA_def_property_editable_func(prop, "rna_DriverTarget_id_type_editable");
@@ -1458,11 +1467,11 @@ static void rna_def_drivervar(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem prop_type_items[] = {
- {DVAR_TYPE_SINGLE_PROP, "SINGLE_PROP", 0, "Single Property", "Use the value from some RNA property (Default)"},
- {DVAR_TYPE_TRANSFORM_CHAN, "TRANSFORMS", 0, "Transform Channel",
+ {DVAR_TYPE_SINGLE_PROP, "SINGLE_PROP", ICON_RNA, "Single Property", "Use the value from some RNA property (Default)"},
+ {DVAR_TYPE_TRANSFORM_CHAN, "TRANSFORMS", ICON_MANIPUL, "Transform Channel",
"Final transformation value of object or bone"},
- {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", 0, "Rotational Difference", "Use the angle between two bones"},
- {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", 0, "Distance", "Distance between two bones or objects"},
+ {DVAR_TYPE_ROT_DIFF, "ROTATION_DIFF", ICON_PARTICLE_TIP, "Rotational Difference", "Use the angle between two bones"}, /* XXX: Icon... */
+ {DVAR_TYPE_LOC_DIFF, "LOC_DIFF", ICON_FULLSCREEN_ENTER, "Distance", "Distance between two bones or objects"}, /* XXX: Icon... */
{0, NULL, 0, NULL, NULL}
};
@@ -1474,6 +1483,7 @@ static void rna_def_drivervar(BlenderRNA *brna)
/* Variable Name */
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_DriverVariable_name_set");
RNA_def_property_ui_text(prop, "Name",
"Name to use in scripted expressions/functions (no spaces or dots are allowed, "
"and must start with a letter)");
@@ -1493,6 +1503,12 @@ static void rna_def_drivervar(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "targets", "num_targets");
RNA_def_property_struct_type(prop, "DriverTarget");
RNA_def_property_ui_text(prop, "Targets", "Sources of input data for evaluating this variable");
+
+ /* Name Validity Flags */
+ prop = RNA_def_property(srna, "is_name_valid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", DVAR_FLAG_INVALID_NAME);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Is Name Valid", "Is this a valid name for a driver variable");
}
@@ -1638,19 +1654,19 @@ static void rna_def_fkeyframe(BlenderRNA *brna)
/* Enums */
prop = RNA_def_property(srna, "handle_left_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "h1");
- RNA_def_property_enum_items(prop, keyframe_handle_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyframe_handle_type_items);
RNA_def_property_ui_text(prop, "Left Handle Type", "Handle types");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
prop = RNA_def_property(srna, "handle_right_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "h2");
- RNA_def_property_enum_items(prop, keyframe_handle_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyframe_handle_type_items);
RNA_def_property_ui_text(prop, "Right Handle Type", "Handle types");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "ipo");
- RNA_def_property_enum_items(prop, beztriple_interpolation_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_mode_items);
RNA_def_property_ui_text(prop, "Interpolation",
"Interpolation method to use for segment of the F-Curve from "
"this Keyframe until the next Keyframe");
@@ -1658,14 +1674,14 @@ static void rna_def_fkeyframe(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "hide");
- RNA_def_property_enum_items(prop, beztriple_keyframe_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_keyframe_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of keyframe (for visual purposes only)");
RNA_def_property_update(prop, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
prop = RNA_def_property(srna, "easing", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "easing");
- RNA_def_property_enum_items(prop, beztriple_interpolation_easing_items);
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_easing_items);
RNA_def_property_ui_text(prop, "Easing",
"Which ends of the segment between this and the next keyframe easing "
"interpolation is applied to");
@@ -1737,7 +1753,7 @@ static void rna_def_fcurve_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "fmodifier", "FModifier", "", "New fmodifier");
RNA_def_function_return(func, parm);
/* object to add */
- parm = RNA_def_enum(func, "type", fmodifier_type_items, 1, "", "Constraint type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_fmodifier_type_items, 1, "", "Constraint type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_FCurve_modifiers_remove");
@@ -1777,8 +1793,9 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "",
"Y Value of this keyframe point", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(parm, PROP_REQUIRED);
-
RNA_def_enum_flag(func, "options", keyframe_flag_items, 0, "", "Keyframe options");
+ RNA_def_enum(func, "keyframe_type", rna_enum_beztriple_keyframe_type_items, BEZT_KEYTYPE_KEYFRAME, "",
+ "Type of keyframe to insert");
parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Newly created keyframe");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 01feb3cb748..16e0f17eac5 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -343,12 +343,12 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "animStart");
- RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(prop, "Start Time", "Simulation time of the first blender frame (in seconds)");
prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "animEnd");
- RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_text(prop, "End Time", "Simulation time of the last blender frame (in seconds)");
prop = RNA_def_property(srna, "frame_offset", PROP_INT, PROP_NONE);
@@ -627,12 +627,12 @@ static void rna_def_fluidsim_control(BlenderRNA *brna)
prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "cpsTimeStart");
- RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_text(prop, "Start Time", "Time when the control particles are activated");
prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
RNA_def_property_float_sdna(prop, NULL, "cpsTimeEnd");
- RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_text(prop, "End Time", "Time when the control particles are deactivated");
prop = RNA_def_property(srna, "attraction_strength", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 333220146d6..3c16f086325 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -50,11 +50,46 @@
#include "BKE_gpencil.h"
+#include "DNA_object_types.h"
+
+
static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
+static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ /* Notify all places where GPencil data lives that the editing state is different */
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_MODE, NULL);
+}
+
+static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bGPdata *gpd = (bGPdata *)ptr->id.data;
+ bGPDlayer *gpl;
+ bool enabled = false;
+
+ /* Ensure that the datablock's onionskinning toggle flag
+ * stays in sync with the status of the actual layers
+ */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_ONIONSKIN) {
+ enabled = true;
+ }
+ }
+
+ if (enabled)
+ gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
+ else
+ gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
+
+
+ /* Now do standard updates... */
+ rna_GPencil_update(bmain, scene, ptr);
+}
+
static char *rna_GPencilLayer_path(PointerRNA *ptr)
{
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
@@ -73,7 +108,7 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr)
if (gpl->flag & GP_LAYER_LOCKED)
return 0;
else
- return 1;
+ return PROP_EDITABLE;
}
static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max,
@@ -110,7 +145,7 @@ static int rna_GPencilLayer_is_stroke_visible_get(PointerRNA *ptr)
* about this limit for showing/not showing
*/
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
- return (gpl->color[3] > 0.001f);
+ return (gpl->color[3] > GPENCIL_ALPHA_OPACITY_THRESH);
}
static int rna_GPencilLayer_is_fill_visible_get(PointerRNA *ptr)
@@ -119,7 +154,7 @@ static int rna_GPencilLayer_is_fill_visible_get(PointerRNA *ptr)
* about this limit for showing/not showing
*/
bGPDlayer *gpl = (bGPDlayer *)ptr->data;
- return (gpl->fill[3] > 0.001f);
+ return (gpl->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH);
}
static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr)
@@ -201,6 +236,30 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
}
+static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value)
+{
+ bGPdata *gpd = ptr->id.data;
+ bGPDlayer *gpl;
+
+ /* set new value */
+ if (value) {
+ /* enable on active layer (it's the one that's most likely to be of interest right now) */
+ gpl = gpencil_layer_getactive(gpd);
+ if (gpl) {
+ gpl->flag |= GP_LAYER_ONIONSKIN;
+ }
+
+ gpd->flag |= GP_DATA_SHOW_ONIONSKINS;
+ }
+ else {
+ /* disable on all layers - allowa quickly turning them all off, without having to check */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->flag &= ~GP_LAYER_ONIONSKIN;
+ }
+
+ gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
+ }
+}
static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, bGPDframe **r_gpf)
{
@@ -389,7 +448,7 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src)
static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive)
{
- bGPDlayer *gl = gpencil_layer_addnew(gpd, name, setactive);
+ bGPDlayer *gl = gpencil_layer_addnew(gpd, name, setactive != 0);
WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -639,7 +698,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Info", "Layer name");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilLayer_info_set");
RNA_def_struct_name_property(srna, prop);
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_RENAME, NULL);
/* Frames */
prop = RNA_def_property(srna, "frames", PROP_COLLECTION, PROP_NONE);
@@ -701,7 +760,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ONIONSKIN);
RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_onion_skinning_update");
prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "gstep");
@@ -738,6 +797,20 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+ /* Smoothing factor for new strokes */
+ prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
+ RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_ui_text(prop, "Smooth", "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Subdivision level for new strokes */
+ prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sublevel");
+ RNA_def_property_range(prop, 0, 3);
+ RNA_def_property_ui_text(prop, "Subdivision Steps", "Number of times to subdivide newly created strokes, for less jagged strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -849,14 +922,6 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
PropertyRNA *prop;
FunctionRNA *func;
- static EnumPropertyItem draw_mode_items[] = {
- {GP_DATA_VIEWALIGN, "CURSOR", 0, "Cursor", "Draw stroke at the 3D cursor"},
- {0, "VIEW", 0, "View", "Stick stroke to the view "}, /* weird, GP_DATA_VIEWALIGN is inverted */
- {GP_DATA_VIEWALIGN | GP_DATA_DEPTH_VIEW, "SURFACE", 0, "Surface", "Stick stroke to surfaces"},
- {GP_DATA_VIEWALIGN | GP_DATA_DEPTH_STROKE, "STROKE", 0, "Stroke", "Stick stroke to other strokes"},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "GreasePencil", "ID");
RNA_def_struct_sdna(srna, "bGPdata");
RNA_def_struct_ui_text(srna, "Grease Pencil", "Freehand annotation sketchbook");
@@ -873,21 +938,17 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
rna_def_animdata_common(srna);
/* Flags */
- prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
- RNA_def_property_enum_items(prop, draw_mode_items);
- RNA_def_property_ui_text(prop, "Draw Mode", "");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
- prop = RNA_def_property(srna, "use_stroke_endpoints", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_DEPTH_STROKE_ENDPOINTS);
- RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
-
prop = RNA_def_property(srna, "use_stroke_edit_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_EDITMODE);
- RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Enable alternative keymap to make editing stroke points easier");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_update");
+ RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Edit Grease Pencil strokes instead of viewport data");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update");
+
+ prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_ONIONSKINS);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_use_onion_skinning_set");
+ RNA_def_property_ui_text(prop, "Onion Skins",
+ "Show ghosts of the frames before and after the current frame, toggle to enable on active layer or disable all");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
/* API Functions */
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c
index 2f9c12c713b..47bee589615 100644
--- a/source/blender/makesrna/intern/rna_group.c
+++ b/source/blender/makesrna/intern/rna_group.c
@@ -113,7 +113,7 @@ void RNA_def_group(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Group", "ID");
- RNA_def_struct_ui_text(srna, "Group", "Group of Object datablocks");
+ RNA_def_struct_ui_text(srna, "Group", "Group of Object data-blocks");
RNA_def_struct_ui_icon(srna, ICON_GROUP);
/* this is done on save/load in readfile.c, removed if no objects are in the group */
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 561f5c9dd26..f65aa90ea71 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -44,7 +44,7 @@
#include "WM_types.h"
#include "WM_api.h"
-EnumPropertyItem image_generated_type_items[] = {
+EnumPropertyItem rna_enum_image_generated_type_items[] = {
{IMA_GENTYPE_BLANK, "BLANK", 0, "Blank", "Generate a blank image"},
{IMA_GENTYPE_GRID, "UV_GRID", 0, "UV Grid", "Generated grid to test UV mappings"},
{IMA_GENTYPE_GRID_COLOR, "COLOR_GRID", 0, "Color Grid", "Generated improved UV grid to test UV mappings"},
@@ -62,6 +62,10 @@ static EnumPropertyItem image_source_items[] = {
#ifdef RNA_RUNTIME
+#include "BKE_global.h"
+
+#include "GPU_draw.h"
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -78,6 +82,16 @@ static void rna_Image_animated_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
}
}
+static int rna_Image_is_stereo_3d_get(PointerRNA *ptr)
+{
+ return BKE_image_is_stereo((Image *)ptr->data);
+}
+
+static int rna_Image_is_multiview_get(PointerRNA *ptr)
+{
+ return BKE_image_is_multiview((Image *)ptr->data);
+}
+
static int rna_Image_dirty_get(PointerRNA *ptr)
{
return BKE_image_is_dirty((Image *)ptr->data);
@@ -389,7 +403,11 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values)
((unsigned char *)ibuf->rect)[i] = FTOCHAR(values[i]);
}
- ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID;
+ ibuf->userflags |= IB_BITMAPDIRTY | IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID;
+ if (!G.background) {
+ GPU_free_image(ima);
+ }
+ WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
}
BKE_image_release_ibuf(ima, ibuf, lock);
@@ -486,7 +504,7 @@ static void rna_def_imageuser(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ImageUser", NULL);
RNA_def_struct_ui_text(srna, "Image User",
- "Parameters defining how an Image datablock is used by another datablock");
+ "Parameters defining how an Image data-block is used by another data-block");
RNA_def_struct_path_func(srna, "rna_ImageUser_path");
prop = RNA_def_property(srna, "use_auto_refresh", PROP_BOOLEAN, PROP_NONE);
@@ -566,9 +584,9 @@ static void rna_def_image_packed_files(BlenderRNA *brna)
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "filepath");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_struct_name_property(srna, prop);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ RNA_api_image_packed_file(srna);
}
static void rna_def_render_slot(BlenderRNA *brna)
@@ -639,7 +657,7 @@ static void rna_def_image(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "Image", "ID");
- RNA_def_struct_ui_text(srna, "Image", "Image datablock referencing an external or packed image");
+ RNA_def_struct_ui_text(srna, "Image", "Image data-block referencing an external or packed image");
RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
@@ -653,7 +671,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "File Name", "Image/Movie file name (without data refreshing)");
prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, image_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_image_type_items);
RNA_def_property_enum_funcs(prop, "rna_Image_file_format_get", "rna_Image_file_format_set", NULL);
RNA_def_property_ui_text(prop, "File Format", "Format used for re-saving this file");
@@ -716,12 +734,12 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
prop = RNA_def_property(srna, "is_stereo_3d", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_STEREO);
+ RNA_def_property_boolean_funcs(prop, "rna_Image_is_stereo_3d_get", NULL);
RNA_def_property_ui_text(prop, "Stereo 3D", "Image has left and right views");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "is_multiview", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_IS_MULTIVIEW);
+ RNA_def_property_boolean_funcs(prop, "rna_Image_is_multiview_get", NULL);
RNA_def_property_ui_text(prop, "Multiple Views", "Image has more than one view");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -733,7 +751,7 @@ static void rna_def_image(BlenderRNA *brna)
/* generated image (image_generated_change_cb) */
prop = RNA_def_property(srna, "generated_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "gen_type");
- RNA_def_property_enum_items(prop, image_generated_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_image_generated_type_items);
RNA_def_property_ui_text(prop, "Generated Type", "Generated image type");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -908,7 +926,7 @@ static void rna_def_image(BlenderRNA *brna)
/* multiview */
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
- RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_views_format_update");
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index f187a0e1804..6530e0938f6 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -48,6 +48,7 @@
#ifdef RNA_RUNTIME
+#include <errno.h>
#include "BKE_image.h"
#include "BKE_packedFile.h"
#include "BKE_main.h"
@@ -63,6 +64,14 @@
#include "MEM_guardedalloc.h"
+static void rna_ImagePackedFile_save(ImagePackedFile *imapf, ReportList *reports)
+{
+ if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) {
+ BKE_reportf(reports, RPT_ERROR, "Image could not save packed file to '%s'",
+ imapf->filepath);
+ }
+}
+
static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports, const char *path, Scene *scene)
{
ImBuf *ibuf;
@@ -93,7 +102,7 @@ static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports
write_ibuf->dither = scene->r.dither_intensity;
if (!BKE_imbuf_write(write_ibuf, path, &scene->r.im_format)) {
- BKE_reportf(reports, RPT_ERROR, "Could not write image '%s'", path);
+ BKE_reportf(reports, RPT_ERROR, "Could not write image: %s, '%s'", strerror(errno), path);
}
if (write_ibuf != ibuf)
@@ -115,17 +124,10 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r
BLI_strncpy(filename, image->name, sizeof(filename));
BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id));
- if (BKE_image_has_packedfile(image)) {
- ImagePackedFile *imapf;
+ /* note, we purposefully ignore packed files here,
+ * developers need to explicitly write them via 'packed_files' */
- for (imapf = image->packedfiles.first; imapf; imapf = imapf->next) {
- if (writePackedFile(reports, imapf->filepath, imapf->packedfile, 0) != RET_OK) {
- BKE_reportf(reports, RPT_ERROR, "Image '%s' could not save packed file to '%s'",
- image->id.name + 2, imapf->filepath);
- }
- }
- }
- else if (IMB_saveiff(ibuf, filename, ibuf->flags)) {
+ if (IMB_saveiff(ibuf, filename, ibuf->flags)) {
image->type = IMA_TYPE_IMAGE;
if (image->source == IMA_SRC_GENERATED)
@@ -222,7 +224,7 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int filter, int mag)
{
ImBuf *ibuf;
- unsigned int *bind = &image->bindcode;
+ unsigned int *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
int error = GL_NO_ERROR;
ImageUser iuser = {NULL};
void *lock;
@@ -243,18 +245,17 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
return (int)GL_INVALID_OPERATION;
}
- GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y,
+ GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D,
(filter != GL_NEAREST && filter != GL_LINEAR), false, image);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
error = glGetError();
if (error) {
glDeleteTextures(1, (GLuint *)bind);
- image->bindcode = 0;
+ image->bindcode[TEXTARGET_TEXTURE_2D] = 0;
}
BKE_image_release_ibuf(image, ibuf, NULL);
@@ -264,7 +265,7 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f
static int rna_Image_gl_touch(Image *image, ReportList *reports, int frame, int filter, int mag)
{
- unsigned int *bind = &image->bindcode;
+ unsigned int *bind = &image->bindcode[TEXTARGET_TEXTURE_2D];
int error = GL_NO_ERROR;
BKE_image_tag_time(image);
@@ -295,6 +296,15 @@ static void rna_Image_buffers_free(Image *image)
#else
+void RNA_api_image_packed_file(StructRNA *srna)
+{
+ FunctionRNA *func;
+
+ func = RNA_def_function(srna, "save", "rna_ImagePackedFile_save");
+ RNA_def_function_ui_description(func, "Save the packed file to its filepath");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+}
+
void RNA_api_image(StructRNA *srna)
{
FunctionRNA *func;
@@ -323,7 +333,7 @@ void RNA_api_image(StructRNA *srna)
func = RNA_def_function(srna, "unpack", "rna_Image_unpack");
RNA_def_function_ui_description(func, "Save an image packed in the .blend file to disk");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_enum(func, "method", unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
+ RNA_def_enum(func, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
func = RNA_def_function(srna, "reload", "rna_Image_reload");
RNA_def_function_ui_description(func, "Reload the image from its source path");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index eab14be9085..703b02f9d18 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -234,7 +234,6 @@ int rna_object_shapekey_index_set(struct ID *id, PointerRNA value, int current);
void rna_Object_internal_update_data(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
void rna_Mesh_update_draw(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
void rna_TextureSlot_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
-void rna_TextureSlot_brush_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
/* basic poll functions for object types */
int rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
@@ -260,6 +259,7 @@ void RNA_api_camera(StructRNA *srna);
void RNA_api_curve(StructRNA *srna);
void RNA_api_fcurves(StructRNA *srna);
void RNA_api_drivers(StructRNA *srna);
+void RNA_api_image_packed_file(struct StructRNA *srna);
void RNA_api_image(struct StructRNA *srna);
void RNA_api_lattice(struct StructRNA *srna);
void RNA_api_operator(struct StructRNA *srna);
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index c25566b6e33..502e22e2c07 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -156,6 +156,112 @@ static void rna_ShapeKey_slider_max_set(PointerRNA *ptr, float value)
#undef SHAPEKEY_SLIDER_TOL
+/* ***** Normals accessors for shapekeys. ***** */
+/* Note: with this we may recompute several times the same data, should we want to access verts, then polys, then loops
+ * normals... However, such case looks rather unlikely - and not worth adding some kind of caching in KeyBlocks.
+ */
+
+static Mesh *rna_KeyBlock_normals_get_mesh(PointerRNA *ptr, ID *id)
+{
+ Key *key = rna_ShapeKey_find_key((id == NULL && ptr != NULL) ? ptr->id.data : id);
+ id = key ? key->from : NULL;
+
+ if (id != NULL) {
+ switch (GS(id->name)) {
+ case ID_ME:
+ return (Mesh *)id;
+ case ID_OB:
+ {
+ Object *ob = (Object *)id;
+ if (ob->type == OB_MESH) {
+ return ob->data;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int rna_KeyBlock_normals_vert_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+
+ length[0] = me ? me->totvert : 0;
+ length[1] = 3;
+
+ return (length[0] * length[1]);
+}
+
+static void rna_KeyBlock_normals_vert_calc(ID *id, KeyBlock *data, int *normals_len, float **normals)
+{
+ Mesh *me = rna_KeyBlock_normals_get_mesh(NULL, id);
+
+ *normals_len = (me ? me->totvert : 0) * 3;
+
+ if (ELEM(NULL, me, data) || (me->totvert == 0)) {
+ *normals = NULL;
+ return;
+ }
+
+ *normals = MEM_mallocN(sizeof(**normals) * (size_t)(*normals_len), __func__);
+
+ BKE_keyblock_mesh_calc_normals(data, me, (float (*)[3])(*normals), NULL, NULL);
+}
+
+static int rna_KeyBlock_normals_poly_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+
+ length[0] = me ? me->totpoly : 0;
+ length[1] = 3;
+
+ return (length[0] * length[1]);
+}
+
+static void rna_KeyBlock_normals_poly_calc(ID *id, KeyBlock *data, int *normals_len, float **normals)
+{
+ Mesh *me = rna_KeyBlock_normals_get_mesh(NULL, id);
+
+ *normals_len = (me ? me->totpoly : 0) * 3;
+
+ if (ELEM(NULL, me, data) || (me->totpoly == 0)) {
+ *normals = NULL;
+ return;
+ }
+
+ *normals = MEM_mallocN(sizeof(**normals) * (size_t)(*normals_len), __func__);
+
+ BKE_keyblock_mesh_calc_normals(data, me, NULL, (float (*)[3])(*normals), NULL);
+}
+
+static int rna_KeyBlock_normals_loop_len(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION])
+{
+ Mesh *me = rna_KeyBlock_normals_get_mesh(ptr, NULL);
+
+ length[0] = me ? me->totloop : 0;
+ length[1] = 3;
+
+ return (length[0] * length[1]);
+}
+
+static void rna_KeyBlock_normals_loop_calc(ID *id, KeyBlock *data, int *normals_len, float **normals)
+{
+ Mesh *me = rna_KeyBlock_normals_get_mesh(NULL, id);
+
+ *normals_len = (me ? me->totloop : 0) * 3;
+
+ if (ELEM(NULL, me, data) || (me->totloop == 0)) {
+ *normals = NULL;
+ return;
+ }
+
+ *normals = MEM_mallocN(sizeof(**normals) * (size_t)(*normals_len), __func__);
+
+ BKE_keyblock_mesh_calc_normals(data, me, NULL, NULL, (float (*)[3])(*normals));
+}
+
+
PointerRNA rna_object_shapekey_index_get(ID *id, int value)
{
Key *key = rna_ShapeKey_find_key(id);
@@ -482,7 +588,7 @@ static char *rna_ShapeKeyPoint_path(PointerRNA *ptr)
#else
-EnumPropertyItem keyblock_type_items[] = {
+EnumPropertyItem rna_enum_keyblock_type_items[] = {
{KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""},
{KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""},
{KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""},
@@ -558,10 +664,11 @@ static void rna_def_keydata(BlenderRNA *brna)
static void rna_def_keyblock(BlenderRNA *brna)
{
StructRNA *srna;
- PropertyRNA *prop;
+ PropertyRNA *prop, *parm;
+ FunctionRNA *func;
srna = RNA_def_struct(brna, "ShapeKey", NULL);
- RNA_def_struct_ui_text(srna, "Shape Key", "Shape key in a shape keys datablock");
+ RNA_def_struct_ui_text(srna, "Shape Key", "Shape key in a shape keys data-block");
RNA_def_struct_sdna(srna, "KeyBlock");
RNA_def_struct_path_func(srna, "rna_ShapeKey_path");
RNA_def_struct_ui_icon(srna, ICON_SHAPEKEY_DATA);
@@ -591,7 +698,7 @@ static void rna_def_keyblock(BlenderRNA *brna)
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, keyblock_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyblock_type_items);
RNA_def_property_ui_text(prop, "Interpolation", "Interpolation type for absolute shape keys");
RNA_def_property_update(prop, 0, "rna_Key_update_data");
@@ -633,6 +740,36 @@ static void rna_def_keyblock(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Data", "");
RNA_def_property_collection_funcs(prop, "rna_ShapeKey_data_begin", NULL, NULL, "rna_ShapeKey_data_get",
"rna_ShapeKey_data_length", NULL, NULL, NULL);
+
+ /* XXX multi-dim dynamic arrays are very badly supported by (py)rna currently, those are defined for the day
+ * it works better, for now user will get a 1D tuple...
+ **/
+ func = RNA_def_function(srna, "normals_vertex_get", "rna_KeyBlock_normals_vert_calc");
+ RNA_def_function_ui_description(func, "Compute local space vertices' normals for this shape key");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
+ RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_property_multi_array(parm, 2, NULL);
+ RNA_def_property_range(parm, -1.0f, 1.0f);
+ RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_vert_len");
+
+ func = RNA_def_function(srna, "normals_polygon_get", "rna_KeyBlock_normals_poly_calc");
+ RNA_def_function_ui_description(func, "Compute local space faces' normals for this shape key");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
+ RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_property_multi_array(parm, 2, NULL);
+ RNA_def_property_range(parm, -1.0f, 1.0f);
+ RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_poly_len");
+
+ func = RNA_def_function(srna, "normals_split_get", "rna_KeyBlock_normals_loop_calc");
+ RNA_def_function_ui_description(func, "Compute local space face corners' normals for this shape key");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE);
+ RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT);
+ RNA_def_property_multi_array(parm, 2, NULL);
+ RNA_def_property_range(parm, -1.0f, 1.0f);
+ RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_loop_len");
}
static void rna_def_key(BlenderRNA *brna)
@@ -641,7 +778,7 @@ static void rna_def_key(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Key", "ID");
- RNA_def_struct_ui_text(srna, "Key", "Shape keys datablock containing different shapes of geometric datablocks");
+ RNA_def_struct_ui_text(srna, "Key", "Shape keys data-block containing different shapes of geometric data-blocks");
RNA_def_struct_ui_icon(srna, ICON_SHAPEKEY_DATA);
prop = RNA_def_property(srna, "reference_key", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index 3cd51f5d66f..e4e3699f301 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -166,7 +166,7 @@ static void rna_Lamp_use_nodes_update(bContext *C, PointerRNA *ptr)
#else
/* Don't define icons here, so they don't show up in the Lamp UI (properties Editor) - DingTo */
-EnumPropertyItem lamp_type_items[] = {
+EnumPropertyItem rna_enum_lamp_type_items[] = {
{LA_LOCAL, "POINT", 0, "Point", "Omnidirectional point light source"},
{LA_SUN, "SUN", 0, "Sun", "Constant direction parallel ray light source"},
{LA_SPOT, "SPOT", 0, "Spot", "Directional cone light source"},
@@ -189,7 +189,7 @@ static void rna_def_lamp_mtex(BlenderRNA *brna)
srna = RNA_def_struct(brna, "LampTextureSlot", "TextureSlot");
RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "Lamp Texture Slot", "Texture slot for textures in a Lamp datablock");
+ RNA_def_struct_ui_text(srna, "Lamp Texture Slot", "Texture slot for textures in a Lamp data-block");
prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "texco");
@@ -250,7 +250,7 @@ static void rna_def_lamp_sky_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "sky_blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "skyblendtype");
- RNA_def_property_enum_items(prop, ramp_blend_items);
+ RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
RNA_def_property_ui_text(prop, "Sky Blend Mode", "Blend mode for combining sun sky with world sky");
RNA_def_property_update(prop, 0, "rna_Lamp_sky_update");
@@ -343,11 +343,11 @@ static void rna_def_lamp(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Lamp", "ID");
RNA_def_struct_refine_func(srna, "rna_Lamp_refine");
- RNA_def_struct_ui_text(srna, "Lamp", "Lamp datablock for lighting a scene");
+ RNA_def_struct_ui_text(srna, "Lamp", "Lamp data-block for lighting a scene");
RNA_def_struct_ui_icon(srna, ICON_LAMP_DATA);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, lamp_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_lamp_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of Lamp");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_LAMP);
RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
@@ -420,6 +420,7 @@ static void rna_def_lamp_falloff(StructRNA *srna)
{LA_FALLOFF_CONSTANT, "CONSTANT", 0, "Constant", ""},
{LA_FALLOFF_INVLINEAR, "INVERSE_LINEAR", 0, "Inverse Linear", ""},
{LA_FALLOFF_INVSQUARE, "INVERSE_SQUARE", 0, "Inverse Square", ""},
+ {LA_FALLOFF_INVCOEFFICIENTS, "INVERSE_COEFFICIENTS", 0, "Inverse Coefficients", ""},
{LA_FALLOFF_CURVE, "CUSTOM_CURVE", 0, "Custom Curve", ""},
{LA_FALLOFF_SLIDERS, "LINEAR_QUADRATIC_WEIGHTED", 0, "Lin/Quad Weighted", ""},
{0, NULL, 0, NULL, NULL}
@@ -451,6 +452,27 @@ static void rna_def_lamp_falloff(StructRNA *srna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Quadratic Attenuation", "Quadratic distance attenuation");
RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+
+ prop = RNA_def_property(srna, "constant_coefficient", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "coeff_const");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Constant Coefficient",
+ "Constant distance attenuation coefficient");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+
+ prop = RNA_def_property(srna, "linear_coefficient", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "coeff_lin");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Linear Coefficient",
+ "Linear distance attenuation coefficient");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
+
+ prop = RNA_def_property(srna, "quadratic_coefficient", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "coeff_quad");
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Quadratic Coefficient",
+ "Quadratic distance attenuation coefficient");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
}
static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c
index 60e5f6d205c..6bc9cc38a7d 100644
--- a/source/blender/makesrna/intern/rna_lattice.c
+++ b/source/blender/makesrna/intern/rna_lattice.c
@@ -175,7 +175,7 @@ static int rna_Lattice_size_editable(PointerRNA *ptr)
{
Lattice *lt = (Lattice *)ptr->data;
- return lt->key == NULL;
+ return (lt->key == NULL) ? PROP_EDITABLE : 0;
}
static void rna_Lattice_points_u_set(PointerRNA *ptr, int value)
@@ -291,7 +291,7 @@ static void rna_def_lattice(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Lattice", "ID");
- RNA_def_struct_ui_text(srna, "Lattice", "Lattice datablock defining a grid for deforming other objects");
+ RNA_def_struct_ui_text(srna, "Lattice", "Lattice data-block defining a grid for deforming other objects");
RNA_def_struct_ui_icon(srna, ICON_LATTICE_DATA);
prop = RNA_def_property(srna, "points_u", PROP_INT, PROP_NONE);
@@ -323,19 +323,19 @@ static void rna_def_lattice(BlenderRNA *brna)
prop = RNA_def_property(srna, "interpolation_type_u", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typeu");
- RNA_def_property_enum_items(prop, keyblock_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyblock_type_items);
RNA_def_property_ui_text(prop, "Interpolation Type U", "");
RNA_def_property_update(prop, 0, "rna_Lattice_update_data_editlatt");
prop = RNA_def_property(srna, "interpolation_type_v", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typev");
- RNA_def_property_enum_items(prop, keyblock_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyblock_type_items);
RNA_def_property_ui_text(prop, "Interpolation Type V", "");
RNA_def_property_update(prop, 0, "rna_Lattice_update_data_editlatt");
prop = RNA_def_property(srna, "interpolation_type_w", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typew");
- RNA_def_property_enum_items(prop, keyblock_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyblock_type_items);
RNA_def_property_ui_text(prop, "Interpolation Type W", "");
RNA_def_property_update(prop, 0, "rna_Lattice_update_data_editlatt");
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index fe8f52469be..d8cc61bf906 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -39,7 +39,7 @@
#include "WM_types.h"
#include "WM_api.h"
-EnumPropertyItem linestyle_color_modifier_type_items[] = {
+EnumPropertyItem rna_enum_linestyle_color_modifier_type_items[] = {
{LS_MODIFIER_ALONG_STROKE, "ALONG_STROKE", ICON_MODIFIER, "Along Stroke", ""},
{LS_MODIFIER_CREASE_ANGLE, "CREASE_ANGLE", ICON_MODIFIER, "Crease Angle", ""},
{LS_MODIFIER_CURVATURE_3D, "CURVATURE_3D", ICON_MODIFIER, "Curvature 3D", ""},
@@ -51,7 +51,7 @@ EnumPropertyItem linestyle_color_modifier_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem linestyle_alpha_modifier_type_items[] = {
+EnumPropertyItem rna_enum_linestyle_alpha_modifier_type_items[] = {
{LS_MODIFIER_ALONG_STROKE, "ALONG_STROKE", ICON_MODIFIER, "Along Stroke", ""},
{LS_MODIFIER_CREASE_ANGLE, "CREASE_ANGLE", ICON_MODIFIER, "Crease Angle", ""},
{LS_MODIFIER_CURVATURE_3D, "CURVATURE_3D", ICON_MODIFIER, "Curvature 3D", ""},
@@ -63,7 +63,7 @@ EnumPropertyItem linestyle_alpha_modifier_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem linestyle_thickness_modifier_type_items[] = {
+EnumPropertyItem rna_enum_linestyle_thickness_modifier_type_items[] = {
{LS_MODIFIER_ALONG_STROKE, "ALONG_STROKE", ICON_MODIFIER, "Along Stroke", ""},
{LS_MODIFIER_CALLIGRAPHY, "CALLIGRAPHY", ICON_MODIFIER, "Calligraphy", ""},
{LS_MODIFIER_CREASE_ANGLE, "CREASE_ANGLE", ICON_MODIFIER, "Crease Angle", ""},
@@ -76,7 +76,7 @@ EnumPropertyItem linestyle_thickness_modifier_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem linestyle_geometry_modifier_type_items[] = {
+EnumPropertyItem rna_enum_linestyle_geometry_modifier_type_items[] = {
{LS_MODIFIER_2D_OFFSET, "2D_OFFSET", ICON_MODIFIER, "2D Offset", ""},
{LS_MODIFIER_2D_TRANSFORM, "2D_TRANSFORM", ICON_MODIFIER, "2D Transform", ""},
{LS_MODIFIER_BACKBONE_STRETCHER, "BACKBONE_STRETCHER", ICON_MODIFIER, "Backbone Stretcher", ""},
@@ -513,7 +513,7 @@ static void rna_def_linestyle_mtex(BlenderRNA *brna)
srna = RNA_def_struct(brna, "LineStyleTextureSlot", "TextureSlot");
RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "LineStyle Texture Slot", "Texture slot for textures in a LineStyle datablock");
+ RNA_def_struct_ui_text(srna, "LineStyle Texture Slot", "Texture slot for textures in a LineStyle data-block");
prop = RNA_def_property(srna, "mapping_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "projx");
@@ -574,8 +574,9 @@ static void rna_def_linestyle_mtex(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_LineStyle_update");
}
-static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modifier_type_items,
- const char *set_name_func, const bool blend, const bool color)
+static void rna_def_modifier_type_common(
+ StructRNA *srna, EnumPropertyItem *modifier_type_items,
+ const char *set_name_func, const bool blend, const bool color)
{
PropertyRNA *prop;
@@ -587,8 +588,8 @@ static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modi
{LS_VALUE_MULT, "MULTIPLY", 0, "Multiply", ""},
{LS_VALUE_DIV, "DIVIDE", 0, "Divide", ""},
{LS_VALUE_DIFF, "DIFFERENCE", 0, "Difference", ""},
- {LS_VALUE_MIN, "MININUM", 0, "Minimum", ""},
- {LS_VALUE_MAX, "MAXIMUM", 0, "Maximum", ""},
+ {LS_VALUE_MIN, "MININUM", 0, "Minimum", ""},
+ {LS_VALUE_MAX, "MAXIMUM", 0, "Maximum", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -608,7 +609,7 @@ static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modi
if (blend) {
prop = RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "modifier.blend");
- RNA_def_property_enum_items(prop, (color) ? ramp_blend_items : value_blend_items);
+ RNA_def_property_enum_items(prop, (color) ? rna_enum_ramp_blend_items : value_blend_items);
RNA_def_property_ui_text(prop, "Blend", "Specify how the modifier value is blended into the base value");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
@@ -631,25 +632,25 @@ static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modi
static void rna_def_color_modifier(StructRNA *srna)
{
- rna_def_modifier_type_common(srna, linestyle_color_modifier_type_items,
+ rna_def_modifier_type_common(srna, rna_enum_linestyle_color_modifier_type_items,
"rna_LineStyleColorModifier_name_set", true, true);
}
static void rna_def_alpha_modifier(StructRNA *srna)
{
- rna_def_modifier_type_common(srna, linestyle_alpha_modifier_type_items,
+ rna_def_modifier_type_common(srna, rna_enum_linestyle_alpha_modifier_type_items,
"rna_LineStyleAlphaModifier_name_set", true, false);
}
static void rna_def_thickness_modifier(StructRNA *srna)
{
- rna_def_modifier_type_common(srna, linestyle_thickness_modifier_type_items,
+ rna_def_modifier_type_common(srna, rna_enum_linestyle_thickness_modifier_type_items,
"rna_LineStyleThicknessModifier_name_set", true, false);
}
static void rna_def_geometry_modifier(StructRNA *srna)
{
- rna_def_modifier_type_common(srna, linestyle_geometry_modifier_type_items,
+ rna_def_modifier_type_common(srna, rna_enum_linestyle_geometry_modifier_type_items,
"rna_LineStyleGeometryModifier_name_set", false, false);
}
@@ -1447,7 +1448,7 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ColorModifier", 0, "", "New name for the color modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", linestyle_color_modifier_type_items, 0, "", "Color modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_color_modifier_type_items, 0, "", "Color modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Newly added color modifier");
RNA_def_function_return(func, parm);
@@ -1476,7 +1477,7 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "AlphaModifier", 0, "", "New name for the alpha modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", linestyle_alpha_modifier_type_items, 0, "", "Alpha modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_alpha_modifier_type_items, 0, "", "Alpha modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Newly added alpha modifier");
RNA_def_function_return(func, parm);
@@ -1505,7 +1506,7 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier");
RNA_def_function_return(func, parm);
@@ -1534,7 +1535,7 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier");
RNA_def_function_return(func, parm);
@@ -1890,6 +1891,9 @@ static void rna_def_linestyle(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke length");
RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
+ /* anim */
+ rna_def_animdata_common(srna);
+
/* nodes */
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 348fa3c8302..e0538d1c05b 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -185,12 +185,6 @@ static void rna_Main_screen_begin(CollectionPropertyIterator *iter, PointerRNA *
rna_iterator_listbase_begin(iter, &bmain->screen, NULL);
}
-static void rna_Main_script_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Main *bmain = (Main *)ptr->data;
- rna_iterator_listbase_begin(iter, &bmain->script, NULL);
-}
-
static void rna_Main_font_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Main *bmain = (Main *)ptr->data;
@@ -349,7 +343,6 @@ void RNA_def_main(BlenderRNA *brna)
{"worlds", "World", "rna_Main_world_begin", "Worlds", "World datablocks", RNA_def_main_worlds},
{"groups", "Group", "rna_Main_group_begin", "Groups", "Group datablocks", RNA_def_main_groups},
{"shape_keys", "Key", "rna_Main_key_begin", "Shape Keys", "Shape Key datablocks", NULL},
- {"scripts", "ID", "rna_Main_script_begin", "Scripts", "Script datablocks (DEPRECATED)", NULL},
{"texts", "Text", "rna_Main_text_begin", "Texts", "Text datablocks", RNA_def_main_texts},
{"speakers", "Speaker", "rna_Main_speaker_begin", "Speakers", "Speaker datablocks", RNA_def_main_speakers},
{"sounds", "Sound", "rna_Main_sound_begin", "Sounds", "Sound datablocks", RNA_def_main_sounds},
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index b38f4fa67b6..4b7ce640a56 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -202,7 +202,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
default:
{
const char *idname;
- if (RNA_enum_id_from_value(id_type_items, GS(data->name), &idname) == 0)
+ if (RNA_enum_id_from_value(rna_enum_id_type_items, GS(data->name), &idname) == 0)
idname = "UNKNOWN";
BKE_reportf(reports, RPT_ERROR, "ID type '%s' is not valid for an object", idname);
@@ -218,7 +218,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char
ob->data = data;
test_object_materials(bmain, ob->data);
-
+
return ob;
}
@@ -226,7 +226,7 @@ static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA
{
Object *object = object_ptr->data;
if (ID_REAL_USERS(object) <= 0) {
- BKE_object_unlink(object); /* needed or ID pointers to this are not cleared */
+ BKE_object_unlink(bmain, object); /* needed or ID pointers to this are not cleared */
BKE_libblock_free(bmain, object);
RNA_POINTER_INVALIDATE(object_ptr);
}
@@ -264,7 +264,7 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in
bNodeTreeType *typeinfo = rna_node_tree_type_from_enum(type);
if (typeinfo) {
bNodeTree *ntree = ntreeAddTree(bmain, name, typeinfo->idname);
-
+
id_us_min(&ntree->id);
return ntree;
}
@@ -352,18 +352,24 @@ static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int
id_us_min(&image->id);
return image;
}
-static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char *filepath)
+static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
Image *ima;
errno = 0;
- ima = BKE_image_load(bmain, filepath);
+ if (check_existing) {
+ ima = BKE_image_load_exists(filepath);
+ }
+ else {
+ ima = BKE_image_load(bmain, filepath);
+ }
if (!ima) {
BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unsupported image format"));
}
+ id_us_min((ID *)ima);
return ima;
}
static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr)
@@ -436,17 +442,23 @@ static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerR
}
}
-static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath)
+static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
VFont *font;
-
errno = 0;
- font = BKE_vfont_load(bmain, filepath);
+
+ if (check_existing) {
+ font = BKE_vfont_load_exists(bmain, filepath);
+ }
+ else {
+ font = BKE_vfont_load(bmain, filepath);
+ }
if (!font)
BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unsupported font format"));
+ id_us_min((ID *)font);
return font;
}
@@ -494,6 +506,7 @@ static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA
{
Brush *brush = brush_ptr->data;
if (ID_REAL_USERS(brush) <= 0) {
+ BKE_brush_unlink(bmain, brush);
BKE_libblock_free(bmain, brush);
RNA_POINTER_INVALIDATE(brush_ptr);
}
@@ -529,7 +542,7 @@ static Group *rna_Main_groups_new(Main *bmain, const char *name)
static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr)
{
Group *group = group_ptr->data;
- BKE_group_unlink(group);
+ BKE_group_unlink(bmain, group);
BKE_libblock_free(bmain, group);
RNA_POINTER_INVALIDATE(group_ptr);
}
@@ -553,9 +566,17 @@ static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRN
}
}
-static bSound *rna_Main_sounds_load(Main *bmain, const char *name)
+static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing)
{
- bSound *sound = BKE_sound_new_file(bmain, name);
+ bSound *sound;
+
+ if (check_existing) {
+ sound = BKE_sound_new_file_exists(bmain, name);
+ }
+ else {
+ sound = BKE_sound_new_file(bmain, name);
+ }
+
id_us_min(&sound->id);
return sound;
}
@@ -620,8 +641,7 @@ static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerR
static bAction *rna_Main_actions_new(Main *bmain, const char *name)
{
bAction *act = add_empty_action(bmain, name);
- id_us_min(&act->id);
- act->id.flag &= ~LIB_FAKEUSER;
+ id_fake_user_clear(&act->id);
return act;
}
static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr)
@@ -675,17 +695,24 @@ static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRN
}
}
-static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath)
+static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing)
{
MovieClip *clip;
errno = 0;
- clip = BKE_movieclip_file_add(bmain, filepath);
+
+ if (check_existing) {
+ clip = BKE_movieclip_file_add_exists(bmain, filepath);
+ }
+ else {
+ clip = BKE_movieclip_file_add(bmain, filepath);
+ }
if (!clip)
BKE_reportf(reports, RPT_ERROR, "Cannot read '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to load movie clip"));
+ id_us_min((ID *)clip);
return clip;
}
@@ -745,68 +772,48 @@ static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, Freesty
/* XXX python now has invalid pointer? */
}
-/* tag functions, all the same */
-static void rna_Main_cameras_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->camera, value); }
-static void rna_Main_scenes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->scene, value); }
-static void rna_Main_objects_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->object, value); }
-static void rna_Main_materials_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->mat, value); }
-static void rna_Main_node_groups_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->nodetree, value); }
-static void rna_Main_meshes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->mesh, value); }
-static void rna_Main_lamps_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->lamp, value); }
-static void rna_Main_libraries_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->library, value); }
-static void rna_Main_screens_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->screen, value); }
-static void rna_Main_window_managers_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->wm, value); }
-static void rna_Main_images_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->image, value); }
-static void rna_Main_lattices_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->latt, value); }
-static void rna_Main_curves_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->curve, value); }
-static void rna_Main_metaballs_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->mball, value); }
-static void rna_Main_fonts_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->vfont, value); }
-static void rna_Main_textures_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->tex, value); }
-static void rna_Main_brushes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->brush, value); }
-static void rna_Main_worlds_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->world, value); }
-static void rna_Main_groups_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->group, value); }
-// static void rna_Main_shape_keys_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->key, value); }
-// static void rna_Main_scripts_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->script, value); }
-static void rna_Main_texts_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->text, value); }
-static void rna_Main_speakers_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->speaker, value); }
-static void rna_Main_sounds_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->sound, value); }
-static void rna_Main_armatures_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->armature, value); }
-static void rna_Main_actions_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->action, value); }
-static void rna_Main_particles_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->particle, value); }
-static void rna_Main_palettes_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->palettes, value); }
-static void rna_Main_gpencil_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->gpencil, value); }
-static void rna_Main_movieclips_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->movieclip, value); }
-static void rna_Main_masks_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->mask, value); }
-static void rna_Main_linestyle_tag(Main *bmain, int value) { BKE_main_id_tag_listbase(&bmain->linestyle, value); }
-
-static int rna_Main_cameras_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CA) != 0; }
-static int rna_Main_scenes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SCE) != 0; }
-static int rna_Main_objects_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_OB) != 0; }
-static int rna_Main_materials_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_MA) != 0; }
-static int rna_Main_node_groups_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_NT) != 0; }
-static int rna_Main_meshes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_ME) != 0; }
-static int rna_Main_lamps_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_LA) != 0; }
-static int rna_Main_libraries_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_LI) != 0; }
-static int rna_Main_screens_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SCR) != 0; }
-static int rna_Main_window_managers_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_WM) != 0; }
-static int rna_Main_images_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_IM) != 0; }
-static int rna_Main_lattices_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_LT) != 0; }
-static int rna_Main_curves_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CU) != 0; }
-static int rna_Main_metaballs_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_MB) != 0; }
-static int rna_Main_fonts_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_VF) != 0; }
-static int rna_Main_textures_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_TE) != 0; }
-static int rna_Main_brushes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_BR) != 0; }
-static int rna_Main_worlds_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_WO) != 0; }
-static int rna_Main_groups_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_GR) != 0; }
-static int rna_Main_texts_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_TXT) != 0; }
-static int rna_Main_speakers_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SPK) != 0; }
-static int rna_Main_sounds_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SO) != 0; }
-static int rna_Main_armatures_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_AR) != 0; }
-static int rna_Main_actions_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_AC) != 0; }
-static int rna_Main_particles_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_PA) != 0; }
-static int rna_Main_palettes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_PAL) != 0; }
-static int rna_Main_gpencil_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_GD) != 0; }
-static int rna_Main_linestyle_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_LS) != 0; }
+/* tag and is_updated functions, all the same */
+#define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \
+ static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \
+ BKE_main_id_tag_listbase(&bmain->_listbase_name, LIB_TAG_DOIT, value); \
+ } \
+ static int rna_Main_##_func_name##_is_updated_get(PointerRNA *ptr) { \
+ return DAG_id_type_tagged(ptr->data, _id_type) != 0; \
+ }
+
+RNA_MAIN_ID_TAG_FUNCS_DEF(cameras, camera, ID_CA)
+RNA_MAIN_ID_TAG_FUNCS_DEF(scenes, scene, ID_SCE)
+RNA_MAIN_ID_TAG_FUNCS_DEF(objects, object, ID_OB)
+RNA_MAIN_ID_TAG_FUNCS_DEF(materials, mat, ID_MA)
+RNA_MAIN_ID_TAG_FUNCS_DEF(node_groups, nodetree, ID_NT)
+RNA_MAIN_ID_TAG_FUNCS_DEF(meshes, mesh, ID_ME)
+RNA_MAIN_ID_TAG_FUNCS_DEF(lamps, lamp, ID_LA)
+RNA_MAIN_ID_TAG_FUNCS_DEF(libraries, library, ID_LI)
+RNA_MAIN_ID_TAG_FUNCS_DEF(screens, screen, ID_SCR)
+RNA_MAIN_ID_TAG_FUNCS_DEF(window_managers, wm, ID_WM)
+RNA_MAIN_ID_TAG_FUNCS_DEF(images, image, ID_IM)
+RNA_MAIN_ID_TAG_FUNCS_DEF(lattices, latt, ID_LT)
+RNA_MAIN_ID_TAG_FUNCS_DEF(curves, curve, ID_CU)
+RNA_MAIN_ID_TAG_FUNCS_DEF(metaballs, mball, ID_MB)
+RNA_MAIN_ID_TAG_FUNCS_DEF(fonts, vfont, ID_VF)
+RNA_MAIN_ID_TAG_FUNCS_DEF(textures, tex, ID_TE)
+RNA_MAIN_ID_TAG_FUNCS_DEF(brushes, brush, ID_BR)
+RNA_MAIN_ID_TAG_FUNCS_DEF(worlds, world, ID_WO)
+RNA_MAIN_ID_TAG_FUNCS_DEF(groups, group, ID_GR)
+//RNA_MAIN_ID_TAG_FUNCS_DEF(shape_keys, key, ID_KE)
+RNA_MAIN_ID_TAG_FUNCS_DEF(texts, text, ID_TXT)
+RNA_MAIN_ID_TAG_FUNCS_DEF(speakers, speaker, ID_SPK)
+RNA_MAIN_ID_TAG_FUNCS_DEF(sounds, sound, ID_SO)
+RNA_MAIN_ID_TAG_FUNCS_DEF(armatures, armature, ID_AR)
+RNA_MAIN_ID_TAG_FUNCS_DEF(actions, action, ID_AC)
+RNA_MAIN_ID_TAG_FUNCS_DEF(particles, particle, ID_PA)
+RNA_MAIN_ID_TAG_FUNCS_DEF(palettes, palettes, ID_PAL)
+RNA_MAIN_ID_TAG_FUNCS_DEF(gpencil, gpencil, ID_GD)
+RNA_MAIN_ID_TAG_FUNCS_DEF(movieclips, movieclip, ID_MC)
+RNA_MAIN_ID_TAG_FUNCS_DEF(masks, mask, ID_MSK)
+RNA_MAIN_ID_TAG_FUNCS_DEF(linestyle, linestyle, ID_LS)
+
+#undef RNA_MAIN_ID_TAG_FUNCS_DEF
#else
@@ -841,10 +848,10 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_cameras_new");
RNA_def_function_ui_description(func, "Add a new camera to the main database");
- parm = RNA_def_string(func, "name", "Camera", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Camera", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera datablock");
+ parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove");
@@ -877,10 +884,10 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_scenes_new");
RNA_def_function_ui_description(func, "Add a new scene to the main database");
- parm = RNA_def_string(func, "name", "Scene", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Scene", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "scene", "Scene", "", "New scene datablock");
+ parm = RNA_def_pointer(func, "scene", "Scene", "", "New scene data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_scenes_remove");
@@ -914,13 +921,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_objects_new");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new object to the main database");
- parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "object_data", "ID", "", "Object data or None for an empty object");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "object", "Object", "", "New object datablock");
+ parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_objects_remove");
@@ -953,10 +960,10 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_materials_new");
RNA_def_function_ui_description(func, "Add a new material to the main database");
- parm = RNA_def_string(func, "name", "Material", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Material", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "material", "Material", "", "New material datablock");
+ parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_materials_remove");
@@ -993,13 +1000,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_nodetree_new");
RNA_def_function_ui_description(func, "Add a new node tree to the main database");
- parm = RNA_def_string(func, "name", "NodeGroup", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "NodeGroup", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_enum(func, "type", dummy_items, 0, "Type", "The type of node_group to add");
RNA_def_property_enum_funcs(parm, NULL, NULL, "rna_Main_nodetree_type_itemf");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree datablock");
+ parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove");
@@ -1037,10 +1044,10 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_meshes_new");
RNA_def_function_ui_description(func, "Add a new mesh to the main database");
- parm = RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Mesh", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh datablock");
+ parm = RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "new_from_object", "rna_Main_meshes_new_from_object");
@@ -1089,12 +1096,12 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_lamps_new");
RNA_def_function_ui_description(func, "Add a new lamp to the main database");
- parm = RNA_def_string(func, "name", "Lamp", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Lamp", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", lamp_type_items, 0, "Type", "The type of texture to add");
+ parm = RNA_def_enum(func, "type", rna_enum_lamp_type_items, 0, "Type", "The type of texture to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp datablock");
+ parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove");
@@ -1189,7 +1196,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_images_new");
RNA_def_function_ui_description(func, "Add a new image to the main database");
- parm = RNA_def_string(func, "name", "Image", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Image", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_int(func, "width", 1024, 1, INT_MAX, "", "Width of the image", 1, INT_MAX);
RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -1199,7 +1206,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_boolean(func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color");
RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views");
/* return type */
- parm = RNA_def_pointer(func, "image", "Image", "", "New image datablock");
+ parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "load", "rna_Main_images_load");
@@ -1207,8 +1214,9 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Load a new image into the main database");
parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the file to load");
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
- parm = RNA_def_pointer(func, "image", "Image", "", "New image datablock");
+ parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_images_remove");
@@ -1241,10 +1249,10 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_lattices_new");
RNA_def_function_ui_description(func, "Add a new lattice to the main database");
- parm = RNA_def_string(func, "name", "Lattice", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Lattice", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices datablock");
+ parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove");
@@ -1276,12 +1284,12 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_curves_new");
RNA_def_function_ui_description(func, "Add a new curve to the main database");
- parm = RNA_def_string(func, "name", "Curve", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Curve", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", object_type_curve_items, 0, "Type", "The type of curve to add");
+ parm = RNA_def_enum(func, "type", rna_enum_object_type_curve_items, 0, "Type", "The type of curve to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve datablock");
+ parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_curves_remove");
@@ -1313,10 +1321,10 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_metaballs_new");
RNA_def_function_ui_description(func, "Add a new metaball to the main database");
- parm = RNA_def_string(func, "name", "MetaBall", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "MetaBall", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball datablock");
+ parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove");
@@ -1351,8 +1359,9 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_ui_description(func, "Load a new font into the main database");
parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the font to load");
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
- parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font datablock");
+ parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove");
@@ -1384,12 +1393,12 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_textures_new");
RNA_def_function_ui_description(func, "Add a new texture to the main database");
- parm = RNA_def_string(func, "name", "Texture", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Texture", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", texture_type_items, 0, "Type", "The type of texture to add");
+ parm = RNA_def_enum(func, "type", rna_enum_texture_type_items, 0, "Type", "The type of texture to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture datablock");
+ parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_textures_remove");
@@ -1421,11 +1430,11 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_brushes_new");
RNA_def_function_ui_description(func, "Add a new brush to the main database");
- parm = RNA_def_string(func, "name", "Brush", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Brush", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "mode", object_mode_items, OB_MODE_TEXTURE_PAINT, "", "Paint Mode for the new brush");
+ parm = RNA_def_enum(func, "mode", rna_enum_object_mode_items, OB_MODE_TEXTURE_PAINT, "", "Paint Mode for the new brush");
/* return type */
- parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush datablock");
+ parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove");
@@ -1458,10 +1467,10 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_worlds_new");
RNA_def_function_ui_description(func, "Add a new world to the main database");
- parm = RNA_def_string(func, "name", "World", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "World", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "world", "World", "", "New world datablock");
+ parm = RNA_def_pointer(func, "world", "World", "", "New world data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove");
@@ -1494,10 +1503,10 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_groups_new");
RNA_def_function_ui_description(func, "Add a new group to the main database");
- parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "group", "Group", "", "New group datablock");
+ parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_groups_remove");
@@ -1529,10 +1538,10 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_speakers_new");
RNA_def_function_ui_description(func, "Add a new speaker to the main database");
- parm = RNA_def_string(func, "name", "Speaker", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Speaker", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker datablock");
+ parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove");
@@ -1565,10 +1574,10 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_texts_new");
RNA_def_function_ui_description(func, "Add a new text to the main database");
- parm = RNA_def_string(func, "name", "Text", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Text", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "text", "Text", "", "New text datablock");
+ parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_texts_remove");
@@ -1581,11 +1590,11 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "load", "rna_Main_texts_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new text to the main database from a file");
- parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the datablock");
+ parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_boolean(func, "internal", 0, "Make internal", "Make text file internal after loading");
/* return type */
- parm = RNA_def_pointer(func, "text", "Text", "", "New text datablock");
+ parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "tag", "rna_Main_texts_tag");
@@ -1612,10 +1621,11 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop)
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_sounds_load");
RNA_def_function_ui_description(func, "Add a new sound to the main database from a file");
- parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the datablock");
+ parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
- parm = RNA_def_pointer(func, "sound", "Sound", "", "New text datablock");
+ parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove");
@@ -1648,10 +1658,10 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_armatures_new");
RNA_def_function_ui_description(func, "Add a new armature to the main database");
- parm = RNA_def_string(func, "name", "Armature", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Armature", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature datablock");
+ parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove");
@@ -1683,10 +1693,10 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_actions_new");
RNA_def_function_ui_description(func, "Add a new action to the main database");
- parm = RNA_def_string(func, "name", "Action", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Action", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "action", "Action", "", "New action datablock");
+ parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_actions_remove");
@@ -1718,10 +1728,10 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_particles_new");
RNA_def_function_ui_description(func, "Add a new particle settings instance to the main database");
- parm = RNA_def_string(func, "name", "ParticleSettings", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "ParticleSettings", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings datablock");
+ parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_particles_remove");
@@ -1753,10 +1763,10 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_palettes_new");
RNA_def_function_ui_description(func, "Add a new palette to the main database");
- parm = RNA_def_string(func, "name", "Palette", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "Palette", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette datablock");
+ parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove");
@@ -1792,10 +1802,10 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "gpencil_data_addnew");
RNA_def_function_flag(func, FUNC_NO_SELF);
- parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil datablock");
+ parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove");
@@ -1815,6 +1825,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
+ PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataMovieClips");
srna = RNA_def_struct(brna, "BlendDataMovieClips", NULL);
@@ -1834,12 +1845,20 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop)
/* load func */
func = RNA_def_function(srna, "load", "rna_Main_movieclip_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Add a new movie clip to the main database from a file");
- parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the datablock");
+ RNA_def_function_ui_description(
+ func, "Add a new movie clip to the main database from a file "
+ "(while ``check_existing`` is disabled for consistency with other load functions, "
+ "behavior with multiple movie-clips using the same file may incorrectly generate proxies)");
+ parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded");
/* return type */
- parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip datablock");
+ parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip data-block");
RNA_def_function_return(func, parm);
+
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_movieclips_is_updated_get", NULL);
}
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1847,6 +1866,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
+ PropertyRNA *prop;
RNA_def_property_srna(cprop, "BlendDataMasks");
srna = RNA_def_struct(brna, "BlendDataMasks", NULL);
@@ -1860,9 +1880,9 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
/* new func */
func = RNA_def_function(srna, "new", "rna_Main_mask_new");
RNA_def_function_ui_description(func, "Add a new mask with a given name to the main database");
- RNA_def_string_file_path(func, "name", NULL, MAX_ID_NAME - 2, "Mask", "Name of new mask datablock");
+ RNA_def_string_file_path(func, "name", NULL, MAX_ID_NAME - 2, "Mask", "Name of new mask data-block");
/* return type */
- parm = RNA_def_pointer(func, "mask", "Mask", "", "New mask datablock");
+ parm = RNA_def_pointer(func, "mask", "Mask", "", "New mask data-block");
RNA_def_function_return(func, parm);
/* remove func */
@@ -1871,6 +1891,10 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
+ prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Main_masks_is_updated_get", NULL);
}
void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
@@ -1891,10 +1915,10 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Main_linestyles_new");
RNA_def_function_ui_description(func, "Add a new line style instance to the main database");
- parm = RNA_def_string(func, "name", "FreestyleLineStyle", 0, "", "New name for the datablock");
+ parm = RNA_def_string(func, "name", "FreestyleLineStyle", 0, "", "New name for the data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
- parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style datablock");
+ parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove");
diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c
index 1a8cea143a1..a23d4444861 100644
--- a/source/blender/makesrna/intern/rna_mask.c
+++ b/source/blender/makesrna/intern/rna_mask.c
@@ -974,7 +974,7 @@ static void rna_def_mask_layer(BlenderRNA *brna)
prop = RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "falloff");
- RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_property_update(prop, NC_MASK | NA_EDITED, NULL);
@@ -1037,7 +1037,7 @@ static void rna_def_mask(BlenderRNA *brna)
rna_def_mask_layer(brna);
srna = RNA_def_struct(brna, "Mask", "ID");
- RNA_def_struct_ui_text(srna, "Mask", "Mask datablock defining mask for compositing");
+ RNA_def_struct_ui_text(srna, "Mask", "Mask data-block defining mask for compositing");
RNA_def_struct_ui_icon(srna, ICON_MOD_MASK);
/* mask layers */
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index a1fa6ab13be..e4f9f856db7 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -54,7 +54,7 @@ static EnumPropertyItem prop_texture_coordinates_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem ramp_blend_items[] = {
+EnumPropertyItem rna_enum_ramp_blend_items[] = {
{MA_RAMP_BLEND, "MIX", 0, "Mix", ""},
{MA_RAMP_ADD, "ADD", 0, "Add", ""},
{MA_RAMP_MULT, "MULTIPLY", 0, "Multiply", ""},
@@ -237,7 +237,7 @@ static int rna_Material_active_texture_editable(PointerRNA *ptr)
{
Material *ma = (Material *)ptr->id.data;
- return has_current_material_texture(ma);
+ return has_current_material_texture(ma) ? PROP_EDITABLE : 0;
}
static PointerRNA rna_Material_active_node_material_get(PointerRNA *ptr)
@@ -501,7 +501,7 @@ static void rna_def_material_mtex(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialTextureSlot", "TextureSlot");
RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "Material Texture Slot", "Texture slot for textures in a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Texture Slot", "Texture slot for textures in a Material data-block");
prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "texco");
@@ -853,7 +853,7 @@ static void rna_def_material_gamesettings(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialGameSettings", NULL);
RNA_def_struct_sdna(srna, "GameSettings");
RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Game Settings", "Game Engine settings for a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Game Settings", "Game Engine settings for a Material data-block");
prop = RNA_def_property(srna, "use_backface_culling", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GEMAT_BACKCULL); /* use bitflags */
@@ -953,13 +953,13 @@ static void rna_def_material_colors(StructRNA *srna)
prop = RNA_def_property(srna, "diffuse_ramp_blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "rampblend_col");
- RNA_def_property_enum_items(prop, ramp_blend_items);
+ RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
RNA_def_property_ui_text(prop, "Diffuse Ramp Blend", "Blending method of the ramp and the diffuse color");
RNA_def_property_update(prop, 0, "rna_Material_update");
prop = RNA_def_property(srna, "specular_ramp_blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "rampblend_spec");
- RNA_def_property_enum_items(prop, ramp_blend_items);
+ RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
RNA_def_property_ui_text(prop, "Specular Ramp Blend", "Blending method of the ramp and the specular color");
RNA_def_property_update(prop, 0, "rna_Material_update");
@@ -1076,7 +1076,7 @@ static void rna_def_material_raymirror(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialRaytraceMirror", NULL);
RNA_def_struct_sdna(srna, "Material");
RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Raytrace Mirror", "Raytraced reflection settings for a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Raytrace Mirror", "Raytraced reflection settings for a Material data-block");
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_RAYMIRROR); /* use bitflags */
@@ -1162,7 +1162,7 @@ static void rna_def_material_raytra(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "Material");
RNA_def_struct_nested(brna, srna, "Material");
RNA_def_struct_ui_text(srna, "Material Raytrace Transparency",
- "Raytraced refraction settings for a Material datablock");
+ "Raytraced refraction settings for a Material data-block");
prop = RNA_def_property(srna, "ior", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ang");
@@ -1256,7 +1256,7 @@ static void rna_def_material_volume(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialVolume", NULL);
RNA_def_struct_sdna(srna, "VolumeSettings");
RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Volume", "Volume rendering settings for a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Volume", "Volume rendering settings for a Material data-block");
prop = RNA_def_property(srna, "step_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "stepsize_type");
@@ -1399,7 +1399,7 @@ static void rna_def_material_halo(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialHalo", NULL);
RNA_def_struct_sdna(srna, "Material");
RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Halo", "Halo particle effect settings for a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Halo", "Halo particle effect settings for a Material data-block");
prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "hasize");
@@ -1528,7 +1528,7 @@ static void rna_def_material_sss(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "Material");
RNA_def_struct_nested(brna, srna, "Material");
RNA_def_struct_ui_text(srna, "Material Subsurface Scattering",
- "Diffuse subsurface scattering settings for a Material datablock");
+ "Diffuse subsurface scattering settings for a Material data-block");
prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_COLOR | PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "sss_radius");
@@ -1659,7 +1659,7 @@ static void rna_def_material_strand(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialStrand", NULL);
RNA_def_struct_sdna(srna, "Material");
RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Strand", "Strand settings for a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Strand", "Strand settings for a Material data-block");
prop = RNA_def_property(srna, "use_tangent_shading", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TANGENT_STR);
@@ -1730,7 +1730,7 @@ static void rna_def_material_physics(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MaterialPhysics", NULL);
RNA_def_struct_sdna(srna, "Material");
RNA_def_struct_nested(brna, srna, "Material");
- RNA_def_struct_ui_text(srna, "Material Physics", "Physics settings for a Material datablock");
+ RNA_def_struct_ui_text(srna, "Material Physics", "Physics settings for a Material data-block");
prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "friction");
@@ -1806,7 +1806,7 @@ void RNA_def_material(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Material", "ID");
RNA_def_struct_ui_text(srna, "Material",
- "Material datablock to define the appearance of geometric objects for rendering");
+ "Material data-block to define the appearance of geometric objects for rendering");
RNA_def_struct_ui_icon(srna, ICON_MATERIAL_DATA);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index ec64aa38275..1d734864833 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -51,7 +51,7 @@
#include "WM_types.h"
-EnumPropertyItem mesh_delimit_mode_items[] = {
+EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = {
{BMO_DELIM_NORMAL, "NORMAL", 0, "Normal", "Delimit by face directions"},
{BMO_DELIM_MATERIAL, "MATERIAL", 0, "Material", "Delimit by face material"},
{BMO_DELIM_SEAM, "SEAM", 0, "Seam", "Delimit by edge seams"},
@@ -418,6 +418,14 @@ static float rna_MeshPolygon_area_get(PointerRNA *ptr)
return BKE_mesh_calc_poly_area(mp, me->mloop + mp->loopstart, me->mvert);
}
+static void rna_MeshPolygon_flip(ID *id, MPoly *mp)
+{
+ Mesh *me = (Mesh *)id;
+
+ BKE_mesh_polygon_flip(mp, me->mloop, &me->ldata);
+ BKE_mesh_tessface_clear(me);
+}
+
static void rna_MeshTessFace_normal_get(PointerRNA *ptr, float *values)
{
Mesh *me = rna_mesh(ptr);
@@ -1885,7 +1893,7 @@ static void rna_def_mvert(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MeshVertex", NULL);
RNA_def_struct_sdna(srna, "MVert");
- RNA_def_struct_ui_text(srna, "Mesh Vertex", "Vertex in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh Vertex", "Vertex in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshVertex_path");
RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
@@ -1942,7 +1950,7 @@ static void rna_def_medge(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MeshEdge", NULL);
RNA_def_struct_sdna(srna, "MEdge");
- RNA_def_struct_ui_text(srna, "Mesh Edge", "Edge in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh Edge", "Edge in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshEdge_path");
RNA_def_struct_ui_icon(srna, ICON_EDGESEL);
@@ -2005,7 +2013,7 @@ static void rna_def_mface(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MeshTessFace", NULL);
RNA_def_struct_sdna(srna, "MFace");
- RNA_def_struct_ui_text(srna, "Mesh TessFace", "TessFace in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh TessFace", "TessFace in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshTessFace_path");
RNA_def_struct_ui_icon(srna, ICON_FACESEL);
@@ -2082,7 +2090,7 @@ static void rna_def_mloop(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MeshLoop", NULL);
RNA_def_struct_sdna(srna, "MLoop");
- RNA_def_struct_ui_text(srna, "Mesh Loop", "Loop in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh Loop", "Loop in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshLoop_path");
RNA_def_struct_ui_icon(srna, ICON_EDGESEL);
@@ -2138,10 +2146,11 @@ static void rna_def_mpolygon(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
srna = RNA_def_struct(brna, "MeshPolygon", NULL);
RNA_def_struct_sdna(srna, "MPoly");
- RNA_def_struct_ui_text(srna, "Mesh Polygon", "Polygon in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh Polygon", "Polygon in a Mesh data-block");
RNA_def_struct_path_func(srna, "rna_MeshPolygon_path");
RNA_def_struct_ui_icon(srna, ICON_FACESEL);
@@ -2216,6 +2225,11 @@ static void rna_def_mpolygon(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_int_funcs(prop, "rna_MeshPolygon_index_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Index", "Index of this polygon");
+
+ func = RNA_def_function(srna, "flip", "rna_MeshPolygon_flip");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ RNA_def_function_ui_description(func, "Invert winding of this polygon (flip its normal)");
+
}
/* mesh.loop_uvs */
@@ -2267,7 +2281,7 @@ static void rna_def_mtface(BlenderRNA *brna)
const int uv_dim[] = {4, 2};
srna = RNA_def_struct(brna, "MeshTextureFaceLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh data-block");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshTextureFaceLayer_path");
RNA_def_struct_ui_icon(srna, ICON_GROUP_UVS);
@@ -2379,7 +2393,7 @@ static void rna_def_mtexpoly(BlenderRNA *brna)
#endif
srna = RNA_def_struct(brna, "MeshTexturePolyLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh UV Map", "UV map with assigned image textures in a Mesh data-block");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshTexturePolyLayer_path");
RNA_def_struct_ui_icon(srna, ICON_GROUP_UVS);
@@ -2454,7 +2468,7 @@ static void rna_def_mcol(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshColorLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh Vertex Color Layer", "Layer of vertex colors in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh Vertex Color Layer", "Layer of vertex colors in a Mesh data-block");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshColorLayer_path");
RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL);
@@ -2524,7 +2538,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "MeshLoopColorLayer", NULL);
- RNA_def_struct_ui_text(srna, "Mesh Vertex Color Layer", "Layer of vertex colors in a Mesh datablock");
+ RNA_def_struct_ui_text(srna, "Mesh Vertex Color Layer", "Layer of vertex colors in a Mesh data-block");
RNA_def_struct_sdna(srna, "CustomDataLayer");
RNA_def_struct_path_func(srna, "rna_MeshLoopColorLayer_path");
RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL);
@@ -3241,7 +3255,7 @@ static void rna_def_mesh(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Mesh", "ID");
- RNA_def_struct_ui_text(srna, "Mesh", "Mesh datablock defining geometric surfaces");
+ RNA_def_struct_ui_text(srna, "Mesh", "Mesh data-block defining geometric surfaces");
RNA_def_struct_ui_icon(srna, ICON_MESH_DATA);
prop = RNA_def_property(srna, "vertices", PROP_COLLECTION, PROP_NONE);
@@ -3460,7 +3474,6 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "smoothresh");
RNA_def_property_float_default(prop, DEG2RADF(180.0f));
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
- RNA_def_property_ui_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f), 1.0, 1);
RNA_def_property_ui_text(prop, "Auto Smooth Angle",
"Maximum angle between face normals that will be considered as smooth "
"(unused if custom split normals data are available)");
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index 632b07c19ce..a3bc21b0170 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -136,8 +136,9 @@ static void rna_Mesh_normals_split_custom_do(Mesh *mesh, float (*custom_loopnors
}
else {
polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
- polynors, false);
+ BKE_mesh_calc_normals_poly(
+ mesh->mvert, NULL, mesh->totvert,
+ mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, polynors, false);
free_polynors = true;
}
@@ -199,6 +200,15 @@ static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
DAG_id_tag_update(&mesh->id, 0);
}
+static void rna_Mesh_flip_normals(Mesh *mesh)
+{
+ BKE_mesh_polygons_flip(mesh->mpoly, mesh->mloop, &mesh->ldata, mesh->totpoly);
+ BKE_mesh_tessface_clear(mesh);
+ BKE_mesh_calc_normals(mesh);
+
+ DAG_id_tag_update(&mesh->id, 0);
+}
+
#else
void RNA_api_mesh(StructRNA *srna)
@@ -208,11 +218,16 @@ void RNA_api_mesh(StructRNA *srna)
const int normals_array_dim[] = {1, 3};
func = RNA_def_function(srna, "transform", "rna_Mesh_transform");
- RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix");
+ RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix "
+ "(Warning: inverts normals if matrix is negative)");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
+ func = RNA_def_function(srna, "flip_normals", "rna_Mesh_flip_normals");
+ RNA_def_function_ui_description(func, "Invert winding of all polygons "
+ "(clears tessellation, does not handle custom normals)");
+
func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals");
RNA_def_function_ui_description(func, "Calculate vertex normals");
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index 5f4a7706c0e..d3b66e4c3b4 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -189,13 +189,13 @@ static void rna_def_metaelement(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MetaElement", NULL);
RNA_def_struct_sdna(srna, "MetaElem");
- RNA_def_struct_ui_text(srna, "Meta Element", "Blobby element in a Metaball datablock");
+ RNA_def_struct_ui_text(srna, "Meta Element", "Blobby element in a Metaball data-block");
RNA_def_struct_path_func(srna, "rna_MetaElement_path");
RNA_def_struct_ui_icon(srna, ICON_OUTLINER_DATA_META);
/* enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, metaelem_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_metaelem_type_items);
RNA_def_property_ui_text(prop, "Type", "Metaball types");
RNA_def_property_update(prop, 0, "rna_MetaBall_update_data");
@@ -272,7 +272,7 @@ static void rna_def_metaball_elements(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_MetaBall_elements_new");
RNA_def_function_ui_description(func, "Add a new element to the metaball");
- RNA_def_enum(func, "type", metaelem_type_items, MB_BALL, "", "type for the new meta-element");
+ RNA_def_enum(func, "type", rna_enum_metaelem_type_items, MB_BALL, "", "type for the new meta-element");
parm = RNA_def_pointer(func, "element", "MetaElement", "", "The newly created meta-element");
RNA_def_function_return(func, parm);
@@ -304,7 +304,7 @@ static void rna_def_metaball(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "MetaBall", "ID");
- RNA_def_struct_ui_text(srna, "MetaBall", "Metaball datablock to defined blobby surfaces");
+ RNA_def_struct_ui_text(srna, "MetaBall", "Metaball data-block to defined blobby surfaces");
RNA_def_struct_ui_icon(srna, ICON_META_DATA);
prop = RNA_def_property(srna, "elements", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 27c4bf0e985..0c4b3ba485d 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -61,7 +61,7 @@
#include "WM_api.h"
#include "WM_types.h"
-EnumPropertyItem modifier_type_items[] = {
+EnumPropertyItem rna_enum_object_modifier_type_items[] = {
{0, "", 0, N_("Modify"), ""},
{eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
@@ -120,7 +120,7 @@ EnumPropertyItem modifier_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem modifier_triangulate_quad_method_items[] = {
+EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[] = {
{MOD_TRIANGULATE_QUAD_BEAUTY, "BEAUTY", 0, "Beauty ", "Split the quads in nice triangles, slower method"},
{MOD_TRIANGULATE_QUAD_FIXED, "FIXED", 0, "Fixed", "Split the quads on the first and third vertices"},
{MOD_TRIANGULATE_QUAD_ALTERNATE, "FIXED_ALTERNATE", 0, "Fixed Alternate",
@@ -130,7 +130,7 @@ EnumPropertyItem modifier_triangulate_quad_method_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem modifier_triangulate_ngon_method_items[] = {
+EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[] = {
{MOD_TRIANGULATE_NGON_BEAUTY, "BEAUTY", 0, "Beauty", "Arrange the new triangles evenly (slow)"},
{MOD_TRIANGULATE_NGON_EARCLIP, "CLIP", 0, "Clip", "Split the polygons with an ear clipping algorithm"},
{0, NULL, 0, NULL, NULL}
@@ -154,7 +154,7 @@ static EnumPropertyItem modifier_warp_falloff_items[] = {
/* ***** Data Transfer ***** */
-EnumPropertyItem DT_method_vertex_items[] = {
+EnumPropertyItem rna_enum_dt_method_vertex_items[] = {
{MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology",
"Copy from identical topology meshes"},
{MREMAP_MODE_VERT_NEAREST, "NEAREST", 0, "Nearest vertex",
@@ -172,11 +172,11 @@ EnumPropertyItem DT_method_vertex_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem DT_method_edge_items[] = {
+EnumPropertyItem rna_enum_dt_method_edge_items[] = {
{MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology",
"Copy from identical topology meshes"},
{MREMAP_MODE_EDGE_VERT_NEAREST, "VERT_NEAREST", 0, "Nearest Vertices",
- "Copy from most similar edge (edge which vertices are the closest of destination edge’s ones)"},
+ "Copy from most similar edge (edge which vertices are the closest of destination edge's ones)"},
{MREMAP_MODE_EDGE_NEAREST, "NEAREST", 0, "Nearest Edge",
"Copy from closest edge (using midpoints)"},
{MREMAP_MODE_EDGE_POLY_NEAREST, "POLY_NEAREST", 0, "Nearest Face Edge",
@@ -186,7 +186,7 @@ EnumPropertyItem DT_method_edge_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem DT_method_loop_items[] = {
+EnumPropertyItem rna_enum_dt_method_loop_items[] = {
{MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology",
"Copy from identical topology meshes"},
{MREMAP_MODE_LOOP_NEAREST_LOOPNOR, "NEAREST_NORMAL", 0, "Nearest Corner And Best Matching Normal",
@@ -202,7 +202,7 @@ EnumPropertyItem DT_method_loop_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem DT_method_poly_items[] = {
+EnumPropertyItem rna_enum_dt_method_poly_items[] = {
{MREMAP_MODE_TOPOLOGY, "TOPOLOGY", 0, "Topology",
"Copy from identical topology meshes"},
{MREMAP_MODE_POLY_NEAREST, "NEAREST", 0, "Nearest Face",
@@ -214,7 +214,7 @@ EnumPropertyItem DT_method_poly_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem DT_mix_mode_items[] = {
+EnumPropertyItem rna_enum_dt_mix_mode_items[] = {
{CDT_MIX_TRANSFER, "REPLACE", 0, "Replace",
"Overwrite all elements' data"},
{CDT_MIX_REPLACE_ABOVE_THRESHOLD, "ABOVE_THRESHOLD", 0, "Above Threshold",
@@ -233,7 +233,7 @@ EnumPropertyItem DT_mix_mode_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem DT_layers_select_src_items[] = {
+EnumPropertyItem rna_enum_dt_layers_select_src_items[] = {
{DT_LAYERS_ACTIVE_SRC, "ACTIVE", 0, "Active Layer",
"Only transfer active data layer"},
{DT_LAYERS_ALL_SRC, "ALL", 0, "All Layers",
@@ -245,7 +245,7 @@ EnumPropertyItem DT_layers_select_src_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem DT_layers_select_dst_items[] = {
+EnumPropertyItem rna_enum_dt_layers_select_dst_items[] = {
{DT_LAYERS_ACTIVE_DST, "ACTIVE", 0, "Active Layer",
"Affect active data layer of all targets"},
{DT_LAYERS_NAME_DST, "NAME", 0, "By Name",
@@ -255,6 +255,25 @@ EnumPropertyItem DT_layers_select_dst_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_axis_xy_items[] = {
+ {0, "X", 0, "X", ""},
+ {1, "Y", 0, "Y", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem rna_enum_axis_xyz_items[] = {
+ {0, "X", 0, "X", ""},
+ {1, "Y", 0, "Y", ""},
+ {2, "Z", 0, "Z", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem rna_enum_axis_flag_xyz_items[] = {
+ {(1 << 0), "X", 0, "X", ""},
+ {(1 << 1), "Y", 0, "Y", ""},
+ {(1 << 2), "Z", 0, "Z", ""},
+ {0, NULL, 0, NULL, NULL}
+};
#ifdef RNA_RUNTIME
@@ -549,9 +568,11 @@ RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH);
static void rna_HookModifier_object_set(PointerRNA *ptr, PointerRNA value)
{
HookModifierData *hmd = ptr->data;
+ Object *ob = (Object *)value.data;
- hmd->object = (Object *)value.data;
- BKE_object_modifier_hook_reset((Object *)ptr->id.data, hmd);
+ hmd->object = ob;
+ id_lib_extern((ID *)ob);
+ BKE_object_modifier_hook_reset(ob, hmd);
}
static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr)
@@ -562,8 +583,10 @@ static PointerRNA rna_UVProjector_object_get(PointerRNA *ptr)
static void rna_UVProjector_object_set(PointerRNA *ptr, PointerRNA value)
{
- Object **ob = (Object **)ptr->data;
- *ob = value.data;
+ Object **ob_p = (Object **)ptr->data;
+ Object *ob = (Object *)value.data;
+ id_lib_extern((ID *)ob);
+ *ob_p = ob;
}
#undef RNA_MOD_OBJECT_SET
@@ -821,6 +844,38 @@ static void rna_DataTransferModifier_data_types_update(Main *bmain, Scene *scene
rna_Modifier_update(bmain, scene, ptr);
}
+static void rna_DataTransferModifier_verts_data_types_set(struct PointerRNA *ptr, int value)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data;
+
+ dtmd->data_types &= ~DT_TYPE_VERT_ALL;
+ dtmd->data_types |= value;
+}
+
+static void rna_DataTransferModifier_edges_data_types_set(struct PointerRNA *ptr, int value)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data;
+
+ dtmd->data_types &= ~DT_TYPE_EDGE_ALL;
+ dtmd->data_types |= value;
+}
+
+static void rna_DataTransferModifier_loops_data_types_set(struct PointerRNA *ptr, int value)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data;
+
+ dtmd->data_types &= ~DT_TYPE_LOOP_ALL;
+ dtmd->data_types |= value;
+}
+
+static void rna_DataTransferModifier_polys_data_types_set(struct PointerRNA *ptr, int value)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data;
+
+ dtmd->data_types &= ~DT_TYPE_POLY_ALL;
+ dtmd->data_types |= value;
+}
+
static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *)ptr->data;
@@ -828,19 +883,19 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(bConte
int totitem = 0;
if (!C) { /* needed for docs and i18n tools */
- return DT_layers_select_src_items;
+ return rna_enum_dt_layers_select_src_items;
}
/* No active here! */
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_ALL_SRC);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC);
if (STREQ(RNA_property_identifier(prop), "layers_vgroup_select_src")) {
Object *ob_src = dtmd->ob_source;
#if 0 /* XXX Don't think we want this in modifier version... */
if (BKE_object_pose_armature_get(ob_src)) {
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_SELECT);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_src_items, DT_LAYERS_VGROUP_SRC_BONE_DEFORM);
}
#endif
@@ -918,12 +973,12 @@ static EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(bConte
int totitem = 0;
if (!C) { /* needed for docs and i18n tools */
- return DT_layers_select_dst_items;
+ return rna_enum_dt_layers_select_dst_items;
}
/* No active here! */
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_NAME_DST);
- RNA_enum_items_add_value(&item, &totitem, DT_layers_select_dst_items, DT_LAYERS_INDEX_DST);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_layers_select_dst_items, DT_LAYERS_INDEX_DST);
if (STREQ(RNA_property_identifier(prop), "layers_vgroup_select_dst")) {
/* Only list destination layers if we have a single source! */
@@ -1012,24 +1067,24 @@ static EnumPropertyItem *rna_DataTransferModifier_mix_mode_itemf(bContext *C, Po
bool support_advanced_mixing, support_threshold;
if (!C) { /* needed for docs and i18n tools */
- return DT_mix_mode_items;
+ return rna_enum_dt_mix_mode_items;
}
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_TRANSFER);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER);
BKE_object_data_transfer_get_dttypes_capacity(dtmd->data_types, &support_advanced_mixing, &support_threshold);
if (support_threshold) {
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_ABOVE_THRESHOLD);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_REPLACE_BELOW_THRESHOLD);
}
if (support_advanced_mixing) {
RNA_enum_item_add_separator(&item, &totitem);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MIX);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_ADD);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_SUB);
- RNA_enum_items_add_value(&item, &totitem, DT_mix_mode_items, CDT_MIX_MUL);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MIX);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_ADD);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_SUB);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_dt_mix_mode_items, CDT_MIX_MUL);
}
RNA_enum_item_end(&item, &totitem);
@@ -1514,6 +1569,17 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Triangulate", "Keep triangulated faces resulting from decimation (collapse only)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_symmetry", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_DECIM_FLAG_SYMMETRY);
+ RNA_def_property_ui_text(prop, "Symmetry", "Maintain symmetry on an axis");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "symmetry_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "symmetry_axis");
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
+ RNA_def_property_ui_text(prop, "Axis", "Axis of symmetry");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "vertex_group_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "defgrp_factor");
RNA_def_property_range(prop, 0, 1000);
@@ -1530,7 +1596,7 @@ static void rna_def_modifier_decimate(BlenderRNA *brna)
prop = RNA_def_property(srna, "delimit", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_FLAG); /* important to run before default set */
- RNA_def_property_enum_items(prop, mesh_delimit_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_mesh_delimit_mode_items);
RNA_def_property_ui_text(prop, "Delimit", "Limit merging geometry");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -1836,6 +1902,36 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_enum_items(prop, prop_operation_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+#if 0 /* WITH_MOD_BOOLEAN */
+ /* BMesh intersection options */
+ prop = RNA_def_property(srna, "use_bmesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_Enabled);
+ RNA_def_property_ui_text(prop, "Use BMesh", "Use BMesh boolean calculation");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_bmesh_separate", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_Separate);
+ RNA_def_property_ui_text(prop, "Separate", "Keep edges separate");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_bmesh_dissolve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoDissolve);
+ RNA_def_property_ui_text(prop, "Dissolve", "Dissolve verts created from tessellated intersection");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_bmesh_connect_regions", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoConnectRegions);
+ RNA_def_property_ui_text(prop, "Calculate Holes", "Connect regions (needed for hole filling)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "threshold");
+ RNA_def_property_range(prop, 0, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1, 1, 7);
+ RNA_def_property_ui_text(prop, "Threshold", "");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+#endif
}
static void rna_def_modifier_array(BlenderRNA *brna)
@@ -2469,13 +2565,6 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem particleinstance_axis[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {2, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "ParticleInstanceModifier", "Modifier");
RNA_def_struct_ui_text(srna, "ParticleInstance Modifier", "Particle system instancing modifier");
RNA_def_struct_sdna(srna, "ParticleInstanceModifierData");
@@ -2496,7 +2585,7 @@ static void rna_def_modifier_particleinstance(BlenderRNA *brna)
prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "axis");
- RNA_def_property_enum_items(prop, particleinstance_axis);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Axis", "Pole axis for rotation");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -2709,7 +2798,7 @@ static void rna_def_modifier_dynamic_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "ui_type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_dynamicpaint_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_prop_dynamicpaint_type_items);
RNA_def_property_ui_text(prop, "Type", "");
}
@@ -2954,6 +3043,11 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE);
RNA_def_property_ui_text(prop, "Keep Above Surface", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_fluidsim(BlenderRNA *brna)
@@ -3080,6 +3174,11 @@ static void rna_def_modifier_simpledeform(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "axis", MOD_SIMPLEDEFORM_LOCK_AXIS_Y);
RNA_def_property_ui_text(prop, "Lock Y Axis", "Do not allow deformation along the Y axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_surface(BlenderRNA *brna)
@@ -3209,13 +3308,6 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
static void rna_def_modifier_screw(BlenderRNA *brna)
{
- static EnumPropertyItem axis_items[] = {
- {0, "X", 0, "X Axis", ""},
- {1, "Y", 0, "Y Axis", ""},
- {2, "Z", 0, "Z Axis", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
StructRNA *srna;
PropertyRNA *prop;
@@ -3250,7 +3342,7 @@ static void rna_def_modifier_screw(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Axis", "Screw axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -3308,13 +3400,6 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem uvwarp_axis[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {2, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "UVWarpModifier", "Modifier");
RNA_def_struct_ui_text(srna, "UVWarp Modifier", "Add target position to uv coordinates");
RNA_def_struct_sdna(srna, "UVWarpModifierData");
@@ -3322,13 +3407,13 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
prop = RNA_def_property(srna, "axis_u", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "axis_u");
- RNA_def_property_enum_items(prop, uvwarp_axis);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "U-Axis", "Pole axis for rotation");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "axis_v", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "axis_v");
- RNA_def_property_enum_items(prop, uvwarp_axis);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "V-Axis", "Pole axis for rotation");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -3979,13 +4064,13 @@ static void rna_def_modifier_triangulate(BlenderRNA *brna)
prop = RNA_def_property(srna, "quad_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "quad_method");
- RNA_def_property_enum_items(prop, modifier_triangulate_quad_method_items);
+ RNA_def_property_enum_items(prop, rna_enum_modifier_triangulate_quad_method_items);
RNA_def_property_ui_text(prop, "Quad Method", "Method for splitting the quads into triangles");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "ngon_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "ngon_method");
- RNA_def_property_enum_items(prop, modifier_triangulate_ngon_method_items);
+ RNA_def_property_enum_items(prop, rna_enum_modifier_triangulate_ngon_method_items);
RNA_def_property_ui_text(prop, "Polygon Method", "Method for splitting the polygons into triangles");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
@@ -4031,13 +4116,6 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem prop_flip_axis_flag_items[] = {
- {(1 << 0), "X", 0, "X", ""},
- {(1 << 1), "Y", 0, "Y", ""},
- {(1 << 2), "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
StructRNA *srna;
PropertyRNA *prop;
@@ -4090,19 +4168,19 @@ static void rna_def_modifier_meshcache(BlenderRNA *brna)
/* Axis Conversion */
prop = RNA_def_property(srna, "forward_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "forward_axis");
- RNA_def_property_enum_items(prop, object_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Forward", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "up_axis");
- RNA_def_property_enum_items(prop, object_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Up", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "flip_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "flip_axis");
- RNA_def_property_enum_items(prop, prop_flip_axis_flag_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_flag_xyz_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Flip Axis", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4262,22 +4340,16 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem DT_layer_vert_items[] = {
+ {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"},
+#if 0 /* TODO */
+ {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"},
+#endif
#if 0 /* XXX When SkinModifier is enabled, it seems to erase its own CD_MVERT_SKIN layer from final DM :( */
{DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"},
#endif
{DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"},
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem DT_layer_vert_vgroup_items[] = {
- {DT_TYPE_MDEFORMVERT, "VGROUP_WEIGHTS", 0, "Vertex Group(s)", "Transfer active or all vertex groups"},
- {0, NULL, 0, NULL, NULL}
- };
-#if 0 /* XXX For now, would like to finish/merge work from 2014 gsoc first. */
- static EnumPropertyItem DT_layer_vert_shapekey_items[] = {
- {DT_TYPE_SHAPEKEY, "SHAPEKEYS", 0, "Shapekey(s)", "Transfer active or all shape keys"},
- {0, NULL, 0, NULL, NULL}
- };
-#endif
static EnumPropertyItem DT_layer_edge_items[] = {
{DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"},
@@ -4290,13 +4362,7 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
static EnumPropertyItem DT_layer_loop_items[] = {
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
- {0, NULL, 0, NULL, NULL}
- };
- static EnumPropertyItem DT_layer_loop_vcol_items[] = {
{DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"},
- {0, NULL, 0, NULL, NULL}
- };
- static EnumPropertyItem DT_layer_loop_uv_items[] = {
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
{0, NULL, 0, NULL, NULL}
};
@@ -4346,58 +4412,47 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
"Which vertex data layers to transfer");
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_enum_sdna(prop, NULL, "data_types");
- RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
- prop = RNA_def_enum(srna, "data_types_verts_vgroup", DT_layer_vert_vgroup_items, 0, "Vertex Data Types",
- "Which vertex data layers to transfer");
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_enum_sdna(prop, NULL, "data_types");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_DataTransferModifier_verts_data_types_set", NULL);
RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
prop = RNA_def_enum(srna, "data_types_edges", DT_layer_edge_items, 0, "Edge Data Types",
"Which edge data layers to transfer");
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_enum_sdna(prop, NULL, "data_types");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_DataTransferModifier_edges_data_types_set", NULL);
RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
prop = RNA_def_enum(srna, "data_types_loops", DT_layer_loop_items, 0, "Face Corner Data Types",
"Which face corner data layers to transfer");
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_enum_sdna(prop, NULL, "data_types");
- RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
- prop = RNA_def_enum(srna, "data_types_loops_vcol", DT_layer_loop_vcol_items, 0, "Face Corner Data Types",
- "Which face corner data layers to transfer");
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_enum_sdna(prop, NULL, "data_types");
- RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
- prop = RNA_def_enum(srna, "data_types_loops_uv", DT_layer_loop_uv_items, 0, "Face Corner Data Types",
- "Which face corner data layers to transfer");
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_enum_sdna(prop, NULL, "data_types");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_DataTransferModifier_loops_data_types_set", NULL);
RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
prop = RNA_def_enum(srna, "data_types_polys", DT_layer_poly_items, 0, "Poly Data Types",
"Which poly data layers to transfer");
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_enum_sdna(prop, NULL, "data_types");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_DataTransferModifier_polys_data_types_set", NULL);
RNA_def_property_update(prop, 0, "rna_DataTransferModifier_data_types_update");
/* Mapping methods. */
- prop = RNA_def_enum(srna, "vert_mapping", DT_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping",
+ prop = RNA_def_enum(srna, "vert_mapping", rna_enum_dt_method_vertex_items, MREMAP_MODE_VERT_NEAREST, "Vertex Mapping",
"Method used to map source vertices to destination ones");
RNA_def_property_enum_sdna(prop, NULL, "vmap_mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_enum(srna, "edge_mapping", DT_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping",
+ prop = RNA_def_enum(srna, "edge_mapping", rna_enum_dt_method_edge_items, MREMAP_MODE_EDGE_NEAREST, "Edge Mapping",
"Method used to map source edges to destination ones");
RNA_def_property_enum_sdna(prop, NULL, "emap_mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_enum(srna, "loop_mapping", DT_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR,
+ prop = RNA_def_enum(srna, "loop_mapping", rna_enum_dt_method_loop_items, MREMAP_MODE_LOOP_NEAREST_POLYNOR,
"Face Corner Mapping", "Method used to map source faces' corners to destination ones");
RNA_def_property_enum_sdna(prop, NULL, "lmap_mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_enum(srna, "poly_mapping", DT_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping",
+ prop = RNA_def_enum(srna, "poly_mapping", rna_enum_dt_method_poly_items, MREMAP_MODE_POLY_NEAREST, "Face Mapping",
"Method used to map source faces to destination ones");
RNA_def_property_enum_sdna(prop, NULL, "pmap_mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4428,60 +4483,60 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* How to handle multi-layers types of data. */
- prop = RNA_def_enum(srna, "layers_vgroup_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC,
+ prop = RNA_def_enum(srna, "layers_vgroup_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC,
"Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_MDEFORMVERT]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
#if 0
- prop = RNA_def_enum(srna, "layers_shapekey_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC,
+ prop = RNA_def_enum(srna, "layers_shapekey_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC,
"Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_SHAPEKEY]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
#endif
- prop = RNA_def_enum(srna, "layers_vcol_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC,
+ prop = RNA_def_enum(srna, "layers_vcol_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC,
"Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_VCOL]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_enum(srna, "layers_uv_select_src", DT_layers_select_src_items, DT_LAYERS_ALL_SRC,
+ prop = RNA_def_enum(srna, "layers_uv_select_src", rna_enum_dt_layers_select_src_items, DT_LAYERS_ALL_SRC,
"Source Layers Selection", "Which layers to transfer, in case of multi-layers types");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_src[DT_MULTILAYER_INDEX_UV]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_src_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_enum(srna, "layers_vgroup_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST,
+ prop = RNA_def_enum(srna, "layers_vgroup_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST,
"Destination Layers Matching", "How to match source and destination layers");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_MDEFORMVERT]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
#if 0
- prop = RNA_def_enum(srna, "layers_shapekey_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST,
+ prop = RNA_def_enum(srna, "layers_shapekey_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST,
"Destination Layers Matching", "How to match source and destination layers");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_SHAPEKEY]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
#endif
- prop = RNA_def_enum(srna, "layers_vcol_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST,
+ prop = RNA_def_enum(srna, "layers_vcol_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST,
"Destination Layers Matching", "How to match source and destination layers");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_VCOL]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_enum(srna, "layers_uv_select_dst", DT_layers_select_dst_items, DT_LAYERS_NAME_DST,
+ prop = RNA_def_enum(srna, "layers_uv_select_dst", rna_enum_dt_layers_select_dst_items, DT_LAYERS_NAME_DST,
"Destination Layers Matching", "How to match source and destination layers");
RNA_def_property_enum_sdna(prop, NULL, "layers_select_dst[DT_MULTILAYER_INDEX_UV]");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_layers_select_dst_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* Mix stuff */
- prop = RNA_def_enum(srna, "mix_mode", DT_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode",
+ prop = RNA_def_enum(srna, "mix_mode", rna_enum_dt_mix_mode_items, CDT_MIX_TRANSFER, "Mix Mode",
"How to affect destination elements with source values");
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DataTransferModifier_mix_mode_itemf");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -4596,7 +4651,7 @@ void RNA_def_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, modifier_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_modifier_type_items);
RNA_def_property_ui_text(prop, "Type", "");
/* flags */
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index 9ccde654af2..19d78361019 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -222,7 +222,7 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
srna = RNA_def_struct(brna, "MovieClipUser", NULL);
RNA_def_struct_ui_text(srna, "Movie Clip User",
- "Parameters defining how a MovieClip datablock is used by another datablock");
+ "Parameters defining how a MovieClip data-block is used by another data-block");
prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "framenr");
@@ -265,7 +265,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
};
srna = RNA_def_struct(brna, "MovieClip", "ID");
- RNA_def_struct_ui_text(srna, "MovieClip", "MovieClip datablock referencing an external movie file");
+ RNA_def_struct_ui_text(srna, "MovieClip", "MovieClip data-block referencing an external movie file");
RNA_def_struct_ui_icon(srna, ICON_SEQUENCE);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 4b66313cdd4..d09cac2a383 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -290,7 +290,7 @@ static int rna_NlaStrip_action_editable(PointerRNA *ptr)
return 0;
/* should be ok, though we may still miss some cases */
- return 1;
+ return PROP_EDITABLE;
}
static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value)
@@ -459,7 +459,7 @@ static void rna_NlaTrack_solo_set(PointerRNA *ptr, int value)
#else
/* enum defines exported for rna_animation.c */
-EnumPropertyItem nla_mode_blend_items[] = {
+EnumPropertyItem rna_enum_nla_mode_blend_items[] = {
{NLASTRIP_MODE_REPLACE, "REPLACE", 0, "Replace",
"Result strip replaces the accumulated results by amount specified by influence"},
{NLASTRIP_MODE_ADD, "ADD", 0, "Add", "Weighted result of strip is added to the accumulated results"},
@@ -470,7 +470,7 @@ EnumPropertyItem nla_mode_blend_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem nla_mode_extend_items[] = {
+EnumPropertyItem rna_enum_nla_mode_extend_items[] = {
{NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"},
{NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold",
"Hold the first frame if no previous strips in track, and always hold last frame"},
@@ -540,13 +540,13 @@ static void rna_def_nlastrip(BlenderRNA *brna)
prop = RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "extendmode");
- RNA_def_property_enum_items(prop, nla_mode_extend_items);
+ RNA_def_property_enum_items(prop, rna_enum_nla_mode_extend_items);
RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blendmode");
- RNA_def_property_enum_items(prop, nla_mode_blend_items);
+ RNA_def_property_enum_items(prop, rna_enum_nla_mode_blend_items);
RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
@@ -614,7 +614,7 @@ static void rna_def_nlastrip(BlenderRNA *brna)
* (minimum should still be > 0 though) if needed... */
RNA_def_property_range(prop, 0.1f, 1000.0f);
RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range");
- RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+ RNA_def_property_update(prop, 0, "rna_NlaStrip_transform_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 8ebc3f03608..ccbabb2b238 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -64,7 +64,7 @@
#include "RE_render_ext.h"
-EnumPropertyItem node_socket_in_out_items[] = {
+EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
{ SOCK_IN, "IN", 0, "Input", "" },
{ SOCK_OUT, "OUT", 0, "Output", "" },
{ 0, NULL, 0, NULL, NULL }
@@ -104,14 +104,14 @@ static EnumPropertyItem node_chunksize_items[] = {
#define DEF_ICON_BLANK_SKIP
#define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""},
#define DEF_VICO(name)
-EnumPropertyItem node_icon_items[] = {
+EnumPropertyItem rna_enum_node_icon_items[] = {
#include "UI_icons.h"
{0, NULL, 0, NULL, NULL}};
#undef DEF_ICON_BLANK_SKIP
#undef DEF_ICON
#undef DEF_VICO
-EnumPropertyItem node_math_items[] = {
+EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_ADD, "ADD", 0, "Add", ""},
{NODE_MATH_SUB, "SUBTRACT", 0, "Subtract", ""},
{NODE_MATH_MUL, "MULTIPLY", 0, "Multiply", ""},
@@ -134,7 +134,7 @@ EnumPropertyItem node_math_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem node_vec_math_items[] = {
+EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, "ADD", 0, "Add", ""},
{1, "SUBTRACT", 0, "Subtract", ""},
{2, "AVERAGE", 0, "Average", ""},
@@ -144,7 +144,7 @@ EnumPropertyItem node_vec_math_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem node_filter_items[] = {
+EnumPropertyItem rna_enum_node_filter_items[] = {
{0, "SOFTEN", 0, "Soften", ""},
{1, "SHARPEN", 0, "Sharpen", ""},
{2, "LAPLACE", 0, "Laplace", ""},
@@ -657,11 +657,12 @@ static bool rna_NodeTree_check(bNodeTree *ntree, ReportList *reports)
static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ bNode *node = (bNode *)ptr->data;
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
static bNode *rna_NodeTree_node_new(bNodeTree *ntree, bContext *C, ReportList *reports, const char *type)
@@ -1048,7 +1049,7 @@ static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C)
ntree->update |= NTREE_UPDATE_GROUP;
ntreeUpdateTree(G.main, ntree);
- ED_node_tag_update_nodetree(CTX_data_main(C), ntree);
+ ED_node_tag_update_nodetree(CTX_data_main(C), ntree, NULL);
}
@@ -1182,6 +1183,24 @@ static void rna_Node_update_reg(bNodeTree *ntree, bNode *node)
RNA_parameter_list_free(&list);
}
+static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
+{
+ extern FunctionRNA rna_Node_insert_link_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+
+ RNA_pointer_create((ID *)ntree, node->typeinfo->ext.srna, node, &ptr);
+ func = &rna_Node_insert_link_func;
+
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "link", &link);
+ node->typeinfo->ext.call(NULL, &ptr, func, &list);
+
+ RNA_parameter_list_free(&list);
+}
+
static void rna_Node_init(const bContext *C, PointerRNA *ptr)
{
extern FunctionRNA rna_Node_init_func;
@@ -1331,7 +1350,7 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc
PointerRNA dummyptr;
FunctionRNA *func;
PropertyRNA *parm;
- int have_function[9];
+ int have_function[10];
/* setup dummy node & node type to store static properties in */
memset(&dummynt, 0, sizeof(bNodeType));
@@ -1384,12 +1403,13 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc
nt->poll = (have_function[0]) ? rna_Node_poll : NULL;
nt->poll_instance = (have_function[1]) ? rna_Node_poll_instance : rna_Node_poll_instance_default;
nt->updatefunc = (have_function[2]) ? rna_Node_update_reg : NULL;
- nt->initfunc_api = (have_function[3]) ? rna_Node_init : NULL;
- nt->copyfunc_api = (have_function[4]) ? rna_Node_copy : NULL;
- nt->freefunc_api = (have_function[5]) ? rna_Node_free : NULL;
- nt->draw_buttons = (have_function[6]) ? rna_Node_draw_buttons : NULL;
- nt->draw_buttons_ex = (have_function[7]) ? rna_Node_draw_buttons_ext : NULL;
- nt->labelfunc = (have_function[8]) ? rna_Node_draw_label : NULL;
+ nt->insert_link = (have_function[3]) ? rna_Node_insert_link : NULL;
+ nt->initfunc_api = (have_function[4]) ? rna_Node_init : NULL;
+ nt->copyfunc_api = (have_function[5]) ? rna_Node_copy : NULL;
+ nt->freefunc_api = (have_function[6]) ? rna_Node_free : NULL;
+ nt->draw_buttons = (have_function[7]) ? rna_Node_draw_buttons : NULL;
+ nt->draw_buttons_ex = (have_function[8]) ? rna_Node_draw_buttons_ext : NULL;
+ nt->labelfunc = (have_function[9]) ? rna_Node_draw_label : NULL;
/* sanitize size values in case not all have been registered */
if (nt->maxwidth < nt->minwidth)
@@ -1526,12 +1546,13 @@ static int rna_Node_parent_poll(PointerRNA *ptr, PointerRNA value)
static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
- ED_node_tag_update_nodetree(bmain, ntree);
+ bNode *node = (bNode *)ptr->data;
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
-static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C)
+static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C)
{
- ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id);
+ ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node);
}
static void rna_Node_select_set(PointerRNA *ptr, int value)
@@ -1897,7 +1918,11 @@ static PointerRNA rna_NodeSocket_node_get(PointerRNA *ptr)
static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
- ED_node_tag_update_nodetree(bmain, ntree);
+ bNodeSocket *sock = (bNodeSocket *)ptr->data;
+ bNode *node;
+ if (nodeFindNode(ntree, sock, &node, NULL)) {
+ ED_node_tag_update_nodetree(bmain, ntree, node);
+ }
}
static int rna_NodeSocket_is_output_get(PointerRNA *ptr)
@@ -2163,7 +2188,7 @@ static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), Po
ntree->update |= NTREE_UPDATE_GROUP;
ntreeUpdateTree(G.main, ntree);
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, NULL);
}
@@ -2419,8 +2444,9 @@ static void rna_CompositorNode_tag_need_exec(bNode *node)
static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+ bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -2432,7 +2458,7 @@ static void rna_Node_material_update(Main *bmain, Scene *UNUSED(scene), PointerR
if (node->id)
nodeSetActive(ntree, node);
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -2443,7 +2469,7 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
if (node->id)
ntreeUpdateTree(bmain, (bNodeTree *)node->id);
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
static void rna_NodeGroup_node_tree_set(PointerRNA *ptr, const PointerRNA value)
@@ -2887,7 +2913,7 @@ static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value)
nss->filepath[0] = '\0';
nss->flag &= ~NODE_SCRIPT_AUTO_UPDATE;
- /* replace text datablock by filepath */
+ /* replace text data-block by filepath */
if (node->id) {
Text *text = (Text *)node->id;
@@ -2953,7 +2979,7 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
RE_engine_free(engine);
}
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, node);
}
static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -3004,57 +3030,123 @@ static void rna_ShaderNodePointDensity_psys_set(PointerRNA *ptr, PointerRNA valu
}
}
-static int point_density_color_source_from_shader(NodeShaderTexPointDensity *shader_point_density)
+static int point_density_particle_color_source_from_shader(NodeShaderTexPointDensity *shader_point_density)
{
switch (shader_point_density->color_source) {
- case SHD_POINTDENSITY_COLOR_PARTAGE: return TEX_PD_COLOR_PARTAGE;
- case SHD_POINTDENSITY_COLOR_PARTSPEED: return TEX_PD_COLOR_PARTSPEED;
- case SHD_POINTDENSITY_COLOR_PARTVEL: return TEX_PD_COLOR_PARTVEL;
+ case SHD_POINTDENSITY_COLOR_PARTAGE:
+ return TEX_PD_COLOR_PARTAGE;
+ case SHD_POINTDENSITY_COLOR_PARTSPEED:
+ return TEX_PD_COLOR_PARTSPEED;
+ case SHD_POINTDENSITY_COLOR_PARTVEL:
+ return TEX_PD_COLOR_PARTVEL;
default:
BLI_assert(!"Unknown color source");
return TEX_PD_COLOR_CONSTANT;
}
}
-/* TODO(sergey): This function assumes allocated array was passed,
- * works fine with Cycles via C++ RNA, but fails with call from python.
- */
-void rna_ShaderNodePointDensity_density_calc(bNode *self, Scene *scene, int *length, float **values)
+static int point_density_vertex_color_source_from_shader(NodeShaderTexPointDensity *shader_point_density)
{
- NodeShaderTexPointDensity *shader_point_density = self->storage;
- PointDensity pd;
-
- *length = 4 * shader_point_density->resolution *
- shader_point_density->resolution *
- shader_point_density->resolution;
+ switch (shader_point_density->ob_color_source) {
+ case SHD_POINTDENSITY_COLOR_VERTCOL:
+ return TEX_PD_COLOR_VERTCOL;
+ case SHD_POINTDENSITY_COLOR_VERTWEIGHT:
+ return TEX_PD_COLOR_VERTWEIGHT;
+ case SHD_POINTDENSITY_COLOR_VERTNOR:
+ return TEX_PD_COLOR_VERTNOR;
+ default:
+ BLI_assert(!"Unknown color source");
+ return TEX_PD_COLOR_CONSTANT;
+ }
+}
- if (*values == NULL) {
- *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array");
+void rna_ShaderNodePointDensity_density_cache(bNode *self,
+ Scene *scene,
+ int settings)
+{
+ NodeShaderTexPointDensity *shader_point_density = self->storage;
+ PointDensity *pd = &shader_point_density->pd;
+ if (scene == NULL) {
+ return;
}
+ /* Make sure there's no cached data. */
+ BKE_texture_pointdensity_free_data(pd);
+ RE_point_density_free(pd);
+
/* Create PointDensity structure from node for sampling. */
- BKE_texture_pointdensity_init_data(&pd);
- pd.object = (Object *)self->id;
- pd.radius = shader_point_density->radius;
+ BKE_texture_pointdensity_init_data(pd);
+ pd->object = (Object *)self->id;
+ pd->radius = shader_point_density->radius;
if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- pd.source = TEX_PD_PSYS;
- pd.psys = shader_point_density->particle_system;
- pd.psys_cache_space = TEX_PD_OBJECTSPACE;
+ pd->source = TEX_PD_PSYS;
+ pd->psys = shader_point_density->particle_system;
+ pd->psys_cache_space = TEX_PD_OBJECTSPACE;
+ pd->color_source = point_density_particle_color_source_from_shader(shader_point_density);
}
else {
BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT);
- pd.source = TEX_PD_OBJECT;
- pd.ob_cache_space = TEX_PD_OBJECTSPACE;
+ pd->source = TEX_PD_OBJECT;
+ pd->ob_cache_space = TEX_PD_OBJECTSPACE;
+ pd->ob_color_source = point_density_vertex_color_source_from_shader(shader_point_density);
+ BLI_strncpy(pd->vertex_attribute_name,
+ shader_point_density->vertex_attribute_name,
+ sizeof(pd->vertex_attribute_name));
}
- pd.color_source = point_density_color_source_from_shader(shader_point_density);
/* Single-threaded sampling of the voxel domain. */
- RE_sample_point_density(scene, &pd,
+ RE_point_density_cache(scene,
+ pd,
+ settings == 1);
+}
+
+void rna_ShaderNodePointDensity_density_calc(bNode *self,
+ Scene *scene,
+ int settings,
+ int *length,
+ float **values)
+{
+ NodeShaderTexPointDensity *shader_point_density = self->storage;
+ PointDensity *pd = &shader_point_density->pd;
+
+ if (scene == NULL) {
+ *length = 0;
+ return;
+ }
+
+ *length = 4 * shader_point_density->resolution *
+ shader_point_density->resolution *
+ shader_point_density->resolution;
+
+ if (*values == NULL) {
+ *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array");
+ }
+
+ /* Single-threaded sampling of the voxel domain. */
+ RE_point_density_sample(scene, pd,
shader_point_density->resolution,
+ settings == 1,
*values);
/* We're done, time to clean up. */
- BKE_texture_pointdensity_free_data(&pd);
+ BKE_texture_pointdensity_free_data(pd);
+ memset(pd, 0, sizeof(*pd));
+}
+
+void rna_ShaderNodePointDensity_density_minmax(bNode *self,
+ Scene *scene,
+ int settings,
+ float r_min[3],
+ float r_max[3])
+{
+ NodeShaderTexPointDensity *shader_point_density = self->storage;
+ PointDensity *pd = &shader_point_density->pd;
+ if (scene == NULL) {
+ zero_v3(r_min);
+ zero_v3(r_max);
+ return;
+ }
+ RE_point_density_minmax(scene, pd, settings == 1, r_min, r_max);
}
#else
@@ -3130,7 +3222,7 @@ static EnumPropertyItem node_hair_items[] = {
};
static EnumPropertyItem node_script_mode_items[] = {
- {NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text datablock"},
+ {NODE_SCRIPT_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text data-block"},
{NODE_SCRIPT_EXTERNAL, "EXTERNAL", 0, "External", "Use external .osl or .oso file"},
{0, NULL, 0, NULL, NULL}
};
@@ -3227,7 +3319,7 @@ static void def_math(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, node_math_items);
+ RNA_def_property_enum_items(prop, rna_enum_node_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -3243,7 +3335,7 @@ static void def_vector_math(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, node_vec_math_items);
+ RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -3308,7 +3400,7 @@ static void def_mix_rgb(StructRNA *srna)
prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, ramp_blend_items);
+ RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
RNA_def_property_ui_text(prop, "Blend Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -3543,17 +3635,29 @@ static void def_sh_tex_sky(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static const EnumPropertyItem sh_tex_prop_color_space_items[] = {
+ {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color",
+ "Image contains color data, and will be converted to linear color for rendering"},
+ {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data",
+ "Image contains non-color data, for example a displacement or normal map, "
+ "and will not be converted"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static const EnumPropertyItem sh_tex_prop_interpolation_items[] = {
+ {SHD_INTERP_LINEAR, "Linear", 0, "Linear",
+ "Linear interpolation"},
+ {SHD_INTERP_CLOSEST, "Closest", 0, "Closest",
+ "No interpolation (sample closest texel)"},
+ {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic",
+ "Cubic interpolation (CPU only)"},
+ {SHD_INTERP_SMART, "Smart", 0, "Smart",
+ "Bicubic when magnifying, else bilinear (OSL only)"},
+ {0, NULL, 0, NULL, NULL}
+};
+
static void def_sh_tex_environment(StructRNA *srna)
{
- static const EnumPropertyItem prop_color_space_items[] = {
- {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color",
- "Image contains color data, and will be converted to linear color for rendering"},
- {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data",
- "Image contains non-color data, for example a displacement or normal map, "
- "and will not be converted"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem prop_projection_items[] = {
{SHD_PROJ_EQUIRECTANGULAR, "EQUIRECTANGULAR", 0, "Equirectangular",
"Equirectangular or latitude-longitude projection"},
@@ -3575,7 +3679,7 @@ static void def_sh_tex_environment(StructRNA *srna)
def_sh_tex(srna);
prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_color_space_items);
+ RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items);
RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -3585,6 +3689,11 @@ static void def_sh_tex_environment(StructRNA *srna)
RNA_def_property_ui_text(prop, "Projection", "Projection of the input image");
RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, sh_tex_prop_interpolation_items);
+ RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
@@ -3595,15 +3704,6 @@ static void def_sh_tex_environment(StructRNA *srna)
static void def_sh_tex_image(StructRNA *srna)
{
- static const EnumPropertyItem prop_color_space_items[] = {
- {SHD_COLORSPACE_COLOR, "COLOR", 0, "Color",
- "Image contains color data, and will be converted to linear color for rendering"},
- {SHD_COLORSPACE_NONE, "NONE", 0, "Non-Color Data",
- "Image contains non-color data, for example a displacement or normal map, "
- "and will not be converted"},
- {0, NULL, 0, NULL, NULL}
- };
-
static const EnumPropertyItem prop_projection_items[] = {
{SHD_PROJ_FLAT, "FLAT", 0, "Flat",
"Image is projected flat using the X and Y coordinates of the texture vector"},
@@ -3616,18 +3716,6 @@ static void def_sh_tex_image(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
- static const EnumPropertyItem prop_interpolation_items[] = {
- {SHD_INTERP_LINEAR, "Linear", 0, "Linear",
- "Linear interpolation"},
- {SHD_INTERP_CLOSEST, "Closest", 0, "Closest",
- "No interpolation (sample closest texel)"},
- {SHD_INTERP_CUBIC, "Cubic", 0, "Cubic",
- "Cubic interpolation (CPU only)"},
- {SHD_INTERP_SMART, "Smart", 0, "Smart",
- "Bicubic when magnifying, else bilinear (OSL only)"},
- {0, NULL, 0, NULL, NULL}
- };
-
static EnumPropertyItem prop_image_extension[] = {
{SHD_IMAGE_EXTENSION_REPEAT, "REPEAT", 0, "Repeat", "Cause the image to repeat horizontally and vertically"},
{SHD_IMAGE_EXTENSION_EXTEND, "EXTEND", 0, "Extend", "Extend by repeating edge pixels of the image"},
@@ -3648,7 +3736,7 @@ static void def_sh_tex_image(StructRNA *srna)
def_sh_tex(srna);
prop = RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_color_space_items);
+ RNA_def_property_enum_items(prop, sh_tex_prop_color_space_items);
RNA_def_property_enum_default(prop, SHD_COLORSPACE_COLOR);
RNA_def_property_ui_text(prop, "Color Space", "Image file color space");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -3659,7 +3747,7 @@ static void def_sh_tex_image(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_interpolation_items);
+ RNA_def_property_enum_items(prop, sh_tex_prop_interpolation_items);
RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation");
RNA_def_property_update(prop, 0, "rna_Node_update");
@@ -3819,6 +3907,12 @@ static void def_sh_tex_wave(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_wave_profile_items[] = {
+ {SHD_WAVE_PROFILE_SIN, "SIN", 0, "Sine", "Use a standard sine profile"},
+ {SHD_WAVE_PROFILE_SAW, "SAW", 0, "Saw", "Use a sawtooth profile"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeTexWave", "storage");
@@ -3829,6 +3923,12 @@ static void def_sh_tex_wave(StructRNA *srna)
RNA_def_property_enum_items(prop, prop_wave_type_items);
RNA_def_property_ui_text(prop, "Wave Type", "");
RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "wave_profile", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "wave_profile");
+ RNA_def_property_enum_items(prop, prop_wave_profile_items);
+ RNA_def_property_ui_text(prop, "Wave Profile", "");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
}
static void def_sh_tex_coord(StructRNA *srna)
@@ -3924,7 +4024,7 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem color_source_items[] = {
+ static EnumPropertyItem particle_color_source_items[] = {
{SHD_POINTDENSITY_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age",
"Lifetime mapped as 0.0 - 1.0 intensity"},
{SHD_POINTDENSITY_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed",
@@ -3934,6 +4034,21 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem vertex_color_source_items[] = {
+ {SHD_POINTDENSITY_COLOR_VERTCOL, "VERTEX_COLOR", 0, "Vertex Color", "Vertex color layer"},
+ {SHD_POINTDENSITY_COLOR_VERTWEIGHT, "VERTEX_WEIGHT", 0, "Vertex Weight", "Vertex group weight"},
+ {SHD_POINTDENSITY_COLOR_VERTNOR, "VERTEX_NORMAL", 0, "Vertex Normal",
+ "XYZ normal vector mapped to RGB colors"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* TODO(sergey): Use some mnemonic names for the hardcoded values here. */
+ static EnumPropertyItem calc_mode_items[] = {
+ {0, "VIEWPORT", 0, "Viewport", "Canculate density using viewport settings"},
+ {1, "RENDER", 0, "Render", "Canculate duplis using render settings"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "id");
RNA_def_property_struct_type(prop, "Object");
@@ -3977,19 +4092,48 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
RNA_def_property_ui_text(prop, "Interpolation", "Texture interpolation");
RNA_def_property_update(prop, 0, "rna_Node_update");
- prop = RNA_def_property(srna, "color_source", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "particle_color_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_source");
- RNA_def_property_enum_items(prop, color_source_items);
+ RNA_def_property_enum_items(prop, particle_color_source_items);
RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "vertex_color_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "ob_color_source");
+ RNA_def_property_enum_items(prop, vertex_color_source_items);
+ RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
+ RNA_def_property_update(prop, 0, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "vertex_attribute_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Vertex Attribute Name", "Vertex attribute to use for color");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ func = RNA_def_function(srna, "cache_point_density", "rna_ShaderNodePointDensity_density_cache");
+ RNA_def_function_ui_description(func, "Cache point density data for later calculation");
+ RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
+
func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc");
RNA_def_function_ui_description(func, "Calculate point density");
RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
/* TODO, See how array size of 0 works, this shouldnt be used. */
prop = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0);
RNA_def_property_flag(prop, PROP_DYNAMIC);
RNA_def_function_output(func, prop);
+
+ func = RNA_def_function(srna, "calc_point_density_minmax", "rna_ShaderNodePointDensity_density_minmax");
+ RNA_def_function_ui_description(func, "Calculate point density");
+ RNA_def_pointer(func, "scene", "Scene", "", "");
+ RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
+ prop = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_flag(prop, PROP_THICK_WRAP);
+ RNA_def_function_output(func, prop);
+ prop = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_flag(prop, PROP_THICK_WRAP);
+ RNA_def_function_output(func, prop);
}
static void def_glossy(StructRNA *srna)
@@ -4154,6 +4298,7 @@ static void def_sh_subsurface(StructRNA *srna)
static EnumPropertyItem prop_subsurface_falloff_items[] = {
{SHD_SUBSURFACE_CUBIC, "CUBIC", 0, "Cubic", "Simple cubic falloff function"},
{SHD_SUBSURFACE_GAUSSIAN, "GAUSSIAN", 0, "Gaussian", "Normal distribution, multiple can be combined to fit more complex profiles"},
+ {SHD_SUBSURFACE_BURLEY, "BURLEY", 0, "Christensen-Burley", "Approximation to physically based volume scattering"},
{0, NULL, 0, NULL, NULL}
};
@@ -4312,6 +4457,11 @@ static void def_cmp_blur(StructRNA *srna)
RNA_def_property_ui_text(prop, "Variable Size", "Support variable blur per-pixel when using an image for size input");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ prop = RNA_def_property(srna, "use_extended_bounds", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_BLUR_EXTEND_BOUNDS);
+ RNA_def_property_ui_text(prop, "Extend Bounds", "Extend bounds of the input image to fully fit blurred image");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
RNA_def_struct_sdna_from(srna, "NodeBlurData", "storage");
prop = RNA_def_property(srna, "size_x", PROP_INT, PROP_NONE);
@@ -4378,7 +4528,7 @@ static void def_cmp_filter(StructRNA *srna)
prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, node_filter_items);
+ RNA_def_property_enum_items(prop, rna_enum_node_filter_items);
RNA_def_property_ui_text(prop, "Filter Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -4772,7 +4922,7 @@ static void def_cmp_dilate_erode(StructRNA *srna)
/* CMP_NODE_DILATEERODE_DISTANCE_FEATHER only */
prop = RNA_def_property(srna, "falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "falloff");
- RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
RNA_def_property_ui_text(prop, "Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5160,15 +5310,9 @@ static void def_cmp_splitviewer(StructRNA *srna)
{
PropertyRNA *prop;
- static EnumPropertyItem axis_items[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
- RNA_def_property_enum_items(prop, axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xy_items);
RNA_def_property_ui_text(prop, "Axis", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5817,6 +5961,11 @@ static void def_cmp_stabilize2d(StructRNA *srna)
RNA_def_property_enum_items(prop, node_sampler_type_items);
RNA_def_property_ui_text(prop, "Filter", "Method to use to filter stabilization");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom2", CMP_NODEFLAG_STABILIZE_INVERSE);
+ RNA_def_property_ui_text(prop, "Invert", "Invert stabilization to re-introduce motion to the frame");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_moviedistortion(StructRNA *srna)
@@ -6035,6 +6184,11 @@ static void def_cmp_bokehblur(StructRNA *srna)
"Support variable blur per-pixel when using an image for size input");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ prop = RNA_def_property(srna, "use_extended_bounds", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODEFLAG_BLUR_EXTEND_BOUNDS);
+ RNA_def_property_ui_text(prop, "Extend Bounds", "Extend bounds of the input image to fully fit blurred image");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
#if 0
prop = RNA_def_property(srna, "f_stop", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "custom3");
@@ -6429,7 +6583,7 @@ static void def_cmp_keying(StructRNA *srna)
prop = RNA_def_property(srna, "feather_falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "feather_falloff");
- RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_curve_only_items);
RNA_def_property_ui_text(prop, "Feather Falloff", "Falloff type the feather");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -7610,7 +7764,7 @@ static void rna_def_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typeinfo->ui_icon");
- RNA_def_property_enum_items(prop, node_icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_node_icon_items);
RNA_def_property_enum_default(prop, ICON_NODE);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(prop, "Icon", "The node icon");
@@ -7668,6 +7822,13 @@ static void rna_def_node(BlenderRNA *brna)
RNA_def_function_ui_description(func, "Update on editor changes");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ /* insert_link */
+ func = RNA_def_function(srna, "insert_link", NULL);
+ RNA_def_function_ui_description(func, "Handle creation of a link to or from the node");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
+ parm = RNA_def_pointer(func, "link", "NodeLink", "Link", "Node link that will be inserted");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+
/* init */
func = RNA_def_function(srna, "init", NULL);
RNA_def_function_ui_description(func, "Initialize a new instance of this node");
@@ -7934,7 +8095,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
+ RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
RNA_def_property_update(prop, NC_NODE, NULL);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
@@ -7989,7 +8150,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "typeinfo->ui_icon");
- RNA_def_property_enum_items(prop, node_icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_node_icon_items);
RNA_def_property_enum_default(prop, ICON_NODETREE);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Icon", "The node tree icon");
@@ -8072,7 +8233,7 @@ static void rna_def_shader_nodetree(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ShaderNodeTree", "NodeTree");
RNA_def_struct_ui_text(srna, "Shader Node Tree",
- "Node tree consisting of linked nodes used for materials (and other shading datablocks)");
+ "Node tree consisting of linked nodes used for materials (and other shading data-blocks)");
RNA_def_struct_sdna(srna, "bNodeTree");
RNA_def_struct_ui_icon(srna, ICON_MATERIAL);
}
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 54f1798b10c..031ea89cff6 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -60,7 +60,7 @@
#include "WM_api.h"
#include "WM_types.h"
-EnumPropertyItem object_mode_items[] = {
+EnumPropertyItem rna_enum_object_mode_items[] = {
{OB_MODE_OBJECT, "OBJECT", ICON_OBJECT_DATAMODE, "Object Mode", ""},
{OB_MODE_EDIT, "EDIT", ICON_EDITMODE_HLT, "Edit Mode", ""},
{OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""},
@@ -69,10 +69,11 @@ EnumPropertyItem object_mode_items[] = {
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
+ {OB_MODE_GPENCIL, "GPENCIL_EDIT", ICON_GREASEPENCIL, "Edit Strokes", "Edit Grease Pencil Strokes"},
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem object_empty_drawtype_items[] = {
+EnumPropertyItem rna_enum_object_empty_drawtype_items[] = {
{OB_PLAINAXES, "PLAIN_AXES", 0, "Plain Axes", ""},
{OB_ARROWS, "ARROWS", 0, "Arrows", ""},
{OB_SINGLE_ARROW, "SINGLE_ARROW", 0, "Single Arrow", ""},
@@ -107,18 +108,18 @@ static EnumPropertyItem dupli_items[] = {
#endif
static EnumPropertyItem collision_bounds_items[] = {
- {OB_BOUND_BOX, "BOX", 0, "Box", ""},
- {OB_BOUND_SPHERE, "SPHERE", 0, "Sphere", ""},
- {OB_BOUND_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
- {OB_BOUND_CONE, "CONE", 0, "Cone", ""},
- {OB_BOUND_CONVEX_HULL, "CONVEX_HULL", 0, "Convex Hull", ""},
- {OB_BOUND_TRIANGLE_MESH, "TRIANGLE_MESH", 0, "Triangle Mesh", ""},
- {OB_BOUND_CAPSULE, "CAPSULE", 0, "Capsule", ""},
+ {OB_BOUND_BOX, "BOX", ICON_MESH_CUBE, "Box", ""},
+ {OB_BOUND_SPHERE, "SPHERE", ICON_MESH_UVSPHERE, "Sphere", ""},
+ {OB_BOUND_CYLINDER, "CYLINDER", ICON_MESH_CYLINDER, "Cylinder", ""},
+ {OB_BOUND_CONE, "CONE", ICON_MESH_CONE, "Cone", ""},
+ {OB_BOUND_CONVEX_HULL, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull", ""},
+ {OB_BOUND_TRIANGLE_MESH, "TRIANGLE_MESH", ICON_MESH_MONKEY, "Triangle Mesh", ""},
+ {OB_BOUND_CAPSULE, "CAPSULE", ICON_MESH_CAPSULE, "Capsule", ""},
/*{OB_DYN_MESH, "DYNAMIC_MESH", 0, "Dynamic Mesh", ""}, */
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem metaelem_type_items[] = {
+EnumPropertyItem rna_enum_metaelem_type_items[] = {
{MB_BALL, "BALL", ICON_META_BALL, "Ball", ""},
{MB_TUBE, "CAPSULE", ICON_META_CAPSULE, "Capsule", ""},
{MB_PLANE, "PLANE", ICON_META_PLANE, "Plane", ""},
@@ -132,7 +133,7 @@ EnumPropertyItem metaelem_type_items[] = {
#define OBTYPE_CU_SURF {OB_SURF, "SURFACE", 0, "Surface", ""}
#define OBTYPE_CU_FONT {OB_FONT, "FONT", 0, "Font", ""}
-EnumPropertyItem object_type_items[] = {
+EnumPropertyItem rna_enum_object_type_items[] = {
{OB_MESH, "MESH", 0, "Mesh", ""},
OBTYPE_CU_CURVE,
OBTYPE_CU_SURF,
@@ -149,14 +150,14 @@ EnumPropertyItem object_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem object_type_curve_items[] = {
+EnumPropertyItem rna_enum_object_type_curve_items[] = {
OBTYPE_CU_CURVE,
OBTYPE_CU_SURF,
OBTYPE_CU_FONT,
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem object_axis_items[] = {
+EnumPropertyItem rna_enum_object_axis_items[] = {
{OB_POSX, "POS_X", 0, "+X", ""},
{OB_POSY, "POS_Y", 0, "+Y", ""},
{OB_POSZ, "POS_Z", 0, "+Z", ""},
@@ -166,14 +167,6 @@ EnumPropertyItem object_axis_items[] = {
{0, NULL, 0, NULL, NULL}
};
-/* for general use (not just object) */
-EnumPropertyItem object_axis_unsigned_items[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {2, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
#ifdef RNA_RUNTIME
#include "BLI_math.h"
@@ -275,17 +268,20 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA
case OB_MESH:
EDBM_mesh_load(ob);
EDBM_mesh_make(scene->toolsettings, ob);
+
+ DAG_id_tag_update(ob->data, 0);
+
EDBM_mesh_normals_update(((Mesh *)ob->data)->edit_btmesh);
BKE_editmesh_tessface_calc(((Mesh *)ob->data)->edit_btmesh);
break;
case OB_CURVE:
case OB_SURF:
- load_editNurb(ob);
- make_editNurb(ob);
+ ED_curve_editnurb_load(ob);
+ ED_curve_editnurb_make(ob);
break;
case OB_LATTICE:
- load_editLatt(ob);
- make_editLatt(ob);
+ ED_lattice_editlatt_load(ob);
+ ED_lattice_editlatt_make(ob);
break;
}
}
@@ -535,11 +531,14 @@ static void rna_Object_dup_group_set(PointerRNA *ptr, PointerRNA value)
/* must not let this be set if the object belongs in this group already,
* thus causing a cycle/infinite-recursion leading to crashes on load [#25298]
*/
- if (BKE_group_object_exists(grp, ob) == 0)
+ if (BKE_group_object_exists(grp, ob) == 0) {
ob->dup_group = grp;
- else
+ id_lib_extern((ID *)grp);
+ }
+ else {
BKE_report(NULL, RPT_ERROR,
"Cannot set dupli-group as object belongs in group being instanced, thus causing a cycle");
+ }
}
static void rna_VertexGroup_name_set(PointerRNA *ptr, const char *value)
@@ -1033,6 +1032,11 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
ob->gameflag |= OB_COLLISION | OB_CHARACTER;
ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR |
OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
+ /* When we switch to character physics and the collision bounds is set to triangle mesh
+ we have to change collision bounds because triangle mesh is not supported by Characters*/
+ if ((ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) {
+ ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX;
+ }
break;
case OB_BODY_TYPE_STATIC:
ob->gameflag |= OB_COLLISION;
@@ -1598,7 +1602,7 @@ static void rna_def_material_slot(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL);
- RNA_def_property_ui_text(prop, "Material", "Material datablock used by this material slot");
+ RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
prop = RNA_def_property(srna, "link", PROP_ENUM, PROP_NONE);
@@ -1771,6 +1775,14 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
RNA_def_property_float_default(prop, 55.0f);
RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall");
+ prop = RNA_def_property(srna, "jump_max", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "max_jumps");
+ RNA_def_property_range(prop, 1, CHAR_MAX);
+ RNA_def_property_ui_range(prop, 1, 10, 1, 1);
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_ui_text(prop, "Max Jumps",
+ "The maximum number of jumps the character can make before it hits the ground");
+
/* Collision Masks */
prop = RNA_def_property(srna, "collision_group", PROP_BOOLEAN, PROP_LAYER_MEMBER);
RNA_def_property_boolean_sdna(prop, NULL, "col_group", 1);
@@ -1942,7 +1954,7 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_Object_constraints_new");
RNA_def_function_ui_description(func, "Add a new constraint to this object");
/* object to add */
- parm = RNA_def_enum(func, "type", constraint_type_items, 1, "", "Constraint type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint");
@@ -1993,7 +2005,7 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* modifier to add */
- parm = RNA_def_enum(func, "type", modifier_type_items, 1, "", "Modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_object_modifier_type_items, 1, "", "Modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Newly created modifier");
@@ -2195,7 +2207,7 @@ static void rna_def_object(BlenderRNA *brna)
static int boundbox_dimsize[] = {8, 3};
srna = RNA_def_struct(brna, "Object", "ID");
- RNA_def_struct_ui_text(srna, "Object", "Object datablock defining an object in a scene");
+ RNA_def_struct_ui_text(srna, "Object", "Object data-block defining an object in a scene");
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
RNA_def_struct_ui_icon(srna, ICON_OBJECT_DATA);
@@ -2208,13 +2220,13 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, object_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "Type of Object");
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, object_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mode", "Object interaction mode");
@@ -2278,7 +2290,7 @@ static void rna_def_object(BlenderRNA *brna)
* since some other tools still refer to this */
prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "trackflag");
- RNA_def_property_enum_items(prop, object_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Track Axis",
"Axis that points in 'forward' direction (applies to DupliFrame when "
"parent 'Follow' is enabled)");
@@ -2517,7 +2529,7 @@ static void rna_def_object(BlenderRNA *brna)
/* empty */
prop = RNA_def_property(srna, "empty_draw_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "empty_drawtype");
- RNA_def_property_enum_items(prop, object_empty_drawtype_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_empty_drawtype_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_Object_empty_draw_type_set", NULL);
RNA_def_property_ui_text(prop, "Empty Display Type", "Viewport display style for empties");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
@@ -2769,7 +2781,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
+ RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
/* pose */
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index a446f119132..7cc69831dce 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -35,6 +35,7 @@
#include <time.h>
#include "BLI_utildefines.h"
+#include "BLI_kdopbvh.h"
#include "RNA_define.h"
@@ -315,8 +316,10 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly;
}
-static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3],
- float r_location[3], float r_normal[3], int *index)
+static void rna_Object_ray_cast(
+ Object *ob, ReportList *reports,
+ float origin[3], float direction[3], float distance,
+ int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
BVHTreeFromMesh treeData = {NULL};
@@ -331,33 +334,41 @@ static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start
/* may fail if the mesh has no faces, in that case the ray-cast misses */
if (treeData.tree != NULL) {
BVHTreeRayHit hit;
- float ray_nor[3], dist;
- sub_v3_v3v3(ray_nor, ray_end, ray_start);
- dist = hit.dist = normalize_v3(ray_nor);
hit.index = -1;
+ hit.dist = distance;
- if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit,
+ normalize_v3(direction);
+
+
+ if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit,
treeData.raycast_callback, &treeData) != -1)
{
- if (hit.dist <= dist) {
+ if (hit.dist <= distance) {
+ *r_success = true;
+
copy_v3_v3(r_location, hit.co);
copy_v3_v3(r_normal, hit.no);
- *index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
- free_bvhtree_from_mesh(&treeData);
- return;
+ *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]);
+
+ goto finally;
}
}
}
+ *r_success = false;
+
zero_v3(r_location);
zero_v3(r_normal);
- *index = -1;
+ *r_index = -1;
+
+finally:
free_bvhtree_from_mesh(&treeData);
}
-static void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float max_dist,
- float n_location[3], float n_normal[3], int *index)
+static void rna_Object_closest_point_on_mesh(
+ Object *ob, ReportList *reports, float origin[3], float distance,
+ int *r_success, float r_location[3], float r_normal[3], int *r_index)
{
BVHTreeFromMesh treeData = {NULL};
@@ -379,20 +390,26 @@ static void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, fl
BVHTreeNearest nearest;
nearest.index = -1;
- nearest.dist_sq = max_dist * max_dist;
+ nearest.dist_sq = distance * distance;
- if (BLI_bvhtree_find_nearest(treeData.tree, point_co, &nearest, treeData.nearest_callback, &treeData) != -1) {
- copy_v3_v3(n_location, nearest.co);
- copy_v3_v3(n_normal, nearest.no);
- *index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[nearest.index]);
- free_bvhtree_from_mesh(&treeData);
- return;
+ if (BLI_bvhtree_find_nearest(treeData.tree, origin, &nearest, treeData.nearest_callback, &treeData) != -1) {
+ *r_success = true;
+
+ copy_v3_v3(r_location, nearest.co);
+ copy_v3_v3(r_normal, nearest.no);
+ *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[nearest.index]);
+
+ goto finally;
}
}
- zero_v3(n_location);
- zero_v3(n_normal);
- *index = -1;
+ *r_success = false;
+
+ zero_v3(r_location);
+ zero_v3(r_normal);
+ *r_index = -1;
+
+finally:
free_bvhtree_from_mesh(&treeData);
}
@@ -537,7 +554,7 @@ void RNA_api_object(StructRNA *srna)
/* mesh */
func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh");
- RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied");
+ RNA_def_function_ui_description(func, "Create a Mesh data-block with modifiers applied");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
@@ -593,12 +610,16 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* ray start and end */
- parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX,
+ "", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX);
/* return location and normal */
+ parm = RNA_def_boolean(func, "result", 0, "", "");
+ RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this ray cast", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_THICK_WRAP);
@@ -607,8 +628,7 @@ void RNA_api_object(StructRNA *srna)
"The face normal at the ray cast hit location", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_THICK_WRAP);
RNA_def_function_output(func, parm);
-
- parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no intersection is found", 0, 0);
+ parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
RNA_def_function_output(func, parm);
/* Nearest Point */
@@ -617,12 +637,14 @@ void RNA_api_object(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
/* location of point for test and max distance */
- parm = RNA_def_float_vector(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_REQUIRED);
/* default is sqrt(FLT_MAX) */
- RNA_def_float(func, "max_dist", 1.844674352395373e+19, 0.0, FLT_MAX, "", "", 0.0, FLT_MAX);
+ RNA_def_float(func, "distance", 1.844674352395373e+19, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX);
/* return location and normal */
+ parm = RNA_def_boolean(func, "result", 0, "", "");
+ RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The location on the object closest to the point", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_THICK_WRAP);
@@ -632,7 +654,7 @@ void RNA_api_object(StructRNA *srna)
RNA_def_property_flag(parm, PROP_THICK_WRAP);
RNA_def_function_output(func, parm);
- parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no closest point is found", 0, 0);
+ parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
RNA_def_function_output(func, parm);
/* View */
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 75becb341b9..ed765f1b5c6 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -34,6 +34,7 @@
#include "DNA_smoke_types.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "rna_internal.h"
@@ -163,7 +164,7 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
PointCache *cache = (PointCache *)ptr->data;
PTCacheID *pid = NULL, *pid2 = NULL;
ListBase pidlist;
- int new_name = 1;
+ bool use_new_name = true;
if (!ob)
return;
@@ -193,11 +194,11 @@ static void rna_Cache_idname_change(Main *UNUSED(bmain), Scene *UNUSED(scene), P
else if (cache->name[0] != '\0' && STREQ(cache->name, pid->cache->name)) {
/*TODO: report "name exists" to user */
BLI_strncpy(cache->name, cache->prev_name, sizeof(cache->name));
- new_name = 0;
+ use_new_name = false;
}
}
- if (new_name) {
+ if (use_new_name) {
if (pid2 && cache->flag & PTCACHE_DISK_CACHE) {
char old_name[80];
char new_name[80];
@@ -487,12 +488,12 @@ static void rna_FieldSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
ParticleSettings *part = (ParticleSettings *)ptr->id.data;
if (part->pd->forcefield != PFIELD_TEXTURE && part->pd->tex) {
- part->pd->tex->id.us--;
+ id_us_min(&part->pd->tex->id);
part->pd->tex = NULL;
}
if (part->pd2 && part->pd2->forcefield != PFIELD_TEXTURE && part->pd2->tex) {
- part->pd2->tex->id.us--;
+ id_us_min(&part->pd2->tex->id);
part->pd2->tex = NULL;
}
@@ -504,7 +505,7 @@ static void rna_FieldSettings_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
Object *ob = (Object *)ptr->id.data;
if (ob->pd->forcefield != PFIELD_TEXTURE && ob->pd->tex) {
- ob->pd->tex->id.us--;
+ id_us_min(&ob->pd->tex->id);
ob->pd->tex = NULL;
}
@@ -1169,13 +1170,6 @@ static void rna_def_field(BlenderRNA *brna)
{6, "ROLL", 0, "Roll", ""},
{0, NULL, 0, NULL, NULL}
};
-
- static EnumPropertyItem guide_kink_axis_items[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {2, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
srna = RNA_def_struct(brna, "FieldSettings", NULL);
RNA_def_struct_sdna(srna, "PartDeflect");
@@ -1456,7 +1450,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "guide_kink_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "kink_axis");
- RNA_def_property_enum_items(prop, guide_kink_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Axis", "Which axis to use for offset");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1639,7 +1633,7 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Goal Default",
- "Default Goal (vertex target position) value, when no Vertex Group used");
+ "Default Goal (vertex target position) value");
RNA_def_property_update(prop, 0, "rna_softbody_update");
prop = RNA_def_property(srna, "goal_spring", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_packedfile.c b/source/blender/makesrna/intern/rna_packedfile.c
index 34810e8a91b..f3da03714a1 100644
--- a/source/blender/makesrna/intern/rna_packedfile.c
+++ b/source/blender/makesrna/intern/rna_packedfile.c
@@ -35,7 +35,7 @@
#include "rna_internal.h"
-EnumPropertyItem unpack_method_items[] = {
+EnumPropertyItem rna_enum_unpack_method_items[] = {
{PF_USE_LOCAL, "USE_LOCAL", 0, "Use Local File", ""},
{PF_WRITE_LOCAL, "WRITE_LOCAL", 0, "Write Local File (overwrite existing)", ""},
{PF_USE_ORIGINAL, "USE_ORIGINAL", 0, "Use Original File", ""},
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 6676e9dc1c4..3f401a29945 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -175,7 +175,7 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, ParticleSy
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
psmd = (ParticleSystemModifierData *) md;
- if (psmd && psmd->dm && psmd->psys) {
+ if (psmd && psmd->dm_final && psmd->psys) {
psys = psmd->psys;
for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
/* hairkeys are stored sequentially in memory, so we can
@@ -210,7 +210,7 @@ static void rna_ParticleHairKey_location_object_get(PointerRNA *ptr, float *valu
}
else {
float hairmat[4][4];
- psys_mat_hair_to_object(ob, psmd->dm, psmd->psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(ob, psmd->dm_final, psmd->psys->part->from, pa, hairmat);
copy_v3_v3(values, hkey->co);
mul_m4_v3(hairmat, values);
}
@@ -240,7 +240,7 @@ static void rna_ParticleHairKey_location_object_set(PointerRNA *ptr, const float
float hairmat[4][4];
float imat[4][4];
- psys_mat_hair_to_object(ob, psmd->dm, psmd->psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(ob, psmd->dm_final, psmd->psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
copy_v3_v3(hkey->co, values);
mul_m4_v3(imat, hkey->co);
@@ -263,7 +263,7 @@ static void rna_ParticleHairKey_co_object(HairKey *hairkey, Object *object, Part
}
else {
float hairmat[4][4];
- psys_mat_hair_to_object(object, modifier->dm, modifier->psys->part->from, particle, hairmat);
+ psys_mat_hair_to_object(object, modifier->dm_final, modifier->psys->part->from, particle, hairmat);
copy_v3_v3(n_co, hairkey->co);
mul_m4_v3(hairmat, n_co);
}
@@ -282,14 +282,14 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *repor
int num = particle->num_dmcache;
int from = modifier->psys->part->from;
- if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) {
+ if (!CustomData_has_layer(&modifier->dm_final->loopData, CD_MLOOPUV)) {
BKE_report(reports, RPT_ERROR, "Mesh has no UV data");
return;
}
- DM_ensure_tessface(modifier->dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ DM_ensure_tessface(modifier->dm_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
if (num == DMCACHE_NOTFOUND)
- if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
+ if (particle->num < modifier->dm_final->getNumTessFaces(modifier->dm_final))
num = particle->num;
/* get uvco */
@@ -299,8 +299,8 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *repor
MFace *mface;
MTFace *mtface;
- mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
+ mface = modifier->dm_final->getTessFaceData(modifier->dm_final, num, CD_MFACE);
+ mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm_final->faceData, CD_MTFACE, 0);
if (mface && mtface) {
mtface += num;
@@ -446,8 +446,8 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
int totface;
int num = -1;
- DM_ensure_tessface(modifier->dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
- totface = modifier->dm->getNumTessFaces(modifier->dm);
+ DM_ensure_tessface(modifier->dm_final); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ totface = modifier->dm_final->getNumTessFaces(modifier->dm_final);
/* 1. check that everything is ok & updated */
if (!particlesystem || !totface) {
@@ -476,9 +476,6 @@ static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesys
if (particle_no < totpart) {
num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? particle->num : particle->num_dmcache;
- if (num == DMCACHE_NOTFOUND)
- num = particle->num;
-
if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
if (num != DMCACHE_NOTFOUND && num < totface) {
*r_fuv = &particle->fuv;
@@ -521,7 +518,7 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep
ParticleSystemModifierData *modifier, ParticleData *particle,
int particle_no, int uv_no, float r_uv[2])
{
- if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) {
+ if (!CustomData_has_layer(&modifier->dm_final->loopData, CD_MLOOPUV)) {
BKE_report(reports, RPT_ERROR, "Mesh has no UV data");
zero_v2(r_uv);
return;
@@ -538,8 +535,8 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep
zero_v2(r_uv);
}
else {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no);
+ MFace *mface = modifier->dm_final->getTessFaceData(modifier->dm_final, num, CD_MFACE);
+ MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm_final->faceData, CD_MTFACE, uv_no);
psys_interpolate_uvs(&mtface[num], mface->v4, *fuv, r_uv);
}
@@ -550,7 +547,7 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, R
ParticleSystemModifierData *modifier, ParticleData *particle,
int particle_no, int vcol_no, float r_mcol[3])
{
- if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPCOL)) {
+ if (!CustomData_has_layer(&modifier->dm_final->loopData, CD_MLOOPCOL)) {
BKE_report(reports, RPT_ERROR, "Mesh has no VCol data");
zero_v3(r_mcol);
return;
@@ -567,8 +564,8 @@ static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, R
zero_v3(r_mcol);
}
else {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no);
+ MFace *mface = modifier->dm_final->getTessFaceData(modifier->dm_final, num, CD_MFACE);
+ MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm_final->faceData, CD_MCOL, vcol_no);
MCol mcol;
psys_interpolate_mcol(&mc[num * 4], mface->v4, *fuv, &mcol);
@@ -751,13 +748,13 @@ static void rna_particle_settings_set(PointerRNA *ptr, PointerRNA value)
if (psys->part) {
old_type = psys->part->type;
- psys->part->id.us--;
+ id_us_min(&psys->part->id);
}
psys->part = (ParticleSettings *)value.data;
if (psys->part) {
- psys->part->id.us++;
+ id_us_plus(&psys->part->id);
psys_check_boid_data(psys);
if (old_type != psys->part->type)
psys->recalc |= PSYS_RECALC_TYPE;
@@ -1724,7 +1721,7 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ParticleSettingsTextureSlot", "TextureSlot");
RNA_def_struct_sdna(srna, "MTex");
RNA_def_struct_ui_text(srna, "Particle Settings Texture Slot",
- "Texture slot for textures in a Particle Settings datablock");
+ "Texture slot for textures in a Particle Settings data-block");
prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "texco");
@@ -1997,13 +1994,6 @@ static void rna_def_particle_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem kink_axis_items[] = {
- {0, "X", 0, "X", ""},
- {1, "Y", 0, "Y", ""},
- {2, "Z", 0, "Z", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
static EnumPropertyItem bb_align_items[] = {
{PART_BB_X, "X", 0, "X", ""},
{PART_BB_Y, "Y", 0, "Y", ""},
@@ -2233,7 +2223,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_hair_grid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HAIR_GRID);
- RNA_def_property_ui_text(prop, "Guide Hairs", "Show guide hairs");
+ RNA_def_property_ui_text(prop, "Guide Hairs", "Show hair simulation grid");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE);
@@ -2421,7 +2411,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
prop = RNA_def_property(srna, "kink_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, kink_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
RNA_def_property_ui_text(prop, "Axis", "Which axis to use for offset");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index e65023132c9..5bbc2b49a0d 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -49,7 +49,7 @@
/* XXX: this RNA enum define is currently duplicated for objects,
* since there is some text here which is not applicable */
-EnumPropertyItem posebone_rotmode_items[] = {
+EnumPropertyItem rna_enum_posebone_rotmode_items[] = {
{ROT_MODE_QUAT, "QUATERNION", 0, "Quaternion (WXYZ)", "No Gimbal Lock (default)"},
{ROT_MODE_XYZ, "XYZ", 0, "XYZ Euler", "XYZ Rotation Order (prone to Gimbal Lock)"},
{ROT_MODE_XZY, "XZY", 0, "XZY Euler", "XZY Rotation Order (prone to Gimbal Lock)"},
@@ -63,7 +63,7 @@ EnumPropertyItem posebone_rotmode_items[] = {
};
/* Bone and Group Color Sets */
-EnumPropertyItem color_sets_items[] = {
+EnumPropertyItem rna_enum_color_sets_items[] = {
{0, "DEFAULT", 0, "Default Colors", ""},
{1, "THEME01", 0, "01 - Theme Color Set", ""},
{2, "THEME02", 0, "02 - Theme Color Set", ""},
@@ -532,7 +532,7 @@ static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int typ
static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, ReportList *reports, PointerRNA *con_ptr)
{
bConstraint *con = con_ptr->data;
- const short is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK);
+ const bool is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK);
Object *ob = (Object *)id;
if (BLI_findindex(&pchan->constraints, con) == -1) {
@@ -675,7 +675,7 @@ void rna_def_actionbone_group_common(StructRNA *srna, int update_flag, const cha
/* color set + colors */
prop = RNA_def_property(srna, "color_set", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "customCol");
- RNA_def_property_enum_items(prop, color_sets_items);
+ RNA_def_property_enum_items(prop, rna_enum_color_sets_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_ActionGroup_colorset_set", NULL);
RNA_def_property_ui_text(prop, "Color Set", "Custom color set to use");
RNA_def_property_update(prop, update_flag, update_cb);
@@ -760,7 +760,7 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro
parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint");
RNA_def_function_return(func, parm);
/* constraint to add */
- parm = RNA_def_enum(func, "type", constraint_type_items, 1, "", "Constraint type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
func = RNA_def_function(srna, "remove", "rna_PoseChannel_constraints_remove");
@@ -865,7 +865,7 @@ static void rna_def_pose_channel(BlenderRNA *brna)
prop = RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "rotmode");
- RNA_def_property_enum_items(prop, posebone_rotmode_items); /* XXX move to using a single define of this someday */
+ RNA_def_property_enum_items(prop, rna_enum_posebone_rotmode_items); /* XXX move to using a single define of this someday */
RNA_def_property_enum_funcs(prop, NULL, "rna_PoseChannel_rotation_mode_set", NULL);
/* XXX... disabled, since proxy-locked layers are currently used for ensuring proxy-syncing too */
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
@@ -1062,6 +1062,17 @@ static void rna_def_pose_channel(BlenderRNA *brna)
RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable");
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+ prop = RNA_def_property(srna, "custom_shape_scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "custom_scale");
+ RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_text(prop, "Custom Shape Scale", "Adjust the size of the custom shape");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
+ prop = RNA_def_property(srna, "use_custom_shape_bone_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "drawflag", PCHAN_DRAW_NO_CUSTOM_BONE_SIZE);
+ RNA_def_property_ui_text(prop, "Use Bone Size", "Scale the custom object by the bone length");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+
prop = RNA_def_property(srna, "custom_shape_transform", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "custom_tx");
RNA_def_property_struct_type(prop, "PoseBone");
diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c
index 454816d4e0a..07bdbb03357 100644
--- a/source/blender/makesrna/intern/rna_property.c
+++ b/source/blender/makesrna/intern/rna_property.c
@@ -42,7 +42,7 @@
#include "WM_types.h"
-EnumPropertyItem gameproperty_type_items[] = {
+EnumPropertyItem rna_enum_gameproperty_type_items[] = {
{GPROP_BOOL, "BOOL", 0, "Boolean", "Boolean Property"},
{GPROP_INT, "INT", 0, "Integer", "Integer Property"},
{GPROP_FLOAT, "FLOAT", 0, "Float", "Floating-Point Property"},
@@ -130,7 +130,7 @@ void RNA_def_gameproperty(BlenderRNA *brna)
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, gameproperty_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_gameproperty_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_enum_funcs(prop, NULL, "rna_GameProperty_type_set", NULL);
RNA_def_property_update(prop, NC_LOGIC, NULL);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 61eb2c69bfe..84382704b2b 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -41,7 +41,7 @@
#include "RE_pipeline.h"
-EnumPropertyItem render_pass_type_items[] = {
+EnumPropertyItem rna_enum_render_pass_type_items[] = {
{SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{SCE_PASS_Z, "Z", 0, "Z", ""},
{SCE_PASS_RGBA, "COLOR", 0, "Color", ""},
@@ -77,13 +77,28 @@ EnumPropertyItem render_pass_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem render_pass_debug_type_items[] = {
+EnumPropertyItem rna_enum_render_pass_debug_type_items[] = {
{RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, "BVH_TRAVERSAL_STEPS", 0, "BVH Traversal Steps", ""},
{RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES, "BVH_TRAVERSED_INSTANCES", 0, "BVH Traversed Instances", ""},
{RENDER_PASS_DEBUG_RAY_BOUNCES, "RAY_BOUNCES", 0, "Ray Steps", ""},
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_bake_pass_type_items[] = {
+ {SCE_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
+ {SCE_PASS_AO, "AO", 0, "AO", ""},
+ {SCE_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
+ {SCE_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SCE_PASS_UV, "UV", 0, "UV", ""},
+ {SCE_PASS_EMIT, "EMIT", 0, "Emit", ""},
+ {SCE_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
+ {SCE_PASS_DIFFUSE_COLOR, "DIFFUSE", 0, "Diffuse", ""},
+ {SCE_PASS_GLOSSY_COLOR, "GLOSSY", 0, "Glossy", ""},
+ {SCE_PASS_TRANSM_COLOR, "TRANSMISSION", 0, "Transmission", ""},
+ {SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE", 0, "Subsurface", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "MEM_guardedalloc.h"
@@ -162,7 +177,7 @@ static void engine_render(RenderEngine *engine, struct Scene *scene)
}
static void engine_bake(RenderEngine *engine, struct Scene *scene,
- struct Object *object, const int pass_type,
+ struct Object *object, const int pass_type, const int pass_filter,
const int object_id, const struct BakePixel *pixel_array,
const int num_pixels, const int depth, void *result)
{
@@ -178,6 +193,7 @@ static void engine_bake(RenderEngine *engine, struct Scene *scene,
RNA_parameter_set_lookup(&list, "scene", &scene);
RNA_parameter_set_lookup(&list, "object", &object);
RNA_parameter_set_lookup(&list, "pass_type", &pass_type);
+ RNA_parameter_set_lookup(&list, "pass_filter", &pass_filter);
RNA_parameter_set_lookup(&list, "object_id", &object_id);
RNA_parameter_set_lookup(&list, "pixel_array", &pixel_array);
RNA_parameter_set_lookup(&list, "num_pixels", &num_pixels);
@@ -432,7 +448,9 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_pointer(func, "object", "Object", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
- prop = RNA_def_enum(func, "pass_type", render_pass_type_items, 0, "Pass", "Pass to bake");
+ prop = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake");
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_REQUIRED);
@@ -504,6 +522,10 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_boolean(func, "do_break", 0, "Break", "");
RNA_def_function_return(func, prop);
+ func = RNA_def_function(srna, "active_view_get", "RE_engine_active_view_get");
+ prop = RNA_def_string(func, "view", NULL, 0, "View", "Single view active");
+ RNA_def_function_return(func, prop);
+
func = RNA_def_function(srna, "active_view_set", "RE_engine_active_view_set");
RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */
RNA_def_property_flag(prop, PROP_REQUIRED);
@@ -511,15 +533,23 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "camera_shift_x", "RE_engine_get_camera_shift_x");
prop = RNA_def_pointer(func, "camera", "Object", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
prop = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX);
RNA_def_function_return(func, prop);
func = RNA_def_function(srna, "camera_model_matrix", "RE_engine_get_camera_model_matrix");
prop = RNA_def_pointer(func, "camera", "Object", "", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f);
RNA_def_property_flag(prop, PROP_REQUIRED);
+ func = RNA_def_function(srna, "use_spherical_stereo", "RE_engine_get_spherical_stereo");
+ prop = RNA_def_pointer(func, "camera", "Object", "", "");
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", "");
+ RNA_def_function_return(func, prop);
+
func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats");
RNA_def_function_ui_description(func, "Update and signal to redraw render status text");
prop = RNA_def_string(func, "stats", NULL, 0, "Stats", "");
@@ -547,7 +577,7 @@ static void rna_def_render_engine(BlenderRNA *brna)
func = RNA_def_function(srna, "report", "RE_engine_report");
RNA_def_function_ui_description(func, "Report info, warning or error messages");
- prop = RNA_def_enum_flag(func, "type", wm_report_items, 0, "Type", "");
+ prop = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
prop = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
@@ -649,6 +679,10 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SAVE_BUFFERS);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ prop = RNA_def_property(srna, "bl_use_spherical_stereo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_SPHERICAL_STEREO);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
RNA_define_verify_sdna(1);
}
@@ -726,7 +760,7 @@ static void rna_def_render_passes(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "find_by_type", "rna_RenderPass_find_by_type");
RNA_def_function_ui_description(func, "Get the render pass for a given type and view");
- parm = RNA_def_enum(func, "pass_type", render_pass_type_items, SCE_PASS_COMBINED, "Pass", "");
+ parm = RNA_def_enum(func, "pass_type", rna_enum_render_pass_type_items, SCE_PASS_COMBINED, "Pass", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */
RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -794,7 +828,7 @@ static void rna_def_render_pass(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "passtype");
- RNA_def_property_enum_items(prop, render_pass_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_render_pass_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "rect", PROP_FLOAT, PROP_NONE);
@@ -809,7 +843,7 @@ static void rna_def_render_pass(BlenderRNA *brna)
prop = RNA_def_property(srna, "debug_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "debug_type");
- RNA_def_property_enum_items(prop, render_pass_debug_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_render_pass_debug_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_define_verify_sdna(1);
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index 58a12f62644..bdf001ed0e1 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -44,16 +44,16 @@
#include "WM_types.h"
/* roles of objects in RigidBody Sims */
-EnumPropertyItem rigidbody_object_type_items[] = {
+EnumPropertyItem rna_enum_rigidbody_object_type_items[] = {
{RBO_TYPE_ACTIVE, "ACTIVE", 0, "Active", "Object is directly controlled by simulation results"},
{RBO_TYPE_PASSIVE, "PASSIVE", 0, "Passive", "Object is directly controlled by animation system"},
{0, NULL, 0, NULL, NULL}};
/* collision shapes of objects in rigid body sim */
-EnumPropertyItem rigidbody_object_shape_items[] = {
+EnumPropertyItem rna_enum_rigidbody_object_shape_items[] = {
{RB_SHAPE_BOX, "BOX", ICON_MESH_CUBE, "Box", "Box-like shapes (i.e. cubes), including planes (i.e. ground planes)"},
{RB_SHAPE_SPHERE, "SPHERE", ICON_MESH_UVSPHERE, "Sphere", ""},
- {RB_SHAPE_CAPSULE, "CAPSULE", ICON_OUTLINER_OB_META, "Capsule", ""},
+ {RB_SHAPE_CAPSULE, "CAPSULE", ICON_MESH_CAPSULE, "Capsule", ""},
{RB_SHAPE_CYLINDER, "CYLINDER", ICON_MESH_CYLINDER, "Cylinder", ""},
{RB_SHAPE_CONE, "CONE", ICON_MESH_CONE, "Cone", ""},
{RB_SHAPE_CONVEXH, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull",
@@ -64,7 +64,7 @@ EnumPropertyItem rigidbody_object_shape_items[] = {
{0, NULL, 0, NULL, NULL}};
/* collision shapes of constraints in rigid body sim */
-EnumPropertyItem rigidbody_constraint_type_items[] = {
+EnumPropertyItem rna_enum_rigidbody_constraint_type_items[] = {
{RBC_TYPE_FIXED, "FIXED", ICON_NONE, "Fixed", "Glue rigid bodies together"},
{RBC_TYPE_POINT, "POINT", ICON_NONE, "Point", "Constrain rigid bodies to move around common pivot point"},
{RBC_TYPE_HINGE, "HINGE", ICON_NONE, "Hinge", "Restrict rigid body rotation to one axis"},
@@ -781,7 +781,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, rigidbody_object_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_rigidbody_object_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_type_set", NULL);
RNA_def_property_ui_text(prop, "Type", "Role of object in Rigid Body Simulations");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -803,7 +803,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_shape", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "shape");
- RNA_def_property_enum_items(prop, rigidbody_object_shape_items);
+ RNA_def_property_enum_items(prop, rna_enum_rigidbody_object_shape_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_shape_set", NULL);
RNA_def_property_ui_text(prop, "Collision Shape", "Collision Shape of object in Rigid Body Simulations");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -946,7 +946,7 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, rigidbody_constraint_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_rigidbody_constraint_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyCon_type_set", NULL);
RNA_def_property_ui_text(prop, "Type", "Type of Rigid Body Constraint");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 4650e27f63e..727bdac087b 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -36,7 +36,7 @@
#include "rna_internal.h"
-EnumPropertyItem property_type_items[] = {
+EnumPropertyItem rna_enum_property_type_items[] = {
{PROP_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
{PROP_INT, "INT", 0, "Integer", ""},
{PROP_FLOAT, "FLOAT", 0, "Float", ""},
@@ -50,7 +50,7 @@ EnumPropertyItem property_type_items[] = {
/* XXX Keep in sync with bpy_props.c's property_subtype_xxx_items ???
* Currently it is not...
*/
-EnumPropertyItem property_subtype_items[] = {
+EnumPropertyItem rna_enum_property_subtype_items[] = {
{PROP_NONE, "NONE", 0, "None", ""},
/* strings */
@@ -90,7 +90,7 @@ EnumPropertyItem property_subtype_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem property_unit_items[] = {
+EnumPropertyItem rna_enum_property_unit_items[] = {
{PROP_UNIT_NONE, "NONE", 0, "None", ""},
{PROP_UNIT_LENGTH, "LENGTH", 0, "Length", ""},
{PROP_UNIT_AREA, "AREA", 0, "Area", ""},
@@ -652,6 +652,13 @@ static int rna_NumberProperty_default_array_get_length(PointerRNA *ptr, int leng
return length[0];
}
+static int rna_NumberProperty_is_array_get(PointerRNA *ptr)
+{
+ PropertyRNA *prop = (PropertyRNA *)ptr->data;
+
+ return RNA_property_array_check(prop);
+}
+
static void rna_IntProperty_default_array_get(PointerRNA *ptr, int *values)
{
PropertyRNA *prop = (PropertyRNA *)ptr->data;
@@ -854,7 +861,8 @@ static void rna_EnumProperty_items_begin(CollectionPropertyIterator *iter, Point
rna_idproperty_check(&prop, ptr);
/* eprop = (EnumPropertyRNA *)prop; */
- RNA_property_enum_items(NULL, ptr, prop, &item, &totitem, &free);
+ RNA_property_enum_items_ex(
+ NULL, ptr, prop, STREQ(iter->prop->identifier, "enum_items_static"), &item, &totitem, &free);
rna_iterator_array_begin(iter, (void *)item, sizeof(EnumPropertyItem), totitem, free, rna_enum_check_separator);
}
@@ -952,13 +960,13 @@ static void rna_Function_parameters_begin(CollectionPropertyIterator *iter, Poin
static int rna_Function_registered_get(PointerRNA *ptr)
{
FunctionRNA *func = (FunctionRNA *)ptr->data;
- return func->flag & FUNC_REGISTER;
+ return 0 != (func->flag & FUNC_REGISTER);
}
static int rna_Function_registered_optional_get(PointerRNA *ptr)
{
FunctionRNA *func = (FunctionRNA *)ptr->data;
- return func->flag & (FUNC_REGISTER_OPTIONAL & ~FUNC_REGISTER);
+ return 0 != (func->flag & (FUNC_REGISTER_OPTIONAL & ~FUNC_REGISTER));
}
static int rna_Function_no_self_get(PointerRNA *ptr)
@@ -970,7 +978,7 @@ static int rna_Function_no_self_get(PointerRNA *ptr)
static int rna_Function_use_self_type_get(PointerRNA *ptr)
{
FunctionRNA *func = (FunctionRNA *)ptr->data;
- return (func->flag & FUNC_USE_SELF_TYPE);
+ return 0 != (func->flag & FUNC_USE_SELF_TYPE);
}
/* Blender RNA */
@@ -1138,7 +1146,7 @@ static void rna_def_property(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, property_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_property_type_items);
RNA_def_property_enum_funcs(prop, "rna_Property_type_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Type", "Data type of the property");
@@ -1156,13 +1164,13 @@ static void rna_def_property(BlenderRNA *brna)
prop = RNA_def_property(srna, "unit", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, property_unit_items);
+ RNA_def_property_enum_items(prop, rna_enum_property_unit_items);
RNA_def_property_enum_funcs(prop, "rna_Property_unit_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Unit", "Type of units for this property");
prop = RNA_def_property(srna, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
RNA_def_property_enum_funcs(prop, "rna_Property_icon_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Icon", "Icon of the item");
@@ -1336,6 +1344,11 @@ static void rna_def_number_property(StructRNA *srna, PropertyType type)
RNA_def_property_int_funcs(prop, "rna_Property_array_length_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Array Length", "Maximum length of the array, 0 means unlimited");
+ prop = RNA_def_property(srna, "is_array", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_NumberProperty_is_array_get", NULL);
+ RNA_def_property_ui_text(prop, "Is Array", "");
+
if (type == PROP_BOOLEAN)
return;
@@ -1423,6 +1436,14 @@ static void rna_def_enum_property(BlenderRNA *brna, StructRNA *srna)
"rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Items", "Possible values for the property");
+ prop = RNA_def_property(srna, "enum_items_static", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "EnumPropertyItem");
+ RNA_def_property_collection_funcs(prop, "rna_EnumProperty_items_begin", "rna_iterator_array_next",
+ "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Static Items",
+ "Possible values for the property (never calls optional dynamic generation of those)");
+
srna = RNA_def_struct(brna, "EnumPropertyItem", NULL);
RNA_def_struct_ui_text(srna, "Enum Item Definition", "Definition of a choice in an RNA enum property");
RNA_def_struct_ui_icon(srna, ICON_RNA);
@@ -1452,7 +1473,7 @@ static void rna_def_enum_property(BlenderRNA *brna, StructRNA *srna)
prop = RNA_def_property(srna, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
RNA_def_property_enum_funcs(prop, "rna_EnumPropertyItem_icon_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Icon", "Icon of the item");
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 176c218e378..71d1df91c5d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -76,7 +76,7 @@
#include "BLI_threads.h"
#ifdef WITH_OPENEXR
-EnumPropertyItem exr_codec_items[] = {
+EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_NONE, "NONE", 0, "None", ""},
{R_IMF_EXR_CODEC_PXR24, "PXR24", 0, "Pxr24 (lossy)", ""},
{R_IMF_EXR_CODEC_ZIP, "ZIP", 0, "ZIP (lossless)", ""},
@@ -105,7 +105,7 @@ EnumPropertyItem uv_sculpt_tool_items[] = {
};
-EnumPropertyItem snap_target_items[] = {
+EnumPropertyItem rna_enum_snap_target_items[] = {
{SCE_SNAP_TARGET_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
{SCE_SNAP_TARGET_CENTER, "CENTER", 0, "Center", "Snap center onto target"},
{SCE_SNAP_TARGET_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
@@ -113,7 +113,7 @@ EnumPropertyItem snap_target_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem proportional_falloff_items[] = {
+EnumPropertyItem rna_enum_proportional_falloff_items[] = {
{PROP_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "Smooth falloff"},
{PROP_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", "Spherical falloff"},
{PROP_ROOT, "ROOT", ICON_ROOTCURVE, "Root", "Root falloff"},
@@ -126,7 +126,7 @@ EnumPropertyItem proportional_falloff_items[] = {
};
/* subset of the enum - only curves, missing random and const */
-EnumPropertyItem proportional_falloff_curve_only_items[] = {
+EnumPropertyItem rna_enum_proportional_falloff_curve_only_items[] = {
{PROP_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "Smooth falloff"},
{PROP_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", "Spherical falloff"},
{PROP_ROOT, "ROOT", ICON_ROOTCURVE, "Root", "Root falloff"},
@@ -137,7 +137,7 @@ EnumPropertyItem proportional_falloff_curve_only_items[] = {
};
-EnumPropertyItem proportional_editing_items[] = {
+EnumPropertyItem rna_enum_proportional_editing_items[] = {
{PROP_EDIT_OFF, "DISABLED", ICON_PROP_OFF, "Disable", "Proportional Editing disabled"},
{PROP_EDIT_ON, "ENABLED", ICON_PROP_ON, "Enable", "Proportional Editing enabled"},
{PROP_EDIT_PROJECTED, "PROJECTED", ICON_PROP_ON, "Projected (2D)",
@@ -148,14 +148,14 @@ EnumPropertyItem proportional_editing_items[] = {
};
/* keep for operators, not used here */
-EnumPropertyItem mesh_select_mode_items[] = {
+EnumPropertyItem rna_enum_mesh_select_mode_items[] = {
{SCE_SELECT_VERTEX, "VERTEX", ICON_VERTEXSEL, "Vertex", "Vertex selection mode"},
{SCE_SELECT_EDGE, "EDGE", ICON_EDGESEL, "Edge", "Edge selection mode"},
{SCE_SELECT_FACE, "FACE", ICON_FACESEL, "Face", "Face selection mode"},
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem snap_element_items[] = {
+EnumPropertyItem rna_enum_snap_element_items[] = {
{SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
@@ -164,7 +164,7 @@ EnumPropertyItem snap_element_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem snap_node_element_items[] = {
+EnumPropertyItem rna_enum_snap_node_element_items[] = {
{SCE_SNAP_MODE_GRID, "GRID", ICON_SNAP_GRID, "Grid", "Snap to grid"},
{SCE_SNAP_MODE_NODE_X, "NODE_X", ICON_SNAP_EDGE, "Node X", "Snap to left/right node border"},
{SCE_SNAP_MODE_NODE_Y, "NODE_Y", ICON_SNAP_EDGE, "Node Y", "Snap to top/bottom node border"},
@@ -264,7 +264,7 @@ EnumPropertyItem image_only_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem image_type_items[] = {
+EnumPropertyItem rna_enum_image_type_items[] = {
{0, "", 0, N_("Image"), NULL},
IMAGE_TYPE_ITEMS_IMAGE_ONLY
@@ -289,7 +289,7 @@ EnumPropertyItem image_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem image_color_mode_items[] = {
+EnumPropertyItem rna_enum_image_color_mode_items[] = {
{R_IMF_PLANES_BW, "BW", 0, "BW", "Images get saved in 8 bits grayscale (only PNG, JPEG, TGA, TIF)"},
{R_IMF_PLANES_RGB, "RGB", 0, "RGB", "Images are saved with RGB (color) data"},
{R_IMF_PLANES_RGBA, "RGBA", 0, "RGBA", "Images are saved with RGB and Alpha data (if supported)"},
@@ -297,12 +297,12 @@ EnumPropertyItem image_color_mode_items[] = {
};
#ifdef RNA_RUNTIME
-#define IMAGE_COLOR_MODE_BW image_color_mode_items[0]
-#define IMAGE_COLOR_MODE_RGB image_color_mode_items[1]
-#define IMAGE_COLOR_MODE_RGBA image_color_mode_items[2]
+#define IMAGE_COLOR_MODE_BW rna_enum_image_color_mode_items[0]
+#define IMAGE_COLOR_MODE_RGB rna_enum_image_color_mode_items[1]
+#define IMAGE_COLOR_MODE_RGBA rna_enum_image_color_mode_items[2]
#endif
-EnumPropertyItem image_color_depth_items[] = {
+EnumPropertyItem rna_enum_image_color_depth_items[] = {
/* 1 (monochrome) not used */
{R_IMF_CHAN_DEPTH_8, "8", 0, "8", "8 bit color channels"},
{R_IMF_CHAN_DEPTH_10, "10", 0, "10", "10 bit color channels"},
@@ -313,13 +313,13 @@ EnumPropertyItem image_color_depth_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem normal_space_items[] = {
+EnumPropertyItem rna_enum_normal_space_items[] = {
{R_BAKE_SPACE_OBJECT, "OBJECT", 0, "Object", "Bake the normals in object space"},
{R_BAKE_SPACE_TANGENT, "TANGENT", 0, "Tangent", "Bake the normals in tangent space"},
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem normal_swizzle_items[] = {
+EnumPropertyItem rna_enum_normal_swizzle_items[] = {
{R_BAKE_POSX, "POS_X", 0, "+X", ""},
{R_BAKE_POSY, "POS_Y", 0, "+Y", ""},
{R_BAKE_POSZ, "POS_Z", 0, "+Z", ""},
@@ -329,8 +329,8 @@ EnumPropertyItem normal_swizzle_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem bake_save_mode_items[] = {
- {R_BAKE_SAVE_INTERNAL, "INTERNAL", 0, "Internal", "Save the baking map in an internal image datablock"},
+EnumPropertyItem rna_enum_bake_save_mode_items[] = {
+ {R_BAKE_SAVE_INTERNAL, "INTERNAL", 0, "Internal", "Save the baking map in an internal image data-block"},
{R_BAKE_SAVE_EXTERNAL, "EXTERNAL", 0, "External", "Save the baking map in an external file"},
{0, NULL, 0, NULL, NULL}
};
@@ -341,19 +341,19 @@ EnumPropertyItem bake_save_mode_items[] = {
"Single file with an encoded stereo pair"},
#define R_IMF_VIEWS_ENUM_MV {R_IMF_VIEWS_MULTIVIEW, "MULTIVIEW", 0, "Multi-View", "Single file with all the views"},
-EnumPropertyItem views_format_items[] = {
+EnumPropertyItem rna_enum_views_format_items[] = {
R_IMF_VIEWS_ENUM_IND
R_IMF_VIEWS_ENUM_S3D
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem views_format_multilayer_items[] = {
+EnumPropertyItem rna_enum_views_format_multilayer_items[] = {
R_IMF_VIEWS_ENUM_IND
R_IMF_VIEWS_ENUM_MV
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem views_format_multiview_items[] = {
+EnumPropertyItem rna_enum_views_format_multiview_items[] = {
R_IMF_VIEWS_ENUM_IND
R_IMF_VIEWS_ENUM_S3D
R_IMF_VIEWS_ENUM_MV
@@ -364,7 +364,7 @@ EnumPropertyItem views_format_multiview_items[] = {
#undef R_IMF_VIEWS_ENUM_S3D
#undef R_IMF_VIEWS_ENUM_MV
-EnumPropertyItem stereo3d_display_items[] = {
+EnumPropertyItem rna_enum_stereo3d_display_items[] = {
{S3D_DISPLAY_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph",
"Render views for left and right eyes as two differently filtered colors in a single image "
"(anaglyph glasses are required)"},
@@ -377,20 +377,34 @@ EnumPropertyItem stereo3d_display_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem stereo3d_anaglyph_type_items[] = {
+EnumPropertyItem rna_enum_stereo3d_anaglyph_type_items[] = {
{S3D_ANAGLYPH_REDCYAN, "RED_CYAN", 0, "Red-Cyan", ""},
{S3D_ANAGLYPH_GREENMAGENTA, "GREEN_MAGENTA", 0, "Green-Magenta", ""},
{S3D_ANAGLYPH_YELLOWBLUE, "YELLOW_BLUE", 0, "Yellow-Blue", ""},
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem stereo3d_interlace_type_items[] = {
+EnumPropertyItem rna_enum_stereo3d_interlace_type_items[] = {
{S3D_INTERLACE_ROW, "ROW_INTERLEAVED", 0, "Row Interleaved", ""},
{S3D_INTERLACE_COLUMN, "COLUMN_INTERLEAVED", 0, "Column Interleaved", ""},
{S3D_INTERLACE_CHECKERBOARD, "CHECKERBOARD_INTERLEAVED", 0, "Checkerboard Interleaved", ""},
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = {
+ {R_BAKE_PASS_FILTER_NONE, "NONE", 0, "None", ""},
+ {R_BAKE_PASS_FILTER_AO, "AO", 0, "AO", ""},
+ {R_BAKE_PASS_FILTER_EMIT, "EMIT", 0, "Emit", ""},
+ {R_BAKE_PASS_FILTER_DIRECT, "DIRECT", 0, "Direct", ""},
+ {R_BAKE_PASS_FILTER_INDIRECT, "INDIRECT", 0, "Indirect", ""},
+ {R_BAKE_PASS_FILTER_COLOR, "COLOR", 0, "Color", ""},
+ {R_BAKE_PASS_FILTER_DIFFUSE, "DIFFUSE", 0, "Diffuse", ""},
+ {R_BAKE_PASS_FILTER_GLOSSY, "GLOSSY", 0, "Glossy", ""},
+ {R_BAKE_PASS_FILTER_TRANSM, "TRANSMISSION", 0, "Transmission", ""},
+ {R_BAKE_PASS_FILTER_SUBSURFACE, "SUBSURFACE", 0, "Subsurface", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
#ifdef RNA_RUNTIME
#include "DNA_anim_types.h"
@@ -508,7 +522,7 @@ static void rna_Scene_object_unlink(Scene *scene, ReportList *reports, Object *o
BKE_scene_base_unlink(scene, base);
MEM_freeN(base);
- ob->id.us--;
+ id_us_min(&ob->id);
/* needed otherwise the depgraph will contain freed objects which can crash, see [#20958] */
DAG_relations_tag_update(G.main);
@@ -554,6 +568,7 @@ static void rna_Scene_set_set(PointerRNA *ptr, PointerRNA value)
return;
}
+ id_lib_extern((ID *)set);
scene->set = set;
}
@@ -845,7 +860,7 @@ static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value)
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->id.data;
- const char is_render = (id && GS(id->name) == ID_SCE);
+ const bool is_render = (id && GS(id->name) == ID_SCE);
/* see note below on why this is */
const char chan_flag = BKE_imtype_valid_channels(imf->imtype, true) | (is_render ? IMA_CHAN_FLAG_BW : 0);
@@ -900,7 +915,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_file_format_itemf(
{
ID *id = ptr->id.data;
if (id && GS(id->name) == ID_SCE) {
- return image_type_items;
+ return rna_enum_image_type_items;
}
else {
return image_only_type_items;
@@ -912,7 +927,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(
{
ImageFormatData *imf = (ImageFormatData *)ptr->data;
ID *id = ptr->id.data;
- const char is_render = (id && GS(id->name) == ID_SCE);
+ const bool is_render = (id && GS(id->name) == ID_SCE);
/* note, we need to act differently for render
* where 'BW' will force grayscale even if the output format writes
@@ -935,7 +950,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_mode_itemf(
#endif
if (chan_flag == (IMA_CHAN_FLAG_BW | IMA_CHAN_FLAG_RGB | IMA_CHAN_FLAG_ALPHA)) {
- return image_color_mode_items;
+ return rna_enum_image_color_mode_items;
}
else {
int totitem = 0;
@@ -958,17 +973,17 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(
ImageFormatData *imf = (ImageFormatData *)ptr->data;
if (imf == NULL) {
- return image_color_depth_items;
+ return rna_enum_image_color_depth_items;
}
else {
const int depth_ok = BKE_imtype_valid_depths(imf->imtype);
const int is_float = ELEM(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER);
- EnumPropertyItem *item_8bit = &image_color_depth_items[0];
- EnumPropertyItem *item_10bit = &image_color_depth_items[1];
- EnumPropertyItem *item_12bit = &image_color_depth_items[2];
- EnumPropertyItem *item_16bit = &image_color_depth_items[3];
- EnumPropertyItem *item_32bit = &image_color_depth_items[4];
+ EnumPropertyItem *item_8bit = &rna_enum_image_color_depth_items[0];
+ EnumPropertyItem *item_10bit = &rna_enum_image_color_depth_items[1];
+ EnumPropertyItem *item_12bit = &rna_enum_image_color_depth_items[2];
+ EnumPropertyItem *item_16bit = &rna_enum_image_color_depth_items[3];
+ EnumPropertyItem *item_32bit = &rna_enum_image_color_depth_items[4];
int totitem = 0;
EnumPropertyItem *item = NULL;
@@ -1021,16 +1036,16 @@ static EnumPropertyItem *rna_ImageFormatSettings_views_format_itemf(
ImageFormatData *imf = (ImageFormatData *)ptr->data;
if (imf == NULL) {
- return views_format_items;
+ return rna_enum_views_format_items;
}
else if (imf->imtype == R_IMF_IMTYPE_OPENEXR) {
- return views_format_multiview_items;
+ return rna_enum_views_format_multiview_items;
}
else if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
- return views_format_multilayer_items;
+ return rna_enum_views_format_multilayer_items;
}
else {
- return views_format_items;
+ return rna_enum_views_format_items;
}
}
@@ -1046,14 +1061,14 @@ static EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(
int i = 1, totitem = 0;
if (imf->depth == 16)
- return exr_codec_items; /* All compression types are defined for halfs */
+ return rna_enum_exr_codec_items; /* All compression types are defined for halfs */
for (i = 0; i < R_IMF_EXR_CODEC_MAX; i++) {
if ((i == R_IMF_EXR_CODEC_B44 || i == R_IMF_EXR_CODEC_B44A)) {
continue; /* B44 and B44A are not defined for 32 bit floats */
}
- RNA_enum_item_add(&item, &totitem, &exr_codec_items[i]);
+ RNA_enum_item_add(&item, &totitem, &rna_enum_exr_codec_items[i]);
}
RNA_enum_item_end(&item, &totitem);
@@ -1455,6 +1470,12 @@ static int rna_RenderSettings_use_shading_nodes_get(PointerRNA *ptr)
return BKE_scene_use_new_shading_nodes(scene);
}
+static int rna_RenderSettings_use_spherical_stereo_get(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+ return BKE_scene_use_spherical_stereo(scene);
+}
+
static int rna_RenderSettings_use_game_engine_get(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -1538,11 +1559,11 @@ static void object_simplify_update(Object *ob)
ModifierData *md;
ParticleSystem *psys;
- if ((ob->id.flag & LIB_DOIT) == 0) {
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
return;
}
- ob->id.flag &= ~LIB_DOIT;
+ ob->id.tag &= ~LIB_TAG_DOIT;
for (md = ob->modifiers.first; md; md = md->next) {
if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) {
@@ -1567,7 +1588,7 @@ static void rna_Scene_use_simplify_update(Main *bmain, Scene *UNUSED(scene), Poi
Scene *sce_iter;
Base *base;
- BKE_main_id_tag_listbase(&bmain->object, true);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
for (SETLOOPER(sce, sce_iter, base))
object_simplify_update(base->object);
@@ -1746,6 +1767,11 @@ static char *rna_UnifiedPaintSettings_path(PointerRNA *UNUSED(ptr))
return BLI_strdup("tool_settings.unified_paint_settings");
}
+static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.curve_paint_settings");
+}
+
/* generic function to recalc geometry */
static void rna_EditMesh_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
@@ -1814,9 +1840,9 @@ static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value
FreestyleLineSet *lineset = (FreestyleLineSet *)ptr->data;
if (lineset->linestyle)
- lineset->linestyle->id.us--;
+ id_us_min(&lineset->linestyle->id);
lineset->linestyle = (FreestyleLineStyle *)value.data;
- lineset->linestyle->id.us++;
+ id_us_plus(&lineset->linestyle->id);
}
static FreestyleLineSet *rna_FreestyleSettings_lineset_add(
@@ -1950,7 +1976,7 @@ static void rna_Stereo3dFormat_update(Main *UNUSED(bmain), Scene *UNUSED(scene),
ImBuf *ibuf;
void *lock;
- if ((ima->flag & IMA_IS_STEREO) == 0)
+ if (!BKE_image_is_stereo(ima))
return;
ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
@@ -2051,16 +2077,24 @@ static void rna_def_tool_settings(BlenderRNA *brna)
};
static EnumPropertyItem gpencil_source_3d_items[] = {
- {GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene",
+ {GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene",
"Grease Pencil data attached to the current scene is used, "
- "unless the active object already has Grease Pencil data (i.e. for old files)"},
+ "unless the active object already has Grease Pencil data (i.e. for old files)"},
{GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object",
- "Grease Pencil datablocks attached to the active object are used "
- "(required using pre 2.73 add-ons, e.g. BSurfaces)"},
+ "Grease Pencil data-blocks attached to the active object are used "
+ "(required when using pre 2.73 add-ons, e.g. BSurfaces)"},
{0, NULL, 0, NULL, NULL}
};
-
-
+
+ static EnumPropertyItem gpencil_stroke_placement_items[] = {
+ {GP_PROJECT_VIEWSPACE, "CURSOR", 0, "Cursor", "Draw stroke at the 3D cursor"},
+ {0, "VIEW", 0, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", 0, "Surface", "Stick stroke to surfaces"},
+ {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", 0, "Stroke", "Stick stroke to other strokes"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+
srna = RNA_def_struct(brna, "ToolSettings", NULL);
RNA_def_struct_path_func(srna, "rna_ToolSettings_path");
RNA_def_struct_ui_text(srna, "Tool Settings", "");
@@ -2079,14 +2113,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_multipaint", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "multipaint", 1);
RNA_def_property_ui_text(prop, "WPaint Multi-Paint",
- "Paint across all selected bones while "
- "weight painting");
+ "Paint across the weights of all selected bones, "
+ "maintaining their relative influence");
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_group_user", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "weightuser");
RNA_def_property_enum_items(prop, draw_groupuser_items);
- RNA_def_property_ui_text(prop, "Mask Non-Group Vertices", "Display unweighted vertices (multi-paint overrides)");
+ RNA_def_property_ui_text(prop, "Mask Non-Group Vertices", "Display unweighted vertices");
RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data");
prop = RNA_def_property(srna, "vertex_group_subset", PROP_ENUM, PROP_NONE);
@@ -2141,7 +2175,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
/* Transform */
prop = RNA_def_property(srna, "proportional_edit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "proportional");
- RNA_def_property_enum_items(prop, proportional_editing_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_editing_items);
RNA_def_property_ui_text(prop, "Proportional Editing",
"Proportional Editing mode, allows transforms with distance fall-off");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -2176,7 +2210,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "proportional_edit_falloff", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "prop_mode");
- RNA_def_property_enum_items(prop, proportional_falloff_items);
+ RNA_def_property_enum_items(prop, rna_enum_proportional_falloff_items);
RNA_def_property_ui_text(prop, "Proportional Editing Falloff", "Falloff type for proportional editing mode");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -2224,14 +2258,14 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "snap_element", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_mode");
- RNA_def_property_enum_items(prop, snap_element_items);
+ RNA_def_property_enum_items(prop, rna_enum_snap_element_items);
RNA_def_property_ui_text(prop, "Snap Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
/* node editor uses own set of snap modes */
prop = RNA_def_property(srna, "snap_node_element", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_node_mode");
- RNA_def_property_enum_items(prop, snap_node_element_items);
+ RNA_def_property_enum_items(prop, rna_enum_snap_node_element_items);
RNA_def_property_ui_text(prop, "Snap Node Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -2244,7 +2278,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_target");
- RNA_def_property_enum_items(prop, snap_target_items);
+ RNA_def_property_enum_items(prop, rna_enum_snap_target_items);
RNA_def_property_ui_text(prop, "Snap Target", "Which part to snap onto the target");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -2268,12 +2302,19 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
/* Grease Pencil */
- prop = RNA_def_property(srna, "use_grease_pencil_sessions", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_gpencil_continuous_drawing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINTSESSIONS_ON);
- RNA_def_property_ui_text(prop, "Use Sketching Sessions",
+ RNA_def_property_ui_text(prop, "Use Continuous Drawing",
"Allow drawing multiple strokes at a time with Grease Pencil");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* xxx: need toolbar to be redrawn... */
+ prop = RNA_def_property(srna, "use_gpencil_additive_drawing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_RETAIN_LAST);
+ RNA_def_property_ui_text(prop, "Use Additive Drawing",
+ "When creating new frames, the strokes from the previous/active frame "
+ "are included as the basis for the new one");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_src");
RNA_def_property_enum_items(prop, gpencil_source_3d_items);
@@ -2281,6 +2322,45 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Datablock where active Grease Pencil data is found from");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+ prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
+ RNA_def_property_struct_type(prop, "GPencilSculptSettings");
+ RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", "");
+
+ /* Grease Pencil - 3D View Stroke Placement */
+ prop = RNA_def_property(srna, "gpencil_stroke_placement_view3d", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align");
+ RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_ui_text(prop, "Stroke Placement (3D View)", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ prop = RNA_def_property(srna, "use_gpencil_stroke_endpoints", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpencil_v3d_align", GP_PROJECT_DEPTH_STROKE_ENDPOINTS);
+ RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Grease Pencil - 2D Views Stroke Placement */
+ prop = RNA_def_property(srna, "gpencil_stroke_placement_view2d", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v2d_align");
+ RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_ui_text(prop, "Stroke Placement (2D View)", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Grease Pencil - Sequencer Preview Stroke Placement */
+ prop = RNA_def_property(srna, "gpencil_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_seq_align");
+ RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_ui_text(prop, "Stroke Placement (Sequencer Preview)", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+ /* Grease Pencil - Image Editor Stroke Placement */
+ prop = RNA_def_property(srna, "gpencil_stroke_placement_image_editor", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_ima_align");
+ RNA_def_property_enum_items(prop, gpencil_stroke_placement_items);
+ RNA_def_property_ui_text(prop, "Stroke Placement (Image Editor)", "");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
+
+
/* Auto Keying */
prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "autokey_mode", AUTOKEY_ON);
@@ -2304,6 +2384,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Automatic keyframe insertion using active Keying Set only");
RNA_def_property_ui_icon(prop, ICON_KEYINGSET, 0);
+ /* Keyframing */
+ prop = RNA_def_property(srna, "keyframe_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "keyframe_type");
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_keyframe_type_items);
+ RNA_def_property_ui_text(prop, "New Keyframe Type", "Type of keyframes to create when inserting keyframes");
+
/* UV */
prop = RNA_def_property(srna, "uv_select_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "uv_selectmode");
@@ -2416,6 +2502,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "UnifiedPaintSettings");
RNA_def_property_ui_text(prop, "Unified Paint Settings", NULL);
+ /* Curve Paint Settings */
+ prop = RNA_def_property(srna, "curve_paint_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "CurvePaintSettings");
+ RNA_def_property_ui_text(prop, "Curve Paint Settings", NULL);
+
/* Mesh Statistics */
prop = RNA_def_property(srna, "statvis", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -2514,6 +2606,96 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
"when unlocked brush size is given in pixels");
}
+
+static void rna_def_curve_paint_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "CurvePaintSettings", NULL);
+ RNA_def_struct_path_func(srna, "rna_CurvePaintSettings_path");
+ RNA_def_struct_ui_text(srna, "Curve Paint Settings", "");
+
+ static EnumPropertyItem curve_type_items[] = {
+ {CU_POLY, "POLY", 0, "Poly", ""},
+ {CU_BEZIER, "BEZIER", 0, "Bezier", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "curve_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "curve_type");
+ RNA_def_property_enum_items(prop, curve_type_items);
+ RNA_def_property_ui_text(prop, "Type", "Type of curve to use for new strokes");
+
+ prop = RNA_def_property(srna, "use_corners_detect", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_CORNERS_DETECT);
+ RNA_def_property_ui_text(prop, "Detect Corners", "Detect corners and use non-aligned handles");
+
+ prop = RNA_def_property(srna, "use_pressure_radius", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_PRESSURE_RADIUS);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Use Pressure", "Map tablet pressure to curve radius");
+
+ prop = RNA_def_property(srna, "use_stroke_endpoints", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS);
+ RNA_def_property_ui_text(prop, "Only First", "Use the start of the stroke for the depth");
+
+ prop = RNA_def_property(srna, "error_threshold", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(prop, "Tolerance", "Allow deviation for a smoother, less preceise line");
+
+ prop = RNA_def_property(srna, "corner_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_range(prop, 0, M_PI);
+ RNA_def_property_ui_text(prop, "Corner Angle", "Angles above this are considered corners");
+
+ prop = RNA_def_property(srna, "radius_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Radius Min",
+ "Minimum radius when the minimum pressure is applied (also the minimum when tapering)");
+
+ prop = RNA_def_property(srna, "radius_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0, 10, 2);
+ RNA_def_property_ui_text(prop, "Radius Max",
+ "Radius to use when the maximum pressure is applied (or when a tablet isn't used)");
+
+ prop = RNA_def_property(srna, "radius_taper_start", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Radius Min", "Taper factor for the radius of each point along the curve");
+
+ prop = RNA_def_property(srna, "radius_taper_end", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 10.0);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Radius Max", "Taper factor for the radius of each point along the curve");
+
+ prop = RNA_def_property(srna, "radius_offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -10.0, 10.0);
+ RNA_def_property_ui_range(prop, -1.0f, 1.0, 1, 2);
+ RNA_def_property_ui_text(prop, "Offset", "Offset the stroke from the surface");
+
+ static EnumPropertyItem depth_mode_items[] = {
+ {CURVE_PAINT_PROJECT_CURSOR, "CURSOR", 0, "Cursor", ""},
+ {CURVE_PAINT_PROJECT_SURFACE, "SURFACE", 0, "Surface", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "depth_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "depth_mode");
+ RNA_def_property_enum_items(prop, depth_mode_items);
+ RNA_def_property_ui_text(prop, "Depth", "Method of projecting depth");
+
+ static EnumPropertyItem surface_plane_items[] = {
+ {CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW, "NORMAL_VIEW", 0, "Normal/View", "Draw perpendicular to the surface"},
+ {CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE, "NORMAL_SURFACE", 0, "Normal/Surface", "Draw aligned to the surface"},
+ {CURVE_PAINT_SURFACE_PLANE_VIEW, "VIEW", 0, "View", "Draw aligned to the viewport"},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "surface_plane", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "surface_plane");
+ RNA_def_property_enum_items(prop, surface_plane_items);
+ RNA_def_property_ui_text(prop, "Plane", "Plane for projected stroke");
+}
+
static void rna_def_statvis(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2556,7 +2738,7 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "overhang_axis", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "overhang_axis");
- RNA_def_property_enum_items(prop, object_axis_items);
+ RNA_def_property_enum_items(prop, rna_enum_object_axis_items);
RNA_def_property_ui_text(prop, "Axis", "");
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
@@ -2654,7 +2836,7 @@ static void rna_def_unit_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "scale_length", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_ui_text(prop, "Unit Scale", "Scale to use when converting between blender units and dimensions");
RNA_def_property_range(prop, 0.00001, 100000.0);
- RNA_def_property_ui_range(prop, 0.001, 100.0, 0.1, 3);
+ RNA_def_property_ui_range(prop, 0.001, 100.0, 0.1, 6);
RNA_def_property_update(prop, NC_WINDOW, NULL);
prop = RNA_def_property(srna, "use_separate", PROP_BOOLEAN, PROP_NONE);
@@ -2781,6 +2963,12 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "use_ao", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_AO);
+ RNA_def_property_ui_text(prop, "AO", "Render AO in this Layer");
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+ else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
prop = RNA_def_property(srna, "use_edge_enhance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_EDGE);
RNA_def_property_ui_text(prop, "Edge", "Render Edge-enhance in this Layer (only works for Solid faces)");
@@ -3397,7 +3585,7 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
srna = RNA_def_struct(brna, "FreestyleSettings", NULL);
RNA_def_struct_sdna(srna, "FreestyleConfig");
RNA_def_struct_nested(brna, srna, "SceneRenderLayer");
- RNA_def_struct_ui_text(srna, "Freestyle Settings", "Freestyle settings for a SceneRenderLayer datablock");
+ RNA_def_struct_ui_text(srna, "Freestyle Settings", "Freestyle settings for a SceneRenderLayer data-block");
prop = RNA_def_property(srna, "modules", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "modules", NULL);
@@ -3478,10 +3666,17 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static EnumPropertyItem rna_enum_partitioning_items[] = {
+ {RC_PARTITION_WATERSHED, "WATERSHED", 0, "Watershed", "Classic Recast partitioning method generating the nicest tessellation"},
+ {RC_PARTITION_MONOTONE, "MONOTONE", 0, "Monotone", "Fastest navmesh generation method, may create long thin polygons"},
+ {RC_PARTITION_LAYERS, "LAYERS", 0, "Layers", "Reasonably fast method that produces better triangles than monotone partitioning"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SceneGameRecastData", NULL);
RNA_def_struct_sdna(srna, "RecastData");
RNA_def_struct_nested(brna, srna, "Scene");
- RNA_def_struct_ui_text(srna, "Recast Data", "Recast data for a Game datablock");
+ RNA_def_struct_ui_text(srna, "Recast Data", "Recast data for a Game data-block");
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cellsize");
@@ -3540,6 +3735,13 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Merged Region Size", "Minimum regions size (smaller regions will be merged)");
RNA_def_property_update(prop, NC_SCENE, NULL);
+ prop = RNA_def_property(srna, "partitioning", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "partitioning");
+ RNA_def_property_enum_items(prop, rna_enum_partitioning_items);
+ RNA_def_property_enum_default(prop, RC_PARTITION_WATERSHED);
+ RNA_def_property_ui_text(prop, "Partitioning", "Choose partitioning method");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
prop = RNA_def_property(srna, "edge_max_len", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "edgemaxlen");
RNA_def_property_ui_range(prop, 0, 50, 1, 2);
@@ -3585,7 +3787,7 @@ static void rna_def_bake_data(BlenderRNA *brna)
srna = RNA_def_struct(brna, "BakeSettings", NULL);
RNA_def_struct_sdna(srna, "BakeData");
RNA_def_struct_nested(brna, srna, "RenderSettings");
- RNA_def_struct_ui_text(srna, "Bake Data", "Bake data for a Scene datablock");
+ RNA_def_struct_ui_text(srna, "Bake Data", "Bake data for a Scene data-block");
prop = RNA_def_property(srna, "cage_object", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "cage");
@@ -3622,25 +3824,25 @@ static void rna_def_bake_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "normal_space", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_space");
- RNA_def_property_enum_items(prop, normal_space_items);
+ RNA_def_property_enum_items(prop, rna_enum_normal_space_items);
RNA_def_property_ui_text(prop, "Normal Space", "Choose normal space for baking");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_r", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_swizzle[0]");
- RNA_def_property_enum_items(prop, normal_swizzle_items);
+ RNA_def_property_enum_items(prop, rna_enum_normal_swizzle_items);
RNA_def_property_ui_text(prop, "Normal Space", "Axis to bake in red channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_g", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_swizzle[1]");
- RNA_def_property_enum_items(prop, normal_swizzle_items);
+ RNA_def_property_enum_items(prop, rna_enum_normal_swizzle_items);
RNA_def_property_ui_text(prop, "Normal Space", "Axis to bake in green channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "normal_b", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "normal_swizzle[2]");
- RNA_def_property_enum_items(prop, normal_swizzle_items);
+ RNA_def_property_enum_items(prop, rna_enum_normal_swizzle_items);
RNA_def_property_ui_text(prop, "Normal Space", "Axis to bake in blue channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -3652,7 +3854,7 @@ static void rna_def_bake_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "save_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "save_mode");
- RNA_def_property_enum_items(prop, bake_save_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_bake_save_mode_items);
RNA_def_property_ui_text(prop, "Save Mode", "Choose how to save the baking map");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -3686,6 +3888,57 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Cage",
"Cast rays to active object from a cage");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ /* custom passes flags */
+ prop = RNA_def_property(srna, "use_pass_ambient_occlusion", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_AO);
+ RNA_def_property_ui_text(prop, "AO", "Add ambient occlusion contribution");
+
+ prop = RNA_def_property(srna, "use_pass_emit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_EMIT);
+ RNA_def_property_ui_text(prop, "Emit", "Add emission contribution");
+
+ prop = RNA_def_property(srna, "use_pass_direct", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_DIRECT);
+ RNA_def_property_ui_text(prop, "Direct", "Add direct lighting contribution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_pass_indirect", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_INDIRECT);
+ RNA_def_property_ui_text(prop, "Indirect", "Add indirect lighting contribution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_pass_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_COLOR);
+ RNA_def_property_ui_text(prop, "Color", "Color the pass");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_pass_diffuse", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_DIFFUSE);
+ RNA_def_property_ui_text(prop, "Diffuse", "Add diffuse contribution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_pass_glossy", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_GLOSSY);
+ RNA_def_property_ui_text(prop, "Glossy", "Add glossy contribution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_pass_transmission", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_TRANSM);
+ RNA_def_property_ui_text(prop, "Transmission", "Add transmission contribution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_pass_subsurface", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "pass_filter", R_BAKE_PASS_FILTER_SUBSURFACE);
+ RNA_def_property_ui_text(prop, "Subsurface", "Add subsurface contribution");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "pass_filter", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "pass_filter");
+ RNA_def_property_enum_items(prop, rna_enum_bake_pass_filter_type_items);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Pass Filter", "Passes to include in the active baking pass");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_scene_game_data(BlenderRNA *brna)
@@ -3767,18 +4020,15 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
static EnumPropertyItem storage_items[] = {
{RAS_STORE_AUTO, "AUTO", 0, "Auto Select", "Choose the best supported mode"},
- {RAS_STORE_IMMEDIATE, "IMMEDIATE", 0, "Immediate Mode", "Slowest performance, requires OpenGL (any version)"},
- {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Better performance, requires at least OpenGL 1.1"},
-#if 0 /* XXX VBOS are currently disabled since they cannot beat vertex array with display lists in performance. */
+ {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Usually the best choice (good performance with display lists)"},
{RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects",
- "Best performance, requires at least OpenGL 1.4"},
-#endif
+ "Typically slower than vertex arrays with display lists, requires at least OpenGL 1.4"},
{0, NULL, 0, NULL, NULL}};
srna = RNA_def_struct(brna, "SceneGameData", NULL);
RNA_def_struct_sdna(srna, "GameData");
RNA_def_struct_nested(brna, srna, "Scene");
- RNA_def_struct_ui_text(srna, "Game Data", "Game data for a Scene datablock");
+ RNA_def_struct_ui_text(srna, "Game Data", "Game data for a Scene data-block");
prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "xplay");
@@ -3813,7 +4063,8 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "exit_key", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "exitkey");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_enum_default(prop, ESCKEY);
RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL);
RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine");
@@ -4456,12 +4707,13 @@ static void rna_def_image_format_stereo3d_format(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ /* rna_enum_stereo3d_display_items, without (S3D_DISPLAY_PAGEFLIP) */
static EnumPropertyItem stereo3d_display_items[] = {
{S3D_DISPLAY_ANAGLYPH, "ANAGLYPH", 0, "Anaglyph",
- "Render views for left and right eyes as two differently filtered colors in a single image "
- "(anaglyph glasses are required)"},
+ "Render views for left and right eyes as two differently filtered colors in a single image "
+ "(anaglyph glasses are required)"},
{S3D_DISPLAY_INTERLACE, "INTERLACE", 0, "Interlace",
- "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)"},
+ "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)"},
{S3D_DISPLAY_SIDEBYSIDE, "SIDEBYSIDE", 0, "Side-by-Side", "Render views for left and right eyes side-by-side"},
{S3D_DISPLAY_TOPBOTTOM, "TOPBOTTOM", 0, "Top-Bottom", "Render views for left and right eyes one above another"},
{0, NULL, 0, NULL, NULL}
@@ -4479,12 +4731,12 @@ static void rna_def_image_format_stereo3d_format(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
prop = RNA_def_property(srna, "anaglyph_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, stereo3d_anaglyph_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_stereo3d_anaglyph_type_items);
RNA_def_property_ui_text(prop, "Anaglyph Type", "");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
prop = RNA_def_property(srna, "interlace_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, stereo3d_interlace_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_stereo3d_interlace_type_items);
RNA_def_property_ui_text(prop, "Interlace Type", "");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Stereo3dFormat_update");
@@ -4520,6 +4772,16 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
};
#endif
+#ifdef WITH_TIFF
+ static EnumPropertyItem tiff_codec_items[] = {
+ {R_IMF_TIFF_CODEC_NONE, "NONE", 0, "None", ""},
+ {R_IMF_TIFF_CODEC_DEFLATE, "DEFLATE", 0, "Deflate", ""},
+ {R_IMF_TIFF_CODEC_LZW, "LZW", 0, "LZW", ""},
+ {R_IMF_TIFF_CODEC_PACKBITS, "PACKBITS", 0, "Pack Bits", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+#endif
+
StructRNA *srna;
PropertyRNA *prop;
@@ -4533,7 +4795,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "imtype");
- RNA_def_property_enum_items(prop, image_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_image_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_ImageFormatSettings_file_format_set",
"rna_ImageFormatSettings_file_format_itemf");
RNA_def_property_ui_text(prop, "File Format", "File format to save the rendered images as");
@@ -4541,7 +4803,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "planes");
- RNA_def_property_enum_items(prop, image_color_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_image_color_mode_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_color_mode_itemf");
RNA_def_property_ui_text(prop, "Color Mode",
"Choose BW for saving grayscale images, RGB for saving red, green and blue channels, "
@@ -4550,7 +4812,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "color_depth", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "depth");
- RNA_def_property_enum_items(prop, image_color_depth_items);
+ RNA_def_property_enum_items(prop, rna_enum_image_color_depth_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_color_depth_itemf");
RNA_def_property_ui_text(prop, "Color Depth", "Bit depth per channel");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -4589,7 +4851,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "exr_codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "exr_codec");
- RNA_def_property_enum_items(prop, exr_codec_items);
+ RNA_def_property_enum_items(prop, rna_enum_exr_codec_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_exr_codec_itemf");
RNA_def_property_ui_text(prop, "Codec", "Codec settings for OpenEXR");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -4619,6 +4881,15 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
#endif
+#ifdef WITH_TIFF
+ /* TIFF */
+ prop = RNA_def_property(srna, "tiff_codec", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "tiff_codec");
+ RNA_def_property_enum_items(prop, tiff_codec_items);
+ RNA_def_property_ui_text(prop, "Compression", "Compression mode for TIFF");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+#endif
+
/* Cineon and DPX */
prop = RNA_def_property(srna, "use_cineon_log", PROP_BOOLEAN, PROP_NONE);
@@ -4647,7 +4918,7 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
/* multiview */
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
- RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_ImageFormatSettings_views_format_itemf");
RNA_def_property_ui_text(prop, "Views Format", "Format of multiview media");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5079,7 +5350,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "RenderData");
RNA_def_struct_nested(brna, srna, "Scene");
RNA_def_struct_path_func(srna, "rna_RenderSettings_path");
- RNA_def_struct_ui_text(srna, "Render Data", "Rendering settings for a Scene datablock");
+ RNA_def_struct_ui_text(srna, "Render Data", "Rendering settings for a Scene data-block");
/* Render Data */
prop = RNA_def_property(srna, "image_settings", PROP_POINTER, PROP_NONE);
@@ -5364,6 +5635,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
+
+ prop = RNA_def_property(srna, "motion_blur_shutter_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "mblur_shutter_curve");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Shutter Curve", "Curve defining the shutter's openness over time");
/* border */
prop = RNA_def_property(srna, "use_border", PROP_BOOLEAN, PROP_NONE);
@@ -5446,7 +5722,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
#if 0 /* moved */
prop = RNA_def_property(srna, "file_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "imtype");
- RNA_def_property_enum_items(prop, image_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_image_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_RenderSettings_file_format_set", NULL);
RNA_def_property_ui_text(prop, "File Format", "File format to save the rendered images as");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
@@ -5468,12 +5744,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"Free all image textures from memory after render, to save memory before compositing");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- prop = RNA_def_property(srna, "use_free_unused_nodes", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_COMP_FREE);
- RNA_def_property_ui_text(prop, "Free Unused Nodes",
- "Free Nodes that are not used while compositing, to save memory");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
prop = RNA_def_property(srna, "use_save_buffers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXR_TILE_FILE);
RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_save_buffers_get", NULL);
@@ -5729,13 +5999,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "sequencer_gl_preview", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "seq_prev_type");
- RNA_def_property_enum_items(prop, viewport_shade_items);
+ RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update");
prop = RNA_def_property(srna, "sequencer_gl_render", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "seq_rend_type");
- RNA_def_property_enum_items(prop, viewport_shade_items);
+ RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
RNA_def_property_ui_text(prop, "Sequencer Preview Shading", "Method to draw in the sequencer view");
prop = RNA_def_property(srna, "use_sequencer_gl_textured_solid", PROP_BOOLEAN, PROP_NONE);
@@ -5802,6 +6072,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Use Shading Nodes", "Active render engine uses new shading nodes system");
+ prop = RNA_def_property(srna, "use_spherical_stereo", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_spherical_stereo_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Use Spherical Stereo", "Active render engine supports spherical stereo rendering");
+
prop = RNA_def_property(srna, "use_game_engine", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_use_game_engine_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -5879,7 +6154,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
/* Debugging settings. */
#ifdef WITH_CYCLES_DEBUG
prop = RNA_def_property(srna, "debug_pass_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, render_pass_debug_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_render_pass_debug_type_items);
RNA_def_property_ui_text(prop, "Debug Pass Type", "Type of the debug pass to use");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
#endif
@@ -6503,7 +6778,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
RNA_def_property_struct_type(prop, "GreasePencil");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
- RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
+ RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
/* Transform Orientations */
@@ -6546,6 +6821,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_define_animate_sdna(false);
rna_def_tool_settings(brna);
rna_def_unified_paint_settings(brna);
+ rna_def_curve_paint_settings(brna);
rna_def_statvis(brna);
rna_def_unit_settings(brna);
rna_def_scene_image_format_data(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 9d63dfe0f55..6d7506f3911 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -33,6 +33,7 @@
#include <stdio.h>
#include "BLI_utildefines.h"
+#include "BLI_kdopbvh.h"
#include "BLI_path_util.h"
#include "RNA_define.h"
@@ -137,30 +138,28 @@ static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, int previe
}
}
-static void rna_Scene_ray_cast(Scene *scene, float ray_start[3], float ray_end[3],
- int *r_success, Object **r_ob, float r_obmat[16],
- float r_location[3], float r_normal[3])
+static void rna_Scene_ray_cast(
+ Scene *scene, float origin[3], float direction[3], float ray_dist,
+ int *r_success, float r_location[3], float r_normal[3], int *r_index,
+ Object **r_ob, float r_obmat[16])
{
- float dummy_dist_px = 0;
- float ray_nor[3];
- float ray_dist;
-
- sub_v3_v3v3(ray_nor, ray_end, ray_start);
- ray_dist = normalize_v3(ray_nor);
-
- if (snapObjectsRayEx(scene, NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE,
- r_ob, (float(*)[4])r_obmat,
- ray_start, ray_nor, &ray_dist,
- NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL))
+ normalize_v3(direction);
+
+ if (snapObjectsRayEx(
+ scene, NULL, NULL, NULL, NULL,
+ NULL, SNAP_ALL, SCE_SNAP_MODE_FACE,
+ origin, direction, &ray_dist,
+ r_location, r_normal, NULL, r_index,
+ r_ob, (float(*)[4])r_obmat))
{
*r_success = true;
}
else {
+ *r_success = false;
+
unit_m4((float(*)[4])r_obmat);
zero_v3(r_location);
zero_v3(r_normal);
-
- *r_success = false;
}
}
@@ -230,18 +229,16 @@ void RNA_api_scene(StructRNA *srna)
RNA_def_function_ui_description(func, "Cast a ray onto in object space");
/* ray start and end */
- parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
+ parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX,
+ "", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX);
/* return location and normal */
parm = RNA_def_boolean(func, "result", 0, "", "");
RNA_def_function_output(func, parm);
- parm = RNA_def_pointer(func, "object", "Object", "", "Ray cast object");
- RNA_def_function_output(func, parm);
- parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
- RNA_def_function_output(func, parm);
parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location",
"The hit location of this ray cast", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_THICK_WRAP);
@@ -250,6 +247,12 @@ void RNA_api_scene(StructRNA *srna)
"The face normal at the ray cast hit location", -1e4, 1e4);
RNA_def_property_flag(parm, PROP_THICK_WRAP);
RNA_def_function_output(func, parm);
+ parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0);
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_pointer(func, "object", "Object", "", "Ray cast object");
+ RNA_def_function_output(func, parm);
+ parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
+ RNA_def_function_output(func, parm);
#ifdef WITH_COLLADA
/* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 477a9dbca4f..43d5cda17ae 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -36,7 +36,7 @@
#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
-EnumPropertyItem region_type_items[] = {
+EnumPropertyItem rna_enum_region_type_items[] = {
{RGN_TYPE_WINDOW, "WINDOW", 0, "Window", ""},
{RGN_TYPE_HEADER, "HEADER", 0, "Header", ""},
{RGN_TYPE_CHANNELS, "CHANNELS", 0, "Channels", ""},
@@ -127,7 +127,7 @@ static EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C), PointerRNA *UN
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
/* +1 to skip SPACE_EMPTY */
- return space_type_items + 1;
+ return rna_enum_space_type_items + 1;
}
static int rna_Area_type_get(PointerRNA *ptr)
@@ -161,7 +161,7 @@ static void rna_Area_type_update(bContext *C, PointerRNA *ptr)
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, NULL);
- ED_area_newspace(C, sa, sa->butspacetype);
+ ED_area_newspace(C, sa, sa->butspacetype, true);
ED_area_tag_redraw(sa);
/* It is possible that new layers becomes visible. */
@@ -239,7 +239,7 @@ static void rna_def_area(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
- RNA_def_property_enum_items(prop, space_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_enum_default(prop, SPACE_VIEW3D);
RNA_def_property_enum_funcs(prop, "rna_Area_type_get", "rna_Area_type_set", "rna_Area_type_itemf");
RNA_def_property_ui_text(prop, "Editor Type", "Current editor type for this area");
@@ -334,7 +334,7 @@ static void rna_def_region(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "regiontype");
- RNA_def_property_enum_items(prop, region_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_region_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Region Type", "Type of this region");
@@ -374,7 +374,7 @@ static void rna_def_screen(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Screen", "ID");
RNA_def_struct_sdna(srna, "Screen"); /* it is actually bScreen but for 2.5 the dna is patched! */
- RNA_def_struct_ui_text(srna, "Screen", "Screen datablock, defining the layout of areas in a window");
+ RNA_def_struct_ui_text(srna, "Screen", "Screen data-block, defining the layout of areas in a window");
RNA_def_struct_ui_icon(srna, ICON_SPLITSCREEN);
/* pointers */
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 3ec9944900a..90215bc883f 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -60,7 +60,21 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem symmetrize_direction_items[] = {
+EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = {
+ {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points"},
+ {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes"},
+ {GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle"},
+ {GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them"},
+ {GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush"},
+ {GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush"},
+ {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Introduce jitter/randomness into strokes"},
+ //{GP_EDITBRUSH_TYPE_SUBDIVIDE, "SUBDIVIDE", 0, "Subdivide", "Increase point density for higher resolution strokes when zoomed in"},
+ //{GP_EDITBRUSH_TYPE_SIMPLIFY, "SIMPLIFY", 0, "Simplify", "Reduce density of stroke points"},
+ {GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem rna_enum_symmetrize_direction_items[] = {
{BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""},
{BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""},
@@ -359,6 +373,30 @@ static int rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
{
return imapaint->missing_data == 0;
}
+
+
+static PointerRNA rna_GPencilSculptSettings_brush_get(PointerRNA *ptr)
+{
+ GP_BrushEdit_Settings *gset = (GP_BrushEdit_Settings *)ptr->data;
+ GP_EditBrush_Data *brush = NULL;
+
+ if ((gset->brushtype >= 0) && (gset->brushtype < TOT_GP_EDITBRUSH_TYPES))
+ brush = &gset->brush[gset->brushtype];
+
+ return rna_pointer_inherit_refine(ptr, &RNA_GPencilSculptBrush, brush);
+}
+
+static char *rna_GPencilSculptSettings_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_sculpt");
+}
+
+static char *rna_GPencilSculptBrush_path(PointerRNA *UNUSED(ptr))
+{
+ return BLI_strdup("tool_settings.gpencil_sculpt.brush");
+}
+
+
#else
static void rna_def_paint_curve(BlenderRNA *brna)
@@ -562,7 +600,7 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, symmetrize_direction_items);
+ RNA_def_property_enum_items(prop, rna_enum_symmetrize_direction_items);
RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator");
prop = RNA_def_property(srna, "detail_refine_method", PROP_ENUM, PROP_NONE);
@@ -945,6 +983,79 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve", "");
}
+static void rna_def_gpencil_sculpt(BlenderRNA *brna)
+{
+ static EnumPropertyItem prop_direction_items[] = {
+ {0, "ADD", 0, "Add", "Add effect of brush"},
+ {GP_EDITBRUSH_FLAG_INVERT, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
+ {0, NULL, 0, NULL, NULL}};
+
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* == Settings == */
+ srna = RNA_def_struct(brna, "GPencilSculptSettings", NULL);
+ RNA_def_struct_sdna(srna, "GP_BrushEdit_Settings");
+ RNA_def_struct_path_func(srna, "rna_GPencilSculptSettings_path");
+ RNA_def_struct_ui_text(srna, "GPencil Sculpt Settings", "Properties for Grease Pencil stroke sculpting tool");
+
+ prop = RNA_def_property(srna, "tool", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "brushtype");
+ RNA_def_property_enum_items(prop, rna_enum_gpencil_sculpt_brush_items);
+ RNA_def_property_ui_text(prop, "Tool", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "GPencilSculptBrush");
+ RNA_def_property_pointer_funcs(prop, "rna_GPencilSculptSettings_brush_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Brush", "");
+
+ prop = RNA_def_property(srna, "use_select_mask", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_SELECT_MASK);
+ RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points");
+ RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ /* brush */
+ srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL);
+ RNA_def_struct_sdna(srna, "GP_EditBrush_Data");
+ RNA_def_struct_path_func(srna, "rna_GPencilSculptBrush_path");
+ RNA_def_struct_ui_text(srna, "GPencil Sculpt Brush", "Stroke editing brush");
+
+ prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS);
+ RNA_def_property_ui_range(prop, 1, 100, 10, 3); // XXX: too big
+ RNA_def_property_ui_text(prop, "Radius", "Radius of the brush in pixels");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.001, 1.0);
+ RNA_def_property_ui_text(prop, "Strength", "Brush strength");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_USE_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "use_falloff", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_USE_FALLOFF);
+ RNA_def_property_ui_text(prop, "Use Falloff", "Strength of brush decays with distance from cursor");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "affect_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE);
+ RNA_def_property_ui_text(prop, "Affect Pressure", "Affect pressure values as well when smoothing strokes");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_direction_items);
+ RNA_def_property_ui_text(prop, "Direction", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+}
+
void RNA_def_sculpt_paint(BlenderRNA *brna)
{
/* *** Non-Animated *** */
@@ -956,6 +1067,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna)
rna_def_vertex_paint(brna);
rna_def_image_paint(brna);
rna_def_particle_edit(brna);
+ rna_def_gpencil_sculpt(brna);
RNA_define_animate_sdna(true);
}
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index baf0ae3ccf5..ee24a434486 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -457,7 +457,8 @@ static void rna_def_keyboard_sensor(BlenderRNA *brna)
prop = RNA_def_property(srna, "key", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "key");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_key_set", NULL);
RNA_def_property_ui_text(prop, "Key", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_WINDOWMANAGER);
@@ -465,14 +466,16 @@ static void rna_def_keyboard_sensor(BlenderRNA *brna)
prop = RNA_def_property(srna, "modifier_key_1", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "qual");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier_set", NULL);
RNA_def_property_ui_text(prop, "Modifier Key", "Modifier key code");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "modifier_key_2", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "qual2");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_enum_funcs(prop, NULL, "rna_Sensor_keyboard_modifier2_set", NULL);
RNA_def_property_ui_text(prop, "Second Modifier Key", "Modifier key code");
RNA_def_property_update(prop, NC_LOGIC, NULL);
@@ -587,7 +590,7 @@ static void rna_def_actuator_sensor(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Actuator Sensor", "Sensor to detect state modifications of actuators");
RNA_def_struct_sdna_from(srna, "bActuatorSensor", "data");
- /* XXX if eventually have Logics using RNA 100%, we could use the actuator datablock isntead of its name */
+ /* XXX if eventually have Logics using RNA 100%, we could use the actuator data-block isntead of its name */
prop = RNA_def_property(srna, "actuator", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Actuator", "Actuator name, actuator active state modifications will be detected");
@@ -657,7 +660,7 @@ static void rna_def_collision_sensor(BlenderRNA *brna)
RNA_def_property_update(prop, NC_LOGIC, NULL);
#if 0
- /* XXX either use a datablock look up to store the string name (material)
+ /* XXX either use a data-block look up to store the string name (material)
* or to do a doversion and use a material pointer. */
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
@@ -765,7 +768,7 @@ static void rna_def_ray_sensor(BlenderRNA *brna)
RNA_def_property_update(prop, NC_LOGIC, NULL);
#if 0
- /* XXX either use a datablock look up to store the string name (material)
+ /* XXX either use a data-block look up to store the string name (material)
* or to do a doversion and use a material pointer. */
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Material");
@@ -813,7 +816,7 @@ static void rna_def_joystick_sensor(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem event_type_items[] = {
+ static EnumPropertyItem event_type_joystick_items[] = {
{SENS_JOY_BUTTON, "BUTTON", 0, "Button", ""},
{SENS_JOY_AXIS, "AXIS", 0, "Axis", ""},
{SENS_JOY_HAT, "HAT", 0, "Hat", ""},
@@ -854,7 +857,8 @@ static void rna_def_joystick_sensor(BlenderRNA *brna)
prop = RNA_def_property(srna, "event_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, event_type_joystick_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_ui_text(prop, "Event Type", "The type of event this joystick sensor is triggered on");
RNA_def_property_update(prop, NC_LOGIC, NULL);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 8f45c185798..e8a45e6a77d 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -60,12 +60,14 @@ typedef struct EffectInfo {
int inputs;
} EffectInfo;
-EnumPropertyItem sequence_modifier_type_items[] = {
+EnumPropertyItem rna_enum_sequence_modifier_type_items[] = {
{seqModifierType_ColorBalance, "COLOR_BALANCE", ICON_NONE, "Color Balance", ""},
{seqModifierType_Curves, "CURVES", ICON_NONE, "Curves", ""},
{seqModifierType_HueCorrect, "HUE_CORRECT", ICON_NONE, "Hue Correct", ""},
{seqModifierType_BrightContrast, "BRIGHT_CONTRAST", ICON_NONE, "Bright/Contrast", ""},
{seqModifierType_Mask, "MASK", ICON_NONE, "Mask", ""},
+ {seqModifierType_WhiteBalance, "WHITE_BALANCE", ICON_NONE, "White Balance", ""},
+ {seqModifierType_Tonemap, "TONEMAP", ICON_NONE, "Tone Map", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -280,7 +282,7 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->id.data;
- BKE_sequence_tx_set_final_right(seq, seq->start + value);
+ BKE_sequence_tx_set_final_right(seq, BKE_sequence_tx_get_final_left(seq, false) + value);
do_sequence_frame_change_update(scene, seq);
}
@@ -558,7 +560,7 @@ static char *rna_Sequence_path(PointerRNA *ptr)
Sequence *seq = (Sequence *)ptr->data;
/* sequencer data comes from scene...
- * TODO: would be nice to make SequenceEditor data a datablock of its own (for shorter paths)
+ * TODO: would be nice to make SequenceEditor data a data-block of its own (for shorter paths)
*/
if (seq->name + 2) {
char name_esc[(sizeof(seq->name) - 2) * 2];
@@ -595,19 +597,6 @@ static PointerRNA rna_SequenceEditor_meta_stack_get(CollectionPropertyIterator *
static void rna_Sequence_filepath_set(PointerRNA *ptr, const char *value)
{
Sequence *seq = (Sequence *)(ptr->data);
-
- if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) {
- /* for sound strips we need to update the sound as well.
- * arguably, this could load in a new sound rather than modify an existing one.
- * but while using the sequencer its most likely your not using the sound in the game engine too.
- */
- PointerRNA id_ptr;
- RNA_id_pointer_create((ID *)seq->sound, &id_ptr);
- RNA_string_set(&id_ptr, "filepath", value);
- BKE_sound_load(G.main, seq->sound);
- BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
- }
-
BLI_split_dirfile(value, seq->strip->dir, seq->strip->stripdata->name, sizeof(seq->strip->dir),
sizeof(seq->strip->stripdata->name));
}
@@ -733,6 +722,14 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin
rna_Sequence_update(bmain, scene, ptr);
}
+static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Sequence *seq = (Sequence *) ptr->data;
+
+ BKE_sound_update_scene_sound(seq->scene_sound, seq->sound);
+ rna_Sequence_update(bmain, scene, ptr);
+}
+
static int seqproxy_seq_cmp_cb(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -844,10 +841,8 @@ static char *rna_SequenceColorBalance_path(PointerRNA *ptr)
}
else {
/* path to modifier */
- char name_esc[(sizeof(seq->name) - 2) * 2];
char name_esc_smd[sizeof(smd->name) * 2];
- BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc));
BLI_strescape(name_esc_smd, smd->name, sizeof(name_esc_smd));
return BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].modifiers[\"%s\"].color_balance",
name_esc, name_esc_smd);
@@ -957,6 +952,10 @@ static StructRNA *rna_SequenceModifier_refine(struct PointerRNA *ptr)
return &RNA_HueCorrectModifier;
case seqModifierType_BrightContrast:
return &RNA_BrightContrastModifier;
+ case seqModifierType_WhiteBalance:
+ return &RNA_WhiteBalanceModifier;
+ case seqModifierType_Tonemap:
+ return &RNA_SequencerTonemapModifierData;
default:
return &RNA_SequenceModifier;
}
@@ -1028,8 +1027,9 @@ static int rna_SequenceModifier_otherSequence_poll(PointerRNA *ptr, PointerRNA v
Sequence *seq = sequence_get_by_modifier(ed, ptr->data);
Sequence *cur = (Sequence *) value.data;
- if (seq == cur)
+ if ((seq == cur) || (cur->type == SEQ_TYPE_SOUND_RAM)) {
return false;
+ }
return true;
}
@@ -1359,7 +1359,7 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* modifier to add */
- parm = RNA_def_enum(func, "type", sequence_modifier_type_items, seqModifierType_ColorBalance, "", "Modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_sequence_modifier_type_items, seqModifierType_ColorBalance, "", "Modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Newly created modifier");
@@ -1604,7 +1604,7 @@ static void rna_def_editor(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "SequenceEditor", NULL);
- RNA_def_struct_ui_text(srna, "Sequence Editor", "Sequence editing data for a Scene datablock");
+ RNA_def_struct_ui_text(srna, "Sequence Editor", "Sequence editing data for a Scene data-block");
RNA_def_struct_ui_icon(srna, ICON_SEQUENCE);
RNA_def_struct_sdna(srna, "Editing");
@@ -1849,7 +1849,7 @@ static void rna_def_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
- RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_ui_text(prop, "Views Format", "Mode to load image views");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Sequence_views_format_update");
@@ -1903,7 +1903,12 @@ static void rna_def_scene(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Camera_object_poll");
RNA_def_property_ui_text(prop, "Camera Override", "Override the scenes active camera");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
-
+
+ prop = RNA_def_property(srna, "use_sequence", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SCENE_STRIPS);
+ RNA_def_property_ui_text(prop, "Use Sequence", "Use scenes sequence strips directly, instead of rendering");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
prop = RNA_def_property(srna, "use_grease_pencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_SCENE_NO_GPENCIL);
RNA_def_property_ui_text(prop, "Use Grease Pencil", "Show Grease Pencil strokes in OpenGL previews");
@@ -1958,7 +1963,7 @@ static void rna_def_movie(BlenderRNA *brna)
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "views_format");
- RNA_def_property_enum_items(prop, views_format_items);
+ RNA_def_property_enum_items(prop, rna_enum_views_format_items);
RNA_def_property_ui_text(prop, "Views Format", "Mode to load movie views");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Sequence_views_format_update");
@@ -2028,9 +2033,10 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "Sequence");
prop = RNA_def_property(srna, "sound", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "Sound");
- RNA_def_property_ui_text(prop, "Sound", "Sound datablock used by this sequence");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+ RNA_def_property_ui_text(prop, "Sound", "Sound data-block used by this sequence");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_sound_update");
prop = RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "volume");
@@ -2055,12 +2061,6 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_pan_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
- prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
- RNA_def_property_ui_text(prop, "File", "");
- RNA_def_property_string_funcs(prop, "rna_Sequence_filepath_get", "rna_Sequence_filepath_length",
- "rna_Sequence_filepath_set");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_filepath_update");
-
prop = RNA_def_property(srna, "show_waveform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_AUDIO_DRAW_WAVEFORM);
RNA_def_property_ui_text(prop, "Draw Waveform", "Whether to draw the sound's waveform");
@@ -2330,7 +2330,7 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_ui_range(prop, 0.0f, 1000, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
- prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_ui_text(prop, "Location", "Location of the text");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
@@ -2387,7 +2387,7 @@ static EffectInfo def_effects[] = {
{"TransformSequence", "Transform Sequence",
"Sequence strip applying affine transformations to other strips", rna_def_transform, 1},
{"WipeSequence", "Wipe Sequence", "Sequence strip creating a wipe transition",
- rna_def_wipe, 1},
+ rna_def_wipe, 2},
{"GaussianBlurSequence", "Gaussian Blur Sequence", "Sequence strip creating a gaussian blur",
rna_def_gaussian_blur, 1},
{"TextSequence", "Text Sequence", "Sequence strip creating text",
@@ -2423,6 +2423,12 @@ static void rna_def_modifier(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static const EnumPropertyItem mask_time_items[] = {
+ {SEQUENCE_MASK_TIME_RELATIVE, "RELATIVE", 0, "Relative", "Mask animation is offset to start of strip"},
+ {SEQUENCE_MASK_TIME_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Mask animation is in sync with scene frame"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SequenceModifier", NULL);
RNA_def_struct_sdna(srna, "SequenceModifierData");
RNA_def_struct_ui_text(srna, "SequenceModifier", "Modifier for sequence strip");
@@ -2437,7 +2443,7 @@ static void rna_def_modifier(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, sequence_modifier_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_sequence_modifier_type_items);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
@@ -2459,6 +2465,12 @@ static void rna_def_modifier(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mask Input Type", "Type of input data used for mask");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+ prop = RNA_def_property(srna, "mask_time", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mask_time");
+ RNA_def_property_enum_items(prop, mask_time_items);
+ RNA_def_property_ui_text(prop, "Mask Time", "Time to use for the Mask animation");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
prop = RNA_def_property(srna, "input_mask_strip", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "mask_sequence");
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_SequenceModifier_otherSequence_poll");
@@ -2493,6 +2505,22 @@ static void rna_def_colorbalance_modifier(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
+static void rna_def_whitebalance_modifier(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WhiteBalanceModifier", "SequenceModifier");
+ RNA_def_struct_sdna(srna, "WhiteBalanceModifierData");
+ RNA_def_struct_ui_text(srna, "WhiteBalanceModifier", "White balance modifier for sequence strip");
+
+ prop = RNA_def_property(srna, "white_value", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "white_value");
+ RNA_def_property_ui_text(prop, "White value", "This color defines white in the strip");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+}
+
static void rna_def_curves_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2547,6 +2575,65 @@ static void rna_def_brightcontrast_modifier(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
}
+static void rna_def_tonemap_modifier(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem type_items[] = {
+ {SEQ_TONEMAP_RD_PHOTORECEPTOR, "RD_PHOTORECEPTOR", 0, "R/D Photoreceptor", ""},
+ {SEQ_TONEMAP_RH_SIMPLE, "RH_SIMPLE", 0, "Rh Simple", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "SequencerTonemapModifierData", "SequenceModifier");
+ RNA_def_struct_sdna(srna, "SequencerTonemapModifierData");
+ RNA_def_struct_ui_text(srna, "SequencerTonemapModifierData",
+ "Tone mapping modifier");
+
+ prop = RNA_def_property(srna, "tonemap_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_ui_text(prop, "Tonemap Type", "");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "key", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Key", "The value the average luminance is mapped to");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.001f, 10.0f);
+ RNA_def_property_ui_text(prop, "Offset",
+ "Normally always 1, but can be used as an extra control to alter the brightness curve");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "gamma", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.001f, 3.0f);
+ RNA_def_property_ui_text(prop, "Gamma", "If not used, set to 1");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, -8.0f, 8.0f);
+ RNA_def_property_ui_text(prop, "Intensity", "If less than zero, darkens image; otherwise, makes it brighter");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Contrast", "Set to 0 to use estimate from input image");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "adaptation", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Adaptation", "If 0, global; if 1, based on pixel intensity");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+
+ prop = RNA_def_property(srna, "correction", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Color Correction", "If 0, same for all channels; if 1, each independent");
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceModifier_update");
+}
+
static void rna_def_modifiers(BlenderRNA *brna)
{
rna_def_modifier(brna);
@@ -2555,6 +2642,8 @@ static void rna_def_modifiers(BlenderRNA *brna)
rna_def_curves_modifier(brna);
rna_def_hue_modifier(brna);
rna_def_brightcontrast_modifier(brna);
+ rna_def_whitebalance_modifier(brna);
+ rna_def_tonemap_modifier(brna);
}
void RNA_def_sequencer(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 539f3c192be..9a31952b84b 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -35,6 +35,7 @@
#include "BKE_modifier.h"
#include "BKE_smoke.h"
+#include "BKE_pointcache.h"
#include "BLI_threads.h"
@@ -190,6 +191,29 @@ static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr, int lengt
return length[0];
}
+static int rna_SmokeModifier_heat_grid_get_length(
+ PointerRNA *ptr,
+ int length[RNA_MAX_ARRAY_DIMENSION])
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ float *heat = NULL;
+ int size = 0;
+
+ /* Heat data is always low-resolution. */
+ if (sds->fluid) {
+ size = sds->res[0] * sds->res[1] * sds->res[2];
+ heat = smoke_get_heat(sds->fluid);
+ }
+
+ length[0] = (heat) ? size : 0;
+#else
+ (void)ptr;
+ length[0] = 0;
+#endif
+ return length[0];
+}
+
static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values)
{
#ifdef WITH_SMOKE
@@ -292,6 +316,34 @@ static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values)
#endif
}
+static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values)
+{
+#ifdef WITH_SMOKE
+ SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data;
+ int length[RNA_MAX_ARRAY_DIMENSION];
+ int size = rna_SmokeModifier_heat_grid_get_length(ptr, length);
+ float *heat;
+
+ BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ);
+
+ heat = smoke_get_heat(sds->fluid);
+
+ if (heat != NULL) {
+ /* scale heat values from -2.0-2.0 to -1.0-1.0. */
+ for (int i = 0; i < size; i++) {
+ values[i] = heat[i] * 0.5f;
+ }
+ }
+ else {
+ memset(values, 0, size * sizeof(float));
+ }
+
+ BLI_rw_mutex_unlock(sds->fluid_mutex);
+#else
+ UNUSED_VARS(ptr, values);
+#endif
+}
+
static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value)
{
SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data;
@@ -332,6 +384,15 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_compression_items[] = {
+ { VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression" },
+#ifdef WITH_OPENVDB_BLOSC
+ { VDB_COMPRESSION_BLOSC, "BLOSC", 0, "Blosc", "Multithreaded compression, similar in size and quality as 'Zip'" },
+#endif
+ { VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression" },
+ { 0, NULL, 0, NULL, NULL }
+ };
+
static EnumPropertyItem smoke_cache_comp_items[] = {
{SM_CACHE_LIGHT, "CACHELIGHT", 0, "Light", "Fast but not so effective compression"},
{SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"},
@@ -345,6 +406,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem smoke_data_depth_items[] = {
+ {16, "16", 0, "Float (Half)", "Half float (16 bit data)"},
+ {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */
+ {0, NULL, 0, NULL, NULL},
+ };
+
static EnumPropertyItem smoke_domain_colli_items[] = {
{SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"},
{SM_BORDER_VERTICAL, "BORDERVERTICAL", 0, "Vertically Open",
@@ -353,6 +420,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem cache_file_type_items[] = {
+ {PTCACHE_FILE_PTCACHE, "POINTCACHE", 0, "Point Cache", "Blender specific point cache file format"},
+#ifdef WITH_OPENVDB
+ {PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"},
+#endif
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL);
RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings");
RNA_def_struct_sdna(srna, "SmokeDomainSettings");
@@ -463,6 +538,19 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, smoke_cache_comp_items);
RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used");
+ prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp");
+ RNA_def_property_enum_items(prop, prop_compression_items);
+ RNA_def_property_ui_text(prop, "Compression", "Compression method to be used");
+
+ prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth");
+ RNA_def_property_enum_items(prop, smoke_data_depth_items);
+ RNA_def_property_ui_text(prop, "Data Depth",
+ "Bit depth for writing all scalar (including vector) "
+ "lower values reduce file size");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
+
prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "border_collisions");
RNA_def_property_enum_items(prop, smoke_domain_colli_items);
@@ -526,6 +614,14 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_SmokeModifier_color_grid_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid");
+ prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 32);
+ RNA_def_property_flag(prop, PROP_DYNAMIC);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_heat_grid_get_length");
+ RNA_def_property_float_funcs(prop, "rna_SmokeModifier_heat_grid_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid");
+
prop = RNA_def_property(srna, "cell_size", PROP_FLOAT, PROP_XYZ); /* can change each frame when using adaptive domain */
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "cell_size", "Cell Size");
@@ -601,6 +697,12 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Threshold",
"Maximum amount of fluid cell can contain before it is considered empty");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
+
+ prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "cache_file_format");
+ RNA_def_property_enum_items(prop, cache_file_type_items);
+ RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching");
+ RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache");
}
static void rna_def_smoke_flow_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index 25b3475c423..6aacede5816 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -74,14 +74,14 @@ static void rna_def_sound(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Sound", "ID");
RNA_def_struct_sdna(srna, "bSound");
- RNA_def_struct_ui_text(srna, "Sound", "Sound datablock referencing an external or packed sound file");
+ RNA_def_struct_ui_text(srna, "Sound", "Sound data-block referencing an external or packed sound file");
RNA_def_struct_ui_icon(srna, ICON_SOUND);
/*rna_def_ipo_common(srna); */
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "name");
- RNA_def_property_ui_text(prop, "File Path", "Sound sample file used by this Sound datablock");
+ RNA_def_property_ui_text(prop, "File Path", "Sound sample file used by this Sound data-block");
RNA_def_property_update(prop, 0, "rna_Sound_update");
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sound_api.c b/source/blender/makesrna/intern/rna_sound_api.c
index 0164daa98d0..293a5135acb 100644
--- a/source/blender/makesrna/intern/rna_sound_api.c
+++ b/source/blender/makesrna/intern/rna_sound_api.c
@@ -67,7 +67,7 @@ void RNA_api_sound(StructRNA *srna)
func = RNA_def_function(srna, "unpack", "rna_Sound_unpack");
RNA_def_function_ui_description(func, "Unpack the sound to the samples filename");
RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
- RNA_def_enum(func, "method", unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
+ RNA_def_enum(func, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index cee98261e23..f4db0277660 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -60,7 +60,7 @@
#include "RNA_enum_types.h"
-EnumPropertyItem space_type_items[] = {
+EnumPropertyItem rna_enum_space_type_items[] = {
/* empty must be here for python, is skipped for UI */
{SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""},
{SPACE_VIEW3D, "VIEW_3D", ICON_VIEW3D, "3D View", "3D viewport"},
@@ -77,8 +77,8 @@ EnumPropertyItem space_type_items[] = {
{SPACE_NODE, "NODE_EDITOR", ICON_NODETREE, "Node Editor", "Editor for node-based shading and compositing tools"},
{SPACE_LOGIC, "LOGIC_EDITOR", ICON_LOGIC, "Logic Editor", "Game logic editing"},
{0, "", ICON_NONE, NULL, NULL},
- {SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related datablocks"},
- {SPACE_OUTLINER, "OUTLINER", ICON_OOPS, "Outliner", "Overview of scene graph and all available datablocks"},
+ {SPACE_BUTS, "PROPERTIES", ICON_BUTS, "Properties", "Edit properties of active object and related data-blocks"},
+ {SPACE_OUTLINER, "OUTLINER", ICON_OOPS, "Outliner", "Overview of scene graph and all available data-blocks"},
{SPACE_USERPREF, "USER_PREFERENCES", ICON_PREFERENCES, "User Preferences", "Edit persistent configuration settings"},
{SPACE_INFO, "INFO", ICON_INFO, "Info", "Main menu bar and list of error messages (drag down to expand and display)"},
{0, "", ICON_NONE, NULL, NULL},
@@ -124,14 +124,14 @@ static EnumPropertyItem stereo3d_eye_items[] = {
#endif
static EnumPropertyItem pivot_items_full[] = {
- {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
"Pivot around bounding box center of selected object(s)"},
- {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"},
- {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
"Individual Origins", "Pivot around each object's own origin"},
- {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
"Pivot around the median point of selected objects"},
- {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"},
+ {V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"},
{0, NULL, 0, NULL, NULL}
};
@@ -142,6 +142,9 @@ static EnumPropertyItem draw_channels_items[] = {
{SI_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Draw alpha transparency channel"},
{SI_SHOW_ZBUF, "Z_BUFFER", ICON_IMAGE_ZDEPTH, "Z-Buffer",
"Draw Z-buffer associated with image (mapped from camera clip start to end)"},
+ {SI_SHOW_R, "RED", ICON_COLOR_RED, "Red", ""},
+ {SI_SHOW_G, "GREEN", ICON_COLOR_GREEN, "Green", ""},
+ {SI_SHOW_B, "BLUE", ICON_COLOR_BLUE, "Blue", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -172,7 +175,7 @@ static EnumPropertyItem autosnap_items[] = {
};
#endif
-EnumPropertyItem viewport_shade_items[] = {
+EnumPropertyItem rna_enum_viewport_shade_items[] = {
{OB_BOUNDBOX, "BOUNDBOX", ICON_BBOX, "Bounding Box", "Display the object's local bounding boxes only"},
{OB_WIRE, "WIREFRAME", ICON_WIRE, "Wireframe", "Display the object as wire edges"},
{OB_SOLID, "SOLID", ICON_SOLID, "Solid", "Display the object solid, lit with default OpenGL lights"},
@@ -183,7 +186,7 @@ EnumPropertyItem viewport_shade_items[] = {
};
-EnumPropertyItem clip_editor_mode_items[] = {
+EnumPropertyItem rna_enum_clip_editor_mode_items[] = {
{SC_MODE_TRACKING, "TRACKING", ICON_ANIM_DATA, "Tracking", "Show tracking and solving tools"},
{SC_MODE_MASKEDIT, "MASK", ICON_MOD_MASK, "Mask", "Show mask editing tools"},
{0, NULL, 0, NULL, NULL}
@@ -229,7 +232,7 @@ static EnumPropertyItem fileselectparams_recursion_level_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem file_sort_items[] = {
+EnumPropertyItem rna_enum_file_sort_items[] = {
{FILE_SORT_ALPHA, "FILE_SORT_ALPHA", ICON_SORTALPHA, "Sort alphabetically", "Sort the file list alphabetically"},
{FILE_SORT_EXTENSION, "FILE_SORT_EXTENSION", ICON_SORTBYEXT, "Sort by extension", "Sort the file list by extension/type"},
{FILE_SORT_TIME, "FILE_SORT_TIME", ICON_SORTTIME, "Sort by time", "Sort files by modification time"},
@@ -695,14 +698,14 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
EnumPropertyItem *item = NULL;
int totitem = 0;
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_BOUNDBOX);
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_WIRE);
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_SOLID);
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_TEXTURE);
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_BOUNDBOX);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_WIRE);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_SOLID);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_TEXTURE);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_MATERIAL);
if (type && type->view_draw)
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_RENDER);
+ RNA_enum_items_add_value(&item, &totitem, rna_enum_viewport_shade_items, OB_RENDER);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -838,6 +841,10 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *UNUS
RNA_enum_items_add_value(&item, &totitem, draw_channels_items, 0);
}
+ RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_R);
+ RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_G);
+ RNA_enum_items_add_value(&item, &totitem, draw_channels_items, SI_SHOW_B);
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -928,11 +935,11 @@ static EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), P
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
static EnumPropertyItem pivot_items[] = {
- {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""},
- {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""},
- {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
- {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
- "Individual Origins", "Pivot around each object's own origin"},
+ {V3D_AROUND_CENTER_BOUNDS, "CENTER", ICON_ROTATE, "Bounding Box Center", ""},
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""},
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ "Individual Origins", "Pivot around each selected island's own median point"},
{0, NULL, 0, NULL, NULL}
};
@@ -1095,6 +1102,14 @@ static EnumPropertyItem *rna_SpaceProperties_context_itemf(bContext *UNUSED(C),
return item;
}
+static void rna_SpaceProperties_context_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ SpaceButs *sbuts = (SpaceButs *)(ptr->data);
+ if (ELEM(sbuts->mainb, BCONTEXT_WORLD, BCONTEXT_MATERIAL, BCONTEXT_TEXTURE)) {
+ sbuts->preview = 1;
+ }
+}
+
static void rna_SpaceProperties_align_set(PointerRNA *ptr, int value)
{
SpaceButs *sbuts = (SpaceButs *)(ptr->data);
@@ -1220,7 +1235,7 @@ static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA valu
}
}
-static void rna_SpaceDopeSheetEditor_action_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SpaceDopeSheetEditor_action_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
SpaceAction *saction = (SpaceAction *)(ptr->data);
Object *obact = (scene->basact) ? scene->basact->object : NULL;
@@ -1290,6 +1305,8 @@ static void rna_SpaceDopeSheetEditor_action_update(Main *UNUSED(bmain), Scene *s
/* force depsgraph flush too */
DAG_id_tag_update(&obact->id, OB_RECALC_OB | OB_RECALC_DATA);
+ /* Update relations as well, so new time source dependency is added. */
+ DAG_relations_tag_update(bmain);
}
}
@@ -1346,6 +1363,12 @@ static int rna_SpaceGraphEditor_has_ghost_curves_get(PointerRNA *ptr)
return (BLI_listbase_is_empty(&sipo->ghostCurves) == false);
}
+static void rna_SpaceConsole_rect_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ SpaceConsole *sc = ptr->data;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_CONSOLE | NA_EDITED, sc);
+}
+
static void rna_Sequencer_view_type_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
ScrArea *sa = rna_area_from_space(ptr);
@@ -1617,7 +1640,7 @@ static int rna_FileBrowser_FSMenuEntry_name_get_editable(PointerRNA *ptr)
{
FSMenuEntry *fsm = ptr->data;
- return fsm->save;
+ return fsm->save ? PROP_EDITABLE : 0;
}
static void rna_FileBrowser_FSMenu_next(CollectionPropertyIterator *iter)
@@ -1856,7 +1879,7 @@ static void rna_def_space(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
- RNA_def_property_enum_items(prop, space_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "Space data type");
@@ -2024,20 +2047,20 @@ static void rna_def_space_outliner(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem display_mode_items[] = {
- {SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display datablocks in all scenes"},
- {SO_CUR_SCENE, "CURRENT_SCENE", 0, "Current Scene", "Display datablocks in current scene"},
- {SO_VISIBLE, "VISIBLE_LAYERS", 0, "Visible Layers", "Display datablocks in visible layers"},
- {SO_SELECTED, "SELECTED", 0, "Selected", "Display datablocks of selected objects"},
- {SO_ACTIVE, "ACTIVE", 0, "Active", "Display datablocks of active object"},
+ {SO_ALL_SCENES, "ALL_SCENES", 0, "All Scenes", "Display data-blocks in all scenes"},
+ {SO_CUR_SCENE, "CURRENT_SCENE", 0, "Current Scene", "Display data-blocks in current scene"},
+ {SO_VISIBLE, "VISIBLE_LAYERS", 0, "Visible Layers", "Display data-blocks in visible layers"},
+ {SO_SELECTED, "SELECTED", 0, "Selected", "Display data-blocks of selected, visible objects"},
+ {SO_ACTIVE, "ACTIVE", 0, "Active", "Display data-blocks of active object"},
{SO_SAME_TYPE, "SAME_TYPES", 0, "Same Types",
- "Display datablocks of all objects of same type as selected object"},
- {SO_GROUPS, "GROUPS", 0, "Groups", "Display groups and their datablocks"},
- {SO_SEQUENCE, "SEQUENCE", 0, "Sequence", "Display sequence datablocks"},
+ "Display data-blocks of all objects of same type as selected object"},
+ {SO_GROUPS, "GROUPS", 0, "Groups", "Display groups and their data-blocks"},
+ {SO_SEQUENCE, "SEQUENCE", 0, "Sequence", "Display sequence data-blocks"},
{SO_LIBRARIES, "LIBRARIES", 0, "Blender File", "Display data of current file and linked libraries"},
- {SO_DATABLOCKS, "DATABLOCKS", 0, "Datablocks", "Display all raw datablocks"},
- {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display the user preference datablocks"},
+ {SO_DATABLOCKS, "DATABLOCKS", 0, "Data-Blocks", "Display all raw data-blocks"},
+ {SO_USERDEF, "USER_PREFERENCES", 0, "User Preferences", "Display user preference data"},
{SO_ID_ORPHANS, "ORPHAN_DATA", 0, "Orphan Data",
- "Display datablocks which are unused and/or will be lost when the file is reloaded"},
+ "Display data-blocks which are unused and/or will be lost when the file is reloaded"},
{0, NULL, 0, NULL, NULL}
};
@@ -2388,7 +2411,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "viewport_shade", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "drawtype");
- RNA_def_property_enum_items(prop, viewport_shade_items);
+ RNA_def_property_enum_items(prop, rna_enum_viewport_shade_items);
RNA_def_property_enum_funcs(prop, "rna_SpaceView3D_viewport_shade_get", NULL,
"rna_SpaceView3D_viewport_shade_itemf");
RNA_def_property_ui_text(prop, "Viewport Shading", "Method to display/shade objects in the 3D View");
@@ -2627,7 +2650,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
"rna_iterator_listbase_end", "rna_SpaceView3D_region_quadviews_get",
NULL, NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Quad View Regions", "3D regions (the third one defines quad view settings, "
- "the forth one is same as 'region_3d')");
+ "the fourth one is same as 'region_3d')");
prop = RNA_def_property(srna, "show_reconstruction", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_RECONSTRUCTION);
@@ -2830,7 +2853,7 @@ static void rna_def_space_buttons(BlenderRNA *brna)
RNA_def_property_enum_items(prop, buttons_context_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_SpaceProperties_context_set", "rna_SpaceProperties_context_itemf");
RNA_def_property_ui_text(prop, "Context", "Type of active data to display and edit");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_SpaceProperties_context_update");
prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
@@ -3283,7 +3306,7 @@ static void rna_def_space_text(BlenderRNA *brna)
/* find */
prop = RNA_def_property(srna, "use_find_all", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", ST_FIND_ALL);
- RNA_def_property_ui_text(prop, "Find All", "Search in all text datablocks, instead of only the active one");
+ RNA_def_property_ui_text(prop, "Find All", "Search in all text data-blocks, instead of only the active one");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
prop = RNA_def_property(srna, "use_find_wrap", PROP_BOOLEAN, PROP_NONE);
@@ -3419,11 +3442,11 @@ static void rna_def_space_graph(BlenderRNA *brna)
/* this is basically the same as the one for the 3D-View, but with some entries omitted */
static EnumPropertyItem gpivot_items[] = {
- {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""},
- {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
- {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Centers", ""},
- /*{V3D_CENTROID, "MEDIAN_POINT", 0, "Median Point", ""}, */
- /*{V3D_ACTIVE, "ACTIVE_ELEMENT", 0, "Active Element", ""}, */
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""},
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Centers", ""},
+ /*{V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", 0, "Median Point", ""}, */
+ /*{V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", 0, "Active Element", ""}, */
{0, NULL, 0, NULL, NULL}
};
@@ -3504,6 +3527,11 @@ static void rna_def_space_graph(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Show Cursor", "Show 2D cursor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+ prop = RNA_def_property(srna, "cursor_position_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cursorTime");
+ RNA_def_property_ui_text(prop, "Cursor X-Value", "Graph Editor 2D-Value cursor - X-Value component");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
prop = RNA_def_property(srna, "cursor_position_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cursorVal");
RNA_def_property_ui_text(prop, "Cursor Y-Value", "Graph Editor 2D-Value cursor - Y-Value component");
@@ -3701,7 +3729,7 @@ static void rna_def_space_console(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "lheight");
RNA_def_property_range(prop, 8, 32);
RNA_def_property_ui_text(prop, "Font Size", "Font size to use for displaying the text");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
+ RNA_def_property_update(prop, 0, "rna_SpaceConsole_rect_update");
prop = RNA_def_property(srna, "select_start", PROP_INT, PROP_UNSIGNED); /* copied from text editor */
@@ -3735,13 +3763,13 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem file_display_items[] = {
- {FILE_SHORTDISPLAY, "FILE_SHORTDISPLAY", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
- {FILE_LONGDISPLAY, "FILE_LONGDISPLAY", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
- {FILE_IMGDISPLAY, "FILE_IMGDISPLAY", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
+ {FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
+ {FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
+ {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem thumbnail_size_items[] = {
+ static EnumPropertyItem display_size_items[] = {
{32, "TINY", 0, "Tiny", ""},
{64, "SMALL", 0, "Small", ""},
{128, "NORMAL", 0, "Normal", ""},
@@ -3750,36 +3778,36 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
};
static EnumPropertyItem file_filter_idtypes_items[] = {
- {FILTER_ID_AC, "ACTION", ICON_ANIM_DATA, "Actions", "Show/hide Action datablocks"},
- {FILTER_ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armatures", "Show/hide Armature datablocks"},
- {FILTER_ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brushes", "Show/hide Brushes datablocks"},
- {FILTER_ID_CA, "CAMERA", ICON_CAMERA_DATA, "Cameras", "Show/hide Camera datablocks"},
- {FILTER_ID_CU, "CURVE", ICON_CURVE_DATA, "Curves", "Show/hide Curve datablocks"},
- {FILTER_ID_GD, "GREASE_PENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Show/hide Grease pencil datablocks"},
- {FILTER_ID_GR, "GROUP", ICON_GROUP, "Groups", "Show/hide Group datablocks"},
- {FILTER_ID_IM, "IMAGE", ICON_IMAGE_DATA, "Images", "Show/hide Image datablocks"},
- {FILTER_ID_LA, "LAMP", ICON_LAMP_DATA, "Lamps", "Show/hide Lamp datablocks"},
+ {FILTER_ID_AC, "ACTION", ICON_ANIM_DATA, "Actions", "Show/hide Action data-blocks"},
+ {FILTER_ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armatures", "Show/hide Armature data-blocks"},
+ {FILTER_ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brushes", "Show/hide Brushes data-blocks"},
+ {FILTER_ID_CA, "CAMERA", ICON_CAMERA_DATA, "Cameras", "Show/hide Camera data-blocks"},
+ {FILTER_ID_CU, "CURVE", ICON_CURVE_DATA, "Curves", "Show/hide Curve data-blocks"},
+ {FILTER_ID_GD, "GREASE_PENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Show/hide Grease pencil data-blocks"},
+ {FILTER_ID_GR, "GROUP", ICON_GROUP, "Groups", "Show/hide Group data-blocks"},
+ {FILTER_ID_IM, "IMAGE", ICON_IMAGE_DATA, "Images", "Show/hide Image data-blocks"},
+ {FILTER_ID_LA, "LAMP", ICON_LAMP_DATA, "Lamps", "Show/hide Lamp data-blocks"},
{FILTER_ID_LS, "LINESTYLE", ICON_LINE_DATA,
- "Freestyle Linestyles", "Show/hide Freestyle's Line Style datablocks"},
- {FILTER_ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattices", "Show/hide Lattice datablocks"},
- {FILTER_ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Materials", "Show/hide Material datablocks"},
- {FILTER_ID_MB, "METABALL", ICON_META_DATA, "Metaballs", "Show/hide Metaball datablocks"},
- {FILTER_ID_MC, "MOVIE_CLIP", ICON_CLIP, "Movie Clips", "Show/hide Movie Clip datablocks"},
- {FILTER_ID_ME, "MESH", ICON_MESH_DATA, "Meshes", "Show/hide Mesh datablocks"},
- {FILTER_ID_MSK, "MASK", ICON_MOD_MASK, "Masks", "Show/hide Mask datablocks"},
- {FILTER_ID_NT, "NODE_TREE", ICON_NODETREE, "Node Trees", "Show/hide Node Tree datablocks"},
- {FILTER_ID_OB, "OBJECT", ICON_OBJECT_DATA, "Objects", "Show/hide Object datablocks"},
+ "Freestyle Linestyles", "Show/hide Freestyle's Line Style data-blocks"},
+ {FILTER_ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattices", "Show/hide Lattice data-blocks"},
+ {FILTER_ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Materials", "Show/hide Material data-blocks"},
+ {FILTER_ID_MB, "METABALL", ICON_META_DATA, "Metaballs", "Show/hide Metaball data-blocks"},
+ {FILTER_ID_MC, "MOVIE_CLIP", ICON_CLIP, "Movie Clips", "Show/hide Movie Clip data-blocks"},
+ {FILTER_ID_ME, "MESH", ICON_MESH_DATA, "Meshes", "Show/hide Mesh data-blocks"},
+ {FILTER_ID_MSK, "MASK", ICON_MOD_MASK, "Masks", "Show/hide Mask data-blocks"},
+ {FILTER_ID_NT, "NODE_TREE", ICON_NODETREE, "Node Trees", "Show/hide Node Tree data-blocks"},
+ {FILTER_ID_OB, "OBJECT", ICON_OBJECT_DATA, "Objects", "Show/hide Object data-blocks"},
{FILTER_ID_PA, "PARTICLE_SETTINGS", ICON_PARTICLE_DATA,
- "Particles Settings", "Show/hide Particle Settings datablocks"},
- {FILTER_ID_PAL, "PALETTE", ICON_COLOR, "Palettes", "Show/hide Palette datablocks"},
- {FILTER_ID_PC, "PAINT_CURVE", ICON_CURVE_BEZCURVE, "Paint Curves", "Show/hide Paint Curve datablocks"},
- {FILTER_ID_SCE, "SCENE", ICON_SCENE_DATA, "Scenes", "Show/hide Scene datablocks"},
- {FILTER_ID_SPK, "SPEAKER", ICON_SPEAKER, "Speakers", "Show/hide Speaker datablocks"},
- {FILTER_ID_SO, "SOUND", ICON_SOUND, "Sounds", "Show/hide Sound datablocks"},
- {FILTER_ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Textures", "Show/hide Texture datablocks"},
- {FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text datablocks"},
- {FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font datablocks"},
- {FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World datablocks"},
+ "Particles Settings", "Show/hide Particle Settings data-blocks"},
+ {FILTER_ID_PAL, "PALETTE", ICON_COLOR, "Palettes", "Show/hide Palette data-blocks"},
+ {FILTER_ID_PC, "PAINT_CURVE", ICON_CURVE_BEZCURVE, "Paint Curves", "Show/hide Paint Curve data-blocks"},
+ {FILTER_ID_SCE, "SCENE", ICON_SCENE_DATA, "Scenes", "Show/hide Scene data-blocks"},
+ {FILTER_ID_SPK, "SPEAKER", ICON_SPEAKER, "Speakers", "Show/hide Speaker data-blocks"},
+ {FILTER_ID_SO, "SOUND", ICON_SOUND, "Sounds", "Show/hide Sound data-blocks"},
+ {FILTER_ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Textures", "Show/hide Texture data-blocks"},
+ {FILTER_ID_TXT, "TEXT", ICON_TEXT, "Texts", "Show/hide Text data-blocks"},
+ {FILTER_ID_VF, "FONT", ICON_FONT_DATA, "Fonts", "Show/hide Font data-blocks"},
+ {FILTER_ID_WO, "WORLD", ICON_WORLD_DATA, "Worlds", "Show/hide World data-blocks"},
{0, NULL, 0, NULL, NULL}
};
@@ -3851,7 +3879,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
prop = RNA_def_property(srna, "sort_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sort");
- RNA_def_property_enum_items(prop, file_sort_items);
+ RNA_def_property_enum_items(prop, rna_enum_file_sort_items);
RNA_def_property_ui_text(prop, "Sort", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
@@ -3940,10 +3968,11 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_TEXTEDIT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
- prop = RNA_def_property(srna, "thumbnail_size", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "display_size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "thumbnail_size");
- RNA_def_property_enum_items(prop, thumbnail_size_items);
- RNA_def_property_ui_text(prop, "Thumbnails Size", "Change the size of the thumbnails");
+ RNA_def_property_enum_items(prop, display_size_items);
+ RNA_def_property_ui_text(prop, "Display Size",
+ "Change the size of the display (width of columns or thumbnails size)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -4190,7 +4219,7 @@ static void rna_def_space_node(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem texture_type_items[] = {
+ static EnumPropertyItem texture_id_type_items[] = {
{SNODE_TEX_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit texture nodes from Object"},
{SNODE_TEX_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit texture nodes from World"},
{SNODE_TEX_BRUSH, "BRUSH", ICON_BRUSH_DATA, "Brush", "Edit texture nodes from Brush"},
@@ -4243,7 +4272,7 @@ static void rna_def_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "texture_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "texfrom");
- RNA_def_property_enum_items(prop, texture_type_items);
+ RNA_def_property_enum_items(prop, texture_id_type_items);
RNA_def_property_ui_text(prop, "Texture Type", "Type of data to take texture from");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
@@ -4260,7 +4289,7 @@ static void rna_def_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "id_from", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "from");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "ID From", "Datablock from which the edited datablock is linked");
+ RNA_def_property_ui_text(prop, "ID From", "Datablock from which the edited data-block is linked");
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
@@ -4438,18 +4467,18 @@ static void rna_def_space_clip(BlenderRNA *brna)
};
static EnumPropertyItem gpencil_source_items[] = {
- {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show grease pencil datablock which belongs to movie clip"},
- {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show grease pencil datablock which belongs to active track"},
+ {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show grease pencil data-block which belongs to movie clip"},
+ {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show grease pencil data-block which belongs to active track"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem pivot_items[] = {
- {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
+ {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
"Pivot around bounding box center of selected object(s)"},
- {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", "Pivot around the 2D cursor"},
- {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", "Pivot around the 2D cursor"},
+ {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
"Individual Origins", "Pivot around each object's own origin"},
- {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
+ {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
"Pivot around the median point of selected objects"},
{0, NULL, 0, NULL, NULL}
};
@@ -4480,7 +4509,7 @@ static void rna_def_space_clip(BlenderRNA *brna)
/* mode */
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, clip_editor_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_clip_editor_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, "rna_SpaceClipEditor_clip_mode_update");
diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c
index 31a4e672983..f47b54c2d95 100644
--- a/source/blender/makesrna/intern/rna_speaker.c
+++ b/source/blender/makesrna/intern/rna_speaker.c
@@ -55,7 +55,7 @@ static void rna_def_speaker(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Speaker", "ID");
- RNA_def_struct_ui_text(srna, "Speaker", "Speaker datablock for 3D audio speaker objects");
+ RNA_def_struct_ui_text(srna, "Speaker", "Speaker data-block for 3D audio speaker objects");
RNA_def_struct_ui_icon(srna, ICON_SPEAKER);
prop = RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
@@ -75,7 +75,7 @@ static void rna_def_speaker(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Sound");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Sound", "Sound datablock used by this speaker");
+ RNA_def_property_ui_text(prop, "Sound", "Sound data-block used by this speaker");
/* RNA_def_property_float_funcs(prop, NULL, "rna_Speaker_sound_set", NULL); */
/* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */
diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c
index fb9d447850a..474fc3e5dc7 100644
--- a/source/blender/makesrna/intern/rna_text.c
+++ b/source/blender/makesrna/intern/rna_text.c
@@ -133,7 +133,7 @@ static void rna_def_text_line(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "TextLine", NULL);
- RNA_def_struct_ui_text(srna, "Text Line", "Line of text in a Text datablock");
+ RNA_def_struct_ui_text(srna, "Text Line", "Line of text in a Text data-block");
prop = RNA_def_property(srna, "body", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_TextLine_body_get", "rna_TextLine_body_length", "rna_TextLine_body_set");
@@ -148,7 +148,7 @@ static void rna_def_text(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Text", "ID");
- RNA_def_struct_ui_text(srna, "Text", "Text datablock referencing an external or packed text file");
+ RNA_def_struct_ui_text(srna, "Text", "Text data-block referencing an external or packed text file");
RNA_def_struct_ui_icon(srna, ICON_TEXT);
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c
index de398bc10a6..2478ad0fe1a 100644
--- a/source/blender/makesrna/intern/rna_text_api.c
+++ b/source/blender/makesrna/intern/rna_text_api.c
@@ -62,7 +62,7 @@ void RNA_api_text(StructRNA *srna)
func = RNA_def_function(srna, "write", "rna_Text_write");
RNA_def_function_ui_description(func, "write text at the cursor location and advance to the end of the text block");
- prop = RNA_def_string(func, "text", "Text", 0, "", "New text for this datablock");
+ prop = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block");
RNA_def_property_flag(prop, PROP_REQUIRED);
}
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 726744782ed..1e88585a286 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -61,7 +61,7 @@ static EnumPropertyItem texture_filter_items[] = {
};
#endif
-EnumPropertyItem texture_type_items[] = {
+EnumPropertyItem rna_enum_texture_type_items[] = {
{0, "NONE", 0, "None", ""},
{TEX_BLEND, "BLEND", ICON_TEXTURE, "Blend", "Procedural - create a ramp texture"},
{TEX_CLOUDS, "CLOUDS", ICON_TEXTURE, "Clouds", "Procedural - create a cloud-like fractal noise texture"},
@@ -174,7 +174,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
}
else if (GS(id->name) == ID_NT) {
bNodeTree *ntree = ptr->id.data;
- ED_node_tag_update_nodetree(bmain, ntree);
+ ED_node_tag_update_nodetree(bmain, ntree, NULL);
}
}
@@ -225,7 +225,7 @@ static void rna_Texture_type_set(PointerRNA *ptr, int value)
BKE_texture_type_set(tex, value);
}
-void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->id.data;
@@ -244,8 +244,12 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, id);
break;
case ID_BR:
+ {
+ MTex *mtex = ptr->data;
+ BKE_paint_invalidate_overlay_tex(scene, mtex->tex);
WM_main_add_notifier(NC_BRUSH, id);
break;
+ }
case ID_LS:
WM_main_add_notifier(NC_LINESTYLE, id);
break;
@@ -266,24 +270,6 @@ void rna_TextureSlot_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRN
}
}
-void rna_TextureSlot_brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- ID *id = ptr->id.data;
-
- DAG_id_tag_update(id, 0);
-
- switch (GS(id->name)) {
- case ID_BR:
- {
- MTex *mtex = ptr->data;
- BKE_paint_invalidate_overlay_tex(scene, mtex->tex);
- break;
- }
- }
- rna_TextureSlot_update(bmain, scene, ptr);
-}
-
-
char *rna_TextureSlot_path(PointerRNA *ptr)
{
MTex *mtex = ptr->data;
@@ -660,7 +646,7 @@ static void rna_def_mtex(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "tex");
RNA_def_property_struct_type(prop, "Texture");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_ui_text(prop, "Texture", "Texture datablock used by this texture slot");
+ RNA_def_property_ui_text(prop, "Texture", "Texture data-block used by this texture slot");
RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
@@ -675,14 +661,14 @@ static void rna_def_mtex(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "ofs");
RNA_def_property_ui_range(prop, -10, 10, 10, RNA_TRANSLATION_PREC_DEFAULT);
RNA_def_property_ui_text(prop, "Offset", "Fine tune of the texture mapping X, Y and Z locations");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "size");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_range(prop, -100, 100, 10, 2);
RNA_def_property_ui_text(prop, "Size", "Set scaling for the texture's X, Y and Z sizes");
- RNA_def_property_update(prop, 0, "rna_TextureSlot_brush_update");
+ RNA_def_property_update(prop, 0, "rna_TextureSlot_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "r");
@@ -1668,7 +1654,7 @@ static void rna_def_texture_pointdensity(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem color_source_items[] = {
+ static EnumPropertyItem particle_color_source_items[] = {
{TEX_PD_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""},
{TEX_PD_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age", "Lifetime mapped as 0.0 - 1.0 intensity"},
{TEX_PD_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed",
@@ -1677,6 +1663,14 @@ static void rna_def_texture_pointdensity(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem vertex_color_source_items[] = {
+ {TEX_PD_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""},
+ {TEX_PD_COLOR_VERTCOL, "VERTEX_COLOR", 0, "Vertex Color", "Vertex color layer"},
+ {TEX_PD_COLOR_VERTWEIGHT, "VERTEX_WEIGHT", 0, "Vertex Weight", "Vertex group weight"},
+ {TEX_PD_COLOR_VERTNOR, "VERTEX_NORMAL", 0, "Vertex Normal", "XYZ normal vector mapped to RGB colors"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
static EnumPropertyItem turbulence_influence_items[] = {
{TEX_PD_NOISE_STATIC, "STATIC", 0, "Static",
"Noise patterns will remain unchanged, faster and suitable for stills"},
@@ -1742,12 +1736,22 @@ static void rna_def_texture_pointdensity(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Softness", "Softness of the 'soft' falloff option");
RNA_def_property_update(prop, 0, "rna_Texture_update");
- prop = RNA_def_property(srna, "color_source", PROP_ENUM, PROP_NONE);
+ prop = RNA_def_property(srna, "particle_color_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_source");
- RNA_def_property_enum_items(prop, color_source_items);
+ RNA_def_property_enum_items(prop, particle_color_source_items);
RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
RNA_def_property_update(prop, 0, "rna_Texture_update");
+ prop = RNA_def_property(srna, "vertex_color_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "ob_color_source");
+ RNA_def_property_enum_items(prop, vertex_color_source_items);
+ RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
+ RNA_def_property_update(prop, 0, "rna_Texture_update");
+
+ prop = RNA_def_property(srna, "vertex_attribute_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Vertex Attribute Name", "Vertex attribute to use for color");
+ RNA_def_property_update(prop, 0, "rna_Texture_update");
+
prop = RNA_def_property(srna, "speed_scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "speed_scale");
RNA_def_property_range(prop, 0.001, 100.0);
@@ -2021,14 +2025,14 @@ static void rna_def_texture(BlenderRNA *brna)
srna = RNA_def_struct(brna, "Texture", "ID");
RNA_def_struct_sdna(srna, "Tex");
- RNA_def_struct_ui_text(srna, "Texture", "Texture datablock used by materials, lamps, worlds and brushes");
+ RNA_def_struct_ui_text(srna, "Texture", "Texture data-block used by materials, lamps, worlds and brushes");
RNA_def_struct_ui_icon(srna, ICON_TEXTURE_DATA);
RNA_def_struct_refine_func(srna, "rna_Texture_refine");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
/*RNA_def_property_clear_flag(prop, PROP_EDITABLE); */
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, texture_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_texture_type_items);
RNA_def_property_enum_funcs(prop, NULL, "rna_Texture_type_set", NULL);
RNA_def_property_ui_text(prop, "Type", "");
RNA_def_property_update(prop, 0, "rna_Texture_update");
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index a27ba6ea06d..ef1ef5e1469 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -74,7 +74,7 @@ static void texture_evaluate(struct Tex *tex, float value[3], float r_color[4])
TexResult texres = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
/* TODO(sergey): always use color management now. */
- multitex_ext(tex, value, NULL, NULL, 1, &texres, NULL, true, false);
+ multitex_ext(tex, value, NULL, NULL, 1, &texres, 0, NULL, true, false);
r_color[0] = texres.tr;
r_color[1] = texres.tg;
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 5a70d47a19a..a9901fd3a50 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -55,6 +55,71 @@
#include "WM_api.h"
+static MovieTrackingObject *tracking_object_from_track(MovieClip *clip,
+ MovieTrackingTrack *track)
+{
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = &tracking->tracks;
+ /* TODO: it's a bit difficult to find list track came from knowing just
+ * movie clip ID and MovieTracking structure, so keep this naive
+ * search for a while */
+ if (BLI_findindex(tracksbase, track) == -1) {
+ MovieTrackingObject *object = tracking->objects.first;
+ while (object) {
+ if (BLI_findindex(&object->tracks, track) != -1) {
+ return object;
+ }
+ object = object->next;
+ }
+ }
+ return NULL;
+}
+
+static ListBase *tracking_tracksbase_from_track(MovieClip *clip,
+ MovieTrackingTrack *track)
+{
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object = tracking_object_from_track(clip, track);
+ if (object != NULL) {
+ return &object->tracks;
+ }
+ return &tracking->tracks;
+}
+
+static MovieTrackingObject *tracking_object_from_plane_track(
+ MovieClip *clip,
+ MovieTrackingPlaneTrack *plane_track)
+{
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *plane_tracks_base = &tracking->plane_tracks;
+ /* TODO: it's a bit difficult to find list track came from knowing just
+ * movie clip ID and MovieTracking structure, so keep this naive
+ * search for a while */
+ if (BLI_findindex(plane_tracks_base, plane_track) == -1) {
+ MovieTrackingObject *object = tracking->objects.first;
+ while (object) {
+ if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
+ return object;
+ }
+ object = object->next;
+ }
+ }
+ return NULL;
+}
+
+static ListBase *tracking_tracksbase_from_plane_track(
+ MovieClip *clip,
+ MovieTrackingPlaneTrack *plane_track)
+{
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *object = tracking_object_from_plane_track(clip,
+ plane_track);
+ if (object != NULL) {
+ return &object->plane_tracks;
+ }
+ return &tracking->plane_tracks;
+}
+
static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
{
return BLI_sprintfN("tracking");
@@ -82,10 +147,21 @@ static void rna_tracking_defaultSettings_searchUpdate(Main *UNUSED(bmain), Scene
static char *rna_trackingTrack_path(PointerRNA *ptr)
{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data;
- char name_esc[sizeof(track->name) * 2];
- BLI_strescape(name_esc, track->name, sizeof(name_esc));
- return BLI_sprintfN("tracking.tracks[\"%s\"]", name_esc);
+ MovieTrackingObject *object = tracking_object_from_track(clip, track);
+ char track_name_esc[sizeof(track->name) * 2];
+ BLI_strescape(track_name_esc, track->name, sizeof(track_name_esc));
+ if (object == NULL) {
+ return BLI_sprintfN("tracking.tracks[\"%s\"]", track_name_esc);
+ }
+ else {
+ char object_name_esc[sizeof(object->name) * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ return BLI_sprintfN("tracking.objects[\"%s\"].tracks[\"%s\"]",
+ object_name_esc,
+ track_name_esc);
+ }
}
static void rna_trackingTracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -178,28 +254,9 @@ static void rna_tracking_active_plane_track_set(PointerRNA *ptr, PointerRNA valu
static void rna_trackingTrack_name_set(PointerRNA *ptr, const char *value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- MovieTracking *tracking = &clip->tracking;
MovieTrackingTrack *track = (MovieTrackingTrack *)ptr->data;
- ListBase *tracksbase = &tracking->tracks;
-
+ ListBase *tracksbase = tracking_tracksbase_from_track(clip, track);
BLI_strncpy(track->name, value, sizeof(track->name));
-
- /* TODO: it's a bit difficult to find list track came from knowing just
- * movie clip ID and MovieTracking structure, so keep this naive
- * search for a while */
- if (BLI_findindex(tracksbase, track) == -1) {
- MovieTrackingObject *object = tracking->objects.first;
-
- while (object) {
- if (BLI_findindex(&object->tracks, track) != -1) {
- tracksbase = &object->tracks;
- break;
- }
-
- object = object->next;
- }
- }
-
BKE_tracking_track_unique_name(tracksbase, track);
}
@@ -267,37 +324,29 @@ static void rna_trackingPlaneMarker_frame_set(PointerRNA *ptr, int value)
static char *rna_trackingPlaneTrack_path(PointerRNA *ptr)
{
+ MovieClip *clip = (MovieClip *)ptr->id.data;
MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
- char name_esc[sizeof(plane_track->name) * 2];
- BLI_strescape(name_esc, plane_track->name, sizeof(name_esc));
- return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", name_esc);
+ char track_name_esc[sizeof(plane_track->name) * 2];
+ MovieTrackingObject *object = tracking_object_from_plane_track(clip, plane_track);
+ BLI_strescape(track_name_esc, plane_track->name, sizeof(track_name_esc));
+ if (object == NULL) {
+ return BLI_sprintfN("tracking.plane_tracks[\"%s\"]", track_name_esc);
+ }
+ else {
+ char object_name_esc[sizeof(object->name) * 2];
+ BLI_strescape(object_name_esc, object->name, sizeof(object_name_esc));
+ return BLI_sprintfN("tracking.objects[\"%s\"].plane_tracks[\"%s\"]",
+ object_name_esc,
+ track_name_esc);
+ }
}
static void rna_trackingPlaneTrack_name_set(PointerRNA *ptr, const char *value)
{
MovieClip *clip = (MovieClip *)ptr->id.data;
- MovieTracking *tracking = &clip->tracking;
MovieTrackingPlaneTrack *plane_track = (MovieTrackingPlaneTrack *)ptr->data;
- ListBase *plane_tracks_base = &tracking->plane_tracks;
-
+ ListBase *plane_tracks_base = tracking_tracksbase_from_plane_track(clip, plane_track);
BLI_strncpy(plane_track->name, value, sizeof(plane_track->name));
-
- /* TODO: it's a bit difficult to find list track came from knowing just
- * movie clip ID and MovieTracking structure, so keep this naive
- * search for a while */
- if (BLI_findindex(plane_tracks_base, plane_track) == -1) {
- MovieTrackingObject *object = tracking->objects.first;
-
- while (object) {
- if (BLI_findindex(&object->plane_tracks, plane_track) != -1) {
- plane_tracks_base = &object->plane_tracks;
- break;
- }
-
- object = object->next;
- }
- }
-
BKE_tracking_plane_track_unique_name(plane_tracks_base, plane_track);
}
@@ -926,7 +975,7 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_default_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "default_algorithm_flag", TRACK_ALGORITHM_FLAG_USE_MASK);
RNA_def_property_ui_text(prop, "Use Mask",
- "Use a grease pencil datablock as a mask to use only specified areas of pattern "
+ "Use a grease pencil data-block as a mask to use only specified areas of pattern "
"when tracking");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
@@ -1304,7 +1353,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "algorithm_flag", TRACK_ALGORITHM_FLAG_USE_MASK);
RNA_def_property_ui_text(prop, "Use Mask",
- "Use a grease pencil datablock as a mask to use only specified areas of pattern "
+ "Use a grease pencil data-block as a mask to use only specified areas of pattern "
"when tracking");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 2595771bece..5f11dd51282 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -43,7 +43,7 @@
#include "WM_types.h"
/* see WM_types.h */
-EnumPropertyItem operator_context_items[] = {
+EnumPropertyItem rna_enum_operator_context_items[] = {
{WM_OP_INVOKE_DEFAULT, "INVOKE_DEFAULT", 0, "Invoke Default", ""},
{WM_OP_INVOKE_REGION_WIN, "INVOKE_REGION_WIN", 0, "Invoke Region Window", ""},
{WM_OP_INVOKE_REGION_CHANNELS, "INVOKE_REGION_CHANNELS", 0, "Invoke Region Channels", ""},
@@ -59,7 +59,7 @@ EnumPropertyItem operator_context_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem uilist_layout_type_items[] = {
+EnumPropertyItem rna_enum_uilist_layout_type_items[] = {
{UILST_LAYOUT_DEFAULT, "DEFAULT", 0, "Default Layout", "Use the default, multi-rows layout"},
{UILST_LAYOUT_COMPACT, "COMPACT", 0, "Compact Layout", "Use the compact, single-row layout"},
{UILST_LAYOUT_GRID, "GRID", 0, "Grid Layout", "Use the grid-based layout"},
@@ -886,7 +886,7 @@ static void rna_def_ui_layout(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_UILayout_active_get", "rna_UILayout_active_set");
prop = RNA_def_property(srna, "operator_context", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, operator_context_items);
+ RNA_def_property_enum_items(prop, rna_enum_operator_context_items);
RNA_def_property_enum_funcs(prop, "rna_UILayout_op_context_get", "rna_UILayout_op_context_set", NULL);
prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
@@ -996,13 +996,13 @@ static void rna_def_panel(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
- RNA_def_property_enum_items(prop, space_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Space type", "The space where the panel is going to be used in");
prop = RNA_def_property(srna, "bl_region_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->region_type");
- RNA_def_property_enum_items(prop, region_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_region_type_items);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Region Type", "The region where the panel is going to be used in");
@@ -1052,7 +1052,7 @@ static void rna_def_uilist(BlenderRNA *brna)
/* Data */
prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, uilist_layout_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_uilist_layout_type_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* Filter options */
@@ -1187,7 +1187,7 @@ static void rna_def_header(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type->space_type");
- RNA_def_property_enum_items(prop, space_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_flag(prop, PROP_REGISTER);
RNA_def_property_ui_text(prop, "Space type", "The space where the header is going to be used in");
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 81b6a77f683..80777f57811 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -50,7 +50,7 @@
#define DEF_ICON_BLANK_SKIP
#define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""},
#define DEF_VICO(name) {VICO_##name, (#name), 0, (#name), ""},
-EnumPropertyItem icon_items[] = {
+EnumPropertyItem rna_enum_icon_items[] = {
#include "UI_icons.h"
{0, NULL, 0, NULL, NULL}
};
@@ -389,7 +389,7 @@ static void api_ui_item_common(FunctionRNA *func)
api_ui_item_common_text(func);
prop = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, icon_items);
+ RNA_def_property_enum_items(prop, rna_enum_icon_items);
RNA_def_property_ui_text(prop, "Icon", "Override automatic icon of the item");
}
@@ -698,10 +698,10 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_preview", "uiTemplatePreview");
RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
- parm = RNA_def_pointer(func, "id", "ID", "", "ID datablock");
+ parm = RNA_def_pointer(func, "id", "ID", "", "ID data-block");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?");
- RNA_def_pointer(func, "parent", "ID", "", "ID datablock");
+ RNA_def_pointer(func, "parent", "ID", "", "ID data-block");
RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot");
RNA_def_string(func, "preview_id", NULL, 0, "",
"Identifier of this preview widget, if not set the ID type will be used "
@@ -843,7 +843,7 @@ void RNA_api_ui_layout(StructRNA *srna)
"Identifier of a string property in items, to use as tooltip content");
RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Default and minimum number of rows to display", 0, INT_MAX);
RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Default maximum number of rows to display", 0, INT_MAX);
- RNA_def_enum(func, "type", uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use");
+ RNA_def_enum(func, "type", rna_enum_uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use");
RNA_def_int(func, "columns", 9, 0, INT_MAX, "", "Number of items to display per row, for GRID layout", 0, INT_MAX);
func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index f2e62e6f559..efd302ce451 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -68,7 +68,7 @@ static EnumPropertyItem opensubdiv_compute_type_items[] = {
{USER_OPENSUBDIV_COMPUTE_OPENMP, "OPENMP", 0, "OpenMP", ""},
{USER_OPENSUBDIV_COMPUTE_OPENCL, "OPENCL", 0, "OpenCL", ""},
{USER_OPENSUBDIV_COMPUTE_CUDA, "CUDA", 0, "CUDA", ""},
- {USER_OPENSUBDIV_COMPUTE_GLSL_TRANSFORM_FEEDBACK, "GLSL_TRANSFORM_FEEDBACL", 0, "GLSL Transform Feedback", ""},
+ {USER_OPENSUBDIV_COMPUTE_GLSL_TRANSFORM_FEEDBACK, "GLSL_TRANSFORM_FEEDBACK", 0, "GLSL Transform Feedback", ""},
{USER_OPENSUBDIV_COMPUTE_GLSL_COMPUTE, "GLSL_COMPUTE", 0, "GLSL Compute", ""},
{ 0, NULL, 0, NULL, NULL}
};
@@ -88,7 +88,7 @@ static EnumPropertyItem audio_device_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem navigation_mode_items[] = {
+EnumPropertyItem rna_enum_navigation_mode_items[] = {
{VIEW_NAVIGATION_WALK, "WALK", 0, "Walk", "Interactively walk or free navigate around the scene"},
{VIEW_NAVIGATION_FLY, "FLY", 0, "Fly", "Use fly dynamics to navigate the scene"},
{0, NULL, 0, NULL, NULL}
@@ -144,12 +144,19 @@ static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}
-static void rna_userdef_virtual_pixel_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+static void rna_userdef_virtual_pixel_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
/* font's are stored at each DPI level, without this we can easy load 100's of fonts */
BLF_cache_clear();
BKE_userdef_state();
+
+ /* force setting drawable again */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm) {
+ wm->windrawable = NULL;
+ }
+
WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}
@@ -161,25 +168,6 @@ static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene
UI_reinit_font();
}
-static void update_cb(PBVHNode *node, void *UNUSED(rebuild))
-{
- BKE_pbvh_node_mark_rebuild_draw(node);
-}
-
-static void rna_userdef_vbo_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
-{
- Object *ob;
-
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- GPU_drawobject_free(ob->derivedFinal);
-
- if (ob->sculpt && ob->sculpt->pbvh) {
- BKE_pbvh_search_callback(ob->sculpt->pbvh, NULL, NULL, update_cb, NULL);
- }
- }
- GPU_buffer_multires_free(false);
-}
-
static void rna_userdef_show_manipulator_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
UserDef *userdef = (UserDef *)ptr->data;
@@ -400,11 +388,6 @@ static void rna_UserDef_viewport_lights_update(Main *bmain, Scene *scene, Pointe
rna_userdef_update(bmain, scene, ptr);
}
-static int rna_Scene_GPU_selection_supported(UserDef *UNUSED(U))
-{
- return GPU_select_query_check_support();
-}
-
static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
wmWindowManager *wm = bmain->wm.first;
@@ -1617,11 +1600,18 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
rna_def_userdef_theme_spaces_gradient(srna);
+ /* General Viewport options */
+
prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Grid", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "clipping_border_3d", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Clipping Border", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "wire", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Wire", "");
@@ -1632,32 +1622,18 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Wire Edit", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- rna_def_userdef_theme_spaces_gpencil(srna);
- prop = RNA_def_property(srna, "lamp", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Lamp", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* Grease Pencil */
- prop = RNA_def_property(srna, "speaker", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Speaker", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "camera", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Camera", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
+ rna_def_userdef_theme_spaces_gpencil(srna);
- prop = RNA_def_property(srna, "view_overlay", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "text_grease_pencil", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "time_gp_keyframe");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "View Overlay", "");
+ RNA_def_property_ui_text(prop, "Grease Pencil Keyframe", "Color for indicating Grease Pencil keyframes");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "empty", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Empty", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* Object specific options */
prop = RNA_def_property(srna, "object_selected", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "select");
@@ -1683,14 +1659,42 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Object Grouped Active", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "transform", PROP_FLOAT, PROP_COLOR_GAMMA);
+ prop = RNA_def_property(srna, "text_keyframe", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "time_keyframe");
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Transform", "");
+ RNA_def_property_ui_text(prop, "Object Keyframe", "Color for indicating Object keyframes");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
+
+ /* Object type options */
+
+ prop = RNA_def_property(srna, "camera", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Camera", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "empty", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Empty", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "lamp", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Lamp", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "speaker", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Speaker", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ /* Mesh Object specific */
+
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_edge(srna);
rna_def_userdef_theme_spaces_face(srna);
+
+ /* Mesh Object specific curves*/
+
rna_def_userdef_theme_spaces_curves(srna, true, true, true, false);
prop = RNA_def_property(srna, "extra_edge_len", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -1734,10 +1738,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Split Normal", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "bone_solid", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Bone Solid", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* Armature Object specific */
prop = RNA_def_property(srna, "bone_pose", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
@@ -1749,16 +1750,12 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bone Pose Active", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_float_sdna(prop, NULL, "cframe");
+ prop = RNA_def_property(srna, "bone_solid", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Current Frame", "");
+ RNA_def_property_ui_text(prop, "Bone Solid", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "outline_width", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 1, 5);
- RNA_def_property_ui_text(prop, "Outline Width", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
+ /* misc */
prop = RNA_def_property(srna, "bundle_solid", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "bundle_solid");
@@ -1777,12 +1774,29 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Skin Root", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "clipping_border_3d", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 4);
- RNA_def_property_ui_text(prop, "Clipping Border", "");
+ prop = RNA_def_property(srna, "view_overlay", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "View Overlay", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
+
+ prop = RNA_def_property(srna, "transform", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Transform", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "cframe");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Current Frame", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
rna_def_userdef_theme_spaces_paint_curves(srna);
+
+ prop = RNA_def_property(srna, "outline_width", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, 5);
+ RNA_def_property_ui_text(prop, "Outline Width", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
}
@@ -2572,6 +2586,11 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Meta Strip", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "text_strip", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Text Strip", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "cframe");
RNA_def_property_array(prop, 3);
@@ -3362,7 +3381,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
static EnumPropertyItem zoom_frame_modes[] = {
{ZOOM_FRAME_MODE_KEEP_RANGE, "KEEP_RANGE", 0, "Keep Range", ""},
{ZOOM_FRAME_MODE_SECONDS, "SECONDS", 0, "Seconds", ""},
- {ZOOM_FRAME_MODE_KEYFRAMES, "KEYFRAMES", 0, "Keyframes", ""},
+ {ZOOM_FRAME_MODE_KEYFRAMES, "KEYFRAMES", 0, "Keyframes", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3464,11 +3483,6 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Prompt Quit",
"Ask for confirmation when quitting through the window close button");
- prop = RNA_def_property(srna, "use_gl_warn_support", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag2", USER_OPENGL_NO_WARN_SUPPORT);
- RNA_def_property_ui_text(prop, "Warn On Deprecated OpenGL",
- "Pop up a warning when an old OpenGL version is detected");
-
/* Toolbox click-hold delay */
prop = RNA_def_property(srna, "open_left_mouse_delay", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "tb_leftmouse");
@@ -3738,14 +3752,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
"and also Color is based on the transform axis");
prop = RNA_def_property(srna, "keyframe_new_interpolation_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, beztriple_interpolation_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_mode_items);
RNA_def_property_enum_sdna(prop, NULL, "ipo_new");
RNA_def_property_ui_text(prop, "New Interpolation Type",
"Interpolation mode used for first keyframe on newly added F-Curves "
"(subsequent keyframes take interpolation from preceding keyframe)");
prop = RNA_def_property(srna, "keyframe_new_handle_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, keyframe_handle_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_keyframe_handle_type_items);
RNA_def_property_enum_sdna(prop, NULL, "keyhandles_new");
RNA_def_property_ui_text(prop, "New Handles Type", "Handle type for handles of new keyframes");
@@ -3776,17 +3790,13 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil Euclidean Distance",
"Distance moved by mouse when drawing stroke to include");
- prop = RNA_def_property(srna, "use_grease_pencil_smooth_stroke", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "gp_settings", GP_PAINT_DOSMOOTH);
- RNA_def_property_ui_text(prop, "Grease Pencil Smooth Stroke", "Smooth the final stroke");
-
prop = RNA_def_property(srna, "use_grease_pencil_simplify_stroke", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "gp_settings", GP_PAINT_DOSIMPLIFY);
RNA_def_property_ui_text(prop, "Grease Pencil Simplify Stroke", "Simplify the final stroke");
prop = RNA_def_property(srna, "grease_pencil_eraser_radius", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "gp_eraser");
- RNA_def_property_range(prop, 0, 100);
+ RNA_def_property_range(prop, 1, 500);
RNA_def_property_ui_text(prop, "Grease Pencil Eraser Radius", "Radius of eraser 'brush'");
@@ -3861,9 +3871,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
static void rna_def_userdef_system(BlenderRNA *brna)
{
- FunctionRNA *func;
PropertyRNA *prop;
- PropertyRNA *parm;
StructRNA *srna;
static EnumPropertyItem gl_texture_clamp_items[] = {
@@ -4031,6 +4039,11 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Interface Font", "Path to interface font");
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
+ prop = RNA_def_property(srna, "font_path_ui_mono", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "font_path_ui_mono");
+ RNA_def_property_ui_text(prop, "Mono-space Font", "Path to interface mono-space Font");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
+
prop = RNA_def_property(srna, "scrollback", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "scrollback");
RNA_def_property_range(prop, 32, 32768);
@@ -4162,13 +4175,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Image Draw Method", "Method used for displaying images on the screen");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_vertex_buffer_objects", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_VBO);
- RNA_def_property_ui_text(prop, "VBOs",
- "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering");
- /* this isn't essential but nice to check if VBO draws any differently */
- RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_vbo_update");
-
prop = RNA_def_property(srna, "anisotropic_filter", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "anisotropic_filter");
RNA_def_property_enum_items(prop, anisotropic_items);
@@ -4250,11 +4256,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased");
RNA_def_property_update(prop, 0, "rna_userdef_text_update");
- func = RNA_def_function(srna, "is_occlusion_query_supported", "rna_Scene_GPU_selection_supported");
- parm = RNA_def_boolean(func, "is_supported", 0, "Occlusion Query Support",
- "Check if GPU supports Occlusion Queries");
- RNA_def_function_return(func, parm);
-
prop = RNA_def_property(srna, "select_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "gpu_select_method");
RNA_def_property_enum_items(prop, gpu_select_method_items);
@@ -4385,7 +4386,7 @@ static void rna_def_userdef_input(BlenderRNA *brna)
/* View Navigation */
prop = RNA_def_property(srna, "navigation_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "navigation_mode");
- RNA_def_property_enum_items(prop, navigation_mode_items);
+ RNA_def_property_enum_items(prop, rna_enum_navigation_mode_items);
RNA_def_property_ui_text(prop, "View Navigation", "Which method to use for viewport navigation");
prop = RNA_def_property(srna, "walk_navigation", PROP_POINTER, PROP_NONE);
@@ -4550,7 +4551,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_hidden_files_datablocks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_HIDE_DOT);
- RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/datablocks that start with a dot (.*)");
+ RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/data-blocks that start with a dot (.*)");
prop = RNA_def_property(srna, "use_filter_files", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_FILTERFILEEXTS);
@@ -4685,7 +4686,7 @@ static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cpro
RNA_def_function_flag(func, FUNC_NO_SELF);
RNA_def_function_ui_description(func, "Add a new add-on");
/* return type */
- parm = RNA_def_pointer(func, "addon", "Addon", "", "Addon datablock");
+ parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on data");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_userdef_addon_remove");
diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c
index 0879f4d355d..e9ba0c78439 100644
--- a/source/blender/makesrna/intern/rna_vfont.c
+++ b/source/blender/makesrna/intern/rna_vfont.c
@@ -48,9 +48,9 @@ static int rna_VectorFont_filepath_editable(PointerRNA *ptr)
{
VFont *vfont = ptr->id.data;
if (BKE_vfont_is_builtin(vfont)) {
- return false;
+ return 0;
}
- return true;
+ return PROP_EDITABLE;
}
static void rna_VectorFont_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_vfont_api.c b/source/blender/makesrna/intern/rna_vfont_api.c
index d92e75daf0a..6a2a7f3ffad 100644
--- a/source/blender/makesrna/intern/rna_vfont_api.c
+++ b/source/blender/makesrna/intern/rna_vfont_api.c
@@ -67,7 +67,7 @@ void RNA_api_vfont(StructRNA *srna)
func = RNA_def_function(srna, "unpack", "rna_VectorFont_unpack");
RNA_def_function_ui_description(func, "Unpack the font to the samples filename");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_enum(func, "method", unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
+ RNA_def_enum(func, "method", rna_enum_unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index aa4bfe0462e..51c410e44e1 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -86,6 +86,9 @@ static EnumPropertyItem event_mouse_type_items[] = {
{ACTIONMOUSE, "ACTIONMOUSE", 0, "Action", ""},
{SELECTMOUSE, "SELECTMOUSE", 0, "Select", ""},
{0, "", 0, NULL, NULL},
+ {TABLET_STYLUS, "PEN", 0, "Pen", ""},
+ {TABLET_ERASER, "ERASER", 0, "Eraser", ""},
+ {0, "", 0, NULL, NULL},
{MOUSEMOVE, "MOUSEMOVE", 0, "Move", ""},
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""},
@@ -167,7 +170,7 @@ static EnumPropertyItem event_ndof_type_items[] = {
#endif
/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
-EnumPropertyItem event_type_items[] = {
+EnumPropertyItem rna_enum_event_type_items[] = {
/* Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names. */
{0, "NONE", 0, "", ""},
{LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", "LMB"},
@@ -180,6 +183,9 @@ EnumPropertyItem event_type_items[] = {
{ACTIONMOUSE, "ACTIONMOUSE", 0, "Action Mouse", "MBA"},
{SELECTMOUSE, "SELECTMOUSE", 0, "Select Mouse", "MBS"},
{0, "", 0, NULL, NULL},
+ {TABLET_STYLUS, "PEN", 0, "Pen", ""},
+ {TABLET_ERASER, "ERASER", 0, "Eraser", ""},
+ {0, "", 0, NULL, NULL},
{MOUSEMOVE, "MOUSEMOVE", 0, "Mouse Move", "MsMov"},
{INBETWEEN_MOUSEMOVE, "INBETWEEN_MOUSEMOVE", 0, "In-between Move", "MsSubMov"},
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", "MsPan"},
@@ -374,7 +380,7 @@ EnumPropertyItem event_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem event_value_items[] = {
+EnumPropertyItem rna_enum_event_value_items[] = {
{KM_ANY, "ANY", 0, "Any", ""},
{KM_NOTHING, "NOTHING", 0, "Nothing", ""},
{KM_PRESS, "PRESS", 0, "Press", ""},
@@ -392,7 +398,7 @@ EnumPropertyItem event_value_items[] = {
{0, NULL, 0, NULL, NULL}
};
-EnumPropertyItem keymap_propvalue_items[] = {
+EnumPropertyItem rna_enum_keymap_propvalue_items[] = {
{0, "NONE", 0, "", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -423,7 +429,7 @@ static EnumPropertyItem operator_flag_items[] = {
};
#endif
-EnumPropertyItem operator_return_items[] = {
+EnumPropertyItem rna_enum_operator_return_items[] = {
{OPERATOR_RUNNING_MODAL, "RUNNING_MODAL", 0, "Running Modal", "Keep the operator running with blender"},
{OPERATOR_CANCELLED, "CANCELLED", 0, "Cancelled", "When no action has been taken, operator exits"},
{OPERATOR_FINISHED, "FINISHED", 0, "Finished", "When the operator is complete, operator exits"},
@@ -434,7 +440,7 @@ EnumPropertyItem operator_return_items[] = {
};
/* flag/enum */
-EnumPropertyItem wm_report_items[] = {
+EnumPropertyItem rna_enum_wm_report_items[] = {
{RPT_DEBUG, "DEBUG", 0, "Debug", ""},
{RPT_INFO, "INFO", 0, "Info", ""},
{RPT_OPERATOR, "OPERATOR", 0, "Operator", ""},
@@ -700,7 +706,7 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value)
}
}
-/* assumes value to be an enum from event_type_items */
+/* assumes value to be an enum from rna_enum_event_type_items */
/* function makes sure keymodifiers are only valid keys, ESC keeps it unaltered */
static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
{
@@ -731,7 +737,7 @@ static EnumPropertyItem *rna_KeyMapItem_type_itemf(bContext *UNUSED(C), PointerR
if (map_type == KMI_TYPE_TIMER) return event_timer_type_items;
if (map_type == KMI_TYPE_NDOF) return event_ndof_type_items;
if (map_type == KMI_TYPE_TEXTINPUT) return event_textinput_type_items;
- else return event_type_items;
+ else return rna_enum_event_type_items;
}
static EnumPropertyItem *rna_KeyMapItem_value_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop),
@@ -744,7 +750,7 @@ static EnumPropertyItem *rna_KeyMapItem_value_itemf(bContext *UNUSED(C), Pointer
if (map_type == KMI_TYPE_TWEAK)
return event_tweak_value_items;
else
- return event_value_items;
+ return rna_enum_event_value_items;
}
static EnumPropertyItem *rna_KeyMapItem_propvalue_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop),
@@ -769,7 +775,7 @@ static EnumPropertyItem *rna_KeyMapItem_propvalue_itemf(bContext *C, PointerRNA
}
- return keymap_propvalue_items; /* ERROR */
+ return rna_enum_keymap_propvalue_items; /* ERROR */
}
static int rna_KeyMapItem_any_get(PointerRNA *ptr)
@@ -1667,13 +1673,14 @@ static void rna_def_event(BlenderRNA *brna)
/* enums */
prop = RNA_def_property(srna, "value", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "val");
- RNA_def_property_enum_items(prop, event_value_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_value_items);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Value", "The type of event, only applies to some");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "");
@@ -1830,15 +1837,15 @@ static void rna_def_window_stereo3d(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Stereo 3D Display", "Settings for stereo 3D display");
prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, stereo3d_display_items);
+ RNA_def_property_enum_items(prop, rna_enum_stereo3d_display_items);
RNA_def_property_ui_text(prop, "Display Mode", "");
prop = RNA_def_property(srna, "anaglyph_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, stereo3d_anaglyph_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_stereo3d_anaglyph_type_items);
RNA_def_property_ui_text(prop, "Anaglyph Type", "");
prop = RNA_def_property(srna, "interlace_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, stereo3d_interlace_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_stereo3d_interlace_type_items);
RNA_def_property_ui_text(prop, "Interlace Type", "");
prop = RNA_def_property(srna, "use_interlace_swap", PROP_BOOLEAN, PROP_BOOLEAN);
@@ -1946,7 +1953,7 @@ static void rna_def_windowmanager(BlenderRNA *brna)
srna = RNA_def_struct(brna, "WindowManager", "ID");
RNA_def_struct_ui_text(srna, "Window Manager",
- "Window manager datablock defining open windows and other user interface data");
+ "Window manager data-block defining open windows and other user interface data");
RNA_def_struct_clear_flag(srna, STRUCT_ID_REFCOUNT);
RNA_def_struct_sdna(srna, "wmWindowManager");
@@ -2046,13 +2053,13 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spaceid");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, space_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_space_type_items);
RNA_def_property_ui_text(prop, "Space Type", "Optional space type keymap is associated with");
prop = RNA_def_property(srna, "region_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "regionid");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_enum_items(prop, region_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_region_type_items);
RNA_def_property_ui_text(prop, "Region Type", "Optional region type keymap is associated with");
prop = RNA_def_property(srna, "keymap_items", PROP_COLLECTION, PROP_NONE);
@@ -2119,14 +2126,15 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_type_itemf");
RNA_def_property_ui_text(prop, "Type", "Type of event");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
prop = RNA_def_property(srna, "value", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "val");
- RNA_def_property_enum_items(prop, event_value_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_value_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_value_itemf");
RNA_def_property_ui_text(prop, "Value", "");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
@@ -2176,7 +2184,8 @@ static void rna_def_keyconfig(BlenderRNA *brna)
prop = RNA_def_property(srna, "key_modifier", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "keymodifier");
- RNA_def_property_enum_items(prop, event_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
RNA_def_property_enum_funcs(prop, NULL, "rna_wmKeyMapItem_keymodifier_set", NULL);
RNA_def_property_ui_text(prop, "Key Modifier", "Regular key pressed as a modifier");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
@@ -2185,11 +2194,10 @@ static void rna_def_keyconfig(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", KMI_EXPANDED);
RNA_def_property_ui_text(prop, "Expanded", "Show key map event and property details in the user interface");
RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1);
- RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
prop = RNA_def_property(srna, "propvalue", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "propvalue");
- RNA_def_property_enum_items(prop, keymap_propvalue_items);
+ RNA_def_property_enum_items(prop, rna_enum_keymap_propvalue_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_propvalue_itemf");
RNA_def_property_ui_text(prop, "Property Value", "The value this event translates to in a modal keymap");
RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index e819d331124..7cf0cf67269 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -46,7 +46,7 @@
#include "rna_internal.h" /* own include */
/* confusingm 2 enums mixed up here */
-EnumPropertyItem window_cursor_items[] = {
+EnumPropertyItem rna_enum_window_cursor_items[] = {
{CURSOR_STD, "DEFAULT", 0, "Default", ""},
{CURSOR_NONE, "NONE", 0, "None", ""},
{CURSOR_WAIT, "WAIT", 0, "Wait", ""},
@@ -353,7 +353,7 @@ static void rna_generic_op_invoke(FunctionRNA *func, int flag)
}
if (flag & WM_GEN_INVOKE_RETURN) {
- parm = RNA_def_enum_flag(func, "result", operator_return_items, OPERATOR_CANCELLED, "result", "");
+ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
RNA_def_function_return(func, parm);
}
}
@@ -372,13 +372,13 @@ void RNA_api_window(StructRNA *srna)
func = RNA_def_function(srna, "cursor_set", "WM_cursor_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(parm, window_cursor_items);
+ RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor");
func = RNA_def_function(srna, "cursor_modal_set", "WM_cursor_modal_set");
parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(parm, window_cursor_items);
+ RNA_def_property_enum_items(parm, rna_enum_window_cursor_items);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_function_ui_description(func, "Set the cursor, so the previous cursor can be restored");
@@ -420,7 +420,7 @@ void RNA_api_wm(StructRNA *srna)
/* Progress bar interface */
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
- RNA_def_function_ui_description(func, "Start Progress bar");
+ RNA_def_function_ui_description(func, "Start progress report");
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]");
@@ -436,7 +436,7 @@ void RNA_api_wm(StructRNA *srna)
RNA_def_property_ui_text(parm, "value", "any value between min and max as set in progress_begin()");
func = RNA_def_function(srna, "progress_end", "rna_progress_end");
- RNA_def_function_ui_description(func, "Terminate Progress bar");
+ RNA_def_function_ui_description(func, "Terminate progress report");
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_props_popup", "rna_Operator_props_popup");
@@ -468,7 +468,7 @@ void RNA_api_wm(StructRNA *srna)
parm = RNA_def_string(func, "title", NULL, 0, "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(parm, icon_items);
+ RNA_def_property_enum_items(parm, rna_enum_icon_items);
/* return */
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
@@ -486,7 +486,7 @@ void RNA_api_wm(StructRNA *srna)
parm = RNA_def_string(func, "title", NULL, 0, "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(parm, icon_items);
+ RNA_def_property_enum_items(parm, rna_enum_icon_items);
parm = RNA_def_pointer(func, "event", "Event", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
/* return */
@@ -508,7 +508,7 @@ void RNA_api_operator(StructRNA *srna)
/* utility, not for registering */
func = RNA_def_function(srna, "report", "rna_Operator_report");
- parm = RNA_def_enum_flag(func, "type", wm_report_items, 0, "Type", "");
+ parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -532,7 +532,7 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
/* better name? */
- parm = RNA_def_enum_flag(func, "result", operator_return_items, OPERATOR_CANCELLED, "result", "");
+ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
RNA_def_function_return(func, parm);
/* check */
@@ -555,7 +555,7 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
/* better name? */
- parm = RNA_def_enum_flag(func, "result", operator_return_items, OPERATOR_CANCELLED, "result", "");
+ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "modal", NULL); /* same as invoke */
@@ -567,7 +567,7 @@ void RNA_api_operator(StructRNA *srna)
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
/* better name? */
- parm = RNA_def_enum_flag(func, "result", operator_return_items, OPERATOR_CANCELLED, "result", "");
+ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", "");
RNA_def_function_return(func, parm);
/* draw */
@@ -592,7 +592,7 @@ void RNA_api_macro(StructRNA *srna)
/* utility, not for registering */
func = RNA_def_function(srna, "report", "rna_Operator_report");
- parm = RNA_def_enum_flag(func, "type", wm_report_items, 0, "Type", "");
+ parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_string(func, "message", NULL, 0, "Report Message", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -662,16 +662,16 @@ void RNA_api_keymapitems(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "idname", NULL, 0, "Operator Identifier", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", event_type_items, 0, "Type", "");
+ parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "value", event_value_items, 0, "Value", "");
+ parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
RNA_def_boolean(func, "shift", 0, "Shift", "");
RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
RNA_def_boolean(func, "alt", 0, "Alt", "");
RNA_def_boolean(func, "oskey", 0, "OS Key", "");
- RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", "");
+ RNA_def_enum(func, "key_modifier", rna_enum_event_type_items, 0, "Key Modifier", "");
RNA_def_boolean(func, "head", 0, "At Head",
"Force item to be added at start (not end) of key map so that "
"it doesn't get blocked by an existing key map item");
@@ -682,16 +682,16 @@ void RNA_api_keymapitems(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "propvalue", NULL, 0, "Property Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", event_type_items, 0, "Type", "");
+ parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "value", event_value_items, 0, "Value", "");
+ parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_boolean(func, "any", 0, "Any", "");
RNA_def_boolean(func, "shift", 0, "Shift", "");
RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
RNA_def_boolean(func, "alt", 0, "Alt", "");
RNA_def_boolean(func, "oskey", 0, "OS Key", "");
- RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", "");
+ RNA_def_enum(func, "key_modifier", rna_enum_event_type_items, 0, "Key Modifier", "");
parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item");
RNA_def_function_return(func, parm);
@@ -717,8 +717,8 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", "");
- RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+ RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
+ RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
RNA_def_boolean(func, "modal", 0, "Modal", "");
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Added key map");
RNA_def_function_return(func, parm);
@@ -732,8 +732,8 @@ void RNA_api_keymaps(StructRNA *srna)
func = RNA_def_function(srna, "find", "rna_keymap_find"); /* find_keymap */
parm = RNA_def_string(func, "name", NULL, 0, "Name", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", "");
- RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+ RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
+ RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index 3f55ad9c668..f950ba75c42 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -142,7 +142,7 @@ static void rna_def_world_mtex(BlenderRNA *brna)
srna = RNA_def_struct(brna, "WorldTextureSlot", "TextureSlot");
RNA_def_struct_sdna(srna, "MTex");
- RNA_def_struct_ui_text(srna, "World Texture Slot", "Texture slot for textures in a World datablock");
+ RNA_def_struct_ui_text(srna, "World Texture Slot", "Texture slot for textures in a World data-block");
/* map to */
prop = RNA_def_property(srna, "use_map_blend", PROP_BOOLEAN, PROP_NONE);
@@ -238,7 +238,7 @@ static void rna_def_lighting(BlenderRNA *brna)
srna = RNA_def_struct(brna, "WorldLighting", NULL);
RNA_def_struct_sdna(srna, "World");
RNA_def_struct_nested(brna, srna, "World");
- RNA_def_struct_ui_text(srna, "Lighting", "Lighting for a World datablock");
+ RNA_def_struct_ui_text(srna, "Lighting", "Lighting for a World data-block");
/* ambient occlusion */
prop = RNA_def_property(srna, "use_ambient_occlusion", PROP_BOOLEAN, PROP_NONE);
@@ -447,7 +447,7 @@ void RNA_def_world(BlenderRNA *brna)
srna = RNA_def_struct(brna, "World", "ID");
RNA_def_struct_ui_text(srna, "World",
- "World datablock describing the environment and ambient lighting of a scene");
+ "World data-block describing the environment and ambient lighting of a scene");
RNA_def_struct_ui_icon(srna, ICON_WORLD_DATA);
rna_def_animdata_common(srna);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index ad230dede24..0de7676e8f8 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -37,6 +37,7 @@ set(INC
../render/extern/include
../../../intern/elbeem/extern
../../../intern/guardedalloc
+ ../../../intern/eigen
)
set(INC_SYS
@@ -144,13 +145,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-if(WITH_OPENNL)
- add_definitions(-DWITH_OPENNL)
- list(APPEND INC_SYS
- ../../../intern/opennl/extern
- )
-endif()
-
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
endif()
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
deleted file mode 100644
index 7be295aa1a0..00000000000
--- a/source/blender/modifiers/SConscript
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import('env')
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- './intern',
- '#/intern/guardedalloc',
- '#/intern/elbeem/extern',
- '#/intern/opennl/extern',
- '../render/extern/include',
- '../bmesh',
- '../include',
- '../blenlib',
- '../blenfont',
- '../depsgraph',
- '../makesdna',
- '../makesrna',
- '../blenkernel',
- '../gpu',
- env['BF_ZLIB_INC'],
- ]
-
-defs = []
-
-if env['WITH_BF_BOOLEAN']:
- incs.append('#/extern/carve')
- defs.append('WITH_MOD_BOOLEAN')
-else:
- from os import path
- sources.remove(path.join('intern', 'MOD_boolean_util.c'))
-
-if env['WITH_BF_REMESH']:
- incs.append('#/intern/dualcon')
- defs.append('WITH_MOD_REMESH')
-
-if env['WITH_BF_FLUID']:
- defs.append('WITH_MOD_FLUID')
-
-if env['WITH_BF_OCEANSIM']:
- defs.append('WITH_OCEANSIM')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-if env['WITH_BF_GAMEENGINE']:
- incs.append('#/extern/recastnavigation')
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_OPENSUBDIV']:
- defs.append('WITH_OPENSUBDIV')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs.append(env['BF_PTHREADS_INC'])
-
-env.BlenderLib(libname='bf_modifiers', sources=sources,
- includes=incs, defines=defs,
- libtype=['core', 'player'], priority=[80, 40])
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 9ce31cebb66..d9ace45453c 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -45,6 +45,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_lattice.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "MEM_guardedalloc.h"
@@ -91,12 +92,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
ArmatureModifierData *amd = (ArmatureModifierData *) md;
- walk(userData, ob, &amd->object);
+ walk(userData, ob, &amd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index efb77f73ec9..ecbc3891e8c 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -48,6 +48,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_displist.h"
#include "BKE_curve.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "MOD_util.h"
@@ -90,15 +91,14 @@ static void copyData(ModifierData *md, ModifierData *target)
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
ArrayModifierData *amd = (ArrayModifierData *) md;
- walk(userData, ob, &amd->start_cap);
- walk(userData, ob, &amd->end_cap);
- walk(userData, ob, &amd->curve_ob);
- walk(userData, ob, &amd->offset_ob);
+ walk(userData, ob, &amd->start_cap, IDWALK_NOP);
+ walk(userData, ob, &amd->end_cap, IDWALK_NOP);
+ walk(userData, ob, &amd->curve_ob, IDWALK_NOP);
+ walk(userData, ob, &amd->offset_ob, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -222,8 +222,7 @@ static void dm_mvert_map_doubles(
const int target_num_verts,
const int source_start,
const int source_num_verts,
- const float dist,
- const bool with_follow)
+ const float dist)
{
const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
int i_source, i_target, i_target_low_bound, target_end, source_end;
@@ -258,7 +257,8 @@ static void dm_mvert_map_doubles(
i_source < source_num_verts;
i_source++, sve_source++)
{
- bool double_found;
+ int best_target_vertex = -1;
+ float best_dist_sq = dist * dist;
float sve_source_sumco;
/* If source has already been assigned to a target (in an earlier call, with other chunks) */
@@ -294,37 +294,38 @@ static void dm_mvert_map_doubles(
/* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */
- double_found = false;
while ((i_target < target_num_verts) &&
(sve_target->sum_co <= sve_source_sumco + dist3))
{
/* Testing distance for candidate double in target */
/* v_target is within dist3 of v_source in terms of sumco; check real distance */
- if (compare_len_v3v3(sve_source->co, sve_target->co, dist)) {
- /* Double found */
- /* If double target is itself already mapped to other vertex,
- * behavior depends on with_follow option */
- int target_vertex = sve_target->vertex_num;
- if (doubles_map[target_vertex] != -1) {
- if (with_follow) { /* with_follow option: map to initial target */
- target_vertex = doubles_map[target_vertex];
+ float dist_sq;
+ if ((dist_sq = len_squared_v3v3(sve_source->co, sve_target->co)) <= best_dist_sq) {
+ /* Potential double found */
+ best_dist_sq = dist_sq;
+ best_target_vertex = sve_target->vertex_num;
+
+ /* If target is already mapped, we only follow that mapping if final target remains
+ * close enough from current vert (otherwise no mapping at all).
+ * Note that if we later find another target closer than this one, then we check it. But if other
+ * potential targets are farther, then there will be no mapping at all for this source. */
+ while (best_target_vertex != -1 && !ELEM(doubles_map[best_target_vertex], -1, best_target_vertex)) {
+ if (compare_len_v3v3(mverts[sve_source->vertex_num].co,
+ mverts[doubles_map[best_target_vertex]].co,
+ dist))
+ {
+ best_target_vertex = doubles_map[best_target_vertex];
}
else {
- /* not with_follow: if target is mapped, then we do not map source, and stop searching */
- break;
+ best_target_vertex = -1;
}
}
- doubles_map[sve_source->vertex_num] = target_vertex;
- double_found = true;
- break;
}
i_target++;
sve_target++;
}
/* End of candidate scan: if none found then no doubles */
- if (!double_found) {
- doubles_map[sve_source->vertex_num] = -1;
- }
+ doubles_map[sve_source->vertex_num] = best_target_vertex;
}
MEM_freeN(sorted_verts_source);
@@ -431,8 +432,6 @@ static DerivedMesh *arrayModifier_doArray(
const bool use_merge = (amd->flags & MOD_ARR_MERGE) != 0;
const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge;
const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob);
- /* allow pole vertices to be used by many faces */
- const bool with_follow = use_offset_ob;
int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
@@ -509,8 +508,8 @@ static DerivedMesh *arrayModifier_doArray(
#endif
if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) {
- float scale = mat4_to_scale(amd->curve_ob->obmat);
- length = scale * amd->curve_ob->curve_cache->path->totdist;
+ float scale_fac = mat4_to_scale(amd->curve_ob->obmat);
+ length = scale_fac * amd->curve_ob->curve_cache->path->totdist;
}
}
}
@@ -633,13 +632,16 @@ static DerivedMesh *arrayModifier_doArray(
int target = full_doubles_map[prev_chunk_index];
if (target != -1) {
target += chunk_nverts; /* translate mapping */
- if (full_doubles_map[target] != -1) {
- if (with_follow) {
+ while (target != -1 && !ELEM(full_doubles_map[target], -1, target)) {
+ /* If target is already mapped, we only follow that mapping if final target remains
+ * close enough from current vert (otherwise no mapping at all). */
+ if (compare_len_v3v3(result_dm_verts[this_chunk_index].co,
+ result_dm_verts[full_doubles_map[target]].co,
+ amd->merge_dist))
+ {
target = full_doubles_map[target];
}
else {
- /* The rule here is to not follow mapping to chunk N-2, which could be too far
- * so if target vertex was itself mapped, then this vertex is not mapped */
target = -1;
}
}
@@ -655,8 +657,7 @@ static DerivedMesh *arrayModifier_doArray(
chunk_nverts,
c * chunk_nverts,
chunk_nverts,
- amd->merge_dist,
- with_follow);
+ amd->merge_dist);
}
}
}
@@ -675,8 +676,7 @@ static DerivedMesh *arrayModifier_doArray(
last_chunk_nverts,
first_chunk_start,
first_chunk_nverts,
- amd->merge_dist,
- with_follow);
+ amd->merge_dist);
}
/* start capping */
@@ -700,8 +700,7 @@ static DerivedMesh *arrayModifier_doArray(
first_chunk_nverts,
start_cap_start,
start_cap_nverts,
- amd->merge_dist,
- false);
+ amd->merge_dist);
}
}
@@ -725,8 +724,7 @@ static DerivedMesh *arrayModifier_doArray(
last_chunk_nverts,
end_cap_start,
end_cap_nverts,
- amd->merge_dist,
- false);
+ amd->merge_dist);
}
}
/* done capping */
@@ -735,11 +733,18 @@ static DerivedMesh *arrayModifier_doArray(
tot_doubles = 0;
if (use_merge) {
for (i = 0; i < result_nverts; i++) {
- if (full_doubles_map[i] != -1) {
- if (i == full_doubles_map[i]) {
+ int new_i = full_doubles_map[i];
+ if (new_i != -1) {
+ /* We have to follow chains of doubles (merge start/end especially is likely to create some),
+ * those are not supported at all by CDDM_merge_verts! */
+ while (!ELEM(full_doubles_map[new_i], -1, new_i)) {
+ new_i = full_doubles_map[new_i];
+ }
+ if (i == new_i) {
full_doubles_map[i] = -1;
}
else {
+ full_doubles_map[i] = new_i;
tot_doubles++;
}
}
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index eb54a3c4e9c..1fcf4c5ec79 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -1,4 +1,3 @@
-
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -33,13 +32,21 @@
* \ingroup modifiers
*/
+// #ifdef DEBUG_TIME
+// #define USE_BMESH
+#ifdef WITH_MOD_BOOLEAN
+# define USE_CARVE WITH_MOD_BOOLEAN
+#endif
+
#include <stdio.h>
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
+#include "BLI_math_matrix.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "depsgraph_private.h"
@@ -47,6 +54,23 @@
#include "MOD_boolean_util.h"
#include "MOD_util.h"
+
+#ifdef USE_BMESH
+#include "BLI_alloca.h"
+#include "BLI_math_geom.h"
+#include "BKE_material.h"
+#include "MEM_guardedalloc.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+#include "tools/bmesh_intersect.h"
+#endif
+
+#ifdef DEBUG_TIME
+#include "PIL_time.h"
+#include "PIL_time_utildefines.h"
+#endif
+
static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
@@ -65,12 +89,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
- walk(userData, ob, &bmd->object);
+ walk(userData, ob, &bmd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -104,35 +127,223 @@ static void updateDepsgraph(ModifierData *md,
DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
}
-#ifdef WITH_MOD_BOOLEAN
-static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
+#if defined(USE_CARVE) || defined(USE_BMESH)
+
+static DerivedMesh *get_quick_derivedMesh(
+ Object *ob_self, DerivedMesh *dm_self,
+ Object *ob_other, DerivedMesh *dm_other,
+ int operation)
{
DerivedMesh *result = NULL;
- if (derivedData->getNumPolys(derivedData) == 0 || dm->getNumPolys(dm) == 0) {
+ if (dm_self->getNumPolys(dm_self) == 0 || dm_other->getNumPolys(dm_other) == 0) {
switch (operation) {
case eBooleanModifierOp_Intersect:
result = CDDM_new(0, 0, 0, 0, 0);
break;
case eBooleanModifierOp_Union:
- if (derivedData->getNumPolys(derivedData)) result = derivedData;
- else result = CDDM_copy(dm);
+ if (dm_self->getNumPolys(dm_self) != 0) {
+ result = dm_self;
+ }
+ else {
+ result = CDDM_copy(dm_other);
+
+ float imat[4][4];
+ float omat[4][4];
+
+ invert_m4_m4(imat, ob_self->obmat);
+ mul_m4_m4m4(omat, imat, ob_other->obmat);
+
+ const int mverts_len = result->getNumVerts(result);
+ MVert *mv = CDDM_get_verts(result);
+
+ for (int i = 0; i < mverts_len; i++, mv++) {
+ mul_m4_v3(omat, mv->co);
+ }
+
+ result->dirty |= DM_DIRTY_NORMALS;
+ }
break;
case eBooleanModifierOp_Difference:
- result = derivedData;
+ result = dm_self;
break;
}
}
return result;
}
+#endif /* defined(USE_CARVE) || defined(USE_BMESH) */
+
+
+/* -------------------------------------------------------------------- */
+/* BMESH */
-static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
- DerivedMesh *derivedData,
- ModifierApplyFlag flag)
+#ifdef USE_BMESH
+
+/* has no meaning for faces, do this so we can tell which face is which */
+#define BM_FACE_TAG BM_ELEM_DRAW
+
+/**
+ * Compare selected/unselected.
+ */
+static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
+{
+ return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0;
+}
+
+static DerivedMesh *applyModifier_bmesh(
+ ModifierData *md, Object *ob,
+ DerivedMesh *dm,
+ ModifierApplyFlag flag)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *) md;
+ DerivedMesh *dm_other;
+
+ if (!bmd->object)
+ return dm;
+
+ dm_other = get_dm_for_modifier(bmd->object, flag);
+
+ if (dm_other) {
+ DerivedMesh *result;
+
+ /* when one of objects is empty (has got no faces) we could speed up
+ * calculation a bit returning one of objects' derived meshes (or empty one)
+ * Returning mesh is depended on modifiers operation (sergey) */
+ result = get_quick_derivedMesh(ob, dm, bmd->object, dm_other, bmd->operation);
+
+ if (result == NULL) {
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(boolean_bmesh);
+#endif
+ bm = BM_mesh_create(&allocsize);
+
+ DM_to_bmesh_ex(dm_other, bm, true);
+ DM_to_bmesh_ex(dm, bm, true);
+
+ /* main bmesh intersection setup */
+ {
+ /* create tessface & intersect */
+ const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+ int tottri;
+ BMLoop *(*looptris)[3];
+
+ looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
+
+ BM_mesh_calc_tessellation(bm, looptris, &tottri);
+
+ /* postpone this until after tessellating
+ * so we can use the original normals before the vertex are moved */
+ {
+ BMIter iter;
+ int i;
+ const int i_verts_end = dm_other->getNumVerts(dm_other);
+ const int i_faces_end = dm_other->getNumPolys(dm_other);
+
+ float imat[4][4];
+ float omat[4][4];
+
+ invert_m4_m4(imat, ob->obmat);
+ mul_m4_m4m4(omat, imat, bmd->object->obmat);
+
+
+ BMVert *eve;
+ i = 0;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ mul_m4_v3(omat, eve->co);
+ if (++i == i_verts_end) {
+ break;
+ }
+ }
+
+ /* we need face normals because of 'BM_face_split_edgenet'
+ * we could calculate on the fly too (before calling split). */
+ {
+ float nmat[4][4];
+ invert_m4_m4(nmat, omat);
+
+ const short ob_src_totcol = bmd->object->totcol;
+ short *material_remap = BLI_array_alloca(material_remap, ob_src_totcol ? ob_src_totcol : 1);
+
+ BKE_material_remap_object_calc(ob, bmd->object, material_remap);
+
+ BMFace *efa;
+ i = 0;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ mul_transposed_mat3_m4_v3(nmat, efa->no);
+ normalize_v3(efa->no);
+ BM_elem_flag_enable(efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */
+
+ /* remap material */
+ if (LIKELY(efa->mat_nr < ob_src_totcol)) {
+ efa->mat_nr = material_remap[efa->mat_nr];
+ }
+
+ if (++i == i_faces_end) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* not needed, but normals for 'dm' will be invalid,
+ * currently this is ok for 'BM_mesh_intersect' */
+ // BM_mesh_normals_update(bm);
+
+ BM_mesh_intersect(
+ bm,
+ looptris, tottri,
+ bm_face_isect_pair, NULL,
+ false,
+ (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0,
+ (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0,
+ (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0,
+ bmd->operation,
+ bmd->threshold);
+
+ MEM_freeN(looptris);
+ }
+
+ result = CDDM_from_bmesh(bm, true);
+
+ BM_mesh_free(bm);
+
+ result->dirty |= DM_DIRTY_NORMALS;
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(boolean_bmesh);
+#endif
+
+ return result;
+ }
+
+ /* if new mesh returned, return it; otherwise there was
+ * an error, so delete the modifier object */
+ if (result)
+ return result;
+ else
+ modifier_setError(md, "Cannot execute boolean operation");
+ }
+
+ return dm;
+}
+#endif /* USE_BMESH */
+
+
+/* -------------------------------------------------------------------- */
+/* CARVE */
+
+#ifdef USE_CARVE
+static DerivedMesh *applyModifier_carve(
+ ModifierData *md, Object *ob,
+ DerivedMesh *derivedData,
+ ModifierApplyFlag flag)
{
BooleanModifierData *bmd = (BooleanModifierData *) md;
DerivedMesh *dm;
@@ -148,15 +359,18 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* when one of objects is empty (has got no faces) we could speed up
* calculation a bit returning one of objects' derived meshes (or empty one)
* Returning mesh is depended on modifiers operation (sergey) */
- result = get_quick_derivedMesh(derivedData, dm, bmd->operation);
+ result = get_quick_derivedMesh(ob, derivedData, bmd->object, dm, bmd->operation);
if (result == NULL) {
- // TIMEIT_START(NewBooleanDerivedMesh)
+#ifdef DEBUG_TIME
+ TIMEIT_START(boolean_carve);
+#endif
result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob,
1 + bmd->operation);
-
- // TIMEIT_END(NewBooleanDerivedMesh)
+#ifdef DEBUG_TIME
+ TIMEIT_END(boolean_carve);
+#endif
}
/* if new mesh returned, return it; otherwise there was
@@ -169,14 +383,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
return derivedData;
}
-#else // WITH_MOD_BOOLEAN
-static DerivedMesh *applyModifier(ModifierData *UNUSED(md), Object *UNUSED(ob),
- DerivedMesh *derivedData,
- ModifierApplyFlag UNUSED(flag))
+#endif /* USE_CARVE */
+
+
+static DerivedMesh *applyModifier_nop(
+ ModifierData *UNUSED(md), Object *UNUSED(ob),
+ DerivedMesh *derivedData,
+ ModifierApplyFlag UNUSED(flag))
{
return derivedData;
}
-#endif // WITH_MOD_BOOLEAN
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md))
{
@@ -187,6 +403,28 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(
return dataMask;
}
+static DerivedMesh *applyModifier(
+ ModifierData *md, Object *ob,
+ DerivedMesh *derivedData,
+ ModifierApplyFlag flag)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ const int method = (bmd->bm_flag & eBooleanModifierBMeshFlag_Enabled) ? 1 : 0;
+
+ switch (method) {
+#ifdef USE_CARVE
+ case 0:
+ return applyModifier_carve(md, ob, derivedData, flag);
+#endif
+#ifdef USE_BMESH
+ case 1:
+ return applyModifier_bmesh(md, ob, derivedData, flag);
+#endif
+ default:
+ return applyModifier_nop(md, ob, derivedData, flag);
+ }
+}
+
ModifierTypeInfo modifierType_Boolean = {
/* name */ "Boolean",
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 507fad466a3..a364eef2974 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -106,15 +106,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
edgeMap = MEM_mallocN(sizeof(*edgeMap) * numEdge_src, "build modifier edgeMap");
faceMap = MEM_mallocN(sizeof(*faceMap) * numPoly_src, "build modifier faceMap");
-#pragma omp parallel sections if (numVert_src + numEdge_src + numPoly_src >= BKE_MESH_OMP_LIMIT)
- {
-#pragma omp section
- { range_vn_i(vertMap, numVert_src, 0); }
-#pragma omp section
- { range_vn_i(edgeMap, numEdge_src, 0); }
-#pragma omp section
- { range_vn_i(faceMap, numPoly_src, 0); }
- }
+ range_vn_i(vertMap, numVert_src, 0);
+ range_vn_i(edgeMap, numEdge_src, 0);
+ range_vn_i(faceMap, numPoly_src, 0);
frac = (BKE_scene_frame_get(md->scene) - bmd->start) / bmd->length;
CLAMP(frac, 0.0f, 1.0f);
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 7c3d65a5c9a..32c3d41c4b6 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -42,6 +42,7 @@
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
@@ -97,12 +98,11 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
CastModifierData *cmd = (CastModifierData *) md;
- walk(userData, ob, &cmd->object);
+ walk(userData, ob, &cmd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index dac0e516e0d..6cc2f097be8 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -49,6 +49,7 @@
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_key.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
@@ -241,11 +242,11 @@ static void foreachIDLink(ModifierData *md, Object *ob,
ClothModifierData *clmd = (ClothModifierData *) md;
if (clmd->coll_parms) {
- walk(userData, ob, (ID **)&clmd->coll_parms->group);
+ walk(userData, ob, (ID **)&clmd->coll_parms->group, IDWALK_NOP);
}
if (clmd->sim_parms && clmd->sim_parms->effector_weights) {
- walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group);
+ walk(userData, ob, (ID **)&clmd->sim_parms->effector_weights->group, IDWALK_NOP);
}
}
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index d5b4daca3b7..4046620592b 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -575,7 +575,7 @@ static void correctivesmooth_modifier_do(
const bool force_delta_cache_update =
/* XXX, take care! if mesh data its self changes we need to forcefully recalculate deltas */
((csmd->rest_source == MOD_CORRECTIVESMOOTH_RESTSOURCE_ORCO) &&
- (((ID *)ob->data)->flag & LIB_ID_RECALC));
+ (((ID *)ob->data)->tag & LIB_TAG_ID_RECALC));
bool use_only_smooth = (csmd->flag & MOD_CORRECTIVESMOOTH_ONLY_SMOOTH) != 0;
MDeformVert *dvert = NULL;
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index 1488296caf9..6e2d746c858 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -42,6 +42,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_lattice.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "depsgraph_private.h"
@@ -84,12 +85,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
CurveModifierData *cmd = (CurveModifierData *) md;
- walk(userData, ob, &cmd->object);
+ walk(userData, ob, &cmd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -112,7 +112,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
static void updateDepsgraph(ModifierData *md,
struct Main *UNUSED(bmain),
struct Scene *scene,
- Object *UNUSED(ob),
+ Object *object,
struct DepsNodeHandle *node)
{
CurveModifierData *cmd = (CurveModifierData *)md;
@@ -126,6 +126,8 @@ static void updateDepsgraph(ModifierData *md,
DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
}
+
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Curve Modifier");
}
static void deformVerts(ModifierData *md, Object *ob,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index 85e9b4ee185..f5ab28d3d88 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -41,6 +41,7 @@
#include "BKE_data_transfer.h"
#include "BKE_DerivedMesh.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_modifier.h"
@@ -118,17 +119,12 @@ static bool dependsOnNormals(ModifierData *md)
return false;
}
-static void foreachObjectLink(ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+static void foreachObjectLink(
+ ModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
- walk(userData, ob, &dtmd->ob_source);
-}
-
-static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
-{
- foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+ walk(userData, ob, &dtmd->ob_source, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -260,6 +256,6 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ foreachIDLink,
+ /* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 14468ab7c12..617ae5a89f3 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -94,7 +94,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm = derivedData, *result = NULL;
BMesh *bm;
bool calc_face_normal;
-
float *vweights = NULL;
#ifdef USE_TIMEIT
@@ -165,7 +164,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
case MOD_DECIM_MODE_COLLAPSE:
{
const bool do_triangulate = (dmd->flag & MOD_DECIM_FLAG_TRIANGULATE) != 0;
- BM_mesh_decimate_collapse(bm, dmd->percent, vweights, dmd->defgrp_factor, do_triangulate);
+ const int symmetry_axis = (dmd->flag & MOD_DECIM_FLAG_SYMMETRY) ? dmd->symmetry_axis : -1;
+ const float symmetry_eps = 0.00002f;
+ BM_mesh_decimate_collapse(
+ bm, dmd->percent, vweights, dmd->defgrp_factor, do_triangulate,
+ symmetry_axis, symmetry_eps);
break;
}
case MOD_DECIM_MODE_UNSUBDIV:
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index b20d7d8a3a9..9ba2d214d50 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -41,6 +41,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_texture.h"
@@ -129,7 +130,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, &dmd->map_object);
+ walk(userData, ob, &dmd->map_object, IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -137,7 +138,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
DisplaceModifierData *dmd = (DisplaceModifierData *) md;
- walk(userData, ob, (ID **)&dmd->texture);
+ walk(userData, ob, (ID **)&dmd->texture, IDWALK_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index f1b6ceb070c..edf959f42c6 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -29,12 +29,14 @@
#include "DNA_dynamicpaint_types.h"
#include "DNA_object_types.h"
+#include "DNA_object_force.h"
#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_dynamicpaint.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "depsgraph_private.h"
@@ -170,12 +172,15 @@ static void foreachIDLink(ModifierData *md, Object *ob,
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- walk(userData, ob, (ID **)&surface->brush_group);
- walk(userData, ob, (ID **)&surface->init_texture);
+ walk(userData, ob, (ID **)&surface->brush_group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&surface->init_texture, IDWALK_USER);
+ if (surface->effector_weights) {
+ walk(userData, ob, (ID **)&surface->effector_weights->group, IDWALK_NOP);
+ }
}
}
if (pmd->brush) {
- walk(userData, ob, (ID **)&pmd->brush->mat);
+ walk(userData, ob, (ID **)&pmd->brush->mat, IDWALK_USER);
}
}
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 82600421736..38ffdaa709b 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -634,7 +634,9 @@ static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
for (i = 0, fs = facesplit; i < totface; i++, fs++)
totfsplit += add_faces[*fs];
- splitdm = CDDM_from_template(dm, totesplit, 0, totface + totfsplit, 0, 0);
+ splitdm = CDDM_from_template_ex(
+ dm, totesplit, 0, totface + totfsplit, 0, 0,
+ CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS);
numlayer = CustomData_number_of_layers(&splitdm->faceData, CD_MTFACE);
/* copy new faces & verts (is it really this painful with custom data??) */
@@ -861,7 +863,7 @@ static DerivedMesh *explodeMesh(ExplodeModifierData *emd,
BLI_edgehashIterator_free(ehi);
/* the final duplicated vertices */
- explode = CDDM_from_template(dm, totdup, 0, totface - delface, 0, 0);
+ explode = CDDM_from_template_ex(dm, totdup, 0, totface - delface, 0, 0, CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS);
mtface = CustomData_get_layer_named(&explode->faceData, CD_MTFACE, emd->uvname);
/*dupvert = CDDM_get_verts(explode);*/
@@ -1006,7 +1008,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (psys == NULL || psys->totpart == 0) return derivedData;
if (psys->part == NULL || psys->particles == NULL) return derivedData;
- if (psmd->dm == NULL) return derivedData;
+ if (psmd->dm_final == NULL) return derivedData;
/* 1. find faces to be exploded if needed */
if (emd->facepa == NULL ||
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 3a10fabbb8e..e175f4943a7 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -41,6 +41,7 @@
#include "BKE_action.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_colortools.h"
@@ -66,6 +67,13 @@ static void copyData(ModifierData *md, ModifierData *target)
HookModifierData *hmd = (HookModifierData *) md;
HookModifierData *thmd = (HookModifierData *) target;
+ if (thmd->curfalloff != NULL) {
+ curvemapping_free(thmd->curfalloff);
+ }
+ if (thmd->indexar != NULL) {
+ MEM_freeN(thmd->indexar);
+ }
+
modifier_copyData_generic(md, target);
thmd->curfalloff = curvemapping_copy(hmd->curfalloff);
@@ -103,12 +111,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
HookModifierData *hmd = (HookModifierData *) md;
- walk(userData, ob, &hmd->object);
+ walk(userData, ob, &hmd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 8b0ca7f99fb..d4f02d923d3 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -42,6 +42,7 @@
#include "MOD_util.h"
+#include "eigen_capi.h"
enum {
LAPDEFORM_SYSTEM_NOT_CHANGE = 0,
@@ -54,10 +55,6 @@ enum {
LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP,
};
-#ifdef WITH_OPENNL
-
-#include "ONL_opennl.h"
-
typedef struct LaplacianSystem {
bool is_matrix_computed;
bool has_solution;
@@ -75,7 +72,7 @@ typedef struct LaplacianSystem {
int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */
int *ringf_indices; /* Indices of faces per vertex */
int *ringv_indices; /* Indices of neighbors(vertex) per vertex */
- NLContext *context; /* System for solve general implicit rotations */
+ LinearSolver *context; /* System for solve general implicit rotations */
MeshElemMap *ringf_map; /* Map of faces per vertex */
MeshElemMap *ringv_map; /* Map of vertex per vertex */
} LaplacianSystem;
@@ -134,7 +131,7 @@ static void deleteLaplacianSystem(LaplacianSystem *sys)
MEM_SAFE_FREE(sys->ringv_map);
if (sys->context) {
- nlDeleteContext(sys->context);
+ EIG_linear_solver_delete(sys->context);
}
MEM_SAFE_FREE(sys);
}
@@ -283,9 +280,9 @@ static void initLaplacianMatrix(LaplacianSystem *sys)
sys->delta[idv[0]][1] -= v3[1] * w3;
sys->delta[idv[0]][2] -= v3[2] * w3;
- nlMatrixAdd(idv[0], idv[1], -w2);
- nlMatrixAdd(idv[0], idv[2], -w3);
- nlMatrixAdd(idv[0], idv[0], w2 + w3);
+ EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2);
+ EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3);
+ EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3);
}
}
}
@@ -338,9 +335,9 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
beta = dot_v3v3(uij, di);
gamma = dot_v3v3(e2, di);
- pi[0] = nlGetVariable(0, i);
- pi[1] = nlGetVariable(1, i);
- pi[2] = nlGetVariable(2, i);
+ pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i);
+ pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i);
+ pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i);
zero_v3(ni);
num_fni = 0;
num_fni = sys->ringf_map[i].count;
@@ -349,9 +346,9 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
fidn = sys->ringf_map[i].indices;
vin = sys->tris[fidn[fi]];
for (j = 0; j < 3; j++) {
- vn[j][0] = nlGetVariable(0, vin[j]);
- vn[j][1] = nlGetVariable(1, vin[j]);
- vn[j][2] = nlGetVariable(2, vin[j]);
+ vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]);
+ vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]);
+ vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]);
if (vin[j] == sys->unit_verts[i]) {
copy_v3_v3(pj, vn[j]);
}
@@ -372,14 +369,14 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys)
fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2];
if (len_squared_v3(fni) > FLT_EPSILON) {
- nlRightHandSideSet(0, i, fni[0]);
- nlRightHandSideSet(1, i, fni[1]);
- nlRightHandSideSet(2, i, fni[2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, i, fni[0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, i, fni[1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, i, fni[2]);
}
else {
- nlRightHandSideSet(0, i, sys->delta[i][0]);
- nlRightHandSideSet(1, i, sys->delta[i][1]);
- nlRightHandSideSet(2, i, sys->delta[i][2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
}
}
}
@@ -390,77 +387,59 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
n = sys->total_verts;
na = sys->total_anchors;
-#ifdef OPENNL_THREADING_HACK
- modifier_opennl_lock();
-#endif
-
if (!sys->is_matrix_computed) {
- nlNewContext();
- sys->context = nlGetCurrent();
-
- nlSolverParameteri(NL_NB_VARIABLES, n);
- nlSolverParameteri(NL_SYMMETRIC, NL_FALSE);
- nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
- nlSolverParameteri(NL_NB_ROWS, n + na);
- nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);
- nlBegin(NL_SYSTEM);
+ sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3);
+
for (i = 0; i < n; i++) {
- nlSetVariable(0, i, sys->co[i][0]);
- nlSetVariable(1, i, sys->co[i][1]);
- nlSetVariable(2, i, sys->co[i][2]);
+ EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]);
+ EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]);
+ EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]);
}
for (i = 0; i < na; i++) {
vid = sys->index_anchors[i];
- nlSetVariable(0, vid, vertexCos[vid][0]);
- nlSetVariable(1, vid, vertexCos[vid][1]);
- nlSetVariable(2, vid, vertexCos[vid][2]);
+ EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]);
+ EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]);
+ EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]);
}
- nlBegin(NL_MATRIX);
initLaplacianMatrix(sys);
computeImplictRotations(sys);
for (i = 0; i < n; i++) {
- nlRightHandSideSet(0, i, sys->delta[i][0]);
- nlRightHandSideSet(1, i, sys->delta[i][1]);
- nlRightHandSideSet(2, i, sys->delta[i][2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
}
for (i = 0; i < na; i++) {
vid = sys->index_anchors[i];
- nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
- nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
- nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
- nlMatrixAdd(n + i, vid, 1.0f);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
+ EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
}
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
- if (nlSolveAdvanced(NULL, NL_TRUE)) {
+ if (EIG_linear_solver_solve(sys->context)) {
sys->has_solution = true;
for (j = 1; j <= sys->repeat; j++) {
- nlBegin(NL_SYSTEM);
- nlBegin(NL_MATRIX);
rotateDifferentialCoordinates(sys);
for (i = 0; i < na; i++) {
vid = sys->index_anchors[i];
- nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
- nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
- nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
}
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
- if (!nlSolveAdvanced(NULL, NL_FALSE)) {
+ if (!EIG_linear_solver_solve(sys->context)) {
sys->has_solution = false;
break;
}
}
if (sys->has_solution) {
for (vid = 0; vid < sys->total_verts; vid++) {
- vertexCos[vid][0] = nlGetVariable(0, vid);
- vertexCos[vid][1] = nlGetVariable(1, vid);
- vertexCos[vid][2] = nlGetVariable(2, vid);
+ vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
+ vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
+ vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
}
}
else {
@@ -475,51 +454,40 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
}
else if (sys->has_solution) {
- nlMakeCurrent(sys->context);
-
- nlBegin(NL_SYSTEM);
- nlBegin(NL_MATRIX);
-
for (i = 0; i < n; i++) {
- nlRightHandSideSet(0, i, sys->delta[i][0]);
- nlRightHandSideSet(1, i, sys->delta[i][1]);
- nlRightHandSideSet(2, i, sys->delta[i][2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
}
for (i = 0; i < na; i++) {
vid = sys->index_anchors[i];
- nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
- nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
- nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
- nlMatrixAdd(n + i, vid, 1.0f);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
+ EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
}
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
- if (nlSolveAdvanced(NULL, NL_FALSE)) {
+ if (EIG_linear_solver_solve(sys->context)) {
sys->has_solution = true;
for (j = 1; j <= sys->repeat; j++) {
- nlBegin(NL_SYSTEM);
- nlBegin(NL_MATRIX);
rotateDifferentialCoordinates(sys);
for (i = 0; i < na; i++) {
vid = sys->index_anchors[i];
- nlRightHandSideSet(0, n + i, vertexCos[vid][0]);
- nlRightHandSideSet(1, n + i, vertexCos[vid][1]);
- nlRightHandSideSet(2, n + i, vertexCos[vid][2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
}
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
- if (!nlSolveAdvanced(NULL, NL_FALSE)) {
+ if (!EIG_linear_solver_solve(sys->context)) {
sys->has_solution = false;
break;
}
}
if (sys->has_solution) {
for (vid = 0; vid < sys->total_verts; vid++) {
- vertexCos[vid][0] = nlGetVariable(0, vid);
- vertexCos[vid][1] = nlGetVariable(1, vid);
- vertexCos[vid][2] = nlGetVariable(2, vid);
+ vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
+ vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
+ vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
}
}
else {
@@ -530,10 +498,6 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
sys->has_solution = false;
}
}
-
-#ifdef OPENNL_THREADING_HACK
- modifier_opennl_unlock();
-#endif
}
static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm)
@@ -724,15 +688,6 @@ static void LaplacianDeformModifier_do(
}
}
-#else /* WITH_OPENNL */
-static void LaplacianDeformModifier_do(
- LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts)
-{
- UNUSED_VARS(lmd, ob, dm, vertexCos, numVerts);
-}
-#endif /* WITH_OPENNL */
-
static void initData(ModifierData *md)
{
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
@@ -796,12 +751,10 @@ static void deformVertsEM(
static void freeData(ModifierData *md)
{
LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md;
-#ifdef WITH_OPENNL
LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system;
if (sys) {
deleteLaplacianSystem(sys);
}
-#endif
MEM_SAFE_FREE(lmd->vertexco);
lmd->total_verts = 0;
}
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index f04e092b39e..f1216ff462a 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -43,9 +43,7 @@
#include "MOD_util.h"
-#ifdef WITH_OPENNL
-
-#include "ONL_opennl.h"
+#include "eigen_capi.h"
#if 0
#define MOD_LAPLACIANSMOOTH_MAX_EDGE_PERCENTAGE 1.8f
@@ -71,7 +69,7 @@ struct BLaplacianSystem {
const MPoly *mpoly;
const MLoop *mloop;
const MEdge *medges;
- NLContext *context;
+ LinearSolver *context;
/*Data*/
float min_area;
@@ -104,7 +102,7 @@ static void delete_laplacian_system(LaplacianSystem *sys)
MEM_SAFE_FREE(sys->zerola);
if (sys->context) {
- nlDeleteContext(sys->context);
+ EIG_linear_solver_delete(sys->context);
}
sys->vertexCos = NULL;
sys->mpoly = NULL;
@@ -300,16 +298,16 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
/* Is ring if number of faces == number of edges around vertice*/
if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) {
- nlMatrixAdd(l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]);
- nlMatrixAdd(l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]);
+ EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]);
+ EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]);
}
if (sys->numNeEd[l_next->v] == sys->numNeFa[l_next->v] && sys->zerola[l_next->v] == 0) {
- nlMatrixAdd(l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]);
- nlMatrixAdd(l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]);
+ EIG_linear_solver_matrix_add(sys->context, l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]);
+ EIG_linear_solver_matrix_add(sys->context, l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]);
}
if (sys->numNeEd[l_prev->v] == sys->numNeFa[l_prev->v] && sys->zerola[l_prev->v] == 0) {
- nlMatrixAdd(l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]);
- nlMatrixAdd(l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]);
+ EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]);
+ EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]);
}
}
}
@@ -323,8 +321,8 @@ static void fill_laplacian_matrix(LaplacianSystem *sys)
sys->zerola[idv1] == 0 &&
sys->zerola[idv2] == 0)
{
- nlMatrixAdd(idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
- nlMatrixAdd(idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
+ EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
+ EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
}
}
}
@@ -342,13 +340,13 @@ static void validate_solution(LaplacianSystem *sys, short flag, float lambda, fl
if (sys->zerola[i] == 0) {
lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : (lambda_border >= 0.0f ? 1.0f : -1.0f);
if (flag & MOD_LAPLACIANSMOOTH_X) {
- sys->vertexCos[i][0] += lam * ((float)nlGetVariable(0, i) - sys->vertexCos[i][0]);
+ sys->vertexCos[i][0] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 0, i) - sys->vertexCos[i][0]);
}
if (flag & MOD_LAPLACIANSMOOTH_Y) {
- sys->vertexCos[i][1] += lam * ((float)nlGetVariable(1, i) - sys->vertexCos[i][1]);
+ sys->vertexCos[i][1] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 1, i) - sys->vertexCos[i][1]);
}
if (flag & MOD_LAPLACIANSMOOTH_Z) {
- sys->vertexCos[i][2] += lam * ((float)nlGetVariable(2, i) - sys->vertexCos[i][2]);
+ sys->vertexCos[i][2] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 2, i) - sys->vertexCos[i][2]);
}
}
}
@@ -386,25 +384,15 @@ static void laplaciansmoothModifier_do(
sys->vert_centroid[2] = 0.0f;
memset_laplacian_system(sys, 0);
-#ifdef OPENNL_THREADING_HACK
- modifier_opennl_lock();
-#endif
-
- nlNewContext();
- sys->context = nlGetCurrent();
- nlSolverParameteri(NL_NB_VARIABLES, numVerts);
- nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
- nlSolverParameteri(NL_NB_ROWS, numVerts);
- nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 3);
+ sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3);
init_laplacian_matrix(sys);
for (iter = 0; iter < smd->repeat; iter++) {
- nlBegin(NL_SYSTEM);
for (i = 0; i < numVerts; i++) {
- nlSetVariable(0, i, vertexCos[i][0]);
- nlSetVariable(1, i, vertexCos[i][1]);
- nlSetVariable(2, i, vertexCos[i][2]);
+ EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]);
+ EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]);
+ EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]);
if (iter == 0) {
add_v3_v3(sys->vert_centroid, vertexCos[i]);
}
@@ -413,12 +401,11 @@ static void laplaciansmoothModifier_do(
mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts);
}
- nlBegin(NL_MATRIX);
dv = dvert;
for (i = 0; i < numVerts; i++) {
- nlRightHandSideSet(0, i, vertexCos[i][0]);
- nlRightHandSideSet(1, i, vertexCos[i][1]);
- nlRightHandSideSet(2, i, vertexCos[i][2]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]);
+ EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]);
if (iter == 0) {
if (dv) {
wpaint = defvert_find_weight(dv, defgrp_index);
@@ -435,10 +422,10 @@ static void laplaciansmoothModifier_do(
w = sys->vlengths[i];
sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
if (sys->numNeEd[i] == sys->numNeFa[i]) {
- nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda) * wpaint);
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint);
}
else {
- nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
}
}
else {
@@ -448,15 +435,15 @@ static void laplaciansmoothModifier_do(
sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
if (sys->numNeEd[i] == sys->numNeFa[i]) {
- nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i]));
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i]));
}
else {
- nlMatrixAdd(i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
}
}
}
else {
- nlMatrixAdd(i, i, 1.0f);
+ EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f);
}
}
}
@@ -465,32 +452,16 @@ static void laplaciansmoothModifier_do(
fill_laplacian_matrix(sys);
}
- nlEnd(NL_MATRIX);
- nlEnd(NL_SYSTEM);
-
- if (nlSolveAdvanced(NULL, NL_TRUE)) {
+ if (EIG_linear_solver_solve(sys->context)) {
validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
}
}
- nlDeleteContext(sys->context);
+ EIG_linear_solver_delete(sys->context);
sys->context = NULL;
-#ifdef OPENNL_THREADING_HACK
- modifier_opennl_unlock();
-#endif
-
delete_laplacian_system(sys);
}
-#else /* WITH_OPENNL */
-static void laplaciansmoothModifier_do(
- LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts)
-{
- UNUSED_VARS(smd, ob, dm, vertexCos, numVerts);
-}
-#endif /* WITH_OPENNL */
-
static void init_data(ModifierData *md)
{
LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md;
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 52a4f441b63..0f49ce6cfbf 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -41,6 +41,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_lattice.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "depsgraph_private.h"
@@ -83,12 +84,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(userRenderParams))
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
LatticeModifierData *lmd = (LatticeModifierData *) md;
- walk(userData, ob, &lmd->object);
+ walk(userData, ob, &lmd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 06fbab65d7b..5e01a20d93b 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -46,6 +46,7 @@
#include "BKE_action.h" /* BKE_pose_channel_find_name */
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
@@ -70,11 +71,10 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
MaskModifierData *mmd = (MaskModifierData *)md;
- walk(userData, ob, &mmd->ob_arm);
+ walk(userData, ob, &mmd->ob_arm, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 5bd33d2a49f..e3c94a1a4df 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -42,6 +42,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
@@ -114,12 +115,11 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
- walk(userData, ob, &mmd->object);
+ walk(userData, ob, &mmd->object, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
@@ -234,7 +234,7 @@ typedef struct MeshdeformUserdata {
float (*icagemat)[3];
} MeshdeformUserdata;
-static void meshdeform_vert_task(void * userdata, int iter)
+static void meshdeform_vert_task(void *userdata, const int iter)
{
MeshdeformUserdata *data = userdata;
/*const*/ MeshDeformModifierData *mmd = data->mmd;
@@ -352,7 +352,7 @@ static void meshdeformModifier_do(
/* progress bar redraw can make this recursive .. */
if (!recursive) {
recursive = 1;
- mmd->bindfunc(md->scene, mmd, (float *)vertexCos, numVerts, cagemat);
+ mmd->bindfunc(md->scene, mmd, cagedm, (float *)vertexCos, numVerts, cagemat);
recursive = 0;
}
}
@@ -413,7 +413,7 @@ static void meshdeformModifier_do(
data.icagemat = icagemat;
/* Do deformation. */
- BLI_task_parallel_range(0, totvert, &data, meshdeform_vert_task);
+ BLI_task_parallel_range(0, totvert, &data, meshdeform_vert_task, totvert > 1000);
/* release cage derivedmesh */
MEM_freeN(dco);
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 3e10fa1d77d..88facb22e0e 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -39,6 +39,7 @@
#include "BLI_math.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
@@ -65,13 +66,13 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
}
-static void foreachObjectLink(ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+static void foreachObjectLink(
+ ModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
{
MirrorModifierData *mmd = (MirrorModifierData *) md;
- walk(userData, ob, &mmd->mirror_ob);
+ walk(userData, ob, &mmd->mirror_ob, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 87d75c6f1a7..355dd6d6677 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -38,6 +38,7 @@
#include "BLI_bitmap.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_mesh.h"
#include "BKE_deform.h"
@@ -84,7 +85,7 @@ static void generate_vert_coordinates(
/* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
/* Get ob_center (world) coordinates in ob local coordinates.
- * No need to take into accound ob_center's space here, see T44027. */
+ * No need to take into account ob_center's space here, see T44027. */
invert_m4_m4(inv_obmat, ob->obmat);
mul_v3_m4v3(diff, inv_obmat, ob_center->obmat[3]);
negate_v3(diff);
@@ -148,6 +149,40 @@ static void mix_normals(
MEM_SAFE_FREE(facs);
}
+/* Check poly normals and new loop normals are compatible, otherwise flip polygons
+ * (and invert matching poly normals). */
+static bool polygons_check_flip(
+ MLoop *mloop, float (*nos)[3], CustomData *ldata,
+ MPoly *mpoly, float (*polynors)[3], const int num_polys)
+{
+ MPoly *mp;
+ int i;
+ bool flipped = false;
+
+ for (i = 0, mp = mpoly; i < num_polys; i++, mp++) {
+ float norsum[3] = {0.0f};
+ float (*no)[3];
+ int j;
+
+ for (j = 0, no = &nos[mp->loopstart]; j < mp->totloop; j++, no++) {
+ add_v3_v3(norsum, *no);
+ }
+
+ if (!normalize_v3(norsum)) {
+ continue;
+ }
+
+ /* If average of new loop normals is opposed to polygon normal, flip polygon. */
+ if (dot_v3v3(polynors[i], norsum) < 0.0f) {
+ BKE_mesh_polygon_flip(mp, mloop, ldata);
+ negate_v3(polynors[i]);
+ flipped = true;
+ }
+ }
+
+ return flipped;
+}
+
static void normalEditModifier_do_radial(
NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
@@ -233,6 +268,10 @@ static void normalEditModifier_do_radial(
mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
+ if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ }
+
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
mpoly, (const float(*)[3])polynors, num_polys, clnors);
@@ -306,6 +345,10 @@ static void normalEditModifier_do_directional(
mix_mode, num_verts, mloop, loopnors, nos, num_loops);
}
+ if (polygons_check_flip(mloop, nos, dm->getLoopDataLayout(dm), mpoly, polynors, num_polys)) {
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ }
+
BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
mpoly, (const float(*)[3])polynors, num_polys, clnors);
@@ -387,7 +430,7 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
polynors = dm->getPolyDataArray(dm, CD_NORMAL);
if (!polynors) {
polynors = MEM_mallocN(sizeof(*polynors) * num_polys, __func__);
- BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false);
+ BKE_mesh_calc_normals_poly(mvert, NULL, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false);
free_polynors = true;
}
@@ -450,14 +493,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
NormalEditModifierData *smd = (NormalEditModifierData *) md;
- walk(userData, ob, &smd->target);
-}
-
-static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
-{
- NormalEditModifierData *smd = (NormalEditModifierData *) md;
-
- walk(userData, ob, (ID **)&smd->target);
+ walk(userData, ob, &smd->target, IDWALK_NOP);
}
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
@@ -504,7 +540,6 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* structSize */ sizeof(NormalEditModifierData),
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
- eModifierTypeFlag_AcceptsCVs |
eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode,
@@ -524,6 +559,6 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
- /* foreachIDLink */ foreachIDLink,
+ /* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
};
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 913c2f25c15..a90a51e9ddc 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -37,6 +37,7 @@
#include "BLI_math.h"
#include "BLI_math_inline.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
@@ -265,125 +266,144 @@ static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, floa
#ifdef WITH_OCEANSIM
-#ifdef _OPENMP
-#define OMP_MIN_RES 18
-#endif
-
-static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
-{
- DerivedMesh *result;
-
+typedef struct GenerateOceanGeometryData {
MVert *mverts;
MPoly *mpolys;
MLoop *mloops;
int *origindex;
+ MLoopUV *mloopuvs;
- int cdlayer;
+ int res_x, res_y;
+ int rx, ry;
+ float ox, oy;
+ float sx, sy;
+ float ix, iy;
+} GenerateOceanGeometryData;
- const int rx = omd->resolution * omd->resolution;
- const int ry = omd->resolution * omd->resolution;
- const int res_x = rx * omd->repeat_x;
- const int res_y = ry * omd->repeat_y;
+static void generate_ocean_geometry_vertices(void *userdata, const int y)
+{
+ GenerateOceanGeometryData *gogd = userdata;
+ int x;
+
+ for (x = 0; x <= gogd->res_x; x++) {
+ const int i = y * (gogd->res_x + 1) + x;
+ float *co = gogd->mverts[i].co;
+ co[0] = gogd->ox + (x * gogd->sx);
+ co[1] = gogd->oy + (y * gogd->sy);
+ co[2] = 0.0f;
+ }
+}
- const int num_verts = (res_x + 1) * (res_y + 1);
- /* const int num_edges = (res_x * res_y * 2) + res_x + res_y; */ /* UNUSED BMESH */
- const int num_faces = res_x * res_y;
+static void generate_ocean_geometry_polygons(void *userdata, const int y)
+{
+ GenerateOceanGeometryData *gogd = userdata;
+ int x;
+
+ for (x = 0; x < gogd->res_x; x++) {
+ const int fi = y * gogd->res_x + x;
+ const int vi = y * (gogd->res_x + 1) + x;
+ MPoly *mp = &gogd->mpolys[fi];
+ MLoop *ml = &gogd->mloops[fi * 4];
+
+ ml->v = vi;
+ ml++;
+ ml->v = vi + 1;
+ ml++;
+ ml->v = vi + 1 + gogd->res_x + 1;
+ ml++;
+ ml->v = vi + gogd->res_x + 1;
+ ml++;
+
+ mp->loopstart = fi * 4;
+ mp->totloop = 4;
+
+ mp->flag |= ME_SMOOTH;
+
+ /* generated geometry does not map to original faces */
+ gogd->origindex[fi] = ORIGINDEX_NONE;
+ }
+}
- float sx = omd->size * omd->spatial_size;
- float sy = omd->size * omd->spatial_size;
- const float ox = -sx / 2.0f;
- const float oy = -sy / 2.0f;
+static void generate_ocean_geometry_uvs(void *userdata, const int y)
+{
+ GenerateOceanGeometryData *gogd = userdata;
+ int x;
- float ix, iy;
+ for (x = 0; x < gogd->res_x; x++) {
+ const int i = y * gogd->res_x + x;
+ MLoopUV *luv = &gogd->mloopuvs[i * 4];
+
+ luv->uv[0] = x * gogd->ix;
+ luv->uv[1] = y * gogd->iy;
+ luv++;
+
+ luv->uv[0] = (x + 1) * gogd->ix;
+ luv->uv[1] = y * gogd->iy;
+ luv++;
+
+ luv->uv[0] = (x + 1) * gogd->ix;
+ luv->uv[1] = (y + 1) * gogd->iy;
+ luv++;
+
+ luv->uv[0] = x * gogd->ix;
+ luv->uv[1] = (y + 1) * gogd->iy;
+ luv++;
+ }
+}
+
+static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
+{
+ DerivedMesh *result;
+
+ GenerateOceanGeometryData gogd;
+
+ int num_verts;
+ int num_polys;
+
+ const bool use_threading = omd->resolution > 4;
- int x, y;
+ gogd.rx = omd->resolution * omd->resolution;
+ gogd.ry = omd->resolution * omd->resolution;
+ gogd.res_x = gogd.rx * omd->repeat_x;
+ gogd.res_y = gogd.ry * omd->repeat_y;
- sx /= rx;
- sy /= ry;
+ num_verts = (gogd.res_x + 1) * (gogd.res_y + 1);
+ num_polys = gogd.res_x * gogd.res_y;
- result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);
+ gogd.sx = omd->size * omd->spatial_size;
+ gogd.sy = omd->size * omd->spatial_size;
+ gogd.ox = -gogd.sx / 2.0f;
+ gogd.oy = -gogd.sy / 2.0f;
- mverts = CDDM_get_verts(result);
- mpolys = CDDM_get_polys(result);
- mloops = CDDM_get_loops(result);
+ gogd.sx /= gogd.rx;
+ gogd.sy /= gogd.ry;
- origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
+ result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys);
+
+ gogd.mverts = CDDM_get_verts(result);
+ gogd.mpolys = CDDM_get_polys(result);
+ gogd.mloops = CDDM_get_loops(result);
+
+ gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
/* create vertices */
-#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
- for (y = 0; y <= res_y; y++) {
- for (x = 0; x <= res_x; x++) {
- const int i = y * (res_x + 1) + x;
- float *co = mverts[i].co;
- co[0] = ox + (x * sx);
- co[1] = oy + (y * sy);
- co[2] = 0;
- }
- }
+ BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices, use_threading);
/* create faces */
-#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
- for (y = 0; y < res_y; y++) {
- for (x = 0; x < res_x; x++) {
- const int fi = y * res_x + x;
- const int vi = y * (res_x + 1) + x;
- MPoly *mp = &mpolys[fi];
- MLoop *ml = &mloops[fi * 4];
-
- ml->v = vi;
- ml++;
- ml->v = vi + 1;
- ml++;
- ml->v = vi + 1 + res_x + 1;
- ml++;
- ml->v = vi + res_x + 1;
- ml++;
-
- mp->loopstart = fi * 4;
- mp->totloop = 4;
-
- mp->flag |= ME_SMOOTH;
-
- /* generated geometry does not map to original faces */
- origindex[fi] = ORIGINDEX_NONE;
- }
- }
+ BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons, use_threading);
CDDM_calc_edges(result);
/* add uvs */
- cdlayer = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);
- if (cdlayer < MAX_MTFACE) {
- MLoopUV *mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_faces * 4);
- CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_faces);
-
- if (mloopuvs) { /* unlikely to fail */
- ix = 1.0 / rx;
- iy = 1.0 / ry;
-#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
- for (y = 0; y < res_y; y++) {
- for (x = 0; x < res_x; x++) {
- const int i = y * res_x + x;
- MLoopUV *luv = &mloopuvs[i * 4];
-
- luv->uv[0] = x * ix;
- luv->uv[1] = y * iy;
- luv++;
-
- luv->uv[0] = (x + 1) * ix;
- luv->uv[1] = y * iy;
- luv++;
-
- luv->uv[0] = (x + 1) * ix;
- luv->uv[1] = (y + 1) * iy;
- luv++;
-
- luv->uv[0] = x * ix;
- luv->uv[1] = (y + 1) * iy;
- luv++;
+ if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) {
+ gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4);
+ CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys);
- }
- }
+ if (gogd.mloopuvs) { /* unlikely to fail */
+ gogd.ix = 1.0 / gogd.rx;
+ gogd.iy = 1.0 / gogd.ry;
+
+ BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs, use_threading);
}
}
@@ -401,15 +421,10 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
DerivedMesh *dm = NULL;
OceanResult ocr;
- MVert *mverts, *mv;
- MLoop *mloops;
-
- int i, j;
-
- int num_verts;
- int num_faces;
+ MVert *mverts;
int cfra;
+ int i, j;
/* use cached & inverted value for speed
* expanded this would read...
@@ -425,18 +440,22 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
}
/* update modifier */
- if (omd->refresh & MOD_OCEAN_REFRESH_ADD)
+ if (omd->refresh & MOD_OCEAN_REFRESH_ADD) {
omd->ocean = BKE_ocean_add();
- if (omd->refresh & MOD_OCEAN_REFRESH_RESET)
+ }
+ if (omd->refresh & MOD_OCEAN_REFRESH_RESET) {
init_ocean_modifier(omd);
- if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE)
+ }
+ if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) {
clear_cache_data(omd);
-
+ }
omd->refresh = 0;
/* do ocean simulation */
if (omd->cached == true) {
- if (!omd->oceancache) init_cache_data(ob, omd);
+ if (!omd->oceancache) {
+ init_cache_data(ob, omd);
+ }
BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra);
}
else {
@@ -455,38 +474,31 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
CLAMP(cfra, omd->bakestart, omd->bakeend);
cfra -= omd->bakestart; /* shift to 0 based */
- num_verts = dm->getNumVerts(dm);
- num_faces = dm->getNumPolys(dm);
-
mverts = dm->getVertArray(dm);
- mloops = dm->getLoopArray(dm);
/* add vcols before displacement - allows lookup based on position */
if (omd->flag & MOD_OCEAN_GENERATE_FOAM) {
- int cdlayer = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL);
-
- if (cdlayer < MAX_MCOL) {
- MLoopCol *mloopcols = CustomData_add_layer_named(&dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL,
- num_faces * 4, omd->foamlayername);
+ if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) {
+ const int num_polys = dm->getNumPolys(dm);
+ const int num_loops = dm->getNumLoops(dm);
+ MLoop *mloops = dm->getLoopArray(dm);
+ MLoopCol *mloopcols = CustomData_add_layer_named(
+ &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername);
if (mloopcols) { /* unlikely to fail */
- MLoopCol *mlcol;
MPoly *mpolys = dm->getPolyArray(dm);
MPoly *mp;
- float foam;
-
- for (i = 0, mp = mpolys; i < num_faces; i++, mp++) {
- j = mp->totloop - 1;
+ for (i = 0, mp = mpolys; i < num_polys; i++, mp++) {
+ MLoop *ml = &mloops[mp->loopstart];
+ MLoopCol *mlcol = &mloopcols[mp->loopstart];
- /* highly unlikely */
- if (j <= 0) continue;
-
- do {
- const float *co = mverts[mloops[mp->loopstart + j].v].co;
- const float u = OCEAN_CO(size_co_inv, co[0]);
- const float v = OCEAN_CO(size_co_inv, co[1]);
+ for (j = mp->totloop; j--; ml++, mlcol++) {
+ const float *vco = mverts[ml->v].co;
+ const float u = OCEAN_CO(size_co_inv, vco[0]);
+ const float v = OCEAN_CO(size_co_inv, vco[1]);
+ float foam;
if (omd->oceancache && omd->cached == true) {
BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
@@ -498,11 +510,10 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage);
}
- mlcol = &mloopcols[mp->loopstart + j];
mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255);
/* This needs to be set (render engine uses) */
mlcol->a = 255;
- } while (j--);
+ }
}
}
}
@@ -511,21 +522,28 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
/* displace the geometry */
- /* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */
- for (i = 0, mv = mverts; i < num_verts; i++, mv++) {
- const float u = OCEAN_CO(size_co_inv, mv->co[0]);
- const float v = OCEAN_CO(size_co_inv, mv->co[1]);
+ /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */
+ {
+ const int num_verts = dm->getNumVerts(dm);
- if (omd->oceancache && omd->cached == true)
- BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
- else
- BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
+ for (i = 0; i < num_verts; i++) {
+ float *vco = mverts[i].co;
+ const float u = OCEAN_CO(size_co_inv, vco[0]);
+ const float v = OCEAN_CO(size_co_inv, vco[1]);
- mv->co[2] += ocr.disp[1];
+ if (omd->oceancache && omd->cached == true) {
+ BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v);
+ }
+ else {
+ BKE_ocean_eval_uv(omd->ocean, &ocr, u, v);
+ }
+
+ vco[2] += ocr.disp[1];
- if (omd->chop_amount > 0.0f) {
- mv->co[0] += ocr.disp[0];
- mv->co[1] += ocr.disp[2];
+ if (omd->chop_amount > 0.0f) {
+ vco[0] += ocr.disp[0];
+ vco[1] += ocr.disp[2];
+ }
}
}
@@ -585,4 +603,5 @@ ModifierTypeInfo modifierType_Ocean = {
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
};
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index cb6234d50b7..4e78e758dc3 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -46,6 +46,7 @@
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_lattice.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -144,7 +145,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
{
ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
- walk(userData, ob, &pimd->ob);
+ walk(userData, ob, &pimd->ob, IDWALK_NOP);
}
static int particle_skip(ParticleInstanceModifierData *pimd, ParticleSystem *psys, int p)
@@ -350,7 +351,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
ChildParticle *cpa = psys->child + (p - psys->totpart);
pa = psys->particles + cpa->parent;
}
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm, sim.psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, sim.psys->part->from, pa, hairmat);
copy_m3_m4(mat, hairmat);
/* to quaternion */
mat3_to_quat(frame, mat);
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index de1b11eddd9..4791e41d433 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -36,6 +36,7 @@
#include <stddef.h>
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "BLI_utildefines.h"
@@ -51,17 +52,23 @@ static void initData(ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
psmd->psys = NULL;
- psmd->dm = NULL;
+ psmd->dm_final = NULL;
+ psmd->dm_deformed = NULL;
psmd->totdmvert = psmd->totdmedge = psmd->totdmface = 0;
}
static void freeData(ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->dm) {
- psmd->dm->needsFree = 1;
- psmd->dm->release(psmd->dm);
- psmd->dm = NULL;
+ if (psmd->dm_final) {
+ psmd->dm_final->needsFree = true;
+ psmd->dm_final->release(psmd->dm_final);
+ psmd->dm_final = NULL;
+ if (psmd->dm_deformed) {
+ psmd->dm_deformed->needsFree = true;
+ psmd->dm_deformed->release(psmd->dm_deformed);
+ psmd->dm_deformed = NULL;
+ }
}
/* ED_object_modifier_remove may have freed this first before calling
@@ -78,7 +85,8 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
- tpsmd->dm = NULL;
+ tpsmd->dm_final = NULL;
+ tpsmd->dm_deformed = NULL;
tpsmd->totdmvert = tpsmd->totdmedge = tpsmd->totdmface = 0;
}
@@ -98,7 +106,7 @@ static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *dm = derivedData;
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
ParticleSystem *psys = NULL;
- int needsFree = 0;
+ bool needsFree = false;
/* float cfra = BKE_scene_frame_get(md->scene); */ /* UNUSED */
if (ob->particlesystem.first)
@@ -115,13 +123,18 @@ static void deformVerts(ModifierData *md, Object *ob,
if (!dm)
return;
- needsFree = 1;
+ needsFree = true;
}
/* clear old dm */
- if (psmd->dm) {
- psmd->dm->needsFree = 1;
- psmd->dm->release(psmd->dm);
+ if (psmd->dm_final) {
+ psmd->dm_final->needsFree = true;
+ psmd->dm_final->release(psmd->dm_final);
+ if (psmd->dm_deformed) {
+ psmd->dm_deformed->needsFree = 1;
+ psmd->dm_deformed->release(psmd->dm_deformed);
+ psmd->dm_deformed = NULL;
+ }
}
else if (psmd->flag & eParticleSystemFlag_file_loaded) {
/* in file read dm just wasn't saved in file so no need to reset everything */
@@ -133,29 +146,42 @@ static void deformVerts(ModifierData *md, Object *ob,
}
/* make new dm */
- psmd->dm = CDDM_copy(dm);
- CDDM_apply_vert_coords(psmd->dm, vertexCos);
- CDDM_calc_normals(psmd->dm);
+ psmd->dm_final = CDDM_copy(dm);
+ CDDM_apply_vert_coords(psmd->dm_final, vertexCos);
+ CDDM_calc_normals(psmd->dm_final);
if (needsFree) {
- dm->needsFree = 1;
+ dm->needsFree = true;
dm->release(dm);
}
/* protect dm */
- psmd->dm->needsFree = 0;
+ psmd->dm_final->needsFree = false;
+
+ DM_ensure_tessface(psmd->dm_final);
+
+ if (!psmd->dm_final->deformedOnly) {
+ /* XXX Think we can assume here that if current DM is not only-deformed, ob->deformedOnly has been set.
+ * This is awfully weak though. :| */
+ if (ob->derivedDeform) {
+ psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
+ }
+ else { /* Can happen in some cases, e.g. when rendering from Edit mode... */
+ psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
+ }
+ DM_ensure_tessface(psmd->dm_deformed);
+ }
/* report change in mesh structure */
- DM_ensure_tessface(psmd->dm);
- if (psmd->dm->getNumVerts(psmd->dm) != psmd->totdmvert ||
- psmd->dm->getNumEdges(psmd->dm) != psmd->totdmedge ||
- psmd->dm->getNumTessFaces(psmd->dm) != psmd->totdmface)
+ if (psmd->dm_final->getNumVerts(psmd->dm_final) != psmd->totdmvert ||
+ psmd->dm_final->getNumEdges(psmd->dm_final) != psmd->totdmedge ||
+ psmd->dm_final->getNumTessFaces(psmd->dm_final) != psmd->totdmface)
{
psys->recalc |= PSYS_RECALC_RESET;
- psmd->totdmvert = psmd->dm->getNumVerts(psmd->dm);
- psmd->totdmedge = psmd->dm->getNumEdges(psmd->dm);
- psmd->totdmface = psmd->dm->getNumTessFaces(psmd->dm);
+ psmd->totdmvert = psmd->dm_final->getNumVerts(psmd->dm_final);
+ psmd->totdmedge = psmd->dm_final->getNumEdges(psmd->dm_final);
+ psmd->totdmface = psmd->dm_final->getNumTessFaces(psmd->dm_final);
}
if (!(ob->transflag & OB_NO_PSYS_UPDATE)) {
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index db65f4431e4..41ebd865720 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -44,6 +44,7 @@
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "depsgraph_private.h"
#include "DEG_depsgraph_build.h"
@@ -1090,12 +1091,11 @@ static void updateDepsgraph(ModifierData *md,
static void foreachObjectLink(
ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+ ObjectWalkFunc walk, void *userData)
{
ScrewModifierData *ltmd = (ScrewModifierData *) md;
- walk(userData, ob, &ltmd->ob_axis);
+ walk(userData, ob, &ltmd->ob_axis, IDWALK_NOP);
}
ModifierTypeInfo modifierType_Screw = {
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 91be0c40059..a9919cadd16 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -41,6 +41,7 @@
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_shrinkwrap.h"
@@ -100,8 +101,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *) md;
- walk(userData, ob, &smd->target);
- walk(userData, ob, &smd->auxTarget);
+ walk(userData, ob, &smd->target, IDWALK_NOP);
+ walk(userData, ob, &smd->auxTarget, IDWALK_NOP);
}
static void deformVerts(ModifierData *md, Object *ob,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 706a296f5a1..588b56d6aba 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -40,6 +40,7 @@
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
@@ -213,10 +214,15 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
}
modifier_get_vgroup(ob, dm, smd->vgroup_name, &dvert, &vgroup);
+ const bool invert_vgroup = (smd->flag & MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP) != 0;
for (i = 0; i < numVerts; i++) {
float weight = defvert_array_find_weight_safe(dvert, i, vgroup);
+ if (invert_vgroup) {
+ weight = 1.0f - weight;
+ }
+
if (weight != 0.0f) {
float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
@@ -279,11 +285,12 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
-static void foreachObjectLink(ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData)
+static void foreachObjectLink(
+ ModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
{
SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
- walk(userData, ob, &smd->origin);
+ walk(userData, ob, &smd->origin, IDWALK_NOP);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 1b8b29666e2..9f1ec4de3d5 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -708,7 +708,8 @@ static EMat *build_edge_mats(const MVertSkin *vs,
int totvert,
const MEdge *medge,
const MeshElemMap *emap,
- int totedge)
+ int totedge,
+ bool *has_valid_root)
{
BLI_Stack *stack;
EMat *emat;
@@ -736,6 +737,8 @@ static EMat *build_edge_mats(const MVertSkin *vs,
stack_elem.e = emap[v].indices[i];
BLI_stack_push(stack, &stack_elem);
}
+
+ *has_valid_root = true;
}
}
}
@@ -1828,6 +1831,7 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
MEdge *medge;
MDeformVert *dvert;
int totvert, totedge;
+ bool has_valid_root = false;
nodes = CustomData_get_layer(&origdm->vertData, CD_MVERT_SKIN);
@@ -1839,7 +1843,7 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
BKE_mesh_vert_edge_map_create(&emap, &emapmem, medge, totvert, totedge);
- emat = build_edge_mats(nodes, mvert, totvert, medge, emap, totedge);
+ emat = build_edge_mats(nodes, mvert, totvert, medge, emap, totedge, &has_valid_root);
skin_nodes = build_frames(mvert, totvert, nodes, emap, emat);
MEM_freeN(emat);
emat = NULL;
@@ -1850,6 +1854,10 @@ static DerivedMesh *base_skin(DerivedMesh *origdm,
MEM_freeN(emap);
MEM_freeN(emapmem);
+ if (!has_valid_root) {
+ modifier_setError(&smd->modifier, "No valid root vertex found (you need one per mesh island you want to skin)");
+ }
+
if (!bm)
return NULL;
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 657c4e09d96..237d4cc6718 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -48,6 +48,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_smoke.h"
@@ -104,12 +105,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
ModifierApplyFlag flag)
{
SmokeModifierData *smd = (SmokeModifierData *) md;
- bool for_render = (flag & MOD_APPLY_RENDER) != 0;
if (flag & MOD_APPLY_ORCO)
return dm;
- return smokeModifier_do(smd, md->scene, ob, dm, for_render);
+ return smokeModifier_do(smd, md->scene, ob, dm);
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -122,10 +122,10 @@ static void update_depsgraph_flow_coll_object(DagForest *forest,
Object *object2)
{
SmokeModifierData *smd;
- if ((object2->id.flag & LIB_DOIT) == 0) {
+ if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
return;
}
- object2->id.flag &= ~LIB_DOIT;
+ object2->id.tag &= ~LIB_TAG_DOIT;
smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
@@ -152,10 +152,10 @@ static void update_depsgraph_field_source_object(DagForest *forest,
Object *object,
Object *object2)
{
- if ((object2->id.flag & LIB_DOIT) == 0) {
+ if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
return;
}
- object2->id.flag &= ~LIB_DOIT;
+ object2->id.tag &= ~LIB_TAG_DOIT;
if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
DagNode *node2 = dag_get_node(forest, object2);
dag_add_relation(forest, obNode, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Field Source Object");
@@ -213,7 +213,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
else {
- BKE_main_id_tag_listbase(&bmain->object, true);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
base = scene->base.first;
for (; base; base = base->next) {
update_depsgraph_flow_coll_object(forest, obNode, base->object);
@@ -221,7 +221,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
/* add relation to all "smoke flow" force fields */
base = scene->base.first;
- BKE_main_id_tag_listbase(&bmain->object, true);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
for (; base; base = base->next) {
update_depsgraph_field_source_object(forest, obNode, ob, base->object);
}
@@ -232,10 +232,10 @@ static void update_depsgraph_flow_coll_object_new(struct DepsNodeHandle *node,
Object *object2)
{
SmokeModifierData *smd;
- if ((object2->id.flag & LIB_DOIT) == 0) {
+ if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
return;
}
- object2->id.flag &= ~LIB_DOIT;
+ object2->id.tag &= ~LIB_TAG_DOIT;
smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
@@ -261,10 +261,10 @@ static void update_depsgraph_field_source_object_new(struct DepsNodeHandle *node
Object *object,
Object *object2)
{
- if ((object2->id.flag & LIB_DOIT) == 0) {
+ if ((object2->id.tag & LIB_TAG_DOIT) == 0) {
return;
}
- object2->id.flag &= ~LIB_DOIT;
+ object2->id.tag &= ~LIB_TAG_DOIT;
if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Field Source Object");
DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Field Source Object");
@@ -318,7 +318,7 @@ static void updateDepsgraph(ModifierData *md,
}
}
else {
- BKE_main_id_tag_listbase(&bmain->object, true);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
base = scene->base.first;
for (; base; base = base->next) {
update_depsgraph_flow_coll_object_new(node, base->object);
@@ -326,7 +326,7 @@ static void updateDepsgraph(ModifierData *md,
}
/* add relation to all "smoke flow" force fields */
base = scene->base.first;
- BKE_main_id_tag_listbase(&bmain->object, true);
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
for (; base; base = base->next) {
update_depsgraph_field_source_object_new(node, ob, base->object);
}
@@ -339,17 +339,17 @@ static void foreachIDLink(ModifierData *md, Object *ob,
SmokeModifierData *smd = (SmokeModifierData *) md;
if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) {
- walk(userData, ob, (ID **)&smd->domain->coll_group);
- walk(userData, ob, (ID **)&smd->domain->fluid_group);
- walk(userData, ob, (ID **)&smd->domain->eff_group);
+ walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_NOP);
+ walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_NOP);
if (smd->domain->effector_weights) {
- walk(userData, ob, (ID **)&smd->domain->effector_weights->group);
+ walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_NOP);
}
}
if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) {
- walk(userData, ob, (ID **)&smd->flow->noise_texture);
+ walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_USER);
}
}
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index ca2dcfec3a3..527576843e3 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -272,7 +272,7 @@ static DerivedMesh *applyModifier(
/* calculate only face normals */
face_nors = MEM_mallocN(sizeof(*face_nors) * (size_t)numFaces, __func__);
BKE_mesh_calc_normals_poly(
- orig_mvert, (int)numVerts,
+ orig_mvert, NULL, (int)numVerts,
orig_mloop, orig_mpoly,
(int)numLoops, (int)numFaces,
face_nors, true);
@@ -455,15 +455,28 @@ static DerivedMesh *applyModifier(
mp = mpoly + numFaces;
for (i = 0; i < dm->numPolyData; i++, mp++) {
+ const int loop_end = mp->totloop - 1;
MLoop *ml2;
unsigned int e;
int j;
+ /* reverses the loop direction (MLoop.v as well as custom-data)
+ * MLoop.e also needs to be corrected too, done in a separate loop below. */
ml2 = mloop + mp->loopstart + dm->numLoopData;
+#if 0
for (j = 0; j < mp->totloop; j++) {
CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
- mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
+ mp->loopstart + (loop_end - j) + dm->numLoopData, 1);
+ }
+#else
+ /* slightly more involved, keep the first vertex the same for the copy,
+ * ensures the diagonals in the new face match the original. */
+ j = 0;
+ for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) {
+ CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
+ mp->loopstart + (loop_end - j_prev) + dm->numLoopData, 1);
}
+#endif
if (mat_ofs) {
mp->mat_nr += mat_ofs;
@@ -471,10 +484,10 @@ static DerivedMesh *applyModifier(
}
e = ml2[0].e;
- for (j = 0; j < mp->totloop - 1; j++) {
+ for (j = 0; j < loop_end; j++) {
ml2[j].e = ml2[j + 1].e;
}
- ml2[mp->totloop - 1].e = e;
+ ml2[loop_end].e = e;
mp->loopstart += dm->numLoopData;
@@ -694,9 +707,9 @@ static DerivedMesh *applyModifier(
INIT_VERT_ARRAY_OFFSETS(false);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
- if (vert_accum[i]) { /* zero if unselected */
- madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
+ const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (vert_accum[i_other]) { /* zero if unselected */
+ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
}
}
}
@@ -709,9 +722,9 @@ static DerivedMesh *applyModifier(
INIT_VERT_ARRAY_OFFSETS(true);
for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
- if (vert_accum[i]) { /* zero if unselected */
- madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
+ const unsigned int i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (vert_accum[i_other]) { /* zero if unselected */
+ madd_v3_v3fl(mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index cbd7bc97768..23ab61821f4 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -108,10 +108,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
#ifdef WITH_OPENSUBDIV
const bool allow_gpu = (flag & MOD_APPLY_ALLOW_GPU) != 0;
- const bool do_cddm_convert = useRenderParams || (!isFinalCalc && !smd->use_opensubdiv);
-#else
- const bool do_cddm_convert = useRenderParams || !isFinalCalc;
#endif
+ bool do_cddm_convert = useRenderParams || !isFinalCalc;
if (useRenderParams)
subsurf_flags |= SUBSURF_USE_RENDER_PARAMS;
@@ -134,6 +132,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
+ do_cddm_convert = false;
}
else {
modifier_setError(md, "OpenSubdiv is disabled due to dependencies");
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index ff5e5f643a7..68987a1d28e 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -190,6 +190,6 @@ ModifierTypeInfo modifierType_Surface = {
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
};
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 194a46b6f28..6fad2756f82 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -44,7 +44,7 @@ static DerivedMesh *triangulate_dm(DerivedMesh *dm, const int quad_method, const
bm = DM_to_bmesh(dm, true);
- BM_mesh_triangulate(bm, quad_method, ngon_method, false, NULL, NULL);
+ BM_mesh_triangulate(bm, quad_method, ngon_method, false, NULL, NULL, NULL);
result = CDDM_from_bmesh(bm, false);
BM_mesh_free(bm);
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index be6f7af7791..f9291fb077f 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -55,10 +55,6 @@
#include "MEM_guardedalloc.h"
-#ifdef OPENNL_THREADING_HACK
-#include "BLI_threads.h"
-#endif
-
void modifier_init_texture(const Scene *scene, Tex *tex)
{
if (!tex)
@@ -234,23 +230,6 @@ void modifier_get_vgroup(Object *ob, DerivedMesh *dm, const char *name, MDeformV
}
-#ifdef OPENNL_THREADING_HACK
-
-static ThreadMutex opennl_context_mutex = BLI_MUTEX_INITIALIZER;
-
-void modifier_opennl_lock(void)
-{
- BLI_mutex_lock(&opennl_context_mutex);
-}
-
-void modifier_opennl_unlock(void)
-{
- BLI_mutex_unlock(&opennl_context_mutex);
-}
-
-#endif
-
-
/* only called by BKE_modifier.h/modifier.c */
void modifier_type_init(ModifierTypeInfo *types[])
{
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index b74ff9c2a25..095d7c278df 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -52,21 +52,4 @@ struct DerivedMesh *get_dm_for_modifier(struct Object *ob, ModifierApplyFlag fla
void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm,
const char *name, struct MDeformVert **dvert, int *defgrp_index);
-/* XXX workaround for non-threadsafe context in OpenNL (T38403)
- * OpenNL uses global pointer for "current context", which causes
- * conflict when multiple modifiers get evaluated in threaded depgraph.
- * This is just a stupid hack to prevent assert failure / crash,
- * otherwise we'd have to modify OpenNL on a large scale.
- * OpenNL should be replaced eventually, there are other options (eigen, ceres).
- * - lukas_t
- */
-#ifdef WITH_OPENNL
-#define OPENNL_THREADING_HACK
-#endif
-
-#ifdef OPENNL_THREADING_HACK
-void modifier_opennl_lock(void);
-void modifier_opennl_unlock(void);
-#endif
-
#endif /* __MOD_UTIL_H__ */
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 1b1474ee666..fb7668d16e0 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -45,6 +45,7 @@
#include "BKE_camera.h"
+#include "BKE_library_query.h"
#include "BKE_mesh.h"
#include "BKE_DerivedMesh.h"
@@ -91,7 +92,7 @@ static void foreachObjectLink(ModifierData *md, Object *ob,
int i;
for (i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
- walk(userData, ob, &umd->projectors[i]);
+ walk(userData, ob, &umd->projectors[i], IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -99,10 +100,9 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
UVProjectModifierData *umd = (UVProjectModifierData *) md;
- walk(userData, ob, (ID **)&umd->image);
+ walk(userData, ob, (ID **)&umd->image, IDWALK_USER);
- foreachObjectLink(md, ob, (ObjectWalkFunc)walk,
- userData);
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
static void updateDepgraph(ModifierData *md, DagForest *forest,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index 3c4ca66485d..89994c3ae22 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -31,11 +31,13 @@
#include "DNA_object_types.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_action.h" /* BKE_pose_channel_find_name */
#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "depsgraph_private.h"
@@ -97,16 +99,58 @@ static void matrix_from_obj_pchan(float mat[4][4], Object *ob, const char *bonen
}
}
-#ifdef _OPENMP
-# define OMP_LIMIT 1000
-#endif
+typedef struct UVWarpData {
+ MPoly *mpoly;
+ MLoop *mloop;
+ MLoopUV *mloopuv;
+
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ float (*warp_mat)[4];
+ int axis_u;
+ int axis_v;
+} UVWarpData;
+
+static void uv_warp_compute(void *userdata, const int i)
+{
+ const UVWarpData *data = userdata;
+
+ const MPoly *mp = &data->mpoly[i];
+ const MLoop *ml = &data->mloop[mp->loopstart];
+ MLoopUV *mluv = &data->mloopuv[mp->loopstart];
+
+ const MDeformVert *dvert = data->dvert;
+ const int defgrp_index = data->defgrp_index;
+
+ float (*warp_mat)[4] = data->warp_mat;
+ const int axis_u = data->axis_u;
+ const int axis_v = data->axis_v;
+
+ int l;
+
+ if (dvert) {
+ for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
+ float uv[2];
+ const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index);
+
+ uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v);
+ interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight);
+ }
+ }
+ else {
+ for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
+ uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v);
+ }
+ }
+}
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- int i, numPolys, numLoops;
+ int numPolys, numLoops;
MPoly *mpoly;
MLoop *mloop;
MLoopUV *mloopuv;
@@ -163,33 +207,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
mloopuv = CustomData_duplicate_referenced_layer_named(&dm->loopData, CD_MLOOPUV, uvname, numLoops);
modifier_get_vgroup(ob, dm, umd->vgroup_name, &dvert, &defgrp_index);
- if (dvert) {
-#pragma omp parallel for if (numPolys > OMP_LIMIT)
- for (i = 0; i < numPolys; i++) {
- float uv[2];
- MPoly *mp = &mpoly[i];
- MLoop *ml = &mloop[mp->loopstart];
- MLoopUV *mluv = &mloopuv[mp->loopstart];
- int l;
- for (l = 0; l < mp->totloop; l++, ml++, mluv++) {
- const float weight = defvert_find_weight(&dvert[ml->v], defgrp_index);
- uv_warp_from_mat4_pair(uv, mluv->uv, warp_mat, axis_u, axis_v);
- interp_v2_v2v2(mluv->uv, mluv->uv, uv, weight);
- }
- }
- }
- else {
-#pragma omp parallel for if (numPolys > OMP_LIMIT)
- for (i = 0; i < numPolys; i++) {
- MPoly *mp = &mpoly[i];
- // MLoop *ml = &mloop[mp->loopstart];
- MLoopUV *mluv = &mloopuv[mp->loopstart];
- int l;
- for (l = 0; l < mp->totloop; l++, /* ml++, */ mluv++) {
- uv_warp_from_mat4_pair(mluv->uv, mluv->uv, warp_mat, axis_u, axis_v);
- }
- }
- }
+ UVWarpData data = {.mpoly = mpoly, .mloop = mloop, .mloopuv = mloopuv,
+ .dvert = dvert, .defgrp_index = defgrp_index,
+ .warp_mat = warp_mat, .axis_u = axis_u, .axis_v = axis_v};
+ BLI_task_parallel_range(0, numPolys, &data, uv_warp_compute, numPolys > 1000);
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
@@ -200,8 +221,8 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
UVWarpModifierData *umd = (UVWarpModifierData *) md;
- walk(userData, ob, &umd->object_dst);
- walk(userData, ob, &umd->object_src);
+ walk(userData, ob, &umd->object_dst, IDWALK_NOP);
+ walk(userData, ob, &umd->object_src, IDWALK_NOP);
}
static void uv_warp_deps_object_bone(DagForest *forest, DagNode *obNode,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index ae2dbd4a37c..27d3bac59ec 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -36,6 +36,7 @@
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_texture.h"
@@ -115,20 +116,18 @@ static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk,
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, &wmd->object_from);
- walk(userData, ob, &wmd->object_to);
- walk(userData, ob, &wmd->map_object);
+ walk(userData, ob, &wmd->object_from, IDWALK_NOP);
+ walk(userData, ob, &wmd->object_to, IDWALK_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WarpModifierData *wmd = (WarpModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
- walk(userData, ob, (ID **)&wmd->object_from);
- walk(userData, ob, (ID **)&wmd->object_to);
- walk(userData, ob, (ID **)&wmd->map_object);
+ foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 5b98f221489..f13eeb3185e 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -45,6 +45,7 @@
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -110,8 +111,8 @@ static void foreachObjectLink(
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, &wmd->objectcenter);
- walk(userData, ob, &wmd->map_object);
+ walk(userData, ob, &wmd->objectcenter, IDWALK_NOP);
+ walk(userData, ob, &wmd->map_object, IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob,
@@ -119,7 +120,7 @@ static void foreachIDLink(ModifierData *md, Object *ob,
{
WaveModifierData *wmd = (WaveModifierData *) md;
- walk(userData, ob, (ID **)&wmd->texture);
+ walk(userData, ob, (ID **)&wmd->texture, IDWALK_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index cba077a2f8d..93567aed2c4 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -42,6 +42,7 @@
#include "BKE_colortools.h" /* CurveMapping. */
#include "BKE_deform.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
@@ -122,19 +123,17 @@ static bool dependsOnTime(ModifierData *md)
return false;
}
-static void foreachObjectLink(ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 0649998e42d..01a219d1457 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -39,6 +39,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
@@ -171,19 +172,17 @@ static bool dependsOnTime(ModifierData *md)
return false;
}
-static void foreachObjectLink(ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, &wmd->mask_tex_map_obj);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 08d7d77c74e..f126e499fc2 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -33,6 +33,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
+#include "BLI_task.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -42,6 +43,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
#include "BKE_library.h"
+#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_texture.h" /* Texture masking. */
@@ -51,7 +53,7 @@
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
-// #define USE_TIMEIT
+//#define USE_TIMEIT
#ifdef USE_TIMEIT
# include "PIL_time.h"
@@ -65,6 +67,67 @@
/* Util macro. */
#define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n"))
+typedef struct Vert2GeomData {
+ /* Read-only data */
+ float (*v_cos)[3];
+
+ const SpaceTransform *loc2trgt;
+
+ BVHTreeFromMesh *treeData[3];
+
+ /* Write data, but not needing locking (two different threads will never write same index). */
+ float *dist[3];
+} Vert2GeomData;
+
+/* Data which is localized to each computed chunk (i.e. thread-safe, and with continous subset of index range). */
+typedef struct Vert2GeomDataChunk {
+ /* Read-only data */
+ float last_hit_co[3][3];
+ bool is_init[3];
+} Vert2GeomDataChunk;
+
+/**
+ * Callback used by BLI_task 'for loop' helper.
+ */
+static void vert2geom_task_cb_ex(void *userdata, void *userdata_chunk, const int iter, const int UNUSED(thread_id))
+{
+ Vert2GeomData *data = userdata;
+ Vert2GeomDataChunk *data_chunk = userdata_chunk;
+
+ float tmp_co[3];
+ int i;
+
+ /* Convert the vertex to tree coordinates. */
+ copy_v3_v3(tmp_co, data->v_cos[iter]);
+ BLI_space_transform_apply(data->loc2trgt, tmp_co);
+
+ for (i = 0; i < ARRAY_SIZE(data->dist); i++) {
+ if (data->dist[i]) {
+ BVHTreeNearest nearest = {0};
+
+ /* Note that we use local proximity heuristics (to reduce the nearest search).
+ *
+ * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index),
+ * we assume this vertex is going to have a close hit to that other vertex, so we can initiate
+ * the "nearest.dist" with the expected value to that last hit.
+ * This will lead in pruning of the search tree.
+ */
+ nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX;
+ nearest.index = -1;
+
+ /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
+ BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest,
+ data->treeData[i]->nearest_callback, data->treeData[i]);
+ data->dist[i][iter] = sqrtf(nearest.dist_sq);
+
+ if (nearest.index != -1) {
+ copy_v3_v3(data_chunk->last_hit_co[i], nearest.co);
+ data_chunk->is_init[i] = true;
+ }
+ }
+ }
+}
+
/**
* Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
*/
@@ -72,13 +135,12 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
float *dist_v, float *dist_e, float *dist_f,
DerivedMesh *target, const SpaceTransform *loc2trgt)
{
- int i;
+ Vert2GeomData data = {0};
+ Vert2GeomDataChunk data_chunk = {{{0}}};
+
BVHTreeFromMesh treeData_v = {NULL};
BVHTreeFromMesh treeData_e = {NULL};
BVHTreeFromMesh treeData_f = {NULL};
- BVHTreeNearest nearest_v = {0};
- BVHTreeNearest nearest_e = {0};
- BVHTreeNearest nearest_f = {0};
if (dist_v) {
/* Create a bvh-tree of the given target's verts. */
@@ -105,45 +167,18 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
}
}
- /* Setup nearest. */
- nearest_v.index = nearest_e.index = nearest_f.index = -1;
- /*nearest_v.dist = nearest_e.dist = nearest_f.dist = FLT_MAX;*/
- /* Find the nearest vert/edge/face. */
-#pragma omp parallel for default(shared) private(i) firstprivate(nearest_v, nearest_e, nearest_f) \
- schedule(static) if (numVerts > 10000)
- for (i = 0; i < numVerts; i++) {
- float tmp_co[3];
-
- /* Convert the vertex to tree coordinates. */
- copy_v3_v3(tmp_co, v_cos[i]);
- BLI_space_transform_apply(loc2trgt, tmp_co);
-
- /* Use local proximity heuristics (to reduce the nearest search).
- *
- * If we already had an hit before, we assume this vertex is going to have a close hit to
- * that other vertex, so we can initiate the "nearest.dist" with the expected value to that
- * last hit.
- * This will lead in prunning of the search tree.
- */
- if (dist_v) {
- nearest_v.dist_sq = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX;
- /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
- BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v);
- dist_v[i] = sqrtf(nearest_v.dist_sq);
- }
- if (dist_e) {
- nearest_e.dist_sq = nearest_e.index != -1 ? len_squared_v3v3(tmp_co, nearest_e.co) : FLT_MAX;
- /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
- BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e);
- dist_e[i] = sqrtf(nearest_e.dist_sq);
- }
- if (dist_f) {
- nearest_f.dist_sq = nearest_f.index != -1 ? len_squared_v3v3(tmp_co, nearest_f.co) : FLT_MAX;
- /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
- BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f);
- dist_f[i] = sqrtf(nearest_f.dist_sq);
- }
- }
+ data.v_cos = v_cos;
+ data.loc2trgt = loc2trgt;
+ data.treeData[0] = &treeData_v;
+ data.treeData[1] = &treeData_e;
+ data.treeData[2] = &treeData_f;
+ data.dist[0] = dist_v;
+ data.dist[1] = dist_e;
+ data.dist[2] = dist_f;
+
+ BLI_task_parallel_range_ex(
+ 0, numVerts, &data, &data_chunk, sizeof(data_chunk), vert2geom_task_cb_ex,
+ numVerts > 10000, false);
if (dist_v)
free_bvhtree_from_mesh(&treeData_v);
@@ -287,20 +322,18 @@ static bool dependsOnTime(ModifierData *md)
return 0;
}
-static void foreachObjectLink(ModifierData *md, Object *ob,
- void (*walk)(void *userData, Object *ob, Object **obpoin),
- void *userData)
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, &wmd->proximity_ob_target);
- walk(userData, ob, &wmd->mask_tex_map_obj);
+ walk(userData, ob, &wmd->proximity_ob_target, IDWALK_NOP);
+ walk(userData, ob, &wmd->mask_tex_map_obj, IDWALK_NOP);
}
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
- walk(userData, ob, (ID **)&wmd->mask_texture);
+ walk(userData, ob, (ID **)&wmd->mask_texture, IDWALK_USER);
foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
}
diff --git a/source/blender/nodes/SConscript b/source/blender/nodes/SConscript
deleted file mode 100644
index ad500725812..00000000000
--- a/source/blender/nodes/SConscript
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.c')
-cmpsources = env.Glob('composite/*.c') + env.Glob('composite/nodes/*.c')
-shdsources = env.Glob('shader/*.c') + env.Glob('shader/nodes/*.c')
-texsources = env.Glob('texture/*.c') + env.Glob('texture/nodes/*.c')
-
-incs = [
- '.',
- './composite',
- './intern',
- './shader',
- './texture',
- '#/intern/guardedalloc',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../blenkernel',
- '../blenlib',
- '../blentranslation',
- '../gpu',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../render/extern/include',
- env['BF_ZLIB_INC'],
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- incs += ' ../python'
- defs.append('WITH_PYTHON')
- if env['BF_DEBUG']:
- defs.append('_DEBUG')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['WITH_BF_COMPOSITOR']:
- incs += ' ../compositor '
- defs.append("WITH_COMPOSITOR")
-
-if env['WITH_BF_FREESTYLE']:
- defs.append('WITH_FREESTYLE')
-
-if env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-env.BlenderLib ( libname = 'bf_nodes', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [190,105] )
-env.BlenderLib ( libname = 'bf_cmpnodes', sources = cmpsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] )
-env.BlenderLib ( libname = 'bf_shdnodes', sources = shdsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] )
-env.BlenderLib ( libname = 'bf_texnodes', sources = texsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] )
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c
index bbfb07a316d..c6b1d37f8b4 100644
--- a/source/blender/nodes/composite/node_composite_util.c
+++ b/source/blender/nodes/composite/node_composite_util.c
@@ -55,5 +55,6 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
+ ntype->insert_link = node_insert_link_default;
ntype->update_internal_links = node_update_internal_links_default;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c
index 75e7fa8fbac..0fbbb54ee7a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.c
+++ b/source/blender/nodes/composite/nodes/node_composite_common.c
@@ -51,6 +51,7 @@ void register_node_type_cmp_group(void)
ntype.type = NODE_GROUP;
ntype.poll = cmp_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
ntype.ext.srna = RNA_struct_find("CompositorNodeGroup");
BLI_assert(ntype.ext.srna != NULL);
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.c b/source/blender/nodes/composite/nodes/node_composite_levels.c
index ffee10528ee..65e5b2fedf1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.c
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.c
@@ -57,7 +57,6 @@ void register_node_type_cmp_view_levels(void)
cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW);
node_type_socket_templates(&ntype, cmp_node_view_levels_in, cmp_node_view_levels_out);
node_type_init(&ntype, node_composit_init_view_levels);
- node_type_storage(&ntype, "ImageUser", NULL, NULL);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.c b/source/blender/nodes/composite/nodes/node_composite_mask.c
index dd05d5d83ad..39c7a750ea1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.c
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.c
@@ -51,6 +51,16 @@ static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
node->custom3 = 0.5f; /* shutter */
}
+static void node_mask_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+{
+ if (node->id != NULL) {
+ BLI_strncpy(label, node->id->name + 2, maxlen);
+ }
+ else {
+ BLI_strncpy(label, IFACE_("Mask"), maxlen);
+ }
+}
+
void register_node_type_cmp_mask(void)
{
static bNodeType ntype;
@@ -58,6 +68,7 @@ void register_node_type_cmp_mask(void)
cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
node_type_socket_templates(&ntype, NULL, cmp_node_mask_out);
node_type_init(&ntype, node_composit_init_mask);
+ node_type_label(&ntype, node_mask_label);
node_type_storage(&ntype, "NodeMask", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.c b/source/blender/nodes/composite/nodes/node_composite_trackpos.c
index 0daf89b12f7..4a00fb5a900 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.c
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.c
@@ -36,6 +36,7 @@
static bNodeSocketTemplate cmp_node_trackpos_out[] = {
{ SOCK_FLOAT, 0, N_("X")},
{ SOCK_FLOAT, 0, N_("Y")},
+ { SOCK_VECTOR, 0, N_("Speed"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_VELOCITY},
{ -1, 0, "" }
};
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 046188f8508..dd5715891d5 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -29,6 +29,7 @@
* \ingroup nodes
*/
+#include <ctype.h>
#include <limits.h>
#include <string.h>
@@ -86,32 +87,121 @@ void *node_initexec_curves(bNodeExecContext *UNUSED(context), bNode *node, bNode
void node_blend_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
- RNA_enum_name(ramp_blend_items, node->custom1, &name);
+ RNA_enum_name(rna_enum_ramp_blend_items, node->custom1, &name);
BLI_strncpy(label, IFACE_(name), maxlen);
}
void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
- RNA_enum_name(node_math_items, node->custom1, &name);
+ RNA_enum_name(rna_enum_node_math_items, node->custom1, &name);
BLI_strncpy(label, IFACE_(name), maxlen);
}
void node_vect_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
- RNA_enum_name(node_vec_math_items, node->custom1, &name);
+ RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
BLI_strncpy(label, IFACE_(name), maxlen);
}
void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
{
const char *name;
- RNA_enum_name(node_filter_items, node->custom1, &name);
+ RNA_enum_name(rna_enum_node_filter_items, node->custom1, &name);
BLI_strncpy(label, IFACE_(name), maxlen);
}
+/*** Link Insertion ***/
+
+/* test if two sockets are interchangeable */
+static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b)
+{
+ /* tests if alphabetic prefix matches
+ * this allows for imperfect matches, such as numeric suffixes,
+ * like Color1/Color2
+ */
+ int prefix_len = 0;
+ char *ca = a->name, *cb = b->name;
+ for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) {
+ /* end of common prefix? */
+ if (*ca != *cb) {
+ /* prefix delimited by non-alphabetic char */
+ if (isalpha(*ca) || isalpha(*cb))
+ return false;
+ break;
+ }
+ ++prefix_len;
+ }
+ return prefix_len > 0;
+}
+
+static int node_count_links(bNodeTree *ntree, bNodeSocket *sock)
+{
+ bNodeLink *link;
+ int count = 0;
+ for (link = ntree->links.first; link; link = link->next) {
+ if (link->fromsock == sock)
+ ++count;
+ if (link->tosock == sock)
+ ++count;
+ }
+ return count;
+}
+
+/* find an eligible socket for linking */
+static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur)
+{
+ /* link swapping: try to find a free slot with a matching name */
+
+ bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first;
+ bNodeSocket *sock;
+
+ sock = cur->next ? cur->next : first; /* wrap around the list end */
+ while (sock != cur) {
+ if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) {
+ int link_count = node_count_links(ntree, sock);
+ /* take +1 into account since we would add a new link */
+ if (link_count + 1 <= sock->limit)
+ return sock; /* found a valid free socket we can swap to */
+ }
+
+ sock = sock->next ? sock->next : first; /* wrap around the list end */
+ }
+ return NULL;
+}
+
+void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
+{
+ bNodeSocket *sock = link->tosock;
+ bNodeLink *tlink, *tlink_next;
+
+ /* inputs can have one link only, outputs can have unlimited links */
+ if (node != link->tonode)
+ return;
+
+ for (tlink = ntree->links.first; tlink; tlink = tlink_next) {
+ bNodeSocket *new_sock;
+ tlink_next = tlink->next;
+
+ if (sock != tlink->tosock)
+ continue;
+
+ new_sock = node_find_linkable_socket(ntree, node, sock);
+ if (new_sock && new_sock != sock) {
+ /* redirect existing link */
+ tlink->tosock = new_sock;
+ }
+ else if (!new_sock) {
+ /* no possible replacement, remove tlink */
+ nodeRemLink(ntree, tlink);
+ tlink = NULL;
+ }
+ }
+}
+
+
/**** Internal Links (mute and disconnect) ****/
/* common datatype priorities, works for compositor, shader and texture nodes alike
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
index 64b2028874b..2e20a8e79d4 100644
--- a/source/blender/nodes/intern/node_util.h
+++ b/source/blender/nodes/intern/node_util.h
@@ -76,6 +76,9 @@ void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, i
void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+
+/*** Link Handling */
+void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link);
void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node);
float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock);
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 49881381253..9bd43f331fb 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -47,6 +47,7 @@ void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, shor
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = sh_node_poll_default;
+ ntype->insert_link = node_insert_link_default;
ntype->update_internal_links = node_update_internal_links_default;
}
@@ -141,7 +142,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
{
memset(gs, 0, sizeof(*gs));
- copy_v4_v4(gs->vec, ns->vec);
+ nodestack_get_vec(gs->vec, type, ns);
gs->link = ns->data;
if (type == SOCK_FLOAT)
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
index 8dda7b0859b..01ca0bd6512 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -53,6 +53,8 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *UNUSED(node
{
if (!in[4].link)
in[4].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[4].link, GPU_builtin(GPU_VIEW_MATRIX), &in[4].link);
return GPU_stack_link(mat, "node_bsdf_anisotropic", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
index ffb53f3b330..e86d2677a61 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
@@ -45,6 +45,8 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, bNode *UNUSED(node), b
{
if (!in[2].link)
in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link);
return GPU_stack_link(mat, "node_bsdf_diffuse", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
index 75ca4b87f09..5569fe85489 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
@@ -51,6 +51,8 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, bNode *UNUSED(node), bNo
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
return GPU_stack_link(mat, "node_bsdf_glass", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
index 9518784eebe..7e1bc971c73 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
@@ -50,6 +50,8 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, bNode *UNUSED(node), bN
{
if (!in[2].link)
in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link);
return GPU_stack_link(mat, "node_bsdf_glossy", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
index dbc8807a845..25be59f091d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
@@ -33,7 +33,9 @@ static bNodeSocketTemplate sh_node_bsdf_hair_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Offset"), 0.0f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE},
{ SOCK_FLOAT, 1, N_("RoughnessU"), 0.1f, 0.1f, 0.1f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- { SOCK_FLOAT, 1, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { -1, 0, "" }
+ { SOCK_FLOAT, 1, N_("RoughnessV"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
+ { SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ { -1, 0, "" },
};
static bNodeSocketTemplate sh_node_bsdf_hair_out[] = {
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
index 90db7a5771d..c447f5de219 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
@@ -51,6 +51,8 @@ static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, bNode *UNUSED(node)
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
return GPU_stack_link(mat, "node_bsdf_refraction", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
index 29c1165314e..c3510beb470 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
@@ -46,6 +46,8 @@ static int node_shader_gpu_bsdf_toon(GPUMaterial *mat, bNode *UNUSED(node), bNod
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
return GPU_stack_link(mat, "node_bsdf_toon", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
index 0e346b8cc70..3b88d609cdb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
@@ -44,6 +44,8 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, bNode *UNUSED(node
{
if (!in[1].link)
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
return GPU_stack_link(mat, "node_bsdf_translucent", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
index e5d83a3b8f2..ef3d52ecbce 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
@@ -45,6 +45,8 @@ static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat, bNode *UNUSED(node), bN
{
if (!in[2].link)
in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link);
return GPU_stack_link(mat, "node_bsdf_velvet", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c
index 3146454f26d..22027d58385 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.c
@@ -49,6 +49,8 @@ static int gpu_shader_bump(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData
{
if (!in[3].link)
in[3].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link);
return GPU_stack_link(mat, "node_bump", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 7ff60ac716a..796193a564e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -236,6 +236,7 @@ void register_node_type_sh_group(void)
ntype.type = NODE_GROUP;
ntype.poll = sh_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
ntype.ext.srna = RNA_struct_find("ShaderNodeGroup");
BLI_assert(ntype.ext.srna != NULL);
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
index 59d798dc80c..b50f722c71b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c
@@ -43,6 +43,8 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE
{
if (!in[1].link)
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
index 832ce582b4b..8cbc587e339 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
@@ -45,6 +45,8 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), b
{
if (!in[1].link)
in[1].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link);
return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION));
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c
index 023c6ea02a9..b1001cd3937 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.c
@@ -40,6 +40,7 @@ static bNodeSocketTemplate sh_node_light_path_out[] = {
{ SOCK_FLOAT, 0, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
index 41e44a64376..fa13f6191ad 100644
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -263,6 +263,8 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
if (node->type == SH_NODE_MATERIAL_EXT) {
+ if (hasinput[MAT_IN_MIR])
+ shi.mir = gpu_get_input_link(&in[MAT_IN_MIR]);
if (hasinput[MAT_IN_AMB])
shi.amb = gpu_get_input_link(&in[MAT_IN_AMB]);
if (hasinput[MAT_IN_EMIT])
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
index 097a4928dd0..13bf2a0fe43 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c
@@ -48,7 +48,10 @@ static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
static int gpu_shader_normal_map(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- return GPU_stack_link(mat, "node_normal_map", in, out, GPU_builtin(GPU_VIEW_NORMAL));
+ GPUNodeLink *normal;
+ GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &normal);
+
+ return GPU_stack_link(mat, "node_normal_map", in, out, normal);
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.c
index 6cc8de322af..5f0d81e98c9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.c
@@ -52,10 +52,10 @@ static int gpu_shader_particle_info(GPUMaterial *mat, bNode *UNUSED(node), bNode
{
return GPU_stack_link(mat, "particle_info", in, out,
- GPU_builtin(GPU_PARTICLE_SCALAR_PROPS),
- GPU_builtin(GPU_PARTICLE_LOCATION),
- GPU_builtin(GPU_PARTICLE_VELOCITY),
- GPU_builtin(GPU_PARTICLE_ANG_VELOCITY));
+ GPU_builtin(GPU_PARTICLE_SCALAR_PROPS),
+ GPU_builtin(GPU_PARTICLE_LOCATION),
+ GPU_builtin(GPU_PARTICLE_VELOCITY),
+ GPU_builtin(GPU_PARTICLE_ANG_VELOCITY));
}
/* node type definition */
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index 8c83fa47815..7dfac32e85b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -46,22 +46,15 @@ static bNodeSocketTemplate sh_node_subsurface_scattering_out[] = {
static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNode *node)
{
- /*bNodeSocket *sock;*/
-
- node->custom1 = SHD_SUBSURFACE_CUBIC;
-
- /*for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Sharpness")) {
- bNodeSocketValueFloat *dval = sock->default_value;
- dval->value = 0.0f;
- }
- }*/
+ node->custom1 = SHD_SUBSURFACE_BURLEY;
}
static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[5].link)
in[5].link = GPU_builtin(GPU_VIEW_NORMAL);
+ else
+ GPU_link(mat, "direction_transform_m4v3", in[5].link, GPU_builtin(GPU_VIEW_MATRIX), &in[5].link);
return GPU_stack_link(mat, "node_subsurface_scattering", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
index 6205b0fa11f..006bd0cc8bb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
@@ -27,6 +27,10 @@
#include "../node_shader_util.h"
+#include "BKE_texture.h"
+
+#include "RE_render_ext.h"
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_pointdensity_in[] = {
@@ -52,6 +56,26 @@ static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree),
node->storage = point_density;
}
+static void node_shader_free_tex_pointdensity(bNode *node)
+{
+ NodeShaderTexPointDensity *point_density = node->storage;
+ PointDensity *pd = &point_density->pd;
+ RE_point_density_free(pd);
+ BKE_texture_pointdensity_free_data(pd);
+ memset(pd, 0, sizeof(*pd));
+ MEM_freeN(point_density);
+}
+
+static void node_shader_copy_tex_pointdensity(bNodeTree * UNUSED(dest_ntree),
+ bNode *dest_node,
+ bNode *src_node)
+{
+ dest_node->storage = MEM_dupallocN(src_node->storage);
+ NodeShaderTexPointDensity *point_density = dest_node->storage;
+ PointDensity *pd = &point_density->pd;
+ memset(pd, 0, sizeof(*pd));
+}
+
/* node type definition */
void register_node_type_sh_tex_pointdensity(void)
{
@@ -69,8 +93,8 @@ void register_node_type_sh_tex_pointdensity(void)
node_type_init(&ntype, node_shader_init_tex_pointdensity);
node_type_storage(&ntype,
"NodeShaderTexPointDensity",
- node_free_standard_storage,
- node_copy_standard_storage);
+ node_shader_free_tex_pointdensity,
+ node_shader_copy_tex_pointdensity);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
index 4cab9d3ca97..35a12d52b2d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c
@@ -52,15 +52,165 @@ static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *nod
node->storage = vect;
}
+static const float (* get_matrix_from_to(ShaderCallData *scd, short from, short to))[4]
+{
+ switch (from) {
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ switch (to) {
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ return NULL;
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB);
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW);
+ }
+ break;
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ switch (to) {
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ return NULL;
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ return RE_render_current_get_matrix(RE_VIEW_MATRIX);
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OBINV);
+ }
+ break;
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ switch (to) {
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ return NULL;
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ return RE_render_current_get_matrix(RE_VIEWINV_MATRIX);
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ return RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV);
+ }
+ break;
+ }
+ return NULL;
+}
+
+static void node_shader_exec_vect_transform(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out)
+{
+ float vec[4];
+ const float (*mat)[4];
+
+ if (data) {
+ NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
+
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+
+ if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT)
+ vec[3] = 1.0f;
+ else
+ vec[3] = 0.0f;
+
+ mat = get_matrix_from_to((ShaderCallData *)data, nodeprop->convert_from, nodeprop->convert_to);
+ if (mat) {
+ mul_m4_v4((float(*)[4])mat, vec);
+ }
+
+ if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_NORMAL)
+ normalize_v3(vec);
+
+ copy_v4_v4(out[0]->vec, vec);
+ }
+}
+
+static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
+{
+ switch (from) {
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ switch (to) {
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ return NULL;
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ return GPU_builtin(GPU_OBJECT_MATRIX);
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ return GPU_builtin(GPU_LOC_TO_VIEW_MATRIX);
+ }
+ break;
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ switch (to) {
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ return NULL;
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ return GPU_builtin(GPU_VIEW_MATRIX);
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ return GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
+ }
+ break;
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ switch (to) {
+ case SHD_VECT_TRANSFORM_SPACE_CAMERA:
+ return NULL;
+ case SHD_VECT_TRANSFORM_SPACE_WORLD:
+ return GPU_builtin(GPU_INVERSE_VIEW_MATRIX);
+ case SHD_VECT_TRANSFORM_SPACE_OBJECT:
+ return GPU_builtin(GPU_INVERSE_LOC_TO_VIEW_MATRIX);
+ }
+ break;
+ }
+ return NULL;
+}
+static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ struct GPUNodeLink *inputlink;
+ struct GPUNodeLink *fromto;
+
+ int ret = 0;
+
+ const char *vtransform = "direction_transform_m4v3";
+ const char *ptransform = "point_transform_m4v3";
+ const char *func_name = 0;
+
+ bool new_shading = GPU_material_use_new_shading_nodes(mat);
+
+ NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
+
+ if (in[0].hasinput)
+ inputlink = in[0].link;
+ else
+ inputlink = GPU_uniform(in[0].vec);
+
+ fromto = get_gpulink_matrix_from_to(nodeprop->convert_from, nodeprop->convert_to);
+
+ func_name = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? ptransform : vtransform;
+ if (fromto) {
+ if (new_shading) {
+ /* For cycles we have inverted Z */
+ /* TODO: pass here the correct matrices */
+ if (nodeprop->convert_from == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_to != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
+ ret = GPU_link(mat, "invert_z", inputlink, &inputlink);
+ }
+ ret = GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+ if (nodeprop->convert_to == SHD_VECT_TRANSFORM_SPACE_CAMERA && nodeprop->convert_from != SHD_VECT_TRANSFORM_SPACE_CAMERA) {
+ ret = GPU_link(mat, "invert_z", out[0].link, &out[0].link);
+ }
+ }
+ else {
+ ret = GPU_link(mat, func_name, inputlink, fromto, &out[0].link);
+ }
+ }
+ else
+ ret = GPU_link(mat, "set_rgb", inputlink, &out[0].link);
+
+ if (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_NORMAL)
+ return GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
+
+ return ret;
+}
+
void register_node_type_sh_vect_transform(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_CONVERTOR, 0);
- node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING);
node_type_init(&ntype, node_shader_init_vect_transform);
node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out);
node_type_storage(&ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_transform);
+ node_type_gpu(&ntype, gpu_shader_vect_transform);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index 42c684b8247..32720364f73 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -60,6 +60,7 @@ void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, sho
node_type_base(ntype, type, name, nclass, flag);
ntype->poll = tex_node_poll_default;
+ ntype->insert_link = node_insert_link_default;
ntype->update_internal_links = node_update_internal_links_default;
}
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 0410a9d4b33..9000cbb90d8 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -39,7 +39,6 @@
#include "MEM_guardedalloc.h"
#include "DNA_color_types.h"
-#include "DNA_ipo_types.h"
#include "DNA_ID.h"
#include "DNA_image_types.h"
#include "DNA_material_types.h"
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index 914f1ef5110..79a4c4e3a6b 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -166,6 +166,7 @@ void register_node_type_tex_group(void)
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
+ ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
ntype.ext.srna = RNA_struct_find("TextureNodeGroup");
BLI_assert(ntype.ext.srna != NULL);
diff --git a/source/blender/physics/CMakeLists.txt b/source/blender/physics/CMakeLists.txt
index 08ff1faca49..0a4ff3fe0f0 100644
--- a/source/blender/physics/CMakeLists.txt
+++ b/source/blender/physics/CMakeLists.txt
@@ -31,11 +31,10 @@ set(INC
../imbuf
../makesdna
../../../intern/guardedalloc
- ../../../extern/Eigen3
)
set(INC_SYS
-
+ ${EIGEN3_INCLUDE_DIRS}
)
set(SRC
diff --git a/source/blender/physics/SConscript b/source/blender/physics/SConscript
deleted file mode 100644
index c8165886cab..00000000000
--- a/source/blender/physics/SConscript
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2011, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Jeroen Bakker, Monique Dewanchand, Blender Developers Fund.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-defs = []
-
-sources = env.Glob('intern/*.cpp') + env.Glob('intern/*.c')
-
-incs = [
- '.',
- 'intern',
- '../blenlib',
- '../blenkernel',
- '../imbuf',
- '../makesdna',
- '../../../intern/guardedalloc',
- '../../../extern/Eigen3',
- ]
-
-env.BlenderLib('bf_physics', sources, incs, defines=defs, libtype=['core', 'player'], priority=[180, 190])
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
index 30a8478e0e4..4d114e182c0 100644
--- a/source/blender/physics/intern/BPH_mass_spring.cpp
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -1,1117 +1,1117 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Lukas Toenne
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/physics/intern/BPH_mass_spring.cpp
- * \ingroup bph
- */
-
-extern "C" {
-#include "MEM_guardedalloc.h"
-
-#include "DNA_cloth_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_force.h"
-#include "DNA_object_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-
-#include "BLI_math.h"
-#include "BLI_linklist.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_cloth.h"
-#include "BKE_collision.h"
-#include "BKE_effect.h"
-}
-
-#include "BPH_mass_spring.h"
-#include "implicit.h"
-
-static float I3[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
-
-/* Number of off-diagonal non-zero matrix blocks.
- * Basically there is one of these for each vertex-vertex interaction.
- */
-static int cloth_count_nondiag_blocks(Cloth *cloth)
-{
- LinkNode *link;
- int nondiag = 0;
-
- for (link = cloth->springs; link; link = link->next) {
- ClothSpring *spring = (ClothSpring *)link->link;
- switch (spring->type) {
- case CLOTH_SPRING_TYPE_BENDING_ANG:
- /* angular bending combines 3 vertices */
- nondiag += 3;
- break;
-
- default:
- /* all other springs depend on 2 vertices only */
- nondiag += 1;
- break;
- }
- }
-
- return nondiag;
-}
-
-int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
-{
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts;
- const float ZERO[3] = {0.0f, 0.0f, 0.0f};
- Implicit_Data *id;
- unsigned int i, nondiag;
-
- nondiag = cloth_count_nondiag_blocks(cloth);
- cloth->implicit = id = BPH_mass_spring_solver_create(cloth->mvert_num, nondiag);
-
- for (i = 0; i < cloth->mvert_num; i++) {
- BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
- }
-
- for (i = 0; i < cloth->mvert_num; i++) {
- BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO);
- }
-
- return 1;
-}
-
-void BPH_cloth_solver_free(ClothModifierData *clmd)
-{
- Cloth *cloth = clmd->clothObject;
-
- if (cloth->implicit) {
- BPH_mass_spring_solver_free(cloth->implicit);
- cloth->implicit = NULL;
- }
-}
-
-void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
-{
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts;
- unsigned int mvert_num = cloth->mvert_num, i;
- ClothHairData *cloth_hairdata = clmd->hairdata;
- Implicit_Data *id = cloth->implicit;
-
- for (i = 0; i < mvert_num; i++) {
- if (cloth_hairdata) {
- ClothHairData *root = &cloth_hairdata[i];
- BPH_mass_spring_set_rest_transform(id, i, root->rot);
- }
- else
- BPH_mass_spring_set_rest_transform(id, i, I3);
-
- BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v);
- }
-}
-
-static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3])
-{
- Cloth *cloth = clmd->clothObject;
- int index = collpair->ap1;
- bool result = false;
-
- float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
-
- float margin_distance = (float)collpair->distance - epsilon2;
- float mag_v_rel;
-
- zero_v3(r_impulse);
-
- if (margin_distance > 0.0f)
- return false; /* XXX tested before already? */
-
- /* only handle static collisions here */
- if ( collpair->flag & COLLISION_IN_FUTURE )
- return false;
-
- /* velocity */
- copy_v3_v3(v1, cloth->verts[index].v);
- collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
- /* relative velocity = velocity of the cloth point relative to the collider */
- sub_v3_v3v3(v_rel_old, v1, v2_old);
- sub_v3_v3v3(v_rel_new, v1, v2_new);
- /* normal component of the relative velocity */
- mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
- /* only valid when moving toward the collider */
- if (mag_v_rel < -ALMOST_ZERO) {
- float v_nor_old, v_nor_new;
- float v_tan_old[3], v_tan_new[3];
- float bounce, repulse;
-
- /* Collision response based on
- * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
- * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
- */
-
- v_nor_old = mag_v_rel;
- v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
- madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
- madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
- bounce = -v_nor_old * restitution;
-
- repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
- /* XXX this clamping factor is quite arbitrary ...
- * not sure if there is a more scientific approach, but seems to give good results
- */
- CLAMP(repulse, 0.0f, 4.0f * bounce);
-
- if (margin_distance < -epsilon2) {
- mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
- }
- else {
- bounce = 0.0f;
- mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
- }
-
- result = true;
- }
-
- return result;
-}
-
-/* Init constraint matrix
- * This is part of the modified CG method suggested by Baraff/Witkin in
- * "Large Steps in Cloth Simulation" (Siggraph 1998)
- */
-static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *contacts, int totcolliders, float dt)
-{
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- ClothVertex *verts = cloth->verts;
- int mvert_num = cloth->mvert_num;
- int i, j, v;
-
- const float ZERO[3] = {0.0f, 0.0f, 0.0f};
-
- BPH_mass_spring_clear_constraints(data);
-
- for (v = 0; v < mvert_num; v++) {
- if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
- /* pinned vertex constraints */
- BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */
- }
-
- verts[v].impulse_count = 0;
- }
-
- for (i = 0; i < totcolliders; ++i) {
- ColliderContacts *ct = &contacts[i];
- for (j = 0; j < ct->totcollisions; ++j) {
- CollPair *collpair = &ct->collisions[j];
-// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
- float restitution = 0.0f;
- int v = collpair->face1;
- float impulse[3];
-
- /* pinned verts handled separately */
- if (verts[v].flags & CLOTH_VERT_FLAG_PINNED)
- continue;
-
- /* XXX cheap way of avoiding instability from multiple collisions in the same step
- * this should eventually be supported ...
- */
- if (verts[v].impulse_count > 0)
- continue;
-
- /* calculate collision response */
- if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse))
- continue;
-
- BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
- ++verts[v].impulse_count;
- }
- }
-}
-
-/* computes where the cloth would be if it were subject to perfectly stiff edges
- * (edge distance constraints) in a lagrangian solver. then add forces to help
- * guide the implicit solver to that state. this function is called after
- * collisions*/
-static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
-{
- Cloth *cloth= clmd->clothObject;
- float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, "cos cloth_calc_helper_forces");
- float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, "cos cloth_calc_helper_forces");
- LinkNode *node;
- ClothSpring *spring;
- ClothVertex *cv;
- int i, steps;
-
- cv = cloth->verts;
- for (i = 0; i < cloth->mvert_num; i++, cv++) {
- copy_v3_v3(cos[i], cv->tx);
-
- if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
- masses[i] = 1e+10;
- }
- else {
- masses[i] = cv->mass;
- }
- }
-
- steps = 55;
- for (i=0; i<steps; i++) {
- for (node=cloth->springs; node; node=node->next) {
- /* ClothVertex *cv1, *cv2; */ /* UNUSED */
- int v1, v2;
- float len, c, l, vec[3];
-
- spring = (ClothSpring *)node->link;
- if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
- continue;
-
- v1 = spring->ij; v2 = spring->kl;
- /* cv1 = cloth->verts + v1; */ /* UNUSED */
- /* cv2 = cloth->verts + v2; */ /* UNUSED */
- len = len_v3v3(cos[v1], cos[v2]);
-
- sub_v3_v3v3(vec, cos[v1], cos[v2]);
- normalize_v3(vec);
-
- c = (len - spring->restlen);
- if (c == 0.0f)
- continue;
-
- l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2]));
-
- mul_v3_fl(vec, -(1.0f / masses[v1]) * l);
- add_v3_v3(cos[v1], vec);
-
- sub_v3_v3v3(vec, cos[v2], cos[v1]);
- normalize_v3(vec);
-
- mul_v3_fl(vec, -(1.0f / masses[v2]) * l);
- add_v3_v3(cos[v2], vec);
- }
- }
-
- cv = cloth->verts;
- for (i = 0; i < cloth->mvert_num; i++, cv++) {
- float vec[3];
-
- /*compute forces*/
- sub_v3_v3v3(vec, cos[i], cv->tx);
- mul_v3_fl(vec, cv->mass*dt*20.0f);
- add_v3_v3(cv->tv, vec);
- //copy_v3_v3(cv->tx, cos[i]);
- }
-
- MEM_freeN(cos);
- MEM_freeN(masses);
-
- return 1;
-}
-
-BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time)
-{
- Cloth *cloth = clmd->clothObject;
- ClothSimSettings *parms = clmd->sim_parms;
- Implicit_Data *data = cloth->implicit;
- ClothVertex *verts = cloth->verts;
-
- bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
-
- zero_v3(s->f);
- zero_m3(s->dfdx);
- zero_m3(s->dfdv);
-
- s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
-
- // calculate force of structural + shear springs
- if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
-#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
- k = scaling / (parms->avg_spring_len + FLT_EPSILON);
-
- if (s->type & CLOTH_SPRING_TYPE_SEWING) {
- // TODO: verify, half verified (couldn't see error)
- // sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
- }
- else {
- BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
- }
-#endif
- }
- else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
-#ifdef CLOTH_FORCE_SPRING_GOAL
- float goal_x[3], goal_v[3];
- float k, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- // current_position = xold + t * (newposition - xold)
- interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
- sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
-
- scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
- k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
-
- BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
-#endif
- }
- else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
-#ifdef CLOTH_FORCE_SPRING_BEND
- float kb, cb, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
- kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
- // Fix for [#45084] for cloth stiffness must have cb proportional to kb
- cb = kb * parms->bending_damping;
-
- BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
-#endif
- }
- else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
-#ifdef CLOTH_FORCE_SPRING_BEND
- float kb, cb, scaling;
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- /* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, unlike cloth springs!
- * this is crap, but needed due to cloth/hair mixing ...
- * max_bend factor is not even used for hair, so ...
- */
- scaling = s->stiffness * parms->bending;
- kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
-
- // Fix for [#45084] for cloth stiffness must have cb proportional to kb
- cb = kb * parms->bending_damping;
-
- /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
- BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
-
-#if 0
- {
- float x_kl[3], x_mn[3], v[3], d[3];
-
- BPH_mass_spring_get_motion_state(data, s->kl, x_kl, v);
- BPH_mass_spring_get_motion_state(data, s->mn, x_mn, v);
-
- BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl);
- BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl);
-
- copy_v3_v3(d, s->target);
- BKE_sim_debug_data_add_vector(clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl);
-
-// copy_v3_v3(d, s->target_ij);
-// BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl);
- }
-#endif
-#endif
- }
-}
-
-static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3])
-{
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- unsigned int looptri_num = cloth->tri_num;
- int i;
-
- INIT_MINMAX(gmin, gmax);
- for (i = 0; i < looptri_num; i++) {
- float x[3];
- BPH_mass_spring_get_motion_state(data, i, x, NULL);
- DO_MINMAX(x, gmin, gmax);
- }
-}
-
-static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
-{
- /* Collect forces and derivatives: F, dFdX, dFdV */
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- unsigned int i = 0;
- float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
- float gravity[3] = {0.0f, 0.0f, 0.0f};
- const MVertTri *tri = cloth->tri;
- unsigned int mvert_num = cloth->mvert_num;
- ClothVertex *vert;
-
-#ifdef CLOTH_FORCE_GRAVITY
- /* global acceleration (gravitation) */
- if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- /* scale gravity force */
- mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
- }
- vert = cloth->verts;
- for (i = 0; i < cloth->mvert_num; i++, vert++) {
- BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
- }
-#endif
-
- /* cloth_calc_volume_force(clmd); */
-
-#ifdef CLOTH_FORCE_DRAG
- BPH_mass_spring_force_drag(data, drag);
-#endif
-
- /* handle external forces like wind */
- if (effectors) {
- /* cache per-vertex forces to avoid redundant calculation */
- float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces");
- for (i = 0; i < cloth->mvert_num; i++) {
- float x[3], v[3];
- EffectedPoint epoint;
-
- BPH_mass_spring_get_motion_state(data, i, x, v);
- pd_point_from_loc(clmd->scene, x, v, i, &epoint);
- pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
- }
-
- for (i = 0; i < cloth->tri_num; i++) {
- const MVertTri *vt = &tri[i];
- BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
- }
-
- /* Hair has only edges */
- if (cloth->tri_num == 0) {
-#if 0
- ClothHairData *hairdata = clmd->hairdata;
- ClothHairData *hair_ij, *hair_kl;
-
- for (LinkNode *link = cloth->springs; link; link = link->next) {
- ClothSpring *spring = (ClothSpring *)link->link;
- if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
- if (hairdata) {
- hair_ij = &hairdata[spring->ij];
- hair_kl = &hairdata[spring->kl];
- BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec);
- }
- else
- BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec);
- }
- }
-#else
- ClothHairData *hairdata = clmd->hairdata;
-
- vert = cloth->verts;
- for (i = 0; i < cloth->mvert_num; i++, vert++) {
- if (hairdata) {
- ClothHairData *hair = &hairdata[i];
- BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec);
- }
- else
- BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec);
- }
- }
-#endif
-
- MEM_freeN(winvec);
- }
-
- // calculate spring forces
- for (LinkNode *link = cloth->springs; link; link = link->next) {
- ClothSpring *spring = (ClothSpring *)link->link;
- // only handle active springs
- if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
- cloth_calc_spring_force(clmd, spring, time);
- }
-}
-
-/* returns vertexes' motion state */
-BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, float cell_scale, const float cell_offset[3],
- int index, float x[3], float v[3])
-{
- BPH_mass_spring_get_position(data, index, x);
- BPH_mass_spring_get_new_velocity(data, index, v);
-
- mul_v3_fl(x, cell_scale);
- add_v3_v3(x, cell_offset);
-}
-
-/* returns next spring forming a continous hair sequence */
-BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link)
-{
- ClothSpring *spring = (ClothSpring *)spring_link->link;
- LinkNode *next = spring_link->next;
- if (next) {
- ClothSpring *next_spring = (ClothSpring *)next->link;
- if (next_spring->type == CLOTH_SPRING_TYPE_STRUCTURAL && next_spring->kl == spring->ij)
- return next;
- }
- return NULL;
-}
-
-/* XXX this is nasty: cloth meshes do not explicitly store
- * the order of hair segments!
- * We have to rely on the spring build function for now,
- * which adds structural springs in reverse order:
- * (3,4), (2,3), (1,2)
- * This is currently the only way to figure out hair geometry inside this code ...
- */
-static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float cell_scale, const float cell_offset[3], Cloth *cloth, LinkNode *spring_link)
-{
- Implicit_Data *data = cloth->implicit;
- LinkNode *next_spring_link = NULL; /* return value */
- ClothSpring *spring1, *spring2, *spring3;
- // ClothVertex *verts = cloth->verts;
- // ClothVertex *vert3, *vert4;
- float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3];
- float dir1[3], dir2[3], dir3[3];
-
- spring1 = NULL;
- spring2 = NULL;
- spring3 = (ClothSpring *)spring_link->link;
-
- zero_v3(x1); zero_v3(v1);
- zero_v3(dir1);
- zero_v3(x2); zero_v3(v2);
- zero_v3(dir2);
-
- // vert3 = &verts[spring3->kl];
- cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3);
- // vert4 = &verts[spring3->ij];
- cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
- sub_v3_v3v3(dir3, x4, x3);
- normalize_v3(dir3);
-
- while (spring_link) {
- /* move on */
- spring1 = spring2;
- spring2 = spring3;
-
- // vert3 = vert4;
-
- copy_v3_v3(x1, x2); copy_v3_v3(v1, v2);
- copy_v3_v3(x2, x3); copy_v3_v3(v2, v3);
- copy_v3_v3(x3, x4); copy_v3_v3(v3, v4);
-
- copy_v3_v3(dir1, dir2);
- copy_v3_v3(dir2, dir3);
-
- /* read next segment */
- next_spring_link = spring_link->next;
- spring_link = hair_spring_next(spring_link);
-
- if (spring_link) {
- spring3 = (ClothSpring *)spring_link->link;
- // vert4 = &verts[spring3->ij];
- cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
- sub_v3_v3v3(dir3, x4, x3);
- normalize_v3(dir3);
- }
- else {
- spring3 = NULL;
- // vert4 = NULL;
- zero_v3(x4); zero_v3(v4);
- zero_v3(dir3);
- }
-
- BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4,
- spring1 ? dir1 : NULL,
- dir2,
- spring3 ? dir3 : NULL);
- }
-
- return next_spring_link;
-}
-
-static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
-{
-#if 0
- Implicit_Data *data = cloth->implicit;
- int mvert_num = cloth->mvert_num;
- ClothVertex *vert;
- int i;
-
- for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
- float x[3], v[3];
-
- cloth_get_vertex_motion_state(data, vert, x, v);
- BPH_hair_volume_add_vertex(grid, x, v);
- }
-#else
- LinkNode *link;
- float cellsize, gmin[3], cell_scale, cell_offset[3];
-
- /* scale and offset for transforming vertex locations into grid space
- * (cell size is 0..1, gmin becomes origin)
- */
- BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL);
- cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f;
- mul_v3_v3fl(cell_offset, gmin, cell_scale);
- negate_v3(cell_offset);
-
- link = cloth->springs;
- while (link) {
- ClothSpring *spring = (ClothSpring *)link->link;
- if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
- link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link);
- else
- link = link->next;
- }
-#endif
- BPH_hair_volume_normalize_vertex_grid(grid);
-}
-
-static void cloth_continuum_step(ClothModifierData *clmd, float dt)
-{
- ClothSimSettings *parms = clmd->sim_parms;
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- int mvert_num = cloth->mvert_num;
- ClothVertex *vert;
-
- const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
- float smoothfac = parms->velocity_smooth;
- /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead,
- * like number of hairs per cell and time decay instead of "strength"
- */
- float density_target = parms->density_target;
- float density_strength = parms->density_strength;
- float gmin[3], gmax[3];
- int i;
-
- /* clear grid info */
- zero_v3_int(clmd->hair_grid_res);
- zero_v3(clmd->hair_grid_min);
- zero_v3(clmd->hair_grid_max);
- clmd->hair_grid_cellsize = 0.0f;
-
- hair_get_boundbox(clmd, gmin, gmax);
-
- /* gather velocities & density */
- if (smoothfac > 0.0f || density_strength > 0.0f) {
- HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
-
- cloth_continuum_fill_grid(grid, cloth);
-
- /* main hair continuum solver */
- BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength);
-
- for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
- float x[3], v[3], nv[3];
-
- /* calculate volumetric velocity influence */
- BPH_mass_spring_get_position(data, i, x);
- BPH_mass_spring_get_new_velocity(data, i, v);
-
- BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv);
-
- interp_v3_v3v3(nv, v, nv, smoothfac);
-
- /* apply on hair data */
- BPH_mass_spring_set_new_velocity(data, i, nv);
- }
-
- /* store basic grid info in the modifier data */
- BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max);
-
-#if 0 /* DEBUG hair velocity vector field */
- {
- const int size = 64;
- int i, j;
- float offset[3], a[3], b[3];
- const int axis = 0;
- const float shift = 0.0f;
-
- copy_v3_v3(offset, clmd->hair_grid_min);
- zero_v3(a);
- zero_v3(b);
-
- offset[axis] = shift * clmd->hair_grid_cellsize;
- a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3];
- b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3];
-
- BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
- for (j = 0; j < size; ++j) {
- for (i = 0; i < size; ++i) {
- float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
-
- madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1));
- madd_v3_v3fl(x, b, (float)j / (float)(size-1));
- zero_v3(v);
-
- BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL);
-
-// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111);
- if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) {
- float dvel[3];
- sub_v3_v3v3(dvel, gvel_smooth, gvel);
-// BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel, 0.4, 0, 1, "grid velocity", i, j, 3112);
-// BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, "grid velocity", i, j, 3113);
- BKE_sim_debug_data_add_vector(clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114);
-#if 0
- if (gdensity > 0.0f) {
- float col0[3] = {0.0, 0.0, 0.0};
- float col1[3] = {0.0, 1.0, 0.0};
- float col[3];
-
- interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0));
-// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115);
-// BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115);
- BKE_sim_debug_data_add_circle(clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115);
- }
-#endif
- }
- }
- }
- }
-#endif
-
- BPH_hair_volume_free_vertex_grid(grid);
- }
-}
-
-#if 0
-static void cloth_calc_volume_force(ClothModifierData *clmd)
-{
- ClothSimSettings *parms = clmd->sim_parms;
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *data = cloth->implicit;
- int mvert_num = cloth->mvert_num;
- ClothVertex *vert;
-
- /* 2.0f is an experimental value that seems to give good results */
- float smoothfac = 2.0f * parms->velocity_smooth;
- float collfac = 2.0f * parms->collider_friction;
- float pressfac = parms->pressure;
- float minpress = parms->pressure_threshold;
- float gmin[3], gmax[3];
- int i;
-
- hair_get_boundbox(clmd, gmin, gmax);
-
- /* gather velocities & density */
- if (smoothfac > 0.0f || pressfac > 0.0f) {
- HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
-
- vert = cloth->verts;
- for (i = 0; i < mvert_num; i++, vert++) {
- float x[3], v[3];
-
- if (vert->solver_index < 0) {
- copy_v3_v3(x, vert->x);
- copy_v3_v3(v, vert->v);
- }
- else {
- BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
- }
- BPH_hair_volume_add_vertex(vertex_grid, x, v);
- }
- BPH_hair_volume_normalize_vertex_grid(vertex_grid);
-
- vert = cloth->verts;
- for (i = 0; i < mvert_num; i++, vert++) {
- float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3];
-
- if (vert->solver_index < 0)
- continue;
-
- /* calculate volumetric forces */
- BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
- BPH_hair_volume_vertex_grid_forces(vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv);
- /* apply on hair data */
- BPH_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv);
- }
-
- BPH_hair_volume_free_vertex_grid(vertex_grid);
- }
-}
-#endif
-
-/* old collision stuff for cloth, use for continuity
- * until a good replacement is ready
- */
-static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, ListBase *effectors, float frame, float step, float dt)
-{
- Cloth *cloth = clmd->clothObject;
- Implicit_Data *id = cloth->implicit;
- ClothVertex *verts = cloth->verts;
- int mvert_num = cloth->mvert_num;
- const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
-
- bool do_extra_solve;
- int i;
-
- if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED))
- return;
- if (!clmd->clothObject->bvhtree)
- return;
-
- // update verts to current positions
- for (i = 0; i < mvert_num; i++) {
- BPH_mass_spring_get_new_position(id, i, verts[i].tx);
-
- sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
-#if 0 /* unused */
- for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
- copy_v3_v3(initial_cos[i], cv->tx);
- }
-#endif
-
- // call collision function
- // TODO: check if "step" or "step+dt" is correct - dg
- do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
-
- // copy corrected positions back to simulation
- for (i = 0; i < mvert_num; i++) {
- float curx[3];
- BPH_mass_spring_get_position(id, i, curx);
- // correct velocity again, just to be sure we had to change it due to adaptive collisions
- sub_v3_v3v3(verts[i].tv, verts[i].tx, curx);
- }
-
- if (do_extra_solve) {
-// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
-
- for (i = 0; i < mvert_num; i++) {
-
- float newv[3];
-
- if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
- continue;
-
- BPH_mass_spring_set_new_position(id, i, verts[i].tx);
- mul_v3_v3fl(newv, verts[i].tv, spf);
- BPH_mass_spring_set_new_velocity(id, i, newv);
- }
- }
-
- // X = Xnew;
- BPH_mass_spring_apply_result(id);
-
- if (do_extra_solve) {
- ImplicitSolverResult result;
-
- /* initialize forces to zero */
- BPH_mass_spring_clear_forces(id);
-
- // calculate forces
- cloth_calc_force(clmd, frame, effectors, step);
-
- // calculate new velocity and position
- BPH_mass_spring_solve_velocities(id, dt, &result);
-// cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
-
- /* note: positions are advanced only once in the main solver step! */
-
- BPH_mass_spring_apply_result(id);
- }
-}
-
-static void cloth_clear_result(ClothModifierData *clmd)
-{
- ClothSolverResult *sres = clmd->solver_result;
-
- sres->status = 0;
- sres->max_error = sres->min_error = sres->avg_error = 0.0f;
- sres->max_iterations = sres->min_iterations = 0;
- sres->avg_iterations = 0.0f;
-}
-
-static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps)
-{
- ClothSolverResult *sres = clmd->solver_result;
-
- if (sres->status) { /* already initialized ? */
- /* error only makes sense for successful iterations */
- if (result->status == BPH_SOLVER_SUCCESS) {
- sres->min_error = min_ff(sres->min_error, result->error);
- sres->max_error = max_ff(sres->max_error, result->error);
- sres->avg_error += result->error / (float)steps;
- }
-
- sres->min_iterations = min_ii(sres->min_iterations, result->iterations);
- sres->max_iterations = max_ii(sres->max_iterations, result->iterations);
- sres->avg_iterations += (float)result->iterations / (float)steps;
- }
- else {
- /* error only makes sense for successful iterations */
- if (result->status == BPH_SOLVER_SUCCESS) {
- sres->min_error = sres->max_error = result->error;
- sres->avg_error += result->error / (float)steps;
- }
-
- sres->min_iterations = sres->max_iterations = result->iterations;
- sres->avg_iterations += (float)result->iterations / (float)steps;
- }
-
- sres->status |= result->status;
-}
-
-int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
-{
- /* Hair currently is a cloth sim in disguise ...
- * Collision detection and volumetrics work differently then.
- * Bad design, TODO
- */
- const bool is_hair = (clmd->hairdata != NULL);
-
- unsigned int i=0;
- float step=0.0f, tf=clmd->sim_parms->timescale;
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts/*, *cv*/;
- unsigned int mvert_num = cloth->mvert_num;
- float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
- Implicit_Data *id = cloth->implicit;
- ColliderContacts *contacts = NULL;
- int totcolliders = 0;
-
- BKE_sim_debug_data_clear_category("collision");
-
- if (!clmd->solver_result)
- clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
- cloth_clear_result(clmd);
-
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
- for (i = 0; i < mvert_num; i++) {
- // update velocities with constrained velocities from pinned verts
- if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
- float v[3];
- sub_v3_v3v3(v, verts[i].xconst, verts[i].xold);
- // mul_v3_fl(v, clmd->sim_parms->stepsPerFrame);
- BPH_mass_spring_set_velocity(id, i, v);
- }
- }
- }
-
- while (step < tf) {
- ImplicitSolverResult result;
-
- /* copy velocities for collision */
- for (i = 0; i < mvert_num; i++) {
- BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
- if (is_hair) {
- /* determine contact points */
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
- cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
- }
-
- /* setup vertex constraints for pinned vertices and contacts */
- cloth_setup_constraints(clmd, contacts, totcolliders, dt);
- }
- else {
- /* setup vertex constraints for pinned vertices */
- cloth_setup_constraints(clmd, NULL, 0, dt);
- }
-
- /* initialize forces to zero */
- BPH_mass_spring_clear_forces(id);
-
- // damping velocity for artistic reasons
- // this is a bad way to do it, should be removed imo - lukas_t
- if (clmd->sim_parms->vel_damping != 1.0f) {
- for (i = 0; i < mvert_num; i++) {
- float v[3];
- BPH_mass_spring_get_motion_state(id, i, NULL, v);
- mul_v3_fl(v, clmd->sim_parms->vel_damping);
- BPH_mass_spring_set_velocity(id, i, v);
- }
- }
-
- // calculate forces
- cloth_calc_force(clmd, frame, effectors, step);
-
- // calculate new velocity and position
- BPH_mass_spring_solve_velocities(id, dt, &result);
- cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
-
- if (is_hair) {
- cloth_continuum_step(clmd, dt);
- }
-
- BPH_mass_spring_solve_positions(id, dt);
-
- if (!is_hair) {
- cloth_collision_solve_extra(ob, clmd, effectors, frame, step, dt);
- }
-
- BPH_mass_spring_apply_result(id);
-
- /* move pinned verts to correct position */
- for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
- if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
- float x[3];
- interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
- BPH_mass_spring_set_position(id, i, x);
- }
- }
-
- BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
- }
-
- /* free contact points */
- if (contacts) {
- cloth_free_contacts(contacts, totcolliders);
- }
-
- step += dt;
- }
-
- /* copy results back to cloth data */
- for (i = 0; i < mvert_num; i++) {
- BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
- copy_v3_v3(verts[i].txold, verts[i].x);
- }
-
- return 1;
-}
-
-bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, VoxelData *vd)
-{
- Cloth *cloth = clmd->clothObject;
- HairGrid *grid;
- float gmin[3], gmax[3];
-
- if (!clmd->clothObject || !clmd->clothObject->implicit)
- return false;
-
- hair_get_boundbox(clmd, gmin, gmax);
-
- grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
- cloth_continuum_fill_grid(grid, cloth);
-
- BPH_hair_volume_get_texture_data(grid, vd);
-
- BPH_hair_volume_free_vertex_grid(grid);
-
- return true;
-}
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/physics/intern/BPH_mass_spring.cpp
+ * \ingroup bph
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cloth_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cloth.h"
+#include "BKE_collision.h"
+#include "BKE_effect.h"
+}
+
+#include "BPH_mass_spring.h"
+#include "implicit.h"
+
+static float I3[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
+
+/* Number of off-diagonal non-zero matrix blocks.
+ * Basically there is one of these for each vertex-vertex interaction.
+ */
+static int cloth_count_nondiag_blocks(Cloth *cloth)
+{
+ LinkNode *link;
+ int nondiag = 0;
+
+ for (link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ switch (spring->type) {
+ case CLOTH_SPRING_TYPE_BENDING_ANG:
+ /* angular bending combines 3 vertices */
+ nondiag += 3;
+ break;
+
+ default:
+ /* all other springs depend on 2 vertices only */
+ nondiag += 1;
+ break;
+ }
+ }
+
+ return nondiag;
+}
+
+int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts;
+ const float ZERO[3] = {0.0f, 0.0f, 0.0f};
+ Implicit_Data *id;
+ unsigned int i, nondiag;
+
+ nondiag = cloth_count_nondiag_blocks(cloth);
+ cloth->implicit = id = BPH_mass_spring_solver_create(cloth->mvert_num, nondiag);
+
+ for (i = 0; i < cloth->mvert_num; i++) {
+ BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
+ }
+
+ for (i = 0; i < cloth->mvert_num; i++) {
+ BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO);
+ }
+
+ return 1;
+}
+
+void BPH_cloth_solver_free(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+
+ if (cloth->implicit) {
+ BPH_mass_spring_solver_free(cloth->implicit);
+ cloth->implicit = NULL;
+ }
+}
+
+void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts;
+ unsigned int mvert_num = cloth->mvert_num, i;
+ ClothHairData *cloth_hairdata = clmd->hairdata;
+ Implicit_Data *id = cloth->implicit;
+
+ for (i = 0; i < mvert_num; i++) {
+ if (cloth_hairdata) {
+ ClothHairData *root = &cloth_hairdata[i];
+ BPH_mass_spring_set_rest_transform(id, i, root->rot);
+ }
+ else
+ BPH_mass_spring_set_rest_transform(id, i, I3);
+
+ BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v);
+ }
+}
+
+static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3])
+{
+ Cloth *cloth = clmd->clothObject;
+ int index = collpair->ap1;
+ bool result = false;
+
+ float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
+ float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
+
+ float margin_distance = (float)collpair->distance - epsilon2;
+ float mag_v_rel;
+
+ zero_v3(r_impulse);
+
+ if (margin_distance > 0.0f)
+ return false; /* XXX tested before already? */
+
+ /* only handle static collisions here */
+ if ( collpair->flag & COLLISION_IN_FUTURE )
+ return false;
+
+ /* velocity */
+ copy_v3_v3(v1, cloth->verts[index].v);
+ collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
+ /* relative velocity = velocity of the cloth point relative to the collider */
+ sub_v3_v3v3(v_rel_old, v1, v2_old);
+ sub_v3_v3v3(v_rel_new, v1, v2_new);
+ /* normal component of the relative velocity */
+ mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
+
+ /* only valid when moving toward the collider */
+ if (mag_v_rel < -ALMOST_ZERO) {
+ float v_nor_old, v_nor_new;
+ float v_tan_old[3], v_tan_new[3];
+ float bounce, repulse;
+
+ /* Collision response based on
+ * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
+ * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
+ */
+
+ v_nor_old = mag_v_rel;
+ v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
+
+ madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
+ madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
+
+ bounce = -v_nor_old * restitution;
+
+ repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
+ /* XXX this clamping factor is quite arbitrary ...
+ * not sure if there is a more scientific approach, but seems to give good results
+ */
+ CLAMP(repulse, 0.0f, 4.0f * bounce);
+
+ if (margin_distance < -epsilon2) {
+ mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
+ }
+ else {
+ bounce = 0.0f;
+ mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
+ }
+
+ result = true;
+ }
+
+ return result;
+}
+
+/* Init constraint matrix
+ * This is part of the modified CG method suggested by Baraff/Witkin in
+ * "Large Steps in Cloth Simulation" (Siggraph 1998)
+ */
+static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *contacts, int totcolliders, float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+ int mvert_num = cloth->mvert_num;
+ int i, j, v;
+
+ const float ZERO[3] = {0.0f, 0.0f, 0.0f};
+
+ BPH_mass_spring_clear_constraints(data);
+
+ for (v = 0; v < mvert_num; v++) {
+ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
+ /* pinned vertex constraints */
+ BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */
+ }
+
+ verts[v].impulse_count = 0;
+ }
+
+ for (i = 0; i < totcolliders; ++i) {
+ ColliderContacts *ct = &contacts[i];
+ for (j = 0; j < ct->totcollisions; ++j) {
+ CollPair *collpair = &ct->collisions[j];
+// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
+ float restitution = 0.0f;
+ int v = collpair->face1;
+ float impulse[3];
+
+ /* pinned verts handled separately */
+ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED)
+ continue;
+
+ /* XXX cheap way of avoiding instability from multiple collisions in the same step
+ * this should eventually be supported ...
+ */
+ if (verts[v].impulse_count > 0)
+ continue;
+
+ /* calculate collision response */
+ if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse))
+ continue;
+
+ BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
+ ++verts[v].impulse_count;
+ }
+ }
+}
+
+/* computes where the cloth would be if it were subject to perfectly stiff edges
+ * (edge distance constraints) in a lagrangian solver. then add forces to help
+ * guide the implicit solver to that state. this function is called after
+ * collisions*/
+static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
+{
+ Cloth *cloth= clmd->clothObject;
+ float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, "cos cloth_calc_helper_forces");
+ float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, "cos cloth_calc_helper_forces");
+ LinkNode *node;
+ ClothSpring *spring;
+ ClothVertex *cv;
+ int i, steps;
+
+ cv = cloth->verts;
+ for (i = 0; i < cloth->mvert_num; i++, cv++) {
+ copy_v3_v3(cos[i], cv->tx);
+
+ if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
+ masses[i] = 1e+10;
+ }
+ else {
+ masses[i] = cv->mass;
+ }
+ }
+
+ steps = 55;
+ for (i=0; i<steps; i++) {
+ for (node=cloth->springs; node; node=node->next) {
+ /* ClothVertex *cv1, *cv2; */ /* UNUSED */
+ int v1, v2;
+ float len, c, l, vec[3];
+
+ spring = (ClothSpring *)node->link;
+ if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
+ continue;
+
+ v1 = spring->ij; v2 = spring->kl;
+ /* cv1 = cloth->verts + v1; */ /* UNUSED */
+ /* cv2 = cloth->verts + v2; */ /* UNUSED */
+ len = len_v3v3(cos[v1], cos[v2]);
+
+ sub_v3_v3v3(vec, cos[v1], cos[v2]);
+ normalize_v3(vec);
+
+ c = (len - spring->restlen);
+ if (c == 0.0f)
+ continue;
+
+ l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2]));
+
+ mul_v3_fl(vec, -(1.0f / masses[v1]) * l);
+ add_v3_v3(cos[v1], vec);
+
+ sub_v3_v3v3(vec, cos[v2], cos[v1]);
+ normalize_v3(vec);
+
+ mul_v3_fl(vec, -(1.0f / masses[v2]) * l);
+ add_v3_v3(cos[v2], vec);
+ }
+ }
+
+ cv = cloth->verts;
+ for (i = 0; i < cloth->mvert_num; i++, cv++) {
+ float vec[3];
+
+ /*compute forces*/
+ sub_v3_v3v3(vec, cos[i], cv->tx);
+ mul_v3_fl(vec, cv->mass*dt*20.0f);
+ add_v3_v3(cv->tv, vec);
+ //copy_v3_v3(cv->tx, cos[i]);
+ }
+
+ MEM_freeN(cos);
+ MEM_freeN(masses);
+
+ return 1;
+}
+
+BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothSimSettings *parms = clmd->sim_parms;
+ Implicit_Data *data = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+
+ bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+
+ zero_v3(s->f);
+ zero_m3(s->dfdx);
+ zero_m3(s->dfdv);
+
+ s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
+
+ // calculate force of structural + shear springs
+ if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
+#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
+ k = scaling / (parms->avg_spring_len + FLT_EPSILON);
+
+ if (s->type & CLOTH_SPRING_TYPE_SEWING) {
+ // TODO: verify, half verified (couldn't see error)
+ // sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
+ }
+ else {
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
+ }
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
+#ifdef CLOTH_FORCE_SPRING_GOAL
+ float goal_x[3], goal_v[3];
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ // current_position = xold + t * (newposition - xold)
+ interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
+ sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
+
+ scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
+ k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
+#ifdef CLOTH_FORCE_SPRING_BEND
+ float kb, cb, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
+ kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ // Fix for [#45084] for cloth stiffness must have cb proportional to kb
+ cb = kb * parms->bending_damping;
+
+ BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
+#ifdef CLOTH_FORCE_SPRING_BEND
+ float kb, cb, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ /* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, unlike cloth springs!
+ * this is crap, but needed due to cloth/hair mixing ...
+ * max_bend factor is not even used for hair, so ...
+ */
+ scaling = s->stiffness * parms->bending;
+ kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ // Fix for [#45084] for cloth stiffness must have cb proportional to kb
+ cb = kb * parms->bending_damping;
+
+ /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
+ BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
+
+#if 0
+ {
+ float x_kl[3], x_mn[3], v[3], d[3];
+
+ BPH_mass_spring_get_motion_state(data, s->kl, x_kl, v);
+ BPH_mass_spring_get_motion_state(data, s->mn, x_mn, v);
+
+ BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl);
+ BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl);
+
+ copy_v3_v3(d, s->target);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl);
+
+// copy_v3_v3(d, s->target_ij);
+// BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl);
+ }
+#endif
+#endif
+ }
+}
+
+static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3])
+{
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ unsigned int mvert_num = cloth->mvert_num;
+ int i;
+
+ INIT_MINMAX(gmin, gmax);
+ for (i = 0; i < mvert_num; i++) {
+ float x[3];
+ BPH_mass_spring_get_motion_state(data, i, x, NULL);
+ DO_MINMAX(x, gmin, gmax);
+ }
+}
+
+static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
+{
+ /* Collect forces and derivatives: F, dFdX, dFdV */
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ unsigned int i = 0;
+ float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
+ float gravity[3] = {0.0f, 0.0f, 0.0f};
+ const MVertTri *tri = cloth->tri;
+ unsigned int mvert_num = cloth->mvert_num;
+ ClothVertex *vert;
+
+#ifdef CLOTH_FORCE_GRAVITY
+ /* global acceleration (gravitation) */
+ if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ /* scale gravity force */
+ mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
+ }
+ vert = cloth->verts;
+ for (i = 0; i < cloth->mvert_num; i++, vert++) {
+ BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
+ }
+#endif
+
+ /* cloth_calc_volume_force(clmd); */
+
+#ifdef CLOTH_FORCE_DRAG
+ BPH_mass_spring_force_drag(data, drag);
+#endif
+
+ /* handle external forces like wind */
+ if (effectors) {
+ /* cache per-vertex forces to avoid redundant calculation */
+ float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces");
+ for (i = 0; i < cloth->mvert_num; i++) {
+ float x[3], v[3];
+ EffectedPoint epoint;
+
+ BPH_mass_spring_get_motion_state(data, i, x, v);
+ pd_point_from_loc(clmd->scene, x, v, i, &epoint);
+ pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
+ }
+
+ for (i = 0; i < cloth->tri_num; i++) {
+ const MVertTri *vt = &tri[i];
+ BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec);
+ }
+
+ /* Hair has only edges */
+ if (cloth->tri_num == 0) {
+#if 0
+ ClothHairData *hairdata = clmd->hairdata;
+ ClothHairData *hair_ij, *hair_kl;
+
+ for (LinkNode *link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
+ if (hairdata) {
+ hair_ij = &hairdata[spring->ij];
+ hair_kl = &hairdata[spring->kl];
+ BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec);
+ }
+ else
+ BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec);
+ }
+ }
+#else
+ ClothHairData *hairdata = clmd->hairdata;
+
+ vert = cloth->verts;
+ for (i = 0; i < cloth->mvert_num; i++, vert++) {
+ if (hairdata) {
+ ClothHairData *hair = &hairdata[i];
+ BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec);
+ }
+ else
+ BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec);
+ }
+ }
+#endif
+
+ MEM_freeN(winvec);
+ }
+
+ // calculate spring forces
+ for (LinkNode *link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ // only handle active springs
+ if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
+ cloth_calc_spring_force(clmd, spring, time);
+ }
+}
+
+/* returns vertexes' motion state */
+BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, float cell_scale, const float cell_offset[3],
+ int index, float x[3], float v[3])
+{
+ BPH_mass_spring_get_position(data, index, x);
+ BPH_mass_spring_get_new_velocity(data, index, v);
+
+ mul_v3_fl(x, cell_scale);
+ add_v3_v3(x, cell_offset);
+}
+
+/* returns next spring forming a continous hair sequence */
+BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link)
+{
+ ClothSpring *spring = (ClothSpring *)spring_link->link;
+ LinkNode *next = spring_link->next;
+ if (next) {
+ ClothSpring *next_spring = (ClothSpring *)next->link;
+ if (next_spring->type == CLOTH_SPRING_TYPE_STRUCTURAL && next_spring->kl == spring->ij)
+ return next;
+ }
+ return NULL;
+}
+
+/* XXX this is nasty: cloth meshes do not explicitly store
+ * the order of hair segments!
+ * We have to rely on the spring build function for now,
+ * which adds structural springs in reverse order:
+ * (3,4), (2,3), (1,2)
+ * This is currently the only way to figure out hair geometry inside this code ...
+ */
+static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float cell_scale, const float cell_offset[3], Cloth *cloth, LinkNode *spring_link)
+{
+ Implicit_Data *data = cloth->implicit;
+ LinkNode *next_spring_link = NULL; /* return value */
+ ClothSpring *spring1, *spring2, *spring3;
+ // ClothVertex *verts = cloth->verts;
+ // ClothVertex *vert3, *vert4;
+ float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3];
+ float dir1[3], dir2[3], dir3[3];
+
+ spring1 = NULL;
+ spring2 = NULL;
+ spring3 = (ClothSpring *)spring_link->link;
+
+ zero_v3(x1); zero_v3(v1);
+ zero_v3(dir1);
+ zero_v3(x2); zero_v3(v2);
+ zero_v3(dir2);
+
+ // vert3 = &verts[spring3->kl];
+ cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3);
+ // vert4 = &verts[spring3->ij];
+ cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
+ sub_v3_v3v3(dir3, x4, x3);
+ normalize_v3(dir3);
+
+ while (spring_link) {
+ /* move on */
+ spring1 = spring2;
+ spring2 = spring3;
+
+ // vert3 = vert4;
+
+ copy_v3_v3(x1, x2); copy_v3_v3(v1, v2);
+ copy_v3_v3(x2, x3); copy_v3_v3(v2, v3);
+ copy_v3_v3(x3, x4); copy_v3_v3(v3, v4);
+
+ copy_v3_v3(dir1, dir2);
+ copy_v3_v3(dir2, dir3);
+
+ /* read next segment */
+ next_spring_link = spring_link->next;
+ spring_link = hair_spring_next(spring_link);
+
+ if (spring_link) {
+ spring3 = (ClothSpring *)spring_link->link;
+ // vert4 = &verts[spring3->ij];
+ cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
+ sub_v3_v3v3(dir3, x4, x3);
+ normalize_v3(dir3);
+ }
+ else {
+ spring3 = NULL;
+ // vert4 = NULL;
+ zero_v3(x4); zero_v3(v4);
+ zero_v3(dir3);
+ }
+
+ BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4,
+ spring1 ? dir1 : NULL,
+ dir2,
+ spring3 ? dir3 : NULL);
+ }
+
+ return next_spring_link;
+}
+
+static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
+{
+#if 0
+ Implicit_Data *data = cloth->implicit;
+ int mvert_num = cloth->mvert_num;
+ ClothVertex *vert;
+ int i;
+
+ for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
+ float x[3], v[3];
+
+ cloth_get_vertex_motion_state(data, vert, x, v);
+ BPH_hair_volume_add_vertex(grid, x, v);
+ }
+#else
+ LinkNode *link;
+ float cellsize, gmin[3], cell_scale, cell_offset[3];
+
+ /* scale and offset for transforming vertex locations into grid space
+ * (cell size is 0..1, gmin becomes origin)
+ */
+ BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL);
+ cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f;
+ mul_v3_v3fl(cell_offset, gmin, cell_scale);
+ negate_v3(cell_offset);
+
+ link = cloth->springs;
+ while (link) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
+ link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link);
+ else
+ link = link->next;
+ }
+#endif
+ BPH_hair_volume_normalize_vertex_grid(grid);
+}
+
+static void cloth_continuum_step(ClothModifierData *clmd, float dt)
+{
+ ClothSimSettings *parms = clmd->sim_parms;
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ int mvert_num = cloth->mvert_num;
+ ClothVertex *vert;
+
+ const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
+ float smoothfac = parms->velocity_smooth;
+ /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead,
+ * like number of hairs per cell and time decay instead of "strength"
+ */
+ float density_target = parms->density_target;
+ float density_strength = parms->density_strength;
+ float gmin[3], gmax[3];
+ int i;
+
+ /* clear grid info */
+ zero_v3_int(clmd->hair_grid_res);
+ zero_v3(clmd->hair_grid_min);
+ zero_v3(clmd->hair_grid_max);
+ clmd->hair_grid_cellsize = 0.0f;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ /* gather velocities & density */
+ if (smoothfac > 0.0f || density_strength > 0.0f) {
+ HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
+
+ cloth_continuum_fill_grid(grid, cloth);
+
+ /* main hair continuum solver */
+ BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength);
+
+ for (i = 0, vert = cloth->verts; i < mvert_num; i++, vert++) {
+ float x[3], v[3], nv[3];
+
+ /* calculate volumetric velocity influence */
+ BPH_mass_spring_get_position(data, i, x);
+ BPH_mass_spring_get_new_velocity(data, i, v);
+
+ BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv);
+
+ interp_v3_v3v3(nv, v, nv, smoothfac);
+
+ /* apply on hair data */
+ BPH_mass_spring_set_new_velocity(data, i, nv);
+ }
+
+ /* store basic grid info in the modifier data */
+ BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max);
+
+#if 0 /* DEBUG hair velocity vector field */
+ {
+ const int size = 64;
+ int i, j;
+ float offset[3], a[3], b[3];
+ const int axis = 0;
+ const float shift = 0.0f;
+
+ copy_v3_v3(offset, clmd->hair_grid_min);
+ zero_v3(a);
+ zero_v3(b);
+
+ offset[axis] = shift * clmd->hair_grid_cellsize;
+ a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3];
+ b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3];
+
+ BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
+ for (j = 0; j < size; ++j) {
+ for (i = 0; i < size; ++i) {
+ float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
+
+ madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1));
+ madd_v3_v3fl(x, b, (float)j / (float)(size-1));
+ zero_v3(v);
+
+ BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL);
+
+// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111);
+ if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) {
+ float dvel[3];
+ sub_v3_v3v3(dvel, gvel_smooth, gvel);
+// BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel, 0.4, 0, 1, "grid velocity", i, j, 3112);
+// BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, "grid velocity", i, j, 3113);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114);
+#if 0
+ if (gdensity > 0.0f) {
+ float col0[3] = {0.0, 0.0, 0.0};
+ float col1[3] = {0.0, 1.0, 0.0};
+ float col[3];
+
+ interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0));
+// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115);
+// BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115);
+ BKE_sim_debug_data_add_circle(clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115);
+ }
+#endif
+ }
+ }
+ }
+ }
+#endif
+
+ BPH_hair_volume_free_vertex_grid(grid);
+ }
+}
+
+#if 0
+static void cloth_calc_volume_force(ClothModifierData *clmd)
+{
+ ClothSimSettings *parms = clmd->sim_parms;
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ int mvert_num = cloth->mvert_num;
+ ClothVertex *vert;
+
+ /* 2.0f is an experimental value that seems to give good results */
+ float smoothfac = 2.0f * parms->velocity_smooth;
+ float collfac = 2.0f * parms->collider_friction;
+ float pressfac = parms->pressure;
+ float minpress = parms->pressure_threshold;
+ float gmin[3], gmax[3];
+ int i;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ /* gather velocities & density */
+ if (smoothfac > 0.0f || pressfac > 0.0f) {
+ HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
+
+ vert = cloth->verts;
+ for (i = 0; i < mvert_num; i++, vert++) {
+ float x[3], v[3];
+
+ if (vert->solver_index < 0) {
+ copy_v3_v3(x, vert->x);
+ copy_v3_v3(v, vert->v);
+ }
+ else {
+ BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
+ }
+ BPH_hair_volume_add_vertex(vertex_grid, x, v);
+ }
+ BPH_hair_volume_normalize_vertex_grid(vertex_grid);
+
+ vert = cloth->verts;
+ for (i = 0; i < mvert_num; i++, vert++) {
+ float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3];
+
+ if (vert->solver_index < 0)
+ continue;
+
+ /* calculate volumetric forces */
+ BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
+ BPH_hair_volume_vertex_grid_forces(vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv);
+ /* apply on hair data */
+ BPH_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv);
+ }
+
+ BPH_hair_volume_free_vertex_grid(vertex_grid);
+ }
+}
+#endif
+
+/* old collision stuff for cloth, use for continuity
+ * until a good replacement is ready
+ */
+static void cloth_collision_solve_extra(Object *ob, ClothModifierData *clmd, ListBase *effectors, float frame, float step, float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *id = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+ int mvert_num = cloth->mvert_num;
+ const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
+
+ bool do_extra_solve;
+ int i;
+
+ if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED))
+ return;
+ if (!clmd->clothObject->bvhtree)
+ return;
+
+ // update verts to current positions
+ for (i = 0; i < mvert_num; i++) {
+ BPH_mass_spring_get_new_position(id, i, verts[i].tx);
+
+ sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
+ copy_v3_v3(verts[i].v, verts[i].tv);
+ }
+
+#if 0 /* unused */
+ for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
+ copy_v3_v3(initial_cos[i], cv->tx);
+ }
+#endif
+
+ // call collision function
+ // TODO: check if "step" or "step+dt" is correct - dg
+ do_extra_solve = cloth_bvh_objcollision(ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
+
+ // copy corrected positions back to simulation
+ for (i = 0; i < mvert_num; i++) {
+ float curx[3];
+ BPH_mass_spring_get_position(id, i, curx);
+ // correct velocity again, just to be sure we had to change it due to adaptive collisions
+ sub_v3_v3v3(verts[i].tv, verts[i].tx, curx);
+ }
+
+ if (do_extra_solve) {
+// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
+
+ for (i = 0; i < mvert_num; i++) {
+
+ float newv[3];
+
+ if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
+ continue;
+
+ BPH_mass_spring_set_new_position(id, i, verts[i].tx);
+ mul_v3_v3fl(newv, verts[i].tv, spf);
+ BPH_mass_spring_set_new_velocity(id, i, newv);
+ }
+ }
+
+ // X = Xnew;
+ BPH_mass_spring_apply_result(id);
+
+ if (do_extra_solve) {
+ ImplicitSolverResult result;
+
+ /* initialize forces to zero */
+ BPH_mass_spring_clear_forces(id);
+
+ // calculate forces
+ cloth_calc_force(clmd, frame, effectors, step);
+
+ // calculate new velocity and position
+ BPH_mass_spring_solve_velocities(id, dt, &result);
+// cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
+
+ /* note: positions are advanced only once in the main solver step! */
+
+ BPH_mass_spring_apply_result(id);
+ }
+}
+
+static void cloth_clear_result(ClothModifierData *clmd)
+{
+ ClothSolverResult *sres = clmd->solver_result;
+
+ sres->status = 0;
+ sres->max_error = sres->min_error = sres->avg_error = 0.0f;
+ sres->max_iterations = sres->min_iterations = 0;
+ sres->avg_iterations = 0.0f;
+}
+
+static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps)
+{
+ ClothSolverResult *sres = clmd->solver_result;
+
+ if (sres->status) { /* already initialized ? */
+ /* error only makes sense for successful iterations */
+ if (result->status == BPH_SOLVER_SUCCESS) {
+ sres->min_error = min_ff(sres->min_error, result->error);
+ sres->max_error = max_ff(sres->max_error, result->error);
+ sres->avg_error += result->error / (float)steps;
+ }
+
+ sres->min_iterations = min_ii(sres->min_iterations, result->iterations);
+ sres->max_iterations = max_ii(sres->max_iterations, result->iterations);
+ sres->avg_iterations += (float)result->iterations / (float)steps;
+ }
+ else {
+ /* error only makes sense for successful iterations */
+ if (result->status == BPH_SOLVER_SUCCESS) {
+ sres->min_error = sres->max_error = result->error;
+ sres->avg_error += result->error / (float)steps;
+ }
+
+ sres->min_iterations = sres->max_iterations = result->iterations;
+ sres->avg_iterations += (float)result->iterations / (float)steps;
+ }
+
+ sres->status |= result->status;
+}
+
+int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
+{
+ /* Hair currently is a cloth sim in disguise ...
+ * Collision detection and volumetrics work differently then.
+ * Bad design, TODO
+ */
+ const bool is_hair = (clmd->hairdata != NULL);
+
+ unsigned int i=0;
+ float step=0.0f, tf=clmd->sim_parms->timescale;
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts/*, *cv*/;
+ unsigned int mvert_num = cloth->mvert_num;
+ float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
+ Implicit_Data *id = cloth->implicit;
+ ColliderContacts *contacts = NULL;
+ int totcolliders = 0;
+
+ BKE_sim_debug_data_clear_category("collision");
+
+ if (!clmd->solver_result)
+ clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
+ cloth_clear_result(clmd);
+
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
+ for (i = 0; i < mvert_num; i++) {
+ // update velocities with constrained velocities from pinned verts
+ if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
+ float v[3];
+ sub_v3_v3v3(v, verts[i].xconst, verts[i].xold);
+ // mul_v3_fl(v, clmd->sim_parms->stepsPerFrame);
+ BPH_mass_spring_set_velocity(id, i, v);
+ }
+ }
+ }
+
+ while (step < tf) {
+ ImplicitSolverResult result;
+
+ /* copy velocities for collision */
+ for (i = 0; i < mvert_num; i++) {
+ BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
+ copy_v3_v3(verts[i].v, verts[i].tv);
+ }
+
+ if (is_hair) {
+ /* determine contact points */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
+ }
+
+ /* setup vertex constraints for pinned vertices and contacts */
+ cloth_setup_constraints(clmd, contacts, totcolliders, dt);
+ }
+ else {
+ /* setup vertex constraints for pinned vertices */
+ cloth_setup_constraints(clmd, NULL, 0, dt);
+ }
+
+ /* initialize forces to zero */
+ BPH_mass_spring_clear_forces(id);
+
+ // damping velocity for artistic reasons
+ // this is a bad way to do it, should be removed imo - lukas_t
+ if (clmd->sim_parms->vel_damping != 1.0f) {
+ for (i = 0; i < mvert_num; i++) {
+ float v[3];
+ BPH_mass_spring_get_motion_state(id, i, NULL, v);
+ mul_v3_fl(v, clmd->sim_parms->vel_damping);
+ BPH_mass_spring_set_velocity(id, i, v);
+ }
+ }
+
+ // calculate forces
+ cloth_calc_force(clmd, frame, effectors, step);
+
+ // calculate new velocity and position
+ BPH_mass_spring_solve_velocities(id, dt, &result);
+ cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
+
+ if (is_hair) {
+ cloth_continuum_step(clmd, dt);
+ }
+
+ BPH_mass_spring_solve_positions(id, dt);
+
+ if (!is_hair) {
+ cloth_collision_solve_extra(ob, clmd, effectors, frame, step, dt);
+ }
+
+ BPH_mass_spring_apply_result(id);
+
+ /* move pinned verts to correct position */
+ for (i = 0; i < mvert_num; i++) {
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
+ float x[3];
+ interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
+ BPH_mass_spring_set_position(id, i, x);
+ }
+ }
+
+ BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
+ }
+
+ /* free contact points */
+ if (contacts) {
+ cloth_free_contacts(contacts, totcolliders);
+ }
+
+ step += dt;
+ }
+
+ /* copy results back to cloth data */
+ for (i = 0; i < mvert_num; i++) {
+ BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
+ copy_v3_v3(verts[i].txold, verts[i].x);
+ }
+
+ return 1;
+}
+
+bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, VoxelData *vd)
+{
+ Cloth *cloth = clmd->clothObject;
+ HairGrid *grid;
+ float gmin[3], gmax[3];
+
+ if (!clmd->clothObject || !clmd->clothObject->implicit)
+ return false;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
+ cloth_continuum_fill_grid(grid, cloth);
+
+ BPH_hair_volume_get_texture_data(grid, vd);
+
+ BPH_hair_volume_free_vertex_grid(grid);
+
+ return true;
+}
diff --git a/source/blender/physics/intern/ConstrainedConjugateGradient.h b/source/blender/physics/intern/ConstrainedConjugateGradient.h
index 2d4389f6766..f9c6931fe8c 100644
--- a/source/blender/physics/intern/ConstrainedConjugateGradient.h
+++ b/source/blender/physics/intern/ConstrainedConjugateGradient.h
@@ -1,6 +1,6 @@
-#ifndef EIGEN_CONSTRAINEDCG_H
-#define EIGEN_CONSTRAINEDCG_H
+#ifndef __CONSTRAINEDCONJUGATEGRADIENT_H__
+#define __CONSTRAINEDCONJUGATEGRADIENT_H__
#include <Eigen/Core>
@@ -291,4 +291,4 @@ struct solve_retval<ConstrainedConjugateGradient<_MatrixType,_UpLo,_Filter,_Prec
} // end namespace Eigen
-#endif // EIGEN_CONSTRAINEDCG_H
+#endif // __CONSTRAINEDCONJUGATEGRADIENT_H__
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
index 0fd2a1f35cc..832d516b839 100644
--- a/source/blender/physics/intern/implicit_blender.c
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -60,55 +60,11 @@
# define CLOTH_OPENMP_LIMIT 512
#endif
-#if 0 /* debug timing */
-#ifdef _WIN32
-#include <windows.h>
-static LARGE_INTEGER _itstart, _itend;
-static LARGE_INTEGER ifreq;
-static void itstart(void)
-{
- static int first = 1;
- if (first) {
- QueryPerformanceFrequency(&ifreq);
- first = 0;
- }
- QueryPerformanceCounter(&_itstart);
-}
-static void itend(void)
-{
- QueryPerformanceCounter(&_itend);
-}
-double itval(void)
-{
- return ((double)_itend.QuadPart -
- (double)_itstart.QuadPart)/((double)ifreq.QuadPart);
-}
-#else
-#include <sys/time.h>
-// intrinsics need better compile flag checking
-// #include <xmmintrin.h>
-// #include <pmmintrin.h>
-// #include <pthread.h>
+//#define DEBUG_TIME
-static struct timeval _itstart, _itend;
-static struct timezone itz;
-static void itstart(void)
-{
- gettimeofday(&_itstart, &itz);
-}
-static void itend(void)
-{
- gettimeofday(&_itend, &itz);
-}
-static double itval(void)
-{
- double t1, t2;
- t1 = (double)_itstart.tv_sec + (double)_itstart.tv_usec/(1000*1000);
- t2 = (double)_itend.tv_sec + (double)_itend.tv_usec/(1000*1000);
- return t2-t1;
-}
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
#endif
-#endif /* debug timing */
static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
@@ -989,7 +945,9 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
delta0 = deltaNew * sqrt(conjgrad_epsilon);
- // itstart();
+#ifdef DEBUG_TIME
+ double start = PIL_check_seconds_timer();
+#endif
while ((deltaNew > delta0) && (iterations < conjgrad_looplimit))
{
@@ -1016,9 +974,11 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
filter(p, S);
}
-
- // itend();
- // printf("cg_filtered_pre time: %f\n", (float)itval());
+
+#ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+ printf("cg_filtered_pre time: %f\n", (float)(end - start));
+#endif
del_lfvector(h);
del_lfvector(s);
@@ -1087,8 +1047,10 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
delta0 = deltaNew * sqrt(conjgrad_epsilon);
*/
-
- // itstart();
+
+#ifdef DEBUG_TIME
+ double start = PIL_check_seconds_timer();
+#endif
tol = (0.01*0.2);
@@ -1117,10 +1079,12 @@ static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector
filter(p, S);
}
-
- // itend();
- // printf("cg_filtered_pre time: %f\n", (float)itval());
-
+
+#ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+ printf("cg_filtered_pre time: %f\n", (float)(end - start));
+#endif
+
del_lfvector(btemp);
del_lfvector(bhat);
del_lfvector(h);
@@ -1149,13 +1113,17 @@ bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSol
add_lfvectorS_lfvectorS(data->B, data->F, dt, dFdXmV, (dt*dt), numverts);
- // itstart();
+#ifdef DEBUG_TIME
+ double start = PIL_check_seconds_timer();
+#endif
cg_filtered(data->dV, data->A, data->B, data->z, data->S, result); /* conjugate gradient algorithm to solve Ax=b */
// cg_filtered_pre(id->dV, id->A, id->B, id->z, id->S, id->P, id->Pinv, id->bigI);
- // itend();
- // printf("cg_filtered calc time: %f\n", (float)itval());
+#ifdef DEBUG_TIME
+ double end = PIL_check_seconds_timer();
+ printf("cg_filtered calc time: %f\n", (float)(end - start));
+#endif
// advance velocities
add_lfvector_lfvector(data->Vnew, data->V, data->dV, numverts);
@@ -1577,7 +1545,8 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[
/*
if (length>L) {
if ((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) &&
- ( ((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen )) {
+ ( ((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen ))
+ {
// cut spring!
s->flags |= CSPRING_FLAG_DEACTIVATE;
return false;
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
index 64a75083f72..ff4c705ed61 100644
--- a/source/blender/physics/intern/implicit_eigen.cpp
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -903,7 +903,8 @@ BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[
/*
if (length>L) {
if ((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) &&
- ( ((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen )) {
+ ( ((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen ))
+ {
// cut spring!
s->flags |= CSPRING_FLAG_DEACTIVATE;
return false;
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 815beebb159..4006816e788 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -72,10 +72,12 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
#define BPy_BEGIN_ALLOW_THREADS { BPy_ThreadStatePtr _bpy_saved_tstate = BPY_thread_save(); (void)0
#define BPy_END_ALLOW_THREADS BPY_thread_restore(_bpy_saved_tstate); } (void)0
+bool BPY_execute_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
+bool BPY_execute_text(struct bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump);
+bool BPY_execute_string_as_number(struct bContext *C, const char *expr, double *value, const bool verbose);
+bool BPY_execute_string_ex(struct bContext *C, const char *expr, bool use_eval);
+bool BPY_execute_string(struct bContext *C, const char *expr);
-/* 2.5 UI Scripts */
-int BPY_filepath_exec(struct bContext *C, const char *filepath, struct ReportList *reports);
-int BPY_text_exec(struct bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump);
void BPY_text_free_code(struct Text *text);
void BPY_modules_update(struct bContext *C); // XXX - annoying, need this for pointers that get out of date
void BPY_modules_load_user(struct bContext *C);
@@ -85,10 +87,6 @@ void BPY_app_handlers_reset(const short do_all);
void BPY_driver_reset(void);
float BPY_driver_exec(struct ChannelDriver *driver, const float evaltime);
-int BPY_button_exec(struct bContext *C, const char *expr, double *value, const bool verbose);
-int BPY_string_exec_ex(struct bContext *C, const char *expr, bool use_eval);
-int BPY_string_exec(struct bContext *C, const char *expr);
-
void BPY_DECREF(void *pyob_ptr); /* Py_DECREF() */
void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr);
int BPY_context_member_get(struct bContext *C, const char *member, struct bContextDataResult *result);
@@ -97,6 +95,8 @@ void BPY_context_update(struct bContext *C);
void BPY_id_release(struct ID *id);
+bool BPY_string_is_keyword(const char *str);
+
/* I18n for addons */
#ifdef WITH_INTERNATIONAL
const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
deleted file mode 100644
index 79c53760302..00000000000
--- a/source/blender/python/SConscript
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# TODO, split into 3 files.
-
-Import ('env')
-
-incs = [
- '.',
- '#/intern/guardedalloc',
- '#/intern/memutil',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#/intern/cycles/blender',
- '../blentranslation',
- '../blenfont',
- '../blenkernel',
- '../blenlib',
- '../blenloader',
- '../bmesh',
- '../editors/include',
- '../gpu',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../nodes',
- '../render/extern/include',
- '../windowmanager',
- env['BF_PYTHON_INC'],
- ]
-incs = ' '.join(incs)
-
-is_debug = (env['OURPLATFORM'] in ('win32-mingw', 'win32-vc','win64-vc', 'win64-mingw') and env['BF_DEBUG'])
-
-# bmesh
-defs = []
-
-sources = env.Glob('bmesh/*.c')
-env.BlenderLib( libname = 'bf_python_bmesh', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [362,165])
-
-# generic
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if is_debug:
- defs.append('_DEBUG')
-
-sources = env.Glob('generic/*.c')
-env.BlenderLib( libname = 'bf_python_ext', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [363,165]) # ketsji is 360
-
-
-# mathutils
-defs = []
-
-sources = env.Glob('mathutils/*.c')
-env.BlenderLib( libname = 'bf_python_mathutils', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [362,165])
-
-
-# bpy
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if is_debug:
- defs.append('_DEBUG')
-
-if env['WITH_BF_PYTHON_SAFETY']:
- defs.append('WITH_PYTHON_SAFETY')
-
-if env['BF_BUILDINFO']:
- defs.append('BUILD_DATE')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-# AVI is always on currently
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
- incs += ' ' + env['BF_FFMPEG_INC']
-
-if env['WITH_BF_QUICKTIME']:
- defs.append('WITH_QUICKTIME')
-
-if env['WITH_BF_SNDFILE']:
- defs.append('WITH_SNDFILE')
-
-if env['WITH_BF_COMPOSITOR']:
- defs.append('WITH_COMPOSITOR')
-
-if env['WITH_BF_CYCLES']:
- defs.append('WITH_CYCLES')
-
-if env['WITH_BF_CYCLES_OSL']:
- defs.append('WITH_CYCLES_OSL')
-
-if env['WITH_BF_FREESTYLE']:
- incs += ' ../freestyle/intern/python'
- defs.append('WITH_FREESTYLE')
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_CINEON']:
- defs.append('WITH_CINEON')
-
-if env['WITH_BF_DDS']:
- defs.append('WITH_DDS')
-
-if env['WITH_BF_FRAMESERVER']:
- defs.append('WITH_FRAMESERVER')
-
-if env['WITH_BF_HDR']:
- defs.append('WITH_HDR')
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-
-if env['WITH_BF_OPENJPEG']:
- defs.append('WITH_OPENJPEG')
-
-if env['WITH_BF_REDCODE']:
- defs.append('WITH_REDCODE')
-
-if env['WITH_BF_TIFF']:
- defs.append('WITH_TIFF')
-
-# NDof is always on currently
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_OPENAL']:
- defs.append('WITH_OPENAL')
-
-if env['WITH_BF_SDL']:
- defs.append('WITH_SDL')
- incs += ' ' + env['BF_SDL_INC']
-
- if env['WITH_BF_SDL_DYNLOAD']:
- defs.append('WITH_SDL_DYNLOAD')
- incs += ' #extern/sdlew/include'
-
-if env['WITH_BF_JACK']:
- defs.append('WITH_JACK')
-
-if env['WITH_BF_LIBMV']:
- defs.append('WITH_LIBMV')
-
-if env['WITH_BF_BOOLEAN']:
- defs.append('WITH_MOD_BOOLEAN')
-
-if env['WITH_BF_FLUID']:
- defs.append('WITH_MOD_FLUID')
-
-if env['WITH_BF_OCEANSIM']:
- defs.append('WITH_OCEANSIM')
-
-if env['WITH_BF_REMESH']:
- defs.append('WITH_MOD_REMESH')
-
-if env['WITH_BF_SMOKE']:
- defs.append('WITH_SMOKE')
-
-if env['WITH_BF_COLLADA']:
- defs.append('WITH_COLLADA')
-
-if env['WITH_BF_OCIO']:
- defs.append('WITH_OCIO')
- incs += ' ' + '#/intern/opencolorio'
-
-if env['WITH_BF_OIIO']:
- defs.append('WITH_OPENIMAGEIO')
- incs += ' ../imbuf/intern/oiio'
-
-if env['WITH_BF_PLAYER']:
- defs.append('WITH_PLAYER')
-
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-sources = env.Glob('intern/*.c')
-env.BlenderLib( libname = 'bf_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [361])
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index bf773d3d9c3..ce8f1247919 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -937,8 +937,9 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc,
" :arg face_normals: Calculate face normals.\n"
" :type face_normals: boolean\n"
);
-static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args)
+static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
+ static const char *kwlist[] = {"object", "scene", "deform", "render", "cage", "face_normals", NULL};
PyObject *py_object;
PyObject *py_scene;
Object *ob;
@@ -953,8 +954,8 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args)
BPY_BM_CHECK_OBJ(self);
- if (!PyArg_ParseTuple(
- args, "OO|O&O&O&O&:from_object",
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kw, "OO|O&O&O&O&:from_object", (char **)kwlist,
&py_object, &py_scene,
PyC_ParseBool, &use_deform,
PyC_ParseBool, &use_render,
@@ -1257,7 +1258,7 @@ static PyObject *bpy_bmesh_calc_tessface(BPy_BMElem *self)
looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
looptris = PyMem_MALLOC(sizeof(*looptris) * looptris_tot);
- BM_bmesh_calc_tessellation(bm, looptris, &tottri);
+ BM_mesh_calc_tessellation(bm, looptris, &tottri);
ret = PyList_New(tottri);
for (i = 0; i < tottri; i++) {
@@ -2789,7 +2790,7 @@ static PyTypeObject *bpy_bm_itype_as_pytype(const char itype)
case BM_FACES_OF_VERT:
return &BPy_BMFace_Type;
- case BM_ALL_LOOPS_OF_FACE:
+ // case BM_ALL_LOOPS_OF_FACE:
case BM_LOOPS_OF_FACE:
case BM_LOOPS_OF_EDGE:
case BM_LOOPS_OF_VERT:
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index a2dceb2a877..b5a480c05b5 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -145,12 +145,40 @@ static PyObject *bpy_bmeditselseq_remove(BPy_BMEditSelSeq *self, BPy_BMElem *val
Py_RETURN_NONE;
}
+PyDoc_STRVAR(bpy_bmeditselseq_discard_doc,
+".. method:: discard(element)\n"
+"\n"
+" Discard an element from the selection history.\n"
+"\n"
+" Like remove but doesn't raise an error when the elements not in the selection list.\n"
+);
+static PyObject *bpy_bmeditselseq_discard(BPy_BMEditSelSeq *self, BPy_BMElem *value)
+{
+ BPY_BM_CHECK_OBJ(self);
+
+ if ((BPy_BMVert_Check(value) ||
+ BPy_BMEdge_Check(value) ||
+ BPy_BMFace_Check(value)) == false)
+ {
+ PyErr_Format(PyExc_TypeError,
+ "Expected a BMVert/BMedge/BMFace not a %.200s", Py_TYPE(value)->tp_name);
+ return NULL;
+ }
+
+ BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.discard()", value);
+
+ BM_select_history_remove(self->bm, value->ele);
+
+ Py_RETURN_NONE;
+}
+
static struct PyMethodDef bpy_bmeditselseq_methods[] = {
{"validate", (PyCFunction)bpy_bmeditselseq_validate, METH_NOARGS, bpy_bmeditselseq_validate_doc},
{"clear", (PyCFunction)bpy_bmeditselseq_clear, METH_NOARGS, bpy_bmeditselseq_clear_doc},
{"add", (PyCFunction)bpy_bmeditselseq_add, METH_O, bpy_bmeditselseq_add_doc},
{"remove", (PyCFunction)bpy_bmeditselseq_remove, METH_O, bpy_bmeditselseq_remove_doc},
+ {"discard", (PyCFunction)bpy_bmeditselseq_discard, METH_O, bpy_bmeditselseq_discard_doc},
{NULL, NULL, 0, NULL}
};
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index 379aafa5918..89c196dbcad 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -513,6 +513,13 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args,
return NULL;
}
}
+ else {
+ if (BM_loop_is_adjacent(l_a, l_b)) {
+ PyErr_SetString(PyExc_ValueError,
+ "face_split(...): verts are adjacent in the face");
+ return NULL;
+ }
+ }
/* --- main function body --- */
bm = py_face->bm;
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index cd6ef3f16a4..4bd2e9d8d62 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -3681,7 +3681,7 @@ static PyObject *Method_ShaderSource(PyObject *UNUSED(self), PyObject *args)
glShaderSource(shader, 1, (const char **)&source, NULL);
- return Py_INCREF(Py_None), Py_None;
+ Py_RETURN_NONE;
}
diff --git a/source/blender/python/generic/bpy_threads.c b/source/blender/python/generic/bpy_threads.c
index 63a47ff0b20..fbc145660f3 100644
--- a/source/blender/python/generic/bpy_threads.c
+++ b/source/blender/python/generic/bpy_threads.c
@@ -27,11 +27,6 @@
* these functions are slightly different from the original Python API,
* don't throw SIGABRT even if the thread state is NULL. */
-/* grr, python redefines */
-#ifdef _POSIX_C_SOURCE
-# undef _POSIX_C_SOURCE
-#endif
-
#include <Python.h>
#include "BLI_utildefines.h"
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index cd86ed24bcb..dd32c913f78 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -29,7 +29,6 @@
* BLI_string_utf8() for unicode conversion.
*/
-
#include <Python.h>
#include <frameobject.h>
@@ -39,8 +38,10 @@
#include "python_utildefines.h"
+#ifndef MATH_STANDALONE
/* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */
#include "BLI_string_utf8.h"
+#endif
#ifdef _WIN32
#include "BLI_path_util.h" /* BLI_setenv() */
@@ -200,6 +201,27 @@ void PyC_List_Fill(PyObject *list, PyObject *value)
}
}
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
+int PyC_ParseBool(PyObject *o, void *p)
+{
+ bool *bool_p = p;
+ long value;
+ if (((value = PyLong_AsLong(o)) == -1) || !ELEM(value, 0, 1)) {
+ PyErr_Format(PyExc_ValueError,
+ "expected a bool or int (0/1), got %s",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+
+ *bool_p = value ? true : false;
+ return 1;
+}
+
+
+#ifndef MATH_STANDALONE
+
/* for debugging */
void PyC_ObSpit(const char *name, PyObject *var)
{
@@ -534,15 +556,6 @@ const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
if (PyBytes_Check(py_str)) {
return PyBytes_AS_STRING(py_str);
}
-#ifdef WIN32
- /* bug [#31856] oddly enough, Python3.2 --> 3.3 on Windows will throw an
- * exception here this needs to be fixed in python:
- * see: bugs.python.org/issue15859 */
- else if (!PyUnicode_Check(py_str)) {
- PyErr_BadArgument();
- return NULL;
- }
-#endif
else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
return PyBytes_AS_STRING(*coerce);
}
@@ -666,7 +679,8 @@ void PyC_SetHomePath(const char *py_path_bundle)
bool PyC_IsInterpreterActive(void)
{
- return (PyThreadState_GET() != NULL);
+ /* instead of PyThreadState_Get, which calls Py_FatalError */
+ return (PyThreadState_GetDict() != NULL);
}
/* Would be nice if python had this built in
@@ -710,7 +724,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
}
if (ret == NULL) {
- printf("PyC_InlineRun error, line:%d\n", __LINE__);
+ printf("%s error, line:%d\n", __func__, __LINE__);
PyErr_Print();
PyErr_Clear();
@@ -784,7 +798,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
Py_DECREF(ret);
}
else {
- printf("PyC_InlineRun error on arg '%d', line:%d\n", i, __LINE__);
+ printf("%s error on arg '%d', line:%d\n", __func__, i, __LINE__);
PyC_ObSpit("failed converting:", item_new);
PyErr_Print();
PyErr_Clear();
@@ -795,11 +809,11 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
va_end(vargs);
}
else {
- printf("PyC_InlineRun error, 'values' not a list, line:%d\n", __LINE__);
+ printf("%s error, 'values' not a list, line:%d\n", __func__, __LINE__);
}
}
else {
- printf("PyC_InlineRun error line:%d\n", __LINE__);
+ printf("%s error line:%d\n", __func__, __LINE__);
PyErr_Print();
PyErr_Clear();
}
@@ -957,14 +971,14 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
/**
- * \return -1 on error, else 0
+ * \return success
*
* \note it is caller's responsibility to acquire & release GIL!
*/
-int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename)
+bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filename)
{
PyObject *py_dict, *mod, *retval;
- int error_ret = 0;
+ bool ok = true;
PyObject *main_mod = NULL;
PyC_MainModule_Backup(&main_mod);
@@ -984,7 +998,7 @@ int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename
retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
if (retval == NULL) {
- error_ret = -1;
+ ok = false;
}
else {
double val;
@@ -1010,7 +1024,7 @@ int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename
Py_DECREF(retval);
if (val == -1 && PyErr_Occurred()) {
- error_ret = -1;
+ ok = false;
}
else if (!finite(val)) {
*value = 0.0;
@@ -1022,23 +1036,7 @@ int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename
PyC_MainModule_Restore(main_mod);
- return error_ret;
+ return ok;
}
-/**
- * Use with PyArg_ParseTuple's "O&" formatting.
- */
-int PyC_ParseBool(PyObject *o, void *p)
-{
- bool *bool_p = p;
- long value;
- if (((value = PyLong_AsLong(o)) == -1) || !ELEM(value, 0, 1)) {
- PyErr_Format(PyExc_ValueError,
- "expected a bool or int (0/1), got %s",
- Py_TYPE(o)->tp_name);
- return 0;
- }
-
- *bool_p = value ? true : false;
- return 1;
-}
+#endif /* #ifndef MATH_STANDALONE */
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 0ebc06ce2fa..a06a717ecbc 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -79,7 +79,7 @@ int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int
int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
-int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename);
+bool PyC_RunString_AsNumber(const char *expr, double *value, const char *filename);
int PyC_ParseBool(PyObject *o, void *p);
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index cd2a9fd8584..2715d2c5992 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -46,6 +46,7 @@ set(INC_SYS
set(SRC
gpu.c
+ gpu_offscreen.c
bpy.c
bpy_app.c
bpy_app_build_options.c
@@ -53,13 +54,15 @@ set(SRC
bpy_app_handlers.c
bpy_app_ocio.c
bpy_app_oiio.c
+ bpy_app_openvdb.c
bpy_app_sdl.c
bpy_app_translations.c
bpy_driver.c
bpy_interface.c
bpy_interface_atexit.c
bpy_intern_string.c
- bpy_library.c
+ bpy_library_load.c
+ bpy_library_write.c
bpy_operator.c
bpy_operator_wrap.c
bpy_path.c
@@ -68,6 +71,8 @@ set(SRC
bpy_rna_anim.c
bpy_rna_array.c
bpy_rna_callback.c
+ bpy_rna_driver.c
+ bpy_rna_id_collection.c
bpy_traceback.c
bpy_util.c
bpy_utils_previews.c
@@ -82,6 +87,7 @@ set(SRC
bpy_app_handlers.h
bpy_app_ocio.h
bpy_app_oiio.h
+ bpy_app_openvdb.h
bpy_app_sdl.h
bpy_app_translations.h
bpy_driver.h
@@ -94,6 +100,8 @@ set(SRC
bpy_rna.h
bpy_rna_anim.h
bpy_rna_callback.h
+ bpy_rna_driver.h
+ bpy_rna_id_collection.h
bpy_traceback.h
bpy_util.h
bpy_utils_previews.h
@@ -194,10 +202,6 @@ if(WITH_IMAGE_OPENJPEG)
add_definitions(-DWITH_OPENJPEG)
endif()
-if(WITH_IMAGE_REDCODE)
- add_definitions(-DWITH_REDCODE)
-endif()
-
if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
@@ -264,6 +268,13 @@ if(WITH_OPENCOLORIO)
add_definitions(-DWITH_OCIO)
endif()
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB)
+ list(APPEND INC
+ ../../../../intern/openvdb
+ )
+endif()
+
if(WITH_OPENIMAGEIO)
add_definitions(-DWITH_OPENIMAGEIO)
list(APPEND INC
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index fa2ad3a4803..c09b39139c2 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -45,6 +45,7 @@
#include "bpy_util.h"
#include "bpy_rna.h"
#include "bpy_app.h"
+#include "bpy_rna_id_collection.h"
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
@@ -320,11 +321,11 @@ void BPy_init_modules(void)
/* needs to be first so bpy_types can run */
PyModule_AddObject(mod, "types", BPY_rna_types());
- /* metaclass for idprop types, bpy_types.py needs access */
- PyModule_AddObject(mod, "StructMetaPropGroup", (PyObject *)&pyrna_struct_meta_idprop_Type);
-
/* needs to be first so bpy_types can run */
- BPY_library_module(mod);
+ BPY_library_load_module(mod);
+ BPY_library_write_module(mod);
+
+ BPY_rna_id_collection_module(mod);
bpy_import_test("bpy_types");
PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 90d97cad880..595bb7b0f22 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -36,6 +36,7 @@
#include "bpy_app_ffmpeg.h"
#include "bpy_app_ocio.h"
#include "bpy_app_oiio.h"
+#include "bpy_app_openvdb.h"
#include "bpy_app_sdl.h"
#include "bpy_app_build_options.h"
@@ -54,6 +55,10 @@
#include "UI_interface_icons.h"
+/* for notifiers */
+#include "WM_api.h"
+#include "WM_types.h"
+
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
@@ -102,6 +107,7 @@ static PyStructSequence_Field app_info_fields[] = {
{(char *)"ffmpeg", (char *)"FFmpeg library information backend"},
{(char *)"ocio", (char *)"OpenColorIO library information backend"},
{(char *)"oiio", (char *)"OpenImageIO library information backend"},
+ {(char *)"openvdb", (char *)"OpenVDB library information backend"},
{(char *)"sdl", (char *)"SDL library information backend"},
{(char *)"build_options", (char *)"A set containing most important enabled optional build features"},
{(char *)"handlers", (char *)"Application handler callbacks"},
@@ -179,6 +185,7 @@ static PyObject *make_app_info(void)
SetObjItem(BPY_app_ffmpeg_struct());
SetObjItem(BPY_app_ocio_struct());
SetObjItem(BPY_app_oiio_struct());
+ SetObjItem(BPY_app_openvdb_struct());
SetObjItem(BPY_app_sdl_struct());
SetObjItem(BPY_app_build_options_struct());
SetObjItem(BPY_app_handlers_struct());
@@ -270,6 +277,8 @@ static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void
G.debug_value = param;
+ WM_main_add_notifier(NC_WINDOW, NULL);
+
return 0;
}
@@ -334,8 +343,8 @@ static PyGetSetDef bpy_app_getsets[] = {
{(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
{(char *)"driver_namespace", bpy_app_driver_dict_get, NULL, (char *)bpy_app_driver_dict_doc, NULL},
- {(char *)"render_icon_size", bpy_app_preview_render_size_get, NULL, (char *)bpy_app_preview_render_size_doc, (void *)ICON_SIZE_ICON},
- {(char *)"render_preview_size", bpy_app_preview_render_size_get, NULL, (char *)bpy_app_preview_render_size_doc, (void *)ICON_SIZE_PREVIEW},
+ {(char *)"render_icon_size", bpy_app_preview_render_size_get, NULL, (char *)bpy_app_preview_render_size_doc, (void *)ICON_SIZE_ICON},
+ {(char *)"render_preview_size", bpy_app_preview_render_size_get, NULL, (char *)bpy_app_preview_render_size_doc, (void *)ICON_SIZE_PREVIEW},
/* security */
{(char *)"autoexec_fail", bpy_app_global_flag_get, NULL, NULL, (void *)G_SCRIPT_AUTOEXEC_FAIL},
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index 975d76ca42d..4c186aab100 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -50,7 +50,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"image_hdr", NULL},
{(char *)"image_openexr", NULL},
{(char *)"image_openjpeg", NULL},
- {(char *)"image_redcode", NULL},
{(char *)"image_tiff", NULL},
{(char *)"input_ndof", NULL},
{(char *)"audaspace", NULL},
@@ -69,6 +68,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"opencolorio", NULL},
{(char *)"player", NULL},
{(char *)"openmp", NULL},
+ {(char *)"openvdb", NULL},
{NULL}
};
@@ -189,12 +189,6 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
-#ifdef WITH_REDCODE
- SetObjIncref(Py_True);
-#else
- SetObjIncref(Py_False);
-#endif
-
#ifdef WITH_TIFF
SetObjIncref(Py_True);
#else
@@ -303,6 +297,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_OPENVDB
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#undef SetObjIncref
return builtopts_info;
diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c
new file mode 100644
index 00000000000..8a24aaf0555
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_openvdb.c
@@ -0,0 +1,117 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_openvdb.c
+ * \ingroup pythonintern
+ */
+
+#include <Python.h>
+#include "BLI_utildefines.h"
+
+#include "bpy_app_openvdb.h"
+
+#ifdef WITH_OPENVDB
+# include "openvdb_capi.h"
+#endif
+
+static PyTypeObject BlenderAppOVDBType;
+
+static PyStructSequence_Field app_openvdb_info_fields[] = {
+ {(char *)"supported", (char *)("Boolean, True when Blender is built with OpenVDB support")},
+ {(char *)("version"), (char *)("The OpenVDB version as a tuple of 3 numbers")},
+ {(char *)("version_string"), (char *)("The OpenVDB version formatted as a string")},
+ {NULL}
+};
+
+static PyStructSequence_Desc app_openvdb_info_desc = {
+ (char *)"bpy.app.openvdb", /* name */
+ (char *)"This module contains information about OpenVDB blender is linked against", /* doc */
+ app_openvdb_info_fields, /* fields */
+ ARRAY_SIZE(app_openvdb_info_fields) - 1
+};
+
+static PyObject *make_openvdb_info(void)
+{
+ PyObject *openvdb_info;
+ int pos = 0;
+
+#ifdef WITH_OPENVDB
+ int curversion;
+#endif
+
+ openvdb_info = PyStructSequence_New(&BlenderAppOVDBType);
+ if (openvdb_info == NULL) {
+ return NULL;
+ }
+
+#ifndef WITH_OPENVDB
+#define SetStrItem(str) \
+ PyStructSequence_SET_ITEM(openvdb_info, pos++, PyUnicode_FromString(str))
+#endif
+
+#define SetObjItem(obj) \
+ PyStructSequence_SET_ITEM(openvdb_info, pos++, obj)
+
+#ifdef WITH_OPENVDB
+ curversion = OpenVDB_getVersionHex();
+ SetObjItem(PyBool_FromLong(1));
+ SetObjItem(Py_BuildValue("(iii)",
+ curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
+ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d",
+ curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256));
+#else
+ SetObjItem(PyBool_FromLong(0));
+ SetObjItem(Py_BuildValue("(iii)", 0, 0, 0));
+ SetStrItem("Unknown");
+#endif
+
+ if (PyErr_Occurred()) {
+ Py_CLEAR(openvdb_info);
+ return NULL;
+ }
+
+#undef SetStrItem
+#undef SetObjItem
+
+ return openvdb_info;
+}
+
+PyObject *BPY_app_openvdb_struct(void)
+{
+ PyObject *ret;
+
+ PyStructSequence_InitType(&BlenderAppOVDBType, &app_openvdb_info_desc);
+
+ ret = make_openvdb_info();
+
+ /* prevent user from creating new instances */
+ BlenderAppOVDBType.tp_init = NULL;
+ BlenderAppOVDBType.tp_new = NULL;
+ BlenderAppOVDBType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
+
+ return ret;
+}
diff --git a/source/blender/python/intern/bpy_app_openvdb.h b/source/blender/python/intern/bpy_app_openvdb.h
new file mode 100644
index 00000000000..12fa54ea7a3
--- /dev/null
+++ b/source/blender/python/intern/bpy_app_openvdb.h
@@ -0,0 +1,38 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_app_openvdb.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_APP_OPENVDB_H__
+#define __BPY_APP_OPENVDB_H__
+
+PyObject *BPY_app_openvdb_struct(void);
+
+#endif /* __BPY_APP_OPENVDB_H__ */
+
diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c
index c91595b5900..2f4d8e6c325 100644
--- a/source/blender/python/intern/bpy_app_sdl.c
+++ b/source/blender/python/intern/bpy_app_sdl.c
@@ -30,7 +30,18 @@
#include "bpy_app_sdl.h"
#ifdef WITH_SDL
+/* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings
+ * because we pass those defines via command line as well. For until there's
+ * proper ifndef added to SDL headers we ignore the redefinition warning.
+ */
+# ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4005)
+# endif
# include "SDL.h"
+# ifdef _MSC_VER
+# pragma warning(pop)
+# endif
# ifdef WITH_SDL_DYNLOAD
# include "sdlew.h"
# endif
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index dfff67e6ca1..b90deafb377 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -181,7 +181,6 @@ static void _build_translations_cache(PyObject *py_messages, const char *locale)
/* Iterate over all translations of the found language dict, and populate our ghash cache. */
while (PyDict_Next(lang_dict, &ppos, &pykey, &trans)) {
- GHashKey *key;
const char *msgctxt = NULL, *msgid = NULL;
bool invalid_key = false;
@@ -229,14 +228,11 @@ static void _build_translations_cache(PyObject *py_messages, const char *locale)
continue;
}
- key = _ghashutil_keyalloc(msgctxt, msgid);
-
/* Do not overwrite existing keys! */
- if (BLI_ghash_lookup(_translations_cache, (void *)key)) {
- continue;
+ if (BPY_app_translations_py_pgettext(msgctxt, msgid) == msgid) {
+ GHashKey *key = _ghashutil_keyalloc(msgctxt, msgid);
+ BLI_ghash_insert(_translations_cache, key, BLI_strdup(_PyUnicode_AsString(trans)));
}
-
- BLI_ghash_insert(_translations_cache, key, BLI_strdup(_PyUnicode_AsString(trans)));
}
}
}
@@ -251,7 +247,7 @@ const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *ms
{
#define STATIC_LOCALE_SIZE 32 /* Should be more than enough! */
- GHashKey *key;
+ GHashKey key;
static char locale[STATIC_LOCALE_SIZE] = "";
const char *tmp;
@@ -275,11 +271,10 @@ const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *ms
}
/* And now, simply create the key (context, messageid) and find it in the cached dict! */
- key = _ghashutil_keyalloc(msgctxt, msgid);
-
- tmp = BLI_ghash_lookup(_translations_cache, key);
+ key.msgctxt = BLT_is_default_context(msgctxt) ? BLT_I18NCONTEXT_DEFAULT_BPYRNA : msgctxt;
+ key.msgid = msgid;
- _ghashutil_keyfree((void *)key);
+ tmp = BLI_ghash_lookup(_translations_cache, &key);
return tmp ? tmp : msgid;
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index df848f6b60c..f9c0982a4c3 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -42,10 +42,13 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
+#include "bpy_rna_driver.h" /* for pyrna_driver_get_variable_value */
+
#include "bpy_driver.h"
extern void BPY_update_rna_module(void);
+#define USE_RNA_AS_PYOBJECT
/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
PyObject *bpy_pydriver_Dict = NULL;
@@ -211,7 +214,7 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
/* init global dictionary for py-driver evaluation settings */
if (!bpy_pydriver_Dict) {
if (bpy_pydriver_create_dict() != 0) {
- fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
+ fprintf(stderr, "PyDriver error: couldn't create Python dictionary\n");
if (use_gil)
PyGILState_Release(gilstate);
return 0.0f;
@@ -259,15 +262,27 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
}
/* add target values to a dict that will be used as '__locals__' dict */
- driver_vars = PyDict_New(); // XXX do we need to decref this?
+ driver_vars = PyDict_New();
for (dvar = driver->variables.first, i = 0; dvar; dvar = dvar->next) {
PyObject *driver_arg = NULL;
- float tval = 0.0f;
-
- /* try to get variable value */
- tval = driver_get_variable_value(driver, dvar);
- driver_arg = PyFloat_FromDouble((double)tval);
-
+
+ /* support for any RNA data */
+#ifdef USE_RNA_AS_PYOBJECT
+ if (dvar->type == DVAR_TYPE_SINGLE_PROP) {
+ driver_arg = pyrna_driver_get_variable_value(driver, &dvar->targets[0]);
+
+ if (driver_arg == NULL) {
+ driver_arg = PyFloat_FromDouble(0.0);
+ }
+ }
+ else
+#endif
+ {
+ /* try to get variable value */
+ float tval = driver_get_variable_value(driver, dvar);
+ driver_arg = PyFloat_FromDouble((double)tval);
+ }
+
/* try to add to dictionary */
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) {
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 61477d0bd56..b559623f619 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -29,12 +29,6 @@
* be accesses from scripts.
*/
-
-/* grr, python redefines */
-#ifdef _POSIX_C_SOURCE
-# undef _POSIX_C_SOURCE
-#endif
-
#include <Python.h>
#ifdef WIN32
@@ -430,8 +424,9 @@ typedef struct {
} PyModuleObject;
#endif
-static int python_script_exec(bContext *C, const char *fn, struct Text *text,
- struct ReportList *reports, const bool do_jump)
+static bool python_script_exec(
+ bContext *C, const char *fn, struct Text *text,
+ struct ReportList *reports, const bool do_jump)
{
Main *bmain_old = CTX_data_main(C);
PyObject *main_mod = NULL;
@@ -549,13 +544,13 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text,
}
/* Can run a file or text block */
-int BPY_filepath_exec(bContext *C, const char *filepath, struct ReportList *reports)
+bool BPY_execute_filepath(bContext *C, const char *filepath, struct ReportList *reports)
{
return python_script_exec(C, filepath, NULL, reports, false);
}
-int BPY_text_exec(bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump)
+bool BPY_execute_text(bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump)
{
return python_script_exec(C, NULL, text, reports, do_jump);
}
@@ -578,24 +573,26 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
PyGILState_Release(gilstate);
}
-/* return -1 on error, else 0 */
-int BPY_button_exec(bContext *C, const char *expr, double *value, const bool verbose)
+/**
+ * \return success
+ */
+bool BPY_execute_string_as_number(bContext *C, const char *expr, double *value, const bool verbose)
{
PyGILState_STATE gilstate;
- int error_ret = 0;
+ bool ok = true;
if (!value || !expr) return -1;
if (expr[0] == '\0') {
*value = 0.0;
- return error_ret;
+ return ok;
}
bpy_context_set(C, &gilstate);
- error_ret = PyC_RunString_AsNumber(expr, value, "<blender button>");
+ ok = PyC_RunString_AsNumber(expr, value, "<blender button>");
- if (error_ret) {
+ if (ok == false) {
if (verbose) {
BPy_errors_to_report_ex(CTX_wm_reports(C), false, false);
}
@@ -606,21 +603,21 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
bpy_context_clear(C, &gilstate);
- return error_ret;
+ return ok;
}
-int BPY_string_exec_ex(bContext *C, const char *expr, bool use_eval)
+bool BPY_execute_string_ex(bContext *C, const char *expr, bool use_eval)
{
PyGILState_STATE gilstate;
PyObject *main_mod = NULL;
PyObject *py_dict, *retval;
- int error_ret = 0;
+ bool ok = true;
Main *bmain_back; /* XXX, quick fix for release (Copy Settings crash), needs further investigation */
if (!expr) return -1;
if (expr[0] == '\0') {
- return error_ret;
+ return ok;
}
bpy_context_set(C, &gilstate);
@@ -637,7 +634,7 @@ int BPY_string_exec_ex(bContext *C, const char *expr, bool use_eval)
bpy_import_main_set(bmain_back);
if (retval == NULL) {
- error_ret = -1;
+ ok = false;
BPy_errors_to_report(CTX_wm_reports(C));
}
@@ -649,12 +646,12 @@ int BPY_string_exec_ex(bContext *C, const char *expr, bool use_eval)
bpy_context_clear(C, &gilstate);
- return error_ret;
+ return ok;
}
-int BPY_string_exec(bContext *C, const char *expr)
+bool BPY_execute_string(bContext *C, const char *expr)
{
- return BPY_string_exec_ex(C, expr, true);
+ return BPY_execute_string_ex(C, expr, true);
}
void BPY_modules_load_user(bContext *C)
@@ -828,7 +825,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy)
char filename_abs[1024];
BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs));
- BLI_path_cwd(filename_abs);
+ BLI_path_cwd(filename_abs, sizeof(filename_abs));
argv[0] = filename_abs;
argv[1] = NULL;
@@ -902,6 +899,32 @@ static void bpy_module_free(void *UNUSED(mod))
#endif
+/**
+ * Avoids duplicating keyword list.
+ */
+bool BPY_string_is_keyword(const char *str)
+{
+ /* list is from...
+ * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist])
+ */
+ const char *kwlist[] = {
+ "False", "None", "True",
+ "and", "as", "assert", "break",
+ "class", "continue", "def", "del", "elif", "else", "except",
+ "finally", "for", "from", "global", "if", "import", "in",
+ "is", "lambda", "nonlocal", "not", "or", "pass", "raise",
+ "return", "try", "while", "with", "yield", NULL,
+ };
+
+ for (int i = 0; kwlist[i]; i++) {
+ if (STREQ(str, kwlist[i])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* EVIL, define text.c functions here... */
/* BKE_text.h */
diff --git a/source/blender/python/intern/bpy_library.c b/source/blender/python/intern/bpy_library.c
deleted file mode 100644
index a5879f11e51..00000000000
--- a/source/blender/python/intern/bpy_library.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s): Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/python/intern/bpy_library.c
- * \ingroup pythonintern
- *
- * This file exposed blend file library appending/linking to python, typically
- * this would be done via RNA api but in this case a hand written python api
- * allows us to use pythons context manager (__enter__ and __exit__).
- *
- * Everything here is exposed via bpy.data.libraries.load(...) which returns
- * a context manager.
- */
-
-#include <Python.h>
-#include <stddef.h>
-
-#include "BLI_utildefines.h"
-#include "BLI_string.h"
-#include "BLI_linklist.h"
-#include "BLI_path_util.h"
-
-#include "BLO_readfile.h"
-
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_library.h"
-#include "BKE_idcode.h"
-#include "BKE_report.h"
-#include "BKE_context.h"
-
-#include "DNA_space_types.h" /* FILE_LINK, FILE_RELPATH */
-
-#include "bpy_util.h"
-#include "bpy_library.h"
-
-#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
-
-/* nifty feature. swap out strings for RNA data */
-#define USE_RNA_DATABLOCKS
-
-#ifdef USE_RNA_DATABLOCKS
-# include "bpy_rna.h"
-# include "RNA_access.h"
-#endif
-
-typedef struct {
- PyObject_HEAD /* required python macro */
- /* collection iterator specific parts */
- char relpath[FILE_MAX];
- char abspath[FILE_MAX]; /* absolute path */
- BlendHandle *blo_handle;
- int flag;
- PyObject *dict;
-} BPy_Library;
-
-static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds);
-static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args);
-static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args);
-static PyObject *bpy_lib_dir(BPy_Library *self);
-
-static PyMethodDef bpy_lib_methods[] = {
- {"__enter__", (PyCFunction)bpy_lib_enter, METH_NOARGS},
- {"__exit__", (PyCFunction)bpy_lib_exit, METH_VARARGS},
- {"__dir__", (PyCFunction)bpy_lib_dir, METH_NOARGS},
- {NULL} /* sentinel */
-};
-
-static void bpy_lib_dealloc(BPy_Library *self)
-{
- Py_XDECREF(self->dict);
- Py_TYPE(self)->tp_free(self);
-}
-
-
-static PyTypeObject bpy_lib_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "bpy_lib", /* tp_name */
- sizeof(BPy_Library), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)bpy_lib_dealloc, /* tp_dealloc */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
- NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
- NULL, /* tp_repr */
-
- /* Method suites for standard classes */
-
- NULL, /* PyNumberMethods *tp_as_number; */
- NULL, /* PySequenceMethods *tp_as_sequence; */
- NULL, /* PyMappingMethods *tp_as_mapping; */
-
- /* More standard operations (here for binary compatibility) */
-
- NULL, /* hashfunc tp_hash; */
- NULL, /* ternaryfunc tp_call; */
- NULL, /* reprfunc tp_str; */
-
- /* will only use these if this is a subtype of a py class */
- NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
-
- /* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
-
- /*** Flags to define presence of optional/expanded features ***/
- Py_TPFLAGS_DEFAULT, /* long tp_flags; */
-
- NULL, /* char *tp_doc; Documentation string */
- /*** Assigned meaning in release 2.0 ***/
- /* call function for all accessible objects */
- NULL, /* traverseproc tp_traverse; */
-
- /* delete references to contained objects */
- NULL, /* inquiry tp_clear; */
-
- /*** Assigned meaning in release 2.1 ***/
- /*** rich comparisons ***/
- NULL, /* subclassed */ /* richcmpfunc tp_richcompare; */
-
- /*** weak reference enabler ***/
- 0,
- /*** Added in release 2.2 ***/
- /* Iterators */
- NULL, /* getiterfunc tp_iter; */
- NULL, /* iternextfunc tp_iternext; */
-
- /*** Attribute descriptor and subclassing stuff ***/
- bpy_lib_methods, /* struct PyMethodDef *tp_methods; */
- NULL, /* struct PyMemberDef *tp_members; */
- NULL, /* struct PyGetSetDef *tp_getset; */
- NULL, /* struct _typeobject *tp_base; */
- NULL, /* PyObject *tp_dict; */
- NULL, /* descrgetfunc tp_descr_get; */
- NULL, /* descrsetfunc tp_descr_set; */
- offsetof(BPy_Library, dict), /* long tp_dictoffset; */
- NULL, /* initproc tp_init; */
- NULL, /* allocfunc tp_alloc; */
- NULL, /* newfunc tp_new; */
- /* Low-level free-memory routine */
- NULL, /* freefunc tp_free; */
- /* For PyObject_IS_GC */
- NULL, /* inquiry tp_is_gc; */
- NULL, /* PyObject *tp_bases; */
- /* method resolution order */
- NULL, /* PyObject *tp_mro; */
- NULL, /* PyObject *tp_cache; */
- NULL, /* PyObject *tp_subclasses; */
- NULL, /* PyObject *tp_weaklist; */
- NULL
-};
-
-PyDoc_STRVAR(bpy_lib_load_doc,
-".. method:: load(filepath, link=False, relative=False)\n"
-"\n"
-" Returns a context manager which exposes 2 library objects on entering.\n"
-" Each object has attributes matching bpy.data which are lists of strings to be linked.\n"
-"\n"
-" :arg filepath: The path to a blend file.\n"
-" :type filepath: string\n"
-" :arg link: When False reference to the original file is lost.\n"
-" :type link: bool\n"
-" :arg relative: When True the path is stored relative to the open blend file.\n"
-" :type relative: bool\n"
-);
-static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"filepath", "link", "relative", NULL};
- BPy_Library *ret;
- const char *filename = NULL;
- bool is_rel = false, is_link = false;
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds,
- "s|O&O&:load", (char **)kwlist,
- &filename,
- PyC_ParseBool, &is_link,
- PyC_ParseBool, &is_rel))
- {
- return NULL;
- }
-
- ret = PyObject_New(BPy_Library, &bpy_lib_Type);
-
- BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
- BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
- BLI_path_abs(ret->abspath, G.main->name);
-
- ret->blo_handle = NULL;
- ret->flag = ((is_link ? FILE_LINK : 0) |
- (is_rel ? FILE_RELPATH : 0));
-
- ret->dict = PyDict_New();
-
- return (PyObject *)ret;
-}
-
-static PyObject *_bpy_names(BPy_Library *self, int blocktype)
-{
- PyObject *list;
- LinkNode *l, *names;
- int totnames;
-
- names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames);
-
- if (names) {
- int counter = 0;
- list = PyList_New(totnames);
- for (l = names; l; l = l->next) {
- PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link));
- counter++;
- }
- BLI_linklist_free(names, free); /* free linklist *and* each node's data */
- }
- else {
- list = PyList_New(0);
- }
-
- return list;
-}
-
-static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
-{
- PyObject *ret;
- BPy_Library *self_from;
- PyObject *from_dict = PyDict_New();
- ReportList reports;
-
- BKE_reports_init(&reports, RPT_STORE);
-
- self->blo_handle = BLO_blendhandle_from_file(self->abspath, &reports);
-
- if (self->blo_handle == NULL) {
- if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) {
- PyErr_Format(PyExc_IOError,
- "load: %s failed to open blend file",
- self->abspath);
- }
- return NULL;
- }
- else {
- int i = 0, code;
- while ((code = BKE_idcode_iter_step(&i))) {
- if (BKE_idcode_is_linkable(code)) {
- const char *name_plural = BKE_idcode_to_name_plural(code);
- PyObject *str = PyUnicode_FromString(name_plural);
- PyDict_SetItem(self->dict, str, PyList_New(0));
- PyDict_SetItem(from_dict, str, _bpy_names(self, code));
- Py_DECREF(str);
- }
- }
- }
-
- /* create a dummy */
- self_from = PyObject_New(BPy_Library, &bpy_lib_Type);
- BLI_strncpy(self_from->relpath, self->relpath, sizeof(self_from->relpath));
- BLI_strncpy(self_from->abspath, self->abspath, sizeof(self_from->abspath));
-
- self_from->blo_handle = NULL;
- self_from->flag = 0;
- self_from->dict = from_dict; /* owns the dict */
-
- /* return pair */
- ret = PyTuple_New(2);
- PyTuple_SET_ITEMS(ret,
- (PyObject *)self_from,
- (PyObject *)self);
- Py_INCREF(self);
-
- BKE_reports_clear(&reports);
-
- return ret;
-}
-
-static void bpy_lib_exit_warn_idname(BPy_Library *self, const char *name_plural, const char *idname)
-{
- PyObject *exc, *val, *tb;
- PyErr_Fetch(&exc, &val, &tb);
- if (PyErr_WarnFormat(PyExc_UserWarning, 1,
- "load: '%s' does not contain %s[\"%s\"]",
- self->abspath, name_plural, idname))
- {
- /* Spurious errors can appear at shutdown */
- if (PyErr_ExceptionMatches(PyExc_Warning)) {
- PyErr_WriteUnraisable((PyObject *)self);
- }
- }
- PyErr_Restore(exc, val, tb);
-}
-
-static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
-{
- PyObject *exc, *val, *tb;
- PyErr_Fetch(&exc, &val, &tb);
- if (PyErr_WarnFormat(PyExc_UserWarning, 1,
- "load: '%s' expected a string type, not a %.200s",
- self->abspath, Py_TYPE(item)->tp_name))
- {
- /* Spurious errors can appear at shutdown */
- if (PyErr_ExceptionMatches(PyExc_Warning)) {
- PyErr_WriteUnraisable((PyObject *)self);
- }
- }
- PyErr_Restore(exc, val, tb);
-}
-
-static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
-{
- Main *bmain = CTX_data_main(BPy_GetContext());
- Main *mainl = NULL;
- int err = 0;
-
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, true);
-
- /* here appending/linking starts */
- mainl = BLO_library_append_begin(bmain, &(self->blo_handle), self->relpath);
-
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
- if (BKE_idcode_is_linkable(idcode)) {
- const char *name_plural = BKE_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- // printf("lib: %s\n", name_plural);
- if (ls && PyList_Check(ls)) {
- /* loop */
- Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
- PyObject *item;
- const char *item_str;
-
- for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- item_str = _PyUnicode_AsString(item);
-
- // printf(" %s\n", item_str);
-
- if (item_str) {
- ID *id = BLO_library_append_named_part(mainl, &(self->blo_handle), item_str, idcode);
- if (id) {
-#ifdef USE_RNA_DATABLOCKS
- /* swap name for pointer to the id */
- Py_DECREF(item);
- item = PyCapsule_New((void *)id, NULL, NULL);
-#endif
- }
- else {
- bpy_lib_exit_warn_idname(self, name_plural, item_str);
- /* just warn for now */
- /* err = -1; */
-#ifdef USE_RNA_DATABLOCKS
- item = Py_INCREF_RET(Py_None);
-#endif
- }
-
- /* ID or None */
- }
- else {
- /* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item);
- PyErr_Clear();
-
-#ifdef USE_RNA_DATABLOCKS
- item = Py_INCREF_RET(Py_None);
-#endif
- }
-
-#ifdef USE_RNA_DATABLOCKS
- PyList_SET_ITEM(ls, i, item);
-#endif
- }
- }
- }
- }
- }
-
- if (err == -1) {
- /* exception raised above, XXX, this leaks some memory */
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false);
- return NULL;
- }
- else {
- Library *lib = mainl->curlib; /* newly added lib, assign before append end */
- BLO_library_append_end(NULL, mainl, &(self->blo_handle), 0, self->flag);
- BLO_blendhandle_close(self->blo_handle);
- self->blo_handle = NULL;
-
- /* copied from wm_operator.c */
- {
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(G.main);
-
- /* append, rather than linking */
- if ((self->flag & FILE_LINK) == 0) {
- BKE_library_make_local(bmain, lib, true);
- }
- }
-
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false);
-
- /* finally swap the capsules for real bpy objects
- * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
- {
- int idcode_step = 0, idcode;
- while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
- if (BKE_idcode_is_linkable(idcode)) {
- const char *name_plural = BKE_idcode_to_name_plural(idcode);
- PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
- if (ls && PyList_Check(ls)) {
- Py_ssize_t size = PyList_GET_SIZE(ls);
- Py_ssize_t i;
- PyObject *item;
-
- for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- if (PyCapsule_CheckExact(item)) {
- PointerRNA id_ptr;
- ID *id;
-
- id = PyCapsule_GetPointer(item, NULL);
- Py_DECREF(item);
-
- RNA_id_pointer_create(id, &id_ptr);
- item = pyrna_struct_CreatePyObject(&id_ptr);
- PyList_SET_ITEM(ls, i, item);
- }
- }
- }
- }
- }
- }
-
- Py_RETURN_NONE;
- }
-}
-
-static PyObject *bpy_lib_dir(BPy_Library *self)
-{
- return PyDict_Keys(self->dict);
-}
-
-
-int BPY_library_module(PyObject *mod_par)
-{
- static PyMethodDef load_meth = {"load", (PyCFunction)bpy_lib_load,
- METH_STATIC | METH_VARARGS | METH_KEYWORDS,
- bpy_lib_load_doc};
-
- PyModule_AddObject(mod_par, "_library_load", PyCFunction_New(&load_meth, NULL));
-
- /* some compilers don't like accessing this directly, delay assignment */
- bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr;
-
- if (PyType_Ready(&bpy_lib_Type) < 0)
- return -1;
-
- return 0;
-}
diff --git a/source/blender/python/intern/bpy_library.h b/source/blender/python/intern/bpy_library.h
index 1b68007b704..c381a4206fa 100644
--- a/source/blender/python/intern/bpy_library.h
+++ b/source/blender/python/intern/bpy_library.h
@@ -27,6 +27,7 @@
#ifndef __BPY_LIBRARY_H__
#define __BPY_LIBRARY_H__
-int BPY_library_module(PyObject *);
+int BPY_library_load_module(PyObject *mod_par);
+int BPY_library_write_module(PyObject *mod_par);
#endif /* __BPY_LIBRARY_H__ */
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
new file mode 100644
index 00000000000..a120e4886e0
--- /dev/null
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -0,0 +1,481 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_library_load.c
+ * \ingroup pythonintern
+ *
+ * This file exposed blend file library appending/linking to python, typically
+ * this would be done via RNA api but in this case a hand written python api
+ * allows us to use pythons context manager (__enter__ and __exit__).
+ *
+ * Everything here is exposed via bpy.data.libraries.load(...) which returns
+ * a context manager.
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_linklist.h"
+#include "BLI_path_util.h"
+
+#include "BLO_readfile.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_idcode.h"
+#include "BKE_report.h"
+#include "BKE_context.h"
+
+#include "DNA_space_types.h" /* FILE_LINK, FILE_RELPATH */
+
+#include "bpy_util.h"
+#include "bpy_library.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+/* nifty feature. swap out strings for RNA data */
+#define USE_RNA_DATABLOCKS
+
+#ifdef USE_RNA_DATABLOCKS
+# include "bpy_rna.h"
+# include "RNA_access.h"
+#endif
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ /* collection iterator specific parts */
+ char relpath[FILE_MAX];
+ char abspath[FILE_MAX]; /* absolute path */
+ BlendHandle *blo_handle;
+ int flag;
+ PyObject *dict;
+} BPy_Library;
+
+static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds);
+static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args);
+static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args);
+static PyObject *bpy_lib_dir(BPy_Library *self);
+
+static PyMethodDef bpy_lib_methods[] = {
+ {"__enter__", (PyCFunction)bpy_lib_enter, METH_NOARGS},
+ {"__exit__", (PyCFunction)bpy_lib_exit, METH_VARARGS},
+ {"__dir__", (PyCFunction)bpy_lib_dir, METH_NOARGS},
+ {NULL} /* sentinel */
+};
+
+static void bpy_lib_dealloc(BPy_Library *self)
+{
+ Py_XDECREF(self->dict);
+ Py_TYPE(self)->tp_free(self);
+}
+
+
+static PyTypeObject bpy_lib_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "bpy_lib", /* tp_name */
+ sizeof(BPy_Library), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)bpy_lib_dealloc, /* tp_dealloc */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
+ NULL, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+
+ /* will only use these if this is a subtype of a py class */
+ NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* subclassed */ /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0,
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ bpy_lib_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ offsetof(BPy_Library, dict), /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+PyDoc_STRVAR(bpy_lib_load_doc,
+".. method:: load(filepath, link=False, relative=False)\n"
+"\n"
+" Returns a context manager which exposes 2 library objects on entering.\n"
+" Each object has attributes matching bpy.data which are lists of strings to be linked.\n"
+"\n"
+" :arg filepath: The path to a blend file.\n"
+" :type filepath: string\n"
+" :arg link: When False reference to the original file is lost.\n"
+" :type link: bool\n"
+" :arg relative: When True the path is stored relative to the open blend file.\n"
+" :type relative: bool\n"
+);
+static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {"filepath", "link", "relative", NULL};
+ BPy_Library *ret;
+ const char *filename = NULL;
+ bool is_rel = false, is_link = false;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds,
+ "s|O&O&:load", (char **)kwlist,
+ &filename,
+ PyC_ParseBool, &is_link,
+ PyC_ParseBool, &is_rel))
+ {
+ return NULL;
+ }
+
+ ret = PyObject_New(BPy_Library, &bpy_lib_Type);
+
+ BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
+ BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
+ BLI_path_abs(ret->abspath, G.main->name);
+
+ ret->blo_handle = NULL;
+ ret->flag = ((is_link ? FILE_LINK : 0) |
+ (is_rel ? FILE_RELPATH : 0));
+
+ ret->dict = PyDict_New();
+
+ return (PyObject *)ret;
+}
+
+static PyObject *_bpy_names(BPy_Library *self, int blocktype)
+{
+ PyObject *list;
+ LinkNode *l, *names;
+ int totnames;
+
+ names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames);
+
+ if (names) {
+ int counter = 0;
+ list = PyList_New(totnames);
+ for (l = names; l; l = l->next) {
+ PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link));
+ counter++;
+ }
+ BLI_linklist_free(names, free); /* free linklist *and* each node's data */
+ }
+ else {
+ list = PyList_New(0);
+ }
+
+ return list;
+}
+
+static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
+{
+ PyObject *ret;
+ BPy_Library *self_from;
+ PyObject *from_dict = PyDict_New();
+ ReportList reports;
+
+ BKE_reports_init(&reports, RPT_STORE);
+
+ self->blo_handle = BLO_blendhandle_from_file(self->abspath, &reports);
+
+ if (self->blo_handle == NULL) {
+ if (BPy_reports_to_error(&reports, PyExc_IOError, true) != -1) {
+ PyErr_Format(PyExc_IOError,
+ "load: %s failed to open blend file",
+ self->abspath);
+ }
+ return NULL;
+ }
+ else {
+ int i = 0, code;
+ while ((code = BKE_idcode_iter_step(&i))) {
+ if (BKE_idcode_is_linkable(code)) {
+ const char *name_plural = BKE_idcode_to_name_plural(code);
+ PyObject *str = PyUnicode_FromString(name_plural);
+ PyDict_SetItem(self->dict, str, PyList_New(0));
+ PyDict_SetItem(from_dict, str, _bpy_names(self, code));
+ Py_DECREF(str);
+ }
+ }
+ }
+
+ /* create a dummy */
+ self_from = PyObject_New(BPy_Library, &bpy_lib_Type);
+ BLI_strncpy(self_from->relpath, self->relpath, sizeof(self_from->relpath));
+ BLI_strncpy(self_from->abspath, self->abspath, sizeof(self_from->abspath));
+
+ self_from->blo_handle = NULL;
+ self_from->flag = 0;
+ self_from->dict = from_dict; /* owns the dict */
+
+ /* return pair */
+ ret = PyTuple_New(2);
+ PyTuple_SET_ITEMS(ret,
+ (PyObject *)self_from,
+ (PyObject *)self);
+ Py_INCREF(self);
+
+ BKE_reports_clear(&reports);
+
+ return ret;
+}
+
+static void bpy_lib_exit_warn_idname(BPy_Library *self, const char *name_plural, const char *idname)
+{
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ if (PyErr_WarnFormat(PyExc_UserWarning, 1,
+ "load: '%s' does not contain %s[\"%s\"]",
+ self->abspath, name_plural, idname))
+ {
+ /* Spurious errors can appear at shutdown */
+ if (PyErr_ExceptionMatches(PyExc_Warning)) {
+ PyErr_WriteUnraisable((PyObject *)self);
+ }
+ }
+ PyErr_Restore(exc, val, tb);
+}
+
+static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item)
+{
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ if (PyErr_WarnFormat(PyExc_UserWarning, 1,
+ "load: '%s' expected a string type, not a %.200s",
+ self->abspath, Py_TYPE(item)->tp_name))
+ {
+ /* Spurious errors can appear at shutdown */
+ if (PyErr_ExceptionMatches(PyExc_Warning)) {
+ PyErr_WriteUnraisable((PyObject *)self);
+ }
+ }
+ PyErr_Restore(exc, val, tb);
+}
+
+static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
+{
+ Main *bmain = CTX_data_main(BPy_GetContext());
+ Main *mainl = NULL;
+ int err = 0;
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* here appending/linking starts */
+ mainl = BLO_library_link_begin(bmain, &(self->blo_handle), self->relpath);
+
+ {
+ int idcode_step = 0, idcode;
+ while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
+ if (BKE_idcode_is_linkable(idcode)) {
+ const char *name_plural = BKE_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ // printf("lib: %s\n", name_plural);
+ if (ls && PyList_Check(ls)) {
+ /* loop */
+ Py_ssize_t size = PyList_GET_SIZE(ls);
+ Py_ssize_t i;
+ PyObject *item;
+ const char *item_str;
+
+ for (i = 0; i < size; i++) {
+ item = PyList_GET_ITEM(ls, i);
+ item_str = _PyUnicode_AsString(item);
+
+ // printf(" %s\n", item_str);
+
+ if (item_str) {
+ ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_str);
+ if (id) {
+#ifdef USE_RNA_DATABLOCKS
+ /* swap name for pointer to the id */
+ Py_DECREF(item);
+ item = PyCapsule_New((void *)id, NULL, NULL);
+#endif
+ }
+ else {
+ bpy_lib_exit_warn_idname(self, name_plural, item_str);
+ /* just warn for now */
+ /* err = -1; */
+#ifdef USE_RNA_DATABLOCKS
+ item = Py_INCREF_RET(Py_None);
+#endif
+ }
+
+ /* ID or None */
+ }
+ else {
+ /* XXX, could complain about this */
+ bpy_lib_exit_warn_type(self, item);
+ PyErr_Clear();
+
+#ifdef USE_RNA_DATABLOCKS
+ item = Py_INCREF_RET(Py_None);
+#endif
+ }
+
+#ifdef USE_RNA_DATABLOCKS
+ PyList_SET_ITEM(ls, i, item);
+#endif
+ }
+ }
+ }
+ }
+ }
+
+ if (err == -1) {
+ /* exception raised above, XXX, this leaks some memory */
+ BLO_blendhandle_close(self->blo_handle);
+ self->blo_handle = NULL;
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+ return NULL;
+ }
+ else {
+ Library *lib = mainl->curlib; /* newly added lib, assign before append end */
+ BLO_library_link_end(mainl, &(self->blo_handle), self->flag, NULL, NULL);
+ BLO_blendhandle_close(self->blo_handle);
+ self->blo_handle = NULL;
+
+ /* copied from wm_operator.c */
+ {
+ /* mark all library linked objects to be updated */
+ BKE_main_lib_objects_recalc_all(G.main);
+
+ /* append, rather than linking */
+ if ((self->flag & FILE_LINK) == 0) {
+ BKE_library_make_local(bmain, lib, true, false);
+ }
+ }
+
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* finally swap the capsules for real bpy objects
+ * important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+ {
+ int idcode_step = 0, idcode;
+ while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
+ if (BKE_idcode_is_linkable(idcode)) {
+ const char *name_plural = BKE_idcode_to_name_plural(idcode);
+ PyObject *ls = PyDict_GetItemString(self->dict, name_plural);
+ if (ls && PyList_Check(ls)) {
+ Py_ssize_t size = PyList_GET_SIZE(ls);
+ Py_ssize_t i;
+ PyObject *item;
+
+ for (i = 0; i < size; i++) {
+ item = PyList_GET_ITEM(ls, i);
+ if (PyCapsule_CheckExact(item)) {
+ PointerRNA id_ptr;
+ ID *id;
+
+ id = PyCapsule_GetPointer(item, NULL);
+ Py_DECREF(item);
+
+ RNA_id_pointer_create(id, &id_ptr);
+ item = pyrna_struct_CreatePyObject(&id_ptr);
+ PyList_SET_ITEM(ls, i, item);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Py_RETURN_NONE;
+ }
+}
+
+static PyObject *bpy_lib_dir(BPy_Library *self)
+{
+ return PyDict_Keys(self->dict);
+}
+
+
+int BPY_library_load_module(PyObject *mod_par)
+{
+ static PyMethodDef load_meth = {
+ "load", (PyCFunction)bpy_lib_load,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_lib_load_doc,
+ };
+ PyModule_AddObject(mod_par, "_library_load", PyCFunction_New(&load_meth, NULL));
+
+ /* some compilers don't like accessing this directly, delay assignment */
+ bpy_lib_Type.tp_getattro = PyObject_GenericGetAttr;
+
+ if (PyType_Ready(&bpy_lib_Type) < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
new file mode 100644
index 00000000000..ab239bbfa8c
--- /dev/null
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -0,0 +1,215 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_library_write.c
+ * \ingroup pythonintern
+ *
+ * Python API for writing a set of data-blocks into a file.
+ * Useful for writing out asset-libraries, defines: `bpy.data.libraries.write(...)`.
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_path_util.h"
+
+#include "BKE_library.h"
+#include "BKE_blender.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "RNA_types.h"
+
+#include "bpy_rna.h"
+#include "bpy_util.h"
+#include "bpy_library.h"
+
+#include "../generic/py_capi_utils.h"
+
+
+PyDoc_STRVAR(bpy_lib_write_doc,
+".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False)\n"
+"\n"
+" Write data-blocks into a blend file.\n"
+"\n"
+" .. note::\n"
+"\n"
+" Indirectly referenced data-blocks will be expanded and written too.\n"
+"\n"
+" :arg filepath: The path to write the blend-file.\n"
+" :type filepath: string\n"
+" :arg datablocks: set of data-blocks (:class:`bpy.types.ID` instances).\n"
+" :type datablocks: set\n"
+" :arg relative_remap: When True, remap the paths relative to the current blend-file.\n"
+" :type relative_remap: bool\n"
+" :arg fake_user: When True, data-blocks will be written with fake-user flag enabled.\n"
+" :type fake_user: bool\n"
+);
+static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {
+ "filepath", "datablocks",
+ /* optional */
+ "relative_remap", "fake_user",
+ NULL,
+ };
+
+ /* args */
+ const char *filepath;
+ char filepath_abs[FILE_MAX];
+ PyObject *datablocks = NULL;
+ bool use_relative_remap = false, use_fake_user = false;
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds,
+ "sO!|$O&O&:write", (char **)kwlist,
+ &filepath,
+ &PySet_Type, &datablocks,
+ PyC_ParseBool, &use_relative_remap,
+ PyC_ParseBool, &use_fake_user))
+ {
+ return NULL;
+ }
+
+ Main *bmain_src = G.main;
+ int write_flags = 0;
+
+ if (use_relative_remap) {
+ write_flags |= G_FILE_RELATIVE_REMAP;
+ }
+
+ BLI_strncpy(filepath_abs, filepath, FILE_MAX);
+ BLI_path_abs(filepath_abs, G.main->name);
+
+ BKE_blendfile_write_partial_begin(bmain_src);
+
+ /* array of ID's and backup any data we modify */
+ struct {
+ ID *id;
+ /* original values */
+ short id_flag;
+ short id_us;
+ } *id_store_array, *id_store;
+ int id_store_len = 0;
+
+ PyObject *ret;
+
+ /* collect all id data from the set and store in 'id_store_array' */
+ {
+ Py_ssize_t pos, hash;
+ PyObject *key;
+
+ id_store_array = MEM_mallocN(sizeof(*id_store_array) * PySet_Size(datablocks), __func__);
+ id_store = id_store_array;
+
+ pos = hash = 0;
+ while (_PySet_NextEntry(datablocks, &pos, &key, &hash)) {
+
+ if (!pyrna_id_FromPyObject(key, &id_store->id)) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected and ID type, not %.200s",
+ Py_TYPE(key)->tp_name);
+ ret = NULL;
+ goto finally;
+ }
+ else {
+ id_store->id_flag = id_store->id->flag;
+ id_store->id_us = id_store->id->us;
+
+ if (use_fake_user) {
+ id_store->id->flag |= LIB_FAKEUSER;
+ }
+ id_store->id->us = 1;
+
+ BKE_blendfile_write_partial_tag_ID(id_store->id, true);
+
+ id_store_len += 1;
+ id_store++;
+ }
+ }
+ }
+
+ /* write blend */
+ int retval = 0;
+ ReportList reports;
+
+ BKE_reports_init(&reports, RPT_STORE);
+
+ retval = BKE_blendfile_write_partial(bmain_src, filepath_abs, write_flags, &reports);
+
+ /* cleanup state */
+ BKE_blendfile_write_partial_end(bmain_src);
+
+ if (retval) {
+ BKE_reports_print(&reports, RPT_ERROR_ALL);
+ BKE_reports_clear(&reports);
+ ret = Py_None;
+ Py_INCREF(ret);
+ }
+ else {
+ if (BPy_reports_to_error(&reports, PyExc_IOError, true) == 0) {
+ PyErr_SetString(PyExc_IOError, "Unknown error writing library data");
+ }
+ ret = NULL;
+ }
+
+
+finally:
+
+ /* clear all flags for ID's added to the store (may run on error too) */
+ id_store = id_store_array;
+
+ for (int i = 0; i < id_store_len; id_store++, i++) {
+
+
+ if (use_fake_user) {
+ if ((id_store->id_flag & LIB_FAKEUSER) == 0) {
+ id_store->id->flag &= ~LIB_FAKEUSER;
+ }
+ }
+
+ id_store->id->us = id_store->id_us;
+
+ BKE_blendfile_write_partial_tag_ID(id_store->id, false);
+ }
+
+ MEM_freeN(id_store_array);
+
+ return ret;
+}
+
+
+int BPY_library_write_module(PyObject *mod_par)
+{
+ static PyMethodDef write_meth = {
+ "write", (PyCFunction)bpy_lib_write,
+ METH_STATIC | METH_VARARGS | METH_KEYWORDS,
+ bpy_lib_write_doc,
+ };
+
+ PyModule_AddObject(mod_par, "_library_write", PyCFunction_New(&write_meth, NULL));
+
+ return 0;
+}
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 7cccc204088..d6c57f4c302 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -98,8 +98,8 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
}
if (context_str) {
- if (RNA_enum_value_from_id(operator_context_items, context_str, &context) == 0) {
- char *enum_str = BPy_enum_as_string(operator_context_items);
+ if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) {
+ char *enum_str = BPy_enum_as_string(rna_enum_operator_context_items);
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s.poll\" error, "
"expected a string enum in (%s)",
@@ -184,8 +184,8 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
}
if (context_str) {
- if (RNA_enum_value_from_id(operator_context_items, context_str, &context) == 0) {
- char *enum_str = BPy_enum_as_string(operator_context_items);
+ if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) {
+ char *enum_str = BPy_enum_as_string(rna_enum_operator_context_items);
PyErr_Format(PyExc_TypeError,
"Calling operator \"bpy.ops.%s\" error, "
"expected a string enum in (%s)",
@@ -301,7 +301,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
bpy_import_main_set(CTX_data_main(C));
/* return operator_ret as a bpy enum */
- return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret);
+ return pyrna_enum_bitfield_to_py(rna_enum_operator_return_items, operator_ret);
}
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 19ded7fb4f3..bce1d923462 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -85,7 +85,7 @@ static EnumPropertyItem property_flag_enum_items[] = {
" :type options: set\n" \
/* subtypes */
-/* XXX Keep in sync with rna_rna.c's property_subtype_items ???
+/* XXX Keep in sync with rna_rna.c's rna_enum_property_subtype_items ???
* Currently it is not...
*/
static EnumPropertyItem property_subtype_string_items[] = {
@@ -1304,7 +1304,7 @@ static int icon_id_from_name(const char *name)
int id;
if (name[0]) {
- for (item = icon_items, id = 0; item->identifier; item++, id++) {
+ for (item = rna_enum_icon_items, id = 0; item->identifier; item++, id++) {
if (STREQ(item->name, name)) {
return item->value;
}
@@ -1314,7 +1314,7 @@ static int icon_id_from_name(const char *name)
return 0;
}
-static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, int *defvalue, const short is_enum_flag)
+static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, int *defvalue, const bool is_enum_flag)
{
EnumPropertyItem *items;
PyObject *item;
@@ -2376,7 +2376,7 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
BPY_PROPDEF_SUBTYPE_CHECK(FloatProperty, property_flag_items, property_subtype_number_items);
- if (pyunit && RNA_enum_value_from_id(property_unit_items, pyunit, &unit) == 0) {
+ if (pyunit && RNA_enum_value_from_id(rna_enum_property_unit_items, pyunit, &unit) == 0) {
PyErr_Format(PyExc_TypeError, "FloatProperty(unit='%s'): invalid unit", pyunit);
return NULL;
}
@@ -2489,7 +2489,7 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
BPY_PROPDEF_SUBTYPE_CHECK(FloatVectorProperty, property_flag_items, property_subtype_array_items);
- if (pyunit && RNA_enum_value_from_id(property_unit_items, pyunit, &unit) == 0) {
+ if (pyunit && RNA_enum_value_from_id(rna_enum_property_unit_items, pyunit, &unit) == 0) {
PyErr_Format(PyExc_TypeError, "FloatVectorProperty(unit='%s'): invalid unit", pyunit);
return NULL;
}
@@ -2630,7 +2630,7 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" [(identifier, name, description, icon, number), ...] where the identifier is used\n"
" for python access and other values are used for the interface.\n"
" The three first elements of the tuples are mandatory.\n"
-" The forth one is either the (unique!) number id of the item or, if followed by a fith element\n"
+" The fourth one is either the (unique!) number id of the item or, if followed by a fith element\n"
" (which must be the numid), an icon string identifier or integer icon value (e.g. returned by icon()...).\n"
" Note the item is optional.\n"
" For dynamic values a callback can be passed which returns a list in\n"
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 5414c4e4204..33ac58dadb1 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -37,6 +37,7 @@
#include "RNA_types.h"
+#include "BLI_bitmap.h"
#include "BLI_dynstr.h"
#include "BLI_string.h"
#include "BLI_listbase.h"
@@ -920,7 +921,7 @@ static PyObject *pyrna_prop_str(BPy_PropertyRNA *self)
type = RNA_property_type(self->prop);
- if (RNA_enum_id_from_value(property_type_items, type, &type_id) == 0) {
+ if (RNA_enum_id_from_value(rna_enum_property_type_items, type, &type_id) == 0) {
PyErr_SetString(PyExc_RuntimeError, "could not use property type, internal error"); /* should never happen */
return NULL;
}
@@ -1176,6 +1177,69 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr
return 0;
}
+/**
+ * Takes a set of strings and map it to and array of booleans.
+ *
+ * Useful when the values aren't flags.
+ *
+ * \param type_convert_sign: Maps signed to unsigned range,
+ * needed when we want to use the full range of a signed short/char.
+ */
+BLI_bitmap *pyrna_set_to_enum_bitmap(
+ EnumPropertyItem *items, PyObject *value,
+ int type_size, bool type_convert_sign,
+ int bitmap_size,
+ const char *error_prefix)
+{
+ /* set looping */
+ Py_ssize_t pos = 0;
+ Py_ssize_t hash = 0;
+ PyObject *key;
+
+ BLI_bitmap *bitmap = BLI_BITMAP_NEW(bitmap_size, __func__);
+
+ while (_PySet_NextEntry(value, &pos, &key, &hash)) {
+ const char *param = _PyUnicode_AsString(key);
+ if (param == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s expected a string, not %.200s",
+ error_prefix, Py_TYPE(key)->tp_name);
+ goto error;
+ }
+
+ int ret;
+ if (pyrna_enum_value_from_id(items, param, &ret, error_prefix) == -1) {
+ goto error;
+ }
+
+ int index = ret;
+
+ if (type_convert_sign) {
+ if (type_size == 2) {
+ union { signed short as_signed; unsigned short as_unsigned; } ret_convert;
+ ret_convert.as_signed = (signed short)ret;
+ index = (int)ret_convert.as_unsigned;
+ }
+ else if (type_size == 1) {
+ union { signed char as_signed; unsigned char as_unsigned; } ret_convert;
+ ret_convert.as_signed = (signed char)ret;
+ index = (int)ret_convert.as_unsigned;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ BLI_assert(index < bitmap_size);
+ BLI_BITMAP_ENABLE(bitmap, index);
+ }
+
+ return bitmap;
+
+error:
+ MEM_freeN(bitmap);
+ return NULL;
+}
+
/* 'value' _must_ be a set type, error check before calling */
int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix)
{
@@ -1303,27 +1367,32 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
ret = PyUnicode_FromString(enum_item->identifier);
}
else {
- const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
-
- /* prefer not fail silently in case of api errors, maybe disable it later */
- printf("RNA Warning: Current value \"%d\" "
- "matches no enum in '%s', '%s', '%s'\n",
- val, RNA_struct_identifier(ptr->type),
- ptr_name, RNA_property_identifier(prop));
-
-#if 0 /* gives python decoding errors while generating docs :( */
- char error_str[256];
- BLI_snprintf(error_str, sizeof(error_str),
- "RNA Warning: Current value \"%d\" "
- "matches no enum in '%s', '%s', '%s'",
- val, RNA_struct_identifier(ptr->type),
- ptr_name, RNA_property_identifier(prop));
-
- PyErr_Warn(PyExc_RuntimeWarning, error_str);
+ RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free);
+
+ /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */
+ if (enum_item != DummyRNA_NULL_items) {
+ const char *ptr_name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL);
+
+ /* prefer not fail silently in case of api errors, maybe disable it later */
+ printf("RNA Warning: Current value \"%d\" "
+ "matches no enum in '%s', '%s', '%s'\n",
+ val, RNA_struct_identifier(ptr->type),
+ ptr_name, RNA_property_identifier(prop));
+
+#if 0 /* gives python decoding errors while generating docs :( */
+ char error_str[256];
+ BLI_snprintf(error_str, sizeof(error_str),
+ "RNA Warning: Current value \"%d\" "
+ "matches no enum in '%s', '%s', '%s'",
+ val, RNA_struct_identifier(ptr->type),
+ ptr_name, RNA_property_identifier(prop));
+
+ PyErr_Warn(PyExc_RuntimeWarning, error_str);
#endif
- if (ptr_name)
- MEM_freeN((void *)ptr_name);
+ if (ptr_name)
+ MEM_freeN((void *)ptr_name);
+ }
ret = PyUnicode_FromString("");
}
@@ -2633,13 +2702,147 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject
}
}
+/**
+ * Helpers for #prop_subscript_ass_array_slice
+ */
+
+static PyObject *prop_subscript_ass_array_slice__as_seq_fast(PyObject *value, int length)
+{
+ PyObject *value_fast;
+ if (!(value_fast = PySequence_Fast(
+ value,
+ "bpy_prop_array[slice] = value: "
+ "element in assignment is not a sequence type")))
+ {
+ return NULL;
+ }
+ else if (PySequence_Fast_GET_SIZE(value_fast) != length) {
+ Py_DECREF(value_fast);
+ PyErr_SetString(
+ PyExc_ValueError,
+ "bpy_prop_array[slice] = value: "
+ "re-sizing bpy_struct element in arrays isn't supported");
+
+ return NULL;
+ }
+ else {
+ return value_fast;
+ }
+}
+
+static int prop_subscript_ass_array_slice__float_recursive(
+ PyObject **value_items, float *value,
+ int totdim, const int dimsize[],
+ const float range[2])
+{
+ const int length = dimsize[0];
+ if (totdim > 1) {
+ int index = 0;
+ int i;
+ for (i = 0; i != length; i++) {
+ PyObject *subvalue = prop_subscript_ass_array_slice__as_seq_fast(value_items[i], dimsize[1]);
+ if (UNLIKELY(subvalue == NULL)) {
+ return 0;
+ }
+
+ index += prop_subscript_ass_array_slice__float_recursive(
+ PySequence_Fast_ITEMS(subvalue), &value[index],
+ totdim - 1, &dimsize[1], range);
+
+ Py_DECREF(subvalue);
+ }
+ return index;
+ }
+ else {
+ BLI_assert(totdim == 1);
+ const float min = range[0], max = range[1];
+ int i;
+ for (i = 0; i != length; i++) {
+ float v = PyFloat_AsDouble(value_items[i]);
+ CLAMP(v, min, max);
+ value[i] = v;
+ }
+ return i;
+ }
+}
+
+static int prop_subscript_ass_array_slice__int_recursive(
+ PyObject **value_items, int *value,
+ int totdim, const int dimsize[],
+ const int range[2])
+{
+ const int length = dimsize[0];
+ if (totdim > 1) {
+ int index = 0;
+ int i;
+ for (i = 0; i != length; i++) {
+ PyObject *subvalue = prop_subscript_ass_array_slice__as_seq_fast(value_items[i], dimsize[1]);
+ if (UNLIKELY(subvalue == NULL)) {
+ return 0;
+ }
+
+ index += prop_subscript_ass_array_slice__int_recursive(
+ PySequence_Fast_ITEMS(subvalue), &value[index],
+ totdim - 1, &dimsize[1], range);
+
+ Py_DECREF(subvalue);
+ }
+ return index;
+ }
+ else {
+ BLI_assert(totdim == 1);
+ const int min = range[0], max = range[1];
+ int i;
+ for (i = 0; i != length; i++) {
+ int v = PyLong_AsLong(value_items[i]);
+ CLAMP(v, min, max);
+ value[i] = v;
+ }
+ return i;
+ }
+}
+
+static int prop_subscript_ass_array_slice__bool_recursive(
+ PyObject **value_items, int *value,
+ int totdim, const int dimsize[])
+{
+ const int length = dimsize[0];
+ if (totdim > 1) {
+ int index = 0;
+ int i;
+ for (i = 0; i != length; i++) {
+ PyObject *subvalue = prop_subscript_ass_array_slice__as_seq_fast(value_items[i], dimsize[1]);
+ if (UNLIKELY(subvalue == NULL)) {
+ return 0;
+ }
+
+ index += prop_subscript_ass_array_slice__bool_recursive(
+ PySequence_Fast_ITEMS(subvalue), &value[index],
+ totdim - 1, &dimsize[1]);
+
+ Py_DECREF(subvalue);
+ }
+ return index;
+ }
+ else {
+ BLI_assert(totdim == 1);
+ int i;
+ for (i = 0; i != length; i++) {
+ int v = PyLong_AsLong(value_items[i]);
+ value[i] = v;
+ }
+ return i;
+ }
+}
+
/* could call (pyrna_py_to_prop_array_index(self, i, value) in a loop but it is slow */
-static int prop_subscript_ass_array_slice(PointerRNA *ptr, PropertyRNA *prop,
- int start, int stop, int length, PyObject *value_orig)
+static int prop_subscript_ass_array_slice(
+ PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset,
+ int start, int stop, int length, PyObject *value_orig)
{
+ const int length_flat = RNA_property_array_length(ptr, prop);
PyObject *value;
PyObject **value_items;
- int count;
void *values_alloc = NULL;
int ret = 0;
@@ -2660,70 +2863,85 @@ static int prop_subscript_ass_array_slice(PointerRNA *ptr, PropertyRNA *prop,
return -1;
}
+ int dimsize[3];
+ int totdim = RNA_property_array_dimension(ptr, prop, dimsize);
+ if (totdim > 1) {
+ BLI_assert(dimsize[arraydim] == length);
+ }
+
+ int span = 1;
+ if (totdim > 1) {
+ for (int i = arraydim + 1; i < totdim; i++) {
+ span *= dimsize[i];
+ }
+ }
+
value_items = PySequence_Fast_ITEMS(value);
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
{
float values_stack[PYRNA_STACK_ARRAY];
- float *values, fval;
-
- float min, max;
- RNA_property_float_range(ptr, prop, &min, &max);
-
- if (length > PYRNA_STACK_ARRAY) { values = values_alloc = PyMem_MALLOC(sizeof(float) * length); }
- else { values = values_stack; }
- if (start != 0 || stop != length) /* partial assignment? - need to get the array */
+ float *values = (length_flat > PYRNA_STACK_ARRAY) ?
+ (values_alloc = PyMem_MALLOC(sizeof(*values) * length_flat)) : values_stack;
+ if (start != 0 || stop != length) {
+ /* partial assignment? - need to get the array */
RNA_property_float_get_array(ptr, prop, values);
-
- for (count = start; count < stop; count++) {
- fval = PyFloat_AsDouble(value_items[count - start]);
- CLAMP(fval, min, max);
- values[count] = fval;
}
+ float range[2];
+ RNA_property_float_range(ptr, prop, &range[0], &range[1]);
+
+ dimsize[arraydim] = stop - start;
+ prop_subscript_ass_array_slice__float_recursive(
+ value_items, &values[arrayoffset + (start * span)],
+ totdim - arraydim, &dimsize[arraydim],
+ range);
+
if (PyErr_Occurred()) ret = -1;
else RNA_property_float_set_array(ptr, prop, values);
break;
}
- case PROP_BOOLEAN:
+ case PROP_INT:
{
int values_stack[PYRNA_STACK_ARRAY];
- int *values;
- if (length > PYRNA_STACK_ARRAY) { values = values_alloc = PyMem_MALLOC(sizeof(int) * length); }
- else { values = values_stack; }
+ int *values = (length_flat > PYRNA_STACK_ARRAY) ?
+ (values_alloc = PyMem_MALLOC(sizeof(*values) * length_flat)) : values_stack;
+ if (start != 0 || stop != length) {
+ /* partial assignment? - need to get the array */
+ RNA_property_int_get_array(ptr, prop, values);
+ }
- if (start != 0 || stop != length) /* partial assignment? - need to get the array */
- RNA_property_boolean_get_array(ptr, prop, values);
+ int range[2];
+ RNA_property_int_range(ptr, prop, &range[0], &range[1]);
- for (count = start; count < stop; count++)
- values[count] = PyLong_AsLong(value_items[count - start]);
+ dimsize[arraydim] = stop - start;
+ prop_subscript_ass_array_slice__int_recursive(
+ value_items, &values[arrayoffset + (start * span)],
+ totdim - arraydim, &dimsize[arraydim],
+ range);
if (PyErr_Occurred()) ret = -1;
- else RNA_property_boolean_set_array(ptr, prop, values);
+ else RNA_property_int_set_array(ptr, prop, values);
break;
}
- case PROP_INT:
+ case PROP_BOOLEAN:
{
int values_stack[PYRNA_STACK_ARRAY];
- int *values, ival;
-
- int min, max;
- RNA_property_int_range(ptr, prop, &min, &max);
+ int *values = (length_flat > PYRNA_STACK_ARRAY) ?
+ (values_alloc = PyMem_MALLOC(sizeof(*values) * length_flat)) : values_stack;
- if (length > PYRNA_STACK_ARRAY) { values = values_alloc = PyMem_MALLOC(sizeof(int) * length); }
- else { values = values_stack; }
-
- if (start != 0 || stop != length) /* partial assignment? - need to get the array */
- RNA_property_int_get_array(ptr, prop, values);
-
- for (count = start; count < stop; count++) {
- ival = PyLong_AsLong(value_items[count - start]);
- CLAMP(ival, min, max);
- values[count] = ival;
+ if (start != 0 || stop != length) {
+ /* partial assignment? - need to get the array */
+ RNA_property_boolean_get_array(ptr, prop, values);
}
+ dimsize[arraydim] = stop - start;
+ prop_subscript_ass_array_slice__bool_recursive(
+ value_items, &values[arrayoffset + (start * span)],
+ totdim - arraydim, &dimsize[arraydim]);
+
if (PyErr_Occurred()) ret = -1;
- else RNA_property_int_set_array(ptr, prop, values);
+ else RNA_property_boolean_set_array(ptr, prop, values);
break;
}
default:
@@ -2784,7 +3002,7 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self, PyObject *
}
}
else if (PySlice_Check(key)) {
- int len = RNA_property_array_length(&self->ptr, self->prop);
+ Py_ssize_t len = pyrna_prop_array_length(self);
Py_ssize_t start, stop, step, slicelength;
if (PySlice_GetIndicesEx(key, len, &start, &stop, &step, &slicelength) < 0) {
@@ -2794,7 +3012,9 @@ static int pyrna_prop_array_ass_subscript(BPy_PropertyArrayRNA *self, PyObject *
ret = 0; /* do nothing */
}
else if (step == 1) {
- ret = prop_subscript_ass_array_slice(&self->ptr, self->prop, start, stop, len, value);
+ ret = prop_subscript_ass_array_slice(
+ &self->ptr, self->prop, self->arraydim, self->arrayoffset,
+ start, stop, len, value);
}
else {
PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna");
@@ -6678,6 +6898,21 @@ PyObject *BPY_rna_types(void)
/* add __name__ since help() expects its */
PyDict_SetItem(pyrna_basetype_Type.tp_dict, bpy_intern_str___name__, bpy_intern_str_bpy_types);
+ /* internal base types we have no other accessors for */
+ {
+ PyTypeObject *pyrna_types[] = {
+ &pyrna_struct_meta_idprop_Type,
+ &pyrna_struct_Type,
+ &pyrna_prop_Type,
+ &pyrna_prop_array_Type,
+ &pyrna_prop_collection_Type,
+ &pyrna_func_Type,
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(pyrna_types); i += 1) {
+ PyDict_SetItemString(pyrna_basetype_Type.tp_dict, pyrna_types[i]->tp_name, (PyObject *)pyrna_types[i]);
+ }
+ }
self = (BPy_BaseTypeRNA *)PyObject_NEW(BPy_BaseTypeRNA, &pyrna_basetype_Type);
@@ -7128,12 +7363,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PointerRNA funcptr;
int err = 0, i, ret_len = 0, arg_count;
int flag = RNA_function_flag(func);
- const char is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
- const char is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
-
- /* annoying!, need to check if the screen gets set to NULL which is a
- * hint that the file was actually re-loaded. */
- char is_valid_wm;
+ const bool is_staticmethod = (flag & FUNC_NO_SELF) && !(flag & FUNC_USE_SELF_TYPE);
+ const bool is_classmethod = (flag & FUNC_NO_SELF) && (flag & FUNC_USE_SELF_TYPE);
PropertyRNA *pret_single = NULL;
void *retdata_single = NULL;
@@ -7160,7 +7391,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
if (C == NULL)
C = BPy_GetContext();
- is_valid_wm = (CTX_wm_manager(C) != NULL);
+ /* annoying!, need to check if the screen gets set to NULL which is a
+ * hint that the file was actually re-loaded. */
+ const bool is_valid_wm = (CTX_wm_manager(C) != NULL);
bpy_context_set(C, &gilstate);
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index f546c2955e5..c5d4a346f56 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -184,6 +184,11 @@ bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix);
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
+unsigned int *pyrna_set_to_enum_bitmap(
+ struct EnumPropertyItem *items, PyObject *value,
+ int type_size, bool type_convert_sign,
+ int bitmap_size,
+ const char *error_prefix);
PyObject *pyrna_enum_bitfield_to_py(struct EnumPropertyItem *items, int value);
int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix);
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index ced7d6a5c1c..2ec73c3c9b7 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -171,7 +171,7 @@ static int pyrna_struct_keyframe_parse(
/* flag may be null (no option currently for remove keyframes e.g.). */
if (options) {
- if (pyoptions && (pyrna_set_to_enum_bitfield(keying_flag_items, pyoptions, options, error_prefix) == -1)) {
+ if (pyoptions && (pyrna_set_to_enum_bitfield(rna_enum_keying_flag_items, pyoptions, options, error_prefix) == -1)) {
return -1;
}
@@ -188,18 +188,19 @@ char pyrna_struct_keyframe_insert_doc[] =
"\n"
" :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
" :type data_path: string\n"
-" :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel "
- "if the property is not an array.\n"
+" :arg index: array index of the property to key.\n"
+" Defaults to -1 which will key all indices or a single channel if the property is not an array.\n"
" :type index: int\n"
" :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n"
" :type frame: float\n"
" :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
" :type group: str\n"
-" :arg options: Some optional flags:\n"
-" 'NEEDED': Only insert keyframes where they're needed in the relevant F-Curves.\n"
-" 'VISUAL': Insert keyframes based on 'visual transforms'.\n"
-" 'XYZ_TO_RGB': Color for newly added transformation F-Curves (Location, Rotation, Scale) "
- "and also Color is based on the transform axis.\n"
+" :arg options: Optional flags:\n"
+"\n"
+" - ``INSERTKEY_NEEDED`` Only insert keyframes where they're needed in the relevant F-Curves.\n"
+" - ``INSERTKEY_VISUAL`` Insert keyframes based on 'visual transforms'.\n"
+" - ``INSERTKEY_XYZ_TO_RGB`` Color for newly added transformation F-Curves (Location, Rotation, Scale)\n"
+" and also Color is based on the transform axis.\n"
" :type flag: set\n"
" :return: Success of keyframe insertion.\n"
" :rtype: boolean\n"
@@ -211,6 +212,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
int index = -1;
float cfra = FLT_MAX;
const char *group_name = NULL;
+ char keytype = BEZT_KEYTYPE_KEYFRAME; /* XXX: Expose this as a one-off option... */
int options = 0;
PYRNA_STRUCT_CHECK_OBJ(self);
@@ -227,7 +229,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
BKE_reports_init(&reports, RPT_STORE);
- result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, options);
+ result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, keytype, options);
MEM_freeN((void *)path_full);
if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c
index 033f8a3f3ec..38931cd85de 100644
--- a/source/blender/python/intern/bpy_rna_array.c
+++ b/source/blender/python/intern/bpy_rna_array.c
@@ -46,11 +46,32 @@
#define MAX_ARRAY_DIMENSION 10
-typedef void (*ItemConvertFunc)(PyObject *, char *);
+struct ItemConvertArgData;
+
+typedef void (*ItemConvertFunc)(const struct ItemConvertArgData *arg, PyObject *, char *);
typedef int (*ItemTypeCheckFunc)(PyObject *);
typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
+struct ItemConvertArgData {
+ union {
+ struct {
+ int range[2];
+ } int_data;
+ struct {
+ float range[2];
+ } float_data;
+ };
+};
+
+/**
+ * Callback and args needed to apply the value (clamp range for now)
+ */
+typedef struct ItemConvert_FuncArg {
+ ItemConvertFunc func;
+ struct ItemConvertArgData arg;
+} ItemConvert_FuncArg;
+
/*
* arr[3][4][5]
* 0 1 2 <- dimension index
@@ -328,28 +349,31 @@ static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop,
}
}
-static char *copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop,
- char *data, unsigned int item_size, int *index,
- ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
+static char *copy_value_single(
+ PyObject *item, PointerRNA *ptr, PropertyRNA *prop,
+ char *data, unsigned int item_size, int *index,
+ const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index)
{
if (!data) {
- char value[sizeof(int)];
+ union { float fl; int i; } value_buf;
+ char *value = (void *)&value_buf;
- convert_item(item, value);
+ convert_item->func(&convert_item->arg, item, value);
rna_set_index(ptr, prop, *index, value);
- *index = *index + 1;
+ (*index) += 1;
}
else {
- convert_item(item, data);
+ convert_item->func(&convert_item->arg, item, data);
data += item_size;
}
return data;
}
-static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
- int dim, char *data, unsigned int item_size, int *index,
- ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
+static char *copy_values(
+ PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
+ int dim, char *data, unsigned int item_size, int *index,
+ const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index)
{
int totdim = RNA_property_array_dimension(ptr, prop, NULL);
const Py_ssize_t seq_size = PySequence_Size(seq);
@@ -410,9 +434,10 @@ static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
return data;
}
-static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
- char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size,
- ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
+static int py_to_array(
+ PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
+ char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size,
+ const ItemConvert_FuncArg *convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
{
/*int totdim, dim_size[MAX_ARRAY_DIMENSION];*/
int totitem;
@@ -464,10 +489,11 @@ static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop,
return 0;
}
-static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
- int lvalue_dim, int arrayoffset, int index,
- ItemTypeCheckFunc check_item_type, const char *item_type_str,
- ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
+static int py_to_array_index(
+ PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
+ int lvalue_dim, int arrayoffset, int index,
+ ItemTypeCheckFunc check_item_type, const char *item_type_str,
+ const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
{
int totdim, dimsize[MAX_ARRAY_DIMENSION];
int totitem, i;
@@ -513,17 +539,23 @@ static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop,
return 0;
}
-static void py_to_float(PyObject *py, char *data)
+static void py_to_float(const struct ItemConvertArgData *arg, PyObject *py, char *data)
{
- *(float *)data = (float)PyFloat_AsDouble(py);
+ const float *range = arg->float_data.range;
+ float value = (float)PyFloat_AsDouble(py);
+ CLAMP(value, range[0], range[1]);
+ *(float *)data = value;
}
-static void py_to_int(PyObject *py, char *data)
+static void py_to_int(const struct ItemConvertArgData *arg, PyObject *py, char *data)
{
- *(int *)data = (int)PyLong_AsLong(py);
+ const int *range = arg->int_data.range;
+ int value = (int)PyLong_AsLong(py);
+ CLAMP(value, range[0], range[1]);
+ *(int *)data = value;
}
-static void py_to_bool(PyObject *py, char *data)
+static void py_to_bool(const struct ItemConvertArgData *UNUSED(arg), PyObject *py, char *data)
{
*(int *)data = (int)PyObject_IsTrue(py);
}
@@ -560,27 +592,72 @@ static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *
RNA_property_boolean_set_index(ptr, prop, index, *(int *)value);
}
+static void convert_item_init_float(
+ PointerRNA *ptr, PropertyRNA *prop,
+ ItemConvert_FuncArg *convert_item)
+{
+ float *range = convert_item->arg.float_data.range;
+ convert_item->func = py_to_float;
+ RNA_property_float_range(ptr, prop, &range[0], &range[1]);
+}
+
+static void convert_item_init_int(
+ PointerRNA *ptr, PropertyRNA *prop,
+ ItemConvert_FuncArg *convert_item)
+{
+ int *range = convert_item->arg.int_data.range;
+ convert_item->func = py_to_int;
+ RNA_property_int_range(ptr, prop, &range[0], &range[1]);
+}
+
+static void convert_item_init_bool(
+ PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
+ ItemConvert_FuncArg *convert_item)
+{
+ convert_item->func = py_to_bool;
+}
+
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data,
PyObject *py, const char *error_prefix)
{
int ret;
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
- ret = py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float),
- py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
+ {
+ ItemConvert_FuncArg convert_item;
+ convert_item_init_float(ptr, prop, &convert_item);
+
+ ret = py_to_array(
+ py, ptr, prop, param_data, py_float_check, "float", sizeof(float),
+ &convert_item, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
break;
+ }
case PROP_INT:
- ret = py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int),
- py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
+ {
+ ItemConvert_FuncArg convert_item;
+ convert_item_init_int(ptr, prop, &convert_item);
+
+ ret = py_to_array(
+ py, ptr, prop, param_data, py_int_check, "int", sizeof(int),
+ &convert_item, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
break;
+ }
case PROP_BOOLEAN:
- ret = py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int),
- py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
+ {
+ ItemConvert_FuncArg convert_item;
+ convert_item_init_bool(ptr, prop, &convert_item);
+
+ ret = py_to_array(
+ py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int),
+ &convert_item, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
break;
+ }
default:
+ {
PyErr_SetString(PyExc_TypeError, "not an array type");
ret = -1;
break;
+ }
}
return ret;
@@ -592,21 +669,44 @@ int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, in
int ret;
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
- ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
- py_float_check, "float", py_to_float, float_set_index, error_prefix);
+ {
+ ItemConvert_FuncArg convert_item;
+ convert_item_init_float(ptr, prop, &convert_item);
+
+ ret = py_to_array_index(
+ py, ptr, prop, arraydim, arrayoffset, index,
+ py_float_check, "float",
+ &convert_item, float_set_index, error_prefix);
break;
+ }
case PROP_INT:
- ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
- py_int_check, "int", py_to_int, int_set_index, error_prefix);
+ {
+ ItemConvert_FuncArg convert_item;
+ convert_item_init_int(ptr, prop, &convert_item);
+
+ ret = py_to_array_index(
+ py, ptr, prop, arraydim, arrayoffset, index,
+ py_int_check, "int",
+ &convert_item, int_set_index, error_prefix);
break;
+ }
case PROP_BOOLEAN:
- ret = py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index,
- py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
+ {
+ ItemConvert_FuncArg convert_item;
+ convert_item_init_bool(ptr, prop, &convert_item);
+
+ ret = py_to_array_index(
+ py, ptr, prop, arraydim, arrayoffset, index,
+ py_bool_check, "boolean",
+ &convert_item, bool_set_index, error_prefix);
break;
+ }
default:
+ {
PyErr_SetString(PyExc_TypeError, "not an array type");
ret = -1;
break;
+ }
}
return ret;
diff --git a/source/blender/python/intern/bpy_rna_callback.c b/source/blender/python/intern/bpy_rna_callback.c
index 87c3a6eb4ef..df1c4155a6d 100644
--- a/source/blender/python/intern/bpy_rna_callback.c
+++ b/source/blender/python/intern/bpy_rna_callback.c
@@ -174,7 +174,7 @@ static eSpace_Type rna_Space_refine_reverse(StructRNA *srna)
if (srna == &RNA_SpaceConsole) return SPACE_CONSOLE;
if (srna == &RNA_SpaceUserPreferences) return SPACE_USERPREF;
if (srna == &RNA_SpaceClipEditor) return SPACE_CLIP;
- return -1;
+ return SPACE_EMPTY;
}
PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
@@ -215,12 +215,12 @@ PyObject *pyrna_callback_classmethod_add(PyObject *UNUSED(self), PyObject *args)
if (pyrna_enum_value_from_id(region_draw_mode_items, cb_event_str, &cb_event, "bpy_struct.callback_add()") == -1) {
return NULL;
}
- else if (pyrna_enum_value_from_id(region_type_items, cb_regiontype_str, &cb_regiontype, "bpy_struct.callback_add()") == -1) {
+ else if (pyrna_enum_value_from_id(rna_enum_region_type_items, cb_regiontype_str, &cb_regiontype, "bpy_struct.callback_add()") == -1) {
return NULL;
}
else {
const eSpace_Type spaceid = rna_Space_refine_reverse(srna);
- if (spaceid == -1) {
+ if (spaceid == SPACE_EMPTY) {
PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna));
return NULL;
}
@@ -278,12 +278,12 @@ PyObject *pyrna_callback_classmethod_remove(PyObject *UNUSED(self), PyObject *ar
customdata = ED_region_draw_cb_customdata(handle);
Py_DECREF((PyObject *)customdata);
- if (pyrna_enum_value_from_id(region_type_items, cb_regiontype_str, &cb_regiontype, "bpy_struct.callback_remove()") == -1) {
+ if (pyrna_enum_value_from_id(rna_enum_region_type_items, cb_regiontype_str, &cb_regiontype, "bpy_struct.callback_remove()") == -1) {
return NULL;
}
else {
const eSpace_Type spaceid = rna_Space_refine_reverse(srna);
- if (spaceid == -1) {
+ if (spaceid == SPACE_EMPTY) {
PyErr_Format(PyExc_TypeError, "unknown space type '%.200s'", RNA_struct_identifier(srna));
return NULL;
}
diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c
new file mode 100644
index 00000000000..482508a8d85
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_driver.c
@@ -0,0 +1,79 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_rna_driver.c
+ * \ingroup pythonintern
+ *
+ * This file defines utility functions that use the RNA API, from PyDrivers.
+ */
+
+#include <Python.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_fcurve.h"
+
+#include "RNA_access.h"
+
+#include "bpy_rna.h"
+
+#include "bpy_rna_driver.h" /* own include */
+
+
+/**
+ * A version of #driver_get_variable_value which returns a PyObject.
+ */
+PyObject *pyrna_driver_get_variable_value(
+ struct ChannelDriver *driver, struct DriverTarget *dtar)
+{
+ PyObject *driver_arg = NULL;
+ PointerRNA ptr;
+ PropertyRNA *prop = NULL;
+ int index;
+
+ if (driver_get_variable_property(driver, dtar, &ptr, &prop, &index)) {
+ if (prop) {
+ if (index != -1) {
+ if (index < RNA_property_array_length(&ptr, prop) && index >= 0) {
+ /* object, property & index */
+ driver_arg = pyrna_array_index(&ptr, prop, index);
+ }
+ else {
+ /* out of range, pass */
+ }
+ }
+ else {
+ /* object & property */
+ driver_arg = pyrna_prop_to_py(&ptr, prop);
+ }
+ }
+ else {
+ /* object only */
+ driver_arg = pyrna_struct_CreatePyObject(&ptr);
+ }
+ }
+ else {
+ /* can't resolve path, pass */
+ }
+
+ return driver_arg;
+}
diff --git a/source/blender/python/intern/bpy_rna_driver.h b/source/blender/python/intern/bpy_rna_driver.h
new file mode 100644
index 00000000000..8deac2e4384
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_driver.h
@@ -0,0 +1,33 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BPY_RNA_DRIVER_H__
+#define __BPY_RNA_DRIVER_H__
+
+/** \file blender/python/intern/bpy_rna_driver.h
+ * \ingroup pythonintern
+ */
+
+struct ChannelDriver;
+struct DriverTarget;
+
+PyObject *pyrna_driver_get_variable_value(struct ChannelDriver *driver, struct DriverTarget *dtar);
+
+#endif /* __BPY_RNA_DRIVER_H__ */
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
new file mode 100644
index 00000000000..104e3e47646
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -0,0 +1,272 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_rna_id_collection.c
+ * \ingroup pythonintern
+ *
+ * This file adds some helpers related to ID/Main handling, that cannot fit well in RNA itself.
+ */
+
+#include <Python.h>
+#include <stddef.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+
+#include "DNA_ID.h"
+
+#include "bpy_util.h"
+#include "bpy_rna_id_collection.h"
+
+#include "../generic/py_capi_utils.h"
+#include "../generic/python_utildefines.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+#include "RNA_enum_types.h"
+
+#include "bpy_rna.h"
+
+typedef struct IDUserMapData {
+ /* place-holder key only used for lookups to avoid creating new data only for lookups
+ * (never return its contents) */
+ PyObject *py_id_key_lookup_only;
+
+ /* we loop over data-blocks that this ID points to (do build a reverse lookup table) */
+ PyObject *py_id_curr;
+ ID *id_curr;
+
+ /* filter the values we add into the set */
+ BLI_bitmap *types_bitmap;
+
+ PyObject *user_map; /* set to fill in as we iterate */
+ bool is_subset; /* true when we're only mapping a subset of all the ID's (subset arg is passed) */
+} IDUserMapData;
+
+
+static int id_code_as_index(const short idcode)
+{
+ return (int)*((unsigned short *)&idcode);
+}
+
+static bool id_check_type(const ID *id, const BLI_bitmap *types_bitmap)
+{
+ return BLI_BITMAP_TEST_BOOL(types_bitmap, id_code_as_index(GS(id->name)));
+}
+
+static int foreach_libblock_id_user_map_callback(
+ void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag))
+{
+ IDUserMapData *data = user_data;
+
+ if (*id_p) {
+
+ if (data->types_bitmap) {
+ if (!id_check_type(*id_p, data->types_bitmap)) {
+ return IDWALK_RET_NOP;
+ }
+ }
+
+ /* pyrna_struct_hash() uses ptr.data only,
+ * but pyrna_struct_richcmp() uses also ptr.type,
+ * so we need to create a valid PointerRNA here...
+ */
+ PyObject *key = data->py_id_key_lookup_only;
+ RNA_id_pointer_create(*id_p, &((BPy_StructRNA *)key)->ptr);
+
+ PyObject *set;
+ if ((set = PyDict_GetItem(data->user_map, key)) == NULL) {
+
+ /* limit to key's added already */
+ if (data->is_subset) {
+ return IDWALK_RET_NOP;
+ }
+
+ /* Cannot use our placeholder key here! */
+ key = pyrna_id_CreatePyObject(*id_p);
+ set = PySet_New(NULL);
+ PyDict_SetItem(data->user_map, key, set);
+ Py_DECREF(set);
+ Py_DECREF(key);
+ }
+
+ if (data->py_id_curr == NULL) {
+ data->py_id_curr = pyrna_id_CreatePyObject(data->id_curr);
+ }
+
+ PySet_Add(set, data->py_id_curr);
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+PyDoc_STRVAR(bpy_user_map_doc,
+".. method:: user_map([subset=(id1, id2, ...)], key_types={..}, value_types={..})\n"
+"\n"
+" Returns a mapping of all ID datablocks in current ``bpy.data`` to a set of all datablocks using them.\n"
+"\n"
+" For list of valid set members for key_types & value_types, see: :class:`bpy.types.KeyingSetPath.id_type`.\n"
+"\n"
+" :arg subset: When passed, only these data-blocks and their users will be included as keys/values in the map.\n"
+" :type subset: sequence\n"
+" :arg key_types: Filter the keys mapped by ID types.\n"
+" :type key_types: set of strings\n"
+" :arg value_types: Filter the values in the set by ID types.\n"
+" :type value_types: set of strings\n"
+" :return: dictionary of :class:`bpy.types.ID` instances, with sets of ID's as their values.\n"
+" :rtype: dict\n"
+);
+static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+#if 0 /* If someone knows how to get a proper 'self' in that case... */
+ BPy_StructRNA *pyrna = (BPy_StructRNA *)self;
+ Main *bmain = pyrna->ptr.data;
+#else
+ Main *bmain = G.main; /* XXX Ugly, but should work! */
+#endif
+
+ static const char *kwlist[] = {"subset", "key_types", "value_types", NULL};
+ PyObject *subset = NULL;
+
+ PyObject *key_types = NULL;
+ PyObject *val_types = NULL;
+ BLI_bitmap *key_types_bitmap = NULL;
+ BLI_bitmap *val_types_bitmap = NULL;
+
+ PyObject *ret = NULL;
+
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|O$O!O!:user_map", (char **)kwlist,
+ &subset,
+ &PySet_Type, &key_types,
+ &PySet_Type, &val_types))
+ {
+ return NULL;
+ }
+
+ if (key_types) {
+ key_types_bitmap = pyrna_set_to_enum_bitmap(
+ rna_enum_id_type_items, key_types, sizeof(short), true, USHRT_MAX, "key types");
+ if (key_types_bitmap == NULL) {
+ goto error;
+ }
+ }
+
+ if (val_types) {
+ val_types_bitmap = pyrna_set_to_enum_bitmap(
+ rna_enum_id_type_items, val_types, sizeof(short), true, USHRT_MAX, "value types");
+ if (val_types_bitmap == NULL) {
+ goto error;
+ }
+ }
+
+ IDUserMapData data_cb = {NULL};
+
+ if (subset) {
+ PyObject *subset_fast = PySequence_Fast(subset, "user_map");
+ if (subset_fast == NULL) {
+ goto error;
+ }
+
+ PyObject **subset_array = PySequence_Fast_ITEMS(subset_fast);
+ Py_ssize_t subset_len = PySequence_Fast_GET_SIZE(subset_fast);
+
+ data_cb.user_map = PyDict_New();
+ data_cb.is_subset = true;
+ for (; subset_len; subset_array++, subset_len--) {
+ PyObject *set = PySet_New(NULL);
+ PyDict_SetItem(data_cb.user_map, *subset_array, set);
+ Py_DECREF(set);
+ }
+ Py_DECREF(subset_fast);
+ }
+ else {
+ data_cb.user_map = PyDict_New();
+ }
+
+ data_cb.types_bitmap = key_types_bitmap;
+
+ ListBase *lb_array[MAX_LIBARRAY];
+ int lb_index;
+ lb_index = set_listbasepointers(bmain, lb_array);
+
+ while (lb_index--) {
+
+ if (val_types_bitmap && lb_array[lb_index]->first) {
+ if (!id_check_type(lb_array[lb_index]->first, val_types_bitmap)) {
+ continue;
+ }
+ }
+
+ for (ID *id = lb_array[lb_index]->first; id; id = id->next) {
+ /* One-time init, ID is just used as placeholder here, we abuse this in iterator callback
+ * to avoid having to rebuild a complete bpyrna object each time for the key searching
+ * (where only ID pointer value is used). */
+ if (data_cb.py_id_key_lookup_only == NULL) {
+ data_cb.py_id_key_lookup_only = pyrna_id_CreatePyObject(id);
+ }
+
+ data_cb.id_curr = id;
+ BKE_library_foreach_ID_link(id, foreach_libblock_id_user_map_callback, &data_cb, IDWALK_NOP);
+ if (data_cb.py_id_curr) {
+ Py_DECREF(data_cb.py_id_curr);
+ data_cb.py_id_curr = NULL;
+ }
+ }
+ }
+
+ ret = data_cb.user_map;
+
+
+error:
+
+ Py_XDECREF(data_cb.py_id_key_lookup_only);
+
+ if (key_types_bitmap) {
+ MEM_freeN(key_types_bitmap);
+ }
+
+ if (val_types_bitmap) {
+ MEM_freeN(val_types_bitmap);
+ }
+
+ return ret;
+
+}
+
+int BPY_rna_id_collection_module(PyObject *mod_par)
+{
+ static PyMethodDef user_map = {
+ "user_map", (PyCFunction)bpy_user_map, METH_VARARGS | METH_KEYWORDS, bpy_user_map_doc};
+
+ PyModule_AddObject(mod_par, "_rna_id_collection_user_map", PyCFunction_New(&user_map, NULL));
+
+ return 0;
+}
diff --git a/source/blender/python/intern/bpy_rna_id_collection.h b/source/blender/python/intern/bpy_rna_id_collection.h
new file mode 100644
index 00000000000..c293289c821
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_id_collection.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_rna_id_collection.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_RNA_ID_COLLECTION_H__
+#define __BPY_RNA_ID_COLLECTION_H__
+
+int BPY_rna_id_collection_module(PyObject *);
+
+#endif /* __BPY_RNA_ID_COLLECTION_H__ */
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h
index 1ae00a7fb02..63cb7920bd1 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_util.h
@@ -27,8 +27,8 @@
#ifndef __BPY_UTIL_H__
#define __BPY_UTIL_H__
-#if PY_VERSION_HEX < 0x03040000
-# error "Python 3.4 or greater is required, you'll need to update your python."
+#if PY_VERSION_HEX < 0x03050000
+# error "Python 3.5 or greater is required, you'll need to update your python."
#endif
struct EnumPropertyItem;
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
index 057df4ccd41..974d7c5549c 100644
--- a/source/blender/python/intern/bpy_utils_units.c
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -201,7 +201,7 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj
bUnit_ReplaceString(str, (int)str_len, uref, scale, usys, ucat);
- if (PyC_RunString_AsNumber(str, &result, "<bpy_units_api>") != 0) {
+ if (!PyC_RunString_AsNumber(str, &result, "<bpy_units_api>")) {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index a7ece10f06c..66c1ddcc352 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -32,11 +32,6 @@
* from blender materials.
*/
-/* python redefines */
-#ifdef _POSIX_C_SOURCE
-#undef _POSIX_C_SOURCE
-#endif
-
#include <Python.h>
#include "DNA_scene_types.h"
@@ -60,7 +55,7 @@
#define PY_MODULE_ADD_CONSTANT(module, name) PyModule_AddIntConstant(module, # name, name)
PyDoc_STRVAR(M_gpu_doc,
-"This module provides access to the GLSL shader."
+"This module provides access to the GLSL shader and Offscreen rendering functionalities."
);
static struct PyModuleDef gpumodule = {
PyModuleDef_HEAD_INIT,
@@ -102,6 +97,8 @@ static PyObject *PyInit_gpu(void)
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_MAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_VIEWIMAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_IMAT);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_LOCTOVIEWMAT);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_COLOR);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE);
/* GPU_DYNAMIC_GROUP_LAMP */
@@ -116,6 +113,7 @@ static PyObject *PyInit_gpu(void)
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE);
/* GPU_DYNAMIC_GROUP_SAMPLER */
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE);
@@ -130,6 +128,7 @@ static PyObject *PyInit_gpu(void)
/* GPU_DYNAMIC_GROUP_WORLD */
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR);
+ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_ZENITH_COLOR);
/* GPU_DYNAMIC_GROUP_MAT */
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB);
PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF);
@@ -313,12 +312,25 @@ static PyMethodDef meth_export_shader[] = {
{"export_shader", (PyCFunction)GPU_export_shader, METH_VARARGS | METH_KEYWORDS, GPU_export_shader_doc}
};
+/* -------------------------------------------------------------------- */
+/* Initialize Module */
+
PyObject *GPU_initPython(void)
{
- PyObject *module = PyInit_gpu();
+ PyObject *module;
+ PyObject *submodule;
+ PyObject *sys_modules = PyThreadState_GET()->interp->modules;
+
+ module = PyInit_gpu();
+
PyModule_AddObject(module, "export_shader", (PyObject *)PyCFunction_New(meth_export_shader, NULL));
- PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
+ /* gpu.offscreen */
+ PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
return module;
}
diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/gpu.h
index 82338869b9d..0da44a4eb87 100644
--- a/source/blender/python/intern/gpu.h
+++ b/source/blender/python/intern/gpu.h
@@ -36,4 +36,6 @@
PyObject *GPU_initPython(void);
+PyObject *BPyInit_gpu_offscreen(void);
+
#endif /* __GPU_H__ */
diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c
new file mode 100644
index 00000000000..c4863b2a92f
--- /dev/null
+++ b/source/blender/python/intern/gpu_offscreen.c
@@ -0,0 +1,432 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2015, Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/gpu_offscreen.c
+ * \ingroup pythonintern
+ *
+ * This file defines the offscreen functionalities of the 'gpu' module
+ * used for off-screen OpenGL rendering.
+ */
+
+#include <Python.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+#include "GPU_compositing.h"
+#include "GPU_framebuffer.h"
+
+#include "../mathutils/mathutils.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "gpu.h"
+
+#include "ED_view3d.h"
+
+/* -------------------------------------------------------------------- */
+/* GPU Offscreen PyObject */
+
+typedef struct {
+ PyObject_HEAD
+ GPUOffScreen *ofs;
+} BPy_GPUOffScreen;
+
+static int bpy_gpu_offscreen_valid_check(BPy_GPUOffScreen *py_gpu_ofs)
+{
+ if (UNLIKELY(py_gpu_ofs->ofs == NULL)) {
+ PyErr_SetString(PyExc_ReferenceError, "GPU offscreen was freed, no further access is valid");
+ return -1;
+ }
+ return 0;
+}
+
+#define BPY_GPU_OFFSCREEN_CHECK_OBJ(pygpu) { \
+ if (UNLIKELY(bpy_gpu_offscreen_valid_check(pygpu) == -1)) { \
+ return NULL; \
+ } \
+} ((void)0)
+
+PyDoc_STRVAR(pygpu_offscreen_width_doc, "Texture width.\n\n:type: int");
+static PyObject *pygpu_offscreen_width_get(BPy_GPUOffScreen *self, void *UNUSED(type))
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ return PyLong_FromLong(GPU_offscreen_width(self->ofs));
+}
+
+PyDoc_STRVAR(pygpu_offscreen_height_doc, "Texture height.\n\n:type: int");
+static PyObject *pygpu_offscreen_height_get(BPy_GPUOffScreen *self, void *UNUSED(type))
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ return PyLong_FromLong(GPU_offscreen_height(self->ofs));
+}
+
+PyDoc_STRVAR(pygpu_offscreen_color_texture_doc, "Color texture.\n\n:type: int");
+static PyObject *pygpu_offscreen_color_texture_get(BPy_GPUOffScreen *self, void *UNUSED(type))
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+ return PyLong_FromLong(GPU_offscreen_color_texture(self->ofs));
+}
+
+PyDoc_STRVAR(pygpu_offscreen_bind_doc,
+"bind(save=True)\n"
+"\n"
+" Bind the offscreen object.\n"
+"\n"
+" :param save: save OpenGL current states.\n"
+" :type save: bool\n"
+);
+static PyObject *pygpu_offscreen_bind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {"save", NULL};
+ bool save = true;
+
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|O&:bind", (char **)(kwlist),
+ PyC_ParseBool, &save))
+ {
+ return NULL;
+ }
+
+ GPU_offscreen_bind(self->ofs, save);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(pygpu_offscreen_unbind_doc,
+"unbind(restore=True)\n"
+"\n"
+" Unbind the offscreen object.\n"
+"\n"
+" :param restore: restore OpenGL previous states.\n"
+" :type restore: bool\n"
+);
+static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {"restore", NULL};
+ bool restore = true;
+
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|O&:unbind", (char **)(kwlist),
+ PyC_ParseBool, &restore))
+ {
+ return NULL;
+ }
+
+ GPU_offscreen_unbind(self->ofs, restore);
+ Py_RETURN_NONE;
+}
+
+/**
+ * Use with PyArg_ParseTuple's "O&" formatting.
+ */
+static int pygpu_offscreen_check_matrix(PyObject *o, void *p)
+{
+ MatrixObject **pymat_p = p;
+ MatrixObject *pymat = (MatrixObject *)o;
+
+ if (!MatrixObject_Check(pymat)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected a mathutils.Matrix, not a %.200s",
+ Py_TYPE(o)->tp_name);
+ return 0;
+ }
+
+ if (BaseMath_ReadCallback(pymat) == -1) {
+ return 0;
+ }
+
+ if ((pymat->num_col != 4) ||
+ (pymat->num_row != 4))
+ {
+ PyErr_SetString(PyExc_ValueError, "matrix must be 4x4");
+ return 0;
+ }
+
+ *pymat_p = pymat;
+ return 1;
+}
+
+PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc,
+"draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n"
+"\n"
+" Draw the 3d viewport in the offscreen object.\n"
+"\n"
+" :param scene: Scene to draw.\n"
+" :type scene: :class:`bpy.types.Scene`\n"
+" :param view3d: 3D View to get the drawing settings from.\n"
+" :type view3d: :class:`bpy.types.SpaceView3D`\n"
+" :param region: Region of the 3D View.\n"
+" :type region: :class:`bpy.types.Region`\n"
+" :param modelview_matrix: ModelView Matrix.\n"
+" :type modelview_matrix: :class:`mathutils.Matrix`\n"
+" :param projection_matrix: Projection Matrix.\n"
+" :type projection_matrix: :class:`mathutils.Matrix`\n"
+);
+static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {"scene", "view3d", "region", "projection_matrix", "modelview_matrix", NULL};
+
+ MatrixObject *py_mat_modelview, *py_mat_projection;
+ PyObject *py_scene, *py_region, *py_view3d;
+
+ Scene *scene;
+ View3D *v3d;
+ ARegion *ar;
+ GPUFX *fx;
+ GPUFXSettings fx_settings;
+ void *rv3d_mats;
+
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "OOOO&O&:draw_view3d", (char **)(kwlist),
+ &py_scene, &py_view3d, &py_region,
+ pygpu_offscreen_check_matrix, &py_mat_projection,
+ pygpu_offscreen_check_matrix, &py_mat_modelview) ||
+ (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) ||
+ !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) ||
+ !(ar = PyC_RNA_AsPointer(py_region, "Region"))))
+ {
+ return NULL;
+ }
+
+ fx = GPU_fx_compositor_create();
+
+ fx_settings = v3d->fx_settings; /* full copy */
+
+ ED_view3d_draw_offscreen_init(scene, v3d);
+
+ rv3d_mats = ED_view3d_mats_rv3d_backup(ar->regiondata);
+
+ GPU_offscreen_bind(self->ofs, true); /* bind */
+
+ ED_view3d_draw_offscreen(
+ scene, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs),
+ (float(*)[4])py_mat_modelview->matrix, (float(*)[4])py_mat_projection->matrix,
+ false, true, true, "",
+ fx, &fx_settings,
+ self->ofs);
+
+ GPU_fx_compositor_destroy(fx);
+ GPU_offscreen_unbind(self->ofs, true); /* unbind */
+
+ ED_view3d_mats_rv3d_restore(ar->regiondata, rv3d_mats);
+ MEM_freeN(rv3d_mats);
+
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(pygpu_offscreen_free_doc,
+"free()\n"
+"\n"
+" Free the offscreen object\n"
+" The framebuffer, texture and render objects will no longer be accessible.\n"
+);
+static PyObject *pygpu_offscreen_free(BPy_GPUOffScreen *self)
+{
+ BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
+
+ GPU_offscreen_free(self->ofs);
+ self->ofs = NULL;
+ Py_RETURN_NONE;
+}
+
+static void BPy_GPUOffScreen__tp_dealloc(BPy_GPUOffScreen *self)
+{
+ if (self->ofs)
+ GPU_offscreen_free(self->ofs);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static PyGetSetDef bpy_gpu_offscreen_getseters[] = {
+ {(char *)"color_texture", (getter)pygpu_offscreen_color_texture_get, (setter)NULL, pygpu_offscreen_color_texture_doc, NULL},
+ {(char *)"width", (getter)pygpu_offscreen_width_get, (setter)NULL, pygpu_offscreen_width_doc, NULL},
+ {(char *)"height", (getter)pygpu_offscreen_height_get, (setter)NULL, pygpu_offscreen_height_doc, NULL},
+ {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
+};
+
+static struct PyMethodDef bpy_gpu_offscreen_methods[] = {
+ {"bind", (PyCFunction)pygpu_offscreen_bind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_bind_doc},
+ {"unbind", (PyCFunction)pygpu_offscreen_unbind, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_unbind_doc},
+ {"draw_view3d", (PyCFunction)pygpu_offscreen_draw_view3d, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_draw_view3d_doc},
+ {"free", (PyCFunction)pygpu_offscreen_free, METH_NOARGS, pygpu_offscreen_free_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(py_gpu_offscreen_doc,
+".. class:: GPUOffscreen"
+"\n"
+" This object gives access to off screen buffers.\n"
+);
+static PyTypeObject BPy_GPUOffScreen_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GPUOffScreen", /* tp_name */
+ sizeof(BPy_GPUOffScreen), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)BPy_GPUOffScreen__tp_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_compare */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ NULL, /* tp_str */
+ NULL, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ py_gpu_offscreen_doc, /* Documentation string */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ bpy_gpu_offscreen_methods, /* tp_methods */
+ NULL, /* tp_members */
+ bpy_gpu_offscreen_getseters, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ NULL, /* tp_alloc */
+ NULL, /* tp_new */
+ (freefunc)0, /* tp_free */
+ NULL, /* tp_is_gc */
+ NULL, /* tp_bases */
+ NULL, /* tp_mro */
+ NULL, /* tp_cache */
+ NULL, /* tp_subclasses */
+ NULL, /* tp_weaklist */
+ (destructor) NULL /* tp_del */
+};
+
+/* -------------------------------------------------------------------- */
+/* GPU offscreen methods */
+
+static PyObject *BPy_GPU_OffScreen_CreatePyObject(GPUOffScreen *ofs)
+{
+ BPy_GPUOffScreen *self;
+ self = PyObject_New(BPy_GPUOffScreen, &BPy_GPUOffScreen_Type);
+ self->ofs = ofs;
+ return (PyObject *)self;
+}
+
+PyDoc_STRVAR(pygpu_offscreen_new_doc,
+"new(width, height, samples=0)\n"
+"\n"
+" Return a GPUOffScreen.\n"
+"\n"
+" :param width: Horizontal dimension of the buffer.\n"
+" :type width: int`\n"
+" :param height: Vertical dimension of the buffer.\n"
+" :type height: int`\n"
+" :param samples: OpenGL samples to use for MSAA or zero to disable.\n"
+" :type samples: int\n"
+" :return: Newly created off-screen buffer.\n"
+" :rtype: :class:`gpu.GPUOffscreen`\n"
+);
+static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ static const char *kwlist[] = {"width", "height", "samples", NULL};
+
+ GPUOffScreen *ofs;
+ int width, height, samples = 0;
+ char err_out[256];
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "ii|i:new", (char **)(kwlist),
+ &width, &height, &samples))
+ {
+ return NULL;
+ }
+
+ ofs = GPU_offscreen_create(width, height, samples, err_out);
+
+ if (ofs == NULL) {
+ PyErr_Format(PyExc_RuntimeError,
+ "gpu.offscreen.new(...) failed with '%s'",
+ err_out[0] ? err_out : "unknown error");
+ return NULL;
+ }
+
+ return BPy_GPU_OffScreen_CreatePyObject(ofs);
+}
+
+static struct PyMethodDef BPy_GPU_offscreen_methods[] = {
+ {"new", (PyCFunction)pygpu_offscreen_new, METH_VARARGS | METH_KEYWORDS, pygpu_offscreen_new_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(BPy_GPU_offscreen_doc,
+"This module provides access to offscreen rendering functions."
+);
+static PyModuleDef BPy_GPU_offscreen_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "gpu.offscreen", /* m_name */
+ BPy_GPU_offscreen_doc, /* m_doc */
+ 0, /* m_size */
+ BPy_GPU_offscreen_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+PyObject *BPyInit_gpu_offscreen(void)
+{
+ PyObject *submodule;
+
+ /* Register the 'GPUOffscreen' class */
+ if (PyType_Ready(&BPy_GPUOffScreen_Type)) {
+ return NULL;
+ }
+
+ submodule = PyModule_Create(&BPy_GPU_offscreen_module_def);
+
+#define MODULE_TYPE_ADD(s, t) \
+ PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t)
+
+ MODULE_TYPE_ADD(submodule, BPy_GPUOffScreen_Type);
+
+#undef MODULE_TYPE_ADD
+
+ return submodule;
+}
+
+#undef BPY_GPU_OFFSCREEN_CHECK_OBJ
diff --git a/source/blender/python/intern/stubs.c b/source/blender/python/intern/stubs.c
index e0508359e13..cc186be60ea 100644
--- a/source/blender/python/intern/stubs.c
+++ b/source/blender/python/intern/stubs.c
@@ -32,11 +32,16 @@
#include "BPY_extern.h"
+#if defined(__GNUC__)
+# pragma GCC diagnostic error "-Wmissing-prototypes"
+# pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
/* python, will come back */
//void BPY_script_exec(void) {}
//void BPY_python_start(void) {}
//void BPY_text_free_code(void) {}
-void BPY_pyconstraint_exec(struct bPythonConstraint *UNUSED(con), struct bConstraintOb *UNUSED(cob), struct ListBase *UNUSED(targets)) {}
-void BPY_pyconstraint_target(struct bPythonConstraint *UNUSED(con), struct bConstraintTarget *UNUSED(ct)) {}
-int BPY_is_pyconstraint(struct Text *UNUSED(text)) { return 0;}
-void BPY_pyconstraint_update(struct Object *UNUSED(owner), struct bConstraint *UNUSED(con)) {}
+void BPY_pyconstraint_exec(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets) {}
+void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct) {}
+int BPY_is_pyconstraint(struct Text *text) { return 0;}
+void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con) {}
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 41baa9b089f..71288871104 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -1120,8 +1120,7 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
float eul[3], eul_compatf[3];
EulerObject *eul_compat = NULL;
- float tmat[3][3];
- float (*mat)[3];
+ float mat[3][3];
if (BaseMath_ReadCallback(self) == -1)
return NULL;
@@ -1138,11 +1137,10 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
/*must be 3-4 cols, 3-4 rows, square matrix */
if (self->num_row == 3 && self->num_col == 3) {
- mat = (float (*)[3])self->matrix;
+ copy_m3_m3(mat, (float (*)[3])self->matrix);
}
else if (self->num_row == 4 && self->num_col == 4) {
- copy_m3_m4(tmat, (float (*)[4])self->matrix);
- mat = tmat;
+ copy_m3_m4(mat, (float (*)[4])self->matrix);
}
else {
PyErr_SetString(PyExc_ValueError,
@@ -1158,13 +1156,15 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
return NULL;
}
+ normalize_m3(mat);
+
if (eul_compat) {
- if (order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat);
- else mat3_to_compatible_eulO(eul, eul_compatf, order, mat);
+ if (order == 1) mat3_normalized_to_compatible_eul(eul, eul_compatf, mat);
+ else mat3_normalized_to_compatible_eulO(eul, eul_compatf, order, mat);
}
else {
- if (order == 1) mat3_to_eul(eul, mat);
- else mat3_to_eulO(eul, order, mat);
+ if (order == 1) mat3_normalized_to_eul(eul, mat);
+ else mat3_normalized_to_eulO(eul, order, mat);
}
return Euler_CreatePyObject(eul, order, NULL);
@@ -2055,7 +2055,7 @@ static PyObject *Matrix_richcmpr(PyObject *a, PyObject *b, int op)
static Py_hash_t Matrix_hash(MatrixObject *self)
{
- float mat[SQUARE(MATRIX_MAX_DIM)];
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
if (BaseMath_ReadCallback(self) == -1)
return -1;
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 1752be6e306..ea5732966b2 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -108,15 +108,11 @@ static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
normalize_qt_qt(tquat, self->quat);
if (eul_compat) {
- float mat[3][3];
-
if (BaseMath_ReadCallback(eul_compat) == -1)
return NULL;
- quat_to_mat3(mat, tquat);
-
- if (order == EULER_ORDER_XYZ) mat3_to_compatible_eul(eul, eul_compat->eul, mat);
- else mat3_to_compatible_eulO(eul, eul_compat->eul, order, mat);
+ if (order == EULER_ORDER_XYZ) quat_to_compatible_eul(eul, eul_compat->eul, tquat);
+ else quat_to_compatible_eulO(eul, eul_compat->eul, order, tquat);
}
else {
if (order == EULER_ORDER_XYZ) quat_to_eul(eul, tquat);
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 3d7a505eb12..7b6fa466fce 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -1717,6 +1717,8 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
}
+ /* Intentionally don't support (Quaternion) here, uses reverse order instead. */
+
/* make sure v1 is always the vector */
if (vec1 && vec2) {
if (vec1->size != vec2->size) {
@@ -1749,34 +1751,6 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2)
return Vector_CreatePyObject(tvec, vec_size, Py_TYPE(vec1));
}
- else if (QuaternionObject_Check(v2)) {
- /* VEC * QUAT */
-/* ------ to be removed ------*/
-#if 1
- PyErr_SetString(PyExc_ValueError,
- "(Vector * Quat) is now removed, reverse the "
- "order (promoted to an Error for Debug builds)");
- return NULL;
-#else
- QuaternionObject *quat2 = (QuaternionObject *)v2;
- float tvec[3];
-
- if (vec1->size != 3) {
- PyErr_SetString(PyExc_ValueError,
- "Vector multiplication: "
- "only 3D vector rotations (with quats) currently supported");
- return NULL;
- }
- if (BaseMath_ReadCallback(quat2) == -1) {
- return NULL;
- }
-
- copy_v3_v3(tvec, vec1->vec);
- mul_qt_v3(quat2->quat, tvec);
- return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec1));
-#endif
-/* ------ to be removed ------*/
- }
else if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC * FLOAT */
return vector_mul_float(vec1, scalar);
}
@@ -1806,57 +1780,11 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2)
if (BaseMath_ReadCallback_ForWrite(vec) == -1)
return NULL;
- /* only support vec*=float and vec*=mat
- * vec*=vec result is a float so that wont work */
- if (MatrixObject_Check(v2)) {
-/* ------ to be removed ------*/
-#if 1
- PyErr_SetString(PyExc_ValueError,
- "(Vector *= Matrix) is now removed, reverse the "
- "order (promoted to an Error for Debug builds) "
- "and uses the non in-place multiplication.");
- return NULL;
-#else
- float rvec[MAX_DIMENSIONS];
- if (BaseMath_ReadCallback((MatrixObject *)v2) == -1)
- return NULL;
-
- if (column_vector_multiplication(rvec, vec, (MatrixObject *)v2) == -1)
- return NULL;
+ /* Intentionally don't support (Quaternion, Matrix) here, uses reverse order instead. */
- memcpy(vec->vec, rvec, sizeof(float) * vec->size);
-#endif
-/* ------ to be removed ------*/
- }
- else if (QuaternionObject_Check(v2)) {
- /* VEC *= QUAT */
-
-/* ------ to be removed ------*/
-#if 1
- PyErr_SetString(PyExc_ValueError,
- "(Vector *= Quat) is now removed, reverse the "
- "order (promoted to an Error for Debug builds) "
- "and uses the non in-place multiplication.");
- return NULL;
-#else
- QuaternionObject *quat2 = (QuaternionObject *)v2;
-
- if (vec->size != 3) {
- PyErr_SetString(PyExc_ValueError,
- "Vector multiplication: "
- "only 3D vector rotations (with quats) currently supported");
- return NULL;
- }
-
- if (BaseMath_ReadCallback(quat2) == -1) {
- return NULL;
- }
-
- mul_qt_v3(quat2->quat, vec->vec);
-#endif
-/* ------ to be removed ------*/
- }
- else if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC *= FLOAT */
+ /* only support 'vec *= float'
+ * vec*=vec result is a float so that wont work */
+ if (((scalar = PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) == 0) { /* VEC *= FLOAT */
mul_vn_fl(vec->vec, vec->size, scalar);
}
else {
@@ -2356,7 +2284,7 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure
size_from = axis_from;
}
- else if ((PyErr_Clear()), /* run but ignore the result */
+ else if (((void)PyErr_Clear()), /* run but ignore the result */
(size_from = mathutils_array_parse(vec_assign, 2, 4, value,
"mathutils.Vector.**** = swizzle assignment")) == -1)
{
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c
index bf06b889e25..ff1761eb6d7 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -72,10 +72,16 @@
" :type distance: float\n"
#define PYBVH_FIND_GENERIC_RETURN_DOC \
-" :return: Returns a tuple (:class:`Vector` location, :class:`Vector` normal, int index, float distance),\n" \
+" :return: Returns a tuple\n" \
+" (:class:`Vector` location, :class:`Vector` normal, int index, float distance),\n" \
" Values will all be None if no hit is found.\n" \
" :rtype: :class:`tuple`\n"
+#define PYBVH_FIND_GENERIC_RETURN_LIST_DOC \
+" :return: Returns a list of tuples\n" \
+" (:class:`Vector` location, :class:`Vector` normal, int index, float distance),\n" \
+" :rtype: :class:`list`\n"
+
#define PYBVH_FROM_GENERIC_EPSILON_DOC \
" :arg epsilon: Increase the threshold for detecting overlap and raycast hits.\n" \
" :type epsilon: float\n"
@@ -328,7 +334,7 @@ static void py_bvhtree_nearest_point_cb(void *userdata, int index, const float c
}
PyDoc_STRVAR(py_bvhtree_ray_cast_doc,
-".. method:: ray_cast(co, direction, distance=sys.float_info.max)\n"
+".. method:: ray_cast(origin, direction, distance=sys.float_info.max)\n"
"\n"
" Cast a ray onto the mesh.\n"
"\n"
@@ -352,7 +358,7 @@ static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args)
if (!PyArg_ParseTuple(
args, (char *)"OO|f:ray_cast",
- &py_co, &py_direction, max_dist))
+ &py_co, &py_direction, &max_dist))
{
return NULL;
}
@@ -383,7 +389,7 @@ static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args)
}
PyDoc_STRVAR(py_bvhtree_find_nearest_doc,
-".. method:: find_nearest(co, distance=" PYBVH_MAX_DIST_STR ")\n"
+".. method:: find_nearest(origin, distance=" PYBVH_MAX_DIST_STR ")\n"
"\n"
" Find the nearest element to a point.\n"
"\n"
@@ -432,6 +438,91 @@ static PyObject *py_bvhtree_find_nearest(PyBVHTree *self, PyObject *args)
return py_bvhtree_nearest_to_py_none();
}
+struct PyBVH_RangeData {
+ PyBVHTree *self;
+ PyObject *result;
+ float dist_sq;
+};
+
+static void py_bvhtree_nearest_point_range_cb(void *userdata, int index, const float co[3], float UNUSED(dist_sq_bvh))
+{
+ struct PyBVH_RangeData *data = userdata;
+ PyBVHTree *self = data->self;
+
+ const float (*coords)[3] = (const float (*)[3])self->coords;
+ const unsigned int *tri = self->tris[index];
+ const float *tri_co[3] = {coords[tri[0]], coords[tri[1]], coords[tri[2]]};
+ float nearest_tmp[3], dist_sq;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(tri_co));
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < data->dist_sq) {
+ BVHTreeNearest nearest;
+ nearest.index = self->orig_index ? self->orig_index[index] : index;
+ nearest.dist_sq = dist_sq;
+ copy_v3_v3(nearest.co, nearest_tmp);
+ if (self->orig_normal) {
+ copy_v3_v3(nearest.no, self->orig_normal[nearest.index]);
+ }
+ else {
+ normal_tri_v3(nearest.no, UNPACK3(tri_co));
+ }
+
+ PyList_APPEND(data->result, py_bvhtree_nearest_to_py(&nearest));
+ }
+}
+
+PyDoc_STRVAR(py_bvhtree_find_nearest_range_doc,
+".. method:: find_nearest_range(origin, distance=" PYBVH_MAX_DIST_STR ")\n"
+"\n"
+" Find the nearest elements to a point in the distance range.\n"
+"\n"
+" :arg co: Find nearest elements to this point.\n"
+" :type co: :class:`Vector`\n"
+PYBVH_FIND_GENERIC_DISTANCE_DOC
+PYBVH_FIND_GENERIC_RETURN_LIST_DOC
+);
+static PyObject *py_bvhtree_find_nearest_range(PyBVHTree *self, PyObject *args)
+{
+ const char *error_prefix = "find_nearest_range";
+ float co[3];
+ float max_dist = max_dist_default;
+
+ /* parse args */
+ {
+ PyObject *py_co;
+
+ if (!PyArg_ParseTuple(
+ args, (char *)"O|f:find_nearest_range",
+ &py_co, &max_dist))
+ {
+ return NULL;
+ }
+
+ if (mathutils_array_parse(co, 2, 3 | MU_ARRAY_ZERO, py_co, error_prefix) == -1) {
+ return NULL;
+ }
+ }
+
+ PyObject *ret = PyList_New(0);
+
+ if (self->tree) {
+ struct PyBVH_RangeData data = {
+ .self = self,
+ .result = ret,
+ .dist_sq = SQUARE(max_dist),
+ };
+
+ BLI_bvhtree_range_query(
+ self->tree, co, max_dist,
+ py_bvhtree_nearest_point_range_cb, &data);
+ }
+
+ return ret;
+}
+
+
BLI_INLINE unsigned int overlap_hash(const void *overlap_v)
{
const BVHTreeOverlap *overlap = overlap_v;
@@ -777,7 +868,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P
axis_dominant_v3_to_m3_negate(axis_mat, normal);
for (j = 0; j < plink->len; j++) {
- mul_v2_m3v3(proj_coords[i], axis_mat, coords[plink->poly[j]]);
+ mul_v2_m3v3(proj_coords[j], axis_mat, coords[plink->poly[j]]);
}
BLI_polyfill_calc_arena((const float (*)[2])proj_coords, plink->len, 1, tris_offset, pf_arena);
@@ -894,7 +985,7 @@ static PyObject *C_BVHTree_FromBMesh(PyObject *UNUSED(cls), PyObject *args, PyOb
looptris = MEM_mallocN(sizeof(*looptris) * (size_t)tris_len, __func__);
- BM_bmesh_calc_tessellation(bm, looptris, &tris_len_dummy);
+ BM_mesh_calc_tessellation(bm, looptris, &tris_len_dummy);
BLI_assert(tris_len_dummy == (int)tris_len);
}
@@ -1132,7 +1223,8 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO
static PyMethodDef py_bvhtree_methods[] = {
{"ray_cast", (PyCFunction)py_bvhtree_ray_cast, METH_VARARGS, py_bvhtree_ray_cast_doc},
- {"find", (PyCFunction)py_bvhtree_find_nearest, METH_VARARGS, py_bvhtree_find_nearest_doc},
+ {"find_nearest", (PyCFunction)py_bvhtree_find_nearest, METH_VARARGS, py_bvhtree_find_nearest_doc},
+ {"find_nearest_range", (PyCFunction)py_bvhtree_find_nearest_range, METH_VARARGS, py_bvhtree_find_nearest_range_doc},
{"overlap", (PyCFunction)py_bvhtree_overlap, METH_O, py_bvhtree_overlap_doc},
/* class methods */
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 02247986558..868e4b38408 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -415,7 +415,9 @@ static PyObject *M_Geometry_volume_tetrahedron(PyObject *UNUSED(self), PyObject
PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc,
".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n"
"\n"
-" Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n"
+" Takes 2 segments (defined by 4 vectors) and returns a vector for their point of intersection or None.\n"
+"\n"
+" .. warning:: Despite its name, this function works on segments, and not on lines.\n"
"\n"
" :arg lineA_p1: First point of the first line\n"
" :type lineA_p1: :class:`mathutils.Vector`\n"
@@ -870,7 +872,7 @@ PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc,
" :type quad_p2: :class:`mathutils.Vector`\n"
" :arg quad_p3: Third point of the quad\n"
" :type quad_p3: :class:`mathutils.Vector`\n"
-" :arg quad_p4: Forth point of the quad\n"
+" :arg quad_p4: Fourth point of the quad\n"
" :type quad_p4: :class:`mathutils.Vector`\n"
" :rtype: int\n"
);
diff --git a/source/blender/python/mathutils/mathutils_interpolate.c b/source/blender/python/mathutils/mathutils_interpolate.c
index 4d7841b906a..c8cb71874db 100644
--- a/source/blender/python/mathutils/mathutils_interpolate.c
+++ b/source/blender/python/mathutils/mathutils_interpolate.c
@@ -64,9 +64,10 @@ static PyObject *M_Interpolate_poly_3d_calc(PyObject *UNUSED(self), PyObject *ar
PyObject *point, *veclist, *ret;
int i;
- if (!PyArg_ParseTuple(args, "OO!:interpolation_weights",
- &veclist,
- &vector_Type, &point))
+ if (!PyArg_ParseTuple(
+ args, "OO!:poly_3d_calc",
+ &veclist,
+ &vector_Type, &point))
{
return NULL;
}
@@ -81,13 +82,13 @@ static PyObject *M_Interpolate_poly_3d_calc(PyObject *UNUSED(self), PyObject *ar
else
fp[2] = 0.0f; /* if its a 2d vector then set the z to be zero */
- len = mathutils_array_parse_alloc_v(((float **)&vecs), 3, veclist, "interpolation_weights");
+ len = mathutils_array_parse_alloc_v(((float **)&vecs), 3, veclist, __func__);
if (len == -1) {
return NULL;
}
if (len) {
- float *weights = MEM_mallocN(sizeof(float) * len, "interpolation weights");
+ float *weights = MEM_mallocN(sizeof(float) * len, __func__);
interp_weights_poly_v3(weights, vecs, len, fp);
diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c
index 199c2e02da4..ca66c1906b4 100644
--- a/source/blender/python/mathutils/mathutils_kdtree.c
+++ b/source/blender/python/mathutils/mathutils_kdtree.c
@@ -104,7 +104,10 @@ static int PyKDTree__tp_init(PyKDTree *self, PyObject *args, PyObject *kwargs)
unsigned int maxsize;
const char *keywords[] = {"size", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "I:KDTree", (char **)keywords, &maxsize)) {
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, "I:KDTree", (char **)keywords,
+ &maxsize))
+ {
return -1;
}
@@ -144,8 +147,9 @@ static PyObject *py_kdtree_insert(PyKDTree *self, PyObject *args, PyObject *kwar
int index;
const char *keywords[] = {"co", "index", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "Oi:insert", (char **)keywords,
- &py_co, &index))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, (char *) "Oi:insert", (char **)keywords,
+ &py_co, &index))
{
return NULL;
}
@@ -185,25 +189,57 @@ static PyObject *py_kdtree_balance(PyKDTree *self)
Py_RETURN_NONE;
}
+struct PyKDTree_NearestData {
+ PyObject *py_filter;
+ bool is_error;
+};
+
+static int py_find_nearest_cb(void *user_data, int index, const float co[3], float dist_sq)
+{
+ UNUSED_VARS(co, dist_sq);
+
+ struct PyKDTree_NearestData *data = user_data;
+
+ PyObject *py_args = PyTuple_New(1);
+ PyTuple_SET_ITEM(py_args, 0, PyLong_FromLong(index));
+ PyObject *result = PyObject_CallObject(data->py_filter, py_args);
+ Py_DECREF(py_args);
+
+ if (result) {
+ bool use_node;
+ int ok = PyC_ParseBool(result, &use_node);
+ Py_DECREF(result);
+ if (ok) {
+ return (int)use_node;
+ }
+ }
+
+ data->is_error = true;
+ return -1;
+}
+
PyDoc_STRVAR(py_kdtree_find_doc,
-".. method:: find(co)\n"
+".. method:: find(co, filter=None)\n"
"\n"
" Find nearest point to ``co``.\n"
"\n"
" :arg co: 3d coordinates.\n"
" :type co: float triplet\n"
+" :arg filter: function which takes an index and returns True for indices to include in the search.\n"
+" :type filter: callable\n"
" :return: Returns (:class:`Vector`, index, distance).\n"
" :rtype: :class:`tuple`\n"
);
static PyObject *py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs)
{
- PyObject *py_co;
+ PyObject *py_co, *py_filter = NULL;
float co[3];
KDTreeNearest nearest;
- const char *keywords[] = {"co", NULL};
+ const char *keywords[] = {"co", "filter", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O:find", (char **)keywords,
- &py_co))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, (char *) "O|O:find", (char **)keywords,
+ &py_co, &py_filter))
{
return NULL;
}
@@ -216,10 +252,26 @@ static PyObject *py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs
return NULL;
}
-
nearest.index = -1;
- BLI_kdtree_find_nearest(self->obj, co, &nearest);
+ if (py_filter == NULL) {
+ BLI_kdtree_find_nearest(self->obj, co, &nearest);
+ }
+ else {
+ struct PyKDTree_NearestData data = {0};
+
+ data.py_filter = py_filter;
+ data.is_error = false;
+
+ BLI_kdtree_find_nearest_cb(
+ self->obj, co,
+ py_find_nearest_cb, &data,
+ &nearest);
+
+ if (data.is_error) {
+ return NULL;
+ }
+ }
return kdtree_nearest_to_py_and_check(&nearest);
}
@@ -246,8 +298,9 @@ static PyObject *py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwar
int i, found;
const char *keywords[] = {"co", "n", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "OI:find_n", (char **)keywords,
- &py_co, &n))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, (char *) "OI:find_n", (char **)keywords,
+ &py_co, &n))
{
return NULL;
}
@@ -303,8 +356,9 @@ static PyObject *py_kdtree_find_range(PyKDTree *self, PyObject *args, PyObject *
const char *keywords[] = {"co", "radius", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "Of:find_range", (char **)keywords,
- &py_co, &radius))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwargs, (char *) "Of:find_range", (char **)keywords,
+ &py_co, &radius))
{
return NULL;
}
diff --git a/source/blender/python/mathutils/mathutils_noise.c b/source/blender/python/mathutils/mathutils_noise.c
index f0449c23dcd..143e51ecfd8 100644
--- a/source/blender/python/mathutils/mathutils_noise.c
+++ b/source/blender/python/mathutils/mathutils_noise.c
@@ -113,6 +113,7 @@ static unsigned long state[N]; /* the array for the state vector */
static int left = 1;
static int initf = 0;
static unsigned long *next;
+static float state_offset_vector[3 * 3];
/* initializes state[N] with a seed */
static void init_genrand(unsigned long s)
@@ -131,6 +132,16 @@ static void init_genrand(unsigned long s)
}
left = 1;
initf = 1;
+
+ /* update vector offset */
+ {
+ const unsigned long *state_offset = &state[N - ARRAY_SIZE(state_offset_vector)];
+ const float range = 32; /* range in both pos/neg direction */
+ for (j = 0; j < ARRAY_SIZE(state_offset_vector); j++, state_offset++) {
+ /* overflow is fine here */
+ state_offset_vector[j] = (float)(int)(*state_offset) * (1.0f / (INT_MAX / range));
+ }
+ }
}
static void next_state(void)
@@ -199,9 +210,11 @@ static void rand_vn(float *array_tar, const int size)
static void noise_vector(float x, float y, float z, int nb, float v[3])
{
/* Simply evaluate noise at 3 different positions */
- v[0] = (float)(2.0f * BLI_gNoise(1.f, x + 9.321f, y - 1.531f, z - 7.951f, 0, nb) - 1.0f);
- v[1] = (float)(2.0f * BLI_gNoise(1.f, x, y, z, 0, nb) - 1.0f);
- v[2] = (float)(2.0f * BLI_gNoise(1.f, x + 6.327f, y + 0.1671f, z - 2.672f, 0, nb) - 1.0f);
+ const float *ofs = state_offset_vector;
+ for (int j = 0; j < 3; j++) {
+ v[j] = (2.0f * BLI_gNoise(1.0f, x + ofs[0], y + ofs[1], z + ofs[2], 0, nb) - 1.0f);
+ ofs += 3;
+ }
}
/* Returns a turbulence value for a given position (x, y, z) */
diff --git a/source/blender/quicktime/SConscript b/source/blender/quicktime/SConscript
deleted file mode 100644
index 746662ebf3e..00000000000
--- a/source/blender/quicktime/SConscript
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-
-source_files = ['apple/qtkit_import.m',
- 'apple/qtkit_export.m']
-
-
-incs = ['.',
- '../quicktime',
- '../makesdna',
- '../makesrna',
- '../windowmanager',
- '#/intern/guardedalloc',
- '../blenlib',
- '../blenkernel',
- '../avi',
- '../imbuf',
- '../imbuf/intern',
- '../render/extern/include',
- '../editors/include']
-
-incs.append(env['BF_QUICKTIME_INC'])
-
-types = ['core','player']
-priorities = [200,235]
-
-defs=['WITH_QUICKTIME']
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs.append(env['BF_AUDASPACE_C_INC'])
-
-if env['C_COMPILER_ID'] == 'gcc' and env['CCVERSION'] >= '4.6': # always use default-Apple-gcc for objC language, gnu-compilers do not support it fully yet
- env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=defs, libtype=types, priority=priorities, cc_compilerchange='/usr/bin/gcc', cxx_compilerchange='/usr/bin/g++')
-else:
- env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=defs, libtype=types, priority=priorities)
diff --git a/source/blender/quicktime/apple/qtkit_export.m b/source/blender/quicktime/apple/qtkit_export.m
index 9bc4ec444bb..1ac3c58f888 100644
--- a/source/blender/quicktime/apple/qtkit_export.m
+++ b/source/blender/quicktime/apple/qtkit_export.m
@@ -62,10 +62,6 @@
#import <QTKit/QTKit.h>
#include <AudioToolbox/AudioToolbox.h>
-#if MAC_OS_X_VERSION_MIN_REQUIRED <= 1040
-#error OSX 10.5 minimum is needed for QTKit
-#endif
-
#include "quicktime_import.h"
#include "quicktime_export.h"
diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h
index 8a10a4a05d6..aaa3f5c9070 100644
--- a/source/blender/quicktime/quicktime_export.h
+++ b/source/blender/quicktime/quicktime_export.h
@@ -46,7 +46,7 @@
typedef struct QuicktimeCodecTypeDesc {
int codecType;
int rnatmpvalue;
- char *codecName;
+ const char *codecName;
} QuicktimeCodecTypeDesc;
// quicktime movie output functions
@@ -80,8 +80,7 @@ void free_qtcomponentdata(void);
void makeqtstring(struct RenderData *rd, char *string, bool preview); //for playanim.c
-
-#if (MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 && __LP64__)
+#ifdef __APPLE__
//Include the quicktime codec types constants that are missing in QTKitDefines.h
enum {
kRawCodecType = 'raw ',
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
deleted file mode 100644
index 16d9b4a832d..00000000000
--- a/source/blender/render/SConscript
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/source/*.c')
-raysources = env.Glob('intern/raytrace/*.cpp')
-
-incs = [
- 'extern/include',
- 'intern/include',
- '#/intern/guardedalloc',
- '../blenkernel',
- '../blenlib',
- '../blentranslation',
- '../imbuf',
- '../depsgraph',
- '../makesdna',
- '../makesrna',
- '../physics',
- '../../../intern/mikktspace',
- '../../../intern/smoke/extern',
- ]
-incs = ' '.join(incs)
-
-cflags_raytrace = env['CCFLAGS']
-cxxflags_raytrace = env['CXXFLAGS']
-
-defs = []
-defs_raytrace = []
-
-if env['WITH_BF_SMOKE']:
- defs.append('WITH_SMOKE')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ../python'
- defs.append('WITH_PYTHON')
- if env['BF_DEBUG']:
- defs.append('DEBUG')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- if env['WITH_BF_RAYOPTIMIZATION']:
- cflags_raytrace = env['CCFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
- cxxflags_raytrace = env['CCFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
-
-if env['OURPLATFORM'] in ('win32-mingw', 'win64-mingw'):
- if env['WITH_BF_RAYOPTIMIZATION']:
- cflags_raytrace = env['CCFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
- cxxflags_raytrace = env['CXXFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
-
-if env['OURPLATFORM'] == 'darwin':
- if env['MACOSX_ARCHITECTURE'] in ('i386', 'x86_64') and env['WITH_BF_RAYOPTIMIZATION']:
- cflags_raytrace = env['CFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
- cxxflags_raytrace = env['CXXFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
-
-if env['OURPLATFORM'] == 'linux':
- if env['WITH_BF_RAYOPTIMIZATION']:
- cflags_raytrace = env['CCFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
- cxxflags_raytrace = env['CXXFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
-
-if env['OURPLATFORM'] == 'linuxcross':
- if env['WITH_BF_RAYOPTIMIZATION']:
- cflags_raytrace = env['CCFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
- cxxflags_raytrace = env['CCFLAGS'] + env['BF_RAYOPTIMIZATION_SSE_FLAGS']
-
-if env['WITH_BF_QUICKTIME']:
- defs.append('WITH_QUICKTIME')
- incs += ' ../quicktime ' + env['BF_QUICKTIME_INC']
-
-if env['WITH_BF_OPENEXR']:
- defs.append('WITH_OPENEXR')
-
-if env['WITH_BF_FREESTYLE']:
- incs += ' ../freestyle'
- defs.append('WITH_FREESTYLE')
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_DEBUG']:
- defs.append('WITH_CYCLES_DEBUG')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-#
-# HACK: To fix problem with error 'MMX instruction set not enabled' from mmintrin.h
-#
-if env['OURPLATFORM'] == 'linuxcross':
- defs.append('__SSE__')
- defs_raytrace.append('__MMX__')
-
-if env['WITH_BF_RAYOPTIMIZATION']:
- defs.append('__SSE__')
- defs_raytrace.append('__SSE__')
-
-env.BlenderLib ( libname = 'bf_render', sources = sources, includes = Split(incs), defines=defs, libtype='core', priority=145 )
-env.BlenderLib ( libname = 'bf_render_raytrace', sources = raysources, includes = Split(incs), defines=defs_raytrace, libtype='core', priority=145, compileflags=cflags_raytrace, cxx_compileflags=cxxflags_raytrace )
diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h
index 0750ea1aa28..a04d1d6632c 100644
--- a/source/blender/render/extern/include/RE_bake.h
+++ b/source/blender/render/extern/include/RE_bake.h
@@ -72,7 +72,7 @@ bool RE_bake_has_engine(struct Render *re);
bool RE_bake_engine(
struct Render *re, struct Object *object, const int object_id, const BakePixel pixel_array[],
- const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
+ const size_t num_pixels, const int depth, const ScenePassType pass_type, const int pass_filter, float result[]);
/* bake.c */
int RE_pass_depth(const ScenePassType pass_type);
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 4e48060c54f..f83a210275f 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -62,6 +62,7 @@ struct BakePixel;
#define RE_USE_SAVE_BUFFERS 64
#define RE_USE_TEXTURE_PREVIEW 128
#define RE_USE_SHADING_NODES_CUSTOM 256
+#define RE_USE_SPHERICAL_STEREO 512
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@@ -89,7 +90,7 @@ typedef struct RenderEngineType {
void (*update)(struct RenderEngine *engine, struct Main *bmain, struct Scene *scene);
void (*render)(struct RenderEngine *engine, struct Scene *scene);
- void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const int object_id, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
+ void (*bake)(struct RenderEngine *engine, struct Scene *scene, struct Object *object, const int pass_type, const int pass_filter, const int object_id, const struct BakePixel *pixel_array, const int num_pixels, const int depth, void *result);
void (*view_update)(struct RenderEngine *engine, const struct bContext *context);
void (*view_draw)(struct RenderEngine *engine, const struct bContext *context);
@@ -140,9 +141,11 @@ struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y,
void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results);
+const char *RE_engine_active_view_get(RenderEngine *engine);
void RE_engine_active_view_set(RenderEngine *engine, const char *viewname);
-float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera);
-void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, float *r_modelmat);
+float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera, int use_spherical_stereo);
+void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat);
+int RE_engine_get_spherical_stereo(RenderEngine *engine, struct Object *camera);
int RE_engine_test_break(RenderEngine *engine);
void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info);
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 2a679f0f0d0..ce0691b7632 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -159,7 +159,7 @@ typedef struct RenderResult {
ListBase layers;
/* multiView maps to a StringVector in OpenEXR */
- ListBase views;
+ ListBase views; /* RenderView */
/* allowing live updates: */
volatile rcti renrect;
@@ -207,6 +207,10 @@ void RE_InitRenderCB(struct Render *re);
void RE_FreeRender(struct Render *re);
/* only called on exit */
void RE_FreeAllRender(void);
+/* Free memory used by persistent data.
+ * Invoked when loading new file.
+ */
+void RE_FreeAllPersistentData(void);
/* only call on file load */
void RE_FreeAllRenderResults(void);
/* for external render engines that can keep persistent data */
@@ -227,6 +231,9 @@ struct RenderStats *RE_GetStats(struct Render *re);
void RE_ResultGet32(struct Render *re, unsigned int *rect);
void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id);
+void RE_render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd,
+ struct ImBuf *ibuf, const int view_id);
+
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
@@ -269,10 +276,12 @@ void RE_init_threadcount(Render *re);
/* the main processor, assumes all was set OK! */
void RE_TileProcessor(struct Render *re);
-bool RE_WriteRenderViewsImage(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, const bool stamp, char *name);
-bool RE_WriteRenderViewsMovie(struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, struct RenderData *rd,
- struct bMovieHandle *mh, const size_t width, const size_t height, void **movie_ctx_arr,
- const size_t totvideos, bool preview);
+bool RE_WriteRenderViewsImage(
+ struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, const bool stamp, char *name);
+bool RE_WriteRenderViewsMovie(
+ struct ReportList *reports, struct RenderResult *rr, struct Scene *scene, struct RenderData *rd,
+ struct bMovieHandle *mh, void **movie_ctx_arr,
+ const int totvideos, bool preview);
/* only RE_NewRender() needed, main Blender render calls */
void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene,
@@ -354,6 +363,13 @@ bool RE_is_rendering_allowed(struct Scene *scene, struct Object *camera_override
bool RE_allow_render_generic_object(struct Object *ob);
+/* RE_updateRenderInstances flag */
+enum {
+ RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0),
+ RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1),
+};
+void RE_updateRenderInstances(Render *re, int flag);
+
/******* defined in render_result.c *********/
bool RE_HasFakeLayer(RenderResult *res);
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index 6e1f128b7a5..2b5d0ca4e14 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -42,30 +42,51 @@ struct ImagePool;
struct MTex;
struct Scene;
-/* particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
-int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image);
-
-/* particle.c */
+/* render_texture.c */
+/* used by particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
+int externtex(
+ struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta,
+ const int thread, struct ImagePool *pool, const bool skip_load_image, const bool texnode_preview);
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype);
-/* node_composite.c */
-void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
-void antialias_tagbuf(int xsize, int ysize, char *rectmove);
+void RE_texture_rng_init(void);
+void RE_texture_rng_exit(void);
-/* dynamicpaint.c */
-struct Material *RE_init_sample_material(struct Material *orig_mat, struct Scene *scene);
-void RE_free_sample_material(struct Material *mat);
+struct Material *RE_sample_material_init(struct Material *orig_mat, struct Scene *scene);
+void RE_sample_material_free(struct Material *mat);
void RE_sample_material_color(
struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
int tri_index, struct DerivedMesh *orcoDm, struct Object *ob);
-/* pointdensity.c */
+/* imagetexture.c */
+void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]);
+
+/* zbuf.c */
+void antialias_tagbuf(int xsize, int ysize, char *rectmove);
+
+/* pointdensity.c */
struct PointDensity;
-void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, int resolution, float *values);
+void RE_point_density_cache(
+ struct Scene *scene,
+ struct PointDensity *pd,
+ const bool use_render_params);
+
+void RE_point_density_minmax(
+ struct Scene *scene,
+ struct PointDensity *pd,
+ const bool use_render_params,
+ float r_min[3], float r_max[3]);
+
+void RE_point_density_sample(
+ struct Scene *scene,
+ struct PointDensity *pd,
+ const int resolution,
+ const bool use_render_params,
+ float *values);
+
+void RE_point_density_free(struct PointDensity *pd);
-void RE_init_texture_rng(void);
-void RE_exit_texture_rng(void);
#endif /* __RE_RENDER_EXT_H__ */
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index f78c0aa8cb2..12b97aedbd3 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -198,7 +198,15 @@ struct ImagePool;
struct Object;
/* this one uses nodes */
-int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image);
+int multitex_ext(struct Tex *tex,
+ float texvec[3],
+ float dxt[3], float dyt[3],
+ int osatex,
+ struct TexResult *texres,
+ const short thread,
+ struct ImagePool *pool,
+ bool scene_color_manage,
+ const bool skip_load_image);
/* nodes disabled */
int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image);
/* only for internal node usage */
@@ -220,6 +228,22 @@ float RE_bake_make_derivative(struct ImBuf *ibuf, float *heights_buffer, const c
const float height_min, const float height_max,
const float fmult);
+enum {
+ RE_OBJECT_INSTANCE_MATRIX_OB,
+ RE_OBJECT_INSTANCE_MATRIX_OBINV,
+ RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW,
+ RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV,
+};
+
+const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4];
+
+enum {
+ RE_VIEW_MATRIX,
+ RE_VIEWINV_MATRIX,
+};
+
+const float (*RE_render_current_get_matrix(int matrix_id))[4];
+
#define BAKE_RESULT_OK 0
#define BAKE_RESULT_NO_OBJECTS 1
#define BAKE_RESULT_FEEDBACK_LOOP 2
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 90ad0fa30d7..2619ac76d59 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -97,8 +97,6 @@ bool render_result_exr_file_cache_read(struct Render *re);
/* Combined Pixel Rect */
struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd, const int view_id);
-void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd,
- struct ImBuf *ibuf, const int view_id);
void render_result_rect_fill_zero(struct RenderResult *rr, const int view_id);
void render_result_rect_get_pixels(struct RenderResult *rr,
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 3569cb2c168..cef3a073084 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -353,6 +353,10 @@ typedef struct ObjectInstanceRen {
float mat[4][4], imat[4][4];
float nmat[3][3]; /* nmat is inverse mat tranposed */
+
+ float obmat[4][4], obinvmat[4][4];
+ float localtoviewmat[4][4], localtoviewinvmat[4][4];
+
short flag;
float dupliorco[3], dupliuv[2];
@@ -433,7 +437,7 @@ typedef struct HaloRen {
unsigned int lay;
struct Material *mat;
struct ImagePool *pool;
- bool skip_load_image;
+ bool skip_load_image, texnode_preview;
} HaloRen;
/* ------------------------------------------------------------------------- */
@@ -565,6 +569,7 @@ typedef struct LampRen {
short falloff_type;
float ld1, ld2;
+ float coeff_const, coeff_lin, coeff_quad;
struct CurveMapping *curfalloff;
/* copied from Lamp, to decouple more rendering stuff */
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index da45a2bfead..167ebc58030 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -115,8 +115,11 @@ struct HaloRen *RE_inithalo_particle(struct Render *re, struct ObjectRen *obr, s
struct StrandBuffer *RE_addStrandBuffer(struct ObjectRen *obr, int totvert);
struct ObjectRen *RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int psysindex, int lay);
-struct ObjectInstanceRen *RE_addRenderInstance(struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par, int index, int psysindex, float mat[4][4], int lay);
+struct ObjectInstanceRen *RE_addRenderInstance(
+ struct Render *re, struct ObjectRen *obr, struct Object *ob, struct Object *par,
+ int index, int psysindex, float mat[4][4], int lay, const struct DupliObject *dob);
void RE_makeRenderInstances(struct Render *re);
+void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag);
void RE_instance_rotate_ray_start(struct ObjectInstanceRen *obi, struct Isect *is);
void RE_instance_rotate_ray_dir(struct ObjectInstanceRen *obi, struct Isect *is);
diff --git a/source/blender/render/intern/include/renderpipeline.h b/source/blender/render/intern/include/renderpipeline.h
index a831ab3c29c..c5d6e3b44b1 100644
--- a/source/blender/render/intern/include/renderpipeline.h
+++ b/source/blender/render/intern/include/renderpipeline.h
@@ -41,6 +41,7 @@ struct RenderResult;
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
float panorama_pixel_rot(struct Render *re);
void render_update_anim_renderdata(struct Render *re, struct RenderData *rd);
+void render_copy_renderdata(struct RenderData *to, struct RenderData *from);
#endif /* __RENDERPIPELINE_H__ */
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
index 11dcc9d9e80..27867eadbb4 100644
--- a/source/blender/render/intern/include/shading.h
+++ b/source/blender/render/intern/include/shading.h
@@ -82,6 +82,10 @@ void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3);
void calc_R_ref(struct ShadeInput *shi);
+void barycentric_differentials_from_position(
+ const float co[3], const float v1[3], const float v2[3], const float v3[3],
+ const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
+ float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v);
/* shadeoutput. */
void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr);
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index ed161e186b8..dfb491f46b0 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -74,7 +74,9 @@ struct ImagePool;
/* texture.h */
void do_halo_tex(struct HaloRen *har, float xn, float yn, float col_r[4]);
-void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float hor[3], float zen[3], float *blend, int skyflag, short thread);
+void do_sky_tex(
+ const float rco[3], const float view[3], const float lo[3], const float dxyview[2],
+ float hor[3], float zen[3], float *blend, int skyflag, short thread);
void do_material_tex(struct ShadeInput *shi, struct Render *re);
void do_lamp_tex(LampRen *la, const float lavec[3], struct ShadeInput *shi, float col_r[3], int effect);
void do_volume_tex(struct ShadeInput *shi, const float xyz[3], int mapto_flag, float col_r[3], float *val, struct Render *re);
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
index cf804d75d70..6fc1a4c2656 100644
--- a/source/blender/render/intern/include/zbuf.h
+++ b/source/blender/render/intern/include/zbuf.h
@@ -95,7 +95,7 @@ typedef struct ZSpan {
float zmulx, zmuly, zofsx, zofsy; /* transform from hoco to zbuf co */
int *rectz, *arectz; /* zbuffers, arectz is for transparent */
- int *rectz1; /* seconday z buffer for shadowbuffer (2nd closest z) */
+ int *rectz1; /* secondary z buffer for shadowbuffer (2nd closest z) */
int *rectp; /* polygon index buffer */
int *recto; /* object buffer */
int *rectmask; /* negative zmask buffer */
@@ -142,7 +142,7 @@ void zbufclipwire(struct ZSpan *zspan, int obi, int zvlnr, int ec,
void zbuf_make_winmat(Render *re, float winmat[4][4]);
void zbuf_render_project(float winmat[4][4], const float co[3], float ho[4]);
-/* sould not really be exposed, bad! */
+/* should not really be exposed, bad! */
void hoco_to_zco(ZSpan *zspan, float zco[3], const float hoco[4]);
void zspan_scanconvert_strand(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float, float) );
void zbufsinglewire(ZSpan *zspan, int obi, int zvlnr, const float ho1[4], const float ho2[4]);
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 1d67a8c4f44..00c1129fa85 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -331,7 +331,8 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
if (size > nchilds) {
float bcost = FLT_MAX;
- baxis = -1, boffset = size / 2;
+ baxis = -1;
+ boffset = size / 2;
SweepCost *sweep = (SweepCost *)MEM_mallocN(sizeof(SweepCost) * size, "RTBuilder.HeuristicSweep");
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
index e25538cd584..84d04a8851f 100644
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ b/source/blender/render/intern/raytrace/reorganize.h
@@ -38,6 +38,8 @@
#include <queue>
#include <vector>
+#include "BKE_global.h"
+
#ifdef _WIN32
# ifdef INFINITY
# undef INFINITY
@@ -500,7 +502,7 @@ struct VBVH_optimalPackSIMD {
calc_costs(node);
#ifdef DEBUG
- if (first) {
+ if (first && G.debug) {
printf("expected cost = %f (%d)\n", node->cut_cost[0], node->best_cutsize);
}
#endif
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
index 0210bec5ab4..31e461b4536 100644
--- a/source/blender/render/intern/source/bake.c
+++ b/source/blender/render/intern/source/bake.c
@@ -320,7 +320,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua
}
else {
unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
- copy_v4_v4_char((char *)imcol, (char *)col);
+ copy_v4_v4_uchar(imcol, col);
}
}
@@ -375,8 +375,8 @@ static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist,
bs->vcol->b = col[2];
}
else {
- char *imcol = (char *)(bs->rect + bs->rectx * y + x);
- copy_v4_v4_char(imcol, (char *)col);
+ unsigned char *imcol = (unsigned char *)(bs->rect + bs->rectx * y + x);
+ copy_v4_v4_uchar(imcol, col);
}
}
if (bs->rect_mask) {
@@ -656,7 +656,7 @@ static int get_next_bake_face(BakeShade *bs)
bs->mloop = me->mloop + bs->mpoly->loopstart;
/* Tag mesh for reevaluation. */
- me->id.flag |= LIB_DOIT;
+ me->id.tag |= LIB_TAG_DOIT;
}
else {
Image *ima = NULL;
@@ -690,14 +690,14 @@ static int get_next_bake_face(BakeShade *bs)
}
if (ima->flag & IMA_USED_FOR_RENDER) {
- ima->id.flag &= ~LIB_DOIT;
+ ima->id.tag &= ~LIB_TAG_DOIT;
BKE_image_release_ibuf(ima, ibuf, NULL);
continue;
}
/* find the image for the first time? */
- if (ima->id.flag & LIB_DOIT) {
- ima->id.flag &= ~LIB_DOIT;
+ if (ima->id.tag & LIB_TAG_DOIT) {
+ ima->id.tag &= ~LIB_TAG_DOIT;
/* we either fill in float or char, this ensures things go fine */
if (ibuf->rect_float)
@@ -926,7 +926,7 @@ static void *do_bake_thread(void *bs_v)
void RE_bake_ibuf_filter(ImBuf *ibuf, char *mask, const int filter)
{
/* must check before filtering */
- const short is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
+ const bool is_new_alpha = (ibuf->planes != R_IMF_PLANES_RGBA) && BKE_imbuf_alpha_test(ibuf);
/* Margin */
if (filter) {
@@ -1026,7 +1026,7 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
for (ima = G.main->image.first; ima; ima = ima->id.next) {
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- ima->id.flag |= LIB_DOIT;
+ ima->id.tag |= LIB_TAG_DOIT;
ima->flag &= ~IMA_USED_FOR_RENDER;
if (ibuf) {
ibuf->userdata = NULL; /* use for masking if needed */
@@ -1037,7 +1037,7 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
if (R.r.bake_flag & R_BAKE_VCOL) {
/* untag all meshes */
- BKE_main_id_tag_listbase(&G.main->mesh, false);
+ BKE_main_id_tag_listbase(&G.main->mesh, LIB_TAG_DOIT, false);
}
BLI_init_threads(&threads, do_bake_thread, re->r.threads);
@@ -1110,7 +1110,7 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
}
for (ima = G.main->image.first; ima; ima = ima->id.next) {
- if ((ima->id.flag & LIB_DOIT) == 0) {
+ if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
BakeImBufuserData *userdata;
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index dee75d43f36..eff021c9b14 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -84,8 +84,11 @@
/* local include */
#include "render_types.h"
+#include "shading.h"
#include "zbuf.h"
+/* Remove when Cycles moves from MFace to MLoopTri */
+#define USE_MFACE_WORKAROUND
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
@@ -261,31 +264,14 @@ static void calc_point_from_barycentric_extrusion(
}
/**
- * This function returns the barycentric u,v of a face for a coordinate. The face is defined by its index.
- */
-static void calc_barycentric_from_point(
- TriTessFace *triangles, const int index, const float co[3],
- int *r_primitive_id, float r_uv[2])
-{
- TriTessFace *triangle = &triangles[index];
- resolve_tri_uv_v3(r_uv, co,
- triangle->mverts[0]->co,
- triangle->mverts[1]->co,
- triangle->mverts[2]->co);
- *r_primitive_id = index;
-}
-
-/**
* This function populates pixel_array and returns TRUE if things are correct
*/
static bool cast_ray_highpoly(
- BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly,
- const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly,
- const float du_dx, const float du_dy, const float dv_dx, const float dv_dy)
+ BVHTreeFromMesh *treeData, TriTessFace *triangle_low, TriTessFace *triangles[],
+ BakePixel *pixel_array_low, BakePixel *pixel_array, float mat_low[4][4], BakeHighPolyData *highpoly,
+ const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly)
{
int i;
- int primitive_id = -1;
- float uv[2];
int hit_mesh = -1;
float hit_distance = FLT_MAX;
@@ -297,7 +283,7 @@ static bool cast_ray_highpoly(
hits[i].index = -1;
/* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
- hits[i].dist = 10000.0f;
+ hits[i].dist = BVH_RAYCAST_DIST_MAX;
/* transform the ray from the world space to the highpoly space */
mul_v3_m4v3(co_high, highpoly[i].imat, co);
@@ -331,17 +317,54 @@ static bool cast_ray_highpoly(
}
if (hit_mesh != -1) {
- calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv);
- pixel_array[pixel_id].primitive_id = primitive_id;
- pixel_array[pixel_id].object_id = hit_mesh;
- copy_v2_v2(pixel_array[pixel_id].uv, uv);
-
- /* the differentials are relative to the UV/image space, so the highpoly differentials
- * are the same as the low poly differentials */
- pixel_array[pixel_id].du_dx = du_dx;
- pixel_array[pixel_id].du_dy = du_dy;
- pixel_array[pixel_id].dv_dx = dv_dx;
- pixel_array[pixel_id].dv_dy = dv_dy;
+ int primitive_id_high = hits[hit_mesh].index;
+ TriTessFace *triangle_high = &triangles[hit_mesh][primitive_id_high];
+ BakePixel *pixel_low = &pixel_array_low[pixel_id];
+ BakePixel *pixel_high = &pixel_array[pixel_id];
+
+ pixel_high->primitive_id = primitive_id_high;
+ pixel_high->object_id = hit_mesh;
+
+ /* ray direction in high poly object space */
+ float dir_high[3];
+ mul_v3_mat3_m4v3(dir_high, highpoly[hit_mesh].imat, dir);
+ normalize_v3(dir_high);
+
+ /* compute position differentials on low poly object */
+ float duco_low[3], dvco_low[3], dxco[3], dyco[3];
+ sub_v3_v3v3(duco_low, triangle_low->mverts[0]->co, triangle_low->mverts[2]->co);
+ sub_v3_v3v3(dvco_low, triangle_low->mverts[1]->co, triangle_low->mverts[2]->co);
+
+ mul_v3_v3fl(dxco, duco_low, pixel_low->du_dx);
+ madd_v3_v3fl(dxco, dvco_low, pixel_low->dv_dx);
+ mul_v3_v3fl(dyco, duco_low, pixel_low->du_dy);
+ madd_v3_v3fl(dyco, dvco_low, pixel_low->dv_dy);
+
+ /* transform from low poly to to high poly object space */
+ mul_mat3_m4_v3(mat_low, dxco);
+ mul_mat3_m4_v3(mat_low, dyco);
+ mul_mat3_m4_v3(highpoly[hit_mesh].imat, dxco);
+ mul_mat3_m4_v3(highpoly[hit_mesh].imat, dyco);
+
+ /* transfer position differentials */
+ float tmp[3];
+ mul_v3_v3fl(tmp, dir_high, 1.0f/dot_v3v3(dir_high, triangle_high->normal));
+ madd_v3_v3fl(dxco, tmp, -dot_v3v3(dxco, triangle_high->normal));
+ madd_v3_v3fl(dyco, tmp, -dot_v3v3(dyco, triangle_high->normal));
+
+ /* compute barycentric differentials from position differentials */
+ barycentric_differentials_from_position(
+ hits[hit_mesh].co, triangle_high->mverts[0]->co,
+ triangle_high->mverts[1]->co, triangle_high->mverts[2]->co,
+ dxco, dyco, triangle_high->normal, true,
+ &pixel_high->uv[0], &pixel_high->uv[1],
+ &pixel_high->du_dx, &pixel_high->dv_dx,
+ &pixel_high->du_dy, &pixel_high->dv_dy);
+
+ /* verify we have valid uvs */
+ BLI_assert(pixel_high->uv[0] >= -1e-3f &&
+ pixel_high->uv[1] >= -1e-3f &&
+ pixel_high->uv[0] + pixel_high->uv[1] <= 1.0f + 1e-3f);
}
else {
pixel_array[pixel_id].primitive_id = -1;
@@ -352,34 +375,58 @@ static bool cast_ray_highpoly(
return hit_mesh != -1;
}
+#ifdef USE_MFACE_WORKAROUND
+/**
+ * Until cycles moves to #MLoopTri, we need to keep face-rotation in sync with #test_index_face
+ *
+ * We only need to consider quads since #BKE_mesh_recalc_tessellation doesn't execute this on triangles.
+ */
+static void test_index_face_looptri(const MPoly *mp, MLoop *mloop, MLoopTri *lt)
+{
+ if (mp->totloop == 4) {
+ if (UNLIKELY((mloop[mp->loopstart + 2].v == 0) ||
+ (mloop[mp->loopstart + 3].v == 0)))
+ {
+ /* remap: (2, 3, 0, 1) */
+ unsigned int l = mp->loopstart;
+ ARRAY_SET_ITEMS(lt[0].tri, l + 2, l + 3, l + 0);
+ ARRAY_SET_ITEMS(lt[1].tri, l + 2, l + 0, l + 1);
+ }
+ }
+}
+#endif
+
/**
* This function populates an array of verts for the triangles of a mesh
* Tangent and Normals are also stored
*/
-static void mesh_calc_tri_tessface(
- TriTessFace *triangles, Mesh *me, bool tangent, DerivedMesh *dm)
+static TriTessFace *mesh_calc_tri_tessface(
+ Mesh *me, bool tangent, DerivedMesh *dm)
{
int i;
MVert *mvert;
TSpace *tspace;
- float *precomputed_normals = NULL;
- bool calculate_normal;
+
const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
+ TriTessFace *triangles;
+
/* calculate normal for each polygon only once */
unsigned int mpoly_prev = UINT_MAX;
float no[3];
+#ifdef USE_MFACE_WORKAROUND
+ unsigned int mpoly_prev_testindex = UINT_MAX;
+#endif
+
mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
+ triangles = MEM_mallocN(sizeof(TriTessFace) * tottri, __func__);
if (tangent) {
DM_ensure_normals(dm);
DM_calc_loop_tangents(dm);
- precomputed_normals = dm->getPolyDataArray(dm, CD_NORMAL);
- calculate_normal = precomputed_normals ? false : true;
-
tspace = dm->getLoopDataArray(dm, CD_TANGENT);
BLI_assert(tspace);
}
@@ -390,9 +437,20 @@ static void mesh_calc_tri_tessface(
me->totloop, me->totpoly,
looptri);
+
+ const float *precomputed_normals = dm ? dm->getPolyDataArray(dm, CD_NORMAL) : NULL;
+ const bool calculate_normal = precomputed_normals ? false : true;
+
for (i = 0; i < tottri; i++) {
- MLoopTri *lt = &looptri[i];
- MPoly *mp = &me->mpoly[lt->poly];
+ const MLoopTri *lt = &looptri[i];
+ const MPoly *mp = &me->mpoly[lt->poly];
+
+#ifdef USE_MFACE_WORKAROUND
+ if (lt->poly != mpoly_prev_testindex) {
+ test_index_face_looptri(mp, me->mloop, &looptri[i]);
+ mpoly_prev_testindex = lt->poly;
+ }
+#endif
triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
@@ -403,22 +461,23 @@ static void mesh_calc_tri_tessface(
triangles[i].tspace[0] = &tspace[lt->tri[0]];
triangles[i].tspace[1] = &tspace[lt->tri[1]];
triangles[i].tspace[2] = &tspace[lt->tri[2]];
+ }
- if (calculate_normal) {
- if (lt->poly != mpoly_prev) {
- const MPoly *mp = &me->mpoly[lt->poly];
- BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no);
- mpoly_prev = lt->poly;
- }
- copy_v3_v3(triangles[i].normal, no);
- }
- else {
- copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]);
+ if (calculate_normal) {
+ if (lt->poly != mpoly_prev) {
+ BKE_mesh_calc_poly_normal(mp, &me->mloop[mp->loopstart], me->mvert, no);
+ mpoly_prev = lt->poly;
}
+ copy_v3_v3(triangles[i].normal, no);
+ }
+ else {
+ copy_v3_v3(triangles[i].normal, &precomputed_normals[lt->poly]);
}
}
MEM_freeN(looptri);
+
+ return triangles;
}
bool RE_bake_pixels_populate_from_objects(
@@ -451,26 +510,20 @@ bool RE_bake_pixels_populate_from_objects(
if (!is_cage) {
dm_low = CDDM_from_mesh(me_low);
- tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
- mesh_calc_tri_tessface(tris_low, me_low, true, dm_low);
+ tris_low = mesh_calc_tri_tessface(me_low, true, dm_low);
}
else if (is_custom_cage) {
- tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
- mesh_calc_tri_tessface(tris_low, me_low, false, NULL);
-
- tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh");
- mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL);
+ tris_low = mesh_calc_tri_tessface(me_low, false, NULL);
+ tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL);
}
else {
- tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh");
- mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL);
+ tris_cage = mesh_calc_tri_tessface(me_cage, false, NULL);
}
invert_m4_m4(imat_low, mat_low);
for (i = 0; i < tot_highpoly; i++) {
- tris_high[i] = MEM_mallocN(sizeof(TriTessFace) * highpoly[i].me->totface, "MVerts Highpoly Mesh");
- mesh_calc_tri_tessface(tris_high[i], highpoly[i].me, false, NULL);
+ tris_high[i] = mesh_calc_tri_tessface(highpoly[i].me, false, NULL);
dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me);
DM_ensure_tessface(dm_highpoly[i]);
@@ -490,6 +543,7 @@ bool RE_bake_pixels_populate_from_objects(
for (i = 0; i < num_pixels; i++) {
float co[3];
float dir[3];
+ TriTessFace *tri_low;
primitive_id = pixel_array_from[i].primitive_id;
@@ -504,18 +558,21 @@ bool RE_bake_pixels_populate_from_objects(
/* calculate from low poly mesh cage */
if (is_custom_cage) {
calc_point_from_barycentric_cage(tris_low, tris_cage, mat_low, mat_cage, primitive_id, u, v, co, dir);
+ tri_low = &tris_cage[primitive_id];
}
else if (is_cage) {
calc_point_from_barycentric_extrusion(tris_cage, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, true);
+ tri_low = &tris_cage[primitive_id];
}
else {
calc_point_from_barycentric_extrusion(tris_low, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, false);
+ tri_low = &tris_low[primitive_id];
}
/* cast ray */
- if (!cast_ray_highpoly(treeData, tris_high, pixel_array_to, highpoly, co, dir, i, tot_highpoly,
- pixel_array_from[i].du_dx, pixel_array_from[i].du_dy,
- pixel_array_from[i].dv_dx, pixel_array_from[i].dv_dy)) {
+ if (!cast_ray_highpoly(treeData, tri_low, tris_high,
+ pixel_array_from, pixel_array_to, mat_low,
+ highpoly, co, dir, i, tot_highpoly)) {
/* if it fails mask out the original pixel array */
pixel_array_from[i].primitive_id = -1;
}
@@ -583,73 +640,84 @@ void RE_bake_pixels_populate(
size_t i;
int a, p_id;
- MTFace *mtface;
- MFace *mface;
+ const MLoopUV *mloopuv;
+ const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
+ MLoopTri *looptri;
+#ifdef USE_MFACE_WORKAROUND
+ unsigned int mpoly_prev_testindex = UINT_MAX;
+#endif
- /* we can't bake in edit mode */
- if (me->edit_btmesh)
+ if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
+ mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
+ }
+ else {
+ int uv_id = CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer);
+ mloopuv = CustomData_get_layer_n(&me->ldata, CD_MTFACE, uv_id);
+ }
+
+ if (mloopuv == NULL)
return;
+
bd.pixel_array = pixel_array;
bd.zspan = MEM_callocN(sizeof(ZSpan) * bake_images->size, "bake zspan");
/* initialize all pixel arrays so we know which ones are 'blank' */
for (i = 0; i < num_pixels; i++) {
pixel_array[i].primitive_id = -1;
+ pixel_array[i].object_id = 0;
}
for (i = 0; i < bake_images->size; i++) {
zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop);
}
- if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
- mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
- }
- else {
- int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer);
- mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id);
- }
-
- mface = CustomData_get_layer(&me->fdata, CD_MFACE);
+ looptri = MEM_mallocN(sizeof(*looptri) * tottri, __func__);
- if (mtface == NULL)
- return;
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ looptri);
p_id = -1;
- for (i = 0; i < me->totface; i++) {
- float vec[4][2];
- MTFace *mtf = &mtface[i];
- MFace *mf = &mface[i];
- int mat_nr = mf->mat_nr;
+ for (i = 0; i < tottri; i++) {
+ const MLoopTri *lt = &looptri[i];
+ const MPoly *mp = &me->mpoly[lt->poly];
+ float vec[3][2];
+ int mat_nr = mp->mat_nr;
int image_id = bake_images->lookup[mat_nr];
bd.bk_image = &bake_images->data[image_id];
bd.primitive_id = ++p_id;
- for (a = 0; a < 4; a++) {
+#ifdef USE_MFACE_WORKAROUND
+ if (lt->poly != mpoly_prev_testindex) {
+ test_index_face_looptri(mp, me->mloop, &looptri[i]);
+ mpoly_prev_testindex = lt->poly;
+ }
+#endif
+
+ for (a = 0; a < 3; a++) {
+ const float *uv = mloopuv[lt->tri[a]].uv;
+
/* Note, workaround for pixel aligned UVs which are common and can screw up our intersection tests
* where a pixel gets in between 2 faces or the middle of a quad,
* camera aligned quads also have this problem but they are less common.
* Add a small offset to the UVs, fixes bug #18685 - Campbell */
- vec[a][0] = mtf->uv[a][0] * (float)bd.bk_image->width - (0.5f + 0.001f);
- vec[a][1] = mtf->uv[a][1] * (float)bd.bk_image->height - (0.5f + 0.002f);
+ vec[a][0] = uv[0] * (float)bd.bk_image->width - (0.5f + 0.001f);
+ vec[a][1] = uv[1] * (float)bd.bk_image->height - (0.5f + 0.002f);
}
bake_differentials(&bd, vec[0], vec[1], vec[2]);
zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[1], vec[2], store_bake_pixel);
-
- /* 4 vertices in the face */
- if (mf->v4 != 0) {
- bd.primitive_id = ++p_id;
-
- bake_differentials(&bd, vec[0], vec[2], vec[3]);
- zspan_scanconvert(&bd.zspan[image_id], (void *)&bd, vec[0], vec[2], vec[3], store_bake_pixel);
- }
}
for (i = 0; i < bake_images->size; i++) {
zbuf_free_span(&bd.zspan[i]);
}
+
+ MEM_freeN(looptri);
MEM_freeN(bd.zspan);
}
@@ -718,8 +786,7 @@ void RE_bake_normal_world_to_tangent(
DerivedMesh *dm = CDDM_from_mesh(me);
- triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh");
- mesh_calc_tri_tessface(triangles, me, true, dm);
+ triangles = mesh_calc_tri_tessface(me, true, dm);
BLI_assert(num_pixels >= 3);
@@ -749,7 +816,10 @@ void RE_bake_normal_world_to_tangent(
offset = i * depth;
if (primitive_id == -1) {
- copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f);
+ if (depth == 4)
+ copy_v4_fl4(&result[offset], 0.5f, 0.5f, 1.0f, 1.0f);
+ else
+ copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f);
continue;
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index ee28c3b286f..ccf54cb6bcd 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -140,29 +140,30 @@ static void split_v_renderfaces(ObjectRen *obr, int startvlak, int UNUSED(startv
for (v=0; v<vLen; v++) {
VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v);
+ VlakRen *vlr_other;
VertRen *vert = RE_vertren_copy(obr, vlr->v2);
if (cyclv) {
vlr->v2 = vert;
- if (v==vLen-1) {
- VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
- vlr->v1 = vert;
+ if (v == vLen - 1) {
+ vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + 0);
+ vlr_other->v1 = vert;
}
else {
- VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
- vlr->v1 = vert;
+ vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
+ vlr_other->v1 = vert;
}
}
else {
vlr->v2 = vert;
- if (v<vLen-1) {
- VlakRen *vlr = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
- vlr->v1 = vert;
+ if (v < vLen - 1) {
+ vlr_other = RE_findOrAddVlak(obr, startvlak + vLen*uIndex + v+1);
+ vlr_other->v1 = vert;
}
- if (v==0) {
+ if (v == 0) {
vlr->v1 = RE_vertren_copy(obr, vlr->v1);
}
}
@@ -1391,16 +1392,16 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
re->flag |= R_HALO;
- RE_set_customdata_names(obr, &psmd->dm->faceData);
- sd.totuv = CustomData_number_of_layers(&psmd->dm->faceData, CD_MTFACE);
- sd.totcol = CustomData_number_of_layers(&psmd->dm->faceData, CD_MCOL);
+ RE_set_customdata_names(obr, &psmd->dm_final->faceData);
+ sd.totuv = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MTFACE);
+ sd.totcol = CustomData_number_of_layers(&psmd->dm_final->faceData, CD_MCOL);
if (ma->texco & TEXCO_UV && sd.totuv) {
sd.uvco = MEM_callocN(sd.totuv * 2 * sizeof(float), "particle_uvs");
if (ma->strand_uvname[0]) {
- sd.override_uv = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, ma->strand_uvname);
- sd.override_uv -= CustomData_get_layer_index(&psmd->dm->faceData, CD_MTFACE);
+ sd.override_uv = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, ma->strand_uvname);
+ sd.override_uv -= CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
}
}
else
@@ -1411,15 +1412,15 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
/* 2.2 setup billboards */
if (part->ren_as == PART_DRAW_BB) {
- int first_uv = CustomData_get_layer_index(&psmd->dm->faceData, CD_MTFACE);
+ int first_uv = CustomData_get_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
- bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, psys->bb_uvname[0]);
+ bb.uv[0] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[0]);
if (bb.uv[0] < 0)
- bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm->faceData, CD_MTFACE);
+ bb.uv[0] = CustomData_get_active_layer_index(&psmd->dm_final->faceData, CD_MTFACE);
- bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, psys->bb_uvname[1]);
+ bb.uv[1] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[1]);
- bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm->faceData, CD_MTFACE, psys->bb_uvname[2]);
+ bb.uv[2] = CustomData_get_named_layer_index(&psmd->dm_final->faceData, CD_MTFACE, psys->bb_uvname[2]);
if (first_uv >= 0) {
bb.uv[0] -= first_uv;
@@ -1499,9 +1500,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if (ma->amb != 0.0f)
do_surfacecache = true;
- totface= psmd->dm->getNumTessFaces(psmd->dm);
- index_mf_to_mpoly = psmd->dm->getTessFaceDataArray(psmd->dm, CD_ORIGINDEX);
- index_mp_to_orig = psmd->dm->getPolyDataArray(psmd->dm, CD_ORIGINDEX);
+ totface= psmd->dm_final->getNumTessFaces(psmd->dm_final);
+ index_mf_to_mpoly = psmd->dm_final->getTessFaceDataArray(psmd->dm_final, CD_ORIGINDEX);
+ index_mp_to_orig = psmd->dm_final->getPolyDataArray(psmd->dm_final, CD_ORIGINDEX);
if (index_mf_to_mpoly == NULL) {
index_mp_to_orig = NULL;
}
@@ -1556,10 +1557,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
num= pa->num_dmcache;
if (num == DMCACHE_NOTFOUND)
- if (pa->num < psmd->dm->getNumTessFaces(psmd->dm))
+ if (pa->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
num= pa->num;
- get_particle_uvco_mcol(part->from, psmd->dm, pa->fuv, num, &sd);
+ get_particle_uvco_mcol(part->from, psmd->dm_final, pa->fuv, num, &sd);
pa_size = pa->size;
@@ -1610,17 +1611,17 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
/* get uvco & mcol */
if (part->childtype==PART_CHILD_FACES) {
- get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm, cpa->fuv, cpa->num, &sd);
+ get_particle_uvco_mcol(PART_FROM_FACE, psmd->dm_final, cpa->fuv, cpa->num, &sd);
}
else {
ParticleData *parent = psys->particles + cpa->parent;
num = parent->num_dmcache;
if (num == DMCACHE_NOTFOUND)
- if (parent->num < psmd->dm->getNumTessFaces(psmd->dm))
+ if (parent->num < psmd->dm_final->getNumTessFaces(psmd->dm_final))
num = parent->num;
- get_particle_uvco_mcol(part->from, psmd->dm, parent->fuv, num, &sd);
+ get_particle_uvco_mcol(part->from, psmd->dm_final, parent->fuv, num, &sd);
}
do_simplify = psys_render_simplify_params(psys, cpa, simplify);
@@ -1736,14 +1737,14 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
sub_v3_v3v3(loc0, loc1, loc);
add_v3_v3v3(loc0, loc1, loc0);
- particle_curve(re, obr, psmd->dm, ma, &sd, loc1, loc0, seed, pa_co);
+ particle_curve(re, obr, psmd->dm_final, ma, &sd, loc1, loc0, seed, pa_co);
}
sd.first = 0;
sd.time = time;
if (k)
- particle_curve(re, obr, psmd->dm, ma, &sd, loc, loc1, seed, pa_co);
+ particle_curve(re, obr, psmd->dm_final, ma, &sd, loc, loc1, seed, pa_co);
copy_v3_v3(loc1, loc);
}
@@ -1802,7 +1803,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
pa_co[0] = (part->draw & PART_ABS_PATH_TIME) ? (ct-pa_birthtime)/(pa_dietime-pa_birthtime) : ct;
pa_co[1] = (float)i/(float)(trail_count-1);
- particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize, pa_co);
+ particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
}
}
else {
@@ -1838,7 +1839,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
bb.lifetime = pa_dietime-pa_birthtime;
}
- particle_normal_ren(part->ren_as, part, re, obr, psmd->dm, ma, &sd, &bb, &state, seed, hasize, pa_co);
+ particle_normal_ren(part->ren_as, part, re, obr, psmd->dm_final, ma, &sd, &bb, &state, seed, hasize, pa_co);
}
}
@@ -1850,7 +1851,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
}
if (do_surfacecache)
- strandbuf->surface= cache_strand_surface(re, obr, psmd->dm, mat, timeoffset);
+ strandbuf->surface= cache_strand_surface(re, obr, psmd->dm_final, mat, timeoffset);
/* 4. clean up */
#if 0 /* XXX old animation system */
@@ -3130,9 +3131,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
copy_m3_m4(imat, ob->imat);
negative_scale= is_negative_m4(mat);
- if (me->totvert==0)
- return;
-
need_orco= 0;
for (a=1; a<=ob->totcol; a++) {
ma= give_render_material(re, ob, a);
@@ -3193,6 +3191,14 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
dm= mesh_create_derived_render(re->scene, ob, mask);
if (dm==NULL) return; /* in case duplicated object fails? */
+ mvert= dm->getVertArray(dm);
+ totvert= dm->getNumVerts(dm);
+
+ if (totvert == 0) {
+ dm->release(dm);
+ return;
+ }
+
if (mask & CD_MASK_ORCO) {
orco = get_object_orco(re, ob);
if (!orco) {
@@ -3204,9 +3210,6 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
}
- mvert= dm->getVertArray(dm);
- totvert= dm->getNumVerts(dm);
-
/* attempt to autsmooth on original mesh, only without subsurf */
if (do_autosmooth && me->totvert==totvert && me->totface==dm->getNumTessFaces(dm))
use_original_normals= true;
@@ -3798,6 +3801,9 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
lar->falloff_type = la->falloff_type;
lar->ld1= la->att1;
lar->ld2= la->att2;
+ lar->coeff_const= la->coeff_const;
+ lar->coeff_lin= la->coeff_lin;
+ lar->coeff_quad= la->coeff_quad;
lar->curfalloff = curvemapping_copy(la->curfalloff);
if (lar->curfalloff) {
@@ -3955,7 +3961,7 @@ static void add_lightgroup(Render *re, Group *group, int exclusive)
{
GroupObject *go, *gol;
- group->id.flag &= ~LIB_DOIT;
+ group->id.tag &= ~LIB_TAG_DOIT;
/* it's a bit too many loops in loops... but will survive */
/* note that 'exclusive' will remove it from the global list */
@@ -3994,12 +4000,12 @@ static void set_material_lightgroups(Render *re)
return;
for (group= re->main->group.first; group; group=group->id.next)
- group->id.flag |= LIB_DOIT;
+ group->id.tag |= LIB_TAG_DOIT;
/* it's a bit too many loops in loops... but will survive */
/* hola! materials not in use...? */
for (ma= re->main->mat.first; ma; ma=ma->id.next) {
- if (ma->group && (ma->group->id.flag & LIB_DOIT))
+ if (ma->group && (ma->group->id.tag & LIB_TAG_DOIT))
add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
}
}
@@ -4251,6 +4257,7 @@ static void check_non_flat_quads(ObjectRen *obr)
vlr->v2= v3;
vlr->v3= v4;
vlr->v4= NULL;
+ vlr->flag |= (R_DIVIDE_24 | R_FACE_SPLIT);
}
else {
sub_v3_v3v3(nor, v2->co, v3->co);
@@ -4258,6 +4265,7 @@ static void check_non_flat_quads(ObjectRen *obr)
vlr->v2= v3;
vlr->v3= v4;
vlr->v4= NULL;
+ vlr->flag |= R_FACE_SPLIT;
}
else {
sub_v3_v3v3(nor, v3->co, v4->co);
@@ -4658,7 +4666,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
/* only add instance for objects that have not been used for dupli */
if (!(ob->transflag & OB_RENDER_DUPLI)) {
- obi= RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay);
+ obi = RE_addRenderInstance(re, obr, ob, par, index, 0, NULL, ob->lay, dob);
if (dob) set_dupli_tex_mat(re, obi, dob, omat);
}
else
@@ -4692,7 +4700,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
/* only add instance for objects that have not been used for dupli */
if (!(ob->transflag & OB_RENDER_DUPLI)) {
- obi= RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay);
+ obi = RE_addRenderInstance(re, obr, ob, par, index, psysindex, NULL, ob->lay, dob);
if (dob) set_dupli_tex_mat(re, obi, dob, omat);
}
else
@@ -5053,7 +5061,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) {
mul_m4_m4m4(mat, re->viewmat, dob->mat);
/* ob = particle system, use that layer */
- obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay);
+ obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay, dob);
/* fill in instance variables for texturing */
set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
@@ -5080,7 +5088,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) {
if (obi == NULL)
mul_m4_m4m4(mat, re->viewmat, dob->mat);
- obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay);
+ obi = RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay, dob);
set_dupli_tex_mat(re, obi, dob, dob_extra->obmat);
if (dob->type != OB_DUPLIGROUP) {
@@ -5868,11 +5876,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
re->lay= lay;
/* renderdata setup and exceptions */
- BLI_freelistN(&re->r.layers);
- BLI_freelistN(&re->r.views);
- re->r = scene->r;
- BLI_duplicatelist(&re->r.layers, &scene->r.layers);
- BLI_duplicatelist(&re->r.views, &scene->r.views);
+ render_copy_renderdata(&re->r, &scene->r);
RE_init_threadcount(re);
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index b9b908f550b..b1afb86e5af 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -56,7 +56,8 @@
/* this module */
#include "render_types.h"
#include "envmap.h"
-#include "renderdatabase.h"
+#include "renderdatabase.h"
+#include "renderpipeline.h"
#include "texture.h"
#include "zbuf.h"
@@ -138,7 +139,7 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
envre->flag = re->flag;
/* set up renderdata */
- envre->r = re->r;
+ render_copy_renderdata(&envre->r, &re->r);
envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
BLI_listbase_clear(&envre->r.layers);
BLI_listbase_clear(&envre->r.views);
@@ -262,7 +263,6 @@ static void env_set_imats(Render *re)
void env_rotate_scene(Render *re, float mat[4][4], int do_rotate)
{
- GroupObject *go;
ObjectRen *obr;
ObjectInstanceRen *obi;
LampRen *lar = NULL;
@@ -321,19 +321,18 @@ void env_rotate_scene(Render *re, float mat[4][4], int do_rotate)
invert_m4(obr->ob->imat_ren);
}
- for (go = re->lights.first; go; go = go->next) {
- lar = go->lampren;
-
+ for (lar = re->lampren.first; lar; lar = lar->next) {
+ float lamp_imat[4][4];
+
/* copy from add_render_lamp */
if (do_rotate == 1)
mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat);
else
mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat);
- invert_m4_m4(go->ob->imat, tmpmat);
-
+
+ invert_m4_m4(lamp_imat, tmpmat);
copy_m3_m4(lar->mat, tmpmat);
-
- copy_m3_m4(lar->imat, go->ob->imat);
+ copy_m3_m4(lar->imat, lamp_imat);
lar->vec[0]= -tmpmat[2][0];
lar->vec[1]= -tmpmat[2][1];
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index fef453efce2..fd9d95c63b6 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -44,6 +44,7 @@
#include "BKE_camera.h"
#include "BKE_global.h"
+#include "BKE_colortools.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -361,32 +362,56 @@ void RE_engine_set_error_message(RenderEngine *engine, const char *msg)
Render *re = engine->re;
if (re != NULL) {
RenderResult *rr = RE_AcquireResultRead(re);
- if (rr->error != NULL) {
- MEM_freeN(rr->error);
+ if (rr) {
+ if (rr->error != NULL) {
+ MEM_freeN(rr->error);
+ }
+ rr->error = BLI_strdup(msg);
}
- rr->error = BLI_strdup(msg);
RE_ReleaseResult(re);
}
}
+const char *RE_engine_active_view_get(RenderEngine *engine)
+{
+ Render *re = engine->re;
+ return RE_GetActiveRenderView(re);
+}
+
void RE_engine_active_view_set(RenderEngine *engine, const char *viewname)
{
Render *re = engine->re;
RE_SetActiveRenderView(re, viewname);
}
-float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera)
+float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, int use_spherical_stereo)
{
Render *re = engine->re;
+
+ /* when using spherical stereo, get camera shift without multiview, leaving stereo to be handled by the engine */
+ if (use_spherical_stereo)
+ re = NULL;
+
return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
}
-void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, float *r_modelmat)
+void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, int use_spherical_stereo, float *r_modelmat)
{
Render *re = engine->re;
+
+ /* when using spherical stereo, get model matrix without multiview, leaving stereo to be handled by the engine */
+ if (use_spherical_stereo)
+ re = NULL;
+
BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat);
}
+int RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera)
+{
+ Render *re = engine->re;
+ return BKE_camera_multiview_spherical_stereo(re ? &re->r : NULL, camera) ? 1 : 0;
+}
+
rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_free)
{
static rcti tiles_static[BLENDER_MAX_THREADS];
@@ -412,15 +437,18 @@ rcti* RE_engine_get_current_tiles(Render *re, int *r_total_tiles, bool *r_needs_
/* Just in case we're using crazy network rendering with more
* slaves as BLENDER_MAX_THREADS.
*/
- if (tiles == tiles_static)
- tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles");
- else
- tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti));
-
allocation_size += allocation_step;
+ if (tiles == tiles_static) {
+ /* Can not realloc yet, tiles are pointing to a
+ * stack memory.
+ */
+ tiles = MEM_mallocN(allocation_size * sizeof(rcti), "current engine tiles");
+ }
+ else {
+ tiles = MEM_reallocN(tiles, allocation_size * sizeof(rcti));
+ }
*r_needs_free = true;
}
-
tiles[total_tiles] = pa->disprect;
if (pa->crop) {
@@ -448,13 +476,7 @@ void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
{
re->scene = scene;
re->main = bmain;
- re->r = scene->r;
-
- /* prevent crash when freeing the scene
- * but it potentially leaves unfreed memory blocks
- * not sure how to fix this yet -- dfelinto */
- BLI_listbase_clear(&re->r.layers);
- BLI_listbase_clear(&re->r.views);
+ render_copy_renderdata(&re->r, &scene->r);
}
bool RE_bake_has_engine(Render *re)
@@ -467,7 +489,8 @@ bool RE_bake_engine(
Render *re, Object *object,
const int object_id, const BakePixel pixel_array[],
const size_t num_pixels, const int depth,
- const ScenePassType pass_type, float result[])
+ const ScenePassType pass_type, const int pass_filter,
+ float result[])
{
RenderEngineType *type = RE_engines_find(re->r.engine);
RenderEngine *engine;
@@ -503,7 +526,7 @@ bool RE_bake_engine(
type->update(engine, re->main, re->scene);
if (type->bake)
- type->bake(engine, re->scene, object, pass_type, object_id, pixel_array, num_pixels, depth, result);
+ type->bake(engine, re->scene, object, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result);
engine->tile_x = 0;
engine->tile_y = 0;
@@ -596,7 +619,7 @@ int RE_engine_render(Render *re, int do_all)
if (re->r.scemode & R_SINGLE_LAYER) {
srl = BLI_findlink(&re->r.layers, re->r.actlay);
if (srl) {
- non_excluded_lay |= ~srl->lay_exclude;
+ non_excluded_lay |= ~(srl->lay_exclude & ~srl->lay_zmask);
/* in this case we must update all because animation for
* the scene has not been updated yet, and so may not be
@@ -608,7 +631,7 @@ int RE_engine_render(Render *re, int do_all)
else {
for (srl = re->r.layers.first; srl; srl = srl->next) {
if (!(srl->layflag & SCE_LAY_DISABLE)) {
- non_excluded_lay |= ~srl->lay_exclude;
+ non_excluded_lay |= ~(srl->lay_exclude & ~srl->lay_zmask);
if (render_layer_exclude_animated(re->scene, srl))
non_excluded_lay |= ~0;
@@ -642,6 +665,11 @@ int RE_engine_render(Render *re, int do_all)
if (re->draw_lock) {
re->draw_lock(re->dlh, 0);
}
+ /* Too small image is handled earlier, here it could only happen if
+ * there was no sufficient memory to allocate all passes.
+ */
+ BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
+ G.is_break = true;
return 1;
}
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index b44c0135420..04010522c12 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -1055,6 +1055,13 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
fx -= xs;
fy -= ys;
}
+ else if ((tex->flag & TEX_CHECKER_ODD) == 0 &&
+ (tex->flag & TEX_CHECKER_EVEN) == 0)
+ {
+ if (ima)
+ BKE_image_pool_release_ibuf(ima, ibuf, pool);
+ return retval;
+ }
else {
int xs1 = (int)floorf(fx - minx);
int ys1 = (int)floorf(fy - miny);
@@ -1248,7 +1255,9 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
texres->ta += levf*(texr.ta - texres->ta);
}
- alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
+ if (tex->texfilter != TXF_EWA) {
+ alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
+ }
}
}
else { /* no mipmap */
@@ -1290,7 +1299,9 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
}
else {
filterfunc(texres, ibuf, fx, fy, &AFD);
- alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
+ if (tex->texfilter != TXF_EWA) {
+ alpha_clip_aniso(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, extflag, texres);
+ }
}
}
@@ -1472,6 +1483,13 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
fx-= xs;
fy-= ys;
}
+ else if ((tex->flag & TEX_CHECKER_ODD) == 0 &&
+ (tex->flag & TEX_CHECKER_EVEN) == 0)
+ {
+ if (ima)
+ BKE_image_pool_release_ibuf(ima, ibuf, pool);
+ return retval;
+ }
else {
xs1= (int)floor(fx-minx);
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 0223f76f869..8eb6e7000ab 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -612,7 +612,7 @@ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm,
int col = cell_index % polys_per_grid_side;
/* S is the vertex whose grid we are examining */
- S = loc_cage_poly_offs / (polys_per_grid_side * polys_per_grid_side);
+ S = poly_index / (1 << (2 * (lvl - 1))) - grid_offset[cage_face_index];
/* get offset of grid data for original cage face */
g_index = grid_offset[cage_face_index];
@@ -1189,20 +1189,20 @@ static void count_images(MultiresBakeRender *bkr)
totpoly = dm->getNumPolys(dm);
for (a = 0; a < totpoly; a++)
- mtexpoly[a].tpage->id.flag &= ~LIB_DOIT;
+ mtexpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
for (a = 0; a < totpoly; a++) {
Image *ima = mtexpoly[a].tpage;
- if ((ima->id.flag & LIB_DOIT) == 0) {
+ if ((ima->id.tag & LIB_TAG_DOIT) == 0) {
LinkData *data = BLI_genericNodeN(ima);
BLI_addtail(&bkr->image, data);
bkr->tot_image++;
- ima->id.flag |= LIB_DOIT;
+ ima->id.tag |= LIB_TAG_DOIT;
}
}
for (a = 0; a < totpoly; a++)
- mtexpoly[a].tpage->id.flag &= ~LIB_DOIT;
+ mtexpoly[a].tpage->id.tag &= ~LIB_TAG_DOIT;
}
static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
@@ -1234,7 +1234,7 @@ static void bake_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
BKE_image_release_ibuf(ima, ibuf, NULL);
- ima->id.flag |= LIB_DOIT;
+ ima->id.tag |= LIB_TAG_DOIT;
}
}
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 46fb0603038..93666bd2a48 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -34,7 +34,9 @@
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
+#include <errno.h>
+#include "DNA_anim_types.h"
#include "DNA_image_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -59,6 +61,7 @@
#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
#include "BKE_camera.h"
+#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -135,7 +138,7 @@ Render R;
/* ********* alloc and free ******** */
-static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override);
+static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const int totvideos, const char *name_override);
static volatile int g_break = 0;
static int thread_break(void *UNUSED(arg))
@@ -196,6 +199,39 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
fflush(stdout);
}
+static void render_print_save_message(
+ ReportList *reports, const char *name, int ok, int err)
+{
+ if (ok) {
+ /* no need to report, just some helpful console info */
+ printf("Saved: '%s'\n", name);
+ }
+ else {
+ /* report on error since users will want to know what failed */
+ BKE_reportf(reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), name);
+ }
+}
+
+static int render_imbuf_write_stamp_test(
+ ReportList *reports,
+ Scene *scene, struct RenderResult *rr, ImBuf *ibuf, const char *name,
+ const ImageFormatData *imf, bool stamp)
+{
+ int ok;
+
+ if (stamp) {
+ /* writes the name of the individual cameras */
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, imf);
+ }
+ else {
+ ok = BKE_imbuf_write(ibuf, name, imf);
+ }
+
+ render_print_save_message(reports, name, ok, errno);
+
+ return ok;
+}
+
void RE_FreeRenderResult(RenderResult *res)
{
render_result_free(res);
@@ -416,6 +452,8 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id)
rr->xof = re->disprect.xmin;
rr->yof = re->disprect.ymin;
+
+ rr->stamp_data = re->result->stamp_data;
}
}
}
@@ -430,7 +468,7 @@ void RE_ReleaseResultImage(Render *re)
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
- const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname);
+ const int view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname);
RE_AcquireResultImageViews(re, &rres);
render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id);
@@ -505,6 +543,8 @@ void RE_FreeRender(Render *re)
BLI_freelistN(&re->r.layers);
BLI_freelistN(&re->r.views);
+ curvemapping_free_data(&re->r.mblur_shutter_curve);
+
/* main dbase can already be invalid now, some database-free code checks it */
re->main = NULL;
re->scene = NULL;
@@ -533,6 +573,17 @@ void RE_FreeAllRender(void)
#endif
}
+void RE_FreeAllPersistentData(void)
+{
+ Render *re;
+ for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) {
+ if ((re->r.mode & R_PERSISTENT_DATA) != 0 && re->engine != NULL) {
+ RE_engine_free(re->engine);
+ re->engine = NULL;
+ }
+ }
+}
+
/* on file load, free all re */
void RE_FreeAllRenderResults(void)
{
@@ -637,6 +688,19 @@ static void re_init_resolution(Render *re, Render *source,
re->clipcrop = 1.0f + 2.0f / (float)(re->winx > re->winy ? re->winy : re->winx);
}
+void render_copy_renderdata(RenderData *to, RenderData *from)
+{
+ BLI_freelistN(&to->layers);
+ BLI_freelistN(&to->views);
+ curvemapping_free_data(&to->mblur_shutter_curve);
+
+ *to = *from;
+
+ BLI_duplicatelist(&to->layers, &from->layers);
+ BLI_duplicatelist(&to->views, &from->views);
+ curvemapping_copy_data(&to->mblur_shutter_curve, &from->mblur_shutter_curve);
+}
+
/* what doesn't change during entire render sequence */
/* disprect is optional, if NULL it assumes full window render */
void RE_InitState(Render *re, Render *source, RenderData *rd,
@@ -650,11 +714,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd,
re->i.starttime = PIL_check_seconds_timer();
/* copy render data and render layers for thread safety */
- BLI_freelistN(&re->r.layers);
- BLI_freelistN(&re->r.views);
- re->r = *rd;
- BLI_duplicatelist(&re->r.layers, &rd->layers);
- BLI_duplicatelist(&re->r.views, &rd->views);
+ render_copy_renderdata(&re->r, rd);
if (source) {
/* reuse border flags from source renderer */
@@ -1443,7 +1503,6 @@ void RE_TileProcessor(Render *re)
static void do_render_3d(Render *re)
{
RenderView *rv;
- int cfra_backup;
re->current_scene_update(re->suh, re->scene);
@@ -1455,12 +1514,20 @@ static void do_render_3d(Render *re)
RE_parts_clamp(re);
/* add motion blur and fields offset to frames */
- cfra_backup = re->scene->r.cfra;
+ const int cfra_backup = re->scene->r.cfra;
+ const float subframe_backup = re->scene->r.subframe;
- BKE_scene_frame_set(re->scene, (double)re->scene->r.cfra + (double)re->mblur_offs + (double)re->field_offs);
+ BKE_scene_frame_set(
+ re->scene, (double)re->scene->r.cfra + (double)re->scene->r.subframe +
+ (double)re->mblur_offs + (double)re->field_offs);
/* init main render result */
main_render_result_new(re);
+ if (re->result == NULL) {
+ BKE_report(re->reports, RPT_ERROR, "Failed allocate render result, out of memory");
+ G.is_break = true;
+ return;
+ }
#ifdef WITH_FREESTYLE
if (re->r.mode & R_EDGE_FRS) {
@@ -1509,7 +1576,7 @@ static void do_render_3d(Render *re)
main_render_result_end(re);
re->scene->r.cfra = cfra_backup;
- re->scene->r.subframe = 0.f;
+ re->scene->r.subframe = subframe_backup;
}
/* called by blur loop, accumulate RGBA key alpha */
@@ -1996,7 +2063,7 @@ static void tag_scenes_for_render(Render *re)
#endif
for (sce = re->main->scene.first; sce; sce = sce->id.next) {
- sce->id.flag &= ~LIB_DOIT;
+ sce->id.tag &= ~LIB_TAG_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
tag_dependend_objects_for_render(sce, renderlay);
#endif
@@ -2005,7 +2072,7 @@ static void tag_scenes_for_render(Render *re)
#ifdef WITH_FREESTYLE
if (re->freestyle_bmain) {
for (sce = re->freestyle_bmain->scene.first; sce; sce = sce->id.next) {
- sce->id.flag &= ~LIB_DOIT;
+ sce->id.tag &= ~LIB_TAG_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
tag_dependend_objects_for_render(sce, renderlay);
#endif
@@ -2014,7 +2081,7 @@ static void tag_scenes_for_render(Render *re)
#endif
if (RE_GetCamera(re) && composite_needs_render(re->scene, 1)) {
- re->scene->id.flag |= LIB_DOIT;
+ re->scene->id.tag |= LIB_TAG_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
tag_dependend_objects_for_render(re->scene, renderlay);
#endif
@@ -2022,7 +2089,7 @@ static void tag_scenes_for_render(Render *re)
if (re->scene->nodetree == NULL) return;
- /* check for render-layers nodes using other scenes, we tag them LIB_DOIT */
+ /* check for render-layers nodes using other scenes, we tag them LIB_TAG_DOIT */
for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
node->flag &= ~NODE_TEST;
if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
@@ -2043,11 +2110,11 @@ static void tag_scenes_for_render(Render *re)
}
if (node->id != (ID *)re->scene) {
- if ((node->id->flag & LIB_DOIT) == 0) {
+ if ((node->id->tag & LIB_TAG_DOIT) == 0) {
Scene *scene = (Scene *) node->id;
if (render_scene_has_layers_to_render(scene)) {
node->flag |= NODE_TEST;
- node->id->flag |= LIB_DOIT;
+ node->id->tag |= LIB_TAG_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
tag_dependend_objects_for_render(scene, renderlay);
#endif
@@ -2097,9 +2164,10 @@ static void ntree_render_scenes(Render *re)
/* bad call... need to think over proper method still */
static void render_composit_stats(void *UNUSED(arg), const char *str)
{
- R.i.infostr = str;
- R.stats_draw(R.sdh, &R.i);
- R.i.infostr = NULL;
+ RenderStats i;
+ memcpy(&i, &R.i, sizeof(i));
+ i.infostr = str;
+ R.stats_draw(R.sdh, &i);
}
#ifdef WITH_FREESTYLE
@@ -2265,7 +2333,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
tag_scenes_for_render(re);
for (sce = re->main->scene.first; sce; sce = sce->id.next) {
- if (sce->id.flag & LIB_DOIT) {
+ if (sce->id.tag & LIB_TAG_DOIT) {
re1 = RE_GetRender(sce->id.name);
if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) {
@@ -2366,7 +2434,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
/* garbage collection */
while (rectfs->first) {
- RenderView *rv = rectfs->first;
+ rv = rectfs->first;
BLI_remlink(rectfs, rv);
MEM_freeN(rv);
}
@@ -2390,12 +2458,12 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
/* tag scenes unread */
for (scene = re->main->scene.first; scene; scene = scene->id.next)
- scene->id.flag |= LIB_DOIT;
+ scene->id.tag |= LIB_TAG_DOIT;
#ifdef WITH_FREESTYLE
if (re->freestyle_bmain) {
for (scene = re->freestyle_bmain->scene.first; scene; scene = scene->id.next)
- scene->id.flag &= ~LIB_DOIT;
+ scene->id.tag &= ~LIB_TAG_DOIT;
}
#endif
@@ -2404,18 +2472,18 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
Scene *nodescene = (Scene *)node->id;
if (nodescene == NULL) nodescene = sce;
- if (nodescene->id.flag & LIB_DOIT) {
+ if (nodescene->id.tag & LIB_TAG_DOIT) {
nodescene->r.mode |= R_OSA; /* render struct needs tables */
RE_ReadRenderResult(sce, nodescene);
- nodescene->id.flag &= ~LIB_DOIT;
+ nodescene->id.tag &= ~LIB_TAG_DOIT;
}
}
}
/* own render result should be read/allocated */
- if (re->scene->id.flag & LIB_DOIT) {
+ if (re->scene->id.tag & LIB_TAG_DOIT) {
RE_ReadRenderResult(re->scene, re->scene);
- re->scene->id.flag &= ~LIB_DOIT;
+ re->scene->id.tag &= ~LIB_TAG_DOIT;
}
/* and now we can draw (result is there) */
@@ -2533,8 +2601,10 @@ static void do_render_composite_fields_blur_3d(Render *re)
#endif
/* weak... the display callback wants an active renderlayer pointer... */
- re->result->renlay = render_get_active_layer(re, re->result);
- re->display_update(re->duh, re->result, NULL);
+ if (re->result != NULL) {
+ re->result->renlay = render_get_active_layer(re, re->result);
+ re->display_update(re->duh, re->result, NULL);
+ }
}
static void renderresult_stampinfo(Render *re)
@@ -2548,7 +2618,13 @@ static void renderresult_stampinfo(Render *re)
for (rv = re->result->views.first;rv;rv = rv->next, nr++) {
RE_SetActiveRenderView(re, rv->name);
RE_AcquireResultImage(re, &rres, nr);
- BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
+ BKE_image_stamp_buf(re->scene,
+ RE_GetCamera(re),
+ (re->r.stamp & R_STAMP_STRIPMETA) ? rres.stamp_data : NULL,
+ (unsigned char *)rres.rect32,
+ rres.rectf,
+ rres.rectx, rres.recty,
+ 4);
RE_ReleaseResultImage(re);
}
}
@@ -2578,7 +2654,7 @@ static void do_render_seq(Render *re)
RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */
int cfra = re->r.cfra;
SeqRenderData context;
- size_t view_id, tot_views;
+ int view_id, tot_views;
struct ImBuf **ibuf_arr;
int re_x, re_y;
@@ -2640,7 +2716,7 @@ static void do_render_seq(Render *re)
if (ibuf_arr[view_id]) {
/* copy ibuf into combined pixel rect */
- render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id);
+ RE_render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id);
if (ibuf_arr[view_id]->metadata && (re->r.stamp & R_STAMP_STRIPMETA)) {
/* ensure render stamp info first */
@@ -2725,15 +2801,17 @@ static void do_render_all_options(Render *re)
re->stats_draw(re->sdh, &re->i);
/* save render result stamp if needed */
- camera = RE_GetCamera(re);
- /* sequence rendering should have taken care of that already */
- if (!(render_seq && (re->r.stamp & R_STAMP_STRIPMETA)))
- BKE_render_result_stamp_info(re->scene, camera, re->result, false);
+ if (re->result != NULL) {
+ camera = RE_GetCamera(re);
+ /* sequence rendering should have taken care of that already */
+ if (!(render_seq && (re->r.stamp & R_STAMP_STRIPMETA)))
+ BKE_render_result_stamp_info(re->scene, camera, re->result, false);
- /* stamp image info here */
- if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) {
- renderresult_stampinfo(re);
- re->display_update(re->duh, re->result, NULL);
+ /* stamp image info here */
+ if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) {
+ renderresult_stampinfo(re);
+ re->display_update(re->duh, re->result, NULL);
+ }
}
}
@@ -2759,13 +2837,14 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override
while (node) {
if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
Scene *sce = node->id ? (Scene *)node->id : scene;
-
- if (!sce->camera && !BKE_scene_camera_find(sce)) {
+ if (sce->camera == NULL) {
+ sce->camera = BKE_scene_camera_find(sce);
+ }
+ if (sce->camera == NULL) {
/* all render layers nodes need camera */
return false;
}
}
-
node = node->next;
}
@@ -2814,6 +2893,8 @@ static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportLis
static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports)
{
+ const char *err_msg = "No camera found in scene \"%s\"";
+
if (camera_override == NULL && scene->camera == NULL)
scene->camera = BKE_scene_camera_find(scene);
@@ -2825,14 +2906,17 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
Sequence *seq = scene->ed->seqbase.first;
while (seq) {
- if (seq->type == SEQ_TYPE_SCENE && seq->scene) {
+ if ((seq->type == SEQ_TYPE_SCENE) &&
+ ((seq->flag & SEQ_SCENE_STRIPS) == 0) &&
+ (seq->scene != NULL))
+ {
if (!seq->scene_camera) {
if (!seq->scene->camera && !BKE_scene_camera_find(seq->scene)) {
/* camera could be unneeded due to composite nodes */
Object *override = (seq->scene == scene) ? camera_override : NULL;
if (!check_valid_compositing_camera(seq->scene, override)) {
- BKE_reportf(reports, RPT_ERROR, "No camera found in scene \"%s\"", seq->scene->id.name+2);
+ BKE_reportf(reports, RPT_ERROR, err_msg, seq->scene->id.name + 2);
return false;
}
}
@@ -2846,7 +2930,7 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
}
}
else if (!check_valid_compositing_camera(scene, camera_override)) {
- BKE_report(reports, RPT_ERROR, "No camera found in scene");
+ BKE_reportf(reports, RPT_ERROR, err_msg, scene->id.name + 2);
return false;
}
@@ -2990,16 +3074,13 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init)
{
PTCacheBaker baker;
+ memset(&baker, 0, sizeof(baker));
baker.main = re->main;
baker.scene = scene;
- baker.pid = NULL;
baker.bake = 0;
baker.render = 1;
baker.anim_init = 1;
baker.quick_step = 1;
- baker.break_test = re->test_break;
- baker.break_data = re->tbh;
- baker.progressbar = NULL;
BKE_ptcache_bake(&baker);
}
@@ -3157,11 +3238,17 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render
void RE_RenderFreestyleExternal(Render *re)
{
if (!re->test_break(re->tbh)) {
- RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
- RE_Database_Preprocess(re);
+ RenderView *rv;
+
init_freestyle(re);
- add_freestyle(re, 1);
- RE_Database_Free(re);
+
+ for (rv = re->result->views.first; rv; rv = rv->next) {
+ RE_SetActiveRenderView(re, rv->name);
+ RE_Database_FromScene(re, re->main, re->scene, re->lay, 1);
+ RE_Database_Preprocess(re);
+ add_freestyle(re, 1);
+ RE_Database_Free(re);
+ }
}
}
#endif
@@ -3180,15 +3267,15 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW)
{
- RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL);
- printf("Saved: %s\n", name);
+ ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL);
+ render_print_save_message(reports, name, ok, errno);
}
/* mono, legacy code */
else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL))
{
RenderView *rv;
- size_t view_id;
+ int view_id;
char filepath[FILE_MAX];
BLI_strncpy(filepath, name, sizeof(filepath));
@@ -3199,8 +3286,8 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
}
if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name);
- printf("Saved: %s\n", name);
+ ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name);
+ render_print_save_message(reports, name, ok, errno);
}
else {
ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id);
@@ -3208,18 +3295,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
&scene->display_settings, &rd->im_format);
- if (stamp) {
- /* writes the name of the individual cameras */
- ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format);
- }
- else {
- ok = BKE_imbuf_write(ibuf, name, &rd->im_format);
- }
-
- if (ok == false) {
- printf("Render error: cannot save %s\n", name);
- }
- else printf("Saved: %s\n", name);
+ ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &rd->im_format, stamp);
/* optional preview images for exr */
if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
@@ -3234,14 +3310,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
&scene->display_settings, &imf);
- if (stamp) {
- /* writes the name of the individual cameras */
- ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &imf);
- }
- else {
- ok = BKE_imbuf_write(ibuf, name, &imf);
- }
- printf("Saved: %s\n", name);
+ ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &imf, stamp);
}
/* imbuf knows which rects are not part of ibuf */
@@ -3270,15 +3339,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
- if (stamp)
- ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format);
- else
- ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format);
-
- if (ok == false)
- printf("Render error: cannot save %s\n", name);
- else
- printf("Saved: %s\n", name);
+ ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp);
/* optional preview images for exr */
if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR &&
@@ -3296,12 +3357,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings,
&scene->display_settings, &imf);
- if (stamp)
- ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format);
- else
- ok = BKE_imbuf_write(ibuf_arr[2], name, &imf);
-
- printf("Saved: %s\n", name);
+ ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp);
}
/* imbuf knows which rects are not part of ibuf */
@@ -3314,8 +3370,9 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen
return ok;
}
-bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh,
- const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos, bool preview)
+bool RE_WriteRenderViewsMovie(
+ ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh,
+ void **movie_ctx_arr, const int totvideos, bool preview)
{
bool is_mono;
bool ok = true;
@@ -3326,32 +3383,17 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen
is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2;
if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- size_t view_id;
+ int view_id;
for (view_id = 0; view_id < totvideos; view_id++) {
- bool do_free = false;
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id);
- /* note; the way it gets 32 bits rects is weak... */
- if (ibuf->rect == NULL) {
- ibuf->rect = MEM_mapallocN(sizeof(int) * rr->rectx * rr->recty, "temp 32 bits rect");
- ibuf->mall |= IB_rect;
- render_result_rect_get_pixels(rr, ibuf->rect, width, height, &scene->view_settings, &scene->display_settings, view_id);
- do_free = true;
- }
-
IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
&scene->display_settings, &scene->r.im_format);
ok &= mh->append_movie(movie_ctx_arr[view_id], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra,
(int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports);
- if (do_free) {
- MEM_freeN(ibuf->rect);
- ibuf->rect = NULL;
- ibuf->mall &= ~IB_rect;
- }
-
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf);
}
@@ -3360,8 +3402,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen
else { /* R_IMF_VIEWS_STEREO_3D */
const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
ImBuf *ibuf_arr[3] = {NULL};
- bool do_free[2] = {false, false};
- size_t i;
+ int i;
BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D));
@@ -3369,14 +3410,6 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen
int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id);
- /* note; the way it gets 32 bits rects is weak... */
- if (ibuf_arr[i]->rect == NULL) {
- ibuf_arr[i]->rect = MEM_mapallocN(sizeof(int) * width * height, "temp 32 bits rect");
- ibuf_arr[i]->mall |= IB_rect;
- render_result_rect_get_pixels(rr, ibuf_arr[i]->rect, width, height, &scene->view_settings, &scene->display_settings, view_id);
- do_free[i] = true;
- }
-
IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings,
&scene->display_settings, &scene->r.im_format);
}
@@ -3387,12 +3420,6 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen
ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports);
for (i = 0; i < 2; i++) {
- if (do_free[i]) {
- MEM_freeN(ibuf_arr[i]->rect);
- ibuf_arr[i]->rect = NULL;
- ibuf_arr[i]->mall &= ~IB_rect;
- }
-
/* imbuf knows which rects are not part of ibuf */
IMB_freeImBuf(ibuf_arr[i]);
}
@@ -3401,7 +3428,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen
return ok;
}
-static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override)
+static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const int totvideos, const char *name_override)
{
char name[FILE_MAX];
RenderResult rres;
@@ -3412,7 +3439,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
/* write movie or image */
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos, false);
+ RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->movie_ctx_arr, totvideos, false);
}
else {
if (name_override)
@@ -3448,7 +3475,9 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
return ok;
}
-static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height)
+static void get_videos_dimensions(
+ Render *re, RenderData *rd,
+ size_t *r_width, size_t *r_height)
{
size_t width, height;
if (re->r.mode & R_BORDER) {
@@ -3469,6 +3498,18 @@ static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, s
BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height);
}
+static void re_movie_free_all(Render *re, bMovieHandle *mh, int totvideos)
+{
+ int i;
+
+ for (i = 0; i < totvideos; i++) {
+ mh->end_movie(re->movie_ctx_arr[i]);
+ mh->context_free(re->movie_ctx_arr[i]);
+ }
+
+ MEM_SAFE_FREE(re->movie_ctx_arr);
+}
+
/* saves images to disk */
void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override,
unsigned int lay_override, int sfra, int efra, int tfra)
@@ -3477,7 +3518,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
bMovieHandle *mh = NULL;
int cfrao = scene->r.cfra;
int nfra, totrendered = 0, totskipped = 0;
- const size_t totvideos = BKE_scene_multiview_num_videos_get(&rd);
+ const int totvideos = BKE_scene_multiview_num_videos_get(&rd);
const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 &&
(scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL));
@@ -3488,24 +3529,28 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1))
return;
- /* we don't support Frame Server and streaming of individual views */
+ /* MULTIVIEW_TODO:
+ * in case a new video format is added that implements get_next_frame multiview has to be addressed
+ * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well
+ */
if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) {
BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering");
return;
}
-
- /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
- /* is also set by caller renderwin.c */
- G.is_rendering = true;
-
- re->flag |= R_ANIMATION;
if (is_movie) {
- size_t i, width, height;
+ size_t width, height;
+ int i;
+ bool is_error = false;
get_videos_dimensions(re, &rd, &width, &height);
mh = BKE_movie_handle_get(scene->r.im_format.imtype);
+ if (mh == NULL) {
+ BKE_report(re->reports, RPT_ERROR, "Movie format unsupported");
+ return;
+ }
+
re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context");
for (i = 0; i < totvideos; i++) {
@@ -3513,49 +3558,63 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
re->movie_ctx_arr[i] = mh->context_create();
- if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix))
- G.is_break = true;
+ if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix)) {
+ is_error = true;
+ break;
+ }
}
- }
-
- if (mh && mh->get_next_frame) {
- /* MULTIVIEW_TODO:
- * in case a new video format is added that implements get_next_frame multiview has to be addressed
- * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well
- */
- BLI_assert(totvideos < 2);
- while (!(G.is_break == 1)) {
- int nf = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports);
- if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
- scene->r.cfra = re->r.cfra = nf;
+ if (is_error) {
+ /* report is handled above */
+ re_movie_free_all(re, mh, i + 1);
+ return;
+ }
+ }
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
+ /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
+ /* is also set by caller renderwin.c */
+ G.is_rendering = true;
- do_render_all_options(re);
- totrendered++;
+ re->flag |= R_ANIMATION;
- if (re->test_break(re->tbh) == 0) {
- if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL))
- G.is_break = true;
- }
+ {
+ for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
+ char name[FILE_MAX];
- if (G.is_break == false) {
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_POST); /* keep after file save */
- BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_WRITE);
+ /* Special case for 'mh->get_next_frame'
+ * this overrides regular frame stepping logic */
+ if (mh && mh->get_next_frame) {
+ while (G.is_break == false) {
+ int nfra_test = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports);
+ if (nfra_test >= 0 && nfra_test >= sfra && nfra_test <= efra) {
+ nfra = nfra_test;
+ break;
+ }
+ else {
+ if (re->test_break(re->tbh)) {
+ G.is_break = true;
+ }
+ }
}
}
- else {
- if (re->test_break(re->tbh)) {
- G.is_break = true;
- }
+
+ /* Here is a feedback loop exists -- render initialization requires updated
+ * render layers settings which could be animated, but scene evaluation for
+ * the frame happens later because it depends on what layers are visible to
+ * render engine.
+ *
+ * The idea here is to only evaluate animation data associated with the scene,
+ * which will make sure render layer settings are up-to-date, initialize the
+ * render database itself and then perform full scene update with only needed
+ * layers.
+ * -sergey-
+ */
+ {
+ float ctime = BKE_scene_frame_get(scene);
+ AnimData *adt = BKE_animdata_from_id(&scene->id);
+ BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, ADT_RECALC_ALL);
}
- }
- }
- else {
- for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
- char name[FILE_MAX];
-
+
/* only border now, todo: camera lens. (ton) */
render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 1, 0);
@@ -3701,15 +3760,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
/* end movie */
if (is_movie) {
- size_t i;
- for (i = 0; i < totvideos; i++) {
- mh->end_movie(re->movie_ctx_arr[i]);
- mh->context_free(re->movie_ctx_arr[i]);
- }
-
- if (re->movie_ctx_arr) {
- MEM_freeN(re->movie_ctx_arr);
- }
+ re_movie_free_all(re, mh, totvideos);
}
if (totskipped && totrendered == 0)
@@ -3930,13 +3981,10 @@ bool RE_layers_have_name(struct RenderResult *rr)
switch (BLI_listbase_count_ex(&rr->layers, 2)) {
case 0:
return false;
- break;
case 1:
return (((RenderLayer *)rr->layers.first)->name[0] != '\0');
- break;
default:
return true;
- break;
}
return false;
}
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
index 104cde0a0b5..97d6b060e0a 100644
--- a/source/blender/render/intern/source/pixelshading.c
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -492,7 +492,7 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz,
/* Only view vector is important here. Result goes to col_r[3] */
void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const float dxyview[2], short thread)
{
- float lo[3], zen[3], hor[3], blend, blendm;
+ float zen[3], hor[3], blend, blendm;
int skyflag;
/* flag indicating if we render the top hemisphere */
@@ -521,15 +521,16 @@ void shadeSkyView(float col_r[3], const float rco[3], const float view[3], const
/* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
/* SKYBLEND is active, the texture and color blend are added. */
if (R.wrld.skytype & WO_SKYTEX) {
+ float lo[3];
copy_v3_v3(lo, view);
if (R.wrld.skytype & WO_SKYREAL) {
-
+
mul_m3_v3(R.imat, lo);
-
+
SWAP(float, lo[1], lo[2]);
-
+
}
- do_sky_tex(rco, lo, dxyview, hor, zen, &blend, skyflag, thread);
+ do_sky_tex(rco, view, lo, dxyview, hor, zen, &blend, skyflag, thread);
}
if (blend>1.0f) blend= 1.0f;
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index b8d8cc37ae3..59aaad661c9 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -39,9 +39,16 @@
#include "BLI_noise.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
+#include "BLI_task.h"
#include "BLT_translation.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
@@ -51,10 +58,6 @@
#include "BKE_texture.h"
#include "BKE_colortools.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_texture_types.h"
-#include "DNA_particle_types.h"
-
#include "render_types.h"
#include "texture.h"
#include "pointdensity.h"
@@ -88,29 +91,78 @@ static int point_data_used(PointDensity *pd)
pd_bitflag |= POINT_DATA_LIFE;
}
}
+ else if (pd->source == TEX_PD_OBJECT) {
+ if (ELEM(pd->ob_color_source, TEX_PD_COLOR_VERTCOL, TEX_PD_COLOR_VERTWEIGHT, TEX_PD_COLOR_VERTNOR)) {
+ pd_bitflag |= POINT_DATA_COLOR;
+ }
+ }
return pd_bitflag;
}
+static void point_data_pointers(PointDensity *pd,
+ float **r_data_velocity, float **r_data_life, float **r_data_color)
+{
+ const int data_used = point_data_used(pd);
+ const int totpoint = pd->totpoints;
+ float *data = pd->point_data;
+ int offset = 0;
+
+ if (data_used & POINT_DATA_VEL) {
+ if (r_data_velocity)
+ *r_data_velocity = data + offset;
+ offset += 3 * totpoint;
+ }
+ else {
+ if (r_data_velocity)
+ *r_data_velocity = NULL;
+ }
+
+ if (data_used & POINT_DATA_LIFE) {
+ if (r_data_life)
+ *r_data_life = data + offset;
+ offset += totpoint;
+ }
+ else {
+ if (r_data_life)
+ *r_data_life = NULL;
+ }
+
+ if (data_used & POINT_DATA_COLOR) {
+ if (r_data_color)
+ *r_data_color = data + offset;
+ offset += 3 * totpoint;
+ }
+ else {
+ if (r_data_color)
+ *r_data_color = NULL;
+ }
+}
/* additional data stored alongside the point density BVH,
* accessible by point index number to retrieve other information
* such as particle velocity or lifetime */
-static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
+static void alloc_point_data(PointDensity *pd)
{
+ const int totpoints = pd->totpoints;
+ int data_used = point_data_used(pd);
int data_size = 0;
- if (point_data_used & POINT_DATA_VEL) {
+ if (data_used & POINT_DATA_VEL) {
/* store 3 channels of velocity data */
data_size += 3;
}
- if (point_data_used & POINT_DATA_LIFE) {
+ if (data_used & POINT_DATA_LIFE) {
/* store 1 channel of lifetime data */
data_size += 1;
}
+ if (data_used & POINT_DATA_COLOR) {
+ /* store 3 channels of RGB data */
+ data_size += 3;
+ }
if (data_size) {
- pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles,
+ pd->point_data = MEM_callocN(sizeof(float) * data_size * totpoints,
"particle point data");
}
}
@@ -121,7 +173,8 @@ static void pointdensity_cache_psys(Scene *scene,
ParticleSystem *psys,
float viewmat[4][4],
float winmat[4][4],
- int winx, int winy)
+ int winx, int winy,
+ const bool use_render_params)
{
DerivedMesh *dm;
ParticleKey state;
@@ -130,8 +183,9 @@ static void pointdensity_cache_psys(Scene *scene,
ParticleData *pa = NULL;
float cfra = BKE_scene_frame_get(scene);
int i /*, childexists*/ /* UNUSED */;
- int total_particles, offset = 0;
- int data_used = point_data_used(pd);
+ int total_particles;
+ int data_used;
+ float *data_vel, *data_life;
float partco[3];
/* init everything */
@@ -139,12 +193,25 @@ static void pointdensity_cache_psys(Scene *scene,
return;
}
+ data_used = point_data_used(pd);
+
/* Just to create a valid rendering context for particles */
- psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
+ if (use_render_params) {
+ psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
+ }
- dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ if (use_render_params) {
+ dm = mesh_create_derived_render(scene,
+ ob,
+ CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ }
+ else {
+ dm = mesh_get_derived_final(scene,
+ ob,
+ CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+ }
- if ( !psys_check_enabled(ob, psys)) {
+ if (!psys_check_enabled(ob, psys)) {
psys_render_restore(ob, psys);
return;
}
@@ -161,11 +228,9 @@ static void pointdensity_cache_psys(Scene *scene,
psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
- alloc_point_data(pd, total_particles, data_used);
pd->totpoints = total_particles;
- if (data_used & POINT_DATA_VEL) {
- offset = pd->totpoints * 3;
- }
+ alloc_point_data(pd);
+ point_data_pointers(pd, &data_vel, &data_life, NULL);
#if 0 /* UNUSED */
if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
@@ -222,13 +287,13 @@ static void pointdensity_cache_psys(Scene *scene,
BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
- if (data_used & POINT_DATA_VEL) {
- pd->point_data[i * 3 + 0] = state.vel[0];
- pd->point_data[i * 3 + 1] = state.vel[1];
- pd->point_data[i * 3 + 2] = state.vel[2];
+ if (data_vel) {
+ data_vel[i*3 + 0] = state.vel[0];
+ data_vel[i*3 + 1] = state.vel[1];
+ data_vel[i*3 + 2] = state.vel[2];
}
- if (data_used & POINT_DATA_LIFE) {
- pd->point_data[offset + i] = state.time;
+ if (data_life) {
+ data_life[i] = state.time;
}
}
@@ -240,30 +305,133 @@ static void pointdensity_cache_psys(Scene *scene,
psys->lattice_deform_data = NULL;
}
- psys_render_restore(ob, psys);
+ if (use_render_params) {
+ psys_render_restore(ob, psys);
+ }
}
-static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob)
+static void pointdensity_cache_vertex_color(PointDensity *pd, Object *UNUSED(ob), DerivedMesh *dm, float *data_color)
+{
+ const MLoop *mloop = dm->getLoopArray(dm);
+ const int totloop = dm->getNumLoops(dm);
+ const MLoopCol *mcol;
+ char layername[MAX_CUSTOMDATA_LAYER_NAME];
+ int i;
+
+ BLI_assert(data_color);
+
+ if (!CustomData_has_layer(&dm->loopData, CD_MLOOPCOL))
+ return;
+ CustomData_validate_layer_name(&dm->loopData, CD_MLOOPCOL, pd->vertex_attribute_name, layername);
+ mcol = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, layername);
+ if (!mcol)
+ return;
+
+ /* Stores the number of MLoops using the same vertex, so we can normalize colors. */
+ int *mcorners = MEM_callocN(sizeof(int) * pd->totpoints, "point density corner count");
+
+ for (i = 0; i < totloop; i++) {
+ int v = mloop[i].v;
+ rgb_uchar_to_float(&data_color[v*3], &mcol[i].r);
+ ++mcorners[v];
+ }
+
+ /* Normalize colors by averaging over mcorners.
+ * All the corners share the same vertex, ie. occupy the same point in space.
+ */
+ for (i = 0; i < pd->totpoints; i++) {
+ if (mcorners[i] > 0)
+ mul_v3_fl(&data_color[i*3], 1.0f / mcorners[i]);
+ }
+
+ MEM_freeN(mcorners);
+}
+
+static void pointdensity_cache_vertex_weight(PointDensity *pd, Object *ob, DerivedMesh *dm, float *data_color)
{
+ const int totvert = dm->getNumVerts(dm);
+ const MDeformVert *mdef, *dv;
+ int mdef_index;
+ int i;
+
+ BLI_assert(data_color);
+
+ mdef = CustomData_get_layer(&dm->vertData, CD_MDEFORMVERT);
+ if (!mdef)
+ return;
+ mdef_index = defgroup_name_index(ob, pd->vertex_attribute_name);
+ if (mdef_index < 0)
+ mdef_index = ob->actdef - 1;
+ if (mdef_index < 0)
+ return;
+
+ for (i = 0, dv = mdef; i < totvert; ++i, ++dv, data_color += 3) {
+ MDeformWeight *dw;
+ int j;
+
+ for (j = 0, dw = dv->dw; j < dv->totweight; ++j, ++dw) {
+ if (dw->def_nr == mdef_index) {
+ copy_v3_fl(data_color, dw->weight);
+ break;
+ }
+ }
+ }
+}
+
+static void pointdensity_cache_vertex_normal(PointDensity *pd, Object *UNUSED(ob), DerivedMesh *dm, float *data_color)
+{
+ MVert *mvert = dm->getVertArray(dm), *mv;
+ int i;
+
+ BLI_assert(data_color);
+
+ for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) {
+ normal_short_to_float_v3(data_color, mv->no);
+ }
+}
+
+static void pointdensity_cache_object(Scene *scene,
+ PointDensity *pd,
+ Object *ob,
+ const bool use_render_params)
+{
+ float *data_color;
int i;
DerivedMesh *dm;
- MVert *mvert = NULL;
+ CustomDataMask mask = CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL;
+ MVert *mvert = NULL, *mv;
- dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
- mvert = dm->getVertArray(dm); /* local object space */
+ switch (pd->ob_color_source) {
+ case TEX_PD_COLOR_VERTCOL:
+ mask |= CD_MASK_MLOOPCOL;
+ break;
+ case TEX_PD_COLOR_VERTWEIGHT:
+ mask |= CD_MASK_MDEFORMVERT;
+ break;
+ }
+ if (use_render_params) {
+ dm = mesh_create_derived_render(scene, ob, mask);
+ }
+ else {
+ dm = mesh_get_derived_final(scene, ob, mask);
+ }
+
+ mvert = dm->getVertArray(dm); /* local object space */
pd->totpoints = dm->getNumVerts(dm);
if (pd->totpoints == 0) {
return;
}
pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
+ alloc_point_data(pd);
+ point_data_pointers(pd, NULL, NULL, &data_color);
- for (i = 0; i < pd->totpoints; i++, mvert++) {
+ for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++) {
float co[3];
- copy_v3_v3(co, mvert->co);
+ copy_v3_v3(co, mv->co);
switch (pd->ob_cache_space) {
case TEX_PD_OBJECTSPACE:
@@ -280,6 +448,18 @@ static void pointdensity_cache_object(Scene *scene, PointDensity *pd, Object *ob
BLI_bvhtree_insert(pd->point_tree, i, co, 1);
}
+
+ switch (pd->ob_color_source) {
+ case TEX_PD_COLOR_VERTCOL:
+ pointdensity_cache_vertex_color(pd, ob, dm, data_color);
+ break;
+ case TEX_PD_COLOR_VERTWEIGHT:
+ pointdensity_cache_vertex_weight(pd, ob, dm, data_color);
+ break;
+ case TEX_PD_COLOR_VERTNOR:
+ pointdensity_cache_vertex_normal(pd, ob, dm, data_color);
+ break;
+ }
BLI_bvhtree_balance(pd->point_tree);
dm->release(dm);
@@ -290,7 +470,8 @@ static void cache_pointdensity_ex(Scene *scene,
PointDensity *pd,
float viewmat[4][4],
float winmat[4][4],
- int winx, int winy)
+ int winx, int winy,
+ const bool use_render_params)
{
if (pd == NULL) {
return;
@@ -314,18 +495,28 @@ static void cache_pointdensity_ex(Scene *scene,
return;
}
- pointdensity_cache_psys(scene, pd, ob, psys, viewmat, winmat, winx, winy);
+ pointdensity_cache_psys(scene,
+ pd,
+ ob,
+ psys,
+ viewmat, winmat,
+ winx, winy,
+ use_render_params);
}
else if (pd->source == TEX_PD_OBJECT) {
Object *ob = pd->object;
if (ob && ob->type == OB_MESH)
- pointdensity_cache_object(scene, pd, ob);
+ pointdensity_cache_object(scene, pd, ob, use_render_params);
}
}
void cache_pointdensity(Render *re, PointDensity *pd)
{
- cache_pointdensity_ex(re->scene, pd, re->viewmat, re->winmat, re->winx, re->winy);
+ cache_pointdensity_ex(re->scene,
+ pd,
+ re->viewmat, re->winmat,
+ re->winx, re->winy,
+ true);
}
void free_pointdensity(PointDensity *pd)
@@ -384,78 +575,99 @@ void free_pointdensities(Render *re)
typedef struct PointDensityRangeData {
float *density;
float squared_radius;
- const float *point_data;
+ float *point_data_life;
+ float *point_data_velocity;
+ float *point_data_color;
float *vec;
+ float *col;
float softness;
short falloff_type;
short noise_influence;
float *age;
- int point_data_used;
- int offset;
struct CurveMapping *density_curve;
float velscale;
} PointDensityRangeData;
-static void accum_density(void *userdata, int index, float squared_dist)
+static float density_falloff(PointDensityRangeData *pdr, int index, float squared_dist)
{
- PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
float density = 0.0f;
-
- if (pdr->point_data_used & POINT_DATA_VEL) {
- pdr->vec[0] += pdr->point_data[index * 3 + 0]; // * density;
- pdr->vec[1] += pdr->point_data[index * 3 + 1]; // * density;
- pdr->vec[2] += pdr->point_data[index * 3 + 2]; // * density;
- }
- if (pdr->point_data_used & POINT_DATA_LIFE) {
- *pdr->age += pdr->point_data[pdr->offset + index]; // * density;
- }
-
- if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
- density = dist;
- else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
- density = 3.0f * dist * dist - 2.0f * dist * dist * dist;
- else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
- density = pow(dist, pdr->softness);
- else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
- density = pdr->squared_radius;
- else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
- density = sqrtf(dist);
- else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
- if (pdr->point_data_used & POINT_DATA_LIFE)
- density = dist * MIN2(pdr->point_data[pdr->offset + index], 1.0f);
- else
- density = dist;
- }
- else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
- if (pdr->point_data_used & POINT_DATA_VEL)
- density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale;
- else
+
+ switch (pdr->falloff_type) {
+ case TEX_PD_FALLOFF_STD:
density = dist;
+ break;
+ case TEX_PD_FALLOFF_SMOOTH:
+ density = 3.0f * dist * dist - 2.0f * dist * dist * dist;
+ break;
+ case TEX_PD_FALLOFF_SOFT:
+ density = pow(dist, pdr->softness);
+ break;
+ case TEX_PD_FALLOFF_CONSTANT:
+ density = pdr->squared_radius;
+ break;
+ case TEX_PD_FALLOFF_ROOT:
+ density = sqrtf(dist);
+ break;
+ case TEX_PD_FALLOFF_PARTICLE_AGE:
+ if (pdr->point_data_life)
+ density = dist * MIN2(pdr->point_data_life[index], 1.0f);
+ else
+ density = dist;
+ break;
+ case TEX_PD_FALLOFF_PARTICLE_VEL:
+ if (pdr->point_data_velocity)
+ density = dist * len_v3(&pdr->point_data_velocity[index * 3]) * pdr->velscale;
+ else
+ density = dist;
+ break;
}
-
+
if (pdr->density_curve && dist != 0.0f) {
curvemapping_initialize(pdr->density_curve);
density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist;
}
+
+ return density;
+}
+
+static void accum_density(void *userdata, int index, const float co[3], float squared_dist)
+{
+ PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
+ float density = 0.0f;
+
+ UNUSED_VARS(co);
+
+ if (pdr->point_data_velocity) {
+ pdr->vec[0] += pdr->point_data_velocity[index * 3 + 0]; // * density;
+ pdr->vec[1] += pdr->point_data_velocity[index * 3 + 1]; // * density;
+ pdr->vec[2] += pdr->point_data_velocity[index * 3 + 2]; // * density;
+ }
+ if (pdr->point_data_life) {
+ *pdr->age += pdr->point_data_life[index]; // * density;
+ }
+ if (pdr->point_data_color) {
+ add_v3_v3(pdr->col, &pdr->point_data_color[index * 3]); // * density;
+ }
+
+ density = density_falloff(pdr, index, squared_dist);
*pdr->density += density;
}
static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
- float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
+ float *density, float *vec, float *age, float *col, struct CurveMapping *density_curve, float velscale)
{
pdr->squared_radius = pd->radius * pd->radius;
pdr->density = density;
- pdr->point_data = pd->point_data;
pdr->falloff_type = pd->falloff_type;
pdr->vec = vec;
pdr->age = age;
+ pdr->col = col;
pdr->softness = pd->falloff_softness;
pdr->noise_influence = pd->noise_influence;
- pdr->point_data_used = point_data_used(pd);
- pdr->offset = (pdr->point_data_used & POINT_DATA_VEL) ? pd->totpoints * 3 : 0;
+ point_data_pointers(pd, &pdr->point_data_velocity, &pdr->point_data_life, &pdr->point_data_color);
pdr->density_curve = density_curve;
pdr->velscale = velscale;
}
@@ -464,13 +676,14 @@ static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *
static int pointdensity(PointDensity *pd,
const float texvec[3],
TexResult *texres,
+ float r_vec[3],
float *r_age,
- float r_vec[3])
+ float r_col[3])
{
int retval = TEX_INT;
PointDensityRangeData pdr;
float density = 0.0f, age = 0.0f, time = 0.0f;
- float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
+ float vec[3] = {0.0f, 0.0f, 0.0f}, col[3] = {0.0f, 0.0f, 0.0f}, co[3];
float turb, noise_fac;
int num = 0;
@@ -479,7 +692,7 @@ static int pointdensity(PointDensity *pd,
if ((!pd) || (!pd->point_tree))
return 0;
- init_pointdensityrangedata(pd, &pdr, &density, vec, &age,
+ init_pointdensityrangedata(pd, &pdr, &density, vec, &age, col,
(pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL),
pd->falloff_speed_scale * 0.001f);
noise_fac = pd->noise_fac * 0.5f; /* better default */
@@ -493,10 +706,13 @@ static int pointdensity(PointDensity *pd,
if (num > 0) {
age /= num;
mul_v3_fl(vec, 1.0f / num);
+ mul_v3_fl(col, 1.0f / num);
}
/* reset */
- density = vec[0] = vec[1] = vec[2] = 0.0f;
+ density = 0.0f;
+ zero_v3(vec);
+ zero_v3(col);
}
if (pd->flag & TEX_PD_TURBULENCE) {
@@ -529,6 +745,7 @@ static int pointdensity(PointDensity *pd,
if (num > 0) {
age /= num;
mul_v3_fl(vec, 1.0f / num);
+ mul_v3_fl(col, 1.0f / num);
}
texres->tin = density;
@@ -538,51 +755,88 @@ static int pointdensity(PointDensity *pd,
if (r_vec != NULL) {
copy_v3_v3(r_vec, vec);
}
+ if (r_col != NULL) {
+ copy_v3_v3(r_col, col);
+ }
return retval;
}
-static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3])
+static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3], const float col[3])
{
- int retval = 0;
- float col[4];
-
- retval |= TEX_RGB;
+ int retval = TEX_RGB;
- switch (pd->color_source) {
- case TEX_PD_COLOR_PARTAGE:
- if (pd->coba) {
- if (do_colorband(pd->coba, age, col)) {
- texres->talpha = true;
- copy_v3_v3(&texres->tr, col);
- texres->tin *= col[3];
- texres->ta = texres->tin;
+ if (pd->source == TEX_PD_PSYS) {
+ float rgba[4];
+
+ switch (pd->color_source) {
+ case TEX_PD_COLOR_PARTAGE:
+ if (pd->coba) {
+ if (do_colorband(pd->coba, age, rgba)) {
+ texres->talpha = true;
+ copy_v3_v3(&texres->tr, rgba);
+ texres->tin *= rgba[3];
+ texres->ta = texres->tin;
+ }
}
+ break;
+ case TEX_PD_COLOR_PARTSPEED:
+ {
+ float speed = len_v3(vec) * pd->speed_scale;
+
+ if (pd->coba) {
+ if (do_colorband(pd->coba, speed, rgba)) {
+ texres->talpha = true;
+ copy_v3_v3(&texres->tr, rgba);
+ texres->tin *= rgba[3];
+ texres->ta = texres->tin;
+ }
+ }
+ break;
}
- break;
- case TEX_PD_COLOR_PARTSPEED:
- {
- float speed = len_v3(vec) * pd->speed_scale;
-
- if (pd->coba) {
- if (do_colorband(pd->coba, speed, col)) {
- texres->talpha = true;
+ case TEX_PD_COLOR_PARTVEL:
+ texres->talpha = true;
+ mul_v3_v3fl(&texres->tr, vec, pd->speed_scale);
+ texres->ta = texres->tin;
+ break;
+ case TEX_PD_COLOR_CONSTANT:
+ default:
+ texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
+ retval = TEX_INT;
+ break;
+ }
+ }
+ else {
+ float rgba[4];
+
+ switch (pd->ob_color_source) {
+ case TEX_PD_COLOR_VERTCOL:
+ texres->talpha = true;
+ copy_v3_v3(&texres->tr, col);
+ texres->ta = texres->tin;
+ break;
+ case TEX_PD_COLOR_VERTWEIGHT:
+ texres->talpha = true;
+ if (pd->coba && do_colorband(pd->coba, col[0], rgba)) {
+ copy_v3_v3(&texres->tr, rgba);
+ texres->tin *= rgba[3];
+ }
+ else {
copy_v3_v3(&texres->tr, col);
- texres->tin *= col[3];
- texres->ta = texres->tin;
}
- }
- break;
+ texres->ta = texres->tin;
+ break;
+ case TEX_PD_COLOR_VERTNOR:
+ texres->talpha = true;
+ copy_v3_v3(&texres->tr, col);
+ texres->ta = texres->tin;
+ break;
+ case TEX_PD_COLOR_CONSTANT:
+ default:
+ texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
+ retval = TEX_INT;
+ break;
}
- case TEX_PD_COLOR_PARTVEL:
- texres->talpha = true;
- mul_v3_v3fl(&texres->tr, vec, pd->speed_scale);
- texres->ta = texres->tin;
- break;
- case TEX_PD_COLOR_CONSTANT:
- default:
- texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
- break;
}
return retval;
@@ -593,13 +847,12 @@ int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
PointDensity *pd = tex->pd;
float age = 0.0f;
float vec[3] = {0.0f, 0.0f, 0.0f};
- int retval = pointdensity(pd, texvec, texres, &age, vec);
-
- BRICONT;
+ float col[3] = {0.0f, 0.0f, 0.0f};
+ int retval = pointdensity(pd, texvec, texres, vec, &age, col);
- retval |= pointdensity_color(pd, texres, age, vec);
+ retval |= pointdensity_color(pd, texres, age, vec, col);
BRICONTRGB;
-
+
return retval;
#if 0
@@ -614,100 +867,219 @@ static void sample_dummy_point_density(int resolution, float *values)
memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
}
-static void particle_system_minmax(Object *object,
+static void particle_system_minmax(Scene *scene,
+ Object *object,
ParticleSystem *psys,
float radius,
+ const bool use_render_params,
float min[3], float max[3])
{
+ const float size[3] = {radius, radius, radius};
+ const float cfra = BKE_scene_frame_get(scene);
ParticleSettings *part = psys->part;
- float imat[4][4];
- float size[3] = {radius, radius, radius};
- PARTICLE_P;
+ ParticleSimulationData sim = {NULL};
+ ParticleData *pa = NULL;
+ int i;
+ int total_particles;
+ float mat[4][4], imat[4][4];
+
INIT_MINMAX(min, max);
if (part->type == PART_HAIR) {
/* TOOD(sergey): Not supported currently. */
return;
}
+
+ unit_m4(mat);
+ if (use_render_params) {
+ psys_render_set(object, psys, mat, mat, 1, 1, 0);
+ }
+
+ sim.scene = scene;
+ sim.ob = object;
+ sim.psys = psys;
+ sim.psmd = psys_get_modifier(object, psys);
+
invert_m4_m4(imat, object->obmat);
- LOOP_PARTICLES {
+ total_particles = psys->totpart + psys->totchild;
+ psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
+
+ for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
float co_object[3], co_min[3], co_max[3];
- mul_v3_m4v3(co_object, imat, pa->state.co);
+ ParticleKey state;
+ state.time = cfra;
+ if (!psys_get_particle_state(&sim, i, &state, 0)) {
+ continue;
+ }
+ mul_v3_m4v3(co_object, imat, state.co);
sub_v3_v3v3(co_min, co_object, size);
add_v3_v3v3(co_max, co_object, size);
minmax_v3v3_v3(min, max, co_min);
minmax_v3v3_v3(min, max, co_max);
}
+
+ if (psys->lattice_deform_data) {
+ end_latt_deform(psys->lattice_deform_data);
+ psys->lattice_deform_data = NULL;
+ }
+
+ if (use_render_params) {
+ psys_render_restore(object, psys);
+ }
}
-void RE_sample_point_density(Scene *scene, PointDensity *pd,
- int resolution, float *values)
+void RE_point_density_cache(
+ Scene *scene,
+ PointDensity *pd,
+ const bool use_render_params)
{
- const size_t resolution2 = resolution * resolution;
- Object *object = pd->object;
- size_t x, y, z;
- float min[3], max[3], dim[3], mat[4][4];
+ float mat[4][4];
+ /* Same matricies/resolution as dupli_render_particle_set(). */
+ unit_m4(mat);
+ BLI_mutex_lock(&sample_mutex);
+ cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params);
+ BLI_mutex_unlock(&sample_mutex);
+}
+void RE_point_density_minmax(
+ struct Scene *scene,
+ struct PointDensity *pd,
+ const bool use_render_params,
+ float r_min[3], float r_max[3])
+{
+ Object *object = pd->object;
if (object == NULL) {
- sample_dummy_point_density(resolution, values);
+ zero_v3(r_min);
+ zero_v3(r_max);
return;
}
-
if (pd->source == TEX_PD_PSYS) {
ParticleSystem *psys;
if (pd->psys == 0) {
- sample_dummy_point_density(resolution, values);
+ zero_v3(r_min);
+ zero_v3(r_max);
return;
}
psys = BLI_findlink(&object->particlesystem, pd->psys - 1);
if (psys == NULL) {
- sample_dummy_point_density(resolution, values);
+ zero_v3(r_min);
+ zero_v3(r_max);
return;
}
- particle_system_minmax(object, psys, pd->radius, min, max);
+ particle_system_minmax(scene,
+ object,
+ psys,
+ pd->radius,
+ use_render_params,
+ r_min, r_max);
}
else {
float radius[3] = {pd->radius, pd->radius, pd->radius};
float *loc, *size;
- BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL);
- sub_v3_v3v3(min, loc, size);
- add_v3_v3v3(max, loc, size);
- /* Adjust texture space to include density points on the boundaries. */
- sub_v3_v3(min, radius);
- add_v3_v3(max, radius);
+
+ if (BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL)) {
+ sub_v3_v3v3(r_min, loc, size);
+ add_v3_v3v3(r_max, loc, size);
+ /* Adjust texture space to include density points on the boundaries. */
+ sub_v3_v3(r_min, radius);
+ add_v3_v3(r_max, radius);
+ }
+ else {
+ zero_v3(r_min);
+ zero_v3(r_max);
+ }
}
+}
+typedef struct SampleCallbackData {
+ PointDensity *pd;
+ int resolution;
+ float *min, *dim;
+ float *values;
+} SampleCallbackData;
+
+static void point_density_sample_func(void *data_v, const int iter)
+{
+ SampleCallbackData *data = (SampleCallbackData *)data_v;
+
+ const int resolution = data->resolution;
+ const int resolution2 = resolution * resolution;
+ const float *min = data->min, *dim = data->dim;
+ PointDensity *pd = data->pd;
+ float *values = data->values;
+
+ size_t z = (size_t)iter;
+ for (size_t y = 0; y < resolution; ++y) {
+ for (size_t x = 0; x < resolution; ++x) {
+ size_t index = z * resolution2 + y * resolution + x;
+ float texvec[3];
+ float age, vec[3], col[3];
+ TexResult texres;
+
+ copy_v3_v3(texvec, min);
+ texvec[0] += dim[0] * (float)x / (float)resolution;
+ texvec[1] += dim[1] * (float)y / (float)resolution;
+ texvec[2] += dim[2] * (float)z / (float)resolution;
+
+ pointdensity(pd, texvec, &texres, vec, &age, col);
+ pointdensity_color(pd, &texres, age, vec, col);
+
+ copy_v3_v3(&values[index*4 + 0], &texres.tr);
+ values[index*4 + 3] = texres.tin;
+ }
+ }
+}
+
+/* NOTE 1: Requires RE_point_density_cache() to be called first.
+ * NOTE 2: Frees point density structure after sampling.
+ */
+void RE_point_density_sample(
+ Scene *scene,
+ PointDensity *pd,
+ const int resolution,
+ const bool use_render_params,
+ float *values)
+{
+ Object *object = pd->object;
+ float min[3], max[3], dim[3];
+
+ /* TODO(sergey): Implement some sort of assert() that point density
+ * was cached already.
+ */
+
+ if (object == NULL) {
+ sample_dummy_point_density(resolution, values);
+ return;
+ }
+
+ BLI_mutex_lock(&sample_mutex);
+ RE_point_density_minmax(scene,
+ pd,
+ use_render_params,
+ min,
+ max);
+ BLI_mutex_unlock(&sample_mutex);
sub_v3_v3v3(dim, max, min);
if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) {
sample_dummy_point_density(resolution, values);
return;
}
- /* Same matricies/resolution as dupli_render_particle_set(). */
- unit_m4(mat);
+ SampleCallbackData data;
+ data.pd = pd;
+ data.resolution = resolution;
+ data.min = min;
+ data.dim = dim;
+ data.values = values;
+ BLI_task_parallel_range(0,
+ resolution,
+ &data,
+ point_density_sample_func,
+ resolution > 32);
- BLI_mutex_lock(&sample_mutex);
- cache_pointdensity_ex(scene, pd, mat, mat, 1, 1);
- for (z = 0; z < resolution; ++z) {
- for (y = 0; y < resolution; ++y) {
- for (x = 0; x < resolution; ++x) {
- size_t index = z * resolution2 + y * resolution + x;
- float texvec[3];
- float age, vec[3];
- TexResult texres;
-
- copy_v3_v3(texvec, min);
- texvec[0] += dim[0] * (float)x / (float)resolution;
- texvec[1] += dim[1] * (float)y / (float)resolution;
- texvec[2] += dim[2] * (float)z / (float)resolution;
-
- pointdensity(pd, texvec, &texres, &age, vec);
- pointdensity_color(pd, &texres, age, vec);
-
- copy_v3_v3(&values[index*4 + 0], &texres.tr);
- values[index*4 + 3] = texres.tin;
- }
- }
- }
free_pointdensity(pd);
- BLI_mutex_unlock(&sample_mutex);
+}
+
+void RE_point_density_free(struct PointDensity *pd)
+{
+ free_pointdensity(pd);
}
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 900312ee984..9aac5ed1f1d 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -184,7 +184,7 @@ void freeraytree(Render *re)
#endif
}
-static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
+static bool is_raytraceable_vlr(Render *re, VlakRen *vlr)
{
/* note: volumetric must be tracable, wire must not */
if ((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
@@ -193,7 +193,7 @@ static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
return 0;
}
-static int is_raytraceable(Render *re, ObjectInstanceRen *obi)
+static bool is_raytraceable(Render *re, ObjectInstanceRen *obi)
{
int v;
ObjectRen *obr = obi->obr;
@@ -750,7 +750,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con
d= shade_by_transmission(&isec, &shi, &shr);
if (depth>0) {
- float fr, fg, fb, f, f1;
+ float fr, fg, fb, f1;
if ((shi.mat->mode_l & MA_TRANSP) && shr.alpha < 1.0f && (shi.mat->mode_l & (MA_ZTRANSP | MA_RAYTRANSP))) {
float nf, f, refract[3], tracol[4];
@@ -810,9 +810,11 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, con
col[3]= f1*tracol[3] + f;
}
- else
+ else {
col[3]= 1.0f;
+ }
+ float f;
if (shi.mat->mode_l & MA_RAYMIRROR) {
f= shi.ray_mirror;
if (f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir);
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 27fc412e1cd..2d26fcf4905 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include "MEM_guardedalloc.h"
@@ -485,12 +486,11 @@ static void set_pass_name(char *passname, int passtype, int channel, const char
static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype, const char *viewname)
{
- const size_t view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
+ const int view_id = BLI_findstringindex(&rr->views, viewname, offsetof(RenderView, name));
const char *typestr = name_from_passtype(passtype, -1);
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
size_t rectsize = ((size_t)rr->rectx) * rr->recty * channels;
- BLI_addtail(&rl->passes, rpass);
rpass->passtype = passtype;
rpass->channels = channels;
rpass->rectx = rl->rectx;
@@ -511,6 +511,10 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
int x;
rpass->rect = MEM_mapallocN(sizeof(float) * rectsize, typestr);
+ if (rpass->rect == NULL) {
+ MEM_freeN(rpass);
+ return NULL;
+ }
if (passtype == SCE_PASS_VECTOR) {
/* initialize to max speed */
@@ -524,6 +528,9 @@ static RenderPass *render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int
rect[x] = 10e10;
}
}
+
+ BLI_addtail(&rl->passes, rpass);
+
return rpass;
}
@@ -556,6 +563,9 @@ static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
const char *name = RE_debug_pass_name_get(debug_type);
int channels = RE_debug_pass_num_channels_get(debug_type);
RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type, view);
+ if (rpass == NULL) {
+ return NULL;
+ }
rpass->debug_type = debug_type;
BLI_strncpy(rpass->name,
name,
@@ -640,7 +650,12 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
rl->recty = recty;
if (rr->do_exr_tile) {
- rl->display_buffer = MEM_mapallocN(rectx * recty * sizeof(unsigned int), "Combined display space rgba");
+ rl->display_buffer = MEM_mapallocN((size_t)rectx * recty * sizeof(unsigned int),
+ "Combined display space rgba");
+ if (rl->display_buffer == NULL) {
+ render_result_free(rr);
+ return NULL;
+ }
rl->exrhandle = IMB_exr_get_handle();
}
@@ -654,76 +669,90 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
if (rr->do_exr_tile)
IMB_exr_add_view(rl->exrhandle, view);
+#define RENDER_LAYER_ADD_PASS_SAFE(rr, rl, channels, passtype, viewname) \
+ do { \
+ if (render_layer_add_pass(rr, rl, channels, passtype, viewname) == NULL) { \
+ render_result_free(rr); \
+ return NULL; \
+ } \
+ } while (false)
+
/* a renderlayer should always have a Combined pass*/
render_layer_add_pass(rr, rl, 4, SCE_PASS_COMBINED, view);
if (srl->passflag & SCE_PASS_Z)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_Z, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_Z, view);
if (srl->passflag & SCE_PASS_VECTOR)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_VECTOR, view);
if (srl->passflag & SCE_PASS_NORMAL)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_NORMAL, view);
if (srl->passflag & SCE_PASS_UV)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_UV, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_UV, view);
if (srl->passflag & SCE_PASS_RGBA)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RGBA, view);
if (srl->passflag & SCE_PASS_EMIT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_EMIT, view);
if (srl->passflag & SCE_PASS_DIFFUSE)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE, view);
if (srl->passflag & SCE_PASS_SPEC)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SPEC, view);
if (srl->passflag & SCE_PASS_AO)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_AO, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_AO, view);
if (srl->passflag & SCE_PASS_ENVIRONMENT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_ENVIRONMENT, view);
if (srl->passflag & SCE_PASS_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_INDIRECT, view);
if (srl->passflag & SCE_PASS_SHADOW)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SHADOW, view);
if (srl->passflag & SCE_PASS_REFLECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFLECT, view);
if (srl->passflag & SCE_PASS_REFRACT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_REFRACT, view);
if (srl->passflag & SCE_PASS_INDEXOB)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXOB, view);
if (srl->passflag & SCE_PASS_INDEXMA)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_INDEXMA, view);
if (srl->passflag & SCE_PASS_MIST)
- render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 1, SCE_PASS_MIST, view);
if (rl->passflag & SCE_PASS_RAYHITS)
- render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 4, SCE_PASS_RAYHITS, view);
if (srl->passflag & SCE_PASS_DIFFUSE_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_DIRECT, view);
if (srl->passflag & SCE_PASS_DIFFUSE_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_INDIRECT, view);
if (srl->passflag & SCE_PASS_DIFFUSE_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_DIFFUSE_COLOR, view);
if (srl->passflag & SCE_PASS_GLOSSY_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_DIRECT, view);
if (srl->passflag & SCE_PASS_GLOSSY_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_INDIRECT, view);
if (srl->passflag & SCE_PASS_GLOSSY_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_GLOSSY_COLOR, view);
if (srl->passflag & SCE_PASS_TRANSM_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_DIRECT, view);
if (srl->passflag & SCE_PASS_TRANSM_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_INDIRECT, view);
if (srl->passflag & SCE_PASS_TRANSM_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_TRANSM_COLOR, view);
if (srl->passflag & SCE_PASS_SUBSURFACE_DIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_DIRECT, view);
if (srl->passflag & SCE_PASS_SUBSURFACE_INDIRECT)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_INDIRECT, view);
if (srl->passflag & SCE_PASS_SUBSURFACE_COLOR)
- render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
+ RENDER_LAYER_ADD_PASS_SAFE(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR, view);
#ifdef WITH_CYCLES_DEBUG
if (BKE_scene_use_new_shading_nodes(re->scene)) {
- render_layer_add_debug_pass(rr, rl, SCE_PASS_DEBUG,
- re->r.debug_pass_type, view);
+ if (render_layer_add_debug_pass(rr, rl, SCE_PASS_DEBUG,
+ re->r.debug_pass_type, view) == NULL)
+ {
+ render_result_free(rr);
+ return NULL;
+ }
}
#endif
+
+#undef RENDER_LAYER_ADD_PASS_SAFE
}
}
/* sss, previewrender and envmap don't do layers, so we make a default one */
@@ -1134,6 +1163,8 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
}
}
+ errno = 0;
+
BLI_make_existing_file(filename);
if (IMB_exr_begin_write(exrhandle, filename, width, height, compress, rr->stamp_data)) {
@@ -1142,7 +1173,7 @@ bool RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *fil
}
else {
/* TODO, get the error from openexr's exception */
- BKE_report(reports, RPT_ERROR, "Error writing render result (see console)");
+ BKE_reportf(reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
success = false;
}
@@ -1527,7 +1558,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd, const int vi
return ibuf;
}
-void render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id)
+void RE_render_result_rect_from_ibuf(RenderResult *rr, RenderData *UNUSED(rd), ImBuf *ibuf, const int view_id)
{
RenderView *rv = RE_RenderViewGetById(rr, view_id);
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index b282ec0593e..8f61f4159e6 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -85,12 +85,12 @@ extern struct Render R;
static RNG_THREAD_ARRAY *random_tex_array;
-void RE_init_texture_rng(void)
+void RE_texture_rng_init(void)
{
random_tex_array = BLI_rng_threaded_new();
}
-void RE_exit_texture_rng(void)
+void RE_texture_rng_exit(void)
{
BLI_rng_threaded_free(random_tex_array);
}
@@ -1103,7 +1103,16 @@ static void do_2d_mapping(MTex *mtex, float texvec[3], VlakRen *vlr, const float
/* ************************************** */
-static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, struct ImagePool *pool, const bool skip_load_image)
+static int multitex(Tex *tex,
+ float texvec[3],
+ float dxt[3], float dyt[3],
+ int osatex,
+ TexResult *texres,
+ const short thread,
+ const short which_output,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview)
{
float tmpvec[3];
int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
@@ -1112,7 +1121,7 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o
if (tex->use_nodes && tex->nodetree) {
retval = ntreeTexExecTree(tex->nodetree, texres, texvec, dxt, dyt, osatex, thread,
- tex, which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, NULL, NULL);
+ tex, which_output, R.r.cfra, texnode_preview, NULL, NULL);
}
else {
switch (tex->type) {
@@ -1218,9 +1227,19 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o
return retval;
}
-static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres,
- const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool,
- bool scene_color_manage, const bool skip_load_image)
+static int multitex_nodes_intern(Tex *tex,
+ float texvec[3],
+ float dxt[3], float dyt[3],
+ int osatex,
+ TexResult *texres,
+ const short thread,
+ short which_output,
+ ShadeInput *shi,
+ MTex *mtex, struct
+ ImagePool *pool,
+ const bool scene_color_manage,
+ const bool skip_load_image,
+ const bool texnode_preview)
{
if (tex==NULL) {
memset(texres, 0, sizeof(TexResult));
@@ -1236,14 +1255,28 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float
if (mtex) {
/* we have mtex, use it for 2d mapping images only */
do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
- rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool, skip_load_image);
+ rgbnor = multitex(tex,
+ texvec,
+ dxt, dyt,
+ osatex,
+ texres,
+ thread,
+ which_output,
+ pool,
+ skip_load_image,
+ texnode_preview);
if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && scene_color_manage)
+ if (ibuf != NULL &&
+ ibuf->rect_float == NULL &&
+ (rgbnor & TEX_RGB) &&
+ scene_color_manage)
+ {
IMB_colormanagement_colorspace_to_scene_linear_v3(&texres->tr, ibuf->rect_colorspace);
+ }
BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
}
@@ -1269,14 +1302,28 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float
}
do_2d_mapping(&localmtex, texvec_l, NULL, NULL, dxt_l, dyt_l);
- rgbnor = multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output, pool, skip_load_image);
+ rgbnor = multitex(tex,
+ texvec_l,
+ dxt_l, dyt_l,
+ osatex,
+ texres,
+ thread,
+ which_output,
+ pool,
+ skip_load_image,
+ texnode_preview);
{
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && scene_color_manage)
+ if (ibuf != NULL &&
+ ibuf->rect_float == NULL &&
+ (rgbnor & TEX_RGB) &&
+ scene_color_manage)
+ {
IMB_colormanagement_colorspace_to_scene_linear_v3(&texres->tr, ibuf->rect_colorspace);
+ }
BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
}
@@ -1285,7 +1332,16 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float
return rgbnor;
}
else {
- return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool, skip_load_image);
+ return multitex(tex,
+ texvec,
+ dxt, dyt,
+ osatex,
+ texres,
+ thread,
+ which_output,
+ pool,
+ skip_load_image,
+ texnode_preview);
}
}
@@ -1297,14 +1353,15 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os
{
return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres,
thread, which_output, shi, mtex, pool, R.scene_color_manage,
- (R.r.scemode & R_NO_IMAGE_LOAD) != 0);
+ (R.r.scemode & R_NO_IMAGE_LOAD) != 0,
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
}
/* this is called for surface shading */
static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
Tex *tex = mtex->tex;
-
+ /* TODO(sergey): Texture preview should become an argument? */
if (tex->use_nodes && tex->nodetree) {
/* stupid exception here .. but we have to pass shi and mtex to
* textures nodes for 2d mapping and color management for images */
@@ -1312,7 +1369,16 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
tex, mtex->which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, shi, mtex);
}
else {
- return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output, pool, skip_load_image);
+ return multitex(mtex->tex,
+ texvec,
+ dxt, dyt,
+ shi->osatex,
+ texres,
+ shi->thread,
+ mtex->which_output,
+ pool,
+ skip_load_image,
+ (R.r.scemode & R_TEXNODE_PREVIEW) != 0);
}
}
@@ -1321,9 +1387,28 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
*
* Use it for stuff which is out of render pipeline.
*/
-int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
+int multitex_ext(Tex *tex,
+ float texvec[3],
+ float dxt[3], float dyt[3],
+ int osatex,
+ TexResult *texres,
+ const short thread,
+ struct ImagePool *pool,
+ bool scene_color_manage,
+ const bool skip_load_image)
{
- return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image);
+ return multitex_nodes_intern(tex,
+ texvec,
+ dxt, dyt,
+ osatex,
+ texres,
+ thread,
+ 0,
+ NULL, NULL,
+ pool,
+ scene_color_manage,
+ skip_load_image,
+ false);
}
/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
@@ -1335,7 +1420,7 @@ int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct Image
int use_nodes= tex->use_nodes, retval;
tex->use_nodes = false;
- retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image);
+ retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image, false);
tex->use_nodes= use_nodes;
return retval;
@@ -2426,8 +2511,13 @@ void do_material_tex(ShadeInput *shi, Render *re)
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, re->pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf && !(ibuf->rect_float) && R.scene_color_manage)
+ if (ibuf != NULL &&
+ ibuf->rect_float == NULL &&
+ (rgbnor & TEX_RGB) &&
+ R.scene_color_manage)
+ {
IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace);
+ }
BKE_image_pool_release_ibuf(ima, ibuf, re->pool);
}
@@ -2672,6 +2762,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_r[3], float *val, Render *re)
{
const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
MTex *mtex;
Tex *tex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
@@ -2759,7 +2850,16 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
}
- rgbnor = multitex(tex, texvec, NULL, NULL, 0, &texres, shi->thread, mtex->which_output, re->pool, skip_load_image); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
+ rgbnor = multitex(tex,
+ texvec,
+ NULL, NULL,
+ 0,
+ &texres,
+ shi->thread,
+ mtex->which_output,
+ re->pool,
+ skip_load_image,
+ texnode_preview); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
/* texture output */
@@ -2871,6 +2971,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
{
const bool skip_load_image = har->skip_load_image;
+ const bool texnode_preview = har->texnode_preview;
MTex *mtex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
float texvec[3], dxt[3], dyt[3], fact, facm, dx;
@@ -2927,7 +3028,16 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
if (mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- rgb = multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output, har->pool, skip_load_image);
+ rgb = multitex(mtex->tex,
+ texvec,
+ dxt, dyt,
+ osatex,
+ &texres,
+ 0,
+ mtex->which_output,
+ har->pool,
+ skip_load_image,
+ texnode_preview);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3014,13 +3124,16 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
/* ------------------------------------------------------------------------- */
/* hor and zen are RGB vectors, blend is 1 float, should all be initialized */
-void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float hor[3], float zen[3], float *blend, int skyflag, short thread)
+void do_sky_tex(
+ const float rco[3], const float view[3], const float lo[3], const float dxyview[2],
+ float hor[3], float zen[3], float *blend, int skyflag, short thread)
{
const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (R.r.scemode & R_TEXNODE_PREVIEW) != 0;
MTex *mtex;
Tex *tex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
- float *co, fact, stencilTin=1.0;
+ float fact, stencilTin=1.0;
float tempvec[3], texvec[3], dxt[3], dyt[3];
int tex_nr, rgb= 0;
@@ -3030,6 +3143,8 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
for (tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
if (R.wrld.mtex[tex_nr]) {
+ const float *co;
+
mtex= R.wrld.mtex[tex_nr];
tex= mtex->tex;
@@ -3091,8 +3206,8 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
}
break;
case TEXCO_EQUIRECTMAP:
- tempvec[0]= atan2f(lo[0], lo[2]) / (float)M_PI;
- tempvec[1]= 1.0f - 2.0f*saacos(lo[1]) / (float)M_PI;
+ tempvec[0]= -atan2f(lo[2], lo[0]) / (float)M_PI;
+ tempvec[1]= atan2f(lo[1], hypot(lo[0], lo[2])) / (float)M_PI_2;
tempvec[2]= 0.0f;
co= tempvec;
break;
@@ -3118,6 +3233,9 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
// copy_v3_v3(shi->dygl, shi->dyco);
// mul_m3_v3(R.imat, shi->dyco);
break;
+ case TEXCO_VIEW:
+ co = view;
+ break;
}
/* placement */
@@ -3133,7 +3251,16 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
/* texture */
if (tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- rgb = multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output, R.pool, skip_load_image);
+ rgb = multitex(mtex->tex,
+ texvec,
+ dxt, dyt,
+ R.osa,
+ &texres,
+ thread,
+ mtex->which_output,
+ R.pool,
+ skip_load_image,
+ texnode_preview);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3226,6 +3353,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r[3], int effect)
{
const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (R.r.scemode & R_TEXNODE_PREVIEW) != 0;
Object *ob;
MTex *mtex;
Tex *tex;
@@ -3349,7 +3477,16 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
}
- rgb = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output, R.pool, skip_load_image);
+ rgb = multitex(tex,
+ texvec,
+ dxt, dyt,
+ shi->osatex,
+ &texres,
+ shi->thread,
+ mtex->which_output,
+ R.pool,
+ skip_load_image,
+ texnode_preview);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3423,7 +3560,13 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
/* ------------------------------------------------------------------------- */
-int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image)
+int externtex(MTex *mtex,
+ const float vec[3],
+ float *tin, float *tr, float *tg, float *tb, float *ta,
+ const int thread,
+ struct ImagePool *pool,
+ const bool skip_load_image,
+ const bool texnode_preview)
{
Tex *tex;
TexResult texr;
@@ -3449,7 +3592,15 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg,
do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
}
- rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool, skip_load_image);
+ rgb = multitex(tex,
+ texvec,
+ dxt, dyt,
+ 0, &texr,
+ thread,
+ mtex->which_output,
+ pool,
+ skip_load_image,
+ texnode_preview);
if (rgb) {
texr.tin = IMB_colormanagement_get_luminance(&texr.tr);
@@ -3555,7 +3706,7 @@ static void textured_face_generate_uv(
}
/* Generate an updated copy of material to use for color sampling. */
-Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
+Material *RE_sample_material_init(Material *orig_mat, Scene *scene)
{
Tex *tex = NULL;
Material *mat;
@@ -3643,8 +3794,8 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
return mat;
}
-/* free all duplicate data allocated by RE_init_sample_material() */
-void RE_free_sample_material(Material *mat)
+/* free all duplicate data allocated by RE_sample_material_init() */
+void RE_sample_material_free(Material *mat)
{
int tex_nr;
@@ -3684,7 +3835,7 @@ void RE_sample_material_color(
MVert *mvert;
MLoop *mloop;
const MLoopTri *mlooptri;
- float uv[3], normal[3];
+ float normal[3];
ShadeInput shi = {NULL};
Render re = {NULL};
@@ -3697,7 +3848,9 @@ void RE_sample_material_color(
return;
}
- v1=mloop[mlooptri[tri_index].tri[0]].v, v2=mloop[mlooptri[tri_index].tri[1]].v, v3=mloop[mlooptri[tri_index].tri[2]].v;
+ v1 = mloop[mlooptri[tri_index].tri[0]].v;
+ v2 = mloop[mlooptri[tri_index].tri[1]].v;
+ v3 = mloop[mlooptri[tri_index].tri[2]].v;
normal_tri_v3(normal, mvert[v1].co, mvert[v2].co, mvert[v3].co);
/* generate shadeinput with data required */
@@ -3712,6 +3865,7 @@ void RE_sample_material_color(
mul_m4_v3(ob->imat, shi.co);
/* orco coordinates */
{
+ float uv[2];
float l;
/* Get generated UV */
textured_face_generate_uv(normal, shi.co, mvert[v1].co, mvert[v2].co, mvert[v3].co, uv);
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 894ade42a1f..910ea16607e 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -1971,9 +1971,9 @@ void add_halo_flare(Render *re)
rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, re->viewname);
- if (rl==NULL || rect)
- return;
-
+ if (rect==NULL)
+ continue;
+
mode= R.r.mode;
R.r.mode &= ~R_PANORAMA;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index d271592af5f..e8db096c9a5 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -956,6 +956,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
const float *orco, float hasize, float vectsize, int seed)
{
const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
HaloRen *har;
MTex *mtex;
float tin, tr, tg, tb, ta;
@@ -1047,7 +1048,13 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
}
}
- externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool, skip_load_image);
+ externtex(mtex,
+ texvec,
+ &tin, &tr, &tg, &tb, &ta,
+ 0,
+ re->pool,
+ skip_load_image,
+ texnode_preview);
yn= tin*mtex->colfac;
//zn= tin*mtex->alphafac;
@@ -1067,7 +1074,8 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
}
har->pool = re->pool;
- har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ har->skip_load_image = skip_load_image;
+ har->texnode_preview = texnode_preview;
return har;
}
@@ -1077,6 +1085,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3])
{
const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ const bool texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
HaloRen *har;
MTex *mtex;
float tin, tr, tg, tb, ta;
@@ -1180,7 +1189,13 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
copy_v3_v3(texvec, orco);
}
- hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool, skip_load_image);
+ hasrgb = externtex(mtex,
+ texvec,
+ &tin, &tr, &tg, &tb, &ta,
+ 0,
+ re->pool,
+ skip_load_image,
+ texnode_preview);
//yn= tin*mtex->colfac;
//zn= tin*mtex->alphafac;
@@ -1225,6 +1240,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
har->pool = re->pool;
har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
+ har->texnode_preview = (re->r.scemode & R_TEXNODE_PREVIEW) != 0;
return har;
}
@@ -1363,7 +1379,29 @@ void project_renderdata(Render *re,
/* ------------------------------------------------------------------------- */
-ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob, Object *par, int index, int psysindex, float mat[4][4], int lay)
+void RE_updateRenderInstance(Render *re, ObjectInstanceRen *obi, int flag)
+{
+ /* flag specifies what things have changed. */
+ if (flag & RE_OBJECT_INSTANCES_UPDATE_OBMAT) {
+ copy_m4_m4(obi->obmat, obi->ob->obmat);
+ invert_m4_m4(obi->obinvmat, obi->obmat);
+ }
+ if (flag & RE_OBJECT_INSTANCES_UPDATE_VIEW) {
+ mul_m4_m4m4(obi->localtoviewmat, re->viewmat, obi->obmat);
+ mul_m4_m4m4(obi->localtoviewinvmat, obi->obinvmat, re->viewinv);
+ }
+}
+
+void RE_updateRenderInstances(Render *re, int flag)
+{
+ int i = 0;
+ for (i = 0; i < re->totinstance; i++)
+ RE_updateRenderInstance(re, &re->objectinstance[i], flag);
+}
+
+ObjectInstanceRen *RE_addRenderInstance(
+ Render *re, ObjectRen *obr, Object *ob, Object *par,
+ int index, int psysindex, float mat[4][4], int lay, const DupliObject *dob)
{
ObjectInstanceRen *obi;
float mat3[3][3];
@@ -1377,37 +1415,36 @@ ObjectInstanceRen *RE_addRenderInstance(Render *re, ObjectRen *obr, Object *ob,
obi->lay= lay;
/* Fill particle info */
- if (obi->psysindex >= 0) {
- int psysindex = 0;
- int index;
- ParticleSystem *psys;
- if (obi->par) {
- for (psys = obi->par->particlesystem.first; psys; psys = psys->next) {
- if (psysindex == obi->psysindex)
- break;
- ++psysindex;
+ if (par && dob) {
+ const ParticleSystem *psys = dob->particle_system;
+ if (psys) {
+ int part_index;
+ if (obi->index < psys->totpart) {
+ part_index = obi->index;
}
- if (psys) {
- if (obi->index < psys->totpart)
- index = obi->index;
- else {
- index = psys->child[obi->index - psys->totpart].parent;
- }
- if (index >= 0) {
- ParticleData* p = &psys->particles[index];
- obi->part_index = index;
- obi->part_size = p->size;
- obi->part_age = RE_GetStats(re)->cfra - p->time;
- obi->part_lifetime = p->lifetime;
-
- copy_v3_v3(obi->part_co, p->state.co);
- copy_v3_v3(obi->part_vel, p->state.vel);
- copy_v3_v3(obi->part_avel, p->state.ave);
- }
+ else if (psys->child) {
+ part_index = psys->child[obi->index - psys->totpart].parent;
+ }
+ else {
+ part_index = -1;
+ }
+
+ if (part_index >= 0) {
+ const ParticleData *p = &psys->particles[part_index];
+ obi->part_index = part_index;
+ obi->part_size = p->size;
+ obi->part_age = RE_GetStats(re)->cfra - p->time;
+ obi->part_lifetime = p->lifetime;
+
+ copy_v3_v3(obi->part_co, p->state.co);
+ copy_v3_v3(obi->part_vel, p->state.vel);
+ copy_v3_v3(obi->part_avel, p->state.ave);
}
}
}
+ RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW);
+
if (mat) {
copy_m4_m4(obi->mat, mat);
copy_m3_m4(mat3, mat);
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
index 0bd4815fb73..6dd7e2c152d 100644
--- a/source/blender/render/intern/source/shadbuf.c
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -287,12 +287,12 @@ static int compress_deepsamples(DeepSample *dsample, int tot, float epsilon)
return newtot;
}
-static float deep_alpha(Render *re, int obinr, int facenr, int strand)
+static float deep_alpha(Render *re, int obinr, int facenr, bool use_strand)
{
ObjectInstanceRen *obi= &re->objectinstance[obinr];
Material *ma;
- if (strand) {
+ if (use_strand) {
StrandRen *strand= RE_findOrAddStrand(obi->obr, facenr-1);
ma= strand->buffer->ma;
}
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
index 08304533b95..e60a5a70a7f 100644
--- a/source/blender/render/intern/source/shadeinput.c
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -705,6 +705,35 @@ void shade_input_set_viewco(ShadeInput *shi, float x, float y, float xs, float y
shade_input_calc_viewco(shi, xs, ys, z, shi->view, dxyview, shi->co, dxco, dyco);
}
+void barycentric_differentials_from_position(
+ const float co[3], const float v1[3], const float v2[3], const float v3[3],
+ const float dxco[3], const float dyco[3], const float facenor[3], const bool differentials,
+ float *u, float *v, float *dx_u, float *dx_v, float *dy_u, float *dy_v)
+{
+ /* find most stable axis to project */
+ int axis1, axis2;
+ axis_dominant_v3(&axis1, &axis2, facenor);
+
+ /* compute u,v and derivatives */
+ float t00 = v3[axis1] - v1[axis1];
+ float t01 = v3[axis2] - v1[axis2];
+ float t10 = v3[axis1] - v2[axis1];
+ float t11 = v3[axis2] - v2[axis2];
+
+ float detsh = (t00 * t11 - t10 * t01);
+ detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
+ t00 *= detsh; t01 *= detsh;
+ t10 *= detsh; t11 *= detsh;
+
+ *u = (v3[axis1] - co[axis1]) * t11 - (v3[axis2] - co[axis2]) * t10;
+ *v = (v3[axis2] - co[axis2]) * t00 - (v3[axis1] - co[axis1]) * t01;
+ if (differentials) {
+ *dx_u = dxco[axis1] * t11 - dxco[axis2] * t10;
+ *dx_v = dxco[axis2] * t00 - dxco[axis1] * t01;
+ *dy_u = dyco[axis1] * t11 - dyco[axis2] * t10;
+ *dy_v = dyco[axis2] * t00 - dyco[axis1] * t01;
+ }
+}
/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
void shade_input_set_uv(ShadeInput *shi)
{
@@ -746,30 +775,12 @@ void shade_input_set_uv(ShadeInput *shi)
}
}
else {
- /* most of this could become re-used for faces */
- float detsh, t00, t10, t01, t11;
- int axis1, axis2;
-
- /* find most stable axis to project */
- axis_dominant_v3(&axis1, &axis2, shi->facenor);
+ barycentric_differentials_from_position(
+ shi->co, v1, v2, v3, shi->dxco, shi->dyco, shi->facenor, shi->osatex,
+ &shi->u, &shi->v, &shi->dx_u, &shi->dx_v, &shi->dy_u, &shi->dy_v);
- /* compute u,v and derivatives */
- t00 = v3[axis1] - v1[axis1]; t01 = v3[axis2] - v1[axis2];
- t10 = v3[axis1] - v2[axis1]; t11 = v3[axis2] - v2[axis2];
-
- detsh = (t00 * t11 - t10 * t01);
- detsh = (detsh != 0.0f) ? 1.0f / detsh : 0.0f;
- t00 *= detsh; t01 *= detsh;
- t10 *= detsh; t11 *= detsh;
-
- shi->u = (shi->co[axis1] - v3[axis1]) * t11 - (shi->co[axis2] - v3[axis2]) * t10;
- shi->v = (shi->co[axis2] - v3[axis2]) * t00 - (shi->co[axis1] - v3[axis1]) * t01;
- if (shi->osatex) {
- shi->dx_u = shi->dxco[axis1] * t11 - shi->dxco[axis2] * t10;
- shi->dx_v = shi->dxco[axis2] * t00 - shi->dxco[axis1] * t01;
- shi->dy_u = shi->dyco[axis1] * t11 - shi->dyco[axis2] * t10;
- shi->dy_v = shi->dyco[axis2] * t00 - shi->dyco[axis1] * t01;
- }
+ shi->u = -shi->u;
+ shi->v = -shi->v;
/* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
CLAMP(shi->u, -2.0f, 1.0f);
@@ -1131,7 +1142,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
float obwinmat[4][4], winmat[4][4], ho1[4], ho2[4], ho3[4];
float Zmulx, Zmuly;
- float hox, hoy, l, dl, u, v;
+ float hox, hoy, l_proj, dl_proj, u_proj, v_proj;
float s00, s01, s10, s11, detsh;
/* old globals, localized now */
@@ -1161,12 +1172,12 @@ void shade_input_set_shade_texco(ShadeInput *shi)
/* recalc u and v again */
hox = x / Zmulx - 1.0f;
hoy = y / Zmuly - 1.0f;
- u = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10;
- v = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01;
- l = 1.0f + u + v;
+ u_proj = (hox - ho3[0] / ho3[3]) * s11 - (hoy - ho3[1] / ho3[3]) * s10;
+ v_proj = (hoy - ho3[1] / ho3[3]) * s00 - (hox - ho3[0] / ho3[3]) * s01;
+ l_proj = 1.0f + u_proj + v_proj;
- suv->uv[0] = l * s3[0] - u * s1[0] - v * s2[0];
- suv->uv[1] = l * s3[1] - u * s1[1] - v * s2[1];
+ suv->uv[0] = l_proj * s3[0] - u_proj * s1[0] - v_proj * s2[0];
+ suv->uv[1] = l_proj * s3[1] - u_proj * s1[1] - v_proj * s2[1];
suv->uv[2] = 0.0f;
if (shi->osatex) {
@@ -1176,12 +1187,12 @@ void shade_input_set_shade_texco(ShadeInput *shi)
dyuv[0] = -s10 / Zmuly;
dyuv[1] = s00 / Zmuly;
- dl = dxuv[0] + dxuv[1];
- suv->dxuv[0] = dl * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0];
- suv->dxuv[1] = dl * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1];
- dl = dyuv[0] + dyuv[1];
- suv->dyuv[0] = dl * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0];
- suv->dyuv[1] = dl * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1];
+ dl_proj = dxuv[0] + dxuv[1];
+ suv->dxuv[0] = dl_proj * s3[0] - dxuv[0] * s1[0] - dxuv[1] * s2[0];
+ suv->dxuv[1] = dl_proj * s3[1] - dxuv[0] * s1[1] - dxuv[1] * s2[1];
+ dl_proj = dyuv[0] + dyuv[1];
+ suv->dyuv[0] = dl_proj * s3[0] - dyuv[0] * s1[0] - dyuv[1] * s2[0];
+ suv->dyuv[1] = dl_proj * s3[1] - dyuv[0] * s1[1] - dyuv[1] * s2[1];
}
}
else {
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 39dfa48d3f1..9dec2698720 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -894,7 +894,7 @@ void calc_R_ref(ShadeInput *shi)
}
-/* called from ray.c */
+/* called from rayshade.c */
void shade_color(ShadeInput *shi, ShadeResult *shr)
{
Material *ma= shi->mat;
@@ -1188,12 +1188,10 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
return 1.0f;
}
else {
- float visifac= 1.0f, t;
+ float visifac= 1.0f, visifac_r;
sub_v3_v3v3(lv, co, lar->co);
- *dist = len_v3(lv);
- t = 1.0f / (*dist);
- mul_v3_fl(lv, t);
+ mul_v3_fl(lv, 1.0f / (*dist = len_v3(lv)));
/* area type has no quad or sphere option */
if (lar->type==LA_AREA) {
@@ -1225,6 +1223,15 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
if (lar->ld2>0.0f)
visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
break;
+ case LA_FALLOFF_INVCOEFFICIENTS:
+ visifac_r = lar->coeff_const +
+ lar->coeff_lin * dist[0] +
+ lar->coeff_quad * dist[0] * dist[0];
+ if (visifac_r > 0.0)
+ visifac = 1.0 / visifac_r;
+ else
+ visifac = 0.0;
+ break;
case LA_FALLOFF_CURVE:
/* curvemapping_initialize is called from #add_render_lamp */
visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
@@ -1241,7 +1248,7 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
if (visifac > 0.0f) {
if (lar->type==LA_SPOT) {
- float inpr;
+ float inpr, t;
if (lar->mode & LA_SQUARE) {
if (dot_v3v3(lv, lar->vec) > 0.0f) {
@@ -1615,9 +1622,6 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
lar= go->lampren;
if (lar==NULL) continue;
- /* yafray: ignore shading by photonlights, not used in Blender */
- if (lar->type==LA_YF_PHOTON) continue;
-
if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
if ((lar->lay & shi->lay)==0) continue;
@@ -1815,7 +1819,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
shr->combined[1]= shi->g;
shr->combined[2]= shi->b;
shr->alpha= shi->alpha;
- return;
+ goto finally_shadeless;
}
if ( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { /* vertexcolor light */
@@ -1858,9 +1862,6 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
lar= go->lampren;
if (lar==NULL) continue;
- /* yafray: ignore shading by photonlights, not used in Blender */
- if (lar->type==LA_YF_PHOTON) continue;
-
/* test for lamp layer */
if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay)==0) continue;
if ((lar->lay & shi->lay)==0) continue;
@@ -1922,8 +1923,8 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
copy_v3_v3(shr->combined, shr->diffshad);
/* calculate shadow pass, we use a multiplication mask */
- /* if diff = 0,0,0 it doesn't matter what the shadow pass is, so leave it as is */
- if (passflag & SCE_PASS_SHADOW && !(shr->diff[0]==0.0f && shr->diff[1]==0.0f && shr->diff[2]==0.0f)) {
+ /* Even if diff = 0,0,0, it does matter what the shadow pass is, since we may want it 'for itself'! */
+ if (passflag & SCE_PASS_SHADOW) {
if (shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
/* can't determine proper shadow from shad/diff (0/0), so use shadow intensity */
else if (shr->shad[0]==0.0f) shr->shad[0]= shr->shad[3];
@@ -2006,7 +2007,11 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
add_v3_v3(shr->combined, shr->emit);
if (shi->combinedflag & SCE_PASS_SPEC)
add_v3_v3(shr->combined, shr->spec);
-
+
+
+ /* Last section of this function applies to shadeless colors too */
+finally_shadeless:
+
/* modulate by the object color */
if ((ma->shade_flag & MA_OBCOLOR) && shi->obr->ob) {
if (!(ma->sss_flag & MA_DIFF_SSS) || !sss_pass_done(&R, ma)) {
@@ -2031,7 +2036,7 @@ static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[
LampRen *lar = go->lampren;
float visifac, inp;
- if (!lar || lar->type == LA_YF_PHOTON
+ if (!lar
|| ((lar->mode & LA_LAYER) && (lar->lay & shi->obi->lay) == 0)
|| (lar->lay & shi->lay) == 0)
return 0.0f;
@@ -2116,3 +2121,31 @@ float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv
return 0.0f;
}
+
+const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4]
+{
+ if (obi) {
+ switch (matrix_id) {
+ case RE_OBJECT_INSTANCE_MATRIX_OB:
+ return (const float(*)[4])obi->obmat;
+ case RE_OBJECT_INSTANCE_MATRIX_OBINV:
+ return (const float(*)[4])obi->obinvmat;
+ case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEW:
+ return (const float(*)[4])obi->localtoviewmat;
+ case RE_OBJECT_INSTANCE_MATRIX_LOCALTOVIEWINV:
+ return (const float(*)[4])obi->localtoviewinvmat;
+ }
+ }
+ return NULL;
+}
+
+const float (*RE_render_current_get_matrix(int matrix_id))[4]
+{
+ switch(matrix_id) {
+ case RE_VIEW_MATRIX:
+ return (const float(*)[4])R.viewmat;
+ case RE_VIEWINV_MATRIX:
+ return (const float(*)[4])R.viewinv;
+ }
+ return NULL;
+}
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
index 78ede01d6c1..5377d0eba00 100644
--- a/source/blender/render/intern/source/volume_precache.c
+++ b/source/blender/render/intern/source/volume_precache.c
@@ -181,7 +181,7 @@ static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz)
for (x=-1; x <= 1; x++) {
x_ = xx+x;
if (x_ >= 0 && x_ <= res[0]-1) {
- const int i = BLI_VOXEL_INDEX(x_, y_, z_, res);
+ const int64_t i = BLI_VOXEL_INDEX(x_, y_, z_, res);
if (cache[i] > 0.0f) {
tot += cache[i];
@@ -212,7 +212,7 @@ static void lightcache_filter(VolumePrecache *vp)
for (y=0; y < vp->res[1]; y++) {
for (x=0; x < vp->res[0]; x++) {
/* trigger for outside mesh */
- const int i = BLI_VOXEL_INDEX(x, y, z, vp->res);
+ const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
if (vp->data_r[i] < -0.f)
vp->data_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
@@ -244,7 +244,7 @@ static void lightcache_filter2(VolumePrecache *vp)
for (y=0; y < vp->res[1]; y++) {
for (x=0; x < vp->res[0]; x++) {
/* trigger for outside mesh */
- const int i = BLI_VOXEL_INDEX(x, y, z, vp->res);
+ const int64_t i = BLI_VOXEL_INDEX(x, y, z, vp->res);
if (vp->data_r[i] < -0.f)
new_r[i] = get_avg_surrounds(vp->data_r, vp->res, x, y, z);
if (vp->data_g[i] < -0.f)
@@ -265,22 +265,30 @@ static void lightcache_filter2(VolumePrecache *vp)
}
#endif
-BLI_INLINE int ms_I(int x, int y, int z, int *n) /* has a pad of 1 voxel surrounding the core for boundary simulation */
+/* has a pad of 1 voxel surrounding the core for boundary simulation */
+BLI_INLINE int64_t ms_I(int x, int y, int z, const int *n)
{
/* different ordering to light cache */
- return x*(n[1]+2)*(n[2]+2) + y*(n[2]+2) + z;
+ return ((int64_t)x * (int64_t)(n[1] + 2) * (int64_t)(n[2] + 2) +
+ (int64_t)y * (int64_t)(n[2] + 2) +
+ (int64_t)z);
}
-BLI_INLINE int v_I_pad(int x, int y, int z, int *n) /* has a pad of 1 voxel surrounding the core for boundary simulation */
+/* has a pad of 1 voxel surrounding the core for boundary simulation */
+BLI_INLINE int64_t v_I_pad(int x, int y, int z, const int *n)
{
/* same ordering to light cache, with padding */
- return z*(n[1]+2)*(n[0]+2) + y*(n[0]+2) + x;
+ return ((int64_t)z * (int64_t)(n[1] + 2) * (int64_t)(n[0] + 2) +
+ (int64_t)y * (int64_t)(n[0] + 2) +
+ (int64_t)x);
}
-BLI_INLINE int lc_to_ms_I(int x, int y, int z, int *n)
+BLI_INLINE int64_t lc_to_ms_I(int x, int y, int z, const int *n)
{
/* converting light cache index to multiple scattering index */
- return (x-1)*(n[1]*n[2]) + (y-1)*(n[2]) + z-1;
+ return ((int64_t)(x - 1) * ((int64_t)n[1] * (int64_t)n[2]) +
+ (int64_t)(y - 1) * ((int64_t)n[2]) +
+ (int64_t)(z - 1));
}
/* *** multiple scattering approximation *** */
@@ -295,7 +303,7 @@ static float total_ss_energy(Render *re, int do_test_break, VolumePrecache *vp)
for (z=0; z < res[2]; z++) {
for (y=0; y < res[1]; y++) {
for (x=0; x < res[0]; x++) {
- const int i = BLI_VOXEL_INDEX(x, y, z, res);
+ const int64_t i = BLI_VOXEL_INDEX(x, y, z, res);
if (vp->data_r[i] > 0.f) energy += vp->data_r[i];
if (vp->data_g[i] > 0.f) energy += vp->data_g[i];
@@ -309,7 +317,7 @@ static float total_ss_energy(Render *re, int do_test_break, VolumePrecache *vp)
return energy;
}
-static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg, float *sb, int *res)
+static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg, float *sb, const int res[3])
{
int x, y, z;
float energy=0.f;
@@ -317,7 +325,7 @@ static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg
for (z=1;z<=res[2];z++) {
for (y=1;y<=res[1];y++) {
for (x=1;x<=res[0];x++) {
- const int i = ms_I(x, y, z, res);
+ const int64_t i = ms_I(x, y, z, res);
if (sr[i] > 0.f) energy += sr[i];
if (sg[i] > 0.f) energy += sg[i];
@@ -331,20 +339,28 @@ static float total_ms_energy(Render *re, int do_test_break, float *sr, float *sg
return energy;
}
-static void ms_diffuse(Render *re, int do_test_break, float *x0, float *x, float diff, int *n) //n is the unpadded resolution
+/**
+ * \param n: the unpadded resolution
+ */
+static void ms_diffuse(Render *re, int do_test_break, const float *x0, float *x, float diff, const int n[3])
{
int i, j, k, l;
const float dt = VOL_MS_TIMESTEP;
- size_t size = n[0]*n[1]*n[2];
- const float a = dt*diff*size;
+ int64_t size = (int64_t)n[0] * (int64_t)n[1] * (int64_t)n[2];
+ const float a = dt * diff * size;
for (l=0; l<20; l++) {
for (k=1; k<=n[2]; k++) {
for (j=1; j<=n[1]; j++) {
for (i=1; i<=n[0]; i++) {
- x[v_I_pad(i, j, k, n)] = (x0[v_I_pad(i, j, k, n)]) + a*( x0[v_I_pad(i-1, j, k, n)]+ x0[v_I_pad(i+1, j, k, n)]+ x0[v_I_pad(i, j-1, k, n)]+
- x0[v_I_pad(i, j+1, k, n)]+ x0[v_I_pad(i, j, k-1, n)]+x0[v_I_pad(i, j, k+1, n)]
- ) / (1+6*a);
+ x[v_I_pad(i, j, k, n)] =
+ ((x0[v_I_pad(i, j, k, n)]) + (
+ (x0[v_I_pad(i - 1, j, k, n)] +
+ x0[v_I_pad(i + 1, j, k, n)] +
+ x0[v_I_pad(i, j - 1, k, n)] +
+ x0[v_I_pad(i, j + 1, k, n)] +
+ x0[v_I_pad(i, j, k - 1, n)] +
+ x0[v_I_pad(i, j, k + 1, n)]) * a) / (1 + 6 * a));
}
}
@@ -363,7 +379,7 @@ static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Materi
float fac = ma->vol.ms_intensity;
int x, y, z, m;
- int *n = vp->res;
+ const int *n = vp->res;
const int size = (n[0]+2)*(n[1]+2)*(n[2]+2);
const int do_test_break = (size > 100000);
double time, lasttime= PIL_check_seconds_timer();
@@ -389,8 +405,8 @@ static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Materi
for (z=1; z<=n[2]; z++) {
for (y=1; y<=n[1]; y++) {
for (x=1; x<=n[0]; x++) {
- const int i = lc_to_ms_I(x, y, z, n); //lc index
- const int j = ms_I(x, y, z, n); //ms index
+ const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
+ const int64_t j = ms_I(x, y, z, n); //ms index
time= PIL_check_seconds_timer();
c++;
@@ -448,8 +464,8 @@ static void multiple_scattering_diffusion(Render *re, VolumePrecache *vp, Materi
for (z=1;z<=n[2];z++) {
for (y=1;y<=n[1];y++) {
for (x=1;x<=n[0];x++) {
- const int i = lc_to_ms_I(x, y, z, n); //lc index
- const int j = ms_I(x, y, z, n); //ms index
+ const int64_t i = lc_to_ms_I(x, y, z, n); //lc index
+ const int64_t j = ms_I(x, y, z, n); //ms index
vp->data_r[i] = origf * vp->data_r[i] + fac * sr[j];
vp->data_g[i] = origf * vp->data_g[i] + fac * sg[j];
@@ -496,7 +512,7 @@ typedef struct VolPrecacheState {
int totparts;
} VolPrecacheState;
-static void vol_precache_part(TaskPool *pool, void *taskdata, int UNUSED(threadid))
+static void vol_precache_part(TaskPool * __restrict pool, void *taskdata, int UNUSED(threadid))
{
VolPrecacheState *state = (VolPrecacheState *)BLI_task_pool_userdata(pool);
VolPrecachePart *pa = (VolPrecachePart *)taskdata;
@@ -507,7 +523,7 @@ static void vol_precache_part(TaskPool *pool, void *taskdata, int UNUSED(threadi
ShadeInput *shi = pa->shi;
float scatter_col[3] = {0.f, 0.f, 0.f};
float co[3], cco[3], view[3];
- int x, y, z, i;
+ int x, y, z;
int res[3];
double time;
@@ -527,6 +543,7 @@ static void vol_precache_part(TaskPool *pool, void *taskdata, int UNUSED(threadi
co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f));
for (x=pa->minx; x < pa->maxx; x++) {
+ int64_t i;
co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f));
if (re->test_break && re->test_break(re->tbh))
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index 2c0917243a3..610e86caa13 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -269,7 +269,9 @@ static float metadensity(Object *ob, const float co[3])
/* MB_BALL default */
switch (ml->type) {
case MB_ELIPSOID:
- tp[0] /= ml->expx, tp[1] /= ml->expy, tp[2] /= ml->expz;
+ tp[0] /= ml->expx;
+ tp[1] /= ml->expy;
+ tp[2] /= ml->expz;
break;
case MB_CUBE:
tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
index bb92a8f7e8a..1022aeeec66 100644
--- a/source/blender/render/intern/source/voxeldata.c
+++ b/source/blender/render/intern/source/voxeldata.c
@@ -371,7 +371,6 @@ static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
{
Object *ob;
ModifierData *md;
- bool found = false;
vd->dataset = NULL;
if (vd->object == NULL) return;
@@ -381,11 +380,9 @@ static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
if (pmd->psys && pmd->psys->clmd) {
- found |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
+ vd->ok |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
}
}
-
- vd->ok = found;
}
void cache_voxeldata(Tex *tex, int scene_frame)
@@ -414,6 +411,9 @@ void cache_voxeldata(Tex *tex, int scene_frame)
BLI_strncpy(path, vd->source_path, sizeof(path));
+ /* each type is responsible for setting to true */
+ vd->ok = false;
+
switch (vd->file_format) {
case TEX_VD_IMAGE_SEQUENCE:
load_frame_image_sequence(vd, tex);
@@ -426,7 +426,6 @@ void cache_voxeldata(Tex *tex, int scene_frame)
return;
case TEX_VD_BLENDERVOXEL:
BLI_path_abs(path, G.main->name);
- if (!BLI_exists(path)) return;
fp = BLI_fopen(path, "rb");
if (!fp) return;
@@ -437,7 +436,6 @@ void cache_voxeldata(Tex *tex, int scene_frame)
return;
case TEX_VD_RAW_8BIT:
BLI_path_abs(path, G.main->name);
- if (!BLI_exists(path)) return;
fp = BLI_fopen(path, "rb");
if (!fp) return;
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 58ac34080b9..d3a1dcfd8ce 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -3250,7 +3250,9 @@ static void copyto_abufz(RenderPart *pa, int *arectz, int *rectmask, int sample)
}
}
- rd++; rza++, rma++;
+ rza++;
+ rma++;
+ rd++;
}
}
}
@@ -4238,15 +4240,15 @@ unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pas
if (pa->fullresult.first) {
for (a=0; a<R.osa; a++) {
alpha= samp_shr[a].combined[3];
- if (alpha!=0.0f) {
- RenderLayer *rl= ssamp.rlpp[a];
+ if (alpha != 0.0f) {
+ RenderLayer *rl_other = ssamp.rlpp[a];
- float *rect = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, R.viewname);
+ float *rect = RE_RenderLayerGetPass(rl_other , SCE_PASS_COMBINED, R.viewname);
addAlphaOverFloat(rect + 4 * od, samp_shr[a].combined);
- add_transp_passes(rl, od, &samp_shr[a], alpha);
+ add_transp_passes(rl_other , od, &samp_shr[a], alpha);
if (addpassflag & SCE_PASS_VECTOR)
- add_transp_speed(rl, od, samp_shr[a].winspeed, alpha, rdrect);
+ add_transp_speed(rl_other , od, samp_shr[a].winspeed, alpha, rdrect);
}
}
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index c5e8cbf1260..01188cb7f65 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -58,10 +58,12 @@ set(SRC
intern/wm_draw.c
intern/wm_event_system.c
intern/wm_files.c
+ intern/wm_files_link.c
intern/wm_gesture.c
intern/wm_init_exit.c
intern/wm_jobs.c
intern/wm_keymap.c
+ intern/wm_operator_props.c
intern/wm_operators.c
intern/wm_subwindow.c
intern/wm_window.c
@@ -142,9 +144,6 @@ endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
- list(APPEND INC
- ../../../intern/opensubdiv
- )
endif()
if(WIN32)
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
deleted file mode 100644
index ec1b265d800..00000000000
--- a/source/blender/windowmanager/SConscript
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-import os
-
-sources = env.Glob('intern/*.c')
-
-incs = [
- '.',
- '#/intern/ghost',
- '#/intern/guardedalloc',
- '#/intern/memutil',
- '#/source/gameengine/BlenderRoutines',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '../blenfont',
- '../blenkernel',
- '../blenlib',
- '../blenloader',
- '../blentranslation',
- '../compositor',
- '../editors/include',
- '../gpu',
- '../imbuf',
- '../makesdna',
- '../makesrna',
- '../nodes',
- '../python',
- '../render/extern/include',
- env['BF_ZLIB_INC'],
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_COLLADA']:
- defs.append('WITH_COLLADA')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-if env['BF_BUILDINFO']:
- defs.append('WITH_BUILDINFO')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'):
- if env['WITH_BF_IME']:
- defs.append('WITH_INPUT_IME')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_COMPOSITOR']:
- defs.append("WITH_COMPOSITOR")
-
-if env['WITH_BF_PYTHON_SECURITY']:
- defs.append("WITH_PYTHON_SECURITY")
-
-if env['OURPLATFORM'] in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'aix4', 'aix5'):
- defs.append("WITH_X11")
-
-if env['WITH_BF_OPENSUBDIV']:
- defs.append("WITH_OPENSUBDIV")
- incs += ' #intern/opensubdiv'
-
-env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defines=defs, libtype=['core'], priority=[5] )
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index abbbe759858..db2547e4fbe 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -26,7 +26,7 @@
#ifndef __WM_API_H__
#define __WM_API_H__
-/** \file WM_api.h
+/** \file blender/windowmanager/WM_api.h
* \ingroup wm
*
* \page wmpage windowmanager
@@ -87,18 +87,19 @@ void WM_init_splash (struct bContext *C);
void WM_check (struct bContext *C);
-struct wmWindow *WM_window_open (struct bContext *C, const struct rcti *rect);
-
int WM_window_pixels_x (struct wmWindow *win);
int WM_window_pixels_y (struct wmWindow *win);
bool WM_window_is_fullscreen (struct wmWindow *win);
/* defines for 'type' WM_window_open_temp */
-#define WM_WINDOW_RENDER 0
-#define WM_WINDOW_USERPREFS 1
-// #define WM_WINDOW_FILESEL 2 // UNUSED
+enum {
+ WM_WINDOW_RENDER = 1,
+ WM_WINDOW_USERPREFS,
+ // WM_WINDOW_FILESEL // UNUSED
+};
-void WM_window_open_temp (struct bContext *C, struct rcti *position, int type);
+struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
+struct wmWindow *WM_window_open_temp(struct bContext *C, const struct rcti *rect_init, int type);
/* returns true if draw method is triple buffer */
bool WM_is_draw_triple(struct wmWindow *win);
@@ -111,6 +112,7 @@ void WM_file_autoexec_init(const char *filepath);
bool WM_file_read(struct bContext *C, const char *filepath, struct ReportList *reports);
void WM_autosave_init(struct wmWindowManager *wm);
void WM_recover_last_session(struct bContext *C, struct ReportList *reports);
+void WM_file_tag_modified(const struct bContext *C);
/* mouse cursors */
void WM_cursor_set(struct wmWindow *win, int curs);
@@ -192,9 +194,9 @@ void WM_main_remove_notifier_reference(const void *reference);
void WM_main_remove_editor_id_reference(const struct ID *id);
/* reports */
-void WM_report_banner_show(const struct bContext *C);
-void WM_report(const struct bContext *C, ReportType type, const char *message);
-void WM_reportf(const struct bContext *C, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4);
+void WM_report_banner_show(void);
+void WM_report(ReportType type, const char *message);
+void WM_reportf(ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
void wm_event_add_ex(
struct wmWindow *win, const struct wmEvent *event_to_add,
@@ -279,16 +281,6 @@ void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring
void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot);
void WM_operator_properties_clear(struct PointerRNA *ptr);
void WM_operator_properties_free(struct PointerRNA *ptr);
-void WM_operator_properties_filesel(struct wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort);
-void WM_operator_properties_border(struct wmOperatorType *ot);
-void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
-void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
-void WM_operator_properties_gesture_border(struct wmOperatorType *ot, bool extend);
-void WM_operator_properties_mouse_select(struct wmOperatorType *ot);
-void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor);
-void WM_operator_properties_select_all(struct wmOperatorType *ot);
-void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action);
-void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action);
bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname);
wmOperator *WM_operator_last_redo(const struct bContext *C);
@@ -297,6 +289,34 @@ ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op
bool WM_operator_last_properties_init(struct wmOperator *op);
bool WM_operator_last_properties_store(struct wmOperator *op);
+
+/* wm_operator_props.c */
+void WM_operator_properties_filesel(
+ struct wmOperatorType *ot, int filter, short type, short action,
+ short flag, short display, short sort);
+void WM_operator_properties_border(struct wmOperatorType *ot);
+void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
+void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
+void WM_operator_properties_gesture_border(struct wmOperatorType *ot, bool extend);
+void WM_operator_properties_mouse_select(struct wmOperatorType *ot);
+void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor);
+void WM_operator_properties_select_all(struct wmOperatorType *ot);
+void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action);
+void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action);
+void WM_operator_properties_select_random(struct wmOperatorType *ot);
+int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
+struct CheckerIntervalParams {
+ int nth; /* bypass when set to zero */
+ int skip;
+ int offset;
+};
+void WM_operator_properties_checker_interval(struct wmOperatorType *ot, bool nth_can_disable);
+void WM_operator_properties_checker_interval_from_op(
+ struct wmOperator *op, struct CheckerIntervalParams *op_params);
+bool WM_operator_properties_checker_interval_test(
+ const struct CheckerIntervalParams *op_params, int depth);
+
+
/* MOVE THIS SOMEWHERE ELSE */
#define SEL_TOGGLE 0
#define SEL_SELECT 1
@@ -390,7 +410,6 @@ void wmOrtho (float x1, float x2, float y1, float y2, float n, float f);
void wmOrtho2 (float x1, float x2, float y1, float y2);
/* use for conventions (avoid hard-coded offsets all over) */
void wmOrtho2_region_pixelspace(const struct ARegion *ar);
-void wmOrtho2_region_ui(const struct ARegion *ar);
void wmOrtho2_pixelspace(const float x, const float y);
/* utilities */
@@ -425,6 +444,8 @@ enum {
WM_JOB_TYPE_CLIP_PREFETCH,
WM_JOB_TYPE_SEQ_BUILD_PROXY,
WM_JOB_TYPE_SEQ_BUILD_PREVIEW,
+ WM_JOB_TYPE_POINTCACHE,
+ WM_JOB_TYPE_DPAINT_BAKE,
/* add as needed, screencast, seq proxy build
* if having hard coded values is a problem */
};
@@ -434,10 +455,12 @@ struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void
bool WM_jobs_test(struct wmWindowManager *wm, void *owner, int job_type);
float WM_jobs_progress(struct wmWindowManager *wm, void *owner);
char *WM_jobs_name(struct wmWindowManager *wm, void *owner);
+double WM_jobs_starttime(struct wmWindowManager *wm, void *owner);
void *WM_jobs_customdata(struct wmWindowManager *wm, void *owner);
void *WM_jobs_customdata_from_type(struct wmWindowManager *wm, int job_type);
bool WM_jobs_is_running(struct wmJob *);
+bool WM_jobs_is_stopped(wmWindowManager *wm, void *owner);
void *WM_jobs_customdata_get(struct wmJob *);
void WM_jobs_customdata_set(struct wmJob *, void *customdata, void (*free)(void *));
void WM_jobs_timer(struct wmJob *, double timestep, unsigned int note, unsigned int endnote);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 28a8340cd92..a6413369a8f 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -26,7 +26,7 @@
#ifndef __WM_KEYMAP_H__
#define __WM_KEYMAP_H__
-/** \file WM_keymap.h
+/** \file blender/windowmanager/WM_keymap.h
* \ingroup wm
*/
@@ -110,7 +110,7 @@ const char *WM_key_event_string(const short type, const bool compact);
int WM_keymap_item_raw_to_string(
const short shift, const short ctrl, const short alt, const short oskey, const short keymodifier,
const short val, const short type, const bool compact, const int len, char *r_str);
-int WM_key_event_operator_id(
+wmKeyMapItem *WM_key_event_operator(
const struct bContext *C, const char *opname, int opcontext,
struct IDProperty *properties, const bool is_hotkey,
struct wmKeyMap **r_keymap);
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index fe92d80c1bd..b76a1f1d422 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -376,7 +376,7 @@ void WM_check(bContext *C)
}
/* case: no open windows at all, for old file reads */
- wm_window_add_ghostwindows(wm);
+ wm_window_ghostwindows_ensure(wm);
}
/* case: fileread */
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index d84b65847ca..d4c3928bd6c 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -199,14 +199,10 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4])
* It helps not to get a stuck WM when hitting a breakpoint
* */
GHOST_TGrabCursorMode mode = GHOST_kGrabNormal;
- float fac = GHOST_GetNativePixelSize(win->ghostwin);
- /* in case pixel coords differ from window/mouse coords */
if (bounds) {
- bounds[0] /= fac;
- bounds[1] /= fac;
- bounds[2] /= fac;
- bounds[3] /= fac;
+ wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]);
+ wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]);
}
if (hide) {
@@ -234,7 +230,15 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
{
if ((G.debug & G_DEBUG) == 0) {
if (win && win->ghostwin) {
- GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_ungrab_xy);
+ if (mouse_ungrab_xy) {
+ int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]};
+ wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]);
+ GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_xy);
+ }
+ else {
+ GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, NULL);
+ }
+
win->grabcursor = GHOST_kGrabDisable;
}
}
@@ -249,7 +253,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y)
}
/* give it a modal keymap one day? */
-int wm_cursor_arrow_move(wmWindow *win, wmEvent *event)
+bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event)
{
if (win && event->val == KM_PRESS) {
if (event->type == UPARROWKEY) {
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 16fe9ca5142..8f15d94f538 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -43,7 +43,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLI_math_base.h"
#include "BIF_gl.h"
@@ -59,6 +58,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_glew.h"
+#include "GPU_basic_shader.h"
#include "RE_engine.h"
@@ -69,6 +69,10 @@
#include "wm_window.h"
#include "wm_event_system.h"
+#ifdef WITH_OPENSUBDIV
+# include "BKE_subsurf.h"
+#endif
+
/* swap */
#define WIN_NONE_OK 0
#define WIN_BACK_OK 1
@@ -351,67 +355,15 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
}
}
-#if 0
-/******************** draw damage ************************/
-/* - not implemented */
-
-static void wm_method_draw_damage(bContext *C, wmWindow *win)
-{
- wm_method_draw_all(C, win);
-}
-#endif
-
/****************** draw triple buffer ********************/
/* - area regions are written into a texture, without any */
/* of the overlapping menus, brushes, gestures. these */
/* are redrawn each time. */
-/* */
-/* - if non-power of two textures are supported, that is */
-/* used. if not, multiple smaller ones are used, with */
-/* worst case wasted space being 23.4% for 3x3 textures */
-
-static void split_width(int x, int n, int *splitx, int *nx)
-{
- int a, newnx, waste;
-
- /* if already power of two just use it */
- if (is_power_of_2_i(x)) {
- splitx[0] = x;
- (*nx)++;
- return;
- }
-
- if (n == 1) {
- /* last part, we have to go larger */
- splitx[0] = power_of_2_max_i(x);
- (*nx)++;
- }
- else {
- /* two or more parts to go, use smaller part */
- splitx[0] = power_of_2_min_i(x);
- newnx = ++(*nx);
- split_width(x - splitx[0], n - 1, splitx + 1, &newnx);
-
- for (waste = 0, a = 0; a < n; a++)
- waste += splitx[a];
-
- /* if we waste more space or use the same amount,
- * revert deeper splits and just use larger */
- if (waste >= power_of_2_max_i(x)) {
- splitx[0] = power_of_2_max_i(x);
- memset(splitx + 1, 0, sizeof(int) * (n - 1));
- }
- else
- *nx = newnx;
- }
-}
static void wm_draw_triple_free(wmDrawTriple *triple)
{
if (triple) {
-
- glDeleteTextures(triple->nx * triple->ny, triple->bind);
-
+ glDeleteTextures(1, &triple->bind);
MEM_freeN(triple);
}
}
@@ -430,68 +382,49 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
const int winsize_y = WM_window_pixels_y(win);
GLint maxsize;
- int x, y;
/* compute texture sizes */
if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
triple->target = GL_TEXTURE_RECTANGLE_ARB;
- triple->nx = 1;
- triple->ny = 1;
- triple->x[0] = winsize_x;
- triple->y[0] = winsize_y;
- }
- else if (GPU_non_power_of_two_support()) {
- triple->target = GL_TEXTURE_2D;
- triple->nx = 1;
- triple->ny = 1;
- triple->x[0] = winsize_x;
- triple->y[0] = winsize_y;
}
else {
triple->target = GL_TEXTURE_2D;
- triple->nx = 0;
- triple->ny = 0;
- split_width(winsize_x, MAX_N_TEX, triple->x, &triple->nx);
- split_width(winsize_y, MAX_N_TEX, triple->y, &triple->ny);
}
+ triple->x = winsize_x;
+ triple->y = winsize_y;
+
/* generate texture names */
- glGenTextures(triple->nx * triple->ny, triple->bind);
+ glGenTextures(1, &triple->bind);
- if (!triple->bind[0]) {
+ if (!triple->bind) {
/* not the typical failure case but we handle it anyway */
printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
return 0;
}
- for (y = 0; y < triple->ny; y++) {
- for (x = 0; x < triple->nx; x++) {
- /* proxy texture is only guaranteed to test for the cases that
- * there is only one texture in use, which may not be the case */
- maxsize = GPU_max_texture_size();
-
- if (triple->x[x] > maxsize || triple->y[y] > maxsize) {
- glBindTexture(triple->target, 0);
- printf("WM: failed to allocate texture for triple buffer drawing "
- "(texture too large for graphics card).\n");
- return 0;
- }
+ /* proxy texture is only guaranteed to test for the cases that
+ * there is only one texture in use, which may not be the case */
+ maxsize = GPU_max_texture_size();
- /* setup actual texture */
- glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
- glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- /* The current color is ignored if the GL_REPLACE texture environment is used. */
- // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- glBindTexture(triple->target, 0);
-
- /* not sure if this works everywhere .. */
- if (glGetError() == GL_OUT_OF_MEMORY) {
- printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
- return 0;
- }
- }
+ if (triple->x > maxsize || triple->y > maxsize) {
+ glBindTexture(triple->target, 0);
+ printf("WM: failed to allocate texture for triple buffer drawing "
+ "(texture too large for graphics card).\n");
+ return 0;
+ }
+
+ /* setup actual texture */
+ glBindTexture(triple->target, triple->bind);
+ glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glBindTexture(triple->target, 0);
+
+ /* not sure if this works everywhere .. */
+ if (glGetError() == GL_OUT_OF_MEMORY) {
+ printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
+ return 0;
}
return 1;
@@ -499,51 +432,43 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
float halfx, halfy, ratiox, ratioy;
- int x, y, sizex, sizey, offx, offy;
glEnable(triple->target);
- for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
- for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
- sizex = (x == triple->nx - 1) ? winsize_x - offx : triple->x[x];
- sizey = (y == triple->ny - 1) ? winsize_y - offy : triple->y[y];
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x[x];
- ratioy /= triple->y[y];
- halfx /= triple->x[x];
- halfy /= triple->y[y];
- }
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x;
+ ratioy /= triple->y;
+ halfx /= triple->x;
+ halfy /= triple->y;
+ }
- glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
+ glBindTexture(triple->target, triple->bind);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(offx, offy);
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(0, 0);
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(offx + sizex, offy);
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(sizex, 0);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(offx + sizex, offy + sizey);
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(sizex, sizey);
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(offx, offy + sizey);
- glEnd();
- }
- }
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(0, sizey);
+ glEnd();
glBindTexture(triple->target, 0);
glDisable(triple->target);
@@ -551,20 +476,11 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
- int x, y, sizex, sizey, offx, offy;
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
- for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
- for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
- sizex = (x == triple->nx - 1) ? winsize_x - offx : triple->x[x];
- sizey = (y == triple->ny - 1) ? winsize_y - offy : triple->y[y];
-
- glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
- glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey);
- }
- }
+ glBindTexture(triple->target, triple->bind);
+ glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey);
glBindTexture(triple->target, 0);
}
@@ -948,15 +864,6 @@ static int wm_automatic_draw_method(wmWindow *win)
/* ATI opensource driver is known to be very slow at this */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))
return USER_DRAW_OVERLAP;
- /* also Intel drivers are slow */
-#if 0 /* 2.64 BCon3 period, let's try if intel now works... */
- else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY))
- return USER_DRAW_OVERLAP;
- else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY))
- return USER_DRAW_OVERLAP_FLIP;
- else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY))
- return USER_DRAW_OVERLAP_FLIP;
-#endif
/* Windows software driver darkens color on each redraw */
else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
return USER_DRAW_OVERLAP_FLIP;
@@ -1002,6 +909,10 @@ void wm_draw_update(bContext *C)
wmWindow *win;
int drawmethod;
+#ifdef WITH_OPENSUBDIV
+ BKE_subsurf_free_unused_buffers();
+#endif
+
GPU_free_unused_buffers();
for (win = wm->windows.first; win; win = win->next) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 187c11ef3da..e5b98a1b735 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -410,15 +410,15 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, NULL);
}
-static int wm_event_always_pass(wmEvent *event)
+static int wm_event_always_pass(const wmEvent *event)
{
/* some events we always pass on, to ensure proper communication */
- return ISTIMER(event->type) || (event->type == WINDEACTIVATE) || (event->type == EVT_BUT_OPEN);
+ return ISTIMER(event->type) || (event->type == WINDEACTIVATE);
}
/* ********************* ui handler ******************* */
-static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *event, int always_pass)
+static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, const wmEvent *event, int always_pass)
{
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
@@ -559,8 +559,8 @@ void WM_event_print(const wmEvent *event)
const char *type_id = unknown;
const char *val_id = unknown;
- RNA_enum_identifier(event_type_items, event->type, &type_id);
- RNA_enum_identifier(event_value_items, event->val, &val_id);
+ RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id);
+ RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id);
printf("wmEvent type:%d / %s, val:%d / %s,\n"
" shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n"
@@ -598,17 +598,17 @@ void WM_event_print(const wmEvent *event)
/**
* Show the report in the info header.
*/
-void WM_report_banner_show(const bContext *C)
+void WM_report_banner_show(void)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- ReportList *wm_reports = CTX_wm_reports(C);
+ wmWindowManager *wm = G.main->wm.first;
+ ReportList *wm_reports = &wm->reports;
ReportTimerInfo *rti;
/* After adding reports to the global list, reset the report timer. */
WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
/* Records time since last report was added */
- wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05);
+ wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
wm_reports->reporttimer->customdata = rti;
@@ -624,32 +624,32 @@ void WM_ndof_deadzone_set(float deadzone)
GHOST_setNDOFDeadZone(deadzone);
}
-static void wm_add_reports(const bContext *C, ReportList *reports)
+static void wm_add_reports(ReportList *reports)
{
/* if the caller owns them, handle this */
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
- ReportList *wm_reports = CTX_wm_reports(C);
+ wmWindowManager *wm = G.main->wm.first;
/* add reports to the global list, otherwise they are not seen */
- BLI_movelisttolist(&wm_reports->list, &reports->list);
+ BLI_movelisttolist(&wm->reports.list, &reports->list);
- WM_report_banner_show(C);
+ WM_report_banner_show();
}
}
-void WM_report(const bContext *C, ReportType type, const char *message)
+void WM_report(ReportType type, const char *message)
{
ReportList reports;
BKE_reports_init(&reports, RPT_STORE);
BKE_report(&reports, type, message);
- wm_add_reports(C, &reports);
+ wm_add_reports(&reports);
BKE_reports_clear(&reports);
}
-void WM_reportf(const bContext *C, ReportType type, const char *format, ...)
+void WM_reportf(ReportType type, const char *format, ...)
{
DynStr *ds;
va_list args;
@@ -659,7 +659,9 @@ void WM_reportf(const bContext *C, ReportType type, const char *format, ...)
BLI_dynstr_vappendf(ds, format, args);
va_end(args);
- WM_report(C, type, BLI_dynstr_get_cstring(ds));
+ char *str = BLI_dynstr_get_cstring(ds);
+ WM_report(type, str);
+ MEM_freeN(str);
BLI_dynstr_free(ds);
}
@@ -706,7 +708,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
}
/* if the caller owns them, handle this */
- wm_add_reports(C, op->reports);
+ wm_add_reports(op->reports);
}
/**
@@ -1524,7 +1526,7 @@ int WM_userdef_event_map(int kmitype)
}
-static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
+static int wm_eventmatch(const wmEvent *winevent, wmKeyMapItem *kmi)
{
int kmitype = WM_userdef_event_map(kmi->type);
@@ -1538,8 +1540,24 @@ static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1;
}
- if (kmitype != KM_ANY)
- if (winevent->type != kmitype) return 0;
+ if (kmitype != KM_ANY) {
+ if (ELEM(kmitype, TABLET_STYLUS, TABLET_ERASER)) {
+ const wmTabletData *wmtab = winevent->tablet_data;
+
+ if (wmtab == NULL)
+ return 0;
+ else if (winevent->type != LEFTMOUSE) /* tablet events can occur on hover + keypress */
+ return 0;
+ else if ((kmitype == TABLET_STYLUS) && (wmtab->Active != EVT_TABLET_STYLUS))
+ return 0;
+ else if ((kmitype == TABLET_ERASER) && (wmtab->Active != EVT_TABLET_ERASER))
+ return 0;
+ }
+ else {
+ if (winevent->type != kmitype)
+ return 0;
+ }
+ }
if (kmi->val != KM_ANY)
if (winevent->val != kmi->val) return 0;
@@ -1673,8 +1691,15 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
if (ot->flag & OPTYPE_UNDO)
wm->op_undo_depth--;
- if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED))
+ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
wm_operator_reports(C, op, retval, false);
+ }
+ else {
+ /* not very common, but modal operators may report before finishing */
+ if (!BLI_listbase_is_empty(&op->reports->list)) {
+ wm_add_reports(op->reports);
+ }
+ }
/* important to run 'wm_operator_finished' before NULLing the context members */
if (retval & OPERATOR_FINISHED) {
@@ -1767,9 +1792,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
if (sa->prev) {
sa = sa->prev;
}
- ED_area_newspace(C, sa, SPACE_FILE); /* 'sa' is modified in-place */
+ ED_area_newspace(C, sa, SPACE_FILE, true); /* 'sa' is modified in-place */
/* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ }
+ else if (sa->spacetype == SPACE_FILE) {
+ sa = ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
}
else {
sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
@@ -1798,11 +1826,9 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
ScrArea *sa = CTX_wm_area(C);
- const SpaceLink *sl = sa->spacedata.first;
- const bool was_prev_temp = (sl->next && sl->next->spacetype == SPACE_IMAGE);
if (sa->full) {
- ED_screen_full_prevspace(C, sa, was_prev_temp);
+ ED_screen_full_prevspace(C, sa);
}
/* user may have left fullscreen */
else {
@@ -1850,6 +1876,9 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
/* add reports to the global list, otherwise they are not seen */
BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
+ /* more hacks, since we meddle with reports, banner display doesn't happen automatic */
+ WM_report_banner_show();
+
CTX_wm_window_set(C, win_prev);
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, ar_prev);
@@ -1862,7 +1891,9 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
WM_operator_last_properties_store(handler->op);
}
- WM_operator_free(handler->op);
+ if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
+ WM_operator_free(handler->op);
+ }
}
else {
if (handler->op->type->cancel) {
@@ -1890,7 +1921,7 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
return action;
}
-static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
+static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, const wmEvent *event)
{
int action = WM_HANDLER_CONTINUE;
@@ -1902,7 +1933,7 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
return wm_handler_fileselect_do(C, handlers, handler, event->val);
}
-static bool handler_boundbox_test(wmEventHandler *handler, wmEvent *event)
+static bool handler_boundbox_test(wmEventHandler *handler, const wmEvent *event)
{
if (handler->bbwin) {
if (handler->bblocal) {
@@ -2214,7 +2245,7 @@ static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *ar)
/* called on mousemove, check updates for paintcursors */
/* context was set on active area and region */
-static void wm_paintcursor_test(bContext *C, wmEvent *event)
+static void wm_paintcursor_test(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -2281,7 +2312,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
}
/* filter out all events of the pie that spawned the last pie unless it's a release event */
-static bool wm_event_pie_filter(wmWindow *win, wmEvent *event)
+static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
{
if (win->lock_pie_event && win->lock_pie_event == event->type) {
if (event->val == KM_RELEASE) {
@@ -3093,7 +3124,7 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
return NULL;
}
-static bool wm_event_is_double_click(wmEvent *event, wmEvent *event_state)
+static bool wm_event_is_double_click(wmEvent *event, const wmEvent *event_state)
{
if ((event->type == event_state->prevtype) &&
(event_state->prevval == KM_RELEASE) &&
@@ -3380,11 +3411,12 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
if (event.keymodifier == event.type)
event.keymodifier = 0;
- /* this case happened with an external numpad, it's not really clear
- * why, but it's also impossible to map a key modifier to an unknown
- * key, so it shouldn't harm */
- if (event.keymodifier == UNKNOWNKEY)
- event.keymodifier = 0;
+ /* this case happens with an external numpad, and also when using 'dead keys' (to compose complex latin
+ * characters e.g.), it's not really clear why.
+ * Since it's impossible to map a key modifier to an unknown key, it shouldn't harm to clear it. */
+ if (event.keymodifier == UNKNOWNKEY) {
+ evt->keymodifier = event.keymodifier = 0;
+ }
/* if test_break set, it catches this. Do not set with modifier presses. XXX Keep global for now? */
if ((event.type == ESCKEY && event.val == KM_PRESS) &&
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 6927e2dbc14..498a3f5bdda 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -26,7 +26,7 @@
/** \file blender/windowmanager/intern/wm_files.c
* \ingroup wm
*
- * User level access for blend file read/write, file-history and userprefs.
+ * User level access for blend file read/write, file-history and userprefs (including relevant operators).
*/
@@ -62,6 +62,7 @@
#include "BLT_translation.h"
+#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
@@ -81,12 +82,14 @@
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -102,10 +105,14 @@
#include "GHOST_Path-api.h"
#include "UI_interface.h"
+#include "UI_resources.h"
#include "UI_view2d.h"
#include "GPU_draw.h"
+/* only to report a missing engine */
+#include "RE_engine.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -157,6 +164,13 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
/* reset active window */
CTX_wm_window_set(C, active_win);
+ /* XXX Hack! We have to clear context menu here, because removing all modalhandlers above frees the active menu
+ * (at least, in the 'startup splash' case), causing use-after-free error in later handling of the button
+ * callbacks in UI code (see ui_apply_but_funcs_after()).
+ * Tried solving this by always NULL-ing context's menu when setting wm/win/etc., but it broke popups refreshing
+ * (see T47632), so for now just handling this specific case here. */
+ CTX_wm_menu_set(C, NULL);
+
ED_editors_exit(C);
/* just had return; here from r12991, this code could just get removed?*/
@@ -178,6 +192,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
{
win->ghostwin = oldwin->ghostwin;
+ win->multisamples = oldwin->multisamples;
win->active = oldwin->active;
if (win->active)
wm->winactive = win;
@@ -186,6 +201,7 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
oldwin->ghostwin = NULL;
+ oldwin->multisamples = 0;
win->eventstate = oldwin->eventstate;
oldwin->eventstate = NULL;
@@ -335,11 +351,13 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
#define BKE_READ_EXOTIC_FAIL_FORMAT -2 /* file format is not supported */
#define BKE_READ_EXOTIC_FAIL_OPEN -1 /* Can't open the file */
#define BKE_READ_EXOTIC_OK_BLEND 0 /* .blend file */
+#if 0
#define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */
+#endif
/* intended to check for non-blender formats but for now it only reads blends */
-static int wm_read_exotic(Scene *UNUSED(scene), const char *name)
+static int wm_read_exotic(const char *name)
{
int len;
gzFile gzfile;
@@ -401,6 +419,106 @@ void WM_file_autoexec_init(const char *filepath)
}
}
+void wm_file_read_report(bContext *C)
+{
+ ReportList *reports = NULL;
+ Scene *sce;
+
+ for (sce = G.main->scene.first; sce; sce = sce->id.next) {
+ if (sce->r.engine[0] &&
+ BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
+ {
+ if (reports == NULL) {
+ reports = CTX_wm_reports(C);
+ }
+
+ BKE_reportf(reports, RPT_ERROR,
+ "Engine '%s' not available for scene '%s' "
+ "(an addon may need to be installed or enabled)",
+ sce->r.engine, sce->id.name + 2);
+ }
+ }
+
+ if (reports) {
+ if (!G.background) {
+ WM_report_banner_show();
+ }
+ }
+}
+
+/**
+ * Logic shared between #WM_file_read & #wm_homefile_read,
+ * updates to make after reading a file.
+ */
+static void wm_file_read_post(bContext *C, bool is_startup_file)
+{
+ bool addons_loaded = false;
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ if (!G.background) {
+ /* remove windows which failed to be added via WM_check */
+ wm_window_ghostwindows_remove_invalid(C, wm);
+ }
+
+ CTX_wm_window_set(C, wm->windows.first);
+
+ ED_editors_init(C);
+ DAG_on_visible_update(CTX_data_main(C), true);
+
+#ifdef WITH_PYTHON
+ if (is_startup_file) {
+ /* possible python hasn't been initialized */
+ if (CTX_py_init_get(C)) {
+ /* sync addons, these may have changed from the defaults */
+ BPY_execute_string(C, "__import__('addon_utils').reset_all()");
+
+ BPY_python_reset(C);
+ addons_loaded = true;
+ }
+ }
+ else {
+ /* run any texts that were loaded in and flagged as modules */
+ BPY_python_reset(C);
+ addons_loaded = true;
+ }
+#else
+ UNUSED_VARS(is_startup_file);
+#endif /* WITH_PYTHON */
+
+ WM_operatortype_last_properties_clear_all();
+
+ /* important to do before NULL'ing the context */
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
+
+ /* would otherwise be handled by event loop */
+ if (G.background) {
+ Main *bmain = CTX_data_main(C);
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
+ }
+
+ WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+
+ /* report any errors.
+ * currently disabled if addons aren't yet loaded */
+ if (addons_loaded) {
+ wm_file_read_report(C);
+ }
+
+ if (!G.background) {
+ /* in background mode this makes it hard to load
+ * a blend file and do anything since the screen
+ * won't be set to a valid value again */
+ CTX_wm_window_set(C, NULL); /* exits queues */
+ }
+
+ if (!G.background) {
+// undo_editmode_clear();
+ BKE_undo_reset();
+ BKE_undo_write(C, "original"); /* save current state */
+ }
+}
+
bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
{
/* assume automated tasks with background, don't write recent file list */
@@ -420,7 +538,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* first try to append data from exotic file formats... */
/* it throws error box when file doesn't exist and returns -1 */
/* note; it should set some error message somewhere... (ton) */
- retval = wm_read_exotic(CTX_data_scene(C), filepath);
+ retval = wm_read_exotic(filepath);
/* we didn't succeed, now try to read Blender file */
if (retval == BKE_READ_EXOTIC_OK_BLEND) {
@@ -465,58 +583,14 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
-
- WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
-// refresh_interface_font();
-
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
-
- ED_editors_init(C);
- DAG_on_visible_update(CTX_data_main(C), true);
-
-#ifdef WITH_PYTHON
- /* run any texts that were loaded in and flagged as modules */
- BPY_python_reset(C);
-#endif
-
- WM_operatortype_last_properties_clear_all();
-
- /* important to do before NULL'ing the context */
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
-
- if (!G.background) {
- /* in background mode this makes it hard to load
- * a blend file and do anything since the screen
- * won't be set to a valid value again */
- CTX_wm_window_set(C, NULL); /* exits queues */
- }
-
-#if 0
- /* gives popups on windows but not linux, bug in report API
- * but disable for now to stop users getting annoyed */
- /* TODO, make this show in header info window */
- {
- Scene *sce;
- for (sce = G.main->scene.first; sce; sce = sce->id.next) {
- if (sce->r.engine[0] &&
- BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
- {
- BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' "
- "(an addon may need to be installed or enabled)",
- sce->r.engine, sce->id.name + 2);
- }
- }
- }
-#endif
-
- BKE_undo_reset();
- BKE_undo_write(C, "original"); /* save current state */
+ wm_file_read_post(C, false);
success = true;
}
+#if 0
else if (retval == BKE_READ_EXOTIC_OK_OTHER)
BKE_undo_write(C, "Import file");
+#endif
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -673,74 +747,11 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
G.save_over = 0; // start with save preference untitled.blend
G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
-// refresh_interface_font();
-
-// undo_editmode_clear();
- BKE_undo_reset();
- BKE_undo_write(C, "original"); /* save current state */
-
- ED_editors_init(C);
- DAG_on_visible_update(CTX_data_main(C), true);
-
-#ifdef WITH_PYTHON
- if (CTX_py_init_get(C)) {
- /* sync addons, these may have changed from the defaults */
- BPY_string_exec(C, "__import__('addon_utils').reset_all()");
-
- BPY_python_reset(C);
- }
-#endif
-
- WM_operatortype_last_properties_clear_all();
-
- /* important to do before NULL'ing the context */
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
-
- WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
-
- /* in background mode the scene will stay NULL */
- if (!G.background) {
- CTX_wm_window_set(C, NULL); /* exits queues */
- }
+ wm_file_read_post(C, true);
return true;
}
-int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
-{
- ED_file_read_bookmarks();
- wm_history_file_read();
- return OPERATOR_FINISHED;
-}
-
-int wm_homefile_read_exec(bContext *C, wmOperator *op)
-{
- const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
- char filepath_buf[FILE_MAX];
- const char *filepath = NULL;
-
- if (!from_memory) {
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
-
- /* This can be used when loading of a start-up file should only change
- * the scene content but keep the blender UI as it is. */
- wm_open_init_load_ui(op, true);
- BKE_BIT_TEST_SET(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
-
- if (RNA_property_is_set(op->ptr, prop)) {
- RNA_property_string_get(op->ptr, prop, filepath_buf);
- filepath = filepath_buf;
- if (BLI_access(filepath, R_OK)) {
- BKE_reportf(op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
- return OPERATOR_CANCELLED;
- }
- }
- }
-
- return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
/** \name WM History File API
* \{ */
@@ -901,13 +912,18 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **t
/* gets scaled to BLEN_THUMB_SIZE */
if (scene->camera) {
- ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
- BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, NULL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf_simple(
+ scene, scene->camera,
+ BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
+ IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, false, NULL,
+ NULL, NULL, err_out);
}
else {
- ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf(
+ scene, v3d, ar,
+ BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
+ IB_rect, false, R_ALPHAPREMUL, 0, false, NULL,
+ NULL, NULL, err_out);
}
if (ibuf) {
@@ -954,7 +970,7 @@ bool write_crash_blend(void)
/**
* \see #wm_homefile_write_exec wraps #BLO_write_file in a similar way.
*/
-int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
+static int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *reports)
{
Library *li;
int len;
@@ -1026,6 +1042,8 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
G.main->recovered = 0;
if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) {
+ const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0);
+
if (!(fileflags & G_FILE_SAVE_COPY)) {
G.relbase_valid = 1;
BLI_strncpy(G.main->name, filepath, sizeof(G.main->name)); /* is guaranteed current file */
@@ -1037,7 +1055,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
BKE_BIT_TEST_SET(G.fileflags, fileflags & G_FILE_AUTOPLAY, G_FILE_AUTOPLAY);
/* prevent background mode scripts from clobbering history */
- if (!G.background) {
+ if (do_history) {
wm_history_file_update();
}
@@ -1064,69 +1082,6 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
return ret;
}
-/**
- * \see #wm_file_write wraps #BLO_write_file in a similar way.
- */
-int wm_homefile_write_exec(bContext *C, wmOperator *op)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- char filepath[FILE_MAX];
- int fileflags;
-
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
-
- /* check current window and close it if temp */
- if (win && win->screen->temp)
- wm_window_close(C, wm, win);
-
- /* update keymaps in user preferences */
- WM_keyconfig_update(wm);
-
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
- printf("trying to save homefile at %s ", filepath);
-
- ED_editors_flush_edits(C, false);
-
- /* force save as regular blend file */
- fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
-
- if (BLO_write_file(CTX_data_main(C), filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
- }
-
- printf("ok\n");
-
- G.save_over = 0;
-
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
-
- return OPERATOR_FINISHED;
-}
-
-/* Only save the prefs block. operator entry */
-int wm_userpref_write_exec(bContext *C, wmOperator *op)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- char filepath[FILE_MAX];
-
- /* update keymaps in user preferences */
- WM_keyconfig_update(wm);
-
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
- printf("trying to save userpref at %s ", filepath);
-
- if (BKE_write_file_userdef(filepath, op->reports) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
- }
-
- printf("ok\n");
-
- return OPERATOR_FINISHED;
-}
-
/************************ autosave ****************************/
void wm_autosave_location(char *filepath)
@@ -1278,3 +1233,738 @@ void wm_open_init_use_scripts(wmOperator *op, bool use_prefs)
}
/** \} */
+
+void WM_file_tag_modified(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->file_saved) {
+ wm->file_saved = 0;
+ /* notifier that data changed, for save-over warning or header */
+ WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL);
+ }
+}
+
+/** \name Preferences/startup save & load.
+ *
+ * \{ */
+
+/**
+ * \see #wm_file_write wraps #BLO_write_file in a similar way.
+ */
+static int wm_homefile_write_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ char filepath[FILE_MAX];
+ int fileflags;
+
+ BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
+
+ /* check current window and close it if temp */
+ if (win && win->screen->temp)
+ wm_window_close(C, wm, win);
+
+ /* update keymaps in user preferences */
+ WM_keyconfig_update(wm);
+
+ BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+ printf("trying to save homefile at %s ", filepath);
+
+ ED_editors_flush_edits(C, false);
+
+ /* force save as regular blend file */
+ fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+
+ if (BLO_write_file(CTX_data_main(C), filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
+ printf("fail\n");
+ return OPERATOR_CANCELLED;
+ }
+
+ printf("ok\n");
+
+ G.save_over = 0;
+
+ BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_save_homefile(wmOperatorType *ot)
+{
+ ot->name = "Save Startup File";
+ ot->idname = "WM_OT_save_homefile";
+ ot->description = "Make the current file the default .blend file, includes preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_homefile_write_exec;
+}
+
+static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
+ BLI_addtail(&U.autoexec_paths, path_cmp);
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
+{
+ ot->name = "Add Autoexec Path";
+ ot->idname = "WM_OT_userpref_autoexec_path_add";
+ ot->description = "Add path to exclude from autoexecution";
+
+ ot->exec = wm_userpref_autoexec_add_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
+{
+ const int index = RNA_int_get(op->ptr, "index");
+ bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
+ if (path_cmp) {
+ BLI_freelinkN(&U.autoexec_paths, path_cmp);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Autoexec Path";
+ ot->idname = "WM_OT_userpref_autoexec_path_remove";
+ ot->description = "Remove path to exclude from autoexecution";
+
+ ot->exec = wm_userpref_autoexec_remove_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
+}
+
+/* Only save the prefs block. operator entry */
+static int wm_userpref_write_exec(bContext *C, wmOperator *op)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ char filepath[FILE_MAX];
+
+ /* update keymaps in user preferences */
+ WM_keyconfig_update(wm);
+
+ BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
+ printf("trying to save userpref at %s ", filepath);
+
+ if (BKE_write_file_userdef(filepath, op->reports) == 0) {
+ printf("fail\n");
+ return OPERATOR_CANCELLED;
+ }
+
+ printf("ok\n");
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_save_userpref(wmOperatorType *ot)
+{
+ ot->name = "Save User Settings";
+ ot->idname = "WM_OT_save_userpref";
+ ot->description = "Save user preferences separately, overrides startup file preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_userpref_write_exec;
+}
+
+static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ ED_file_read_bookmarks();
+ wm_history_file_read();
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_read_history(wmOperatorType *ot)
+{
+ ot->name = "Reload History File";
+ ot->idname = "WM_OT_read_history";
+ ot->description = "Reloads history and bookmarks";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_history_file_read_exec;
+
+ /* this operator is only used for loading settings from a previous blender install */
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+static int wm_homefile_read_exec(bContext *C, wmOperator *op)
+{
+ const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ char filepath_buf[FILE_MAX];
+ const char *filepath = NULL;
+
+ if (!from_memory) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
+
+ /* This can be used when loading of a start-up file should only change
+ * the scene content but keep the blender UI as it is. */
+ wm_open_init_load_ui(op, true);
+ BKE_BIT_TEST_SET(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI);
+
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_string_get(op->ptr, prop, filepath_buf);
+ filepath = filepath_buf;
+ if (BLI_access(filepath, R_OK)) {
+ BKE_reportf(op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ else {
+ /* always load UI for factory settings (prefs will re-init) */
+ G.fileflags &= ~G_FILE_NO_UI;
+ }
+
+ return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void WM_OT_read_homefile(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ ot->name = "Reload Start-Up File";
+ ot->idname = "WM_OT_read_homefile";
+ ot->description = "Open the default file (doesn't save the current file)";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_homefile_read_exec;
+
+ prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
+ FILE_MAX, "File Path",
+ "Path to an alternative start-up file");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* So scripts can use an alternative start-up file without the UI */
+ prop = RNA_def_boolean(ot->srna, "load_ui", true, "Load UI",
+ "Load user interface setup from the .blend file");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* omit poll to run in background mode */
+}
+
+void WM_OT_read_factory_settings(wmOperatorType *ot)
+{
+ ot->name = "Load Factory Settings";
+ ot->idname = "WM_OT_read_factory_settings";
+ ot->description = "Load default file and user preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_homefile_read_exec;
+ /* omit poll to run in background mode */
+}
+
+/** \} */
+
+/** \name Open main .blend file.
+ *
+ * \{ */
+
+/**
+ * Wrap #WM_file_read, shared by file reading operators.
+ */
+static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports,
+ const bool autoexec_init)
+{
+ bool success;
+
+ /* XXX wm in context is not set correctly after WM_file_read -> crash */
+ /* do it before for now, but is this correct with multiple windows? */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ if (autoexec_init) {
+ WM_file_autoexec_init(filepath);
+ }
+
+ success = WM_file_read(C, filepath, reports);
+
+ return success;
+}
+
+/* currently fits in a pointer */
+struct FileRuntime {
+ bool is_untrusted;
+};
+
+static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const char *openname = G.main->name;
+
+ if (CTX_wm_window(C) == NULL) {
+ /* in rare cases this could happen, when trying to invoke in background
+ * mode on load for example. Don't use poll for this because exec()
+ * can still run without a window */
+ BKE_report(op->reports, RPT_ERROR, "Context window not set");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if possible, get the name of the most recently used .blend file */
+ if (G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ openname = recent->filepath;
+ }
+
+ RNA_string_set(op->ptr, "filepath", openname);
+ wm_open_init_load_ui(op, true);
+ wm_open_init_use_scripts(op, true);
+ op->customdata = NULL;
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ bool success;
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ /* re-use last loaded setting so we can reload a file without changing */
+ wm_open_init_load_ui(op, false);
+ wm_open_init_use_scripts(op, false);
+
+ if (RNA_boolean_get(op->ptr, "load_ui"))
+ G.fileflags &= ~G_FILE_NO_UI;
+ else
+ G.fileflags |= G_FILE_NO_UI;
+
+ if (RNA_boolean_get(op->ptr, "use_scripts"))
+ G.f |= G_SCRIPT_AUTOEXEC;
+ else
+ G.f &= ~G_SCRIPT_AUTOEXEC;
+
+ success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
+
+ /* for file open also popup for warnings, not only errors */
+ BKE_report_print_level_set(op->reports, RPT_WARNING);
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
+{
+ struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
+ bool is_untrusted = false;
+ char path[FILE_MAX];
+ char *lslash;
+
+ RNA_string_get(op->ptr, "filepath", path);
+
+ /* get the dir */
+ lslash = (char *)BLI_last_slash(path);
+ if (lslash) *(lslash + 1) = '\0';
+
+ if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
+ if (BKE_autoexec_match(path) == true) {
+ RNA_property_boolean_set(op->ptr, prop, false);
+ is_untrusted = true;
+ }
+ }
+
+ if (file_info) {
+ file_info->is_untrusted = is_untrusted;
+ }
+
+ return is_untrusted;
+}
+
+static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
+ uiLayout *layout = op->layout;
+ uiLayout *col = op->layout;
+ const char *autoexec_text;
+
+ uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
+
+ col = uiLayoutColumn(layout, false);
+ if (file_info->is_untrusted) {
+ autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
+ uiLayoutSetActive(col, false);
+ uiLayoutSetEnabled(col, false);
+ }
+ else {
+ autoexec_text = IFACE_("Trusted Source");
+ }
+
+ uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
+}
+
+void WM_OT_open_mainfile(wmOperatorType *ot)
+{
+ ot->name = "Open Blender File";
+ ot->idname = "WM_OT_open_mainfile";
+ ot->description = "Open a Blender file";
+
+ ot->invoke = wm_open_mainfile_invoke;
+ ot->exec = wm_open_mainfile_exec;
+ ot->check = wm_open_mainfile_check;
+ ot->ui = wm_open_mainfile_ui;
+ /* omit window poll so this can work in background mode */
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
+ RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
+ "Allow .blend file to execute scripts automatically, default available from system preferences");
+}
+
+/** \} */
+
+/** \name Reload (revert) main .blend file.
+ *
+ * \{ */
+
+static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
+{
+ bool success;
+
+ wm_open_init_use_scripts(op, false);
+
+ if (RNA_boolean_get(op->ptr, "use_scripts"))
+ G.f |= G_SCRIPT_AUTOEXEC;
+ else
+ G.f &= ~G_SCRIPT_AUTOEXEC;
+
+ success = wm_file_read_opwrap(C, G.main->name, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int wm_revert_mainfile_poll(bContext *UNUSED(C))
+{
+ return G.relbase_valid;
+}
+
+void WM_OT_revert_mainfile(wmOperatorType *ot)
+{
+ ot->name = "Revert";
+ ot->idname = "WM_OT_revert_mainfile";
+ ot->description = "Reload the saved file";
+ ot->invoke = WM_operator_confirm;
+
+ RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
+ "Allow .blend file to execute scripts automatically, default available from system preferences");
+
+ ot->exec = wm_revert_mainfile_exec;
+ ot->poll = wm_revert_mainfile_poll;
+}
+
+/** \} */
+
+/** \name Recover last session & auto-save.
+ *
+ * \{ */
+
+void WM_recover_last_session(bContext *C, ReportList *reports)
+{
+ char filepath[FILE_MAX];
+
+ BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE);
+ /* if reports==NULL, it's called directly without operator, we add a quick check here */
+ if (reports || BLI_exists(filepath)) {
+ G.fileflags |= G_FILE_RECOVER;
+
+ wm_file_read_opwrap(C, filepath, reports, true);
+
+ G.fileflags &= ~G_FILE_RECOVER;
+
+ /* XXX bad global... fixme */
+ if (G.main->name[0])
+ G.file_loaded = 1; /* prevents splash to show */
+ else {
+ G.relbase_valid = 0;
+ G.save_over = 0; /* start with save preference untitled.blend */
+ }
+
+ }
+}
+
+static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
+{
+ WM_recover_last_session(C, op->reports);
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_recover_last_session(wmOperatorType *ot)
+{
+ ot->name = "Recover Last Session";
+ ot->idname = "WM_OT_recover_last_session";
+ ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
+ ot->invoke = WM_operator_confirm;
+
+ ot->exec = wm_recover_last_session_exec;
+}
+
+static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ bool success;
+
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ G.fileflags |= G_FILE_RECOVER;
+
+ success = wm_file_read_opwrap(C, filepath, op->reports, true);
+
+ G.fileflags &= ~G_FILE_RECOVER;
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ char filename[FILE_MAX];
+
+ wm_autosave_location(filename);
+ RNA_string_set(op->ptr, "filepath", filename);
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void WM_OT_recover_auto_save(wmOperatorType *ot)
+{
+ ot->name = "Recover Auto Save";
+ ot->idname = "WM_OT_recover_auto_save";
+ ot->description = "Open an automatically saved file to recover it";
+
+ ot->exec = wm_recover_auto_save_exec;
+ ot->invoke = wm_recover_auto_save_invoke;
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH, FILE_LONGDISPLAY, FILE_SORT_TIME);
+}
+
+/** \} */
+
+/** \name Save main .blend file.
+ *
+ * \{ */
+
+static void wm_filepath_default(char *filepath)
+{
+ if (G.save_over == false) {
+ BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend");
+ }
+}
+
+static void save_set_compress(wmOperator *op)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_struct_find_property(op->ptr, "compress");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ if (G.save_over) { /* keep flag for existing file */
+ RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
+ }
+ else { /* use userdef for new file */
+ RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
+ }
+ }
+}
+
+static void save_set_filepath(wmOperator *op)
+{
+ PropertyRNA *prop;
+ char name[FILE_MAX];
+
+ prop = RNA_struct_find_property(op->ptr, "filepath");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ /* if not saved before, get the name of the most recently used .blend file */
+ if (G.main->name[0] == 0 && G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ BLI_strncpy(name, recent->filepath, FILE_MAX);
+ }
+ else {
+ BLI_strncpy(name, G.main->name, FILE_MAX);
+ }
+
+ wm_filepath_default(name);
+ RNA_property_string_set(op->ptr, prop, name);
+ }
+}
+
+static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+
+ save_set_compress(op);
+ save_set_filepath(op);
+
+ WM_event_add_fileselect(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* function used for WM_OT_save_mainfile too */
+static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
+{
+ char path[FILE_MAX];
+ int fileflags;
+
+ save_set_compress(op);
+
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ RNA_string_get(op->ptr, "filepath", path);
+ }
+ else {
+ BLI_strncpy(path, G.main->name, FILE_MAX);
+ wm_filepath_default(path);
+ }
+
+ fileflags = G.fileflags & ~G_FILE_USERPREFS;
+
+ /* set compression flag */
+ BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "compress"),
+ G_FILE_COMPRESS);
+ BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "relative_remap"),
+ G_FILE_RELATIVE_REMAP);
+ BKE_BIT_TEST_SET(fileflags,
+ (RNA_struct_property_is_set(op->ptr, "copy") &&
+ RNA_boolean_get(op->ptr, "copy")),
+ G_FILE_SAVE_COPY);
+
+#ifdef USE_BMESH_SAVE_AS_COMPAT
+ BKE_BIT_TEST_SET(fileflags,
+ (RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
+ RNA_boolean_get(op->ptr, "use_mesh_compat")),
+ G_FILE_MESH_COMPAT);
+#else
+# error "don't remove by accident"
+#endif
+
+ if (wm_file_write(C, path, fileflags, op->reports) != 0)
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/* function used for WM_OT_save_mainfile too */
+static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+ if (!BLO_has_bfile_extension(filepath)) {
+ /* some users would prefer BLI_replace_extension(),
+ * we keep getting nitpicking bug reports about this - campbell */
+ BLI_ensure_extension(filepath, FILE_MAX, ".blend");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ return true;
+ }
+ return false;
+}
+
+void WM_OT_save_as_mainfile(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Save As Blender File";
+ ot->idname = "WM_OT_save_as_mainfile";
+ ot->description = "Save the current file in the desired location";
+
+ ot->invoke = wm_save_as_mainfile_invoke;
+ ot->exec = wm_save_as_mainfile_exec;
+ ot->check = blend_save_check;
+ /* omit window poll so this can work in background mode */
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
+ RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative",
+ "Remap relative paths when saving in a different directory");
+ prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy",
+ "Save a copy of the actual working state but does not make saved file active");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+#ifdef USE_BMESH_SAVE_AS_COMPAT
+ RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format",
+ "Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
+ "be lost (no implicit triangulation)");
+#endif
+}
+
+static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ int ret;
+
+ /* cancel if no active window */
+ if (CTX_wm_window(C) == NULL)
+ return OPERATOR_CANCELLED;
+
+ save_set_compress(op);
+ save_set_filepath(op);
+
+ /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
+ * enable the option to remap paths to avoid confusion [#37240] */
+ if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(op->ptr, prop, true);
+ }
+ }
+
+ if (G.save_over) {
+ char path[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", path);
+ if (BLI_exists(path)) {
+ ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
+ }
+ else {
+ ret = wm_save_as_mainfile_exec(C, op);
+ }
+ }
+ else {
+ WM_event_add_fileselect(C, op);
+ ret = OPERATOR_RUNNING_MODAL;
+ }
+
+ return ret;
+}
+
+void WM_OT_save_mainfile(wmOperatorType *ot)
+{
+ ot->name = "Save Blender File";
+ ot->idname = "WM_OT_save_mainfile";
+ ot->description = "Save the current Blender file";
+
+ ot->invoke = wm_save_mainfile_invoke;
+ ot->exec = wm_save_as_mainfile_exec;
+ ot->check = blend_save_check;
+ /* omit window poll so this can work in background mode */
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+ RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
+ RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
+ "Remap relative paths when saving in a different directory");
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
new file mode 100644
index 00000000000..5041eebd126
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -0,0 +1,497 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_files_link.c
+ * \ingroup wm
+ *
+ * Functions for dealing with append/link operators and helpers.
+ */
+
+
+#include <float.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+
+
+
+#include "BLI_blenlib.h"
+#include "BLI_bitmap.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BLO_readfile.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "BKE_idcode.h"
+
+
+#include "IMB_colormanagement.h"
+
+#include "ED_screen.h"
+
+#include "GPU_material.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_files.h"
+
+/* **************** link/append *************** */
+
+static int wm_link_append_poll(bContext *C)
+{
+ if (WM_operator_winactive(C)) {
+ /* linking changes active object which is pretty useful in general,
+ * but which totally confuses edit mode (i.e. it becoming not so obvious
+ * to leave from edit mode and invalid tools in toolbar might be displayed)
+ * so disable link/append when in edit mode (sergey) */
+ if (CTX_data_edit_object(C))
+ return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ return WM_operator_call_notest(C, op);
+ }
+ else {
+ /* XXX TODO solve where to get last linked library from */
+ if (G.lib[0] != '\0') {
+ RNA_string_set(op->ptr, "filepath", G.lib);
+ }
+ else if (G.relbase_valid) {
+ char path[FILE_MAX];
+ BLI_strncpy(path, G.main->name, sizeof(G.main->name));
+ BLI_parent_dir(path);
+ RNA_string_set(op->ptr, "filepath", path);
+ }
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+ }
+}
+
+static short wm_link_append_flag(wmOperator *op)
+{
+ PropertyRNA *prop;
+ short flag = 0;
+
+ if (RNA_boolean_get(op->ptr, "autoselect"))
+ flag |= FILE_AUTOSELECT;
+ if (RNA_boolean_get(op->ptr, "active_layer"))
+ flag |= FILE_ACTIVELAY;
+ if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
+ flag |= FILE_RELPATH;
+ if (RNA_boolean_get(op->ptr, "link"))
+ flag |= FILE_LINK;
+ if (RNA_boolean_get(op->ptr, "instance_groups"))
+ flag |= FILE_GROUP_INSTANCE;
+
+ return flag;
+}
+
+typedef struct WMLinkAppendDataItem {
+ char *name;
+ BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
+ short idcode;
+
+ ID *new_id;
+ void *customdata;
+} WMLinkAppendDataItem;
+
+typedef struct WMLinkAppendData {
+ LinkNodePair libraries;
+ LinkNodePair items;
+ int num_libraries;
+ int num_items;
+ short flag;
+
+ /* Internal 'private' data */
+ MemArena *memarena;
+} WMLinkAppendData;
+
+static WMLinkAppendData *wm_link_append_data_new(const int flag)
+{
+ MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
+
+ lapp_data->flag = flag;
+ lapp_data->memarena = ma;
+
+ return lapp_data;
+}
+
+static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
+{
+ BLI_memarena_free(lapp_data->memarena);
+}
+
+/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
+
+static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
+{
+ size_t len = strlen(libname) + 1;
+ char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
+
+ BLI_strncpy(libpath, libname, len);
+ BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
+ lapp_data->num_libraries++;
+}
+
+static WMLinkAppendDataItem *wm_link_append_data_item_add(
+ WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata)
+{
+ WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
+ size_t len = strlen(idname) + 1;
+
+ item->name = BLI_memarena_alloc(lapp_data->memarena, len);
+ BLI_strncpy(item->name, idname, len);
+ item->idcode = idcode;
+ item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
+
+ item->new_id = NULL;
+ item->customdata = customdata;
+
+ BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
+ lapp_data->num_items++;
+
+ return item;
+}
+
+static void wm_link_do(
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+{
+ Main *mainl;
+ BlendHandle *bh;
+ Library *lib;
+
+ const int flag = lapp_data->flag;
+
+ LinkNode *liblink, *itemlink;
+ int lib_idx, item_idx;
+
+ BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
+
+ for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
+ char *libname = liblink->link;
+
+ bh = BLO_blendhandle_from_file(libname, reports);
+
+ if (bh == NULL) {
+ /* Unlikely since we just browsed it, but possible
+ * Error reports will have been made by BLO_blendhandle_from_file() */
+ continue;
+ }
+
+ /* here appending/linking starts */
+ mainl = BLO_library_link_begin(bmain, &bh, libname);
+ lib = mainl->curlib;
+ BLI_assert(lib);
+ UNUSED_VARS_NDEBUG(lib);
+
+ if (mainl->versionfile < 250) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
+ "be done! You may want to re-save your lib file with current Blender",
+ mainl->versionfile, mainl->subversionfile);
+ }
+
+ /* For each lib file, we try to link all items belonging to that lib,
+ * and tag those successful to not try to load them again with the other libs. */
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *new_id;
+
+ if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
+ continue;
+ }
+
+ new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ if (new_id) {
+ /* If the link is sucessful, clear item's libs 'todo' flags.
+ * This avoids trying to link same item with other libraries to come. */
+ BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
+ item->new_id = new_id;
+ }
+ }
+
+ BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_blendhandle_close(bh);
+ }
+}
+
+static int wm_link_append_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ PropertyRNA *prop;
+ WMLinkAppendData *lapp_data;
+ char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ char *group, *name;
+ int totfiles = 0;
+ short flag;
+
+ RNA_string_get(op->ptr, "filename", relname);
+ RNA_string_get(op->ptr, "directory", root);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ /* test if we have a valid data */
+ if (!BLO_library_path_explode(path, libname, &group, &name)) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
+ return OPERATOR_CANCELLED;
+ }
+ else if (!group) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
+ return OPERATOR_CANCELLED;
+ }
+ else if (BLI_path_cmp(bmain->name, libname) == 0) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* check if something is indicated for append/link */
+ prop = RNA_struct_find_property(op->ptr, "files");
+ if (prop) {
+ totfiles = RNA_property_collection_length(op->ptr, prop);
+ if (totfiles == 0) {
+ if (!name) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ else if (!name) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
+ return OPERATOR_CANCELLED;
+ }
+
+ flag = wm_link_append_flag(op);
+
+ /* sanity checks for flag */
+ if (scene && scene->id.lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Scene '%s' is linked, instantiation of objects & groups is disabled", scene->id.name + 2);
+ flag &= ~FILE_GROUP_INSTANCE;
+ scene = NULL;
+ }
+
+ /* from here down, no error returns */
+
+ if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
+ BKE_scene_base_deselect_all(scene);
+ }
+
+ /* tag everything, all untagged data can be made local
+ * its also generally useful to know what is new
+ *
+ * take extra care BKE_main_id_flag_all(bmain, LIB_TAG_PRE_EXISTING, false) is called after! */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
+
+ /* We define our working data...
+ * Note that here, each item 'uses' one library, and only one. */
+ lapp_data = wm_link_append_data_new(flag);
+ if (totfiles != 0) {
+ GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
+ int lib_idx = 0;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLO_library_path_explode(path, libname, &group, &name)) {
+ if (!group || !name) {
+ continue;
+ }
+
+ if (!BLI_ghash_haskey(libraries, libname)) {
+ BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
+ lib_idx++;
+ wm_link_append_data_library_add(lapp_data, libname);
+ }
+ }
+ }
+ RNA_END;
+
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLO_library_path_explode(path, libname, &group, &name)) {
+ WMLinkAppendDataItem *item;
+ if (!group || !name) {
+ printf("skipping %s\n", path);
+ continue;
+ }
+
+ lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname));
+
+ item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
+ BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ }
+ }
+ RNA_END;
+
+ BLI_ghash_free(libraries, MEM_freeN, NULL);
+ }
+ else {
+ WMLinkAppendDataItem *item;
+
+ wm_link_append_data_library_add(lapp_data, libname);
+ item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
+ BLI_BITMAP_ENABLE(item->libraries, 0);
+ }
+
+ /* XXX We'd need re-entrant locking on Main for this to work... */
+ /* BKE_main_lock(bmain); */
+
+ wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+
+ /* BKE_main_unlock(bmain); */
+
+ wm_link_append_data_free(lapp_data);
+
+ /* mark all library linked objects to be updated */
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* append, rather than linking */
+ if ((flag & FILE_LINK) == 0) {
+ bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
+ BKE_library_make_local(bmain, NULL, true, set_fake);
+ }
+
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+
+ /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
+ BLI_strncpy(G.lib, root, FILE_MAX);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
+{
+ PropertyRNA *prop;
+
+ /* better not save _any_ settings for this operator */
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "link", is_link,
+ "Link", "Link the objects or datablocks rather than appending");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "autoselect", true,
+ "Select", "Select new objects");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "active_layer", true,
+ "Active Layer", "Put new objects on the active layer");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
+ "Instance Groups", "Create Dupli-Group instances for each group");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+void WM_OT_link(wmOperatorType *ot)
+{
+ ot->name = "Link from Library";
+ ot->idname = "WM_OT_link";
+ ot->description = "Link from a Library .blend file";
+
+ ot->invoke = wm_link_append_invoke;
+ ot->exec = wm_link_append_exec;
+ ot->poll = wm_link_append_poll;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ wm_link_append_properties_common(ot, true);
+}
+
+void WM_OT_append(wmOperatorType *ot)
+{
+ ot->name = "Append from Library";
+ ot->idname = "WM_OT_append";
+ ot->description = "Append from a Library .blend file";
+
+ ot->invoke = wm_link_append_invoke;
+ ot->exec = wm_link_append_exec;
+ ot->poll = wm_link_append_poll;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+
+ wm_link_append_properties_common(ot, false);
+ RNA_def_boolean(ot->srna, "set_fake", false, "Fake User", "Set Fake User for appended items (except Objects and Groups)");
+}
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 288e6711b56..26d1d4c3266 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -51,6 +51,7 @@
#include "wm.h"
#include "wm_subwindow.h"
#include "wm_draw.h"
+#include "GPU_basic_shader.h"
#include "BIF_glutil.h"
@@ -180,29 +181,29 @@ static void wm_gesture_draw_rect(wmGesture *gt)
glEnd();
glDisable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xCCCC);
+ GPU_basic_shader_line_stipple(1, 0xCCCC);
sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x3333);
+ GPU_basic_shader_line_stipple(1, 0x3333);
sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
static void wm_gesture_draw_line(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x5555);
+ GPU_basic_shader_line_stipple(1, 0x5555);
sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -217,15 +218,16 @@ static void wm_gesture_draw_circle(wmGesture *gt)
glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
glDisable(GL_BLEND);
- glEnable(GL_LINE_STIPPLE);
+ // for USE_GLSL works bad because of no relation between lines
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x5555);
+ GPU_basic_shader_line_stipple(1, 0x5555);
glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
}
@@ -235,12 +237,15 @@ struct LassoFillData {
int width;
};
-static void draw_filled_lasso_px_cb(int x, int y, void *user_data)
+static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
{
struct LassoFillData *data = user_data;
unsigned char *col = (unsigned char *)&(data->px[(y * data->width) + x]);
- col[0] = col[1] = col[2] = 0xff;
- col[3] = 0x10;
+ do {
+ col[0] = col[1] = col[2] = 0xff;
+ col[3] = 0x10;
+ col += 4;
+ } while (++x != x_end);
}
static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
@@ -300,9 +305,10 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
draw_filled_lasso(win, gt);
}
- glEnable(GL_LINE_STIPPLE);
+ // for USE_GLSL can't check this yet
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xAAAA);
+ GPU_basic_shader_line_stipple(1, 0xAAAA);
glBegin(GL_LINE_STRIP);
for (i = 0; i < gt->points; i++, lasso += 2)
glVertex2sv(lasso);
@@ -311,7 +317,7 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
glEnd();
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x5555);
+ GPU_basic_shader_line_stipple(1, 0x5555);
glBegin(GL_LINE_STRIP);
lasso = (short *)gt->customdata;
for (i = 0; i < gt->points; i++, lasso += 2)
@@ -320,7 +326,7 @@ static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
glVertex2sv((short *)gt->customdata);
glEnd();
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
@@ -330,17 +336,17 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
- glEnable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
glColor3ub(96, 96, 96);
- glLineStipple(1, 0xCCCC);
+ GPU_basic_shader_line_stipple(1, 0xCCCC);
sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
glColor3ub(255, 255, 255);
- glLineStipple(1, 0x3333);
+ GPU_basic_shader_line_stipple(1, 0x3333);
sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
- glDisable(GL_LINE_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
/* called in wm_draw.c */
@@ -348,6 +354,7 @@ void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
+ GPU_basic_shader_line_width(1);
for (; gt; gt = gt->next) {
/* all in subwindow space */
wmSubWindowSet(win, gt->swinid);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index a0ac945b647..e08d0afb906 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -64,6 +64,7 @@
#include "BKE_mball_tessellate.h"
#include "BKE_node.h"
#include "BKE_report.h"
+#include "BKE_font.h"
#include "BKE_addon.h"
#include "BKE_appdir.h"
@@ -96,9 +97,11 @@
#include "wm_files.h"
#include "wm_window.h"
+#include "ED_anim_api.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_keyframing.h"
+#include "ED_keyframes_edit.h"
#include "ED_node.h"
#include "ED_render.h"
#include "ED_space_api.h"
@@ -118,7 +121,7 @@
#include "COM_compositor.h"
#ifdef WITH_OPENSUBDIV
-# include "opensubdiv_capi.h"
+# include "BKE_subsurf.h"
#endif
static void wm_init_reports(bContext *C)
@@ -174,6 +177,10 @@ void WM_init(bContext *C, int argc, const char **argv)
/* Enforce loading the UI for the initial homefile */
G.fileflags &= ~G_FILE_NO_UI;
+ /* reports cant be initialized before the wm,
+ * but keep before file reading, since that may report errors */
+ wm_init_reports(C);
+
/* get the default database, plus a wm */
wm_homefile_read(C, NULL, G.factory_startup, NULL);
@@ -192,7 +199,7 @@ void WM_init(bContext *C, int argc, const char **argv)
GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
#ifdef WITH_OPENSUBDIV
- openSubdiv_init();
+ BKE_subsurf_osd_init();
#endif
UI_init();
@@ -229,8 +236,6 @@ void WM_init(bContext *C, int argc, const char **argv)
if (!G.background && !wm_start_with_console)
GHOST_toggleConsole(3);
- wm_init_reports(C); /* reports cant be initialized before the wm */
-
clear_matcopybuf();
ED_render_clear_mtex_copybuf();
@@ -259,13 +264,24 @@ void WM_init(bContext *C, int argc, const char **argv)
/* that prevents loading both the kept session, and the file on the command line */
}
else {
+ /* note, logic here is from wm_file_read_post,
+ * call functions that depend on Python being initialized. */
+
/* normally 'wm_homefile_read' will do this,
* however python is not initialized when called from this function.
*
* unlikely any handlers are set but its possible,
* note that recovering the last session does its own callbacks. */
+ CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
+
+ wm_file_read_report(C);
+
+ if (!G.background) {
+ CTX_wm_window_set(C, NULL);
+ }
}
}
@@ -385,13 +401,6 @@ static void free_openrecent(void)
}
-/* bad stuff*/
-
-// XXX copy/paste buffer stuff...
-extern void free_anim_copybuf(void);
-extern void free_anim_drivers_copybuf(void);
-extern void free_fmodifiers_copybuf(void);
-
#ifdef WIN32
/* Read console events until there is a key event. Also returns on any error. */
static void wait_for_console_key(void)
@@ -415,8 +424,9 @@ static void wait_for_console_key(void)
}
#endif
-/* called in creator.c even... tsk, split this! */
-/* note, doesnt run exit() call WM_exit() for that */
+/**
+ * \note doesn't run exit() call #WM_exit() for that.
+ */
void WM_exit_ext(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
@@ -490,6 +500,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
BKE_sequencer_free_clipboard(); /* sequencer.c */
BKE_tracking_clipboard_free();
BKE_mask_clipboard_free();
+ BKE_vfont_clipboard_free();
#ifdef WITH_COMPOSITOR
COM_deinitialize();
@@ -497,9 +508,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
free_blender(); /* blender.c, does entire library and spacetypes */
// free_matcopybuf();
- free_anim_copybuf();
- free_anim_drivers_copybuf();
- free_fmodifiers_copybuf();
+ ANIM_fcurves_copybuf_free();
+ ANIM_drivers_copybuf_free();
+ ANIM_driver_vars_copybuf_free();
+ ANIM_fmodifiers_copybuf_free();
+ ED_gpencil_anim_copybuf_free();
ED_gpencil_strokes_copybuf_free();
ED_clipboard_posebuf_free();
BKE_node_clipboard_clear();
@@ -533,11 +546,11 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
+ if (!G.background) {
#ifdef WITH_OPENSUBDIV
- openSubdiv_cleanup();
+ BKE_subsurf_osd_cleanup();
#endif
- if (!G.background) {
GPU_global_buffer_pool_free();
GPU_free_unused_buffers();
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index f8258d18c1a..5580d3217a5 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -103,7 +103,7 @@ struct wmJob {
unsigned int note, endnote;
-/* internal */
+ /* internal */
void *owner;
int flag;
short suspended, running, ready, do_update, stop, job_type;
@@ -111,7 +111,7 @@ struct wmJob {
/* for display in header, identification */
char name[128];
-
+
/* once running, we store this separately */
void *run_customdata;
void (*run_free)(void *);
@@ -124,7 +124,6 @@ struct wmJob {
/* ticket mutex for main thread locking while some job accesses
* data that the main thread might modify at the same time */
TicketMutex *main_thread_mutex;
- bool main_thread_mutex_ending;
};
/* Main thread locking */
@@ -132,25 +131,15 @@ struct wmJob {
void WM_job_main_thread_lock_acquire(wmJob *wm_job)
{
BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
-
- /* if BLI_end_threads is being called to stop the job before it's finished,
- * we no longer need to lock to get access to the main thread as it's
- * waiting and can't respond */
- if (wm_job->main_thread_mutex_ending)
- BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
}
void WM_job_main_thread_lock_release(wmJob *wm_job)
{
- if (!wm_job->main_thread_mutex_ending)
- BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
+ BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
}
-static void wm_job_main_thread_yield(wmJob *wm_job, bool ending)
+static void wm_job_main_thread_yield(wmJob *wm_job)
{
- if (ending)
- wm_job->main_thread_mutex_ending = true;
-
/* unlock and lock the ticket mutex. because it's a fair mutex any job that
* is waiting to acquire the lock will get it first, before we can lock */
BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
@@ -206,7 +195,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *
BLI_strncpy(wm_job->name, name, sizeof(wm_job->name));
wm_job->main_thread_mutex = BLI_ticket_mutex_alloc();
- BLI_ticket_mutex_lock(wm_job->main_thread_mutex);
+ WM_job_main_thread_lock_acquire(wm_job);
}
/* else: a running job, be careful */
@@ -245,6 +234,17 @@ float WM_jobs_progress(wmWindowManager *wm, void *owner)
return 0.0;
}
+/* time that job started */
+double WM_jobs_starttime(wmWindowManager *wm, void *owner)
+{
+ wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
+
+ if (wm_job && wm_job->flag & WM_JOB_PROGRESS)
+ return wm_job->start_time;
+
+ return 0;
+}
+
char *WM_jobs_name(wmWindowManager *wm, void *owner)
{
wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
@@ -280,6 +280,12 @@ bool WM_jobs_is_running(wmJob *wm_job)
return wm_job->running;
}
+bool WM_jobs_is_stopped(wmWindowManager *wm, void *owner)
+{
+ wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY);
+ return wm_job ? wm_job->stop : true; /* XXX to be redesigned properly. */
+}
+
void *WM_jobs_customdata_get(wmJob *wm_job)
{
if (!wm_job->customdata) {
@@ -420,8 +426,7 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
if (wm_job->wt == NULL)
wm_job->wt = WM_event_add_timer(wm, wm_job->win, TIMERJOBS, wm_job->timestep);
- if (G.debug & G_DEBUG_JOBS)
- wm_job->start_time = PIL_check_seconds_timer();
+ wm_job->start_time = PIL_check_seconds_timer();
}
else {
printf("job fails, not initialized\n");
@@ -432,7 +437,7 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
{
BLI_remlink(&wm->jobs, wm_job);
- BLI_ticket_mutex_unlock(wm_job->main_thread_mutex);
+ WM_job_main_thread_lock_release(wm_job);
BLI_ticket_mutex_free(wm_job->main_thread_mutex);
MEM_freeN(wm_job);
}
@@ -443,8 +448,10 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
if (wm_job->running) {
/* signal job to end */
wm_job->stop = true;
- wm_job_main_thread_yield(wm_job, true);
+
+ WM_job_main_thread_lock_release(wm_job);
BLI_end_threads(&wm_job->threads);
+ WM_job_main_thread_lock_acquire(wm_job);
if (wm_job->endjob)
wm_job->endjob(wm_job->run_customdata);
@@ -560,7 +567,7 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
if (wm_job->threads.first) {
/* let threads get temporary lock over main thread if needed */
- wm_job_main_thread_yield(wm_job, false);
+ wm_job_main_thread_yield(wm_job);
/* always call note and update when ready */
if (wm_job->do_update || wm_job->ready) {
@@ -592,9 +599,10 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
}
wm_job->running = false;
- wm_job_main_thread_yield(wm_job, true);
+
+ WM_job_main_thread_lock_release(wm_job);
BLI_end_threads(&wm_job->threads);
- wm_job->main_thread_mutex_ending = false;
+ WM_job_main_thread_lock_acquire(wm_job);
if (wm_job->endnote)
WM_event_add_notifier(C, wm_job->endnote, NULL);
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 5098df2c0a6..72b26cc6207 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -202,6 +202,9 @@ int WM_keymap_map_type_get(wmKeyMapItem *kmi)
if (kmi->type == KM_TEXTINPUT) {
return KMI_TYPE_TEXTINPUT;
}
+ if (ELEM(kmi->type, TABLET_STYLUS, TABLET_ERASER)) {
+ return KMI_TYPE_MOUSE;
+ }
return KMI_TYPE_KEYBOARD;
}
@@ -903,15 +906,21 @@ static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
const char *WM_key_event_string(const short type, const bool compact)
{
- const char *name = NULL;
+ EnumPropertyItem *it;
+ const int i = RNA_enum_from_value(rna_enum_event_type_items, (int)type);
+
+ if (i == -1) {
+ return "";
+ }
+ it = &rna_enum_event_type_items[i];
+
/* We first try enum items' description (abused as shortname here), and fall back to usual name if empty. */
- if ((compact && RNA_enum_description(event_type_items, (int)type, &name) && name[0]) ||
- RNA_enum_name(event_type_items, (int)type, &name))
- {
- return IFACE_(name);
+ if (compact && it->description[0]) {
+ /* XXX No context for enum descriptions... In practice shall not be an issue though. */
+ return IFACE_(it->description);
}
- return "";
+ return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
}
/* TODO: also support (some) value, like e.g. double-click? */
@@ -1292,17 +1301,12 @@ char *WM_key_event_operator_string(
return NULL;
}
-int WM_key_event_operator_id(
+wmKeyMapItem *WM_key_event_operator(
const bContext *C, const char *opname, int opcontext,
IDProperty *properties, const bool is_hotkey,
wmKeyMap **r_keymap)
{
- wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap);
-
- if (kmi)
- return kmi->id;
- else
- return 0;
+ return wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap);
}
int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2)
@@ -1783,7 +1787,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
}
/* UV Editor */
else if (STRPREFIX(opname, "UV_OT")) {
- km = WM_keymap_find_all(C, "UV Editor", sl->spacetype, 0);
+ km = WM_keymap_find_all(C, "UV Editor", 0, 0);
}
/* Node Editor */
else if (STRPREFIX(opname, "NODE_OT")) {
@@ -1791,7 +1795,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
}
/* Animation Editor Channels */
else if (STRPREFIX(opname, "ANIM_OT_channels")) {
- km = WM_keymap_find_all(C, "Animation Channels", sl->spacetype, 0);
+ km = WM_keymap_find_all(C, "Animation Channels", 0, 0);
}
/* Animation Generic - after channels */
else if (STRPREFIX(opname, "ANIM_OT")) {
@@ -1858,7 +1862,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "NLA Editor", sl->spacetype, 0);
break;
case SPACE_IMAGE:
- km = WM_keymap_find_all(C, "UV Editor", sl->spacetype, 0);
+ km = WM_keymap_find_all(C, "UV Editor", 0, 0);
break;
case SPACE_NODE:
km = WM_keymap_find_all(C, "Node Editor", sl->spacetype, 0);
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
new file mode 100644
index 00000000000..7ec2aea73e1
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -0,0 +1,298 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_operator_props.c
+ * \ingroup wm
+ *
+ * Generic re-usable property definitions and accessors for operators to share.
+ * (`WM_operator_properties_*` functions).
+ */
+
+#include "DNA_space_types.h"
+
+#include "BLI_rect.h"
+#include "BLI_math_base.h"
+
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* default properties for fileselect */
+void WM_operator_properties_filesel(
+ wmOperatorType *ot, int filter, short type, short action,
+ short flag, short display, short sort)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem file_display_items[] = {
+ {FILE_DEFAULTDISPLAY, "DEFAULT", 0, "Default", "Automatically determine display type for files"},
+ {FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
+ {FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
+ {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ if (flag & WM_FILESEL_FILEPATH)
+ RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
+
+ if (flag & WM_FILESEL_DIRECTORY)
+ RNA_def_string_dir_path(ot->srna, "directory", NULL, FILE_MAX, "Directory", "Directory of the file");
+
+ if (flag & WM_FILESEL_FILENAME)
+ RNA_def_string_file_name(ot->srna, "filename", NULL, FILE_MAX, "File Name", "Name of the file");
+
+ if (flag & WM_FILESEL_FILES)
+ RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
+
+ if (action == FILE_SAVE) {
+ /* note, this is only used to check if we should highlight the filename area red when the
+ * filepath is an existing file. */
+ prop = RNA_def_boolean(ot->srna, "check_existing", true, "Check Existing",
+ "Check and warn on overwriting existing files");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
+ prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & FILE_TYPE_BLENDER) != 0, "Filter .blend files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & FILE_TYPE_BLENDER_BACKUP) != 0, "Filter .blend files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_image", (filter & FILE_TYPE_IMAGE) != 0, "Filter image files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & FILE_TYPE_MOVIE) != 0, "Filter movie files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter python files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FILE_TYPE_FTFONT) != 0, "Filter font files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & FILE_TYPE_SOUND) != 0, "Filter sound files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL,
+ "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file",
+ FILE_LOADLIB, FILE_SPECIAL);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ if (flag & WM_FILESEL_RELPATH)
+ RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
+
+ if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) {
+ prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ }
+
+ prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna, "sort_method", rna_enum_file_sort_items, sort, "File sorting mode", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+}
+
+static void wm_operator_properties_select_action_ex(wmOperatorType *ot, int default_action,
+ const EnumPropertyItem *select_actions)
+{
+ RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
+}
+
+void WM_operator_properties_select_action(wmOperatorType *ot, int default_action)
+{
+ static EnumPropertyItem select_actions[] = {
+ {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"},
+ {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
+ {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
+ {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wm_operator_properties_select_action_ex(ot, default_action, select_actions);
+}
+
+/**
+ * only SELECT/DESELECT
+ */
+void WM_operator_properties_select_action_simple(wmOperatorType *ot, int default_action)
+{
+ static EnumPropertyItem select_actions[] = {
+ {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
+ {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wm_operator_properties_select_action_ex(ot, default_action, select_actions);
+}
+
+/**
+ * Use for all select random operators.
+ * Adds properties: percent, seed, action.
+ */
+void WM_operator_properties_select_random(wmOperatorType *ot)
+{
+ RNA_def_float_percentage(
+ ot->srna, "percent", 50.f, 0.0f, 100.0f,
+ "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
+ RNA_def_int(
+ ot->srna, "seed", 0, 0, INT_MAX,
+ "Random Seed", "Seed for the random number generator", 0, 255);
+
+ WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+}
+
+int WM_operator_properties_select_random_seed_increment_get(wmOperator *op)
+{
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "seed");
+ int value = RNA_property_int_get(op->ptr, prop);
+
+ if (op->flag & OP_IS_INVOKE) {
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ value += 1;
+ RNA_property_int_set(op->ptr, prop, value);
+ }
+ }
+ return value;
+}
+
+void WM_operator_properties_select_all(wmOperatorType *ot)
+{
+ WM_operator_properties_select_action(ot, SEL_TOGGLE);
+}
+
+void WM_operator_properties_border(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect)
+{
+ rect->xmin = RNA_int_get(op->ptr, "xmin");
+ rect->ymin = RNA_int_get(op->ptr, "ymin");
+ rect->xmax = RNA_int_get(op->ptr, "xmax");
+ rect->ymax = RNA_int_get(op->ptr, "ymax");
+}
+
+void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
+{
+ rcti rect_i;
+ WM_operator_properties_border_to_rcti(op, &rect_i);
+ BLI_rctf_rcti_copy(rect, &rect_i);
+}
+
+void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend)
+{
+ RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
+
+ WM_operator_properties_border(ot);
+
+ if (extend) {
+ RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
+ }
+}
+
+void WM_operator_properties_mouse_select(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend",
+ "Extend selection instead of deselecting everything first");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Remove from selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle Selection", "Toggle the selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ if (cursor) {
+ prop = RNA_def_int(ot->srna, "cursor", cursor, 0, INT_MAX,
+ "Cursor", "Mouse cursor style to use during the modal operator", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
+}
+
+/**
+ * \param nth_can_disable: Enable if we want to be able to select no interval at all.
+ */
+void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
+{
+ const int nth_default = nth_can_disable ? 1 : 2;
+ const int nth_min = min_ii(nth_default, 2);
+ RNA_def_int(ot->srna, "nth", nth_default, nth_min, INT_MAX, "Nth Selection", "", nth_min, 100);
+ RNA_def_int(ot->srna, "skip", 1, 1, INT_MAX, "Skip", "", 1, 100);
+ RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "", -100, 100);
+}
+
+void WM_operator_properties_checker_interval_from_op(
+ struct wmOperator *op, struct CheckerIntervalParams *op_params)
+{
+ const int nth = RNA_int_get(op->ptr, "nth") - 1;
+ const int skip = RNA_int_get(op->ptr, "skip");
+ int offset = RNA_int_get(op->ptr, "offset");
+
+ op_params->nth = nth;
+ op_params->skip = skip;
+ op_params->offset = mod_i(offset, nth + skip); /* so input of offset zero ends up being (nth - 1) */
+}
+
+bool WM_operator_properties_checker_interval_test(
+ const struct CheckerIntervalParams *op_params, int depth)
+{
+ return ((op_params->nth == 0) ||
+ ((op_params->offset + depth) % (op_params->skip + op_params->nth) >= op_params->skip));
+}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index c9dd07208c1..8a15237078a 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -52,7 +52,6 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
#include "BLT_translation.h"
@@ -61,7 +60,6 @@
#include "BLI_blenlib.h"
#include "BLI_dial.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
-#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -69,7 +67,6 @@
#include "BLO_readfile.h"
#include "BKE_appdir.h"
-#include "BKE_autoexec.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -86,14 +83,12 @@
#include "BKE_scene.h"
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
#include "BKE_unit.h"
-#include "BKE_utildefines.h"
#include "BKE_idcode.h"
#include "BIF_glutil.h" /* for paint cursor */
#include "BLF_api.h"
-#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -102,7 +97,7 @@
#include "ED_util.h"
#include "ED_view3d.h"
-#include "GPU_material.h"
+#include "GPU_basic_shader.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -1206,199 +1201,6 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor
return false;
}
-/* default properties for fileselect */
-void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort)
-{
- PropertyRNA *prop;
-
- static EnumPropertyItem file_display_items[] = {
- {FILE_DEFAULTDISPLAY, "FILE_DEFAULTDISPLAY", 0, "Default", "Automatically determine display type for files"},
- {FILE_SHORTDISPLAY, "FILE_SHORTDISPLAY", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
- {FILE_LONGDISPLAY, "FILE_LONGDISPLAY", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
- {FILE_IMGDISPLAY, "FILE_IMGDISPLAY", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
- {0, NULL, 0, NULL, NULL}
- };
-
- if (flag & WM_FILESEL_FILEPATH)
- RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
-
- if (flag & WM_FILESEL_DIRECTORY)
- RNA_def_string_dir_path(ot->srna, "directory", NULL, FILE_MAX, "Directory", "Directory of the file");
-
- if (flag & WM_FILESEL_FILENAME)
- RNA_def_string_file_name(ot->srna, "filename", NULL, FILE_MAX, "File Name", "Name of the file");
-
- if (flag & WM_FILESEL_FILES)
- RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
-
- if (action == FILE_SAVE) {
- /* note, this is only used to check if we should highlight the filename area red when the
- * filepath is an existing file. */
- prop = RNA_def_boolean(ot->srna, "check_existing", true, "Check Existing",
- "Check and warn on overwriting existing files");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- }
-
- prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & FILE_TYPE_BLENDER) != 0, "Filter .blend files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & FILE_TYPE_BLENDER_BACKUP) != 0, "Filter .blend files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_image", (filter & FILE_TYPE_IMAGE) != 0, "Filter image files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & FILE_TYPE_MOVIE) != 0, "Filter movie files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter python files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FILE_TYPE_FTFONT) != 0, "Filter font files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & FILE_TYPE_SOUND) != 0, "Filter sound files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL,
- "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file",
- FILE_LOADLIB, FILE_SPECIAL);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- if (flag & WM_FILESEL_RELPATH)
- RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file");
-
- if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) {
- prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- }
-
- prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- prop = RNA_def_enum(ot->srna, "sort_method", file_sort_items, sort, "File sorting mode", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
-}
-
-static void wm_operator_properties_select_action_ex(wmOperatorType *ot, int default_action,
- const EnumPropertyItem *select_actions)
-{
- RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
-}
-
-void WM_operator_properties_select_action(wmOperatorType *ot, int default_action)
-{
- static EnumPropertyItem select_actions[] = {
- {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"},
- {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
- {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
- {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"},
- {0, NULL, 0, NULL, NULL}
- };
-
- wm_operator_properties_select_action_ex(ot, default_action, select_actions);
-}
-
-/**
- * only SELECT/DESELECT
- */
-void WM_operator_properties_select_action_simple(wmOperatorType *ot, int default_action)
-{
- static EnumPropertyItem select_actions[] = {
- {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"},
- {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"},
- {0, NULL, 0, NULL, NULL}
- };
-
- wm_operator_properties_select_action_ex(ot, default_action, select_actions);
-}
-
-void WM_operator_properties_select_all(wmOperatorType *ot)
-{
- WM_operator_properties_select_action(ot, SEL_TOGGLE);
-}
-
-void WM_operator_properties_border(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-}
-
-void WM_operator_properties_border_to_rcti(struct wmOperator *op, rcti *rect)
-{
- rect->xmin = RNA_int_get(op->ptr, "xmin");
- rect->ymin = RNA_int_get(op->ptr, "ymin");
- rect->xmax = RNA_int_get(op->ptr, "xmax");
- rect->ymax = RNA_int_get(op->ptr, "ymax");
-}
-
-void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
-{
- rcti rect_i;
- WM_operator_properties_border_to_rcti(op, &rect_i);
- BLI_rctf_rcti_copy(rect, &rect_i);
-}
-
-void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend)
-{
- RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
-
- WM_operator_properties_border(ot);
-
- if (extend) {
- RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
- }
-}
-
-void WM_operator_properties_mouse_select(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_boolean(ot->srna, "extend", false, "Extend",
- "Extend selection instead of deselecting everything first");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Remove from selection");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle Selection", "Toggle the selection");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_int(ot->srna, "xstart", 0, INT_MIN, INT_MAX, "X Start", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "xend", 0, INT_MIN, INT_MAX, "X End", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "ystart", 0, INT_MIN, INT_MAX, "Y Start", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- prop = RNA_def_int(ot->srna, "yend", 0, INT_MIN, INT_MAX, "Y End", "", INT_MIN, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- if (cursor) {
- prop = RNA_def_int(ot->srna, "cursor", cursor, 0, INT_MAX,
- "Cursor", "Mouse cursor style to use during the modal operator", 0, INT_MAX);
- RNA_def_property_flag(prop, PROP_HIDDEN);
- }
-}
-
-
/* op->poll */
int WM_operator_winactive(bContext *C)
{
@@ -1539,6 +1341,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
if (op->type->flag & OPTYPE_MACRO) {
for (op = op->macro.first; op; op = op->next) {
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
+ if (op->next)
+ uiItemS(layout);
}
}
else {
@@ -2087,8 +1891,14 @@ static void WM_OT_splash(wmOperatorType *ot)
/* ***************** Search menu ************************* */
-static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_op))
+
+struct SearchPopupInit_Data {
+ int size[2];
+};
+
+static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *userdata)
{
+ const struct SearchPopupInit_Data *init_data = userdata;
static char search[256] = "";
wmEvent event;
wmWindow *win = CTX_wm_window(C);
@@ -2098,11 +1908,12 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
- but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, "");
+ but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, init_data->size[0], UI_UNIT_Y, 0, 0, "");
UI_but_func_operator_search(but);
/* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - init_data->size[1],
+ init_data->size[0], init_data->size[1], NULL, 0, 0, 0, 0, NULL);
UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
@@ -2121,9 +1932,16 @@ static int wm_search_menu_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int wm_search_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
- UI_popup_block_invoke(C, wm_block_search_menu, op);
+ struct SearchPopupInit_Data data = {
+ .size = {
+ UI_searchbox_size_x() * 2,
+ UI_searchbox_size_y(),
+ },
+ };
+
+ UI_popup_block_invoke(C, wm_block_search_menu, &data);
return OPERATOR_INTERFACE;
}
@@ -2226,6 +2044,17 @@ static int wm_operator_winactive_normal(bContext *C)
return 1;
}
+/* included for script-access */
+static void WM_OT_window_close(wmOperatorType *ot)
+{
+ ot->name = "Close Window";
+ ot->idname = "WM_OT_window_close";
+ ot->description = "Close the current Blender window";
+
+ ot->exec = wm_window_close_exec;
+ ot->poll = WM_operator_winactive;
+}
+
static void WM_OT_window_duplicate(wmOperatorType *ot)
{
ot->name = "Duplicate Window";
@@ -2236,919 +2065,6 @@ static void WM_OT_window_duplicate(wmOperatorType *ot)
ot->poll = wm_operator_winactive_normal;
}
-static void WM_OT_save_homefile(wmOperatorType *ot)
-{
- ot->name = "Save Startup File";
- ot->idname = "WM_OT_save_homefile";
- ot->description = "Make the current file the default .blend file, includes preferences";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_homefile_write_exec;
-}
-
-static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
-{
- bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
- BLI_addtail(&U.autoexec_paths, path_cmp);
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot)
-{
- ot->name = "Add Autoexec Path";
- ot->idname = "WM_OT_userpref_autoexec_path_add";
- ot->description = "Add path to exclude from autoexecution";
-
- ot->exec = wm_userpref_autoexec_add_exec;
-
- ot->flag = OPTYPE_INTERNAL;
-}
-
-static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
-{
- const int index = RNA_int_get(op->ptr, "index");
- bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
- if (path_cmp) {
- BLI_freelinkN(&U.autoexec_paths, path_cmp);
- }
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
-{
- ot->name = "Remove Autoexec Path";
- ot->idname = "WM_OT_userpref_autoexec_path_remove";
- ot->description = "Remove path to exclude from autoexecution";
-
- ot->exec = wm_userpref_autoexec_remove_exec;
-
- ot->flag = OPTYPE_INTERNAL;
-
- RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
-}
-
-static void WM_OT_save_userpref(wmOperatorType *ot)
-{
- ot->name = "Save User Settings";
- ot->idname = "WM_OT_save_userpref";
- ot->description = "Save user preferences separately, overrides startup file preferences";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_userpref_write_exec;
-}
-
-static void WM_OT_read_history(wmOperatorType *ot)
-{
- ot->name = "Reload History File";
- ot->idname = "WM_OT_read_history";
- ot->description = "Reloads history and bookmarks";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_history_file_read_exec;
-
- /* this operator is only used for loading settings from a previous blender install */
- ot->flag = OPTYPE_INTERNAL;
-}
-
-static void WM_OT_read_homefile(wmOperatorType *ot)
-{
- PropertyRNA *prop;
- ot->name = "Reload Start-Up File";
- ot->idname = "WM_OT_read_homefile";
- ot->description = "Open the default file (doesn't save the current file)";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_homefile_read_exec;
-
- prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
- FILE_MAX, "File Path",
- "Path to an alternative start-up file");
- RNA_def_property_flag(prop, PROP_HIDDEN);
-
- /* So scripts can use an alternative start-up file without the UI */
- prop = RNA_def_boolean(ot->srna, "load_ui", true, "Load UI",
- "Load user interface setup from the .blend file");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- /* omit poll to run in background mode */
-}
-
-static void WM_OT_read_factory_settings(wmOperatorType *ot)
-{
- ot->name = "Load Factory Settings";
- ot->idname = "WM_OT_read_factory_settings";
- ot->description = "Load default file and user preferences";
-
- ot->invoke = WM_operator_confirm;
- ot->exec = wm_homefile_read_exec;
- /* omit poll to run in background mode */
-}
-
-/* *************** open file **************** */
-
-/**
- * Wrap #WM_file_read, shared by file reading operators.
- */
-static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports,
- const bool autoexec_init)
-{
- bool success;
-
- /* XXX wm in context is not set correctly after WM_file_read -> crash */
- /* do it before for now, but is this correct with multiple windows? */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
- if (autoexec_init) {
- WM_file_autoexec_init(filepath);
- }
-
- success = WM_file_read(C, filepath, reports);
-
- return success;
-}
-
-/* currently fits in a pointer */
-struct FileRuntime {
- bool is_untrusted;
-};
-
-static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- const char *openname = G.main->name;
-
- if (CTX_wm_window(C) == NULL) {
- /* in rare cases this could happen, when trying to invoke in background
- * mode on load for example. Don't use poll for this because exec()
- * can still run without a window */
- BKE_report(op->reports, RPT_ERROR, "Context window not set");
- return OPERATOR_CANCELLED;
- }
-
- /* if possible, get the name of the most recently used .blend file */
- if (G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- openname = recent->filepath;
- }
-
- RNA_string_set(op->ptr, "filepath", openname);
- wm_open_init_load_ui(op, true);
- wm_open_init_use_scripts(op, true);
- op->customdata = NULL;
-
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
-{
- char filepath[FILE_MAX];
- bool success;
-
- RNA_string_get(op->ptr, "filepath", filepath);
-
- /* re-use last loaded setting so we can reload a file without changing */
- wm_open_init_load_ui(op, false);
- wm_open_init_use_scripts(op, false);
-
- if (RNA_boolean_get(op->ptr, "load_ui"))
- G.fileflags &= ~G_FILE_NO_UI;
- else
- G.fileflags |= G_FILE_NO_UI;
-
- if (RNA_boolean_get(op->ptr, "use_scripts"))
- G.f |= G_SCRIPT_AUTOEXEC;
- else
- G.f &= ~G_SCRIPT_AUTOEXEC;
-
- success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
-
- /* for file open also popup for warnings, not only errors */
- BKE_report_print_level_set(op->reports, RPT_WARNING);
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
-{
- struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts");
- bool is_untrusted = false;
- char path[FILE_MAX];
- char *lslash;
-
- RNA_string_get(op->ptr, "filepath", path);
-
- /* get the dir */
- lslash = (char *)BLI_last_slash(path);
- if (lslash) *(lslash + 1) = '\0';
-
- if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) {
- if (BKE_autoexec_match(path) == true) {
- RNA_property_boolean_set(op->ptr, prop, false);
- is_untrusted = true;
- }
- }
-
- if (file_info) {
- file_info->is_untrusted = is_untrusted;
- }
-
- return is_untrusted;
-}
-
-static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op)
-{
- struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
- uiLayout *layout = op->layout;
- uiLayout *col = op->layout;
- const char *autoexec_text;
-
- uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE);
-
- col = uiLayoutColumn(layout, false);
- if (file_info->is_untrusted) {
- autoexec_text = IFACE_("Trusted Source [Untrusted Path]");
- uiLayoutSetActive(col, false);
- uiLayoutSetEnabled(col, false);
- }
- else {
- autoexec_text = IFACE_("Trusted Source");
- }
-
- uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE);
-}
-
-static void WM_OT_open_mainfile(wmOperatorType *ot)
-{
- ot->name = "Open Blender File";
- ot->idname = "WM_OT_open_mainfile";
- ot->description = "Open a Blender file";
-
- ot->invoke = wm_open_mainfile_invoke;
- ot->exec = wm_open_mainfile_exec;
- ot->check = wm_open_mainfile_check;
- ot->ui = wm_open_mainfile_ui;
- /* omit window poll so this can work in background mode */
-
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
- RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
- RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
- "Allow .blend file to execute scripts automatically, default available from system preferences");
-}
-
-
-/* *************** revert file **************** */
-
-static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
-{
- bool success;
-
- wm_open_init_use_scripts(op, false);
-
- if (RNA_boolean_get(op->ptr, "use_scripts"))
- G.f |= G_SCRIPT_AUTOEXEC;
- else
- G.f &= ~G_SCRIPT_AUTOEXEC;
-
- success = wm_file_read_opwrap(C, G.main->name, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int wm_revert_mainfile_poll(bContext *UNUSED(C))
-{
- return G.relbase_valid;
-}
-
-static void WM_OT_revert_mainfile(wmOperatorType *ot)
-{
- ot->name = "Revert";
- ot->idname = "WM_OT_revert_mainfile";
- ot->description = "Reload the saved file";
- ot->invoke = WM_operator_confirm;
-
- RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
- "Allow .blend file to execute scripts automatically, default available from system preferences");
-
- ot->exec = wm_revert_mainfile_exec;
- ot->poll = wm_revert_mainfile_poll;
-}
-
-/* **************** link/append *************** */
-
-static int wm_link_append_poll(bContext *C)
-{
- if (WM_operator_winactive(C)) {
- /* linking changes active object which is pretty useful in general,
- * but which totally confuses edit mode (i.e. it becoming not so obvious
- * to leave from edit mode and invalid tools in toolbar might be displayed)
- * so disable link/append when in edit mode (sergey) */
- if (CTX_data_edit_object(C))
- return 0;
-
- return 1;
- }
-
- return 0;
-}
-
-static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- return WM_operator_call_notest(C, op);
- }
- else {
- /* XXX TODO solve where to get last linked library from */
- if (G.lib[0] != '\0') {
- RNA_string_set(op->ptr, "filepath", G.lib);
- }
- else if (G.relbase_valid) {
- char path[FILE_MAX];
- BLI_strncpy(path, G.main->name, sizeof(G.main->name));
- BLI_parent_dir(path);
- RNA_string_set(op->ptr, "filepath", path);
- }
- WM_event_add_fileselect(C, op);
- return OPERATOR_RUNNING_MODAL;
- }
-}
-
-static short wm_link_append_flag(wmOperator *op)
-{
- short flag = 0;
-
- if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT;
- if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY;
- if (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH;
- if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK;
- if (RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE;
-
- return flag;
-}
-
-/* Helper.
- * if `name` is non-NULL, we assume a single-item link/append.
- * else if `*todo_libraries` is NULL we assume first-run.
- */
-static void wm_link_append_do_libgroup(
- bContext *C, wmOperator *op, const char *root, const char *libname, char *group, char *name,
- const short flag, GSet **todo_libraries)
-{
- Main *bmain = CTX_data_main(C);
- Main *mainl;
- BlendHandle *bh;
- Library *lib;
-
- char path[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
- int idcode;
- const bool is_first_run = (*todo_libraries == NULL);
-
- BLI_assert(group);
- idcode = BKE_idcode_from_name(group);
-
- bh = BLO_blendhandle_from_file(libname, op->reports);
-
- if (bh == NULL) {
- /* unlikely since we just browsed it, but possible
- * error reports will have been made by BLO_blendhandle_from_file() */
- return;
- }
-
- /* here appending/linking starts */
- mainl = BLO_library_append_begin(bmain, &bh, libname);
- lib = mainl->curlib;
- BLI_assert(lib);
-
- if (mainl->versionfile < 250) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
- "be done! You may want to re-save your lib file with current Blender",
- mainl->versionfile, mainl->subversionfile);
- }
-
- if (name) {
- BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
- }
- else {
- if (is_first_run) {
- *todo_libraries = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
- }
-
- RNA_BEGIN (op->ptr, itemptr, "files")
- {
- char curr_libname[FILE_MAX];
- int curr_idcode;
-
- RNA_string_get(&itemptr, "name", relname);
-
- BLI_join_dirfile(path, sizeof(path), root, relname);
-
- if (BLO_library_path_explode(path, curr_libname, &group, &name)) {
- if (!group || !name) {
- continue;
- }
-
- curr_idcode = BKE_idcode_from_name(group);
-
- if ((idcode == curr_idcode) && (BLI_path_cmp(curr_libname, libname) == 0)) {
- BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
- }
- else if (is_first_run) {
- BLI_join_dirfile(path, sizeof(path), curr_libname, group);
- if (!BLI_gset_haskey(*todo_libraries, path)) {
- BLI_gset_insert(*todo_libraries, BLI_strdup(path));
- }
- }
- }
- }
- RNA_END;
- }
- BLO_library_append_end(C, mainl, &bh, idcode, flag);
-
- BLO_blendhandle_close(bh);
-
- /* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* append, rather than linking */
- if ((flag & FILE_LINK) == 0) {
- BLI_assert(BLI_findindex(&bmain->library, lib) != -1);
- BKE_library_make_local(bmain, lib, true);
- }
-}
-
-static int wm_link_append_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- PropertyRNA *prop;
- char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
- char *group, *name;
- int totfiles = 0;
- short flag;
-
- GSet *todo_libraries = NULL;
-
- RNA_string_get(op->ptr, "filename", relname);
- RNA_string_get(op->ptr, "directory", root);
-
- BLI_join_dirfile(path, sizeof(path), root, relname);
-
- /* test if we have a valid data */
- if (!BLO_library_path_explode(path, libname, &group, &name)) {
- BKE_report(op->reports, RPT_ERROR, "Not a library");
- return OPERATOR_CANCELLED;
- }
- else if (!group) {
- BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
- return OPERATOR_CANCELLED;
- }
- else if (BLI_path_cmp(bmain->name, libname) == 0) {
- BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
- return OPERATOR_CANCELLED;
- }
-
- /* check if something is indicated for append/link */
- prop = RNA_struct_find_property(op->ptr, "files");
- if (prop) {
- totfiles = RNA_property_collection_length(op->ptr, prop);
- if (totfiles == 0) {
- if (!name) {
- BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
- return OPERATOR_CANCELLED;
- }
- }
- }
- else if (!name) {
- BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
- return OPERATOR_CANCELLED;
- }
-
- flag = wm_link_append_flag(op);
-
- /* sanity checks for flag */
- if (scene->id.lib && (flag & FILE_GROUP_INSTANCE)) {
- /* TODO, user never gets this message */
- BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name + 2);
- flag &= ~FILE_GROUP_INSTANCE;
- }
-
- /* from here down, no error returns */
-
- /* now we have or selected, or an indicated file */
- if (RNA_boolean_get(op->ptr, "autoselect"))
- BKE_scene_base_deselect_all(scene);
-
- /* tag everything, all untagged data can be made local
- * its also generally useful to know what is new
- *
- * take extra care BKE_main_id_flag_all(LIB_LINK_TAG, false) is called after! */
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, 1);
-
- if (totfiles != 0) {
- name = NULL;
- }
-
- wm_link_append_do_libgroup(C, op, root, libname, group, name, flag, &todo_libraries);
-
- if (todo_libraries) {
- GSetIterator libs_it;
-
- GSET_ITER(libs_it, todo_libraries) {
- char *libpath = (char *)BLI_gsetIterator_getKey(&libs_it);
-
- BLO_library_path_explode(libpath, libname, &group, NULL);
-
- wm_link_append_do_libgroup(C, op, root, libname, group, NULL, flag, &todo_libraries);
- }
-
- BLI_gset_free(todo_libraries, MEM_freeN);
- }
-
- /* important we unset, otherwise these object wont
- * link into other scenes from this blend file */
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free();
-
- /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
- BLI_strncpy(G.lib, root, FILE_MAX);
-
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
-{
- PropertyRNA *prop;
-
- /* better not save _any_ settings for this operator */
- /* properties */
- prop = RNA_def_boolean(ot->srna, "link", is_link,
- "Link", "Link the objects or datablocks rather than appending");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
- prop = RNA_def_boolean(ot->srna, "autoselect", true,
- "Select", "Select new objects");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "active_layer", true,
- "Active Layer", "Put new objects on the active layer");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
- "Instance Groups", "Create Dupli-Group instances for each group");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-static void WM_OT_link(wmOperatorType *ot)
-{
- ot->name = "Link from Library";
- ot->idname = "WM_OT_link";
- ot->description = "Link from a Library .blend file";
-
- ot->invoke = wm_link_append_invoke;
- ot->exec = wm_link_append_exec;
- ot->poll = wm_link_append_poll;
-
- ot->flag |= OPTYPE_UNDO;
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
- wm_link_append_properties_common(ot, true);
-}
-
-static void WM_OT_append(wmOperatorType *ot)
-{
- ot->name = "Append from Library";
- ot->idname = "WM_OT_append";
- ot->description = "Append from a Library .blend file";
-
- ot->invoke = wm_link_append_invoke;
- ot->exec = wm_link_append_exec;
- ot->poll = wm_link_append_poll;
-
- ot->flag |= OPTYPE_UNDO;
-
- WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
-
- wm_link_append_properties_common(ot, false);
-}
-
-/* *************** recover last session **************** */
-
-void WM_recover_last_session(bContext *C, ReportList *reports)
-{
- char filepath[FILE_MAX];
-
- BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE);
- /* if reports==NULL, it's called directly without operator, we add a quick check here */
- if (reports || BLI_exists(filepath)) {
- G.fileflags |= G_FILE_RECOVER;
-
- wm_file_read_opwrap(C, filepath, reports, true);
-
- G.fileflags &= ~G_FILE_RECOVER;
-
- /* XXX bad global... fixme */
- if (G.main->name[0])
- G.file_loaded = 1; /* prevents splash to show */
- else {
- G.relbase_valid = 0;
- G.save_over = 0; /* start with save preference untitled.blend */
- }
-
- }
-}
-
-static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
-{
- WM_recover_last_session(C, op->reports);
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_recover_last_session(wmOperatorType *ot)
-{
- ot->name = "Recover Last Session";
- ot->idname = "WM_OT_recover_last_session";
- ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")";
- ot->invoke = WM_operator_confirm;
-
- ot->exec = wm_recover_last_session_exec;
-}
-
-/* *************** recover auto save **************** */
-
-static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
-{
- char filepath[FILE_MAX];
- bool success;
-
- RNA_string_get(op->ptr, "filepath", filepath);
-
- G.fileflags |= G_FILE_RECOVER;
-
- success = wm_file_read_opwrap(C, filepath, op->reports, true);
-
- G.fileflags &= ~G_FILE_RECOVER;
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- char filename[FILE_MAX];
-
- wm_autosave_location(filename);
- RNA_string_set(op->ptr, "filepath", filename);
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void WM_OT_recover_auto_save(wmOperatorType *ot)
-{
- ot->name = "Recover Auto Save";
- ot->idname = "WM_OT_recover_auto_save";
- ot->description = "Open an automatically saved file to recover it";
-
- ot->exec = wm_recover_auto_save_exec;
- ot->invoke = wm_recover_auto_save_invoke;
-
- WM_operator_properties_filesel(ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_LONGDISPLAY, FILE_SORT_TIME);
-}
-
-/* *************** save file as **************** */
-
-static void wm_filepath_default(char *filepath)
-{
- if (G.save_over == false) {
- BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend");
- }
-}
-
-static void save_set_compress(wmOperator *op)
-{
- PropertyRNA *prop;
-
- prop = RNA_struct_find_property(op->ptr, "compress");
- if (!RNA_property_is_set(op->ptr, prop)) {
- if (G.save_over) { /* keep flag for existing file */
- RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0);
- }
- else { /* use userdef for new file */
- RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0);
- }
- }
-}
-
-static void save_set_filepath(wmOperator *op)
-{
- PropertyRNA *prop;
- char name[FILE_MAX];
-
- prop = RNA_struct_find_property(op->ptr, "filepath");
- if (!RNA_property_is_set(op->ptr, prop)) {
- /* if not saved before, get the name of the most recently used .blend file */
- if (G.main->name[0] == 0 && G.recent_files.first) {
- struct RecentFile *recent = G.recent_files.first;
- BLI_strncpy(name, recent->filepath, FILE_MAX);
- }
- else {
- BLI_strncpy(name, G.main->name, FILE_MAX);
- }
-
- wm_filepath_default(name);
- RNA_property_string_set(op->ptr, prop, name);
- }
-}
-
-static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
-
- save_set_compress(op);
- save_set_filepath(op);
-
- WM_event_add_fileselect(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* function used for WM_OT_save_mainfile too */
-static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
-{
- char path[FILE_MAX];
- int fileflags;
-
- save_set_compress(op);
-
- if (RNA_struct_property_is_set(op->ptr, "filepath")) {
- RNA_string_get(op->ptr, "filepath", path);
- }
- else {
- BLI_strncpy(path, G.main->name, FILE_MAX);
- wm_filepath_default(path);
- }
-
- fileflags = G.fileflags & ~G_FILE_USERPREFS;
-
- /* set compression flag */
- BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "compress"),
- G_FILE_COMPRESS);
- BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "relative_remap"),
- G_FILE_RELATIVE_REMAP);
- BKE_BIT_TEST_SET(fileflags,
- (RNA_struct_property_is_set(op->ptr, "copy") &&
- RNA_boolean_get(op->ptr, "copy")),
- G_FILE_SAVE_COPY);
-
-#ifdef USE_BMESH_SAVE_AS_COMPAT
- BKE_BIT_TEST_SET(fileflags,
- (RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
- RNA_boolean_get(op->ptr, "use_mesh_compat")),
- G_FILE_MESH_COMPAT);
-#else
-# error "don't remove by accident"
-#endif
-
- if (wm_file_write(C, path, fileflags, op->reports) != 0)
- return OPERATOR_CANCELLED;
-
- WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-/* function used for WM_OT_save_mainfile too */
-static bool blend_save_check(bContext *UNUSED(C), wmOperator *op)
-{
- char filepath[FILE_MAX];
- RNA_string_get(op->ptr, "filepath", filepath);
- if (!BLO_has_bfile_extension(filepath)) {
- /* some users would prefer BLI_replace_extension(),
- * we keep getting nitpicking bug reports about this - campbell */
- BLI_ensure_extension(filepath, FILE_MAX, ".blend");
- RNA_string_set(op->ptr, "filepath", filepath);
- return true;
- }
- return false;
-}
-
-static void WM_OT_save_as_mainfile(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- ot->name = "Save As Blender File";
- ot->idname = "WM_OT_save_as_mainfile";
- ot->description = "Save the current file in the desired location";
-
- ot->invoke = wm_save_as_mainfile_invoke;
- ot->exec = wm_save_as_mainfile_exec;
- ot->check = blend_save_check;
- /* omit window poll so this can work in background mode */
-
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
- RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative",
- "Remap relative paths when saving in a different directory");
- prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy",
- "Save a copy of the actual working state but does not make saved file active");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-#ifdef USE_BMESH_SAVE_AS_COMPAT
- RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format",
- "Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will "
- "be lost (no implicit triangulation)");
-#endif
-}
-
-/* *************** save file directly ******** */
-
-static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- int ret;
-
- /* cancel if no active window */
- if (CTX_wm_window(C) == NULL)
- return OPERATOR_CANCELLED;
-
- save_set_compress(op);
- save_set_filepath(op);
-
- /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute,
- * enable the option to remap paths to avoid confusion [#37240] */
- if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) {
- PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap");
- if (!RNA_property_is_set(op->ptr, prop)) {
- RNA_property_boolean_set(op->ptr, prop, true);
- }
- }
-
- if (G.save_over) {
- char path[FILE_MAX];
-
- RNA_string_get(op->ptr, "filepath", path);
- if (BLI_exists(path)) {
- ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path);
- }
- else {
- ret = wm_save_as_mainfile_exec(C, op);
- }
- }
- else {
- WM_event_add_fileselect(C, op);
- ret = OPERATOR_RUNNING_MODAL;
- }
-
- return ret;
-}
-
-static void WM_OT_save_mainfile(wmOperatorType *ot)
-{
- ot->name = "Save Blender File";
- ot->idname = "WM_OT_save_mainfile";
- ot->description = "Save the current Blender file";
-
- ot->invoke = wm_save_mainfile_invoke;
- ot->exec = wm_save_as_mainfile_exec;
- ot->check = blend_save_check;
- /* omit window poll so this can work in background mode */
-
- WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
- RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
- RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
- "Remap relative paths when saving in a different directory");
-}
-
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
{
ot->name = "Toggle Window Fullscreen";
@@ -3936,7 +2852,9 @@ typedef struct {
PropertyType type;
PropertySubType subtype;
PointerRNA ptr, col_ptr, fill_col_ptr, rot_ptr, zoom_ptr, image_id_ptr;
+ PointerRNA fill_col_override_ptr, fill_col_override_test_ptr;
PropertyRNA *prop, *col_prop, *fill_col_prop, *rot_prop, *zoom_prop;
+ PropertyRNA *fill_col_override_prop, *fill_col_override_test_prop;
StructRNA *image_id_srna;
float initial_value, current_value, min_value, max_value;
int initial_mouse[2];
@@ -3956,12 +2874,39 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
char msg[WM_RADIAL_CONTROL_HEADER_LENGTH];
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
-
- if (sa && hasNumInput(&rc->num_input)) {
- char num_str[NUM_STR_REP_LEN];
- outputNumInput(&rc->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %s", RNA_property_ui_name(rc->prop), num_str);
- ED_area_headerprint(sa, msg);
+
+ if (sa) {
+ if (hasNumInput(&rc->num_input)) {
+ char num_str[NUM_STR_REP_LEN];
+ outputNumInput(&rc->num_input, num_str, &scene->unit);
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %s", RNA_property_ui_name(rc->prop), num_str);
+ ED_area_headerprint(sa, msg);
+ }
+ else {
+ const char *ui_name = RNA_property_ui_name(rc->prop);
+ switch (rc->subtype) {
+ case PROP_NONE:
+ case PROP_DISTANCE:
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %0.4f", ui_name, rc->current_value);
+ break;
+ case PROP_PIXEL:
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
+ break;
+ case PROP_PERCENTAGE:
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %3.1f%%", ui_name, rc->current_value);
+ break;
+ case PROP_FACTOR:
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %1.3f", ui_name, rc->current_value);
+ break;
+ case PROP_ANGLE:
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
+ break;
+ default:
+ BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s", ui_name); /* XXX: No value? */
+ break;
+ }
+ ED_area_headerprint(sa, msg);
+ }
}
}
@@ -4012,7 +2957,7 @@ static void radial_control_set_tex(RadialControl *rc)
if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) {
glGenTextures(1, &rc->gltex);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, ibuf->x, ibuf->y, 0,
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, ibuf->x, ibuf->y, 0,
GL_ALPHA, GL_FLOAT, ibuf->rect_float);
MEM_freeN(ibuf->rect_float);
MEM_freeN(ibuf);
@@ -4029,8 +2974,23 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
float rot;
/* set fill color */
- if (rc->fill_col_prop)
- RNA_property_float_get_array(&rc->fill_col_ptr, rc->fill_col_prop, col);
+ if (rc->fill_col_prop) {
+ PointerRNA *fill_ptr;
+ PropertyRNA *fill_prop;
+
+ if (rc->fill_col_override_prop &&
+ RNA_property_boolean_get(&rc->fill_col_override_test_ptr, rc->fill_col_override_test_prop))
+ {
+ fill_ptr = &rc->fill_col_override_ptr;
+ fill_prop = rc->fill_col_override_prop;
+ }
+ else {
+ fill_ptr = &rc->fill_col_ptr;
+ fill_prop = rc->fill_col_prop;
+ }
+
+ RNA_property_float_get_array(fill_ptr, fill_prop, col);
+ }
glColor4f(col[0], col[1], col[2], alpha);
if (rc->gltex) {
@@ -4047,7 +3007,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
}
/* draw textured quad */
- glEnable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(-radius, -radius);
@@ -4058,7 +3018,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
glTexCoord2f(0, 1);
glVertex2f(-radius, radius);
glEnd();
- glDisable(GL_TEXTURE_2D);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
/* undo rotation */
if (rc->rot_prop)
@@ -4107,14 +3067,14 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
alpha = rc->current_value / 2.0f + 0.5f;
- BLI_snprintf(str, WM_RADIAL_MAX_STR, "%1.2f", rc->current_value);
+ BLI_snprintf(str, WM_RADIAL_MAX_STR, "%1.3f", rc->current_value);
strdrawlen = BLI_strlen_utf8(str);
break;
case PROP_ANGLE:
r1 = r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE;
alpha = 0.75;
rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
- BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3f", RAD2DEGF(rc->current_value));
+ BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3.2f", RAD2DEGF(rc->current_value));
strdrawlen = BLI_strlen_utf8(str);
break;
default:
@@ -4163,12 +3123,12 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), rmin, 40);
BLF_size(fontid, 1.5 * fstyle_points, 1.0f / U.dpi);
- BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
BLF_enable(fontid, BLF_SHADOW);
BLF_shadow(fontid, 3, 0.0f, 0.0f, 0.0f, 0.5f);
BLF_shadow_offset(fontid, 1, -1);
/* draw value */
+ BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
BLF_draw(fontid, str, strdrawlen);
@@ -4294,9 +3254,27 @@ static int radial_control_get_properties(bContext *C, wmOperator *op)
return 0;
if (!radial_control_get_path(&ctx_ptr, op, "color_path", &rc->col_ptr, &rc->col_prop, 3, RC_PROP_REQUIRE_FLOAT))
return 0;
- if (!radial_control_get_path(&ctx_ptr, op, "fill_color_path", &rc->fill_col_ptr, &rc->fill_col_prop, 3, RC_PROP_REQUIRE_FLOAT))
+
+
+ if (!radial_control_get_path(
+ &ctx_ptr, op, "fill_color_path", &rc->fill_col_ptr, &rc->fill_col_prop, 3, RC_PROP_REQUIRE_FLOAT))
+ {
return 0;
-
+ }
+
+ if (!radial_control_get_path(
+ &ctx_ptr, op, "fill_color_override_path",
+ &rc->fill_col_override_ptr, &rc->fill_col_override_prop, 3, RC_PROP_REQUIRE_FLOAT))
+ {
+ return 0;
+ }
+ if (!radial_control_get_path(
+ &ctx_ptr, op, "fill_color_override_test_path",
+ &rc->fill_col_override_test_ptr, &rc->fill_col_override_test_prop, 0, RC_PROP_REQUIRE_BOOL))
+ {
+ return 0;
+ }
+
/* slightly ugly; allow this property to not resolve
* correctly. needed because 3d texture paint shares the same
* keymap as 2d image paint */
@@ -4635,6 +3613,7 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
}
ED_region_tag_redraw(CTX_wm_region(C));
+ radial_control_update_header(op, C);
if (ret != OPERATOR_RUNNING_MODAL)
radial_control_cancel(C, op);
@@ -4667,6 +3646,9 @@ static void WM_OT_radial_control(wmOperatorType *ot)
RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control");
+ RNA_def_string(ot->srna, "fill_color_override_path", NULL, 0, "Fill Color Override Path", "");
+ RNA_def_string(ot->srna, "fill_color_override_test_path", NULL, 0, "Fill Color Override Test", "");
+
RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control");
RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control");
@@ -4884,12 +3866,10 @@ static void WM_OT_dependency_relations(wmOperatorType *ot)
/* *************************** Mat/tex/etc. previews generation ************* */
-typedef struct PreviewsIDEnsureStack {
+typedef struct PreviewsIDEnsureData {
bContext *C;
Scene *scene;
-
- BLI_LINKSTACK_DECLARE(id_stack, ID *);
-} PreviewsIDEnsureStack;
+} PreviewsIDEnsureData;
static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
{
@@ -4903,55 +3883,51 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
}
}
-static bool previews_id_ensure_callback(void *todo_v, ID **idptr, int UNUSED(cd_flag))
+static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int UNUSED(cd_flag))
{
- PreviewsIDEnsureStack *todo = todo_v;
+ PreviewsIDEnsureData *data = userdata;
ID *id = *idptr;
- if (id && (id->flag & LIB_DOIT)) {
- if (ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)) {
- previews_id_ensure(todo->C, todo->scene, id);
- }
- id->flag &= ~LIB_DOIT; /* Tag the ID as done in any case. */
- BLI_LINKSTACK_PUSH(todo->id_stack, id);
+ if (id && (id->tag & LIB_TAG_DOIT)) {
+ BLI_assert(ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA));
+ previews_id_ensure(data->C, data->scene, id);
+ id->tag &= ~LIB_TAG_DOIT;
}
- return true;
+ return IDWALK_RET_NOP;
}
static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
ListBase *lb[] = {&bmain->mat, &bmain->tex, &bmain->image, &bmain->world, &bmain->lamp, NULL};
- PreviewsIDEnsureStack preview_id_stack;
+ PreviewsIDEnsureData preview_id_data;
Scene *scene;
ID *id;
int i;
- /* We use LIB_DOIT to check whether we have already handled a given ID or not. */
- BKE_main_id_flag_all(bmain, LIB_DOIT, true);
-
- BLI_LINKSTACK_INIT(preview_id_stack.id_stack);
+ /* We use LIB_TAG_DOIT to check whether we have already handled a given ID or not. */
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ for (i = 0; lb[i]; i++) {
+ BKE_main_id_tag_listbase(lb[i], LIB_TAG_DOIT, true);
+ }
+ preview_id_data.C = C;
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
- preview_id_stack.scene = scene;
- preview_id_stack.C = C;
+ preview_id_data.scene = scene;
id = (ID *)scene;
- do {
- /* This will loop over all IDs linked by current one, render icons for them if needed,
- * and add them to 'todo' preview_id_stack. */
- BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_stack, IDWALK_READONLY);
- } while ((id = BLI_LINKSTACK_POP(preview_id_stack.id_stack)));
+ BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
}
- BLI_LINKSTACK_FREE(preview_id_stack.id_stack);
-
/* Check a last time for ID not used (fake users only, in theory), and
* do our best for those, using current scene... */
for (i = 0; lb[i]; i++) {
for (id = lb[i]->first; id; id = id->next) {
- previews_id_ensure(C, NULL, id);
+ if (id->tag & LIB_TAG_DOIT) {
+ previews_id_ensure(C, NULL, id);
+ id->tag &= ~LIB_TAG_DOIT;
+ }
}
}
@@ -5028,7 +4004,7 @@ static void WM_OT_previews_clear(wmOperatorType *ot)
ot->prop = RNA_def_enum_flag(ot->srna, "id_type", preview_id_type_items,
FILTER_ID_SCE | FILTER_ID_OB | FILTER_ID_GR |
- FILTER_ID_MA | FILTER_ID_LA | FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM,
+ FILTER_ID_MA | FILTER_ID_LA | FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM,
"DataBlock Type", "Which datablock previews to clear");
}
@@ -5101,11 +4077,11 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
ot->check = wm_stereo3d_set_check;
ot->cancel = wm_stereo3d_set_cancel;
- prop = RNA_def_enum(ot->srna, "display_mode", stereo3d_display_items, S3D_DISPLAY_ANAGLYPH, "Display Mode", "");
+ prop = RNA_def_enum(ot->srna, "display_mode", rna_enum_stereo3d_display_items, S3D_DISPLAY_ANAGLYPH, "Display Mode", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_enum(ot->srna, "anaglyph_type", stereo3d_anaglyph_type_items, S3D_ANAGLYPH_REDCYAN, "Anaglyph Type", "");
+ prop = RNA_def_enum(ot->srna, "anaglyph_type", rna_enum_stereo3d_anaglyph_type_items, S3D_ANAGLYPH_REDCYAN, "Anaglyph Type", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_enum(ot->srna, "interlace_type", stereo3d_interlace_type_items, S3D_INTERLACE_ROW, "Interlace Type", "");
+ prop = RNA_def_enum(ot->srna, "interlace_type", rna_enum_stereo3d_interlace_type_items, S3D_INTERLACE_ROW, "Interlace Type", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "use_interlace_swap", false, "Swap Left/Right",
"Swap left and right stereo channels");
@@ -5129,6 +4105,7 @@ void wm_operatortype_init(void)
/* reserve size is set based on blender default setup */
global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048);
+ WM_operatortype_append(WM_OT_window_close);
WM_operatortype_append(WM_OT_window_duplicate);
WM_operatortype_append(WM_OT_read_history);
WM_operatortype_append(WM_OT_read_homefile);
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index bf30fd83736..675958cf0a3 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -383,7 +383,6 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
// short val;
PlayAnimPict *picture = NULL;
struct ImBuf *ibuf = NULL;
- char str[32 + FILE_MAX];
struct anim *anim;
if (IMB_isanim(first)) {
@@ -402,8 +401,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
picture->anim = anim;
picture->frame = pic;
picture->IB_flags = IB_rect;
- BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1);
- picture->name = strdup(str);
+ picture->name = BLI_sprintfN("%s : %4.d", first, pic + 1);
BLI_addtail(&picsbase, picture);
}
}
@@ -414,7 +412,14 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
else {
int count = 0;
+ int fp_framenr;
+ struct {
+ char head[FILE_MAX], tail[FILE_MAX];
+ unsigned short digits;
+ } fp_decoded;
+
BLI_strncpy(filepath, first, sizeof(filepath));
+ fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
pupdate_time();
ptottime = 1.0;
@@ -480,8 +485,8 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
}
picture->mem = mem;
- picture->name = strdup(filepath);
- picture->frame = count; /* not exact but should work for positioning */
+ picture->name = BLI_strdup(filepath);
+ picture->frame = count;
close(file);
BLI_addtail(&picsbase, picture);
count++;
@@ -505,7 +510,9 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
ptottime = 0.0;
}
- BLI_newname(filepath, +fstep);
+ /* create a new filepath each time */
+ fp_framenr += fstep;
+ BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) {
if (hasevent) {
@@ -544,17 +551,16 @@ static void update_sound_fps(void)
static void change_frame(PlayState *ps, int cx)
{
int sizex, sizey;
- int i;
+ int i, i_last;
- playanim_window_get_size(&sizex, &sizey);
- ps->picture = picsbase.first;
- /* TODO - store in ps direct? */
- i = 0;
- while (ps->picture) {
- i++;
- ps->picture = ps->picture->next;
+ if (BLI_listbase_is_empty(&picsbase)) {
+ return;
}
- i = (i * cx) / sizex;
+
+ playanim_window_get_size(&sizex, &sizey);
+ i_last = ((struct PlayAnimPict *)picsbase.last)->frame;
+ i = (i_last * cx) / sizex;
+ CLAMP(i, 0, i_last);
#ifdef WITH_AUDASPACE
if (scrub_handle) {
@@ -588,11 +594,8 @@ static void change_frame(PlayState *ps, int cx)
}
#endif
- ps->picture = picsbase.first;
- for (; i > 0; i--) {
- if (ps->picture->next == NULL) break;
- ps->picture = ps->picture->next;
- }
+ ps->picture = BLI_findlink(&picsbase, i);
+ BLI_assert(ps->picture != NULL);
ps->sstep = true;
ps->wait2 = false;
@@ -977,6 +980,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
int cx, cy;
+ /* Ignore 'in-between' events, since they can make scrubbing lag.
+ *
+ * Ideally we would keep into the event queue and see if this is the last motion event.
+ * however the API currently doesn't support this. */
+ {
+ int x_test, y_test;
+ GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test);
+ if (x_test != cd->x || y_test != cd->y) {
+ /* we're not the last event... skipping */
+ break;
+ }
+ }
+
GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
change_frame(ps, cx);
@@ -1093,7 +1109,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GHOST_TUns32 maxwinx, maxwiny;
int i;
/* This was done to disambiguate the name for use under c++. */
- struct anim *anim = NULL;
int start_x = 0, start_y = 0;
int sfra = -1;
int efra = -1;
@@ -1194,12 +1209,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
BLI_strncpy(filepath, argv[1], sizeof(filepath));
}
else {
- BLI_current_working_dir(filepath, sizeof(filepath));
- BLI_add_slash(filepath);
+ printf("%s: no filepath argument given\n", __func__);
+ exit(1);
}
if (IMB_isanim(filepath)) {
/* OCIO_TODO: support different input color spaces */
+ struct anim *anim;
anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
if (anim) {
ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
@@ -1222,12 +1238,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
exit(1);
}
-#if 0 //XXX25
-#if !defined(WIN32) && !defined(__APPLE__)
- if (fork()) exit(0);
-#endif
-#endif //XXX25
-
{
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
@@ -1471,13 +1481,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
}
}
- ps.picture = picsbase.first;
- anim = NULL;
- while (ps.picture) {
- if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
- // to prevent divx crashes
- anim = ps.picture->anim;
- IMB_close_anim(anim);
+ while ((ps.picture = BLI_pophead(&picsbase))) {
+ if (ps.picture->anim) {
+ if ((ps.picture->next == NULL) ||
+ (ps.picture->next->anim != ps.picture->anim))
+ {
+ IMB_close_anim(ps.picture->anim);
+ }
}
if (ps.picture->ibuf) {
@@ -1487,7 +1497,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
MEM_freeN(ps.picture->mem);
}
- ps.picture = ps.picture->next;
+ MEM_freeN((void *)ps.picture->name);
+ MEM_freeN(ps.picture);
}
/* cleanup */
@@ -1511,15 +1522,11 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
AUD_Sound_free(source);
source = NULL;
#endif
-
-#if 0 // XXX25
- free_blender();
-#else
/* we still miss freeing a lot!,
* but many areas could skip initialization too for anim play */
BLF_exit();
-#endif
+
GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
/* early exit, IMB and BKE should be exited only in end */
@@ -1554,7 +1561,7 @@ void WM_main_playanim(int argc, const char **argv)
{
AUD_DeviceSpecs specs;
- specs.rate = AUD_RATE_44100;
+ specs.rate = AUD_RATE_48000;
specs.format = AUD_FORMAT_S16;
specs.channels = AUD_CHANNELS_STEREO;
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 98c45bfb6ea..5576a104123 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -53,6 +53,7 @@
#include "ED_screen.h"
#include "GPU_glew.h"
+#include "GPU_basic_shader.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -82,76 +83,48 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
glDrawBuffer(GL_BACK);
}
-static GLuint left_interlace_mask[32];
-static GLuint right_interlace_mask[32];
static enum eStereo3dInterlaceType interlace_prev_type = -1;
static char interlace_prev_swap = -1;
-static void wm_interlace_masks_create(wmWindow *win)
-{
- GLuint pattern;
- char i;
- bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
- enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
-
- if (interlace_prev_type == interlace_type && interlace_prev_swap == swap)
- return;
-
- switch (interlace_type) {
- case S3D_INTERLACE_ROW:
- pattern = 0x00000000;
- pattern = swap ? ~pattern : pattern;
- for (i = 0; i < 32; i += 2) {
- left_interlace_mask[i] = pattern;
- right_interlace_mask[i] = ~pattern;
- }
- for (i = 1; i < 32; i += 2) {
- left_interlace_mask[i] = ~pattern;
- right_interlace_mask[i] = pattern;
- }
- break;
- case S3D_INTERLACE_COLUMN:
- pattern = 0x55555555;
- pattern = swap ? ~pattern : pattern;
- for (i = 0; i < 32; i++) {
- left_interlace_mask[i] = pattern;
- right_interlace_mask[i] = ~pattern;
- }
- break;
- case S3D_INTERLACE_CHECKERBOARD:
- default:
- pattern = 0x55555555;
- pattern = swap ? ~pattern : pattern;
- for (i = 0; i < 32; i += 2) {
- left_interlace_mask[i] = pattern;
- right_interlace_mask[i] = ~pattern;
- }
- for (i = 1; i < 32; i += 2) {
- left_interlace_mask[i] = ~pattern;
- right_interlace_mask[i] = pattern;
- }
- break;
- }
- interlace_prev_type = interlace_type;
- interlace_prev_swap = swap;
-}
-
static void wm_method_draw_stereo3d_interlace(wmWindow *win)
{
wmDrawData *drawdata;
int view;
-
- wm_interlace_masks_create(win);
+ bool flag;
+ bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
+ enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
for (view = 0; view < 2; view ++) {
+ flag = swap ? !view : view;
drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
-
- glEnable(GL_POLYGON_STIPPLE);
- glPolygonStipple(view ? (GLubyte *) right_interlace_mask : (GLubyte *) left_interlace_mask);
+ GPU_basic_shader_bind(GPU_SHADER_STIPPLE);
+ switch (interlace_type) {
+ case S3D_INTERLACE_ROW:
+ if (flag)
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP);
+ else
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW);
+ break;
+ case S3D_INTERLACE_COLUMN:
+ if (flag)
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP);
+ else
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN);
+ break;
+ case S3D_INTERLACE_CHECKERBOARD:
+ default:
+ if (flag)
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP);
+ else
+ GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER);
+ break;
+ }
wm_triple_draw_textures(win, drawdata->triple, 1.0f);
- glDisable(GL_POLYGON_STIPPLE);
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
+ interlace_prev_type = interlace_type;
+ interlace_prev_swap = swap;
}
static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
@@ -195,7 +168,6 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
wmDrawData *drawdata;
wmDrawTriple *triple;
float halfx, halfy, ratiox, ratioy;
- int x, y, offx, offy;
float alpha = 1.0f;
int view;
int soffx;
@@ -217,44 +189,40 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
glEnable(triple->target);
- for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
- for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
- const int sizex = triple->x[x];
- const int sizey = triple->y[y];
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x[x];
- ratioy /= triple->y[y];
- halfx /= triple->x[x];
- halfy /= triple->y[y];
- }
-
- glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
-
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(soffx + (offx * 0.5f), offy);
-
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(soffx + ((offx + sizex) * 0.5f), offy);
-
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(soffx + ((offx + sizex) * 0.5f), offy + sizey);
-
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(soffx + (offx * 0.5f), offy + sizey);
- glEnd();
- }
+ const int sizex = triple->x;
+ const int sizey = triple->y;
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x;
+ ratioy /= triple->y;
+ halfx /= triple->x;
+ halfy /= triple->y;
}
+ glBindTexture(triple->target, triple->bind);
+
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(soffx, 0);
+
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(soffx + (sizex * 0.5f), 0);
+
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(soffx + (sizex * 0.5f), sizey);
+
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(soffx, sizey);
+ glEnd();
+
glBindTexture(triple->target, 0);
glDisable(triple->target);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -266,7 +234,6 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
wmDrawData *drawdata;
wmDrawTriple *triple;
float halfx, halfy, ratiox, ratioy;
- int x, y, offx, offy;
float alpha = 1.0f;
int view;
int soffy;
@@ -284,44 +251,40 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
glEnable(triple->target);
- for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
- for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
- const int sizex = triple->x[x];
- const int sizey = triple->y[y];
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x[x];
- ratioy /= triple->y[y];
- halfx /= triple->x[x];
- halfy /= triple->y[y];
- }
-
- glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
-
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(offx, soffy + (offy * 0.5f));
-
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(offx + sizex, soffy + (offy * 0.5f));
-
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(offx + sizex, soffy + ((offy + sizey) * 0.5f));
-
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(offx, soffy + ((offy + sizey) * 0.5f));
- glEnd();
- }
+ const int sizex = triple->x;
+ const int sizey = triple->y;
+
+ /* wmOrtho for the screen has this same offset */
+ ratiox = sizex;
+ ratioy = sizey;
+ halfx = GLA_PIXEL_OFS;
+ halfy = GLA_PIXEL_OFS;
+
+ /* texture rectangle has unnormalized coordinates */
+ if (triple->target == GL_TEXTURE_2D) {
+ ratiox /= triple->x;
+ ratioy /= triple->y;
+ halfx /= triple->x;
+ halfy /= triple->y;
}
+ glBindTexture(triple->target, triple->bind);
+
+ glColor4f(1.0f, 1.0f, 1.0f, alpha);
+ glBegin(GL_QUADS);
+ glTexCoord2f(halfx, halfy);
+ glVertex2f(0, soffy);
+
+ glTexCoord2f(ratiox + halfx, halfy);
+ glVertex2f(sizex, soffy);
+
+ glTexCoord2f(ratiox + halfx, ratioy + halfy);
+ glVertex2f(sizex, soffy + (sizey * 0.5f));
+
+ glTexCoord2f(halfx, ratioy + halfy);
+ glVertex2f(0, soffy + (sizey * 0.5f));
+ glEnd();
+
glBindTexture(triple->target, 0);
glDisable(triple->target);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 7dade62347c..6526d419914 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -48,6 +48,7 @@
#include "BIF_gl.h"
#include "GPU_extensions.h"
+#include "GPU_basic_shader.h"
#include "WM_api.h"
#include "wm_subwindow.h"
@@ -192,7 +193,7 @@ void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect)
/* always sets pixel-precise 2D window/view matrices */
/* coords is in whole pixels. xmin = 15, xmax = 16: means window is 2 pix big */
-int wm_subwindow_open(wmWindow *win, const rcti *winrct)
+int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate)
{
wmSubWindow *swin;
int width, height;
@@ -208,18 +209,19 @@ int wm_subwindow_open(wmWindow *win, const rcti *winrct)
swin->swinid = freewinid;
swin->winrct = *winrct;
- /* and we appy it all right away */
- wmSubWindowSet(win, swin->swinid);
-
- /* extra service */
- wm_swin_size_get(swin, &width, &height);
- wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
+ if (activate) {
+ /* and we appy it all right away */
+ wmSubWindowSet(win, swin->swinid);
+
+ /* extra service */
+ wm_swin_size_get(swin, &width, &height);
+ wmOrtho2_pixelspace(width, height);
+ glLoadIdentity();
+ }
return swin->swinid;
}
-
void wm_subwindow_close(wmWindow *win, int swinid)
{
wmSubWindow *swin = swin_from_swinid(win, swinid);
@@ -237,7 +239,7 @@ void wm_subwindow_close(wmWindow *win, int swinid)
}
/* pixels go from 0-99 for a 100 pixel window */
-void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct)
+void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct, bool activate)
{
wmSubWindow *swin = swin_from_swinid(win, swinid);
@@ -267,10 +269,12 @@ void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct)
if (swin->winrct.ymax > winsize_y)
swin->winrct.ymax = winsize_y;
- /* extra service */
- wmSubWindowSet(win, swinid);
- wm_swin_size_get(swin, &width, &height);
- wmOrtho2_pixelspace(width, height);
+ if (activate) {
+ /* extra service */
+ wmSubWindowSet(win, swinid);
+ wm_swin_size_get(swin, &width, &height);
+ wmOrtho2_pixelspace(width, height);
+ }
}
else {
printf("%s: Internal error, bad winid: %d\n", __func__, swinid);
@@ -364,7 +368,7 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
/**
* default pixel alignment.
*/
-void wmOrtho2_region_pixelspace(const struct ARegion *ar)
+void wmOrtho2_region_pixelspace(const ARegion *ar)
{
wmOrtho2_offset(ar->winx, ar->winy, -0.01f);
}
@@ -374,17 +378,6 @@ void wmOrtho2_pixelspace(const float x, const float y)
wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
}
-/**
- * use for drawing uiBlock, any UI elements and text.
- * \note prevents blurry text with multi-sample (FSAA), see T41749
- */
-void wmOrtho2_region_ui(const ARegion *ar)
-{
- /* note, intentionally no '+ 1',
- * as with wmOrtho2_region_pixelspace */
- wmOrtho2_offset(ar->winx, ar->winy, -0.01f);
-}
-
/* *************************** Framebuffer color depth, for selection codes ********************** */
#ifdef __APPLE__
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index a03f2c22055..688be21cdd0 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -163,6 +163,7 @@ static void wm_ghostwindow_destroy(wmWindow *win)
if (win->ghostwin) {
GHOST_DisposeWindow(g_system, win->ghostwin);
win->ghostwin = NULL;
+ win->multisamples = 0;
}
}
@@ -329,12 +330,17 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
CTX_wm_window_set(C, win); /* needed by handlers */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+
+ /* for regular use this will _never_ be NULL,
+ * however we may be freeing an improperly initialized window. */
+ if (win->screen) {
+ ED_screen_exit(C, win, win->screen);
+ }
wm_window_free(C, wm, win);
/* if temp screen, delete it after window free (it stops jobs that can access it) */
- if (screen->temp) {
+ if (screen && screen->temp) {
Main *bmain = CTX_data_main(C);
BKE_libblock_free(bmain, screen);
}
@@ -366,21 +372,18 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
+static float wm_window_get_virtual_pixelsize(void)
+{
+ return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
+}
+
float wm_window_pixelsize(wmWindow *win)
{
- float pixelsize = GHOST_GetNativePixelSize(win->ghostwin);
-
- switch (U.virtual_pixel) {
- default:
- case VIRTUAL_PIXEL_NATIVE:
- return pixelsize;
- case VIRTUAL_PIXEL_DOUBLE:
- return 2.0f * pixelsize;
- }
+ return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
}
/* belongs to below */
-static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wmWindow *win)
+static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win)
{
GHOST_WindowHandle ghostwin;
GHOST_GLSettings glSettings = {0};
@@ -402,15 +405,17 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm
glSettings.flags |= GHOST_glDebugContext;
}
- if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT))
- glSettings.flags |= GHOST_glWarnSupport;
-
wm_get_screensize(&scr_w, &scr_h);
posy = (scr_h - win->posy - win->sizey);
ghostwin = GHOST_CreateWindow(g_system, title,
win->posx, posy, win->sizex, win->sizey,
+#ifdef __APPLE__
+ /* we agreed to not set any fullscreen or iconized state on startup */
+ GHOST_kWindowStateNormal,
+#else
(GHOST_TWindowState)win->windowstate,
+#endif
GHOST_kDrawingContextTypeOpenGL,
glSettings);
@@ -428,12 +433,10 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm
if (win->eventstate == NULL)
win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
+
+ /* store multisamples window was created with, in case user prefs change */
+ win->multisamples = multisamples;
-#ifdef __APPLE__
- /* set the state here, else OSX would not recognize changed screen resolution */
- /* we agreed to not set any fullscreen or iconized state on startup */
- GHOST_SetWindowState(ghostwin, GHOST_kWindowStateNormal);
-#endif
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
win->sizex = GHOST_GetWidthRectangle(bounds);
@@ -466,14 +469,26 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm
}
}
-/* for wmWindows without ghostwin, open these and clear */
-/* window size is read from window, if 0 it uses prefsize */
-/* called in WM_check, also inits stuff after file read */
-void wm_window_add_ghostwindows(wmWindowManager *wm)
+/**
+ * Initialize #wmWindows without ghostwin, open these and clear.
+ *
+ * window size is read from window, if 0 it uses prefsize
+ * called in #WM_check, also inits stuff after file read.
+ *
+ * \warning
+ * After running, 'win->ghostwin' can be NULL in rare cases
+ * (where OpenGL driver fails to create a context for eg).
+ * We could remove them with #wm_window_ghostwindows_remove_invalid
+ * but better not since caller may continue to use.
+ * Instead, caller needs to handle the error case and cleanup.
+ */
+void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
wmKeyMap *keymap;
wmWindow *win;
+ BLI_assert(G.background == false);
+
/* no commandline prefsize? then we set this.
* Note that these values will be used only
* when there is no startup.blend yet.
@@ -521,7 +536,7 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
win->cursor = CURSOR_STD;
}
- wm_window_add_ghostwindow(wm, "Blender", win);
+ wm_window_ghostwindow_add(wm, "Blender", win);
}
/* happens after fileread */
if (win->eventstate == NULL)
@@ -546,11 +561,33 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
}
}
-/* new window, no screen yet, but we open ghostwindow for it */
-/* also gets the window level handlers */
-/* area-rip calls this */
+/**
+ * Call after #wm_window_ghostwindows_ensure or #WM_check
+ * (after loading a new file) in the unlikely event a window couldn't be created.
+ */
+void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
+{
+ wmWindow *win, *win_next;
+
+ BLI_assert(G.background == false);
+
+ for (win = wm->windows.first; win; win = win_next) {
+ win_next = win->next;
+ if (win->ghostwin == NULL) {
+ wm_window_close(C, wm, win);
+ }
+ }
+}
+
+/**
+ * new window, no screen yet, but we open ghostwindow for it,
+ * also gets the window level handlers
+ * \note area-rip calls this.
+ * \return the window or NULL.
+ */
wmWindow *WM_window_open(bContext *C, const rcti *rect)
{
+ wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win = wm_window_new(C);
win->posx = rect->xmin;
@@ -561,22 +598,36 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
win->drawmethod = U.wmdrawmethod;
WM_check(C);
-
- return win;
-}
-/* uses screen->temp tag to define what to do, currently it limits
- * to only one "temp" window for render out, preferences, filewindow, etc */
-/* type is defined in WM_api.h */
+ if (win->ghostwin) {
+ return win;
+ }
+ else {
+ wm_window_close(C, CTX_wm_manager(C), win);
+ CTX_wm_window_set(C, win_prev);
+ return NULL;
+ }
+}
-void WM_window_open_temp(bContext *C, rcti *position, int type)
+/**
+ * Uses `screen->temp` tag to define what to do, currently it limits
+ * to only one "temp" window for render out, preferences, filewindow, etc...
+ *
+ * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
+ * \return the window or NULL.
+ */
+wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
{
+ wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
-
+ const char *title;
+ rcti rect = *rect_init;
+ const short px_virtual = (short)wm_window_get_virtual_pixelsize();
+
/* changes rect to fit within desktop */
- wm_window_check_position(position);
+ wm_window_check_position(&rect);
/* test if we have a temp screen already */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
@@ -587,13 +638,14 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
if (win == NULL) {
win = wm_window_new(C);
- win->posx = position->xmin;
- win->posy = position->ymin;
+ win->posx = rect.xmin;
+ win->posy = rect.ymin;
}
-
- win->sizex = BLI_rcti_size_x(position);
- win->sizey = BLI_rcti_size_y(position);
-
+
+ /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
+ win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
+ win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+
if (win->ghostwin) {
wm_window_set_size(win, win->sizex, win->sizey);
wm_window_raise(win);
@@ -614,34 +666,60 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
WM_check(C);
-
+
+ /* It's possible `win->ghostwin == NULL`.
+ * instead of attempting to cleanup here (in a half finished state),
+ * finish setting up the screen, then free it at the end of the function,
+ * to avoid having to take into account a partially-created window.
+ */
+
/* ensure it shows the right spacetype editor */
sa = win->screen->areabase.first;
CTX_wm_area_set(C, sa);
if (type == WM_WINDOW_RENDER) {
- ED_area_newspace(C, sa, SPACE_IMAGE);
+ ED_area_newspace(C, sa, SPACE_IMAGE, false);
}
else {
- ED_area_newspace(C, sa, SPACE_USERPREF);
+ ED_area_newspace(C, sa, SPACE_USERPREF, false);
}
ED_screen_set(C, win->screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
if (sa->spacetype == SPACE_IMAGE)
- GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render"));
+ title = IFACE_("Blender Render");
else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
- GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences"));
+ title = IFACE_("Blender User Preferences");
else if (sa->spacetype == SPACE_FILE)
- GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View"));
+ title = IFACE_("Blender File View");
else
- GHOST_SetTitle(win->ghostwin, "Blender");
+ title = "Blender";
+
+ if (win->ghostwin) {
+ GHOST_SetTitle(win->ghostwin, title);
+ return win;
+ }
+ else {
+ /* very unlikely! but opening a new window can fail */
+ wm_window_close(C, CTX_wm_manager(C), win);
+ CTX_wm_window_set(C, win_prev);
+
+ return NULL;
+ }
}
/* ****************** Operators ****************** */
+int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ wm_window_close(C, wm, win);
+ return OPERATOR_FINISHED;
+}
+
/* operator callback */
int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -676,7 +754,7 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
/* ************ events *************** */
-static void wm_convert_cursor_position(wmWindow *win, int *x, int *y)
+void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y)
{
float fac = GHOST_GetNativePixelSize(win->ghostwin);
@@ -687,11 +765,21 @@ static void wm_convert_cursor_position(wmWindow *win, int *x, int *y)
*y *= fac;
}
+void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
+{
+ float fac = GHOST_GetNativePixelSize(win->ghostwin);
+
+ *x /= fac;
+ *y /= fac;
+ *y = win->sizey - *y - 1;
+
+ GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
+}
void wm_get_cursor_position(wmWindow *win, int *x, int *y)
{
GHOST_GetCursorPosition(g_system, x, y);
- wm_convert_cursor_position(win, x, y);
+ wm_cursor_position_from_ghost(win, x, y);
}
typedef enum {
@@ -1017,7 +1105,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#if defined(__APPLE__) || defined(WIN32)
/* OSX and Win32 don't return to the mainloop while resize */
- wm_event_do_handlers(C);
wm_event_do_notifiers(C);
wm_draw_update(C);
@@ -1119,7 +1206,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
GHOST_TEventTrackpadData *pd = data;
- wm_convert_cursor_position(win, &pd->x, &pd->y);
+ wm_cursor_position_from_ghost(win, &pd->x, &pd->y);
wm_event_add_ghostevent(wm, win, type, time, data);
break;
}
@@ -1127,7 +1214,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
GHOST_TEventCursorData *cd = data;
- wm_convert_cursor_position(win, &cd->x, &cd->y);
+ wm_cursor_position_from_ghost(win, &cd->x, &cd->y);
wm_event_add_ghostevent(wm, win, type, time, data);
break;
}
@@ -1278,7 +1365,7 @@ void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *t
wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
{
wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
-
+
wt->event_type = event_type;
wt->ltime = PIL_check_seconds_timer();
wt->ntime = wt->ltime + timestep;
@@ -1542,14 +1629,9 @@ void WM_init_native_pixels(bool do_it)
void WM_cursor_warp(wmWindow *win, int x, int y)
{
if (win && win->ghostwin) {
- float f = GHOST_GetNativePixelSize(win->ghostwin);
int oldx = x, oldy = y;
- x = x / f;
- y = y / f;
- y = win->sizey - y - 1;
-
- GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
+ wm_cursor_position_to_ghost(win, &x, &y);
GHOST_SetCursorPosition(g_system, x, y);
win->eventstate->prevx = oldx;
diff --git a/source/blender/windowmanager/wm_cursors.h b/source/blender/windowmanager/wm_cursors.h
index 4c07324184d..c695a12f52c 100644
--- a/source/blender/windowmanager/wm_cursors.h
+++ b/source/blender/windowmanager/wm_cursors.h
@@ -29,9 +29,6 @@
* \ingroup wm
*/
-
-
-
#ifndef __WM_CURSORS_H__
#define __WM_CURSORS_H__
@@ -111,13 +108,10 @@ enum {
BC_YELLOW
};
-#define SMALL_CURSOR 0
-#define BIG_CURSOR 1
-
struct wmWindow;
struct wmEvent;
-int wm_cursor_arrow_move(struct wmWindow *win, struct wmEvent *event);
+bool wm_cursor_arrow_move(struct wmWindow *win, const struct wmEvent *event);
#endif /* __WM_CURSORS_H__ */
diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h
index 5dc52b2e4fb..0f125309045 100644
--- a/source/blender/windowmanager/wm_draw.h
+++ b/source/blender/windowmanager/wm_draw.h
@@ -34,13 +34,9 @@
#include "GPU_glew.h"
-
-#define MAX_N_TEX 3
-
typedef struct wmDrawTriple {
- GLuint bind[MAX_N_TEX * MAX_N_TEX];
- int x[MAX_N_TEX], y[MAX_N_TEX];
- int nx, ny;
+ GLuint bind;
+ int x, y;
GLenum target;
} wmDrawTriple;
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 390e769aa88..c32ded28126 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -92,6 +92,10 @@ enum {
WM_IME_COMPOSITE_EVENT = 0x0015,
/* IME event, GHOST_kEventImeCompositionEnd in ghost */
WM_IME_COMPOSITE_END = 0x0016,
+
+ /* Tablet/Pen Specific Events */
+ TABLET_STYLUS = 0x001a,
+ TABLET_ERASER = 0x001b,
/* *** Start of keyboard codes. *** */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 467926aa770..2eae9cdb012 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -31,14 +31,33 @@
#ifndef __WM_FILES_H__
#define __WM_FILES_H__
+struct wmOperatorType;
+
+/* wm_files.c */
void wm_history_file_read(void);
-int wm_history_file_read_exec(bContext *C, wmOperator *op);
-int wm_file_write(struct bContext *C, const char *target, int fileflags, struct ReportList *reports);
-int wm_homefile_read_exec(struct bContext *C, struct wmOperator *op);
int wm_homefile_read(struct bContext *C, struct ReportList *reports, bool from_memory, const char *filepath);
-int wm_homefile_write_exec(struct bContext *C, struct wmOperator *op);
-int wm_userpref_write_exec(struct bContext *C, struct wmOperator *op);
+void wm_file_read_report(bContext *C);
+
+void WM_OT_save_homefile(struct wmOperatorType *ot);
+void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot);
+void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot);
+void WM_OT_save_userpref(struct wmOperatorType *ot);
+void WM_OT_read_history(struct wmOperatorType *ot);
+void WM_OT_read_homefile(struct wmOperatorType *ot);
+void WM_OT_read_factory_settings(struct wmOperatorType *ot);
+
+void WM_OT_open_mainfile(struct wmOperatorType *ot);
+
+void WM_OT_revert_mainfile(struct wmOperatorType *ot);
+void WM_OT_recover_last_session(struct wmOperatorType *ot);
+void WM_OT_recover_auto_save(struct wmOperatorType *ot);
+
+void WM_OT_save_as_mainfile(struct wmOperatorType *ot);
+void WM_OT_save_mainfile(struct wmOperatorType *ot);
+/* wm_files_link.c */
+void WM_OT_link(struct wmOperatorType *ot);
+void WM_OT_append(struct wmOperatorType *ot);
#endif /* __WM_FILES_H__ */
diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h
index bf7b99433c6..2a8118a726b 100644
--- a/source/blender/windowmanager/wm_subwindow.h
+++ b/source/blender/windowmanager/wm_subwindow.h
@@ -36,11 +36,11 @@
/* *************** internal api ************** */
void wm_subwindows_free(wmWindow *win);
-int wm_subwindow_open(wmWindow *win, const rcti *winrct);
+int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate);
void wm_subwindow_close(wmWindow *win, int swinid);
int wm_subwindow_get_id(wmWindow *win); /* returns id */
-void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct);
+void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct, bool activate);
void wm_subwindow_size_get(wmWindow *win, int swinid, int *x, int *y);
void wm_subwindow_origin_get(wmWindow *win, int swinid, int *x, int *y);
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index a104f6aba39..c106f9d7851 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -48,7 +48,8 @@ void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_title (wmWindowManager *wm, wmWindow *win);
-void wm_window_add_ghostwindows (wmWindowManager *wm);
+void wm_window_ghostwindows_ensure(wmWindowManager *wm);
+void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm);
void wm_window_process_events (const bContext *C);
void wm_window_process_events_nosleep(void);
@@ -64,7 +65,9 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
float wm_window_pixelsize(wmWindow *win);
-void wm_get_cursor_position (wmWindow *win, int *x, int *y);
+void wm_get_cursor_position (wmWindow *win, int *x, int *y);
+void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y);
+void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y);
void wm_window_testbreak (void);
@@ -74,6 +77,7 @@ void wm_window_IME_end (wmWindow *win);
#endif
/* *************** window operators ************** */
+int wm_window_close_exec(bContext *C, struct wmOperator *op);
int wm_window_duplicate_exec(bContext *C, struct wmOperator *op);
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index af367467e00..4b828408e45 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -54,7 +54,10 @@ if(WIN32 AND NOT UNIX)
)
endif()
- add_executable(blenderplayer ${EXETYPE} bad_level_call_stubs/stubs.c ../icons/winblender.rc)
+ add_executable(
+ blenderplayer ${EXETYPE}
+ bad_level_call_stubs/stubs.c
+ ${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc)
install(TARGETS blenderplayer
COMPONENT Blenderplayer
@@ -79,6 +82,11 @@ else()
TARGETS blenderplayer
DESTINATION bin
)
+ else()
+ install(
+ TARGETS blenderplayer
+ DESTINATION "."
+ )
endif()
endif()
@@ -145,7 +153,6 @@ endif()
bf_imbuf_openexr
bf_imbuf_openimageio
extern_openjpeg
- extern_redcode
bf_imbuf_dds
bf_dna
ge_videotex
@@ -162,16 +169,15 @@ endif()
bf_blenkernel # duplicate for linking
bf_intern_mikktspace
extern_recastnavigation
- bf_intern_raskter
bf_intern_opencolorio
- bf_intern_opennl
bf_intern_glew_mx
+ bf_intern_eigen
extern_rangetree
extern_wcwidth
- extern_libmv
+ bf_intern_libmv
extern_glog
+ extern_gflags
extern_sdlew
- extern_eigen3
)
if(WITH_MOD_CLOTH_ELTOPO)
@@ -190,8 +196,6 @@ endif()
list(APPEND BLENDER_SORTED_LIBS extern_ceres)
endif()
- list(APPEND BLENDER_SORTED_LIBS extern_colamd)
-
if(WITH_MOD_BOOLEAN)
list(APPEND BLENDER_SORTED_LIBS extern_carve)
endif()
@@ -216,6 +220,10 @@ endif()
list(APPEND BLENDER_SORTED_LIBS bf_intern_opensubdiv)
endif()
+ if(WITH_OPENVDB)
+ list(APPEND BLENDER_SORTED_LIBS bf_intern_openvdb)
+ endif()
+
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
set(REMLIB ${SORTLIB})
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
@@ -253,5 +261,9 @@ setup_liblinks(blenderplayer)
# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them..
if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
target_link_libraries(blenderplayer "extern_clew")
- target_link_libraries(blenderplayer "extern_cuew")
+ if(WITH_CUDA_DYNLOAD)
+ target_link_libraries(blenderplayer "extern_cuew")
+ else()
+ target_link_libraries(${target} ${CUDA_CUDA_LIBRARY})
+ endif()
endif()
diff --git a/source/blenderplayer/bad_level_call_stubs/SConscript b/source/blenderplayer/bad_level_call_stubs/SConscript
deleted file mode 100644
index a331b6d1e6e..00000000000
--- a/source/blenderplayer/bad_level_call_stubs/SConscript
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = ['stubs.c']
-
-incs = [
- '..',
- '#/intern/guardedalloc',
- '#/source/blender/makesdna',
- '#/source/blender/makesrna',
- '#/source/blender/blenlib',
- ]
-
-defs = []
-
-if env['WITH_BF_GAMEENGINE']:
- defs.append('WITH_GAMEENGINE')
-
-if env['WITH_BF_FREESTYLE']:
- defs.append(' WITH_FREESTYLE')
-
-env.BlenderLib('blenkernel_blc', sources=sources, includes=incs, defines=defs, libtype=['player'], priority=[220])
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 657a1c52d82..dfe7a03719a 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -137,6 +137,7 @@ struct wmWindowManager;
#if 1
#if defined(__GNUC__)
# pragma GCC diagnostic error "-Wmissing-prototypes"
+# pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "../../intern/cycles/blender/CCL_api.h"
@@ -194,6 +195,8 @@ extern bool pyrna_id_FromPyObject(struct PyObject *obj, struct ID **id);
extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
extern const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid);
extern struct PyObject *pyrna_id_CreatePyObject(struct ID *id);
+/* bpy_interface.c */
+bool BPY_string_is_keyword(const char *str) { return false; }
#endif
/* end declarations */
@@ -225,13 +228,15 @@ bool EDBM_mtexpoly_check(struct BMEditMesh *em) RET_ZERO
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
float RE_filter_value(int type, float x) RET_ZERO
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) RET_NULL
-void RE_init_texture_rng() RET_NONE
-void RE_exit_texture_rng() RET_NONE
+void RE_texture_rng_init() RET_NONE
+void RE_texture_rng_exit() RET_NONE
bool RE_layers_have_name(struct RenderResult *result) {STUB_ASSERT(0); return 0;}
+const char *RE_engine_active_view_get(struct RenderEngine *engine) RET_NULL
void RE_engine_active_view_set(struct RenderEngine *engine, const char *viewname) {STUB_ASSERT(0);}
-void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, float *r_modelmat) {STUB_ASSERT(0);}
-float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera) RET_ZERO
+void RE_engine_get_camera_model_matrix(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat) {STUB_ASSERT(0);}
+float RE_engine_get_camera_shift_x(struct RenderEngine *engine, struct Object *camera, int use_spherical_stereo) RET_ZERO
+int RE_engine_get_spherical_stereo(struct RenderEngine *engine, struct Object *camera) RET_ZERO
void RE_SetActiveRenderView(struct Render *re, const char *viewname) {STUB_ASSERT(0);}
struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int passtype, const char *viewname) RET_NULL
@@ -249,12 +254,12 @@ bool ED_texture_context_check_linestyle(const struct bContext *C) RET_ZERO
void FRS_free_view_map_cache(void) RET_NONE
/* texture.c */
-int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
+int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, short thread, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex, struct ImagePool *pool) RET_ZERO
-struct Material *RE_init_sample_material(struct Material *orig_mat, struct Scene *scene) RET_NULL
-void RE_free_sample_material(struct Material *mat) RET_NONE
+struct Material *RE_sample_material_init(struct Material *orig_mat, struct Scene *scene) RET_NULL
+void RE_sample_material_free(struct Material *mat) RET_NONE
void RE_sample_material_color(
struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
int tri_index, struct DerivedMesh *orcoDm, struct Object *ob) RET_NONE
@@ -262,6 +267,8 @@ void RE_sample_material_color(
struct Render *RE_GetRender(const char *name) RET_NULL
struct Object *RE_GetCamera(struct Render *re) RET_NULL
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
+const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL
+const float (*RE_render_current_get_matrix(int matrix_id))[4] RET_NULL
/* blenkernel */
bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO
@@ -274,10 +281,11 @@ struct Scene *RE_GetScene(struct Render *re) RET_NULL
void RE_Database_Free(struct Render *re) RET_NONE
void RE_FreeRender(struct Render *re) RET_NONE
void RE_DataBase_GetView(struct Render *re, float mat[4][4]) RET_NONE
-int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image) RET_ZERO
+int externtex(
+ struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta,
+ const int thread, struct ImagePool *pool, const bool skip_load_image, const bool texnode_preview) RET_ZERO
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype) RET_ZERO
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) RET_NONE
-const unsigned char stipple_quarttone[128];
double elbeemEstimateMemreq(int res, float sx, float sy, float sz, int refine, char *retstr) RET_ZERO
struct Render *RE_NewRender(const char *name) RET_NULL
void RE_SwapResult(struct Render *re, struct RenderResult **rr) RET_NONE
@@ -406,7 +414,7 @@ int WM_keymap_map_type_get(struct wmKeyMapItem *kmi) RET_ZERO
/* rna editors */
struct FCurve *verify_fcurve(struct bAction *act, const char group[], struct PointerRNA *ptr, const char rna_path[], const int array_index, short add) RET_NULL
-int insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag) RET_ZERO
+int insert_vert_fcurve(struct FCurve *fcu, float x, float y, char keytype, short flag) RET_ZERO
void delete_fcurve_key(struct FCurve *fcu, int index, bool do_recalc) RET_NONE
struct KeyingSetInfo *ANIM_keyingset_info_find_name (const char name[]) RET_NULL
struct KeyingSet *ANIM_scene_get_active_keyingset (struct Scene *scene) RET_NULL
@@ -423,13 +431,13 @@ void ED_space_image_get_zoom(struct SpaceImage *sima, struct ARegion *ar, float
const char *ED_info_stats_string(struct Scene *scene) RET_NULL
void ED_area_tag_redraw(struct ScrArea *sa) RET_NONE
void ED_area_tag_refresh(struct ScrArea *sa) RET_NONE
-void ED_area_newspace(struct bContext *C, struct ScrArea *sa, int type) RET_NONE
+void ED_area_newspace(struct bContext *C, struct ScrArea *sa, int type, const bool skip_ar_exit) RET_NONE
void ED_region_tag_redraw(struct ARegion *ar) RET_NONE
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op) RET_NONE
void WM_cursor_wait(bool val) RET_NONE
void ED_node_texture_default(const struct bContext *C, struct Tex *tex) RET_NONE
void ED_node_tag_update_id(struct ID *id) RET_NONE
-void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree) RET_NONE
+void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node) RET_NONE
void ED_node_tree_update(const struct bContext *C) RET_NONE
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo){}
void ED_init_custom_node_type(struct bNodeType *ntype){}
@@ -496,8 +504,8 @@ void ED_object_constraint_tag_update(struct Object *ob, struct bConstraint *con)
void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum, float weight, int assignmode) RET_NONE
void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum) RET_NONE
float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum) RET_ZERO
-int ED_mesh_mirror_topo_table(struct Object *ob, char mode) RET_ZERO
-int ED_mesh_mirror_spatial_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode) RET_ZERO
+int ED_mesh_mirror_topo_table(struct Object *ob, struct DerivedMesh *dm, char mode) RET_ZERO
+int ED_mesh_mirror_spatial_table(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, const float co[3], char mode) RET_ZERO
float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const bool axis_only) RET_ZERO
void ED_space_image_get_size(struct SpaceImage *sima, int *width, int *height) RET_NONE
@@ -511,16 +519,18 @@ bool ED_texture_context_check_others(const struct bContext *C) RET_ZERO
bool ED_text_region_location_from_cursor(SpaceText *st, ARegion *ar, const int cursor_co[2], int r_pixel_co[2]) RET_ZERO
-bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode,
- struct Object **r_ob, float r_obmat[4][4],
- const float ray_start[3], const float ray_normal[3], float *r_ray_dist,
- const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) RET_ZERO
+bool snapObjectsRayEx(
+ struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit,
+ const float mval[2], SnapSelect snap_select, short snap_mode,
+ const float ray_start[3], const float ray_normal[3], float *ray_dist,
+ float r_loc[3], float r_no[3], float *r_dist_px, int *r_index,
+ struct Object **r_ob, float r_obmat[4][4]) RET_ZERO
-void make_editLatt(struct Object *obedit) RET_NONE
-void load_editLatt(struct Object *obedit) RET_NONE
+void ED_lattice_editlatt_make(struct Object *obedit) RET_NONE
+void ED_lattice_editlatt_load(struct Object *obedit) RET_NONE
-void load_editNurb(struct Object *obedit) RET_NONE
-void make_editNurb(struct Object *obedit) RET_NONE
+void ED_curve_editnurb_load(struct Object *obedit) RET_NONE
+void ED_curve_editnurb_make(struct Object *obedit) RET_NONE
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon) RET_NONE
@@ -627,8 +637,12 @@ void RE_engine_update_memory_stats(struct RenderEngine *engine, float mem_used,
struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL
void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE
void RE_FreePersistentData(void) RET_NONE
-void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, int resolution, float *values) RET_NONE;
+void RE_point_density_cache(struct Scene *scene, struct PointDensity *pd, const bool use_render_params) RET_NONE
+void RE_point_density_minmax(struct Scene *scene, struct PointDensity *pd, const bool use_render_params, float r_min[3], float r_max[3]) RET_NONE;
+void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int resolution, const bool use_render_params, float *values) RET_NONE;
+void RE_point_density_free(struct PointDensity *pd) RET_NONE;
void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE
+void RE_FreeAllPersistentData(void) RET_NONE
/* python */
struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL
@@ -650,7 +664,7 @@ void WM_operator_bl_idname(char *to, const char *from) RET_NONE
void WM_operator_py_idname(char *to, const char *from) RET_NONE
int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width, int height) RET_ZERO
void update_autoflags_fcurve(struct FCurve *fcu, struct bContext *C, struct ReportList *reports, struct PointerRNA *ptr) RET_NONE
-short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag) RET_ZERO
+short insert_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, char keytype, short flag) RET_ZERO
short delete_keyframe(struct ReportList *reports, struct ID *id, struct bAction *act, const char group[], const char rna_path[], int array_index, float cfra, short flag) RET_ZERO
struct bAction *verify_adt_action(struct ID *id, short add) RET_NULL
char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op, const bool all_args, const bool macro_args, struct wmOperatorType *ot, struct PointerRNA *opptr) RET_NULL
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index a3589175197..273e5b33d0d 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -49,7 +49,7 @@ if(WIN32)
endif()
if(WITH_LIBMV)
- blender_include_dirs(../../extern/libmv)
+ blender_include_dirs(../../intern/libmv)
add_definitions(-DWITH_LIBMV)
endif()
@@ -102,6 +102,10 @@ endif()
# Setup the exe sources and buildinfo
set(SRC
creator.c
+ creator_args.c
+ creator_signals.c
+
+ creator_intern.h
)
# MSVC 2010 gives linking errors with the manifest
@@ -130,7 +134,7 @@ if(WIN32 AND NOT UNIX)
list(APPEND SRC
- ../icons/winblender.rc
+ ${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc
)
endif()
@@ -250,8 +254,11 @@ endif()
set(BLENDER_TEXT_FILES
${CMAKE_SOURCE_DIR}/release/text/GPL-license.txt
+ ${CMAKE_SOURCE_DIR}/release/text/GPL3-license.txt
${CMAKE_SOURCE_DIR}/release/text/Python-license.txt
${CMAKE_SOURCE_DIR}/release/text/copyright.txt
+ ${CMAKE_SOURCE_DIR}/release/text/jemalloc-license.txt
+ ${CMAKE_SOURCE_DIR}/release/text/ocio-license.txt
# generate this file
# ${CMAKE_SOURCE_DIR}/release/text/readme.html
${CMAKE_SOURCE_DIR}/release/datafiles/LICENSE-bfont.ttf.txt
@@ -292,7 +299,8 @@ elseif(APPLE)
else()
set(TARGETDIR_VER blender.app/Contents/Resources/${BLENDER_VERSION})
endif()
-
+ # Skip relinking on cpack / install
+ set_target_properties(blender PROPERTIES BUILD_WITH_INSTALL_RPATH true)
endif()
@@ -503,7 +511,7 @@ if(UNIX AND NOT APPLE)
if(WITH_PYTHON_INSTALL)
install(
- FILES ${PYTHON_EXECUTABLE}
+ PROGRAMS ${PYTHON_EXECUTABLE}
DESTINATION ${TARGETDIR_VER}/python/bin
)
@@ -521,17 +529,12 @@ if(UNIX AND NOT APPLE)
unset(_pypath_real)
# Copy the systems python into the install directory
- # Scons copy in tools/Blender.py
# install(CODE "message(\"copying a subset of the systems python...\")")
install(
DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}
DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}
- PATTERN ".svn" EXCLUDE
PATTERN "__pycache__" EXCLUDE # * any cache *
- PATTERN "distutils" EXCLUDE # ./distutils
PATTERN "lib2to3" EXCLUDE # ./lib2to3
- PATTERN "config" EXCLUDE # ./config
- PATTERN "config-*" EXCLUDE # ./config-*
PATTERN "site-packages/*" EXCLUDE # ./site-packages/*
PATTERN "tkinter" EXCLUDE # ./tkinter
PATTERN "lib-dynload/_tkinter.*" EXCLUDE # ./lib-dynload/_tkinter.co
@@ -541,6 +544,15 @@ if(UNIX AND NOT APPLE)
PATTERN "turtle.py" EXCLUDE # ./turtle.py
)
+ # Needed for distutils/pip
+ # get the last part of the include dir, will be 'python{version}{abiflag}',
+ get_filename_component(_py_inc_suffix ${PYTHON_INCLUDE_DIR} NAME)
+ install(
+ FILES ${PYTHON_INCLUDE_DIR}/pyconfig.h
+ DESTINATION ${TARGETDIR_VER}/python/include/${_py_inc_suffix}
+ )
+ unset(_py_inc_suffix)
+
# # doesnt work, todo
# install(CODE "execute_process(COMMAND find ${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python/lib/ -name '*.so' -exec strip -s {} '\;')")
@@ -558,7 +570,6 @@ if(UNIX AND NOT APPLE)
PATTERN "__pycache__" EXCLUDE # * any cache *
PATTERN "*.pyc" EXCLUDE # * any cache *
PATTERN "*.pyo" EXCLUDE # * any cache *
- PATTERN "distutils" EXCLUDE # ./distutils
PATTERN "oldnumeric" EXCLUDE # ./oldnumeric
PATTERN "doc" EXCLUDE # ./doc
PATTERN "tests" EXCLUDE # ./tests
@@ -583,7 +594,6 @@ if(UNIX AND NOT APPLE)
PATTERN "__pycache__" EXCLUDE # * any cache *
PATTERN "*.pyc" EXCLUDE # * any cache *
PATTERN "*.pyo" EXCLUDE # * any cache *
- PATTERN "cacert.pem" EXCLUDE # for now we don't deal with security
)
# On some platforms requests does have extra dependencies.
set(_requests_deps "chardet" "urllib3")
@@ -620,17 +630,20 @@ elseif(WIN32)
if(WITH_PYTHON)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
- install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll ${LIBDIR}/python/lib/sqlite3.dll
- DESTINATION "."
- CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
- )
+ # MinGW TODO: This bit of Python configuration diverges from MSVC
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ install(
+ FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
+ DESTINATION "."
+ CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
+ )
- install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll ${LIBDIR}/python/lib/sqlite3_d.dll
- DESTINATION "."
- CONFIGURATIONS Debug
- )
+ install(
+ FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
+ DESTINATION "."
+ CONFIGURATIONS Debug
+ )
+ endif()
if(WITH_PYTHON_INSTALL)
# note, as far as python is concerned 'RelWithDebInfo' is not debug since its without debug flags.
@@ -703,6 +716,20 @@ elseif(WIN32)
DESTINATION ${BLENDER_VERSION}/python/bin
CONFIGURATIONS Debug
)
+
+ # MinGW needs Python DLL
+ if(MINGW)
+ install(
+ FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
+ DESTINATION "."
+ CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
+ )
+ install(
+ FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
+ DESTINATION "."
+ CONFIGURATIONS Debug
+ )
+ endif()
endif()
unset(_PYTHON_VERSION_NO_DOTS)
@@ -790,13 +817,30 @@ elseif(WIN32)
${LIBDIR}/openal/lib/OpenAL32.dll
DESTINATION "."
)
+ # MinGW TODO: Need to update to a newer OpenAL version
+ # which does not depend on wrap_oal.dll
+ if(CMAKE_COMPILER_IS_GNUCC)
+ install(
+ FILES
+ ${LIBDIR}/openal/lib/wrap_oal.dll
+ DESTINATION "."
+ )
+ endif()
endif()
if(WITH_SDL)
- install(
- FILES ${LIBDIR}/sdl/lib/SDL2.dll
- DESTINATION "."
- )
+ #MinGW TODO: Update to SDL2
+ if(NOT CMAKE_COMPILER_IS_GNUCC)
+ install(
+ FILES ${LIBDIR}/sdl/lib/SDL2.dll
+ DESTINATION "."
+ )
+ else()
+ install(
+ FILES ${LIBDIR}/sdl/lib/SDL.dll
+ DESTINATION "."
+ )
+ endif()
endif()
if(WITH_SYSTEM_AUDASPACE)
@@ -945,9 +989,13 @@ elseif(APPLE)
# copy site-packages files
install_dir(
${LIBDIR}/release/site-packages
- ${CMAKE_CURRENT_BINARY_DIR}/python/lib/python${PYTHON_VERSION}/site-packages
+ ${CMAKE_CURRENT_BINARY_DIR}/python/lib/python${PYTHON_VERSION}
)
+ install(DIRECTORY ${LIBDIR}/python/bin
+ DESTINATION ${TARGETDIR_VER}/python
+ USE_SOURCE_PERMISSIONS
+ )
endif()
# install blenderplayer bundle - copy of blender.app above. re-using macros et al
@@ -1016,7 +1064,7 @@ if(DEFINED BLENDER_TEXT_FILES_DESTINATION)
"
file(READ \"${CMAKE_SOURCE_DIR}/release/text/readme.html\" DATA_SRC)
string(REGEX REPLACE \"BLENDER_VERSION\" \"${BLENDER_VERSION}\" DATA_DST \"\${DATA_SRC}\")
- file(WRITE \"\${CMAKE_BINARY_DIR}/release/text/readme.html\" \"\${DATA_DST}\")
+ file(WRITE \"${CMAKE_BINARY_DIR}/release/text/readme.html\" \"\${DATA_DST}\")
unset(DATA_SRC)
unset(DATA_DST)
"
@@ -1052,17 +1100,7 @@ setup_liblinks(blender)
# Setup launcher
if(WIN32 AND NOT WITH_PYTHON_MODULE)
- set(LAUNCHER_SRC
- creator_launch_win.c
- ../icons/winblender.rc
- )
- add_executable(blender-launcher ${LAUNCHER_SRC})
- target_link_libraries(blender-launcher bf_intern_utfconv ${PLATFORM_LINKLIBS})
-
- set_target_properties(blender PROPERTIES OUTPUT_NAME blender-app)
- set_target_properties(blender-launcher PROPERTIES OUTPUT_NAME blender)
-
- install(TARGETS blender blender-launcher
+ install(TARGETS blender
COMPONENT Blender
DESTINATION ".")
diff --git a/source/creator/blender.map b/source/creator/blender.map
index 359cbe0415f..9c900a62705 100644
--- a/source/creator/blender.map
+++ b/source/creator/blender.map
@@ -9,6 +9,7 @@ global:
*;
*_boost*;
local:
+ *default_error_condition*;
*llvm*;
*LLVM*;
decodeInstruction;
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 86922c38ba0..1010c9f06c8 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -29,16 +29,8 @@
* \ingroup creator
*/
-
-#if defined(__linux__) && defined(__GNUC__)
-# define _GNU_SOURCE
-# include <fenv.h>
-#endif
-
-#if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
-# define OSX_SSE_FPE
-# include <xmmintrin.h>
-#endif
+#include <stdlib.h>
+#include <string.h>
#ifdef WIN32
# if defined(_MSC_VER) && defined(_M_X64)
@@ -48,14 +40,6 @@
# include "utfconv.h"
#endif
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-
-/* This little block needed for linking to Blender... */
-
#include "MEM_guardedalloc.h"
#ifdef WIN32
@@ -66,63 +50,39 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_callbacks.h"
-#include "BLI_blenlib.h"
-#include "BLI_mempool.h"
-#include "BLI_system.h"
-#include BLI_SYSTEM_PID_H
-
-#include "DNA_ID.h"
-#include "DNA_scene_types.h"
-#include "DNA_userdef_types.h"
+#include "BLI_string.h"
+/* mostly init functions */
#include "BKE_appdir.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h" /* for DAG_on_visible_update */
+#include "BKE_depsgraph.h" /* for DAG_init */
#include "BKE_font.h"
#include "BKE_global.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
-#include "BKE_scene.h"
#include "BKE_node.h"
-#include "BKE_report.h"
#include "BKE_sound.h"
#include "BKE_image.h"
#include "BKE_particle.h"
-#include "DEG_depsgraph.h"
#include "IMB_imbuf.h" /* for IMB_init */
-#ifdef WITH_PYTHON
-#include "BPY_extern.h"
-#endif
-
#include "RE_engine.h"
-#include "RE_pipeline.h"
#include "RE_render_ext.h"
#include "ED_datafiles.h"
-#include "ED_util.h"
#include "WM_api.h"
#include "RNA_define.h"
-#include "GPU_draw.h"
-#include "GPU_extensions.h"
-
#ifdef WITH_FREESTYLE
# include "FRS_freestyle.h"
#endif
-#ifdef WITH_BUILDINFO_HEADER
-# define BUILD_DATE
-#endif
-
/* for passing information between creator and gameengine */
#ifdef WITH_GAMEENGINE
# include "BL_System.h"
@@ -133,9 +93,7 @@
#include <signal.h>
#ifdef __FreeBSD__
-# include <sys/types.h>
# include <floatingpoint.h>
-# include <sys/rtprio.h>
#endif
#ifdef WITH_BINRELOC
@@ -154,1469 +112,54 @@
# include "sdlew.h"
#endif
-/* from buildinfo.c */
-#ifdef BUILD_DATE
-extern char build_date[];
-extern char build_time[];
-extern char build_hash[];
-extern unsigned long build_commit_timestamp;
-
-/* TODO(sergey): ideally size need to be in sync with buildinfo.c */
-extern char build_commit_date[16];
-extern char build_commit_time[16];
-
-extern char build_branch[];
-extern char build_platform[];
-extern char build_type[];
-extern char build_cflags[];
-extern char build_cxxflags[];
-extern char build_linkflags[];
-extern char build_system[];
-#endif
+#include "creator_intern.h" /* own include */
+
/* Local Function prototypes */
#ifdef WITH_PYTHON_MODULE
int main_python_enter(int argc, const char **argv);
void main_python_exit(void);
-#else
-static int print_help(int argc, const char **argv, void *data);
-static int print_version(int argc, const char **argv, void *data);
-#endif
-
-/* for the callbacks: */
-#ifndef WITH_PYTHON_MODULE
-#define BLEND_VERSION_FMT "Blender %d.%02d (sub %d)"
-#define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION
-/* pass directly to printf */
-#define BLEND_VERSION_STRING_FMT BLEND_VERSION_FMT "\n", BLEND_VERSION_ARG
-#endif
-
-/* Initialize callbacks for the modules that need them */
-static void setCallbacks(void);
-
-#ifndef WITH_PYTHON_MODULE
-
-static bool use_crash_handler = true;
-static bool use_abort_handler = true;
-
-/* set breakpoints here when running in debug mode, useful to catch floating point errors */
-#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
-static void fpe_handler(int UNUSED(sig))
-{
- fprintf(stderr, "debug: SIGFPE trapped\n");
-}
-#endif
-
-/* handling ctrl-c event in console */
-#if !(defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS))
-static void blender_esc(int sig)
-{
- static int count = 0;
-
- G.is_break = true; /* forces render loop to read queue, not sure if its needed */
-
- if (sig == 2) {
- if (count) {
- printf("\nBlender killed\n");
- exit(2);
- }
- printf("\nSent an internal break event. Press ^C again to kill Blender\n");
- count++;
- }
-}
-#endif
-
-static int print_version(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- printf(BLEND_VERSION_STRING_FMT);
-#ifdef BUILD_DATE
- printf("\tbuild date: %s\n", build_date);
- printf("\tbuild time: %s\n", build_time);
- printf("\tbuild commit date: %s\n", build_commit_date);
- printf("\tbuild commit time: %s\n", build_commit_time);
- printf("\tbuild hash: %s\n", build_hash);
- printf("\tbuild platform: %s\n", build_platform);
- printf("\tbuild type: %s\n", build_type);
- printf("\tbuild c flags: %s\n", build_cflags);
- printf("\tbuild c++ flags: %s\n", build_cxxflags);
- printf("\tbuild link flags: %s\n", build_linkflags);
- printf("\tbuild system: %s\n", build_system);
-#endif
- exit(0);
-
- return 0;
-}
-
-static int print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
-{
- bArgs *ba = (bArgs *)data;
-
- printf(BLEND_VERSION_STRING_FMT);
- printf("Usage: blender [args ...] [file] [args ...]\n\n");
-
- printf("Render Options:\n");
- BLI_argsPrintArgDoc(ba, "--background");
- BLI_argsPrintArgDoc(ba, "--render-anim");
- BLI_argsPrintArgDoc(ba, "--scene");
- BLI_argsPrintArgDoc(ba, "--render-frame");
- BLI_argsPrintArgDoc(ba, "--frame-start");
- BLI_argsPrintArgDoc(ba, "--frame-end");
- BLI_argsPrintArgDoc(ba, "--frame-jump");
- BLI_argsPrintArgDoc(ba, "--render-output");
- BLI_argsPrintArgDoc(ba, "--engine");
- BLI_argsPrintArgDoc(ba, "--threads");
-
- printf("\n");
- printf("Format Options:\n");
- BLI_argsPrintArgDoc(ba, "--render-format");
- BLI_argsPrintArgDoc(ba, "--use-extension");
-
- printf("\n");
- printf("Animation Playback Options:\n");
- BLI_argsPrintArgDoc(ba, "-a");
-
- printf("\n");
- printf("Window Options:\n");
- BLI_argsPrintArgDoc(ba, "--window-border");
- BLI_argsPrintArgDoc(ba, "--window-borderless");
- BLI_argsPrintArgDoc(ba, "--window-geometry");
- BLI_argsPrintArgDoc(ba, "--start-console");
- BLI_argsPrintArgDoc(ba, "--no-native-pixels");
-
-
- printf("\n");
- printf("Game Engine Specific Options:\n");
- BLI_argsPrintArgDoc(ba, "-g");
-
- printf("\n");
- printf("Python Options:\n");
- BLI_argsPrintArgDoc(ba, "--enable-autoexec");
- BLI_argsPrintArgDoc(ba, "--disable-autoexec");
-
- printf("\n");
-
- BLI_argsPrintArgDoc(ba, "--python");
- BLI_argsPrintArgDoc(ba, "--python-text");
- BLI_argsPrintArgDoc(ba, "--python-expr");
- BLI_argsPrintArgDoc(ba, "--python-console");
- BLI_argsPrintArgDoc(ba, "--addons");
-
-
- printf("\n");
- printf("Debug Options:\n");
- BLI_argsPrintArgDoc(ba, "--debug");
- BLI_argsPrintArgDoc(ba, "--debug-value");
-
- printf("\n");
- BLI_argsPrintArgDoc(ba, "--debug-events");
-#ifdef WITH_FFMPEG
- BLI_argsPrintArgDoc(ba, "--debug-ffmpeg");
-#endif
- BLI_argsPrintArgDoc(ba, "--debug-handlers");
-#ifdef WITH_LIBMV
- BLI_argsPrintArgDoc(ba, "--debug-libmv");
-#endif
-#ifdef WITH_CYCLES_LOGGING
- BLI_argsPrintArgDoc(ba, "--debug-cycles");
-#endif
- BLI_argsPrintArgDoc(ba, "--debug-memory");
- BLI_argsPrintArgDoc(ba, "--debug-jobs");
- BLI_argsPrintArgDoc(ba, "--debug-python");
- BLI_argsPrintArgDoc(ba, "--debug-depsgraph");
- BLI_argsPrintArgDoc(ba, "--debug-depsgraph-no-threads");
-
- BLI_argsPrintArgDoc(ba, "--debug-gpumem");
- BLI_argsPrintArgDoc(ba, "--debug-wm");
- BLI_argsPrintArgDoc(ba, "--debug-all");
-
- printf("\n");
- BLI_argsPrintArgDoc(ba, "--debug-fpe");
- BLI_argsPrintArgDoc(ba, "--disable-crash-handler");
-
- printf("\n");
- printf("Misc Options:\n");
- BLI_argsPrintArgDoc(ba, "--factory-startup");
- printf("\n");
- BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
- BLI_argsPrintArgDoc(ba, "--env-system-scripts");
- BLI_argsPrintArgDoc(ba, "--env-system-python");
- printf("\n");
- BLI_argsPrintArgDoc(ba, "-nojoystick");
- BLI_argsPrintArgDoc(ba, "-noglsl");
- BLI_argsPrintArgDoc(ba, "-noaudio");
- BLI_argsPrintArgDoc(ba, "-setaudio");
-
- printf("\n");
-
- BLI_argsPrintArgDoc(ba, "--help");
-
-#ifdef WIN32
- BLI_argsPrintArgDoc(ba, "-R");
- BLI_argsPrintArgDoc(ba, "-r");
-#endif
- BLI_argsPrintArgDoc(ba, "--version");
-
- BLI_argsPrintArgDoc(ba, "--");
-
- printf("Other Options:\n");
- BLI_argsPrintOtherDoc(ba);
-
- printf("\n");
- printf("Experimental features:\n");
- BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
-
- printf("Argument Parsing:\n");
- printf("\tArguments must be separated by white space, eg:\n");
- printf("\t# blender -ba test.blend\n");
- printf("\t...will ignore the 'a'\n");
- printf("\t# blender -b test.blend -f8\n");
- printf("\t...will ignore '8' because there is no space between the '-f' and the frame value\n\n");
-
- printf("Argument Order:\n");
- printf("\tArguments are executed in the order they are given. eg:\n");
- printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n");
- printf("\t...will not render to '/tmp' because '--render-frame 1' renders before the output path is set\n");
- printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n");
- printf("\t...will not render to '/tmp' because loading the blend file overwrites the render output that was set\n");
- printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n");
- printf("\t...works as expected.\n\n");
-
- printf("Environment Variables:\n");
- printf(" $BLENDER_USER_CONFIG Directory for user configuration files.\n");
- printf(" $BLENDER_USER_SCRIPTS Directory for user scripts.\n");
- printf(" $BLENDER_SYSTEM_SCRIPTS Directory for system wide scripts.\n");
- printf(" $BLENDER_USER_DATAFILES Directory for user data files (icons, translations, ..).\n");
- printf(" $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
- printf(" $BLENDER_SYSTEM_PYTHON Directory for system python libraries.\n");
-#ifdef WIN32
- printf(" $TEMP Store temporary files here.\n");
-#else
- printf(" $TMP or $TMPDIR Store temporary files here.\n");
-#endif
-#ifdef WITH_SDL
- printf(" $SDL_AUDIODRIVER LibSDL audio driver - alsa, esd, dma.\n");
-#endif
- printf(" $PYTHONHOME Path to the python directory, eg. /usr/lib/python.\n\n");
-
- exit(0);
-
- return 0;
-}
-
-static int parse_relative_int(const char *str, int pos, int neg, int min, int max)
-{
- int ret;
-
- switch (*str) {
- case '+':
- ret = pos + atoi(str + 1);
- break;
- case '-':
- ret = (neg - atoi(str + 1)) + 1;
- break;
- default:
- ret = atoi(str);
- break;
- }
-
- CLAMP(ret, min, max);
-
- return ret;
-}
-
-static int end_arguments(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- return -1;
-}
-
-static int enable_python(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- G.f |= G_SCRIPT_AUTOEXEC;
- G.f |= G_SCRIPT_OVERRIDE_PREF;
- return 0;
-}
-
-static int disable_python(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- G.f &= ~G_SCRIPT_AUTOEXEC;
- G.f |= G_SCRIPT_OVERRIDE_PREF;
- return 0;
-}
-
-static int disable_crash_handler(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- use_crash_handler = false;
- return 0;
-}
-
-static int disable_abort_handler(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- use_abort_handler = false;
- return 0;
-}
-
-static int background_mode(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- G.background = 1;
- return 0;
-}
-
-static int debug_mode(int UNUSED(argc), const char **UNUSED(argv), void *data)
-{
- G.debug |= G_DEBUG; /* std output printf's */
- printf(BLEND_VERSION_STRING_FMT);
- MEM_set_memory_debug();
-#ifndef NDEBUG
- BLI_mempool_set_memory_debug();
-#endif
-
-#ifdef WITH_BUILDINFO
- printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type);
-#endif
-
- BLI_argsPrint(data);
- return 0;
-}
-
-static int debug_mode_generic(int UNUSED(argc), const char **UNUSED(argv), void *data)
-{
- G.debug |= GET_INT_FROM_POINTER(data);
- return 0;
-}
-
-#ifdef WITH_LIBMV
-static int debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- libmv_startDebugLogging();
-
- return 0;
-}
-#endif
-
-#ifdef WITH_CYCLES_LOGGING
-static int debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv),
- void *UNUSED(data))
-{
- CCL_start_debug_logging();
- return 0;
-}
-#endif
-
-static int debug_mode_memory(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- MEM_set_memory_debug();
- return 0;
-}
-
-static int set_debug_value(int argc, const char **argv, void *UNUSED(data))
-{
- if (argc > 1) {
- G.debug_value = atoi(argv[1]);
-
- return 1;
- }
- else {
- printf("\nError: you must specify debug value to set.\n");
- return 0;
- }
-}
-
-static int set_fpe(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
-#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
- /* zealous but makes float issues a heck of a lot easier to find!
- * set breakpoints on fpe_handler */
- signal(SIGFPE, fpe_handler);
-
-# if defined(__linux__) && defined(__GNUC__)
- feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
-# endif /* defined(__linux__) && defined(__GNUC__) */
-# if defined(OSX_SSE_FPE)
- /* OSX uses SSE for floating point by default, so here
- * use SSE instructions to throw floating point exceptions */
- _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK & ~
- (_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
-# endif /* OSX_SSE_FPE */
-# if defined(_WIN32) && defined(_MSC_VER)
- _controlfp_s(NULL, 0, _MCW_EM); /* enables all fp exceptions */
- _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); /* hide the ones we don't care about */
-# endif /* _WIN32 && _MSC_VER */
-#endif
-
- return 0;
-}
-
-static void blender_crash_handler_backtrace(FILE *fp)
-{
- fputs("\n# backtrace\n", fp);
- BLI_system_backtrace(fp);
-}
-
-static void blender_crash_handler(int signum)
-{
-
-#if 0
- {
- char fname[FILE_MAX];
-
- if (!G.main->name[0]) {
- BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
- }
- else {
- BLI_strncpy(fname, G.main->name, sizeof(fname));
- BLI_replace_extension(fname, sizeof(fname), ".crash.blend");
- }
-
- printf("Writing: %s\n", fname);
- fflush(stdout);
-
- BKE_undo_save_file(fname);
- }
#endif
- FILE *fp;
- char header[512];
- wmWindowManager *wm = G.main->wm.first;
-
- char fname[FILE_MAX];
-
- if (!G.main->name[0]) {
- BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
- }
- else {
- BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G.main->name));
- BLI_replace_extension(fname, sizeof(fname), ".crash.txt");
+/* written to by 'creator_args.c' */
+struct ApplicationState app_state = {
+ .signal = {
+ .use_crash_handler = true,
+ .use_abort_handler = true,
+ },
+ .exit_code_on_error = {
+ .python = 0,
}
+};
- printf("Writing: %s\n", fname);
- fflush(stdout);
+/* -------------------------------------------------------------------- */
-#ifndef BUILD_DATE
- BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
-#else
- BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
- BLEND_VERSION_ARG, build_commit_date, build_commit_time, build_hash);
-#endif
-
- /* open the crash log */
- errno = 0;
- fp = BLI_fopen(fname, "wb");
- if (fp == NULL) {
- fprintf(stderr, "Unable to save '%s': %s\n",
- fname, errno ? strerror(errno) : "Unknown error opening file");
- }
- else {
- if (wm) {
- BKE_report_write_file_fp(fp, &wm->reports, header);
- }
-
- blender_crash_handler_backtrace(fp);
-
- fclose(fp);
- }
-
- /* Delete content of temp dir! */
- BKE_tempdir_session_purge();
-
- /* really crash */
- signal(signum, SIG_DFL);
-#ifndef WIN32
- kill(getpid(), signum);
-#else
- TerminateProcess(GetCurrentProcess(), signum);
-#endif
-}
+/** \name Application Level Callbacks
+ *
+ * Initialize callbacks for the modules that need them.
+ *
+ * \{ */
-#ifdef WIN32
-LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
+static void callback_mem_error(const char *errorStr)
{
- switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
- case EXCEPTION_ACCESS_VIOLATION:
- fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
- break;
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
- break;
- case EXCEPTION_BREAKPOINT:
- fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
- break;
- case EXCEPTION_FLT_OVERFLOW:
- fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
- break;
- case EXCEPTION_IN_PAGE_ERROR:
- fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
- break;
- case EXCEPTION_INT_OVERFLOW:
- fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
- break;
- case EXCEPTION_SINGLE_STEP:
- fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
- break;
- case EXCEPTION_STACK_OVERFLOW:
- fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
- break;
- default:
- fputs("Error: Unrecognized Exception\n", stderr);
- break;
- }
-
+ fputs(errorStr, stderr);
fflush(stderr);
-
- /* If this is a stack overflow then we can't walk the stack, so just show
- * where the error happened */
- if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
-#ifdef NDEBUG
- TerminateProcess(GetCurrentProcess(), SIGSEGV);
-#else
- blender_crash_handler(SIGSEGV);
-#endif
- }
-
- return EXCEPTION_EXECUTE_HANDLER;
-}
-#endif
-
-
-static void blender_abort_handler(int UNUSED(signum))
-{
- /* Delete content of temp dir! */
- BKE_tempdir_session_purge();
-}
-
-static int set_factory_startup(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- G.factory_startup = 1;
- return 0;
-}
-
-static int set_env(int argc, const char **argv, void *UNUSED(data))
-{
- /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */
-
- char env[64] = "BLENDER";
- char *ch_dst = env + 7; /* skip BLENDER */
- const char *ch_src = argv[0] + 5; /* skip --env */
-
- if (argc < 2) {
- printf("%s requires one argument\n", argv[0]);
- exit(1);
- }
-
- for (; *ch_src; ch_src++, ch_dst++) {
- *ch_dst = (*ch_src == '-') ? '_' : (*ch_src) - 32; /* toupper() */
- }
-
- *ch_dst = '\0';
- BLI_setenv(env, argv[1]);
- return 1;
-}
-
-static int playback_mode(int argc, const char **argv, void *UNUSED(data))
-{
- /* not if -b was given first */
- if (G.background == 0) {
-#ifdef WITH_FFMPEG
- /* Setup FFmpeg with current debug flags. */
- IMB_ffmpeg_init();
-#endif
-
- WM_main_playanim(argc, argv); /* not the same argc and argv as before */
- exit(0); /* 2.4x didn't do this */
- }
-
- return -2;
-}
-
-static int prefsize(int argc, const char **argv, void *UNUSED(data))
-{
- int stax, stay, sizx, sizy;
-
- if (argc < 5) {
- fprintf(stderr, "-p requires four arguments\n");
- exit(1);
- }
-
- stax = atoi(argv[1]);
- stay = atoi(argv[2]);
- sizx = atoi(argv[3]);
- sizy = atoi(argv[4]);
-
- WM_init_state_size_set(stax, stay, sizx, sizy);
-
- return 4;
-}
-
-static int native_pixels(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- WM_init_native_pixels(false);
- return 0;
-}
-
-static int with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- WM_init_state_normal_set();
- return 0;
-}
-
-static int without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- WM_init_state_fullscreen_set();
- return 0;
-}
-
-extern bool wm_start_with_console; /* wm_init_exit.c */
-static int start_with_console(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- wm_start_with_console = true;
- return 0;
-}
-
-static int register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
-{
-#ifdef WIN32
- if (data)
- G.background = 1;
- RegisterBlendExtension();
-#else
- (void)data; /* unused */
-#endif
- return 0;
-}
-
-static int no_joystick(int UNUSED(argc), const char **UNUSED(argv), void *data)
-{
-#ifndef WITH_GAMEENGINE
- (void)data;
-#else
- SYS_SystemHandle *syshandle = data;
-
- /**
- * don't initialize joysticks if user doesn't want to use joysticks
- * failed joystick initialization delays over 5 seconds, before game engine start
- */
- SYS_WriteCommandLineInt(*syshandle, "nojoystick", 1);
- if (G.debug & G_DEBUG) printf("disabling nojoystick\n");
-#endif
-
- return 0;
-}
-
-static int no_glsl(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- GPU_extensions_disable();
- return 0;
-}
-
-static int no_audio(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- BKE_sound_force_device("Null");
- return 0;
-}
-
-static int set_audio(int argc, const char **argv, void *UNUSED(data))
-{
- if (argc < 1) {
- fprintf(stderr, "-setaudio require one argument\n");
- exit(1);
- }
-
- BKE_sound_force_device(argv[1]);
- return 1;
-}
-
-static int set_output(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- if (argc > 1) {
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- BLI_strncpy(scene->r.pic, argv[1], sizeof(scene->r.pic));
- }
- else {
- printf("\nError: no blend loaded. cannot use '-o / --render-output'.\n");
- }
- return 1;
- }
- else {
- printf("\nError: you must specify a path after '-o / --render-output'.\n");
- return 0;
- }
}
-static int set_engine(int argc, const char **argv, void *data)
+static void main_callback_setup(void)
{
- bContext *C = data;
- if (argc >= 2) {
- if (STREQ(argv[1], "help")) {
- RenderEngineType *type = NULL;
- printf("Blender Engine Listing:\n");
- for (type = R_engines.first; type; type = type->next) {
- printf("\t%s\n", type->idname);
- }
- exit(0);
- }
- else {
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- RenderData *rd = &scene->r;
-
- if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
- BLI_strncpy_utf8(rd->engine, argv[1], sizeof(rd->engine));
- }
- else {
- printf("\nError: engine not found '%s'\n", argv[1]);
- exit(1);
- }
- }
- else {
- printf("\nError: no blend loaded. order the arguments so '-E / --engine ' is after a blend is loaded.\n");
- }
- }
-
- return 1;
- }
- else {
- printf("\nEngine not specified, give 'help' for a list of available engines.\n");
- return 0;
- }
-}
-
-static int set_image_type(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- if (argc > 1) {
- const char *imtype = argv[1];
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- const char imtype_new = BKE_imtype_from_arg(imtype);
-
- if (imtype_new == R_IMF_IMTYPE_INVALID) {
- printf("\nError: Format from '-F / --render-format' not known or not compiled in this release.\n");
- }
- else {
- scene->r.im_format.imtype = imtype_new;
- }
- }
- else {
- printf("\nError: no blend loaded. order the arguments so '-F / --render-format' is after the blend is loaded.\n");
- }
- return 1;
- }
- else {
- printf("\nError: you must specify a format after '-F / --render-foramt'.\n");
- return 0;
- }
-}
-
-static int set_threads(int argc, const char **argv, void *UNUSED(data))
-{
- if (argc > 1) {
- int threads = atoi(argv[1]);
-
- if (threads >= 0 && threads <= BLENDER_MAX_THREADS) {
- BLI_system_num_threads_override_set(threads);
- }
- else {
- printf("Error, threads has to be in range 0-%d\n", BLENDER_MAX_THREADS);
- }
- return 1;
- }
- else {
- printf("\nError: you must specify a number of threads between 0 and %d '-t / --threads'.\n", BLENDER_MAX_THREADS);
- return 0;
- }
-}
-
-static int depsgraph_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
-{
- printf("Using new dependency graph.\n");
- DEG_depsgraph_switch_to_new();
- return 0;
-}
-
-static int set_verbosity(int argc, const char **argv, void *UNUSED(data))
-{
- if (argc > 1) {
- int level = atoi(argv[1]);
-
-#ifdef WITH_LIBMV
- libmv_setLoggingVerbosity(level);
-#elif defined(WITH_CYCLES_LOGGING)
- CCL_logging_verbosity_set(level);
-#else
- (void)level;
-#endif
-
- return 1;
- }
- else {
- printf("\nError: you must specify a verbosity level.\n");
- return 0;
- }
-}
-
-static int set_extension(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- if (argc > 1) {
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- if (argv[1][0] == '0') {
- scene->r.scemode &= ~R_EXTENSION;
- }
- else if (argv[1][0] == '1') {
- scene->r.scemode |= R_EXTENSION;
- }
- else {
- printf("\nError: Use '-x 1 / -x 0' To set the extension option or '--use-extension'\n");
- }
- }
- else {
- printf("\nError: no blend loaded. order the arguments so '-o ' is after '-x '.\n");
- }
- return 1;
- }
- else {
- printf("\nError: you must specify a path after '- '.\n");
- return 0;
- }
-}
-
-static int set_ge_parameters(int argc, const char **argv, void *data)
-{
- int a = 0;
-#ifdef WITH_GAMEENGINE
- SYS_SystemHandle syshandle = *(SYS_SystemHandle *)data;
-#else
- (void)data;
-#endif
-
- /**
- * gameengine parameters are automatically put into system
- * -g [paramname = value]
- * -g [boolparamname]
- * example:
- * -g novertexarrays
- * -g maxvertexarraysize = 512
- */
-
- if (argc >= 1) {
- const char *paramname = argv[a];
- /* check for single value versus assignment */
- if (a + 1 < argc && (*(argv[a + 1]) == '=')) {
- a++;
- if (a + 1 < argc) {
- a++;
- /* assignment */
-#ifdef WITH_GAMEENGINE
- SYS_WriteCommandLineString(syshandle, paramname, argv[a]);
-#endif
- }
- else {
- printf("error: argument assignment (%s) without value.\n", paramname);
- return 0;
- }
- /* name arg eaten */
-
- }
- else {
-#ifdef WITH_GAMEENGINE
- SYS_WriteCommandLineInt(syshandle, argv[a], 1);
-#endif
- /* doMipMap */
- if (STREQ(argv[a], "nomipmap")) {
- GPU_set_mipmap(0); //doMipMap = 0;
- }
- /* linearMipMap */
- if (STREQ(argv[a], "linearmipmap")) {
- GPU_set_mipmap(1);
- GPU_set_linear_mipmap(1); //linearMipMap = 1;
- }
-
-
- } /* if (*(argv[a + 1]) == '=') */
- }
-
- return a;
-}
-
-static int render_frame(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- Main *bmain = CTX_data_main(C);
-
- if (argc > 1) {
- Render *re = RE_NewRender(scene->id.name);
- int frame;
- ReportList reports;
-
- frame = parse_relative_int(argv[1], scene->r.sfra, scene->r.efra, MINAFRAME, MAXFRAME);
-
- BLI_begin_threaded_malloc();
- BKE_reports_init(&reports, RPT_PRINT);
-
- RE_SetReports(re, &reports);
- RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
- RE_SetReports(re, NULL);
- BLI_end_threaded_malloc();
- return 1;
- }
- else {
- printf("\nError: frame number must follow '-f / --render-frame'.\n");
- return 0;
- }
- }
- else {
- printf("\nError: no blend loaded. cannot use '-f / --render-frame'.\n");
- return 0;
- }
-}
-
-static int render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
-{
- bContext *C = data;
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- Main *bmain = CTX_data_main(C);
- Render *re = RE_NewRender(scene->id.name);
- ReportList reports;
- BLI_begin_threaded_malloc();
- BKE_reports_init(&reports, RPT_PRINT);
- RE_SetReports(re, &reports);
- RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
- RE_SetReports(re, NULL);
- BLI_end_threaded_malloc();
- }
- else {
- printf("\nError: no blend loaded. cannot use '-a'.\n");
- }
- return 0;
-}
-
-static int set_scene(int argc, const char **argv, void *data)
-{
- if (argc > 1) {
- bContext *C = data;
- Scene *scene = BKE_scene_set_name(CTX_data_main(C), argv[1]);
- if (scene) {
- CTX_data_scene_set(C, scene);
- }
- return 1;
- }
- else {
- printf("\nError: Scene name must follow '-S / --scene'.\n");
- return 0;
- }
-}
-
-static int set_start_frame(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- if (argc > 1) {
- scene->r.sfra = parse_relative_int(argv[1], scene->r.sfra, scene->r.sfra - 1, MINAFRAME, MAXFRAME);
-
- return 1;
- }
- else {
- printf("\nError: frame number must follow '-s / --frame-start'.\n");
- return 0;
- }
- }
- else {
- printf("\nError: no blend loaded. cannot use '-s / --frame-start'.\n");
- return 0;
- }
-}
-
-static int set_end_frame(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- if (argc > 1) {
- scene->r.efra = parse_relative_int(argv[1], scene->r.efra, scene->r.efra - 1, MINAFRAME, MAXFRAME);
- return 1;
- }
- else {
- printf("\nError: frame number must follow '-e / --frame-end'.\n");
- return 0;
- }
- }
- else {
- printf("\nError: no blend loaded. cannot use '-e / --frame-end'.\n");
- return 0;
- }
-}
-
-static int set_skip_frame(int argc, const char **argv, void *data)
-{
- bContext *C = data;
- Scene *scene = CTX_data_scene(C);
- if (scene) {
- if (argc > 1) {
- int frame = atoi(argv[1]);
- (scene->r.frame_step) = CLAMPIS(frame, 1, MAXFRAME);
- return 1;
- }
- else {
- printf("\nError: number of frames to step must follow '-j / --frame-jump'.\n");
- return 0;
- }
- }
- else {
- printf("\nError: no blend loaded. cannot use '-j / --frame-jump'.\n");
- return 0;
- }
-}
-
-/* macro for ugly context setup/reset */
-#ifdef WITH_PYTHON
-#define BPY_CTX_SETUP(_cmd) \
- { \
- wmWindowManager *wm = CTX_wm_manager(C); \
- Scene *scene_prev = CTX_data_scene(C); \
- wmWindow *win_prev; \
- const bool has_win = !BLI_listbase_is_empty(&wm->windows); \
- if (has_win) { \
- win_prev = CTX_wm_window(C); \
- CTX_wm_window_set(C, wm->windows.first); \
- } \
- else { \
- fprintf(stderr, "Python script \"%s\" " \
- "running with missing context data.\n", argv[1]); \
- } \
- { \
- _cmd; \
- } \
- if (has_win) { \
- CTX_wm_window_set(C, win_prev); \
- } \
- CTX_data_scene_set(C, scene_prev); \
- } (void)0 \
-
-#endif /* WITH_PYTHON */
-
-static int run_python_file(int argc, const char **argv, void *data)
-{
-#ifdef WITH_PYTHON
- bContext *C = data;
-
- /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
- if (argc > 1) {
- /* Make the path absolute because its needed for relative linked blends to be found */
- char filename[FILE_MAX];
- BLI_strncpy(filename, argv[1], sizeof(filename));
- BLI_path_cwd(filename);
-
- BPY_CTX_SETUP(BPY_filepath_exec(C, filename, NULL));
-
- return 1;
- }
- else {
- printf("\nError: you must specify a filepath after '%s'.\n", argv[0]);
- return 0;
- }
-#else
- UNUSED_VARS(argc, argv, data);
- printf("This blender was built without python support\n");
- return 0;
-#endif /* WITH_PYTHON */
-}
-
-static int run_python_text(int argc, const char **argv, void *data)
-{
-#ifdef WITH_PYTHON
- bContext *C = data;
-
- /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
- if (argc > 1) {
- /* Make the path absolute because its needed for relative linked blends to be found */
- struct Text *text = (struct Text *)BKE_libblock_find_name(ID_TXT, argv[1]);
-
- if (text) {
- BPY_CTX_SETUP(BPY_text_exec(C, text, NULL, false));
- return 1;
- }
- else {
- printf("\nError: text block not found %s.\n", argv[1]);
- return 1;
- }
- }
- else {
- printf("\nError: you must specify a text block after '%s'.\n", argv[0]);
- return 0;
- }
-#else
- UNUSED_VARS(argc, argv, data);
- printf("This blender was built without python support\n");
- return 0;
-#endif /* WITH_PYTHON */
-}
-
-static int run_python_expr(int argc, const char **argv, void *data)
-{
-#ifdef WITH_PYTHON
- bContext *C = data;
-
- /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
- if (argc > 1) {
- BPY_CTX_SETUP(BPY_string_exec_ex(C, argv[1], false));
- return 1;
- }
- else {
- printf("\nError: you must specify a Python expression after '%s'.\n", argv[0]);
- return 0;
- }
-#else
- UNUSED_VARS(argc, argv, data);
- printf("This blender was built without python support\n");
- return 0;
-#endif /* WITH_PYTHON */
-}
-
-static int run_python_console(int UNUSED(argc), const char **argv, void *data)
-{
-#ifdef WITH_PYTHON
- bContext *C = data;
-
- BPY_CTX_SETUP(BPY_string_exec(C, "__import__('code').interact()"));
-
- return 0;
-#else
- UNUSED_VARS(argv, data);
- printf("This blender was built without python support\n");
- return 0;
-#endif /* WITH_PYTHON */
-}
-
-static int set_addons(int argc, const char **argv, void *data)
-{
- /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
- if (argc > 1) {
-#ifdef WITH_PYTHON
- const char script_str[] =
- "from addon_utils import check, enable\n"
- "for m in '%s'.split(','):\n"
- " if check(m)[1] is False:\n"
- " enable(m, persistent=True)";
- const int slen = strlen(argv[1]) + (sizeof(script_str) - 2);
- char *str = malloc(slen);
- bContext *C = data;
- BLI_snprintf(str, slen, script_str, argv[1]);
-
- BLI_assert(strlen(str) + 1 == slen);
- BPY_CTX_SETUP(BPY_string_exec_ex(C, str, false));
- free(str);
-#else
- UNUSED_VARS(argv, data);
-#endif /* WITH_PYTHON */
- return 1;
- }
- else {
- printf("\nError: you must specify a comma separated list after '--addons'.\n");
- return 0;
- }
-}
-
-static int load_file(int UNUSED(argc), const char **argv, void *data)
-{
- bContext *C = data;
-
- /* Make the path absolute because its needed for relative linked blends to be found */
- char filename[FILE_MAX];
-
- /* note, we could skip these, but so far we always tried to load these files */
- if (argv[0][0] == '-') {
- fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]);
- }
-
- BLI_strncpy(filename, argv[0], sizeof(filename));
- BLI_path_cwd(filename);
-
- if (G.background) {
- Main *bmain;
- wmWindowManager *wm;
- int retval;
-
- bmain = CTX_data_main(C);
-
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_PRE);
-
- retval = BKE_read_file(C, filename, NULL);
-
- if (retval == BKE_READ_FILE_FAIL) {
- /* failed to load file, stop processing arguments */
- if (G.background) {
- /* Set is_break if running in the background mode so
- * blender will return non-zero exit code which then
- * could be used in automated script to control how
- * good or bad things are.
- */
- G.is_break = true;
- }
- return -1;
- }
-
- wm = CTX_wm_manager(C);
- bmain = CTX_data_main(C);
-
- /* special case, 2.4x files */
- if (wm == NULL && BLI_listbase_is_empty(&bmain->wm)) {
- extern void wm_add_default(bContext *C);
-
- /* wm_add_default() needs the screen to be set. */
- CTX_wm_screen_set(C, bmain->screen.first);
- wm_add_default(C);
- }
-
- CTX_wm_manager_set(C, NULL); /* remove wm to force check */
- WM_check(C);
- if (bmain->name[0]) {
- G.save_over = 1;
- G.relbase_valid = 1;
- }
- else {
- G.save_over = 0;
- G.relbase_valid = 0;
- }
-
- if (CTX_wm_manager(C) == NULL) {
- CTX_wm_manager_set(C, wm); /* reset wm */
- }
-
- /* WM_file_read would call normally */
- ED_editors_init(C);
- DAG_on_visible_update(bmain, true);
-
- /* WM_file_read() runs normally but since we're in background mode do here */
-#ifdef WITH_PYTHON
- /* run any texts that were loaded in and flagged as modules */
- BPY_python_reset(C);
-#endif
-
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
-
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
-
- /* happens for the UI on file reading too (huh? (ton))*/
- // XXX BKE_undo_reset();
- // BKE_undo_write("original"); /* save current state */
- }
- else {
- /* we are not running in background mode here, but start blender in UI mode with
- * a file - this should do everything a 'load file' does */
- ReportList reports;
- BKE_reports_init(&reports, RPT_PRINT);
- WM_file_autoexec_init(filename);
- WM_file_read(C, filename, &reports);
- BKE_reports_clear(&reports);
- }
-
- G.file_loaded = 1;
-
- return 0;
+ /* Error output from the alloc routines: */
+ MEM_set_error_callback(callback_mem_error);
}
-static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
-{
- static char output_doc[] = "<path>"
- "\n\tSet the render path and file name."
- "\n\tUse '//' at the start of the path to render relative to the blend file."
- "\n"
- "\n\tThe '#' characters are replaced by the frame number, and used to define zero padding."
- "\n\t* 'ani_##_test.png' becomes 'ani_01_test.png'"
- "\n\t* 'test-######.png' becomes 'test-000001.png'"
- "\n"
- "\n\tWhen the filename does not contain '#', The suffix '####' is added to the filename."
- "\n"
- "\n\tThe frame number will be added at the end of the filename, eg:"
- "\n\t# blender -b foobar.blend -o //render_ -F PNG -x 1 -a"
- "\n\t'//render_' becomes '//render_####', writing frames as '//render_0001.png'";
-
- static char format_doc[] = "<format>"
- "\n\tSet the render format, Valid options are..."
- "\n\t\tTGA IRIS JPEG MOVIE IRIZ RAWTGA"
- "\n\t\tAVIRAW AVIJPEG PNG BMP FRAMESERVER"
- "\n\t(formats that can be compiled into blender, not available on all systems)"
- "\n\t\tHDR TIFF EXR MULTILAYER MPEG AVICODEC QUICKTIME CINEON DPX DDS";
-
- static char playback_doc[] = "<options> <file(s)>"
- "\n\tPlayback <file(s)>, only operates this way when not running in background."
- "\n\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>"
- "\n\t\t-m\t\tRead from disk (Don't buffer)"
- "\n\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with"
- "\n\t\t-j <frame>\tSet frame step to <frame>"
- "\n\t\t-s <frame>\tPlay from <frame>"
- "\n\t\t-e <frame>\tPlay until <frame>";
-
- static char game_doc[] = "Game Engine specific options"
- "\n\t-g fixedtime\t\tRun on 50 hertz without dropping frames"
- "\n\t-g vertexarrays\t\tUse Vertex Arrays for rendering (usually faster)"
- "\n\t-g nomipmap\t\tNo Texture Mipmapping"
- "\n\t-g linearmipmap\t\tLinear Texture Mipmapping instead of Nearest (default)";
-
- static char debug_doc[] = "\n\tTurn debugging on\n"
- "\n\t* Enables memory error detection"
- "\n\t* Disables mouse grab (to interact with a debugger in some cases)"
- "\n\t* Keeps Python's 'sys.stdin' rather than setting it to None";
-
- //BLI_argsAdd(ba, pass, short_arg, long_arg, doc, cb, C);
-
- /* end argument processing after -- */
- BLI_argsAdd(ba, -1, "--", NULL, "\n\tEnds option processing, following arguments passed unchanged. Access via Python's 'sys.argv'", end_arguments, NULL);
-
- /* first pass: background mode, disable python and commands that exit after usage */
- BLI_argsAdd(ba, 1, "-h", "--help", "\n\tPrint this help text and exit", print_help, ba);
- /* Windows only */
- BLI_argsAdd(ba, 1, "/?", NULL, "\n\tPrint this help text and exit (windows only)", print_help, ba);
-
- BLI_argsAdd(ba, 1, "-v", "--version", "\n\tPrint Blender version and exit", print_version, NULL);
-
- /* only to give help message */
-#ifndef WITH_PYTHON_SECURITY /* default */
-# define PY_ENABLE_AUTO ", (default)"
-# define PY_DISABLE_AUTO ""
-#else
-# define PY_ENABLE_AUTO ""
-# define PY_DISABLE_AUTO ", (compiled as non-standard default)"
-#endif
-
- BLI_argsAdd(ba, 1, "-y", "--enable-autoexec", "\n\tEnable automatic Python script execution" PY_ENABLE_AUTO, enable_python, NULL);
- BLI_argsAdd(ba, 1, "-Y", "--disable-autoexec", "\n\tDisable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO, disable_python, NULL);
+/** \} */
- BLI_argsAdd(ba, 1, NULL, "--disable-crash-handler", "\n\tDisable the crash handler", disable_crash_handler, NULL);
- BLI_argsAdd(ba, 1, NULL, "--disable-abort-handler", "\n\tDisable the abort handler", disable_abort_handler, NULL);
-#undef PY_ENABLE_AUTO
-#undef PY_DISABLE_AUTO
-
- BLI_argsAdd(ba, 1, "-b", "--background", "\n\tRun in background (often used for UI-less rendering)", background_mode, NULL);
- BLI_argsAdd(ba, 1, "-a", NULL, playback_doc, playback_mode, NULL);
+/* -------------------------------------------------------------------- */
- BLI_argsAdd(ba, 1, "-d", "--debug", debug_doc, debug_mode, ba);
-
-#ifdef WITH_FFMPEG
- BLI_argsAdd(ba, 1, NULL, "--debug-ffmpeg", "\n\tEnable debug messages from FFmpeg library", debug_mode_generic, (void *)G_DEBUG_FFMPEG);
-#endif
-
-#ifdef WITH_FREESTYLE
- BLI_argsAdd(ba, 1, NULL, "--debug-freestyle", "\n\tEnable debug/profiling messages from Freestyle rendering", debug_mode_generic, (void *)G_DEBUG_FREESTYLE);
-#endif
-
- BLI_argsAdd(ba, 1, NULL, "--debug-python", "\n\tEnable debug messages for Python", debug_mode_generic, (void *)G_DEBUG_PYTHON);
- BLI_argsAdd(ba, 1, NULL, "--debug-events", "\n\tEnable debug messages for the event system", debug_mode_generic, (void *)G_DEBUG_EVENTS);
- BLI_argsAdd(ba, 1, NULL, "--debug-handlers", "\n\tEnable debug messages for event handling", debug_mode_generic, (void *)G_DEBUG_HANDLERS);
- BLI_argsAdd(ba, 1, NULL, "--debug-wm", "\n\tEnable debug messages for the window manager, also prints every operator call", debug_mode_generic, (void *)G_DEBUG_WM);
- BLI_argsAdd(ba, 1, NULL, "--debug-all", "\n\tEnable all debug messages (excludes libmv)", debug_mode_generic, (void *)G_DEBUG_ALL);
-
- BLI_argsAdd(ba, 1, NULL, "--debug-fpe", "\n\tEnable floating point exceptions", set_fpe, NULL);
-
-#ifdef WITH_LIBMV
- BLI_argsAdd(ba, 1, NULL, "--debug-libmv", "\n\tEnable debug messages from libmv library", debug_mode_libmv, NULL);
-#endif
-#ifdef WITH_CYCLES_LOGGING
- BLI_argsAdd(ba, 1, NULL, "--debug-cycles", "\n\tEnable debug messages from Cycles", debug_mode_cycles, NULL);
-#endif
- BLI_argsAdd(ba, 1, NULL, "--debug-memory", "\n\tEnable fully guarded memory allocation and debugging", debug_mode_memory, NULL);
-
- BLI_argsAdd(ba, 1, NULL, "--debug-value", "<value>\n\tSet debug value of <value> on startup\n", set_debug_value, NULL);
- BLI_argsAdd(ba, 1, NULL, "--debug-jobs", "\n\tEnable time profiling for background jobs.", debug_mode_generic, (void *)G_DEBUG_JOBS);
- BLI_argsAdd(ba, 1, NULL, "--debug-gpu", "\n\tEnable gpu debug context and information for OpenGL 4.3+.", debug_mode_generic, (void *)G_DEBUG_GPU);
- BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph", "\n\tEnable debug messages from dependency graph", debug_mode_generic, (void *)G_DEBUG_DEPSGRAPH);
- BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads", "\n\tSwitch dependency graph to a single threaded evaluation", debug_mode_generic, (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
- BLI_argsAdd(ba, 1, NULL, "--debug-gpumem", "\n\tEnable GPU memory stats in status bar", debug_mode_generic, (void *)G_DEBUG_GPU_MEM);
-
- BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", "\n\tUse new dependency graph", depsgraph_use_new, NULL);
-
- BLI_argsAdd(ba, 1, NULL, "--verbose", "<verbose>\n\tSet logging verbosity level.", set_verbosity, NULL);
-
- BLI_argsAdd(ba, 1, NULL, "--factory-startup", "\n\tSkip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory", set_factory_startup, NULL);
-
- /* TODO, add user env vars? */
- BLI_argsAdd(ba, 1, NULL, "--env-system-datafiles", "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_DATAFILES)" environment variable", set_env, NULL);
- BLI_argsAdd(ba, 1, NULL, "--env-system-scripts", "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_SCRIPTS)" environment variable", set_env, NULL);
- BLI_argsAdd(ba, 1, NULL, "--env-system-python", "\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_PYTHON)" environment variable", set_env, NULL);
-
- /* second pass: custom window stuff */
- BLI_argsAdd(ba, 2, "-p", "--window-geometry", "<sx> <sy> <w> <h>\n\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>", prefsize, NULL);
- BLI_argsAdd(ba, 2, "-w", "--window-border", "\n\tForce opening with borders (default)", with_borders, NULL);
- BLI_argsAdd(ba, 2, "-W", "--window-borderless", "\n\tForce opening without borders", without_borders, NULL);
- BLI_argsAdd(ba, 2, "-con", "--start-console", "\n\tStart with the console window open (ignored if -b is set), (Windows only)", start_with_console, NULL);
- BLI_argsAdd(ba, 2, "-R", NULL, "\n\tRegister .blend extension, then exit (Windows only)", register_extension, NULL);
- BLI_argsAdd(ba, 2, "-r", NULL, "\n\tSilently register .blend extension, then exit (Windows only)", register_extension, ba);
- BLI_argsAdd(ba, 2, NULL, "--no-native-pixels", "\n\tDo not use native pixel size, for high resolution displays (MacBook 'Retina')", native_pixels, ba);
-
- /* third pass: disabling things and forcing settings */
- BLI_argsAddCase(ba, 3, "-nojoystick", 1, NULL, 0, "\n\tDisable joystick support", no_joystick, syshandle);
- BLI_argsAddCase(ba, 3, "-noglsl", 1, NULL, 0, "\n\tDisable GLSL shading", no_glsl, NULL);
- BLI_argsAddCase(ba, 3, "-noaudio", 1, NULL, 0, "\n\tForce sound system to None", no_audio, NULL);
- BLI_argsAddCase(ba, 3, "-setaudio", 1, NULL, 0, "\n\tForce sound system to a specific device\n\tNULL SDL OPENAL JACK", set_audio, NULL);
-
- /* fourth pass: processing arguments */
- BLI_argsAdd(ba, 4, "-g", NULL, game_doc, set_ge_parameters, syshandle);
- BLI_argsAdd(ba, 4, "-f", "--render-frame", "<frame>\n\tRender frame <frame> and save it.\n\t+<frame> start frame relative, -<frame> end frame relative.", render_frame, C);
- BLI_argsAdd(ba, 4, "-a", "--render-anim", "\n\tRender frames from start to end (inclusive)", render_animation, C);
- BLI_argsAdd(ba, 4, "-S", "--scene", "<name>\n\tSet the active scene <name> for rendering", set_scene, C);
- BLI_argsAdd(ba, 4, "-s", "--frame-start", "<frame>\n\tSet start to frame <frame>, supports +/- for relative frames too.", set_start_frame, C);
- BLI_argsAdd(ba, 4, "-e", "--frame-end", "<frame>\n\tSet end to frame <frame>, supports +/- for relative frames too.", set_end_frame, C);
- BLI_argsAdd(ba, 4, "-j", "--frame-jump", "<frames>\n\tSet number of frames to step forward after each rendered frame", set_skip_frame, C);
- BLI_argsAdd(ba, 4, "-P", "--python", "<filename>\n\tRun the given Python script file", run_python_file, C);
- BLI_argsAdd(ba, 4, NULL, "--python-text", "<name>\n\tRun the given Python script text block", run_python_text, C);
- BLI_argsAdd(ba, 4, NULL, "--python-expr", "<expression>\n\tRun the given expression as a Python script", run_python_expr, C);
- BLI_argsAdd(ba, 4, NULL, "--python-console", "\n\tRun blender with an interactive console", run_python_console, C);
- BLI_argsAdd(ba, 4, NULL, "--addons", "\n\tComma separated list of addons (no spaces)", set_addons, C);
-
- BLI_argsAdd(ba, 4, "-o", "--render-output", output_doc, set_output, C);
- BLI_argsAdd(ba, 4, "-E", "--engine", "<engine>\n\tSpecify the render engine\n\tuse -E help to list available engines", set_engine, C);
-
- BLI_argsAdd(ba, 4, "-F", "--render-format", format_doc, set_image_type, C);
- BLI_argsAdd(ba, 4, "-t", "--threads", "<threads>\n\tUse amount of <threads> for rendering and other operations\n\t[1-" STRINGIFY(BLENDER_MAX_THREADS) "], 0 for systems processor count.", set_threads, NULL);
- BLI_argsAdd(ba, 4, "-x", "--use-extension", "<bool>\n\tSet option to add the file extension to the end of the file", set_extension, C);
-
-}
-#endif /* WITH_PYTHON_MODULE */
+/** \name Main Function
+ * \{ */
#ifdef WITH_PYTHON_MODULE
/* allow python module to call main */
@@ -1631,11 +174,11 @@ char **environ = NULL;
#endif
/**
- * Blender's main function responsabilities are:
+ * Blender's main function responsibilities are:
* - setup subsystems.
* - handle arguments.
- * - run WM_main() event loop,
- * or exit when running in background mode.
+ * - run #WM_main() event loop,
+ * or exit immediately when running in background mode.
*/
int main(
int argc,
@@ -1662,6 +205,11 @@ int main(
#ifdef WIN32
+ /* We delay loading of openmp so we can set the policy here. */
+# if defined(_MSC_VER)
+ _putenv_s("OMP_WAIT_POLICY", "PASSIVE");
+# endif
+
/* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */
# if defined(_MSC_VER) && defined(_M_X64)
_set_FMA3_enable(0);
@@ -1744,7 +292,7 @@ int main(
CCL_init_logging(argv[0]);
#endif
- setCallbacks();
+ main_callback_setup();
#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
/* patch to ignore argument finder gives us (pid?) */
@@ -1778,7 +326,7 @@ int main(
DAG_init();
BKE_brush_system_init();
- RE_init_texture_rng();
+ RE_texture_rng_init();
BLI_callback_global_init();
@@ -1792,22 +340,11 @@ int main(
/* first test for background */
#ifndef WITH_PYTHON_MODULE
ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */
- setupArguments(C, ba, &syshandle);
+ main_args_setup(C, ba, &syshandle);
BLI_argsParse(ba, 1, NULL, NULL);
- if (use_crash_handler) {
-#ifdef WIN32
- SetUnhandledExceptionFilter(windows_exception_handler);
-#else
- /* after parsing args */
- signal(SIGSEGV, blender_crash_handler);
-#endif
- }
-
- if (use_abort_handler) {
- signal(SIGABRT, blender_abort_handler);
- }
+ main_signal_setup();
#else
G.factory_startup = true; /* using preferences or user startup makes no sense for py-as-module */
@@ -1830,9 +367,8 @@ int main(
#if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS)
G.background = true; /* python module mode ALWAYS runs in background mode (for now) */
#else
- /* for all platforms, even windos has it! */
if (G.background) {
- signal(SIGINT, blender_esc); /* ctrl c out bg render */
+ main_signal_setup_background();
}
#endif
@@ -1890,7 +426,7 @@ int main(
/* OK we are ready for it */
#ifndef WITH_PYTHON_MODULE
- BLI_argsParse(ba, 4, load_file, C);
+ main_args_setup_post(C, ba);
if (G.background == 0) {
if (!G.file_loaded)
@@ -1917,7 +453,7 @@ int main(
#endif
if (G.background) {
- /* actually incorrect, but works for now (ton) */
+ /* Using window-manager API in background mode is a bit odd, but works fine. */
WM_exit(C);
}
else {
@@ -1953,14 +489,4 @@ void main_python_exit(void)
}
#endif
-static void mem_error_cb(const char *errorStr)
-{
- fputs(errorStr, stderr);
- fflush(stderr);
-}
-
-static void setCallbacks(void)
-{
- /* Error output from the alloc routines: */
- MEM_set_error_callback(mem_error_cb);
-}
+/** \} */
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
new file mode 100644
index 00000000000..c2ded1f2b09
--- /dev/null
+++ b/source/creator/creator_args.c
@@ -0,0 +1,1870 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file creator/creator_args.c
+ * \ingroup creator
+ */
+
+#ifndef WITH_PYTHON_MODULE
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "MEM_guardedalloc.h"
+
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
+
+#include "BLI_args.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_path_util.h"
+#include "BLI_fileops.h"
+#include "BLI_mempool.h"
+
+#include "BKE_blender.h"
+#include "BKE_context.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_report.h"
+#include "BKE_sound.h"
+#include "BKE_image.h"
+
+#include "DEG_depsgraph.h"
+
+#ifdef WITH_FFMPEG
+#include "IMB_imbuf.h"
+#endif
+
+#ifdef WITH_PYTHON
+#include "BPY_extern.h"
+#endif
+
+#include "RE_engine.h"
+#include "RE_pipeline.h"
+
+#include "ED_datafiles.h"
+
+#include "WM_api.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+
+/* for passing information between creator and gameengine */
+#ifdef WITH_GAMEENGINE
+# include "BL_System.h"
+#else /* dummy */
+# define SYS_SystemHandle int
+#endif
+
+#ifdef WITH_LIBMV
+# include "libmv-capi.h"
+#endif
+
+#ifdef WITH_CYCLES_LOGGING
+# include "CCL_api.h"
+#endif
+
+#include "creator_intern.h" /* own include */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Utility String Parsing
+ * \{ */
+
+static bool parse_int_relative(
+ const char *str, const char *str_end_test, int pos, int neg,
+ int *r_value, const char **r_err_msg)
+{
+ char *str_end = NULL;
+ long value;
+
+ errno = 0;
+
+ switch (*str) {
+ case '+':
+ value = pos + strtol(str + 1, &str_end, 10);
+ break;
+ case '-':
+ value = (neg - strtol(str + 1, &str_end, 10)) + 1;
+ break;
+ default:
+ value = strtol(str, &str_end, 10);
+ break;
+ }
+
+
+ if (*str_end != '\0' && (str_end != str_end_test)) {
+ static const char *msg = "not a number";
+ *r_err_msg = msg;
+ return false;
+ }
+ else if ((errno == ERANGE) || ((value < INT_MIN || value > INT_MAX))) {
+ static const char *msg = "exceeds range";
+ *r_err_msg = msg;
+ return false;
+ }
+ else {
+ *r_value = (int)value;
+ return true;
+ }
+}
+
+static const char *parse_int_range_sep_search(const char *str, const char *str_end_test)
+{
+ const char *str_end_range = NULL;
+ if (str_end_test) {
+ str_end_range = memchr(str, '.', (str_end_test - str) - 1);
+ if (str_end_range && (str_end_range[1] != '.')) {
+ str_end_range = NULL;
+ }
+ }
+ else {
+ str_end_range = strstr(str, "..");
+ if (str_end_range && (str_end_range[2] == '\0')) {
+ str_end_range = NULL;
+ }
+ }
+ return str_end_range;
+}
+
+/**
+ * Parse a number as a range, eg: `1..4`.
+ *
+ * The \a str_end_range argument is a result of #parse_int_range_sep_search.
+ */
+static bool parse_int_range_relative(
+ const char *str, const char *str_end_range, const char *str_end_test, int pos, int neg,
+ int r_value_range[2], const char **r_err_msg)
+{
+ if (parse_int_relative(str, str_end_range, pos, neg, &r_value_range[0], r_err_msg) &&
+ parse_int_relative(str_end_range + 2, str_end_test, pos, neg, &r_value_range[1], r_err_msg))
+ {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static bool parse_int_relative_clamp(
+ const char *str, const char *str_end_test, int pos, int neg, int min, int max,
+ int *r_value, const char **r_err_msg)
+{
+ if (parse_int_relative(str, str_end_test, pos, neg, r_value, r_err_msg)) {
+ CLAMP(*r_value, min, max);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static bool parse_int_range_relative_clamp(
+ const char *str, const char *str_end_range, const char *str_end_test, int pos, int neg, int min, int max,
+ int r_value_range[2], const char **r_err_msg)
+{
+ if (parse_int_range_relative(str, str_end_range, str_end_test, pos, neg, r_value_range, r_err_msg)) {
+ CLAMP(r_value_range[0], min, max);
+ CLAMP(r_value_range[1], min, max);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * No clamping, fails with any number outside the range.
+ */
+static bool parse_int_strict_range(
+ const char *str, const char *str_end_test, const int min, const int max,
+ int *r_value, const char **r_err_msg)
+{
+ char *str_end = NULL;
+ long value;
+
+ errno = 0;
+ value = strtol(str, &str_end, 10);
+
+ if (*str_end != '\0' && (str_end != str_end_test)) {
+ static const char *msg = "not a number";
+ *r_err_msg = msg;
+ return false;
+ }
+ else if ((errno == ERANGE) || ((value < min || value > max))) {
+ static const char *msg = "exceeds range";
+ *r_err_msg = msg;
+ return false;
+ }
+ else {
+ *r_value = (int)value;
+ return true;
+ }
+}
+
+static bool parse_int(
+ const char *str, const char *str_end_test,
+ int *r_value, const char **r_err_msg)
+{
+ return parse_int_strict_range(str, str_end_test, INT_MIN, INT_MAX, r_value, r_err_msg);
+}
+
+static bool parse_int_clamp(
+ const char *str, const char *str_end_test, int min, int max,
+ int *r_value, const char **r_err_msg)
+{
+ if (parse_int(str, str_end_test, r_value, r_err_msg)) {
+ CLAMP(*r_value, min, max);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+#if 0
+/**
+ * Version of #parse_int_relative_clamp
+ * that parses a comma separated list of numbers.
+ */
+static int *parse_int_relative_clamp_n(
+ const char *str, int pos, int neg, int min, int max,
+ int *r_value_len, const char **r_err_msg)
+{
+ const char sep = ',';
+ int len = 1;
+ for (int i = 0; str[i]; i++) {
+ if (str[i] == sep) {
+ len++;
+ }
+ }
+
+ int *values = MEM_mallocN(sizeof(*values) * len, __func__);
+ int i = 0;
+ while (true) {
+ const char *str_end = strchr(str, sep);
+ if ((*str == sep) || (*str == '\0')) {
+ static const char *msg = "incorrect comma use";
+ *r_err_msg = msg;
+ goto fail;
+
+ }
+ else if (parse_int_relative_clamp(str, str_end, pos, neg, min, max, &values[i], r_err_msg)) {
+ i++;
+ }
+ else {
+ goto fail; /* error message already set */
+ }
+
+ if (str_end) { /* next */
+ str = str_end + 1;
+ }
+ else { /* finished */
+ break;
+ }
+ }
+
+ *r_value_len = i;
+ return values;
+
+fail:
+ MEM_freeN(values);
+ return NULL;
+}
+
+#endif
+
+/**
+ * Version of #parse_int_relative_clamp & #parse_int_range_relative_clamp
+ * that parses a comma separated list of numbers.
+ *
+ * \note single values are evaluated as a range with matching start/end.
+ */
+static int (*parse_int_range_relative_clamp_n(
+ const char *str, int pos, int neg, int min, int max,
+ int *r_value_len, const char **r_err_msg))[2]
+{
+ const char sep = ',';
+ int len = 1;
+ for (int i = 0; str[i]; i++) {
+ if (str[i] == sep) {
+ len++;
+ }
+ }
+
+ int (*values)[2] = MEM_mallocN(sizeof(*values) * len, __func__);
+ int i = 0;
+ while (true) {
+ const char *str_end_range;
+ const char *str_end = strchr(str, sep);
+ if ((*str == sep) || (*str == '\0')) {
+ static const char *msg = "incorrect comma use";
+ *r_err_msg = msg;
+ goto fail;
+ }
+ else if ((str_end_range = parse_int_range_sep_search(str, str_end)) ?
+ parse_int_range_relative_clamp(str, str_end_range, str_end, pos, neg, min, max, values[i], r_err_msg) :
+ parse_int_relative_clamp(str, str_end, pos, neg, min, max, &values[i][0], r_err_msg))
+ {
+ if (str_end_range == NULL) {
+ values[i][1] = values[i][0];
+ }
+ i++;
+ }
+ else {
+ goto fail; /* error message already set */
+ }
+
+ if (str_end) { /* next */
+ str = str_end + 1;
+ }
+ else { /* finished */
+ break;
+ }
+ }
+
+ *r_value_len = i;
+ return values;
+
+fail:
+ MEM_freeN(values);
+ return NULL;
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+#ifdef WITH_PYTHON
+
+/** \name Utilities Python Context Macro (#BPY_CTX_SETUP)
+ * \{ */
+struct BlendePyContextStore {
+ wmWindowManager *wm;
+ Scene *scene;
+ wmWindow *win;
+ bool has_win;
+};
+
+static void arg_py_context_backup(
+ bContext *C, struct BlendePyContextStore *c_py,
+ const char *script_id)
+{
+ c_py->wm = CTX_wm_manager(C);
+ c_py->scene = CTX_data_scene(C);
+ c_py->has_win = !BLI_listbase_is_empty(&c_py->wm->windows);
+ if (c_py->has_win) {
+ c_py->win = CTX_wm_window(C);
+ CTX_wm_window_set(C, c_py->wm->windows.first);
+ }
+ else {
+ c_py->win = NULL;
+ fprintf(stderr, "Python script \"%s\" "
+ "running with missing context data.\n", script_id);
+ }
+}
+
+static void arg_py_context_restore(
+ bContext *C, struct BlendePyContextStore *c_py)
+{
+ /* script may load a file, check old data is valid before using */
+ if (c_py->has_win) {
+ if ((c_py->win == NULL) ||
+ ((BLI_findindex(&G.main->wm, c_py->wm) != -1) &&
+ (BLI_findindex(&c_py->wm->windows, c_py->win) != -1)))
+ {
+ CTX_wm_window_set(C, c_py->win);
+ }
+ }
+
+ if ((c_py->scene == NULL) ||
+ BLI_findindex(&G.main->scene, c_py->scene) != -1)
+ {
+ CTX_data_scene_set(C, c_py->scene);
+ }
+}
+
+/* macro for context setup/reset */
+#define BPY_CTX_SETUP(_cmd) \
+ { \
+ struct BlendePyContextStore py_c; \
+ arg_py_context_backup(C, &py_c, argv[1]); \
+ { _cmd; } \
+ arg_py_context_restore(C, &py_c); \
+ } ((void)0)
+
+#endif /* WITH_PYTHON */
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Handle Argument Callbacks
+ *
+ * \note Doc strings here are used in differently:
+ *
+ * - The `--help` message.
+ * - The man page (for Unix systems),
+ * see: `doc/manpage/blender.1.py`
+ * - Parsed and extracted for the manual,
+ * which converts our ad-hoc formatting to reStructuredText.
+ * see: http://www.blender.org/manual/advanced/command_line.html
+ *
+ * \{ */
+
+static const char arg_handle_print_version_doc[] =
+"\n\tPrint Blender version and exit"
+;
+static int arg_handle_print_version(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ printf(BLEND_VERSION_STRING_FMT);
+#ifdef BUILD_DATE
+ printf("\tbuild date: %s\n", build_date);
+ printf("\tbuild time: %s\n", build_time);
+ printf("\tbuild commit date: %s\n", build_commit_date);
+ printf("\tbuild commit time: %s\n", build_commit_time);
+ printf("\tbuild hash: %s\n", build_hash);
+ printf("\tbuild platform: %s\n", build_platform);
+ printf("\tbuild type: %s\n", build_type);
+ printf("\tbuild c flags: %s\n", build_cflags);
+ printf("\tbuild c++ flags: %s\n", build_cxxflags);
+ printf("\tbuild link flags: %s\n", build_linkflags);
+ printf("\tbuild system: %s\n", build_system);
+#endif
+ exit(0);
+
+ return 0;
+}
+
+static const char arg_handle_print_help_doc[] =
+"\n\tPrint this help text and exit"
+;
+static const char arg_handle_print_help_doc_win32[] =
+"\n\tPrint this help text and exit (windows only)"
+;
+static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+ bArgs *ba = (bArgs *)data;
+
+ printf(BLEND_VERSION_STRING_FMT);
+ printf("Usage: blender [args ...] [file] [args ...]\n\n");
+
+ printf("Render Options:\n");
+ BLI_argsPrintArgDoc(ba, "--background");
+ BLI_argsPrintArgDoc(ba, "--render-anim");
+ BLI_argsPrintArgDoc(ba, "--scene");
+ BLI_argsPrintArgDoc(ba, "--render-frame");
+ BLI_argsPrintArgDoc(ba, "--frame-start");
+ BLI_argsPrintArgDoc(ba, "--frame-end");
+ BLI_argsPrintArgDoc(ba, "--frame-jump");
+ BLI_argsPrintArgDoc(ba, "--render-output");
+ BLI_argsPrintArgDoc(ba, "--engine");
+ BLI_argsPrintArgDoc(ba, "--threads");
+
+ printf("\n");
+ printf("Format Options:\n");
+ BLI_argsPrintArgDoc(ba, "--render-format");
+ BLI_argsPrintArgDoc(ba, "--use-extension");
+
+ printf("\n");
+ printf("Animation Playback Options:\n");
+ BLI_argsPrintArgDoc(ba, "-a");
+
+ printf("\n");
+ printf("Window Options:\n");
+ BLI_argsPrintArgDoc(ba, "--window-border");
+ BLI_argsPrintArgDoc(ba, "--window-borderless");
+ BLI_argsPrintArgDoc(ba, "--window-geometry");
+ BLI_argsPrintArgDoc(ba, "--start-console");
+ BLI_argsPrintArgDoc(ba, "--no-native-pixels");
+
+
+ printf("\n");
+ printf("Game Engine Specific Options:\n");
+ BLI_argsPrintArgDoc(ba, "-g");
+
+ printf("\n");
+ printf("Python Options:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-autoexec");
+ BLI_argsPrintArgDoc(ba, "--disable-autoexec");
+
+ printf("\n");
+
+ BLI_argsPrintArgDoc(ba, "--python");
+ BLI_argsPrintArgDoc(ba, "--python-text");
+ BLI_argsPrintArgDoc(ba, "--python-expr");
+ BLI_argsPrintArgDoc(ba, "--python-console");
+ BLI_argsPrintArgDoc(ba, "--python-exit-code");
+ BLI_argsPrintArgDoc(ba, "--addons");
+
+
+ printf("\n");
+ printf("Debug Options:\n");
+ BLI_argsPrintArgDoc(ba, "--debug");
+ BLI_argsPrintArgDoc(ba, "--debug-value");
+
+ printf("\n");
+ BLI_argsPrintArgDoc(ba, "--debug-events");
+#ifdef WITH_FFMPEG
+ BLI_argsPrintArgDoc(ba, "--debug-ffmpeg");
+#endif
+ BLI_argsPrintArgDoc(ba, "--debug-handlers");
+#ifdef WITH_LIBMV
+ BLI_argsPrintArgDoc(ba, "--debug-libmv");
+#endif
+#ifdef WITH_CYCLES_LOGGING
+ BLI_argsPrintArgDoc(ba, "--debug-cycles");
+#endif
+ BLI_argsPrintArgDoc(ba, "--debug-memory");
+ BLI_argsPrintArgDoc(ba, "--debug-jobs");
+ BLI_argsPrintArgDoc(ba, "--debug-python");
+ BLI_argsPrintArgDoc(ba, "--debug-depsgraph");
+ BLI_argsPrintArgDoc(ba, "--debug-depsgraph-no-threads");
+
+ BLI_argsPrintArgDoc(ba, "--debug-gpumem");
+ BLI_argsPrintArgDoc(ba, "--debug-wm");
+ BLI_argsPrintArgDoc(ba, "--debug-all");
+
+ printf("\n");
+ BLI_argsPrintArgDoc(ba, "--debug-fpe");
+ BLI_argsPrintArgDoc(ba, "--disable-crash-handler");
+
+ printf("\n");
+ printf("Misc Options:\n");
+ BLI_argsPrintArgDoc(ba, "--factory-startup");
+ printf("\n");
+ BLI_argsPrintArgDoc(ba, "--env-system-datafiles");
+ BLI_argsPrintArgDoc(ba, "--env-system-scripts");
+ BLI_argsPrintArgDoc(ba, "--env-system-python");
+ printf("\n");
+ BLI_argsPrintArgDoc(ba, "-nojoystick");
+ BLI_argsPrintArgDoc(ba, "-noglsl");
+ BLI_argsPrintArgDoc(ba, "-noaudio");
+ BLI_argsPrintArgDoc(ba, "-setaudio");
+
+ printf("\n");
+
+ BLI_argsPrintArgDoc(ba, "--help");
+
+#ifdef WIN32
+ BLI_argsPrintArgDoc(ba, "-R");
+ BLI_argsPrintArgDoc(ba, "-r");
+#endif
+ BLI_argsPrintArgDoc(ba, "--version");
+
+ BLI_argsPrintArgDoc(ba, "--");
+
+ printf("Other Options:\n");
+ BLI_argsPrintOtherDoc(ba);
+
+ printf("Argument Parsing:\n");
+ printf("\tArguments must be separated by white space, eg:\n");
+ printf("\t# blender -ba test.blend\n");
+ printf("\t...will ignore the 'a'\n");
+ printf("\t# blender -b test.blend -f8\n");
+ printf("\t...will ignore '8' because there is no space between the '-f' and the frame value\n\n");
+
+ printf("Argument Order:\n");
+ printf("\tArguments are executed in the order they are given. eg:\n");
+ printf("\t# blender --background test.blend --render-frame 1 --render-output '/tmp'\n");
+ printf("\t...will not render to '/tmp' because '--render-frame 1' renders before the output path is set\n");
+ printf("\t# blender --background --render-output /tmp test.blend --render-frame 1\n");
+ printf("\t...will not render to '/tmp' because loading the blend-file overwrites the render output that was set\n");
+ printf("\t# blender --background test.blend --render-output /tmp --render-frame 1\n");
+ printf("\t...works as expected.\n\n");
+
+ printf("Environment Variables:\n");
+ printf(" $BLENDER_USER_CONFIG Directory for user configuration files.\n");
+ printf(" $BLENDER_USER_SCRIPTS Directory for user scripts.\n");
+ printf(" $BLENDER_SYSTEM_SCRIPTS Directory for system wide scripts.\n");
+ printf(" $BLENDER_USER_DATAFILES Directory for user data files (icons, translations, ..).\n");
+ printf(" $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n");
+ printf(" $BLENDER_SYSTEM_PYTHON Directory for system python libraries.\n");
+#ifdef WIN32
+ printf(" $TEMP Store temporary files here.\n");
+#else
+ printf(" $TMP or $TMPDIR Store temporary files here.\n");
+#endif
+#ifdef WITH_SDL
+ printf(" $SDL_AUDIODRIVER LibSDL audio driver - alsa, esd, dma.\n");
+#endif
+ printf(" $PYTHONHOME Path to the python directory, eg. /usr/lib/python.\n\n");
+
+ /* keep last */
+ printf("\n");
+ printf("Experimental Features:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+
+ exit(0);
+
+ return 0;
+}
+
+static const char arg_handle_arguments_end_doc[] =
+"\n\tEnds option processing, following arguments passed unchanged. Access via Python's 'sys.argv'"
+;
+static int arg_handle_arguments_end(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ return -1;
+}
+
+/* only to give help message */
+#ifndef WITH_PYTHON_SECURITY /* default */
+# define PY_ENABLE_AUTO ", (default)"
+# define PY_DISABLE_AUTO ""
+#else
+# define PY_ENABLE_AUTO ""
+# define PY_DISABLE_AUTO ", (compiled as non-standard default)"
+#endif
+
+static const char arg_handle_python_set_doc_enable[] =
+"\n\tEnable automatic Python script execution" PY_ENABLE_AUTO
+;
+static const char arg_handle_python_set_doc_disable[] =
+"\n\tDisable automatic Python script execution (pydrivers & startup scripts)" PY_DISABLE_AUTO
+;
+#undef PY_ENABLE_AUTO
+#undef PY_DISABLE_AUTO
+
+static int arg_handle_python_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+ if ((bool)data) {
+ G.f |= G_SCRIPT_AUTOEXEC;
+ }
+ else {
+ G.f &= ~G_SCRIPT_AUTOEXEC;
+ }
+ G.f |= G_SCRIPT_OVERRIDE_PREF;
+ return 0;
+}
+
+static const char arg_handle_crash_handler_disable_doc[] =
+"\n\tDisable the crash handler"
+;
+static int arg_handle_crash_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ app_state.signal.use_crash_handler = false;
+ return 0;
+}
+
+static const char arg_handle_abort_handler_disable_doc[] =
+"\n\tDisable the abort handler"
+;
+static int arg_handle_abort_handler_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ app_state.signal.use_abort_handler = false;
+ return 0;
+}
+
+static const char arg_handle_background_mode_set_doc[] =
+"\n\tRun in background (often used for UI-less rendering)"
+;
+static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ G.background = 1;
+ return 0;
+}
+
+static const char arg_handle_debug_mode_set_doc[] =
+"\n"
+"\tTurn debugging on\n"
+"\n"
+"\t* Enables memory error detection\n"
+"\t* Disables mouse grab (to interact with a debugger in some cases)\n"
+"\t* Keeps Python's 'sys.stdin' rather than setting it to None"
+;
+static int arg_handle_debug_mode_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+ G.debug |= G_DEBUG; /* std output printf's */
+ printf(BLEND_VERSION_STRING_FMT);
+ MEM_set_memory_debug();
+#ifndef NDEBUG
+ BLI_mempool_set_memory_debug();
+#endif
+
+#ifdef WITH_BUILDINFO
+ printf("Build: %s %s %s %s\n", build_date, build_time, build_platform, build_type);
+#endif
+
+ BLI_argsPrint(data);
+ return 0;
+}
+
+#ifdef WITH_FFMPEG
+static const char arg_handle_debug_mode_generic_set_doc_ffmpeg[] =
+"\n\tEnable debug messages from FFmpeg library";
+#endif
+#ifdef WITH_FREESTYLE
+static const char arg_handle_debug_mode_generic_set_doc_freestyle[] =
+"\n\tEnable debug messages for FreeStyle";
+#endif
+static const char arg_handle_debug_mode_generic_set_doc_python[] =
+"\n\tEnable debug messages for Python";
+static const char arg_handle_debug_mode_generic_set_doc_events[] =
+"\n\tEnable debug messages for the event system";
+static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
+"\n\tEnable debug messages for event handling";
+static const char arg_handle_debug_mode_generic_set_doc_wm[] =
+"\n\tEnable debug messages for the window manager, also prints every operator call";
+static const char arg_handle_debug_mode_generic_set_doc_all[] =
+"\n\tEnable all debug messages (excludes libmv)";
+static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
+"\n\tEnable time profiling for background jobs.";
+static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
+"\n\tEnable gpu debug context and information for OpenGL 4.3+.";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph[] =
+"\n\tEnable debug messages from dependency graph";
+static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] =
+"\n\tSwitch dependency graph to a single threaded evaluation";
+static const char arg_handle_debug_mode_generic_set_doc_gpumem[] =
+"\n\tEnable GPU memory stats in status bar";
+
+static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+ G.debug |= GET_INT_FROM_POINTER(data);
+ return 0;
+}
+
+#ifdef WITH_LIBMV
+static const char arg_handle_debug_mode_libmv_doc[] =
+"\n\tEnable debug messages from libmv library"
+;
+static int arg_handle_debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ libmv_startDebugLogging();
+
+ return 0;
+}
+#endif
+
+#ifdef WITH_CYCLES_LOGGING
+static const char arg_handle_debug_mode_cycles_doc[] =
+"\n\tEnable debug messages from Cycles"
+;
+static int arg_handle_debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ CCL_start_debug_logging();
+ return 0;
+}
+#endif
+
+static const char arg_handle_debug_mode_memory_set_doc[] =
+"\n\tEnable fully guarded memory allocation and debugging"
+;
+static int arg_handle_debug_mode_memory_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ MEM_set_memory_debug();
+ return 0;
+}
+
+static const char arg_handle_debug_value_set_doc[] =
+"<value>\n"
+"\tSet debug value of <value> on startup\n"
+;
+static int arg_handle_debug_value_set(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "--debug-value";
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ int value;
+ if (!parse_int(argv[1], NULL, &value, &err_msg)) {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ return 1;
+ }
+
+ G.debug_value = value;
+
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify debug value to set.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_debug_fpe_set_doc[] =
+"\n\tEnable floating point exceptions"
+;
+static int arg_handle_debug_fpe_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ main_signal_setup_fpe();
+ return 0;
+}
+
+static const char arg_handle_factory_startup_set_doc[] =
+"\n\tSkip reading the " STRINGIFY(BLENDER_STARTUP_FILE) " in the users home directory"
+;
+static int arg_handle_factory_startup_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ G.factory_startup = 1;
+ return 0;
+}
+
+static const char arg_handle_env_system_set_doc_datafiles[] =
+"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_DATAFILES)" environment variable";
+static const char arg_handle_env_system_set_doc_scripts[] =
+"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_SCRIPTS)" environment variable";
+static const char arg_handle_env_system_set_doc_python[] =
+"\n\tSet the "STRINGIFY_ARG (BLENDER_SYSTEM_PYTHON)" environment variable";
+
+static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data))
+{
+ /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */
+
+ char env[64] = "BLENDER";
+ char *ch_dst = env + 7; /* skip BLENDER */
+ const char *ch_src = argv[0] + 5; /* skip --env */
+
+ if (argc < 2) {
+ printf("%s requires one argument\n", argv[0]);
+ exit(1);
+ }
+
+ for (; *ch_src; ch_src++, ch_dst++) {
+ *ch_dst = (*ch_src == '-') ? '_' : (*ch_src) - 32; /* toupper() */
+ }
+
+ *ch_dst = '\0';
+ BLI_setenv(env, argv[1]);
+ return 1;
+}
+
+static const char arg_handle_playback_mode_doc[] =
+"<options> <file(s)>\n"
+"\tPlayback <file(s)>, only operates this way when not running in background.\n"
+"\t\t-p <sx> <sy>\tOpen with lower left corner at <sx>, <sy>\n"
+"\t\t-m\t\tRead from disk (Don't buffer)\n"
+"\t\t-f <fps> <fps-base>\t\tSpecify FPS to start with\n"
+"\t\t-j <frame>\tSet frame step to <frame>\n"
+"\t\t-s <frame>\tPlay from <frame>\n"
+"\t\t-e <frame>\tPlay until <frame>"
+;
+static int arg_handle_playback_mode(int argc, const char **argv, void *UNUSED(data))
+{
+ /* not if -b was given first */
+ if (G.background == 0) {
+#ifdef WITH_FFMPEG
+ /* Setup FFmpeg with current debug flags. */
+ IMB_ffmpeg_init();
+#endif
+
+ WM_main_playanim(argc, argv); /* not the same argc and argv as before */
+ exit(0); /* 2.4x didn't do this */
+ }
+
+ return -2;
+}
+
+static const char arg_handle_window_geometry_doc[] =
+"<sx> <sy> <w> <h>\n"
+"\tOpen with lower left corner at <sx>, <sy> and width and height as <w>, <h>"
+;
+static int arg_handle_window_geometry(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "-p / --window-geometry";
+ int params[4], i;
+
+ if (argc < 5) {
+ fprintf(stderr, "Error: requires four arguments '%s'\n", arg_id);
+ exit(1);
+ }
+
+ for (i = 0; i < 4; i++) {
+ const char *err_msg = NULL;
+ if (!parse_int(argv[i + 1], NULL, &params[i], &err_msg)) {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ exit(1);
+ }
+ }
+
+ WM_init_state_size_set(UNPACK4(params));
+
+ return 4;
+}
+
+static const char arg_handle_native_pixels_set_doc[] =
+"\n\tDo not use native pixel size, for high resolution displays (MacBook 'Retina')"
+;
+static int arg_handle_native_pixels_set(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ WM_init_native_pixels(false);
+ return 0;
+}
+
+static const char arg_handle_with_borders_doc[] =
+"\n\tForce opening without borders"
+;
+static int arg_handle_with_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ WM_init_state_normal_set();
+ return 0;
+}
+
+static const char arg_handle_without_borders_doc[] =
+"\n\tForce opening without borders"
+;
+static int arg_handle_without_borders(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ WM_init_state_fullscreen_set();
+ return 0;
+}
+
+extern bool wm_start_with_console; /* wm_init_exit.c */
+
+static const char arg_handle_start_with_console_doc[] =
+"\n\tStart with the console window open (ignored if -b is set), (Windows only)"
+;
+static int arg_handle_start_with_console(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ wm_start_with_console = true;
+ return 0;
+}
+
+static const char arg_handle_register_extension_doc[] =
+"\n\tRegister .blend extension, then exit (Windows only)"
+;
+static const char arg_handle_register_extension_doc_silent[] =
+"\n\tSilently register .blend extension, then exit (Windows only)"
+;
+static int arg_handle_register_extension(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+#ifdef WIN32
+ if (data)
+ G.background = 1;
+ RegisterBlendExtension();
+#else
+ (void)data; /* unused */
+#endif
+ return 0;
+}
+
+static const char arg_handle_joystick_disable_doc[] =
+"\n\tDisable joystick support"
+;
+static int arg_handle_joystick_disable(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+#ifndef WITH_GAMEENGINE
+ (void)data;
+#else
+ SYS_SystemHandle *syshandle = data;
+
+ /**
+ * don't initialize joysticks if user doesn't want to use joysticks
+ * failed joystick initialization delays over 5 seconds, before game engine start
+ */
+ SYS_WriteCommandLineInt(*syshandle, "nojoystick", 1);
+ if (G.debug & G_DEBUG) printf("disabling nojoystick\n");
+#endif
+
+ return 0;
+}
+
+static const char arg_handle_glsl_disable_doc[] =
+"\n\tDisable GLSL shading"
+;
+static int arg_handle_glsl_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ GPU_extensions_disable();
+ return 0;
+}
+
+static const char arg_handle_audio_disable_doc[] =
+"\n\tForce sound system to None"
+;
+static int arg_handle_audio_disable(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ BKE_sound_force_device("Null");
+ return 0;
+}
+
+static const char arg_handle_audio_set_doc[] =
+"\n\tForce sound system to a specific device\n\tNULL SDL OPENAL JACK"
+;
+static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
+{
+ if (argc < 1) {
+ fprintf(stderr, "-setaudio require one argument\n");
+ exit(1);
+ }
+
+ BKE_sound_force_device(argv[1]);
+ return 1;
+}
+
+static const char arg_handle_output_set_doc[] =
+"<path>\n"
+"\tSet the render path and file name.\n"
+"\tUse '//' at the start of the path to render relative to the blend-file.\n"
+"\n"
+"\tThe '#' characters are replaced by the frame number, and used to define zero padding.\n"
+"\n"
+"\t* 'ani_##_test.png' becomes 'ani_01_test.png'\n"
+"\t* 'test-######.png' becomes 'test-000001.png'\n"
+"\n"
+"\tWhen the filename does not contain '#', The suffix '####' is added to the filename.\n"
+"\n"
+"\tThe frame number will be added at the end of the filename, eg:\n"
+"\t# blender -b foobar.blend -o //render_ -F PNG -x 1 -a\n"
+"\t'//render_' becomes '//render_####', writing frames as '//render_0001.png'"
+;
+static int arg_handle_output_set(int argc, const char **argv, void *data)
+{
+ bContext *C = data;
+ if (argc > 1) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ BLI_strncpy(scene->r.pic, argv[1], sizeof(scene->r.pic));
+ }
+ else {
+ printf("\nError: no blend loaded. cannot use '-o / --render-output'.\n");
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a path after '-o / --render-output'.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_engine_set_doc[] =
+"<engine>\n"
+"\tSpecify the render engine\n\tuse -E help to list available engines"
+;
+static int arg_handle_engine_set(int argc, const char **argv, void *data)
+{
+ bContext *C = data;
+ if (argc >= 2) {
+ if (STREQ(argv[1], "help")) {
+ RenderEngineType *type = NULL;
+ printf("Blender Engine Listing:\n");
+ for (type = R_engines.first; type; type = type->next) {
+ printf("\t%s\n", type->idname);
+ }
+ exit(0);
+ }
+ else {
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ RenderData *rd = &scene->r;
+
+ if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
+ BLI_strncpy_utf8(rd->engine, argv[1], sizeof(rd->engine));
+ }
+ else {
+ printf("\nError: engine not found '%s'\n", argv[1]);
+ exit(1);
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. "
+ "order the arguments so '-E / --engine ' is after a blend is loaded.\n");
+ }
+ }
+
+ return 1;
+ }
+ else {
+ printf("\nEngine not specified, give 'help' for a list of available engines.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_image_type_set_doc[] =
+"<format>\n"
+"\tSet the render format, Valid options are...\n"
+"\t\tTGA RAWTGA JPEG IRIS IRIZ\n"
+"\t\tAVIRAW AVIJPEG PNG BMP\n"
+"\t(formats that can be compiled into blender, not available on all systems)\n"
+"\t\tHDR TIFF EXR MULTILAYER MPEG FRAMESERVER QUICKTIME CINEON DPX DDS JP2"
+;
+static int arg_handle_image_type_set(int argc, const char **argv, void *data)
+{
+ bContext *C = data;
+ if (argc > 1) {
+ const char *imtype = argv[1];
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ const char imtype_new = BKE_imtype_from_arg(imtype);
+
+ if (imtype_new == R_IMF_IMTYPE_INVALID) {
+ printf("\nError: Format from '-F / --render-format' not known or not compiled in this release.\n");
+ }
+ else {
+ scene->r.im_format.imtype = imtype_new;
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. "
+ "order the arguments so '-F / --render-format' is after the blend is loaded.\n");
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a format after '-F / --render-foramt'.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_threads_set_doc[] =
+"<threads>\n"
+"\tUse amount of <threads> for rendering and other operations\n"
+"\t[1-" STRINGIFY(BLENDER_MAX_THREADS) "], 0 for systems processor count."
+;
+static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "-t / --threads";
+ const int min = 0, max = BLENDER_MAX_THREADS;
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ int threads;
+ if (!parse_int_strict_range(argv[1], NULL, min, max, &threads, &err_msg)) {
+ printf("\nError: %s '%s %s', expected number in [%d..%d].\n", err_msg, arg_id, argv[1], min, max);
+ return 1;
+ }
+
+ BLI_system_num_threads_override_set(threads);
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a number of threads in [%d..%d] '%s'.\n", min, max, arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_depsgraph_use_new_doc[] =
+"\n\tUse new dependency graph"
+;
+static int arg_handle_depsgraph_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ printf("Using new dependency graph.\n");
+ DEG_depsgraph_switch_to_new();
+ return 0;
+}
+
+static const char arg_handle_verbosity_set_doc[] =
+"<verbose>\n"
+"\tSet logging verbosity level."
+;
+static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "--verbose";
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ int level;
+ if (!parse_int(argv[1], NULL, &level, &err_msg)) {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ }
+
+#ifdef WITH_LIBMV
+ libmv_setLoggingVerbosity(level);
+#elif defined(WITH_CYCLES_LOGGING)
+ CCL_logging_verbosity_set(level);
+#else
+ (void)level;
+#endif
+
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a verbosity level.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_extension_set_doc[] =
+"<bool>\n"
+"\tSet option to add the file extension to the end of the file"
+;
+static int arg_handle_extension_set(int argc, const char **argv, void *data)
+{
+ bContext *C = data;
+ if (argc > 1) {
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ if (argv[1][0] == '0') {
+ scene->r.scemode &= ~R_EXTENSION;
+ }
+ else if (argv[1][0] == '1') {
+ scene->r.scemode |= R_EXTENSION;
+ }
+ else {
+ printf("\nError: Use '-x 1 / -x 0' To set the extension option or '--use-extension'\n");
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. "
+ "order the arguments so '-o ' is after '-x '.\n");
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a path after '- '.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_ge_parameters_set_doc[] =
+"Game Engine specific options\n"
+"\t-g fixedtime\t\tRun on 50 hertz without dropping frames\n"
+"\t-g vertexarrays\t\tUse Vertex Arrays for rendering (usually faster)\n"
+"\t-g nomipmap\t\tNo Texture Mipmapping\n"
+"\t-g linearmipmap\t\tLinear Texture Mipmapping instead of Nearest (default)"
+;
+static int arg_handle_ge_parameters_set(int argc, const char **argv, void *data)
+{
+ int a = 0;
+#ifdef WITH_GAMEENGINE
+ SYS_SystemHandle syshandle = *(SYS_SystemHandle *)data;
+#else
+ (void)data;
+#endif
+
+ /**
+ * gameengine parameters are automatically put into system
+ * -g [paramname = value]
+ * -g [boolparamname]
+ * example:
+ * -g novertexarrays
+ * -g maxvertexarraysize = 512
+ */
+
+ if (argc >= 1) {
+ const char *paramname = argv[a];
+ /* check for single value versus assignment */
+ if (a + 1 < argc && (*(argv[a + 1]) == '=')) {
+ a++;
+ if (a + 1 < argc) {
+ a++;
+ /* assignment */
+#ifdef WITH_GAMEENGINE
+ SYS_WriteCommandLineString(syshandle, paramname, argv[a]);
+#endif
+ }
+ else {
+ printf("error: argument assignment (%s) without value.\n", paramname);
+ return 0;
+ }
+ /* name arg eaten */
+
+ }
+ else {
+#ifdef WITH_GAMEENGINE
+ SYS_WriteCommandLineInt(syshandle, argv[a], 1);
+#endif
+ /* doMipMap */
+ if (STREQ(argv[a], "nomipmap")) {
+ GPU_set_mipmap(0); //doMipMap = 0;
+ }
+ /* linearMipMap */
+ if (STREQ(argv[a], "linearmipmap")) {
+ GPU_set_mipmap(1);
+ GPU_set_linear_mipmap(1); //linearMipMap = 1;
+ }
+
+
+ } /* if (*(argv[a + 1]) == '=') */
+ }
+
+ return a;
+}
+
+static const char arg_handle_render_frame_doc[] =
+"<frame>\n"
+"\tRender frame <frame> and save it.\n"
+"\n"
+"\t* +<frame> start frame relative, -<frame> end frame relative.\n"
+"\t* A comma separated list of frames can also be used (no spaces).\n"
+"\t* A range of frames can be expressed using '..' seperator between the first and last frames (inclusive).\n"
+;
+static int arg_handle_render_frame(int argc, const char **argv, void *data)
+{
+ const char *arg_id = "-f / --render-frame";
+ bContext *C = data;
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ Main *bmain = CTX_data_main(C);
+
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ Render *re;
+ ReportList reports;
+
+ int (*frame_range_arr)[2], frames_range_len;
+ if ((frame_range_arr = parse_int_range_relative_clamp_n(
+ argv[1], scene->r.sfra, scene->r.efra, MINAFRAME, MAXFRAME,
+ &frames_range_len, &err_msg)) == NULL)
+ {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ return 1;
+ }
+
+ re = RE_NewRender(scene->id.name);
+ BLI_begin_threaded_malloc();
+ BKE_reports_init(&reports, RPT_PRINT);
+
+ RE_SetReports(re, &reports);
+ for (int i = 0; i < frames_range_len; i++) {
+ /* We could pass in frame ranges,
+ * but prefer having exact behavior as passing in multiple frames */
+ if ((frame_range_arr[i][0] <= frame_range_arr[i][1]) == 0) {
+ printf("\nWarning: negative range ignored '%s %s'.\n", arg_id, argv[1]);
+ }
+
+ for (int frame = frame_range_arr[i][0]; frame <= frame_range_arr[i][1]; frame++) {
+ RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
+ }
+ }
+ RE_SetReports(re, NULL);
+ BLI_end_threaded_malloc();
+ MEM_freeN(frame_range_arr);
+ return 1;
+ }
+ else {
+ printf("\nError: frame number must follow '%s'.\n", arg_id);
+ return 0;
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_render_animation_doc[] =
+"\n\tRender frames from start to end (inclusive)"
+;
+static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(argv), void *data)
+{
+ bContext *C = data;
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ Main *bmain = CTX_data_main(C);
+ Render *re = RE_NewRender(scene->id.name);
+ ReportList reports;
+ BLI_begin_threaded_malloc();
+ BKE_reports_init(&reports, RPT_PRINT);
+ RE_SetReports(re, &reports);
+ RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
+ RE_SetReports(re, NULL);
+ BLI_end_threaded_malloc();
+ }
+ else {
+ printf("\nError: no blend loaded. cannot use '-a'.\n");
+ }
+ return 0;
+}
+
+static const char arg_handle_scene_set_doc[] =
+"<name>\n"
+"\tSet the active scene <name> for rendering"
+;
+static int arg_handle_scene_set(int argc, const char **argv, void *data)
+{
+ if (argc > 1) {
+ bContext *C = data;
+ Scene *scene = BKE_scene_set_name(CTX_data_main(C), argv[1]);
+ if (scene) {
+ CTX_data_scene_set(C, scene);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: Scene name must follow '-S / --scene'.\n");
+ return 0;
+ }
+}
+
+static const char arg_handle_frame_start_set_doc[] =
+"<frame>\n"
+"\tSet start to frame <frame>, supports +/- for relative frames too."
+;
+static int arg_handle_frame_start_set(int argc, const char **argv, void *data)
+{
+ const char *arg_id = "-s / --frame-start";
+ bContext *C = data;
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ if (!parse_int_relative_clamp(
+ argv[1], NULL, scene->r.sfra, scene->r.sfra - 1, MINAFRAME, MAXFRAME,
+ &scene->r.sfra, &err_msg))
+ {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: frame number must follow '%s'.\n", arg_id);
+ return 0;
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_frame_end_set_doc[] =
+"<frame>\n"
+"\tSet end to frame <frame>, supports +/- for relative frames too."
+;
+static int arg_handle_frame_end_set(int argc, const char **argv, void *data)
+{
+ const char *arg_id = "-e / --frame-end";
+ bContext *C = data;
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ if (!parse_int_relative_clamp(
+ argv[1], NULL, scene->r.efra, scene->r.efra - 1, MINAFRAME, MAXFRAME,
+ &scene->r.efra, &err_msg))
+ {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: frame number must follow '%s'.\n", arg_id);
+ return 0;
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_frame_skip_set_doc[] =
+"<frames>\n"
+"\tSet number of frames to step forward after each rendered frame"
+;
+static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
+{
+ const char *arg_id = "-j / --frame-jump";
+ bContext *C = data;
+ Scene *scene = CTX_data_scene(C);
+ if (scene) {
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ if (!parse_int_clamp(argv[1], NULL, 1, MAXFRAME, &scene->r.frame_step, &err_msg)) {
+ printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: number of frames to step must follow '%s'.\n", arg_id);
+ return 0;
+ }
+ }
+ else {
+ printf("\nError: no blend loaded. cannot use '%s'.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_python_file_run_doc[] =
+"<filename>\n"
+"\tRun the given Python script file"
+;
+static int arg_handle_python_file_run(int argc, const char **argv, void *data)
+{
+#ifdef WITH_PYTHON
+ bContext *C = data;
+
+ /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
+ if (argc > 1) {
+ /* Make the path absolute because its needed for relative linked blends to be found */
+ char filename[FILE_MAX];
+ BLI_strncpy(filename, argv[1], sizeof(filename));
+ BLI_path_cwd(filename, sizeof(filename));
+
+ bool ok;
+ BPY_CTX_SETUP(ok = BPY_execute_filepath(C, filename, NULL));
+ if (!ok && app_state.exit_code_on_error.python) {
+ printf("\nError: script failed, file: '%s', exiting.\n", argv[1]);
+ exit(app_state.exit_code_on_error.python);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a filepath after '%s'.\n", argv[0]);
+ return 0;
+ }
+#else
+ UNUSED_VARS(argc, argv, data);
+ printf("This blender was built without python support\n");
+ return 0;
+#endif /* WITH_PYTHON */
+}
+
+static const char arg_handle_python_text_run_doc[] =
+"<name>\n"
+"\tRun the given Python script text block"
+;
+static int arg_handle_python_text_run(int argc, const char **argv, void *data)
+{
+#ifdef WITH_PYTHON
+ bContext *C = data;
+
+ /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
+ if (argc > 1) {
+ /* Make the path absolute because its needed for relative linked blends to be found */
+ struct Text *text = (struct Text *)BKE_libblock_find_name(ID_TXT, argv[1]);
+ bool ok;
+
+ if (text) {
+ BPY_CTX_SETUP(ok = BPY_execute_text(C, text, NULL, false));
+ }
+ else {
+ printf("\nError: text block not found %s.\n", argv[1]);
+ ok = false;
+ }
+
+ if (!ok && app_state.exit_code_on_error.python) {
+ printf("\nError: script failed, text: '%s', exiting.\n", argv[1]);
+ exit(app_state.exit_code_on_error.python);
+ }
+
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a text block after '%s'.\n", argv[0]);
+ return 0;
+ }
+#else
+ UNUSED_VARS(argc, argv, data);
+ printf("This blender was built without python support\n");
+ return 0;
+#endif /* WITH_PYTHON */
+}
+
+static const char arg_handle_python_expr_run_doc[] =
+"<expression>\n"
+"\tRun the given expression as a Python script"
+;
+static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
+{
+#ifdef WITH_PYTHON
+ bContext *C = data;
+
+ /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
+ if (argc > 1) {
+ bool ok;
+ BPY_CTX_SETUP(ok = BPY_execute_string_ex(C, argv[1], false));
+ if (!ok && app_state.exit_code_on_error.python) {
+ printf("\nError: script failed, expr: '%s', exiting.\n", argv[1]);
+ exit(app_state.exit_code_on_error.python);
+ }
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a Python expression after '%s'.\n", argv[0]);
+ return 0;
+ }
+#else
+ UNUSED_VARS(argc, argv, data);
+ printf("This blender was built without python support\n");
+ return 0;
+#endif /* WITH_PYTHON */
+}
+
+static const char arg_handle_python_console_run_doc[] =
+"\n\tRun blender with an interactive console"
+;
+static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, void *data)
+{
+#ifdef WITH_PYTHON
+ bContext *C = data;
+
+ BPY_CTX_SETUP(BPY_execute_string(C, "__import__('code').interact()"));
+
+ return 0;
+#else
+ UNUSED_VARS(argv, data);
+ printf("This blender was built without python support\n");
+ return 0;
+#endif /* WITH_PYTHON */
+}
+
+static const char arg_handle_python_exit_code_set_doc[] =
+"\n"
+"\tSet the exit-code in [0..255] to exit if a Python exception is raised\n"
+"\t(only for scripts executed from the command line), zero disables."
+;
+static int arg_handle_python_exit_code_set(int argc, const char **argv, void *UNUSED(data))
+{
+ const char *arg_id = "--python-exit-code";
+ if (argc > 1) {
+ const char *err_msg = NULL;
+ const int min = 0, max = 255;
+ int exit_code;
+ if (!parse_int_strict_range(argv[1], NULL, min, max, &exit_code, &err_msg)) {
+ printf("\nError: %s '%s %s', expected number in [%d..%d].\n", err_msg, arg_id, argv[1], min, max);
+ return 1;
+ }
+
+ app_state.exit_code_on_error.python = (unsigned char)exit_code;
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify an exit code number '%s'.\n", arg_id);
+ return 0;
+ }
+}
+
+static const char arg_handle_addons_set_doc[] =
+"\n\tComma separated list of add-ons (no spaces)"
+;
+static int arg_handle_addons_set(int argc, const char **argv, void *data)
+{
+ /* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
+ if (argc > 1) {
+#ifdef WITH_PYTHON
+ const char script_str[] =
+ "from addon_utils import check, enable\n"
+ "for m in '%s'.split(','):\n"
+ " if check(m)[1] is False:\n"
+ " enable(m, persistent=True)";
+ const int slen = strlen(argv[1]) + (sizeof(script_str) - 2);
+ char *str = malloc(slen);
+ bContext *C = data;
+ BLI_snprintf(str, slen, script_str, argv[1]);
+
+ BLI_assert(strlen(str) + 1 == slen);
+ BPY_CTX_SETUP(BPY_execute_string_ex(C, str, false));
+ free(str);
+#else
+ UNUSED_VARS(argv, data);
+#endif /* WITH_PYTHON */
+ return 1;
+ }
+ else {
+ printf("\nError: you must specify a comma separated list after '--addons'.\n");
+ return 0;
+ }
+}
+
+static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
+{
+ bContext *C = data;
+ ReportList reports;
+ bool success;
+
+ /* Make the path absolute because its needed for relative linked blends to be found */
+ char filename[FILE_MAX];
+
+ /* note, we could skip these, but so far we always tried to load these files */
+ if (argv[0][0] == '-') {
+ fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]);
+ }
+
+ BLI_strncpy(filename, argv[0], sizeof(filename));
+ BLI_path_cwd(filename, sizeof(filename));
+
+ /* load the file */
+ BKE_reports_init(&reports, RPT_PRINT);
+ WM_file_autoexec_init(filename);
+ success = WM_file_read(C, filename, &reports);
+ BKE_reports_clear(&reports);
+
+ if (success) {
+ if (G.background) {
+ /* ensuer we use 'C->data.scene' for background render */
+ CTX_wm_window_set(C, NULL);
+ }
+ }
+ else {
+ /* failed to load file, stop processing arguments if running in background mode */
+ if (G.background) {
+ /* Set is_break if running in the background mode so
+ * blender will return non-zero exit code which then
+ * could be used in automated script to control how
+ * good or bad things are.
+ */
+ G.is_break = true;
+ return -1;
+ }
+
+ /* Just pretend a file was loaded, so the user can press Save and it'll save at the filename from the CLI. */
+ BLI_strncpy(G.main->name, filename, FILE_MAX);
+ G.relbase_valid = true;
+ G.save_over = true;
+ printf("... opened default scene instead; saving will write to %s\n", filename);
+ }
+
+ G.file_loaded = 1;
+
+ return 0;
+}
+
+
+void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
+{
+
+#define CB(a) a##_doc, a
+#define CB_EX(a, b) a##_doc_##b, a
+
+ //BLI_argsAdd(ba, pass, short_arg, long_arg, doc, cb, C);
+
+ /* end argument processing after -- */
+ BLI_argsAdd(ba, -1, "--", NULL, CB(arg_handle_arguments_end), NULL);
+
+ /* first pass: background mode, disable python and commands that exit after usage */
+ BLI_argsAdd(ba, 1, "-h", "--help", CB(arg_handle_print_help), ba);
+ /* Windows only */
+ BLI_argsAdd(ba, 1, "/?", NULL, CB_EX(arg_handle_print_help, win32), ba);
+
+ BLI_argsAdd(ba, 1, "-v", "--version", CB(arg_handle_print_version), NULL);
+
+ BLI_argsAdd(ba, 1, "-y", "--enable-autoexec", CB_EX(arg_handle_python_set, enable), (void *)true);
+ BLI_argsAdd(ba, 1, "-Y", "--disable-autoexec", CB_EX(arg_handle_python_set, disable), (void *)false);
+
+ BLI_argsAdd(ba, 1, NULL, "--disable-crash-handler", CB(arg_handle_crash_handler_disable), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--disable-abort-handler", CB(arg_handle_abort_handler_disable), NULL);
+
+ BLI_argsAdd(ba, 1, "-b", "--background", CB(arg_handle_background_mode_set), NULL);
+
+ BLI_argsAdd(ba, 1, "-a", NULL, CB(arg_handle_playback_mode), NULL);
+
+ BLI_argsAdd(ba, 1, "-d", "--debug", CB(arg_handle_debug_mode_set), ba);
+
+#ifdef WITH_FFMPEG
+ BLI_argsAdd(ba, 1, NULL, "--debug-ffmpeg",
+ CB_EX(arg_handle_debug_mode_generic_set, ffmpeg), (void *)G_DEBUG_FFMPEG);
+#endif
+
+#ifdef WITH_FREESTYLE
+ BLI_argsAdd(ba, 1, NULL, "--debug-freestyle",
+ CB_EX(arg_handle_debug_mode_generic_set, freestyle), (void *)G_DEBUG_FREESTYLE);
+#endif
+
+ BLI_argsAdd(ba, 1, NULL, "--debug-python",
+ CB_EX(arg_handle_debug_mode_generic_set, python), (void *)G_DEBUG_PYTHON);
+ BLI_argsAdd(ba, 1, NULL, "--debug-events",
+ CB_EX(arg_handle_debug_mode_generic_set, events), (void *)G_DEBUG_EVENTS);
+ BLI_argsAdd(ba, 1, NULL, "--debug-handlers",
+ CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS);
+ BLI_argsAdd(ba, 1, NULL, "--debug-wm",
+ CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
+ BLI_argsAdd(ba, 1, NULL, "--debug-all",
+ CB_EX(arg_handle_debug_mode_generic_set, all), (void *)G_DEBUG_ALL);
+
+ BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
+ CB(arg_handle_debug_fpe_set), NULL);
+
+#ifdef WITH_LIBMV
+ BLI_argsAdd(ba, 1, NULL, "--debug-libmv", CB(arg_handle_debug_mode_libmv), NULL);
+#endif
+#ifdef WITH_CYCLES_LOGGING
+ BLI_argsAdd(ba, 1, NULL, "--debug-cycles", CB(arg_handle_debug_mode_cycles), NULL);
+#endif
+ BLI_argsAdd(ba, 1, NULL, "--debug-memory", CB(arg_handle_debug_mode_memory_set), NULL);
+
+ BLI_argsAdd(ba, 1, NULL, "--debug-value",
+ CB(arg_handle_debug_value_set), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--debug-jobs",
+ CB_EX(arg_handle_debug_mode_generic_set, jobs), (void *)G_DEBUG_JOBS);
+ BLI_argsAdd(ba, 1, NULL, "--debug-gpu",
+ CB_EX(arg_handle_debug_mode_generic_set, gpu), (void *)G_DEBUG_GPU);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph), (void *)G_DEBUG_DEPSGRAPH);
+ BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads",
+ CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads), (void *)G_DEBUG_DEPSGRAPH_NO_THREADS);
+ BLI_argsAdd(ba, 1, NULL, "--debug-gpumem",
+ CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM);
+
+ BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", CB(arg_handle_depsgraph_use_new), NULL);
+
+ BLI_argsAdd(ba, 1, NULL, "--verbose", CB(arg_handle_verbosity_set), NULL);
+
+ BLI_argsAdd(ba, 1, NULL, "--factory-startup", CB(arg_handle_factory_startup_set), NULL);
+
+ /* TODO, add user env vars? */
+ BLI_argsAdd(ba, 1, NULL, "--env-system-datafiles", CB_EX(arg_handle_env_system_set, datafiles), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--env-system-scripts", CB_EX(arg_handle_env_system_set, scripts), NULL);
+ BLI_argsAdd(ba, 1, NULL, "--env-system-python", CB_EX(arg_handle_env_system_set, python), NULL);
+
+ /* second pass: custom window stuff */
+ BLI_argsAdd(ba, 2, "-p", "--window-geometry", CB(arg_handle_window_geometry), NULL);
+ BLI_argsAdd(ba, 2, "-w", "--window-border", CB(arg_handle_with_borders), NULL);
+ BLI_argsAdd(ba, 2, "-W", "--window-borderless", CB(arg_handle_without_borders), NULL);
+ BLI_argsAdd(ba, 2, "-con", "--start-console", CB(arg_handle_start_with_console), NULL);
+ BLI_argsAdd(ba, 2, "-R", NULL, CB(arg_handle_register_extension), NULL);
+ BLI_argsAdd(ba, 2, "-r", NULL, CB_EX(arg_handle_register_extension, silent), ba);
+ BLI_argsAdd(ba, 2, NULL, "--no-native-pixels", CB(arg_handle_native_pixels_set), ba);
+
+ /* third pass: disabling things and forcing settings */
+ BLI_argsAddCase(ba, 3, "-nojoystick", 1, NULL, 0, CB(arg_handle_joystick_disable), syshandle);
+ BLI_argsAddCase(ba, 3, "-noglsl", 1, NULL, 0, CB(arg_handle_glsl_disable), NULL);
+ BLI_argsAddCase(ba, 3, "-noaudio", 1, NULL, 0, CB(arg_handle_audio_disable), NULL);
+ BLI_argsAddCase(ba, 3, "-setaudio", 1, NULL, 0, CB(arg_handle_audio_set), NULL);
+
+ /* fourth pass: processing arguments */
+ BLI_argsAdd(ba, 4, "-g", NULL, CB(arg_handle_ge_parameters_set), syshandle);
+ BLI_argsAdd(ba, 4, "-f", "--render-frame", CB(arg_handle_render_frame), C);
+ BLI_argsAdd(ba, 4, "-a", "--render-anim", CB(arg_handle_render_animation), C);
+ BLI_argsAdd(ba, 4, "-S", "--scene", CB(arg_handle_scene_set), C);
+ BLI_argsAdd(ba, 4, "-s", "--frame-start", CB(arg_handle_frame_start_set), C);
+ BLI_argsAdd(ba, 4, "-e", "--frame-end", CB(arg_handle_frame_end_set), C);
+ BLI_argsAdd(ba, 4, "-j", "--frame-jump", CB(arg_handle_frame_skip_set), C);
+ BLI_argsAdd(ba, 4, "-P", "--python", CB(arg_handle_python_file_run), C);
+ BLI_argsAdd(ba, 4, NULL, "--python-text", CB(arg_handle_python_text_run), C);
+ BLI_argsAdd(ba, 4, NULL, "--python-expr", CB(arg_handle_python_expr_run), C);
+ BLI_argsAdd(ba, 4, NULL, "--python-console", CB(arg_handle_python_console_run), C);
+ BLI_argsAdd(ba, 4, NULL, "--python-exit-code", CB(arg_handle_python_exit_code_set), NULL);
+ BLI_argsAdd(ba, 4, NULL, "--addons", CB(arg_handle_addons_set), C);
+
+ BLI_argsAdd(ba, 4, "-o", "--render-output", CB(arg_handle_output_set), C);
+ BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C);
+
+ BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C);
+ BLI_argsAdd(ba, 4, "-t", "--threads", CB(arg_handle_threads_set), NULL);
+ BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C);
+
+#undef CB
+#undef CB_EX
+
+}
+
+/**
+ * Needs to be added separately.
+ */
+void main_args_setup_post(bContext *C, bArgs *ba)
+{
+ BLI_argsParse(ba, 4, arg_handle_load_file, C);
+}
+
+/** \} */
+
+#endif /* WITH_PYTHON_MODULE */
diff --git a/source/creator/creator_intern.h b/source/creator/creator_intern.h
new file mode 100644
index 00000000000..a972a926677
--- /dev/null
+++ b/source/creator/creator_intern.h
@@ -0,0 +1,95 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __CREATOR_INTERN_H__
+#define __CREATOR_INTERN_H__
+
+/** \file creator/creator_intern.h
+ * \ingroup creator
+ *
+ * Functionality for main() initialization.
+ */
+
+struct bArgs;
+struct bContext;
+
+#ifndef WITH_PYTHON_MODULE
+
+/* creator_args.c */
+void main_args_setup(struct bContext *C, struct bArgs *ba, SYS_SystemHandle *syshandle);
+void main_args_setup_post(struct bContext *C, struct bArgs *ba);
+
+
+/* creator_signals.c */
+void main_signal_setup(void);
+void main_signal_setup_background(void);
+void main_signal_setup_fpe(void);
+
+#endif /* WITH_PYTHON_MODULE */
+
+
+/* Shared data for argument handlers to store state in */
+struct ApplicationState {
+ struct {
+ bool use_crash_handler;
+ bool use_abort_handler;
+ } signal;
+
+ /* we may want to set different exit codes for other kinds of errors */
+ struct {
+ unsigned char python;
+ } exit_code_on_error;
+
+};
+extern struct ApplicationState app_state; /* creator.c */
+
+/* for the callbacks: */
+#ifndef WITH_PYTHON_MODULE
+#define BLEND_VERSION_FMT "Blender %d.%02d (sub %d)"
+#define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION
+/* pass directly to printf */
+#define BLEND_VERSION_STRING_FMT BLEND_VERSION_FMT "\n", BLEND_VERSION_ARG
+#endif
+
+#ifdef WITH_BUILDINFO_HEADER
+# define BUILD_DATE
+#endif
+
+/* from buildinfo.c */
+#ifdef BUILD_DATE
+ extern char build_date[];
+extern char build_time[];
+extern char build_hash[];
+extern unsigned long build_commit_timestamp;
+
+/* TODO(sergey): ideally size need to be in sync with buildinfo.c */
+extern char build_commit_date[16];
+extern char build_commit_time[16];
+
+extern char build_branch[];
+extern char build_platform[];
+extern char build_type[];
+extern char build_cflags[];
+extern char build_cxxflags[];
+extern char build_linkflags[];
+extern char build_system[];
+#endif
+
+#endif /* __CREATOR_INTERN_H__ */
diff --git a/source/creator/creator_launch_win.c b/source/creator/creator_launch_win.c
deleted file mode 100644
index 03f28cd4034..00000000000
--- a/source/creator/creator_launch_win.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2014 by Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Sergey Sharybin.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/* Binary name to launch. */
-#define BLENDER_BINARY L"blender-app.exe"
-
-#define WIN32_LEAN_AND_MEAN
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <windows.h>
-#include <Shellapi.h>
-
-#include "utfconv.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_winstuff.h"
-
-static void local_hacks_do(void)
-{
- _putenv_s("OMP_WAIT_POLICY", "PASSIVE");
-}
-
-int main(int argc, const char **UNUSED(argv_c))
-{
- PROCESS_INFORMATION processInformation = {0};
- STARTUPINFOW startupInfo = {0};
- BOOL result;
- wchar_t command[65536];
- int i, len = sizeof(command) / sizeof(wchar_t);
- wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
- int argci = 0;
-
- local_hacks_do();
-
- wcsncpy(command, BLENDER_BINARY, len - 1);
- len -= wcslen(BLENDER_BINARY);
- for (i = 1; i < argc; ++i) {
- size_t argument_len = wcslen(argv_16[i]);
- wcsncat(command, L" \"", len - 2);
- wcsncat(command, argv_16[i], len - 3);
- len -= argument_len + 1;
- if (argv_16[i][argument_len - 1] == '\\') {
- wcsncat(command, L"\\", len - 1);
- len--;
- }
- wcsncat(command, L"\"", len - 1);
- }
-
- LocalFree(argv_16);
-
- startupInfo.cb = sizeof(startupInfo);
- result = CreateProcessW(NULL, command, NULL, NULL, TRUE,
- 0, NULL, NULL,
- &startupInfo, &processInformation);
-
- if (!result) {
- fprintf(stderr, "%S\n", L"Error launching " BLENDER_BINARY);
- return EXIT_FAILURE;
- }
-
- WaitForSingleObject(processInformation.hProcess, INFINITE);
-
- CloseHandle(processInformation.hProcess);
- CloseHandle(processInformation.hThread);
-
- return EXIT_SUCCESS;
-}
diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c
new file mode 100644
index 00000000000..b25d7c56f6e
--- /dev/null
+++ b/source/creator/creator_signals.c
@@ -0,0 +1,328 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file creator/creator_signals.c
+ * \ingroup creator
+ */
+
+#ifndef WITH_PYTHON_MODULE
+
+#if defined(__linux__) && defined(__GNUC__)
+# define _GNU_SOURCE
+# include <fenv.h>
+#endif
+
+#if (defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
+# define OSX_SSE_FPE
+# include <xmmintrin.h>
+#endif
+
+#ifdef WIN32
+# if defined(_MSC_VER) && defined(_M_X64)
+# include <math.h> /* needed for _set_FMA3_enable */
+# endif
+# include <windows.h>
+# include <float.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "BLI_sys_types.h"
+
+#ifdef WIN32
+# include "BLI_winstuff.h"
+#endif
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_path_util.h"
+#include "BLI_fileops.h"
+#include "BLI_system.h"
+#include BLI_SYSTEM_PID_H
+
+#include "BKE_appdir.h" /* BKE_tempdir_base */
+#include "BKE_blender.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+/* for passing information between creator and gameengine */
+#ifdef WITH_GAMEENGINE
+# include "BL_System.h"
+#else /* dummy */
+# define SYS_SystemHandle int
+#endif
+
+#include <signal.h>
+
+#include "creator_intern.h" /* own include */
+
+/* set breakpoints here when running in debug mode, useful to catch floating point errors */
+#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
+static void sig_handle_fpe(int UNUSED(sig))
+{
+ fprintf(stderr, "debug: SIGFPE trapped\n");
+}
+#endif
+
+/* handling ctrl-c event in console */
+#if !defined(WITH_HEADLESS)
+static void sig_handle_blender_esc(int sig)
+{
+ static int count = 0;
+
+ G.is_break = true; /* forces render loop to read queue, not sure if its needed */
+
+ if (sig == 2) {
+ if (count) {
+ printf("\nBlender killed\n");
+ exit(2);
+ }
+ printf("\nSent an internal break event. Press ^C again to kill Blender\n");
+ count++;
+ }
+}
+#endif
+
+static void sig_handle_crash_backtrace(FILE *fp)
+{
+ fputs("\n# backtrace\n", fp);
+ BLI_system_backtrace(fp);
+}
+
+static void sig_handle_crash(int signum)
+{
+
+#if 0
+ {
+ char fname[FILE_MAX];
+
+ if (!G.main->name[0]) {
+ BLI_make_file_string("/", fname, BKE_tempdir_base(), "crash.blend");
+ }
+ else {
+ BLI_strncpy(fname, G.main->name, sizeof(fname));
+ BLI_replace_extension(fname, sizeof(fname), ".crash.blend");
+ }
+
+ printf("Writing: %s\n", fname);
+ fflush(stdout);
+
+ BKE_undo_save_file(fname);
+ }
+#endif
+
+ FILE *fp;
+ char header[512];
+ wmWindowManager *wm = G.main->wm.first;
+
+ char fname[FILE_MAX];
+
+ if (!G.main->name[0]) {
+ BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt");
+ }
+ else {
+ BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G.main->name));
+ BLI_replace_extension(fname, sizeof(fname), ".crash.txt");
+ }
+
+ printf("Writing: %s\n", fname);
+ fflush(stdout);
+
+#ifndef BUILD_DATE
+ BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG);
+#else
+ BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n",
+ BLEND_VERSION_ARG, build_commit_date, build_commit_time, build_hash);
+#endif
+
+ /* open the crash log */
+ errno = 0;
+ fp = BLI_fopen(fname, "wb");
+ if (fp == NULL) {
+ fprintf(stderr, "Unable to save '%s': %s\n",
+ fname, errno ? strerror(errno) : "Unknown error opening file");
+ }
+ else {
+ if (wm) {
+ BKE_report_write_file_fp(fp, &wm->reports, header);
+ }
+
+ sig_handle_crash_backtrace(fp);
+
+ fclose(fp);
+ }
+
+ /* Delete content of temp dir! */
+ BKE_tempdir_session_purge();
+
+ /* really crash */
+ signal(signum, SIG_DFL);
+#ifndef WIN32
+ kill(getpid(), signum);
+#else
+ TerminateProcess(GetCurrentProcess(), signum);
+#endif
+}
+
+#ifdef WIN32
+LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS *ExceptionInfo)
+{
+ switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
+ break;
+ case EXCEPTION_BREAKPOINT:
+ fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
+ break;
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
+ break;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
+ break;
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
+ break;
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
+ break;
+ case EXCEPTION_FLT_OVERFLOW:
+ fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
+ break;
+ case EXCEPTION_FLT_STACK_CHECK:
+ fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
+ break;
+ case EXCEPTION_FLT_UNDERFLOW:
+ fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
+ break;
+ case EXCEPTION_IN_PAGE_ERROR:
+ fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
+ break;
+ case EXCEPTION_INT_OVERFLOW:
+ fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
+ break;
+ case EXCEPTION_INVALID_DISPOSITION:
+ fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
+ break;
+ default:
+ fputs("Error: Unrecognized Exception\n", stderr);
+ break;
+ }
+
+ fflush(stderr);
+
+ /* If this is a stack overflow then we can't walk the stack, so just show
+ * where the error happened */
+ if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
+#ifdef NDEBUG
+ TerminateProcess(GetCurrentProcess(), SIGSEGV);
+#else
+ sig_handle_crash(SIGSEGV);
+#endif
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+#endif
+
+static void sig_handle_abort(int UNUSED(signum))
+{
+ /* Delete content of temp dir! */
+ BKE_tempdir_session_purge();
+}
+
+
+void main_signal_setup(void)
+{
+ if (app_state.signal.use_crash_handler) {
+#ifdef WIN32
+ SetUnhandledExceptionFilter(windows_exception_handler);
+#else
+ /* after parsing args */
+ signal(SIGSEGV, sig_handle_crash);
+#endif
+ }
+
+ if (app_state.signal.use_abort_handler) {
+ signal(SIGABRT, sig_handle_abort);
+ }
+}
+
+void main_signal_setup_background(void)
+{
+ /* for all platforms, even windos has it! */
+ BLI_assert(G.background);
+
+#if !defined(WITH_HEADLESS)
+ signal(SIGINT, sig_handle_blender_esc); /* ctrl c out bg render */
+#endif
+}
+
+
+void main_signal_setup_fpe(void)
+{
+#if defined(__linux__) || defined(_WIN32) || defined(OSX_SSE_FPE)
+ /* zealous but makes float issues a heck of a lot easier to find!
+ * set breakpoints on sig_handle_fpe */
+ signal(SIGFPE, sig_handle_fpe);
+
+# if defined(__linux__) && defined(__GNUC__)
+ feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
+# endif /* defined(__linux__) && defined(__GNUC__) */
+# if defined(OSX_SSE_FPE)
+ /* OSX uses SSE for floating point by default, so here
+ * use SSE instructions to throw floating point exceptions */
+ _MM_SET_EXCEPTION_MASK(_MM_MASK_MASK & ~
+ (_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
+# endif /* OSX_SSE_FPE */
+# if defined(_WIN32) && defined(_MSC_VER)
+ _controlfp_s(NULL, 0, _MCW_EM); /* enables all fp exceptions */
+ _controlfp_s(NULL, _EM_DENORMAL | _EM_UNDERFLOW | _EM_INEXACT, _MCW_EM); /* hide the ones we don't care about */
+# endif /* _WIN32 && _MSC_VER */
+#endif
+}
+
+#endif /* WITH_PYTHON_MODULE */ \ No newline at end of file
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index 91382669d5c..c5fc55a8e68 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -54,7 +54,6 @@
#include "KX_PyConstraintBinding.h"
#include "KX_PythonMain.h"
-#include "RAS_GLExtensionManager.h"
#include "RAS_OpenGLRasterizer.h"
#include "RAS_ListRasterizer.h"
@@ -250,12 +249,6 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */
#endif
-
- bgl::InitExtensions(true);
-
- // VBO code for derived mesh is not compatible with BGE (couldn't find why), so disable
- int disableVBO = (U.gameflags & USER_DISABLE_VBO);
- U.gameflags |= USER_DISABLE_VBO;
// Globals to be carried on over blender files
GlobalSettings gs;
@@ -306,12 +299,20 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
canvas->SetSwapInterval((startscene->gm.vsync == VSYNC_ON) ? 1 : 0);
RAS_IRasterizer* rasterizer = NULL;
+ RAS_STORAGE_TYPE raster_storage = RAS_AUTO_STORAGE;
+
+ if (startscene->gm.raster_storage == RAS_STORE_VBO) {
+ raster_storage = RAS_VBO;
+ }
+ else if (startscene->gm.raster_storage == RAS_STORE_VA) {
+ raster_storage = RAS_VA;
+ }
//Don't use displaylists with VBOs
//If auto starts using VBOs, make sure to check for that here
- if (displaylists && startscene->gm.raster_storage != RAS_STORE_VBO)
- rasterizer = new RAS_ListRasterizer(canvas, true, startscene->gm.raster_storage);
+ if (displaylists && raster_storage != RAS_VBO)
+ rasterizer = new RAS_ListRasterizer(canvas, true, raster_storage);
else
- rasterizer = new RAS_OpenGLRasterizer(canvas, startscene->gm.raster_storage);
+ rasterizer = new RAS_OpenGLRasterizer(canvas, raster_storage);
RAS_IRasterizer::MipmapOption mipmapval = rasterizer->GetMipmapping();
@@ -359,25 +360,22 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
}
// some blender stuff
- float camzoom;
+ float camzoom = 1.0f;
int draw_letterbox = 0;
-
+
if (rv3d->persp==RV3D_CAMOB) {
if (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) { /* Letterbox */
- camzoom = 1.0f;
draw_letterbox = 1;
}
else {
camzoom = 1.0f / BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
}
}
- else {
- camzoom = 2.0;
- }
rasterizer->SetDrawingMode(drawtype);
ketsjiengine->SetCameraZoom(camzoom);
-
+ ketsjiengine->SetCameraOverrideZoom(2.0f);
+
// if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME)
{
@@ -679,14 +677,12 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
} while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
- if (!disableVBO)
- U.gameflags &= ~USER_DISABLE_VBO;
-
if (bfd) BLO_blendfiledata_free(bfd);
BLI_strncpy(G.main->name, oldsce, sizeof(G.main->name));
#ifdef WITH_PYTHON
+ PyDict_Clear(pyGlobalDict);
Py_DECREF(pyGlobalDict);
// Release Python's GIL
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index e37818678d6..927b26faf8a 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -35,23 +35,16 @@
#include "KX_BlenderCanvas.h"
-#include "DNA_image_types.h"
-#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_image.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
-
-#include "BLI_path_util.h"
-#include "BLI_string.h"
#include <assert.h>
+#include <iostream>
extern "C" {
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
#include "WM_api.h"
#include "wm_cursors.h"
#include "wm_window.h"
@@ -341,33 +334,20 @@ void KX_BlenderCanvas::MakeScreenShot(const char *filename)
area_dummy.totrct.ymax = m_frame_rect.GetTop();
dumprect = screenshot(&area_dummy, &dumpsx, &dumpsy);
-
- if (dumprect) {
- /* initialize image file format data */
- Scene *scene = (screen)? screen->scene: NULL;
- ImageFormatData im_format;
-
- if (scene)
- im_format = scene->r.im_format;
- else
- BKE_imformat_defaults(&im_format);
-
- /* create file path */
- char path[FILE_MAX];
- BLI_strncpy(path, filename, sizeof(path));
- BLI_path_abs(path, G.main->name);
- BLI_path_frame(path, m_frame, 0);
- m_frame++;
- BKE_image_path_ensure_ext_from_imtype(path, im_format.imtype);
-
- /* create and save imbuf */
- ImBuf *ibuf = IMB_allocImBuf(dumpsx, dumpsy, 24, 0);
- ibuf->rect = dumprect;
-
- BKE_imbuf_write_as(ibuf, path, &im_format, false);
-
- ibuf->rect = NULL;
- IMB_freeImBuf(ibuf);
- MEM_freeN(dumprect);
+ if (!dumprect) {
+ std::cerr << "KX_BlenderCanvas: Unable to take screenshot!" << std::endl;
+ return;
}
+
+ /* initialize image file format data */
+ Scene *scene = (screen)? screen->scene: NULL;
+ ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format");
+
+ if (scene)
+ *im_format = scene->r.im_format;
+ else
+ BKE_imformat_defaults(im_format);
+
+ /* save_screenshot() frees dumprect and im_format */
+ save_screenshot(filename, dumpsx, dumpsy, dumprect, im_format);
}
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
index 817a667d783..6f408f86551 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
@@ -212,7 +212,6 @@ private:
RAS_Rect m_area_rect;
int m_area_left;
int m_area_top;
- int m_frame;
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript
deleted file mode 100644
index ea14092943a..00000000000
--- a/source/gameengine/BlenderRoutines/SConscript
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '.',
- '#intern/container',
- '#intern/guardedalloc',
- '#intern/string',
- '#source/blender',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#intern/ghost/include',
- '#intern/moto/include',
- '#source/blender/blenfont',
- '#source/blender/blenkernel',
- '#source/blender/blenlib',
- '#source/blender/blenloader',
- '#source/blender/gpu',
- '#source/blender/imbuf',
- '#source/blender/makesdna',
- '#source/blender/makesrna',
- '#source/blender/misc',
- '#source/blender/windowmanager',
- '#source/gameengine/Converter',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Ketsji',
- '#source/gameengine/Network',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/SceneGraph',
- '#source/blender/editors/include',
- '#source/gameengine/Network/LoopBackNetwork',
- '#source/gameengine/Physics/Bullet',
- '#source/gameengine/Physics/common',
- '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
- ]
-incs = ' '.join(incs)
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-incs += ' ' + env['BF_BULLET_INC']
-incs += ' ' + env['BF_OPENGL_INC']
-incs += ' ' + env['BF_BOOST_INC']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'ge_blen_routines', sources, Split(incs), defs, libtype=['core','player'], priority=[300,35] , cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp
index d4cfeb2201a..d28cdb84275 100644
--- a/source/gameengine/Converter/BL_ActionActuator.cpp
+++ b/source/gameengine/Converter/BL_ActionActuator.cpp
@@ -307,6 +307,7 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
}
switch (m_playtype) {
+ case ACT_ACTION_FROM_PROP:
case ACT_ACTION_LOOP_STOP:
obj->StopAction(m_layer); // Stop the action after getting the frame
@@ -335,6 +336,17 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
return m_flag & ACT_FLAG_ACTIVE;
}
+void BL_ActionActuator::DecLink()
+{
+ SCA_IActuator::DecLink();
+ /* In this case no controllers use this action actuator,
+ and it should stop its action. */
+ if (m_links == 0) {
+ KX_GameObject *obj = (KX_GameObject *)GetParent();
+ obj->StopAction(m_layer);
+ }
+}
+
#ifdef WITH_PYTHON
/* ------------------------------------------------------------------------- */
@@ -572,7 +584,7 @@ int BL_ActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF
if (val != "")
{
- action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
+ action= (bAction*)self->GetLogicManager()->GetActionByName(val);
if (!action)
{
PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, action not found!");
diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h
index f488b0c76a6..a43cf0f0a7b 100644
--- a/source/gameengine/Converter/BL_ActionActuator.h
+++ b/source/gameengine/Converter/BL_ActionActuator.h
@@ -69,6 +69,8 @@ public:
bAction* GetAction() { return m_action; }
void SetAction(bAction* act) { m_action= act; }
+ virtual void DecLink();
+
#ifdef WITH_PYTHON
KX_PYMETHOD_O(BL_ActionActuator,GetChannel)
diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp
index e38cb6eadaf..67cc7d2c291 100644
--- a/source/gameengine/Converter/BL_ArmatureActuator.cpp
+++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp
@@ -243,7 +243,7 @@ int BL_ArmatureActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBU
KX_GameObject* &target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget;
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (target != NULL)
diff --git a/source/gameengine/Converter/BL_ArmatureChannel.h b/source/gameengine/Converter/BL_ArmatureChannel.h
index d349e6e9dae..a07097f8178 100644
--- a/source/gameengine/Converter/BL_ArmatureChannel.h
+++ b/source/gameengine/Converter/BL_ArmatureChannel.h
@@ -60,6 +60,11 @@ public:
struct bPoseChannel *posechannel);
virtual ~BL_ArmatureChannel();
+ inline const char *GetName()
+ {
+ return m_posechannel->name;
+ }
+
#ifdef WITH_PYTHON
// Python access
virtual PyObject *py_repr(void);
diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
index 88d82e21d61..d0c7e061fb7 100644
--- a/source/gameengine/Converter/BL_ArmatureConstraint.cpp
+++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp
@@ -36,6 +36,7 @@
#include "BL_ArmatureObject.h"
#include "BLI_math.h"
#include "BLI_string.h"
+#include "KX_PythonInit.h"
#ifdef WITH_PYTHON
@@ -360,6 +361,7 @@ int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRI
int ival;
double dval;
// char* sval;
+ SCA_LogicManager *logicmgr = KX_GetActiveScene()->GetLogicManager();
KX_GameObject *oval;
if (!constraint) {
@@ -387,13 +389,13 @@ int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRI
return PY_SET_ATTR_SUCCESS;
case BCA_TARGET:
- if (!ConvertPythonToGameObject(value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
+ if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.target = value: BL_ArmatureConstraint"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
self->SetTarget(oval);
return PY_SET_ATTR_SUCCESS;
case BCA_SUBTARGET:
- if (!ConvertPythonToGameObject(value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
+ if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
self->SetSubtarget(oval);
return PY_SET_ATTR_SUCCESS;
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index 74ebdbcf1b5..a1819a8dc92 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -60,10 +60,11 @@ extern "C" {
#include "DNA_scene_types.h"
#include "DNA_constraint_types.h"
#include "RNA_access.h"
-#include "KX_PythonSeq.h"
#include "KX_PythonInit.h"
#include "KX_KetsjiEngine.h"
+#include "EXP_ListWrapper.h"
+
#include "MT_Matrix4x4.h"
/**
@@ -176,6 +177,10 @@ static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode
copy_qt_qt(dquat, dchan->quat);
copy_qt_qt(squat, schan->quat);
+ // Normalize quaternions so that interpolation/multiplication result is correct.
+ normalize_qt(dquat);
+ normalize_qt(squat);
+
if (mode==BL_Action::ACT_BLEND_BLEND)
interp_qt_qtqt(dchan->quat, dquat, squat, srcweight);
else {
@@ -615,16 +620,58 @@ PyAttributeDef BL_ArmatureObject::Attributes[] = {
{NULL} //Sentinel
};
+static int bl_armature_object_get_constraints_size_cb(void *self_v)
+{
+ return ((BL_ArmatureObject *)self_v)->GetConstraintNumber();
+}
+
+static PyObject *bl_armature_object_get_constraints_item_cb(void *self_v, int index)
+{
+ return ((BL_ArmatureObject *)self_v)->GetConstraint(index)->GetProxy();
+}
+
+static const char *bl_armature_object_get_constraints_item_name_cb(void *self_v, int index)
+{
+ return ((BL_ArmatureObject *)self_v)->GetConstraint(index)->GetName();
+}
+
PyObject *BL_ArmatureObject::pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONSTRAINTS);
+ return (new CListWrapper(self_v,
+ ((BL_ArmatureObject *)self_v)->GetProxy(),
+ NULL,
+ bl_armature_object_get_constraints_size_cb,
+ bl_armature_object_get_constraints_item_cb,
+ bl_armature_object_get_constraints_item_name_cb,
+ NULL))->NewProxy(true);
+}
+
+static int bl_armature_object_get_channels_size_cb(void *self_v)
+{
+ return ((BL_ArmatureObject *)self_v)->GetChannelNumber();
+}
+
+static PyObject *bl_armature_object_get_channels_item_cb(void *self_v, int index)
+{
+ return ((BL_ArmatureObject *)self_v)->GetChannel(index)->GetProxy();
+}
+
+static const char *bl_armature_object_get_channels_item_name_cb(void *self_v, int index)
+{
+ return ((BL_ArmatureObject *)self_v)->GetChannel(index)->GetName();
}
PyObject *BL_ArmatureObject::pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- BL_ArmatureObject* self = static_cast<BL_ArmatureObject*>(self_v);
+ BL_ArmatureObject *self = static_cast<BL_ArmatureObject *>(self_v);
self->LoadChannels(); // make sure we have the channels
- return KX_PythonSeq_CreatePyObject((static_cast<BL_ArmatureObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CHANNELS);
+ return (new CListWrapper(self_v,
+ self->GetProxy(),
+ NULL,
+ bl_armature_object_get_channels_size_cb,
+ bl_armature_object_get_channels_item_cb,
+ bl_armature_object_get_channels_item_name_cb,
+ NULL))->NewProxy(true);
}
KX_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update,
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index c74fd82a9f6..c2cfd8808a9 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -228,17 +228,7 @@ static std::map<int, SCA_IInputDevice::KX_EnumInputs> create_translate_table()
m[EKEY ] = SCA_IInputDevice::KX_EKEY;
m[FKEY ] = SCA_IInputDevice::KX_FKEY;
m[GKEY ] = SCA_IInputDevice::KX_GKEY;
-
-//XXX clean up
-#ifdef WIN32
-#define HKEY 'h'
-#endif
m[HKEY ] = SCA_IInputDevice::KX_HKEY;
-//XXX clean up
-#ifdef WIN32
-#undef HKEY
-#endif
-
m[IKEY ] = SCA_IInputDevice::KX_IKEY;
m[JKEY ] = SCA_IInputDevice::KX_JKEY;
m[KKEY ] = SCA_IInputDevice::KX_KKEY;
@@ -562,11 +552,11 @@ static void GetUVs(BL_Material *material, MTF_localLayer *layers, MFace *mface,
// ------------------------------------
static bool ConvertMaterial(
BL_Material *material,
- Material *mat,
- MTFace* tface,
+ Material *mat,
+ MTFace *tface,
const char *tfaceName,
- MFace* mface,
- MCol* mmcol,
+ MFace *mface,
+ MCol *mmcol,
bool glslmat)
{
material->Initialize();
@@ -583,41 +573,41 @@ static bool ConvertMaterial(
if (validmat) {
// use lighting?
- material->ras_mode |= ( mat->mode & MA_SHLESS )?0:USE_LIGHT;
- material->ras_mode |= ( mat->game.flag & GEMAT_BACKCULL )?0:TWOSIDED;
+ material->ras_mode |= (mat->mode & MA_SHLESS) ? 0 : USE_LIGHT;
+ material->ras_mode |= (mat->game.flag & GEMAT_BACKCULL) ? 0 : TWOSIDED;
// cast shadows?
- material->ras_mode |= ( (mat->mode2 & MA_CASTSHADOW) && (mat->mode & MA_SHADBUF) )?CAST_SHADOW:0;
+ material->ras_mode |= ((mat->mode2 & MA_CASTSHADOW) && (mat->mode & MA_SHADBUF)) ? CAST_SHADOW : 0;
// only shadows?
- material->ras_mode |= ( mat->mode & MA_ONLYCAST )?ONLY_SHADOW:0;
+ material->ras_mode |= (mat->mode & MA_ONLYCAST) ? ONLY_SHADOW : 0;
- MTex *mttmp = 0;
+ MTex *mttmp = NULL;
int valid_index = 0;
-
+
/* In Multitexture use the face texture if and only if
* it is set in the buttons
* In GLSL is not working yet :/ 3.2011 */
bool facetex = false;
- if (validface && mat->mode &MA_FACETEXTURE)
+ if (validface && mat->mode & MA_FACETEXTURE) {
facetex = true;
-
+ }
+
// foreach MTex
- for (int i=0; i<MAXTEX; i++) {
+ for (int i = 0; i < MAXTEX; i++) {
// use face tex
-
- if (i==0 && facetex ) {
+ if (i == 0 && facetex ) {
facetex = false;
- Image*tmp = (Image*)(tface->tpage);
+ Image *tmp = (Image *)(tface->tpage);
if (tmp) {
material->img[i] = tmp;
material->texname[i] = material->img[i]->id.name;
material->flag[i] |= MIPMAP;
- material->flag[i] |= ( mat->game.alpha_blend & GEMAT_ALPHA_SORT )?USEALPHA:0;
- material->flag[i] |= ( mat->game.alpha_blend & GEMAT_ALPHA )?USEALPHA:0;
- material->flag[i] |= ( mat->game.alpha_blend & GEMAT_ADD )?CALCALPHA:0;
+ material->flag[i] |= (mat->game.alpha_blend & GEMAT_ALPHA_SORT) ? USEALPHA : 0;
+ material->flag[i] |= (mat->game.alpha_blend & GEMAT_ALPHA) ? USEALPHA : 0;
+ material->flag[i] |= (mat->game.alpha_blend & GEMAT_ADD) ? CALCALPHA : 0;
if (material->img[i]->flag & IMA_REFLECT) {
material->mapping[i].mapping |= USEREFL;
@@ -643,44 +633,43 @@ static bool ConvertMaterial(
mttmp = getMTexFromMaterial(mat, i);
if (mttmp) {
if (mttmp->tex) {
- if ( mttmp->tex->type == TEX_IMAGE ) {
+ if (mttmp->tex->type == TEX_IMAGE) {
material->mtexname[i] = mttmp->tex->id.name;
material->img[i] = mttmp->tex->ima;
- if ( material->img[i] ) {
+ if (material->img[i]) {
material->texname[i] = material->img[i]->id.name;
- material->flag[i] |= ( mttmp->tex->imaflag &TEX_MIPMAP )?MIPMAP:0;
- // -----------------------
- if (material->img[i] && (material->img[i]->flag & IMA_IGNORE_ALPHA) == 0)
- material->flag[i] |= USEALPHA;
- // -----------------------
- if ( mttmp->tex->imaflag &TEX_CALCALPHA ) {
- material->flag[i] |= CALCALPHA;
+ material->flag[i] |= (mttmp->tex->imaflag &TEX_MIPMAP) ? MIPMAP : 0;
+ if (material->img[i] && (material->img[i]->flag & IMA_IGNORE_ALPHA) == 0) {
+ material->flag[i] |= USEALPHA;
+ }
+ if (mttmp->tex->imaflag & TEX_CALCALPHA) {
+ material->flag[i] |= CALCALPHA;
}
- else if (mttmp->tex->flag &TEX_NEGALPHA) {
- material->flag[i] |= USENEGALPHA;
+ else if (mttmp->tex->flag & TEX_NEGALPHA) {
+ material->flag[i] |= USENEGALPHA;
}
material->color_blend[i] = mttmp->colfac;
- material->flag[i] |= ( mttmp->mapto & MAP_ALPHA )?TEXALPHA:0;
- material->flag[i] |= ( mttmp->texflag& MTEX_NEGATIVE )?TEXNEG:0;
+ material->flag[i] |= (mttmp->mapto & MAP_ALPHA) ? TEXALPHA : 0;
+ material->flag[i] |= (mttmp->texflag & MTEX_NEGATIVE) ? TEXNEG : 0;
- if (!glslmat && (material->flag[i] & TEXALPHA))
+ if (!glslmat && (material->flag[i] & TEXALPHA)) {
texalpha = 1;
+ }
}
}
else if (mttmp->tex->type == TEX_ENVMAP) {
- if ( mttmp->tex->env->stype == ENV_LOAD ) {
-
- material->mtexname[i] = mttmp->tex->id.name;
+ if (mttmp->tex->env->stype == ENV_LOAD) {
+ material->mtexname[i] = mttmp->tex->id.name;
EnvMap *env = mttmp->tex->env;
env->ima = mttmp->tex->ima;
material->cubemap[i] = env;
- if (material->cubemap[i])
- {
- if (!material->cubemap[i]->cube[0])
+ if (material->cubemap[i]) {
+ if (!material->cubemap[i]->cube[0]) {
BL_Texture::SplitEnvMap(material->cubemap[i]);
+ }
material->texname[i] = material->cubemap[i]->ima->id.name;
material->mapping[i].mapping |= USEENV;
@@ -695,29 +684,36 @@ static bool ConvertMaterial(
if (mat->septex & (1 << i)) {
// If this texture slot isn't in use, set it to disabled to prevent multi-uv problems
material->mapping[i].mapping = DISABLE;
- } else {
- material->mapping[i].mapping |= ( mttmp->texco & TEXCO_REFL )?USEREFL:0;
+ }
+ else {
+ material->mapping[i].mapping |= (mttmp->texco & TEXCO_REFL) ? USEREFL : 0;
if (mttmp->texco & TEXCO_OBJECT) {
material->mapping[i].mapping |= USEOBJ;
- if (mttmp->object)
+ if (mttmp->object) {
material->mapping[i].objconame = mttmp->object->id.name;
+ }
}
- else if (mttmp->texco &TEXCO_REFL)
+ else if (mttmp->texco & TEXCO_REFL) {
material->mapping[i].mapping |= USEREFL;
- else if (mttmp->texco &(TEXCO_ORCO|TEXCO_GLOB))
+ }
+ else if (mttmp->texco & (TEXCO_ORCO | TEXCO_GLOB)) {
material->mapping[i].mapping |= USEORCO;
+ }
else if (mttmp->texco & TEXCO_UV) {
/* string may be "" but thats detected as empty after */
material->mapping[i].uvCoName = mttmp->uvname;
material->mapping[i].mapping |= USEUV;
}
- else if (mttmp->texco &TEXCO_NORM)
+ else if (mttmp->texco & TEXCO_NORM) {
material->mapping[i].mapping |= USENORM;
- else if (mttmp->texco &TEXCO_TANGENT)
+ }
+ else if (mttmp->texco & TEXCO_TANGENT) {
material->mapping[i].mapping |= USETANG;
- else
+ }
+ else {
material->mapping[i].mapping |= DISABLE;
+ }
material->mapping[i].scale[0] = mttmp->size[0];
material->mapping[i].scale[1] = mttmp->size[1];
@@ -771,59 +767,60 @@ static bool ConvertMaterial(
material->num_enabled = valid_index;
- material->speccolor[0] = mat->specr;
- material->speccolor[1] = mat->specg;
- material->speccolor[2] = mat->specb;
- material->hard = (float)mat->har/4.0f;
- material->matcolor[0] = mat->r;
- material->matcolor[1] = mat->g;
- material->matcolor[2] = mat->b;
- material->matcolor[3] = mat->alpha;
- material->alpha = mat->alpha;
- material->emit = mat->emit;
- material->spec_f = mat->spec;
- material->ref = mat->ref;
- material->amb = mat->amb;
-
- material->ras_mode |= (mat->material_type == MA_TYPE_WIRE)? WIRE: 0;
+ material->speccolor[0] = mat->specr;
+ material->speccolor[1] = mat->specg;
+ material->speccolor[2] = mat->specb;
+ material->hard = (float)mat->har / 4.0f;
+ material->matcolor[0] = mat->r;
+ material->matcolor[1] = mat->g;
+ material->matcolor[2] = mat->b;
+ material->matcolor[3] = mat->alpha;
+ material->alpha = mat->alpha;
+ material->emit = mat->emit;
+ material->spec_f = mat->spec;
+ material->ref = mat->ref;
+ material->amb = mat->amb;
+
+ material->ras_mode |= (mat->material_type == MA_TYPE_WIRE) ? WIRE : 0;
}
else { // No Material
int valid = 0;
// check for tface tex to fallback on
- if ( validface ) {
- material->img[0] = (Image*)(tface->tpage);
+ if (validface) {
+ material->img[0] = (Image *)(tface->tpage);
// ------------------------
if (material->img[0]) {
material->texname[0] = material->img[0]->id.name;
- material->mapping[0].mapping |= ( (material->img[0]->flag & IMA_REFLECT)!=0 )?USEREFL:0;
+ material->mapping[0].mapping |= ((material->img[0]->flag & IMA_REFLECT) != 0) ? USEREFL : 0;
/* see if depth of the image is 32bits */
if (BKE_image_has_alpha(material->img[0])) {
material->flag[0] |= USEALPHA;
material->alphablend = GEMAT_ALPHA;
}
- else
+ else {
material->alphablend = GEMAT_SOLID;
-
+ }
valid++;
}
}
- else
+ else {
material->alphablend = GEMAT_SOLID;
+ }
material->SetUsers(-1);
- material->num_enabled = valid;
- material->IdMode = TEXFACE;
- material->speccolor[0] = 1.f;
- material->speccolor[1] = 1.f;
- material->speccolor[2] = 1.f;
- material->hard = 35.f;
- material->matcolor[0] = 0.5f;
- material->matcolor[1] = 0.5f;
- material->matcolor[2] = 0.5f;
- material->spec_f = 0.5f;
- material->ref = 0.8f;
+ material->num_enabled = valid;
+ material->IdMode = TEXFACE;
+ material->speccolor[0] = 1.0f;
+ material->speccolor[1] = 1.0f;
+ material->speccolor[2] = 1.0f;
+ material->hard = 35.0f;
+ material->matcolor[0] = 0.5f;
+ material->matcolor[1] = 0.5f;
+ material->matcolor[2] = 0.5f;
+ material->spec_f = 0.5f;
+ material->ref = 0.8f;
// No material - old default TexFace properties
material->ras_mode |= USE_LIGHT;
@@ -831,13 +828,13 @@ static bool ConvertMaterial(
/* No material, what to do? let's see what is in the UV and set the material accordingly
* light and visible is always on */
- if ( validface ) {
- material->tile = tface->tile;
+ if (validface) {
+ material->tile = tface->tile;
}
else {
// nothing at all
- material->alphablend = GEMAT_SOLID;
- material->tile = 0;
+ material->alphablend = GEMAT_SOLID;
+ material->tile = 0;
}
if (validmat && validface) {
@@ -845,13 +842,14 @@ static bool ConvertMaterial(
}
// with ztransp enabled, enforce alpha blending mode
- if (validmat && (mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (material->alphablend == GEMAT_SOLID))
+ if (validmat && (mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (material->alphablend == GEMAT_SOLID)) {
material->alphablend = GEMAT_ALPHA;
+ }
// always zsort alpha + add
- if ((ELEM(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) {
+ if ((ELEM(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP)) {
material->ras_mode |= ALPHA;
- material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT))? ZSORT: 0;
+ material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT)) ? ZSORT : 0;
}
// XXX The RGB values here were meant to be temporary storage for the conversion process,
@@ -860,16 +858,16 @@ static bool ConvertMaterial(
GetRGB(use_vcol, mface, mmcol, mat, rgb);
// swap the material color, so MCol on bitmap font works
- if (validmat && (use_vcol == false) && (mat->game.flag & GEMAT_TEXT))
- {
+ if (validmat && (use_vcol == false) && (mat->game.flag & GEMAT_TEXT)) {
material->rgb[0] = KX_rgbaint2uint_new(rgb[0]);
material->rgb[1] = KX_rgbaint2uint_new(rgb[1]);
material->rgb[2] = KX_rgbaint2uint_new(rgb[2]);
material->rgb[3] = KX_rgbaint2uint_new(rgb[3]);
}
- if (validmat)
- material->matname =(mat->id.name);
+ if (validmat) {
+ material->matname =(mat->id.name);
+ }
if (tface) {
ME_MTEXFACE_CPY(&material->mtexpoly, tface);
@@ -877,7 +875,7 @@ static bool ConvertMaterial(
else {
memset(&material->mtexpoly, 0, sizeof(material->mtexpoly));
}
- material->material = mat;
+ material->material = mat;
return true;
}
@@ -1215,7 +1213,8 @@ static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blendero
shapeProps->m_step_height = blenderobject->step_height;
shapeProps->m_jump_speed = blenderobject->jump_speed;
shapeProps->m_fall_speed = blenderobject->fall_speed;
-
+ shapeProps->m_max_jumps = blenderobject->max_jumps;
+
return shapeProps;
}
@@ -1418,11 +1417,23 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l
lightobj->m_att1 = la->att1;
lightobj->m_att2 = (la->mode & LA_QUAD) ? la->att2 : 0.0f;
+ lightobj->m_coeff_const = la->coeff_const;
+ lightobj->m_coeff_lin = la->coeff_lin;
+ lightobj->m_coeff_quad = la->coeff_quad;
lightobj->m_color[0] = la->r;
lightobj->m_color[1] = la->g;
lightobj->m_color[2] = la->b;
lightobj->m_distance = la->dist;
lightobj->m_energy = la->energy;
+ lightobj->m_shadowclipstart = la->clipsta;
+ lightobj->m_shadowclipend = la->clipend;
+ lightobj->m_shadowbias = la->bias;
+ lightobj->m_shadowbleedbias = la->bleedbias;
+ lightobj->m_shadowmaptype = la->shadowmap_type;
+ lightobj->m_shadowfrustumsize = la->shadow_frustum_size;
+ lightobj->m_shadowcolor[0] = la->shdwr;
+ lightobj->m_shadowcolor[1] = la->shdwg;
+ lightobj->m_shadowcolor[2] = la->shdwb;
lightobj->m_layer = layerflag;
lightobj->m_spotblend = la->spotblend;
lightobj->m_spotsize = la->spotsize;
diff --git a/source/gameengine/Converter/BL_ModifierDeformer.cpp b/source/gameengine/Converter/BL_ModifierDeformer.cpp
index 3bc07113ff6..b40fb7a9f47 100644
--- a/source/gameengine/Converter/BL_ModifierDeformer.cpp
+++ b/source/gameengine/Converter/BL_ModifierDeformer.cpp
@@ -46,7 +46,6 @@
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_ipo_types.h"
#include "DNA_curve_types.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
index e8f451213f5..f21db419ebc 100644
--- a/source/gameengine/Converter/BL_ShapeActionActuator.cpp
+++ b/source/gameengine/Converter/BL_ShapeActionActuator.cpp
@@ -547,7 +547,7 @@ int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE
if (val != "")
{
- action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
+ action= (bAction*)self->GetLogicManager()->GetActionByName(val);
if (action==NULL)
{
PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp
index 950c1dcad11..68da99f9fa5 100644
--- a/source/gameengine/Converter/BL_SkinDeformer.cpp
+++ b/source/gameengine/Converter/BL_SkinDeformer.cpp
@@ -153,7 +153,10 @@ void BL_SkinDeformer::Relink(CTR_Map<class CTR_HashedPtr, void*>*map)
bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat)
{
// We do everything in UpdateInternal() now so we can thread it.
- return false;
+ // All that is left is telling the rasterizer if we've changed the mesh
+ bool retval = !m_poseApplied;
+ m_poseApplied = true;
+ return retval;
}
RAS_Deformer *BL_SkinDeformer::GetReplica()
@@ -359,6 +362,8 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied)
UpdateTransverts();
+ m_poseApplied = false;
+
/* indicate that the m_transverts and normals are up to date */
return true;
}
diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp
index 1e1bc738301..4d344cdf16a 100644
--- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp
+++ b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp
@@ -35,7 +35,6 @@
#include <cstring>
extern "C" {
-#include "DNA_ipo_types.h"
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "BKE_fcurve.h"
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
index 9d01d3d5a39..b97d0b2a85d 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -108,12 +108,12 @@ extern "C" {
#include "../../blender/blenlib/BLI_linklist.h"
}
-#include <pthread.h>
+#include "BLI_task.h"
-/* This is used to avoid including pthread.h in KX_BlenderSceneConverter.h */
+// This is used to avoid including BLI_task.h in KX_BlenderSceneConverter.h
typedef struct ThreadInfo {
- vector<pthread_t> threads;
- pthread_mutex_t merge_lock;
+ TaskPool *m_pool;
+ ThreadMutex m_mutex;
} ThreadInfo;
KX_BlenderSceneConverter::KX_BlenderSceneConverter(
@@ -126,10 +126,11 @@ KX_BlenderSceneConverter::KX_BlenderSceneConverter(
m_useglslmat(false),
m_use_mat_cache(true)
{
- BKE_main_id_tag_all(maggie, false); /* avoid re-tagging later on */
+ BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, false); /* avoid re-tagging later on */
m_newfilename = "";
m_threadinfo = new ThreadInfo();
- pthread_mutex_init(&m_threadinfo->merge_lock, NULL);
+ m_threadinfo->m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), NULL);
+ BLI_mutex_init(&m_threadinfo->m_mutex);
}
KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
@@ -137,17 +138,6 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
// clears meshes, and hashmaps from blender to gameengine data
// delete sumoshapes
- if (m_threadinfo) {
- vector<pthread_t>::iterator pit = m_threadinfo->threads.begin();
- while (pit != m_threadinfo->threads.end()) {
- pthread_join((*pit), NULL);
- pit++;
- }
-
- pthread_mutex_destroy(&m_threadinfo->merge_lock);
- delete m_threadinfo;
- }
-
int numAdtLists = m_map_blender_to_gameAdtList.size();
for (int i = 0; i < numAdtLists; i++) {
BL_InterpolatorList *adtList = *m_map_blender_to_gameAdtList.at(i);
@@ -190,6 +180,15 @@ KX_BlenderSceneConverter::~KX_BlenderSceneConverter()
}
m_DynamicMaggie.clear();
+
+ if (m_threadinfo) {
+ /* Thread infos like mutex must be freed after FreeBlendFile function.
+ Because it needs to lock the mutex, even if there's no active task when it's
+ in the scene converter destructor. */
+ BLI_task_pool_free(m_threadinfo->m_pool);
+ BLI_mutex_end(&m_threadinfo->m_mutex);
+ delete m_threadinfo;
+ }
}
void KX_BlenderSceneConverter::SetNewFileName(const STR_String &filename)
@@ -631,8 +630,8 @@ void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber)
mat3_to_compatible_eul(blenderObject->rot, blenderObject->rot, tmat);
- insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "location", -1, (float)frameNumber, INSERTKEY_FAST);
- insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "rotation_euler", -1, (float)frameNumber, INSERTKEY_FAST);
+ insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "location", -1, (float)frameNumber, BEZT_KEYTYPE_JITTER, INSERTKEY_FAST);
+ insert_keyframe(NULL, &blenderObject->id, NULL, NULL, "rotation_euler", -1, (float)frameNumber, BEZT_KEYTYPE_JITTER, INSERTKEY_FAST);
#if 0
const MT_Point3& position = gameObj->NodeGetWorldPosition();
@@ -787,7 +786,7 @@ void KX_BlenderSceneConverter::MergeAsyncLoads()
vector<KX_LibLoadStatus *>::iterator mit;
vector<KX_Scene *>::iterator sit;
- pthread_mutex_lock(&m_threadinfo->merge_lock);
+ BLI_mutex_lock(&m_threadinfo->m_mutex);
for (mit = m_mergequeue.begin(); mit != m_mergequeue.end(); ++mit) {
merge_scenes = (vector<KX_Scene *> *)(*mit)->GetData();
@@ -805,17 +804,27 @@ void KX_BlenderSceneConverter::MergeAsyncLoads()
m_mergequeue.clear();
- pthread_mutex_unlock(&m_threadinfo->merge_lock);
+ BLI_mutex_unlock(&m_threadinfo->m_mutex);
+}
+
+void KX_BlenderSceneConverter::FinalizeAsyncLoads()
+{
+ // Finish all loading libraries.
+ if (m_threadinfo) {
+ BLI_task_pool_work_and_wait(m_threadinfo->m_pool);
+ }
+ // Merge all libraries data in the current scene, to avoid memory leak of unmerged scenes.
+ MergeAsyncLoads();
}
void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status)
{
- pthread_mutex_lock(&m_threadinfo->merge_lock);
+ BLI_mutex_lock(&m_threadinfo->m_mutex);
m_mergequeue.push_back(status);
- pthread_mutex_unlock(&m_threadinfo->merge_lock);
+ BLI_mutex_unlock(&m_threadinfo->m_mutex);
}
-static void *async_convert(void *ptr)
+static void async_convert(TaskPool *pool, void *ptr, int UNUSED(threadid))
{
KX_Scene *new_scene = NULL;
KX_LibLoadStatus *status = (KX_LibLoadStatus *)ptr;
@@ -835,8 +844,6 @@ static void *async_convert(void *ptr)
status->SetData(merge_scenes);
status->GetConverter()->AddScenesToMergeQueue(status);
-
- return NULL;
}
KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options)
@@ -865,7 +872,7 @@ static void load_datablocks(Main *main_tmp, BlendHandle *bpy_openlib, const char
int i = 0;
LinkNode *n = names;
while (n) {
- BLO_library_append_named_part(main_tmp, &bpy_openlib, (char *)n->link, idcode);
+ BLO_library_link_named_part(main_tmp, &bpy_openlib, idcode, (char *)n->link);
n = (LinkNode *)n->next;
i++;
}
@@ -909,7 +916,7 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
short flag = 0; /* don't need any special options */
/* created only for linking, then freed */
- Main *main_tmp = BLO_library_append_begin(main_newlib, &bpy_openlib, (char *)path);
+ Main *main_tmp = BLO_library_link_begin(main_newlib, &bpy_openlib, (char *)path);
load_datablocks(main_tmp, bpy_openlib, path, idcode);
@@ -922,7 +929,7 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
load_datablocks(main_tmp, bpy_openlib, path, ID_AC);
}
- BLO_library_append_end(NULL, main_tmp, &bpy_openlib, idcode, flag);
+ BLO_library_link_end(main_tmp, &bpy_openlib, flag, NULL, NULL);
BLO_blendhandle_close(bpy_openlib);
@@ -981,10 +988,8 @@ KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openl
}
if (options & LIB_LOAD_ASYNC) {
- pthread_t id;
status->SetData(scenes);
- pthread_create(&id, NULL, &async_convert, (void *)status);
- m_threadinfo->threads.push_back(id);
+ BLI_task_pool_push(m_threadinfo->m_pool, async_convert, (void *)status, false, TASK_PRIORITY_LOW);
}
#ifdef WITH_PYTHON
@@ -1023,12 +1028,24 @@ bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
if (maggie == NULL)
return false;
-
+
+ // If the given library is currently in loading, we do nothing.
+ if (m_status_map.count(maggie->name)) {
+ BLI_mutex_lock(&m_threadinfo->m_mutex);
+ const bool finished = m_status_map[maggie->name]->IsFinished();
+ BLI_mutex_unlock(&m_threadinfo->m_mutex);
+
+ if (!finished) {
+ printf("Library (%s) is currently being loaded asynchronously, and cannot be freed until this process is done\n", maggie->name);
+ return false;
+ }
+ }
+
/* tag all false except the one we remove */
for (vector<Main *>::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) {
Main *main = *it;
if (main != maggie) {
- BKE_main_id_tag_all(main, false);
+ BKE_main_id_tag_all(main, LIB_TAG_DOIT, false);
}
else {
maggie_index = i;
@@ -1041,7 +1058,7 @@ bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie)
return false;
m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index);
- BKE_main_id_tag_all(maggie, true);
+ BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, true);
/* free all tagged objects */
KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes();
@@ -1409,7 +1426,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
printf("Mesh has a user \"%s\"\n", name);
#endif
me = (ID*)BKE_mesh_copy_ex(from_maggie, (Mesh*)me);
- me->us--;
+ id_us_min(me);
}
BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */
BLI_addtail(&maggie->mesh, me);
@@ -1421,19 +1438,19 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
/* ensure all materials are tagged */
for (int i = 0; i < mesh->totcol; i++) {
if (mesh->mat[i])
- mesh->mat[i]->id.flag &= ~LIB_DOIT;
+ mesh->mat[i]->id.tag &= ~LIB_TAG_DOIT;
}
for (int i = 0; i < mesh->totcol; i++) {
Material *mat_old = mesh->mat[i];
/* if its tagged its a replaced material */
- if (mat_old && (mat_old->id.flag & LIB_DOIT) == 0) {
+ if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) {
Material *mat_old = mesh->mat[i];
Material *mat_new = BKE_material_copy(mat_old);
- mat_new->id.flag |= LIB_DOIT;
- mat_old->id.us--;
+ mat_new->id.tag |= LIB_TAG_DOIT;
+ id_us_min(&mat_old->id);
BLI_remlink(&G.main->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex
BLI_addtail(&maggie->mat, mat_new);
@@ -1444,8 +1461,8 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene,
for (int j = i + 1; j < mesh->totcol; j++) {
if (mesh->mat[j] == mat_old) {
mesh->mat[j] = mat_new;
- mat_new->id.us++;
- mat_old->id.us--;
+ id_us_plus(&mat_new->id);
+ id_us_min(&mat_old->id);
}
}
}
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h
index a40188d197d..40c71a4d74b 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.h
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h
@@ -184,6 +184,7 @@ public:
bool FreeBlendFile(const char *path);
virtual void MergeAsyncLoads();
+ virtual void FinalizeAsyncLoads();
void AddScenesToMergeQueue(class KX_LibLoadStatus *status);
void PrintStats() {
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index 3b36e094a75..455fef0aceb 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -54,7 +54,6 @@
// Ketsji specific logicbricks
#include "KX_SceneActuator.h"
-#include "KX_IpoActuator.h"
#include "KX_SoundActuator.h"
#include "KX_ObjectActuator.h"
#include "KX_TrackToActuator.h"
@@ -262,32 +261,6 @@ void BL_ConvertActuators(const char* maggiename,
else
printf ("Discarded shape action actuator from non-mesh object [%s]\n", blenderobject->id.name+2);
}
- case ACT_IPO:
- {
- bIpoActuator* ipoact = (bIpoActuator*) bact->data;
- bool ipochild = (ipoact->flag & ACT_IPOCHILD) !=0;
- STR_String propname = ipoact->name;
- STR_String frameProp = ipoact->frameProp;
- // first bit?
- bool ipo_as_force = (ipoact->flag & ACT_IPOFORCE);
- bool local = (ipoact->flag & ACT_IPOLOCAL);
- bool ipo_add = (ipoact->flag & ACT_IPOADD);
-
- KX_IpoActuator* tmpbaseact = new KX_IpoActuator(
- gameobj,
- propname ,
- frameProp,
- ipoact->sta,
- ipoact->end,
- ipochild,
- ipoact->type + 1, // + 1, because Blender starts to count at zero,
- // Ketsji at 1, because zero is reserved for "NoDef"
- ipo_as_force,
- ipo_add,
- local);
- baseact = tmpbaseact;
- break;
- }
case ACT_LAMP:
{
break;
@@ -421,7 +394,7 @@ void BL_ConvertActuators(const char* maggiename,
soundActuatorType);
// if we made it mono, we have to free it
- if(snd_sound != sound->playback_handle && snd_sound != NULL)
+ if(sound && snd_sound && snd_sound != sound->playback_handle)
AUD_Sound_free(snd_sound);
tmpsoundact->SetName(bact->name);
@@ -505,6 +478,13 @@ void BL_ConvertActuators(const char* maggiename,
{
RAS_MeshObject *tmpmesh = converter->FindGameMesh(editobact->me);
+ if (!tmpmesh) {
+ std::cout << "Warning: object \"" << objectname <<
+ "\" from ReplaceMesh actuator \"" << uniquename <<
+ "\" uses a mesh not owned by an object in scene \"" <<
+ scene->GetName() << "\"." << std::endl;
+ }
+
KX_SCA_ReplaceMeshActuator* tmpreplaceact = new KX_SCA_ReplaceMeshActuator(
gameobj,
tmpmesh,
@@ -806,6 +786,12 @@ void BL_ConvertActuators(const char* maggiename,
mode = KX_GameActuator::KX_GAME_LOADCFG;
break;
}
+ case ACT_GAME_SCREENSHOT:
+ {
+ mode = KX_GameActuator::KX_GAME_SCREENSHOT;
+ filename = gameact->filename;
+ break;
+ }
default:
; /* flag error */
}
@@ -1141,6 +1127,7 @@ void BL_ConvertActuators(const char* maggiename,
uniquename += uniqueval->GetText();
uniqueval->Release();
baseact->SetName(bact->name);
+ baseact->SetLogicManager(logicmgr);
//gameobj->SetProperty(uniquename,baseact);
gameobj->AddActuator(baseact);
diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp
index e3697087ea9..f55d81adb80 100644
--- a/source/gameengine/Converter/KX_ConvertControllers.cpp
+++ b/source/gameengine/Converter/KX_ConvertControllers.cpp
@@ -214,6 +214,7 @@ void BL_ConvertControllers(
//at some point it should either be implemented globally (and saved as a separate var) or removed.
//gamecontroller->SetName(uniquename);
gamecontroller->SetName(bcontr->name);
+ gamecontroller->SetLogicManager(logicmgr);
gameobj->AddController(gamecontroller);
converter->RegisterGameController(gamecontroller, bcontr);
diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp
index 79fd9cb9254..5e897bb4a62 100644
--- a/source/gameengine/Converter/KX_ConvertSensors.cpp
+++ b/source/gameengine/Converter/KX_ConvertSensors.cpp
@@ -608,6 +608,7 @@ void BL_ConvertSensors(struct Object* blenderobject,
gamesensor->SetLevel(level);
gamesensor->SetTap(tap);
gamesensor->SetName(sens->name);
+ gamesensor->SetLogicManager(logicmgr);
gameobj->AddSensor(gamesensor);
diff --git a/source/gameengine/Converter/KX_LibLoadStatus.cpp b/source/gameengine/Converter/KX_LibLoadStatus.cpp
index 2a38e062f89..66fcd998269 100644
--- a/source/gameengine/Converter/KX_LibLoadStatus.cpp
+++ b/source/gameengine/Converter/KX_LibLoadStatus.cpp
@@ -36,7 +36,8 @@ KX_LibLoadStatus::KX_LibLoadStatus(class KX_BlenderSceneConverter* kx_converter,
m_mergescene(merge_scene),
m_data(NULL),
m_libname(path),
- m_progress(0.f)
+ m_progress(0.0f),
+ m_finished(false)
#ifdef WITH_PYTHON
,
m_finish_cb(NULL),
@@ -48,6 +49,7 @@ KX_LibLoadStatus::KX_LibLoadStatus(class KX_BlenderSceneConverter* kx_converter,
void KX_LibLoadStatus::Finish()
{
+ m_finished = true;
m_progress = 1.f;
m_endtime = PIL_check_seconds_timer();
@@ -157,6 +159,7 @@ PyAttributeDef KX_LibLoadStatus::Attributes[] = {
KX_PYATTRIBUTE_FLOAT_RO("progress", KX_LibLoadStatus, m_progress),
KX_PYATTRIBUTE_STRING_RO("libraryName", KX_LibLoadStatus, m_libname),
KX_PYATTRIBUTE_RO_FUNCTION("timeTaken", KX_LibLoadStatus, pyattr_get_timetaken),
+ KX_PYATTRIBUTE_BOOL_RO("finished", KX_LibLoadStatus, m_finished),
{ NULL } //Sentinel
};
diff --git a/source/gameengine/Converter/KX_LibLoadStatus.h b/source/gameengine/Converter/KX_LibLoadStatus.h
index bedf4498c96..fd51bfddd85 100644
--- a/source/gameengine/Converter/KX_LibLoadStatus.h
+++ b/source/gameengine/Converter/KX_LibLoadStatus.h
@@ -43,6 +43,9 @@ private:
double m_starttime;
double m_endtime;
+ // The current status of this libload, used by the scene converter.
+ bool m_finished;
+
#ifdef WITH_PYTHON
PyObject* m_finish_cb;
PyObject* m_progress_cb;
@@ -68,6 +71,11 @@ public:
void SetData(void *data);
void *GetData();
+ inline bool IsFinished() const
+ {
+ return m_finished;
+ }
+
void SetProgress(float progress);
float GetProgress();
void AddProgress(float progress);
diff --git a/source/gameengine/Converter/SConscript b/source/gameengine/Converter/SConscript
deleted file mode 100644
index 6336fcd3906..00000000000
--- a/source/gameengine/Converter/SConscript
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-defs = []
-
-incs = [
- '.',
- '#extern/Eigen3',
- '#intern/container',
- '#intern/guardedalloc',
- '#intern/string',
- '#source/blender',
- '#intern/moto/include',
- '#source/blender/blenkernel',
- '#source/blender/blenlib',
- '#source/blender/blenloader',
- '#source/blender/gpu',
- '#source/blender/ikplugin',
- '#source/blender/imbuf',
- '#source/blender/makesdna',
- '#source/blender/makesrna',
- '#source/blender/misc',
- '#source/blender/windowmanager',
- '#source/gameengine/BlenderRoutines',
- '#source/gameengine/Converter',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Ketsji',
- '#source/gameengine/Network',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/SceneGraph',
- '#extern/recastnavigation/Detour/Include',
- '#source/blender/editors/include',
- '#source/gameengine/Ketsji/KXNetwork',
- '#source/gameengine/Network/LoopBackNetwork',
- '#source/gameengine/Physics/Bullet',
- '#source/gameengine/Physics/Dummy',
- '#source/gameengine/Physics/common',
- '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
- ]
-incs = ' '.join(incs)
-
-incs += ' ' + env['BF_BULLET_INC']
-incs += ' ' + env['BF_BOOST_INC']
-
-if env['BF_DEBUG']:
- if env['OURPLATFORM'] in ('win32-mingw', 'win32-vc', 'win64-vc', 'win64-mingw'):
- defs.append('_DEBUG')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'ge_converter', sources, Split(incs), defs, libtype=['core','player'], priority=[305,40], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt
index 6ab4d3fdacc..9c563a46ea2 100644
--- a/source/gameengine/Expressions/CMakeLists.txt
+++ b/source/gameengine/Expressions/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
intern/StringValue.cpp
intern/Value.cpp
intern/VectorValue.cpp
+ intern/ListWrapper.cpp
EXP_BoolValue.h
EXP_ConstExpr.h
@@ -75,6 +76,8 @@ set(SRC
EXP_Value.h
EXP_VectorValue.h
EXP_VoidValue.h
+ EXP_ListWrapper.h
+
)
if(WITH_PYTHON)
diff --git a/source/gameengine/Expressions/EXP_ListWrapper.h b/source/gameengine/Expressions/EXP_ListWrapper.h
new file mode 100644
index 00000000000..e4c97691acb
--- /dev/null
+++ b/source/gameengine/Expressions/EXP_ListWrapper.h
@@ -0,0 +1,109 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Porteries Tristan.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file EXP_ListWrapper.h
+ * \ingroup expressions
+ */
+
+#ifdef WITH_PYTHON
+
+#ifndef __EXP_LISTWRAPPER_H__
+#define __EXP_LISTWRAPPER_H__
+
+#include "EXP_Value.h"
+
+class CListWrapper : public CValue
+{
+ Py_Header
+private:
+ /** The client instance passed as first argument of each callback.
+ * We use a void * instead of a template to avoid to declare this class
+ * for each use in KX_PythonInitTypes.
+ */
+ void *m_client;
+
+ // The python object which owned this list.
+ PyObject *m_base;
+
+ /// Returns true if the list is still valid, else each call will raise an error.
+ bool (*m_checkValid)(void *);
+
+ /// Returns the list size.
+ int (*m_getSize)(void *);
+
+ /// Returns the list item for the giving index.
+ PyObject *(*m_getItem)(void *, int);
+
+ /// Returns name item for the giving index, used for python operator list["name"].
+ const char *(*m_getItemName)(void *, int);
+
+ /// Sets the nex item to the index place, return false when failed item conversion.
+ bool (*m_setItem)(void *, int, PyObject *);
+
+public:
+ CListWrapper(void *client,
+ PyObject *base,
+ bool (*checkValid)(void *),
+ int (*getSize)(void *),
+ PyObject *(*getItem)(void *, int),
+ const char *(*getItemName)(void *, int),
+ bool (*setItem)(void *, int, PyObject *));
+ ~CListWrapper();
+
+ /// \section Python Interface
+ bool CheckValid();
+ int GetSize();
+ PyObject *GetItem(int index);
+ const char *GetItemName(int index);
+ bool SetItem(int index, PyObject *item);
+ bool AllowSetItem();
+ bool AllowGetItemByName();
+
+ /// \section CValue Inherited Functions.
+ virtual const STR_String &GetText();
+ virtual void SetName(const char *name);
+ virtual STR_String &GetName();
+ virtual CValue *GetReplica();
+ virtual CValue *Calc(VALUE_OPERATOR op, CValue *val);
+ virtual CValue *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
+ virtual double GetNumber();
+ virtual int GetValueType();
+ virtual PyObject *py_repr();
+
+ // Python list operators.
+ static PySequenceMethods py_as_sequence;
+ // Python dictionnary operators.
+ static PyMappingMethods py_as_mapping;
+
+ static Py_ssize_t py_len(PyObject *self);
+ static PyObject *py_get_item(PyObject *self, Py_ssize_t index);
+ static int py_set_item(PyObject *self, Py_ssize_t index, PyObject *value);
+ static PyObject *py_mapping_subscript(PyObject *self, PyObject *key);
+ static int py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value);
+ static int py_contains(PyObject *self, PyObject *key);
+
+ KX_PYMETHOD_VARARGS(CListWrapper, Get);
+};
+
+#endif // __EXP_LISTWRAPPER_H__
+
+#endif // WITH_PYTHON
diff --git a/source/gameengine/Expressions/SConscript b/source/gameengine/Expressions/SConscript
deleted file mode 100644
index b66d36c2080..00000000000
--- a/source/gameengine/Expressions/SConscript
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('intern/*.cpp')
-
-incs = [
- '.',
- '#intern/guardedalloc',
- '#intern/string',
- '#intern/moto/include',
- '#source/gameengine/SceneGraph',
- '#source/blender/blenlib',
- ]
-
-defs = []
-
-if env['WITH_BF_PYTHON']:
- incs.extend(Split(env['BF_PYTHON_INC']))
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-env.BlenderLib('ge_logic_expressions', sources, incs, defs, libtype=['core','player'], priority = [360,80], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Expressions/intern/ListWrapper.cpp b/source/gameengine/Expressions/intern/ListWrapper.cpp
new file mode 100644
index 00000000000..db1518a4388
--- /dev/null
+++ b/source/gameengine/Expressions/intern/ListWrapper.cpp
@@ -0,0 +1,424 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Porteries Tristan.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ListWrapper.cpp
+ * \ingroup expressions
+ */
+
+#ifdef WITH_PYTHON
+
+#include "EXP_ListWrapper.h"
+
+static STR_String pythonGeneratorList = "ListWrapper";
+
+CListWrapper::CListWrapper(void *client,
+ PyObject *base,
+ bool (*checkValid)(void *),
+ int (*getSize)(void *),
+ PyObject *(*getItem)(void *, int),
+ const char *(*getItemName)(void *, int),
+ bool (*setItem)(void *, int, PyObject *))
+:m_client(client),
+m_base(base),
+m_checkValid(checkValid),
+m_getSize(getSize),
+m_getItem(getItem),
+m_getItemName(getItemName),
+m_setItem(setItem)
+{
+ // Incref to always have a existing pointer.
+ Py_INCREF(m_base);
+}
+
+CListWrapper::~CListWrapper()
+{
+ Py_DECREF(m_base);
+}
+
+bool CListWrapper::CheckValid()
+{
+ if (m_base && !BGE_PROXY_REF(m_base)) {
+ return false;
+ }
+ return m_checkValid ? (*m_checkValid)(m_client) : true;
+}
+
+int CListWrapper::GetSize()
+{
+ return (*m_getSize)(m_client);
+}
+
+PyObject *CListWrapper::GetItem(int index)
+{
+ return (*m_getItem)(m_client, index);
+}
+
+const char *CListWrapper::GetItemName(int index)
+{
+ return (*m_getItemName)(m_client, index);
+}
+
+bool CListWrapper::SetItem(int index, PyObject *item)
+{
+ return (*m_setItem)(m_client, index, item);
+}
+
+bool CListWrapper::AllowSetItem()
+{
+ return m_setItem != NULL;
+}
+
+bool CListWrapper::AllowGetItemByName()
+{
+ return m_getItemName != NULL;
+}
+
+// ================================================================
+
+const STR_String &CListWrapper::GetText()
+{
+ return pythonGeneratorList;
+}
+
+void CListWrapper::SetName(const char *name)
+{
+}
+
+STR_String &CListWrapper::GetName()
+{
+ return pythonGeneratorList;
+}
+
+CValue *CListWrapper::GetReplica()
+{
+ return NULL;
+}
+
+CValue *CListWrapper::Calc(VALUE_OPERATOR op, CValue *val)
+{
+ return NULL;
+}
+
+CValue *CListWrapper::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val)
+{
+ return NULL;
+}
+
+double CListWrapper::GetNumber()
+{
+ return -1;
+}
+
+int CListWrapper::GetValueType()
+{
+ return -1;
+}
+
+// We convert all elements to python objects to make a proper repr string.
+PyObject *CListWrapper::py_repr()
+{
+ if (!CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "CListWrapper : repr, " BGE_PROXY_ERROR_MSG);
+ return NULL;
+ }
+
+ PyObject *py_proxy = GetProxy();
+ PyObject *py_list = PySequence_List(py_proxy);
+ PyObject *py_string = PyObject_Repr(py_list);
+ Py_DECREF(py_list);
+ Py_DECREF(py_proxy);
+ return py_string;
+}
+
+
+Py_ssize_t CListWrapper::py_len(PyObject *self)
+{
+ CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+ // Invalid list.
+ if (!list->CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "len(CListWrapper), " BGE_PROXY_ERROR_MSG);
+ return 0;
+ }
+
+ return (Py_ssize_t)list->GetSize();
+}
+
+PyObject *CListWrapper::py_get_item(PyObject *self, Py_ssize_t index)
+{
+ CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+ // Invalid list.
+ if (!list->CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG);
+ return NULL;
+ }
+
+ int size = list->GetSize();
+
+ if (index < 0) {
+ index = size + index;
+ }
+ if (index < 0 || index >= size) {
+ PyErr_SetString(PyExc_IndexError, "CListWrapper[i]: List index out of range in CListWrapper");
+ return NULL;
+ }
+
+ PyObject *pyobj = list->GetItem(index);
+
+ return pyobj;
+}
+
+int CListWrapper::py_set_item(PyObject *self, Py_ssize_t index, PyObject *value)
+{
+ CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+ // Invalid list.
+ if (!list->CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "CListWrapper[i] = val, " BGE_PROXY_ERROR_MSG);
+ return -1;
+ }
+
+ if (!list->AllowSetItem()) {
+ PyErr_SetString(PyExc_TypeError, "CListWrapper's item type doesn't support assignment");
+ return -1;
+ }
+
+ if (!value) {
+ PyErr_SetString(PyExc_TypeError, "CListWrapper doesn't support item deletion");
+ return -1;
+ }
+
+ int size = list->GetSize();
+
+ if (index < 0) {
+ index = size + index;
+ }
+ if (index < 0 || index >= size) {
+ PyErr_SetString(PyExc_IndexError, "CListWrapper[i]: List index out of range in CListWrapper");
+ return -1;
+ }
+
+ if (!list->SetItem(index, value)) {
+ return -1;
+ }
+ return 0;
+}
+
+PyObject *CListWrapper::py_mapping_subscript(PyObject *self, PyObject *key)
+{
+ CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+ // Invalid list.
+ if (!list->CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "val = CListWrapper[key], " BGE_PROXY_ERROR_MSG);
+ return NULL;
+ }
+
+ if (PyIndex_Check(key)) {
+ Py_ssize_t index = PyLong_AsSsize_t(key);
+ return py_get_item(self, index);
+ }
+ else if (PyUnicode_Check(key)) {
+ if (!list->AllowGetItemByName()) {
+ PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+ return NULL;
+ }
+
+ const char *name = _PyUnicode_AsString(key);
+ int size = list->GetSize();
+
+ for (unsigned int i = 0; i < size; ++i) {
+ if (strcmp(list->GetItemName(i), name) == 0) {
+ return list->GetItem(i);
+ }
+ }
+
+ PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name);
+ return NULL;
+ }
+
+ PyErr_Format(PyExc_KeyError, "CListWrapper[key]: '%R' key not in list", key);
+ return NULL;
+}
+
+int CListWrapper::py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
+{
+ CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+ // Invalid list.
+ if (!list->CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "val = CListWrapper[key], " BGE_PROXY_ERROR_MSG);
+ return -1;
+ }
+
+ if (!list->AllowSetItem()) {
+ PyErr_SetString(PyExc_TypeError, "CListWrapper's item type doesn't support assignment");
+ return -1;
+ }
+
+ if (PyIndex_Check(key)) {
+ Py_ssize_t index = PyLong_AsSsize_t(key);
+ return py_set_item(self, index, value);
+ }
+ else if (PyUnicode_Check(key)) {
+ if (!list->AllowGetItemByName()) {
+ PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+ return -1;
+ }
+
+ const char *name = _PyUnicode_AsString(key);
+ int size = list->GetSize();
+
+ for (unsigned int i = 0; i < size; ++i) {
+ if (strcmp(list->GetItemName(i), name) == 0) {
+ if (!list->SetItem(i, value)) {
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name);
+ return -1;
+ }
+
+ PyErr_Format(PyExc_KeyError, "CListWrapper[key]: '%R' key not in list", key);
+ return -1;
+}
+
+int CListWrapper::py_contains(PyObject *self, PyObject *key)
+{
+ CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self);
+ // Invalid list.
+ if (!list->CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG);
+ return -1;
+ }
+
+ if (!list->AllowGetItemByName()) {
+ PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+ return -1;
+ }
+
+ if (!PyUnicode_Check(key)) {
+ PyErr_SetString(PyExc_SystemError, "key in list, CListWrapper: key must be a string");
+ return -1;
+ }
+
+ const char *name = _PyUnicode_AsString(key);
+ int size = list->GetSize();
+
+ for (unsigned int i = 0; i < size; ++i) {
+ if (strcmp(list->GetItemName(i), name) == 0) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+PySequenceMethods CListWrapper::py_as_sequence = {
+ py_len, // sq_length
+ NULL, // sq_concat
+ NULL, // sq_repeat
+ py_get_item, // sq_item
+ NULL, // sq_slice
+ py_set_item, // sq_ass_item
+ NULL, // sq_ass_slice
+ (objobjproc)py_contains, // sq_contains
+ (binaryfunc) NULL, // sq_inplace_concat
+ (ssizeargfunc) NULL, // sq_inplace_repeat
+};
+
+PyMappingMethods CListWrapper::py_as_mapping = {
+ py_len, // mp_length
+ py_mapping_subscript, // mp_subscript
+ py_mapping_ass_subscript // mp_ass_subscript
+};
+
+PyTypeObject CListWrapper::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CListWrapper", // tp_name
+ sizeof(PyObjectPlus_Proxy), // tp_basicsize
+ 0, // tp_itemsize
+ py_base_dealloc, // tp_dealloc
+ 0, // tp_print
+ 0, // tp_getattr
+ 0, // tp_setattr
+ 0, // tp_compare
+ py_base_repr, // tp_repr
+ 0, // tp_as_number
+ &py_as_sequence, // tp_as_sequence
+ &py_as_mapping, // tp_as_mapping
+ 0, // tp_hash
+ 0, // tp_call
+ 0,
+ NULL,
+ NULL,
+ 0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyMethodDef CListWrapper::Methods[] = {
+ {"get", (PyCFunction)CListWrapper::sPyGet, METH_VARARGS},
+ {NULL, NULL} //Sentinel
+};
+
+PyAttributeDef CListWrapper::Attributes[] = {
+ {NULL} //Sentinel
+};
+
+/* Matches python dict.get(key, [default]) */
+PyObject *CListWrapper::PyGet(PyObject *args)
+{
+ char *name;
+ PyObject *def = Py_None;
+
+ // Invalid list.
+ if (!CheckValid()) {
+ PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG);
+ return NULL;
+ }
+
+ if (!AllowGetItemByName()) {
+ PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key");
+ return NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "s|O:get", &name, &def)) {
+ return NULL;
+ }
+
+ for (unsigned int i = 0; i < GetSize(); ++i) {
+ if (strcmp(GetItemName(i), name) == 0) {
+ return GetItem(i);
+ }
+ }
+
+ Py_INCREF(def);
+ return def;
+}
+
+#endif // WITH_PYTHON
diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
index b03570e3c28..1a66b2aee52 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
+++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
@@ -29,10 +29,6 @@
* \ingroup gamelogic
*/
-#ifdef WITH_SDL
-# include <SDL.h>
-#endif
-
#include <stdio.h>
#include <stdlib.h>
diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h
index dd9fbefa545..c9221753d45 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h
+++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.h
@@ -34,7 +34,18 @@
#include "SCA_JoystickDefines.h"
#ifdef WITH_SDL
+/* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings
+ * because we pass those defines via command line as well. For until there's
+ * proper ifndef added to SDL headers we ignore the redefinition warning.
+ */
+# ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4005)
+# endif
# include "SDL.h"
+# ifdef _MSC_VER
+# pragma warning(pop)
+# endif
#endif
/**
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
index 0033c137eb6..fd3d713b3d2 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp
@@ -29,10 +29,6 @@
* \ingroup gamelogic
*/
-#ifdef WITH_SDL
-# include <SDL.h>
-#endif
-
#include "SCA_Joystick.h"
#include "SCA_JoystickPrivate.h"
diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.h b/source/gameengine/GameLogic/SCA_DelaySensor.h
index b516cd8360e..9b39de7e099 100644
--- a/source/gameengine/GameLogic/SCA_DelaySensor.h
+++ b/source/gameengine/GameLogic/SCA_DelaySensor.h
@@ -61,8 +61,6 @@ public:
/* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */
/* --------------------------------------------------------------------- */
-
-
};
#endif /* __SCA_DELAYSENSOR_H__ */
diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h
index 8c22fb39c80..b63cb633b4e 100644
--- a/source/gameengine/GameLogic/SCA_IActuator.h
+++ b/source/gameengine/GameLogic/SCA_IActuator.h
@@ -156,7 +156,7 @@ public:
void ClrLink() { m_links=0; }
void IncLink() { m_links++; }
- void DecLink();
+ virtual void DecLink();
bool IsNoLink() const { return !m_links; }
bool IsType(KX_ACTUATOR_TYPE type) { return m_type == type; }
diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp
index 2bb04fe7be0..c4176d66688 100644
--- a/source/gameengine/GameLogic/SCA_IController.cpp
+++ b/source/gameengine/GameLogic/SCA_IController.cpp
@@ -37,7 +37,7 @@
#include "SCA_IActuator.h"
#include "SCA_ISensor.h"
#include "EXP_PyObjectPlus.h"
-#include "../Ketsji/KX_PythonSeq.h" /* not nice, only need for KX_PythonSeq_CreatePyObject */
+#include "EXP_ListWrapper.h"
#include <stdio.h>
@@ -244,13 +244,55 @@ PyObject *SCA_IController::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_D
return PyLong_FromLong(self->m_statemask);
}
+static int sca_icontroller_get_sensors_size_cb(void *self_v)
+{
+ return ((SCA_IController *)self_v)->GetLinkedSensors().size();
+}
+
+static PyObject *sca_icontroller_get_sensors_item_cb(void *self_v, int index)
+{
+ return ((SCA_IController *)self_v)->GetLinkedSensors()[index]->GetProxy();
+}
+
+static const char *sca_icontroller_get_sensors_item_name_cb(void *self_v, int index)
+{
+ return ((SCA_IController *)self_v)->GetLinkedSensors()[index]->GetName().ReadPtr();
+}
+
PyObject *SCA_IController::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return KX_PythonSeq_CreatePyObject((static_cast<SCA_IController*>(self_v))->m_proxy, KX_PYGENSEQ_CONT_TYPE_SENSORS);
+ return (new CListWrapper(self_v,
+ ((SCA_IController *)self_v)->GetProxy(),
+ NULL,
+ sca_icontroller_get_sensors_size_cb,
+ sca_icontroller_get_sensors_item_cb,
+ sca_icontroller_get_sensors_item_name_cb,
+ NULL))->NewProxy(true);
+}
+
+static int sca_icontroller_get_actuators_size_cb(void *self_v)
+{
+ return ((SCA_IController *)self_v)->GetLinkedActuators().size();
+}
+
+static PyObject *sca_icontroller_get_actuators_item_cb(void *self_v, int index)
+{
+ return ((SCA_IController *)self_v)->GetLinkedActuators()[index]->GetProxy();
+}
+
+static const char *sca_icontroller_get_actuators_item_name_cb(void *self_v, int index)
+{
+ return ((SCA_IController *)self_v)->GetLinkedActuators()[index]->GetName().ReadPtr();
}
PyObject *SCA_IController::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return KX_PythonSeq_CreatePyObject((static_cast<SCA_IController*>(self_v))->m_proxy, KX_PYGENSEQ_CONT_TYPE_ACTUATORS);
+ return (new CListWrapper(self_v,
+ ((SCA_IController *)self_v)->GetProxy(),
+ NULL,
+ sca_icontroller_get_actuators_size_cb,
+ sca_icontroller_get_actuators_item_cb,
+ sca_icontroller_get_actuators_item_name_cb,
+ NULL))->NewProxy(true);
}
#endif // WITH_PYTHON
diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
index 72a0b392447..d0a6e4540c9 100644
--- a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
+++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
@@ -35,12 +35,11 @@
#include "SCA_ILogicBrick.h"
#include "EXP_PyObjectPlus.h"
-SCA_LogicManager* SCA_ILogicBrick::m_sCurrentLogicManager = NULL;
-
SCA_ILogicBrick::SCA_ILogicBrick(SCA_IObject* gameobj)
:
CValue(),
m_gameobj(gameobj),
+ m_logicManager(NULL),
m_Execute_Priority(0),
m_Execute_Ueber_Priority(0),
m_bActive(false),
@@ -143,6 +142,16 @@ bool SCA_ILogicBrick::LessComparedTo(SCA_ILogicBrick* other)
(this->m_Execute_Priority < other->m_Execute_Priority));
}
+void SCA_ILogicBrick::SetLogicManager(SCA_LogicManager *logicmgr)
+{
+ m_logicManager = logicmgr;
+}
+
+SCA_LogicManager *SCA_ILogicBrick::GetLogicManager()
+{
+ return m_logicManager;
+}
+
void SCA_ILogicBrick::RegisterEvent(CValue* eventval)
{
if (m_eventval)
diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h
index a3725789227..f9ef18cc348 100644
--- a/source/gameengine/GameLogic/SCA_ILogicBrick.h
+++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h
@@ -40,12 +40,14 @@
class NG_NetworkScene;
class SCA_IScene;
+class SCA_LogicManager;
class SCA_ILogicBrick : public CValue
{
Py_Header
protected:
SCA_IObject* m_gameobj;
+ SCA_LogicManager *m_logicManager;
int m_Execute_Priority;
int m_Execute_Ueber_Priority;
@@ -127,9 +129,8 @@ public:
virtual bool LessComparedTo(SCA_ILogicBrick* other);
- /* runtime variable, set when Triggering the python controller */
- static class SCA_LogicManager* m_sCurrentLogicManager;
-
+ virtual void SetLogicManager(SCA_LogicManager *logicmgr);
+ SCA_LogicManager *GetLogicManager();
/* for moving logic bricks between scenes */
virtual void Replace_IScene(SCA_IScene *val) {}
diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp
index fa30e3a5caf..25936b34fde 100644
--- a/source/gameengine/GameLogic/SCA_PythonController.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonController.cpp
@@ -386,8 +386,7 @@ bool SCA_PythonController::Import()
void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr)
{
m_sCurrentController = this;
- m_sCurrentLogicManager = logicmgr;
-
+
PyObject *excdict= NULL;
PyObject *resultobj= NULL;
@@ -478,7 +477,7 @@ PyObject *SCA_PythonController::PyActivate(PyObject *value)
if (actu==NULL)
return NULL;
- m_sCurrentLogicManager->AddActiveActuator((SCA_IActuator*)actu, true);
+ m_logicManager->AddActiveActuator((SCA_IActuator*)actu, true);
Py_RETURN_NONE;
}
@@ -493,7 +492,7 @@ PyObject *SCA_PythonController::PyDeActivate(PyObject *value)
if (actu==NULL)
return NULL;
- m_sCurrentLogicManager->AddActiveActuator((SCA_IActuator*)actu, false);
+ m_logicManager->AddActiveActuator((SCA_IActuator*)actu, false);
Py_RETURN_NONE;
}
diff --git a/source/gameengine/GameLogic/SConscript b/source/gameengine/GameLogic/SConscript
deleted file mode 100644
index 0ecd08d3495..00000000000
--- a/source/gameengine/GameLogic/SConscript
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp') + env.Glob('Joystick/*.cpp')
-
-incs = [
- '.',
- '#intern/container',
- '#intern/ghost',
- '#/intern/string',
- '#/intern/moto/include',
- '#/source/blender/blenlib',
- '#/source/gameengine/Expressions',
- '#/source/gameengine/Rasterizer',
- '#/source/gameengine/SceneGraph',
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['WITH_BF_SDL']:
- defs.append('WITH_SDL')
- incs += ' ' + env['BF_SDL_INC']
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
- if env['BF_DEBUG']:
- defs.append('_DEBUG')
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
- incs += ' #/intern/guardedalloc'
-
-env.BlenderLib ( 'ge_logic', sources, Split(incs), defs, libtype=['core','player'], priority=[330,65], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/GamePlayer/SConscript b/source/gameengine/GamePlayer/SConscript
deleted file mode 100644
index d1930aca26d..00000000000
--- a/source/gameengine/GamePlayer/SConscript
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-SConscript(['common/SConscript',
- 'ghost/SConscript'])
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
index 52c4d13c638..2b355407d46 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
@@ -30,31 +30,14 @@
*/
-#ifndef NOPNG
-#ifdef WIN32
-#include "png.h"
-#else
-#include <png.h>
-#endif
-#endif // NOPNG
-
#include "RAS_IPolygonMaterial.h"
#include "GPC_Canvas.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
-#include "BKE_global.h"
-#include "BKE_main.h"
#include "BKE_image.h"
-
-extern "C" {
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-}
+#include "MEM_guardedalloc.h"
GPC_Canvas::GPC_Canvas(
@@ -164,37 +147,22 @@ MakeScreenShot(
const char* filename
) {
// copy image data
- unsigned char *pixels = new unsigned char[GetWidth() * GetHeight() * 4];
+ unsigned int dumpsx = GetWidth();
+ unsigned int dumpsy = GetHeight();
+ unsigned int *pixels = (unsigned int *)MEM_mallocN(sizeof(int) * dumpsx * dumpsy, "pixels");
if (!pixels) {
std::cout << "Cannot allocate pixels array" << std::endl;
return;
}
- glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ glReadPixels(0, 0, dumpsx, dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// initialize image file format data
- ImageFormatData im_format;
- BKE_imformat_defaults(&im_format);
-
- // create file path
- char path[FILE_MAX];
- BLI_strncpy(path, filename, sizeof(path));
- BLI_path_abs(path, G.main->name);
- BLI_path_frame(path, m_frame, 0);
- m_frame++;
- BKE_image_path_ensure_ext_from_imtype(path, im_format.imtype);
-
- // create and save imbuf
- ImBuf *ibuf = IMB_allocImBuf(GetWidth(), GetHeight(), 24, 0);
- ibuf->rect = (unsigned int*)pixels;
-
- BKE_imbuf_write_as(ibuf, path, &im_format, false);
-
- ibuf->rect = NULL;
- IMB_freeImBuf(ibuf);
+ ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format");
+ BKE_imformat_defaults(im_format);
- // clean up
- delete [] (pixels);
+ /* save_screenshot() frees dumprect and im_format */
+ save_screenshot(filename, dumpsx, dumpsy, pixels, im_format);
}
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
index 34cc9759a08..9a108203ee8 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.h
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -56,8 +56,6 @@ protected:
/** Rect that defines the area used for rendering,
* relative to the context */
RAS_Rect m_displayarea;
- /** Frame counter for screenshots */
- int m_frame;
int m_viewport[4];
diff --git a/source/gameengine/GamePlayer/common/SConscript b/source/gameengine/GamePlayer/common/SConscript
deleted file mode 100644
index dc105491c98..00000000000
--- a/source/gameengine/GamePlayer/common/SConscript
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-Import ('env')
-
-
-source_files = [
- 'GPC_Canvas.cpp',
- 'GPC_KeyboardDevice.cpp',
- 'GPC_MouseDevice.cpp',
- ]
-
-incs = [
- '.',
- '#intern/string',
- '#intern/ghost',
- '#intern/guardedalloc',
- '#intern/moto/include',
- '#intern/container',
- '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
- '#source/gameengine/Converter',
- '#source/gameengine/BlenderRoutines',
- '#source/blender/imbuf',
- '#source/gameengine/Ketsji',
- '#source/blender/blenlib',
- '#source/blender/blenfont',
- '#source/blender/blenkernel',
- '#source/blender',
- '#source/blender/include',
- '#source/blender/makesdna',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Expressions',
- '#source/gameengine/Network',
- '#source/gameengine/SceneGraph',
- '#source/gameengine/Physics/common',
- '#source/gameengine/Network/LoopBackNetwork',
- '#source/gameengine/GamePlayer/ghost',
- '#source/blender/misc',
- '#source/blender/blenloader',
- '#source/blender/gpu',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- incs.extend(Split(env['BF_PYTHON_INC']))
- defs.append('WITH_PYTHON')
-
-incs.extend(Split(env['BF_PNG_INC']))
-incs.extend(Split(env['BF_ZLIB_INC']))
-
-env.BlenderLib (libname='ge_player_common', sources=source_files, includes=incs, defines = defs, libtype=['player'], priority=[5], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index 2b357f43031..f0a7bd47ca3 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -78,7 +78,6 @@ extern "C"
#include "RAS_MeshObject.h"
#include "RAS_OpenGLRasterizer.h"
#include "RAS_ListRasterizer.h"
-#include "RAS_GLExtensionManager.h"
#include "KX_PythonInit.h"
#include "KX_PyConstraintBinding.h"
#include "BL_Material.h" // MAXTEX
@@ -563,7 +562,6 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
if (!m_engineInitialized)
{
GPU_init();
- bgl::InitExtensions(true);
// get and set the preferences
SYS_SystemHandle syshandle = SYS_GetSystem();
@@ -607,12 +605,20 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
if (gm->flag & GAME_SHOW_MOUSE)
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
+ RAS_STORAGE_TYPE raster_storage = RAS_AUTO_STORAGE;
+
+ if (gm->raster_storage == RAS_STORE_VBO) {
+ raster_storage = RAS_VBO;
+ }
+ else if (gm->raster_storage == RAS_STORE_VA) {
+ raster_storage = RAS_VA;
+ }
//Don't use displaylists with VBOs
//If auto starts using VBOs, make sure to check for that here
- if (useLists && gm->raster_storage != RAS_STORE_VBO)
- m_rasterizer = new RAS_ListRasterizer(m_canvas, false, gm->raster_storage);
+ if (useLists && raster_storage != RAS_VBO)
+ m_rasterizer = new RAS_ListRasterizer(m_canvas, true, raster_storage);
else
- m_rasterizer = new RAS_OpenGLRasterizer(m_canvas, gm->raster_storage);
+ m_rasterizer = new RAS_OpenGLRasterizer(m_canvas, raster_storage);
/* Stereo parameters - Eye Separation from the UI - stereomode from the command-line/UI */
m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
diff --git a/source/gameengine/GamePlayer/ghost/GPG_System.cpp b/source/gameengine/GamePlayer/ghost/GPG_System.cpp
index 6710572d843..669ab0532d9 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_System.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_System.cpp
@@ -46,7 +46,7 @@ double GPG_System::GetTimeInSeconds()
{
GHOST_TInt64 millis = (GHOST_TInt64)m_system->getMilliSeconds();
double time = (double)millis;
- time /= 1000.0f;
+ time /= 1000.0;
return time;
}
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index 23d5b89f140..eee53b775a9 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -457,7 +457,6 @@ int main(int argc, char** argv)
initglobals();
- U.gameflags |= USER_DISABLE_VBO;
// We load our own G.main, so free the one that initglobals() gives us
BKE_main_free(G.main);
G.main = NULL;
@@ -855,7 +854,7 @@ int main(int argc, char** argv)
get_filename(argc_py_clamped, argv, filename);
if (filename[0])
- BLI_path_cwd(filename);
+ BLI_path_cwd(filename, sizeof(filename));
// fill the GlobalSettings with the first scene files
diff --git a/source/gameengine/GamePlayer/ghost/SConscript b/source/gameengine/GamePlayer/ghost/SConscript
deleted file mode 100644
index be9f50f40fb..00000000000
--- a/source/gameengine/GamePlayer/ghost/SConscript
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-Import ('env')
-
-source_files = [
- 'GPG_Application.cpp',
- 'GPG_Canvas.cpp',
- 'GPG_ghost.cpp',
- 'GPG_KeyboardDevice.cpp',
- 'GPG_System.cpp',
- ]
-
-incs = [
- '.',
- '#intern/string',
- '#intern/ghost',
- '#intern/guardedalloc',
- '#intern/memutil',
- '#intern/moto/include',
- '#intern/container',
- '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
- '#source/gameengine/BlenderRoutines',
- '#source/gameengine/Converter',
- '#source/blender/imbuf',
- '#source/gameengine/Ketsji',
- '#source/blender/blenfont',
- '#source/blender/blenlib',
- '#source/blender/blenkernel',
- '#source/blender/blentranslation',
- '#source/blender',
- '#source/blender/include',
- '#source/blender/makesdna',
- '#source/blender/makesrna',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Expressions',
- '#source/gameengine/Network',
- '#source/gameengine/SceneGraph',
- '#source/gameengine/Physics/common',
- '#source/gameengine/Network/LoopBackNetwork',
- '#source/gameengine/GamePlayer/common',
- '#source/blender/misc',
- '#source/blender/blenloader',
- '#source/blender/gpu',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- ]
-
-incs.append(env['BF_PTHREADS_INC'])
-incs.append(env['BF_BOOST_INC'])
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- incs += Split(env['BF_PYTHON_INC'])
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs.append(env['BF_AUDASPACE_C_INC'])
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
-
-if env['WITH_BF_INTERNATIONAL']:
- defs.append('WITH_INTERNATIONAL')
-
-if env['WITH_BF_SDL'] and env['WITH_BF_SDL_DYNLOAD']:
- defs.append('WITH_SDL_DYNLOAD')
- incs += ['#extern/sdlew/include']
-
-env.BlenderLib (libname='ge_player_ghost', sources=source_files, includes = incs, defines = defs, libtype=['player'],priority=[0], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
index 12a1caee221..45946f30827 100644
--- a/source/gameengine/Ketsji/BL_Action.cpp
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -56,6 +56,15 @@ extern "C" {
#include "BKE_library.h"
#include "BKE_global.h"
+#include "BLI_threads.h" // for lock
+
+/* Lock to solve animation thread issues.
+ * A spin lock is better than a mutex in case of short wait
+ * because spin lock stop the thread by a loop contrary to mutex
+ * which switch all memory, process.
+ */
+static SpinLock BL_ActionLock;
+
BL_Action::BL_Action(class KX_GameObject* gameobj)
:
m_action(NULL),
@@ -65,8 +74,7 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
m_obj(gameobj),
m_startframe(0.f),
m_endframe(0.f),
- m_endtime(0.f),
- m_localtime(0.f),
+ m_localframe(0.f),
m_blendin(0.f),
m_blendframe(0.f),
m_blendstart(0.f),
@@ -76,7 +84,8 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
m_blendmode(ACT_BLEND_BLEND),
m_ipo_flags(0),
m_done(true),
- m_calc_localtime(true)
+ m_calc_localtime(true),
+ m_initializedTime(false)
{
}
@@ -252,27 +261,22 @@ bool BL_Action::Play(const char* name,
// Now that we have an action, we have something we can play
m_starttime = -1.f; // We get the start time on our first update
- m_startframe = m_localtime = start;
+ m_startframe = m_localframe = start;
m_endframe = end;
m_blendin = blendin;
m_playmode = play_mode;
m_blendmode = blend_mode;
- m_endtime = 0.f;
m_blendframe = 0.f;
m_blendstart = 0.f;
m_speed = playback_speed;
m_layer_weight = layer_weight;
m_done = false;
+ m_initializedTime = false;
return true;
}
-void BL_Action::Stop()
-{
- m_done = true;
-}
-
bool BL_Action::IsDone()
{
return m_done;
@@ -298,7 +302,7 @@ bAction *BL_Action::GetAction()
float BL_Action::GetFrame()
{
- return m_localtime;
+ return m_localframe;
}
const char *BL_Action::GetName()
@@ -321,7 +325,7 @@ void BL_Action::SetFrame(float frame)
else if (frame > max(m_startframe, m_endframe))
frame = max(m_startframe, m_endframe);
- m_localtime = frame;
+ m_localframe = frame;
m_calc_localtime = false;
}
@@ -338,19 +342,19 @@ void BL_Action::SetTimes(float start, float end)
void BL_Action::SetLocalTime(float curtime)
{
- float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate()*m_speed;
+ float dt = (curtime-m_starttime)*(float)KX_KetsjiEngine::GetAnimFrameRate()*m_speed;
if (m_endframe < m_startframe)
dt = -dt;
- m_localtime = m_startframe + dt;
+ m_localframe = m_startframe + dt;
}
void BL_Action::ResetStartTime(float curtime)
{
- float dt = (m_localtime > m_startframe) ? m_localtime - m_startframe : m_startframe - m_localtime;
+ float dt = (m_localframe > m_startframe) ? m_localframe - m_startframe : m_startframe - m_localframe;
- m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
+ m_starttime = curtime - dt / ((float)KX_KetsjiEngine::GetAnimFrameRate()*m_speed);
SetLocalTime(curtime);
}
@@ -361,7 +365,7 @@ void BL_Action::IncrementBlending(float curtime)
m_blendstart = curtime;
// Bump the blend frame
- m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
+ m_blendframe = (curtime - m_blendstart)*(float)KX_KetsjiEngine::GetAnimFrameRate();
// Clamp
if (m_blendframe>m_blendin)
@@ -394,12 +398,14 @@ void BL_Action::Update(float curtime)
if (m_done)
return;
- curtime -= KX_KetsjiEngine::GetSuspendedDelta();
+ curtime -= (float)KX_KetsjiEngine::GetSuspendedDelta();
- // Grab the start time here so we don't end up with a negative m_localtime when
+ // Grab the start time here so we don't end up with a negative m_localframe when
// suspending and resuming scenes.
- if (m_starttime < 0)
+ if (!m_initializedTime) {
m_starttime = curtime;
+ m_initializedTime = true;
+ }
if (m_calc_localtime)
SetLocalTime(curtime);
@@ -410,16 +416,16 @@ void BL_Action::Update(float curtime)
}
// Handle wrap around
- if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) {
+ if (m_localframe < min(m_startframe, m_endframe) || m_localframe > max(m_startframe, m_endframe)) {
switch (m_playmode) {
case ACT_MODE_PLAY:
// Clamp
- m_localtime = m_endframe;
+ m_localframe = m_endframe;
m_done = true;
break;
case ACT_MODE_LOOP:
// Put the time back to the beginning
- m_localtime = m_startframe;
+ m_localframe = m_startframe;
m_starttime = curtime;
break;
case ACT_MODE_PING_PONG:
@@ -442,7 +448,7 @@ void BL_Action::Update(float curtime)
obj->GetPose(&m_blendpose);
// Extract the pose from the action
- obj->SetPoseByAction(m_tmpaction, m_localtime);
+ obj->SetPoseByAction(m_tmpaction, m_localframe);
// Handle blending between armature actions
if (m_blendin && m_blendframe<m_blendin)
@@ -476,7 +482,7 @@ void BL_Action::Update(float curtime)
PointerRNA ptrrna;
RNA_id_pointer_create(&key->id, &ptrrna);
- animsys_evaluate_action(&ptrrna, m_tmpaction, NULL, m_localtime);
+ animsys_evaluate_action(&ptrrna, m_tmpaction, NULL, m_localframe);
// Handle blending between shape actions
if (m_blendin && m_blendframe < m_blendin)
@@ -506,15 +512,23 @@ void BL_Action::Update(float curtime)
}
}
- // This isn't thread-safe, so we move it into it's own function for now
- //m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
+ BLI_spin_lock(&BL_ActionLock);
+ /* This function is not thread safe because of recursive scene graph transform
+ * updates on children. e.g: If an object and one of its children is animated,
+ * the both can write transform at the same time. A thread lock avoid problems. */
+ m_obj->UpdateIPO(m_localframe, m_ipo_flags & ACT_IPOFLAG_CHILD);
+ BLI_spin_unlock(&BL_ActionLock);
if (m_done)
ClearControllerList();
}
-void BL_Action::UpdateIPOs()
+void BL_Action::InitLock()
+{
+ BLI_spin_init(&BL_ActionLock);
+}
+
+void BL_Action::EndLock()
{
- if (!m_done)
- m_obj->UpdateIPO(m_localtime, m_ipo_flags & ACT_IPOFLAG_CHILD);
+ BLI_spin_end(&BL_ActionLock);
}
diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h
index 379dd52df5b..f4c2975a547 100644
--- a/source/gameengine/Ketsji/BL_Action.h
+++ b/source/gameengine/Ketsji/BL_Action.h
@@ -48,9 +48,9 @@ private:
float m_startframe;
float m_endframe;
+ /// The current action frame.
+ float m_localframe;
float m_starttime;
- float m_endtime;
- float m_localtime;
float m_blendin;
float m_blendframe;
@@ -69,6 +69,8 @@ private:
bool m_done;
bool m_calc_localtime;
+ /// Set to true when m_starttime is initialized in Update.
+ bool m_initializedTime;
void ClearControllerList();
void InitIPO();
@@ -94,10 +96,6 @@ public:
float playback_speed,
short blend_mode);
/**
- * Stop playing the action
- */
- void Stop();
- /**
* Whether or not the action is still playing
*/
bool IsDone();
@@ -105,10 +103,6 @@ public:
* Update the action's frame, etc.
*/
void Update(float curtime);
- /**
- * Update object IPOs (note: not thread-safe!)
- */
- void UpdateIPOs();
// Accessors
float GetFrame();
@@ -144,6 +138,11 @@ public:
ACT_IPOFLAG_CHILD = 8,
};
+ /// Initialize a lock for animation thread issues.
+ static void InitLock();
+ /// Finalize a lock for animation thread issues.
+ static void EndLock();
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Action")
#endif
diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp
index 9e4690548d3..35f605f1a5f 100644
--- a/source/gameengine/Ketsji/BL_ActionManager.cpp
+++ b/source/gameengine/Ketsji/BL_ActionManager.cpp
@@ -28,7 +28,7 @@
#include "BL_ActionManager.h"
#include "DNA_ID.h"
-#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT))
+#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
BL_ActionManager::BL_ActionManager(class KX_GameObject *obj):
m_obj(obj),
@@ -53,14 +53,6 @@ BL_Action *BL_ActionManager::GetAction(short layer)
return (it != m_layers.end()) ? it->second : 0;
}
-BL_Action* BL_ActionManager::AddAction(short layer)
-{
- BL_Action *action = new BL_Action(m_obj);
- m_layers[layer] = action;
-
- return action;
-}
-
float BL_ActionManager::GetActionFrame(short layer)
{
BL_Action *action = GetAction(layer);
@@ -116,8 +108,10 @@ bool BL_ActionManager::PlayAction(const char* name,
{
// Only this method will create layer if non-existent
BL_Action *action = GetAction(layer);
- if (!action)
- action = AddAction(layer);
+ if (!action) {
+ action = new BL_Action(m_obj);
+ m_layers[layer] = action;
+ }
// Disable layer blending on the first layer
if (layer == 0) layer_weight = -1.f;
@@ -129,7 +123,10 @@ void BL_ActionManager::StopAction(short layer)
{
BL_Action *action = GetAction(layer);
- if (action) action->Stop();
+ if (action) {
+ m_layers.erase(layer);
+ delete action;
+ }
}
void BL_ActionManager::RemoveTaggedActions()
@@ -158,25 +155,10 @@ void BL_ActionManager::Update(float curtime)
m_prevUpdate = curtime;
BL_ActionMap::iterator it;
- for (it = m_layers.begin(); it != m_layers.end(); )
+ for (it = m_layers.begin(); it != m_layers.end(); ++it)
{
- if (it->second->IsDone()) {
- delete it->second;
- m_layers.erase(it++);
- }
- else {
+ if (!it->second->IsDone()) {
it->second->Update(curtime);
- ++it;
}
}
}
-
-void BL_ActionManager::UpdateIPOs()
-{
- BL_ActionMap::iterator it;
- for (it = m_layers.begin(); it != m_layers.end(); ++it)
- {
- if (!it->second->IsDone())
- it->second->UpdateIPOs();
- }
-}
diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h
index 97d6d88cf22..69c6d611df0 100644
--- a/source/gameengine/Ketsji/BL_ActionManager.h
+++ b/source/gameengine/Ketsji/BL_ActionManager.h
@@ -59,11 +59,6 @@ private:
*/
BL_Action* GetAction(short layer);
- /**
- * Add new action with given layer
- */
- BL_Action* AddAction(short layer);
-
public:
BL_ActionManager(class KX_GameObject* obj);
~BL_ActionManager();
@@ -129,11 +124,6 @@ public:
*/
void Update(float);
- /**
- * Update object IPOs (note: not thread-safe!)
- */
- void UpdateIPOs();
-
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ActionManager")
#endif
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
index b5151615f3b..95679b5d3a6 100644
--- a/source/gameengine/Ketsji/BL_BlenderShader.cpp
+++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp
@@ -35,8 +35,8 @@
#include "BL_BlenderShader.h"
#include "BL_Material.h"
-#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "GPU_shader.h"
#include "RAS_BucketManager.h"
#include "RAS_MeshObject.h"
@@ -74,8 +74,8 @@ void BL_BlenderShader::SetProg(bool enable, double time, RAS_IRasterizer* rasty)
float viewmat[4][4], viewinvmat[4][4];
const MT_Matrix4x4& view = rasty->GetViewMatrix();
const MT_Matrix4x4& viewinv = rasty->GetViewInvMatrix();
- view.getValue((float*)viewmat);
- viewinv.getValue((float*)viewinvmat);
+ view.getValue(&viewmat[0][0]);
+ viewinv.getValue(&viewinvmat[0][0]);
GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat, NULL, false);
}
@@ -148,7 +148,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat)
void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
{
- float obmat[4][4], obcol[4];
+ float obmat[4][4], viewmat[4][4], obcol[4];
GPUMaterial *gpumat;
gpumat = mGPUMat;
@@ -160,15 +160,16 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
model.setValue(ms.m_OpenGLMatrix);
// note: getValue gives back column major as needed by OpenGL
- model.getValue((float*)obmat);
+ model.getValue(&obmat[0][0]);
if (ms.m_bObjectColor)
- ms.m_RGBAcolor.getValue((float *)obcol);
+ ms.m_RGBAcolor.getValue(&obcol[0]);
else
obcol[0] = obcol[1] = obcol[2] = obcol[3] = 1.0f;
+ rasty->GetViewMatrix().getValue(&viewmat[0][0]);
float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f;
- GPU_material_bind_uniforms(gpumat, obmat, obcol, auto_bump_scale, NULL);
+ GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL);
mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol);
}
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index a59c3686a18..6613780a0f8 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -34,18 +34,18 @@
#include "KX_PyMath.h"
#include "MEM_guardedalloc.h"
-#include "RAS_GLExtensionManager.h"
#include "RAS_MeshObject.h"
#include "RAS_IRasterizer.h"
#define spit(x) std::cout << x << std::endl;
#define SORT_UNIFORMS 1
-#define UNIFORM_MAX_LEN (int)sizeof(float)*16
+#define UNIFORM_MAX_LEN (int)sizeof(float) * 16
#define MAX_LOG_LEN 262144 // bounds
BL_Uniform::BL_Uniform(int data_size)
-: mLoc(-1),
+ :
+ mLoc(-1),
mDirty(true),
mType(UNI_NONE),
mTranspose(0),
@@ -53,7 +53,7 @@ BL_Uniform::BL_Uniform(int data_size)
{
#ifdef SORT_UNIFORMS
MT_assert((int)mDataLen <= UNIFORM_MAX_LEN);
- mData = (void*)MEM_mallocN(mDataLen, "shader-uniform-alloc");
+ mData = (void *)MEM_mallocN(mDataLen, "shader-uniform-alloc");
#endif
}
@@ -62,7 +62,7 @@ BL_Uniform::~BL_Uniform()
#ifdef SORT_UNIFORMS
if (mData) {
MEM_freeN(mData);
- mData=0;
+ mData = NULL;
}
#endif
}
@@ -72,68 +72,69 @@ void BL_Uniform::Apply(class BL_Shader *shader)
#ifdef SORT_UNIFORMS
MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData);
- if (!mDirty)
+ if (!mDirty) {
return;
+ }
switch (mType) {
case UNI_FLOAT:
{
- float *f = (float*)mData;
- glUniform1fARB(mLoc,(GLfloat)*f);
+ float *f = (float *)mData;
+ glUniform1fARB(mLoc, (GLfloat)*f);
break;
}
case UNI_INT:
{
- int *f = (int*)mData;
+ int *f = (int *)mData;
glUniform1iARB(mLoc, (GLint)*f);
break;
}
case UNI_FLOAT2:
{
- float *f = (float*)mData;
- glUniform2fvARB(mLoc,1, (GLfloat*)f);
+ float *f = (float *)mData;
+ glUniform2fvARB(mLoc, 1, (GLfloat *)f);
break;
}
case UNI_FLOAT3:
{
- float *f = (float*)mData;
- glUniform3fvARB(mLoc,1,(GLfloat*)f);
+ float *f = (float *)mData;
+ glUniform3fvARB(mLoc, 1, (GLfloat *)f);
break;
}
case UNI_FLOAT4:
{
- float *f = (float*)mData;
- glUniform4fvARB(mLoc,1,(GLfloat*)f);
+ float *f = (float *)mData;
+ glUniform4fvARB(mLoc, 1, (GLfloat *)f);
break;
}
case UNI_INT2:
{
- int *f = (int*)mData;
- glUniform2ivARB(mLoc,1,(GLint*)f);
+ int *f = (int *)mData;
+ glUniform2ivARB(mLoc, 1, (GLint *)f);
break;
}
case UNI_INT3:
{
- int *f = (int*)mData;
- glUniform3ivARB(mLoc,1,(GLint*)f);
+ int *f = (int *)mData;
+ glUniform3ivARB(mLoc, 1, (GLint *)f);
break;
}
case UNI_INT4:
{
- int *f = (int*)mData;
- glUniform4ivARB(mLoc,1,(GLint*)f);
+ int *f = (int *)mData;
+ glUniform4ivARB(mLoc, 1, (GLint *)f);
break;
}
case UNI_MAT4:
{
- float *f = (float*)mData;
- glUniformMatrix4fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
+ float *f = (float *)mData;
+ glUniformMatrix4fvARB(mLoc, 1, mTranspose ? GL_TRUE : GL_FALSE, (GLfloat *)f);
break;
}
case UNI_MAT3:
{
- float *f = (float*)mData;
- glUniformMatrix3fvARB(mLoc, 1, mTranspose?GL_TRUE:GL_FALSE,(GLfloat*)f);
+ float *f = (float *)mData;
+ glUniformMatrix3fvARB(mLoc, 1, mTranspose ? GL_TRUE : GL_FALSE, (GLfloat *)f);
break;
}
}
@@ -141,29 +142,30 @@ void BL_Uniform::Apply(class BL_Shader *shader)
#endif
}
-void BL_Uniform::SetData(int location, int type,bool transpose)
+void BL_Uniform::SetData(int location, int type, bool transpose)
{
#ifdef SORT_UNIFORMS
- mType = type;
- mLoc = location;
- mDirty = true;
+ mType = type;
+ mLoc = location;
+ mDirty = true;
#endif
}
bool BL_Shader::Ok()const
{
- return (mShader !=0 && mOk && mUse);
+ return (mShader != 0 && mOk && mUse);
}
BL_Shader::BL_Shader()
-: PyObjectPlus(),
+ :
+ PyObjectPlus(),
mShader(0),
mPass(1),
mOk(0),
mUse(0),
mAttr(0),
- vertProg(""),
- fragProg(""),
+ vertProg(NULL),
+ fragProg(NULL),
mError(0),
mDirty(true)
{
@@ -183,13 +185,14 @@ BL_Shader::~BL_Shader()
//}
ClearUniforms();
- if ( mShader ) {
+ if (mShader) {
glDeleteObjectARB(mShader);
mShader = 0;
}
- vertProg = 0;
- fragProg = 0;
- mOk = 0;
+
+ vertProg = NULL;
+ fragProg = NULL;
+ mOk = 0;
glUseProgramObjectARB(0);
}
@@ -197,39 +200,38 @@ void BL_Shader::ClearUniforms()
{
BL_UniformVec::iterator it = mUniforms.begin();
while (it != mUniforms.end()) {
- delete (*it);
+ delete *it;
it++;
}
mUniforms.clear();
-
BL_UniformVecDef::iterator itp = mPreDef.begin();
while (itp != mPreDef.end()) {
- delete (*itp);
+ delete *itp;
itp++;
}
mPreDef.clear();
-
}
-
-BL_Uniform *BL_Shader::FindUniform(const int location)
+BL_Uniform *BL_Shader::FindUniform(const int location)
{
#ifdef SORT_UNIFORMS
BL_UniformVec::iterator it = mUniforms.begin();
while (it != mUniforms.end()) {
- if ((*it)->GetLocation() == location)
- return (*it);
+ if ((*it)->GetLocation() == location) {
+ return *it;
+ }
it++;
}
#endif
- return 0;
+ return NULL;
}
-void BL_Shader::SetUniformfv(int location, int type, float *param,int size, bool transpose)
+void BL_Shader::SetUniformfv(int location, int type, float *param, int size, bool transpose)
{
#ifdef SORT_UNIFORMS
- BL_Uniform *uni= FindUniform(location);
+ BL_Uniform *uni = FindUniform(location);
+
if (uni) {
memcpy(uni->getData(), param, size);
uni->SetData(location, type, transpose);
@@ -237,18 +239,19 @@ void BL_Shader::SetUniformfv(int location, int type, float *param,int size, bool
else {
uni = new BL_Uniform(size);
memcpy(uni->getData(), param, size);
-
uni->SetData(location, type, transpose);
mUniforms.push_back(uni);
}
+
mDirty = true;
#endif
}
-void BL_Shader::SetUniformiv(int location, int type, int *param,int size, bool transpose)
+void BL_Shader::SetUniformiv(int location, int type, int *param, int size, bool transpose)
{
#ifdef SORT_UNIFORMS
- BL_Uniform *uni= FindUniform(location);
+ BL_Uniform *uni = FindUniform(location);
+
if (uni) {
memcpy(uni->getData(), param, size);
uni->SetData(location, type, transpose);
@@ -259,19 +262,21 @@ void BL_Shader::SetUniformiv(int location, int type, int *param,int size, bool t
uni->SetData(location, type, transpose);
mUniforms.push_back(uni);
}
+
mDirty = true;
#endif
}
-
void BL_Shader::ApplyShader()
{
#ifdef SORT_UNIFORMS
- if (!mDirty)
+ if (!mDirty) {
return;
+ }
- for (unsigned int i=0; i<mUniforms.size(); i++)
+ for (unsigned int i = 0; i < mUniforms.size(); i++) {
mUniforms[i]->Apply(this);
+ }
mDirty = false;
#endif
@@ -282,50 +287,55 @@ void BL_Shader::UnloadShader()
//
}
-
bool BL_Shader::LinkProgram()
{
- int vertlen = 0, fraglen=0, proglen=0;
- int vertstatus=0, fragstatus=0, progstatus=0;
- unsigned int tmpVert=0, tmpFrag=0, tmpProg=0;
- int char_len=0;
- char *logInf =0;
+ int vertlen = 0, fraglen = 0, proglen = 0;
+ int vertstatus = 0, fragstatus = 0, progstatus = 0;
+ unsigned int tmpVert = 0, tmpFrag = 0, tmpProg = 0;
+ int char_len = 0;
+ char *logInf = NULL;
- if (mError)
+ if (mError) {
goto programError;
+ }
if (!vertProg || !fragProg) {
spit("Invalid GLSL sources");
return false;
}
- if ( !GLEW_ARB_fragment_shader) {
+
+ if (!GLEW_ARB_fragment_shader) {
spit("Fragment shaders not supported");
return false;
}
- if ( !GLEW_ARB_vertex_shader) {
+
+ if (!GLEW_ARB_vertex_shader) {
spit("Vertex shaders not supported");
return false;
}
-
+
// -- vertex shader ------------------
tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
- glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0);
+ glShaderSourceARB(tmpVert, 1, (const char **)&vertProg, 0);
glCompileShaderARB(tmpVert);
- glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB,(GLint*) &vertlen);
-
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&vertlen);
+
// print info if any
- if ( vertlen > 0 && vertlen < MAX_LOG_LEN) {
- logInf = (char*)MEM_mallocN(vertlen, "vert-log");
- glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf);
- if (char_len >0) {
+ if (vertlen > 0 && vertlen < MAX_LOG_LEN) {
+ logInf = (char *)MEM_mallocN(vertlen, "vert-log");
+ glGetInfoLogARB(tmpVert, vertlen, (GLsizei *)&char_len, logInf);
+
+ if (char_len > 0) {
spit("---- Vertex Shader Error ----");
spit(logInf);
}
+
MEM_freeN(logInf);
- logInf=0;
+ logInf = 0;
}
+
// check for compile errors
- glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB,(GLint*)&vertstatus);
+ glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&vertstatus);
if (!vertstatus) {
spit("---- Vertex shader failed to compile ----");
goto programError;
@@ -333,46 +343,50 @@ bool BL_Shader::LinkProgram()
// -- fragment shader ----------------
tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
- glShaderSourceARB(tmpFrag, 1,(const char**)&fragProg, 0);
+ glShaderSourceARB(tmpFrag, 1, (const char **)&fragProg, 0);
glCompileShaderARB(tmpFrag);
- glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &fraglen);
- if (fraglen >0 && fraglen < MAX_LOG_LEN) {
- logInf = (char*)MEM_mallocN(fraglen, "frag-log");
- glGetInfoLogARB(tmpFrag, fraglen,(GLsizei*) &char_len, logInf);
- if (char_len >0) {
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&fraglen);
+
+ if (fraglen > 0 && fraglen < MAX_LOG_LEN) {
+ logInf = (char *)MEM_mallocN(fraglen, "frag-log");
+ glGetInfoLogARB(tmpFrag, fraglen, (GLsizei *)&char_len, logInf);
+
+ if (char_len > 0) {
spit("---- Fragment Shader Error ----");
spit(logInf);
}
+
MEM_freeN(logInf);
- logInf=0;
+ logInf = 0;
}
- glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*) &fragstatus);
+ glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint *)&fragstatus);
+
if (!fragstatus) {
spit("---- Fragment shader failed to compile ----");
goto programError;
}
-
// -- program ------------------------
- // set compiled vert/frag shader & link
+ // set compiled vert/frag shader & link
tmpProg = glCreateProgramObjectARB();
glAttachObjectARB(tmpProg, tmpVert);
glAttachObjectARB(tmpProg, tmpFrag);
glLinkProgramARB(tmpProg);
- glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*) &proglen);
- glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &progstatus);
-
+ glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&proglen);
+ glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint *)&progstatus);
if (proglen > 0 && proglen < MAX_LOG_LEN) {
- logInf = (char*)MEM_mallocN(proglen, "prog-log");
- glGetInfoLogARB(tmpProg, proglen, (GLsizei*)&char_len, logInf);
- if (char_len >0) {
+ logInf = (char *)MEM_mallocN(proglen, "prog-log");
+ glGetInfoLogARB(tmpProg, proglen, (GLsizei *)&char_len, logInf);
+
+ if (char_len > 0) {
spit("---- GLSL Program ----");
spit(logInf);
}
+
MEM_freeN(logInf);
- logInf=0;
+ logInf = 0;
}
if (!progstatus) {
@@ -384,57 +398,58 @@ bool BL_Shader::LinkProgram()
mShader = tmpProg;
glDeleteObjectARB(tmpVert);
glDeleteObjectARB(tmpFrag);
- mOk = 1;
+ mOk = 1;
mError = 0;
return true;
programError:
if (tmpVert) {
glDeleteObjectARB(tmpVert);
- tmpVert=0;
+ tmpVert = 0;
}
+
if (tmpFrag) {
glDeleteObjectARB(tmpFrag);
- tmpFrag=0;
+ tmpFrag = 0;
}
if (tmpProg) {
glDeleteObjectARB(tmpProg);
- tmpProg=0;
+ tmpProg = 0;
}
- mOk = 0;
- mUse = 0;
- mError = 1;
+ mOk = 0;
+ mUse = 0;
+ mError = 1;
return false;
}
const char *BL_Shader::GetVertPtr()
{
- return vertProg?vertProg:0;
+ return vertProg ? vertProg : NULL;
}
const char *BL_Shader::GetFragPtr()
{
- return fragProg?fragProg:0;
+ return fragProg ? fragProg : NULL;
}
-void BL_Shader::SetVertPtr( char *vert )
+void BL_Shader::SetVertPtr(char *vert)
{
vertProg = vert;
}
-void BL_Shader::SetFragPtr( char *frag )
+void BL_Shader::SetFragPtr(char *frag)
{
fragProg = frag;
}
unsigned int BL_Shader::GetProg()
-{
+{
return mShader;
}
-//
-//const BL_Sampler* BL_Shader::GetSampler(int i)
+
+//const BL_Sampler *BL_Shader::GetSampler(int i)
//{
// MT_assert(i<=MAXTEX);
// return &mSampler[i];
@@ -442,31 +457,23 @@ unsigned int BL_Shader::GetProg()
void BL_Shader::SetSampler(int loc, int unit)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
glUniform1iARB(loc, unit);
}
}
-//
-//void BL_Shader::InitializeSampler(int unit, BL_Texture* texture)
+
+//void BL_Shader::InitializeSampler(int unit, BL_Texture *texture)
//{
-// MT_assert(unit<=MAXTEX);
+// MT_assert(unit <= MAXTEX);
// mSampler[unit].mTexture = texture;
-// mSampler[unit].mLoc =-1;
+// mSampler[unit].mLoc = -1;
// mSampler[unit].mOwn = 0;
//}
void BL_Shader::SetProg(bool enable)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
- if ( mShader != 0 && mOk && enable) {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
+ if (mShader != 0 && mOk && enable) {
glUseProgramObjectARB(mShader);
}
else {
@@ -475,114 +482,112 @@ void BL_Shader::SetProg(bool enable)
}
}
-void BL_Shader::Update( const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
+void BL_Shader::Update(const RAS_MeshSlot &ms, RAS_IRasterizer *rasty)
{
- if (!Ok() || !mPreDef.size())
+ if (!Ok() || !mPreDef.size()) {
return;
+ }
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
MT_Matrix4x4 model;
model.setValue(ms.m_OpenGLMatrix);
- const MT_Matrix4x4& view = rasty->GetViewMatrix();
+ const MT_Matrix4x4 &view = rasty->GetViewMatrix();
- if (mAttr==SHD_TANGENT)
+ if (mAttr == SHD_TANGENT) {
ms.m_mesh->SetMeshModified(true);
+ }
BL_UniformVecDef::iterator it;
- for (it = mPreDef.begin(); it!= mPreDef.end(); it++)
- {
+ for (it = mPreDef.begin(); it != mPreDef.end(); it++) {
BL_DefUniform *uni = (*it);
- if (uni->mLoc == -1) continue;
- switch (uni->mType)
- {
+ if (uni->mLoc == -1) {
+ continue;
+ }
+
+ switch (uni->mType) {
case MODELMATRIX:
- {
- SetUniform(uni->mLoc, model);
- break;
- }
+ {
+ SetUniform(uni->mLoc, model);
+ break;
+ }
case MODELMATRIX_TRANSPOSE:
- {
- SetUniform(uni->mLoc, model, true);
- break;
- }
+ {
+ SetUniform(uni->mLoc, model, true);
+ break;
+ }
case MODELMATRIX_INVERSE:
- {
- model.invert();
- SetUniform(uni->mLoc, model);
- break;
- }
+ {
+ model.invert();
+ SetUniform(uni->mLoc, model);
+ break;
+ }
case MODELMATRIX_INVERSETRANSPOSE:
- {
- model.invert();
- SetUniform(uni->mLoc, model, true);
- break;
- }
+ {
+ model.invert();
+ SetUniform(uni->mLoc, model, true);
+ break;
+ }
case MODELVIEWMATRIX:
- {
- SetUniform(uni->mLoc, view*model);
- break;
- }
-
+ {
+ SetUniform(uni->mLoc, view * model);
+ break;
+ }
case MODELVIEWMATRIX_TRANSPOSE:
- {
- MT_Matrix4x4 mat(view*model);
- SetUniform(uni->mLoc, mat, true);
- break;
- }
+ {
+ MT_Matrix4x4 mat(view * model);
+ SetUniform(uni->mLoc, mat, true);
+ break;
+ }
case MODELVIEWMATRIX_INVERSE:
- {
- MT_Matrix4x4 mat(view*model);
- mat.invert();
- SetUniform(uni->mLoc, mat);
- break;
- }
+ {
+ MT_Matrix4x4 mat(view * model);
+ mat.invert();
+ SetUniform(uni->mLoc, mat);
+ break;
+ }
case MODELVIEWMATRIX_INVERSETRANSPOSE:
- {
- MT_Matrix4x4 mat(view*model);
- mat.invert();
- SetUniform(uni->mLoc, mat, true);
- break;
- }
+ {
+ MT_Matrix4x4 mat(view * model);
+ mat.invert();
+ SetUniform(uni->mLoc, mat, true);
+ break;
+ }
case CAM_POS:
- {
- MT_Point3 pos(rasty->GetCameraPosition());
- SetUniform(uni->mLoc, pos);
- break;
- }
+ {
+ MT_Point3 pos(rasty->GetCameraPosition());
+ SetUniform(uni->mLoc, pos);
+ break;
+ }
case VIEWMATRIX:
- {
- SetUniform(uni->mLoc, view);
- break;
- }
+ {
+ SetUniform(uni->mLoc, view);
+ break;
+ }
case VIEWMATRIX_TRANSPOSE:
- {
- SetUniform(uni->mLoc, view, true);
- break;
- }
+ {
+ SetUniform(uni->mLoc, view, true);
+ break;
+ }
case VIEWMATRIX_INVERSE:
- {
- MT_Matrix4x4 viewinv = view;
- viewinv.invert();
- SetUniform(uni->mLoc, view);
- break;
- }
+ {
+ MT_Matrix4x4 viewinv = view;
+ viewinv.invert();
+ SetUniform(uni->mLoc, view);
+ break;
+ }
case VIEWMATRIX_INVERSETRANSPOSE:
- {
- MT_Matrix4x4 viewinv = view;
- viewinv.invert();
- SetUniform(uni->mLoc, view, true);
- break;
- }
+ {
+ MT_Matrix4x4 viewinv = view;
+ viewinv.invert();
+ SetUniform(uni->mLoc, view, true);
+ break;
+ }
case CONSTANT_TIMER:
- {
- SetUniform(uni->mLoc, (float)rasty->GetTime());
- break;
- }
+ {
+ SetUniform(uni->mLoc, (float)rasty->GetTime());
+ break;
+ }
default:
break;
}
@@ -590,13 +595,9 @@ void BL_Shader::Update( const RAS_MeshSlot & ms, RAS_IRasterizer* rasty )
}
}
-
int BL_Shader::GetAttribLocation(const char *name)
{
- if (GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects)
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
return glGetAttribLocationARB(mShader, name);
}
@@ -605,205 +606,168 @@ int BL_Shader::GetAttribLocation(const char *name)
void BL_Shader::BindAttribute(const char *attr, int loc)
{
- if (GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
glBindAttribLocationARB(mShader, loc, attr);
}
}
int BL_Shader::GetUniformLocation(const char *name)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
- MT_assert(mShader!=0);
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
+ MT_assert(mShader != 0);
int location = glGetUniformLocationARB(mShader, name);
- if (location == -1)
+
+ if (location == -1) {
spit("Invalid uniform value: " << name << ".");
+ }
+
return location;
}
-
return -1;
}
-void BL_Shader::SetUniform(int uniform, const MT_Tuple2& vec)
+void BL_Shader::SetUniform(int uniform, const MT_Tuple2 &vec)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
float value[2];
vec.getValue(value);
glUniform2fvARB(uniform, 1, value);
}
-
}
-void BL_Shader::SetUniform(int uniform, const MT_Tuple3& vec)
+void BL_Shader::SetUniform(int uniform, const MT_Tuple3 &vec)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
float value[3];
vec.getValue(value);
glUniform3fvARB(uniform, 1, value);
}
}
-void BL_Shader::SetUniform(int uniform, const MT_Tuple4& vec)
+void BL_Shader::SetUniform(int uniform, const MT_Tuple4 &vec)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
float value[4];
vec.getValue(value);
glUniform4fvARB(uniform, 1, value);
}
}
-void BL_Shader::SetUniform(int uniform, const unsigned int& val)
+void BL_Shader::SetUniform(int uniform, const unsigned int &val)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
glUniform1iARB(uniform, val);
}
}
void BL_Shader::SetUniform(int uniform, const int val)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
glUniform1iARB(uniform, val);
}
}
-void BL_Shader::SetUniform(int uniform, const float& val)
+void BL_Shader::SetUniform(int uniform, const float &val)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
glUniform1fARB(uniform, val);
}
}
-void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose)
+void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4 &vec, bool transpose)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
float value[16];
// note: getValue gives back column major as needed by OpenGL
vec.getValue(value);
- glUniformMatrix4fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
+ glUniformMatrix4fvARB(uniform, 1, transpose ? GL_TRUE : GL_FALSE, value);
}
}
-void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose)
+void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3 &vec, bool transpose)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
float value[9];
- value[0] = (float)vec[0][0]; value[1] = (float)vec[1][0]; value[2] = (float)vec[2][0];
- value[3] = (float)vec[0][1]; value[4] = (float)vec[1][1]; value[5] = (float)vec[2][1];
- value[6] = (float)vec[0][2]; value[7] = (float)vec[1][2]; value[8] = (float)vec[2][2];
- glUniformMatrix3fvARB(uniform, 1, transpose?GL_TRUE:GL_FALSE, value);
+ value[0] = (float)vec[0][0];
+ value[1] = (float)vec[1][0];
+ value[2] = (float)vec[2][0];
+ value[3] = (float)vec[0][1];
+ value[4] = (float)vec[1][1];
+ value[5] = (float)vec[2][1];
+ value[6] = (float)vec[0][2];
+ value[7] = (float)vec[1][2];
+ value[8] = (float)vec[2][2];
+ glUniformMatrix3fvARB(uniform, 1, transpose ? GL_TRUE : GL_FALSE, value);
}
}
-void BL_Shader::SetUniform(int uniform, const float* val, int len)
+void BL_Shader::SetUniform(int uniform, const float *val, int len)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
- if (len == 2)
- glUniform2fvARB(uniform, 1,(GLfloat*)val);
- else if (len == 3)
- glUniform3fvARB(uniform, 1,(GLfloat*)val);
- else if (len == 4)
- glUniform4fvARB(uniform, 1,(GLfloat*)val);
- else
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
+ if (len == 2) {
+ glUniform2fvARB(uniform, 1, (GLfloat *)val);
+ }
+ else if (len == 3) {
+ glUniform3fvARB(uniform, 1, (GLfloat *)val);
+ }
+ else if (len == 4) {
+ glUniform4fvARB(uniform, 1, (GLfloat *)val);
+ }
+ else {
MT_assert(0);
+ }
}
}
-void BL_Shader::SetUniform(int uniform, const int* val, int len)
+void BL_Shader::SetUniform(int uniform, const int *val, int len)
{
- if ( GLEW_ARB_fragment_shader &&
- GLEW_ARB_vertex_shader &&
- GLEW_ARB_shader_objects
- )
- {
- if (len == 2)
- glUniform2ivARB(uniform, 1, (GLint*)val);
- else if (len == 3)
- glUniform3ivARB(uniform, 1, (GLint*)val);
- else if (len == 4)
- glUniform4ivARB(uniform, 1, (GLint*)val);
- else
+ if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) {
+ if (len == 2) {
+ glUniform2ivARB(uniform, 1, (GLint *)val);
+ }
+ else if (len == 3) {
+ glUniform3ivARB(uniform, 1, (GLint *)val);
+ }
+ else if (len == 4) {
+ glUniform4ivARB(uniform, 1, (GLint *)val);
+ }
+ else {
MT_assert(0);
+ }
}
}
#ifdef WITH_PYTHON
-
-PyMethodDef BL_Shader::Methods[] =
-{
+PyMethodDef BL_Shader::Methods[] = {
// creation
- KX_PYMETHODTABLE( BL_Shader, setSource ),
- KX_PYMETHODTABLE( BL_Shader, delSource ),
- KX_PYMETHODTABLE( BL_Shader, getVertexProg ),
- KX_PYMETHODTABLE( BL_Shader, getFragmentProg ),
- KX_PYMETHODTABLE( BL_Shader, setNumberOfPasses ),
- KX_PYMETHODTABLE( BL_Shader, validate),
- /// access functions
- KX_PYMETHODTABLE( BL_Shader, isValid),
- KX_PYMETHODTABLE( BL_Shader, setUniform1f ),
- KX_PYMETHODTABLE( BL_Shader, setUniform2f ),
- KX_PYMETHODTABLE( BL_Shader, setUniform3f ),
- KX_PYMETHODTABLE( BL_Shader, setUniform4f ),
- KX_PYMETHODTABLE( BL_Shader, setUniform1i ),
- KX_PYMETHODTABLE( BL_Shader, setUniform2i ),
- KX_PYMETHODTABLE( BL_Shader, setUniform3i ),
- KX_PYMETHODTABLE( BL_Shader, setUniform4i ),
- KX_PYMETHODTABLE( BL_Shader, setAttrib ),
-
- KX_PYMETHODTABLE( BL_Shader, setUniformfv ),
- KX_PYMETHODTABLE( BL_Shader, setUniformiv ),
- KX_PYMETHODTABLE( BL_Shader, setUniformDef ),
-
- KX_PYMETHODTABLE( BL_Shader, setSampler ),
- KX_PYMETHODTABLE( BL_Shader, setUniformMatrix4 ),
- KX_PYMETHODTABLE( BL_Shader, setUniformMatrix3 ),
-
- {NULL,NULL} //Sentinel
+ KX_PYMETHODTABLE(BL_Shader, setSource),
+ KX_PYMETHODTABLE(BL_Shader, delSource),
+ KX_PYMETHODTABLE(BL_Shader, getVertexProg),
+ KX_PYMETHODTABLE(BL_Shader, getFragmentProg),
+ KX_PYMETHODTABLE(BL_Shader, setNumberOfPasses),
+ KX_PYMETHODTABLE(BL_Shader, validate),
+ // access functions
+ KX_PYMETHODTABLE(BL_Shader, isValid),
+ KX_PYMETHODTABLE(BL_Shader, setUniform1f),
+ KX_PYMETHODTABLE(BL_Shader, setUniform2f),
+ KX_PYMETHODTABLE(BL_Shader, setUniform3f),
+ KX_PYMETHODTABLE(BL_Shader, setUniform4f),
+ KX_PYMETHODTABLE(BL_Shader, setUniform1i),
+ KX_PYMETHODTABLE(BL_Shader, setUniform2i),
+ KX_PYMETHODTABLE(BL_Shader, setUniform3i),
+ KX_PYMETHODTABLE(BL_Shader, setUniform4i),
+ KX_PYMETHODTABLE(BL_Shader, setAttrib),
+ KX_PYMETHODTABLE(BL_Shader, setUniformfv),
+ KX_PYMETHODTABLE(BL_Shader, setUniformiv),
+ KX_PYMETHODTABLE(BL_Shader, setUniformDef),
+ KX_PYMETHODTABLE(BL_Shader, setSampler),
+ KX_PYMETHODTABLE(BL_Shader, setUniformMatrix4),
+ KX_PYMETHODTABLE(BL_Shader, setUniformMatrix3),
+ {NULL, NULL} //Sentinel
};
PyAttributeDef BL_Shader::Attributes[] = {
- { NULL } //Sentinel
+ {NULL} //Sentinel
};
PyTypeObject BL_Shader::Type = {
@@ -817,37 +781,39 @@ PyTypeObject BL_Shader::Type = {
0,
0,
py_base_repr,
- 0,0,0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- 0,0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0, 0,
Methods,
0,
0,
&PyObjectPlus::Type,
- 0,0,0,0,0,0,
+ 0, 0, 0, 0, 0, 0,
py_base_new
};
-KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProgram)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setSource, " setSource(vertexProgram, fragmentProgram)")
{
- if (mShader !=0 && mOk )
- {
+ if (mShader != 0 && mOk) {
// already set...
Py_RETURN_NONE;
}
- char *v,*f;
- int apply=0;
- if ( PyArg_ParseTuple(args, "ssi:setSource", &v, &f, &apply) )
- {
+
+ char *v, *f;
+ int apply = 0;
+
+ if (PyArg_ParseTuple(args, "ssi:setSource", &v, &f, &apply)) {
vertProg = v;
fragProg = f;
- if ( LinkProgram() ) {
- glUseProgramObjectARB( mShader );
- mUse = apply!=0;
+
+ if (LinkProgram()) {
+ glUseProgramObjectARB(mShader);
+ mUse = apply != 0;
Py_RETURN_NONE;
}
- vertProg = 0;
- fragProg = 0;
+
+ vertProg = NULL;
+ fragProg = NULL;
mUse = 0;
Py_RETURN_NONE;
}
@@ -855,80 +821,82 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSource," setSource(vertexProgram, fragmentProg
}
-KX_PYMETHODDEF_DOC( BL_Shader, delSource, "delSource( )" )
+KX_PYMETHODDEF_DOC(BL_Shader, delSource, "delSource( )")
{
ClearUniforms();
glUseProgramObjectARB(0);
-
glDeleteObjectARB(mShader);
- mShader = 0;
- mOk = 0;
- mUse = 0;
+ mShader = 0;
+ mOk = 0;
+ mUse = 0;
Py_RETURN_NONE;
}
-KX_PYMETHODDEF_DOC( BL_Shader, isValid, "isValid()" )
+KX_PYMETHODDEF_DOC(BL_Shader, isValid, "isValid()")
{
- return PyBool_FromLong(( mShader !=0 && mOk ));
+ return PyBool_FromLong((mShader != 0 && mOk));
}
-KX_PYMETHODDEF_DOC( BL_Shader, getVertexProg, "getVertexProg( )" )
+KX_PYMETHODDEF_DOC(BL_Shader, getVertexProg, "getVertexProg( )")
{
- return PyUnicode_FromString(vertProg?vertProg:"");
+ return PyUnicode_FromString(vertProg ? vertProg : "");
}
-KX_PYMETHODDEF_DOC( BL_Shader, getFragmentProg, "getFragmentProg( )" )
+KX_PYMETHODDEF_DOC(BL_Shader, getFragmentProg, "getFragmentProg( )")
{
- return PyUnicode_FromString(fragProg?fragProg:"");
+ return PyUnicode_FromString(fragProg ? fragProg : "");
}
-KX_PYMETHODDEF_DOC( BL_Shader, validate, "validate()")
+KX_PYMETHODDEF_DOC(BL_Shader, validate, "validate()")
{
if (mError) {
Py_RETURN_NONE;
}
- if (mShader==0) {
+
+ if (mShader == 0) {
PyErr_SetString(PyExc_TypeError, "shader.validate(): BL_Shader, invalid shader object");
return NULL;
}
+
int stat = 0;
glValidateProgramARB(mShader);
- glGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB,(GLint*) &stat);
-
+ glGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB, (GLint *)&stat);
if (stat > 0 && stat < MAX_LOG_LEN) {
- int char_len=0;
- char *logInf = (char*)MEM_mallocN(stat, "validate-log");
+ int char_len = 0;
+ char *logInf = (char *)MEM_mallocN(stat, "validate-log");
- glGetInfoLogARB(mShader, stat,(GLsizei*) &char_len, logInf);
- if (char_len >0) {
+ glGetInfoLogARB(mShader, stat, (GLsizei *)&char_len, logInf);
+
+ if (char_len > 0) {
spit("---- GLSL Validation ----");
spit(logInf);
}
MEM_freeN(logInf);
- logInf=0;
+ logInf = NULL;
}
Py_RETURN_NONE;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setSampler, "setSampler(name, index)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
- int index=-1;
- if (PyArg_ParseTuple(args, "si:setSampler", &uniform, &index))
- {
+ int index = -1;
+
+ if (PyArg_ParseTuple(args, "si:setSampler", &uniform, &index)) {
int loc = GetUniformLocation(uniform);
+
if (loc != -1) {
- if (index >= MAXTEX || index < 0)
+ if (index >= MAXTEX || index < 0) {
spit("Invalid texture sample index: " << index);
-
+ }
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT, &index, (sizeof(int)) );
+ SetUniformiv(loc, BL_Uniform::UNI_INT, &index, (sizeof(int)));
#else
SetUniform(loc, index);
#endif
@@ -942,34 +910,36 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" )
return NULL;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )" )
+KX_PYMETHODDEF_DOC(BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )")
{
int pass = 1;
- if (!PyArg_ParseTuple(args, "i:setNumberOfPasses", &pass))
+
+ if (!PyArg_ParseTuple(args, "i:setNumberOfPasses", &pass)) {
return NULL;
+ }
mPass = 1;
Py_RETURN_NONE;
}
/// access functions
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform1f, "setUniform1f(name, fx)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
- float value=0;
- if (PyArg_ParseTuple(args, "sf:setUniform1f", &uniform, &value ))
- {
+ float value = 0.0f;
+
+ if (PyArg_ParseTuple(args, "sf:setUniform1f", &uniform, &value)) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
SetUniformfv(loc, BL_Uniform::UNI_FLOAT, &value, sizeof(float));
#else
- SetUniform( loc, (float)value );
+ SetUniform(loc, (float)value);
#endif
}
Py_RETURN_NONE;
@@ -977,21 +947,21 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" )
return NULL;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform;
- float array[2] = {0, 0};
- if (PyArg_ParseTuple(args, "sff:setUniform2f", &uniform, &array[0],&array[1] ))
- {
+ float array[2] = {0.0f, 0.0f};
+
+ if (PyArg_ParseTuple(args, "sff:setUniform2f", &uniform, &array[0], &array[1])) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
- SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array, (sizeof(float)*2) );
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array, (sizeof(float) * 2));
#else
SetUniform(loc, array, 2);
#endif
@@ -1001,46 +971,45 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)")
return NULL;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform;
- float array[3] = {0, 0, 0};
- if (PyArg_ParseTuple(args, "sfff:setUniform3f", &uniform, &array[0],&array[1],&array[2]))
- {
+ float array[3] = {0.0f, 0.0f, 0.0f};
+
+ if (PyArg_ParseTuple(args, "sfff:setUniform3f", &uniform, &array[0], &array[1], &array[2])) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
- SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array, (sizeof(float)*3) );
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array, (sizeof(float) * 3));
#else
SetUniform(loc, array, 3);
#endif
}
Py_RETURN_NONE;
-
}
return NULL;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform;
- float array[4] = {0, 0, 0, 0};
- if (PyArg_ParseTuple(args, "sffff:setUniform4f", &uniform, &array[0],&array[1],&array[2], &array[3]))
- {
+ float array[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ if (PyArg_ParseTuple(args, "sffff:setUniform4f", &uniform, &array[0], &array[1], &array[2], &array[3])) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
- SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array, (sizeof(float)*4) );
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array, (sizeof(float) * 4));
#else
SetUniform(loc, array, 4);
#endif
@@ -1050,19 +1019,19 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) "
return NULL;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform;
- int value=0;
- if (PyArg_ParseTuple(args, "si:setUniform1i", &uniform, &value ))
- {
+ int value = 0;
+
+ if (PyArg_ParseTuple(args, "si:setUniform1i", &uniform, &value)) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
SetUniformiv(loc, BL_Uniform::UNI_INT, &value, sizeof(int));
#else
@@ -1074,21 +1043,21 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" )
return NULL;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform;
int array[2] = {0, 0};
- if (PyArg_ParseTuple(args, "sii:setUniform2i", &uniform, &array[0],&array[1] ))
- {
+
+ if (PyArg_ParseTuple(args, "sii:setUniform2i", &uniform, &array[0], &array[1])) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT2, array, sizeof(int)*2);
+ SetUniformiv(loc, BL_Uniform::UNI_INT2, array, sizeof(int) * 2);
#else
SetUniform(loc, array, 2);
#endif
@@ -1098,8 +1067,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)")
return NULL;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
{
if (mError) {
Py_RETURN_NONE;
@@ -1107,13 +1075,13 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
const char *uniform;
int array[3] = {0, 0, 0};
- if (PyArg_ParseTuple(args, "siii:setUniform3i", &uniform, &array[0],&array[1],&array[2]))
- {
+
+ if (PyArg_ParseTuple(args, "siii:setUniform3i", &uniform, &array[0], &array[1], &array[2])) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT3, array, sizeof(int)*3);
+ SetUniformiv(loc, BL_Uniform::UNI_INT3, array, sizeof(int) * 3);
#else
SetUniform(loc, array, 3);
#endif
@@ -1123,20 +1091,21 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ")
return NULL;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform;
int array[4] = {0, 0, 0, 0};
- if (PyArg_ParseTuple(args, "siiii:setUniform4i", &uniform, &array[0],&array[1],&array[2], &array[3] ))
- {
+
+ if (PyArg_ParseTuple(args, "siiii:setUniform4i", &uniform, &array[0], &array[1], &array[2], &array[3])) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT4, array, sizeof(int)*4);
+ SetUniformiv(loc, BL_Uniform::UNI_INT4, array, sizeof(int) * 4);
#else
SetUniform(loc, array, 4);
#endif
@@ -1146,68 +1115,69 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) "
return NULL;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv, "setUniformfv( float (list2 or list3 or list4) )")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 or list4))")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform = "";
- PyObject *listPtr =0;
- float array_data[4] = {0.f,0.f,0.f,0.f};
+ PyObject *listPtr = NULL;
+ float array_data[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- if (PyArg_ParseTuple(args, "sO:setUniformfv", &uniform, &listPtr))
- {
+ if (PyArg_ParseTuple(args, "sO:setUniformfv", &uniform, &listPtr)) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
- if (PySequence_Check(listPtr))
- {
+ if (loc != -1) {
+ if (PySequence_Check(listPtr)) {
unsigned int list_size = PySequence_Size(listPtr);
-
- for (unsigned int i=0; (i<list_size && i<4); i++)
- {
+
+ for (unsigned int i = 0; (i < list_size && i < 4); i++) {
PyObject *item = PySequence_GetItem(listPtr, i);
array_data[i] = (float)PyFloat_AsDouble(item);
Py_DECREF(item);
}
- switch (list_size)
- {
- case 2:
+ switch (list_size) {
+ case 2:
{
- float array2[2] = { array_data[0],array_data[1] };
+ float array2[2] = {array_data[0], array_data[1]};
#ifdef SORT_UNIFORMS
- SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array2, sizeof(float)*2);
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array2, sizeof(float) * 2);
#else
SetUniform(loc, array2, 2);
#endif
Py_RETURN_NONE;
- } break;
- case 3:
+ break;
+ }
+ case 3:
{
- float array3[3] = { array_data[0],array_data[1],array_data[2] };
+ float array3[3] = {array_data[0], array_data[1], array_data[2]};
#ifdef SORT_UNIFORMS
- SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array3, sizeof(float)*3);
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array3, sizeof(float) * 3);
#else
SetUniform(loc, array3, 3);
#endif
Py_RETURN_NONE;
- }break;
- case 4:
+ break;
+ }
+ case 4:
{
- float array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] };
+ float array4[4] = {array_data[0], array_data[1], array_data[2], array_data[3]};
#ifdef SORT_UNIFORMS
- SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array4, sizeof(float)*4);
+ SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array4, sizeof(float) * 4);
#else
SetUniform(loc, array4, 4);
#endif
Py_RETURN_NONE;
- }break;
- default:
+ break;
+ }
+ default:
{
- PyErr_SetString(PyExc_TypeError, "shader.setUniform4i(name, ix,iy,iz, iw): BL_Shader. invalid list size");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniform4i(name, ix,iy,iz, iw): BL_Shader. invalid list size");
return NULL;
- }break;
+ break;
+ }
}
}
}
@@ -1215,220 +1185,227 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformfv, "setUniformfv( float (list2 or list
return NULL;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setUniformiv, "setUniformiv( uniform_name, (list2 or list3 or list4) )")
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 or list3 or list4))")
{
if (mError) {
Py_RETURN_NONE;
}
+
const char *uniform = "";
- PyObject *listPtr =0;
- int array_data[4] = {0,0,0,0};
+ PyObject *listPtr = NULL;
+ int array_data[4] = {0, 0, 0, 0};
- if (!PyArg_ParseTuple(args, "sO:setUniformiv", &uniform, &listPtr))
+ if (!PyArg_ParseTuple(args, "sO:setUniformiv", &uniform, &listPtr)) {
return NULL;
-
+ }
+
int loc = GetUniformLocation(uniform);
-
+
if (loc == -1) {
- PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, first string argument is not a valid uniform value");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformiv(...): BL_Shader, first string argument is not a valid uniform value");
return NULL;
}
-
+
if (!PySequence_Check(listPtr)) {
PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument is not a sequence");
return NULL;
}
-
+
unsigned int list_size = PySequence_Size(listPtr);
-
- for (unsigned int i=0; (i<list_size && i<4); i++)
- {
+
+ for (unsigned int i = 0; (i < list_size && i < 4); i++) {
PyObject *item = PySequence_GetItem(listPtr, i);
array_data[i] = PyLong_AsLong(item);
Py_DECREF(item);
}
-
+
if (PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, one or more values in the list is not an int");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformiv(...): BL_Shader, one or more values in the list is not an int");
return NULL;
}
-
- /* Sanity checks done! */
-
- switch (list_size)
- {
- case 2:
+
+ // Sanity checks done!
+ switch (list_size) {
+ case 2:
{
- int array2[2] = { array_data[0],array_data[1]};
+ int array2[2] = {array_data[0], array_data[1]};
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int)*2);
+ SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int) * 2);
#else
SetUniform(loc, array2, 2);
#endif
Py_RETURN_NONE;
- } break;
- case 3:
+ break;
+ }
+ case 3:
{
- int array3[3] = { array_data[0],array_data[1],array_data[2] };
+ int array3[3] = {array_data[0], array_data[1], array_data[2]};
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int)*3);
-
+ SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int) * 3);
#else
SetUniform(loc, array3, 3);
#endif
Py_RETURN_NONE;
- }break;
- case 4:
+ break;
+ }
+ case 4:
{
- int array4[4] = { array_data[0],array_data[1],array_data[2],array_data[3] };
+ int array4[4] = {array_data[0], array_data[1], array_data[2], array_data[3]};
#ifdef SORT_UNIFORMS
- SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int)*4);
-
+ SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int) * 4);
#else
SetUniform(loc, array4, 4);
#endif
Py_RETURN_NONE;
- }break;
- default:
+ break;
+ }
+ default:
{
- PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument, invalid list size, expected an int list between 2 and 4");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformiv(...): BL_Shader, second argument, invalid list size, expected an int "
+ "list between 2 and 4");
return NULL;
- }break;
+ break;
+ }
}
-
Py_RETURN_NONE;
}
-
-KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4,
-"setUniformMatrix4(uniform_name, mat-4x4, transpose(row-major=true, col-major=false)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix4,
+ "setUniformMatrix4(uniform_name, mat-4x4, transpose(row-major=true, col-major=false)")
{
if (mError) {
Py_RETURN_NONE;
}
float matr[16] = {
- 1,0,0,0,
- 0,1,0,0,
- 0,0,1,0,
- 0,0,0,1
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
};
const char *uniform;
- PyObject *matrix=0;
- int transp=0; // python use column major by default, so no transpose....
-
- if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix4",&uniform, &matrix,&transp))
+ PyObject *matrix = NULL;
+ int transp = 0; // python use column major by default, so no transpose....
+
+ if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix4", &uniform, &matrix, &transp)) {
return NULL;
+ }
int loc = GetUniformLocation(uniform);
-
+
if (loc == -1) {
- PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix4(...): BL_Shader, first string argument is not a valid uniform value");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformMatrix4(...): BL_Shader, first string argument is not a valid uniform value");
return NULL;
}
-
+
MT_Matrix4x4 mat;
-
+
if (!PyMatTo(matrix, mat)) {
- PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix4(...): BL_Shader, second argument cannot be converted into a 4x4 matrix");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformMatrix4(...): BL_Shader, second argument cannot be converted into a 4x4 matrix");
return NULL;
}
-
- /* Sanity checks done! */
+ // Sanity checks done!
#ifdef SORT_UNIFORMS
mat.getValue(matr);
- SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float)*16), (transp!=0) );
+ SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float) * 16), (transp != 0));
#else
- SetUniform(loc,mat,(transp!=0));
+ SetUniform(loc, mat, (transp != 0));
#endif
Py_RETURN_NONE;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3,
-"setUniformMatrix3(uniform_name, list[3x3], transpose(row-major=true, col-major=false)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix3,
+ "setUniformMatrix3(uniform_name, list[3x3], transpose(row-major=true, col-major=false)")
{
if (mError) {
Py_RETURN_NONE;
}
float matr[9] = {
- 1,0,0,
- 0,1,0,
- 0,0,1,
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
};
const char *uniform;
- PyObject *matrix=0;
- int transp=0; // python use column major by default, so no transpose....
- if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix3",&uniform, &matrix,&transp))
+ PyObject *matrix = NULL;
+ int transp = 0; // python use column major by default, so no transpose....
+
+ if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix3", &uniform, &matrix, &transp)) {
return NULL;
-
+ }
+
int loc = GetUniformLocation(uniform);
-
+
if (loc == -1) {
- PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix3(...): BL_Shader, first string argument is not a valid uniform value");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformMatrix3(...): BL_Shader, first string argument is not a valid uniform value");
return NULL;
}
-
-
+
MT_Matrix3x3 mat;
-
+
if (!PyMatTo(matrix, mat)) {
- PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix3(...): BL_Shader, second argument cannot be converted into a 3x3 matrix");
+ PyErr_SetString(PyExc_TypeError,
+ "shader.setUniformMatrix3(...): BL_Shader, second argument cannot be converted into a 3x3 matrix");
return NULL;
}
-
#ifdef SORT_UNIFORMS
mat.getValue3x3(matr);
- SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float)*9), (transp!=0) );
+ SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float) * 9), (transp != 0));
#else
- SetUniform(loc,mat,(transp!=0));
+ SetUniform(loc, mat, (transp != 0));
#endif
Py_RETURN_NONE;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setAttrib, "setAttrib(enum)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setAttrib, "setAttrib(enum)")
{
if (mError) {
Py_RETURN_NONE;
}
-
- int attr=0;
-
- if (!PyArg_ParseTuple(args, "i:setAttrib", &attr))
+
+ int attr = 0;
+
+ if (!PyArg_ParseTuple(args, "i:setAttrib", &attr)) {
return NULL;
+ }
- attr= SHD_TANGENT; /* user input is ignored for now, there is only 1 attr */
+ attr = SHD_TANGENT; // user input is ignored for now, there is only 1 attr
- if (mShader==0) {
+ if (mShader == 0) {
PyErr_SetString(PyExc_ValueError, "shader.setAttrib() BL_Shader, invalid shader object");
return NULL;
}
- mAttr= attr;
+ mAttr = attr;
glUseProgramObjectARB(mShader);
glBindAttribLocationARB(mShader, mAttr, "Tangent");
Py_RETURN_NONE;
}
-KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" )
+KX_PYMETHODDEF_DOC(BL_Shader, setUniformDef, "setUniformDef(name, enum)")
{
if (mError) {
Py_RETURN_NONE;
}
const char *uniform;
- int nloc=0;
- if (PyArg_ParseTuple(args, "si:setUniformDef", &uniform, &nloc))
- {
+ int nloc = 0;
+ if (PyArg_ParseTuple(args, "si:setUniformDef", &uniform, &nloc)) {
int loc = GetUniformLocation(uniform);
- if (loc != -1)
- {
+
+ if (loc != -1) {
bool defined = false;
BL_UniformVecDef::iterator it = mPreDef.begin();
while (it != mPreDef.end()) {
@@ -1438,6 +1415,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" )
}
it++;
}
+
if (defined) {
Py_RETURN_NONE;
}
diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h
index e3dc4b19773..aef4b42a85a 100644
--- a/source/gameengine/Ketsji/BL_Shader.h
+++ b/source/gameengine/Ketsji/BL_Shader.h
@@ -9,7 +9,6 @@
#include "EXP_PyObjectPlus.h"
#include "BL_Material.h"
#include "BL_Texture.h"
-// --
#include "MT_Matrix4x4.h"
#include "MT_Matrix3x3.h"
#include "MT_Tuple2.h"
@@ -18,17 +17,19 @@
/**
* BL_Sampler
- * Sampler access
+ * Sampler access
*/
class BL_Sampler
{
public:
- BL_Sampler():
+ BL_Sampler()
+ :
mLoc(-1)
{
}
- int mLoc; // Sampler location
-
+
+ int mLoc; // Sampler location
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Sampler")
#endif
@@ -36,27 +37,23 @@ public:
/**
* BL_Uniform
- * uniform storage
+ * uniform storage
*/
-class BL_Uniform
+class BL_Uniform
{
private:
- int mLoc; // Uniform location
- void* mData; // Memory allocated for variable
- bool mDirty; // Caching variable
- int mType; // Enum UniformTypes
- bool mTranspose; // Transpose matrices
- const int mDataLen; // Length of our data
+ int mLoc; // Uniform location
+ void *mData; // Memory allocated for variable
+ bool mDirty; // Caching variable
+ int mType; // Enum UniformTypes
+ bool mTranspose; // Transpose matrices
+ const int mDataLen; // Length of our data
public:
BL_Uniform(int data_size);
~BL_Uniform();
-
-
- void Apply(class BL_Shader *shader);
- void SetData(int location, int type, bool transpose=false);
enum UniformTypes {
- UNI_NONE =0,
+ UNI_NONE = 0,
UNI_INT,
UNI_FLOAT,
UNI_INT2,
@@ -70,10 +67,11 @@ public:
UNI_MAX
};
- int GetLocation() { return mLoc; }
- void* getData() { return mData; }
-
-
+ void Apply(class BL_Shader *shader);
+ void SetData(int location, int type, bool transpose = false);
+ int GetLocation() { return mLoc; }
+ void *getData() { return mData; }
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Uniform")
#endif
@@ -81,22 +79,23 @@ public:
/**
* BL_DefUniform
- * pre defined uniform storage
+ * pre defined uniform storage
*/
class BL_DefUniform
{
public:
- BL_DefUniform() :
+ BL_DefUniform()
+ :
mType(0),
mLoc(0),
mFlag(0)
{
}
- int mType;
- int mLoc;
- unsigned int mFlag;
-
-
+
+ int mType;
+ int mLoc;
+ unsigned int mFlag;
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_DefUniform")
#endif
@@ -104,46 +103,46 @@ public:
/**
* BL_Shader
- * shader access
+ * shader access
*/
class BL_Shader : public PyObjectPlus
{
Py_Header
private:
- typedef std::vector<BL_Uniform*> BL_UniformVec;
- typedef std::vector<BL_DefUniform*> BL_UniformVecDef;
-
- unsigned int mShader; // Shader object
- int mPass; // 1.. unused
- bool mOk; // Valid and ok
- bool mUse; // ...
-//BL_Sampler mSampler[MAXTEX]; // Number of samplers
- int mAttr; // Tangent attribute
- const char* vertProg; // Vertex program string
- const char* fragProg; // Fragment program string
- bool mError; // ...
- bool mDirty; //
+ typedef std::vector<BL_Uniform *> BL_UniformVec;
+ typedef std::vector<BL_DefUniform *> BL_UniformVecDef;
+
+ unsigned int mShader; // Shader object
+ int mPass; // 1.. unused
+ bool mOk; // Valid and ok
+ bool mUse;
+ //BL_Sampler mSampler[MAXTEX]; // Number of samplers
+ int mAttr; // Tangent attribute
+ const char *vertProg; // Vertex program string
+ const char *fragProg; // Fragment program string
+ bool mError;
+ bool mDirty;
+
+ // Stored uniform variables
+ BL_UniformVec mUniforms;
+ BL_UniformVecDef mPreDef;
// Compiles and links the shader
bool LinkProgram();
- // Stored uniform variables
- BL_UniformVec mUniforms;
- BL_UniformVecDef mPreDef;
-
// search by location
- BL_Uniform* FindUniform(const int location);
+ BL_Uniform *FindUniform(const int location);
+
// clears uniform data
- void ClearUniforms();
+ void ClearUniforms();
public:
BL_Shader();
virtual ~BL_Shader();
- // Unused for now tangent is set as
- // tex coords
+ // Unused for now tangent is set as tex coords
enum AttribTypes {
- SHD_TANGENT =1
+ SHD_TANGENT = 1
};
enum GenType {
@@ -151,76 +150,63 @@ public:
MODELVIEWMATRIX_TRANSPOSE,
MODELVIEWMATRIX_INVERSE,
MODELVIEWMATRIX_INVERSETRANSPOSE,
-
- // Model matrix
MODELMATRIX,
MODELMATRIX_TRANSPOSE,
MODELMATRIX_INVERSE,
MODELMATRIX_INVERSETRANSPOSE,
-
- // View Matrix
VIEWMATRIX,
VIEWMATRIX_TRANSPOSE,
VIEWMATRIX_INVERSE,
VIEWMATRIX_INVERSETRANSPOSE,
-
- // Current camera position
CAM_POS,
-
- // RAS timer
CONSTANT_TIMER
};
- const char* GetVertPtr();
- const char* GetFragPtr();
- void SetVertPtr( char *vert );
- void SetFragPtr( char *frag );
-
- // ---
- int getNumPass() {return mPass;}
- bool GetError() {return mError;}
- // ---
- //const BL_Sampler* GetSampler(int i);
- void SetSampler(int loc, int unit);
-
- bool Ok()const;
- unsigned int GetProg();
- void SetProg(bool enable);
- int GetAttribute() { return mAttr; }
-
- // --
+ const char *GetVertPtr();
+ const char *GetFragPtr();
+ void SetVertPtr(char *vert);
+ void SetFragPtr(char *frag);
+ int getNumPass() { return mPass; }
+ bool GetError() { return mError; }
+
+ //const BL_Sampler *GetSampler(int i);
+ void SetSampler(int loc, int unit);
+ bool Ok() const;
+ unsigned int GetProg();
+ void SetProg(bool enable);
+ int GetAttribute() { return mAttr; }
+
// Apply methods : sets colected uniforms
void ApplyShader();
void UnloadShader();
// Update predefined uniforms each render call
- void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty);
-
- //// Set sampler units (copied)
- //void InitializeSampler(int unit, BL_Texture* texture );
-
-
- void SetUniformfv(int location,int type, float *param, int size,bool transpose=false);
- void SetUniformiv(int location,int type, int *param, int size,bool transpose=false);
+ void Update(const class RAS_MeshSlot &ms, class RAS_IRasterizer *rasty);
+ // Set sampler units (copied)
+ //void InitializeSampler(int unit, BL_Texture *texture);
+ void SetUniformfv(int location, int type, float *param, int size, bool transpose = false);
+ void SetUniformiv(int location, int type, int *param, int size, bool transpose = false);
int GetAttribLocation(const char *name);
void BindAttribute(const char *attr, int loc);
int GetUniformLocation(const char *name);
-
- void SetUniform(int uniform, const MT_Tuple2& vec);
- void SetUniform(int uniform, const MT_Tuple3& vec);
- void SetUniform(int uniform, const MT_Tuple4& vec);
- void SetUniform(int uniform, const MT_Matrix4x4& vec, bool transpose=false);
- void SetUniform(int uniform, const MT_Matrix3x3& vec, bool transpose=false);
- void SetUniform(int uniform, const float& val);
- void SetUniform(int uniform, const float* val, int len);
- void SetUniform(int uniform, const int* val, int len);
- void SetUniform(int uniform, const unsigned int& val);
+ void SetUniform(int uniform, const MT_Tuple2 &vec);
+ void SetUniform(int uniform, const MT_Tuple3 &vec);
+ void SetUniform(int uniform, const MT_Tuple4 &vec);
+ void SetUniform(int uniform, const MT_Matrix4x4 &vec, bool transpose = false);
+ void SetUniform(int uniform, const MT_Matrix3x3 &vec, bool transpose = false);
+ void SetUniform(int uniform, const float &val);
+ void SetUniform(int uniform, const float *val, int len);
+ void SetUniform(int uniform, const int *val, int len);
+ void SetUniform(int uniform, const unsigned int &val);
void SetUniform(int uniform, const int val);
// Python interface
#ifdef WITH_PYTHON
- virtual PyObject *py_repr(void) { return PyUnicode_FromFormat("BL_Shader\n\tvertex shader:%s\n\n\tfragment shader%s\n\n", vertProg, fragProg); }
+ virtual PyObject *py_repr()
+ {
+ return PyUnicode_FromFormat("BL_Shader\n\tvertex shader:%s\n\n\tfragment shader%s\n\n", vertProg, fragProg);
+ }
// -----------------------------------
KX_PYMETHOD_DOC(BL_Shader, setSource);
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 8f717c05c0f..730e49c4918 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -38,7 +38,6 @@
#include "BKE_image.h"
#include "BLI_blenlib.h"
-#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
#include "RAS_ICanvas.h"
#include "RAS_Rect.h"
@@ -139,7 +138,7 @@ bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap)
mipmap = mipmap && GPU_get_mipmap();
- mTexture = img->bindcode;
+ mTexture = img->bindcode[TEXTARGET_TEXTURE_2D];
mType = GL_TEXTURE_2D;
mUnit = unit;
@@ -196,7 +195,7 @@ bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap)
void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap)
{
- if (!GPU_non_power_of_two_support() && (!is_power_of_2_i(x) || !is_power_of_2_i(y)) ) {
+ if (!GPU_full_non_power_of_two_support() && (!is_power_of_2_i(x) || !is_power_of_2_i(y)) ) {
InitNonPow2Tex(pix, x,y,mipmap);
return;
}
@@ -686,7 +685,7 @@ void BL_Texture::setTexEnv(BL_Material *mat, bool modulate)
glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand);
} break;
}
- glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0);
+ glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f);
glEndList();
}
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
index 2607e2bb4b7..417f54cc8b9 100644
--- a/source/gameengine/Ketsji/CMakeLists.txt
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -85,7 +85,6 @@ set(SRC
KX_GameObject.cpp
KX_IpoConvert.cpp
KX_IPO_SGController.cpp
- KX_IpoActuator.cpp
KX_KetsjiEngine.cpp
KX_Light.cpp
KX_LightIpoSGController.cpp
@@ -108,7 +107,6 @@ set(SRC
KX_PythonInit.cpp
KX_PythonInitTypes.cpp
KX_PythonMain.cpp
- KX_PythonSeq.cpp
KX_RadarSensor.cpp
KX_RayCast.cpp
KX_RayEventManager.cpp
@@ -164,7 +162,6 @@ set(SRC
KX_IScalarInterpolator.h
KX_ISceneConverter.h
KX_ISystem.h
- KX_IpoActuator.h
KX_KetsjiEngine.h
KX_Light.h
KX_LightIpoSGController.h
@@ -188,7 +185,6 @@ set(SRC
KX_PythonInit.h
KX_PythonInitTypes.h
KX_PythonMain.h
- KX_PythonSeq.h
KX_RadarSensor.h
KX_RayCast.h
KX_RayEventManager.h
diff --git a/source/gameengine/Ketsji/KXNetwork/SConscript b/source/gameengine/Ketsji/KXNetwork/SConscript
deleted file mode 100644
index ab03e03e74d..00000000000
--- a/source/gameengine/Ketsji/KXNetwork/SConscript
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-
-incs = [
- '.',
- '#intern/container',
- '#intern/string',
- '#intern/moto/include',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Ketsji',
- '#source/gameengine/Network',
- '#source/gameengine/SceneGraph',
- '../../../blender/blenlib',
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-env.BlenderLib ( 'bf_network', Split(sources), Split(incs), defines=defs,libtype=['core','player'], priority=[400,125], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
index d85d33d9834..476fbd29b8b 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -39,7 +39,6 @@
#include "RAS_BucketManager.h"
#include "RAS_MeshObject.h"
#include "RAS_IRasterizer.h"
-#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h"
#include "GPU_draw.h"
@@ -676,13 +675,13 @@ void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const
mMaterial->matcolor[0]*mMaterial->emit,
mMaterial->matcolor[1]*mMaterial->emit,
mMaterial->matcolor[2]*mMaterial->emit,
- 1.0 );
+ 1.0f );
rasty->SetAmbient(mMaterial->amb);
}
if (mMaterial->material)
- rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0);
+ rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0f);
}
@@ -973,6 +972,7 @@ PyMethodDef KX_BlenderMaterial::Methods[] =
{
KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ),
KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ),
+ KX_PYMETHODTABLE( KX_BlenderMaterial, getTextureBindcode ),
KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ),
{NULL,NULL} //Sentinel
};
@@ -1326,4 +1326,20 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( bge.logic.sr
return NULL;
}
+KX_PYMETHODDEF_DOC(KX_BlenderMaterial, getTextureBindcode, "getTextureBindcode(texslot)")
+{
+ unsigned int texslot;
+ if (!PyArg_ParseTuple(args, "i:texslot", &texslot)) {
+ PyErr_SetString(PyExc_ValueError, "material.getTextureBindcode(texslot): KX_BlenderMaterial, expected an int.");
+ return NULL;
+ }
+ Image *ima = getImage(texslot);
+ if (ima) {
+ unsigned int *bindcode = ima->bindcode;
+ return PyLong_FromLong(*bindcode);
+ }
+ PyErr_SetString(PyExc_ValueError, "material.getTextureBindcode(texslot): KX_BlenderMaterial, invalid texture slot.");
+ return NULL;
+}
+
#endif // WITH_PYTHON
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h
index df089cb7f99..a3d10c0a89d 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.h
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h
@@ -133,6 +133,7 @@ public:
KX_PYMETHOD_DOC(KX_BlenderMaterial, getMaterialIndex);
KX_PYMETHOD_DOC(KX_BlenderMaterial, getTexture);
KX_PYMETHOD_DOC(KX_BlenderMaterial, setTexture);
+ KX_PYMETHOD_DOC(KX_BlenderMaterial, getTextureBindcode);
KX_PYMETHOD_DOC(KX_BlenderMaterial, setBlending);
#endif /* WITH_PYTHON */
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
index 644c71a68e4..89aea80bb67 100644
--- a/source/gameengine/Ketsji/KX_Camera.cpp
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -294,7 +294,7 @@ void KX_Camera::NormalizeClipPlanes()
for (unsigned int p = 0; p < 6; p++)
{
- MT_Scalar factor = sqrt(m_planes[p][0]*m_planes[p][0] + m_planes[p][1]*m_planes[p][1] + m_planes[p][2]*m_planes[p][2]);
+ MT_Scalar factor = sqrtf(m_planes[p][0]*m_planes[p][0] + m_planes[p][1]*m_planes[p][1] + m_planes[p][2]*m_planes[p][2]);
if (!MT_fuzzyZero(factor))
m_planes[p] /= factor;
}
@@ -318,21 +318,21 @@ void KX_Camera::ExtractFrustumSphere()
MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix;
clip_camcs_matrix.invert();
- if (m_projection_matrix[3][3] == MT_Scalar(0.0))
+ if (m_projection_matrix[3][3] == MT_Scalar(0.0f))
{
- // frustrum projection
+ // frustum projection
// detect which of the corner of the far clipping plane is the farthest to the origin
MT_Vector4 nfar; // far point in device normalized coordinate
MT_Point3 farpoint; // most extreme far point in camera coordinate
MT_Point3 nearpoint;// most extreme near point in camera coordinate
- MT_Point3 farcenter(0.0, 0.0, 0.0);// center of far cliping plane in camera coordinate
- MT_Scalar F=-1.0, N; // square distance of far and near point to origin
+ MT_Point3 farcenter(0.0f, 0.0f, 0.0f);// center of far cliping plane in camera coordinate
+ MT_Scalar F=-1.0f, N; // square distance of far and near point to origin
MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0
MT_Scalar e, s; // far and near clipping distance (<0)
MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance
MT_Scalar z; // projection of sphere center on z axis (<0)
// tmp value
- MT_Vector4 npoint(1.0, 1.0, 1.0, 1.0);
+ MT_Vector4 npoint(1.0f, 1.0f, 1.0f, 1.0f);
MT_Vector4 hpoint;
MT_Point3 point;
MT_Scalar len;
@@ -354,12 +354,12 @@ void KX_Camera::ExtractFrustumSphere()
farcenter += point;
}
// the far center is the average of the far clipping points
- farcenter *= 0.25;
+ farcenter *= 0.25f;
// the extreme near point is the opposite point on the near clipping plane
- nfar.setValue(-nfar[0], -nfar[1], -1.0, 1.0);
+ nfar.setValue(-nfar[0], -nfar[1], -1.0f, 1.0f);
nfar = clip_camcs_matrix*nfar;
nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]);
- // this is a frustrum projection
+ // this is a frustum projection
N = nearpoint.dot(nearpoint);
e = farpoint[2];
s = nearpoint[2];
@@ -373,7 +373,7 @@ void KX_Camera::ExtractFrustumSphere()
n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length();
c = MT_Point2(farcenter[0], farcenter[1]).length()/e;
// the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case
- z = (F-N)/(2.0*(e-s+c*(f-n)));
+ z = (F-N)/(2.0f*(e-s+c*(f-n)));
m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z);
m_frustum_radius = m_frustum_center.distance(farpoint);
}
@@ -381,7 +381,7 @@ void KX_Camera::ExtractFrustumSphere()
{
// orthographic projection
// The most extreme points on the near and far plane. (normalized device coords)
- MT_Vector4 hnear(1.0, 1.0, 1.0, 1.0), hfar(-1.0, -1.0, -1.0, 1.0);
+ MT_Vector4 hnear(1.0f, 1.0f, 1.0f, 1.0f), hfar(-1.0f, -1.0f, -1.0f, 1.0f);
// Transform to hom camera local space
hnear = clip_camcs_matrix*hnear;
@@ -392,12 +392,12 @@ void KX_Camera::ExtractFrustumSphere()
MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]);
// just use mediant point
- m_frustum_center = (farpoint + nearpoint)*0.5;
+ m_frustum_center = (farpoint + nearpoint)*0.5f;
m_frustum_radius = m_frustum_center.distance(farpoint);
}
// Transform to world space.
m_frustum_center = GetCameraToWorld()(m_frustum_center);
- m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
+ m_frustum_radius /= fabsf(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]);
m_set_frustum_center = true;
}
@@ -408,7 +408,7 @@ bool KX_Camera::PointInsideFrustum(const MT_Point3& x)
for ( unsigned int i = 0; i < 6 ; i++ )
{
- if (m_planes[i][0] * x[0] + m_planes[i][1] * x[1] + m_planes[i][2] * x[2] + m_planes[i][3] < 0.0)
+ if (m_planes[i][0] * x[0] + m_planes[i][1] * x[1] + m_planes[i][2] * x[2] + m_planes[i][3] < 0.0f)
return false;
}
return true;
@@ -426,7 +426,7 @@ int KX_Camera::BoxInsideFrustum(const MT_Point3 *box)
// 8 box vertices.
for (unsigned int v = 0; v < 8 ; v++)
{
- if (m_planes[p][0] * box[v][0] + m_planes[p][1] * box[v][1] + m_planes[p][2] * box[v][2] + m_planes[p][3] < 0.0)
+ if (m_planes[p][0] * box[v][0] + m_planes[p][1] * box[v][1] + m_planes[p][2] * box[v][2] + m_planes[p][3] < 0.0f)
behindCount++;
}
@@ -463,7 +463,7 @@ int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &rad
for (p = 0; p < 6; p++)
{
distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3];
- if (fabs(distance) <= radius)
+ if (fabsf(distance) <= radius)
intersect = INTERSECT;
else if (distance < -radius)
return OUTSIDE;
@@ -781,7 +781,7 @@ PyObject *KX_Camera::pyattr_get_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attr
float lens = self->m_camdata.m_lens;
float width = self->m_camdata.m_sensor_x;
- float fov = 2.0 * atan(0.5 * width / lens);
+ float fov = 2.0f * atanf(0.5f * width / lens);
return PyFloat_FromDouble(fov * MT_DEGS_PER_RAD);
}
@@ -790,14 +790,14 @@ int KX_Camera::pyattr_set_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, P
{
KX_Camera* self = static_cast<KX_Camera*>(self_v);
float fov = PyFloat_AsDouble(value);
- if (fov <= 0.0) {
+ if (fov <= 0.0f) {
PyErr_SetString(PyExc_AttributeError, "camera.fov = float: KX_Camera, expected a float greater than zero");
return PY_SET_ATTR_FAIL;
}
fov *= MT_RADS_PER_DEG;
float width = self->m_camdata.m_sensor_x;
- float lens = width / (2.0 * tan(0.5 * fov));
+ float lens = width / (2.0f * tanf(0.5f * fov));
self->m_camdata.m_lens= lens;
self->m_set_projection_matrix = false;
@@ -1035,7 +1035,7 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition,
{
PyErr_Clear();
- if (ConvertPythonToGameObject(value, &obj, true, ""))
+ if (ConvertPythonToGameObject(GetScene()->GetLogicManager(), value, &obj, true, ""))
{
PyErr_Clear();
vect = MT_Vector3(obj->NodeGetWorldPosition());
@@ -1065,7 +1065,7 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition,
vect[0] = (win[0] - viewport[0]) / viewport[2];
vect[1] = (win[1] - viewport[1]) / viewport[3];
- vect[1] = 1.0 - vect[1]; //to follow Blender window coordinate system (Top-Down)
+ vect[1] = 1.0f - vect[1]; //to follow Blender window coordinate system (Top-Down)
PyObject *ret = PyTuple_New(2);
if (ret) {
diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp
index f065e3f0001..e488bf3c30a 100644
--- a/source/gameengine/Ketsji/KX_CameraActuator.cpp
+++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp
@@ -411,7 +411,7 @@ int KX_CameraActuator::pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF
KX_CameraActuator* self = static_cast<KX_CameraActuator*>(self_v);
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_CameraActuator"))
+ if (!ConvertPythonToGameObject(self->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_CameraActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (self->m_ob)
diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp
index fdf4fa01b03..44f06a9f1eb 100644
--- a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp
@@ -25,6 +25,7 @@
#include "KX_CharacterWrapper.h"
#include "PHY_ICharacter.h"
#include "KX_PyMath.h"
+#include "BLI_utildefines.h"
KX_CharacterWrapper::KX_CharacterWrapper(PHY_ICharacter* character) :
PyObjectPlus(),
@@ -116,7 +117,9 @@ int KX_CharacterWrapper::pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE
return PY_SET_ATTR_FAIL;
}
- self->m_character->SetMaxJumps((int)param);
+ CLAMP(param, 0, 255);
+
+ self->m_character->SetMaxJumps(param);
return PY_SET_ATTR_SUCCESS;
}
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
index e07660cef72..27c074393b4 100644
--- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
@@ -96,10 +96,10 @@ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj,
m_refDirection[2] /= len;
m_refDirVector /= len;
}
- m_minimumBound = cos(minBound);
- m_maximumBound = cos(maxBound);
- m_minimumSine = sin(minBound);
- m_maximumSine = sin(maxBound);
+ m_minimumBound = cosf(minBound);
+ m_maximumBound = cosf(maxBound);
+ m_minimumSine = sinf(minBound);
+ m_maximumSine = sinf(maxBound);
}
break;
default:
@@ -117,7 +117,7 @@ KX_ConstraintActuator::~KX_ConstraintActuator()
// there's nothing to be done here, really....
} /* end of destructor */
-bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data))
{
m_hitObject = client->m_gameobject;
@@ -153,7 +153,7 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *resu
/* This function is used to pre-filter the object before casting the ray on them.
* This is useful for "X-Ray" option when we want to see "through" unwanted object.
*/
-bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo *client)
+bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data))
{
if (client->m_type > KX_ClientObjectInfo::ACTOR)
{
@@ -188,9 +188,9 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
int axis, sign;
if (m_posDampTime) {
- filter = m_posDampTime/(1.0+m_posDampTime);
+ filter = m_posDampTime/(1.0f+m_posDampTime);
} else {
- filter = 0.0;
+ filter = 0.0f;
}
switch (m_locrot) {
case KX_ACT_CONSTRAINT_ORIX:
@@ -232,10 +232,10 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
if (MT_fuzzyZero2(zaxis.length2())) {
// direction and refDirection are identical,
// choose any other direction to define plane
- if (direction[0] < 0.9999)
- zaxis = m_refDirVector.cross(MT_Vector3(1.0,0.0,0.0));
+ if (direction[0] < 0.9999f)
+ zaxis = m_refDirVector.cross(MT_Vector3(1.0f,0.0f,0.0f));
else
- zaxis = m_refDirVector.cross(MT_Vector3(0.0,1.0,0.0));
+ zaxis = m_refDirVector.cross(MT_Vector3(0.0f,1.0f,0.0f));
}
MT_Vector3 yaxis = zaxis.cross(m_refDirVector);
yaxis.normalize();
@@ -251,7 +251,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
refDirection = m_refDirVector;
}
// apply damping on the direction
- direction = filter*direction + (1.0-filter)*refDirection;
+ direction = filter*direction + (1.0f-filter)*refDirection;
obj->AlignAxisToVect(direction, axis);
result = true;
goto CHECK_TIME;
@@ -312,22 +312,22 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
} else {
switch (m_locrot) {
case KX_ACT_CONSTRAINT_DIRPX:
- direction = MT_Vector3(1.0,0.0,0.0);
+ direction = MT_Vector3(1.0f,0.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_DIRPY:
- direction = MT_Vector3(0.0,1.0,0.0);
+ direction = MT_Vector3(0.0f,1.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_DIRPZ:
- direction = MT_Vector3(0.0,0.0,1.0);
+ direction = MT_Vector3(0.0f,0.0f,1.0f);
break;
case KX_ACT_CONSTRAINT_DIRNX:
- direction = MT_Vector3(-1.0,0.0,0.0);
+ direction = MT_Vector3(-1.0f,0.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_DIRNY:
- direction = MT_Vector3(0.0,-1.0,0.0);
+ direction = MT_Vector3(0.0f,-1.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_DIRNZ:
- direction = MT_Vector3(0.0,0.0,-1.0);
+ direction = MT_Vector3(0.0f,0.0f,-1.0f);
break;
}
}
@@ -347,7 +347,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
spc = parent->GetPhysicsController();
}
}
- KX_RayCast::Callback<KX_ConstraintActuator> callback(this,dynamic_cast<PHY_IPhysicsController*>(spc));
+ KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this,dynamic_cast<PHY_IPhysicsController*>(spc));
result = KX_RayCast::RayTest(pe, position, topoint, callback);
if (result) {
MT_Vector3 newnormal = callback.m_hitNormal;
@@ -361,11 +361,11 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
MT_Scalar rotFilter;
// apply damping on the direction
if (m_rotDampTime) {
- rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
+ rotFilter = m_rotDampTime/(1.0f+m_rotDampTime);
} else {
rotFilter = filter;
}
- newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
+ newnormal = rotFilter*normal - (1.0f-rotFilter)*newnormal;
obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
direction = newnormal;
@@ -374,7 +374,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
}
if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
if (m_posDampTime) {
- newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
+ newdistance = filter*(position-callback.m_hitPoint).length()+(1.0f-filter)*m_minimumBound;
} else {
newdistance = m_minimumBound;
}
@@ -410,37 +410,37 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
normal[0] = -rotation[0][0];
normal[1] = -rotation[1][0];
normal[2] = -rotation[2][0];
- direction = MT_Vector3(1.0,0.0,0.0);
+ direction = MT_Vector3(1.0f,0.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_FHPY:
normal[0] = -rotation[0][1];
normal[1] = -rotation[1][1];
normal[2] = -rotation[2][1];
- direction = MT_Vector3(0.0,1.0,0.0);
+ direction = MT_Vector3(0.0f,1.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_FHPZ:
normal[0] = -rotation[0][2];
normal[1] = -rotation[1][2];
normal[2] = -rotation[2][2];
- direction = MT_Vector3(0.0,0.0,1.0);
+ direction = MT_Vector3(0.0f,0.0f,1.0f);
break;
case KX_ACT_CONSTRAINT_FHNX:
normal[0] = rotation[0][0];
normal[1] = rotation[1][0];
normal[2] = rotation[2][0];
- direction = MT_Vector3(-1.0,0.0,0.0);
+ direction = MT_Vector3(-1.0f,0.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_FHNY:
normal[0] = rotation[0][1];
normal[1] = rotation[1][1];
normal[2] = rotation[2][1];
- direction = MT_Vector3(0.0,-1.0,0.0);
+ direction = MT_Vector3(0.0f,-1.0f,0.0f);
break;
case KX_ACT_CONSTRAINT_FHNZ:
normal[0] = rotation[0][2];
normal[1] = rotation[1][2];
normal[2] = rotation[2][2];
- direction = MT_Vector3(0.0,0.0,-1.0);
+ direction = MT_Vector3(0.0f,0.0f,-1.0f);
break;
}
normal.normalize();
@@ -459,7 +459,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
m_hitObject = NULL;
// distance of Fh area is stored in m_minimum
MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
- KX_RayCast::Callback<KX_ConstraintActuator> callback(this, spc);
+ KX_RayCast::Callback<KX_ConstraintActuator, void> callback(this, spc);
result = KX_RayCast::RayTest(pe, position, topoint, callback);
// we expect a hit object
if (!m_hitObject)
@@ -475,7 +475,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
- MT_Scalar springExtent = 1.0 - distance/m_minimumBound;
+ MT_Scalar springExtent = 1.0f - distance/m_minimumBound;
// Fh force is stored in m_maximum
MT_Scalar springForce = springExtent * m_maximumBound;
// damping is stored in m_refDirection [0] = damping, [1] = rot damping
@@ -520,7 +520,7 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame)
}
result = true;
if (m_posDampTime) {
- newposition = filter*position + (1.0-filter)*newposition;
+ newposition = filter*position + (1.0f-filter)*newposition;
}
obj->NodeSetLocalPosition(newposition);
goto CHECK_TIME;
diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h
index edb2e5e0180..af617655d5e 100644
--- a/source/gameengine/Ketsji/KX_ConstraintActuator.h
+++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h
@@ -37,6 +37,8 @@
#include "MT_Vector3.h"
#include "KX_ClientObjectInfo.h"
+#include "BLI_utildefines.h"
+
class KX_RayCast;
class KX_GameObject;
@@ -113,9 +115,11 @@ protected:
KX_ACT_CONSTRAINT_LOCAL = 1024,
KX_ACT_CONSTRAINT_DOROTFH = 2048
};
- bool IsValidMode(KX_CONSTRAINTTYPE m);
- bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
- bool NeedRayCast(KX_ClientObjectInfo*);
+ bool IsValidMode(KX_CONSTRAINTTYPE m);
+ /// \see KX_RayCast
+ bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data));
+ /// \see KX_RayCast
+ bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data));
KX_ConstraintActuator(SCA_IObject* gameobj,
int posDamptime,
diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp
index 07bed647b29..6585b9dc831 100644
--- a/source/gameengine/Ketsji/KX_Dome.cpp
+++ b/source/gameengine/Ketsji/KX_Dome.cpp
@@ -400,19 +400,19 @@ void KX_Dome::GLDrawWarpQuads(void)
glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i);
glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height));
- glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0);
+ glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0f);
glColor3f(warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i);
glTexCoord2f((warp.nodes[i+1][j+1].u * uv_width), (warp.nodes[i+1][j+1].v * uv_height));
- glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0);
+ glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0f);
glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i);
glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height));
- glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0);
+ glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0f);
glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i);
glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
- glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0);
+ glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0f);
}
}
glEnd();
@@ -428,19 +428,19 @@ void KX_Dome::GLDrawWarpQuads(void)
glColor3f(warp.nodes[i][j].i,warp.nodes[i][j].i,warp.nodes[i][j].i);
glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
- glVertex3f(warp.nodes[i][j].x,warp.nodes[i][j].y,0.0);
+ glVertex3f(warp.nodes[i][j].x,warp.nodes[i][j].y,0.0f);
glColor3f(warp.nodes[i2][j].i,warp.nodes[i2][j].i,warp.nodes[i2][j].i);
glTexCoord2f((warp.nodes[i2][j].u * uv_width), (warp.nodes[i2][j].v * uv_height));
- glVertex3f(warp.nodes[i2][j].x,warp.nodes[i2][j].y,0.0);
+ glVertex3f(warp.nodes[i2][j].x,warp.nodes[i2][j].y,0.0f);
glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
- glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
+ glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0f);
glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
- glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
+ glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0f);
}
}
@@ -551,42 +551,42 @@ void KX_Dome::CreateMeshDome180(void)
//creating faces for the env mapcube 180deg Dome
// Top Face - just a triangle
- cubetop[0].verts[0][0] = -M_SQRT2 / 2.0;
- cubetop[0].verts[0][1] = 0.0;
- cubetop[0].verts[0][2] = 0.5;
+ cubetop[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
+ cubetop[0].verts[0][1] = 0.0f;
+ cubetop[0].verts[0][2] = 0.5f;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = uv_ratio;
- cubetop[0].verts[1][0] = 0.0;
- cubetop[0].verts[1][1] = M_SQRT2 / 2.0;
- cubetop[0].verts[1][2] = 0.5;
+ cubetop[0].verts[1][0] = 0.0f;
+ cubetop[0].verts[1][1] = (float)M_SQRT2 / 2.0f;
+ cubetop[0].verts[1][2] = 0.5f;
cubetop[0].u[1] = 0.0;
cubetop[0].v[1] = 0.0;
- cubetop[0].verts[2][0] = M_SQRT2 / 2.0;
- cubetop[0].verts[2][1] = 0.0;
- cubetop[0].verts[2][2] = 0.5;
+ cubetop[0].verts[2][0] = (float)M_SQRT2 / 2.0f;
+ cubetop[0].verts[2][1] = 0.0f;
+ cubetop[0].verts[2][2] = 0.5f;
cubetop[0].u[2] = uv_ratio;
cubetop[0].v[2] = 0.0;
nfacestop = 1;
/* Bottom face - just a triangle */
- cubebottom[0].verts[0][0] = -M_SQRT2 / 2.0;
- cubebottom[0].verts[0][1] = 0.0;
- cubebottom[0].verts[0][2] = -0.5;
+ cubebottom[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
+ cubebottom[0].verts[0][1] = 0.0f;
+ cubebottom[0].verts[0][2] = -0.5f;
cubebottom[0].u[0] = uv_ratio;
cubebottom[0].v[0] = 0.0;
- cubebottom[0].verts[1][0] = M_SQRT2 / 2.0;
+ cubebottom[0].verts[1][0] = (float)M_SQRT2 / 2.0f;
cubebottom[0].verts[1][1] = 0;
- cubebottom[0].verts[1][2] = -0.5;
+ cubebottom[0].verts[1][2] = -0.5f;
cubebottom[0].u[1] = 0.0;
cubebottom[0].v[1] = uv_ratio;
- cubebottom[0].verts[2][0] = 0.0;
- cubebottom[0].verts[2][1] = M_SQRT2 / 2.0;
- cubebottom[0].verts[2][2] = -0.5;
+ cubebottom[0].verts[2][0] = 0.0f;
+ cubebottom[0].verts[2][1] = (float)M_SQRT2 / 2.0f;
+ cubebottom[0].verts[2][2] = -0.5f;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = 0.0;
@@ -594,80 +594,80 @@ void KX_Dome::CreateMeshDome180(void)
/* Left face - two triangles */
- cubeleft[0].verts[0][0] = -M_SQRT2 / 2.0;
- cubeleft[0].verts[0][1] = 0.0;
- cubeleft[0].verts[0][2] = -0.5;
+ cubeleft[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
+ cubeleft[0].verts[0][1] = 0.0f;
+ cubeleft[0].verts[0][2] = -0.5f;
cubeleft[0].u[0] = 0.0;
cubeleft[0].v[0] = 0.0;
- cubeleft[0].verts[1][0] = 0.0;
- cubeleft[0].verts[1][1] = M_SQRT2 / 2.0;
- cubeleft[0].verts[1][2] = -0.5;
+ cubeleft[0].verts[1][0] = 0.0f;
+ cubeleft[0].verts[1][1] = (float)M_SQRT2 / 2.0f;
+ cubeleft[0].verts[1][2] = -0.5f;
cubeleft[0].u[1] = uv_ratio;
cubeleft[0].v[1] = 0.0;
- cubeleft[0].verts[2][0] = -M_SQRT2 / 2.0;
- cubeleft[0].verts[2][1] = 0.0;
- cubeleft[0].verts[2][2] = 0.5;
+ cubeleft[0].verts[2][0] = (float)(-M_SQRT2) / 2.0f;
+ cubeleft[0].verts[2][1] = 0.0f;
+ cubeleft[0].verts[2][2] = 0.5f;
cubeleft[0].u[2] = 0.0;
cubeleft[0].v[2] = uv_ratio;
//second triangle
- cubeleft[1].verts[0][0] = -M_SQRT2 / 2.0;
- cubeleft[1].verts[0][1] = 0.0;
- cubeleft[1].verts[0][2] = 0.5;
+ cubeleft[1].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
+ cubeleft[1].verts[0][1] = 0.0f;
+ cubeleft[1].verts[0][2] = 0.5f;
cubeleft[1].u[0] = 0.0;
cubeleft[1].v[0] = uv_ratio;
- cubeleft[1].verts[1][0] = 0.0;
- cubeleft[1].verts[1][1] = M_SQRT2 / 2.0;
- cubeleft[1].verts[1][2] = -0.5;
+ cubeleft[1].verts[1][0] = 0.0f;
+ cubeleft[1].verts[1][1] = (float)M_SQRT2 / 2.0f;
+ cubeleft[1].verts[1][2] = -0.5f;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
- cubeleft[1].verts[2][0] = 0.0;
- cubeleft[1].verts[2][1] = M_SQRT2 / 2.0;
- cubeleft[1].verts[2][2] = 0.5;
+ cubeleft[1].verts[2][0] = 0.0f;
+ cubeleft[1].verts[2][1] = (float)M_SQRT2 / 2.0f;
+ cubeleft[1].verts[2][2] = 0.5f;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
/* Right face - two triangles */
- cuberight[0].verts[0][0] = 0.0;
- cuberight[0].verts[0][1] = M_SQRT2 / 2.0;
- cuberight[0].verts[0][2] = -0.5;
+ cuberight[0].verts[0][0] = 0.0f;
+ cuberight[0].verts[0][1] = (float)M_SQRT2 / 2.0f;
+ cuberight[0].verts[0][2] = -0.5f;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = 0.0;
- cuberight[0].verts[1][0] = M_SQRT2 / 2.0;
- cuberight[0].verts[1][1] = 0.0;
- cuberight[0].verts[1][2] = -0.5;
+ cuberight[0].verts[1][0] = (float)M_SQRT2 / 2.0f;
+ cuberight[0].verts[1][1] = 0.0f;
+ cuberight[0].verts[1][2] = -0.5f;
cuberight[0].u[1] = uv_ratio;
cuberight[0].v[1] = 0.0;
- cuberight[0].verts[2][0] = M_SQRT2 / 2.0;
- cuberight[0].verts[2][1] = 0.0;
- cuberight[0].verts[2][2] = 0.5;
+ cuberight[0].verts[2][0] = (float)M_SQRT2 / 2.0f;
+ cuberight[0].verts[2][1] = 0.0f;
+ cuberight[0].verts[2][2] = 0.5f;
cuberight[0].u[2] = uv_ratio;
cuberight[0].v[2] = uv_ratio;
//second triangle
- cuberight[1].verts[0][0] = 0.0;
- cuberight[1].verts[0][1] = M_SQRT2 / 2.0;
- cuberight[1].verts[0][2] = -0.5;
+ cuberight[1].verts[0][0] = 0.0f;
+ cuberight[1].verts[0][1] = (float)M_SQRT2 / 2.0f;
+ cuberight[1].verts[0][2] = -0.5f;
cuberight[1].u[0] = 0.0;
cuberight[1].v[0] = 0.0;
- cuberight[1].verts[1][0] = M_SQRT2 / 2.0;
- cuberight[1].verts[1][1] = 0.0;
- cuberight[1].verts[1][2] = 0.5;
+ cuberight[1].verts[1][0] = (float)M_SQRT2 / 2.0f;
+ cuberight[1].verts[1][1] = 0.0f;
+ cuberight[1].verts[1][2] = 0.5f;
cuberight[1].u[1] = uv_ratio;
cuberight[1].v[1] = uv_ratio;
- cuberight[1].verts[2][0] = 0.0;
- cuberight[1].verts[2][1] = M_SQRT2 / 2.0;
- cuberight[1].verts[2][2] = 0.5;
+ cuberight[1].verts[2][0] = 0.0f;
+ cuberight[1].verts[2][1] = (float)M_SQRT2 / 2.0f;
+ cuberight[1].verts[2][2] = 0.5f;
cuberight[1].u[2] = 0.0;
cuberight[1].v[2] = uv_ratio;
@@ -728,10 +728,10 @@ void KX_Dome::CreateMeshDome250(void)
float uv_height, uv_base;
float verts_height;
- float rad_ang = m_angle * MT_PI / 180.0;
+ float rad_ang = m_angle * MT_PI / 180.0f;
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
- m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening
+ m_radangle = m_angle * (float)M_PI/180.0f;//calculates the radians angle, used for flattening
/*
* verts_height is the exactly needed height of the cube faces (not always 1.0).
* When we want some horizontal information (e.g. for horizontal 220deg domes) we don't need to create and tessellate the whole cube.
@@ -746,207 +746,207 @@ void KX_Dome::CreateMeshDome250(void)
* Once we take the tangent of that angle, you have the verts coordinate corresponding to the verts on the side faces.
* Then we need to multiply it by sqrt(2.0) to get the coordinate of the verts on the diagonal of the original cube.
*/
- verts_height = tanf((rad_ang / 2.0f) - (float)(MT_PI / 2.0)) * (float)M_SQRT2;
+ verts_height = tanf((rad_ang / 2.0f) - (MT_PI / 2.0f)) * (float)M_SQRT2;
uv_height = uv_ratio * ( (verts_height / 2.0f) + 0.5f);
- uv_base = uv_ratio * (1.0 - ((verts_height / 2.0f) + 0.5f));
+ uv_base = uv_ratio * (1.0f - ((verts_height / 2.0f) + 0.5f));
//creating faces for the env mapcube 180deg Dome
// Front Face - 2 triangles
- cubefront[0].verts[0][0] =-1.0;
- cubefront[0].verts[0][1] = 1.0;
- cubefront[0].verts[0][2] =-1.0;
+ cubefront[0].verts[0][0] =-1.0f;
+ cubefront[0].verts[0][1] = 1.0f;
+ cubefront[0].verts[0][2] =-1.0f;
cubefront[0].u[0] = 0.0;
cubefront[0].v[0] = 0.0;
- cubefront[0].verts[1][0] = 1.0;
- cubefront[0].verts[1][1] = 1.0;
- cubefront[0].verts[1][2] = 1.0;
+ cubefront[0].verts[1][0] = 1.0f;
+ cubefront[0].verts[1][1] = 1.0f;
+ cubefront[0].verts[1][2] = 1.0f;
cubefront[0].u[1] = uv_ratio;
cubefront[0].v[1] = uv_ratio;
- cubefront[0].verts[2][0] =-1.0;
- cubefront[0].verts[2][1] = 1.0;
- cubefront[0].verts[2][2] = 1.0;
+ cubefront[0].verts[2][0] =-1.0f;
+ cubefront[0].verts[2][1] = 1.0f;
+ cubefront[0].verts[2][2] = 1.0f;
cubefront[0].u[2] = 0.0;
cubefront[0].v[2] = uv_ratio;
//second triangle
- cubefront[1].verts[0][0] = 1.0;
- cubefront[1].verts[0][1] = 1.0;
- cubefront[1].verts[0][2] = 1.0;
+ cubefront[1].verts[0][0] = 1.0f;
+ cubefront[1].verts[0][1] = 1.0f;
+ cubefront[1].verts[0][2] = 1.0f;
cubefront[1].u[0] = uv_ratio;
cubefront[1].v[0] = uv_ratio;
- cubefront[1].verts[1][0] =-1.0;
- cubefront[1].verts[1][1] = 1.0;
- cubefront[1].verts[1][2] =-1.0;
+ cubefront[1].verts[1][0] =-1.0f;
+ cubefront[1].verts[1][1] = 1.0f;
+ cubefront[1].verts[1][2] =-1.0f;
cubefront[1].u[1] = 0.0;
cubefront[1].v[1] = 0.0;
- cubefront[1].verts[2][0] = 1.0;
- cubefront[1].verts[2][1] = 1.0;
- cubefront[1].verts[2][2] =-1.0;
+ cubefront[1].verts[2][0] = 1.0f;
+ cubefront[1].verts[2][1] = 1.0f;
+ cubefront[1].verts[2][2] =-1.0f;
cubefront[1].u[2] = uv_ratio;
cubefront[1].v[2] = 0.0;
nfacesfront = 2;
// Left Face - 2 triangles
- cubeleft[0].verts[0][0] =-1.0;
- cubeleft[0].verts[0][1] = 1.0;
- cubeleft[0].verts[0][2] =-1.0;
+ cubeleft[0].verts[0][0] =-1.0f;
+ cubeleft[0].verts[0][1] = 1.0f;
+ cubeleft[0].verts[0][2] =-1.0f;
cubeleft[0].u[0] = uv_ratio;
cubeleft[0].v[0] = 0.0;
- cubeleft[0].verts[1][0] =-1.0;
+ cubeleft[0].verts[1][0] =-1.0f;
cubeleft[0].verts[1][1] =-verts_height;
- cubeleft[0].verts[1][2] = 1.0;
+ cubeleft[0].verts[1][2] = 1.0f;
cubeleft[0].u[1] = uv_base;
cubeleft[0].v[1] = uv_ratio;
- cubeleft[0].verts[2][0] =-1.0;
+ cubeleft[0].verts[2][0] =-1.0f;
cubeleft[0].verts[2][1] =-verts_height;
- cubeleft[0].verts[2][2] =-1.0;
+ cubeleft[0].verts[2][2] =-1.0f;
cubeleft[0].u[2] = uv_base;
cubeleft[0].v[2] = 0.0;
//second triangle
- cubeleft[1].verts[0][0] =-1.0;
+ cubeleft[1].verts[0][0] =-1.0f;
cubeleft[1].verts[0][1] =-verts_height;
- cubeleft[1].verts[0][2] = 1.0;
+ cubeleft[1].verts[0][2] = 1.0f;
cubeleft[1].u[0] = uv_base;
cubeleft[1].v[0] = uv_ratio;
- cubeleft[1].verts[1][0] =-1.0;
- cubeleft[1].verts[1][1] = 1.0;
- cubeleft[1].verts[1][2] =-1.0;
+ cubeleft[1].verts[1][0] =-1.0f;
+ cubeleft[1].verts[1][1] = 1.0f;
+ cubeleft[1].verts[1][2] =-1.0f;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
- cubeleft[1].verts[2][0] =-1.0;
- cubeleft[1].verts[2][1] = 1.0;
- cubeleft[1].verts[2][2] = 1.0;
+ cubeleft[1].verts[2][0] =-1.0f;
+ cubeleft[1].verts[2][1] = 1.0f;
+ cubeleft[1].verts[2][2] = 1.0f;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
// right Face - 2 triangles
- cuberight[0].verts[0][0] = 1.0;
- cuberight[0].verts[0][1] = 1.0;
- cuberight[0].verts[0][2] = 1.0;
+ cuberight[0].verts[0][0] = 1.0f;
+ cuberight[0].verts[0][1] = 1.0f;
+ cuberight[0].verts[0][2] = 1.0f;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = uv_ratio;
- cuberight[0].verts[1][0] = 1.0;
+ cuberight[0].verts[1][0] = 1.0f;
cuberight[0].verts[1][1] =-verts_height;
- cuberight[0].verts[1][2] =-1.0;
+ cuberight[0].verts[1][2] =-1.0f;
cuberight[0].u[1] = uv_height;
cuberight[0].v[1] = 0.0;
- cuberight[0].verts[2][0] = 1.0;
+ cuberight[0].verts[2][0] = 1.0f;
cuberight[0].verts[2][1] =-verts_height;
- cuberight[0].verts[2][2] = 1.0;
+ cuberight[0].verts[2][2] = 1.0f;
cuberight[0].u[2] = uv_height;
cuberight[0].v[2] = uv_ratio;
//second triangle
- cuberight[1].verts[0][0] = 1.0;
+ cuberight[1].verts[0][0] = 1.0f;
cuberight[1].verts[0][1] =-verts_height;
- cuberight[1].verts[0][2] =-1.0;
+ cuberight[1].verts[0][2] =-1.0f;
cuberight[1].u[0] = uv_height;
cuberight[1].v[0] = 0.0;
- cuberight[1].verts[1][0] = 1.0;
- cuberight[1].verts[1][1] = 1.0;
- cuberight[1].verts[1][2] = 1.0;
+ cuberight[1].verts[1][0] = 1.0f;
+ cuberight[1].verts[1][1] = 1.0f;
+ cuberight[1].verts[1][2] = 1.0f;
cuberight[1].u[1] = 0.0;
cuberight[1].v[1] = uv_ratio;
- cuberight[1].verts[2][0] = 1.0;
- cuberight[1].verts[2][1] = 1.0;
- cuberight[1].verts[2][2] =-1.0;
+ cuberight[1].verts[2][0] = 1.0f;
+ cuberight[1].verts[2][1] = 1.0f;
+ cuberight[1].verts[2][2] =-1.0f;
cuberight[1].u[2] = 0.0;
cuberight[1].v[2] = 0.0;
nfacesright = 2;
// top Face - 2 triangles
- cubetop[0].verts[0][0] =-1.0;
- cubetop[0].verts[0][1] = 1.0;
- cubetop[0].verts[0][2] = 1.0;
+ cubetop[0].verts[0][0] =-1.0f;
+ cubetop[0].verts[0][1] = 1.0f;
+ cubetop[0].verts[0][2] = 1.0f;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = 0.0;
- cubetop[0].verts[1][0] = 1.0;
+ cubetop[0].verts[1][0] = 1.0f;
cubetop[0].verts[1][1] =-verts_height;
- cubetop[0].verts[1][2] = 1.0;
+ cubetop[0].verts[1][2] = 1.0f;
cubetop[0].u[1] = uv_ratio;
cubetop[0].v[1] = uv_height;
- cubetop[0].verts[2][0] =-1.0;
+ cubetop[0].verts[2][0] =-1.0f;
cubetop[0].verts[2][1] =-verts_height;
- cubetop[0].verts[2][2] = 1.0;
+ cubetop[0].verts[2][2] = 1.0f;
cubetop[0].u[2] = 0.0;
cubetop[0].v[2] = uv_height;
//second triangle
- cubetop[1].verts[0][0] = 1.0;
+ cubetop[1].verts[0][0] = 1.0f;
cubetop[1].verts[0][1] =-verts_height;
- cubetop[1].verts[0][2] = 1.0;
+ cubetop[1].verts[0][2] = 1.0f;
cubetop[1].u[0] = uv_ratio;
cubetop[1].v[0] = uv_height;
- cubetop[1].verts[1][0] =-1.0;
- cubetop[1].verts[1][1] = 1.0;
- cubetop[1].verts[1][2] = 1.0;
+ cubetop[1].verts[1][0] =-1.0f;
+ cubetop[1].verts[1][1] = 1.0f;
+ cubetop[1].verts[1][2] = 1.0f;
cubetop[1].u[1] = 0.0;
cubetop[1].v[1] = 0.0;
- cubetop[1].verts[2][0] = 1.0;
- cubetop[1].verts[2][1] = 1.0;
- cubetop[1].verts[2][2] = 1.0;
+ cubetop[1].verts[2][0] = 1.0f;
+ cubetop[1].verts[2][1] = 1.0f;
+ cubetop[1].verts[2][2] = 1.0f;
cubetop[1].u[2] = uv_ratio;
cubetop[1].v[2] = 0.0;
nfacestop = 2;
// bottom Face - 2 triangles
- cubebottom[0].verts[0][0] =-1.0;
+ cubebottom[0].verts[0][0] =-1.0f;
cubebottom[0].verts[0][1] =-verts_height;
- cubebottom[0].verts[0][2] =-1.0;
+ cubebottom[0].verts[0][2] =-1.0f;
cubebottom[0].u[0] = 0.0;
cubebottom[0].v[0] = uv_base;
- cubebottom[0].verts[1][0] = 1.0;
- cubebottom[0].verts[1][1] = 1.0;
- cubebottom[0].verts[1][2] =-1.0;
+ cubebottom[0].verts[1][0] = 1.0f;
+ cubebottom[0].verts[1][1] = 1.0f;
+ cubebottom[0].verts[1][2] =-1.0f;
cubebottom[0].u[1] = uv_ratio;
cubebottom[0].v[1] = uv_ratio;
- cubebottom[0].verts[2][0] =-1.0;
- cubebottom[0].verts[2][1] = 1.0;
- cubebottom[0].verts[2][2] =-1.0;
+ cubebottom[0].verts[2][0] =-1.0f;
+ cubebottom[0].verts[2][1] = 1.0f;
+ cubebottom[0].verts[2][2] =-1.0f;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = uv_ratio;
//second triangle
- cubebottom[1].verts[0][0] = 1.0;
- cubebottom[1].verts[0][1] = 1.0;
- cubebottom[1].verts[0][2] =-1.0;
+ cubebottom[1].verts[0][0] = 1.0f;
+ cubebottom[1].verts[0][1] = 1.0f;
+ cubebottom[1].verts[0][2] =-1.0f;
cubebottom[1].u[0] = uv_ratio;
cubebottom[1].v[0] = uv_ratio;
- cubebottom[1].verts[1][0] =-1.0;
+ cubebottom[1].verts[1][0] =-1.0f;
cubebottom[1].verts[1][1] =-verts_height;
- cubebottom[1].verts[1][2] =-1.0;
+ cubebottom[1].verts[1][2] =-1.0f;
cubebottom[1].u[1] = 0.0;
cubebottom[1].v[1] = uv_base;
- cubebottom[1].verts[2][0] = 1.0;
+ cubebottom[1].verts[2][0] = 1.0f;
cubebottom[1].verts[2][1] =-verts_height;
- cubebottom[1].verts[2][2] =-1.0;
+ cubebottom[1].verts[2][2] =-1.0f;
cubebottom[1].u[2] = uv_ratio;
cubebottom[1].v[2] = uv_base;
@@ -1012,80 +1012,80 @@ void KX_Dome::CreateMeshPanorama(void)
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
/* Top face - two triangles */
- cubetop[0].verts[0][0] = -M_SQRT2;
- cubetop[0].verts[0][1] = 0.0;
- cubetop[0].verts[0][2] = 1.0;
+ cubetop[0].verts[0][0] = (float)(-M_SQRT2);
+ cubetop[0].verts[0][1] = 0.0f;
+ cubetop[0].verts[0][2] = 1.0f;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = uv_ratio;
- cubetop[0].verts[1][0] = 0.0;
- cubetop[0].verts[1][1] = M_SQRT2;
- cubetop[0].verts[1][2] = 1.0;
+ cubetop[0].verts[1][0] = 0.0f;
+ cubetop[0].verts[1][1] = (float)M_SQRT2;
+ cubetop[0].verts[1][2] = 1.0f;
cubetop[0].u[1] = 0.0;
cubetop[0].v[1] = 0.0;
//second triangle
- cubetop[0].verts[2][0] = M_SQRT2;
- cubetop[0].verts[2][1] = 0.0;
- cubetop[0].verts[2][2] = 1.0;
+ cubetop[0].verts[2][0] = (float)M_SQRT2;
+ cubetop[0].verts[2][1] = 0.0f;
+ cubetop[0].verts[2][2] = 1.0f;
cubetop[0].u[2] = uv_ratio;
cubetop[0].v[2] = 0.0;
- cubetop[1].verts[0][0] = M_SQRT2;
- cubetop[1].verts[0][1] = 0.0;
- cubetop[1].verts[0][2] = 1.0;
+ cubetop[1].verts[0][0] = (float)M_SQRT2;
+ cubetop[1].verts[0][1] = 0.0f;
+ cubetop[1].verts[0][2] = 1.0f;
cubetop[1].u[0] = uv_ratio;
cubetop[1].v[0] = 0.0;
- cubetop[1].verts[1][0] = 0.0;
- cubetop[1].verts[1][1] = -M_SQRT2;
- cubetop[1].verts[1][2] = 1.0;
+ cubetop[1].verts[1][0] = 0.0f;
+ cubetop[1].verts[1][1] = (float)(-M_SQRT2);
+ cubetop[1].verts[1][2] = 1.0f;
cubetop[1].u[1] = uv_ratio;
cubetop[1].v[1] = uv_ratio;
- cubetop[1].verts[2][0] = -M_SQRT2;
- cubetop[1].verts[2][1] = 0.0;
- cubetop[1].verts[2][2] = 1.0;
+ cubetop[1].verts[2][0] = (float)(-M_SQRT2);
+ cubetop[1].verts[2][1] = 0.0f;
+ cubetop[1].verts[2][2] = 1.0f;
cubetop[1].u[2] = 0.0;
cubetop[1].v[2] = uv_ratio;
nfacestop = 2;
/* Bottom face - two triangles */
- cubebottom[0].verts[0][0] = -M_SQRT2;
- cubebottom[0].verts[0][1] = 0.0;
- cubebottom[0].verts[0][2] = -1.0;
+ cubebottom[0].verts[0][0] = (float)(-M_SQRT2);
+ cubebottom[0].verts[0][1] = 0.0f;
+ cubebottom[0].verts[0][2] = -1.0f;
cubebottom[0].u[0] = uv_ratio;
cubebottom[0].v[0] = 0.0;
- cubebottom[0].verts[1][0] = M_SQRT2;
- cubebottom[0].verts[1][1] = 0.0;
- cubebottom[0].verts[1][2] = -1.0;
+ cubebottom[0].verts[1][0] = (float)M_SQRT2;
+ cubebottom[0].verts[1][1] = 0.0f;
+ cubebottom[0].verts[1][2] = -1.0f;
cubebottom[0].u[1] = 0.0;
cubebottom[0].v[1] = uv_ratio;
- cubebottom[0].verts[2][0] = 0.0;
- cubebottom[0].verts[2][1] = M_SQRT2;
- cubebottom[0].verts[2][2] = -1.0;
+ cubebottom[0].verts[2][0] = 0.0f;
+ cubebottom[0].verts[2][1] = (float)M_SQRT2;
+ cubebottom[0].verts[2][2] = -1.0f;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = 0.0;
//second triangle
- cubebottom[1].verts[0][0] = M_SQRT2;
- cubebottom[1].verts[0][1] = 0.0;
- cubebottom[1].verts[0][2] = -1.0;
+ cubebottom[1].verts[0][0] = (float)M_SQRT2;
+ cubebottom[1].verts[0][1] = 0.0f;
+ cubebottom[1].verts[0][2] = -1.0f;
cubebottom[1].u[0] = 0.0;
cubebottom[1].v[0] = uv_ratio;
- cubebottom[1].verts[1][0] = -M_SQRT2;
- cubebottom[1].verts[1][1] = 0.0;
- cubebottom[1].verts[1][2] = -1.0;
+ cubebottom[1].verts[1][0] = (float)(-M_SQRT2);
+ cubebottom[1].verts[1][1] = 0.0f;
+ cubebottom[1].verts[1][2] = -1.0f;
cubebottom[1].u[1] = uv_ratio;
cubebottom[1].v[1] = 0.0;
- cubebottom[1].verts[2][0] = 0.0;
- cubebottom[1].verts[2][1] = -M_SQRT2;
- cubebottom[1].verts[2][2] = -1.0;
+ cubebottom[1].verts[2][0] = 0.0f;
+ cubebottom[1].verts[2][1] = (float)(-M_SQRT2);
+ cubebottom[1].verts[2][2] = -1.0f;
cubebottom[1].u[2] = uv_ratio;
cubebottom[1].v[2] = uv_ratio;
@@ -1093,40 +1093,40 @@ void KX_Dome::CreateMeshPanorama(void)
/* Left Back (135deg) face - two triangles */
- cubeleftback[0].verts[0][0] = 0;
- cubeleftback[0].verts[0][1] = -M_SQRT2;
- cubeleftback[0].verts[0][2] = -1.0;
- cubeleftback[0].u[0] = 0;
- cubeleftback[0].v[0] = 0;
+ cubeleftback[0].verts[0][0] = 0.0f;
+ cubeleftback[0].verts[0][1] = (float)(-M_SQRT2);
+ cubeleftback[0].verts[0][2] = -1.0f;
+ cubeleftback[0].u[0] = 0.0;
+ cubeleftback[0].v[0] = 0.0;
- cubeleftback[0].verts[1][0] = -M_SQRT2;
- cubeleftback[0].verts[1][1] = 0;
- cubeleftback[0].verts[1][2] = -1.0;
+ cubeleftback[0].verts[1][0] = (float)(-M_SQRT2);
+ cubeleftback[0].verts[1][1] = 0.0f;
+ cubeleftback[0].verts[1][2] = -1.0f;
cubeleftback[0].u[1] = uv_ratio;
- cubeleftback[0].v[1] = 0;
+ cubeleftback[0].v[1] = 0.0;
- cubeleftback[0].verts[2][0] = 0;
- cubeleftback[0].verts[2][1] = -M_SQRT2;
- cubeleftback[0].verts[2][2] = 1.0;
- cubeleftback[0].u[2] = 0;
+ cubeleftback[0].verts[2][0] = 0.0f;
+ cubeleftback[0].verts[2][1] = (float)(-M_SQRT2);
+ cubeleftback[0].verts[2][2] = 1.0f;
+ cubeleftback[0].u[2] = 0.0;
cubeleftback[0].v[2] = uv_ratio;
//second triangle
- cubeleftback[1].verts[0][0] = 0;
- cubeleftback[1].verts[0][1] = -M_SQRT2;
- cubeleftback[1].verts[0][2] = 1.0;
- cubeleftback[1].u[0] = 0;
+ cubeleftback[1].verts[0][0] = 0.0f;
+ cubeleftback[1].verts[0][1] = (float)(-M_SQRT2);
+ cubeleftback[1].verts[0][2] = 1.0f;
+ cubeleftback[1].u[0] = 0.0;
cubeleftback[1].v[0] = uv_ratio;
- cubeleftback[1].verts[1][0] = -M_SQRT2;
- cubeleftback[1].verts[1][1] = 0;
- cubeleftback[1].verts[1][2] = -1.0;
+ cubeleftback[1].verts[1][0] = (float)(-M_SQRT2);
+ cubeleftback[1].verts[1][1] = 0.0f;
+ cubeleftback[1].verts[1][2] = -1.0f;
cubeleftback[1].u[1] = uv_ratio;
- cubeleftback[1].v[1] = 0;
+ cubeleftback[1].v[1] = 0.0;
- cubeleftback[1].verts[2][0] = -M_SQRT2;
- cubeleftback[1].verts[2][1] = 0;
- cubeleftback[1].verts[2][2] = 1.0;
+ cubeleftback[1].verts[2][0] = (float)(-M_SQRT2);
+ cubeleftback[1].verts[2][1] = 0.0f;
+ cubeleftback[1].verts[2][2] = 1.0f;
cubeleftback[1].u[2] = uv_ratio;
cubeleftback[1].v[2] = uv_ratio;
@@ -1134,121 +1134,121 @@ void KX_Dome::CreateMeshPanorama(void)
/* Left face - two triangles */
- cubeleft[0].verts[0][0] = -M_SQRT2;
- cubeleft[0].verts[0][1] = 0;
- cubeleft[0].verts[0][2] = -1.0;
- cubeleft[0].u[0] = 0;
- cubeleft[0].v[0] = 0;
-
- cubeleft[0].verts[1][0] = 0;
- cubeleft[0].verts[1][1] = M_SQRT2;
- cubeleft[0].verts[1][2] = -1.0;
+ cubeleft[0].verts[0][0] = (float)(-M_SQRT2);
+ cubeleft[0].verts[0][1] = 0.0f;
+ cubeleft[0].verts[0][2] = -1.0f;
+ cubeleft[0].u[0] = 0.0;
+ cubeleft[0].v[0] = 0.0;
+
+ cubeleft[0].verts[1][0] = 0.0f;
+ cubeleft[0].verts[1][1] = (float)M_SQRT2;
+ cubeleft[0].verts[1][2] = -1.0f;
cubeleft[0].u[1] = uv_ratio;
- cubeleft[0].v[1] = 0;
+ cubeleft[0].v[1] = 0.0;
- cubeleft[0].verts[2][0] = -M_SQRT2;
- cubeleft[0].verts[2][1] = 0;
- cubeleft[0].verts[2][2] = 1.0;
- cubeleft[0].u[2] = 0;
+ cubeleft[0].verts[2][0] = (float)(-M_SQRT2);
+ cubeleft[0].verts[2][1] = 0.0f;
+ cubeleft[0].verts[2][2] = 1.0f;
+ cubeleft[0].u[2] = 0.0;
cubeleft[0].v[2] = uv_ratio;
//second triangle
- cubeleft[1].verts[0][0] = -M_SQRT2;
- cubeleft[1].verts[0][1] = 0;
- cubeleft[1].verts[0][2] = 1.0;
- cubeleft[1].u[0] = 0;
+ cubeleft[1].verts[0][0] = (float)(-M_SQRT2);
+ cubeleft[1].verts[0][1] = 0.0f;
+ cubeleft[1].verts[0][2] = 1.0f;
+ cubeleft[1].u[0] = 0.0;
cubeleft[1].v[0] = uv_ratio;
- cubeleft[1].verts[1][0] = 0;
- cubeleft[1].verts[1][1] = M_SQRT2;
- cubeleft[1].verts[1][2] = -1.0;
+ cubeleft[1].verts[1][0] = 0.0f;
+ cubeleft[1].verts[1][1] = (float)M_SQRT2;
+ cubeleft[1].verts[1][2] = -1.0f;
cubeleft[1].u[1] = uv_ratio;
- cubeleft[1].v[1] = 0;
+ cubeleft[1].v[1] = 0.0;
- cubeleft[1].verts[2][0] = 0;
- cubeleft[1].verts[2][1] = M_SQRT2;
- cubeleft[1].verts[2][2] = 1.0;
+ cubeleft[1].verts[2][0] = 0.0f;
+ cubeleft[1].verts[2][1] = (float)M_SQRT2;
+ cubeleft[1].verts[2][2] = 1.0f;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
/* Right face - two triangles */
- cuberight[0].verts[0][0] = 0;
- cuberight[0].verts[0][1] = M_SQRT2;
- cuberight[0].verts[0][2] = -1.0;
- cuberight[0].u[0] = 0;
- cuberight[0].v[0] = 0;
-
- cuberight[0].verts[1][0] = M_SQRT2;
- cuberight[0].verts[1][1] = 0;
- cuberight[0].verts[1][2] = -1.0;
+ cuberight[0].verts[0][0] = 0.0f;
+ cuberight[0].verts[0][1] = (float)M_SQRT2;
+ cuberight[0].verts[0][2] = -1.0f;
+ cuberight[0].u[0] = 0.0;
+ cuberight[0].v[0] = 0.0;
+
+ cuberight[0].verts[1][0] = (float)M_SQRT2;
+ cuberight[0].verts[1][1] = 0.0f;
+ cuberight[0].verts[1][2] = -1.0f;
cuberight[0].u[1] = uv_ratio;
- cuberight[0].v[1] = 0;
+ cuberight[0].v[1] = 0.0;
- cuberight[0].verts[2][0] = M_SQRT2;
- cuberight[0].verts[2][1] = 0;
- cuberight[0].verts[2][2] = 1.0;
+ cuberight[0].verts[2][0] = (float)M_SQRT2;
+ cuberight[0].verts[2][1] = 0.0f;
+ cuberight[0].verts[2][2] = 1.0f;
cuberight[0].u[2] = uv_ratio;
cuberight[0].v[2] = uv_ratio;
//second triangle
- cuberight[1].verts[0][0] = 0;
- cuberight[1].verts[0][1] = M_SQRT2;
- cuberight[1].verts[0][2] = -1.0;
- cuberight[1].u[0] = 0;
- cuberight[1].v[0] = 0;
-
- cuberight[1].verts[1][0] = M_SQRT2;
- cuberight[1].verts[1][1] = 0;
- cuberight[1].verts[1][2] = 1.0;
+ cuberight[1].verts[0][0] = 0.0f;
+ cuberight[1].verts[0][1] = (float)M_SQRT2;
+ cuberight[1].verts[0][2] = -1.0f;
+ cuberight[1].u[0] = 0.0;
+ cuberight[1].v[0] = 0.0;
+
+ cuberight[1].verts[1][0] = (float)M_SQRT2;
+ cuberight[1].verts[1][1] = 0.0f;
+ cuberight[1].verts[1][2] = 1.0f;
cuberight[1].u[1] = uv_ratio;
cuberight[1].v[1] = uv_ratio;
- cuberight[1].verts[2][0] = 0;
- cuberight[1].verts[2][1] = M_SQRT2;
- cuberight[1].verts[2][2] = 1.0;
- cuberight[1].u[2] = 0;
+ cuberight[1].verts[2][0] = 0.0f;
+ cuberight[1].verts[2][1] = (float)M_SQRT2;
+ cuberight[1].verts[2][2] = 1.0f;
+ cuberight[1].u[2] = 0.0f;
cuberight[1].v[2] = uv_ratio;
nfacesright = 2;
/* Right Back (-135deg) face - two triangles */
- cuberightback[0].verts[0][0] = M_SQRT2;
- cuberightback[0].verts[0][1] = 0;
- cuberightback[0].verts[0][2] = -1.0;
- cuberightback[0].u[0] = 0;
- cuberightback[0].v[0] = 0;
-
- cuberightback[0].verts[1][0] = 0;
- cuberightback[0].verts[1][1] = -M_SQRT2;
- cuberightback[0].verts[1][2] = -1.0;
+ cuberightback[0].verts[0][0] = (float)M_SQRT2;
+ cuberightback[0].verts[0][1] = 0.0f;
+ cuberightback[0].verts[0][2] = -1.0f;
+ cuberightback[0].u[0] = 0.0;
+ cuberightback[0].v[0] = 0.0;
+
+ cuberightback[0].verts[1][0] = 0.0f;
+ cuberightback[0].verts[1][1] = (float)(-M_SQRT2);
+ cuberightback[0].verts[1][2] = -1.0f;
cuberightback[0].u[1] = uv_ratio;
- cuberightback[0].v[1] = 0;
+ cuberightback[0].v[1] = 0.0;
- cuberightback[0].verts[2][0] = 0;
- cuberightback[0].verts[2][1] = -M_SQRT2;
- cuberightback[0].verts[2][2] = 1.0;
+ cuberightback[0].verts[2][0] = 0.0f;
+ cuberightback[0].verts[2][1] = (float)(-M_SQRT2);
+ cuberightback[0].verts[2][2] = 1.0f;
cuberightback[0].u[2] = uv_ratio;
cuberightback[0].v[2] = uv_ratio;
//second triangle
- cuberightback[1].verts[0][0] = M_SQRT2;
- cuberightback[1].verts[0][1] = 0;
- cuberightback[1].verts[0][2] = -1.0;
- cuberightback[1].u[0] = 0;
- cuberightback[1].v[0] = 0;
-
- cuberightback[1].verts[1][0] = 0;
- cuberightback[1].verts[1][1] = -M_SQRT2;
- cuberightback[1].verts[1][2] = 1.0;
+ cuberightback[1].verts[0][0] = (float)M_SQRT2;
+ cuberightback[1].verts[0][1] = 0.0f;
+ cuberightback[1].verts[0][2] = -1.0f;
+ cuberightback[1].u[0] = 0.0;
+ cuberightback[1].v[0] = 0.0;
+
+ cuberightback[1].verts[1][0] = 0.0f;
+ cuberightback[1].verts[1][1] = (float)(-M_SQRT2);
+ cuberightback[1].verts[1][2] = 1.0f;
cuberightback[1].u[1] = uv_ratio;
cuberightback[1].v[1] = uv_ratio;
- cuberightback[1].verts[2][0] = M_SQRT2;
- cuberightback[1].verts[2][1] = 0;
- cuberightback[1].verts[2][2] = 1.0;
- cuberightback[1].u[2] = 0;
+ cuberightback[1].verts[2][0] = (float)M_SQRT2;
+ cuberightback[1].verts[2][1] = 0.0f;
+ cuberightback[1].verts[2][2] = 1.0f;
+ cuberightback[1].u[2] = 0.0;
cuberightback[1].v[2] = uv_ratio;
nfacesrightback = 2;
@@ -1328,13 +1328,13 @@ void KX_Dome::FlattenDome(MT_Vector3 verts[3])
phi = atan2(verts[i][2], verts[i][0]);
verts[i][0] = r * cos(phi);
- verts[i][1] = 0;
+ verts[i][1] = 0.0f;
verts[i][2] = r * sin(phi);
if (r > 1.0) {
//round the border
verts[i][0] = cos(phi);
- verts[i][1] = -3.0;
+ verts[i][1] = -3.0f;
verts[i][2] = sin(phi);
}
}
@@ -1355,7 +1355,7 @@ void KX_Dome::FlattenPanorama(MT_Vector3 verts[3])
edge=true;
verts[i][0] = phi / MT_PI;
- verts[i][1] = 0;
+ verts[i][1] = 0.0f;
theta = asin(verts[i][2]);
verts[i][2] = theta / MT_PI;
@@ -1364,15 +1364,15 @@ void KX_Dome::FlattenPanorama(MT_Vector3 verts[3])
bool right=false;
for (i=0;i<3;i++) {
- if (fmod(verts[i][0],1.0) > 0.0) {
+ if (fmodf(verts[i][0],1.0f) > 0.0f) {
right=true;
break;
}
}
if (right) {
for (i=0;i<3;i++) {
- if (verts[i][0] < 0.0)
- verts[i][0] *= -1.0;
+ if (verts[i][0] < 0.0f)
+ verts[i][0] *= -1.0f;
}
}
}
@@ -1438,8 +1438,8 @@ void KX_Dome::CalculateFrustum(KX_Camera *cam)
// manually creating a 90deg Field of View Frustum
// the original formula:
- top = tan(fov*3.14159/360.0) * near [for fov in degrees]
- fov*0.5 = arctan ((top-bottom)*0.5 / near) [for fov in radians]
+ top = tan(fov*3.14159f/30.0f)) * near [for fov in degrees]
+ fov*0.5f = arctan ((top-bottom)*0.5f / near) [for fov in radians]
bottom = -top
left = aspect * bottom
right = aspect * top
@@ -1447,25 +1447,24 @@ void KX_Dome::CalculateFrustum(KX_Camera *cam)
// the equivalent GLU call is:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- gluPerspective(90.0,1.0,cam->GetCameraNear(),cam->GetCameraFar());
+ gluPerspective(90.0f,1.0f,cam->GetCameraNear(),cam->GetCameraFar());
#endif
- RAS_FrameFrustum m_frustrum; //90 deg. Frustum
+ RAS_FrameFrustum m_frustum; //90 deg. Frustum
- m_frustrum.camnear = cam->GetCameraNear();
- m_frustrum.camfar = cam->GetCameraFar();
+ m_frustum.camnear = cam->GetCameraNear();
+ m_frustum.camfar = cam->GetCameraFar();
-// float top = tan(90.0*MT_PI/360.0) * m_frustrum.camnear;
- float top = m_frustrum.camnear; // for deg = 90deg, tan = 1
+// float top = tan(90.0f*MT_PI/360.0f) * m_frustum.camnear;
+ float top = m_frustum.camnear; // for deg = 90deg, tan = 1
- m_frustrum.x1 = -top;
- m_frustrum.x2 = top;
- m_frustrum.y1 = -top;
- m_frustrum.y2 = top;
+ m_frustum.x1 = -top;
+ m_frustum.x2 = top;
+ m_frustum.y1 = -top;
+ m_frustum.y2 = top;
m_projmat = m_rasterizer->GetFrustumMatrix(
- m_frustrum.x1, m_frustrum.x2, m_frustrum.y1, m_frustrum.y2, m_frustrum.camnear, m_frustrum.camfar);
-
+ m_frustum.x1, m_frustum.x2, m_frustum.y1, m_frustum.y2, m_frustum.camnear, m_frustum.camfar);
}
void KX_Dome::CalculateCameraOrientation()
@@ -1476,112 +1475,112 @@ void KX_Dome::CalculateCameraOrientation()
* Uses 6 cameras for angles up to 360deg
*/
int i;
- float deg45 = MT_PI / 4;
- MT_Scalar c = cos(deg45);
- MT_Scalar s = sin(deg45);
+ float deg45 = MT_PI / 4.0f;
+ MT_Scalar c = cosf(deg45);
+ MT_Scalar s = sinf(deg45);
if (m_angle <= 180 && (m_mode == DOME_FISHEYE
|| m_mode == DOME_TRUNCATED_FRONT
|| m_mode == DOME_TRUNCATED_REAR)) {
m_locRot[0] = MT_Matrix3x3( // 90deg - Top
- c, -s, 0.0,
- 0.0,0.0, -1.0,
- s, c, 0.0);
+ c, -s, 0.0f,
+ 0.0f,0.0f, -1.0f,
+ s, c, 0.0f);
m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom
- -s, c, 0.0,
- 0.0,0.0, 1.0,
- s, c, 0.0);
+ -s, c, 0.0f,
+ 0.0f,0.0f, 1.0f,
+ s, c, 0.0f);
m_locRot[2] = MT_Matrix3x3( // 45deg - Left
- c, 0.0, s,
- 0, 1.0, 0.0,
- -s, 0.0, c);
+ c, 0.0f, s,
+ 0, 1.0f, 0.0f,
+ -s, 0.0f, c);
m_locRot[3] = MT_Matrix3x3( // 45deg - Right
- c, 0.0, -s,
- 0.0, 1.0, 0.0,
- s, 0.0, c);
+ c, 0.0f, -s,
+ 0.0f, 1.0f, 0.0f,
+ s, 0.0f, c);
} else if (m_mode == DOME_ENVMAP || (m_angle > 180 && (m_mode == DOME_FISHEYE
|| m_mode == DOME_TRUNCATED_FRONT
|| m_mode == DOME_TRUNCATED_REAR))) {
m_locRot[0] = MT_Matrix3x3( // 90deg - Top
- 1.0, 0.0, 0.0,
- 0.0, 0.0,-1.0,
- 0.0, 1.0, 0.0);
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f,-1.0f,
+ 0.0f, 1.0f, 0.0f);
m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom
- 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0,
- 0.0,-1.0, 0.0);
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ 0.0f,-1.0f, 0.0f);
m_locRot[2] = MT_Matrix3x3( // -90deg - Left
- 0.0, 0.0, 1.0,
- 0.0, 1.0, 0.0,
- -1.0, 0.0, 0.0);
+ 0.0f, 0.0f, 1.0f,
+ 0.0f, 1.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f);
m_locRot[3] = MT_Matrix3x3( // 90deg - Right
- 0.0, 0.0,-1.0,
- 0.0, 1.0, 0.0,
- 1.0, 0.0, 0.0);
+ 0.0f, 0.0f,-1.0f,
+ 0.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f);
m_locRot[4] = MT_Matrix3x3( // 0deg - Front
- 1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 0.0, 1.0);
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f);
m_locRot[5] = MT_Matrix3x3( // 180deg - Back - USED for ENVMAP only
- -1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 0.0,-1.0);
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f,-1.0f);
} else if (m_mode == DOME_PANORAM_SPH) {
m_locRot[0] = MT_Matrix3x3( // Top
- c, s, 0.0,
- 0.0,0.0, -1.0,
- -s, c, 0.0);
+ c, s, 0.0f,
+ 0.0f,0.0f, -1.0f,
+ -s, c, 0.0f);
m_locRot[1] = MT_Matrix3x3( // Bottom
- c, s, 0.0,
- 0.0, 0.0, 1.0,
- s, -c, 0.0);
+ c, s, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ s, -c, 0.0f);
m_locRot[2] = MT_Matrix3x3( // 45deg - Left
- -s, 0.0, c,
- 0, 1.0, 0.0,
- -c, 0.0, -s);
+ -s, 0.0f, c,
+ 0, 1.0f, 0.0f,
+ -c, 0.0f, -s);
m_locRot[3] = MT_Matrix3x3( // 45deg - Right
- c, 0.0, s,
- 0, 1.0, 0.0,
- -s, 0.0, c);
+ c, 0.0f, s,
+ 0, 1.0f, 0.0f,
+ -s, 0.0f, c);
m_locRot[4] = MT_Matrix3x3( // 135deg - LeftBack
- -s, 0.0, -c,
- 0.0, 1.0, 0.0,
- c, 0.0, -s);
+ -s, 0.0f, -c,
+ 0.0f, 1.0f, 0.0f,
+ c, 0.0f, -s);
m_locRot[5] = MT_Matrix3x3( // 135deg - RightBack
- c, 0.0, -s,
- 0.0, 1.0, 0.0,
- s, 0.0, c);
+ c, 0.0f, -s,
+ 0.0f, 1.0f, 0.0f,
+ s, 0.0f, c);
}
// rotating the camera in horizontal axis
if (m_tilt)
{
float tiltdeg = ((m_tilt % 360) * 2 * MT_PI) / 360;
- c = cos(tiltdeg);
- s = sin(tiltdeg);
+ c = cosf(tiltdeg);
+ s = sinf(tiltdeg);
MT_Matrix3x3 tilt_mat = MT_Matrix3x3(
- 1.0, 0.0, 0.0,
- 0.0, c, -s,
- 0.0, s, c
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, c, -s,
+ 0.0f, s, c
);
for (i =0;i<6;i++)
@@ -1667,11 +1666,11 @@ void KX_Dome::DrawEnvMap(void)
float ortho_width, ortho_height;
if (warp.usemesh)
- glOrtho((-1.0), 1.0, (-0.66), 0.66, -20.0, 10.0); //stretch the image to reduce resolution lost
+ glOrtho((-1.0), 1.0, (-0.66), 0.66, 0.0, 0.0); //stretch the image to reduce resolution lost
else {
if (can_width/3 <= can_height/2) {
- ortho_width = 1.0;
+ ortho_width = 1.0f;
ortho_height = (float)can_height/can_width;
}
else {
@@ -1679,14 +1678,14 @@ void KX_Dome::DrawEnvMap(void)
ortho_width = (float)can_width/can_height * ortho_height;
}
- glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
+ glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0,0.0,1.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
+ gluLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
glPolygonMode(GL_FRONT, GL_FILL);
glShadeModel(GL_SMOOTH);
@@ -1694,7 +1693,7 @@ void KX_Dome::DrawEnvMap(void)
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
- glColor3f(1.0,1.0,1.0);
+ glColor3f(1.0f,1.0f,1.0f);
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
double onebythree = 1.0f / 3;
@@ -1704,11 +1703,11 @@ void KX_Dome::DrawEnvMap(void)
glBegin(GL_QUADS);
glTexCoord2f(uv_ratio,uv_ratio);
glVertex3f( onebythree, 0.0f, 3.0f);
- glTexCoord2f(0.0,uv_ratio);
+ glTexCoord2f(0.0f,uv_ratio);
glVertex3f(-onebythree, 0.0f, 3.0f);
- glTexCoord2f(0.0,0.0);
+ glTexCoord2f(0.0f,0.0f);
glVertex3f(-onebythree,-2 * onebythree, 3.0f);
- glTexCoord2f(uv_ratio,0.0);
+ glTexCoord2f(uv_ratio,0.0f);
glVertex3f(onebythree,-2 * onebythree, 3.0f);
glEnd();
@@ -1717,11 +1716,11 @@ void KX_Dome::DrawEnvMap(void)
glBegin(GL_QUADS);
glTexCoord2f(uv_ratio,uv_ratio);
glVertex3f(-onebythree, 0.0f, 3.0f);
- glTexCoord2f(0.0,uv_ratio);
+ glTexCoord2f(0.0f,uv_ratio);
glVertex3f(-1.0f, 0.0f, 3.0f);
- glTexCoord2f(0.0,0.0);
+ glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f,-2 * onebythree, 3.0f);
- glTexCoord2f(uv_ratio,0.0);
+ glTexCoord2f(uv_ratio,0.0f);
glVertex3f(-onebythree,-2 * onebythree, 3.0f);
glEnd();
@@ -1730,11 +1729,11 @@ void KX_Dome::DrawEnvMap(void)
glBegin(GL_QUADS);
glTexCoord2f(uv_ratio,uv_ratio);
glVertex3f(-onebythree, 2 * onebythree, 3.0f);
- glTexCoord2f(0.0,uv_ratio);
+ glTexCoord2f(0.0f,uv_ratio);
glVertex3f(-1.0f, 2 * onebythree, 3.0f);
- glTexCoord2f(0.0,0.0);
+ glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f, 0.0f, 3.0f);
- glTexCoord2f(uv_ratio,0.0);
+ glTexCoord2f(uv_ratio,0.0f);
glVertex3f(-onebythree, 0.0f, 3.0f);
glEnd();
@@ -1743,11 +1742,11 @@ void KX_Dome::DrawEnvMap(void)
glBegin(GL_QUADS);
glTexCoord2f(uv_ratio,uv_ratio);
glVertex3f( 1.0f, 2 * onebythree, 3.0f);
- glTexCoord2f(0.0,uv_ratio);
+ glTexCoord2f(0.0f,uv_ratio);
glVertex3f( onebythree, 2 * onebythree, 3.0f);
- glTexCoord2f(0.0,0.0);
+ glTexCoord2f(0.0f,0.0f);
glVertex3f( onebythree, 0.0f, 3.0f);
- glTexCoord2f(uv_ratio,0.0);
+ glTexCoord2f(uv_ratio,0.0f);
glVertex3f(1.0f, 0.0f, 3.0f);
glEnd();
@@ -1756,11 +1755,11 @@ void KX_Dome::DrawEnvMap(void)
glBegin(GL_QUADS);
glTexCoord2f(uv_ratio,uv_ratio);
glVertex3f( 1.0f, 0.0f, 3.0f);
- glTexCoord2f(0.0,uv_ratio);
+ glTexCoord2f(0.0f,uv_ratio);
glVertex3f( onebythree, 0.0f, 3.0f);
- glTexCoord2f(0.0,0.0);
+ glTexCoord2f(0.0f,0.0f);
glVertex3f( onebythree,-2 * onebythree, 3.0f);
- glTexCoord2f(uv_ratio,0.0);
+ glTexCoord2f(uv_ratio,0.0f);
glVertex3f(1.0f, -2 * onebythree, 3.0f);
glEnd();
@@ -1769,11 +1768,11 @@ void KX_Dome::DrawEnvMap(void)
glBegin(GL_QUADS);
glTexCoord2f(uv_ratio,uv_ratio);
glVertex3f( onebythree, 2 * onebythree, 3.0f);
- glTexCoord2f(0.0,uv_ratio);
+ glTexCoord2f(0.0f,uv_ratio);
glVertex3f(-onebythree, 2 * onebythree, 3.0f);
- glTexCoord2f(0.0,0.0);
+ glTexCoord2f(0.0f,0.0f);
glVertex3f(-onebythree, 0.0f, 3.0f);
- glTexCoord2f(uv_ratio,0.0);
+ glTexCoord2f(uv_ratio,0.0f);
glVertex3f(onebythree, 0.0f, 3.0f);
glEnd();
@@ -1798,40 +1797,40 @@ void KX_Dome::DrawDomeFisheye(void)
if (m_mode == DOME_FISHEYE) {
if (warp.usemesh)
- glOrtho((-1.0), 1.0, (-1.0), 1.0, -20.0, 10.0); //stretch the image to reduce resolution lost
+ glOrtho((-1.0f), 1.0f, (-1.0f), 1.0f, -20.0f, 10.0f); //stretch the image to reduce resolution lost
else {
if (can_width < can_height) {
- ortho_width = 1.0;
+ ortho_width = 1.0f;
ortho_height = (float)can_height/can_width;
}
else {
ortho_width = (float)can_width/can_height;
- ortho_height = 1.0;
+ ortho_height = 1.0f;
}
- glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
+ glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f);
}
}
else if (m_mode == DOME_TRUNCATED_FRONT)
{
- ortho_width = 1.0;
+ ortho_width = 1.0f;
ortho_height = 2.0f * ((float)can_height / can_width) - 1.0f;
- glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0);
+ glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0f, 10.0f);
}
else { //m_mode == DOME_TRUNCATED_REAR
- ortho_width = 1.0;
+ ortho_width = 1.0f;
ortho_height = 2.0f * ((float)can_height / can_width) - 1.0f;
- glOrtho((-ortho_width), ortho_width, (-ortho_width), ortho_height, -20.0, 10.0);
+ glOrtho((-ortho_width), ortho_width, (-ortho_width), ortho_height, -20.0f, 10.0f);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0);
+ gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
@@ -1843,7 +1842,7 @@ void KX_Dome::DrawDomeFisheye(void)
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
- glColor3f(1.0,1.0,1.0);
+ glColor3f(1.0f,1.0f,1.0f);
if (dlistSupported) {
for (i=0;i<m_numfaces;i++) {
@@ -1890,16 +1889,16 @@ void KX_Dome::DrawPanorama(void)
int can_width = m_viewport.GetRight();
int can_height = m_viewport.GetTop();
- float ortho_height = 1.0;
- float ortho_width = 1.0;
+ float ortho_height = 1.0f;
+ float ortho_width = 1.0f;
if (warp.usemesh)
- glOrtho((-1.0), 1.0, (-0.5), 0.5, -20.0, 10.0); //stretch the image to reduce resolution lost
+ glOrtho((-1.0f), 1.0f, (-0.5f), 0.5f, -20.0f, 10.0f); //stretch the image to reduce resolution lost
else {
//using all the screen
if ((can_width / 2) <= (can_height)) {
- ortho_width = 1.0;
+ ortho_width = 1.0f;
ortho_height = (float)can_height/can_width;
}
else {
@@ -1907,14 +1906,14 @@ void KX_Dome::DrawPanorama(void)
ortho_height = 0.5f;
}
- glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
+ glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0);
+ gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
@@ -1926,7 +1925,7 @@ void KX_Dome::DrawPanorama(void)
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
- glColor3f(1.0,1.0,1.0);
+ glColor3f(1.0f,1.0f,1.0f);
if (dlistSupported) {
for (i=0;i<m_numfaces;i++) {
@@ -1975,14 +1974,14 @@ void KX_Dome::DrawDomeWarped(void)
double screen_ratio = can_width/ (double) can_height;
- glOrtho(-screen_ratio,screen_ratio,-1.0,1.0,-20.0,10.0);
+ glOrtho(-screen_ratio,screen_ratio,-1.0f,1.0f,-20.0f,10.0f);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- gluLookAt(0.0, 0.0, 1.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
+ gluLookAt(0.0f, 0.0f, 1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
@@ -1994,7 +1993,7 @@ void KX_Dome::DrawDomeWarped(void)
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
- glColor3f(1.0,1.0,1.0);
+ glColor3f(1.0f,1.0f,1.0f);
if (dlistSupported) {
glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
@@ -2036,7 +2035,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
- m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0);
+ m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0f);
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp
index 420f1f7eb98..364f8d4bfc6 100644
--- a/source/gameengine/Ketsji/KX_FontObject.cpp
+++ b/source/gameengine/Ketsji/KX_FontObject.cpp
@@ -193,15 +193,14 @@ void KX_FontObject::DrawFontText()
const float aspect = m_fsize / size;
/* Get a working copy of the OpenGLMatrix to use */
- double mat[16];
- memcpy(mat, this->GetOpenGLMatrix(), sizeof(double)*16);
+ float *mat = GetOpenGLMatrix();
/* Account for offset */
MT_Vector3 offset = this->NodeGetWorldOrientation() * m_offset * this->NodeGetWorldScaling();
mat[12] += offset[0]; mat[13] += offset[1]; mat[14] += offset[2];
/* Orient the spacing vector */
- MT_Vector3 spacing = MT_Vector3(0, m_fsize*m_line_spacing, 0);
+ MT_Vector3 spacing = MT_Vector3(0.0f, m_fsize*m_line_spacing, 0.0f);
spacing = this->NodeGetWorldOrientation() * spacing * this->NodeGetWorldScaling()[1];
/* Draw each line, taking spacing into consideration */
diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp
index a23af680104..f1bd253f8b3 100644
--- a/source/gameengine/Ketsji/KX_GameActuator.cpp
+++ b/source/gameengine/Ketsji/KX_GameActuator.cpp
@@ -41,6 +41,7 @@
#include "KX_Scene.h"
#include "KX_KetsjiEngine.h"
#include "KX_PythonInit.h" /* for config load/saving */
+#include "RAS_ICanvas.h"
#include <stdio.h>
#include <stdlib.h>
@@ -204,6 +205,17 @@ bool KX_GameActuator::Update()
break;
#endif // WITH_PYTHON
}
+ case KX_GAME_SCREENSHOT:
+ {
+ RAS_ICanvas *canvas = m_ketsjiengine->GetCanvas();
+ if (canvas) {
+ canvas->MakeScreenShot(m_filename);
+ }
+ else {
+ printf("KX_GAME_SCREENSHOT error: Rasterizer not available");
+ }
+ break;
+ }
default:
; /* do nothing? this is an internal error !!! */
}
diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h
index 0c1c4f0c277..57472836bb2 100644
--- a/source/gameengine/Ketsji/KX_GameActuator.h
+++ b/source/gameengine/Ketsji/KX_GameActuator.h
@@ -59,6 +59,7 @@ protected:
KX_GAME_QUIT,
KX_GAME_SAVECFG,
KX_GAME_LOADCFG,
+ KX_GAME_SCREENSHOT,
KX_GAME_MAX
};
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index c3da80bc14f..69c1af35bd9 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -47,7 +47,6 @@
#include "KX_MeshProxy.h"
#include "KX_PolyProxy.h"
#include <stdio.h> // printf
-#include <climits> // USHRT_MAX
#include "SG_Controller.h"
#include "PHY_IGraphicController.h"
#include "SG_Node.h"
@@ -56,7 +55,6 @@
#include "KX_RayCast.h"
#include "KX_PythonInit.h"
#include "KX_PyMath.h"
-#include "KX_PythonSeq.h"
#include "SCA_IActuator.h"
#include "SCA_ISensor.h"
#include "SCA_IController.h"
@@ -70,6 +68,7 @@
#include "BL_Action.h"
#include "EXP_PyObjectPlus.h" /* python stuff */
+#include "EXP_ListWrapper.h"
#include "BLI_utildefines.h"
#ifdef WITH_PYTHON
@@ -84,11 +83,11 @@
#include "BLI_math.h"
-static MT_Point3 dummy_point= MT_Point3(0.0, 0.0, 0.0);
-static MT_Vector3 dummy_scaling = MT_Vector3(1.0, 1.0, 1.0);
-static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3(1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 0.0, 1.0);
+static MT_Point3 dummy_point= MT_Point3(0.0f, 0.0f, 0.0f);
+static MT_Vector3 dummy_scaling = MT_Vector3(1.0f, 1.0f, 1.0f);
+static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3(1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f);
KX_GameObject::KX_GameObject(
void* sgReplicationInfo,
@@ -102,14 +101,12 @@ KX_GameObject::KX_GameObject(
m_pBlenderGroupObject(NULL),
m_bUseObjectColor(false),
m_bIsNegativeScaling(false),
- m_objectColor(1.0, 1.0, 1.0, 1.0),
+ m_objectColor(1.0f, 1.0f, 1.0f, 1.0f),
m_bVisible(true),
m_bCulled(true),
m_bOccluder(false),
m_pPhysicsController(NULL),
m_pGraphicController(NULL),
- m_xray(false),
- m_pHitObject(NULL),
m_pObstacleSimulation(NULL),
m_pInstanceObjects(NULL),
m_pDupliGroupObject(NULL),
@@ -357,9 +354,9 @@ void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj, bool addToCom
m_pPhysicsController->SuspendDynamics(ghost);
}
// Set us to our new scale, position, and orientation
- scale2[0] = 1.0/scale2[0];
- scale2[1] = 1.0/scale2[1];
- scale2[2] = 1.0/scale2[2];
+ scale2[0] = 1.0f/scale2[0];
+ scale2[1] = 1.0f/scale2[1];
+ scale2[2] = 1.0f/scale2[2];
scale1 = scale1 * scale2;
MT_Matrix3x3 invori = obj->NodeGetWorldOrientation().inverse();
MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale2;
@@ -484,11 +481,6 @@ void KX_GameObject::UpdateActionManager(float curtime)
GetActionManager()->Update(curtime);
}
-void KX_GameObject::UpdateActionIPOs()
-{
- GetActionManager()->UpdateIPOs();
-}
-
float KX_GameObject::GetActionFrame(short layer)
{
return GetActionManager()->GetActionFrame(layer);
@@ -526,6 +518,11 @@ void KX_GameObject::ProcessReplica()
m_pGraphicController = NULL;
m_pPhysicsController = NULL;
m_pSGNode = NULL;
+
+ /* Dupli group and instance list are set later in replication.
+ * See KX_Scene::DupliGroupRecurse. */
+ m_pDupliGroupObject = NULL;
+ m_pInstanceObjects = NULL;
m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
m_pClient_info->m_gameobject = this;
m_actionManager = NULL;
@@ -703,10 +700,10 @@ void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local)
/**
* GetOpenGL Matrix, returns an OpenGL 'compatible' matrix
*/
-double* KX_GameObject::GetOpenGLMatrix()
+float *KX_GameObject::GetOpenGLMatrix()
{
// todo: optimize and only update if necessary
- double* fl = m_OpenGL_4x4Matrix.getPointer();
+ float *fl = m_OpenGL_4x4Matrix.getPointer();
if (GetSGNode()) {
MT_Transform trans;
@@ -714,7 +711,7 @@ double* KX_GameObject::GetOpenGLMatrix()
trans.setBasis(GetSGNode()->GetWorldOrientation());
MT_Vector3 scaling = GetSGNode()->GetWorldScaling();
- m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false;
+ m_bIsNegativeScaling = ((scaling[0] < 0.0f) ^ (scaling[1] < 0.0f) ^ (scaling[2] < 0.0f)) ? true : false;
trans.scale(scaling[0], scaling[1], scaling[2]);
trans.getValue(fl);
GetSGNode()->ClearDirty();
@@ -745,7 +742,7 @@ void KX_GameObject::AddMeshUser()
m_meshes[i]->AddMeshUser(this, &m_meshSlots, GetDeformer());
}
// set the part of the mesh slot that never change
- double* fl = GetOpenGLMatrixPtr()->getPointer();
+ float *fl = GetOpenGLMatrixPtr()->getPointer();
SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots);
// RAS_MeshSlot* ms;
@@ -952,6 +949,9 @@ void KX_GameObject::InitIPO(bool ipo_as_force,
void KX_GameObject::UpdateIPO(float curframetime,
bool recurse)
{
+ /* This function shouldn't call BL_Action::Update, not even indirectly,
+ * as it will cause deadlock due to the lock in BL_Action::Update. */
+
// just the 'normal' update procedure.
GetSGNode()->SetSimulatedTime(curframetime,recurse);
GetSGNode()->UpdateWorldData(curframetime);
@@ -1187,6 +1187,7 @@ const MT_Vector4& KX_GameObject::GetObjectColor()
void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac)
{
+ const MT_Scalar eps = 3.0f * MT_EPSILON;
MT_Matrix3x3 orimat;
MT_Vector3 vect,ori,z,x,y;
MT_Scalar len;
@@ -1212,14 +1213,16 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac)
orimat = GetSGNode()->GetWorldOrientation();
switch (axis)
{
- case 0: //x axis
- ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); //pivot axis
- if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON) //is the vector parallel to the pivot?
- ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); //change the pivot!
+ case 0: // align x axis of new coord system to vect
+ ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); // pivot axis
+ if (1.0f - MT_abs(vect.dot(ori)) < eps) { // vect parallel to pivot?
+ ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); // change the pivot!
+ }
+
if (fac == 1.0f) {
x = vect;
} else {
- x = (vect * fac) + ((orimat * MT_Vector3(1.0, 0.0, 0.0)) * (1.0f - fac));
+ x = (vect * fac) + ((orimat * MT_Vector3(1.0f, 0.0f, 0.0f)) * (1.0f - fac));
len = x.length();
if (MT_fuzzyZero(len)) x = vect;
else x /= len;
@@ -1227,14 +1230,16 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac)
y = ori.cross(x);
z = x.cross(y);
break;
- case 1: //y axis
+ case 1: // y axis
ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]);
- if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON)
+ if (1.0f - MT_abs(vect.dot(ori)) < eps) {
ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]);
+ }
+
if (fac == 1.0f) {
y = vect;
} else {
- y = (vect * fac) + ((orimat * MT_Vector3(0.0, 1.0, 0.0)) * (1.0f - fac));
+ y = (vect * fac) + ((orimat * MT_Vector3(0.0f, 1.0f, 0.0f)) * (1.0f - fac));
len = y.length();
if (MT_fuzzyZero(len)) y = vect;
else y /= len;
@@ -1242,14 +1247,16 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac)
z = ori.cross(y);
x = y.cross(z);
break;
- case 2: //z axis
+ case 2: // z axis
ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]);
- if (MT_abs(vect.dot(ori)) > 1.0-3.0*MT_EPSILON)
+ if (1.0f - MT_abs(vect.dot(ori)) < eps) {
ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]);
+ }
+
if (fac == 1.0f) {
z = vect;
} else {
- z = (vect * fac) + ((orimat * MT_Vector3(0.0, 0.0, 1.0)) * (1.0f - fac));
+ z = (vect * fac) + ((orimat * MT_Vector3(0.0f, 0.0f, 1.0f)) * (1.0f - fac));
len = z.length();
if (MT_fuzzyZero(len)) z = vect;
else z /= len;
@@ -1257,25 +1264,27 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac)
x = ori.cross(z);
y = z.cross(x);
break;
- default: //wrong input?
- cout << "alignAxisToVect(): Wrong axis '" << axis <<"'\n";
+ default: // invalid axis specified
+ cout << "alignAxisToVect(): Invalid axis '" << axis <<"'\n";
return;
}
- x.normalize(); //normalize the vectors
+ x.normalize(); // normalize the new base vectors
y.normalize();
z.normalize();
- orimat.setValue( x[0],y[0],z[0],
- x[1],y[1],z[1],
- x[2],y[2],z[2]);
+ orimat.setValue(x[0], y[0], z[0],
+ x[1], y[1], z[1],
+ x[2], y[2], z[2]);
+
if (GetSGNode()->GetSGParent() != NULL)
{
// the object is a child, adapt its local orientation so that
- // the global orientation is aligned as we want.
+ // the global orientation is aligned as we want (cancelling out the parent orientation)
MT_Matrix3x3 invori = GetSGNode()->GetSGParent()->GetWorldOrientation().inverse();
NodeSetLocalOrientation(invori*orimat);
}
- else
+ else {
NodeSetLocalOrientation(orimat);
+ }
}
MT_Scalar KX_GameObject::GetMass()
@@ -1284,12 +1293,12 @@ MT_Scalar KX_GameObject::GetMass()
{
return m_pPhysicsController->GetMass();
}
- return 0.0;
+ return 0.0f;
}
MT_Vector3 KX_GameObject::GetLocalInertia()
{
- MT_Vector3 local_inertia(0.0,0.0,0.0);
+ MT_Vector3 local_inertia(0.0f,0.0f,0.0f);
if (m_pPhysicsController)
{
local_inertia = m_pPhysicsController->GetLocalInertia();
@@ -1299,7 +1308,7 @@ MT_Vector3 KX_GameObject::GetLocalInertia()
MT_Vector3 KX_GameObject::GetLinearVelocity(bool local)
{
- MT_Vector3 velocity(0.0,0.0,0.0), locvel;
+ MT_Vector3 velocity(0.0f,0.0f,0.0f), locvel;
MT_Matrix3x3 ori;
if (m_pPhysicsController)
{
@@ -1318,7 +1327,7 @@ MT_Vector3 KX_GameObject::GetLinearVelocity(bool local)
MT_Vector3 KX_GameObject::GetAngularVelocity(bool local)
{
- MT_Vector3 velocity(0.0,0.0,0.0), locvel;
+ MT_Vector3 velocity(0.0f,0.0f,0.0f), locvel;
MT_Matrix3x3 ori;
if (m_pPhysicsController)
{
@@ -1341,7 +1350,7 @@ MT_Vector3 KX_GameObject::GetVelocity(const MT_Point3& point)
{
return m_pPhysicsController->GetVelocity(point);
}
- return MT_Vector3(0.0,0.0,0.0);
+ return MT_Vector3(0.0f,0.0f,0.0f);
}
// scenegraph node stuff
@@ -1468,9 +1477,9 @@ void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans)
{
return;
}
- scale[0] = 1.0/scale[0];
- scale[1] = 1.0/scale[1];
- scale[2] = 1.0/scale[2];
+ scale[0] = 1.0f/scale[0];
+ scale[1] = 1.0f/scale[1];
+ scale[2] = 1.0f/scale[2];
MT_Matrix3x3 invori = parent->GetWorldOrientation().inverse();
MT_Vector3 newpos = invori*(trans-parent->GetWorldPosition())*scale;
NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2]));
@@ -1588,14 +1597,6 @@ void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider, const MT_Vect
if (!m_collisionCallbacks || PyList_GET_SIZE(m_collisionCallbacks) == 0)
return;
- /** Current logic controller is set by each python logic bricks before run,
- * but if no python logic brick ran the logic manager can be wrong
- * (if the user use muti scenes) and it will cause problems with function
- * ConvertPythonToGameObject which use the current logic manager for object's name.
- * Note: the scene is already set in logic frame loop.
- */
- SCA_ILogicBrick::m_sCurrentLogicManager = GetScene()->GetLogicManager();
-
PyObject *args[] = {collider->GetProxy(), PyObjectFrom(point), PyObjectFrom(normal)};
RunPythonCallBackList(m_collisionCallbacks, args, 1, ARRAY_SIZE(args));
@@ -2034,7 +2035,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
PyObject *KX_GameObject::PyReplaceMesh(PyObject *args)
{
KX_Scene *scene = KX_GetActiveScene();
-
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
+
PyObject *value;
int use_gfx= 1, use_phys= 0;
RAS_MeshObject *new_mesh;
@@ -2042,7 +2044,7 @@ PyObject *KX_GameObject::PyReplaceMesh(PyObject *args)
if (!PyArg_ParseTuple(args,"O|ii:replaceMesh", &value, &use_gfx, &use_phys))
return NULL;
- if (!ConvertPythonToMesh(value, &new_mesh, false, "gameOb.replaceMesh(value): KX_GameObject"))
+ if (!ConvertPythonToMesh(logicmgr, value, &new_mesh, false, "gameOb.replaceMesh(value): KX_GameObject"))
return NULL;
scene->ReplaceMesh(this, new_mesh, (bool)use_gfx, (bool)use_phys);
@@ -2063,13 +2065,14 @@ PyObject *KX_GameObject::PyReinstancePhysicsMesh(PyObject *args)
{
KX_GameObject *gameobj= NULL;
RAS_MeshObject *mesh= NULL;
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
PyObject *gameobj_py= NULL;
PyObject *mesh_py= NULL;
if ( !PyArg_ParseTuple(args,"|OO:reinstancePhysicsMesh",&gameobj_py, &mesh_py) ||
- (gameobj_py && !ConvertPythonToGameObject(gameobj_py, &gameobj, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) ||
- (mesh_py && !ConvertPythonToMesh(mesh_py, &mesh, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject"))
+ (gameobj_py && !ConvertPythonToGameObject(logicmgr, gameobj_py, &gameobj, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) ||
+ (mesh_py && !ConvertPythonToMesh(logicmgr, mesh_py, &mesh, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject"))
) {
return NULL;
}
@@ -2361,8 +2364,8 @@ int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_
return PY_SET_ATTR_FAIL;
}
- if (val < 0 || val > USHRT_MAX) {
- PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
+ if (val == 0 || val & ~((1 << OB_MAX_COL_MASKS) - 1)) {
+ PyErr_Format(PyExc_AttributeError, "gameOb.collisionGroup = int: KX_GameObject, expected a int bit field, 0 < group < %i", (1 << OB_MAX_COL_MASKS));
return PY_SET_ATTR_FAIL;
}
@@ -2386,8 +2389,8 @@ int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_D
return PY_SET_ATTR_FAIL;
}
- if (val < 0 || val > USHRT_MAX) {
- PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field between 0 and %i", USHRT_MAX);
+ if (val == 0 || val & ~((1 << OB_MAX_COL_MASKS) - 1)) {
+ PyErr_Format(PyExc_AttributeError, "gameOb.collisionMask = int: KX_GameObject, expected a int bit field, 0 < mask < %i", (1 << OB_MAX_COL_MASKS));
return PY_SET_ATTR_FAIL;
}
@@ -2421,7 +2424,7 @@ PyObject *KX_GameObject::pyattr_get_life(void *self_v, const KX_PYATTRIBUTE_DEF
CValue *life = self->GetProperty("::timebomb");
if (life)
- // this convert the timebomb seconds to frames, hard coded 50.0 (assuming 50fps)
+ // this convert the timebomb seconds to frames, hard coded 50.0f (assuming 50fps)
// value hardcoded in KX_Scene::AddReplicaObject()
return PyFloat_FromDouble(life->GetNumber() * 50.0);
else
@@ -2432,7 +2435,7 @@ PyObject *KX_GameObject::pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF
{
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
PHY_IPhysicsController *spc = self->GetPhysicsController();
- return PyFloat_FromDouble(spc ? spc->GetMass() : 0.0);
+ return PyFloat_FromDouble(spc ? spc->GetMass() : 0.0f);
}
int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@@ -2440,7 +2443,7 @@ int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrd
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
PHY_IPhysicsController *spc = self->GetPhysicsController();
MT_Scalar val = PyFloat_AsDouble(value);
- if (val < 0.0) { /* also accounts for non float */
+ if (val < 0.0f) { /* also accounts for non float */
PyErr_SetString(PyExc_AttributeError, "gameOb.mass = float: KX_GameObject, expected a float zero or above");
return PY_SET_ATTR_FAIL;
}
@@ -2476,7 +2479,7 @@ int KX_GameObject::pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
PHY_IPhysicsController *spc = self->GetPhysicsController();
MT_Scalar val = PyFloat_AsDouble(value);
- if (val < 0.0) { /* also accounts for non float */
+ if (val < 0.0f) { /* also accounts for non float */
PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMin = float: KX_GameObject, expected a float zero or above");
return PY_SET_ATTR_FAIL;
}
@@ -2499,7 +2502,7 @@ int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
PHY_IPhysicsController *spc = self->GetPhysicsController();
MT_Scalar val = PyFloat_AsDouble(value);
- if (val < 0.0) { /* also accounts for non float */
+ if (val < 0.0f) { /* also accounts for non float */
PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMax = float: KX_GameObject, expected a float zero or above");
return PY_SET_ATTR_FAIL;
}
@@ -2768,7 +2771,7 @@ PyObject *KX_GameObject::pyattr_get_localTransform(void *self_v, const KX_PYATTR
{
KX_GameObject* self = static_cast<KX_GameObject*>(self_v);
- double mat[16];
+ float mat[16];
MT_Transform trans;
@@ -2976,7 +2979,7 @@ PyObject *KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUT
if (self->GetSGNode() && (sg_parent = self->GetSGNode()->GetSGParent()) != NULL && sg_parent->IsSlowParent()) {
return PyFloat_FromDouble(static_cast<KX_SlowParentRelation *>(sg_parent->GetParentRelation())->GetTimeOffset());
} else {
- return PyFloat_FromDouble(0.0);
+ return PyFloat_FromDouble(0.0f);
}
}
@@ -2986,7 +2989,7 @@ int KX_GameObject::pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF
if (self->GetSGNode()) {
MT_Scalar val = PyFloat_AsDouble(value);
SG_Node *sg_parent= self->GetSGNode()->GetSGParent();
- if (val < 0.0) { /* also accounts for non float */
+ if (val < 0.0f) { /* also accounts for non float */
PyErr_SetString(PyExc_AttributeError, "gameOb.timeOffset = float: KX_GameObject, expected a float zero or above");
return PY_SET_ATTR_FAIL;
}
@@ -3062,20 +3065,83 @@ int KX_GameObject::pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *at
return PY_SET_ATTR_SUCCESS;
}
+static int kx_game_object_get_sensors_size_cb(void *self_v)
+{
+ return ((KX_GameObject *)self_v)->GetSensors().size();
+}
+
+static PyObject *kx_game_object_get_sensors_item_cb(void *self_v, int index)
+{
+ return ((KX_GameObject *)self_v)->GetSensors()[index]->GetProxy();
+}
+
+static const char *kx_game_object_get_sensors_item_name_cb(void *self_v, int index)
+{
+ return ((KX_GameObject *)self_v)->GetSensors()[index]->GetName().ReadPtr();
+}
+
/* These are experimental! */
PyObject *KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_SENSORS);
+ return (new CListWrapper(self_v,
+ ((KX_GameObject *)self_v)->GetProxy(),
+ NULL,
+ kx_game_object_get_sensors_size_cb,
+ kx_game_object_get_sensors_item_cb,
+ kx_game_object_get_sensors_item_name_cb,
+ NULL))->NewProxy(true);
+}
+
+static int kx_game_object_get_controllers_size_cb(void *self_v)
+{
+ return ((KX_GameObject *)self_v)->GetControllers().size();
+}
+
+static PyObject *kx_game_object_get_controllers_item_cb(void *self_v, int index)
+{
+ return ((KX_GameObject *)self_v)->GetControllers()[index]->GetProxy();
+}
+
+static const char *kx_game_object_get_controllers_item_name_cb(void *self_v, int index)
+{
+ return ((KX_GameObject *)self_v)->GetControllers()[index]->GetName().ReadPtr();
}
PyObject *KX_GameObject::pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_CONTROLLERS);
+ return (new CListWrapper(self_v,
+ ((KX_GameObject *)self_v)->GetProxy(),
+ NULL,
+ kx_game_object_get_controllers_size_cb,
+ kx_game_object_get_controllers_item_cb,
+ kx_game_object_get_controllers_item_name_cb,
+ NULL))->NewProxy(true);
+}
+
+static int kx_game_object_get_actuators_size_cb(void *self_v)
+{
+ return ((KX_GameObject *)self_v)->GetActuators().size();
+}
+
+static PyObject *kx_game_object_get_actuators_item_cb(void *self_v, int index)
+{
+ return ((KX_GameObject *)self_v)->GetActuators()[index]->GetProxy();
+}
+
+static const char *kx_game_object_get_actuators_item_name_cb(void *self_v, int index)
+{
+ return ((KX_GameObject *)self_v)->GetActuators()[index]->GetName().ReadPtr();
}
PyObject *KX_GameObject::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
- return KX_PythonSeq_CreatePyObject((static_cast<KX_GameObject*>(self_v))->m_proxy, KX_PYGENSEQ_OB_TYPE_ACTUATORS);
+ return (new CListWrapper(self_v,
+ ((KX_GameObject *)self_v)->GetProxy(),
+ NULL,
+ kx_game_object_get_actuators_size_cb,
+ kx_game_object_get_actuators_item_cb,
+ kx_game_object_get_actuators_item_name_cb,
+ NULL))->NewProxy(true);
}
/* End experimental */
@@ -3303,7 +3369,7 @@ PyObject *KX_GameObject::PySetOcclusion(PyObject *args)
PyObject *KX_GameObject::PyGetVelocity(PyObject *args)
{
// only can get the velocity if we have a physics object connected to us...
- MT_Point3 point(0.0,0.0,0.0);
+ MT_Point3 point(0.0f,0.0f,0.0f);
PyObject *pypos = NULL;
if (!PyArg_ParseTuple(args, "|O:getVelocity", &pypos) || (pypos && !PyVecTo(pypos, point)))
@@ -3323,7 +3389,7 @@ PyObject *KX_GameObject::PyGetReactionForce()
return PyObjectFrom(dummy_point);
#endif
- return Py_BuildValue("fff", 0.0, 0.0, 0.0);
+ return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f);
}
@@ -3351,6 +3417,7 @@ PyObject *KX_GameObject::PyDisableRigidBody()
PyObject *KX_GameObject::PySetParent(PyObject *args)
{
KX_Scene *scene = KX_GetActiveScene();
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
PyObject *pyobj;
KX_GameObject *obj;
int addToCompound=1, ghost=1;
@@ -3358,7 +3425,7 @@ PyObject *KX_GameObject::PySetParent(PyObject *args)
if (!PyArg_ParseTuple(args,"O|ii:setParent", &pyobj, &addToCompound, &ghost)) {
return NULL; // Python sets a simple error
}
- if (!ConvertPythonToGameObject(pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject"))
+ if (!ConvertPythonToGameObject(logicmgr, pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject"))
return NULL;
if (obj)
this->SetParent(scene, obj, addToCompound, ghost);
@@ -3514,9 +3581,10 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getDistanceTo,
return PyFloat_FromDouble(NodeGetWorldPosition().distance(b));
}
PyErr_Clear();
-
+
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
KX_GameObject *other;
- if (ConvertPythonToGameObject(value, &other, false, "gameOb.getDistanceTo(value): KX_GameObject"))
+ if (ConvertPythonToGameObject(logicmgr, value, &other, false, "gameOb.getDistanceTo(value): KX_GameObject"))
{
return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition()));
}
@@ -3532,6 +3600,7 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo,
MT_Vector3 toDir, locToDir;
MT_Scalar distance;
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
PyObject *returnValue;
if (!PyVecTo(value, toPoint))
@@ -3539,7 +3608,7 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo,
PyErr_Clear();
KX_GameObject *other;
- if (ConvertPythonToGameObject(value, &other, false, "")) /* error will be overwritten */
+ if (ConvertPythonToGameObject(logicmgr, value, &other, false, "")) /* error will be overwritten */
{
toPoint = other->NodeGetWorldPosition();
} else
@@ -3556,8 +3625,8 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo,
if (MT_fuzzyZero(distance))
{
//cout << "getVectTo() Error: Null vector!\n";
- locToDir = toDir = MT_Vector3(0.0,0.0,0.0);
- distance = 0.0;
+ locToDir = toDir = MT_Vector3(0.0f,0.0f,0.0f);
+ distance = 0.0f;
} else {
toDir.normalize();
locToDir = toDir * NodeGetWorldOrientation();
@@ -3572,15 +3641,32 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo,
return returnValue;
}
-bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+struct KX_GameObject::RayCastData
+{
+ RayCastData(STR_String prop, bool xray, short mask)
+ :m_prop(prop),
+ m_xray(xray),
+ m_mask(mask),
+ m_hitObject(NULL)
+ {
+ }
+
+ STR_String m_prop;
+ bool m_xray;
+ unsigned short m_mask;
+ KX_GameObject *m_hitObject;
+};
+
+bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayCastData *rayData)
{
KX_GameObject* hitKXObj = client->m_gameobject;
-
+
// if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit
// if not, all objects were tested and the front one may not be the correct one.
- if (m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
+ if ((rayData->m_xray || rayData->m_prop.Length() == 0 || hitKXObj->GetProperty(rayData->m_prop) != NULL) &&
+ hitKXObj->GetUserCollisionGroup() & rayData->m_mask)
{
- m_pHitObject = hitKXObj;
+ rayData->m_hitObject = hitKXObj;
return true;
}
// return true to stop RayCast::RayTest from looping, the above test was decisive
@@ -3591,10 +3677,10 @@ bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void
/* this function is used to pre-filter the object before casting the ray on them.
* This is useful for "X-Ray" option when we want to see "through" unwanted object.
*/
-bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client)
+bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client, RayCastData *rayData)
{
KX_GameObject* hitKXObj = client->m_gameobject;
-
+
if (client->m_type > KX_ClientObjectInfo::ACTOR)
{
// Unknown type of object, skip it.
@@ -3605,7 +3691,8 @@ bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client)
// if X-Ray option is selected, skip object that don't match the criteria as we see through them
// if not, test all objects because we don't know yet which one will be on front
- if (!m_xray || m_testPropName.Length() == 0 || hitKXObj->GetProperty(m_testPropName) != NULL)
+ if ((!rayData->m_xray || rayData->m_prop.Length() == 0 || hitKXObj->GetProperty(rayData->m_prop) != NULL) &&
+ hitKXObj->GetUserCollisionGroup() & rayData->m_mask)
{
return true;
}
@@ -3623,6 +3710,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
PyObject *pyarg;
float dist = 0.0f;
char *propName = NULL;
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
if (!PyArg_ParseTuple(args,"O|fs:rayCastTo", &pyarg, &dist, &propName)) {
return NULL; // python sets simple error
@@ -3633,7 +3721,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
KX_GameObject *other;
PyErr_Clear();
- if (ConvertPythonToGameObject(pyarg, &other, false, "")) /* error will be overwritten */
+ if (ConvertPythonToGameObject(logicmgr, pyarg, &other, false, "")) /* error will be overwritten */
{
toPoint = other->NodeGetWorldPosition();
} else
@@ -3652,17 +3740,12 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
KX_GameObject *parent = GetParent();
if (!spc && parent)
spc = parent->GetPhysicsController();
-
- m_pHitObject = NULL;
- if (propName)
- m_testPropName = propName;
- else
- m_testPropName.SetLength(0);
- KX_RayCast::Callback<KX_GameObject> callback(this,spc);
- KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
- if (m_pHitObject)
- return m_pHitObject->GetProxy();
+ RayCastData rayData(propName, false, (1u << OB_MAX_COL_MASKS) - 1);
+ KX_RayCast::Callback<KX_GameObject, RayCastData> callback(this, spc, &rayData);
+ if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback) && rayData.m_hitObject) {
+ return rayData.m_hitObject->GetProxy();
+ }
Py_RETURN_NONE;
}
@@ -3713,7 +3796,7 @@ static PyObject *none_tuple_5()
}
KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
- "rayCast(to,from,dist,prop,face,xray,poly): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n"
+ "rayCast(to,from,dist,prop,face,xray,poly,mask): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n"
" If no hit, return (None,None,None) or (None,None,None,None) or (None,None,None,None,None).\n"
" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n"
" from = 3-tuple or object reference for origin of ray (if object, use center of object)\n"
@@ -3727,6 +3810,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
" 2=>return value is a 5-tuple, the 4th element is the KX_PolyProxy object\n"
" and the 5th element is the vector of UV coordinates at the hit point of the None if there is no UV mapping\n"
" If 0 or omitted, return value is a 3-tuple\n"
+" mask = collision mask: the collision mask that ray can hit, 0 < mask < 65536\n"
"Note: The object on which you call this method matters: the ray will ignore it.\n"
" prop and xray option interact as follow:\n"
" prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n"
@@ -3742,8 +3826,10 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
char *propName = NULL;
KX_GameObject *other;
int face=0, xray=0, poly=0;
+ int mask = (1 << OB_MAX_COL_MASKS) - 1;
+ SCA_LogicManager *logicmgr = GetScene()->GetLogicManager();
- if (!PyArg_ParseTuple(args,"O|Ofsiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly)) {
+ if (!PyArg_ParseTuple(args,"O|Ofsiiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly, &mask)) {
return NULL; // Python sets a simple error
}
@@ -3751,7 +3837,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
{
PyErr_Clear();
- if (ConvertPythonToGameObject(pyto, &other, false, "")) /* error will be overwritten */
+ if (ConvertPythonToGameObject(logicmgr, pyto, &other, false, "")) /* error will be overwritten */
{
toPoint = other->NodeGetWorldPosition();
} else
@@ -3768,16 +3854,21 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
{
PyErr_Clear();
- if (ConvertPythonToGameObject(pyfrom, &other, false, "")) /* error will be overwritten */
+ if (ConvertPythonToGameObject(logicmgr, pyfrom, &other, false, "")) /* error will be overwritten */
{
fromPoint = other->NodeGetWorldPosition();
} else
{
- PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject");
+ PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly,mask): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject");
return NULL;
}
}
-
+
+ if (mask == 0 || mask & ~((1 << OB_MAX_COL_MASKS) - 1)) {
+ PyErr_Format(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly,mask): KX_GameObject, mask argument to rayCast must be a int bitfield, 0 < mask < %i", (1 << OB_MAX_COL_MASKS));
+ return NULL;
+ }
+
if (dist != 0.0f) {
MT_Vector3 toDir = toPoint-fromPoint;
if (MT_fuzzyZero(toDir.length2())) {
@@ -3796,22 +3887,15 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
KX_GameObject *parent = GetParent();
if (!spc && parent)
spc = parent->GetPhysicsController();
-
- m_pHitObject = NULL;
- if (propName)
- m_testPropName = propName;
- else
- m_testPropName.SetLength(0);
- m_xray = xray;
+
// to get the hit results
- KX_RayCast::Callback<KX_GameObject> callback(this,spc,NULL,face,(poly==2));
- KX_RayCast::RayTest(pe, fromPoint, toPoint, callback);
+ RayCastData rayData(propName, xray, mask);
+ KX_RayCast::Callback<KX_GameObject, RayCastData> callback(this, spc, &rayData, face, (poly == 2));
- if (m_pHitObject)
- {
+ if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback) && rayData.m_hitObject) {
PyObject *returnValue = (poly == 2) ? PyTuple_New(5) : (poly) ? PyTuple_New(4) : PyTuple_New(3);
if (returnValue) { // unlikely this would ever fail, if it does python sets an error
- PyTuple_SET_ITEM(returnValue, 0, m_pHitObject->GetProxy());
+ PyTuple_SET_ITEM(returnValue, 0, rayData.m_hitObject->GetProxy());
PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint));
PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal));
if (poly)
@@ -4059,7 +4143,7 @@ PyObject *KX_GameObject::Pyget(PyObject *args)
return def;
}
-bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_none_ok, const char *error_prefix)
+bool ConvertPythonToGameObject(SCA_LogicManager *manager, PyObject *value, KX_GameObject **object, bool py_none_ok, const char *error_prefix)
{
if (value==NULL) {
PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix);
@@ -4079,7 +4163,7 @@ bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_
}
if (PyUnicode_Check(value)) {
- *object = (KX_GameObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) ));
+ *object = (KX_GameObject*)manager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) ));
if (*object) {
return true;
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index c10802a83b2..9c582d3e27a 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -67,7 +67,7 @@ struct bAction;
#ifdef WITH_PYTHON
/* utility conversion function */
-bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_none_ok, const char *error_prefix);
+bool ConvertPythonToGameObject(SCA_LogicManager *logicmgr, PyObject *value, KX_GameObject **object, bool py_none_ok, const char *error_prefix);
#endif
#ifdef USE_MATHUTILS
@@ -111,9 +111,6 @@ protected:
PHY_IPhysicsController* m_pPhysicsController;
PHY_IGraphicController* m_pGraphicController;
- STR_String m_testPropName;
- bool m_xray;
- KX_GameObject* m_pHitObject;
SG_Node* m_pSGNode;
@@ -131,10 +128,19 @@ protected:
BL_ActionManager* GetActionManager();
bool m_bRecordAnimation;
+
public:
bool m_isDeformable;
/**
+ * KX_GameObject custom infos for ray cast, it contains property name,
+ * collision mask, xray flag and hited object.
+ * This structure is created during ray cast and passed as argument
+ * "data" to functions KX_GameObject::NeedRayCast and KX_GameObject::RayHit.
+ */
+ struct RayCastData;
+
+ /**
* Helper function for modules that can't include KX_ClientObjectInfo.h
*/
static KX_GameObject* GetClientObject(KX_ClientObjectInfo* info);
@@ -169,7 +175,7 @@ public:
* side effect of storing the result internally. The
* memory for the matrix remains the property of this class.
*/
- double *
+ float *
GetOpenGLMatrix(
);
@@ -321,12 +327,6 @@ public:
*/
void UpdateActionManager(float curtime);
- /**
- * Have the action manager update IPOs
- * note: not thread-safe!
- */
- void UpdateActionIPOs();
-
/*********************************
* End Animation API
*********************************/
@@ -661,8 +661,10 @@ public:
return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent());
}
- bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
- bool NeedRayCast(KX_ClientObjectInfo* client);
+ /// \see KX_RayCast
+ bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayCastData *rayData);
+ /// \see KX_RayCast
+ bool NeedRayCast(KX_ClientObjectInfo *client, RayCastData *rayData);
/**
diff --git a/source/gameengine/Ketsji/KX_IPOTransform.h b/source/gameengine/Ketsji/KX_IPOTransform.h
index a68292bf9df..a81c432b01e 100644
--- a/source/gameengine/Ketsji/KX_IPOTransform.h
+++ b/source/gameengine/Ketsji/KX_IPOTransform.h
@@ -38,12 +38,12 @@
class KX_IPOTransform {
public:
KX_IPOTransform() :
- m_position(0.0, 0.0, 0.0),
- m_eulerAngles(0.0, 0.0, 0.0),
- m_scaling(1.0, 1.0, 1.0),
- m_deltaPosition(0.0, 0.0, 0.0),
- m_deltaEulerAngles(0.0, 0.0, 0.0),
- m_deltaScaling(0.0, 0.0, 0.0)
+ m_position(0.0f, 0.0f, 0.0f),
+ m_eulerAngles(0.0f, 0.0f, 0.0f),
+ m_scaling(1.0f, 1.0f, 1.0f),
+ m_deltaPosition(0.0f, 0.0f, 0.0f),
+ m_deltaEulerAngles(0.0f, 0.0f, 0.0f),
+ m_deltaScaling(0.0f, 0.0f, 0.0f)
{}
MT_Transform GetTransform() const {
@@ -69,9 +69,9 @@ public:
void SetScaling(const MT_Vector3& scaling) { m_scaling = scaling; }
void ClearDeltaStuff() {
- m_deltaPosition.setValue(0.0, 0.0, 0.0);
- m_deltaEulerAngles.setValue(0.0, 0.0, 0.0);
- m_deltaScaling.setValue(0.0, 0.0, 0.0);
+ m_deltaPosition.setValue(0.0f, 0.0f, 0.0f);
+ m_deltaEulerAngles.setValue(0.0f, 0.0f, 0.0f);
+ m_deltaScaling.setValue(0.0f, 0.0f, 0.0f);
}
protected:
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
index f75633659ff..f3947fdd710 100644
--- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.cpp
@@ -61,18 +61,16 @@ KX_IpoSGController::KX_IpoSGController()
m_modified(true),
m_ipotime(1.0),
m_ipo_start_initialized(false),
- m_ipo_start_euler(0.0,0.0,0.0),
+ m_ipo_start_euler(0.0f, 0.0f, 0.0f),
m_ipo_euler_initialized(false)
{
m_game_object = NULL;
- for (int i=0; i < KX_MAX_IPO_CHANNELS; i++)
+ for (int i = 0; i < KX_MAX_IPO_CHANNELS; i++)
m_ipo_channels_active[i] = false;
}
-void KX_IpoSGController::SetOption(
- int option,
- int value)
+void KX_IpoSGController::SetOption(int option, int value)
{
switch (option) {
case SG_CONTR_IPO_IPO_AS_FORCE:
@@ -93,7 +91,8 @@ void KX_IpoSGController::SetOption(
if (value/* && ((SG_Node*)m_pObject)->GetSGParent() == NULL*/) {
// only accept local Ipo if the object has no parent
m_ipo_local = true;
- } else {
+ }
+ else {
m_ipo_local = false;
}
m_modified = true;
@@ -103,38 +102,29 @@ void KX_IpoSGController::SetOption(
}
}
- void
-KX_IpoSGController::UpdateSumoReference(
- )
+void KX_IpoSGController::UpdateSumoReference()
{
if (m_game_object) {
-
}
}
- void
-KX_IpoSGController::SetGameObject(
- KX_GameObject* go
- )
+void KX_IpoSGController::SetGameObject(KX_GameObject *go)
{
m_game_object = go;
}
-
-
bool KX_IpoSGController::Update(double currentTime)
{
- if (m_modified)
- {
+ if (m_modified) {
T_InterpolatorList::iterator i;
- for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ for (i = m_interpolators.begin(); i != m_interpolators.end(); ++i) {
(*i)->Execute(m_ipotime);//currentTime);
}
-
- SG_Spatial* ob = (SG_Spatial*)m_pObject;
+
+ SG_Spatial *ob = (SG_Spatial *)m_pObject;
//initialization on the first frame of the IPO
- if (! m_ipo_start_initialized && currentTime != 0.0) {
+ if (!m_ipo_start_initialized) {
m_ipo_start_point = ob->GetLocalPosition();
m_ipo_start_orient = ob->GetLocalOrientation();
m_ipo_start_scale = ob->GetLocalScale();
@@ -150,22 +140,19 @@ bool KX_IpoSGController::Update(double currentTime)
if (m_ipo_channels_active[OB_LOC_X] || m_ipo_channels_active[OB_LOC_Y] || m_ipo_channels_active[OB_LOC_Z] ||
m_ipo_channels_active[OB_DLOC_X] || m_ipo_channels_active[OB_DLOC_Y] || m_ipo_channels_active[OB_DLOC_Z])
{
- if (m_ipo_as_force == true)
- {
- if (m_game_object && ob && m_game_object->GetPhysicsController())
- {
+ if (m_ipo_as_force == true) {
+ if (m_game_object && ob && m_game_object->GetPhysicsController()) {
MT_Vector3 vec = m_ipo_local ?
ob->GetWorldOrientation() * m_ipo_xform.GetPosition() :
m_ipo_xform.GetPosition();
m_game_object->GetPhysicsController()->ApplyForce(vec, false);
}
}
- else
- {
+ else {
// Local ipo should be defined with the object position at (0,0,0)
// Local transform is applied to the object based on initial position
- MT_Point3 newPosition(0.0,0.0,0.0);
-
+ MT_Point3 newPosition(0.0f, 0.0f, 0.0f);
+
if (!m_ipo_add)
newPosition = ob->GetLocalPosition();
//apply separate IPO channels if there is any data in them
@@ -175,21 +162,21 @@ bool KX_IpoSGController::Update(double currentTime)
newPosition[0] = (m_ipo_channels_active[OB_DLOC_X] ? m_ipo_xform.GetPosition()[0] + m_ipo_xform.GetDeltaPosition()[0] : m_ipo_xform.GetPosition()[0]);
}
else if (m_ipo_channels_active[OB_DLOC_X] && m_ipo_start_initialized) {
- newPosition[0] = (((!m_ipo_add)?m_ipo_start_point[0]:0.0) + m_ipo_xform.GetDeltaPosition()[0]);
+ newPosition[0] = (((!m_ipo_add) ? m_ipo_start_point[0] : 0.0f) + m_ipo_xform.GetDeltaPosition()[0]);
}
//LocY and dLocY
if (m_ipo_channels_active[OB_LOC_Y]) {
newPosition[1] = (m_ipo_channels_active[OB_DLOC_Y] ? m_ipo_xform.GetPosition()[1] + m_ipo_xform.GetDeltaPosition()[1] : m_ipo_xform.GetPosition()[1]);
}
else if (m_ipo_channels_active[OB_DLOC_Y] && m_ipo_start_initialized) {
- newPosition[1] = (((!m_ipo_add)?m_ipo_start_point[1]:0.0) + m_ipo_xform.GetDeltaPosition()[1]);
+ newPosition[1] = (((!m_ipo_add) ? m_ipo_start_point[1] : 0.0f) + m_ipo_xform.GetDeltaPosition()[1]);
}
//LocZ and dLocZ
if (m_ipo_channels_active[OB_LOC_Z]) {
newPosition[2] = (m_ipo_channels_active[OB_DLOC_Z] ? m_ipo_xform.GetPosition()[2] + m_ipo_xform.GetDeltaPosition()[2] : m_ipo_xform.GetPosition()[2]);
}
else if (m_ipo_channels_active[OB_DLOC_Z] && m_ipo_start_initialized) {
- newPosition[2] = (((!m_ipo_add)?m_ipo_start_point[2]:0.0) + m_ipo_xform.GetDeltaPosition()[2]);
+ newPosition[2] = (((!m_ipo_add) ? m_ipo_start_point[2] : 0.0f) + m_ipo_xform.GetDeltaPosition()[2]);
}
if (m_ipo_add) {
if (m_ipo_local)
@@ -206,15 +193,15 @@ bool KX_IpoSGController::Update(double currentTime)
m_ipo_channels_active[OB_DROT_X] || m_ipo_channels_active[OB_DROT_Y] || m_ipo_channels_active[OB_DROT_Z])
{
if (m_ipo_as_force) {
-
if (m_game_object && ob) {
m_game_object->ApplyTorque(m_ipo_local ?
ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() :
m_ipo_xform.GetEulerAngles(), false);
}
- } else if (m_ipo_add) {
+ }
+ else if (m_ipo_add) {
if (m_ipo_start_initialized) {
- double yaw=0, pitch=0, roll=0; //delta Euler angles
+ double yaw = 0.0, pitch = 0.0, roll = 0.0; //delta Euler angles
//RotX and dRotX
if (m_ipo_channels_active[OB_ROT_X])
@@ -227,7 +214,7 @@ bool KX_IpoSGController::Update(double currentTime)
pitch += m_ipo_xform.GetEulerAngles()[1];
if (m_ipo_channels_active[OB_DROT_Y])
pitch += m_ipo_xform.GetDeltaEulerAngles()[1];
-
+
//RotZ and dRotZ
if (m_ipo_channels_active[OB_ROT_Z])
roll += m_ipo_xform.GetEulerAngles()[2];
@@ -242,12 +229,13 @@ bool KX_IpoSGController::Update(double currentTime)
if (m_game_object)
m_game_object->NodeSetLocalOrientation(rotation);
}
- } else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) {
+ }
+ else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) {
if (m_ipo_euler_initialized) {
// assume all channel absolute
// All 3 channels should be specified but if they are not, we will take
// the value at the start of the game to avoid angle sign reversal
- double yaw=m_ipo_start_euler[0], pitch=m_ipo_start_euler[1], roll=m_ipo_start_euler[2];
+ double yaw = m_ipo_start_euler[0], pitch = m_ipo_start_euler[1], roll = m_ipo_start_euler[2];
//RotX and dRotX
if (m_ipo_channels_active[OB_ROT_X]) {
@@ -275,9 +263,10 @@ bool KX_IpoSGController::Update(double currentTime)
if (m_game_object)
m_game_object->NodeSetLocalOrientation(MT_Vector3(yaw, pitch, roll));
}
- } else if (m_ipo_start_initialized) {
+ }
+ else if (m_ipo_start_initialized) {
// only DROT, treat as Add
- double yaw=0, pitch=0, roll=0; //delta Euler angles
+ double yaw = 0.0, pitch = 0.0, roll = 0.0; //delta Euler angles
//dRotX
if (m_ipo_channels_active[OB_DROT_X])
@@ -286,7 +275,7 @@ bool KX_IpoSGController::Update(double currentTime)
//dRotY
if (m_ipo_channels_active[OB_DROT_Y])
pitch = m_ipo_xform.GetDeltaEulerAngles()[1];
-
+
//dRotZ
if (m_ipo_channels_active[OB_DROT_Z])
roll = m_ipo_xform.GetDeltaEulerAngles()[2];
@@ -303,7 +292,7 @@ bool KX_IpoSGController::Update(double currentTime)
m_ipo_channels_active[OB_DSIZE_X] || m_ipo_channels_active[OB_DSIZE_Y] || m_ipo_channels_active[OB_DSIZE_Z])
{
//default is no scale change
- MT_Vector3 newScale(1.0,1.0,1.0);
+ MT_Vector3 newScale(1.0f, 1.0f, 1.0f);
if (!m_ipo_add)
newScale = ob->GetLocalScale();
@@ -311,7 +300,7 @@ bool KX_IpoSGController::Update(double currentTime)
newScale[0] = (m_ipo_channels_active[OB_DSIZE_X] ? (m_ipo_xform.GetScaling()[0] + m_ipo_xform.GetDeltaScaling()[0]) : m_ipo_xform.GetScaling()[0]);
}
else if (m_ipo_channels_active[OB_DSIZE_X] && m_ipo_start_initialized) {
- newScale[0] = (m_ipo_xform.GetDeltaScaling()[0] + ((!m_ipo_add)?m_ipo_start_scale[0]:0.0));
+ newScale[0] = (m_ipo_xform.GetDeltaScaling()[0] + ((!m_ipo_add) ? m_ipo_start_scale[0] : 0.0f));
}
//RotY dRotY
@@ -319,7 +308,7 @@ bool KX_IpoSGController::Update(double currentTime)
newScale[1] = (m_ipo_channels_active[OB_DSIZE_Y] ? (m_ipo_xform.GetScaling()[1] + m_ipo_xform.GetDeltaScaling()[1]): m_ipo_xform.GetScaling()[1]);
}
else if (m_ipo_channels_active[OB_DSIZE_Y] && m_ipo_start_initialized) {
- newScale[1] = (m_ipo_xform.GetDeltaScaling()[1] + ((!m_ipo_add)?m_ipo_start_scale[1]:0.0));
+ newScale[1] = (m_ipo_xform.GetDeltaScaling()[1] + ((!m_ipo_add)?m_ipo_start_scale[1] : 0.0f));
}
//RotZ and dRotZ
@@ -327,7 +316,7 @@ bool KX_IpoSGController::Update(double currentTime)
newScale[2] = (m_ipo_channels_active[OB_DSIZE_Z] ? (m_ipo_xform.GetScaling()[2] + m_ipo_xform.GetDeltaScaling()[2]) : m_ipo_xform.GetScaling()[2]);
}
else if (m_ipo_channels_active[OB_DSIZE_Z] && m_ipo_start_initialized) {
- newScale[2] = (m_ipo_xform.GetDeltaScaling()[2] + ((!m_ipo_add)?m_ipo_start_scale[2]:1.0));
+ newScale[2] = (m_ipo_xform.GetDeltaScaling()[2] + ((!m_ipo_add)?m_ipo_start_scale[2] : 1.0f));
}
if (m_ipo_add) {
@@ -336,24 +325,22 @@ bool KX_IpoSGController::Update(double currentTime)
if (m_game_object)
m_game_object->NodeSetLocalScale(newScale);
}
-
- m_modified=false;
+ m_modified = false;
}
return false;
}
-
-void KX_IpoSGController::AddInterpolator(KX_IInterpolator* interp)
+void KX_IpoSGController::AddInterpolator(KX_IInterpolator *interp)
{
- this->m_interpolators.push_back(interp);
+ m_interpolators.push_back(interp);
}
-SG_Controller* KX_IpoSGController::GetReplica(class SG_Node* destnode)
+SG_Controller *KX_IpoSGController::GetReplica(SG_Node *destnode)
{
- KX_IpoSGController* iporeplica = new KX_IpoSGController(*this);
+ KX_IpoSGController *iporeplica = new KX_IpoSGController(*this);
// clear object that ipo acts on in the replica.
iporeplica->ClearObject();
- iporeplica->SetGameObject((KX_GameObject*)destnode->GetSGClientObject());
+ iporeplica->SetGameObject((KX_GameObject *)destnode->GetSGClientObject());
// dirty hack, ask Gino for a better solution in the ipo implementation
// hacken en zagen, in what we call datahiding, not written for replication :(
@@ -362,29 +349,27 @@ SG_Controller* KX_IpoSGController::GetReplica(class SG_Node* destnode)
iporeplica->m_interpolators.clear();
T_InterpolatorList::iterator i;
- for (i = oldlist.begin(); !(i == oldlist.end()); ++i) {
- KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i));
+ for (i = oldlist.begin(); i != oldlist.end(); ++i) {
+ KX_ScalarInterpolator *copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator *)*i));
iporeplica->AddInterpolator(copyipo);
- MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget();
+ MT_Scalar *scaal = ((KX_ScalarInterpolator *)*i)->GetTarget();
uint_ptr orgbase = (uint_ptr)&m_ipo_xform;
uint_ptr orgloc = (uint_ptr)scaal;
- uint_ptr offset = orgloc-orgbase;
+ uint_ptr offset = orgloc - orgbase;
uint_ptr newaddrbase = (uint_ptr)&iporeplica->m_ipo_xform;
newaddrbase += offset;
- MT_Scalar* blaptr = (MT_Scalar*) newaddrbase;
- copyipo->SetNewTarget((MT_Scalar*)blaptr);
+ MT_Scalar *blaptr = (MT_Scalar *) newaddrbase;
+ copyipo->SetNewTarget((MT_Scalar *)blaptr);
}
-
+
return iporeplica;
}
KX_IpoSGController::~KX_IpoSGController()
{
-
T_InterpolatorList::iterator i;
- for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) {
+ for (i = m_interpolators.begin(); i != m_interpolators.end(); ++i) {
delete (*i);
}
-
}
diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IPO_SGController.h
index cecfa9804db..3318761bb88 100644
--- a/source/gameengine/Ketsji/KX_IPO_SGController.h
+++ b/source/gameengine/Ketsji/KX_IPO_SGController.h
@@ -42,85 +42,80 @@
class KX_IpoSGController : public SG_Controller
{
- KX_IPOTransform m_ipo_xform;
- T_InterpolatorList m_interpolators;
+ KX_IPOTransform m_ipo_xform;
+ T_InterpolatorList m_interpolators;
/** Flag for each IPO channel that can be applied to a game object */
- bool m_ipo_channels_active[KX_MAX_IPO_CHANNELS];
+ bool m_ipo_channels_active[KX_MAX_IPO_CHANNELS];
/** Interpret the ipo as a force rather than a displacement? */
- bool m_ipo_as_force;
+ bool m_ipo_as_force;
/** Add Ipo curve to current loc/rot/scale */
- bool m_ipo_add;
+ bool m_ipo_add;
/** Ipo must be applied in local coordinate rather than in global coordinates (used for force and Add mode)*/
- bool m_ipo_local;
+ bool m_ipo_local;
/** Were settings altered since the last update? */
- bool m_modified;
+ bool m_modified;
/** Local time of this ipo.*/
- double m_ipotime;
+ double m_ipotime;
/** Location of the object when the IPO is first fired (for local transformations) */
- class MT_Point3 m_ipo_start_point;
+ MT_Point3 m_ipo_start_point;
/** Orientation of the object when the IPO is first fired (for local transformations) */
- class MT_Matrix3x3 m_ipo_start_orient;
+ MT_Matrix3x3 m_ipo_start_orient;
/** Scale of the object when the IPO is first fired (for local transformations) */
- class MT_Vector3 m_ipo_start_scale;
+ MT_Vector3 m_ipo_start_scale;
/** if IPO initial position has been set for local normal IPO */
- bool m_ipo_start_initialized;
+ bool m_ipo_start_initialized;
/** Euler angles at the start of the game, needed for incomplete ROT Ipo curves */
- class MT_Vector3 m_ipo_start_euler;
+ MT_Vector3 m_ipo_start_euler;
/** true is m_ipo_start_euler has been initialized */
- bool m_ipo_euler_initialized;
+ bool m_ipo_euler_initialized;
/** A reference to the original game object. */
- class KX_GameObject* m_game_object;
+ class KX_GameObject *m_game_object;
public:
KX_IpoSGController();
virtual ~KX_IpoSGController();
- virtual SG_Controller* GetReplica(class SG_Node* destnode);
+ virtual SG_Controller *GetReplica(class SG_Node *destnode);
- void
- SetOption(
- int option,
- int value
- );
+ void SetOption(int option, int value);
/** Set sumo data. */
void UpdateSumoReference();
/** Set reference to the corresponding game object. */
- void SetGameObject(class KX_GameObject*);
+ void SetGameObject(class KX_GameObject *go);
void SetIPOChannelActive(int index, bool value) {
//indexes found in makesdna\DNA_ipo_types.h
m_ipo_channels_active[index] = value;
}
-
-
- KX_IPOTransform& GetIPOTransform()
+
+ KX_IPOTransform &GetIPOTransform()
{
return m_ipo_xform;
}
- void AddInterpolator(KX_IInterpolator* interp);
+
+ void AddInterpolator(KX_IInterpolator *interp);
virtual bool Update(double time);
- virtual void SetSimulatedTime(double time)
+ virtual void SetSimulatedTime(double time)
{
m_ipotime = time;
m_modified = true;
}
-
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_IpoSGController")
#endif
diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h
index 2e1c16c6e32..1963fc7c48f 100644
--- a/source/gameengine/Ketsji/KX_ISceneConverter.h
+++ b/source/gameengine/Ketsji/KX_ISceneConverter.h
@@ -64,6 +64,7 @@ public:
// handle any pending merges from asynchronous loads
virtual void MergeAsyncLoads()=0;
+ virtual void FinalizeAsyncLoads() = 0;
virtual void SetAlwaysUseExpandFraming(bool to_what) = 0;
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.cpp b/source/gameengine/Ketsji/KX_IpoActuator.cpp
deleted file mode 100644
index ec7a4146b7d..00000000000
--- a/source/gameengine/Ketsji/KX_IpoActuator.cpp
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Do Ipo stuff
- *
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file gameengine/Ketsji/KX_IpoActuator.cpp
- * \ingroup ketsji
- */
-
-#include <cmath>
-
-#include "KX_IpoActuator.h"
-#include "KX_GameObject.h"
-#include "EXP_FloatValue.h"
-
-#include "KX_KetsjiEngine.h"
-
-/* ------------------------------------------------------------------------- */
-/* Type strings */
-/* ------------------------------------------------------------------------- */
-
-const char *KX_IpoActuator::S_KX_ACT_IPO_PLAY_STRING = "Play";
-const char *KX_IpoActuator::S_KX_ACT_IPO_PINGPONG_STRING = "PingPong";
-const char *KX_IpoActuator::S_KX_ACT_IPO_FLIPPER_STRING = "Flipper";
-const char *KX_IpoActuator::S_KX_ACT_IPO_LOOPSTOP_STRING = "LoopStop";
-const char *KX_IpoActuator::S_KX_ACT_IPO_LOOPEND_STRING = "LoopEnd";
-const char *KX_IpoActuator::S_KX_ACT_IPO_KEY2KEY_STRING = "Key2key";
-const char *KX_IpoActuator::S_KX_ACT_IPO_FROM_PROP_STRING = "FromProp";
-
-/* ------------------------------------------------------------------------- */
-/* Native functions */
-/* ------------------------------------------------------------------------- */
-
-KX_IpoActuator::KX_IpoActuator(SCA_IObject* gameobj,
- const STR_String& propname,
- const STR_String& framePropname,
- float starttime,
- float endtime,
- bool recurse,
- int acttype,
- bool ipo_as_force,
- bool ipo_add,
- bool ipo_local)
- : SCA_IActuator(gameobj, KX_ACT_IPO),
- m_bNegativeEvent(false),
- m_startframe (starttime),
- m_endframe(endtime),
- m_recurse(recurse),
- m_localtime(starttime),
- m_direction(1),
- m_propname(propname),
- m_framepropname(framePropname),
- m_ipo_as_force(ipo_as_force),
- m_ipo_add(ipo_add),
- m_ipo_local(ipo_local),
- m_type(acttype)
-{
- this->ResetStartTime();
- m_bIpoPlaying = false;
-}
-
-void KX_IpoActuator::SetStart(float starttime)
-{
- m_startframe=starttime;
-}
-
-void KX_IpoActuator::SetEnd(float endtime)
-{
- m_endframe=endtime;
-}
-
-bool KX_IpoActuator::ClampLocalTime()
-{
- if (m_startframe < m_endframe)
- {
- if (m_localtime < m_startframe)
- {
- m_localtime = m_startframe;
- return true;
- }
- else if (m_localtime > m_endframe)
- {
- m_localtime = m_endframe;
- return true;
- }
- } else {
- if (m_localtime > m_startframe)
- {
- m_localtime = m_startframe;
- return true;
- }
- else if (m_localtime < m_endframe)
- {
- m_localtime = m_endframe;
- return true;
- }
- }
- return false;
-}
-
-void KX_IpoActuator::SetStartTime(float curtime)
-{
- float direction = m_startframe < m_endframe ? 1.0f : -1.0f;
-
- if (m_direction > 0)
- m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
- else
- m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
-}
-
-void KX_IpoActuator::SetLocalTime(float curtime)
-{
- float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
-
- // negative delta_time is caused by floating point inaccuracy
- // perhaps the inaccuracy could be reduced a bit
- if ((m_localtime==m_startframe || m_localtime==m_endframe) && delta_time<0.0)
- {
- delta_time = 0.0;
- }
-
- if (m_endframe < m_startframe)
- delta_time = -delta_time;
-
- if (m_direction > 0)
- m_localtime = m_startframe + delta_time;
- else
- m_localtime = m_endframe - delta_time;
-}
-
-bool KX_IpoActuator::Update(double curtime, bool frame)
-{
- // result = true if animation has to be continued, false if animation stops
- // maybe there are events for us in the queue !
- bool bNegativeEvent = false;
- bool numevents = false;
- bool bIpoStart = false;
-
- curtime -= KX_KetsjiEngine::GetSuspendedDelta();
-
- if (frame)
- {
- numevents = m_posevent || m_negevent;
- bNegativeEvent = IsNegativeEvent();
- RemoveAllEvents();
- }
-
- float start_smaller_then_end = ( m_startframe < m_endframe ? 1.0f : -1.0f);
-
- bool result=true;
- if (!bNegativeEvent)
- {
- if (m_starttime < -2.0f*fabs(m_endframe - m_startframe))
- {
- // start for all Ipo, initial start for LOOP_STOP
- m_starttime = curtime;
- m_bIpoPlaying = true;
- bIpoStart = true;
- }
- }
-
- switch ((IpoActType)m_type)
- {
-
- case KX_ACT_IPO_PLAY:
- {
- // Check if playing forwards. result = ! finished
-
- if (start_smaller_then_end > 0.f)
- result = (m_localtime < m_endframe && m_bIpoPlaying);
- else
- result = (m_localtime > m_endframe && m_bIpoPlaying);
-
- if (result)
- {
- SetLocalTime(curtime);
-
- /* Perform clamping */
- ClampLocalTime();
-
- if (bIpoStart)
- ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
- ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
- } else
- {
- m_localtime=m_startframe;
- m_direction=1;
- }
- break;
- }
- case KX_ACT_IPO_PINGPONG:
- {
- result = true;
- if (bNegativeEvent && !m_bIpoPlaying)
- result = false;
- else
- SetLocalTime(curtime);
-
- if (ClampLocalTime())
- {
- result = false;
- m_direction = -m_direction;
- }
-
- if (bIpoStart && m_direction > 0)
- ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
- ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
- break;
- }
- case KX_ACT_IPO_FLIPPER:
- {
- if (bNegativeEvent && !m_bIpoPlaying)
- result = false;
- if (numevents)
- {
- float oldDirection = m_direction;
- if (bNegativeEvent)
- m_direction = -1;
- else
- m_direction = 1;
- if (m_direction != oldDirection)
- // changing direction, reset start time
- SetStartTime(curtime);
- }
-
- SetLocalTime(curtime);
-
- if (ClampLocalTime() && m_localtime == m_startframe)
- result = false;
-
- if (bIpoStart)
- ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
- ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
- break;
- }
-
- case KX_ACT_IPO_LOOPSTOP:
- {
- if (numevents)
- {
- if (bNegativeEvent)
- {
- result = false;
- m_bNegativeEvent = false;
- numevents = false;
- }
- if (!m_bIpoPlaying)
- {
- // Ipo was stopped, make sure we will restart from where it stopped
- SetStartTime(curtime);
- if (!bNegativeEvent)
- // positive signal will restart the Ipo
- m_bIpoPlaying = true;
- }
-
- } // fall through to loopend, and quit the ipo animation immediatly
- }
- case KX_ACT_IPO_LOOPEND:
- {
- if (numevents) {
- if (bNegativeEvent && m_bIpoPlaying) {
- m_bNegativeEvent = true;
- }
- }
-
- if (bNegativeEvent && !m_bIpoPlaying) {
- result = false;
- }
- else
- {
- if (m_localtime*start_smaller_then_end < m_endframe*start_smaller_then_end)
- {
- SetLocalTime(curtime);
- }
- else {
- if (!m_bNegativeEvent) {
- /* Perform wraparound */
- SetLocalTime(curtime);
- if (start_smaller_then_end > 0.f)
- m_localtime = m_startframe + fmod(m_localtime - m_startframe, m_endframe - m_startframe);
- else
- m_localtime = m_startframe - fmod(m_startframe - m_localtime, m_startframe - m_endframe);
- SetStartTime(curtime);
- bIpoStart = true;
- }
- else
- {
- /* Perform clamping */
- m_localtime=m_endframe;
- result = false;
- m_bNegativeEvent = false;
- }
- }
- }
-
- if (m_bIpoPlaying && bIpoStart)
- ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
- ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
- break;
- }
-
- case KX_ACT_IPO_KEY2KEY:
- {
- // not implemented yet
- result = false;
- break;
- }
-
- case KX_ACT_IPO_FROM_PROP:
- {
- result = !bNegativeEvent;
-
- CValue* propval = GetParent()->GetProperty(m_propname);
- if (propval)
- {
- m_localtime = propval->GetNumber();
-
- if (bIpoStart)
- ((KX_GameObject*)GetParent())->InitIPO(m_ipo_as_force, m_ipo_add, m_ipo_local);
- ((KX_GameObject*)GetParent())->UpdateIPO(m_localtime,m_recurse);
- } else
- {
- result = false;
- }
- break;
- }
-
- default:
- result = false;
- }
-
- /* Set the property if its defined */
- if (m_framepropname[0] != '\0') {
- CValue* propowner = GetParent();
- CValue* oldprop = propowner->GetProperty(m_framepropname);
- CValue* newval = new CFloatValue(m_localtime);
- if (oldprop) {
- oldprop->SetValue(newval);
- } else {
- propowner->SetProperty(m_framepropname, newval);
- }
- newval->Release();
- }
-
- if (!result)
- {
- if (m_type != KX_ACT_IPO_LOOPSTOP)
- this->ResetStartTime();
- m_bIpoPlaying = false;
- }
-
- return result;
-}
-
-void KX_IpoActuator::ResetStartTime()
-{
- this->m_starttime = -2.0f * fabsf(this->m_endframe - this->m_startframe) - 1.0f;
-}
-
-int KX_IpoActuator::string2mode(const char *modename)
-{
- IpoActType res = KX_ACT_IPO_NODEF;
-
- if (strcmp(modename, S_KX_ACT_IPO_PLAY_STRING)==0) {
- res = KX_ACT_IPO_PLAY;
- } else if (strcmp(modename, S_KX_ACT_IPO_PINGPONG_STRING)==0) {
- res = KX_ACT_IPO_PINGPONG;
- } else if (strcmp(modename, S_KX_ACT_IPO_FLIPPER_STRING)==0) {
- res = KX_ACT_IPO_FLIPPER;
- } else if (strcmp(modename, S_KX_ACT_IPO_LOOPSTOP_STRING)==0) {
- res = KX_ACT_IPO_LOOPSTOP;
- } else if (strcmp(modename, S_KX_ACT_IPO_LOOPEND_STRING)==0) {
- res = KX_ACT_IPO_LOOPEND;
- } else if (strcmp(modename, S_KX_ACT_IPO_KEY2KEY_STRING)==0) {
- res = KX_ACT_IPO_KEY2KEY;
- } else if (strcmp(modename, S_KX_ACT_IPO_FROM_PROP_STRING)==0) {
- res = KX_ACT_IPO_FROM_PROP;
- }
-
- return res;
-}
-
-#ifdef WITH_PYTHON
-
-/* ------------------------------------------------------------------------- */
-/* Python functions */
-/* ------------------------------------------------------------------------- */
-
-
-/* Integration hooks ------------------------------------------------------- */
-PyTypeObject KX_IpoActuator::Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "KX_IpoActuator",
- sizeof(PyObjectPlus_Proxy),
- 0,
- py_base_dealloc,
- 0,
- 0,
- 0,
- 0,
- py_base_repr,
- 0,0,0,0,0,0,0,0,0,
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- 0,0,0,0,0,0,0,
- Methods,
- 0,
- 0,
- &SCA_IActuator::Type,
- 0,0,0,0,0,0,
- py_base_new
-};
-
-PyMethodDef KX_IpoActuator::Methods[] = {
- {NULL,NULL} //Sentinel
-};
-
-PyAttributeDef KX_IpoActuator::Attributes[] = {
- KX_PYATTRIBUTE_RW_FUNCTION("frameStart", KX_IpoActuator, pyattr_get_frame_start, pyattr_set_frame_start),
- KX_PYATTRIBUTE_RW_FUNCTION("frameEnd", KX_IpoActuator, pyattr_get_frame_end, pyattr_set_frame_end),
- KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_IpoActuator, m_propname),
- KX_PYATTRIBUTE_STRING_RW("framePropName", 0, MAX_PROP_NAME, false, KX_IpoActuator, m_framepropname),
- KX_PYATTRIBUTE_INT_RW("mode", KX_ACT_IPO_NODEF+1, KX_ACT_IPO_MAX-1, true, KX_IpoActuator, m_type),
- KX_PYATTRIBUTE_BOOL_RW("useIpoAsForce", KX_IpoActuator, m_ipo_as_force),
- KX_PYATTRIBUTE_BOOL_RW("useIpoAdd", KX_IpoActuator, m_ipo_add),
- KX_PYATTRIBUTE_BOOL_RW("useIpoLocal", KX_IpoActuator, m_ipo_local),
- KX_PYATTRIBUTE_BOOL_RW("useChildren", KX_IpoActuator, m_recurse),
-
- { NULL } //Sentinel
-};
-
-PyObject *KX_IpoActuator::pyattr_get_frame_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
-{
- KX_IpoActuator* self = static_cast<KX_IpoActuator*>(self_v);
- return PyFloat_FromDouble(self->m_startframe);
-}
-
-int KX_IpoActuator::pyattr_set_frame_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
-{
- KX_IpoActuator* self = static_cast<KX_IpoActuator*>(self_v);
- float param = PyFloat_AsDouble(value);
-
- if (PyErr_Occurred()) {
- PyErr_SetString(PyExc_AttributeError, "frameStart = float: KX_IpoActuator, expected a float value");
- return PY_SET_ATTR_FAIL;
- }
-
- self->m_startframe = param;
- self->ResetStartTime();
- return PY_SET_ATTR_SUCCESS;
-}
-
-PyObject *KX_IpoActuator::pyattr_get_frame_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
-{
- KX_IpoActuator* self = static_cast<KX_IpoActuator*>(self_v);
- return PyFloat_FromDouble(self->m_endframe);
-}
-
-int KX_IpoActuator::pyattr_set_frame_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
-{
- KX_IpoActuator* self = static_cast<KX_IpoActuator*>(self_v);
- float param = PyFloat_AsDouble(value);
-
- if (PyErr_Occurred()) {
- PyErr_SetString(PyExc_AttributeError, "frameEnd = float: KX_IpoActuator, expected a float value");
- return PY_SET_ATTR_FAIL;
- }
-
- self->m_endframe = param;
- self->ResetStartTime();
- return PY_SET_ATTR_SUCCESS;
-}
-
-#endif // WITH_PYTHON
-
-/* eof */
diff --git a/source/gameengine/Ketsji/KX_IpoActuator.h b/source/gameengine/Ketsji/KX_IpoActuator.h
deleted file mode 100644
index 1c2f4e49b72..00000000000
--- a/source/gameengine/Ketsji/KX_IpoActuator.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file KX_IpoActuator.h
- * \ingroup ketsji
- * \brief Do an object ipo
- */
-
-#ifndef __KX_IPOACTUATOR_H__
-#define __KX_IPOACTUATOR_H__
-
-#include "SCA_IActuator.h"
-
-class KX_IpoActuator : public SCA_IActuator
-{
- Py_Header
-private:
- /** Computes the IPO start time from the current time
- * and the current frame. */
- void SetStartTime(float curtime);
- /** Computes the current frame from the current time
- * and the IPO start time. */
- void SetLocalTime(float curtime);
- /** Ensures the current frame is between the start and
- * end frames. */
- bool ClampLocalTime();
-
-protected:
- bool m_bNegativeEvent;
-
- /** Begin frame of the ipo. */
- float m_startframe;
-
- /** End frame of the ipo. */
- float m_endframe;
-
- /** Include children in the transforms? */
- bool m_recurse;
-
- /** Current active frame of the ipo. */
- float m_localtime;
-
- /** The time this ipo started at. */
- float m_starttime;
-
- /** play backwards or forwards? (positive means forward). */
- float m_direction;
-
- /** Name of the property (only used in from_prop mode). */
- STR_String m_propname;
-
- /** Name of the property where we write the current frame number */
- STR_String m_framepropname;
-
- /** Interpret the ipo as a force? */
- bool m_ipo_as_force;
-
- /** Add Ipo curve to current loc/rot/scale */
- bool m_ipo_add;
-
- /** The Ipo curve is applied in local coordinates */
- bool m_ipo_local;
-
- bool m_bIpoPlaying;
-
- /** Reset/Update the start time*/
- void ResetStartTime();
-
-public:
- enum IpoActType
- {
- KX_ACT_IPO_NODEF = 0,
- KX_ACT_IPO_PLAY,
- KX_ACT_IPO_PINGPONG,
- KX_ACT_IPO_FLIPPER,
- KX_ACT_IPO_LOOPSTOP,
- KX_ACT_IPO_LOOPEND,
- KX_ACT_IPO_KEY2KEY,
- KX_ACT_IPO_FROM_PROP,
- KX_ACT_IPO_MAX
- };
-
-#ifdef WITH_PYTHON
- static PyObject* pyattr_get_frame_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
- static int pyattr_set_frame_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
- static PyObject* pyattr_get_frame_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
- static int pyattr_set_frame_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
-#endif
- static const char *S_KX_ACT_IPO_PLAY_STRING;
- static const char *S_KX_ACT_IPO_PINGPONG_STRING;
- static const char *S_KX_ACT_IPO_FLIPPER_STRING;
- static const char *S_KX_ACT_IPO_LOOPSTOP_STRING;
- static const char *S_KX_ACT_IPO_LOOPEND_STRING;
- static const char *S_KX_ACT_IPO_KEY2KEY_STRING;
- static const char *S_KX_ACT_IPO_FROM_PROP_STRING;
-
- int string2mode(const char *modename);
-
- int m_type;
-
- KX_IpoActuator(SCA_IObject* gameobj,
- const STR_String& propname,
- const STR_String& framePropname,
- float starttime,
- float endtime,
- bool recurse,
- int acttype,
- bool ipo_as_force,
- bool ipo_add,
- bool ipo_local);
- virtual ~KX_IpoActuator() {};
-
- virtual CValue* GetReplica() {
- KX_IpoActuator* replica = new KX_IpoActuator(*this);//m_float,GetName());
- replica->ProcessReplica();
- return replica;
- };
-
- void SetStart(float starttime);
- void SetEnd(float endtime);
- virtual bool Update(double curtime, bool frame);
-
- /* --------------------------------------------------------------------- */
- /* Python interface ---------------------------------------------------- */
- /* --------------------------------------------------------------------- */
-
-};
-
-#endif /* __KX_IPOACTUATOR_H__ */
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 72c512589a4..7237c473332 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -75,6 +75,8 @@
#include "KX_NavMeshObject.h"
+#include "BL_Action.h" // For managing action lock.
+
#define DEFAULT_LOGIC_TIC_RATE 60.0
//#define DEFAULT_PHYSICS_TIC_RATE 60.0
@@ -105,7 +107,7 @@ double KX_KetsjiEngine::m_suspendedtime = 0.0;
double KX_KetsjiEngine::m_suspendeddelta = 0.0;
double KX_KetsjiEngine::m_average_framerate = 0.0;
bool KX_KetsjiEngine::m_restrict_anim_fps = false;
-short KX_KetsjiEngine::m_exitkey = 130; //ESC Key
+short KX_KetsjiEngine::m_exitkey = 130; // ESC Key
/**
@@ -126,6 +128,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_bInitialized(false),
m_activecam(0),
m_bFixedTime(false),
+ m_useExternalClock(false),
m_firstframe(true),
@@ -133,17 +136,20 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_clockTime(0.f),
m_previousClockTime(0.f),
m_previousAnimTime(0.f),
+ m_timescale(1.0f),
+ m_previousRealTime(0.0f),
m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
m_exitstring(""),
- m_cameraZoom(1.0),
+ m_cameraZoom(1.0f),
m_overrideCam(false),
m_overrideCamUseOrtho(false),
- m_overrideCamNear(0.0),
- m_overrideCamFar(0.0),
+ m_overrideCamNear(0.0f),
+ m_overrideCamFar(0.0f),
+ m_overrideCamZoom(1.0f),
m_stereo(false),
m_curreye(0),
@@ -164,9 +170,9 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_hideCursor(false),
m_overrideFrameColor(false),
- m_overrideFrameColorR(0.0),
- m_overrideFrameColorG(0.0),
- m_overrideFrameColorB(0.0),
+ m_overrideFrameColorR(0.0f),
+ m_overrideFrameColorG(0.0f),
+ m_overrideFrameColorB(0.0f),
m_usedome(false)
{
@@ -181,6 +187,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
#endif
m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS);
+
+ BL_Action::InitLock();
}
@@ -200,6 +208,8 @@ KX_KetsjiEngine::~KX_KetsjiEngine()
if (m_taskscheduler)
BLI_task_scheduler_free(m_taskscheduler);
+
+ BL_Action::EndLock();
}
@@ -300,7 +310,7 @@ void KX_KetsjiEngine::RenderDome()
KX_SceneList::iterator sceneit;
KX_Scene* scene = NULL;
- int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
+ int n_renders=m_dome->GetNumberRenders(); // usually 4 or 6
for (int i=0;i<n_renders;i++) {
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
@@ -317,7 +327,7 @@ void KX_KetsjiEngine::RenderDome()
if (i == 0) {
RenderShadowBuffers(scene);
}
- // Avoid drawing the scene with the active camera twice when it's viewport is enabled
+ // Avoid drawing the scene with the active camera twice when its viewport is enabled
if (cam && !cam->GetViewport())
{
if (scene->IsClearingZBuffer())
@@ -327,7 +337,7 @@ void KX_KetsjiEngine::RenderDome()
// do the rendering
m_dome->RenderDomeFrame(scene,cam, i);
- //render all the font objects for this scene
+ // render all the font objects for this scene
scene->RenderFonts();
}
@@ -345,7 +355,7 @@ void KX_KetsjiEngine::RenderDome()
// do the rendering
m_dome->RenderDomeFrame(scene, (*it),i);
- //render all the font objects for this scene
+ // render all the font objects for this scene
scene->RenderFonts();
}
@@ -404,6 +414,7 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo)
m_clockTime = m_kxsystem->GetTimeInSeconds();
m_frameTime = m_kxsystem->GetTimeInSeconds();
m_previousClockTime = m_kxsystem->GetTimeInSeconds();
+ m_previousRealTime = m_kxsystem->GetTimeInSeconds();
m_firstframe = true;
m_bInitialized = true;
@@ -427,7 +438,6 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo)
m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo);
m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame);
}
-
}
void KX_KetsjiEngine::ClearFrame()
@@ -518,8 +528,8 @@ void KX_KetsjiEngine::EndFrame()
for (int i = tc_first; i < tc_numCategories; ++i) {
double time = m_logger->GetAverage((KX_TimeCategory)i);
PyObject *val = PyTuple_New(2);
- PyTuple_SetItem(val, 0, PyFloat_FromDouble(time*1000.f));
- PyTuple_SetItem(val, 1, PyFloat_FromDouble(time/tottime * 100.f));
+ PyTuple_SetItem(val, 0, PyFloat_FromDouble(time*1000.0));
+ PyTuple_SetItem(val, 1, PyFloat_FromDouble(time/tottime * 100.0));
PyDict_SetItemString(m_pyprofiledict, m_profileLabels[i], val);
Py_DECREF(val);
@@ -528,7 +538,7 @@ void KX_KetsjiEngine::EndFrame()
m_average_framerate = 1.0/tottime;
- // Go to next profiling measurement, time spend after this call is shown in the next frame.
+ // Go to next profiling measurement, time spent after this call is shown in the next frame.
m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds());
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
@@ -547,7 +557,7 @@ void KX_KetsjiEngine::EndFrame()
bool KX_KetsjiEngine::NextFrame()
{
- double timestep = 1.0/m_ticrate;
+ double timestep = m_timescale / m_ticrate;
double framestep = timestep;
// static hidden::Clock sClock;
@@ -556,32 +566,61 @@ bool KX_KetsjiEngine::NextFrame()
//float dt = sClock.getTimeMicroseconds() * 0.000001f;
//sClock.reset();
- if (m_bFixedTime) {
- m_clockTime += timestep;
- }
- else {
- // m_clockTime += dt;
- m_clockTime = m_kxsystem->GetTimeInSeconds();
+ /*
+ * Clock advancement. There is basically three case:
+ * - m_useExternalClock is true, the user is responsible to advance the time
+ * manually using setClockTime, so here, we do not do anything.
+ * - m_useExternalClock is false, m_bFixedTime is true, we advance for one
+ * timestep, which already handle the time scaling parameter
+ * - m_useExternalClock is false, m_bFixedTime is false, we consider how much
+ * time has elapsed since last call and we scale this time by the time
+ * scaling parameter. If m_timescale is 1.0 (default value), the clock
+ * corresponds to the computer clock.
+ *
+ * Once clockTime has been computed, we will compute how many logic frames
+ * will be executed before the next rendering phase (which will occur at "clockTime").
+ * The game time elapsing between two logic frames (called framestep)
+ * depends on several variables:
+ * - ticrate
+ * - max_physic_frame
+ * - max_logic_frame
+ * XXX The logic over computation framestep is definitively not clear (and
+ * I'm not even sure it is correct). If needed frame is strictly greater
+ * than max_physics_frame, we are doing a jump in game time, but keeping
+ * framestep = 1 / ticrate, while if frames is greater than
+ * max_logic_frame, we increase framestep.
+ *
+ * XXX render.fps is not considred anywhere.
+ */
+ if (!m_useExternalClock) {
+ if (m_bFixedTime) {
+ m_clockTime += timestep;
+ }
+ else {
+ double current_time = m_kxsystem->GetTimeInSeconds();
+ double dt = current_time - m_previousRealTime;
+ m_previousRealTime = current_time;
+ // m_clockTime += dt;
+ m_clockTime += dt * m_timescale;
+ }
}
double deltatime = m_clockTime - m_frameTime;
- if (deltatime<0.f)
+ if (deltatime<0.0)
{
- // We got here too quickly, which means there is nothing todo, just return and don't render.
+ // We got here too quickly, which means there is nothing to do, just return and don't render.
// Not sure if this is the best fix, but it seems to stop the jumping framerate issue (#33088)
return false;
}
-
// Compute the number of logic frames to do each update (fixed tic bricks)
- int frames =int(deltatime*m_ticrate+1e-6);
+ int frames = int(deltatime * m_ticrate / m_timescale + 1e-6);
// if (frames>1)
// printf("****************************************");
// printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames);
// if (!frames)
// PIL_sleep_ms(1);
-
KX_SceneList::iterator sceneit;
if (frames>m_maxPhysicsFrame)
@@ -620,13 +659,13 @@ bool KX_KetsjiEngine::NextFrame()
* update. */
m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true);
- m_sceneconverter->resetNoneDynamicObjectToIpo();//this is for none dynamic objects with ipo
+ m_sceneconverter->resetNoneDynamicObjectToIpo(); // this is for none dynamic objects with ipo
scene->UpdateObjectActivity();
if (!scene->IsSuspended())
{
- // if the scene was suspended recalcutlate the delta tu "curtime"
+ // if the scene was suspended recalculate the delta tu "curtime"
m_suspendedtime = scene->getSuspendedTime();
if (scene->getSuspendedTime()!=0.0)
scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime());
@@ -729,7 +768,7 @@ bool KX_KetsjiEngine::NextFrame()
frames--;
}
- // Start logging time spend outside main loop
+ // Start logging time spent outside main loop
m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
return doRender;
@@ -798,13 +837,13 @@ void KX_KetsjiEngine::Render()
// pass the scene's worldsettings to the rasterizer
scene->GetWorldInfo()->UpdateWorldSettings();
- // this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes
+ // this is now done incrementally in KX_Scene::CalculateVisibleMeshes
//scene->UpdateMeshTransformations();
// shadow buffers
RenderShadowBuffers(scene);
- // Avoid drawing the scene with the active camera twice when it's viewport is enabled
+ // Avoid drawing the scene with the active camera twice when its viewport is enabled
if (cam && !cam->GetViewport())
{
if (scene->IsClearingZBuffer())
@@ -858,7 +897,7 @@ void KX_KetsjiEngine::Render()
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
- //pass the scene, for picking and raycasting (shadows)
+ // pass the scene, for picking and raycasting (shadows)
m_rasterizer->SetAuxilaryClientInfo(scene);
// do the rendering
@@ -908,10 +947,10 @@ void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame)
int KX_KetsjiEngine::GetExitCode()
{
- // if a gameactuator has set an exitcode or if there are no scenes left
+ // if a game actuator has set an exit code or if there are no scenes left
if (!m_exitcode)
{
- if (m_scenes.begin()==m_scenes.end())
+ if (m_scenes.begin() == m_scenes.end())
m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT;
}
@@ -970,11 +1009,15 @@ void KX_KetsjiEngine::SetCameraOverrideLens(float lens)
m_overrideCamLens = lens;
}
+void KX_KetsjiEngine::SetCameraOverrideZoom(float camzoom)
+{
+ m_overrideCamZoom = camzoom;
+}
+
void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport)
{
- // In this function we make sure the rasterizer settings are upto
- // date. We compute the viewport so that logic
- // using this information is upto date.
+ // In this function we make sure the rasterizer settings are up-to-date.
+ // We compute the viewport so that logic using this information is up-to-date.
// Note we postpone computation of the projection matrix
// so that we are using the latest camera position.
@@ -1019,6 +1062,10 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect
void KX_KetsjiEngine::UpdateAnimations(KX_Scene *scene)
{
+ if (scene->IsSuspended()) {
+ return;
+ }
+
// Handle the animations independently of the logic time step
if (GetRestrictAnimationFPS()) {
double anim_timestep = 1.0 / KX_GetActiveScene()->GetAnimationFPS();
@@ -1049,7 +1096,9 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
raslight->Update();
- if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED && raslight->HasShadowBuffer()) {
+ if (light->GetVisible() && m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED &&
+ raslight->HasShadowBuffer())
+ {
/* make temporary camera */
RAS_CameraData camdata = RAS_CameraData();
KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true);
@@ -1122,7 +1171,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
if (override_camera && m_overrideCamUseOrtho) {
m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat);
if (!cam->hasValidProjectionMatrix()) {
- // needed to get frustrum planes for culling
+ // needed to get frustum planes for culling
MT_Matrix4x4 projmat;
projmat.setValue(m_overrideCamProjMat.getPointer());
cam->SetProjectionMatrix(projmat);
@@ -1144,6 +1193,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
farfrust = m_overrideCamFar;
}
+ float camzoom = override_camera ? m_overrideCamZoom : m_cameraZoom;
if (orthographic) {
RAS_FramingManager::ComputeOrtho(
@@ -1159,10 +1209,10 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
frustum
);
if (!cam->GetViewport()) {
- frustum.x1 *= m_cameraZoom;
- frustum.x2 *= m_cameraZoom;
- frustum.y1 *= m_cameraZoom;
- frustum.y2 *= m_cameraZoom;
+ frustum.x1 *= camzoom;
+ frustum.x2 *= camzoom;
+ frustum.y1 *= camzoom;
+ frustum.y2 *= camzoom;
}
projmat = m_rasterizer->GetOrthoMatrix(
frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar);
@@ -1184,10 +1234,10 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
);
if (!cam->GetViewport()) {
- frustum.x1 *= m_cameraZoom;
- frustum.x2 *= m_cameraZoom;
- frustum.y1 *= m_cameraZoom;
- frustum.y2 *= m_cameraZoom;
+ frustum.x1 *= camzoom;
+ frustum.x2 *= camzoom;
+ frustum.y1 *= camzoom;
+ frustum.y2 *= camzoom;
}
projmat = m_rasterizer->GetFrustumMatrix(
frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength);
@@ -1230,9 +1280,9 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
scene->RenderBuckets(camtrans, m_rasterizer);
- //render all the font objects for this scene
+ // render all the font objects for this scene
scene->RenderFonts();
-
+
if (scene->GetPhysicsEnvironment())
scene->GetPhysicsEnvironment()->DebugDrawWorld();
}
@@ -1263,6 +1313,7 @@ void KX_KetsjiEngine::StopEngine()
{
if (m_bInitialized)
{
+ m_sceneconverter->FinalizeAsyncLoads();
if (m_animation_record)
{
@@ -1284,7 +1335,7 @@ void KX_KetsjiEngine::StopEngine()
}
// Scene Management is able to switch between scenes
-// and have several scene's running in parallel
+// and have several scenes running in parallel
void KX_KetsjiEngine::AddScene(KX_Scene* scene)
{
m_scenes.push_back(scene);
@@ -1300,7 +1351,7 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
SG_SetActiveStage(SG_STAGE_SCENE);
// if there is no activecamera, or the camera is being
- // overridden we need to construct a temporarily camera
+ // overridden we need to construct a temporary camera
if (!scene->GetActiveCamera() || override_camera)
{
KX_Camera* activecam = NULL;
@@ -1317,7 +1368,7 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata);
activecam->SetName("__default__cam__");
- // set transformation
+ // set transformation
if (override_camera) {
const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat;
MT_Transform trans = MT_Transform(cammatdata.getPointer());
@@ -1328,8 +1379,8 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
activecam->NodeSetLocalOrientation(camtrans.getBasis());
activecam->NodeUpdateGS(0);
} else {
- activecam->NodeSetLocalPosition(MT_Point3(0.0, 0.0, 0.0));
- activecam->NodeSetLocalOrientation(MT_Vector3(0.0, 0.0, 0.0));
+ activecam->NodeSetLocalPosition(MT_Point3(0.0f, 0.0f, 0.0f));
+ activecam->NodeSetLocalOrientation(MT_Vector3(0.0f, 0.0f, 0.0f));
activecam->NodeUpdateGS(0);
}
@@ -1337,7 +1388,7 @@ void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene)
scene->SetActiveCamera(activecam);
scene->GetObjectList()->Add(activecam->AddRef());
scene->GetRootParentList()->Add(activecam->AddRef());
- //done with activecam
+ // done with activecam
activecam->Release();
}
@@ -1394,7 +1445,7 @@ void KX_KetsjiEngine::RenderDebugProperties()
m_canvas->GetWidth() /* RdV, TODO ?? */,
m_canvas->GetHeight() /* RdV, TODO ?? */);
- debugtxt.Format("%5.1fms (%.1ffps)", tottime * 1000.f, 1.0/tottime);
+ debugtxt.Format("%5.1fms (%.1ffps)", tottime * 1000.0f, 1.0f/tottime);
m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
debugtxt.ReadPtr(),
xcoord + const_xindent + profile_indent,
@@ -1417,21 +1468,21 @@ void KX_KetsjiEngine::RenderDebugProperties()
double time = m_logger->GetAverage((KX_TimeCategory)j);
- debugtxt.Format("%5.2fms | %d%%", time*1000.f, (int)(time/tottime * 100.f));
+ debugtxt.Format("%5.2fms | %d%%", (float)time*1000.f, (int)((float)time/tottime * 100.f));
m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED,
debugtxt.ReadPtr(),
xcoord + const_xindent + profile_indent, ycoord,
m_canvas->GetWidth(),
m_canvas->GetHeight());
- m_rasterizer->RenderBox2D(xcoord + (int)(2.2 * profile_indent), ycoord, m_canvas->GetWidth(), m_canvas->GetHeight(), time/tottime);
+ m_rasterizer->RenderBox2D(xcoord + (int)(2.2f * profile_indent), ycoord, m_canvas->GetWidth(), m_canvas->GetHeight(), (float)time/tottime);
ycoord += const_ysize;
}
}
// Add the ymargin for titles below the other section of debug info
ycoord += title_y_top_margin;
- /* Property display*/
+ /* Property display */
if (m_show_debug_properties) {
/* Title for debugging("Debug properties") */
@@ -1661,7 +1712,7 @@ void KX_KetsjiEngine::AddScheduledScenes()
bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
{
- // Don't allow replacement if the new scene doesn't exists.
+ // Don't allow replacement if the new scene doesn't exist.
// Allows smarter game design (used to have no check here).
// Note that it creates a small backward compatbility issue
// for a game that did a replace followed by a lib load with the
@@ -1738,13 +1789,17 @@ void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime)
m_bFixedTime = bUseFixedTime;
}
+void KX_KetsjiEngine::SetUseExternalClock(bool useExternalClock)
+{
+ m_useExternalClock = useExternalClock;
+}
void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame)
{
m_animation_record = animation_record;
if (animation_record)
{
- //when recording physics keyframes, run at a variable (capped) frame rate (fixed time == full speed)
+ // when recording physics keyframes, run at a variable (capped) frame rate (fixed time == full speed)
m_bFixedTime = false;
}
m_currentFrame = startFrame;
@@ -1765,6 +1820,11 @@ bool KX_KetsjiEngine::GetUseFixedTime(void) const
return m_bFixedTime;
}
+bool KX_KetsjiEngine::GetUseExternalClock(void) const
+{
+ return m_useExternalClock;
+}
+
double KX_KetsjiEngine::GetSuspendedDelta()
{
return m_suspendeddelta;
@@ -1780,6 +1840,16 @@ void KX_KetsjiEngine::SetTicRate(double ticrate)
m_ticrate = ticrate;
}
+double KX_KetsjiEngine::GetTimeScale() const
+{
+ return m_timescale;
+}
+
+void KX_KetsjiEngine::SetTimeScale(double timescale)
+{
+ m_timescale = timescale;
+}
+
int KX_KetsjiEngine::GetMaxLogicFrame()
{
return m_maxLogicFrame;
@@ -1820,6 +1890,11 @@ double KX_KetsjiEngine::GetClockTime(void) const
return m_clockTime;
}
+void KX_KetsjiEngine::SetClockTime(double externalClockTime)
+{
+ m_clockTime = externalClockTime;
+}
+
double KX_KetsjiEngine::GetFrameTime(void) const
{
return m_frameTime;
@@ -1968,12 +2043,12 @@ void KX_KetsjiEngine::Resize()
{
KX_SceneList::iterator sceneit;
- /* extended mode needs to recalculate camera frustrums when */
+ /* extended mode needs to recalculate camera frusta when */
KX_Scene* firstscene = *m_scenes.begin();
const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
if (framesettings.FrameType() == RAS_FrameSettings::e_frame_extend) {
- for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) {
+ for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++) {
KX_Camera* cam = ((KX_Scene *)*sceneit)->GetActiveCamera();
cam->InvalidateProjectionMatrix();
}
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index 04e09c8db15..3b8cec2ac82 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -103,16 +103,19 @@ private:
bool m_bInitialized;
int m_activecam;
bool m_bFixedTime;
+ bool m_useExternalClock;
bool m_firstframe;
int m_currentFrame;
- double m_frameTime;//discrete timestamp of the 'game logic frame'
- double m_clockTime;//current time
- double m_previousClockTime;//previous clock time
- double m_previousAnimTime; //the last time animations were updated
+ double m_frameTime; // current logic game time
+ double m_clockTime; // game time for the next rendering step
+ double m_previousClockTime; // game time of the previous rendering step
+ double m_previousAnimTime; //game time when the animations were last updated
double m_remainingTime;
+ double m_timescale; // time scaling parameter. if > 1.0, time goes faster than real-time. If < 1.0, times goes slower than real-time.
+ double m_previousRealTime;
static int m_maxLogicFrame; /* maximum number of consecutive logic frame */
static int m_maxPhysicsFrame; /* maximum number of consecutive physics frame */
@@ -140,6 +143,8 @@ private:
float m_overrideCamNear;
float m_overrideCamFar;
float m_overrideCamLens;
+ /// Default camera zoom.
+ float m_overrideCamZoom;
bool m_stereo;
int m_curreye;
@@ -266,6 +271,7 @@ public:
void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport);
+ /// Sets zoom for camera objects, useful only with extend and scale framing mode.
void SetCameraZoom(float camzoom);
void EnableCameraOverride(const STR_String& forscene);
@@ -275,6 +281,8 @@ public:
void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat);
void SetCameraOverrideClipping(float near, float far);
void SetCameraOverrideLens(float lens);
+ /// Sets zoom for default camera, = 2 in embedded mode.
+ void SetCameraOverrideZoom(float camzoom);
// Update animations for object in this scene
void UpdateAnimations(KX_Scene *scene);
@@ -292,15 +300,37 @@ public:
bool GetUseFixedTime(void) const;
/**
- * Returns current render frame clock time
+ * Sets if the BGE relies on a external clock or its own internal clock
+ */
+ void SetUseExternalClock(bool bUseExternalClock);
+
+ /**
+ * Returns if we rely on an external clock
+ * \return Current setting
+ */
+ bool GetUseExternalClock(void) const;
+
+ /**
+ * Returns next render frame game time
*/
double GetClockTime(void) const;
+
+ /**
+ * Set the next render frame game time. It will impact also frame time, as
+ * this one is derived from clocktime
+ */
+ void SetClockTime(double externalClockTime);
+
/**
- * Returns current logic frame clock time
+ * Returns current logic frame game time
*/
double GetFrameTime(void) const;
+ /**
+ * Returns the real (system) time
+ */
double GetRealTime(void) const;
+
/**
* Returns the difference between the local time of the scene (when it
* was running and not suspended) and the "curtime"
@@ -356,6 +386,16 @@ public:
*/
static double GetAverageFrameRate();
+ /**
+ * Gets the time scale multiplier
+ */
+ double GetTimeScale() const;
+
+ /**
+ * Sets the time scale multiplier
+ */
+ void SetTimeScale(double scale);
+
static void SetExitKey(short key);
static short GetExitKey();
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 0dec5715588..9ccf60b15ce 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -158,6 +158,16 @@ PyAttributeDef KX_LightObject::Attributes[] = {
KX_PYATTRIBUTE_RW_FUNCTION("quad_attenuation", KX_LightObject, pyattr_get_quad_attenuation, pyattr_set_quad_attenuation),
KX_PYATTRIBUTE_RW_FUNCTION("spotsize", KX_LightObject, pyattr_get_spotsize, pyattr_set_spotsize),
KX_PYATTRIBUTE_RW_FUNCTION("spotblend", KX_LightObject, pyattr_get_spotblend, pyattr_set_spotblend),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowClipStart", KX_LightObject, pyattr_get_shadow_clip_start),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowClipEnd", KX_LightObject, pyattr_get_shadow_clip_end),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowFrustumSize", KX_LightObject, pyattr_get_shadow_frustum_size),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowBias", KX_LightObject, pyattr_get_shadow_bias),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowBleedBias", KX_LightObject, pyattr_get_shadow_bleed_bias),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowBindId", KX_LightObject, pyattr_get_shadow_bind_code),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowMapType", KX_LightObject, pyattr_get_shadow_map_type),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowColor", KX_LightObject, pyattr_get_shadow_color),
+ KX_PYATTRIBUTE_RO_FUNCTION("useShadow", KX_LightObject, pyattr_get_shadow_active),
+ KX_PYATTRIBUTE_RO_FUNCTION("shadowMatrix", KX_LightObject, pyattr_get_shadow_matrix),
KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst),
KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst),
KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst),
@@ -219,6 +229,66 @@ int KX_LightObject::pyattr_set_energy(void *self_v, const KX_PYATTRIBUTE_DEF *at
return PY_SET_ATTR_FAIL;
}
+PyObject *KX_LightObject::pyattr_get_shadow_clip_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyFloat_FromDouble(self->m_lightobj->m_shadowclipstart);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_clip_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyFloat_FromDouble(self->m_lightobj->m_shadowclipend);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_frustum_size(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyFloat_FromDouble(self->m_lightobj->m_shadowfrustumsize);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_bind_code(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyLong_FromLong(self->m_lightobj->GetShadowBindCode());
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyFloat_FromDouble(self->m_lightobj->m_shadowbias);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_bleed_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyFloat_FromDouble(self->m_lightobj->m_shadowbleedbias);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_map_type(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyLong_FromLong(self->m_lightobj->m_shadowmaptype);
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyObjectFrom(self->m_lightobj->GetShadowMatrix());
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyColorFromVector(MT_Vector3(self->m_lightobj->m_shadowcolor));
+}
+
+PyObject *KX_LightObject::pyattr_get_shadow_active(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_LightObject *self = static_cast<KX_LightObject *>(self_v);
+ return PyBool_FromLong(self->m_lightobj->HasShadowBuffer());
+}
+
PyObject *KX_LightObject::pyattr_get_distance(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
@@ -231,8 +301,8 @@ int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF *
if (PyFloat_Check(value)) {
float val = PyFloat_AsDouble(value);
- if (val < 0.01)
- val = 0.01;
+ if (val < 0.01f)
+ val = 0.01f;
else if (val > 5000.f)
val = 5000.f;
@@ -326,13 +396,13 @@ int KX_LightObject::pyattr_set_spotsize(void *self_v, const KX_PYATTRIBUTE_DEF *
KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
if (PyFloat_Check(value)) {
- float val = PyFloat_AsDouble(value);
- if (val < 0.f)
- val = 0.f;
- else if (val > 180.f)
- val = 180.f;
+ double val = PyFloat_AsDouble(value);
+ if (val < 0.0)
+ val = 0.0;
+ else if (val > 180.0)
+ val = 180.0;
- self->m_lightobj->m_spotsize = DEG2RAD(val);
+ self->m_lightobj->m_spotsize = (float)DEG2RAD(val);
return PY_SET_ATTR_SUCCESS;
}
@@ -350,7 +420,7 @@ int KX_LightObject::pyattr_set_spotblend(void *self_v, const KX_PYATTRIBUTE_DEF
KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
if (PyFloat_Check(value)) {
- float val = PyFloat_AsDouble(value);
+ float val = (float)PyFloat_AsDouble(value);
if (val < 0.f)
val = 0.f;
else if (val > 1.f)
diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h
index 3a58584223d..b446acd6e63 100644
--- a/source/gameengine/Ketsji/KX_Light.h
+++ b/source/gameengine/Ketsji/KX_Light.h
@@ -70,6 +70,16 @@ public:
static int pyattr_set_layer(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_energy(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_energy(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject *pyattr_get_shadow_clip_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_clip_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_frustum_size(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_bind_code(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_bleed_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_map_type(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_active(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_shadow_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_distance(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_distance(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp
index c98766c9c81..8da3542b4d6 100644
--- a/source/gameengine/Ketsji/KX_MeshProxy.cpp
+++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp
@@ -43,6 +43,8 @@
#include "KX_PyMath.h"
+#include "SCA_LogicManager.h"
+
#include "EXP_PyObjectPlus.h"
PyTypeObject KX_MeshProxy::Type = {
@@ -405,7 +407,7 @@ PyObject *KX_MeshProxy::pyattr_get_numPolygons(void *self_v, const KX_PYATTRIBUT
}
/* a close copy of ConvertPythonToGameObject but for meshes */
-bool ConvertPythonToMesh(PyObject *value, RAS_MeshObject **object, bool py_none_ok, const char *error_prefix)
+bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, RAS_MeshObject **object, bool py_none_ok, const char *error_prefix)
{
if (value==NULL) {
PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix);
@@ -425,7 +427,7 @@ bool ConvertPythonToMesh(PyObject *value, RAS_MeshObject **object, bool py_none_
}
if (PyUnicode_Check(value)) {
- *object = (RAS_MeshObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetMeshByName(STR_String( _PyUnicode_AsString(value) ));
+ *object = (RAS_MeshObject*)logicmgr->GetMeshByName(STR_String( _PyUnicode_AsString(value) ));
if (*object) {
return true;
diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h
index 4a4358bff3a..dbd7987f785 100644
--- a/source/gameengine/Ketsji/KX_MeshProxy.h
+++ b/source/gameengine/Ketsji/KX_MeshProxy.h
@@ -36,8 +36,9 @@
#include "SCA_IObject.h"
+class SCA_LogicManager;
/* utility conversion function */
-bool ConvertPythonToMesh(PyObject *value, class RAS_MeshObject **object, bool py_none_ok, const char *error_prefix);
+bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, class RAS_MeshObject **object, bool py_none_ok, const char *error_prefix);
class KX_MeshProxy : public CValue
{
diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp
index 154ad1da3a1..6aa0d588b50 100644
--- a/source/gameengine/Ketsji/KX_MouseActuator.cpp
+++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp
@@ -125,8 +125,8 @@ bool KX_MouseActuator::Update()
float position[2];
float movement[2];
MT_Vector3 rotation;
- float setposition[2] = {0.0};
- float center_x = 0.5, center_y = 0.5;
+ float setposition[2] = {0.0f};
+ float center_x = 0.5f, center_y = 0.5f;
getMousePosition(position);
@@ -135,14 +135,14 @@ bool KX_MouseActuator::Update()
//preventing undesired drifting when resolution is odd
if ((m_canvas->GetWidth() % 2) != 0) {
- center_x = ((m_canvas->GetWidth() - 1.0) / 2.0) / (m_canvas->GetWidth());
+ center_x = ((m_canvas->GetWidth() - 1.0f) / 2.0f) / (m_canvas->GetWidth());
}
if ((m_canvas->GetHeight() % 2) != 0) {
- center_y = ((m_canvas->GetHeight() - 1.0) / 2.0) / (m_canvas->GetHeight());
+ center_y = ((m_canvas->GetHeight() - 1.0f) / 2.0f) / (m_canvas->GetHeight());
}
//preventing initial skipping.
- if ((m_oldposition[0] <= -0.9) && (m_oldposition[1] <= -0.9)) {
+ if ((m_oldposition[0] <= -0.9f) && (m_oldposition[1] <= -0.9f)) {
if (m_reset_x) {
m_oldposition[0] = center_x;
@@ -173,21 +173,21 @@ bool KX_MouseActuator::Update()
movement[0] -= m_oldposition[0];
}
- movement[0] *= -1.0;
+ movement[0] *= -1.0f;
/* Don't apply the rotation when we are under a certain threshold for mouse
movement */
- if (((movement[0] > (m_threshold[0] / 10.0)) ||
- ((movement[0] * (-1.0)) > (m_threshold[0] / 10.0)))) {
+ if (((movement[0] > (m_threshold[0] / 10.0f)) ||
+ ((movement[0] * (-1.0f)) > (m_threshold[0] / 10.0f)))) {
movement[0] *= m_sensitivity[0];
- if ((m_limit_x[0] != 0.0) && ((m_angle[0] + movement[0]) <= m_limit_x[0])) {
+ if ((m_limit_x[0] != 0.0f) && ((m_angle[0] + movement[0]) <= m_limit_x[0])) {
movement[0] = m_limit_x[0] - m_angle[0];
}
- if ((m_limit_x[1] != 0.0) && ((m_angle[0] + movement[0]) >= m_limit_x[1])) {
+ if ((m_limit_x[1] != 0.0f) && ((m_angle[0] + movement[0]) >= m_limit_x[1])) {
movement[0] = m_limit_x[1] - m_angle[0];
}
@@ -196,17 +196,17 @@ bool KX_MouseActuator::Update()
switch (m_object_axis[0]) {
case KX_ACT_MOUSE_OBJECT_AXIS_X:
{
- rotation = MT_Vector3(movement[0], 0.0, 0.0);
+ rotation = MT_Vector3(movement[0], 0.0f, 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
{
- rotation = MT_Vector3(0.0, movement[0], 0.0);
+ rotation = MT_Vector3(0.0f, movement[0], 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
{
- rotation = MT_Vector3(0.0, 0.0, movement[0]);
+ rotation = MT_Vector3(0.0f, 0.0f, movement[0]);
break;
}
default:
@@ -231,21 +231,21 @@ bool KX_MouseActuator::Update()
movement[1] -= m_oldposition[1];
}
- movement[1] *= -1.0;
+ movement[1] *= -1.0f;
/* Don't apply the rotation when we are under a certain threshold for mouse
movement */
- if (((movement[1] > (m_threshold[1] / 10.0)) ||
- ((movement[1] * (-1.0)) > (m_threshold[1] / 10.0)))) {
+ if (((movement[1] > (m_threshold[1] / 10.0f)) ||
+ ((movement[1] * (-1.0f)) > (m_threshold[1] / 10.0f)))) {
movement[1] *= m_sensitivity[1];
- if ((m_limit_y[0] != 0.0) && ((m_angle[1] + movement[1]) <= m_limit_y[0])) {
+ if ((m_limit_y[0] != 0.0f) && ((m_angle[1] + movement[1]) <= m_limit_y[0])) {
movement[1] = m_limit_y[0] - m_angle[1];
}
- if ((m_limit_y[1] != 0.0) && ((m_angle[1] + movement[1]) >= m_limit_y[1])) {
+ if ((m_limit_y[1] != 0.0f) && ((m_angle[1] + movement[1]) >= m_limit_y[1])) {
movement[1] = m_limit_y[1] - m_angle[1];
}
@@ -255,17 +255,17 @@ bool KX_MouseActuator::Update()
{
case KX_ACT_MOUSE_OBJECT_AXIS_X:
{
- rotation = MT_Vector3(movement[1], 0.0, 0.0);
+ rotation = MT_Vector3(movement[1], 0.0f, 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
{
- rotation = MT_Vector3(0.0, movement[1], 0.0);
+ rotation = MT_Vector3(0.0f, movement[1], 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
{
- rotation = MT_Vector3(0.0, 0.0, movement[1]);
+ rotation = MT_Vector3(0.0f, 0.0f, movement[1]);
break;
}
default:
@@ -377,7 +377,7 @@ PyAttributeDef KX_MouseActuator::Attributes[] = {
KX_PYATTRIBUTE_BOOL_RW("visible", KX_MouseActuator, m_visible),
KX_PYATTRIBUTE_BOOL_RW("use_axis_x", KX_MouseActuator, m_use_axis_x),
KX_PYATTRIBUTE_BOOL_RW("use_axis_y", KX_MouseActuator, m_use_axis_y),
- KX_PYATTRIBUTE_FLOAT_ARRAY_RW("threshold", 0.0, 0.5, KX_MouseActuator, m_threshold, 2),
+ KX_PYATTRIBUTE_FLOAT_ARRAY_RW("threshold", 0.0f, 0.5f, KX_MouseActuator, m_threshold, 2),
KX_PYATTRIBUTE_BOOL_RW("reset_x", KX_MouseActuator, m_reset_x),
KX_PYATTRIBUTE_BOOL_RW("reset_y", KX_MouseActuator, m_reset_y),
KX_PYATTRIBUTE_INT_ARRAY_RW("object_axis", 0, 2, 1, KX_MouseActuator, m_object_axis, 2),
@@ -393,7 +393,7 @@ PyAttributeDef KX_MouseActuator::Attributes[] = {
PyObject* KX_MouseActuator::pyattr_get_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
- return Py_BuildValue("[f,f]", (self->m_limit_x[0] / M_PI * 180.0), (self->m_limit_x[1] / M_PI * 180.0));
+ return Py_BuildValue("[f,f]", (self->m_limit_x[0] / (float)M_PI * 180.0f), (self->m_limit_x[1] / (float)M_PI * 180.0f));
}
int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@@ -414,8 +414,8 @@ int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF
return PY_SET_ATTR_FAIL;
}
else {
- self->m_limit_x[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
- self->m_limit_x[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
+ self->m_limit_x[0] = (float)((PyFloat_AsDouble(item1) * M_PI) / 180.0f);
+ self->m_limit_x[1] = (float)((PyFloat_AsDouble(item2) * M_PI) / 180.0f);
}
return PY_SET_ATTR_SUCCESS;
@@ -424,7 +424,7 @@ int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF
PyObject* KX_MouseActuator::pyattr_get_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
- return Py_BuildValue("[f,f]", (self->m_limit_y[0] / M_PI * 180.0), (self->m_limit_y[1] / M_PI * 180.0));
+ return Py_BuildValue("[f,f]", (self->m_limit_y[0] / (float)M_PI * 180.0f), (self->m_limit_y[1] / (float)M_PI * 180.0f));
}
int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@@ -445,8 +445,8 @@ int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF
return PY_SET_ATTR_FAIL;
}
else {
- self->m_limit_y[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
- self->m_limit_y[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
+ self->m_limit_y[0] = (float)((PyFloat_AsDouble(item1) * M_PI) / 180.0f);
+ self->m_limit_y[1] = (float)((PyFloat_AsDouble(item2) * M_PI) / 180.0f);
}
return PY_SET_ATTR_SUCCESS;
@@ -455,7 +455,7 @@ int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF
PyObject* KX_MouseActuator::pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
- return Py_BuildValue("[f,f]", (self->m_angle[0] / M_PI * 180.0), (self->m_angle[1] / M_PI * 180.0));
+ return Py_BuildValue("[f,f]", (self->m_angle[0] / (float)M_PI * 180.0f), (self->m_angle[1] / (float)M_PI * 180.0f));
}
int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@@ -476,8 +476,8 @@ int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *a
return PY_SET_ATTR_FAIL;
}
else {
- self->m_angle[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
- self->m_angle[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
+ self->m_angle[0] = ((float)(PyFloat_AsDouble(item1) * M_PI) / 180.0f);
+ self->m_angle[1] = ((float)(PyFloat_AsDouble(item2) * M_PI) / 180.0f);
}
return PY_SET_ATTR_SUCCESS;
@@ -491,17 +491,17 @@ PyObject* KX_MouseActuator::PyReset()
switch (m_object_axis[0]) {
case KX_ACT_MOUSE_OBJECT_AXIS_X:
{
- rotation = MT_Vector3(-1.0 * m_angle[0], 0.0, 0.0);
+ rotation = MT_Vector3(-1.0f * m_angle[0], 0.0f, 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
{
- rotation = MT_Vector3(0.0, -1.0 * m_angle[0], 0.0);
+ rotation = MT_Vector3(0.0f, -1.0f * m_angle[0], 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
{
- rotation = MT_Vector3(0.0, 0.0, -1.0 * m_angle[0]);
+ rotation = MT_Vector3(0.0f, 0.0f, -1.0f * m_angle[0]);
break;
}
default:
@@ -512,17 +512,17 @@ PyObject* KX_MouseActuator::PyReset()
switch (m_object_axis[1]) {
case KX_ACT_MOUSE_OBJECT_AXIS_X:
{
- rotation = MT_Vector3(-1.0 * m_angle[1], 0.0, 0.0);
+ rotation = MT_Vector3(-1.0f * m_angle[1], 0.0f, 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Y:
{
- rotation = MT_Vector3(0.0, -1.0 * m_angle[1], 0.0);
+ rotation = MT_Vector3(0.0f, -1.0f * m_angle[1], 0.0f);
break;
}
case KX_ACT_MOUSE_OBJECT_AXIS_Z:
{
- rotation = MT_Vector3(0.0, 0.0, -1.0 * m_angle[1]);
+ rotation = MT_Vector3(0.0f, 0.0f, -1.0f * m_angle[1]);
break;
}
default:
@@ -530,8 +530,8 @@ PyObject* KX_MouseActuator::PyReset()
}
parent->ApplyRotation(rotation, m_local_y);
- m_angle[0] = 0.0;
- m_angle[1] = 0.0;
+ m_angle[0] = 0.0f;
+ m_angle[1] = 0.0f;
Py_RETURN_NONE;
}
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
index 46f27e1a2df..451078d4a36 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
@@ -144,7 +144,7 @@ bool KX_MouseFocusSensor::Evaluate()
return result;
}
-bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *result, void * const data)
+bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *result, void *UNUSED(data))
{
KX_GameObject* hitKXObj = client_info->m_gameobject;
@@ -198,7 +198,7 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r
/* this function is used to pre-filter the object before casting the ray on them.
* This is useful for "X-Ray" option when we want to see "through" unwanted object.
*/
-bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo* client)
+bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data))
{
KX_GameObject *hitKXObj = client->m_gameobject;
@@ -314,15 +314,15 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam)
* The actual z coordinates used don't have to be exact just infront and
* behind of the near and far clip planes.
*/
- frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0,
- 1.0 - (2 * (m_y_inv - y_lb) / height),
- -1.0,
- 1.0 );
+ frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0f,
+ 1.0f - (2 * (m_y_inv - y_lb) / height),
+ -1.0f,
+ 1.0f );
- topoint.setValue( (2 * (m_x-x_lb) / width) - 1.0,
- 1.0 - (2 * (m_y_inv-y_lb) / height),
- 1.0,
- 1.0 );
+ topoint.setValue( (2 * (m_x-x_lb) / width) - 1.0f,
+ 1.0f - (2 * (m_y_inv-y_lb) / height),
+ 1.0f,
+ 1.0f );
/* camera to world */
MT_Matrix4x4 camcs_wcs_matrix = MT_Matrix4x4(cam->GetCameraToWorld());
@@ -356,7 +356,7 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam)
PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment();
// get UV mapping
- KX_RayCast::Callback<KX_MouseFocusSensor> callback(this,physics_controller,NULL,false,true);
+ KX_RayCast::Callback<KX_MouseFocusSensor, void> callback(this,physics_controller,NULL,false,true);
KX_RayCast::RayTest(physics_environment, m_prevSourcePoint, m_prevTargetPoint, callback);
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
index 0c7c8ab676a..dd9295b2ff4 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
@@ -35,6 +35,8 @@
#include "SCA_MouseSensor.h"
+#include "BLI_utildefines.h"
+
class KX_RayCast;
/**
@@ -90,8 +92,10 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
return result;
};
- bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
- bool NeedRayCast(KX_ClientObjectInfo* client);
+ /// \see KX_RayCast
+ bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data));
+ /// \see KX_RayCast
+ bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data));
const MT_Point3& RaySource() const;
const MT_Point3& RayTarget() const;
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
index 12abcb250a7..8c1dee7940f 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
@@ -65,12 +65,12 @@ KX_ObjectActuator(
m_drot(drot),
m_linear_velocity(linV),
m_angular_velocity(angV),
- m_linear_length2(0.0),
- m_current_linear_factor(0.0),
- m_current_angular_factor(0.0),
+ m_linear_length2(0.0f),
+ m_current_linear_factor(0.0f),
+ m_current_angular_factor(0.0f),
m_damping(damping),
- m_previous_error(0.0,0.0,0.0),
- m_error_accumulator(0.0,0.0,0.0),
+ m_previous_error(0.0f,0.0f,0.0f),
+ m_error_accumulator(0.0f,0.0f,0.0f),
m_bitLocalFlag (flag),
m_reference(refobj),
m_active_combined_velocity (false),
@@ -134,13 +134,13 @@ bool KX_ObjectActuator::Update()
// Explicitly stop the movement if we're using character motion
if (m_bitLocalFlag.CharacterMotion) {
- character->SetWalkDirection(MT_Vector3 (0.0, 0.0, 0.0));
+ character->SetWalkDirection(MT_Vector3 (0.0f, 0.0f, 0.0f));
}
m_linear_damping_active = false;
m_angular_damping_active = false;
- m_error_accumulator.setValue(0.0,0.0,0.0);
- m_previous_error.setValue(0.0,0.0,0.0);
+ m_error_accumulator.setValue(0.0f,0.0f,0.0f);
+ m_previous_error.setValue(0.0f,0.0f,0.0f);
m_jumping = false;
return false;
@@ -291,10 +291,10 @@ bool KX_ObjectActuator::Update()
m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
m_linear_damping_active = true;
}
- if (m_current_linear_factor < 1.0)
- m_current_linear_factor += 1.0/m_damping;
- if (m_current_linear_factor > 1.0)
- m_current_linear_factor = 1.0;
+ if (m_current_linear_factor < 1.0f)
+ m_current_linear_factor += 1.0f/m_damping;
+ if (m_current_linear_factor > 1.0f)
+ m_current_linear_factor = 1.0f;
linV = m_current_linear_factor * m_linear_velocity;
parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
} else {
@@ -314,10 +314,10 @@ bool KX_ObjectActuator::Update()
m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
m_angular_damping_active = true;
}
- if (m_current_angular_factor < 1.0)
- m_current_angular_factor += 1.0/m_damping;
- if (m_current_angular_factor > 1.0)
- m_current_angular_factor = 1.0;
+ if (m_current_angular_factor < 1.0f)
+ m_current_angular_factor += 1.0f/m_damping;
+ if (m_current_angular_factor > 1.0f)
+ m_current_angular_factor = 1.0f;
angV = m_current_angular_factor * m_angular_velocity;
parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
} else {
@@ -687,7 +687,7 @@ int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIB
KX_ObjectActuator* actuator = static_cast<KX_ObjectActuator*>(self);
KX_GameObject *refOb;
- if (!ConvertPythonToGameObject(value, &refOb, true, "actu.reference = value: KX_ObjectActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &refOb, true, "actu.reference = value: KX_ObjectActuator"))
return PY_SET_ATTR_FAIL;
if (actuator->m_reference)
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h
index b5622d97611..919c6acf03b 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.h
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.h
@@ -161,9 +161,9 @@ public:
m_bitLocalFlag.ZeroDLoc = MT_fuzzyZero(m_dloc);
m_bitLocalFlag.ZeroDRot = MT_fuzzyZero(m_drot);
m_bitLocalFlag.ZeroLinearVelocity = MT_fuzzyZero(m_linear_velocity);
- m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0 : m_linear_velocity.length2();
+ m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0f : m_linear_velocity.length2();
m_bitLocalFlag.ZeroAngularVelocity = MT_fuzzyZero(m_angular_velocity);
- m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0 : m_angular_velocity.length2();
+ m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0f : m_angular_velocity.length2();
}
virtual bool Update();
diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
index 456f5f8af3b..239bfde4c98 100644
--- a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
+++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp
@@ -302,7 +302,7 @@ void KX_ObstacleSimulation::DrawObstacles()
if (!m_enableVisualization)
return;
static const MT_Vector3 bluecolor(0,0,1);
- static const MT_Vector3 normal(0.0, 0.0, 1.0);
+ static const MT_Vector3 normal(0.0f, 0.0f, 1.0f);
static const int SECTORS_NUM = 32;
for (size_t i=0; i<m_obstacles.size(); i++)
{
@@ -362,7 +362,7 @@ static bool filterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavM
//filter obstacles by position
MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst);
- if ( fabs(activeObst->m_pos.z() - p.z()) > levelHeight)
+ if ( fabsf(activeObst->m_pos.z() - p.z()) > levelHeight)
return false;
return true;
@@ -459,14 +459,14 @@ void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle* activeObst, KX_NavMes
{
// Calculate sample velocity
const float ndir = ((float)iter/(float)m_maxSamples) - aoff;
- const float dir = odir+ndir*M_PI*2;
+ const float dir = odir+ndir*(float)M_PI*2.0f;
MT_Vector2 svel;
svel.x() = cosf(dir) * vmax;
svel.y() = sinf(dir) * vmax;
// Find min time of impact and exit amongst all obstacles.
float tmin = m_maxToi;
- float tmine = 0;
+ float tmine = 0.0f;
for (int i = 0; i < nobs; ++i)
{
KX_Obstacle* ob = m_obstacles[i];
diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp
index d2468d0317d..bcaa1e60e92 100644
--- a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp
+++ b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp
@@ -39,12 +39,12 @@ void KX_OrientationInterpolator::Execute(float currentTime) const
MT_Vector3 eul(m_ipos[0]->GetValue(currentTime),
m_ipos[1]->GetValue(currentTime),
m_ipos[2]->GetValue(currentTime));
- MT_Scalar ci = cos(eul[0]);
- MT_Scalar cj = cos(eul[1]);
- MT_Scalar ch = cos(eul[2]);
- MT_Scalar si = sin(eul[0]);
- MT_Scalar sj = sin(eul[1]);
- MT_Scalar sh = sin(eul[2]);
+ MT_Scalar ci = cosf(eul[0]);
+ MT_Scalar cj = cosf(eul[1]);
+ MT_Scalar ch = cosf(eul[2]);
+ MT_Scalar si = sinf(eul[0]);
+ MT_Scalar sj = sinf(eul[1]);
+ MT_Scalar sh = sinf(eul[2]);
MT_Scalar cc = ci*ch;
MT_Scalar cs = ci*sh;
MT_Scalar sc = si*ch;
diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp
index 6ffa2593792..0b133400920 100644
--- a/source/gameengine/Ketsji/KX_ParentActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp
@@ -186,7 +186,7 @@ int KX_ParentActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE
KX_ParentActuator* actuator = static_cast<KX_ParentActuator*>(self);
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_ParentActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_ParentActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (actuator->m_ob != NULL)
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
index a0084662490..81fe3be1fcf 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -40,6 +40,7 @@
#include "MT_Matrix3x3.h"
#include "KX_GameObject.h" // ConvertPythonToGameObject()
+#include "KX_PythonInit.h"
#include "EXP_PyObjectPlus.h"
@@ -472,7 +473,7 @@ static PyObject* gPyGetCharacter(PyObject* self,
if (!PyArg_ParseTuple(args,"O", &pyob))
return NULL;
- if (!ConvertPythonToGameObject(pyob, &ob, false, "bge.constraints.getCharacter(value)"))
+ if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), pyob, &ob, false, "bge.constraints.getCharacter(value)"))
return NULL;
if (PHY_GetActiveEnvironment())
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 2fef74ca33d..76eb915a30d 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -37,9 +37,6 @@
#endif
#ifdef WITH_PYTHON
-# ifdef _POSIX_C_SOURCE
-# undef _POSIX_C_SOURCE
-# endif
# ifdef _XOPEN_SOURCE
# undef _XOPEN_SOURCE
# endif
@@ -101,7 +98,6 @@ extern "C" {
#include "SCA_PythonKeyboard.h"
#include "SCA_PythonMouse.h"
#include "KX_ConstraintActuator.h"
-#include "KX_IpoActuator.h"
#include "KX_SoundActuator.h"
#include "KX_StateActuator.h"
#include "BL_ActionActuator.h"
@@ -201,8 +197,12 @@ void KX_RasterizerDrawDebugCircle(const MT_Vector3& center, const MT_Scalar radi
#ifdef WITH_PYTHON
-static PyObject *gp_OrigPythonSysPath= NULL;
-static PyObject *gp_OrigPythonSysModules= NULL;
+
+static struct {
+ PyObject *path;
+ PyObject *meta_path;
+ PyObject *modules;
+} gp_sys_backup = {NULL};
/* Macro for building the keyboard translation */
//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromLong(SCA_IInputDevice::KX_##name))
@@ -552,6 +552,64 @@ static PyObject *gPyGetAverageFrameRate(PyObject *)
return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate());
}
+static PyObject *gPyGetUseExternalClock(PyObject *)
+{
+ return PyBool_FromLong(gp_KetsjiEngine->GetUseExternalClock());
+}
+
+static PyObject *gPySetUseExternalClock(PyObject *, PyObject *args)
+{
+ bool bUseExternalClock;
+
+ if (!PyArg_ParseTuple(args, "p:setUseExternalClock", &bUseExternalClock))
+ return NULL;
+
+ gp_KetsjiEngine->SetUseExternalClock(bUseExternalClock);
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyGetClockTime(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetClockTime());
+}
+
+static PyObject *gPySetClockTime(PyObject *, PyObject *args)
+{
+ double externalClockTime;
+
+ if (!PyArg_ParseTuple(args, "d:setClockTime", &externalClockTime))
+ return NULL;
+
+ gp_KetsjiEngine->SetClockTime(externalClockTime);
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyGetFrameTime(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetFrameTime());
+}
+
+static PyObject *gPyGetRealTime(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetRealTime());
+}
+
+static PyObject *gPyGetTimeScale(PyObject *)
+{
+ return PyFloat_FromDouble(gp_KetsjiEngine->GetTimeScale());
+}
+
+static PyObject *gPySetTimeScale(PyObject *, PyObject *args)
+{
+ double time_scale;
+
+ if (!PyArg_ParseTuple(args, "d:setTimeScale", &time_scale))
+ return NULL;
+
+ gp_KetsjiEngine->SetTimeScale(time_scale);
+ Py_RETURN_NONE;
+}
+
static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args)
{
char cpath[sizeof(gp_GamePythonPath)];
@@ -651,71 +709,10 @@ static PyObject *pyPrintStats(PyObject *,PyObject *,PyObject *)
static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
{
-#define pprint(x) std::cout << x << std::endl;
- bool count=0;
- bool support=0;
- pprint("Supported Extensions...");
- pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no."));
- count = 1;
-
- support= GLEW_ARB_vertex_shader;
- pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no."));
- count = 1;
- if (support) {
- pprint(" ----------Details----------");
- int max=0;
- glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint*)&max);
- pprint(" Max uniform components." << max);
-
- glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint*)&max);
- pprint(" Max varying floats." << max);
-
- glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max);
- pprint(" Max vertex texture units." << max);
-
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max);
- pprint(" Max combined texture units." << max);
- pprint("");
- }
-
- support=GLEW_ARB_fragment_shader;
- pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no."));
- count = 1;
- if (support) {
- pprint(" ----------Details----------");
- int max=0;
- glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint*)&max);
- pprint(" Max uniform components." << max);
- pprint("");
- }
-
- support = GLEW_ARB_texture_cube_map;
- pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no."));
- count = 1;
- if (support) {
- pprint(" ----------Details----------");
- int size=0;
- glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&size);
- pprint(" Max cubemap size." << size);
- pprint("");
- }
-
- support = GLEW_ARB_multitexture;
- count = 1;
- pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no."));
- if (support) {
- pprint(" ----------Details----------");
- int units=0;
- glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&units);
- pprint(" Max texture units available. " << units);
- pprint("");
- }
-
- pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no."));
- count = 1;
-
- if (!count)
- pprint("No extenstions are used in this build");
+ if (gp_Rasterizer)
+ gp_Rasterizer->PrintHardwareInfo();
+ else
+ printf("Warning: no rasterizer detected for PrintGLInfo!\n");
Py_RETURN_NONE;
}
@@ -912,7 +909,19 @@ static struct PyMethodDef game_methods[] = {
{"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"},
{"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"},
{"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"},
+ {"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"},
+ {"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"},
+ {"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. "
+ "The BGE render time is the simulated time corresponding to the next scene that will be renderered"},
+ {"setClockTime", (PyCFunction) gPySetClockTime, METH_VARARGS, (const char *)"Set the BGE render time. "
+ "The BGE render time is the simulated time corresponding to the next scene that will be rendered"},
+ {"getFrameTime", (PyCFunction) gPyGetFrameTime, METH_NOARGS, (const char *)"Get the BGE last frametime. "
+ "The BGE frame time is the simulated time corresponding to the last call of the logic system"},
+ {"getRealTime", (PyCFunction) gPyGetRealTime, METH_NOARGS, (const char *)"Get the real system time. "
+ "The real-time corresponds to the system time" },
{"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"},
+ {"getTimeScale", (PyCFunction) gPyGetTimeScale, METH_NOARGS, (const char *)"Get the time multiplier"},
+ {"setTimeScale", (PyCFunction) gPySetTimeScale, METH_VARARGS, (const char *)"Set the time multiplier"},
{"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"},
{"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"},
{"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"},
@@ -1804,6 +1813,7 @@ PyMODINIT_FUNC initGameLogicPythonBinding()
KX_MACRO_addTypesToDict(d, KX_GAME_QUIT, KX_GameActuator::KX_GAME_QUIT);
KX_MACRO_addTypesToDict(d, KX_GAME_SAVECFG, KX_GameActuator::KX_GAME_SAVECFG);
KX_MACRO_addTypesToDict(d, KX_GAME_LOADCFG, KX_GameActuator::KX_GAME_LOADCFG);
+ KX_MACRO_addTypesToDict(d, KX_GAME_SCREENSHOT, KX_GameActuator::KX_GAME_SCREENSHOT);
/* Scene Actuator Modes */
KX_MACRO_addTypesToDict(d, KX_SCENE_RESTART, KX_SceneActuator::KX_SCENE_RESTART);
@@ -1901,11 +1911,12 @@ PyMODINIT_FUNC initGameLogicPythonBinding()
return m;
}
-/* Explanation of
+/**
+ * Explanation of
*
- * - backupPySysObjects() : stores sys.path in gp_OrigPythonSysPath
- * - initPySysObjects(main) : initializes the blendfile and library paths
- * - restorePySysObjects() : restores sys.path from gp_OrigPythonSysPath
+ * - backupPySysObjects() : stores sys.path in #gp_sys_backup
+ * - initPySysObjects(main) : initializes the blendfile and library paths
+ * - restorePySysObjects() : restores sys.path from #gp_sys_backup
*
* These exist so the current blend dir "//" can always be used to import modules from.
* the reason we need a few functions for this is that python is not only used by the game engine
@@ -1922,16 +1933,21 @@ PyMODINIT_FUNC initGameLogicPythonBinding()
*/
static void backupPySysObjects(void)
{
- PyObject *sys_path= PySys_GetObject("path"); /* should never fail */
- PyObject *sys_mods= PySys_GetObject("modules"); /* should never fail */
+ PyObject *sys_path = PySys_GetObject("path");
+ PyObject *sys_meta_path = PySys_GetObject("meta_path");
+ PyObject *sys_mods = PySys_GetObject("modules");
/* paths */
- Py_XDECREF(gp_OrigPythonSysPath); /* just in case its set */
- gp_OrigPythonSysPath = PyList_GetSlice(sys_path, 0, INT_MAX); /* copy the list */
+ Py_XDECREF(gp_sys_backup.path); /* just in case its set */
+ gp_sys_backup.path = PyList_GetSlice(sys_path, 0, INT_MAX); /* copy the list */
+ /* meta_paths */
+ Py_XDECREF(gp_sys_backup.meta_path); /* just in case its set */
+ gp_sys_backup.meta_path = PyList_GetSlice(sys_meta_path, 0, INT_MAX); /* copy the list */
+
/* modules */
- Py_XDECREF(gp_OrigPythonSysModules); /* just in case its set */
- gp_OrigPythonSysModules = PyDict_Copy(sys_mods); /* copy the list */
+ Py_XDECREF(gp_sys_backup.modules); /* just in case its set */
+ gp_sys_backup.modules = PyDict_Copy(sys_mods); /* copy the dict */
}
@@ -1961,15 +1977,17 @@ static void initPySysObjects__append(PyObject *sys_path, const char *filename)
}
static void initPySysObjects(Main *maggie)
{
- PyObject *sys_path= PySys_GetObject("path"); /* should never fail */
+ PyObject *sys_path = PySys_GetObject("path");
+ PyObject *sys_meta_path = PySys_GetObject("meta_path");
- if (gp_OrigPythonSysPath==NULL) {
+ if (gp_sys_backup.path == NULL) {
/* backup */
backupPySysObjects();
}
else {
/* get the original sys path when the BGE started */
- PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath);
+ PyList_SetSlice(sys_path, 0, INT_MAX, gp_sys_backup.path);
+ PyList_SetSlice(sys_meta_path, 0, INT_MAX, gp_sys_backup.meta_path);
}
Library *lib= (Library *)maggie->library.first;
@@ -1989,22 +2007,30 @@ static void initPySysObjects(Main *maggie)
static void restorePySysObjects(void)
{
- if (gp_OrigPythonSysPath==NULL)
+ if (gp_sys_backup.path == NULL) {
return;
-
- PyObject *sys_path= PySys_GetObject("path"); /* should never fail */
- PyObject *sys_mods= PySys_GetObject("modules"); /* should never fail */
+ }
+
+ /* will never fail */
+ PyObject *sys_path = PySys_GetObject("path");
+ PyObject *sys_meta_path = PySys_GetObject("meta_path");
+ PyObject *sys_mods = PySys_GetObject("modules");
/* paths */
- PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath);
- Py_DECREF(gp_OrigPythonSysPath);
- gp_OrigPythonSysPath= NULL;
+ PyList_SetSlice(sys_path, 0, INT_MAX, gp_sys_backup.path);
+ Py_DECREF(gp_sys_backup.path);
+ gp_sys_backup.path = NULL;
+
+ /* meta_path */
+ PyList_SetSlice(sys_meta_path, 0, INT_MAX, gp_sys_backup.meta_path);
+ Py_DECREF(gp_sys_backup.meta_path);
+ gp_sys_backup.meta_path = NULL;
/* modules */
PyDict_Clear(sys_mods);
- PyDict_Update(sys_mods, gp_OrigPythonSysModules);
- Py_DECREF(gp_OrigPythonSysModules);
- gp_OrigPythonSysModules= NULL;
+ PyDict_Update(sys_mods, gp_sys_backup.modules);
+ Py_DECREF(gp_sys_backup.modules);
+ gp_sys_backup.modules = NULL;
// fprintf(stderr, "\nRestore Path: %d ", PyList_GET_SIZE(sys_path));
diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
index ef6ad4712a5..4a999e37f2b 100644
--- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
@@ -58,7 +58,6 @@
#include "KX_ObjectActuator.h"
#include "KX_ParentActuator.h"
#include "KX_PolyProxy.h"
-#include "KX_PythonSeq.h"
#include "KX_SCA_AddObjectActuator.h"
#include "KX_SCA_EndObjectActuator.h"
#include "KX_SCA_ReplaceMeshActuator.h"
@@ -85,7 +84,6 @@
#include "SCA_PythonJoystick.h"
#include "SCA_PythonKeyboard.h"
#include "SCA_PythonMouse.h"
-#include "KX_IpoActuator.h"
#include "KX_NearSensor.h"
#include "KX_RadarSensor.h"
#include "KX_RaySensor.h"
@@ -99,6 +97,7 @@
#include "SCA_IController.h"
#include "KX_NavMeshObject.h"
#include "KX_MouseActuator.h"
+#include "EXP_ListWrapper.h"
static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr)
{
@@ -203,6 +202,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
PyType_Ready_AttrPtr(dict, BL_ArmatureChannel, init_getset);
// PyType_Ready_Attr(dict, CPropValue, init_getset); // doesn't use Py_Header
PyType_Ready_Attr(dict, CListValue, init_getset);
+ PyType_Ready_Attr(dict, CListWrapper, init_getset);
PyType_Ready_Attr(dict, CValue, init_getset);
PyType_Ready_Attr(dict, KX_ArmatureSensor, init_getset);
PyType_Ready_Attr(dict, KX_BlenderMaterial, init_getset);
@@ -213,7 +213,6 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
PyType_Ready_Attr(dict, KX_ConstraintWrapper, init_getset);
PyType_Ready_Attr(dict, KX_GameActuator, init_getset);
PyType_Ready_Attr(dict, KX_GameObject, init_getset);
- PyType_Ready_Attr(dict, KX_IpoActuator, init_getset);
PyType_Ready_Attr(dict, KX_LibLoadStatus, init_getset);
PyType_Ready_Attr(dict, KX_LightObject, init_getset);
PyType_Ready_Attr(dict, KX_FontObject, init_getset);
@@ -273,10 +272,6 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void)
PyType_Ready_Attr(dict, SCA_PythonMouse, init_getset);
}
-
- /* Normal python type */
- PyType_Ready(&KX_PythonSeq_Type);
-
#ifdef USE_MATHUTILS
/* Init mathutils callbacks */
KX_GameObject_Mathutils_Callback_Init();
diff --git a/source/gameengine/Ketsji/KX_PythonSeq.cpp b/source/gameengine/Ketsji/KX_PythonSeq.cpp
deleted file mode 100644
index ab4f2c2d2c9..00000000000
--- a/source/gameengine/Ketsji/KX_PythonSeq.cpp
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s): Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- * Readonly sequence wrapper for lookups on logic bricks
- */
-
-/** \file gameengine/Ketsji/KX_PythonSeq.cpp
- * \ingroup ketsji
- */
-
-
-#ifdef WITH_PYTHON
-
-#include "KX_PythonSeq.h"
-#include "KX_GameObject.h"
-#include "BL_ArmatureObject.h"
-#include "SCA_ISensor.h"
-#include "SCA_IController.h"
-#include "SCA_IActuator.h"
-
-
-PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
-{
- KX_PythonSeq *seq = PyObject_GC_New(KX_PythonSeq, &KX_PythonSeq_Type);
- seq->base = base;
- Py_INCREF(base); /* so we can always access to check if its valid */
- seq->type = type;
- seq->iter = -1; /* init */
- return (PyObject *)seq;
-}
-
-static int KX_PythonSeq_traverse(KX_PythonSeq *self, visitproc visit, void *arg)
-{
- Py_VISIT(self->base);
- return 0;
-}
-
-static int KX_PythonSeq_clear(KX_PythonSeq *self)
-{
- Py_CLEAR(self->base);
- return 0;
-}
-
-static void KX_PythonSeq_dealloc(KX_PythonSeq *self)
-{
- KX_PythonSeq_clear(self);
- PyObject_GC_Del(self);
-}
-
-static Py_ssize_t KX_PythonSeq_len( PyObject *self )
-{
- PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-
- if (self_plus==NULL) {
- PyErr_SetString(PyExc_SystemError, "len(seq): " BGE_PROXY_ERROR_MSG);
- return -1;
- }
-
- switch (((KX_PythonSeq *)self)->type) {
- case KX_PYGENSEQ_CONT_TYPE_SENSORS:
- return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
- case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
- return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
- case KX_PYGENSEQ_OB_TYPE_SENSORS:
- return ((KX_GameObject *)self_plus)->GetSensors().size();
- case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
- return ((KX_GameObject *)self_plus)->GetControllers().size();
- case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
- return ((KX_GameObject *)self_plus)->GetActuators().size();
- case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
- return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
- case KX_PYGENSEQ_OB_TYPE_CHANNELS:
- return ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
- default:
- /* Should never happen */
- PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
- return -1;
- }
-}
-
-static PyObject *KX_PythonSeq_getIndex(PyObject *self, Py_ssize_t index)
-{
- PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-
- if (self_plus==NULL) {
- PyErr_SetString(PyExc_SystemError, "val = seq[i]: " BGE_PROXY_ERROR_MSG);
- return NULL;
- }
-
- switch (((KX_PythonSeq *)self)->type) {
- case KX_PYGENSEQ_CONT_TYPE_SENSORS:
- {
- vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
- if (index<0) index += linkedsensors.size();
- if (index<0 || index>= linkedsensors.size()) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return linkedsensors[index]->GetProxy();
- }
- case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
- {
- vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
- if (index<0) index += linkedactuators.size();
- if (index<0 || index>= linkedactuators.size()) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return linkedactuators[index]->GetProxy();
- }
- case KX_PYGENSEQ_OB_TYPE_SENSORS:
- {
- SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
- if (index<0) index += linkedsensors.size();
- if (index<0 || index>= linkedsensors.size()) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return linkedsensors[index]->GetProxy();
- }
- case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
- {
- SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
- if (index<0) index += linkedcontrollers.size();
- if (index<0 || index>= linkedcontrollers.size()) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return linkedcontrollers[index]->GetProxy();
- }
- case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
- {
- SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
- if (index<0) index += linkedactuators.size();
- if (index<0 || index>= linkedactuators.size()) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return linkedactuators[index]->GetProxy();
- }
- case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
- {
- int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
- if (index<0)
- index += nb_constraint;
- if (index<0 || index>= nb_constraint) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return ((BL_ArmatureObject *)self_plus)->GetConstraint(index)->GetProxy();
- }
- case KX_PYGENSEQ_OB_TYPE_CHANNELS:
- {
- int nb_channel = ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
- if (index<0)
- index += nb_channel;
- if (index<0 || index>= nb_channel) {
- PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
- return NULL;
- }
- return ((BL_ArmatureObject *)self_plus)->GetChannel(index)->GetProxy();
- }
-
- }
-
- PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
- return NULL;
-}
-
-static PyObjectPlus *KX_PythonSeq_subscript__internal(PyObject *self, const char *key)
-{
- PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-
- switch (((KX_PythonSeq *)self)->type) {
- case KX_PYGENSEQ_CONT_TYPE_SENSORS:
- {
- vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
- SCA_ISensor* sensor;
- for (unsigned int index=0;index<linkedsensors.size();index++) {
- sensor = linkedsensors[index];
- if (sensor->GetName() == key)
- return static_cast<PyObjectPlus *>(sensor);
-
- }
- break;
- }
- case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
- {
- vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
- SCA_IActuator* actuator;
- for (unsigned int index=0;index<linkedactuators.size();index++) {
- actuator = linkedactuators[index];
- if (actuator->GetName() == key)
- return static_cast<PyObjectPlus *>(actuator);
- }
- break;
- }
- case KX_PYGENSEQ_OB_TYPE_SENSORS:
- {
- SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
- SCA_ISensor *sensor;
- for (unsigned int index=0;index<linkedsensors.size();index++) {
- sensor= linkedsensors[index];
- if (sensor->GetName() == key)
- return static_cast<PyObjectPlus *>(sensor);
- }
- break;
- }
- case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
- {
- SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
- SCA_IController *controller;
- for (unsigned int index=0;index<linkedcontrollers.size();index++) {
- controller= linkedcontrollers[index];
- if (controller->GetName() == key)
- return static_cast<PyObjectPlus *>(controller);
- }
- break;
- }
- case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
- {
- SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
- SCA_IActuator *actuator;
- for (unsigned int index=0;index<linkedactuators.size();index++) {
- actuator= linkedactuators[index];
- if (actuator->GetName() == key)
- return static_cast<PyObjectPlus *>(actuator);
- }
- break;
- }
- case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
- {
- return ((BL_ArmatureObject*)self_plus)->GetConstraint(key);
- }
- case KX_PYGENSEQ_OB_TYPE_CHANNELS:
- {
- return ((BL_ArmatureObject*)self_plus)->GetChannel(key);
- }
- }
-
- return NULL;
-}
-
-
-static PyObject *KX_PythonSeq_subscript(PyObject *self, PyObject *key)
-{
- PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-
- if (self_plus==NULL) {
- PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: " BGE_PROXY_ERROR_MSG);
- return NULL;
- }
-
- if (PyIndex_Check(key)) {
- return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t(key));
- }
- else if ( PyUnicode_Check(key) ) {
- const char *name = _PyUnicode_AsString(key);
- PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
-
- if (ret) {
- return ret->GetProxy();
- } else {
- PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
- return NULL;
- }
- }
- else {
- PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
- return NULL;
- }
-}
-
-
-static int KX_PythonSeq_contains(PyObject *self, PyObject *key)
-{
- PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
-
- if (self_plus==NULL) {
- PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: " BGE_PROXY_ERROR_MSG);
- return -1;
- }
- if (!PyUnicode_Check(key)) {
- PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string");
- return -1;
- }
-
- if (KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key)))
- return 1;
-
- return 0;
-}
-
-/* Matches python dict.get(key, [default]) */
-static PyObject *KX_PythonSeq_get(PyObject *self, PyObject *args)
-{
- char *key;
- PyObject *def = Py_None;
- PyObjectPlus* ret_plus;
-
- if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
- return NULL;
-
- if ((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
- return ret_plus->GetProxy();
-
- Py_INCREF(def);
- return def;
-}
-
-static PySequenceMethods KX_PythonSeq_as_sequence = {
- NULL, /* Cant set the len otherwise it can evaluate as false */
- NULL, /* sq_concat */
- NULL, /* sq_repeat */
- NULL, /* sq_item */
- NULL, /* sq_slice */
- NULL, /* sq_ass_item */
- NULL, /* sq_ass_slice */
- (objobjproc)KX_PythonSeq_contains, /* sq_contains */
- (binaryfunc) NULL, /* sq_inplace_concat */
- (ssizeargfunc) NULL, /* sq_inplace_repeat */
-};
-
-static PyMappingMethods KX_PythonSeq_as_mapping = {
- KX_PythonSeq_len, /* mp_length */
- KX_PythonSeq_subscript, /* mp_subscript */
- 0, /* mp_ass_subscript */
-};
-
-static PyMethodDef KX_PythonSeq_methods[] = {
- // dict style access for props
- {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS},
- {NULL,NULL} //Sentinel
-};
-
-/*
- * Initialize the iterator index
- */
-
-static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self)
-{
- if (BGE_PROXY_REF(self->base)==NULL) {
- PyErr_SetString(PyExc_SystemError, "for i in seq: " BGE_PROXY_ERROR_MSG);
- return NULL;
- }
-
- /* create a new iterator if were already using this one */
- if (self->iter == -1) {
- self->iter = 0;
- Py_INCREF(self);
- return (PyObject *)self;
- } else {
- return KX_PythonSeq_CreatePyObject(self->base, self->type);
- }
-}
-
-
-/*
- * Return next KX_PythonSeq iter.
- */
-
-static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self)
-{
- PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter);
-
- self->iter++;
- if ( object==NULL ) {
- self->iter= -1; /* for reuse */
- PyErr_SetNone(PyExc_StopIteration);
- }
- return object; /* can be NULL for end of iterator */
-}
-
-
-static int KX_PythonSeq_compare(KX_PythonSeq *a, KX_PythonSeq *b)
-{
- return (a->type == b->type && a->base == b->base) ? 0 : -1;
-}
-
-static PyObject *KX_PythonSeq_richcmp(PyObject *a, PyObject *b, int op)
-{
- PyObject *res;
- int ok= -1; /* zero is true */
-
- if (BPy_KX_PythonSeq_Check(a) && BPy_KX_PythonSeq_Check(b))
- ok= KX_PythonSeq_compare((KX_PythonSeq *)a, (KX_PythonSeq *)b);
-
- switch (op) {
- case Py_NE:
- ok = !ok;
- /* fall-through */
- case Py_EQ:
- res = ok ? Py_False : Py_True;
- break;
-
- case Py_LT:
- case Py_LE:
- case Py_GT:
- case Py_GE:
- res = Py_NotImplemented;
- break;
- default:
- PyErr_BadArgument();
- return NULL;
- }
-
- Py_INCREF(res);
- return res;
-}
-
-
-/*
- * repr function
- * convert to a list and get its string value
- */
-static PyObject *KX_PythonSeq_repr(KX_PythonSeq *self)
-{
- PyObject *list = PySequence_List((PyObject *)self);
- PyObject *repr = PyObject_Repr(list);
- Py_DECREF(list);
- return repr;
-}
-
-
-/*****************************************************************************/
-/* Python KX_PythonSeq_Type structure definition: */
-/*****************************************************************************/
-PyTypeObject KX_PythonSeq_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- /* For printing, in format "<module>.<name>" */
- "KX_PythonSeq", /* char *tp_name; */
- sizeof( KX_PythonSeq ), /* int tp_basicsize; */
- 0, /* tp_itemsize; For allocation */
-
- /* Methods to implement standard operations */
-
- ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
- NULL, /* cmpfunc tp_compare; */
- ( reprfunc ) KX_PythonSeq_repr, /* reprfunc tp_repr; */
-
- /* Method suites for standard classes */
-
- NULL, /* PyNumberMethods *tp_as_number; */
- &KX_PythonSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
- &KX_PythonSeq_as_mapping, /* PyMappingMethods *tp_as_mapping; */
-
- /* More standard operations (here for binary compatibility) */
-
- NULL, /* hashfunc tp_hash; */
- NULL, /* ternaryfunc tp_call; */
- NULL, /* reprfunc tp_str; */
- NULL, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
-
- /* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
-
- /*** Flags to define presence of optional/expanded features ***/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */
-
- NULL, /* char *tp_doc; Documentation string */
- /*** Assigned meaning in release 2.0 ***/
- /* call function for all accessible objects */
- (traverseproc)KX_PythonSeq_traverse, /* traverseproc tp_traverse; */
-
- /* delete references to contained objects */
- (inquiry)KX_PythonSeq_clear, /* inquiry tp_clear; */
-
- /*** Assigned meaning in release 2.1 ***/
- /*** rich comparisons ***/
- (richcmpfunc)KX_PythonSeq_richcmp, /* richcmpfunc tp_richcompare; */
-
- /*** weak reference enabler ***/
- 0, /* long tp_weaklistoffset; */
-
- /*** Added in release 2.2 ***/
- /* Iterators */
- ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
- ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
-
- /*** Attribute descriptor and subclassing stuff ***/
- KX_PythonSeq_methods, /* struct PyMethodDef *tp_methods; */
- NULL, /* struct PyMemberDef *tp_members; */
- NULL, /* struct PyGetSetDef *tp_getset; */
- NULL, /* struct _typeobject *tp_base; */
- NULL, /* PyObject *tp_dict; */
- NULL, /* descrgetfunc tp_descr_get; */
- NULL, /* descrsetfunc tp_descr_set; */
- 0, /* long tp_dictoffset; */
- NULL, /* initproc tp_init; */
- NULL, /* allocfunc tp_alloc; */
- NULL, /* newfunc tp_new; */
- /* Low-level free-memory routine */
- NULL, /* freefunc tp_free; */
- /* For PyObject_IS_GC */
- NULL, /* inquiry tp_is_gc; */
- NULL, /* PyObject *tp_bases; */
- /* method resolution order */
- NULL, /* PyObject *tp_mro; */
- NULL, /* PyObject *tp_cache; */
- NULL, /* PyObject *tp_subclasses; */
- NULL, /* PyObject *tp_weaklist; */
- NULL
-};
-
-#endif // WITH_PYTHON
diff --git a/source/gameengine/Ketsji/KX_PythonSeq.h b/source/gameengine/Ketsji/KX_PythonSeq.h
deleted file mode 100644
index 33b5335ddf4..00000000000
--- a/source/gameengine/Ketsji/KX_PythonSeq.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file KX_PythonSeq.h
- * \ingroup ketsji
- * \brief Readonly sequence wrapper for lookups on logic bricks
- */
-
-#ifndef __KX_PYTHONSEQ_H__
-#define __KX_PYTHONSEQ_H__
-
-#ifdef WITH_PYTHON
-
-#include "EXP_PyObjectPlus.h"
-
-// -------------------------
-enum KX_PYGENSEQ_TYPE {
- KX_PYGENSEQ_CONT_TYPE_SENSORS,
- KX_PYGENSEQ_CONT_TYPE_ACTUATORS,
- KX_PYGENSEQ_OB_TYPE_SENSORS,
- KX_PYGENSEQ_OB_TYPE_CONTROLLERS,
- KX_PYGENSEQ_OB_TYPE_ACTUATORS,
- KX_PYGENSEQ_OB_TYPE_CONSTRAINTS,
- KX_PYGENSEQ_OB_TYPE_CHANNELS,
-};
-
-/* The Main PyType Object defined in Main.c */
-extern PyTypeObject KX_PythonSeq_Type;
-
-#define BPy_KX_PythonSeq_Check(obj) \
- (Py_TYPE(obj) == &KX_PythonSeq_Type)
-
-typedef struct {
- PyObject_VAR_HEAD
- PyObject *base;
- short type;
- short iter;
-} KX_PythonSeq;
-
-PyObject *KX_PythonSeq_CreatePyObject(PyObject *base, short type);
-
-#endif /* WITH_PYTHON */
-
-#endif /* __KX_PYTHONSEQ_H__ */
diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp
index 732bcdc3773..861e3f70296 100644
--- a/source/gameengine/Ketsji/KX_RadarSensor.cpp
+++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp
@@ -104,42 +104,42 @@ void KX_RadarSensor::SynchronizeTransform()
{
MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90));
trans.rotate(rotquatje);
- trans.translate(MT_Vector3 (0, -m_coneheight/2.0, 0));
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0));
break;
};
case SENS_RADAR_Y_AXIS: // +Y Axis
{
MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180));
trans.rotate(rotquatje);
- trans.translate(MT_Vector3 (0, -m_coneheight/2.0, 0));
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0));
break;
};
case SENS_RADAR_Z_AXIS: // +Z Axis
{
MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-90));
trans.rotate(rotquatje);
- trans.translate(MT_Vector3 (0, -m_coneheight/2.0, 0));
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0));
break;
};
case SENS_RADAR_NEG_X_AXIS: // -X Axis
{
MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(-90));
trans.rotate(rotquatje);
- trans.translate(MT_Vector3 (0, -m_coneheight/2.0, 0));
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0));
break;
};
case SENS_RADAR_NEG_Y_AXIS: // -Y Axis
{
//MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180));
//trans.rotate(rotquatje);
- trans.translate(MT_Vector3 (0, -m_coneheight/2.0, 0));
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0));
break;
};
case SENS_RADAR_NEG_Z_AXIS: // -Z Axis
{
MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(90));
trans.rotate(rotquatje);
- trans.translate(MT_Vector3 (0, -m_coneheight/2.0, 0));
+ trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0));
break;
};
default:
@@ -154,7 +154,7 @@ void KX_RadarSensor::SynchronizeTransform()
m_cone_origin[1] = temp[1];
m_cone_origin[2] = temp[2];
- temp = trans(MT_Point3(0, -m_coneheight/2.0, 0));
+ temp = trans(MT_Point3(0, -m_coneheight/2.0f, 0));
m_cone_target[0] = temp[0];
m_cone_target[1] = temp[1];
m_cone_target[2] = temp[2];
diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp
index 333e7b57d67..478019c6304 100644
--- a/source/gameengine/Ketsji/KX_RayCast.cpp
+++ b/source/gameengine/Ketsji/KX_RayCast.cpp
@@ -103,11 +103,11 @@ bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_
// but it would require some change in Bullet.
prevpoint = callback.m_hitPoint;
/* We add 0.001 of fudge, so that if the margin && radius == 0.0, we don't endless loop. */
- MT_Scalar marg = 0.001 + hit_controller->GetMargin();
+ MT_Scalar marg = 0.001f + hit_controller->GetMargin();
marg *= 2.f;
/* Calculate the other side of this object */
MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal));
- if (h <= 0.01)
+ if (h <= 0.01f)
// the normal is almost orthogonal to the ray direction, cannot compute the other side
break;
marg /= h;
diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h
index e47ac676eb1..c977fb8f385 100644
--- a/source/gameengine/Ketsji/KX_RayCast.h
+++ b/source/gameengine/Ketsji/KX_RayCast.h
@@ -44,12 +44,15 @@ struct KX_ClientObjectInfo;
/**
* Defines a function for doing a ray cast.
*
- * eg KX_RayCast::RayTest(ignore_physics_controller, physics_environment, frompoint, topoint, result_point, result_normal, KX_RayCast::Callback<KX_MyClass>(this, data)
+ * eg KX_RayCast::RayTest(ignore_physics_controller, physics_environment, frompoint, topoint, result_point, result_normal, KX_RayCast::Callback<MyClass, MyDataClass>(this, data)
*
- * Calls myclass->RayHit(client, hit_point, hit_normal, data) for all client
+ * Calls myclass->NeedRayCast(client, data) for all client in environment
+ * and myclass->RayHit(client, hit_point, hit_normal, data) for all client
* between frompoint and topoint
*
- * myclass->RayHit should return true to end the raycast, false to ignore the current client.
+ * myclass->NeedRayCast should return true to ray test the current client.
+ *
+ * myclass->RayHit should return true to end the raycast, false to ignore the current client and to continue.
*
* Returns true if a client was accepted, false if nothing found.
*/
@@ -80,10 +83,10 @@ public:
/**
* Callback wrapper.
*
- * Construct with KX_RayCast::Callback<MyClass>(this, data)
+ * Construct with KX_RayCast::Callback<MyClass, MyDataClass>(this, data)
* and pass to KX_RayCast::RayTest
*/
- template<class T> class Callback;
+ template<class T, class dataT> class Callback;
/// Public interface.
/// Implement bool RayHit in your class to receive ray callbacks.
@@ -99,12 +102,18 @@ public:
#endif
};
-template<class T> class KX_RayCast::Callback : public KX_RayCast
+template<class T, class dataT>
+class KX_RayCast::Callback : public KX_RayCast
{
T *self;
- void *data;
+ /**
+ * Some user info passed as argument in constructor.
+ * It contains all info needed to check client in NeedRayCast
+ * and RayHit.
+ */
+ dataT *data;
public:
- Callback(T *_self, PHY_IPhysicsController* controller=NULL, void *_data = NULL, bool faceNormal=false, bool faceUV=false)
+ Callback(T *_self, PHY_IPhysicsController *controller = NULL, dataT *_data = NULL, bool faceNormal = false, bool faceUV = false)
: KX_RayCast(controller, faceNormal, faceUV),
self(_self),
data(_data)
@@ -127,7 +136,7 @@ public:
MT_assert(info && "Physics controller with no client object info");
return false;
}
- return self->NeedRayCast(info);
+ return self->NeedRayCast(info, data);
}
diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp
index c97d233a67b..4ffb5f332db 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.cpp
+++ b/source/gameengine/Ketsji/KX_RaySensor.cpp
@@ -107,7 +107,7 @@ bool KX_RaySensor::IsPositiveTrigger()
return result;
}
-bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data))
{
KX_GameObject* hitKXObj = client->m_gameobject;
@@ -158,7 +158,7 @@ bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void
/* this function is used to pre-filter the object before casting the ray on them.
* This is useful for "X-Ray" option when we want to see "through" unwanted object.
*/
-bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client)
+bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data))
{
KX_GameObject *hitKXObj = client->m_gameobject;
@@ -282,7 +282,7 @@ bool KX_RaySensor::Evaluate()
PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment();
- KX_RayCast::Callback<KX_RaySensor> callback(this, spc);
+ KX_RayCast::Callback<KX_RaySensor, void> callback(this, spc);
KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback);
/* now pass this result to some controller */
diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h
index 4604863a233..1901bb04f86 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.h
+++ b/source/gameengine/Ketsji/KX_RaySensor.h
@@ -38,6 +38,8 @@
#include "SCA_IScene.h" /* only for scene replace */
#include "KX_Scene.h" /* only for scene replace */
+#include "BLI_utildefines.h"
+
struct KX_ClientObjectInfo;
class KX_RayCast;
@@ -74,8 +76,10 @@ public:
virtual bool IsPositiveTrigger();
virtual void Init();
- bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
- bool NeedRayCast(KX_ClientObjectInfo* client);
+ /// \see KX_RayCast
+ bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data));
+ /// \see KX_RayCast
+ bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data));
virtual void Replace_IScene(SCA_IScene *val)
{
diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
index fdcfd22270b..bb38d8269b7 100644
--- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
@@ -216,7 +216,7 @@ int KX_SCA_AddObjectActuator::pyattr_set_object(void *self, const struct KX_PYAT
KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self);
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SCA_AddObjectActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SCA_AddObjectActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (actuator->m_OriginalObject != NULL)
diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp
index 96e1cc29de3..a4220424c6f 100644
--- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp
@@ -73,7 +73,7 @@ PyMethodDef KX_SCA_DynamicActuator::Methods[] = {
PyAttributeDef KX_SCA_DynamicActuator::Attributes[] = {
KX_PYATTRIBUTE_SHORT_RW("mode",0,4,false,KX_SCA_DynamicActuator,m_dyn_operation),
- KX_PYATTRIBUTE_FLOAT_RW("mass",0.0,FLT_MAX,KX_SCA_DynamicActuator,m_setmass),
+ KX_PYATTRIBUTE_FLOAT_RW("mass",0.0f,FLT_MAX,KX_SCA_DynamicActuator,m_setmass),
{ NULL } //Sentinel
};
diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
index 6b6b090c1c4..1bf76de0b40 100644
--- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
@@ -101,7 +101,7 @@ int KX_SCA_ReplaceMeshActuator::pyattr_set_mesh(void *self, const struct KX_PYAT
KX_SCA_ReplaceMeshActuator* actuator = static_cast<KX_SCA_ReplaceMeshActuator*>(self);
RAS_MeshObject* new_mesh;
- if (!ConvertPythonToMesh(value, &new_mesh, true, "actuator.mesh = value: KX_SCA_ReplaceMeshActuator"))
+ if (!ConvertPythonToMesh(actuator->GetLogicManager(), value, &new_mesh, true, "actuator.mesh = value: KX_SCA_ReplaceMeshActuator"))
return PY_SET_ATTR_FAIL;
actuator->m_mesh = new_mesh;
diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
index 19b9d13087d..5a13cf5440d 100644
--- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
+++ b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp
@@ -89,7 +89,7 @@ UpdateChildCoordinates(
{
// Get the child's transform, and the bone matrix.
MT_Matrix4x4 child_transform (
- MT_Transform(child_pos + MT_Vector3(0.0, armature->GetBoneLength(m_bone), 0.0),
+ MT_Transform(child_pos + MT_Vector3(0.0f, armature->GetBoneLength(m_bone), 0.0f),
child_rotation.scaled(
child_scale[0],
child_scale[1],
@@ -107,7 +107,7 @@ UpdateChildCoordinates(
child_w_rotation.setValue(child_transform[0][0], child_transform[0][1], child_transform[0][2],
child_transform[1][0], child_transform[1][1], child_transform[1][2],
child_transform[2][0], child_transform[2][1], child_transform[2][2]);
- child_w_rotation.scale(1.0/child_w_scale[0], 1.0/child_w_scale[1], 1.0/child_w_scale[2]);
+ child_w_rotation.scale(1.0f/child_w_scale[0], 1.0f/child_w_scale[1], 1.0f/child_w_scale[2]);
child_w_pos = MT_Point3(child_transform[0][3], child_transform[1][3], child_transform[2][3]);
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 723736906a9..a5a418b5e78 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -898,7 +898,7 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
m_tempObjectList->Add(replica->AddRef());
// this convert the life from frames to sort-of seconds, hard coded 0.02 that assumes we have 50 frames per second
// if you change this value, make sure you change it in KX_GameObject::pyattr_get_life property too
- CValue *fval = new CFloatValue(lifespan*0.02);
+ CValue *fval = new CFloatValue(lifespan*0.02f);
replica->SetProperty("::timebomb",fval);
fval->Release();
}
@@ -1006,17 +1006,28 @@ void KX_Scene::RemoveObject(class CValue* gameobj)
//newobj->SetSGNode(0);
}
+void KX_Scene::RemoveDupliGroup(class CValue *gameobj)
+{
+ KX_GameObject *newobj = (KX_GameObject *) gameobj;
+
+ if (newobj->IsDupliGroup()) {
+ for (int i = 0; i < newobj->GetInstanceObjects()->GetCount(); i++) {
+ CValue *obj = newobj->GetInstanceObjects()->GetValue(i);
+ DelayedRemoveObject(obj);
+ }
+ }
+}
+
void KX_Scene::DelayedRemoveObject(class CValue* gameobj)
{
- //KX_GameObject* newobj = (KX_GameObject*) gameobj;
+ RemoveDupliGroup(gameobj);
+
if (!m_euthanasyobjects->SearchValue(gameobj))
{
m_euthanasyobjects->Add(gameobj->AddRef());
- }
+ }
}
-
-
int KX_Scene::NewRemoveObject(class CValue* gameobj)
{
int ret;
@@ -1546,9 +1557,9 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int
planes[5].setValue(cplanes[3].getValue()); // bottom
CullingInfo info(layer);
- double mvmat[16] = {0};
+ float mvmat[16] = {0};
cam->GetModelviewMatrix().getValue(mvmat);
- double pmat[16] = {0};
+ float pmat[16] = {0};
cam->GetProjectionMatrix().getValue(pmat);
dbvt_culling = m_physicsEnvironment->CullingTest(PhysicsCullingCallback,&info,planes,5,m_dbvt_occlusion_res,
@@ -1577,7 +1588,7 @@ void KX_Scene::LogicBeginFrame(double curtime)
if (propval)
{
- float timeleft = propval->GetNumber() - 1.0/KX_KetsjiEngine::GetTicRate();
+ float timeleft = (float)(propval->GetNumber() - 1.0/KX_KetsjiEngine::GetTicRate());
if (timeleft > 0)
{
@@ -1678,10 +1689,6 @@ void KX_Scene::UpdateAnimations(double curtime)
BLI_task_pool_work_and_wait(pool);
BLI_task_pool_free(pool);
-
- for (int i=0; i<m_animatedlist->GetCount(); ++i) {
- ((KX_GameObject*)m_animatedlist->GetValue(i))->UpdateActionIPOs();
- }
}
void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
@@ -1820,9 +1827,9 @@ void KX_Scene::UpdateObjectActivity(void)
* Manhattan distance. */
MT_Point3 obpos = ob->NodeGetWorldPosition();
- if ((fabs(camloc[0] - obpos[0]) > m_activity_box_radius) ||
- (fabs(camloc[1] - obpos[1]) > m_activity_box_radius) ||
- (fabs(camloc[2] - obpos[2]) > m_activity_box_radius) )
+ if ((fabsf(camloc[0] - obpos[0]) > m_activity_box_radius) ||
+ (fabsf(camloc[1] - obpos[1]) > m_activity_box_radius) ||
+ (fabsf(camloc[2] - obpos[2]) > m_activity_box_radius) )
{
ob->Suspend();
}
@@ -1836,8 +1843,8 @@ void KX_Scene::UpdateObjectActivity(void)
void KX_Scene::SetActivityCullingRadius(float f)
{
- if (f < 0.5)
- f = 0.5;
+ if (f < 0.5f)
+ f = 0.5f;
m_activity_box_radius = f;
}
@@ -1918,6 +1925,7 @@ static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *from, KX_Sce
brick->Replace_IScene(to);
brick->Replace_NetworkScene(to->GetNetworkScene());
+ brick->SetLogicManager(to->GetLogicManager());
// If we end up replacing a KX_TouchEventManager, we need to make sure
// physics controllers are properly in place. In other words, do this
@@ -2534,8 +2542,8 @@ KX_PYMETHODDEF_DOC(KX_Scene, addObject,
if (!PyArg_ParseTuple(args, "O|Oi:addObject", &pyob, &pyreference, &time))
return NULL;
- if (!ConvertPythonToGameObject(pyob, &ob, false, "scene.addObject(object, reference, time): KX_Scene (first argument)") ||
- !ConvertPythonToGameObject(pyreference, &reference, true, "scene.addObject(object, reference, time): KX_Scene (second argument)"))
+ if (!ConvertPythonToGameObject(m_logicmgr, pyob, &ob, false, "scene.addObject(object, reference, time): KX_Scene (first argument)") ||
+ !ConvertPythonToGameObject(m_logicmgr, pyreference, &reference, true, "scene.addObject(object, reference, time): KX_Scene (second argument)"))
return NULL;
if (!m_inactivelist->SearchValue(ob)) {
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index 4f7ad98f30d..c43b7be45dc 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -93,7 +93,7 @@ class KX_ObstacleSimulation;
#endif
/* for ID freeing */
-#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->flag & LIB_DOIT))
+#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT))
/**
* The KX_Scene holds all data for an independent scene. It relates
@@ -339,6 +339,7 @@ public:
void RemoveNodeDestructObject(SG_IObject* node,
CValue* gameobj);
void RemoveObject(CValue* gameobj);
+ void RemoveDupliGroup(CValue *gameobj);
void DelayedRemoveObject(CValue* gameobj);
int NewRemoveObject(CValue* gameobj);
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index 02b1071e267..1c42d65ae75 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -65,7 +65,7 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
KX_SOUNDACT_TYPE type)//,
: SCA_IActuator(gameobj, KX_ACT_SOUND)
{
- m_sound = AUD_Sound_copy(sound);
+ m_sound = sound ? AUD_Sound_copy(sound) : NULL;
m_handle = NULL;
m_volume = volume;
m_pitch = pitch;
@@ -379,7 +379,7 @@ PyObject *KX_SoundActuator::pyattr_get_3d_property(void *self, const struct KX_P
{
KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
const char* prop = attrdef->m_name;
- float result_value = 0.0;
+ float result_value = 0.0f;
if (!strcmp(prop, "volume_maximum")) {
result_value = actuator->m_3d.max_gain;
@@ -416,7 +416,7 @@ PyObject *KX_SoundActuator::pyattr_get_3d_property(void *self, const struct KX_P
PyObject *KX_SoundActuator::pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
{
KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
- float position = 0.0;
+ float position = 0.0f;
if (actuator->m_handle)
position = AUD_Handle_getPosition(actuator->m_handle);
@@ -459,7 +459,7 @@ int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRI
{
KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
const char* prop = attrdef->m_name;
- float prop_value = 0.0;
+ float prop_value = 0.0f;
if (!PyArg_Parse(value, "f", &prop_value))
return PY_SET_ATTR_FAIL;
@@ -519,7 +519,7 @@ int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRI
{
KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
- float position = 1.0;
+ float position = 1.0f;
if (!PyArg_Parse(value, "f", &position))
return PY_SET_ATTR_FAIL;
@@ -530,7 +530,7 @@ int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRI
int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
- float gain = 1.0;
+ float gain = 1.0f;
KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
if (!PyArg_Parse(value, "f", &gain))
return PY_SET_ATTR_FAIL;
@@ -544,7 +544,7 @@ int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DE
int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
{
- float pitch = 1.0;
+ float pitch = 1.0f;
KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
if (!PyArg_Parse(value, "f", &pitch))
return PY_SET_ATTR_FAIL;
diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp
index cd2cd2bae0b..d3a7b665e61 100644
--- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp
@@ -169,8 +169,8 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
if (m_posevent && !m_isActive)
{
- delta = 0;
- m_pathUpdateTime = -1;
+ delta = 0.0;
+ m_pathUpdateTime = -1.0;
m_updateTime = curtime;
m_isActive = true;
}
@@ -191,8 +191,8 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
const MT_Point3& targpos = m_target->NodeGetWorldPosition();
MT_Vector3 vectotarg = targpos - mypos;
MT_Vector3 vectotarg2d = vectotarg;
- vectotarg2d.z() = 0;
- m_steerVec = MT_Vector3(0, 0, 0);
+ vectotarg2d.z() = 0.0f;
+ m_steerVec = MT_Vector3(0.0f, 0.0f, 0.0f);
bool apply_steerforce = false;
bool terminate = true;
@@ -220,10 +220,10 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
{
terminate = false;
- static const MT_Scalar WAYPOINT_RADIUS(0.25);
+ static const MT_Scalar WAYPOINT_RADIUS(0.25f);
if (m_pathUpdateTime<0 || (m_pathUpdatePeriod>=0 &&
- curtime - m_pathUpdateTime>((double)m_pathUpdatePeriod/1000)))
+ curtime - m_pathUpdateTime>((double)m_pathUpdatePeriod/1000.0)))
{
m_pathUpdateTime = curtime;
m_pathLen = m_navmesh->FindPath(mypos, targpos, m_path, MAX_PATH_LENGTH);
@@ -252,7 +252,7 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
if (m_enableVisualization)
{
//debug draw
- static const MT_Vector3 PATH_COLOR(1,0,0);
+ static const MT_Vector3 PATH_COLOR(1.0f,0.0f,0.0f);
m_navmesh->DrawPath(m_path, m_pathLen, PATH_COLOR);
}
}
@@ -274,11 +274,11 @@ bool KX_SteeringActuator::Update(double curtime, bool frame)
if (m_simulation && m_obstacle /*&& !newvel.fuzzyZero()*/)
{
if (m_enableVisualization)
- KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(1.0, 0.0, 0.0));
+ KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(1.0f, 0.0f, 0.0f));
m_simulation->AdjustObstacleVelocity(m_obstacle, m_mode!=KX_STEERING_PATHFOLLOWING ? m_navmesh : NULL,
- newvel, m_acceleration*delta, m_turnspeed/180.0f*M_PI*delta);
+ newvel, m_acceleration*(float)delta, m_turnspeed/(180.0f*(float)(M_PI*delta)));
if (m_enableVisualization)
- KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.0, 1.0, 0.0));
+ KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.0f, 1.0f, 0.0f));
}
HandleActorFace(newvel);
@@ -579,7 +579,7 @@ int KX_SteeringActuator::pyattr_set_target(void *self, const struct KX_PYATTRIBU
KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self);
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SteeringActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (actuator->m_target != NULL)
@@ -607,7 +607,7 @@ int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIB
KX_SteeringActuator* actuator = static_cast<KX_SteeringActuator*>(self);
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SteeringActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (dynamic_cast<KX_NavMeshObject *>(gameobj) == NULL) {
diff --git a/source/gameengine/Ketsji/KX_TimeLogger.cpp b/source/gameengine/Ketsji/KX_TimeLogger.cpp
index 1a0d3d28d4c..12106245c4d 100644
--- a/source/gameengine/Ketsji/KX_TimeLogger.cpp
+++ b/source/gameengine/Ketsji/KX_TimeLogger.cpp
@@ -109,7 +109,7 @@ double KX_TimeLogger::GetAverage(void) const
for (unsigned int i = 1; i < numMeasurements; i++) {
avg += m_measurements[i];
}
- avg /= (float)numMeasurements - 1;
+ avg /= (double)numMeasurements - 1.0;
}
return avg;
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
index eb774960d41..7f167652464 100644
--- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
@@ -235,5 +235,12 @@ KX_TouchEventManager::NewCollision::NewCollision(const NewCollision &to_copy)
bool KX_TouchEventManager::NewCollision::operator<(const NewCollision &other) const
{
- return first < other.first || second < other.second || colldata < other.colldata;
+ //see strict weak ordering: https://support.microsoft.com/en-us/kb/949171
+ if (first == other.first) {
+ if (second == other.second) {
+ return colldata < other.colldata;
+ }
+ return second < other.second;
+ }
+ return first < other.first;
}
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
index 3ed8eba759f..beccdfaad93 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
@@ -92,12 +92,12 @@ static MT_Matrix3x3 EulToMat3(float eul[3])
MT_Matrix3x3 mat;
float ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
- ci = cos(eul[0]);
- cj = cos(eul[1]);
- ch = cos(eul[2]);
- si = sin(eul[0]);
- sj = sin(eul[1]);
- sh = sin(eul[2]);
+ ci = cosf(eul[0]);
+ cj = cosf(eul[1]);
+ ch = cosf(eul[2]);
+ si = sinf(eul[0]);
+ sj = sinf(eul[1]);
+ sh = sinf(eul[2]);
cc = ci*ch;
cs = ci*sh;
sc = si*ch;
@@ -131,7 +131,7 @@ static void Mat3ToEulOld(MT_Matrix3x3 mat, float eul[3])
else {
eul[0] = atan2f(-mat[2][1], mat[1][1]);
eul[1] = atan2f(-mat[0][2], cy);
- eul[2] = 0.0;
+ eul[2] = 0.0f;
}
}
@@ -196,8 +196,8 @@ static float basis_cross(int n, int m)
static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short threedimup)
{
MT_Matrix3x3 mat;
- MT_Vector3 y(MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0));
- MT_Vector3 z(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); /* world Z axis is the global up axis */
+ MT_Vector3 y(MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f));
+ MT_Vector3 z(MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f)); /* world Z axis is the global up axis */
MT_Vector3 proj;
MT_Vector3 right;
MT_Scalar mul;
@@ -208,7 +208,7 @@ static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short thr
/* if 2D doesn't move the up vector */
if (!threedimup){
- vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0));
+ vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0f));
vec = (vec - z.dot(vec)*z).safe_normalized_vec(z);
}
@@ -411,7 +411,7 @@ int KX_TrackToActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUT
KX_TrackToActuator* actuator = static_cast<KX_TrackToActuator*>(self);
KX_GameObject *gameobj;
- if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_TrackToActuator"))
+ if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_TrackToActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
if (actuator->m_object != NULL)
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
index ee791a44782..c1af6de127e 100644
--- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -30,6 +30,7 @@
#include "KX_PyMath.h"
#include "KX_GameObject.h"
#include "KX_MotionState.h"
+#include "KX_PythonInit.h"
KX_VehicleWrapper::KX_VehicleWrapper(
PHY_IVehicle* vehicle,
@@ -82,7 +83,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
if (PyArg_ParseTuple(args,"OOOOffi:addWheel",&wheelGameObject,&pylistPos,&pylistDir,&pylistAxleDir,&suspensionRestLength,&wheelRadius,&hasSteering))
{
KX_GameObject *gameOb;
- if (!ConvertPythonToGameObject(wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)"))
+ if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)"))
return NULL;
if (gameOb->GetSGNode())
diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp
index cd1c9eed91b..40f4c462801 100644
--- a/source/gameengine/Ketsji/KX_VertexProxy.cpp
+++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp
@@ -198,7 +198,7 @@ PyObject *KX_VertexProxy::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DE
KX_VertexProxy* self = static_cast<KX_VertexProxy*>(self_v);
const unsigned char *colp = self->m_vertex->getRGBA();
MT_Vector4 color(colp[0], colp[1], colp[2], colp[3]);
- color /= 255.0;
+ color /= 255.0f;
return PyObjectFrom(color);
}
@@ -321,7 +321,7 @@ int KX_VertexProxy::pyattr_set_r(void *self_v, const struct KX_PYATTRIBUTE_DEF *
float val = PyFloat_AsDouble(value);
unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA());
unsigned char *cp = (unsigned char*) &icol;
- val *= 255.0;
+ val *= 255.0f;
cp[0] = (unsigned char) val;
self->m_vertex->SetRGBA(icol);
self->m_mesh->SetMeshModified(true);
@@ -338,7 +338,7 @@ int KX_VertexProxy::pyattr_set_g(void *self_v, const struct KX_PYATTRIBUTE_DEF *
float val = PyFloat_AsDouble(value);
unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA());
unsigned char *cp = (unsigned char*) &icol;
- val *= 255.0;
+ val *= 255.0f;
cp[1] = (unsigned char) val;
self->m_vertex->SetRGBA(icol);
self->m_mesh->SetMeshModified(true);
@@ -355,7 +355,7 @@ int KX_VertexProxy::pyattr_set_b(void *self_v, const struct KX_PYATTRIBUTE_DEF *
float val = PyFloat_AsDouble(value);
unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA());
unsigned char *cp = (unsigned char*) &icol;
- val *= 255.0;
+ val *= 255.0f;
cp[2] = (unsigned char) val;
self->m_vertex->SetRGBA(icol);
self->m_mesh->SetMeshModified(true);
@@ -372,7 +372,7 @@ int KX_VertexProxy::pyattr_set_a(void *self_v, const struct KX_PYATTRIBUTE_DEF *
float val = PyFloat_AsDouble(value);
unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA());
unsigned char *cp = (unsigned char*) &icol;
- val *= 255.0;
+ val *= 255.0f;
cp[3] = (unsigned char) val;
self->m_vertex->SetRGBA(icol);
self->m_mesh->SetMeshModified(true);
diff --git a/source/gameengine/Ketsji/KX_WorldInfo.cpp b/source/gameengine/Ketsji/KX_WorldInfo.cpp
index 111d81cad2e..be8b1ce92fc 100644
--- a/source/gameengine/Ketsji/KX_WorldInfo.cpp
+++ b/source/gameengine/Ketsji/KX_WorldInfo.cpp
@@ -253,11 +253,11 @@ PyAttributeDef KX_WorldInfo::Attributes[] = {
/*----------------------mathutils callbacks ----------------------------*/
/* subtype */
-#define MATHUTILS_VEC_CB_MIST_COLOR 1
-#define MATHUTILS_VEC_CB_BACK_COLOR 2
-#define MATHUTILS_VEC_CB_AMBIENT_COLOR 3
+#define MATHUTILS_COL_CB_MIST_COLOR 1
+#define MATHUTILS_COL_CB_BACK_COLOR 2
+#define MATHUTILS_COL_CB_AMBIENT_COLOR 3
-static unsigned char mathutils_world_vector_cb_index = -1; /* index for our callbacks */
+static unsigned char mathutils_world_color_cb_index = -1; /* index for our callbacks */
static int mathutils_world_generic_check(BaseMathObject *bmo)
{
@@ -268,20 +268,20 @@ static int mathutils_world_generic_check(BaseMathObject *bmo)
return 0;
}
-static int mathutils_world_vector_get(BaseMathObject *bmo, int subtype)
+static int mathutils_world_color_get(BaseMathObject *bmo, int subtype)
{
KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
if (self == NULL)
return -1;
switch (subtype) {
- case MATHUTILS_VEC_CB_MIST_COLOR:
+ case MATHUTILS_COL_CB_MIST_COLOR:
copy_v3_v3(bmo->data, self->m_mistcolor);
break;
- case MATHUTILS_VEC_CB_BACK_COLOR:
+ case MATHUTILS_COL_CB_BACK_COLOR:
copy_v3_v3(bmo->data, self->m_backgroundcolor);
break;
- case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ case MATHUTILS_COL_CB_AMBIENT_COLOR:
copy_v3_v3(bmo->data, self->m_ambientcolor);
break;
default:
@@ -290,7 +290,7 @@ static int mathutils_world_vector_get(BaseMathObject *bmo, int subtype)
return 0;
}
-static int mathutils_world_vector_set(BaseMathObject *bmo, int subtype)
+static int mathutils_world_color_set(BaseMathObject *bmo, int subtype)
{
KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
@@ -298,13 +298,13 @@ static int mathutils_world_vector_set(BaseMathObject *bmo, int subtype)
return -1;
switch (subtype) {
- case MATHUTILS_VEC_CB_MIST_COLOR:
+ case MATHUTILS_COL_CB_MIST_COLOR:
self->setMistColor(bmo->data[0], bmo->data[1], bmo->data[2]);
break;
- case MATHUTILS_VEC_CB_BACK_COLOR:
+ case MATHUTILS_COL_CB_BACK_COLOR:
self->setBackColor(bmo->data[0], bmo->data[1], bmo->data[2]);
break;
- case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ case MATHUTILS_COL_CB_AMBIENT_COLOR:
self->setAmbientColor(bmo->data[0], bmo->data[1], bmo->data[2]);
break;
default:
@@ -313,7 +313,7 @@ static int mathutils_world_vector_set(BaseMathObject *bmo, int subtype)
return 0;
}
-static int mathutils_world_vector_get_index(BaseMathObject *bmo, int subtype, int index)
+static int mathutils_world_color_get_index(BaseMathObject *bmo, int subtype, int index)
{
KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
@@ -321,19 +321,19 @@ static int mathutils_world_vector_get_index(BaseMathObject *bmo, int subtype, in
return -1;
switch (subtype) {
- case MATHUTILS_VEC_CB_MIST_COLOR:
+ case MATHUTILS_COL_CB_MIST_COLOR:
{
const float *color = self->m_mistcolor;
bmo->data[index] = color[index];
}
break;
- case MATHUTILS_VEC_CB_BACK_COLOR:
+ case MATHUTILS_COL_CB_BACK_COLOR:
{
const float *color = self->m_backgroundcolor;
bmo->data[index] = color[index];
}
break;
- case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ case MATHUTILS_COL_CB_AMBIENT_COLOR:
{
const float *color = self->m_ambientcolor;
bmo->data[index] = color[index];
@@ -345,7 +345,7 @@ static int mathutils_world_vector_get_index(BaseMathObject *bmo, int subtype, in
return 0;
}
-static int mathutils_world_vector_set_index(BaseMathObject *bmo, int subtype, int index)
+static int mathutils_world_color_set_index(BaseMathObject *bmo, int subtype, int index)
{
KX_WorldInfo *self = static_cast<KX_WorldInfo*>BGE_PROXY_REF(bmo->cb_user);
@@ -354,17 +354,17 @@ static int mathutils_world_vector_set_index(BaseMathObject *bmo, int subtype, in
float color[4];
switch (subtype) {
- case MATHUTILS_VEC_CB_MIST_COLOR:
+ case MATHUTILS_COL_CB_MIST_COLOR:
copy_v3_v3(color, self->m_mistcolor);
color[index] = bmo->data[index];
self->setMistColor(color[0], color[1], color[2]);
break;
- case MATHUTILS_VEC_CB_BACK_COLOR:
+ case MATHUTILS_COL_CB_BACK_COLOR:
copy_v3_v3(color, self->m_backgroundcolor);
color[index] = bmo->data[index];
self->setBackColor(color[0], color[1], color[2]);
break;
- case MATHUTILS_VEC_CB_AMBIENT_COLOR:
+ case MATHUTILS_COL_CB_AMBIENT_COLOR:
copy_v3_v3(color, self->m_ambientcolor);
color[index] = bmo->data[index];
self->setAmbientColor(color[0], color[1], color[2]);
@@ -375,18 +375,18 @@ static int mathutils_world_vector_set_index(BaseMathObject *bmo, int subtype, in
return 0;
}
-static Mathutils_Callback mathutils_world_vector_cb = {
+static Mathutils_Callback mathutils_world_color_cb = {
mathutils_world_generic_check,
- mathutils_world_vector_get,
- mathutils_world_vector_set,
- mathutils_world_vector_get_index,
- mathutils_world_vector_set_index
+ mathutils_world_color_get,
+ mathutils_world_color_set,
+ mathutils_world_color_get_index,
+ mathutils_world_color_set_index
};
void KX_WorldInfo_Mathutils_Callback_Init()
{
// register mathutils callbacks, ok to run more than once.
- mathutils_world_vector_cb_index = Mathutils_RegisterCallback(&mathutils_world_vector_cb);
+ mathutils_world_color_cb_index = Mathutils_RegisterCallback(&mathutils_world_color_cb);
}
#endif // USE_MATHUTILS
@@ -418,9 +418,9 @@ PyObject *KX_WorldInfo::pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRI
PyObject *KX_WorldInfo::pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(
- BGE_PROXY_FROM_REF_BORROW(self_v), 3,
- mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_MIST_COLOR);
+ return Color_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v),
+ mathutils_world_color_cb_index, MATHUTILS_COL_CB_MIST_COLOR);
#else
KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
return PyObjectFrom(MT_Vector3(self->m_mistcolor));
@@ -444,9 +444,9 @@ PyObject *KX_WorldInfo::pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(
- BGE_PROXY_FROM_REF_BORROW(self_v), 3,
- mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_BACK_COLOR);
+ return Color_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v),
+ mathutils_world_color_cb_index, MATHUTILS_COL_CB_BACK_COLOR);
#else
KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
return PyObjectFrom(MT_Vector3(self->m_backgroundcolor));
@@ -469,9 +469,9 @@ int KX_WorldInfo::pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *
PyObject *KX_WorldInfo::pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
#ifdef USE_MATHUTILS
- return Vector_CreatePyObject_cb(
- BGE_PROXY_FROM_REF_BORROW(self_v), 3,
- mathutils_world_vector_cb_index, MATHUTILS_VEC_CB_AMBIENT_COLOR);
+ return Color_CreatePyObject_cb(
+ BGE_PROXY_FROM_REF_BORROW(self_v),
+ mathutils_world_color_cb_index, MATHUTILS_COL_CB_AMBIENT_COLOR);
#else
KX_WorldInfo *self = static_cast<KX_WorldInfo*>(self_v);
return PyObjectFrom(MT_Vector3(self->m_ambientcolor));
diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript
deleted file mode 100644
index d8dfd3d9bca..00000000000
--- a/source/gameengine/Ketsji/SConscript
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '.',
- '#intern/container',
- '#intern/guardedalloc',
- '#intern/string',
- '#source/blender',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#intern/moto/include',
- '#source/blender/blenfont',
- '#source/blender/blenkernel',
- '#source/blender/blenlib',
- '#source/blender/gpu',
- '#source/blender/imbuf',
- '#source/blender/makesdna',
- '#source/blender/makesrna',
- '#source/blender/misc',
- '#source/blender/python',
- '#source/gameengine/BlenderRoutines',
- '#source/gameengine/Converter',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Ketsji',
- '#source/gameengine/Network',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/SceneGraph',
- '#extern/recastnavigation/Detour/Include',
- '#extern/recastnavigation/Recast/Include',
- '#source/blender/editors/include',
- # Only for bpy_internal_import.h, be very careful
- '#source/blender/python/generic',
- # Only for mathutils, be very careful
- '#source/blender/python/mathutils',
- '#source/gameengine/Ketsji/KXNetwork',
- '#source/gameengine/Physics/Dummy',
- '#source/gameengine/Physics/common',
- '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
- ]
-incs = ' '.join(incs)
-
-incs += ' ' + env['BF_BULLET_INC']
-incs += ' ' + env['BF_OPENGL_INC']
-incs += ' ' + env['BF_BOOST_INC']
-
-if env['WITH_BF_SDL']:
- incs += ' ' + env['BF_SDL_INC']
- defs.append('WITH_SDL')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_AUDASPACE']:
- defs += env['BF_AUDASPACE_DEF']
- incs += ' ' + env['BF_AUDASPACE_C_INC']
- incs += ' ' + env['BF_AUDASPACE_PY_INC']
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw', 'win64-mingw'):
- if env['BF_DEBUG']:
- defs.append('_DEBUG') # for Python
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
- incs += ' #source/gameengine/Physics/Bullet'
-
-if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
- incs += ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'ge_logic_ketsji', sources, Split(incs), defs, libtype=['core','player'], priority=[320,45], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Network/LoopBackNetwork/SConscript b/source/gameengine/Network/LoopBackNetwork/SConscript
deleted file mode 100644
index 01352fbe732..00000000000
--- a/source/gameengine/Network/LoopBackNetwork/SConscript
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = [
- 'NG_LoopBackNetworkDeviceInterface.cpp',
- ]
-
-incs = [
- '.',
- '#intern/container',
- '#intern/string',
- '#source/gameengine/Network',
- ]
-
-env.BlenderLib('ge_logic_loopbacknetwork', sources, incs, defines=[], libtype=['core', 'player'], priority=[400, 135])
diff --git a/source/gameengine/Network/SConscript b/source/gameengine/Network/SConscript
deleted file mode 100644
index feb14e29552..00000000000
--- a/source/gameengine/Network/SConscript
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp') #'NG_NetworkMessage.cpp NG_NetworkObject.cpp NG_NetworkScene.cpp'
-
-incs = [
- '.',
- '../../blender/blenlib',
- '#intern/container',
- '#intern/string',
- '#intern/moto/include',
- ]
-
-defs = []
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
- incs.append('#intern/guardedalloc')
-
-env.BlenderLib('ge_logic_ngnetwork', sources, incs, defs, libtype=['core', 'player'], priority=[400, 130])
diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp
index fdafc4e507d..470a5431843 100644
--- a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp
@@ -86,15 +86,15 @@ void CcdGraphicController::GetAabb(btVector3& aabbMin, btVector3& aabbMax)
btVector3 tmpAabbMin = m_localAabbMin * scale;
btVector3 tmpAabbMax = m_localAabbMax * scale;
- localAabbMin[0] = (scale.getX() >= 0.0) ? tmpAabbMin[0] : tmpAabbMax[0];
- localAabbMin[1] = (scale.getY() >= 0.0) ? tmpAabbMin[1] : tmpAabbMax[1];
- localAabbMin[2] = (scale.getZ() >= 0.0) ? tmpAabbMin[2] : tmpAabbMax[2];
- localAabbMax[0] = (scale.getX() <= 0.0) ? tmpAabbMin[0] : tmpAabbMax[0];
- localAabbMax[1] = (scale.getY() <= 0.0) ? tmpAabbMin[1] : tmpAabbMax[1];
- localAabbMax[2] = (scale.getZ() <= 0.0) ? tmpAabbMin[2] : tmpAabbMax[2];
-
- btVector3 localHalfExtents = btScalar(0.5)*(localAabbMax-localAabbMin);
- btVector3 localCenter = btScalar(0.5)*(localAabbMax+localAabbMin);
+ localAabbMin[0] = (scale.getX() >= 0.0f) ? tmpAabbMin[0] : tmpAabbMax[0];
+ localAabbMin[1] = (scale.getY() >= 0.0f) ? tmpAabbMin[1] : tmpAabbMax[1];
+ localAabbMin[2] = (scale.getZ() >= 0.0f) ? tmpAabbMin[2] : tmpAabbMax[2];
+ localAabbMax[0] = (scale.getX() <= 0.0f) ? tmpAabbMin[0] : tmpAabbMax[0];
+ localAabbMax[1] = (scale.getY() <= 0.0f) ? tmpAabbMin[1] : tmpAabbMax[1];
+ localAabbMax[2] = (scale.getZ() <= 0.0f) ? tmpAabbMin[2] : tmpAabbMax[2];
+
+ btVector3 localHalfExtents = btScalar(0.5f)*(localAabbMax-localAabbMin);
+ btVector3 localCenter = btScalar(0.5f)*(localAabbMax+localAabbMin);
btMatrix3x3 abs_b = rot.absolute();
btVector3 center = rot*localCenter + pos;
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index dbaa925db08..c79e1c23ef6 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -81,24 +81,24 @@ void BlenderBulletCharacterController::updateAction(btCollisionWorld *collisionW
m_motionState->setWorldTransform(getGhostObject()->getWorldTransform());
}
-int BlenderBulletCharacterController::getMaxJumps() const
+unsigned char BlenderBulletCharacterController::getMaxJumps() const
{
return m_maxJumps;
}
-void BlenderBulletCharacterController::setMaxJumps(int maxJumps)
+void BlenderBulletCharacterController::setMaxJumps(unsigned char maxJumps)
{
m_maxJumps = maxJumps;
}
-int BlenderBulletCharacterController::getJumpCount() const
+unsigned char BlenderBulletCharacterController::getJumpCount() const
{
return m_jumps;
}
bool BlenderBulletCharacterController::canJump() const
{
- return onGround() || m_jumps < m_maxJumps;
+ return (onGround() && m_maxJumps > 0) || m_jumps < m_maxJumps;
}
void BlenderBulletCharacterController::jump()
@@ -157,7 +157,7 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
m_savedCollisionFlags = 0;
m_savedCollisionFilterGroup = 0;
m_savedCollisionFilterMask = 0;
- m_savedMass = 0.0;
+ m_savedMass = 0.0f;
m_savedDyna = false;
m_suspended = false;
@@ -280,7 +280,7 @@ bool CcdPhysicsController::CreateSoftbody()
rbci.m_friction = m_cci.m_friction;
rbci.m_restitution = m_cci.m_restitution;
- btVector3 p(0,0,0);// = getOrigin();
+ btVector3 p(0.0f,0.0f,0.0f);// = getOrigin();
//btSoftBody* psb=btSoftBodyHelpers::CreateRope(worldInfo, btVector3(-10,0,i*0.25),btVector3(10,0,i*0.25), 16,1+2);
btSoftBody* psb = 0;
btSoftBodyWorldInfo& worldInfo = m_cci.m_physicsEnv->GetDynamicsWorld()->getWorldInfo();
@@ -533,6 +533,7 @@ bool CcdPhysicsController::CreateCharacterController()
m_characterController->setJumpSpeed(m_cci.m_jumpSpeed);
m_characterController->setFallSpeed(m_cci.m_fallSpeed);
+ m_characterController->setMaxJumps(m_cci.m_maxJumps);
return true;
}
@@ -1094,7 +1095,7 @@ void CcdPhysicsController::SuspendDynamics(bool ghost)
m_savedCollisionFilterMask = handle->m_collisionFilterMask;
m_suspended = true;
GetPhysicsEnvironment()->UpdateCcdPhysicsController(this,
- 0.0,
+ 0.0f,
btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)),
btBroadphaseProxy::StaticFilter,
btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter);
@@ -1193,16 +1194,12 @@ void CcdPhysicsController::SetMass(MT_Scalar newmass)
btRigidBody *body = GetRigidBody();
if (body && !m_suspended && newmass>MT_EPSILON && GetMass()>MT_EPSILON)
{
- btVector3 grav = body->getGravity();
- btVector3 accel = grav / GetMass();
-
btBroadphaseProxy* handle = body->getBroadphaseHandle();
GetPhysicsEnvironment()->UpdateCcdPhysicsController(this,
newmass,
body->getCollisionFlags(),
handle->m_collisionFilterGroup,
handle->m_collisionFilterMask);
- body->setGravity(accel);
}
}
@@ -1283,7 +1280,13 @@ void CcdPhysicsController::ApplyForce(const MT_Vector3& forcein,bool local)
void CcdPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local)
{
btVector3 angvel(ang_vel.x(),ang_vel.y(),ang_vel.z());
- if (m_object && angvel.length2() > (SIMD_EPSILON*SIMD_EPSILON))
+
+ /* Refuse tiny tiny velocities, as they might cause instabilities. */
+ float vel_squared = angvel.length2();
+ if (vel_squared > 0 && vel_squared <= (SIMD_EPSILON*SIMD_EPSILON))
+ angvel = btVector3(0, 0, 0);
+
+ if (m_object)
{
m_object->activate(true);
if (m_object->isStaticObject())
@@ -1305,9 +1308,14 @@ void CcdPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool lo
}
void CcdPhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local)
{
-
btVector3 linVel(lin_vel.x(),lin_vel.y(),lin_vel.z());
- if (m_object/* && linVel.length2() > (SIMD_EPSILON*SIMD_EPSILON)*/)
+
+ /* Refuse tiny tiny velocities, as they might cause instabilities. */
+ float vel_squared = linVel.length2();
+ if (vel_squared > 0 && vel_squared <= (SIMD_EPSILON*SIMD_EPSILON))
+ linVel = btVector3(0, 0, 0);
+
+ if (m_object)
{
m_object->activate(true);
if (m_object->isStaticObject())
@@ -1553,9 +1561,9 @@ void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController* child)
rootBody->getMotionState()->getWorldTransform(rootTrans);
childBody->getMotionState()->getWorldTransform(childTrans);
btVector3 rootScale = rootShape->getLocalScaling();
- rootScale[0] = 1.0/rootScale[0];
- rootScale[1] = 1.0/rootScale[1];
- rootScale[2] = 1.0/rootScale[2];
+ rootScale[0] = 1.0f/rootScale[0];
+ rootScale[1] = 1.0f/rootScale[1];
+ rootScale[2] = 1.0f/rootScale[2];
// relative scale = child_scale/parent_scale
btVector3 relativeScale = childShape->getLocalScaling()*rootScale;
btMatrix3x3 rootRotInverse = rootTrans.getBasis().transpose();
@@ -1858,9 +1866,11 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm,
if (!dm) {
free_dm = true;
dm = CDDM_from_mesh(meshobj->GetMesh());
- DM_ensure_tessface(dm);
}
+ // Some meshes with modifiers returns 0 polys, call DM_ensure_tessface avoid this.
+ DM_ensure_tessface(dm);
+
MVert *mvert = dm->getVertArray(dm);
MFace *mface = dm->getTessFaceArray(dm);
numpolys = dm->getNumTessFaces(dm);
@@ -1885,10 +1895,10 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm,
for (int p2 = 0; p2 < numpolys; p2++) {
MFace *mf = &mface[p2];
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon *poly = meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL;
// only add polygons that have the collision flag set
- if (poly->IsCollider()) {
+ if (poly && poly->IsCollider()) {
if (!vert_tag_array[mf->v1]) {
vert_tag_array[mf->v1] = true;
tot_bt_verts++;
@@ -1920,7 +1930,7 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm,
for (int p2 = 0; p2 < numpolys; p2++) {
MFace *mf = &mface[p2];
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon *poly = meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL;
// only add polygons that have the collisionflag set
if (poly->IsCollider()) {
@@ -1963,10 +1973,10 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm,
for (int p2 = 0; p2 < numpolys; p2++) {
MFace *mf = &mface[p2];
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon *poly = meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL;
// only add polygons that have the collision flag set
- if (poly->IsCollider()) {
+ if (poly && poly->IsCollider()) {
if (!vert_tag_array[mf->v1]) {
vert_tag_array[mf->v1] = true;
vert_remap_array[mf->v1] = tot_bt_verts;
@@ -2015,10 +2025,10 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm,
MFace *mf = &mface[p2];
MTFace *tf = (tface) ? &tface[p2] : NULL;
const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2;
- RAS_Polygon *poly = meshobj->GetPolygon(origi);
+ RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL;
// only add polygons that have the collisionflag set
- if (poly->IsCollider()) {
+ if (poly && poly->IsCollider()) {
MVert *v1 = &mvert[mf->v1];
MVert *v2 = &mvert[mf->v2];
MVert *v3 = &mvert[mf->v3];
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index c49ae8d20e1..58ea5e2e390 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -72,8 +72,8 @@ public:
CcdShapeConstructionInfo() :
m_shapeType(PHY_SHAPE_NONE),
- m_radius(1.0),
- m_height(1.0),
+ m_radius(1.0f),
+ m_height(1.0f),
m_halfExtend(0.f,0.f,0.f),
m_childScale(1.0f,1.0f,1.0f),
m_userData(NULL),
@@ -316,7 +316,8 @@ struct CcdConstructionInfo
float m_stepHeight;
float m_jumpSpeed;
float m_fallSpeed;
-
+ unsigned char m_maxJumps;
+
int m_gamesoftFlag;
float m_soft_linStiff; /* linear stiffness 0..1 */
float m_soft_angStiff; /* angular stiffness 0..1 */
@@ -407,19 +408,19 @@ class BlenderBulletCharacterController : public btKinematicCharacterController,
{
private:
btMotionState* m_motionState;
- int m_jumps;
- int m_maxJumps;
+ unsigned char m_jumps;
+ unsigned char m_maxJumps;
public:
BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight);
virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt);
- int getMaxJumps() const;
+ unsigned char getMaxJumps() const;
- void setMaxJumps(int maxJumps);
+ void setMaxJumps(unsigned char maxJumps);
- int getJumpCount() const;
+ unsigned char getJumpCount() const;
virtual bool canJump() const;
@@ -432,9 +433,9 @@ public:
virtual bool OnGround(){ return onGround(); }
virtual float GetGravity() { return getGravity(); }
virtual void SetGravity(float gravity) { setGravity(gravity); }
- virtual int GetMaxJumps() { return getMaxJumps(); }
- virtual void SetMaxJumps(int maxJumps) { setMaxJumps(maxJumps); }
- virtual int GetJumpCount() { return getJumpCount(); }
+ virtual unsigned char GetMaxJumps() { return getMaxJumps(); }
+ virtual void SetMaxJumps(unsigned char maxJumps) { setMaxJumps(maxJumps); }
+ virtual unsigned char GetJumpCount() { return getJumpCount(); }
virtual void SetWalkDirection(const MT_Vector3& dir)
{
btVector3 vec = btVector3(dir[0], dir[1], dir[2]);
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
index eec579158cc..72c96668fe7 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -513,8 +513,8 @@ void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl)
void CcdPhysicsEnvironment::RemoveConstraint(btTypedConstraint *con)
{
- btRigidBody rbA = con->getRigidBodyA();
- btRigidBody rbB = con->getRigidBodyB();
+ btRigidBody &rbA = con->getRigidBodyA();
+ btRigidBody &rbB = con->getRigidBodyB();
rbA.activate();
rbB.activate();
m_dynamicsWorld->removeConstraint(con);
@@ -598,7 +598,7 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr
btCollisionObject* obj = ctrl->GetCollisionObject();
if (obj)
{
- btVector3 inertia(0.0,0.0,0.0);
+ btVector3 inertia(0.0f,0.0f,0.0f);
m_dynamicsWorld->removeCollisionObject(obj);
obj->setCollisionFlags(newCollisionFlags);
if (body)
@@ -861,7 +861,7 @@ void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval)
lspot -= hit_object->getCenterOfMassPosition();
btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot);
btScalar rel_vel_ray = ray_dir.dot(rel_vel);
- btScalar spring_extent = 1.0 - distance / hitObjShapeProps.m_fh_distance;
+ btScalar spring_extent = 1.0f - distance / hitObjShapeProps.m_fh_distance;
btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring;
btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping;
@@ -889,7 +889,7 @@ void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval)
if (rel_vel_lateral > SIMD_EPSILON) {
btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction();
- btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring);
+ btScalar max_friction = friction_factor * btMax(btScalar(0.0f), i_spring);
btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass();
@@ -1405,98 +1405,111 @@ struct OcclusionBuffer
{
struct WriteOCL
{
- static inline bool Process(btScalar& q,btScalar v) { if (q<v) q=v;return(false); }
- static inline void Occlusion(bool& flag) { flag = true; }
+ static inline bool Process(btScalar &q, btScalar v)
+ {
+ if (q < v) {
+ q = v;
+ }
+ return false;
+ }
+ static inline void Occlusion(bool &flag)
+ {
+ flag = true;
+ }
};
+
struct QueryOCL
{
- static inline bool Process(btScalar& q,btScalar v) { return(q<=v); }
- static inline void Occlusion(bool& flag) { }
+ static inline bool Process(btScalar &q, btScalar v)
+ {
+ return (q <= v);
+ }
+ static inline void Occlusion(bool &flag)
+ {
+ }
};
- btScalar* m_buffer;
- size_t m_bufferSize;
- bool m_initialized;
- bool m_occlusion;
- int m_sizes[2];
- btScalar m_scales[2];
- btScalar m_offsets[2];
- btScalar m_wtc[16]; // world to clip transform
- btScalar m_mtc[16]; // model to clip transform
+
+ btScalar *m_buffer;
+ size_t m_bufferSize;
+ bool m_initialized;
+ bool m_occlusion;
+ int m_sizes[2];
+ btScalar m_scales[2];
+ btScalar m_offsets[2];
+ btScalar m_wtc[16]; // world to clip transform
+ btScalar m_mtc[16]; // model to clip transform
// constructor: size=largest dimension of the buffer.
// Buffer size depends on aspect ratio
OcclusionBuffer()
{
- m_initialized=false;
+ m_initialized = false;
m_occlusion = false;
m_buffer = NULL;
m_bufferSize = 0;
}
- // multiplication of column major matrices: m=m1*m2
+ // multiplication of column major matrices: m = m1 * m2
template<typename T1, typename T2>
- void CMmat4mul(btScalar* m, const T1* m1, const T2* m2)
+ void CMmat4mul(btScalar *m, const T1 *m1, const T2 *m2)
{
- m[ 0] = btScalar(m1[ 0]*m2[ 0]+m1[ 4]*m2[ 1]+m1[ 8]*m2[ 2]+m1[12]*m2[ 3]);
- m[ 1] = btScalar(m1[ 1]*m2[ 0]+m1[ 5]*m2[ 1]+m1[ 9]*m2[ 2]+m1[13]*m2[ 3]);
- m[ 2] = btScalar(m1[ 2]*m2[ 0]+m1[ 6]*m2[ 1]+m1[10]*m2[ 2]+m1[14]*m2[ 3]);
- m[ 3] = btScalar(m1[ 3]*m2[ 0]+m1[ 7]*m2[ 1]+m1[11]*m2[ 2]+m1[15]*m2[ 3]);
+ m[0] = btScalar(m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]);
+ m[1] = btScalar(m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]);
+ m[2] = btScalar(m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]);
+ m[3] = btScalar(m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]);
- m[ 4] = btScalar(m1[ 0]*m2[ 4]+m1[ 4]*m2[ 5]+m1[ 8]*m2[ 6]+m1[12]*m2[ 7]);
- m[ 5] = btScalar(m1[ 1]*m2[ 4]+m1[ 5]*m2[ 5]+m1[ 9]*m2[ 6]+m1[13]*m2[ 7]);
- m[ 6] = btScalar(m1[ 2]*m2[ 4]+m1[ 6]*m2[ 5]+m1[10]*m2[ 6]+m1[14]*m2[ 7]);
- m[ 7] = btScalar(m1[ 3]*m2[ 4]+m1[ 7]*m2[ 5]+m1[11]*m2[ 6]+m1[15]*m2[ 7]);
+ m[4] = btScalar(m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]);
+ m[5] = btScalar(m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]);
+ m[6] = btScalar(m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]);
+ m[7] = btScalar(m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]);
- m[ 8] = btScalar(m1[ 0]*m2[ 8]+m1[ 4]*m2[ 9]+m1[ 8]*m2[10]+m1[12]*m2[11]);
- m[ 9] = btScalar(m1[ 1]*m2[ 8]+m1[ 5]*m2[ 9]+m1[ 9]*m2[10]+m1[13]*m2[11]);
- m[10] = btScalar(m1[ 2]*m2[ 8]+m1[ 6]*m2[ 9]+m1[10]*m2[10]+m1[14]*m2[11]);
- m[11] = btScalar(m1[ 3]*m2[ 8]+m1[ 7]*m2[ 9]+m1[11]*m2[10]+m1[15]*m2[11]);
+ m[8] = btScalar(m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]);
+ m[9] = btScalar(m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]);
+ m[10] = btScalar(m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]);
+ m[11] = btScalar(m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]);
- m[12] = btScalar(m1[ 0]*m2[12]+m1[ 4]*m2[13]+m1[ 8]*m2[14]+m1[12]*m2[15]);
- m[13] = btScalar(m1[ 1]*m2[12]+m1[ 5]*m2[13]+m1[ 9]*m2[14]+m1[13]*m2[15]);
- m[14] = btScalar(m1[ 2]*m2[12]+m1[ 6]*m2[13]+m1[10]*m2[14]+m1[14]*m2[15]);
- m[15] = btScalar(m1[ 3]*m2[12]+m1[ 7]*m2[13]+m1[11]*m2[14]+m1[15]*m2[15]);
+ m[12] = btScalar(m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]);
+ m[13] = btScalar(m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]);
+ m[14] = btScalar(m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]);
+ m[15] = btScalar(m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]);
}
- void setup(int size, const int *view, double modelview[16], double projection[16])
+
+ void setup(int size, const int *view, float modelview[16], float projection[16])
{
- m_initialized=false;
- m_occlusion=false;
+ m_initialized = false;
+ m_occlusion = false;
// compute the size of the buffer
- int maxsize;
- double ratio;
- maxsize = (view[2] > view[3]) ? view[2] : view[3];
+ int maxsize = (view[2] > view[3]) ? view[2] : view[3];
assert(maxsize > 0);
- ratio = 1.0/(2*maxsize);
+ double ratio = 1.0 / (2 * maxsize);
// ensure even number
- m_sizes[0] = 2*((int)(size*view[2]*ratio+0.5));
- m_sizes[1] = 2*((int)(size*view[3]*ratio+0.5));
- m_scales[0]=btScalar(m_sizes[0]/2);
- m_scales[1]=btScalar(m_sizes[1]/2);
- m_offsets[0]=m_scales[0]+0.5f;
- m_offsets[1]=m_scales[1]+0.5f;
+ m_sizes[0] = 2 * ((int)(size * view[2] * ratio + 0.5));
+ m_sizes[1] = 2 * ((int)(size * view[3] * ratio + 0.5));
+ m_scales[0] = btScalar(m_sizes[0] / 2);
+ m_scales[1] = btScalar(m_sizes[1] / 2);
+ m_offsets[0] = m_scales[0] + 0.5f;
+ m_offsets[1] = m_scales[1] + 0.5f;
// prepare matrix
// at this time of the rendering, the modelview matrix is the
// world to camera transformation and the projection matrix is
// camera to clip transformation. combine both so that
CMmat4mul(m_wtc, projection, modelview);
}
- void initialize()
+
+ void initialize()
{
- size_t newsize = (m_sizes[0]*m_sizes[1])*sizeof(btScalar);
- if (m_buffer)
- {
+ size_t newsize = (m_sizes[0] * m_sizes[1]) * sizeof(btScalar);
+ if (m_buffer) {
// see if we can reuse
- if (newsize > m_bufferSize)
- {
+ if (newsize > m_bufferSize) {
free(m_buffer);
m_buffer = NULL;
m_bufferSize = 0;
}
}
- if (!m_buffer)
- {
- m_buffer = (btScalar*)calloc(1, newsize);
+ if (!m_buffer) {
+ m_buffer = (btScalar *)calloc(1, newsize);
m_bufferSize = newsize;
- } else
- {
+ }
+ else {
// buffer exists already, just clears it
memset(m_buffer, 0, newsize);
}
@@ -1505,163 +1518,169 @@ struct OcclusionBuffer
m_initialized = true;
m_occlusion = false;
}
- void SetModelMatrix(double *fl)
+
+ void SetModelMatrix(float *fl)
{
CMmat4mul(m_mtc,m_wtc,fl);
- if (!m_initialized)
+ if (!m_initialized) {
initialize();
+ }
}
// transform a segment in world coordinate to clip coordinate
- void transformW(const btVector3& x, btVector4& t)
+ void transformW(const btVector3 &x, btVector4 &t)
{
- t[0] = x[0]*m_wtc[0]+x[1]*m_wtc[4]+x[2]*m_wtc[8]+m_wtc[12];
- t[1] = x[0]*m_wtc[1]+x[1]*m_wtc[5]+x[2]*m_wtc[9]+m_wtc[13];
- t[2] = x[0]*m_wtc[2]+x[1]*m_wtc[6]+x[2]*m_wtc[10]+m_wtc[14];
- t[3] = x[0]*m_wtc[3]+x[1]*m_wtc[7]+x[2]*m_wtc[11]+m_wtc[15];
+ t[0] = x[0] * m_wtc[0] + x[1] * m_wtc[4] + x[2] * m_wtc[8] + m_wtc[12];
+ t[1] = x[0] * m_wtc[1] + x[1] * m_wtc[5] + x[2] * m_wtc[9] + m_wtc[13];
+ t[2] = x[0] * m_wtc[2] + x[1] * m_wtc[6] + x[2] * m_wtc[10] + m_wtc[14];
+ t[3] = x[0] * m_wtc[3] + x[1] * m_wtc[7] + x[2] * m_wtc[11] + m_wtc[15];
}
- void transformM(const float* x, btVector4& t)
+
+ void transformM(const float *x, btVector4 &t)
{
- t[0] = x[0]*m_mtc[0]+x[1]*m_mtc[4]+x[2]*m_mtc[8]+m_mtc[12];
- t[1] = x[0]*m_mtc[1]+x[1]*m_mtc[5]+x[2]*m_mtc[9]+m_mtc[13];
- t[2] = x[0]*m_mtc[2]+x[1]*m_mtc[6]+x[2]*m_mtc[10]+m_mtc[14];
- t[3] = x[0]*m_mtc[3]+x[1]*m_mtc[7]+x[2]*m_mtc[11]+m_mtc[15];
+ t[0] = x[0] * m_mtc[0] + x[1] * m_mtc[4] + x[2] * m_mtc[8] + m_mtc[12];
+ t[1] = x[0] * m_mtc[1] + x[1] * m_mtc[5] + x[2] * m_mtc[9] + m_mtc[13];
+ t[2] = x[0] * m_mtc[2] + x[1] * m_mtc[6] + x[2] * m_mtc[10] + m_mtc[14];
+ t[3] = x[0] * m_mtc[3] + x[1] * m_mtc[7] + x[2] * m_mtc[11] + m_mtc[15];
}
// convert polygon to device coordinates
- static bool project(btVector4* p,int n)
+ static bool project(btVector4 *p, int n)
{
- for (int i=0;i<n;++i)
- {
- p[i][2]=1/p[i][3];
- p[i][0]*=p[i][2];
- p[i][1]*=p[i][2];
+ for (int i = 0; i < n; ++i) {
+ p[i][2] = 1 / p[i][3];
+ p[i][0] *= p[i][2];
+ p[i][1] *= p[i][2];
}
- return(true);
+ return true;
}
// pi: closed polygon in clip coordinate, NP = number of segments
// po: same polygon with clipped segments removed
template <const int NP>
- static int clip(const btVector4* pi,btVector4* po)
+ static int clip(const btVector4 *pi, btVector4 *po)
{
- btScalar s[2*NP];
- btVector4 pn[2*NP];
- int i, j, m, n, ni;
+ btScalar s[2 * NP];
+ btVector4 pn[2 * NP];
+ int i, j, m, n, ni;
// deal with near clipping
- for (i=0, m=0;i<NP;++i)
- {
- s[i]=pi[i][2]+pi[i][3];
- if (s[i]<0) m+=1<<i;
+ for (i = 0, m = 0; i < NP; ++i) {
+ s[i] = pi[i][2] + pi[i][3];
+ if (s[i] < 0) {
+ m += 1 << i;
+ }
}
- if (m==((1<<NP)-1))
- return(0);
- if (m!=0)
- {
- for (i=NP-1,j=0,n=0;j<NP;i=j++)
- {
- const btVector4& a=pi[i];
- const btVector4& b=pi[j];
- const btScalar t=s[i]/(a[3]+a[2]-b[3]-b[2]);
- if ((t>0)&&(t<1))
- {
- pn[n][0] = a[0]+(b[0]-a[0])*t;
- pn[n][1] = a[1]+(b[1]-a[1])*t;
- pn[n][2] = a[2]+(b[2]-a[2])*t;
- pn[n][3] = a[3]+(b[3]-a[3])*t;
+ if (m == ((1 << NP) - 1)) {
+ return 0;
+ }
+ if (m != 0) {
+ for (i = NP - 1, j = 0, n = 0; j < NP; i = j++) {
+ const btVector4 &a = pi[i];
+ const btVector4 &b = pi[j];
+ const btScalar t = s[i] / (a[3] + a[2] - b[3] - b[2]);
+ if ((t > 0) && (t < 1)) {
+ pn[n][0] = a[0] + (b[0] - a[0]) * t;
+ pn[n][1] = a[1] + (b[1] - a[1]) * t;
+ pn[n][2] = a[2] + (b[2] - a[2]) * t;
+ pn[n][3] = a[3] + (b[3] - a[3]) * t;
++n;
}
- if (s[j]>0) pn[n++]=b;
+ if (s[j] > 0) {
+ pn[n++] = b;
+ }
}
// ready to test far clipping, start from the modified polygon
pi = pn;
ni = n;
- } else
- {
+ }
+ else {
// no clipping on the near plane, keep same vector
ni = NP;
}
// now deal with far clipping
- for (i=0, m=0;i<ni;++i)
- {
- s[i]=pi[i][2]-pi[i][3];
- if (s[i]>0) m+=1<<i;
+ for (i = 0, m = 0; i < ni; ++i) {
+ s[i] = pi[i][2] - pi[i][3];
+ if (s[i] > 0) {
+ m += 1 << i;
+ }
}
- if (m==((1<<ni)-1))
- return(0);
- if (m!=0)
- {
- for (i=ni-1,j=0,n=0;j<ni;i=j++)
- {
- const btVector4& a=pi[i];
- const btVector4& b=pi[j];
- const btScalar t=s[i]/(a[2]-a[3]-b[2]+b[3]);
- if ((t>0)&&(t<1))
- {
- po[n][0] = a[0]+(b[0]-a[0])*t;
- po[n][1] = a[1]+(b[1]-a[1])*t;
- po[n][2] = a[2]+(b[2]-a[2])*t;
- po[n][3] = a[3]+(b[3]-a[3])*t;
+ if (m == ((1 << ni) - 1)) {
+ return 0;
+ }
+ if (m != 0) {
+ for (i = ni - 1, j = 0, n = 0;j < ni; i = j++) {
+ const btVector4 &a = pi[i];
+ const btVector4 &b = pi[j];
+ const btScalar t = s[i] / (a[2] - a[3] - b[2] + b[3]);
+ if ((t > 0) && (t < 1)) {
+ po[n][0] = a[0] + (b[0] - a[0]) * t;
+ po[n][1] = a[1] + (b[1] - a[1]) * t;
+ po[n][2] = a[2] + (b[2] - a[2]) * t;
+ po[n][3] = a[3] + (b[3] - a[3]) * t;
++n;
}
- if (s[j]<0) po[n++]=b;
+ if (s[j] < 0) {
+ po[n++] = b;
+ }
}
- return(n);
+ return n;
}
- for (int i=0;i<ni;++i) po[i]=pi[i];
- return(ni);
+ for (int i = 0; i < ni; ++i) {
+ po[i] = pi[i];
+ }
+ return ni;
}
// write or check a triangle to buffer. a,b,c in device coordinates (-1,+1)
template <typename POLICY>
- inline bool draw( const btVector4& a,
- const btVector4& b,
- const btVector4& c,
- const float face,
- const btScalar minarea)
- {
- const btScalar a2=btCross(b-a,c-a)[2];
- if ((face*a2)<0.f || btFabs(a2)<minarea)
+ inline bool draw(const btVector4 &a,
+ const btVector4 &b,
+ const btVector4 &c,
+ const float face,
+ const btScalar minarea)
+ {
+ const btScalar a2 = btCross(b - a, c - a)[2];
+ if ((face * a2) < 0.0f || btFabs(a2) < minarea) {
return false;
+ }
// further down we are normally going to write to the Zbuffer, mark it so
POLICY::Occlusion(m_occlusion);
- int x[3], y[3], ib=1, ic=2;
+ int x[3], y[3], ib = 1, ic = 2;
btScalar z[3];
- x[0]=(int)(a.x()*m_scales[0]+m_offsets[0]);
- y[0]=(int)(a.y()*m_scales[1]+m_offsets[1]);
- z[0]=a.z();
- if (a2 < 0.f)
- {
+ x[0] = (int)(a.x() * m_scales[0] + m_offsets[0]);
+ y[0] = (int)(a.y() * m_scales[1] + m_offsets[1]);
+ z[0] = a.z();
+ if (a2 < 0.f) {
// negative aire is possible with double face => must
// change the order of b and c otherwise the algorithm doesn't work
- ib=2;
- ic=1;
- }
- x[ib]=(int)(b.x()*m_scales[0]+m_offsets[0]);
- x[ic]=(int)(c.x()*m_scales[0]+m_offsets[0]);
- y[ib]=(int)(b.y()*m_scales[1]+m_offsets[1]);
- y[ic]=(int)(c.y()*m_scales[1]+m_offsets[1]);
- z[ib]=b.z();
- z[ic]=c.z();
- const int mix=btMax(0,btMin(x[0],btMin(x[1],x[2])));
- const int mxx=btMin(m_sizes[0],1+btMax(x[0],btMax(x[1],x[2])));
- const int miy=btMax(0,btMin(y[0],btMin(y[1],y[2])));
- const int mxy=btMin(m_sizes[1],1+btMax(y[0],btMax(y[1],y[2])));
- const int width=mxx-mix;
- const int height=mxy-miy;
- if ((width*height) <= 1)
- {
+ ib = 2;
+ ic = 1;
+ }
+ x[ib] = (int)(b.x() * m_scales[0] + m_offsets[0]);
+ x[ic] = (int)(c.x() * m_scales[0] + m_offsets[0]);
+ y[ib] = (int)(b.y() * m_scales[1] + m_offsets[1]);
+ y[ic] = (int)(c.y() * m_scales[1] + m_offsets[1]);
+ z[ib] = b.z();
+ z[ic] = c.z();
+ const int mix = btMax(0, btMin(x[0], btMin(x[1], x[2])));
+ const int mxx = btMin(m_sizes[0], 1 + btMax(x[0], btMax(x[1], x[2])));
+ const int miy = btMax(0, btMin(y[0], btMin(y[1], y[2])));
+ const int mxy = btMin(m_sizes[1], 1 + btMax(y[0], btMax(y[1], y[2])));
+ const int width = mxx - mix;
+ const int height = mxy - miy;
+ if ((width * height) <= 1) {
// degenerated in at most one single pixel
- btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
+ btScalar *scan = &m_buffer[miy * m_sizes[0] + mix];
// use for loop to detect the case where width or height == 0
- for (int iy=miy;iy<mxy;++iy)
- {
- for (int ix=mix;ix<mxx;++ix)
- {
- if (POLICY::Process(*scan,z[0]))
- return(true);
- if (POLICY::Process(*scan,z[1]))
- return(true);
- if (POLICY::Process(*scan,z[2]))
- return(true);
+ for (int iy = miy; iy < mxy; ++iy) {
+ for (int ix = mix; ix < mxx; ++ix) {
+ if (POLICY::Process(*scan, z[0])) {
+ return true;
+ }
+ if (POLICY::Process(*scan, z[1])) {
+ return true;
+ }
+ if (POLICY::Process(*scan, z[2])) {
+ return true;
+ }
}
}
}
@@ -1673,182 +1692,236 @@ struct OcclusionBuffer
// sort the y coord to make formula simpler
int ytmp;
btScalar ztmp;
- if (y[0] > y[1]) { ytmp=y[1];y[1]=y[0];y[0]=ytmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
- if (y[0] > y[2]) { ytmp=y[2];y[2]=y[0];y[0]=ytmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
- if (y[1] > y[2]) { ytmp=y[2];y[2]=y[1];y[1]=ytmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
- int dy[] = {y[0] - y[1],
+ if (y[0] > y[1]) {
+ ytmp = y[1];
+ y[1] = y[0];
+ y[0] = ytmp;
+ ztmp = z[1];
+ z[1] = z[0];
+ z[0] = ztmp;
+ }
+ if (y[0] > y[2]) {
+ ytmp = y[2];
+ y[2] = y[0];
+ y[0] = ytmp;
+ ztmp = z[2];
+ z[2] = z[0];
+ z[0] = ztmp;
+ }
+ if (y[1] > y[2]) {
+ ytmp = y[2];
+ y[2] = y[1];
+ y[1] = ytmp;
+ ztmp = z[2];
+ z[2] = z[1];
+ z[1] = ztmp;
+ }
+ int dy[] = {y[0] - y[1],
y[1] - y[2],
y[2] - y[0]};
btScalar dzy[3];
- dzy[0] = (dy[0]) ? (z[0] - z[1]) / dy[0] : btScalar(0.f);
- dzy[1] = (dy[1]) ? (z[1] - z[2]) / dy[1] : btScalar(0.f);
- dzy[2] = (dy[2]) ? (z[2] - z[0]) / dy[2] : btScalar(0.f);
+ dzy[0] = (dy[0]) ? (z[0] - z[1]) / dy[0] : btScalar(0.0f);
+ dzy[1] = (dy[1]) ? (z[1] - z[2]) / dy[1] : btScalar(0.0f);
+ dzy[2] = (dy[2]) ? (z[2] - z[0]) / dy[2] : btScalar(0.0f);
btScalar v[3] = {dzy[0] * (miy - y[0]) + z[0],
dzy[1] * (miy - y[1]) + z[1],
dzy[2] * (miy - y[2]) + z[2]};
- dy[0] = y[1]-y[0];
- dy[1] = y[0]-y[1];
- dy[2] = y[2]-y[0];
- btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
- for (int iy=miy;iy<mxy;++iy)
- {
- if (dy[0] >= 0 && POLICY::Process(*scan,v[0]))
- return(true);
- if (dy[1] >= 0 && POLICY::Process(*scan,v[1]))
- return(true);
- if (dy[2] >= 0 && POLICY::Process(*scan,v[2]))
- return(true);
- scan+=m_sizes[0];
- v[0] += dzy[0]; v[1] += dzy[1]; v[2] += dzy[2];
- dy[0]--; dy[1]++, dy[2]--;
+ dy[0] = y[1] - y[0];
+ dy[1] = y[0] - y[1];
+ dy[2] = y[2] - y[0];
+ btScalar *scan = &m_buffer[miy * m_sizes[0] + mix];
+ for (int iy = miy; iy < mxy; ++iy) {
+ if (dy[0] >= 0 && POLICY::Process(*scan, v[0])) {
+ return true;
+ }
+ if (dy[1] >= 0 && POLICY::Process(*scan, v[1])) {
+ return true;
+ }
+ if (dy[2] >= 0 && POLICY::Process(*scan, v[2])) {
+ return true;
+ }
+ scan += m_sizes[0];
+ v[0] += dzy[0];
+ v[1] += dzy[1];
+ v[2] += dzy[2];
+ dy[0]--;
+ dy[1]++;
+ dy[2]--;
}
- } else if (height == 1)
- {
+ }
+ else if (height == 1) {
// Degenerated in at least 2 horizontal lines
// The algorithm below doesn't work when face has a single pixel width
// We cannot use general formulas because the plane is degenerated.
// We have to interpolate along the 3 edges that overlaps and process each pixel.
int xtmp;
btScalar ztmp;
- if (x[0] > x[1]) { xtmp=x[1];x[1]=x[0];x[0]=xtmp;ztmp=z[1];z[1]=z[0];z[0]=ztmp; }
- if (x[0] > x[2]) { xtmp=x[2];x[2]=x[0];x[0]=xtmp;ztmp=z[2];z[2]=z[0];z[0]=ztmp; }
- if (x[1] > x[2]) { xtmp=x[2];x[2]=x[1];x[1]=xtmp;ztmp=z[2];z[2]=z[1];z[1]=ztmp; }
+ if (x[0] > x[1]) {
+ xtmp = x[1];
+ x[1] = x[0];
+ x[0] = xtmp;
+ ztmp = z[1];
+ z[1] = z[0];
+ z[0] = ztmp;
+ }
+ if (x[0] > x[2]) {
+ xtmp = x[2];
+ x[2] = x[0];
+ x[0] = xtmp;
+ ztmp = z[2];
+ z[2] = z[0];
+ z[0] = ztmp;
+ }
+ if (x[1] > x[2]) {
+ xtmp = x[2];
+ x[2] = x[1];
+ x[1] = xtmp;
+ ztmp = z[2];
+ z[2] = z[1];
+ z[1] = ztmp;
+ }
int dx[] = {x[0] - x[1],
x[1] - x[2],
x[2] - x[0]};
btScalar dzx[3];
- dzx[0] = (dx[0]) ? (z[0]-z[1])/dx[0] : btScalar(0.f);
- dzx[1] = (dx[1]) ? (z[1]-z[2])/dx[1] : btScalar(0.f);
- dzx[2] = (dx[2]) ? (z[2]-z[0])/dx[2] : btScalar(0.f);
+ dzx[0] = (dx[0]) ? (z[0]-z[1]) / dx[0] : btScalar(0.0f);
+ dzx[1] = (dx[1]) ? (z[1]-z[2]) / dx[1] : btScalar(0.0f);
+ dzx[2] = (dx[2]) ? (z[2]-z[0]) / dx[2] : btScalar(0.0f);
btScalar v[3] = {dzx[0] * (mix - x[0]) + z[0],
dzx[1] * (mix - x[1]) + z[1],
dzx[2] * (mix - x[2]) + z[2]};
- dx[0] = x[1]-x[0];
- dx[1] = x[0]-x[1];
- dx[2] = x[2]-x[0];
- btScalar* scan=&m_buffer[miy*m_sizes[0]+mix];
- for (int ix=mix;ix<mxx;++ix)
- {
- if (dx[0] >= 0 && POLICY::Process(*scan,v[0]))
- return(true);
- if (dx[1] >= 0 && POLICY::Process(*scan,v[1]))
- return(true);
- if (dx[2] >= 0 && POLICY::Process(*scan,v[2]))
- return(true);
+ dx[0] = x[1] - x[0];
+ dx[1] = x[0] - x[1];
+ dx[2] = x[2] - x[0];
+ btScalar *scan = &m_buffer[miy * m_sizes[0] + mix];
+ for (int ix = mix; ix < mxx; ++ix) {
+ if (dx[0] >= 0 && POLICY::Process(*scan, v[0])) {
+ return true;
+ }
+ if (dx[1] >= 0 && POLICY::Process(*scan, v[1])) {
+ return true;
+ }
+ if (dx[2] >= 0 && POLICY::Process(*scan, v[2])) {
+ return true;
+ }
scan++;
- v[0] += dzx[0]; v[1] += dzx[1]; v[2] += dzx[2];
- dx[0]--; dx[1]++, dx[2]--;
+ v[0] += dzx[0];
+ v[1] += dzx[1];
+ v[2] += dzx[2];
+ dx[0]--;
+ dx[1]++;
+ dx[2]--;
}
}
else {
// general case
- const int dx[] = {y[0] - y[1],
- y[1] - y[2],
- y[2] - y[0]};
- const int dy[] = {x[1] - x[0] - dx[0] * width,
- x[2] - x[1] - dx[1] * width,
- x[0] - x[2] - dx[2] * width};
- const int a = x[2] * y[0] + x[0] * y[1] - x[2] * y[1] - x[0] * y[2] + x[1] * y[2] - x[1] * y[0];
- const btScalar ia = 1 / (btScalar)a;
- const btScalar dzx = ia*(y[2]*(z[1]-z[0])+y[1]*(z[0]-z[2])+y[0]*(z[2]-z[1]));
- const btScalar dzy = ia*(x[2]*(z[0]-z[1])+x[0]*(z[1]-z[2])+x[1]*(z[2]-z[0]))-(dzx*width);
- int c[] = {miy*x[1]+mix*y[0]-x[1]*y[0]-mix*y[1]+x[0]*y[1]-miy*x[0],
- miy*x[2]+mix*y[1]-x[2]*y[1]-mix*y[2]+x[1]*y[2]-miy*x[1],
- miy*x[0]+mix*y[2]-x[0]*y[2]-mix*y[0]+x[2]*y[0]-miy*x[2]};
- btScalar v = ia*((z[2]*c[0])+(z[0]*c[1])+(z[1]*c[2]));
- btScalar *scan = &m_buffer[miy*m_sizes[0]];
- for (int iy=miy;iy<mxy;++iy)
- {
- for (int ix=mix;ix<mxx;++ix)
- {
- if ((c[0]>=0)&&(c[1]>=0)&&(c[2]>=0))
- {
- if (POLICY::Process(scan[ix],v))
- return(true);
+ const int dx[] = {y[0] - y[1],
+ y[1] - y[2],
+ y[2] - y[0]};
+ const int dy[] = {x[1] - x[0] - dx[0] * width,
+ x[2] - x[1] - dx[1] * width,
+ x[0] - x[2] - dx[2] * width};
+ const int a = x[2] * y[0] + x[0] * y[1] - x[2] * y[1] - x[0] * y[2] + x[1] * y[2] - x[1] * y[0];
+ const btScalar ia = 1 / (btScalar)a;
+ const btScalar dzx = ia * (y[2] * (z[1] - z[0]) + y[1] * (z[0] - z[2]) + y[0] * (z[2] - z[1]));
+ const btScalar dzy = ia * (x[2] * (z[0] - z[1]) + x[0] * (z[1] - z[2]) + x[1] * (z[2] - z[0])) - (dzx * width);
+ int c[] = {miy * x[1] + mix * y[0] - x[1] * y[0] - mix * y[1] + x[0] * y[1] - miy * x[0],
+ miy * x[2] + mix * y[1] - x[2] * y[1] - mix * y[2] + x[1] * y[2] - miy * x[1],
+ miy * x[0] + mix * y[2] - x[0] * y[2] - mix * y[0] + x[2] * y[0] - miy * x[2]};
+ btScalar v = ia * ((z[2] * c[0]) + (z[0] * c[1]) + (z[1] * c[2]));
+ btScalar *scan = &m_buffer[miy * m_sizes[0]];
+
+ for (int iy = miy; iy < mxy; ++iy) {
+ for (int ix = mix; ix < mxx; ++ix) {
+ if ((c[0] >= 0) && (c[1] >= 0) && (c[2] >= 0)) {
+ if (POLICY::Process(scan[ix], v)) {
+ return true;
+ }
}
- c[0]+=dx[0];c[1]+=dx[1];c[2]+=dx[2];v+=dzx;
+ c[0] += dx[0]; c[1] += dx[1]; c[2] += dx[2]; v += dzx;
}
- c[0]+=dy[0];c[1]+=dy[1];c[2]+=dy[2];v+=dzy;
- scan+=m_sizes[0];
+ c[0] += dy[0]; c[1] += dy[1]; c[2] += dy[2]; v += dzy;
+ scan += m_sizes[0];
}
}
- return(false);
+ return false;
}
// clip than write or check a polygon
- template <const int NP,typename POLICY>
- inline bool clipDraw( const btVector4* p,
- const float face,
- btScalar minarea)
- {
- btVector4 o[NP*2];
- int n=clip<NP>(p,o);
- bool earlyexit=false;
- if (n)
- {
- project(o,n);
- for (int i=2;i<n && !earlyexit;++i)
- {
- earlyexit|=draw<POLICY>(o[0],o[i-1],o[i],face,minarea);
+ template <const int NP, typename POLICY>
+ inline bool clipDraw(const btVector4 *p,
+ const float face,
+ btScalar minarea)
+ {
+ btVector4 o[NP * 2];
+ int n = clip<NP>(p, o);
+ bool earlyexit = false;
+ if (n) {
+ project(o, n);
+ for (int i = 2; i < n && !earlyexit; ++i) {
+ earlyexit |= draw<POLICY>(o[0], o[i - 1], o[i], face, minarea);
}
}
- return(earlyexit);
+ return earlyexit;
}
// add a triangle (in model coordinate)
// face = 0.f if face is double side,
// = 1.f if face is single sided and scale is positive
// = -1.f if face is single sided and scale is negative
- void appendOccluderM(const float* a,
- const float* b,
- const float* c,
- const float face)
+ void appendOccluderM(const float *a,
+ const float *b,
+ const float *c,
+ const float face)
{
- btVector4 p[3];
- transformM(a,p[0]);
- transformM(b,p[1]);
- transformM(c,p[2]);
- clipDraw<3,WriteOCL>(p,face,btScalar(0.f));
+ btVector4 p[3];
+ transformM(a, p[0]);
+ transformM(b, p[1]);
+ transformM(c, p[2]);
+ clipDraw<3, WriteOCL>(p, face, btScalar(0.0f));
}
// add a quad (in model coordinate)
- void appendOccluderM(const float* a,
- const float* b,
- const float* c,
- const float* d,
- const float face)
- {
- btVector4 p[4];
- transformM(a,p[0]);
- transformM(b,p[1]);
- transformM(c,p[2]);
- transformM(d,p[3]);
- clipDraw<4,WriteOCL>(p,face,btScalar(0.f));
+ void appendOccluderM(const float *a,
+ const float *b,
+ const float *c,
+ const float *d,
+ const float face)
+ {
+ btVector4 p[4];
+ transformM(a, p[0]);
+ transformM(b, p[1]);
+ transformM(c, p[2]);
+ transformM(d, p[3]);
+ clipDraw<4, WriteOCL>(p, face, btScalar(0.0f));
}
// query occluder for a box (c=center, e=extend) in world coordinate
- inline bool queryOccluderW( const btVector3& c,
- const btVector3& e)
+ inline bool queryOccluderW(const btVector3 &c,
+ const btVector3 &e)
{
- if (!m_occlusion)
+ if (!m_occlusion) {
// no occlusion yet, no need to check
return true;
- btVector4 x[8];
- transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]-e[2]),x[0]);
- transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]-e[2]),x[1]);
- transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]-e[2]),x[2]);
- transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]-e[2]),x[3]);
- transformW(btVector3(c[0]-e[0],c[1]-e[1],c[2]+e[2]),x[4]);
- transformW(btVector3(c[0]+e[0],c[1]-e[1],c[2]+e[2]),x[5]);
- transformW(btVector3(c[0]+e[0],c[1]+e[1],c[2]+e[2]),x[6]);
- transformW(btVector3(c[0]-e[0],c[1]+e[1],c[2]+e[2]),x[7]);
- for (int i=0;i<8;++i)
- {
+ }
+ btVector4 x[8];
+ transformW(btVector3(c[0] - e[0], c[1] - e[1], c[2] - e[2]), x[0]);
+ transformW(btVector3(c[0] + e[0], c[1] - e[1], c[2] - e[2]), x[1]);
+ transformW(btVector3(c[0] + e[0], c[1] + e[1], c[2] - e[2]), x[2]);
+ transformW(btVector3(c[0] - e[0], c[1] + e[1], c[2] - e[2]), x[3]);
+ transformW(btVector3(c[0] - e[0], c[1] - e[1], c[2] + e[2]), x[4]);
+ transformW(btVector3(c[0] + e[0], c[1] - e[1], c[2] + e[2]), x[5]);
+ transformW(btVector3(c[0] + e[0], c[1] + e[1], c[2] + e[2]), x[6]);
+ transformW(btVector3(c[0] - e[0], c[1] + e[1], c[2] + e[2]), x[7]);
+
+ for (int i = 0; i < 8; ++i) {
// the box is clipped, it's probably a large box, don't waste our time to check
- if ((x[i][2]+x[i][3])<=0) return(true);
- }
- static const int d[] = {1,0,3,2,
- 4,5,6,7,
- 4,7,3,0,
- 6,5,1,2,
- 7,6,2,3,
- 5,4,0,1};
+ if ((x[i][2] + x[i][3]) <= 0) {
+ return true;
+ }
+ }
+ static const int d[] = {1, 0, 3, 2,
+ 4, 5, 6, 7,
+ 4, 7, 3, 0,
+ 6, 5, 1, 2,
+ 7, 6, 2, 3,
+ 5, 4, 0, 1};
for (unsigned int i = 0; i < (sizeof(d) / sizeof(d[0]));) {
const btVector4 p[] = {x[d[i + 0]],
x[d[i + 1]],
@@ -1896,7 +1969,7 @@ struct DbvtCullingCallback : btDbvt::ICollide
KX_GameObject* gameobj = KX_GameObject::GetClientObject(info);
if (gameobj && gameobj->GetOccluder())
{
- double* fl = gameobj->GetOpenGLMatrixPtr()->getPointer();
+ float *fl = gameobj->GetOpenGLMatrixPtr()->getPointer();
// this will create the occlusion buffer if not already done
// and compute the transformation from model local space to clip space
m_ocb->SetModelMatrix(fl);
@@ -1937,7 +2010,7 @@ struct DbvtCullingCallback : btDbvt::ICollide
};
static OcclusionBuffer gOcb;
-bool CcdPhysicsEnvironment::CullingTest(PHY_CullingCallback callback, void* userData, MT_Vector4 *planes, int nplanes, int occlusionRes, const int *viewport, double modelview[16], double projection[16])
+bool CcdPhysicsEnvironment::CullingTest(PHY_CullingCallback callback, void* userData, MT_Vector4 *planes, int nplanes, int occlusionRes, const int *viewport, float modelview[16], float projection[16])
{
if (!m_cullingTree)
return false;
@@ -2730,7 +2803,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
btTransform frameInB;
btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z);
- if (axis1.length() == 0.0)
+ if (axis1.length() == 0.0f)
{
btPlaneSpace1( axisInA, axis1, axis2 );
}
@@ -2804,7 +2877,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
btTransform frameInB;
btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z);
- if (axis1.length() == 0.0)
+ if (axis1.length() == 0.0f)
{
btPlaneSpace1( axisInA, axis1, axis2 );
}
@@ -2882,7 +2955,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
btTransform frameInB;
btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z);
- if (axis1.length() == 0.0)
+ if (axis1.length() == 0.0f)
{
btPlaneSpace1( axisInA, axis1, axis2 );
}
@@ -2911,7 +2984,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
btTransform frameInB;
btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z);
- if (axis1.length() == 0.0)
+ if (axis1.length() == 0.0f)
{
btPlaneSpace1( axisInA, axis1, axis2 );
}
@@ -3076,7 +3149,7 @@ struct BlenderDebugDraw : public btIDebugDraw
virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,float distance,int lifeTime,const btVector3& color)
{
drawLine(PointOnB, PointOnB + normalOnB, color);
- drawSphere(PointOnB, 0.1, color);
+ drawSphere(PointOnB, 0.1f, color);
}
virtual void setDebugMode(int debugMode)
@@ -3162,6 +3235,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
ci.m_stepHeight = isbulletchar ? shapeprops->m_step_height : 0.f;
ci.m_jumpSpeed = isbulletchar ? shapeprops->m_jump_speed : 0.f;
ci.m_fallSpeed = isbulletchar ? shapeprops->m_fall_speed : 0.f;
+ ci.m_maxJumps = isbulletchar ? shapeprops->m_max_jumps : 0;
//mmm, for now, take this for the size of the dynamicobject
// Blender uses inertia for radius of dynamic object
@@ -3215,7 +3289,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
ci.m_margin = 0.f;
ci.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
- ci.m_soft_linStiff = 0.5;
+ ci.m_soft_linStiff = 0.5f;
ci.m_soft_angStiff = 1.f; /* angular stiffness 0..1 */
ci.m_soft_volume = 1.f; /* volume preservation 0..1 */
@@ -3226,7 +3300,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
ci.m_soft_kSRHR_CL = 0.1f;
ci.m_soft_kSKHR_CL = 1.f;
- ci.m_soft_kSSHR_CL = 0.5;
+ ci.m_soft_kSSHR_CL = 0.5f;
ci.m_soft_kSR_SPLT_CL = 0.5f;
ci.m_soft_kSK_SPLT_CL = 0.5f;
@@ -3284,8 +3358,8 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
BoundBox *bb= BKE_object_boundbox_get(blenderobject);
if (bb==NULL)
{
- bounds_center[0] = bounds_center[1] = bounds_center[2] = 0.0;
- bounds_extends[0] = bounds_extends[1] = bounds_extends[2] = 1.0;
+ bounds_center[0] = bounds_center[1] = bounds_center[2] = 0.0f;
+ bounds_extends[0] = bounds_extends[1] = bounds_extends[2] = 1.0f;
}
else
{
@@ -3324,7 +3398,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
2.f * bounds_extends[1],
2.f * bounds_extends[2]);
- shapeInfo->m_halfExtend /= 2.0;
+ shapeInfo->m_halfExtend /= 2.0f;
shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute();
shapeInfo->m_shapeType = PHY_SHAPE_BOX;
bm = shapeInfo->CreateBulletShape(ci.m_margin);
@@ -3430,9 +3504,9 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
SG_Node* parentNode = parent->GetSGNode();
// relative transform
MT_Vector3 parentScale = parentNode->GetWorldScaling();
- parentScale[0] = MT_Scalar(1.0)/parentScale[0];
- parentScale[1] = MT_Scalar(1.0)/parentScale[1];
- parentScale[2] = MT_Scalar(1.0)/parentScale[2];
+ parentScale[0] = MT_Scalar(1.0f)/parentScale[0];
+ parentScale[1] = MT_Scalar(1.0f)/parentScale[1];
+ parentScale[2] = MT_Scalar(1.0f)/parentScale[2];
MT_Vector3 relativeScale = gameNode->GetWorldScaling() * parentScale;
MT_Matrix3x3 parentInvRot = parentNode->GetWorldOrientation().transposed();
MT_Vector3 relativePos = parentInvRot*((gameNode->GetWorldPosition()-parentNode->GetWorldPosition())*parentScale);
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
index 86f663959f1..a64d2c8f15f 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
@@ -211,7 +211,7 @@ protected:
btTypedConstraint* GetConstraintById(int constraintId);
virtual PHY_IPhysicsController* RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
- virtual bool CullingTest(PHY_CullingCallback callback, void* userData, MT_Vector4* planes, int nplanes, int occlusionRes, const int *viewport, double modelview[16], double projection[16]);
+ virtual bool CullingTest(PHY_CullingCallback callback, void* userData, MT_Vector4* planes, int nplanes, int occlusionRes, const int *viewport, float modelview[16], float projection[16]);
//Methods for gamelogic collision/physics callbacks
diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript
deleted file mode 100644
index 5c5b1fe6ea6..00000000000
--- a/source/gameengine/Physics/Bullet/SConscript
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = 'CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp CcdGraphicController.cpp'
-
-incs = [
- '.',
- '#intern/container',
- '#intern/guardedalloc',
- '#intern/string',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#intern/moto/include',
- '#source/blender/blenkernel',
- '#source/blender/blenlib',
- '#source/blender/makesdna',
- '#source/gameengine/Converter',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Ketsji',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/SceneGraph',
- '../common',
- ]
-incs = ' '.join(incs)
-
-incs += ' ' + env['BF_BULLET_INC']
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-if env['WITH_BF_BULLET']:
- defs.append('WITH_BULLET')
-
-env.BlenderLib ( 'ge_phys_bullet', Split(sources), Split(incs), defs, libtype=['core','player'], priority=[350,50], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
index 929345d7161..3e9379dd60d 100644
--- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
@@ -83,7 +83,7 @@ public:
}
virtual PHY_IPhysicsController* RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ);
- virtual bool CullingTest(PHY_CullingCallback callback, void* userData, class MT_Vector4* planes, int nplanes, int occlusionRes, const int *viewport, double modelview[16], double projection[16]) { return false; }
+ virtual bool CullingTest(PHY_CullingCallback callback, void* userData, class MT_Vector4* planes, int nplanes, int occlusionRes, const int *viewport, float modelview[16], float projection[16]) { return false; }
//gamelogic callbacks
diff --git a/source/gameengine/Physics/Dummy/SConscript b/source/gameengine/Physics/Dummy/SConscript
deleted file mode 100644
index 3715dcf6aed..00000000000
--- a/source/gameengine/Physics/Dummy/SConscript
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = 'DummyPhysicsEnvironment.cpp'
-
-incs = [
- '.',
- '../common',
- '../../../../intern/moto/include',
- ]
-incs = ' '.join(incs)
-
-defs = []
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
- incs += ' #intern/guardedalloc'
-
-env.BlenderLib ( 'ge_phys_dummy', Split(sources), Split(incs), defs, libtype=['core','player'], priority=[350,60] )
diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h
index a3d3000a143..81c567ef08a 100644
--- a/source/gameengine/Physics/common/PHY_ICharacter.h
+++ b/source/gameengine/Physics/common/PHY_ICharacter.h
@@ -23,10 +23,10 @@ public:
virtual float GetGravity()= 0;
virtual void SetGravity(float gravity)= 0;
- virtual int GetMaxJumps()= 0;
- virtual void SetMaxJumps(int maxJumps)= 0;
+ virtual unsigned char GetMaxJumps() = 0;
+ virtual void SetMaxJumps(unsigned char maxJumps) = 0;
- virtual int GetJumpCount()= 0;
+ virtual unsigned char GetJumpCount() = 0;
virtual void SetWalkDirection(const class MT_Vector3& dir)=0;
virtual MT_Vector3 GetWalkDirection()=0;
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index 4b8d36285be..2997048805f 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -183,7 +183,7 @@ class PHY_IPhysicsEnvironment
//culling based on physical broad phase
// the plane number must be set as follow: near, far, left, right, top, botton
// the near plane must be the first one and must always be present, it is used to get the direction of the view
- virtual bool CullingTest(PHY_CullingCallback callback, void *userData, MT_Vector4* planeNormals, int planeNumber, int occlusionRes, const int *viewport, double modelview[16], double projection[16]) = 0;
+ virtual bool CullingTest(PHY_CullingCallback callback, void *userData, MT_Vector4* planeNormals, int planeNumber, int occlusionRes, const int *viewport, float modelview[16], float projection[16]) = 0;
//Methods for gamelogic collision/physics callbacks
//todo:
diff --git a/source/gameengine/Physics/common/PHY_Pro.h b/source/gameengine/Physics/common/PHY_Pro.h
index c9b91b06a3c..bfe574e73cb 100644
--- a/source/gameengine/Physics/common/PHY_Pro.h
+++ b/source/gameengine/Physics/common/PHY_Pro.h
@@ -51,6 +51,7 @@ struct PHY_ShapeProps {
MT_Scalar m_step_height; // Max height of climbable steps (Character)
MT_Scalar m_jump_speed; // Velocity of jumps (Character)
MT_Scalar m_fall_speed; // Max velocity of falling (Character)
+ unsigned char m_max_jumps; // Max ammount of jumps (Character)
};
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index 5bc3f22e327..496a864244b 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../blender/makesdna
../../blender/blenlib
../../blender/blenkernel
+ ../../blender/imbuf
../../../intern/container
../../../intern/glew-mx
../../../intern/guardedalloc
@@ -53,6 +54,7 @@ set(SRC
RAS_Polygon.cpp
RAS_TexVert.cpp
RAS_texmatrix.cpp
+ RAS_ICanvas.cpp
RAS_2DFilterManager.h
RAS_BucketManager.h
diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
index cedc27c3b92..82b26749fd1 100644
--- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
@@ -495,10 +495,10 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
glBegin(GL_QUADS);
glColor4f(1.f, 1.f, 1.f, 1.f);
- glTexCoord2f(1.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[3]); glVertex2f(1,1);
- glTexCoord2f(0.0, 1.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[3]); glVertex2f(-1,1);
- glTexCoord2f(0.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[2]); glVertex2f(-1,-1);
- glTexCoord2f(1.0, 0.0); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[2]); glVertex2f(1,-1);
+ glTexCoord2f(1.0f, 1.0f); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[3]); glVertex2f(1.0f,1.0f);
+ glTexCoord2f(0.0f, 1.0f); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[3]); glVertex2f(-1.0f,1.0f);
+ glTexCoord2f(0.0f, 0.0f); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[0], canvascoord[2]); glVertex2f(-1.0f,-1.0f);
+ glTexCoord2f(1.0f, 0.0f); glMultiTexCoord2fARB(GL_TEXTURE3_ARB, canvascoord[1], canvascoord[2]); glVertex2f(1.0f,-1.0f);
glEnd();
}
}
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
index f90b5959f76..deca7cbed9f 100644
--- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
@@ -125,7 +125,7 @@ void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList
{
RAS_MaterialBucket* bucket = *bit;
RAS_MeshSlot* ms;
- // remove the mesh slot form the list, it culls them automatically for next frame
+ // remove the mesh slot from the list, it culls them automatically for next frame
while ((ms = bucket->GetNextActiveMeshSlot())) {
slots[i++].set(ms, bucket, pnorm);
}
@@ -157,7 +157,7 @@ void RAS_BucketManager::RenderAlphaBuckets(const MT_Transform& cameratrans, RAS_
sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms));
// make this mesh slot culled automatically for next frame
- // it will be culled out by frustrum culling
+ // it will be culled out by frustum culling
sit->m_ms->SetCulled(true);
}
@@ -174,14 +174,14 @@ void RAS_BucketManager::RenderSolidBuckets(const MT_Transform& cameratrans, RAS_
#if 1
RAS_MaterialBucket* bucket = *bit;
RAS_MeshSlot* ms;
- // remove the mesh slot form the list, it culls them automatically for next frame
+ // remove the mesh slot from the list, it culls them automatically for next frame
while ((ms = bucket->GetNextActiveMeshSlot())) {
rasty->SetClientObject(ms->m_clientObj);
while (bucket->ActivateMaterial(cameratrans, rasty))
bucket->RenderMeshSlot(cameratrans, rasty, *ms);
// make this mesh slot culled automatically for next frame
- // it will be culled out by frustrum culling
+ // it will be culled out by frustum culling
ms->SetCulled(true);
}
#else
@@ -196,7 +196,7 @@ void RAS_BucketManager::RenderSolidBuckets(const MT_Transform& cameratrans, RAS_
(*bit)->RenderMeshSlot(cameratrans, rasty, *mit);
// make this mesh slot culled automatically for next frame
- // it will be culled out by frustrum culling
+ // it will be culled out by frustum culling
mit->SetCulled(true);
}
#endif
@@ -282,7 +282,7 @@ void RAS_BucketManager::OptimizeBuckets(MT_Scalar distance)
{
BucketList::iterator bit;
- distance = 10.0;
+ distance = 10.0f;
for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit)
(*bit)->Optimize(distance);
@@ -367,7 +367,7 @@ void RAS_BucketManager::RemoveMaterial(RAS_IPolyMaterial * mat)
void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other, SCA_IScene *scene)
{
- /* concatinate lists */
+ /* concatenate lists */
// printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size());
GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() );
diff --git a/source/gameengine/Rasterizer/RAS_CameraData.h b/source/gameengine/Rasterizer/RAS_CameraData.h
index e2024a4a55d..bc8433afd05 100644
--- a/source/gameengine/Rasterizer/RAS_CameraData.h
+++ b/source/gameengine/Rasterizer/RAS_CameraData.h
@@ -51,10 +51,10 @@ struct RAS_CameraData
int m_viewporttop;
float m_focallength;
- RAS_CameraData(float lens = 35.0, float scale = 6.0, float sensor_x = 32.0, float sensor_y = 18.0, short sensor_fit = 0,
- float shift_x = 0.0, float shift_y = 0.0,
- float clipstart = 0.1, float clipend = 5000.0, bool perspective = true,
- float focallength = 3.0, bool viewport = false, int viewportleft = 0, int viewportbottom = 0,
+ RAS_CameraData(float lens = 35.0f, float scale = 6.0f, float sensor_x = 32.0f, float sensor_y = 18.0f, short sensor_fit = 0,
+ float shift_x = 0.0f, float shift_y = 0.0f,
+ float clipstart = 0.1f, float clipend = 5000.0f, bool perspective = true,
+ float focallength = 3.0f, bool viewport = false, int viewportleft = 0, int viewportbottom = 0,
int viewportright = 0, int viewporttop = 0) :
m_lens(lens),
m_scale(scale),
diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.cpp b/source/gameengine/Rasterizer/RAS_FramingManager.cpp
index c5f15c9ad21..8b0ec22fde3 100644
--- a/source/gameengine/Rasterizer/RAS_FramingManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_FramingManager.cpp
@@ -283,14 +283,14 @@ ComputeFrustum(
switch (sensor_fit) {
case RAS_SENSORFIT_HOR:
{
- x_scale = 1.0;
+ x_scale = 1.0f;
y_scale = float(viewport.GetHeight()) / float(viewport.GetWidth());
break;
}
case RAS_SENSORFIT_VERT:
{
x_scale = float(viewport.GetWidth()) / float(viewport.GetHeight());
- y_scale = 1.0;
+ y_scale = 1.0f;
break;
}
case RAS_SENSORFIT_AUTO:
@@ -377,14 +377,14 @@ RAS_FramingManager::
switch (sensor_fit) {
case RAS_SENSORFIT_HOR:
{
- x_scale = 1.0;
+ x_scale = 1.0f;
y_scale = float(viewport.GetHeight()) / float(viewport.GetWidth());
break;
}
case RAS_SENSORFIT_VERT:
{
x_scale = float(viewport.GetWidth()) / float(viewport.GetHeight());
- y_scale = 1.0;
+ y_scale = 1.0f;
break;
}
case RAS_SENSORFIT_AUTO:
diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.h b/source/gameengine/Rasterizer/RAS_FramingManager.h
index 5741a91939e..cb86a7a4484 100644
--- a/source/gameengine/Rasterizer/RAS_FramingManager.h
+++ b/source/gameengine/Rasterizer/RAS_FramingManager.h
@@ -73,7 +73,7 @@ public :
};
/**
- * Contructor
+ * Constructor
*/
RAS_FrameSettings(
@@ -221,7 +221,7 @@ public :
/**
- * compute a frustrum given a valid viewport,
+ * compute a frustum given a valid viewport,
* RAS_FrameSettings, canvas description
* and camera description
*/
diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.cpp b/source/gameengine/Rasterizer/RAS_ICanvas.cpp
new file mode 100644
index 00000000000..808d257f8f0
--- /dev/null
+++ b/source/gameengine/Rasterizer/RAS_ICanvas.cpp
@@ -0,0 +1,128 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gameengine/Rasterizer/RAS_ICanvas.cpp
+ * \ingroup bgerast
+ */
+
+#include "RAS_ICanvas.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BLI_task.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+}
+
+
+// Task data for saving screenshots in a different thread.
+struct ScreenshotTaskData
+{
+ unsigned int *dumprect;
+ int dumpsx;
+ int dumpsy;
+ char *path;
+ ImageFormatData *im_format;
+};
+
+/**
+ * Function that actually performs the image compression and saving to disk of a screenshot.
+ * Run in a separate thread by RAS_ICanvas::save_screenshot().
+ *
+ * @param taskdata Must point to a ScreenshotTaskData object. This function takes ownership
+ * of all pointers in the ScreenshotTaskData, and frees them.
+ */
+void save_screenshot_thread_func(TaskPool *__restrict pool, void *taskdata, int threadid);
+
+
+RAS_ICanvas::RAS_ICanvas()
+{
+ m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS);
+ m_taskpool = BLI_task_pool_create(m_taskscheduler, NULL);
+}
+
+RAS_ICanvas::~RAS_ICanvas()
+{
+ if (m_taskpool) {
+ BLI_task_pool_work_and_wait(m_taskpool);
+ BLI_task_pool_free(m_taskpool);
+ m_taskpool = NULL;
+ }
+
+ if (m_taskscheduler) {
+ BLI_task_scheduler_free(m_taskscheduler);
+ m_taskscheduler = NULL;
+ }
+}
+
+
+void save_screenshot_thread_func(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ ScreenshotTaskData *task = static_cast<ScreenshotTaskData *>(taskdata);
+
+ /* create and save imbuf */
+ ImBuf *ibuf = IMB_allocImBuf(task->dumpsx, task->dumpsy, 24, 0);
+ ibuf->rect = task->dumprect;
+
+ BKE_imbuf_write_as(ibuf, task->path, task->im_format, false);
+
+ ibuf->rect = NULL;
+ IMB_freeImBuf(ibuf);
+ MEM_freeN(task->dumprect);
+ MEM_freeN(task->path);
+ MEM_freeN(task->im_format);
+}
+
+
+void RAS_ICanvas::save_screenshot(const char *filename, int dumpsx, int dumpsy, unsigned int *dumprect,
+ ImageFormatData * im_format)
+{
+ /* create file path */
+ char *path = (char *)MEM_mallocN(FILE_MAX, "screenshot-path");
+ BLI_strncpy(path, filename, FILE_MAX);
+ BLI_path_abs(path, G.main->name);
+ BLI_path_frame(path, m_frame, 0);
+ m_frame++;
+ BKE_image_path_ensure_ext_from_imtype(path, im_format->imtype);
+
+ /* Save the actual file in a different thread, so that the
+ * game engine can keep running at full speed. */
+ ScreenshotTaskData *task = (ScreenshotTaskData *)MEM_mallocN(sizeof(ScreenshotTaskData), "screenshot-data");
+ task->dumprect = dumprect;
+ task->dumpsx = dumpsx;
+ task->dumpsy = dumpsy;
+ task->path = path;
+ task->im_format = im_format;
+
+ BLI_task_pool_push(m_taskpool,
+ save_screenshot_thread_func,
+ task,
+ true, // free task data
+ TASK_PRIORITY_LOW);
+}
diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h
index 471c2c97fa1..91cc13c8f85 100644
--- a/source/gameengine/Rasterizer/RAS_ICanvas.h
+++ b/source/gameengine/Rasterizer/RAS_ICanvas.h
@@ -37,6 +37,9 @@
#endif
class RAS_Rect;
+struct TaskScheduler;
+struct TaskPool;
+struct ImageFormatData;
/**
* 2D rendering device context. The connection from 3d rendercontext to 2d surface.
@@ -56,10 +59,8 @@ public:
MOUSE_NORMAL
};
- virtual
- ~RAS_ICanvas(
- ) {
- }
+ RAS_ICanvas();
+ virtual ~RAS_ICanvas();
virtual
void
@@ -260,7 +261,23 @@ public:
protected:
RAS_MouseState m_mousestate;
+ int m_frame; /// frame number for screenshots.
+ TaskScheduler *m_taskscheduler;
+ TaskPool *m_taskpool;
+ /**
+ * Saves screenshot data to a file. The actual compression and disk I/O is performed in
+ * a separate thread.
+ *
+ * @param filename name of the file, can contain "###" for sequential numbering. A copy of the string
+ * is made, so the pointer can be freed by the caller.
+ * @param dumpsx width in pixels.
+ * @param dumpsy height in pixels.
+ * @param dumprect pixel data; ownership is passed to this function, which also frees the data.
+ * @param im_format image format for the file; ownership is passed to this function, which also frees the data.
+ */
+ void save_screenshot(const char *filename, int dumpsx, int dumpsy, unsigned int *dumprect,
+ ImageFormatData * im_format);
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_ICanvas")
diff --git a/source/gameengine/Rasterizer/RAS_ILightObject.h b/source/gameengine/Rasterizer/RAS_ILightObject.h
index f087f3bbb70..a3d55c925d6 100644
--- a/source/gameengine/Rasterizer/RAS_ILightObject.h
+++ b/source/gameengine/Rasterizer/RAS_ILightObject.h
@@ -38,6 +38,7 @@ class KX_Camera;
class KX_Scene;
class MT_Transform;
+class MT_Matrix4x4;
struct Image;
@@ -56,11 +57,19 @@ public:
float m_energy;
float m_distance;
+ float m_shadowclipstart;
+ float m_shadowfrustumsize;
+ float m_shadowclipend;
+ float m_shadowbias;
+ float m_shadowbleedbias;
+ short m_shadowmaptype;
+ float m_shadowcolor[3];
float m_color[3];
float m_att1;
float m_att2;
+ float m_coeff_const, m_coeff_lin, m_coeff_quad;
float m_spotsize;
float m_spotblend;
@@ -74,6 +83,8 @@ public:
virtual RAS_ILightObject* Clone() = 0;
virtual bool HasShadowBuffer() = 0;
+ virtual int GetShadowBindCode() = 0;
+ virtual MT_Matrix4x4 GetShadowMatrix() = 0;
virtual int GetShadowLayer() = 0;
virtual void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans) = 0;
virtual void UnbindShadowBuffer() = 0;
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
index d07b4910968..2a736aa7deb 100644
--- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
@@ -62,10 +62,10 @@ void RAS_IPolyMaterial::Initialize(
m_polymatid = m_newpolymatid++;
m_flag = 0;
m_multimode = 0;
- m_shininess = 35.0;
- m_specular.setValue(0.5,0.5,0.5);
- m_specularity = 1.0;
- m_diffuse.setValue(0.5,0.5,0.5);
+ m_shininess = 35.0f;
+ m_specular.setValue(0.5f,0.5f,0.5f);
+ m_specularity = 1.0f;
+ m_diffuse.setValue(0.5f,0.5f,0.5f);
m_drawingmode = ConvertFaceMode(game, image);
}
@@ -85,10 +85,10 @@ RAS_IPolyMaterial::RAS_IPolyMaterial()
m_flag(0),
m_multimode(0)
{
- m_shininess = 35.0;
- m_specular = MT_Vector3(0.5,0.5,0.5);
- m_specularity = 1.0;
- m_diffuse = MT_Vector3(0.5,0.5,0.5);
+ m_shininess = 35.0f;
+ m_specular = MT_Vector3(0.5f,0.5f,0.5f);
+ m_specularity = 1.0f;
+ m_diffuse = MT_Vector3(0.5f,0.5f,0.5f);
}
RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname,
@@ -113,10 +113,10 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname,
m_flag(0),
m_multimode(0)
{
- m_shininess = 35.0;
- m_specular = MT_Vector3(0.5,0.5,0.5);
- m_specularity = 1.0;
- m_diffuse = MT_Vector3(0.5,0.5,0.5);
+ m_shininess = 35.0f;
+ m_specular = MT_Vector3(0.5f,0.5f,0.5f);
+ m_specularity = 1.0f;
+ m_diffuse = MT_Vector3(0.5f,0.5f,0.5f);
}
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
index 7fbaf076d25..a92b87773c7 100644
--- a/source/gameengine/Rasterizer/RAS_IRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -267,7 +267,6 @@ public:
* IndexPrimitives: Renders primitives from mesh slot.
*/
virtual void IndexPrimitives(class RAS_MeshSlot &ms) = 0;
- virtual void IndexPrimitivesMulti(class RAS_MeshSlot &ms) = 0;
/**
* IndexPrimitives_3DText will render text into the polygons.
@@ -423,7 +422,7 @@ public:
/**
* Render Tools
*/
- virtual void applyTransform(double *oglmatrix, int drawingmode) = 0;
+ virtual void applyTransform(float *oglmatrix, int drawingmode) = 0;
/**
* Renders 2D boxes.
@@ -447,7 +446,7 @@ public:
*/
virtual void RenderText3D(
int fontid, const char *text, int size, int dpi,
- const float color[4], const double mat[16], float aspect) = 0;
+ const float color[4], const float mat[16], float aspect) = 0;
/**
* Renders 2D text string.
@@ -480,6 +479,11 @@ public:
virtual void SetAuxilaryClientInfo(void *inf) = 0;
+ /**
+ * Prints information about what the hardware supports.
+ */
+ virtual void PrintHardwareInfo() = 0;
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_IRasterizer")
#endif
diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
index 2078fc99f2e..9cd8f77adfd 100644
--- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
+++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
@@ -58,7 +58,7 @@ RAS_MeshSlot::RAS_MeshSlot() : SG_QList()
m_bVisible = false;
m_bCulled = true;
m_bObjectColor = false;
- m_RGBAcolor = MT_Vector4(0.0, 0.0, 0.0, 0.0);
+ m_RGBAcolor = MT_Vector4(0.0f, 0.0f, 0.0f, 0.0f);
m_DisplayList = NULL;
m_bDisplayList = true;
m_joinSlot = NULL;
@@ -649,15 +649,13 @@ void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRa
else
ms.m_bDisplayList = true;
- // for text drawing using faces
- if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT)
+ if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT) {
+ // for text drawing using faces
rasty->IndexPrimitives_3DText(ms, m_material);
- // for multitexturing
- else if ((m_material->GetFlag() & (RAS_MULTITEX|RAS_BLENDERGLSL)))
- rasty->IndexPrimitivesMulti(ms);
- // use normal IndexPrimitives
- else
+ }
+ else {
rasty->IndexPrimitives(ms);
+ }
rasty->PopMatrix();
}
diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h
index 1eee99f896b..75cc382c78c 100644
--- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h
+++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h
@@ -128,7 +128,7 @@ public:
void* m_clientObj;
RAS_Deformer* m_pDeformer;
DerivedMesh* m_pDerivedMesh;
- double* m_OpenGLMatrix;
+ float* m_OpenGLMatrix;
// visibility
bool m_bVisible;
bool m_bCulled;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
index 888a7114f50..9f95e2c82af 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
@@ -49,20 +49,16 @@ set(INC_SYS
)
set(SRC
- RAS_GLExtensionManager.cpp
RAS_ListRasterizer.cpp
RAS_OpenGLLight.cpp
RAS_OpenGLRasterizer.cpp
- RAS_StorageIM.cpp
RAS_StorageVA.cpp
RAS_StorageVBO.cpp
- RAS_GLExtensionManager.h
RAS_IStorage.h
RAS_ListRasterizer.h
RAS_OpenGLLight.h
RAS_OpenGLRasterizer.h
- RAS_StorageIM.h
RAS_StorageVA.h
RAS_StorageVBO.h
)
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
deleted file mode 100644
index bc22d68e218..00000000000
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
- * \ingroup bgerastogl
- */
-
-
-#include <iostream>
-
-#include "glew-mx.h"
-
-#include "RAS_GLExtensionManager.h"
-
-namespace bgl
-{
- void InitExtensions(bool debug)
- {
- static bool firsttime = true;
-
- if (firsttime) {
- firsttime = false;
-
- if (debug) {
- if (GLEW_ATI_pn_triangles)
- std::cout << "Enabled GL_ATI_pn_triangles" << std::endl;
- if (GLEW_ARB_texture_env_combine)
- std::cout << "Detected GL_ARB_texture_env_combine" << std::endl;
- if (GLEW_ARB_texture_cube_map)
- std::cout << "Detected GL_ARB_texture_cube_map" << std::endl;
- if (GLEW_ARB_multitexture)
- std::cout << "Detected GL_ARB_multitexture" << std::endl;
- if (GLEW_ARB_shader_objects)
- std::cout << "Detected GL_ARB_shader_objects" << std::endl;
- if (GLEW_ARB_vertex_shader)
- std::cout << "Detected GL_ARB_vertex_shader" << std::endl;
- if (GLEW_ARB_fragment_shader)
- std::cout << "Detected GL_ARB_fragment_shader" << std::endl;
- if (GLEW_ARB_vertex_program)
- std::cout << "Detected GL_ARB_vertex_program" << std::endl;
- if (GLEW_ARB_depth_texture)
- std::cout << "Detected GL_ARB_depth_texture" << std::endl;
- if (GLEW_EXT_separate_specular_color)
- std::cout << "Detected GL_EXT_separate_specular_color" << std::endl;
- }
- }
- }
-} // namespace bgl
-
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h
deleted file mode 100644
index 9f2039b4c6f..00000000000
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file RAS_GLExtensionManager.h
- * \ingroup bgerastogl
- */
-
-#ifndef __RAS_GLEXTENSIONMANAGER_H__
-#define __RAS_GLEXTENSIONMANAGER_H__
-
-/** Note: this used to have a lot more code, but now extension handling
- * is done by GLEW, so it does mostly debug stuff */
-
-namespace bgl
-{
- void InitExtensions(bool debug);
-} /* namespace bgl */
-
-#endif /* __RAS_GLEXTENSIONMANAGER_H__ */
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h
index bfa6e1a6cb7..ae0cdcd84af 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h
@@ -44,7 +44,6 @@ public:
virtual void Exit()=0;
virtual void IndexPrimitives(RAS_MeshSlot& ms)=0;
- virtual void IndexPrimitivesMulti(RAS_MeshSlot& ms)=0;
virtual void SetDrawingMode(int drawingmode)=0;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
index 34184f73953..b2d580161ca 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -122,7 +122,7 @@ bool RAS_ListSlot::End()
-RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, int storage)
+RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, RAS_STORAGE_TYPE storage)
: RAS_OpenGLRasterizer(canvas, storage)
{
}
@@ -243,30 +243,6 @@ void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms)
if (ms.m_bDisplayList) {
localSlot = FindOrAdd(ms);
localSlot->DrawList();
- if (localSlot->End()) {
- // save slot here too, needed for replicas and object using same mesh
- // => they have the same vertexarray but different mesh slot
- ms.m_DisplayList = localSlot;
- return;
- }
- }
-
- RAS_OpenGLRasterizer::IndexPrimitives(ms);
-
- if (ms.m_bDisplayList) {
- localSlot->EndList();
- ms.m_DisplayList = localSlot;
- }
-}
-
-
-void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms)
-{
- RAS_ListSlot* localSlot =0;
-
- if (ms.m_bDisplayList) {
- localSlot = FindOrAdd(ms);
- localSlot->DrawList();
if (localSlot->End()) {
// save slot here too, needed for replicas and object using same mesh
@@ -276,7 +252,7 @@ void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms)
}
}
- RAS_OpenGLRasterizer::IndexPrimitivesMulti(ms);
+ RAS_OpenGLRasterizer::IndexPrimitives(ms);
if (ms.m_bDisplayList) {
localSlot->EndList();
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
index 5e1c662bc17..e3e6931311b 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
@@ -56,11 +56,10 @@ class RAS_ListRasterizer : public RAS_OpenGLRasterizer
public:
void RemoveListSlot(RAS_ListSlot* list);
- RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock=false, int storage=RAS_AUTO_STORAGE);
+ RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, RAS_STORAGE_TYPE storage);
virtual ~RAS_ListRasterizer();
virtual void IndexPrimitives(class RAS_MeshSlot& ms);
- virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms);
virtual bool Init();
virtual void Exit();
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
index 4ac1c9c4ebb..e15ae4bd0d7 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
@@ -59,7 +59,7 @@ RAS_OpenGLLight::~RAS_OpenGLLight()
if ((lamp = GetGPULamp())) {
float obmat[4][4] = {{0}};
GPU_lamp_update(lamp, 0, 0, obmat);
- GPU_lamp_update_distance(lamp, la->dist, la->att1, la->att2);
+ GPU_lamp_update_distance(lamp, la->dist, la->att1, la->att2, la->coeff_const, la->coeff_lin, la->coeff_quad);
GPU_lamp_update_spot(lamp, la->spotsize, la->spotblend);
}
}
@@ -100,13 +100,13 @@ bool RAS_OpenGLLight::ApplyFixedFunctionLighting(KX_Scene *kxscene, int oblayer,
//vec[0] = base->object->obmat[2][0];
//vec[1] = base->object->obmat[2][1];
//vec[2] = base->object->obmat[2][2];
- vec[3] = 0.0;
+ vec[3] = 0.0f;
glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec);
}
else {
- //vec[3] = 1.0;
+ //vec[3] = 1.0f;
glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec);
- glLightf((GLenum)(GL_LIGHT0+slot), GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf((GLenum)(GL_LIGHT0+slot), GL_CONSTANT_ATTENUATION, 1.0f);
glLightf((GLenum)(GL_LIGHT0+slot), GL_LINEAR_ATTENUATION, m_att1/m_distance);
// without this next line it looks backward compatible.
//attennuation still is acceptable
@@ -124,30 +124,30 @@ bool RAS_OpenGLLight::ApplyFixedFunctionLighting(KX_Scene *kxscene, int oblayer,
glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_EXPONENT, 128.0f * m_spotblend);
}
else {
- glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, 180.0);
+ glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, 180.0f);
}
}
if (m_nodiffuse) {
- vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
+ vec[0] = vec[1] = vec[2] = vec[3] = 0.0f;
}
else {
vec[0] = m_energy*m_color[0];
vec[1] = m_energy*m_color[1];
vec[2] = m_energy*m_color[2];
- vec[3] = 1.0;
+ vec[3] = 1.0f;
}
glLightfv((GLenum)(GL_LIGHT0+slot), GL_DIFFUSE, vec);
if (m_nospecular)
{
- vec[0] = vec[1] = vec[2] = vec[3] = 0.0;
+ vec[0] = vec[1] = vec[2] = vec[3] = 0.0f;
}
else if (m_nodiffuse) {
vec[0] = m_energy*m_color[0];
vec[1] = m_energy*m_color[1];
vec[2] = m_energy*m_color[2];
- vec[3] = 1.0;
+ vec[3] = 1.0f;
}
glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPECULAR, vec);
@@ -177,6 +177,26 @@ bool RAS_OpenGLLight::HasShadowBuffer()
return false;
}
+int RAS_OpenGLLight::GetShadowBindCode()
+{
+ GPULamp *lamp;
+
+ if ((lamp = GetGPULamp()))
+ return GPU_lamp_shadow_bind_code(lamp);
+ return -1;
+}
+
+MT_Matrix4x4 RAS_OpenGLLight::GetShadowMatrix()
+{
+ GPULamp *lamp;
+
+ if ((lamp = GetGPULamp()))
+ return MT_Matrix4x4(GPU_lamp_dynpersmat(lamp));
+ MT_Matrix4x4 mat;
+ mat.setIdentity();
+ return mat;
+}
+
int RAS_OpenGLLight::GetShadowLayer()
{
GPULamp *lamp;
@@ -262,16 +282,16 @@ void RAS_OpenGLLight::Update()
// lights don't get their openGL matrix updated, do it now
if (kxlight->GetSGNode()->IsDirty())
kxlight->GetOpenGLMatrix();
- double *dobmat = kxlight->GetOpenGLMatrixPtr()->getPointer();
+ float *dobmat = kxlight->GetOpenGLMatrixPtr()->getPointer();
for (int i=0; i<4; i++)
for (int j=0; j<4; j++, dobmat++)
obmat[i][j] = (float)*dobmat;
-
- GPU_lamp_update(lamp, m_layer, 0, obmat);
+ int hide = kxlight->GetVisible() ? 0 : 1;
+ GPU_lamp_update(lamp, m_layer, hide, obmat);
GPU_lamp_update_colors(lamp, m_color[0], m_color[1],
m_color[2], m_energy);
- GPU_lamp_update_distance(lamp, m_distance, m_att1, m_att2);
+ GPU_lamp_update_distance(lamp, m_distance, m_att1, m_att2, m_coeff_const, m_coeff_lin, m_coeff_quad);
GPU_lamp_update_spot(lamp, m_spotsize, m_spotblend);
}
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h
index 0c4e5bf41c4..a520b18c434 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h
@@ -46,6 +46,8 @@ public:
RAS_OpenGLLight* Clone() { return new RAS_OpenGLLight(*this); }
bool HasShadowBuffer();
+ int GetShadowBindCode();
+ MT_Matrix4x4 GetShadowMatrix();
int GetShadowLayer();
void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans);
void UnbindShadowBuffer();
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 1758b7abf9f..34f0ef04a58 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -47,15 +47,17 @@
#include "RAS_OpenGLLight.h"
-#include "RAS_StorageIM.h"
#include "RAS_StorageVA.h"
#include "RAS_StorageVBO.h"
#include "GPU_draw.h"
+#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "GPU_shader.h"
extern "C"{
#include "BLF_api.h"
+ #include "BKE_DerivedMesh.h"
}
@@ -83,21 +85,21 @@ static GLuint right_eye_vinterlace_mask[32];
*/
static GLuint hinterlace_mask[33];
-RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, int storage)
+RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE storage)
:RAS_IRasterizer(canvas),
m_2DCanvas(canvas),
m_fogenabled(false),
- m_time(0.0),
+ m_time(0.0f),
m_campos(0.0f, 0.0f, 0.0f),
m_camortho(false),
m_stereomode(RAS_STEREO_NOSTEREO),
m_curreye(RAS_STEREO_LEFTEYE),
- m_eyeseparation(0.0),
- m_focallength(0.0),
+ m_eyeseparation(0.0f),
+ m_focallength(0.0f),
m_setfocallength(false),
m_noOfScanlines(32),
m_motionblur(0),
- m_motionblurvalue(-1.0),
+ m_motionblurvalue(-1.0f),
m_usingoverrideshader(false),
m_clientobject(NULL),
m_auxilaryClientInfo(NULL),
@@ -122,27 +124,22 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, int storage)
m_prevafvalue = GPU_get_anisotropic();
- if (m_storage_type == RAS_VBO /*|| m_storage_type == RAS_AUTO_STORAGE && GLEW_ARB_vertex_buffer_object*/)
- {
+ if (m_storage_type == RAS_VBO /*|| m_storage_type == RAS_AUTO_STORAGE && GLEW_ARB_vertex_buffer_object*/) {
m_storage = new RAS_StorageVBO(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer);
- m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer);
- m_storage_type = RAS_VBO;
}
- else if ((m_storage_type == RAS_VA) || (m_storage_type == RAS_AUTO_STORAGE && GLEW_VERSION_1_1))
- {
+ else if ((m_storage_type == RAS_VA) || (m_storage_type == RAS_AUTO_STORAGE)) {
m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer);
- m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer);
- m_storage_type = RAS_VA;
}
- else
- {
- m_storage = m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer);
- m_storage_type = RAS_IMMEDIATE;
+ else {
+ printf("Unknown rasterizer storage type, falling back to vertex arrays\n");
+ m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer);
}
glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights);
if (m_numgllights < 8)
m_numgllights = 8;
+
+ PrintHardwareInfo();
}
@@ -151,8 +148,6 @@ RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer()
{
// Restore the previous AF value
GPU_set_anisotropic(m_prevafvalue);
- if (m_failsafe_storage && m_failsafe_storage != m_storage)
- delete m_failsafe_storage;
if (m_storage)
delete m_storage;
@@ -176,10 +171,10 @@ bool RAS_OpenGLRasterizer::Init()
glFrontFace(GL_CCW);
m_last_frontface = true;
- m_redback = 0.4375;
- m_greenback = 0.4375;
- m_blueback = 0.4375;
- m_alphaback = 0.0;
+ m_redback = 0.4375f;
+ m_greenback = 0.4375f;
+ m_blueback = 0.4375f;
+ m_alphaback = 0.0f;
glClearColor(m_redback,m_greenback,m_blueback,m_alphaback);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@@ -249,12 +244,11 @@ bool RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat)
void RAS_OpenGLRasterizer::Exit()
{
-
m_storage->Exit();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
- glClearDepth(1.0);
+ glClearDepth(1.0f);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(m_redback, m_greenback, m_blueback, m_alphaback);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -321,9 +315,6 @@ void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode)
glDisable(GL_CULL_FACE);
m_storage->SetDrawingMode(drawingmode);
- if (m_failsafe_storage && m_failsafe_storage != m_storage) {
- m_failsafe_storage->SetDrawingMode(drawingmode);
- }
}
int RAS_OpenGLRasterizer::GetDrawingMode()
@@ -371,7 +362,7 @@ void RAS_OpenGLRasterizer::FlushDebugShapes(SCA_IScene *scene)
if (light) glDisable(GL_LIGHTING);
if (tex) glDisable(GL_TEXTURE_2D);
- //draw lines
+ // draw lines
glBegin(GL_LINES);
for (unsigned int i = 0; i < debugShapes.size(); i++) {
if (debugShapes[i].m_type != OglDebugShape::LINE)
@@ -379,19 +370,19 @@ void RAS_OpenGLRasterizer::FlushDebugShapes(SCA_IScene *scene)
glColor4f(debugShapes[i].m_color[0], debugShapes[i].m_color[1], debugShapes[i].m_color[2], 1.0f);
const MT_Scalar *fromPtr = &debugShapes[i].m_pos.x();
const MT_Scalar *toPtr= &debugShapes[i].m_param.x();
- glVertex3dv(fromPtr);
- glVertex3dv(toPtr);
+ glVertex3fv(fromPtr);
+ glVertex3fv(toPtr);
}
glEnd();
- //draw circles
+ // draw circles
for (unsigned int i = 0; i < debugShapes.size(); i++) {
if (debugShapes[i].m_type != OglDebugShape::CIRCLE)
continue;
glBegin(GL_LINE_LOOP);
glColor4f(debugShapes[i].m_color[0], debugShapes[i].m_color[1], debugShapes[i].m_color[2], 1.0f);
- static const MT_Vector3 worldUp(0.0, 0.0, 1.0);
+ static const MT_Vector3 worldUp(0.0f, 0.0f, 1.0f);
MT_Vector3 norm = debugShapes[i].m_param;
MT_Matrix3x3 tr;
if (norm.fuzzyZero() || norm == worldUp)
@@ -411,12 +402,12 @@ void RAS_OpenGLRasterizer::FlushDebugShapes(SCA_IScene *scene)
int n = (int)debugShapes[i].m_param2.y();
for (int j = 0; j<n; j++)
{
- MT_Scalar theta = j*M_PI*2/n;
- MT_Vector3 pos(cos(theta) * rad, sin(theta) * rad, 0.0);
+ MT_Scalar theta = j*(float)M_PI*2/n;
+ MT_Vector3 pos(cosf(theta) * rad, sinf(theta) * rad, 0.0f);
pos = pos*tr;
pos += debugShapes[i].m_pos;
const MT_Scalar* posPtr = &pos.x();
- glVertex3dv(posPtr);
+ glVertex3fv(posPtr);
}
glEnd();
}
@@ -554,13 +545,15 @@ void RAS_OpenGLRasterizer::SetEye(const StereoEye eye)
glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
}
else {
- //glAccum(GL_LOAD, 1.0);
+ //glAccum(GL_LOAD, 1.0f);
glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE);
ClearDepthBuffer();
}
break;
case RAS_STEREO_VINTERLACE:
{
+ // OpenGL stippling is deprecated, it is no longer possible to affect all shaders
+ // this way, offscreen rendering and then compositing may be the better solution
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple((const GLubyte*) ((m_curreye == RAS_STEREO_LEFTEYE) ? left_eye_vinterlace_mask : right_eye_vinterlace_mask));
if (m_curreye == RAS_STEREO_RIGHTEYE)
@@ -735,38 +728,117 @@ void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit, int layer)
void RAS_OpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms)
{
if (ms.m_pDerivedMesh)
- m_failsafe_storage->IndexPrimitives(ms);
+ DrawDerivedMesh(ms);
else
m_storage->IndexPrimitives(ms);
}
-void RAS_OpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms)
+// Code for hooking into Blender's mesh drawing for derived meshes.
+// If/when we use more of Blender's drawing code, we may be able to
+// clean this up
+static bool current_wireframe;
+static RAS_MaterialBucket *current_bucket;
+static RAS_IPolyMaterial *current_polymat;
+static RAS_MeshSlot *current_ms;
+static RAS_MeshObject *current_mesh;
+static int current_blmat_nr;
+static GPUVertexAttribs current_gpu_attribs;
+static Image *current_image;
+static int CheckMaterialDM(int matnr, void *attribs)
+{
+ // only draw the current material
+ if (matnr != current_blmat_nr)
+ return 0;
+ GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs;
+ if (gattribs)
+ memcpy(gattribs, &current_gpu_attribs, sizeof(GPUVertexAttribs));
+ return 1;
+}
+
+static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr)
+{
+
+ // index is the original face index, retrieve the polygon
+ if (matnr == current_blmat_nr &&
+ (mtexpoly == NULL || mtexpoly->tpage == current_image)) {
+ // must handle color.
+ if (current_wireframe)
+ return DM_DRAW_OPTION_NO_MCOL;
+ if (current_ms->m_bObjectColor) {
+ MT_Vector4& rgba = current_ms->m_RGBAcolor;
+ glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
+ // don't use mcol
+ return DM_DRAW_OPTION_NO_MCOL;
+ }
+ if (!has_mcol) {
+ // we have to set the color from the material
+ unsigned char rgba[4];
+ current_polymat->GetMaterialRGBAColor(rgba);
+ glColor4ubv((const GLubyte *)rgba);
+ return DM_DRAW_OPTION_NORMAL;
+ }
+ return DM_DRAW_OPTION_NORMAL;
+ }
+ return DM_DRAW_OPTION_SKIP;
+}
+
+void RAS_OpenGLRasterizer::DrawDerivedMesh(class RAS_MeshSlot &ms)
{
- if (ms.m_pDerivedMesh)
- m_failsafe_storage->IndexPrimitivesMulti(ms);
+ // mesh data is in derived mesh
+ current_bucket = ms.m_bucket;
+ current_polymat = current_bucket->GetPolyMaterial();
+ current_ms = &ms;
+ current_mesh = ms.m_mesh;
+ current_wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME;
+ // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */
+
+ // handle two-side
+ if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL)
+ this->SetCullFace(true);
else
- m_storage->IndexPrimitivesMulti(ms);
+ this->SetCullFace(false);
+
+ if (current_polymat->GetFlag() & RAS_BLENDERGLSL) {
+ // GetMaterialIndex return the original mface material index,
+ // increment by 1 to match what derived mesh is doing
+ current_blmat_nr = current_polymat->GetMaterialIndex()+1;
+ // For GLSL we need to retrieve the GPU material attribute
+ Material* blmat = current_polymat->GetBlenderMaterial();
+ Scene* blscene = current_polymat->GetBlenderScene();
+ if (!current_wireframe && blscene && blmat)
+ GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat, false), &current_gpu_attribs);
+ else
+ memset(&current_gpu_attribs, 0, sizeof(current_gpu_attribs));
+ // DM draw can mess up blending mode, restore at the end
+ int current_blend_mode = GPU_get_material_alpha_blend();
+ ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM);
+ GPU_set_material_alpha_blend(current_blend_mode);
+ } else {
+ //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol);
+ current_blmat_nr = current_polymat->GetMaterialIndex();
+ current_image = current_polymat->GetBlenderImage();
+ ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV);
+ }
}
void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat)
{
glMatrixMode(GL_PROJECTION);
- double* matrix = &mat(0, 0);
- glLoadMatrixd(matrix);
+ float* matrix = &mat(0, 0);
+ glLoadMatrixf(matrix);
- m_camortho = (mat(3, 3) != 0.0);
+ m_camortho = (mat(3, 3) != 0.0f);
}
void RAS_OpenGLRasterizer::SetProjectionMatrix(const MT_Matrix4x4 & mat)
{
glMatrixMode(GL_PROJECTION);
- double matrix[16];
+ float matrix[16];
/* Get into argument. Looks a bit dodgy, but it's ok. */
mat.getValue(matrix);
- /* Internally, MT_Matrix4x4 uses doubles (MT_Scalar). */
- glLoadMatrixd(matrix);
+ glLoadMatrixf(matrix);
- m_camortho= (mat[3][3] != 0.0);
+ m_camortho = (mat[3][3] != 0.0f);
}
MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
@@ -780,7 +852,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
bool
) {
MT_Matrix4x4 result;
- double mat[16];
+ float mat[16];
// correction for stereo
if (Stereo())
@@ -808,8 +880,8 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
}
// leave bottom and top untouched
if (m_stereomode == RAS_STEREO_3DTVTOPBOTTOM) {
- // restore the vertical frustrum because the 3DTV will
- // expande the top and bottom part to the full size of the screen
+ // restore the vertical frustum because the 3DTV will
+ // expand the top and bottom part to the full size of the screen
bottom *= 2.0f;
top *= 2.0f;
}
@@ -819,7 +891,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
glLoadIdentity();
glFrustum(left, right, bottom, top, frustnear, frustfar);
- glGetDoublev(GL_PROJECTION_MATRIX, mat);
+ glGetFloatv(GL_PROJECTION_MATRIX, mat);
result.setValue(mat);
return result;
@@ -834,14 +906,14 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetOrthoMatrix(
float frustfar
) {
MT_Matrix4x4 result;
- double mat[16];
+ float mat[16];
- // stereo is meaning less for orthographic, disable it
+ // stereo is meaningless for orthographic, disable it
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(left, right, bottom, top, frustnear, frustfar);
- glGetDoublev(GL_PROJECTION_MATRIX, mat);
+ glGetFloatv(GL_PROJECTION_MATRIX, mat);
result.setValue(mat);
return result;
@@ -859,8 +931,8 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
// correction for stereo
if (Stereo() && perspective)
{
- MT_Vector3 unitViewDir(0.0, -1.0, 0.0); // minus y direction, Blender convention
- MT_Vector3 unitViewupVec(0.0, 0.0, 1.0);
+ MT_Vector3 unitViewDir(0.0f, -1.0f, 0.0f); // minus y direction, Blender convention
+ MT_Vector3 unitViewupVec(0.0f, 0.0f, 1.0f);
MT_Vector3 viewDir, viewupVec;
MT_Vector3 eyeline;
@@ -878,7 +950,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
// translate to left by half the eye distance
MT_Transform transform;
transform.setIdentity();
- transform.translate(-(eyeline * m_eyeseparation / 2.0));
+ transform.translate(-(eyeline * m_eyeseparation / 2.0f));
m_viewmatrix *= transform;
}
break;
@@ -887,7 +959,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
// translate to right by half the eye distance
MT_Transform transform;
transform.setIdentity();
- transform.translate(eyeline * m_eyeseparation / 2.0);
+ transform.translate(eyeline * m_eyeseparation / 2.0f);
m_viewmatrix *= transform;
}
break;
@@ -902,7 +974,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat,
m_viewmatrix.getValue(glviewmat);
glMatrixMode(GL_MODELVIEW);
- glLoadMatrixd(glviewmat);
+ glLoadMatrixf(glviewmat);
m_campos = pos;
}
@@ -994,7 +1066,7 @@ void RAS_OpenGLRasterizer::EnableMotionBlur(float motionblurvalue)
void RAS_OpenGLRasterizer::DisableMotionBlur()
{
m_motionblur = 0;
- m_motionblurvalue = -1.0;
+ m_motionblurvalue = -1.0f;
}
void RAS_OpenGLRasterizer::SetAlphaBlend(int alphablend)
@@ -1215,10 +1287,9 @@ void RAS_OpenGLRasterizer::RemoveLight(RAS_ILightObject* lightobject)
m_lights.erase(lit);
}
-bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast *result, void * const data)
+bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast *result, float *oglmatrix)
{
if (result->m_hitMesh) {
- double* const oglmatrix = (double* const) data;
RAS_Polygon* poly = result->m_hitMesh->GetPolygon(result->m_hitPolygon);
if (!poly->IsVisible())
@@ -1230,14 +1301,14 @@ bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast
left = (dir.cross(resultnormal)).safe_normalized();
// for the up vector, we take the 'resultnormal' returned by the physics
- double maat[16] = {left[0], left[1], left[2], 0,
+ float maat[16] = {left[0], left[1], left[2], 0,
dir[0], dir[1], dir[2], 0,
- resultnormal[0], resultnormal[1], resultnormal[2], 0,
- 0, 0, 0, 1};
+ resultnormal[0], resultnormal[1], resultnormal[2], 0,
+ 0, 0, 0, 1};
- glTranslated(oglmatrix[12],oglmatrix[13],oglmatrix[14]);
+ glTranslatef(oglmatrix[12],oglmatrix[13],oglmatrix[14]);
//glMultMatrixd(oglmatrix);
- glMultMatrixd(maat);
+ glMultMatrixf(maat);
return true;
}
else {
@@ -1245,7 +1316,7 @@ bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast
}
}
-void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode )
+void RAS_OpenGLRasterizer::applyTransform(float* oglmatrix,int objectdrawmode )
{
/* FIXME:
blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const
@@ -1266,14 +1337,14 @@ void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode )
//page 360/361 3D Game Engine Design, David Eberly for a discussion
// on screen aligned and axis aligned billboards
// assumed is that the preprocessor transformed all billboard polygons
- // so that their normal points into the positive x direction (1.0, 0.0, 0.0)
+ // so that their normal points into the positive x direction (1.0f, 0.0f, 0.0f)
// when new parenting for objects is done, this rotation
// will be moved into the object
MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]);
MT_Point3 campos = GetCameraPosition();
MT_Vector3 dir = (campos - objpos).safe_normalized();
- MT_Vector3 up(0,0,1.0);
+ MT_Vector3 up(0,0,1.0f);
KX_GameObject* gameobj = (KX_GameObject*)m_clientobject;
// get scaling of halo object
@@ -1298,13 +1369,13 @@ void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode )
dir *= size[1];
up *= size[2];
- double maat[16] = {left[0], left[1], left[2], 0,
+ float maat[16] = {left[0], left[1], left[2], 0,
dir[0], dir[1], dir[2], 0,
up[0], up[1], up[2], 0,
0, 0, 0, 1};
glTranslatef(objpos[0],objpos[1],objpos[2]);
- glMultMatrixd(maat);
+ glMultMatrixf(maat);
}
else {
@@ -1328,11 +1399,11 @@ void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode )
if (!physics_controller && parent)
physics_controller = parent->GetPhysicsController();
- KX_RayCast::Callback<RAS_OpenGLRasterizer> callback(this, physics_controller, oglmatrix);
+ KX_RayCast::Callback<RAS_OpenGLRasterizer, float> callback(this, physics_controller, oglmatrix);
if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback))
{
// couldn't find something to cast the shadow on...
- glMultMatrixd(oglmatrix);
+ glMultMatrixf(oglmatrix);
}
else
{ // we found the "ground", but the cast matrix doesn't take
@@ -1344,7 +1415,7 @@ void RAS_OpenGLRasterizer::applyTransform(double* oglmatrix,int objectdrawmode )
{
// 'normal' object
- glMultMatrixd(oglmatrix);
+ glMultMatrixf(oglmatrix);
}
}
}
@@ -1363,9 +1434,13 @@ static void DisableForText()
for (int i=0; i<RAS_MAX_TEXCO; i++) {
glActiveTextureARB(GL_TEXTURE0_ARB+i);
- if (GLEW_ARB_texture_cube_map)
+ if (GLEW_ARB_texture_cube_map) {
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
-
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_Q);
+ glDisable(GL_TEXTURE_GEN_R);
+ }
glDisable(GL_TEXTURE_2D);
}
@@ -1403,7 +1478,7 @@ void RAS_OpenGLRasterizer::RenderBox2D(int xco,
yco = height - yco;
int barsize = 50;
- /* draw in black first*/
+ /* draw in black first */
glColor3ub(0, 0, 0);
glBegin(GL_QUADS);
glVertex2f(xco + 1 + 1 + barsize * percentage, yco - 1 + 10);
@@ -1429,7 +1504,7 @@ void RAS_OpenGLRasterizer::RenderBox2D(int xco,
void RAS_OpenGLRasterizer::RenderText3D(
int fontid, const char *text, int size, int dpi,
- const float color[4], const double mat[16], float aspect)
+ const float color[4], const float mat[16], float aspect)
{
/* gl prepping */
DisableForText();
@@ -1441,9 +1516,9 @@ void RAS_OpenGLRasterizer::RenderText3D(
BLF_enable(fontid, BLF_MATRIX|BLF_ASPECT);
BLF_matrix(fontid, mat);
- /* aspect is the inverse scale that allows you to increase */
- /* your resolution without sizing the final text size */
- /* the bigger the size, the smaller the aspect */
+ /* aspect is the inverse scale that allows you to increase
+ * your resolution without sizing the final text size
+ * the bigger the size, the smaller the aspect */
BLF_aspect(fontid, aspect, aspect, aspect);
BLF_size(fontid, size, dpi);
@@ -1476,7 +1551,7 @@ void RAS_OpenGLRasterizer::RenderText2D(
glLoadIdentity();
if (mode == RAS_TEXT_PADDED) {
- /* draw in black first*/
+ /* draw in black first */
glColor3ub(0, 0, 0);
BLF_size(blf_mono_font, 11, 72);
BLF_position(blf_mono_font, (float)xco+1, (float)(height-yco-1), 0.0f);
@@ -1515,14 +1590,14 @@ void RAS_OpenGLRasterizer::MotionBlur()
motionblurvalue = GetMotionBlurValue();
if (state==1)
{
- //bugfix:load color buffer into accum buffer for the first time(state=1)
- glAccum(GL_LOAD, 1.0);
+ // bugfix:load color buffer into accum buffer for the first time(state=1)
+ glAccum(GL_LOAD, 1.0f);
SetMotionBlurState(2);
}
else if (motionblurvalue >= 0.0f && motionblurvalue <= 1.0f) {
glAccum(GL_MULT, motionblurvalue);
glAccum(GL_ACCUM, 1-motionblurvalue);
- glAccum(GL_RETURN, 1.0);
+ glAccum(GL_RETURN, 1.0f);
glFlush();
}
}
@@ -1544,3 +1619,68 @@ void RAS_OpenGLRasterizer::SetAuxilaryClientInfo(void* inf)
m_auxilaryClientInfo = inf;
}
+void RAS_OpenGLRasterizer::PrintHardwareInfo()
+{
+ #define pprint(x) std::cout << x << std::endl;
+
+ pprint("GL_VENDOR: " << glGetString(GL_VENDOR));
+ pprint("GL_RENDERER: " << glGetString(GL_RENDERER));
+ pprint("GL_VERSION: " << glGetString(GL_VERSION));
+ bool support=0;
+ pprint("Supported Extensions...");
+ pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no."));
+
+ support= GLEW_ARB_vertex_shader;
+ pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no."));
+ if (support) {
+ pprint(" ----------Details----------");
+ int max=0;
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint*)&max);
+ pprint(" Max uniform components." << max);
+
+ glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint*)&max);
+ pprint(" Max varying floats." << max);
+
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max);
+ pprint(" Max vertex texture units." << max);
+
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max);
+ pprint(" Max combined texture units." << max);
+ pprint("");
+ }
+
+ support=GLEW_ARB_fragment_shader;
+ pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no."));
+ if (support) {
+ pprint(" ----------Details----------");
+ int max=0;
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint*)&max);
+ pprint(" Max uniform components." << max);
+ pprint("");
+ }
+
+ support = GLEW_ARB_texture_cube_map;
+ pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no."));
+ if (support) {
+ pprint(" ----------Details----------");
+ int size=0;
+ glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&size);
+ pprint(" Max cubemap size." << size);
+ pprint("");
+ }
+
+ support = GLEW_ARB_multitexture;
+ pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no."));
+ if (support) {
+ pprint(" ----------Details----------");
+ int units=0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&units);
+ pprint(" Max texture units available. " << units);
+ pprint("");
+ }
+
+ pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no."));
+
+ pprint(" GL_ARB_texture_non_power_of_two supported " << (GPU_full_non_power_of_two_support()?"yes.":"no."));
+}
+
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
index ad49ebe5179..4c22d1de611 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -45,6 +45,8 @@ using namespace std;
#include "RAS_MaterialBucket.h"
#include "RAS_IPolygonMaterial.h"
+#include "BLI_utildefines.h"
+
class RAS_IStorage;
class RAS_ICanvas;
class RAS_OpenGLLight;
@@ -54,7 +56,6 @@ class RAS_OpenGLLight;
enum RAS_STORAGE_TYPE {
RAS_AUTO_STORAGE,
- RAS_IMMEDIATE,
RAS_VA,
RAS_VBO,
};
@@ -137,11 +138,10 @@ protected:
* Examples of concrete strategies: Vertex Arrays, VBOs, Immediate Mode*/
int m_storage_type;
RAS_IStorage *m_storage;
- RAS_IStorage *m_failsafe_storage; /* So derived mesh can use immediate mode */
public:
double GetTime();
- RAS_OpenGLRasterizer(RAS_ICanvas *canv, int storage=RAS_AUTO_STORAGE);
+ RAS_OpenGLRasterizer(RAS_ICanvas *canv, RAS_STORAGE_TYPE storage);
virtual ~RAS_OpenGLRasterizer();
/*enum DrawType
@@ -184,8 +184,8 @@ public:
virtual void SwapBuffers();
virtual void IndexPrimitives(class RAS_MeshSlot &ms);
- virtual void IndexPrimitivesMulti(class RAS_MeshSlot &ms);
virtual void IndexPrimitives_3DText(class RAS_MeshSlot &ms, class RAS_IPolyMaterial *polymat);
+ virtual void DrawDerivedMesh(class RAS_MeshSlot &ms);
virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat);
virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat);
@@ -297,17 +297,19 @@ public:
void RenderBox2D(int xco, int yco, int width, int height, float percentage);
void RenderText3D(int fontid, const char *text, int size, int dpi,
- const float color[4], const double mat[16], float aspect);
+ const float color[4], const float mat[16], float aspect);
void RenderText2D(RAS_TEXT_RENDER_MODE mode, const char *text,
int xco, int yco, int width, int height);
- void applyTransform(double *oglmatrix, int objectdrawmode);
+ void applyTransform(float *oglmatrix, int objectdrawmode);
void PushMatrix();
void PopMatrix();
- bool RayHit(struct KX_ClientObjectInfo *client, class KX_RayCast *result, void * const data);
- bool NeedRayCast(struct KX_ClientObjectInfo *) { return true; }
+ /// \see KX_RayCast
+ bool RayHit(struct KX_ClientObjectInfo *client, class KX_RayCast *result, float *oglmatrix);
+ /// \see KX_RayCast
+ bool NeedRayCast(struct KX_ClientObjectInfo *, void *UNUSED(data)) { return true; }
RAS_ILightObject* CreateLight();
void AddLight(RAS_ILightObject* lightobject);
@@ -321,6 +323,10 @@ public:
void SetAuxilaryClientInfo(void *inf);
+ /**
+ * Prints information about what the hardware supports.
+ */
+ virtual void PrintHardwareInfo();
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_OpenGLRasterizer")
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
deleted file mode 100644
index 2cf6088629a..00000000000
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "RAS_StorageIM.h"
-#include "RAS_MaterialBucket.h"
-#include "RAS_IPolygonMaterial.h"
-
-#include "glew-mx.h"
-#include "GPU_draw.h"
-#include "GPU_extensions.h"
-#include "GPU_material.h"
-
-extern "C"{
- #include "BKE_DerivedMesh.h"
-}
-
-RAS_StorageIM::RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
- m_drawingmode(RAS_IRasterizer::KX_TEXTURED),
- m_texco_num(texco_num),
- m_attrib_num(attrib_num),
- m_texco(texco),
- m_attrib(attrib),
- m_attrib_layer(attrib_layer)
-{
-}
-RAS_StorageIM::~RAS_StorageIM()
-{
-}
-
-bool RAS_StorageIM::Init()
-{
- return true;
-}
-void RAS_StorageIM::Exit()
-{
-}
-
-void RAS_StorageIM::IndexPrimitives(RAS_MeshSlot& ms)
-{
- IndexPrimitivesInternal(ms, false);
-}
-
-void RAS_StorageIM::IndexPrimitivesMulti(class RAS_MeshSlot& ms)
-{
- IndexPrimitivesInternal(ms, true);
-}
-
-void RAS_StorageIM::TexCoord(const RAS_TexVert &tv)
-{
- int unit;
-
- if (GLEW_ARB_multitexture) {
- for (unit = 0; unit < *m_texco_num; unit++) {
- switch (m_texco[unit]) {
- case RAS_IRasterizer::RAS_TEXCO_ORCO:
- case RAS_IRasterizer::RAS_TEXCO_GLOB:
- glMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, tv.getXYZ());
- break;
- case RAS_IRasterizer::RAS_TEXCO_UV:
- glMultiTexCoord2fvARB(GL_TEXTURE0_ARB + unit, tv.getUV(unit));
- break;
- case RAS_IRasterizer::RAS_TEXCO_NORM:
- glMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, tv.getNormal());
- break;
- case RAS_IRasterizer::RAS_TEXTANGENT:
- glMultiTexCoord4fvARB(GL_TEXTURE0_ARB + unit, tv.getTangent());
- break;
- default:
- break;
- }
- }
- }
-
- if (GLEW_ARB_vertex_program) {
- for (unit = 0; unit < *m_attrib_num; unit++) {
- switch (m_attrib[unit]) {
- case RAS_IRasterizer::RAS_TEXCO_ORCO:
- case RAS_IRasterizer::RAS_TEXCO_GLOB:
- glVertexAttrib3fvARB(unit, tv.getXYZ());
- break;
- case RAS_IRasterizer::RAS_TEXCO_UV:
- glVertexAttrib2fvARB(unit, tv.getUV(m_attrib_layer[unit]));
- break;
- case RAS_IRasterizer::RAS_TEXCO_NORM:
- glVertexAttrib3fvARB(unit, tv.getNormal());
- break;
- case RAS_IRasterizer::RAS_TEXTANGENT:
- glVertexAttrib4fvARB(unit, tv.getTangent());
- break;
- case RAS_IRasterizer::RAS_TEXCO_VCOL:
- glVertexAttrib4ubvARB(unit, tv.getRGBA());
- break;
- default:
- break;
- }
- }
- }
-
-}
-
-void RAS_StorageIM::SetCullFace(bool enable)
-{
- if (enable)
- glEnable(GL_CULL_FACE);
- else
- glDisable(GL_CULL_FACE);
-}
-
-static bool current_wireframe;
-static RAS_MaterialBucket *current_bucket;
-static RAS_IPolyMaterial *current_polymat;
-static RAS_MeshSlot *current_ms;
-static RAS_MeshObject *current_mesh;
-static int current_blmat_nr;
-static GPUVertexAttribs current_gpu_attribs;
-static Image *current_image;
-static int CheckMaterialDM(int matnr, void *attribs)
-{
- // only draw the current material
- if (matnr != current_blmat_nr)
- return 0;
- GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs;
- if (gattribs)
- memcpy(gattribs, &current_gpu_attribs, sizeof(GPUVertexAttribs));
- return 1;
-}
-
-/*
-static int CheckTexfaceDM(void *mcol, int index)
-{
-
- // index is the original face index, retrieve the polygon
- RAS_Polygon* polygon = (index >= 0 && index < current_mesh->NumPolygons()) ?
- current_mesh->GetPolygon(index) : NULL;
- if (polygon && polygon->GetMaterial() == current_bucket) {
- // must handle color.
- if (current_wireframe)
- return 2;
- if (current_ms->m_bObjectColor) {
- MT_Vector4& rgba = current_ms->m_RGBAcolor;
- glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
- // don't use mcol
- return 2;
- }
- if (!mcol) {
- // we have to set the color from the material
- unsigned char rgba[4];
- current_polymat->GetMaterialRGBAColor(rgba);
- glColor4ubv((const GLubyte *)rgba);
- return 2;
- }
- return 1;
- }
- return 0;
-}
-*/
-
-static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr)
-{
-
- // index is the original face index, retrieve the polygon
- if (matnr == current_blmat_nr &&
- (mtexpoly == NULL || mtexpoly->tpage == current_image)) {
- // must handle color.
- if (current_wireframe)
- return DM_DRAW_OPTION_NO_MCOL;
- if (current_ms->m_bObjectColor) {
- MT_Vector4& rgba = current_ms->m_RGBAcolor;
- glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
- // don't use mcol
- return DM_DRAW_OPTION_NO_MCOL;
- }
- if (!has_mcol) {
- // we have to set the color from the material
- unsigned char rgba[4];
- current_polymat->GetMaterialRGBAColor(rgba);
- glColor4ubv((const GLubyte *)rgba);
- return DM_DRAW_OPTION_NO_MCOL;
- }
- return DM_DRAW_OPTION_NORMAL;
- }
- return DM_DRAW_OPTION_SKIP;
-}
-
-void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
-{
- bool obcolor = ms.m_bObjectColor;
- bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME;
- MT_Vector4& rgba = ms.m_RGBAcolor;
- RAS_MeshSlot::iterator it;
-
- if (ms.m_pDerivedMesh) {
- // mesh data is in derived mesh,
- current_bucket = ms.m_bucket;
- current_polymat = current_bucket->GetPolyMaterial();
- current_ms = &ms;
- current_mesh = ms.m_mesh;
- current_wireframe = wireframe;
- // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */
-
- // handle two-side
- if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL)
- this->SetCullFace(true);
- else
- this->SetCullFace(false);
-
- if (current_polymat->GetFlag() & RAS_BLENDERGLSL) {
- // GetMaterialIndex return the original mface material index,
- // increment by 1 to match what derived mesh is doing
- current_blmat_nr = current_polymat->GetMaterialIndex()+1;
- // For GLSL we need to retrieve the GPU material attribute
- Material* blmat = current_polymat->GetBlenderMaterial();
- Scene* blscene = current_polymat->GetBlenderScene();
- if (!wireframe && blscene && blmat)
- GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat, false), &current_gpu_attribs);
- else
- memset(&current_gpu_attribs, 0, sizeof(current_gpu_attribs));
- // DM draw can mess up blending mode, restore at the end
- int current_blend_mode = GPU_get_material_alpha_blend();
- ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM);
- GPU_set_material_alpha_blend(current_blend_mode);
- } else {
- //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol);
- current_blmat_nr = current_polymat->GetMaterialIndex();
- current_image = current_polymat->GetBlenderImage();
- ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV);
- }
- return;
- }
- // iterate over display arrays, each containing an index + vertex array
- for (ms.begin(it); !ms.end(it); ms.next(it)) {
- RAS_TexVert *vertex;
- size_t i, j, numvert;
-
- numvert = it.array->m_type;
-
- if (it.array->m_type == RAS_DisplayArray::LINE) {
- // line drawing
- glBegin(GL_LINES);
-
- for (i = 0; i < it.totindex; i += 2)
- {
- vertex = &it.vertex[it.index[i]];
- glVertex3fv(vertex->getXYZ());
-
- vertex = &it.vertex[it.index[i+1]];
- glVertex3fv(vertex->getXYZ());
- }
-
- glEnd();
- }
- else {
- // triangle and quad drawing
- if (it.array->m_type == RAS_DisplayArray::TRIANGLE)
- glBegin(GL_TRIANGLES);
- else
- glBegin(GL_QUADS);
-
- for (i = 0; i < it.totindex; i += numvert)
- {
- if (obcolor)
- glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
-
- for (j = 0; j < numvert; j++) {
- vertex = &it.vertex[it.index[i+j]];
-
- if (!wireframe) {
- if (!obcolor)
- glColor4ubv((const GLubyte *)(vertex->getRGBA()));
-
- glNormal3fv(vertex->getNormal());
-
- if (multi)
- TexCoord(*vertex);
- else
- glTexCoord2fv(vertex->getUV(0));
- }
-
- glVertex3fv(vertex->getXYZ());
- }
- }
-
- glEnd();
- }
- }
-}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h
deleted file mode 100644
index 54ba2a57b61..00000000000
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __KX_IMMEDIATEMODESTORAGE
-#define __KX_IMMEDIATEMODESTORAGE
-
-#include "RAS_IStorage.h"
-#include "RAS_IRasterizer.h"
-
-class RAS_StorageIM : public RAS_IStorage
-{
-public:
- RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer);
- virtual ~RAS_StorageIM();
-
- virtual bool Init();
- virtual void Exit();
-
- virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms);
-
- virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
-
-protected:
- int m_drawingmode;
- int* m_texco_num;
- int* m_attrib_num;
- RAS_IRasterizer::TexCoGen* m_texco;
- RAS_IRasterizer::TexCoGen* m_attrib;
- int* m_attrib_layer;
-
- void TexCoord(const RAS_TexVert &tv);
- void SetCullFace(bool enable);
-
- void IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi);
-
-
-#ifdef WITH_CXX_GUARDEDALLOC
-public:
- void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_StorageIM"); }
- void operator delete( void *mem ) { MEM_freeN(mem); }
-#endif
-};
-
-#endif //__KX_IMMEDIATEMODESTORAGE
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
index c2980a6c15f..cf77ebfbeb9 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
@@ -56,68 +56,7 @@ void RAS_StorageVA::Exit()
{
}
-void RAS_StorageVA::IndexPrimitives(RAS_MeshSlot& ms)
-{
- static const GLsizei stride = sizeof(RAS_TexVert);
- bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME;
- RAS_MeshSlot::iterator it;
- GLenum drawmode;
-
- if (!wireframe)
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_NORMAL_ARRAY);
-
- // use glDrawElements to draw each vertexarray
- for (ms.begin(it); !ms.end(it); ms.next(it)) {
- if (it.totindex == 0)
- continue;
-
- // drawing mode
- if (it.array->m_type == RAS_DisplayArray::TRIANGLE)
- drawmode = GL_TRIANGLES;
- else if (it.array->m_type == RAS_DisplayArray::QUAD)
- drawmode = GL_QUADS;
- else
- drawmode = GL_LINES;
-
- // colors
- if (drawmode != GL_LINES && !wireframe) {
- if (ms.m_bObjectColor) {
- const MT_Vector4& rgba = ms.m_RGBAcolor;
-
- glDisableClientState(GL_COLOR_ARRAY);
- glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]);
- }
- else {
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
- glEnableClientState(GL_COLOR_ARRAY);
- }
- }
- else
- glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
-
- glVertexPointer(3, GL_FLOAT, stride, it.vertex->getXYZ());
- glNormalPointer(GL_FLOAT, stride, it.vertex->getNormal());
- if (!wireframe) {
- glTexCoordPointer(2, GL_FLOAT, stride, it.vertex->getUV(0));
- if (glIsEnabled(GL_COLOR_ARRAY))
- glColorPointer(4, GL_UNSIGNED_BYTE, stride, it.vertex->getRGBA());
- }
-
- // here the actual drawing takes places
- glDrawElements(drawmode, it.totindex, GL_UNSIGNED_SHORT, it.index);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_NORMAL_ARRAY);
- if (!wireframe) {
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- }
-}
-
-void RAS_StorageVA::IndexPrimitivesMulti(class RAS_MeshSlot& ms)
+void RAS_StorageVA::IndexPrimitives(class RAS_MeshSlot& ms)
{
static const GLsizei stride = sizeof(RAS_TexVert);
bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME, use_color_array = true;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
index e4d00310a11..34fdca23ee6 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
@@ -44,7 +44,6 @@ public:
virtual void Exit();
virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms);
virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
index 58f3d4c05da..cad5b5a508e 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
@@ -80,7 +80,7 @@ void VBO::UpdateIndices()
&data->m_index[0], GL_STATIC_DRAW);
}
-void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer, bool multi)
+void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer)
{
int unit;
@@ -100,41 +100,32 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_UNSIGNED_BYTE, this->stride, this->color_offset);
- if (multi)
+ for (unit = 0; unit < texco_num; ++unit)
{
- for (unit = 0; unit < texco_num; ++unit)
- {
- glClientActiveTexture(GL_TEXTURE0_ARB + unit);
- switch (texco[unit]) {
- case RAS_IRasterizer::RAS_TEXCO_ORCO:
- case RAS_IRasterizer::RAS_TEXCO_GLOB:
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(3, GL_FLOAT, this->stride, this->vertex_offset);
- break;
- case RAS_IRasterizer::RAS_TEXCO_UV:
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, this->stride, (void*)((intptr_t)this->uv_offset+(sizeof(GLfloat)*2*unit)));
- break;
- case RAS_IRasterizer::RAS_TEXCO_NORM:
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(3, GL_FLOAT, this->stride, this->normal_offset);
- break;
- case RAS_IRasterizer::RAS_TEXTANGENT:
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(4, GL_FLOAT, this->stride, this->tangent_offset);
- break;
- default:
- break;
- }
+ glClientActiveTexture(GL_TEXTURE0_ARB + unit);
+ switch (texco[unit]) {
+ case RAS_IRasterizer::RAS_TEXCO_ORCO:
+ case RAS_IRasterizer::RAS_TEXCO_GLOB:
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(3, GL_FLOAT, this->stride, this->vertex_offset);
+ break;
+ case RAS_IRasterizer::RAS_TEXCO_UV:
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, this->stride, (void*)((intptr_t)this->uv_offset+(sizeof(GLfloat)*2*unit)));
+ break;
+ case RAS_IRasterizer::RAS_TEXCO_NORM:
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(3, GL_FLOAT, this->stride, this->normal_offset);
+ break;
+ case RAS_IRasterizer::RAS_TEXTANGENT:
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(4, GL_FLOAT, this->stride, this->tangent_offset);
+ break;
+ default:
+ break;
}
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- }
- else //TexFace
- {
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, this->stride, this->uv_offset);
}
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
if (GLEW_ARB_vertex_program)
{
@@ -163,7 +154,7 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
}
}
}
-
+
glDrawElements(this->mode, this->indices, GL_UNSIGNED_SHORT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
@@ -202,21 +193,16 @@ bool RAS_StorageVBO::Init()
void RAS_StorageVBO::Exit()
{
+ VBOMap::iterator it = m_vbo_lookup.begin();
+ while (it != m_vbo_lookup.end()) {
+ delete it->second;
+ ++it;
+ }
m_vbo_lookup.clear();
}
void RAS_StorageVBO::IndexPrimitives(RAS_MeshSlot& ms)
{
- IndexPrimitivesInternal(ms, false);
-}
-
-void RAS_StorageVBO::IndexPrimitivesMulti(RAS_MeshSlot& ms)
-{
- IndexPrimitivesInternal(ms, true);
-}
-
-void RAS_StorageVBO::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
-{
RAS_MeshSlot::iterator it;
VBO *vbo;
@@ -233,6 +219,6 @@ void RAS_StorageVBO::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
vbo->UpdateData();
}
- vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer, multi);
+ vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer);
}
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index f156722247c..9cb3449bed5 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
@@ -42,7 +42,7 @@ public:
VBO(RAS_DisplayArray *data, unsigned int indices);
~VBO();
- void Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer, bool multi);
+ void Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer);
void UpdateData();
void UpdateIndices();
@@ -62,6 +62,8 @@ private:
void* uv_offset;
};
+typedef std::map<RAS_DisplayArray*, VBO*> VBOMap;
+
class RAS_StorageVBO : public RAS_IStorage
{
@@ -73,7 +75,6 @@ public:
virtual void Exit();
virtual void IndexPrimitives(RAS_MeshSlot& ms);
- virtual void IndexPrimitivesMulti(RAS_MeshSlot& ms);
virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;};
@@ -87,9 +88,7 @@ protected:
RAS_IRasterizer::TexCoGen* m_attrib;
int* m_attrib_layer;
- std::map<RAS_DisplayArray*, class VBO*> m_vbo_lookup;
-
- virtual void IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi);
+ VBOMap m_vbo_lookup;
#ifdef WITH_CXX_GUARDEDALLOC
public:
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
deleted file mode 100644
index ce520df2a21..00000000000
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/python
-Import ('env')
-
-sources = env.Glob('*.cpp')
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-incs = [
- '.',
- '#intern/container',
- '#intern/guardedalloc',
- '#intern/string',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#intern/moto/include',
- '#source/blender/blenkernel',
- '#source/blender/blenfont',
- '#source/blender/blenlib',
- '#source/blender/gpu',
- '#source/blender/makesdna',
- '#source/gameengine/BlenderRoutines',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Physics/common',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/SceneGraph',
- '#source/gameengine/Ketsji',
- env['BF_OPENGL_INC'],
- ]
-incs = ' '.join(incs)
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-env.BlenderLib ( 'ge_oglrasterizer', Split(sources), Split(incs), defines = defs, libtype=['core','player'], priority=[350,75], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Rasterizer/RAS_TexVert.cpp b/source/gameengine/Rasterizer/RAS_TexVert.cpp
index e6edc064200..2e176360d61 100644
--- a/source/gameengine/Rasterizer/RAS_TexVert.cpp
+++ b/source/gameengine/Rasterizer/RAS_TexVert.cpp
@@ -66,10 +66,10 @@ const MT_Point3& RAS_TexVert::xyz()
void RAS_TexVert::SetRGBA(const MT_Vector4& rgba)
{
unsigned char *colp = (unsigned char*) &m_rgba;
- colp[0] = (unsigned char) (rgba[0] * 255.0);
- colp[1] = (unsigned char) (rgba[1] * 255.0);
- colp[2] = (unsigned char) (rgba[2] * 255.0);
- colp[3] = (unsigned char) (rgba[3] * 255.0);
+ colp[0] = (unsigned char) (rgba[0] * 255.0f);
+ colp[1] = (unsigned char) (rgba[1] * 255.0f);
+ colp[2] = (unsigned char) (rgba[2] * 255.0f);
+ colp[3] = (unsigned char) (rgba[3] * 255.0f);
}
@@ -153,12 +153,12 @@ unsigned int RAS_TexVert::getUnit() const
void RAS_TexVert::Transform(const MT_Matrix4x4& mat, const MT_Matrix4x4& nmat)
{
- SetXYZ((mat * MT_Vector4(m_localxyz[0], m_localxyz[1], m_localxyz[2], 1.0)).getValue());
- SetNormal((nmat * MT_Vector4(m_normal[0], m_normal[1], m_normal[2], 1.0)).getValue());
- SetTangent((nmat * MT_Vector4(m_tangent[0], m_tangent[1], m_tangent[2], 1.0)).getValue());
+ SetXYZ((mat * MT_Vector4(m_localxyz[0], m_localxyz[1], m_localxyz[2], 1.0f)).getValue());
+ SetNormal((nmat * MT_Vector4(m_normal[0], m_normal[1], m_normal[2], 1.0f)).getValue());
+ SetTangent((nmat * MT_Vector4(m_tangent[0], m_tangent[1], m_tangent[2], 1.0f)).getValue());
}
void RAS_TexVert::TransformUV(int index, const MT_Matrix4x4& mat)
{
- SetUV(index, (mat * MT_Vector4(m_uvs[index][0], m_uvs[index][1], 0.0, 1.0)).getValue());
+ SetUV(index, (mat * MT_Vector4(m_uvs[index][0], m_uvs[index][1], 0.0f, 1.0f)).getValue());
}
diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript
deleted file mode 100644
index a643f46e39a..00000000000
--- a/source/gameengine/Rasterizer/SConscript
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-
-incs = [
- '.',
- '#intern/guardedalloc',
- '#intern/string',
- '#intern/moto/include',
- '#intern/container',
- '#source/gameengine/BlenderRoutines',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#source/gameengine/Expressions',
- '#source/gameengine/SceneGraph',
- '#source/blender/blenlib',
- '#source/blender/blenkernel',
- '#source/blender/gpu',
- '#source/blender/makesdna',
- ]
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['WITH_BF_PYTHON']:
- incs.extend(Split(env['BF_PYTHON_INC']))
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
-
-env.BlenderLib('ge_rasterizer', sources,
- includes=incs, defines=defs,
- libtype=['core', 'player'], priority=[350, 70],
- cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/SConscript b/source/gameengine/SConscript
deleted file mode 100644
index ae1bb756f8e..00000000000
--- a/source/gameengine/SConscript
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-SConscript(['BlenderRoutines/SConscript',
- 'Converter/SConscript',
- 'Expressions/SConscript', #310
- 'GameLogic/SConscript',
- 'Ketsji/SConscript',
- 'Ketsji/KXNetwork/SConscript',
- 'Network/SConscript',
- 'Network/LoopBackNetwork/SConscript',
- 'Physics/Dummy/SConscript',
- 'Rasterizer/SConscript',
- 'Rasterizer/RAS_OpenGLRasterizer/SConscript',
- 'SceneGraph/SConscript',
- ])
-
-if env['WITH_BF_PYTHON']:
- SConscript(['VideoTexture/SConscript'])
-
-if env['WITH_BF_PLAYER']:
- SConscript(['GamePlayer/SConscript'])
-
-if env['WITH_BF_BULLET']:
- SConscript(['Physics/Bullet/SConscript'])
diff --git a/source/gameengine/SceneGraph/SConscript b/source/gameengine/SceneGraph/SConscript
deleted file mode 100644
index f6e73a902a4..00000000000
--- a/source/gameengine/SceneGraph/SConscript
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-
-incs = [
- '.',
- '#intern/moto/include',
- ]
-
-defs = []
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
- incs.append('#intern/guardedalloc')
-
-if env['WITH_BF_PYTHON']:
- defs.append('WITH_PYTHON')
- incs.extend(Split(env['BF_PYTHON_INC']))
-
-env.BlenderLib('ge_scenegraph', sources, incs, defs, libtype=['core', 'player'], priority=[325, 85], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/SceneGraph/SG_BBox.cpp b/source/gameengine/SceneGraph/SG_BBox.cpp
index 0ecf6284a14..f9d83d37384 100644
--- a/source/gameengine/SceneGraph/SG_BBox.cpp
+++ b/source/gameengine/SceneGraph/SG_BBox.cpp
@@ -37,8 +37,8 @@
#include "SG_Node.h"
SG_BBox::SG_BBox() :
- m_min(0.0, 0.0, 0.0),
- m_max(0.0, 0.0, 0.0)
+ m_min(0.0f, 0.0f, 0.0f),
+ m_max(0.0f, 0.0f, 0.0f)
{
}
@@ -209,11 +209,11 @@ void SG_BBox::split(SG_BBox &left, SG_BBox &right) const
{
left.m_min = m_min;
left.m_max[0] = m_max[0];
- left.m_max[1] = m_min[1] + sizey/2.0;
+ left.m_max[1] = m_min[1] + sizey/2.0f;
left.m_max[2] = m_max[2];
right.m_min[0] = m_min[0];
- right.m_min[1] = m_min[1] + sizey/2.0;
+ right.m_min[1] = m_min[1] + sizey/2.0f;
right.m_min[2] = m_min[2];
right.m_max = m_max;
std::cout << "splity" << std::endl;
@@ -222,11 +222,11 @@ void SG_BBox::split(SG_BBox &left, SG_BBox &right) const
left.m_min = m_min;
left.m_max[0] = m_max[0];
left.m_max[1] = m_max[1];
- left.m_max[2] = m_min[2] + sizez/2.0;
+ left.m_max[2] = m_min[2] + sizez/2.0f;
right.m_min[0] = m_min[0];
right.m_min[1] = m_min[1];
- right.m_min[2] = m_min[2] + sizez/2.0;
+ right.m_min[2] = m_min[2] + sizez/2.0f;
right.m_max = m_max;
std::cout << "splitz" << std::endl;
}
@@ -234,11 +234,11 @@ void SG_BBox::split(SG_BBox &left, SG_BBox &right) const
else {
if (sizex > sizez) {
left.m_min = m_min;
- left.m_max[0] = m_min[0] + sizex/2.0;
+ left.m_max[0] = m_min[0] + sizex/2.0f;
left.m_max[1] = m_max[1];
left.m_max[2] = m_max[2];
- right.m_min[0] = m_min[0] + sizex/2.0;
+ right.m_min[0] = m_min[0] + sizex/2.0f;
right.m_min[1] = m_min[1];
right.m_min[2] = m_min[2];
right.m_max = m_max;
@@ -248,11 +248,11 @@ void SG_BBox::split(SG_BBox &left, SG_BBox &right) const
left.m_min = m_min;
left.m_max[0] = m_max[0];
left.m_max[1] = m_max[1];
- left.m_max[2] = m_min[2] + sizez/2.0;
+ left.m_max[2] = m_min[2] + sizez/2.0f;
right.m_min[0] = m_min[0];
right.m_min[1] = m_min[1];
- right.m_min[2] = m_min[2] + sizez/2.0;
+ right.m_min[2] = m_min[2] + sizez/2.0f;
right.m_max = m_max;
std::cout << "splitz" << std::endl;
}
diff --git a/source/gameengine/SceneGraph/SG_BBox.h b/source/gameengine/SceneGraph/SG_BBox.h
index cd1c523ff40..3c524dc7f18 100644
--- a/source/gameengine/SceneGraph/SG_BBox.h
+++ b/source/gameengine/SceneGraph/SG_BBox.h
@@ -81,7 +81,7 @@ public:
/**
* Scales the bounding box about the optional point.
*/
- void scale(const MT_Vector3 &size, const MT_Point3 &point = MT_Point3(0.0, 0.0, 0.0));
+ void scale(const MT_Vector3 &size, const MT_Point3 &point = MT_Point3(0.0f, 0.0f, 0.0f));
#endif
SG_BBox transform(const MT_Transform &world) const;
/**
diff --git a/source/gameengine/SceneGraph/SG_Spatial.cpp b/source/gameengine/SceneGraph/SG_Spatial.cpp
index f30c80da434..5cb75873237 100644
--- a/source/gameengine/SceneGraph/SG_Spatial.cpp
+++ b/source/gameengine/SceneGraph/SG_Spatial.cpp
@@ -43,18 +43,18 @@ SG_Spatial(
):
SG_IObject(clientobj,clientinfo,callbacks),
- m_localPosition(0.0,0.0,0.0),
- m_localRotation(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0),
- m_localScaling(1.f,1.f,1.f),
+ m_localPosition(0.0f,0.0f,0.0f),
+ m_localRotation(1.0f,0.0f,0.0f,0.0f,1.0f,0.0f,0.0f,0.0f,1.0f),
+ m_localScaling(1.0f,1.0f,1.0f),
- m_worldPosition(0.0,0.0,0.0),
- m_worldRotation(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0),
- m_worldScaling(1.f,1.f,1.f),
+ m_worldPosition(0.0f,0.0f,0.0f),
+ m_worldRotation(1.0f,0.0f,0.0f,0.0f,1.0f,0.0f,0.0f,0.0f,1.0f),
+ m_worldScaling(1.0f,1.0f,1.0f),
m_parent_relation (NULL),
- m_bbox(MT_Point3(-1.0, -1.0, -1.0), MT_Point3(1.0, 1.0, 1.0)),
- m_radius(1.0),
+ m_bbox(MT_Point3(-1.0f, -1.0f, -1.0f), MT_Point3(1.0f, 1.0f, 1.0f)),
+ m_radius(1.0f),
m_modified(false),
m_ogldirty(false)
{
diff --git a/source/gameengine/SceneGraph/SG_Tree.cpp b/source/gameengine/SceneGraph/SG_Tree.cpp
index bef246533a6..87feb2c012a 100644
--- a/source/gameengine/SceneGraph/SG_Tree.cpp
+++ b/source/gameengine/SceneGraph/SG_Tree.cpp
@@ -41,7 +41,7 @@ SG_Tree::SG_Tree() :
m_left(NULL),
m_right(NULL),
m_parent(NULL),
- m_radius(0.0),
+ m_radius(0.0f),
m_client_object(NULL)
{
}
@@ -62,7 +62,7 @@ SG_Tree::SG_Tree(SG_Tree* left, SG_Tree* right) :
m_bbox += m_right->m_bbox;
m_right->m_parent = this;
}
- m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0f;
m_radius = (m_bbox.m_max - m_bbox.m_min).length();
}
@@ -73,7 +73,7 @@ SG_Tree::SG_Tree(SG_Node* client) :
m_client_object(client)
{
m_bbox = SG_BBox(client->BBox(), client->GetWorldTransform());
- m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0f;
m_radius = (m_bbox.m_max - m_bbox.m_min).length();
}
@@ -162,7 +162,7 @@ void SG_Tree::SetLeft(SG_Tree *left)
{
m_left = left;
m_bbox += left->m_bbox;
- m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0f;
m_radius = (m_bbox.m_max - m_bbox.m_min).length();
}
@@ -170,7 +170,7 @@ void SG_Tree::SetRight(SG_Tree *right)
{
m_right = right;
m_bbox += right->m_bbox;
- m_center = (m_bbox.m_min + m_bbox.m_max)/2.0;
+ m_center = (m_bbox.m_min + m_bbox.m_max)/2.0f;
m_radius = (m_bbox.m_max - m_bbox.m_min).length();
}
@@ -263,7 +263,7 @@ SG_Tree* SG_TreeFactory::MakeTreeDown(SG_BBox &bbox)
return root;
}
- if (bbox.volume() < 1.0)
+ if (bbox.volume() < 1.0f)
return MakeTreeUp();
SG_TreeFactory lefttree;
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index 9086b042537..a374fbba2df 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -141,14 +141,14 @@ void ImageRender::calcImage (unsigned int texId, double ts)
void ImageRender::Render()
{
- RAS_FrameFrustum frustrum;
+ RAS_FrameFrustum frustum;
if (!m_render)
return;
if (m_mirror)
{
- // mirror mode, compute camera frustrum, position and orientation
+ // mirror mode, compute camera frustum, position and orientation
// convert mirror position and normal in world space
const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation();
const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition();
@@ -177,7 +177,7 @@ void ImageRender::Render()
mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]);
m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri);
m_camera->GetSGNode()->UpdateWorldData(0.0);
- // compute camera frustrum:
+ // compute camera frustum:
// get position of mirror relative to camera: offset = mirrorPos-cameraPos
MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos;
// convert to camera orientation
@@ -203,12 +203,12 @@ void ImageRender::Render()
// bottom = offsety-height
// near = -offsetz
// far = near+100
- frustrum.x1 = mirrorOffset[0]-width;
- frustrum.x2 = mirrorOffset[0]+width;
- frustrum.y1 = mirrorOffset[1]-height;
- frustrum.y2 = mirrorOffset[1]+height;
- frustrum.camnear = -mirrorOffset[2];
- frustrum.camfar = -mirrorOffset[2]+m_clip;
+ frustum.x1 = mirrorOffset[0]-width;
+ frustum.x2 = mirrorOffset[0]+width;
+ frustum.y1 = mirrorOffset[1]-height;
+ frustum.y2 = mirrorOffset[1]+height;
+ frustum.camnear = -mirrorOffset[2];
+ frustum.camfar = -mirrorOffset[2]+m_clip;
}
// Store settings to be restored later
const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode();
@@ -226,10 +226,10 @@ void ImageRender::Render()
m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO);
if (m_mirror)
{
- // frustrum was computed above
- // get frustrum matrix and set projection matrix
+ // frustum was computed above
+ // get frustum matrix and set projection matrix
MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix(
- frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
+ frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar);
m_camera->SetProjectionMatrix(projmat);
}
@@ -264,11 +264,11 @@ void ImageRender::Render()
m_camera->GetSensorFit(),
shift_x,
shift_y,
- frustrum
+ frustum
);
projmat = m_rasterizer->GetOrthoMatrix(
- frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
+ frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar);
}
else {
RAS_FramingManager::ComputeDefaultFrustum(
@@ -281,10 +281,10 @@ void ImageRender::Render()
shift_x,
shift_y,
aspect_ratio,
- frustrum);
+ frustum);
projmat = m_rasterizer->GetFrustumMatrix(
- frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar);
+ frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar);
}
m_camera->SetProjectionMatrix(projmat);
}
@@ -548,7 +548,7 @@ static int ImageMirror_init(PyObject *pySelf, PyObject *args, PyObject *kwds)
exp.report();
return -1;
}
- // initialization succeded
+ // initialization succeeded
return 0;
}
@@ -607,7 +607,7 @@ ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObjec
m_clip(100.f)
{
// this constructor is used for automatic planar mirror
- // create a camera, take all data by default, in any case we will recompute the frustrum on each frame
+ // create a camera, take all data by default, in any case we will recompute the frustum on each frame
RAS_CameraData camdata;
vector<RAS_TexVert*> mirrorVerts;
vector<RAS_TexVert*>::iterator it;
@@ -641,7 +641,7 @@ ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObjec
RAS_TexVert *v1, *v2, *v3, *v4;
float normal[3];
float area;
- // this polygon is part of the mirror,
+ // this polygon is part of the mirror
v1 = polygon->GetVertex(0);
v2 = polygon->GetVertex(1);
v3 = polygon->GetVertex(2);
diff --git a/source/gameengine/VideoTexture/PyTypeList.h b/source/gameengine/VideoTexture/PyTypeList.h
index a8716e72e14..ce0eb81e656 100644
--- a/source/gameengine/VideoTexture/PyTypeList.h
+++ b/source/gameengine/VideoTexture/PyTypeList.h
@@ -66,7 +66,11 @@ public:
protected:
/// pointer to list of types
+#if (__cplusplus > 199711L) /* || (defined(_MSC_VER) && _MSC_VER >= 1800) */
+ std::unique_ptr<PyTypeListType> m_list;
+#else
std::auto_ptr<PyTypeListType> m_list;
+#endif
};
diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript
deleted file mode 100644
index dc708904309..00000000000
--- a/source/gameengine/VideoTexture/SConscript
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-import sys
-
-Import ('env')
-
-sources = env.Glob('*.cpp')
-
-incs = [
- '.',
- '#intern/container',
- '#intern/ffmpeg',
- '#intern/guardedalloc',
- '#intern/string',
- env['BF_GLEW_INC'],
- '#/intern/glew-mx',
- '#intern/moto/include',
- '#source/blender/blenkernel',
- '#source/blender/blenlib',
- '#source/blender/gpu',
- '#source/blender/imbuf',
- '#source/blender/makesdna',
- '#source/blender/python',
- '#source/gameengine/BlenderRoutines',
- '#source/gameengine/Expressions',
- '#source/gameengine/GameLogic',
- '#source/gameengine/Ketsji',
- '#source/gameengine/Rasterizer',
- '#source/gameengine/SceneGraph',
- '#source/blender/editors/include',
- '#source/blender/python/generic',
- '#source/gameengine/Rasterizer/RAS_OpenGLRasterizer',
- ]
-incs = ' '.join(incs)
-
-defs = []
-defs += env['BF_GL_DEFINITIONS']
-
-if env['OURPLATFORM'] in ('win32-vc', 'win64-vc','win32-mingw', 'win64-mingw'):
- if env['BF_DEBUG']:
- defs.append('_DEBUG')
-
-if env['WITH_BF_PYTHON']:
- incs += ' ' + env['BF_PYTHON_INC']
- defs.append('WITH_PYTHON')
-
-if env['WITH_BF_FFMPEG']:
- defs.append('WITH_FFMPEG')
- incs += ' ' + env['BF_FFMPEG_INC'] + ' ' + env['BF_PTHREADS_INC']
-
-env.BlenderLib ( 'ge_videotex', sources, Split(incs), defs, libtype=['core','player'], priority=[340,205], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index cc010f08b17..f1c7bc303ee 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -299,7 +299,7 @@ PyObject *Texture_close(Texture * self)
self->m_matTexture->swapTexture(self->m_orgTex);
else
{
- self->m_imgTexture->bindcode = self->m_orgTex;
+ self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_orgTex;
BKE_image_release_ibuf(self->m_imgTexture, self->m_imgBuf, NULL);
self->m_imgBuf = NULL;
}
@@ -357,8 +357,8 @@ static PyObject *Texture_refresh(Texture *self, PyObject *args)
// WARNING: GPU has a ImageUser to pass, we don't. Using NULL
// works on image file, not necessarily on other type of image.
self->m_imgBuf = BKE_image_acquire_ibuf(self->m_imgTexture, NULL, NULL);
- self->m_orgTex = self->m_imgTexture->bindcode;
- self->m_imgTexture->bindcode = self->m_actTex;
+ self->m_orgTex = self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D];
+ self->m_imgTexture->bindcode[TEXTARGET_TEXTURE_2D] = self->m_actTex;
}
}
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
index ffe06cff100..5fed1211d6c 100644
--- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -34,7 +34,10 @@
// INT64_C fix for some linux machines (C99ism)
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
+#ifdef __STDC_CONSTANT_MACROS /* quiet warning */
#endif
+#endif
+
#include <stdint.h>
@@ -49,8 +52,6 @@
// default framerate
const double defFrameRate = 25.0;
-// time scale constant
-const long timeScale = 1000;
// macro for exception handling and logging
#define CATCH_EXCP catch (Exception & exp) \
@@ -140,23 +141,23 @@ bool VideoFFmpeg::release()
AVFrame *VideoFFmpeg::allocFrameRGB()
{
AVFrame *frame;
- frame = avcodec_alloc_frame();
+ frame = av_frame_alloc();
if (m_format == RGBA32)
{
avpicture_fill((AVPicture*)frame,
(uint8_t*)MEM_callocN(avpicture_get_size(
- PIX_FMT_RGBA,
+ AV_PIX_FMT_RGBA,
m_codecCtx->width, m_codecCtx->height),
"ffmpeg rgba"),
- PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height);
+ AV_PIX_FMT_RGBA, m_codecCtx->width, m_codecCtx->height);
} else
{
avpicture_fill((AVPicture*)frame,
(uint8_t*)MEM_callocN(avpicture_get_size(
- PIX_FMT_RGB24,
+ AV_PIX_FMT_RGB24,
m_codecCtx->width, m_codecCtx->height),
"ffmpeg rgb"),
- PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height);
+ AV_PIX_FMT_RGB24, m_codecCtx->width, m_codecCtx->height);
}
return frame;
}
@@ -236,8 +237,8 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
m_codecCtx = codecCtx;
m_formatCtx = formatCtx;
m_videoStream = videoStream;
- m_frame = avcodec_alloc_frame();
- m_frameDeinterlaced = avcodec_alloc_frame();
+ m_frame = av_frame_alloc();
+ m_frameDeinterlaced = av_frame_alloc();
// allocate buffer if deinterlacing is required
avpicture_fill((AVPicture*)m_frameDeinterlaced,
@@ -248,10 +249,10 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height);
// check if the pixel format supports Alpha
- if (m_codecCtx->pix_fmt == PIX_FMT_RGB32 ||
- m_codecCtx->pix_fmt == PIX_FMT_BGR32 ||
- m_codecCtx->pix_fmt == PIX_FMT_RGB32_1 ||
- m_codecCtx->pix_fmt == PIX_FMT_BGR32_1)
+ if (m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32 ||
+ m_codecCtx->pix_fmt == AV_PIX_FMT_BGR32 ||
+ m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32_1 ||
+ m_codecCtx->pix_fmt == AV_PIX_FMT_BGR32_1)
{
// allocate buffer to store final decoded frame
m_format = RGBA32;
@@ -262,7 +263,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
m_codecCtx->pix_fmt,
m_codecCtx->width,
m_codecCtx->height,
- PIX_FMT_RGBA,
+ AV_PIX_FMT_RGBA,
SWS_FAST_BILINEAR,
NULL, NULL, NULL);
} else
@@ -276,7 +277,7 @@ int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AV
m_codecCtx->pix_fmt,
m_codecCtx->width,
m_codecCtx->height,
- PIX_FMT_RGB24,
+ AV_PIX_FMT_RGB24,
SWS_FAST_BILINEAR,
NULL, NULL, NULL);
}
@@ -1026,11 +1027,11 @@ AVFrame *VideoFFmpeg::grabFrame(long position)
AVFrame *input = m_frame;
short counter = 0;
- /* While the data is not read properly (png, tiffs, etc formats may need several pass)*/
- while ((input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) && counter < 10) {
+ /* If m_isImage, while the data is not read properly (png, tiffs, etc formats may need several pass), else don't need while loop*/
+ do {
avcodec_decode_video2(m_codecCtx, m_frame, &frameFinished, &packet);
counter++;
- }
+ } while ((input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) && counter < 10 && m_isImage);
// remember dts to compute exact frame number
dts = packet.dts;
diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp
index 30a8107b558..a62ffee3137 100644
--- a/source/gameengine/VideoTexture/blendVideoTex.cpp
+++ b/source/gameengine/VideoTexture/blendVideoTex.cpp
@@ -32,8 +32,6 @@
#include "KX_PythonInit.h"
-#include <RAS_GLExtensionManager.h>
-
#include <RAS_IPolygonMaterial.h>
//Old API
diff --git a/source/icons/SConscript b/source/icons/SConscript
deleted file mode 100644
index 443f6454417..00000000000
--- a/source/icons/SConscript
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# The Original Code is Copyright (C) 2006, Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): Nathan Letwory.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-Import ('env')
-import btools
-
-env['RCFLAGS'].append("-DWINDRES")
-env['RCFLAGS'].append("-DBLEN_VER_RC_STR_M=" + btools.VERSION)
-env['RCFLAGS'].append("-DBLEN_VER_RC_1=" + btools.VERSION[0])
-env['RCFLAGS'].append("-DBLEN_VER_RC_2=" + btools.VERSION[2])
-env['RCFLAGS'].append("-DBLEN_VER_RC_3=" + btools.VERSION[3])
-env['RCFLAGS'].append("-DBLEN_VER_RC_4=0")
-
-env.BlenderRes('winresource', 'winblender.rc', ['core'], priority=[95])
diff --git a/tests/check_deprecated.py b/tests/check_deprecated.py
index d7193155b1c..cf8f8e0cc35 100644
--- a/tests/check_deprecated.py
+++ b/tests/check_deprecated.py
@@ -24,7 +24,6 @@ from os.path import splitext
DEPRECATE_DAYS = 120
SKIP_DIRS = ("extern",
- "scons",
"tests", # not this dir
)
diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc
new file mode 100644
index 00000000000..e532419691a
--- /dev/null
+++ b/tests/gtests/blenlib/BLI_array_utils_test.cc
@@ -0,0 +1,120 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_array_utils.h"
+}
+
+/* -------------------------------------------------------------------- */
+/* tests */
+
+/* BLI_array_reverse */
+TEST(array_utils, ReverseStringEmpty)
+{
+ char data[] = "";
+ BLI_array_reverse(data, ARRAY_SIZE(data) - 1);
+ EXPECT_STREQ("", data);
+}
+
+TEST(array_utils, ReverseStringSingle)
+{
+ char data[] = "0";
+ BLI_array_reverse(data, ARRAY_SIZE(data) - 1);
+ EXPECT_STREQ("0", data);
+}
+
+TEST(array_utils, ReverseString4)
+{
+ char data[] = "0123";
+ BLI_array_reverse(data, ARRAY_SIZE(data) - 1);
+ EXPECT_STREQ("3210", data);
+}
+
+TEST(array_utils, ReverseInt4)
+{
+ const int data_cmp[] = {3, 2, 1, 0};
+ int data[] = {0, 1, 2, 3};
+ BLI_array_reverse(data, ARRAY_SIZE(data));
+ EXPECT_EQ_ARRAY(data_cmp, data, ARRAY_SIZE(data));
+}
+
+/* BLI_array_findindex */
+TEST(array_utils, FindIndexStringEmpty)
+{
+ char data[] = "", find = '0';
+ EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+}
+
+TEST(array_utils, FindIndexStringSingle)
+{
+ char data[] = "0", find = '0';
+ EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+}
+
+TEST(array_utils, FindIndexStringSingleMissing)
+{
+ char data[] = "1", find = '0';
+ EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+}
+
+TEST(array_utils, FindIndexString4)
+{
+ char data[] = "0123", find = '3';
+ EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+}
+
+TEST(array_utils, FindIndexInt4)
+{
+ int data[] = {0, 1, 2, 3}, find = 2;
+ EXPECT_EQ(2, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find));
+}
+
+/* BLI_array_binary_and */
+#define BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, length) \
+{ \
+ BLI_array_binary_and(data_combine, data_a, data_b, length); \
+ EXPECT_EQ_ARRAY(data_cmp, data_combine, length); \
+} ((void)0)
+
+TEST(array_utils, BinaryAndInt4Zero)
+{
+ const int data_cmp[] = {0, 0, 0, 0};
+ int data_a[] = {0, 1, 0, 1}, data_b[] = {1, 0, 1, 0};
+ int data_combine[ARRAY_SIZE(data_cmp)];
+ BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
+}
+
+TEST(array_utils, BinaryAndInt4Mix)
+{
+ const int data_cmp[] = {1, 0, 1, 0};
+ int data_a[] = {1, 1, 1, 1}, data_b[] = {1, 0, 1, 0};
+ int data_combine[ARRAY_SIZE(data_cmp)];
+ BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
+}
+#undef BINARY_AND_TEST
+
+
+/* BLI_array_binary_or */
+#define BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, length) \
+{ \
+ BLI_array_binary_or(data_combine, data_a, data_b, length); \
+ EXPECT_EQ_ARRAY(data_combine, data_cmp, length); \
+} ((void)0)
+
+TEST(array_utils, BinaryOrInt4Alternate)
+{
+ int data_a[] = {0, 1, 0, 1}, data_b[] = {1, 0, 1, 0}, data_cmp[] = {1, 1, 1, 1};
+ int data_combine[ARRAY_SIZE(data_cmp)];
+ BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
+}
+
+TEST(array_utils, BinaryOrInt4Mix)
+{
+ int data_a[] = {1, 1, 0, 0}, data_b[] = {0, 0, 1, 0}, data_cmp[] = {1, 1, 1, 0};
+ int data_combine[ARRAY_SIZE(data_cmp)];
+ BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
+}
+#undef BINARY_OR_TEST
+
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
index fcee72466b7..709302db021 100644
--- a/tests/gtests/blenlib/BLI_ghash_performance_test.cc
+++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc
@@ -196,6 +196,21 @@ static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr
TIMEIT_END(int_lookup);
}
+ {
+ void *k, *v;
+
+ TIMEIT_START(int_pop);
+
+ GHashIterState pop_state = {0};
+
+ while (BLI_ghash_pop(ghash, &pop_state, &k, &v)) {
+ EXPECT_EQ(k, v);
+ }
+
+ TIMEIT_END(int_pop);
+ }
+ EXPECT_EQ(0, BLI_ghash_size(ghash));
+
BLI_ghash_free(ghash, NULL, NULL);
printf("========== ENDED %s ==========\n\n", id);
@@ -339,7 +354,8 @@ static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nb
{
printf("\n========== STARTING %s ==========\n", id);
- unsigned int (*data)[4] = (unsigned int (*)[4])MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ void *data_v = MEM_mallocN(sizeof(unsigned int[4]) * (size_t)nbr, __func__);
+ unsigned int (*data)[4] = (unsigned int (*)[4])data_v;
unsigned int (*dt)[4];
unsigned int i, j;
diff --git a/tests/gtests/blenlib/BLI_ghash_test.cc b/tests/gtests/blenlib/BLI_ghash_test.cc
index 5fe43d14cbe..ffbe5f5547f 100644
--- a/tests/gtests/blenlib/BLI_ghash_test.cc
+++ b/tests/gtests/blenlib/BLI_ghash_test.cc
@@ -156,3 +156,45 @@ TEST(ghash, Copy)
BLI_ghash_free(ghash, NULL, NULL);
BLI_ghash_free(ghash_copy, NULL, NULL);
}
+
+/* Check pop. */
+TEST(ghash, Pop)
+{
+ GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
+ unsigned int keys[TESTCASE_SIZE], *k;
+ int i;
+
+ BLI_ghash_flag_set(ghash, GHASH_FLAG_ALLOW_SHRINK);
+ init_keys(keys, 30);
+
+ for (i = TESTCASE_SIZE, k = keys; i--; k++) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k));
+ }
+
+ EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash));
+
+ GHashIterState pop_state = {0};
+
+ for (i = TESTCASE_SIZE / 2; i--; ) {
+ void *k, *v;
+ bool success = BLI_ghash_pop(ghash, &pop_state, &k, &v);
+ EXPECT_EQ(k, v);
+ EXPECT_EQ(success, true);
+
+ if (i % 2) {
+ BLI_ghash_insert(ghash, SET_UINT_IN_POINTER(i * 4), SET_UINT_IN_POINTER(i * 4));
+ }
+ }
+
+ EXPECT_EQ((TESTCASE_SIZE - TESTCASE_SIZE / 2 + TESTCASE_SIZE / 4), BLI_ghash_size(ghash));
+
+ {
+ void *k, *v;
+ while (BLI_ghash_pop(ghash, &pop_state, &k, &v)) {
+ EXPECT_EQ(k, v);
+ }
+ }
+ EXPECT_EQ(0, BLI_ghash_size(ghash));
+
+ BLI_ghash_free(ghash, NULL, NULL);
+}
diff --git a/tests/gtests/blenlib/BLI_path_util_test.cc b/tests/gtests/blenlib/BLI_path_util_test.cc
index c4ef7c2c970..c80987c3586 100644
--- a/tests/gtests/blenlib/BLI_path_util_test.cc
+++ b/tests/gtests/blenlib/BLI_path_util_test.cc
@@ -6,6 +6,11 @@ extern "C" {
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "../../../source/blender/imbuf/IMB_imbuf.h"
+
+#ifdef _WIN32
+# include "../../../source/blender/blenkernel/BKE_global.h"
+#endif
+
}
/* -------------------------------------------------------------------- */
@@ -13,6 +18,10 @@ extern "C" {
extern "C" {
+#if _WIN32
+Global G = {0};
+#endif
+
const char *GHOST_getUserDir(int version, const char *versionstr);
const char *GHOST_getSystemDir(int version, const char *versionstr);
#ifdef __linux__
@@ -47,6 +56,7 @@ char *zLhm65070058860608_br_find_exe(const char *default_exe)
/* tests */
/* BLI_cleanup_path */
+#ifndef _WIN32
TEST(path_util, PathUtilClean)
{
/* "/./" -> "/" */
@@ -101,6 +111,7 @@ TEST(path_util, PathUtilClean)
EXPECT_STREQ("/a/b/", path);
}
}
+#endif
/* BLI_path_frame */
TEST(path_util, PathUtilFrame)
diff --git a/tests/gtests/blenlib/BLI_polyfill2d_test.cc b/tests/gtests/blenlib/BLI_polyfill2d_test.cc
index 8ca19b11632..a4ed70fbec9 100644
--- a/tests/gtests/blenlib/BLI_polyfill2d_test.cc
+++ b/tests/gtests/blenlib/BLI_polyfill2d_test.cc
@@ -116,6 +116,7 @@ static void test_polyfill_topology(
EXPECT_EQ(true, ELEM((intptr_t)*p, 1, 2));
}
+ BLI_edgehashIterator_free(ehi);
BLI_edgehash_free(edgehash, NULL);
}
diff --git a/tests/gtests/blenlib/BLI_ressource_strings.h b/tests/gtests/blenlib/BLI_ressource_strings.h
index d7002d748c9..819cf893575 100644
--- a/tests/gtests/blenlib/BLI_ressource_strings.h
+++ b/tests/gtests/blenlib/BLI_ressource_strings.h
@@ -579,6 +579,7 @@ const char words10k[] =
"arcu. Integer ut tellus ac sapien maximus tincidunt sed vitae risus. Nulla viverra, nibh eget eleifend aliquam, quam "
"quam tempor massa, eu semper ipsum lacus in turpis. Nulla sed purus enim. Nullam sed fermentum ipsum. Sed dui nisi, "
"elementum a auctor at, ultrices et nibh. Phasellus aliquam nulla ut lacinia accumsan. Phasellus sed arcu ligula. "
+#ifndef _MSC_VER
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fermentum magna vitae dui sagittis tempor. Vivamus "
"eu ligula blandit, imperdiet arcu at, rutrum sem. Aliquam erat volutpat. Quisque luctus enim quis volutpat lobortis. "
"Vestibulum eget sodales libero. Aenean at condimentum est. Proin eget massa vel nulla efficitur tempor eget at enim. "
@@ -597,6 +598,8 @@ const char words10k[] =
"sit amet porta risus hendrerit non. Aenean id sem nisi. Nullam non nisl vestibulum, pellentesque nisl et, imperdiet "
"ligula. Sed laoreet fringilla felis. Proin ac dolor viverra tellus mollis aliquet eget et neque. Suspendisse mattis "
"nulla vitae nulla sagittis blandit. Sed at tortor rutrum, ornare magna nec, pellentesque nisi. Etiam non aliquet "
-"tellus. Aliquam at ex suscipit, posuere sem sit amet, tincidunt.";
+"tellus. Aliquam at ex suscipit, posuere sem sit amet, tincidunt."
+#endif
+;
#endif /* __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__ */
diff --git a/tests/gtests/blenlib/BLI_stack_test.cc b/tests/gtests/blenlib/BLI_stack_test.cc
index 44956a589dc..4c0b95f4b6b 100644
--- a/tests/gtests/blenlib/BLI_stack_test.cc
+++ b/tests/gtests/blenlib/BLI_stack_test.cc
@@ -116,6 +116,8 @@ TEST(stack, Peek)
}
EXPECT_EQ(BLI_stack_is_empty(stack), true);
+
+ BLI_stack_free(stack);
}
/* Check that clearing the stack leaves in it a correct state. */
diff --git a/tests/gtests/blenlib/BLI_string_test.cc b/tests/gtests/blenlib/BLI_string_test.cc
index fa10e21730b..17a4b5e82b9 100644
--- a/tests/gtests/blenlib/BLI_string_test.cc
+++ b/tests/gtests/blenlib/BLI_string_test.cc
@@ -363,3 +363,106 @@ TEST(string, StrFormatIntGrouped)
BLI_str_format_int_grouped(num_str, num = -999);
EXPECT_STREQ("-999", num_str);
}
+
+#define STRING_FIND_SPLIT_WORDS_EX(word_str_src, word_str_src_len, limit_words, ...) \
+{ \
+ int word_info[][2] = \
+ {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}}; \
+ const int word_cmp[][2] = __VA_ARGS__; \
+ const int word_cmp_size_input = ARRAY_SIZE(word_cmp) - (limit_words ? 1 : 0); \
+ const int word_cmp_size = ARRAY_SIZE(word_cmp); \
+ const int word_num = BLI_string_find_split_words( \
+ word_str_src, word_str_src_len, ' ', word_info, word_cmp_size_input); \
+ EXPECT_EQ(word_num, word_cmp_size - 1); \
+ EXPECT_EQ_ARRAY_ND(word_cmp, word_info, word_cmp_size, 2); \
+} ((void)0)
+
+#define STRING_FIND_SPLIT_WORDS(word_str_src, ...) \
+ STRING_FIND_SPLIT_WORDS_EX(word_str_src, strlen(word_str_src), false, __VA_ARGS__)
+
+/* BLI_string_find_split_words */
+TEST(string, StringFindSplitWords_Single)
+{
+ STRING_FIND_SPLIT_WORDS("t", {{0, 1}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS("test", {{0, 4}, {-1, -1}});
+}
+TEST(string, StringFindSplitWords_Triple)
+{
+ STRING_FIND_SPLIT_WORDS("f t w", {{0, 1}, {2, 1}, {4, 1}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS("find three words", {{0, 4}, {5, 5}, {11, 5}, {-1, -1}});
+}
+TEST(string, StringFindSplitWords_Spacing)
+{
+ STRING_FIND_SPLIT_WORDS("# ## ### ####", {{0, 1}, {2, 2}, {5, 3}, {9, 4}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS("# # # #", {{0, 1}, {3, 1}, {7, 1}, {12, 1}, {-1, -1}});
+}
+TEST(string, StringFindSplitWords_Trailing_Left)
+{
+ STRING_FIND_SPLIT_WORDS(" t", {{3, 1}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS(" test", {{3, 4}, {-1, -1}});
+}
+TEST(string, StringFindSplitWords_Trailing_Right)
+{
+ STRING_FIND_SPLIT_WORDS("t ", {{0, 1}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS("test ", {{0, 4}, {-1, -1}});
+}
+TEST(string, StringFindSplitWords_Trailing_LeftRight)
+{
+ STRING_FIND_SPLIT_WORDS(" surrounding space test 123 ", {{3, 11}, {15, 5}, {21, 4}, {28, 3}, {-1, -1}});
+}
+TEST(string, StringFindSplitWords_Blank)
+{
+ STRING_FIND_SPLIT_WORDS("", {{-1, -1}});
+}
+TEST(string, StringFindSplitWords_Whitespace)
+{
+ STRING_FIND_SPLIT_WORDS(" ", {{-1, -1}});
+ STRING_FIND_SPLIT_WORDS(" ", {{-1, -1}});
+}
+TEST(string, StringFindSplitWords_LimitWords)
+{
+ const char *words = "too many words";
+ const int words_len = strlen(words);
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len, false, {{0, 3}, {4, 4}, {9, 5}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len, true, {{0, 3}, {4, 4}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len, true, {{0, 3}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len, true, {{-1, -1}});
+}
+TEST(string, StringFindSplitWords_LimitChars)
+{
+ const char *words = "too many chars";
+ const int words_len = strlen(words);
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len, false, {{0, 3}, {4, 4}, {9, 5}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len - 1, false, {{0, 3}, {4, 4}, {9, 4}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, words_len - 5, false, {{0, 3}, {4, 4}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, 1, false, {{0, 1}, {-1, -1}});
+ STRING_FIND_SPLIT_WORDS_EX(words, 0, false, {{-1, -1}});
+}
+
+#undef STRING_FIND_SPLIT_WORDS
+
+
+/* BLI_strncasestr */
+TEST(string, StringStrncasestr)
+{
+ const char *str_test0 = "search here";
+ const char *res;
+
+ res = BLI_strncasestr(str_test0, "", 0);
+ EXPECT_EQ(str_test0, res);
+
+ res = BLI_strncasestr(str_test0, " ", 1);
+ EXPECT_EQ(str_test0 + 6, res);
+
+ res = BLI_strncasestr(str_test0, "her", 3);
+ EXPECT_EQ(str_test0 + 7, res);
+
+ res = BLI_strncasestr(str_test0, "ARCh", 4);
+ EXPECT_EQ(str_test0 + 2, res);
+
+ res = BLI_strncasestr(str_test0, "earcq", 4);
+ EXPECT_EQ(str_test0 + 1, res);
+
+ res = BLI_strncasestr(str_test0, "not there", 9);
+ EXPECT_EQ(NULL, res);
+}
diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt
index acd9f944e4c..5e6bddcdeab 100644
--- a/tests/gtests/blenlib/CMakeLists.txt
+++ b/tests/gtests/blenlib/CMakeLists.txt
@@ -35,13 +35,18 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
+BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
-BLENDER_TEST(BLI_math_geom "bf_blenlib")
+BLENDER_TEST(BLI_math_geom "bf_blenlib;bf_intern_eigen")
BLENDER_TEST(BLI_math_base "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")
-BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
-BLENDER_TEST(BLI_polyfill2d "bf_blenlib")
+if(WIN32)
+ BLENDER_TEST(BLI_path_util "bf_blenlib;bf_intern_utfconv;extern_wcwidth;${ZLIB_LIBRARIES}")
+else()
+ BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
+endif()
+BLENDER_TEST(BLI_polyfill2d "bf_blenlib;bf_intern_eigen")
BLENDER_TEST(BLI_listbase "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
diff --git a/tests/gtests/bmesh/bmesh_core_test.cc b/tests/gtests/bmesh/bmesh_core_test.cc
index 9c389a802de..0cbb6ca343e 100644
--- a/tests/gtests/bmesh/bmesh_core_test.cc
+++ b/tests/gtests/bmesh/bmesh_core_test.cc
@@ -33,4 +33,5 @@ TEST(bmesh_core, BMVertCreate) {
EXPECT_FALSE(BM_elem_flag_test((BMElem *)bv3, BM_ELEM_SELECT));
EXPECT_EQ(1.5f, BM_elem_float_data_get(&bm->vdata, bv3, CD_PROP_FLT));
EXPECT_EQ(3, BM_mesh_elem_count(bm, BM_VERT));
+ BM_mesh_free(bm);
}
diff --git a/tests/gtests/guardedalloc/CMakeLists.txt b/tests/gtests/guardedalloc/CMakeLists.txt
index 394bc0b6700..f4fb4f882ec 100644
--- a/tests/gtests/guardedalloc/CMakeLists.txt
+++ b/tests/gtests/guardedalloc/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
.
..
../../../intern/guardedalloc
+ ../../../source/blender/blenlib
)
include_directories(${INC})
diff --git a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
index 38305b388e0..345c3824b63 100644
--- a/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
+++ b/tests/gtests/guardedalloc/guardedalloc_alignment_test.cc
@@ -2,6 +2,10 @@
#include "testing/testing.h"
+extern "C" {
+#include "BLI_utildefines.h"
+}
+
#include "MEM_guardedalloc.h"
#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ(0, (size_t)ptr % align)
@@ -48,6 +52,6 @@ TEST(guardedalloc, GuardedAlignedAlloc16)
TEST(guardedalloc, GuardedAlignedAlloc32)
{
MEM_use_guarded_allocator();
- DoBasicAlignmentChecks(16);
+ DoBasicAlignmentChecks(32);
}
#endif
diff --git a/tests/gtests/testing/CMakeLists.txt b/tests/gtests/testing/CMakeLists.txt
index 0e5da492ed2..1eb60e7f3b5 100644
--- a/tests/gtests/testing/CMakeLists.txt
+++ b/tests/gtests/testing/CMakeLists.txt
@@ -24,17 +24,17 @@
set(INC
.
..
- ../../../extern/libmv/third_party/gflags
+ ../../../extern/gflags/src
../../../extern/gtest/include
)
if(WIN32)
list(APPEND INC
- ../../../extern/libmv/third_party/glog/src/windows
+ ../../../extern/glog/src/windows
)
else()
list(APPEND INC
- ../../../extern/libmv/third_party/glog/src
+ ../../../extern/glog/src
)
endif()
@@ -47,4 +47,7 @@ set(SRC
testing.h
)
+add_definitions(${GFLAGS_DEFINES})
+add_definitions(${GLOG_DEFINES})
+
blender_add_lib(bf_testing_main "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/tests/gtests/testing/testing.h b/tests/gtests/testing/testing.h
index 9083654f1d5..1594ed3926c 100644
--- a/tests/gtests/testing/testing.h
+++ b/tests/gtests/testing/testing.h
@@ -75,4 +75,20 @@ double CosinusBetweenMatrices(const TMat &a, const TMat &b) {
}
#endif
+template <typename T>
+inline void EXPECT_EQ_ARRAY(const T *expected, T *actual, const size_t N) {
+ for(size_t i = 0; i < N; ++i) {
+ EXPECT_EQ(expected[i], actual[i]);
+ }
+}
+
+template <typename T>
+inline void EXPECT_EQ_ARRAY_ND(const T *expected, T *actual, const size_t N, const size_t D) {
+ for(size_t i = 0; i < N; ++i) {
+ for(size_t j = 0; j < D; ++j) {
+ EXPECT_EQ(expected[i][j], actual[i][j]);
+ }
+ }
+}
+
#endif // __BLENDER_TESTING_H__
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 8ed9b51f736..8487c6a2094 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -73,6 +73,16 @@ if(USE_EXPERIMENTAL_TESTS)
)
endif()
+# ------------------------------------------------------------------------------
+# PY API TESTS
+add_test(script_pyapi_bpy_path ${TEST_BLENDER_EXE}
+ --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_path.py
+)
+
+add_test(script_pyapi_bpy_utils_units ${TEST_BLENDER_EXE}
+ --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_utils_units.py
+)
+
# test running mathutils testing script
add_test(script_pyapi_mathutils ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_mathutils.py
@@ -120,7 +130,7 @@ add_test(export_obj_cube ${TEST_BLENDER_EXE}
--run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\)
--md5_source=${TEST_OUT_DIR}/export_obj_cube.obj
--md5_source=${TEST_OUT_DIR}/export_obj_cube.mtl
- --md5=e776c6f8e9e0afba346e85bcd10b8e99 --md5_method=FILE
+ --md5=826f74e6b7a2128b0b61a52071ada36e --md5_method=FILE
)
add_test(export_obj_nurbs ${TEST_BLENDER_EXE}
diff --git a/tests/python/bl_bpy_path.py b/tests/python/bl_bpy_path.py
deleted file mode 100644
index 5c4ae91a5df..00000000000
--- a/tests/python/bl_bpy_path.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Apache License, Version 2.0
-
-# ./blender.bin --background -noaudio --python tests/python/bl_bpy_path.py -- --verbose
-import unittest
-
-
-class TestBpyPath(unittest.TestCase):
- def test_ensure_ext(self):
- from bpy.path import ensure_ext
-
- # Should work with both strings and bytes.
- self.assertEqual(ensure_ext('demo', '.blend'), 'demo.blend')
- self.assertEqual(ensure_ext(b'demo', b'.blend'), b'demo.blend')
-
- # Test different cases.
- self.assertEqual(ensure_ext('demo.blend', '.blend'), 'demo.blend')
- self.assertEqual(ensure_ext('demo.BLEND', '.blend'), 'demo.BLEND')
- self.assertEqual(ensure_ext('demo.blend', '.BLEND'), 'demo.blend')
-
- # Test empty extensions, compound extensions etc.
- self.assertEqual(ensure_ext('demo', 'blend'), 'demoblend')
- self.assertEqual(ensure_ext('demo', ''), 'demo')
- self.assertEqual(ensure_ext('demo', '.json.gz'), 'demo.json.gz')
- self.assertEqual(ensure_ext('demo.json.gz', '.json.gz'), 'demo.json.gz')
- self.assertEqual(ensure_ext('demo.json', '.json.gz'), 'demo.json.json.gz')
- self.assertEqual(ensure_ext('', ''), '')
- self.assertEqual(ensure_ext('', '.blend'), '.blend')
-
- # Test case-sensitive behaviour.
- self.assertEqual(ensure_ext('demo', '.blend', True), 'demo.blend')
- self.assertEqual(ensure_ext('demo.BLEND', '.blend', True), 'demo.BLEND.blend')
- self.assertEqual(ensure_ext('demo', 'Blend', True), 'demoBlend')
- self.assertEqual(ensure_ext('demoBlend', 'blend', True), 'demoBlendblend')
- self.assertEqual(ensure_ext('demo', '', True), 'demo')
-
-
-if __name__ == '__main__':
- import sys
-
- sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
- unittest.main()
diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py
index 5cd21058c99..4256cba0933 100644
--- a/tests/python/bl_load_py_modules.py
+++ b/tests/python/bl_load_py_modules.py
@@ -38,6 +38,9 @@ BLACKLIST = {
'io_import_dxf', # Because of cydxfentity.so dependency
}
+if not bpy.app.build_options.freestyle:
+ BLACKLIST.add("render_freestyle_svg")
+
BLACKLIST_DIRS = (
os.path.join(bpy.utils.resource_path('USER'), "scripts"),
) + tuple(addon_utils.paths()[1:])
@@ -75,8 +78,11 @@ def load_addons():
for mod in modules:
mod_name = mod.__name__
+ if mod_name in BLACKLIST:
+ continue
addon_utils.enable(mod_name, default_set=True)
- assert(mod_name in addons)
+ if not (mod_name in addons):
+ raise Exception("'addon_utils.enable(%r)' call failed" % mod_name)
def load_modules():
@@ -157,7 +163,8 @@ def load_modules():
ignore_paths = [
os.sep + "presets" + os.sep,
os.sep + "templates" + os.sep,
- ] + [(os.sep + f + os.sep) for f in BLACKLIST]
+ ] + ([(os.sep + f + os.sep) for f in BLACKLIST] +
+ [(os.sep + f + ".py") for f in BLACKLIST])
for f in source_files:
ok = False
diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py
index 2db38895f9b..526a54a49a2 100644
--- a/tests/python/bl_mesh_modifiers.py
+++ b/tests/python/bl_mesh_modifiers.py
@@ -197,8 +197,9 @@ def defaults_object(obj):
obj.show_wire = True
if obj.type == 'MESH':
+ obj.show_all_edges = True
+
mesh = obj.data
- mesh.show_all_edges = True
mesh.show_normal_vertex = True
@@ -815,8 +816,8 @@ def test_cube_shell(context, test):
def main():
print("Calling main!")
- #render_gl(bpy.context, "/testme")
- #ctx_clear_scene()
+ # render_gl(bpy.context, "/testme")
+ # ctx_clear_scene()
context = bpy.context
diff --git a/tests/python/bl_pyapi_bpy_path.py b/tests/python/bl_pyapi_bpy_path.py
new file mode 100644
index 00000000000..2d6019fbb07
--- /dev/null
+++ b/tests/python/bl_pyapi_bpy_path.py
@@ -0,0 +1,41 @@
+# Apache License, Version 2.0
+
+# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_bpy_path.py -- --verbose
+import unittest
+
+
+class TestBpyPath(unittest.TestCase):
+ def test_ensure_ext(self):
+ from bpy.path import ensure_ext
+
+ # Should work with both strings and bytes.
+ self.assertEqual(ensure_ext('demo', '.blend'), 'demo.blend')
+ self.assertEqual(ensure_ext(b'demo', b'.blend'), b'demo.blend')
+
+ # Test different cases.
+ self.assertEqual(ensure_ext('demo.blend', '.blend'), 'demo.blend')
+ self.assertEqual(ensure_ext('demo.BLEND', '.blend'), 'demo.BLEND')
+ self.assertEqual(ensure_ext('demo.blend', '.BLEND'), 'demo.blend')
+
+ # Test empty extensions, compound extensions etc.
+ self.assertEqual(ensure_ext('demo', 'blend'), 'demoblend')
+ self.assertEqual(ensure_ext('demo', ''), 'demo')
+ self.assertEqual(ensure_ext('demo', '.json.gz'), 'demo.json.gz')
+ self.assertEqual(ensure_ext('demo.json.gz', '.json.gz'), 'demo.json.gz')
+ self.assertEqual(ensure_ext('demo.json', '.json.gz'), 'demo.json.json.gz')
+ self.assertEqual(ensure_ext('', ''), '')
+ self.assertEqual(ensure_ext('', '.blend'), '.blend')
+
+ # Test case-sensitive behaviour.
+ self.assertEqual(ensure_ext('demo', '.blend', True), 'demo.blend')
+ self.assertEqual(ensure_ext('demo.BLEND', '.blend', True), 'demo.BLEND.blend')
+ self.assertEqual(ensure_ext('demo', 'Blend', True), 'demoBlend')
+ self.assertEqual(ensure_ext('demoBlend', 'blend', True), 'demoBlendblend')
+ self.assertEqual(ensure_ext('demo', '', True), 'demo')
+
+
+if __name__ == '__main__':
+ import sys
+
+ sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+ unittest.main()
diff --git a/tests/python/bl_pyapi_bpy_utils_units.py b/tests/python/bl_pyapi_bpy_utils_units.py
new file mode 100644
index 00000000000..f40dab4b5eb
--- /dev/null
+++ b/tests/python/bl_pyapi_bpy_utils_units.py
@@ -0,0 +1,75 @@
+# Apache License, Version 2.0
+
+# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_bpy_utils_units.py -- --verbose
+import unittest
+
+from bpy.utils import units
+
+class UnitsTesting(unittest.TestCase):
+ # From user typing to 'internal' Blender value.
+ INPUT_TESTS = (
+ # system, type, ref, input, value
+ ##### LENGTH
+ ('IMPERIAL', 'LENGTH', "", "1ft", 0.3048),
+ ('IMPERIAL', 'LENGTH', "", "(1+1)ft", 0.3048 * 2),
+ ('IMPERIAL', 'LENGTH', "", "1mi4\"", 1609.344 + 0.0254 * 4),
+ ('METRIC', 'LENGTH', "", "0.005µm", 0.000001 * 0.005),
+ ('METRIC', 'LENGTH', "", "1e6km", 1000.0 * 1e6),
+ ('IMPERIAL', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
+ ('METRIC', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
+ # Using reference string to find a unit when none is given.
+ ('IMPERIAL', 'LENGTH', "33.3ft", "1", 0.3048),
+ ('METRIC', 'LENGTH', "33.3dm", "1", 0.1),
+ ('IMPERIAL', 'LENGTH', "33.3cm", "1", 0.3048), # ref unit is not in IMPERIAL system, default to feet...
+ ('IMPERIAL', 'LENGTH', "33.3ft", "1\"", 0.0254), # unused ref unit, since one is given already!
+ ('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2), # default unit taken from current string (feet).
+ ('METRIC', 'LENGTH', "", "1+1ft", 1.3048), # no metric units, we default to meters.
+ ('IMPERIAL', 'LENGTH', "", "3+1in+1ft", 0.3048 * 4 + 0.0254), # bigger unit becomes default one!
+ ('IMPERIAL', 'LENGTH', "", "(3+1)in+1ft", 0.3048 + 0.0254 * 4),
+ )
+
+ # From 'internal' Blender value to user-friendly printing
+ OUTPUT_TESTS = (
+ # system, type, prec, sep, compat, value, output
+ ##### LENGTH
+ ('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"),
+ ('IMPERIAL', 'LENGTH', 3, False, True, 0.3048, "1ft"),
+ ('IMPERIAL', 'LENGTH', 3, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""),
+ # Those next two fail, here again because precision ignores order magnitude :/
+ #('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"), # == 1000000.004mi!!!
+ #('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"), # == 1000000.003641mi!!!
+ ('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2km 1.5cm"),
+ ('METRIC', 'LENGTH', 3, True, False, 1234.56789, "1km 234.6m"),
+ # Note: precision seems basically unused when using multi units!
+ ('METRIC', 'LENGTH', 9, True, False, 1234.56789, "1km 234.6m"),
+ ('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.23456789km"),
+ ('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1km 0.1mm"),
+ )
+
+ def test_units_inputs(self):
+ # Stolen from FBX addon!
+ def similar_values(v1, v2, e):
+ if v1 == v2:
+ return True
+ return ((abs(v1 - v2) / max(abs(v1), abs(v2))) <= e)
+
+ for usys, utype, ref, inpt, val in self.INPUT_TESTS:
+ opt_val = units.to_value(usys, utype, inpt, ref)
+ # Note: almostequal is not good here, precision is fixed on decimal digits, not variable with
+ # magnitude of numbers (i.e. 1609.4416 ~= 1609.4456 fails even at 5 of 'places'...).
+ self.assertTrue(similar_values(opt_val, val, 1e-7),
+ msg="%s, %s: \"%s\" (ref: \"%s\") => %f, expected %f"
+ "" % (usys, utype, inpt, ref, opt_val, val))
+
+ def test_units_outputs(self):
+ for usys, utype, prec, sep, compat, val, output in self.OUTPUT_TESTS:
+ opt_str = units.to_string(usys, utype, val, prec, sep, compat)
+ self.assertEqual(opt_str, output,
+ msg="%s, %s: %f (precision: %d, separate units: %d, compat units: %d) => "
+ "\"%s\", expected \"%s\"" % (usys, utype, val, prec, sep, compat, opt_str, output))
+
+
+if __name__ == '__main__':
+ import sys
+ sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+ unittest.main()
diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py
index b7f61df0e40..7761b6cb7b1 100644
--- a/tests/python/bl_pyapi_mathutils.py
+++ b/tests/python/bl_pyapi_mathutils.py
@@ -240,17 +240,23 @@ class QuaternionTesting(unittest.TestCase):
class KDTreeTesting(unittest.TestCase):
-
@staticmethod
- def kdtree_create_grid_3d(tot):
- k = kdtree.KDTree(tot * tot * tot)
+ def kdtree_create_grid_3d_data(tot):
index = 0
mul = 1.0 / (tot - 1)
for x in range(tot):
for y in range(tot):
for z in range(tot):
- k.insert((x * mul, y * mul, z * mul), index)
+ yield (x * mul, y * mul, z * mul), index
index += 1
+
+ @staticmethod
+ def kdtree_create_grid_3d(tot, *, filter_fn=None):
+ k = kdtree.KDTree(tot * tot * tot)
+ for co, index in KDTreeTesting.kdtree_create_grid_3d_data(tot):
+ if (filter_fn is not None) and (not filter_fn(co, index)):
+ continue
+ k.insert(co, index)
k.balance()
return k
@@ -327,6 +333,49 @@ class KDTreeTesting(unittest.TestCase):
ret = k.find_n((1.0,) * 3, tot)
self.assertEqual(len(ret), tot)
+ def test_kdtree_grid_filter_simple(self):
+ size = 10
+ k = self.kdtree_create_grid_3d(size)
+
+ # filter exact index
+ ret_regular = k.find((1.0,) * 3)
+ ret_filter = k.find((1.0,) * 3, filter=lambda i: i == ret_regular[1])
+ self.assertEqual(ret_regular, ret_filter)
+ ret_filter = k.find((-1.0,) * 3, filter=lambda i: i == ret_regular[1])
+ self.assertEqual(ret_regular[:2], ret_filter[:2]) # ignore distance
+
+ def test_kdtree_grid_filter_pairs(self):
+ size = 10
+ k_all = self.kdtree_create_grid_3d(size)
+ k_odd = self.kdtree_create_grid_3d(size, filter_fn=lambda co, i: (i % 2) == 1)
+ k_evn = self.kdtree_create_grid_3d(size, filter_fn=lambda co, i: (i % 2) == 0)
+
+ samples = 5
+ mul = 1 / (samples - 1)
+ for x in range(samples):
+ for y in range(samples):
+ for z in range(samples):
+ co = (x * mul, y * mul, z * mul)
+
+ ret_regular = k_odd.find(co)
+ self.assertEqual(ret_regular[1] % 2, 1)
+ ret_filter = k_all.find(co, lambda i: (i % 2) == 1)
+ self.assertEqual(ret_regular, ret_filter)
+
+ ret_regular = k_evn.find(co)
+ self.assertEqual(ret_regular[1] % 2, 0)
+ ret_filter = k_all.find(co, lambda i: (i % 2) == 0)
+ self.assertEqual(ret_regular, ret_filter)
+
+
+ # filter out all values (search odd tree for even values and the reverse)
+ co = (0,) * 3
+ ret_filter = k_odd.find(co, lambda i: (i % 2) == 0)
+ self.assertEqual(ret_filter[1], None)
+
+ ret_filter = k_evn.find(co, lambda i: (i % 2) == 1)
+ self.assertEqual(ret_filter[1], None)
+
def test_kdtree_invalid_size(self):
with self.assertRaises(ValueError):
kdtree.KDTree(-1)
@@ -342,6 +391,21 @@ class KDTreeTesting(unittest.TestCase):
with self.assertRaises(RuntimeError):
k.find(co)
+ def test_kdtree_invalid_filter(self):
+ k = kdtree.KDTree(1)
+ k.insert((0,) * 3, 0)
+ k.balance()
+ # not callable
+ with self.assertRaises(TypeError):
+ k.find((0,) * 3, filter=None)
+ # no args
+ with self.assertRaises(TypeError):
+ k.find((0,) * 3, filter=lambda: None)
+ # bad return value
+ with self.assertRaises(ValueError):
+ k.find((0,) * 3, filter=lambda i: None)
+
+
if __name__ == '__main__':
import sys
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
diff --git a/tests/python/bl_pyapi_units.py b/tests/python/bl_pyapi_units.py
deleted file mode 100644
index 128cc100b25..00000000000
--- a/tests/python/bl_pyapi_units.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Apache License, Version 2.0
-
-# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_units.py -- --verbose
-import unittest
-
-from bpy.utils import units
-
-class UnitsTesting(unittest.TestCase):
- # From user typing to 'internal' Blender value.
- INPUT_TESTS = (
- # system, type, ref, input, value
- ##### LENGTH
- ('IMPERIAL', 'LENGTH', "", "1ft", 0.3048),
- ('IMPERIAL', 'LENGTH', "", "(1+1)ft", 0.3048 * 2),
- ('IMPERIAL', 'LENGTH', "", "1mi4\"", 1609.344 + 0.0254 * 4),
- ('METRIC', 'LENGTH', "", "0.005µm", 0.000001 * 0.005),
- ('METRIC', 'LENGTH', "", "1e6km", 1000.0 * 1e6),
- ('IMPERIAL', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
- ('METRIC', 'LENGTH', "", "1ft5cm", 0.3048 + 0.01 * 5),
- # Using reference string to find a unit when none is given.
- ('IMPERIAL', 'LENGTH', "33.3ft", "1", 0.3048),
- ('METRIC', 'LENGTH', "33.3dm", "1", 0.1),
- ('IMPERIAL', 'LENGTH', "33.3cm", "1", 0.3048), # ref unit is not in IMPERIAL system, default to feet...
- ('IMPERIAL', 'LENGTH', "33.3ft", "1\"", 0.0254), # unused ref unit, since one is given already!
- ('IMPERIAL', 'LENGTH', "", "1+1ft", 0.3048 * 2), # default unit taken from current string (feet).
- ('METRIC', 'LENGTH', "", "1+1ft", 1.3048), # no metric units, we default to meters.
- ('IMPERIAL', 'LENGTH', "", "3+1in+1ft", 0.3048 * 4 + 0.0254), # bigger unit becomes default one!
- ('IMPERIAL', 'LENGTH', "", "(3+1)in+1ft", 0.3048 + 0.0254 * 4),
- )
-
- # From 'internal' Blender value to user-friendly printing
- OUTPUT_TESTS = (
- # system, type, prec, sep, compat, value, output
- ##### LENGTH
- ('IMPERIAL', 'LENGTH', 3, False, False, 0.3048, "1'"),
- ('IMPERIAL', 'LENGTH', 3, False, True, 0.3048, "1ft"),
- ('IMPERIAL', 'LENGTH', 3, True, False, 0.3048 * 2 + 0.0254 * 5.5, "2' 5.5\""),
- # Those next two fail, here again because precision ignores order magnitude :/
- #('IMPERIAL', 'LENGTH', 3, False, False, 1609.344 * 1e6, "1000000mi"), # == 1000000.004mi!!!
- #('IMPERIAL', 'LENGTH', 6, False, False, 1609.344 * 1e6, "1000000mi"), # == 1000000.003641mi!!!
- ('METRIC', 'LENGTH', 3, True, False, 1000 * 2 + 0.001 * 15, "2km 1.5cm"),
- ('METRIC', 'LENGTH', 3, True, False, 1234.56789, "1km 234.6m"),
- # Note: precision seems basically unused when using multi units!
- ('METRIC', 'LENGTH', 9, True, False, 1234.56789, "1km 234.6m"),
- ('METRIC', 'LENGTH', 9, False, False, 1234.56789, "1.23456789km"),
- ('METRIC', 'LENGTH', 9, True, False, 1000.000123456789, "1km 0.1mm"),
- )
-
- def test_units_inputs(self):
- # Stolen from FBX addon!
- def similar_values(v1, v2, e):
- if v1 == v2:
- return True
- return ((abs(v1 - v2) / max(abs(v1), abs(v2))) <= e)
-
- for usys, utype, ref, inpt, val in self.INPUT_TESTS:
- opt_val = units.to_value(usys, utype, inpt, ref)
- # Note: almostequal is not good here, precision is fixed on decimal digits, not variable with
- # magnitude of numbers (i.e. 1609.4416 ~= 1609.4456 fails even at 5 of 'places'...).
- self.assertTrue(similar_values(opt_val, val, 1e-7),
- msg="%s, %s: \"%s\" (ref: \"%s\") => %f, expected %f"
- "" % (usys, utype, inpt, ref, opt_val, val))
-
- def test_units_outputs(self):
- for usys, utype, prec, sep, compat, val, output in self.OUTPUT_TESTS:
- opt_str = units.to_string(usys, utype, val, prec, sep, compat)
- self.assertEqual(opt_str, output,
- msg="%s, %s: %f (precision: %d, separate units: %d, compat units: %d) => "
- "\"%s\", expected \"%s\"" % (usys, utype, val, prec, sep, compat, opt_str, output))
-
-
-if __name__ == '__main__':
- import sys
- sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
- unittest.main()
diff --git a/tests/python/bl_rna_defaults.py b/tests/python/bl_rna_defaults.py
index 1d6f82b06c2..72f50a827f0 100644
--- a/tests/python/bl_rna_defaults.py
+++ b/tests/python/bl_rna_defaults.py
@@ -11,11 +11,40 @@ GLOBALS = {
}
+def as_float_32(f):
+ from struct import pack, unpack
+ return unpack("f", pack("f", f))[0]
+
+
+def repr_float_precision(f, round_fn):
+ """
+ Get's the value which was most likely entered by a human in C.
+
+ Needed since Python will show trailing precision from a 32bit float.
+ """
+ f_round = round_fn(f)
+ f_str = repr(f)
+ f_str_frac = f_str.partition(".")[2]
+ if not f_str_frac:
+ return f_str
+ for i in range(1, len(f_str_frac)):
+ f_test = round(f, i)
+ f_test_round = round_fn(f_test)
+ if f_test_round == f_round:
+ return "%.*f" % (i, f_test)
+ return f_str
+
+
+def repr_float_32(f):
+ return repr_float_precision(f, as_float_32)
+
+
def validate_defaults(test_id, o):
- def warning(prop_id, val_real, val_default):
- print("Error %s: '%s.%s' is:%r, expected:%r" %
- (test_id, o.__class__.__name__, prop_id, val_real, val_default))
+ def warning(prop_id, val_real, val_default, *, repr_fn=repr):
+ print("Error %s: '%s.%s' is:%s, expected:%s" %
+ (test_id, o.__class__.__name__, prop_id,
+ repr_fn(val_real), repr_fn(val_default)))
GLOBALS["error_num"] += 1
properties = type(o).bl_rna.properties.items()
@@ -32,8 +61,8 @@ def validate_defaults(test_id, o):
if (val_real is not None) and (not isinstance(val_real, bpy.types.ID)):
validate_defaults("%s.%s" % (test_id, prop_id), val_real)
elif prop_type in {'INT', 'BOOL'}:
- array_length = prop.array_length
- if array_length == 0:
+ # array_length = prop.array_length
+ if not prop.is_array:
val_real = getattr(o, prop_id)
val_default = prop.default
if val_real != val_default:
@@ -41,12 +70,12 @@ def validate_defaults(test_id, o):
else:
pass # TODO, array defaults
elif prop_type == 'FLOAT':
- array_length = prop.array_length
- if array_length == 0:
+ # array_length = prop.array_length
+ if not prop.is_array:
val_real = getattr(o, prop_id)
val_default = prop.default
if val_real != val_default:
- warning(prop_id, val_real, val_default)
+ warning(prop_id, val_real, val_default, repr_fn=repr_float_32)
else:
pass # TODO, array defaults
elif prop_type == 'ENUM':
diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py
index f3c553cf3ef..7e92b424faa 100644
--- a/tests/python/bl_run_operators.py
+++ b/tests/python/bl_run_operators.py
@@ -285,8 +285,8 @@ def run_ops(operators, setup_func=None, reset=True):
try:
op(mode)
except:
- #import traceback
- #traceback.print_exc()
+ # import traceback
+ # traceback.print_exc()
pass
if USE_ATTRSET:
@@ -445,7 +445,7 @@ def main():
filter_op_list(operators)
# for testing, mix the list up.
- #operators.reverse()
+ # operators.reverse()
if USE_RANDOM:
import random
diff --git a/tests/python/pep8.py b/tests/python/pep8.py
index 0d6db729767..61093fd7c27 100644
--- a/tests/python/pep8.py
+++ b/tests/python/pep8.py
@@ -37,7 +37,7 @@ import os
# how many lines to read into the file, pep8 comment
# should be directly after the license header, ~20 in most cases
PEP8_SEEK_COMMENT = 40
-SKIP_PREFIX = "./tools", "./config", "./scons", "./extern"
+SKIP_PREFIX = "./tools", "./config", "./extern"
SKIP_ADDONS = True
FORCE_PEP8_ALL = False
diff --git a/tests/python/rst_to_doctree_mini.py b/tests/python/rst_to_doctree_mini.py
index dfc6cd57db6..b5e643ac46d 100644
--- a/tests/python/rst_to_doctree_mini.py
+++ b/tests/python/rst_to_doctree_mini.py
@@ -54,7 +54,7 @@ def parse_rst_py(filepath):
for i, line in enumerate(f):
line_strip = line.lstrip()
# ^\.\.\s[a-zA-Z09\-]+::.*$
- #if line.startswith(".. "):
+ # if line.startswith(".. "):
march = re_prefix.match(line_strip)
if march: